blob: 3f5fcb0156a180a49977f200b7a16fe5e19f6a38 [file] [log] [blame]
Michael Chanb6016b72005-05-26 13:03:09 -07001/* bnx2.c: Broadcom NX2 network driver.
2 *
Michael Chana6952b52009-02-12 16:54:48 -08003 * Copyright (c) 2004-2009 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>
Michael Chanf2a4f052006-03-23 01:13:12 -080038#include <linux/if_vlan.h>
David S. Miller08013fa2008-08-15 19:46:01 -070039#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
Michael Chanf2a4f052006-03-23 01:13:12 -080040#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 Chan57579f72009-04-04 16:51:14 -070049#include <linux/firmware.h>
Benjamin Li706bf242008-07-18 17:55:11 -070050#include <linux/log2.h>
Michael Chanf2a4f052006-03-23 01:13:12 -080051
Michael Chan4edd4732009-06-08 18:14:42 -070052#if defined(CONFIG_CNIC) || defined(CONFIG_CNIC_MODULE)
53#define BCM_CNIC 1
54#include "cnic_if.h"
55#endif
Michael Chanb6016b72005-05-26 13:03:09 -070056#include "bnx2.h"
57#include "bnx2_fw.h"
Denys Vlasenkob3448b02007-09-30 17:55:51 -070058
Michael Chanb6016b72005-05-26 13:03:09 -070059#define DRV_MODULE_NAME "bnx2"
60#define PFX DRV_MODULE_NAME ": "
Michael Chan581daf72009-05-06 16:46:47 -070061#define DRV_MODULE_VERSION "2.0.1"
62#define DRV_MODULE_RELDATE "May 6, 2009"
Michael Chan57579f72009-04-04 16:51:14 -070063#define FW_MIPS_FILE_06 "bnx2/bnx2-mips-06-4.6.16.fw"
64#define FW_RV2P_FILE_06 "bnx2/bnx2-rv2p-06-4.6.16.fw"
65#define FW_MIPS_FILE_09 "bnx2/bnx2-mips-09-4.6.17.fw"
66#define FW_RV2P_FILE_09 "bnx2/bnx2-rv2p-09-4.6.15.fw"
Michael Chanb6016b72005-05-26 13:03:09 -070067
68#define RUN_AT(x) (jiffies + (x))
69
70/* Time in jiffies before concluding the transmitter is hung. */
71#define TX_TIMEOUT (5*HZ)
72
Andrew Mortonfefa8642008-02-09 23:17:15 -080073static char version[] __devinitdata =
Michael Chanb6016b72005-05-26 13:03:09 -070074 "Broadcom NetXtreme II Gigabit Ethernet Driver " DRV_MODULE_NAME " v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";
75
76MODULE_AUTHOR("Michael Chan <mchan@broadcom.com>");
Benjamin Li453a9c62008-09-18 16:39:16 -070077MODULE_DESCRIPTION("Broadcom NetXtreme II BCM5706/5708/5709/5716 Driver");
Michael Chanb6016b72005-05-26 13:03:09 -070078MODULE_LICENSE("GPL");
79MODULE_VERSION(DRV_MODULE_VERSION);
Michael Chan57579f72009-04-04 16:51:14 -070080MODULE_FIRMWARE(FW_MIPS_FILE_06);
81MODULE_FIRMWARE(FW_RV2P_FILE_06);
82MODULE_FIRMWARE(FW_MIPS_FILE_09);
83MODULE_FIRMWARE(FW_RV2P_FILE_09);
Michael Chanb6016b72005-05-26 13:03:09 -070084
85static int disable_msi = 0;
86
87module_param(disable_msi, int, 0);
88MODULE_PARM_DESC(disable_msi, "Disable Message Signaled Interrupt (MSI)");
89
90typedef enum {
91 BCM5706 = 0,
92 NC370T,
93 NC370I,
94 BCM5706S,
95 NC370F,
Michael Chan5b0c76a2005-11-04 08:45:49 -080096 BCM5708,
97 BCM5708S,
Michael Chanbac0dff2006-11-19 14:15:05 -080098 BCM5709,
Michael Chan27a005b2007-05-03 13:23:41 -070099 BCM5709S,
Michael Chan7bb0a042008-07-14 22:37:47 -0700100 BCM5716,
Michael Chan1caacec2008-11-12 16:01:12 -0800101 BCM5716S,
Michael Chanb6016b72005-05-26 13:03:09 -0700102} board_t;
103
104/* indexed by board_t, above */
Andrew Mortonfefa8642008-02-09 23:17:15 -0800105static struct {
Michael Chanb6016b72005-05-26 13:03:09 -0700106 char *name;
107} board_info[] __devinitdata = {
108 { "Broadcom NetXtreme II BCM5706 1000Base-T" },
109 { "HP NC370T Multifunction Gigabit Server Adapter" },
110 { "HP NC370i Multifunction Gigabit Server Adapter" },
111 { "Broadcom NetXtreme II BCM5706 1000Base-SX" },
112 { "HP NC370F Multifunction Gigabit Server Adapter" },
Michael Chan5b0c76a2005-11-04 08:45:49 -0800113 { "Broadcom NetXtreme II BCM5708 1000Base-T" },
114 { "Broadcom NetXtreme II BCM5708 1000Base-SX" },
Michael Chanbac0dff2006-11-19 14:15:05 -0800115 { "Broadcom NetXtreme II BCM5709 1000Base-T" },
Michael Chan27a005b2007-05-03 13:23:41 -0700116 { "Broadcom NetXtreme II BCM5709 1000Base-SX" },
Michael Chan7bb0a042008-07-14 22:37:47 -0700117 { "Broadcom NetXtreme II BCM5716 1000Base-T" },
Michael Chan1caacec2008-11-12 16:01:12 -0800118 { "Broadcom NetXtreme II BCM5716 1000Base-SX" },
Michael Chanb6016b72005-05-26 13:03:09 -0700119 };
120
Michael Chan7bb0a042008-07-14 22:37:47 -0700121static DEFINE_PCI_DEVICE_TABLE(bnx2_pci_tbl) = {
Michael Chanb6016b72005-05-26 13:03:09 -0700122 { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5706,
123 PCI_VENDOR_ID_HP, 0x3101, 0, 0, NC370T },
124 { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5706,
125 PCI_VENDOR_ID_HP, 0x3106, 0, 0, NC370I },
126 { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5706,
127 PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5706 },
Michael Chan5b0c76a2005-11-04 08:45:49 -0800128 { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5708,
129 PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5708 },
Michael Chanb6016b72005-05-26 13:03:09 -0700130 { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5706S,
131 PCI_VENDOR_ID_HP, 0x3102, 0, 0, NC370F },
132 { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5706S,
133 PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5706S },
Michael Chan5b0c76a2005-11-04 08:45:49 -0800134 { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5708S,
135 PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5708S },
Michael Chanbac0dff2006-11-19 14:15:05 -0800136 { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5709,
137 PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5709 },
Michael Chan27a005b2007-05-03 13:23:41 -0700138 { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5709S,
139 PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5709S },
Michael Chan7bb0a042008-07-14 22:37:47 -0700140 { PCI_VENDOR_ID_BROADCOM, 0x163b,
141 PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5716 },
Michael Chan1caacec2008-11-12 16:01:12 -0800142 { PCI_VENDOR_ID_BROADCOM, 0x163c,
Michael Chan1f2435e2008-12-16 20:28:13 -0800143 PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5716S },
Michael Chanb6016b72005-05-26 13:03:09 -0700144 { 0, }
145};
146
147static struct flash_spec flash_table[] =
148{
Michael Chane30372c2007-07-16 18:26:23 -0700149#define BUFFERED_FLAGS (BNX2_NV_BUFFERED | BNX2_NV_TRANSLATE)
150#define NONBUFFERED_FLAGS (BNX2_NV_WREN)
Michael Chanb6016b72005-05-26 13:03:09 -0700151 /* Slow EEPROM */
Michael Chan37137702005-11-04 08:49:17 -0800152 {0x00000000, 0x40830380, 0x009f0081, 0xa184a053, 0xaf000400,
Michael Chane30372c2007-07-16 18:26:23 -0700153 BUFFERED_FLAGS, SEEPROM_PAGE_BITS, SEEPROM_PAGE_SIZE,
Michael Chanb6016b72005-05-26 13:03:09 -0700154 SEEPROM_BYTE_ADDR_MASK, SEEPROM_TOTAL_SIZE,
155 "EEPROM - slow"},
Michael Chan37137702005-11-04 08:49:17 -0800156 /* Expansion entry 0001 */
157 {0x08000002, 0x4b808201, 0x00050081, 0x03840253, 0xaf020406,
Michael Chane30372c2007-07-16 18:26:23 -0700158 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
Michael Chan37137702005-11-04 08:49:17 -0800159 SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
160 "Entry 0001"},
Michael Chanb6016b72005-05-26 13:03:09 -0700161 /* Saifun SA25F010 (non-buffered flash) */
162 /* strap, cfg1, & write1 need updates */
Michael Chan37137702005-11-04 08:49:17 -0800163 {0x04000001, 0x47808201, 0x00050081, 0x03840253, 0xaf020406,
Michael Chane30372c2007-07-16 18:26:23 -0700164 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
Michael Chanb6016b72005-05-26 13:03:09 -0700165 SAIFUN_FLASH_BYTE_ADDR_MASK, SAIFUN_FLASH_BASE_TOTAL_SIZE*2,
166 "Non-buffered flash (128kB)"},
167 /* Saifun SA25F020 (non-buffered flash) */
168 /* strap, cfg1, & write1 need updates */
Michael Chan37137702005-11-04 08:49:17 -0800169 {0x0c000003, 0x4f808201, 0x00050081, 0x03840253, 0xaf020406,
Michael Chane30372c2007-07-16 18:26:23 -0700170 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
Michael Chanb6016b72005-05-26 13:03:09 -0700171 SAIFUN_FLASH_BYTE_ADDR_MASK, SAIFUN_FLASH_BASE_TOTAL_SIZE*4,
172 "Non-buffered flash (256kB)"},
Michael Chan37137702005-11-04 08:49:17 -0800173 /* Expansion entry 0100 */
174 {0x11000000, 0x53808201, 0x00050081, 0x03840253, 0xaf020406,
Michael Chane30372c2007-07-16 18:26:23 -0700175 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
Michael Chan37137702005-11-04 08:49:17 -0800176 SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
177 "Entry 0100"},
178 /* Entry 0101: ST M45PE10 (non-buffered flash, TetonII B0) */
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400179 {0x19000002, 0x5b808201, 0x000500db, 0x03840253, 0xaf020406,
Michael Chane30372c2007-07-16 18:26:23 -0700180 NONBUFFERED_FLAGS, ST_MICRO_FLASH_PAGE_BITS, ST_MICRO_FLASH_PAGE_SIZE,
Michael Chan37137702005-11-04 08:49:17 -0800181 ST_MICRO_FLASH_BYTE_ADDR_MASK, ST_MICRO_FLASH_BASE_TOTAL_SIZE*2,
182 "Entry 0101: ST M45PE10 (128kB non-bufferred)"},
183 /* Entry 0110: ST M45PE20 (non-buffered flash)*/
184 {0x15000001, 0x57808201, 0x000500db, 0x03840253, 0xaf020406,
Michael Chane30372c2007-07-16 18:26:23 -0700185 NONBUFFERED_FLAGS, ST_MICRO_FLASH_PAGE_BITS, ST_MICRO_FLASH_PAGE_SIZE,
Michael Chan37137702005-11-04 08:49:17 -0800186 ST_MICRO_FLASH_BYTE_ADDR_MASK, ST_MICRO_FLASH_BASE_TOTAL_SIZE*4,
187 "Entry 0110: ST M45PE20 (256kB non-bufferred)"},
188 /* Saifun SA25F005 (non-buffered flash) */
189 /* strap, cfg1, & write1 need updates */
190 {0x1d000003, 0x5f808201, 0x00050081, 0x03840253, 0xaf020406,
Michael Chane30372c2007-07-16 18:26:23 -0700191 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
Michael Chan37137702005-11-04 08:49:17 -0800192 SAIFUN_FLASH_BYTE_ADDR_MASK, SAIFUN_FLASH_BASE_TOTAL_SIZE,
193 "Non-buffered flash (64kB)"},
194 /* Fast EEPROM */
195 {0x22000000, 0x62808380, 0x009f0081, 0xa184a053, 0xaf000400,
Michael Chane30372c2007-07-16 18:26:23 -0700196 BUFFERED_FLAGS, SEEPROM_PAGE_BITS, SEEPROM_PAGE_SIZE,
Michael Chan37137702005-11-04 08:49:17 -0800197 SEEPROM_BYTE_ADDR_MASK, SEEPROM_TOTAL_SIZE,
198 "EEPROM - fast"},
199 /* Expansion entry 1001 */
200 {0x2a000002, 0x6b808201, 0x00050081, 0x03840253, 0xaf020406,
Michael Chane30372c2007-07-16 18:26:23 -0700201 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
Michael Chan37137702005-11-04 08:49:17 -0800202 SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
203 "Entry 1001"},
204 /* Expansion entry 1010 */
205 {0x26000001, 0x67808201, 0x00050081, 0x03840253, 0xaf020406,
Michael Chane30372c2007-07-16 18:26:23 -0700206 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
Michael Chan37137702005-11-04 08:49:17 -0800207 SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
208 "Entry 1010"},
209 /* ATMEL AT45DB011B (buffered flash) */
210 {0x2e000003, 0x6e808273, 0x00570081, 0x68848353, 0xaf000400,
Michael Chane30372c2007-07-16 18:26:23 -0700211 BUFFERED_FLAGS, BUFFERED_FLASH_PAGE_BITS, BUFFERED_FLASH_PAGE_SIZE,
Michael Chan37137702005-11-04 08:49:17 -0800212 BUFFERED_FLASH_BYTE_ADDR_MASK, BUFFERED_FLASH_TOTAL_SIZE,
213 "Buffered flash (128kB)"},
214 /* Expansion entry 1100 */
215 {0x33000000, 0x73808201, 0x00050081, 0x03840253, 0xaf020406,
Michael Chane30372c2007-07-16 18:26:23 -0700216 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
Michael Chan37137702005-11-04 08:49:17 -0800217 SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
218 "Entry 1100"},
219 /* Expansion entry 1101 */
220 {0x3b000002, 0x7b808201, 0x00050081, 0x03840253, 0xaf020406,
Michael Chane30372c2007-07-16 18:26:23 -0700221 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
Michael Chan37137702005-11-04 08:49:17 -0800222 SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
223 "Entry 1101"},
224 /* Ateml Expansion entry 1110 */
225 {0x37000001, 0x76808273, 0x00570081, 0x68848353, 0xaf000400,
Michael Chane30372c2007-07-16 18:26:23 -0700226 BUFFERED_FLAGS, BUFFERED_FLASH_PAGE_BITS, BUFFERED_FLASH_PAGE_SIZE,
Michael Chan37137702005-11-04 08:49:17 -0800227 BUFFERED_FLASH_BYTE_ADDR_MASK, 0,
228 "Entry 1110 (Atmel)"},
229 /* ATMEL AT45DB021B (buffered flash) */
230 {0x3f000003, 0x7e808273, 0x00570081, 0x68848353, 0xaf000400,
Michael Chane30372c2007-07-16 18:26:23 -0700231 BUFFERED_FLAGS, BUFFERED_FLASH_PAGE_BITS, BUFFERED_FLASH_PAGE_SIZE,
Michael Chan37137702005-11-04 08:49:17 -0800232 BUFFERED_FLASH_BYTE_ADDR_MASK, BUFFERED_FLASH_TOTAL_SIZE*2,
233 "Buffered flash (256kB)"},
Michael Chanb6016b72005-05-26 13:03:09 -0700234};
235
Michael Chane30372c2007-07-16 18:26:23 -0700236static struct flash_spec flash_5709 = {
237 .flags = BNX2_NV_BUFFERED,
238 .page_bits = BCM5709_FLASH_PAGE_BITS,
239 .page_size = BCM5709_FLASH_PAGE_SIZE,
240 .addr_mask = BCM5709_FLASH_BYTE_ADDR_MASK,
241 .total_size = BUFFERED_FLASH_TOTAL_SIZE*2,
242 .name = "5709 Buffered flash (256kB)",
243};
244
Michael Chanb6016b72005-05-26 13:03:09 -0700245MODULE_DEVICE_TABLE(pci, bnx2_pci_tbl);
246
Michael Chan35e90102008-06-19 16:37:42 -0700247static inline u32 bnx2_tx_avail(struct bnx2 *bp, struct bnx2_tx_ring_info *txr)
Michael Chane89bbf12005-08-25 15:36:58 -0700248{
Michael Chan2f8af122006-08-15 01:39:10 -0700249 u32 diff;
Michael Chane89bbf12005-08-25 15:36:58 -0700250
Michael Chan2f8af122006-08-15 01:39:10 -0700251 smp_mb();
Michael Chanfaac9c42006-12-14 15:56:32 -0800252
253 /* The ring uses 256 indices for 255 entries, one of them
254 * needs to be skipped.
255 */
Michael Chan35e90102008-06-19 16:37:42 -0700256 diff = txr->tx_prod - txr->tx_cons;
Michael Chanfaac9c42006-12-14 15:56:32 -0800257 if (unlikely(diff >= TX_DESC_CNT)) {
258 diff &= 0xffff;
259 if (diff == TX_DESC_CNT)
260 diff = MAX_TX_DESC_CNT;
261 }
Michael Chane89bbf12005-08-25 15:36:58 -0700262 return (bp->tx_ring_size - diff);
263}
264
Michael Chanb6016b72005-05-26 13:03:09 -0700265static u32
266bnx2_reg_rd_ind(struct bnx2 *bp, u32 offset)
267{
Michael Chan1b8227c2007-05-03 13:24:05 -0700268 u32 val;
269
270 spin_lock_bh(&bp->indirect_lock);
Michael Chanb6016b72005-05-26 13:03:09 -0700271 REG_WR(bp, BNX2_PCICFG_REG_WINDOW_ADDRESS, offset);
Michael Chan1b8227c2007-05-03 13:24:05 -0700272 val = REG_RD(bp, BNX2_PCICFG_REG_WINDOW);
273 spin_unlock_bh(&bp->indirect_lock);
274 return val;
Michael Chanb6016b72005-05-26 13:03:09 -0700275}
276
277static void
278bnx2_reg_wr_ind(struct bnx2 *bp, u32 offset, u32 val)
279{
Michael Chan1b8227c2007-05-03 13:24:05 -0700280 spin_lock_bh(&bp->indirect_lock);
Michael Chanb6016b72005-05-26 13:03:09 -0700281 REG_WR(bp, BNX2_PCICFG_REG_WINDOW_ADDRESS, offset);
282 REG_WR(bp, BNX2_PCICFG_REG_WINDOW, val);
Michael Chan1b8227c2007-05-03 13:24:05 -0700283 spin_unlock_bh(&bp->indirect_lock);
Michael Chanb6016b72005-05-26 13:03:09 -0700284}
285
286static void
Michael Chan2726d6e2008-01-29 21:35:05 -0800287bnx2_shmem_wr(struct bnx2 *bp, u32 offset, u32 val)
288{
289 bnx2_reg_wr_ind(bp, bp->shmem_base + offset, val);
290}
291
292static u32
293bnx2_shmem_rd(struct bnx2 *bp, u32 offset)
294{
295 return (bnx2_reg_rd_ind(bp, bp->shmem_base + offset));
296}
297
298static void
Michael Chanb6016b72005-05-26 13:03:09 -0700299bnx2_ctx_wr(struct bnx2 *bp, u32 cid_addr, u32 offset, u32 val)
300{
301 offset += cid_addr;
Michael Chan1b8227c2007-05-03 13:24:05 -0700302 spin_lock_bh(&bp->indirect_lock);
Michael Chan59b47d82006-11-19 14:10:45 -0800303 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
304 int i;
305
306 REG_WR(bp, BNX2_CTX_CTX_DATA, val);
307 REG_WR(bp, BNX2_CTX_CTX_CTRL,
308 offset | BNX2_CTX_CTX_CTRL_WRITE_REQ);
309 for (i = 0; i < 5; i++) {
Michael Chan59b47d82006-11-19 14:10:45 -0800310 val = REG_RD(bp, BNX2_CTX_CTX_CTRL);
311 if ((val & BNX2_CTX_CTX_CTRL_WRITE_REQ) == 0)
312 break;
313 udelay(5);
314 }
315 } else {
316 REG_WR(bp, BNX2_CTX_DATA_ADR, offset);
317 REG_WR(bp, BNX2_CTX_DATA, val);
318 }
Michael Chan1b8227c2007-05-03 13:24:05 -0700319 spin_unlock_bh(&bp->indirect_lock);
Michael Chanb6016b72005-05-26 13:03:09 -0700320}
321
Michael Chan4edd4732009-06-08 18:14:42 -0700322#ifdef BCM_CNIC
323static int
324bnx2_drv_ctl(struct net_device *dev, struct drv_ctl_info *info)
325{
326 struct bnx2 *bp = netdev_priv(dev);
327 struct drv_ctl_io *io = &info->data.io;
328
329 switch (info->cmd) {
330 case DRV_CTL_IO_WR_CMD:
331 bnx2_reg_wr_ind(bp, io->offset, io->data);
332 break;
333 case DRV_CTL_IO_RD_CMD:
334 io->data = bnx2_reg_rd_ind(bp, io->offset);
335 break;
336 case DRV_CTL_CTX_WR_CMD:
337 bnx2_ctx_wr(bp, io->cid_addr, io->offset, io->data);
338 break;
339 default:
340 return -EINVAL;
341 }
342 return 0;
343}
344
345static void bnx2_setup_cnic_irq_info(struct bnx2 *bp)
346{
347 struct cnic_eth_dev *cp = &bp->cnic_eth_dev;
348 struct bnx2_napi *bnapi = &bp->bnx2_napi[0];
349 int sb_id;
350
351 if (bp->flags & BNX2_FLAG_USING_MSIX) {
352 cp->drv_state |= CNIC_DRV_STATE_USING_MSIX;
353 bnapi->cnic_present = 0;
354 sb_id = bp->irq_nvecs;
355 cp->irq_arr[0].irq_flags |= CNIC_IRQ_FL_MSIX;
356 } else {
357 cp->drv_state &= ~CNIC_DRV_STATE_USING_MSIX;
358 bnapi->cnic_tag = bnapi->last_status_idx;
359 bnapi->cnic_present = 1;
360 sb_id = 0;
361 cp->irq_arr[0].irq_flags &= ~CNIC_IRQ_FL_MSIX;
362 }
363
364 cp->irq_arr[0].vector = bp->irq_tbl[sb_id].vector;
365 cp->irq_arr[0].status_blk = (void *)
366 ((unsigned long) bnapi->status_blk.msi +
367 (BNX2_SBLK_MSIX_ALIGN_SIZE * sb_id));
368 cp->irq_arr[0].status_blk_num = sb_id;
369 cp->num_irq = 1;
370}
371
372static int bnx2_register_cnic(struct net_device *dev, struct cnic_ops *ops,
373 void *data)
374{
375 struct bnx2 *bp = netdev_priv(dev);
376 struct cnic_eth_dev *cp = &bp->cnic_eth_dev;
377
378 if (ops == NULL)
379 return -EINVAL;
380
381 if (cp->drv_state & CNIC_DRV_STATE_REGD)
382 return -EBUSY;
383
384 bp->cnic_data = data;
385 rcu_assign_pointer(bp->cnic_ops, ops);
386
387 cp->num_irq = 0;
388 cp->drv_state = CNIC_DRV_STATE_REGD;
389
390 bnx2_setup_cnic_irq_info(bp);
391
392 return 0;
393}
394
395static int bnx2_unregister_cnic(struct net_device *dev)
396{
397 struct bnx2 *bp = netdev_priv(dev);
398 struct bnx2_napi *bnapi = &bp->bnx2_napi[0];
399 struct cnic_eth_dev *cp = &bp->cnic_eth_dev;
400
401 cp->drv_state = 0;
402 bnapi->cnic_present = 0;
403 rcu_assign_pointer(bp->cnic_ops, NULL);
404 synchronize_rcu();
405 return 0;
406}
407
408struct cnic_eth_dev *bnx2_cnic_probe(struct net_device *dev)
409{
410 struct bnx2 *bp = netdev_priv(dev);
411 struct cnic_eth_dev *cp = &bp->cnic_eth_dev;
412
413 cp->drv_owner = THIS_MODULE;
414 cp->chip_id = bp->chip_id;
415 cp->pdev = bp->pdev;
416 cp->io_base = bp->regview;
417 cp->drv_ctl = bnx2_drv_ctl;
418 cp->drv_register_cnic = bnx2_register_cnic;
419 cp->drv_unregister_cnic = bnx2_unregister_cnic;
420
421 return cp;
422}
423EXPORT_SYMBOL(bnx2_cnic_probe);
424
425static void
426bnx2_cnic_stop(struct bnx2 *bp)
427{
428 struct cnic_ops *c_ops;
429 struct cnic_ctl_info info;
430
431 rcu_read_lock();
432 c_ops = rcu_dereference(bp->cnic_ops);
433 if (c_ops) {
434 info.cmd = CNIC_CTL_STOP_CMD;
435 c_ops->cnic_ctl(bp->cnic_data, &info);
436 }
437 rcu_read_unlock();
438}
439
440static void
441bnx2_cnic_start(struct bnx2 *bp)
442{
443 struct cnic_ops *c_ops;
444 struct cnic_ctl_info info;
445
446 rcu_read_lock();
447 c_ops = rcu_dereference(bp->cnic_ops);
448 if (c_ops) {
449 if (!(bp->flags & BNX2_FLAG_USING_MSIX)) {
450 struct bnx2_napi *bnapi = &bp->bnx2_napi[0];
451
452 bnapi->cnic_tag = bnapi->last_status_idx;
453 }
454 info.cmd = CNIC_CTL_START_CMD;
455 c_ops->cnic_ctl(bp->cnic_data, &info);
456 }
457 rcu_read_unlock();
458}
459
460#else
461
462static void
463bnx2_cnic_stop(struct bnx2 *bp)
464{
465}
466
467static void
468bnx2_cnic_start(struct bnx2 *bp)
469{
470}
471
472#endif
473
Michael Chanb6016b72005-05-26 13:03:09 -0700474static int
475bnx2_read_phy(struct bnx2 *bp, u32 reg, u32 *val)
476{
477 u32 val1;
478 int i, ret;
479
Michael Chan583c28e2008-01-21 19:51:35 -0800480 if (bp->phy_flags & BNX2_PHY_FLAG_INT_MODE_AUTO_POLLING) {
Michael Chanb6016b72005-05-26 13:03:09 -0700481 val1 = REG_RD(bp, BNX2_EMAC_MDIO_MODE);
482 val1 &= ~BNX2_EMAC_MDIO_MODE_AUTO_POLL;
483
484 REG_WR(bp, BNX2_EMAC_MDIO_MODE, val1);
485 REG_RD(bp, BNX2_EMAC_MDIO_MODE);
486
487 udelay(40);
488 }
489
490 val1 = (bp->phy_addr << 21) | (reg << 16) |
491 BNX2_EMAC_MDIO_COMM_COMMAND_READ | BNX2_EMAC_MDIO_COMM_DISEXT |
492 BNX2_EMAC_MDIO_COMM_START_BUSY;
493 REG_WR(bp, BNX2_EMAC_MDIO_COMM, val1);
494
495 for (i = 0; i < 50; i++) {
496 udelay(10);
497
498 val1 = REG_RD(bp, BNX2_EMAC_MDIO_COMM);
499 if (!(val1 & BNX2_EMAC_MDIO_COMM_START_BUSY)) {
500 udelay(5);
501
502 val1 = REG_RD(bp, BNX2_EMAC_MDIO_COMM);
503 val1 &= BNX2_EMAC_MDIO_COMM_DATA;
504
505 break;
506 }
507 }
508
509 if (val1 & BNX2_EMAC_MDIO_COMM_START_BUSY) {
510 *val = 0x0;
511 ret = -EBUSY;
512 }
513 else {
514 *val = val1;
515 ret = 0;
516 }
517
Michael Chan583c28e2008-01-21 19:51:35 -0800518 if (bp->phy_flags & BNX2_PHY_FLAG_INT_MODE_AUTO_POLLING) {
Michael Chanb6016b72005-05-26 13:03:09 -0700519 val1 = REG_RD(bp, BNX2_EMAC_MDIO_MODE);
520 val1 |= BNX2_EMAC_MDIO_MODE_AUTO_POLL;
521
522 REG_WR(bp, BNX2_EMAC_MDIO_MODE, val1);
523 REG_RD(bp, BNX2_EMAC_MDIO_MODE);
524
525 udelay(40);
526 }
527
528 return ret;
529}
530
531static int
532bnx2_write_phy(struct bnx2 *bp, u32 reg, u32 val)
533{
534 u32 val1;
535 int i, ret;
536
Michael Chan583c28e2008-01-21 19:51:35 -0800537 if (bp->phy_flags & BNX2_PHY_FLAG_INT_MODE_AUTO_POLLING) {
Michael Chanb6016b72005-05-26 13:03:09 -0700538 val1 = REG_RD(bp, BNX2_EMAC_MDIO_MODE);
539 val1 &= ~BNX2_EMAC_MDIO_MODE_AUTO_POLL;
540
541 REG_WR(bp, BNX2_EMAC_MDIO_MODE, val1);
542 REG_RD(bp, BNX2_EMAC_MDIO_MODE);
543
544 udelay(40);
545 }
546
547 val1 = (bp->phy_addr << 21) | (reg << 16) | val |
548 BNX2_EMAC_MDIO_COMM_COMMAND_WRITE |
549 BNX2_EMAC_MDIO_COMM_START_BUSY | BNX2_EMAC_MDIO_COMM_DISEXT;
550 REG_WR(bp, BNX2_EMAC_MDIO_COMM, val1);
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400551
Michael Chanb6016b72005-05-26 13:03:09 -0700552 for (i = 0; i < 50; i++) {
553 udelay(10);
554
555 val1 = REG_RD(bp, BNX2_EMAC_MDIO_COMM);
556 if (!(val1 & BNX2_EMAC_MDIO_COMM_START_BUSY)) {
557 udelay(5);
558 break;
559 }
560 }
561
562 if (val1 & BNX2_EMAC_MDIO_COMM_START_BUSY)
563 ret = -EBUSY;
564 else
565 ret = 0;
566
Michael Chan583c28e2008-01-21 19:51:35 -0800567 if (bp->phy_flags & BNX2_PHY_FLAG_INT_MODE_AUTO_POLLING) {
Michael Chanb6016b72005-05-26 13:03:09 -0700568 val1 = REG_RD(bp, BNX2_EMAC_MDIO_MODE);
569 val1 |= BNX2_EMAC_MDIO_MODE_AUTO_POLL;
570
571 REG_WR(bp, BNX2_EMAC_MDIO_MODE, val1);
572 REG_RD(bp, BNX2_EMAC_MDIO_MODE);
573
574 udelay(40);
575 }
576
577 return ret;
578}
579
580static void
581bnx2_disable_int(struct bnx2 *bp)
582{
Michael Chanb4b36042007-12-20 19:59:30 -0800583 int i;
584 struct bnx2_napi *bnapi;
585
586 for (i = 0; i < bp->irq_nvecs; i++) {
587 bnapi = &bp->bnx2_napi[i];
588 REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD, bnapi->int_num |
589 BNX2_PCICFG_INT_ACK_CMD_MASK_INT);
590 }
Michael Chanb6016b72005-05-26 13:03:09 -0700591 REG_RD(bp, BNX2_PCICFG_INT_ACK_CMD);
592}
593
594static void
595bnx2_enable_int(struct bnx2 *bp)
596{
Michael Chanb4b36042007-12-20 19:59:30 -0800597 int i;
598 struct bnx2_napi *bnapi;
Michael Chan1269a8a2006-01-23 16:11:03 -0800599
Michael Chanb4b36042007-12-20 19:59:30 -0800600 for (i = 0; i < bp->irq_nvecs; i++) {
601 bnapi = &bp->bnx2_napi[i];
Michael Chan35efa7c2007-12-20 19:56:37 -0800602
Michael Chanb4b36042007-12-20 19:59:30 -0800603 REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD, bnapi->int_num |
604 BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
605 BNX2_PCICFG_INT_ACK_CMD_MASK_INT |
606 bnapi->last_status_idx);
Michael Chanb6016b72005-05-26 13:03:09 -0700607
Michael Chanb4b36042007-12-20 19:59:30 -0800608 REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD, bnapi->int_num |
609 BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
610 bnapi->last_status_idx);
611 }
Michael Chanbf5295b2006-03-23 01:11:56 -0800612 REG_WR(bp, BNX2_HC_COMMAND, bp->hc_cmd | BNX2_HC_COMMAND_COAL_NOW);
Michael Chanb6016b72005-05-26 13:03:09 -0700613}
614
615static void
616bnx2_disable_int_sync(struct bnx2 *bp)
617{
Michael Chanb4b36042007-12-20 19:59:30 -0800618 int i;
619
Michael Chanb6016b72005-05-26 13:03:09 -0700620 atomic_inc(&bp->intr_sem);
621 bnx2_disable_int(bp);
Michael Chanb4b36042007-12-20 19:59:30 -0800622 for (i = 0; i < bp->irq_nvecs; i++)
623 synchronize_irq(bp->irq_tbl[i].vector);
Michael Chanb6016b72005-05-26 13:03:09 -0700624}
625
626static void
Michael Chan35efa7c2007-12-20 19:56:37 -0800627bnx2_napi_disable(struct bnx2 *bp)
628{
Michael Chanb4b36042007-12-20 19:59:30 -0800629 int i;
630
631 for (i = 0; i < bp->irq_nvecs; i++)
632 napi_disable(&bp->bnx2_napi[i].napi);
Michael Chan35efa7c2007-12-20 19:56:37 -0800633}
634
635static void
636bnx2_napi_enable(struct bnx2 *bp)
637{
Michael Chanb4b36042007-12-20 19:59:30 -0800638 int i;
639
640 for (i = 0; i < bp->irq_nvecs; i++)
641 napi_enable(&bp->bnx2_napi[i].napi);
Michael Chan35efa7c2007-12-20 19:56:37 -0800642}
643
644static void
Michael Chanb6016b72005-05-26 13:03:09 -0700645bnx2_netif_stop(struct bnx2 *bp)
646{
Michael Chan4edd4732009-06-08 18:14:42 -0700647 bnx2_cnic_stop(bp);
Michael Chanb6016b72005-05-26 13:03:09 -0700648 bnx2_disable_int_sync(bp);
649 if (netif_running(bp->dev)) {
Michael Chan35efa7c2007-12-20 19:56:37 -0800650 bnx2_napi_disable(bp);
Michael Chanb6016b72005-05-26 13:03:09 -0700651 netif_tx_disable(bp->dev);
652 bp->dev->trans_start = jiffies; /* prevent tx timeout */
653 }
654}
655
656static void
657bnx2_netif_start(struct bnx2 *bp)
658{
659 if (atomic_dec_and_test(&bp->intr_sem)) {
660 if (netif_running(bp->dev)) {
Benjamin Li706bf242008-07-18 17:55:11 -0700661 netif_tx_wake_all_queues(bp->dev);
Michael Chan35efa7c2007-12-20 19:56:37 -0800662 bnx2_napi_enable(bp);
Michael Chanb6016b72005-05-26 13:03:09 -0700663 bnx2_enable_int(bp);
Michael Chan4edd4732009-06-08 18:14:42 -0700664 bnx2_cnic_start(bp);
Michael Chanb6016b72005-05-26 13:03:09 -0700665 }
666 }
667}
668
669static void
Michael Chan35e90102008-06-19 16:37:42 -0700670bnx2_free_tx_mem(struct bnx2 *bp)
671{
672 int i;
673
674 for (i = 0; i < bp->num_tx_rings; i++) {
675 struct bnx2_napi *bnapi = &bp->bnx2_napi[i];
676 struct bnx2_tx_ring_info *txr = &bnapi->tx_ring;
677
678 if (txr->tx_desc_ring) {
679 pci_free_consistent(bp->pdev, TXBD_RING_SIZE,
680 txr->tx_desc_ring,
681 txr->tx_desc_mapping);
682 txr->tx_desc_ring = NULL;
683 }
684 kfree(txr->tx_buf_ring);
685 txr->tx_buf_ring = NULL;
686 }
687}
688
Michael Chanbb4f98a2008-06-19 16:38:19 -0700689static void
690bnx2_free_rx_mem(struct bnx2 *bp)
691{
692 int i;
693
694 for (i = 0; i < bp->num_rx_rings; i++) {
695 struct bnx2_napi *bnapi = &bp->bnx2_napi[i];
696 struct bnx2_rx_ring_info *rxr = &bnapi->rx_ring;
697 int j;
698
699 for (j = 0; j < bp->rx_max_ring; j++) {
700 if (rxr->rx_desc_ring[j])
701 pci_free_consistent(bp->pdev, RXBD_RING_SIZE,
702 rxr->rx_desc_ring[j],
703 rxr->rx_desc_mapping[j]);
704 rxr->rx_desc_ring[j] = NULL;
705 }
706 if (rxr->rx_buf_ring)
707 vfree(rxr->rx_buf_ring);
708 rxr->rx_buf_ring = NULL;
709
710 for (j = 0; j < bp->rx_max_pg_ring; j++) {
711 if (rxr->rx_pg_desc_ring[j])
712 pci_free_consistent(bp->pdev, RXBD_RING_SIZE,
Michael Chan3298a732008-12-17 19:06:08 -0800713 rxr->rx_pg_desc_ring[j],
714 rxr->rx_pg_desc_mapping[j]);
715 rxr->rx_pg_desc_ring[j] = NULL;
Michael Chanbb4f98a2008-06-19 16:38:19 -0700716 }
717 if (rxr->rx_pg_ring)
718 vfree(rxr->rx_pg_ring);
719 rxr->rx_pg_ring = NULL;
720 }
721}
722
Michael Chan35e90102008-06-19 16:37:42 -0700723static int
724bnx2_alloc_tx_mem(struct bnx2 *bp)
725{
726 int i;
727
728 for (i = 0; i < bp->num_tx_rings; i++) {
729 struct bnx2_napi *bnapi = &bp->bnx2_napi[i];
730 struct bnx2_tx_ring_info *txr = &bnapi->tx_ring;
731
732 txr->tx_buf_ring = kzalloc(SW_TXBD_RING_SIZE, GFP_KERNEL);
733 if (txr->tx_buf_ring == NULL)
734 return -ENOMEM;
735
736 txr->tx_desc_ring =
737 pci_alloc_consistent(bp->pdev, TXBD_RING_SIZE,
738 &txr->tx_desc_mapping);
739 if (txr->tx_desc_ring == NULL)
740 return -ENOMEM;
741 }
742 return 0;
743}
744
Michael Chanbb4f98a2008-06-19 16:38:19 -0700745static int
746bnx2_alloc_rx_mem(struct bnx2 *bp)
747{
748 int i;
749
750 for (i = 0; i < bp->num_rx_rings; i++) {
751 struct bnx2_napi *bnapi = &bp->bnx2_napi[i];
752 struct bnx2_rx_ring_info *rxr = &bnapi->rx_ring;
753 int j;
754
755 rxr->rx_buf_ring =
756 vmalloc(SW_RXBD_RING_SIZE * bp->rx_max_ring);
757 if (rxr->rx_buf_ring == NULL)
758 return -ENOMEM;
759
760 memset(rxr->rx_buf_ring, 0,
761 SW_RXBD_RING_SIZE * bp->rx_max_ring);
762
763 for (j = 0; j < bp->rx_max_ring; j++) {
764 rxr->rx_desc_ring[j] =
765 pci_alloc_consistent(bp->pdev, RXBD_RING_SIZE,
766 &rxr->rx_desc_mapping[j]);
767 if (rxr->rx_desc_ring[j] == NULL)
768 return -ENOMEM;
769
770 }
771
772 if (bp->rx_pg_ring_size) {
773 rxr->rx_pg_ring = vmalloc(SW_RXPG_RING_SIZE *
774 bp->rx_max_pg_ring);
775 if (rxr->rx_pg_ring == NULL)
776 return -ENOMEM;
777
778 memset(rxr->rx_pg_ring, 0, SW_RXPG_RING_SIZE *
779 bp->rx_max_pg_ring);
780 }
781
782 for (j = 0; j < bp->rx_max_pg_ring; j++) {
783 rxr->rx_pg_desc_ring[j] =
784 pci_alloc_consistent(bp->pdev, RXBD_RING_SIZE,
785 &rxr->rx_pg_desc_mapping[j]);
786 if (rxr->rx_pg_desc_ring[j] == NULL)
787 return -ENOMEM;
788
789 }
790 }
791 return 0;
792}
793
Michael Chan35e90102008-06-19 16:37:42 -0700794static void
Michael Chanb6016b72005-05-26 13:03:09 -0700795bnx2_free_mem(struct bnx2 *bp)
796{
Michael Chan13daffa2006-03-20 17:49:20 -0800797 int i;
Michael Chan43e80b82008-06-19 16:41:08 -0700798 struct bnx2_napi *bnapi = &bp->bnx2_napi[0];
Michael Chan13daffa2006-03-20 17:49:20 -0800799
Michael Chan35e90102008-06-19 16:37:42 -0700800 bnx2_free_tx_mem(bp);
Michael Chanbb4f98a2008-06-19 16:38:19 -0700801 bnx2_free_rx_mem(bp);
Michael Chan35e90102008-06-19 16:37:42 -0700802
Michael Chan59b47d82006-11-19 14:10:45 -0800803 for (i = 0; i < bp->ctx_pages; i++) {
804 if (bp->ctx_blk[i]) {
805 pci_free_consistent(bp->pdev, BCM_PAGE_SIZE,
806 bp->ctx_blk[i],
807 bp->ctx_blk_mapping[i]);
808 bp->ctx_blk[i] = NULL;
809 }
810 }
Michael Chan43e80b82008-06-19 16:41:08 -0700811 if (bnapi->status_blk.msi) {
Michael Chan0f31f992006-03-23 01:12:38 -0800812 pci_free_consistent(bp->pdev, bp->status_stats_size,
Michael Chan43e80b82008-06-19 16:41:08 -0700813 bnapi->status_blk.msi,
814 bp->status_blk_mapping);
815 bnapi->status_blk.msi = NULL;
Michael Chan0f31f992006-03-23 01:12:38 -0800816 bp->stats_blk = NULL;
Michael Chanb6016b72005-05-26 13:03:09 -0700817 }
Michael Chanb6016b72005-05-26 13:03:09 -0700818}
819
820static int
821bnx2_alloc_mem(struct bnx2 *bp)
822{
Michael Chan35e90102008-06-19 16:37:42 -0700823 int i, status_blk_size, err;
Michael Chan43e80b82008-06-19 16:41:08 -0700824 struct bnx2_napi *bnapi;
825 void *status_blk;
Michael Chanb6016b72005-05-26 13:03:09 -0700826
Michael Chan0f31f992006-03-23 01:12:38 -0800827 /* Combine status and statistics blocks into one allocation. */
828 status_blk_size = L1_CACHE_ALIGN(sizeof(struct status_block));
David S. Millerf86e82f2008-01-21 17:15:40 -0800829 if (bp->flags & BNX2_FLAG_MSIX_CAP)
Michael Chanb4b36042007-12-20 19:59:30 -0800830 status_blk_size = L1_CACHE_ALIGN(BNX2_MAX_MSIX_HW_VEC *
831 BNX2_SBLK_MSIX_ALIGN_SIZE);
Michael Chan0f31f992006-03-23 01:12:38 -0800832 bp->status_stats_size = status_blk_size +
833 sizeof(struct statistics_block);
834
Michael Chan43e80b82008-06-19 16:41:08 -0700835 status_blk = pci_alloc_consistent(bp->pdev, bp->status_stats_size,
836 &bp->status_blk_mapping);
837 if (status_blk == NULL)
Michael Chanb6016b72005-05-26 13:03:09 -0700838 goto alloc_mem_err;
839
Michael Chan43e80b82008-06-19 16:41:08 -0700840 memset(status_blk, 0, bp->status_stats_size);
Michael Chanb6016b72005-05-26 13:03:09 -0700841
Michael Chan43e80b82008-06-19 16:41:08 -0700842 bnapi = &bp->bnx2_napi[0];
843 bnapi->status_blk.msi = status_blk;
844 bnapi->hw_tx_cons_ptr =
845 &bnapi->status_blk.msi->status_tx_quick_consumer_index0;
846 bnapi->hw_rx_cons_ptr =
847 &bnapi->status_blk.msi->status_rx_quick_consumer_index0;
David S. Millerf86e82f2008-01-21 17:15:40 -0800848 if (bp->flags & BNX2_FLAG_MSIX_CAP) {
Michael Chanb4b36042007-12-20 19:59:30 -0800849 for (i = 1; i < BNX2_MAX_MSIX_VEC; i++) {
Michael Chan43e80b82008-06-19 16:41:08 -0700850 struct status_block_msix *sblk;
Michael Chanb4b36042007-12-20 19:59:30 -0800851
Michael Chan43e80b82008-06-19 16:41:08 -0700852 bnapi = &bp->bnx2_napi[i];
853
854 sblk = (void *) (status_blk +
855 BNX2_SBLK_MSIX_ALIGN_SIZE * i);
856 bnapi->status_blk.msix = sblk;
857 bnapi->hw_tx_cons_ptr =
858 &sblk->status_tx_quick_consumer_index;
859 bnapi->hw_rx_cons_ptr =
860 &sblk->status_rx_quick_consumer_index;
Michael Chanb4b36042007-12-20 19:59:30 -0800861 bnapi->int_num = i << 24;
862 }
863 }
Michael Chan35efa7c2007-12-20 19:56:37 -0800864
Michael Chan43e80b82008-06-19 16:41:08 -0700865 bp->stats_blk = status_blk + status_blk_size;
Michael Chanb6016b72005-05-26 13:03:09 -0700866
Michael Chan0f31f992006-03-23 01:12:38 -0800867 bp->stats_blk_mapping = bp->status_blk_mapping + status_blk_size;
Michael Chanb6016b72005-05-26 13:03:09 -0700868
Michael Chan59b47d82006-11-19 14:10:45 -0800869 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
870 bp->ctx_pages = 0x2000 / BCM_PAGE_SIZE;
871 if (bp->ctx_pages == 0)
872 bp->ctx_pages = 1;
873 for (i = 0; i < bp->ctx_pages; i++) {
874 bp->ctx_blk[i] = pci_alloc_consistent(bp->pdev,
875 BCM_PAGE_SIZE,
876 &bp->ctx_blk_mapping[i]);
877 if (bp->ctx_blk[i] == NULL)
878 goto alloc_mem_err;
879 }
880 }
Michael Chan35e90102008-06-19 16:37:42 -0700881
Michael Chanbb4f98a2008-06-19 16:38:19 -0700882 err = bnx2_alloc_rx_mem(bp);
883 if (err)
884 goto alloc_mem_err;
885
Michael Chan35e90102008-06-19 16:37:42 -0700886 err = bnx2_alloc_tx_mem(bp);
887 if (err)
888 goto alloc_mem_err;
889
Michael Chanb6016b72005-05-26 13:03:09 -0700890 return 0;
891
892alloc_mem_err:
893 bnx2_free_mem(bp);
894 return -ENOMEM;
895}
896
897static void
Michael Chane3648b32005-11-04 08:51:21 -0800898bnx2_report_fw_link(struct bnx2 *bp)
899{
900 u32 fw_link_status = 0;
901
Michael Chan583c28e2008-01-21 19:51:35 -0800902 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
Michael Chan0d8a6572007-07-07 22:49:43 -0700903 return;
904
Michael Chane3648b32005-11-04 08:51:21 -0800905 if (bp->link_up) {
906 u32 bmsr;
907
908 switch (bp->line_speed) {
909 case SPEED_10:
910 if (bp->duplex == DUPLEX_HALF)
911 fw_link_status = BNX2_LINK_STATUS_10HALF;
912 else
913 fw_link_status = BNX2_LINK_STATUS_10FULL;
914 break;
915 case SPEED_100:
916 if (bp->duplex == DUPLEX_HALF)
917 fw_link_status = BNX2_LINK_STATUS_100HALF;
918 else
919 fw_link_status = BNX2_LINK_STATUS_100FULL;
920 break;
921 case SPEED_1000:
922 if (bp->duplex == DUPLEX_HALF)
923 fw_link_status = BNX2_LINK_STATUS_1000HALF;
924 else
925 fw_link_status = BNX2_LINK_STATUS_1000FULL;
926 break;
927 case SPEED_2500:
928 if (bp->duplex == DUPLEX_HALF)
929 fw_link_status = BNX2_LINK_STATUS_2500HALF;
930 else
931 fw_link_status = BNX2_LINK_STATUS_2500FULL;
932 break;
933 }
934
935 fw_link_status |= BNX2_LINK_STATUS_LINK_UP;
936
937 if (bp->autoneg) {
938 fw_link_status |= BNX2_LINK_STATUS_AN_ENABLED;
939
Michael Chanca58c3a2007-05-03 13:22:52 -0700940 bnx2_read_phy(bp, bp->mii_bmsr, &bmsr);
941 bnx2_read_phy(bp, bp->mii_bmsr, &bmsr);
Michael Chane3648b32005-11-04 08:51:21 -0800942
943 if (!(bmsr & BMSR_ANEGCOMPLETE) ||
Michael Chan583c28e2008-01-21 19:51:35 -0800944 bp->phy_flags & BNX2_PHY_FLAG_PARALLEL_DETECT)
Michael Chane3648b32005-11-04 08:51:21 -0800945 fw_link_status |= BNX2_LINK_STATUS_PARALLEL_DET;
946 else
947 fw_link_status |= BNX2_LINK_STATUS_AN_COMPLETE;
948 }
949 }
950 else
951 fw_link_status = BNX2_LINK_STATUS_LINK_DOWN;
952
Michael Chan2726d6e2008-01-29 21:35:05 -0800953 bnx2_shmem_wr(bp, BNX2_LINK_STATUS, fw_link_status);
Michael Chane3648b32005-11-04 08:51:21 -0800954}
955
Michael Chan9b1084b2007-07-07 22:50:37 -0700956static char *
957bnx2_xceiver_str(struct bnx2 *bp)
958{
959 return ((bp->phy_port == PORT_FIBRE) ? "SerDes" :
Michael Chan583c28e2008-01-21 19:51:35 -0800960 ((bp->phy_flags & BNX2_PHY_FLAG_SERDES) ? "Remote Copper" :
Michael Chan9b1084b2007-07-07 22:50:37 -0700961 "Copper"));
962}
963
Michael Chane3648b32005-11-04 08:51:21 -0800964static void
Michael Chanb6016b72005-05-26 13:03:09 -0700965bnx2_report_link(struct bnx2 *bp)
966{
967 if (bp->link_up) {
968 netif_carrier_on(bp->dev);
Michael Chan9b1084b2007-07-07 22:50:37 -0700969 printk(KERN_INFO PFX "%s NIC %s Link is Up, ", bp->dev->name,
970 bnx2_xceiver_str(bp));
Michael Chanb6016b72005-05-26 13:03:09 -0700971
972 printk("%d Mbps ", bp->line_speed);
973
974 if (bp->duplex == DUPLEX_FULL)
975 printk("full duplex");
976 else
977 printk("half duplex");
978
979 if (bp->flow_ctrl) {
980 if (bp->flow_ctrl & FLOW_CTRL_RX) {
981 printk(", receive ");
982 if (bp->flow_ctrl & FLOW_CTRL_TX)
983 printk("& transmit ");
984 }
985 else {
986 printk(", transmit ");
987 }
988 printk("flow control ON");
989 }
990 printk("\n");
991 }
992 else {
993 netif_carrier_off(bp->dev);
Michael Chan9b1084b2007-07-07 22:50:37 -0700994 printk(KERN_ERR PFX "%s NIC %s Link is Down\n", bp->dev->name,
995 bnx2_xceiver_str(bp));
Michael Chanb6016b72005-05-26 13:03:09 -0700996 }
Michael Chane3648b32005-11-04 08:51:21 -0800997
998 bnx2_report_fw_link(bp);
Michael Chanb6016b72005-05-26 13:03:09 -0700999}
1000
1001static void
1002bnx2_resolve_flow_ctrl(struct bnx2 *bp)
1003{
1004 u32 local_adv, remote_adv;
1005
1006 bp->flow_ctrl = 0;
Jeff Garzik6aa20a22006-09-13 13:24:59 -04001007 if ((bp->autoneg & (AUTONEG_SPEED | AUTONEG_FLOW_CTRL)) !=
Michael Chanb6016b72005-05-26 13:03:09 -07001008 (AUTONEG_SPEED | AUTONEG_FLOW_CTRL)) {
1009
1010 if (bp->duplex == DUPLEX_FULL) {
1011 bp->flow_ctrl = bp->req_flow_ctrl;
1012 }
1013 return;
1014 }
1015
1016 if (bp->duplex != DUPLEX_FULL) {
1017 return;
1018 }
1019
Michael Chan583c28e2008-01-21 19:51:35 -08001020 if ((bp->phy_flags & BNX2_PHY_FLAG_SERDES) &&
Michael Chan5b0c76a2005-11-04 08:45:49 -08001021 (CHIP_NUM(bp) == CHIP_NUM_5708)) {
1022 u32 val;
1023
1024 bnx2_read_phy(bp, BCM5708S_1000X_STAT1, &val);
1025 if (val & BCM5708S_1000X_STAT1_TX_PAUSE)
1026 bp->flow_ctrl |= FLOW_CTRL_TX;
1027 if (val & BCM5708S_1000X_STAT1_RX_PAUSE)
1028 bp->flow_ctrl |= FLOW_CTRL_RX;
1029 return;
1030 }
1031
Michael Chanca58c3a2007-05-03 13:22:52 -07001032 bnx2_read_phy(bp, bp->mii_adv, &local_adv);
1033 bnx2_read_phy(bp, bp->mii_lpa, &remote_adv);
Michael Chanb6016b72005-05-26 13:03:09 -07001034
Michael Chan583c28e2008-01-21 19:51:35 -08001035 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Michael Chanb6016b72005-05-26 13:03:09 -07001036 u32 new_local_adv = 0;
1037 u32 new_remote_adv = 0;
1038
1039 if (local_adv & ADVERTISE_1000XPAUSE)
1040 new_local_adv |= ADVERTISE_PAUSE_CAP;
1041 if (local_adv & ADVERTISE_1000XPSE_ASYM)
1042 new_local_adv |= ADVERTISE_PAUSE_ASYM;
1043 if (remote_adv & ADVERTISE_1000XPAUSE)
1044 new_remote_adv |= ADVERTISE_PAUSE_CAP;
1045 if (remote_adv & ADVERTISE_1000XPSE_ASYM)
1046 new_remote_adv |= ADVERTISE_PAUSE_ASYM;
1047
1048 local_adv = new_local_adv;
1049 remote_adv = new_remote_adv;
1050 }
1051
1052 /* See Table 28B-3 of 802.3ab-1999 spec. */
1053 if (local_adv & ADVERTISE_PAUSE_CAP) {
1054 if(local_adv & ADVERTISE_PAUSE_ASYM) {
1055 if (remote_adv & ADVERTISE_PAUSE_CAP) {
1056 bp->flow_ctrl = FLOW_CTRL_TX | FLOW_CTRL_RX;
1057 }
1058 else if (remote_adv & ADVERTISE_PAUSE_ASYM) {
1059 bp->flow_ctrl = FLOW_CTRL_RX;
1060 }
1061 }
1062 else {
1063 if (remote_adv & ADVERTISE_PAUSE_CAP) {
1064 bp->flow_ctrl = FLOW_CTRL_TX | FLOW_CTRL_RX;
1065 }
1066 }
1067 }
1068 else if (local_adv & ADVERTISE_PAUSE_ASYM) {
1069 if ((remote_adv & ADVERTISE_PAUSE_CAP) &&
1070 (remote_adv & ADVERTISE_PAUSE_ASYM)) {
1071
1072 bp->flow_ctrl = FLOW_CTRL_TX;
1073 }
1074 }
1075}
1076
1077static int
Michael Chan27a005b2007-05-03 13:23:41 -07001078bnx2_5709s_linkup(struct bnx2 *bp)
1079{
1080 u32 val, speed;
1081
1082 bp->link_up = 1;
1083
1084 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_GP_STATUS);
1085 bnx2_read_phy(bp, MII_BNX2_GP_TOP_AN_STATUS1, &val);
1086 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
1087
1088 if ((bp->autoneg & AUTONEG_SPEED) == 0) {
1089 bp->line_speed = bp->req_line_speed;
1090 bp->duplex = bp->req_duplex;
1091 return 0;
1092 }
1093 speed = val & MII_BNX2_GP_TOP_AN_SPEED_MSK;
1094 switch (speed) {
1095 case MII_BNX2_GP_TOP_AN_SPEED_10:
1096 bp->line_speed = SPEED_10;
1097 break;
1098 case MII_BNX2_GP_TOP_AN_SPEED_100:
1099 bp->line_speed = SPEED_100;
1100 break;
1101 case MII_BNX2_GP_TOP_AN_SPEED_1G:
1102 case MII_BNX2_GP_TOP_AN_SPEED_1GKV:
1103 bp->line_speed = SPEED_1000;
1104 break;
1105 case MII_BNX2_GP_TOP_AN_SPEED_2_5G:
1106 bp->line_speed = SPEED_2500;
1107 break;
1108 }
1109 if (val & MII_BNX2_GP_TOP_AN_FD)
1110 bp->duplex = DUPLEX_FULL;
1111 else
1112 bp->duplex = DUPLEX_HALF;
1113 return 0;
1114}
1115
1116static int
Michael Chan5b0c76a2005-11-04 08:45:49 -08001117bnx2_5708s_linkup(struct bnx2 *bp)
1118{
1119 u32 val;
1120
1121 bp->link_up = 1;
1122 bnx2_read_phy(bp, BCM5708S_1000X_STAT1, &val);
1123 switch (val & BCM5708S_1000X_STAT1_SPEED_MASK) {
1124 case BCM5708S_1000X_STAT1_SPEED_10:
1125 bp->line_speed = SPEED_10;
1126 break;
1127 case BCM5708S_1000X_STAT1_SPEED_100:
1128 bp->line_speed = SPEED_100;
1129 break;
1130 case BCM5708S_1000X_STAT1_SPEED_1G:
1131 bp->line_speed = SPEED_1000;
1132 break;
1133 case BCM5708S_1000X_STAT1_SPEED_2G5:
1134 bp->line_speed = SPEED_2500;
1135 break;
1136 }
1137 if (val & BCM5708S_1000X_STAT1_FD)
1138 bp->duplex = DUPLEX_FULL;
1139 else
1140 bp->duplex = DUPLEX_HALF;
1141
1142 return 0;
1143}
1144
1145static int
1146bnx2_5706s_linkup(struct bnx2 *bp)
Michael Chanb6016b72005-05-26 13:03:09 -07001147{
1148 u32 bmcr, local_adv, remote_adv, common;
1149
1150 bp->link_up = 1;
1151 bp->line_speed = SPEED_1000;
1152
Michael Chanca58c3a2007-05-03 13:22:52 -07001153 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chanb6016b72005-05-26 13:03:09 -07001154 if (bmcr & BMCR_FULLDPLX) {
1155 bp->duplex = DUPLEX_FULL;
1156 }
1157 else {
1158 bp->duplex = DUPLEX_HALF;
1159 }
1160
1161 if (!(bmcr & BMCR_ANENABLE)) {
1162 return 0;
1163 }
1164
Michael Chanca58c3a2007-05-03 13:22:52 -07001165 bnx2_read_phy(bp, bp->mii_adv, &local_adv);
1166 bnx2_read_phy(bp, bp->mii_lpa, &remote_adv);
Michael Chanb6016b72005-05-26 13:03:09 -07001167
1168 common = local_adv & remote_adv;
1169 if (common & (ADVERTISE_1000XHALF | ADVERTISE_1000XFULL)) {
1170
1171 if (common & ADVERTISE_1000XFULL) {
1172 bp->duplex = DUPLEX_FULL;
1173 }
1174 else {
1175 bp->duplex = DUPLEX_HALF;
1176 }
1177 }
1178
1179 return 0;
1180}
1181
1182static int
1183bnx2_copper_linkup(struct bnx2 *bp)
1184{
1185 u32 bmcr;
1186
Michael Chanca58c3a2007-05-03 13:22:52 -07001187 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chanb6016b72005-05-26 13:03:09 -07001188 if (bmcr & BMCR_ANENABLE) {
1189 u32 local_adv, remote_adv, common;
1190
1191 bnx2_read_phy(bp, MII_CTRL1000, &local_adv);
1192 bnx2_read_phy(bp, MII_STAT1000, &remote_adv);
1193
1194 common = local_adv & (remote_adv >> 2);
1195 if (common & ADVERTISE_1000FULL) {
1196 bp->line_speed = SPEED_1000;
1197 bp->duplex = DUPLEX_FULL;
1198 }
1199 else if (common & ADVERTISE_1000HALF) {
1200 bp->line_speed = SPEED_1000;
1201 bp->duplex = DUPLEX_HALF;
1202 }
1203 else {
Michael Chanca58c3a2007-05-03 13:22:52 -07001204 bnx2_read_phy(bp, bp->mii_adv, &local_adv);
1205 bnx2_read_phy(bp, bp->mii_lpa, &remote_adv);
Michael Chanb6016b72005-05-26 13:03:09 -07001206
1207 common = local_adv & remote_adv;
1208 if (common & ADVERTISE_100FULL) {
1209 bp->line_speed = SPEED_100;
1210 bp->duplex = DUPLEX_FULL;
1211 }
1212 else if (common & ADVERTISE_100HALF) {
1213 bp->line_speed = SPEED_100;
1214 bp->duplex = DUPLEX_HALF;
1215 }
1216 else if (common & ADVERTISE_10FULL) {
1217 bp->line_speed = SPEED_10;
1218 bp->duplex = DUPLEX_FULL;
1219 }
1220 else if (common & ADVERTISE_10HALF) {
1221 bp->line_speed = SPEED_10;
1222 bp->duplex = DUPLEX_HALF;
1223 }
1224 else {
1225 bp->line_speed = 0;
1226 bp->link_up = 0;
1227 }
1228 }
1229 }
1230 else {
1231 if (bmcr & BMCR_SPEED100) {
1232 bp->line_speed = SPEED_100;
1233 }
1234 else {
1235 bp->line_speed = SPEED_10;
1236 }
1237 if (bmcr & BMCR_FULLDPLX) {
1238 bp->duplex = DUPLEX_FULL;
1239 }
1240 else {
1241 bp->duplex = DUPLEX_HALF;
1242 }
1243 }
1244
1245 return 0;
1246}
1247
Michael Chan83e3fc82008-01-29 21:37:17 -08001248static void
Michael Chanbb4f98a2008-06-19 16:38:19 -07001249bnx2_init_rx_context(struct bnx2 *bp, u32 cid)
Michael Chan83e3fc82008-01-29 21:37:17 -08001250{
Michael Chanbb4f98a2008-06-19 16:38:19 -07001251 u32 val, rx_cid_addr = GET_CID_ADDR(cid);
Michael Chan83e3fc82008-01-29 21:37:17 -08001252
1253 val = BNX2_L2CTX_CTX_TYPE_CTX_BD_CHN_TYPE_VALUE;
1254 val |= BNX2_L2CTX_CTX_TYPE_SIZE_L2;
1255 val |= 0x02 << 8;
1256
1257 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
1258 u32 lo_water, hi_water;
1259
1260 if (bp->flow_ctrl & FLOW_CTRL_TX)
1261 lo_water = BNX2_L2CTX_LO_WATER_MARK_DEFAULT;
1262 else
1263 lo_water = BNX2_L2CTX_LO_WATER_MARK_DIS;
1264 if (lo_water >= bp->rx_ring_size)
1265 lo_water = 0;
1266
1267 hi_water = bp->rx_ring_size / 4;
1268
1269 if (hi_water <= lo_water)
1270 lo_water = 0;
1271
1272 hi_water /= BNX2_L2CTX_HI_WATER_MARK_SCALE;
1273 lo_water /= BNX2_L2CTX_LO_WATER_MARK_SCALE;
1274
1275 if (hi_water > 0xf)
1276 hi_water = 0xf;
1277 else if (hi_water == 0)
1278 lo_water = 0;
1279 val |= lo_water | (hi_water << BNX2_L2CTX_HI_WATER_MARK_SHIFT);
1280 }
1281 bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_CTX_TYPE, val);
1282}
1283
Michael Chanbb4f98a2008-06-19 16:38:19 -07001284static void
1285bnx2_init_all_rx_contexts(struct bnx2 *bp)
1286{
1287 int i;
1288 u32 cid;
1289
1290 for (i = 0, cid = RX_CID; i < bp->num_rx_rings; i++, cid++) {
1291 if (i == 1)
1292 cid = RX_RSS_CID;
1293 bnx2_init_rx_context(bp, cid);
1294 }
1295}
1296
Benjamin Li344478d2008-09-18 16:38:24 -07001297static void
Michael Chanb6016b72005-05-26 13:03:09 -07001298bnx2_set_mac_link(struct bnx2 *bp)
1299{
1300 u32 val;
1301
1302 REG_WR(bp, BNX2_EMAC_TX_LENGTHS, 0x2620);
1303 if (bp->link_up && (bp->line_speed == SPEED_1000) &&
1304 (bp->duplex == DUPLEX_HALF)) {
1305 REG_WR(bp, BNX2_EMAC_TX_LENGTHS, 0x26ff);
1306 }
1307
1308 /* Configure the EMAC mode register. */
1309 val = REG_RD(bp, BNX2_EMAC_MODE);
1310
1311 val &= ~(BNX2_EMAC_MODE_PORT | BNX2_EMAC_MODE_HALF_DUPLEX |
Michael Chan5b0c76a2005-11-04 08:45:49 -08001312 BNX2_EMAC_MODE_MAC_LOOP | BNX2_EMAC_MODE_FORCE_LINK |
Michael Chan59b47d82006-11-19 14:10:45 -08001313 BNX2_EMAC_MODE_25G_MODE);
Michael Chanb6016b72005-05-26 13:03:09 -07001314
1315 if (bp->link_up) {
Michael Chan5b0c76a2005-11-04 08:45:49 -08001316 switch (bp->line_speed) {
1317 case SPEED_10:
Michael Chan59b47d82006-11-19 14:10:45 -08001318 if (CHIP_NUM(bp) != CHIP_NUM_5706) {
1319 val |= BNX2_EMAC_MODE_PORT_MII_10M;
Michael Chan5b0c76a2005-11-04 08:45:49 -08001320 break;
1321 }
1322 /* fall through */
1323 case SPEED_100:
1324 val |= BNX2_EMAC_MODE_PORT_MII;
1325 break;
1326 case SPEED_2500:
Michael Chan59b47d82006-11-19 14:10:45 -08001327 val |= BNX2_EMAC_MODE_25G_MODE;
Michael Chan5b0c76a2005-11-04 08:45:49 -08001328 /* fall through */
1329 case SPEED_1000:
1330 val |= BNX2_EMAC_MODE_PORT_GMII;
1331 break;
1332 }
Michael Chanb6016b72005-05-26 13:03:09 -07001333 }
1334 else {
1335 val |= BNX2_EMAC_MODE_PORT_GMII;
1336 }
1337
1338 /* Set the MAC to operate in the appropriate duplex mode. */
1339 if (bp->duplex == DUPLEX_HALF)
1340 val |= BNX2_EMAC_MODE_HALF_DUPLEX;
1341 REG_WR(bp, BNX2_EMAC_MODE, val);
1342
1343 /* Enable/disable rx PAUSE. */
1344 bp->rx_mode &= ~BNX2_EMAC_RX_MODE_FLOW_EN;
1345
1346 if (bp->flow_ctrl & FLOW_CTRL_RX)
1347 bp->rx_mode |= BNX2_EMAC_RX_MODE_FLOW_EN;
1348 REG_WR(bp, BNX2_EMAC_RX_MODE, bp->rx_mode);
1349
1350 /* Enable/disable tx PAUSE. */
1351 val = REG_RD(bp, BNX2_EMAC_TX_MODE);
1352 val &= ~BNX2_EMAC_TX_MODE_FLOW_EN;
1353
1354 if (bp->flow_ctrl & FLOW_CTRL_TX)
1355 val |= BNX2_EMAC_TX_MODE_FLOW_EN;
1356 REG_WR(bp, BNX2_EMAC_TX_MODE, val);
1357
1358 /* Acknowledge the interrupt. */
1359 REG_WR(bp, BNX2_EMAC_STATUS, BNX2_EMAC_STATUS_LINK_CHANGE);
1360
Michael Chan83e3fc82008-01-29 21:37:17 -08001361 if (CHIP_NUM(bp) == CHIP_NUM_5709)
Michael Chanbb4f98a2008-06-19 16:38:19 -07001362 bnx2_init_all_rx_contexts(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07001363}
1364
Michael Chan27a005b2007-05-03 13:23:41 -07001365static void
1366bnx2_enable_bmsr1(struct bnx2 *bp)
1367{
Michael Chan583c28e2008-01-21 19:51:35 -08001368 if ((bp->phy_flags & BNX2_PHY_FLAG_SERDES) &&
Michael Chan27a005b2007-05-03 13:23:41 -07001369 (CHIP_NUM(bp) == CHIP_NUM_5709))
1370 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
1371 MII_BNX2_BLK_ADDR_GP_STATUS);
1372}
1373
1374static void
1375bnx2_disable_bmsr1(struct bnx2 *bp)
1376{
Michael Chan583c28e2008-01-21 19:51:35 -08001377 if ((bp->phy_flags & BNX2_PHY_FLAG_SERDES) &&
Michael Chan27a005b2007-05-03 13:23:41 -07001378 (CHIP_NUM(bp) == CHIP_NUM_5709))
1379 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
1380 MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
1381}
1382
Michael Chanb6016b72005-05-26 13:03:09 -07001383static int
Michael Chan605a9e22007-05-03 13:23:13 -07001384bnx2_test_and_enable_2g5(struct bnx2 *bp)
1385{
1386 u32 up1;
1387 int ret = 1;
1388
Michael Chan583c28e2008-01-21 19:51:35 -08001389 if (!(bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE))
Michael Chan605a9e22007-05-03 13:23:13 -07001390 return 0;
1391
1392 if (bp->autoneg & AUTONEG_SPEED)
1393 bp->advertising |= ADVERTISED_2500baseX_Full;
1394
Michael Chan27a005b2007-05-03 13:23:41 -07001395 if (CHIP_NUM(bp) == CHIP_NUM_5709)
1396 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_OVER1G);
1397
Michael Chan605a9e22007-05-03 13:23:13 -07001398 bnx2_read_phy(bp, bp->mii_up1, &up1);
1399 if (!(up1 & BCM5708S_UP1_2G5)) {
1400 up1 |= BCM5708S_UP1_2G5;
1401 bnx2_write_phy(bp, bp->mii_up1, up1);
1402 ret = 0;
1403 }
1404
Michael Chan27a005b2007-05-03 13:23:41 -07001405 if (CHIP_NUM(bp) == CHIP_NUM_5709)
1406 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
1407 MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
1408
Michael Chan605a9e22007-05-03 13:23:13 -07001409 return ret;
1410}
1411
1412static int
1413bnx2_test_and_disable_2g5(struct bnx2 *bp)
1414{
1415 u32 up1;
1416 int ret = 0;
1417
Michael Chan583c28e2008-01-21 19:51:35 -08001418 if (!(bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE))
Michael Chan605a9e22007-05-03 13:23:13 -07001419 return 0;
1420
Michael Chan27a005b2007-05-03 13:23:41 -07001421 if (CHIP_NUM(bp) == CHIP_NUM_5709)
1422 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_OVER1G);
1423
Michael Chan605a9e22007-05-03 13:23:13 -07001424 bnx2_read_phy(bp, bp->mii_up1, &up1);
1425 if (up1 & BCM5708S_UP1_2G5) {
1426 up1 &= ~BCM5708S_UP1_2G5;
1427 bnx2_write_phy(bp, bp->mii_up1, up1);
1428 ret = 1;
1429 }
1430
Michael Chan27a005b2007-05-03 13:23:41 -07001431 if (CHIP_NUM(bp) == CHIP_NUM_5709)
1432 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
1433 MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
1434
Michael Chan605a9e22007-05-03 13:23:13 -07001435 return ret;
1436}
1437
1438static void
1439bnx2_enable_forced_2g5(struct bnx2 *bp)
1440{
1441 u32 bmcr;
1442
Michael Chan583c28e2008-01-21 19:51:35 -08001443 if (!(bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE))
Michael Chan605a9e22007-05-03 13:23:13 -07001444 return;
1445
Michael Chan27a005b2007-05-03 13:23:41 -07001446 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
1447 u32 val;
1448
1449 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
1450 MII_BNX2_BLK_ADDR_SERDES_DIG);
1451 bnx2_read_phy(bp, MII_BNX2_SERDES_DIG_MISC1, &val);
1452 val &= ~MII_BNX2_SD_MISC1_FORCE_MSK;
1453 val |= MII_BNX2_SD_MISC1_FORCE | MII_BNX2_SD_MISC1_FORCE_2_5G;
1454 bnx2_write_phy(bp, MII_BNX2_SERDES_DIG_MISC1, val);
1455
1456 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
1457 MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
1458 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
1459
1460 } else if (CHIP_NUM(bp) == CHIP_NUM_5708) {
Michael Chan605a9e22007-05-03 13:23:13 -07001461 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
1462 bmcr |= BCM5708S_BMCR_FORCE_2500;
1463 }
1464
1465 if (bp->autoneg & AUTONEG_SPEED) {
1466 bmcr &= ~BMCR_ANENABLE;
1467 if (bp->req_duplex == DUPLEX_FULL)
1468 bmcr |= BMCR_FULLDPLX;
1469 }
1470 bnx2_write_phy(bp, bp->mii_bmcr, bmcr);
1471}
1472
1473static void
1474bnx2_disable_forced_2g5(struct bnx2 *bp)
1475{
1476 u32 bmcr;
1477
Michael Chan583c28e2008-01-21 19:51:35 -08001478 if (!(bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE))
Michael Chan605a9e22007-05-03 13:23:13 -07001479 return;
1480
Michael Chan27a005b2007-05-03 13:23:41 -07001481 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
1482 u32 val;
1483
1484 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
1485 MII_BNX2_BLK_ADDR_SERDES_DIG);
1486 bnx2_read_phy(bp, MII_BNX2_SERDES_DIG_MISC1, &val);
1487 val &= ~MII_BNX2_SD_MISC1_FORCE;
1488 bnx2_write_phy(bp, MII_BNX2_SERDES_DIG_MISC1, val);
1489
1490 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
1491 MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
1492 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
1493
1494 } else if (CHIP_NUM(bp) == CHIP_NUM_5708) {
Michael Chan605a9e22007-05-03 13:23:13 -07001495 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
1496 bmcr &= ~BCM5708S_BMCR_FORCE_2500;
1497 }
1498
1499 if (bp->autoneg & AUTONEG_SPEED)
1500 bmcr |= BMCR_SPEED1000 | BMCR_ANENABLE | BMCR_ANRESTART;
1501 bnx2_write_phy(bp, bp->mii_bmcr, bmcr);
1502}
1503
Michael Chanb2fadea2008-01-21 17:07:06 -08001504static void
1505bnx2_5706s_force_link_dn(struct bnx2 *bp, int start)
1506{
1507 u32 val;
1508
1509 bnx2_write_phy(bp, MII_BNX2_DSP_ADDRESS, MII_EXPAND_SERDES_CTL);
1510 bnx2_read_phy(bp, MII_BNX2_DSP_RW_PORT, &val);
1511 if (start)
1512 bnx2_write_phy(bp, MII_BNX2_DSP_RW_PORT, val & 0xff0f);
1513 else
1514 bnx2_write_phy(bp, MII_BNX2_DSP_RW_PORT, val | 0xc0);
1515}
1516
Michael Chan605a9e22007-05-03 13:23:13 -07001517static int
Michael Chanb6016b72005-05-26 13:03:09 -07001518bnx2_set_link(struct bnx2 *bp)
1519{
1520 u32 bmsr;
1521 u8 link_up;
1522
Michael Chan80be4432006-11-19 14:07:28 -08001523 if (bp->loopback == MAC_LOOPBACK || bp->loopback == PHY_LOOPBACK) {
Michael Chanb6016b72005-05-26 13:03:09 -07001524 bp->link_up = 1;
1525 return 0;
1526 }
1527
Michael Chan583c28e2008-01-21 19:51:35 -08001528 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
Michael Chan0d8a6572007-07-07 22:49:43 -07001529 return 0;
1530
Michael Chanb6016b72005-05-26 13:03:09 -07001531 link_up = bp->link_up;
1532
Michael Chan27a005b2007-05-03 13:23:41 -07001533 bnx2_enable_bmsr1(bp);
1534 bnx2_read_phy(bp, bp->mii_bmsr1, &bmsr);
1535 bnx2_read_phy(bp, bp->mii_bmsr1, &bmsr);
1536 bnx2_disable_bmsr1(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07001537
Michael Chan583c28e2008-01-21 19:51:35 -08001538 if ((bp->phy_flags & BNX2_PHY_FLAG_SERDES) &&
Michael Chanb6016b72005-05-26 13:03:09 -07001539 (CHIP_NUM(bp) == CHIP_NUM_5706)) {
Michael Chana2724e22008-02-23 19:47:44 -08001540 u32 val, an_dbg;
Michael Chanb6016b72005-05-26 13:03:09 -07001541
Michael Chan583c28e2008-01-21 19:51:35 -08001542 if (bp->phy_flags & BNX2_PHY_FLAG_FORCED_DOWN) {
Michael Chanb2fadea2008-01-21 17:07:06 -08001543 bnx2_5706s_force_link_dn(bp, 0);
Michael Chan583c28e2008-01-21 19:51:35 -08001544 bp->phy_flags &= ~BNX2_PHY_FLAG_FORCED_DOWN;
Michael Chanb2fadea2008-01-21 17:07:06 -08001545 }
Michael Chanb6016b72005-05-26 13:03:09 -07001546 val = REG_RD(bp, BNX2_EMAC_STATUS);
Michael Chana2724e22008-02-23 19:47:44 -08001547
1548 bnx2_write_phy(bp, MII_BNX2_MISC_SHADOW, MISC_SHDW_AN_DBG);
1549 bnx2_read_phy(bp, MII_BNX2_MISC_SHADOW, &an_dbg);
1550 bnx2_read_phy(bp, MII_BNX2_MISC_SHADOW, &an_dbg);
1551
1552 if ((val & BNX2_EMAC_STATUS_LINK) &&
1553 !(an_dbg & MISC_SHDW_AN_DBG_NOSYNC))
Michael Chanb6016b72005-05-26 13:03:09 -07001554 bmsr |= BMSR_LSTATUS;
1555 else
1556 bmsr &= ~BMSR_LSTATUS;
1557 }
1558
1559 if (bmsr & BMSR_LSTATUS) {
1560 bp->link_up = 1;
1561
Michael Chan583c28e2008-01-21 19:51:35 -08001562 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Michael Chan5b0c76a2005-11-04 08:45:49 -08001563 if (CHIP_NUM(bp) == CHIP_NUM_5706)
1564 bnx2_5706s_linkup(bp);
1565 else if (CHIP_NUM(bp) == CHIP_NUM_5708)
1566 bnx2_5708s_linkup(bp);
Michael Chan27a005b2007-05-03 13:23:41 -07001567 else if (CHIP_NUM(bp) == CHIP_NUM_5709)
1568 bnx2_5709s_linkup(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07001569 }
1570 else {
1571 bnx2_copper_linkup(bp);
1572 }
1573 bnx2_resolve_flow_ctrl(bp);
1574 }
1575 else {
Michael Chan583c28e2008-01-21 19:51:35 -08001576 if ((bp->phy_flags & BNX2_PHY_FLAG_SERDES) &&
Michael Chan605a9e22007-05-03 13:23:13 -07001577 (bp->autoneg & AUTONEG_SPEED))
1578 bnx2_disable_forced_2g5(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07001579
Michael Chan583c28e2008-01-21 19:51:35 -08001580 if (bp->phy_flags & BNX2_PHY_FLAG_PARALLEL_DETECT) {
Michael Chanb2fadea2008-01-21 17:07:06 -08001581 u32 bmcr;
1582
1583 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
1584 bmcr |= BMCR_ANENABLE;
1585 bnx2_write_phy(bp, bp->mii_bmcr, bmcr);
1586
Michael Chan583c28e2008-01-21 19:51:35 -08001587 bp->phy_flags &= ~BNX2_PHY_FLAG_PARALLEL_DETECT;
Michael Chanb2fadea2008-01-21 17:07:06 -08001588 }
Michael Chanb6016b72005-05-26 13:03:09 -07001589 bp->link_up = 0;
1590 }
1591
1592 if (bp->link_up != link_up) {
1593 bnx2_report_link(bp);
1594 }
1595
1596 bnx2_set_mac_link(bp);
1597
1598 return 0;
1599}
1600
1601static int
1602bnx2_reset_phy(struct bnx2 *bp)
1603{
1604 int i;
1605 u32 reg;
1606
Michael Chanca58c3a2007-05-03 13:22:52 -07001607 bnx2_write_phy(bp, bp->mii_bmcr, BMCR_RESET);
Michael Chanb6016b72005-05-26 13:03:09 -07001608
1609#define PHY_RESET_MAX_WAIT 100
1610 for (i = 0; i < PHY_RESET_MAX_WAIT; i++) {
1611 udelay(10);
1612
Michael Chanca58c3a2007-05-03 13:22:52 -07001613 bnx2_read_phy(bp, bp->mii_bmcr, &reg);
Michael Chanb6016b72005-05-26 13:03:09 -07001614 if (!(reg & BMCR_RESET)) {
1615 udelay(20);
1616 break;
1617 }
1618 }
1619 if (i == PHY_RESET_MAX_WAIT) {
1620 return -EBUSY;
1621 }
1622 return 0;
1623}
1624
1625static u32
1626bnx2_phy_get_pause_adv(struct bnx2 *bp)
1627{
1628 u32 adv = 0;
1629
1630 if ((bp->req_flow_ctrl & (FLOW_CTRL_RX | FLOW_CTRL_TX)) ==
1631 (FLOW_CTRL_RX | FLOW_CTRL_TX)) {
1632
Michael Chan583c28e2008-01-21 19:51:35 -08001633 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Michael Chanb6016b72005-05-26 13:03:09 -07001634 adv = ADVERTISE_1000XPAUSE;
1635 }
1636 else {
1637 adv = ADVERTISE_PAUSE_CAP;
1638 }
1639 }
1640 else if (bp->req_flow_ctrl & FLOW_CTRL_TX) {
Michael Chan583c28e2008-01-21 19:51:35 -08001641 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Michael Chanb6016b72005-05-26 13:03:09 -07001642 adv = ADVERTISE_1000XPSE_ASYM;
1643 }
1644 else {
1645 adv = ADVERTISE_PAUSE_ASYM;
1646 }
1647 }
1648 else if (bp->req_flow_ctrl & FLOW_CTRL_RX) {
Michael Chan583c28e2008-01-21 19:51:35 -08001649 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Michael Chanb6016b72005-05-26 13:03:09 -07001650 adv = ADVERTISE_1000XPAUSE | ADVERTISE_1000XPSE_ASYM;
1651 }
1652 else {
1653 adv = ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM;
1654 }
1655 }
1656 return adv;
1657}
1658
Michael Chana2f13892008-07-14 22:38:23 -07001659static int bnx2_fw_sync(struct bnx2 *, u32, int, int);
Michael Chan0d8a6572007-07-07 22:49:43 -07001660
Michael Chanb6016b72005-05-26 13:03:09 -07001661static int
Michael Chan0d8a6572007-07-07 22:49:43 -07001662bnx2_setup_remote_phy(struct bnx2 *bp, u8 port)
Harvey Harrison52d07b12009-01-19 17:27:06 -08001663__releases(&bp->phy_lock)
1664__acquires(&bp->phy_lock)
Michael Chan0d8a6572007-07-07 22:49:43 -07001665{
1666 u32 speed_arg = 0, pause_adv;
1667
1668 pause_adv = bnx2_phy_get_pause_adv(bp);
1669
1670 if (bp->autoneg & AUTONEG_SPEED) {
1671 speed_arg |= BNX2_NETLINK_SET_LINK_ENABLE_AUTONEG;
1672 if (bp->advertising & ADVERTISED_10baseT_Half)
1673 speed_arg |= BNX2_NETLINK_SET_LINK_SPEED_10HALF;
1674 if (bp->advertising & ADVERTISED_10baseT_Full)
1675 speed_arg |= BNX2_NETLINK_SET_LINK_SPEED_10FULL;
1676 if (bp->advertising & ADVERTISED_100baseT_Half)
1677 speed_arg |= BNX2_NETLINK_SET_LINK_SPEED_100HALF;
1678 if (bp->advertising & ADVERTISED_100baseT_Full)
1679 speed_arg |= BNX2_NETLINK_SET_LINK_SPEED_100FULL;
1680 if (bp->advertising & ADVERTISED_1000baseT_Full)
1681 speed_arg |= BNX2_NETLINK_SET_LINK_SPEED_1GFULL;
1682 if (bp->advertising & ADVERTISED_2500baseX_Full)
1683 speed_arg |= BNX2_NETLINK_SET_LINK_SPEED_2G5FULL;
1684 } else {
1685 if (bp->req_line_speed == SPEED_2500)
1686 speed_arg = BNX2_NETLINK_SET_LINK_SPEED_2G5FULL;
1687 else if (bp->req_line_speed == SPEED_1000)
1688 speed_arg = BNX2_NETLINK_SET_LINK_SPEED_1GFULL;
1689 else if (bp->req_line_speed == SPEED_100) {
1690 if (bp->req_duplex == DUPLEX_FULL)
1691 speed_arg = BNX2_NETLINK_SET_LINK_SPEED_100FULL;
1692 else
1693 speed_arg = BNX2_NETLINK_SET_LINK_SPEED_100HALF;
1694 } else if (bp->req_line_speed == SPEED_10) {
1695 if (bp->req_duplex == DUPLEX_FULL)
1696 speed_arg = BNX2_NETLINK_SET_LINK_SPEED_10FULL;
1697 else
1698 speed_arg = BNX2_NETLINK_SET_LINK_SPEED_10HALF;
1699 }
1700 }
1701
1702 if (pause_adv & (ADVERTISE_1000XPAUSE | ADVERTISE_PAUSE_CAP))
1703 speed_arg |= BNX2_NETLINK_SET_LINK_FC_SYM_PAUSE;
Michael Chanc26736e2008-01-31 17:07:21 -08001704 if (pause_adv & (ADVERTISE_1000XPSE_ASYM | ADVERTISE_PAUSE_ASYM))
Michael Chan0d8a6572007-07-07 22:49:43 -07001705 speed_arg |= BNX2_NETLINK_SET_LINK_FC_ASYM_PAUSE;
1706
1707 if (port == PORT_TP)
1708 speed_arg |= BNX2_NETLINK_SET_LINK_PHY_APP_REMOTE |
1709 BNX2_NETLINK_SET_LINK_ETH_AT_WIRESPEED;
1710
Michael Chan2726d6e2008-01-29 21:35:05 -08001711 bnx2_shmem_wr(bp, BNX2_DRV_MB_ARG0, speed_arg);
Michael Chan0d8a6572007-07-07 22:49:43 -07001712
1713 spin_unlock_bh(&bp->phy_lock);
Michael Chana2f13892008-07-14 22:38:23 -07001714 bnx2_fw_sync(bp, BNX2_DRV_MSG_CODE_CMD_SET_LINK, 1, 0);
Michael Chan0d8a6572007-07-07 22:49:43 -07001715 spin_lock_bh(&bp->phy_lock);
1716
1717 return 0;
1718}
1719
1720static int
1721bnx2_setup_serdes_phy(struct bnx2 *bp, u8 port)
Harvey Harrison52d07b12009-01-19 17:27:06 -08001722__releases(&bp->phy_lock)
1723__acquires(&bp->phy_lock)
Michael Chanb6016b72005-05-26 13:03:09 -07001724{
Michael Chan605a9e22007-05-03 13:23:13 -07001725 u32 adv, bmcr;
Michael Chanb6016b72005-05-26 13:03:09 -07001726 u32 new_adv = 0;
1727
Michael Chan583c28e2008-01-21 19:51:35 -08001728 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
Michael Chan0d8a6572007-07-07 22:49:43 -07001729 return (bnx2_setup_remote_phy(bp, port));
1730
Michael Chanb6016b72005-05-26 13:03:09 -07001731 if (!(bp->autoneg & AUTONEG_SPEED)) {
1732 u32 new_bmcr;
Michael Chan5b0c76a2005-11-04 08:45:49 -08001733 int force_link_down = 0;
1734
Michael Chan605a9e22007-05-03 13:23:13 -07001735 if (bp->req_line_speed == SPEED_2500) {
1736 if (!bnx2_test_and_enable_2g5(bp))
1737 force_link_down = 1;
1738 } else if (bp->req_line_speed == SPEED_1000) {
1739 if (bnx2_test_and_disable_2g5(bp))
1740 force_link_down = 1;
1741 }
Michael Chanca58c3a2007-05-03 13:22:52 -07001742 bnx2_read_phy(bp, bp->mii_adv, &adv);
Michael Chan80be4432006-11-19 14:07:28 -08001743 adv &= ~(ADVERTISE_1000XFULL | ADVERTISE_1000XHALF);
1744
Michael Chanca58c3a2007-05-03 13:22:52 -07001745 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chan605a9e22007-05-03 13:23:13 -07001746 new_bmcr = bmcr & ~BMCR_ANENABLE;
Michael Chan80be4432006-11-19 14:07:28 -08001747 new_bmcr |= BMCR_SPEED1000;
Michael Chan605a9e22007-05-03 13:23:13 -07001748
Michael Chan27a005b2007-05-03 13:23:41 -07001749 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
1750 if (bp->req_line_speed == SPEED_2500)
1751 bnx2_enable_forced_2g5(bp);
1752 else if (bp->req_line_speed == SPEED_1000) {
1753 bnx2_disable_forced_2g5(bp);
1754 new_bmcr &= ~0x2000;
1755 }
1756
1757 } else if (CHIP_NUM(bp) == CHIP_NUM_5708) {
Michael Chan605a9e22007-05-03 13:23:13 -07001758 if (bp->req_line_speed == SPEED_2500)
1759 new_bmcr |= BCM5708S_BMCR_FORCE_2500;
1760 else
1761 new_bmcr = bmcr & ~BCM5708S_BMCR_FORCE_2500;
Michael Chan5b0c76a2005-11-04 08:45:49 -08001762 }
1763
Michael Chanb6016b72005-05-26 13:03:09 -07001764 if (bp->req_duplex == DUPLEX_FULL) {
Michael Chan5b0c76a2005-11-04 08:45:49 -08001765 adv |= ADVERTISE_1000XFULL;
Michael Chanb6016b72005-05-26 13:03:09 -07001766 new_bmcr |= BMCR_FULLDPLX;
1767 }
1768 else {
Michael Chan5b0c76a2005-11-04 08:45:49 -08001769 adv |= ADVERTISE_1000XHALF;
Michael Chanb6016b72005-05-26 13:03:09 -07001770 new_bmcr &= ~BMCR_FULLDPLX;
1771 }
Michael Chan5b0c76a2005-11-04 08:45:49 -08001772 if ((new_bmcr != bmcr) || (force_link_down)) {
Michael Chanb6016b72005-05-26 13:03:09 -07001773 /* Force a link down visible on the other side */
1774 if (bp->link_up) {
Michael Chanca58c3a2007-05-03 13:22:52 -07001775 bnx2_write_phy(bp, bp->mii_adv, adv &
Michael Chan5b0c76a2005-11-04 08:45:49 -08001776 ~(ADVERTISE_1000XFULL |
1777 ADVERTISE_1000XHALF));
Michael Chanca58c3a2007-05-03 13:22:52 -07001778 bnx2_write_phy(bp, bp->mii_bmcr, bmcr |
Michael Chanb6016b72005-05-26 13:03:09 -07001779 BMCR_ANRESTART | BMCR_ANENABLE);
1780
1781 bp->link_up = 0;
1782 netif_carrier_off(bp->dev);
Michael Chanca58c3a2007-05-03 13:22:52 -07001783 bnx2_write_phy(bp, bp->mii_bmcr, new_bmcr);
Michael Chan80be4432006-11-19 14:07:28 -08001784 bnx2_report_link(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07001785 }
Michael Chanca58c3a2007-05-03 13:22:52 -07001786 bnx2_write_phy(bp, bp->mii_adv, adv);
1787 bnx2_write_phy(bp, bp->mii_bmcr, new_bmcr);
Michael Chan605a9e22007-05-03 13:23:13 -07001788 } else {
1789 bnx2_resolve_flow_ctrl(bp);
1790 bnx2_set_mac_link(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07001791 }
1792 return 0;
1793 }
1794
Michael Chan605a9e22007-05-03 13:23:13 -07001795 bnx2_test_and_enable_2g5(bp);
Michael Chan5b0c76a2005-11-04 08:45:49 -08001796
Michael Chanb6016b72005-05-26 13:03:09 -07001797 if (bp->advertising & ADVERTISED_1000baseT_Full)
1798 new_adv |= ADVERTISE_1000XFULL;
1799
1800 new_adv |= bnx2_phy_get_pause_adv(bp);
1801
Michael Chanca58c3a2007-05-03 13:22:52 -07001802 bnx2_read_phy(bp, bp->mii_adv, &adv);
1803 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chanb6016b72005-05-26 13:03:09 -07001804
1805 bp->serdes_an_pending = 0;
1806 if ((adv != new_adv) || ((bmcr & BMCR_ANENABLE) == 0)) {
1807 /* Force a link down visible on the other side */
1808 if (bp->link_up) {
Michael Chanca58c3a2007-05-03 13:22:52 -07001809 bnx2_write_phy(bp, bp->mii_bmcr, BMCR_LOOPBACK);
Michael Chan80be4432006-11-19 14:07:28 -08001810 spin_unlock_bh(&bp->phy_lock);
1811 msleep(20);
1812 spin_lock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07001813 }
1814
Michael Chanca58c3a2007-05-03 13:22:52 -07001815 bnx2_write_phy(bp, bp->mii_adv, new_adv);
1816 bnx2_write_phy(bp, bp->mii_bmcr, bmcr | BMCR_ANRESTART |
Michael Chanb6016b72005-05-26 13:03:09 -07001817 BMCR_ANENABLE);
Michael Chanf8dd0642006-11-19 14:08:29 -08001818 /* Speed up link-up time when the link partner
1819 * does not autonegotiate which is very common
1820 * in blade servers. Some blade servers use
1821 * IPMI for kerboard input and it's important
1822 * to minimize link disruptions. Autoneg. involves
1823 * exchanging base pages plus 3 next pages and
1824 * normally completes in about 120 msec.
1825 */
Michael Chan40105c02008-11-12 16:02:45 -08001826 bp->current_interval = BNX2_SERDES_AN_TIMEOUT;
Michael Chanf8dd0642006-11-19 14:08:29 -08001827 bp->serdes_an_pending = 1;
1828 mod_timer(&bp->timer, jiffies + bp->current_interval);
Michael Chan605a9e22007-05-03 13:23:13 -07001829 } else {
1830 bnx2_resolve_flow_ctrl(bp);
1831 bnx2_set_mac_link(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07001832 }
1833
1834 return 0;
1835}
1836
1837#define ETHTOOL_ALL_FIBRE_SPEED \
Michael Chan583c28e2008-01-21 19:51:35 -08001838 (bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE) ? \
Michael Chandeaf3912007-07-07 22:48:00 -07001839 (ADVERTISED_2500baseX_Full | ADVERTISED_1000baseT_Full) :\
1840 (ADVERTISED_1000baseT_Full)
Michael Chanb6016b72005-05-26 13:03:09 -07001841
1842#define ETHTOOL_ALL_COPPER_SPEED \
1843 (ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full | \
1844 ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full | \
1845 ADVERTISED_1000baseT_Full)
1846
1847#define PHY_ALL_10_100_SPEED (ADVERTISE_10HALF | ADVERTISE_10FULL | \
1848 ADVERTISE_100HALF | ADVERTISE_100FULL | ADVERTISE_CSMA)
Jeff Garzik6aa20a22006-09-13 13:24:59 -04001849
Michael Chanb6016b72005-05-26 13:03:09 -07001850#define PHY_ALL_1000_SPEED (ADVERTISE_1000HALF | ADVERTISE_1000FULL)
1851
Michael Chandeaf3912007-07-07 22:48:00 -07001852static void
Michael Chan0d8a6572007-07-07 22:49:43 -07001853bnx2_set_default_remote_link(struct bnx2 *bp)
1854{
1855 u32 link;
1856
1857 if (bp->phy_port == PORT_TP)
Michael Chan2726d6e2008-01-29 21:35:05 -08001858 link = bnx2_shmem_rd(bp, BNX2_RPHY_COPPER_LINK);
Michael Chan0d8a6572007-07-07 22:49:43 -07001859 else
Michael Chan2726d6e2008-01-29 21:35:05 -08001860 link = bnx2_shmem_rd(bp, BNX2_RPHY_SERDES_LINK);
Michael Chan0d8a6572007-07-07 22:49:43 -07001861
1862 if (link & BNX2_NETLINK_SET_LINK_ENABLE_AUTONEG) {
1863 bp->req_line_speed = 0;
1864 bp->autoneg |= AUTONEG_SPEED;
1865 bp->advertising = ADVERTISED_Autoneg;
1866 if (link & BNX2_NETLINK_SET_LINK_SPEED_10HALF)
1867 bp->advertising |= ADVERTISED_10baseT_Half;
1868 if (link & BNX2_NETLINK_SET_LINK_SPEED_10FULL)
1869 bp->advertising |= ADVERTISED_10baseT_Full;
1870 if (link & BNX2_NETLINK_SET_LINK_SPEED_100HALF)
1871 bp->advertising |= ADVERTISED_100baseT_Half;
1872 if (link & BNX2_NETLINK_SET_LINK_SPEED_100FULL)
1873 bp->advertising |= ADVERTISED_100baseT_Full;
1874 if (link & BNX2_NETLINK_SET_LINK_SPEED_1GFULL)
1875 bp->advertising |= ADVERTISED_1000baseT_Full;
1876 if (link & BNX2_NETLINK_SET_LINK_SPEED_2G5FULL)
1877 bp->advertising |= ADVERTISED_2500baseX_Full;
1878 } else {
1879 bp->autoneg = 0;
1880 bp->advertising = 0;
1881 bp->req_duplex = DUPLEX_FULL;
1882 if (link & BNX2_NETLINK_SET_LINK_SPEED_10) {
1883 bp->req_line_speed = SPEED_10;
1884 if (link & BNX2_NETLINK_SET_LINK_SPEED_10HALF)
1885 bp->req_duplex = DUPLEX_HALF;
1886 }
1887 if (link & BNX2_NETLINK_SET_LINK_SPEED_100) {
1888 bp->req_line_speed = SPEED_100;
1889 if (link & BNX2_NETLINK_SET_LINK_SPEED_100HALF)
1890 bp->req_duplex = DUPLEX_HALF;
1891 }
1892 if (link & BNX2_NETLINK_SET_LINK_SPEED_1GFULL)
1893 bp->req_line_speed = SPEED_1000;
1894 if (link & BNX2_NETLINK_SET_LINK_SPEED_2G5FULL)
1895 bp->req_line_speed = SPEED_2500;
1896 }
1897}
1898
1899static void
Michael Chandeaf3912007-07-07 22:48:00 -07001900bnx2_set_default_link(struct bnx2 *bp)
1901{
Harvey Harrisonab598592008-05-01 02:47:38 -07001902 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP) {
1903 bnx2_set_default_remote_link(bp);
1904 return;
1905 }
Michael Chan0d8a6572007-07-07 22:49:43 -07001906
Michael Chandeaf3912007-07-07 22:48:00 -07001907 bp->autoneg = AUTONEG_SPEED | AUTONEG_FLOW_CTRL;
1908 bp->req_line_speed = 0;
Michael Chan583c28e2008-01-21 19:51:35 -08001909 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Michael Chandeaf3912007-07-07 22:48:00 -07001910 u32 reg;
1911
1912 bp->advertising = ETHTOOL_ALL_FIBRE_SPEED | ADVERTISED_Autoneg;
1913
Michael Chan2726d6e2008-01-29 21:35:05 -08001914 reg = bnx2_shmem_rd(bp, BNX2_PORT_HW_CFG_CONFIG);
Michael Chandeaf3912007-07-07 22:48:00 -07001915 reg &= BNX2_PORT_HW_CFG_CFG_DFLT_LINK_MASK;
1916 if (reg == BNX2_PORT_HW_CFG_CFG_DFLT_LINK_1G) {
1917 bp->autoneg = 0;
1918 bp->req_line_speed = bp->line_speed = SPEED_1000;
1919 bp->req_duplex = DUPLEX_FULL;
1920 }
1921 } else
1922 bp->advertising = ETHTOOL_ALL_COPPER_SPEED | ADVERTISED_Autoneg;
1923}
1924
Michael Chan0d8a6572007-07-07 22:49:43 -07001925static void
Michael Chandf149d72007-07-07 22:51:36 -07001926bnx2_send_heart_beat(struct bnx2 *bp)
1927{
1928 u32 msg;
1929 u32 addr;
1930
1931 spin_lock(&bp->indirect_lock);
1932 msg = (u32) (++bp->fw_drv_pulse_wr_seq & BNX2_DRV_PULSE_SEQ_MASK);
1933 addr = bp->shmem_base + BNX2_DRV_PULSE_MB;
1934 REG_WR(bp, BNX2_PCICFG_REG_WINDOW_ADDRESS, addr);
1935 REG_WR(bp, BNX2_PCICFG_REG_WINDOW, msg);
1936 spin_unlock(&bp->indirect_lock);
1937}
1938
1939static void
Michael Chan0d8a6572007-07-07 22:49:43 -07001940bnx2_remote_phy_event(struct bnx2 *bp)
1941{
1942 u32 msg;
1943 u8 link_up = bp->link_up;
1944 u8 old_port;
1945
Michael Chan2726d6e2008-01-29 21:35:05 -08001946 msg = bnx2_shmem_rd(bp, BNX2_LINK_STATUS);
Michael Chan0d8a6572007-07-07 22:49:43 -07001947
Michael Chandf149d72007-07-07 22:51:36 -07001948 if (msg & BNX2_LINK_STATUS_HEART_BEAT_EXPIRED)
1949 bnx2_send_heart_beat(bp);
1950
1951 msg &= ~BNX2_LINK_STATUS_HEART_BEAT_EXPIRED;
1952
Michael Chan0d8a6572007-07-07 22:49:43 -07001953 if ((msg & BNX2_LINK_STATUS_LINK_UP) == BNX2_LINK_STATUS_LINK_DOWN)
1954 bp->link_up = 0;
1955 else {
1956 u32 speed;
1957
1958 bp->link_up = 1;
1959 speed = msg & BNX2_LINK_STATUS_SPEED_MASK;
1960 bp->duplex = DUPLEX_FULL;
1961 switch (speed) {
1962 case BNX2_LINK_STATUS_10HALF:
1963 bp->duplex = DUPLEX_HALF;
1964 case BNX2_LINK_STATUS_10FULL:
1965 bp->line_speed = SPEED_10;
1966 break;
1967 case BNX2_LINK_STATUS_100HALF:
1968 bp->duplex = DUPLEX_HALF;
1969 case BNX2_LINK_STATUS_100BASE_T4:
1970 case BNX2_LINK_STATUS_100FULL:
1971 bp->line_speed = SPEED_100;
1972 break;
1973 case BNX2_LINK_STATUS_1000HALF:
1974 bp->duplex = DUPLEX_HALF;
1975 case BNX2_LINK_STATUS_1000FULL:
1976 bp->line_speed = SPEED_1000;
1977 break;
1978 case BNX2_LINK_STATUS_2500HALF:
1979 bp->duplex = DUPLEX_HALF;
1980 case BNX2_LINK_STATUS_2500FULL:
1981 bp->line_speed = SPEED_2500;
1982 break;
1983 default:
1984 bp->line_speed = 0;
1985 break;
1986 }
1987
Michael Chan0d8a6572007-07-07 22:49:43 -07001988 bp->flow_ctrl = 0;
1989 if ((bp->autoneg & (AUTONEG_SPEED | AUTONEG_FLOW_CTRL)) !=
1990 (AUTONEG_SPEED | AUTONEG_FLOW_CTRL)) {
1991 if (bp->duplex == DUPLEX_FULL)
1992 bp->flow_ctrl = bp->req_flow_ctrl;
1993 } else {
1994 if (msg & BNX2_LINK_STATUS_TX_FC_ENABLED)
1995 bp->flow_ctrl |= FLOW_CTRL_TX;
1996 if (msg & BNX2_LINK_STATUS_RX_FC_ENABLED)
1997 bp->flow_ctrl |= FLOW_CTRL_RX;
1998 }
1999
2000 old_port = bp->phy_port;
2001 if (msg & BNX2_LINK_STATUS_SERDES_LINK)
2002 bp->phy_port = PORT_FIBRE;
2003 else
2004 bp->phy_port = PORT_TP;
2005
2006 if (old_port != bp->phy_port)
2007 bnx2_set_default_link(bp);
2008
Michael Chan0d8a6572007-07-07 22:49:43 -07002009 }
2010 if (bp->link_up != link_up)
2011 bnx2_report_link(bp);
2012
2013 bnx2_set_mac_link(bp);
2014}
2015
2016static int
2017bnx2_set_remote_link(struct bnx2 *bp)
2018{
2019 u32 evt_code;
2020
Michael Chan2726d6e2008-01-29 21:35:05 -08002021 evt_code = bnx2_shmem_rd(bp, BNX2_FW_EVT_CODE_MB);
Michael Chan0d8a6572007-07-07 22:49:43 -07002022 switch (evt_code) {
2023 case BNX2_FW_EVT_CODE_LINK_EVENT:
2024 bnx2_remote_phy_event(bp);
2025 break;
2026 case BNX2_FW_EVT_CODE_SW_TIMER_EXPIRATION_EVENT:
2027 default:
Michael Chandf149d72007-07-07 22:51:36 -07002028 bnx2_send_heart_beat(bp);
Michael Chan0d8a6572007-07-07 22:49:43 -07002029 break;
2030 }
2031 return 0;
2032}
2033
Michael Chanb6016b72005-05-26 13:03:09 -07002034static int
2035bnx2_setup_copper_phy(struct bnx2 *bp)
Harvey Harrison52d07b12009-01-19 17:27:06 -08002036__releases(&bp->phy_lock)
2037__acquires(&bp->phy_lock)
Michael Chanb6016b72005-05-26 13:03:09 -07002038{
2039 u32 bmcr;
2040 u32 new_bmcr;
2041
Michael Chanca58c3a2007-05-03 13:22:52 -07002042 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chanb6016b72005-05-26 13:03:09 -07002043
2044 if (bp->autoneg & AUTONEG_SPEED) {
2045 u32 adv_reg, adv1000_reg;
2046 u32 new_adv_reg = 0;
2047 u32 new_adv1000_reg = 0;
2048
Michael Chanca58c3a2007-05-03 13:22:52 -07002049 bnx2_read_phy(bp, bp->mii_adv, &adv_reg);
Michael Chanb6016b72005-05-26 13:03:09 -07002050 adv_reg &= (PHY_ALL_10_100_SPEED | ADVERTISE_PAUSE_CAP |
2051 ADVERTISE_PAUSE_ASYM);
2052
2053 bnx2_read_phy(bp, MII_CTRL1000, &adv1000_reg);
2054 adv1000_reg &= PHY_ALL_1000_SPEED;
2055
2056 if (bp->advertising & ADVERTISED_10baseT_Half)
2057 new_adv_reg |= ADVERTISE_10HALF;
2058 if (bp->advertising & ADVERTISED_10baseT_Full)
2059 new_adv_reg |= ADVERTISE_10FULL;
2060 if (bp->advertising & ADVERTISED_100baseT_Half)
2061 new_adv_reg |= ADVERTISE_100HALF;
2062 if (bp->advertising & ADVERTISED_100baseT_Full)
2063 new_adv_reg |= ADVERTISE_100FULL;
2064 if (bp->advertising & ADVERTISED_1000baseT_Full)
2065 new_adv1000_reg |= ADVERTISE_1000FULL;
Jeff Garzik6aa20a22006-09-13 13:24:59 -04002066
Michael Chanb6016b72005-05-26 13:03:09 -07002067 new_adv_reg |= ADVERTISE_CSMA;
2068
2069 new_adv_reg |= bnx2_phy_get_pause_adv(bp);
2070
2071 if ((adv1000_reg != new_adv1000_reg) ||
2072 (adv_reg != new_adv_reg) ||
2073 ((bmcr & BMCR_ANENABLE) == 0)) {
2074
Michael Chanca58c3a2007-05-03 13:22:52 -07002075 bnx2_write_phy(bp, bp->mii_adv, new_adv_reg);
Michael Chanb6016b72005-05-26 13:03:09 -07002076 bnx2_write_phy(bp, MII_CTRL1000, new_adv1000_reg);
Michael Chanca58c3a2007-05-03 13:22:52 -07002077 bnx2_write_phy(bp, bp->mii_bmcr, BMCR_ANRESTART |
Michael Chanb6016b72005-05-26 13:03:09 -07002078 BMCR_ANENABLE);
2079 }
2080 else if (bp->link_up) {
2081 /* Flow ctrl may have changed from auto to forced */
2082 /* or vice-versa. */
2083
2084 bnx2_resolve_flow_ctrl(bp);
2085 bnx2_set_mac_link(bp);
2086 }
2087 return 0;
2088 }
2089
2090 new_bmcr = 0;
2091 if (bp->req_line_speed == SPEED_100) {
2092 new_bmcr |= BMCR_SPEED100;
2093 }
2094 if (bp->req_duplex == DUPLEX_FULL) {
2095 new_bmcr |= BMCR_FULLDPLX;
2096 }
2097 if (new_bmcr != bmcr) {
2098 u32 bmsr;
Michael Chanb6016b72005-05-26 13:03:09 -07002099
Michael Chanca58c3a2007-05-03 13:22:52 -07002100 bnx2_read_phy(bp, bp->mii_bmsr, &bmsr);
2101 bnx2_read_phy(bp, bp->mii_bmsr, &bmsr);
Jeff Garzik6aa20a22006-09-13 13:24:59 -04002102
Michael Chanb6016b72005-05-26 13:03:09 -07002103 if (bmsr & BMSR_LSTATUS) {
2104 /* Force link down */
Michael Chanca58c3a2007-05-03 13:22:52 -07002105 bnx2_write_phy(bp, bp->mii_bmcr, BMCR_LOOPBACK);
Michael Chana16dda02006-11-19 14:08:56 -08002106 spin_unlock_bh(&bp->phy_lock);
2107 msleep(50);
2108 spin_lock_bh(&bp->phy_lock);
2109
Michael Chanca58c3a2007-05-03 13:22:52 -07002110 bnx2_read_phy(bp, bp->mii_bmsr, &bmsr);
2111 bnx2_read_phy(bp, bp->mii_bmsr, &bmsr);
Michael Chanb6016b72005-05-26 13:03:09 -07002112 }
2113
Michael Chanca58c3a2007-05-03 13:22:52 -07002114 bnx2_write_phy(bp, bp->mii_bmcr, new_bmcr);
Michael Chanb6016b72005-05-26 13:03:09 -07002115
2116 /* Normally, the new speed is setup after the link has
2117 * gone down and up again. In some cases, link will not go
2118 * down so we need to set up the new speed here.
2119 */
2120 if (bmsr & BMSR_LSTATUS) {
2121 bp->line_speed = bp->req_line_speed;
2122 bp->duplex = bp->req_duplex;
2123 bnx2_resolve_flow_ctrl(bp);
2124 bnx2_set_mac_link(bp);
2125 }
Michael Chan27a005b2007-05-03 13:23:41 -07002126 } else {
2127 bnx2_resolve_flow_ctrl(bp);
2128 bnx2_set_mac_link(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07002129 }
2130 return 0;
2131}
2132
2133static int
Michael Chan0d8a6572007-07-07 22:49:43 -07002134bnx2_setup_phy(struct bnx2 *bp, u8 port)
Harvey Harrison52d07b12009-01-19 17:27:06 -08002135__releases(&bp->phy_lock)
2136__acquires(&bp->phy_lock)
Michael Chanb6016b72005-05-26 13:03:09 -07002137{
2138 if (bp->loopback == MAC_LOOPBACK)
2139 return 0;
2140
Michael Chan583c28e2008-01-21 19:51:35 -08002141 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Michael Chan0d8a6572007-07-07 22:49:43 -07002142 return (bnx2_setup_serdes_phy(bp, port));
Michael Chanb6016b72005-05-26 13:03:09 -07002143 }
2144 else {
2145 return (bnx2_setup_copper_phy(bp));
2146 }
2147}
2148
2149static int
Michael Chan9a120bc2008-05-16 22:17:45 -07002150bnx2_init_5709s_phy(struct bnx2 *bp, int reset_phy)
Michael Chan27a005b2007-05-03 13:23:41 -07002151{
2152 u32 val;
2153
2154 bp->mii_bmcr = MII_BMCR + 0x10;
2155 bp->mii_bmsr = MII_BMSR + 0x10;
2156 bp->mii_bmsr1 = MII_BNX2_GP_TOP_AN_STATUS1;
2157 bp->mii_adv = MII_ADVERTISE + 0x10;
2158 bp->mii_lpa = MII_LPA + 0x10;
2159 bp->mii_up1 = MII_BNX2_OVER1G_UP1;
2160
2161 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_AER);
2162 bnx2_write_phy(bp, MII_BNX2_AER_AER, MII_BNX2_AER_AER_AN_MMD);
2163
2164 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
Michael Chan9a120bc2008-05-16 22:17:45 -07002165 if (reset_phy)
2166 bnx2_reset_phy(bp);
Michael Chan27a005b2007-05-03 13:23:41 -07002167
2168 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_SERDES_DIG);
2169
2170 bnx2_read_phy(bp, MII_BNX2_SERDES_DIG_1000XCTL1, &val);
2171 val &= ~MII_BNX2_SD_1000XCTL1_AUTODET;
2172 val |= MII_BNX2_SD_1000XCTL1_FIBER;
2173 bnx2_write_phy(bp, MII_BNX2_SERDES_DIG_1000XCTL1, val);
2174
2175 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_OVER1G);
2176 bnx2_read_phy(bp, MII_BNX2_OVER1G_UP1, &val);
Michael Chan583c28e2008-01-21 19:51:35 -08002177 if (bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE)
Michael Chan27a005b2007-05-03 13:23:41 -07002178 val |= BCM5708S_UP1_2G5;
2179 else
2180 val &= ~BCM5708S_UP1_2G5;
2181 bnx2_write_phy(bp, MII_BNX2_OVER1G_UP1, val);
2182
2183 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_BAM_NXTPG);
2184 bnx2_read_phy(bp, MII_BNX2_BAM_NXTPG_CTL, &val);
2185 val |= MII_BNX2_NXTPG_CTL_T2 | MII_BNX2_NXTPG_CTL_BAM;
2186 bnx2_write_phy(bp, MII_BNX2_BAM_NXTPG_CTL, val);
2187
2188 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_CL73_USERB0);
2189
2190 val = MII_BNX2_CL73_BAM_EN | MII_BNX2_CL73_BAM_STA_MGR_EN |
2191 MII_BNX2_CL73_BAM_NP_AFT_BP_EN;
2192 bnx2_write_phy(bp, MII_BNX2_CL73_BAM_CTL1, val);
2193
2194 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
2195
2196 return 0;
2197}
2198
2199static int
Michael Chan9a120bc2008-05-16 22:17:45 -07002200bnx2_init_5708s_phy(struct bnx2 *bp, int reset_phy)
Michael Chan5b0c76a2005-11-04 08:45:49 -08002201{
2202 u32 val;
2203
Michael Chan9a120bc2008-05-16 22:17:45 -07002204 if (reset_phy)
2205 bnx2_reset_phy(bp);
Michael Chan27a005b2007-05-03 13:23:41 -07002206
2207 bp->mii_up1 = BCM5708S_UP1;
2208
Michael Chan5b0c76a2005-11-04 08:45:49 -08002209 bnx2_write_phy(bp, BCM5708S_BLK_ADDR, BCM5708S_BLK_ADDR_DIG3);
2210 bnx2_write_phy(bp, BCM5708S_DIG_3_0, BCM5708S_DIG_3_0_USE_IEEE);
2211 bnx2_write_phy(bp, BCM5708S_BLK_ADDR, BCM5708S_BLK_ADDR_DIG);
2212
2213 bnx2_read_phy(bp, BCM5708S_1000X_CTL1, &val);
2214 val |= BCM5708S_1000X_CTL1_FIBER_MODE | BCM5708S_1000X_CTL1_AUTODET_EN;
2215 bnx2_write_phy(bp, BCM5708S_1000X_CTL1, val);
2216
2217 bnx2_read_phy(bp, BCM5708S_1000X_CTL2, &val);
2218 val |= BCM5708S_1000X_CTL2_PLLEL_DET_EN;
2219 bnx2_write_phy(bp, BCM5708S_1000X_CTL2, val);
2220
Michael Chan583c28e2008-01-21 19:51:35 -08002221 if (bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE) {
Michael Chan5b0c76a2005-11-04 08:45:49 -08002222 bnx2_read_phy(bp, BCM5708S_UP1, &val);
2223 val |= BCM5708S_UP1_2G5;
2224 bnx2_write_phy(bp, BCM5708S_UP1, val);
2225 }
2226
2227 if ((CHIP_ID(bp) == CHIP_ID_5708_A0) ||
Michael Chandda1e392006-01-23 16:08:14 -08002228 (CHIP_ID(bp) == CHIP_ID_5708_B0) ||
2229 (CHIP_ID(bp) == CHIP_ID_5708_B1)) {
Michael Chan5b0c76a2005-11-04 08:45:49 -08002230 /* increase tx signal amplitude */
2231 bnx2_write_phy(bp, BCM5708S_BLK_ADDR,
2232 BCM5708S_BLK_ADDR_TX_MISC);
2233 bnx2_read_phy(bp, BCM5708S_TX_ACTL1, &val);
2234 val &= ~BCM5708S_TX_ACTL1_DRIVER_VCM;
2235 bnx2_write_phy(bp, BCM5708S_TX_ACTL1, val);
2236 bnx2_write_phy(bp, BCM5708S_BLK_ADDR, BCM5708S_BLK_ADDR_DIG);
2237 }
2238
Michael Chan2726d6e2008-01-29 21:35:05 -08002239 val = bnx2_shmem_rd(bp, BNX2_PORT_HW_CFG_CONFIG) &
Michael Chan5b0c76a2005-11-04 08:45:49 -08002240 BNX2_PORT_HW_CFG_CFG_TXCTL3_MASK;
2241
2242 if (val) {
2243 u32 is_backplane;
2244
Michael Chan2726d6e2008-01-29 21:35:05 -08002245 is_backplane = bnx2_shmem_rd(bp, BNX2_SHARED_HW_CFG_CONFIG);
Michael Chan5b0c76a2005-11-04 08:45:49 -08002246 if (is_backplane & BNX2_SHARED_HW_CFG_PHY_BACKPLANE) {
2247 bnx2_write_phy(bp, BCM5708S_BLK_ADDR,
2248 BCM5708S_BLK_ADDR_TX_MISC);
2249 bnx2_write_phy(bp, BCM5708S_TX_ACTL3, val);
2250 bnx2_write_phy(bp, BCM5708S_BLK_ADDR,
2251 BCM5708S_BLK_ADDR_DIG);
2252 }
2253 }
2254 return 0;
2255}
2256
2257static int
Michael Chan9a120bc2008-05-16 22:17:45 -07002258bnx2_init_5706s_phy(struct bnx2 *bp, int reset_phy)
Michael Chanb6016b72005-05-26 13:03:09 -07002259{
Michael Chan9a120bc2008-05-16 22:17:45 -07002260 if (reset_phy)
2261 bnx2_reset_phy(bp);
Michael Chan27a005b2007-05-03 13:23:41 -07002262
Michael Chan583c28e2008-01-21 19:51:35 -08002263 bp->phy_flags &= ~BNX2_PHY_FLAG_PARALLEL_DETECT;
Michael Chanb6016b72005-05-26 13:03:09 -07002264
Michael Chan59b47d82006-11-19 14:10:45 -08002265 if (CHIP_NUM(bp) == CHIP_NUM_5706)
2266 REG_WR(bp, BNX2_MISC_GP_HW_CTL0, 0x300);
Michael Chanb6016b72005-05-26 13:03:09 -07002267
2268 if (bp->dev->mtu > 1500) {
2269 u32 val;
2270
2271 /* Set extended packet length bit */
2272 bnx2_write_phy(bp, 0x18, 0x7);
2273 bnx2_read_phy(bp, 0x18, &val);
2274 bnx2_write_phy(bp, 0x18, (val & 0xfff8) | 0x4000);
2275
2276 bnx2_write_phy(bp, 0x1c, 0x6c00);
2277 bnx2_read_phy(bp, 0x1c, &val);
2278 bnx2_write_phy(bp, 0x1c, (val & 0x3ff) | 0xec02);
2279 }
2280 else {
2281 u32 val;
2282
2283 bnx2_write_phy(bp, 0x18, 0x7);
2284 bnx2_read_phy(bp, 0x18, &val);
2285 bnx2_write_phy(bp, 0x18, val & ~0x4007);
2286
2287 bnx2_write_phy(bp, 0x1c, 0x6c00);
2288 bnx2_read_phy(bp, 0x1c, &val);
2289 bnx2_write_phy(bp, 0x1c, (val & 0x3fd) | 0xec00);
2290 }
2291
2292 return 0;
2293}
2294
2295static int
Michael Chan9a120bc2008-05-16 22:17:45 -07002296bnx2_init_copper_phy(struct bnx2 *bp, int reset_phy)
Michael Chanb6016b72005-05-26 13:03:09 -07002297{
Michael Chan5b0c76a2005-11-04 08:45:49 -08002298 u32 val;
2299
Michael Chan9a120bc2008-05-16 22:17:45 -07002300 if (reset_phy)
2301 bnx2_reset_phy(bp);
Michael Chan27a005b2007-05-03 13:23:41 -07002302
Michael Chan583c28e2008-01-21 19:51:35 -08002303 if (bp->phy_flags & BNX2_PHY_FLAG_CRC_FIX) {
Michael Chanb6016b72005-05-26 13:03:09 -07002304 bnx2_write_phy(bp, 0x18, 0x0c00);
2305 bnx2_write_phy(bp, 0x17, 0x000a);
2306 bnx2_write_phy(bp, 0x15, 0x310b);
2307 bnx2_write_phy(bp, 0x17, 0x201f);
2308 bnx2_write_phy(bp, 0x15, 0x9506);
2309 bnx2_write_phy(bp, 0x17, 0x401f);
2310 bnx2_write_phy(bp, 0x15, 0x14e2);
2311 bnx2_write_phy(bp, 0x18, 0x0400);
2312 }
2313
Michael Chan583c28e2008-01-21 19:51:35 -08002314 if (bp->phy_flags & BNX2_PHY_FLAG_DIS_EARLY_DAC) {
Michael Chanb659f442007-02-02 00:46:35 -08002315 bnx2_write_phy(bp, MII_BNX2_DSP_ADDRESS,
2316 MII_BNX2_DSP_EXPAND_REG | 0x8);
2317 bnx2_read_phy(bp, MII_BNX2_DSP_RW_PORT, &val);
2318 val &= ~(1 << 8);
2319 bnx2_write_phy(bp, MII_BNX2_DSP_RW_PORT, val);
2320 }
2321
Michael Chanb6016b72005-05-26 13:03:09 -07002322 if (bp->dev->mtu > 1500) {
Michael Chanb6016b72005-05-26 13:03:09 -07002323 /* Set extended packet length bit */
2324 bnx2_write_phy(bp, 0x18, 0x7);
2325 bnx2_read_phy(bp, 0x18, &val);
2326 bnx2_write_phy(bp, 0x18, val | 0x4000);
2327
2328 bnx2_read_phy(bp, 0x10, &val);
2329 bnx2_write_phy(bp, 0x10, val | 0x1);
2330 }
2331 else {
Michael Chanb6016b72005-05-26 13:03:09 -07002332 bnx2_write_phy(bp, 0x18, 0x7);
2333 bnx2_read_phy(bp, 0x18, &val);
2334 bnx2_write_phy(bp, 0x18, val & ~0x4007);
2335
2336 bnx2_read_phy(bp, 0x10, &val);
2337 bnx2_write_phy(bp, 0x10, val & ~0x1);
2338 }
2339
Michael Chan5b0c76a2005-11-04 08:45:49 -08002340 /* ethernet@wirespeed */
2341 bnx2_write_phy(bp, 0x18, 0x7007);
2342 bnx2_read_phy(bp, 0x18, &val);
2343 bnx2_write_phy(bp, 0x18, val | (1 << 15) | (1 << 4));
Michael Chanb6016b72005-05-26 13:03:09 -07002344 return 0;
2345}
2346
2347
2348static int
Michael Chan9a120bc2008-05-16 22:17:45 -07002349bnx2_init_phy(struct bnx2 *bp, int reset_phy)
Harvey Harrison52d07b12009-01-19 17:27:06 -08002350__releases(&bp->phy_lock)
2351__acquires(&bp->phy_lock)
Michael Chanb6016b72005-05-26 13:03:09 -07002352{
2353 u32 val;
2354 int rc = 0;
2355
Michael Chan583c28e2008-01-21 19:51:35 -08002356 bp->phy_flags &= ~BNX2_PHY_FLAG_INT_MODE_MASK;
2357 bp->phy_flags |= BNX2_PHY_FLAG_INT_MODE_LINK_READY;
Michael Chanb6016b72005-05-26 13:03:09 -07002358
Michael Chanca58c3a2007-05-03 13:22:52 -07002359 bp->mii_bmcr = MII_BMCR;
2360 bp->mii_bmsr = MII_BMSR;
Michael Chan27a005b2007-05-03 13:23:41 -07002361 bp->mii_bmsr1 = MII_BMSR;
Michael Chanca58c3a2007-05-03 13:22:52 -07002362 bp->mii_adv = MII_ADVERTISE;
2363 bp->mii_lpa = MII_LPA;
2364
Michael Chanb6016b72005-05-26 13:03:09 -07002365 REG_WR(bp, BNX2_EMAC_ATTENTION_ENA, BNX2_EMAC_ATTENTION_ENA_LINK);
2366
Michael Chan583c28e2008-01-21 19:51:35 -08002367 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
Michael Chan0d8a6572007-07-07 22:49:43 -07002368 goto setup_phy;
2369
Michael Chanb6016b72005-05-26 13:03:09 -07002370 bnx2_read_phy(bp, MII_PHYSID1, &val);
2371 bp->phy_id = val << 16;
2372 bnx2_read_phy(bp, MII_PHYSID2, &val);
2373 bp->phy_id |= val & 0xffff;
2374
Michael Chan583c28e2008-01-21 19:51:35 -08002375 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Michael Chan5b0c76a2005-11-04 08:45:49 -08002376 if (CHIP_NUM(bp) == CHIP_NUM_5706)
Michael Chan9a120bc2008-05-16 22:17:45 -07002377 rc = bnx2_init_5706s_phy(bp, reset_phy);
Michael Chan5b0c76a2005-11-04 08:45:49 -08002378 else if (CHIP_NUM(bp) == CHIP_NUM_5708)
Michael Chan9a120bc2008-05-16 22:17:45 -07002379 rc = bnx2_init_5708s_phy(bp, reset_phy);
Michael Chan27a005b2007-05-03 13:23:41 -07002380 else if (CHIP_NUM(bp) == CHIP_NUM_5709)
Michael Chan9a120bc2008-05-16 22:17:45 -07002381 rc = bnx2_init_5709s_phy(bp, reset_phy);
Michael Chanb6016b72005-05-26 13:03:09 -07002382 }
2383 else {
Michael Chan9a120bc2008-05-16 22:17:45 -07002384 rc = bnx2_init_copper_phy(bp, reset_phy);
Michael Chanb6016b72005-05-26 13:03:09 -07002385 }
2386
Michael Chan0d8a6572007-07-07 22:49:43 -07002387setup_phy:
2388 if (!rc)
2389 rc = bnx2_setup_phy(bp, bp->phy_port);
Michael Chanb6016b72005-05-26 13:03:09 -07002390
2391 return rc;
2392}
2393
2394static int
2395bnx2_set_mac_loopback(struct bnx2 *bp)
2396{
2397 u32 mac_mode;
2398
2399 mac_mode = REG_RD(bp, BNX2_EMAC_MODE);
2400 mac_mode &= ~BNX2_EMAC_MODE_PORT;
2401 mac_mode |= BNX2_EMAC_MODE_MAC_LOOP | BNX2_EMAC_MODE_FORCE_LINK;
2402 REG_WR(bp, BNX2_EMAC_MODE, mac_mode);
2403 bp->link_up = 1;
2404 return 0;
2405}
2406
Michael Chanbc5a0692006-01-23 16:13:22 -08002407static int bnx2_test_link(struct bnx2 *);
2408
2409static int
2410bnx2_set_phy_loopback(struct bnx2 *bp)
2411{
2412 u32 mac_mode;
2413 int rc, i;
2414
2415 spin_lock_bh(&bp->phy_lock);
Michael Chanca58c3a2007-05-03 13:22:52 -07002416 rc = bnx2_write_phy(bp, bp->mii_bmcr, BMCR_LOOPBACK | BMCR_FULLDPLX |
Michael Chanbc5a0692006-01-23 16:13:22 -08002417 BMCR_SPEED1000);
2418 spin_unlock_bh(&bp->phy_lock);
2419 if (rc)
2420 return rc;
2421
2422 for (i = 0; i < 10; i++) {
2423 if (bnx2_test_link(bp) == 0)
2424 break;
Michael Chan80be4432006-11-19 14:07:28 -08002425 msleep(100);
Michael Chanbc5a0692006-01-23 16:13:22 -08002426 }
2427
2428 mac_mode = REG_RD(bp, BNX2_EMAC_MODE);
2429 mac_mode &= ~(BNX2_EMAC_MODE_PORT | BNX2_EMAC_MODE_HALF_DUPLEX |
2430 BNX2_EMAC_MODE_MAC_LOOP | BNX2_EMAC_MODE_FORCE_LINK |
Michael Chan59b47d82006-11-19 14:10:45 -08002431 BNX2_EMAC_MODE_25G_MODE);
Michael Chanbc5a0692006-01-23 16:13:22 -08002432
2433 mac_mode |= BNX2_EMAC_MODE_PORT_GMII;
2434 REG_WR(bp, BNX2_EMAC_MODE, mac_mode);
2435 bp->link_up = 1;
2436 return 0;
2437}
2438
Michael Chanb6016b72005-05-26 13:03:09 -07002439static int
Michael Chana2f13892008-07-14 22:38:23 -07002440bnx2_fw_sync(struct bnx2 *bp, u32 msg_data, int ack, int silent)
Michael Chanb6016b72005-05-26 13:03:09 -07002441{
2442 int i;
2443 u32 val;
2444
Michael Chanb6016b72005-05-26 13:03:09 -07002445 bp->fw_wr_seq++;
2446 msg_data |= bp->fw_wr_seq;
2447
Michael Chan2726d6e2008-01-29 21:35:05 -08002448 bnx2_shmem_wr(bp, BNX2_DRV_MB, msg_data);
Michael Chanb6016b72005-05-26 13:03:09 -07002449
Michael Chana2f13892008-07-14 22:38:23 -07002450 if (!ack)
2451 return 0;
2452
Michael Chanb6016b72005-05-26 13:03:09 -07002453 /* wait for an acknowledgement. */
Michael Chan40105c02008-11-12 16:02:45 -08002454 for (i = 0; i < (BNX2_FW_ACK_TIME_OUT_MS / 10); i++) {
Michael Chanb090ae22006-01-23 16:07:10 -08002455 msleep(10);
Michael Chanb6016b72005-05-26 13:03:09 -07002456
Michael Chan2726d6e2008-01-29 21:35:05 -08002457 val = bnx2_shmem_rd(bp, BNX2_FW_MB);
Michael Chanb6016b72005-05-26 13:03:09 -07002458
2459 if ((val & BNX2_FW_MSG_ACK) == (msg_data & BNX2_DRV_MSG_SEQ))
2460 break;
2461 }
Michael Chanb090ae22006-01-23 16:07:10 -08002462 if ((msg_data & BNX2_DRV_MSG_DATA) == BNX2_DRV_MSG_DATA_WAIT0)
2463 return 0;
Michael Chanb6016b72005-05-26 13:03:09 -07002464
2465 /* If we timed out, inform the firmware that this is the case. */
Michael Chanb090ae22006-01-23 16:07:10 -08002466 if ((val & BNX2_FW_MSG_ACK) != (msg_data & BNX2_DRV_MSG_SEQ)) {
2467 if (!silent)
2468 printk(KERN_ERR PFX "fw sync timeout, reset code = "
2469 "%x\n", msg_data);
Michael Chanb6016b72005-05-26 13:03:09 -07002470
2471 msg_data &= ~BNX2_DRV_MSG_CODE;
2472 msg_data |= BNX2_DRV_MSG_CODE_FW_TIMEOUT;
2473
Michael Chan2726d6e2008-01-29 21:35:05 -08002474 bnx2_shmem_wr(bp, BNX2_DRV_MB, msg_data);
Michael Chanb6016b72005-05-26 13:03:09 -07002475
Michael Chanb6016b72005-05-26 13:03:09 -07002476 return -EBUSY;
2477 }
2478
Michael Chanb090ae22006-01-23 16:07:10 -08002479 if ((val & BNX2_FW_MSG_STATUS_MASK) != BNX2_FW_MSG_STATUS_OK)
2480 return -EIO;
2481
Michael Chanb6016b72005-05-26 13:03:09 -07002482 return 0;
2483}
2484
Michael Chan59b47d82006-11-19 14:10:45 -08002485static int
2486bnx2_init_5709_context(struct bnx2 *bp)
2487{
2488 int i, ret = 0;
2489 u32 val;
2490
2491 val = BNX2_CTX_COMMAND_ENABLED | BNX2_CTX_COMMAND_MEM_INIT | (1 << 12);
2492 val |= (BCM_PAGE_BITS - 8) << 16;
2493 REG_WR(bp, BNX2_CTX_COMMAND, val);
Michael Chan641bdcd2007-06-04 21:22:24 -07002494 for (i = 0; i < 10; i++) {
2495 val = REG_RD(bp, BNX2_CTX_COMMAND);
2496 if (!(val & BNX2_CTX_COMMAND_MEM_INIT))
2497 break;
2498 udelay(2);
2499 }
2500 if (val & BNX2_CTX_COMMAND_MEM_INIT)
2501 return -EBUSY;
2502
Michael Chan59b47d82006-11-19 14:10:45 -08002503 for (i = 0; i < bp->ctx_pages; i++) {
2504 int j;
2505
Michael Chan352f7682008-05-02 16:57:26 -07002506 if (bp->ctx_blk[i])
2507 memset(bp->ctx_blk[i], 0, BCM_PAGE_SIZE);
2508 else
2509 return -ENOMEM;
2510
Michael Chan59b47d82006-11-19 14:10:45 -08002511 REG_WR(bp, BNX2_CTX_HOST_PAGE_TBL_DATA0,
2512 (bp->ctx_blk_mapping[i] & 0xffffffff) |
2513 BNX2_CTX_HOST_PAGE_TBL_DATA0_VALID);
2514 REG_WR(bp, BNX2_CTX_HOST_PAGE_TBL_DATA1,
2515 (u64) bp->ctx_blk_mapping[i] >> 32);
2516 REG_WR(bp, BNX2_CTX_HOST_PAGE_TBL_CTRL, i |
2517 BNX2_CTX_HOST_PAGE_TBL_CTRL_WRITE_REQ);
2518 for (j = 0; j < 10; j++) {
2519
2520 val = REG_RD(bp, BNX2_CTX_HOST_PAGE_TBL_CTRL);
2521 if (!(val & BNX2_CTX_HOST_PAGE_TBL_CTRL_WRITE_REQ))
2522 break;
2523 udelay(5);
2524 }
2525 if (val & BNX2_CTX_HOST_PAGE_TBL_CTRL_WRITE_REQ) {
2526 ret = -EBUSY;
2527 break;
2528 }
2529 }
2530 return ret;
2531}
2532
Michael Chanb6016b72005-05-26 13:03:09 -07002533static void
2534bnx2_init_context(struct bnx2 *bp)
2535{
2536 u32 vcid;
2537
2538 vcid = 96;
2539 while (vcid) {
2540 u32 vcid_addr, pcid_addr, offset;
Michael Chan7947b202007-06-04 21:17:10 -07002541 int i;
Michael Chanb6016b72005-05-26 13:03:09 -07002542
2543 vcid--;
2544
2545 if (CHIP_ID(bp) == CHIP_ID_5706_A0) {
2546 u32 new_vcid;
2547
2548 vcid_addr = GET_PCID_ADDR(vcid);
2549 if (vcid & 0x8) {
2550 new_vcid = 0x60 + (vcid & 0xf0) + (vcid & 0x7);
2551 }
2552 else {
2553 new_vcid = vcid;
2554 }
2555 pcid_addr = GET_PCID_ADDR(new_vcid);
2556 }
2557 else {
2558 vcid_addr = GET_CID_ADDR(vcid);
2559 pcid_addr = vcid_addr;
2560 }
2561
Michael Chan7947b202007-06-04 21:17:10 -07002562 for (i = 0; i < (CTX_SIZE / PHY_CTX_SIZE); i++) {
2563 vcid_addr += (i << PHY_CTX_SHIFT);
2564 pcid_addr += (i << PHY_CTX_SHIFT);
Michael Chanb6016b72005-05-26 13:03:09 -07002565
Michael Chan5d5d0012007-12-12 11:17:43 -08002566 REG_WR(bp, BNX2_CTX_VIRT_ADDR, vcid_addr);
Michael Chan7947b202007-06-04 21:17:10 -07002567 REG_WR(bp, BNX2_CTX_PAGE_TBL, pcid_addr);
2568
2569 /* Zero out the context. */
2570 for (offset = 0; offset < PHY_CTX_SIZE; offset += 4)
Michael Chan62a83132008-01-29 21:35:40 -08002571 bnx2_ctx_wr(bp, vcid_addr, offset, 0);
Michael Chanb6016b72005-05-26 13:03:09 -07002572 }
Michael Chanb6016b72005-05-26 13:03:09 -07002573 }
2574}
2575
2576static int
2577bnx2_alloc_bad_rbuf(struct bnx2 *bp)
2578{
2579 u16 *good_mbuf;
2580 u32 good_mbuf_cnt;
2581 u32 val;
2582
2583 good_mbuf = kmalloc(512 * sizeof(u16), GFP_KERNEL);
2584 if (good_mbuf == NULL) {
2585 printk(KERN_ERR PFX "Failed to allocate memory in "
2586 "bnx2_alloc_bad_rbuf\n");
2587 return -ENOMEM;
2588 }
2589
2590 REG_WR(bp, BNX2_MISC_ENABLE_SET_BITS,
2591 BNX2_MISC_ENABLE_SET_BITS_RX_MBUF_ENABLE);
2592
2593 good_mbuf_cnt = 0;
2594
2595 /* Allocate a bunch of mbufs and save the good ones in an array. */
Michael Chan2726d6e2008-01-29 21:35:05 -08002596 val = bnx2_reg_rd_ind(bp, BNX2_RBUF_STATUS1);
Michael Chanb6016b72005-05-26 13:03:09 -07002597 while (val & BNX2_RBUF_STATUS1_FREE_COUNT) {
Michael Chan2726d6e2008-01-29 21:35:05 -08002598 bnx2_reg_wr_ind(bp, BNX2_RBUF_COMMAND,
2599 BNX2_RBUF_COMMAND_ALLOC_REQ);
Michael Chanb6016b72005-05-26 13:03:09 -07002600
Michael Chan2726d6e2008-01-29 21:35:05 -08002601 val = bnx2_reg_rd_ind(bp, BNX2_RBUF_FW_BUF_ALLOC);
Michael Chanb6016b72005-05-26 13:03:09 -07002602
2603 val &= BNX2_RBUF_FW_BUF_ALLOC_VALUE;
2604
2605 /* The addresses with Bit 9 set are bad memory blocks. */
2606 if (!(val & (1 << 9))) {
2607 good_mbuf[good_mbuf_cnt] = (u16) val;
2608 good_mbuf_cnt++;
2609 }
2610
Michael Chan2726d6e2008-01-29 21:35:05 -08002611 val = bnx2_reg_rd_ind(bp, BNX2_RBUF_STATUS1);
Michael Chanb6016b72005-05-26 13:03:09 -07002612 }
2613
2614 /* Free the good ones back to the mbuf pool thus discarding
2615 * all the bad ones. */
2616 while (good_mbuf_cnt) {
2617 good_mbuf_cnt--;
2618
2619 val = good_mbuf[good_mbuf_cnt];
2620 val = (val << 9) | val | 1;
2621
Michael Chan2726d6e2008-01-29 21:35:05 -08002622 bnx2_reg_wr_ind(bp, BNX2_RBUF_FW_BUF_FREE, val);
Michael Chanb6016b72005-05-26 13:03:09 -07002623 }
2624 kfree(good_mbuf);
2625 return 0;
2626}
2627
2628static void
Benjamin Li5fcaed02008-07-14 22:39:52 -07002629bnx2_set_mac_addr(struct bnx2 *bp, u8 *mac_addr, u32 pos)
Michael Chanb6016b72005-05-26 13:03:09 -07002630{
2631 u32 val;
Michael Chanb6016b72005-05-26 13:03:09 -07002632
2633 val = (mac_addr[0] << 8) | mac_addr[1];
2634
Benjamin Li5fcaed02008-07-14 22:39:52 -07002635 REG_WR(bp, BNX2_EMAC_MAC_MATCH0 + (pos * 8), val);
Michael Chanb6016b72005-05-26 13:03:09 -07002636
Jeff Garzik6aa20a22006-09-13 13:24:59 -04002637 val = (mac_addr[2] << 24) | (mac_addr[3] << 16) |
Michael Chanb6016b72005-05-26 13:03:09 -07002638 (mac_addr[4] << 8) | mac_addr[5];
2639
Benjamin Li5fcaed02008-07-14 22:39:52 -07002640 REG_WR(bp, BNX2_EMAC_MAC_MATCH1 + (pos * 8), val);
Michael Chanb6016b72005-05-26 13:03:09 -07002641}
2642
2643static inline int
Michael Chanbb4f98a2008-06-19 16:38:19 -07002644bnx2_alloc_rx_page(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr, u16 index)
Michael Chan47bf4242007-12-12 11:19:12 -08002645{
2646 dma_addr_t mapping;
Michael Chanbb4f98a2008-06-19 16:38:19 -07002647 struct sw_pg *rx_pg = &rxr->rx_pg_ring[index];
Michael Chan47bf4242007-12-12 11:19:12 -08002648 struct rx_bd *rxbd =
Michael Chanbb4f98a2008-06-19 16:38:19 -07002649 &rxr->rx_pg_desc_ring[RX_RING(index)][RX_IDX(index)];
Michael Chan47bf4242007-12-12 11:19:12 -08002650 struct page *page = alloc_page(GFP_ATOMIC);
2651
2652 if (!page)
2653 return -ENOMEM;
2654 mapping = pci_map_page(bp->pdev, page, 0, PAGE_SIZE,
2655 PCI_DMA_FROMDEVICE);
Benjamin Li3d16af82008-10-09 12:26:41 -07002656 if (pci_dma_mapping_error(bp->pdev, mapping)) {
2657 __free_page(page);
2658 return -EIO;
2659 }
2660
Michael Chan47bf4242007-12-12 11:19:12 -08002661 rx_pg->page = page;
2662 pci_unmap_addr_set(rx_pg, mapping, mapping);
2663 rxbd->rx_bd_haddr_hi = (u64) mapping >> 32;
2664 rxbd->rx_bd_haddr_lo = (u64) mapping & 0xffffffff;
2665 return 0;
2666}
2667
2668static void
Michael Chanbb4f98a2008-06-19 16:38:19 -07002669bnx2_free_rx_page(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr, u16 index)
Michael Chan47bf4242007-12-12 11:19:12 -08002670{
Michael Chanbb4f98a2008-06-19 16:38:19 -07002671 struct sw_pg *rx_pg = &rxr->rx_pg_ring[index];
Michael Chan47bf4242007-12-12 11:19:12 -08002672 struct page *page = rx_pg->page;
2673
2674 if (!page)
2675 return;
2676
2677 pci_unmap_page(bp->pdev, pci_unmap_addr(rx_pg, mapping), PAGE_SIZE,
2678 PCI_DMA_FROMDEVICE);
2679
2680 __free_page(page);
2681 rx_pg->page = NULL;
2682}
2683
2684static inline int
Michael Chanbb4f98a2008-06-19 16:38:19 -07002685bnx2_alloc_rx_skb(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr, u16 index)
Michael Chanb6016b72005-05-26 13:03:09 -07002686{
2687 struct sk_buff *skb;
Michael Chanbb4f98a2008-06-19 16:38:19 -07002688 struct sw_bd *rx_buf = &rxr->rx_buf_ring[index];
Michael Chanb6016b72005-05-26 13:03:09 -07002689 dma_addr_t mapping;
Michael Chanbb4f98a2008-06-19 16:38:19 -07002690 struct rx_bd *rxbd = &rxr->rx_desc_ring[RX_RING(index)][RX_IDX(index)];
Michael Chanb6016b72005-05-26 13:03:09 -07002691 unsigned long align;
2692
Michael Chan932f3772006-08-15 01:39:36 -07002693 skb = netdev_alloc_skb(bp->dev, bp->rx_buf_size);
Michael Chanb6016b72005-05-26 13:03:09 -07002694 if (skb == NULL) {
2695 return -ENOMEM;
2696 }
2697
Michael Chan59b47d82006-11-19 14:10:45 -08002698 if (unlikely((align = (unsigned long) skb->data & (BNX2_RX_ALIGN - 1))))
2699 skb_reserve(skb, BNX2_RX_ALIGN - align);
Michael Chanb6016b72005-05-26 13:03:09 -07002700
Michael Chanb6016b72005-05-26 13:03:09 -07002701 mapping = pci_map_single(bp->pdev, skb->data, bp->rx_buf_use_size,
2702 PCI_DMA_FROMDEVICE);
Benjamin Li3d16af82008-10-09 12:26:41 -07002703 if (pci_dma_mapping_error(bp->pdev, mapping)) {
2704 dev_kfree_skb(skb);
2705 return -EIO;
2706 }
Michael Chanb6016b72005-05-26 13:03:09 -07002707
2708 rx_buf->skb = skb;
2709 pci_unmap_addr_set(rx_buf, mapping, mapping);
2710
2711 rxbd->rx_bd_haddr_hi = (u64) mapping >> 32;
2712 rxbd->rx_bd_haddr_lo = (u64) mapping & 0xffffffff;
2713
Michael Chanbb4f98a2008-06-19 16:38:19 -07002714 rxr->rx_prod_bseq += bp->rx_buf_use_size;
Michael Chanb6016b72005-05-26 13:03:09 -07002715
2716 return 0;
2717}
2718
Michael Chanda3e4fb2007-05-03 13:24:23 -07002719static int
Michael Chan35efa7c2007-12-20 19:56:37 -08002720bnx2_phy_event_is_set(struct bnx2 *bp, struct bnx2_napi *bnapi, u32 event)
Michael Chanda3e4fb2007-05-03 13:24:23 -07002721{
Michael Chan43e80b82008-06-19 16:41:08 -07002722 struct status_block *sblk = bnapi->status_blk.msi;
Michael Chanda3e4fb2007-05-03 13:24:23 -07002723 u32 new_link_state, old_link_state;
2724 int is_set = 1;
2725
2726 new_link_state = sblk->status_attn_bits & event;
2727 old_link_state = sblk->status_attn_bits_ack & event;
2728 if (new_link_state != old_link_state) {
2729 if (new_link_state)
2730 REG_WR(bp, BNX2_PCICFG_STATUS_BIT_SET_CMD, event);
2731 else
2732 REG_WR(bp, BNX2_PCICFG_STATUS_BIT_CLEAR_CMD, event);
2733 } else
2734 is_set = 0;
2735
2736 return is_set;
2737}
2738
Michael Chanb6016b72005-05-26 13:03:09 -07002739static void
Michael Chan35efa7c2007-12-20 19:56:37 -08002740bnx2_phy_int(struct bnx2 *bp, struct bnx2_napi *bnapi)
Michael Chanb6016b72005-05-26 13:03:09 -07002741{
Michael Chan74ecc622008-05-02 16:56:16 -07002742 spin_lock(&bp->phy_lock);
2743
2744 if (bnx2_phy_event_is_set(bp, bnapi, STATUS_ATTN_BITS_LINK_STATE))
Michael Chanb6016b72005-05-26 13:03:09 -07002745 bnx2_set_link(bp);
Michael Chan35efa7c2007-12-20 19:56:37 -08002746 if (bnx2_phy_event_is_set(bp, bnapi, STATUS_ATTN_BITS_TIMER_ABORT))
Michael Chan0d8a6572007-07-07 22:49:43 -07002747 bnx2_set_remote_link(bp);
2748
Michael Chan74ecc622008-05-02 16:56:16 -07002749 spin_unlock(&bp->phy_lock);
2750
Michael Chanb6016b72005-05-26 13:03:09 -07002751}
2752
Michael Chanead72702007-12-20 19:55:39 -08002753static inline u16
Michael Chan35efa7c2007-12-20 19:56:37 -08002754bnx2_get_hw_tx_cons(struct bnx2_napi *bnapi)
Michael Chanead72702007-12-20 19:55:39 -08002755{
2756 u16 cons;
2757
Michael Chan43e80b82008-06-19 16:41:08 -07002758 /* Tell compiler that status block fields can change. */
2759 barrier();
2760 cons = *bnapi->hw_tx_cons_ptr;
Michael Chan581daf72009-05-06 16:46:47 -07002761 barrier();
Michael Chanead72702007-12-20 19:55:39 -08002762 if (unlikely((cons & MAX_TX_DESC_CNT) == MAX_TX_DESC_CNT))
2763 cons++;
2764 return cons;
2765}
2766
Michael Chan57851d82007-12-20 20:01:44 -08002767static int
2768bnx2_tx_int(struct bnx2 *bp, struct bnx2_napi *bnapi, int budget)
Michael Chanb6016b72005-05-26 13:03:09 -07002769{
Michael Chan35e90102008-06-19 16:37:42 -07002770 struct bnx2_tx_ring_info *txr = &bnapi->tx_ring;
Michael Chanb6016b72005-05-26 13:03:09 -07002771 u16 hw_cons, sw_cons, sw_ring_cons;
Benjamin Li706bf242008-07-18 17:55:11 -07002772 int tx_pkt = 0, index;
2773 struct netdev_queue *txq;
2774
2775 index = (bnapi - bp->bnx2_napi);
2776 txq = netdev_get_tx_queue(bp->dev, index);
Michael Chanb6016b72005-05-26 13:03:09 -07002777
Michael Chan35efa7c2007-12-20 19:56:37 -08002778 hw_cons = bnx2_get_hw_tx_cons(bnapi);
Michael Chan35e90102008-06-19 16:37:42 -07002779 sw_cons = txr->tx_cons;
Michael Chanb6016b72005-05-26 13:03:09 -07002780
2781 while (sw_cons != hw_cons) {
Benjamin Li3d16af82008-10-09 12:26:41 -07002782 struct sw_tx_bd *tx_buf;
Michael Chanb6016b72005-05-26 13:03:09 -07002783 struct sk_buff *skb;
2784 int i, last;
2785
2786 sw_ring_cons = TX_RING_IDX(sw_cons);
2787
Michael Chan35e90102008-06-19 16:37:42 -07002788 tx_buf = &txr->tx_buf_ring[sw_ring_cons];
Michael Chanb6016b72005-05-26 13:03:09 -07002789 skb = tx_buf->skb;
Arjan van de Ven1d39ed52006-12-12 14:06:23 +01002790
Michael Chanb6016b72005-05-26 13:03:09 -07002791 /* partial BD completions possible with TSO packets */
Herbert Xu89114af2006-07-08 13:34:32 -07002792 if (skb_is_gso(skb)) {
Michael Chanb6016b72005-05-26 13:03:09 -07002793 u16 last_idx, last_ring_idx;
2794
2795 last_idx = sw_cons +
2796 skb_shinfo(skb)->nr_frags + 1;
2797 last_ring_idx = sw_ring_cons +
2798 skb_shinfo(skb)->nr_frags + 1;
2799 if (unlikely(last_ring_idx >= MAX_TX_DESC_CNT)) {
2800 last_idx++;
2801 }
2802 if (((s16) ((s16) last_idx - (s16) hw_cons)) > 0) {
2803 break;
2804 }
2805 }
Arjan van de Ven1d39ed52006-12-12 14:06:23 +01002806
Benjamin Li3d16af82008-10-09 12:26:41 -07002807 skb_dma_unmap(&bp->pdev->dev, skb, DMA_TO_DEVICE);
Michael Chanb6016b72005-05-26 13:03:09 -07002808
2809 tx_buf->skb = NULL;
2810 last = skb_shinfo(skb)->nr_frags;
2811
2812 for (i = 0; i < last; i++) {
2813 sw_cons = NEXT_TX_BD(sw_cons);
Michael Chanb6016b72005-05-26 13:03:09 -07002814 }
2815
2816 sw_cons = NEXT_TX_BD(sw_cons);
2817
Michael Chan745720e2006-06-29 12:37:41 -07002818 dev_kfree_skb(skb);
Michael Chan57851d82007-12-20 20:01:44 -08002819 tx_pkt++;
2820 if (tx_pkt == budget)
2821 break;
Michael Chanb6016b72005-05-26 13:03:09 -07002822
Michael Chan35efa7c2007-12-20 19:56:37 -08002823 hw_cons = bnx2_get_hw_tx_cons(bnapi);
Michael Chanb6016b72005-05-26 13:03:09 -07002824 }
2825
Michael Chan35e90102008-06-19 16:37:42 -07002826 txr->hw_tx_cons = hw_cons;
2827 txr->tx_cons = sw_cons;
Benjamin Li706bf242008-07-18 17:55:11 -07002828
Michael Chan2f8af122006-08-15 01:39:10 -07002829 /* Need to make the tx_cons update visible to bnx2_start_xmit()
Benjamin Li706bf242008-07-18 17:55:11 -07002830 * before checking for netif_tx_queue_stopped(). Without the
Michael Chan2f8af122006-08-15 01:39:10 -07002831 * memory barrier, there is a small possibility that bnx2_start_xmit()
2832 * will miss it and cause the queue to be stopped forever.
2833 */
2834 smp_mb();
Michael Chanb6016b72005-05-26 13:03:09 -07002835
Benjamin Li706bf242008-07-18 17:55:11 -07002836 if (unlikely(netif_tx_queue_stopped(txq)) &&
Michael Chan35e90102008-06-19 16:37:42 -07002837 (bnx2_tx_avail(bp, txr) > bp->tx_wake_thresh)) {
Benjamin Li706bf242008-07-18 17:55:11 -07002838 __netif_tx_lock(txq, smp_processor_id());
2839 if ((netif_tx_queue_stopped(txq)) &&
Michael Chan35e90102008-06-19 16:37:42 -07002840 (bnx2_tx_avail(bp, txr) > bp->tx_wake_thresh))
Benjamin Li706bf242008-07-18 17:55:11 -07002841 netif_tx_wake_queue(txq);
2842 __netif_tx_unlock(txq);
Michael Chanb6016b72005-05-26 13:03:09 -07002843 }
Benjamin Li706bf242008-07-18 17:55:11 -07002844
Michael Chan57851d82007-12-20 20:01:44 -08002845 return tx_pkt;
Michael Chanb6016b72005-05-26 13:03:09 -07002846}
2847
Michael Chan1db82f22007-12-12 11:19:35 -08002848static void
Michael Chanbb4f98a2008-06-19 16:38:19 -07002849bnx2_reuse_rx_skb_pages(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr,
Michael Chana1f60192007-12-20 19:57:19 -08002850 struct sk_buff *skb, int count)
Michael Chan1db82f22007-12-12 11:19:35 -08002851{
2852 struct sw_pg *cons_rx_pg, *prod_rx_pg;
2853 struct rx_bd *cons_bd, *prod_bd;
Michael Chan1db82f22007-12-12 11:19:35 -08002854 int i;
Benjamin Li3d16af82008-10-09 12:26:41 -07002855 u16 hw_prod, prod;
Michael Chanbb4f98a2008-06-19 16:38:19 -07002856 u16 cons = rxr->rx_pg_cons;
Michael Chan1db82f22007-12-12 11:19:35 -08002857
Benjamin Li3d16af82008-10-09 12:26:41 -07002858 cons_rx_pg = &rxr->rx_pg_ring[cons];
2859
2860 /* The caller was unable to allocate a new page to replace the
2861 * last one in the frags array, so we need to recycle that page
2862 * and then free the skb.
2863 */
2864 if (skb) {
2865 struct page *page;
2866 struct skb_shared_info *shinfo;
2867
2868 shinfo = skb_shinfo(skb);
2869 shinfo->nr_frags--;
2870 page = shinfo->frags[shinfo->nr_frags].page;
2871 shinfo->frags[shinfo->nr_frags].page = NULL;
2872
2873 cons_rx_pg->page = page;
2874 dev_kfree_skb(skb);
2875 }
2876
2877 hw_prod = rxr->rx_pg_prod;
2878
Michael Chan1db82f22007-12-12 11:19:35 -08002879 for (i = 0; i < count; i++) {
2880 prod = RX_PG_RING_IDX(hw_prod);
2881
Michael Chanbb4f98a2008-06-19 16:38:19 -07002882 prod_rx_pg = &rxr->rx_pg_ring[prod];
2883 cons_rx_pg = &rxr->rx_pg_ring[cons];
2884 cons_bd = &rxr->rx_pg_desc_ring[RX_RING(cons)][RX_IDX(cons)];
2885 prod_bd = &rxr->rx_pg_desc_ring[RX_RING(prod)][RX_IDX(prod)];
Michael Chan1db82f22007-12-12 11:19:35 -08002886
Michael Chan1db82f22007-12-12 11:19:35 -08002887 if (prod != cons) {
2888 prod_rx_pg->page = cons_rx_pg->page;
2889 cons_rx_pg->page = NULL;
2890 pci_unmap_addr_set(prod_rx_pg, mapping,
2891 pci_unmap_addr(cons_rx_pg, mapping));
2892
2893 prod_bd->rx_bd_haddr_hi = cons_bd->rx_bd_haddr_hi;
2894 prod_bd->rx_bd_haddr_lo = cons_bd->rx_bd_haddr_lo;
2895
2896 }
2897 cons = RX_PG_RING_IDX(NEXT_RX_BD(cons));
2898 hw_prod = NEXT_RX_BD(hw_prod);
2899 }
Michael Chanbb4f98a2008-06-19 16:38:19 -07002900 rxr->rx_pg_prod = hw_prod;
2901 rxr->rx_pg_cons = cons;
Michael Chan1db82f22007-12-12 11:19:35 -08002902}
2903
Michael Chanb6016b72005-05-26 13:03:09 -07002904static inline void
Michael Chanbb4f98a2008-06-19 16:38:19 -07002905bnx2_reuse_rx_skb(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr,
2906 struct sk_buff *skb, u16 cons, u16 prod)
Michael Chanb6016b72005-05-26 13:03:09 -07002907{
Michael Chan236b6392006-03-20 17:49:02 -08002908 struct sw_bd *cons_rx_buf, *prod_rx_buf;
2909 struct rx_bd *cons_bd, *prod_bd;
2910
Michael Chanbb4f98a2008-06-19 16:38:19 -07002911 cons_rx_buf = &rxr->rx_buf_ring[cons];
2912 prod_rx_buf = &rxr->rx_buf_ring[prod];
Michael Chanb6016b72005-05-26 13:03:09 -07002913
2914 pci_dma_sync_single_for_device(bp->pdev,
2915 pci_unmap_addr(cons_rx_buf, mapping),
Benjamin Li601d3d12008-05-16 22:19:35 -07002916 BNX2_RX_OFFSET + BNX2_RX_COPY_THRESH, PCI_DMA_FROMDEVICE);
Michael Chanb6016b72005-05-26 13:03:09 -07002917
Michael Chanbb4f98a2008-06-19 16:38:19 -07002918 rxr->rx_prod_bseq += bp->rx_buf_use_size;
Michael Chan236b6392006-03-20 17:49:02 -08002919
2920 prod_rx_buf->skb = skb;
2921
2922 if (cons == prod)
2923 return;
2924
Michael Chanb6016b72005-05-26 13:03:09 -07002925 pci_unmap_addr_set(prod_rx_buf, mapping,
2926 pci_unmap_addr(cons_rx_buf, mapping));
2927
Michael Chanbb4f98a2008-06-19 16:38:19 -07002928 cons_bd = &rxr->rx_desc_ring[RX_RING(cons)][RX_IDX(cons)];
2929 prod_bd = &rxr->rx_desc_ring[RX_RING(prod)][RX_IDX(prod)];
Michael Chan236b6392006-03-20 17:49:02 -08002930 prod_bd->rx_bd_haddr_hi = cons_bd->rx_bd_haddr_hi;
2931 prod_bd->rx_bd_haddr_lo = cons_bd->rx_bd_haddr_lo;
Michael Chanb6016b72005-05-26 13:03:09 -07002932}
2933
Michael Chan85833c62007-12-12 11:17:01 -08002934static int
Michael Chanbb4f98a2008-06-19 16:38:19 -07002935bnx2_rx_skb(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr, struct sk_buff *skb,
Michael Chana1f60192007-12-20 19:57:19 -08002936 unsigned int len, unsigned int hdr_len, dma_addr_t dma_addr,
2937 u32 ring_idx)
Michael Chan85833c62007-12-12 11:17:01 -08002938{
2939 int err;
2940 u16 prod = ring_idx & 0xffff;
2941
Michael Chanbb4f98a2008-06-19 16:38:19 -07002942 err = bnx2_alloc_rx_skb(bp, rxr, prod);
Michael Chan85833c62007-12-12 11:17:01 -08002943 if (unlikely(err)) {
Michael Chanbb4f98a2008-06-19 16:38:19 -07002944 bnx2_reuse_rx_skb(bp, rxr, skb, (u16) (ring_idx >> 16), prod);
Michael Chan1db82f22007-12-12 11:19:35 -08002945 if (hdr_len) {
2946 unsigned int raw_len = len + 4;
2947 int pages = PAGE_ALIGN(raw_len - hdr_len) >> PAGE_SHIFT;
2948
Michael Chanbb4f98a2008-06-19 16:38:19 -07002949 bnx2_reuse_rx_skb_pages(bp, rxr, NULL, pages);
Michael Chan1db82f22007-12-12 11:19:35 -08002950 }
Michael Chan85833c62007-12-12 11:17:01 -08002951 return err;
2952 }
2953
Benjamin Lid89cb6a2008-05-16 22:18:57 -07002954 skb_reserve(skb, BNX2_RX_OFFSET);
Michael Chan85833c62007-12-12 11:17:01 -08002955 pci_unmap_single(bp->pdev, dma_addr, bp->rx_buf_use_size,
2956 PCI_DMA_FROMDEVICE);
2957
Michael Chan1db82f22007-12-12 11:19:35 -08002958 if (hdr_len == 0) {
2959 skb_put(skb, len);
2960 return 0;
2961 } else {
2962 unsigned int i, frag_len, frag_size, pages;
2963 struct sw_pg *rx_pg;
Michael Chanbb4f98a2008-06-19 16:38:19 -07002964 u16 pg_cons = rxr->rx_pg_cons;
2965 u16 pg_prod = rxr->rx_pg_prod;
Michael Chan1db82f22007-12-12 11:19:35 -08002966
2967 frag_size = len + 4 - hdr_len;
2968 pages = PAGE_ALIGN(frag_size) >> PAGE_SHIFT;
2969 skb_put(skb, hdr_len);
2970
2971 for (i = 0; i < pages; i++) {
Benjamin Li3d16af82008-10-09 12:26:41 -07002972 dma_addr_t mapping_old;
2973
Michael Chan1db82f22007-12-12 11:19:35 -08002974 frag_len = min(frag_size, (unsigned int) PAGE_SIZE);
2975 if (unlikely(frag_len <= 4)) {
2976 unsigned int tail = 4 - frag_len;
2977
Michael Chanbb4f98a2008-06-19 16:38:19 -07002978 rxr->rx_pg_cons = pg_cons;
2979 rxr->rx_pg_prod = pg_prod;
2980 bnx2_reuse_rx_skb_pages(bp, rxr, NULL,
Michael Chana1f60192007-12-20 19:57:19 -08002981 pages - i);
Michael Chan1db82f22007-12-12 11:19:35 -08002982 skb->len -= tail;
2983 if (i == 0) {
2984 skb->tail -= tail;
2985 } else {
2986 skb_frag_t *frag =
2987 &skb_shinfo(skb)->frags[i - 1];
2988 frag->size -= tail;
2989 skb->data_len -= tail;
2990 skb->truesize -= tail;
2991 }
2992 return 0;
2993 }
Michael Chanbb4f98a2008-06-19 16:38:19 -07002994 rx_pg = &rxr->rx_pg_ring[pg_cons];
Michael Chan1db82f22007-12-12 11:19:35 -08002995
Benjamin Li3d16af82008-10-09 12:26:41 -07002996 /* Don't unmap yet. If we're unable to allocate a new
2997 * page, we need to recycle the page and the DMA addr.
2998 */
2999 mapping_old = pci_unmap_addr(rx_pg, mapping);
Michael Chan1db82f22007-12-12 11:19:35 -08003000 if (i == pages - 1)
3001 frag_len -= 4;
3002
3003 skb_fill_page_desc(skb, i, rx_pg->page, 0, frag_len);
3004 rx_pg->page = NULL;
3005
Michael Chanbb4f98a2008-06-19 16:38:19 -07003006 err = bnx2_alloc_rx_page(bp, rxr,
3007 RX_PG_RING_IDX(pg_prod));
Michael Chan1db82f22007-12-12 11:19:35 -08003008 if (unlikely(err)) {
Michael Chanbb4f98a2008-06-19 16:38:19 -07003009 rxr->rx_pg_cons = pg_cons;
3010 rxr->rx_pg_prod = pg_prod;
3011 bnx2_reuse_rx_skb_pages(bp, rxr, skb,
Michael Chana1f60192007-12-20 19:57:19 -08003012 pages - i);
Michael Chan1db82f22007-12-12 11:19:35 -08003013 return err;
3014 }
3015
Benjamin Li3d16af82008-10-09 12:26:41 -07003016 pci_unmap_page(bp->pdev, mapping_old,
3017 PAGE_SIZE, PCI_DMA_FROMDEVICE);
3018
Michael Chan1db82f22007-12-12 11:19:35 -08003019 frag_size -= frag_len;
3020 skb->data_len += frag_len;
3021 skb->truesize += frag_len;
3022 skb->len += frag_len;
3023
3024 pg_prod = NEXT_RX_BD(pg_prod);
3025 pg_cons = RX_PG_RING_IDX(NEXT_RX_BD(pg_cons));
3026 }
Michael Chanbb4f98a2008-06-19 16:38:19 -07003027 rxr->rx_pg_prod = pg_prod;
3028 rxr->rx_pg_cons = pg_cons;
Michael Chan1db82f22007-12-12 11:19:35 -08003029 }
Michael Chan85833c62007-12-12 11:17:01 -08003030 return 0;
3031}
3032
Michael Chanc09c2622007-12-10 17:18:37 -08003033static inline u16
Michael Chan35efa7c2007-12-20 19:56:37 -08003034bnx2_get_hw_rx_cons(struct bnx2_napi *bnapi)
Michael Chanc09c2622007-12-10 17:18:37 -08003035{
Michael Chanbb4f98a2008-06-19 16:38:19 -07003036 u16 cons;
3037
Michael Chan43e80b82008-06-19 16:41:08 -07003038 /* Tell compiler that status block fields can change. */
3039 barrier();
3040 cons = *bnapi->hw_rx_cons_ptr;
Michael Chan581daf72009-05-06 16:46:47 -07003041 barrier();
Michael Chanc09c2622007-12-10 17:18:37 -08003042 if (unlikely((cons & MAX_RX_DESC_CNT) == MAX_RX_DESC_CNT))
3043 cons++;
3044 return cons;
3045}
3046
Michael Chanb6016b72005-05-26 13:03:09 -07003047static int
Michael Chan35efa7c2007-12-20 19:56:37 -08003048bnx2_rx_int(struct bnx2 *bp, struct bnx2_napi *bnapi, int budget)
Michael Chanb6016b72005-05-26 13:03:09 -07003049{
Michael Chanbb4f98a2008-06-19 16:38:19 -07003050 struct bnx2_rx_ring_info *rxr = &bnapi->rx_ring;
Michael Chanb6016b72005-05-26 13:03:09 -07003051 u16 hw_cons, sw_cons, sw_ring_cons, sw_prod, sw_ring_prod;
3052 struct l2_fhdr *rx_hdr;
Michael Chan1db82f22007-12-12 11:19:35 -08003053 int rx_pkt = 0, pg_ring_used = 0;
Michael Chanb6016b72005-05-26 13:03:09 -07003054
Michael Chan35efa7c2007-12-20 19:56:37 -08003055 hw_cons = bnx2_get_hw_rx_cons(bnapi);
Michael Chanbb4f98a2008-06-19 16:38:19 -07003056 sw_cons = rxr->rx_cons;
3057 sw_prod = rxr->rx_prod;
Michael Chanb6016b72005-05-26 13:03:09 -07003058
3059 /* Memory barrier necessary as speculative reads of the rx
3060 * buffer can be ahead of the index in the status block
3061 */
3062 rmb();
3063 while (sw_cons != hw_cons) {
Michael Chan1db82f22007-12-12 11:19:35 -08003064 unsigned int len, hdr_len;
Michael Chanade2bfe2006-01-23 16:09:51 -08003065 u32 status;
Michael Chanb6016b72005-05-26 13:03:09 -07003066 struct sw_bd *rx_buf;
3067 struct sk_buff *skb;
Michael Chan236b6392006-03-20 17:49:02 -08003068 dma_addr_t dma_addr;
Michael Chanf22828e2008-08-14 15:30:14 -07003069 u16 vtag = 0;
3070 int hw_vlan __maybe_unused = 0;
Michael Chanb6016b72005-05-26 13:03:09 -07003071
3072 sw_ring_cons = RX_RING_IDX(sw_cons);
3073 sw_ring_prod = RX_RING_IDX(sw_prod);
3074
Michael Chanbb4f98a2008-06-19 16:38:19 -07003075 rx_buf = &rxr->rx_buf_ring[sw_ring_cons];
Michael Chanb6016b72005-05-26 13:03:09 -07003076 skb = rx_buf->skb;
Michael Chan236b6392006-03-20 17:49:02 -08003077
3078 rx_buf->skb = NULL;
3079
3080 dma_addr = pci_unmap_addr(rx_buf, mapping);
3081
3082 pci_dma_sync_single_for_cpu(bp->pdev, dma_addr,
Benjamin Li601d3d12008-05-16 22:19:35 -07003083 BNX2_RX_OFFSET + BNX2_RX_COPY_THRESH,
3084 PCI_DMA_FROMDEVICE);
Michael Chanb6016b72005-05-26 13:03:09 -07003085
3086 rx_hdr = (struct l2_fhdr *) skb->data;
Michael Chan1db82f22007-12-12 11:19:35 -08003087 len = rx_hdr->l2_fhdr_pkt_len;
Michael Chan990ec382009-02-12 16:54:13 -08003088 status = rx_hdr->l2_fhdr_status;
Michael Chanb6016b72005-05-26 13:03:09 -07003089
Michael Chan1db82f22007-12-12 11:19:35 -08003090 hdr_len = 0;
3091 if (status & L2_FHDR_STATUS_SPLIT) {
3092 hdr_len = rx_hdr->l2_fhdr_ip_xsum;
3093 pg_ring_used = 1;
3094 } else if (len > bp->rx_jumbo_thresh) {
3095 hdr_len = bp->rx_jumbo_thresh;
3096 pg_ring_used = 1;
3097 }
3098
Michael Chan990ec382009-02-12 16:54:13 -08003099 if (unlikely(status & (L2_FHDR_ERRORS_BAD_CRC |
3100 L2_FHDR_ERRORS_PHY_DECODE |
3101 L2_FHDR_ERRORS_ALIGNMENT |
3102 L2_FHDR_ERRORS_TOO_SHORT |
3103 L2_FHDR_ERRORS_GIANT_FRAME))) {
3104
3105 bnx2_reuse_rx_skb(bp, rxr, skb, sw_ring_cons,
3106 sw_ring_prod);
3107 if (pg_ring_used) {
3108 int pages;
3109
3110 pages = PAGE_ALIGN(len - hdr_len) >> PAGE_SHIFT;
3111
3112 bnx2_reuse_rx_skb_pages(bp, rxr, NULL, pages);
3113 }
3114 goto next_rx;
3115 }
3116
Michael Chan1db82f22007-12-12 11:19:35 -08003117 len -= 4;
Michael Chanb6016b72005-05-26 13:03:09 -07003118
Michael Chan5d5d0012007-12-12 11:17:43 -08003119 if (len <= bp->rx_copy_thresh) {
Michael Chanb6016b72005-05-26 13:03:09 -07003120 struct sk_buff *new_skb;
3121
Michael Chanf22828e2008-08-14 15:30:14 -07003122 new_skb = netdev_alloc_skb(bp->dev, len + 6);
Michael Chan85833c62007-12-12 11:17:01 -08003123 if (new_skb == NULL) {
Michael Chanbb4f98a2008-06-19 16:38:19 -07003124 bnx2_reuse_rx_skb(bp, rxr, skb, sw_ring_cons,
Michael Chan85833c62007-12-12 11:17:01 -08003125 sw_ring_prod);
3126 goto next_rx;
3127 }
Michael Chanb6016b72005-05-26 13:03:09 -07003128
3129 /* aligned copy */
Benjamin Lid89cb6a2008-05-16 22:18:57 -07003130 skb_copy_from_linear_data_offset(skb,
Michael Chanf22828e2008-08-14 15:30:14 -07003131 BNX2_RX_OFFSET - 6,
3132 new_skb->data, len + 6);
3133 skb_reserve(new_skb, 6);
Michael Chanb6016b72005-05-26 13:03:09 -07003134 skb_put(new_skb, len);
Michael Chanb6016b72005-05-26 13:03:09 -07003135
Michael Chanbb4f98a2008-06-19 16:38:19 -07003136 bnx2_reuse_rx_skb(bp, rxr, skb,
Michael Chanb6016b72005-05-26 13:03:09 -07003137 sw_ring_cons, sw_ring_prod);
3138
3139 skb = new_skb;
Michael Chanbb4f98a2008-06-19 16:38:19 -07003140 } else if (unlikely(bnx2_rx_skb(bp, rxr, skb, len, hdr_len,
Michael Chana1f60192007-12-20 19:57:19 -08003141 dma_addr, (sw_ring_cons << 16) | sw_ring_prod)))
Michael Chanb6016b72005-05-26 13:03:09 -07003142 goto next_rx;
Michael Chanb6016b72005-05-26 13:03:09 -07003143
Michael Chanf22828e2008-08-14 15:30:14 -07003144 if ((status & L2_FHDR_STATUS_L2_VLAN_TAG) &&
3145 !(bp->rx_mode & BNX2_EMAC_RX_MODE_KEEP_VLAN_TAG)) {
3146 vtag = rx_hdr->l2_fhdr_vlan_tag;
3147#ifdef BCM_VLAN
3148 if (bp->vlgrp)
3149 hw_vlan = 1;
3150 else
3151#endif
3152 {
3153 struct vlan_ethhdr *ve = (struct vlan_ethhdr *)
3154 __skb_push(skb, 4);
3155
3156 memmove(ve, skb->data + 4, ETH_ALEN * 2);
3157 ve->h_vlan_proto = htons(ETH_P_8021Q);
3158 ve->h_vlan_TCI = htons(vtag);
3159 len += 4;
3160 }
3161 }
3162
Michael Chanb6016b72005-05-26 13:03:09 -07003163 skb->protocol = eth_type_trans(skb, bp->dev);
3164
3165 if ((len > (bp->dev->mtu + ETH_HLEN)) &&
Alexey Dobriyand1e100b2006-06-11 20:57:17 -07003166 (ntohs(skb->protocol) != 0x8100)) {
Michael Chanb6016b72005-05-26 13:03:09 -07003167
Michael Chan745720e2006-06-29 12:37:41 -07003168 dev_kfree_skb(skb);
Michael Chanb6016b72005-05-26 13:03:09 -07003169 goto next_rx;
3170
3171 }
3172
Michael Chanb6016b72005-05-26 13:03:09 -07003173 skb->ip_summed = CHECKSUM_NONE;
3174 if (bp->rx_csum &&
3175 (status & (L2_FHDR_STATUS_TCP_SEGMENT |
3176 L2_FHDR_STATUS_UDP_DATAGRAM))) {
3177
Michael Chanade2bfe2006-01-23 16:09:51 -08003178 if (likely((status & (L2_FHDR_ERRORS_TCP_XSUM |
3179 L2_FHDR_ERRORS_UDP_XSUM)) == 0))
Michael Chanb6016b72005-05-26 13:03:09 -07003180 skb->ip_summed = CHECKSUM_UNNECESSARY;
3181 }
3182
David S. Miller0c8dfc82009-01-27 16:22:32 -08003183 skb_record_rx_queue(skb, bnapi - &bp->bnx2_napi[0]);
3184
Michael Chanb6016b72005-05-26 13:03:09 -07003185#ifdef BCM_VLAN
Michael Chanf22828e2008-08-14 15:30:14 -07003186 if (hw_vlan)
3187 vlan_hwaccel_receive_skb(skb, bp->vlgrp, vtag);
Michael Chanb6016b72005-05-26 13:03:09 -07003188 else
3189#endif
3190 netif_receive_skb(skb);
3191
Michael Chanb6016b72005-05-26 13:03:09 -07003192 rx_pkt++;
3193
3194next_rx:
Michael Chanb6016b72005-05-26 13:03:09 -07003195 sw_cons = NEXT_RX_BD(sw_cons);
3196 sw_prod = NEXT_RX_BD(sw_prod);
3197
3198 if ((rx_pkt == budget))
3199 break;
Michael Chanf4e418f2005-11-04 08:53:48 -08003200
3201 /* Refresh hw_cons to see if there is new work */
3202 if (sw_cons == hw_cons) {
Michael Chan35efa7c2007-12-20 19:56:37 -08003203 hw_cons = bnx2_get_hw_rx_cons(bnapi);
Michael Chanf4e418f2005-11-04 08:53:48 -08003204 rmb();
3205 }
Michael Chanb6016b72005-05-26 13:03:09 -07003206 }
Michael Chanbb4f98a2008-06-19 16:38:19 -07003207 rxr->rx_cons = sw_cons;
3208 rxr->rx_prod = sw_prod;
Michael Chanb6016b72005-05-26 13:03:09 -07003209
Michael Chan1db82f22007-12-12 11:19:35 -08003210 if (pg_ring_used)
Michael Chanbb4f98a2008-06-19 16:38:19 -07003211 REG_WR16(bp, rxr->rx_pg_bidx_addr, rxr->rx_pg_prod);
Michael Chan1db82f22007-12-12 11:19:35 -08003212
Michael Chanbb4f98a2008-06-19 16:38:19 -07003213 REG_WR16(bp, rxr->rx_bidx_addr, sw_prod);
Michael Chanb6016b72005-05-26 13:03:09 -07003214
Michael Chanbb4f98a2008-06-19 16:38:19 -07003215 REG_WR(bp, rxr->rx_bseq_addr, rxr->rx_prod_bseq);
Michael Chanb6016b72005-05-26 13:03:09 -07003216
3217 mmiowb();
3218
3219 return rx_pkt;
3220
3221}
3222
3223/* MSI ISR - The only difference between this and the INTx ISR
3224 * is that the MSI interrupt is always serviced.
3225 */
3226static irqreturn_t
David Howells7d12e782006-10-05 14:55:46 +01003227bnx2_msi(int irq, void *dev_instance)
Michael Chanb6016b72005-05-26 13:03:09 -07003228{
Michael Chanf0ea2e62008-06-19 16:41:57 -07003229 struct bnx2_napi *bnapi = dev_instance;
3230 struct bnx2 *bp = bnapi->bp;
Michael Chanb6016b72005-05-26 13:03:09 -07003231
Michael Chan43e80b82008-06-19 16:41:08 -07003232 prefetch(bnapi->status_blk.msi);
Michael Chanb6016b72005-05-26 13:03:09 -07003233 REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
3234 BNX2_PCICFG_INT_ACK_CMD_USE_INT_HC_PARAM |
3235 BNX2_PCICFG_INT_ACK_CMD_MASK_INT);
3236
3237 /* Return here if interrupt is disabled. */
Michael Chan73eef4c2005-08-25 15:39:15 -07003238 if (unlikely(atomic_read(&bp->intr_sem) != 0))
3239 return IRQ_HANDLED;
Michael Chanb6016b72005-05-26 13:03:09 -07003240
Ben Hutchings288379f2009-01-19 16:43:59 -08003241 napi_schedule(&bnapi->napi);
Michael Chanb6016b72005-05-26 13:03:09 -07003242
Michael Chan73eef4c2005-08-25 15:39:15 -07003243 return IRQ_HANDLED;
Michael Chanb6016b72005-05-26 13:03:09 -07003244}
3245
3246static irqreturn_t
Michael Chan8e6a72c2007-05-03 13:24:48 -07003247bnx2_msi_1shot(int irq, void *dev_instance)
3248{
Michael Chanf0ea2e62008-06-19 16:41:57 -07003249 struct bnx2_napi *bnapi = dev_instance;
3250 struct bnx2 *bp = bnapi->bp;
Michael Chan8e6a72c2007-05-03 13:24:48 -07003251
Michael Chan43e80b82008-06-19 16:41:08 -07003252 prefetch(bnapi->status_blk.msi);
Michael Chan8e6a72c2007-05-03 13:24:48 -07003253
3254 /* Return here if interrupt is disabled. */
3255 if (unlikely(atomic_read(&bp->intr_sem) != 0))
3256 return IRQ_HANDLED;
3257
Ben Hutchings288379f2009-01-19 16:43:59 -08003258 napi_schedule(&bnapi->napi);
Michael Chan8e6a72c2007-05-03 13:24:48 -07003259
3260 return IRQ_HANDLED;
3261}
3262
3263static irqreturn_t
David Howells7d12e782006-10-05 14:55:46 +01003264bnx2_interrupt(int irq, void *dev_instance)
Michael Chanb6016b72005-05-26 13:03:09 -07003265{
Michael Chanf0ea2e62008-06-19 16:41:57 -07003266 struct bnx2_napi *bnapi = dev_instance;
3267 struct bnx2 *bp = bnapi->bp;
Michael Chan43e80b82008-06-19 16:41:08 -07003268 struct status_block *sblk = bnapi->status_blk.msi;
Michael Chanb6016b72005-05-26 13:03:09 -07003269
3270 /* When using INTx, it is possible for the interrupt to arrive
3271 * at the CPU before the status block posted prior to the
3272 * interrupt. Reading a register will flush the status block.
3273 * When using MSI, the MSI message will always complete after
3274 * the status block write.
3275 */
Michael Chan35efa7c2007-12-20 19:56:37 -08003276 if ((sblk->status_idx == bnapi->last_status_idx) &&
Michael Chanb6016b72005-05-26 13:03:09 -07003277 (REG_RD(bp, BNX2_PCICFG_MISC_STATUS) &
3278 BNX2_PCICFG_MISC_STATUS_INTA_VALUE))
Michael Chan73eef4c2005-08-25 15:39:15 -07003279 return IRQ_NONE;
Michael Chanb6016b72005-05-26 13:03:09 -07003280
3281 REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
3282 BNX2_PCICFG_INT_ACK_CMD_USE_INT_HC_PARAM |
3283 BNX2_PCICFG_INT_ACK_CMD_MASK_INT);
3284
Michael Chanb8a7ce72007-07-07 22:51:03 -07003285 /* Read back to deassert IRQ immediately to avoid too many
3286 * spurious interrupts.
3287 */
3288 REG_RD(bp, BNX2_PCICFG_INT_ACK_CMD);
3289
Michael Chanb6016b72005-05-26 13:03:09 -07003290 /* Return here if interrupt is shared and is disabled. */
Michael Chan73eef4c2005-08-25 15:39:15 -07003291 if (unlikely(atomic_read(&bp->intr_sem) != 0))
3292 return IRQ_HANDLED;
Michael Chanb6016b72005-05-26 13:03:09 -07003293
Ben Hutchings288379f2009-01-19 16:43:59 -08003294 if (napi_schedule_prep(&bnapi->napi)) {
Michael Chan35efa7c2007-12-20 19:56:37 -08003295 bnapi->last_status_idx = sblk->status_idx;
Ben Hutchings288379f2009-01-19 16:43:59 -08003296 __napi_schedule(&bnapi->napi);
Michael Chanb8a7ce72007-07-07 22:51:03 -07003297 }
Michael Chanb6016b72005-05-26 13:03:09 -07003298
Michael Chan73eef4c2005-08-25 15:39:15 -07003299 return IRQ_HANDLED;
Michael Chanb6016b72005-05-26 13:03:09 -07003300}
3301
Michael Chan43e80b82008-06-19 16:41:08 -07003302static inline int
3303bnx2_has_fast_work(struct bnx2_napi *bnapi)
3304{
3305 struct bnx2_tx_ring_info *txr = &bnapi->tx_ring;
3306 struct bnx2_rx_ring_info *rxr = &bnapi->rx_ring;
3307
3308 if ((bnx2_get_hw_rx_cons(bnapi) != rxr->rx_cons) ||
3309 (bnx2_get_hw_tx_cons(bnapi) != txr->hw_tx_cons))
3310 return 1;
3311 return 0;
3312}
3313
Michael Chan0d8a6572007-07-07 22:49:43 -07003314#define STATUS_ATTN_EVENTS (STATUS_ATTN_BITS_LINK_STATE | \
3315 STATUS_ATTN_BITS_TIMER_ABORT)
Michael Chanda3e4fb2007-05-03 13:24:23 -07003316
Michael Chanf4e418f2005-11-04 08:53:48 -08003317static inline int
Michael Chan35efa7c2007-12-20 19:56:37 -08003318bnx2_has_work(struct bnx2_napi *bnapi)
Michael Chanf4e418f2005-11-04 08:53:48 -08003319{
Michael Chan43e80b82008-06-19 16:41:08 -07003320 struct status_block *sblk = bnapi->status_blk.msi;
Michael Chanf4e418f2005-11-04 08:53:48 -08003321
Michael Chan43e80b82008-06-19 16:41:08 -07003322 if (bnx2_has_fast_work(bnapi))
Michael Chanf4e418f2005-11-04 08:53:48 -08003323 return 1;
3324
Michael Chan4edd4732009-06-08 18:14:42 -07003325#ifdef BCM_CNIC
3326 if (bnapi->cnic_present && (bnapi->cnic_tag != sblk->status_idx))
3327 return 1;
3328#endif
3329
Michael Chanda3e4fb2007-05-03 13:24:23 -07003330 if ((sblk->status_attn_bits & STATUS_ATTN_EVENTS) !=
3331 (sblk->status_attn_bits_ack & STATUS_ATTN_EVENTS))
Michael Chanf4e418f2005-11-04 08:53:48 -08003332 return 1;
3333
3334 return 0;
3335}
3336
Michael Chanefba0182008-12-03 00:36:15 -08003337static void
3338bnx2_chk_missed_msi(struct bnx2 *bp)
3339{
3340 struct bnx2_napi *bnapi = &bp->bnx2_napi[0];
3341 u32 msi_ctrl;
3342
3343 if (bnx2_has_work(bnapi)) {
3344 msi_ctrl = REG_RD(bp, BNX2_PCICFG_MSI_CONTROL);
3345 if (!(msi_ctrl & BNX2_PCICFG_MSI_CONTROL_ENABLE))
3346 return;
3347
3348 if (bnapi->last_status_idx == bp->idle_chk_status_idx) {
3349 REG_WR(bp, BNX2_PCICFG_MSI_CONTROL, msi_ctrl &
3350 ~BNX2_PCICFG_MSI_CONTROL_ENABLE);
3351 REG_WR(bp, BNX2_PCICFG_MSI_CONTROL, msi_ctrl);
3352 bnx2_msi(bp->irq_tbl[0].vector, bnapi);
3353 }
3354 }
3355
3356 bp->idle_chk_status_idx = bnapi->last_status_idx;
3357}
3358
Michael Chan4edd4732009-06-08 18:14:42 -07003359#ifdef BCM_CNIC
3360static void bnx2_poll_cnic(struct bnx2 *bp, struct bnx2_napi *bnapi)
3361{
3362 struct cnic_ops *c_ops;
3363
3364 if (!bnapi->cnic_present)
3365 return;
3366
3367 rcu_read_lock();
3368 c_ops = rcu_dereference(bp->cnic_ops);
3369 if (c_ops)
3370 bnapi->cnic_tag = c_ops->cnic_handler(bp->cnic_data,
3371 bnapi->status_blk.msi);
3372 rcu_read_unlock();
3373}
3374#endif
3375
Michael Chan43e80b82008-06-19 16:41:08 -07003376static void bnx2_poll_link(struct bnx2 *bp, struct bnx2_napi *bnapi)
Michael Chanb6016b72005-05-26 13:03:09 -07003377{
Michael Chan43e80b82008-06-19 16:41:08 -07003378 struct status_block *sblk = bnapi->status_blk.msi;
Michael Chanda3e4fb2007-05-03 13:24:23 -07003379 u32 status_attn_bits = sblk->status_attn_bits;
3380 u32 status_attn_bits_ack = sblk->status_attn_bits_ack;
Michael Chanb6016b72005-05-26 13:03:09 -07003381
Michael Chanda3e4fb2007-05-03 13:24:23 -07003382 if ((status_attn_bits & STATUS_ATTN_EVENTS) !=
3383 (status_attn_bits_ack & STATUS_ATTN_EVENTS)) {
Michael Chanb6016b72005-05-26 13:03:09 -07003384
Michael Chan35efa7c2007-12-20 19:56:37 -08003385 bnx2_phy_int(bp, bnapi);
Michael Chanbf5295b2006-03-23 01:11:56 -08003386
3387 /* This is needed to take care of transient status
3388 * during link changes.
3389 */
3390 REG_WR(bp, BNX2_HC_COMMAND,
3391 bp->hc_cmd | BNX2_HC_COMMAND_COAL_NOW_WO_INT);
3392 REG_RD(bp, BNX2_HC_COMMAND);
Michael Chanb6016b72005-05-26 13:03:09 -07003393 }
Michael Chan43e80b82008-06-19 16:41:08 -07003394}
3395
3396static int bnx2_poll_work(struct bnx2 *bp, struct bnx2_napi *bnapi,
3397 int work_done, int budget)
3398{
3399 struct bnx2_tx_ring_info *txr = &bnapi->tx_ring;
3400 struct bnx2_rx_ring_info *rxr = &bnapi->rx_ring;
Michael Chanb6016b72005-05-26 13:03:09 -07003401
Michael Chan35e90102008-06-19 16:37:42 -07003402 if (bnx2_get_hw_tx_cons(bnapi) != txr->hw_tx_cons)
Michael Chan57851d82007-12-20 20:01:44 -08003403 bnx2_tx_int(bp, bnapi, 0);
Michael Chanb6016b72005-05-26 13:03:09 -07003404
Michael Chanbb4f98a2008-06-19 16:38:19 -07003405 if (bnx2_get_hw_rx_cons(bnapi) != rxr->rx_cons)
Michael Chan35efa7c2007-12-20 19:56:37 -08003406 work_done += bnx2_rx_int(bp, bnapi, budget - work_done);
Jeff Garzik6aa20a22006-09-13 13:24:59 -04003407
David S. Miller6f535762007-10-11 18:08:29 -07003408 return work_done;
3409}
Michael Chanf4e418f2005-11-04 08:53:48 -08003410
Michael Chanf0ea2e62008-06-19 16:41:57 -07003411static int bnx2_poll_msix(struct napi_struct *napi, int budget)
3412{
3413 struct bnx2_napi *bnapi = container_of(napi, struct bnx2_napi, napi);
3414 struct bnx2 *bp = bnapi->bp;
3415 int work_done = 0;
3416 struct status_block_msix *sblk = bnapi->status_blk.msix;
3417
3418 while (1) {
3419 work_done = bnx2_poll_work(bp, bnapi, work_done, budget);
3420 if (unlikely(work_done >= budget))
3421 break;
3422
3423 bnapi->last_status_idx = sblk->status_idx;
3424 /* status idx must be read before checking for more work. */
3425 rmb();
3426 if (likely(!bnx2_has_fast_work(bnapi))) {
3427
Ben Hutchings288379f2009-01-19 16:43:59 -08003428 napi_complete(napi);
Michael Chanf0ea2e62008-06-19 16:41:57 -07003429 REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD, bnapi->int_num |
3430 BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
3431 bnapi->last_status_idx);
3432 break;
3433 }
3434 }
3435 return work_done;
3436}
3437
David S. Miller6f535762007-10-11 18:08:29 -07003438static int bnx2_poll(struct napi_struct *napi, int budget)
3439{
Michael Chan35efa7c2007-12-20 19:56:37 -08003440 struct bnx2_napi *bnapi = container_of(napi, struct bnx2_napi, napi);
3441 struct bnx2 *bp = bnapi->bp;
David S. Miller6f535762007-10-11 18:08:29 -07003442 int work_done = 0;
Michael Chan43e80b82008-06-19 16:41:08 -07003443 struct status_block *sblk = bnapi->status_blk.msi;
David S. Miller6f535762007-10-11 18:08:29 -07003444
3445 while (1) {
Michael Chan43e80b82008-06-19 16:41:08 -07003446 bnx2_poll_link(bp, bnapi);
3447
Michael Chan35efa7c2007-12-20 19:56:37 -08003448 work_done = bnx2_poll_work(bp, bnapi, work_done, budget);
David S. Miller6f535762007-10-11 18:08:29 -07003449
Michael Chan4edd4732009-06-08 18:14:42 -07003450#ifdef BCM_CNIC
3451 bnx2_poll_cnic(bp, bnapi);
3452#endif
3453
Michael Chan35efa7c2007-12-20 19:56:37 -08003454 /* bnapi->last_status_idx is used below to tell the hw how
Michael Chan6dee6422007-10-12 01:40:38 -07003455 * much work has been processed, so we must read it before
3456 * checking for more work.
3457 */
Michael Chan35efa7c2007-12-20 19:56:37 -08003458 bnapi->last_status_idx = sblk->status_idx;
Michael Chanefba0182008-12-03 00:36:15 -08003459
3460 if (unlikely(work_done >= budget))
3461 break;
3462
Michael Chan6dee6422007-10-12 01:40:38 -07003463 rmb();
Michael Chan35efa7c2007-12-20 19:56:37 -08003464 if (likely(!bnx2_has_work(bnapi))) {
Ben Hutchings288379f2009-01-19 16:43:59 -08003465 napi_complete(napi);
David S. Millerf86e82f2008-01-21 17:15:40 -08003466 if (likely(bp->flags & BNX2_FLAG_USING_MSI_OR_MSIX)) {
David S. Miller6f535762007-10-11 18:08:29 -07003467 REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
3468 BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
Michael Chan35efa7c2007-12-20 19:56:37 -08003469 bnapi->last_status_idx);
Michael Chan6dee6422007-10-12 01:40:38 -07003470 break;
David S. Miller6f535762007-10-11 18:08:29 -07003471 }
3472 REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
3473 BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
3474 BNX2_PCICFG_INT_ACK_CMD_MASK_INT |
Michael Chan35efa7c2007-12-20 19:56:37 -08003475 bnapi->last_status_idx);
David S. Miller6f535762007-10-11 18:08:29 -07003476
Michael Chan1269a8a2006-01-23 16:11:03 -08003477 REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
3478 BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
Michael Chan35efa7c2007-12-20 19:56:37 -08003479 bnapi->last_status_idx);
David S. Miller6f535762007-10-11 18:08:29 -07003480 break;
Michael Chan1269a8a2006-01-23 16:11:03 -08003481 }
Michael Chanb6016b72005-05-26 13:03:09 -07003482 }
3483
Stephen Hemmingerbea33482007-10-03 16:41:36 -07003484 return work_done;
Michael Chanb6016b72005-05-26 13:03:09 -07003485}
3486
Herbert Xu932ff272006-06-09 12:20:56 -07003487/* Called with rtnl_lock from vlan functions and also netif_tx_lock
Michael Chanb6016b72005-05-26 13:03:09 -07003488 * from set_multicast.
3489 */
3490static void
3491bnx2_set_rx_mode(struct net_device *dev)
3492{
Michael Chan972ec0d2006-01-23 16:12:43 -08003493 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07003494 u32 rx_mode, sort_mode;
Benjamin Li5fcaed02008-07-14 22:39:52 -07003495 struct dev_addr_list *uc_ptr;
Michael Chanb6016b72005-05-26 13:03:09 -07003496 int i;
Michael Chanb6016b72005-05-26 13:03:09 -07003497
Michael Chan9f52b562008-10-09 12:21:46 -07003498 if (!netif_running(dev))
3499 return;
3500
Michael Chanc770a652005-08-25 15:38:39 -07003501 spin_lock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07003502
3503 rx_mode = bp->rx_mode & ~(BNX2_EMAC_RX_MODE_PROMISCUOUS |
3504 BNX2_EMAC_RX_MODE_KEEP_VLAN_TAG);
3505 sort_mode = 1 | BNX2_RPM_SORT_USER0_BC_EN;
3506#ifdef BCM_VLAN
Michael Chan7c6337a2008-08-14 15:29:09 -07003507 if (!bp->vlgrp && (bp->flags & BNX2_FLAG_CAN_KEEP_VLAN))
Michael Chanb6016b72005-05-26 13:03:09 -07003508 rx_mode |= BNX2_EMAC_RX_MODE_KEEP_VLAN_TAG;
Michael Chanb6016b72005-05-26 13:03:09 -07003509#else
Michael Chan7c6337a2008-08-14 15:29:09 -07003510 if (bp->flags & BNX2_FLAG_CAN_KEEP_VLAN)
Michael Chane29054f2006-01-23 16:06:06 -08003511 rx_mode |= BNX2_EMAC_RX_MODE_KEEP_VLAN_TAG;
Michael Chanb6016b72005-05-26 13:03:09 -07003512#endif
3513 if (dev->flags & IFF_PROMISC) {
3514 /* Promiscuous mode. */
3515 rx_mode |= BNX2_EMAC_RX_MODE_PROMISCUOUS;
Michael Chan75108732006-11-19 14:06:40 -08003516 sort_mode |= BNX2_RPM_SORT_USER0_PROM_EN |
3517 BNX2_RPM_SORT_USER0_PROM_VLAN;
Michael Chanb6016b72005-05-26 13:03:09 -07003518 }
3519 else if (dev->flags & IFF_ALLMULTI) {
3520 for (i = 0; i < NUM_MC_HASH_REGISTERS; i++) {
3521 REG_WR(bp, BNX2_EMAC_MULTICAST_HASH0 + (i * 4),
3522 0xffffffff);
3523 }
3524 sort_mode |= BNX2_RPM_SORT_USER0_MC_EN;
3525 }
3526 else {
3527 /* Accept one or more multicast(s). */
3528 struct dev_mc_list *mclist;
3529 u32 mc_filter[NUM_MC_HASH_REGISTERS];
3530 u32 regidx;
3531 u32 bit;
3532 u32 crc;
3533
3534 memset(mc_filter, 0, 4 * NUM_MC_HASH_REGISTERS);
3535
3536 for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
3537 i++, mclist = mclist->next) {
3538
3539 crc = ether_crc_le(ETH_ALEN, mclist->dmi_addr);
3540 bit = crc & 0xff;
3541 regidx = (bit & 0xe0) >> 5;
3542 bit &= 0x1f;
3543 mc_filter[regidx] |= (1 << bit);
3544 }
3545
3546 for (i = 0; i < NUM_MC_HASH_REGISTERS; i++) {
3547 REG_WR(bp, BNX2_EMAC_MULTICAST_HASH0 + (i * 4),
3548 mc_filter[i]);
3549 }
3550
3551 sort_mode |= BNX2_RPM_SORT_USER0_MC_HSH_EN;
3552 }
3553
Benjamin Li5fcaed02008-07-14 22:39:52 -07003554 uc_ptr = NULL;
3555 if (dev->uc_count > BNX2_MAX_UNICAST_ADDRESSES) {
3556 rx_mode |= BNX2_EMAC_RX_MODE_PROMISCUOUS;
3557 sort_mode |= BNX2_RPM_SORT_USER0_PROM_EN |
3558 BNX2_RPM_SORT_USER0_PROM_VLAN;
3559 } else if (!(dev->flags & IFF_PROMISC)) {
3560 uc_ptr = dev->uc_list;
3561
3562 /* Add all entries into to the match filter list */
3563 for (i = 0; i < dev->uc_count; i++) {
3564 bnx2_set_mac_addr(bp, uc_ptr->da_addr,
3565 i + BNX2_START_UNICAST_ADDRESS_INDEX);
3566 sort_mode |= (1 <<
3567 (i + BNX2_START_UNICAST_ADDRESS_INDEX));
3568 uc_ptr = uc_ptr->next;
3569 }
3570
3571 }
3572
Michael Chanb6016b72005-05-26 13:03:09 -07003573 if (rx_mode != bp->rx_mode) {
3574 bp->rx_mode = rx_mode;
3575 REG_WR(bp, BNX2_EMAC_RX_MODE, rx_mode);
3576 }
3577
3578 REG_WR(bp, BNX2_RPM_SORT_USER0, 0x0);
3579 REG_WR(bp, BNX2_RPM_SORT_USER0, sort_mode);
3580 REG_WR(bp, BNX2_RPM_SORT_USER0, sort_mode | BNX2_RPM_SORT_USER0_ENA);
3581
Michael Chanc770a652005-08-25 15:38:39 -07003582 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07003583}
3584
Michael Chan57579f72009-04-04 16:51:14 -07003585static int __devinit
3586check_fw_section(const struct firmware *fw,
3587 const struct bnx2_fw_file_section *section,
3588 u32 alignment, bool non_empty)
Michael Chanb6016b72005-05-26 13:03:09 -07003589{
Michael Chan57579f72009-04-04 16:51:14 -07003590 u32 offset = be32_to_cpu(section->offset);
3591 u32 len = be32_to_cpu(section->len);
Michael Chanb6016b72005-05-26 13:03:09 -07003592
Michael Chan57579f72009-04-04 16:51:14 -07003593 if ((offset == 0 && len != 0) || offset >= fw->size || offset & 3)
3594 return -EINVAL;
3595 if ((non_empty && len == 0) || len > fw->size - offset ||
3596 len & (alignment - 1))
3597 return -EINVAL;
3598 return 0;
3599}
3600
3601static int __devinit
3602check_mips_fw_entry(const struct firmware *fw,
3603 const struct bnx2_mips_fw_file_entry *entry)
3604{
3605 if (check_fw_section(fw, &entry->text, 4, true) ||
3606 check_fw_section(fw, &entry->data, 4, false) ||
3607 check_fw_section(fw, &entry->rodata, 4, false))
3608 return -EINVAL;
3609 return 0;
3610}
3611
3612static int __devinit
3613bnx2_request_firmware(struct bnx2 *bp)
3614{
3615 const char *mips_fw_file, *rv2p_fw_file;
Bastian Blank5ee1c322009-04-08 15:50:07 -07003616 const struct bnx2_mips_fw_file *mips_fw;
3617 const struct bnx2_rv2p_fw_file *rv2p_fw;
Michael Chan57579f72009-04-04 16:51:14 -07003618 int rc;
3619
3620 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
3621 mips_fw_file = FW_MIPS_FILE_09;
3622 rv2p_fw_file = FW_RV2P_FILE_09;
3623 } else {
3624 mips_fw_file = FW_MIPS_FILE_06;
3625 rv2p_fw_file = FW_RV2P_FILE_06;
3626 }
3627
3628 rc = request_firmware(&bp->mips_firmware, mips_fw_file, &bp->pdev->dev);
3629 if (rc) {
3630 printk(KERN_ERR PFX "Can't load firmware file \"%s\"\n",
3631 mips_fw_file);
3632 return rc;
3633 }
3634
3635 rc = request_firmware(&bp->rv2p_firmware, rv2p_fw_file, &bp->pdev->dev);
3636 if (rc) {
3637 printk(KERN_ERR PFX "Can't load firmware file \"%s\"\n",
3638 rv2p_fw_file);
3639 return rc;
3640 }
Bastian Blank5ee1c322009-04-08 15:50:07 -07003641 mips_fw = (const struct bnx2_mips_fw_file *) bp->mips_firmware->data;
3642 rv2p_fw = (const struct bnx2_rv2p_fw_file *) bp->rv2p_firmware->data;
3643 if (bp->mips_firmware->size < sizeof(*mips_fw) ||
3644 check_mips_fw_entry(bp->mips_firmware, &mips_fw->com) ||
3645 check_mips_fw_entry(bp->mips_firmware, &mips_fw->cp) ||
3646 check_mips_fw_entry(bp->mips_firmware, &mips_fw->rxp) ||
3647 check_mips_fw_entry(bp->mips_firmware, &mips_fw->tpat) ||
3648 check_mips_fw_entry(bp->mips_firmware, &mips_fw->txp)) {
Michael Chan57579f72009-04-04 16:51:14 -07003649 printk(KERN_ERR PFX "Firmware file \"%s\" is invalid\n",
3650 mips_fw_file);
3651 return -EINVAL;
3652 }
Bastian Blank5ee1c322009-04-08 15:50:07 -07003653 if (bp->rv2p_firmware->size < sizeof(*rv2p_fw) ||
3654 check_fw_section(bp->rv2p_firmware, &rv2p_fw->proc1.rv2p, 8, true) ||
3655 check_fw_section(bp->rv2p_firmware, &rv2p_fw->proc2.rv2p, 8, true)) {
Michael Chan57579f72009-04-04 16:51:14 -07003656 printk(KERN_ERR PFX "Firmware file \"%s\" is invalid\n",
3657 rv2p_fw_file);
3658 return -EINVAL;
3659 }
3660
3661 return 0;
3662}
3663
3664static u32
3665rv2p_fw_fixup(u32 rv2p_proc, int idx, u32 loc, u32 rv2p_code)
3666{
3667 switch (idx) {
3668 case RV2P_P1_FIXUP_PAGE_SIZE_IDX:
3669 rv2p_code &= ~RV2P_BD_PAGE_SIZE_MSK;
3670 rv2p_code |= RV2P_BD_PAGE_SIZE;
3671 break;
3672 }
3673 return rv2p_code;
3674}
3675
3676static int
3677load_rv2p_fw(struct bnx2 *bp, u32 rv2p_proc,
3678 const struct bnx2_rv2p_fw_file_entry *fw_entry)
3679{
3680 u32 rv2p_code_len, file_offset;
3681 __be32 *rv2p_code;
3682 int i;
3683 u32 val, cmd, addr;
3684
3685 rv2p_code_len = be32_to_cpu(fw_entry->rv2p.len);
3686 file_offset = be32_to_cpu(fw_entry->rv2p.offset);
3687
3688 rv2p_code = (__be32 *)(bp->rv2p_firmware->data + file_offset);
3689
3690 if (rv2p_proc == RV2P_PROC1) {
3691 cmd = BNX2_RV2P_PROC1_ADDR_CMD_RDWR;
3692 addr = BNX2_RV2P_PROC1_ADDR_CMD;
3693 } else {
3694 cmd = BNX2_RV2P_PROC2_ADDR_CMD_RDWR;
3695 addr = BNX2_RV2P_PROC2_ADDR_CMD;
Michael Chand25be1d2008-05-02 16:57:59 -07003696 }
Michael Chanb6016b72005-05-26 13:03:09 -07003697
3698 for (i = 0; i < rv2p_code_len; i += 8) {
Michael Chan57579f72009-04-04 16:51:14 -07003699 REG_WR(bp, BNX2_RV2P_INSTR_HIGH, be32_to_cpu(*rv2p_code));
Michael Chanb6016b72005-05-26 13:03:09 -07003700 rv2p_code++;
Michael Chan57579f72009-04-04 16:51:14 -07003701 REG_WR(bp, BNX2_RV2P_INSTR_LOW, be32_to_cpu(*rv2p_code));
Michael Chanb6016b72005-05-26 13:03:09 -07003702 rv2p_code++;
3703
Michael Chan57579f72009-04-04 16:51:14 -07003704 val = (i / 8) | cmd;
3705 REG_WR(bp, addr, val);
3706 }
3707
3708 rv2p_code = (__be32 *)(bp->rv2p_firmware->data + file_offset);
3709 for (i = 0; i < 8; i++) {
3710 u32 loc, code;
3711
3712 loc = be32_to_cpu(fw_entry->fixup[i]);
3713 if (loc && ((loc * 4) < rv2p_code_len)) {
3714 code = be32_to_cpu(*(rv2p_code + loc - 1));
3715 REG_WR(bp, BNX2_RV2P_INSTR_HIGH, code);
3716 code = be32_to_cpu(*(rv2p_code + loc));
3717 code = rv2p_fw_fixup(rv2p_proc, i, loc, code);
3718 REG_WR(bp, BNX2_RV2P_INSTR_LOW, code);
3719
3720 val = (loc / 2) | cmd;
3721 REG_WR(bp, addr, val);
Michael Chanb6016b72005-05-26 13:03:09 -07003722 }
3723 }
3724
3725 /* Reset the processor, un-stall is done later. */
3726 if (rv2p_proc == RV2P_PROC1) {
3727 REG_WR(bp, BNX2_RV2P_COMMAND, BNX2_RV2P_COMMAND_PROC1_RESET);
3728 }
3729 else {
3730 REG_WR(bp, BNX2_RV2P_COMMAND, BNX2_RV2P_COMMAND_PROC2_RESET);
3731 }
Michael Chan57579f72009-04-04 16:51:14 -07003732
3733 return 0;
Michael Chanb6016b72005-05-26 13:03:09 -07003734}
3735
Michael Chanaf3ee512006-11-19 14:09:25 -08003736static int
Michael Chan57579f72009-04-04 16:51:14 -07003737load_cpu_fw(struct bnx2 *bp, const struct cpu_reg *cpu_reg,
3738 const struct bnx2_mips_fw_file_entry *fw_entry)
Michael Chanb6016b72005-05-26 13:03:09 -07003739{
Michael Chan57579f72009-04-04 16:51:14 -07003740 u32 addr, len, file_offset;
3741 __be32 *data;
Michael Chanb6016b72005-05-26 13:03:09 -07003742 u32 offset;
3743 u32 val;
3744
3745 /* Halt the CPU. */
Michael Chan2726d6e2008-01-29 21:35:05 -08003746 val = bnx2_reg_rd_ind(bp, cpu_reg->mode);
Michael Chanb6016b72005-05-26 13:03:09 -07003747 val |= cpu_reg->mode_value_halt;
Michael Chan2726d6e2008-01-29 21:35:05 -08003748 bnx2_reg_wr_ind(bp, cpu_reg->mode, val);
3749 bnx2_reg_wr_ind(bp, cpu_reg->state, cpu_reg->state_value_clear);
Michael Chanb6016b72005-05-26 13:03:09 -07003750
3751 /* Load the Text area. */
Michael Chan57579f72009-04-04 16:51:14 -07003752 addr = be32_to_cpu(fw_entry->text.addr);
3753 len = be32_to_cpu(fw_entry->text.len);
3754 file_offset = be32_to_cpu(fw_entry->text.offset);
3755 data = (__be32 *)(bp->mips_firmware->data + file_offset);
3756
3757 offset = cpu_reg->spad_base + (addr - cpu_reg->mips_view_base);
3758 if (len) {
Michael Chanb6016b72005-05-26 13:03:09 -07003759 int j;
3760
Michael Chan57579f72009-04-04 16:51:14 -07003761 for (j = 0; j < (len / 4); j++, offset += 4)
3762 bnx2_reg_wr_ind(bp, offset, be32_to_cpu(data[j]));
Michael Chanb6016b72005-05-26 13:03:09 -07003763 }
3764
3765 /* Load the Data area. */
Michael Chan57579f72009-04-04 16:51:14 -07003766 addr = be32_to_cpu(fw_entry->data.addr);
3767 len = be32_to_cpu(fw_entry->data.len);
3768 file_offset = be32_to_cpu(fw_entry->data.offset);
3769 data = (__be32 *)(bp->mips_firmware->data + file_offset);
3770
3771 offset = cpu_reg->spad_base + (addr - cpu_reg->mips_view_base);
3772 if (len) {
Michael Chanb6016b72005-05-26 13:03:09 -07003773 int j;
3774
Michael Chan57579f72009-04-04 16:51:14 -07003775 for (j = 0; j < (len / 4); j++, offset += 4)
3776 bnx2_reg_wr_ind(bp, offset, be32_to_cpu(data[j]));
Michael Chanb6016b72005-05-26 13:03:09 -07003777 }
3778
3779 /* Load the Read-Only area. */
Michael Chan57579f72009-04-04 16:51:14 -07003780 addr = be32_to_cpu(fw_entry->rodata.addr);
3781 len = be32_to_cpu(fw_entry->rodata.len);
3782 file_offset = be32_to_cpu(fw_entry->rodata.offset);
3783 data = (__be32 *)(bp->mips_firmware->data + file_offset);
3784
3785 offset = cpu_reg->spad_base + (addr - cpu_reg->mips_view_base);
3786 if (len) {
Michael Chanb6016b72005-05-26 13:03:09 -07003787 int j;
3788
Michael Chan57579f72009-04-04 16:51:14 -07003789 for (j = 0; j < (len / 4); j++, offset += 4)
3790 bnx2_reg_wr_ind(bp, offset, be32_to_cpu(data[j]));
Michael Chanb6016b72005-05-26 13:03:09 -07003791 }
3792
3793 /* Clear the pre-fetch instruction. */
Michael Chan2726d6e2008-01-29 21:35:05 -08003794 bnx2_reg_wr_ind(bp, cpu_reg->inst, 0);
Michael Chan57579f72009-04-04 16:51:14 -07003795
3796 val = be32_to_cpu(fw_entry->start_addr);
3797 bnx2_reg_wr_ind(bp, cpu_reg->pc, val);
Michael Chanb6016b72005-05-26 13:03:09 -07003798
3799 /* Start the CPU. */
Michael Chan2726d6e2008-01-29 21:35:05 -08003800 val = bnx2_reg_rd_ind(bp, cpu_reg->mode);
Michael Chanb6016b72005-05-26 13:03:09 -07003801 val &= ~cpu_reg->mode_value_halt;
Michael Chan2726d6e2008-01-29 21:35:05 -08003802 bnx2_reg_wr_ind(bp, cpu_reg->state, cpu_reg->state_value_clear);
3803 bnx2_reg_wr_ind(bp, cpu_reg->mode, val);
Michael Chanaf3ee512006-11-19 14:09:25 -08003804
3805 return 0;
Michael Chanb6016b72005-05-26 13:03:09 -07003806}
3807
Michael Chanfba9fe92006-06-12 22:21:25 -07003808static int
Michael Chanb6016b72005-05-26 13:03:09 -07003809bnx2_init_cpus(struct bnx2 *bp)
3810{
Michael Chan57579f72009-04-04 16:51:14 -07003811 const struct bnx2_mips_fw_file *mips_fw =
3812 (const struct bnx2_mips_fw_file *) bp->mips_firmware->data;
3813 const struct bnx2_rv2p_fw_file *rv2p_fw =
3814 (const struct bnx2_rv2p_fw_file *) bp->rv2p_firmware->data;
3815 int rc;
Michael Chanb6016b72005-05-26 13:03:09 -07003816
3817 /* Initialize the RV2P processor. */
Michael Chan57579f72009-04-04 16:51:14 -07003818 load_rv2p_fw(bp, RV2P_PROC1, &rv2p_fw->proc1);
3819 load_rv2p_fw(bp, RV2P_PROC2, &rv2p_fw->proc2);
Michael Chanb6016b72005-05-26 13:03:09 -07003820
3821 /* Initialize the RX Processor. */
Michael Chan57579f72009-04-04 16:51:14 -07003822 rc = load_cpu_fw(bp, &cpu_reg_rxp, &mips_fw->rxp);
Michael Chanfba9fe92006-06-12 22:21:25 -07003823 if (rc)
3824 goto init_cpu_err;
3825
Michael Chanb6016b72005-05-26 13:03:09 -07003826 /* Initialize the TX Processor. */
Michael Chan57579f72009-04-04 16:51:14 -07003827 rc = load_cpu_fw(bp, &cpu_reg_txp, &mips_fw->txp);
Michael Chanfba9fe92006-06-12 22:21:25 -07003828 if (rc)
3829 goto init_cpu_err;
3830
Michael Chanb6016b72005-05-26 13:03:09 -07003831 /* Initialize the TX Patch-up Processor. */
Michael Chan57579f72009-04-04 16:51:14 -07003832 rc = load_cpu_fw(bp, &cpu_reg_tpat, &mips_fw->tpat);
Michael Chanfba9fe92006-06-12 22:21:25 -07003833 if (rc)
3834 goto init_cpu_err;
3835
Michael Chanb6016b72005-05-26 13:03:09 -07003836 /* Initialize the Completion Processor. */
Michael Chan57579f72009-04-04 16:51:14 -07003837 rc = load_cpu_fw(bp, &cpu_reg_com, &mips_fw->com);
Michael Chanfba9fe92006-06-12 22:21:25 -07003838 if (rc)
3839 goto init_cpu_err;
3840
Michael Chand43584c2006-11-19 14:14:35 -08003841 /* Initialize the Command Processor. */
Michael Chan57579f72009-04-04 16:51:14 -07003842 rc = load_cpu_fw(bp, &cpu_reg_cp, &mips_fw->cp);
Michael Chan110d0ef2007-12-12 11:18:34 -08003843
Michael Chanfba9fe92006-06-12 22:21:25 -07003844init_cpu_err:
Michael Chanfba9fe92006-06-12 22:21:25 -07003845 return rc;
Michael Chanb6016b72005-05-26 13:03:09 -07003846}
3847
3848static int
Pavel Machek829ca9a2005-09-03 15:56:56 -07003849bnx2_set_power_state(struct bnx2 *bp, pci_power_t state)
Michael Chanb6016b72005-05-26 13:03:09 -07003850{
3851 u16 pmcsr;
3852
3853 pci_read_config_word(bp->pdev, bp->pm_cap + PCI_PM_CTRL, &pmcsr);
3854
3855 switch (state) {
Pavel Machek829ca9a2005-09-03 15:56:56 -07003856 case PCI_D0: {
Michael Chanb6016b72005-05-26 13:03:09 -07003857 u32 val;
3858
3859 pci_write_config_word(bp->pdev, bp->pm_cap + PCI_PM_CTRL,
3860 (pmcsr & ~PCI_PM_CTRL_STATE_MASK) |
3861 PCI_PM_CTRL_PME_STATUS);
3862
3863 if (pmcsr & PCI_PM_CTRL_STATE_MASK)
3864 /* delay required during transition out of D3hot */
3865 msleep(20);
3866
3867 val = REG_RD(bp, BNX2_EMAC_MODE);
3868 val |= BNX2_EMAC_MODE_MPKT_RCVD | BNX2_EMAC_MODE_ACPI_RCVD;
3869 val &= ~BNX2_EMAC_MODE_MPKT;
3870 REG_WR(bp, BNX2_EMAC_MODE, val);
3871
3872 val = REG_RD(bp, BNX2_RPM_CONFIG);
3873 val &= ~BNX2_RPM_CONFIG_ACPI_ENA;
3874 REG_WR(bp, BNX2_RPM_CONFIG, val);
3875 break;
3876 }
Pavel Machek829ca9a2005-09-03 15:56:56 -07003877 case PCI_D3hot: {
Michael Chanb6016b72005-05-26 13:03:09 -07003878 int i;
3879 u32 val, wol_msg;
3880
3881 if (bp->wol) {
3882 u32 advertising;
3883 u8 autoneg;
3884
3885 autoneg = bp->autoneg;
3886 advertising = bp->advertising;
3887
Michael Chan239cd342007-10-17 19:26:15 -07003888 if (bp->phy_port == PORT_TP) {
3889 bp->autoneg = AUTONEG_SPEED;
3890 bp->advertising = ADVERTISED_10baseT_Half |
3891 ADVERTISED_10baseT_Full |
3892 ADVERTISED_100baseT_Half |
3893 ADVERTISED_100baseT_Full |
3894 ADVERTISED_Autoneg;
3895 }
Michael Chanb6016b72005-05-26 13:03:09 -07003896
Michael Chan239cd342007-10-17 19:26:15 -07003897 spin_lock_bh(&bp->phy_lock);
3898 bnx2_setup_phy(bp, bp->phy_port);
3899 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07003900
3901 bp->autoneg = autoneg;
3902 bp->advertising = advertising;
3903
Benjamin Li5fcaed02008-07-14 22:39:52 -07003904 bnx2_set_mac_addr(bp, bp->dev->dev_addr, 0);
Michael Chanb6016b72005-05-26 13:03:09 -07003905
3906 val = REG_RD(bp, BNX2_EMAC_MODE);
3907
3908 /* Enable port mode. */
3909 val &= ~BNX2_EMAC_MODE_PORT;
Michael Chan239cd342007-10-17 19:26:15 -07003910 val |= BNX2_EMAC_MODE_MPKT_RCVD |
Michael Chanb6016b72005-05-26 13:03:09 -07003911 BNX2_EMAC_MODE_ACPI_RCVD |
Michael Chanb6016b72005-05-26 13:03:09 -07003912 BNX2_EMAC_MODE_MPKT;
Michael Chan239cd342007-10-17 19:26:15 -07003913 if (bp->phy_port == PORT_TP)
3914 val |= BNX2_EMAC_MODE_PORT_MII;
3915 else {
3916 val |= BNX2_EMAC_MODE_PORT_GMII;
3917 if (bp->line_speed == SPEED_2500)
3918 val |= BNX2_EMAC_MODE_25G_MODE;
3919 }
Michael Chanb6016b72005-05-26 13:03:09 -07003920
3921 REG_WR(bp, BNX2_EMAC_MODE, val);
3922
3923 /* receive all multicast */
3924 for (i = 0; i < NUM_MC_HASH_REGISTERS; i++) {
3925 REG_WR(bp, BNX2_EMAC_MULTICAST_HASH0 + (i * 4),
3926 0xffffffff);
3927 }
3928 REG_WR(bp, BNX2_EMAC_RX_MODE,
3929 BNX2_EMAC_RX_MODE_SORT_MODE);
3930
3931 val = 1 | BNX2_RPM_SORT_USER0_BC_EN |
3932 BNX2_RPM_SORT_USER0_MC_EN;
3933 REG_WR(bp, BNX2_RPM_SORT_USER0, 0x0);
3934 REG_WR(bp, BNX2_RPM_SORT_USER0, val);
3935 REG_WR(bp, BNX2_RPM_SORT_USER0, val |
3936 BNX2_RPM_SORT_USER0_ENA);
3937
3938 /* Need to enable EMAC and RPM for WOL. */
3939 REG_WR(bp, BNX2_MISC_ENABLE_SET_BITS,
3940 BNX2_MISC_ENABLE_SET_BITS_RX_PARSER_MAC_ENABLE |
3941 BNX2_MISC_ENABLE_SET_BITS_TX_HEADER_Q_ENABLE |
3942 BNX2_MISC_ENABLE_SET_BITS_EMAC_ENABLE);
3943
3944 val = REG_RD(bp, BNX2_RPM_CONFIG);
3945 val &= ~BNX2_RPM_CONFIG_ACPI_ENA;
3946 REG_WR(bp, BNX2_RPM_CONFIG, val);
3947
3948 wol_msg = BNX2_DRV_MSG_CODE_SUSPEND_WOL;
3949 }
3950 else {
3951 wol_msg = BNX2_DRV_MSG_CODE_SUSPEND_NO_WOL;
3952 }
3953
David S. Millerf86e82f2008-01-21 17:15:40 -08003954 if (!(bp->flags & BNX2_FLAG_NO_WOL))
Michael Chana2f13892008-07-14 22:38:23 -07003955 bnx2_fw_sync(bp, BNX2_DRV_MSG_DATA_WAIT3 | wol_msg,
3956 1, 0);
Michael Chanb6016b72005-05-26 13:03:09 -07003957
3958 pmcsr &= ~PCI_PM_CTRL_STATE_MASK;
3959 if ((CHIP_ID(bp) == CHIP_ID_5706_A0) ||
3960 (CHIP_ID(bp) == CHIP_ID_5706_A1)) {
3961
3962 if (bp->wol)
3963 pmcsr |= 3;
3964 }
3965 else {
3966 pmcsr |= 3;
3967 }
3968 if (bp->wol) {
3969 pmcsr |= PCI_PM_CTRL_PME_ENABLE;
3970 }
3971 pci_write_config_word(bp->pdev, bp->pm_cap + PCI_PM_CTRL,
3972 pmcsr);
3973
3974 /* No more memory access after this point until
3975 * device is brought back to D0.
3976 */
3977 udelay(50);
3978 break;
3979 }
3980 default:
3981 return -EINVAL;
3982 }
3983 return 0;
3984}
3985
3986static int
3987bnx2_acquire_nvram_lock(struct bnx2 *bp)
3988{
3989 u32 val;
3990 int j;
3991
3992 /* Request access to the flash interface. */
3993 REG_WR(bp, BNX2_NVM_SW_ARB, BNX2_NVM_SW_ARB_ARB_REQ_SET2);
3994 for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) {
3995 val = REG_RD(bp, BNX2_NVM_SW_ARB);
3996 if (val & BNX2_NVM_SW_ARB_ARB_ARB2)
3997 break;
3998
3999 udelay(5);
4000 }
4001
4002 if (j >= NVRAM_TIMEOUT_COUNT)
4003 return -EBUSY;
4004
4005 return 0;
4006}
4007
4008static int
4009bnx2_release_nvram_lock(struct bnx2 *bp)
4010{
4011 int j;
4012 u32 val;
4013
4014 /* Relinquish nvram interface. */
4015 REG_WR(bp, BNX2_NVM_SW_ARB, BNX2_NVM_SW_ARB_ARB_REQ_CLR2);
4016
4017 for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) {
4018 val = REG_RD(bp, BNX2_NVM_SW_ARB);
4019 if (!(val & BNX2_NVM_SW_ARB_ARB_ARB2))
4020 break;
4021
4022 udelay(5);
4023 }
4024
4025 if (j >= NVRAM_TIMEOUT_COUNT)
4026 return -EBUSY;
4027
4028 return 0;
4029}
4030
4031
4032static int
4033bnx2_enable_nvram_write(struct bnx2 *bp)
4034{
4035 u32 val;
4036
4037 val = REG_RD(bp, BNX2_MISC_CFG);
4038 REG_WR(bp, BNX2_MISC_CFG, val | BNX2_MISC_CFG_NVM_WR_EN_PCI);
4039
Michael Chane30372c2007-07-16 18:26:23 -07004040 if (bp->flash_info->flags & BNX2_NV_WREN) {
Michael Chanb6016b72005-05-26 13:03:09 -07004041 int j;
4042
4043 REG_WR(bp, BNX2_NVM_COMMAND, BNX2_NVM_COMMAND_DONE);
4044 REG_WR(bp, BNX2_NVM_COMMAND,
4045 BNX2_NVM_COMMAND_WREN | BNX2_NVM_COMMAND_DOIT);
4046
4047 for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) {
4048 udelay(5);
4049
4050 val = REG_RD(bp, BNX2_NVM_COMMAND);
4051 if (val & BNX2_NVM_COMMAND_DONE)
4052 break;
4053 }
4054
4055 if (j >= NVRAM_TIMEOUT_COUNT)
4056 return -EBUSY;
4057 }
4058 return 0;
4059}
4060
4061static void
4062bnx2_disable_nvram_write(struct bnx2 *bp)
4063{
4064 u32 val;
4065
4066 val = REG_RD(bp, BNX2_MISC_CFG);
4067 REG_WR(bp, BNX2_MISC_CFG, val & ~BNX2_MISC_CFG_NVM_WR_EN);
4068}
4069
4070
4071static void
4072bnx2_enable_nvram_access(struct bnx2 *bp)
4073{
4074 u32 val;
4075
4076 val = REG_RD(bp, BNX2_NVM_ACCESS_ENABLE);
4077 /* Enable both bits, even on read. */
Jeff Garzik6aa20a22006-09-13 13:24:59 -04004078 REG_WR(bp, BNX2_NVM_ACCESS_ENABLE,
Michael Chanb6016b72005-05-26 13:03:09 -07004079 val | BNX2_NVM_ACCESS_ENABLE_EN | BNX2_NVM_ACCESS_ENABLE_WR_EN);
4080}
4081
4082static void
4083bnx2_disable_nvram_access(struct bnx2 *bp)
4084{
4085 u32 val;
4086
4087 val = REG_RD(bp, BNX2_NVM_ACCESS_ENABLE);
4088 /* Disable both bits, even after read. */
Jeff Garzik6aa20a22006-09-13 13:24:59 -04004089 REG_WR(bp, BNX2_NVM_ACCESS_ENABLE,
Michael Chanb6016b72005-05-26 13:03:09 -07004090 val & ~(BNX2_NVM_ACCESS_ENABLE_EN |
4091 BNX2_NVM_ACCESS_ENABLE_WR_EN));
4092}
4093
4094static int
4095bnx2_nvram_erase_page(struct bnx2 *bp, u32 offset)
4096{
4097 u32 cmd;
4098 int j;
4099
Michael Chane30372c2007-07-16 18:26:23 -07004100 if (bp->flash_info->flags & BNX2_NV_BUFFERED)
Michael Chanb6016b72005-05-26 13:03:09 -07004101 /* Buffered flash, no erase needed */
4102 return 0;
4103
4104 /* Build an erase command */
4105 cmd = BNX2_NVM_COMMAND_ERASE | BNX2_NVM_COMMAND_WR |
4106 BNX2_NVM_COMMAND_DOIT;
4107
4108 /* Need to clear DONE bit separately. */
4109 REG_WR(bp, BNX2_NVM_COMMAND, BNX2_NVM_COMMAND_DONE);
4110
4111 /* Address of the NVRAM to read from. */
4112 REG_WR(bp, BNX2_NVM_ADDR, offset & BNX2_NVM_ADDR_NVM_ADDR_VALUE);
4113
4114 /* Issue an erase command. */
4115 REG_WR(bp, BNX2_NVM_COMMAND, cmd);
4116
4117 /* Wait for completion. */
4118 for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) {
4119 u32 val;
4120
4121 udelay(5);
4122
4123 val = REG_RD(bp, BNX2_NVM_COMMAND);
4124 if (val & BNX2_NVM_COMMAND_DONE)
4125 break;
4126 }
4127
4128 if (j >= NVRAM_TIMEOUT_COUNT)
4129 return -EBUSY;
4130
4131 return 0;
4132}
4133
4134static int
4135bnx2_nvram_read_dword(struct bnx2 *bp, u32 offset, u8 *ret_val, u32 cmd_flags)
4136{
4137 u32 cmd;
4138 int j;
4139
4140 /* Build the command word. */
4141 cmd = BNX2_NVM_COMMAND_DOIT | cmd_flags;
4142
Michael Chane30372c2007-07-16 18:26:23 -07004143 /* Calculate an offset of a buffered flash, not needed for 5709. */
4144 if (bp->flash_info->flags & BNX2_NV_TRANSLATE) {
Michael Chanb6016b72005-05-26 13:03:09 -07004145 offset = ((offset / bp->flash_info->page_size) <<
4146 bp->flash_info->page_bits) +
4147 (offset % bp->flash_info->page_size);
4148 }
4149
4150 /* Need to clear DONE bit separately. */
4151 REG_WR(bp, BNX2_NVM_COMMAND, BNX2_NVM_COMMAND_DONE);
4152
4153 /* Address of the NVRAM to read from. */
4154 REG_WR(bp, BNX2_NVM_ADDR, offset & BNX2_NVM_ADDR_NVM_ADDR_VALUE);
4155
4156 /* Issue a read command. */
4157 REG_WR(bp, BNX2_NVM_COMMAND, cmd);
4158
4159 /* Wait for completion. */
4160 for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) {
4161 u32 val;
4162
4163 udelay(5);
4164
4165 val = REG_RD(bp, BNX2_NVM_COMMAND);
4166 if (val & BNX2_NVM_COMMAND_DONE) {
Al Virob491edd2007-12-22 19:44:51 +00004167 __be32 v = cpu_to_be32(REG_RD(bp, BNX2_NVM_READ));
4168 memcpy(ret_val, &v, 4);
Michael Chanb6016b72005-05-26 13:03:09 -07004169 break;
4170 }
4171 }
4172 if (j >= NVRAM_TIMEOUT_COUNT)
4173 return -EBUSY;
4174
4175 return 0;
4176}
4177
4178
4179static int
4180bnx2_nvram_write_dword(struct bnx2 *bp, u32 offset, u8 *val, u32 cmd_flags)
4181{
Al Virob491edd2007-12-22 19:44:51 +00004182 u32 cmd;
4183 __be32 val32;
Michael Chanb6016b72005-05-26 13:03:09 -07004184 int j;
4185
4186 /* Build the command word. */
4187 cmd = BNX2_NVM_COMMAND_DOIT | BNX2_NVM_COMMAND_WR | cmd_flags;
4188
Michael Chane30372c2007-07-16 18:26:23 -07004189 /* Calculate an offset of a buffered flash, not needed for 5709. */
4190 if (bp->flash_info->flags & BNX2_NV_TRANSLATE) {
Michael Chanb6016b72005-05-26 13:03:09 -07004191 offset = ((offset / bp->flash_info->page_size) <<
4192 bp->flash_info->page_bits) +
4193 (offset % bp->flash_info->page_size);
4194 }
4195
4196 /* Need to clear DONE bit separately. */
4197 REG_WR(bp, BNX2_NVM_COMMAND, BNX2_NVM_COMMAND_DONE);
4198
4199 memcpy(&val32, val, 4);
Michael Chanb6016b72005-05-26 13:03:09 -07004200
4201 /* Write the data. */
Al Virob491edd2007-12-22 19:44:51 +00004202 REG_WR(bp, BNX2_NVM_WRITE, be32_to_cpu(val32));
Michael Chanb6016b72005-05-26 13:03:09 -07004203
4204 /* Address of the NVRAM to write to. */
4205 REG_WR(bp, BNX2_NVM_ADDR, offset & BNX2_NVM_ADDR_NVM_ADDR_VALUE);
4206
4207 /* Issue the write command. */
4208 REG_WR(bp, BNX2_NVM_COMMAND, cmd);
4209
4210 /* Wait for completion. */
4211 for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) {
4212 udelay(5);
4213
4214 if (REG_RD(bp, BNX2_NVM_COMMAND) & BNX2_NVM_COMMAND_DONE)
4215 break;
4216 }
4217 if (j >= NVRAM_TIMEOUT_COUNT)
4218 return -EBUSY;
4219
4220 return 0;
4221}
4222
4223static int
4224bnx2_init_nvram(struct bnx2 *bp)
4225{
4226 u32 val;
Michael Chane30372c2007-07-16 18:26:23 -07004227 int j, entry_count, rc = 0;
Michael Chanb6016b72005-05-26 13:03:09 -07004228 struct flash_spec *flash;
4229
Michael Chane30372c2007-07-16 18:26:23 -07004230 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
4231 bp->flash_info = &flash_5709;
4232 goto get_flash_size;
4233 }
4234
Michael Chanb6016b72005-05-26 13:03:09 -07004235 /* Determine the selected interface. */
4236 val = REG_RD(bp, BNX2_NVM_CFG1);
4237
Denis Chengff8ac602007-09-02 18:30:18 +08004238 entry_count = ARRAY_SIZE(flash_table);
Michael Chanb6016b72005-05-26 13:03:09 -07004239
Michael Chanb6016b72005-05-26 13:03:09 -07004240 if (val & 0x40000000) {
4241
4242 /* Flash interface has been reconfigured */
4243 for (j = 0, flash = &flash_table[0]; j < entry_count;
Michael Chan37137702005-11-04 08:49:17 -08004244 j++, flash++) {
4245 if ((val & FLASH_BACKUP_STRAP_MASK) ==
4246 (flash->config1 & FLASH_BACKUP_STRAP_MASK)) {
Michael Chanb6016b72005-05-26 13:03:09 -07004247 bp->flash_info = flash;
4248 break;
4249 }
4250 }
4251 }
4252 else {
Michael Chan37137702005-11-04 08:49:17 -08004253 u32 mask;
Michael Chanb6016b72005-05-26 13:03:09 -07004254 /* Not yet been reconfigured */
4255
Michael Chan37137702005-11-04 08:49:17 -08004256 if (val & (1 << 23))
4257 mask = FLASH_BACKUP_STRAP_MASK;
4258 else
4259 mask = FLASH_STRAP_MASK;
4260
Michael Chanb6016b72005-05-26 13:03:09 -07004261 for (j = 0, flash = &flash_table[0]; j < entry_count;
4262 j++, flash++) {
4263
Michael Chan37137702005-11-04 08:49:17 -08004264 if ((val & mask) == (flash->strapping & mask)) {
Michael Chanb6016b72005-05-26 13:03:09 -07004265 bp->flash_info = flash;
4266
4267 /* Request access to the flash interface. */
4268 if ((rc = bnx2_acquire_nvram_lock(bp)) != 0)
4269 return rc;
4270
4271 /* Enable access to flash interface */
4272 bnx2_enable_nvram_access(bp);
4273
4274 /* Reconfigure the flash interface */
4275 REG_WR(bp, BNX2_NVM_CFG1, flash->config1);
4276 REG_WR(bp, BNX2_NVM_CFG2, flash->config2);
4277 REG_WR(bp, BNX2_NVM_CFG3, flash->config3);
4278 REG_WR(bp, BNX2_NVM_WRITE1, flash->write1);
4279
4280 /* Disable access to flash interface */
4281 bnx2_disable_nvram_access(bp);
4282 bnx2_release_nvram_lock(bp);
4283
4284 break;
4285 }
4286 }
4287 } /* if (val & 0x40000000) */
4288
4289 if (j == entry_count) {
4290 bp->flash_info = NULL;
John W. Linville2f23c522005-11-10 12:57:33 -08004291 printk(KERN_ALERT PFX "Unknown flash/EEPROM type.\n");
Michael Chan1122db72006-01-23 16:11:42 -08004292 return -ENODEV;
Michael Chanb6016b72005-05-26 13:03:09 -07004293 }
4294
Michael Chane30372c2007-07-16 18:26:23 -07004295get_flash_size:
Michael Chan2726d6e2008-01-29 21:35:05 -08004296 val = bnx2_shmem_rd(bp, BNX2_SHARED_HW_CFG_CONFIG2);
Michael Chan1122db72006-01-23 16:11:42 -08004297 val &= BNX2_SHARED_HW_CFG2_NVM_SIZE_MASK;
4298 if (val)
4299 bp->flash_size = val;
4300 else
4301 bp->flash_size = bp->flash_info->total_size;
4302
Michael Chanb6016b72005-05-26 13:03:09 -07004303 return rc;
4304}
4305
4306static int
4307bnx2_nvram_read(struct bnx2 *bp, u32 offset, u8 *ret_buf,
4308 int buf_size)
4309{
4310 int rc = 0;
4311 u32 cmd_flags, offset32, len32, extra;
4312
4313 if (buf_size == 0)
4314 return 0;
4315
4316 /* Request access to the flash interface. */
4317 if ((rc = bnx2_acquire_nvram_lock(bp)) != 0)
4318 return rc;
4319
4320 /* Enable access to flash interface */
4321 bnx2_enable_nvram_access(bp);
4322
4323 len32 = buf_size;
4324 offset32 = offset;
4325 extra = 0;
4326
4327 cmd_flags = 0;
4328
4329 if (offset32 & 3) {
4330 u8 buf[4];
4331 u32 pre_len;
4332
4333 offset32 &= ~3;
4334 pre_len = 4 - (offset & 3);
4335
4336 if (pre_len >= len32) {
4337 pre_len = len32;
4338 cmd_flags = BNX2_NVM_COMMAND_FIRST |
4339 BNX2_NVM_COMMAND_LAST;
4340 }
4341 else {
4342 cmd_flags = BNX2_NVM_COMMAND_FIRST;
4343 }
4344
4345 rc = bnx2_nvram_read_dword(bp, offset32, buf, cmd_flags);
4346
4347 if (rc)
4348 return rc;
4349
4350 memcpy(ret_buf, buf + (offset & 3), pre_len);
4351
4352 offset32 += 4;
4353 ret_buf += pre_len;
4354 len32 -= pre_len;
4355 }
4356 if (len32 & 3) {
4357 extra = 4 - (len32 & 3);
4358 len32 = (len32 + 4) & ~3;
4359 }
4360
4361 if (len32 == 4) {
4362 u8 buf[4];
4363
4364 if (cmd_flags)
4365 cmd_flags = BNX2_NVM_COMMAND_LAST;
4366 else
4367 cmd_flags = BNX2_NVM_COMMAND_FIRST |
4368 BNX2_NVM_COMMAND_LAST;
4369
4370 rc = bnx2_nvram_read_dword(bp, offset32, buf, cmd_flags);
4371
4372 memcpy(ret_buf, buf, 4 - extra);
4373 }
4374 else if (len32 > 0) {
4375 u8 buf[4];
4376
4377 /* Read the first word. */
4378 if (cmd_flags)
4379 cmd_flags = 0;
4380 else
4381 cmd_flags = BNX2_NVM_COMMAND_FIRST;
4382
4383 rc = bnx2_nvram_read_dword(bp, offset32, ret_buf, cmd_flags);
4384
4385 /* Advance to the next dword. */
4386 offset32 += 4;
4387 ret_buf += 4;
4388 len32 -= 4;
4389
4390 while (len32 > 4 && rc == 0) {
4391 rc = bnx2_nvram_read_dword(bp, offset32, ret_buf, 0);
4392
4393 /* Advance to the next dword. */
4394 offset32 += 4;
4395 ret_buf += 4;
4396 len32 -= 4;
4397 }
4398
4399 if (rc)
4400 return rc;
4401
4402 cmd_flags = BNX2_NVM_COMMAND_LAST;
4403 rc = bnx2_nvram_read_dword(bp, offset32, buf, cmd_flags);
4404
4405 memcpy(ret_buf, buf, 4 - extra);
4406 }
4407
4408 /* Disable access to flash interface */
4409 bnx2_disable_nvram_access(bp);
4410
4411 bnx2_release_nvram_lock(bp);
4412
4413 return rc;
4414}
4415
4416static int
4417bnx2_nvram_write(struct bnx2 *bp, u32 offset, u8 *data_buf,
4418 int buf_size)
4419{
4420 u32 written, offset32, len32;
Michael Chane6be7632007-01-08 19:56:13 -08004421 u8 *buf, start[4], end[4], *align_buf = NULL, *flash_buffer = NULL;
Michael Chanb6016b72005-05-26 13:03:09 -07004422 int rc = 0;
4423 int align_start, align_end;
4424
4425 buf = data_buf;
4426 offset32 = offset;
4427 len32 = buf_size;
4428 align_start = align_end = 0;
4429
4430 if ((align_start = (offset32 & 3))) {
4431 offset32 &= ~3;
Michael Chanc8738792007-03-30 14:53:06 -07004432 len32 += align_start;
4433 if (len32 < 4)
4434 len32 = 4;
Michael Chanb6016b72005-05-26 13:03:09 -07004435 if ((rc = bnx2_nvram_read(bp, offset32, start, 4)))
4436 return rc;
4437 }
4438
4439 if (len32 & 3) {
Michael Chanc8738792007-03-30 14:53:06 -07004440 align_end = 4 - (len32 & 3);
4441 len32 += align_end;
4442 if ((rc = bnx2_nvram_read(bp, offset32 + len32 - 4, end, 4)))
4443 return rc;
Michael Chanb6016b72005-05-26 13:03:09 -07004444 }
4445
4446 if (align_start || align_end) {
Michael Chane6be7632007-01-08 19:56:13 -08004447 align_buf = kmalloc(len32, GFP_KERNEL);
4448 if (align_buf == NULL)
Michael Chanb6016b72005-05-26 13:03:09 -07004449 return -ENOMEM;
4450 if (align_start) {
Michael Chane6be7632007-01-08 19:56:13 -08004451 memcpy(align_buf, start, 4);
Michael Chanb6016b72005-05-26 13:03:09 -07004452 }
4453 if (align_end) {
Michael Chane6be7632007-01-08 19:56:13 -08004454 memcpy(align_buf + len32 - 4, end, 4);
Michael Chanb6016b72005-05-26 13:03:09 -07004455 }
Michael Chane6be7632007-01-08 19:56:13 -08004456 memcpy(align_buf + align_start, data_buf, buf_size);
4457 buf = align_buf;
Michael Chanb6016b72005-05-26 13:03:09 -07004458 }
4459
Michael Chane30372c2007-07-16 18:26:23 -07004460 if (!(bp->flash_info->flags & BNX2_NV_BUFFERED)) {
Michael Chanae181bc2006-05-22 16:39:20 -07004461 flash_buffer = kmalloc(264, GFP_KERNEL);
4462 if (flash_buffer == NULL) {
4463 rc = -ENOMEM;
4464 goto nvram_write_end;
4465 }
4466 }
4467
Michael Chanb6016b72005-05-26 13:03:09 -07004468 written = 0;
4469 while ((written < len32) && (rc == 0)) {
4470 u32 page_start, page_end, data_start, data_end;
4471 u32 addr, cmd_flags;
4472 int i;
Michael Chanb6016b72005-05-26 13:03:09 -07004473
4474 /* Find the page_start addr */
4475 page_start = offset32 + written;
4476 page_start -= (page_start % bp->flash_info->page_size);
4477 /* Find the page_end addr */
4478 page_end = page_start + bp->flash_info->page_size;
4479 /* Find the data_start addr */
4480 data_start = (written == 0) ? offset32 : page_start;
4481 /* Find the data_end addr */
Jeff Garzik6aa20a22006-09-13 13:24:59 -04004482 data_end = (page_end > offset32 + len32) ?
Michael Chanb6016b72005-05-26 13:03:09 -07004483 (offset32 + len32) : page_end;
4484
4485 /* Request access to the flash interface. */
4486 if ((rc = bnx2_acquire_nvram_lock(bp)) != 0)
4487 goto nvram_write_end;
4488
4489 /* Enable access to flash interface */
4490 bnx2_enable_nvram_access(bp);
4491
4492 cmd_flags = BNX2_NVM_COMMAND_FIRST;
Michael Chane30372c2007-07-16 18:26:23 -07004493 if (!(bp->flash_info->flags & BNX2_NV_BUFFERED)) {
Michael Chanb6016b72005-05-26 13:03:09 -07004494 int j;
4495
4496 /* Read the whole page into the buffer
4497 * (non-buffer flash only) */
4498 for (j = 0; j < bp->flash_info->page_size; j += 4) {
4499 if (j == (bp->flash_info->page_size - 4)) {
4500 cmd_flags |= BNX2_NVM_COMMAND_LAST;
4501 }
4502 rc = bnx2_nvram_read_dword(bp,
Jeff Garzik6aa20a22006-09-13 13:24:59 -04004503 page_start + j,
4504 &flash_buffer[j],
Michael Chanb6016b72005-05-26 13:03:09 -07004505 cmd_flags);
4506
4507 if (rc)
4508 goto nvram_write_end;
4509
4510 cmd_flags = 0;
4511 }
4512 }
4513
4514 /* Enable writes to flash interface (unlock write-protect) */
4515 if ((rc = bnx2_enable_nvram_write(bp)) != 0)
4516 goto nvram_write_end;
4517
Michael Chanb6016b72005-05-26 13:03:09 -07004518 /* Loop to write back the buffer data from page_start to
4519 * data_start */
4520 i = 0;
Michael Chane30372c2007-07-16 18:26:23 -07004521 if (!(bp->flash_info->flags & BNX2_NV_BUFFERED)) {
Michael Chanc8738792007-03-30 14:53:06 -07004522 /* Erase the page */
4523 if ((rc = bnx2_nvram_erase_page(bp, page_start)) != 0)
4524 goto nvram_write_end;
4525
4526 /* Re-enable the write again for the actual write */
4527 bnx2_enable_nvram_write(bp);
4528
Michael Chanb6016b72005-05-26 13:03:09 -07004529 for (addr = page_start; addr < data_start;
4530 addr += 4, i += 4) {
Jeff Garzik6aa20a22006-09-13 13:24:59 -04004531
Michael Chanb6016b72005-05-26 13:03:09 -07004532 rc = bnx2_nvram_write_dword(bp, addr,
4533 &flash_buffer[i], cmd_flags);
4534
4535 if (rc != 0)
4536 goto nvram_write_end;
4537
4538 cmd_flags = 0;
4539 }
4540 }
4541
4542 /* Loop to write the new data from data_start to data_end */
Michael Chanbae25762006-05-22 16:38:38 -07004543 for (addr = data_start; addr < data_end; addr += 4, i += 4) {
Michael Chanb6016b72005-05-26 13:03:09 -07004544 if ((addr == page_end - 4) ||
Michael Chane30372c2007-07-16 18:26:23 -07004545 ((bp->flash_info->flags & BNX2_NV_BUFFERED) &&
Michael Chanb6016b72005-05-26 13:03:09 -07004546 (addr == data_end - 4))) {
4547
4548 cmd_flags |= BNX2_NVM_COMMAND_LAST;
4549 }
4550 rc = bnx2_nvram_write_dword(bp, addr, buf,
4551 cmd_flags);
4552
4553 if (rc != 0)
4554 goto nvram_write_end;
4555
4556 cmd_flags = 0;
4557 buf += 4;
4558 }
4559
4560 /* Loop to write back the buffer data from data_end
4561 * to page_end */
Michael Chane30372c2007-07-16 18:26:23 -07004562 if (!(bp->flash_info->flags & BNX2_NV_BUFFERED)) {
Michael Chanb6016b72005-05-26 13:03:09 -07004563 for (addr = data_end; addr < page_end;
4564 addr += 4, i += 4) {
Jeff Garzik6aa20a22006-09-13 13:24:59 -04004565
Michael Chanb6016b72005-05-26 13:03:09 -07004566 if (addr == page_end-4) {
4567 cmd_flags = BNX2_NVM_COMMAND_LAST;
4568 }
4569 rc = bnx2_nvram_write_dword(bp, addr,
4570 &flash_buffer[i], cmd_flags);
4571
4572 if (rc != 0)
4573 goto nvram_write_end;
4574
4575 cmd_flags = 0;
4576 }
4577 }
4578
4579 /* Disable writes to flash interface (lock write-protect) */
4580 bnx2_disable_nvram_write(bp);
4581
4582 /* Disable access to flash interface */
4583 bnx2_disable_nvram_access(bp);
4584 bnx2_release_nvram_lock(bp);
4585
4586 /* Increment written */
4587 written += data_end - data_start;
4588 }
4589
4590nvram_write_end:
Michael Chane6be7632007-01-08 19:56:13 -08004591 kfree(flash_buffer);
4592 kfree(align_buf);
Michael Chanb6016b72005-05-26 13:03:09 -07004593 return rc;
4594}
4595
Michael Chan0d8a6572007-07-07 22:49:43 -07004596static void
Michael Chan7c62e832008-07-14 22:39:03 -07004597bnx2_init_fw_cap(struct bnx2 *bp)
Michael Chan0d8a6572007-07-07 22:49:43 -07004598{
Michael Chan7c62e832008-07-14 22:39:03 -07004599 u32 val, sig = 0;
Michael Chan0d8a6572007-07-07 22:49:43 -07004600
Michael Chan583c28e2008-01-21 19:51:35 -08004601 bp->phy_flags &= ~BNX2_PHY_FLAG_REMOTE_PHY_CAP;
Michael Chan7c62e832008-07-14 22:39:03 -07004602 bp->flags &= ~BNX2_FLAG_CAN_KEEP_VLAN;
4603
4604 if (!(bp->flags & BNX2_FLAG_ASF_ENABLE))
4605 bp->flags |= BNX2_FLAG_CAN_KEEP_VLAN;
Michael Chan0d8a6572007-07-07 22:49:43 -07004606
Michael Chan2726d6e2008-01-29 21:35:05 -08004607 val = bnx2_shmem_rd(bp, BNX2_FW_CAP_MB);
Michael Chan0d8a6572007-07-07 22:49:43 -07004608 if ((val & BNX2_FW_CAP_SIGNATURE_MASK) != BNX2_FW_CAP_SIGNATURE)
4609 return;
4610
Michael Chan7c62e832008-07-14 22:39:03 -07004611 if ((val & BNX2_FW_CAP_CAN_KEEP_VLAN) == BNX2_FW_CAP_CAN_KEEP_VLAN) {
4612 bp->flags |= BNX2_FLAG_CAN_KEEP_VLAN;
4613 sig |= BNX2_DRV_ACK_CAP_SIGNATURE | BNX2_FW_CAP_CAN_KEEP_VLAN;
4614 }
4615
4616 if ((bp->phy_flags & BNX2_PHY_FLAG_SERDES) &&
4617 (val & BNX2_FW_CAP_REMOTE_PHY_CAPABLE)) {
4618 u32 link;
4619
Michael Chan583c28e2008-01-21 19:51:35 -08004620 bp->phy_flags |= BNX2_PHY_FLAG_REMOTE_PHY_CAP;
Michael Chan0d8a6572007-07-07 22:49:43 -07004621
Michael Chan7c62e832008-07-14 22:39:03 -07004622 link = bnx2_shmem_rd(bp, BNX2_LINK_STATUS);
4623 if (link & BNX2_LINK_STATUS_SERDES_LINK)
Michael Chan0d8a6572007-07-07 22:49:43 -07004624 bp->phy_port = PORT_FIBRE;
4625 else
4626 bp->phy_port = PORT_TP;
Michael Chan489310a2007-10-10 16:16:31 -07004627
Michael Chan7c62e832008-07-14 22:39:03 -07004628 sig |= BNX2_DRV_ACK_CAP_SIGNATURE |
4629 BNX2_FW_CAP_REMOTE_PHY_CAPABLE;
Michael Chan0d8a6572007-07-07 22:49:43 -07004630 }
Michael Chan7c62e832008-07-14 22:39:03 -07004631
4632 if (netif_running(bp->dev) && sig)
4633 bnx2_shmem_wr(bp, BNX2_DRV_ACK_CAP_MB, sig);
Michael Chan0d8a6572007-07-07 22:49:43 -07004634}
4635
Michael Chanb4b36042007-12-20 19:59:30 -08004636static void
4637bnx2_setup_msix_tbl(struct bnx2 *bp)
4638{
4639 REG_WR(bp, BNX2_PCI_GRC_WINDOW_ADDR, BNX2_PCI_GRC_WINDOW_ADDR_SEP_WIN);
4640
4641 REG_WR(bp, BNX2_PCI_GRC_WINDOW2_ADDR, BNX2_MSIX_TABLE_ADDR);
4642 REG_WR(bp, BNX2_PCI_GRC_WINDOW3_ADDR, BNX2_MSIX_PBA_ADDR);
4643}
4644
Michael Chanb6016b72005-05-26 13:03:09 -07004645static int
4646bnx2_reset_chip(struct bnx2 *bp, u32 reset_code)
4647{
4648 u32 val;
4649 int i, rc = 0;
Michael Chan489310a2007-10-10 16:16:31 -07004650 u8 old_port;
Michael Chanb6016b72005-05-26 13:03:09 -07004651
4652 /* Wait for the current PCI transaction to complete before
4653 * issuing a reset. */
4654 REG_WR(bp, BNX2_MISC_ENABLE_CLR_BITS,
4655 BNX2_MISC_ENABLE_CLR_BITS_TX_DMA_ENABLE |
4656 BNX2_MISC_ENABLE_CLR_BITS_DMA_ENGINE_ENABLE |
4657 BNX2_MISC_ENABLE_CLR_BITS_RX_DMA_ENABLE |
4658 BNX2_MISC_ENABLE_CLR_BITS_HOST_COALESCE_ENABLE);
4659 val = REG_RD(bp, BNX2_MISC_ENABLE_CLR_BITS);
4660 udelay(5);
4661
Michael Chanb090ae22006-01-23 16:07:10 -08004662 /* Wait for the firmware to tell us it is ok to issue a reset. */
Michael Chana2f13892008-07-14 22:38:23 -07004663 bnx2_fw_sync(bp, BNX2_DRV_MSG_DATA_WAIT0 | reset_code, 1, 1);
Michael Chanb090ae22006-01-23 16:07:10 -08004664
Michael Chanb6016b72005-05-26 13:03:09 -07004665 /* Deposit a driver reset signature so the firmware knows that
4666 * this is a soft reset. */
Michael Chan2726d6e2008-01-29 21:35:05 -08004667 bnx2_shmem_wr(bp, BNX2_DRV_RESET_SIGNATURE,
4668 BNX2_DRV_RESET_SIGNATURE_MAGIC);
Michael Chanb6016b72005-05-26 13:03:09 -07004669
Michael Chanb6016b72005-05-26 13:03:09 -07004670 /* Do a dummy read to force the chip to complete all current transaction
4671 * before we issue a reset. */
4672 val = REG_RD(bp, BNX2_MISC_ID);
4673
Michael Chan234754d2006-11-19 14:11:41 -08004674 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
4675 REG_WR(bp, BNX2_MISC_COMMAND, BNX2_MISC_COMMAND_SW_RESET);
4676 REG_RD(bp, BNX2_MISC_COMMAND);
4677 udelay(5);
Michael Chanb6016b72005-05-26 13:03:09 -07004678
Michael Chan234754d2006-11-19 14:11:41 -08004679 val = BNX2_PCICFG_MISC_CONFIG_REG_WINDOW_ENA |
4680 BNX2_PCICFG_MISC_CONFIG_TARGET_MB_WORD_SWAP;
Michael Chanb6016b72005-05-26 13:03:09 -07004681
Michael Chan234754d2006-11-19 14:11:41 -08004682 pci_write_config_dword(bp->pdev, BNX2_PCICFG_MISC_CONFIG, val);
Michael Chanb6016b72005-05-26 13:03:09 -07004683
Michael Chan234754d2006-11-19 14:11:41 -08004684 } else {
4685 val = BNX2_PCICFG_MISC_CONFIG_CORE_RST_REQ |
4686 BNX2_PCICFG_MISC_CONFIG_REG_WINDOW_ENA |
4687 BNX2_PCICFG_MISC_CONFIG_TARGET_MB_WORD_SWAP;
4688
4689 /* Chip reset. */
4690 REG_WR(bp, BNX2_PCICFG_MISC_CONFIG, val);
4691
Michael Chan594a9df2007-08-28 15:39:42 -07004692 /* Reading back any register after chip reset will hang the
4693 * bus on 5706 A0 and A1. The msleep below provides plenty
4694 * of margin for write posting.
4695 */
Michael Chan234754d2006-11-19 14:11:41 -08004696 if ((CHIP_ID(bp) == CHIP_ID_5706_A0) ||
Arjan van de Ven8e545882007-08-28 14:34:43 -07004697 (CHIP_ID(bp) == CHIP_ID_5706_A1))
4698 msleep(20);
Michael Chanb6016b72005-05-26 13:03:09 -07004699
Michael Chan234754d2006-11-19 14:11:41 -08004700 /* Reset takes approximate 30 usec */
4701 for (i = 0; i < 10; i++) {
4702 val = REG_RD(bp, BNX2_PCICFG_MISC_CONFIG);
4703 if ((val & (BNX2_PCICFG_MISC_CONFIG_CORE_RST_REQ |
4704 BNX2_PCICFG_MISC_CONFIG_CORE_RST_BSY)) == 0)
4705 break;
4706 udelay(10);
4707 }
4708
4709 if (val & (BNX2_PCICFG_MISC_CONFIG_CORE_RST_REQ |
4710 BNX2_PCICFG_MISC_CONFIG_CORE_RST_BSY)) {
4711 printk(KERN_ERR PFX "Chip reset did not complete\n");
4712 return -EBUSY;
4713 }
Michael Chanb6016b72005-05-26 13:03:09 -07004714 }
4715
4716 /* Make sure byte swapping is properly configured. */
4717 val = REG_RD(bp, BNX2_PCI_SWAP_DIAG0);
4718 if (val != 0x01020304) {
4719 printk(KERN_ERR PFX "Chip not in correct endian mode\n");
4720 return -ENODEV;
4721 }
4722
Michael Chanb6016b72005-05-26 13:03:09 -07004723 /* Wait for the firmware to finish its initialization. */
Michael Chana2f13892008-07-14 22:38:23 -07004724 rc = bnx2_fw_sync(bp, BNX2_DRV_MSG_DATA_WAIT1 | reset_code, 1, 0);
Michael Chanb090ae22006-01-23 16:07:10 -08004725 if (rc)
4726 return rc;
Michael Chanb6016b72005-05-26 13:03:09 -07004727
Michael Chan0d8a6572007-07-07 22:49:43 -07004728 spin_lock_bh(&bp->phy_lock);
Michael Chan489310a2007-10-10 16:16:31 -07004729 old_port = bp->phy_port;
Michael Chan7c62e832008-07-14 22:39:03 -07004730 bnx2_init_fw_cap(bp);
Michael Chan583c28e2008-01-21 19:51:35 -08004731 if ((bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP) &&
4732 old_port != bp->phy_port)
Michael Chan0d8a6572007-07-07 22:49:43 -07004733 bnx2_set_default_remote_link(bp);
4734 spin_unlock_bh(&bp->phy_lock);
4735
Michael Chanb6016b72005-05-26 13:03:09 -07004736 if (CHIP_ID(bp) == CHIP_ID_5706_A0) {
4737 /* Adjust the voltage regular to two steps lower. The default
4738 * of this register is 0x0000000e. */
4739 REG_WR(bp, BNX2_MISC_VREG_CONTROL, 0x000000fa);
4740
4741 /* Remove bad rbuf memory from the free pool. */
4742 rc = bnx2_alloc_bad_rbuf(bp);
4743 }
4744
David S. Millerf86e82f2008-01-21 17:15:40 -08004745 if (bp->flags & BNX2_FLAG_USING_MSIX)
Michael Chanb4b36042007-12-20 19:59:30 -08004746 bnx2_setup_msix_tbl(bp);
4747
Michael Chanb6016b72005-05-26 13:03:09 -07004748 return rc;
4749}
4750
4751static int
4752bnx2_init_chip(struct bnx2 *bp)
4753{
Michael Chand8026d92008-11-12 16:02:20 -08004754 u32 val, mtu;
Michael Chanb4b36042007-12-20 19:59:30 -08004755 int rc, i;
Michael Chanb6016b72005-05-26 13:03:09 -07004756
4757 /* Make sure the interrupt is not active. */
4758 REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD, BNX2_PCICFG_INT_ACK_CMD_MASK_INT);
4759
4760 val = BNX2_DMA_CONFIG_DATA_BYTE_SWAP |
4761 BNX2_DMA_CONFIG_DATA_WORD_SWAP |
4762#ifdef __BIG_ENDIAN
Jeff Garzik6aa20a22006-09-13 13:24:59 -04004763 BNX2_DMA_CONFIG_CNTL_BYTE_SWAP |
Michael Chanb6016b72005-05-26 13:03:09 -07004764#endif
Jeff Garzik6aa20a22006-09-13 13:24:59 -04004765 BNX2_DMA_CONFIG_CNTL_WORD_SWAP |
Michael Chanb6016b72005-05-26 13:03:09 -07004766 DMA_READ_CHANS << 12 |
4767 DMA_WRITE_CHANS << 16;
4768
4769 val |= (0x2 << 20) | (1 << 11);
4770
David S. Millerf86e82f2008-01-21 17:15:40 -08004771 if ((bp->flags & BNX2_FLAG_PCIX) && (bp->bus_speed_mhz == 133))
Michael Chanb6016b72005-05-26 13:03:09 -07004772 val |= (1 << 23);
4773
4774 if ((CHIP_NUM(bp) == CHIP_NUM_5706) &&
David S. Millerf86e82f2008-01-21 17:15:40 -08004775 (CHIP_ID(bp) != CHIP_ID_5706_A0) && !(bp->flags & BNX2_FLAG_PCIX))
Michael Chanb6016b72005-05-26 13:03:09 -07004776 val |= BNX2_DMA_CONFIG_CNTL_PING_PONG_DMA;
4777
4778 REG_WR(bp, BNX2_DMA_CONFIG, val);
4779
4780 if (CHIP_ID(bp) == CHIP_ID_5706_A0) {
4781 val = REG_RD(bp, BNX2_TDMA_CONFIG);
4782 val |= BNX2_TDMA_CONFIG_ONE_DMA;
4783 REG_WR(bp, BNX2_TDMA_CONFIG, val);
4784 }
4785
David S. Millerf86e82f2008-01-21 17:15:40 -08004786 if (bp->flags & BNX2_FLAG_PCIX) {
Michael Chanb6016b72005-05-26 13:03:09 -07004787 u16 val16;
4788
4789 pci_read_config_word(bp->pdev, bp->pcix_cap + PCI_X_CMD,
4790 &val16);
4791 pci_write_config_word(bp->pdev, bp->pcix_cap + PCI_X_CMD,
4792 val16 & ~PCI_X_CMD_ERO);
4793 }
4794
4795 REG_WR(bp, BNX2_MISC_ENABLE_SET_BITS,
4796 BNX2_MISC_ENABLE_SET_BITS_HOST_COALESCE_ENABLE |
4797 BNX2_MISC_ENABLE_STATUS_BITS_RX_V2P_ENABLE |
4798 BNX2_MISC_ENABLE_STATUS_BITS_CONTEXT_ENABLE);
4799
4800 /* Initialize context mapping and zero out the quick contexts. The
4801 * context block must have already been enabled. */
Michael Chan641bdcd2007-06-04 21:22:24 -07004802 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
4803 rc = bnx2_init_5709_context(bp);
4804 if (rc)
4805 return rc;
4806 } else
Michael Chan59b47d82006-11-19 14:10:45 -08004807 bnx2_init_context(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07004808
Michael Chanfba9fe92006-06-12 22:21:25 -07004809 if ((rc = bnx2_init_cpus(bp)) != 0)
4810 return rc;
4811
Michael Chanb6016b72005-05-26 13:03:09 -07004812 bnx2_init_nvram(bp);
4813
Benjamin Li5fcaed02008-07-14 22:39:52 -07004814 bnx2_set_mac_addr(bp, bp->dev->dev_addr, 0);
Michael Chanb6016b72005-05-26 13:03:09 -07004815
4816 val = REG_RD(bp, BNX2_MQ_CONFIG);
4817 val &= ~BNX2_MQ_CONFIG_KNL_BYP_BLK_SIZE;
4818 val |= BNX2_MQ_CONFIG_KNL_BYP_BLK_SIZE_256;
Michael Chan4edd4732009-06-08 18:14:42 -07004819 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
4820 val |= BNX2_MQ_CONFIG_BIN_MQ_MODE;
4821 if (CHIP_REV(bp) == CHIP_REV_Ax)
4822 val |= BNX2_MQ_CONFIG_HALT_DIS;
4823 }
Michael Chan68c9f752007-04-24 15:35:53 -07004824
Michael Chanb6016b72005-05-26 13:03:09 -07004825 REG_WR(bp, BNX2_MQ_CONFIG, val);
4826
4827 val = 0x10000 + (MAX_CID_CNT * MB_KERNEL_CTX_SIZE);
4828 REG_WR(bp, BNX2_MQ_KNL_BYP_WIND_START, val);
4829 REG_WR(bp, BNX2_MQ_KNL_WIND_END, val);
4830
4831 val = (BCM_PAGE_BITS - 8) << 24;
4832 REG_WR(bp, BNX2_RV2P_CONFIG, val);
4833
4834 /* Configure page size. */
4835 val = REG_RD(bp, BNX2_TBDR_CONFIG);
4836 val &= ~BNX2_TBDR_CONFIG_PAGE_SIZE;
4837 val |= (BCM_PAGE_BITS - 8) << 24 | 0x40;
4838 REG_WR(bp, BNX2_TBDR_CONFIG, val);
4839
4840 val = bp->mac_addr[0] +
4841 (bp->mac_addr[1] << 8) +
4842 (bp->mac_addr[2] << 16) +
4843 bp->mac_addr[3] +
4844 (bp->mac_addr[4] << 8) +
4845 (bp->mac_addr[5] << 16);
4846 REG_WR(bp, BNX2_EMAC_BACKOFF_SEED, val);
4847
4848 /* Program the MTU. Also include 4 bytes for CRC32. */
Michael Chand8026d92008-11-12 16:02:20 -08004849 mtu = bp->dev->mtu;
4850 val = mtu + ETH_HLEN + ETH_FCS_LEN;
Michael Chanb6016b72005-05-26 13:03:09 -07004851 if (val > (MAX_ETHERNET_PACKET_SIZE + 4))
4852 val |= BNX2_EMAC_RX_MTU_SIZE_JUMBO_ENA;
4853 REG_WR(bp, BNX2_EMAC_RX_MTU_SIZE, val);
4854
Michael Chand8026d92008-11-12 16:02:20 -08004855 if (mtu < 1500)
4856 mtu = 1500;
4857
4858 bnx2_reg_wr_ind(bp, BNX2_RBUF_CONFIG, BNX2_RBUF_CONFIG_VAL(mtu));
4859 bnx2_reg_wr_ind(bp, BNX2_RBUF_CONFIG2, BNX2_RBUF_CONFIG2_VAL(mtu));
4860 bnx2_reg_wr_ind(bp, BNX2_RBUF_CONFIG3, BNX2_RBUF_CONFIG3_VAL(mtu));
4861
Michael Chanb4b36042007-12-20 19:59:30 -08004862 for (i = 0; i < BNX2_MAX_MSIX_VEC; i++)
4863 bp->bnx2_napi[i].last_status_idx = 0;
4864
Michael Chanefba0182008-12-03 00:36:15 -08004865 bp->idle_chk_status_idx = 0xffff;
4866
Michael Chanb6016b72005-05-26 13:03:09 -07004867 bp->rx_mode = BNX2_EMAC_RX_MODE_SORT_MODE;
4868
4869 /* Set up how to generate a link change interrupt. */
4870 REG_WR(bp, BNX2_EMAC_ATTENTION_ENA, BNX2_EMAC_ATTENTION_ENA_LINK);
4871
4872 REG_WR(bp, BNX2_HC_STATUS_ADDR_L,
4873 (u64) bp->status_blk_mapping & 0xffffffff);
4874 REG_WR(bp, BNX2_HC_STATUS_ADDR_H, (u64) bp->status_blk_mapping >> 32);
4875
4876 REG_WR(bp, BNX2_HC_STATISTICS_ADDR_L,
4877 (u64) bp->stats_blk_mapping & 0xffffffff);
4878 REG_WR(bp, BNX2_HC_STATISTICS_ADDR_H,
4879 (u64) bp->stats_blk_mapping >> 32);
4880
Jeff Garzik6aa20a22006-09-13 13:24:59 -04004881 REG_WR(bp, BNX2_HC_TX_QUICK_CONS_TRIP,
Michael Chanb6016b72005-05-26 13:03:09 -07004882 (bp->tx_quick_cons_trip_int << 16) | bp->tx_quick_cons_trip);
4883
4884 REG_WR(bp, BNX2_HC_RX_QUICK_CONS_TRIP,
4885 (bp->rx_quick_cons_trip_int << 16) | bp->rx_quick_cons_trip);
4886
4887 REG_WR(bp, BNX2_HC_COMP_PROD_TRIP,
4888 (bp->comp_prod_trip_int << 16) | bp->comp_prod_trip);
4889
4890 REG_WR(bp, BNX2_HC_TX_TICKS, (bp->tx_ticks_int << 16) | bp->tx_ticks);
4891
4892 REG_WR(bp, BNX2_HC_RX_TICKS, (bp->rx_ticks_int << 16) | bp->rx_ticks);
4893
4894 REG_WR(bp, BNX2_HC_COM_TICKS,
4895 (bp->com_ticks_int << 16) | bp->com_ticks);
4896
4897 REG_WR(bp, BNX2_HC_CMD_TICKS,
4898 (bp->cmd_ticks_int << 16) | bp->cmd_ticks);
4899
Michael Chan02537b062007-06-04 21:24:07 -07004900 if (CHIP_NUM(bp) == CHIP_NUM_5708)
4901 REG_WR(bp, BNX2_HC_STATS_TICKS, 0);
4902 else
Michael Chan7ea69202007-07-16 18:27:10 -07004903 REG_WR(bp, BNX2_HC_STATS_TICKS, bp->stats_ticks);
Michael Chanb6016b72005-05-26 13:03:09 -07004904 REG_WR(bp, BNX2_HC_STAT_COLLECT_TICKS, 0xbb8); /* 3ms */
4905
4906 if (CHIP_ID(bp) == CHIP_ID_5706_A1)
Michael Chan8e6a72c2007-05-03 13:24:48 -07004907 val = BNX2_HC_CONFIG_COLLECT_STATS;
Michael Chanb6016b72005-05-26 13:03:09 -07004908 else {
Michael Chan8e6a72c2007-05-03 13:24:48 -07004909 val = BNX2_HC_CONFIG_RX_TMR_MODE | BNX2_HC_CONFIG_TX_TMR_MODE |
4910 BNX2_HC_CONFIG_COLLECT_STATS;
Michael Chanb6016b72005-05-26 13:03:09 -07004911 }
4912
Michael Chan5e9ad9e2008-06-19 16:43:17 -07004913 if (bp->irq_nvecs > 1) {
Michael Chanc76c0472007-12-20 20:01:19 -08004914 REG_WR(bp, BNX2_HC_MSIX_BIT_VECTOR,
4915 BNX2_HC_MSIX_BIT_VECTOR_VAL);
4916
Michael Chan5e9ad9e2008-06-19 16:43:17 -07004917 val |= BNX2_HC_CONFIG_SB_ADDR_INC_128B;
4918 }
4919
4920 if (bp->flags & BNX2_FLAG_ONE_SHOT_MSI)
4921 val |= BNX2_HC_CONFIG_ONE_SHOT;
4922
4923 REG_WR(bp, BNX2_HC_CONFIG, val);
4924
4925 for (i = 1; i < bp->irq_nvecs; i++) {
4926 u32 base = ((i - 1) * BNX2_HC_SB_CONFIG_SIZE) +
4927 BNX2_HC_SB_CONFIG_1;
4928
Michael Chan6f743ca2008-01-29 21:34:08 -08004929 REG_WR(bp, base,
Michael Chanc76c0472007-12-20 20:01:19 -08004930 BNX2_HC_SB_CONFIG_1_TX_TMR_MODE |
Michael Chan5e9ad9e2008-06-19 16:43:17 -07004931 BNX2_HC_SB_CONFIG_1_RX_TMR_MODE |
Michael Chanc76c0472007-12-20 20:01:19 -08004932 BNX2_HC_SB_CONFIG_1_ONE_SHOT);
4933
Michael Chan6f743ca2008-01-29 21:34:08 -08004934 REG_WR(bp, base + BNX2_HC_TX_QUICK_CONS_TRIP_OFF,
Michael Chanc76c0472007-12-20 20:01:19 -08004935 (bp->tx_quick_cons_trip_int << 16) |
4936 bp->tx_quick_cons_trip);
4937
Michael Chan6f743ca2008-01-29 21:34:08 -08004938 REG_WR(bp, base + BNX2_HC_TX_TICKS_OFF,
Michael Chanc76c0472007-12-20 20:01:19 -08004939 (bp->tx_ticks_int << 16) | bp->tx_ticks);
4940
Michael Chan5e9ad9e2008-06-19 16:43:17 -07004941 REG_WR(bp, base + BNX2_HC_RX_QUICK_CONS_TRIP_OFF,
4942 (bp->rx_quick_cons_trip_int << 16) |
4943 bp->rx_quick_cons_trip);
4944
4945 REG_WR(bp, base + BNX2_HC_RX_TICKS_OFF,
4946 (bp->rx_ticks_int << 16) | bp->rx_ticks);
Michael Chanc76c0472007-12-20 20:01:19 -08004947 }
4948
Michael Chanb6016b72005-05-26 13:03:09 -07004949 /* Clear internal stats counters. */
4950 REG_WR(bp, BNX2_HC_COMMAND, BNX2_HC_COMMAND_CLR_STAT_NOW);
4951
Michael Chanda3e4fb2007-05-03 13:24:23 -07004952 REG_WR(bp, BNX2_HC_ATTN_BITS_ENABLE, STATUS_ATTN_EVENTS);
Michael Chanb6016b72005-05-26 13:03:09 -07004953
4954 /* Initialize the receive filter. */
4955 bnx2_set_rx_mode(bp->dev);
4956
Michael Chan0aa38df2007-06-04 21:23:06 -07004957 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
4958 val = REG_RD(bp, BNX2_MISC_NEW_CORE_CTL);
4959 val |= BNX2_MISC_NEW_CORE_CTL_DMA_ENABLE;
4960 REG_WR(bp, BNX2_MISC_NEW_CORE_CTL, val);
4961 }
Michael Chanb090ae22006-01-23 16:07:10 -08004962 rc = bnx2_fw_sync(bp, BNX2_DRV_MSG_DATA_WAIT2 | BNX2_DRV_MSG_CODE_RESET,
Michael Chana2f13892008-07-14 22:38:23 -07004963 1, 0);
Michael Chanb6016b72005-05-26 13:03:09 -07004964
Michael Chandf149d72007-07-07 22:51:36 -07004965 REG_WR(bp, BNX2_MISC_ENABLE_SET_BITS, BNX2_MISC_ENABLE_DEFAULT);
Michael Chanb6016b72005-05-26 13:03:09 -07004966 REG_RD(bp, BNX2_MISC_ENABLE_SET_BITS);
4967
4968 udelay(20);
4969
Michael Chanbf5295b2006-03-23 01:11:56 -08004970 bp->hc_cmd = REG_RD(bp, BNX2_HC_COMMAND);
4971
Michael Chanb090ae22006-01-23 16:07:10 -08004972 return rc;
Michael Chanb6016b72005-05-26 13:03:09 -07004973}
4974
Michael Chan59b47d82006-11-19 14:10:45 -08004975static void
Michael Chanc76c0472007-12-20 20:01:19 -08004976bnx2_clear_ring_states(struct bnx2 *bp)
4977{
4978 struct bnx2_napi *bnapi;
Michael Chan35e90102008-06-19 16:37:42 -07004979 struct bnx2_tx_ring_info *txr;
Michael Chanbb4f98a2008-06-19 16:38:19 -07004980 struct bnx2_rx_ring_info *rxr;
Michael Chanc76c0472007-12-20 20:01:19 -08004981 int i;
4982
4983 for (i = 0; i < BNX2_MAX_MSIX_VEC; i++) {
4984 bnapi = &bp->bnx2_napi[i];
Michael Chan35e90102008-06-19 16:37:42 -07004985 txr = &bnapi->tx_ring;
Michael Chanbb4f98a2008-06-19 16:38:19 -07004986 rxr = &bnapi->rx_ring;
Michael Chanc76c0472007-12-20 20:01:19 -08004987
Michael Chan35e90102008-06-19 16:37:42 -07004988 txr->tx_cons = 0;
4989 txr->hw_tx_cons = 0;
Michael Chanbb4f98a2008-06-19 16:38:19 -07004990 rxr->rx_prod_bseq = 0;
4991 rxr->rx_prod = 0;
4992 rxr->rx_cons = 0;
4993 rxr->rx_pg_prod = 0;
4994 rxr->rx_pg_cons = 0;
Michael Chanc76c0472007-12-20 20:01:19 -08004995 }
4996}
4997
4998static void
Michael Chan35e90102008-06-19 16:37:42 -07004999bnx2_init_tx_context(struct bnx2 *bp, u32 cid, struct bnx2_tx_ring_info *txr)
Michael Chan59b47d82006-11-19 14:10:45 -08005000{
5001 u32 val, offset0, offset1, offset2, offset3;
Michael Chan62a83132008-01-29 21:35:40 -08005002 u32 cid_addr = GET_CID_ADDR(cid);
Michael Chan59b47d82006-11-19 14:10:45 -08005003
5004 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
5005 offset0 = BNX2_L2CTX_TYPE_XI;
5006 offset1 = BNX2_L2CTX_CMD_TYPE_XI;
5007 offset2 = BNX2_L2CTX_TBDR_BHADDR_HI_XI;
5008 offset3 = BNX2_L2CTX_TBDR_BHADDR_LO_XI;
5009 } else {
5010 offset0 = BNX2_L2CTX_TYPE;
5011 offset1 = BNX2_L2CTX_CMD_TYPE;
5012 offset2 = BNX2_L2CTX_TBDR_BHADDR_HI;
5013 offset3 = BNX2_L2CTX_TBDR_BHADDR_LO;
5014 }
5015 val = BNX2_L2CTX_TYPE_TYPE_L2 | BNX2_L2CTX_TYPE_SIZE_L2;
Michael Chan62a83132008-01-29 21:35:40 -08005016 bnx2_ctx_wr(bp, cid_addr, offset0, val);
Michael Chan59b47d82006-11-19 14:10:45 -08005017
5018 val = BNX2_L2CTX_CMD_TYPE_TYPE_L2 | (8 << 16);
Michael Chan62a83132008-01-29 21:35:40 -08005019 bnx2_ctx_wr(bp, cid_addr, offset1, val);
Michael Chan59b47d82006-11-19 14:10:45 -08005020
Michael Chan35e90102008-06-19 16:37:42 -07005021 val = (u64) txr->tx_desc_mapping >> 32;
Michael Chan62a83132008-01-29 21:35:40 -08005022 bnx2_ctx_wr(bp, cid_addr, offset2, val);
Michael Chan59b47d82006-11-19 14:10:45 -08005023
Michael Chan35e90102008-06-19 16:37:42 -07005024 val = (u64) txr->tx_desc_mapping & 0xffffffff;
Michael Chan62a83132008-01-29 21:35:40 -08005025 bnx2_ctx_wr(bp, cid_addr, offset3, val);
Michael Chan59b47d82006-11-19 14:10:45 -08005026}
Michael Chanb6016b72005-05-26 13:03:09 -07005027
5028static void
Michael Chan35e90102008-06-19 16:37:42 -07005029bnx2_init_tx_ring(struct bnx2 *bp, int ring_num)
Michael Chanb6016b72005-05-26 13:03:09 -07005030{
5031 struct tx_bd *txbd;
Michael Chanc76c0472007-12-20 20:01:19 -08005032 u32 cid = TX_CID;
5033 struct bnx2_napi *bnapi;
Michael Chan35e90102008-06-19 16:37:42 -07005034 struct bnx2_tx_ring_info *txr;
Michael Chanc76c0472007-12-20 20:01:19 -08005035
Michael Chan35e90102008-06-19 16:37:42 -07005036 bnapi = &bp->bnx2_napi[ring_num];
5037 txr = &bnapi->tx_ring;
5038
5039 if (ring_num == 0)
5040 cid = TX_CID;
5041 else
5042 cid = TX_TSS_CID + ring_num - 1;
Michael Chanb6016b72005-05-26 13:03:09 -07005043
Michael Chan2f8af122006-08-15 01:39:10 -07005044 bp->tx_wake_thresh = bp->tx_ring_size / 2;
5045
Michael Chan35e90102008-06-19 16:37:42 -07005046 txbd = &txr->tx_desc_ring[MAX_TX_DESC_CNT];
Jeff Garzik6aa20a22006-09-13 13:24:59 -04005047
Michael Chan35e90102008-06-19 16:37:42 -07005048 txbd->tx_bd_haddr_hi = (u64) txr->tx_desc_mapping >> 32;
5049 txbd->tx_bd_haddr_lo = (u64) txr->tx_desc_mapping & 0xffffffff;
Michael Chanb6016b72005-05-26 13:03:09 -07005050
Michael Chan35e90102008-06-19 16:37:42 -07005051 txr->tx_prod = 0;
5052 txr->tx_prod_bseq = 0;
Jeff Garzik6aa20a22006-09-13 13:24:59 -04005053
Michael Chan35e90102008-06-19 16:37:42 -07005054 txr->tx_bidx_addr = MB_GET_CID_ADDR(cid) + BNX2_L2CTX_TX_HOST_BIDX;
5055 txr->tx_bseq_addr = MB_GET_CID_ADDR(cid) + BNX2_L2CTX_TX_HOST_BSEQ;
Michael Chanb6016b72005-05-26 13:03:09 -07005056
Michael Chan35e90102008-06-19 16:37:42 -07005057 bnx2_init_tx_context(bp, cid, txr);
Michael Chanb6016b72005-05-26 13:03:09 -07005058}
5059
5060static void
Michael Chan5d5d0012007-12-12 11:17:43 -08005061bnx2_init_rxbd_rings(struct rx_bd *rx_ring[], dma_addr_t dma[], u32 buf_size,
5062 int num_rings)
Michael Chanb6016b72005-05-26 13:03:09 -07005063{
Michael Chanb6016b72005-05-26 13:03:09 -07005064 int i;
Michael Chan5d5d0012007-12-12 11:17:43 -08005065 struct rx_bd *rxbd;
Michael Chanb6016b72005-05-26 13:03:09 -07005066
Michael Chan5d5d0012007-12-12 11:17:43 -08005067 for (i = 0; i < num_rings; i++) {
Michael Chan13daffa2006-03-20 17:49:20 -08005068 int j;
Michael Chanb6016b72005-05-26 13:03:09 -07005069
Michael Chan5d5d0012007-12-12 11:17:43 -08005070 rxbd = &rx_ring[i][0];
Michael Chan13daffa2006-03-20 17:49:20 -08005071 for (j = 0; j < MAX_RX_DESC_CNT; j++, rxbd++) {
Michael Chan5d5d0012007-12-12 11:17:43 -08005072 rxbd->rx_bd_len = buf_size;
Michael Chan13daffa2006-03-20 17:49:20 -08005073 rxbd->rx_bd_flags = RX_BD_FLAGS_START | RX_BD_FLAGS_END;
5074 }
Michael Chan5d5d0012007-12-12 11:17:43 -08005075 if (i == (num_rings - 1))
Michael Chan13daffa2006-03-20 17:49:20 -08005076 j = 0;
5077 else
5078 j = i + 1;
Michael Chan5d5d0012007-12-12 11:17:43 -08005079 rxbd->rx_bd_haddr_hi = (u64) dma[j] >> 32;
5080 rxbd->rx_bd_haddr_lo = (u64) dma[j] & 0xffffffff;
Michael Chan13daffa2006-03-20 17:49:20 -08005081 }
Michael Chan5d5d0012007-12-12 11:17:43 -08005082}
5083
5084static void
Michael Chanbb4f98a2008-06-19 16:38:19 -07005085bnx2_init_rx_ring(struct bnx2 *bp, int ring_num)
Michael Chan5d5d0012007-12-12 11:17:43 -08005086{
5087 int i;
5088 u16 prod, ring_prod;
Michael Chanbb4f98a2008-06-19 16:38:19 -07005089 u32 cid, rx_cid_addr, val;
5090 struct bnx2_napi *bnapi = &bp->bnx2_napi[ring_num];
5091 struct bnx2_rx_ring_info *rxr = &bnapi->rx_ring;
Michael Chan5d5d0012007-12-12 11:17:43 -08005092
Michael Chanbb4f98a2008-06-19 16:38:19 -07005093 if (ring_num == 0)
5094 cid = RX_CID;
5095 else
5096 cid = RX_RSS_CID + ring_num - 1;
5097
5098 rx_cid_addr = GET_CID_ADDR(cid);
5099
5100 bnx2_init_rxbd_rings(rxr->rx_desc_ring, rxr->rx_desc_mapping,
Michael Chan5d5d0012007-12-12 11:17:43 -08005101 bp->rx_buf_use_size, bp->rx_max_ring);
5102
Michael Chanbb4f98a2008-06-19 16:38:19 -07005103 bnx2_init_rx_context(bp, cid);
Michael Chan83e3fc82008-01-29 21:37:17 -08005104
5105 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
5106 val = REG_RD(bp, BNX2_MQ_MAP_L2_5);
5107 REG_WR(bp, BNX2_MQ_MAP_L2_5, val | BNX2_MQ_MAP_L2_5_ARM);
5108 }
5109
Michael Chan62a83132008-01-29 21:35:40 -08005110 bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_PG_BUF_SIZE, 0);
Michael Chan47bf4242007-12-12 11:19:12 -08005111 if (bp->rx_pg_ring_size) {
Michael Chanbb4f98a2008-06-19 16:38:19 -07005112 bnx2_init_rxbd_rings(rxr->rx_pg_desc_ring,
5113 rxr->rx_pg_desc_mapping,
Michael Chan47bf4242007-12-12 11:19:12 -08005114 PAGE_SIZE, bp->rx_max_pg_ring);
5115 val = (bp->rx_buf_use_size << 16) | PAGE_SIZE;
Michael Chan62a83132008-01-29 21:35:40 -08005116 bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_PG_BUF_SIZE, val);
5117 bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_RBDC_KEY,
Michael Chan5e9ad9e2008-06-19 16:43:17 -07005118 BNX2_L2CTX_RBDC_JUMBO_KEY - ring_num);
Michael Chan47bf4242007-12-12 11:19:12 -08005119
Michael Chanbb4f98a2008-06-19 16:38:19 -07005120 val = (u64) rxr->rx_pg_desc_mapping[0] >> 32;
Michael Chan62a83132008-01-29 21:35:40 -08005121 bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_NX_PG_BDHADDR_HI, val);
Michael Chan47bf4242007-12-12 11:19:12 -08005122
Michael Chanbb4f98a2008-06-19 16:38:19 -07005123 val = (u64) rxr->rx_pg_desc_mapping[0] & 0xffffffff;
Michael Chan62a83132008-01-29 21:35:40 -08005124 bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_NX_PG_BDHADDR_LO, val);
Michael Chan47bf4242007-12-12 11:19:12 -08005125
5126 if (CHIP_NUM(bp) == CHIP_NUM_5709)
5127 REG_WR(bp, BNX2_MQ_MAP_L2_3, BNX2_MQ_MAP_L2_3_DEFAULT);
5128 }
Michael Chanb6016b72005-05-26 13:03:09 -07005129
Michael Chanbb4f98a2008-06-19 16:38:19 -07005130 val = (u64) rxr->rx_desc_mapping[0] >> 32;
Michael Chan62a83132008-01-29 21:35:40 -08005131 bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_NX_BDHADDR_HI, val);
Michael Chanb6016b72005-05-26 13:03:09 -07005132
Michael Chanbb4f98a2008-06-19 16:38:19 -07005133 val = (u64) rxr->rx_desc_mapping[0] & 0xffffffff;
Michael Chan62a83132008-01-29 21:35:40 -08005134 bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_NX_BDHADDR_LO, val);
Michael Chanb6016b72005-05-26 13:03:09 -07005135
Michael Chanbb4f98a2008-06-19 16:38:19 -07005136 ring_prod = prod = rxr->rx_pg_prod;
Michael Chan47bf4242007-12-12 11:19:12 -08005137 for (i = 0; i < bp->rx_pg_ring_size; i++) {
Michael Chanbb4f98a2008-06-19 16:38:19 -07005138 if (bnx2_alloc_rx_page(bp, rxr, ring_prod) < 0)
Michael Chan47bf4242007-12-12 11:19:12 -08005139 break;
5140 prod = NEXT_RX_BD(prod);
5141 ring_prod = RX_PG_RING_IDX(prod);
5142 }
Michael Chanbb4f98a2008-06-19 16:38:19 -07005143 rxr->rx_pg_prod = prod;
Michael Chan47bf4242007-12-12 11:19:12 -08005144
Michael Chanbb4f98a2008-06-19 16:38:19 -07005145 ring_prod = prod = rxr->rx_prod;
Michael Chan236b6392006-03-20 17:49:02 -08005146 for (i = 0; i < bp->rx_ring_size; i++) {
Michael Chanbb4f98a2008-06-19 16:38:19 -07005147 if (bnx2_alloc_rx_skb(bp, rxr, ring_prod) < 0)
Michael Chanb6016b72005-05-26 13:03:09 -07005148 break;
Michael Chanb6016b72005-05-26 13:03:09 -07005149 prod = NEXT_RX_BD(prod);
5150 ring_prod = RX_RING_IDX(prod);
5151 }
Michael Chanbb4f98a2008-06-19 16:38:19 -07005152 rxr->rx_prod = prod;
Michael Chanb6016b72005-05-26 13:03:09 -07005153
Michael Chanbb4f98a2008-06-19 16:38:19 -07005154 rxr->rx_bidx_addr = MB_GET_CID_ADDR(cid) + BNX2_L2CTX_HOST_BDIDX;
5155 rxr->rx_bseq_addr = MB_GET_CID_ADDR(cid) + BNX2_L2CTX_HOST_BSEQ;
5156 rxr->rx_pg_bidx_addr = MB_GET_CID_ADDR(cid) + BNX2_L2CTX_HOST_PG_BDIDX;
Michael Chanb6016b72005-05-26 13:03:09 -07005157
Michael Chanbb4f98a2008-06-19 16:38:19 -07005158 REG_WR16(bp, rxr->rx_pg_bidx_addr, rxr->rx_pg_prod);
5159 REG_WR16(bp, rxr->rx_bidx_addr, prod);
5160
5161 REG_WR(bp, rxr->rx_bseq_addr, rxr->rx_prod_bseq);
Michael Chanb6016b72005-05-26 13:03:09 -07005162}
5163
Michael Chan35e90102008-06-19 16:37:42 -07005164static void
5165bnx2_init_all_rings(struct bnx2 *bp)
5166{
5167 int i;
Michael Chan5e9ad9e2008-06-19 16:43:17 -07005168 u32 val;
Michael Chan35e90102008-06-19 16:37:42 -07005169
5170 bnx2_clear_ring_states(bp);
5171
5172 REG_WR(bp, BNX2_TSCH_TSS_CFG, 0);
5173 for (i = 0; i < bp->num_tx_rings; i++)
5174 bnx2_init_tx_ring(bp, i);
5175
5176 if (bp->num_tx_rings > 1)
5177 REG_WR(bp, BNX2_TSCH_TSS_CFG, ((bp->num_tx_rings - 1) << 24) |
5178 (TX_TSS_CID << 7));
5179
Michael Chan5e9ad9e2008-06-19 16:43:17 -07005180 REG_WR(bp, BNX2_RLUP_RSS_CONFIG, 0);
5181 bnx2_reg_wr_ind(bp, BNX2_RXP_SCRATCH_RSS_TBL_SZ, 0);
5182
Michael Chanbb4f98a2008-06-19 16:38:19 -07005183 for (i = 0; i < bp->num_rx_rings; i++)
5184 bnx2_init_rx_ring(bp, i);
Michael Chan5e9ad9e2008-06-19 16:43:17 -07005185
5186 if (bp->num_rx_rings > 1) {
5187 u32 tbl_32;
5188 u8 *tbl = (u8 *) &tbl_32;
5189
5190 bnx2_reg_wr_ind(bp, BNX2_RXP_SCRATCH_RSS_TBL_SZ,
5191 BNX2_RXP_SCRATCH_RSS_TBL_MAX_ENTRIES);
5192
5193 for (i = 0; i < BNX2_RXP_SCRATCH_RSS_TBL_MAX_ENTRIES; i++) {
5194 tbl[i % 4] = i % (bp->num_rx_rings - 1);
5195 if ((i % 4) == 3)
5196 bnx2_reg_wr_ind(bp,
5197 BNX2_RXP_SCRATCH_RSS_TBL + i,
5198 cpu_to_be32(tbl_32));
5199 }
5200
5201 val = BNX2_RLUP_RSS_CONFIG_IPV4_RSS_TYPE_ALL_XI |
5202 BNX2_RLUP_RSS_CONFIG_IPV6_RSS_TYPE_ALL_XI;
5203
5204 REG_WR(bp, BNX2_RLUP_RSS_CONFIG, val);
5205
5206 }
Michael Chan35e90102008-06-19 16:37:42 -07005207}
5208
Michael Chan5d5d0012007-12-12 11:17:43 -08005209static u32 bnx2_find_max_ring(u32 ring_size, u32 max_size)
Michael Chan13daffa2006-03-20 17:49:20 -08005210{
Michael Chan5d5d0012007-12-12 11:17:43 -08005211 u32 max, num_rings = 1;
Michael Chan13daffa2006-03-20 17:49:20 -08005212
Michael Chan5d5d0012007-12-12 11:17:43 -08005213 while (ring_size > MAX_RX_DESC_CNT) {
5214 ring_size -= MAX_RX_DESC_CNT;
Michael Chan13daffa2006-03-20 17:49:20 -08005215 num_rings++;
5216 }
5217 /* round to next power of 2 */
Michael Chan5d5d0012007-12-12 11:17:43 -08005218 max = max_size;
Michael Chan13daffa2006-03-20 17:49:20 -08005219 while ((max & num_rings) == 0)
5220 max >>= 1;
5221
5222 if (num_rings != max)
5223 max <<= 1;
5224
Michael Chan5d5d0012007-12-12 11:17:43 -08005225 return max;
5226}
5227
5228static void
5229bnx2_set_rx_ring_size(struct bnx2 *bp, u32 size)
5230{
Michael Chan84eaa182007-12-12 11:19:57 -08005231 u32 rx_size, rx_space, jumbo_size;
Michael Chan5d5d0012007-12-12 11:17:43 -08005232
5233 /* 8 for CRC and VLAN */
Benjamin Lid89cb6a2008-05-16 22:18:57 -07005234 rx_size = bp->dev->mtu + ETH_HLEN + BNX2_RX_OFFSET + 8;
Michael Chan5d5d0012007-12-12 11:17:43 -08005235
Michael Chan84eaa182007-12-12 11:19:57 -08005236 rx_space = SKB_DATA_ALIGN(rx_size + BNX2_RX_ALIGN) + NET_SKB_PAD +
5237 sizeof(struct skb_shared_info);
5238
Benjamin Li601d3d12008-05-16 22:19:35 -07005239 bp->rx_copy_thresh = BNX2_RX_COPY_THRESH;
Michael Chan47bf4242007-12-12 11:19:12 -08005240 bp->rx_pg_ring_size = 0;
5241 bp->rx_max_pg_ring = 0;
5242 bp->rx_max_pg_ring_idx = 0;
David S. Millerf86e82f2008-01-21 17:15:40 -08005243 if ((rx_space > PAGE_SIZE) && !(bp->flags & BNX2_FLAG_JUMBO_BROKEN)) {
Michael Chan84eaa182007-12-12 11:19:57 -08005244 int pages = PAGE_ALIGN(bp->dev->mtu - 40) >> PAGE_SHIFT;
5245
5246 jumbo_size = size * pages;
5247 if (jumbo_size > MAX_TOTAL_RX_PG_DESC_CNT)
5248 jumbo_size = MAX_TOTAL_RX_PG_DESC_CNT;
5249
5250 bp->rx_pg_ring_size = jumbo_size;
5251 bp->rx_max_pg_ring = bnx2_find_max_ring(jumbo_size,
5252 MAX_RX_PG_RINGS);
5253 bp->rx_max_pg_ring_idx = (bp->rx_max_pg_ring * RX_DESC_CNT) - 1;
Benjamin Li601d3d12008-05-16 22:19:35 -07005254 rx_size = BNX2_RX_COPY_THRESH + BNX2_RX_OFFSET;
Michael Chan84eaa182007-12-12 11:19:57 -08005255 bp->rx_copy_thresh = 0;
5256 }
Michael Chan5d5d0012007-12-12 11:17:43 -08005257
5258 bp->rx_buf_use_size = rx_size;
5259 /* hw alignment */
5260 bp->rx_buf_size = bp->rx_buf_use_size + BNX2_RX_ALIGN;
Benjamin Lid89cb6a2008-05-16 22:18:57 -07005261 bp->rx_jumbo_thresh = rx_size - BNX2_RX_OFFSET;
Michael Chan5d5d0012007-12-12 11:17:43 -08005262 bp->rx_ring_size = size;
5263 bp->rx_max_ring = bnx2_find_max_ring(size, MAX_RX_RINGS);
Michael Chan13daffa2006-03-20 17:49:20 -08005264 bp->rx_max_ring_idx = (bp->rx_max_ring * RX_DESC_CNT) - 1;
5265}
5266
5267static void
Michael Chanb6016b72005-05-26 13:03:09 -07005268bnx2_free_tx_skbs(struct bnx2 *bp)
5269{
5270 int i;
5271
Michael Chan35e90102008-06-19 16:37:42 -07005272 for (i = 0; i < bp->num_tx_rings; i++) {
5273 struct bnx2_napi *bnapi = &bp->bnx2_napi[i];
5274 struct bnx2_tx_ring_info *txr = &bnapi->tx_ring;
5275 int j;
Michael Chanb6016b72005-05-26 13:03:09 -07005276
Michael Chan35e90102008-06-19 16:37:42 -07005277 if (txr->tx_buf_ring == NULL)
Michael Chanb6016b72005-05-26 13:03:09 -07005278 continue;
Michael Chanb6016b72005-05-26 13:03:09 -07005279
Michael Chan35e90102008-06-19 16:37:42 -07005280 for (j = 0; j < TX_DESC_CNT; ) {
Benjamin Li3d16af82008-10-09 12:26:41 -07005281 struct sw_tx_bd *tx_buf = &txr->tx_buf_ring[j];
Michael Chan35e90102008-06-19 16:37:42 -07005282 struct sk_buff *skb = tx_buf->skb;
Michael Chan35e90102008-06-19 16:37:42 -07005283
5284 if (skb == NULL) {
5285 j++;
5286 continue;
5287 }
5288
Benjamin Li3d16af82008-10-09 12:26:41 -07005289 skb_dma_unmap(&bp->pdev->dev, skb, DMA_TO_DEVICE);
Michael Chanb6016b72005-05-26 13:03:09 -07005290
Michael Chan35e90102008-06-19 16:37:42 -07005291 tx_buf->skb = NULL;
Michael Chanb6016b72005-05-26 13:03:09 -07005292
Benjamin Li3d16af82008-10-09 12:26:41 -07005293 j += skb_shinfo(skb)->nr_frags + 1;
Michael Chan35e90102008-06-19 16:37:42 -07005294 dev_kfree_skb(skb);
Michael Chanb6016b72005-05-26 13:03:09 -07005295 }
Michael Chanb6016b72005-05-26 13:03:09 -07005296 }
Michael Chanb6016b72005-05-26 13:03:09 -07005297}
5298
5299static void
5300bnx2_free_rx_skbs(struct bnx2 *bp)
5301{
5302 int i;
5303
Michael Chanbb4f98a2008-06-19 16:38:19 -07005304 for (i = 0; i < bp->num_rx_rings; i++) {
5305 struct bnx2_napi *bnapi = &bp->bnx2_napi[i];
5306 struct bnx2_rx_ring_info *rxr = &bnapi->rx_ring;
5307 int j;
Michael Chanb6016b72005-05-26 13:03:09 -07005308
Michael Chanbb4f98a2008-06-19 16:38:19 -07005309 if (rxr->rx_buf_ring == NULL)
5310 return;
Michael Chanb6016b72005-05-26 13:03:09 -07005311
Michael Chanbb4f98a2008-06-19 16:38:19 -07005312 for (j = 0; j < bp->rx_max_ring_idx; j++) {
5313 struct sw_bd *rx_buf = &rxr->rx_buf_ring[j];
5314 struct sk_buff *skb = rx_buf->skb;
Michael Chanb6016b72005-05-26 13:03:09 -07005315
Michael Chanbb4f98a2008-06-19 16:38:19 -07005316 if (skb == NULL)
5317 continue;
Michael Chanb6016b72005-05-26 13:03:09 -07005318
Michael Chanbb4f98a2008-06-19 16:38:19 -07005319 pci_unmap_single(bp->pdev,
5320 pci_unmap_addr(rx_buf, mapping),
5321 bp->rx_buf_use_size,
5322 PCI_DMA_FROMDEVICE);
Michael Chanb6016b72005-05-26 13:03:09 -07005323
Michael Chanbb4f98a2008-06-19 16:38:19 -07005324 rx_buf->skb = NULL;
5325
5326 dev_kfree_skb(skb);
5327 }
5328 for (j = 0; j < bp->rx_max_pg_ring_idx; j++)
5329 bnx2_free_rx_page(bp, rxr, j);
Michael Chanb6016b72005-05-26 13:03:09 -07005330 }
5331}
5332
5333static void
5334bnx2_free_skbs(struct bnx2 *bp)
5335{
5336 bnx2_free_tx_skbs(bp);
5337 bnx2_free_rx_skbs(bp);
5338}
5339
5340static int
5341bnx2_reset_nic(struct bnx2 *bp, u32 reset_code)
5342{
5343 int rc;
5344
5345 rc = bnx2_reset_chip(bp, reset_code);
5346 bnx2_free_skbs(bp);
5347 if (rc)
5348 return rc;
5349
Michael Chanfba9fe92006-06-12 22:21:25 -07005350 if ((rc = bnx2_init_chip(bp)) != 0)
5351 return rc;
5352
Michael Chan35e90102008-06-19 16:37:42 -07005353 bnx2_init_all_rings(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07005354 return 0;
5355}
5356
5357static int
Michael Chan9a120bc2008-05-16 22:17:45 -07005358bnx2_init_nic(struct bnx2 *bp, int reset_phy)
Michael Chanb6016b72005-05-26 13:03:09 -07005359{
5360 int rc;
5361
5362 if ((rc = bnx2_reset_nic(bp, BNX2_DRV_MSG_CODE_RESET)) != 0)
5363 return rc;
5364
Michael Chan80be4432006-11-19 14:07:28 -08005365 spin_lock_bh(&bp->phy_lock);
Michael Chan9a120bc2008-05-16 22:17:45 -07005366 bnx2_init_phy(bp, reset_phy);
Michael Chanb6016b72005-05-26 13:03:09 -07005367 bnx2_set_link(bp);
Michael Chan543a8272008-05-02 16:56:44 -07005368 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
5369 bnx2_remote_phy_event(bp);
Michael Chan0d8a6572007-07-07 22:49:43 -07005370 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07005371 return 0;
5372}
5373
5374static int
Michael Chan74bf4ba2008-10-09 12:21:08 -07005375bnx2_shutdown_chip(struct bnx2 *bp)
5376{
5377 u32 reset_code;
5378
5379 if (bp->flags & BNX2_FLAG_NO_WOL)
5380 reset_code = BNX2_DRV_MSG_CODE_UNLOAD_LNK_DN;
5381 else if (bp->wol)
5382 reset_code = BNX2_DRV_MSG_CODE_SUSPEND_WOL;
5383 else
5384 reset_code = BNX2_DRV_MSG_CODE_SUSPEND_NO_WOL;
5385
5386 return bnx2_reset_chip(bp, reset_code);
5387}
5388
5389static int
Michael Chanb6016b72005-05-26 13:03:09 -07005390bnx2_test_registers(struct bnx2 *bp)
5391{
5392 int ret;
Michael Chan5bae30c2007-05-03 13:18:46 -07005393 int i, is_5709;
Arjan van de Venf71e1302006-03-03 21:33:57 -05005394 static const struct {
Michael Chanb6016b72005-05-26 13:03:09 -07005395 u16 offset;
5396 u16 flags;
Michael Chan5bae30c2007-05-03 13:18:46 -07005397#define BNX2_FL_NOT_5709 1
Michael Chanb6016b72005-05-26 13:03:09 -07005398 u32 rw_mask;
5399 u32 ro_mask;
5400 } reg_tbl[] = {
5401 { 0x006c, 0, 0x00000000, 0x0000003f },
5402 { 0x0090, 0, 0xffffffff, 0x00000000 },
5403 { 0x0094, 0, 0x00000000, 0x00000000 },
5404
Michael Chan5bae30c2007-05-03 13:18:46 -07005405 { 0x0404, BNX2_FL_NOT_5709, 0x00003f00, 0x00000000 },
5406 { 0x0418, BNX2_FL_NOT_5709, 0x00000000, 0xffffffff },
5407 { 0x041c, BNX2_FL_NOT_5709, 0x00000000, 0xffffffff },
5408 { 0x0420, BNX2_FL_NOT_5709, 0x00000000, 0x80ffffff },
5409 { 0x0424, BNX2_FL_NOT_5709, 0x00000000, 0x00000000 },
5410 { 0x0428, BNX2_FL_NOT_5709, 0x00000000, 0x00000001 },
5411 { 0x0450, BNX2_FL_NOT_5709, 0x00000000, 0x0000ffff },
5412 { 0x0454, BNX2_FL_NOT_5709, 0x00000000, 0xffffffff },
5413 { 0x0458, BNX2_FL_NOT_5709, 0x00000000, 0xffffffff },
Michael Chanb6016b72005-05-26 13:03:09 -07005414
Michael Chan5bae30c2007-05-03 13:18:46 -07005415 { 0x0808, BNX2_FL_NOT_5709, 0x00000000, 0xffffffff },
5416 { 0x0854, BNX2_FL_NOT_5709, 0x00000000, 0xffffffff },
5417 { 0x0868, BNX2_FL_NOT_5709, 0x00000000, 0x77777777 },
5418 { 0x086c, BNX2_FL_NOT_5709, 0x00000000, 0x77777777 },
5419 { 0x0870, BNX2_FL_NOT_5709, 0x00000000, 0x77777777 },
5420 { 0x0874, BNX2_FL_NOT_5709, 0x00000000, 0x77777777 },
Michael Chanb6016b72005-05-26 13:03:09 -07005421
Michael Chan5bae30c2007-05-03 13:18:46 -07005422 { 0x0c00, BNX2_FL_NOT_5709, 0x00000000, 0x00000001 },
5423 { 0x0c04, BNX2_FL_NOT_5709, 0x00000000, 0x03ff0001 },
5424 { 0x0c08, BNX2_FL_NOT_5709, 0x0f0ff073, 0x00000000 },
Michael Chanb6016b72005-05-26 13:03:09 -07005425
5426 { 0x1000, 0, 0x00000000, 0x00000001 },
Michael Chan15b169c2008-05-02 16:57:08 -07005427 { 0x1004, BNX2_FL_NOT_5709, 0x00000000, 0x000f0001 },
Michael Chanb6016b72005-05-26 13:03:09 -07005428
5429 { 0x1408, 0, 0x01c00800, 0x00000000 },
5430 { 0x149c, 0, 0x8000ffff, 0x00000000 },
5431 { 0x14a8, 0, 0x00000000, 0x000001ff },
Michael Chan5b0c76a2005-11-04 08:45:49 -08005432 { 0x14ac, 0, 0x0fffffff, 0x10000000 },
Michael Chanb6016b72005-05-26 13:03:09 -07005433 { 0x14b0, 0, 0x00000002, 0x00000001 },
5434 { 0x14b8, 0, 0x00000000, 0x00000000 },
5435 { 0x14c0, 0, 0x00000000, 0x00000009 },
5436 { 0x14c4, 0, 0x00003fff, 0x00000000 },
5437 { 0x14cc, 0, 0x00000000, 0x00000001 },
5438 { 0x14d0, 0, 0xffffffff, 0x00000000 },
Michael Chanb6016b72005-05-26 13:03:09 -07005439
5440 { 0x1800, 0, 0x00000000, 0x00000001 },
5441 { 0x1804, 0, 0x00000000, 0x00000003 },
Michael Chanb6016b72005-05-26 13:03:09 -07005442
5443 { 0x2800, 0, 0x00000000, 0x00000001 },
5444 { 0x2804, 0, 0x00000000, 0x00003f01 },
5445 { 0x2808, 0, 0x0f3f3f03, 0x00000000 },
5446 { 0x2810, 0, 0xffff0000, 0x00000000 },
5447 { 0x2814, 0, 0xffff0000, 0x00000000 },
5448 { 0x2818, 0, 0xffff0000, 0x00000000 },
5449 { 0x281c, 0, 0xffff0000, 0x00000000 },
5450 { 0x2834, 0, 0xffffffff, 0x00000000 },
5451 { 0x2840, 0, 0x00000000, 0xffffffff },
5452 { 0x2844, 0, 0x00000000, 0xffffffff },
5453 { 0x2848, 0, 0xffffffff, 0x00000000 },
5454 { 0x284c, 0, 0xf800f800, 0x07ff07ff },
5455
5456 { 0x2c00, 0, 0x00000000, 0x00000011 },
5457 { 0x2c04, 0, 0x00000000, 0x00030007 },
5458
Michael Chanb6016b72005-05-26 13:03:09 -07005459 { 0x3c00, 0, 0x00000000, 0x00000001 },
5460 { 0x3c04, 0, 0x00000000, 0x00070000 },
5461 { 0x3c08, 0, 0x00007f71, 0x07f00000 },
5462 { 0x3c0c, 0, 0x1f3ffffc, 0x00000000 },
5463 { 0x3c10, 0, 0xffffffff, 0x00000000 },
5464 { 0x3c14, 0, 0x00000000, 0xffffffff },
5465 { 0x3c18, 0, 0x00000000, 0xffffffff },
5466 { 0x3c1c, 0, 0xfffff000, 0x00000000 },
5467 { 0x3c20, 0, 0xffffff00, 0x00000000 },
Michael Chanb6016b72005-05-26 13:03:09 -07005468
5469 { 0x5004, 0, 0x00000000, 0x0000007f },
5470 { 0x5008, 0, 0x0f0007ff, 0x00000000 },
Michael Chanb6016b72005-05-26 13:03:09 -07005471
Michael Chanb6016b72005-05-26 13:03:09 -07005472 { 0x5c00, 0, 0x00000000, 0x00000001 },
5473 { 0x5c04, 0, 0x00000000, 0x0003000f },
5474 { 0x5c08, 0, 0x00000003, 0x00000000 },
5475 { 0x5c0c, 0, 0x0000fff8, 0x00000000 },
5476 { 0x5c10, 0, 0x00000000, 0xffffffff },
5477 { 0x5c80, 0, 0x00000000, 0x0f7113f1 },
5478 { 0x5c84, 0, 0x00000000, 0x0000f333 },
5479 { 0x5c88, 0, 0x00000000, 0x00077373 },
5480 { 0x5c8c, 0, 0x00000000, 0x0007f737 },
5481
5482 { 0x6808, 0, 0x0000ff7f, 0x00000000 },
5483 { 0x680c, 0, 0xffffffff, 0x00000000 },
5484 { 0x6810, 0, 0xffffffff, 0x00000000 },
5485 { 0x6814, 0, 0xffffffff, 0x00000000 },
5486 { 0x6818, 0, 0xffffffff, 0x00000000 },
5487 { 0x681c, 0, 0xffffffff, 0x00000000 },
5488 { 0x6820, 0, 0x00ff00ff, 0x00000000 },
5489 { 0x6824, 0, 0x00ff00ff, 0x00000000 },
5490 { 0x6828, 0, 0x00ff00ff, 0x00000000 },
5491 { 0x682c, 0, 0x03ff03ff, 0x00000000 },
5492 { 0x6830, 0, 0x03ff03ff, 0x00000000 },
5493 { 0x6834, 0, 0x03ff03ff, 0x00000000 },
5494 { 0x6838, 0, 0x03ff03ff, 0x00000000 },
5495 { 0x683c, 0, 0x0000ffff, 0x00000000 },
5496 { 0x6840, 0, 0x00000ff0, 0x00000000 },
5497 { 0x6844, 0, 0x00ffff00, 0x00000000 },
5498 { 0x684c, 0, 0xffffffff, 0x00000000 },
5499 { 0x6850, 0, 0x7f7f7f7f, 0x00000000 },
5500 { 0x6854, 0, 0x7f7f7f7f, 0x00000000 },
5501 { 0x6858, 0, 0x7f7f7f7f, 0x00000000 },
5502 { 0x685c, 0, 0x7f7f7f7f, 0x00000000 },
5503 { 0x6908, 0, 0x00000000, 0x0001ff0f },
5504 { 0x690c, 0, 0x00000000, 0x0ffe00f0 },
5505
5506 { 0xffff, 0, 0x00000000, 0x00000000 },
5507 };
5508
5509 ret = 0;
Michael Chan5bae30c2007-05-03 13:18:46 -07005510 is_5709 = 0;
5511 if (CHIP_NUM(bp) == CHIP_NUM_5709)
5512 is_5709 = 1;
5513
Michael Chanb6016b72005-05-26 13:03:09 -07005514 for (i = 0; reg_tbl[i].offset != 0xffff; i++) {
5515 u32 offset, rw_mask, ro_mask, save_val, val;
Michael Chan5bae30c2007-05-03 13:18:46 -07005516 u16 flags = reg_tbl[i].flags;
5517
5518 if (is_5709 && (flags & BNX2_FL_NOT_5709))
5519 continue;
Michael Chanb6016b72005-05-26 13:03:09 -07005520
5521 offset = (u32) reg_tbl[i].offset;
5522 rw_mask = reg_tbl[i].rw_mask;
5523 ro_mask = reg_tbl[i].ro_mask;
5524
Peter Hagervall14ab9b82005-08-10 14:18:16 -07005525 save_val = readl(bp->regview + offset);
Michael Chanb6016b72005-05-26 13:03:09 -07005526
Peter Hagervall14ab9b82005-08-10 14:18:16 -07005527 writel(0, bp->regview + offset);
Michael Chanb6016b72005-05-26 13:03:09 -07005528
Peter Hagervall14ab9b82005-08-10 14:18:16 -07005529 val = readl(bp->regview + offset);
Michael Chanb6016b72005-05-26 13:03:09 -07005530 if ((val & rw_mask) != 0) {
5531 goto reg_test_err;
5532 }
5533
5534 if ((val & ro_mask) != (save_val & ro_mask)) {
5535 goto reg_test_err;
5536 }
5537
Peter Hagervall14ab9b82005-08-10 14:18:16 -07005538 writel(0xffffffff, bp->regview + offset);
Michael Chanb6016b72005-05-26 13:03:09 -07005539
Peter Hagervall14ab9b82005-08-10 14:18:16 -07005540 val = readl(bp->regview + offset);
Michael Chanb6016b72005-05-26 13:03:09 -07005541 if ((val & rw_mask) != rw_mask) {
5542 goto reg_test_err;
5543 }
5544
5545 if ((val & ro_mask) != (save_val & ro_mask)) {
5546 goto reg_test_err;
5547 }
5548
Peter Hagervall14ab9b82005-08-10 14:18:16 -07005549 writel(save_val, bp->regview + offset);
Michael Chanb6016b72005-05-26 13:03:09 -07005550 continue;
5551
5552reg_test_err:
Peter Hagervall14ab9b82005-08-10 14:18:16 -07005553 writel(save_val, bp->regview + offset);
Michael Chanb6016b72005-05-26 13:03:09 -07005554 ret = -ENODEV;
5555 break;
5556 }
5557 return ret;
5558}
5559
5560static int
5561bnx2_do_mem_test(struct bnx2 *bp, u32 start, u32 size)
5562{
Arjan van de Venf71e1302006-03-03 21:33:57 -05005563 static const u32 test_pattern[] = { 0x00000000, 0xffffffff, 0x55555555,
Michael Chanb6016b72005-05-26 13:03:09 -07005564 0xaaaaaaaa , 0xaa55aa55, 0x55aa55aa };
5565 int i;
5566
5567 for (i = 0; i < sizeof(test_pattern) / 4; i++) {
5568 u32 offset;
5569
5570 for (offset = 0; offset < size; offset += 4) {
5571
Michael Chan2726d6e2008-01-29 21:35:05 -08005572 bnx2_reg_wr_ind(bp, start + offset, test_pattern[i]);
Michael Chanb6016b72005-05-26 13:03:09 -07005573
Michael Chan2726d6e2008-01-29 21:35:05 -08005574 if (bnx2_reg_rd_ind(bp, start + offset) !=
Michael Chanb6016b72005-05-26 13:03:09 -07005575 test_pattern[i]) {
5576 return -ENODEV;
5577 }
5578 }
5579 }
5580 return 0;
5581}
5582
5583static int
5584bnx2_test_memory(struct bnx2 *bp)
5585{
5586 int ret = 0;
5587 int i;
Michael Chan5bae30c2007-05-03 13:18:46 -07005588 static struct mem_entry {
Michael Chanb6016b72005-05-26 13:03:09 -07005589 u32 offset;
5590 u32 len;
Michael Chan5bae30c2007-05-03 13:18:46 -07005591 } mem_tbl_5706[] = {
Michael Chanb6016b72005-05-26 13:03:09 -07005592 { 0x60000, 0x4000 },
Michael Chan5b0c76a2005-11-04 08:45:49 -08005593 { 0xa0000, 0x3000 },
Michael Chanb6016b72005-05-26 13:03:09 -07005594 { 0xe0000, 0x4000 },
5595 { 0x120000, 0x4000 },
5596 { 0x1a0000, 0x4000 },
5597 { 0x160000, 0x4000 },
5598 { 0xffffffff, 0 },
Michael Chan5bae30c2007-05-03 13:18:46 -07005599 },
5600 mem_tbl_5709[] = {
5601 { 0x60000, 0x4000 },
5602 { 0xa0000, 0x3000 },
5603 { 0xe0000, 0x4000 },
5604 { 0x120000, 0x4000 },
5605 { 0x1a0000, 0x4000 },
5606 { 0xffffffff, 0 },
Michael Chanb6016b72005-05-26 13:03:09 -07005607 };
Michael Chan5bae30c2007-05-03 13:18:46 -07005608 struct mem_entry *mem_tbl;
5609
5610 if (CHIP_NUM(bp) == CHIP_NUM_5709)
5611 mem_tbl = mem_tbl_5709;
5612 else
5613 mem_tbl = mem_tbl_5706;
Michael Chanb6016b72005-05-26 13:03:09 -07005614
5615 for (i = 0; mem_tbl[i].offset != 0xffffffff; i++) {
5616 if ((ret = bnx2_do_mem_test(bp, mem_tbl[i].offset,
5617 mem_tbl[i].len)) != 0) {
5618 return ret;
5619 }
5620 }
Jeff Garzik6aa20a22006-09-13 13:24:59 -04005621
Michael Chanb6016b72005-05-26 13:03:09 -07005622 return ret;
5623}
5624
Michael Chanbc5a0692006-01-23 16:13:22 -08005625#define BNX2_MAC_LOOPBACK 0
5626#define BNX2_PHY_LOOPBACK 1
5627
Michael Chanb6016b72005-05-26 13:03:09 -07005628static int
Michael Chanbc5a0692006-01-23 16:13:22 -08005629bnx2_run_loopback(struct bnx2 *bp, int loopback_mode)
Michael Chanb6016b72005-05-26 13:03:09 -07005630{
5631 unsigned int pkt_size, num_pkts, i;
5632 struct sk_buff *skb, *rx_skb;
5633 unsigned char *packet;
Michael Chanbc5a0692006-01-23 16:13:22 -08005634 u16 rx_start_idx, rx_idx;
Michael Chanb6016b72005-05-26 13:03:09 -07005635 dma_addr_t map;
5636 struct tx_bd *txbd;
5637 struct sw_bd *rx_buf;
5638 struct l2_fhdr *rx_hdr;
5639 int ret = -ENODEV;
Michael Chanc76c0472007-12-20 20:01:19 -08005640 struct bnx2_napi *bnapi = &bp->bnx2_napi[0], *tx_napi;
Michael Chan35e90102008-06-19 16:37:42 -07005641 struct bnx2_tx_ring_info *txr = &bnapi->tx_ring;
Michael Chanbb4f98a2008-06-19 16:38:19 -07005642 struct bnx2_rx_ring_info *rxr = &bnapi->rx_ring;
Michael Chanc76c0472007-12-20 20:01:19 -08005643
5644 tx_napi = bnapi;
Michael Chanb6016b72005-05-26 13:03:09 -07005645
Michael Chan35e90102008-06-19 16:37:42 -07005646 txr = &tx_napi->tx_ring;
Michael Chanbb4f98a2008-06-19 16:38:19 -07005647 rxr = &bnapi->rx_ring;
Michael Chanbc5a0692006-01-23 16:13:22 -08005648 if (loopback_mode == BNX2_MAC_LOOPBACK) {
5649 bp->loopback = MAC_LOOPBACK;
5650 bnx2_set_mac_loopback(bp);
5651 }
5652 else if (loopback_mode == BNX2_PHY_LOOPBACK) {
Michael Chan583c28e2008-01-21 19:51:35 -08005653 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
Michael Chan489310a2007-10-10 16:16:31 -07005654 return 0;
5655
Michael Chan80be4432006-11-19 14:07:28 -08005656 bp->loopback = PHY_LOOPBACK;
Michael Chanbc5a0692006-01-23 16:13:22 -08005657 bnx2_set_phy_loopback(bp);
5658 }
5659 else
5660 return -EINVAL;
Michael Chanb6016b72005-05-26 13:03:09 -07005661
Michael Chan84eaa182007-12-12 11:19:57 -08005662 pkt_size = min(bp->dev->mtu + ETH_HLEN, bp->rx_jumbo_thresh - 4);
Michael Chan932f3772006-08-15 01:39:36 -07005663 skb = netdev_alloc_skb(bp->dev, pkt_size);
John W. Linvilleb6cbc3b62005-11-10 12:58:00 -08005664 if (!skb)
5665 return -ENOMEM;
Michael Chanb6016b72005-05-26 13:03:09 -07005666 packet = skb_put(skb, pkt_size);
Michael Chan66342922006-12-14 15:57:04 -08005667 memcpy(packet, bp->dev->dev_addr, 6);
Michael Chanb6016b72005-05-26 13:03:09 -07005668 memset(packet + 6, 0x0, 8);
5669 for (i = 14; i < pkt_size; i++)
5670 packet[i] = (unsigned char) (i & 0xff);
5671
Benjamin Li3d16af82008-10-09 12:26:41 -07005672 if (skb_dma_map(&bp->pdev->dev, skb, DMA_TO_DEVICE)) {
5673 dev_kfree_skb(skb);
5674 return -EIO;
5675 }
5676 map = skb_shinfo(skb)->dma_maps[0];
Michael Chanb6016b72005-05-26 13:03:09 -07005677
Michael Chanbf5295b2006-03-23 01:11:56 -08005678 REG_WR(bp, BNX2_HC_COMMAND,
5679 bp->hc_cmd | BNX2_HC_COMMAND_COAL_NOW_WO_INT);
5680
Michael Chanb6016b72005-05-26 13:03:09 -07005681 REG_RD(bp, BNX2_HC_COMMAND);
5682
5683 udelay(5);
Michael Chan35efa7c2007-12-20 19:56:37 -08005684 rx_start_idx = bnx2_get_hw_rx_cons(bnapi);
Michael Chanb6016b72005-05-26 13:03:09 -07005685
Michael Chanb6016b72005-05-26 13:03:09 -07005686 num_pkts = 0;
5687
Michael Chan35e90102008-06-19 16:37:42 -07005688 txbd = &txr->tx_desc_ring[TX_RING_IDX(txr->tx_prod)];
Michael Chanb6016b72005-05-26 13:03:09 -07005689
5690 txbd->tx_bd_haddr_hi = (u64) map >> 32;
5691 txbd->tx_bd_haddr_lo = (u64) map & 0xffffffff;
5692 txbd->tx_bd_mss_nbytes = pkt_size;
5693 txbd->tx_bd_vlan_tag_flags = TX_BD_FLAGS_START | TX_BD_FLAGS_END;
5694
5695 num_pkts++;
Michael Chan35e90102008-06-19 16:37:42 -07005696 txr->tx_prod = NEXT_TX_BD(txr->tx_prod);
5697 txr->tx_prod_bseq += pkt_size;
Michael Chanb6016b72005-05-26 13:03:09 -07005698
Michael Chan35e90102008-06-19 16:37:42 -07005699 REG_WR16(bp, txr->tx_bidx_addr, txr->tx_prod);
5700 REG_WR(bp, txr->tx_bseq_addr, txr->tx_prod_bseq);
Michael Chanb6016b72005-05-26 13:03:09 -07005701
5702 udelay(100);
5703
Michael Chanbf5295b2006-03-23 01:11:56 -08005704 REG_WR(bp, BNX2_HC_COMMAND,
5705 bp->hc_cmd | BNX2_HC_COMMAND_COAL_NOW_WO_INT);
5706
Michael Chanb6016b72005-05-26 13:03:09 -07005707 REG_RD(bp, BNX2_HC_COMMAND);
5708
5709 udelay(5);
5710
Benjamin Li3d16af82008-10-09 12:26:41 -07005711 skb_dma_unmap(&bp->pdev->dev, skb, DMA_TO_DEVICE);
Michael Chan745720e2006-06-29 12:37:41 -07005712 dev_kfree_skb(skb);
Michael Chanb6016b72005-05-26 13:03:09 -07005713
Michael Chan35e90102008-06-19 16:37:42 -07005714 if (bnx2_get_hw_tx_cons(tx_napi) != txr->tx_prod)
Michael Chanb6016b72005-05-26 13:03:09 -07005715 goto loopback_test_done;
Michael Chanb6016b72005-05-26 13:03:09 -07005716
Michael Chan35efa7c2007-12-20 19:56:37 -08005717 rx_idx = bnx2_get_hw_rx_cons(bnapi);
Michael Chanb6016b72005-05-26 13:03:09 -07005718 if (rx_idx != rx_start_idx + num_pkts) {
5719 goto loopback_test_done;
5720 }
5721
Michael Chanbb4f98a2008-06-19 16:38:19 -07005722 rx_buf = &rxr->rx_buf_ring[rx_start_idx];
Michael Chanb6016b72005-05-26 13:03:09 -07005723 rx_skb = rx_buf->skb;
5724
5725 rx_hdr = (struct l2_fhdr *) rx_skb->data;
Benjamin Lid89cb6a2008-05-16 22:18:57 -07005726 skb_reserve(rx_skb, BNX2_RX_OFFSET);
Michael Chanb6016b72005-05-26 13:03:09 -07005727
5728 pci_dma_sync_single_for_cpu(bp->pdev,
5729 pci_unmap_addr(rx_buf, mapping),
5730 bp->rx_buf_size, PCI_DMA_FROMDEVICE);
5731
Michael Chanade2bfe2006-01-23 16:09:51 -08005732 if (rx_hdr->l2_fhdr_status &
Michael Chanb6016b72005-05-26 13:03:09 -07005733 (L2_FHDR_ERRORS_BAD_CRC |
5734 L2_FHDR_ERRORS_PHY_DECODE |
5735 L2_FHDR_ERRORS_ALIGNMENT |
5736 L2_FHDR_ERRORS_TOO_SHORT |
5737 L2_FHDR_ERRORS_GIANT_FRAME)) {
5738
5739 goto loopback_test_done;
5740 }
5741
5742 if ((rx_hdr->l2_fhdr_pkt_len - 4) != pkt_size) {
5743 goto loopback_test_done;
5744 }
5745
5746 for (i = 14; i < pkt_size; i++) {
5747 if (*(rx_skb->data + i) != (unsigned char) (i & 0xff)) {
5748 goto loopback_test_done;
5749 }
5750 }
5751
5752 ret = 0;
5753
5754loopback_test_done:
5755 bp->loopback = 0;
5756 return ret;
5757}
5758
Michael Chanbc5a0692006-01-23 16:13:22 -08005759#define BNX2_MAC_LOOPBACK_FAILED 1
5760#define BNX2_PHY_LOOPBACK_FAILED 2
5761#define BNX2_LOOPBACK_FAILED (BNX2_MAC_LOOPBACK_FAILED | \
5762 BNX2_PHY_LOOPBACK_FAILED)
5763
5764static int
5765bnx2_test_loopback(struct bnx2 *bp)
5766{
5767 int rc = 0;
5768
5769 if (!netif_running(bp->dev))
5770 return BNX2_LOOPBACK_FAILED;
5771
5772 bnx2_reset_nic(bp, BNX2_DRV_MSG_CODE_RESET);
5773 spin_lock_bh(&bp->phy_lock);
Michael Chan9a120bc2008-05-16 22:17:45 -07005774 bnx2_init_phy(bp, 1);
Michael Chanbc5a0692006-01-23 16:13:22 -08005775 spin_unlock_bh(&bp->phy_lock);
5776 if (bnx2_run_loopback(bp, BNX2_MAC_LOOPBACK))
5777 rc |= BNX2_MAC_LOOPBACK_FAILED;
5778 if (bnx2_run_loopback(bp, BNX2_PHY_LOOPBACK))
5779 rc |= BNX2_PHY_LOOPBACK_FAILED;
5780 return rc;
5781}
5782
Michael Chanb6016b72005-05-26 13:03:09 -07005783#define NVRAM_SIZE 0x200
5784#define CRC32_RESIDUAL 0xdebb20e3
5785
5786static int
5787bnx2_test_nvram(struct bnx2 *bp)
5788{
Al Virob491edd2007-12-22 19:44:51 +00005789 __be32 buf[NVRAM_SIZE / 4];
Michael Chanb6016b72005-05-26 13:03:09 -07005790 u8 *data = (u8 *) buf;
5791 int rc = 0;
5792 u32 magic, csum;
5793
5794 if ((rc = bnx2_nvram_read(bp, 0, data, 4)) != 0)
5795 goto test_nvram_done;
5796
5797 magic = be32_to_cpu(buf[0]);
5798 if (magic != 0x669955aa) {
5799 rc = -ENODEV;
5800 goto test_nvram_done;
5801 }
5802
5803 if ((rc = bnx2_nvram_read(bp, 0x100, data, NVRAM_SIZE)) != 0)
5804 goto test_nvram_done;
5805
5806 csum = ether_crc_le(0x100, data);
5807 if (csum != CRC32_RESIDUAL) {
5808 rc = -ENODEV;
5809 goto test_nvram_done;
5810 }
5811
5812 csum = ether_crc_le(0x100, data + 0x100);
5813 if (csum != CRC32_RESIDUAL) {
5814 rc = -ENODEV;
5815 }
5816
5817test_nvram_done:
5818 return rc;
5819}
5820
5821static int
5822bnx2_test_link(struct bnx2 *bp)
5823{
5824 u32 bmsr;
5825
Michael Chan9f52b562008-10-09 12:21:46 -07005826 if (!netif_running(bp->dev))
5827 return -ENODEV;
5828
Michael Chan583c28e2008-01-21 19:51:35 -08005829 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP) {
Michael Chan489310a2007-10-10 16:16:31 -07005830 if (bp->link_up)
5831 return 0;
5832 return -ENODEV;
5833 }
Michael Chanc770a652005-08-25 15:38:39 -07005834 spin_lock_bh(&bp->phy_lock);
Michael Chan27a005b2007-05-03 13:23:41 -07005835 bnx2_enable_bmsr1(bp);
5836 bnx2_read_phy(bp, bp->mii_bmsr1, &bmsr);
5837 bnx2_read_phy(bp, bp->mii_bmsr1, &bmsr);
5838 bnx2_disable_bmsr1(bp);
Michael Chanc770a652005-08-25 15:38:39 -07005839 spin_unlock_bh(&bp->phy_lock);
Jeff Garzik6aa20a22006-09-13 13:24:59 -04005840
Michael Chanb6016b72005-05-26 13:03:09 -07005841 if (bmsr & BMSR_LSTATUS) {
5842 return 0;
5843 }
5844 return -ENODEV;
5845}
5846
5847static int
5848bnx2_test_intr(struct bnx2 *bp)
5849{
5850 int i;
Michael Chanb6016b72005-05-26 13:03:09 -07005851 u16 status_idx;
5852
5853 if (!netif_running(bp->dev))
5854 return -ENODEV;
5855
5856 status_idx = REG_RD(bp, BNX2_PCICFG_INT_ACK_CMD) & 0xffff;
5857
5858 /* This register is not touched during run-time. */
Michael Chanbf5295b2006-03-23 01:11:56 -08005859 REG_WR(bp, BNX2_HC_COMMAND, bp->hc_cmd | BNX2_HC_COMMAND_COAL_NOW);
Michael Chanb6016b72005-05-26 13:03:09 -07005860 REG_RD(bp, BNX2_HC_COMMAND);
5861
5862 for (i = 0; i < 10; i++) {
5863 if ((REG_RD(bp, BNX2_PCICFG_INT_ACK_CMD) & 0xffff) !=
5864 status_idx) {
5865
5866 break;
5867 }
5868
5869 msleep_interruptible(10);
5870 }
5871 if (i < 10)
5872 return 0;
5873
5874 return -ENODEV;
5875}
5876
Michael Chan38ea3682008-02-23 19:48:57 -08005877/* Determining link for parallel detection. */
Michael Chanb2fadea2008-01-21 17:07:06 -08005878static int
5879bnx2_5706_serdes_has_link(struct bnx2 *bp)
5880{
5881 u32 mode_ctl, an_dbg, exp;
5882
Michael Chan38ea3682008-02-23 19:48:57 -08005883 if (bp->phy_flags & BNX2_PHY_FLAG_NO_PARALLEL)
5884 return 0;
5885
Michael Chanb2fadea2008-01-21 17:07:06 -08005886 bnx2_write_phy(bp, MII_BNX2_MISC_SHADOW, MISC_SHDW_MODE_CTL);
5887 bnx2_read_phy(bp, MII_BNX2_MISC_SHADOW, &mode_ctl);
5888
5889 if (!(mode_ctl & MISC_SHDW_MODE_CTL_SIG_DET))
5890 return 0;
5891
5892 bnx2_write_phy(bp, MII_BNX2_MISC_SHADOW, MISC_SHDW_AN_DBG);
5893 bnx2_read_phy(bp, MII_BNX2_MISC_SHADOW, &an_dbg);
5894 bnx2_read_phy(bp, MII_BNX2_MISC_SHADOW, &an_dbg);
5895
Michael Chanf3014c02008-01-29 21:33:03 -08005896 if (an_dbg & (MISC_SHDW_AN_DBG_NOSYNC | MISC_SHDW_AN_DBG_RUDI_INVALID))
Michael Chanb2fadea2008-01-21 17:07:06 -08005897 return 0;
5898
5899 bnx2_write_phy(bp, MII_BNX2_DSP_ADDRESS, MII_EXPAND_REG1);
5900 bnx2_read_phy(bp, MII_BNX2_DSP_RW_PORT, &exp);
5901 bnx2_read_phy(bp, MII_BNX2_DSP_RW_PORT, &exp);
5902
5903 if (exp & MII_EXPAND_REG1_RUDI_C) /* receiving CONFIG */
5904 return 0;
5905
5906 return 1;
5907}
5908
Michael Chanb6016b72005-05-26 13:03:09 -07005909static void
Michael Chan48b01e22006-11-19 14:08:00 -08005910bnx2_5706_serdes_timer(struct bnx2 *bp)
5911{
Michael Chanb2fadea2008-01-21 17:07:06 -08005912 int check_link = 1;
5913
Michael Chan48b01e22006-11-19 14:08:00 -08005914 spin_lock(&bp->phy_lock);
Michael Chanb2fadea2008-01-21 17:07:06 -08005915 if (bp->serdes_an_pending) {
Michael Chan48b01e22006-11-19 14:08:00 -08005916 bp->serdes_an_pending--;
Michael Chanb2fadea2008-01-21 17:07:06 -08005917 check_link = 0;
5918 } else if ((bp->link_up == 0) && (bp->autoneg & AUTONEG_SPEED)) {
Michael Chan48b01e22006-11-19 14:08:00 -08005919 u32 bmcr;
5920
Benjamin Liac392ab2008-09-18 16:40:49 -07005921 bp->current_interval = BNX2_TIMER_INTERVAL;
Michael Chan48b01e22006-11-19 14:08:00 -08005922
Michael Chanca58c3a2007-05-03 13:22:52 -07005923 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chan48b01e22006-11-19 14:08:00 -08005924
5925 if (bmcr & BMCR_ANENABLE) {
Michael Chanb2fadea2008-01-21 17:07:06 -08005926 if (bnx2_5706_serdes_has_link(bp)) {
Michael Chan48b01e22006-11-19 14:08:00 -08005927 bmcr &= ~BMCR_ANENABLE;
5928 bmcr |= BMCR_SPEED1000 | BMCR_FULLDPLX;
Michael Chanca58c3a2007-05-03 13:22:52 -07005929 bnx2_write_phy(bp, bp->mii_bmcr, bmcr);
Michael Chan583c28e2008-01-21 19:51:35 -08005930 bp->phy_flags |= BNX2_PHY_FLAG_PARALLEL_DETECT;
Michael Chan48b01e22006-11-19 14:08:00 -08005931 }
5932 }
5933 }
5934 else if ((bp->link_up) && (bp->autoneg & AUTONEG_SPEED) &&
Michael Chan583c28e2008-01-21 19:51:35 -08005935 (bp->phy_flags & BNX2_PHY_FLAG_PARALLEL_DETECT)) {
Michael Chan48b01e22006-11-19 14:08:00 -08005936 u32 phy2;
5937
5938 bnx2_write_phy(bp, 0x17, 0x0f01);
5939 bnx2_read_phy(bp, 0x15, &phy2);
5940 if (phy2 & 0x20) {
5941 u32 bmcr;
5942
Michael Chanca58c3a2007-05-03 13:22:52 -07005943 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chan48b01e22006-11-19 14:08:00 -08005944 bmcr |= BMCR_ANENABLE;
Michael Chanca58c3a2007-05-03 13:22:52 -07005945 bnx2_write_phy(bp, bp->mii_bmcr, bmcr);
Michael Chan48b01e22006-11-19 14:08:00 -08005946
Michael Chan583c28e2008-01-21 19:51:35 -08005947 bp->phy_flags &= ~BNX2_PHY_FLAG_PARALLEL_DETECT;
Michael Chan48b01e22006-11-19 14:08:00 -08005948 }
5949 } else
Benjamin Liac392ab2008-09-18 16:40:49 -07005950 bp->current_interval = BNX2_TIMER_INTERVAL;
Michael Chan48b01e22006-11-19 14:08:00 -08005951
Michael Chana2724e22008-02-23 19:47:44 -08005952 if (check_link) {
Michael Chanb2fadea2008-01-21 17:07:06 -08005953 u32 val;
5954
5955 bnx2_write_phy(bp, MII_BNX2_MISC_SHADOW, MISC_SHDW_AN_DBG);
5956 bnx2_read_phy(bp, MII_BNX2_MISC_SHADOW, &val);
5957 bnx2_read_phy(bp, MII_BNX2_MISC_SHADOW, &val);
5958
Michael Chana2724e22008-02-23 19:47:44 -08005959 if (bp->link_up && (val & MISC_SHDW_AN_DBG_NOSYNC)) {
5960 if (!(bp->phy_flags & BNX2_PHY_FLAG_FORCED_DOWN)) {
5961 bnx2_5706s_force_link_dn(bp, 1);
5962 bp->phy_flags |= BNX2_PHY_FLAG_FORCED_DOWN;
5963 } else
5964 bnx2_set_link(bp);
5965 } else if (!bp->link_up && !(val & MISC_SHDW_AN_DBG_NOSYNC))
5966 bnx2_set_link(bp);
Michael Chanb2fadea2008-01-21 17:07:06 -08005967 }
Michael Chan48b01e22006-11-19 14:08:00 -08005968 spin_unlock(&bp->phy_lock);
5969}
5970
5971static void
Michael Chanf8dd0642006-11-19 14:08:29 -08005972bnx2_5708_serdes_timer(struct bnx2 *bp)
5973{
Michael Chan583c28e2008-01-21 19:51:35 -08005974 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
Michael Chan0d8a6572007-07-07 22:49:43 -07005975 return;
5976
Michael Chan583c28e2008-01-21 19:51:35 -08005977 if ((bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE) == 0) {
Michael Chanf8dd0642006-11-19 14:08:29 -08005978 bp->serdes_an_pending = 0;
5979 return;
5980 }
5981
5982 spin_lock(&bp->phy_lock);
5983 if (bp->serdes_an_pending)
5984 bp->serdes_an_pending--;
5985 else if ((bp->link_up == 0) && (bp->autoneg & AUTONEG_SPEED)) {
5986 u32 bmcr;
5987
Michael Chanca58c3a2007-05-03 13:22:52 -07005988 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chanf8dd0642006-11-19 14:08:29 -08005989 if (bmcr & BMCR_ANENABLE) {
Michael Chan605a9e22007-05-03 13:23:13 -07005990 bnx2_enable_forced_2g5(bp);
Michael Chan40105c02008-11-12 16:02:45 -08005991 bp->current_interval = BNX2_SERDES_FORCED_TIMEOUT;
Michael Chanf8dd0642006-11-19 14:08:29 -08005992 } else {
Michael Chan605a9e22007-05-03 13:23:13 -07005993 bnx2_disable_forced_2g5(bp);
Michael Chanf8dd0642006-11-19 14:08:29 -08005994 bp->serdes_an_pending = 2;
Benjamin Liac392ab2008-09-18 16:40:49 -07005995 bp->current_interval = BNX2_TIMER_INTERVAL;
Michael Chanf8dd0642006-11-19 14:08:29 -08005996 }
5997
5998 } else
Benjamin Liac392ab2008-09-18 16:40:49 -07005999 bp->current_interval = BNX2_TIMER_INTERVAL;
Michael Chanf8dd0642006-11-19 14:08:29 -08006000
6001 spin_unlock(&bp->phy_lock);
6002}
6003
6004static void
Michael Chanb6016b72005-05-26 13:03:09 -07006005bnx2_timer(unsigned long data)
6006{
6007 struct bnx2 *bp = (struct bnx2 *) data;
Michael Chanb6016b72005-05-26 13:03:09 -07006008
Michael Chancd339a02005-08-25 15:35:24 -07006009 if (!netif_running(bp->dev))
6010 return;
6011
Michael Chanb6016b72005-05-26 13:03:09 -07006012 if (atomic_read(&bp->intr_sem) != 0)
6013 goto bnx2_restart_timer;
6014
Michael Chanefba0182008-12-03 00:36:15 -08006015 if ((bp->flags & (BNX2_FLAG_USING_MSI | BNX2_FLAG_ONE_SHOT_MSI)) ==
6016 BNX2_FLAG_USING_MSI)
6017 bnx2_chk_missed_msi(bp);
6018
Michael Chandf149d72007-07-07 22:51:36 -07006019 bnx2_send_heart_beat(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07006020
Michael Chan2726d6e2008-01-29 21:35:05 -08006021 bp->stats_blk->stat_FwRxDrop =
6022 bnx2_reg_rd_ind(bp, BNX2_FW_RX_DROP_COUNT);
Michael Chancea94db2006-06-12 22:16:13 -07006023
Michael Chan02537b062007-06-04 21:24:07 -07006024 /* workaround occasional corrupted counters */
6025 if (CHIP_NUM(bp) == CHIP_NUM_5708 && bp->stats_ticks)
6026 REG_WR(bp, BNX2_HC_COMMAND, bp->hc_cmd |
6027 BNX2_HC_COMMAND_STATS_NOW);
6028
Michael Chan583c28e2008-01-21 19:51:35 -08006029 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Michael Chanf8dd0642006-11-19 14:08:29 -08006030 if (CHIP_NUM(bp) == CHIP_NUM_5706)
6031 bnx2_5706_serdes_timer(bp);
Michael Chan27a005b2007-05-03 13:23:41 -07006032 else
Michael Chanf8dd0642006-11-19 14:08:29 -08006033 bnx2_5708_serdes_timer(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07006034 }
6035
6036bnx2_restart_timer:
Michael Chancd339a02005-08-25 15:35:24 -07006037 mod_timer(&bp->timer, jiffies + bp->current_interval);
Michael Chanb6016b72005-05-26 13:03:09 -07006038}
6039
Michael Chan8e6a72c2007-05-03 13:24:48 -07006040static int
6041bnx2_request_irq(struct bnx2 *bp)
6042{
Michael Chan6d866ff2007-12-20 19:56:09 -08006043 unsigned long flags;
Michael Chanb4b36042007-12-20 19:59:30 -08006044 struct bnx2_irq *irq;
6045 int rc = 0, i;
Michael Chan8e6a72c2007-05-03 13:24:48 -07006046
David S. Millerf86e82f2008-01-21 17:15:40 -08006047 if (bp->flags & BNX2_FLAG_USING_MSI_OR_MSIX)
Michael Chan6d866ff2007-12-20 19:56:09 -08006048 flags = 0;
6049 else
6050 flags = IRQF_SHARED;
Michael Chanb4b36042007-12-20 19:59:30 -08006051
6052 for (i = 0; i < bp->irq_nvecs; i++) {
6053 irq = &bp->irq_tbl[i];
Michael Chanc76c0472007-12-20 20:01:19 -08006054 rc = request_irq(irq->vector, irq->handler, flags, irq->name,
Michael Chanf0ea2e62008-06-19 16:41:57 -07006055 &bp->bnx2_napi[i]);
Michael Chanb4b36042007-12-20 19:59:30 -08006056 if (rc)
6057 break;
6058 irq->requested = 1;
6059 }
Michael Chan8e6a72c2007-05-03 13:24:48 -07006060 return rc;
6061}
6062
6063static void
6064bnx2_free_irq(struct bnx2 *bp)
6065{
Michael Chanb4b36042007-12-20 19:59:30 -08006066 struct bnx2_irq *irq;
6067 int i;
Michael Chan8e6a72c2007-05-03 13:24:48 -07006068
Michael Chanb4b36042007-12-20 19:59:30 -08006069 for (i = 0; i < bp->irq_nvecs; i++) {
6070 irq = &bp->irq_tbl[i];
6071 if (irq->requested)
Michael Chanf0ea2e62008-06-19 16:41:57 -07006072 free_irq(irq->vector, &bp->bnx2_napi[i]);
Michael Chanb4b36042007-12-20 19:59:30 -08006073 irq->requested = 0;
Michael Chan6d866ff2007-12-20 19:56:09 -08006074 }
David S. Millerf86e82f2008-01-21 17:15:40 -08006075 if (bp->flags & BNX2_FLAG_USING_MSI)
Michael Chanb4b36042007-12-20 19:59:30 -08006076 pci_disable_msi(bp->pdev);
David S. Millerf86e82f2008-01-21 17:15:40 -08006077 else if (bp->flags & BNX2_FLAG_USING_MSIX)
Michael Chanb4b36042007-12-20 19:59:30 -08006078 pci_disable_msix(bp->pdev);
6079
David S. Millerf86e82f2008-01-21 17:15:40 -08006080 bp->flags &= ~(BNX2_FLAG_USING_MSI_OR_MSIX | BNX2_FLAG_ONE_SHOT_MSI);
Michael Chanb4b36042007-12-20 19:59:30 -08006081}
6082
6083static void
Michael Chan5e9ad9e2008-06-19 16:43:17 -07006084bnx2_enable_msix(struct bnx2 *bp, int msix_vecs)
Michael Chanb4b36042007-12-20 19:59:30 -08006085{
Michael Chan57851d82007-12-20 20:01:44 -08006086 int i, rc;
6087 struct msix_entry msix_ent[BNX2_MAX_MSIX_VEC];
Michael Chan4e1d0de2008-12-16 20:27:45 -08006088 struct net_device *dev = bp->dev;
6089 const int len = sizeof(bp->irq_tbl[0].name);
Michael Chan57851d82007-12-20 20:01:44 -08006090
Michael Chanb4b36042007-12-20 19:59:30 -08006091 bnx2_setup_msix_tbl(bp);
6092 REG_WR(bp, BNX2_PCI_MSIX_CONTROL, BNX2_MAX_MSIX_HW_VEC - 1);
6093 REG_WR(bp, BNX2_PCI_MSIX_TBL_OFF_BIR, BNX2_PCI_GRC_WINDOW2_BASE);
6094 REG_WR(bp, BNX2_PCI_MSIX_PBA_OFF_BIT, BNX2_PCI_GRC_WINDOW3_BASE);
Michael Chan57851d82007-12-20 20:01:44 -08006095
6096 for (i = 0; i < BNX2_MAX_MSIX_VEC; i++) {
6097 msix_ent[i].entry = i;
6098 msix_ent[i].vector = 0;
6099 }
6100
6101 rc = pci_enable_msix(bp->pdev, msix_ent, BNX2_MAX_MSIX_VEC);
6102 if (rc != 0)
6103 return;
6104
Michael Chan5e9ad9e2008-06-19 16:43:17 -07006105 bp->irq_nvecs = msix_vecs;
David S. Millerf86e82f2008-01-21 17:15:40 -08006106 bp->flags |= BNX2_FLAG_USING_MSIX | BNX2_FLAG_ONE_SHOT_MSI;
Michael Chan69010312009-03-18 18:11:51 -07006107 for (i = 0; i < BNX2_MAX_MSIX_VEC; i++) {
Michael Chan57851d82007-12-20 20:01:44 -08006108 bp->irq_tbl[i].vector = msix_ent[i].vector;
Michael Chan69010312009-03-18 18:11:51 -07006109 snprintf(bp->irq_tbl[i].name, len, "%s-%d", dev->name, i);
6110 bp->irq_tbl[i].handler = bnx2_msi_1shot;
6111 }
Michael Chan6d866ff2007-12-20 19:56:09 -08006112}
6113
6114static void
6115bnx2_setup_int_mode(struct bnx2 *bp, int dis_msi)
6116{
Michael Chan5e9ad9e2008-06-19 16:43:17 -07006117 int cpus = num_online_cpus();
Benjamin Li706bf242008-07-18 17:55:11 -07006118 int msix_vecs = min(cpus + 1, RX_MAX_RINGS);
Michael Chan5e9ad9e2008-06-19 16:43:17 -07006119
Michael Chan6d866ff2007-12-20 19:56:09 -08006120 bp->irq_tbl[0].handler = bnx2_interrupt;
6121 strcpy(bp->irq_tbl[0].name, bp->dev->name);
Michael Chanb4b36042007-12-20 19:59:30 -08006122 bp->irq_nvecs = 1;
6123 bp->irq_tbl[0].vector = bp->pdev->irq;
Michael Chan6d866ff2007-12-20 19:56:09 -08006124
Michael Chan5e9ad9e2008-06-19 16:43:17 -07006125 if ((bp->flags & BNX2_FLAG_MSIX_CAP) && !dis_msi && cpus > 1)
6126 bnx2_enable_msix(bp, msix_vecs);
Michael Chanb4b36042007-12-20 19:59:30 -08006127
David S. Millerf86e82f2008-01-21 17:15:40 -08006128 if ((bp->flags & BNX2_FLAG_MSI_CAP) && !dis_msi &&
6129 !(bp->flags & BNX2_FLAG_USING_MSIX)) {
Michael Chan6d866ff2007-12-20 19:56:09 -08006130 if (pci_enable_msi(bp->pdev) == 0) {
David S. Millerf86e82f2008-01-21 17:15:40 -08006131 bp->flags |= BNX2_FLAG_USING_MSI;
Michael Chan6d866ff2007-12-20 19:56:09 -08006132 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
David S. Millerf86e82f2008-01-21 17:15:40 -08006133 bp->flags |= BNX2_FLAG_ONE_SHOT_MSI;
Michael Chan6d866ff2007-12-20 19:56:09 -08006134 bp->irq_tbl[0].handler = bnx2_msi_1shot;
6135 } else
6136 bp->irq_tbl[0].handler = bnx2_msi;
Michael Chanb4b36042007-12-20 19:59:30 -08006137
6138 bp->irq_tbl[0].vector = bp->pdev->irq;
Michael Chan6d866ff2007-12-20 19:56:09 -08006139 }
6140 }
Benjamin Li706bf242008-07-18 17:55:11 -07006141
6142 bp->num_tx_rings = rounddown_pow_of_two(bp->irq_nvecs);
6143 bp->dev->real_num_tx_queues = bp->num_tx_rings;
6144
Michael Chan5e9ad9e2008-06-19 16:43:17 -07006145 bp->num_rx_rings = bp->irq_nvecs;
Michael Chan8e6a72c2007-05-03 13:24:48 -07006146}
6147
Michael Chanb6016b72005-05-26 13:03:09 -07006148/* Called with rtnl_lock */
6149static int
6150bnx2_open(struct net_device *dev)
6151{
Michael Chan972ec0d2006-01-23 16:12:43 -08006152 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006153 int rc;
6154
Michael Chan1b2f9222007-05-03 13:20:19 -07006155 netif_carrier_off(dev);
6156
Pavel Machek829ca9a2005-09-03 15:56:56 -07006157 bnx2_set_power_state(bp, PCI_D0);
Michael Chanb6016b72005-05-26 13:03:09 -07006158 bnx2_disable_int(bp);
6159
Michael Chan6d866ff2007-12-20 19:56:09 -08006160 bnx2_setup_int_mode(bp, disable_msi);
Michael Chan35efa7c2007-12-20 19:56:37 -08006161 bnx2_napi_enable(bp);
Michael Chan35e90102008-06-19 16:37:42 -07006162 rc = bnx2_alloc_mem(bp);
Michael Chan2739a8b2008-06-19 16:44:10 -07006163 if (rc)
6164 goto open_err;
Michael Chan35e90102008-06-19 16:37:42 -07006165
Michael Chan8e6a72c2007-05-03 13:24:48 -07006166 rc = bnx2_request_irq(bp);
Michael Chan2739a8b2008-06-19 16:44:10 -07006167 if (rc)
6168 goto open_err;
Michael Chanb6016b72005-05-26 13:03:09 -07006169
Michael Chan9a120bc2008-05-16 22:17:45 -07006170 rc = bnx2_init_nic(bp, 1);
Michael Chan2739a8b2008-06-19 16:44:10 -07006171 if (rc)
6172 goto open_err;
Jeff Garzik6aa20a22006-09-13 13:24:59 -04006173
Michael Chancd339a02005-08-25 15:35:24 -07006174 mod_timer(&bp->timer, jiffies + bp->current_interval);
Michael Chanb6016b72005-05-26 13:03:09 -07006175
6176 atomic_set(&bp->intr_sem, 0);
6177
6178 bnx2_enable_int(bp);
6179
David S. Millerf86e82f2008-01-21 17:15:40 -08006180 if (bp->flags & BNX2_FLAG_USING_MSI) {
Michael Chanb6016b72005-05-26 13:03:09 -07006181 /* Test MSI to make sure it is working
6182 * If MSI test fails, go back to INTx mode
6183 */
6184 if (bnx2_test_intr(bp) != 0) {
6185 printk(KERN_WARNING PFX "%s: No interrupt was generated"
6186 " using MSI, switching to INTx mode. Please"
6187 " report this failure to the PCI maintainer"
6188 " and include system chipset information.\n",
6189 bp->dev->name);
6190
6191 bnx2_disable_int(bp);
Michael Chan8e6a72c2007-05-03 13:24:48 -07006192 bnx2_free_irq(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07006193
Michael Chan6d866ff2007-12-20 19:56:09 -08006194 bnx2_setup_int_mode(bp, 1);
6195
Michael Chan9a120bc2008-05-16 22:17:45 -07006196 rc = bnx2_init_nic(bp, 0);
Michael Chanb6016b72005-05-26 13:03:09 -07006197
Michael Chan8e6a72c2007-05-03 13:24:48 -07006198 if (!rc)
6199 rc = bnx2_request_irq(bp);
6200
Michael Chanb6016b72005-05-26 13:03:09 -07006201 if (rc) {
Michael Chanb6016b72005-05-26 13:03:09 -07006202 del_timer_sync(&bp->timer);
Michael Chan2739a8b2008-06-19 16:44:10 -07006203 goto open_err;
Michael Chanb6016b72005-05-26 13:03:09 -07006204 }
6205 bnx2_enable_int(bp);
6206 }
6207 }
David S. Millerf86e82f2008-01-21 17:15:40 -08006208 if (bp->flags & BNX2_FLAG_USING_MSI)
Michael Chanb6016b72005-05-26 13:03:09 -07006209 printk(KERN_INFO PFX "%s: using MSI\n", dev->name);
David S. Millerf86e82f2008-01-21 17:15:40 -08006210 else if (bp->flags & BNX2_FLAG_USING_MSIX)
Michael Chan57851d82007-12-20 20:01:44 -08006211 printk(KERN_INFO PFX "%s: using MSIX\n", dev->name);
Michael Chanb6016b72005-05-26 13:03:09 -07006212
Benjamin Li706bf242008-07-18 17:55:11 -07006213 netif_tx_start_all_queues(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006214
6215 return 0;
Michael Chan2739a8b2008-06-19 16:44:10 -07006216
6217open_err:
6218 bnx2_napi_disable(bp);
6219 bnx2_free_skbs(bp);
6220 bnx2_free_irq(bp);
6221 bnx2_free_mem(bp);
6222 return rc;
Michael Chanb6016b72005-05-26 13:03:09 -07006223}
6224
6225static void
David Howellsc4028952006-11-22 14:57:56 +00006226bnx2_reset_task(struct work_struct *work)
Michael Chanb6016b72005-05-26 13:03:09 -07006227{
David Howellsc4028952006-11-22 14:57:56 +00006228 struct bnx2 *bp = container_of(work, struct bnx2, reset_task);
Michael Chanb6016b72005-05-26 13:03:09 -07006229
Michael Chanafdc08b2005-08-25 15:34:29 -07006230 if (!netif_running(bp->dev))
6231 return;
6232
Michael Chanb6016b72005-05-26 13:03:09 -07006233 bnx2_netif_stop(bp);
6234
Michael Chan9a120bc2008-05-16 22:17:45 -07006235 bnx2_init_nic(bp, 1);
Michael Chanb6016b72005-05-26 13:03:09 -07006236
6237 atomic_set(&bp->intr_sem, 1);
6238 bnx2_netif_start(bp);
6239}
6240
6241static void
6242bnx2_tx_timeout(struct net_device *dev)
6243{
Michael Chan972ec0d2006-01-23 16:12:43 -08006244 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006245
6246 /* This allows the netif to be shutdown gracefully before resetting */
6247 schedule_work(&bp->reset_task);
6248}
6249
6250#ifdef BCM_VLAN
6251/* Called with rtnl_lock */
6252static void
6253bnx2_vlan_rx_register(struct net_device *dev, struct vlan_group *vlgrp)
6254{
Michael Chan972ec0d2006-01-23 16:12:43 -08006255 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006256
6257 bnx2_netif_stop(bp);
6258
6259 bp->vlgrp = vlgrp;
6260 bnx2_set_rx_mode(dev);
Michael Chan7c62e832008-07-14 22:39:03 -07006261 if (bp->flags & BNX2_FLAG_CAN_KEEP_VLAN)
6262 bnx2_fw_sync(bp, BNX2_DRV_MSG_CODE_KEEP_VLAN_UPDATE, 0, 1);
Michael Chanb6016b72005-05-26 13:03:09 -07006263
6264 bnx2_netif_start(bp);
6265}
Michael Chanb6016b72005-05-26 13:03:09 -07006266#endif
6267
Herbert Xu932ff272006-06-09 12:20:56 -07006268/* Called with netif_tx_lock.
Michael Chan2f8af122006-08-15 01:39:10 -07006269 * bnx2_tx_int() runs without netif_tx_lock unless it needs to call
6270 * netif_wake_queue().
Michael Chanb6016b72005-05-26 13:03:09 -07006271 */
6272static int
6273bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev)
6274{
Michael Chan972ec0d2006-01-23 16:12:43 -08006275 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006276 dma_addr_t mapping;
6277 struct tx_bd *txbd;
Benjamin Li3d16af82008-10-09 12:26:41 -07006278 struct sw_tx_bd *tx_buf;
Michael Chanb6016b72005-05-26 13:03:09 -07006279 u32 len, vlan_tag_flags, last_frag, mss;
6280 u16 prod, ring_prod;
6281 int i;
Benjamin Li706bf242008-07-18 17:55:11 -07006282 struct bnx2_napi *bnapi;
6283 struct bnx2_tx_ring_info *txr;
6284 struct netdev_queue *txq;
Benjamin Li3d16af82008-10-09 12:26:41 -07006285 struct skb_shared_info *sp;
Benjamin Li706bf242008-07-18 17:55:11 -07006286
6287 /* Determine which tx ring we will be placed on */
6288 i = skb_get_queue_mapping(skb);
6289 bnapi = &bp->bnx2_napi[i];
6290 txr = &bnapi->tx_ring;
6291 txq = netdev_get_tx_queue(dev, i);
Michael Chanb6016b72005-05-26 13:03:09 -07006292
Michael Chan35e90102008-06-19 16:37:42 -07006293 if (unlikely(bnx2_tx_avail(bp, txr) <
Michael Chana550c992007-12-20 19:56:59 -08006294 (skb_shinfo(skb)->nr_frags + 1))) {
Benjamin Li706bf242008-07-18 17:55:11 -07006295 netif_tx_stop_queue(txq);
Michael Chanb6016b72005-05-26 13:03:09 -07006296 printk(KERN_ERR PFX "%s: BUG! Tx ring full when queue awake!\n",
6297 dev->name);
6298
6299 return NETDEV_TX_BUSY;
6300 }
6301 len = skb_headlen(skb);
Michael Chan35e90102008-06-19 16:37:42 -07006302 prod = txr->tx_prod;
Michael Chanb6016b72005-05-26 13:03:09 -07006303 ring_prod = TX_RING_IDX(prod);
6304
6305 vlan_tag_flags = 0;
Patrick McHardy84fa7932006-08-29 16:44:56 -07006306 if (skb->ip_summed == CHECKSUM_PARTIAL) {
Michael Chanb6016b72005-05-26 13:03:09 -07006307 vlan_tag_flags |= TX_BD_FLAGS_TCP_UDP_CKSUM;
6308 }
6309
Michael Chan729b85c2008-08-14 15:29:39 -07006310#ifdef BCM_VLAN
Al Viro79ea13c2008-01-24 02:06:46 -08006311 if (bp->vlgrp && vlan_tx_tag_present(skb)) {
Michael Chanb6016b72005-05-26 13:03:09 -07006312 vlan_tag_flags |=
6313 (TX_BD_FLAGS_VLAN_TAG | (vlan_tx_tag_get(skb) << 16));
6314 }
Michael Chan729b85c2008-08-14 15:29:39 -07006315#endif
Michael Chanfde82052007-05-03 17:23:35 -07006316 if ((mss = skb_shinfo(skb)->gso_size)) {
Michael Chana1efb4b2008-10-09 12:24:39 -07006317 u32 tcp_opt_len;
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -07006318 struct iphdr *iph;
Michael Chanb6016b72005-05-26 13:03:09 -07006319
Michael Chanb6016b72005-05-26 13:03:09 -07006320 vlan_tag_flags |= TX_BD_FLAGS_SW_LSO;
6321
Michael Chan4666f872007-05-03 13:22:28 -07006322 tcp_opt_len = tcp_optlen(skb);
Arnaldo Carvalho de Meloab6a5bb2007-03-18 17:43:48 -07006323
Michael Chan4666f872007-05-03 13:22:28 -07006324 if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6) {
6325 u32 tcp_off = skb_transport_offset(skb) -
6326 sizeof(struct ipv6hdr) - ETH_HLEN;
Michael Chanb6016b72005-05-26 13:03:09 -07006327
Michael Chan4666f872007-05-03 13:22:28 -07006328 vlan_tag_flags |= ((tcp_opt_len >> 2) << 8) |
6329 TX_BD_FLAGS_SW_FLAGS;
6330 if (likely(tcp_off == 0))
6331 vlan_tag_flags &= ~TX_BD_FLAGS_TCP6_OFF0_MSK;
6332 else {
6333 tcp_off >>= 3;
6334 vlan_tag_flags |= ((tcp_off & 0x3) <<
6335 TX_BD_FLAGS_TCP6_OFF0_SHL) |
6336 ((tcp_off & 0x10) <<
6337 TX_BD_FLAGS_TCP6_OFF4_SHL);
6338 mss |= (tcp_off & 0xc) << TX_BD_TCP6_OFF2_SHL;
6339 }
6340 } else {
Michael Chan4666f872007-05-03 13:22:28 -07006341 iph = ip_hdr(skb);
Michael Chan4666f872007-05-03 13:22:28 -07006342 if (tcp_opt_len || (iph->ihl > 5)) {
6343 vlan_tag_flags |= ((iph->ihl - 5) +
6344 (tcp_opt_len >> 2)) << 8;
6345 }
Michael Chanb6016b72005-05-26 13:03:09 -07006346 }
Michael Chan4666f872007-05-03 13:22:28 -07006347 } else
Michael Chanb6016b72005-05-26 13:03:09 -07006348 mss = 0;
Michael Chanb6016b72005-05-26 13:03:09 -07006349
Benjamin Li3d16af82008-10-09 12:26:41 -07006350 if (skb_dma_map(&bp->pdev->dev, skb, DMA_TO_DEVICE)) {
6351 dev_kfree_skb(skb);
6352 return NETDEV_TX_OK;
6353 }
6354
6355 sp = skb_shinfo(skb);
6356 mapping = sp->dma_maps[0];
Jeff Garzik6aa20a22006-09-13 13:24:59 -04006357
Michael Chan35e90102008-06-19 16:37:42 -07006358 tx_buf = &txr->tx_buf_ring[ring_prod];
Michael Chanb6016b72005-05-26 13:03:09 -07006359 tx_buf->skb = skb;
Michael Chanb6016b72005-05-26 13:03:09 -07006360
Michael Chan35e90102008-06-19 16:37:42 -07006361 txbd = &txr->tx_desc_ring[ring_prod];
Michael Chanb6016b72005-05-26 13:03:09 -07006362
6363 txbd->tx_bd_haddr_hi = (u64) mapping >> 32;
6364 txbd->tx_bd_haddr_lo = (u64) mapping & 0xffffffff;
6365 txbd->tx_bd_mss_nbytes = len | (mss << 16);
6366 txbd->tx_bd_vlan_tag_flags = vlan_tag_flags | TX_BD_FLAGS_START;
6367
6368 last_frag = skb_shinfo(skb)->nr_frags;
6369
6370 for (i = 0; i < last_frag; i++) {
6371 skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
6372
6373 prod = NEXT_TX_BD(prod);
6374 ring_prod = TX_RING_IDX(prod);
Michael Chan35e90102008-06-19 16:37:42 -07006375 txbd = &txr->tx_desc_ring[ring_prod];
Michael Chanb6016b72005-05-26 13:03:09 -07006376
6377 len = frag->size;
Benjamin Li3d16af82008-10-09 12:26:41 -07006378 mapping = sp->dma_maps[i + 1];
Michael Chanb6016b72005-05-26 13:03:09 -07006379
6380 txbd->tx_bd_haddr_hi = (u64) mapping >> 32;
6381 txbd->tx_bd_haddr_lo = (u64) mapping & 0xffffffff;
6382 txbd->tx_bd_mss_nbytes = len | (mss << 16);
6383 txbd->tx_bd_vlan_tag_flags = vlan_tag_flags;
6384
6385 }
6386 txbd->tx_bd_vlan_tag_flags |= TX_BD_FLAGS_END;
6387
6388 prod = NEXT_TX_BD(prod);
Michael Chan35e90102008-06-19 16:37:42 -07006389 txr->tx_prod_bseq += skb->len;
Michael Chanb6016b72005-05-26 13:03:09 -07006390
Michael Chan35e90102008-06-19 16:37:42 -07006391 REG_WR16(bp, txr->tx_bidx_addr, prod);
6392 REG_WR(bp, txr->tx_bseq_addr, txr->tx_prod_bseq);
Michael Chanb6016b72005-05-26 13:03:09 -07006393
6394 mmiowb();
6395
Michael Chan35e90102008-06-19 16:37:42 -07006396 txr->tx_prod = prod;
Michael Chanb6016b72005-05-26 13:03:09 -07006397 dev->trans_start = jiffies;
6398
Michael Chan35e90102008-06-19 16:37:42 -07006399 if (unlikely(bnx2_tx_avail(bp, txr) <= MAX_SKB_FRAGS)) {
Benjamin Li706bf242008-07-18 17:55:11 -07006400 netif_tx_stop_queue(txq);
Michael Chan35e90102008-06-19 16:37:42 -07006401 if (bnx2_tx_avail(bp, txr) > bp->tx_wake_thresh)
Benjamin Li706bf242008-07-18 17:55:11 -07006402 netif_tx_wake_queue(txq);
Michael Chanb6016b72005-05-26 13:03:09 -07006403 }
6404
6405 return NETDEV_TX_OK;
6406}
6407
6408/* Called with rtnl_lock */
6409static int
6410bnx2_close(struct net_device *dev)
6411{
Michael Chan972ec0d2006-01-23 16:12:43 -08006412 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006413
David S. Miller4bb073c2008-06-12 02:22:02 -07006414 cancel_work_sync(&bp->reset_task);
Michael Chanafdc08b2005-08-25 15:34:29 -07006415
Stephen Hemmingerbea33482007-10-03 16:41:36 -07006416 bnx2_disable_int_sync(bp);
Michael Chan35efa7c2007-12-20 19:56:37 -08006417 bnx2_napi_disable(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07006418 del_timer_sync(&bp->timer);
Michael Chan74bf4ba2008-10-09 12:21:08 -07006419 bnx2_shutdown_chip(bp);
Michael Chan8e6a72c2007-05-03 13:24:48 -07006420 bnx2_free_irq(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07006421 bnx2_free_skbs(bp);
6422 bnx2_free_mem(bp);
6423 bp->link_up = 0;
6424 netif_carrier_off(bp->dev);
Pavel Machek829ca9a2005-09-03 15:56:56 -07006425 bnx2_set_power_state(bp, PCI_D3hot);
Michael Chanb6016b72005-05-26 13:03:09 -07006426 return 0;
6427}
6428
6429#define GET_NET_STATS64(ctr) \
6430 (unsigned long) ((unsigned long) (ctr##_hi) << 32) + \
6431 (unsigned long) (ctr##_lo)
6432
6433#define GET_NET_STATS32(ctr) \
6434 (ctr##_lo)
6435
6436#if (BITS_PER_LONG == 64)
6437#define GET_NET_STATS GET_NET_STATS64
6438#else
6439#define GET_NET_STATS GET_NET_STATS32
6440#endif
6441
6442static struct net_device_stats *
6443bnx2_get_stats(struct net_device *dev)
6444{
Michael Chan972ec0d2006-01-23 16:12:43 -08006445 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006446 struct statistics_block *stats_blk = bp->stats_blk;
Ilpo Järvinend8e80342008-11-28 15:52:43 -08006447 struct net_device_stats *net_stats = &dev->stats;
Michael Chanb6016b72005-05-26 13:03:09 -07006448
6449 if (bp->stats_blk == NULL) {
6450 return net_stats;
6451 }
6452 net_stats->rx_packets =
6453 GET_NET_STATS(stats_blk->stat_IfHCInUcastPkts) +
6454 GET_NET_STATS(stats_blk->stat_IfHCInMulticastPkts) +
6455 GET_NET_STATS(stats_blk->stat_IfHCInBroadcastPkts);
6456
6457 net_stats->tx_packets =
6458 GET_NET_STATS(stats_blk->stat_IfHCOutUcastPkts) +
6459 GET_NET_STATS(stats_blk->stat_IfHCOutMulticastPkts) +
6460 GET_NET_STATS(stats_blk->stat_IfHCOutBroadcastPkts);
6461
6462 net_stats->rx_bytes =
6463 GET_NET_STATS(stats_blk->stat_IfHCInOctets);
6464
6465 net_stats->tx_bytes =
6466 GET_NET_STATS(stats_blk->stat_IfHCOutOctets);
6467
Jeff Garzik6aa20a22006-09-13 13:24:59 -04006468 net_stats->multicast =
Michael Chanb6016b72005-05-26 13:03:09 -07006469 GET_NET_STATS(stats_blk->stat_IfHCOutMulticastPkts);
6470
Jeff Garzik6aa20a22006-09-13 13:24:59 -04006471 net_stats->collisions =
Michael Chanb6016b72005-05-26 13:03:09 -07006472 (unsigned long) stats_blk->stat_EtherStatsCollisions;
6473
Jeff Garzik6aa20a22006-09-13 13:24:59 -04006474 net_stats->rx_length_errors =
Michael Chanb6016b72005-05-26 13:03:09 -07006475 (unsigned long) (stats_blk->stat_EtherStatsUndersizePkts +
6476 stats_blk->stat_EtherStatsOverrsizePkts);
6477
Jeff Garzik6aa20a22006-09-13 13:24:59 -04006478 net_stats->rx_over_errors =
Michael Chanb6016b72005-05-26 13:03:09 -07006479 (unsigned long) stats_blk->stat_IfInMBUFDiscards;
6480
Jeff Garzik6aa20a22006-09-13 13:24:59 -04006481 net_stats->rx_frame_errors =
Michael Chanb6016b72005-05-26 13:03:09 -07006482 (unsigned long) stats_blk->stat_Dot3StatsAlignmentErrors;
6483
Jeff Garzik6aa20a22006-09-13 13:24:59 -04006484 net_stats->rx_crc_errors =
Michael Chanb6016b72005-05-26 13:03:09 -07006485 (unsigned long) stats_blk->stat_Dot3StatsFCSErrors;
6486
6487 net_stats->rx_errors = net_stats->rx_length_errors +
6488 net_stats->rx_over_errors + net_stats->rx_frame_errors +
6489 net_stats->rx_crc_errors;
6490
6491 net_stats->tx_aborted_errors =
6492 (unsigned long) (stats_blk->stat_Dot3StatsExcessiveCollisions +
6493 stats_blk->stat_Dot3StatsLateCollisions);
6494
Michael Chan5b0c76a2005-11-04 08:45:49 -08006495 if ((CHIP_NUM(bp) == CHIP_NUM_5706) ||
6496 (CHIP_ID(bp) == CHIP_ID_5708_A0))
Michael Chanb6016b72005-05-26 13:03:09 -07006497 net_stats->tx_carrier_errors = 0;
6498 else {
6499 net_stats->tx_carrier_errors =
6500 (unsigned long)
6501 stats_blk->stat_Dot3StatsCarrierSenseErrors;
6502 }
6503
6504 net_stats->tx_errors =
Jeff Garzik6aa20a22006-09-13 13:24:59 -04006505 (unsigned long)
Michael Chanb6016b72005-05-26 13:03:09 -07006506 stats_blk->stat_emac_tx_stat_dot3statsinternalmactransmiterrors
6507 +
6508 net_stats->tx_aborted_errors +
6509 net_stats->tx_carrier_errors;
6510
Michael Chancea94db2006-06-12 22:16:13 -07006511 net_stats->rx_missed_errors =
6512 (unsigned long) (stats_blk->stat_IfInMBUFDiscards +
6513 stats_blk->stat_FwRxDrop);
6514
Michael Chanb6016b72005-05-26 13:03:09 -07006515 return net_stats;
6516}
6517
6518/* All ethtool functions called with rtnl_lock */
6519
6520static int
6521bnx2_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
6522{
Michael Chan972ec0d2006-01-23 16:12:43 -08006523 struct bnx2 *bp = netdev_priv(dev);
Michael Chan7b6b8342007-07-07 22:50:15 -07006524 int support_serdes = 0, support_copper = 0;
Michael Chanb6016b72005-05-26 13:03:09 -07006525
6526 cmd->supported = SUPPORTED_Autoneg;
Michael Chan583c28e2008-01-21 19:51:35 -08006527 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP) {
Michael Chan7b6b8342007-07-07 22:50:15 -07006528 support_serdes = 1;
6529 support_copper = 1;
6530 } else if (bp->phy_port == PORT_FIBRE)
6531 support_serdes = 1;
6532 else
6533 support_copper = 1;
6534
6535 if (support_serdes) {
Michael Chanb6016b72005-05-26 13:03:09 -07006536 cmd->supported |= SUPPORTED_1000baseT_Full |
6537 SUPPORTED_FIBRE;
Michael Chan583c28e2008-01-21 19:51:35 -08006538 if (bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE)
Michael Chan605a9e22007-05-03 13:23:13 -07006539 cmd->supported |= SUPPORTED_2500baseX_Full;
Michael Chanb6016b72005-05-26 13:03:09 -07006540
Michael Chanb6016b72005-05-26 13:03:09 -07006541 }
Michael Chan7b6b8342007-07-07 22:50:15 -07006542 if (support_copper) {
Michael Chanb6016b72005-05-26 13:03:09 -07006543 cmd->supported |= SUPPORTED_10baseT_Half |
6544 SUPPORTED_10baseT_Full |
6545 SUPPORTED_100baseT_Half |
6546 SUPPORTED_100baseT_Full |
6547 SUPPORTED_1000baseT_Full |
6548 SUPPORTED_TP;
6549
Michael Chanb6016b72005-05-26 13:03:09 -07006550 }
6551
Michael Chan7b6b8342007-07-07 22:50:15 -07006552 spin_lock_bh(&bp->phy_lock);
6553 cmd->port = bp->phy_port;
Michael Chanb6016b72005-05-26 13:03:09 -07006554 cmd->advertising = bp->advertising;
6555
6556 if (bp->autoneg & AUTONEG_SPEED) {
6557 cmd->autoneg = AUTONEG_ENABLE;
6558 }
6559 else {
6560 cmd->autoneg = AUTONEG_DISABLE;
6561 }
6562
6563 if (netif_carrier_ok(dev)) {
6564 cmd->speed = bp->line_speed;
6565 cmd->duplex = bp->duplex;
6566 }
6567 else {
6568 cmd->speed = -1;
6569 cmd->duplex = -1;
6570 }
Michael Chan7b6b8342007-07-07 22:50:15 -07006571 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07006572
6573 cmd->transceiver = XCVR_INTERNAL;
6574 cmd->phy_address = bp->phy_addr;
6575
6576 return 0;
6577}
Jeff Garzik6aa20a22006-09-13 13:24:59 -04006578
Michael Chanb6016b72005-05-26 13:03:09 -07006579static int
6580bnx2_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
6581{
Michael Chan972ec0d2006-01-23 16:12:43 -08006582 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006583 u8 autoneg = bp->autoneg;
6584 u8 req_duplex = bp->req_duplex;
6585 u16 req_line_speed = bp->req_line_speed;
6586 u32 advertising = bp->advertising;
Michael Chan7b6b8342007-07-07 22:50:15 -07006587 int err = -EINVAL;
6588
6589 spin_lock_bh(&bp->phy_lock);
6590
6591 if (cmd->port != PORT_TP && cmd->port != PORT_FIBRE)
6592 goto err_out_unlock;
6593
Michael Chan583c28e2008-01-21 19:51:35 -08006594 if (cmd->port != bp->phy_port &&
6595 !(bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP))
Michael Chan7b6b8342007-07-07 22:50:15 -07006596 goto err_out_unlock;
Michael Chanb6016b72005-05-26 13:03:09 -07006597
Michael Chand6b14482008-07-14 22:37:21 -07006598 /* If device is down, we can store the settings only if the user
6599 * is setting the currently active port.
6600 */
6601 if (!netif_running(dev) && cmd->port != bp->phy_port)
6602 goto err_out_unlock;
6603
Michael Chanb6016b72005-05-26 13:03:09 -07006604 if (cmd->autoneg == AUTONEG_ENABLE) {
6605 autoneg |= AUTONEG_SPEED;
6606
Jeff Garzik6aa20a22006-09-13 13:24:59 -04006607 cmd->advertising &= ETHTOOL_ALL_COPPER_SPEED;
Michael Chanb6016b72005-05-26 13:03:09 -07006608
6609 /* allow advertising 1 speed */
6610 if ((cmd->advertising == ADVERTISED_10baseT_Half) ||
6611 (cmd->advertising == ADVERTISED_10baseT_Full) ||
6612 (cmd->advertising == ADVERTISED_100baseT_Half) ||
6613 (cmd->advertising == ADVERTISED_100baseT_Full)) {
6614
Michael Chan7b6b8342007-07-07 22:50:15 -07006615 if (cmd->port == PORT_FIBRE)
6616 goto err_out_unlock;
Michael Chanb6016b72005-05-26 13:03:09 -07006617
6618 advertising = cmd->advertising;
6619
Michael Chan27a005b2007-05-03 13:23:41 -07006620 } else if (cmd->advertising == ADVERTISED_2500baseX_Full) {
Michael Chan583c28e2008-01-21 19:51:35 -08006621 if (!(bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE) ||
Michael Chan7b6b8342007-07-07 22:50:15 -07006622 (cmd->port == PORT_TP))
6623 goto err_out_unlock;
6624 } else if (cmd->advertising == ADVERTISED_1000baseT_Full)
Michael Chanb6016b72005-05-26 13:03:09 -07006625 advertising = cmd->advertising;
Michael Chan7b6b8342007-07-07 22:50:15 -07006626 else if (cmd->advertising == ADVERTISED_1000baseT_Half)
6627 goto err_out_unlock;
Michael Chanb6016b72005-05-26 13:03:09 -07006628 else {
Michael Chan7b6b8342007-07-07 22:50:15 -07006629 if (cmd->port == PORT_FIBRE)
Michael Chanb6016b72005-05-26 13:03:09 -07006630 advertising = ETHTOOL_ALL_FIBRE_SPEED;
Michael Chan7b6b8342007-07-07 22:50:15 -07006631 else
Michael Chanb6016b72005-05-26 13:03:09 -07006632 advertising = ETHTOOL_ALL_COPPER_SPEED;
Michael Chanb6016b72005-05-26 13:03:09 -07006633 }
6634 advertising |= ADVERTISED_Autoneg;
6635 }
6636 else {
Michael Chan7b6b8342007-07-07 22:50:15 -07006637 if (cmd->port == PORT_FIBRE) {
Michael Chan80be4432006-11-19 14:07:28 -08006638 if ((cmd->speed != SPEED_1000 &&
6639 cmd->speed != SPEED_2500) ||
6640 (cmd->duplex != DUPLEX_FULL))
Michael Chan7b6b8342007-07-07 22:50:15 -07006641 goto err_out_unlock;
Michael Chan80be4432006-11-19 14:07:28 -08006642
6643 if (cmd->speed == SPEED_2500 &&
Michael Chan583c28e2008-01-21 19:51:35 -08006644 !(bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE))
Michael Chan7b6b8342007-07-07 22:50:15 -07006645 goto err_out_unlock;
Michael Chanb6016b72005-05-26 13:03:09 -07006646 }
Michael Chan7b6b8342007-07-07 22:50:15 -07006647 else if (cmd->speed == SPEED_1000 || cmd->speed == SPEED_2500)
6648 goto err_out_unlock;
6649
Michael Chanb6016b72005-05-26 13:03:09 -07006650 autoneg &= ~AUTONEG_SPEED;
6651 req_line_speed = cmd->speed;
6652 req_duplex = cmd->duplex;
6653 advertising = 0;
6654 }
6655
6656 bp->autoneg = autoneg;
6657 bp->advertising = advertising;
6658 bp->req_line_speed = req_line_speed;
6659 bp->req_duplex = req_duplex;
6660
Michael Chand6b14482008-07-14 22:37:21 -07006661 err = 0;
6662 /* If device is down, the new settings will be picked up when it is
6663 * brought up.
6664 */
6665 if (netif_running(dev))
6666 err = bnx2_setup_phy(bp, cmd->port);
Michael Chanb6016b72005-05-26 13:03:09 -07006667
Michael Chan7b6b8342007-07-07 22:50:15 -07006668err_out_unlock:
Michael Chanc770a652005-08-25 15:38:39 -07006669 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07006670
Michael Chan7b6b8342007-07-07 22:50:15 -07006671 return err;
Michael Chanb6016b72005-05-26 13:03:09 -07006672}
6673
6674static void
6675bnx2_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
6676{
Michael Chan972ec0d2006-01-23 16:12:43 -08006677 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006678
6679 strcpy(info->driver, DRV_MODULE_NAME);
6680 strcpy(info->version, DRV_MODULE_VERSION);
6681 strcpy(info->bus_info, pci_name(bp->pdev));
Michael Chan58fc2ea2007-07-07 22:52:02 -07006682 strcpy(info->fw_version, bp->fw_version);
Michael Chanb6016b72005-05-26 13:03:09 -07006683}
6684
Michael Chan244ac4f2006-03-20 17:48:46 -08006685#define BNX2_REGDUMP_LEN (32 * 1024)
6686
6687static int
6688bnx2_get_regs_len(struct net_device *dev)
6689{
6690 return BNX2_REGDUMP_LEN;
6691}
6692
6693static void
6694bnx2_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *_p)
6695{
6696 u32 *p = _p, i, offset;
6697 u8 *orig_p = _p;
6698 struct bnx2 *bp = netdev_priv(dev);
6699 u32 reg_boundaries[] = { 0x0000, 0x0098, 0x0400, 0x045c,
6700 0x0800, 0x0880, 0x0c00, 0x0c10,
6701 0x0c30, 0x0d08, 0x1000, 0x101c,
6702 0x1040, 0x1048, 0x1080, 0x10a4,
6703 0x1400, 0x1490, 0x1498, 0x14f0,
6704 0x1500, 0x155c, 0x1580, 0x15dc,
6705 0x1600, 0x1658, 0x1680, 0x16d8,
6706 0x1800, 0x1820, 0x1840, 0x1854,
6707 0x1880, 0x1894, 0x1900, 0x1984,
6708 0x1c00, 0x1c0c, 0x1c40, 0x1c54,
6709 0x1c80, 0x1c94, 0x1d00, 0x1d84,
6710 0x2000, 0x2030, 0x23c0, 0x2400,
6711 0x2800, 0x2820, 0x2830, 0x2850,
6712 0x2b40, 0x2c10, 0x2fc0, 0x3058,
6713 0x3c00, 0x3c94, 0x4000, 0x4010,
6714 0x4080, 0x4090, 0x43c0, 0x4458,
6715 0x4c00, 0x4c18, 0x4c40, 0x4c54,
6716 0x4fc0, 0x5010, 0x53c0, 0x5444,
6717 0x5c00, 0x5c18, 0x5c80, 0x5c90,
6718 0x5fc0, 0x6000, 0x6400, 0x6428,
6719 0x6800, 0x6848, 0x684c, 0x6860,
6720 0x6888, 0x6910, 0x8000 };
6721
6722 regs->version = 0;
6723
6724 memset(p, 0, BNX2_REGDUMP_LEN);
6725
6726 if (!netif_running(bp->dev))
6727 return;
6728
6729 i = 0;
6730 offset = reg_boundaries[0];
6731 p += offset;
6732 while (offset < BNX2_REGDUMP_LEN) {
6733 *p++ = REG_RD(bp, offset);
6734 offset += 4;
6735 if (offset == reg_boundaries[i + 1]) {
6736 offset = reg_boundaries[i + 2];
6737 p = (u32 *) (orig_p + offset);
6738 i += 2;
6739 }
6740 }
6741}
6742
Michael Chanb6016b72005-05-26 13:03:09 -07006743static void
6744bnx2_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
6745{
Michael Chan972ec0d2006-01-23 16:12:43 -08006746 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006747
David S. Millerf86e82f2008-01-21 17:15:40 -08006748 if (bp->flags & BNX2_FLAG_NO_WOL) {
Michael Chanb6016b72005-05-26 13:03:09 -07006749 wol->supported = 0;
6750 wol->wolopts = 0;
6751 }
6752 else {
6753 wol->supported = WAKE_MAGIC;
6754 if (bp->wol)
6755 wol->wolopts = WAKE_MAGIC;
6756 else
6757 wol->wolopts = 0;
6758 }
6759 memset(&wol->sopass, 0, sizeof(wol->sopass));
6760}
6761
6762static int
6763bnx2_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
6764{
Michael Chan972ec0d2006-01-23 16:12:43 -08006765 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006766
6767 if (wol->wolopts & ~WAKE_MAGIC)
6768 return -EINVAL;
6769
6770 if (wol->wolopts & WAKE_MAGIC) {
David S. Millerf86e82f2008-01-21 17:15:40 -08006771 if (bp->flags & BNX2_FLAG_NO_WOL)
Michael Chanb6016b72005-05-26 13:03:09 -07006772 return -EINVAL;
6773
6774 bp->wol = 1;
6775 }
6776 else {
6777 bp->wol = 0;
6778 }
6779 return 0;
6780}
6781
6782static int
6783bnx2_nway_reset(struct net_device *dev)
6784{
Michael Chan972ec0d2006-01-23 16:12:43 -08006785 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006786 u32 bmcr;
6787
Michael Chan9f52b562008-10-09 12:21:46 -07006788 if (!netif_running(dev))
6789 return -EAGAIN;
6790
Michael Chanb6016b72005-05-26 13:03:09 -07006791 if (!(bp->autoneg & AUTONEG_SPEED)) {
6792 return -EINVAL;
6793 }
6794
Michael Chanc770a652005-08-25 15:38:39 -07006795 spin_lock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07006796
Michael Chan583c28e2008-01-21 19:51:35 -08006797 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP) {
Michael Chan7b6b8342007-07-07 22:50:15 -07006798 int rc;
6799
6800 rc = bnx2_setup_remote_phy(bp, bp->phy_port);
6801 spin_unlock_bh(&bp->phy_lock);
6802 return rc;
6803 }
6804
Michael Chanb6016b72005-05-26 13:03:09 -07006805 /* Force a link down visible on the other side */
Michael Chan583c28e2008-01-21 19:51:35 -08006806 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Michael Chanca58c3a2007-05-03 13:22:52 -07006807 bnx2_write_phy(bp, bp->mii_bmcr, BMCR_LOOPBACK);
Michael Chanc770a652005-08-25 15:38:39 -07006808 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07006809
6810 msleep(20);
6811
Michael Chanc770a652005-08-25 15:38:39 -07006812 spin_lock_bh(&bp->phy_lock);
Michael Chanf8dd0642006-11-19 14:08:29 -08006813
Michael Chan40105c02008-11-12 16:02:45 -08006814 bp->current_interval = BNX2_SERDES_AN_TIMEOUT;
Michael Chanf8dd0642006-11-19 14:08:29 -08006815 bp->serdes_an_pending = 1;
6816 mod_timer(&bp->timer, jiffies + bp->current_interval);
Michael Chanb6016b72005-05-26 13:03:09 -07006817 }
6818
Michael Chanca58c3a2007-05-03 13:22:52 -07006819 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chanb6016b72005-05-26 13:03:09 -07006820 bmcr &= ~BMCR_LOOPBACK;
Michael Chanca58c3a2007-05-03 13:22:52 -07006821 bnx2_write_phy(bp, bp->mii_bmcr, bmcr | BMCR_ANRESTART | BMCR_ANENABLE);
Michael Chanb6016b72005-05-26 13:03:09 -07006822
Michael Chanc770a652005-08-25 15:38:39 -07006823 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07006824
6825 return 0;
6826}
6827
6828static int
6829bnx2_get_eeprom_len(struct net_device *dev)
6830{
Michael Chan972ec0d2006-01-23 16:12:43 -08006831 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006832
Michael Chan1122db72006-01-23 16:11:42 -08006833 if (bp->flash_info == NULL)
Michael Chanb6016b72005-05-26 13:03:09 -07006834 return 0;
6835
Michael Chan1122db72006-01-23 16:11:42 -08006836 return (int) bp->flash_size;
Michael Chanb6016b72005-05-26 13:03:09 -07006837}
6838
6839static int
6840bnx2_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
6841 u8 *eebuf)
6842{
Michael Chan972ec0d2006-01-23 16:12:43 -08006843 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006844 int rc;
6845
Michael Chan9f52b562008-10-09 12:21:46 -07006846 if (!netif_running(dev))
6847 return -EAGAIN;
6848
John W. Linville1064e942005-11-10 12:58:24 -08006849 /* parameters already validated in ethtool_get_eeprom */
Michael Chanb6016b72005-05-26 13:03:09 -07006850
6851 rc = bnx2_nvram_read(bp, eeprom->offset, eebuf, eeprom->len);
6852
6853 return rc;
6854}
6855
6856static int
6857bnx2_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
6858 u8 *eebuf)
6859{
Michael Chan972ec0d2006-01-23 16:12:43 -08006860 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006861 int rc;
6862
Michael Chan9f52b562008-10-09 12:21:46 -07006863 if (!netif_running(dev))
6864 return -EAGAIN;
6865
John W. Linville1064e942005-11-10 12:58:24 -08006866 /* parameters already validated in ethtool_set_eeprom */
Michael Chanb6016b72005-05-26 13:03:09 -07006867
6868 rc = bnx2_nvram_write(bp, eeprom->offset, eebuf, eeprom->len);
6869
6870 return rc;
6871}
6872
6873static int
6874bnx2_get_coalesce(struct net_device *dev, struct ethtool_coalesce *coal)
6875{
Michael Chan972ec0d2006-01-23 16:12:43 -08006876 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006877
6878 memset(coal, 0, sizeof(struct ethtool_coalesce));
6879
6880 coal->rx_coalesce_usecs = bp->rx_ticks;
6881 coal->rx_max_coalesced_frames = bp->rx_quick_cons_trip;
6882 coal->rx_coalesce_usecs_irq = bp->rx_ticks_int;
6883 coal->rx_max_coalesced_frames_irq = bp->rx_quick_cons_trip_int;
6884
6885 coal->tx_coalesce_usecs = bp->tx_ticks;
6886 coal->tx_max_coalesced_frames = bp->tx_quick_cons_trip;
6887 coal->tx_coalesce_usecs_irq = bp->tx_ticks_int;
6888 coal->tx_max_coalesced_frames_irq = bp->tx_quick_cons_trip_int;
6889
6890 coal->stats_block_coalesce_usecs = bp->stats_ticks;
6891
6892 return 0;
6893}
6894
6895static int
6896bnx2_set_coalesce(struct net_device *dev, struct ethtool_coalesce *coal)
6897{
Michael Chan972ec0d2006-01-23 16:12:43 -08006898 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006899
6900 bp->rx_ticks = (u16) coal->rx_coalesce_usecs;
6901 if (bp->rx_ticks > 0x3ff) bp->rx_ticks = 0x3ff;
6902
Jeff Garzik6aa20a22006-09-13 13:24:59 -04006903 bp->rx_quick_cons_trip = (u16) coal->rx_max_coalesced_frames;
Michael Chanb6016b72005-05-26 13:03:09 -07006904 if (bp->rx_quick_cons_trip > 0xff) bp->rx_quick_cons_trip = 0xff;
6905
6906 bp->rx_ticks_int = (u16) coal->rx_coalesce_usecs_irq;
6907 if (bp->rx_ticks_int > 0x3ff) bp->rx_ticks_int = 0x3ff;
6908
6909 bp->rx_quick_cons_trip_int = (u16) coal->rx_max_coalesced_frames_irq;
6910 if (bp->rx_quick_cons_trip_int > 0xff)
6911 bp->rx_quick_cons_trip_int = 0xff;
6912
6913 bp->tx_ticks = (u16) coal->tx_coalesce_usecs;
6914 if (bp->tx_ticks > 0x3ff) bp->tx_ticks = 0x3ff;
6915
6916 bp->tx_quick_cons_trip = (u16) coal->tx_max_coalesced_frames;
6917 if (bp->tx_quick_cons_trip > 0xff) bp->tx_quick_cons_trip = 0xff;
6918
6919 bp->tx_ticks_int = (u16) coal->tx_coalesce_usecs_irq;
6920 if (bp->tx_ticks_int > 0x3ff) bp->tx_ticks_int = 0x3ff;
6921
6922 bp->tx_quick_cons_trip_int = (u16) coal->tx_max_coalesced_frames_irq;
6923 if (bp->tx_quick_cons_trip_int > 0xff) bp->tx_quick_cons_trip_int =
6924 0xff;
6925
6926 bp->stats_ticks = coal->stats_block_coalesce_usecs;
Michael Chan02537b062007-06-04 21:24:07 -07006927 if (CHIP_NUM(bp) == CHIP_NUM_5708) {
6928 if (bp->stats_ticks != 0 && bp->stats_ticks != USEC_PER_SEC)
6929 bp->stats_ticks = USEC_PER_SEC;
6930 }
Michael Chan7ea69202007-07-16 18:27:10 -07006931 if (bp->stats_ticks > BNX2_HC_STATS_TICKS_HC_STAT_TICKS)
6932 bp->stats_ticks = BNX2_HC_STATS_TICKS_HC_STAT_TICKS;
6933 bp->stats_ticks &= BNX2_HC_STATS_TICKS_HC_STAT_TICKS;
Michael Chanb6016b72005-05-26 13:03:09 -07006934
6935 if (netif_running(bp->dev)) {
6936 bnx2_netif_stop(bp);
Michael Chan9a120bc2008-05-16 22:17:45 -07006937 bnx2_init_nic(bp, 0);
Michael Chanb6016b72005-05-26 13:03:09 -07006938 bnx2_netif_start(bp);
6939 }
6940
6941 return 0;
6942}
6943
6944static void
6945bnx2_get_ringparam(struct net_device *dev, struct ethtool_ringparam *ering)
6946{
Michael Chan972ec0d2006-01-23 16:12:43 -08006947 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006948
Michael Chan13daffa2006-03-20 17:49:20 -08006949 ering->rx_max_pending = MAX_TOTAL_RX_DESC_CNT;
Michael Chanb6016b72005-05-26 13:03:09 -07006950 ering->rx_mini_max_pending = 0;
Michael Chan47bf4242007-12-12 11:19:12 -08006951 ering->rx_jumbo_max_pending = MAX_TOTAL_RX_PG_DESC_CNT;
Michael Chanb6016b72005-05-26 13:03:09 -07006952
6953 ering->rx_pending = bp->rx_ring_size;
6954 ering->rx_mini_pending = 0;
Michael Chan47bf4242007-12-12 11:19:12 -08006955 ering->rx_jumbo_pending = bp->rx_pg_ring_size;
Michael Chanb6016b72005-05-26 13:03:09 -07006956
6957 ering->tx_max_pending = MAX_TX_DESC_CNT;
6958 ering->tx_pending = bp->tx_ring_size;
6959}
6960
6961static int
Michael Chan5d5d0012007-12-12 11:17:43 -08006962bnx2_change_ring_size(struct bnx2 *bp, u32 rx, u32 tx)
Michael Chanb6016b72005-05-26 13:03:09 -07006963{
Michael Chan13daffa2006-03-20 17:49:20 -08006964 if (netif_running(bp->dev)) {
6965 bnx2_netif_stop(bp);
6966 bnx2_reset_chip(bp, BNX2_DRV_MSG_CODE_RESET);
6967 bnx2_free_skbs(bp);
6968 bnx2_free_mem(bp);
6969 }
6970
Michael Chan5d5d0012007-12-12 11:17:43 -08006971 bnx2_set_rx_ring_size(bp, rx);
6972 bp->tx_ring_size = tx;
Michael Chanb6016b72005-05-26 13:03:09 -07006973
6974 if (netif_running(bp->dev)) {
Michael Chan13daffa2006-03-20 17:49:20 -08006975 int rc;
6976
6977 rc = bnx2_alloc_mem(bp);
6978 if (rc)
6979 return rc;
Michael Chan9a120bc2008-05-16 22:17:45 -07006980 bnx2_init_nic(bp, 0);
Michael Chanb6016b72005-05-26 13:03:09 -07006981 bnx2_netif_start(bp);
6982 }
Michael Chanb6016b72005-05-26 13:03:09 -07006983 return 0;
6984}
6985
Michael Chan5d5d0012007-12-12 11:17:43 -08006986static int
6987bnx2_set_ringparam(struct net_device *dev, struct ethtool_ringparam *ering)
6988{
6989 struct bnx2 *bp = netdev_priv(dev);
6990 int rc;
6991
6992 if ((ering->rx_pending > MAX_TOTAL_RX_DESC_CNT) ||
6993 (ering->tx_pending > MAX_TX_DESC_CNT) ||
6994 (ering->tx_pending <= MAX_SKB_FRAGS)) {
6995
6996 return -EINVAL;
6997 }
6998 rc = bnx2_change_ring_size(bp, ering->rx_pending, ering->tx_pending);
6999 return rc;
7000}
7001
Michael Chanb6016b72005-05-26 13:03:09 -07007002static void
7003bnx2_get_pauseparam(struct net_device *dev, struct ethtool_pauseparam *epause)
7004{
Michael Chan972ec0d2006-01-23 16:12:43 -08007005 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007006
7007 epause->autoneg = ((bp->autoneg & AUTONEG_FLOW_CTRL) != 0);
7008 epause->rx_pause = ((bp->flow_ctrl & FLOW_CTRL_RX) != 0);
7009 epause->tx_pause = ((bp->flow_ctrl & FLOW_CTRL_TX) != 0);
7010}
7011
7012static int
7013bnx2_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam *epause)
7014{
Michael Chan972ec0d2006-01-23 16:12:43 -08007015 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007016
7017 bp->req_flow_ctrl = 0;
7018 if (epause->rx_pause)
7019 bp->req_flow_ctrl |= FLOW_CTRL_RX;
7020 if (epause->tx_pause)
7021 bp->req_flow_ctrl |= FLOW_CTRL_TX;
7022
7023 if (epause->autoneg) {
7024 bp->autoneg |= AUTONEG_FLOW_CTRL;
7025 }
7026 else {
7027 bp->autoneg &= ~AUTONEG_FLOW_CTRL;
7028 }
7029
Michael Chan9f52b562008-10-09 12:21:46 -07007030 if (netif_running(dev)) {
7031 spin_lock_bh(&bp->phy_lock);
7032 bnx2_setup_phy(bp, bp->phy_port);
7033 spin_unlock_bh(&bp->phy_lock);
7034 }
Michael Chanb6016b72005-05-26 13:03:09 -07007035
7036 return 0;
7037}
7038
7039static u32
7040bnx2_get_rx_csum(struct net_device *dev)
7041{
Michael Chan972ec0d2006-01-23 16:12:43 -08007042 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007043
7044 return bp->rx_csum;
7045}
7046
7047static int
7048bnx2_set_rx_csum(struct net_device *dev, u32 data)
7049{
Michael Chan972ec0d2006-01-23 16:12:43 -08007050 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007051
7052 bp->rx_csum = data;
7053 return 0;
7054}
7055
Michael Chanb11d6212006-06-29 12:31:21 -07007056static int
7057bnx2_set_tso(struct net_device *dev, u32 data)
7058{
Michael Chan4666f872007-05-03 13:22:28 -07007059 struct bnx2 *bp = netdev_priv(dev);
7060
7061 if (data) {
Michael Chanb11d6212006-06-29 12:31:21 -07007062 dev->features |= NETIF_F_TSO | NETIF_F_TSO_ECN;
Michael Chan4666f872007-05-03 13:22:28 -07007063 if (CHIP_NUM(bp) == CHIP_NUM_5709)
7064 dev->features |= NETIF_F_TSO6;
7065 } else
7066 dev->features &= ~(NETIF_F_TSO | NETIF_F_TSO6 |
7067 NETIF_F_TSO_ECN);
Michael Chanb11d6212006-06-29 12:31:21 -07007068 return 0;
7069}
7070
Michael Chancea94db2006-06-12 22:16:13 -07007071#define BNX2_NUM_STATS 46
Michael Chanb6016b72005-05-26 13:03:09 -07007072
Peter Hagervall14ab9b82005-08-10 14:18:16 -07007073static struct {
Michael Chanb6016b72005-05-26 13:03:09 -07007074 char string[ETH_GSTRING_LEN];
7075} bnx2_stats_str_arr[BNX2_NUM_STATS] = {
7076 { "rx_bytes" },
7077 { "rx_error_bytes" },
7078 { "tx_bytes" },
7079 { "tx_error_bytes" },
7080 { "rx_ucast_packets" },
7081 { "rx_mcast_packets" },
7082 { "rx_bcast_packets" },
7083 { "tx_ucast_packets" },
7084 { "tx_mcast_packets" },
7085 { "tx_bcast_packets" },
7086 { "tx_mac_errors" },
7087 { "tx_carrier_errors" },
7088 { "rx_crc_errors" },
7089 { "rx_align_errors" },
7090 { "tx_single_collisions" },
7091 { "tx_multi_collisions" },
7092 { "tx_deferred" },
7093 { "tx_excess_collisions" },
7094 { "tx_late_collisions" },
7095 { "tx_total_collisions" },
7096 { "rx_fragments" },
7097 { "rx_jabbers" },
7098 { "rx_undersize_packets" },
7099 { "rx_oversize_packets" },
7100 { "rx_64_byte_packets" },
7101 { "rx_65_to_127_byte_packets" },
7102 { "rx_128_to_255_byte_packets" },
7103 { "rx_256_to_511_byte_packets" },
7104 { "rx_512_to_1023_byte_packets" },
7105 { "rx_1024_to_1522_byte_packets" },
7106 { "rx_1523_to_9022_byte_packets" },
7107 { "tx_64_byte_packets" },
7108 { "tx_65_to_127_byte_packets" },
7109 { "tx_128_to_255_byte_packets" },
7110 { "tx_256_to_511_byte_packets" },
7111 { "tx_512_to_1023_byte_packets" },
7112 { "tx_1024_to_1522_byte_packets" },
7113 { "tx_1523_to_9022_byte_packets" },
7114 { "rx_xon_frames" },
7115 { "rx_xoff_frames" },
7116 { "tx_xon_frames" },
7117 { "tx_xoff_frames" },
7118 { "rx_mac_ctrl_frames" },
7119 { "rx_filtered_packets" },
7120 { "rx_discards" },
Michael Chancea94db2006-06-12 22:16:13 -07007121 { "rx_fw_discards" },
Michael Chanb6016b72005-05-26 13:03:09 -07007122};
7123
7124#define STATS_OFFSET32(offset_name) (offsetof(struct statistics_block, offset_name) / 4)
7125
Arjan van de Venf71e1302006-03-03 21:33:57 -05007126static const unsigned long bnx2_stats_offset_arr[BNX2_NUM_STATS] = {
Michael Chanb6016b72005-05-26 13:03:09 -07007127 STATS_OFFSET32(stat_IfHCInOctets_hi),
7128 STATS_OFFSET32(stat_IfHCInBadOctets_hi),
7129 STATS_OFFSET32(stat_IfHCOutOctets_hi),
7130 STATS_OFFSET32(stat_IfHCOutBadOctets_hi),
7131 STATS_OFFSET32(stat_IfHCInUcastPkts_hi),
7132 STATS_OFFSET32(stat_IfHCInMulticastPkts_hi),
7133 STATS_OFFSET32(stat_IfHCInBroadcastPkts_hi),
7134 STATS_OFFSET32(stat_IfHCOutUcastPkts_hi),
7135 STATS_OFFSET32(stat_IfHCOutMulticastPkts_hi),
7136 STATS_OFFSET32(stat_IfHCOutBroadcastPkts_hi),
7137 STATS_OFFSET32(stat_emac_tx_stat_dot3statsinternalmactransmiterrors),
Jeff Garzik6aa20a22006-09-13 13:24:59 -04007138 STATS_OFFSET32(stat_Dot3StatsCarrierSenseErrors),
7139 STATS_OFFSET32(stat_Dot3StatsFCSErrors),
7140 STATS_OFFSET32(stat_Dot3StatsAlignmentErrors),
7141 STATS_OFFSET32(stat_Dot3StatsSingleCollisionFrames),
7142 STATS_OFFSET32(stat_Dot3StatsMultipleCollisionFrames),
7143 STATS_OFFSET32(stat_Dot3StatsDeferredTransmissions),
7144 STATS_OFFSET32(stat_Dot3StatsExcessiveCollisions),
7145 STATS_OFFSET32(stat_Dot3StatsLateCollisions),
7146 STATS_OFFSET32(stat_EtherStatsCollisions),
7147 STATS_OFFSET32(stat_EtherStatsFragments),
7148 STATS_OFFSET32(stat_EtherStatsJabbers),
7149 STATS_OFFSET32(stat_EtherStatsUndersizePkts),
7150 STATS_OFFSET32(stat_EtherStatsOverrsizePkts),
7151 STATS_OFFSET32(stat_EtherStatsPktsRx64Octets),
7152 STATS_OFFSET32(stat_EtherStatsPktsRx65Octetsto127Octets),
7153 STATS_OFFSET32(stat_EtherStatsPktsRx128Octetsto255Octets),
7154 STATS_OFFSET32(stat_EtherStatsPktsRx256Octetsto511Octets),
7155 STATS_OFFSET32(stat_EtherStatsPktsRx512Octetsto1023Octets),
7156 STATS_OFFSET32(stat_EtherStatsPktsRx1024Octetsto1522Octets),
7157 STATS_OFFSET32(stat_EtherStatsPktsRx1523Octetsto9022Octets),
7158 STATS_OFFSET32(stat_EtherStatsPktsTx64Octets),
7159 STATS_OFFSET32(stat_EtherStatsPktsTx65Octetsto127Octets),
7160 STATS_OFFSET32(stat_EtherStatsPktsTx128Octetsto255Octets),
7161 STATS_OFFSET32(stat_EtherStatsPktsTx256Octetsto511Octets),
7162 STATS_OFFSET32(stat_EtherStatsPktsTx512Octetsto1023Octets),
7163 STATS_OFFSET32(stat_EtherStatsPktsTx1024Octetsto1522Octets),
7164 STATS_OFFSET32(stat_EtherStatsPktsTx1523Octetsto9022Octets),
7165 STATS_OFFSET32(stat_XonPauseFramesReceived),
7166 STATS_OFFSET32(stat_XoffPauseFramesReceived),
7167 STATS_OFFSET32(stat_OutXonSent),
7168 STATS_OFFSET32(stat_OutXoffSent),
7169 STATS_OFFSET32(stat_MacControlFramesReceived),
7170 STATS_OFFSET32(stat_IfInFramesL2FilterDiscards),
7171 STATS_OFFSET32(stat_IfInMBUFDiscards),
Michael Chancea94db2006-06-12 22:16:13 -07007172 STATS_OFFSET32(stat_FwRxDrop),
Michael Chanb6016b72005-05-26 13:03:09 -07007173};
7174
7175/* stat_IfHCInBadOctets and stat_Dot3StatsCarrierSenseErrors are
7176 * skipped because of errata.
Jeff Garzik6aa20a22006-09-13 13:24:59 -04007177 */
Peter Hagervall14ab9b82005-08-10 14:18:16 -07007178static u8 bnx2_5706_stats_len_arr[BNX2_NUM_STATS] = {
Michael Chanb6016b72005-05-26 13:03:09 -07007179 8,0,8,8,8,8,8,8,8,8,
7180 4,0,4,4,4,4,4,4,4,4,
7181 4,4,4,4,4,4,4,4,4,4,
7182 4,4,4,4,4,4,4,4,4,4,
Michael Chancea94db2006-06-12 22:16:13 -07007183 4,4,4,4,4,4,
Michael Chanb6016b72005-05-26 13:03:09 -07007184};
7185
Michael Chan5b0c76a2005-11-04 08:45:49 -08007186static u8 bnx2_5708_stats_len_arr[BNX2_NUM_STATS] = {
7187 8,0,8,8,8,8,8,8,8,8,
7188 4,4,4,4,4,4,4,4,4,4,
7189 4,4,4,4,4,4,4,4,4,4,
7190 4,4,4,4,4,4,4,4,4,4,
Michael Chancea94db2006-06-12 22:16:13 -07007191 4,4,4,4,4,4,
Michael Chan5b0c76a2005-11-04 08:45:49 -08007192};
7193
Michael Chanb6016b72005-05-26 13:03:09 -07007194#define BNX2_NUM_TESTS 6
7195
Peter Hagervall14ab9b82005-08-10 14:18:16 -07007196static struct {
Michael Chanb6016b72005-05-26 13:03:09 -07007197 char string[ETH_GSTRING_LEN];
7198} bnx2_tests_str_arr[BNX2_NUM_TESTS] = {
7199 { "register_test (offline)" },
7200 { "memory_test (offline)" },
7201 { "loopback_test (offline)" },
7202 { "nvram_test (online)" },
7203 { "interrupt_test (online)" },
7204 { "link_test (online)" },
7205};
7206
7207static int
Jeff Garzikb9f2c042007-10-03 18:07:32 -07007208bnx2_get_sset_count(struct net_device *dev, int sset)
Michael Chanb6016b72005-05-26 13:03:09 -07007209{
Jeff Garzikb9f2c042007-10-03 18:07:32 -07007210 switch (sset) {
7211 case ETH_SS_TEST:
7212 return BNX2_NUM_TESTS;
7213 case ETH_SS_STATS:
7214 return BNX2_NUM_STATS;
7215 default:
7216 return -EOPNOTSUPP;
7217 }
Michael Chanb6016b72005-05-26 13:03:09 -07007218}
7219
7220static void
7221bnx2_self_test(struct net_device *dev, struct ethtool_test *etest, u64 *buf)
7222{
Michael Chan972ec0d2006-01-23 16:12:43 -08007223 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007224
Michael Chan9f52b562008-10-09 12:21:46 -07007225 bnx2_set_power_state(bp, PCI_D0);
7226
Michael Chanb6016b72005-05-26 13:03:09 -07007227 memset(buf, 0, sizeof(u64) * BNX2_NUM_TESTS);
7228 if (etest->flags & ETH_TEST_FL_OFFLINE) {
Michael Chan80be4432006-11-19 14:07:28 -08007229 int i;
7230
Michael Chanb6016b72005-05-26 13:03:09 -07007231 bnx2_netif_stop(bp);
7232 bnx2_reset_chip(bp, BNX2_DRV_MSG_CODE_DIAG);
7233 bnx2_free_skbs(bp);
7234
7235 if (bnx2_test_registers(bp) != 0) {
7236 buf[0] = 1;
7237 etest->flags |= ETH_TEST_FL_FAILED;
7238 }
7239 if (bnx2_test_memory(bp) != 0) {
7240 buf[1] = 1;
7241 etest->flags |= ETH_TEST_FL_FAILED;
7242 }
Michael Chanbc5a0692006-01-23 16:13:22 -08007243 if ((buf[2] = bnx2_test_loopback(bp)) != 0)
Michael Chanb6016b72005-05-26 13:03:09 -07007244 etest->flags |= ETH_TEST_FL_FAILED;
Michael Chanb6016b72005-05-26 13:03:09 -07007245
Michael Chan9f52b562008-10-09 12:21:46 -07007246 if (!netif_running(bp->dev))
7247 bnx2_shutdown_chip(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07007248 else {
Michael Chan9a120bc2008-05-16 22:17:45 -07007249 bnx2_init_nic(bp, 1);
Michael Chanb6016b72005-05-26 13:03:09 -07007250 bnx2_netif_start(bp);
7251 }
7252
7253 /* wait for link up */
Michael Chan80be4432006-11-19 14:07:28 -08007254 for (i = 0; i < 7; i++) {
7255 if (bp->link_up)
7256 break;
7257 msleep_interruptible(1000);
7258 }
Michael Chanb6016b72005-05-26 13:03:09 -07007259 }
7260
7261 if (bnx2_test_nvram(bp) != 0) {
7262 buf[3] = 1;
7263 etest->flags |= ETH_TEST_FL_FAILED;
7264 }
7265 if (bnx2_test_intr(bp) != 0) {
7266 buf[4] = 1;
7267 etest->flags |= ETH_TEST_FL_FAILED;
7268 }
7269
7270 if (bnx2_test_link(bp) != 0) {
7271 buf[5] = 1;
7272 etest->flags |= ETH_TEST_FL_FAILED;
7273
7274 }
Michael Chan9f52b562008-10-09 12:21:46 -07007275 if (!netif_running(bp->dev))
7276 bnx2_set_power_state(bp, PCI_D3hot);
Michael Chanb6016b72005-05-26 13:03:09 -07007277}
7278
7279static void
7280bnx2_get_strings(struct net_device *dev, u32 stringset, u8 *buf)
7281{
7282 switch (stringset) {
7283 case ETH_SS_STATS:
7284 memcpy(buf, bnx2_stats_str_arr,
7285 sizeof(bnx2_stats_str_arr));
7286 break;
7287 case ETH_SS_TEST:
7288 memcpy(buf, bnx2_tests_str_arr,
7289 sizeof(bnx2_tests_str_arr));
7290 break;
7291 }
7292}
7293
Michael Chanb6016b72005-05-26 13:03:09 -07007294static void
7295bnx2_get_ethtool_stats(struct net_device *dev,
7296 struct ethtool_stats *stats, u64 *buf)
7297{
Michael Chan972ec0d2006-01-23 16:12:43 -08007298 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007299 int i;
7300 u32 *hw_stats = (u32 *) bp->stats_blk;
Peter Hagervall14ab9b82005-08-10 14:18:16 -07007301 u8 *stats_len_arr = NULL;
Michael Chanb6016b72005-05-26 13:03:09 -07007302
7303 if (hw_stats == NULL) {
7304 memset(buf, 0, sizeof(u64) * BNX2_NUM_STATS);
7305 return;
7306 }
7307
Michael Chan5b0c76a2005-11-04 08:45:49 -08007308 if ((CHIP_ID(bp) == CHIP_ID_5706_A0) ||
7309 (CHIP_ID(bp) == CHIP_ID_5706_A1) ||
7310 (CHIP_ID(bp) == CHIP_ID_5706_A2) ||
7311 (CHIP_ID(bp) == CHIP_ID_5708_A0))
Michael Chanb6016b72005-05-26 13:03:09 -07007312 stats_len_arr = bnx2_5706_stats_len_arr;
Michael Chan5b0c76a2005-11-04 08:45:49 -08007313 else
7314 stats_len_arr = bnx2_5708_stats_len_arr;
Michael Chanb6016b72005-05-26 13:03:09 -07007315
7316 for (i = 0; i < BNX2_NUM_STATS; i++) {
7317 if (stats_len_arr[i] == 0) {
7318 /* skip this counter */
7319 buf[i] = 0;
7320 continue;
7321 }
7322 if (stats_len_arr[i] == 4) {
7323 /* 4-byte counter */
7324 buf[i] = (u64)
7325 *(hw_stats + bnx2_stats_offset_arr[i]);
7326 continue;
7327 }
7328 /* 8-byte counter */
7329 buf[i] = (((u64) *(hw_stats +
7330 bnx2_stats_offset_arr[i])) << 32) +
7331 *(hw_stats + bnx2_stats_offset_arr[i] + 1);
7332 }
7333}
7334
7335static int
7336bnx2_phys_id(struct net_device *dev, u32 data)
7337{
Michael Chan972ec0d2006-01-23 16:12:43 -08007338 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007339 int i;
7340 u32 save;
7341
Michael Chan9f52b562008-10-09 12:21:46 -07007342 bnx2_set_power_state(bp, PCI_D0);
7343
Michael Chanb6016b72005-05-26 13:03:09 -07007344 if (data == 0)
7345 data = 2;
7346
7347 save = REG_RD(bp, BNX2_MISC_CFG);
7348 REG_WR(bp, BNX2_MISC_CFG, BNX2_MISC_CFG_LEDMODE_MAC);
7349
7350 for (i = 0; i < (data * 2); i++) {
7351 if ((i % 2) == 0) {
7352 REG_WR(bp, BNX2_EMAC_LED, BNX2_EMAC_LED_OVERRIDE);
7353 }
7354 else {
7355 REG_WR(bp, BNX2_EMAC_LED, BNX2_EMAC_LED_OVERRIDE |
7356 BNX2_EMAC_LED_1000MB_OVERRIDE |
7357 BNX2_EMAC_LED_100MB_OVERRIDE |
7358 BNX2_EMAC_LED_10MB_OVERRIDE |
7359 BNX2_EMAC_LED_TRAFFIC_OVERRIDE |
7360 BNX2_EMAC_LED_TRAFFIC);
7361 }
7362 msleep_interruptible(500);
7363 if (signal_pending(current))
7364 break;
7365 }
7366 REG_WR(bp, BNX2_EMAC_LED, 0);
7367 REG_WR(bp, BNX2_MISC_CFG, save);
Michael Chan9f52b562008-10-09 12:21:46 -07007368
7369 if (!netif_running(dev))
7370 bnx2_set_power_state(bp, PCI_D3hot);
7371
Michael Chanb6016b72005-05-26 13:03:09 -07007372 return 0;
7373}
7374
Michael Chan4666f872007-05-03 13:22:28 -07007375static int
7376bnx2_set_tx_csum(struct net_device *dev, u32 data)
7377{
7378 struct bnx2 *bp = netdev_priv(dev);
7379
7380 if (CHIP_NUM(bp) == CHIP_NUM_5709)
Michael Chan6460d942007-07-14 19:07:52 -07007381 return (ethtool_op_set_tx_ipv6_csum(dev, data));
Michael Chan4666f872007-05-03 13:22:28 -07007382 else
7383 return (ethtool_op_set_tx_csum(dev, data));
7384}
7385
Jeff Garzik7282d492006-09-13 14:30:00 -04007386static const struct ethtool_ops bnx2_ethtool_ops = {
Michael Chanb6016b72005-05-26 13:03:09 -07007387 .get_settings = bnx2_get_settings,
7388 .set_settings = bnx2_set_settings,
7389 .get_drvinfo = bnx2_get_drvinfo,
Michael Chan244ac4f2006-03-20 17:48:46 -08007390 .get_regs_len = bnx2_get_regs_len,
7391 .get_regs = bnx2_get_regs,
Michael Chanb6016b72005-05-26 13:03:09 -07007392 .get_wol = bnx2_get_wol,
7393 .set_wol = bnx2_set_wol,
7394 .nway_reset = bnx2_nway_reset,
7395 .get_link = ethtool_op_get_link,
7396 .get_eeprom_len = bnx2_get_eeprom_len,
7397 .get_eeprom = bnx2_get_eeprom,
7398 .set_eeprom = bnx2_set_eeprom,
7399 .get_coalesce = bnx2_get_coalesce,
7400 .set_coalesce = bnx2_set_coalesce,
7401 .get_ringparam = bnx2_get_ringparam,
7402 .set_ringparam = bnx2_set_ringparam,
7403 .get_pauseparam = bnx2_get_pauseparam,
7404 .set_pauseparam = bnx2_set_pauseparam,
7405 .get_rx_csum = bnx2_get_rx_csum,
7406 .set_rx_csum = bnx2_set_rx_csum,
Michael Chan4666f872007-05-03 13:22:28 -07007407 .set_tx_csum = bnx2_set_tx_csum,
Michael Chanb6016b72005-05-26 13:03:09 -07007408 .set_sg = ethtool_op_set_sg,
Michael Chanb11d6212006-06-29 12:31:21 -07007409 .set_tso = bnx2_set_tso,
Michael Chanb6016b72005-05-26 13:03:09 -07007410 .self_test = bnx2_self_test,
7411 .get_strings = bnx2_get_strings,
7412 .phys_id = bnx2_phys_id,
Michael Chanb6016b72005-05-26 13:03:09 -07007413 .get_ethtool_stats = bnx2_get_ethtool_stats,
Jeff Garzikb9f2c042007-10-03 18:07:32 -07007414 .get_sset_count = bnx2_get_sset_count,
Michael Chanb6016b72005-05-26 13:03:09 -07007415};
7416
7417/* Called with rtnl_lock */
7418static int
7419bnx2_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
7420{
Peter Hagervall14ab9b82005-08-10 14:18:16 -07007421 struct mii_ioctl_data *data = if_mii(ifr);
Michael Chan972ec0d2006-01-23 16:12:43 -08007422 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007423 int err;
7424
7425 switch(cmd) {
7426 case SIOCGMIIPHY:
7427 data->phy_id = bp->phy_addr;
7428
7429 /* fallthru */
7430 case SIOCGMIIREG: {
7431 u32 mii_regval;
7432
Michael Chan583c28e2008-01-21 19:51:35 -08007433 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
Michael Chan7b6b8342007-07-07 22:50:15 -07007434 return -EOPNOTSUPP;
7435
Michael Chandad3e452007-05-03 13:18:03 -07007436 if (!netif_running(dev))
7437 return -EAGAIN;
7438
Michael Chanc770a652005-08-25 15:38:39 -07007439 spin_lock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07007440 err = bnx2_read_phy(bp, data->reg_num & 0x1f, &mii_regval);
Michael Chanc770a652005-08-25 15:38:39 -07007441 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07007442
7443 data->val_out = mii_regval;
7444
7445 return err;
7446 }
7447
7448 case SIOCSMIIREG:
7449 if (!capable(CAP_NET_ADMIN))
7450 return -EPERM;
7451
Michael Chan583c28e2008-01-21 19:51:35 -08007452 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
Michael Chan7b6b8342007-07-07 22:50:15 -07007453 return -EOPNOTSUPP;
7454
Michael Chandad3e452007-05-03 13:18:03 -07007455 if (!netif_running(dev))
7456 return -EAGAIN;
7457
Michael Chanc770a652005-08-25 15:38:39 -07007458 spin_lock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07007459 err = bnx2_write_phy(bp, data->reg_num & 0x1f, data->val_in);
Michael Chanc770a652005-08-25 15:38:39 -07007460 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07007461
7462 return err;
7463
7464 default:
7465 /* do nothing */
7466 break;
7467 }
7468 return -EOPNOTSUPP;
7469}
7470
7471/* Called with rtnl_lock */
7472static int
7473bnx2_change_mac_addr(struct net_device *dev, void *p)
7474{
7475 struct sockaddr *addr = p;
Michael Chan972ec0d2006-01-23 16:12:43 -08007476 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007477
Michael Chan73eef4c2005-08-25 15:39:15 -07007478 if (!is_valid_ether_addr(addr->sa_data))
7479 return -EINVAL;
7480
Michael Chanb6016b72005-05-26 13:03:09 -07007481 memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
7482 if (netif_running(dev))
Benjamin Li5fcaed02008-07-14 22:39:52 -07007483 bnx2_set_mac_addr(bp, bp->dev->dev_addr, 0);
Michael Chanb6016b72005-05-26 13:03:09 -07007484
7485 return 0;
7486}
7487
7488/* Called with rtnl_lock */
7489static int
7490bnx2_change_mtu(struct net_device *dev, int new_mtu)
7491{
Michael Chan972ec0d2006-01-23 16:12:43 -08007492 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007493
7494 if (((new_mtu + ETH_HLEN) > MAX_ETHERNET_JUMBO_PACKET_SIZE) ||
7495 ((new_mtu + ETH_HLEN) < MIN_ETHERNET_PACKET_SIZE))
7496 return -EINVAL;
7497
7498 dev->mtu = new_mtu;
Michael Chan5d5d0012007-12-12 11:17:43 -08007499 return (bnx2_change_ring_size(bp, bp->rx_ring_size, bp->tx_ring_size));
Michael Chanb6016b72005-05-26 13:03:09 -07007500}
7501
7502#if defined(HAVE_POLL_CONTROLLER) || defined(CONFIG_NET_POLL_CONTROLLER)
7503static void
7504poll_bnx2(struct net_device *dev)
7505{
Michael Chan972ec0d2006-01-23 16:12:43 -08007506 struct bnx2 *bp = netdev_priv(dev);
Neil Hormanb2af2c12008-11-12 16:23:44 -08007507 int i;
Michael Chanb6016b72005-05-26 13:03:09 -07007508
Neil Hormanb2af2c12008-11-12 16:23:44 -08007509 for (i = 0; i < bp->irq_nvecs; i++) {
7510 disable_irq(bp->irq_tbl[i].vector);
7511 bnx2_interrupt(bp->irq_tbl[i].vector, &bp->bnx2_napi[i]);
7512 enable_irq(bp->irq_tbl[i].vector);
7513 }
Michael Chanb6016b72005-05-26 13:03:09 -07007514}
7515#endif
7516
Michael Chan253c8b72007-01-08 19:56:01 -08007517static void __devinit
7518bnx2_get_5709_media(struct bnx2 *bp)
7519{
7520 u32 val = REG_RD(bp, BNX2_MISC_DUAL_MEDIA_CTRL);
7521 u32 bond_id = val & BNX2_MISC_DUAL_MEDIA_CTRL_BOND_ID;
7522 u32 strap;
7523
7524 if (bond_id == BNX2_MISC_DUAL_MEDIA_CTRL_BOND_ID_C)
7525 return;
7526 else if (bond_id == BNX2_MISC_DUAL_MEDIA_CTRL_BOND_ID_S) {
Michael Chan583c28e2008-01-21 19:51:35 -08007527 bp->phy_flags |= BNX2_PHY_FLAG_SERDES;
Michael Chan253c8b72007-01-08 19:56:01 -08007528 return;
7529 }
7530
7531 if (val & BNX2_MISC_DUAL_MEDIA_CTRL_STRAP_OVERRIDE)
7532 strap = (val & BNX2_MISC_DUAL_MEDIA_CTRL_PHY_CTRL) >> 21;
7533 else
7534 strap = (val & BNX2_MISC_DUAL_MEDIA_CTRL_PHY_CTRL_STRAP) >> 8;
7535
7536 if (PCI_FUNC(bp->pdev->devfn) == 0) {
7537 switch (strap) {
7538 case 0x4:
7539 case 0x5:
7540 case 0x6:
Michael Chan583c28e2008-01-21 19:51:35 -08007541 bp->phy_flags |= BNX2_PHY_FLAG_SERDES;
Michael Chan253c8b72007-01-08 19:56:01 -08007542 return;
7543 }
7544 } else {
7545 switch (strap) {
7546 case 0x1:
7547 case 0x2:
7548 case 0x4:
Michael Chan583c28e2008-01-21 19:51:35 -08007549 bp->phy_flags |= BNX2_PHY_FLAG_SERDES;
Michael Chan253c8b72007-01-08 19:56:01 -08007550 return;
7551 }
7552 }
7553}
7554
Michael Chan883e5152007-05-03 13:25:11 -07007555static void __devinit
7556bnx2_get_pci_speed(struct bnx2 *bp)
7557{
7558 u32 reg;
7559
7560 reg = REG_RD(bp, BNX2_PCICFG_MISC_STATUS);
7561 if (reg & BNX2_PCICFG_MISC_STATUS_PCIX_DET) {
7562 u32 clkreg;
7563
David S. Millerf86e82f2008-01-21 17:15:40 -08007564 bp->flags |= BNX2_FLAG_PCIX;
Michael Chan883e5152007-05-03 13:25:11 -07007565
7566 clkreg = REG_RD(bp, BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS);
7567
7568 clkreg &= BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET;
7569 switch (clkreg) {
7570 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_133MHZ:
7571 bp->bus_speed_mhz = 133;
7572 break;
7573
7574 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_95MHZ:
7575 bp->bus_speed_mhz = 100;
7576 break;
7577
7578 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_66MHZ:
7579 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_80MHZ:
7580 bp->bus_speed_mhz = 66;
7581 break;
7582
7583 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_48MHZ:
7584 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_55MHZ:
7585 bp->bus_speed_mhz = 50;
7586 break;
7587
7588 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_LOW:
7589 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_32MHZ:
7590 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_38MHZ:
7591 bp->bus_speed_mhz = 33;
7592 break;
7593 }
7594 }
7595 else {
7596 if (reg & BNX2_PCICFG_MISC_STATUS_M66EN)
7597 bp->bus_speed_mhz = 66;
7598 else
7599 bp->bus_speed_mhz = 33;
7600 }
7601
7602 if (reg & BNX2_PCICFG_MISC_STATUS_32BIT_DET)
David S. Millerf86e82f2008-01-21 17:15:40 -08007603 bp->flags |= BNX2_FLAG_PCI_32BIT;
Michael Chan883e5152007-05-03 13:25:11 -07007604
7605}
7606
Michael Chanb6016b72005-05-26 13:03:09 -07007607static int __devinit
7608bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
7609{
7610 struct bnx2 *bp;
7611 unsigned long mem_len;
Michael Chan58fc2ea2007-07-07 22:52:02 -07007612 int rc, i, j;
Michael Chanb6016b72005-05-26 13:03:09 -07007613 u32 reg;
Michael Chan40453c82007-05-03 13:19:18 -07007614 u64 dma_mask, persist_dma_mask;
Michael Chanb6016b72005-05-26 13:03:09 -07007615
Michael Chanb6016b72005-05-26 13:03:09 -07007616 SET_NETDEV_DEV(dev, &pdev->dev);
Michael Chan972ec0d2006-01-23 16:12:43 -08007617 bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007618
7619 bp->flags = 0;
7620 bp->phy_flags = 0;
7621
7622 /* enable device (incl. PCI PM wakeup), and bus-mastering */
7623 rc = pci_enable_device(pdev);
7624 if (rc) {
Joe Perches898eb712007-10-18 03:06:30 -07007625 dev_err(&pdev->dev, "Cannot enable PCI device, aborting.\n");
Michael Chanb6016b72005-05-26 13:03:09 -07007626 goto err_out;
7627 }
7628
7629 if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) {
Jeff Garzik9b91cf92006-06-27 11:39:50 -04007630 dev_err(&pdev->dev,
Jeff Garzik2e8a5382006-06-27 10:47:51 -04007631 "Cannot find PCI device base address, aborting.\n");
Michael Chanb6016b72005-05-26 13:03:09 -07007632 rc = -ENODEV;
7633 goto err_out_disable;
7634 }
7635
7636 rc = pci_request_regions(pdev, DRV_MODULE_NAME);
7637 if (rc) {
Jeff Garzik9b91cf92006-06-27 11:39:50 -04007638 dev_err(&pdev->dev, "Cannot obtain PCI resources, aborting.\n");
Michael Chanb6016b72005-05-26 13:03:09 -07007639 goto err_out_disable;
7640 }
7641
7642 pci_set_master(pdev);
Wendy Xiong6ff2da42008-05-16 22:18:21 -07007643 pci_save_state(pdev);
Michael Chanb6016b72005-05-26 13:03:09 -07007644
7645 bp->pm_cap = pci_find_capability(pdev, PCI_CAP_ID_PM);
7646 if (bp->pm_cap == 0) {
Jeff Garzik9b91cf92006-06-27 11:39:50 -04007647 dev_err(&pdev->dev,
Jeff Garzik2e8a5382006-06-27 10:47:51 -04007648 "Cannot find power management capability, aborting.\n");
Michael Chanb6016b72005-05-26 13:03:09 -07007649 rc = -EIO;
7650 goto err_out_release;
7651 }
7652
Michael Chanb6016b72005-05-26 13:03:09 -07007653 bp->dev = dev;
7654 bp->pdev = pdev;
7655
7656 spin_lock_init(&bp->phy_lock);
Michael Chan1b8227c2007-05-03 13:24:05 -07007657 spin_lock_init(&bp->indirect_lock);
David Howellsc4028952006-11-22 14:57:56 +00007658 INIT_WORK(&bp->reset_task, bnx2_reset_task);
Michael Chanb6016b72005-05-26 13:03:09 -07007659
7660 dev->base_addr = dev->mem_start = pci_resource_start(pdev, 0);
Michael Chan4edd4732009-06-08 18:14:42 -07007661 mem_len = MB_GET_CID_ADDR(TX_TSS_CID + TX_MAX_TSS_RINGS + 1);
Michael Chanb6016b72005-05-26 13:03:09 -07007662 dev->mem_end = dev->mem_start + mem_len;
7663 dev->irq = pdev->irq;
7664
7665 bp->regview = ioremap_nocache(dev->base_addr, mem_len);
7666
7667 if (!bp->regview) {
Jeff Garzik9b91cf92006-06-27 11:39:50 -04007668 dev_err(&pdev->dev, "Cannot map register space, aborting.\n");
Michael Chanb6016b72005-05-26 13:03:09 -07007669 rc = -ENOMEM;
7670 goto err_out_release;
7671 }
7672
7673 /* Configure byte swap and enable write to the reg_window registers.
7674 * Rely on CPU to do target byte swapping on big endian systems
7675 * The chip's target access swapping will not swap all accesses
7676 */
7677 pci_write_config_dword(bp->pdev, BNX2_PCICFG_MISC_CONFIG,
7678 BNX2_PCICFG_MISC_CONFIG_REG_WINDOW_ENA |
7679 BNX2_PCICFG_MISC_CONFIG_TARGET_MB_WORD_SWAP);
7680
Pavel Machek829ca9a2005-09-03 15:56:56 -07007681 bnx2_set_power_state(bp, PCI_D0);
Michael Chanb6016b72005-05-26 13:03:09 -07007682
7683 bp->chip_id = REG_RD(bp, BNX2_MISC_ID);
7684
Michael Chan883e5152007-05-03 13:25:11 -07007685 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
7686 if (pci_find_capability(pdev, PCI_CAP_ID_EXP) == 0) {
7687 dev_err(&pdev->dev,
7688 "Cannot find PCIE capability, aborting.\n");
7689 rc = -EIO;
7690 goto err_out_unmap;
7691 }
David S. Millerf86e82f2008-01-21 17:15:40 -08007692 bp->flags |= BNX2_FLAG_PCIE;
Michael Chan2dd201d2008-01-21 17:06:09 -08007693 if (CHIP_REV(bp) == CHIP_REV_Ax)
David S. Millerf86e82f2008-01-21 17:15:40 -08007694 bp->flags |= BNX2_FLAG_JUMBO_BROKEN;
Michael Chan883e5152007-05-03 13:25:11 -07007695 } else {
Michael Chan59b47d82006-11-19 14:10:45 -08007696 bp->pcix_cap = pci_find_capability(pdev, PCI_CAP_ID_PCIX);
7697 if (bp->pcix_cap == 0) {
7698 dev_err(&pdev->dev,
7699 "Cannot find PCIX capability, aborting.\n");
7700 rc = -EIO;
7701 goto err_out_unmap;
7702 }
7703 }
7704
Michael Chanb4b36042007-12-20 19:59:30 -08007705 if (CHIP_NUM(bp) == CHIP_NUM_5709 && CHIP_REV(bp) != CHIP_REV_Ax) {
7706 if (pci_find_capability(pdev, PCI_CAP_ID_MSIX))
David S. Millerf86e82f2008-01-21 17:15:40 -08007707 bp->flags |= BNX2_FLAG_MSIX_CAP;
Michael Chanb4b36042007-12-20 19:59:30 -08007708 }
7709
Michael Chan8e6a72c2007-05-03 13:24:48 -07007710 if (CHIP_ID(bp) != CHIP_ID_5706_A0 && CHIP_ID(bp) != CHIP_ID_5706_A1) {
7711 if (pci_find_capability(pdev, PCI_CAP_ID_MSI))
David S. Millerf86e82f2008-01-21 17:15:40 -08007712 bp->flags |= BNX2_FLAG_MSI_CAP;
Michael Chan8e6a72c2007-05-03 13:24:48 -07007713 }
7714
Michael Chan40453c82007-05-03 13:19:18 -07007715 /* 5708 cannot support DMA addresses > 40-bit. */
7716 if (CHIP_NUM(bp) == CHIP_NUM_5708)
Yang Hongyang50cf1562009-04-06 19:01:14 -07007717 persist_dma_mask = dma_mask = DMA_BIT_MASK(40);
Michael Chan40453c82007-05-03 13:19:18 -07007718 else
Yang Hongyang6a355282009-04-06 19:01:13 -07007719 persist_dma_mask = dma_mask = DMA_BIT_MASK(64);
Michael Chan40453c82007-05-03 13:19:18 -07007720
7721 /* Configure DMA attributes. */
7722 if (pci_set_dma_mask(pdev, dma_mask) == 0) {
7723 dev->features |= NETIF_F_HIGHDMA;
7724 rc = pci_set_consistent_dma_mask(pdev, persist_dma_mask);
7725 if (rc) {
7726 dev_err(&pdev->dev,
7727 "pci_set_consistent_dma_mask failed, aborting.\n");
7728 goto err_out_unmap;
7729 }
Yang Hongyang284901a2009-04-06 19:01:15 -07007730 } else if ((rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) != 0) {
Michael Chan40453c82007-05-03 13:19:18 -07007731 dev_err(&pdev->dev, "System does not support DMA, aborting.\n");
7732 goto err_out_unmap;
7733 }
7734
David S. Millerf86e82f2008-01-21 17:15:40 -08007735 if (!(bp->flags & BNX2_FLAG_PCIE))
Michael Chan883e5152007-05-03 13:25:11 -07007736 bnx2_get_pci_speed(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07007737
7738 /* 5706A0 may falsely detect SERR and PERR. */
7739 if (CHIP_ID(bp) == CHIP_ID_5706_A0) {
7740 reg = REG_RD(bp, PCI_COMMAND);
7741 reg &= ~(PCI_COMMAND_SERR | PCI_COMMAND_PARITY);
7742 REG_WR(bp, PCI_COMMAND, reg);
7743 }
7744 else if ((CHIP_ID(bp) == CHIP_ID_5706_A1) &&
David S. Millerf86e82f2008-01-21 17:15:40 -08007745 !(bp->flags & BNX2_FLAG_PCIX)) {
Michael Chanb6016b72005-05-26 13:03:09 -07007746
Jeff Garzik9b91cf92006-06-27 11:39:50 -04007747 dev_err(&pdev->dev,
Jeff Garzik2e8a5382006-06-27 10:47:51 -04007748 "5706 A1 can only be used in a PCIX bus, aborting.\n");
Michael Chanb6016b72005-05-26 13:03:09 -07007749 goto err_out_unmap;
7750 }
7751
7752 bnx2_init_nvram(bp);
7753
Michael Chan2726d6e2008-01-29 21:35:05 -08007754 reg = bnx2_reg_rd_ind(bp, BNX2_SHM_HDR_SIGNATURE);
Michael Chane3648b32005-11-04 08:51:21 -08007755
7756 if ((reg & BNX2_SHM_HDR_SIGNATURE_SIG_MASK) ==
Michael Chan24cb2302007-01-25 15:49:56 -08007757 BNX2_SHM_HDR_SIGNATURE_SIG) {
7758 u32 off = PCI_FUNC(pdev->devfn) << 2;
7759
Michael Chan2726d6e2008-01-29 21:35:05 -08007760 bp->shmem_base = bnx2_reg_rd_ind(bp, BNX2_SHM_HDR_ADDR_0 + off);
Michael Chan24cb2302007-01-25 15:49:56 -08007761 } else
Michael Chane3648b32005-11-04 08:51:21 -08007762 bp->shmem_base = HOST_VIEW_SHMEM_BASE;
7763
Michael Chanb6016b72005-05-26 13:03:09 -07007764 /* Get the permanent MAC address. First we need to make sure the
7765 * firmware is actually running.
7766 */
Michael Chan2726d6e2008-01-29 21:35:05 -08007767 reg = bnx2_shmem_rd(bp, BNX2_DEV_INFO_SIGNATURE);
Michael Chanb6016b72005-05-26 13:03:09 -07007768
7769 if ((reg & BNX2_DEV_INFO_SIGNATURE_MAGIC_MASK) !=
7770 BNX2_DEV_INFO_SIGNATURE_MAGIC) {
Jeff Garzik9b91cf92006-06-27 11:39:50 -04007771 dev_err(&pdev->dev, "Firmware not running, aborting.\n");
Michael Chanb6016b72005-05-26 13:03:09 -07007772 rc = -ENODEV;
7773 goto err_out_unmap;
7774 }
7775
Michael Chan2726d6e2008-01-29 21:35:05 -08007776 reg = bnx2_shmem_rd(bp, BNX2_DEV_INFO_BC_REV);
Michael Chan58fc2ea2007-07-07 22:52:02 -07007777 for (i = 0, j = 0; i < 3; i++) {
7778 u8 num, k, skip0;
7779
7780 num = (u8) (reg >> (24 - (i * 8)));
7781 for (k = 100, skip0 = 1; k >= 1; num %= k, k /= 10) {
7782 if (num >= k || !skip0 || k == 1) {
7783 bp->fw_version[j++] = (num / k) + '0';
7784 skip0 = 0;
7785 }
7786 }
7787 if (i != 2)
7788 bp->fw_version[j++] = '.';
7789 }
Michael Chan2726d6e2008-01-29 21:35:05 -08007790 reg = bnx2_shmem_rd(bp, BNX2_PORT_FEATURE);
Michael Chan846f5c62007-10-10 16:16:51 -07007791 if (reg & BNX2_PORT_FEATURE_WOL_ENABLED)
7792 bp->wol = 1;
7793
7794 if (reg & BNX2_PORT_FEATURE_ASF_ENABLED) {
David S. Millerf86e82f2008-01-21 17:15:40 -08007795 bp->flags |= BNX2_FLAG_ASF_ENABLE;
Michael Chanc2d3db82007-07-16 18:26:43 -07007796
7797 for (i = 0; i < 30; i++) {
Michael Chan2726d6e2008-01-29 21:35:05 -08007798 reg = bnx2_shmem_rd(bp, BNX2_BC_STATE_CONDITION);
Michael Chanc2d3db82007-07-16 18:26:43 -07007799 if (reg & BNX2_CONDITION_MFW_RUN_MASK)
7800 break;
7801 msleep(10);
7802 }
7803 }
Michael Chan2726d6e2008-01-29 21:35:05 -08007804 reg = bnx2_shmem_rd(bp, BNX2_BC_STATE_CONDITION);
Michael Chan58fc2ea2007-07-07 22:52:02 -07007805 reg &= BNX2_CONDITION_MFW_RUN_MASK;
7806 if (reg != BNX2_CONDITION_MFW_RUN_UNKNOWN &&
7807 reg != BNX2_CONDITION_MFW_RUN_NONE) {
Michael Chan2726d6e2008-01-29 21:35:05 -08007808 u32 addr = bnx2_shmem_rd(bp, BNX2_MFW_VER_PTR);
Michael Chan58fc2ea2007-07-07 22:52:02 -07007809
7810 bp->fw_version[j++] = ' ';
7811 for (i = 0; i < 3; i++) {
Michael Chan2726d6e2008-01-29 21:35:05 -08007812 reg = bnx2_reg_rd_ind(bp, addr + i * 4);
Michael Chan58fc2ea2007-07-07 22:52:02 -07007813 reg = swab32(reg);
7814 memcpy(&bp->fw_version[j], &reg, 4);
7815 j += 4;
7816 }
7817 }
Michael Chanb6016b72005-05-26 13:03:09 -07007818
Michael Chan2726d6e2008-01-29 21:35:05 -08007819 reg = bnx2_shmem_rd(bp, BNX2_PORT_HW_CFG_MAC_UPPER);
Michael Chanb6016b72005-05-26 13:03:09 -07007820 bp->mac_addr[0] = (u8) (reg >> 8);
7821 bp->mac_addr[1] = (u8) reg;
7822
Michael Chan2726d6e2008-01-29 21:35:05 -08007823 reg = bnx2_shmem_rd(bp, BNX2_PORT_HW_CFG_MAC_LOWER);
Michael Chanb6016b72005-05-26 13:03:09 -07007824 bp->mac_addr[2] = (u8) (reg >> 24);
7825 bp->mac_addr[3] = (u8) (reg >> 16);
7826 bp->mac_addr[4] = (u8) (reg >> 8);
7827 bp->mac_addr[5] = (u8) reg;
7828
7829 bp->tx_ring_size = MAX_TX_DESC_CNT;
Michael Chan932f3772006-08-15 01:39:36 -07007830 bnx2_set_rx_ring_size(bp, 255);
Michael Chanb6016b72005-05-26 13:03:09 -07007831
7832 bp->rx_csum = 1;
7833
Michael Chanb6016b72005-05-26 13:03:09 -07007834 bp->tx_quick_cons_trip_int = 20;
7835 bp->tx_quick_cons_trip = 20;
7836 bp->tx_ticks_int = 80;
7837 bp->tx_ticks = 80;
Jeff Garzik6aa20a22006-09-13 13:24:59 -04007838
Michael Chanb6016b72005-05-26 13:03:09 -07007839 bp->rx_quick_cons_trip_int = 6;
7840 bp->rx_quick_cons_trip = 6;
7841 bp->rx_ticks_int = 18;
7842 bp->rx_ticks = 18;
7843
Michael Chan7ea69202007-07-16 18:27:10 -07007844 bp->stats_ticks = USEC_PER_SEC & BNX2_HC_STATS_TICKS_HC_STAT_TICKS;
Michael Chanb6016b72005-05-26 13:03:09 -07007845
Benjamin Liac392ab2008-09-18 16:40:49 -07007846 bp->current_interval = BNX2_TIMER_INTERVAL;
Michael Chanb6016b72005-05-26 13:03:09 -07007847
Michael Chan5b0c76a2005-11-04 08:45:49 -08007848 bp->phy_addr = 1;
7849
Michael Chanb6016b72005-05-26 13:03:09 -07007850 /* Disable WOL support if we are running on a SERDES chip. */
Michael Chan253c8b72007-01-08 19:56:01 -08007851 if (CHIP_NUM(bp) == CHIP_NUM_5709)
7852 bnx2_get_5709_media(bp);
7853 else if (CHIP_BOND_ID(bp) & CHIP_BOND_ID_SERDES_BIT)
Michael Chan583c28e2008-01-21 19:51:35 -08007854 bp->phy_flags |= BNX2_PHY_FLAG_SERDES;
Michael Chanbac0dff2006-11-19 14:15:05 -08007855
Michael Chan0d8a6572007-07-07 22:49:43 -07007856 bp->phy_port = PORT_TP;
Michael Chan583c28e2008-01-21 19:51:35 -08007857 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Michael Chan0d8a6572007-07-07 22:49:43 -07007858 bp->phy_port = PORT_FIBRE;
Michael Chan2726d6e2008-01-29 21:35:05 -08007859 reg = bnx2_shmem_rd(bp, BNX2_SHARED_HW_CFG_CONFIG);
Michael Chan846f5c62007-10-10 16:16:51 -07007860 if (!(reg & BNX2_SHARED_HW_CFG_GIG_LINK_ON_VAUX)) {
David S. Millerf86e82f2008-01-21 17:15:40 -08007861 bp->flags |= BNX2_FLAG_NO_WOL;
Michael Chan846f5c62007-10-10 16:16:51 -07007862 bp->wol = 0;
7863 }
Michael Chan38ea3682008-02-23 19:48:57 -08007864 if (CHIP_NUM(bp) == CHIP_NUM_5706) {
7865 /* Don't do parallel detect on this board because of
7866 * some board problems. The link will not go down
7867 * if we do parallel detect.
7868 */
7869 if (pdev->subsystem_vendor == PCI_VENDOR_ID_HP &&
7870 pdev->subsystem_device == 0x310c)
7871 bp->phy_flags |= BNX2_PHY_FLAG_NO_PARALLEL;
7872 } else {
Michael Chan5b0c76a2005-11-04 08:45:49 -08007873 bp->phy_addr = 2;
Michael Chan5b0c76a2005-11-04 08:45:49 -08007874 if (reg & BNX2_SHARED_HW_CFG_PHY_2_5G)
Michael Chan583c28e2008-01-21 19:51:35 -08007875 bp->phy_flags |= BNX2_PHY_FLAG_2_5G_CAPABLE;
Michael Chan5b0c76a2005-11-04 08:45:49 -08007876 }
Michael Chan261dd5c2007-01-08 19:55:46 -08007877 } else if (CHIP_NUM(bp) == CHIP_NUM_5706 ||
7878 CHIP_NUM(bp) == CHIP_NUM_5708)
Michael Chan583c28e2008-01-21 19:51:35 -08007879 bp->phy_flags |= BNX2_PHY_FLAG_CRC_FIX;
Michael Chanfb0c18b2007-12-10 17:18:23 -08007880 else if (CHIP_NUM(bp) == CHIP_NUM_5709 &&
7881 (CHIP_REV(bp) == CHIP_REV_Ax ||
7882 CHIP_REV(bp) == CHIP_REV_Bx))
Michael Chan583c28e2008-01-21 19:51:35 -08007883 bp->phy_flags |= BNX2_PHY_FLAG_DIS_EARLY_DAC;
Michael Chanb6016b72005-05-26 13:03:09 -07007884
Michael Chan7c62e832008-07-14 22:39:03 -07007885 bnx2_init_fw_cap(bp);
7886
Michael Chan16088272006-06-12 22:16:43 -07007887 if ((CHIP_ID(bp) == CHIP_ID_5708_A0) ||
7888 (CHIP_ID(bp) == CHIP_ID_5708_B0) ||
Michael Chan5ec6d7b2008-11-12 16:01:41 -08007889 (CHIP_ID(bp) == CHIP_ID_5708_B1) ||
7890 !(REG_RD(bp, BNX2_PCI_CONFIG_3) & BNX2_PCI_CONFIG_3_VAUX_PRESET)) {
David S. Millerf86e82f2008-01-21 17:15:40 -08007891 bp->flags |= BNX2_FLAG_NO_WOL;
Michael Chan846f5c62007-10-10 16:16:51 -07007892 bp->wol = 0;
7893 }
Michael Chandda1e392006-01-23 16:08:14 -08007894
Michael Chanb6016b72005-05-26 13:03:09 -07007895 if (CHIP_ID(bp) == CHIP_ID_5706_A0) {
7896 bp->tx_quick_cons_trip_int =
7897 bp->tx_quick_cons_trip;
7898 bp->tx_ticks_int = bp->tx_ticks;
7899 bp->rx_quick_cons_trip_int =
7900 bp->rx_quick_cons_trip;
7901 bp->rx_ticks_int = bp->rx_ticks;
7902 bp->comp_prod_trip_int = bp->comp_prod_trip;
7903 bp->com_ticks_int = bp->com_ticks;
7904 bp->cmd_ticks_int = bp->cmd_ticks;
7905 }
7906
Michael Chanf9317a42006-09-29 17:06:23 -07007907 /* Disable MSI on 5706 if AMD 8132 bridge is found.
7908 *
7909 * MSI is defined to be 32-bit write. The 5706 does 64-bit MSI writes
7910 * with byte enables disabled on the unused 32-bit word. This is legal
7911 * but causes problems on the AMD 8132 which will eventually stop
7912 * responding after a while.
7913 *
7914 * AMD believes this incompatibility is unique to the 5706, and
Michael Ellerman88187df2007-01-25 19:34:07 +11007915 * prefers to locally disable MSI rather than globally disabling it.
Michael Chanf9317a42006-09-29 17:06:23 -07007916 */
7917 if (CHIP_NUM(bp) == CHIP_NUM_5706 && disable_msi == 0) {
7918 struct pci_dev *amd_8132 = NULL;
7919
7920 while ((amd_8132 = pci_get_device(PCI_VENDOR_ID_AMD,
7921 PCI_DEVICE_ID_AMD_8132_BRIDGE,
7922 amd_8132))) {
Michael Chanf9317a42006-09-29 17:06:23 -07007923
Auke Kok44c10132007-06-08 15:46:36 -07007924 if (amd_8132->revision >= 0x10 &&
7925 amd_8132->revision <= 0x13) {
Michael Chanf9317a42006-09-29 17:06:23 -07007926 disable_msi = 1;
7927 pci_dev_put(amd_8132);
7928 break;
7929 }
7930 }
7931 }
7932
Michael Chandeaf3912007-07-07 22:48:00 -07007933 bnx2_set_default_link(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07007934 bp->req_flow_ctrl = FLOW_CTRL_RX | FLOW_CTRL_TX;
7935
Michael Chancd339a02005-08-25 15:35:24 -07007936 init_timer(&bp->timer);
Benjamin Liac392ab2008-09-18 16:40:49 -07007937 bp->timer.expires = RUN_AT(BNX2_TIMER_INTERVAL);
Michael Chancd339a02005-08-25 15:35:24 -07007938 bp->timer.data = (unsigned long) bp;
7939 bp->timer.function = bnx2_timer;
7940
Michael Chanb6016b72005-05-26 13:03:09 -07007941 return 0;
7942
7943err_out_unmap:
7944 if (bp->regview) {
7945 iounmap(bp->regview);
Michael Chan73eef4c2005-08-25 15:39:15 -07007946 bp->regview = NULL;
Michael Chanb6016b72005-05-26 13:03:09 -07007947 }
7948
7949err_out_release:
7950 pci_release_regions(pdev);
7951
7952err_out_disable:
7953 pci_disable_device(pdev);
7954 pci_set_drvdata(pdev, NULL);
7955
7956err_out:
7957 return rc;
7958}
7959
Michael Chan883e5152007-05-03 13:25:11 -07007960static char * __devinit
7961bnx2_bus_string(struct bnx2 *bp, char *str)
7962{
7963 char *s = str;
7964
David S. Millerf86e82f2008-01-21 17:15:40 -08007965 if (bp->flags & BNX2_FLAG_PCIE) {
Michael Chan883e5152007-05-03 13:25:11 -07007966 s += sprintf(s, "PCI Express");
7967 } else {
7968 s += sprintf(s, "PCI");
David S. Millerf86e82f2008-01-21 17:15:40 -08007969 if (bp->flags & BNX2_FLAG_PCIX)
Michael Chan883e5152007-05-03 13:25:11 -07007970 s += sprintf(s, "-X");
David S. Millerf86e82f2008-01-21 17:15:40 -08007971 if (bp->flags & BNX2_FLAG_PCI_32BIT)
Michael Chan883e5152007-05-03 13:25:11 -07007972 s += sprintf(s, " 32-bit");
7973 else
7974 s += sprintf(s, " 64-bit");
7975 s += sprintf(s, " %dMHz", bp->bus_speed_mhz);
7976 }
7977 return str;
7978}
7979
Michael Chan2ba582b2007-12-21 15:04:49 -08007980static void __devinit
Michael Chan35efa7c2007-12-20 19:56:37 -08007981bnx2_init_napi(struct bnx2 *bp)
7982{
Michael Chanb4b36042007-12-20 19:59:30 -08007983 int i;
Michael Chan35efa7c2007-12-20 19:56:37 -08007984
Michael Chanb4b36042007-12-20 19:59:30 -08007985 for (i = 0; i < BNX2_MAX_MSIX_VEC; i++) {
Michael Chan35e90102008-06-19 16:37:42 -07007986 struct bnx2_napi *bnapi = &bp->bnx2_napi[i];
7987 int (*poll)(struct napi_struct *, int);
7988
7989 if (i == 0)
7990 poll = bnx2_poll;
7991 else
Michael Chanf0ea2e62008-06-19 16:41:57 -07007992 poll = bnx2_poll_msix;
Michael Chan35e90102008-06-19 16:37:42 -07007993
7994 netif_napi_add(bp->dev, &bp->bnx2_napi[i].napi, poll, 64);
Michael Chanb4b36042007-12-20 19:59:30 -08007995 bnapi->bp = bp;
7996 }
Michael Chan35efa7c2007-12-20 19:56:37 -08007997}
7998
Stephen Hemminger0421eae2008-11-21 17:31:27 -08007999static const struct net_device_ops bnx2_netdev_ops = {
8000 .ndo_open = bnx2_open,
8001 .ndo_start_xmit = bnx2_start_xmit,
8002 .ndo_stop = bnx2_close,
8003 .ndo_get_stats = bnx2_get_stats,
8004 .ndo_set_rx_mode = bnx2_set_rx_mode,
8005 .ndo_do_ioctl = bnx2_ioctl,
8006 .ndo_validate_addr = eth_validate_addr,
8007 .ndo_set_mac_address = bnx2_change_mac_addr,
8008 .ndo_change_mtu = bnx2_change_mtu,
8009 .ndo_tx_timeout = bnx2_tx_timeout,
8010#ifdef BCM_VLAN
8011 .ndo_vlan_rx_register = bnx2_vlan_rx_register,
8012#endif
8013#if defined(HAVE_POLL_CONTROLLER) || defined(CONFIG_NET_POLL_CONTROLLER)
8014 .ndo_poll_controller = poll_bnx2,
8015#endif
8016};
8017
Michael Chan35efa7c2007-12-20 19:56:37 -08008018static int __devinit
Michael Chanb6016b72005-05-26 13:03:09 -07008019bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
8020{
8021 static int version_printed = 0;
8022 struct net_device *dev = NULL;
8023 struct bnx2 *bp;
Joe Perches0795af52007-10-03 17:59:30 -07008024 int rc;
Michael Chan883e5152007-05-03 13:25:11 -07008025 char str[40];
Michael Chanb6016b72005-05-26 13:03:09 -07008026
8027 if (version_printed++ == 0)
8028 printk(KERN_INFO "%s", version);
8029
8030 /* dev zeroed in init_etherdev */
Benjamin Li706bf242008-07-18 17:55:11 -07008031 dev = alloc_etherdev_mq(sizeof(*bp), TX_MAX_RINGS);
Michael Chanb6016b72005-05-26 13:03:09 -07008032
8033 if (!dev)
8034 return -ENOMEM;
8035
8036 rc = bnx2_init_board(pdev, dev);
8037 if (rc < 0) {
8038 free_netdev(dev);
8039 return rc;
8040 }
8041
Stephen Hemminger0421eae2008-11-21 17:31:27 -08008042 dev->netdev_ops = &bnx2_netdev_ops;
Michael Chanb6016b72005-05-26 13:03:09 -07008043 dev->watchdog_timeo = TX_TIMEOUT;
Michael Chanb6016b72005-05-26 13:03:09 -07008044 dev->ethtool_ops = &bnx2_ethtool_ops;
Michael Chanb6016b72005-05-26 13:03:09 -07008045
Michael Chan972ec0d2006-01-23 16:12:43 -08008046 bp = netdev_priv(dev);
Michael Chan35efa7c2007-12-20 19:56:37 -08008047 bnx2_init_napi(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07008048
Michael Chan1b2f9222007-05-03 13:20:19 -07008049 pci_set_drvdata(pdev, dev);
8050
Michael Chan57579f72009-04-04 16:51:14 -07008051 rc = bnx2_request_firmware(bp);
8052 if (rc)
8053 goto error;
8054
Michael Chan1b2f9222007-05-03 13:20:19 -07008055 memcpy(dev->dev_addr, bp->mac_addr, 6);
8056 memcpy(dev->perm_addr, bp->mac_addr, 6);
Michael Chan1b2f9222007-05-03 13:20:19 -07008057
Stephen Hemmingerd212f872007-06-27 00:47:37 -07008058 dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG;
Michael Chan4666f872007-05-03 13:22:28 -07008059 if (CHIP_NUM(bp) == CHIP_NUM_5709)
Stephen Hemmingerd212f872007-06-27 00:47:37 -07008060 dev->features |= NETIF_F_IPV6_CSUM;
8061
Michael Chan1b2f9222007-05-03 13:20:19 -07008062#ifdef BCM_VLAN
8063 dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
8064#endif
8065 dev->features |= NETIF_F_TSO | NETIF_F_TSO_ECN;
Michael Chan4666f872007-05-03 13:22:28 -07008066 if (CHIP_NUM(bp) == CHIP_NUM_5709)
8067 dev->features |= NETIF_F_TSO6;
Michael Chan1b2f9222007-05-03 13:20:19 -07008068
Michael Chanb6016b72005-05-26 13:03:09 -07008069 if ((rc = register_netdev(dev))) {
Jeff Garzik9b91cf92006-06-27 11:39:50 -04008070 dev_err(&pdev->dev, "Cannot register net device\n");
Michael Chan57579f72009-04-04 16:51:14 -07008071 goto error;
Michael Chanb6016b72005-05-26 13:03:09 -07008072 }
8073
Michael Chan883e5152007-05-03 13:25:11 -07008074 printk(KERN_INFO "%s: %s (%c%d) %s found at mem %lx, "
Johannes Berge1749612008-10-27 15:59:26 -07008075 "IRQ %d, node addr %pM\n",
Michael Chanb6016b72005-05-26 13:03:09 -07008076 dev->name,
Benjamin Lifbbf68b2008-09-18 16:40:03 -07008077 board_info[ent->driver_data].name,
Michael Chanb6016b72005-05-26 13:03:09 -07008078 ((CHIP_ID(bp) & 0xf000) >> 12) + 'A',
8079 ((CHIP_ID(bp) & 0x0ff0) >> 4),
Michael Chan883e5152007-05-03 13:25:11 -07008080 bnx2_bus_string(bp, str),
Michael Chanb6016b72005-05-26 13:03:09 -07008081 dev->base_addr,
Johannes Berge1749612008-10-27 15:59:26 -07008082 bp->pdev->irq, dev->dev_addr);
Michael Chanb6016b72005-05-26 13:03:09 -07008083
Michael Chanb6016b72005-05-26 13:03:09 -07008084 return 0;
Michael Chan57579f72009-04-04 16:51:14 -07008085
8086error:
8087 if (bp->mips_firmware)
8088 release_firmware(bp->mips_firmware);
8089 if (bp->rv2p_firmware)
8090 release_firmware(bp->rv2p_firmware);
8091
8092 if (bp->regview)
8093 iounmap(bp->regview);
8094 pci_release_regions(pdev);
8095 pci_disable_device(pdev);
8096 pci_set_drvdata(pdev, NULL);
8097 free_netdev(dev);
8098 return rc;
Michael Chanb6016b72005-05-26 13:03:09 -07008099}
8100
8101static void __devexit
8102bnx2_remove_one(struct pci_dev *pdev)
8103{
8104 struct net_device *dev = pci_get_drvdata(pdev);
Michael Chan972ec0d2006-01-23 16:12:43 -08008105 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07008106
Michael Chanafdc08b2005-08-25 15:34:29 -07008107 flush_scheduled_work();
8108
Michael Chanb6016b72005-05-26 13:03:09 -07008109 unregister_netdev(dev);
8110
Michael Chan57579f72009-04-04 16:51:14 -07008111 if (bp->mips_firmware)
8112 release_firmware(bp->mips_firmware);
8113 if (bp->rv2p_firmware)
8114 release_firmware(bp->rv2p_firmware);
8115
Michael Chanb6016b72005-05-26 13:03:09 -07008116 if (bp->regview)
8117 iounmap(bp->regview);
8118
8119 free_netdev(dev);
8120 pci_release_regions(pdev);
8121 pci_disable_device(pdev);
8122 pci_set_drvdata(pdev, NULL);
8123}
8124
8125static int
Pavel Machek829ca9a2005-09-03 15:56:56 -07008126bnx2_suspend(struct pci_dev *pdev, pm_message_t state)
Michael Chanb6016b72005-05-26 13:03:09 -07008127{
8128 struct net_device *dev = pci_get_drvdata(pdev);
Michael Chan972ec0d2006-01-23 16:12:43 -08008129 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07008130
Michael Chan6caebb02007-08-03 20:57:25 -07008131 /* PCI register 4 needs to be saved whether netif_running() or not.
8132 * MSI address and data need to be saved if using MSI and
8133 * netif_running().
8134 */
8135 pci_save_state(pdev);
Michael Chanb6016b72005-05-26 13:03:09 -07008136 if (!netif_running(dev))
8137 return 0;
8138
Michael Chan1d60290f2006-03-20 17:50:08 -08008139 flush_scheduled_work();
Michael Chanb6016b72005-05-26 13:03:09 -07008140 bnx2_netif_stop(bp);
8141 netif_device_detach(dev);
8142 del_timer_sync(&bp->timer);
Michael Chan74bf4ba2008-10-09 12:21:08 -07008143 bnx2_shutdown_chip(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07008144 bnx2_free_skbs(bp);
Pavel Machek829ca9a2005-09-03 15:56:56 -07008145 bnx2_set_power_state(bp, pci_choose_state(pdev, state));
Michael Chanb6016b72005-05-26 13:03:09 -07008146 return 0;
8147}
8148
8149static int
8150bnx2_resume(struct pci_dev *pdev)
8151{
8152 struct net_device *dev = pci_get_drvdata(pdev);
Michael Chan972ec0d2006-01-23 16:12:43 -08008153 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07008154
Michael Chan6caebb02007-08-03 20:57:25 -07008155 pci_restore_state(pdev);
Michael Chanb6016b72005-05-26 13:03:09 -07008156 if (!netif_running(dev))
8157 return 0;
8158
Pavel Machek829ca9a2005-09-03 15:56:56 -07008159 bnx2_set_power_state(bp, PCI_D0);
Michael Chanb6016b72005-05-26 13:03:09 -07008160 netif_device_attach(dev);
Michael Chan9a120bc2008-05-16 22:17:45 -07008161 bnx2_init_nic(bp, 1);
Michael Chanb6016b72005-05-26 13:03:09 -07008162 bnx2_netif_start(bp);
8163 return 0;
8164}
8165
Wendy Xiong6ff2da42008-05-16 22:18:21 -07008166/**
8167 * bnx2_io_error_detected - called when PCI error is detected
8168 * @pdev: Pointer to PCI device
8169 * @state: The current pci connection state
8170 *
8171 * This function is called after a PCI bus error affecting
8172 * this device has been detected.
8173 */
8174static pci_ers_result_t bnx2_io_error_detected(struct pci_dev *pdev,
8175 pci_channel_state_t state)
8176{
8177 struct net_device *dev = pci_get_drvdata(pdev);
8178 struct bnx2 *bp = netdev_priv(dev);
8179
8180 rtnl_lock();
8181 netif_device_detach(dev);
8182
8183 if (netif_running(dev)) {
8184 bnx2_netif_stop(bp);
8185 del_timer_sync(&bp->timer);
8186 bnx2_reset_nic(bp, BNX2_DRV_MSG_CODE_RESET);
8187 }
8188
8189 pci_disable_device(pdev);
8190 rtnl_unlock();
8191
8192 /* Request a slot slot reset. */
8193 return PCI_ERS_RESULT_NEED_RESET;
8194}
8195
8196/**
8197 * bnx2_io_slot_reset - called after the pci bus has been reset.
8198 * @pdev: Pointer to PCI device
8199 *
8200 * Restart the card from scratch, as if from a cold-boot.
8201 */
8202static pci_ers_result_t bnx2_io_slot_reset(struct pci_dev *pdev)
8203{
8204 struct net_device *dev = pci_get_drvdata(pdev);
8205 struct bnx2 *bp = netdev_priv(dev);
8206
8207 rtnl_lock();
8208 if (pci_enable_device(pdev)) {
8209 dev_err(&pdev->dev,
8210 "Cannot re-enable PCI device after reset.\n");
8211 rtnl_unlock();
8212 return PCI_ERS_RESULT_DISCONNECT;
8213 }
8214 pci_set_master(pdev);
8215 pci_restore_state(pdev);
8216
8217 if (netif_running(dev)) {
8218 bnx2_set_power_state(bp, PCI_D0);
8219 bnx2_init_nic(bp, 1);
8220 }
8221
8222 rtnl_unlock();
8223 return PCI_ERS_RESULT_RECOVERED;
8224}
8225
8226/**
8227 * bnx2_io_resume - called when traffic can start flowing again.
8228 * @pdev: Pointer to PCI device
8229 *
8230 * This callback is called when the error recovery driver tells us that
8231 * its OK to resume normal operation.
8232 */
8233static void bnx2_io_resume(struct pci_dev *pdev)
8234{
8235 struct net_device *dev = pci_get_drvdata(pdev);
8236 struct bnx2 *bp = netdev_priv(dev);
8237
8238 rtnl_lock();
8239 if (netif_running(dev))
8240 bnx2_netif_start(bp);
8241
8242 netif_device_attach(dev);
8243 rtnl_unlock();
8244}
8245
8246static struct pci_error_handlers bnx2_err_handler = {
8247 .error_detected = bnx2_io_error_detected,
8248 .slot_reset = bnx2_io_slot_reset,
8249 .resume = bnx2_io_resume,
8250};
8251
Michael Chanb6016b72005-05-26 13:03:09 -07008252static struct pci_driver bnx2_pci_driver = {
Peter Hagervall14ab9b82005-08-10 14:18:16 -07008253 .name = DRV_MODULE_NAME,
8254 .id_table = bnx2_pci_tbl,
8255 .probe = bnx2_init_one,
8256 .remove = __devexit_p(bnx2_remove_one),
8257 .suspend = bnx2_suspend,
8258 .resume = bnx2_resume,
Wendy Xiong6ff2da42008-05-16 22:18:21 -07008259 .err_handler = &bnx2_err_handler,
Michael Chanb6016b72005-05-26 13:03:09 -07008260};
8261
8262static int __init bnx2_init(void)
8263{
Jeff Garzik29917622006-08-19 17:48:59 -04008264 return pci_register_driver(&bnx2_pci_driver);
Michael Chanb6016b72005-05-26 13:03:09 -07008265}
8266
8267static void __exit bnx2_cleanup(void)
8268{
8269 pci_unregister_driver(&bnx2_pci_driver);
8270}
8271
8272module_init(bnx2_init);
8273module_exit(bnx2_cleanup);
8274
8275
8276