blob: dc6f26190f36d8bc0a975a97c0b42c5f793143c2 [file] [log] [blame]
Michael Chanb6016b72005-05-26 13:03:09 -07001/* bnx2.c: Broadcom NX2 network driver.
2 *
Michael Chanfeebb332008-01-21 17:07:29 -08003 * Copyright (c) 2004-2008 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>
Jiri Slaby1977f032007-10-18 23:40:25 -070029#include <linux/bitops.h>
Michael Chanf2a4f052006-03-23 01:13:12 -080030#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>
Benjamin Li706bf242008-07-18 17:55:11 -070050#include <linux/log2.h>
Michael Chanf2a4f052006-03-23 01:13:12 -080051
Michael Chanb6016b72005-05-26 13:03:09 -070052#include "bnx2.h"
53#include "bnx2_fw.h"
Michael Chand43584c2006-11-19 14:14:35 -080054#include "bnx2_fw2.h"
Michael Chanb6016b72005-05-26 13:03:09 -070055
Michael Chan110d0ef2007-12-12 11:18:34 -080056#define FW_BUF_SIZE 0x10000
Denys Vlasenkob3448b02007-09-30 17:55:51 -070057
Michael Chanb6016b72005-05-26 13:03:09 -070058#define DRV_MODULE_NAME "bnx2"
59#define PFX DRV_MODULE_NAME ": "
Michael Chan3cb29b12008-07-14 22:40:21 -070060#define DRV_MODULE_VERSION "1.7.8"
61#define DRV_MODULE_RELDATE "July 10, 2008"
Michael Chanb6016b72005-05-26 13:03:09 -070062
63#define RUN_AT(x) (jiffies + (x))
64
65/* Time in jiffies before concluding the transmitter is hung. */
66#define TX_TIMEOUT (5*HZ)
67
Andrew Mortonfefa8642008-02-09 23:17:15 -080068static char version[] __devinitdata =
Michael Chanb6016b72005-05-26 13:03:09 -070069 "Broadcom NetXtreme II Gigabit Ethernet Driver " DRV_MODULE_NAME " v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";
70
71MODULE_AUTHOR("Michael Chan <mchan@broadcom.com>");
Michael Chan8427f132008-06-19 16:44:44 -070072MODULE_DESCRIPTION("Broadcom NetXtreme II BCM5706/5708/5709 Driver");
Michael Chanb6016b72005-05-26 13:03:09 -070073MODULE_LICENSE("GPL");
74MODULE_VERSION(DRV_MODULE_VERSION);
75
76static int disable_msi = 0;
77
78module_param(disable_msi, int, 0);
79MODULE_PARM_DESC(disable_msi, "Disable Message Signaled Interrupt (MSI)");
80
81typedef enum {
82 BCM5706 = 0,
83 NC370T,
84 NC370I,
85 BCM5706S,
86 NC370F,
Michael Chan5b0c76a2005-11-04 08:45:49 -080087 BCM5708,
88 BCM5708S,
Michael Chanbac0dff2006-11-19 14:15:05 -080089 BCM5709,
Michael Chan27a005b2007-05-03 13:23:41 -070090 BCM5709S,
Michael Chan7bb0a042008-07-14 22:37:47 -070091 BCM5716,
Michael Chanb6016b72005-05-26 13:03:09 -070092} board_t;
93
94/* indexed by board_t, above */
Andrew Mortonfefa8642008-02-09 23:17:15 -080095static struct {
Michael Chanb6016b72005-05-26 13:03:09 -070096 char *name;
97} board_info[] __devinitdata = {
98 { "Broadcom NetXtreme II BCM5706 1000Base-T" },
99 { "HP NC370T Multifunction Gigabit Server Adapter" },
100 { "HP NC370i Multifunction Gigabit Server Adapter" },
101 { "Broadcom NetXtreme II BCM5706 1000Base-SX" },
102 { "HP NC370F Multifunction Gigabit Server Adapter" },
Michael Chan5b0c76a2005-11-04 08:45:49 -0800103 { "Broadcom NetXtreme II BCM5708 1000Base-T" },
104 { "Broadcom NetXtreme II BCM5708 1000Base-SX" },
Michael Chanbac0dff2006-11-19 14:15:05 -0800105 { "Broadcom NetXtreme II BCM5709 1000Base-T" },
Michael Chan27a005b2007-05-03 13:23:41 -0700106 { "Broadcom NetXtreme II BCM5709 1000Base-SX" },
Michael Chan7bb0a042008-07-14 22:37:47 -0700107 { "Broadcom NetXtreme II BCM5716 1000Base-T" },
Michael Chanb6016b72005-05-26 13:03:09 -0700108 };
109
Michael Chan7bb0a042008-07-14 22:37:47 -0700110static DEFINE_PCI_DEVICE_TABLE(bnx2_pci_tbl) = {
Michael Chanb6016b72005-05-26 13:03:09 -0700111 { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5706,
112 PCI_VENDOR_ID_HP, 0x3101, 0, 0, NC370T },
113 { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5706,
114 PCI_VENDOR_ID_HP, 0x3106, 0, 0, NC370I },
115 { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5706,
116 PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5706 },
Michael Chan5b0c76a2005-11-04 08:45:49 -0800117 { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5708,
118 PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5708 },
Michael Chanb6016b72005-05-26 13:03:09 -0700119 { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5706S,
120 PCI_VENDOR_ID_HP, 0x3102, 0, 0, NC370F },
121 { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5706S,
122 PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5706S },
Michael Chan5b0c76a2005-11-04 08:45:49 -0800123 { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5708S,
124 PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5708S },
Michael Chanbac0dff2006-11-19 14:15:05 -0800125 { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5709,
126 PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5709 },
Michael Chan27a005b2007-05-03 13:23:41 -0700127 { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5709S,
128 PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5709S },
Michael Chan7bb0a042008-07-14 22:37:47 -0700129 { PCI_VENDOR_ID_BROADCOM, 0x163b,
130 PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5716 },
Michael Chanb6016b72005-05-26 13:03:09 -0700131 { 0, }
132};
133
134static struct flash_spec flash_table[] =
135{
Michael Chane30372c2007-07-16 18:26:23 -0700136#define BUFFERED_FLAGS (BNX2_NV_BUFFERED | BNX2_NV_TRANSLATE)
137#define NONBUFFERED_FLAGS (BNX2_NV_WREN)
Michael Chanb6016b72005-05-26 13:03:09 -0700138 /* Slow EEPROM */
Michael Chan37137702005-11-04 08:49:17 -0800139 {0x00000000, 0x40830380, 0x009f0081, 0xa184a053, 0xaf000400,
Michael Chane30372c2007-07-16 18:26:23 -0700140 BUFFERED_FLAGS, SEEPROM_PAGE_BITS, SEEPROM_PAGE_SIZE,
Michael Chanb6016b72005-05-26 13:03:09 -0700141 SEEPROM_BYTE_ADDR_MASK, SEEPROM_TOTAL_SIZE,
142 "EEPROM - slow"},
Michael Chan37137702005-11-04 08:49:17 -0800143 /* Expansion entry 0001 */
144 {0x08000002, 0x4b808201, 0x00050081, 0x03840253, 0xaf020406,
Michael Chane30372c2007-07-16 18:26:23 -0700145 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
Michael Chan37137702005-11-04 08:49:17 -0800146 SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
147 "Entry 0001"},
Michael Chanb6016b72005-05-26 13:03:09 -0700148 /* Saifun SA25F010 (non-buffered flash) */
149 /* strap, cfg1, & write1 need updates */
Michael Chan37137702005-11-04 08:49:17 -0800150 {0x04000001, 0x47808201, 0x00050081, 0x03840253, 0xaf020406,
Michael Chane30372c2007-07-16 18:26:23 -0700151 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
Michael Chanb6016b72005-05-26 13:03:09 -0700152 SAIFUN_FLASH_BYTE_ADDR_MASK, SAIFUN_FLASH_BASE_TOTAL_SIZE*2,
153 "Non-buffered flash (128kB)"},
154 /* Saifun SA25F020 (non-buffered flash) */
155 /* strap, cfg1, & write1 need updates */
Michael Chan37137702005-11-04 08:49:17 -0800156 {0x0c000003, 0x4f808201, 0x00050081, 0x03840253, 0xaf020406,
Michael Chane30372c2007-07-16 18:26:23 -0700157 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
Michael Chanb6016b72005-05-26 13:03:09 -0700158 SAIFUN_FLASH_BYTE_ADDR_MASK, SAIFUN_FLASH_BASE_TOTAL_SIZE*4,
159 "Non-buffered flash (256kB)"},
Michael Chan37137702005-11-04 08:49:17 -0800160 /* Expansion entry 0100 */
161 {0x11000000, 0x53808201, 0x00050081, 0x03840253, 0xaf020406,
Michael Chane30372c2007-07-16 18:26:23 -0700162 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
Michael Chan37137702005-11-04 08:49:17 -0800163 SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
164 "Entry 0100"},
165 /* Entry 0101: ST M45PE10 (non-buffered flash, TetonII B0) */
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400166 {0x19000002, 0x5b808201, 0x000500db, 0x03840253, 0xaf020406,
Michael Chane30372c2007-07-16 18:26:23 -0700167 NONBUFFERED_FLAGS, ST_MICRO_FLASH_PAGE_BITS, ST_MICRO_FLASH_PAGE_SIZE,
Michael Chan37137702005-11-04 08:49:17 -0800168 ST_MICRO_FLASH_BYTE_ADDR_MASK, ST_MICRO_FLASH_BASE_TOTAL_SIZE*2,
169 "Entry 0101: ST M45PE10 (128kB non-bufferred)"},
170 /* Entry 0110: ST M45PE20 (non-buffered flash)*/
171 {0x15000001, 0x57808201, 0x000500db, 0x03840253, 0xaf020406,
Michael Chane30372c2007-07-16 18:26:23 -0700172 NONBUFFERED_FLAGS, ST_MICRO_FLASH_PAGE_BITS, ST_MICRO_FLASH_PAGE_SIZE,
Michael Chan37137702005-11-04 08:49:17 -0800173 ST_MICRO_FLASH_BYTE_ADDR_MASK, ST_MICRO_FLASH_BASE_TOTAL_SIZE*4,
174 "Entry 0110: ST M45PE20 (256kB non-bufferred)"},
175 /* Saifun SA25F005 (non-buffered flash) */
176 /* strap, cfg1, & write1 need updates */
177 {0x1d000003, 0x5f808201, 0x00050081, 0x03840253, 0xaf020406,
Michael Chane30372c2007-07-16 18:26:23 -0700178 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
Michael Chan37137702005-11-04 08:49:17 -0800179 SAIFUN_FLASH_BYTE_ADDR_MASK, SAIFUN_FLASH_BASE_TOTAL_SIZE,
180 "Non-buffered flash (64kB)"},
181 /* Fast EEPROM */
182 {0x22000000, 0x62808380, 0x009f0081, 0xa184a053, 0xaf000400,
Michael Chane30372c2007-07-16 18:26:23 -0700183 BUFFERED_FLAGS, SEEPROM_PAGE_BITS, SEEPROM_PAGE_SIZE,
Michael Chan37137702005-11-04 08:49:17 -0800184 SEEPROM_BYTE_ADDR_MASK, SEEPROM_TOTAL_SIZE,
185 "EEPROM - fast"},
186 /* Expansion entry 1001 */
187 {0x2a000002, 0x6b808201, 0x00050081, 0x03840253, 0xaf020406,
Michael Chane30372c2007-07-16 18:26:23 -0700188 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
Michael Chan37137702005-11-04 08:49:17 -0800189 SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
190 "Entry 1001"},
191 /* Expansion entry 1010 */
192 {0x26000001, 0x67808201, 0x00050081, 0x03840253, 0xaf020406,
Michael Chane30372c2007-07-16 18:26:23 -0700193 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
Michael Chan37137702005-11-04 08:49:17 -0800194 SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
195 "Entry 1010"},
196 /* ATMEL AT45DB011B (buffered flash) */
197 {0x2e000003, 0x6e808273, 0x00570081, 0x68848353, 0xaf000400,
Michael Chane30372c2007-07-16 18:26:23 -0700198 BUFFERED_FLAGS, BUFFERED_FLASH_PAGE_BITS, BUFFERED_FLASH_PAGE_SIZE,
Michael Chan37137702005-11-04 08:49:17 -0800199 BUFFERED_FLASH_BYTE_ADDR_MASK, BUFFERED_FLASH_TOTAL_SIZE,
200 "Buffered flash (128kB)"},
201 /* Expansion entry 1100 */
202 {0x33000000, 0x73808201, 0x00050081, 0x03840253, 0xaf020406,
Michael Chane30372c2007-07-16 18:26:23 -0700203 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
Michael Chan37137702005-11-04 08:49:17 -0800204 SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
205 "Entry 1100"},
206 /* Expansion entry 1101 */
207 {0x3b000002, 0x7b808201, 0x00050081, 0x03840253, 0xaf020406,
Michael Chane30372c2007-07-16 18:26:23 -0700208 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
Michael Chan37137702005-11-04 08:49:17 -0800209 SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
210 "Entry 1101"},
211 /* Ateml Expansion entry 1110 */
212 {0x37000001, 0x76808273, 0x00570081, 0x68848353, 0xaf000400,
Michael Chane30372c2007-07-16 18:26:23 -0700213 BUFFERED_FLAGS, BUFFERED_FLASH_PAGE_BITS, BUFFERED_FLASH_PAGE_SIZE,
Michael Chan37137702005-11-04 08:49:17 -0800214 BUFFERED_FLASH_BYTE_ADDR_MASK, 0,
215 "Entry 1110 (Atmel)"},
216 /* ATMEL AT45DB021B (buffered flash) */
217 {0x3f000003, 0x7e808273, 0x00570081, 0x68848353, 0xaf000400,
Michael Chane30372c2007-07-16 18:26:23 -0700218 BUFFERED_FLAGS, BUFFERED_FLASH_PAGE_BITS, BUFFERED_FLASH_PAGE_SIZE,
Michael Chan37137702005-11-04 08:49:17 -0800219 BUFFERED_FLASH_BYTE_ADDR_MASK, BUFFERED_FLASH_TOTAL_SIZE*2,
220 "Buffered flash (256kB)"},
Michael Chanb6016b72005-05-26 13:03:09 -0700221};
222
Michael Chane30372c2007-07-16 18:26:23 -0700223static struct flash_spec flash_5709 = {
224 .flags = BNX2_NV_BUFFERED,
225 .page_bits = BCM5709_FLASH_PAGE_BITS,
226 .page_size = BCM5709_FLASH_PAGE_SIZE,
227 .addr_mask = BCM5709_FLASH_BYTE_ADDR_MASK,
228 .total_size = BUFFERED_FLASH_TOTAL_SIZE*2,
229 .name = "5709 Buffered flash (256kB)",
230};
231
Michael Chanb6016b72005-05-26 13:03:09 -0700232MODULE_DEVICE_TABLE(pci, bnx2_pci_tbl);
233
Michael Chan35e90102008-06-19 16:37:42 -0700234static inline u32 bnx2_tx_avail(struct bnx2 *bp, struct bnx2_tx_ring_info *txr)
Michael Chane89bbf12005-08-25 15:36:58 -0700235{
Michael Chan2f8af122006-08-15 01:39:10 -0700236 u32 diff;
Michael Chane89bbf12005-08-25 15:36:58 -0700237
Michael Chan2f8af122006-08-15 01:39:10 -0700238 smp_mb();
Michael Chanfaac9c42006-12-14 15:56:32 -0800239
240 /* The ring uses 256 indices for 255 entries, one of them
241 * needs to be skipped.
242 */
Michael Chan35e90102008-06-19 16:37:42 -0700243 diff = txr->tx_prod - txr->tx_cons;
Michael Chanfaac9c42006-12-14 15:56:32 -0800244 if (unlikely(diff >= TX_DESC_CNT)) {
245 diff &= 0xffff;
246 if (diff == TX_DESC_CNT)
247 diff = MAX_TX_DESC_CNT;
248 }
Michael Chane89bbf12005-08-25 15:36:58 -0700249 return (bp->tx_ring_size - diff);
250}
251
Michael Chanb6016b72005-05-26 13:03:09 -0700252static u32
253bnx2_reg_rd_ind(struct bnx2 *bp, u32 offset)
254{
Michael Chan1b8227c2007-05-03 13:24:05 -0700255 u32 val;
256
257 spin_lock_bh(&bp->indirect_lock);
Michael Chanb6016b72005-05-26 13:03:09 -0700258 REG_WR(bp, BNX2_PCICFG_REG_WINDOW_ADDRESS, offset);
Michael Chan1b8227c2007-05-03 13:24:05 -0700259 val = REG_RD(bp, BNX2_PCICFG_REG_WINDOW);
260 spin_unlock_bh(&bp->indirect_lock);
261 return val;
Michael Chanb6016b72005-05-26 13:03:09 -0700262}
263
264static void
265bnx2_reg_wr_ind(struct bnx2 *bp, u32 offset, u32 val)
266{
Michael Chan1b8227c2007-05-03 13:24:05 -0700267 spin_lock_bh(&bp->indirect_lock);
Michael Chanb6016b72005-05-26 13:03:09 -0700268 REG_WR(bp, BNX2_PCICFG_REG_WINDOW_ADDRESS, offset);
269 REG_WR(bp, BNX2_PCICFG_REG_WINDOW, val);
Michael Chan1b8227c2007-05-03 13:24:05 -0700270 spin_unlock_bh(&bp->indirect_lock);
Michael Chanb6016b72005-05-26 13:03:09 -0700271}
272
273static void
Michael Chan2726d6e2008-01-29 21:35:05 -0800274bnx2_shmem_wr(struct bnx2 *bp, u32 offset, u32 val)
275{
276 bnx2_reg_wr_ind(bp, bp->shmem_base + offset, val);
277}
278
279static u32
280bnx2_shmem_rd(struct bnx2 *bp, u32 offset)
281{
282 return (bnx2_reg_rd_ind(bp, bp->shmem_base + offset));
283}
284
285static void
Michael Chanb6016b72005-05-26 13:03:09 -0700286bnx2_ctx_wr(struct bnx2 *bp, u32 cid_addr, u32 offset, u32 val)
287{
288 offset += cid_addr;
Michael Chan1b8227c2007-05-03 13:24:05 -0700289 spin_lock_bh(&bp->indirect_lock);
Michael Chan59b47d82006-11-19 14:10:45 -0800290 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
291 int i;
292
293 REG_WR(bp, BNX2_CTX_CTX_DATA, val);
294 REG_WR(bp, BNX2_CTX_CTX_CTRL,
295 offset | BNX2_CTX_CTX_CTRL_WRITE_REQ);
296 for (i = 0; i < 5; i++) {
297 u32 val;
298 val = REG_RD(bp, BNX2_CTX_CTX_CTRL);
299 if ((val & BNX2_CTX_CTX_CTRL_WRITE_REQ) == 0)
300 break;
301 udelay(5);
302 }
303 } else {
304 REG_WR(bp, BNX2_CTX_DATA_ADR, offset);
305 REG_WR(bp, BNX2_CTX_DATA, val);
306 }
Michael Chan1b8227c2007-05-03 13:24:05 -0700307 spin_unlock_bh(&bp->indirect_lock);
Michael Chanb6016b72005-05-26 13:03:09 -0700308}
309
310static int
311bnx2_read_phy(struct bnx2 *bp, u32 reg, u32 *val)
312{
313 u32 val1;
314 int i, ret;
315
Michael Chan583c28e2008-01-21 19:51:35 -0800316 if (bp->phy_flags & BNX2_PHY_FLAG_INT_MODE_AUTO_POLLING) {
Michael Chanb6016b72005-05-26 13:03:09 -0700317 val1 = REG_RD(bp, BNX2_EMAC_MDIO_MODE);
318 val1 &= ~BNX2_EMAC_MDIO_MODE_AUTO_POLL;
319
320 REG_WR(bp, BNX2_EMAC_MDIO_MODE, val1);
321 REG_RD(bp, BNX2_EMAC_MDIO_MODE);
322
323 udelay(40);
324 }
325
326 val1 = (bp->phy_addr << 21) | (reg << 16) |
327 BNX2_EMAC_MDIO_COMM_COMMAND_READ | BNX2_EMAC_MDIO_COMM_DISEXT |
328 BNX2_EMAC_MDIO_COMM_START_BUSY;
329 REG_WR(bp, BNX2_EMAC_MDIO_COMM, val1);
330
331 for (i = 0; i < 50; i++) {
332 udelay(10);
333
334 val1 = REG_RD(bp, BNX2_EMAC_MDIO_COMM);
335 if (!(val1 & BNX2_EMAC_MDIO_COMM_START_BUSY)) {
336 udelay(5);
337
338 val1 = REG_RD(bp, BNX2_EMAC_MDIO_COMM);
339 val1 &= BNX2_EMAC_MDIO_COMM_DATA;
340
341 break;
342 }
343 }
344
345 if (val1 & BNX2_EMAC_MDIO_COMM_START_BUSY) {
346 *val = 0x0;
347 ret = -EBUSY;
348 }
349 else {
350 *val = val1;
351 ret = 0;
352 }
353
Michael Chan583c28e2008-01-21 19:51:35 -0800354 if (bp->phy_flags & BNX2_PHY_FLAG_INT_MODE_AUTO_POLLING) {
Michael Chanb6016b72005-05-26 13:03:09 -0700355 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 return ret;
365}
366
367static int
368bnx2_write_phy(struct bnx2 *bp, u32 reg, u32 val)
369{
370 u32 val1;
371 int i, ret;
372
Michael Chan583c28e2008-01-21 19:51:35 -0800373 if (bp->phy_flags & BNX2_PHY_FLAG_INT_MODE_AUTO_POLLING) {
Michael Chanb6016b72005-05-26 13:03:09 -0700374 val1 = REG_RD(bp, BNX2_EMAC_MDIO_MODE);
375 val1 &= ~BNX2_EMAC_MDIO_MODE_AUTO_POLL;
376
377 REG_WR(bp, BNX2_EMAC_MDIO_MODE, val1);
378 REG_RD(bp, BNX2_EMAC_MDIO_MODE);
379
380 udelay(40);
381 }
382
383 val1 = (bp->phy_addr << 21) | (reg << 16) | val |
384 BNX2_EMAC_MDIO_COMM_COMMAND_WRITE |
385 BNX2_EMAC_MDIO_COMM_START_BUSY | BNX2_EMAC_MDIO_COMM_DISEXT;
386 REG_WR(bp, BNX2_EMAC_MDIO_COMM, val1);
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400387
Michael Chanb6016b72005-05-26 13:03:09 -0700388 for (i = 0; i < 50; i++) {
389 udelay(10);
390
391 val1 = REG_RD(bp, BNX2_EMAC_MDIO_COMM);
392 if (!(val1 & BNX2_EMAC_MDIO_COMM_START_BUSY)) {
393 udelay(5);
394 break;
395 }
396 }
397
398 if (val1 & BNX2_EMAC_MDIO_COMM_START_BUSY)
399 ret = -EBUSY;
400 else
401 ret = 0;
402
Michael Chan583c28e2008-01-21 19:51:35 -0800403 if (bp->phy_flags & BNX2_PHY_FLAG_INT_MODE_AUTO_POLLING) {
Michael Chanb6016b72005-05-26 13:03:09 -0700404 val1 = REG_RD(bp, BNX2_EMAC_MDIO_MODE);
405 val1 |= BNX2_EMAC_MDIO_MODE_AUTO_POLL;
406
407 REG_WR(bp, BNX2_EMAC_MDIO_MODE, val1);
408 REG_RD(bp, BNX2_EMAC_MDIO_MODE);
409
410 udelay(40);
411 }
412
413 return ret;
414}
415
416static void
417bnx2_disable_int(struct bnx2 *bp)
418{
Michael Chanb4b36042007-12-20 19:59:30 -0800419 int i;
420 struct bnx2_napi *bnapi;
421
422 for (i = 0; i < bp->irq_nvecs; i++) {
423 bnapi = &bp->bnx2_napi[i];
424 REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD, bnapi->int_num |
425 BNX2_PCICFG_INT_ACK_CMD_MASK_INT);
426 }
Michael Chanb6016b72005-05-26 13:03:09 -0700427 REG_RD(bp, BNX2_PCICFG_INT_ACK_CMD);
428}
429
430static void
431bnx2_enable_int(struct bnx2 *bp)
432{
Michael Chanb4b36042007-12-20 19:59:30 -0800433 int i;
434 struct bnx2_napi *bnapi;
Michael Chan1269a8a2006-01-23 16:11:03 -0800435
Michael Chanb4b36042007-12-20 19:59:30 -0800436 for (i = 0; i < bp->irq_nvecs; i++) {
437 bnapi = &bp->bnx2_napi[i];
Michael Chan35efa7c2007-12-20 19:56:37 -0800438
Michael Chanb4b36042007-12-20 19:59:30 -0800439 REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD, bnapi->int_num |
440 BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
441 BNX2_PCICFG_INT_ACK_CMD_MASK_INT |
442 bnapi->last_status_idx);
Michael Chanb6016b72005-05-26 13:03:09 -0700443
Michael Chanb4b36042007-12-20 19:59:30 -0800444 REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD, bnapi->int_num |
445 BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
446 bnapi->last_status_idx);
447 }
Michael Chanbf5295b2006-03-23 01:11:56 -0800448 REG_WR(bp, BNX2_HC_COMMAND, bp->hc_cmd | BNX2_HC_COMMAND_COAL_NOW);
Michael Chanb6016b72005-05-26 13:03:09 -0700449}
450
451static void
452bnx2_disable_int_sync(struct bnx2 *bp)
453{
Michael Chanb4b36042007-12-20 19:59:30 -0800454 int i;
455
Michael Chanb6016b72005-05-26 13:03:09 -0700456 atomic_inc(&bp->intr_sem);
457 bnx2_disable_int(bp);
Michael Chanb4b36042007-12-20 19:59:30 -0800458 for (i = 0; i < bp->irq_nvecs; i++)
459 synchronize_irq(bp->irq_tbl[i].vector);
Michael Chanb6016b72005-05-26 13:03:09 -0700460}
461
462static void
Michael Chan35efa7c2007-12-20 19:56:37 -0800463bnx2_napi_disable(struct bnx2 *bp)
464{
Michael Chanb4b36042007-12-20 19:59:30 -0800465 int i;
466
467 for (i = 0; i < bp->irq_nvecs; i++)
468 napi_disable(&bp->bnx2_napi[i].napi);
Michael Chan35efa7c2007-12-20 19:56:37 -0800469}
470
471static void
472bnx2_napi_enable(struct bnx2 *bp)
473{
Michael Chanb4b36042007-12-20 19:59:30 -0800474 int i;
475
476 for (i = 0; i < bp->irq_nvecs; i++)
477 napi_enable(&bp->bnx2_napi[i].napi);
Michael Chan35efa7c2007-12-20 19:56:37 -0800478}
479
480static void
Michael Chanb6016b72005-05-26 13:03:09 -0700481bnx2_netif_stop(struct bnx2 *bp)
482{
483 bnx2_disable_int_sync(bp);
484 if (netif_running(bp->dev)) {
Michael Chan35efa7c2007-12-20 19:56:37 -0800485 bnx2_napi_disable(bp);
Michael Chanb6016b72005-05-26 13:03:09 -0700486 netif_tx_disable(bp->dev);
487 bp->dev->trans_start = jiffies; /* prevent tx timeout */
488 }
489}
490
491static void
492bnx2_netif_start(struct bnx2 *bp)
493{
494 if (atomic_dec_and_test(&bp->intr_sem)) {
495 if (netif_running(bp->dev)) {
Benjamin Li706bf242008-07-18 17:55:11 -0700496 netif_tx_wake_all_queues(bp->dev);
Michael Chan35efa7c2007-12-20 19:56:37 -0800497 bnx2_napi_enable(bp);
Michael Chanb6016b72005-05-26 13:03:09 -0700498 bnx2_enable_int(bp);
499 }
500 }
501}
502
503static void
Michael Chan35e90102008-06-19 16:37:42 -0700504bnx2_free_tx_mem(struct bnx2 *bp)
505{
506 int i;
507
508 for (i = 0; i < bp->num_tx_rings; i++) {
509 struct bnx2_napi *bnapi = &bp->bnx2_napi[i];
510 struct bnx2_tx_ring_info *txr = &bnapi->tx_ring;
511
512 if (txr->tx_desc_ring) {
513 pci_free_consistent(bp->pdev, TXBD_RING_SIZE,
514 txr->tx_desc_ring,
515 txr->tx_desc_mapping);
516 txr->tx_desc_ring = NULL;
517 }
518 kfree(txr->tx_buf_ring);
519 txr->tx_buf_ring = NULL;
520 }
521}
522
Michael Chanbb4f98a2008-06-19 16:38:19 -0700523static void
524bnx2_free_rx_mem(struct bnx2 *bp)
525{
526 int i;
527
528 for (i = 0; i < bp->num_rx_rings; i++) {
529 struct bnx2_napi *bnapi = &bp->bnx2_napi[i];
530 struct bnx2_rx_ring_info *rxr = &bnapi->rx_ring;
531 int j;
532
533 for (j = 0; j < bp->rx_max_ring; j++) {
534 if (rxr->rx_desc_ring[j])
535 pci_free_consistent(bp->pdev, RXBD_RING_SIZE,
536 rxr->rx_desc_ring[j],
537 rxr->rx_desc_mapping[j]);
538 rxr->rx_desc_ring[j] = NULL;
539 }
540 if (rxr->rx_buf_ring)
541 vfree(rxr->rx_buf_ring);
542 rxr->rx_buf_ring = NULL;
543
544 for (j = 0; j < bp->rx_max_pg_ring; j++) {
545 if (rxr->rx_pg_desc_ring[j])
546 pci_free_consistent(bp->pdev, RXBD_RING_SIZE,
547 rxr->rx_pg_desc_ring[i],
548 rxr->rx_pg_desc_mapping[i]);
549 rxr->rx_pg_desc_ring[i] = NULL;
550 }
551 if (rxr->rx_pg_ring)
552 vfree(rxr->rx_pg_ring);
553 rxr->rx_pg_ring = NULL;
554 }
555}
556
Michael Chan35e90102008-06-19 16:37:42 -0700557static int
558bnx2_alloc_tx_mem(struct bnx2 *bp)
559{
560 int i;
561
562 for (i = 0; i < bp->num_tx_rings; i++) {
563 struct bnx2_napi *bnapi = &bp->bnx2_napi[i];
564 struct bnx2_tx_ring_info *txr = &bnapi->tx_ring;
565
566 txr->tx_buf_ring = kzalloc(SW_TXBD_RING_SIZE, GFP_KERNEL);
567 if (txr->tx_buf_ring == NULL)
568 return -ENOMEM;
569
570 txr->tx_desc_ring =
571 pci_alloc_consistent(bp->pdev, TXBD_RING_SIZE,
572 &txr->tx_desc_mapping);
573 if (txr->tx_desc_ring == NULL)
574 return -ENOMEM;
575 }
576 return 0;
577}
578
Michael Chanbb4f98a2008-06-19 16:38:19 -0700579static int
580bnx2_alloc_rx_mem(struct bnx2 *bp)
581{
582 int i;
583
584 for (i = 0; i < bp->num_rx_rings; i++) {
585 struct bnx2_napi *bnapi = &bp->bnx2_napi[i];
586 struct bnx2_rx_ring_info *rxr = &bnapi->rx_ring;
587 int j;
588
589 rxr->rx_buf_ring =
590 vmalloc(SW_RXBD_RING_SIZE * bp->rx_max_ring);
591 if (rxr->rx_buf_ring == NULL)
592 return -ENOMEM;
593
594 memset(rxr->rx_buf_ring, 0,
595 SW_RXBD_RING_SIZE * bp->rx_max_ring);
596
597 for (j = 0; j < bp->rx_max_ring; j++) {
598 rxr->rx_desc_ring[j] =
599 pci_alloc_consistent(bp->pdev, RXBD_RING_SIZE,
600 &rxr->rx_desc_mapping[j]);
601 if (rxr->rx_desc_ring[j] == NULL)
602 return -ENOMEM;
603
604 }
605
606 if (bp->rx_pg_ring_size) {
607 rxr->rx_pg_ring = vmalloc(SW_RXPG_RING_SIZE *
608 bp->rx_max_pg_ring);
609 if (rxr->rx_pg_ring == NULL)
610 return -ENOMEM;
611
612 memset(rxr->rx_pg_ring, 0, SW_RXPG_RING_SIZE *
613 bp->rx_max_pg_ring);
614 }
615
616 for (j = 0; j < bp->rx_max_pg_ring; j++) {
617 rxr->rx_pg_desc_ring[j] =
618 pci_alloc_consistent(bp->pdev, RXBD_RING_SIZE,
619 &rxr->rx_pg_desc_mapping[j]);
620 if (rxr->rx_pg_desc_ring[j] == NULL)
621 return -ENOMEM;
622
623 }
624 }
625 return 0;
626}
627
Michael Chan35e90102008-06-19 16:37:42 -0700628static void
Michael Chanb6016b72005-05-26 13:03:09 -0700629bnx2_free_mem(struct bnx2 *bp)
630{
Michael Chan13daffa2006-03-20 17:49:20 -0800631 int i;
Michael Chan43e80b82008-06-19 16:41:08 -0700632 struct bnx2_napi *bnapi = &bp->bnx2_napi[0];
Michael Chan13daffa2006-03-20 17:49:20 -0800633
Michael Chan35e90102008-06-19 16:37:42 -0700634 bnx2_free_tx_mem(bp);
Michael Chanbb4f98a2008-06-19 16:38:19 -0700635 bnx2_free_rx_mem(bp);
Michael Chan35e90102008-06-19 16:37:42 -0700636
Michael Chan59b47d82006-11-19 14:10:45 -0800637 for (i = 0; i < bp->ctx_pages; i++) {
638 if (bp->ctx_blk[i]) {
639 pci_free_consistent(bp->pdev, BCM_PAGE_SIZE,
640 bp->ctx_blk[i],
641 bp->ctx_blk_mapping[i]);
642 bp->ctx_blk[i] = NULL;
643 }
644 }
Michael Chan43e80b82008-06-19 16:41:08 -0700645 if (bnapi->status_blk.msi) {
Michael Chan0f31f992006-03-23 01:12:38 -0800646 pci_free_consistent(bp->pdev, bp->status_stats_size,
Michael Chan43e80b82008-06-19 16:41:08 -0700647 bnapi->status_blk.msi,
648 bp->status_blk_mapping);
649 bnapi->status_blk.msi = NULL;
Michael Chan0f31f992006-03-23 01:12:38 -0800650 bp->stats_blk = NULL;
Michael Chanb6016b72005-05-26 13:03:09 -0700651 }
Michael Chanb6016b72005-05-26 13:03:09 -0700652}
653
654static int
655bnx2_alloc_mem(struct bnx2 *bp)
656{
Michael Chan35e90102008-06-19 16:37:42 -0700657 int i, status_blk_size, err;
Michael Chan43e80b82008-06-19 16:41:08 -0700658 struct bnx2_napi *bnapi;
659 void *status_blk;
Michael Chanb6016b72005-05-26 13:03:09 -0700660
Michael Chan0f31f992006-03-23 01:12:38 -0800661 /* Combine status and statistics blocks into one allocation. */
662 status_blk_size = L1_CACHE_ALIGN(sizeof(struct status_block));
David S. Millerf86e82f2008-01-21 17:15:40 -0800663 if (bp->flags & BNX2_FLAG_MSIX_CAP)
Michael Chanb4b36042007-12-20 19:59:30 -0800664 status_blk_size = L1_CACHE_ALIGN(BNX2_MAX_MSIX_HW_VEC *
665 BNX2_SBLK_MSIX_ALIGN_SIZE);
Michael Chan0f31f992006-03-23 01:12:38 -0800666 bp->status_stats_size = status_blk_size +
667 sizeof(struct statistics_block);
668
Michael Chan43e80b82008-06-19 16:41:08 -0700669 status_blk = pci_alloc_consistent(bp->pdev, bp->status_stats_size,
670 &bp->status_blk_mapping);
671 if (status_blk == NULL)
Michael Chanb6016b72005-05-26 13:03:09 -0700672 goto alloc_mem_err;
673
Michael Chan43e80b82008-06-19 16:41:08 -0700674 memset(status_blk, 0, bp->status_stats_size);
Michael Chanb6016b72005-05-26 13:03:09 -0700675
Michael Chan43e80b82008-06-19 16:41:08 -0700676 bnapi = &bp->bnx2_napi[0];
677 bnapi->status_blk.msi = status_blk;
678 bnapi->hw_tx_cons_ptr =
679 &bnapi->status_blk.msi->status_tx_quick_consumer_index0;
680 bnapi->hw_rx_cons_ptr =
681 &bnapi->status_blk.msi->status_rx_quick_consumer_index0;
David S. Millerf86e82f2008-01-21 17:15:40 -0800682 if (bp->flags & BNX2_FLAG_MSIX_CAP) {
Michael Chanb4b36042007-12-20 19:59:30 -0800683 for (i = 1; i < BNX2_MAX_MSIX_VEC; i++) {
Michael Chan43e80b82008-06-19 16:41:08 -0700684 struct status_block_msix *sblk;
Michael Chanb4b36042007-12-20 19:59:30 -0800685
Michael Chan43e80b82008-06-19 16:41:08 -0700686 bnapi = &bp->bnx2_napi[i];
687
688 sblk = (void *) (status_blk +
689 BNX2_SBLK_MSIX_ALIGN_SIZE * i);
690 bnapi->status_blk.msix = sblk;
691 bnapi->hw_tx_cons_ptr =
692 &sblk->status_tx_quick_consumer_index;
693 bnapi->hw_rx_cons_ptr =
694 &sblk->status_rx_quick_consumer_index;
Michael Chanb4b36042007-12-20 19:59:30 -0800695 bnapi->int_num = i << 24;
696 }
697 }
Michael Chan35efa7c2007-12-20 19:56:37 -0800698
Michael Chan43e80b82008-06-19 16:41:08 -0700699 bp->stats_blk = status_blk + status_blk_size;
Michael Chanb6016b72005-05-26 13:03:09 -0700700
Michael Chan0f31f992006-03-23 01:12:38 -0800701 bp->stats_blk_mapping = bp->status_blk_mapping + status_blk_size;
Michael Chanb6016b72005-05-26 13:03:09 -0700702
Michael Chan59b47d82006-11-19 14:10:45 -0800703 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
704 bp->ctx_pages = 0x2000 / BCM_PAGE_SIZE;
705 if (bp->ctx_pages == 0)
706 bp->ctx_pages = 1;
707 for (i = 0; i < bp->ctx_pages; i++) {
708 bp->ctx_blk[i] = pci_alloc_consistent(bp->pdev,
709 BCM_PAGE_SIZE,
710 &bp->ctx_blk_mapping[i]);
711 if (bp->ctx_blk[i] == NULL)
712 goto alloc_mem_err;
713 }
714 }
Michael Chan35e90102008-06-19 16:37:42 -0700715
Michael Chanbb4f98a2008-06-19 16:38:19 -0700716 err = bnx2_alloc_rx_mem(bp);
717 if (err)
718 goto alloc_mem_err;
719
Michael Chan35e90102008-06-19 16:37:42 -0700720 err = bnx2_alloc_tx_mem(bp);
721 if (err)
722 goto alloc_mem_err;
723
Michael Chanb6016b72005-05-26 13:03:09 -0700724 return 0;
725
726alloc_mem_err:
727 bnx2_free_mem(bp);
728 return -ENOMEM;
729}
730
731static void
Michael Chane3648b32005-11-04 08:51:21 -0800732bnx2_report_fw_link(struct bnx2 *bp)
733{
734 u32 fw_link_status = 0;
735
Michael Chan583c28e2008-01-21 19:51:35 -0800736 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
Michael Chan0d8a6572007-07-07 22:49:43 -0700737 return;
738
Michael Chane3648b32005-11-04 08:51:21 -0800739 if (bp->link_up) {
740 u32 bmsr;
741
742 switch (bp->line_speed) {
743 case SPEED_10:
744 if (bp->duplex == DUPLEX_HALF)
745 fw_link_status = BNX2_LINK_STATUS_10HALF;
746 else
747 fw_link_status = BNX2_LINK_STATUS_10FULL;
748 break;
749 case SPEED_100:
750 if (bp->duplex == DUPLEX_HALF)
751 fw_link_status = BNX2_LINK_STATUS_100HALF;
752 else
753 fw_link_status = BNX2_LINK_STATUS_100FULL;
754 break;
755 case SPEED_1000:
756 if (bp->duplex == DUPLEX_HALF)
757 fw_link_status = BNX2_LINK_STATUS_1000HALF;
758 else
759 fw_link_status = BNX2_LINK_STATUS_1000FULL;
760 break;
761 case SPEED_2500:
762 if (bp->duplex == DUPLEX_HALF)
763 fw_link_status = BNX2_LINK_STATUS_2500HALF;
764 else
765 fw_link_status = BNX2_LINK_STATUS_2500FULL;
766 break;
767 }
768
769 fw_link_status |= BNX2_LINK_STATUS_LINK_UP;
770
771 if (bp->autoneg) {
772 fw_link_status |= BNX2_LINK_STATUS_AN_ENABLED;
773
Michael Chanca58c3a2007-05-03 13:22:52 -0700774 bnx2_read_phy(bp, bp->mii_bmsr, &bmsr);
775 bnx2_read_phy(bp, bp->mii_bmsr, &bmsr);
Michael Chane3648b32005-11-04 08:51:21 -0800776
777 if (!(bmsr & BMSR_ANEGCOMPLETE) ||
Michael Chan583c28e2008-01-21 19:51:35 -0800778 bp->phy_flags & BNX2_PHY_FLAG_PARALLEL_DETECT)
Michael Chane3648b32005-11-04 08:51:21 -0800779 fw_link_status |= BNX2_LINK_STATUS_PARALLEL_DET;
780 else
781 fw_link_status |= BNX2_LINK_STATUS_AN_COMPLETE;
782 }
783 }
784 else
785 fw_link_status = BNX2_LINK_STATUS_LINK_DOWN;
786
Michael Chan2726d6e2008-01-29 21:35:05 -0800787 bnx2_shmem_wr(bp, BNX2_LINK_STATUS, fw_link_status);
Michael Chane3648b32005-11-04 08:51:21 -0800788}
789
Michael Chan9b1084b2007-07-07 22:50:37 -0700790static char *
791bnx2_xceiver_str(struct bnx2 *bp)
792{
793 return ((bp->phy_port == PORT_FIBRE) ? "SerDes" :
Michael Chan583c28e2008-01-21 19:51:35 -0800794 ((bp->phy_flags & BNX2_PHY_FLAG_SERDES) ? "Remote Copper" :
Michael Chan9b1084b2007-07-07 22:50:37 -0700795 "Copper"));
796}
797
Michael Chane3648b32005-11-04 08:51:21 -0800798static void
Michael Chanb6016b72005-05-26 13:03:09 -0700799bnx2_report_link(struct bnx2 *bp)
800{
801 if (bp->link_up) {
802 netif_carrier_on(bp->dev);
Michael Chan9b1084b2007-07-07 22:50:37 -0700803 printk(KERN_INFO PFX "%s NIC %s Link is Up, ", bp->dev->name,
804 bnx2_xceiver_str(bp));
Michael Chanb6016b72005-05-26 13:03:09 -0700805
806 printk("%d Mbps ", bp->line_speed);
807
808 if (bp->duplex == DUPLEX_FULL)
809 printk("full duplex");
810 else
811 printk("half duplex");
812
813 if (bp->flow_ctrl) {
814 if (bp->flow_ctrl & FLOW_CTRL_RX) {
815 printk(", receive ");
816 if (bp->flow_ctrl & FLOW_CTRL_TX)
817 printk("& transmit ");
818 }
819 else {
820 printk(", transmit ");
821 }
822 printk("flow control ON");
823 }
824 printk("\n");
825 }
826 else {
827 netif_carrier_off(bp->dev);
Michael Chan9b1084b2007-07-07 22:50:37 -0700828 printk(KERN_ERR PFX "%s NIC %s Link is Down\n", bp->dev->name,
829 bnx2_xceiver_str(bp));
Michael Chanb6016b72005-05-26 13:03:09 -0700830 }
Michael Chane3648b32005-11-04 08:51:21 -0800831
832 bnx2_report_fw_link(bp);
Michael Chanb6016b72005-05-26 13:03:09 -0700833}
834
835static void
836bnx2_resolve_flow_ctrl(struct bnx2 *bp)
837{
838 u32 local_adv, remote_adv;
839
840 bp->flow_ctrl = 0;
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400841 if ((bp->autoneg & (AUTONEG_SPEED | AUTONEG_FLOW_CTRL)) !=
Michael Chanb6016b72005-05-26 13:03:09 -0700842 (AUTONEG_SPEED | AUTONEG_FLOW_CTRL)) {
843
844 if (bp->duplex == DUPLEX_FULL) {
845 bp->flow_ctrl = bp->req_flow_ctrl;
846 }
847 return;
848 }
849
850 if (bp->duplex != DUPLEX_FULL) {
851 return;
852 }
853
Michael Chan583c28e2008-01-21 19:51:35 -0800854 if ((bp->phy_flags & BNX2_PHY_FLAG_SERDES) &&
Michael Chan5b0c76a2005-11-04 08:45:49 -0800855 (CHIP_NUM(bp) == CHIP_NUM_5708)) {
856 u32 val;
857
858 bnx2_read_phy(bp, BCM5708S_1000X_STAT1, &val);
859 if (val & BCM5708S_1000X_STAT1_TX_PAUSE)
860 bp->flow_ctrl |= FLOW_CTRL_TX;
861 if (val & BCM5708S_1000X_STAT1_RX_PAUSE)
862 bp->flow_ctrl |= FLOW_CTRL_RX;
863 return;
864 }
865
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
Michael Chan583c28e2008-01-21 19:51:35 -0800869 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Michael Chanb6016b72005-05-26 13:03:09 -0700870 u32 new_local_adv = 0;
871 u32 new_remote_adv = 0;
872
873 if (local_adv & ADVERTISE_1000XPAUSE)
874 new_local_adv |= ADVERTISE_PAUSE_CAP;
875 if (local_adv & ADVERTISE_1000XPSE_ASYM)
876 new_local_adv |= ADVERTISE_PAUSE_ASYM;
877 if (remote_adv & ADVERTISE_1000XPAUSE)
878 new_remote_adv |= ADVERTISE_PAUSE_CAP;
879 if (remote_adv & ADVERTISE_1000XPSE_ASYM)
880 new_remote_adv |= ADVERTISE_PAUSE_ASYM;
881
882 local_adv = new_local_adv;
883 remote_adv = new_remote_adv;
884 }
885
886 /* See Table 28B-3 of 802.3ab-1999 spec. */
887 if (local_adv & ADVERTISE_PAUSE_CAP) {
888 if(local_adv & ADVERTISE_PAUSE_ASYM) {
889 if (remote_adv & ADVERTISE_PAUSE_CAP) {
890 bp->flow_ctrl = FLOW_CTRL_TX | FLOW_CTRL_RX;
891 }
892 else if (remote_adv & ADVERTISE_PAUSE_ASYM) {
893 bp->flow_ctrl = FLOW_CTRL_RX;
894 }
895 }
896 else {
897 if (remote_adv & ADVERTISE_PAUSE_CAP) {
898 bp->flow_ctrl = FLOW_CTRL_TX | FLOW_CTRL_RX;
899 }
900 }
901 }
902 else if (local_adv & ADVERTISE_PAUSE_ASYM) {
903 if ((remote_adv & ADVERTISE_PAUSE_CAP) &&
904 (remote_adv & ADVERTISE_PAUSE_ASYM)) {
905
906 bp->flow_ctrl = FLOW_CTRL_TX;
907 }
908 }
909}
910
911static int
Michael Chan27a005b2007-05-03 13:23:41 -0700912bnx2_5709s_linkup(struct bnx2 *bp)
913{
914 u32 val, speed;
915
916 bp->link_up = 1;
917
918 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_GP_STATUS);
919 bnx2_read_phy(bp, MII_BNX2_GP_TOP_AN_STATUS1, &val);
920 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
921
922 if ((bp->autoneg & AUTONEG_SPEED) == 0) {
923 bp->line_speed = bp->req_line_speed;
924 bp->duplex = bp->req_duplex;
925 return 0;
926 }
927 speed = val & MII_BNX2_GP_TOP_AN_SPEED_MSK;
928 switch (speed) {
929 case MII_BNX2_GP_TOP_AN_SPEED_10:
930 bp->line_speed = SPEED_10;
931 break;
932 case MII_BNX2_GP_TOP_AN_SPEED_100:
933 bp->line_speed = SPEED_100;
934 break;
935 case MII_BNX2_GP_TOP_AN_SPEED_1G:
936 case MII_BNX2_GP_TOP_AN_SPEED_1GKV:
937 bp->line_speed = SPEED_1000;
938 break;
939 case MII_BNX2_GP_TOP_AN_SPEED_2_5G:
940 bp->line_speed = SPEED_2500;
941 break;
942 }
943 if (val & MII_BNX2_GP_TOP_AN_FD)
944 bp->duplex = DUPLEX_FULL;
945 else
946 bp->duplex = DUPLEX_HALF;
947 return 0;
948}
949
950static int
Michael Chan5b0c76a2005-11-04 08:45:49 -0800951bnx2_5708s_linkup(struct bnx2 *bp)
952{
953 u32 val;
954
955 bp->link_up = 1;
956 bnx2_read_phy(bp, BCM5708S_1000X_STAT1, &val);
957 switch (val & BCM5708S_1000X_STAT1_SPEED_MASK) {
958 case BCM5708S_1000X_STAT1_SPEED_10:
959 bp->line_speed = SPEED_10;
960 break;
961 case BCM5708S_1000X_STAT1_SPEED_100:
962 bp->line_speed = SPEED_100;
963 break;
964 case BCM5708S_1000X_STAT1_SPEED_1G:
965 bp->line_speed = SPEED_1000;
966 break;
967 case BCM5708S_1000X_STAT1_SPEED_2G5:
968 bp->line_speed = SPEED_2500;
969 break;
970 }
971 if (val & BCM5708S_1000X_STAT1_FD)
972 bp->duplex = DUPLEX_FULL;
973 else
974 bp->duplex = DUPLEX_HALF;
975
976 return 0;
977}
978
979static int
980bnx2_5706s_linkup(struct bnx2 *bp)
Michael Chanb6016b72005-05-26 13:03:09 -0700981{
982 u32 bmcr, local_adv, remote_adv, common;
983
984 bp->link_up = 1;
985 bp->line_speed = SPEED_1000;
986
Michael Chanca58c3a2007-05-03 13:22:52 -0700987 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chanb6016b72005-05-26 13:03:09 -0700988 if (bmcr & BMCR_FULLDPLX) {
989 bp->duplex = DUPLEX_FULL;
990 }
991 else {
992 bp->duplex = DUPLEX_HALF;
993 }
994
995 if (!(bmcr & BMCR_ANENABLE)) {
996 return 0;
997 }
998
Michael Chanca58c3a2007-05-03 13:22:52 -0700999 bnx2_read_phy(bp, bp->mii_adv, &local_adv);
1000 bnx2_read_phy(bp, bp->mii_lpa, &remote_adv);
Michael Chanb6016b72005-05-26 13:03:09 -07001001
1002 common = local_adv & remote_adv;
1003 if (common & (ADVERTISE_1000XHALF | ADVERTISE_1000XFULL)) {
1004
1005 if (common & ADVERTISE_1000XFULL) {
1006 bp->duplex = DUPLEX_FULL;
1007 }
1008 else {
1009 bp->duplex = DUPLEX_HALF;
1010 }
1011 }
1012
1013 return 0;
1014}
1015
1016static int
1017bnx2_copper_linkup(struct bnx2 *bp)
1018{
1019 u32 bmcr;
1020
Michael Chanca58c3a2007-05-03 13:22:52 -07001021 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chanb6016b72005-05-26 13:03:09 -07001022 if (bmcr & BMCR_ANENABLE) {
1023 u32 local_adv, remote_adv, common;
1024
1025 bnx2_read_phy(bp, MII_CTRL1000, &local_adv);
1026 bnx2_read_phy(bp, MII_STAT1000, &remote_adv);
1027
1028 common = local_adv & (remote_adv >> 2);
1029 if (common & ADVERTISE_1000FULL) {
1030 bp->line_speed = SPEED_1000;
1031 bp->duplex = DUPLEX_FULL;
1032 }
1033 else if (common & ADVERTISE_1000HALF) {
1034 bp->line_speed = SPEED_1000;
1035 bp->duplex = DUPLEX_HALF;
1036 }
1037 else {
Michael Chanca58c3a2007-05-03 13:22:52 -07001038 bnx2_read_phy(bp, bp->mii_adv, &local_adv);
1039 bnx2_read_phy(bp, bp->mii_lpa, &remote_adv);
Michael Chanb6016b72005-05-26 13:03:09 -07001040
1041 common = local_adv & remote_adv;
1042 if (common & ADVERTISE_100FULL) {
1043 bp->line_speed = SPEED_100;
1044 bp->duplex = DUPLEX_FULL;
1045 }
1046 else if (common & ADVERTISE_100HALF) {
1047 bp->line_speed = SPEED_100;
1048 bp->duplex = DUPLEX_HALF;
1049 }
1050 else if (common & ADVERTISE_10FULL) {
1051 bp->line_speed = SPEED_10;
1052 bp->duplex = DUPLEX_FULL;
1053 }
1054 else if (common & ADVERTISE_10HALF) {
1055 bp->line_speed = SPEED_10;
1056 bp->duplex = DUPLEX_HALF;
1057 }
1058 else {
1059 bp->line_speed = 0;
1060 bp->link_up = 0;
1061 }
1062 }
1063 }
1064 else {
1065 if (bmcr & BMCR_SPEED100) {
1066 bp->line_speed = SPEED_100;
1067 }
1068 else {
1069 bp->line_speed = SPEED_10;
1070 }
1071 if (bmcr & BMCR_FULLDPLX) {
1072 bp->duplex = DUPLEX_FULL;
1073 }
1074 else {
1075 bp->duplex = DUPLEX_HALF;
1076 }
1077 }
1078
1079 return 0;
1080}
1081
Michael Chan83e3fc82008-01-29 21:37:17 -08001082static void
Michael Chanbb4f98a2008-06-19 16:38:19 -07001083bnx2_init_rx_context(struct bnx2 *bp, u32 cid)
Michael Chan83e3fc82008-01-29 21:37:17 -08001084{
Michael Chanbb4f98a2008-06-19 16:38:19 -07001085 u32 val, rx_cid_addr = GET_CID_ADDR(cid);
Michael Chan83e3fc82008-01-29 21:37:17 -08001086
1087 val = BNX2_L2CTX_CTX_TYPE_CTX_BD_CHN_TYPE_VALUE;
1088 val |= BNX2_L2CTX_CTX_TYPE_SIZE_L2;
1089 val |= 0x02 << 8;
1090
1091 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
1092 u32 lo_water, hi_water;
1093
1094 if (bp->flow_ctrl & FLOW_CTRL_TX)
1095 lo_water = BNX2_L2CTX_LO_WATER_MARK_DEFAULT;
1096 else
1097 lo_water = BNX2_L2CTX_LO_WATER_MARK_DIS;
1098 if (lo_water >= bp->rx_ring_size)
1099 lo_water = 0;
1100
1101 hi_water = bp->rx_ring_size / 4;
1102
1103 if (hi_water <= lo_water)
1104 lo_water = 0;
1105
1106 hi_water /= BNX2_L2CTX_HI_WATER_MARK_SCALE;
1107 lo_water /= BNX2_L2CTX_LO_WATER_MARK_SCALE;
1108
1109 if (hi_water > 0xf)
1110 hi_water = 0xf;
1111 else if (hi_water == 0)
1112 lo_water = 0;
1113 val |= lo_water | (hi_water << BNX2_L2CTX_HI_WATER_MARK_SHIFT);
1114 }
1115 bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_CTX_TYPE, val);
1116}
1117
Michael Chanbb4f98a2008-06-19 16:38:19 -07001118static void
1119bnx2_init_all_rx_contexts(struct bnx2 *bp)
1120{
1121 int i;
1122 u32 cid;
1123
1124 for (i = 0, cid = RX_CID; i < bp->num_rx_rings; i++, cid++) {
1125 if (i == 1)
1126 cid = RX_RSS_CID;
1127 bnx2_init_rx_context(bp, cid);
1128 }
1129}
1130
Michael Chanb6016b72005-05-26 13:03:09 -07001131static int
1132bnx2_set_mac_link(struct bnx2 *bp)
1133{
1134 u32 val;
1135
1136 REG_WR(bp, BNX2_EMAC_TX_LENGTHS, 0x2620);
1137 if (bp->link_up && (bp->line_speed == SPEED_1000) &&
1138 (bp->duplex == DUPLEX_HALF)) {
1139 REG_WR(bp, BNX2_EMAC_TX_LENGTHS, 0x26ff);
1140 }
1141
1142 /* Configure the EMAC mode register. */
1143 val = REG_RD(bp, BNX2_EMAC_MODE);
1144
1145 val &= ~(BNX2_EMAC_MODE_PORT | BNX2_EMAC_MODE_HALF_DUPLEX |
Michael Chan5b0c76a2005-11-04 08:45:49 -08001146 BNX2_EMAC_MODE_MAC_LOOP | BNX2_EMAC_MODE_FORCE_LINK |
Michael Chan59b47d82006-11-19 14:10:45 -08001147 BNX2_EMAC_MODE_25G_MODE);
Michael Chanb6016b72005-05-26 13:03:09 -07001148
1149 if (bp->link_up) {
Michael Chan5b0c76a2005-11-04 08:45:49 -08001150 switch (bp->line_speed) {
1151 case SPEED_10:
Michael Chan59b47d82006-11-19 14:10:45 -08001152 if (CHIP_NUM(bp) != CHIP_NUM_5706) {
1153 val |= BNX2_EMAC_MODE_PORT_MII_10M;
Michael Chan5b0c76a2005-11-04 08:45:49 -08001154 break;
1155 }
1156 /* fall through */
1157 case SPEED_100:
1158 val |= BNX2_EMAC_MODE_PORT_MII;
1159 break;
1160 case SPEED_2500:
Michael Chan59b47d82006-11-19 14:10:45 -08001161 val |= BNX2_EMAC_MODE_25G_MODE;
Michael Chan5b0c76a2005-11-04 08:45:49 -08001162 /* fall through */
1163 case SPEED_1000:
1164 val |= BNX2_EMAC_MODE_PORT_GMII;
1165 break;
1166 }
Michael Chanb6016b72005-05-26 13:03:09 -07001167 }
1168 else {
1169 val |= BNX2_EMAC_MODE_PORT_GMII;
1170 }
1171
1172 /* Set the MAC to operate in the appropriate duplex mode. */
1173 if (bp->duplex == DUPLEX_HALF)
1174 val |= BNX2_EMAC_MODE_HALF_DUPLEX;
1175 REG_WR(bp, BNX2_EMAC_MODE, val);
1176
1177 /* Enable/disable rx PAUSE. */
1178 bp->rx_mode &= ~BNX2_EMAC_RX_MODE_FLOW_EN;
1179
1180 if (bp->flow_ctrl & FLOW_CTRL_RX)
1181 bp->rx_mode |= BNX2_EMAC_RX_MODE_FLOW_EN;
1182 REG_WR(bp, BNX2_EMAC_RX_MODE, bp->rx_mode);
1183
1184 /* Enable/disable tx PAUSE. */
1185 val = REG_RD(bp, BNX2_EMAC_TX_MODE);
1186 val &= ~BNX2_EMAC_TX_MODE_FLOW_EN;
1187
1188 if (bp->flow_ctrl & FLOW_CTRL_TX)
1189 val |= BNX2_EMAC_TX_MODE_FLOW_EN;
1190 REG_WR(bp, BNX2_EMAC_TX_MODE, val);
1191
1192 /* Acknowledge the interrupt. */
1193 REG_WR(bp, BNX2_EMAC_STATUS, BNX2_EMAC_STATUS_LINK_CHANGE);
1194
Michael Chan83e3fc82008-01-29 21:37:17 -08001195 if (CHIP_NUM(bp) == CHIP_NUM_5709)
Michael Chanbb4f98a2008-06-19 16:38:19 -07001196 bnx2_init_all_rx_contexts(bp);
Michael Chan83e3fc82008-01-29 21:37:17 -08001197
Michael Chanb6016b72005-05-26 13:03:09 -07001198 return 0;
1199}
1200
Michael Chan27a005b2007-05-03 13:23:41 -07001201static void
1202bnx2_enable_bmsr1(struct bnx2 *bp)
1203{
Michael Chan583c28e2008-01-21 19:51:35 -08001204 if ((bp->phy_flags & BNX2_PHY_FLAG_SERDES) &&
Michael Chan27a005b2007-05-03 13:23:41 -07001205 (CHIP_NUM(bp) == CHIP_NUM_5709))
1206 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
1207 MII_BNX2_BLK_ADDR_GP_STATUS);
1208}
1209
1210static void
1211bnx2_disable_bmsr1(struct bnx2 *bp)
1212{
Michael Chan583c28e2008-01-21 19:51:35 -08001213 if ((bp->phy_flags & BNX2_PHY_FLAG_SERDES) &&
Michael Chan27a005b2007-05-03 13:23:41 -07001214 (CHIP_NUM(bp) == CHIP_NUM_5709))
1215 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
1216 MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
1217}
1218
Michael Chanb6016b72005-05-26 13:03:09 -07001219static int
Michael Chan605a9e22007-05-03 13:23:13 -07001220bnx2_test_and_enable_2g5(struct bnx2 *bp)
1221{
1222 u32 up1;
1223 int ret = 1;
1224
Michael Chan583c28e2008-01-21 19:51:35 -08001225 if (!(bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE))
Michael Chan605a9e22007-05-03 13:23:13 -07001226 return 0;
1227
1228 if (bp->autoneg & AUTONEG_SPEED)
1229 bp->advertising |= ADVERTISED_2500baseX_Full;
1230
Michael Chan27a005b2007-05-03 13:23:41 -07001231 if (CHIP_NUM(bp) == CHIP_NUM_5709)
1232 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_OVER1G);
1233
Michael Chan605a9e22007-05-03 13:23:13 -07001234 bnx2_read_phy(bp, bp->mii_up1, &up1);
1235 if (!(up1 & BCM5708S_UP1_2G5)) {
1236 up1 |= BCM5708S_UP1_2G5;
1237 bnx2_write_phy(bp, bp->mii_up1, up1);
1238 ret = 0;
1239 }
1240
Michael Chan27a005b2007-05-03 13:23:41 -07001241 if (CHIP_NUM(bp) == CHIP_NUM_5709)
1242 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
1243 MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
1244
Michael Chan605a9e22007-05-03 13:23:13 -07001245 return ret;
1246}
1247
1248static int
1249bnx2_test_and_disable_2g5(struct bnx2 *bp)
1250{
1251 u32 up1;
1252 int ret = 0;
1253
Michael Chan583c28e2008-01-21 19:51:35 -08001254 if (!(bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE))
Michael Chan605a9e22007-05-03 13:23:13 -07001255 return 0;
1256
Michael Chan27a005b2007-05-03 13:23:41 -07001257 if (CHIP_NUM(bp) == CHIP_NUM_5709)
1258 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_OVER1G);
1259
Michael Chan605a9e22007-05-03 13:23:13 -07001260 bnx2_read_phy(bp, bp->mii_up1, &up1);
1261 if (up1 & BCM5708S_UP1_2G5) {
1262 up1 &= ~BCM5708S_UP1_2G5;
1263 bnx2_write_phy(bp, bp->mii_up1, up1);
1264 ret = 1;
1265 }
1266
Michael Chan27a005b2007-05-03 13:23:41 -07001267 if (CHIP_NUM(bp) == CHIP_NUM_5709)
1268 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
1269 MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
1270
Michael Chan605a9e22007-05-03 13:23:13 -07001271 return ret;
1272}
1273
1274static void
1275bnx2_enable_forced_2g5(struct bnx2 *bp)
1276{
1277 u32 bmcr;
1278
Michael Chan583c28e2008-01-21 19:51:35 -08001279 if (!(bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE))
Michael Chan605a9e22007-05-03 13:23:13 -07001280 return;
1281
Michael Chan27a005b2007-05-03 13:23:41 -07001282 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
1283 u32 val;
1284
1285 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
1286 MII_BNX2_BLK_ADDR_SERDES_DIG);
1287 bnx2_read_phy(bp, MII_BNX2_SERDES_DIG_MISC1, &val);
1288 val &= ~MII_BNX2_SD_MISC1_FORCE_MSK;
1289 val |= MII_BNX2_SD_MISC1_FORCE | MII_BNX2_SD_MISC1_FORCE_2_5G;
1290 bnx2_write_phy(bp, MII_BNX2_SERDES_DIG_MISC1, val);
1291
1292 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
1293 MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
1294 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
1295
1296 } else if (CHIP_NUM(bp) == CHIP_NUM_5708) {
Michael Chan605a9e22007-05-03 13:23:13 -07001297 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
1298 bmcr |= BCM5708S_BMCR_FORCE_2500;
1299 }
1300
1301 if (bp->autoneg & AUTONEG_SPEED) {
1302 bmcr &= ~BMCR_ANENABLE;
1303 if (bp->req_duplex == DUPLEX_FULL)
1304 bmcr |= BMCR_FULLDPLX;
1305 }
1306 bnx2_write_phy(bp, bp->mii_bmcr, bmcr);
1307}
1308
1309static void
1310bnx2_disable_forced_2g5(struct bnx2 *bp)
1311{
1312 u32 bmcr;
1313
Michael Chan583c28e2008-01-21 19:51:35 -08001314 if (!(bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE))
Michael Chan605a9e22007-05-03 13:23:13 -07001315 return;
1316
Michael Chan27a005b2007-05-03 13:23:41 -07001317 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
1318 u32 val;
1319
1320 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
1321 MII_BNX2_BLK_ADDR_SERDES_DIG);
1322 bnx2_read_phy(bp, MII_BNX2_SERDES_DIG_MISC1, &val);
1323 val &= ~MII_BNX2_SD_MISC1_FORCE;
1324 bnx2_write_phy(bp, MII_BNX2_SERDES_DIG_MISC1, val);
1325
1326 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
1327 MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
1328 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
1329
1330 } else if (CHIP_NUM(bp) == CHIP_NUM_5708) {
Michael Chan605a9e22007-05-03 13:23:13 -07001331 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
1332 bmcr &= ~BCM5708S_BMCR_FORCE_2500;
1333 }
1334
1335 if (bp->autoneg & AUTONEG_SPEED)
1336 bmcr |= BMCR_SPEED1000 | BMCR_ANENABLE | BMCR_ANRESTART;
1337 bnx2_write_phy(bp, bp->mii_bmcr, bmcr);
1338}
1339
Michael Chanb2fadea2008-01-21 17:07:06 -08001340static void
1341bnx2_5706s_force_link_dn(struct bnx2 *bp, int start)
1342{
1343 u32 val;
1344
1345 bnx2_write_phy(bp, MII_BNX2_DSP_ADDRESS, MII_EXPAND_SERDES_CTL);
1346 bnx2_read_phy(bp, MII_BNX2_DSP_RW_PORT, &val);
1347 if (start)
1348 bnx2_write_phy(bp, MII_BNX2_DSP_RW_PORT, val & 0xff0f);
1349 else
1350 bnx2_write_phy(bp, MII_BNX2_DSP_RW_PORT, val | 0xc0);
1351}
1352
Michael Chan605a9e22007-05-03 13:23:13 -07001353static int
Michael Chanb6016b72005-05-26 13:03:09 -07001354bnx2_set_link(struct bnx2 *bp)
1355{
1356 u32 bmsr;
1357 u8 link_up;
1358
Michael Chan80be4432006-11-19 14:07:28 -08001359 if (bp->loopback == MAC_LOOPBACK || bp->loopback == PHY_LOOPBACK) {
Michael Chanb6016b72005-05-26 13:03:09 -07001360 bp->link_up = 1;
1361 return 0;
1362 }
1363
Michael Chan583c28e2008-01-21 19:51:35 -08001364 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
Michael Chan0d8a6572007-07-07 22:49:43 -07001365 return 0;
1366
Michael Chanb6016b72005-05-26 13:03:09 -07001367 link_up = bp->link_up;
1368
Michael Chan27a005b2007-05-03 13:23:41 -07001369 bnx2_enable_bmsr1(bp);
1370 bnx2_read_phy(bp, bp->mii_bmsr1, &bmsr);
1371 bnx2_read_phy(bp, bp->mii_bmsr1, &bmsr);
1372 bnx2_disable_bmsr1(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07001373
Michael Chan583c28e2008-01-21 19:51:35 -08001374 if ((bp->phy_flags & BNX2_PHY_FLAG_SERDES) &&
Michael Chanb6016b72005-05-26 13:03:09 -07001375 (CHIP_NUM(bp) == CHIP_NUM_5706)) {
Michael Chana2724e22008-02-23 19:47:44 -08001376 u32 val, an_dbg;
Michael Chanb6016b72005-05-26 13:03:09 -07001377
Michael Chan583c28e2008-01-21 19:51:35 -08001378 if (bp->phy_flags & BNX2_PHY_FLAG_FORCED_DOWN) {
Michael Chanb2fadea2008-01-21 17:07:06 -08001379 bnx2_5706s_force_link_dn(bp, 0);
Michael Chan583c28e2008-01-21 19:51:35 -08001380 bp->phy_flags &= ~BNX2_PHY_FLAG_FORCED_DOWN;
Michael Chanb2fadea2008-01-21 17:07:06 -08001381 }
Michael Chanb6016b72005-05-26 13:03:09 -07001382 val = REG_RD(bp, BNX2_EMAC_STATUS);
Michael Chana2724e22008-02-23 19:47:44 -08001383
1384 bnx2_write_phy(bp, MII_BNX2_MISC_SHADOW, MISC_SHDW_AN_DBG);
1385 bnx2_read_phy(bp, MII_BNX2_MISC_SHADOW, &an_dbg);
1386 bnx2_read_phy(bp, MII_BNX2_MISC_SHADOW, &an_dbg);
1387
1388 if ((val & BNX2_EMAC_STATUS_LINK) &&
1389 !(an_dbg & MISC_SHDW_AN_DBG_NOSYNC))
Michael Chanb6016b72005-05-26 13:03:09 -07001390 bmsr |= BMSR_LSTATUS;
1391 else
1392 bmsr &= ~BMSR_LSTATUS;
1393 }
1394
1395 if (bmsr & BMSR_LSTATUS) {
1396 bp->link_up = 1;
1397
Michael Chan583c28e2008-01-21 19:51:35 -08001398 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Michael Chan5b0c76a2005-11-04 08:45:49 -08001399 if (CHIP_NUM(bp) == CHIP_NUM_5706)
1400 bnx2_5706s_linkup(bp);
1401 else if (CHIP_NUM(bp) == CHIP_NUM_5708)
1402 bnx2_5708s_linkup(bp);
Michael Chan27a005b2007-05-03 13:23:41 -07001403 else if (CHIP_NUM(bp) == CHIP_NUM_5709)
1404 bnx2_5709s_linkup(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07001405 }
1406 else {
1407 bnx2_copper_linkup(bp);
1408 }
1409 bnx2_resolve_flow_ctrl(bp);
1410 }
1411 else {
Michael Chan583c28e2008-01-21 19:51:35 -08001412 if ((bp->phy_flags & BNX2_PHY_FLAG_SERDES) &&
Michael Chan605a9e22007-05-03 13:23:13 -07001413 (bp->autoneg & AUTONEG_SPEED))
1414 bnx2_disable_forced_2g5(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07001415
Michael Chan583c28e2008-01-21 19:51:35 -08001416 if (bp->phy_flags & BNX2_PHY_FLAG_PARALLEL_DETECT) {
Michael Chanb2fadea2008-01-21 17:07:06 -08001417 u32 bmcr;
1418
1419 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
1420 bmcr |= BMCR_ANENABLE;
1421 bnx2_write_phy(bp, bp->mii_bmcr, bmcr);
1422
Michael Chan583c28e2008-01-21 19:51:35 -08001423 bp->phy_flags &= ~BNX2_PHY_FLAG_PARALLEL_DETECT;
Michael Chanb2fadea2008-01-21 17:07:06 -08001424 }
Michael Chanb6016b72005-05-26 13:03:09 -07001425 bp->link_up = 0;
1426 }
1427
1428 if (bp->link_up != link_up) {
1429 bnx2_report_link(bp);
1430 }
1431
1432 bnx2_set_mac_link(bp);
1433
1434 return 0;
1435}
1436
1437static int
1438bnx2_reset_phy(struct bnx2 *bp)
1439{
1440 int i;
1441 u32 reg;
1442
Michael Chanca58c3a2007-05-03 13:22:52 -07001443 bnx2_write_phy(bp, bp->mii_bmcr, BMCR_RESET);
Michael Chanb6016b72005-05-26 13:03:09 -07001444
1445#define PHY_RESET_MAX_WAIT 100
1446 for (i = 0; i < PHY_RESET_MAX_WAIT; i++) {
1447 udelay(10);
1448
Michael Chanca58c3a2007-05-03 13:22:52 -07001449 bnx2_read_phy(bp, bp->mii_bmcr, &reg);
Michael Chanb6016b72005-05-26 13:03:09 -07001450 if (!(reg & BMCR_RESET)) {
1451 udelay(20);
1452 break;
1453 }
1454 }
1455 if (i == PHY_RESET_MAX_WAIT) {
1456 return -EBUSY;
1457 }
1458 return 0;
1459}
1460
1461static u32
1462bnx2_phy_get_pause_adv(struct bnx2 *bp)
1463{
1464 u32 adv = 0;
1465
1466 if ((bp->req_flow_ctrl & (FLOW_CTRL_RX | FLOW_CTRL_TX)) ==
1467 (FLOW_CTRL_RX | FLOW_CTRL_TX)) {
1468
Michael Chan583c28e2008-01-21 19:51:35 -08001469 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Michael Chanb6016b72005-05-26 13:03:09 -07001470 adv = ADVERTISE_1000XPAUSE;
1471 }
1472 else {
1473 adv = ADVERTISE_PAUSE_CAP;
1474 }
1475 }
1476 else if (bp->req_flow_ctrl & FLOW_CTRL_TX) {
Michael Chan583c28e2008-01-21 19:51:35 -08001477 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Michael Chanb6016b72005-05-26 13:03:09 -07001478 adv = ADVERTISE_1000XPSE_ASYM;
1479 }
1480 else {
1481 adv = ADVERTISE_PAUSE_ASYM;
1482 }
1483 }
1484 else if (bp->req_flow_ctrl & FLOW_CTRL_RX) {
Michael Chan583c28e2008-01-21 19:51:35 -08001485 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Michael Chanb6016b72005-05-26 13:03:09 -07001486 adv = ADVERTISE_1000XPAUSE | ADVERTISE_1000XPSE_ASYM;
1487 }
1488 else {
1489 adv = ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM;
1490 }
1491 }
1492 return adv;
1493}
1494
Michael Chana2f13892008-07-14 22:38:23 -07001495static int bnx2_fw_sync(struct bnx2 *, u32, int, int);
Michael Chan0d8a6572007-07-07 22:49:43 -07001496
Michael Chanb6016b72005-05-26 13:03:09 -07001497static int
Michael Chan0d8a6572007-07-07 22:49:43 -07001498bnx2_setup_remote_phy(struct bnx2 *bp, u8 port)
1499{
1500 u32 speed_arg = 0, pause_adv;
1501
1502 pause_adv = bnx2_phy_get_pause_adv(bp);
1503
1504 if (bp->autoneg & AUTONEG_SPEED) {
1505 speed_arg |= BNX2_NETLINK_SET_LINK_ENABLE_AUTONEG;
1506 if (bp->advertising & ADVERTISED_10baseT_Half)
1507 speed_arg |= BNX2_NETLINK_SET_LINK_SPEED_10HALF;
1508 if (bp->advertising & ADVERTISED_10baseT_Full)
1509 speed_arg |= BNX2_NETLINK_SET_LINK_SPEED_10FULL;
1510 if (bp->advertising & ADVERTISED_100baseT_Half)
1511 speed_arg |= BNX2_NETLINK_SET_LINK_SPEED_100HALF;
1512 if (bp->advertising & ADVERTISED_100baseT_Full)
1513 speed_arg |= BNX2_NETLINK_SET_LINK_SPEED_100FULL;
1514 if (bp->advertising & ADVERTISED_1000baseT_Full)
1515 speed_arg |= BNX2_NETLINK_SET_LINK_SPEED_1GFULL;
1516 if (bp->advertising & ADVERTISED_2500baseX_Full)
1517 speed_arg |= BNX2_NETLINK_SET_LINK_SPEED_2G5FULL;
1518 } else {
1519 if (bp->req_line_speed == SPEED_2500)
1520 speed_arg = BNX2_NETLINK_SET_LINK_SPEED_2G5FULL;
1521 else if (bp->req_line_speed == SPEED_1000)
1522 speed_arg = BNX2_NETLINK_SET_LINK_SPEED_1GFULL;
1523 else if (bp->req_line_speed == SPEED_100) {
1524 if (bp->req_duplex == DUPLEX_FULL)
1525 speed_arg = BNX2_NETLINK_SET_LINK_SPEED_100FULL;
1526 else
1527 speed_arg = BNX2_NETLINK_SET_LINK_SPEED_100HALF;
1528 } else if (bp->req_line_speed == SPEED_10) {
1529 if (bp->req_duplex == DUPLEX_FULL)
1530 speed_arg = BNX2_NETLINK_SET_LINK_SPEED_10FULL;
1531 else
1532 speed_arg = BNX2_NETLINK_SET_LINK_SPEED_10HALF;
1533 }
1534 }
1535
1536 if (pause_adv & (ADVERTISE_1000XPAUSE | ADVERTISE_PAUSE_CAP))
1537 speed_arg |= BNX2_NETLINK_SET_LINK_FC_SYM_PAUSE;
Michael Chanc26736e2008-01-31 17:07:21 -08001538 if (pause_adv & (ADVERTISE_1000XPSE_ASYM | ADVERTISE_PAUSE_ASYM))
Michael Chan0d8a6572007-07-07 22:49:43 -07001539 speed_arg |= BNX2_NETLINK_SET_LINK_FC_ASYM_PAUSE;
1540
1541 if (port == PORT_TP)
1542 speed_arg |= BNX2_NETLINK_SET_LINK_PHY_APP_REMOTE |
1543 BNX2_NETLINK_SET_LINK_ETH_AT_WIRESPEED;
1544
Michael Chan2726d6e2008-01-29 21:35:05 -08001545 bnx2_shmem_wr(bp, BNX2_DRV_MB_ARG0, speed_arg);
Michael Chan0d8a6572007-07-07 22:49:43 -07001546
1547 spin_unlock_bh(&bp->phy_lock);
Michael Chana2f13892008-07-14 22:38:23 -07001548 bnx2_fw_sync(bp, BNX2_DRV_MSG_CODE_CMD_SET_LINK, 1, 0);
Michael Chan0d8a6572007-07-07 22:49:43 -07001549 spin_lock_bh(&bp->phy_lock);
1550
1551 return 0;
1552}
1553
1554static int
1555bnx2_setup_serdes_phy(struct bnx2 *bp, u8 port)
Michael Chanb6016b72005-05-26 13:03:09 -07001556{
Michael Chan605a9e22007-05-03 13:23:13 -07001557 u32 adv, bmcr;
Michael Chanb6016b72005-05-26 13:03:09 -07001558 u32 new_adv = 0;
1559
Michael Chan583c28e2008-01-21 19:51:35 -08001560 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
Michael Chan0d8a6572007-07-07 22:49:43 -07001561 return (bnx2_setup_remote_phy(bp, port));
1562
Michael Chanb6016b72005-05-26 13:03:09 -07001563 if (!(bp->autoneg & AUTONEG_SPEED)) {
1564 u32 new_bmcr;
Michael Chan5b0c76a2005-11-04 08:45:49 -08001565 int force_link_down = 0;
1566
Michael Chan605a9e22007-05-03 13:23:13 -07001567 if (bp->req_line_speed == SPEED_2500) {
1568 if (!bnx2_test_and_enable_2g5(bp))
1569 force_link_down = 1;
1570 } else if (bp->req_line_speed == SPEED_1000) {
1571 if (bnx2_test_and_disable_2g5(bp))
1572 force_link_down = 1;
1573 }
Michael Chanca58c3a2007-05-03 13:22:52 -07001574 bnx2_read_phy(bp, bp->mii_adv, &adv);
Michael Chan80be4432006-11-19 14:07:28 -08001575 adv &= ~(ADVERTISE_1000XFULL | ADVERTISE_1000XHALF);
1576
Michael Chanca58c3a2007-05-03 13:22:52 -07001577 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chan605a9e22007-05-03 13:23:13 -07001578 new_bmcr = bmcr & ~BMCR_ANENABLE;
Michael Chan80be4432006-11-19 14:07:28 -08001579 new_bmcr |= BMCR_SPEED1000;
Michael Chan605a9e22007-05-03 13:23:13 -07001580
Michael Chan27a005b2007-05-03 13:23:41 -07001581 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
1582 if (bp->req_line_speed == SPEED_2500)
1583 bnx2_enable_forced_2g5(bp);
1584 else if (bp->req_line_speed == SPEED_1000) {
1585 bnx2_disable_forced_2g5(bp);
1586 new_bmcr &= ~0x2000;
1587 }
1588
1589 } else if (CHIP_NUM(bp) == CHIP_NUM_5708) {
Michael Chan605a9e22007-05-03 13:23:13 -07001590 if (bp->req_line_speed == SPEED_2500)
1591 new_bmcr |= BCM5708S_BMCR_FORCE_2500;
1592 else
1593 new_bmcr = bmcr & ~BCM5708S_BMCR_FORCE_2500;
Michael Chan5b0c76a2005-11-04 08:45:49 -08001594 }
1595
Michael Chanb6016b72005-05-26 13:03:09 -07001596 if (bp->req_duplex == DUPLEX_FULL) {
Michael Chan5b0c76a2005-11-04 08:45:49 -08001597 adv |= ADVERTISE_1000XFULL;
Michael Chanb6016b72005-05-26 13:03:09 -07001598 new_bmcr |= BMCR_FULLDPLX;
1599 }
1600 else {
Michael Chan5b0c76a2005-11-04 08:45:49 -08001601 adv |= ADVERTISE_1000XHALF;
Michael Chanb6016b72005-05-26 13:03:09 -07001602 new_bmcr &= ~BMCR_FULLDPLX;
1603 }
Michael Chan5b0c76a2005-11-04 08:45:49 -08001604 if ((new_bmcr != bmcr) || (force_link_down)) {
Michael Chanb6016b72005-05-26 13:03:09 -07001605 /* Force a link down visible on the other side */
1606 if (bp->link_up) {
Michael Chanca58c3a2007-05-03 13:22:52 -07001607 bnx2_write_phy(bp, bp->mii_adv, adv &
Michael Chan5b0c76a2005-11-04 08:45:49 -08001608 ~(ADVERTISE_1000XFULL |
1609 ADVERTISE_1000XHALF));
Michael Chanca58c3a2007-05-03 13:22:52 -07001610 bnx2_write_phy(bp, bp->mii_bmcr, bmcr |
Michael Chanb6016b72005-05-26 13:03:09 -07001611 BMCR_ANRESTART | BMCR_ANENABLE);
1612
1613 bp->link_up = 0;
1614 netif_carrier_off(bp->dev);
Michael Chanca58c3a2007-05-03 13:22:52 -07001615 bnx2_write_phy(bp, bp->mii_bmcr, new_bmcr);
Michael Chan80be4432006-11-19 14:07:28 -08001616 bnx2_report_link(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07001617 }
Michael Chanca58c3a2007-05-03 13:22:52 -07001618 bnx2_write_phy(bp, bp->mii_adv, adv);
1619 bnx2_write_phy(bp, bp->mii_bmcr, new_bmcr);
Michael Chan605a9e22007-05-03 13:23:13 -07001620 } else {
1621 bnx2_resolve_flow_ctrl(bp);
1622 bnx2_set_mac_link(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07001623 }
1624 return 0;
1625 }
1626
Michael Chan605a9e22007-05-03 13:23:13 -07001627 bnx2_test_and_enable_2g5(bp);
Michael Chan5b0c76a2005-11-04 08:45:49 -08001628
Michael Chanb6016b72005-05-26 13:03:09 -07001629 if (bp->advertising & ADVERTISED_1000baseT_Full)
1630 new_adv |= ADVERTISE_1000XFULL;
1631
1632 new_adv |= bnx2_phy_get_pause_adv(bp);
1633
Michael Chanca58c3a2007-05-03 13:22:52 -07001634 bnx2_read_phy(bp, bp->mii_adv, &adv);
1635 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chanb6016b72005-05-26 13:03:09 -07001636
1637 bp->serdes_an_pending = 0;
1638 if ((adv != new_adv) || ((bmcr & BMCR_ANENABLE) == 0)) {
1639 /* Force a link down visible on the other side */
1640 if (bp->link_up) {
Michael Chanca58c3a2007-05-03 13:22:52 -07001641 bnx2_write_phy(bp, bp->mii_bmcr, BMCR_LOOPBACK);
Michael Chan80be4432006-11-19 14:07:28 -08001642 spin_unlock_bh(&bp->phy_lock);
1643 msleep(20);
1644 spin_lock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07001645 }
1646
Michael Chanca58c3a2007-05-03 13:22:52 -07001647 bnx2_write_phy(bp, bp->mii_adv, new_adv);
1648 bnx2_write_phy(bp, bp->mii_bmcr, bmcr | BMCR_ANRESTART |
Michael Chanb6016b72005-05-26 13:03:09 -07001649 BMCR_ANENABLE);
Michael Chanf8dd0642006-11-19 14:08:29 -08001650 /* Speed up link-up time when the link partner
1651 * does not autonegotiate which is very common
1652 * in blade servers. Some blade servers use
1653 * IPMI for kerboard input and it's important
1654 * to minimize link disruptions. Autoneg. involves
1655 * exchanging base pages plus 3 next pages and
1656 * normally completes in about 120 msec.
1657 */
1658 bp->current_interval = SERDES_AN_TIMEOUT;
1659 bp->serdes_an_pending = 1;
1660 mod_timer(&bp->timer, jiffies + bp->current_interval);
Michael Chan605a9e22007-05-03 13:23:13 -07001661 } else {
1662 bnx2_resolve_flow_ctrl(bp);
1663 bnx2_set_mac_link(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07001664 }
1665
1666 return 0;
1667}
1668
1669#define ETHTOOL_ALL_FIBRE_SPEED \
Michael Chan583c28e2008-01-21 19:51:35 -08001670 (bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE) ? \
Michael Chandeaf3912007-07-07 22:48:00 -07001671 (ADVERTISED_2500baseX_Full | ADVERTISED_1000baseT_Full) :\
1672 (ADVERTISED_1000baseT_Full)
Michael Chanb6016b72005-05-26 13:03:09 -07001673
1674#define ETHTOOL_ALL_COPPER_SPEED \
1675 (ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full | \
1676 ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full | \
1677 ADVERTISED_1000baseT_Full)
1678
1679#define PHY_ALL_10_100_SPEED (ADVERTISE_10HALF | ADVERTISE_10FULL | \
1680 ADVERTISE_100HALF | ADVERTISE_100FULL | ADVERTISE_CSMA)
Jeff Garzik6aa20a22006-09-13 13:24:59 -04001681
Michael Chanb6016b72005-05-26 13:03:09 -07001682#define PHY_ALL_1000_SPEED (ADVERTISE_1000HALF | ADVERTISE_1000FULL)
1683
Michael Chandeaf3912007-07-07 22:48:00 -07001684static void
Michael Chan0d8a6572007-07-07 22:49:43 -07001685bnx2_set_default_remote_link(struct bnx2 *bp)
1686{
1687 u32 link;
1688
1689 if (bp->phy_port == PORT_TP)
Michael Chan2726d6e2008-01-29 21:35:05 -08001690 link = bnx2_shmem_rd(bp, BNX2_RPHY_COPPER_LINK);
Michael Chan0d8a6572007-07-07 22:49:43 -07001691 else
Michael Chan2726d6e2008-01-29 21:35:05 -08001692 link = bnx2_shmem_rd(bp, BNX2_RPHY_SERDES_LINK);
Michael Chan0d8a6572007-07-07 22:49:43 -07001693
1694 if (link & BNX2_NETLINK_SET_LINK_ENABLE_AUTONEG) {
1695 bp->req_line_speed = 0;
1696 bp->autoneg |= AUTONEG_SPEED;
1697 bp->advertising = ADVERTISED_Autoneg;
1698 if (link & BNX2_NETLINK_SET_LINK_SPEED_10HALF)
1699 bp->advertising |= ADVERTISED_10baseT_Half;
1700 if (link & BNX2_NETLINK_SET_LINK_SPEED_10FULL)
1701 bp->advertising |= ADVERTISED_10baseT_Full;
1702 if (link & BNX2_NETLINK_SET_LINK_SPEED_100HALF)
1703 bp->advertising |= ADVERTISED_100baseT_Half;
1704 if (link & BNX2_NETLINK_SET_LINK_SPEED_100FULL)
1705 bp->advertising |= ADVERTISED_100baseT_Full;
1706 if (link & BNX2_NETLINK_SET_LINK_SPEED_1GFULL)
1707 bp->advertising |= ADVERTISED_1000baseT_Full;
1708 if (link & BNX2_NETLINK_SET_LINK_SPEED_2G5FULL)
1709 bp->advertising |= ADVERTISED_2500baseX_Full;
1710 } else {
1711 bp->autoneg = 0;
1712 bp->advertising = 0;
1713 bp->req_duplex = DUPLEX_FULL;
1714 if (link & BNX2_NETLINK_SET_LINK_SPEED_10) {
1715 bp->req_line_speed = SPEED_10;
1716 if (link & BNX2_NETLINK_SET_LINK_SPEED_10HALF)
1717 bp->req_duplex = DUPLEX_HALF;
1718 }
1719 if (link & BNX2_NETLINK_SET_LINK_SPEED_100) {
1720 bp->req_line_speed = SPEED_100;
1721 if (link & BNX2_NETLINK_SET_LINK_SPEED_100HALF)
1722 bp->req_duplex = DUPLEX_HALF;
1723 }
1724 if (link & BNX2_NETLINK_SET_LINK_SPEED_1GFULL)
1725 bp->req_line_speed = SPEED_1000;
1726 if (link & BNX2_NETLINK_SET_LINK_SPEED_2G5FULL)
1727 bp->req_line_speed = SPEED_2500;
1728 }
1729}
1730
1731static void
Michael Chandeaf3912007-07-07 22:48:00 -07001732bnx2_set_default_link(struct bnx2 *bp)
1733{
Harvey Harrisonab598592008-05-01 02:47:38 -07001734 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP) {
1735 bnx2_set_default_remote_link(bp);
1736 return;
1737 }
Michael Chan0d8a6572007-07-07 22:49:43 -07001738
Michael Chandeaf3912007-07-07 22:48:00 -07001739 bp->autoneg = AUTONEG_SPEED | AUTONEG_FLOW_CTRL;
1740 bp->req_line_speed = 0;
Michael Chan583c28e2008-01-21 19:51:35 -08001741 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Michael Chandeaf3912007-07-07 22:48:00 -07001742 u32 reg;
1743
1744 bp->advertising = ETHTOOL_ALL_FIBRE_SPEED | ADVERTISED_Autoneg;
1745
Michael Chan2726d6e2008-01-29 21:35:05 -08001746 reg = bnx2_shmem_rd(bp, BNX2_PORT_HW_CFG_CONFIG);
Michael Chandeaf3912007-07-07 22:48:00 -07001747 reg &= BNX2_PORT_HW_CFG_CFG_DFLT_LINK_MASK;
1748 if (reg == BNX2_PORT_HW_CFG_CFG_DFLT_LINK_1G) {
1749 bp->autoneg = 0;
1750 bp->req_line_speed = bp->line_speed = SPEED_1000;
1751 bp->req_duplex = DUPLEX_FULL;
1752 }
1753 } else
1754 bp->advertising = ETHTOOL_ALL_COPPER_SPEED | ADVERTISED_Autoneg;
1755}
1756
Michael Chan0d8a6572007-07-07 22:49:43 -07001757static void
Michael Chandf149d72007-07-07 22:51:36 -07001758bnx2_send_heart_beat(struct bnx2 *bp)
1759{
1760 u32 msg;
1761 u32 addr;
1762
1763 spin_lock(&bp->indirect_lock);
1764 msg = (u32) (++bp->fw_drv_pulse_wr_seq & BNX2_DRV_PULSE_SEQ_MASK);
1765 addr = bp->shmem_base + BNX2_DRV_PULSE_MB;
1766 REG_WR(bp, BNX2_PCICFG_REG_WINDOW_ADDRESS, addr);
1767 REG_WR(bp, BNX2_PCICFG_REG_WINDOW, msg);
1768 spin_unlock(&bp->indirect_lock);
1769}
1770
1771static void
Michael Chan0d8a6572007-07-07 22:49:43 -07001772bnx2_remote_phy_event(struct bnx2 *bp)
1773{
1774 u32 msg;
1775 u8 link_up = bp->link_up;
1776 u8 old_port;
1777
Michael Chan2726d6e2008-01-29 21:35:05 -08001778 msg = bnx2_shmem_rd(bp, BNX2_LINK_STATUS);
Michael Chan0d8a6572007-07-07 22:49:43 -07001779
Michael Chandf149d72007-07-07 22:51:36 -07001780 if (msg & BNX2_LINK_STATUS_HEART_BEAT_EXPIRED)
1781 bnx2_send_heart_beat(bp);
1782
1783 msg &= ~BNX2_LINK_STATUS_HEART_BEAT_EXPIRED;
1784
Michael Chan0d8a6572007-07-07 22:49:43 -07001785 if ((msg & BNX2_LINK_STATUS_LINK_UP) == BNX2_LINK_STATUS_LINK_DOWN)
1786 bp->link_up = 0;
1787 else {
1788 u32 speed;
1789
1790 bp->link_up = 1;
1791 speed = msg & BNX2_LINK_STATUS_SPEED_MASK;
1792 bp->duplex = DUPLEX_FULL;
1793 switch (speed) {
1794 case BNX2_LINK_STATUS_10HALF:
1795 bp->duplex = DUPLEX_HALF;
1796 case BNX2_LINK_STATUS_10FULL:
1797 bp->line_speed = SPEED_10;
1798 break;
1799 case BNX2_LINK_STATUS_100HALF:
1800 bp->duplex = DUPLEX_HALF;
1801 case BNX2_LINK_STATUS_100BASE_T4:
1802 case BNX2_LINK_STATUS_100FULL:
1803 bp->line_speed = SPEED_100;
1804 break;
1805 case BNX2_LINK_STATUS_1000HALF:
1806 bp->duplex = DUPLEX_HALF;
1807 case BNX2_LINK_STATUS_1000FULL:
1808 bp->line_speed = SPEED_1000;
1809 break;
1810 case BNX2_LINK_STATUS_2500HALF:
1811 bp->duplex = DUPLEX_HALF;
1812 case BNX2_LINK_STATUS_2500FULL:
1813 bp->line_speed = SPEED_2500;
1814 break;
1815 default:
1816 bp->line_speed = 0;
1817 break;
1818 }
1819
Michael Chan0d8a6572007-07-07 22:49:43 -07001820 bp->flow_ctrl = 0;
1821 if ((bp->autoneg & (AUTONEG_SPEED | AUTONEG_FLOW_CTRL)) !=
1822 (AUTONEG_SPEED | AUTONEG_FLOW_CTRL)) {
1823 if (bp->duplex == DUPLEX_FULL)
1824 bp->flow_ctrl = bp->req_flow_ctrl;
1825 } else {
1826 if (msg & BNX2_LINK_STATUS_TX_FC_ENABLED)
1827 bp->flow_ctrl |= FLOW_CTRL_TX;
1828 if (msg & BNX2_LINK_STATUS_RX_FC_ENABLED)
1829 bp->flow_ctrl |= FLOW_CTRL_RX;
1830 }
1831
1832 old_port = bp->phy_port;
1833 if (msg & BNX2_LINK_STATUS_SERDES_LINK)
1834 bp->phy_port = PORT_FIBRE;
1835 else
1836 bp->phy_port = PORT_TP;
1837
1838 if (old_port != bp->phy_port)
1839 bnx2_set_default_link(bp);
1840
Michael Chan0d8a6572007-07-07 22:49:43 -07001841 }
1842 if (bp->link_up != link_up)
1843 bnx2_report_link(bp);
1844
1845 bnx2_set_mac_link(bp);
1846}
1847
1848static int
1849bnx2_set_remote_link(struct bnx2 *bp)
1850{
1851 u32 evt_code;
1852
Michael Chan2726d6e2008-01-29 21:35:05 -08001853 evt_code = bnx2_shmem_rd(bp, BNX2_FW_EVT_CODE_MB);
Michael Chan0d8a6572007-07-07 22:49:43 -07001854 switch (evt_code) {
1855 case BNX2_FW_EVT_CODE_LINK_EVENT:
1856 bnx2_remote_phy_event(bp);
1857 break;
1858 case BNX2_FW_EVT_CODE_SW_TIMER_EXPIRATION_EVENT:
1859 default:
Michael Chandf149d72007-07-07 22:51:36 -07001860 bnx2_send_heart_beat(bp);
Michael Chan0d8a6572007-07-07 22:49:43 -07001861 break;
1862 }
1863 return 0;
1864}
1865
Michael Chanb6016b72005-05-26 13:03:09 -07001866static int
1867bnx2_setup_copper_phy(struct bnx2 *bp)
1868{
1869 u32 bmcr;
1870 u32 new_bmcr;
1871
Michael Chanca58c3a2007-05-03 13:22:52 -07001872 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chanb6016b72005-05-26 13:03:09 -07001873
1874 if (bp->autoneg & AUTONEG_SPEED) {
1875 u32 adv_reg, adv1000_reg;
1876 u32 new_adv_reg = 0;
1877 u32 new_adv1000_reg = 0;
1878
Michael Chanca58c3a2007-05-03 13:22:52 -07001879 bnx2_read_phy(bp, bp->mii_adv, &adv_reg);
Michael Chanb6016b72005-05-26 13:03:09 -07001880 adv_reg &= (PHY_ALL_10_100_SPEED | ADVERTISE_PAUSE_CAP |
1881 ADVERTISE_PAUSE_ASYM);
1882
1883 bnx2_read_phy(bp, MII_CTRL1000, &adv1000_reg);
1884 adv1000_reg &= PHY_ALL_1000_SPEED;
1885
1886 if (bp->advertising & ADVERTISED_10baseT_Half)
1887 new_adv_reg |= ADVERTISE_10HALF;
1888 if (bp->advertising & ADVERTISED_10baseT_Full)
1889 new_adv_reg |= ADVERTISE_10FULL;
1890 if (bp->advertising & ADVERTISED_100baseT_Half)
1891 new_adv_reg |= ADVERTISE_100HALF;
1892 if (bp->advertising & ADVERTISED_100baseT_Full)
1893 new_adv_reg |= ADVERTISE_100FULL;
1894 if (bp->advertising & ADVERTISED_1000baseT_Full)
1895 new_adv1000_reg |= ADVERTISE_1000FULL;
Jeff Garzik6aa20a22006-09-13 13:24:59 -04001896
Michael Chanb6016b72005-05-26 13:03:09 -07001897 new_adv_reg |= ADVERTISE_CSMA;
1898
1899 new_adv_reg |= bnx2_phy_get_pause_adv(bp);
1900
1901 if ((adv1000_reg != new_adv1000_reg) ||
1902 (adv_reg != new_adv_reg) ||
1903 ((bmcr & BMCR_ANENABLE) == 0)) {
1904
Michael Chanca58c3a2007-05-03 13:22:52 -07001905 bnx2_write_phy(bp, bp->mii_adv, new_adv_reg);
Michael Chanb6016b72005-05-26 13:03:09 -07001906 bnx2_write_phy(bp, MII_CTRL1000, new_adv1000_reg);
Michael Chanca58c3a2007-05-03 13:22:52 -07001907 bnx2_write_phy(bp, bp->mii_bmcr, BMCR_ANRESTART |
Michael Chanb6016b72005-05-26 13:03:09 -07001908 BMCR_ANENABLE);
1909 }
1910 else if (bp->link_up) {
1911 /* Flow ctrl may have changed from auto to forced */
1912 /* or vice-versa. */
1913
1914 bnx2_resolve_flow_ctrl(bp);
1915 bnx2_set_mac_link(bp);
1916 }
1917 return 0;
1918 }
1919
1920 new_bmcr = 0;
1921 if (bp->req_line_speed == SPEED_100) {
1922 new_bmcr |= BMCR_SPEED100;
1923 }
1924 if (bp->req_duplex == DUPLEX_FULL) {
1925 new_bmcr |= BMCR_FULLDPLX;
1926 }
1927 if (new_bmcr != bmcr) {
1928 u32 bmsr;
Michael Chanb6016b72005-05-26 13:03:09 -07001929
Michael Chanca58c3a2007-05-03 13:22:52 -07001930 bnx2_read_phy(bp, bp->mii_bmsr, &bmsr);
1931 bnx2_read_phy(bp, bp->mii_bmsr, &bmsr);
Jeff Garzik6aa20a22006-09-13 13:24:59 -04001932
Michael Chanb6016b72005-05-26 13:03:09 -07001933 if (bmsr & BMSR_LSTATUS) {
1934 /* Force link down */
Michael Chanca58c3a2007-05-03 13:22:52 -07001935 bnx2_write_phy(bp, bp->mii_bmcr, BMCR_LOOPBACK);
Michael Chana16dda02006-11-19 14:08:56 -08001936 spin_unlock_bh(&bp->phy_lock);
1937 msleep(50);
1938 spin_lock_bh(&bp->phy_lock);
1939
Michael Chanca58c3a2007-05-03 13:22:52 -07001940 bnx2_read_phy(bp, bp->mii_bmsr, &bmsr);
1941 bnx2_read_phy(bp, bp->mii_bmsr, &bmsr);
Michael Chanb6016b72005-05-26 13:03:09 -07001942 }
1943
Michael Chanca58c3a2007-05-03 13:22:52 -07001944 bnx2_write_phy(bp, bp->mii_bmcr, new_bmcr);
Michael Chanb6016b72005-05-26 13:03:09 -07001945
1946 /* Normally, the new speed is setup after the link has
1947 * gone down and up again. In some cases, link will not go
1948 * down so we need to set up the new speed here.
1949 */
1950 if (bmsr & BMSR_LSTATUS) {
1951 bp->line_speed = bp->req_line_speed;
1952 bp->duplex = bp->req_duplex;
1953 bnx2_resolve_flow_ctrl(bp);
1954 bnx2_set_mac_link(bp);
1955 }
Michael Chan27a005b2007-05-03 13:23:41 -07001956 } else {
1957 bnx2_resolve_flow_ctrl(bp);
1958 bnx2_set_mac_link(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07001959 }
1960 return 0;
1961}
1962
1963static int
Michael Chan0d8a6572007-07-07 22:49:43 -07001964bnx2_setup_phy(struct bnx2 *bp, u8 port)
Michael Chanb6016b72005-05-26 13:03:09 -07001965{
1966 if (bp->loopback == MAC_LOOPBACK)
1967 return 0;
1968
Michael Chan583c28e2008-01-21 19:51:35 -08001969 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Michael Chan0d8a6572007-07-07 22:49:43 -07001970 return (bnx2_setup_serdes_phy(bp, port));
Michael Chanb6016b72005-05-26 13:03:09 -07001971 }
1972 else {
1973 return (bnx2_setup_copper_phy(bp));
1974 }
1975}
1976
1977static int
Michael Chan9a120bc2008-05-16 22:17:45 -07001978bnx2_init_5709s_phy(struct bnx2 *bp, int reset_phy)
Michael Chan27a005b2007-05-03 13:23:41 -07001979{
1980 u32 val;
1981
1982 bp->mii_bmcr = MII_BMCR + 0x10;
1983 bp->mii_bmsr = MII_BMSR + 0x10;
1984 bp->mii_bmsr1 = MII_BNX2_GP_TOP_AN_STATUS1;
1985 bp->mii_adv = MII_ADVERTISE + 0x10;
1986 bp->mii_lpa = MII_LPA + 0x10;
1987 bp->mii_up1 = MII_BNX2_OVER1G_UP1;
1988
1989 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_AER);
1990 bnx2_write_phy(bp, MII_BNX2_AER_AER, MII_BNX2_AER_AER_AN_MMD);
1991
1992 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
Michael Chan9a120bc2008-05-16 22:17:45 -07001993 if (reset_phy)
1994 bnx2_reset_phy(bp);
Michael Chan27a005b2007-05-03 13:23:41 -07001995
1996 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_SERDES_DIG);
1997
1998 bnx2_read_phy(bp, MII_BNX2_SERDES_DIG_1000XCTL1, &val);
1999 val &= ~MII_BNX2_SD_1000XCTL1_AUTODET;
2000 val |= MII_BNX2_SD_1000XCTL1_FIBER;
2001 bnx2_write_phy(bp, MII_BNX2_SERDES_DIG_1000XCTL1, val);
2002
2003 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_OVER1G);
2004 bnx2_read_phy(bp, MII_BNX2_OVER1G_UP1, &val);
Michael Chan583c28e2008-01-21 19:51:35 -08002005 if (bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE)
Michael Chan27a005b2007-05-03 13:23:41 -07002006 val |= BCM5708S_UP1_2G5;
2007 else
2008 val &= ~BCM5708S_UP1_2G5;
2009 bnx2_write_phy(bp, MII_BNX2_OVER1G_UP1, val);
2010
2011 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_BAM_NXTPG);
2012 bnx2_read_phy(bp, MII_BNX2_BAM_NXTPG_CTL, &val);
2013 val |= MII_BNX2_NXTPG_CTL_T2 | MII_BNX2_NXTPG_CTL_BAM;
2014 bnx2_write_phy(bp, MII_BNX2_BAM_NXTPG_CTL, val);
2015
2016 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_CL73_USERB0);
2017
2018 val = MII_BNX2_CL73_BAM_EN | MII_BNX2_CL73_BAM_STA_MGR_EN |
2019 MII_BNX2_CL73_BAM_NP_AFT_BP_EN;
2020 bnx2_write_phy(bp, MII_BNX2_CL73_BAM_CTL1, val);
2021
2022 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
2023
2024 return 0;
2025}
2026
2027static int
Michael Chan9a120bc2008-05-16 22:17:45 -07002028bnx2_init_5708s_phy(struct bnx2 *bp, int reset_phy)
Michael Chan5b0c76a2005-11-04 08:45:49 -08002029{
2030 u32 val;
2031
Michael Chan9a120bc2008-05-16 22:17:45 -07002032 if (reset_phy)
2033 bnx2_reset_phy(bp);
Michael Chan27a005b2007-05-03 13:23:41 -07002034
2035 bp->mii_up1 = BCM5708S_UP1;
2036
Michael Chan5b0c76a2005-11-04 08:45:49 -08002037 bnx2_write_phy(bp, BCM5708S_BLK_ADDR, BCM5708S_BLK_ADDR_DIG3);
2038 bnx2_write_phy(bp, BCM5708S_DIG_3_0, BCM5708S_DIG_3_0_USE_IEEE);
2039 bnx2_write_phy(bp, BCM5708S_BLK_ADDR, BCM5708S_BLK_ADDR_DIG);
2040
2041 bnx2_read_phy(bp, BCM5708S_1000X_CTL1, &val);
2042 val |= BCM5708S_1000X_CTL1_FIBER_MODE | BCM5708S_1000X_CTL1_AUTODET_EN;
2043 bnx2_write_phy(bp, BCM5708S_1000X_CTL1, val);
2044
2045 bnx2_read_phy(bp, BCM5708S_1000X_CTL2, &val);
2046 val |= BCM5708S_1000X_CTL2_PLLEL_DET_EN;
2047 bnx2_write_phy(bp, BCM5708S_1000X_CTL2, val);
2048
Michael Chan583c28e2008-01-21 19:51:35 -08002049 if (bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE) {
Michael Chan5b0c76a2005-11-04 08:45:49 -08002050 bnx2_read_phy(bp, BCM5708S_UP1, &val);
2051 val |= BCM5708S_UP1_2G5;
2052 bnx2_write_phy(bp, BCM5708S_UP1, val);
2053 }
2054
2055 if ((CHIP_ID(bp) == CHIP_ID_5708_A0) ||
Michael Chandda1e392006-01-23 16:08:14 -08002056 (CHIP_ID(bp) == CHIP_ID_5708_B0) ||
2057 (CHIP_ID(bp) == CHIP_ID_5708_B1)) {
Michael Chan5b0c76a2005-11-04 08:45:49 -08002058 /* increase tx signal amplitude */
2059 bnx2_write_phy(bp, BCM5708S_BLK_ADDR,
2060 BCM5708S_BLK_ADDR_TX_MISC);
2061 bnx2_read_phy(bp, BCM5708S_TX_ACTL1, &val);
2062 val &= ~BCM5708S_TX_ACTL1_DRIVER_VCM;
2063 bnx2_write_phy(bp, BCM5708S_TX_ACTL1, val);
2064 bnx2_write_phy(bp, BCM5708S_BLK_ADDR, BCM5708S_BLK_ADDR_DIG);
2065 }
2066
Michael Chan2726d6e2008-01-29 21:35:05 -08002067 val = bnx2_shmem_rd(bp, BNX2_PORT_HW_CFG_CONFIG) &
Michael Chan5b0c76a2005-11-04 08:45:49 -08002068 BNX2_PORT_HW_CFG_CFG_TXCTL3_MASK;
2069
2070 if (val) {
2071 u32 is_backplane;
2072
Michael Chan2726d6e2008-01-29 21:35:05 -08002073 is_backplane = bnx2_shmem_rd(bp, BNX2_SHARED_HW_CFG_CONFIG);
Michael Chan5b0c76a2005-11-04 08:45:49 -08002074 if (is_backplane & BNX2_SHARED_HW_CFG_PHY_BACKPLANE) {
2075 bnx2_write_phy(bp, BCM5708S_BLK_ADDR,
2076 BCM5708S_BLK_ADDR_TX_MISC);
2077 bnx2_write_phy(bp, BCM5708S_TX_ACTL3, val);
2078 bnx2_write_phy(bp, BCM5708S_BLK_ADDR,
2079 BCM5708S_BLK_ADDR_DIG);
2080 }
2081 }
2082 return 0;
2083}
2084
2085static int
Michael Chan9a120bc2008-05-16 22:17:45 -07002086bnx2_init_5706s_phy(struct bnx2 *bp, int reset_phy)
Michael Chanb6016b72005-05-26 13:03:09 -07002087{
Michael Chan9a120bc2008-05-16 22:17:45 -07002088 if (reset_phy)
2089 bnx2_reset_phy(bp);
Michael Chan27a005b2007-05-03 13:23:41 -07002090
Michael Chan583c28e2008-01-21 19:51:35 -08002091 bp->phy_flags &= ~BNX2_PHY_FLAG_PARALLEL_DETECT;
Michael Chanb6016b72005-05-26 13:03:09 -07002092
Michael Chan59b47d82006-11-19 14:10:45 -08002093 if (CHIP_NUM(bp) == CHIP_NUM_5706)
2094 REG_WR(bp, BNX2_MISC_GP_HW_CTL0, 0x300);
Michael Chanb6016b72005-05-26 13:03:09 -07002095
2096 if (bp->dev->mtu > 1500) {
2097 u32 val;
2098
2099 /* Set extended packet length bit */
2100 bnx2_write_phy(bp, 0x18, 0x7);
2101 bnx2_read_phy(bp, 0x18, &val);
2102 bnx2_write_phy(bp, 0x18, (val & 0xfff8) | 0x4000);
2103
2104 bnx2_write_phy(bp, 0x1c, 0x6c00);
2105 bnx2_read_phy(bp, 0x1c, &val);
2106 bnx2_write_phy(bp, 0x1c, (val & 0x3ff) | 0xec02);
2107 }
2108 else {
2109 u32 val;
2110
2111 bnx2_write_phy(bp, 0x18, 0x7);
2112 bnx2_read_phy(bp, 0x18, &val);
2113 bnx2_write_phy(bp, 0x18, val & ~0x4007);
2114
2115 bnx2_write_phy(bp, 0x1c, 0x6c00);
2116 bnx2_read_phy(bp, 0x1c, &val);
2117 bnx2_write_phy(bp, 0x1c, (val & 0x3fd) | 0xec00);
2118 }
2119
2120 return 0;
2121}
2122
2123static int
Michael Chan9a120bc2008-05-16 22:17:45 -07002124bnx2_init_copper_phy(struct bnx2 *bp, int reset_phy)
Michael Chanb6016b72005-05-26 13:03:09 -07002125{
Michael Chan5b0c76a2005-11-04 08:45:49 -08002126 u32 val;
2127
Michael Chan9a120bc2008-05-16 22:17:45 -07002128 if (reset_phy)
2129 bnx2_reset_phy(bp);
Michael Chan27a005b2007-05-03 13:23:41 -07002130
Michael Chan583c28e2008-01-21 19:51:35 -08002131 if (bp->phy_flags & BNX2_PHY_FLAG_CRC_FIX) {
Michael Chanb6016b72005-05-26 13:03:09 -07002132 bnx2_write_phy(bp, 0x18, 0x0c00);
2133 bnx2_write_phy(bp, 0x17, 0x000a);
2134 bnx2_write_phy(bp, 0x15, 0x310b);
2135 bnx2_write_phy(bp, 0x17, 0x201f);
2136 bnx2_write_phy(bp, 0x15, 0x9506);
2137 bnx2_write_phy(bp, 0x17, 0x401f);
2138 bnx2_write_phy(bp, 0x15, 0x14e2);
2139 bnx2_write_phy(bp, 0x18, 0x0400);
2140 }
2141
Michael Chan583c28e2008-01-21 19:51:35 -08002142 if (bp->phy_flags & BNX2_PHY_FLAG_DIS_EARLY_DAC) {
Michael Chanb659f442007-02-02 00:46:35 -08002143 bnx2_write_phy(bp, MII_BNX2_DSP_ADDRESS,
2144 MII_BNX2_DSP_EXPAND_REG | 0x8);
2145 bnx2_read_phy(bp, MII_BNX2_DSP_RW_PORT, &val);
2146 val &= ~(1 << 8);
2147 bnx2_write_phy(bp, MII_BNX2_DSP_RW_PORT, val);
2148 }
2149
Michael Chanb6016b72005-05-26 13:03:09 -07002150 if (bp->dev->mtu > 1500) {
Michael Chanb6016b72005-05-26 13:03:09 -07002151 /* Set extended packet length bit */
2152 bnx2_write_phy(bp, 0x18, 0x7);
2153 bnx2_read_phy(bp, 0x18, &val);
2154 bnx2_write_phy(bp, 0x18, val | 0x4000);
2155
2156 bnx2_read_phy(bp, 0x10, &val);
2157 bnx2_write_phy(bp, 0x10, val | 0x1);
2158 }
2159 else {
Michael Chanb6016b72005-05-26 13:03:09 -07002160 bnx2_write_phy(bp, 0x18, 0x7);
2161 bnx2_read_phy(bp, 0x18, &val);
2162 bnx2_write_phy(bp, 0x18, val & ~0x4007);
2163
2164 bnx2_read_phy(bp, 0x10, &val);
2165 bnx2_write_phy(bp, 0x10, val & ~0x1);
2166 }
2167
Michael Chan5b0c76a2005-11-04 08:45:49 -08002168 /* ethernet@wirespeed */
2169 bnx2_write_phy(bp, 0x18, 0x7007);
2170 bnx2_read_phy(bp, 0x18, &val);
2171 bnx2_write_phy(bp, 0x18, val | (1 << 15) | (1 << 4));
Michael Chanb6016b72005-05-26 13:03:09 -07002172 return 0;
2173}
2174
2175
2176static int
Michael Chan9a120bc2008-05-16 22:17:45 -07002177bnx2_init_phy(struct bnx2 *bp, int reset_phy)
Michael Chanb6016b72005-05-26 13:03:09 -07002178{
2179 u32 val;
2180 int rc = 0;
2181
Michael Chan583c28e2008-01-21 19:51:35 -08002182 bp->phy_flags &= ~BNX2_PHY_FLAG_INT_MODE_MASK;
2183 bp->phy_flags |= BNX2_PHY_FLAG_INT_MODE_LINK_READY;
Michael Chanb6016b72005-05-26 13:03:09 -07002184
Michael Chanca58c3a2007-05-03 13:22:52 -07002185 bp->mii_bmcr = MII_BMCR;
2186 bp->mii_bmsr = MII_BMSR;
Michael Chan27a005b2007-05-03 13:23:41 -07002187 bp->mii_bmsr1 = MII_BMSR;
Michael Chanca58c3a2007-05-03 13:22:52 -07002188 bp->mii_adv = MII_ADVERTISE;
2189 bp->mii_lpa = MII_LPA;
2190
Michael Chanb6016b72005-05-26 13:03:09 -07002191 REG_WR(bp, BNX2_EMAC_ATTENTION_ENA, BNX2_EMAC_ATTENTION_ENA_LINK);
2192
Michael Chan583c28e2008-01-21 19:51:35 -08002193 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
Michael Chan0d8a6572007-07-07 22:49:43 -07002194 goto setup_phy;
2195
Michael Chanb6016b72005-05-26 13:03:09 -07002196 bnx2_read_phy(bp, MII_PHYSID1, &val);
2197 bp->phy_id = val << 16;
2198 bnx2_read_phy(bp, MII_PHYSID2, &val);
2199 bp->phy_id |= val & 0xffff;
2200
Michael Chan583c28e2008-01-21 19:51:35 -08002201 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Michael Chan5b0c76a2005-11-04 08:45:49 -08002202 if (CHIP_NUM(bp) == CHIP_NUM_5706)
Michael Chan9a120bc2008-05-16 22:17:45 -07002203 rc = bnx2_init_5706s_phy(bp, reset_phy);
Michael Chan5b0c76a2005-11-04 08:45:49 -08002204 else if (CHIP_NUM(bp) == CHIP_NUM_5708)
Michael Chan9a120bc2008-05-16 22:17:45 -07002205 rc = bnx2_init_5708s_phy(bp, reset_phy);
Michael Chan27a005b2007-05-03 13:23:41 -07002206 else if (CHIP_NUM(bp) == CHIP_NUM_5709)
Michael Chan9a120bc2008-05-16 22:17:45 -07002207 rc = bnx2_init_5709s_phy(bp, reset_phy);
Michael Chanb6016b72005-05-26 13:03:09 -07002208 }
2209 else {
Michael Chan9a120bc2008-05-16 22:17:45 -07002210 rc = bnx2_init_copper_phy(bp, reset_phy);
Michael Chanb6016b72005-05-26 13:03:09 -07002211 }
2212
Michael Chan0d8a6572007-07-07 22:49:43 -07002213setup_phy:
2214 if (!rc)
2215 rc = bnx2_setup_phy(bp, bp->phy_port);
Michael Chanb6016b72005-05-26 13:03:09 -07002216
2217 return rc;
2218}
2219
2220static int
2221bnx2_set_mac_loopback(struct bnx2 *bp)
2222{
2223 u32 mac_mode;
2224
2225 mac_mode = REG_RD(bp, BNX2_EMAC_MODE);
2226 mac_mode &= ~BNX2_EMAC_MODE_PORT;
2227 mac_mode |= BNX2_EMAC_MODE_MAC_LOOP | BNX2_EMAC_MODE_FORCE_LINK;
2228 REG_WR(bp, BNX2_EMAC_MODE, mac_mode);
2229 bp->link_up = 1;
2230 return 0;
2231}
2232
Michael Chanbc5a0692006-01-23 16:13:22 -08002233static int bnx2_test_link(struct bnx2 *);
2234
2235static int
2236bnx2_set_phy_loopback(struct bnx2 *bp)
2237{
2238 u32 mac_mode;
2239 int rc, i;
2240
2241 spin_lock_bh(&bp->phy_lock);
Michael Chanca58c3a2007-05-03 13:22:52 -07002242 rc = bnx2_write_phy(bp, bp->mii_bmcr, BMCR_LOOPBACK | BMCR_FULLDPLX |
Michael Chanbc5a0692006-01-23 16:13:22 -08002243 BMCR_SPEED1000);
2244 spin_unlock_bh(&bp->phy_lock);
2245 if (rc)
2246 return rc;
2247
2248 for (i = 0; i < 10; i++) {
2249 if (bnx2_test_link(bp) == 0)
2250 break;
Michael Chan80be4432006-11-19 14:07:28 -08002251 msleep(100);
Michael Chanbc5a0692006-01-23 16:13:22 -08002252 }
2253
2254 mac_mode = REG_RD(bp, BNX2_EMAC_MODE);
2255 mac_mode &= ~(BNX2_EMAC_MODE_PORT | BNX2_EMAC_MODE_HALF_DUPLEX |
2256 BNX2_EMAC_MODE_MAC_LOOP | BNX2_EMAC_MODE_FORCE_LINK |
Michael Chan59b47d82006-11-19 14:10:45 -08002257 BNX2_EMAC_MODE_25G_MODE);
Michael Chanbc5a0692006-01-23 16:13:22 -08002258
2259 mac_mode |= BNX2_EMAC_MODE_PORT_GMII;
2260 REG_WR(bp, BNX2_EMAC_MODE, mac_mode);
2261 bp->link_up = 1;
2262 return 0;
2263}
2264
Michael Chanb6016b72005-05-26 13:03:09 -07002265static int
Michael Chana2f13892008-07-14 22:38:23 -07002266bnx2_fw_sync(struct bnx2 *bp, u32 msg_data, int ack, int silent)
Michael Chanb6016b72005-05-26 13:03:09 -07002267{
2268 int i;
2269 u32 val;
2270
Michael Chanb6016b72005-05-26 13:03:09 -07002271 bp->fw_wr_seq++;
2272 msg_data |= bp->fw_wr_seq;
2273
Michael Chan2726d6e2008-01-29 21:35:05 -08002274 bnx2_shmem_wr(bp, BNX2_DRV_MB, msg_data);
Michael Chanb6016b72005-05-26 13:03:09 -07002275
Michael Chana2f13892008-07-14 22:38:23 -07002276 if (!ack)
2277 return 0;
2278
Michael Chanb6016b72005-05-26 13:03:09 -07002279 /* wait for an acknowledgement. */
Michael Chanb090ae22006-01-23 16:07:10 -08002280 for (i = 0; i < (FW_ACK_TIME_OUT_MS / 10); i++) {
2281 msleep(10);
Michael Chanb6016b72005-05-26 13:03:09 -07002282
Michael Chan2726d6e2008-01-29 21:35:05 -08002283 val = bnx2_shmem_rd(bp, BNX2_FW_MB);
Michael Chanb6016b72005-05-26 13:03:09 -07002284
2285 if ((val & BNX2_FW_MSG_ACK) == (msg_data & BNX2_DRV_MSG_SEQ))
2286 break;
2287 }
Michael Chanb090ae22006-01-23 16:07:10 -08002288 if ((msg_data & BNX2_DRV_MSG_DATA) == BNX2_DRV_MSG_DATA_WAIT0)
2289 return 0;
Michael Chanb6016b72005-05-26 13:03:09 -07002290
2291 /* If we timed out, inform the firmware that this is the case. */
Michael Chanb090ae22006-01-23 16:07:10 -08002292 if ((val & BNX2_FW_MSG_ACK) != (msg_data & BNX2_DRV_MSG_SEQ)) {
2293 if (!silent)
2294 printk(KERN_ERR PFX "fw sync timeout, reset code = "
2295 "%x\n", msg_data);
Michael Chanb6016b72005-05-26 13:03:09 -07002296
2297 msg_data &= ~BNX2_DRV_MSG_CODE;
2298 msg_data |= BNX2_DRV_MSG_CODE_FW_TIMEOUT;
2299
Michael Chan2726d6e2008-01-29 21:35:05 -08002300 bnx2_shmem_wr(bp, BNX2_DRV_MB, msg_data);
Michael Chanb6016b72005-05-26 13:03:09 -07002301
Michael Chanb6016b72005-05-26 13:03:09 -07002302 return -EBUSY;
2303 }
2304
Michael Chanb090ae22006-01-23 16:07:10 -08002305 if ((val & BNX2_FW_MSG_STATUS_MASK) != BNX2_FW_MSG_STATUS_OK)
2306 return -EIO;
2307
Michael Chanb6016b72005-05-26 13:03:09 -07002308 return 0;
2309}
2310
Michael Chan59b47d82006-11-19 14:10:45 -08002311static int
2312bnx2_init_5709_context(struct bnx2 *bp)
2313{
2314 int i, ret = 0;
2315 u32 val;
2316
2317 val = BNX2_CTX_COMMAND_ENABLED | BNX2_CTX_COMMAND_MEM_INIT | (1 << 12);
2318 val |= (BCM_PAGE_BITS - 8) << 16;
2319 REG_WR(bp, BNX2_CTX_COMMAND, val);
Michael Chan641bdcd2007-06-04 21:22:24 -07002320 for (i = 0; i < 10; i++) {
2321 val = REG_RD(bp, BNX2_CTX_COMMAND);
2322 if (!(val & BNX2_CTX_COMMAND_MEM_INIT))
2323 break;
2324 udelay(2);
2325 }
2326 if (val & BNX2_CTX_COMMAND_MEM_INIT)
2327 return -EBUSY;
2328
Michael Chan59b47d82006-11-19 14:10:45 -08002329 for (i = 0; i < bp->ctx_pages; i++) {
2330 int j;
2331
Michael Chan352f7682008-05-02 16:57:26 -07002332 if (bp->ctx_blk[i])
2333 memset(bp->ctx_blk[i], 0, BCM_PAGE_SIZE);
2334 else
2335 return -ENOMEM;
2336
Michael Chan59b47d82006-11-19 14:10:45 -08002337 REG_WR(bp, BNX2_CTX_HOST_PAGE_TBL_DATA0,
2338 (bp->ctx_blk_mapping[i] & 0xffffffff) |
2339 BNX2_CTX_HOST_PAGE_TBL_DATA0_VALID);
2340 REG_WR(bp, BNX2_CTX_HOST_PAGE_TBL_DATA1,
2341 (u64) bp->ctx_blk_mapping[i] >> 32);
2342 REG_WR(bp, BNX2_CTX_HOST_PAGE_TBL_CTRL, i |
2343 BNX2_CTX_HOST_PAGE_TBL_CTRL_WRITE_REQ);
2344 for (j = 0; j < 10; j++) {
2345
2346 val = REG_RD(bp, BNX2_CTX_HOST_PAGE_TBL_CTRL);
2347 if (!(val & BNX2_CTX_HOST_PAGE_TBL_CTRL_WRITE_REQ))
2348 break;
2349 udelay(5);
2350 }
2351 if (val & BNX2_CTX_HOST_PAGE_TBL_CTRL_WRITE_REQ) {
2352 ret = -EBUSY;
2353 break;
2354 }
2355 }
2356 return ret;
2357}
2358
Michael Chanb6016b72005-05-26 13:03:09 -07002359static void
2360bnx2_init_context(struct bnx2 *bp)
2361{
2362 u32 vcid;
2363
2364 vcid = 96;
2365 while (vcid) {
2366 u32 vcid_addr, pcid_addr, offset;
Michael Chan7947b202007-06-04 21:17:10 -07002367 int i;
Michael Chanb6016b72005-05-26 13:03:09 -07002368
2369 vcid--;
2370
2371 if (CHIP_ID(bp) == CHIP_ID_5706_A0) {
2372 u32 new_vcid;
2373
2374 vcid_addr = GET_PCID_ADDR(vcid);
2375 if (vcid & 0x8) {
2376 new_vcid = 0x60 + (vcid & 0xf0) + (vcid & 0x7);
2377 }
2378 else {
2379 new_vcid = vcid;
2380 }
2381 pcid_addr = GET_PCID_ADDR(new_vcid);
2382 }
2383 else {
2384 vcid_addr = GET_CID_ADDR(vcid);
2385 pcid_addr = vcid_addr;
2386 }
2387
Michael Chan7947b202007-06-04 21:17:10 -07002388 for (i = 0; i < (CTX_SIZE / PHY_CTX_SIZE); i++) {
2389 vcid_addr += (i << PHY_CTX_SHIFT);
2390 pcid_addr += (i << PHY_CTX_SHIFT);
Michael Chanb6016b72005-05-26 13:03:09 -07002391
Michael Chan5d5d0012007-12-12 11:17:43 -08002392 REG_WR(bp, BNX2_CTX_VIRT_ADDR, vcid_addr);
Michael Chan7947b202007-06-04 21:17:10 -07002393 REG_WR(bp, BNX2_CTX_PAGE_TBL, pcid_addr);
2394
2395 /* Zero out the context. */
2396 for (offset = 0; offset < PHY_CTX_SIZE; offset += 4)
Michael Chan62a83132008-01-29 21:35:40 -08002397 bnx2_ctx_wr(bp, vcid_addr, offset, 0);
Michael Chanb6016b72005-05-26 13:03:09 -07002398 }
Michael Chanb6016b72005-05-26 13:03:09 -07002399 }
2400}
2401
2402static int
2403bnx2_alloc_bad_rbuf(struct bnx2 *bp)
2404{
2405 u16 *good_mbuf;
2406 u32 good_mbuf_cnt;
2407 u32 val;
2408
2409 good_mbuf = kmalloc(512 * sizeof(u16), GFP_KERNEL);
2410 if (good_mbuf == NULL) {
2411 printk(KERN_ERR PFX "Failed to allocate memory in "
2412 "bnx2_alloc_bad_rbuf\n");
2413 return -ENOMEM;
2414 }
2415
2416 REG_WR(bp, BNX2_MISC_ENABLE_SET_BITS,
2417 BNX2_MISC_ENABLE_SET_BITS_RX_MBUF_ENABLE);
2418
2419 good_mbuf_cnt = 0;
2420
2421 /* Allocate a bunch of mbufs and save the good ones in an array. */
Michael Chan2726d6e2008-01-29 21:35:05 -08002422 val = bnx2_reg_rd_ind(bp, BNX2_RBUF_STATUS1);
Michael Chanb6016b72005-05-26 13:03:09 -07002423 while (val & BNX2_RBUF_STATUS1_FREE_COUNT) {
Michael Chan2726d6e2008-01-29 21:35:05 -08002424 bnx2_reg_wr_ind(bp, BNX2_RBUF_COMMAND,
2425 BNX2_RBUF_COMMAND_ALLOC_REQ);
Michael Chanb6016b72005-05-26 13:03:09 -07002426
Michael Chan2726d6e2008-01-29 21:35:05 -08002427 val = bnx2_reg_rd_ind(bp, BNX2_RBUF_FW_BUF_ALLOC);
Michael Chanb6016b72005-05-26 13:03:09 -07002428
2429 val &= BNX2_RBUF_FW_BUF_ALLOC_VALUE;
2430
2431 /* The addresses with Bit 9 set are bad memory blocks. */
2432 if (!(val & (1 << 9))) {
2433 good_mbuf[good_mbuf_cnt] = (u16) val;
2434 good_mbuf_cnt++;
2435 }
2436
Michael Chan2726d6e2008-01-29 21:35:05 -08002437 val = bnx2_reg_rd_ind(bp, BNX2_RBUF_STATUS1);
Michael Chanb6016b72005-05-26 13:03:09 -07002438 }
2439
2440 /* Free the good ones back to the mbuf pool thus discarding
2441 * all the bad ones. */
2442 while (good_mbuf_cnt) {
2443 good_mbuf_cnt--;
2444
2445 val = good_mbuf[good_mbuf_cnt];
2446 val = (val << 9) | val | 1;
2447
Michael Chan2726d6e2008-01-29 21:35:05 -08002448 bnx2_reg_wr_ind(bp, BNX2_RBUF_FW_BUF_FREE, val);
Michael Chanb6016b72005-05-26 13:03:09 -07002449 }
2450 kfree(good_mbuf);
2451 return 0;
2452}
2453
2454static void
Benjamin Li5fcaed02008-07-14 22:39:52 -07002455bnx2_set_mac_addr(struct bnx2 *bp, u8 *mac_addr, u32 pos)
Michael Chanb6016b72005-05-26 13:03:09 -07002456{
2457 u32 val;
Michael Chanb6016b72005-05-26 13:03:09 -07002458
2459 val = (mac_addr[0] << 8) | mac_addr[1];
2460
Benjamin Li5fcaed02008-07-14 22:39:52 -07002461 REG_WR(bp, BNX2_EMAC_MAC_MATCH0 + (pos * 8), val);
Michael Chanb6016b72005-05-26 13:03:09 -07002462
Jeff Garzik6aa20a22006-09-13 13:24:59 -04002463 val = (mac_addr[2] << 24) | (mac_addr[3] << 16) |
Michael Chanb6016b72005-05-26 13:03:09 -07002464 (mac_addr[4] << 8) | mac_addr[5];
2465
Benjamin Li5fcaed02008-07-14 22:39:52 -07002466 REG_WR(bp, BNX2_EMAC_MAC_MATCH1 + (pos * 8), val);
Michael Chanb6016b72005-05-26 13:03:09 -07002467}
2468
2469static inline int
Michael Chanbb4f98a2008-06-19 16:38:19 -07002470bnx2_alloc_rx_page(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr, u16 index)
Michael Chan47bf4242007-12-12 11:19:12 -08002471{
2472 dma_addr_t mapping;
Michael Chanbb4f98a2008-06-19 16:38:19 -07002473 struct sw_pg *rx_pg = &rxr->rx_pg_ring[index];
Michael Chan47bf4242007-12-12 11:19:12 -08002474 struct rx_bd *rxbd =
Michael Chanbb4f98a2008-06-19 16:38:19 -07002475 &rxr->rx_pg_desc_ring[RX_RING(index)][RX_IDX(index)];
Michael Chan47bf4242007-12-12 11:19:12 -08002476 struct page *page = alloc_page(GFP_ATOMIC);
2477
2478 if (!page)
2479 return -ENOMEM;
2480 mapping = pci_map_page(bp->pdev, page, 0, PAGE_SIZE,
2481 PCI_DMA_FROMDEVICE);
2482 rx_pg->page = page;
2483 pci_unmap_addr_set(rx_pg, mapping, mapping);
2484 rxbd->rx_bd_haddr_hi = (u64) mapping >> 32;
2485 rxbd->rx_bd_haddr_lo = (u64) mapping & 0xffffffff;
2486 return 0;
2487}
2488
2489static void
Michael Chanbb4f98a2008-06-19 16:38:19 -07002490bnx2_free_rx_page(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr, u16 index)
Michael Chan47bf4242007-12-12 11:19:12 -08002491{
Michael Chanbb4f98a2008-06-19 16:38:19 -07002492 struct sw_pg *rx_pg = &rxr->rx_pg_ring[index];
Michael Chan47bf4242007-12-12 11:19:12 -08002493 struct page *page = rx_pg->page;
2494
2495 if (!page)
2496 return;
2497
2498 pci_unmap_page(bp->pdev, pci_unmap_addr(rx_pg, mapping), PAGE_SIZE,
2499 PCI_DMA_FROMDEVICE);
2500
2501 __free_page(page);
2502 rx_pg->page = NULL;
2503}
2504
2505static inline int
Michael Chanbb4f98a2008-06-19 16:38:19 -07002506bnx2_alloc_rx_skb(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr, u16 index)
Michael Chanb6016b72005-05-26 13:03:09 -07002507{
2508 struct sk_buff *skb;
Michael Chanbb4f98a2008-06-19 16:38:19 -07002509 struct sw_bd *rx_buf = &rxr->rx_buf_ring[index];
Michael Chanb6016b72005-05-26 13:03:09 -07002510 dma_addr_t mapping;
Michael Chanbb4f98a2008-06-19 16:38:19 -07002511 struct rx_bd *rxbd = &rxr->rx_desc_ring[RX_RING(index)][RX_IDX(index)];
Michael Chanb6016b72005-05-26 13:03:09 -07002512 unsigned long align;
2513
Michael Chan932f3772006-08-15 01:39:36 -07002514 skb = netdev_alloc_skb(bp->dev, bp->rx_buf_size);
Michael Chanb6016b72005-05-26 13:03:09 -07002515 if (skb == NULL) {
2516 return -ENOMEM;
2517 }
2518
Michael Chan59b47d82006-11-19 14:10:45 -08002519 if (unlikely((align = (unsigned long) skb->data & (BNX2_RX_ALIGN - 1))))
2520 skb_reserve(skb, BNX2_RX_ALIGN - align);
Michael Chanb6016b72005-05-26 13:03:09 -07002521
Michael Chanb6016b72005-05-26 13:03:09 -07002522 mapping = pci_map_single(bp->pdev, skb->data, bp->rx_buf_use_size,
2523 PCI_DMA_FROMDEVICE);
2524
2525 rx_buf->skb = skb;
2526 pci_unmap_addr_set(rx_buf, mapping, mapping);
2527
2528 rxbd->rx_bd_haddr_hi = (u64) mapping >> 32;
2529 rxbd->rx_bd_haddr_lo = (u64) mapping & 0xffffffff;
2530
Michael Chanbb4f98a2008-06-19 16:38:19 -07002531 rxr->rx_prod_bseq += bp->rx_buf_use_size;
Michael Chanb6016b72005-05-26 13:03:09 -07002532
2533 return 0;
2534}
2535
Michael Chanda3e4fb2007-05-03 13:24:23 -07002536static int
Michael Chan35efa7c2007-12-20 19:56:37 -08002537bnx2_phy_event_is_set(struct bnx2 *bp, struct bnx2_napi *bnapi, u32 event)
Michael Chanda3e4fb2007-05-03 13:24:23 -07002538{
Michael Chan43e80b82008-06-19 16:41:08 -07002539 struct status_block *sblk = bnapi->status_blk.msi;
Michael Chanda3e4fb2007-05-03 13:24:23 -07002540 u32 new_link_state, old_link_state;
2541 int is_set = 1;
2542
2543 new_link_state = sblk->status_attn_bits & event;
2544 old_link_state = sblk->status_attn_bits_ack & event;
2545 if (new_link_state != old_link_state) {
2546 if (new_link_state)
2547 REG_WR(bp, BNX2_PCICFG_STATUS_BIT_SET_CMD, event);
2548 else
2549 REG_WR(bp, BNX2_PCICFG_STATUS_BIT_CLEAR_CMD, event);
2550 } else
2551 is_set = 0;
2552
2553 return is_set;
2554}
2555
Michael Chanb6016b72005-05-26 13:03:09 -07002556static void
Michael Chan35efa7c2007-12-20 19:56:37 -08002557bnx2_phy_int(struct bnx2 *bp, struct bnx2_napi *bnapi)
Michael Chanb6016b72005-05-26 13:03:09 -07002558{
Michael Chan74ecc622008-05-02 16:56:16 -07002559 spin_lock(&bp->phy_lock);
2560
2561 if (bnx2_phy_event_is_set(bp, bnapi, STATUS_ATTN_BITS_LINK_STATE))
Michael Chanb6016b72005-05-26 13:03:09 -07002562 bnx2_set_link(bp);
Michael Chan35efa7c2007-12-20 19:56:37 -08002563 if (bnx2_phy_event_is_set(bp, bnapi, STATUS_ATTN_BITS_TIMER_ABORT))
Michael Chan0d8a6572007-07-07 22:49:43 -07002564 bnx2_set_remote_link(bp);
2565
Michael Chan74ecc622008-05-02 16:56:16 -07002566 spin_unlock(&bp->phy_lock);
2567
Michael Chanb6016b72005-05-26 13:03:09 -07002568}
2569
Michael Chanead72702007-12-20 19:55:39 -08002570static inline u16
Michael Chan35efa7c2007-12-20 19:56:37 -08002571bnx2_get_hw_tx_cons(struct bnx2_napi *bnapi)
Michael Chanead72702007-12-20 19:55:39 -08002572{
2573 u16 cons;
2574
Michael Chan43e80b82008-06-19 16:41:08 -07002575 /* Tell compiler that status block fields can change. */
2576 barrier();
2577 cons = *bnapi->hw_tx_cons_ptr;
Michael Chanead72702007-12-20 19:55:39 -08002578 if (unlikely((cons & MAX_TX_DESC_CNT) == MAX_TX_DESC_CNT))
2579 cons++;
2580 return cons;
2581}
2582
Michael Chan57851d82007-12-20 20:01:44 -08002583static int
2584bnx2_tx_int(struct bnx2 *bp, struct bnx2_napi *bnapi, int budget)
Michael Chanb6016b72005-05-26 13:03:09 -07002585{
Michael Chan35e90102008-06-19 16:37:42 -07002586 struct bnx2_tx_ring_info *txr = &bnapi->tx_ring;
Michael Chanb6016b72005-05-26 13:03:09 -07002587 u16 hw_cons, sw_cons, sw_ring_cons;
Benjamin Li706bf242008-07-18 17:55:11 -07002588 int tx_pkt = 0, index;
2589 struct netdev_queue *txq;
2590
2591 index = (bnapi - bp->bnx2_napi);
2592 txq = netdev_get_tx_queue(bp->dev, index);
Michael Chanb6016b72005-05-26 13:03:09 -07002593
Michael Chan35efa7c2007-12-20 19:56:37 -08002594 hw_cons = bnx2_get_hw_tx_cons(bnapi);
Michael Chan35e90102008-06-19 16:37:42 -07002595 sw_cons = txr->tx_cons;
Michael Chanb6016b72005-05-26 13:03:09 -07002596
2597 while (sw_cons != hw_cons) {
2598 struct sw_bd *tx_buf;
2599 struct sk_buff *skb;
2600 int i, last;
2601
2602 sw_ring_cons = TX_RING_IDX(sw_cons);
2603
Michael Chan35e90102008-06-19 16:37:42 -07002604 tx_buf = &txr->tx_buf_ring[sw_ring_cons];
Michael Chanb6016b72005-05-26 13:03:09 -07002605 skb = tx_buf->skb;
Arjan van de Ven1d39ed52006-12-12 14:06:23 +01002606
Michael Chanb6016b72005-05-26 13:03:09 -07002607 /* partial BD completions possible with TSO packets */
Herbert Xu89114af2006-07-08 13:34:32 -07002608 if (skb_is_gso(skb)) {
Michael Chanb6016b72005-05-26 13:03:09 -07002609 u16 last_idx, last_ring_idx;
2610
2611 last_idx = sw_cons +
2612 skb_shinfo(skb)->nr_frags + 1;
2613 last_ring_idx = sw_ring_cons +
2614 skb_shinfo(skb)->nr_frags + 1;
2615 if (unlikely(last_ring_idx >= MAX_TX_DESC_CNT)) {
2616 last_idx++;
2617 }
2618 if (((s16) ((s16) last_idx - (s16) hw_cons)) > 0) {
2619 break;
2620 }
2621 }
Arjan van de Ven1d39ed52006-12-12 14:06:23 +01002622
Michael Chanb6016b72005-05-26 13:03:09 -07002623 pci_unmap_single(bp->pdev, pci_unmap_addr(tx_buf, mapping),
2624 skb_headlen(skb), PCI_DMA_TODEVICE);
2625
2626 tx_buf->skb = NULL;
2627 last = skb_shinfo(skb)->nr_frags;
2628
2629 for (i = 0; i < last; i++) {
2630 sw_cons = NEXT_TX_BD(sw_cons);
2631
2632 pci_unmap_page(bp->pdev,
2633 pci_unmap_addr(
Michael Chan35e90102008-06-19 16:37:42 -07002634 &txr->tx_buf_ring[TX_RING_IDX(sw_cons)],
Michael Chanb6016b72005-05-26 13:03:09 -07002635 mapping),
2636 skb_shinfo(skb)->frags[i].size,
2637 PCI_DMA_TODEVICE);
2638 }
2639
2640 sw_cons = NEXT_TX_BD(sw_cons);
2641
Michael Chan745720e2006-06-29 12:37:41 -07002642 dev_kfree_skb(skb);
Michael Chan57851d82007-12-20 20:01:44 -08002643 tx_pkt++;
2644 if (tx_pkt == budget)
2645 break;
Michael Chanb6016b72005-05-26 13:03:09 -07002646
Michael Chan35efa7c2007-12-20 19:56:37 -08002647 hw_cons = bnx2_get_hw_tx_cons(bnapi);
Michael Chanb6016b72005-05-26 13:03:09 -07002648 }
2649
Michael Chan35e90102008-06-19 16:37:42 -07002650 txr->hw_tx_cons = hw_cons;
2651 txr->tx_cons = sw_cons;
Benjamin Li706bf242008-07-18 17:55:11 -07002652
Michael Chan2f8af122006-08-15 01:39:10 -07002653 /* Need to make the tx_cons update visible to bnx2_start_xmit()
Benjamin Li706bf242008-07-18 17:55:11 -07002654 * before checking for netif_tx_queue_stopped(). Without the
Michael Chan2f8af122006-08-15 01:39:10 -07002655 * memory barrier, there is a small possibility that bnx2_start_xmit()
2656 * will miss it and cause the queue to be stopped forever.
2657 */
2658 smp_mb();
Michael Chanb6016b72005-05-26 13:03:09 -07002659
Benjamin Li706bf242008-07-18 17:55:11 -07002660 if (unlikely(netif_tx_queue_stopped(txq)) &&
Michael Chan35e90102008-06-19 16:37:42 -07002661 (bnx2_tx_avail(bp, txr) > bp->tx_wake_thresh)) {
Benjamin Li706bf242008-07-18 17:55:11 -07002662 __netif_tx_lock(txq, smp_processor_id());
2663 if ((netif_tx_queue_stopped(txq)) &&
Michael Chan35e90102008-06-19 16:37:42 -07002664 (bnx2_tx_avail(bp, txr) > bp->tx_wake_thresh))
Benjamin Li706bf242008-07-18 17:55:11 -07002665 netif_tx_wake_queue(txq);
2666 __netif_tx_unlock(txq);
Michael Chanb6016b72005-05-26 13:03:09 -07002667 }
Benjamin Li706bf242008-07-18 17:55:11 -07002668
Michael Chan57851d82007-12-20 20:01:44 -08002669 return tx_pkt;
Michael Chanb6016b72005-05-26 13:03:09 -07002670}
2671
Michael Chan1db82f22007-12-12 11:19:35 -08002672static void
Michael Chanbb4f98a2008-06-19 16:38:19 -07002673bnx2_reuse_rx_skb_pages(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr,
Michael Chana1f60192007-12-20 19:57:19 -08002674 struct sk_buff *skb, int count)
Michael Chan1db82f22007-12-12 11:19:35 -08002675{
2676 struct sw_pg *cons_rx_pg, *prod_rx_pg;
2677 struct rx_bd *cons_bd, *prod_bd;
2678 dma_addr_t mapping;
2679 int i;
Michael Chanbb4f98a2008-06-19 16:38:19 -07002680 u16 hw_prod = rxr->rx_pg_prod, prod;
2681 u16 cons = rxr->rx_pg_cons;
Michael Chan1db82f22007-12-12 11:19:35 -08002682
2683 for (i = 0; i < count; i++) {
2684 prod = RX_PG_RING_IDX(hw_prod);
2685
Michael Chanbb4f98a2008-06-19 16:38:19 -07002686 prod_rx_pg = &rxr->rx_pg_ring[prod];
2687 cons_rx_pg = &rxr->rx_pg_ring[cons];
2688 cons_bd = &rxr->rx_pg_desc_ring[RX_RING(cons)][RX_IDX(cons)];
2689 prod_bd = &rxr->rx_pg_desc_ring[RX_RING(prod)][RX_IDX(prod)];
Michael Chan1db82f22007-12-12 11:19:35 -08002690
2691 if (i == 0 && skb) {
2692 struct page *page;
2693 struct skb_shared_info *shinfo;
2694
2695 shinfo = skb_shinfo(skb);
2696 shinfo->nr_frags--;
2697 page = shinfo->frags[shinfo->nr_frags].page;
2698 shinfo->frags[shinfo->nr_frags].page = NULL;
2699 mapping = pci_map_page(bp->pdev, page, 0, PAGE_SIZE,
2700 PCI_DMA_FROMDEVICE);
2701 cons_rx_pg->page = page;
2702 pci_unmap_addr_set(cons_rx_pg, mapping, mapping);
2703 dev_kfree_skb(skb);
2704 }
2705 if (prod != cons) {
2706 prod_rx_pg->page = cons_rx_pg->page;
2707 cons_rx_pg->page = NULL;
2708 pci_unmap_addr_set(prod_rx_pg, mapping,
2709 pci_unmap_addr(cons_rx_pg, mapping));
2710
2711 prod_bd->rx_bd_haddr_hi = cons_bd->rx_bd_haddr_hi;
2712 prod_bd->rx_bd_haddr_lo = cons_bd->rx_bd_haddr_lo;
2713
2714 }
2715 cons = RX_PG_RING_IDX(NEXT_RX_BD(cons));
2716 hw_prod = NEXT_RX_BD(hw_prod);
2717 }
Michael Chanbb4f98a2008-06-19 16:38:19 -07002718 rxr->rx_pg_prod = hw_prod;
2719 rxr->rx_pg_cons = cons;
Michael Chan1db82f22007-12-12 11:19:35 -08002720}
2721
Michael Chanb6016b72005-05-26 13:03:09 -07002722static inline void
Michael Chanbb4f98a2008-06-19 16:38:19 -07002723bnx2_reuse_rx_skb(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr,
2724 struct sk_buff *skb, u16 cons, u16 prod)
Michael Chanb6016b72005-05-26 13:03:09 -07002725{
Michael Chan236b6392006-03-20 17:49:02 -08002726 struct sw_bd *cons_rx_buf, *prod_rx_buf;
2727 struct rx_bd *cons_bd, *prod_bd;
2728
Michael Chanbb4f98a2008-06-19 16:38:19 -07002729 cons_rx_buf = &rxr->rx_buf_ring[cons];
2730 prod_rx_buf = &rxr->rx_buf_ring[prod];
Michael Chanb6016b72005-05-26 13:03:09 -07002731
2732 pci_dma_sync_single_for_device(bp->pdev,
2733 pci_unmap_addr(cons_rx_buf, mapping),
Benjamin Li601d3d12008-05-16 22:19:35 -07002734 BNX2_RX_OFFSET + BNX2_RX_COPY_THRESH, PCI_DMA_FROMDEVICE);
Michael Chanb6016b72005-05-26 13:03:09 -07002735
Michael Chanbb4f98a2008-06-19 16:38:19 -07002736 rxr->rx_prod_bseq += bp->rx_buf_use_size;
Michael Chan236b6392006-03-20 17:49:02 -08002737
2738 prod_rx_buf->skb = skb;
2739
2740 if (cons == prod)
2741 return;
2742
Michael Chanb6016b72005-05-26 13:03:09 -07002743 pci_unmap_addr_set(prod_rx_buf, mapping,
2744 pci_unmap_addr(cons_rx_buf, mapping));
2745
Michael Chanbb4f98a2008-06-19 16:38:19 -07002746 cons_bd = &rxr->rx_desc_ring[RX_RING(cons)][RX_IDX(cons)];
2747 prod_bd = &rxr->rx_desc_ring[RX_RING(prod)][RX_IDX(prod)];
Michael Chan236b6392006-03-20 17:49:02 -08002748 prod_bd->rx_bd_haddr_hi = cons_bd->rx_bd_haddr_hi;
2749 prod_bd->rx_bd_haddr_lo = cons_bd->rx_bd_haddr_lo;
Michael Chanb6016b72005-05-26 13:03:09 -07002750}
2751
Michael Chan85833c62007-12-12 11:17:01 -08002752static int
Michael Chanbb4f98a2008-06-19 16:38:19 -07002753bnx2_rx_skb(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr, struct sk_buff *skb,
Michael Chana1f60192007-12-20 19:57:19 -08002754 unsigned int len, unsigned int hdr_len, dma_addr_t dma_addr,
2755 u32 ring_idx)
Michael Chan85833c62007-12-12 11:17:01 -08002756{
2757 int err;
2758 u16 prod = ring_idx & 0xffff;
2759
Michael Chanbb4f98a2008-06-19 16:38:19 -07002760 err = bnx2_alloc_rx_skb(bp, rxr, prod);
Michael Chan85833c62007-12-12 11:17:01 -08002761 if (unlikely(err)) {
Michael Chanbb4f98a2008-06-19 16:38:19 -07002762 bnx2_reuse_rx_skb(bp, rxr, skb, (u16) (ring_idx >> 16), prod);
Michael Chan1db82f22007-12-12 11:19:35 -08002763 if (hdr_len) {
2764 unsigned int raw_len = len + 4;
2765 int pages = PAGE_ALIGN(raw_len - hdr_len) >> PAGE_SHIFT;
2766
Michael Chanbb4f98a2008-06-19 16:38:19 -07002767 bnx2_reuse_rx_skb_pages(bp, rxr, NULL, pages);
Michael Chan1db82f22007-12-12 11:19:35 -08002768 }
Michael Chan85833c62007-12-12 11:17:01 -08002769 return err;
2770 }
2771
Benjamin Lid89cb6a2008-05-16 22:18:57 -07002772 skb_reserve(skb, BNX2_RX_OFFSET);
Michael Chan85833c62007-12-12 11:17:01 -08002773 pci_unmap_single(bp->pdev, dma_addr, bp->rx_buf_use_size,
2774 PCI_DMA_FROMDEVICE);
2775
Michael Chan1db82f22007-12-12 11:19:35 -08002776 if (hdr_len == 0) {
2777 skb_put(skb, len);
2778 return 0;
2779 } else {
2780 unsigned int i, frag_len, frag_size, pages;
2781 struct sw_pg *rx_pg;
Michael Chanbb4f98a2008-06-19 16:38:19 -07002782 u16 pg_cons = rxr->rx_pg_cons;
2783 u16 pg_prod = rxr->rx_pg_prod;
Michael Chan1db82f22007-12-12 11:19:35 -08002784
2785 frag_size = len + 4 - hdr_len;
2786 pages = PAGE_ALIGN(frag_size) >> PAGE_SHIFT;
2787 skb_put(skb, hdr_len);
2788
2789 for (i = 0; i < pages; i++) {
2790 frag_len = min(frag_size, (unsigned int) PAGE_SIZE);
2791 if (unlikely(frag_len <= 4)) {
2792 unsigned int tail = 4 - frag_len;
2793
Michael Chanbb4f98a2008-06-19 16:38:19 -07002794 rxr->rx_pg_cons = pg_cons;
2795 rxr->rx_pg_prod = pg_prod;
2796 bnx2_reuse_rx_skb_pages(bp, rxr, NULL,
Michael Chana1f60192007-12-20 19:57:19 -08002797 pages - i);
Michael Chan1db82f22007-12-12 11:19:35 -08002798 skb->len -= tail;
2799 if (i == 0) {
2800 skb->tail -= tail;
2801 } else {
2802 skb_frag_t *frag =
2803 &skb_shinfo(skb)->frags[i - 1];
2804 frag->size -= tail;
2805 skb->data_len -= tail;
2806 skb->truesize -= tail;
2807 }
2808 return 0;
2809 }
Michael Chanbb4f98a2008-06-19 16:38:19 -07002810 rx_pg = &rxr->rx_pg_ring[pg_cons];
Michael Chan1db82f22007-12-12 11:19:35 -08002811
2812 pci_unmap_page(bp->pdev, pci_unmap_addr(rx_pg, mapping),
2813 PAGE_SIZE, PCI_DMA_FROMDEVICE);
2814
2815 if (i == pages - 1)
2816 frag_len -= 4;
2817
2818 skb_fill_page_desc(skb, i, rx_pg->page, 0, frag_len);
2819 rx_pg->page = NULL;
2820
Michael Chanbb4f98a2008-06-19 16:38:19 -07002821 err = bnx2_alloc_rx_page(bp, rxr,
2822 RX_PG_RING_IDX(pg_prod));
Michael Chan1db82f22007-12-12 11:19:35 -08002823 if (unlikely(err)) {
Michael Chanbb4f98a2008-06-19 16:38:19 -07002824 rxr->rx_pg_cons = pg_cons;
2825 rxr->rx_pg_prod = pg_prod;
2826 bnx2_reuse_rx_skb_pages(bp, rxr, skb,
Michael Chana1f60192007-12-20 19:57:19 -08002827 pages - i);
Michael Chan1db82f22007-12-12 11:19:35 -08002828 return err;
2829 }
2830
2831 frag_size -= frag_len;
2832 skb->data_len += frag_len;
2833 skb->truesize += frag_len;
2834 skb->len += frag_len;
2835
2836 pg_prod = NEXT_RX_BD(pg_prod);
2837 pg_cons = RX_PG_RING_IDX(NEXT_RX_BD(pg_cons));
2838 }
Michael Chanbb4f98a2008-06-19 16:38:19 -07002839 rxr->rx_pg_prod = pg_prod;
2840 rxr->rx_pg_cons = pg_cons;
Michael Chan1db82f22007-12-12 11:19:35 -08002841 }
Michael Chan85833c62007-12-12 11:17:01 -08002842 return 0;
2843}
2844
Michael Chanc09c2622007-12-10 17:18:37 -08002845static inline u16
Michael Chan35efa7c2007-12-20 19:56:37 -08002846bnx2_get_hw_rx_cons(struct bnx2_napi *bnapi)
Michael Chanc09c2622007-12-10 17:18:37 -08002847{
Michael Chanbb4f98a2008-06-19 16:38:19 -07002848 u16 cons;
2849
Michael Chan43e80b82008-06-19 16:41:08 -07002850 /* Tell compiler that status block fields can change. */
2851 barrier();
2852 cons = *bnapi->hw_rx_cons_ptr;
Michael Chanc09c2622007-12-10 17:18:37 -08002853 if (unlikely((cons & MAX_RX_DESC_CNT) == MAX_RX_DESC_CNT))
2854 cons++;
2855 return cons;
2856}
2857
Michael Chanb6016b72005-05-26 13:03:09 -07002858static int
Michael Chan35efa7c2007-12-20 19:56:37 -08002859bnx2_rx_int(struct bnx2 *bp, struct bnx2_napi *bnapi, int budget)
Michael Chanb6016b72005-05-26 13:03:09 -07002860{
Michael Chanbb4f98a2008-06-19 16:38:19 -07002861 struct bnx2_rx_ring_info *rxr = &bnapi->rx_ring;
Michael Chanb6016b72005-05-26 13:03:09 -07002862 u16 hw_cons, sw_cons, sw_ring_cons, sw_prod, sw_ring_prod;
2863 struct l2_fhdr *rx_hdr;
Michael Chan1db82f22007-12-12 11:19:35 -08002864 int rx_pkt = 0, pg_ring_used = 0;
Michael Chanb6016b72005-05-26 13:03:09 -07002865
Michael Chan35efa7c2007-12-20 19:56:37 -08002866 hw_cons = bnx2_get_hw_rx_cons(bnapi);
Michael Chanbb4f98a2008-06-19 16:38:19 -07002867 sw_cons = rxr->rx_cons;
2868 sw_prod = rxr->rx_prod;
Michael Chanb6016b72005-05-26 13:03:09 -07002869
2870 /* Memory barrier necessary as speculative reads of the rx
2871 * buffer can be ahead of the index in the status block
2872 */
2873 rmb();
2874 while (sw_cons != hw_cons) {
Michael Chan1db82f22007-12-12 11:19:35 -08002875 unsigned int len, hdr_len;
Michael Chanade2bfe2006-01-23 16:09:51 -08002876 u32 status;
Michael Chanb6016b72005-05-26 13:03:09 -07002877 struct sw_bd *rx_buf;
2878 struct sk_buff *skb;
Michael Chan236b6392006-03-20 17:49:02 -08002879 dma_addr_t dma_addr;
Michael Chanb6016b72005-05-26 13:03:09 -07002880
2881 sw_ring_cons = RX_RING_IDX(sw_cons);
2882 sw_ring_prod = RX_RING_IDX(sw_prod);
2883
Michael Chanbb4f98a2008-06-19 16:38:19 -07002884 rx_buf = &rxr->rx_buf_ring[sw_ring_cons];
Michael Chanb6016b72005-05-26 13:03:09 -07002885 skb = rx_buf->skb;
Michael Chan236b6392006-03-20 17:49:02 -08002886
2887 rx_buf->skb = NULL;
2888
2889 dma_addr = pci_unmap_addr(rx_buf, mapping);
2890
2891 pci_dma_sync_single_for_cpu(bp->pdev, dma_addr,
Benjamin Li601d3d12008-05-16 22:19:35 -07002892 BNX2_RX_OFFSET + BNX2_RX_COPY_THRESH,
2893 PCI_DMA_FROMDEVICE);
Michael Chanb6016b72005-05-26 13:03:09 -07002894
2895 rx_hdr = (struct l2_fhdr *) skb->data;
Michael Chan1db82f22007-12-12 11:19:35 -08002896 len = rx_hdr->l2_fhdr_pkt_len;
Michael Chanb6016b72005-05-26 13:03:09 -07002897
Michael Chanade2bfe2006-01-23 16:09:51 -08002898 if ((status = rx_hdr->l2_fhdr_status) &
Michael Chanb6016b72005-05-26 13:03:09 -07002899 (L2_FHDR_ERRORS_BAD_CRC |
2900 L2_FHDR_ERRORS_PHY_DECODE |
2901 L2_FHDR_ERRORS_ALIGNMENT |
2902 L2_FHDR_ERRORS_TOO_SHORT |
2903 L2_FHDR_ERRORS_GIANT_FRAME)) {
2904
Michael Chanbb4f98a2008-06-19 16:38:19 -07002905 bnx2_reuse_rx_skb(bp, rxr, skb, sw_ring_cons,
Michael Chana1f60192007-12-20 19:57:19 -08002906 sw_ring_prod);
Michael Chan85833c62007-12-12 11:17:01 -08002907 goto next_rx;
Michael Chanb6016b72005-05-26 13:03:09 -07002908 }
Michael Chan1db82f22007-12-12 11:19:35 -08002909 hdr_len = 0;
2910 if (status & L2_FHDR_STATUS_SPLIT) {
2911 hdr_len = rx_hdr->l2_fhdr_ip_xsum;
2912 pg_ring_used = 1;
2913 } else if (len > bp->rx_jumbo_thresh) {
2914 hdr_len = bp->rx_jumbo_thresh;
2915 pg_ring_used = 1;
2916 }
2917
2918 len -= 4;
Michael Chanb6016b72005-05-26 13:03:09 -07002919
Michael Chan5d5d0012007-12-12 11:17:43 -08002920 if (len <= bp->rx_copy_thresh) {
Michael Chanb6016b72005-05-26 13:03:09 -07002921 struct sk_buff *new_skb;
2922
Michael Chan932f3772006-08-15 01:39:36 -07002923 new_skb = netdev_alloc_skb(bp->dev, len + 2);
Michael Chan85833c62007-12-12 11:17:01 -08002924 if (new_skb == NULL) {
Michael Chanbb4f98a2008-06-19 16:38:19 -07002925 bnx2_reuse_rx_skb(bp, rxr, skb, sw_ring_cons,
Michael Chan85833c62007-12-12 11:17:01 -08002926 sw_ring_prod);
2927 goto next_rx;
2928 }
Michael Chanb6016b72005-05-26 13:03:09 -07002929
2930 /* aligned copy */
Benjamin Lid89cb6a2008-05-16 22:18:57 -07002931 skb_copy_from_linear_data_offset(skb,
2932 BNX2_RX_OFFSET - 2,
Arnaldo Carvalho de Melod626f622007-03-27 18:55:52 -03002933 new_skb->data, len + 2);
Michael Chanb6016b72005-05-26 13:03:09 -07002934 skb_reserve(new_skb, 2);
2935 skb_put(new_skb, len);
Michael Chanb6016b72005-05-26 13:03:09 -07002936
Michael Chanbb4f98a2008-06-19 16:38:19 -07002937 bnx2_reuse_rx_skb(bp, rxr, skb,
Michael Chanb6016b72005-05-26 13:03:09 -07002938 sw_ring_cons, sw_ring_prod);
2939
2940 skb = new_skb;
Michael Chanbb4f98a2008-06-19 16:38:19 -07002941 } else if (unlikely(bnx2_rx_skb(bp, rxr, skb, len, hdr_len,
Michael Chana1f60192007-12-20 19:57:19 -08002942 dma_addr, (sw_ring_cons << 16) | sw_ring_prod)))
Michael Chanb6016b72005-05-26 13:03:09 -07002943 goto next_rx;
Michael Chanb6016b72005-05-26 13:03:09 -07002944
2945 skb->protocol = eth_type_trans(skb, bp->dev);
2946
2947 if ((len > (bp->dev->mtu + ETH_HLEN)) &&
Alexey Dobriyand1e100b2006-06-11 20:57:17 -07002948 (ntohs(skb->protocol) != 0x8100)) {
Michael Chanb6016b72005-05-26 13:03:09 -07002949
Michael Chan745720e2006-06-29 12:37:41 -07002950 dev_kfree_skb(skb);
Michael Chanb6016b72005-05-26 13:03:09 -07002951 goto next_rx;
2952
2953 }
2954
Michael Chanb6016b72005-05-26 13:03:09 -07002955 skb->ip_summed = CHECKSUM_NONE;
2956 if (bp->rx_csum &&
2957 (status & (L2_FHDR_STATUS_TCP_SEGMENT |
2958 L2_FHDR_STATUS_UDP_DATAGRAM))) {
2959
Michael Chanade2bfe2006-01-23 16:09:51 -08002960 if (likely((status & (L2_FHDR_ERRORS_TCP_XSUM |
2961 L2_FHDR_ERRORS_UDP_XSUM)) == 0))
Michael Chanb6016b72005-05-26 13:03:09 -07002962 skb->ip_summed = CHECKSUM_UNNECESSARY;
2963 }
2964
2965#ifdef BCM_VLAN
Al Viro79ea13c2008-01-24 02:06:46 -08002966 if ((status & L2_FHDR_STATUS_L2_VLAN_TAG) && bp->vlgrp) {
Michael Chanb6016b72005-05-26 13:03:09 -07002967 vlan_hwaccel_receive_skb(skb, bp->vlgrp,
2968 rx_hdr->l2_fhdr_vlan_tag);
2969 }
2970 else
2971#endif
2972 netif_receive_skb(skb);
2973
2974 bp->dev->last_rx = jiffies;
2975 rx_pkt++;
2976
2977next_rx:
Michael Chanb6016b72005-05-26 13:03:09 -07002978 sw_cons = NEXT_RX_BD(sw_cons);
2979 sw_prod = NEXT_RX_BD(sw_prod);
2980
2981 if ((rx_pkt == budget))
2982 break;
Michael Chanf4e418f2005-11-04 08:53:48 -08002983
2984 /* Refresh hw_cons to see if there is new work */
2985 if (sw_cons == hw_cons) {
Michael Chan35efa7c2007-12-20 19:56:37 -08002986 hw_cons = bnx2_get_hw_rx_cons(bnapi);
Michael Chanf4e418f2005-11-04 08:53:48 -08002987 rmb();
2988 }
Michael Chanb6016b72005-05-26 13:03:09 -07002989 }
Michael Chanbb4f98a2008-06-19 16:38:19 -07002990 rxr->rx_cons = sw_cons;
2991 rxr->rx_prod = sw_prod;
Michael Chanb6016b72005-05-26 13:03:09 -07002992
Michael Chan1db82f22007-12-12 11:19:35 -08002993 if (pg_ring_used)
Michael Chanbb4f98a2008-06-19 16:38:19 -07002994 REG_WR16(bp, rxr->rx_pg_bidx_addr, rxr->rx_pg_prod);
Michael Chan1db82f22007-12-12 11:19:35 -08002995
Michael Chanbb4f98a2008-06-19 16:38:19 -07002996 REG_WR16(bp, rxr->rx_bidx_addr, sw_prod);
Michael Chanb6016b72005-05-26 13:03:09 -07002997
Michael Chanbb4f98a2008-06-19 16:38:19 -07002998 REG_WR(bp, rxr->rx_bseq_addr, rxr->rx_prod_bseq);
Michael Chanb6016b72005-05-26 13:03:09 -07002999
3000 mmiowb();
3001
3002 return rx_pkt;
3003
3004}
3005
3006/* MSI ISR - The only difference between this and the INTx ISR
3007 * is that the MSI interrupt is always serviced.
3008 */
3009static irqreturn_t
David Howells7d12e782006-10-05 14:55:46 +01003010bnx2_msi(int irq, void *dev_instance)
Michael Chanb6016b72005-05-26 13:03:09 -07003011{
Michael Chanf0ea2e62008-06-19 16:41:57 -07003012 struct bnx2_napi *bnapi = dev_instance;
3013 struct bnx2 *bp = bnapi->bp;
3014 struct net_device *dev = bp->dev;
Michael Chanb6016b72005-05-26 13:03:09 -07003015
Michael Chan43e80b82008-06-19 16:41:08 -07003016 prefetch(bnapi->status_blk.msi);
Michael Chanb6016b72005-05-26 13:03:09 -07003017 REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
3018 BNX2_PCICFG_INT_ACK_CMD_USE_INT_HC_PARAM |
3019 BNX2_PCICFG_INT_ACK_CMD_MASK_INT);
3020
3021 /* Return here if interrupt is disabled. */
Michael Chan73eef4c2005-08-25 15:39:15 -07003022 if (unlikely(atomic_read(&bp->intr_sem) != 0))
3023 return IRQ_HANDLED;
Michael Chanb6016b72005-05-26 13:03:09 -07003024
Michael Chan35efa7c2007-12-20 19:56:37 -08003025 netif_rx_schedule(dev, &bnapi->napi);
Michael Chanb6016b72005-05-26 13:03:09 -07003026
Michael Chan73eef4c2005-08-25 15:39:15 -07003027 return IRQ_HANDLED;
Michael Chanb6016b72005-05-26 13:03:09 -07003028}
3029
3030static irqreturn_t
Michael Chan8e6a72c2007-05-03 13:24:48 -07003031bnx2_msi_1shot(int irq, void *dev_instance)
3032{
Michael Chanf0ea2e62008-06-19 16:41:57 -07003033 struct bnx2_napi *bnapi = dev_instance;
3034 struct bnx2 *bp = bnapi->bp;
3035 struct net_device *dev = bp->dev;
Michael Chan8e6a72c2007-05-03 13:24:48 -07003036
Michael Chan43e80b82008-06-19 16:41:08 -07003037 prefetch(bnapi->status_blk.msi);
Michael Chan8e6a72c2007-05-03 13:24:48 -07003038
3039 /* Return here if interrupt is disabled. */
3040 if (unlikely(atomic_read(&bp->intr_sem) != 0))
3041 return IRQ_HANDLED;
3042
Michael Chan35efa7c2007-12-20 19:56:37 -08003043 netif_rx_schedule(dev, &bnapi->napi);
Michael Chan8e6a72c2007-05-03 13:24:48 -07003044
3045 return IRQ_HANDLED;
3046}
3047
3048static irqreturn_t
David Howells7d12e782006-10-05 14:55:46 +01003049bnx2_interrupt(int irq, void *dev_instance)
Michael Chanb6016b72005-05-26 13:03:09 -07003050{
Michael Chanf0ea2e62008-06-19 16:41:57 -07003051 struct bnx2_napi *bnapi = dev_instance;
3052 struct bnx2 *bp = bnapi->bp;
3053 struct net_device *dev = bp->dev;
Michael Chan43e80b82008-06-19 16:41:08 -07003054 struct status_block *sblk = bnapi->status_blk.msi;
Michael Chanb6016b72005-05-26 13:03:09 -07003055
3056 /* When using INTx, it is possible for the interrupt to arrive
3057 * at the CPU before the status block posted prior to the
3058 * interrupt. Reading a register will flush the status block.
3059 * When using MSI, the MSI message will always complete after
3060 * the status block write.
3061 */
Michael Chan35efa7c2007-12-20 19:56:37 -08003062 if ((sblk->status_idx == bnapi->last_status_idx) &&
Michael Chanb6016b72005-05-26 13:03:09 -07003063 (REG_RD(bp, BNX2_PCICFG_MISC_STATUS) &
3064 BNX2_PCICFG_MISC_STATUS_INTA_VALUE))
Michael Chan73eef4c2005-08-25 15:39:15 -07003065 return IRQ_NONE;
Michael Chanb6016b72005-05-26 13:03:09 -07003066
3067 REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
3068 BNX2_PCICFG_INT_ACK_CMD_USE_INT_HC_PARAM |
3069 BNX2_PCICFG_INT_ACK_CMD_MASK_INT);
3070
Michael Chanb8a7ce72007-07-07 22:51:03 -07003071 /* Read back to deassert IRQ immediately to avoid too many
3072 * spurious interrupts.
3073 */
3074 REG_RD(bp, BNX2_PCICFG_INT_ACK_CMD);
3075
Michael Chanb6016b72005-05-26 13:03:09 -07003076 /* Return here if interrupt is shared and is disabled. */
Michael Chan73eef4c2005-08-25 15:39:15 -07003077 if (unlikely(atomic_read(&bp->intr_sem) != 0))
3078 return IRQ_HANDLED;
Michael Chanb6016b72005-05-26 13:03:09 -07003079
Michael Chan35efa7c2007-12-20 19:56:37 -08003080 if (netif_rx_schedule_prep(dev, &bnapi->napi)) {
3081 bnapi->last_status_idx = sblk->status_idx;
3082 __netif_rx_schedule(dev, &bnapi->napi);
Michael Chanb8a7ce72007-07-07 22:51:03 -07003083 }
Michael Chanb6016b72005-05-26 13:03:09 -07003084
Michael Chan73eef4c2005-08-25 15:39:15 -07003085 return IRQ_HANDLED;
Michael Chanb6016b72005-05-26 13:03:09 -07003086}
3087
Michael Chan43e80b82008-06-19 16:41:08 -07003088static inline int
3089bnx2_has_fast_work(struct bnx2_napi *bnapi)
3090{
3091 struct bnx2_tx_ring_info *txr = &bnapi->tx_ring;
3092 struct bnx2_rx_ring_info *rxr = &bnapi->rx_ring;
3093
3094 if ((bnx2_get_hw_rx_cons(bnapi) != rxr->rx_cons) ||
3095 (bnx2_get_hw_tx_cons(bnapi) != txr->hw_tx_cons))
3096 return 1;
3097 return 0;
3098}
3099
Michael Chan0d8a6572007-07-07 22:49:43 -07003100#define STATUS_ATTN_EVENTS (STATUS_ATTN_BITS_LINK_STATE | \
3101 STATUS_ATTN_BITS_TIMER_ABORT)
Michael Chanda3e4fb2007-05-03 13:24:23 -07003102
Michael Chanf4e418f2005-11-04 08:53:48 -08003103static inline int
Michael Chan35efa7c2007-12-20 19:56:37 -08003104bnx2_has_work(struct bnx2_napi *bnapi)
Michael Chanf4e418f2005-11-04 08:53:48 -08003105{
Michael Chan43e80b82008-06-19 16:41:08 -07003106 struct status_block *sblk = bnapi->status_blk.msi;
Michael Chanf4e418f2005-11-04 08:53:48 -08003107
Michael Chan43e80b82008-06-19 16:41:08 -07003108 if (bnx2_has_fast_work(bnapi))
Michael Chanf4e418f2005-11-04 08:53:48 -08003109 return 1;
3110
Michael Chanda3e4fb2007-05-03 13:24:23 -07003111 if ((sblk->status_attn_bits & STATUS_ATTN_EVENTS) !=
3112 (sblk->status_attn_bits_ack & STATUS_ATTN_EVENTS))
Michael Chanf4e418f2005-11-04 08:53:48 -08003113 return 1;
3114
3115 return 0;
3116}
3117
Michael Chan43e80b82008-06-19 16:41:08 -07003118static void bnx2_poll_link(struct bnx2 *bp, struct bnx2_napi *bnapi)
Michael Chanb6016b72005-05-26 13:03:09 -07003119{
Michael Chan43e80b82008-06-19 16:41:08 -07003120 struct status_block *sblk = bnapi->status_blk.msi;
Michael Chanda3e4fb2007-05-03 13:24:23 -07003121 u32 status_attn_bits = sblk->status_attn_bits;
3122 u32 status_attn_bits_ack = sblk->status_attn_bits_ack;
Michael Chanb6016b72005-05-26 13:03:09 -07003123
Michael Chanda3e4fb2007-05-03 13:24:23 -07003124 if ((status_attn_bits & STATUS_ATTN_EVENTS) !=
3125 (status_attn_bits_ack & STATUS_ATTN_EVENTS)) {
Michael Chanb6016b72005-05-26 13:03:09 -07003126
Michael Chan35efa7c2007-12-20 19:56:37 -08003127 bnx2_phy_int(bp, bnapi);
Michael Chanbf5295b2006-03-23 01:11:56 -08003128
3129 /* This is needed to take care of transient status
3130 * during link changes.
3131 */
3132 REG_WR(bp, BNX2_HC_COMMAND,
3133 bp->hc_cmd | BNX2_HC_COMMAND_COAL_NOW_WO_INT);
3134 REG_RD(bp, BNX2_HC_COMMAND);
Michael Chanb6016b72005-05-26 13:03:09 -07003135 }
Michael Chan43e80b82008-06-19 16:41:08 -07003136}
3137
3138static int bnx2_poll_work(struct bnx2 *bp, struct bnx2_napi *bnapi,
3139 int work_done, int budget)
3140{
3141 struct bnx2_tx_ring_info *txr = &bnapi->tx_ring;
3142 struct bnx2_rx_ring_info *rxr = &bnapi->rx_ring;
Michael Chanb6016b72005-05-26 13:03:09 -07003143
Michael Chan35e90102008-06-19 16:37:42 -07003144 if (bnx2_get_hw_tx_cons(bnapi) != txr->hw_tx_cons)
Michael Chan57851d82007-12-20 20:01:44 -08003145 bnx2_tx_int(bp, bnapi, 0);
Michael Chanb6016b72005-05-26 13:03:09 -07003146
Michael Chanbb4f98a2008-06-19 16:38:19 -07003147 if (bnx2_get_hw_rx_cons(bnapi) != rxr->rx_cons)
Michael Chan35efa7c2007-12-20 19:56:37 -08003148 work_done += bnx2_rx_int(bp, bnapi, budget - work_done);
Jeff Garzik6aa20a22006-09-13 13:24:59 -04003149
David S. Miller6f535762007-10-11 18:08:29 -07003150 return work_done;
3151}
Michael Chanf4e418f2005-11-04 08:53:48 -08003152
Michael Chanf0ea2e62008-06-19 16:41:57 -07003153static int bnx2_poll_msix(struct napi_struct *napi, int budget)
3154{
3155 struct bnx2_napi *bnapi = container_of(napi, struct bnx2_napi, napi);
3156 struct bnx2 *bp = bnapi->bp;
3157 int work_done = 0;
3158 struct status_block_msix *sblk = bnapi->status_blk.msix;
3159
3160 while (1) {
3161 work_done = bnx2_poll_work(bp, bnapi, work_done, budget);
3162 if (unlikely(work_done >= budget))
3163 break;
3164
3165 bnapi->last_status_idx = sblk->status_idx;
3166 /* status idx must be read before checking for more work. */
3167 rmb();
3168 if (likely(!bnx2_has_fast_work(bnapi))) {
3169
3170 netif_rx_complete(bp->dev, napi);
3171 REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD, bnapi->int_num |
3172 BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
3173 bnapi->last_status_idx);
3174 break;
3175 }
3176 }
3177 return work_done;
3178}
3179
David S. Miller6f535762007-10-11 18:08:29 -07003180static int bnx2_poll(struct napi_struct *napi, int budget)
3181{
Michael Chan35efa7c2007-12-20 19:56:37 -08003182 struct bnx2_napi *bnapi = container_of(napi, struct bnx2_napi, napi);
3183 struct bnx2 *bp = bnapi->bp;
David S. Miller6f535762007-10-11 18:08:29 -07003184 int work_done = 0;
Michael Chan43e80b82008-06-19 16:41:08 -07003185 struct status_block *sblk = bnapi->status_blk.msi;
David S. Miller6f535762007-10-11 18:08:29 -07003186
3187 while (1) {
Michael Chan43e80b82008-06-19 16:41:08 -07003188 bnx2_poll_link(bp, bnapi);
3189
Michael Chan35efa7c2007-12-20 19:56:37 -08003190 work_done = bnx2_poll_work(bp, bnapi, work_done, budget);
David S. Miller6f535762007-10-11 18:08:29 -07003191
3192 if (unlikely(work_done >= budget))
3193 break;
3194
Michael Chan35efa7c2007-12-20 19:56:37 -08003195 /* bnapi->last_status_idx is used below to tell the hw how
Michael Chan6dee6422007-10-12 01:40:38 -07003196 * much work has been processed, so we must read it before
3197 * checking for more work.
3198 */
Michael Chan35efa7c2007-12-20 19:56:37 -08003199 bnapi->last_status_idx = sblk->status_idx;
Michael Chan6dee6422007-10-12 01:40:38 -07003200 rmb();
Michael Chan35efa7c2007-12-20 19:56:37 -08003201 if (likely(!bnx2_has_work(bnapi))) {
David S. Miller6f535762007-10-11 18:08:29 -07003202 netif_rx_complete(bp->dev, napi);
David S. Millerf86e82f2008-01-21 17:15:40 -08003203 if (likely(bp->flags & BNX2_FLAG_USING_MSI_OR_MSIX)) {
David S. Miller6f535762007-10-11 18:08:29 -07003204 REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
3205 BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
Michael Chan35efa7c2007-12-20 19:56:37 -08003206 bnapi->last_status_idx);
Michael Chan6dee6422007-10-12 01:40:38 -07003207 break;
David S. Miller6f535762007-10-11 18:08:29 -07003208 }
3209 REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
3210 BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
3211 BNX2_PCICFG_INT_ACK_CMD_MASK_INT |
Michael Chan35efa7c2007-12-20 19:56:37 -08003212 bnapi->last_status_idx);
David S. Miller6f535762007-10-11 18:08:29 -07003213
Michael Chan1269a8a2006-01-23 16:11:03 -08003214 REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
3215 BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
Michael Chan35efa7c2007-12-20 19:56:37 -08003216 bnapi->last_status_idx);
David S. Miller6f535762007-10-11 18:08:29 -07003217 break;
Michael Chan1269a8a2006-01-23 16:11:03 -08003218 }
Michael Chanb6016b72005-05-26 13:03:09 -07003219 }
3220
Stephen Hemmingerbea33482007-10-03 16:41:36 -07003221 return work_done;
Michael Chanb6016b72005-05-26 13:03:09 -07003222}
3223
Herbert Xu932ff272006-06-09 12:20:56 -07003224/* Called with rtnl_lock from vlan functions and also netif_tx_lock
Michael Chanb6016b72005-05-26 13:03:09 -07003225 * from set_multicast.
3226 */
3227static void
3228bnx2_set_rx_mode(struct net_device *dev)
3229{
Michael Chan972ec0d2006-01-23 16:12:43 -08003230 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07003231 u32 rx_mode, sort_mode;
Benjamin Li5fcaed02008-07-14 22:39:52 -07003232 struct dev_addr_list *uc_ptr;
Michael Chanb6016b72005-05-26 13:03:09 -07003233 int i;
Michael Chanb6016b72005-05-26 13:03:09 -07003234
Michael Chanc770a652005-08-25 15:38:39 -07003235 spin_lock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07003236
3237 rx_mode = bp->rx_mode & ~(BNX2_EMAC_RX_MODE_PROMISCUOUS |
3238 BNX2_EMAC_RX_MODE_KEEP_VLAN_TAG);
3239 sort_mode = 1 | BNX2_RPM_SORT_USER0_BC_EN;
3240#ifdef BCM_VLAN
David S. Millerf86e82f2008-01-21 17:15:40 -08003241 if (!bp->vlgrp && !(bp->flags & BNX2_FLAG_ASF_ENABLE))
Michael Chanb6016b72005-05-26 13:03:09 -07003242 rx_mode |= BNX2_EMAC_RX_MODE_KEEP_VLAN_TAG;
Michael Chanb6016b72005-05-26 13:03:09 -07003243#else
David S. Millerf86e82f2008-01-21 17:15:40 -08003244 if (!(bp->flags & BNX2_FLAG_ASF_ENABLE))
Michael Chane29054f2006-01-23 16:06:06 -08003245 rx_mode |= BNX2_EMAC_RX_MODE_KEEP_VLAN_TAG;
Michael Chanb6016b72005-05-26 13:03:09 -07003246#endif
3247 if (dev->flags & IFF_PROMISC) {
3248 /* Promiscuous mode. */
3249 rx_mode |= BNX2_EMAC_RX_MODE_PROMISCUOUS;
Michael Chan75108732006-11-19 14:06:40 -08003250 sort_mode |= BNX2_RPM_SORT_USER0_PROM_EN |
3251 BNX2_RPM_SORT_USER0_PROM_VLAN;
Michael Chanb6016b72005-05-26 13:03:09 -07003252 }
3253 else if (dev->flags & IFF_ALLMULTI) {
3254 for (i = 0; i < NUM_MC_HASH_REGISTERS; i++) {
3255 REG_WR(bp, BNX2_EMAC_MULTICAST_HASH0 + (i * 4),
3256 0xffffffff);
3257 }
3258 sort_mode |= BNX2_RPM_SORT_USER0_MC_EN;
3259 }
3260 else {
3261 /* Accept one or more multicast(s). */
3262 struct dev_mc_list *mclist;
3263 u32 mc_filter[NUM_MC_HASH_REGISTERS];
3264 u32 regidx;
3265 u32 bit;
3266 u32 crc;
3267
3268 memset(mc_filter, 0, 4 * NUM_MC_HASH_REGISTERS);
3269
3270 for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
3271 i++, mclist = mclist->next) {
3272
3273 crc = ether_crc_le(ETH_ALEN, mclist->dmi_addr);
3274 bit = crc & 0xff;
3275 regidx = (bit & 0xe0) >> 5;
3276 bit &= 0x1f;
3277 mc_filter[regidx] |= (1 << bit);
3278 }
3279
3280 for (i = 0; i < NUM_MC_HASH_REGISTERS; i++) {
3281 REG_WR(bp, BNX2_EMAC_MULTICAST_HASH0 + (i * 4),
3282 mc_filter[i]);
3283 }
3284
3285 sort_mode |= BNX2_RPM_SORT_USER0_MC_HSH_EN;
3286 }
3287
Benjamin Li5fcaed02008-07-14 22:39:52 -07003288 uc_ptr = NULL;
3289 if (dev->uc_count > BNX2_MAX_UNICAST_ADDRESSES) {
3290 rx_mode |= BNX2_EMAC_RX_MODE_PROMISCUOUS;
3291 sort_mode |= BNX2_RPM_SORT_USER0_PROM_EN |
3292 BNX2_RPM_SORT_USER0_PROM_VLAN;
3293 } else if (!(dev->flags & IFF_PROMISC)) {
3294 uc_ptr = dev->uc_list;
3295
3296 /* Add all entries into to the match filter list */
3297 for (i = 0; i < dev->uc_count; i++) {
3298 bnx2_set_mac_addr(bp, uc_ptr->da_addr,
3299 i + BNX2_START_UNICAST_ADDRESS_INDEX);
3300 sort_mode |= (1 <<
3301 (i + BNX2_START_UNICAST_ADDRESS_INDEX));
3302 uc_ptr = uc_ptr->next;
3303 }
3304
3305 }
3306
Michael Chanb6016b72005-05-26 13:03:09 -07003307 if (rx_mode != bp->rx_mode) {
3308 bp->rx_mode = rx_mode;
3309 REG_WR(bp, BNX2_EMAC_RX_MODE, rx_mode);
3310 }
3311
3312 REG_WR(bp, BNX2_RPM_SORT_USER0, 0x0);
3313 REG_WR(bp, BNX2_RPM_SORT_USER0, sort_mode);
3314 REG_WR(bp, BNX2_RPM_SORT_USER0, sort_mode | BNX2_RPM_SORT_USER0_ENA);
3315
Michael Chanc770a652005-08-25 15:38:39 -07003316 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07003317}
3318
3319static void
Al Virob491edd2007-12-22 19:44:51 +00003320load_rv2p_fw(struct bnx2 *bp, __le32 *rv2p_code, u32 rv2p_code_len,
Michael Chanb6016b72005-05-26 13:03:09 -07003321 u32 rv2p_proc)
3322{
3323 int i;
3324 u32 val;
3325
Michael Chand25be1d2008-05-02 16:57:59 -07003326 if (rv2p_proc == RV2P_PROC2 && CHIP_NUM(bp) == CHIP_NUM_5709) {
3327 val = le32_to_cpu(rv2p_code[XI_RV2P_PROC2_MAX_BD_PAGE_LOC]);
3328 val &= ~XI_RV2P_PROC2_BD_PAGE_SIZE_MSK;
3329 val |= XI_RV2P_PROC2_BD_PAGE_SIZE;
3330 rv2p_code[XI_RV2P_PROC2_MAX_BD_PAGE_LOC] = cpu_to_le32(val);
3331 }
Michael Chanb6016b72005-05-26 13:03:09 -07003332
3333 for (i = 0; i < rv2p_code_len; i += 8) {
Al Virob491edd2007-12-22 19:44:51 +00003334 REG_WR(bp, BNX2_RV2P_INSTR_HIGH, le32_to_cpu(*rv2p_code));
Michael Chanb6016b72005-05-26 13:03:09 -07003335 rv2p_code++;
Al Virob491edd2007-12-22 19:44:51 +00003336 REG_WR(bp, BNX2_RV2P_INSTR_LOW, le32_to_cpu(*rv2p_code));
Michael Chanb6016b72005-05-26 13:03:09 -07003337 rv2p_code++;
3338
3339 if (rv2p_proc == RV2P_PROC1) {
3340 val = (i / 8) | BNX2_RV2P_PROC1_ADDR_CMD_RDWR;
3341 REG_WR(bp, BNX2_RV2P_PROC1_ADDR_CMD, val);
3342 }
3343 else {
3344 val = (i / 8) | BNX2_RV2P_PROC2_ADDR_CMD_RDWR;
3345 REG_WR(bp, BNX2_RV2P_PROC2_ADDR_CMD, val);
3346 }
3347 }
3348
3349 /* Reset the processor, un-stall is done later. */
3350 if (rv2p_proc == RV2P_PROC1) {
3351 REG_WR(bp, BNX2_RV2P_COMMAND, BNX2_RV2P_COMMAND_PROC1_RESET);
3352 }
3353 else {
3354 REG_WR(bp, BNX2_RV2P_COMMAND, BNX2_RV2P_COMMAND_PROC2_RESET);
3355 }
3356}
3357
Michael Chanaf3ee512006-11-19 14:09:25 -08003358static int
Benjamin Li10343cc2008-05-16 22:20:27 -07003359load_cpu_fw(struct bnx2 *bp, const struct cpu_reg *cpu_reg, struct fw_info *fw)
Michael Chanb6016b72005-05-26 13:03:09 -07003360{
3361 u32 offset;
3362 u32 val;
Michael Chanaf3ee512006-11-19 14:09:25 -08003363 int rc;
Michael Chanb6016b72005-05-26 13:03:09 -07003364
3365 /* Halt the CPU. */
Michael Chan2726d6e2008-01-29 21:35:05 -08003366 val = bnx2_reg_rd_ind(bp, cpu_reg->mode);
Michael Chanb6016b72005-05-26 13:03:09 -07003367 val |= cpu_reg->mode_value_halt;
Michael Chan2726d6e2008-01-29 21:35:05 -08003368 bnx2_reg_wr_ind(bp, cpu_reg->mode, val);
3369 bnx2_reg_wr_ind(bp, cpu_reg->state, cpu_reg->state_value_clear);
Michael Chanb6016b72005-05-26 13:03:09 -07003370
3371 /* Load the Text area. */
3372 offset = cpu_reg->spad_base + (fw->text_addr - cpu_reg->mips_view_base);
Michael Chanaf3ee512006-11-19 14:09:25 -08003373 if (fw->gz_text) {
Michael Chanb6016b72005-05-26 13:03:09 -07003374 int j;
3375
Michael Chanea1f8d52007-10-02 16:27:35 -07003376 rc = zlib_inflate_blob(fw->text, FW_BUF_SIZE, fw->gz_text,
3377 fw->gz_text_len);
3378 if (rc < 0)
Denys Vlasenkob3448b02007-09-30 17:55:51 -07003379 return rc;
Michael Chanea1f8d52007-10-02 16:27:35 -07003380
Michael Chanb6016b72005-05-26 13:03:09 -07003381 for (j = 0; j < (fw->text_len / 4); j++, offset += 4) {
Michael Chan2726d6e2008-01-29 21:35:05 -08003382 bnx2_reg_wr_ind(bp, offset, le32_to_cpu(fw->text[j]));
Michael Chanb6016b72005-05-26 13:03:09 -07003383 }
3384 }
3385
3386 /* Load the Data area. */
3387 offset = cpu_reg->spad_base + (fw->data_addr - cpu_reg->mips_view_base);
3388 if (fw->data) {
3389 int j;
3390
3391 for (j = 0; j < (fw->data_len / 4); j++, offset += 4) {
Michael Chan2726d6e2008-01-29 21:35:05 -08003392 bnx2_reg_wr_ind(bp, offset, fw->data[j]);
Michael Chanb6016b72005-05-26 13:03:09 -07003393 }
3394 }
3395
3396 /* Load the SBSS area. */
3397 offset = cpu_reg->spad_base + (fw->sbss_addr - cpu_reg->mips_view_base);
Michael Chanea1f8d52007-10-02 16:27:35 -07003398 if (fw->sbss_len) {
Michael Chanb6016b72005-05-26 13:03:09 -07003399 int j;
3400
3401 for (j = 0; j < (fw->sbss_len / 4); j++, offset += 4) {
Michael Chan2726d6e2008-01-29 21:35:05 -08003402 bnx2_reg_wr_ind(bp, offset, 0);
Michael Chanb6016b72005-05-26 13:03:09 -07003403 }
3404 }
3405
3406 /* Load the BSS area. */
3407 offset = cpu_reg->spad_base + (fw->bss_addr - cpu_reg->mips_view_base);
Michael Chanea1f8d52007-10-02 16:27:35 -07003408 if (fw->bss_len) {
Michael Chanb6016b72005-05-26 13:03:09 -07003409 int j;
3410
3411 for (j = 0; j < (fw->bss_len/4); j++, offset += 4) {
Michael Chan2726d6e2008-01-29 21:35:05 -08003412 bnx2_reg_wr_ind(bp, offset, 0);
Michael Chanb6016b72005-05-26 13:03:09 -07003413 }
3414 }
3415
3416 /* Load the Read-Only area. */
3417 offset = cpu_reg->spad_base +
3418 (fw->rodata_addr - cpu_reg->mips_view_base);
3419 if (fw->rodata) {
3420 int j;
3421
3422 for (j = 0; j < (fw->rodata_len / 4); j++, offset += 4) {
Michael Chan2726d6e2008-01-29 21:35:05 -08003423 bnx2_reg_wr_ind(bp, offset, fw->rodata[j]);
Michael Chanb6016b72005-05-26 13:03:09 -07003424 }
3425 }
3426
3427 /* Clear the pre-fetch instruction. */
Michael Chan2726d6e2008-01-29 21:35:05 -08003428 bnx2_reg_wr_ind(bp, cpu_reg->inst, 0);
3429 bnx2_reg_wr_ind(bp, cpu_reg->pc, fw->start_addr);
Michael Chanb6016b72005-05-26 13:03:09 -07003430
3431 /* Start the CPU. */
Michael Chan2726d6e2008-01-29 21:35:05 -08003432 val = bnx2_reg_rd_ind(bp, cpu_reg->mode);
Michael Chanb6016b72005-05-26 13:03:09 -07003433 val &= ~cpu_reg->mode_value_halt;
Michael Chan2726d6e2008-01-29 21:35:05 -08003434 bnx2_reg_wr_ind(bp, cpu_reg->state, cpu_reg->state_value_clear);
3435 bnx2_reg_wr_ind(bp, cpu_reg->mode, val);
Michael Chanaf3ee512006-11-19 14:09:25 -08003436
3437 return 0;
Michael Chanb6016b72005-05-26 13:03:09 -07003438}
3439
Michael Chanfba9fe92006-06-12 22:21:25 -07003440static int
Michael Chanb6016b72005-05-26 13:03:09 -07003441bnx2_init_cpus(struct bnx2 *bp)
3442{
Michael Chanaf3ee512006-11-19 14:09:25 -08003443 struct fw_info *fw;
Michael Chan110d0ef2007-12-12 11:18:34 -08003444 int rc, rv2p_len;
3445 void *text, *rv2p;
Michael Chanb6016b72005-05-26 13:03:09 -07003446
3447 /* Initialize the RV2P processor. */
Denys Vlasenkob3448b02007-09-30 17:55:51 -07003448 text = vmalloc(FW_BUF_SIZE);
3449 if (!text)
3450 return -ENOMEM;
Michael Chan110d0ef2007-12-12 11:18:34 -08003451 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
3452 rv2p = bnx2_xi_rv2p_proc1;
3453 rv2p_len = sizeof(bnx2_xi_rv2p_proc1);
3454 } else {
3455 rv2p = bnx2_rv2p_proc1;
3456 rv2p_len = sizeof(bnx2_rv2p_proc1);
3457 }
3458 rc = zlib_inflate_blob(text, FW_BUF_SIZE, rv2p, rv2p_len);
Michael Chanea1f8d52007-10-02 16:27:35 -07003459 if (rc < 0)
Michael Chanfba9fe92006-06-12 22:21:25 -07003460 goto init_cpu_err;
Michael Chanea1f8d52007-10-02 16:27:35 -07003461
Denys Vlasenkob3448b02007-09-30 17:55:51 -07003462 load_rv2p_fw(bp, text, rc /* == len */, RV2P_PROC1);
Michael Chanfba9fe92006-06-12 22:21:25 -07003463
Michael Chan110d0ef2007-12-12 11:18:34 -08003464 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
3465 rv2p = bnx2_xi_rv2p_proc2;
3466 rv2p_len = sizeof(bnx2_xi_rv2p_proc2);
3467 } else {
3468 rv2p = bnx2_rv2p_proc2;
3469 rv2p_len = sizeof(bnx2_rv2p_proc2);
3470 }
3471 rc = zlib_inflate_blob(text, FW_BUF_SIZE, rv2p, rv2p_len);
Michael Chanea1f8d52007-10-02 16:27:35 -07003472 if (rc < 0)
Michael Chanfba9fe92006-06-12 22:21:25 -07003473 goto init_cpu_err;
Michael Chanea1f8d52007-10-02 16:27:35 -07003474
Denys Vlasenkob3448b02007-09-30 17:55:51 -07003475 load_rv2p_fw(bp, text, rc /* == len */, RV2P_PROC2);
Michael Chanb6016b72005-05-26 13:03:09 -07003476
3477 /* Initialize the RX Processor. */
Michael Chand43584c2006-11-19 14:14:35 -08003478 if (CHIP_NUM(bp) == CHIP_NUM_5709)
3479 fw = &bnx2_rxp_fw_09;
3480 else
3481 fw = &bnx2_rxp_fw_06;
Michael Chanb6016b72005-05-26 13:03:09 -07003482
Michael Chanea1f8d52007-10-02 16:27:35 -07003483 fw->text = text;
Benjamin Li10343cc2008-05-16 22:20:27 -07003484 rc = load_cpu_fw(bp, &cpu_reg_rxp, fw);
Michael Chanfba9fe92006-06-12 22:21:25 -07003485 if (rc)
3486 goto init_cpu_err;
3487
Michael Chanb6016b72005-05-26 13:03:09 -07003488 /* Initialize the TX Processor. */
Michael Chand43584c2006-11-19 14:14:35 -08003489 if (CHIP_NUM(bp) == CHIP_NUM_5709)
3490 fw = &bnx2_txp_fw_09;
3491 else
3492 fw = &bnx2_txp_fw_06;
Michael Chanb6016b72005-05-26 13:03:09 -07003493
Michael Chanea1f8d52007-10-02 16:27:35 -07003494 fw->text = text;
Benjamin Li10343cc2008-05-16 22:20:27 -07003495 rc = load_cpu_fw(bp, &cpu_reg_txp, fw);
Michael Chanfba9fe92006-06-12 22:21:25 -07003496 if (rc)
3497 goto init_cpu_err;
3498
Michael Chanb6016b72005-05-26 13:03:09 -07003499 /* Initialize the TX Patch-up Processor. */
Michael Chand43584c2006-11-19 14:14:35 -08003500 if (CHIP_NUM(bp) == CHIP_NUM_5709)
3501 fw = &bnx2_tpat_fw_09;
3502 else
3503 fw = &bnx2_tpat_fw_06;
Michael Chanb6016b72005-05-26 13:03:09 -07003504
Michael Chanea1f8d52007-10-02 16:27:35 -07003505 fw->text = text;
Benjamin Li10343cc2008-05-16 22:20:27 -07003506 rc = load_cpu_fw(bp, &cpu_reg_tpat, fw);
Michael Chanfba9fe92006-06-12 22:21:25 -07003507 if (rc)
3508 goto init_cpu_err;
3509
Michael Chanb6016b72005-05-26 13:03:09 -07003510 /* Initialize the Completion Processor. */
Michael Chand43584c2006-11-19 14:14:35 -08003511 if (CHIP_NUM(bp) == CHIP_NUM_5709)
3512 fw = &bnx2_com_fw_09;
3513 else
3514 fw = &bnx2_com_fw_06;
Michael Chanb6016b72005-05-26 13:03:09 -07003515
Michael Chanea1f8d52007-10-02 16:27:35 -07003516 fw->text = text;
Benjamin Li10343cc2008-05-16 22:20:27 -07003517 rc = load_cpu_fw(bp, &cpu_reg_com, fw);
Michael Chanfba9fe92006-06-12 22:21:25 -07003518 if (rc)
3519 goto init_cpu_err;
3520
Michael Chand43584c2006-11-19 14:14:35 -08003521 /* Initialize the Command Processor. */
Michael Chan110d0ef2007-12-12 11:18:34 -08003522 if (CHIP_NUM(bp) == CHIP_NUM_5709)
Michael Chand43584c2006-11-19 14:14:35 -08003523 fw = &bnx2_cp_fw_09;
Michael Chan110d0ef2007-12-12 11:18:34 -08003524 else
3525 fw = &bnx2_cp_fw_06;
Michael Chanb6016b72005-05-26 13:03:09 -07003526
Michael Chan110d0ef2007-12-12 11:18:34 -08003527 fw->text = text;
Benjamin Li10343cc2008-05-16 22:20:27 -07003528 rc = load_cpu_fw(bp, &cpu_reg_cp, fw);
Michael Chan110d0ef2007-12-12 11:18:34 -08003529
Michael Chanfba9fe92006-06-12 22:21:25 -07003530init_cpu_err:
Michael Chanea1f8d52007-10-02 16:27:35 -07003531 vfree(text);
Michael Chanfba9fe92006-06-12 22:21:25 -07003532 return rc;
Michael Chanb6016b72005-05-26 13:03:09 -07003533}
3534
3535static int
Pavel Machek829ca9a2005-09-03 15:56:56 -07003536bnx2_set_power_state(struct bnx2 *bp, pci_power_t state)
Michael Chanb6016b72005-05-26 13:03:09 -07003537{
3538 u16 pmcsr;
3539
3540 pci_read_config_word(bp->pdev, bp->pm_cap + PCI_PM_CTRL, &pmcsr);
3541
3542 switch (state) {
Pavel Machek829ca9a2005-09-03 15:56:56 -07003543 case PCI_D0: {
Michael Chanb6016b72005-05-26 13:03:09 -07003544 u32 val;
3545
3546 pci_write_config_word(bp->pdev, bp->pm_cap + PCI_PM_CTRL,
3547 (pmcsr & ~PCI_PM_CTRL_STATE_MASK) |
3548 PCI_PM_CTRL_PME_STATUS);
3549
3550 if (pmcsr & PCI_PM_CTRL_STATE_MASK)
3551 /* delay required during transition out of D3hot */
3552 msleep(20);
3553
3554 val = REG_RD(bp, BNX2_EMAC_MODE);
3555 val |= BNX2_EMAC_MODE_MPKT_RCVD | BNX2_EMAC_MODE_ACPI_RCVD;
3556 val &= ~BNX2_EMAC_MODE_MPKT;
3557 REG_WR(bp, BNX2_EMAC_MODE, val);
3558
3559 val = REG_RD(bp, BNX2_RPM_CONFIG);
3560 val &= ~BNX2_RPM_CONFIG_ACPI_ENA;
3561 REG_WR(bp, BNX2_RPM_CONFIG, val);
3562 break;
3563 }
Pavel Machek829ca9a2005-09-03 15:56:56 -07003564 case PCI_D3hot: {
Michael Chanb6016b72005-05-26 13:03:09 -07003565 int i;
3566 u32 val, wol_msg;
3567
3568 if (bp->wol) {
3569 u32 advertising;
3570 u8 autoneg;
3571
3572 autoneg = bp->autoneg;
3573 advertising = bp->advertising;
3574
Michael Chan239cd342007-10-17 19:26:15 -07003575 if (bp->phy_port == PORT_TP) {
3576 bp->autoneg = AUTONEG_SPEED;
3577 bp->advertising = ADVERTISED_10baseT_Half |
3578 ADVERTISED_10baseT_Full |
3579 ADVERTISED_100baseT_Half |
3580 ADVERTISED_100baseT_Full |
3581 ADVERTISED_Autoneg;
3582 }
Michael Chanb6016b72005-05-26 13:03:09 -07003583
Michael Chan239cd342007-10-17 19:26:15 -07003584 spin_lock_bh(&bp->phy_lock);
3585 bnx2_setup_phy(bp, bp->phy_port);
3586 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07003587
3588 bp->autoneg = autoneg;
3589 bp->advertising = advertising;
3590
Benjamin Li5fcaed02008-07-14 22:39:52 -07003591 bnx2_set_mac_addr(bp, bp->dev->dev_addr, 0);
Michael Chanb6016b72005-05-26 13:03:09 -07003592
3593 val = REG_RD(bp, BNX2_EMAC_MODE);
3594
3595 /* Enable port mode. */
3596 val &= ~BNX2_EMAC_MODE_PORT;
Michael Chan239cd342007-10-17 19:26:15 -07003597 val |= BNX2_EMAC_MODE_MPKT_RCVD |
Michael Chanb6016b72005-05-26 13:03:09 -07003598 BNX2_EMAC_MODE_ACPI_RCVD |
Michael Chanb6016b72005-05-26 13:03:09 -07003599 BNX2_EMAC_MODE_MPKT;
Michael Chan239cd342007-10-17 19:26:15 -07003600 if (bp->phy_port == PORT_TP)
3601 val |= BNX2_EMAC_MODE_PORT_MII;
3602 else {
3603 val |= BNX2_EMAC_MODE_PORT_GMII;
3604 if (bp->line_speed == SPEED_2500)
3605 val |= BNX2_EMAC_MODE_25G_MODE;
3606 }
Michael Chanb6016b72005-05-26 13:03:09 -07003607
3608 REG_WR(bp, BNX2_EMAC_MODE, val);
3609
3610 /* receive all multicast */
3611 for (i = 0; i < NUM_MC_HASH_REGISTERS; i++) {
3612 REG_WR(bp, BNX2_EMAC_MULTICAST_HASH0 + (i * 4),
3613 0xffffffff);
3614 }
3615 REG_WR(bp, BNX2_EMAC_RX_MODE,
3616 BNX2_EMAC_RX_MODE_SORT_MODE);
3617
3618 val = 1 | BNX2_RPM_SORT_USER0_BC_EN |
3619 BNX2_RPM_SORT_USER0_MC_EN;
3620 REG_WR(bp, BNX2_RPM_SORT_USER0, 0x0);
3621 REG_WR(bp, BNX2_RPM_SORT_USER0, val);
3622 REG_WR(bp, BNX2_RPM_SORT_USER0, val |
3623 BNX2_RPM_SORT_USER0_ENA);
3624
3625 /* Need to enable EMAC and RPM for WOL. */
3626 REG_WR(bp, BNX2_MISC_ENABLE_SET_BITS,
3627 BNX2_MISC_ENABLE_SET_BITS_RX_PARSER_MAC_ENABLE |
3628 BNX2_MISC_ENABLE_SET_BITS_TX_HEADER_Q_ENABLE |
3629 BNX2_MISC_ENABLE_SET_BITS_EMAC_ENABLE);
3630
3631 val = REG_RD(bp, BNX2_RPM_CONFIG);
3632 val &= ~BNX2_RPM_CONFIG_ACPI_ENA;
3633 REG_WR(bp, BNX2_RPM_CONFIG, val);
3634
3635 wol_msg = BNX2_DRV_MSG_CODE_SUSPEND_WOL;
3636 }
3637 else {
3638 wol_msg = BNX2_DRV_MSG_CODE_SUSPEND_NO_WOL;
3639 }
3640
David S. Millerf86e82f2008-01-21 17:15:40 -08003641 if (!(bp->flags & BNX2_FLAG_NO_WOL))
Michael Chana2f13892008-07-14 22:38:23 -07003642 bnx2_fw_sync(bp, BNX2_DRV_MSG_DATA_WAIT3 | wol_msg,
3643 1, 0);
Michael Chanb6016b72005-05-26 13:03:09 -07003644
3645 pmcsr &= ~PCI_PM_CTRL_STATE_MASK;
3646 if ((CHIP_ID(bp) == CHIP_ID_5706_A0) ||
3647 (CHIP_ID(bp) == CHIP_ID_5706_A1)) {
3648
3649 if (bp->wol)
3650 pmcsr |= 3;
3651 }
3652 else {
3653 pmcsr |= 3;
3654 }
3655 if (bp->wol) {
3656 pmcsr |= PCI_PM_CTRL_PME_ENABLE;
3657 }
3658 pci_write_config_word(bp->pdev, bp->pm_cap + PCI_PM_CTRL,
3659 pmcsr);
3660
3661 /* No more memory access after this point until
3662 * device is brought back to D0.
3663 */
3664 udelay(50);
3665 break;
3666 }
3667 default:
3668 return -EINVAL;
3669 }
3670 return 0;
3671}
3672
3673static int
3674bnx2_acquire_nvram_lock(struct bnx2 *bp)
3675{
3676 u32 val;
3677 int j;
3678
3679 /* Request access to the flash interface. */
3680 REG_WR(bp, BNX2_NVM_SW_ARB, BNX2_NVM_SW_ARB_ARB_REQ_SET2);
3681 for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) {
3682 val = REG_RD(bp, BNX2_NVM_SW_ARB);
3683 if (val & BNX2_NVM_SW_ARB_ARB_ARB2)
3684 break;
3685
3686 udelay(5);
3687 }
3688
3689 if (j >= NVRAM_TIMEOUT_COUNT)
3690 return -EBUSY;
3691
3692 return 0;
3693}
3694
3695static int
3696bnx2_release_nvram_lock(struct bnx2 *bp)
3697{
3698 int j;
3699 u32 val;
3700
3701 /* Relinquish nvram interface. */
3702 REG_WR(bp, BNX2_NVM_SW_ARB, BNX2_NVM_SW_ARB_ARB_REQ_CLR2);
3703
3704 for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) {
3705 val = REG_RD(bp, BNX2_NVM_SW_ARB);
3706 if (!(val & BNX2_NVM_SW_ARB_ARB_ARB2))
3707 break;
3708
3709 udelay(5);
3710 }
3711
3712 if (j >= NVRAM_TIMEOUT_COUNT)
3713 return -EBUSY;
3714
3715 return 0;
3716}
3717
3718
3719static int
3720bnx2_enable_nvram_write(struct bnx2 *bp)
3721{
3722 u32 val;
3723
3724 val = REG_RD(bp, BNX2_MISC_CFG);
3725 REG_WR(bp, BNX2_MISC_CFG, val | BNX2_MISC_CFG_NVM_WR_EN_PCI);
3726
Michael Chane30372c2007-07-16 18:26:23 -07003727 if (bp->flash_info->flags & BNX2_NV_WREN) {
Michael Chanb6016b72005-05-26 13:03:09 -07003728 int j;
3729
3730 REG_WR(bp, BNX2_NVM_COMMAND, BNX2_NVM_COMMAND_DONE);
3731 REG_WR(bp, BNX2_NVM_COMMAND,
3732 BNX2_NVM_COMMAND_WREN | BNX2_NVM_COMMAND_DOIT);
3733
3734 for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) {
3735 udelay(5);
3736
3737 val = REG_RD(bp, BNX2_NVM_COMMAND);
3738 if (val & BNX2_NVM_COMMAND_DONE)
3739 break;
3740 }
3741
3742 if (j >= NVRAM_TIMEOUT_COUNT)
3743 return -EBUSY;
3744 }
3745 return 0;
3746}
3747
3748static void
3749bnx2_disable_nvram_write(struct bnx2 *bp)
3750{
3751 u32 val;
3752
3753 val = REG_RD(bp, BNX2_MISC_CFG);
3754 REG_WR(bp, BNX2_MISC_CFG, val & ~BNX2_MISC_CFG_NVM_WR_EN);
3755}
3756
3757
3758static void
3759bnx2_enable_nvram_access(struct bnx2 *bp)
3760{
3761 u32 val;
3762
3763 val = REG_RD(bp, BNX2_NVM_ACCESS_ENABLE);
3764 /* Enable both bits, even on read. */
Jeff Garzik6aa20a22006-09-13 13:24:59 -04003765 REG_WR(bp, BNX2_NVM_ACCESS_ENABLE,
Michael Chanb6016b72005-05-26 13:03:09 -07003766 val | BNX2_NVM_ACCESS_ENABLE_EN | BNX2_NVM_ACCESS_ENABLE_WR_EN);
3767}
3768
3769static void
3770bnx2_disable_nvram_access(struct bnx2 *bp)
3771{
3772 u32 val;
3773
3774 val = REG_RD(bp, BNX2_NVM_ACCESS_ENABLE);
3775 /* Disable both bits, even after read. */
Jeff Garzik6aa20a22006-09-13 13:24:59 -04003776 REG_WR(bp, BNX2_NVM_ACCESS_ENABLE,
Michael Chanb6016b72005-05-26 13:03:09 -07003777 val & ~(BNX2_NVM_ACCESS_ENABLE_EN |
3778 BNX2_NVM_ACCESS_ENABLE_WR_EN));
3779}
3780
3781static int
3782bnx2_nvram_erase_page(struct bnx2 *bp, u32 offset)
3783{
3784 u32 cmd;
3785 int j;
3786
Michael Chane30372c2007-07-16 18:26:23 -07003787 if (bp->flash_info->flags & BNX2_NV_BUFFERED)
Michael Chanb6016b72005-05-26 13:03:09 -07003788 /* Buffered flash, no erase needed */
3789 return 0;
3790
3791 /* Build an erase command */
3792 cmd = BNX2_NVM_COMMAND_ERASE | BNX2_NVM_COMMAND_WR |
3793 BNX2_NVM_COMMAND_DOIT;
3794
3795 /* Need to clear DONE bit separately. */
3796 REG_WR(bp, BNX2_NVM_COMMAND, BNX2_NVM_COMMAND_DONE);
3797
3798 /* Address of the NVRAM to read from. */
3799 REG_WR(bp, BNX2_NVM_ADDR, offset & BNX2_NVM_ADDR_NVM_ADDR_VALUE);
3800
3801 /* Issue an erase command. */
3802 REG_WR(bp, BNX2_NVM_COMMAND, cmd);
3803
3804 /* Wait for completion. */
3805 for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) {
3806 u32 val;
3807
3808 udelay(5);
3809
3810 val = REG_RD(bp, BNX2_NVM_COMMAND);
3811 if (val & BNX2_NVM_COMMAND_DONE)
3812 break;
3813 }
3814
3815 if (j >= NVRAM_TIMEOUT_COUNT)
3816 return -EBUSY;
3817
3818 return 0;
3819}
3820
3821static int
3822bnx2_nvram_read_dword(struct bnx2 *bp, u32 offset, u8 *ret_val, u32 cmd_flags)
3823{
3824 u32 cmd;
3825 int j;
3826
3827 /* Build the command word. */
3828 cmd = BNX2_NVM_COMMAND_DOIT | cmd_flags;
3829
Michael Chane30372c2007-07-16 18:26:23 -07003830 /* Calculate an offset of a buffered flash, not needed for 5709. */
3831 if (bp->flash_info->flags & BNX2_NV_TRANSLATE) {
Michael Chanb6016b72005-05-26 13:03:09 -07003832 offset = ((offset / bp->flash_info->page_size) <<
3833 bp->flash_info->page_bits) +
3834 (offset % bp->flash_info->page_size);
3835 }
3836
3837 /* Need to clear DONE bit separately. */
3838 REG_WR(bp, BNX2_NVM_COMMAND, BNX2_NVM_COMMAND_DONE);
3839
3840 /* Address of the NVRAM to read from. */
3841 REG_WR(bp, BNX2_NVM_ADDR, offset & BNX2_NVM_ADDR_NVM_ADDR_VALUE);
3842
3843 /* Issue a read command. */
3844 REG_WR(bp, BNX2_NVM_COMMAND, cmd);
3845
3846 /* Wait for completion. */
3847 for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) {
3848 u32 val;
3849
3850 udelay(5);
3851
3852 val = REG_RD(bp, BNX2_NVM_COMMAND);
3853 if (val & BNX2_NVM_COMMAND_DONE) {
Al Virob491edd2007-12-22 19:44:51 +00003854 __be32 v = cpu_to_be32(REG_RD(bp, BNX2_NVM_READ));
3855 memcpy(ret_val, &v, 4);
Michael Chanb6016b72005-05-26 13:03:09 -07003856 break;
3857 }
3858 }
3859 if (j >= NVRAM_TIMEOUT_COUNT)
3860 return -EBUSY;
3861
3862 return 0;
3863}
3864
3865
3866static int
3867bnx2_nvram_write_dword(struct bnx2 *bp, u32 offset, u8 *val, u32 cmd_flags)
3868{
Al Virob491edd2007-12-22 19:44:51 +00003869 u32 cmd;
3870 __be32 val32;
Michael Chanb6016b72005-05-26 13:03:09 -07003871 int j;
3872
3873 /* Build the command word. */
3874 cmd = BNX2_NVM_COMMAND_DOIT | BNX2_NVM_COMMAND_WR | cmd_flags;
3875
Michael Chane30372c2007-07-16 18:26:23 -07003876 /* Calculate an offset of a buffered flash, not needed for 5709. */
3877 if (bp->flash_info->flags & BNX2_NV_TRANSLATE) {
Michael Chanb6016b72005-05-26 13:03:09 -07003878 offset = ((offset / bp->flash_info->page_size) <<
3879 bp->flash_info->page_bits) +
3880 (offset % bp->flash_info->page_size);
3881 }
3882
3883 /* Need to clear DONE bit separately. */
3884 REG_WR(bp, BNX2_NVM_COMMAND, BNX2_NVM_COMMAND_DONE);
3885
3886 memcpy(&val32, val, 4);
Michael Chanb6016b72005-05-26 13:03:09 -07003887
3888 /* Write the data. */
Al Virob491edd2007-12-22 19:44:51 +00003889 REG_WR(bp, BNX2_NVM_WRITE, be32_to_cpu(val32));
Michael Chanb6016b72005-05-26 13:03:09 -07003890
3891 /* Address of the NVRAM to write to. */
3892 REG_WR(bp, BNX2_NVM_ADDR, offset & BNX2_NVM_ADDR_NVM_ADDR_VALUE);
3893
3894 /* Issue the write command. */
3895 REG_WR(bp, BNX2_NVM_COMMAND, cmd);
3896
3897 /* Wait for completion. */
3898 for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) {
3899 udelay(5);
3900
3901 if (REG_RD(bp, BNX2_NVM_COMMAND) & BNX2_NVM_COMMAND_DONE)
3902 break;
3903 }
3904 if (j >= NVRAM_TIMEOUT_COUNT)
3905 return -EBUSY;
3906
3907 return 0;
3908}
3909
3910static int
3911bnx2_init_nvram(struct bnx2 *bp)
3912{
3913 u32 val;
Michael Chane30372c2007-07-16 18:26:23 -07003914 int j, entry_count, rc = 0;
Michael Chanb6016b72005-05-26 13:03:09 -07003915 struct flash_spec *flash;
3916
Michael Chane30372c2007-07-16 18:26:23 -07003917 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
3918 bp->flash_info = &flash_5709;
3919 goto get_flash_size;
3920 }
3921
Michael Chanb6016b72005-05-26 13:03:09 -07003922 /* Determine the selected interface. */
3923 val = REG_RD(bp, BNX2_NVM_CFG1);
3924
Denis Chengff8ac602007-09-02 18:30:18 +08003925 entry_count = ARRAY_SIZE(flash_table);
Michael Chanb6016b72005-05-26 13:03:09 -07003926
Michael Chanb6016b72005-05-26 13:03:09 -07003927 if (val & 0x40000000) {
3928
3929 /* Flash interface has been reconfigured */
3930 for (j = 0, flash = &flash_table[0]; j < entry_count;
Michael Chan37137702005-11-04 08:49:17 -08003931 j++, flash++) {
3932 if ((val & FLASH_BACKUP_STRAP_MASK) ==
3933 (flash->config1 & FLASH_BACKUP_STRAP_MASK)) {
Michael Chanb6016b72005-05-26 13:03:09 -07003934 bp->flash_info = flash;
3935 break;
3936 }
3937 }
3938 }
3939 else {
Michael Chan37137702005-11-04 08:49:17 -08003940 u32 mask;
Michael Chanb6016b72005-05-26 13:03:09 -07003941 /* Not yet been reconfigured */
3942
Michael Chan37137702005-11-04 08:49:17 -08003943 if (val & (1 << 23))
3944 mask = FLASH_BACKUP_STRAP_MASK;
3945 else
3946 mask = FLASH_STRAP_MASK;
3947
Michael Chanb6016b72005-05-26 13:03:09 -07003948 for (j = 0, flash = &flash_table[0]; j < entry_count;
3949 j++, flash++) {
3950
Michael Chan37137702005-11-04 08:49:17 -08003951 if ((val & mask) == (flash->strapping & mask)) {
Michael Chanb6016b72005-05-26 13:03:09 -07003952 bp->flash_info = flash;
3953
3954 /* Request access to the flash interface. */
3955 if ((rc = bnx2_acquire_nvram_lock(bp)) != 0)
3956 return rc;
3957
3958 /* Enable access to flash interface */
3959 bnx2_enable_nvram_access(bp);
3960
3961 /* Reconfigure the flash interface */
3962 REG_WR(bp, BNX2_NVM_CFG1, flash->config1);
3963 REG_WR(bp, BNX2_NVM_CFG2, flash->config2);
3964 REG_WR(bp, BNX2_NVM_CFG3, flash->config3);
3965 REG_WR(bp, BNX2_NVM_WRITE1, flash->write1);
3966
3967 /* Disable access to flash interface */
3968 bnx2_disable_nvram_access(bp);
3969 bnx2_release_nvram_lock(bp);
3970
3971 break;
3972 }
3973 }
3974 } /* if (val & 0x40000000) */
3975
3976 if (j == entry_count) {
3977 bp->flash_info = NULL;
John W. Linville2f23c522005-11-10 12:57:33 -08003978 printk(KERN_ALERT PFX "Unknown flash/EEPROM type.\n");
Michael Chan1122db72006-01-23 16:11:42 -08003979 return -ENODEV;
Michael Chanb6016b72005-05-26 13:03:09 -07003980 }
3981
Michael Chane30372c2007-07-16 18:26:23 -07003982get_flash_size:
Michael Chan2726d6e2008-01-29 21:35:05 -08003983 val = bnx2_shmem_rd(bp, BNX2_SHARED_HW_CFG_CONFIG2);
Michael Chan1122db72006-01-23 16:11:42 -08003984 val &= BNX2_SHARED_HW_CFG2_NVM_SIZE_MASK;
3985 if (val)
3986 bp->flash_size = val;
3987 else
3988 bp->flash_size = bp->flash_info->total_size;
3989
Michael Chanb6016b72005-05-26 13:03:09 -07003990 return rc;
3991}
3992
3993static int
3994bnx2_nvram_read(struct bnx2 *bp, u32 offset, u8 *ret_buf,
3995 int buf_size)
3996{
3997 int rc = 0;
3998 u32 cmd_flags, offset32, len32, extra;
3999
4000 if (buf_size == 0)
4001 return 0;
4002
4003 /* Request access to the flash interface. */
4004 if ((rc = bnx2_acquire_nvram_lock(bp)) != 0)
4005 return rc;
4006
4007 /* Enable access to flash interface */
4008 bnx2_enable_nvram_access(bp);
4009
4010 len32 = buf_size;
4011 offset32 = offset;
4012 extra = 0;
4013
4014 cmd_flags = 0;
4015
4016 if (offset32 & 3) {
4017 u8 buf[4];
4018 u32 pre_len;
4019
4020 offset32 &= ~3;
4021 pre_len = 4 - (offset & 3);
4022
4023 if (pre_len >= len32) {
4024 pre_len = len32;
4025 cmd_flags = BNX2_NVM_COMMAND_FIRST |
4026 BNX2_NVM_COMMAND_LAST;
4027 }
4028 else {
4029 cmd_flags = BNX2_NVM_COMMAND_FIRST;
4030 }
4031
4032 rc = bnx2_nvram_read_dword(bp, offset32, buf, cmd_flags);
4033
4034 if (rc)
4035 return rc;
4036
4037 memcpy(ret_buf, buf + (offset & 3), pre_len);
4038
4039 offset32 += 4;
4040 ret_buf += pre_len;
4041 len32 -= pre_len;
4042 }
4043 if (len32 & 3) {
4044 extra = 4 - (len32 & 3);
4045 len32 = (len32 + 4) & ~3;
4046 }
4047
4048 if (len32 == 4) {
4049 u8 buf[4];
4050
4051 if (cmd_flags)
4052 cmd_flags = BNX2_NVM_COMMAND_LAST;
4053 else
4054 cmd_flags = BNX2_NVM_COMMAND_FIRST |
4055 BNX2_NVM_COMMAND_LAST;
4056
4057 rc = bnx2_nvram_read_dword(bp, offset32, buf, cmd_flags);
4058
4059 memcpy(ret_buf, buf, 4 - extra);
4060 }
4061 else if (len32 > 0) {
4062 u8 buf[4];
4063
4064 /* Read the first word. */
4065 if (cmd_flags)
4066 cmd_flags = 0;
4067 else
4068 cmd_flags = BNX2_NVM_COMMAND_FIRST;
4069
4070 rc = bnx2_nvram_read_dword(bp, offset32, ret_buf, cmd_flags);
4071
4072 /* Advance to the next dword. */
4073 offset32 += 4;
4074 ret_buf += 4;
4075 len32 -= 4;
4076
4077 while (len32 > 4 && rc == 0) {
4078 rc = bnx2_nvram_read_dword(bp, offset32, ret_buf, 0);
4079
4080 /* Advance to the next dword. */
4081 offset32 += 4;
4082 ret_buf += 4;
4083 len32 -= 4;
4084 }
4085
4086 if (rc)
4087 return rc;
4088
4089 cmd_flags = BNX2_NVM_COMMAND_LAST;
4090 rc = bnx2_nvram_read_dword(bp, offset32, buf, cmd_flags);
4091
4092 memcpy(ret_buf, buf, 4 - extra);
4093 }
4094
4095 /* Disable access to flash interface */
4096 bnx2_disable_nvram_access(bp);
4097
4098 bnx2_release_nvram_lock(bp);
4099
4100 return rc;
4101}
4102
4103static int
4104bnx2_nvram_write(struct bnx2 *bp, u32 offset, u8 *data_buf,
4105 int buf_size)
4106{
4107 u32 written, offset32, len32;
Michael Chane6be7632007-01-08 19:56:13 -08004108 u8 *buf, start[4], end[4], *align_buf = NULL, *flash_buffer = NULL;
Michael Chanb6016b72005-05-26 13:03:09 -07004109 int rc = 0;
4110 int align_start, align_end;
4111
4112 buf = data_buf;
4113 offset32 = offset;
4114 len32 = buf_size;
4115 align_start = align_end = 0;
4116
4117 if ((align_start = (offset32 & 3))) {
4118 offset32 &= ~3;
Michael Chanc8738792007-03-30 14:53:06 -07004119 len32 += align_start;
4120 if (len32 < 4)
4121 len32 = 4;
Michael Chanb6016b72005-05-26 13:03:09 -07004122 if ((rc = bnx2_nvram_read(bp, offset32, start, 4)))
4123 return rc;
4124 }
4125
4126 if (len32 & 3) {
Michael Chanc8738792007-03-30 14:53:06 -07004127 align_end = 4 - (len32 & 3);
4128 len32 += align_end;
4129 if ((rc = bnx2_nvram_read(bp, offset32 + len32 - 4, end, 4)))
4130 return rc;
Michael Chanb6016b72005-05-26 13:03:09 -07004131 }
4132
4133 if (align_start || align_end) {
Michael Chane6be7632007-01-08 19:56:13 -08004134 align_buf = kmalloc(len32, GFP_KERNEL);
4135 if (align_buf == NULL)
Michael Chanb6016b72005-05-26 13:03:09 -07004136 return -ENOMEM;
4137 if (align_start) {
Michael Chane6be7632007-01-08 19:56:13 -08004138 memcpy(align_buf, start, 4);
Michael Chanb6016b72005-05-26 13:03:09 -07004139 }
4140 if (align_end) {
Michael Chane6be7632007-01-08 19:56:13 -08004141 memcpy(align_buf + len32 - 4, end, 4);
Michael Chanb6016b72005-05-26 13:03:09 -07004142 }
Michael Chane6be7632007-01-08 19:56:13 -08004143 memcpy(align_buf + align_start, data_buf, buf_size);
4144 buf = align_buf;
Michael Chanb6016b72005-05-26 13:03:09 -07004145 }
4146
Michael Chane30372c2007-07-16 18:26:23 -07004147 if (!(bp->flash_info->flags & BNX2_NV_BUFFERED)) {
Michael Chanae181bc2006-05-22 16:39:20 -07004148 flash_buffer = kmalloc(264, GFP_KERNEL);
4149 if (flash_buffer == NULL) {
4150 rc = -ENOMEM;
4151 goto nvram_write_end;
4152 }
4153 }
4154
Michael Chanb6016b72005-05-26 13:03:09 -07004155 written = 0;
4156 while ((written < len32) && (rc == 0)) {
4157 u32 page_start, page_end, data_start, data_end;
4158 u32 addr, cmd_flags;
4159 int i;
Michael Chanb6016b72005-05-26 13:03:09 -07004160
4161 /* Find the page_start addr */
4162 page_start = offset32 + written;
4163 page_start -= (page_start % bp->flash_info->page_size);
4164 /* Find the page_end addr */
4165 page_end = page_start + bp->flash_info->page_size;
4166 /* Find the data_start addr */
4167 data_start = (written == 0) ? offset32 : page_start;
4168 /* Find the data_end addr */
Jeff Garzik6aa20a22006-09-13 13:24:59 -04004169 data_end = (page_end > offset32 + len32) ?
Michael Chanb6016b72005-05-26 13:03:09 -07004170 (offset32 + len32) : page_end;
4171
4172 /* Request access to the flash interface. */
4173 if ((rc = bnx2_acquire_nvram_lock(bp)) != 0)
4174 goto nvram_write_end;
4175
4176 /* Enable access to flash interface */
4177 bnx2_enable_nvram_access(bp);
4178
4179 cmd_flags = BNX2_NVM_COMMAND_FIRST;
Michael Chane30372c2007-07-16 18:26:23 -07004180 if (!(bp->flash_info->flags & BNX2_NV_BUFFERED)) {
Michael Chanb6016b72005-05-26 13:03:09 -07004181 int j;
4182
4183 /* Read the whole page into the buffer
4184 * (non-buffer flash only) */
4185 for (j = 0; j < bp->flash_info->page_size; j += 4) {
4186 if (j == (bp->flash_info->page_size - 4)) {
4187 cmd_flags |= BNX2_NVM_COMMAND_LAST;
4188 }
4189 rc = bnx2_nvram_read_dword(bp,
Jeff Garzik6aa20a22006-09-13 13:24:59 -04004190 page_start + j,
4191 &flash_buffer[j],
Michael Chanb6016b72005-05-26 13:03:09 -07004192 cmd_flags);
4193
4194 if (rc)
4195 goto nvram_write_end;
4196
4197 cmd_flags = 0;
4198 }
4199 }
4200
4201 /* Enable writes to flash interface (unlock write-protect) */
4202 if ((rc = bnx2_enable_nvram_write(bp)) != 0)
4203 goto nvram_write_end;
4204
Michael Chanb6016b72005-05-26 13:03:09 -07004205 /* Loop to write back the buffer data from page_start to
4206 * data_start */
4207 i = 0;
Michael Chane30372c2007-07-16 18:26:23 -07004208 if (!(bp->flash_info->flags & BNX2_NV_BUFFERED)) {
Michael Chanc8738792007-03-30 14:53:06 -07004209 /* Erase the page */
4210 if ((rc = bnx2_nvram_erase_page(bp, page_start)) != 0)
4211 goto nvram_write_end;
4212
4213 /* Re-enable the write again for the actual write */
4214 bnx2_enable_nvram_write(bp);
4215
Michael Chanb6016b72005-05-26 13:03:09 -07004216 for (addr = page_start; addr < data_start;
4217 addr += 4, i += 4) {
Jeff Garzik6aa20a22006-09-13 13:24:59 -04004218
Michael Chanb6016b72005-05-26 13:03:09 -07004219 rc = bnx2_nvram_write_dword(bp, addr,
4220 &flash_buffer[i], cmd_flags);
4221
4222 if (rc != 0)
4223 goto nvram_write_end;
4224
4225 cmd_flags = 0;
4226 }
4227 }
4228
4229 /* Loop to write the new data from data_start to data_end */
Michael Chanbae25762006-05-22 16:38:38 -07004230 for (addr = data_start; addr < data_end; addr += 4, i += 4) {
Michael Chanb6016b72005-05-26 13:03:09 -07004231 if ((addr == page_end - 4) ||
Michael Chane30372c2007-07-16 18:26:23 -07004232 ((bp->flash_info->flags & BNX2_NV_BUFFERED) &&
Michael Chanb6016b72005-05-26 13:03:09 -07004233 (addr == data_end - 4))) {
4234
4235 cmd_flags |= BNX2_NVM_COMMAND_LAST;
4236 }
4237 rc = bnx2_nvram_write_dword(bp, addr, buf,
4238 cmd_flags);
4239
4240 if (rc != 0)
4241 goto nvram_write_end;
4242
4243 cmd_flags = 0;
4244 buf += 4;
4245 }
4246
4247 /* Loop to write back the buffer data from data_end
4248 * to page_end */
Michael Chane30372c2007-07-16 18:26:23 -07004249 if (!(bp->flash_info->flags & BNX2_NV_BUFFERED)) {
Michael Chanb6016b72005-05-26 13:03:09 -07004250 for (addr = data_end; addr < page_end;
4251 addr += 4, i += 4) {
Jeff Garzik6aa20a22006-09-13 13:24:59 -04004252
Michael Chanb6016b72005-05-26 13:03:09 -07004253 if (addr == page_end-4) {
4254 cmd_flags = BNX2_NVM_COMMAND_LAST;
4255 }
4256 rc = bnx2_nvram_write_dword(bp, addr,
4257 &flash_buffer[i], cmd_flags);
4258
4259 if (rc != 0)
4260 goto nvram_write_end;
4261
4262 cmd_flags = 0;
4263 }
4264 }
4265
4266 /* Disable writes to flash interface (lock write-protect) */
4267 bnx2_disable_nvram_write(bp);
4268
4269 /* Disable access to flash interface */
4270 bnx2_disable_nvram_access(bp);
4271 bnx2_release_nvram_lock(bp);
4272
4273 /* Increment written */
4274 written += data_end - data_start;
4275 }
4276
4277nvram_write_end:
Michael Chane6be7632007-01-08 19:56:13 -08004278 kfree(flash_buffer);
4279 kfree(align_buf);
Michael Chanb6016b72005-05-26 13:03:09 -07004280 return rc;
4281}
4282
Michael Chan0d8a6572007-07-07 22:49:43 -07004283static void
Michael Chan7c62e832008-07-14 22:39:03 -07004284bnx2_init_fw_cap(struct bnx2 *bp)
Michael Chan0d8a6572007-07-07 22:49:43 -07004285{
Michael Chan7c62e832008-07-14 22:39:03 -07004286 u32 val, sig = 0;
Michael Chan0d8a6572007-07-07 22:49:43 -07004287
Michael Chan583c28e2008-01-21 19:51:35 -08004288 bp->phy_flags &= ~BNX2_PHY_FLAG_REMOTE_PHY_CAP;
Michael Chan7c62e832008-07-14 22:39:03 -07004289 bp->flags &= ~BNX2_FLAG_CAN_KEEP_VLAN;
4290
4291 if (!(bp->flags & BNX2_FLAG_ASF_ENABLE))
4292 bp->flags |= BNX2_FLAG_CAN_KEEP_VLAN;
Michael Chan0d8a6572007-07-07 22:49:43 -07004293
Michael Chan2726d6e2008-01-29 21:35:05 -08004294 val = bnx2_shmem_rd(bp, BNX2_FW_CAP_MB);
Michael Chan0d8a6572007-07-07 22:49:43 -07004295 if ((val & BNX2_FW_CAP_SIGNATURE_MASK) != BNX2_FW_CAP_SIGNATURE)
4296 return;
4297
Michael Chan7c62e832008-07-14 22:39:03 -07004298 if ((val & BNX2_FW_CAP_CAN_KEEP_VLAN) == BNX2_FW_CAP_CAN_KEEP_VLAN) {
4299 bp->flags |= BNX2_FLAG_CAN_KEEP_VLAN;
4300 sig |= BNX2_DRV_ACK_CAP_SIGNATURE | BNX2_FW_CAP_CAN_KEEP_VLAN;
4301 }
4302
4303 if ((bp->phy_flags & BNX2_PHY_FLAG_SERDES) &&
4304 (val & BNX2_FW_CAP_REMOTE_PHY_CAPABLE)) {
4305 u32 link;
4306
Michael Chan583c28e2008-01-21 19:51:35 -08004307 bp->phy_flags |= BNX2_PHY_FLAG_REMOTE_PHY_CAP;
Michael Chan0d8a6572007-07-07 22:49:43 -07004308
Michael Chan7c62e832008-07-14 22:39:03 -07004309 link = bnx2_shmem_rd(bp, BNX2_LINK_STATUS);
4310 if (link & BNX2_LINK_STATUS_SERDES_LINK)
Michael Chan0d8a6572007-07-07 22:49:43 -07004311 bp->phy_port = PORT_FIBRE;
4312 else
4313 bp->phy_port = PORT_TP;
Michael Chan489310a2007-10-10 16:16:31 -07004314
Michael Chan7c62e832008-07-14 22:39:03 -07004315 sig |= BNX2_DRV_ACK_CAP_SIGNATURE |
4316 BNX2_FW_CAP_REMOTE_PHY_CAPABLE;
Michael Chan0d8a6572007-07-07 22:49:43 -07004317 }
Michael Chan7c62e832008-07-14 22:39:03 -07004318
4319 if (netif_running(bp->dev) && sig)
4320 bnx2_shmem_wr(bp, BNX2_DRV_ACK_CAP_MB, sig);
Michael Chan0d8a6572007-07-07 22:49:43 -07004321}
4322
Michael Chanb4b36042007-12-20 19:59:30 -08004323static void
4324bnx2_setup_msix_tbl(struct bnx2 *bp)
4325{
4326 REG_WR(bp, BNX2_PCI_GRC_WINDOW_ADDR, BNX2_PCI_GRC_WINDOW_ADDR_SEP_WIN);
4327
4328 REG_WR(bp, BNX2_PCI_GRC_WINDOW2_ADDR, BNX2_MSIX_TABLE_ADDR);
4329 REG_WR(bp, BNX2_PCI_GRC_WINDOW3_ADDR, BNX2_MSIX_PBA_ADDR);
4330}
4331
Michael Chanb6016b72005-05-26 13:03:09 -07004332static int
4333bnx2_reset_chip(struct bnx2 *bp, u32 reset_code)
4334{
4335 u32 val;
4336 int i, rc = 0;
Michael Chan489310a2007-10-10 16:16:31 -07004337 u8 old_port;
Michael Chanb6016b72005-05-26 13:03:09 -07004338
4339 /* Wait for the current PCI transaction to complete before
4340 * issuing a reset. */
4341 REG_WR(bp, BNX2_MISC_ENABLE_CLR_BITS,
4342 BNX2_MISC_ENABLE_CLR_BITS_TX_DMA_ENABLE |
4343 BNX2_MISC_ENABLE_CLR_BITS_DMA_ENGINE_ENABLE |
4344 BNX2_MISC_ENABLE_CLR_BITS_RX_DMA_ENABLE |
4345 BNX2_MISC_ENABLE_CLR_BITS_HOST_COALESCE_ENABLE);
4346 val = REG_RD(bp, BNX2_MISC_ENABLE_CLR_BITS);
4347 udelay(5);
4348
Michael Chanb090ae22006-01-23 16:07:10 -08004349 /* Wait for the firmware to tell us it is ok to issue a reset. */
Michael Chana2f13892008-07-14 22:38:23 -07004350 bnx2_fw_sync(bp, BNX2_DRV_MSG_DATA_WAIT0 | reset_code, 1, 1);
Michael Chanb090ae22006-01-23 16:07:10 -08004351
Michael Chanb6016b72005-05-26 13:03:09 -07004352 /* Deposit a driver reset signature so the firmware knows that
4353 * this is a soft reset. */
Michael Chan2726d6e2008-01-29 21:35:05 -08004354 bnx2_shmem_wr(bp, BNX2_DRV_RESET_SIGNATURE,
4355 BNX2_DRV_RESET_SIGNATURE_MAGIC);
Michael Chanb6016b72005-05-26 13:03:09 -07004356
Michael Chanb6016b72005-05-26 13:03:09 -07004357 /* Do a dummy read to force the chip to complete all current transaction
4358 * before we issue a reset. */
4359 val = REG_RD(bp, BNX2_MISC_ID);
4360
Michael Chan234754d2006-11-19 14:11:41 -08004361 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
4362 REG_WR(bp, BNX2_MISC_COMMAND, BNX2_MISC_COMMAND_SW_RESET);
4363 REG_RD(bp, BNX2_MISC_COMMAND);
4364 udelay(5);
Michael Chanb6016b72005-05-26 13:03:09 -07004365
Michael Chan234754d2006-11-19 14:11:41 -08004366 val = BNX2_PCICFG_MISC_CONFIG_REG_WINDOW_ENA |
4367 BNX2_PCICFG_MISC_CONFIG_TARGET_MB_WORD_SWAP;
Michael Chanb6016b72005-05-26 13:03:09 -07004368
Michael Chan234754d2006-11-19 14:11:41 -08004369 pci_write_config_dword(bp->pdev, BNX2_PCICFG_MISC_CONFIG, val);
Michael Chanb6016b72005-05-26 13:03:09 -07004370
Michael Chan234754d2006-11-19 14:11:41 -08004371 } else {
4372 val = BNX2_PCICFG_MISC_CONFIG_CORE_RST_REQ |
4373 BNX2_PCICFG_MISC_CONFIG_REG_WINDOW_ENA |
4374 BNX2_PCICFG_MISC_CONFIG_TARGET_MB_WORD_SWAP;
4375
4376 /* Chip reset. */
4377 REG_WR(bp, BNX2_PCICFG_MISC_CONFIG, val);
4378
Michael Chan594a9df2007-08-28 15:39:42 -07004379 /* Reading back any register after chip reset will hang the
4380 * bus on 5706 A0 and A1. The msleep below provides plenty
4381 * of margin for write posting.
4382 */
Michael Chan234754d2006-11-19 14:11:41 -08004383 if ((CHIP_ID(bp) == CHIP_ID_5706_A0) ||
Arjan van de Ven8e545882007-08-28 14:34:43 -07004384 (CHIP_ID(bp) == CHIP_ID_5706_A1))
4385 msleep(20);
Michael Chanb6016b72005-05-26 13:03:09 -07004386
Michael Chan234754d2006-11-19 14:11:41 -08004387 /* Reset takes approximate 30 usec */
4388 for (i = 0; i < 10; i++) {
4389 val = REG_RD(bp, BNX2_PCICFG_MISC_CONFIG);
4390 if ((val & (BNX2_PCICFG_MISC_CONFIG_CORE_RST_REQ |
4391 BNX2_PCICFG_MISC_CONFIG_CORE_RST_BSY)) == 0)
4392 break;
4393 udelay(10);
4394 }
4395
4396 if (val & (BNX2_PCICFG_MISC_CONFIG_CORE_RST_REQ |
4397 BNX2_PCICFG_MISC_CONFIG_CORE_RST_BSY)) {
4398 printk(KERN_ERR PFX "Chip reset did not complete\n");
4399 return -EBUSY;
4400 }
Michael Chanb6016b72005-05-26 13:03:09 -07004401 }
4402
4403 /* Make sure byte swapping is properly configured. */
4404 val = REG_RD(bp, BNX2_PCI_SWAP_DIAG0);
4405 if (val != 0x01020304) {
4406 printk(KERN_ERR PFX "Chip not in correct endian mode\n");
4407 return -ENODEV;
4408 }
4409
Michael Chanb6016b72005-05-26 13:03:09 -07004410 /* Wait for the firmware to finish its initialization. */
Michael Chana2f13892008-07-14 22:38:23 -07004411 rc = bnx2_fw_sync(bp, BNX2_DRV_MSG_DATA_WAIT1 | reset_code, 1, 0);
Michael Chanb090ae22006-01-23 16:07:10 -08004412 if (rc)
4413 return rc;
Michael Chanb6016b72005-05-26 13:03:09 -07004414
Michael Chan0d8a6572007-07-07 22:49:43 -07004415 spin_lock_bh(&bp->phy_lock);
Michael Chan489310a2007-10-10 16:16:31 -07004416 old_port = bp->phy_port;
Michael Chan7c62e832008-07-14 22:39:03 -07004417 bnx2_init_fw_cap(bp);
Michael Chan583c28e2008-01-21 19:51:35 -08004418 if ((bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP) &&
4419 old_port != bp->phy_port)
Michael Chan0d8a6572007-07-07 22:49:43 -07004420 bnx2_set_default_remote_link(bp);
4421 spin_unlock_bh(&bp->phy_lock);
4422
Michael Chanb6016b72005-05-26 13:03:09 -07004423 if (CHIP_ID(bp) == CHIP_ID_5706_A0) {
4424 /* Adjust the voltage regular to two steps lower. The default
4425 * of this register is 0x0000000e. */
4426 REG_WR(bp, BNX2_MISC_VREG_CONTROL, 0x000000fa);
4427
4428 /* Remove bad rbuf memory from the free pool. */
4429 rc = bnx2_alloc_bad_rbuf(bp);
4430 }
4431
David S. Millerf86e82f2008-01-21 17:15:40 -08004432 if (bp->flags & BNX2_FLAG_USING_MSIX)
Michael Chanb4b36042007-12-20 19:59:30 -08004433 bnx2_setup_msix_tbl(bp);
4434
Michael Chanb6016b72005-05-26 13:03:09 -07004435 return rc;
4436}
4437
4438static int
4439bnx2_init_chip(struct bnx2 *bp)
4440{
4441 u32 val;
Michael Chanb4b36042007-12-20 19:59:30 -08004442 int rc, i;
Michael Chanb6016b72005-05-26 13:03:09 -07004443
4444 /* Make sure the interrupt is not active. */
4445 REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD, BNX2_PCICFG_INT_ACK_CMD_MASK_INT);
4446
4447 val = BNX2_DMA_CONFIG_DATA_BYTE_SWAP |
4448 BNX2_DMA_CONFIG_DATA_WORD_SWAP |
4449#ifdef __BIG_ENDIAN
Jeff Garzik6aa20a22006-09-13 13:24:59 -04004450 BNX2_DMA_CONFIG_CNTL_BYTE_SWAP |
Michael Chanb6016b72005-05-26 13:03:09 -07004451#endif
Jeff Garzik6aa20a22006-09-13 13:24:59 -04004452 BNX2_DMA_CONFIG_CNTL_WORD_SWAP |
Michael Chanb6016b72005-05-26 13:03:09 -07004453 DMA_READ_CHANS << 12 |
4454 DMA_WRITE_CHANS << 16;
4455
4456 val |= (0x2 << 20) | (1 << 11);
4457
David S. Millerf86e82f2008-01-21 17:15:40 -08004458 if ((bp->flags & BNX2_FLAG_PCIX) && (bp->bus_speed_mhz == 133))
Michael Chanb6016b72005-05-26 13:03:09 -07004459 val |= (1 << 23);
4460
4461 if ((CHIP_NUM(bp) == CHIP_NUM_5706) &&
David S. Millerf86e82f2008-01-21 17:15:40 -08004462 (CHIP_ID(bp) != CHIP_ID_5706_A0) && !(bp->flags & BNX2_FLAG_PCIX))
Michael Chanb6016b72005-05-26 13:03:09 -07004463 val |= BNX2_DMA_CONFIG_CNTL_PING_PONG_DMA;
4464
4465 REG_WR(bp, BNX2_DMA_CONFIG, val);
4466
4467 if (CHIP_ID(bp) == CHIP_ID_5706_A0) {
4468 val = REG_RD(bp, BNX2_TDMA_CONFIG);
4469 val |= BNX2_TDMA_CONFIG_ONE_DMA;
4470 REG_WR(bp, BNX2_TDMA_CONFIG, val);
4471 }
4472
David S. Millerf86e82f2008-01-21 17:15:40 -08004473 if (bp->flags & BNX2_FLAG_PCIX) {
Michael Chanb6016b72005-05-26 13:03:09 -07004474 u16 val16;
4475
4476 pci_read_config_word(bp->pdev, bp->pcix_cap + PCI_X_CMD,
4477 &val16);
4478 pci_write_config_word(bp->pdev, bp->pcix_cap + PCI_X_CMD,
4479 val16 & ~PCI_X_CMD_ERO);
4480 }
4481
4482 REG_WR(bp, BNX2_MISC_ENABLE_SET_BITS,
4483 BNX2_MISC_ENABLE_SET_BITS_HOST_COALESCE_ENABLE |
4484 BNX2_MISC_ENABLE_STATUS_BITS_RX_V2P_ENABLE |
4485 BNX2_MISC_ENABLE_STATUS_BITS_CONTEXT_ENABLE);
4486
4487 /* Initialize context mapping and zero out the quick contexts. The
4488 * context block must have already been enabled. */
Michael Chan641bdcd2007-06-04 21:22:24 -07004489 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
4490 rc = bnx2_init_5709_context(bp);
4491 if (rc)
4492 return rc;
4493 } else
Michael Chan59b47d82006-11-19 14:10:45 -08004494 bnx2_init_context(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07004495
Michael Chanfba9fe92006-06-12 22:21:25 -07004496 if ((rc = bnx2_init_cpus(bp)) != 0)
4497 return rc;
4498
Michael Chanb6016b72005-05-26 13:03:09 -07004499 bnx2_init_nvram(bp);
4500
Benjamin Li5fcaed02008-07-14 22:39:52 -07004501 bnx2_set_mac_addr(bp, bp->dev->dev_addr, 0);
Michael Chanb6016b72005-05-26 13:03:09 -07004502
4503 val = REG_RD(bp, BNX2_MQ_CONFIG);
4504 val &= ~BNX2_MQ_CONFIG_KNL_BYP_BLK_SIZE;
4505 val |= BNX2_MQ_CONFIG_KNL_BYP_BLK_SIZE_256;
Michael Chan68c9f752007-04-24 15:35:53 -07004506 if (CHIP_ID(bp) == CHIP_ID_5709_A0 || CHIP_ID(bp) == CHIP_ID_5709_A1)
4507 val |= BNX2_MQ_CONFIG_HALT_DIS;
4508
Michael Chanb6016b72005-05-26 13:03:09 -07004509 REG_WR(bp, BNX2_MQ_CONFIG, val);
4510
4511 val = 0x10000 + (MAX_CID_CNT * MB_KERNEL_CTX_SIZE);
4512 REG_WR(bp, BNX2_MQ_KNL_BYP_WIND_START, val);
4513 REG_WR(bp, BNX2_MQ_KNL_WIND_END, val);
4514
4515 val = (BCM_PAGE_BITS - 8) << 24;
4516 REG_WR(bp, BNX2_RV2P_CONFIG, val);
4517
4518 /* Configure page size. */
4519 val = REG_RD(bp, BNX2_TBDR_CONFIG);
4520 val &= ~BNX2_TBDR_CONFIG_PAGE_SIZE;
4521 val |= (BCM_PAGE_BITS - 8) << 24 | 0x40;
4522 REG_WR(bp, BNX2_TBDR_CONFIG, val);
4523
4524 val = bp->mac_addr[0] +
4525 (bp->mac_addr[1] << 8) +
4526 (bp->mac_addr[2] << 16) +
4527 bp->mac_addr[3] +
4528 (bp->mac_addr[4] << 8) +
4529 (bp->mac_addr[5] << 16);
4530 REG_WR(bp, BNX2_EMAC_BACKOFF_SEED, val);
4531
4532 /* Program the MTU. Also include 4 bytes for CRC32. */
4533 val = bp->dev->mtu + ETH_HLEN + 4;
4534 if (val > (MAX_ETHERNET_PACKET_SIZE + 4))
4535 val |= BNX2_EMAC_RX_MTU_SIZE_JUMBO_ENA;
4536 REG_WR(bp, BNX2_EMAC_RX_MTU_SIZE, val);
4537
Michael Chanb4b36042007-12-20 19:59:30 -08004538 for (i = 0; i < BNX2_MAX_MSIX_VEC; i++)
4539 bp->bnx2_napi[i].last_status_idx = 0;
4540
Michael Chanb6016b72005-05-26 13:03:09 -07004541 bp->rx_mode = BNX2_EMAC_RX_MODE_SORT_MODE;
4542
4543 /* Set up how to generate a link change interrupt. */
4544 REG_WR(bp, BNX2_EMAC_ATTENTION_ENA, BNX2_EMAC_ATTENTION_ENA_LINK);
4545
4546 REG_WR(bp, BNX2_HC_STATUS_ADDR_L,
4547 (u64) bp->status_blk_mapping & 0xffffffff);
4548 REG_WR(bp, BNX2_HC_STATUS_ADDR_H, (u64) bp->status_blk_mapping >> 32);
4549
4550 REG_WR(bp, BNX2_HC_STATISTICS_ADDR_L,
4551 (u64) bp->stats_blk_mapping & 0xffffffff);
4552 REG_WR(bp, BNX2_HC_STATISTICS_ADDR_H,
4553 (u64) bp->stats_blk_mapping >> 32);
4554
Jeff Garzik6aa20a22006-09-13 13:24:59 -04004555 REG_WR(bp, BNX2_HC_TX_QUICK_CONS_TRIP,
Michael Chanb6016b72005-05-26 13:03:09 -07004556 (bp->tx_quick_cons_trip_int << 16) | bp->tx_quick_cons_trip);
4557
4558 REG_WR(bp, BNX2_HC_RX_QUICK_CONS_TRIP,
4559 (bp->rx_quick_cons_trip_int << 16) | bp->rx_quick_cons_trip);
4560
4561 REG_WR(bp, BNX2_HC_COMP_PROD_TRIP,
4562 (bp->comp_prod_trip_int << 16) | bp->comp_prod_trip);
4563
4564 REG_WR(bp, BNX2_HC_TX_TICKS, (bp->tx_ticks_int << 16) | bp->tx_ticks);
4565
4566 REG_WR(bp, BNX2_HC_RX_TICKS, (bp->rx_ticks_int << 16) | bp->rx_ticks);
4567
4568 REG_WR(bp, BNX2_HC_COM_TICKS,
4569 (bp->com_ticks_int << 16) | bp->com_ticks);
4570
4571 REG_WR(bp, BNX2_HC_CMD_TICKS,
4572 (bp->cmd_ticks_int << 16) | bp->cmd_ticks);
4573
Michael Chan02537b062007-06-04 21:24:07 -07004574 if (CHIP_NUM(bp) == CHIP_NUM_5708)
4575 REG_WR(bp, BNX2_HC_STATS_TICKS, 0);
4576 else
Michael Chan7ea69202007-07-16 18:27:10 -07004577 REG_WR(bp, BNX2_HC_STATS_TICKS, bp->stats_ticks);
Michael Chanb6016b72005-05-26 13:03:09 -07004578 REG_WR(bp, BNX2_HC_STAT_COLLECT_TICKS, 0xbb8); /* 3ms */
4579
4580 if (CHIP_ID(bp) == CHIP_ID_5706_A1)
Michael Chan8e6a72c2007-05-03 13:24:48 -07004581 val = BNX2_HC_CONFIG_COLLECT_STATS;
Michael Chanb6016b72005-05-26 13:03:09 -07004582 else {
Michael Chan8e6a72c2007-05-03 13:24:48 -07004583 val = BNX2_HC_CONFIG_RX_TMR_MODE | BNX2_HC_CONFIG_TX_TMR_MODE |
4584 BNX2_HC_CONFIG_COLLECT_STATS;
Michael Chanb6016b72005-05-26 13:03:09 -07004585 }
4586
Michael Chan5e9ad9e2008-06-19 16:43:17 -07004587 if (bp->irq_nvecs > 1) {
Michael Chanc76c0472007-12-20 20:01:19 -08004588 REG_WR(bp, BNX2_HC_MSIX_BIT_VECTOR,
4589 BNX2_HC_MSIX_BIT_VECTOR_VAL);
4590
Michael Chan5e9ad9e2008-06-19 16:43:17 -07004591 val |= BNX2_HC_CONFIG_SB_ADDR_INC_128B;
4592 }
4593
4594 if (bp->flags & BNX2_FLAG_ONE_SHOT_MSI)
4595 val |= BNX2_HC_CONFIG_ONE_SHOT;
4596
4597 REG_WR(bp, BNX2_HC_CONFIG, val);
4598
4599 for (i = 1; i < bp->irq_nvecs; i++) {
4600 u32 base = ((i - 1) * BNX2_HC_SB_CONFIG_SIZE) +
4601 BNX2_HC_SB_CONFIG_1;
4602
Michael Chan6f743ca2008-01-29 21:34:08 -08004603 REG_WR(bp, base,
Michael Chanc76c0472007-12-20 20:01:19 -08004604 BNX2_HC_SB_CONFIG_1_TX_TMR_MODE |
Michael Chan5e9ad9e2008-06-19 16:43:17 -07004605 BNX2_HC_SB_CONFIG_1_RX_TMR_MODE |
Michael Chanc76c0472007-12-20 20:01:19 -08004606 BNX2_HC_SB_CONFIG_1_ONE_SHOT);
4607
Michael Chan6f743ca2008-01-29 21:34:08 -08004608 REG_WR(bp, base + BNX2_HC_TX_QUICK_CONS_TRIP_OFF,
Michael Chanc76c0472007-12-20 20:01:19 -08004609 (bp->tx_quick_cons_trip_int << 16) |
4610 bp->tx_quick_cons_trip);
4611
Michael Chan6f743ca2008-01-29 21:34:08 -08004612 REG_WR(bp, base + BNX2_HC_TX_TICKS_OFF,
Michael Chanc76c0472007-12-20 20:01:19 -08004613 (bp->tx_ticks_int << 16) | bp->tx_ticks);
4614
Michael Chan5e9ad9e2008-06-19 16:43:17 -07004615 REG_WR(bp, base + BNX2_HC_RX_QUICK_CONS_TRIP_OFF,
4616 (bp->rx_quick_cons_trip_int << 16) |
4617 bp->rx_quick_cons_trip);
4618
4619 REG_WR(bp, base + BNX2_HC_RX_TICKS_OFF,
4620 (bp->rx_ticks_int << 16) | bp->rx_ticks);
Michael Chanc76c0472007-12-20 20:01:19 -08004621 }
4622
Michael Chanb6016b72005-05-26 13:03:09 -07004623 /* Clear internal stats counters. */
4624 REG_WR(bp, BNX2_HC_COMMAND, BNX2_HC_COMMAND_CLR_STAT_NOW);
4625
Michael Chanda3e4fb2007-05-03 13:24:23 -07004626 REG_WR(bp, BNX2_HC_ATTN_BITS_ENABLE, STATUS_ATTN_EVENTS);
Michael Chanb6016b72005-05-26 13:03:09 -07004627
4628 /* Initialize the receive filter. */
4629 bnx2_set_rx_mode(bp->dev);
4630
Michael Chan0aa38df2007-06-04 21:23:06 -07004631 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
4632 val = REG_RD(bp, BNX2_MISC_NEW_CORE_CTL);
4633 val |= BNX2_MISC_NEW_CORE_CTL_DMA_ENABLE;
4634 REG_WR(bp, BNX2_MISC_NEW_CORE_CTL, val);
4635 }
Michael Chanb090ae22006-01-23 16:07:10 -08004636 rc = bnx2_fw_sync(bp, BNX2_DRV_MSG_DATA_WAIT2 | BNX2_DRV_MSG_CODE_RESET,
Michael Chana2f13892008-07-14 22:38:23 -07004637 1, 0);
Michael Chanb6016b72005-05-26 13:03:09 -07004638
Michael Chandf149d72007-07-07 22:51:36 -07004639 REG_WR(bp, BNX2_MISC_ENABLE_SET_BITS, BNX2_MISC_ENABLE_DEFAULT);
Michael Chanb6016b72005-05-26 13:03:09 -07004640 REG_RD(bp, BNX2_MISC_ENABLE_SET_BITS);
4641
4642 udelay(20);
4643
Michael Chanbf5295b2006-03-23 01:11:56 -08004644 bp->hc_cmd = REG_RD(bp, BNX2_HC_COMMAND);
4645
Michael Chanb090ae22006-01-23 16:07:10 -08004646 return rc;
Michael Chanb6016b72005-05-26 13:03:09 -07004647}
4648
Michael Chan59b47d82006-11-19 14:10:45 -08004649static void
Michael Chanc76c0472007-12-20 20:01:19 -08004650bnx2_clear_ring_states(struct bnx2 *bp)
4651{
4652 struct bnx2_napi *bnapi;
Michael Chan35e90102008-06-19 16:37:42 -07004653 struct bnx2_tx_ring_info *txr;
Michael Chanbb4f98a2008-06-19 16:38:19 -07004654 struct bnx2_rx_ring_info *rxr;
Michael Chanc76c0472007-12-20 20:01:19 -08004655 int i;
4656
4657 for (i = 0; i < BNX2_MAX_MSIX_VEC; i++) {
4658 bnapi = &bp->bnx2_napi[i];
Michael Chan35e90102008-06-19 16:37:42 -07004659 txr = &bnapi->tx_ring;
Michael Chanbb4f98a2008-06-19 16:38:19 -07004660 rxr = &bnapi->rx_ring;
Michael Chanc76c0472007-12-20 20:01:19 -08004661
Michael Chan35e90102008-06-19 16:37:42 -07004662 txr->tx_cons = 0;
4663 txr->hw_tx_cons = 0;
Michael Chanbb4f98a2008-06-19 16:38:19 -07004664 rxr->rx_prod_bseq = 0;
4665 rxr->rx_prod = 0;
4666 rxr->rx_cons = 0;
4667 rxr->rx_pg_prod = 0;
4668 rxr->rx_pg_cons = 0;
Michael Chanc76c0472007-12-20 20:01:19 -08004669 }
4670}
4671
4672static void
Michael Chan35e90102008-06-19 16:37:42 -07004673bnx2_init_tx_context(struct bnx2 *bp, u32 cid, struct bnx2_tx_ring_info *txr)
Michael Chan59b47d82006-11-19 14:10:45 -08004674{
4675 u32 val, offset0, offset1, offset2, offset3;
Michael Chan62a83132008-01-29 21:35:40 -08004676 u32 cid_addr = GET_CID_ADDR(cid);
Michael Chan59b47d82006-11-19 14:10:45 -08004677
4678 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
4679 offset0 = BNX2_L2CTX_TYPE_XI;
4680 offset1 = BNX2_L2CTX_CMD_TYPE_XI;
4681 offset2 = BNX2_L2CTX_TBDR_BHADDR_HI_XI;
4682 offset3 = BNX2_L2CTX_TBDR_BHADDR_LO_XI;
4683 } else {
4684 offset0 = BNX2_L2CTX_TYPE;
4685 offset1 = BNX2_L2CTX_CMD_TYPE;
4686 offset2 = BNX2_L2CTX_TBDR_BHADDR_HI;
4687 offset3 = BNX2_L2CTX_TBDR_BHADDR_LO;
4688 }
4689 val = BNX2_L2CTX_TYPE_TYPE_L2 | BNX2_L2CTX_TYPE_SIZE_L2;
Michael Chan62a83132008-01-29 21:35:40 -08004690 bnx2_ctx_wr(bp, cid_addr, offset0, val);
Michael Chan59b47d82006-11-19 14:10:45 -08004691
4692 val = BNX2_L2CTX_CMD_TYPE_TYPE_L2 | (8 << 16);
Michael Chan62a83132008-01-29 21:35:40 -08004693 bnx2_ctx_wr(bp, cid_addr, offset1, val);
Michael Chan59b47d82006-11-19 14:10:45 -08004694
Michael Chan35e90102008-06-19 16:37:42 -07004695 val = (u64) txr->tx_desc_mapping >> 32;
Michael Chan62a83132008-01-29 21:35:40 -08004696 bnx2_ctx_wr(bp, cid_addr, offset2, val);
Michael Chan59b47d82006-11-19 14:10:45 -08004697
Michael Chan35e90102008-06-19 16:37:42 -07004698 val = (u64) txr->tx_desc_mapping & 0xffffffff;
Michael Chan62a83132008-01-29 21:35:40 -08004699 bnx2_ctx_wr(bp, cid_addr, offset3, val);
Michael Chan59b47d82006-11-19 14:10:45 -08004700}
Michael Chanb6016b72005-05-26 13:03:09 -07004701
4702static void
Michael Chan35e90102008-06-19 16:37:42 -07004703bnx2_init_tx_ring(struct bnx2 *bp, int ring_num)
Michael Chanb6016b72005-05-26 13:03:09 -07004704{
4705 struct tx_bd *txbd;
Michael Chanc76c0472007-12-20 20:01:19 -08004706 u32 cid = TX_CID;
4707 struct bnx2_napi *bnapi;
Michael Chan35e90102008-06-19 16:37:42 -07004708 struct bnx2_tx_ring_info *txr;
Michael Chanc76c0472007-12-20 20:01:19 -08004709
Michael Chan35e90102008-06-19 16:37:42 -07004710 bnapi = &bp->bnx2_napi[ring_num];
4711 txr = &bnapi->tx_ring;
4712
4713 if (ring_num == 0)
4714 cid = TX_CID;
4715 else
4716 cid = TX_TSS_CID + ring_num - 1;
Michael Chanb6016b72005-05-26 13:03:09 -07004717
Michael Chan2f8af122006-08-15 01:39:10 -07004718 bp->tx_wake_thresh = bp->tx_ring_size / 2;
4719
Michael Chan35e90102008-06-19 16:37:42 -07004720 txbd = &txr->tx_desc_ring[MAX_TX_DESC_CNT];
Jeff Garzik6aa20a22006-09-13 13:24:59 -04004721
Michael Chan35e90102008-06-19 16:37:42 -07004722 txbd->tx_bd_haddr_hi = (u64) txr->tx_desc_mapping >> 32;
4723 txbd->tx_bd_haddr_lo = (u64) txr->tx_desc_mapping & 0xffffffff;
Michael Chanb6016b72005-05-26 13:03:09 -07004724
Michael Chan35e90102008-06-19 16:37:42 -07004725 txr->tx_prod = 0;
4726 txr->tx_prod_bseq = 0;
Jeff Garzik6aa20a22006-09-13 13:24:59 -04004727
Michael Chan35e90102008-06-19 16:37:42 -07004728 txr->tx_bidx_addr = MB_GET_CID_ADDR(cid) + BNX2_L2CTX_TX_HOST_BIDX;
4729 txr->tx_bseq_addr = MB_GET_CID_ADDR(cid) + BNX2_L2CTX_TX_HOST_BSEQ;
Michael Chanb6016b72005-05-26 13:03:09 -07004730
Michael Chan35e90102008-06-19 16:37:42 -07004731 bnx2_init_tx_context(bp, cid, txr);
Michael Chanb6016b72005-05-26 13:03:09 -07004732}
4733
4734static void
Michael Chan5d5d0012007-12-12 11:17:43 -08004735bnx2_init_rxbd_rings(struct rx_bd *rx_ring[], dma_addr_t dma[], u32 buf_size,
4736 int num_rings)
Michael Chanb6016b72005-05-26 13:03:09 -07004737{
Michael Chanb6016b72005-05-26 13:03:09 -07004738 int i;
Michael Chan5d5d0012007-12-12 11:17:43 -08004739 struct rx_bd *rxbd;
Michael Chanb6016b72005-05-26 13:03:09 -07004740
Michael Chan5d5d0012007-12-12 11:17:43 -08004741 for (i = 0; i < num_rings; i++) {
Michael Chan13daffa2006-03-20 17:49:20 -08004742 int j;
Michael Chanb6016b72005-05-26 13:03:09 -07004743
Michael Chan5d5d0012007-12-12 11:17:43 -08004744 rxbd = &rx_ring[i][0];
Michael Chan13daffa2006-03-20 17:49:20 -08004745 for (j = 0; j < MAX_RX_DESC_CNT; j++, rxbd++) {
Michael Chan5d5d0012007-12-12 11:17:43 -08004746 rxbd->rx_bd_len = buf_size;
Michael Chan13daffa2006-03-20 17:49:20 -08004747 rxbd->rx_bd_flags = RX_BD_FLAGS_START | RX_BD_FLAGS_END;
4748 }
Michael Chan5d5d0012007-12-12 11:17:43 -08004749 if (i == (num_rings - 1))
Michael Chan13daffa2006-03-20 17:49:20 -08004750 j = 0;
4751 else
4752 j = i + 1;
Michael Chan5d5d0012007-12-12 11:17:43 -08004753 rxbd->rx_bd_haddr_hi = (u64) dma[j] >> 32;
4754 rxbd->rx_bd_haddr_lo = (u64) dma[j] & 0xffffffff;
Michael Chan13daffa2006-03-20 17:49:20 -08004755 }
Michael Chan5d5d0012007-12-12 11:17:43 -08004756}
4757
4758static void
Michael Chanbb4f98a2008-06-19 16:38:19 -07004759bnx2_init_rx_ring(struct bnx2 *bp, int ring_num)
Michael Chan5d5d0012007-12-12 11:17:43 -08004760{
4761 int i;
4762 u16 prod, ring_prod;
Michael Chanbb4f98a2008-06-19 16:38:19 -07004763 u32 cid, rx_cid_addr, val;
4764 struct bnx2_napi *bnapi = &bp->bnx2_napi[ring_num];
4765 struct bnx2_rx_ring_info *rxr = &bnapi->rx_ring;
Michael Chan5d5d0012007-12-12 11:17:43 -08004766
Michael Chanbb4f98a2008-06-19 16:38:19 -07004767 if (ring_num == 0)
4768 cid = RX_CID;
4769 else
4770 cid = RX_RSS_CID + ring_num - 1;
4771
4772 rx_cid_addr = GET_CID_ADDR(cid);
4773
4774 bnx2_init_rxbd_rings(rxr->rx_desc_ring, rxr->rx_desc_mapping,
Michael Chan5d5d0012007-12-12 11:17:43 -08004775 bp->rx_buf_use_size, bp->rx_max_ring);
4776
Michael Chanbb4f98a2008-06-19 16:38:19 -07004777 bnx2_init_rx_context(bp, cid);
Michael Chan83e3fc82008-01-29 21:37:17 -08004778
4779 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
4780 val = REG_RD(bp, BNX2_MQ_MAP_L2_5);
4781 REG_WR(bp, BNX2_MQ_MAP_L2_5, val | BNX2_MQ_MAP_L2_5_ARM);
4782 }
4783
Michael Chan62a83132008-01-29 21:35:40 -08004784 bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_PG_BUF_SIZE, 0);
Michael Chan47bf4242007-12-12 11:19:12 -08004785 if (bp->rx_pg_ring_size) {
Michael Chanbb4f98a2008-06-19 16:38:19 -07004786 bnx2_init_rxbd_rings(rxr->rx_pg_desc_ring,
4787 rxr->rx_pg_desc_mapping,
Michael Chan47bf4242007-12-12 11:19:12 -08004788 PAGE_SIZE, bp->rx_max_pg_ring);
4789 val = (bp->rx_buf_use_size << 16) | PAGE_SIZE;
Michael Chan62a83132008-01-29 21:35:40 -08004790 bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_PG_BUF_SIZE, val);
4791 bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_RBDC_KEY,
Michael Chan5e9ad9e2008-06-19 16:43:17 -07004792 BNX2_L2CTX_RBDC_JUMBO_KEY - ring_num);
Michael Chan47bf4242007-12-12 11:19:12 -08004793
Michael Chanbb4f98a2008-06-19 16:38:19 -07004794 val = (u64) rxr->rx_pg_desc_mapping[0] >> 32;
Michael Chan62a83132008-01-29 21:35:40 -08004795 bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_NX_PG_BDHADDR_HI, val);
Michael Chan47bf4242007-12-12 11:19:12 -08004796
Michael Chanbb4f98a2008-06-19 16:38:19 -07004797 val = (u64) rxr->rx_pg_desc_mapping[0] & 0xffffffff;
Michael Chan62a83132008-01-29 21:35:40 -08004798 bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_NX_PG_BDHADDR_LO, val);
Michael Chan47bf4242007-12-12 11:19:12 -08004799
4800 if (CHIP_NUM(bp) == CHIP_NUM_5709)
4801 REG_WR(bp, BNX2_MQ_MAP_L2_3, BNX2_MQ_MAP_L2_3_DEFAULT);
4802 }
Michael Chanb6016b72005-05-26 13:03:09 -07004803
Michael Chanbb4f98a2008-06-19 16:38:19 -07004804 val = (u64) rxr->rx_desc_mapping[0] >> 32;
Michael Chan62a83132008-01-29 21:35:40 -08004805 bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_NX_BDHADDR_HI, val);
Michael Chanb6016b72005-05-26 13:03:09 -07004806
Michael Chanbb4f98a2008-06-19 16:38:19 -07004807 val = (u64) rxr->rx_desc_mapping[0] & 0xffffffff;
Michael Chan62a83132008-01-29 21:35:40 -08004808 bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_NX_BDHADDR_LO, val);
Michael Chanb6016b72005-05-26 13:03:09 -07004809
Michael Chanbb4f98a2008-06-19 16:38:19 -07004810 ring_prod = prod = rxr->rx_pg_prod;
Michael Chan47bf4242007-12-12 11:19:12 -08004811 for (i = 0; i < bp->rx_pg_ring_size; i++) {
Michael Chanbb4f98a2008-06-19 16:38:19 -07004812 if (bnx2_alloc_rx_page(bp, rxr, ring_prod) < 0)
Michael Chan47bf4242007-12-12 11:19:12 -08004813 break;
4814 prod = NEXT_RX_BD(prod);
4815 ring_prod = RX_PG_RING_IDX(prod);
4816 }
Michael Chanbb4f98a2008-06-19 16:38:19 -07004817 rxr->rx_pg_prod = prod;
Michael Chan47bf4242007-12-12 11:19:12 -08004818
Michael Chanbb4f98a2008-06-19 16:38:19 -07004819 ring_prod = prod = rxr->rx_prod;
Michael Chan236b6392006-03-20 17:49:02 -08004820 for (i = 0; i < bp->rx_ring_size; i++) {
Michael Chanbb4f98a2008-06-19 16:38:19 -07004821 if (bnx2_alloc_rx_skb(bp, rxr, ring_prod) < 0)
Michael Chanb6016b72005-05-26 13:03:09 -07004822 break;
Michael Chanb6016b72005-05-26 13:03:09 -07004823 prod = NEXT_RX_BD(prod);
4824 ring_prod = RX_RING_IDX(prod);
4825 }
Michael Chanbb4f98a2008-06-19 16:38:19 -07004826 rxr->rx_prod = prod;
Michael Chanb6016b72005-05-26 13:03:09 -07004827
Michael Chanbb4f98a2008-06-19 16:38:19 -07004828 rxr->rx_bidx_addr = MB_GET_CID_ADDR(cid) + BNX2_L2CTX_HOST_BDIDX;
4829 rxr->rx_bseq_addr = MB_GET_CID_ADDR(cid) + BNX2_L2CTX_HOST_BSEQ;
4830 rxr->rx_pg_bidx_addr = MB_GET_CID_ADDR(cid) + BNX2_L2CTX_HOST_PG_BDIDX;
Michael Chanb6016b72005-05-26 13:03:09 -07004831
Michael Chanbb4f98a2008-06-19 16:38:19 -07004832 REG_WR16(bp, rxr->rx_pg_bidx_addr, rxr->rx_pg_prod);
4833 REG_WR16(bp, rxr->rx_bidx_addr, prod);
4834
4835 REG_WR(bp, rxr->rx_bseq_addr, rxr->rx_prod_bseq);
Michael Chanb6016b72005-05-26 13:03:09 -07004836}
4837
Michael Chan35e90102008-06-19 16:37:42 -07004838static void
4839bnx2_init_all_rings(struct bnx2 *bp)
4840{
4841 int i;
Michael Chan5e9ad9e2008-06-19 16:43:17 -07004842 u32 val;
Michael Chan35e90102008-06-19 16:37:42 -07004843
4844 bnx2_clear_ring_states(bp);
4845
4846 REG_WR(bp, BNX2_TSCH_TSS_CFG, 0);
4847 for (i = 0; i < bp->num_tx_rings; i++)
4848 bnx2_init_tx_ring(bp, i);
4849
4850 if (bp->num_tx_rings > 1)
4851 REG_WR(bp, BNX2_TSCH_TSS_CFG, ((bp->num_tx_rings - 1) << 24) |
4852 (TX_TSS_CID << 7));
4853
Michael Chan5e9ad9e2008-06-19 16:43:17 -07004854 REG_WR(bp, BNX2_RLUP_RSS_CONFIG, 0);
4855 bnx2_reg_wr_ind(bp, BNX2_RXP_SCRATCH_RSS_TBL_SZ, 0);
4856
Michael Chanbb4f98a2008-06-19 16:38:19 -07004857 for (i = 0; i < bp->num_rx_rings; i++)
4858 bnx2_init_rx_ring(bp, i);
Michael Chan5e9ad9e2008-06-19 16:43:17 -07004859
4860 if (bp->num_rx_rings > 1) {
4861 u32 tbl_32;
4862 u8 *tbl = (u8 *) &tbl_32;
4863
4864 bnx2_reg_wr_ind(bp, BNX2_RXP_SCRATCH_RSS_TBL_SZ,
4865 BNX2_RXP_SCRATCH_RSS_TBL_MAX_ENTRIES);
4866
4867 for (i = 0; i < BNX2_RXP_SCRATCH_RSS_TBL_MAX_ENTRIES; i++) {
4868 tbl[i % 4] = i % (bp->num_rx_rings - 1);
4869 if ((i % 4) == 3)
4870 bnx2_reg_wr_ind(bp,
4871 BNX2_RXP_SCRATCH_RSS_TBL + i,
4872 cpu_to_be32(tbl_32));
4873 }
4874
4875 val = BNX2_RLUP_RSS_CONFIG_IPV4_RSS_TYPE_ALL_XI |
4876 BNX2_RLUP_RSS_CONFIG_IPV6_RSS_TYPE_ALL_XI;
4877
4878 REG_WR(bp, BNX2_RLUP_RSS_CONFIG, val);
4879
4880 }
Michael Chan35e90102008-06-19 16:37:42 -07004881}
4882
Michael Chan5d5d0012007-12-12 11:17:43 -08004883static u32 bnx2_find_max_ring(u32 ring_size, u32 max_size)
Michael Chan13daffa2006-03-20 17:49:20 -08004884{
Michael Chan5d5d0012007-12-12 11:17:43 -08004885 u32 max, num_rings = 1;
Michael Chan13daffa2006-03-20 17:49:20 -08004886
Michael Chan5d5d0012007-12-12 11:17:43 -08004887 while (ring_size > MAX_RX_DESC_CNT) {
4888 ring_size -= MAX_RX_DESC_CNT;
Michael Chan13daffa2006-03-20 17:49:20 -08004889 num_rings++;
4890 }
4891 /* round to next power of 2 */
Michael Chan5d5d0012007-12-12 11:17:43 -08004892 max = max_size;
Michael Chan13daffa2006-03-20 17:49:20 -08004893 while ((max & num_rings) == 0)
4894 max >>= 1;
4895
4896 if (num_rings != max)
4897 max <<= 1;
4898
Michael Chan5d5d0012007-12-12 11:17:43 -08004899 return max;
4900}
4901
4902static void
4903bnx2_set_rx_ring_size(struct bnx2 *bp, u32 size)
4904{
Michael Chan84eaa182007-12-12 11:19:57 -08004905 u32 rx_size, rx_space, jumbo_size;
Michael Chan5d5d0012007-12-12 11:17:43 -08004906
4907 /* 8 for CRC and VLAN */
Benjamin Lid89cb6a2008-05-16 22:18:57 -07004908 rx_size = bp->dev->mtu + ETH_HLEN + BNX2_RX_OFFSET + 8;
Michael Chan5d5d0012007-12-12 11:17:43 -08004909
Michael Chan84eaa182007-12-12 11:19:57 -08004910 rx_space = SKB_DATA_ALIGN(rx_size + BNX2_RX_ALIGN) + NET_SKB_PAD +
4911 sizeof(struct skb_shared_info);
4912
Benjamin Li601d3d12008-05-16 22:19:35 -07004913 bp->rx_copy_thresh = BNX2_RX_COPY_THRESH;
Michael Chan47bf4242007-12-12 11:19:12 -08004914 bp->rx_pg_ring_size = 0;
4915 bp->rx_max_pg_ring = 0;
4916 bp->rx_max_pg_ring_idx = 0;
David S. Millerf86e82f2008-01-21 17:15:40 -08004917 if ((rx_space > PAGE_SIZE) && !(bp->flags & BNX2_FLAG_JUMBO_BROKEN)) {
Michael Chan84eaa182007-12-12 11:19:57 -08004918 int pages = PAGE_ALIGN(bp->dev->mtu - 40) >> PAGE_SHIFT;
4919
4920 jumbo_size = size * pages;
4921 if (jumbo_size > MAX_TOTAL_RX_PG_DESC_CNT)
4922 jumbo_size = MAX_TOTAL_RX_PG_DESC_CNT;
4923
4924 bp->rx_pg_ring_size = jumbo_size;
4925 bp->rx_max_pg_ring = bnx2_find_max_ring(jumbo_size,
4926 MAX_RX_PG_RINGS);
4927 bp->rx_max_pg_ring_idx = (bp->rx_max_pg_ring * RX_DESC_CNT) - 1;
Benjamin Li601d3d12008-05-16 22:19:35 -07004928 rx_size = BNX2_RX_COPY_THRESH + BNX2_RX_OFFSET;
Michael Chan84eaa182007-12-12 11:19:57 -08004929 bp->rx_copy_thresh = 0;
4930 }
Michael Chan5d5d0012007-12-12 11:17:43 -08004931
4932 bp->rx_buf_use_size = rx_size;
4933 /* hw alignment */
4934 bp->rx_buf_size = bp->rx_buf_use_size + BNX2_RX_ALIGN;
Benjamin Lid89cb6a2008-05-16 22:18:57 -07004935 bp->rx_jumbo_thresh = rx_size - BNX2_RX_OFFSET;
Michael Chan5d5d0012007-12-12 11:17:43 -08004936 bp->rx_ring_size = size;
4937 bp->rx_max_ring = bnx2_find_max_ring(size, MAX_RX_RINGS);
Michael Chan13daffa2006-03-20 17:49:20 -08004938 bp->rx_max_ring_idx = (bp->rx_max_ring * RX_DESC_CNT) - 1;
4939}
4940
4941static void
Michael Chanb6016b72005-05-26 13:03:09 -07004942bnx2_free_tx_skbs(struct bnx2 *bp)
4943{
4944 int i;
4945
Michael Chan35e90102008-06-19 16:37:42 -07004946 for (i = 0; i < bp->num_tx_rings; i++) {
4947 struct bnx2_napi *bnapi = &bp->bnx2_napi[i];
4948 struct bnx2_tx_ring_info *txr = &bnapi->tx_ring;
4949 int j;
Michael Chanb6016b72005-05-26 13:03:09 -07004950
Michael Chan35e90102008-06-19 16:37:42 -07004951 if (txr->tx_buf_ring == NULL)
Michael Chanb6016b72005-05-26 13:03:09 -07004952 continue;
Michael Chanb6016b72005-05-26 13:03:09 -07004953
Michael Chan35e90102008-06-19 16:37:42 -07004954 for (j = 0; j < TX_DESC_CNT; ) {
4955 struct sw_bd *tx_buf = &txr->tx_buf_ring[j];
4956 struct sk_buff *skb = tx_buf->skb;
4957 int k, last;
4958
4959 if (skb == NULL) {
4960 j++;
4961 continue;
4962 }
4963
4964 pci_unmap_single(bp->pdev,
4965 pci_unmap_addr(tx_buf, mapping),
Michael Chanb6016b72005-05-26 13:03:09 -07004966 skb_headlen(skb), PCI_DMA_TODEVICE);
4967
Michael Chan35e90102008-06-19 16:37:42 -07004968 tx_buf->skb = NULL;
Michael Chanb6016b72005-05-26 13:03:09 -07004969
Michael Chan35e90102008-06-19 16:37:42 -07004970 last = skb_shinfo(skb)->nr_frags;
4971 for (k = 0; k < last; k++) {
4972 tx_buf = &txr->tx_buf_ring[j + k + 1];
4973 pci_unmap_page(bp->pdev,
4974 pci_unmap_addr(tx_buf, mapping),
4975 skb_shinfo(skb)->frags[j].size,
4976 PCI_DMA_TODEVICE);
4977 }
4978 dev_kfree_skb(skb);
4979 j += k + 1;
Michael Chanb6016b72005-05-26 13:03:09 -07004980 }
Michael Chanb6016b72005-05-26 13:03:09 -07004981 }
Michael Chanb6016b72005-05-26 13:03:09 -07004982}
4983
4984static void
4985bnx2_free_rx_skbs(struct bnx2 *bp)
4986{
4987 int i;
4988
Michael Chanbb4f98a2008-06-19 16:38:19 -07004989 for (i = 0; i < bp->num_rx_rings; i++) {
4990 struct bnx2_napi *bnapi = &bp->bnx2_napi[i];
4991 struct bnx2_rx_ring_info *rxr = &bnapi->rx_ring;
4992 int j;
Michael Chanb6016b72005-05-26 13:03:09 -07004993
Michael Chanbb4f98a2008-06-19 16:38:19 -07004994 if (rxr->rx_buf_ring == NULL)
4995 return;
Michael Chanb6016b72005-05-26 13:03:09 -07004996
Michael Chanbb4f98a2008-06-19 16:38:19 -07004997 for (j = 0; j < bp->rx_max_ring_idx; j++) {
4998 struct sw_bd *rx_buf = &rxr->rx_buf_ring[j];
4999 struct sk_buff *skb = rx_buf->skb;
Michael Chanb6016b72005-05-26 13:03:09 -07005000
Michael Chanbb4f98a2008-06-19 16:38:19 -07005001 if (skb == NULL)
5002 continue;
Michael Chanb6016b72005-05-26 13:03:09 -07005003
Michael Chanbb4f98a2008-06-19 16:38:19 -07005004 pci_unmap_single(bp->pdev,
5005 pci_unmap_addr(rx_buf, mapping),
5006 bp->rx_buf_use_size,
5007 PCI_DMA_FROMDEVICE);
Michael Chanb6016b72005-05-26 13:03:09 -07005008
Michael Chanbb4f98a2008-06-19 16:38:19 -07005009 rx_buf->skb = NULL;
5010
5011 dev_kfree_skb(skb);
5012 }
5013 for (j = 0; j < bp->rx_max_pg_ring_idx; j++)
5014 bnx2_free_rx_page(bp, rxr, j);
Michael Chanb6016b72005-05-26 13:03:09 -07005015 }
5016}
5017
5018static void
5019bnx2_free_skbs(struct bnx2 *bp)
5020{
5021 bnx2_free_tx_skbs(bp);
5022 bnx2_free_rx_skbs(bp);
5023}
5024
5025static int
5026bnx2_reset_nic(struct bnx2 *bp, u32 reset_code)
5027{
5028 int rc;
5029
5030 rc = bnx2_reset_chip(bp, reset_code);
5031 bnx2_free_skbs(bp);
5032 if (rc)
5033 return rc;
5034
Michael Chanfba9fe92006-06-12 22:21:25 -07005035 if ((rc = bnx2_init_chip(bp)) != 0)
5036 return rc;
5037
Michael Chan35e90102008-06-19 16:37:42 -07005038 bnx2_init_all_rings(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07005039 return 0;
5040}
5041
5042static int
Michael Chan9a120bc2008-05-16 22:17:45 -07005043bnx2_init_nic(struct bnx2 *bp, int reset_phy)
Michael Chanb6016b72005-05-26 13:03:09 -07005044{
5045 int rc;
5046
5047 if ((rc = bnx2_reset_nic(bp, BNX2_DRV_MSG_CODE_RESET)) != 0)
5048 return rc;
5049
Michael Chan80be4432006-11-19 14:07:28 -08005050 spin_lock_bh(&bp->phy_lock);
Michael Chan9a120bc2008-05-16 22:17:45 -07005051 bnx2_init_phy(bp, reset_phy);
Michael Chanb6016b72005-05-26 13:03:09 -07005052 bnx2_set_link(bp);
Michael Chan543a8272008-05-02 16:56:44 -07005053 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
5054 bnx2_remote_phy_event(bp);
Michael Chan0d8a6572007-07-07 22:49:43 -07005055 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07005056 return 0;
5057}
5058
5059static int
5060bnx2_test_registers(struct bnx2 *bp)
5061{
5062 int ret;
Michael Chan5bae30c2007-05-03 13:18:46 -07005063 int i, is_5709;
Arjan van de Venf71e1302006-03-03 21:33:57 -05005064 static const struct {
Michael Chanb6016b72005-05-26 13:03:09 -07005065 u16 offset;
5066 u16 flags;
Michael Chan5bae30c2007-05-03 13:18:46 -07005067#define BNX2_FL_NOT_5709 1
Michael Chanb6016b72005-05-26 13:03:09 -07005068 u32 rw_mask;
5069 u32 ro_mask;
5070 } reg_tbl[] = {
5071 { 0x006c, 0, 0x00000000, 0x0000003f },
5072 { 0x0090, 0, 0xffffffff, 0x00000000 },
5073 { 0x0094, 0, 0x00000000, 0x00000000 },
5074
Michael Chan5bae30c2007-05-03 13:18:46 -07005075 { 0x0404, BNX2_FL_NOT_5709, 0x00003f00, 0x00000000 },
5076 { 0x0418, BNX2_FL_NOT_5709, 0x00000000, 0xffffffff },
5077 { 0x041c, BNX2_FL_NOT_5709, 0x00000000, 0xffffffff },
5078 { 0x0420, BNX2_FL_NOT_5709, 0x00000000, 0x80ffffff },
5079 { 0x0424, BNX2_FL_NOT_5709, 0x00000000, 0x00000000 },
5080 { 0x0428, BNX2_FL_NOT_5709, 0x00000000, 0x00000001 },
5081 { 0x0450, BNX2_FL_NOT_5709, 0x00000000, 0x0000ffff },
5082 { 0x0454, BNX2_FL_NOT_5709, 0x00000000, 0xffffffff },
5083 { 0x0458, BNX2_FL_NOT_5709, 0x00000000, 0xffffffff },
Michael Chanb6016b72005-05-26 13:03:09 -07005084
Michael Chan5bae30c2007-05-03 13:18:46 -07005085 { 0x0808, BNX2_FL_NOT_5709, 0x00000000, 0xffffffff },
5086 { 0x0854, BNX2_FL_NOT_5709, 0x00000000, 0xffffffff },
5087 { 0x0868, BNX2_FL_NOT_5709, 0x00000000, 0x77777777 },
5088 { 0x086c, BNX2_FL_NOT_5709, 0x00000000, 0x77777777 },
5089 { 0x0870, BNX2_FL_NOT_5709, 0x00000000, 0x77777777 },
5090 { 0x0874, BNX2_FL_NOT_5709, 0x00000000, 0x77777777 },
Michael Chanb6016b72005-05-26 13:03:09 -07005091
Michael Chan5bae30c2007-05-03 13:18:46 -07005092 { 0x0c00, BNX2_FL_NOT_5709, 0x00000000, 0x00000001 },
5093 { 0x0c04, BNX2_FL_NOT_5709, 0x00000000, 0x03ff0001 },
5094 { 0x0c08, BNX2_FL_NOT_5709, 0x0f0ff073, 0x00000000 },
Michael Chanb6016b72005-05-26 13:03:09 -07005095
5096 { 0x1000, 0, 0x00000000, 0x00000001 },
Michael Chan15b169c2008-05-02 16:57:08 -07005097 { 0x1004, BNX2_FL_NOT_5709, 0x00000000, 0x000f0001 },
Michael Chanb6016b72005-05-26 13:03:09 -07005098
5099 { 0x1408, 0, 0x01c00800, 0x00000000 },
5100 { 0x149c, 0, 0x8000ffff, 0x00000000 },
5101 { 0x14a8, 0, 0x00000000, 0x000001ff },
Michael Chan5b0c76a2005-11-04 08:45:49 -08005102 { 0x14ac, 0, 0x0fffffff, 0x10000000 },
Michael Chanb6016b72005-05-26 13:03:09 -07005103 { 0x14b0, 0, 0x00000002, 0x00000001 },
5104 { 0x14b8, 0, 0x00000000, 0x00000000 },
5105 { 0x14c0, 0, 0x00000000, 0x00000009 },
5106 { 0x14c4, 0, 0x00003fff, 0x00000000 },
5107 { 0x14cc, 0, 0x00000000, 0x00000001 },
5108 { 0x14d0, 0, 0xffffffff, 0x00000000 },
Michael Chanb6016b72005-05-26 13:03:09 -07005109
5110 { 0x1800, 0, 0x00000000, 0x00000001 },
5111 { 0x1804, 0, 0x00000000, 0x00000003 },
Michael Chanb6016b72005-05-26 13:03:09 -07005112
5113 { 0x2800, 0, 0x00000000, 0x00000001 },
5114 { 0x2804, 0, 0x00000000, 0x00003f01 },
5115 { 0x2808, 0, 0x0f3f3f03, 0x00000000 },
5116 { 0x2810, 0, 0xffff0000, 0x00000000 },
5117 { 0x2814, 0, 0xffff0000, 0x00000000 },
5118 { 0x2818, 0, 0xffff0000, 0x00000000 },
5119 { 0x281c, 0, 0xffff0000, 0x00000000 },
5120 { 0x2834, 0, 0xffffffff, 0x00000000 },
5121 { 0x2840, 0, 0x00000000, 0xffffffff },
5122 { 0x2844, 0, 0x00000000, 0xffffffff },
5123 { 0x2848, 0, 0xffffffff, 0x00000000 },
5124 { 0x284c, 0, 0xf800f800, 0x07ff07ff },
5125
5126 { 0x2c00, 0, 0x00000000, 0x00000011 },
5127 { 0x2c04, 0, 0x00000000, 0x00030007 },
5128
Michael Chanb6016b72005-05-26 13:03:09 -07005129 { 0x3c00, 0, 0x00000000, 0x00000001 },
5130 { 0x3c04, 0, 0x00000000, 0x00070000 },
5131 { 0x3c08, 0, 0x00007f71, 0x07f00000 },
5132 { 0x3c0c, 0, 0x1f3ffffc, 0x00000000 },
5133 { 0x3c10, 0, 0xffffffff, 0x00000000 },
5134 { 0x3c14, 0, 0x00000000, 0xffffffff },
5135 { 0x3c18, 0, 0x00000000, 0xffffffff },
5136 { 0x3c1c, 0, 0xfffff000, 0x00000000 },
5137 { 0x3c20, 0, 0xffffff00, 0x00000000 },
Michael Chanb6016b72005-05-26 13:03:09 -07005138
5139 { 0x5004, 0, 0x00000000, 0x0000007f },
5140 { 0x5008, 0, 0x0f0007ff, 0x00000000 },
Michael Chanb6016b72005-05-26 13:03:09 -07005141
Michael Chanb6016b72005-05-26 13:03:09 -07005142 { 0x5c00, 0, 0x00000000, 0x00000001 },
5143 { 0x5c04, 0, 0x00000000, 0x0003000f },
5144 { 0x5c08, 0, 0x00000003, 0x00000000 },
5145 { 0x5c0c, 0, 0x0000fff8, 0x00000000 },
5146 { 0x5c10, 0, 0x00000000, 0xffffffff },
5147 { 0x5c80, 0, 0x00000000, 0x0f7113f1 },
5148 { 0x5c84, 0, 0x00000000, 0x0000f333 },
5149 { 0x5c88, 0, 0x00000000, 0x00077373 },
5150 { 0x5c8c, 0, 0x00000000, 0x0007f737 },
5151
5152 { 0x6808, 0, 0x0000ff7f, 0x00000000 },
5153 { 0x680c, 0, 0xffffffff, 0x00000000 },
5154 { 0x6810, 0, 0xffffffff, 0x00000000 },
5155 { 0x6814, 0, 0xffffffff, 0x00000000 },
5156 { 0x6818, 0, 0xffffffff, 0x00000000 },
5157 { 0x681c, 0, 0xffffffff, 0x00000000 },
5158 { 0x6820, 0, 0x00ff00ff, 0x00000000 },
5159 { 0x6824, 0, 0x00ff00ff, 0x00000000 },
5160 { 0x6828, 0, 0x00ff00ff, 0x00000000 },
5161 { 0x682c, 0, 0x03ff03ff, 0x00000000 },
5162 { 0x6830, 0, 0x03ff03ff, 0x00000000 },
5163 { 0x6834, 0, 0x03ff03ff, 0x00000000 },
5164 { 0x6838, 0, 0x03ff03ff, 0x00000000 },
5165 { 0x683c, 0, 0x0000ffff, 0x00000000 },
5166 { 0x6840, 0, 0x00000ff0, 0x00000000 },
5167 { 0x6844, 0, 0x00ffff00, 0x00000000 },
5168 { 0x684c, 0, 0xffffffff, 0x00000000 },
5169 { 0x6850, 0, 0x7f7f7f7f, 0x00000000 },
5170 { 0x6854, 0, 0x7f7f7f7f, 0x00000000 },
5171 { 0x6858, 0, 0x7f7f7f7f, 0x00000000 },
5172 { 0x685c, 0, 0x7f7f7f7f, 0x00000000 },
5173 { 0x6908, 0, 0x00000000, 0x0001ff0f },
5174 { 0x690c, 0, 0x00000000, 0x0ffe00f0 },
5175
5176 { 0xffff, 0, 0x00000000, 0x00000000 },
5177 };
5178
5179 ret = 0;
Michael Chan5bae30c2007-05-03 13:18:46 -07005180 is_5709 = 0;
5181 if (CHIP_NUM(bp) == CHIP_NUM_5709)
5182 is_5709 = 1;
5183
Michael Chanb6016b72005-05-26 13:03:09 -07005184 for (i = 0; reg_tbl[i].offset != 0xffff; i++) {
5185 u32 offset, rw_mask, ro_mask, save_val, val;
Michael Chan5bae30c2007-05-03 13:18:46 -07005186 u16 flags = reg_tbl[i].flags;
5187
5188 if (is_5709 && (flags & BNX2_FL_NOT_5709))
5189 continue;
Michael Chanb6016b72005-05-26 13:03:09 -07005190
5191 offset = (u32) reg_tbl[i].offset;
5192 rw_mask = reg_tbl[i].rw_mask;
5193 ro_mask = reg_tbl[i].ro_mask;
5194
Peter Hagervall14ab9b82005-08-10 14:18:16 -07005195 save_val = readl(bp->regview + offset);
Michael Chanb6016b72005-05-26 13:03:09 -07005196
Peter Hagervall14ab9b82005-08-10 14:18:16 -07005197 writel(0, bp->regview + offset);
Michael Chanb6016b72005-05-26 13:03:09 -07005198
Peter Hagervall14ab9b82005-08-10 14:18:16 -07005199 val = readl(bp->regview + offset);
Michael Chanb6016b72005-05-26 13:03:09 -07005200 if ((val & rw_mask) != 0) {
5201 goto reg_test_err;
5202 }
5203
5204 if ((val & ro_mask) != (save_val & ro_mask)) {
5205 goto reg_test_err;
5206 }
5207
Peter Hagervall14ab9b82005-08-10 14:18:16 -07005208 writel(0xffffffff, bp->regview + offset);
Michael Chanb6016b72005-05-26 13:03:09 -07005209
Peter Hagervall14ab9b82005-08-10 14:18:16 -07005210 val = readl(bp->regview + offset);
Michael Chanb6016b72005-05-26 13:03:09 -07005211 if ((val & rw_mask) != rw_mask) {
5212 goto reg_test_err;
5213 }
5214
5215 if ((val & ro_mask) != (save_val & ro_mask)) {
5216 goto reg_test_err;
5217 }
5218
Peter Hagervall14ab9b82005-08-10 14:18:16 -07005219 writel(save_val, bp->regview + offset);
Michael Chanb6016b72005-05-26 13:03:09 -07005220 continue;
5221
5222reg_test_err:
Peter Hagervall14ab9b82005-08-10 14:18:16 -07005223 writel(save_val, bp->regview + offset);
Michael Chanb6016b72005-05-26 13:03:09 -07005224 ret = -ENODEV;
5225 break;
5226 }
5227 return ret;
5228}
5229
5230static int
5231bnx2_do_mem_test(struct bnx2 *bp, u32 start, u32 size)
5232{
Arjan van de Venf71e1302006-03-03 21:33:57 -05005233 static const u32 test_pattern[] = { 0x00000000, 0xffffffff, 0x55555555,
Michael Chanb6016b72005-05-26 13:03:09 -07005234 0xaaaaaaaa , 0xaa55aa55, 0x55aa55aa };
5235 int i;
5236
5237 for (i = 0; i < sizeof(test_pattern) / 4; i++) {
5238 u32 offset;
5239
5240 for (offset = 0; offset < size; offset += 4) {
5241
Michael Chan2726d6e2008-01-29 21:35:05 -08005242 bnx2_reg_wr_ind(bp, start + offset, test_pattern[i]);
Michael Chanb6016b72005-05-26 13:03:09 -07005243
Michael Chan2726d6e2008-01-29 21:35:05 -08005244 if (bnx2_reg_rd_ind(bp, start + offset) !=
Michael Chanb6016b72005-05-26 13:03:09 -07005245 test_pattern[i]) {
5246 return -ENODEV;
5247 }
5248 }
5249 }
5250 return 0;
5251}
5252
5253static int
5254bnx2_test_memory(struct bnx2 *bp)
5255{
5256 int ret = 0;
5257 int i;
Michael Chan5bae30c2007-05-03 13:18:46 -07005258 static struct mem_entry {
Michael Chanb6016b72005-05-26 13:03:09 -07005259 u32 offset;
5260 u32 len;
Michael Chan5bae30c2007-05-03 13:18:46 -07005261 } mem_tbl_5706[] = {
Michael Chanb6016b72005-05-26 13:03:09 -07005262 { 0x60000, 0x4000 },
Michael Chan5b0c76a2005-11-04 08:45:49 -08005263 { 0xa0000, 0x3000 },
Michael Chanb6016b72005-05-26 13:03:09 -07005264 { 0xe0000, 0x4000 },
5265 { 0x120000, 0x4000 },
5266 { 0x1a0000, 0x4000 },
5267 { 0x160000, 0x4000 },
5268 { 0xffffffff, 0 },
Michael Chan5bae30c2007-05-03 13:18:46 -07005269 },
5270 mem_tbl_5709[] = {
5271 { 0x60000, 0x4000 },
5272 { 0xa0000, 0x3000 },
5273 { 0xe0000, 0x4000 },
5274 { 0x120000, 0x4000 },
5275 { 0x1a0000, 0x4000 },
5276 { 0xffffffff, 0 },
Michael Chanb6016b72005-05-26 13:03:09 -07005277 };
Michael Chan5bae30c2007-05-03 13:18:46 -07005278 struct mem_entry *mem_tbl;
5279
5280 if (CHIP_NUM(bp) == CHIP_NUM_5709)
5281 mem_tbl = mem_tbl_5709;
5282 else
5283 mem_tbl = mem_tbl_5706;
Michael Chanb6016b72005-05-26 13:03:09 -07005284
5285 for (i = 0; mem_tbl[i].offset != 0xffffffff; i++) {
5286 if ((ret = bnx2_do_mem_test(bp, mem_tbl[i].offset,
5287 mem_tbl[i].len)) != 0) {
5288 return ret;
5289 }
5290 }
Jeff Garzik6aa20a22006-09-13 13:24:59 -04005291
Michael Chanb6016b72005-05-26 13:03:09 -07005292 return ret;
5293}
5294
Michael Chanbc5a0692006-01-23 16:13:22 -08005295#define BNX2_MAC_LOOPBACK 0
5296#define BNX2_PHY_LOOPBACK 1
5297
Michael Chanb6016b72005-05-26 13:03:09 -07005298static int
Michael Chanbc5a0692006-01-23 16:13:22 -08005299bnx2_run_loopback(struct bnx2 *bp, int loopback_mode)
Michael Chanb6016b72005-05-26 13:03:09 -07005300{
5301 unsigned int pkt_size, num_pkts, i;
5302 struct sk_buff *skb, *rx_skb;
5303 unsigned char *packet;
Michael Chanbc5a0692006-01-23 16:13:22 -08005304 u16 rx_start_idx, rx_idx;
Michael Chanb6016b72005-05-26 13:03:09 -07005305 dma_addr_t map;
5306 struct tx_bd *txbd;
5307 struct sw_bd *rx_buf;
5308 struct l2_fhdr *rx_hdr;
5309 int ret = -ENODEV;
Michael Chanc76c0472007-12-20 20:01:19 -08005310 struct bnx2_napi *bnapi = &bp->bnx2_napi[0], *tx_napi;
Michael Chan35e90102008-06-19 16:37:42 -07005311 struct bnx2_tx_ring_info *txr = &bnapi->tx_ring;
Michael Chanbb4f98a2008-06-19 16:38:19 -07005312 struct bnx2_rx_ring_info *rxr = &bnapi->rx_ring;
Michael Chanc76c0472007-12-20 20:01:19 -08005313
5314 tx_napi = bnapi;
Michael Chanb6016b72005-05-26 13:03:09 -07005315
Michael Chan35e90102008-06-19 16:37:42 -07005316 txr = &tx_napi->tx_ring;
Michael Chanbb4f98a2008-06-19 16:38:19 -07005317 rxr = &bnapi->rx_ring;
Michael Chanbc5a0692006-01-23 16:13:22 -08005318 if (loopback_mode == BNX2_MAC_LOOPBACK) {
5319 bp->loopback = MAC_LOOPBACK;
5320 bnx2_set_mac_loopback(bp);
5321 }
5322 else if (loopback_mode == BNX2_PHY_LOOPBACK) {
Michael Chan583c28e2008-01-21 19:51:35 -08005323 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
Michael Chan489310a2007-10-10 16:16:31 -07005324 return 0;
5325
Michael Chan80be4432006-11-19 14:07:28 -08005326 bp->loopback = PHY_LOOPBACK;
Michael Chanbc5a0692006-01-23 16:13:22 -08005327 bnx2_set_phy_loopback(bp);
5328 }
5329 else
5330 return -EINVAL;
Michael Chanb6016b72005-05-26 13:03:09 -07005331
Michael Chan84eaa182007-12-12 11:19:57 -08005332 pkt_size = min(bp->dev->mtu + ETH_HLEN, bp->rx_jumbo_thresh - 4);
Michael Chan932f3772006-08-15 01:39:36 -07005333 skb = netdev_alloc_skb(bp->dev, pkt_size);
John W. Linvilleb6cbc3b62005-11-10 12:58:00 -08005334 if (!skb)
5335 return -ENOMEM;
Michael Chanb6016b72005-05-26 13:03:09 -07005336 packet = skb_put(skb, pkt_size);
Michael Chan66342922006-12-14 15:57:04 -08005337 memcpy(packet, bp->dev->dev_addr, 6);
Michael Chanb6016b72005-05-26 13:03:09 -07005338 memset(packet + 6, 0x0, 8);
5339 for (i = 14; i < pkt_size; i++)
5340 packet[i] = (unsigned char) (i & 0xff);
5341
5342 map = pci_map_single(bp->pdev, skb->data, pkt_size,
5343 PCI_DMA_TODEVICE);
5344
Michael Chanbf5295b2006-03-23 01:11:56 -08005345 REG_WR(bp, BNX2_HC_COMMAND,
5346 bp->hc_cmd | BNX2_HC_COMMAND_COAL_NOW_WO_INT);
5347
Michael Chanb6016b72005-05-26 13:03:09 -07005348 REG_RD(bp, BNX2_HC_COMMAND);
5349
5350 udelay(5);
Michael Chan35efa7c2007-12-20 19:56:37 -08005351 rx_start_idx = bnx2_get_hw_rx_cons(bnapi);
Michael Chanb6016b72005-05-26 13:03:09 -07005352
Michael Chanb6016b72005-05-26 13:03:09 -07005353 num_pkts = 0;
5354
Michael Chan35e90102008-06-19 16:37:42 -07005355 txbd = &txr->tx_desc_ring[TX_RING_IDX(txr->tx_prod)];
Michael Chanb6016b72005-05-26 13:03:09 -07005356
5357 txbd->tx_bd_haddr_hi = (u64) map >> 32;
5358 txbd->tx_bd_haddr_lo = (u64) map & 0xffffffff;
5359 txbd->tx_bd_mss_nbytes = pkt_size;
5360 txbd->tx_bd_vlan_tag_flags = TX_BD_FLAGS_START | TX_BD_FLAGS_END;
5361
5362 num_pkts++;
Michael Chan35e90102008-06-19 16:37:42 -07005363 txr->tx_prod = NEXT_TX_BD(txr->tx_prod);
5364 txr->tx_prod_bseq += pkt_size;
Michael Chanb6016b72005-05-26 13:03:09 -07005365
Michael Chan35e90102008-06-19 16:37:42 -07005366 REG_WR16(bp, txr->tx_bidx_addr, txr->tx_prod);
5367 REG_WR(bp, txr->tx_bseq_addr, txr->tx_prod_bseq);
Michael Chanb6016b72005-05-26 13:03:09 -07005368
5369 udelay(100);
5370
Michael Chanbf5295b2006-03-23 01:11:56 -08005371 REG_WR(bp, BNX2_HC_COMMAND,
5372 bp->hc_cmd | BNX2_HC_COMMAND_COAL_NOW_WO_INT);
5373
Michael Chanb6016b72005-05-26 13:03:09 -07005374 REG_RD(bp, BNX2_HC_COMMAND);
5375
5376 udelay(5);
5377
5378 pci_unmap_single(bp->pdev, map, pkt_size, PCI_DMA_TODEVICE);
Michael Chan745720e2006-06-29 12:37:41 -07005379 dev_kfree_skb(skb);
Michael Chanb6016b72005-05-26 13:03:09 -07005380
Michael Chan35e90102008-06-19 16:37:42 -07005381 if (bnx2_get_hw_tx_cons(tx_napi) != txr->tx_prod)
Michael Chanb6016b72005-05-26 13:03:09 -07005382 goto loopback_test_done;
Michael Chanb6016b72005-05-26 13:03:09 -07005383
Michael Chan35efa7c2007-12-20 19:56:37 -08005384 rx_idx = bnx2_get_hw_rx_cons(bnapi);
Michael Chanb6016b72005-05-26 13:03:09 -07005385 if (rx_idx != rx_start_idx + num_pkts) {
5386 goto loopback_test_done;
5387 }
5388
Michael Chanbb4f98a2008-06-19 16:38:19 -07005389 rx_buf = &rxr->rx_buf_ring[rx_start_idx];
Michael Chanb6016b72005-05-26 13:03:09 -07005390 rx_skb = rx_buf->skb;
5391
5392 rx_hdr = (struct l2_fhdr *) rx_skb->data;
Benjamin Lid89cb6a2008-05-16 22:18:57 -07005393 skb_reserve(rx_skb, BNX2_RX_OFFSET);
Michael Chanb6016b72005-05-26 13:03:09 -07005394
5395 pci_dma_sync_single_for_cpu(bp->pdev,
5396 pci_unmap_addr(rx_buf, mapping),
5397 bp->rx_buf_size, PCI_DMA_FROMDEVICE);
5398
Michael Chanade2bfe2006-01-23 16:09:51 -08005399 if (rx_hdr->l2_fhdr_status &
Michael Chanb6016b72005-05-26 13:03:09 -07005400 (L2_FHDR_ERRORS_BAD_CRC |
5401 L2_FHDR_ERRORS_PHY_DECODE |
5402 L2_FHDR_ERRORS_ALIGNMENT |
5403 L2_FHDR_ERRORS_TOO_SHORT |
5404 L2_FHDR_ERRORS_GIANT_FRAME)) {
5405
5406 goto loopback_test_done;
5407 }
5408
5409 if ((rx_hdr->l2_fhdr_pkt_len - 4) != pkt_size) {
5410 goto loopback_test_done;
5411 }
5412
5413 for (i = 14; i < pkt_size; i++) {
5414 if (*(rx_skb->data + i) != (unsigned char) (i & 0xff)) {
5415 goto loopback_test_done;
5416 }
5417 }
5418
5419 ret = 0;
5420
5421loopback_test_done:
5422 bp->loopback = 0;
5423 return ret;
5424}
5425
Michael Chanbc5a0692006-01-23 16:13:22 -08005426#define BNX2_MAC_LOOPBACK_FAILED 1
5427#define BNX2_PHY_LOOPBACK_FAILED 2
5428#define BNX2_LOOPBACK_FAILED (BNX2_MAC_LOOPBACK_FAILED | \
5429 BNX2_PHY_LOOPBACK_FAILED)
5430
5431static int
5432bnx2_test_loopback(struct bnx2 *bp)
5433{
5434 int rc = 0;
5435
5436 if (!netif_running(bp->dev))
5437 return BNX2_LOOPBACK_FAILED;
5438
5439 bnx2_reset_nic(bp, BNX2_DRV_MSG_CODE_RESET);
5440 spin_lock_bh(&bp->phy_lock);
Michael Chan9a120bc2008-05-16 22:17:45 -07005441 bnx2_init_phy(bp, 1);
Michael Chanbc5a0692006-01-23 16:13:22 -08005442 spin_unlock_bh(&bp->phy_lock);
5443 if (bnx2_run_loopback(bp, BNX2_MAC_LOOPBACK))
5444 rc |= BNX2_MAC_LOOPBACK_FAILED;
5445 if (bnx2_run_loopback(bp, BNX2_PHY_LOOPBACK))
5446 rc |= BNX2_PHY_LOOPBACK_FAILED;
5447 return rc;
5448}
5449
Michael Chanb6016b72005-05-26 13:03:09 -07005450#define NVRAM_SIZE 0x200
5451#define CRC32_RESIDUAL 0xdebb20e3
5452
5453static int
5454bnx2_test_nvram(struct bnx2 *bp)
5455{
Al Virob491edd2007-12-22 19:44:51 +00005456 __be32 buf[NVRAM_SIZE / 4];
Michael Chanb6016b72005-05-26 13:03:09 -07005457 u8 *data = (u8 *) buf;
5458 int rc = 0;
5459 u32 magic, csum;
5460
5461 if ((rc = bnx2_nvram_read(bp, 0, data, 4)) != 0)
5462 goto test_nvram_done;
5463
5464 magic = be32_to_cpu(buf[0]);
5465 if (magic != 0x669955aa) {
5466 rc = -ENODEV;
5467 goto test_nvram_done;
5468 }
5469
5470 if ((rc = bnx2_nvram_read(bp, 0x100, data, NVRAM_SIZE)) != 0)
5471 goto test_nvram_done;
5472
5473 csum = ether_crc_le(0x100, data);
5474 if (csum != CRC32_RESIDUAL) {
5475 rc = -ENODEV;
5476 goto test_nvram_done;
5477 }
5478
5479 csum = ether_crc_le(0x100, data + 0x100);
5480 if (csum != CRC32_RESIDUAL) {
5481 rc = -ENODEV;
5482 }
5483
5484test_nvram_done:
5485 return rc;
5486}
5487
5488static int
5489bnx2_test_link(struct bnx2 *bp)
5490{
5491 u32 bmsr;
5492
Michael Chan583c28e2008-01-21 19:51:35 -08005493 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP) {
Michael Chan489310a2007-10-10 16:16:31 -07005494 if (bp->link_up)
5495 return 0;
5496 return -ENODEV;
5497 }
Michael Chanc770a652005-08-25 15:38:39 -07005498 spin_lock_bh(&bp->phy_lock);
Michael Chan27a005b2007-05-03 13:23:41 -07005499 bnx2_enable_bmsr1(bp);
5500 bnx2_read_phy(bp, bp->mii_bmsr1, &bmsr);
5501 bnx2_read_phy(bp, bp->mii_bmsr1, &bmsr);
5502 bnx2_disable_bmsr1(bp);
Michael Chanc770a652005-08-25 15:38:39 -07005503 spin_unlock_bh(&bp->phy_lock);
Jeff Garzik6aa20a22006-09-13 13:24:59 -04005504
Michael Chanb6016b72005-05-26 13:03:09 -07005505 if (bmsr & BMSR_LSTATUS) {
5506 return 0;
5507 }
5508 return -ENODEV;
5509}
5510
5511static int
5512bnx2_test_intr(struct bnx2 *bp)
5513{
5514 int i;
Michael Chanb6016b72005-05-26 13:03:09 -07005515 u16 status_idx;
5516
5517 if (!netif_running(bp->dev))
5518 return -ENODEV;
5519
5520 status_idx = REG_RD(bp, BNX2_PCICFG_INT_ACK_CMD) & 0xffff;
5521
5522 /* This register is not touched during run-time. */
Michael Chanbf5295b2006-03-23 01:11:56 -08005523 REG_WR(bp, BNX2_HC_COMMAND, bp->hc_cmd | BNX2_HC_COMMAND_COAL_NOW);
Michael Chanb6016b72005-05-26 13:03:09 -07005524 REG_RD(bp, BNX2_HC_COMMAND);
5525
5526 for (i = 0; i < 10; i++) {
5527 if ((REG_RD(bp, BNX2_PCICFG_INT_ACK_CMD) & 0xffff) !=
5528 status_idx) {
5529
5530 break;
5531 }
5532
5533 msleep_interruptible(10);
5534 }
5535 if (i < 10)
5536 return 0;
5537
5538 return -ENODEV;
5539}
5540
Michael Chan38ea3682008-02-23 19:48:57 -08005541/* Determining link for parallel detection. */
Michael Chanb2fadea2008-01-21 17:07:06 -08005542static int
5543bnx2_5706_serdes_has_link(struct bnx2 *bp)
5544{
5545 u32 mode_ctl, an_dbg, exp;
5546
Michael Chan38ea3682008-02-23 19:48:57 -08005547 if (bp->phy_flags & BNX2_PHY_FLAG_NO_PARALLEL)
5548 return 0;
5549
Michael Chanb2fadea2008-01-21 17:07:06 -08005550 bnx2_write_phy(bp, MII_BNX2_MISC_SHADOW, MISC_SHDW_MODE_CTL);
5551 bnx2_read_phy(bp, MII_BNX2_MISC_SHADOW, &mode_ctl);
5552
5553 if (!(mode_ctl & MISC_SHDW_MODE_CTL_SIG_DET))
5554 return 0;
5555
5556 bnx2_write_phy(bp, MII_BNX2_MISC_SHADOW, MISC_SHDW_AN_DBG);
5557 bnx2_read_phy(bp, MII_BNX2_MISC_SHADOW, &an_dbg);
5558 bnx2_read_phy(bp, MII_BNX2_MISC_SHADOW, &an_dbg);
5559
Michael Chanf3014c02008-01-29 21:33:03 -08005560 if (an_dbg & (MISC_SHDW_AN_DBG_NOSYNC | MISC_SHDW_AN_DBG_RUDI_INVALID))
Michael Chanb2fadea2008-01-21 17:07:06 -08005561 return 0;
5562
5563 bnx2_write_phy(bp, MII_BNX2_DSP_ADDRESS, MII_EXPAND_REG1);
5564 bnx2_read_phy(bp, MII_BNX2_DSP_RW_PORT, &exp);
5565 bnx2_read_phy(bp, MII_BNX2_DSP_RW_PORT, &exp);
5566
5567 if (exp & MII_EXPAND_REG1_RUDI_C) /* receiving CONFIG */
5568 return 0;
5569
5570 return 1;
5571}
5572
Michael Chanb6016b72005-05-26 13:03:09 -07005573static void
Michael Chan48b01e22006-11-19 14:08:00 -08005574bnx2_5706_serdes_timer(struct bnx2 *bp)
5575{
Michael Chanb2fadea2008-01-21 17:07:06 -08005576 int check_link = 1;
5577
Michael Chan48b01e22006-11-19 14:08:00 -08005578 spin_lock(&bp->phy_lock);
Michael Chanb2fadea2008-01-21 17:07:06 -08005579 if (bp->serdes_an_pending) {
Michael Chan48b01e22006-11-19 14:08:00 -08005580 bp->serdes_an_pending--;
Michael Chanb2fadea2008-01-21 17:07:06 -08005581 check_link = 0;
5582 } else if ((bp->link_up == 0) && (bp->autoneg & AUTONEG_SPEED)) {
Michael Chan48b01e22006-11-19 14:08:00 -08005583 u32 bmcr;
5584
5585 bp->current_interval = bp->timer_interval;
5586
Michael Chanca58c3a2007-05-03 13:22:52 -07005587 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chan48b01e22006-11-19 14:08:00 -08005588
5589 if (bmcr & BMCR_ANENABLE) {
Michael Chanb2fadea2008-01-21 17:07:06 -08005590 if (bnx2_5706_serdes_has_link(bp)) {
Michael Chan48b01e22006-11-19 14:08:00 -08005591 bmcr &= ~BMCR_ANENABLE;
5592 bmcr |= BMCR_SPEED1000 | BMCR_FULLDPLX;
Michael Chanca58c3a2007-05-03 13:22:52 -07005593 bnx2_write_phy(bp, bp->mii_bmcr, bmcr);
Michael Chan583c28e2008-01-21 19:51:35 -08005594 bp->phy_flags |= BNX2_PHY_FLAG_PARALLEL_DETECT;
Michael Chan48b01e22006-11-19 14:08:00 -08005595 }
5596 }
5597 }
5598 else if ((bp->link_up) && (bp->autoneg & AUTONEG_SPEED) &&
Michael Chan583c28e2008-01-21 19:51:35 -08005599 (bp->phy_flags & BNX2_PHY_FLAG_PARALLEL_DETECT)) {
Michael Chan48b01e22006-11-19 14:08:00 -08005600 u32 phy2;
5601
5602 bnx2_write_phy(bp, 0x17, 0x0f01);
5603 bnx2_read_phy(bp, 0x15, &phy2);
5604 if (phy2 & 0x20) {
5605 u32 bmcr;
5606
Michael Chanca58c3a2007-05-03 13:22:52 -07005607 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chan48b01e22006-11-19 14:08:00 -08005608 bmcr |= BMCR_ANENABLE;
Michael Chanca58c3a2007-05-03 13:22:52 -07005609 bnx2_write_phy(bp, bp->mii_bmcr, bmcr);
Michael Chan48b01e22006-11-19 14:08:00 -08005610
Michael Chan583c28e2008-01-21 19:51:35 -08005611 bp->phy_flags &= ~BNX2_PHY_FLAG_PARALLEL_DETECT;
Michael Chan48b01e22006-11-19 14:08:00 -08005612 }
5613 } else
5614 bp->current_interval = bp->timer_interval;
5615
Michael Chana2724e22008-02-23 19:47:44 -08005616 if (check_link) {
Michael Chanb2fadea2008-01-21 17:07:06 -08005617 u32 val;
5618
5619 bnx2_write_phy(bp, MII_BNX2_MISC_SHADOW, MISC_SHDW_AN_DBG);
5620 bnx2_read_phy(bp, MII_BNX2_MISC_SHADOW, &val);
5621 bnx2_read_phy(bp, MII_BNX2_MISC_SHADOW, &val);
5622
Michael Chana2724e22008-02-23 19:47:44 -08005623 if (bp->link_up && (val & MISC_SHDW_AN_DBG_NOSYNC)) {
5624 if (!(bp->phy_flags & BNX2_PHY_FLAG_FORCED_DOWN)) {
5625 bnx2_5706s_force_link_dn(bp, 1);
5626 bp->phy_flags |= BNX2_PHY_FLAG_FORCED_DOWN;
5627 } else
5628 bnx2_set_link(bp);
5629 } else if (!bp->link_up && !(val & MISC_SHDW_AN_DBG_NOSYNC))
5630 bnx2_set_link(bp);
Michael Chanb2fadea2008-01-21 17:07:06 -08005631 }
Michael Chan48b01e22006-11-19 14:08:00 -08005632 spin_unlock(&bp->phy_lock);
5633}
5634
5635static void
Michael Chanf8dd0642006-11-19 14:08:29 -08005636bnx2_5708_serdes_timer(struct bnx2 *bp)
5637{
Michael Chan583c28e2008-01-21 19:51:35 -08005638 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
Michael Chan0d8a6572007-07-07 22:49:43 -07005639 return;
5640
Michael Chan583c28e2008-01-21 19:51:35 -08005641 if ((bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE) == 0) {
Michael Chanf8dd0642006-11-19 14:08:29 -08005642 bp->serdes_an_pending = 0;
5643 return;
5644 }
5645
5646 spin_lock(&bp->phy_lock);
5647 if (bp->serdes_an_pending)
5648 bp->serdes_an_pending--;
5649 else if ((bp->link_up == 0) && (bp->autoneg & AUTONEG_SPEED)) {
5650 u32 bmcr;
5651
Michael Chanca58c3a2007-05-03 13:22:52 -07005652 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chanf8dd0642006-11-19 14:08:29 -08005653 if (bmcr & BMCR_ANENABLE) {
Michael Chan605a9e22007-05-03 13:23:13 -07005654 bnx2_enable_forced_2g5(bp);
Michael Chanf8dd0642006-11-19 14:08:29 -08005655 bp->current_interval = SERDES_FORCED_TIMEOUT;
5656 } else {
Michael Chan605a9e22007-05-03 13:23:13 -07005657 bnx2_disable_forced_2g5(bp);
Michael Chanf8dd0642006-11-19 14:08:29 -08005658 bp->serdes_an_pending = 2;
5659 bp->current_interval = bp->timer_interval;
5660 }
5661
5662 } else
5663 bp->current_interval = bp->timer_interval;
5664
5665 spin_unlock(&bp->phy_lock);
5666}
5667
5668static void
Michael Chanb6016b72005-05-26 13:03:09 -07005669bnx2_timer(unsigned long data)
5670{
5671 struct bnx2 *bp = (struct bnx2 *) data;
Michael Chanb6016b72005-05-26 13:03:09 -07005672
Michael Chancd339a02005-08-25 15:35:24 -07005673 if (!netif_running(bp->dev))
5674 return;
5675
Michael Chanb6016b72005-05-26 13:03:09 -07005676 if (atomic_read(&bp->intr_sem) != 0)
5677 goto bnx2_restart_timer;
5678
Michael Chandf149d72007-07-07 22:51:36 -07005679 bnx2_send_heart_beat(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07005680
Michael Chan2726d6e2008-01-29 21:35:05 -08005681 bp->stats_blk->stat_FwRxDrop =
5682 bnx2_reg_rd_ind(bp, BNX2_FW_RX_DROP_COUNT);
Michael Chancea94db2006-06-12 22:16:13 -07005683
Michael Chan02537b062007-06-04 21:24:07 -07005684 /* workaround occasional corrupted counters */
5685 if (CHIP_NUM(bp) == CHIP_NUM_5708 && bp->stats_ticks)
5686 REG_WR(bp, BNX2_HC_COMMAND, bp->hc_cmd |
5687 BNX2_HC_COMMAND_STATS_NOW);
5688
Michael Chan583c28e2008-01-21 19:51:35 -08005689 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Michael Chanf8dd0642006-11-19 14:08:29 -08005690 if (CHIP_NUM(bp) == CHIP_NUM_5706)
5691 bnx2_5706_serdes_timer(bp);
Michael Chan27a005b2007-05-03 13:23:41 -07005692 else
Michael Chanf8dd0642006-11-19 14:08:29 -08005693 bnx2_5708_serdes_timer(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07005694 }
5695
5696bnx2_restart_timer:
Michael Chancd339a02005-08-25 15:35:24 -07005697 mod_timer(&bp->timer, jiffies + bp->current_interval);
Michael Chanb6016b72005-05-26 13:03:09 -07005698}
5699
Michael Chan8e6a72c2007-05-03 13:24:48 -07005700static int
5701bnx2_request_irq(struct bnx2 *bp)
5702{
Michael Chan6d866ff2007-12-20 19:56:09 -08005703 unsigned long flags;
Michael Chanb4b36042007-12-20 19:59:30 -08005704 struct bnx2_irq *irq;
5705 int rc = 0, i;
Michael Chan8e6a72c2007-05-03 13:24:48 -07005706
David S. Millerf86e82f2008-01-21 17:15:40 -08005707 if (bp->flags & BNX2_FLAG_USING_MSI_OR_MSIX)
Michael Chan6d866ff2007-12-20 19:56:09 -08005708 flags = 0;
5709 else
5710 flags = IRQF_SHARED;
Michael Chanb4b36042007-12-20 19:59:30 -08005711
5712 for (i = 0; i < bp->irq_nvecs; i++) {
5713 irq = &bp->irq_tbl[i];
Michael Chanc76c0472007-12-20 20:01:19 -08005714 rc = request_irq(irq->vector, irq->handler, flags, irq->name,
Michael Chanf0ea2e62008-06-19 16:41:57 -07005715 &bp->bnx2_napi[i]);
Michael Chanb4b36042007-12-20 19:59:30 -08005716 if (rc)
5717 break;
5718 irq->requested = 1;
5719 }
Michael Chan8e6a72c2007-05-03 13:24:48 -07005720 return rc;
5721}
5722
5723static void
5724bnx2_free_irq(struct bnx2 *bp)
5725{
Michael Chanb4b36042007-12-20 19:59:30 -08005726 struct bnx2_irq *irq;
5727 int i;
Michael Chan8e6a72c2007-05-03 13:24:48 -07005728
Michael Chanb4b36042007-12-20 19:59:30 -08005729 for (i = 0; i < bp->irq_nvecs; i++) {
5730 irq = &bp->irq_tbl[i];
5731 if (irq->requested)
Michael Chanf0ea2e62008-06-19 16:41:57 -07005732 free_irq(irq->vector, &bp->bnx2_napi[i]);
Michael Chanb4b36042007-12-20 19:59:30 -08005733 irq->requested = 0;
Michael Chan6d866ff2007-12-20 19:56:09 -08005734 }
David S. Millerf86e82f2008-01-21 17:15:40 -08005735 if (bp->flags & BNX2_FLAG_USING_MSI)
Michael Chanb4b36042007-12-20 19:59:30 -08005736 pci_disable_msi(bp->pdev);
David S. Millerf86e82f2008-01-21 17:15:40 -08005737 else if (bp->flags & BNX2_FLAG_USING_MSIX)
Michael Chanb4b36042007-12-20 19:59:30 -08005738 pci_disable_msix(bp->pdev);
5739
David S. Millerf86e82f2008-01-21 17:15:40 -08005740 bp->flags &= ~(BNX2_FLAG_USING_MSI_OR_MSIX | BNX2_FLAG_ONE_SHOT_MSI);
Michael Chanb4b36042007-12-20 19:59:30 -08005741}
5742
5743static void
Michael Chan5e9ad9e2008-06-19 16:43:17 -07005744bnx2_enable_msix(struct bnx2 *bp, int msix_vecs)
Michael Chanb4b36042007-12-20 19:59:30 -08005745{
Michael Chan57851d82007-12-20 20:01:44 -08005746 int i, rc;
5747 struct msix_entry msix_ent[BNX2_MAX_MSIX_VEC];
5748
Michael Chanb4b36042007-12-20 19:59:30 -08005749 bnx2_setup_msix_tbl(bp);
5750 REG_WR(bp, BNX2_PCI_MSIX_CONTROL, BNX2_MAX_MSIX_HW_VEC - 1);
5751 REG_WR(bp, BNX2_PCI_MSIX_TBL_OFF_BIR, BNX2_PCI_GRC_WINDOW2_BASE);
5752 REG_WR(bp, BNX2_PCI_MSIX_PBA_OFF_BIT, BNX2_PCI_GRC_WINDOW3_BASE);
Michael Chan57851d82007-12-20 20:01:44 -08005753
5754 for (i = 0; i < BNX2_MAX_MSIX_VEC; i++) {
5755 msix_ent[i].entry = i;
5756 msix_ent[i].vector = 0;
Michael Chan35e90102008-06-19 16:37:42 -07005757
5758 strcpy(bp->irq_tbl[i].name, bp->dev->name);
Michael Chanf0ea2e62008-06-19 16:41:57 -07005759 bp->irq_tbl[i].handler = bnx2_msi_1shot;
Michael Chan57851d82007-12-20 20:01:44 -08005760 }
5761
5762 rc = pci_enable_msix(bp->pdev, msix_ent, BNX2_MAX_MSIX_VEC);
5763 if (rc != 0)
5764 return;
5765
Michael Chan5e9ad9e2008-06-19 16:43:17 -07005766 bp->irq_nvecs = msix_vecs;
David S. Millerf86e82f2008-01-21 17:15:40 -08005767 bp->flags |= BNX2_FLAG_USING_MSIX | BNX2_FLAG_ONE_SHOT_MSI;
Michael Chan57851d82007-12-20 20:01:44 -08005768 for (i = 0; i < BNX2_MAX_MSIX_VEC; i++)
5769 bp->irq_tbl[i].vector = msix_ent[i].vector;
Michael Chan6d866ff2007-12-20 19:56:09 -08005770}
5771
5772static void
5773bnx2_setup_int_mode(struct bnx2 *bp, int dis_msi)
5774{
Michael Chan5e9ad9e2008-06-19 16:43:17 -07005775 int cpus = num_online_cpus();
Benjamin Li706bf242008-07-18 17:55:11 -07005776 int msix_vecs = min(cpus + 1, RX_MAX_RINGS);
Michael Chan5e9ad9e2008-06-19 16:43:17 -07005777
Michael Chan6d866ff2007-12-20 19:56:09 -08005778 bp->irq_tbl[0].handler = bnx2_interrupt;
5779 strcpy(bp->irq_tbl[0].name, bp->dev->name);
Michael Chanb4b36042007-12-20 19:59:30 -08005780 bp->irq_nvecs = 1;
5781 bp->irq_tbl[0].vector = bp->pdev->irq;
Michael Chan6d866ff2007-12-20 19:56:09 -08005782
Michael Chan5e9ad9e2008-06-19 16:43:17 -07005783 if ((bp->flags & BNX2_FLAG_MSIX_CAP) && !dis_msi && cpus > 1)
5784 bnx2_enable_msix(bp, msix_vecs);
Michael Chanb4b36042007-12-20 19:59:30 -08005785
David S. Millerf86e82f2008-01-21 17:15:40 -08005786 if ((bp->flags & BNX2_FLAG_MSI_CAP) && !dis_msi &&
5787 !(bp->flags & BNX2_FLAG_USING_MSIX)) {
Michael Chan6d866ff2007-12-20 19:56:09 -08005788 if (pci_enable_msi(bp->pdev) == 0) {
David S. Millerf86e82f2008-01-21 17:15:40 -08005789 bp->flags |= BNX2_FLAG_USING_MSI;
Michael Chan6d866ff2007-12-20 19:56:09 -08005790 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
David S. Millerf86e82f2008-01-21 17:15:40 -08005791 bp->flags |= BNX2_FLAG_ONE_SHOT_MSI;
Michael Chan6d866ff2007-12-20 19:56:09 -08005792 bp->irq_tbl[0].handler = bnx2_msi_1shot;
5793 } else
5794 bp->irq_tbl[0].handler = bnx2_msi;
Michael Chanb4b36042007-12-20 19:59:30 -08005795
5796 bp->irq_tbl[0].vector = bp->pdev->irq;
Michael Chan6d866ff2007-12-20 19:56:09 -08005797 }
5798 }
Benjamin Li706bf242008-07-18 17:55:11 -07005799
5800 bp->num_tx_rings = rounddown_pow_of_two(bp->irq_nvecs);
5801 bp->dev->real_num_tx_queues = bp->num_tx_rings;
5802
Michael Chan5e9ad9e2008-06-19 16:43:17 -07005803 bp->num_rx_rings = bp->irq_nvecs;
Michael Chan8e6a72c2007-05-03 13:24:48 -07005804}
5805
Michael Chanb6016b72005-05-26 13:03:09 -07005806/* Called with rtnl_lock */
5807static int
5808bnx2_open(struct net_device *dev)
5809{
Michael Chan972ec0d2006-01-23 16:12:43 -08005810 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07005811 int rc;
5812
Michael Chan1b2f9222007-05-03 13:20:19 -07005813 netif_carrier_off(dev);
5814
Pavel Machek829ca9a2005-09-03 15:56:56 -07005815 bnx2_set_power_state(bp, PCI_D0);
Michael Chanb6016b72005-05-26 13:03:09 -07005816 bnx2_disable_int(bp);
5817
Michael Chan6d866ff2007-12-20 19:56:09 -08005818 bnx2_setup_int_mode(bp, disable_msi);
Michael Chan35efa7c2007-12-20 19:56:37 -08005819 bnx2_napi_enable(bp);
Michael Chan35e90102008-06-19 16:37:42 -07005820 rc = bnx2_alloc_mem(bp);
Michael Chan2739a8b2008-06-19 16:44:10 -07005821 if (rc)
5822 goto open_err;
Michael Chan35e90102008-06-19 16:37:42 -07005823
Michael Chan8e6a72c2007-05-03 13:24:48 -07005824 rc = bnx2_request_irq(bp);
Michael Chan2739a8b2008-06-19 16:44:10 -07005825 if (rc)
5826 goto open_err;
Michael Chanb6016b72005-05-26 13:03:09 -07005827
Michael Chan9a120bc2008-05-16 22:17:45 -07005828 rc = bnx2_init_nic(bp, 1);
Michael Chan2739a8b2008-06-19 16:44:10 -07005829 if (rc)
5830 goto open_err;
Jeff Garzik6aa20a22006-09-13 13:24:59 -04005831
Michael Chancd339a02005-08-25 15:35:24 -07005832 mod_timer(&bp->timer, jiffies + bp->current_interval);
Michael Chanb6016b72005-05-26 13:03:09 -07005833
5834 atomic_set(&bp->intr_sem, 0);
5835
5836 bnx2_enable_int(bp);
5837
David S. Millerf86e82f2008-01-21 17:15:40 -08005838 if (bp->flags & BNX2_FLAG_USING_MSI) {
Michael Chanb6016b72005-05-26 13:03:09 -07005839 /* Test MSI to make sure it is working
5840 * If MSI test fails, go back to INTx mode
5841 */
5842 if (bnx2_test_intr(bp) != 0) {
5843 printk(KERN_WARNING PFX "%s: No interrupt was generated"
5844 " using MSI, switching to INTx mode. Please"
5845 " report this failure to the PCI maintainer"
5846 " and include system chipset information.\n",
5847 bp->dev->name);
5848
5849 bnx2_disable_int(bp);
Michael Chan8e6a72c2007-05-03 13:24:48 -07005850 bnx2_free_irq(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07005851
Michael Chan6d866ff2007-12-20 19:56:09 -08005852 bnx2_setup_int_mode(bp, 1);
5853
Michael Chan9a120bc2008-05-16 22:17:45 -07005854 rc = bnx2_init_nic(bp, 0);
Michael Chanb6016b72005-05-26 13:03:09 -07005855
Michael Chan8e6a72c2007-05-03 13:24:48 -07005856 if (!rc)
5857 rc = bnx2_request_irq(bp);
5858
Michael Chanb6016b72005-05-26 13:03:09 -07005859 if (rc) {
Michael Chanb6016b72005-05-26 13:03:09 -07005860 del_timer_sync(&bp->timer);
Michael Chan2739a8b2008-06-19 16:44:10 -07005861 goto open_err;
Michael Chanb6016b72005-05-26 13:03:09 -07005862 }
5863 bnx2_enable_int(bp);
5864 }
5865 }
David S. Millerf86e82f2008-01-21 17:15:40 -08005866 if (bp->flags & BNX2_FLAG_USING_MSI)
Michael Chanb6016b72005-05-26 13:03:09 -07005867 printk(KERN_INFO PFX "%s: using MSI\n", dev->name);
David S. Millerf86e82f2008-01-21 17:15:40 -08005868 else if (bp->flags & BNX2_FLAG_USING_MSIX)
Michael Chan57851d82007-12-20 20:01:44 -08005869 printk(KERN_INFO PFX "%s: using MSIX\n", dev->name);
Michael Chanb6016b72005-05-26 13:03:09 -07005870
Benjamin Li706bf242008-07-18 17:55:11 -07005871 netif_tx_start_all_queues(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07005872
5873 return 0;
Michael Chan2739a8b2008-06-19 16:44:10 -07005874
5875open_err:
5876 bnx2_napi_disable(bp);
5877 bnx2_free_skbs(bp);
5878 bnx2_free_irq(bp);
5879 bnx2_free_mem(bp);
5880 return rc;
Michael Chanb6016b72005-05-26 13:03:09 -07005881}
5882
5883static void
David Howellsc4028952006-11-22 14:57:56 +00005884bnx2_reset_task(struct work_struct *work)
Michael Chanb6016b72005-05-26 13:03:09 -07005885{
David Howellsc4028952006-11-22 14:57:56 +00005886 struct bnx2 *bp = container_of(work, struct bnx2, reset_task);
Michael Chanb6016b72005-05-26 13:03:09 -07005887
Michael Chanafdc08b2005-08-25 15:34:29 -07005888 if (!netif_running(bp->dev))
5889 return;
5890
Michael Chanb6016b72005-05-26 13:03:09 -07005891 bnx2_netif_stop(bp);
5892
Michael Chan9a120bc2008-05-16 22:17:45 -07005893 bnx2_init_nic(bp, 1);
Michael Chanb6016b72005-05-26 13:03:09 -07005894
5895 atomic_set(&bp->intr_sem, 1);
5896 bnx2_netif_start(bp);
5897}
5898
5899static void
5900bnx2_tx_timeout(struct net_device *dev)
5901{
Michael Chan972ec0d2006-01-23 16:12:43 -08005902 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07005903
5904 /* This allows the netif to be shutdown gracefully before resetting */
5905 schedule_work(&bp->reset_task);
5906}
5907
5908#ifdef BCM_VLAN
5909/* Called with rtnl_lock */
5910static void
5911bnx2_vlan_rx_register(struct net_device *dev, struct vlan_group *vlgrp)
5912{
Michael Chan972ec0d2006-01-23 16:12:43 -08005913 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07005914
5915 bnx2_netif_stop(bp);
5916
5917 bp->vlgrp = vlgrp;
5918 bnx2_set_rx_mode(dev);
Michael Chan7c62e832008-07-14 22:39:03 -07005919 if (bp->flags & BNX2_FLAG_CAN_KEEP_VLAN)
5920 bnx2_fw_sync(bp, BNX2_DRV_MSG_CODE_KEEP_VLAN_UPDATE, 0, 1);
Michael Chanb6016b72005-05-26 13:03:09 -07005921
5922 bnx2_netif_start(bp);
5923}
Michael Chanb6016b72005-05-26 13:03:09 -07005924#endif
5925
Herbert Xu932ff272006-06-09 12:20:56 -07005926/* Called with netif_tx_lock.
Michael Chan2f8af122006-08-15 01:39:10 -07005927 * bnx2_tx_int() runs without netif_tx_lock unless it needs to call
5928 * netif_wake_queue().
Michael Chanb6016b72005-05-26 13:03:09 -07005929 */
5930static int
5931bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev)
5932{
Michael Chan972ec0d2006-01-23 16:12:43 -08005933 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07005934 dma_addr_t mapping;
5935 struct tx_bd *txbd;
5936 struct sw_bd *tx_buf;
5937 u32 len, vlan_tag_flags, last_frag, mss;
5938 u16 prod, ring_prod;
5939 int i;
Benjamin Li706bf242008-07-18 17:55:11 -07005940 struct bnx2_napi *bnapi;
5941 struct bnx2_tx_ring_info *txr;
5942 struct netdev_queue *txq;
5943
5944 /* Determine which tx ring we will be placed on */
5945 i = skb_get_queue_mapping(skb);
5946 bnapi = &bp->bnx2_napi[i];
5947 txr = &bnapi->tx_ring;
5948 txq = netdev_get_tx_queue(dev, i);
Michael Chanb6016b72005-05-26 13:03:09 -07005949
Michael Chan35e90102008-06-19 16:37:42 -07005950 if (unlikely(bnx2_tx_avail(bp, txr) <
Michael Chana550c992007-12-20 19:56:59 -08005951 (skb_shinfo(skb)->nr_frags + 1))) {
Benjamin Li706bf242008-07-18 17:55:11 -07005952 netif_tx_stop_queue(txq);
Michael Chanb6016b72005-05-26 13:03:09 -07005953 printk(KERN_ERR PFX "%s: BUG! Tx ring full when queue awake!\n",
5954 dev->name);
5955
5956 return NETDEV_TX_BUSY;
5957 }
5958 len = skb_headlen(skb);
Michael Chan35e90102008-06-19 16:37:42 -07005959 prod = txr->tx_prod;
Michael Chanb6016b72005-05-26 13:03:09 -07005960 ring_prod = TX_RING_IDX(prod);
5961
5962 vlan_tag_flags = 0;
Patrick McHardy84fa7932006-08-29 16:44:56 -07005963 if (skb->ip_summed == CHECKSUM_PARTIAL) {
Michael Chanb6016b72005-05-26 13:03:09 -07005964 vlan_tag_flags |= TX_BD_FLAGS_TCP_UDP_CKSUM;
5965 }
5966
Al Viro79ea13c2008-01-24 02:06:46 -08005967 if (bp->vlgrp && vlan_tx_tag_present(skb)) {
Michael Chanb6016b72005-05-26 13:03:09 -07005968 vlan_tag_flags |=
5969 (TX_BD_FLAGS_VLAN_TAG | (vlan_tx_tag_get(skb) << 16));
5970 }
Michael Chanfde82052007-05-03 17:23:35 -07005971 if ((mss = skb_shinfo(skb)->gso_size)) {
Michael Chanb6016b72005-05-26 13:03:09 -07005972 u32 tcp_opt_len, ip_tcp_len;
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -07005973 struct iphdr *iph;
Michael Chanb6016b72005-05-26 13:03:09 -07005974
Michael Chanb6016b72005-05-26 13:03:09 -07005975 vlan_tag_flags |= TX_BD_FLAGS_SW_LSO;
5976
Michael Chan4666f872007-05-03 13:22:28 -07005977 tcp_opt_len = tcp_optlen(skb);
Arnaldo Carvalho de Meloab6a5bb2007-03-18 17:43:48 -07005978
Michael Chan4666f872007-05-03 13:22:28 -07005979 if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6) {
5980 u32 tcp_off = skb_transport_offset(skb) -
5981 sizeof(struct ipv6hdr) - ETH_HLEN;
Michael Chanb6016b72005-05-26 13:03:09 -07005982
Michael Chan4666f872007-05-03 13:22:28 -07005983 vlan_tag_flags |= ((tcp_opt_len >> 2) << 8) |
5984 TX_BD_FLAGS_SW_FLAGS;
5985 if (likely(tcp_off == 0))
5986 vlan_tag_flags &= ~TX_BD_FLAGS_TCP6_OFF0_MSK;
5987 else {
5988 tcp_off >>= 3;
5989 vlan_tag_flags |= ((tcp_off & 0x3) <<
5990 TX_BD_FLAGS_TCP6_OFF0_SHL) |
5991 ((tcp_off & 0x10) <<
5992 TX_BD_FLAGS_TCP6_OFF4_SHL);
5993 mss |= (tcp_off & 0xc) << TX_BD_TCP6_OFF2_SHL;
5994 }
5995 } else {
5996 if (skb_header_cloned(skb) &&
5997 pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) {
5998 dev_kfree_skb(skb);
5999 return NETDEV_TX_OK;
6000 }
6001
6002 ip_tcp_len = ip_hdrlen(skb) + sizeof(struct tcphdr);
6003
6004 iph = ip_hdr(skb);
6005 iph->check = 0;
6006 iph->tot_len = htons(mss + ip_tcp_len + tcp_opt_len);
6007 tcp_hdr(skb)->check = ~csum_tcpudp_magic(iph->saddr,
6008 iph->daddr, 0,
6009 IPPROTO_TCP,
6010 0);
6011 if (tcp_opt_len || (iph->ihl > 5)) {
6012 vlan_tag_flags |= ((iph->ihl - 5) +
6013 (tcp_opt_len >> 2)) << 8;
6014 }
Michael Chanb6016b72005-05-26 13:03:09 -07006015 }
Michael Chan4666f872007-05-03 13:22:28 -07006016 } else
Michael Chanb6016b72005-05-26 13:03:09 -07006017 mss = 0;
Michael Chanb6016b72005-05-26 13:03:09 -07006018
6019 mapping = pci_map_single(bp->pdev, skb->data, len, PCI_DMA_TODEVICE);
Jeff Garzik6aa20a22006-09-13 13:24:59 -04006020
Michael Chan35e90102008-06-19 16:37:42 -07006021 tx_buf = &txr->tx_buf_ring[ring_prod];
Michael Chanb6016b72005-05-26 13:03:09 -07006022 tx_buf->skb = skb;
6023 pci_unmap_addr_set(tx_buf, mapping, mapping);
6024
Michael Chan35e90102008-06-19 16:37:42 -07006025 txbd = &txr->tx_desc_ring[ring_prod];
Michael Chanb6016b72005-05-26 13:03:09 -07006026
6027 txbd->tx_bd_haddr_hi = (u64) mapping >> 32;
6028 txbd->tx_bd_haddr_lo = (u64) mapping & 0xffffffff;
6029 txbd->tx_bd_mss_nbytes = len | (mss << 16);
6030 txbd->tx_bd_vlan_tag_flags = vlan_tag_flags | TX_BD_FLAGS_START;
6031
6032 last_frag = skb_shinfo(skb)->nr_frags;
6033
6034 for (i = 0; i < last_frag; i++) {
6035 skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
6036
6037 prod = NEXT_TX_BD(prod);
6038 ring_prod = TX_RING_IDX(prod);
Michael Chan35e90102008-06-19 16:37:42 -07006039 txbd = &txr->tx_desc_ring[ring_prod];
Michael Chanb6016b72005-05-26 13:03:09 -07006040
6041 len = frag->size;
6042 mapping = pci_map_page(bp->pdev, frag->page, frag->page_offset,
6043 len, PCI_DMA_TODEVICE);
Michael Chan35e90102008-06-19 16:37:42 -07006044 pci_unmap_addr_set(&txr->tx_buf_ring[ring_prod],
Michael Chanb6016b72005-05-26 13:03:09 -07006045 mapping, mapping);
6046
6047 txbd->tx_bd_haddr_hi = (u64) mapping >> 32;
6048 txbd->tx_bd_haddr_lo = (u64) mapping & 0xffffffff;
6049 txbd->tx_bd_mss_nbytes = len | (mss << 16);
6050 txbd->tx_bd_vlan_tag_flags = vlan_tag_flags;
6051
6052 }
6053 txbd->tx_bd_vlan_tag_flags |= TX_BD_FLAGS_END;
6054
6055 prod = NEXT_TX_BD(prod);
Michael Chan35e90102008-06-19 16:37:42 -07006056 txr->tx_prod_bseq += skb->len;
Michael Chanb6016b72005-05-26 13:03:09 -07006057
Michael Chan35e90102008-06-19 16:37:42 -07006058 REG_WR16(bp, txr->tx_bidx_addr, prod);
6059 REG_WR(bp, txr->tx_bseq_addr, txr->tx_prod_bseq);
Michael Chanb6016b72005-05-26 13:03:09 -07006060
6061 mmiowb();
6062
Michael Chan35e90102008-06-19 16:37:42 -07006063 txr->tx_prod = prod;
Michael Chanb6016b72005-05-26 13:03:09 -07006064 dev->trans_start = jiffies;
6065
Michael Chan35e90102008-06-19 16:37:42 -07006066 if (unlikely(bnx2_tx_avail(bp, txr) <= MAX_SKB_FRAGS)) {
Benjamin Li706bf242008-07-18 17:55:11 -07006067 netif_tx_stop_queue(txq);
Michael Chan35e90102008-06-19 16:37:42 -07006068 if (bnx2_tx_avail(bp, txr) > bp->tx_wake_thresh)
Benjamin Li706bf242008-07-18 17:55:11 -07006069 netif_tx_wake_queue(txq);
Michael Chanb6016b72005-05-26 13:03:09 -07006070 }
6071
6072 return NETDEV_TX_OK;
6073}
6074
6075/* Called with rtnl_lock */
6076static int
6077bnx2_close(struct net_device *dev)
6078{
Michael Chan972ec0d2006-01-23 16:12:43 -08006079 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006080 u32 reset_code;
6081
David S. Miller4bb073c2008-06-12 02:22:02 -07006082 cancel_work_sync(&bp->reset_task);
Michael Chanafdc08b2005-08-25 15:34:29 -07006083
Stephen Hemmingerbea33482007-10-03 16:41:36 -07006084 bnx2_disable_int_sync(bp);
Michael Chan35efa7c2007-12-20 19:56:37 -08006085 bnx2_napi_disable(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07006086 del_timer_sync(&bp->timer);
David S. Millerf86e82f2008-01-21 17:15:40 -08006087 if (bp->flags & BNX2_FLAG_NO_WOL)
Michael Chan6c4f0952006-06-29 12:38:15 -07006088 reset_code = BNX2_DRV_MSG_CODE_UNLOAD_LNK_DN;
Michael Chandda1e392006-01-23 16:08:14 -08006089 else if (bp->wol)
Michael Chanb6016b72005-05-26 13:03:09 -07006090 reset_code = BNX2_DRV_MSG_CODE_SUSPEND_WOL;
6091 else
6092 reset_code = BNX2_DRV_MSG_CODE_SUSPEND_NO_WOL;
6093 bnx2_reset_chip(bp, reset_code);
Michael Chan8e6a72c2007-05-03 13:24:48 -07006094 bnx2_free_irq(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07006095 bnx2_free_skbs(bp);
6096 bnx2_free_mem(bp);
6097 bp->link_up = 0;
6098 netif_carrier_off(bp->dev);
Pavel Machek829ca9a2005-09-03 15:56:56 -07006099 bnx2_set_power_state(bp, PCI_D3hot);
Michael Chanb6016b72005-05-26 13:03:09 -07006100 return 0;
6101}
6102
6103#define GET_NET_STATS64(ctr) \
6104 (unsigned long) ((unsigned long) (ctr##_hi) << 32) + \
6105 (unsigned long) (ctr##_lo)
6106
6107#define GET_NET_STATS32(ctr) \
6108 (ctr##_lo)
6109
6110#if (BITS_PER_LONG == 64)
6111#define GET_NET_STATS GET_NET_STATS64
6112#else
6113#define GET_NET_STATS GET_NET_STATS32
6114#endif
6115
6116static struct net_device_stats *
6117bnx2_get_stats(struct net_device *dev)
6118{
Michael Chan972ec0d2006-01-23 16:12:43 -08006119 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006120 struct statistics_block *stats_blk = bp->stats_blk;
6121 struct net_device_stats *net_stats = &bp->net_stats;
6122
6123 if (bp->stats_blk == NULL) {
6124 return net_stats;
6125 }
6126 net_stats->rx_packets =
6127 GET_NET_STATS(stats_blk->stat_IfHCInUcastPkts) +
6128 GET_NET_STATS(stats_blk->stat_IfHCInMulticastPkts) +
6129 GET_NET_STATS(stats_blk->stat_IfHCInBroadcastPkts);
6130
6131 net_stats->tx_packets =
6132 GET_NET_STATS(stats_blk->stat_IfHCOutUcastPkts) +
6133 GET_NET_STATS(stats_blk->stat_IfHCOutMulticastPkts) +
6134 GET_NET_STATS(stats_blk->stat_IfHCOutBroadcastPkts);
6135
6136 net_stats->rx_bytes =
6137 GET_NET_STATS(stats_blk->stat_IfHCInOctets);
6138
6139 net_stats->tx_bytes =
6140 GET_NET_STATS(stats_blk->stat_IfHCOutOctets);
6141
Jeff Garzik6aa20a22006-09-13 13:24:59 -04006142 net_stats->multicast =
Michael Chanb6016b72005-05-26 13:03:09 -07006143 GET_NET_STATS(stats_blk->stat_IfHCOutMulticastPkts);
6144
Jeff Garzik6aa20a22006-09-13 13:24:59 -04006145 net_stats->collisions =
Michael Chanb6016b72005-05-26 13:03:09 -07006146 (unsigned long) stats_blk->stat_EtherStatsCollisions;
6147
Jeff Garzik6aa20a22006-09-13 13:24:59 -04006148 net_stats->rx_length_errors =
Michael Chanb6016b72005-05-26 13:03:09 -07006149 (unsigned long) (stats_blk->stat_EtherStatsUndersizePkts +
6150 stats_blk->stat_EtherStatsOverrsizePkts);
6151
Jeff Garzik6aa20a22006-09-13 13:24:59 -04006152 net_stats->rx_over_errors =
Michael Chanb6016b72005-05-26 13:03:09 -07006153 (unsigned long) stats_blk->stat_IfInMBUFDiscards;
6154
Jeff Garzik6aa20a22006-09-13 13:24:59 -04006155 net_stats->rx_frame_errors =
Michael Chanb6016b72005-05-26 13:03:09 -07006156 (unsigned long) stats_blk->stat_Dot3StatsAlignmentErrors;
6157
Jeff Garzik6aa20a22006-09-13 13:24:59 -04006158 net_stats->rx_crc_errors =
Michael Chanb6016b72005-05-26 13:03:09 -07006159 (unsigned long) stats_blk->stat_Dot3StatsFCSErrors;
6160
6161 net_stats->rx_errors = net_stats->rx_length_errors +
6162 net_stats->rx_over_errors + net_stats->rx_frame_errors +
6163 net_stats->rx_crc_errors;
6164
6165 net_stats->tx_aborted_errors =
6166 (unsigned long) (stats_blk->stat_Dot3StatsExcessiveCollisions +
6167 stats_blk->stat_Dot3StatsLateCollisions);
6168
Michael Chan5b0c76a2005-11-04 08:45:49 -08006169 if ((CHIP_NUM(bp) == CHIP_NUM_5706) ||
6170 (CHIP_ID(bp) == CHIP_ID_5708_A0))
Michael Chanb6016b72005-05-26 13:03:09 -07006171 net_stats->tx_carrier_errors = 0;
6172 else {
6173 net_stats->tx_carrier_errors =
6174 (unsigned long)
6175 stats_blk->stat_Dot3StatsCarrierSenseErrors;
6176 }
6177
6178 net_stats->tx_errors =
Jeff Garzik6aa20a22006-09-13 13:24:59 -04006179 (unsigned long)
Michael Chanb6016b72005-05-26 13:03:09 -07006180 stats_blk->stat_emac_tx_stat_dot3statsinternalmactransmiterrors
6181 +
6182 net_stats->tx_aborted_errors +
6183 net_stats->tx_carrier_errors;
6184
Michael Chancea94db2006-06-12 22:16:13 -07006185 net_stats->rx_missed_errors =
6186 (unsigned long) (stats_blk->stat_IfInMBUFDiscards +
6187 stats_blk->stat_FwRxDrop);
6188
Michael Chanb6016b72005-05-26 13:03:09 -07006189 return net_stats;
6190}
6191
6192/* All ethtool functions called with rtnl_lock */
6193
6194static int
6195bnx2_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
6196{
Michael Chan972ec0d2006-01-23 16:12:43 -08006197 struct bnx2 *bp = netdev_priv(dev);
Michael Chan7b6b8342007-07-07 22:50:15 -07006198 int support_serdes = 0, support_copper = 0;
Michael Chanb6016b72005-05-26 13:03:09 -07006199
6200 cmd->supported = SUPPORTED_Autoneg;
Michael Chan583c28e2008-01-21 19:51:35 -08006201 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP) {
Michael Chan7b6b8342007-07-07 22:50:15 -07006202 support_serdes = 1;
6203 support_copper = 1;
6204 } else if (bp->phy_port == PORT_FIBRE)
6205 support_serdes = 1;
6206 else
6207 support_copper = 1;
6208
6209 if (support_serdes) {
Michael Chanb6016b72005-05-26 13:03:09 -07006210 cmd->supported |= SUPPORTED_1000baseT_Full |
6211 SUPPORTED_FIBRE;
Michael Chan583c28e2008-01-21 19:51:35 -08006212 if (bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE)
Michael Chan605a9e22007-05-03 13:23:13 -07006213 cmd->supported |= SUPPORTED_2500baseX_Full;
Michael Chanb6016b72005-05-26 13:03:09 -07006214
Michael Chanb6016b72005-05-26 13:03:09 -07006215 }
Michael Chan7b6b8342007-07-07 22:50:15 -07006216 if (support_copper) {
Michael Chanb6016b72005-05-26 13:03:09 -07006217 cmd->supported |= SUPPORTED_10baseT_Half |
6218 SUPPORTED_10baseT_Full |
6219 SUPPORTED_100baseT_Half |
6220 SUPPORTED_100baseT_Full |
6221 SUPPORTED_1000baseT_Full |
6222 SUPPORTED_TP;
6223
Michael Chanb6016b72005-05-26 13:03:09 -07006224 }
6225
Michael Chan7b6b8342007-07-07 22:50:15 -07006226 spin_lock_bh(&bp->phy_lock);
6227 cmd->port = bp->phy_port;
Michael Chanb6016b72005-05-26 13:03:09 -07006228 cmd->advertising = bp->advertising;
6229
6230 if (bp->autoneg & AUTONEG_SPEED) {
6231 cmd->autoneg = AUTONEG_ENABLE;
6232 }
6233 else {
6234 cmd->autoneg = AUTONEG_DISABLE;
6235 }
6236
6237 if (netif_carrier_ok(dev)) {
6238 cmd->speed = bp->line_speed;
6239 cmd->duplex = bp->duplex;
6240 }
6241 else {
6242 cmd->speed = -1;
6243 cmd->duplex = -1;
6244 }
Michael Chan7b6b8342007-07-07 22:50:15 -07006245 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07006246
6247 cmd->transceiver = XCVR_INTERNAL;
6248 cmd->phy_address = bp->phy_addr;
6249
6250 return 0;
6251}
Jeff Garzik6aa20a22006-09-13 13:24:59 -04006252
Michael Chanb6016b72005-05-26 13:03:09 -07006253static int
6254bnx2_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
6255{
Michael Chan972ec0d2006-01-23 16:12:43 -08006256 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006257 u8 autoneg = bp->autoneg;
6258 u8 req_duplex = bp->req_duplex;
6259 u16 req_line_speed = bp->req_line_speed;
6260 u32 advertising = bp->advertising;
Michael Chan7b6b8342007-07-07 22:50:15 -07006261 int err = -EINVAL;
6262
6263 spin_lock_bh(&bp->phy_lock);
6264
6265 if (cmd->port != PORT_TP && cmd->port != PORT_FIBRE)
6266 goto err_out_unlock;
6267
Michael Chan583c28e2008-01-21 19:51:35 -08006268 if (cmd->port != bp->phy_port &&
6269 !(bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP))
Michael Chan7b6b8342007-07-07 22:50:15 -07006270 goto err_out_unlock;
Michael Chanb6016b72005-05-26 13:03:09 -07006271
Michael Chand6b14482008-07-14 22:37:21 -07006272 /* If device is down, we can store the settings only if the user
6273 * is setting the currently active port.
6274 */
6275 if (!netif_running(dev) && cmd->port != bp->phy_port)
6276 goto err_out_unlock;
6277
Michael Chanb6016b72005-05-26 13:03:09 -07006278 if (cmd->autoneg == AUTONEG_ENABLE) {
6279 autoneg |= AUTONEG_SPEED;
6280
Jeff Garzik6aa20a22006-09-13 13:24:59 -04006281 cmd->advertising &= ETHTOOL_ALL_COPPER_SPEED;
Michael Chanb6016b72005-05-26 13:03:09 -07006282
6283 /* allow advertising 1 speed */
6284 if ((cmd->advertising == ADVERTISED_10baseT_Half) ||
6285 (cmd->advertising == ADVERTISED_10baseT_Full) ||
6286 (cmd->advertising == ADVERTISED_100baseT_Half) ||
6287 (cmd->advertising == ADVERTISED_100baseT_Full)) {
6288
Michael Chan7b6b8342007-07-07 22:50:15 -07006289 if (cmd->port == PORT_FIBRE)
6290 goto err_out_unlock;
Michael Chanb6016b72005-05-26 13:03:09 -07006291
6292 advertising = cmd->advertising;
6293
Michael Chan27a005b2007-05-03 13:23:41 -07006294 } else if (cmd->advertising == ADVERTISED_2500baseX_Full) {
Michael Chan583c28e2008-01-21 19:51:35 -08006295 if (!(bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE) ||
Michael Chan7b6b8342007-07-07 22:50:15 -07006296 (cmd->port == PORT_TP))
6297 goto err_out_unlock;
6298 } else if (cmd->advertising == ADVERTISED_1000baseT_Full)
Michael Chanb6016b72005-05-26 13:03:09 -07006299 advertising = cmd->advertising;
Michael Chan7b6b8342007-07-07 22:50:15 -07006300 else if (cmd->advertising == ADVERTISED_1000baseT_Half)
6301 goto err_out_unlock;
Michael Chanb6016b72005-05-26 13:03:09 -07006302 else {
Michael Chan7b6b8342007-07-07 22:50:15 -07006303 if (cmd->port == PORT_FIBRE)
Michael Chanb6016b72005-05-26 13:03:09 -07006304 advertising = ETHTOOL_ALL_FIBRE_SPEED;
Michael Chan7b6b8342007-07-07 22:50:15 -07006305 else
Michael Chanb6016b72005-05-26 13:03:09 -07006306 advertising = ETHTOOL_ALL_COPPER_SPEED;
Michael Chanb6016b72005-05-26 13:03:09 -07006307 }
6308 advertising |= ADVERTISED_Autoneg;
6309 }
6310 else {
Michael Chan7b6b8342007-07-07 22:50:15 -07006311 if (cmd->port == PORT_FIBRE) {
Michael Chan80be4432006-11-19 14:07:28 -08006312 if ((cmd->speed != SPEED_1000 &&
6313 cmd->speed != SPEED_2500) ||
6314 (cmd->duplex != DUPLEX_FULL))
Michael Chan7b6b8342007-07-07 22:50:15 -07006315 goto err_out_unlock;
Michael Chan80be4432006-11-19 14:07:28 -08006316
6317 if (cmd->speed == SPEED_2500 &&
Michael Chan583c28e2008-01-21 19:51:35 -08006318 !(bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE))
Michael Chan7b6b8342007-07-07 22:50:15 -07006319 goto err_out_unlock;
Michael Chanb6016b72005-05-26 13:03:09 -07006320 }
Michael Chan7b6b8342007-07-07 22:50:15 -07006321 else if (cmd->speed == SPEED_1000 || cmd->speed == SPEED_2500)
6322 goto err_out_unlock;
6323
Michael Chanb6016b72005-05-26 13:03:09 -07006324 autoneg &= ~AUTONEG_SPEED;
6325 req_line_speed = cmd->speed;
6326 req_duplex = cmd->duplex;
6327 advertising = 0;
6328 }
6329
6330 bp->autoneg = autoneg;
6331 bp->advertising = advertising;
6332 bp->req_line_speed = req_line_speed;
6333 bp->req_duplex = req_duplex;
6334
Michael Chand6b14482008-07-14 22:37:21 -07006335 err = 0;
6336 /* If device is down, the new settings will be picked up when it is
6337 * brought up.
6338 */
6339 if (netif_running(dev))
6340 err = bnx2_setup_phy(bp, cmd->port);
Michael Chanb6016b72005-05-26 13:03:09 -07006341
Michael Chan7b6b8342007-07-07 22:50:15 -07006342err_out_unlock:
Michael Chanc770a652005-08-25 15:38:39 -07006343 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07006344
Michael Chan7b6b8342007-07-07 22:50:15 -07006345 return err;
Michael Chanb6016b72005-05-26 13:03:09 -07006346}
6347
6348static void
6349bnx2_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
6350{
Michael Chan972ec0d2006-01-23 16:12:43 -08006351 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006352
6353 strcpy(info->driver, DRV_MODULE_NAME);
6354 strcpy(info->version, DRV_MODULE_VERSION);
6355 strcpy(info->bus_info, pci_name(bp->pdev));
Michael Chan58fc2ea2007-07-07 22:52:02 -07006356 strcpy(info->fw_version, bp->fw_version);
Michael Chanb6016b72005-05-26 13:03:09 -07006357}
6358
Michael Chan244ac4f2006-03-20 17:48:46 -08006359#define BNX2_REGDUMP_LEN (32 * 1024)
6360
6361static int
6362bnx2_get_regs_len(struct net_device *dev)
6363{
6364 return BNX2_REGDUMP_LEN;
6365}
6366
6367static void
6368bnx2_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *_p)
6369{
6370 u32 *p = _p, i, offset;
6371 u8 *orig_p = _p;
6372 struct bnx2 *bp = netdev_priv(dev);
6373 u32 reg_boundaries[] = { 0x0000, 0x0098, 0x0400, 0x045c,
6374 0x0800, 0x0880, 0x0c00, 0x0c10,
6375 0x0c30, 0x0d08, 0x1000, 0x101c,
6376 0x1040, 0x1048, 0x1080, 0x10a4,
6377 0x1400, 0x1490, 0x1498, 0x14f0,
6378 0x1500, 0x155c, 0x1580, 0x15dc,
6379 0x1600, 0x1658, 0x1680, 0x16d8,
6380 0x1800, 0x1820, 0x1840, 0x1854,
6381 0x1880, 0x1894, 0x1900, 0x1984,
6382 0x1c00, 0x1c0c, 0x1c40, 0x1c54,
6383 0x1c80, 0x1c94, 0x1d00, 0x1d84,
6384 0x2000, 0x2030, 0x23c0, 0x2400,
6385 0x2800, 0x2820, 0x2830, 0x2850,
6386 0x2b40, 0x2c10, 0x2fc0, 0x3058,
6387 0x3c00, 0x3c94, 0x4000, 0x4010,
6388 0x4080, 0x4090, 0x43c0, 0x4458,
6389 0x4c00, 0x4c18, 0x4c40, 0x4c54,
6390 0x4fc0, 0x5010, 0x53c0, 0x5444,
6391 0x5c00, 0x5c18, 0x5c80, 0x5c90,
6392 0x5fc0, 0x6000, 0x6400, 0x6428,
6393 0x6800, 0x6848, 0x684c, 0x6860,
6394 0x6888, 0x6910, 0x8000 };
6395
6396 regs->version = 0;
6397
6398 memset(p, 0, BNX2_REGDUMP_LEN);
6399
6400 if (!netif_running(bp->dev))
6401 return;
6402
6403 i = 0;
6404 offset = reg_boundaries[0];
6405 p += offset;
6406 while (offset < BNX2_REGDUMP_LEN) {
6407 *p++ = REG_RD(bp, offset);
6408 offset += 4;
6409 if (offset == reg_boundaries[i + 1]) {
6410 offset = reg_boundaries[i + 2];
6411 p = (u32 *) (orig_p + offset);
6412 i += 2;
6413 }
6414 }
6415}
6416
Michael Chanb6016b72005-05-26 13:03:09 -07006417static void
6418bnx2_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
6419{
Michael Chan972ec0d2006-01-23 16:12:43 -08006420 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006421
David S. Millerf86e82f2008-01-21 17:15:40 -08006422 if (bp->flags & BNX2_FLAG_NO_WOL) {
Michael Chanb6016b72005-05-26 13:03:09 -07006423 wol->supported = 0;
6424 wol->wolopts = 0;
6425 }
6426 else {
6427 wol->supported = WAKE_MAGIC;
6428 if (bp->wol)
6429 wol->wolopts = WAKE_MAGIC;
6430 else
6431 wol->wolopts = 0;
6432 }
6433 memset(&wol->sopass, 0, sizeof(wol->sopass));
6434}
6435
6436static int
6437bnx2_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
6438{
Michael Chan972ec0d2006-01-23 16:12:43 -08006439 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006440
6441 if (wol->wolopts & ~WAKE_MAGIC)
6442 return -EINVAL;
6443
6444 if (wol->wolopts & WAKE_MAGIC) {
David S. Millerf86e82f2008-01-21 17:15:40 -08006445 if (bp->flags & BNX2_FLAG_NO_WOL)
Michael Chanb6016b72005-05-26 13:03:09 -07006446 return -EINVAL;
6447
6448 bp->wol = 1;
6449 }
6450 else {
6451 bp->wol = 0;
6452 }
6453 return 0;
6454}
6455
6456static int
6457bnx2_nway_reset(struct net_device *dev)
6458{
Michael Chan972ec0d2006-01-23 16:12:43 -08006459 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006460 u32 bmcr;
6461
6462 if (!(bp->autoneg & AUTONEG_SPEED)) {
6463 return -EINVAL;
6464 }
6465
Michael Chanc770a652005-08-25 15:38:39 -07006466 spin_lock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07006467
Michael Chan583c28e2008-01-21 19:51:35 -08006468 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP) {
Michael Chan7b6b8342007-07-07 22:50:15 -07006469 int rc;
6470
6471 rc = bnx2_setup_remote_phy(bp, bp->phy_port);
6472 spin_unlock_bh(&bp->phy_lock);
6473 return rc;
6474 }
6475
Michael Chanb6016b72005-05-26 13:03:09 -07006476 /* Force a link down visible on the other side */
Michael Chan583c28e2008-01-21 19:51:35 -08006477 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Michael Chanca58c3a2007-05-03 13:22:52 -07006478 bnx2_write_phy(bp, bp->mii_bmcr, BMCR_LOOPBACK);
Michael Chanc770a652005-08-25 15:38:39 -07006479 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07006480
6481 msleep(20);
6482
Michael Chanc770a652005-08-25 15:38:39 -07006483 spin_lock_bh(&bp->phy_lock);
Michael Chanf8dd0642006-11-19 14:08:29 -08006484
6485 bp->current_interval = SERDES_AN_TIMEOUT;
6486 bp->serdes_an_pending = 1;
6487 mod_timer(&bp->timer, jiffies + bp->current_interval);
Michael Chanb6016b72005-05-26 13:03:09 -07006488 }
6489
Michael Chanca58c3a2007-05-03 13:22:52 -07006490 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chanb6016b72005-05-26 13:03:09 -07006491 bmcr &= ~BMCR_LOOPBACK;
Michael Chanca58c3a2007-05-03 13:22:52 -07006492 bnx2_write_phy(bp, bp->mii_bmcr, bmcr | BMCR_ANRESTART | BMCR_ANENABLE);
Michael Chanb6016b72005-05-26 13:03:09 -07006493
Michael Chanc770a652005-08-25 15:38:39 -07006494 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07006495
6496 return 0;
6497}
6498
6499static int
6500bnx2_get_eeprom_len(struct net_device *dev)
6501{
Michael Chan972ec0d2006-01-23 16:12:43 -08006502 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006503
Michael Chan1122db72006-01-23 16:11:42 -08006504 if (bp->flash_info == NULL)
Michael Chanb6016b72005-05-26 13:03:09 -07006505 return 0;
6506
Michael Chan1122db72006-01-23 16:11:42 -08006507 return (int) bp->flash_size;
Michael Chanb6016b72005-05-26 13:03:09 -07006508}
6509
6510static int
6511bnx2_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
6512 u8 *eebuf)
6513{
Michael Chan972ec0d2006-01-23 16:12:43 -08006514 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006515 int rc;
6516
John W. Linville1064e942005-11-10 12:58:24 -08006517 /* parameters already validated in ethtool_get_eeprom */
Michael Chanb6016b72005-05-26 13:03:09 -07006518
6519 rc = bnx2_nvram_read(bp, eeprom->offset, eebuf, eeprom->len);
6520
6521 return rc;
6522}
6523
6524static int
6525bnx2_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
6526 u8 *eebuf)
6527{
Michael Chan972ec0d2006-01-23 16:12:43 -08006528 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006529 int rc;
6530
John W. Linville1064e942005-11-10 12:58:24 -08006531 /* parameters already validated in ethtool_set_eeprom */
Michael Chanb6016b72005-05-26 13:03:09 -07006532
6533 rc = bnx2_nvram_write(bp, eeprom->offset, eebuf, eeprom->len);
6534
6535 return rc;
6536}
6537
6538static int
6539bnx2_get_coalesce(struct net_device *dev, struct ethtool_coalesce *coal)
6540{
Michael Chan972ec0d2006-01-23 16:12:43 -08006541 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006542
6543 memset(coal, 0, sizeof(struct ethtool_coalesce));
6544
6545 coal->rx_coalesce_usecs = bp->rx_ticks;
6546 coal->rx_max_coalesced_frames = bp->rx_quick_cons_trip;
6547 coal->rx_coalesce_usecs_irq = bp->rx_ticks_int;
6548 coal->rx_max_coalesced_frames_irq = bp->rx_quick_cons_trip_int;
6549
6550 coal->tx_coalesce_usecs = bp->tx_ticks;
6551 coal->tx_max_coalesced_frames = bp->tx_quick_cons_trip;
6552 coal->tx_coalesce_usecs_irq = bp->tx_ticks_int;
6553 coal->tx_max_coalesced_frames_irq = bp->tx_quick_cons_trip_int;
6554
6555 coal->stats_block_coalesce_usecs = bp->stats_ticks;
6556
6557 return 0;
6558}
6559
6560static int
6561bnx2_set_coalesce(struct net_device *dev, struct ethtool_coalesce *coal)
6562{
Michael Chan972ec0d2006-01-23 16:12:43 -08006563 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006564
6565 bp->rx_ticks = (u16) coal->rx_coalesce_usecs;
6566 if (bp->rx_ticks > 0x3ff) bp->rx_ticks = 0x3ff;
6567
Jeff Garzik6aa20a22006-09-13 13:24:59 -04006568 bp->rx_quick_cons_trip = (u16) coal->rx_max_coalesced_frames;
Michael Chanb6016b72005-05-26 13:03:09 -07006569 if (bp->rx_quick_cons_trip > 0xff) bp->rx_quick_cons_trip = 0xff;
6570
6571 bp->rx_ticks_int = (u16) coal->rx_coalesce_usecs_irq;
6572 if (bp->rx_ticks_int > 0x3ff) bp->rx_ticks_int = 0x3ff;
6573
6574 bp->rx_quick_cons_trip_int = (u16) coal->rx_max_coalesced_frames_irq;
6575 if (bp->rx_quick_cons_trip_int > 0xff)
6576 bp->rx_quick_cons_trip_int = 0xff;
6577
6578 bp->tx_ticks = (u16) coal->tx_coalesce_usecs;
6579 if (bp->tx_ticks > 0x3ff) bp->tx_ticks = 0x3ff;
6580
6581 bp->tx_quick_cons_trip = (u16) coal->tx_max_coalesced_frames;
6582 if (bp->tx_quick_cons_trip > 0xff) bp->tx_quick_cons_trip = 0xff;
6583
6584 bp->tx_ticks_int = (u16) coal->tx_coalesce_usecs_irq;
6585 if (bp->tx_ticks_int > 0x3ff) bp->tx_ticks_int = 0x3ff;
6586
6587 bp->tx_quick_cons_trip_int = (u16) coal->tx_max_coalesced_frames_irq;
6588 if (bp->tx_quick_cons_trip_int > 0xff) bp->tx_quick_cons_trip_int =
6589 0xff;
6590
6591 bp->stats_ticks = coal->stats_block_coalesce_usecs;
Michael Chan02537b062007-06-04 21:24:07 -07006592 if (CHIP_NUM(bp) == CHIP_NUM_5708) {
6593 if (bp->stats_ticks != 0 && bp->stats_ticks != USEC_PER_SEC)
6594 bp->stats_ticks = USEC_PER_SEC;
6595 }
Michael Chan7ea69202007-07-16 18:27:10 -07006596 if (bp->stats_ticks > BNX2_HC_STATS_TICKS_HC_STAT_TICKS)
6597 bp->stats_ticks = BNX2_HC_STATS_TICKS_HC_STAT_TICKS;
6598 bp->stats_ticks &= BNX2_HC_STATS_TICKS_HC_STAT_TICKS;
Michael Chanb6016b72005-05-26 13:03:09 -07006599
6600 if (netif_running(bp->dev)) {
6601 bnx2_netif_stop(bp);
Michael Chan9a120bc2008-05-16 22:17:45 -07006602 bnx2_init_nic(bp, 0);
Michael Chanb6016b72005-05-26 13:03:09 -07006603 bnx2_netif_start(bp);
6604 }
6605
6606 return 0;
6607}
6608
6609static void
6610bnx2_get_ringparam(struct net_device *dev, struct ethtool_ringparam *ering)
6611{
Michael Chan972ec0d2006-01-23 16:12:43 -08006612 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006613
Michael Chan13daffa2006-03-20 17:49:20 -08006614 ering->rx_max_pending = MAX_TOTAL_RX_DESC_CNT;
Michael Chanb6016b72005-05-26 13:03:09 -07006615 ering->rx_mini_max_pending = 0;
Michael Chan47bf4242007-12-12 11:19:12 -08006616 ering->rx_jumbo_max_pending = MAX_TOTAL_RX_PG_DESC_CNT;
Michael Chanb6016b72005-05-26 13:03:09 -07006617
6618 ering->rx_pending = bp->rx_ring_size;
6619 ering->rx_mini_pending = 0;
Michael Chan47bf4242007-12-12 11:19:12 -08006620 ering->rx_jumbo_pending = bp->rx_pg_ring_size;
Michael Chanb6016b72005-05-26 13:03:09 -07006621
6622 ering->tx_max_pending = MAX_TX_DESC_CNT;
6623 ering->tx_pending = bp->tx_ring_size;
6624}
6625
6626static int
Michael Chan5d5d0012007-12-12 11:17:43 -08006627bnx2_change_ring_size(struct bnx2 *bp, u32 rx, u32 tx)
Michael Chanb6016b72005-05-26 13:03:09 -07006628{
Michael Chan13daffa2006-03-20 17:49:20 -08006629 if (netif_running(bp->dev)) {
6630 bnx2_netif_stop(bp);
6631 bnx2_reset_chip(bp, BNX2_DRV_MSG_CODE_RESET);
6632 bnx2_free_skbs(bp);
6633 bnx2_free_mem(bp);
6634 }
6635
Michael Chan5d5d0012007-12-12 11:17:43 -08006636 bnx2_set_rx_ring_size(bp, rx);
6637 bp->tx_ring_size = tx;
Michael Chanb6016b72005-05-26 13:03:09 -07006638
6639 if (netif_running(bp->dev)) {
Michael Chan13daffa2006-03-20 17:49:20 -08006640 int rc;
6641
6642 rc = bnx2_alloc_mem(bp);
6643 if (rc)
6644 return rc;
Michael Chan9a120bc2008-05-16 22:17:45 -07006645 bnx2_init_nic(bp, 0);
Michael Chanb6016b72005-05-26 13:03:09 -07006646 bnx2_netif_start(bp);
6647 }
Michael Chanb6016b72005-05-26 13:03:09 -07006648 return 0;
6649}
6650
Michael Chan5d5d0012007-12-12 11:17:43 -08006651static int
6652bnx2_set_ringparam(struct net_device *dev, struct ethtool_ringparam *ering)
6653{
6654 struct bnx2 *bp = netdev_priv(dev);
6655 int rc;
6656
6657 if ((ering->rx_pending > MAX_TOTAL_RX_DESC_CNT) ||
6658 (ering->tx_pending > MAX_TX_DESC_CNT) ||
6659 (ering->tx_pending <= MAX_SKB_FRAGS)) {
6660
6661 return -EINVAL;
6662 }
6663 rc = bnx2_change_ring_size(bp, ering->rx_pending, ering->tx_pending);
6664 return rc;
6665}
6666
Michael Chanb6016b72005-05-26 13:03:09 -07006667static void
6668bnx2_get_pauseparam(struct net_device *dev, struct ethtool_pauseparam *epause)
6669{
Michael Chan972ec0d2006-01-23 16:12:43 -08006670 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006671
6672 epause->autoneg = ((bp->autoneg & AUTONEG_FLOW_CTRL) != 0);
6673 epause->rx_pause = ((bp->flow_ctrl & FLOW_CTRL_RX) != 0);
6674 epause->tx_pause = ((bp->flow_ctrl & FLOW_CTRL_TX) != 0);
6675}
6676
6677static int
6678bnx2_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam *epause)
6679{
Michael Chan972ec0d2006-01-23 16:12:43 -08006680 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006681
6682 bp->req_flow_ctrl = 0;
6683 if (epause->rx_pause)
6684 bp->req_flow_ctrl |= FLOW_CTRL_RX;
6685 if (epause->tx_pause)
6686 bp->req_flow_ctrl |= FLOW_CTRL_TX;
6687
6688 if (epause->autoneg) {
6689 bp->autoneg |= AUTONEG_FLOW_CTRL;
6690 }
6691 else {
6692 bp->autoneg &= ~AUTONEG_FLOW_CTRL;
6693 }
6694
Michael Chanc770a652005-08-25 15:38:39 -07006695 spin_lock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07006696
Michael Chan0d8a6572007-07-07 22:49:43 -07006697 bnx2_setup_phy(bp, bp->phy_port);
Michael Chanb6016b72005-05-26 13:03:09 -07006698
Michael Chanc770a652005-08-25 15:38:39 -07006699 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07006700
6701 return 0;
6702}
6703
6704static u32
6705bnx2_get_rx_csum(struct net_device *dev)
6706{
Michael Chan972ec0d2006-01-23 16:12:43 -08006707 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006708
6709 return bp->rx_csum;
6710}
6711
6712static int
6713bnx2_set_rx_csum(struct net_device *dev, u32 data)
6714{
Michael Chan972ec0d2006-01-23 16:12:43 -08006715 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006716
6717 bp->rx_csum = data;
6718 return 0;
6719}
6720
Michael Chanb11d6212006-06-29 12:31:21 -07006721static int
6722bnx2_set_tso(struct net_device *dev, u32 data)
6723{
Michael Chan4666f872007-05-03 13:22:28 -07006724 struct bnx2 *bp = netdev_priv(dev);
6725
6726 if (data) {
Michael Chanb11d6212006-06-29 12:31:21 -07006727 dev->features |= NETIF_F_TSO | NETIF_F_TSO_ECN;
Michael Chan4666f872007-05-03 13:22:28 -07006728 if (CHIP_NUM(bp) == CHIP_NUM_5709)
6729 dev->features |= NETIF_F_TSO6;
6730 } else
6731 dev->features &= ~(NETIF_F_TSO | NETIF_F_TSO6 |
6732 NETIF_F_TSO_ECN);
Michael Chanb11d6212006-06-29 12:31:21 -07006733 return 0;
6734}
6735
Michael Chancea94db2006-06-12 22:16:13 -07006736#define BNX2_NUM_STATS 46
Michael Chanb6016b72005-05-26 13:03:09 -07006737
Peter Hagervall14ab9b82005-08-10 14:18:16 -07006738static struct {
Michael Chanb6016b72005-05-26 13:03:09 -07006739 char string[ETH_GSTRING_LEN];
6740} bnx2_stats_str_arr[BNX2_NUM_STATS] = {
6741 { "rx_bytes" },
6742 { "rx_error_bytes" },
6743 { "tx_bytes" },
6744 { "tx_error_bytes" },
6745 { "rx_ucast_packets" },
6746 { "rx_mcast_packets" },
6747 { "rx_bcast_packets" },
6748 { "tx_ucast_packets" },
6749 { "tx_mcast_packets" },
6750 { "tx_bcast_packets" },
6751 { "tx_mac_errors" },
6752 { "tx_carrier_errors" },
6753 { "rx_crc_errors" },
6754 { "rx_align_errors" },
6755 { "tx_single_collisions" },
6756 { "tx_multi_collisions" },
6757 { "tx_deferred" },
6758 { "tx_excess_collisions" },
6759 { "tx_late_collisions" },
6760 { "tx_total_collisions" },
6761 { "rx_fragments" },
6762 { "rx_jabbers" },
6763 { "rx_undersize_packets" },
6764 { "rx_oversize_packets" },
6765 { "rx_64_byte_packets" },
6766 { "rx_65_to_127_byte_packets" },
6767 { "rx_128_to_255_byte_packets" },
6768 { "rx_256_to_511_byte_packets" },
6769 { "rx_512_to_1023_byte_packets" },
6770 { "rx_1024_to_1522_byte_packets" },
6771 { "rx_1523_to_9022_byte_packets" },
6772 { "tx_64_byte_packets" },
6773 { "tx_65_to_127_byte_packets" },
6774 { "tx_128_to_255_byte_packets" },
6775 { "tx_256_to_511_byte_packets" },
6776 { "tx_512_to_1023_byte_packets" },
6777 { "tx_1024_to_1522_byte_packets" },
6778 { "tx_1523_to_9022_byte_packets" },
6779 { "rx_xon_frames" },
6780 { "rx_xoff_frames" },
6781 { "tx_xon_frames" },
6782 { "tx_xoff_frames" },
6783 { "rx_mac_ctrl_frames" },
6784 { "rx_filtered_packets" },
6785 { "rx_discards" },
Michael Chancea94db2006-06-12 22:16:13 -07006786 { "rx_fw_discards" },
Michael Chanb6016b72005-05-26 13:03:09 -07006787};
6788
6789#define STATS_OFFSET32(offset_name) (offsetof(struct statistics_block, offset_name) / 4)
6790
Arjan van de Venf71e1302006-03-03 21:33:57 -05006791static const unsigned long bnx2_stats_offset_arr[BNX2_NUM_STATS] = {
Michael Chanb6016b72005-05-26 13:03:09 -07006792 STATS_OFFSET32(stat_IfHCInOctets_hi),
6793 STATS_OFFSET32(stat_IfHCInBadOctets_hi),
6794 STATS_OFFSET32(stat_IfHCOutOctets_hi),
6795 STATS_OFFSET32(stat_IfHCOutBadOctets_hi),
6796 STATS_OFFSET32(stat_IfHCInUcastPkts_hi),
6797 STATS_OFFSET32(stat_IfHCInMulticastPkts_hi),
6798 STATS_OFFSET32(stat_IfHCInBroadcastPkts_hi),
6799 STATS_OFFSET32(stat_IfHCOutUcastPkts_hi),
6800 STATS_OFFSET32(stat_IfHCOutMulticastPkts_hi),
6801 STATS_OFFSET32(stat_IfHCOutBroadcastPkts_hi),
6802 STATS_OFFSET32(stat_emac_tx_stat_dot3statsinternalmactransmiterrors),
Jeff Garzik6aa20a22006-09-13 13:24:59 -04006803 STATS_OFFSET32(stat_Dot3StatsCarrierSenseErrors),
6804 STATS_OFFSET32(stat_Dot3StatsFCSErrors),
6805 STATS_OFFSET32(stat_Dot3StatsAlignmentErrors),
6806 STATS_OFFSET32(stat_Dot3StatsSingleCollisionFrames),
6807 STATS_OFFSET32(stat_Dot3StatsMultipleCollisionFrames),
6808 STATS_OFFSET32(stat_Dot3StatsDeferredTransmissions),
6809 STATS_OFFSET32(stat_Dot3StatsExcessiveCollisions),
6810 STATS_OFFSET32(stat_Dot3StatsLateCollisions),
6811 STATS_OFFSET32(stat_EtherStatsCollisions),
6812 STATS_OFFSET32(stat_EtherStatsFragments),
6813 STATS_OFFSET32(stat_EtherStatsJabbers),
6814 STATS_OFFSET32(stat_EtherStatsUndersizePkts),
6815 STATS_OFFSET32(stat_EtherStatsOverrsizePkts),
6816 STATS_OFFSET32(stat_EtherStatsPktsRx64Octets),
6817 STATS_OFFSET32(stat_EtherStatsPktsRx65Octetsto127Octets),
6818 STATS_OFFSET32(stat_EtherStatsPktsRx128Octetsto255Octets),
6819 STATS_OFFSET32(stat_EtherStatsPktsRx256Octetsto511Octets),
6820 STATS_OFFSET32(stat_EtherStatsPktsRx512Octetsto1023Octets),
6821 STATS_OFFSET32(stat_EtherStatsPktsRx1024Octetsto1522Octets),
6822 STATS_OFFSET32(stat_EtherStatsPktsRx1523Octetsto9022Octets),
6823 STATS_OFFSET32(stat_EtherStatsPktsTx64Octets),
6824 STATS_OFFSET32(stat_EtherStatsPktsTx65Octetsto127Octets),
6825 STATS_OFFSET32(stat_EtherStatsPktsTx128Octetsto255Octets),
6826 STATS_OFFSET32(stat_EtherStatsPktsTx256Octetsto511Octets),
6827 STATS_OFFSET32(stat_EtherStatsPktsTx512Octetsto1023Octets),
6828 STATS_OFFSET32(stat_EtherStatsPktsTx1024Octetsto1522Octets),
6829 STATS_OFFSET32(stat_EtherStatsPktsTx1523Octetsto9022Octets),
6830 STATS_OFFSET32(stat_XonPauseFramesReceived),
6831 STATS_OFFSET32(stat_XoffPauseFramesReceived),
6832 STATS_OFFSET32(stat_OutXonSent),
6833 STATS_OFFSET32(stat_OutXoffSent),
6834 STATS_OFFSET32(stat_MacControlFramesReceived),
6835 STATS_OFFSET32(stat_IfInFramesL2FilterDiscards),
6836 STATS_OFFSET32(stat_IfInMBUFDiscards),
Michael Chancea94db2006-06-12 22:16:13 -07006837 STATS_OFFSET32(stat_FwRxDrop),
Michael Chanb6016b72005-05-26 13:03:09 -07006838};
6839
6840/* stat_IfHCInBadOctets and stat_Dot3StatsCarrierSenseErrors are
6841 * skipped because of errata.
Jeff Garzik6aa20a22006-09-13 13:24:59 -04006842 */
Peter Hagervall14ab9b82005-08-10 14:18:16 -07006843static u8 bnx2_5706_stats_len_arr[BNX2_NUM_STATS] = {
Michael Chanb6016b72005-05-26 13:03:09 -07006844 8,0,8,8,8,8,8,8,8,8,
6845 4,0,4,4,4,4,4,4,4,4,
6846 4,4,4,4,4,4,4,4,4,4,
6847 4,4,4,4,4,4,4,4,4,4,
Michael Chancea94db2006-06-12 22:16:13 -07006848 4,4,4,4,4,4,
Michael Chanb6016b72005-05-26 13:03:09 -07006849};
6850
Michael Chan5b0c76a2005-11-04 08:45:49 -08006851static u8 bnx2_5708_stats_len_arr[BNX2_NUM_STATS] = {
6852 8,0,8,8,8,8,8,8,8,8,
6853 4,4,4,4,4,4,4,4,4,4,
6854 4,4,4,4,4,4,4,4,4,4,
6855 4,4,4,4,4,4,4,4,4,4,
Michael Chancea94db2006-06-12 22:16:13 -07006856 4,4,4,4,4,4,
Michael Chan5b0c76a2005-11-04 08:45:49 -08006857};
6858
Michael Chanb6016b72005-05-26 13:03:09 -07006859#define BNX2_NUM_TESTS 6
6860
Peter Hagervall14ab9b82005-08-10 14:18:16 -07006861static struct {
Michael Chanb6016b72005-05-26 13:03:09 -07006862 char string[ETH_GSTRING_LEN];
6863} bnx2_tests_str_arr[BNX2_NUM_TESTS] = {
6864 { "register_test (offline)" },
6865 { "memory_test (offline)" },
6866 { "loopback_test (offline)" },
6867 { "nvram_test (online)" },
6868 { "interrupt_test (online)" },
6869 { "link_test (online)" },
6870};
6871
6872static int
Jeff Garzikb9f2c042007-10-03 18:07:32 -07006873bnx2_get_sset_count(struct net_device *dev, int sset)
Michael Chanb6016b72005-05-26 13:03:09 -07006874{
Jeff Garzikb9f2c042007-10-03 18:07:32 -07006875 switch (sset) {
6876 case ETH_SS_TEST:
6877 return BNX2_NUM_TESTS;
6878 case ETH_SS_STATS:
6879 return BNX2_NUM_STATS;
6880 default:
6881 return -EOPNOTSUPP;
6882 }
Michael Chanb6016b72005-05-26 13:03:09 -07006883}
6884
6885static void
6886bnx2_self_test(struct net_device *dev, struct ethtool_test *etest, u64 *buf)
6887{
Michael Chan972ec0d2006-01-23 16:12:43 -08006888 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006889
6890 memset(buf, 0, sizeof(u64) * BNX2_NUM_TESTS);
6891 if (etest->flags & ETH_TEST_FL_OFFLINE) {
Michael Chan80be4432006-11-19 14:07:28 -08006892 int i;
6893
Michael Chanb6016b72005-05-26 13:03:09 -07006894 bnx2_netif_stop(bp);
6895 bnx2_reset_chip(bp, BNX2_DRV_MSG_CODE_DIAG);
6896 bnx2_free_skbs(bp);
6897
6898 if (bnx2_test_registers(bp) != 0) {
6899 buf[0] = 1;
6900 etest->flags |= ETH_TEST_FL_FAILED;
6901 }
6902 if (bnx2_test_memory(bp) != 0) {
6903 buf[1] = 1;
6904 etest->flags |= ETH_TEST_FL_FAILED;
6905 }
Michael Chanbc5a0692006-01-23 16:13:22 -08006906 if ((buf[2] = bnx2_test_loopback(bp)) != 0)
Michael Chanb6016b72005-05-26 13:03:09 -07006907 etest->flags |= ETH_TEST_FL_FAILED;
Michael Chanb6016b72005-05-26 13:03:09 -07006908
6909 if (!netif_running(bp->dev)) {
6910 bnx2_reset_chip(bp, BNX2_DRV_MSG_CODE_RESET);
6911 }
6912 else {
Michael Chan9a120bc2008-05-16 22:17:45 -07006913 bnx2_init_nic(bp, 1);
Michael Chanb6016b72005-05-26 13:03:09 -07006914 bnx2_netif_start(bp);
6915 }
6916
6917 /* wait for link up */
Michael Chan80be4432006-11-19 14:07:28 -08006918 for (i = 0; i < 7; i++) {
6919 if (bp->link_up)
6920 break;
6921 msleep_interruptible(1000);
6922 }
Michael Chanb6016b72005-05-26 13:03:09 -07006923 }
6924
6925 if (bnx2_test_nvram(bp) != 0) {
6926 buf[3] = 1;
6927 etest->flags |= ETH_TEST_FL_FAILED;
6928 }
6929 if (bnx2_test_intr(bp) != 0) {
6930 buf[4] = 1;
6931 etest->flags |= ETH_TEST_FL_FAILED;
6932 }
6933
6934 if (bnx2_test_link(bp) != 0) {
6935 buf[5] = 1;
6936 etest->flags |= ETH_TEST_FL_FAILED;
6937
6938 }
6939}
6940
6941static void
6942bnx2_get_strings(struct net_device *dev, u32 stringset, u8 *buf)
6943{
6944 switch (stringset) {
6945 case ETH_SS_STATS:
6946 memcpy(buf, bnx2_stats_str_arr,
6947 sizeof(bnx2_stats_str_arr));
6948 break;
6949 case ETH_SS_TEST:
6950 memcpy(buf, bnx2_tests_str_arr,
6951 sizeof(bnx2_tests_str_arr));
6952 break;
6953 }
6954}
6955
Michael Chanb6016b72005-05-26 13:03:09 -07006956static void
6957bnx2_get_ethtool_stats(struct net_device *dev,
6958 struct ethtool_stats *stats, u64 *buf)
6959{
Michael Chan972ec0d2006-01-23 16:12:43 -08006960 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006961 int i;
6962 u32 *hw_stats = (u32 *) bp->stats_blk;
Peter Hagervall14ab9b82005-08-10 14:18:16 -07006963 u8 *stats_len_arr = NULL;
Michael Chanb6016b72005-05-26 13:03:09 -07006964
6965 if (hw_stats == NULL) {
6966 memset(buf, 0, sizeof(u64) * BNX2_NUM_STATS);
6967 return;
6968 }
6969
Michael Chan5b0c76a2005-11-04 08:45:49 -08006970 if ((CHIP_ID(bp) == CHIP_ID_5706_A0) ||
6971 (CHIP_ID(bp) == CHIP_ID_5706_A1) ||
6972 (CHIP_ID(bp) == CHIP_ID_5706_A2) ||
6973 (CHIP_ID(bp) == CHIP_ID_5708_A0))
Michael Chanb6016b72005-05-26 13:03:09 -07006974 stats_len_arr = bnx2_5706_stats_len_arr;
Michael Chan5b0c76a2005-11-04 08:45:49 -08006975 else
6976 stats_len_arr = bnx2_5708_stats_len_arr;
Michael Chanb6016b72005-05-26 13:03:09 -07006977
6978 for (i = 0; i < BNX2_NUM_STATS; i++) {
6979 if (stats_len_arr[i] == 0) {
6980 /* skip this counter */
6981 buf[i] = 0;
6982 continue;
6983 }
6984 if (stats_len_arr[i] == 4) {
6985 /* 4-byte counter */
6986 buf[i] = (u64)
6987 *(hw_stats + bnx2_stats_offset_arr[i]);
6988 continue;
6989 }
6990 /* 8-byte counter */
6991 buf[i] = (((u64) *(hw_stats +
6992 bnx2_stats_offset_arr[i])) << 32) +
6993 *(hw_stats + bnx2_stats_offset_arr[i] + 1);
6994 }
6995}
6996
6997static int
6998bnx2_phys_id(struct net_device *dev, u32 data)
6999{
Michael Chan972ec0d2006-01-23 16:12:43 -08007000 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007001 int i;
7002 u32 save;
7003
7004 if (data == 0)
7005 data = 2;
7006
7007 save = REG_RD(bp, BNX2_MISC_CFG);
7008 REG_WR(bp, BNX2_MISC_CFG, BNX2_MISC_CFG_LEDMODE_MAC);
7009
7010 for (i = 0; i < (data * 2); i++) {
7011 if ((i % 2) == 0) {
7012 REG_WR(bp, BNX2_EMAC_LED, BNX2_EMAC_LED_OVERRIDE);
7013 }
7014 else {
7015 REG_WR(bp, BNX2_EMAC_LED, BNX2_EMAC_LED_OVERRIDE |
7016 BNX2_EMAC_LED_1000MB_OVERRIDE |
7017 BNX2_EMAC_LED_100MB_OVERRIDE |
7018 BNX2_EMAC_LED_10MB_OVERRIDE |
7019 BNX2_EMAC_LED_TRAFFIC_OVERRIDE |
7020 BNX2_EMAC_LED_TRAFFIC);
7021 }
7022 msleep_interruptible(500);
7023 if (signal_pending(current))
7024 break;
7025 }
7026 REG_WR(bp, BNX2_EMAC_LED, 0);
7027 REG_WR(bp, BNX2_MISC_CFG, save);
7028 return 0;
7029}
7030
Michael Chan4666f872007-05-03 13:22:28 -07007031static int
7032bnx2_set_tx_csum(struct net_device *dev, u32 data)
7033{
7034 struct bnx2 *bp = netdev_priv(dev);
7035
7036 if (CHIP_NUM(bp) == CHIP_NUM_5709)
Michael Chan6460d942007-07-14 19:07:52 -07007037 return (ethtool_op_set_tx_ipv6_csum(dev, data));
Michael Chan4666f872007-05-03 13:22:28 -07007038 else
7039 return (ethtool_op_set_tx_csum(dev, data));
7040}
7041
Jeff Garzik7282d492006-09-13 14:30:00 -04007042static const struct ethtool_ops bnx2_ethtool_ops = {
Michael Chanb6016b72005-05-26 13:03:09 -07007043 .get_settings = bnx2_get_settings,
7044 .set_settings = bnx2_set_settings,
7045 .get_drvinfo = bnx2_get_drvinfo,
Michael Chan244ac4f2006-03-20 17:48:46 -08007046 .get_regs_len = bnx2_get_regs_len,
7047 .get_regs = bnx2_get_regs,
Michael Chanb6016b72005-05-26 13:03:09 -07007048 .get_wol = bnx2_get_wol,
7049 .set_wol = bnx2_set_wol,
7050 .nway_reset = bnx2_nway_reset,
7051 .get_link = ethtool_op_get_link,
7052 .get_eeprom_len = bnx2_get_eeprom_len,
7053 .get_eeprom = bnx2_get_eeprom,
7054 .set_eeprom = bnx2_set_eeprom,
7055 .get_coalesce = bnx2_get_coalesce,
7056 .set_coalesce = bnx2_set_coalesce,
7057 .get_ringparam = bnx2_get_ringparam,
7058 .set_ringparam = bnx2_set_ringparam,
7059 .get_pauseparam = bnx2_get_pauseparam,
7060 .set_pauseparam = bnx2_set_pauseparam,
7061 .get_rx_csum = bnx2_get_rx_csum,
7062 .set_rx_csum = bnx2_set_rx_csum,
Michael Chan4666f872007-05-03 13:22:28 -07007063 .set_tx_csum = bnx2_set_tx_csum,
Michael Chanb6016b72005-05-26 13:03:09 -07007064 .set_sg = ethtool_op_set_sg,
Michael Chanb11d6212006-06-29 12:31:21 -07007065 .set_tso = bnx2_set_tso,
Michael Chanb6016b72005-05-26 13:03:09 -07007066 .self_test = bnx2_self_test,
7067 .get_strings = bnx2_get_strings,
7068 .phys_id = bnx2_phys_id,
Michael Chanb6016b72005-05-26 13:03:09 -07007069 .get_ethtool_stats = bnx2_get_ethtool_stats,
Jeff Garzikb9f2c042007-10-03 18:07:32 -07007070 .get_sset_count = bnx2_get_sset_count,
Michael Chanb6016b72005-05-26 13:03:09 -07007071};
7072
7073/* Called with rtnl_lock */
7074static int
7075bnx2_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
7076{
Peter Hagervall14ab9b82005-08-10 14:18:16 -07007077 struct mii_ioctl_data *data = if_mii(ifr);
Michael Chan972ec0d2006-01-23 16:12:43 -08007078 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007079 int err;
7080
7081 switch(cmd) {
7082 case SIOCGMIIPHY:
7083 data->phy_id = bp->phy_addr;
7084
7085 /* fallthru */
7086 case SIOCGMIIREG: {
7087 u32 mii_regval;
7088
Michael Chan583c28e2008-01-21 19:51:35 -08007089 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
Michael Chan7b6b8342007-07-07 22:50:15 -07007090 return -EOPNOTSUPP;
7091
Michael Chandad3e452007-05-03 13:18:03 -07007092 if (!netif_running(dev))
7093 return -EAGAIN;
7094
Michael Chanc770a652005-08-25 15:38:39 -07007095 spin_lock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07007096 err = bnx2_read_phy(bp, data->reg_num & 0x1f, &mii_regval);
Michael Chanc770a652005-08-25 15:38:39 -07007097 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07007098
7099 data->val_out = mii_regval;
7100
7101 return err;
7102 }
7103
7104 case SIOCSMIIREG:
7105 if (!capable(CAP_NET_ADMIN))
7106 return -EPERM;
7107
Michael Chan583c28e2008-01-21 19:51:35 -08007108 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
Michael Chan7b6b8342007-07-07 22:50:15 -07007109 return -EOPNOTSUPP;
7110
Michael Chandad3e452007-05-03 13:18:03 -07007111 if (!netif_running(dev))
7112 return -EAGAIN;
7113
Michael Chanc770a652005-08-25 15:38:39 -07007114 spin_lock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07007115 err = bnx2_write_phy(bp, data->reg_num & 0x1f, data->val_in);
Michael Chanc770a652005-08-25 15:38:39 -07007116 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07007117
7118 return err;
7119
7120 default:
7121 /* do nothing */
7122 break;
7123 }
7124 return -EOPNOTSUPP;
7125}
7126
7127/* Called with rtnl_lock */
7128static int
7129bnx2_change_mac_addr(struct net_device *dev, void *p)
7130{
7131 struct sockaddr *addr = p;
Michael Chan972ec0d2006-01-23 16:12:43 -08007132 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007133
Michael Chan73eef4c2005-08-25 15:39:15 -07007134 if (!is_valid_ether_addr(addr->sa_data))
7135 return -EINVAL;
7136
Michael Chanb6016b72005-05-26 13:03:09 -07007137 memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
7138 if (netif_running(dev))
Benjamin Li5fcaed02008-07-14 22:39:52 -07007139 bnx2_set_mac_addr(bp, bp->dev->dev_addr, 0);
Michael Chanb6016b72005-05-26 13:03:09 -07007140
7141 return 0;
7142}
7143
7144/* Called with rtnl_lock */
7145static int
7146bnx2_change_mtu(struct net_device *dev, int new_mtu)
7147{
Michael Chan972ec0d2006-01-23 16:12:43 -08007148 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007149
7150 if (((new_mtu + ETH_HLEN) > MAX_ETHERNET_JUMBO_PACKET_SIZE) ||
7151 ((new_mtu + ETH_HLEN) < MIN_ETHERNET_PACKET_SIZE))
7152 return -EINVAL;
7153
7154 dev->mtu = new_mtu;
Michael Chan5d5d0012007-12-12 11:17:43 -08007155 return (bnx2_change_ring_size(bp, bp->rx_ring_size, bp->tx_ring_size));
Michael Chanb6016b72005-05-26 13:03:09 -07007156}
7157
7158#if defined(HAVE_POLL_CONTROLLER) || defined(CONFIG_NET_POLL_CONTROLLER)
7159static void
7160poll_bnx2(struct net_device *dev)
7161{
Michael Chan972ec0d2006-01-23 16:12:43 -08007162 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007163
7164 disable_irq(bp->pdev->irq);
David Howells7d12e782006-10-05 14:55:46 +01007165 bnx2_interrupt(bp->pdev->irq, dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007166 enable_irq(bp->pdev->irq);
7167}
7168#endif
7169
Michael Chan253c8b72007-01-08 19:56:01 -08007170static void __devinit
7171bnx2_get_5709_media(struct bnx2 *bp)
7172{
7173 u32 val = REG_RD(bp, BNX2_MISC_DUAL_MEDIA_CTRL);
7174 u32 bond_id = val & BNX2_MISC_DUAL_MEDIA_CTRL_BOND_ID;
7175 u32 strap;
7176
7177 if (bond_id == BNX2_MISC_DUAL_MEDIA_CTRL_BOND_ID_C)
7178 return;
7179 else if (bond_id == BNX2_MISC_DUAL_MEDIA_CTRL_BOND_ID_S) {
Michael Chan583c28e2008-01-21 19:51:35 -08007180 bp->phy_flags |= BNX2_PHY_FLAG_SERDES;
Michael Chan253c8b72007-01-08 19:56:01 -08007181 return;
7182 }
7183
7184 if (val & BNX2_MISC_DUAL_MEDIA_CTRL_STRAP_OVERRIDE)
7185 strap = (val & BNX2_MISC_DUAL_MEDIA_CTRL_PHY_CTRL) >> 21;
7186 else
7187 strap = (val & BNX2_MISC_DUAL_MEDIA_CTRL_PHY_CTRL_STRAP) >> 8;
7188
7189 if (PCI_FUNC(bp->pdev->devfn) == 0) {
7190 switch (strap) {
7191 case 0x4:
7192 case 0x5:
7193 case 0x6:
Michael Chan583c28e2008-01-21 19:51:35 -08007194 bp->phy_flags |= BNX2_PHY_FLAG_SERDES;
Michael Chan253c8b72007-01-08 19:56:01 -08007195 return;
7196 }
7197 } else {
7198 switch (strap) {
7199 case 0x1:
7200 case 0x2:
7201 case 0x4:
Michael Chan583c28e2008-01-21 19:51:35 -08007202 bp->phy_flags |= BNX2_PHY_FLAG_SERDES;
Michael Chan253c8b72007-01-08 19:56:01 -08007203 return;
7204 }
7205 }
7206}
7207
Michael Chan883e5152007-05-03 13:25:11 -07007208static void __devinit
7209bnx2_get_pci_speed(struct bnx2 *bp)
7210{
7211 u32 reg;
7212
7213 reg = REG_RD(bp, BNX2_PCICFG_MISC_STATUS);
7214 if (reg & BNX2_PCICFG_MISC_STATUS_PCIX_DET) {
7215 u32 clkreg;
7216
David S. Millerf86e82f2008-01-21 17:15:40 -08007217 bp->flags |= BNX2_FLAG_PCIX;
Michael Chan883e5152007-05-03 13:25:11 -07007218
7219 clkreg = REG_RD(bp, BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS);
7220
7221 clkreg &= BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET;
7222 switch (clkreg) {
7223 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_133MHZ:
7224 bp->bus_speed_mhz = 133;
7225 break;
7226
7227 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_95MHZ:
7228 bp->bus_speed_mhz = 100;
7229 break;
7230
7231 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_66MHZ:
7232 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_80MHZ:
7233 bp->bus_speed_mhz = 66;
7234 break;
7235
7236 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_48MHZ:
7237 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_55MHZ:
7238 bp->bus_speed_mhz = 50;
7239 break;
7240
7241 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_LOW:
7242 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_32MHZ:
7243 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_38MHZ:
7244 bp->bus_speed_mhz = 33;
7245 break;
7246 }
7247 }
7248 else {
7249 if (reg & BNX2_PCICFG_MISC_STATUS_M66EN)
7250 bp->bus_speed_mhz = 66;
7251 else
7252 bp->bus_speed_mhz = 33;
7253 }
7254
7255 if (reg & BNX2_PCICFG_MISC_STATUS_32BIT_DET)
David S. Millerf86e82f2008-01-21 17:15:40 -08007256 bp->flags |= BNX2_FLAG_PCI_32BIT;
Michael Chan883e5152007-05-03 13:25:11 -07007257
7258}
7259
Michael Chanb6016b72005-05-26 13:03:09 -07007260static int __devinit
7261bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
7262{
7263 struct bnx2 *bp;
7264 unsigned long mem_len;
Michael Chan58fc2ea2007-07-07 22:52:02 -07007265 int rc, i, j;
Michael Chanb6016b72005-05-26 13:03:09 -07007266 u32 reg;
Michael Chan40453c82007-05-03 13:19:18 -07007267 u64 dma_mask, persist_dma_mask;
Michael Chanb6016b72005-05-26 13:03:09 -07007268
Michael Chanb6016b72005-05-26 13:03:09 -07007269 SET_NETDEV_DEV(dev, &pdev->dev);
Michael Chan972ec0d2006-01-23 16:12:43 -08007270 bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007271
7272 bp->flags = 0;
7273 bp->phy_flags = 0;
7274
7275 /* enable device (incl. PCI PM wakeup), and bus-mastering */
7276 rc = pci_enable_device(pdev);
7277 if (rc) {
Joe Perches898eb712007-10-18 03:06:30 -07007278 dev_err(&pdev->dev, "Cannot enable PCI device, aborting.\n");
Michael Chanb6016b72005-05-26 13:03:09 -07007279 goto err_out;
7280 }
7281
7282 if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) {
Jeff Garzik9b91cf92006-06-27 11:39:50 -04007283 dev_err(&pdev->dev,
Jeff Garzik2e8a5382006-06-27 10:47:51 -04007284 "Cannot find PCI device base address, aborting.\n");
Michael Chanb6016b72005-05-26 13:03:09 -07007285 rc = -ENODEV;
7286 goto err_out_disable;
7287 }
7288
7289 rc = pci_request_regions(pdev, DRV_MODULE_NAME);
7290 if (rc) {
Jeff Garzik9b91cf92006-06-27 11:39:50 -04007291 dev_err(&pdev->dev, "Cannot obtain PCI resources, aborting.\n");
Michael Chanb6016b72005-05-26 13:03:09 -07007292 goto err_out_disable;
7293 }
7294
7295 pci_set_master(pdev);
Wendy Xiong6ff2da42008-05-16 22:18:21 -07007296 pci_save_state(pdev);
Michael Chanb6016b72005-05-26 13:03:09 -07007297
7298 bp->pm_cap = pci_find_capability(pdev, PCI_CAP_ID_PM);
7299 if (bp->pm_cap == 0) {
Jeff Garzik9b91cf92006-06-27 11:39:50 -04007300 dev_err(&pdev->dev,
Jeff Garzik2e8a5382006-06-27 10:47:51 -04007301 "Cannot find power management capability, aborting.\n");
Michael Chanb6016b72005-05-26 13:03:09 -07007302 rc = -EIO;
7303 goto err_out_release;
7304 }
7305
Michael Chanb6016b72005-05-26 13:03:09 -07007306 bp->dev = dev;
7307 bp->pdev = pdev;
7308
7309 spin_lock_init(&bp->phy_lock);
Michael Chan1b8227c2007-05-03 13:24:05 -07007310 spin_lock_init(&bp->indirect_lock);
David Howellsc4028952006-11-22 14:57:56 +00007311 INIT_WORK(&bp->reset_task, bnx2_reset_task);
Michael Chanb6016b72005-05-26 13:03:09 -07007312
7313 dev->base_addr = dev->mem_start = pci_resource_start(pdev, 0);
Benjamin Li706bf242008-07-18 17:55:11 -07007314 mem_len = MB_GET_CID_ADDR(TX_TSS_CID + TX_MAX_TSS_RINGS);
Michael Chanb6016b72005-05-26 13:03:09 -07007315 dev->mem_end = dev->mem_start + mem_len;
7316 dev->irq = pdev->irq;
7317
7318 bp->regview = ioremap_nocache(dev->base_addr, mem_len);
7319
7320 if (!bp->regview) {
Jeff Garzik9b91cf92006-06-27 11:39:50 -04007321 dev_err(&pdev->dev, "Cannot map register space, aborting.\n");
Michael Chanb6016b72005-05-26 13:03:09 -07007322 rc = -ENOMEM;
7323 goto err_out_release;
7324 }
7325
7326 /* Configure byte swap and enable write to the reg_window registers.
7327 * Rely on CPU to do target byte swapping on big endian systems
7328 * The chip's target access swapping will not swap all accesses
7329 */
7330 pci_write_config_dword(bp->pdev, BNX2_PCICFG_MISC_CONFIG,
7331 BNX2_PCICFG_MISC_CONFIG_REG_WINDOW_ENA |
7332 BNX2_PCICFG_MISC_CONFIG_TARGET_MB_WORD_SWAP);
7333
Pavel Machek829ca9a2005-09-03 15:56:56 -07007334 bnx2_set_power_state(bp, PCI_D0);
Michael Chanb6016b72005-05-26 13:03:09 -07007335
7336 bp->chip_id = REG_RD(bp, BNX2_MISC_ID);
7337
Michael Chan883e5152007-05-03 13:25:11 -07007338 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
7339 if (pci_find_capability(pdev, PCI_CAP_ID_EXP) == 0) {
7340 dev_err(&pdev->dev,
7341 "Cannot find PCIE capability, aborting.\n");
7342 rc = -EIO;
7343 goto err_out_unmap;
7344 }
David S. Millerf86e82f2008-01-21 17:15:40 -08007345 bp->flags |= BNX2_FLAG_PCIE;
Michael Chan2dd201d2008-01-21 17:06:09 -08007346 if (CHIP_REV(bp) == CHIP_REV_Ax)
David S. Millerf86e82f2008-01-21 17:15:40 -08007347 bp->flags |= BNX2_FLAG_JUMBO_BROKEN;
Michael Chan883e5152007-05-03 13:25:11 -07007348 } else {
Michael Chan59b47d82006-11-19 14:10:45 -08007349 bp->pcix_cap = pci_find_capability(pdev, PCI_CAP_ID_PCIX);
7350 if (bp->pcix_cap == 0) {
7351 dev_err(&pdev->dev,
7352 "Cannot find PCIX capability, aborting.\n");
7353 rc = -EIO;
7354 goto err_out_unmap;
7355 }
7356 }
7357
Michael Chanb4b36042007-12-20 19:59:30 -08007358 if (CHIP_NUM(bp) == CHIP_NUM_5709 && CHIP_REV(bp) != CHIP_REV_Ax) {
7359 if (pci_find_capability(pdev, PCI_CAP_ID_MSIX))
David S. Millerf86e82f2008-01-21 17:15:40 -08007360 bp->flags |= BNX2_FLAG_MSIX_CAP;
Michael Chanb4b36042007-12-20 19:59:30 -08007361 }
7362
Michael Chan8e6a72c2007-05-03 13:24:48 -07007363 if (CHIP_ID(bp) != CHIP_ID_5706_A0 && CHIP_ID(bp) != CHIP_ID_5706_A1) {
7364 if (pci_find_capability(pdev, PCI_CAP_ID_MSI))
David S. Millerf86e82f2008-01-21 17:15:40 -08007365 bp->flags |= BNX2_FLAG_MSI_CAP;
Michael Chan8e6a72c2007-05-03 13:24:48 -07007366 }
7367
Michael Chan40453c82007-05-03 13:19:18 -07007368 /* 5708 cannot support DMA addresses > 40-bit. */
7369 if (CHIP_NUM(bp) == CHIP_NUM_5708)
7370 persist_dma_mask = dma_mask = DMA_40BIT_MASK;
7371 else
7372 persist_dma_mask = dma_mask = DMA_64BIT_MASK;
7373
7374 /* Configure DMA attributes. */
7375 if (pci_set_dma_mask(pdev, dma_mask) == 0) {
7376 dev->features |= NETIF_F_HIGHDMA;
7377 rc = pci_set_consistent_dma_mask(pdev, persist_dma_mask);
7378 if (rc) {
7379 dev_err(&pdev->dev,
7380 "pci_set_consistent_dma_mask failed, aborting.\n");
7381 goto err_out_unmap;
7382 }
7383 } else if ((rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK)) != 0) {
7384 dev_err(&pdev->dev, "System does not support DMA, aborting.\n");
7385 goto err_out_unmap;
7386 }
7387
David S. Millerf86e82f2008-01-21 17:15:40 -08007388 if (!(bp->flags & BNX2_FLAG_PCIE))
Michael Chan883e5152007-05-03 13:25:11 -07007389 bnx2_get_pci_speed(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07007390
7391 /* 5706A0 may falsely detect SERR and PERR. */
7392 if (CHIP_ID(bp) == CHIP_ID_5706_A0) {
7393 reg = REG_RD(bp, PCI_COMMAND);
7394 reg &= ~(PCI_COMMAND_SERR | PCI_COMMAND_PARITY);
7395 REG_WR(bp, PCI_COMMAND, reg);
7396 }
7397 else if ((CHIP_ID(bp) == CHIP_ID_5706_A1) &&
David S. Millerf86e82f2008-01-21 17:15:40 -08007398 !(bp->flags & BNX2_FLAG_PCIX)) {
Michael Chanb6016b72005-05-26 13:03:09 -07007399
Jeff Garzik9b91cf92006-06-27 11:39:50 -04007400 dev_err(&pdev->dev,
Jeff Garzik2e8a5382006-06-27 10:47:51 -04007401 "5706 A1 can only be used in a PCIX bus, aborting.\n");
Michael Chanb6016b72005-05-26 13:03:09 -07007402 goto err_out_unmap;
7403 }
7404
7405 bnx2_init_nvram(bp);
7406
Michael Chan2726d6e2008-01-29 21:35:05 -08007407 reg = bnx2_reg_rd_ind(bp, BNX2_SHM_HDR_SIGNATURE);
Michael Chane3648b32005-11-04 08:51:21 -08007408
7409 if ((reg & BNX2_SHM_HDR_SIGNATURE_SIG_MASK) ==
Michael Chan24cb2302007-01-25 15:49:56 -08007410 BNX2_SHM_HDR_SIGNATURE_SIG) {
7411 u32 off = PCI_FUNC(pdev->devfn) << 2;
7412
Michael Chan2726d6e2008-01-29 21:35:05 -08007413 bp->shmem_base = bnx2_reg_rd_ind(bp, BNX2_SHM_HDR_ADDR_0 + off);
Michael Chan24cb2302007-01-25 15:49:56 -08007414 } else
Michael Chane3648b32005-11-04 08:51:21 -08007415 bp->shmem_base = HOST_VIEW_SHMEM_BASE;
7416
Michael Chanb6016b72005-05-26 13:03:09 -07007417 /* Get the permanent MAC address. First we need to make sure the
7418 * firmware is actually running.
7419 */
Michael Chan2726d6e2008-01-29 21:35:05 -08007420 reg = bnx2_shmem_rd(bp, BNX2_DEV_INFO_SIGNATURE);
Michael Chanb6016b72005-05-26 13:03:09 -07007421
7422 if ((reg & BNX2_DEV_INFO_SIGNATURE_MAGIC_MASK) !=
7423 BNX2_DEV_INFO_SIGNATURE_MAGIC) {
Jeff Garzik9b91cf92006-06-27 11:39:50 -04007424 dev_err(&pdev->dev, "Firmware not running, aborting.\n");
Michael Chanb6016b72005-05-26 13:03:09 -07007425 rc = -ENODEV;
7426 goto err_out_unmap;
7427 }
7428
Michael Chan2726d6e2008-01-29 21:35:05 -08007429 reg = bnx2_shmem_rd(bp, BNX2_DEV_INFO_BC_REV);
Michael Chan58fc2ea2007-07-07 22:52:02 -07007430 for (i = 0, j = 0; i < 3; i++) {
7431 u8 num, k, skip0;
7432
7433 num = (u8) (reg >> (24 - (i * 8)));
7434 for (k = 100, skip0 = 1; k >= 1; num %= k, k /= 10) {
7435 if (num >= k || !skip0 || k == 1) {
7436 bp->fw_version[j++] = (num / k) + '0';
7437 skip0 = 0;
7438 }
7439 }
7440 if (i != 2)
7441 bp->fw_version[j++] = '.';
7442 }
Michael Chan2726d6e2008-01-29 21:35:05 -08007443 reg = bnx2_shmem_rd(bp, BNX2_PORT_FEATURE);
Michael Chan846f5c62007-10-10 16:16:51 -07007444 if (reg & BNX2_PORT_FEATURE_WOL_ENABLED)
7445 bp->wol = 1;
7446
7447 if (reg & BNX2_PORT_FEATURE_ASF_ENABLED) {
David S. Millerf86e82f2008-01-21 17:15:40 -08007448 bp->flags |= BNX2_FLAG_ASF_ENABLE;
Michael Chanc2d3db82007-07-16 18:26:43 -07007449
7450 for (i = 0; i < 30; i++) {
Michael Chan2726d6e2008-01-29 21:35:05 -08007451 reg = bnx2_shmem_rd(bp, BNX2_BC_STATE_CONDITION);
Michael Chanc2d3db82007-07-16 18:26:43 -07007452 if (reg & BNX2_CONDITION_MFW_RUN_MASK)
7453 break;
7454 msleep(10);
7455 }
7456 }
Michael Chan2726d6e2008-01-29 21:35:05 -08007457 reg = bnx2_shmem_rd(bp, BNX2_BC_STATE_CONDITION);
Michael Chan58fc2ea2007-07-07 22:52:02 -07007458 reg &= BNX2_CONDITION_MFW_RUN_MASK;
7459 if (reg != BNX2_CONDITION_MFW_RUN_UNKNOWN &&
7460 reg != BNX2_CONDITION_MFW_RUN_NONE) {
7461 int i;
Michael Chan2726d6e2008-01-29 21:35:05 -08007462 u32 addr = bnx2_shmem_rd(bp, BNX2_MFW_VER_PTR);
Michael Chan58fc2ea2007-07-07 22:52:02 -07007463
7464 bp->fw_version[j++] = ' ';
7465 for (i = 0; i < 3; i++) {
Michael Chan2726d6e2008-01-29 21:35:05 -08007466 reg = bnx2_reg_rd_ind(bp, addr + i * 4);
Michael Chan58fc2ea2007-07-07 22:52:02 -07007467 reg = swab32(reg);
7468 memcpy(&bp->fw_version[j], &reg, 4);
7469 j += 4;
7470 }
7471 }
Michael Chanb6016b72005-05-26 13:03:09 -07007472
Michael Chan2726d6e2008-01-29 21:35:05 -08007473 reg = bnx2_shmem_rd(bp, BNX2_PORT_HW_CFG_MAC_UPPER);
Michael Chanb6016b72005-05-26 13:03:09 -07007474 bp->mac_addr[0] = (u8) (reg >> 8);
7475 bp->mac_addr[1] = (u8) reg;
7476
Michael Chan2726d6e2008-01-29 21:35:05 -08007477 reg = bnx2_shmem_rd(bp, BNX2_PORT_HW_CFG_MAC_LOWER);
Michael Chanb6016b72005-05-26 13:03:09 -07007478 bp->mac_addr[2] = (u8) (reg >> 24);
7479 bp->mac_addr[3] = (u8) (reg >> 16);
7480 bp->mac_addr[4] = (u8) (reg >> 8);
7481 bp->mac_addr[5] = (u8) reg;
7482
7483 bp->tx_ring_size = MAX_TX_DESC_CNT;
Michael Chan932f3772006-08-15 01:39:36 -07007484 bnx2_set_rx_ring_size(bp, 255);
Michael Chanb6016b72005-05-26 13:03:09 -07007485
7486 bp->rx_csum = 1;
7487
Michael Chanb6016b72005-05-26 13:03:09 -07007488 bp->tx_quick_cons_trip_int = 20;
7489 bp->tx_quick_cons_trip = 20;
7490 bp->tx_ticks_int = 80;
7491 bp->tx_ticks = 80;
Jeff Garzik6aa20a22006-09-13 13:24:59 -04007492
Michael Chanb6016b72005-05-26 13:03:09 -07007493 bp->rx_quick_cons_trip_int = 6;
7494 bp->rx_quick_cons_trip = 6;
7495 bp->rx_ticks_int = 18;
7496 bp->rx_ticks = 18;
7497
Michael Chan7ea69202007-07-16 18:27:10 -07007498 bp->stats_ticks = USEC_PER_SEC & BNX2_HC_STATS_TICKS_HC_STAT_TICKS;
Michael Chanb6016b72005-05-26 13:03:09 -07007499
7500 bp->timer_interval = HZ;
Michael Chancd339a02005-08-25 15:35:24 -07007501 bp->current_interval = HZ;
Michael Chanb6016b72005-05-26 13:03:09 -07007502
Michael Chan5b0c76a2005-11-04 08:45:49 -08007503 bp->phy_addr = 1;
7504
Michael Chanb6016b72005-05-26 13:03:09 -07007505 /* Disable WOL support if we are running on a SERDES chip. */
Michael Chan253c8b72007-01-08 19:56:01 -08007506 if (CHIP_NUM(bp) == CHIP_NUM_5709)
7507 bnx2_get_5709_media(bp);
7508 else if (CHIP_BOND_ID(bp) & CHIP_BOND_ID_SERDES_BIT)
Michael Chan583c28e2008-01-21 19:51:35 -08007509 bp->phy_flags |= BNX2_PHY_FLAG_SERDES;
Michael Chanbac0dff2006-11-19 14:15:05 -08007510
Michael Chan0d8a6572007-07-07 22:49:43 -07007511 bp->phy_port = PORT_TP;
Michael Chan583c28e2008-01-21 19:51:35 -08007512 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Michael Chan0d8a6572007-07-07 22:49:43 -07007513 bp->phy_port = PORT_FIBRE;
Michael Chan2726d6e2008-01-29 21:35:05 -08007514 reg = bnx2_shmem_rd(bp, BNX2_SHARED_HW_CFG_CONFIG);
Michael Chan846f5c62007-10-10 16:16:51 -07007515 if (!(reg & BNX2_SHARED_HW_CFG_GIG_LINK_ON_VAUX)) {
David S. Millerf86e82f2008-01-21 17:15:40 -08007516 bp->flags |= BNX2_FLAG_NO_WOL;
Michael Chan846f5c62007-10-10 16:16:51 -07007517 bp->wol = 0;
7518 }
Michael Chan38ea3682008-02-23 19:48:57 -08007519 if (CHIP_NUM(bp) == CHIP_NUM_5706) {
7520 /* Don't do parallel detect on this board because of
7521 * some board problems. The link will not go down
7522 * if we do parallel detect.
7523 */
7524 if (pdev->subsystem_vendor == PCI_VENDOR_ID_HP &&
7525 pdev->subsystem_device == 0x310c)
7526 bp->phy_flags |= BNX2_PHY_FLAG_NO_PARALLEL;
7527 } else {
Michael Chan5b0c76a2005-11-04 08:45:49 -08007528 bp->phy_addr = 2;
Michael Chan5b0c76a2005-11-04 08:45:49 -08007529 if (reg & BNX2_SHARED_HW_CFG_PHY_2_5G)
Michael Chan583c28e2008-01-21 19:51:35 -08007530 bp->phy_flags |= BNX2_PHY_FLAG_2_5G_CAPABLE;
Michael Chan5b0c76a2005-11-04 08:45:49 -08007531 }
Michael Chan261dd5c2007-01-08 19:55:46 -08007532 } else if (CHIP_NUM(bp) == CHIP_NUM_5706 ||
7533 CHIP_NUM(bp) == CHIP_NUM_5708)
Michael Chan583c28e2008-01-21 19:51:35 -08007534 bp->phy_flags |= BNX2_PHY_FLAG_CRC_FIX;
Michael Chanfb0c18b2007-12-10 17:18:23 -08007535 else if (CHIP_NUM(bp) == CHIP_NUM_5709 &&
7536 (CHIP_REV(bp) == CHIP_REV_Ax ||
7537 CHIP_REV(bp) == CHIP_REV_Bx))
Michael Chan583c28e2008-01-21 19:51:35 -08007538 bp->phy_flags |= BNX2_PHY_FLAG_DIS_EARLY_DAC;
Michael Chanb6016b72005-05-26 13:03:09 -07007539
Michael Chan7c62e832008-07-14 22:39:03 -07007540 bnx2_init_fw_cap(bp);
7541
Michael Chan16088272006-06-12 22:16:43 -07007542 if ((CHIP_ID(bp) == CHIP_ID_5708_A0) ||
7543 (CHIP_ID(bp) == CHIP_ID_5708_B0) ||
Michael Chan846f5c62007-10-10 16:16:51 -07007544 (CHIP_ID(bp) == CHIP_ID_5708_B1)) {
David S. Millerf86e82f2008-01-21 17:15:40 -08007545 bp->flags |= BNX2_FLAG_NO_WOL;
Michael Chan846f5c62007-10-10 16:16:51 -07007546 bp->wol = 0;
7547 }
Michael Chandda1e392006-01-23 16:08:14 -08007548
Michael Chanb6016b72005-05-26 13:03:09 -07007549 if (CHIP_ID(bp) == CHIP_ID_5706_A0) {
7550 bp->tx_quick_cons_trip_int =
7551 bp->tx_quick_cons_trip;
7552 bp->tx_ticks_int = bp->tx_ticks;
7553 bp->rx_quick_cons_trip_int =
7554 bp->rx_quick_cons_trip;
7555 bp->rx_ticks_int = bp->rx_ticks;
7556 bp->comp_prod_trip_int = bp->comp_prod_trip;
7557 bp->com_ticks_int = bp->com_ticks;
7558 bp->cmd_ticks_int = bp->cmd_ticks;
7559 }
7560
Michael Chanf9317a42006-09-29 17:06:23 -07007561 /* Disable MSI on 5706 if AMD 8132 bridge is found.
7562 *
7563 * MSI is defined to be 32-bit write. The 5706 does 64-bit MSI writes
7564 * with byte enables disabled on the unused 32-bit word. This is legal
7565 * but causes problems on the AMD 8132 which will eventually stop
7566 * responding after a while.
7567 *
7568 * AMD believes this incompatibility is unique to the 5706, and
Michael Ellerman88187df2007-01-25 19:34:07 +11007569 * prefers to locally disable MSI rather than globally disabling it.
Michael Chanf9317a42006-09-29 17:06:23 -07007570 */
7571 if (CHIP_NUM(bp) == CHIP_NUM_5706 && disable_msi == 0) {
7572 struct pci_dev *amd_8132 = NULL;
7573
7574 while ((amd_8132 = pci_get_device(PCI_VENDOR_ID_AMD,
7575 PCI_DEVICE_ID_AMD_8132_BRIDGE,
7576 amd_8132))) {
Michael Chanf9317a42006-09-29 17:06:23 -07007577
Auke Kok44c10132007-06-08 15:46:36 -07007578 if (amd_8132->revision >= 0x10 &&
7579 amd_8132->revision <= 0x13) {
Michael Chanf9317a42006-09-29 17:06:23 -07007580 disable_msi = 1;
7581 pci_dev_put(amd_8132);
7582 break;
7583 }
7584 }
7585 }
7586
Michael Chandeaf3912007-07-07 22:48:00 -07007587 bnx2_set_default_link(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07007588 bp->req_flow_ctrl = FLOW_CTRL_RX | FLOW_CTRL_TX;
7589
Michael Chancd339a02005-08-25 15:35:24 -07007590 init_timer(&bp->timer);
7591 bp->timer.expires = RUN_AT(bp->timer_interval);
7592 bp->timer.data = (unsigned long) bp;
7593 bp->timer.function = bnx2_timer;
7594
Michael Chanb6016b72005-05-26 13:03:09 -07007595 return 0;
7596
7597err_out_unmap:
7598 if (bp->regview) {
7599 iounmap(bp->regview);
Michael Chan73eef4c2005-08-25 15:39:15 -07007600 bp->regview = NULL;
Michael Chanb6016b72005-05-26 13:03:09 -07007601 }
7602
7603err_out_release:
7604 pci_release_regions(pdev);
7605
7606err_out_disable:
7607 pci_disable_device(pdev);
7608 pci_set_drvdata(pdev, NULL);
7609
7610err_out:
7611 return rc;
7612}
7613
Michael Chan883e5152007-05-03 13:25:11 -07007614static char * __devinit
7615bnx2_bus_string(struct bnx2 *bp, char *str)
7616{
7617 char *s = str;
7618
David S. Millerf86e82f2008-01-21 17:15:40 -08007619 if (bp->flags & BNX2_FLAG_PCIE) {
Michael Chan883e5152007-05-03 13:25:11 -07007620 s += sprintf(s, "PCI Express");
7621 } else {
7622 s += sprintf(s, "PCI");
David S. Millerf86e82f2008-01-21 17:15:40 -08007623 if (bp->flags & BNX2_FLAG_PCIX)
Michael Chan883e5152007-05-03 13:25:11 -07007624 s += sprintf(s, "-X");
David S. Millerf86e82f2008-01-21 17:15:40 -08007625 if (bp->flags & BNX2_FLAG_PCI_32BIT)
Michael Chan883e5152007-05-03 13:25:11 -07007626 s += sprintf(s, " 32-bit");
7627 else
7628 s += sprintf(s, " 64-bit");
7629 s += sprintf(s, " %dMHz", bp->bus_speed_mhz);
7630 }
7631 return str;
7632}
7633
Michael Chan2ba582b2007-12-21 15:04:49 -08007634static void __devinit
Michael Chan35efa7c2007-12-20 19:56:37 -08007635bnx2_init_napi(struct bnx2 *bp)
7636{
Michael Chanb4b36042007-12-20 19:59:30 -08007637 int i;
Michael Chan35efa7c2007-12-20 19:56:37 -08007638
Michael Chanb4b36042007-12-20 19:59:30 -08007639 for (i = 0; i < BNX2_MAX_MSIX_VEC; i++) {
Michael Chan35e90102008-06-19 16:37:42 -07007640 struct bnx2_napi *bnapi = &bp->bnx2_napi[i];
7641 int (*poll)(struct napi_struct *, int);
7642
7643 if (i == 0)
7644 poll = bnx2_poll;
7645 else
Michael Chanf0ea2e62008-06-19 16:41:57 -07007646 poll = bnx2_poll_msix;
Michael Chan35e90102008-06-19 16:37:42 -07007647
7648 netif_napi_add(bp->dev, &bp->bnx2_napi[i].napi, poll, 64);
Michael Chanb4b36042007-12-20 19:59:30 -08007649 bnapi->bp = bp;
7650 }
Michael Chan35efa7c2007-12-20 19:56:37 -08007651}
7652
7653static int __devinit
Michael Chanb6016b72005-05-26 13:03:09 -07007654bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
7655{
7656 static int version_printed = 0;
7657 struct net_device *dev = NULL;
7658 struct bnx2 *bp;
Joe Perches0795af52007-10-03 17:59:30 -07007659 int rc;
Michael Chan883e5152007-05-03 13:25:11 -07007660 char str[40];
Joe Perches0795af52007-10-03 17:59:30 -07007661 DECLARE_MAC_BUF(mac);
Michael Chanb6016b72005-05-26 13:03:09 -07007662
7663 if (version_printed++ == 0)
7664 printk(KERN_INFO "%s", version);
7665
7666 /* dev zeroed in init_etherdev */
Benjamin Li706bf242008-07-18 17:55:11 -07007667 dev = alloc_etherdev_mq(sizeof(*bp), TX_MAX_RINGS);
Michael Chanb6016b72005-05-26 13:03:09 -07007668
7669 if (!dev)
7670 return -ENOMEM;
7671
7672 rc = bnx2_init_board(pdev, dev);
7673 if (rc < 0) {
7674 free_netdev(dev);
7675 return rc;
7676 }
7677
7678 dev->open = bnx2_open;
7679 dev->hard_start_xmit = bnx2_start_xmit;
7680 dev->stop = bnx2_close;
7681 dev->get_stats = bnx2_get_stats;
Benjamin Li5fcaed02008-07-14 22:39:52 -07007682 dev->set_rx_mode = bnx2_set_rx_mode;
Michael Chanb6016b72005-05-26 13:03:09 -07007683 dev->do_ioctl = bnx2_ioctl;
7684 dev->set_mac_address = bnx2_change_mac_addr;
7685 dev->change_mtu = bnx2_change_mtu;
7686 dev->tx_timeout = bnx2_tx_timeout;
7687 dev->watchdog_timeo = TX_TIMEOUT;
7688#ifdef BCM_VLAN
7689 dev->vlan_rx_register = bnx2_vlan_rx_register;
Michael Chanb6016b72005-05-26 13:03:09 -07007690#endif
Michael Chanb6016b72005-05-26 13:03:09 -07007691 dev->ethtool_ops = &bnx2_ethtool_ops;
Michael Chanb6016b72005-05-26 13:03:09 -07007692
Michael Chan972ec0d2006-01-23 16:12:43 -08007693 bp = netdev_priv(dev);
Michael Chan35efa7c2007-12-20 19:56:37 -08007694 bnx2_init_napi(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07007695
7696#if defined(HAVE_POLL_CONTROLLER) || defined(CONFIG_NET_POLL_CONTROLLER)
7697 dev->poll_controller = poll_bnx2;
7698#endif
7699
Michael Chan1b2f9222007-05-03 13:20:19 -07007700 pci_set_drvdata(pdev, dev);
7701
7702 memcpy(dev->dev_addr, bp->mac_addr, 6);
7703 memcpy(dev->perm_addr, bp->mac_addr, 6);
7704 bp->name = board_info[ent->driver_data].name;
7705
Stephen Hemmingerd212f872007-06-27 00:47:37 -07007706 dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG;
Michael Chan4666f872007-05-03 13:22:28 -07007707 if (CHIP_NUM(bp) == CHIP_NUM_5709)
Stephen Hemmingerd212f872007-06-27 00:47:37 -07007708 dev->features |= NETIF_F_IPV6_CSUM;
7709
Michael Chan1b2f9222007-05-03 13:20:19 -07007710#ifdef BCM_VLAN
7711 dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
7712#endif
7713 dev->features |= NETIF_F_TSO | NETIF_F_TSO_ECN;
Michael Chan4666f872007-05-03 13:22:28 -07007714 if (CHIP_NUM(bp) == CHIP_NUM_5709)
7715 dev->features |= NETIF_F_TSO6;
Michael Chan1b2f9222007-05-03 13:20:19 -07007716
Michael Chanb6016b72005-05-26 13:03:09 -07007717 if ((rc = register_netdev(dev))) {
Jeff Garzik9b91cf92006-06-27 11:39:50 -04007718 dev_err(&pdev->dev, "Cannot register net device\n");
Michael Chanb6016b72005-05-26 13:03:09 -07007719 if (bp->regview)
7720 iounmap(bp->regview);
7721 pci_release_regions(pdev);
7722 pci_disable_device(pdev);
7723 pci_set_drvdata(pdev, NULL);
7724 free_netdev(dev);
7725 return rc;
7726 }
7727
Michael Chan883e5152007-05-03 13:25:11 -07007728 printk(KERN_INFO "%s: %s (%c%d) %s found at mem %lx, "
Joe Perches0795af52007-10-03 17:59:30 -07007729 "IRQ %d, node addr %s\n",
Michael Chanb6016b72005-05-26 13:03:09 -07007730 dev->name,
7731 bp->name,
7732 ((CHIP_ID(bp) & 0xf000) >> 12) + 'A',
7733 ((CHIP_ID(bp) & 0x0ff0) >> 4),
Michael Chan883e5152007-05-03 13:25:11 -07007734 bnx2_bus_string(bp, str),
Michael Chanb6016b72005-05-26 13:03:09 -07007735 dev->base_addr,
Joe Perches0795af52007-10-03 17:59:30 -07007736 bp->pdev->irq, print_mac(mac, dev->dev_addr));
Michael Chanb6016b72005-05-26 13:03:09 -07007737
Michael Chanb6016b72005-05-26 13:03:09 -07007738 return 0;
7739}
7740
7741static void __devexit
7742bnx2_remove_one(struct pci_dev *pdev)
7743{
7744 struct net_device *dev = pci_get_drvdata(pdev);
Michael Chan972ec0d2006-01-23 16:12:43 -08007745 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007746
Michael Chanafdc08b2005-08-25 15:34:29 -07007747 flush_scheduled_work();
7748
Michael Chanb6016b72005-05-26 13:03:09 -07007749 unregister_netdev(dev);
7750
7751 if (bp->regview)
7752 iounmap(bp->regview);
7753
7754 free_netdev(dev);
7755 pci_release_regions(pdev);
7756 pci_disable_device(pdev);
7757 pci_set_drvdata(pdev, NULL);
7758}
7759
7760static int
Pavel Machek829ca9a2005-09-03 15:56:56 -07007761bnx2_suspend(struct pci_dev *pdev, pm_message_t state)
Michael Chanb6016b72005-05-26 13:03:09 -07007762{
7763 struct net_device *dev = pci_get_drvdata(pdev);
Michael Chan972ec0d2006-01-23 16:12:43 -08007764 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007765 u32 reset_code;
7766
Michael Chan6caebb02007-08-03 20:57:25 -07007767 /* PCI register 4 needs to be saved whether netif_running() or not.
7768 * MSI address and data need to be saved if using MSI and
7769 * netif_running().
7770 */
7771 pci_save_state(pdev);
Michael Chanb6016b72005-05-26 13:03:09 -07007772 if (!netif_running(dev))
7773 return 0;
7774
Michael Chan1d60290f2006-03-20 17:50:08 -08007775 flush_scheduled_work();
Michael Chanb6016b72005-05-26 13:03:09 -07007776 bnx2_netif_stop(bp);
7777 netif_device_detach(dev);
7778 del_timer_sync(&bp->timer);
David S. Millerf86e82f2008-01-21 17:15:40 -08007779 if (bp->flags & BNX2_FLAG_NO_WOL)
Michael Chan6c4f0952006-06-29 12:38:15 -07007780 reset_code = BNX2_DRV_MSG_CODE_UNLOAD_LNK_DN;
Michael Chandda1e392006-01-23 16:08:14 -08007781 else if (bp->wol)
Michael Chanb6016b72005-05-26 13:03:09 -07007782 reset_code = BNX2_DRV_MSG_CODE_SUSPEND_WOL;
7783 else
7784 reset_code = BNX2_DRV_MSG_CODE_SUSPEND_NO_WOL;
7785 bnx2_reset_chip(bp, reset_code);
7786 bnx2_free_skbs(bp);
Pavel Machek829ca9a2005-09-03 15:56:56 -07007787 bnx2_set_power_state(bp, pci_choose_state(pdev, state));
Michael Chanb6016b72005-05-26 13:03:09 -07007788 return 0;
7789}
7790
7791static int
7792bnx2_resume(struct pci_dev *pdev)
7793{
7794 struct net_device *dev = pci_get_drvdata(pdev);
Michael Chan972ec0d2006-01-23 16:12:43 -08007795 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007796
Michael Chan6caebb02007-08-03 20:57:25 -07007797 pci_restore_state(pdev);
Michael Chanb6016b72005-05-26 13:03:09 -07007798 if (!netif_running(dev))
7799 return 0;
7800
Pavel Machek829ca9a2005-09-03 15:56:56 -07007801 bnx2_set_power_state(bp, PCI_D0);
Michael Chanb6016b72005-05-26 13:03:09 -07007802 netif_device_attach(dev);
Michael Chan9a120bc2008-05-16 22:17:45 -07007803 bnx2_init_nic(bp, 1);
Michael Chanb6016b72005-05-26 13:03:09 -07007804 bnx2_netif_start(bp);
7805 return 0;
7806}
7807
Wendy Xiong6ff2da42008-05-16 22:18:21 -07007808/**
7809 * bnx2_io_error_detected - called when PCI error is detected
7810 * @pdev: Pointer to PCI device
7811 * @state: The current pci connection state
7812 *
7813 * This function is called after a PCI bus error affecting
7814 * this device has been detected.
7815 */
7816static pci_ers_result_t bnx2_io_error_detected(struct pci_dev *pdev,
7817 pci_channel_state_t state)
7818{
7819 struct net_device *dev = pci_get_drvdata(pdev);
7820 struct bnx2 *bp = netdev_priv(dev);
7821
7822 rtnl_lock();
7823 netif_device_detach(dev);
7824
7825 if (netif_running(dev)) {
7826 bnx2_netif_stop(bp);
7827 del_timer_sync(&bp->timer);
7828 bnx2_reset_nic(bp, BNX2_DRV_MSG_CODE_RESET);
7829 }
7830
7831 pci_disable_device(pdev);
7832 rtnl_unlock();
7833
7834 /* Request a slot slot reset. */
7835 return PCI_ERS_RESULT_NEED_RESET;
7836}
7837
7838/**
7839 * bnx2_io_slot_reset - called after the pci bus has been reset.
7840 * @pdev: Pointer to PCI device
7841 *
7842 * Restart the card from scratch, as if from a cold-boot.
7843 */
7844static pci_ers_result_t bnx2_io_slot_reset(struct pci_dev *pdev)
7845{
7846 struct net_device *dev = pci_get_drvdata(pdev);
7847 struct bnx2 *bp = netdev_priv(dev);
7848
7849 rtnl_lock();
7850 if (pci_enable_device(pdev)) {
7851 dev_err(&pdev->dev,
7852 "Cannot re-enable PCI device after reset.\n");
7853 rtnl_unlock();
7854 return PCI_ERS_RESULT_DISCONNECT;
7855 }
7856 pci_set_master(pdev);
7857 pci_restore_state(pdev);
7858
7859 if (netif_running(dev)) {
7860 bnx2_set_power_state(bp, PCI_D0);
7861 bnx2_init_nic(bp, 1);
7862 }
7863
7864 rtnl_unlock();
7865 return PCI_ERS_RESULT_RECOVERED;
7866}
7867
7868/**
7869 * bnx2_io_resume - called when traffic can start flowing again.
7870 * @pdev: Pointer to PCI device
7871 *
7872 * This callback is called when the error recovery driver tells us that
7873 * its OK to resume normal operation.
7874 */
7875static void bnx2_io_resume(struct pci_dev *pdev)
7876{
7877 struct net_device *dev = pci_get_drvdata(pdev);
7878 struct bnx2 *bp = netdev_priv(dev);
7879
7880 rtnl_lock();
7881 if (netif_running(dev))
7882 bnx2_netif_start(bp);
7883
7884 netif_device_attach(dev);
7885 rtnl_unlock();
7886}
7887
7888static struct pci_error_handlers bnx2_err_handler = {
7889 .error_detected = bnx2_io_error_detected,
7890 .slot_reset = bnx2_io_slot_reset,
7891 .resume = bnx2_io_resume,
7892};
7893
Michael Chanb6016b72005-05-26 13:03:09 -07007894static struct pci_driver bnx2_pci_driver = {
Peter Hagervall14ab9b82005-08-10 14:18:16 -07007895 .name = DRV_MODULE_NAME,
7896 .id_table = bnx2_pci_tbl,
7897 .probe = bnx2_init_one,
7898 .remove = __devexit_p(bnx2_remove_one),
7899 .suspend = bnx2_suspend,
7900 .resume = bnx2_resume,
Wendy Xiong6ff2da42008-05-16 22:18:21 -07007901 .err_handler = &bnx2_err_handler,
Michael Chanb6016b72005-05-26 13:03:09 -07007902};
7903
7904static int __init bnx2_init(void)
7905{
Jeff Garzik29917622006-08-19 17:48:59 -04007906 return pci_register_driver(&bnx2_pci_driver);
Michael Chanb6016b72005-05-26 13:03:09 -07007907}
7908
7909static void __exit bnx2_cleanup(void)
7910{
7911 pci_unregister_driver(&bnx2_pci_driver);
7912}
7913
7914module_init(bnx2_init);
7915module_exit(bnx2_cleanup);
7916
7917
7918