blob: d105f1f233914d53ca8f55d95792504493f49957 [file] [log] [blame]
Michael Chanb6016b72005-05-26 13:03:09 -07001/* bnx2.c: Broadcom NX2 network driver.
2 *
Michael Chandc187cb2011-03-14 15:00:12 -07003 * Copyright (c) 2004-2011 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
Joe Perches3a9c6a42010-02-17 15:01:51 +000012#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
Michael Chanf2a4f052006-03-23 01:13:12 -080013
14#include <linux/module.h>
15#include <linux/moduleparam.h>
16
17#include <linux/kernel.h>
18#include <linux/timer.h>
19#include <linux/errno.h>
20#include <linux/ioport.h>
21#include <linux/slab.h>
22#include <linux/vmalloc.h>
23#include <linux/interrupt.h>
24#include <linux/pci.h>
25#include <linux/init.h>
26#include <linux/netdevice.h>
27#include <linux/etherdevice.h>
28#include <linux/skbuff.h>
29#include <linux/dma-mapping.h>
Jiri Slaby1977f032007-10-18 23:40:25 -070030#include <linux/bitops.h>
Michael Chanf2a4f052006-03-23 01:13:12 -080031#include <asm/io.h>
32#include <asm/irq.h>
33#include <linux/delay.h>
34#include <asm/byteorder.h>
Michael Chanc86a31f2006-06-13 15:03:47 -070035#include <asm/page.h>
Michael Chanf2a4f052006-03-23 01:13:12 -080036#include <linux/time.h>
37#include <linux/ethtool.h>
38#include <linux/mii.h>
Michael Chanf2a4f052006-03-23 01:13:12 -080039#include <linux/if_vlan.h>
Michael Chanf2a4f052006-03-23 01:13:12 -080040#include <net/ip.h>
Linus Torvaldsde081fa2007-07-12 16:40:08 -070041#include <net/tcp.h>
Michael Chanf2a4f052006-03-23 01:13:12 -080042#include <net/checksum.h>
Michael Chanf2a4f052006-03-23 01:13:12 -080043#include <linux/workqueue.h>
44#include <linux/crc32.h>
45#include <linux/prefetch.h>
Michael Chan29b12172006-03-23 01:13:43 -080046#include <linux/cache.h>
Michael Chan57579f72009-04-04 16:51:14 -070047#include <linux/firmware.h>
Benjamin Li706bf242008-07-18 17:55:11 -070048#include <linux/log2.h>
John Feeneycd709aa2010-08-22 17:45:53 +000049#include <linux/aer.h>
Michael Chanf2a4f052006-03-23 01:13:12 -080050
Michael Chan4edd4732009-06-08 18:14:42 -070051#if defined(CONFIG_CNIC) || defined(CONFIG_CNIC_MODULE)
52#define BCM_CNIC 1
53#include "cnic_if.h"
54#endif
Michael Chanb6016b72005-05-26 13:03:09 -070055#include "bnx2.h"
56#include "bnx2_fw.h"
Denys Vlasenkob3448b02007-09-30 17:55:51 -070057
Michael Chanb6016b72005-05-26 13:03:09 -070058#define DRV_MODULE_NAME "bnx2"
Michael Chandc187cb2011-03-14 15:00:12 -070059#define DRV_MODULE_VERSION "2.1.6"
60#define DRV_MODULE_RELDATE "Mar 7, 2011"
Michael Chan02681022010-12-31 11:04:02 -080061#define FW_MIPS_FILE_06 "bnx2/bnx2-mips-06-6.2.1.fw"
Michael Chan22fa1592010-10-11 16:12:00 -070062#define FW_RV2P_FILE_06 "bnx2/bnx2-rv2p-06-6.0.15.fw"
Michael Chandc187cb2011-03-14 15:00:12 -070063#define FW_MIPS_FILE_09 "bnx2/bnx2-mips-09-6.2.1a.fw"
Michael Chan22fa1592010-10-11 16:12:00 -070064#define FW_RV2P_FILE_09_Ax "bnx2/bnx2-rv2p-09ax-6.0.17.fw"
65#define FW_RV2P_FILE_09 "bnx2/bnx2-rv2p-09-6.0.17.fw"
Michael Chanb6016b72005-05-26 13:03:09 -070066
67#define RUN_AT(x) (jiffies + (x))
68
69/* Time in jiffies before concluding the transmitter is hung. */
70#define TX_TIMEOUT (5*HZ)
71
Andrew Mortonfefa8642008-02-09 23:17:15 -080072static char version[] __devinitdata =
Michael Chanb6016b72005-05-26 13:03:09 -070073 "Broadcom NetXtreme II Gigabit Ethernet Driver " DRV_MODULE_NAME " v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";
74
75MODULE_AUTHOR("Michael Chan <mchan@broadcom.com>");
Benjamin Li453a9c62008-09-18 16:39:16 -070076MODULE_DESCRIPTION("Broadcom NetXtreme II BCM5706/5708/5709/5716 Driver");
Michael Chanb6016b72005-05-26 13:03:09 -070077MODULE_LICENSE("GPL");
78MODULE_VERSION(DRV_MODULE_VERSION);
Michael Chan57579f72009-04-04 16:51:14 -070079MODULE_FIRMWARE(FW_MIPS_FILE_06);
80MODULE_FIRMWARE(FW_RV2P_FILE_06);
81MODULE_FIRMWARE(FW_MIPS_FILE_09);
82MODULE_FIRMWARE(FW_RV2P_FILE_09);
Michael Chan078b0732009-08-29 00:02:46 -070083MODULE_FIRMWARE(FW_RV2P_FILE_09_Ax);
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
Michael Chan0ced9d02009-08-21 16:20:49 +0000147static const struct flash_spec flash_table[] =
Michael Chanb6016b72005-05-26 13:03:09 -0700148{
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 Chan0ced9d02009-08-21 16:20:49 +0000236static const struct flash_spec flash_5709 = {
Michael Chane30372c2007-07-16 18:26:23 -0700237 .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
Benjamin Li4327ba42010-03-23 13:13:11 +0000247static void bnx2_init_napi(struct bnx2 *bp);
Michael Chanf048fa92010-06-01 15:05:36 +0000248static void bnx2_del_napi(struct bnx2 *bp);
Benjamin Li4327ba42010-03-23 13:13:11 +0000249
Michael Chan35e90102008-06-19 16:37:42 -0700250static inline u32 bnx2_tx_avail(struct bnx2 *bp, struct bnx2_tx_ring_info *txr)
Michael Chane89bbf12005-08-25 15:36:58 -0700251{
Michael Chan2f8af122006-08-15 01:39:10 -0700252 u32 diff;
Michael Chane89bbf12005-08-25 15:36:58 -0700253
Michael Chan11848b962010-07-19 14:15:04 +0000254 /* Tell compiler to fetch tx_prod and tx_cons from memory. */
255 barrier();
Michael Chanfaac9c42006-12-14 15:56:32 -0800256
257 /* The ring uses 256 indices for 255 entries, one of them
258 * needs to be skipped.
259 */
Michael Chan35e90102008-06-19 16:37:42 -0700260 diff = txr->tx_prod - txr->tx_cons;
Michael Chanfaac9c42006-12-14 15:56:32 -0800261 if (unlikely(diff >= TX_DESC_CNT)) {
262 diff &= 0xffff;
263 if (diff == TX_DESC_CNT)
264 diff = MAX_TX_DESC_CNT;
265 }
Eric Dumazet807540b2010-09-23 05:40:09 +0000266 return bp->tx_ring_size - diff;
Michael Chane89bbf12005-08-25 15:36:58 -0700267}
268
Michael Chanb6016b72005-05-26 13:03:09 -0700269static u32
270bnx2_reg_rd_ind(struct bnx2 *bp, u32 offset)
271{
Michael Chan1b8227c2007-05-03 13:24:05 -0700272 u32 val;
273
274 spin_lock_bh(&bp->indirect_lock);
Michael Chanb6016b72005-05-26 13:03:09 -0700275 REG_WR(bp, BNX2_PCICFG_REG_WINDOW_ADDRESS, offset);
Michael Chan1b8227c2007-05-03 13:24:05 -0700276 val = REG_RD(bp, BNX2_PCICFG_REG_WINDOW);
277 spin_unlock_bh(&bp->indirect_lock);
278 return val;
Michael Chanb6016b72005-05-26 13:03:09 -0700279}
280
281static void
282bnx2_reg_wr_ind(struct bnx2 *bp, u32 offset, u32 val)
283{
Michael Chan1b8227c2007-05-03 13:24:05 -0700284 spin_lock_bh(&bp->indirect_lock);
Michael Chanb6016b72005-05-26 13:03:09 -0700285 REG_WR(bp, BNX2_PCICFG_REG_WINDOW_ADDRESS, offset);
286 REG_WR(bp, BNX2_PCICFG_REG_WINDOW, val);
Michael Chan1b8227c2007-05-03 13:24:05 -0700287 spin_unlock_bh(&bp->indirect_lock);
Michael Chanb6016b72005-05-26 13:03:09 -0700288}
289
290static void
Michael Chan2726d6e2008-01-29 21:35:05 -0800291bnx2_shmem_wr(struct bnx2 *bp, u32 offset, u32 val)
292{
293 bnx2_reg_wr_ind(bp, bp->shmem_base + offset, val);
294}
295
296static u32
297bnx2_shmem_rd(struct bnx2 *bp, u32 offset)
298{
Eric Dumazet807540b2010-09-23 05:40:09 +0000299 return bnx2_reg_rd_ind(bp, bp->shmem_base + offset);
Michael Chan2726d6e2008-01-29 21:35:05 -0800300}
301
302static void
Michael Chanb6016b72005-05-26 13:03:09 -0700303bnx2_ctx_wr(struct bnx2 *bp, u32 cid_addr, u32 offset, u32 val)
304{
305 offset += cid_addr;
Michael Chan1b8227c2007-05-03 13:24:05 -0700306 spin_lock_bh(&bp->indirect_lock);
Michael Chan59b47d82006-11-19 14:10:45 -0800307 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
308 int i;
309
310 REG_WR(bp, BNX2_CTX_CTX_DATA, val);
311 REG_WR(bp, BNX2_CTX_CTX_CTRL,
312 offset | BNX2_CTX_CTX_CTRL_WRITE_REQ);
313 for (i = 0; i < 5; i++) {
Michael Chan59b47d82006-11-19 14:10:45 -0800314 val = REG_RD(bp, BNX2_CTX_CTX_CTRL);
315 if ((val & BNX2_CTX_CTX_CTRL_WRITE_REQ) == 0)
316 break;
317 udelay(5);
318 }
319 } else {
320 REG_WR(bp, BNX2_CTX_DATA_ADR, offset);
321 REG_WR(bp, BNX2_CTX_DATA, val);
322 }
Michael Chan1b8227c2007-05-03 13:24:05 -0700323 spin_unlock_bh(&bp->indirect_lock);
Michael Chanb6016b72005-05-26 13:03:09 -0700324}
325
Michael Chan4edd4732009-06-08 18:14:42 -0700326#ifdef BCM_CNIC
327static int
328bnx2_drv_ctl(struct net_device *dev, struct drv_ctl_info *info)
329{
330 struct bnx2 *bp = netdev_priv(dev);
331 struct drv_ctl_io *io = &info->data.io;
332
333 switch (info->cmd) {
334 case DRV_CTL_IO_WR_CMD:
335 bnx2_reg_wr_ind(bp, io->offset, io->data);
336 break;
337 case DRV_CTL_IO_RD_CMD:
338 io->data = bnx2_reg_rd_ind(bp, io->offset);
339 break;
340 case DRV_CTL_CTX_WR_CMD:
341 bnx2_ctx_wr(bp, io->cid_addr, io->offset, io->data);
342 break;
343 default:
344 return -EINVAL;
345 }
346 return 0;
347}
348
349static void bnx2_setup_cnic_irq_info(struct bnx2 *bp)
350{
351 struct cnic_eth_dev *cp = &bp->cnic_eth_dev;
352 struct bnx2_napi *bnapi = &bp->bnx2_napi[0];
353 int sb_id;
354
355 if (bp->flags & BNX2_FLAG_USING_MSIX) {
356 cp->drv_state |= CNIC_DRV_STATE_USING_MSIX;
357 bnapi->cnic_present = 0;
358 sb_id = bp->irq_nvecs;
359 cp->irq_arr[0].irq_flags |= CNIC_IRQ_FL_MSIX;
360 } else {
361 cp->drv_state &= ~CNIC_DRV_STATE_USING_MSIX;
362 bnapi->cnic_tag = bnapi->last_status_idx;
363 bnapi->cnic_present = 1;
364 sb_id = 0;
365 cp->irq_arr[0].irq_flags &= ~CNIC_IRQ_FL_MSIX;
366 }
367
368 cp->irq_arr[0].vector = bp->irq_tbl[sb_id].vector;
369 cp->irq_arr[0].status_blk = (void *)
370 ((unsigned long) bnapi->status_blk.msi +
371 (BNX2_SBLK_MSIX_ALIGN_SIZE * sb_id));
372 cp->irq_arr[0].status_blk_num = sb_id;
373 cp->num_irq = 1;
374}
375
376static int bnx2_register_cnic(struct net_device *dev, struct cnic_ops *ops,
377 void *data)
378{
379 struct bnx2 *bp = netdev_priv(dev);
380 struct cnic_eth_dev *cp = &bp->cnic_eth_dev;
381
382 if (ops == NULL)
383 return -EINVAL;
384
385 if (cp->drv_state & CNIC_DRV_STATE_REGD)
386 return -EBUSY;
387
388 bp->cnic_data = data;
389 rcu_assign_pointer(bp->cnic_ops, ops);
390
391 cp->num_irq = 0;
392 cp->drv_state = CNIC_DRV_STATE_REGD;
393
394 bnx2_setup_cnic_irq_info(bp);
395
396 return 0;
397}
398
399static int bnx2_unregister_cnic(struct net_device *dev)
400{
401 struct bnx2 *bp = netdev_priv(dev);
402 struct bnx2_napi *bnapi = &bp->bnx2_napi[0];
403 struct cnic_eth_dev *cp = &bp->cnic_eth_dev;
404
Michael Chanc5a88952009-08-14 15:49:45 +0000405 mutex_lock(&bp->cnic_lock);
Michael Chan4edd4732009-06-08 18:14:42 -0700406 cp->drv_state = 0;
407 bnapi->cnic_present = 0;
408 rcu_assign_pointer(bp->cnic_ops, NULL);
Michael Chanc5a88952009-08-14 15:49:45 +0000409 mutex_unlock(&bp->cnic_lock);
Michael Chan4edd4732009-06-08 18:14:42 -0700410 synchronize_rcu();
411 return 0;
412}
413
414struct cnic_eth_dev *bnx2_cnic_probe(struct net_device *dev)
415{
416 struct bnx2 *bp = netdev_priv(dev);
417 struct cnic_eth_dev *cp = &bp->cnic_eth_dev;
418
Michael Chan7625eb22011-06-08 19:29:36 +0000419 if (!cp->max_iscsi_conn)
420 return NULL;
421
Michael Chan4edd4732009-06-08 18:14:42 -0700422 cp->drv_owner = THIS_MODULE;
423 cp->chip_id = bp->chip_id;
424 cp->pdev = bp->pdev;
425 cp->io_base = bp->regview;
426 cp->drv_ctl = bnx2_drv_ctl;
427 cp->drv_register_cnic = bnx2_register_cnic;
428 cp->drv_unregister_cnic = bnx2_unregister_cnic;
429
430 return cp;
431}
432EXPORT_SYMBOL(bnx2_cnic_probe);
433
434static void
435bnx2_cnic_stop(struct bnx2 *bp)
436{
437 struct cnic_ops *c_ops;
438 struct cnic_ctl_info info;
439
Michael Chanc5a88952009-08-14 15:49:45 +0000440 mutex_lock(&bp->cnic_lock);
Eric Dumazet13707f92011-01-26 19:28:23 +0000441 c_ops = rcu_dereference_protected(bp->cnic_ops,
442 lockdep_is_held(&bp->cnic_lock));
Michael Chan4edd4732009-06-08 18:14:42 -0700443 if (c_ops) {
444 info.cmd = CNIC_CTL_STOP_CMD;
445 c_ops->cnic_ctl(bp->cnic_data, &info);
446 }
Michael Chanc5a88952009-08-14 15:49:45 +0000447 mutex_unlock(&bp->cnic_lock);
Michael Chan4edd4732009-06-08 18:14:42 -0700448}
449
450static void
451bnx2_cnic_start(struct bnx2 *bp)
452{
453 struct cnic_ops *c_ops;
454 struct cnic_ctl_info info;
455
Michael Chanc5a88952009-08-14 15:49:45 +0000456 mutex_lock(&bp->cnic_lock);
Eric Dumazet13707f92011-01-26 19:28:23 +0000457 c_ops = rcu_dereference_protected(bp->cnic_ops,
458 lockdep_is_held(&bp->cnic_lock));
Michael Chan4edd4732009-06-08 18:14:42 -0700459 if (c_ops) {
460 if (!(bp->flags & BNX2_FLAG_USING_MSIX)) {
461 struct bnx2_napi *bnapi = &bp->bnx2_napi[0];
462
463 bnapi->cnic_tag = bnapi->last_status_idx;
464 }
465 info.cmd = CNIC_CTL_START_CMD;
466 c_ops->cnic_ctl(bp->cnic_data, &info);
467 }
Michael Chanc5a88952009-08-14 15:49:45 +0000468 mutex_unlock(&bp->cnic_lock);
Michael Chan4edd4732009-06-08 18:14:42 -0700469}
470
471#else
472
473static void
474bnx2_cnic_stop(struct bnx2 *bp)
475{
476}
477
478static void
479bnx2_cnic_start(struct bnx2 *bp)
480{
481}
482
483#endif
484
Michael Chanb6016b72005-05-26 13:03:09 -0700485static int
486bnx2_read_phy(struct bnx2 *bp, u32 reg, u32 *val)
487{
488 u32 val1;
489 int i, ret;
490
Michael Chan583c28e2008-01-21 19:51:35 -0800491 if (bp->phy_flags & BNX2_PHY_FLAG_INT_MODE_AUTO_POLLING) {
Michael Chanb6016b72005-05-26 13:03:09 -0700492 val1 = REG_RD(bp, BNX2_EMAC_MDIO_MODE);
493 val1 &= ~BNX2_EMAC_MDIO_MODE_AUTO_POLL;
494
495 REG_WR(bp, BNX2_EMAC_MDIO_MODE, val1);
496 REG_RD(bp, BNX2_EMAC_MDIO_MODE);
497
498 udelay(40);
499 }
500
501 val1 = (bp->phy_addr << 21) | (reg << 16) |
502 BNX2_EMAC_MDIO_COMM_COMMAND_READ | BNX2_EMAC_MDIO_COMM_DISEXT |
503 BNX2_EMAC_MDIO_COMM_START_BUSY;
504 REG_WR(bp, BNX2_EMAC_MDIO_COMM, val1);
505
506 for (i = 0; i < 50; i++) {
507 udelay(10);
508
509 val1 = REG_RD(bp, BNX2_EMAC_MDIO_COMM);
510 if (!(val1 & BNX2_EMAC_MDIO_COMM_START_BUSY)) {
511 udelay(5);
512
513 val1 = REG_RD(bp, BNX2_EMAC_MDIO_COMM);
514 val1 &= BNX2_EMAC_MDIO_COMM_DATA;
515
516 break;
517 }
518 }
519
520 if (val1 & BNX2_EMAC_MDIO_COMM_START_BUSY) {
521 *val = 0x0;
522 ret = -EBUSY;
523 }
524 else {
525 *val = val1;
526 ret = 0;
527 }
528
Michael Chan583c28e2008-01-21 19:51:35 -0800529 if (bp->phy_flags & BNX2_PHY_FLAG_INT_MODE_AUTO_POLLING) {
Michael Chanb6016b72005-05-26 13:03:09 -0700530 val1 = REG_RD(bp, BNX2_EMAC_MDIO_MODE);
531 val1 |= BNX2_EMAC_MDIO_MODE_AUTO_POLL;
532
533 REG_WR(bp, BNX2_EMAC_MDIO_MODE, val1);
534 REG_RD(bp, BNX2_EMAC_MDIO_MODE);
535
536 udelay(40);
537 }
538
539 return ret;
540}
541
542static int
543bnx2_write_phy(struct bnx2 *bp, u32 reg, u32 val)
544{
545 u32 val1;
546 int i, ret;
547
Michael Chan583c28e2008-01-21 19:51:35 -0800548 if (bp->phy_flags & BNX2_PHY_FLAG_INT_MODE_AUTO_POLLING) {
Michael Chanb6016b72005-05-26 13:03:09 -0700549 val1 = REG_RD(bp, BNX2_EMAC_MDIO_MODE);
550 val1 &= ~BNX2_EMAC_MDIO_MODE_AUTO_POLL;
551
552 REG_WR(bp, BNX2_EMAC_MDIO_MODE, val1);
553 REG_RD(bp, BNX2_EMAC_MDIO_MODE);
554
555 udelay(40);
556 }
557
558 val1 = (bp->phy_addr << 21) | (reg << 16) | val |
559 BNX2_EMAC_MDIO_COMM_COMMAND_WRITE |
560 BNX2_EMAC_MDIO_COMM_START_BUSY | BNX2_EMAC_MDIO_COMM_DISEXT;
561 REG_WR(bp, BNX2_EMAC_MDIO_COMM, val1);
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400562
Michael Chanb6016b72005-05-26 13:03:09 -0700563 for (i = 0; i < 50; i++) {
564 udelay(10);
565
566 val1 = REG_RD(bp, BNX2_EMAC_MDIO_COMM);
567 if (!(val1 & BNX2_EMAC_MDIO_COMM_START_BUSY)) {
568 udelay(5);
569 break;
570 }
571 }
572
573 if (val1 & BNX2_EMAC_MDIO_COMM_START_BUSY)
574 ret = -EBUSY;
575 else
576 ret = 0;
577
Michael Chan583c28e2008-01-21 19:51:35 -0800578 if (bp->phy_flags & BNX2_PHY_FLAG_INT_MODE_AUTO_POLLING) {
Michael Chanb6016b72005-05-26 13:03:09 -0700579 val1 = REG_RD(bp, BNX2_EMAC_MDIO_MODE);
580 val1 |= BNX2_EMAC_MDIO_MODE_AUTO_POLL;
581
582 REG_WR(bp, BNX2_EMAC_MDIO_MODE, val1);
583 REG_RD(bp, BNX2_EMAC_MDIO_MODE);
584
585 udelay(40);
586 }
587
588 return ret;
589}
590
591static void
592bnx2_disable_int(struct bnx2 *bp)
593{
Michael Chanb4b36042007-12-20 19:59:30 -0800594 int i;
595 struct bnx2_napi *bnapi;
596
597 for (i = 0; i < bp->irq_nvecs; i++) {
598 bnapi = &bp->bnx2_napi[i];
599 REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD, bnapi->int_num |
600 BNX2_PCICFG_INT_ACK_CMD_MASK_INT);
601 }
Michael Chanb6016b72005-05-26 13:03:09 -0700602 REG_RD(bp, BNX2_PCICFG_INT_ACK_CMD);
603}
604
605static void
606bnx2_enable_int(struct bnx2 *bp)
607{
Michael Chanb4b36042007-12-20 19:59:30 -0800608 int i;
609 struct bnx2_napi *bnapi;
Michael Chan1269a8a2006-01-23 16:11:03 -0800610
Michael Chanb4b36042007-12-20 19:59:30 -0800611 for (i = 0; i < bp->irq_nvecs; i++) {
612 bnapi = &bp->bnx2_napi[i];
Michael Chan35efa7c2007-12-20 19:56:37 -0800613
Michael Chanb4b36042007-12-20 19:59:30 -0800614 REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD, bnapi->int_num |
615 BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
616 BNX2_PCICFG_INT_ACK_CMD_MASK_INT |
617 bnapi->last_status_idx);
Michael Chanb6016b72005-05-26 13:03:09 -0700618
Michael Chanb4b36042007-12-20 19:59:30 -0800619 REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD, bnapi->int_num |
620 BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
621 bnapi->last_status_idx);
622 }
Michael Chanbf5295b2006-03-23 01:11:56 -0800623 REG_WR(bp, BNX2_HC_COMMAND, bp->hc_cmd | BNX2_HC_COMMAND_COAL_NOW);
Michael Chanb6016b72005-05-26 13:03:09 -0700624}
625
626static void
627bnx2_disable_int_sync(struct bnx2 *bp)
628{
Michael Chanb4b36042007-12-20 19:59:30 -0800629 int i;
630
Michael Chanb6016b72005-05-26 13:03:09 -0700631 atomic_inc(&bp->intr_sem);
Michael Chan37675462009-08-21 16:20:44 +0000632 if (!netif_running(bp->dev))
633 return;
634
Michael Chanb6016b72005-05-26 13:03:09 -0700635 bnx2_disable_int(bp);
Michael Chanb4b36042007-12-20 19:59:30 -0800636 for (i = 0; i < bp->irq_nvecs; i++)
637 synchronize_irq(bp->irq_tbl[i].vector);
Michael Chanb6016b72005-05-26 13:03:09 -0700638}
639
640static void
Michael Chan35efa7c2007-12-20 19:56:37 -0800641bnx2_napi_disable(struct bnx2 *bp)
642{
Michael Chanb4b36042007-12-20 19:59:30 -0800643 int i;
644
645 for (i = 0; i < bp->irq_nvecs; i++)
646 napi_disable(&bp->bnx2_napi[i].napi);
Michael Chan35efa7c2007-12-20 19:56:37 -0800647}
648
649static void
650bnx2_napi_enable(struct bnx2 *bp)
651{
Michael Chanb4b36042007-12-20 19:59:30 -0800652 int i;
653
654 for (i = 0; i < bp->irq_nvecs; i++)
655 napi_enable(&bp->bnx2_napi[i].napi);
Michael Chan35efa7c2007-12-20 19:56:37 -0800656}
657
658static void
Michael Chan212f9932010-04-27 11:28:10 +0000659bnx2_netif_stop(struct bnx2 *bp, bool stop_cnic)
Michael Chanb6016b72005-05-26 13:03:09 -0700660{
Michael Chan212f9932010-04-27 11:28:10 +0000661 if (stop_cnic)
662 bnx2_cnic_stop(bp);
Michael Chanb6016b72005-05-26 13:03:09 -0700663 if (netif_running(bp->dev)) {
Michael Chan35efa7c2007-12-20 19:56:37 -0800664 bnx2_napi_disable(bp);
Michael Chanb6016b72005-05-26 13:03:09 -0700665 netif_tx_disable(bp->dev);
Michael Chanb6016b72005-05-26 13:03:09 -0700666 }
Michael Chanb7466562009-12-20 18:40:18 -0800667 bnx2_disable_int_sync(bp);
Michael Chana0ba6762010-05-17 17:34:43 -0700668 netif_carrier_off(bp->dev); /* prevent tx timeout */
Michael Chanb6016b72005-05-26 13:03:09 -0700669}
670
671static void
Michael Chan212f9932010-04-27 11:28:10 +0000672bnx2_netif_start(struct bnx2 *bp, bool start_cnic)
Michael Chanb6016b72005-05-26 13:03:09 -0700673{
674 if (atomic_dec_and_test(&bp->intr_sem)) {
675 if (netif_running(bp->dev)) {
Benjamin Li706bf242008-07-18 17:55:11 -0700676 netif_tx_wake_all_queues(bp->dev);
Michael Chana0ba6762010-05-17 17:34:43 -0700677 spin_lock_bh(&bp->phy_lock);
678 if (bp->link_up)
679 netif_carrier_on(bp->dev);
680 spin_unlock_bh(&bp->phy_lock);
Michael Chan35efa7c2007-12-20 19:56:37 -0800681 bnx2_napi_enable(bp);
Michael Chanb6016b72005-05-26 13:03:09 -0700682 bnx2_enable_int(bp);
Michael Chan212f9932010-04-27 11:28:10 +0000683 if (start_cnic)
684 bnx2_cnic_start(bp);
Michael Chanb6016b72005-05-26 13:03:09 -0700685 }
686 }
687}
688
689static void
Michael Chan35e90102008-06-19 16:37:42 -0700690bnx2_free_tx_mem(struct bnx2 *bp)
691{
692 int i;
693
694 for (i = 0; i < bp->num_tx_rings; i++) {
695 struct bnx2_napi *bnapi = &bp->bnx2_napi[i];
696 struct bnx2_tx_ring_info *txr = &bnapi->tx_ring;
697
698 if (txr->tx_desc_ring) {
Stanislaw Gruszka36227e82010-07-15 04:25:50 +0000699 dma_free_coherent(&bp->pdev->dev, TXBD_RING_SIZE,
700 txr->tx_desc_ring,
701 txr->tx_desc_mapping);
Michael Chan35e90102008-06-19 16:37:42 -0700702 txr->tx_desc_ring = NULL;
703 }
704 kfree(txr->tx_buf_ring);
705 txr->tx_buf_ring = NULL;
706 }
707}
708
Michael Chanbb4f98a2008-06-19 16:38:19 -0700709static void
710bnx2_free_rx_mem(struct bnx2 *bp)
711{
712 int i;
713
714 for (i = 0; i < bp->num_rx_rings; i++) {
715 struct bnx2_napi *bnapi = &bp->bnx2_napi[i];
716 struct bnx2_rx_ring_info *rxr = &bnapi->rx_ring;
717 int j;
718
719 for (j = 0; j < bp->rx_max_ring; j++) {
720 if (rxr->rx_desc_ring[j])
Stanislaw Gruszka36227e82010-07-15 04:25:50 +0000721 dma_free_coherent(&bp->pdev->dev, RXBD_RING_SIZE,
722 rxr->rx_desc_ring[j],
723 rxr->rx_desc_mapping[j]);
Michael Chanbb4f98a2008-06-19 16:38:19 -0700724 rxr->rx_desc_ring[j] = NULL;
725 }
Breno Leitao25b0b992009-06-08 10:30:19 +0000726 vfree(rxr->rx_buf_ring);
Michael Chanbb4f98a2008-06-19 16:38:19 -0700727 rxr->rx_buf_ring = NULL;
728
729 for (j = 0; j < bp->rx_max_pg_ring; j++) {
730 if (rxr->rx_pg_desc_ring[j])
Stanislaw Gruszka36227e82010-07-15 04:25:50 +0000731 dma_free_coherent(&bp->pdev->dev, RXBD_RING_SIZE,
732 rxr->rx_pg_desc_ring[j],
733 rxr->rx_pg_desc_mapping[j]);
Michael Chan3298a732008-12-17 19:06:08 -0800734 rxr->rx_pg_desc_ring[j] = NULL;
Michael Chanbb4f98a2008-06-19 16:38:19 -0700735 }
Breno Leitao25b0b992009-06-08 10:30:19 +0000736 vfree(rxr->rx_pg_ring);
Michael Chanbb4f98a2008-06-19 16:38:19 -0700737 rxr->rx_pg_ring = NULL;
738 }
739}
740
Michael Chan35e90102008-06-19 16:37:42 -0700741static int
742bnx2_alloc_tx_mem(struct bnx2 *bp)
743{
744 int i;
745
746 for (i = 0; i < bp->num_tx_rings; i++) {
747 struct bnx2_napi *bnapi = &bp->bnx2_napi[i];
748 struct bnx2_tx_ring_info *txr = &bnapi->tx_ring;
749
750 txr->tx_buf_ring = kzalloc(SW_TXBD_RING_SIZE, GFP_KERNEL);
751 if (txr->tx_buf_ring == NULL)
752 return -ENOMEM;
753
754 txr->tx_desc_ring =
Stanislaw Gruszka36227e82010-07-15 04:25:50 +0000755 dma_alloc_coherent(&bp->pdev->dev, TXBD_RING_SIZE,
756 &txr->tx_desc_mapping, GFP_KERNEL);
Michael Chan35e90102008-06-19 16:37:42 -0700757 if (txr->tx_desc_ring == NULL)
758 return -ENOMEM;
759 }
760 return 0;
761}
762
Michael Chanbb4f98a2008-06-19 16:38:19 -0700763static int
764bnx2_alloc_rx_mem(struct bnx2 *bp)
765{
766 int i;
767
768 for (i = 0; i < bp->num_rx_rings; i++) {
769 struct bnx2_napi *bnapi = &bp->bnx2_napi[i];
770 struct bnx2_rx_ring_info *rxr = &bnapi->rx_ring;
771 int j;
772
773 rxr->rx_buf_ring =
Eric Dumazet89bf67f2010-11-22 00:15:06 +0000774 vzalloc(SW_RXBD_RING_SIZE * bp->rx_max_ring);
Michael Chanbb4f98a2008-06-19 16:38:19 -0700775 if (rxr->rx_buf_ring == NULL)
776 return -ENOMEM;
777
Michael Chanbb4f98a2008-06-19 16:38:19 -0700778 for (j = 0; j < bp->rx_max_ring; j++) {
779 rxr->rx_desc_ring[j] =
Stanislaw Gruszka36227e82010-07-15 04:25:50 +0000780 dma_alloc_coherent(&bp->pdev->dev,
781 RXBD_RING_SIZE,
782 &rxr->rx_desc_mapping[j],
783 GFP_KERNEL);
Michael Chanbb4f98a2008-06-19 16:38:19 -0700784 if (rxr->rx_desc_ring[j] == NULL)
785 return -ENOMEM;
786
787 }
788
789 if (bp->rx_pg_ring_size) {
Eric Dumazet89bf67f2010-11-22 00:15:06 +0000790 rxr->rx_pg_ring = vzalloc(SW_RXPG_RING_SIZE *
Michael Chanbb4f98a2008-06-19 16:38:19 -0700791 bp->rx_max_pg_ring);
792 if (rxr->rx_pg_ring == NULL)
793 return -ENOMEM;
794
Michael Chanbb4f98a2008-06-19 16:38:19 -0700795 }
796
797 for (j = 0; j < bp->rx_max_pg_ring; j++) {
798 rxr->rx_pg_desc_ring[j] =
Stanislaw Gruszka36227e82010-07-15 04:25:50 +0000799 dma_alloc_coherent(&bp->pdev->dev,
800 RXBD_RING_SIZE,
801 &rxr->rx_pg_desc_mapping[j],
802 GFP_KERNEL);
Michael Chanbb4f98a2008-06-19 16:38:19 -0700803 if (rxr->rx_pg_desc_ring[j] == NULL)
804 return -ENOMEM;
805
806 }
807 }
808 return 0;
809}
810
Michael Chan35e90102008-06-19 16:37:42 -0700811static void
Michael Chanb6016b72005-05-26 13:03:09 -0700812bnx2_free_mem(struct bnx2 *bp)
813{
Michael Chan13daffa2006-03-20 17:49:20 -0800814 int i;
Michael Chan43e80b82008-06-19 16:41:08 -0700815 struct bnx2_napi *bnapi = &bp->bnx2_napi[0];
Michael Chan13daffa2006-03-20 17:49:20 -0800816
Michael Chan35e90102008-06-19 16:37:42 -0700817 bnx2_free_tx_mem(bp);
Michael Chanbb4f98a2008-06-19 16:38:19 -0700818 bnx2_free_rx_mem(bp);
Michael Chan35e90102008-06-19 16:37:42 -0700819
Michael Chan59b47d82006-11-19 14:10:45 -0800820 for (i = 0; i < bp->ctx_pages; i++) {
821 if (bp->ctx_blk[i]) {
Stanislaw Gruszka36227e82010-07-15 04:25:50 +0000822 dma_free_coherent(&bp->pdev->dev, BCM_PAGE_SIZE,
823 bp->ctx_blk[i],
824 bp->ctx_blk_mapping[i]);
Michael Chan59b47d82006-11-19 14:10:45 -0800825 bp->ctx_blk[i] = NULL;
826 }
827 }
Michael Chan43e80b82008-06-19 16:41:08 -0700828 if (bnapi->status_blk.msi) {
Stanislaw Gruszka36227e82010-07-15 04:25:50 +0000829 dma_free_coherent(&bp->pdev->dev, bp->status_stats_size,
830 bnapi->status_blk.msi,
831 bp->status_blk_mapping);
Michael Chan43e80b82008-06-19 16:41:08 -0700832 bnapi->status_blk.msi = NULL;
Michael Chan0f31f992006-03-23 01:12:38 -0800833 bp->stats_blk = NULL;
Michael Chanb6016b72005-05-26 13:03:09 -0700834 }
Michael Chanb6016b72005-05-26 13:03:09 -0700835}
836
837static int
838bnx2_alloc_mem(struct bnx2 *bp)
839{
Michael Chan35e90102008-06-19 16:37:42 -0700840 int i, status_blk_size, err;
Michael Chan43e80b82008-06-19 16:41:08 -0700841 struct bnx2_napi *bnapi;
842 void *status_blk;
Michael Chanb6016b72005-05-26 13:03:09 -0700843
Michael Chan0f31f992006-03-23 01:12:38 -0800844 /* Combine status and statistics blocks into one allocation. */
845 status_blk_size = L1_CACHE_ALIGN(sizeof(struct status_block));
David S. Millerf86e82f2008-01-21 17:15:40 -0800846 if (bp->flags & BNX2_FLAG_MSIX_CAP)
Michael Chanb4b36042007-12-20 19:59:30 -0800847 status_blk_size = L1_CACHE_ALIGN(BNX2_MAX_MSIX_HW_VEC *
848 BNX2_SBLK_MSIX_ALIGN_SIZE);
Michael Chan0f31f992006-03-23 01:12:38 -0800849 bp->status_stats_size = status_blk_size +
850 sizeof(struct statistics_block);
851
Stanislaw Gruszka36227e82010-07-15 04:25:50 +0000852 status_blk = dma_alloc_coherent(&bp->pdev->dev, bp->status_stats_size,
853 &bp->status_blk_mapping, GFP_KERNEL);
Michael Chan43e80b82008-06-19 16:41:08 -0700854 if (status_blk == NULL)
Michael Chanb6016b72005-05-26 13:03:09 -0700855 goto alloc_mem_err;
856
Michael Chan43e80b82008-06-19 16:41:08 -0700857 memset(status_blk, 0, bp->status_stats_size);
Michael Chanb6016b72005-05-26 13:03:09 -0700858
Michael Chan43e80b82008-06-19 16:41:08 -0700859 bnapi = &bp->bnx2_napi[0];
860 bnapi->status_blk.msi = status_blk;
861 bnapi->hw_tx_cons_ptr =
862 &bnapi->status_blk.msi->status_tx_quick_consumer_index0;
863 bnapi->hw_rx_cons_ptr =
864 &bnapi->status_blk.msi->status_rx_quick_consumer_index0;
David S. Millerf86e82f2008-01-21 17:15:40 -0800865 if (bp->flags & BNX2_FLAG_MSIX_CAP) {
Michael Chan379b39a2010-07-19 14:15:03 +0000866 for (i = 1; i < bp->irq_nvecs; i++) {
Michael Chan43e80b82008-06-19 16:41:08 -0700867 struct status_block_msix *sblk;
Michael Chanb4b36042007-12-20 19:59:30 -0800868
Michael Chan43e80b82008-06-19 16:41:08 -0700869 bnapi = &bp->bnx2_napi[i];
870
871 sblk = (void *) (status_blk +
872 BNX2_SBLK_MSIX_ALIGN_SIZE * i);
873 bnapi->status_blk.msix = sblk;
874 bnapi->hw_tx_cons_ptr =
875 &sblk->status_tx_quick_consumer_index;
876 bnapi->hw_rx_cons_ptr =
877 &sblk->status_rx_quick_consumer_index;
Michael Chanb4b36042007-12-20 19:59:30 -0800878 bnapi->int_num = i << 24;
879 }
880 }
Michael Chan35efa7c2007-12-20 19:56:37 -0800881
Michael Chan43e80b82008-06-19 16:41:08 -0700882 bp->stats_blk = status_blk + status_blk_size;
Michael Chanb6016b72005-05-26 13:03:09 -0700883
Michael Chan0f31f992006-03-23 01:12:38 -0800884 bp->stats_blk_mapping = bp->status_blk_mapping + status_blk_size;
Michael Chanb6016b72005-05-26 13:03:09 -0700885
Michael Chan59b47d82006-11-19 14:10:45 -0800886 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
887 bp->ctx_pages = 0x2000 / BCM_PAGE_SIZE;
888 if (bp->ctx_pages == 0)
889 bp->ctx_pages = 1;
890 for (i = 0; i < bp->ctx_pages; i++) {
Stanislaw Gruszka36227e82010-07-15 04:25:50 +0000891 bp->ctx_blk[i] = dma_alloc_coherent(&bp->pdev->dev,
Michael Chan59b47d82006-11-19 14:10:45 -0800892 BCM_PAGE_SIZE,
Stanislaw Gruszka36227e82010-07-15 04:25:50 +0000893 &bp->ctx_blk_mapping[i],
894 GFP_KERNEL);
Michael Chan59b47d82006-11-19 14:10:45 -0800895 if (bp->ctx_blk[i] == NULL)
896 goto alloc_mem_err;
897 }
898 }
Michael Chan35e90102008-06-19 16:37:42 -0700899
Michael Chanbb4f98a2008-06-19 16:38:19 -0700900 err = bnx2_alloc_rx_mem(bp);
901 if (err)
902 goto alloc_mem_err;
903
Michael Chan35e90102008-06-19 16:37:42 -0700904 err = bnx2_alloc_tx_mem(bp);
905 if (err)
906 goto alloc_mem_err;
907
Michael Chanb6016b72005-05-26 13:03:09 -0700908 return 0;
909
910alloc_mem_err:
911 bnx2_free_mem(bp);
912 return -ENOMEM;
913}
914
915static void
Michael Chane3648b32005-11-04 08:51:21 -0800916bnx2_report_fw_link(struct bnx2 *bp)
917{
918 u32 fw_link_status = 0;
919
Michael Chan583c28e2008-01-21 19:51:35 -0800920 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
Michael Chan0d8a6572007-07-07 22:49:43 -0700921 return;
922
Michael Chane3648b32005-11-04 08:51:21 -0800923 if (bp->link_up) {
924 u32 bmsr;
925
926 switch (bp->line_speed) {
927 case SPEED_10:
928 if (bp->duplex == DUPLEX_HALF)
929 fw_link_status = BNX2_LINK_STATUS_10HALF;
930 else
931 fw_link_status = BNX2_LINK_STATUS_10FULL;
932 break;
933 case SPEED_100:
934 if (bp->duplex == DUPLEX_HALF)
935 fw_link_status = BNX2_LINK_STATUS_100HALF;
936 else
937 fw_link_status = BNX2_LINK_STATUS_100FULL;
938 break;
939 case SPEED_1000:
940 if (bp->duplex == DUPLEX_HALF)
941 fw_link_status = BNX2_LINK_STATUS_1000HALF;
942 else
943 fw_link_status = BNX2_LINK_STATUS_1000FULL;
944 break;
945 case SPEED_2500:
946 if (bp->duplex == DUPLEX_HALF)
947 fw_link_status = BNX2_LINK_STATUS_2500HALF;
948 else
949 fw_link_status = BNX2_LINK_STATUS_2500FULL;
950 break;
951 }
952
953 fw_link_status |= BNX2_LINK_STATUS_LINK_UP;
954
955 if (bp->autoneg) {
956 fw_link_status |= BNX2_LINK_STATUS_AN_ENABLED;
957
Michael Chanca58c3a2007-05-03 13:22:52 -0700958 bnx2_read_phy(bp, bp->mii_bmsr, &bmsr);
959 bnx2_read_phy(bp, bp->mii_bmsr, &bmsr);
Michael Chane3648b32005-11-04 08:51:21 -0800960
961 if (!(bmsr & BMSR_ANEGCOMPLETE) ||
Michael Chan583c28e2008-01-21 19:51:35 -0800962 bp->phy_flags & BNX2_PHY_FLAG_PARALLEL_DETECT)
Michael Chane3648b32005-11-04 08:51:21 -0800963 fw_link_status |= BNX2_LINK_STATUS_PARALLEL_DET;
964 else
965 fw_link_status |= BNX2_LINK_STATUS_AN_COMPLETE;
966 }
967 }
968 else
969 fw_link_status = BNX2_LINK_STATUS_LINK_DOWN;
970
Michael Chan2726d6e2008-01-29 21:35:05 -0800971 bnx2_shmem_wr(bp, BNX2_LINK_STATUS, fw_link_status);
Michael Chane3648b32005-11-04 08:51:21 -0800972}
973
Michael Chan9b1084b2007-07-07 22:50:37 -0700974static char *
975bnx2_xceiver_str(struct bnx2 *bp)
976{
Eric Dumazet807540b2010-09-23 05:40:09 +0000977 return (bp->phy_port == PORT_FIBRE) ? "SerDes" :
Michael Chan583c28e2008-01-21 19:51:35 -0800978 ((bp->phy_flags & BNX2_PHY_FLAG_SERDES) ? "Remote Copper" :
Eric Dumazet807540b2010-09-23 05:40:09 +0000979 "Copper");
Michael Chan9b1084b2007-07-07 22:50:37 -0700980}
981
Michael Chane3648b32005-11-04 08:51:21 -0800982static void
Michael Chanb6016b72005-05-26 13:03:09 -0700983bnx2_report_link(struct bnx2 *bp)
984{
985 if (bp->link_up) {
986 netif_carrier_on(bp->dev);
Joe Perches3a9c6a42010-02-17 15:01:51 +0000987 netdev_info(bp->dev, "NIC %s Link is Up, %d Mbps %s duplex",
988 bnx2_xceiver_str(bp),
989 bp->line_speed,
990 bp->duplex == DUPLEX_FULL ? "full" : "half");
Michael Chanb6016b72005-05-26 13:03:09 -0700991
992 if (bp->flow_ctrl) {
993 if (bp->flow_ctrl & FLOW_CTRL_RX) {
Joe Perches3a9c6a42010-02-17 15:01:51 +0000994 pr_cont(", receive ");
Michael Chanb6016b72005-05-26 13:03:09 -0700995 if (bp->flow_ctrl & FLOW_CTRL_TX)
Joe Perches3a9c6a42010-02-17 15:01:51 +0000996 pr_cont("& transmit ");
Michael Chanb6016b72005-05-26 13:03:09 -0700997 }
998 else {
Joe Perches3a9c6a42010-02-17 15:01:51 +0000999 pr_cont(", transmit ");
Michael Chanb6016b72005-05-26 13:03:09 -07001000 }
Joe Perches3a9c6a42010-02-17 15:01:51 +00001001 pr_cont("flow control ON");
Michael Chanb6016b72005-05-26 13:03:09 -07001002 }
Joe Perches3a9c6a42010-02-17 15:01:51 +00001003 pr_cont("\n");
1004 } else {
Michael Chanb6016b72005-05-26 13:03:09 -07001005 netif_carrier_off(bp->dev);
Joe Perches3a9c6a42010-02-17 15:01:51 +00001006 netdev_err(bp->dev, "NIC %s Link is Down\n",
1007 bnx2_xceiver_str(bp));
Michael Chanb6016b72005-05-26 13:03:09 -07001008 }
Michael Chane3648b32005-11-04 08:51:21 -08001009
1010 bnx2_report_fw_link(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07001011}
1012
1013static void
1014bnx2_resolve_flow_ctrl(struct bnx2 *bp)
1015{
1016 u32 local_adv, remote_adv;
1017
1018 bp->flow_ctrl = 0;
Jeff Garzik6aa20a22006-09-13 13:24:59 -04001019 if ((bp->autoneg & (AUTONEG_SPEED | AUTONEG_FLOW_CTRL)) !=
Michael Chanb6016b72005-05-26 13:03:09 -07001020 (AUTONEG_SPEED | AUTONEG_FLOW_CTRL)) {
1021
1022 if (bp->duplex == DUPLEX_FULL) {
1023 bp->flow_ctrl = bp->req_flow_ctrl;
1024 }
1025 return;
1026 }
1027
1028 if (bp->duplex != DUPLEX_FULL) {
1029 return;
1030 }
1031
Michael Chan583c28e2008-01-21 19:51:35 -08001032 if ((bp->phy_flags & BNX2_PHY_FLAG_SERDES) &&
Michael Chan5b0c76a2005-11-04 08:45:49 -08001033 (CHIP_NUM(bp) == CHIP_NUM_5708)) {
1034 u32 val;
1035
1036 bnx2_read_phy(bp, BCM5708S_1000X_STAT1, &val);
1037 if (val & BCM5708S_1000X_STAT1_TX_PAUSE)
1038 bp->flow_ctrl |= FLOW_CTRL_TX;
1039 if (val & BCM5708S_1000X_STAT1_RX_PAUSE)
1040 bp->flow_ctrl |= FLOW_CTRL_RX;
1041 return;
1042 }
1043
Michael Chanca58c3a2007-05-03 13:22:52 -07001044 bnx2_read_phy(bp, bp->mii_adv, &local_adv);
1045 bnx2_read_phy(bp, bp->mii_lpa, &remote_adv);
Michael Chanb6016b72005-05-26 13:03:09 -07001046
Michael Chan583c28e2008-01-21 19:51:35 -08001047 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Michael Chanb6016b72005-05-26 13:03:09 -07001048 u32 new_local_adv = 0;
1049 u32 new_remote_adv = 0;
1050
1051 if (local_adv & ADVERTISE_1000XPAUSE)
1052 new_local_adv |= ADVERTISE_PAUSE_CAP;
1053 if (local_adv & ADVERTISE_1000XPSE_ASYM)
1054 new_local_adv |= ADVERTISE_PAUSE_ASYM;
1055 if (remote_adv & ADVERTISE_1000XPAUSE)
1056 new_remote_adv |= ADVERTISE_PAUSE_CAP;
1057 if (remote_adv & ADVERTISE_1000XPSE_ASYM)
1058 new_remote_adv |= ADVERTISE_PAUSE_ASYM;
1059
1060 local_adv = new_local_adv;
1061 remote_adv = new_remote_adv;
1062 }
1063
1064 /* See Table 28B-3 of 802.3ab-1999 spec. */
1065 if (local_adv & ADVERTISE_PAUSE_CAP) {
1066 if(local_adv & ADVERTISE_PAUSE_ASYM) {
1067 if (remote_adv & ADVERTISE_PAUSE_CAP) {
1068 bp->flow_ctrl = FLOW_CTRL_TX | FLOW_CTRL_RX;
1069 }
1070 else if (remote_adv & ADVERTISE_PAUSE_ASYM) {
1071 bp->flow_ctrl = FLOW_CTRL_RX;
1072 }
1073 }
1074 else {
1075 if (remote_adv & ADVERTISE_PAUSE_CAP) {
1076 bp->flow_ctrl = FLOW_CTRL_TX | FLOW_CTRL_RX;
1077 }
1078 }
1079 }
1080 else if (local_adv & ADVERTISE_PAUSE_ASYM) {
1081 if ((remote_adv & ADVERTISE_PAUSE_CAP) &&
1082 (remote_adv & ADVERTISE_PAUSE_ASYM)) {
1083
1084 bp->flow_ctrl = FLOW_CTRL_TX;
1085 }
1086 }
1087}
1088
1089static int
Michael Chan27a005b2007-05-03 13:23:41 -07001090bnx2_5709s_linkup(struct bnx2 *bp)
1091{
1092 u32 val, speed;
1093
1094 bp->link_up = 1;
1095
1096 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_GP_STATUS);
1097 bnx2_read_phy(bp, MII_BNX2_GP_TOP_AN_STATUS1, &val);
1098 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
1099
1100 if ((bp->autoneg & AUTONEG_SPEED) == 0) {
1101 bp->line_speed = bp->req_line_speed;
1102 bp->duplex = bp->req_duplex;
1103 return 0;
1104 }
1105 speed = val & MII_BNX2_GP_TOP_AN_SPEED_MSK;
1106 switch (speed) {
1107 case MII_BNX2_GP_TOP_AN_SPEED_10:
1108 bp->line_speed = SPEED_10;
1109 break;
1110 case MII_BNX2_GP_TOP_AN_SPEED_100:
1111 bp->line_speed = SPEED_100;
1112 break;
1113 case MII_BNX2_GP_TOP_AN_SPEED_1G:
1114 case MII_BNX2_GP_TOP_AN_SPEED_1GKV:
1115 bp->line_speed = SPEED_1000;
1116 break;
1117 case MII_BNX2_GP_TOP_AN_SPEED_2_5G:
1118 bp->line_speed = SPEED_2500;
1119 break;
1120 }
1121 if (val & MII_BNX2_GP_TOP_AN_FD)
1122 bp->duplex = DUPLEX_FULL;
1123 else
1124 bp->duplex = DUPLEX_HALF;
1125 return 0;
1126}
1127
1128static int
Michael Chan5b0c76a2005-11-04 08:45:49 -08001129bnx2_5708s_linkup(struct bnx2 *bp)
1130{
1131 u32 val;
1132
1133 bp->link_up = 1;
1134 bnx2_read_phy(bp, BCM5708S_1000X_STAT1, &val);
1135 switch (val & BCM5708S_1000X_STAT1_SPEED_MASK) {
1136 case BCM5708S_1000X_STAT1_SPEED_10:
1137 bp->line_speed = SPEED_10;
1138 break;
1139 case BCM5708S_1000X_STAT1_SPEED_100:
1140 bp->line_speed = SPEED_100;
1141 break;
1142 case BCM5708S_1000X_STAT1_SPEED_1G:
1143 bp->line_speed = SPEED_1000;
1144 break;
1145 case BCM5708S_1000X_STAT1_SPEED_2G5:
1146 bp->line_speed = SPEED_2500;
1147 break;
1148 }
1149 if (val & BCM5708S_1000X_STAT1_FD)
1150 bp->duplex = DUPLEX_FULL;
1151 else
1152 bp->duplex = DUPLEX_HALF;
1153
1154 return 0;
1155}
1156
1157static int
1158bnx2_5706s_linkup(struct bnx2 *bp)
Michael Chanb6016b72005-05-26 13:03:09 -07001159{
1160 u32 bmcr, local_adv, remote_adv, common;
1161
1162 bp->link_up = 1;
1163 bp->line_speed = SPEED_1000;
1164
Michael Chanca58c3a2007-05-03 13:22:52 -07001165 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chanb6016b72005-05-26 13:03:09 -07001166 if (bmcr & BMCR_FULLDPLX) {
1167 bp->duplex = DUPLEX_FULL;
1168 }
1169 else {
1170 bp->duplex = DUPLEX_HALF;
1171 }
1172
1173 if (!(bmcr & BMCR_ANENABLE)) {
1174 return 0;
1175 }
1176
Michael Chanca58c3a2007-05-03 13:22:52 -07001177 bnx2_read_phy(bp, bp->mii_adv, &local_adv);
1178 bnx2_read_phy(bp, bp->mii_lpa, &remote_adv);
Michael Chanb6016b72005-05-26 13:03:09 -07001179
1180 common = local_adv & remote_adv;
1181 if (common & (ADVERTISE_1000XHALF | ADVERTISE_1000XFULL)) {
1182
1183 if (common & ADVERTISE_1000XFULL) {
1184 bp->duplex = DUPLEX_FULL;
1185 }
1186 else {
1187 bp->duplex = DUPLEX_HALF;
1188 }
1189 }
1190
1191 return 0;
1192}
1193
1194static int
1195bnx2_copper_linkup(struct bnx2 *bp)
1196{
1197 u32 bmcr;
1198
Michael Chanca58c3a2007-05-03 13:22:52 -07001199 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chanb6016b72005-05-26 13:03:09 -07001200 if (bmcr & BMCR_ANENABLE) {
1201 u32 local_adv, remote_adv, common;
1202
1203 bnx2_read_phy(bp, MII_CTRL1000, &local_adv);
1204 bnx2_read_phy(bp, MII_STAT1000, &remote_adv);
1205
1206 common = local_adv & (remote_adv >> 2);
1207 if (common & ADVERTISE_1000FULL) {
1208 bp->line_speed = SPEED_1000;
1209 bp->duplex = DUPLEX_FULL;
1210 }
1211 else if (common & ADVERTISE_1000HALF) {
1212 bp->line_speed = SPEED_1000;
1213 bp->duplex = DUPLEX_HALF;
1214 }
1215 else {
Michael Chanca58c3a2007-05-03 13:22:52 -07001216 bnx2_read_phy(bp, bp->mii_adv, &local_adv);
1217 bnx2_read_phy(bp, bp->mii_lpa, &remote_adv);
Michael Chanb6016b72005-05-26 13:03:09 -07001218
1219 common = local_adv & remote_adv;
1220 if (common & ADVERTISE_100FULL) {
1221 bp->line_speed = SPEED_100;
1222 bp->duplex = DUPLEX_FULL;
1223 }
1224 else if (common & ADVERTISE_100HALF) {
1225 bp->line_speed = SPEED_100;
1226 bp->duplex = DUPLEX_HALF;
1227 }
1228 else if (common & ADVERTISE_10FULL) {
1229 bp->line_speed = SPEED_10;
1230 bp->duplex = DUPLEX_FULL;
1231 }
1232 else if (common & ADVERTISE_10HALF) {
1233 bp->line_speed = SPEED_10;
1234 bp->duplex = DUPLEX_HALF;
1235 }
1236 else {
1237 bp->line_speed = 0;
1238 bp->link_up = 0;
1239 }
1240 }
1241 }
1242 else {
1243 if (bmcr & BMCR_SPEED100) {
1244 bp->line_speed = SPEED_100;
1245 }
1246 else {
1247 bp->line_speed = SPEED_10;
1248 }
1249 if (bmcr & BMCR_FULLDPLX) {
1250 bp->duplex = DUPLEX_FULL;
1251 }
1252 else {
1253 bp->duplex = DUPLEX_HALF;
1254 }
1255 }
1256
1257 return 0;
1258}
1259
Michael Chan83e3fc82008-01-29 21:37:17 -08001260static void
Michael Chanbb4f98a2008-06-19 16:38:19 -07001261bnx2_init_rx_context(struct bnx2 *bp, u32 cid)
Michael Chan83e3fc82008-01-29 21:37:17 -08001262{
Michael Chanbb4f98a2008-06-19 16:38:19 -07001263 u32 val, rx_cid_addr = GET_CID_ADDR(cid);
Michael Chan83e3fc82008-01-29 21:37:17 -08001264
1265 val = BNX2_L2CTX_CTX_TYPE_CTX_BD_CHN_TYPE_VALUE;
1266 val |= BNX2_L2CTX_CTX_TYPE_SIZE_L2;
1267 val |= 0x02 << 8;
1268
Michael Chan22fa1592010-10-11 16:12:00 -07001269 if (bp->flow_ctrl & FLOW_CTRL_TX)
1270 val |= BNX2_L2CTX_FLOW_CTRL_ENABLE;
Michael Chan83e3fc82008-01-29 21:37:17 -08001271
Michael Chan83e3fc82008-01-29 21:37:17 -08001272 bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_CTX_TYPE, val);
1273}
1274
Michael Chanbb4f98a2008-06-19 16:38:19 -07001275static void
1276bnx2_init_all_rx_contexts(struct bnx2 *bp)
1277{
1278 int i;
1279 u32 cid;
1280
1281 for (i = 0, cid = RX_CID; i < bp->num_rx_rings; i++, cid++) {
1282 if (i == 1)
1283 cid = RX_RSS_CID;
1284 bnx2_init_rx_context(bp, cid);
1285 }
1286}
1287
Benjamin Li344478d2008-09-18 16:38:24 -07001288static void
Michael Chanb6016b72005-05-26 13:03:09 -07001289bnx2_set_mac_link(struct bnx2 *bp)
1290{
1291 u32 val;
1292
1293 REG_WR(bp, BNX2_EMAC_TX_LENGTHS, 0x2620);
1294 if (bp->link_up && (bp->line_speed == SPEED_1000) &&
1295 (bp->duplex == DUPLEX_HALF)) {
1296 REG_WR(bp, BNX2_EMAC_TX_LENGTHS, 0x26ff);
1297 }
1298
1299 /* Configure the EMAC mode register. */
1300 val = REG_RD(bp, BNX2_EMAC_MODE);
1301
1302 val &= ~(BNX2_EMAC_MODE_PORT | BNX2_EMAC_MODE_HALF_DUPLEX |
Michael Chan5b0c76a2005-11-04 08:45:49 -08001303 BNX2_EMAC_MODE_MAC_LOOP | BNX2_EMAC_MODE_FORCE_LINK |
Michael Chan59b47d82006-11-19 14:10:45 -08001304 BNX2_EMAC_MODE_25G_MODE);
Michael Chanb6016b72005-05-26 13:03:09 -07001305
1306 if (bp->link_up) {
Michael Chan5b0c76a2005-11-04 08:45:49 -08001307 switch (bp->line_speed) {
1308 case SPEED_10:
Michael Chan59b47d82006-11-19 14:10:45 -08001309 if (CHIP_NUM(bp) != CHIP_NUM_5706) {
1310 val |= BNX2_EMAC_MODE_PORT_MII_10M;
Michael Chan5b0c76a2005-11-04 08:45:49 -08001311 break;
1312 }
1313 /* fall through */
1314 case SPEED_100:
1315 val |= BNX2_EMAC_MODE_PORT_MII;
1316 break;
1317 case SPEED_2500:
Michael Chan59b47d82006-11-19 14:10:45 -08001318 val |= BNX2_EMAC_MODE_25G_MODE;
Michael Chan5b0c76a2005-11-04 08:45:49 -08001319 /* fall through */
1320 case SPEED_1000:
1321 val |= BNX2_EMAC_MODE_PORT_GMII;
1322 break;
1323 }
Michael Chanb6016b72005-05-26 13:03:09 -07001324 }
1325 else {
1326 val |= BNX2_EMAC_MODE_PORT_GMII;
1327 }
1328
1329 /* Set the MAC to operate in the appropriate duplex mode. */
1330 if (bp->duplex == DUPLEX_HALF)
1331 val |= BNX2_EMAC_MODE_HALF_DUPLEX;
1332 REG_WR(bp, BNX2_EMAC_MODE, val);
1333
1334 /* Enable/disable rx PAUSE. */
1335 bp->rx_mode &= ~BNX2_EMAC_RX_MODE_FLOW_EN;
1336
1337 if (bp->flow_ctrl & FLOW_CTRL_RX)
1338 bp->rx_mode |= BNX2_EMAC_RX_MODE_FLOW_EN;
1339 REG_WR(bp, BNX2_EMAC_RX_MODE, bp->rx_mode);
1340
1341 /* Enable/disable tx PAUSE. */
1342 val = REG_RD(bp, BNX2_EMAC_TX_MODE);
1343 val &= ~BNX2_EMAC_TX_MODE_FLOW_EN;
1344
1345 if (bp->flow_ctrl & FLOW_CTRL_TX)
1346 val |= BNX2_EMAC_TX_MODE_FLOW_EN;
1347 REG_WR(bp, BNX2_EMAC_TX_MODE, val);
1348
1349 /* Acknowledge the interrupt. */
1350 REG_WR(bp, BNX2_EMAC_STATUS, BNX2_EMAC_STATUS_LINK_CHANGE);
1351
Michael Chan22fa1592010-10-11 16:12:00 -07001352 bnx2_init_all_rx_contexts(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07001353}
1354
Michael Chan27a005b2007-05-03 13:23:41 -07001355static void
1356bnx2_enable_bmsr1(struct bnx2 *bp)
1357{
Michael Chan583c28e2008-01-21 19:51:35 -08001358 if ((bp->phy_flags & BNX2_PHY_FLAG_SERDES) &&
Michael Chan27a005b2007-05-03 13:23:41 -07001359 (CHIP_NUM(bp) == CHIP_NUM_5709))
1360 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
1361 MII_BNX2_BLK_ADDR_GP_STATUS);
1362}
1363
1364static void
1365bnx2_disable_bmsr1(struct bnx2 *bp)
1366{
Michael Chan583c28e2008-01-21 19:51:35 -08001367 if ((bp->phy_flags & BNX2_PHY_FLAG_SERDES) &&
Michael Chan27a005b2007-05-03 13:23:41 -07001368 (CHIP_NUM(bp) == CHIP_NUM_5709))
1369 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
1370 MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
1371}
1372
Michael Chanb6016b72005-05-26 13:03:09 -07001373static int
Michael Chan605a9e22007-05-03 13:23:13 -07001374bnx2_test_and_enable_2g5(struct bnx2 *bp)
1375{
1376 u32 up1;
1377 int ret = 1;
1378
Michael Chan583c28e2008-01-21 19:51:35 -08001379 if (!(bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE))
Michael Chan605a9e22007-05-03 13:23:13 -07001380 return 0;
1381
1382 if (bp->autoneg & AUTONEG_SPEED)
1383 bp->advertising |= ADVERTISED_2500baseX_Full;
1384
Michael Chan27a005b2007-05-03 13:23:41 -07001385 if (CHIP_NUM(bp) == CHIP_NUM_5709)
1386 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_OVER1G);
1387
Michael Chan605a9e22007-05-03 13:23:13 -07001388 bnx2_read_phy(bp, bp->mii_up1, &up1);
1389 if (!(up1 & BCM5708S_UP1_2G5)) {
1390 up1 |= BCM5708S_UP1_2G5;
1391 bnx2_write_phy(bp, bp->mii_up1, up1);
1392 ret = 0;
1393 }
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,
1397 MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
1398
Michael Chan605a9e22007-05-03 13:23:13 -07001399 return ret;
1400}
1401
1402static int
1403bnx2_test_and_disable_2g5(struct bnx2 *bp)
1404{
1405 u32 up1;
1406 int ret = 0;
1407
Michael Chan583c28e2008-01-21 19:51:35 -08001408 if (!(bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE))
Michael Chan605a9e22007-05-03 13:23:13 -07001409 return 0;
1410
Michael Chan27a005b2007-05-03 13:23:41 -07001411 if (CHIP_NUM(bp) == CHIP_NUM_5709)
1412 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_OVER1G);
1413
Michael Chan605a9e22007-05-03 13:23:13 -07001414 bnx2_read_phy(bp, bp->mii_up1, &up1);
1415 if (up1 & BCM5708S_UP1_2G5) {
1416 up1 &= ~BCM5708S_UP1_2G5;
1417 bnx2_write_phy(bp, bp->mii_up1, up1);
1418 ret = 1;
1419 }
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,
1423 MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
1424
Michael Chan605a9e22007-05-03 13:23:13 -07001425 return ret;
1426}
1427
1428static void
1429bnx2_enable_forced_2g5(struct bnx2 *bp)
1430{
Michael Chancbd68902010-06-08 07:21:30 +00001431 u32 uninitialized_var(bmcr);
1432 int err;
Michael Chan605a9e22007-05-03 13:23:13 -07001433
Michael Chan583c28e2008-01-21 19:51:35 -08001434 if (!(bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE))
Michael Chan605a9e22007-05-03 13:23:13 -07001435 return;
1436
Michael Chan27a005b2007-05-03 13:23:41 -07001437 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
1438 u32 val;
1439
1440 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
1441 MII_BNX2_BLK_ADDR_SERDES_DIG);
Michael Chancbd68902010-06-08 07:21:30 +00001442 if (!bnx2_read_phy(bp, MII_BNX2_SERDES_DIG_MISC1, &val)) {
1443 val &= ~MII_BNX2_SD_MISC1_FORCE_MSK;
1444 val |= MII_BNX2_SD_MISC1_FORCE |
1445 MII_BNX2_SD_MISC1_FORCE_2_5G;
1446 bnx2_write_phy(bp, MII_BNX2_SERDES_DIG_MISC1, val);
1447 }
Michael Chan27a005b2007-05-03 13:23:41 -07001448
1449 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
1450 MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
Michael Chancbd68902010-06-08 07:21:30 +00001451 err = bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chan27a005b2007-05-03 13:23:41 -07001452
1453 } else if (CHIP_NUM(bp) == CHIP_NUM_5708) {
Michael Chancbd68902010-06-08 07:21:30 +00001454 err = bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
1455 if (!err)
1456 bmcr |= BCM5708S_BMCR_FORCE_2500;
Eric Dumazetc70798572009-11-02 23:17:42 +00001457 } else {
1458 return;
Michael Chan605a9e22007-05-03 13:23:13 -07001459 }
1460
Michael Chancbd68902010-06-08 07:21:30 +00001461 if (err)
1462 return;
1463
Michael Chan605a9e22007-05-03 13:23:13 -07001464 if (bp->autoneg & AUTONEG_SPEED) {
1465 bmcr &= ~BMCR_ANENABLE;
1466 if (bp->req_duplex == DUPLEX_FULL)
1467 bmcr |= BMCR_FULLDPLX;
1468 }
1469 bnx2_write_phy(bp, bp->mii_bmcr, bmcr);
1470}
1471
1472static void
1473bnx2_disable_forced_2g5(struct bnx2 *bp)
1474{
Michael Chancbd68902010-06-08 07:21:30 +00001475 u32 uninitialized_var(bmcr);
1476 int err;
Michael Chan605a9e22007-05-03 13:23:13 -07001477
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);
Michael Chancbd68902010-06-08 07:21:30 +00001486 if (!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 }
Michael Chan27a005b2007-05-03 13:23:41 -07001490
1491 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
1492 MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
Michael Chancbd68902010-06-08 07:21:30 +00001493 err = bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chan27a005b2007-05-03 13:23:41 -07001494
1495 } else if (CHIP_NUM(bp) == CHIP_NUM_5708) {
Michael Chancbd68902010-06-08 07:21:30 +00001496 err = bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
1497 if (!err)
1498 bmcr &= ~BCM5708S_BMCR_FORCE_2500;
Eric Dumazetc70798572009-11-02 23:17:42 +00001499 } else {
1500 return;
Michael Chan605a9e22007-05-03 13:23:13 -07001501 }
1502
Michael Chancbd68902010-06-08 07:21:30 +00001503 if (err)
1504 return;
1505
Michael Chan605a9e22007-05-03 13:23:13 -07001506 if (bp->autoneg & AUTONEG_SPEED)
1507 bmcr |= BMCR_SPEED1000 | BMCR_ANENABLE | BMCR_ANRESTART;
1508 bnx2_write_phy(bp, bp->mii_bmcr, bmcr);
1509}
1510
Michael Chanb2fadea2008-01-21 17:07:06 -08001511static void
1512bnx2_5706s_force_link_dn(struct bnx2 *bp, int start)
1513{
1514 u32 val;
1515
1516 bnx2_write_phy(bp, MII_BNX2_DSP_ADDRESS, MII_EXPAND_SERDES_CTL);
1517 bnx2_read_phy(bp, MII_BNX2_DSP_RW_PORT, &val);
1518 if (start)
1519 bnx2_write_phy(bp, MII_BNX2_DSP_RW_PORT, val & 0xff0f);
1520 else
1521 bnx2_write_phy(bp, MII_BNX2_DSP_RW_PORT, val | 0xc0);
1522}
1523
Michael Chan605a9e22007-05-03 13:23:13 -07001524static int
Michael Chanb6016b72005-05-26 13:03:09 -07001525bnx2_set_link(struct bnx2 *bp)
1526{
1527 u32 bmsr;
1528 u8 link_up;
1529
Michael Chan80be4432006-11-19 14:07:28 -08001530 if (bp->loopback == MAC_LOOPBACK || bp->loopback == PHY_LOOPBACK) {
Michael Chanb6016b72005-05-26 13:03:09 -07001531 bp->link_up = 1;
1532 return 0;
1533 }
1534
Michael Chan583c28e2008-01-21 19:51:35 -08001535 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
Michael Chan0d8a6572007-07-07 22:49:43 -07001536 return 0;
1537
Michael Chanb6016b72005-05-26 13:03:09 -07001538 link_up = bp->link_up;
1539
Michael Chan27a005b2007-05-03 13:23:41 -07001540 bnx2_enable_bmsr1(bp);
1541 bnx2_read_phy(bp, bp->mii_bmsr1, &bmsr);
1542 bnx2_read_phy(bp, bp->mii_bmsr1, &bmsr);
1543 bnx2_disable_bmsr1(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07001544
Michael Chan583c28e2008-01-21 19:51:35 -08001545 if ((bp->phy_flags & BNX2_PHY_FLAG_SERDES) &&
Michael Chanb6016b72005-05-26 13:03:09 -07001546 (CHIP_NUM(bp) == CHIP_NUM_5706)) {
Michael Chana2724e22008-02-23 19:47:44 -08001547 u32 val, an_dbg;
Michael Chanb6016b72005-05-26 13:03:09 -07001548
Michael Chan583c28e2008-01-21 19:51:35 -08001549 if (bp->phy_flags & BNX2_PHY_FLAG_FORCED_DOWN) {
Michael Chanb2fadea2008-01-21 17:07:06 -08001550 bnx2_5706s_force_link_dn(bp, 0);
Michael Chan583c28e2008-01-21 19:51:35 -08001551 bp->phy_flags &= ~BNX2_PHY_FLAG_FORCED_DOWN;
Michael Chanb2fadea2008-01-21 17:07:06 -08001552 }
Michael Chanb6016b72005-05-26 13:03:09 -07001553 val = REG_RD(bp, BNX2_EMAC_STATUS);
Michael Chana2724e22008-02-23 19:47:44 -08001554
1555 bnx2_write_phy(bp, MII_BNX2_MISC_SHADOW, MISC_SHDW_AN_DBG);
1556 bnx2_read_phy(bp, MII_BNX2_MISC_SHADOW, &an_dbg);
1557 bnx2_read_phy(bp, MII_BNX2_MISC_SHADOW, &an_dbg);
1558
1559 if ((val & BNX2_EMAC_STATUS_LINK) &&
1560 !(an_dbg & MISC_SHDW_AN_DBG_NOSYNC))
Michael Chanb6016b72005-05-26 13:03:09 -07001561 bmsr |= BMSR_LSTATUS;
1562 else
1563 bmsr &= ~BMSR_LSTATUS;
1564 }
1565
1566 if (bmsr & BMSR_LSTATUS) {
1567 bp->link_up = 1;
1568
Michael Chan583c28e2008-01-21 19:51:35 -08001569 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Michael Chan5b0c76a2005-11-04 08:45:49 -08001570 if (CHIP_NUM(bp) == CHIP_NUM_5706)
1571 bnx2_5706s_linkup(bp);
1572 else if (CHIP_NUM(bp) == CHIP_NUM_5708)
1573 bnx2_5708s_linkup(bp);
Michael Chan27a005b2007-05-03 13:23:41 -07001574 else if (CHIP_NUM(bp) == CHIP_NUM_5709)
1575 bnx2_5709s_linkup(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07001576 }
1577 else {
1578 bnx2_copper_linkup(bp);
1579 }
1580 bnx2_resolve_flow_ctrl(bp);
1581 }
1582 else {
Michael Chan583c28e2008-01-21 19:51:35 -08001583 if ((bp->phy_flags & BNX2_PHY_FLAG_SERDES) &&
Michael Chan605a9e22007-05-03 13:23:13 -07001584 (bp->autoneg & AUTONEG_SPEED))
1585 bnx2_disable_forced_2g5(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07001586
Michael Chan583c28e2008-01-21 19:51:35 -08001587 if (bp->phy_flags & BNX2_PHY_FLAG_PARALLEL_DETECT) {
Michael Chanb2fadea2008-01-21 17:07:06 -08001588 u32 bmcr;
1589
1590 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
1591 bmcr |= BMCR_ANENABLE;
1592 bnx2_write_phy(bp, bp->mii_bmcr, bmcr);
1593
Michael Chan583c28e2008-01-21 19:51:35 -08001594 bp->phy_flags &= ~BNX2_PHY_FLAG_PARALLEL_DETECT;
Michael Chanb2fadea2008-01-21 17:07:06 -08001595 }
Michael Chanb6016b72005-05-26 13:03:09 -07001596 bp->link_up = 0;
1597 }
1598
1599 if (bp->link_up != link_up) {
1600 bnx2_report_link(bp);
1601 }
1602
1603 bnx2_set_mac_link(bp);
1604
1605 return 0;
1606}
1607
1608static int
1609bnx2_reset_phy(struct bnx2 *bp)
1610{
1611 int i;
1612 u32 reg;
1613
Michael Chanca58c3a2007-05-03 13:22:52 -07001614 bnx2_write_phy(bp, bp->mii_bmcr, BMCR_RESET);
Michael Chanb6016b72005-05-26 13:03:09 -07001615
1616#define PHY_RESET_MAX_WAIT 100
1617 for (i = 0; i < PHY_RESET_MAX_WAIT; i++) {
1618 udelay(10);
1619
Michael Chanca58c3a2007-05-03 13:22:52 -07001620 bnx2_read_phy(bp, bp->mii_bmcr, &reg);
Michael Chanb6016b72005-05-26 13:03:09 -07001621 if (!(reg & BMCR_RESET)) {
1622 udelay(20);
1623 break;
1624 }
1625 }
1626 if (i == PHY_RESET_MAX_WAIT) {
1627 return -EBUSY;
1628 }
1629 return 0;
1630}
1631
1632static u32
1633bnx2_phy_get_pause_adv(struct bnx2 *bp)
1634{
1635 u32 adv = 0;
1636
1637 if ((bp->req_flow_ctrl & (FLOW_CTRL_RX | FLOW_CTRL_TX)) ==
1638 (FLOW_CTRL_RX | FLOW_CTRL_TX)) {
1639
Michael Chan583c28e2008-01-21 19:51:35 -08001640 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Michael Chanb6016b72005-05-26 13:03:09 -07001641 adv = ADVERTISE_1000XPAUSE;
1642 }
1643 else {
1644 adv = ADVERTISE_PAUSE_CAP;
1645 }
1646 }
1647 else if (bp->req_flow_ctrl & FLOW_CTRL_TX) {
Michael Chan583c28e2008-01-21 19:51:35 -08001648 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Michael Chanb6016b72005-05-26 13:03:09 -07001649 adv = ADVERTISE_1000XPSE_ASYM;
1650 }
1651 else {
1652 adv = ADVERTISE_PAUSE_ASYM;
1653 }
1654 }
1655 else if (bp->req_flow_ctrl & FLOW_CTRL_RX) {
Michael Chan583c28e2008-01-21 19:51:35 -08001656 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Michael Chanb6016b72005-05-26 13:03:09 -07001657 adv = ADVERTISE_1000XPAUSE | ADVERTISE_1000XPSE_ASYM;
1658 }
1659 else {
1660 adv = ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM;
1661 }
1662 }
1663 return adv;
1664}
1665
Michael Chana2f13892008-07-14 22:38:23 -07001666static int bnx2_fw_sync(struct bnx2 *, u32, int, int);
Michael Chan0d8a6572007-07-07 22:49:43 -07001667
Michael Chanb6016b72005-05-26 13:03:09 -07001668static int
Michael Chan0d8a6572007-07-07 22:49:43 -07001669bnx2_setup_remote_phy(struct bnx2 *bp, u8 port)
Harvey Harrison52d07b12009-01-19 17:27:06 -08001670__releases(&bp->phy_lock)
1671__acquires(&bp->phy_lock)
Michael Chan0d8a6572007-07-07 22:49:43 -07001672{
1673 u32 speed_arg = 0, pause_adv;
1674
1675 pause_adv = bnx2_phy_get_pause_adv(bp);
1676
1677 if (bp->autoneg & AUTONEG_SPEED) {
1678 speed_arg |= BNX2_NETLINK_SET_LINK_ENABLE_AUTONEG;
1679 if (bp->advertising & ADVERTISED_10baseT_Half)
1680 speed_arg |= BNX2_NETLINK_SET_LINK_SPEED_10HALF;
1681 if (bp->advertising & ADVERTISED_10baseT_Full)
1682 speed_arg |= BNX2_NETLINK_SET_LINK_SPEED_10FULL;
1683 if (bp->advertising & ADVERTISED_100baseT_Half)
1684 speed_arg |= BNX2_NETLINK_SET_LINK_SPEED_100HALF;
1685 if (bp->advertising & ADVERTISED_100baseT_Full)
1686 speed_arg |= BNX2_NETLINK_SET_LINK_SPEED_100FULL;
1687 if (bp->advertising & ADVERTISED_1000baseT_Full)
1688 speed_arg |= BNX2_NETLINK_SET_LINK_SPEED_1GFULL;
1689 if (bp->advertising & ADVERTISED_2500baseX_Full)
1690 speed_arg |= BNX2_NETLINK_SET_LINK_SPEED_2G5FULL;
1691 } else {
1692 if (bp->req_line_speed == SPEED_2500)
1693 speed_arg = BNX2_NETLINK_SET_LINK_SPEED_2G5FULL;
1694 else if (bp->req_line_speed == SPEED_1000)
1695 speed_arg = BNX2_NETLINK_SET_LINK_SPEED_1GFULL;
1696 else if (bp->req_line_speed == SPEED_100) {
1697 if (bp->req_duplex == DUPLEX_FULL)
1698 speed_arg = BNX2_NETLINK_SET_LINK_SPEED_100FULL;
1699 else
1700 speed_arg = BNX2_NETLINK_SET_LINK_SPEED_100HALF;
1701 } else if (bp->req_line_speed == SPEED_10) {
1702 if (bp->req_duplex == DUPLEX_FULL)
1703 speed_arg = BNX2_NETLINK_SET_LINK_SPEED_10FULL;
1704 else
1705 speed_arg = BNX2_NETLINK_SET_LINK_SPEED_10HALF;
1706 }
1707 }
1708
1709 if (pause_adv & (ADVERTISE_1000XPAUSE | ADVERTISE_PAUSE_CAP))
1710 speed_arg |= BNX2_NETLINK_SET_LINK_FC_SYM_PAUSE;
Michael Chanc26736e2008-01-31 17:07:21 -08001711 if (pause_adv & (ADVERTISE_1000XPSE_ASYM | ADVERTISE_PAUSE_ASYM))
Michael Chan0d8a6572007-07-07 22:49:43 -07001712 speed_arg |= BNX2_NETLINK_SET_LINK_FC_ASYM_PAUSE;
1713
1714 if (port == PORT_TP)
1715 speed_arg |= BNX2_NETLINK_SET_LINK_PHY_APP_REMOTE |
1716 BNX2_NETLINK_SET_LINK_ETH_AT_WIRESPEED;
1717
Michael Chan2726d6e2008-01-29 21:35:05 -08001718 bnx2_shmem_wr(bp, BNX2_DRV_MB_ARG0, speed_arg);
Michael Chan0d8a6572007-07-07 22:49:43 -07001719
1720 spin_unlock_bh(&bp->phy_lock);
Michael Chana2f13892008-07-14 22:38:23 -07001721 bnx2_fw_sync(bp, BNX2_DRV_MSG_CODE_CMD_SET_LINK, 1, 0);
Michael Chan0d8a6572007-07-07 22:49:43 -07001722 spin_lock_bh(&bp->phy_lock);
1723
1724 return 0;
1725}
1726
1727static int
1728bnx2_setup_serdes_phy(struct bnx2 *bp, u8 port)
Harvey Harrison52d07b12009-01-19 17:27:06 -08001729__releases(&bp->phy_lock)
1730__acquires(&bp->phy_lock)
Michael Chanb6016b72005-05-26 13:03:09 -07001731{
Michael Chan605a9e22007-05-03 13:23:13 -07001732 u32 adv, bmcr;
Michael Chanb6016b72005-05-26 13:03:09 -07001733 u32 new_adv = 0;
1734
Michael Chan583c28e2008-01-21 19:51:35 -08001735 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
Eric Dumazet807540b2010-09-23 05:40:09 +00001736 return bnx2_setup_remote_phy(bp, port);
Michael Chan0d8a6572007-07-07 22:49:43 -07001737
Michael Chanb6016b72005-05-26 13:03:09 -07001738 if (!(bp->autoneg & AUTONEG_SPEED)) {
1739 u32 new_bmcr;
Michael Chan5b0c76a2005-11-04 08:45:49 -08001740 int force_link_down = 0;
1741
Michael Chan605a9e22007-05-03 13:23:13 -07001742 if (bp->req_line_speed == SPEED_2500) {
1743 if (!bnx2_test_and_enable_2g5(bp))
1744 force_link_down = 1;
1745 } else if (bp->req_line_speed == SPEED_1000) {
1746 if (bnx2_test_and_disable_2g5(bp))
1747 force_link_down = 1;
1748 }
Michael Chanca58c3a2007-05-03 13:22:52 -07001749 bnx2_read_phy(bp, bp->mii_adv, &adv);
Michael Chan80be4432006-11-19 14:07:28 -08001750 adv &= ~(ADVERTISE_1000XFULL | ADVERTISE_1000XHALF);
1751
Michael Chanca58c3a2007-05-03 13:22:52 -07001752 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chan605a9e22007-05-03 13:23:13 -07001753 new_bmcr = bmcr & ~BMCR_ANENABLE;
Michael Chan80be4432006-11-19 14:07:28 -08001754 new_bmcr |= BMCR_SPEED1000;
Michael Chan605a9e22007-05-03 13:23:13 -07001755
Michael Chan27a005b2007-05-03 13:23:41 -07001756 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
1757 if (bp->req_line_speed == SPEED_2500)
1758 bnx2_enable_forced_2g5(bp);
1759 else if (bp->req_line_speed == SPEED_1000) {
1760 bnx2_disable_forced_2g5(bp);
1761 new_bmcr &= ~0x2000;
1762 }
1763
1764 } else if (CHIP_NUM(bp) == CHIP_NUM_5708) {
Michael Chan605a9e22007-05-03 13:23:13 -07001765 if (bp->req_line_speed == SPEED_2500)
1766 new_bmcr |= BCM5708S_BMCR_FORCE_2500;
1767 else
1768 new_bmcr = bmcr & ~BCM5708S_BMCR_FORCE_2500;
Michael Chan5b0c76a2005-11-04 08:45:49 -08001769 }
1770
Michael Chanb6016b72005-05-26 13:03:09 -07001771 if (bp->req_duplex == DUPLEX_FULL) {
Michael Chan5b0c76a2005-11-04 08:45:49 -08001772 adv |= ADVERTISE_1000XFULL;
Michael Chanb6016b72005-05-26 13:03:09 -07001773 new_bmcr |= BMCR_FULLDPLX;
1774 }
1775 else {
Michael Chan5b0c76a2005-11-04 08:45:49 -08001776 adv |= ADVERTISE_1000XHALF;
Michael Chanb6016b72005-05-26 13:03:09 -07001777 new_bmcr &= ~BMCR_FULLDPLX;
1778 }
Michael Chan5b0c76a2005-11-04 08:45:49 -08001779 if ((new_bmcr != bmcr) || (force_link_down)) {
Michael Chanb6016b72005-05-26 13:03:09 -07001780 /* Force a link down visible on the other side */
1781 if (bp->link_up) {
Michael Chanca58c3a2007-05-03 13:22:52 -07001782 bnx2_write_phy(bp, bp->mii_adv, adv &
Michael Chan5b0c76a2005-11-04 08:45:49 -08001783 ~(ADVERTISE_1000XFULL |
1784 ADVERTISE_1000XHALF));
Michael Chanca58c3a2007-05-03 13:22:52 -07001785 bnx2_write_phy(bp, bp->mii_bmcr, bmcr |
Michael Chanb6016b72005-05-26 13:03:09 -07001786 BMCR_ANRESTART | BMCR_ANENABLE);
1787
1788 bp->link_up = 0;
1789 netif_carrier_off(bp->dev);
Michael Chanca58c3a2007-05-03 13:22:52 -07001790 bnx2_write_phy(bp, bp->mii_bmcr, new_bmcr);
Michael Chan80be4432006-11-19 14:07:28 -08001791 bnx2_report_link(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07001792 }
Michael Chanca58c3a2007-05-03 13:22:52 -07001793 bnx2_write_phy(bp, bp->mii_adv, adv);
1794 bnx2_write_phy(bp, bp->mii_bmcr, new_bmcr);
Michael Chan605a9e22007-05-03 13:23:13 -07001795 } else {
1796 bnx2_resolve_flow_ctrl(bp);
1797 bnx2_set_mac_link(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07001798 }
1799 return 0;
1800 }
1801
Michael Chan605a9e22007-05-03 13:23:13 -07001802 bnx2_test_and_enable_2g5(bp);
Michael Chan5b0c76a2005-11-04 08:45:49 -08001803
Michael Chanb6016b72005-05-26 13:03:09 -07001804 if (bp->advertising & ADVERTISED_1000baseT_Full)
1805 new_adv |= ADVERTISE_1000XFULL;
1806
1807 new_adv |= bnx2_phy_get_pause_adv(bp);
1808
Michael Chanca58c3a2007-05-03 13:22:52 -07001809 bnx2_read_phy(bp, bp->mii_adv, &adv);
1810 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chanb6016b72005-05-26 13:03:09 -07001811
1812 bp->serdes_an_pending = 0;
1813 if ((adv != new_adv) || ((bmcr & BMCR_ANENABLE) == 0)) {
1814 /* Force a link down visible on the other side */
1815 if (bp->link_up) {
Michael Chanca58c3a2007-05-03 13:22:52 -07001816 bnx2_write_phy(bp, bp->mii_bmcr, BMCR_LOOPBACK);
Michael Chan80be4432006-11-19 14:07:28 -08001817 spin_unlock_bh(&bp->phy_lock);
1818 msleep(20);
1819 spin_lock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07001820 }
1821
Michael Chanca58c3a2007-05-03 13:22:52 -07001822 bnx2_write_phy(bp, bp->mii_adv, new_adv);
1823 bnx2_write_phy(bp, bp->mii_bmcr, bmcr | BMCR_ANRESTART |
Michael Chanb6016b72005-05-26 13:03:09 -07001824 BMCR_ANENABLE);
Michael Chanf8dd0642006-11-19 14:08:29 -08001825 /* Speed up link-up time when the link partner
1826 * does not autonegotiate which is very common
1827 * in blade servers. Some blade servers use
1828 * IPMI for kerboard input and it's important
1829 * to minimize link disruptions. Autoneg. involves
1830 * exchanging base pages plus 3 next pages and
1831 * normally completes in about 120 msec.
1832 */
Michael Chan40105c02008-11-12 16:02:45 -08001833 bp->current_interval = BNX2_SERDES_AN_TIMEOUT;
Michael Chanf8dd0642006-11-19 14:08:29 -08001834 bp->serdes_an_pending = 1;
1835 mod_timer(&bp->timer, jiffies + bp->current_interval);
Michael Chan605a9e22007-05-03 13:23:13 -07001836 } else {
1837 bnx2_resolve_flow_ctrl(bp);
1838 bnx2_set_mac_link(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07001839 }
1840
1841 return 0;
1842}
1843
1844#define ETHTOOL_ALL_FIBRE_SPEED \
Michael Chan583c28e2008-01-21 19:51:35 -08001845 (bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE) ? \
Michael Chandeaf3912007-07-07 22:48:00 -07001846 (ADVERTISED_2500baseX_Full | ADVERTISED_1000baseT_Full) :\
1847 (ADVERTISED_1000baseT_Full)
Michael Chanb6016b72005-05-26 13:03:09 -07001848
1849#define ETHTOOL_ALL_COPPER_SPEED \
1850 (ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full | \
1851 ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full | \
1852 ADVERTISED_1000baseT_Full)
1853
1854#define PHY_ALL_10_100_SPEED (ADVERTISE_10HALF | ADVERTISE_10FULL | \
1855 ADVERTISE_100HALF | ADVERTISE_100FULL | ADVERTISE_CSMA)
Jeff Garzik6aa20a22006-09-13 13:24:59 -04001856
Michael Chanb6016b72005-05-26 13:03:09 -07001857#define PHY_ALL_1000_SPEED (ADVERTISE_1000HALF | ADVERTISE_1000FULL)
1858
Michael Chandeaf3912007-07-07 22:48:00 -07001859static void
Michael Chan0d8a6572007-07-07 22:49:43 -07001860bnx2_set_default_remote_link(struct bnx2 *bp)
1861{
1862 u32 link;
1863
1864 if (bp->phy_port == PORT_TP)
Michael Chan2726d6e2008-01-29 21:35:05 -08001865 link = bnx2_shmem_rd(bp, BNX2_RPHY_COPPER_LINK);
Michael Chan0d8a6572007-07-07 22:49:43 -07001866 else
Michael Chan2726d6e2008-01-29 21:35:05 -08001867 link = bnx2_shmem_rd(bp, BNX2_RPHY_SERDES_LINK);
Michael Chan0d8a6572007-07-07 22:49:43 -07001868
1869 if (link & BNX2_NETLINK_SET_LINK_ENABLE_AUTONEG) {
1870 bp->req_line_speed = 0;
1871 bp->autoneg |= AUTONEG_SPEED;
1872 bp->advertising = ADVERTISED_Autoneg;
1873 if (link & BNX2_NETLINK_SET_LINK_SPEED_10HALF)
1874 bp->advertising |= ADVERTISED_10baseT_Half;
1875 if (link & BNX2_NETLINK_SET_LINK_SPEED_10FULL)
1876 bp->advertising |= ADVERTISED_10baseT_Full;
1877 if (link & BNX2_NETLINK_SET_LINK_SPEED_100HALF)
1878 bp->advertising |= ADVERTISED_100baseT_Half;
1879 if (link & BNX2_NETLINK_SET_LINK_SPEED_100FULL)
1880 bp->advertising |= ADVERTISED_100baseT_Full;
1881 if (link & BNX2_NETLINK_SET_LINK_SPEED_1GFULL)
1882 bp->advertising |= ADVERTISED_1000baseT_Full;
1883 if (link & BNX2_NETLINK_SET_LINK_SPEED_2G5FULL)
1884 bp->advertising |= ADVERTISED_2500baseX_Full;
1885 } else {
1886 bp->autoneg = 0;
1887 bp->advertising = 0;
1888 bp->req_duplex = DUPLEX_FULL;
1889 if (link & BNX2_NETLINK_SET_LINK_SPEED_10) {
1890 bp->req_line_speed = SPEED_10;
1891 if (link & BNX2_NETLINK_SET_LINK_SPEED_10HALF)
1892 bp->req_duplex = DUPLEX_HALF;
1893 }
1894 if (link & BNX2_NETLINK_SET_LINK_SPEED_100) {
1895 bp->req_line_speed = SPEED_100;
1896 if (link & BNX2_NETLINK_SET_LINK_SPEED_100HALF)
1897 bp->req_duplex = DUPLEX_HALF;
1898 }
1899 if (link & BNX2_NETLINK_SET_LINK_SPEED_1GFULL)
1900 bp->req_line_speed = SPEED_1000;
1901 if (link & BNX2_NETLINK_SET_LINK_SPEED_2G5FULL)
1902 bp->req_line_speed = SPEED_2500;
1903 }
1904}
1905
1906static void
Michael Chandeaf3912007-07-07 22:48:00 -07001907bnx2_set_default_link(struct bnx2 *bp)
1908{
Harvey Harrisonab598592008-05-01 02:47:38 -07001909 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP) {
1910 bnx2_set_default_remote_link(bp);
1911 return;
1912 }
Michael Chan0d8a6572007-07-07 22:49:43 -07001913
Michael Chandeaf3912007-07-07 22:48:00 -07001914 bp->autoneg = AUTONEG_SPEED | AUTONEG_FLOW_CTRL;
1915 bp->req_line_speed = 0;
Michael Chan583c28e2008-01-21 19:51:35 -08001916 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Michael Chandeaf3912007-07-07 22:48:00 -07001917 u32 reg;
1918
1919 bp->advertising = ETHTOOL_ALL_FIBRE_SPEED | ADVERTISED_Autoneg;
1920
Michael Chan2726d6e2008-01-29 21:35:05 -08001921 reg = bnx2_shmem_rd(bp, BNX2_PORT_HW_CFG_CONFIG);
Michael Chandeaf3912007-07-07 22:48:00 -07001922 reg &= BNX2_PORT_HW_CFG_CFG_DFLT_LINK_MASK;
1923 if (reg == BNX2_PORT_HW_CFG_CFG_DFLT_LINK_1G) {
1924 bp->autoneg = 0;
1925 bp->req_line_speed = bp->line_speed = SPEED_1000;
1926 bp->req_duplex = DUPLEX_FULL;
1927 }
1928 } else
1929 bp->advertising = ETHTOOL_ALL_COPPER_SPEED | ADVERTISED_Autoneg;
1930}
1931
Michael Chan0d8a6572007-07-07 22:49:43 -07001932static void
Michael Chandf149d72007-07-07 22:51:36 -07001933bnx2_send_heart_beat(struct bnx2 *bp)
1934{
1935 u32 msg;
1936 u32 addr;
1937
1938 spin_lock(&bp->indirect_lock);
1939 msg = (u32) (++bp->fw_drv_pulse_wr_seq & BNX2_DRV_PULSE_SEQ_MASK);
1940 addr = bp->shmem_base + BNX2_DRV_PULSE_MB;
1941 REG_WR(bp, BNX2_PCICFG_REG_WINDOW_ADDRESS, addr);
1942 REG_WR(bp, BNX2_PCICFG_REG_WINDOW, msg);
1943 spin_unlock(&bp->indirect_lock);
1944}
1945
1946static void
Michael Chan0d8a6572007-07-07 22:49:43 -07001947bnx2_remote_phy_event(struct bnx2 *bp)
1948{
1949 u32 msg;
1950 u8 link_up = bp->link_up;
1951 u8 old_port;
1952
Michael Chan2726d6e2008-01-29 21:35:05 -08001953 msg = bnx2_shmem_rd(bp, BNX2_LINK_STATUS);
Michael Chan0d8a6572007-07-07 22:49:43 -07001954
Michael Chandf149d72007-07-07 22:51:36 -07001955 if (msg & BNX2_LINK_STATUS_HEART_BEAT_EXPIRED)
1956 bnx2_send_heart_beat(bp);
1957
1958 msg &= ~BNX2_LINK_STATUS_HEART_BEAT_EXPIRED;
1959
Michael Chan0d8a6572007-07-07 22:49:43 -07001960 if ((msg & BNX2_LINK_STATUS_LINK_UP) == BNX2_LINK_STATUS_LINK_DOWN)
1961 bp->link_up = 0;
1962 else {
1963 u32 speed;
1964
1965 bp->link_up = 1;
1966 speed = msg & BNX2_LINK_STATUS_SPEED_MASK;
1967 bp->duplex = DUPLEX_FULL;
1968 switch (speed) {
1969 case BNX2_LINK_STATUS_10HALF:
1970 bp->duplex = DUPLEX_HALF;
1971 case BNX2_LINK_STATUS_10FULL:
1972 bp->line_speed = SPEED_10;
1973 break;
1974 case BNX2_LINK_STATUS_100HALF:
1975 bp->duplex = DUPLEX_HALF;
1976 case BNX2_LINK_STATUS_100BASE_T4:
1977 case BNX2_LINK_STATUS_100FULL:
1978 bp->line_speed = SPEED_100;
1979 break;
1980 case BNX2_LINK_STATUS_1000HALF:
1981 bp->duplex = DUPLEX_HALF;
1982 case BNX2_LINK_STATUS_1000FULL:
1983 bp->line_speed = SPEED_1000;
1984 break;
1985 case BNX2_LINK_STATUS_2500HALF:
1986 bp->duplex = DUPLEX_HALF;
1987 case BNX2_LINK_STATUS_2500FULL:
1988 bp->line_speed = SPEED_2500;
1989 break;
1990 default:
1991 bp->line_speed = 0;
1992 break;
1993 }
1994
Michael Chan0d8a6572007-07-07 22:49:43 -07001995 bp->flow_ctrl = 0;
1996 if ((bp->autoneg & (AUTONEG_SPEED | AUTONEG_FLOW_CTRL)) !=
1997 (AUTONEG_SPEED | AUTONEG_FLOW_CTRL)) {
1998 if (bp->duplex == DUPLEX_FULL)
1999 bp->flow_ctrl = bp->req_flow_ctrl;
2000 } else {
2001 if (msg & BNX2_LINK_STATUS_TX_FC_ENABLED)
2002 bp->flow_ctrl |= FLOW_CTRL_TX;
2003 if (msg & BNX2_LINK_STATUS_RX_FC_ENABLED)
2004 bp->flow_ctrl |= FLOW_CTRL_RX;
2005 }
2006
2007 old_port = bp->phy_port;
2008 if (msg & BNX2_LINK_STATUS_SERDES_LINK)
2009 bp->phy_port = PORT_FIBRE;
2010 else
2011 bp->phy_port = PORT_TP;
2012
2013 if (old_port != bp->phy_port)
2014 bnx2_set_default_link(bp);
2015
Michael Chan0d8a6572007-07-07 22:49:43 -07002016 }
2017 if (bp->link_up != link_up)
2018 bnx2_report_link(bp);
2019
2020 bnx2_set_mac_link(bp);
2021}
2022
2023static int
2024bnx2_set_remote_link(struct bnx2 *bp)
2025{
2026 u32 evt_code;
2027
Michael Chan2726d6e2008-01-29 21:35:05 -08002028 evt_code = bnx2_shmem_rd(bp, BNX2_FW_EVT_CODE_MB);
Michael Chan0d8a6572007-07-07 22:49:43 -07002029 switch (evt_code) {
2030 case BNX2_FW_EVT_CODE_LINK_EVENT:
2031 bnx2_remote_phy_event(bp);
2032 break;
2033 case BNX2_FW_EVT_CODE_SW_TIMER_EXPIRATION_EVENT:
2034 default:
Michael Chandf149d72007-07-07 22:51:36 -07002035 bnx2_send_heart_beat(bp);
Michael Chan0d8a6572007-07-07 22:49:43 -07002036 break;
2037 }
2038 return 0;
2039}
2040
Michael Chanb6016b72005-05-26 13:03:09 -07002041static int
2042bnx2_setup_copper_phy(struct bnx2 *bp)
Harvey Harrison52d07b12009-01-19 17:27:06 -08002043__releases(&bp->phy_lock)
2044__acquires(&bp->phy_lock)
Michael Chanb6016b72005-05-26 13:03:09 -07002045{
2046 u32 bmcr;
2047 u32 new_bmcr;
2048
Michael Chanca58c3a2007-05-03 13:22:52 -07002049 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chanb6016b72005-05-26 13:03:09 -07002050
2051 if (bp->autoneg & AUTONEG_SPEED) {
2052 u32 adv_reg, adv1000_reg;
2053 u32 new_adv_reg = 0;
2054 u32 new_adv1000_reg = 0;
2055
Michael Chanca58c3a2007-05-03 13:22:52 -07002056 bnx2_read_phy(bp, bp->mii_adv, &adv_reg);
Michael Chanb6016b72005-05-26 13:03:09 -07002057 adv_reg &= (PHY_ALL_10_100_SPEED | ADVERTISE_PAUSE_CAP |
2058 ADVERTISE_PAUSE_ASYM);
2059
2060 bnx2_read_phy(bp, MII_CTRL1000, &adv1000_reg);
2061 adv1000_reg &= PHY_ALL_1000_SPEED;
2062
2063 if (bp->advertising & ADVERTISED_10baseT_Half)
2064 new_adv_reg |= ADVERTISE_10HALF;
2065 if (bp->advertising & ADVERTISED_10baseT_Full)
2066 new_adv_reg |= ADVERTISE_10FULL;
2067 if (bp->advertising & ADVERTISED_100baseT_Half)
2068 new_adv_reg |= ADVERTISE_100HALF;
2069 if (bp->advertising & ADVERTISED_100baseT_Full)
2070 new_adv_reg |= ADVERTISE_100FULL;
2071 if (bp->advertising & ADVERTISED_1000baseT_Full)
2072 new_adv1000_reg |= ADVERTISE_1000FULL;
Jeff Garzik6aa20a22006-09-13 13:24:59 -04002073
Michael Chanb6016b72005-05-26 13:03:09 -07002074 new_adv_reg |= ADVERTISE_CSMA;
2075
2076 new_adv_reg |= bnx2_phy_get_pause_adv(bp);
2077
2078 if ((adv1000_reg != new_adv1000_reg) ||
2079 (adv_reg != new_adv_reg) ||
2080 ((bmcr & BMCR_ANENABLE) == 0)) {
2081
Michael Chanca58c3a2007-05-03 13:22:52 -07002082 bnx2_write_phy(bp, bp->mii_adv, new_adv_reg);
Michael Chanb6016b72005-05-26 13:03:09 -07002083 bnx2_write_phy(bp, MII_CTRL1000, new_adv1000_reg);
Michael Chanca58c3a2007-05-03 13:22:52 -07002084 bnx2_write_phy(bp, bp->mii_bmcr, BMCR_ANRESTART |
Michael Chanb6016b72005-05-26 13:03:09 -07002085 BMCR_ANENABLE);
2086 }
2087 else if (bp->link_up) {
2088 /* Flow ctrl may have changed from auto to forced */
2089 /* or vice-versa. */
2090
2091 bnx2_resolve_flow_ctrl(bp);
2092 bnx2_set_mac_link(bp);
2093 }
2094 return 0;
2095 }
2096
2097 new_bmcr = 0;
2098 if (bp->req_line_speed == SPEED_100) {
2099 new_bmcr |= BMCR_SPEED100;
2100 }
2101 if (bp->req_duplex == DUPLEX_FULL) {
2102 new_bmcr |= BMCR_FULLDPLX;
2103 }
2104 if (new_bmcr != bmcr) {
2105 u32 bmsr;
Michael Chanb6016b72005-05-26 13:03:09 -07002106
Michael Chanca58c3a2007-05-03 13:22:52 -07002107 bnx2_read_phy(bp, bp->mii_bmsr, &bmsr);
2108 bnx2_read_phy(bp, bp->mii_bmsr, &bmsr);
Jeff Garzik6aa20a22006-09-13 13:24:59 -04002109
Michael Chanb6016b72005-05-26 13:03:09 -07002110 if (bmsr & BMSR_LSTATUS) {
2111 /* Force link down */
Michael Chanca58c3a2007-05-03 13:22:52 -07002112 bnx2_write_phy(bp, bp->mii_bmcr, BMCR_LOOPBACK);
Michael Chana16dda02006-11-19 14:08:56 -08002113 spin_unlock_bh(&bp->phy_lock);
2114 msleep(50);
2115 spin_lock_bh(&bp->phy_lock);
2116
Michael Chanca58c3a2007-05-03 13:22:52 -07002117 bnx2_read_phy(bp, bp->mii_bmsr, &bmsr);
2118 bnx2_read_phy(bp, bp->mii_bmsr, &bmsr);
Michael Chanb6016b72005-05-26 13:03:09 -07002119 }
2120
Michael Chanca58c3a2007-05-03 13:22:52 -07002121 bnx2_write_phy(bp, bp->mii_bmcr, new_bmcr);
Michael Chanb6016b72005-05-26 13:03:09 -07002122
2123 /* Normally, the new speed is setup after the link has
2124 * gone down and up again. In some cases, link will not go
2125 * down so we need to set up the new speed here.
2126 */
2127 if (bmsr & BMSR_LSTATUS) {
2128 bp->line_speed = bp->req_line_speed;
2129 bp->duplex = bp->req_duplex;
2130 bnx2_resolve_flow_ctrl(bp);
2131 bnx2_set_mac_link(bp);
2132 }
Michael Chan27a005b2007-05-03 13:23:41 -07002133 } else {
2134 bnx2_resolve_flow_ctrl(bp);
2135 bnx2_set_mac_link(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07002136 }
2137 return 0;
2138}
2139
2140static int
Michael Chan0d8a6572007-07-07 22:49:43 -07002141bnx2_setup_phy(struct bnx2 *bp, u8 port)
Harvey Harrison52d07b12009-01-19 17:27:06 -08002142__releases(&bp->phy_lock)
2143__acquires(&bp->phy_lock)
Michael Chanb6016b72005-05-26 13:03:09 -07002144{
2145 if (bp->loopback == MAC_LOOPBACK)
2146 return 0;
2147
Michael Chan583c28e2008-01-21 19:51:35 -08002148 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Eric Dumazet807540b2010-09-23 05:40:09 +00002149 return bnx2_setup_serdes_phy(bp, port);
Michael Chanb6016b72005-05-26 13:03:09 -07002150 }
2151 else {
Eric Dumazet807540b2010-09-23 05:40:09 +00002152 return bnx2_setup_copper_phy(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07002153 }
2154}
2155
2156static int
Michael Chan9a120bc2008-05-16 22:17:45 -07002157bnx2_init_5709s_phy(struct bnx2 *bp, int reset_phy)
Michael Chan27a005b2007-05-03 13:23:41 -07002158{
2159 u32 val;
2160
2161 bp->mii_bmcr = MII_BMCR + 0x10;
2162 bp->mii_bmsr = MII_BMSR + 0x10;
2163 bp->mii_bmsr1 = MII_BNX2_GP_TOP_AN_STATUS1;
2164 bp->mii_adv = MII_ADVERTISE + 0x10;
2165 bp->mii_lpa = MII_LPA + 0x10;
2166 bp->mii_up1 = MII_BNX2_OVER1G_UP1;
2167
2168 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_AER);
2169 bnx2_write_phy(bp, MII_BNX2_AER_AER, MII_BNX2_AER_AER_AN_MMD);
2170
2171 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
Michael Chan9a120bc2008-05-16 22:17:45 -07002172 if (reset_phy)
2173 bnx2_reset_phy(bp);
Michael Chan27a005b2007-05-03 13:23:41 -07002174
2175 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_SERDES_DIG);
2176
2177 bnx2_read_phy(bp, MII_BNX2_SERDES_DIG_1000XCTL1, &val);
2178 val &= ~MII_BNX2_SD_1000XCTL1_AUTODET;
2179 val |= MII_BNX2_SD_1000XCTL1_FIBER;
2180 bnx2_write_phy(bp, MII_BNX2_SERDES_DIG_1000XCTL1, val);
2181
2182 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_OVER1G);
2183 bnx2_read_phy(bp, MII_BNX2_OVER1G_UP1, &val);
Michael Chan583c28e2008-01-21 19:51:35 -08002184 if (bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE)
Michael Chan27a005b2007-05-03 13:23:41 -07002185 val |= BCM5708S_UP1_2G5;
2186 else
2187 val &= ~BCM5708S_UP1_2G5;
2188 bnx2_write_phy(bp, MII_BNX2_OVER1G_UP1, val);
2189
2190 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_BAM_NXTPG);
2191 bnx2_read_phy(bp, MII_BNX2_BAM_NXTPG_CTL, &val);
2192 val |= MII_BNX2_NXTPG_CTL_T2 | MII_BNX2_NXTPG_CTL_BAM;
2193 bnx2_write_phy(bp, MII_BNX2_BAM_NXTPG_CTL, val);
2194
2195 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_CL73_USERB0);
2196
2197 val = MII_BNX2_CL73_BAM_EN | MII_BNX2_CL73_BAM_STA_MGR_EN |
2198 MII_BNX2_CL73_BAM_NP_AFT_BP_EN;
2199 bnx2_write_phy(bp, MII_BNX2_CL73_BAM_CTL1, val);
2200
2201 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
2202
2203 return 0;
2204}
2205
2206static int
Michael Chan9a120bc2008-05-16 22:17:45 -07002207bnx2_init_5708s_phy(struct bnx2 *bp, int reset_phy)
Michael Chan5b0c76a2005-11-04 08:45:49 -08002208{
2209 u32 val;
2210
Michael Chan9a120bc2008-05-16 22:17:45 -07002211 if (reset_phy)
2212 bnx2_reset_phy(bp);
Michael Chan27a005b2007-05-03 13:23:41 -07002213
2214 bp->mii_up1 = BCM5708S_UP1;
2215
Michael Chan5b0c76a2005-11-04 08:45:49 -08002216 bnx2_write_phy(bp, BCM5708S_BLK_ADDR, BCM5708S_BLK_ADDR_DIG3);
2217 bnx2_write_phy(bp, BCM5708S_DIG_3_0, BCM5708S_DIG_3_0_USE_IEEE);
2218 bnx2_write_phy(bp, BCM5708S_BLK_ADDR, BCM5708S_BLK_ADDR_DIG);
2219
2220 bnx2_read_phy(bp, BCM5708S_1000X_CTL1, &val);
2221 val |= BCM5708S_1000X_CTL1_FIBER_MODE | BCM5708S_1000X_CTL1_AUTODET_EN;
2222 bnx2_write_phy(bp, BCM5708S_1000X_CTL1, val);
2223
2224 bnx2_read_phy(bp, BCM5708S_1000X_CTL2, &val);
2225 val |= BCM5708S_1000X_CTL2_PLLEL_DET_EN;
2226 bnx2_write_phy(bp, BCM5708S_1000X_CTL2, val);
2227
Michael Chan583c28e2008-01-21 19:51:35 -08002228 if (bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE) {
Michael Chan5b0c76a2005-11-04 08:45:49 -08002229 bnx2_read_phy(bp, BCM5708S_UP1, &val);
2230 val |= BCM5708S_UP1_2G5;
2231 bnx2_write_phy(bp, BCM5708S_UP1, val);
2232 }
2233
2234 if ((CHIP_ID(bp) == CHIP_ID_5708_A0) ||
Michael Chandda1e392006-01-23 16:08:14 -08002235 (CHIP_ID(bp) == CHIP_ID_5708_B0) ||
2236 (CHIP_ID(bp) == CHIP_ID_5708_B1)) {
Michael Chan5b0c76a2005-11-04 08:45:49 -08002237 /* increase tx signal amplitude */
2238 bnx2_write_phy(bp, BCM5708S_BLK_ADDR,
2239 BCM5708S_BLK_ADDR_TX_MISC);
2240 bnx2_read_phy(bp, BCM5708S_TX_ACTL1, &val);
2241 val &= ~BCM5708S_TX_ACTL1_DRIVER_VCM;
2242 bnx2_write_phy(bp, BCM5708S_TX_ACTL1, val);
2243 bnx2_write_phy(bp, BCM5708S_BLK_ADDR, BCM5708S_BLK_ADDR_DIG);
2244 }
2245
Michael Chan2726d6e2008-01-29 21:35:05 -08002246 val = bnx2_shmem_rd(bp, BNX2_PORT_HW_CFG_CONFIG) &
Michael Chan5b0c76a2005-11-04 08:45:49 -08002247 BNX2_PORT_HW_CFG_CFG_TXCTL3_MASK;
2248
2249 if (val) {
2250 u32 is_backplane;
2251
Michael Chan2726d6e2008-01-29 21:35:05 -08002252 is_backplane = bnx2_shmem_rd(bp, BNX2_SHARED_HW_CFG_CONFIG);
Michael Chan5b0c76a2005-11-04 08:45:49 -08002253 if (is_backplane & BNX2_SHARED_HW_CFG_PHY_BACKPLANE) {
2254 bnx2_write_phy(bp, BCM5708S_BLK_ADDR,
2255 BCM5708S_BLK_ADDR_TX_MISC);
2256 bnx2_write_phy(bp, BCM5708S_TX_ACTL3, val);
2257 bnx2_write_phy(bp, BCM5708S_BLK_ADDR,
2258 BCM5708S_BLK_ADDR_DIG);
2259 }
2260 }
2261 return 0;
2262}
2263
2264static int
Michael Chan9a120bc2008-05-16 22:17:45 -07002265bnx2_init_5706s_phy(struct bnx2 *bp, int reset_phy)
Michael Chanb6016b72005-05-26 13:03:09 -07002266{
Michael Chan9a120bc2008-05-16 22:17:45 -07002267 if (reset_phy)
2268 bnx2_reset_phy(bp);
Michael Chan27a005b2007-05-03 13:23:41 -07002269
Michael Chan583c28e2008-01-21 19:51:35 -08002270 bp->phy_flags &= ~BNX2_PHY_FLAG_PARALLEL_DETECT;
Michael Chanb6016b72005-05-26 13:03:09 -07002271
Michael Chan59b47d82006-11-19 14:10:45 -08002272 if (CHIP_NUM(bp) == CHIP_NUM_5706)
2273 REG_WR(bp, BNX2_MISC_GP_HW_CTL0, 0x300);
Michael Chanb6016b72005-05-26 13:03:09 -07002274
2275 if (bp->dev->mtu > 1500) {
2276 u32 val;
2277
2278 /* Set extended packet length bit */
2279 bnx2_write_phy(bp, 0x18, 0x7);
2280 bnx2_read_phy(bp, 0x18, &val);
2281 bnx2_write_phy(bp, 0x18, (val & 0xfff8) | 0x4000);
2282
2283 bnx2_write_phy(bp, 0x1c, 0x6c00);
2284 bnx2_read_phy(bp, 0x1c, &val);
2285 bnx2_write_phy(bp, 0x1c, (val & 0x3ff) | 0xec02);
2286 }
2287 else {
2288 u32 val;
2289
2290 bnx2_write_phy(bp, 0x18, 0x7);
2291 bnx2_read_phy(bp, 0x18, &val);
2292 bnx2_write_phy(bp, 0x18, val & ~0x4007);
2293
2294 bnx2_write_phy(bp, 0x1c, 0x6c00);
2295 bnx2_read_phy(bp, 0x1c, &val);
2296 bnx2_write_phy(bp, 0x1c, (val & 0x3fd) | 0xec00);
2297 }
2298
2299 return 0;
2300}
2301
2302static int
Michael Chan9a120bc2008-05-16 22:17:45 -07002303bnx2_init_copper_phy(struct bnx2 *bp, int reset_phy)
Michael Chanb6016b72005-05-26 13:03:09 -07002304{
Michael Chan5b0c76a2005-11-04 08:45:49 -08002305 u32 val;
2306
Michael Chan9a120bc2008-05-16 22:17:45 -07002307 if (reset_phy)
2308 bnx2_reset_phy(bp);
Michael Chan27a005b2007-05-03 13:23:41 -07002309
Michael Chan583c28e2008-01-21 19:51:35 -08002310 if (bp->phy_flags & BNX2_PHY_FLAG_CRC_FIX) {
Michael Chanb6016b72005-05-26 13:03:09 -07002311 bnx2_write_phy(bp, 0x18, 0x0c00);
2312 bnx2_write_phy(bp, 0x17, 0x000a);
2313 bnx2_write_phy(bp, 0x15, 0x310b);
2314 bnx2_write_phy(bp, 0x17, 0x201f);
2315 bnx2_write_phy(bp, 0x15, 0x9506);
2316 bnx2_write_phy(bp, 0x17, 0x401f);
2317 bnx2_write_phy(bp, 0x15, 0x14e2);
2318 bnx2_write_phy(bp, 0x18, 0x0400);
2319 }
2320
Michael Chan583c28e2008-01-21 19:51:35 -08002321 if (bp->phy_flags & BNX2_PHY_FLAG_DIS_EARLY_DAC) {
Michael Chanb659f442007-02-02 00:46:35 -08002322 bnx2_write_phy(bp, MII_BNX2_DSP_ADDRESS,
2323 MII_BNX2_DSP_EXPAND_REG | 0x8);
2324 bnx2_read_phy(bp, MII_BNX2_DSP_RW_PORT, &val);
2325 val &= ~(1 << 8);
2326 bnx2_write_phy(bp, MII_BNX2_DSP_RW_PORT, val);
2327 }
2328
Michael Chanb6016b72005-05-26 13:03:09 -07002329 if (bp->dev->mtu > 1500) {
Michael Chanb6016b72005-05-26 13:03:09 -07002330 /* Set extended packet length bit */
2331 bnx2_write_phy(bp, 0x18, 0x7);
2332 bnx2_read_phy(bp, 0x18, &val);
2333 bnx2_write_phy(bp, 0x18, val | 0x4000);
2334
2335 bnx2_read_phy(bp, 0x10, &val);
2336 bnx2_write_phy(bp, 0x10, val | 0x1);
2337 }
2338 else {
Michael Chanb6016b72005-05-26 13:03:09 -07002339 bnx2_write_phy(bp, 0x18, 0x7);
2340 bnx2_read_phy(bp, 0x18, &val);
2341 bnx2_write_phy(bp, 0x18, val & ~0x4007);
2342
2343 bnx2_read_phy(bp, 0x10, &val);
2344 bnx2_write_phy(bp, 0x10, val & ~0x1);
2345 }
2346
Michael Chan5b0c76a2005-11-04 08:45:49 -08002347 /* ethernet@wirespeed */
2348 bnx2_write_phy(bp, 0x18, 0x7007);
2349 bnx2_read_phy(bp, 0x18, &val);
2350 bnx2_write_phy(bp, 0x18, val | (1 << 15) | (1 << 4));
Michael Chanb6016b72005-05-26 13:03:09 -07002351 return 0;
2352}
2353
2354
2355static int
Michael Chan9a120bc2008-05-16 22:17:45 -07002356bnx2_init_phy(struct bnx2 *bp, int reset_phy)
Harvey Harrison52d07b12009-01-19 17:27:06 -08002357__releases(&bp->phy_lock)
2358__acquires(&bp->phy_lock)
Michael Chanb6016b72005-05-26 13:03:09 -07002359{
2360 u32 val;
2361 int rc = 0;
2362
Michael Chan583c28e2008-01-21 19:51:35 -08002363 bp->phy_flags &= ~BNX2_PHY_FLAG_INT_MODE_MASK;
2364 bp->phy_flags |= BNX2_PHY_FLAG_INT_MODE_LINK_READY;
Michael Chanb6016b72005-05-26 13:03:09 -07002365
Michael Chanca58c3a2007-05-03 13:22:52 -07002366 bp->mii_bmcr = MII_BMCR;
2367 bp->mii_bmsr = MII_BMSR;
Michael Chan27a005b2007-05-03 13:23:41 -07002368 bp->mii_bmsr1 = MII_BMSR;
Michael Chanca58c3a2007-05-03 13:22:52 -07002369 bp->mii_adv = MII_ADVERTISE;
2370 bp->mii_lpa = MII_LPA;
2371
Michael Chanb6016b72005-05-26 13:03:09 -07002372 REG_WR(bp, BNX2_EMAC_ATTENTION_ENA, BNX2_EMAC_ATTENTION_ENA_LINK);
2373
Michael Chan583c28e2008-01-21 19:51:35 -08002374 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
Michael Chan0d8a6572007-07-07 22:49:43 -07002375 goto setup_phy;
2376
Michael Chanb6016b72005-05-26 13:03:09 -07002377 bnx2_read_phy(bp, MII_PHYSID1, &val);
2378 bp->phy_id = val << 16;
2379 bnx2_read_phy(bp, MII_PHYSID2, &val);
2380 bp->phy_id |= val & 0xffff;
2381
Michael Chan583c28e2008-01-21 19:51:35 -08002382 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Michael Chan5b0c76a2005-11-04 08:45:49 -08002383 if (CHIP_NUM(bp) == CHIP_NUM_5706)
Michael Chan9a120bc2008-05-16 22:17:45 -07002384 rc = bnx2_init_5706s_phy(bp, reset_phy);
Michael Chan5b0c76a2005-11-04 08:45:49 -08002385 else if (CHIP_NUM(bp) == CHIP_NUM_5708)
Michael Chan9a120bc2008-05-16 22:17:45 -07002386 rc = bnx2_init_5708s_phy(bp, reset_phy);
Michael Chan27a005b2007-05-03 13:23:41 -07002387 else if (CHIP_NUM(bp) == CHIP_NUM_5709)
Michael Chan9a120bc2008-05-16 22:17:45 -07002388 rc = bnx2_init_5709s_phy(bp, reset_phy);
Michael Chanb6016b72005-05-26 13:03:09 -07002389 }
2390 else {
Michael Chan9a120bc2008-05-16 22:17:45 -07002391 rc = bnx2_init_copper_phy(bp, reset_phy);
Michael Chanb6016b72005-05-26 13:03:09 -07002392 }
2393
Michael Chan0d8a6572007-07-07 22:49:43 -07002394setup_phy:
2395 if (!rc)
2396 rc = bnx2_setup_phy(bp, bp->phy_port);
Michael Chanb6016b72005-05-26 13:03:09 -07002397
2398 return rc;
2399}
2400
2401static int
2402bnx2_set_mac_loopback(struct bnx2 *bp)
2403{
2404 u32 mac_mode;
2405
2406 mac_mode = REG_RD(bp, BNX2_EMAC_MODE);
2407 mac_mode &= ~BNX2_EMAC_MODE_PORT;
2408 mac_mode |= BNX2_EMAC_MODE_MAC_LOOP | BNX2_EMAC_MODE_FORCE_LINK;
2409 REG_WR(bp, BNX2_EMAC_MODE, mac_mode);
2410 bp->link_up = 1;
2411 return 0;
2412}
2413
Michael Chanbc5a0692006-01-23 16:13:22 -08002414static int bnx2_test_link(struct bnx2 *);
2415
2416static int
2417bnx2_set_phy_loopback(struct bnx2 *bp)
2418{
2419 u32 mac_mode;
2420 int rc, i;
2421
2422 spin_lock_bh(&bp->phy_lock);
Michael Chanca58c3a2007-05-03 13:22:52 -07002423 rc = bnx2_write_phy(bp, bp->mii_bmcr, BMCR_LOOPBACK | BMCR_FULLDPLX |
Michael Chanbc5a0692006-01-23 16:13:22 -08002424 BMCR_SPEED1000);
2425 spin_unlock_bh(&bp->phy_lock);
2426 if (rc)
2427 return rc;
2428
2429 for (i = 0; i < 10; i++) {
2430 if (bnx2_test_link(bp) == 0)
2431 break;
Michael Chan80be4432006-11-19 14:07:28 -08002432 msleep(100);
Michael Chanbc5a0692006-01-23 16:13:22 -08002433 }
2434
2435 mac_mode = REG_RD(bp, BNX2_EMAC_MODE);
2436 mac_mode &= ~(BNX2_EMAC_MODE_PORT | BNX2_EMAC_MODE_HALF_DUPLEX |
2437 BNX2_EMAC_MODE_MAC_LOOP | BNX2_EMAC_MODE_FORCE_LINK |
Michael Chan59b47d82006-11-19 14:10:45 -08002438 BNX2_EMAC_MODE_25G_MODE);
Michael Chanbc5a0692006-01-23 16:13:22 -08002439
2440 mac_mode |= BNX2_EMAC_MODE_PORT_GMII;
2441 REG_WR(bp, BNX2_EMAC_MODE, mac_mode);
2442 bp->link_up = 1;
2443 return 0;
2444}
2445
Jeffrey Huangecdbf6e2011-07-13 17:24:21 +00002446static void
2447bnx2_dump_mcp_state(struct bnx2 *bp)
2448{
2449 struct net_device *dev = bp->dev;
2450 u32 mcp_p0, mcp_p1;
2451
2452 netdev_err(dev, "<--- start MCP states dump --->\n");
2453 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
2454 mcp_p0 = BNX2_MCP_STATE_P0;
2455 mcp_p1 = BNX2_MCP_STATE_P1;
2456 } else {
2457 mcp_p0 = BNX2_MCP_STATE_P0_5708;
2458 mcp_p1 = BNX2_MCP_STATE_P1_5708;
2459 }
2460 netdev_err(dev, "DEBUG: MCP_STATE_P0[%08x] MCP_STATE_P1[%08x]\n",
2461 bnx2_reg_rd_ind(bp, mcp_p0), bnx2_reg_rd_ind(bp, mcp_p1));
2462 netdev_err(dev, "DEBUG: MCP mode[%08x] state[%08x] evt_mask[%08x]\n",
2463 bnx2_reg_rd_ind(bp, BNX2_MCP_CPU_MODE),
2464 bnx2_reg_rd_ind(bp, BNX2_MCP_CPU_STATE),
2465 bnx2_reg_rd_ind(bp, BNX2_MCP_CPU_EVENT_MASK));
2466 netdev_err(dev, "DEBUG: pc[%08x] pc[%08x] instr[%08x]\n",
2467 bnx2_reg_rd_ind(bp, BNX2_MCP_CPU_PROGRAM_COUNTER),
2468 bnx2_reg_rd_ind(bp, BNX2_MCP_CPU_PROGRAM_COUNTER),
2469 bnx2_reg_rd_ind(bp, BNX2_MCP_CPU_INSTRUCTION));
2470 netdev_err(dev, "DEBUG: shmem states:\n");
2471 netdev_err(dev, "DEBUG: drv_mb[%08x] fw_mb[%08x] link_status[%08x]",
2472 bnx2_shmem_rd(bp, BNX2_DRV_MB),
2473 bnx2_shmem_rd(bp, BNX2_FW_MB),
2474 bnx2_shmem_rd(bp, BNX2_LINK_STATUS));
2475 pr_cont(" drv_pulse_mb[%08x]\n", bnx2_shmem_rd(bp, BNX2_DRV_PULSE_MB));
2476 netdev_err(dev, "DEBUG: dev_info_signature[%08x] reset_type[%08x]",
2477 bnx2_shmem_rd(bp, BNX2_DEV_INFO_SIGNATURE),
2478 bnx2_shmem_rd(bp, BNX2_BC_STATE_RESET_TYPE));
2479 pr_cont(" condition[%08x]\n",
2480 bnx2_shmem_rd(bp, BNX2_BC_STATE_CONDITION));
2481 DP_SHMEM_LINE(bp, 0x3cc);
2482 DP_SHMEM_LINE(bp, 0x3dc);
2483 DP_SHMEM_LINE(bp, 0x3ec);
2484 netdev_err(dev, "DEBUG: 0x3fc[%08x]\n", bnx2_shmem_rd(bp, 0x3fc));
2485 netdev_err(dev, "<--- end MCP states dump --->\n");
2486}
2487
Michael Chanb6016b72005-05-26 13:03:09 -07002488static int
Michael Chana2f13892008-07-14 22:38:23 -07002489bnx2_fw_sync(struct bnx2 *bp, u32 msg_data, int ack, int silent)
Michael Chanb6016b72005-05-26 13:03:09 -07002490{
2491 int i;
2492 u32 val;
2493
Michael Chanb6016b72005-05-26 13:03:09 -07002494 bp->fw_wr_seq++;
2495 msg_data |= bp->fw_wr_seq;
2496
Michael Chan2726d6e2008-01-29 21:35:05 -08002497 bnx2_shmem_wr(bp, BNX2_DRV_MB, msg_data);
Michael Chanb6016b72005-05-26 13:03:09 -07002498
Michael Chana2f13892008-07-14 22:38:23 -07002499 if (!ack)
2500 return 0;
2501
Michael Chanb6016b72005-05-26 13:03:09 -07002502 /* wait for an acknowledgement. */
Michael Chan40105c02008-11-12 16:02:45 -08002503 for (i = 0; i < (BNX2_FW_ACK_TIME_OUT_MS / 10); i++) {
Michael Chanb090ae22006-01-23 16:07:10 -08002504 msleep(10);
Michael Chanb6016b72005-05-26 13:03:09 -07002505
Michael Chan2726d6e2008-01-29 21:35:05 -08002506 val = bnx2_shmem_rd(bp, BNX2_FW_MB);
Michael Chanb6016b72005-05-26 13:03:09 -07002507
2508 if ((val & BNX2_FW_MSG_ACK) == (msg_data & BNX2_DRV_MSG_SEQ))
2509 break;
2510 }
Michael Chanb090ae22006-01-23 16:07:10 -08002511 if ((msg_data & BNX2_DRV_MSG_DATA) == BNX2_DRV_MSG_DATA_WAIT0)
2512 return 0;
Michael Chanb6016b72005-05-26 13:03:09 -07002513
2514 /* If we timed out, inform the firmware that this is the case. */
Michael Chanb090ae22006-01-23 16:07:10 -08002515 if ((val & BNX2_FW_MSG_ACK) != (msg_data & BNX2_DRV_MSG_SEQ)) {
Michael Chanb6016b72005-05-26 13:03:09 -07002516 msg_data &= ~BNX2_DRV_MSG_CODE;
2517 msg_data |= BNX2_DRV_MSG_CODE_FW_TIMEOUT;
2518
Michael Chan2726d6e2008-01-29 21:35:05 -08002519 bnx2_shmem_wr(bp, BNX2_DRV_MB, msg_data);
Jeffrey Huangecdbf6e2011-07-13 17:24:21 +00002520 if (!silent) {
2521 pr_err("fw sync timeout, reset code = %x\n", msg_data);
2522 bnx2_dump_mcp_state(bp);
2523 }
Michael Chanb6016b72005-05-26 13:03:09 -07002524
Michael Chanb6016b72005-05-26 13:03:09 -07002525 return -EBUSY;
2526 }
2527
Michael Chanb090ae22006-01-23 16:07:10 -08002528 if ((val & BNX2_FW_MSG_STATUS_MASK) != BNX2_FW_MSG_STATUS_OK)
2529 return -EIO;
2530
Michael Chanb6016b72005-05-26 13:03:09 -07002531 return 0;
2532}
2533
Michael Chan59b47d82006-11-19 14:10:45 -08002534static int
2535bnx2_init_5709_context(struct bnx2 *bp)
2536{
2537 int i, ret = 0;
2538 u32 val;
2539
2540 val = BNX2_CTX_COMMAND_ENABLED | BNX2_CTX_COMMAND_MEM_INIT | (1 << 12);
2541 val |= (BCM_PAGE_BITS - 8) << 16;
2542 REG_WR(bp, BNX2_CTX_COMMAND, val);
Michael Chan641bdcd2007-06-04 21:22:24 -07002543 for (i = 0; i < 10; i++) {
2544 val = REG_RD(bp, BNX2_CTX_COMMAND);
2545 if (!(val & BNX2_CTX_COMMAND_MEM_INIT))
2546 break;
2547 udelay(2);
2548 }
2549 if (val & BNX2_CTX_COMMAND_MEM_INIT)
2550 return -EBUSY;
2551
Michael Chan59b47d82006-11-19 14:10:45 -08002552 for (i = 0; i < bp->ctx_pages; i++) {
2553 int j;
2554
Michael Chan352f7682008-05-02 16:57:26 -07002555 if (bp->ctx_blk[i])
2556 memset(bp->ctx_blk[i], 0, BCM_PAGE_SIZE);
2557 else
2558 return -ENOMEM;
2559
Michael Chan59b47d82006-11-19 14:10:45 -08002560 REG_WR(bp, BNX2_CTX_HOST_PAGE_TBL_DATA0,
2561 (bp->ctx_blk_mapping[i] & 0xffffffff) |
2562 BNX2_CTX_HOST_PAGE_TBL_DATA0_VALID);
2563 REG_WR(bp, BNX2_CTX_HOST_PAGE_TBL_DATA1,
2564 (u64) bp->ctx_blk_mapping[i] >> 32);
2565 REG_WR(bp, BNX2_CTX_HOST_PAGE_TBL_CTRL, i |
2566 BNX2_CTX_HOST_PAGE_TBL_CTRL_WRITE_REQ);
2567 for (j = 0; j < 10; j++) {
2568
2569 val = REG_RD(bp, BNX2_CTX_HOST_PAGE_TBL_CTRL);
2570 if (!(val & BNX2_CTX_HOST_PAGE_TBL_CTRL_WRITE_REQ))
2571 break;
2572 udelay(5);
2573 }
2574 if (val & BNX2_CTX_HOST_PAGE_TBL_CTRL_WRITE_REQ) {
2575 ret = -EBUSY;
2576 break;
2577 }
2578 }
2579 return ret;
2580}
2581
Michael Chanb6016b72005-05-26 13:03:09 -07002582static void
2583bnx2_init_context(struct bnx2 *bp)
2584{
2585 u32 vcid;
2586
2587 vcid = 96;
2588 while (vcid) {
2589 u32 vcid_addr, pcid_addr, offset;
Michael Chan7947b202007-06-04 21:17:10 -07002590 int i;
Michael Chanb6016b72005-05-26 13:03:09 -07002591
2592 vcid--;
2593
2594 if (CHIP_ID(bp) == CHIP_ID_5706_A0) {
2595 u32 new_vcid;
2596
2597 vcid_addr = GET_PCID_ADDR(vcid);
2598 if (vcid & 0x8) {
2599 new_vcid = 0x60 + (vcid & 0xf0) + (vcid & 0x7);
2600 }
2601 else {
2602 new_vcid = vcid;
2603 }
2604 pcid_addr = GET_PCID_ADDR(new_vcid);
2605 }
2606 else {
2607 vcid_addr = GET_CID_ADDR(vcid);
2608 pcid_addr = vcid_addr;
2609 }
2610
Michael Chan7947b202007-06-04 21:17:10 -07002611 for (i = 0; i < (CTX_SIZE / PHY_CTX_SIZE); i++) {
2612 vcid_addr += (i << PHY_CTX_SHIFT);
2613 pcid_addr += (i << PHY_CTX_SHIFT);
Michael Chanb6016b72005-05-26 13:03:09 -07002614
Michael Chan5d5d0012007-12-12 11:17:43 -08002615 REG_WR(bp, BNX2_CTX_VIRT_ADDR, vcid_addr);
Michael Chan7947b202007-06-04 21:17:10 -07002616 REG_WR(bp, BNX2_CTX_PAGE_TBL, pcid_addr);
2617
2618 /* Zero out the context. */
2619 for (offset = 0; offset < PHY_CTX_SIZE; offset += 4)
Michael Chan62a83132008-01-29 21:35:40 -08002620 bnx2_ctx_wr(bp, vcid_addr, offset, 0);
Michael Chanb6016b72005-05-26 13:03:09 -07002621 }
Michael Chanb6016b72005-05-26 13:03:09 -07002622 }
2623}
2624
2625static int
2626bnx2_alloc_bad_rbuf(struct bnx2 *bp)
2627{
2628 u16 *good_mbuf;
2629 u32 good_mbuf_cnt;
2630 u32 val;
2631
2632 good_mbuf = kmalloc(512 * sizeof(u16), GFP_KERNEL);
2633 if (good_mbuf == NULL) {
Joe Perches3a9c6a42010-02-17 15:01:51 +00002634 pr_err("Failed to allocate memory in %s\n", __func__);
Michael Chanb6016b72005-05-26 13:03:09 -07002635 return -ENOMEM;
2636 }
2637
2638 REG_WR(bp, BNX2_MISC_ENABLE_SET_BITS,
2639 BNX2_MISC_ENABLE_SET_BITS_RX_MBUF_ENABLE);
2640
2641 good_mbuf_cnt = 0;
2642
2643 /* Allocate a bunch of mbufs and save the good ones in an array. */
Michael Chan2726d6e2008-01-29 21:35:05 -08002644 val = bnx2_reg_rd_ind(bp, BNX2_RBUF_STATUS1);
Michael Chanb6016b72005-05-26 13:03:09 -07002645 while (val & BNX2_RBUF_STATUS1_FREE_COUNT) {
Michael Chan2726d6e2008-01-29 21:35:05 -08002646 bnx2_reg_wr_ind(bp, BNX2_RBUF_COMMAND,
2647 BNX2_RBUF_COMMAND_ALLOC_REQ);
Michael Chanb6016b72005-05-26 13:03:09 -07002648
Michael Chan2726d6e2008-01-29 21:35:05 -08002649 val = bnx2_reg_rd_ind(bp, BNX2_RBUF_FW_BUF_ALLOC);
Michael Chanb6016b72005-05-26 13:03:09 -07002650
2651 val &= BNX2_RBUF_FW_BUF_ALLOC_VALUE;
2652
2653 /* The addresses with Bit 9 set are bad memory blocks. */
2654 if (!(val & (1 << 9))) {
2655 good_mbuf[good_mbuf_cnt] = (u16) val;
2656 good_mbuf_cnt++;
2657 }
2658
Michael Chan2726d6e2008-01-29 21:35:05 -08002659 val = bnx2_reg_rd_ind(bp, BNX2_RBUF_STATUS1);
Michael Chanb6016b72005-05-26 13:03:09 -07002660 }
2661
2662 /* Free the good ones back to the mbuf pool thus discarding
2663 * all the bad ones. */
2664 while (good_mbuf_cnt) {
2665 good_mbuf_cnt--;
2666
2667 val = good_mbuf[good_mbuf_cnt];
2668 val = (val << 9) | val | 1;
2669
Michael Chan2726d6e2008-01-29 21:35:05 -08002670 bnx2_reg_wr_ind(bp, BNX2_RBUF_FW_BUF_FREE, val);
Michael Chanb6016b72005-05-26 13:03:09 -07002671 }
2672 kfree(good_mbuf);
2673 return 0;
2674}
2675
2676static void
Benjamin Li5fcaed02008-07-14 22:39:52 -07002677bnx2_set_mac_addr(struct bnx2 *bp, u8 *mac_addr, u32 pos)
Michael Chanb6016b72005-05-26 13:03:09 -07002678{
2679 u32 val;
Michael Chanb6016b72005-05-26 13:03:09 -07002680
2681 val = (mac_addr[0] << 8) | mac_addr[1];
2682
Benjamin Li5fcaed02008-07-14 22:39:52 -07002683 REG_WR(bp, BNX2_EMAC_MAC_MATCH0 + (pos * 8), val);
Michael Chanb6016b72005-05-26 13:03:09 -07002684
Jeff Garzik6aa20a22006-09-13 13:24:59 -04002685 val = (mac_addr[2] << 24) | (mac_addr[3] << 16) |
Michael Chanb6016b72005-05-26 13:03:09 -07002686 (mac_addr[4] << 8) | mac_addr[5];
2687
Benjamin Li5fcaed02008-07-14 22:39:52 -07002688 REG_WR(bp, BNX2_EMAC_MAC_MATCH1 + (pos * 8), val);
Michael Chanb6016b72005-05-26 13:03:09 -07002689}
2690
2691static inline int
Stanislaw Gruszkaa2df00a2010-07-15 22:55:40 +00002692bnx2_alloc_rx_page(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr, u16 index, gfp_t gfp)
Michael Chan47bf4242007-12-12 11:19:12 -08002693{
2694 dma_addr_t mapping;
Michael Chanbb4f98a2008-06-19 16:38:19 -07002695 struct sw_pg *rx_pg = &rxr->rx_pg_ring[index];
Michael Chan47bf4242007-12-12 11:19:12 -08002696 struct rx_bd *rxbd =
Michael Chanbb4f98a2008-06-19 16:38:19 -07002697 &rxr->rx_pg_desc_ring[RX_RING(index)][RX_IDX(index)];
Stanislaw Gruszkaa2df00a2010-07-15 22:55:40 +00002698 struct page *page = alloc_page(gfp);
Michael Chan47bf4242007-12-12 11:19:12 -08002699
2700 if (!page)
2701 return -ENOMEM;
Stanislaw Gruszka36227e82010-07-15 04:25:50 +00002702 mapping = dma_map_page(&bp->pdev->dev, page, 0, PAGE_SIZE,
Michael Chan47bf4242007-12-12 11:19:12 -08002703 PCI_DMA_FROMDEVICE);
Stanislaw Gruszka36227e82010-07-15 04:25:50 +00002704 if (dma_mapping_error(&bp->pdev->dev, mapping)) {
Benjamin Li3d16af82008-10-09 12:26:41 -07002705 __free_page(page);
2706 return -EIO;
2707 }
2708
Michael Chan47bf4242007-12-12 11:19:12 -08002709 rx_pg->page = page;
FUJITA Tomonori1a4ccc22010-04-01 16:56:57 +00002710 dma_unmap_addr_set(rx_pg, mapping, mapping);
Michael Chan47bf4242007-12-12 11:19:12 -08002711 rxbd->rx_bd_haddr_hi = (u64) mapping >> 32;
2712 rxbd->rx_bd_haddr_lo = (u64) mapping & 0xffffffff;
2713 return 0;
2714}
2715
2716static void
Michael Chanbb4f98a2008-06-19 16:38:19 -07002717bnx2_free_rx_page(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr, u16 index)
Michael Chan47bf4242007-12-12 11:19:12 -08002718{
Michael Chanbb4f98a2008-06-19 16:38:19 -07002719 struct sw_pg *rx_pg = &rxr->rx_pg_ring[index];
Michael Chan47bf4242007-12-12 11:19:12 -08002720 struct page *page = rx_pg->page;
2721
2722 if (!page)
2723 return;
2724
Stanislaw Gruszka36227e82010-07-15 04:25:50 +00002725 dma_unmap_page(&bp->pdev->dev, dma_unmap_addr(rx_pg, mapping),
2726 PAGE_SIZE, PCI_DMA_FROMDEVICE);
Michael Chan47bf4242007-12-12 11:19:12 -08002727
2728 __free_page(page);
2729 rx_pg->page = NULL;
2730}
2731
2732static inline int
Stanislaw Gruszkaa2df00a2010-07-15 22:55:40 +00002733bnx2_alloc_rx_skb(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr, u16 index, gfp_t gfp)
Michael Chanb6016b72005-05-26 13:03:09 -07002734{
2735 struct sk_buff *skb;
Michael Chanbb4f98a2008-06-19 16:38:19 -07002736 struct sw_bd *rx_buf = &rxr->rx_buf_ring[index];
Michael Chanb6016b72005-05-26 13:03:09 -07002737 dma_addr_t mapping;
Michael Chanbb4f98a2008-06-19 16:38:19 -07002738 struct rx_bd *rxbd = &rxr->rx_desc_ring[RX_RING(index)][RX_IDX(index)];
Michael Chanb6016b72005-05-26 13:03:09 -07002739 unsigned long align;
2740
Stanislaw Gruszkaa2df00a2010-07-15 22:55:40 +00002741 skb = __netdev_alloc_skb(bp->dev, bp->rx_buf_size, gfp);
Michael Chanb6016b72005-05-26 13:03:09 -07002742 if (skb == NULL) {
2743 return -ENOMEM;
2744 }
2745
Michael Chan59b47d82006-11-19 14:10:45 -08002746 if (unlikely((align = (unsigned long) skb->data & (BNX2_RX_ALIGN - 1))))
2747 skb_reserve(skb, BNX2_RX_ALIGN - align);
Michael Chanb6016b72005-05-26 13:03:09 -07002748
Stanislaw Gruszka36227e82010-07-15 04:25:50 +00002749 mapping = dma_map_single(&bp->pdev->dev, skb->data, bp->rx_buf_use_size,
2750 PCI_DMA_FROMDEVICE);
2751 if (dma_mapping_error(&bp->pdev->dev, mapping)) {
Benjamin Li3d16af82008-10-09 12:26:41 -07002752 dev_kfree_skb(skb);
2753 return -EIO;
2754 }
Michael Chanb6016b72005-05-26 13:03:09 -07002755
2756 rx_buf->skb = skb;
Michael Chana33fa662010-05-06 08:58:13 +00002757 rx_buf->desc = (struct l2_fhdr *) skb->data;
FUJITA Tomonori1a4ccc22010-04-01 16:56:57 +00002758 dma_unmap_addr_set(rx_buf, mapping, mapping);
Michael Chanb6016b72005-05-26 13:03:09 -07002759
2760 rxbd->rx_bd_haddr_hi = (u64) mapping >> 32;
2761 rxbd->rx_bd_haddr_lo = (u64) mapping & 0xffffffff;
2762
Michael Chanbb4f98a2008-06-19 16:38:19 -07002763 rxr->rx_prod_bseq += bp->rx_buf_use_size;
Michael Chanb6016b72005-05-26 13:03:09 -07002764
2765 return 0;
2766}
2767
Michael Chanda3e4fb2007-05-03 13:24:23 -07002768static int
Michael Chan35efa7c2007-12-20 19:56:37 -08002769bnx2_phy_event_is_set(struct bnx2 *bp, struct bnx2_napi *bnapi, u32 event)
Michael Chanda3e4fb2007-05-03 13:24:23 -07002770{
Michael Chan43e80b82008-06-19 16:41:08 -07002771 struct status_block *sblk = bnapi->status_blk.msi;
Michael Chanda3e4fb2007-05-03 13:24:23 -07002772 u32 new_link_state, old_link_state;
2773 int is_set = 1;
2774
2775 new_link_state = sblk->status_attn_bits & event;
2776 old_link_state = sblk->status_attn_bits_ack & event;
2777 if (new_link_state != old_link_state) {
2778 if (new_link_state)
2779 REG_WR(bp, BNX2_PCICFG_STATUS_BIT_SET_CMD, event);
2780 else
2781 REG_WR(bp, BNX2_PCICFG_STATUS_BIT_CLEAR_CMD, event);
2782 } else
2783 is_set = 0;
2784
2785 return is_set;
2786}
2787
Michael Chanb6016b72005-05-26 13:03:09 -07002788static void
Michael Chan35efa7c2007-12-20 19:56:37 -08002789bnx2_phy_int(struct bnx2 *bp, struct bnx2_napi *bnapi)
Michael Chanb6016b72005-05-26 13:03:09 -07002790{
Michael Chan74ecc622008-05-02 16:56:16 -07002791 spin_lock(&bp->phy_lock);
2792
2793 if (bnx2_phy_event_is_set(bp, bnapi, STATUS_ATTN_BITS_LINK_STATE))
Michael Chanb6016b72005-05-26 13:03:09 -07002794 bnx2_set_link(bp);
Michael Chan35efa7c2007-12-20 19:56:37 -08002795 if (bnx2_phy_event_is_set(bp, bnapi, STATUS_ATTN_BITS_TIMER_ABORT))
Michael Chan0d8a6572007-07-07 22:49:43 -07002796 bnx2_set_remote_link(bp);
2797
Michael Chan74ecc622008-05-02 16:56:16 -07002798 spin_unlock(&bp->phy_lock);
2799
Michael Chanb6016b72005-05-26 13:03:09 -07002800}
2801
Michael Chanead72702007-12-20 19:55:39 -08002802static inline u16
Michael Chan35efa7c2007-12-20 19:56:37 -08002803bnx2_get_hw_tx_cons(struct bnx2_napi *bnapi)
Michael Chanead72702007-12-20 19:55:39 -08002804{
2805 u16 cons;
2806
Michael Chan43e80b82008-06-19 16:41:08 -07002807 /* Tell compiler that status block fields can change. */
2808 barrier();
2809 cons = *bnapi->hw_tx_cons_ptr;
Michael Chan581daf72009-05-06 16:46:47 -07002810 barrier();
Michael Chanead72702007-12-20 19:55:39 -08002811 if (unlikely((cons & MAX_TX_DESC_CNT) == MAX_TX_DESC_CNT))
2812 cons++;
2813 return cons;
2814}
2815
Michael Chan57851d82007-12-20 20:01:44 -08002816static int
2817bnx2_tx_int(struct bnx2 *bp, struct bnx2_napi *bnapi, int budget)
Michael Chanb6016b72005-05-26 13:03:09 -07002818{
Michael Chan35e90102008-06-19 16:37:42 -07002819 struct bnx2_tx_ring_info *txr = &bnapi->tx_ring;
Michael Chanb6016b72005-05-26 13:03:09 -07002820 u16 hw_cons, sw_cons, sw_ring_cons;
Benjamin Li706bf242008-07-18 17:55:11 -07002821 int tx_pkt = 0, index;
2822 struct netdev_queue *txq;
2823
2824 index = (bnapi - bp->bnx2_napi);
2825 txq = netdev_get_tx_queue(bp->dev, index);
Michael Chanb6016b72005-05-26 13:03:09 -07002826
Michael Chan35efa7c2007-12-20 19:56:37 -08002827 hw_cons = bnx2_get_hw_tx_cons(bnapi);
Michael Chan35e90102008-06-19 16:37:42 -07002828 sw_cons = txr->tx_cons;
Michael Chanb6016b72005-05-26 13:03:09 -07002829
2830 while (sw_cons != hw_cons) {
Benjamin Li3d16af82008-10-09 12:26:41 -07002831 struct sw_tx_bd *tx_buf;
Michael Chanb6016b72005-05-26 13:03:09 -07002832 struct sk_buff *skb;
2833 int i, last;
2834
2835 sw_ring_cons = TX_RING_IDX(sw_cons);
2836
Michael Chan35e90102008-06-19 16:37:42 -07002837 tx_buf = &txr->tx_buf_ring[sw_ring_cons];
Michael Chanb6016b72005-05-26 13:03:09 -07002838 skb = tx_buf->skb;
Arjan van de Ven1d39ed52006-12-12 14:06:23 +01002839
Eric Dumazetd62fda02009-05-12 20:48:02 +00002840 /* prefetch skb_end_pointer() to speedup skb_shinfo(skb) */
2841 prefetch(&skb->end);
2842
Michael Chanb6016b72005-05-26 13:03:09 -07002843 /* partial BD completions possible with TSO packets */
Eric Dumazetd62fda02009-05-12 20:48:02 +00002844 if (tx_buf->is_gso) {
Michael Chanb6016b72005-05-26 13:03:09 -07002845 u16 last_idx, last_ring_idx;
2846
Eric Dumazetd62fda02009-05-12 20:48:02 +00002847 last_idx = sw_cons + tx_buf->nr_frags + 1;
2848 last_ring_idx = sw_ring_cons + tx_buf->nr_frags + 1;
Michael Chanb6016b72005-05-26 13:03:09 -07002849 if (unlikely(last_ring_idx >= MAX_TX_DESC_CNT)) {
2850 last_idx++;
2851 }
2852 if (((s16) ((s16) last_idx - (s16) hw_cons)) > 0) {
2853 break;
2854 }
2855 }
Arjan van de Ven1d39ed52006-12-12 14:06:23 +01002856
Stanislaw Gruszka36227e82010-07-15 04:25:50 +00002857 dma_unmap_single(&bp->pdev->dev, dma_unmap_addr(tx_buf, mapping),
Alexander Duycke95524a2009-12-02 16:47:57 +00002858 skb_headlen(skb), PCI_DMA_TODEVICE);
Michael Chanb6016b72005-05-26 13:03:09 -07002859
2860 tx_buf->skb = NULL;
Eric Dumazetd62fda02009-05-12 20:48:02 +00002861 last = tx_buf->nr_frags;
Michael Chanb6016b72005-05-26 13:03:09 -07002862
2863 for (i = 0; i < last; i++) {
2864 sw_cons = NEXT_TX_BD(sw_cons);
Alexander Duycke95524a2009-12-02 16:47:57 +00002865
Stanislaw Gruszka36227e82010-07-15 04:25:50 +00002866 dma_unmap_page(&bp->pdev->dev,
FUJITA Tomonori1a4ccc22010-04-01 16:56:57 +00002867 dma_unmap_addr(
Alexander Duycke95524a2009-12-02 16:47:57 +00002868 &txr->tx_buf_ring[TX_RING_IDX(sw_cons)],
2869 mapping),
2870 skb_shinfo(skb)->frags[i].size,
2871 PCI_DMA_TODEVICE);
Michael Chanb6016b72005-05-26 13:03:09 -07002872 }
2873
2874 sw_cons = NEXT_TX_BD(sw_cons);
2875
Michael Chan745720e2006-06-29 12:37:41 -07002876 dev_kfree_skb(skb);
Michael Chan57851d82007-12-20 20:01:44 -08002877 tx_pkt++;
2878 if (tx_pkt == budget)
2879 break;
Michael Chanb6016b72005-05-26 13:03:09 -07002880
Eric Dumazetd62fda02009-05-12 20:48:02 +00002881 if (hw_cons == sw_cons)
2882 hw_cons = bnx2_get_hw_tx_cons(bnapi);
Michael Chanb6016b72005-05-26 13:03:09 -07002883 }
2884
Michael Chan35e90102008-06-19 16:37:42 -07002885 txr->hw_tx_cons = hw_cons;
2886 txr->tx_cons = sw_cons;
Benjamin Li706bf242008-07-18 17:55:11 -07002887
Michael Chan2f8af122006-08-15 01:39:10 -07002888 /* Need to make the tx_cons update visible to bnx2_start_xmit()
Benjamin Li706bf242008-07-18 17:55:11 -07002889 * before checking for netif_tx_queue_stopped(). Without the
Michael Chan2f8af122006-08-15 01:39:10 -07002890 * memory barrier, there is a small possibility that bnx2_start_xmit()
2891 * will miss it and cause the queue to be stopped forever.
2892 */
2893 smp_mb();
Michael Chanb6016b72005-05-26 13:03:09 -07002894
Benjamin Li706bf242008-07-18 17:55:11 -07002895 if (unlikely(netif_tx_queue_stopped(txq)) &&
Michael Chan35e90102008-06-19 16:37:42 -07002896 (bnx2_tx_avail(bp, txr) > bp->tx_wake_thresh)) {
Benjamin Li706bf242008-07-18 17:55:11 -07002897 __netif_tx_lock(txq, smp_processor_id());
2898 if ((netif_tx_queue_stopped(txq)) &&
Michael Chan35e90102008-06-19 16:37:42 -07002899 (bnx2_tx_avail(bp, txr) > bp->tx_wake_thresh))
Benjamin Li706bf242008-07-18 17:55:11 -07002900 netif_tx_wake_queue(txq);
2901 __netif_tx_unlock(txq);
Michael Chanb6016b72005-05-26 13:03:09 -07002902 }
Benjamin Li706bf242008-07-18 17:55:11 -07002903
Michael Chan57851d82007-12-20 20:01:44 -08002904 return tx_pkt;
Michael Chanb6016b72005-05-26 13:03:09 -07002905}
2906
Michael Chan1db82f22007-12-12 11:19:35 -08002907static void
Michael Chanbb4f98a2008-06-19 16:38:19 -07002908bnx2_reuse_rx_skb_pages(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr,
Michael Chana1f60192007-12-20 19:57:19 -08002909 struct sk_buff *skb, int count)
Michael Chan1db82f22007-12-12 11:19:35 -08002910{
2911 struct sw_pg *cons_rx_pg, *prod_rx_pg;
2912 struct rx_bd *cons_bd, *prod_bd;
Michael Chan1db82f22007-12-12 11:19:35 -08002913 int i;
Benjamin Li3d16af82008-10-09 12:26:41 -07002914 u16 hw_prod, prod;
Michael Chanbb4f98a2008-06-19 16:38:19 -07002915 u16 cons = rxr->rx_pg_cons;
Michael Chan1db82f22007-12-12 11:19:35 -08002916
Benjamin Li3d16af82008-10-09 12:26:41 -07002917 cons_rx_pg = &rxr->rx_pg_ring[cons];
2918
2919 /* The caller was unable to allocate a new page to replace the
2920 * last one in the frags array, so we need to recycle that page
2921 * and then free the skb.
2922 */
2923 if (skb) {
2924 struct page *page;
2925 struct skb_shared_info *shinfo;
2926
2927 shinfo = skb_shinfo(skb);
2928 shinfo->nr_frags--;
2929 page = shinfo->frags[shinfo->nr_frags].page;
2930 shinfo->frags[shinfo->nr_frags].page = NULL;
2931
2932 cons_rx_pg->page = page;
2933 dev_kfree_skb(skb);
2934 }
2935
2936 hw_prod = rxr->rx_pg_prod;
2937
Michael Chan1db82f22007-12-12 11:19:35 -08002938 for (i = 0; i < count; i++) {
2939 prod = RX_PG_RING_IDX(hw_prod);
2940
Michael Chanbb4f98a2008-06-19 16:38:19 -07002941 prod_rx_pg = &rxr->rx_pg_ring[prod];
2942 cons_rx_pg = &rxr->rx_pg_ring[cons];
2943 cons_bd = &rxr->rx_pg_desc_ring[RX_RING(cons)][RX_IDX(cons)];
2944 prod_bd = &rxr->rx_pg_desc_ring[RX_RING(prod)][RX_IDX(prod)];
Michael Chan1db82f22007-12-12 11:19:35 -08002945
Michael Chan1db82f22007-12-12 11:19:35 -08002946 if (prod != cons) {
2947 prod_rx_pg->page = cons_rx_pg->page;
2948 cons_rx_pg->page = NULL;
FUJITA Tomonori1a4ccc22010-04-01 16:56:57 +00002949 dma_unmap_addr_set(prod_rx_pg, mapping,
2950 dma_unmap_addr(cons_rx_pg, mapping));
Michael Chan1db82f22007-12-12 11:19:35 -08002951
2952 prod_bd->rx_bd_haddr_hi = cons_bd->rx_bd_haddr_hi;
2953 prod_bd->rx_bd_haddr_lo = cons_bd->rx_bd_haddr_lo;
2954
2955 }
2956 cons = RX_PG_RING_IDX(NEXT_RX_BD(cons));
2957 hw_prod = NEXT_RX_BD(hw_prod);
2958 }
Michael Chanbb4f98a2008-06-19 16:38:19 -07002959 rxr->rx_pg_prod = hw_prod;
2960 rxr->rx_pg_cons = cons;
Michael Chan1db82f22007-12-12 11:19:35 -08002961}
2962
Michael Chanb6016b72005-05-26 13:03:09 -07002963static inline void
Michael Chanbb4f98a2008-06-19 16:38:19 -07002964bnx2_reuse_rx_skb(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr,
2965 struct sk_buff *skb, u16 cons, u16 prod)
Michael Chanb6016b72005-05-26 13:03:09 -07002966{
Michael Chan236b6392006-03-20 17:49:02 -08002967 struct sw_bd *cons_rx_buf, *prod_rx_buf;
2968 struct rx_bd *cons_bd, *prod_bd;
2969
Michael Chanbb4f98a2008-06-19 16:38:19 -07002970 cons_rx_buf = &rxr->rx_buf_ring[cons];
2971 prod_rx_buf = &rxr->rx_buf_ring[prod];
Michael Chanb6016b72005-05-26 13:03:09 -07002972
Stanislaw Gruszka36227e82010-07-15 04:25:50 +00002973 dma_sync_single_for_device(&bp->pdev->dev,
FUJITA Tomonori1a4ccc22010-04-01 16:56:57 +00002974 dma_unmap_addr(cons_rx_buf, mapping),
Benjamin Li601d3d12008-05-16 22:19:35 -07002975 BNX2_RX_OFFSET + BNX2_RX_COPY_THRESH, PCI_DMA_FROMDEVICE);
Michael Chanb6016b72005-05-26 13:03:09 -07002976
Michael Chanbb4f98a2008-06-19 16:38:19 -07002977 rxr->rx_prod_bseq += bp->rx_buf_use_size;
Michael Chan236b6392006-03-20 17:49:02 -08002978
2979 prod_rx_buf->skb = skb;
Michael Chana33fa662010-05-06 08:58:13 +00002980 prod_rx_buf->desc = (struct l2_fhdr *) skb->data;
Michael Chan236b6392006-03-20 17:49:02 -08002981
2982 if (cons == prod)
2983 return;
2984
FUJITA Tomonori1a4ccc22010-04-01 16:56:57 +00002985 dma_unmap_addr_set(prod_rx_buf, mapping,
2986 dma_unmap_addr(cons_rx_buf, mapping));
Michael Chanb6016b72005-05-26 13:03:09 -07002987
Michael Chanbb4f98a2008-06-19 16:38:19 -07002988 cons_bd = &rxr->rx_desc_ring[RX_RING(cons)][RX_IDX(cons)];
2989 prod_bd = &rxr->rx_desc_ring[RX_RING(prod)][RX_IDX(prod)];
Michael Chan236b6392006-03-20 17:49:02 -08002990 prod_bd->rx_bd_haddr_hi = cons_bd->rx_bd_haddr_hi;
2991 prod_bd->rx_bd_haddr_lo = cons_bd->rx_bd_haddr_lo;
Michael Chanb6016b72005-05-26 13:03:09 -07002992}
2993
Michael Chan85833c62007-12-12 11:17:01 -08002994static int
Michael Chanbb4f98a2008-06-19 16:38:19 -07002995bnx2_rx_skb(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr, struct sk_buff *skb,
Michael Chana1f60192007-12-20 19:57:19 -08002996 unsigned int len, unsigned int hdr_len, dma_addr_t dma_addr,
2997 u32 ring_idx)
Michael Chan85833c62007-12-12 11:17:01 -08002998{
2999 int err;
3000 u16 prod = ring_idx & 0xffff;
3001
Stanislaw Gruszkaa2df00a2010-07-15 22:55:40 +00003002 err = bnx2_alloc_rx_skb(bp, rxr, prod, GFP_ATOMIC);
Michael Chan85833c62007-12-12 11:17:01 -08003003 if (unlikely(err)) {
Michael Chanbb4f98a2008-06-19 16:38:19 -07003004 bnx2_reuse_rx_skb(bp, rxr, skb, (u16) (ring_idx >> 16), prod);
Michael Chan1db82f22007-12-12 11:19:35 -08003005 if (hdr_len) {
3006 unsigned int raw_len = len + 4;
3007 int pages = PAGE_ALIGN(raw_len - hdr_len) >> PAGE_SHIFT;
3008
Michael Chanbb4f98a2008-06-19 16:38:19 -07003009 bnx2_reuse_rx_skb_pages(bp, rxr, NULL, pages);
Michael Chan1db82f22007-12-12 11:19:35 -08003010 }
Michael Chan85833c62007-12-12 11:17:01 -08003011 return err;
3012 }
3013
Benjamin Lid89cb6a2008-05-16 22:18:57 -07003014 skb_reserve(skb, BNX2_RX_OFFSET);
Stanislaw Gruszka36227e82010-07-15 04:25:50 +00003015 dma_unmap_single(&bp->pdev->dev, dma_addr, bp->rx_buf_use_size,
Michael Chan85833c62007-12-12 11:17:01 -08003016 PCI_DMA_FROMDEVICE);
3017
Michael Chan1db82f22007-12-12 11:19:35 -08003018 if (hdr_len == 0) {
3019 skb_put(skb, len);
3020 return 0;
3021 } else {
3022 unsigned int i, frag_len, frag_size, pages;
3023 struct sw_pg *rx_pg;
Michael Chanbb4f98a2008-06-19 16:38:19 -07003024 u16 pg_cons = rxr->rx_pg_cons;
3025 u16 pg_prod = rxr->rx_pg_prod;
Michael Chan1db82f22007-12-12 11:19:35 -08003026
3027 frag_size = len + 4 - hdr_len;
3028 pages = PAGE_ALIGN(frag_size) >> PAGE_SHIFT;
3029 skb_put(skb, hdr_len);
3030
3031 for (i = 0; i < pages; i++) {
Benjamin Li3d16af82008-10-09 12:26:41 -07003032 dma_addr_t mapping_old;
3033
Michael Chan1db82f22007-12-12 11:19:35 -08003034 frag_len = min(frag_size, (unsigned int) PAGE_SIZE);
3035 if (unlikely(frag_len <= 4)) {
3036 unsigned int tail = 4 - frag_len;
3037
Michael Chanbb4f98a2008-06-19 16:38:19 -07003038 rxr->rx_pg_cons = pg_cons;
3039 rxr->rx_pg_prod = pg_prod;
3040 bnx2_reuse_rx_skb_pages(bp, rxr, NULL,
Michael Chana1f60192007-12-20 19:57:19 -08003041 pages - i);
Michael Chan1db82f22007-12-12 11:19:35 -08003042 skb->len -= tail;
3043 if (i == 0) {
3044 skb->tail -= tail;
3045 } else {
3046 skb_frag_t *frag =
3047 &skb_shinfo(skb)->frags[i - 1];
3048 frag->size -= tail;
3049 skb->data_len -= tail;
3050 skb->truesize -= tail;
3051 }
3052 return 0;
3053 }
Michael Chanbb4f98a2008-06-19 16:38:19 -07003054 rx_pg = &rxr->rx_pg_ring[pg_cons];
Michael Chan1db82f22007-12-12 11:19:35 -08003055
Benjamin Li3d16af82008-10-09 12:26:41 -07003056 /* Don't unmap yet. If we're unable to allocate a new
3057 * page, we need to recycle the page and the DMA addr.
3058 */
FUJITA Tomonori1a4ccc22010-04-01 16:56:57 +00003059 mapping_old = dma_unmap_addr(rx_pg, mapping);
Michael Chan1db82f22007-12-12 11:19:35 -08003060 if (i == pages - 1)
3061 frag_len -= 4;
3062
3063 skb_fill_page_desc(skb, i, rx_pg->page, 0, frag_len);
3064 rx_pg->page = NULL;
3065
Michael Chanbb4f98a2008-06-19 16:38:19 -07003066 err = bnx2_alloc_rx_page(bp, rxr,
Stanislaw Gruszkaa2df00a2010-07-15 22:55:40 +00003067 RX_PG_RING_IDX(pg_prod),
3068 GFP_ATOMIC);
Michael Chan1db82f22007-12-12 11:19:35 -08003069 if (unlikely(err)) {
Michael Chanbb4f98a2008-06-19 16:38:19 -07003070 rxr->rx_pg_cons = pg_cons;
3071 rxr->rx_pg_prod = pg_prod;
3072 bnx2_reuse_rx_skb_pages(bp, rxr, skb,
Michael Chana1f60192007-12-20 19:57:19 -08003073 pages - i);
Michael Chan1db82f22007-12-12 11:19:35 -08003074 return err;
3075 }
3076
Stanislaw Gruszka36227e82010-07-15 04:25:50 +00003077 dma_unmap_page(&bp->pdev->dev, mapping_old,
Benjamin Li3d16af82008-10-09 12:26:41 -07003078 PAGE_SIZE, PCI_DMA_FROMDEVICE);
3079
Michael Chan1db82f22007-12-12 11:19:35 -08003080 frag_size -= frag_len;
3081 skb->data_len += frag_len;
3082 skb->truesize += frag_len;
3083 skb->len += frag_len;
3084
3085 pg_prod = NEXT_RX_BD(pg_prod);
3086 pg_cons = RX_PG_RING_IDX(NEXT_RX_BD(pg_cons));
3087 }
Michael Chanbb4f98a2008-06-19 16:38:19 -07003088 rxr->rx_pg_prod = pg_prod;
3089 rxr->rx_pg_cons = pg_cons;
Michael Chan1db82f22007-12-12 11:19:35 -08003090 }
Michael Chan85833c62007-12-12 11:17:01 -08003091 return 0;
3092}
3093
Michael Chanc09c2622007-12-10 17:18:37 -08003094static inline u16
Michael Chan35efa7c2007-12-20 19:56:37 -08003095bnx2_get_hw_rx_cons(struct bnx2_napi *bnapi)
Michael Chanc09c2622007-12-10 17:18:37 -08003096{
Michael Chanbb4f98a2008-06-19 16:38:19 -07003097 u16 cons;
3098
Michael Chan43e80b82008-06-19 16:41:08 -07003099 /* Tell compiler that status block fields can change. */
3100 barrier();
3101 cons = *bnapi->hw_rx_cons_ptr;
Michael Chan581daf72009-05-06 16:46:47 -07003102 barrier();
Michael Chanc09c2622007-12-10 17:18:37 -08003103 if (unlikely((cons & MAX_RX_DESC_CNT) == MAX_RX_DESC_CNT))
3104 cons++;
3105 return cons;
3106}
3107
Michael Chanb6016b72005-05-26 13:03:09 -07003108static int
Michael Chan35efa7c2007-12-20 19:56:37 -08003109bnx2_rx_int(struct bnx2 *bp, struct bnx2_napi *bnapi, int budget)
Michael Chanb6016b72005-05-26 13:03:09 -07003110{
Michael Chanbb4f98a2008-06-19 16:38:19 -07003111 struct bnx2_rx_ring_info *rxr = &bnapi->rx_ring;
Michael Chanb6016b72005-05-26 13:03:09 -07003112 u16 hw_cons, sw_cons, sw_ring_cons, sw_prod, sw_ring_prod;
3113 struct l2_fhdr *rx_hdr;
Michael Chan1db82f22007-12-12 11:19:35 -08003114 int rx_pkt = 0, pg_ring_used = 0;
Michael Chanb6016b72005-05-26 13:03:09 -07003115
Michael Chan35efa7c2007-12-20 19:56:37 -08003116 hw_cons = bnx2_get_hw_rx_cons(bnapi);
Michael Chanbb4f98a2008-06-19 16:38:19 -07003117 sw_cons = rxr->rx_cons;
3118 sw_prod = rxr->rx_prod;
Michael Chanb6016b72005-05-26 13:03:09 -07003119
3120 /* Memory barrier necessary as speculative reads of the rx
3121 * buffer can be ahead of the index in the status block
3122 */
3123 rmb();
3124 while (sw_cons != hw_cons) {
Michael Chan1db82f22007-12-12 11:19:35 -08003125 unsigned int len, hdr_len;
Michael Chanade2bfe2006-01-23 16:09:51 -08003126 u32 status;
Michael Chana33fa662010-05-06 08:58:13 +00003127 struct sw_bd *rx_buf, *next_rx_buf;
Michael Chanb6016b72005-05-26 13:03:09 -07003128 struct sk_buff *skb;
Michael Chan236b6392006-03-20 17:49:02 -08003129 dma_addr_t dma_addr;
Michael Chanb6016b72005-05-26 13:03:09 -07003130
3131 sw_ring_cons = RX_RING_IDX(sw_cons);
3132 sw_ring_prod = RX_RING_IDX(sw_prod);
3133
Michael Chanbb4f98a2008-06-19 16:38:19 -07003134 rx_buf = &rxr->rx_buf_ring[sw_ring_cons];
Michael Chanb6016b72005-05-26 13:03:09 -07003135 skb = rx_buf->skb;
Michael Chana33fa662010-05-06 08:58:13 +00003136 prefetchw(skb);
Michael Chan236b6392006-03-20 17:49:02 -08003137
FUJITA Tomonoriaabef8b2010-06-17 08:56:05 -07003138 next_rx_buf =
3139 &rxr->rx_buf_ring[RX_RING_IDX(NEXT_RX_BD(sw_cons))];
3140 prefetch(next_rx_buf->desc);
3141
Michael Chan236b6392006-03-20 17:49:02 -08003142 rx_buf->skb = NULL;
3143
FUJITA Tomonori1a4ccc22010-04-01 16:56:57 +00003144 dma_addr = dma_unmap_addr(rx_buf, mapping);
Michael Chan236b6392006-03-20 17:49:02 -08003145
Stanislaw Gruszka36227e82010-07-15 04:25:50 +00003146 dma_sync_single_for_cpu(&bp->pdev->dev, dma_addr,
Benjamin Li601d3d12008-05-16 22:19:35 -07003147 BNX2_RX_OFFSET + BNX2_RX_COPY_THRESH,
3148 PCI_DMA_FROMDEVICE);
Michael Chanb6016b72005-05-26 13:03:09 -07003149
Michael Chana33fa662010-05-06 08:58:13 +00003150 rx_hdr = rx_buf->desc;
Michael Chan1db82f22007-12-12 11:19:35 -08003151 len = rx_hdr->l2_fhdr_pkt_len;
Michael Chan990ec382009-02-12 16:54:13 -08003152 status = rx_hdr->l2_fhdr_status;
Michael Chanb6016b72005-05-26 13:03:09 -07003153
Michael Chan1db82f22007-12-12 11:19:35 -08003154 hdr_len = 0;
3155 if (status & L2_FHDR_STATUS_SPLIT) {
3156 hdr_len = rx_hdr->l2_fhdr_ip_xsum;
3157 pg_ring_used = 1;
3158 } else if (len > bp->rx_jumbo_thresh) {
3159 hdr_len = bp->rx_jumbo_thresh;
3160 pg_ring_used = 1;
3161 }
3162
Michael Chan990ec382009-02-12 16:54:13 -08003163 if (unlikely(status & (L2_FHDR_ERRORS_BAD_CRC |
3164 L2_FHDR_ERRORS_PHY_DECODE |
3165 L2_FHDR_ERRORS_ALIGNMENT |
3166 L2_FHDR_ERRORS_TOO_SHORT |
3167 L2_FHDR_ERRORS_GIANT_FRAME))) {
3168
3169 bnx2_reuse_rx_skb(bp, rxr, skb, sw_ring_cons,
3170 sw_ring_prod);
3171 if (pg_ring_used) {
3172 int pages;
3173
3174 pages = PAGE_ALIGN(len - hdr_len) >> PAGE_SHIFT;
3175
3176 bnx2_reuse_rx_skb_pages(bp, rxr, NULL, pages);
3177 }
3178 goto next_rx;
3179 }
3180
Michael Chan1db82f22007-12-12 11:19:35 -08003181 len -= 4;
Michael Chanb6016b72005-05-26 13:03:09 -07003182
Michael Chan5d5d0012007-12-12 11:17:43 -08003183 if (len <= bp->rx_copy_thresh) {
Michael Chanb6016b72005-05-26 13:03:09 -07003184 struct sk_buff *new_skb;
3185
Michael Chanf22828e2008-08-14 15:30:14 -07003186 new_skb = netdev_alloc_skb(bp->dev, len + 6);
Michael Chan85833c62007-12-12 11:17:01 -08003187 if (new_skb == NULL) {
Michael Chanbb4f98a2008-06-19 16:38:19 -07003188 bnx2_reuse_rx_skb(bp, rxr, skb, sw_ring_cons,
Michael Chan85833c62007-12-12 11:17:01 -08003189 sw_ring_prod);
3190 goto next_rx;
3191 }
Michael Chanb6016b72005-05-26 13:03:09 -07003192
3193 /* aligned copy */
Benjamin Lid89cb6a2008-05-16 22:18:57 -07003194 skb_copy_from_linear_data_offset(skb,
Michael Chanf22828e2008-08-14 15:30:14 -07003195 BNX2_RX_OFFSET - 6,
3196 new_skb->data, len + 6);
3197 skb_reserve(new_skb, 6);
Michael Chanb6016b72005-05-26 13:03:09 -07003198 skb_put(new_skb, len);
Michael Chanb6016b72005-05-26 13:03:09 -07003199
Michael Chanbb4f98a2008-06-19 16:38:19 -07003200 bnx2_reuse_rx_skb(bp, rxr, skb,
Michael Chanb6016b72005-05-26 13:03:09 -07003201 sw_ring_cons, sw_ring_prod);
3202
3203 skb = new_skb;
Michael Chanbb4f98a2008-06-19 16:38:19 -07003204 } else if (unlikely(bnx2_rx_skb(bp, rxr, skb, len, hdr_len,
Michael Chana1f60192007-12-20 19:57:19 -08003205 dma_addr, (sw_ring_cons << 16) | sw_ring_prod)))
Michael Chanb6016b72005-05-26 13:03:09 -07003206 goto next_rx;
Michael Chanb6016b72005-05-26 13:03:09 -07003207
Michael Chanf22828e2008-08-14 15:30:14 -07003208 if ((status & L2_FHDR_STATUS_L2_VLAN_TAG) &&
Jesse Gross7d0fd212010-10-20 13:56:09 +00003209 !(bp->rx_mode & BNX2_EMAC_RX_MODE_KEEP_VLAN_TAG))
3210 __vlan_hwaccel_put_tag(skb, rx_hdr->l2_fhdr_vlan_tag);
Michael Chanf22828e2008-08-14 15:30:14 -07003211
Michael Chanb6016b72005-05-26 13:03:09 -07003212 skb->protocol = eth_type_trans(skb, bp->dev);
3213
3214 if ((len > (bp->dev->mtu + ETH_HLEN)) &&
Alexey Dobriyand1e100b2006-06-11 20:57:17 -07003215 (ntohs(skb->protocol) != 0x8100)) {
Michael Chanb6016b72005-05-26 13:03:09 -07003216
Michael Chan745720e2006-06-29 12:37:41 -07003217 dev_kfree_skb(skb);
Michael Chanb6016b72005-05-26 13:03:09 -07003218 goto next_rx;
3219
3220 }
3221
Eric Dumazetbc8acf22010-09-02 13:07:41 -07003222 skb_checksum_none_assert(skb);
Michał Mirosław8d7dfc22011-04-10 04:47:46 +00003223 if ((bp->dev->features & NETIF_F_RXCSUM) &&
Michael Chanb6016b72005-05-26 13:03:09 -07003224 (status & (L2_FHDR_STATUS_TCP_SEGMENT |
3225 L2_FHDR_STATUS_UDP_DATAGRAM))) {
3226
Michael Chanade2bfe2006-01-23 16:09:51 -08003227 if (likely((status & (L2_FHDR_ERRORS_TCP_XSUM |
3228 L2_FHDR_ERRORS_UDP_XSUM)) == 0))
Michael Chanb6016b72005-05-26 13:03:09 -07003229 skb->ip_summed = CHECKSUM_UNNECESSARY;
3230 }
Michael Chanfdc85412010-07-03 20:42:16 +00003231 if ((bp->dev->features & NETIF_F_RXHASH) &&
3232 ((status & L2_FHDR_STATUS_USE_RXHASH) ==
3233 L2_FHDR_STATUS_USE_RXHASH))
3234 skb->rxhash = rx_hdr->l2_fhdr_hash;
Michael Chanb6016b72005-05-26 13:03:09 -07003235
David S. Miller0c8dfc82009-01-27 16:22:32 -08003236 skb_record_rx_queue(skb, bnapi - &bp->bnx2_napi[0]);
Jesse Gross7d0fd212010-10-20 13:56:09 +00003237 napi_gro_receive(&bnapi->napi, skb);
Michael Chanb6016b72005-05-26 13:03:09 -07003238 rx_pkt++;
3239
3240next_rx:
Michael Chanb6016b72005-05-26 13:03:09 -07003241 sw_cons = NEXT_RX_BD(sw_cons);
3242 sw_prod = NEXT_RX_BD(sw_prod);
3243
3244 if ((rx_pkt == budget))
3245 break;
Michael Chanf4e418f2005-11-04 08:53:48 -08003246
3247 /* Refresh hw_cons to see if there is new work */
3248 if (sw_cons == hw_cons) {
Michael Chan35efa7c2007-12-20 19:56:37 -08003249 hw_cons = bnx2_get_hw_rx_cons(bnapi);
Michael Chanf4e418f2005-11-04 08:53:48 -08003250 rmb();
3251 }
Michael Chanb6016b72005-05-26 13:03:09 -07003252 }
Michael Chanbb4f98a2008-06-19 16:38:19 -07003253 rxr->rx_cons = sw_cons;
3254 rxr->rx_prod = sw_prod;
Michael Chanb6016b72005-05-26 13:03:09 -07003255
Michael Chan1db82f22007-12-12 11:19:35 -08003256 if (pg_ring_used)
Michael Chanbb4f98a2008-06-19 16:38:19 -07003257 REG_WR16(bp, rxr->rx_pg_bidx_addr, rxr->rx_pg_prod);
Michael Chan1db82f22007-12-12 11:19:35 -08003258
Michael Chanbb4f98a2008-06-19 16:38:19 -07003259 REG_WR16(bp, rxr->rx_bidx_addr, sw_prod);
Michael Chanb6016b72005-05-26 13:03:09 -07003260
Michael Chanbb4f98a2008-06-19 16:38:19 -07003261 REG_WR(bp, rxr->rx_bseq_addr, rxr->rx_prod_bseq);
Michael Chanb6016b72005-05-26 13:03:09 -07003262
3263 mmiowb();
3264
3265 return rx_pkt;
3266
3267}
3268
3269/* MSI ISR - The only difference between this and the INTx ISR
3270 * is that the MSI interrupt is always serviced.
3271 */
3272static irqreturn_t
David Howells7d12e782006-10-05 14:55:46 +01003273bnx2_msi(int irq, void *dev_instance)
Michael Chanb6016b72005-05-26 13:03:09 -07003274{
Michael Chanf0ea2e62008-06-19 16:41:57 -07003275 struct bnx2_napi *bnapi = dev_instance;
3276 struct bnx2 *bp = bnapi->bp;
Michael Chanb6016b72005-05-26 13:03:09 -07003277
Michael Chan43e80b82008-06-19 16:41:08 -07003278 prefetch(bnapi->status_blk.msi);
Michael Chanb6016b72005-05-26 13:03:09 -07003279 REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
3280 BNX2_PCICFG_INT_ACK_CMD_USE_INT_HC_PARAM |
3281 BNX2_PCICFG_INT_ACK_CMD_MASK_INT);
3282
3283 /* Return here if interrupt is disabled. */
Michael Chan73eef4c2005-08-25 15:39:15 -07003284 if (unlikely(atomic_read(&bp->intr_sem) != 0))
3285 return IRQ_HANDLED;
Michael Chanb6016b72005-05-26 13:03:09 -07003286
Ben Hutchings288379f2009-01-19 16:43:59 -08003287 napi_schedule(&bnapi->napi);
Michael Chanb6016b72005-05-26 13:03:09 -07003288
Michael Chan73eef4c2005-08-25 15:39:15 -07003289 return IRQ_HANDLED;
Michael Chanb6016b72005-05-26 13:03:09 -07003290}
3291
3292static irqreturn_t
Michael Chan8e6a72c2007-05-03 13:24:48 -07003293bnx2_msi_1shot(int irq, void *dev_instance)
3294{
Michael Chanf0ea2e62008-06-19 16:41:57 -07003295 struct bnx2_napi *bnapi = dev_instance;
3296 struct bnx2 *bp = bnapi->bp;
Michael Chan8e6a72c2007-05-03 13:24:48 -07003297
Michael Chan43e80b82008-06-19 16:41:08 -07003298 prefetch(bnapi->status_blk.msi);
Michael Chan8e6a72c2007-05-03 13:24:48 -07003299
3300 /* Return here if interrupt is disabled. */
3301 if (unlikely(atomic_read(&bp->intr_sem) != 0))
3302 return IRQ_HANDLED;
3303
Ben Hutchings288379f2009-01-19 16:43:59 -08003304 napi_schedule(&bnapi->napi);
Michael Chan8e6a72c2007-05-03 13:24:48 -07003305
3306 return IRQ_HANDLED;
3307}
3308
3309static irqreturn_t
David Howells7d12e782006-10-05 14:55:46 +01003310bnx2_interrupt(int irq, void *dev_instance)
Michael Chanb6016b72005-05-26 13:03:09 -07003311{
Michael Chanf0ea2e62008-06-19 16:41:57 -07003312 struct bnx2_napi *bnapi = dev_instance;
3313 struct bnx2 *bp = bnapi->bp;
Michael Chan43e80b82008-06-19 16:41:08 -07003314 struct status_block *sblk = bnapi->status_blk.msi;
Michael Chanb6016b72005-05-26 13:03:09 -07003315
3316 /* When using INTx, it is possible for the interrupt to arrive
3317 * at the CPU before the status block posted prior to the
3318 * interrupt. Reading a register will flush the status block.
3319 * When using MSI, the MSI message will always complete after
3320 * the status block write.
3321 */
Michael Chan35efa7c2007-12-20 19:56:37 -08003322 if ((sblk->status_idx == bnapi->last_status_idx) &&
Michael Chanb6016b72005-05-26 13:03:09 -07003323 (REG_RD(bp, BNX2_PCICFG_MISC_STATUS) &
3324 BNX2_PCICFG_MISC_STATUS_INTA_VALUE))
Michael Chan73eef4c2005-08-25 15:39:15 -07003325 return IRQ_NONE;
Michael Chanb6016b72005-05-26 13:03:09 -07003326
3327 REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
3328 BNX2_PCICFG_INT_ACK_CMD_USE_INT_HC_PARAM |
3329 BNX2_PCICFG_INT_ACK_CMD_MASK_INT);
3330
Michael Chanb8a7ce72007-07-07 22:51:03 -07003331 /* Read back to deassert IRQ immediately to avoid too many
3332 * spurious interrupts.
3333 */
3334 REG_RD(bp, BNX2_PCICFG_INT_ACK_CMD);
3335
Michael Chanb6016b72005-05-26 13:03:09 -07003336 /* Return here if interrupt is shared and is disabled. */
Michael Chan73eef4c2005-08-25 15:39:15 -07003337 if (unlikely(atomic_read(&bp->intr_sem) != 0))
3338 return IRQ_HANDLED;
Michael Chanb6016b72005-05-26 13:03:09 -07003339
Ben Hutchings288379f2009-01-19 16:43:59 -08003340 if (napi_schedule_prep(&bnapi->napi)) {
Michael Chan35efa7c2007-12-20 19:56:37 -08003341 bnapi->last_status_idx = sblk->status_idx;
Ben Hutchings288379f2009-01-19 16:43:59 -08003342 __napi_schedule(&bnapi->napi);
Michael Chanb8a7ce72007-07-07 22:51:03 -07003343 }
Michael Chanb6016b72005-05-26 13:03:09 -07003344
Michael Chan73eef4c2005-08-25 15:39:15 -07003345 return IRQ_HANDLED;
Michael Chanb6016b72005-05-26 13:03:09 -07003346}
3347
Michael Chan43e80b82008-06-19 16:41:08 -07003348static inline int
3349bnx2_has_fast_work(struct bnx2_napi *bnapi)
3350{
3351 struct bnx2_tx_ring_info *txr = &bnapi->tx_ring;
3352 struct bnx2_rx_ring_info *rxr = &bnapi->rx_ring;
3353
3354 if ((bnx2_get_hw_rx_cons(bnapi) != rxr->rx_cons) ||
3355 (bnx2_get_hw_tx_cons(bnapi) != txr->hw_tx_cons))
3356 return 1;
3357 return 0;
3358}
3359
Michael Chan0d8a6572007-07-07 22:49:43 -07003360#define STATUS_ATTN_EVENTS (STATUS_ATTN_BITS_LINK_STATE | \
3361 STATUS_ATTN_BITS_TIMER_ABORT)
Michael Chanda3e4fb2007-05-03 13:24:23 -07003362
Michael Chanf4e418f2005-11-04 08:53:48 -08003363static inline int
Michael Chan35efa7c2007-12-20 19:56:37 -08003364bnx2_has_work(struct bnx2_napi *bnapi)
Michael Chanf4e418f2005-11-04 08:53:48 -08003365{
Michael Chan43e80b82008-06-19 16:41:08 -07003366 struct status_block *sblk = bnapi->status_blk.msi;
Michael Chanf4e418f2005-11-04 08:53:48 -08003367
Michael Chan43e80b82008-06-19 16:41:08 -07003368 if (bnx2_has_fast_work(bnapi))
Michael Chanf4e418f2005-11-04 08:53:48 -08003369 return 1;
3370
Michael Chan4edd4732009-06-08 18:14:42 -07003371#ifdef BCM_CNIC
3372 if (bnapi->cnic_present && (bnapi->cnic_tag != sblk->status_idx))
3373 return 1;
3374#endif
3375
Michael Chanda3e4fb2007-05-03 13:24:23 -07003376 if ((sblk->status_attn_bits & STATUS_ATTN_EVENTS) !=
3377 (sblk->status_attn_bits_ack & STATUS_ATTN_EVENTS))
Michael Chanf4e418f2005-11-04 08:53:48 -08003378 return 1;
3379
3380 return 0;
3381}
3382
Michael Chanefba0182008-12-03 00:36:15 -08003383static void
3384bnx2_chk_missed_msi(struct bnx2 *bp)
3385{
3386 struct bnx2_napi *bnapi = &bp->bnx2_napi[0];
3387 u32 msi_ctrl;
3388
3389 if (bnx2_has_work(bnapi)) {
3390 msi_ctrl = REG_RD(bp, BNX2_PCICFG_MSI_CONTROL);
3391 if (!(msi_ctrl & BNX2_PCICFG_MSI_CONTROL_ENABLE))
3392 return;
3393
3394 if (bnapi->last_status_idx == bp->idle_chk_status_idx) {
3395 REG_WR(bp, BNX2_PCICFG_MSI_CONTROL, msi_ctrl &
3396 ~BNX2_PCICFG_MSI_CONTROL_ENABLE);
3397 REG_WR(bp, BNX2_PCICFG_MSI_CONTROL, msi_ctrl);
3398 bnx2_msi(bp->irq_tbl[0].vector, bnapi);
3399 }
3400 }
3401
3402 bp->idle_chk_status_idx = bnapi->last_status_idx;
3403}
3404
Michael Chan4edd4732009-06-08 18:14:42 -07003405#ifdef BCM_CNIC
3406static void bnx2_poll_cnic(struct bnx2 *bp, struct bnx2_napi *bnapi)
3407{
3408 struct cnic_ops *c_ops;
3409
3410 if (!bnapi->cnic_present)
3411 return;
3412
3413 rcu_read_lock();
3414 c_ops = rcu_dereference(bp->cnic_ops);
3415 if (c_ops)
3416 bnapi->cnic_tag = c_ops->cnic_handler(bp->cnic_data,
3417 bnapi->status_blk.msi);
3418 rcu_read_unlock();
3419}
3420#endif
3421
Michael Chan43e80b82008-06-19 16:41:08 -07003422static void bnx2_poll_link(struct bnx2 *bp, struct bnx2_napi *bnapi)
Michael Chanb6016b72005-05-26 13:03:09 -07003423{
Michael Chan43e80b82008-06-19 16:41:08 -07003424 struct status_block *sblk = bnapi->status_blk.msi;
Michael Chanda3e4fb2007-05-03 13:24:23 -07003425 u32 status_attn_bits = sblk->status_attn_bits;
3426 u32 status_attn_bits_ack = sblk->status_attn_bits_ack;
Michael Chanb6016b72005-05-26 13:03:09 -07003427
Michael Chanda3e4fb2007-05-03 13:24:23 -07003428 if ((status_attn_bits & STATUS_ATTN_EVENTS) !=
3429 (status_attn_bits_ack & STATUS_ATTN_EVENTS)) {
Michael Chanb6016b72005-05-26 13:03:09 -07003430
Michael Chan35efa7c2007-12-20 19:56:37 -08003431 bnx2_phy_int(bp, bnapi);
Michael Chanbf5295b2006-03-23 01:11:56 -08003432
3433 /* This is needed to take care of transient status
3434 * during link changes.
3435 */
3436 REG_WR(bp, BNX2_HC_COMMAND,
3437 bp->hc_cmd | BNX2_HC_COMMAND_COAL_NOW_WO_INT);
3438 REG_RD(bp, BNX2_HC_COMMAND);
Michael Chanb6016b72005-05-26 13:03:09 -07003439 }
Michael Chan43e80b82008-06-19 16:41:08 -07003440}
3441
3442static int bnx2_poll_work(struct bnx2 *bp, struct bnx2_napi *bnapi,
3443 int work_done, int budget)
3444{
3445 struct bnx2_tx_ring_info *txr = &bnapi->tx_ring;
3446 struct bnx2_rx_ring_info *rxr = &bnapi->rx_ring;
Michael Chanb6016b72005-05-26 13:03:09 -07003447
Michael Chan35e90102008-06-19 16:37:42 -07003448 if (bnx2_get_hw_tx_cons(bnapi) != txr->hw_tx_cons)
Michael Chan57851d82007-12-20 20:01:44 -08003449 bnx2_tx_int(bp, bnapi, 0);
Michael Chanb6016b72005-05-26 13:03:09 -07003450
Michael Chanbb4f98a2008-06-19 16:38:19 -07003451 if (bnx2_get_hw_rx_cons(bnapi) != rxr->rx_cons)
Michael Chan35efa7c2007-12-20 19:56:37 -08003452 work_done += bnx2_rx_int(bp, bnapi, budget - work_done);
Jeff Garzik6aa20a22006-09-13 13:24:59 -04003453
David S. Miller6f535762007-10-11 18:08:29 -07003454 return work_done;
3455}
Michael Chanf4e418f2005-11-04 08:53:48 -08003456
Michael Chanf0ea2e62008-06-19 16:41:57 -07003457static int bnx2_poll_msix(struct napi_struct *napi, int budget)
3458{
3459 struct bnx2_napi *bnapi = container_of(napi, struct bnx2_napi, napi);
3460 struct bnx2 *bp = bnapi->bp;
3461 int work_done = 0;
3462 struct status_block_msix *sblk = bnapi->status_blk.msix;
3463
3464 while (1) {
3465 work_done = bnx2_poll_work(bp, bnapi, work_done, budget);
3466 if (unlikely(work_done >= budget))
3467 break;
3468
3469 bnapi->last_status_idx = sblk->status_idx;
3470 /* status idx must be read before checking for more work. */
3471 rmb();
3472 if (likely(!bnx2_has_fast_work(bnapi))) {
3473
Ben Hutchings288379f2009-01-19 16:43:59 -08003474 napi_complete(napi);
Michael Chanf0ea2e62008-06-19 16:41:57 -07003475 REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD, bnapi->int_num |
3476 BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
3477 bnapi->last_status_idx);
3478 break;
3479 }
3480 }
3481 return work_done;
3482}
3483
David S. Miller6f535762007-10-11 18:08:29 -07003484static int bnx2_poll(struct napi_struct *napi, int budget)
3485{
Michael Chan35efa7c2007-12-20 19:56:37 -08003486 struct bnx2_napi *bnapi = container_of(napi, struct bnx2_napi, napi);
3487 struct bnx2 *bp = bnapi->bp;
David S. Miller6f535762007-10-11 18:08:29 -07003488 int work_done = 0;
Michael Chan43e80b82008-06-19 16:41:08 -07003489 struct status_block *sblk = bnapi->status_blk.msi;
David S. Miller6f535762007-10-11 18:08:29 -07003490
3491 while (1) {
Michael Chan43e80b82008-06-19 16:41:08 -07003492 bnx2_poll_link(bp, bnapi);
3493
Michael Chan35efa7c2007-12-20 19:56:37 -08003494 work_done = bnx2_poll_work(bp, bnapi, work_done, budget);
David S. Miller6f535762007-10-11 18:08:29 -07003495
Michael Chan4edd4732009-06-08 18:14:42 -07003496#ifdef BCM_CNIC
3497 bnx2_poll_cnic(bp, bnapi);
3498#endif
3499
Michael Chan35efa7c2007-12-20 19:56:37 -08003500 /* bnapi->last_status_idx is used below to tell the hw how
Michael Chan6dee6422007-10-12 01:40:38 -07003501 * much work has been processed, so we must read it before
3502 * checking for more work.
3503 */
Michael Chan35efa7c2007-12-20 19:56:37 -08003504 bnapi->last_status_idx = sblk->status_idx;
Michael Chanefba0182008-12-03 00:36:15 -08003505
3506 if (unlikely(work_done >= budget))
3507 break;
3508
Michael Chan6dee6422007-10-12 01:40:38 -07003509 rmb();
Michael Chan35efa7c2007-12-20 19:56:37 -08003510 if (likely(!bnx2_has_work(bnapi))) {
Ben Hutchings288379f2009-01-19 16:43:59 -08003511 napi_complete(napi);
David S. Millerf86e82f2008-01-21 17:15:40 -08003512 if (likely(bp->flags & BNX2_FLAG_USING_MSI_OR_MSIX)) {
David S. Miller6f535762007-10-11 18:08:29 -07003513 REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
3514 BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
Michael Chan35efa7c2007-12-20 19:56:37 -08003515 bnapi->last_status_idx);
Michael Chan6dee6422007-10-12 01:40:38 -07003516 break;
David S. Miller6f535762007-10-11 18:08:29 -07003517 }
3518 REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
3519 BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
3520 BNX2_PCICFG_INT_ACK_CMD_MASK_INT |
Michael Chan35efa7c2007-12-20 19:56:37 -08003521 bnapi->last_status_idx);
David S. Miller6f535762007-10-11 18:08:29 -07003522
Michael Chan1269a8a2006-01-23 16:11:03 -08003523 REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
3524 BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
Michael Chan35efa7c2007-12-20 19:56:37 -08003525 bnapi->last_status_idx);
David S. Miller6f535762007-10-11 18:08:29 -07003526 break;
Michael Chan1269a8a2006-01-23 16:11:03 -08003527 }
Michael Chanb6016b72005-05-26 13:03:09 -07003528 }
3529
Stephen Hemmingerbea33482007-10-03 16:41:36 -07003530 return work_done;
Michael Chanb6016b72005-05-26 13:03:09 -07003531}
3532
Herbert Xu932ff272006-06-09 12:20:56 -07003533/* Called with rtnl_lock from vlan functions and also netif_tx_lock
Michael Chanb6016b72005-05-26 13:03:09 -07003534 * from set_multicast.
3535 */
3536static void
3537bnx2_set_rx_mode(struct net_device *dev)
3538{
Michael Chan972ec0d2006-01-23 16:12:43 -08003539 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07003540 u32 rx_mode, sort_mode;
Jiri Pirkoccffad252009-05-22 23:22:17 +00003541 struct netdev_hw_addr *ha;
Michael Chanb6016b72005-05-26 13:03:09 -07003542 int i;
Michael Chanb6016b72005-05-26 13:03:09 -07003543
Michael Chan9f52b562008-10-09 12:21:46 -07003544 if (!netif_running(dev))
3545 return;
3546
Michael Chanc770a652005-08-25 15:38:39 -07003547 spin_lock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07003548
3549 rx_mode = bp->rx_mode & ~(BNX2_EMAC_RX_MODE_PROMISCUOUS |
3550 BNX2_EMAC_RX_MODE_KEEP_VLAN_TAG);
3551 sort_mode = 1 | BNX2_RPM_SORT_USER0_BC_EN;
Jesse Gross7d0fd212010-10-20 13:56:09 +00003552 if (!(dev->features & NETIF_F_HW_VLAN_RX) &&
3553 (bp->flags & BNX2_FLAG_CAN_KEEP_VLAN))
Michael Chanb6016b72005-05-26 13:03:09 -07003554 rx_mode |= BNX2_EMAC_RX_MODE_KEEP_VLAN_TAG;
Michael Chanb6016b72005-05-26 13:03:09 -07003555 if (dev->flags & IFF_PROMISC) {
3556 /* Promiscuous mode. */
3557 rx_mode |= BNX2_EMAC_RX_MODE_PROMISCUOUS;
Michael Chan75108732006-11-19 14:06:40 -08003558 sort_mode |= BNX2_RPM_SORT_USER0_PROM_EN |
3559 BNX2_RPM_SORT_USER0_PROM_VLAN;
Michael Chanb6016b72005-05-26 13:03:09 -07003560 }
3561 else if (dev->flags & IFF_ALLMULTI) {
3562 for (i = 0; i < NUM_MC_HASH_REGISTERS; i++) {
3563 REG_WR(bp, BNX2_EMAC_MULTICAST_HASH0 + (i * 4),
3564 0xffffffff);
3565 }
3566 sort_mode |= BNX2_RPM_SORT_USER0_MC_EN;
3567 }
3568 else {
3569 /* Accept one or more multicast(s). */
Michael Chanb6016b72005-05-26 13:03:09 -07003570 u32 mc_filter[NUM_MC_HASH_REGISTERS];
3571 u32 regidx;
3572 u32 bit;
3573 u32 crc;
3574
3575 memset(mc_filter, 0, 4 * NUM_MC_HASH_REGISTERS);
3576
Jiri Pirko22bedad32010-04-01 21:22:57 +00003577 netdev_for_each_mc_addr(ha, dev) {
3578 crc = ether_crc_le(ETH_ALEN, ha->addr);
Michael Chanb6016b72005-05-26 13:03:09 -07003579 bit = crc & 0xff;
3580 regidx = (bit & 0xe0) >> 5;
3581 bit &= 0x1f;
3582 mc_filter[regidx] |= (1 << bit);
3583 }
3584
3585 for (i = 0; i < NUM_MC_HASH_REGISTERS; i++) {
3586 REG_WR(bp, BNX2_EMAC_MULTICAST_HASH0 + (i * 4),
3587 mc_filter[i]);
3588 }
3589
3590 sort_mode |= BNX2_RPM_SORT_USER0_MC_HSH_EN;
3591 }
3592
Jiri Pirko32e7bfc2010-01-25 13:36:10 -08003593 if (netdev_uc_count(dev) > BNX2_MAX_UNICAST_ADDRESSES) {
Benjamin Li5fcaed02008-07-14 22:39:52 -07003594 rx_mode |= BNX2_EMAC_RX_MODE_PROMISCUOUS;
3595 sort_mode |= BNX2_RPM_SORT_USER0_PROM_EN |
3596 BNX2_RPM_SORT_USER0_PROM_VLAN;
3597 } else if (!(dev->flags & IFF_PROMISC)) {
Benjamin Li5fcaed02008-07-14 22:39:52 -07003598 /* Add all entries into to the match filter list */
Jiri Pirkoccffad252009-05-22 23:22:17 +00003599 i = 0;
Jiri Pirko32e7bfc2010-01-25 13:36:10 -08003600 netdev_for_each_uc_addr(ha, dev) {
Jiri Pirkoccffad252009-05-22 23:22:17 +00003601 bnx2_set_mac_addr(bp, ha->addr,
Benjamin Li5fcaed02008-07-14 22:39:52 -07003602 i + BNX2_START_UNICAST_ADDRESS_INDEX);
3603 sort_mode |= (1 <<
3604 (i + BNX2_START_UNICAST_ADDRESS_INDEX));
Jiri Pirkoccffad252009-05-22 23:22:17 +00003605 i++;
Benjamin Li5fcaed02008-07-14 22:39:52 -07003606 }
3607
3608 }
3609
Michael Chanb6016b72005-05-26 13:03:09 -07003610 if (rx_mode != bp->rx_mode) {
3611 bp->rx_mode = rx_mode;
3612 REG_WR(bp, BNX2_EMAC_RX_MODE, rx_mode);
3613 }
3614
3615 REG_WR(bp, BNX2_RPM_SORT_USER0, 0x0);
3616 REG_WR(bp, BNX2_RPM_SORT_USER0, sort_mode);
3617 REG_WR(bp, BNX2_RPM_SORT_USER0, sort_mode | BNX2_RPM_SORT_USER0_ENA);
3618
Michael Chanc770a652005-08-25 15:38:39 -07003619 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07003620}
3621
Michael Chan57579f72009-04-04 16:51:14 -07003622static int __devinit
3623check_fw_section(const struct firmware *fw,
3624 const struct bnx2_fw_file_section *section,
3625 u32 alignment, bool non_empty)
Michael Chanb6016b72005-05-26 13:03:09 -07003626{
Michael Chan57579f72009-04-04 16:51:14 -07003627 u32 offset = be32_to_cpu(section->offset);
3628 u32 len = be32_to_cpu(section->len);
Michael Chanb6016b72005-05-26 13:03:09 -07003629
Michael Chan57579f72009-04-04 16:51:14 -07003630 if ((offset == 0 && len != 0) || offset >= fw->size || offset & 3)
3631 return -EINVAL;
3632 if ((non_empty && len == 0) || len > fw->size - offset ||
3633 len & (alignment - 1))
3634 return -EINVAL;
3635 return 0;
3636}
3637
3638static int __devinit
3639check_mips_fw_entry(const struct firmware *fw,
3640 const struct bnx2_mips_fw_file_entry *entry)
3641{
3642 if (check_fw_section(fw, &entry->text, 4, true) ||
3643 check_fw_section(fw, &entry->data, 4, false) ||
3644 check_fw_section(fw, &entry->rodata, 4, false))
3645 return -EINVAL;
3646 return 0;
3647}
3648
3649static int __devinit
3650bnx2_request_firmware(struct bnx2 *bp)
3651{
3652 const char *mips_fw_file, *rv2p_fw_file;
Bastian Blank5ee1c322009-04-08 15:50:07 -07003653 const struct bnx2_mips_fw_file *mips_fw;
3654 const struct bnx2_rv2p_fw_file *rv2p_fw;
Michael Chan57579f72009-04-04 16:51:14 -07003655 int rc;
3656
3657 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
3658 mips_fw_file = FW_MIPS_FILE_09;
Michael Chan078b0732009-08-29 00:02:46 -07003659 if ((CHIP_ID(bp) == CHIP_ID_5709_A0) ||
3660 (CHIP_ID(bp) == CHIP_ID_5709_A1))
3661 rv2p_fw_file = FW_RV2P_FILE_09_Ax;
3662 else
3663 rv2p_fw_file = FW_RV2P_FILE_09;
Michael Chan57579f72009-04-04 16:51:14 -07003664 } else {
3665 mips_fw_file = FW_MIPS_FILE_06;
3666 rv2p_fw_file = FW_RV2P_FILE_06;
3667 }
3668
3669 rc = request_firmware(&bp->mips_firmware, mips_fw_file, &bp->pdev->dev);
3670 if (rc) {
Joe Perches3a9c6a42010-02-17 15:01:51 +00003671 pr_err("Can't load firmware file \"%s\"\n", mips_fw_file);
Michael Chan57579f72009-04-04 16:51:14 -07003672 return rc;
3673 }
3674
3675 rc = request_firmware(&bp->rv2p_firmware, rv2p_fw_file, &bp->pdev->dev);
3676 if (rc) {
Joe Perches3a9c6a42010-02-17 15:01:51 +00003677 pr_err("Can't load firmware file \"%s\"\n", rv2p_fw_file);
Michael Chan57579f72009-04-04 16:51:14 -07003678 return rc;
3679 }
Bastian Blank5ee1c322009-04-08 15:50:07 -07003680 mips_fw = (const struct bnx2_mips_fw_file *) bp->mips_firmware->data;
3681 rv2p_fw = (const struct bnx2_rv2p_fw_file *) bp->rv2p_firmware->data;
3682 if (bp->mips_firmware->size < sizeof(*mips_fw) ||
3683 check_mips_fw_entry(bp->mips_firmware, &mips_fw->com) ||
3684 check_mips_fw_entry(bp->mips_firmware, &mips_fw->cp) ||
3685 check_mips_fw_entry(bp->mips_firmware, &mips_fw->rxp) ||
3686 check_mips_fw_entry(bp->mips_firmware, &mips_fw->tpat) ||
3687 check_mips_fw_entry(bp->mips_firmware, &mips_fw->txp)) {
Joe Perches3a9c6a42010-02-17 15:01:51 +00003688 pr_err("Firmware file \"%s\" is invalid\n", mips_fw_file);
Michael Chan57579f72009-04-04 16:51:14 -07003689 return -EINVAL;
3690 }
Bastian Blank5ee1c322009-04-08 15:50:07 -07003691 if (bp->rv2p_firmware->size < sizeof(*rv2p_fw) ||
3692 check_fw_section(bp->rv2p_firmware, &rv2p_fw->proc1.rv2p, 8, true) ||
3693 check_fw_section(bp->rv2p_firmware, &rv2p_fw->proc2.rv2p, 8, true)) {
Joe Perches3a9c6a42010-02-17 15:01:51 +00003694 pr_err("Firmware file \"%s\" is invalid\n", rv2p_fw_file);
Michael Chan57579f72009-04-04 16:51:14 -07003695 return -EINVAL;
3696 }
3697
3698 return 0;
3699}
3700
3701static u32
3702rv2p_fw_fixup(u32 rv2p_proc, int idx, u32 loc, u32 rv2p_code)
3703{
3704 switch (idx) {
3705 case RV2P_P1_FIXUP_PAGE_SIZE_IDX:
3706 rv2p_code &= ~RV2P_BD_PAGE_SIZE_MSK;
3707 rv2p_code |= RV2P_BD_PAGE_SIZE;
3708 break;
3709 }
3710 return rv2p_code;
3711}
3712
3713static int
3714load_rv2p_fw(struct bnx2 *bp, u32 rv2p_proc,
3715 const struct bnx2_rv2p_fw_file_entry *fw_entry)
3716{
3717 u32 rv2p_code_len, file_offset;
3718 __be32 *rv2p_code;
3719 int i;
3720 u32 val, cmd, addr;
3721
3722 rv2p_code_len = be32_to_cpu(fw_entry->rv2p.len);
3723 file_offset = be32_to_cpu(fw_entry->rv2p.offset);
3724
3725 rv2p_code = (__be32 *)(bp->rv2p_firmware->data + file_offset);
3726
3727 if (rv2p_proc == RV2P_PROC1) {
3728 cmd = BNX2_RV2P_PROC1_ADDR_CMD_RDWR;
3729 addr = BNX2_RV2P_PROC1_ADDR_CMD;
3730 } else {
3731 cmd = BNX2_RV2P_PROC2_ADDR_CMD_RDWR;
3732 addr = BNX2_RV2P_PROC2_ADDR_CMD;
Michael Chand25be1d2008-05-02 16:57:59 -07003733 }
Michael Chanb6016b72005-05-26 13:03:09 -07003734
3735 for (i = 0; i < rv2p_code_len; i += 8) {
Michael Chan57579f72009-04-04 16:51:14 -07003736 REG_WR(bp, BNX2_RV2P_INSTR_HIGH, be32_to_cpu(*rv2p_code));
Michael Chanb6016b72005-05-26 13:03:09 -07003737 rv2p_code++;
Michael Chan57579f72009-04-04 16:51:14 -07003738 REG_WR(bp, BNX2_RV2P_INSTR_LOW, be32_to_cpu(*rv2p_code));
Michael Chanb6016b72005-05-26 13:03:09 -07003739 rv2p_code++;
3740
Michael Chan57579f72009-04-04 16:51:14 -07003741 val = (i / 8) | cmd;
3742 REG_WR(bp, addr, val);
3743 }
3744
3745 rv2p_code = (__be32 *)(bp->rv2p_firmware->data + file_offset);
3746 for (i = 0; i < 8; i++) {
3747 u32 loc, code;
3748
3749 loc = be32_to_cpu(fw_entry->fixup[i]);
3750 if (loc && ((loc * 4) < rv2p_code_len)) {
3751 code = be32_to_cpu(*(rv2p_code + loc - 1));
3752 REG_WR(bp, BNX2_RV2P_INSTR_HIGH, code);
3753 code = be32_to_cpu(*(rv2p_code + loc));
3754 code = rv2p_fw_fixup(rv2p_proc, i, loc, code);
3755 REG_WR(bp, BNX2_RV2P_INSTR_LOW, code);
3756
3757 val = (loc / 2) | cmd;
3758 REG_WR(bp, addr, val);
Michael Chanb6016b72005-05-26 13:03:09 -07003759 }
3760 }
3761
3762 /* Reset the processor, un-stall is done later. */
3763 if (rv2p_proc == RV2P_PROC1) {
3764 REG_WR(bp, BNX2_RV2P_COMMAND, BNX2_RV2P_COMMAND_PROC1_RESET);
3765 }
3766 else {
3767 REG_WR(bp, BNX2_RV2P_COMMAND, BNX2_RV2P_COMMAND_PROC2_RESET);
3768 }
Michael Chan57579f72009-04-04 16:51:14 -07003769
3770 return 0;
Michael Chanb6016b72005-05-26 13:03:09 -07003771}
3772
Michael Chanaf3ee512006-11-19 14:09:25 -08003773static int
Michael Chan57579f72009-04-04 16:51:14 -07003774load_cpu_fw(struct bnx2 *bp, const struct cpu_reg *cpu_reg,
3775 const struct bnx2_mips_fw_file_entry *fw_entry)
Michael Chanb6016b72005-05-26 13:03:09 -07003776{
Michael Chan57579f72009-04-04 16:51:14 -07003777 u32 addr, len, file_offset;
3778 __be32 *data;
Michael Chanb6016b72005-05-26 13:03:09 -07003779 u32 offset;
3780 u32 val;
3781
3782 /* Halt the CPU. */
Michael Chan2726d6e2008-01-29 21:35:05 -08003783 val = bnx2_reg_rd_ind(bp, cpu_reg->mode);
Michael Chanb6016b72005-05-26 13:03:09 -07003784 val |= cpu_reg->mode_value_halt;
Michael Chan2726d6e2008-01-29 21:35:05 -08003785 bnx2_reg_wr_ind(bp, cpu_reg->mode, val);
3786 bnx2_reg_wr_ind(bp, cpu_reg->state, cpu_reg->state_value_clear);
Michael Chanb6016b72005-05-26 13:03:09 -07003787
3788 /* Load the Text area. */
Michael Chan57579f72009-04-04 16:51:14 -07003789 addr = be32_to_cpu(fw_entry->text.addr);
3790 len = be32_to_cpu(fw_entry->text.len);
3791 file_offset = be32_to_cpu(fw_entry->text.offset);
3792 data = (__be32 *)(bp->mips_firmware->data + file_offset);
3793
3794 offset = cpu_reg->spad_base + (addr - cpu_reg->mips_view_base);
3795 if (len) {
Michael Chanb6016b72005-05-26 13:03:09 -07003796 int j;
3797
Michael Chan57579f72009-04-04 16:51:14 -07003798 for (j = 0; j < (len / 4); j++, offset += 4)
3799 bnx2_reg_wr_ind(bp, offset, be32_to_cpu(data[j]));
Michael Chanb6016b72005-05-26 13:03:09 -07003800 }
3801
3802 /* Load the Data area. */
Michael Chan57579f72009-04-04 16:51:14 -07003803 addr = be32_to_cpu(fw_entry->data.addr);
3804 len = be32_to_cpu(fw_entry->data.len);
3805 file_offset = be32_to_cpu(fw_entry->data.offset);
3806 data = (__be32 *)(bp->mips_firmware->data + file_offset);
3807
3808 offset = cpu_reg->spad_base + (addr - cpu_reg->mips_view_base);
3809 if (len) {
Michael Chanb6016b72005-05-26 13:03:09 -07003810 int j;
3811
Michael Chan57579f72009-04-04 16:51:14 -07003812 for (j = 0; j < (len / 4); j++, offset += 4)
3813 bnx2_reg_wr_ind(bp, offset, be32_to_cpu(data[j]));
Michael Chanb6016b72005-05-26 13:03:09 -07003814 }
3815
3816 /* Load the Read-Only area. */
Michael Chan57579f72009-04-04 16:51:14 -07003817 addr = be32_to_cpu(fw_entry->rodata.addr);
3818 len = be32_to_cpu(fw_entry->rodata.len);
3819 file_offset = be32_to_cpu(fw_entry->rodata.offset);
3820 data = (__be32 *)(bp->mips_firmware->data + file_offset);
3821
3822 offset = cpu_reg->spad_base + (addr - cpu_reg->mips_view_base);
3823 if (len) {
Michael Chanb6016b72005-05-26 13:03:09 -07003824 int j;
3825
Michael Chan57579f72009-04-04 16:51:14 -07003826 for (j = 0; j < (len / 4); j++, offset += 4)
3827 bnx2_reg_wr_ind(bp, offset, be32_to_cpu(data[j]));
Michael Chanb6016b72005-05-26 13:03:09 -07003828 }
3829
3830 /* Clear the pre-fetch instruction. */
Michael Chan2726d6e2008-01-29 21:35:05 -08003831 bnx2_reg_wr_ind(bp, cpu_reg->inst, 0);
Michael Chan57579f72009-04-04 16:51:14 -07003832
3833 val = be32_to_cpu(fw_entry->start_addr);
3834 bnx2_reg_wr_ind(bp, cpu_reg->pc, val);
Michael Chanb6016b72005-05-26 13:03:09 -07003835
3836 /* Start the CPU. */
Michael Chan2726d6e2008-01-29 21:35:05 -08003837 val = bnx2_reg_rd_ind(bp, cpu_reg->mode);
Michael Chanb6016b72005-05-26 13:03:09 -07003838 val &= ~cpu_reg->mode_value_halt;
Michael Chan2726d6e2008-01-29 21:35:05 -08003839 bnx2_reg_wr_ind(bp, cpu_reg->state, cpu_reg->state_value_clear);
3840 bnx2_reg_wr_ind(bp, cpu_reg->mode, val);
Michael Chanaf3ee512006-11-19 14:09:25 -08003841
3842 return 0;
Michael Chanb6016b72005-05-26 13:03:09 -07003843}
3844
Michael Chanfba9fe92006-06-12 22:21:25 -07003845static int
Michael Chanb6016b72005-05-26 13:03:09 -07003846bnx2_init_cpus(struct bnx2 *bp)
3847{
Michael Chan57579f72009-04-04 16:51:14 -07003848 const struct bnx2_mips_fw_file *mips_fw =
3849 (const struct bnx2_mips_fw_file *) bp->mips_firmware->data;
3850 const struct bnx2_rv2p_fw_file *rv2p_fw =
3851 (const struct bnx2_rv2p_fw_file *) bp->rv2p_firmware->data;
3852 int rc;
Michael Chanb6016b72005-05-26 13:03:09 -07003853
3854 /* Initialize the RV2P processor. */
Michael Chan57579f72009-04-04 16:51:14 -07003855 load_rv2p_fw(bp, RV2P_PROC1, &rv2p_fw->proc1);
3856 load_rv2p_fw(bp, RV2P_PROC2, &rv2p_fw->proc2);
Michael Chanb6016b72005-05-26 13:03:09 -07003857
3858 /* Initialize the RX Processor. */
Michael Chan57579f72009-04-04 16:51:14 -07003859 rc = load_cpu_fw(bp, &cpu_reg_rxp, &mips_fw->rxp);
Michael Chanfba9fe92006-06-12 22:21:25 -07003860 if (rc)
3861 goto init_cpu_err;
3862
Michael Chanb6016b72005-05-26 13:03:09 -07003863 /* Initialize the TX Processor. */
Michael Chan57579f72009-04-04 16:51:14 -07003864 rc = load_cpu_fw(bp, &cpu_reg_txp, &mips_fw->txp);
Michael Chanfba9fe92006-06-12 22:21:25 -07003865 if (rc)
3866 goto init_cpu_err;
3867
Michael Chanb6016b72005-05-26 13:03:09 -07003868 /* Initialize the TX Patch-up Processor. */
Michael Chan57579f72009-04-04 16:51:14 -07003869 rc = load_cpu_fw(bp, &cpu_reg_tpat, &mips_fw->tpat);
Michael Chanfba9fe92006-06-12 22:21:25 -07003870 if (rc)
3871 goto init_cpu_err;
3872
Michael Chanb6016b72005-05-26 13:03:09 -07003873 /* Initialize the Completion Processor. */
Michael Chan57579f72009-04-04 16:51:14 -07003874 rc = load_cpu_fw(bp, &cpu_reg_com, &mips_fw->com);
Michael Chanfba9fe92006-06-12 22:21:25 -07003875 if (rc)
3876 goto init_cpu_err;
3877
Michael Chand43584c2006-11-19 14:14:35 -08003878 /* Initialize the Command Processor. */
Michael Chan57579f72009-04-04 16:51:14 -07003879 rc = load_cpu_fw(bp, &cpu_reg_cp, &mips_fw->cp);
Michael Chan110d0ef2007-12-12 11:18:34 -08003880
Michael Chanfba9fe92006-06-12 22:21:25 -07003881init_cpu_err:
Michael Chanfba9fe92006-06-12 22:21:25 -07003882 return rc;
Michael Chanb6016b72005-05-26 13:03:09 -07003883}
3884
3885static int
Pavel Machek829ca9a2005-09-03 15:56:56 -07003886bnx2_set_power_state(struct bnx2 *bp, pci_power_t state)
Michael Chanb6016b72005-05-26 13:03:09 -07003887{
3888 u16 pmcsr;
3889
3890 pci_read_config_word(bp->pdev, bp->pm_cap + PCI_PM_CTRL, &pmcsr);
3891
3892 switch (state) {
Pavel Machek829ca9a2005-09-03 15:56:56 -07003893 case PCI_D0: {
Michael Chanb6016b72005-05-26 13:03:09 -07003894 u32 val;
3895
3896 pci_write_config_word(bp->pdev, bp->pm_cap + PCI_PM_CTRL,
3897 (pmcsr & ~PCI_PM_CTRL_STATE_MASK) |
3898 PCI_PM_CTRL_PME_STATUS);
3899
3900 if (pmcsr & PCI_PM_CTRL_STATE_MASK)
3901 /* delay required during transition out of D3hot */
3902 msleep(20);
3903
3904 val = REG_RD(bp, BNX2_EMAC_MODE);
3905 val |= BNX2_EMAC_MODE_MPKT_RCVD | BNX2_EMAC_MODE_ACPI_RCVD;
3906 val &= ~BNX2_EMAC_MODE_MPKT;
3907 REG_WR(bp, BNX2_EMAC_MODE, val);
3908
3909 val = REG_RD(bp, BNX2_RPM_CONFIG);
3910 val &= ~BNX2_RPM_CONFIG_ACPI_ENA;
3911 REG_WR(bp, BNX2_RPM_CONFIG, val);
3912 break;
3913 }
Pavel Machek829ca9a2005-09-03 15:56:56 -07003914 case PCI_D3hot: {
Michael Chanb6016b72005-05-26 13:03:09 -07003915 int i;
3916 u32 val, wol_msg;
3917
3918 if (bp->wol) {
3919 u32 advertising;
3920 u8 autoneg;
3921
3922 autoneg = bp->autoneg;
3923 advertising = bp->advertising;
3924
Michael Chan239cd342007-10-17 19:26:15 -07003925 if (bp->phy_port == PORT_TP) {
3926 bp->autoneg = AUTONEG_SPEED;
3927 bp->advertising = ADVERTISED_10baseT_Half |
3928 ADVERTISED_10baseT_Full |
3929 ADVERTISED_100baseT_Half |
3930 ADVERTISED_100baseT_Full |
3931 ADVERTISED_Autoneg;
3932 }
Michael Chanb6016b72005-05-26 13:03:09 -07003933
Michael Chan239cd342007-10-17 19:26:15 -07003934 spin_lock_bh(&bp->phy_lock);
3935 bnx2_setup_phy(bp, bp->phy_port);
3936 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07003937
3938 bp->autoneg = autoneg;
3939 bp->advertising = advertising;
3940
Benjamin Li5fcaed02008-07-14 22:39:52 -07003941 bnx2_set_mac_addr(bp, bp->dev->dev_addr, 0);
Michael Chanb6016b72005-05-26 13:03:09 -07003942
3943 val = REG_RD(bp, BNX2_EMAC_MODE);
3944
3945 /* Enable port mode. */
3946 val &= ~BNX2_EMAC_MODE_PORT;
Michael Chan239cd342007-10-17 19:26:15 -07003947 val |= BNX2_EMAC_MODE_MPKT_RCVD |
Michael Chanb6016b72005-05-26 13:03:09 -07003948 BNX2_EMAC_MODE_ACPI_RCVD |
Michael Chanb6016b72005-05-26 13:03:09 -07003949 BNX2_EMAC_MODE_MPKT;
Michael Chan239cd342007-10-17 19:26:15 -07003950 if (bp->phy_port == PORT_TP)
3951 val |= BNX2_EMAC_MODE_PORT_MII;
3952 else {
3953 val |= BNX2_EMAC_MODE_PORT_GMII;
3954 if (bp->line_speed == SPEED_2500)
3955 val |= BNX2_EMAC_MODE_25G_MODE;
3956 }
Michael Chanb6016b72005-05-26 13:03:09 -07003957
3958 REG_WR(bp, BNX2_EMAC_MODE, val);
3959
3960 /* receive all multicast */
3961 for (i = 0; i < NUM_MC_HASH_REGISTERS; i++) {
3962 REG_WR(bp, BNX2_EMAC_MULTICAST_HASH0 + (i * 4),
3963 0xffffffff);
3964 }
3965 REG_WR(bp, BNX2_EMAC_RX_MODE,
3966 BNX2_EMAC_RX_MODE_SORT_MODE);
3967
3968 val = 1 | BNX2_RPM_SORT_USER0_BC_EN |
3969 BNX2_RPM_SORT_USER0_MC_EN;
3970 REG_WR(bp, BNX2_RPM_SORT_USER0, 0x0);
3971 REG_WR(bp, BNX2_RPM_SORT_USER0, val);
3972 REG_WR(bp, BNX2_RPM_SORT_USER0, val |
3973 BNX2_RPM_SORT_USER0_ENA);
3974
3975 /* Need to enable EMAC and RPM for WOL. */
3976 REG_WR(bp, BNX2_MISC_ENABLE_SET_BITS,
3977 BNX2_MISC_ENABLE_SET_BITS_RX_PARSER_MAC_ENABLE |
3978 BNX2_MISC_ENABLE_SET_BITS_TX_HEADER_Q_ENABLE |
3979 BNX2_MISC_ENABLE_SET_BITS_EMAC_ENABLE);
3980
3981 val = REG_RD(bp, BNX2_RPM_CONFIG);
3982 val &= ~BNX2_RPM_CONFIG_ACPI_ENA;
3983 REG_WR(bp, BNX2_RPM_CONFIG, val);
3984
3985 wol_msg = BNX2_DRV_MSG_CODE_SUSPEND_WOL;
3986 }
3987 else {
3988 wol_msg = BNX2_DRV_MSG_CODE_SUSPEND_NO_WOL;
3989 }
3990
David S. Millerf86e82f2008-01-21 17:15:40 -08003991 if (!(bp->flags & BNX2_FLAG_NO_WOL))
Michael Chana2f13892008-07-14 22:38:23 -07003992 bnx2_fw_sync(bp, BNX2_DRV_MSG_DATA_WAIT3 | wol_msg,
3993 1, 0);
Michael Chanb6016b72005-05-26 13:03:09 -07003994
3995 pmcsr &= ~PCI_PM_CTRL_STATE_MASK;
3996 if ((CHIP_ID(bp) == CHIP_ID_5706_A0) ||
3997 (CHIP_ID(bp) == CHIP_ID_5706_A1)) {
3998
3999 if (bp->wol)
4000 pmcsr |= 3;
4001 }
4002 else {
4003 pmcsr |= 3;
4004 }
4005 if (bp->wol) {
4006 pmcsr |= PCI_PM_CTRL_PME_ENABLE;
4007 }
4008 pci_write_config_word(bp->pdev, bp->pm_cap + PCI_PM_CTRL,
4009 pmcsr);
4010
4011 /* No more memory access after this point until
4012 * device is brought back to D0.
4013 */
4014 udelay(50);
4015 break;
4016 }
4017 default:
4018 return -EINVAL;
4019 }
4020 return 0;
4021}
4022
4023static int
4024bnx2_acquire_nvram_lock(struct bnx2 *bp)
4025{
4026 u32 val;
4027 int j;
4028
4029 /* Request access to the flash interface. */
4030 REG_WR(bp, BNX2_NVM_SW_ARB, BNX2_NVM_SW_ARB_ARB_REQ_SET2);
4031 for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) {
4032 val = REG_RD(bp, BNX2_NVM_SW_ARB);
4033 if (val & BNX2_NVM_SW_ARB_ARB_ARB2)
4034 break;
4035
4036 udelay(5);
4037 }
4038
4039 if (j >= NVRAM_TIMEOUT_COUNT)
4040 return -EBUSY;
4041
4042 return 0;
4043}
4044
4045static int
4046bnx2_release_nvram_lock(struct bnx2 *bp)
4047{
4048 int j;
4049 u32 val;
4050
4051 /* Relinquish nvram interface. */
4052 REG_WR(bp, BNX2_NVM_SW_ARB, BNX2_NVM_SW_ARB_ARB_REQ_CLR2);
4053
4054 for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) {
4055 val = REG_RD(bp, BNX2_NVM_SW_ARB);
4056 if (!(val & BNX2_NVM_SW_ARB_ARB_ARB2))
4057 break;
4058
4059 udelay(5);
4060 }
4061
4062 if (j >= NVRAM_TIMEOUT_COUNT)
4063 return -EBUSY;
4064
4065 return 0;
4066}
4067
4068
4069static int
4070bnx2_enable_nvram_write(struct bnx2 *bp)
4071{
4072 u32 val;
4073
4074 val = REG_RD(bp, BNX2_MISC_CFG);
4075 REG_WR(bp, BNX2_MISC_CFG, val | BNX2_MISC_CFG_NVM_WR_EN_PCI);
4076
Michael Chane30372c2007-07-16 18:26:23 -07004077 if (bp->flash_info->flags & BNX2_NV_WREN) {
Michael Chanb6016b72005-05-26 13:03:09 -07004078 int j;
4079
4080 REG_WR(bp, BNX2_NVM_COMMAND, BNX2_NVM_COMMAND_DONE);
4081 REG_WR(bp, BNX2_NVM_COMMAND,
4082 BNX2_NVM_COMMAND_WREN | BNX2_NVM_COMMAND_DOIT);
4083
4084 for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) {
4085 udelay(5);
4086
4087 val = REG_RD(bp, BNX2_NVM_COMMAND);
4088 if (val & BNX2_NVM_COMMAND_DONE)
4089 break;
4090 }
4091
4092 if (j >= NVRAM_TIMEOUT_COUNT)
4093 return -EBUSY;
4094 }
4095 return 0;
4096}
4097
4098static void
4099bnx2_disable_nvram_write(struct bnx2 *bp)
4100{
4101 u32 val;
4102
4103 val = REG_RD(bp, BNX2_MISC_CFG);
4104 REG_WR(bp, BNX2_MISC_CFG, val & ~BNX2_MISC_CFG_NVM_WR_EN);
4105}
4106
4107
4108static void
4109bnx2_enable_nvram_access(struct bnx2 *bp)
4110{
4111 u32 val;
4112
4113 val = REG_RD(bp, BNX2_NVM_ACCESS_ENABLE);
4114 /* Enable both bits, even on read. */
Jeff Garzik6aa20a22006-09-13 13:24:59 -04004115 REG_WR(bp, BNX2_NVM_ACCESS_ENABLE,
Michael Chanb6016b72005-05-26 13:03:09 -07004116 val | BNX2_NVM_ACCESS_ENABLE_EN | BNX2_NVM_ACCESS_ENABLE_WR_EN);
4117}
4118
4119static void
4120bnx2_disable_nvram_access(struct bnx2 *bp)
4121{
4122 u32 val;
4123
4124 val = REG_RD(bp, BNX2_NVM_ACCESS_ENABLE);
4125 /* Disable both bits, even after read. */
Jeff Garzik6aa20a22006-09-13 13:24:59 -04004126 REG_WR(bp, BNX2_NVM_ACCESS_ENABLE,
Michael Chanb6016b72005-05-26 13:03:09 -07004127 val & ~(BNX2_NVM_ACCESS_ENABLE_EN |
4128 BNX2_NVM_ACCESS_ENABLE_WR_EN));
4129}
4130
4131static int
4132bnx2_nvram_erase_page(struct bnx2 *bp, u32 offset)
4133{
4134 u32 cmd;
4135 int j;
4136
Michael Chane30372c2007-07-16 18:26:23 -07004137 if (bp->flash_info->flags & BNX2_NV_BUFFERED)
Michael Chanb6016b72005-05-26 13:03:09 -07004138 /* Buffered flash, no erase needed */
4139 return 0;
4140
4141 /* Build an erase command */
4142 cmd = BNX2_NVM_COMMAND_ERASE | BNX2_NVM_COMMAND_WR |
4143 BNX2_NVM_COMMAND_DOIT;
4144
4145 /* Need to clear DONE bit separately. */
4146 REG_WR(bp, BNX2_NVM_COMMAND, BNX2_NVM_COMMAND_DONE);
4147
4148 /* Address of the NVRAM to read from. */
4149 REG_WR(bp, BNX2_NVM_ADDR, offset & BNX2_NVM_ADDR_NVM_ADDR_VALUE);
4150
4151 /* Issue an erase command. */
4152 REG_WR(bp, BNX2_NVM_COMMAND, cmd);
4153
4154 /* Wait for completion. */
4155 for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) {
4156 u32 val;
4157
4158 udelay(5);
4159
4160 val = REG_RD(bp, BNX2_NVM_COMMAND);
4161 if (val & BNX2_NVM_COMMAND_DONE)
4162 break;
4163 }
4164
4165 if (j >= NVRAM_TIMEOUT_COUNT)
4166 return -EBUSY;
4167
4168 return 0;
4169}
4170
4171static int
4172bnx2_nvram_read_dword(struct bnx2 *bp, u32 offset, u8 *ret_val, u32 cmd_flags)
4173{
4174 u32 cmd;
4175 int j;
4176
4177 /* Build the command word. */
4178 cmd = BNX2_NVM_COMMAND_DOIT | cmd_flags;
4179
Michael Chane30372c2007-07-16 18:26:23 -07004180 /* Calculate an offset of a buffered flash, not needed for 5709. */
4181 if (bp->flash_info->flags & BNX2_NV_TRANSLATE) {
Michael Chanb6016b72005-05-26 13:03:09 -07004182 offset = ((offset / bp->flash_info->page_size) <<
4183 bp->flash_info->page_bits) +
4184 (offset % bp->flash_info->page_size);
4185 }
4186
4187 /* Need to clear DONE bit separately. */
4188 REG_WR(bp, BNX2_NVM_COMMAND, BNX2_NVM_COMMAND_DONE);
4189
4190 /* Address of the NVRAM to read from. */
4191 REG_WR(bp, BNX2_NVM_ADDR, offset & BNX2_NVM_ADDR_NVM_ADDR_VALUE);
4192
4193 /* Issue a read command. */
4194 REG_WR(bp, BNX2_NVM_COMMAND, cmd);
4195
4196 /* Wait for completion. */
4197 for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) {
4198 u32 val;
4199
4200 udelay(5);
4201
4202 val = REG_RD(bp, BNX2_NVM_COMMAND);
4203 if (val & BNX2_NVM_COMMAND_DONE) {
Al Virob491edd2007-12-22 19:44:51 +00004204 __be32 v = cpu_to_be32(REG_RD(bp, BNX2_NVM_READ));
4205 memcpy(ret_val, &v, 4);
Michael Chanb6016b72005-05-26 13:03:09 -07004206 break;
4207 }
4208 }
4209 if (j >= NVRAM_TIMEOUT_COUNT)
4210 return -EBUSY;
4211
4212 return 0;
4213}
4214
4215
4216static int
4217bnx2_nvram_write_dword(struct bnx2 *bp, u32 offset, u8 *val, u32 cmd_flags)
4218{
Al Virob491edd2007-12-22 19:44:51 +00004219 u32 cmd;
4220 __be32 val32;
Michael Chanb6016b72005-05-26 13:03:09 -07004221 int j;
4222
4223 /* Build the command word. */
4224 cmd = BNX2_NVM_COMMAND_DOIT | BNX2_NVM_COMMAND_WR | cmd_flags;
4225
Michael Chane30372c2007-07-16 18:26:23 -07004226 /* Calculate an offset of a buffered flash, not needed for 5709. */
4227 if (bp->flash_info->flags & BNX2_NV_TRANSLATE) {
Michael Chanb6016b72005-05-26 13:03:09 -07004228 offset = ((offset / bp->flash_info->page_size) <<
4229 bp->flash_info->page_bits) +
4230 (offset % bp->flash_info->page_size);
4231 }
4232
4233 /* Need to clear DONE bit separately. */
4234 REG_WR(bp, BNX2_NVM_COMMAND, BNX2_NVM_COMMAND_DONE);
4235
4236 memcpy(&val32, val, 4);
Michael Chanb6016b72005-05-26 13:03:09 -07004237
4238 /* Write the data. */
Al Virob491edd2007-12-22 19:44:51 +00004239 REG_WR(bp, BNX2_NVM_WRITE, be32_to_cpu(val32));
Michael Chanb6016b72005-05-26 13:03:09 -07004240
4241 /* Address of the NVRAM to write to. */
4242 REG_WR(bp, BNX2_NVM_ADDR, offset & BNX2_NVM_ADDR_NVM_ADDR_VALUE);
4243
4244 /* Issue the write command. */
4245 REG_WR(bp, BNX2_NVM_COMMAND, cmd);
4246
4247 /* Wait for completion. */
4248 for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) {
4249 udelay(5);
4250
4251 if (REG_RD(bp, BNX2_NVM_COMMAND) & BNX2_NVM_COMMAND_DONE)
4252 break;
4253 }
4254 if (j >= NVRAM_TIMEOUT_COUNT)
4255 return -EBUSY;
4256
4257 return 0;
4258}
4259
4260static int
4261bnx2_init_nvram(struct bnx2 *bp)
4262{
4263 u32 val;
Michael Chane30372c2007-07-16 18:26:23 -07004264 int j, entry_count, rc = 0;
Michael Chan0ced9d02009-08-21 16:20:49 +00004265 const struct flash_spec *flash;
Michael Chanb6016b72005-05-26 13:03:09 -07004266
Michael Chane30372c2007-07-16 18:26:23 -07004267 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
4268 bp->flash_info = &flash_5709;
4269 goto get_flash_size;
4270 }
4271
Michael Chanb6016b72005-05-26 13:03:09 -07004272 /* Determine the selected interface. */
4273 val = REG_RD(bp, BNX2_NVM_CFG1);
4274
Denis Chengff8ac602007-09-02 18:30:18 +08004275 entry_count = ARRAY_SIZE(flash_table);
Michael Chanb6016b72005-05-26 13:03:09 -07004276
Michael Chanb6016b72005-05-26 13:03:09 -07004277 if (val & 0x40000000) {
4278
4279 /* Flash interface has been reconfigured */
4280 for (j = 0, flash = &flash_table[0]; j < entry_count;
Michael Chan37137702005-11-04 08:49:17 -08004281 j++, flash++) {
4282 if ((val & FLASH_BACKUP_STRAP_MASK) ==
4283 (flash->config1 & FLASH_BACKUP_STRAP_MASK)) {
Michael Chanb6016b72005-05-26 13:03:09 -07004284 bp->flash_info = flash;
4285 break;
4286 }
4287 }
4288 }
4289 else {
Michael Chan37137702005-11-04 08:49:17 -08004290 u32 mask;
Michael Chanb6016b72005-05-26 13:03:09 -07004291 /* Not yet been reconfigured */
4292
Michael Chan37137702005-11-04 08:49:17 -08004293 if (val & (1 << 23))
4294 mask = FLASH_BACKUP_STRAP_MASK;
4295 else
4296 mask = FLASH_STRAP_MASK;
4297
Michael Chanb6016b72005-05-26 13:03:09 -07004298 for (j = 0, flash = &flash_table[0]; j < entry_count;
4299 j++, flash++) {
4300
Michael Chan37137702005-11-04 08:49:17 -08004301 if ((val & mask) == (flash->strapping & mask)) {
Michael Chanb6016b72005-05-26 13:03:09 -07004302 bp->flash_info = flash;
4303
4304 /* Request access to the flash interface. */
4305 if ((rc = bnx2_acquire_nvram_lock(bp)) != 0)
4306 return rc;
4307
4308 /* Enable access to flash interface */
4309 bnx2_enable_nvram_access(bp);
4310
4311 /* Reconfigure the flash interface */
4312 REG_WR(bp, BNX2_NVM_CFG1, flash->config1);
4313 REG_WR(bp, BNX2_NVM_CFG2, flash->config2);
4314 REG_WR(bp, BNX2_NVM_CFG3, flash->config3);
4315 REG_WR(bp, BNX2_NVM_WRITE1, flash->write1);
4316
4317 /* Disable access to flash interface */
4318 bnx2_disable_nvram_access(bp);
4319 bnx2_release_nvram_lock(bp);
4320
4321 break;
4322 }
4323 }
4324 } /* if (val & 0x40000000) */
4325
4326 if (j == entry_count) {
4327 bp->flash_info = NULL;
Joe Perches3a9c6a42010-02-17 15:01:51 +00004328 pr_alert("Unknown flash/EEPROM type\n");
Michael Chan1122db72006-01-23 16:11:42 -08004329 return -ENODEV;
Michael Chanb6016b72005-05-26 13:03:09 -07004330 }
4331
Michael Chane30372c2007-07-16 18:26:23 -07004332get_flash_size:
Michael Chan2726d6e2008-01-29 21:35:05 -08004333 val = bnx2_shmem_rd(bp, BNX2_SHARED_HW_CFG_CONFIG2);
Michael Chan1122db72006-01-23 16:11:42 -08004334 val &= BNX2_SHARED_HW_CFG2_NVM_SIZE_MASK;
4335 if (val)
4336 bp->flash_size = val;
4337 else
4338 bp->flash_size = bp->flash_info->total_size;
4339
Michael Chanb6016b72005-05-26 13:03:09 -07004340 return rc;
4341}
4342
4343static int
4344bnx2_nvram_read(struct bnx2 *bp, u32 offset, u8 *ret_buf,
4345 int buf_size)
4346{
4347 int rc = 0;
4348 u32 cmd_flags, offset32, len32, extra;
4349
4350 if (buf_size == 0)
4351 return 0;
4352
4353 /* Request access to the flash interface. */
4354 if ((rc = bnx2_acquire_nvram_lock(bp)) != 0)
4355 return rc;
4356
4357 /* Enable access to flash interface */
4358 bnx2_enable_nvram_access(bp);
4359
4360 len32 = buf_size;
4361 offset32 = offset;
4362 extra = 0;
4363
4364 cmd_flags = 0;
4365
4366 if (offset32 & 3) {
4367 u8 buf[4];
4368 u32 pre_len;
4369
4370 offset32 &= ~3;
4371 pre_len = 4 - (offset & 3);
4372
4373 if (pre_len >= len32) {
4374 pre_len = len32;
4375 cmd_flags = BNX2_NVM_COMMAND_FIRST |
4376 BNX2_NVM_COMMAND_LAST;
4377 }
4378 else {
4379 cmd_flags = BNX2_NVM_COMMAND_FIRST;
4380 }
4381
4382 rc = bnx2_nvram_read_dword(bp, offset32, buf, cmd_flags);
4383
4384 if (rc)
4385 return rc;
4386
4387 memcpy(ret_buf, buf + (offset & 3), pre_len);
4388
4389 offset32 += 4;
4390 ret_buf += pre_len;
4391 len32 -= pre_len;
4392 }
4393 if (len32 & 3) {
4394 extra = 4 - (len32 & 3);
4395 len32 = (len32 + 4) & ~3;
4396 }
4397
4398 if (len32 == 4) {
4399 u8 buf[4];
4400
4401 if (cmd_flags)
4402 cmd_flags = BNX2_NVM_COMMAND_LAST;
4403 else
4404 cmd_flags = BNX2_NVM_COMMAND_FIRST |
4405 BNX2_NVM_COMMAND_LAST;
4406
4407 rc = bnx2_nvram_read_dword(bp, offset32, buf, cmd_flags);
4408
4409 memcpy(ret_buf, buf, 4 - extra);
4410 }
4411 else if (len32 > 0) {
4412 u8 buf[4];
4413
4414 /* Read the first word. */
4415 if (cmd_flags)
4416 cmd_flags = 0;
4417 else
4418 cmd_flags = BNX2_NVM_COMMAND_FIRST;
4419
4420 rc = bnx2_nvram_read_dword(bp, offset32, ret_buf, cmd_flags);
4421
4422 /* Advance to the next dword. */
4423 offset32 += 4;
4424 ret_buf += 4;
4425 len32 -= 4;
4426
4427 while (len32 > 4 && rc == 0) {
4428 rc = bnx2_nvram_read_dword(bp, offset32, ret_buf, 0);
4429
4430 /* Advance to the next dword. */
4431 offset32 += 4;
4432 ret_buf += 4;
4433 len32 -= 4;
4434 }
4435
4436 if (rc)
4437 return rc;
4438
4439 cmd_flags = BNX2_NVM_COMMAND_LAST;
4440 rc = bnx2_nvram_read_dword(bp, offset32, buf, cmd_flags);
4441
4442 memcpy(ret_buf, buf, 4 - extra);
4443 }
4444
4445 /* Disable access to flash interface */
4446 bnx2_disable_nvram_access(bp);
4447
4448 bnx2_release_nvram_lock(bp);
4449
4450 return rc;
4451}
4452
4453static int
4454bnx2_nvram_write(struct bnx2 *bp, u32 offset, u8 *data_buf,
4455 int buf_size)
4456{
4457 u32 written, offset32, len32;
Michael Chane6be7632007-01-08 19:56:13 -08004458 u8 *buf, start[4], end[4], *align_buf = NULL, *flash_buffer = NULL;
Michael Chanb6016b72005-05-26 13:03:09 -07004459 int rc = 0;
4460 int align_start, align_end;
4461
4462 buf = data_buf;
4463 offset32 = offset;
4464 len32 = buf_size;
4465 align_start = align_end = 0;
4466
4467 if ((align_start = (offset32 & 3))) {
4468 offset32 &= ~3;
Michael Chanc8738792007-03-30 14:53:06 -07004469 len32 += align_start;
4470 if (len32 < 4)
4471 len32 = 4;
Michael Chanb6016b72005-05-26 13:03:09 -07004472 if ((rc = bnx2_nvram_read(bp, offset32, start, 4)))
4473 return rc;
4474 }
4475
4476 if (len32 & 3) {
Michael Chanc8738792007-03-30 14:53:06 -07004477 align_end = 4 - (len32 & 3);
4478 len32 += align_end;
4479 if ((rc = bnx2_nvram_read(bp, offset32 + len32 - 4, end, 4)))
4480 return rc;
Michael Chanb6016b72005-05-26 13:03:09 -07004481 }
4482
4483 if (align_start || align_end) {
Michael Chane6be7632007-01-08 19:56:13 -08004484 align_buf = kmalloc(len32, GFP_KERNEL);
4485 if (align_buf == NULL)
Michael Chanb6016b72005-05-26 13:03:09 -07004486 return -ENOMEM;
4487 if (align_start) {
Michael Chane6be7632007-01-08 19:56:13 -08004488 memcpy(align_buf, start, 4);
Michael Chanb6016b72005-05-26 13:03:09 -07004489 }
4490 if (align_end) {
Michael Chane6be7632007-01-08 19:56:13 -08004491 memcpy(align_buf + len32 - 4, end, 4);
Michael Chanb6016b72005-05-26 13:03:09 -07004492 }
Michael Chane6be7632007-01-08 19:56:13 -08004493 memcpy(align_buf + align_start, data_buf, buf_size);
4494 buf = align_buf;
Michael Chanb6016b72005-05-26 13:03:09 -07004495 }
4496
Michael Chane30372c2007-07-16 18:26:23 -07004497 if (!(bp->flash_info->flags & BNX2_NV_BUFFERED)) {
Michael Chanae181bc2006-05-22 16:39:20 -07004498 flash_buffer = kmalloc(264, GFP_KERNEL);
4499 if (flash_buffer == NULL) {
4500 rc = -ENOMEM;
4501 goto nvram_write_end;
4502 }
4503 }
4504
Michael Chanb6016b72005-05-26 13:03:09 -07004505 written = 0;
4506 while ((written < len32) && (rc == 0)) {
4507 u32 page_start, page_end, data_start, data_end;
4508 u32 addr, cmd_flags;
4509 int i;
Michael Chanb6016b72005-05-26 13:03:09 -07004510
4511 /* Find the page_start addr */
4512 page_start = offset32 + written;
4513 page_start -= (page_start % bp->flash_info->page_size);
4514 /* Find the page_end addr */
4515 page_end = page_start + bp->flash_info->page_size;
4516 /* Find the data_start addr */
4517 data_start = (written == 0) ? offset32 : page_start;
4518 /* Find the data_end addr */
Jeff Garzik6aa20a22006-09-13 13:24:59 -04004519 data_end = (page_end > offset32 + len32) ?
Michael Chanb6016b72005-05-26 13:03:09 -07004520 (offset32 + len32) : page_end;
4521
4522 /* Request access to the flash interface. */
4523 if ((rc = bnx2_acquire_nvram_lock(bp)) != 0)
4524 goto nvram_write_end;
4525
4526 /* Enable access to flash interface */
4527 bnx2_enable_nvram_access(bp);
4528
4529 cmd_flags = BNX2_NVM_COMMAND_FIRST;
Michael Chane30372c2007-07-16 18:26:23 -07004530 if (!(bp->flash_info->flags & BNX2_NV_BUFFERED)) {
Michael Chanb6016b72005-05-26 13:03:09 -07004531 int j;
4532
4533 /* Read the whole page into the buffer
4534 * (non-buffer flash only) */
4535 for (j = 0; j < bp->flash_info->page_size; j += 4) {
4536 if (j == (bp->flash_info->page_size - 4)) {
4537 cmd_flags |= BNX2_NVM_COMMAND_LAST;
4538 }
4539 rc = bnx2_nvram_read_dword(bp,
Jeff Garzik6aa20a22006-09-13 13:24:59 -04004540 page_start + j,
4541 &flash_buffer[j],
Michael Chanb6016b72005-05-26 13:03:09 -07004542 cmd_flags);
4543
4544 if (rc)
4545 goto nvram_write_end;
4546
4547 cmd_flags = 0;
4548 }
4549 }
4550
4551 /* Enable writes to flash interface (unlock write-protect) */
4552 if ((rc = bnx2_enable_nvram_write(bp)) != 0)
4553 goto nvram_write_end;
4554
Michael Chanb6016b72005-05-26 13:03:09 -07004555 /* Loop to write back the buffer data from page_start to
4556 * data_start */
4557 i = 0;
Michael Chane30372c2007-07-16 18:26:23 -07004558 if (!(bp->flash_info->flags & BNX2_NV_BUFFERED)) {
Michael Chanc8738792007-03-30 14:53:06 -07004559 /* Erase the page */
4560 if ((rc = bnx2_nvram_erase_page(bp, page_start)) != 0)
4561 goto nvram_write_end;
4562
4563 /* Re-enable the write again for the actual write */
4564 bnx2_enable_nvram_write(bp);
4565
Michael Chanb6016b72005-05-26 13:03:09 -07004566 for (addr = page_start; addr < data_start;
4567 addr += 4, i += 4) {
Jeff Garzik6aa20a22006-09-13 13:24:59 -04004568
Michael Chanb6016b72005-05-26 13:03:09 -07004569 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 /* Loop to write the new data from data_start to data_end */
Michael Chanbae25762006-05-22 16:38:38 -07004580 for (addr = data_start; addr < data_end; addr += 4, i += 4) {
Michael Chanb6016b72005-05-26 13:03:09 -07004581 if ((addr == page_end - 4) ||
Michael Chane30372c2007-07-16 18:26:23 -07004582 ((bp->flash_info->flags & BNX2_NV_BUFFERED) &&
Michael Chanb6016b72005-05-26 13:03:09 -07004583 (addr == data_end - 4))) {
4584
4585 cmd_flags |= BNX2_NVM_COMMAND_LAST;
4586 }
4587 rc = bnx2_nvram_write_dword(bp, addr, buf,
4588 cmd_flags);
4589
4590 if (rc != 0)
4591 goto nvram_write_end;
4592
4593 cmd_flags = 0;
4594 buf += 4;
4595 }
4596
4597 /* Loop to write back the buffer data from data_end
4598 * to page_end */
Michael Chane30372c2007-07-16 18:26:23 -07004599 if (!(bp->flash_info->flags & BNX2_NV_BUFFERED)) {
Michael Chanb6016b72005-05-26 13:03:09 -07004600 for (addr = data_end; addr < page_end;
4601 addr += 4, i += 4) {
Jeff Garzik6aa20a22006-09-13 13:24:59 -04004602
Michael Chanb6016b72005-05-26 13:03:09 -07004603 if (addr == page_end-4) {
4604 cmd_flags = BNX2_NVM_COMMAND_LAST;
4605 }
4606 rc = bnx2_nvram_write_dword(bp, addr,
4607 &flash_buffer[i], cmd_flags);
4608
4609 if (rc != 0)
4610 goto nvram_write_end;
4611
4612 cmd_flags = 0;
4613 }
4614 }
4615
4616 /* Disable writes to flash interface (lock write-protect) */
4617 bnx2_disable_nvram_write(bp);
4618
4619 /* Disable access to flash interface */
4620 bnx2_disable_nvram_access(bp);
4621 bnx2_release_nvram_lock(bp);
4622
4623 /* Increment written */
4624 written += data_end - data_start;
4625 }
4626
4627nvram_write_end:
Michael Chane6be7632007-01-08 19:56:13 -08004628 kfree(flash_buffer);
4629 kfree(align_buf);
Michael Chanb6016b72005-05-26 13:03:09 -07004630 return rc;
4631}
4632
Michael Chan0d8a6572007-07-07 22:49:43 -07004633static void
Michael Chan7c62e832008-07-14 22:39:03 -07004634bnx2_init_fw_cap(struct bnx2 *bp)
Michael Chan0d8a6572007-07-07 22:49:43 -07004635{
Michael Chan7c62e832008-07-14 22:39:03 -07004636 u32 val, sig = 0;
Michael Chan0d8a6572007-07-07 22:49:43 -07004637
Michael Chan583c28e2008-01-21 19:51:35 -08004638 bp->phy_flags &= ~BNX2_PHY_FLAG_REMOTE_PHY_CAP;
Michael Chan7c62e832008-07-14 22:39:03 -07004639 bp->flags &= ~BNX2_FLAG_CAN_KEEP_VLAN;
4640
4641 if (!(bp->flags & BNX2_FLAG_ASF_ENABLE))
4642 bp->flags |= BNX2_FLAG_CAN_KEEP_VLAN;
Michael Chan0d8a6572007-07-07 22:49:43 -07004643
Michael Chan2726d6e2008-01-29 21:35:05 -08004644 val = bnx2_shmem_rd(bp, BNX2_FW_CAP_MB);
Michael Chan0d8a6572007-07-07 22:49:43 -07004645 if ((val & BNX2_FW_CAP_SIGNATURE_MASK) != BNX2_FW_CAP_SIGNATURE)
4646 return;
4647
Michael Chan7c62e832008-07-14 22:39:03 -07004648 if ((val & BNX2_FW_CAP_CAN_KEEP_VLAN) == BNX2_FW_CAP_CAN_KEEP_VLAN) {
4649 bp->flags |= BNX2_FLAG_CAN_KEEP_VLAN;
4650 sig |= BNX2_DRV_ACK_CAP_SIGNATURE | BNX2_FW_CAP_CAN_KEEP_VLAN;
4651 }
4652
4653 if ((bp->phy_flags & BNX2_PHY_FLAG_SERDES) &&
4654 (val & BNX2_FW_CAP_REMOTE_PHY_CAPABLE)) {
4655 u32 link;
4656
Michael Chan583c28e2008-01-21 19:51:35 -08004657 bp->phy_flags |= BNX2_PHY_FLAG_REMOTE_PHY_CAP;
Michael Chan0d8a6572007-07-07 22:49:43 -07004658
Michael Chan7c62e832008-07-14 22:39:03 -07004659 link = bnx2_shmem_rd(bp, BNX2_LINK_STATUS);
4660 if (link & BNX2_LINK_STATUS_SERDES_LINK)
Michael Chan0d8a6572007-07-07 22:49:43 -07004661 bp->phy_port = PORT_FIBRE;
4662 else
4663 bp->phy_port = PORT_TP;
Michael Chan489310a2007-10-10 16:16:31 -07004664
Michael Chan7c62e832008-07-14 22:39:03 -07004665 sig |= BNX2_DRV_ACK_CAP_SIGNATURE |
4666 BNX2_FW_CAP_REMOTE_PHY_CAPABLE;
Michael Chan0d8a6572007-07-07 22:49:43 -07004667 }
Michael Chan7c62e832008-07-14 22:39:03 -07004668
4669 if (netif_running(bp->dev) && sig)
4670 bnx2_shmem_wr(bp, BNX2_DRV_ACK_CAP_MB, sig);
Michael Chan0d8a6572007-07-07 22:49:43 -07004671}
4672
Michael Chanb4b36042007-12-20 19:59:30 -08004673static void
4674bnx2_setup_msix_tbl(struct bnx2 *bp)
4675{
4676 REG_WR(bp, BNX2_PCI_GRC_WINDOW_ADDR, BNX2_PCI_GRC_WINDOW_ADDR_SEP_WIN);
4677
4678 REG_WR(bp, BNX2_PCI_GRC_WINDOW2_ADDR, BNX2_MSIX_TABLE_ADDR);
4679 REG_WR(bp, BNX2_PCI_GRC_WINDOW3_ADDR, BNX2_MSIX_PBA_ADDR);
4680}
4681
Michael Chanb6016b72005-05-26 13:03:09 -07004682static int
4683bnx2_reset_chip(struct bnx2 *bp, u32 reset_code)
4684{
4685 u32 val;
4686 int i, rc = 0;
Michael Chan489310a2007-10-10 16:16:31 -07004687 u8 old_port;
Michael Chanb6016b72005-05-26 13:03:09 -07004688
4689 /* Wait for the current PCI transaction to complete before
4690 * issuing a reset. */
Eddie Waia5dac102010-11-24 13:48:54 +00004691 if ((CHIP_NUM(bp) == CHIP_NUM_5706) ||
4692 (CHIP_NUM(bp) == CHIP_NUM_5708)) {
4693 REG_WR(bp, BNX2_MISC_ENABLE_CLR_BITS,
4694 BNX2_MISC_ENABLE_CLR_BITS_TX_DMA_ENABLE |
4695 BNX2_MISC_ENABLE_CLR_BITS_DMA_ENGINE_ENABLE |
4696 BNX2_MISC_ENABLE_CLR_BITS_RX_DMA_ENABLE |
4697 BNX2_MISC_ENABLE_CLR_BITS_HOST_COALESCE_ENABLE);
4698 val = REG_RD(bp, BNX2_MISC_ENABLE_CLR_BITS);
4699 udelay(5);
4700 } else { /* 5709 */
4701 val = REG_RD(bp, BNX2_MISC_NEW_CORE_CTL);
4702 val &= ~BNX2_MISC_NEW_CORE_CTL_DMA_ENABLE;
4703 REG_WR(bp, BNX2_MISC_NEW_CORE_CTL, val);
4704 val = REG_RD(bp, BNX2_MISC_NEW_CORE_CTL);
4705
4706 for (i = 0; i < 100; i++) {
4707 msleep(1);
4708 val = REG_RD(bp, BNX2_PCICFG_DEVICE_CONTROL);
4709 if (!(val & BNX2_PCICFG_DEVICE_STATUS_NO_PEND))
4710 break;
4711 }
4712 }
Michael Chanb6016b72005-05-26 13:03:09 -07004713
Michael Chanb090ae22006-01-23 16:07:10 -08004714 /* Wait for the firmware to tell us it is ok to issue a reset. */
Michael Chana2f13892008-07-14 22:38:23 -07004715 bnx2_fw_sync(bp, BNX2_DRV_MSG_DATA_WAIT0 | reset_code, 1, 1);
Michael Chanb090ae22006-01-23 16:07:10 -08004716
Michael Chanb6016b72005-05-26 13:03:09 -07004717 /* Deposit a driver reset signature so the firmware knows that
4718 * this is a soft reset. */
Michael Chan2726d6e2008-01-29 21:35:05 -08004719 bnx2_shmem_wr(bp, BNX2_DRV_RESET_SIGNATURE,
4720 BNX2_DRV_RESET_SIGNATURE_MAGIC);
Michael Chanb6016b72005-05-26 13:03:09 -07004721
Michael Chanb6016b72005-05-26 13:03:09 -07004722 /* Do a dummy read to force the chip to complete all current transaction
4723 * before we issue a reset. */
4724 val = REG_RD(bp, BNX2_MISC_ID);
4725
Michael Chan234754d2006-11-19 14:11:41 -08004726 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
4727 REG_WR(bp, BNX2_MISC_COMMAND, BNX2_MISC_COMMAND_SW_RESET);
4728 REG_RD(bp, BNX2_MISC_COMMAND);
4729 udelay(5);
Michael Chanb6016b72005-05-26 13:03:09 -07004730
Michael Chan234754d2006-11-19 14:11:41 -08004731 val = BNX2_PCICFG_MISC_CONFIG_REG_WINDOW_ENA |
4732 BNX2_PCICFG_MISC_CONFIG_TARGET_MB_WORD_SWAP;
Michael Chanb6016b72005-05-26 13:03:09 -07004733
Michael Chanbe7ff1a2010-11-24 13:48:55 +00004734 REG_WR(bp, BNX2_PCICFG_MISC_CONFIG, val);
Michael Chanb6016b72005-05-26 13:03:09 -07004735
Michael Chan234754d2006-11-19 14:11:41 -08004736 } else {
4737 val = BNX2_PCICFG_MISC_CONFIG_CORE_RST_REQ |
4738 BNX2_PCICFG_MISC_CONFIG_REG_WINDOW_ENA |
4739 BNX2_PCICFG_MISC_CONFIG_TARGET_MB_WORD_SWAP;
4740
4741 /* Chip reset. */
4742 REG_WR(bp, BNX2_PCICFG_MISC_CONFIG, val);
4743
Michael Chan594a9df2007-08-28 15:39:42 -07004744 /* Reading back any register after chip reset will hang the
4745 * bus on 5706 A0 and A1. The msleep below provides plenty
4746 * of margin for write posting.
4747 */
Michael Chan234754d2006-11-19 14:11:41 -08004748 if ((CHIP_ID(bp) == CHIP_ID_5706_A0) ||
Arjan van de Ven8e545882007-08-28 14:34:43 -07004749 (CHIP_ID(bp) == CHIP_ID_5706_A1))
4750 msleep(20);
Michael Chanb6016b72005-05-26 13:03:09 -07004751
Michael Chan234754d2006-11-19 14:11:41 -08004752 /* Reset takes approximate 30 usec */
4753 for (i = 0; i < 10; i++) {
4754 val = REG_RD(bp, BNX2_PCICFG_MISC_CONFIG);
4755 if ((val & (BNX2_PCICFG_MISC_CONFIG_CORE_RST_REQ |
4756 BNX2_PCICFG_MISC_CONFIG_CORE_RST_BSY)) == 0)
4757 break;
4758 udelay(10);
4759 }
4760
4761 if (val & (BNX2_PCICFG_MISC_CONFIG_CORE_RST_REQ |
4762 BNX2_PCICFG_MISC_CONFIG_CORE_RST_BSY)) {
Joe Perches3a9c6a42010-02-17 15:01:51 +00004763 pr_err("Chip reset did not complete\n");
Michael Chan234754d2006-11-19 14:11:41 -08004764 return -EBUSY;
4765 }
Michael Chanb6016b72005-05-26 13:03:09 -07004766 }
4767
4768 /* Make sure byte swapping is properly configured. */
4769 val = REG_RD(bp, BNX2_PCI_SWAP_DIAG0);
4770 if (val != 0x01020304) {
Joe Perches3a9c6a42010-02-17 15:01:51 +00004771 pr_err("Chip not in correct endian mode\n");
Michael Chanb6016b72005-05-26 13:03:09 -07004772 return -ENODEV;
4773 }
4774
Michael Chanb6016b72005-05-26 13:03:09 -07004775 /* Wait for the firmware to finish its initialization. */
Michael Chana2f13892008-07-14 22:38:23 -07004776 rc = bnx2_fw_sync(bp, BNX2_DRV_MSG_DATA_WAIT1 | reset_code, 1, 0);
Michael Chanb090ae22006-01-23 16:07:10 -08004777 if (rc)
4778 return rc;
Michael Chanb6016b72005-05-26 13:03:09 -07004779
Michael Chan0d8a6572007-07-07 22:49:43 -07004780 spin_lock_bh(&bp->phy_lock);
Michael Chan489310a2007-10-10 16:16:31 -07004781 old_port = bp->phy_port;
Michael Chan7c62e832008-07-14 22:39:03 -07004782 bnx2_init_fw_cap(bp);
Michael Chan583c28e2008-01-21 19:51:35 -08004783 if ((bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP) &&
4784 old_port != bp->phy_port)
Michael Chan0d8a6572007-07-07 22:49:43 -07004785 bnx2_set_default_remote_link(bp);
4786 spin_unlock_bh(&bp->phy_lock);
4787
Michael Chanb6016b72005-05-26 13:03:09 -07004788 if (CHIP_ID(bp) == CHIP_ID_5706_A0) {
4789 /* Adjust the voltage regular to two steps lower. The default
4790 * of this register is 0x0000000e. */
4791 REG_WR(bp, BNX2_MISC_VREG_CONTROL, 0x000000fa);
4792
4793 /* Remove bad rbuf memory from the free pool. */
4794 rc = bnx2_alloc_bad_rbuf(bp);
4795 }
4796
Michael Chanc441b8d2010-04-27 11:28:09 +00004797 if (bp->flags & BNX2_FLAG_USING_MSIX) {
Michael Chanb4b36042007-12-20 19:59:30 -08004798 bnx2_setup_msix_tbl(bp);
Michael Chanc441b8d2010-04-27 11:28:09 +00004799 /* Prevent MSIX table reads and write from timing out */
4800 REG_WR(bp, BNX2_MISC_ECO_HW_CTL,
4801 BNX2_MISC_ECO_HW_CTL_LARGE_GRC_TMOUT_EN);
4802 }
Michael Chanb4b36042007-12-20 19:59:30 -08004803
Michael Chanb6016b72005-05-26 13:03:09 -07004804 return rc;
4805}
4806
4807static int
4808bnx2_init_chip(struct bnx2 *bp)
4809{
Michael Chand8026d92008-11-12 16:02:20 -08004810 u32 val, mtu;
Michael Chanb4b36042007-12-20 19:59:30 -08004811 int rc, i;
Michael Chanb6016b72005-05-26 13:03:09 -07004812
4813 /* Make sure the interrupt is not active. */
4814 REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD, BNX2_PCICFG_INT_ACK_CMD_MASK_INT);
4815
4816 val = BNX2_DMA_CONFIG_DATA_BYTE_SWAP |
4817 BNX2_DMA_CONFIG_DATA_WORD_SWAP |
4818#ifdef __BIG_ENDIAN
Jeff Garzik6aa20a22006-09-13 13:24:59 -04004819 BNX2_DMA_CONFIG_CNTL_BYTE_SWAP |
Michael Chanb6016b72005-05-26 13:03:09 -07004820#endif
Jeff Garzik6aa20a22006-09-13 13:24:59 -04004821 BNX2_DMA_CONFIG_CNTL_WORD_SWAP |
Michael Chanb6016b72005-05-26 13:03:09 -07004822 DMA_READ_CHANS << 12 |
4823 DMA_WRITE_CHANS << 16;
4824
4825 val |= (0x2 << 20) | (1 << 11);
4826
David S. Millerf86e82f2008-01-21 17:15:40 -08004827 if ((bp->flags & BNX2_FLAG_PCIX) && (bp->bus_speed_mhz == 133))
Michael Chanb6016b72005-05-26 13:03:09 -07004828 val |= (1 << 23);
4829
4830 if ((CHIP_NUM(bp) == CHIP_NUM_5706) &&
David S. Millerf86e82f2008-01-21 17:15:40 -08004831 (CHIP_ID(bp) != CHIP_ID_5706_A0) && !(bp->flags & BNX2_FLAG_PCIX))
Michael Chanb6016b72005-05-26 13:03:09 -07004832 val |= BNX2_DMA_CONFIG_CNTL_PING_PONG_DMA;
4833
4834 REG_WR(bp, BNX2_DMA_CONFIG, val);
4835
4836 if (CHIP_ID(bp) == CHIP_ID_5706_A0) {
4837 val = REG_RD(bp, BNX2_TDMA_CONFIG);
4838 val |= BNX2_TDMA_CONFIG_ONE_DMA;
4839 REG_WR(bp, BNX2_TDMA_CONFIG, val);
4840 }
4841
David S. Millerf86e82f2008-01-21 17:15:40 -08004842 if (bp->flags & BNX2_FLAG_PCIX) {
Michael Chanb6016b72005-05-26 13:03:09 -07004843 u16 val16;
4844
4845 pci_read_config_word(bp->pdev, bp->pcix_cap + PCI_X_CMD,
4846 &val16);
4847 pci_write_config_word(bp->pdev, bp->pcix_cap + PCI_X_CMD,
4848 val16 & ~PCI_X_CMD_ERO);
4849 }
4850
4851 REG_WR(bp, BNX2_MISC_ENABLE_SET_BITS,
4852 BNX2_MISC_ENABLE_SET_BITS_HOST_COALESCE_ENABLE |
4853 BNX2_MISC_ENABLE_STATUS_BITS_RX_V2P_ENABLE |
4854 BNX2_MISC_ENABLE_STATUS_BITS_CONTEXT_ENABLE);
4855
4856 /* Initialize context mapping and zero out the quick contexts. The
4857 * context block must have already been enabled. */
Michael Chan641bdcd2007-06-04 21:22:24 -07004858 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
4859 rc = bnx2_init_5709_context(bp);
4860 if (rc)
4861 return rc;
4862 } else
Michael Chan59b47d82006-11-19 14:10:45 -08004863 bnx2_init_context(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07004864
Michael Chanfba9fe92006-06-12 22:21:25 -07004865 if ((rc = bnx2_init_cpus(bp)) != 0)
4866 return rc;
4867
Michael Chanb6016b72005-05-26 13:03:09 -07004868 bnx2_init_nvram(bp);
4869
Benjamin Li5fcaed02008-07-14 22:39:52 -07004870 bnx2_set_mac_addr(bp, bp->dev->dev_addr, 0);
Michael Chanb6016b72005-05-26 13:03:09 -07004871
4872 val = REG_RD(bp, BNX2_MQ_CONFIG);
4873 val &= ~BNX2_MQ_CONFIG_KNL_BYP_BLK_SIZE;
4874 val |= BNX2_MQ_CONFIG_KNL_BYP_BLK_SIZE_256;
Michael Chan4edd4732009-06-08 18:14:42 -07004875 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
4876 val |= BNX2_MQ_CONFIG_BIN_MQ_MODE;
4877 if (CHIP_REV(bp) == CHIP_REV_Ax)
4878 val |= BNX2_MQ_CONFIG_HALT_DIS;
4879 }
Michael Chan68c9f752007-04-24 15:35:53 -07004880
Michael Chanb6016b72005-05-26 13:03:09 -07004881 REG_WR(bp, BNX2_MQ_CONFIG, val);
4882
4883 val = 0x10000 + (MAX_CID_CNT * MB_KERNEL_CTX_SIZE);
4884 REG_WR(bp, BNX2_MQ_KNL_BYP_WIND_START, val);
4885 REG_WR(bp, BNX2_MQ_KNL_WIND_END, val);
4886
4887 val = (BCM_PAGE_BITS - 8) << 24;
4888 REG_WR(bp, BNX2_RV2P_CONFIG, val);
4889
4890 /* Configure page size. */
4891 val = REG_RD(bp, BNX2_TBDR_CONFIG);
4892 val &= ~BNX2_TBDR_CONFIG_PAGE_SIZE;
4893 val |= (BCM_PAGE_BITS - 8) << 24 | 0x40;
4894 REG_WR(bp, BNX2_TBDR_CONFIG, val);
4895
4896 val = bp->mac_addr[0] +
4897 (bp->mac_addr[1] << 8) +
4898 (bp->mac_addr[2] << 16) +
4899 bp->mac_addr[3] +
4900 (bp->mac_addr[4] << 8) +
4901 (bp->mac_addr[5] << 16);
4902 REG_WR(bp, BNX2_EMAC_BACKOFF_SEED, val);
4903
4904 /* Program the MTU. Also include 4 bytes for CRC32. */
Michael Chand8026d92008-11-12 16:02:20 -08004905 mtu = bp->dev->mtu;
4906 val = mtu + ETH_HLEN + ETH_FCS_LEN;
Michael Chanb6016b72005-05-26 13:03:09 -07004907 if (val > (MAX_ETHERNET_PACKET_SIZE + 4))
4908 val |= BNX2_EMAC_RX_MTU_SIZE_JUMBO_ENA;
4909 REG_WR(bp, BNX2_EMAC_RX_MTU_SIZE, val);
4910
Michael Chand8026d92008-11-12 16:02:20 -08004911 if (mtu < 1500)
4912 mtu = 1500;
4913
4914 bnx2_reg_wr_ind(bp, BNX2_RBUF_CONFIG, BNX2_RBUF_CONFIG_VAL(mtu));
4915 bnx2_reg_wr_ind(bp, BNX2_RBUF_CONFIG2, BNX2_RBUF_CONFIG2_VAL(mtu));
4916 bnx2_reg_wr_ind(bp, BNX2_RBUF_CONFIG3, BNX2_RBUF_CONFIG3_VAL(mtu));
4917
Michael Chan155d5562009-08-21 16:20:43 +00004918 memset(bp->bnx2_napi[0].status_blk.msi, 0, bp->status_stats_size);
Michael Chanb4b36042007-12-20 19:59:30 -08004919 for (i = 0; i < BNX2_MAX_MSIX_VEC; i++)
4920 bp->bnx2_napi[i].last_status_idx = 0;
4921
Michael Chanefba0182008-12-03 00:36:15 -08004922 bp->idle_chk_status_idx = 0xffff;
4923
Michael Chanb6016b72005-05-26 13:03:09 -07004924 bp->rx_mode = BNX2_EMAC_RX_MODE_SORT_MODE;
4925
4926 /* Set up how to generate a link change interrupt. */
4927 REG_WR(bp, BNX2_EMAC_ATTENTION_ENA, BNX2_EMAC_ATTENTION_ENA_LINK);
4928
4929 REG_WR(bp, BNX2_HC_STATUS_ADDR_L,
4930 (u64) bp->status_blk_mapping & 0xffffffff);
4931 REG_WR(bp, BNX2_HC_STATUS_ADDR_H, (u64) bp->status_blk_mapping >> 32);
4932
4933 REG_WR(bp, BNX2_HC_STATISTICS_ADDR_L,
4934 (u64) bp->stats_blk_mapping & 0xffffffff);
4935 REG_WR(bp, BNX2_HC_STATISTICS_ADDR_H,
4936 (u64) bp->stats_blk_mapping >> 32);
4937
Jeff Garzik6aa20a22006-09-13 13:24:59 -04004938 REG_WR(bp, BNX2_HC_TX_QUICK_CONS_TRIP,
Michael Chanb6016b72005-05-26 13:03:09 -07004939 (bp->tx_quick_cons_trip_int << 16) | bp->tx_quick_cons_trip);
4940
4941 REG_WR(bp, BNX2_HC_RX_QUICK_CONS_TRIP,
4942 (bp->rx_quick_cons_trip_int << 16) | bp->rx_quick_cons_trip);
4943
4944 REG_WR(bp, BNX2_HC_COMP_PROD_TRIP,
4945 (bp->comp_prod_trip_int << 16) | bp->comp_prod_trip);
4946
4947 REG_WR(bp, BNX2_HC_TX_TICKS, (bp->tx_ticks_int << 16) | bp->tx_ticks);
4948
4949 REG_WR(bp, BNX2_HC_RX_TICKS, (bp->rx_ticks_int << 16) | bp->rx_ticks);
4950
4951 REG_WR(bp, BNX2_HC_COM_TICKS,
4952 (bp->com_ticks_int << 16) | bp->com_ticks);
4953
4954 REG_WR(bp, BNX2_HC_CMD_TICKS,
4955 (bp->cmd_ticks_int << 16) | bp->cmd_ticks);
4956
Michael Chan61d9e3f2009-08-21 16:20:46 +00004957 if (bp->flags & BNX2_FLAG_BROKEN_STATS)
Michael Chan02537b062007-06-04 21:24:07 -07004958 REG_WR(bp, BNX2_HC_STATS_TICKS, 0);
4959 else
Michael Chan7ea69202007-07-16 18:27:10 -07004960 REG_WR(bp, BNX2_HC_STATS_TICKS, bp->stats_ticks);
Michael Chanb6016b72005-05-26 13:03:09 -07004961 REG_WR(bp, BNX2_HC_STAT_COLLECT_TICKS, 0xbb8); /* 3ms */
4962
4963 if (CHIP_ID(bp) == CHIP_ID_5706_A1)
Michael Chan8e6a72c2007-05-03 13:24:48 -07004964 val = BNX2_HC_CONFIG_COLLECT_STATS;
Michael Chanb6016b72005-05-26 13:03:09 -07004965 else {
Michael Chan8e6a72c2007-05-03 13:24:48 -07004966 val = BNX2_HC_CONFIG_RX_TMR_MODE | BNX2_HC_CONFIG_TX_TMR_MODE |
4967 BNX2_HC_CONFIG_COLLECT_STATS;
Michael Chanb6016b72005-05-26 13:03:09 -07004968 }
4969
Michael Chanefde73a2010-02-15 19:42:07 +00004970 if (bp->flags & BNX2_FLAG_USING_MSIX) {
Michael Chanc76c0472007-12-20 20:01:19 -08004971 REG_WR(bp, BNX2_HC_MSIX_BIT_VECTOR,
4972 BNX2_HC_MSIX_BIT_VECTOR_VAL);
4973
Michael Chan5e9ad9e2008-06-19 16:43:17 -07004974 val |= BNX2_HC_CONFIG_SB_ADDR_INC_128B;
4975 }
4976
4977 if (bp->flags & BNX2_FLAG_ONE_SHOT_MSI)
Michael Chancf7474a2009-08-21 16:20:48 +00004978 val |= BNX2_HC_CONFIG_ONE_SHOT | BNX2_HC_CONFIG_USE_INT_PARAM;
Michael Chan5e9ad9e2008-06-19 16:43:17 -07004979
4980 REG_WR(bp, BNX2_HC_CONFIG, val);
4981
Michael Chan22fa1592010-10-11 16:12:00 -07004982 if (bp->rx_ticks < 25)
4983 bnx2_reg_wr_ind(bp, BNX2_FW_RX_LOW_LATENCY, 1);
4984 else
4985 bnx2_reg_wr_ind(bp, BNX2_FW_RX_LOW_LATENCY, 0);
4986
Michael Chan5e9ad9e2008-06-19 16:43:17 -07004987 for (i = 1; i < bp->irq_nvecs; i++) {
4988 u32 base = ((i - 1) * BNX2_HC_SB_CONFIG_SIZE) +
4989 BNX2_HC_SB_CONFIG_1;
4990
Michael Chan6f743ca2008-01-29 21:34:08 -08004991 REG_WR(bp, base,
Michael Chanc76c0472007-12-20 20:01:19 -08004992 BNX2_HC_SB_CONFIG_1_TX_TMR_MODE |
Michael Chan5e9ad9e2008-06-19 16:43:17 -07004993 BNX2_HC_SB_CONFIG_1_RX_TMR_MODE |
Michael Chanc76c0472007-12-20 20:01:19 -08004994 BNX2_HC_SB_CONFIG_1_ONE_SHOT);
4995
Michael Chan6f743ca2008-01-29 21:34:08 -08004996 REG_WR(bp, base + BNX2_HC_TX_QUICK_CONS_TRIP_OFF,
Michael Chanc76c0472007-12-20 20:01:19 -08004997 (bp->tx_quick_cons_trip_int << 16) |
4998 bp->tx_quick_cons_trip);
4999
Michael Chan6f743ca2008-01-29 21:34:08 -08005000 REG_WR(bp, base + BNX2_HC_TX_TICKS_OFF,
Michael Chanc76c0472007-12-20 20:01:19 -08005001 (bp->tx_ticks_int << 16) | bp->tx_ticks);
5002
Michael Chan5e9ad9e2008-06-19 16:43:17 -07005003 REG_WR(bp, base + BNX2_HC_RX_QUICK_CONS_TRIP_OFF,
5004 (bp->rx_quick_cons_trip_int << 16) |
5005 bp->rx_quick_cons_trip);
5006
5007 REG_WR(bp, base + BNX2_HC_RX_TICKS_OFF,
5008 (bp->rx_ticks_int << 16) | bp->rx_ticks);
Michael Chanc76c0472007-12-20 20:01:19 -08005009 }
5010
Michael Chanb6016b72005-05-26 13:03:09 -07005011 /* Clear internal stats counters. */
5012 REG_WR(bp, BNX2_HC_COMMAND, BNX2_HC_COMMAND_CLR_STAT_NOW);
5013
Michael Chanda3e4fb2007-05-03 13:24:23 -07005014 REG_WR(bp, BNX2_HC_ATTN_BITS_ENABLE, STATUS_ATTN_EVENTS);
Michael Chanb6016b72005-05-26 13:03:09 -07005015
5016 /* Initialize the receive filter. */
5017 bnx2_set_rx_mode(bp->dev);
5018
Michael Chan0aa38df2007-06-04 21:23:06 -07005019 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
5020 val = REG_RD(bp, BNX2_MISC_NEW_CORE_CTL);
5021 val |= BNX2_MISC_NEW_CORE_CTL_DMA_ENABLE;
5022 REG_WR(bp, BNX2_MISC_NEW_CORE_CTL, val);
5023 }
Michael Chanb090ae22006-01-23 16:07:10 -08005024 rc = bnx2_fw_sync(bp, BNX2_DRV_MSG_DATA_WAIT2 | BNX2_DRV_MSG_CODE_RESET,
Michael Chana2f13892008-07-14 22:38:23 -07005025 1, 0);
Michael Chanb6016b72005-05-26 13:03:09 -07005026
Michael Chandf149d72007-07-07 22:51:36 -07005027 REG_WR(bp, BNX2_MISC_ENABLE_SET_BITS, BNX2_MISC_ENABLE_DEFAULT);
Michael Chanb6016b72005-05-26 13:03:09 -07005028 REG_RD(bp, BNX2_MISC_ENABLE_SET_BITS);
5029
5030 udelay(20);
5031
Michael Chanbf5295b2006-03-23 01:11:56 -08005032 bp->hc_cmd = REG_RD(bp, BNX2_HC_COMMAND);
5033
Michael Chanb090ae22006-01-23 16:07:10 -08005034 return rc;
Michael Chanb6016b72005-05-26 13:03:09 -07005035}
5036
Michael Chan59b47d82006-11-19 14:10:45 -08005037static void
Michael Chanc76c0472007-12-20 20:01:19 -08005038bnx2_clear_ring_states(struct bnx2 *bp)
5039{
5040 struct bnx2_napi *bnapi;
Michael Chan35e90102008-06-19 16:37:42 -07005041 struct bnx2_tx_ring_info *txr;
Michael Chanbb4f98a2008-06-19 16:38:19 -07005042 struct bnx2_rx_ring_info *rxr;
Michael Chanc76c0472007-12-20 20:01:19 -08005043 int i;
5044
5045 for (i = 0; i < BNX2_MAX_MSIX_VEC; i++) {
5046 bnapi = &bp->bnx2_napi[i];
Michael Chan35e90102008-06-19 16:37:42 -07005047 txr = &bnapi->tx_ring;
Michael Chanbb4f98a2008-06-19 16:38:19 -07005048 rxr = &bnapi->rx_ring;
Michael Chanc76c0472007-12-20 20:01:19 -08005049
Michael Chan35e90102008-06-19 16:37:42 -07005050 txr->tx_cons = 0;
5051 txr->hw_tx_cons = 0;
Michael Chanbb4f98a2008-06-19 16:38:19 -07005052 rxr->rx_prod_bseq = 0;
5053 rxr->rx_prod = 0;
5054 rxr->rx_cons = 0;
5055 rxr->rx_pg_prod = 0;
5056 rxr->rx_pg_cons = 0;
Michael Chanc76c0472007-12-20 20:01:19 -08005057 }
5058}
5059
5060static void
Michael Chan35e90102008-06-19 16:37:42 -07005061bnx2_init_tx_context(struct bnx2 *bp, u32 cid, struct bnx2_tx_ring_info *txr)
Michael Chan59b47d82006-11-19 14:10:45 -08005062{
5063 u32 val, offset0, offset1, offset2, offset3;
Michael Chan62a83132008-01-29 21:35:40 -08005064 u32 cid_addr = GET_CID_ADDR(cid);
Michael Chan59b47d82006-11-19 14:10:45 -08005065
5066 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
5067 offset0 = BNX2_L2CTX_TYPE_XI;
5068 offset1 = BNX2_L2CTX_CMD_TYPE_XI;
5069 offset2 = BNX2_L2CTX_TBDR_BHADDR_HI_XI;
5070 offset3 = BNX2_L2CTX_TBDR_BHADDR_LO_XI;
5071 } else {
5072 offset0 = BNX2_L2CTX_TYPE;
5073 offset1 = BNX2_L2CTX_CMD_TYPE;
5074 offset2 = BNX2_L2CTX_TBDR_BHADDR_HI;
5075 offset3 = BNX2_L2CTX_TBDR_BHADDR_LO;
5076 }
5077 val = BNX2_L2CTX_TYPE_TYPE_L2 | BNX2_L2CTX_TYPE_SIZE_L2;
Michael Chan62a83132008-01-29 21:35:40 -08005078 bnx2_ctx_wr(bp, cid_addr, offset0, val);
Michael Chan59b47d82006-11-19 14:10:45 -08005079
5080 val = BNX2_L2CTX_CMD_TYPE_TYPE_L2 | (8 << 16);
Michael Chan62a83132008-01-29 21:35:40 -08005081 bnx2_ctx_wr(bp, cid_addr, offset1, val);
Michael Chan59b47d82006-11-19 14:10:45 -08005082
Michael Chan35e90102008-06-19 16:37:42 -07005083 val = (u64) txr->tx_desc_mapping >> 32;
Michael Chan62a83132008-01-29 21:35:40 -08005084 bnx2_ctx_wr(bp, cid_addr, offset2, val);
Michael Chan59b47d82006-11-19 14:10:45 -08005085
Michael Chan35e90102008-06-19 16:37:42 -07005086 val = (u64) txr->tx_desc_mapping & 0xffffffff;
Michael Chan62a83132008-01-29 21:35:40 -08005087 bnx2_ctx_wr(bp, cid_addr, offset3, val);
Michael Chan59b47d82006-11-19 14:10:45 -08005088}
Michael Chanb6016b72005-05-26 13:03:09 -07005089
5090static void
Michael Chan35e90102008-06-19 16:37:42 -07005091bnx2_init_tx_ring(struct bnx2 *bp, int ring_num)
Michael Chanb6016b72005-05-26 13:03:09 -07005092{
5093 struct tx_bd *txbd;
Michael Chanc76c0472007-12-20 20:01:19 -08005094 u32 cid = TX_CID;
5095 struct bnx2_napi *bnapi;
Michael Chan35e90102008-06-19 16:37:42 -07005096 struct bnx2_tx_ring_info *txr;
Michael Chanc76c0472007-12-20 20:01:19 -08005097
Michael Chan35e90102008-06-19 16:37:42 -07005098 bnapi = &bp->bnx2_napi[ring_num];
5099 txr = &bnapi->tx_ring;
5100
5101 if (ring_num == 0)
5102 cid = TX_CID;
5103 else
5104 cid = TX_TSS_CID + ring_num - 1;
Michael Chanb6016b72005-05-26 13:03:09 -07005105
Michael Chan2f8af122006-08-15 01:39:10 -07005106 bp->tx_wake_thresh = bp->tx_ring_size / 2;
5107
Michael Chan35e90102008-06-19 16:37:42 -07005108 txbd = &txr->tx_desc_ring[MAX_TX_DESC_CNT];
Jeff Garzik6aa20a22006-09-13 13:24:59 -04005109
Michael Chan35e90102008-06-19 16:37:42 -07005110 txbd->tx_bd_haddr_hi = (u64) txr->tx_desc_mapping >> 32;
5111 txbd->tx_bd_haddr_lo = (u64) txr->tx_desc_mapping & 0xffffffff;
Michael Chanb6016b72005-05-26 13:03:09 -07005112
Michael Chan35e90102008-06-19 16:37:42 -07005113 txr->tx_prod = 0;
5114 txr->tx_prod_bseq = 0;
Jeff Garzik6aa20a22006-09-13 13:24:59 -04005115
Michael Chan35e90102008-06-19 16:37:42 -07005116 txr->tx_bidx_addr = MB_GET_CID_ADDR(cid) + BNX2_L2CTX_TX_HOST_BIDX;
5117 txr->tx_bseq_addr = MB_GET_CID_ADDR(cid) + BNX2_L2CTX_TX_HOST_BSEQ;
Michael Chanb6016b72005-05-26 13:03:09 -07005118
Michael Chan35e90102008-06-19 16:37:42 -07005119 bnx2_init_tx_context(bp, cid, txr);
Michael Chanb6016b72005-05-26 13:03:09 -07005120}
5121
5122static void
Michael Chan5d5d0012007-12-12 11:17:43 -08005123bnx2_init_rxbd_rings(struct rx_bd *rx_ring[], dma_addr_t dma[], u32 buf_size,
5124 int num_rings)
Michael Chanb6016b72005-05-26 13:03:09 -07005125{
Michael Chanb6016b72005-05-26 13:03:09 -07005126 int i;
Michael Chan5d5d0012007-12-12 11:17:43 -08005127 struct rx_bd *rxbd;
Michael Chanb6016b72005-05-26 13:03:09 -07005128
Michael Chan5d5d0012007-12-12 11:17:43 -08005129 for (i = 0; i < num_rings; i++) {
Michael Chan13daffa2006-03-20 17:49:20 -08005130 int j;
Michael Chanb6016b72005-05-26 13:03:09 -07005131
Michael Chan5d5d0012007-12-12 11:17:43 -08005132 rxbd = &rx_ring[i][0];
Michael Chan13daffa2006-03-20 17:49:20 -08005133 for (j = 0; j < MAX_RX_DESC_CNT; j++, rxbd++) {
Michael Chan5d5d0012007-12-12 11:17:43 -08005134 rxbd->rx_bd_len = buf_size;
Michael Chan13daffa2006-03-20 17:49:20 -08005135 rxbd->rx_bd_flags = RX_BD_FLAGS_START | RX_BD_FLAGS_END;
5136 }
Michael Chan5d5d0012007-12-12 11:17:43 -08005137 if (i == (num_rings - 1))
Michael Chan13daffa2006-03-20 17:49:20 -08005138 j = 0;
5139 else
5140 j = i + 1;
Michael Chan5d5d0012007-12-12 11:17:43 -08005141 rxbd->rx_bd_haddr_hi = (u64) dma[j] >> 32;
5142 rxbd->rx_bd_haddr_lo = (u64) dma[j] & 0xffffffff;
Michael Chan13daffa2006-03-20 17:49:20 -08005143 }
Michael Chan5d5d0012007-12-12 11:17:43 -08005144}
5145
5146static void
Michael Chanbb4f98a2008-06-19 16:38:19 -07005147bnx2_init_rx_ring(struct bnx2 *bp, int ring_num)
Michael Chan5d5d0012007-12-12 11:17:43 -08005148{
5149 int i;
5150 u16 prod, ring_prod;
Michael Chanbb4f98a2008-06-19 16:38:19 -07005151 u32 cid, rx_cid_addr, val;
5152 struct bnx2_napi *bnapi = &bp->bnx2_napi[ring_num];
5153 struct bnx2_rx_ring_info *rxr = &bnapi->rx_ring;
Michael Chan5d5d0012007-12-12 11:17:43 -08005154
Michael Chanbb4f98a2008-06-19 16:38:19 -07005155 if (ring_num == 0)
5156 cid = RX_CID;
5157 else
5158 cid = RX_RSS_CID + ring_num - 1;
5159
5160 rx_cid_addr = GET_CID_ADDR(cid);
5161
5162 bnx2_init_rxbd_rings(rxr->rx_desc_ring, rxr->rx_desc_mapping,
Michael Chan5d5d0012007-12-12 11:17:43 -08005163 bp->rx_buf_use_size, bp->rx_max_ring);
5164
Michael Chanbb4f98a2008-06-19 16:38:19 -07005165 bnx2_init_rx_context(bp, cid);
Michael Chan83e3fc82008-01-29 21:37:17 -08005166
5167 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
5168 val = REG_RD(bp, BNX2_MQ_MAP_L2_5);
5169 REG_WR(bp, BNX2_MQ_MAP_L2_5, val | BNX2_MQ_MAP_L2_5_ARM);
5170 }
5171
Michael Chan62a83132008-01-29 21:35:40 -08005172 bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_PG_BUF_SIZE, 0);
Michael Chan47bf4242007-12-12 11:19:12 -08005173 if (bp->rx_pg_ring_size) {
Michael Chanbb4f98a2008-06-19 16:38:19 -07005174 bnx2_init_rxbd_rings(rxr->rx_pg_desc_ring,
5175 rxr->rx_pg_desc_mapping,
Michael Chan47bf4242007-12-12 11:19:12 -08005176 PAGE_SIZE, bp->rx_max_pg_ring);
5177 val = (bp->rx_buf_use_size << 16) | PAGE_SIZE;
Michael Chan62a83132008-01-29 21:35:40 -08005178 bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_PG_BUF_SIZE, val);
5179 bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_RBDC_KEY,
Michael Chan5e9ad9e2008-06-19 16:43:17 -07005180 BNX2_L2CTX_RBDC_JUMBO_KEY - ring_num);
Michael Chan47bf4242007-12-12 11:19:12 -08005181
Michael Chanbb4f98a2008-06-19 16:38:19 -07005182 val = (u64) rxr->rx_pg_desc_mapping[0] >> 32;
Michael Chan62a83132008-01-29 21:35:40 -08005183 bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_NX_PG_BDHADDR_HI, val);
Michael Chan47bf4242007-12-12 11:19:12 -08005184
Michael Chanbb4f98a2008-06-19 16:38:19 -07005185 val = (u64) rxr->rx_pg_desc_mapping[0] & 0xffffffff;
Michael Chan62a83132008-01-29 21:35:40 -08005186 bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_NX_PG_BDHADDR_LO, val);
Michael Chan47bf4242007-12-12 11:19:12 -08005187
5188 if (CHIP_NUM(bp) == CHIP_NUM_5709)
5189 REG_WR(bp, BNX2_MQ_MAP_L2_3, BNX2_MQ_MAP_L2_3_DEFAULT);
5190 }
Michael Chanb6016b72005-05-26 13:03:09 -07005191
Michael Chanbb4f98a2008-06-19 16:38:19 -07005192 val = (u64) rxr->rx_desc_mapping[0] >> 32;
Michael Chan62a83132008-01-29 21:35:40 -08005193 bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_NX_BDHADDR_HI, val);
Michael Chanb6016b72005-05-26 13:03:09 -07005194
Michael Chanbb4f98a2008-06-19 16:38:19 -07005195 val = (u64) rxr->rx_desc_mapping[0] & 0xffffffff;
Michael Chan62a83132008-01-29 21:35:40 -08005196 bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_NX_BDHADDR_LO, val);
Michael Chanb6016b72005-05-26 13:03:09 -07005197
Michael Chanbb4f98a2008-06-19 16:38:19 -07005198 ring_prod = prod = rxr->rx_pg_prod;
Michael Chan47bf4242007-12-12 11:19:12 -08005199 for (i = 0; i < bp->rx_pg_ring_size; i++) {
Stanislaw Gruszkaa2df00a2010-07-15 22:55:40 +00005200 if (bnx2_alloc_rx_page(bp, rxr, ring_prod, GFP_KERNEL) < 0) {
Joe Perches3a9c6a42010-02-17 15:01:51 +00005201 netdev_warn(bp->dev, "init'ed rx page ring %d with %d/%d pages only\n",
5202 ring_num, i, bp->rx_pg_ring_size);
Michael Chan47bf4242007-12-12 11:19:12 -08005203 break;
Michael Chanb929e532009-12-03 09:46:33 +00005204 }
Michael Chan47bf4242007-12-12 11:19:12 -08005205 prod = NEXT_RX_BD(prod);
5206 ring_prod = RX_PG_RING_IDX(prod);
5207 }
Michael Chanbb4f98a2008-06-19 16:38:19 -07005208 rxr->rx_pg_prod = prod;
Michael Chan47bf4242007-12-12 11:19:12 -08005209
Michael Chanbb4f98a2008-06-19 16:38:19 -07005210 ring_prod = prod = rxr->rx_prod;
Michael Chan236b6392006-03-20 17:49:02 -08005211 for (i = 0; i < bp->rx_ring_size; i++) {
Stanislaw Gruszkaa2df00a2010-07-15 22:55:40 +00005212 if (bnx2_alloc_rx_skb(bp, rxr, ring_prod, GFP_KERNEL) < 0) {
Joe Perches3a9c6a42010-02-17 15:01:51 +00005213 netdev_warn(bp->dev, "init'ed rx ring %d with %d/%d skbs only\n",
5214 ring_num, i, bp->rx_ring_size);
Michael Chanb6016b72005-05-26 13:03:09 -07005215 break;
Michael Chanb929e532009-12-03 09:46:33 +00005216 }
Michael Chanb6016b72005-05-26 13:03:09 -07005217 prod = NEXT_RX_BD(prod);
5218 ring_prod = RX_RING_IDX(prod);
5219 }
Michael Chanbb4f98a2008-06-19 16:38:19 -07005220 rxr->rx_prod = prod;
Michael Chanb6016b72005-05-26 13:03:09 -07005221
Michael Chanbb4f98a2008-06-19 16:38:19 -07005222 rxr->rx_bidx_addr = MB_GET_CID_ADDR(cid) + BNX2_L2CTX_HOST_BDIDX;
5223 rxr->rx_bseq_addr = MB_GET_CID_ADDR(cid) + BNX2_L2CTX_HOST_BSEQ;
5224 rxr->rx_pg_bidx_addr = MB_GET_CID_ADDR(cid) + BNX2_L2CTX_HOST_PG_BDIDX;
Michael Chanb6016b72005-05-26 13:03:09 -07005225
Michael Chanbb4f98a2008-06-19 16:38:19 -07005226 REG_WR16(bp, rxr->rx_pg_bidx_addr, rxr->rx_pg_prod);
5227 REG_WR16(bp, rxr->rx_bidx_addr, prod);
5228
5229 REG_WR(bp, rxr->rx_bseq_addr, rxr->rx_prod_bseq);
Michael Chanb6016b72005-05-26 13:03:09 -07005230}
5231
Michael Chan35e90102008-06-19 16:37:42 -07005232static void
5233bnx2_init_all_rings(struct bnx2 *bp)
5234{
5235 int i;
Michael Chan5e9ad9e2008-06-19 16:43:17 -07005236 u32 val;
Michael Chan35e90102008-06-19 16:37:42 -07005237
5238 bnx2_clear_ring_states(bp);
5239
5240 REG_WR(bp, BNX2_TSCH_TSS_CFG, 0);
5241 for (i = 0; i < bp->num_tx_rings; i++)
5242 bnx2_init_tx_ring(bp, i);
5243
5244 if (bp->num_tx_rings > 1)
5245 REG_WR(bp, BNX2_TSCH_TSS_CFG, ((bp->num_tx_rings - 1) << 24) |
5246 (TX_TSS_CID << 7));
5247
Michael Chan5e9ad9e2008-06-19 16:43:17 -07005248 REG_WR(bp, BNX2_RLUP_RSS_CONFIG, 0);
5249 bnx2_reg_wr_ind(bp, BNX2_RXP_SCRATCH_RSS_TBL_SZ, 0);
5250
Michael Chanbb4f98a2008-06-19 16:38:19 -07005251 for (i = 0; i < bp->num_rx_rings; i++)
5252 bnx2_init_rx_ring(bp, i);
Michael Chan5e9ad9e2008-06-19 16:43:17 -07005253
5254 if (bp->num_rx_rings > 1) {
Michael Chan22fa1592010-10-11 16:12:00 -07005255 u32 tbl_32 = 0;
Michael Chan5e9ad9e2008-06-19 16:43:17 -07005256
5257 for (i = 0; i < BNX2_RXP_SCRATCH_RSS_TBL_MAX_ENTRIES; i++) {
Michael Chan22fa1592010-10-11 16:12:00 -07005258 int shift = (i % 8) << 2;
5259
5260 tbl_32 |= (i % (bp->num_rx_rings - 1)) << shift;
5261 if ((i % 8) == 7) {
5262 REG_WR(bp, BNX2_RLUP_RSS_DATA, tbl_32);
5263 REG_WR(bp, BNX2_RLUP_RSS_COMMAND, (i >> 3) |
5264 BNX2_RLUP_RSS_COMMAND_RSS_WRITE_MASK |
5265 BNX2_RLUP_RSS_COMMAND_WRITE |
5266 BNX2_RLUP_RSS_COMMAND_HASH_MASK);
5267 tbl_32 = 0;
5268 }
Michael Chan5e9ad9e2008-06-19 16:43:17 -07005269 }
5270
5271 val = BNX2_RLUP_RSS_CONFIG_IPV4_RSS_TYPE_ALL_XI |
5272 BNX2_RLUP_RSS_CONFIG_IPV6_RSS_TYPE_ALL_XI;
5273
5274 REG_WR(bp, BNX2_RLUP_RSS_CONFIG, val);
5275
5276 }
Michael Chan35e90102008-06-19 16:37:42 -07005277}
5278
Michael Chan5d5d0012007-12-12 11:17:43 -08005279static u32 bnx2_find_max_ring(u32 ring_size, u32 max_size)
Michael Chan13daffa2006-03-20 17:49:20 -08005280{
Michael Chan5d5d0012007-12-12 11:17:43 -08005281 u32 max, num_rings = 1;
Michael Chan13daffa2006-03-20 17:49:20 -08005282
Michael Chan5d5d0012007-12-12 11:17:43 -08005283 while (ring_size > MAX_RX_DESC_CNT) {
5284 ring_size -= MAX_RX_DESC_CNT;
Michael Chan13daffa2006-03-20 17:49:20 -08005285 num_rings++;
5286 }
5287 /* round to next power of 2 */
Michael Chan5d5d0012007-12-12 11:17:43 -08005288 max = max_size;
Michael Chan13daffa2006-03-20 17:49:20 -08005289 while ((max & num_rings) == 0)
5290 max >>= 1;
5291
5292 if (num_rings != max)
5293 max <<= 1;
5294
Michael Chan5d5d0012007-12-12 11:17:43 -08005295 return max;
5296}
5297
5298static void
5299bnx2_set_rx_ring_size(struct bnx2 *bp, u32 size)
5300{
Michael Chan84eaa182007-12-12 11:19:57 -08005301 u32 rx_size, rx_space, jumbo_size;
Michael Chan5d5d0012007-12-12 11:17:43 -08005302
5303 /* 8 for CRC and VLAN */
Benjamin Lid89cb6a2008-05-16 22:18:57 -07005304 rx_size = bp->dev->mtu + ETH_HLEN + BNX2_RX_OFFSET + 8;
Michael Chan5d5d0012007-12-12 11:17:43 -08005305
Michael Chan84eaa182007-12-12 11:19:57 -08005306 rx_space = SKB_DATA_ALIGN(rx_size + BNX2_RX_ALIGN) + NET_SKB_PAD +
5307 sizeof(struct skb_shared_info);
5308
Benjamin Li601d3d12008-05-16 22:19:35 -07005309 bp->rx_copy_thresh = BNX2_RX_COPY_THRESH;
Michael Chan47bf4242007-12-12 11:19:12 -08005310 bp->rx_pg_ring_size = 0;
5311 bp->rx_max_pg_ring = 0;
5312 bp->rx_max_pg_ring_idx = 0;
David S. Millerf86e82f2008-01-21 17:15:40 -08005313 if ((rx_space > PAGE_SIZE) && !(bp->flags & BNX2_FLAG_JUMBO_BROKEN)) {
Michael Chan84eaa182007-12-12 11:19:57 -08005314 int pages = PAGE_ALIGN(bp->dev->mtu - 40) >> PAGE_SHIFT;
5315
5316 jumbo_size = size * pages;
5317 if (jumbo_size > MAX_TOTAL_RX_PG_DESC_CNT)
5318 jumbo_size = MAX_TOTAL_RX_PG_DESC_CNT;
5319
5320 bp->rx_pg_ring_size = jumbo_size;
5321 bp->rx_max_pg_ring = bnx2_find_max_ring(jumbo_size,
5322 MAX_RX_PG_RINGS);
5323 bp->rx_max_pg_ring_idx = (bp->rx_max_pg_ring * RX_DESC_CNT) - 1;
Benjamin Li601d3d12008-05-16 22:19:35 -07005324 rx_size = BNX2_RX_COPY_THRESH + BNX2_RX_OFFSET;
Michael Chan84eaa182007-12-12 11:19:57 -08005325 bp->rx_copy_thresh = 0;
5326 }
Michael Chan5d5d0012007-12-12 11:17:43 -08005327
5328 bp->rx_buf_use_size = rx_size;
5329 /* hw alignment */
5330 bp->rx_buf_size = bp->rx_buf_use_size + BNX2_RX_ALIGN;
Benjamin Lid89cb6a2008-05-16 22:18:57 -07005331 bp->rx_jumbo_thresh = rx_size - BNX2_RX_OFFSET;
Michael Chan5d5d0012007-12-12 11:17:43 -08005332 bp->rx_ring_size = size;
5333 bp->rx_max_ring = bnx2_find_max_ring(size, MAX_RX_RINGS);
Michael Chan13daffa2006-03-20 17:49:20 -08005334 bp->rx_max_ring_idx = (bp->rx_max_ring * RX_DESC_CNT) - 1;
5335}
5336
5337static void
Michael Chanb6016b72005-05-26 13:03:09 -07005338bnx2_free_tx_skbs(struct bnx2 *bp)
5339{
5340 int i;
5341
Michael Chan35e90102008-06-19 16:37:42 -07005342 for (i = 0; i < bp->num_tx_rings; i++) {
5343 struct bnx2_napi *bnapi = &bp->bnx2_napi[i];
5344 struct bnx2_tx_ring_info *txr = &bnapi->tx_ring;
5345 int j;
Michael Chanb6016b72005-05-26 13:03:09 -07005346
Michael Chan35e90102008-06-19 16:37:42 -07005347 if (txr->tx_buf_ring == NULL)
Michael Chanb6016b72005-05-26 13:03:09 -07005348 continue;
Michael Chanb6016b72005-05-26 13:03:09 -07005349
Michael Chan35e90102008-06-19 16:37:42 -07005350 for (j = 0; j < TX_DESC_CNT; ) {
Benjamin Li3d16af82008-10-09 12:26:41 -07005351 struct sw_tx_bd *tx_buf = &txr->tx_buf_ring[j];
Michael Chan35e90102008-06-19 16:37:42 -07005352 struct sk_buff *skb = tx_buf->skb;
Alexander Duycke95524a2009-12-02 16:47:57 +00005353 int k, last;
Michael Chan35e90102008-06-19 16:37:42 -07005354
5355 if (skb == NULL) {
5356 j++;
5357 continue;
5358 }
5359
Stanislaw Gruszka36227e82010-07-15 04:25:50 +00005360 dma_unmap_single(&bp->pdev->dev,
FUJITA Tomonori1a4ccc22010-04-01 16:56:57 +00005361 dma_unmap_addr(tx_buf, mapping),
Alexander Duycke95524a2009-12-02 16:47:57 +00005362 skb_headlen(skb),
5363 PCI_DMA_TODEVICE);
Michael Chanb6016b72005-05-26 13:03:09 -07005364
Michael Chan35e90102008-06-19 16:37:42 -07005365 tx_buf->skb = NULL;
Michael Chanb6016b72005-05-26 13:03:09 -07005366
Alexander Duycke95524a2009-12-02 16:47:57 +00005367 last = tx_buf->nr_frags;
5368 j++;
5369 for (k = 0; k < last; k++, j++) {
5370 tx_buf = &txr->tx_buf_ring[TX_RING_IDX(j)];
Stanislaw Gruszka36227e82010-07-15 04:25:50 +00005371 dma_unmap_page(&bp->pdev->dev,
FUJITA Tomonori1a4ccc22010-04-01 16:56:57 +00005372 dma_unmap_addr(tx_buf, mapping),
Alexander Duycke95524a2009-12-02 16:47:57 +00005373 skb_shinfo(skb)->frags[k].size,
5374 PCI_DMA_TODEVICE);
5375 }
Michael Chan35e90102008-06-19 16:37:42 -07005376 dev_kfree_skb(skb);
Michael Chanb6016b72005-05-26 13:03:09 -07005377 }
Michael Chanb6016b72005-05-26 13:03:09 -07005378 }
Michael Chanb6016b72005-05-26 13:03:09 -07005379}
5380
5381static void
5382bnx2_free_rx_skbs(struct bnx2 *bp)
5383{
5384 int i;
5385
Michael Chanbb4f98a2008-06-19 16:38:19 -07005386 for (i = 0; i < bp->num_rx_rings; i++) {
5387 struct bnx2_napi *bnapi = &bp->bnx2_napi[i];
5388 struct bnx2_rx_ring_info *rxr = &bnapi->rx_ring;
5389 int j;
Michael Chanb6016b72005-05-26 13:03:09 -07005390
Michael Chanbb4f98a2008-06-19 16:38:19 -07005391 if (rxr->rx_buf_ring == NULL)
5392 return;
Michael Chanb6016b72005-05-26 13:03:09 -07005393
Michael Chanbb4f98a2008-06-19 16:38:19 -07005394 for (j = 0; j < bp->rx_max_ring_idx; j++) {
5395 struct sw_bd *rx_buf = &rxr->rx_buf_ring[j];
5396 struct sk_buff *skb = rx_buf->skb;
Michael Chanb6016b72005-05-26 13:03:09 -07005397
Michael Chanbb4f98a2008-06-19 16:38:19 -07005398 if (skb == NULL)
5399 continue;
Michael Chanb6016b72005-05-26 13:03:09 -07005400
Stanislaw Gruszka36227e82010-07-15 04:25:50 +00005401 dma_unmap_single(&bp->pdev->dev,
FUJITA Tomonori1a4ccc22010-04-01 16:56:57 +00005402 dma_unmap_addr(rx_buf, mapping),
Michael Chanbb4f98a2008-06-19 16:38:19 -07005403 bp->rx_buf_use_size,
5404 PCI_DMA_FROMDEVICE);
Michael Chanb6016b72005-05-26 13:03:09 -07005405
Michael Chanbb4f98a2008-06-19 16:38:19 -07005406 rx_buf->skb = NULL;
5407
5408 dev_kfree_skb(skb);
5409 }
5410 for (j = 0; j < bp->rx_max_pg_ring_idx; j++)
5411 bnx2_free_rx_page(bp, rxr, j);
Michael Chanb6016b72005-05-26 13:03:09 -07005412 }
5413}
5414
5415static void
5416bnx2_free_skbs(struct bnx2 *bp)
5417{
5418 bnx2_free_tx_skbs(bp);
5419 bnx2_free_rx_skbs(bp);
5420}
5421
5422static int
5423bnx2_reset_nic(struct bnx2 *bp, u32 reset_code)
5424{
5425 int rc;
5426
5427 rc = bnx2_reset_chip(bp, reset_code);
5428 bnx2_free_skbs(bp);
5429 if (rc)
5430 return rc;
5431
Michael Chanfba9fe92006-06-12 22:21:25 -07005432 if ((rc = bnx2_init_chip(bp)) != 0)
5433 return rc;
5434
Michael Chan35e90102008-06-19 16:37:42 -07005435 bnx2_init_all_rings(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07005436 return 0;
5437}
5438
5439static int
Michael Chan9a120bc2008-05-16 22:17:45 -07005440bnx2_init_nic(struct bnx2 *bp, int reset_phy)
Michael Chanb6016b72005-05-26 13:03:09 -07005441{
5442 int rc;
5443
5444 if ((rc = bnx2_reset_nic(bp, BNX2_DRV_MSG_CODE_RESET)) != 0)
5445 return rc;
5446
Michael Chan80be4432006-11-19 14:07:28 -08005447 spin_lock_bh(&bp->phy_lock);
Michael Chan9a120bc2008-05-16 22:17:45 -07005448 bnx2_init_phy(bp, reset_phy);
Michael Chanb6016b72005-05-26 13:03:09 -07005449 bnx2_set_link(bp);
Michael Chan543a8272008-05-02 16:56:44 -07005450 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
5451 bnx2_remote_phy_event(bp);
Michael Chan0d8a6572007-07-07 22:49:43 -07005452 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07005453 return 0;
5454}
5455
5456static int
Michael Chan74bf4ba2008-10-09 12:21:08 -07005457bnx2_shutdown_chip(struct bnx2 *bp)
5458{
5459 u32 reset_code;
5460
5461 if (bp->flags & BNX2_FLAG_NO_WOL)
5462 reset_code = BNX2_DRV_MSG_CODE_UNLOAD_LNK_DN;
5463 else if (bp->wol)
5464 reset_code = BNX2_DRV_MSG_CODE_SUSPEND_WOL;
5465 else
5466 reset_code = BNX2_DRV_MSG_CODE_SUSPEND_NO_WOL;
5467
5468 return bnx2_reset_chip(bp, reset_code);
5469}
5470
5471static int
Michael Chanb6016b72005-05-26 13:03:09 -07005472bnx2_test_registers(struct bnx2 *bp)
5473{
5474 int ret;
Michael Chan5bae30c2007-05-03 13:18:46 -07005475 int i, is_5709;
Arjan van de Venf71e1302006-03-03 21:33:57 -05005476 static const struct {
Michael Chanb6016b72005-05-26 13:03:09 -07005477 u16 offset;
5478 u16 flags;
Michael Chan5bae30c2007-05-03 13:18:46 -07005479#define BNX2_FL_NOT_5709 1
Michael Chanb6016b72005-05-26 13:03:09 -07005480 u32 rw_mask;
5481 u32 ro_mask;
5482 } reg_tbl[] = {
5483 { 0x006c, 0, 0x00000000, 0x0000003f },
5484 { 0x0090, 0, 0xffffffff, 0x00000000 },
5485 { 0x0094, 0, 0x00000000, 0x00000000 },
5486
Michael Chan5bae30c2007-05-03 13:18:46 -07005487 { 0x0404, BNX2_FL_NOT_5709, 0x00003f00, 0x00000000 },
5488 { 0x0418, BNX2_FL_NOT_5709, 0x00000000, 0xffffffff },
5489 { 0x041c, BNX2_FL_NOT_5709, 0x00000000, 0xffffffff },
5490 { 0x0420, BNX2_FL_NOT_5709, 0x00000000, 0x80ffffff },
5491 { 0x0424, BNX2_FL_NOT_5709, 0x00000000, 0x00000000 },
5492 { 0x0428, BNX2_FL_NOT_5709, 0x00000000, 0x00000001 },
5493 { 0x0450, BNX2_FL_NOT_5709, 0x00000000, 0x0000ffff },
5494 { 0x0454, BNX2_FL_NOT_5709, 0x00000000, 0xffffffff },
5495 { 0x0458, BNX2_FL_NOT_5709, 0x00000000, 0xffffffff },
Michael Chanb6016b72005-05-26 13:03:09 -07005496
Michael Chan5bae30c2007-05-03 13:18:46 -07005497 { 0x0808, BNX2_FL_NOT_5709, 0x00000000, 0xffffffff },
5498 { 0x0854, BNX2_FL_NOT_5709, 0x00000000, 0xffffffff },
5499 { 0x0868, BNX2_FL_NOT_5709, 0x00000000, 0x77777777 },
5500 { 0x086c, BNX2_FL_NOT_5709, 0x00000000, 0x77777777 },
5501 { 0x0870, BNX2_FL_NOT_5709, 0x00000000, 0x77777777 },
5502 { 0x0874, BNX2_FL_NOT_5709, 0x00000000, 0x77777777 },
Michael Chanb6016b72005-05-26 13:03:09 -07005503
Michael Chan5bae30c2007-05-03 13:18:46 -07005504 { 0x0c00, BNX2_FL_NOT_5709, 0x00000000, 0x00000001 },
5505 { 0x0c04, BNX2_FL_NOT_5709, 0x00000000, 0x03ff0001 },
5506 { 0x0c08, BNX2_FL_NOT_5709, 0x0f0ff073, 0x00000000 },
Michael Chanb6016b72005-05-26 13:03:09 -07005507
5508 { 0x1000, 0, 0x00000000, 0x00000001 },
Michael Chan15b169c2008-05-02 16:57:08 -07005509 { 0x1004, BNX2_FL_NOT_5709, 0x00000000, 0x000f0001 },
Michael Chanb6016b72005-05-26 13:03:09 -07005510
5511 { 0x1408, 0, 0x01c00800, 0x00000000 },
5512 { 0x149c, 0, 0x8000ffff, 0x00000000 },
5513 { 0x14a8, 0, 0x00000000, 0x000001ff },
Michael Chan5b0c76a2005-11-04 08:45:49 -08005514 { 0x14ac, 0, 0x0fffffff, 0x10000000 },
Michael Chanb6016b72005-05-26 13:03:09 -07005515 { 0x14b0, 0, 0x00000002, 0x00000001 },
5516 { 0x14b8, 0, 0x00000000, 0x00000000 },
5517 { 0x14c0, 0, 0x00000000, 0x00000009 },
5518 { 0x14c4, 0, 0x00003fff, 0x00000000 },
5519 { 0x14cc, 0, 0x00000000, 0x00000001 },
5520 { 0x14d0, 0, 0xffffffff, 0x00000000 },
Michael Chanb6016b72005-05-26 13:03:09 -07005521
5522 { 0x1800, 0, 0x00000000, 0x00000001 },
5523 { 0x1804, 0, 0x00000000, 0x00000003 },
Michael Chanb6016b72005-05-26 13:03:09 -07005524
5525 { 0x2800, 0, 0x00000000, 0x00000001 },
5526 { 0x2804, 0, 0x00000000, 0x00003f01 },
5527 { 0x2808, 0, 0x0f3f3f03, 0x00000000 },
5528 { 0x2810, 0, 0xffff0000, 0x00000000 },
5529 { 0x2814, 0, 0xffff0000, 0x00000000 },
5530 { 0x2818, 0, 0xffff0000, 0x00000000 },
5531 { 0x281c, 0, 0xffff0000, 0x00000000 },
5532 { 0x2834, 0, 0xffffffff, 0x00000000 },
5533 { 0x2840, 0, 0x00000000, 0xffffffff },
5534 { 0x2844, 0, 0x00000000, 0xffffffff },
5535 { 0x2848, 0, 0xffffffff, 0x00000000 },
5536 { 0x284c, 0, 0xf800f800, 0x07ff07ff },
5537
5538 { 0x2c00, 0, 0x00000000, 0x00000011 },
5539 { 0x2c04, 0, 0x00000000, 0x00030007 },
5540
Michael Chanb6016b72005-05-26 13:03:09 -07005541 { 0x3c00, 0, 0x00000000, 0x00000001 },
5542 { 0x3c04, 0, 0x00000000, 0x00070000 },
5543 { 0x3c08, 0, 0x00007f71, 0x07f00000 },
5544 { 0x3c0c, 0, 0x1f3ffffc, 0x00000000 },
5545 { 0x3c10, 0, 0xffffffff, 0x00000000 },
5546 { 0x3c14, 0, 0x00000000, 0xffffffff },
5547 { 0x3c18, 0, 0x00000000, 0xffffffff },
5548 { 0x3c1c, 0, 0xfffff000, 0x00000000 },
5549 { 0x3c20, 0, 0xffffff00, 0x00000000 },
Michael Chanb6016b72005-05-26 13:03:09 -07005550
5551 { 0x5004, 0, 0x00000000, 0x0000007f },
5552 { 0x5008, 0, 0x0f0007ff, 0x00000000 },
Michael Chanb6016b72005-05-26 13:03:09 -07005553
Michael Chanb6016b72005-05-26 13:03:09 -07005554 { 0x5c00, 0, 0x00000000, 0x00000001 },
5555 { 0x5c04, 0, 0x00000000, 0x0003000f },
5556 { 0x5c08, 0, 0x00000003, 0x00000000 },
5557 { 0x5c0c, 0, 0x0000fff8, 0x00000000 },
5558 { 0x5c10, 0, 0x00000000, 0xffffffff },
5559 { 0x5c80, 0, 0x00000000, 0x0f7113f1 },
5560 { 0x5c84, 0, 0x00000000, 0x0000f333 },
5561 { 0x5c88, 0, 0x00000000, 0x00077373 },
5562 { 0x5c8c, 0, 0x00000000, 0x0007f737 },
5563
5564 { 0x6808, 0, 0x0000ff7f, 0x00000000 },
5565 { 0x680c, 0, 0xffffffff, 0x00000000 },
5566 { 0x6810, 0, 0xffffffff, 0x00000000 },
5567 { 0x6814, 0, 0xffffffff, 0x00000000 },
5568 { 0x6818, 0, 0xffffffff, 0x00000000 },
5569 { 0x681c, 0, 0xffffffff, 0x00000000 },
5570 { 0x6820, 0, 0x00ff00ff, 0x00000000 },
5571 { 0x6824, 0, 0x00ff00ff, 0x00000000 },
5572 { 0x6828, 0, 0x00ff00ff, 0x00000000 },
5573 { 0x682c, 0, 0x03ff03ff, 0x00000000 },
5574 { 0x6830, 0, 0x03ff03ff, 0x00000000 },
5575 { 0x6834, 0, 0x03ff03ff, 0x00000000 },
5576 { 0x6838, 0, 0x03ff03ff, 0x00000000 },
5577 { 0x683c, 0, 0x0000ffff, 0x00000000 },
5578 { 0x6840, 0, 0x00000ff0, 0x00000000 },
5579 { 0x6844, 0, 0x00ffff00, 0x00000000 },
5580 { 0x684c, 0, 0xffffffff, 0x00000000 },
5581 { 0x6850, 0, 0x7f7f7f7f, 0x00000000 },
5582 { 0x6854, 0, 0x7f7f7f7f, 0x00000000 },
5583 { 0x6858, 0, 0x7f7f7f7f, 0x00000000 },
5584 { 0x685c, 0, 0x7f7f7f7f, 0x00000000 },
5585 { 0x6908, 0, 0x00000000, 0x0001ff0f },
5586 { 0x690c, 0, 0x00000000, 0x0ffe00f0 },
5587
5588 { 0xffff, 0, 0x00000000, 0x00000000 },
5589 };
5590
5591 ret = 0;
Michael Chan5bae30c2007-05-03 13:18:46 -07005592 is_5709 = 0;
5593 if (CHIP_NUM(bp) == CHIP_NUM_5709)
5594 is_5709 = 1;
5595
Michael Chanb6016b72005-05-26 13:03:09 -07005596 for (i = 0; reg_tbl[i].offset != 0xffff; i++) {
5597 u32 offset, rw_mask, ro_mask, save_val, val;
Michael Chan5bae30c2007-05-03 13:18:46 -07005598 u16 flags = reg_tbl[i].flags;
5599
5600 if (is_5709 && (flags & BNX2_FL_NOT_5709))
5601 continue;
Michael Chanb6016b72005-05-26 13:03:09 -07005602
5603 offset = (u32) reg_tbl[i].offset;
5604 rw_mask = reg_tbl[i].rw_mask;
5605 ro_mask = reg_tbl[i].ro_mask;
5606
Peter Hagervall14ab9b82005-08-10 14:18:16 -07005607 save_val = readl(bp->regview + offset);
Michael Chanb6016b72005-05-26 13:03:09 -07005608
Peter Hagervall14ab9b82005-08-10 14:18:16 -07005609 writel(0, bp->regview + offset);
Michael Chanb6016b72005-05-26 13:03:09 -07005610
Peter Hagervall14ab9b82005-08-10 14:18:16 -07005611 val = readl(bp->regview + offset);
Michael Chanb6016b72005-05-26 13:03:09 -07005612 if ((val & rw_mask) != 0) {
5613 goto reg_test_err;
5614 }
5615
5616 if ((val & ro_mask) != (save_val & ro_mask)) {
5617 goto reg_test_err;
5618 }
5619
Peter Hagervall14ab9b82005-08-10 14:18:16 -07005620 writel(0xffffffff, bp->regview + offset);
Michael Chanb6016b72005-05-26 13:03:09 -07005621
Peter Hagervall14ab9b82005-08-10 14:18:16 -07005622 val = readl(bp->regview + offset);
Michael Chanb6016b72005-05-26 13:03:09 -07005623 if ((val & rw_mask) != rw_mask) {
5624 goto reg_test_err;
5625 }
5626
5627 if ((val & ro_mask) != (save_val & ro_mask)) {
5628 goto reg_test_err;
5629 }
5630
Peter Hagervall14ab9b82005-08-10 14:18:16 -07005631 writel(save_val, bp->regview + offset);
Michael Chanb6016b72005-05-26 13:03:09 -07005632 continue;
5633
5634reg_test_err:
Peter Hagervall14ab9b82005-08-10 14:18:16 -07005635 writel(save_val, bp->regview + offset);
Michael Chanb6016b72005-05-26 13:03:09 -07005636 ret = -ENODEV;
5637 break;
5638 }
5639 return ret;
5640}
5641
5642static int
5643bnx2_do_mem_test(struct bnx2 *bp, u32 start, u32 size)
5644{
Arjan van de Venf71e1302006-03-03 21:33:57 -05005645 static const u32 test_pattern[] = { 0x00000000, 0xffffffff, 0x55555555,
Michael Chanb6016b72005-05-26 13:03:09 -07005646 0xaaaaaaaa , 0xaa55aa55, 0x55aa55aa };
5647 int i;
5648
5649 for (i = 0; i < sizeof(test_pattern) / 4; i++) {
5650 u32 offset;
5651
5652 for (offset = 0; offset < size; offset += 4) {
5653
Michael Chan2726d6e2008-01-29 21:35:05 -08005654 bnx2_reg_wr_ind(bp, start + offset, test_pattern[i]);
Michael Chanb6016b72005-05-26 13:03:09 -07005655
Michael Chan2726d6e2008-01-29 21:35:05 -08005656 if (bnx2_reg_rd_ind(bp, start + offset) !=
Michael Chanb6016b72005-05-26 13:03:09 -07005657 test_pattern[i]) {
5658 return -ENODEV;
5659 }
5660 }
5661 }
5662 return 0;
5663}
5664
5665static int
5666bnx2_test_memory(struct bnx2 *bp)
5667{
5668 int ret = 0;
5669 int i;
Michael Chan5bae30c2007-05-03 13:18:46 -07005670 static struct mem_entry {
Michael Chanb6016b72005-05-26 13:03:09 -07005671 u32 offset;
5672 u32 len;
Michael Chan5bae30c2007-05-03 13:18:46 -07005673 } mem_tbl_5706[] = {
Michael Chanb6016b72005-05-26 13:03:09 -07005674 { 0x60000, 0x4000 },
Michael Chan5b0c76a2005-11-04 08:45:49 -08005675 { 0xa0000, 0x3000 },
Michael Chanb6016b72005-05-26 13:03:09 -07005676 { 0xe0000, 0x4000 },
5677 { 0x120000, 0x4000 },
5678 { 0x1a0000, 0x4000 },
5679 { 0x160000, 0x4000 },
5680 { 0xffffffff, 0 },
Michael Chan5bae30c2007-05-03 13:18:46 -07005681 },
5682 mem_tbl_5709[] = {
5683 { 0x60000, 0x4000 },
5684 { 0xa0000, 0x3000 },
5685 { 0xe0000, 0x4000 },
5686 { 0x120000, 0x4000 },
5687 { 0x1a0000, 0x4000 },
5688 { 0xffffffff, 0 },
Michael Chanb6016b72005-05-26 13:03:09 -07005689 };
Michael Chan5bae30c2007-05-03 13:18:46 -07005690 struct mem_entry *mem_tbl;
5691
5692 if (CHIP_NUM(bp) == CHIP_NUM_5709)
5693 mem_tbl = mem_tbl_5709;
5694 else
5695 mem_tbl = mem_tbl_5706;
Michael Chanb6016b72005-05-26 13:03:09 -07005696
5697 for (i = 0; mem_tbl[i].offset != 0xffffffff; i++) {
5698 if ((ret = bnx2_do_mem_test(bp, mem_tbl[i].offset,
5699 mem_tbl[i].len)) != 0) {
5700 return ret;
5701 }
5702 }
Jeff Garzik6aa20a22006-09-13 13:24:59 -04005703
Michael Chanb6016b72005-05-26 13:03:09 -07005704 return ret;
5705}
5706
Michael Chanbc5a0692006-01-23 16:13:22 -08005707#define BNX2_MAC_LOOPBACK 0
5708#define BNX2_PHY_LOOPBACK 1
5709
Michael Chanb6016b72005-05-26 13:03:09 -07005710static int
Michael Chanbc5a0692006-01-23 16:13:22 -08005711bnx2_run_loopback(struct bnx2 *bp, int loopback_mode)
Michael Chanb6016b72005-05-26 13:03:09 -07005712{
5713 unsigned int pkt_size, num_pkts, i;
5714 struct sk_buff *skb, *rx_skb;
5715 unsigned char *packet;
Michael Chanbc5a0692006-01-23 16:13:22 -08005716 u16 rx_start_idx, rx_idx;
Michael Chanb6016b72005-05-26 13:03:09 -07005717 dma_addr_t map;
5718 struct tx_bd *txbd;
5719 struct sw_bd *rx_buf;
5720 struct l2_fhdr *rx_hdr;
5721 int ret = -ENODEV;
Michael Chanc76c0472007-12-20 20:01:19 -08005722 struct bnx2_napi *bnapi = &bp->bnx2_napi[0], *tx_napi;
Michael Chan35e90102008-06-19 16:37:42 -07005723 struct bnx2_tx_ring_info *txr = &bnapi->tx_ring;
Michael Chanbb4f98a2008-06-19 16:38:19 -07005724 struct bnx2_rx_ring_info *rxr = &bnapi->rx_ring;
Michael Chanc76c0472007-12-20 20:01:19 -08005725
5726 tx_napi = bnapi;
Michael Chanb6016b72005-05-26 13:03:09 -07005727
Michael Chan35e90102008-06-19 16:37:42 -07005728 txr = &tx_napi->tx_ring;
Michael Chanbb4f98a2008-06-19 16:38:19 -07005729 rxr = &bnapi->rx_ring;
Michael Chanbc5a0692006-01-23 16:13:22 -08005730 if (loopback_mode == BNX2_MAC_LOOPBACK) {
5731 bp->loopback = MAC_LOOPBACK;
5732 bnx2_set_mac_loopback(bp);
5733 }
5734 else if (loopback_mode == BNX2_PHY_LOOPBACK) {
Michael Chan583c28e2008-01-21 19:51:35 -08005735 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
Michael Chan489310a2007-10-10 16:16:31 -07005736 return 0;
5737
Michael Chan80be4432006-11-19 14:07:28 -08005738 bp->loopback = PHY_LOOPBACK;
Michael Chanbc5a0692006-01-23 16:13:22 -08005739 bnx2_set_phy_loopback(bp);
5740 }
5741 else
5742 return -EINVAL;
Michael Chanb6016b72005-05-26 13:03:09 -07005743
Michael Chan84eaa182007-12-12 11:19:57 -08005744 pkt_size = min(bp->dev->mtu + ETH_HLEN, bp->rx_jumbo_thresh - 4);
Michael Chan932f3772006-08-15 01:39:36 -07005745 skb = netdev_alloc_skb(bp->dev, pkt_size);
John W. Linvilleb6cbc3b62005-11-10 12:58:00 -08005746 if (!skb)
5747 return -ENOMEM;
Michael Chanb6016b72005-05-26 13:03:09 -07005748 packet = skb_put(skb, pkt_size);
Michael Chan66342922006-12-14 15:57:04 -08005749 memcpy(packet, bp->dev->dev_addr, 6);
Michael Chanb6016b72005-05-26 13:03:09 -07005750 memset(packet + 6, 0x0, 8);
5751 for (i = 14; i < pkt_size; i++)
5752 packet[i] = (unsigned char) (i & 0xff);
5753
Stanislaw Gruszka36227e82010-07-15 04:25:50 +00005754 map = dma_map_single(&bp->pdev->dev, skb->data, pkt_size,
5755 PCI_DMA_TODEVICE);
5756 if (dma_mapping_error(&bp->pdev->dev, map)) {
Benjamin Li3d16af82008-10-09 12:26:41 -07005757 dev_kfree_skb(skb);
5758 return -EIO;
5759 }
Michael Chanb6016b72005-05-26 13:03:09 -07005760
Michael Chanbf5295b2006-03-23 01:11:56 -08005761 REG_WR(bp, BNX2_HC_COMMAND,
5762 bp->hc_cmd | BNX2_HC_COMMAND_COAL_NOW_WO_INT);
5763
Michael Chanb6016b72005-05-26 13:03:09 -07005764 REG_RD(bp, BNX2_HC_COMMAND);
5765
5766 udelay(5);
Michael Chan35efa7c2007-12-20 19:56:37 -08005767 rx_start_idx = bnx2_get_hw_rx_cons(bnapi);
Michael Chanb6016b72005-05-26 13:03:09 -07005768
Michael Chanb6016b72005-05-26 13:03:09 -07005769 num_pkts = 0;
5770
Michael Chan35e90102008-06-19 16:37:42 -07005771 txbd = &txr->tx_desc_ring[TX_RING_IDX(txr->tx_prod)];
Michael Chanb6016b72005-05-26 13:03:09 -07005772
5773 txbd->tx_bd_haddr_hi = (u64) map >> 32;
5774 txbd->tx_bd_haddr_lo = (u64) map & 0xffffffff;
5775 txbd->tx_bd_mss_nbytes = pkt_size;
5776 txbd->tx_bd_vlan_tag_flags = TX_BD_FLAGS_START | TX_BD_FLAGS_END;
5777
5778 num_pkts++;
Michael Chan35e90102008-06-19 16:37:42 -07005779 txr->tx_prod = NEXT_TX_BD(txr->tx_prod);
5780 txr->tx_prod_bseq += pkt_size;
Michael Chanb6016b72005-05-26 13:03:09 -07005781
Michael Chan35e90102008-06-19 16:37:42 -07005782 REG_WR16(bp, txr->tx_bidx_addr, txr->tx_prod);
5783 REG_WR(bp, txr->tx_bseq_addr, txr->tx_prod_bseq);
Michael Chanb6016b72005-05-26 13:03:09 -07005784
5785 udelay(100);
5786
Michael Chanbf5295b2006-03-23 01:11:56 -08005787 REG_WR(bp, BNX2_HC_COMMAND,
5788 bp->hc_cmd | BNX2_HC_COMMAND_COAL_NOW_WO_INT);
5789
Michael Chanb6016b72005-05-26 13:03:09 -07005790 REG_RD(bp, BNX2_HC_COMMAND);
5791
5792 udelay(5);
5793
Stanislaw Gruszka36227e82010-07-15 04:25:50 +00005794 dma_unmap_single(&bp->pdev->dev, map, pkt_size, PCI_DMA_TODEVICE);
Michael Chan745720e2006-06-29 12:37:41 -07005795 dev_kfree_skb(skb);
Michael Chanb6016b72005-05-26 13:03:09 -07005796
Michael Chan35e90102008-06-19 16:37:42 -07005797 if (bnx2_get_hw_tx_cons(tx_napi) != txr->tx_prod)
Michael Chanb6016b72005-05-26 13:03:09 -07005798 goto loopback_test_done;
Michael Chanb6016b72005-05-26 13:03:09 -07005799
Michael Chan35efa7c2007-12-20 19:56:37 -08005800 rx_idx = bnx2_get_hw_rx_cons(bnapi);
Michael Chanb6016b72005-05-26 13:03:09 -07005801 if (rx_idx != rx_start_idx + num_pkts) {
5802 goto loopback_test_done;
5803 }
5804
Michael Chanbb4f98a2008-06-19 16:38:19 -07005805 rx_buf = &rxr->rx_buf_ring[rx_start_idx];
Michael Chanb6016b72005-05-26 13:03:09 -07005806 rx_skb = rx_buf->skb;
5807
Michael Chana33fa662010-05-06 08:58:13 +00005808 rx_hdr = rx_buf->desc;
Benjamin Lid89cb6a2008-05-16 22:18:57 -07005809 skb_reserve(rx_skb, BNX2_RX_OFFSET);
Michael Chanb6016b72005-05-26 13:03:09 -07005810
Stanislaw Gruszka36227e82010-07-15 04:25:50 +00005811 dma_sync_single_for_cpu(&bp->pdev->dev,
FUJITA Tomonori1a4ccc22010-04-01 16:56:57 +00005812 dma_unmap_addr(rx_buf, mapping),
Michael Chanb6016b72005-05-26 13:03:09 -07005813 bp->rx_buf_size, PCI_DMA_FROMDEVICE);
5814
Michael Chanade2bfe2006-01-23 16:09:51 -08005815 if (rx_hdr->l2_fhdr_status &
Michael Chanb6016b72005-05-26 13:03:09 -07005816 (L2_FHDR_ERRORS_BAD_CRC |
5817 L2_FHDR_ERRORS_PHY_DECODE |
5818 L2_FHDR_ERRORS_ALIGNMENT |
5819 L2_FHDR_ERRORS_TOO_SHORT |
5820 L2_FHDR_ERRORS_GIANT_FRAME)) {
5821
5822 goto loopback_test_done;
5823 }
5824
5825 if ((rx_hdr->l2_fhdr_pkt_len - 4) != pkt_size) {
5826 goto loopback_test_done;
5827 }
5828
5829 for (i = 14; i < pkt_size; i++) {
5830 if (*(rx_skb->data + i) != (unsigned char) (i & 0xff)) {
5831 goto loopback_test_done;
5832 }
5833 }
5834
5835 ret = 0;
5836
5837loopback_test_done:
5838 bp->loopback = 0;
5839 return ret;
5840}
5841
Michael Chanbc5a0692006-01-23 16:13:22 -08005842#define BNX2_MAC_LOOPBACK_FAILED 1
5843#define BNX2_PHY_LOOPBACK_FAILED 2
5844#define BNX2_LOOPBACK_FAILED (BNX2_MAC_LOOPBACK_FAILED | \
5845 BNX2_PHY_LOOPBACK_FAILED)
5846
5847static int
5848bnx2_test_loopback(struct bnx2 *bp)
5849{
5850 int rc = 0;
5851
5852 if (!netif_running(bp->dev))
5853 return BNX2_LOOPBACK_FAILED;
5854
5855 bnx2_reset_nic(bp, BNX2_DRV_MSG_CODE_RESET);
5856 spin_lock_bh(&bp->phy_lock);
Michael Chan9a120bc2008-05-16 22:17:45 -07005857 bnx2_init_phy(bp, 1);
Michael Chanbc5a0692006-01-23 16:13:22 -08005858 spin_unlock_bh(&bp->phy_lock);
5859 if (bnx2_run_loopback(bp, BNX2_MAC_LOOPBACK))
5860 rc |= BNX2_MAC_LOOPBACK_FAILED;
5861 if (bnx2_run_loopback(bp, BNX2_PHY_LOOPBACK))
5862 rc |= BNX2_PHY_LOOPBACK_FAILED;
5863 return rc;
5864}
5865
Michael Chanb6016b72005-05-26 13:03:09 -07005866#define NVRAM_SIZE 0x200
5867#define CRC32_RESIDUAL 0xdebb20e3
5868
5869static int
5870bnx2_test_nvram(struct bnx2 *bp)
5871{
Al Virob491edd2007-12-22 19:44:51 +00005872 __be32 buf[NVRAM_SIZE / 4];
Michael Chanb6016b72005-05-26 13:03:09 -07005873 u8 *data = (u8 *) buf;
5874 int rc = 0;
5875 u32 magic, csum;
5876
5877 if ((rc = bnx2_nvram_read(bp, 0, data, 4)) != 0)
5878 goto test_nvram_done;
5879
5880 magic = be32_to_cpu(buf[0]);
5881 if (magic != 0x669955aa) {
5882 rc = -ENODEV;
5883 goto test_nvram_done;
5884 }
5885
5886 if ((rc = bnx2_nvram_read(bp, 0x100, data, NVRAM_SIZE)) != 0)
5887 goto test_nvram_done;
5888
5889 csum = ether_crc_le(0x100, data);
5890 if (csum != CRC32_RESIDUAL) {
5891 rc = -ENODEV;
5892 goto test_nvram_done;
5893 }
5894
5895 csum = ether_crc_le(0x100, data + 0x100);
5896 if (csum != CRC32_RESIDUAL) {
5897 rc = -ENODEV;
5898 }
5899
5900test_nvram_done:
5901 return rc;
5902}
5903
5904static int
5905bnx2_test_link(struct bnx2 *bp)
5906{
5907 u32 bmsr;
5908
Michael Chan9f52b562008-10-09 12:21:46 -07005909 if (!netif_running(bp->dev))
5910 return -ENODEV;
5911
Michael Chan583c28e2008-01-21 19:51:35 -08005912 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP) {
Michael Chan489310a2007-10-10 16:16:31 -07005913 if (bp->link_up)
5914 return 0;
5915 return -ENODEV;
5916 }
Michael Chanc770a652005-08-25 15:38:39 -07005917 spin_lock_bh(&bp->phy_lock);
Michael Chan27a005b2007-05-03 13:23:41 -07005918 bnx2_enable_bmsr1(bp);
5919 bnx2_read_phy(bp, bp->mii_bmsr1, &bmsr);
5920 bnx2_read_phy(bp, bp->mii_bmsr1, &bmsr);
5921 bnx2_disable_bmsr1(bp);
Michael Chanc770a652005-08-25 15:38:39 -07005922 spin_unlock_bh(&bp->phy_lock);
Jeff Garzik6aa20a22006-09-13 13:24:59 -04005923
Michael Chanb6016b72005-05-26 13:03:09 -07005924 if (bmsr & BMSR_LSTATUS) {
5925 return 0;
5926 }
5927 return -ENODEV;
5928}
5929
5930static int
5931bnx2_test_intr(struct bnx2 *bp)
5932{
5933 int i;
Michael Chanb6016b72005-05-26 13:03:09 -07005934 u16 status_idx;
5935
5936 if (!netif_running(bp->dev))
5937 return -ENODEV;
5938
5939 status_idx = REG_RD(bp, BNX2_PCICFG_INT_ACK_CMD) & 0xffff;
5940
5941 /* This register is not touched during run-time. */
Michael Chanbf5295b2006-03-23 01:11:56 -08005942 REG_WR(bp, BNX2_HC_COMMAND, bp->hc_cmd | BNX2_HC_COMMAND_COAL_NOW);
Michael Chanb6016b72005-05-26 13:03:09 -07005943 REG_RD(bp, BNX2_HC_COMMAND);
5944
5945 for (i = 0; i < 10; i++) {
5946 if ((REG_RD(bp, BNX2_PCICFG_INT_ACK_CMD) & 0xffff) !=
5947 status_idx) {
5948
5949 break;
5950 }
5951
5952 msleep_interruptible(10);
5953 }
5954 if (i < 10)
5955 return 0;
5956
5957 return -ENODEV;
5958}
5959
Michael Chan38ea3682008-02-23 19:48:57 -08005960/* Determining link for parallel detection. */
Michael Chanb2fadea2008-01-21 17:07:06 -08005961static int
5962bnx2_5706_serdes_has_link(struct bnx2 *bp)
5963{
5964 u32 mode_ctl, an_dbg, exp;
5965
Michael Chan38ea3682008-02-23 19:48:57 -08005966 if (bp->phy_flags & BNX2_PHY_FLAG_NO_PARALLEL)
5967 return 0;
5968
Michael Chanb2fadea2008-01-21 17:07:06 -08005969 bnx2_write_phy(bp, MII_BNX2_MISC_SHADOW, MISC_SHDW_MODE_CTL);
5970 bnx2_read_phy(bp, MII_BNX2_MISC_SHADOW, &mode_ctl);
5971
5972 if (!(mode_ctl & MISC_SHDW_MODE_CTL_SIG_DET))
5973 return 0;
5974
5975 bnx2_write_phy(bp, MII_BNX2_MISC_SHADOW, MISC_SHDW_AN_DBG);
5976 bnx2_read_phy(bp, MII_BNX2_MISC_SHADOW, &an_dbg);
5977 bnx2_read_phy(bp, MII_BNX2_MISC_SHADOW, &an_dbg);
5978
Michael Chanf3014c0c2008-01-29 21:33:03 -08005979 if (an_dbg & (MISC_SHDW_AN_DBG_NOSYNC | MISC_SHDW_AN_DBG_RUDI_INVALID))
Michael Chanb2fadea2008-01-21 17:07:06 -08005980 return 0;
5981
5982 bnx2_write_phy(bp, MII_BNX2_DSP_ADDRESS, MII_EXPAND_REG1);
5983 bnx2_read_phy(bp, MII_BNX2_DSP_RW_PORT, &exp);
5984 bnx2_read_phy(bp, MII_BNX2_DSP_RW_PORT, &exp);
5985
5986 if (exp & MII_EXPAND_REG1_RUDI_C) /* receiving CONFIG */
5987 return 0;
5988
5989 return 1;
5990}
5991
Michael Chanb6016b72005-05-26 13:03:09 -07005992static void
Michael Chan48b01e22006-11-19 14:08:00 -08005993bnx2_5706_serdes_timer(struct bnx2 *bp)
5994{
Michael Chanb2fadea2008-01-21 17:07:06 -08005995 int check_link = 1;
5996
Michael Chan48b01e22006-11-19 14:08:00 -08005997 spin_lock(&bp->phy_lock);
Michael Chanb2fadea2008-01-21 17:07:06 -08005998 if (bp->serdes_an_pending) {
Michael Chan48b01e22006-11-19 14:08:00 -08005999 bp->serdes_an_pending--;
Michael Chanb2fadea2008-01-21 17:07:06 -08006000 check_link = 0;
6001 } else if ((bp->link_up == 0) && (bp->autoneg & AUTONEG_SPEED)) {
Michael Chan48b01e22006-11-19 14:08:00 -08006002 u32 bmcr;
6003
Benjamin Liac392ab2008-09-18 16:40:49 -07006004 bp->current_interval = BNX2_TIMER_INTERVAL;
Michael Chan48b01e22006-11-19 14:08:00 -08006005
Michael Chanca58c3a2007-05-03 13:22:52 -07006006 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chan48b01e22006-11-19 14:08:00 -08006007
6008 if (bmcr & BMCR_ANENABLE) {
Michael Chanb2fadea2008-01-21 17:07:06 -08006009 if (bnx2_5706_serdes_has_link(bp)) {
Michael Chan48b01e22006-11-19 14:08:00 -08006010 bmcr &= ~BMCR_ANENABLE;
6011 bmcr |= BMCR_SPEED1000 | BMCR_FULLDPLX;
Michael Chanca58c3a2007-05-03 13:22:52 -07006012 bnx2_write_phy(bp, bp->mii_bmcr, bmcr);
Michael Chan583c28e2008-01-21 19:51:35 -08006013 bp->phy_flags |= BNX2_PHY_FLAG_PARALLEL_DETECT;
Michael Chan48b01e22006-11-19 14:08:00 -08006014 }
6015 }
6016 }
6017 else if ((bp->link_up) && (bp->autoneg & AUTONEG_SPEED) &&
Michael Chan583c28e2008-01-21 19:51:35 -08006018 (bp->phy_flags & BNX2_PHY_FLAG_PARALLEL_DETECT)) {
Michael Chan48b01e22006-11-19 14:08:00 -08006019 u32 phy2;
6020
6021 bnx2_write_phy(bp, 0x17, 0x0f01);
6022 bnx2_read_phy(bp, 0x15, &phy2);
6023 if (phy2 & 0x20) {
6024 u32 bmcr;
6025
Michael Chanca58c3a2007-05-03 13:22:52 -07006026 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chan48b01e22006-11-19 14:08:00 -08006027 bmcr |= BMCR_ANENABLE;
Michael Chanca58c3a2007-05-03 13:22:52 -07006028 bnx2_write_phy(bp, bp->mii_bmcr, bmcr);
Michael Chan48b01e22006-11-19 14:08:00 -08006029
Michael Chan583c28e2008-01-21 19:51:35 -08006030 bp->phy_flags &= ~BNX2_PHY_FLAG_PARALLEL_DETECT;
Michael Chan48b01e22006-11-19 14:08:00 -08006031 }
6032 } else
Benjamin Liac392ab2008-09-18 16:40:49 -07006033 bp->current_interval = BNX2_TIMER_INTERVAL;
Michael Chan48b01e22006-11-19 14:08:00 -08006034
Michael Chana2724e22008-02-23 19:47:44 -08006035 if (check_link) {
Michael Chanb2fadea2008-01-21 17:07:06 -08006036 u32 val;
6037
6038 bnx2_write_phy(bp, MII_BNX2_MISC_SHADOW, MISC_SHDW_AN_DBG);
6039 bnx2_read_phy(bp, MII_BNX2_MISC_SHADOW, &val);
6040 bnx2_read_phy(bp, MII_BNX2_MISC_SHADOW, &val);
6041
Michael Chana2724e22008-02-23 19:47:44 -08006042 if (bp->link_up && (val & MISC_SHDW_AN_DBG_NOSYNC)) {
6043 if (!(bp->phy_flags & BNX2_PHY_FLAG_FORCED_DOWN)) {
6044 bnx2_5706s_force_link_dn(bp, 1);
6045 bp->phy_flags |= BNX2_PHY_FLAG_FORCED_DOWN;
6046 } else
6047 bnx2_set_link(bp);
6048 } else if (!bp->link_up && !(val & MISC_SHDW_AN_DBG_NOSYNC))
6049 bnx2_set_link(bp);
Michael Chanb2fadea2008-01-21 17:07:06 -08006050 }
Michael Chan48b01e22006-11-19 14:08:00 -08006051 spin_unlock(&bp->phy_lock);
6052}
6053
6054static void
Michael Chanf8dd0642006-11-19 14:08:29 -08006055bnx2_5708_serdes_timer(struct bnx2 *bp)
6056{
Michael Chan583c28e2008-01-21 19:51:35 -08006057 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
Michael Chan0d8a6572007-07-07 22:49:43 -07006058 return;
6059
Michael Chan583c28e2008-01-21 19:51:35 -08006060 if ((bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE) == 0) {
Michael Chanf8dd0642006-11-19 14:08:29 -08006061 bp->serdes_an_pending = 0;
6062 return;
6063 }
6064
6065 spin_lock(&bp->phy_lock);
6066 if (bp->serdes_an_pending)
6067 bp->serdes_an_pending--;
6068 else if ((bp->link_up == 0) && (bp->autoneg & AUTONEG_SPEED)) {
6069 u32 bmcr;
6070
Michael Chanca58c3a2007-05-03 13:22:52 -07006071 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chanf8dd0642006-11-19 14:08:29 -08006072 if (bmcr & BMCR_ANENABLE) {
Michael Chan605a9e22007-05-03 13:23:13 -07006073 bnx2_enable_forced_2g5(bp);
Michael Chan40105c02008-11-12 16:02:45 -08006074 bp->current_interval = BNX2_SERDES_FORCED_TIMEOUT;
Michael Chanf8dd0642006-11-19 14:08:29 -08006075 } else {
Michael Chan605a9e22007-05-03 13:23:13 -07006076 bnx2_disable_forced_2g5(bp);
Michael Chanf8dd0642006-11-19 14:08:29 -08006077 bp->serdes_an_pending = 2;
Benjamin Liac392ab2008-09-18 16:40:49 -07006078 bp->current_interval = BNX2_TIMER_INTERVAL;
Michael Chanf8dd0642006-11-19 14:08:29 -08006079 }
6080
6081 } else
Benjamin Liac392ab2008-09-18 16:40:49 -07006082 bp->current_interval = BNX2_TIMER_INTERVAL;
Michael Chanf8dd0642006-11-19 14:08:29 -08006083
6084 spin_unlock(&bp->phy_lock);
6085}
6086
6087static void
Michael Chanb6016b72005-05-26 13:03:09 -07006088bnx2_timer(unsigned long data)
6089{
6090 struct bnx2 *bp = (struct bnx2 *) data;
Michael Chanb6016b72005-05-26 13:03:09 -07006091
Michael Chancd339a02005-08-25 15:35:24 -07006092 if (!netif_running(bp->dev))
6093 return;
6094
Michael Chanb6016b72005-05-26 13:03:09 -07006095 if (atomic_read(&bp->intr_sem) != 0)
6096 goto bnx2_restart_timer;
6097
Michael Chanefba0182008-12-03 00:36:15 -08006098 if ((bp->flags & (BNX2_FLAG_USING_MSI | BNX2_FLAG_ONE_SHOT_MSI)) ==
6099 BNX2_FLAG_USING_MSI)
6100 bnx2_chk_missed_msi(bp);
6101
Michael Chandf149d72007-07-07 22:51:36 -07006102 bnx2_send_heart_beat(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07006103
Michael Chan2726d6e2008-01-29 21:35:05 -08006104 bp->stats_blk->stat_FwRxDrop =
6105 bnx2_reg_rd_ind(bp, BNX2_FW_RX_DROP_COUNT);
Michael Chancea94db2006-06-12 22:16:13 -07006106
Michael Chan02537b062007-06-04 21:24:07 -07006107 /* workaround occasional corrupted counters */
Michael Chan61d9e3f2009-08-21 16:20:46 +00006108 if ((bp->flags & BNX2_FLAG_BROKEN_STATS) && bp->stats_ticks)
Michael Chan02537b062007-06-04 21:24:07 -07006109 REG_WR(bp, BNX2_HC_COMMAND, bp->hc_cmd |
6110 BNX2_HC_COMMAND_STATS_NOW);
6111
Michael Chan583c28e2008-01-21 19:51:35 -08006112 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Michael Chanf8dd0642006-11-19 14:08:29 -08006113 if (CHIP_NUM(bp) == CHIP_NUM_5706)
6114 bnx2_5706_serdes_timer(bp);
Michael Chan27a005b2007-05-03 13:23:41 -07006115 else
Michael Chanf8dd0642006-11-19 14:08:29 -08006116 bnx2_5708_serdes_timer(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07006117 }
6118
6119bnx2_restart_timer:
Michael Chancd339a02005-08-25 15:35:24 -07006120 mod_timer(&bp->timer, jiffies + bp->current_interval);
Michael Chanb6016b72005-05-26 13:03:09 -07006121}
6122
Michael Chan8e6a72c2007-05-03 13:24:48 -07006123static int
6124bnx2_request_irq(struct bnx2 *bp)
6125{
Michael Chan6d866ff2007-12-20 19:56:09 -08006126 unsigned long flags;
Michael Chanb4b36042007-12-20 19:59:30 -08006127 struct bnx2_irq *irq;
6128 int rc = 0, i;
Michael Chan8e6a72c2007-05-03 13:24:48 -07006129
David S. Millerf86e82f2008-01-21 17:15:40 -08006130 if (bp->flags & BNX2_FLAG_USING_MSI_OR_MSIX)
Michael Chan6d866ff2007-12-20 19:56:09 -08006131 flags = 0;
6132 else
6133 flags = IRQF_SHARED;
Michael Chanb4b36042007-12-20 19:59:30 -08006134
6135 for (i = 0; i < bp->irq_nvecs; i++) {
6136 irq = &bp->irq_tbl[i];
Michael Chanc76c0472007-12-20 20:01:19 -08006137 rc = request_irq(irq->vector, irq->handler, flags, irq->name,
Michael Chanf0ea2e62008-06-19 16:41:57 -07006138 &bp->bnx2_napi[i]);
Michael Chanb4b36042007-12-20 19:59:30 -08006139 if (rc)
6140 break;
6141 irq->requested = 1;
6142 }
Michael Chan8e6a72c2007-05-03 13:24:48 -07006143 return rc;
6144}
6145
6146static void
Michael Chana29ba9d2010-12-31 11:03:14 -08006147__bnx2_free_irq(struct bnx2 *bp)
Michael Chan8e6a72c2007-05-03 13:24:48 -07006148{
Michael Chanb4b36042007-12-20 19:59:30 -08006149 struct bnx2_irq *irq;
6150 int i;
Michael Chan8e6a72c2007-05-03 13:24:48 -07006151
Michael Chanb4b36042007-12-20 19:59:30 -08006152 for (i = 0; i < bp->irq_nvecs; i++) {
6153 irq = &bp->irq_tbl[i];
6154 if (irq->requested)
Michael Chanf0ea2e62008-06-19 16:41:57 -07006155 free_irq(irq->vector, &bp->bnx2_napi[i]);
Michael Chanb4b36042007-12-20 19:59:30 -08006156 irq->requested = 0;
Michael Chan6d866ff2007-12-20 19:56:09 -08006157 }
Michael Chana29ba9d2010-12-31 11:03:14 -08006158}
6159
6160static void
6161bnx2_free_irq(struct bnx2 *bp)
6162{
6163
6164 __bnx2_free_irq(bp);
David S. Millerf86e82f2008-01-21 17:15:40 -08006165 if (bp->flags & BNX2_FLAG_USING_MSI)
Michael Chanb4b36042007-12-20 19:59:30 -08006166 pci_disable_msi(bp->pdev);
David S. Millerf86e82f2008-01-21 17:15:40 -08006167 else if (bp->flags & BNX2_FLAG_USING_MSIX)
Michael Chanb4b36042007-12-20 19:59:30 -08006168 pci_disable_msix(bp->pdev);
6169
David S. Millerf86e82f2008-01-21 17:15:40 -08006170 bp->flags &= ~(BNX2_FLAG_USING_MSI_OR_MSIX | BNX2_FLAG_ONE_SHOT_MSI);
Michael Chanb4b36042007-12-20 19:59:30 -08006171}
6172
6173static void
Michael Chan5e9ad9e2008-06-19 16:43:17 -07006174bnx2_enable_msix(struct bnx2 *bp, int msix_vecs)
Michael Chanb4b36042007-12-20 19:59:30 -08006175{
Michael Chan379b39a2010-07-19 14:15:03 +00006176 int i, total_vecs, rc;
Michael Chan57851d82007-12-20 20:01:44 -08006177 struct msix_entry msix_ent[BNX2_MAX_MSIX_VEC];
Michael Chan4e1d0de2008-12-16 20:27:45 -08006178 struct net_device *dev = bp->dev;
6179 const int len = sizeof(bp->irq_tbl[0].name);
Michael Chan57851d82007-12-20 20:01:44 -08006180
Michael Chanb4b36042007-12-20 19:59:30 -08006181 bnx2_setup_msix_tbl(bp);
6182 REG_WR(bp, BNX2_PCI_MSIX_CONTROL, BNX2_MAX_MSIX_HW_VEC - 1);
6183 REG_WR(bp, BNX2_PCI_MSIX_TBL_OFF_BIR, BNX2_PCI_GRC_WINDOW2_BASE);
6184 REG_WR(bp, BNX2_PCI_MSIX_PBA_OFF_BIT, BNX2_PCI_GRC_WINDOW3_BASE);
Michael Chan57851d82007-12-20 20:01:44 -08006185
Benjamin Lie2eb8e32010-01-08 00:51:21 -08006186 /* Need to flush the previous three writes to ensure MSI-X
6187 * is setup properly */
6188 REG_RD(bp, BNX2_PCI_MSIX_CONTROL);
6189
Michael Chan57851d82007-12-20 20:01:44 -08006190 for (i = 0; i < BNX2_MAX_MSIX_VEC; i++) {
6191 msix_ent[i].entry = i;
6192 msix_ent[i].vector = 0;
6193 }
6194
Michael Chan379b39a2010-07-19 14:15:03 +00006195 total_vecs = msix_vecs;
6196#ifdef BCM_CNIC
6197 total_vecs++;
6198#endif
6199 rc = -ENOSPC;
6200 while (total_vecs >= BNX2_MIN_MSIX_VEC) {
6201 rc = pci_enable_msix(bp->pdev, msix_ent, total_vecs);
6202 if (rc <= 0)
6203 break;
6204 if (rc > 0)
6205 total_vecs = rc;
6206 }
6207
Michael Chan57851d82007-12-20 20:01:44 -08006208 if (rc != 0)
6209 return;
6210
Michael Chan379b39a2010-07-19 14:15:03 +00006211 msix_vecs = total_vecs;
6212#ifdef BCM_CNIC
6213 msix_vecs--;
6214#endif
Michael Chan5e9ad9e2008-06-19 16:43:17 -07006215 bp->irq_nvecs = msix_vecs;
David S. Millerf86e82f2008-01-21 17:15:40 -08006216 bp->flags |= BNX2_FLAG_USING_MSIX | BNX2_FLAG_ONE_SHOT_MSI;
Michael Chan379b39a2010-07-19 14:15:03 +00006217 for (i = 0; i < total_vecs; i++) {
Michael Chan57851d82007-12-20 20:01:44 -08006218 bp->irq_tbl[i].vector = msix_ent[i].vector;
Michael Chan69010312009-03-18 18:11:51 -07006219 snprintf(bp->irq_tbl[i].name, len, "%s-%d", dev->name, i);
6220 bp->irq_tbl[i].handler = bnx2_msi_1shot;
6221 }
Michael Chan6d866ff2007-12-20 19:56:09 -08006222}
6223
Ben Hutchings657d92f2010-09-27 08:25:16 +00006224static int
Michael Chan6d866ff2007-12-20 19:56:09 -08006225bnx2_setup_int_mode(struct bnx2 *bp, int dis_msi)
6226{
Michael Chan5e9ad9e2008-06-19 16:43:17 -07006227 int cpus = num_online_cpus();
Benjamin Li706bf242008-07-18 17:55:11 -07006228 int msix_vecs = min(cpus + 1, RX_MAX_RINGS);
Michael Chan5e9ad9e2008-06-19 16:43:17 -07006229
Michael Chan6d866ff2007-12-20 19:56:09 -08006230 bp->irq_tbl[0].handler = bnx2_interrupt;
6231 strcpy(bp->irq_tbl[0].name, bp->dev->name);
Michael Chanb4b36042007-12-20 19:59:30 -08006232 bp->irq_nvecs = 1;
6233 bp->irq_tbl[0].vector = bp->pdev->irq;
Michael Chan6d866ff2007-12-20 19:56:09 -08006234
Michael Chan3d5f3a72010-07-03 20:42:15 +00006235 if ((bp->flags & BNX2_FLAG_MSIX_CAP) && !dis_msi)
Michael Chan5e9ad9e2008-06-19 16:43:17 -07006236 bnx2_enable_msix(bp, msix_vecs);
Michael Chanb4b36042007-12-20 19:59:30 -08006237
David S. Millerf86e82f2008-01-21 17:15:40 -08006238 if ((bp->flags & BNX2_FLAG_MSI_CAP) && !dis_msi &&
6239 !(bp->flags & BNX2_FLAG_USING_MSIX)) {
Michael Chan6d866ff2007-12-20 19:56:09 -08006240 if (pci_enable_msi(bp->pdev) == 0) {
David S. Millerf86e82f2008-01-21 17:15:40 -08006241 bp->flags |= BNX2_FLAG_USING_MSI;
Michael Chan6d866ff2007-12-20 19:56:09 -08006242 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
David S. Millerf86e82f2008-01-21 17:15:40 -08006243 bp->flags |= BNX2_FLAG_ONE_SHOT_MSI;
Michael Chan6d866ff2007-12-20 19:56:09 -08006244 bp->irq_tbl[0].handler = bnx2_msi_1shot;
6245 } else
6246 bp->irq_tbl[0].handler = bnx2_msi;
Michael Chanb4b36042007-12-20 19:59:30 -08006247
6248 bp->irq_tbl[0].vector = bp->pdev->irq;
Michael Chan6d866ff2007-12-20 19:56:09 -08006249 }
6250 }
Benjamin Li706bf242008-07-18 17:55:11 -07006251
6252 bp->num_tx_rings = rounddown_pow_of_two(bp->irq_nvecs);
Ben Hutchings657d92f2010-09-27 08:25:16 +00006253 netif_set_real_num_tx_queues(bp->dev, bp->num_tx_rings);
Benjamin Li706bf242008-07-18 17:55:11 -07006254
Michael Chan5e9ad9e2008-06-19 16:43:17 -07006255 bp->num_rx_rings = bp->irq_nvecs;
Ben Hutchings657d92f2010-09-27 08:25:16 +00006256 return netif_set_real_num_rx_queues(bp->dev, bp->num_rx_rings);
Michael Chan8e6a72c2007-05-03 13:24:48 -07006257}
6258
Michael Chanb6016b72005-05-26 13:03:09 -07006259/* Called with rtnl_lock */
6260static int
6261bnx2_open(struct net_device *dev)
6262{
Michael Chan972ec0d2006-01-23 16:12:43 -08006263 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006264 int rc;
6265
Michael Chan1b2f9222007-05-03 13:20:19 -07006266 netif_carrier_off(dev);
6267
Pavel Machek829ca9a2005-09-03 15:56:56 -07006268 bnx2_set_power_state(bp, PCI_D0);
Michael Chanb6016b72005-05-26 13:03:09 -07006269 bnx2_disable_int(bp);
6270
Ben Hutchings657d92f2010-09-27 08:25:16 +00006271 rc = bnx2_setup_int_mode(bp, disable_msi);
6272 if (rc)
6273 goto open_err;
Benjamin Li4327ba42010-03-23 13:13:11 +00006274 bnx2_init_napi(bp);
Michael Chan35efa7c2007-12-20 19:56:37 -08006275 bnx2_napi_enable(bp);
Michael Chan35e90102008-06-19 16:37:42 -07006276 rc = bnx2_alloc_mem(bp);
Michael Chan2739a8b2008-06-19 16:44:10 -07006277 if (rc)
6278 goto open_err;
Michael Chan35e90102008-06-19 16:37:42 -07006279
Michael Chan8e6a72c2007-05-03 13:24:48 -07006280 rc = bnx2_request_irq(bp);
Michael Chan2739a8b2008-06-19 16:44:10 -07006281 if (rc)
6282 goto open_err;
Michael Chanb6016b72005-05-26 13:03:09 -07006283
Michael Chan9a120bc2008-05-16 22:17:45 -07006284 rc = bnx2_init_nic(bp, 1);
Michael Chan2739a8b2008-06-19 16:44:10 -07006285 if (rc)
6286 goto open_err;
Jeff Garzik6aa20a22006-09-13 13:24:59 -04006287
Michael Chancd339a02005-08-25 15:35:24 -07006288 mod_timer(&bp->timer, jiffies + bp->current_interval);
Michael Chanb6016b72005-05-26 13:03:09 -07006289
6290 atomic_set(&bp->intr_sem, 0);
6291
Michael Chan354fcd72010-01-17 07:30:44 +00006292 memset(bp->temp_stats_blk, 0, sizeof(struct statistics_block));
6293
Michael Chanb6016b72005-05-26 13:03:09 -07006294 bnx2_enable_int(bp);
6295
David S. Millerf86e82f2008-01-21 17:15:40 -08006296 if (bp->flags & BNX2_FLAG_USING_MSI) {
Michael Chanb6016b72005-05-26 13:03:09 -07006297 /* Test MSI to make sure it is working
6298 * If MSI test fails, go back to INTx mode
6299 */
6300 if (bnx2_test_intr(bp) != 0) {
Joe Perches3a9c6a42010-02-17 15:01:51 +00006301 netdev_warn(bp->dev, "No interrupt was generated using MSI, switching to INTx mode. Please report this failure to the PCI maintainer and include system chipset information.\n");
Michael Chanb6016b72005-05-26 13:03:09 -07006302
6303 bnx2_disable_int(bp);
Michael Chan8e6a72c2007-05-03 13:24:48 -07006304 bnx2_free_irq(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07006305
Michael Chan6d866ff2007-12-20 19:56:09 -08006306 bnx2_setup_int_mode(bp, 1);
6307
Michael Chan9a120bc2008-05-16 22:17:45 -07006308 rc = bnx2_init_nic(bp, 0);
Michael Chanb6016b72005-05-26 13:03:09 -07006309
Michael Chan8e6a72c2007-05-03 13:24:48 -07006310 if (!rc)
6311 rc = bnx2_request_irq(bp);
6312
Michael Chanb6016b72005-05-26 13:03:09 -07006313 if (rc) {
Michael Chanb6016b72005-05-26 13:03:09 -07006314 del_timer_sync(&bp->timer);
Michael Chan2739a8b2008-06-19 16:44:10 -07006315 goto open_err;
Michael Chanb6016b72005-05-26 13:03:09 -07006316 }
6317 bnx2_enable_int(bp);
6318 }
6319 }
David S. Millerf86e82f2008-01-21 17:15:40 -08006320 if (bp->flags & BNX2_FLAG_USING_MSI)
Joe Perches3a9c6a42010-02-17 15:01:51 +00006321 netdev_info(dev, "using MSI\n");
David S. Millerf86e82f2008-01-21 17:15:40 -08006322 else if (bp->flags & BNX2_FLAG_USING_MSIX)
Joe Perches3a9c6a42010-02-17 15:01:51 +00006323 netdev_info(dev, "using MSIX\n");
Michael Chanb6016b72005-05-26 13:03:09 -07006324
Benjamin Li706bf242008-07-18 17:55:11 -07006325 netif_tx_start_all_queues(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006326
6327 return 0;
Michael Chan2739a8b2008-06-19 16:44:10 -07006328
6329open_err:
6330 bnx2_napi_disable(bp);
6331 bnx2_free_skbs(bp);
6332 bnx2_free_irq(bp);
6333 bnx2_free_mem(bp);
Michael Chanf048fa92010-06-01 15:05:36 +00006334 bnx2_del_napi(bp);
Michael Chan2739a8b2008-06-19 16:44:10 -07006335 return rc;
Michael Chanb6016b72005-05-26 13:03:09 -07006336}
6337
6338static void
David Howellsc4028952006-11-22 14:57:56 +00006339bnx2_reset_task(struct work_struct *work)
Michael Chanb6016b72005-05-26 13:03:09 -07006340{
David Howellsc4028952006-11-22 14:57:56 +00006341 struct bnx2 *bp = container_of(work, struct bnx2, reset_task);
Michael Chanb6016b72005-05-26 13:03:09 -07006342
Michael Chan51bf6bb2009-12-03 09:46:31 +00006343 rtnl_lock();
6344 if (!netif_running(bp->dev)) {
6345 rtnl_unlock();
Michael Chanafdc08b2005-08-25 15:34:29 -07006346 return;
Michael Chan51bf6bb2009-12-03 09:46:31 +00006347 }
Michael Chanafdc08b2005-08-25 15:34:29 -07006348
Michael Chan212f9932010-04-27 11:28:10 +00006349 bnx2_netif_stop(bp, true);
Michael Chanb6016b72005-05-26 13:03:09 -07006350
Michael Chan9a120bc2008-05-16 22:17:45 -07006351 bnx2_init_nic(bp, 1);
Michael Chanb6016b72005-05-26 13:03:09 -07006352
6353 atomic_set(&bp->intr_sem, 1);
Michael Chan212f9932010-04-27 11:28:10 +00006354 bnx2_netif_start(bp, true);
Michael Chan51bf6bb2009-12-03 09:46:31 +00006355 rtnl_unlock();
Michael Chanb6016b72005-05-26 13:03:09 -07006356}
6357
6358static void
Michael Chan20175c52009-12-03 09:46:32 +00006359bnx2_dump_state(struct bnx2 *bp)
6360{
6361 struct net_device *dev = bp->dev;
Jeffrey Huangecdbf6e2011-07-13 17:24:21 +00006362 u32 val1, val2;
Michael Chan20175c52009-12-03 09:46:32 +00006363
Michael Chan5804a8f2010-07-03 20:42:17 +00006364 pci_read_config_dword(bp->pdev, PCI_COMMAND, &val1);
6365 netdev_err(dev, "DEBUG: intr_sem[%x] PCI_CMD[%08x]\n",
6366 atomic_read(&bp->intr_sem), val1);
6367 pci_read_config_dword(bp->pdev, bp->pm_cap + PCI_PM_CTRL, &val1);
6368 pci_read_config_dword(bp->pdev, BNX2_PCICFG_MISC_CONFIG, &val2);
6369 netdev_err(dev, "DEBUG: PCI_PM[%08x] PCI_MISC_CFG[%08x]\n", val1, val2);
Eddie Waib98eba52010-05-17 17:32:56 -07006370 netdev_err(dev, "DEBUG: EMAC_TX_STATUS[%08x] EMAC_RX_STATUS[%08x]\n",
Joe Perches3a9c6a42010-02-17 15:01:51 +00006371 REG_RD(bp, BNX2_EMAC_TX_STATUS),
Eddie Waib98eba52010-05-17 17:32:56 -07006372 REG_RD(bp, BNX2_EMAC_RX_STATUS));
6373 netdev_err(dev, "DEBUG: RPM_MGMT_PKT_CTRL[%08x]\n",
Joe Perches3a9c6a42010-02-17 15:01:51 +00006374 REG_RD(bp, BNX2_RPM_MGMT_PKT_CTRL));
Joe Perches3a9c6a42010-02-17 15:01:51 +00006375 netdev_err(dev, "DEBUG: HC_STATS_INTERRUPT_STATUS[%08x]\n",
6376 REG_RD(bp, BNX2_HC_STATS_INTERRUPT_STATUS));
Michael Chan20175c52009-12-03 09:46:32 +00006377 if (bp->flags & BNX2_FLAG_USING_MSIX)
Joe Perches3a9c6a42010-02-17 15:01:51 +00006378 netdev_err(dev, "DEBUG: PBA[%08x]\n",
6379 REG_RD(bp, BNX2_PCI_GRC_WINDOW3_BASE));
Michael Chan20175c52009-12-03 09:46:32 +00006380}
6381
6382static void
Michael Chanb6016b72005-05-26 13:03:09 -07006383bnx2_tx_timeout(struct net_device *dev)
6384{
Michael Chan972ec0d2006-01-23 16:12:43 -08006385 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006386
Michael Chan20175c52009-12-03 09:46:32 +00006387 bnx2_dump_state(bp);
Jeffrey Huangecdbf6e2011-07-13 17:24:21 +00006388 bnx2_dump_mcp_state(bp);
Michael Chan20175c52009-12-03 09:46:32 +00006389
Michael Chanb6016b72005-05-26 13:03:09 -07006390 /* This allows the netif to be shutdown gracefully before resetting */
6391 schedule_work(&bp->reset_task);
6392}
6393
Herbert Xu932ff272006-06-09 12:20:56 -07006394/* Called with netif_tx_lock.
Michael Chan2f8af122006-08-15 01:39:10 -07006395 * bnx2_tx_int() runs without netif_tx_lock unless it needs to call
6396 * netif_wake_queue().
Michael Chanb6016b72005-05-26 13:03:09 -07006397 */
Stephen Hemminger613573252009-08-31 19:50:58 +00006398static netdev_tx_t
Michael Chanb6016b72005-05-26 13:03:09 -07006399bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev)
6400{
Michael Chan972ec0d2006-01-23 16:12:43 -08006401 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006402 dma_addr_t mapping;
6403 struct tx_bd *txbd;
Benjamin Li3d16af82008-10-09 12:26:41 -07006404 struct sw_tx_bd *tx_buf;
Michael Chanb6016b72005-05-26 13:03:09 -07006405 u32 len, vlan_tag_flags, last_frag, mss;
6406 u16 prod, ring_prod;
6407 int i;
Benjamin Li706bf242008-07-18 17:55:11 -07006408 struct bnx2_napi *bnapi;
6409 struct bnx2_tx_ring_info *txr;
6410 struct netdev_queue *txq;
6411
6412 /* Determine which tx ring we will be placed on */
6413 i = skb_get_queue_mapping(skb);
6414 bnapi = &bp->bnx2_napi[i];
6415 txr = &bnapi->tx_ring;
6416 txq = netdev_get_tx_queue(dev, i);
Michael Chanb6016b72005-05-26 13:03:09 -07006417
Michael Chan35e90102008-06-19 16:37:42 -07006418 if (unlikely(bnx2_tx_avail(bp, txr) <
Michael Chana550c992007-12-20 19:56:59 -08006419 (skb_shinfo(skb)->nr_frags + 1))) {
Benjamin Li706bf242008-07-18 17:55:11 -07006420 netif_tx_stop_queue(txq);
Joe Perches3a9c6a42010-02-17 15:01:51 +00006421 netdev_err(dev, "BUG! Tx ring full when queue awake!\n");
Michael Chanb6016b72005-05-26 13:03:09 -07006422
6423 return NETDEV_TX_BUSY;
6424 }
6425 len = skb_headlen(skb);
Michael Chan35e90102008-06-19 16:37:42 -07006426 prod = txr->tx_prod;
Michael Chanb6016b72005-05-26 13:03:09 -07006427 ring_prod = TX_RING_IDX(prod);
6428
6429 vlan_tag_flags = 0;
Patrick McHardy84fa7932006-08-29 16:44:56 -07006430 if (skb->ip_summed == CHECKSUM_PARTIAL) {
Michael Chanb6016b72005-05-26 13:03:09 -07006431 vlan_tag_flags |= TX_BD_FLAGS_TCP_UDP_CKSUM;
6432 }
6433
Jesse Grosseab6d182010-10-20 13:56:03 +00006434 if (vlan_tx_tag_present(skb)) {
Michael Chanb6016b72005-05-26 13:03:09 -07006435 vlan_tag_flags |=
6436 (TX_BD_FLAGS_VLAN_TAG | (vlan_tx_tag_get(skb) << 16));
6437 }
Jesse Gross7d0fd212010-10-20 13:56:09 +00006438
Michael Chanfde82052007-05-03 17:23:35 -07006439 if ((mss = skb_shinfo(skb)->gso_size)) {
Michael Chana1efb4b2008-10-09 12:24:39 -07006440 u32 tcp_opt_len;
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -07006441 struct iphdr *iph;
Michael Chanb6016b72005-05-26 13:03:09 -07006442
Michael Chanb6016b72005-05-26 13:03:09 -07006443 vlan_tag_flags |= TX_BD_FLAGS_SW_LSO;
6444
Michael Chan4666f872007-05-03 13:22:28 -07006445 tcp_opt_len = tcp_optlen(skb);
Arnaldo Carvalho de Meloab6a5bb2007-03-18 17:43:48 -07006446
Michael Chan4666f872007-05-03 13:22:28 -07006447 if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6) {
6448 u32 tcp_off = skb_transport_offset(skb) -
6449 sizeof(struct ipv6hdr) - ETH_HLEN;
Michael Chanb6016b72005-05-26 13:03:09 -07006450
Michael Chan4666f872007-05-03 13:22:28 -07006451 vlan_tag_flags |= ((tcp_opt_len >> 2) << 8) |
6452 TX_BD_FLAGS_SW_FLAGS;
6453 if (likely(tcp_off == 0))
6454 vlan_tag_flags &= ~TX_BD_FLAGS_TCP6_OFF0_MSK;
6455 else {
6456 tcp_off >>= 3;
6457 vlan_tag_flags |= ((tcp_off & 0x3) <<
6458 TX_BD_FLAGS_TCP6_OFF0_SHL) |
6459 ((tcp_off & 0x10) <<
6460 TX_BD_FLAGS_TCP6_OFF4_SHL);
6461 mss |= (tcp_off & 0xc) << TX_BD_TCP6_OFF2_SHL;
6462 }
6463 } else {
Michael Chan4666f872007-05-03 13:22:28 -07006464 iph = ip_hdr(skb);
Michael Chan4666f872007-05-03 13:22:28 -07006465 if (tcp_opt_len || (iph->ihl > 5)) {
6466 vlan_tag_flags |= ((iph->ihl - 5) +
6467 (tcp_opt_len >> 2)) << 8;
6468 }
Michael Chanb6016b72005-05-26 13:03:09 -07006469 }
Michael Chan4666f872007-05-03 13:22:28 -07006470 } else
Michael Chanb6016b72005-05-26 13:03:09 -07006471 mss = 0;
Michael Chanb6016b72005-05-26 13:03:09 -07006472
Stanislaw Gruszka36227e82010-07-15 04:25:50 +00006473 mapping = dma_map_single(&bp->pdev->dev, skb->data, len, PCI_DMA_TODEVICE);
6474 if (dma_mapping_error(&bp->pdev->dev, mapping)) {
Benjamin Li3d16af82008-10-09 12:26:41 -07006475 dev_kfree_skb(skb);
6476 return NETDEV_TX_OK;
6477 }
6478
Michael Chan35e90102008-06-19 16:37:42 -07006479 tx_buf = &txr->tx_buf_ring[ring_prod];
Michael Chanb6016b72005-05-26 13:03:09 -07006480 tx_buf->skb = skb;
FUJITA Tomonori1a4ccc22010-04-01 16:56:57 +00006481 dma_unmap_addr_set(tx_buf, mapping, mapping);
Michael Chanb6016b72005-05-26 13:03:09 -07006482
Michael Chan35e90102008-06-19 16:37:42 -07006483 txbd = &txr->tx_desc_ring[ring_prod];
Michael Chanb6016b72005-05-26 13:03:09 -07006484
6485 txbd->tx_bd_haddr_hi = (u64) mapping >> 32;
6486 txbd->tx_bd_haddr_lo = (u64) mapping & 0xffffffff;
6487 txbd->tx_bd_mss_nbytes = len | (mss << 16);
6488 txbd->tx_bd_vlan_tag_flags = vlan_tag_flags | TX_BD_FLAGS_START;
6489
6490 last_frag = skb_shinfo(skb)->nr_frags;
Eric Dumazetd62fda02009-05-12 20:48:02 +00006491 tx_buf->nr_frags = last_frag;
6492 tx_buf->is_gso = skb_is_gso(skb);
Michael Chanb6016b72005-05-26 13:03:09 -07006493
6494 for (i = 0; i < last_frag; i++) {
6495 skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
6496
6497 prod = NEXT_TX_BD(prod);
6498 ring_prod = TX_RING_IDX(prod);
Michael Chan35e90102008-06-19 16:37:42 -07006499 txbd = &txr->tx_desc_ring[ring_prod];
Michael Chanb6016b72005-05-26 13:03:09 -07006500
6501 len = frag->size;
Stanislaw Gruszka36227e82010-07-15 04:25:50 +00006502 mapping = dma_map_page(&bp->pdev->dev, frag->page, frag->page_offset,
6503 len, PCI_DMA_TODEVICE);
6504 if (dma_mapping_error(&bp->pdev->dev, mapping))
Alexander Duycke95524a2009-12-02 16:47:57 +00006505 goto dma_error;
FUJITA Tomonori1a4ccc22010-04-01 16:56:57 +00006506 dma_unmap_addr_set(&txr->tx_buf_ring[ring_prod], mapping,
Alexander Duycke95524a2009-12-02 16:47:57 +00006507 mapping);
Michael Chanb6016b72005-05-26 13:03:09 -07006508
6509 txbd->tx_bd_haddr_hi = (u64) mapping >> 32;
6510 txbd->tx_bd_haddr_lo = (u64) mapping & 0xffffffff;
6511 txbd->tx_bd_mss_nbytes = len | (mss << 16);
6512 txbd->tx_bd_vlan_tag_flags = vlan_tag_flags;
6513
6514 }
6515 txbd->tx_bd_vlan_tag_flags |= TX_BD_FLAGS_END;
6516
6517 prod = NEXT_TX_BD(prod);
Michael Chan35e90102008-06-19 16:37:42 -07006518 txr->tx_prod_bseq += skb->len;
Michael Chanb6016b72005-05-26 13:03:09 -07006519
Michael Chan35e90102008-06-19 16:37:42 -07006520 REG_WR16(bp, txr->tx_bidx_addr, prod);
6521 REG_WR(bp, txr->tx_bseq_addr, txr->tx_prod_bseq);
Michael Chanb6016b72005-05-26 13:03:09 -07006522
6523 mmiowb();
6524
Michael Chan35e90102008-06-19 16:37:42 -07006525 txr->tx_prod = prod;
Michael Chanb6016b72005-05-26 13:03:09 -07006526
Michael Chan35e90102008-06-19 16:37:42 -07006527 if (unlikely(bnx2_tx_avail(bp, txr) <= MAX_SKB_FRAGS)) {
Benjamin Li706bf242008-07-18 17:55:11 -07006528 netif_tx_stop_queue(txq);
Michael Chan11848b962010-07-19 14:15:04 +00006529
6530 /* netif_tx_stop_queue() must be done before checking
6531 * tx index in bnx2_tx_avail() below, because in
6532 * bnx2_tx_int(), we update tx index before checking for
6533 * netif_tx_queue_stopped().
6534 */
6535 smp_mb();
Michael Chan35e90102008-06-19 16:37:42 -07006536 if (bnx2_tx_avail(bp, txr) > bp->tx_wake_thresh)
Benjamin Li706bf242008-07-18 17:55:11 -07006537 netif_tx_wake_queue(txq);
Michael Chanb6016b72005-05-26 13:03:09 -07006538 }
6539
6540 return NETDEV_TX_OK;
Alexander Duycke95524a2009-12-02 16:47:57 +00006541dma_error:
6542 /* save value of frag that failed */
6543 last_frag = i;
6544
6545 /* start back at beginning and unmap skb */
6546 prod = txr->tx_prod;
6547 ring_prod = TX_RING_IDX(prod);
6548 tx_buf = &txr->tx_buf_ring[ring_prod];
6549 tx_buf->skb = NULL;
Stanislaw Gruszka36227e82010-07-15 04:25:50 +00006550 dma_unmap_single(&bp->pdev->dev, dma_unmap_addr(tx_buf, mapping),
Alexander Duycke95524a2009-12-02 16:47:57 +00006551 skb_headlen(skb), PCI_DMA_TODEVICE);
6552
6553 /* unmap remaining mapped pages */
6554 for (i = 0; i < last_frag; i++) {
6555 prod = NEXT_TX_BD(prod);
6556 ring_prod = TX_RING_IDX(prod);
6557 tx_buf = &txr->tx_buf_ring[ring_prod];
Stanislaw Gruszka36227e82010-07-15 04:25:50 +00006558 dma_unmap_page(&bp->pdev->dev, dma_unmap_addr(tx_buf, mapping),
Alexander Duycke95524a2009-12-02 16:47:57 +00006559 skb_shinfo(skb)->frags[i].size,
6560 PCI_DMA_TODEVICE);
6561 }
6562
6563 dev_kfree_skb(skb);
6564 return NETDEV_TX_OK;
Michael Chanb6016b72005-05-26 13:03:09 -07006565}
6566
6567/* Called with rtnl_lock */
6568static int
6569bnx2_close(struct net_device *dev)
6570{
Michael Chan972ec0d2006-01-23 16:12:43 -08006571 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006572
David S. Miller4bb073c2008-06-12 02:22:02 -07006573 cancel_work_sync(&bp->reset_task);
Michael Chanafdc08b2005-08-25 15:34:29 -07006574
Stephen Hemmingerbea33482007-10-03 16:41:36 -07006575 bnx2_disable_int_sync(bp);
Michael Chan35efa7c2007-12-20 19:56:37 -08006576 bnx2_napi_disable(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07006577 del_timer_sync(&bp->timer);
Michael Chan74bf4ba2008-10-09 12:21:08 -07006578 bnx2_shutdown_chip(bp);
Michael Chan8e6a72c2007-05-03 13:24:48 -07006579 bnx2_free_irq(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07006580 bnx2_free_skbs(bp);
6581 bnx2_free_mem(bp);
Michael Chanf048fa92010-06-01 15:05:36 +00006582 bnx2_del_napi(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07006583 bp->link_up = 0;
6584 netif_carrier_off(bp->dev);
Pavel Machek829ca9a2005-09-03 15:56:56 -07006585 bnx2_set_power_state(bp, PCI_D3hot);
Michael Chanb6016b72005-05-26 13:03:09 -07006586 return 0;
6587}
6588
Michael Chan354fcd72010-01-17 07:30:44 +00006589static void
6590bnx2_save_stats(struct bnx2 *bp)
6591{
6592 u32 *hw_stats = (u32 *) bp->stats_blk;
6593 u32 *temp_stats = (u32 *) bp->temp_stats_blk;
6594 int i;
6595
6596 /* The 1st 10 counters are 64-bit counters */
6597 for (i = 0; i < 20; i += 2) {
6598 u32 hi;
6599 u64 lo;
6600
Patrick Rabauc9885fe2010-02-15 19:42:11 +00006601 hi = temp_stats[i] + hw_stats[i];
6602 lo = (u64) temp_stats[i + 1] + (u64) hw_stats[i + 1];
Michael Chan354fcd72010-01-17 07:30:44 +00006603 if (lo > 0xffffffff)
6604 hi++;
Patrick Rabauc9885fe2010-02-15 19:42:11 +00006605 temp_stats[i] = hi;
6606 temp_stats[i + 1] = lo & 0xffffffff;
Michael Chan354fcd72010-01-17 07:30:44 +00006607 }
6608
6609 for ( ; i < sizeof(struct statistics_block) / 4; i++)
Patrick Rabauc9885fe2010-02-15 19:42:11 +00006610 temp_stats[i] += hw_stats[i];
Michael Chan354fcd72010-01-17 07:30:44 +00006611}
6612
Eric Dumazet5d07bf22010-07-08 04:08:43 +00006613#define GET_64BIT_NET_STATS64(ctr) \
6614 (((u64) (ctr##_hi) << 32) + (u64) (ctr##_lo))
Michael Chanb6016b72005-05-26 13:03:09 -07006615
Michael Chana4743052010-01-17 07:30:43 +00006616#define GET_64BIT_NET_STATS(ctr) \
Michael Chan354fcd72010-01-17 07:30:44 +00006617 GET_64BIT_NET_STATS64(bp->stats_blk->ctr) + \
6618 GET_64BIT_NET_STATS64(bp->temp_stats_blk->ctr)
Michael Chanb6016b72005-05-26 13:03:09 -07006619
Michael Chana4743052010-01-17 07:30:43 +00006620#define GET_32BIT_NET_STATS(ctr) \
Michael Chan354fcd72010-01-17 07:30:44 +00006621 (unsigned long) (bp->stats_blk->ctr + \
6622 bp->temp_stats_blk->ctr)
Michael Chana4743052010-01-17 07:30:43 +00006623
Eric Dumazet5d07bf22010-07-08 04:08:43 +00006624static struct rtnl_link_stats64 *
6625bnx2_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *net_stats)
Michael Chanb6016b72005-05-26 13:03:09 -07006626{
Michael Chan972ec0d2006-01-23 16:12:43 -08006627 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006628
Eric Dumazet5d07bf22010-07-08 04:08:43 +00006629 if (bp->stats_blk == NULL)
Michael Chanb6016b72005-05-26 13:03:09 -07006630 return net_stats;
Eric Dumazet5d07bf22010-07-08 04:08:43 +00006631
Michael Chanb6016b72005-05-26 13:03:09 -07006632 net_stats->rx_packets =
Michael Chana4743052010-01-17 07:30:43 +00006633 GET_64BIT_NET_STATS(stat_IfHCInUcastPkts) +
6634 GET_64BIT_NET_STATS(stat_IfHCInMulticastPkts) +
6635 GET_64BIT_NET_STATS(stat_IfHCInBroadcastPkts);
Michael Chanb6016b72005-05-26 13:03:09 -07006636
6637 net_stats->tx_packets =
Michael Chana4743052010-01-17 07:30:43 +00006638 GET_64BIT_NET_STATS(stat_IfHCOutUcastPkts) +
6639 GET_64BIT_NET_STATS(stat_IfHCOutMulticastPkts) +
6640 GET_64BIT_NET_STATS(stat_IfHCOutBroadcastPkts);
Michael Chanb6016b72005-05-26 13:03:09 -07006641
6642 net_stats->rx_bytes =
Michael Chana4743052010-01-17 07:30:43 +00006643 GET_64BIT_NET_STATS(stat_IfHCInOctets);
Michael Chanb6016b72005-05-26 13:03:09 -07006644
6645 net_stats->tx_bytes =
Michael Chana4743052010-01-17 07:30:43 +00006646 GET_64BIT_NET_STATS(stat_IfHCOutOctets);
Michael Chanb6016b72005-05-26 13:03:09 -07006647
Jeff Garzik6aa20a22006-09-13 13:24:59 -04006648 net_stats->multicast =
Michael Chan6fdae992010-07-19 14:15:02 +00006649 GET_64BIT_NET_STATS(stat_IfHCInMulticastPkts);
Michael Chanb6016b72005-05-26 13:03:09 -07006650
Jeff Garzik6aa20a22006-09-13 13:24:59 -04006651 net_stats->collisions =
Michael Chana4743052010-01-17 07:30:43 +00006652 GET_32BIT_NET_STATS(stat_EtherStatsCollisions);
Michael Chanb6016b72005-05-26 13:03:09 -07006653
Jeff Garzik6aa20a22006-09-13 13:24:59 -04006654 net_stats->rx_length_errors =
Michael Chana4743052010-01-17 07:30:43 +00006655 GET_32BIT_NET_STATS(stat_EtherStatsUndersizePkts) +
6656 GET_32BIT_NET_STATS(stat_EtherStatsOverrsizePkts);
Michael Chanb6016b72005-05-26 13:03:09 -07006657
Jeff Garzik6aa20a22006-09-13 13:24:59 -04006658 net_stats->rx_over_errors =
Michael Chana4743052010-01-17 07:30:43 +00006659 GET_32BIT_NET_STATS(stat_IfInFTQDiscards) +
6660 GET_32BIT_NET_STATS(stat_IfInMBUFDiscards);
Michael Chanb6016b72005-05-26 13:03:09 -07006661
Jeff Garzik6aa20a22006-09-13 13:24:59 -04006662 net_stats->rx_frame_errors =
Michael Chana4743052010-01-17 07:30:43 +00006663 GET_32BIT_NET_STATS(stat_Dot3StatsAlignmentErrors);
Michael Chanb6016b72005-05-26 13:03:09 -07006664
Jeff Garzik6aa20a22006-09-13 13:24:59 -04006665 net_stats->rx_crc_errors =
Michael Chana4743052010-01-17 07:30:43 +00006666 GET_32BIT_NET_STATS(stat_Dot3StatsFCSErrors);
Michael Chanb6016b72005-05-26 13:03:09 -07006667
6668 net_stats->rx_errors = net_stats->rx_length_errors +
6669 net_stats->rx_over_errors + net_stats->rx_frame_errors +
6670 net_stats->rx_crc_errors;
6671
6672 net_stats->tx_aborted_errors =
Michael Chana4743052010-01-17 07:30:43 +00006673 GET_32BIT_NET_STATS(stat_Dot3StatsExcessiveCollisions) +
6674 GET_32BIT_NET_STATS(stat_Dot3StatsLateCollisions);
Michael Chanb6016b72005-05-26 13:03:09 -07006675
Michael Chan5b0c76a2005-11-04 08:45:49 -08006676 if ((CHIP_NUM(bp) == CHIP_NUM_5706) ||
6677 (CHIP_ID(bp) == CHIP_ID_5708_A0))
Michael Chanb6016b72005-05-26 13:03:09 -07006678 net_stats->tx_carrier_errors = 0;
6679 else {
6680 net_stats->tx_carrier_errors =
Michael Chana4743052010-01-17 07:30:43 +00006681 GET_32BIT_NET_STATS(stat_Dot3StatsCarrierSenseErrors);
Michael Chanb6016b72005-05-26 13:03:09 -07006682 }
6683
6684 net_stats->tx_errors =
Michael Chana4743052010-01-17 07:30:43 +00006685 GET_32BIT_NET_STATS(stat_emac_tx_stat_dot3statsinternalmactransmiterrors) +
Michael Chanb6016b72005-05-26 13:03:09 -07006686 net_stats->tx_aborted_errors +
6687 net_stats->tx_carrier_errors;
6688
Michael Chancea94db2006-06-12 22:16:13 -07006689 net_stats->rx_missed_errors =
Michael Chana4743052010-01-17 07:30:43 +00006690 GET_32BIT_NET_STATS(stat_IfInFTQDiscards) +
6691 GET_32BIT_NET_STATS(stat_IfInMBUFDiscards) +
6692 GET_32BIT_NET_STATS(stat_FwRxDrop);
Michael Chancea94db2006-06-12 22:16:13 -07006693
Michael Chanb6016b72005-05-26 13:03:09 -07006694 return net_stats;
6695}
6696
6697/* All ethtool functions called with rtnl_lock */
6698
6699static int
6700bnx2_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
6701{
Michael Chan972ec0d2006-01-23 16:12:43 -08006702 struct bnx2 *bp = netdev_priv(dev);
Michael Chan7b6b8342007-07-07 22:50:15 -07006703 int support_serdes = 0, support_copper = 0;
Michael Chanb6016b72005-05-26 13:03:09 -07006704
6705 cmd->supported = SUPPORTED_Autoneg;
Michael Chan583c28e2008-01-21 19:51:35 -08006706 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP) {
Michael Chan7b6b8342007-07-07 22:50:15 -07006707 support_serdes = 1;
6708 support_copper = 1;
6709 } else if (bp->phy_port == PORT_FIBRE)
6710 support_serdes = 1;
6711 else
6712 support_copper = 1;
6713
6714 if (support_serdes) {
Michael Chanb6016b72005-05-26 13:03:09 -07006715 cmd->supported |= SUPPORTED_1000baseT_Full |
6716 SUPPORTED_FIBRE;
Michael Chan583c28e2008-01-21 19:51:35 -08006717 if (bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE)
Michael Chan605a9e22007-05-03 13:23:13 -07006718 cmd->supported |= SUPPORTED_2500baseX_Full;
Michael Chanb6016b72005-05-26 13:03:09 -07006719
Michael Chanb6016b72005-05-26 13:03:09 -07006720 }
Michael Chan7b6b8342007-07-07 22:50:15 -07006721 if (support_copper) {
Michael Chanb6016b72005-05-26 13:03:09 -07006722 cmd->supported |= SUPPORTED_10baseT_Half |
6723 SUPPORTED_10baseT_Full |
6724 SUPPORTED_100baseT_Half |
6725 SUPPORTED_100baseT_Full |
6726 SUPPORTED_1000baseT_Full |
6727 SUPPORTED_TP;
6728
Michael Chanb6016b72005-05-26 13:03:09 -07006729 }
6730
Michael Chan7b6b8342007-07-07 22:50:15 -07006731 spin_lock_bh(&bp->phy_lock);
6732 cmd->port = bp->phy_port;
Michael Chanb6016b72005-05-26 13:03:09 -07006733 cmd->advertising = bp->advertising;
6734
6735 if (bp->autoneg & AUTONEG_SPEED) {
6736 cmd->autoneg = AUTONEG_ENABLE;
David Decotigny70739492011-04-27 18:32:40 +00006737 } else {
Michael Chanb6016b72005-05-26 13:03:09 -07006738 cmd->autoneg = AUTONEG_DISABLE;
6739 }
6740
6741 if (netif_carrier_ok(dev)) {
David Decotigny70739492011-04-27 18:32:40 +00006742 ethtool_cmd_speed_set(cmd, bp->line_speed);
Michael Chanb6016b72005-05-26 13:03:09 -07006743 cmd->duplex = bp->duplex;
6744 }
6745 else {
David Decotigny70739492011-04-27 18:32:40 +00006746 ethtool_cmd_speed_set(cmd, -1);
Michael Chanb6016b72005-05-26 13:03:09 -07006747 cmd->duplex = -1;
6748 }
Michael Chan7b6b8342007-07-07 22:50:15 -07006749 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07006750
6751 cmd->transceiver = XCVR_INTERNAL;
6752 cmd->phy_address = bp->phy_addr;
6753
6754 return 0;
6755}
Jeff Garzik6aa20a22006-09-13 13:24:59 -04006756
Michael Chanb6016b72005-05-26 13:03:09 -07006757static int
6758bnx2_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
6759{
Michael Chan972ec0d2006-01-23 16:12:43 -08006760 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006761 u8 autoneg = bp->autoneg;
6762 u8 req_duplex = bp->req_duplex;
6763 u16 req_line_speed = bp->req_line_speed;
6764 u32 advertising = bp->advertising;
Michael Chan7b6b8342007-07-07 22:50:15 -07006765 int err = -EINVAL;
6766
6767 spin_lock_bh(&bp->phy_lock);
6768
6769 if (cmd->port != PORT_TP && cmd->port != PORT_FIBRE)
6770 goto err_out_unlock;
6771
Michael Chan583c28e2008-01-21 19:51:35 -08006772 if (cmd->port != bp->phy_port &&
6773 !(bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP))
Michael Chan7b6b8342007-07-07 22:50:15 -07006774 goto err_out_unlock;
Michael Chanb6016b72005-05-26 13:03:09 -07006775
Michael Chand6b14482008-07-14 22:37:21 -07006776 /* If device is down, we can store the settings only if the user
6777 * is setting the currently active port.
6778 */
6779 if (!netif_running(dev) && cmd->port != bp->phy_port)
6780 goto err_out_unlock;
6781
Michael Chanb6016b72005-05-26 13:03:09 -07006782 if (cmd->autoneg == AUTONEG_ENABLE) {
6783 autoneg |= AUTONEG_SPEED;
6784
Michael Chanbeb499a2010-02-15 19:42:10 +00006785 advertising = cmd->advertising;
6786 if (cmd->port == PORT_TP) {
6787 advertising &= ETHTOOL_ALL_COPPER_SPEED;
6788 if (!advertising)
Michael Chanb6016b72005-05-26 13:03:09 -07006789 advertising = ETHTOOL_ALL_COPPER_SPEED;
Michael Chanbeb499a2010-02-15 19:42:10 +00006790 } else {
6791 advertising &= ETHTOOL_ALL_FIBRE_SPEED;
6792 if (!advertising)
6793 advertising = ETHTOOL_ALL_FIBRE_SPEED;
Michael Chanb6016b72005-05-26 13:03:09 -07006794 }
6795 advertising |= ADVERTISED_Autoneg;
6796 }
6797 else {
David Decotigny25db0332011-04-27 18:32:39 +00006798 u32 speed = ethtool_cmd_speed(cmd);
Michael Chan7b6b8342007-07-07 22:50:15 -07006799 if (cmd->port == PORT_FIBRE) {
David Decotigny25db0332011-04-27 18:32:39 +00006800 if ((speed != SPEED_1000 &&
6801 speed != SPEED_2500) ||
Michael Chan80be4432006-11-19 14:07:28 -08006802 (cmd->duplex != DUPLEX_FULL))
Michael Chan7b6b8342007-07-07 22:50:15 -07006803 goto err_out_unlock;
Michael Chan80be4432006-11-19 14:07:28 -08006804
David Decotigny25db0332011-04-27 18:32:39 +00006805 if (speed == SPEED_2500 &&
Michael Chan583c28e2008-01-21 19:51:35 -08006806 !(bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE))
Michael Chan7b6b8342007-07-07 22:50:15 -07006807 goto err_out_unlock;
David Decotigny25db0332011-04-27 18:32:39 +00006808 } else if (speed == SPEED_1000 || speed == SPEED_2500)
Michael Chan7b6b8342007-07-07 22:50:15 -07006809 goto err_out_unlock;
6810
Michael Chanb6016b72005-05-26 13:03:09 -07006811 autoneg &= ~AUTONEG_SPEED;
David Decotigny25db0332011-04-27 18:32:39 +00006812 req_line_speed = speed;
Michael Chanb6016b72005-05-26 13:03:09 -07006813 req_duplex = cmd->duplex;
6814 advertising = 0;
6815 }
6816
6817 bp->autoneg = autoneg;
6818 bp->advertising = advertising;
6819 bp->req_line_speed = req_line_speed;
6820 bp->req_duplex = req_duplex;
6821
Michael Chand6b14482008-07-14 22:37:21 -07006822 err = 0;
6823 /* If device is down, the new settings will be picked up when it is
6824 * brought up.
6825 */
6826 if (netif_running(dev))
6827 err = bnx2_setup_phy(bp, cmd->port);
Michael Chanb6016b72005-05-26 13:03:09 -07006828
Michael Chan7b6b8342007-07-07 22:50:15 -07006829err_out_unlock:
Michael Chanc770a652005-08-25 15:38:39 -07006830 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07006831
Michael Chan7b6b8342007-07-07 22:50:15 -07006832 return err;
Michael Chanb6016b72005-05-26 13:03:09 -07006833}
6834
6835static void
6836bnx2_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
6837{
Michael Chan972ec0d2006-01-23 16:12:43 -08006838 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006839
6840 strcpy(info->driver, DRV_MODULE_NAME);
6841 strcpy(info->version, DRV_MODULE_VERSION);
6842 strcpy(info->bus_info, pci_name(bp->pdev));
Michael Chan58fc2ea2007-07-07 22:52:02 -07006843 strcpy(info->fw_version, bp->fw_version);
Michael Chanb6016b72005-05-26 13:03:09 -07006844}
6845
Michael Chan244ac4f2006-03-20 17:48:46 -08006846#define BNX2_REGDUMP_LEN (32 * 1024)
6847
6848static int
6849bnx2_get_regs_len(struct net_device *dev)
6850{
6851 return BNX2_REGDUMP_LEN;
6852}
6853
6854static void
6855bnx2_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *_p)
6856{
6857 u32 *p = _p, i, offset;
6858 u8 *orig_p = _p;
6859 struct bnx2 *bp = netdev_priv(dev);
Joe Perchesb6bc7652010-12-21 02:16:08 -08006860 static const u32 reg_boundaries[] = {
6861 0x0000, 0x0098, 0x0400, 0x045c,
6862 0x0800, 0x0880, 0x0c00, 0x0c10,
6863 0x0c30, 0x0d08, 0x1000, 0x101c,
6864 0x1040, 0x1048, 0x1080, 0x10a4,
6865 0x1400, 0x1490, 0x1498, 0x14f0,
6866 0x1500, 0x155c, 0x1580, 0x15dc,
6867 0x1600, 0x1658, 0x1680, 0x16d8,
6868 0x1800, 0x1820, 0x1840, 0x1854,
6869 0x1880, 0x1894, 0x1900, 0x1984,
6870 0x1c00, 0x1c0c, 0x1c40, 0x1c54,
6871 0x1c80, 0x1c94, 0x1d00, 0x1d84,
6872 0x2000, 0x2030, 0x23c0, 0x2400,
6873 0x2800, 0x2820, 0x2830, 0x2850,
6874 0x2b40, 0x2c10, 0x2fc0, 0x3058,
6875 0x3c00, 0x3c94, 0x4000, 0x4010,
6876 0x4080, 0x4090, 0x43c0, 0x4458,
6877 0x4c00, 0x4c18, 0x4c40, 0x4c54,
6878 0x4fc0, 0x5010, 0x53c0, 0x5444,
6879 0x5c00, 0x5c18, 0x5c80, 0x5c90,
6880 0x5fc0, 0x6000, 0x6400, 0x6428,
6881 0x6800, 0x6848, 0x684c, 0x6860,
6882 0x6888, 0x6910, 0x8000
6883 };
Michael Chan244ac4f2006-03-20 17:48:46 -08006884
6885 regs->version = 0;
6886
6887 memset(p, 0, BNX2_REGDUMP_LEN);
6888
6889 if (!netif_running(bp->dev))
6890 return;
6891
6892 i = 0;
6893 offset = reg_boundaries[0];
6894 p += offset;
6895 while (offset < BNX2_REGDUMP_LEN) {
6896 *p++ = REG_RD(bp, offset);
6897 offset += 4;
6898 if (offset == reg_boundaries[i + 1]) {
6899 offset = reg_boundaries[i + 2];
6900 p = (u32 *) (orig_p + offset);
6901 i += 2;
6902 }
6903 }
6904}
6905
Michael Chanb6016b72005-05-26 13:03:09 -07006906static void
6907bnx2_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
6908{
Michael Chan972ec0d2006-01-23 16:12:43 -08006909 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006910
David S. Millerf86e82f2008-01-21 17:15:40 -08006911 if (bp->flags & BNX2_FLAG_NO_WOL) {
Michael Chanb6016b72005-05-26 13:03:09 -07006912 wol->supported = 0;
6913 wol->wolopts = 0;
6914 }
6915 else {
6916 wol->supported = WAKE_MAGIC;
6917 if (bp->wol)
6918 wol->wolopts = WAKE_MAGIC;
6919 else
6920 wol->wolopts = 0;
6921 }
6922 memset(&wol->sopass, 0, sizeof(wol->sopass));
6923}
6924
6925static int
6926bnx2_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
6927{
Michael Chan972ec0d2006-01-23 16:12:43 -08006928 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006929
6930 if (wol->wolopts & ~WAKE_MAGIC)
6931 return -EINVAL;
6932
6933 if (wol->wolopts & WAKE_MAGIC) {
David S. Millerf86e82f2008-01-21 17:15:40 -08006934 if (bp->flags & BNX2_FLAG_NO_WOL)
Michael Chanb6016b72005-05-26 13:03:09 -07006935 return -EINVAL;
6936
6937 bp->wol = 1;
6938 }
6939 else {
6940 bp->wol = 0;
6941 }
6942 return 0;
6943}
6944
6945static int
6946bnx2_nway_reset(struct net_device *dev)
6947{
Michael Chan972ec0d2006-01-23 16:12:43 -08006948 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006949 u32 bmcr;
6950
Michael Chan9f52b562008-10-09 12:21:46 -07006951 if (!netif_running(dev))
6952 return -EAGAIN;
6953
Michael Chanb6016b72005-05-26 13:03:09 -07006954 if (!(bp->autoneg & AUTONEG_SPEED)) {
6955 return -EINVAL;
6956 }
6957
Michael Chanc770a652005-08-25 15:38:39 -07006958 spin_lock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07006959
Michael Chan583c28e2008-01-21 19:51:35 -08006960 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP) {
Michael Chan7b6b8342007-07-07 22:50:15 -07006961 int rc;
6962
6963 rc = bnx2_setup_remote_phy(bp, bp->phy_port);
6964 spin_unlock_bh(&bp->phy_lock);
6965 return rc;
6966 }
6967
Michael Chanb6016b72005-05-26 13:03:09 -07006968 /* Force a link down visible on the other side */
Michael Chan583c28e2008-01-21 19:51:35 -08006969 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Michael Chanca58c3a2007-05-03 13:22:52 -07006970 bnx2_write_phy(bp, bp->mii_bmcr, BMCR_LOOPBACK);
Michael Chanc770a652005-08-25 15:38:39 -07006971 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07006972
6973 msleep(20);
6974
Michael Chanc770a652005-08-25 15:38:39 -07006975 spin_lock_bh(&bp->phy_lock);
Michael Chanf8dd0642006-11-19 14:08:29 -08006976
Michael Chan40105c02008-11-12 16:02:45 -08006977 bp->current_interval = BNX2_SERDES_AN_TIMEOUT;
Michael Chanf8dd0642006-11-19 14:08:29 -08006978 bp->serdes_an_pending = 1;
6979 mod_timer(&bp->timer, jiffies + bp->current_interval);
Michael Chanb6016b72005-05-26 13:03:09 -07006980 }
6981
Michael Chanca58c3a2007-05-03 13:22:52 -07006982 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chanb6016b72005-05-26 13:03:09 -07006983 bmcr &= ~BMCR_LOOPBACK;
Michael Chanca58c3a2007-05-03 13:22:52 -07006984 bnx2_write_phy(bp, bp->mii_bmcr, bmcr | BMCR_ANRESTART | BMCR_ANENABLE);
Michael Chanb6016b72005-05-26 13:03:09 -07006985
Michael Chanc770a652005-08-25 15:38:39 -07006986 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07006987
6988 return 0;
6989}
6990
Ooiwa Naohiro7959ea22009-06-24 00:19:06 -07006991static u32
6992bnx2_get_link(struct net_device *dev)
6993{
6994 struct bnx2 *bp = netdev_priv(dev);
6995
6996 return bp->link_up;
6997}
6998
Michael Chanb6016b72005-05-26 13:03:09 -07006999static int
7000bnx2_get_eeprom_len(struct net_device *dev)
7001{
Michael Chan972ec0d2006-01-23 16:12:43 -08007002 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007003
Michael Chan1122db72006-01-23 16:11:42 -08007004 if (bp->flash_info == NULL)
Michael Chanb6016b72005-05-26 13:03:09 -07007005 return 0;
7006
Michael Chan1122db72006-01-23 16:11:42 -08007007 return (int) bp->flash_size;
Michael Chanb6016b72005-05-26 13:03:09 -07007008}
7009
7010static int
7011bnx2_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
7012 u8 *eebuf)
7013{
Michael Chan972ec0d2006-01-23 16:12:43 -08007014 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007015 int rc;
7016
Michael Chan9f52b562008-10-09 12:21:46 -07007017 if (!netif_running(dev))
7018 return -EAGAIN;
7019
John W. Linville1064e942005-11-10 12:58:24 -08007020 /* parameters already validated in ethtool_get_eeprom */
Michael Chanb6016b72005-05-26 13:03:09 -07007021
7022 rc = bnx2_nvram_read(bp, eeprom->offset, eebuf, eeprom->len);
7023
7024 return rc;
7025}
7026
7027static int
7028bnx2_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
7029 u8 *eebuf)
7030{
Michael Chan972ec0d2006-01-23 16:12:43 -08007031 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007032 int rc;
7033
Michael Chan9f52b562008-10-09 12:21:46 -07007034 if (!netif_running(dev))
7035 return -EAGAIN;
7036
John W. Linville1064e942005-11-10 12:58:24 -08007037 /* parameters already validated in ethtool_set_eeprom */
Michael Chanb6016b72005-05-26 13:03:09 -07007038
7039 rc = bnx2_nvram_write(bp, eeprom->offset, eebuf, eeprom->len);
7040
7041 return rc;
7042}
7043
7044static int
7045bnx2_get_coalesce(struct net_device *dev, struct ethtool_coalesce *coal)
7046{
Michael Chan972ec0d2006-01-23 16:12:43 -08007047 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007048
7049 memset(coal, 0, sizeof(struct ethtool_coalesce));
7050
7051 coal->rx_coalesce_usecs = bp->rx_ticks;
7052 coal->rx_max_coalesced_frames = bp->rx_quick_cons_trip;
7053 coal->rx_coalesce_usecs_irq = bp->rx_ticks_int;
7054 coal->rx_max_coalesced_frames_irq = bp->rx_quick_cons_trip_int;
7055
7056 coal->tx_coalesce_usecs = bp->tx_ticks;
7057 coal->tx_max_coalesced_frames = bp->tx_quick_cons_trip;
7058 coal->tx_coalesce_usecs_irq = bp->tx_ticks_int;
7059 coal->tx_max_coalesced_frames_irq = bp->tx_quick_cons_trip_int;
7060
7061 coal->stats_block_coalesce_usecs = bp->stats_ticks;
7062
7063 return 0;
7064}
7065
7066static int
7067bnx2_set_coalesce(struct net_device *dev, struct ethtool_coalesce *coal)
7068{
Michael Chan972ec0d2006-01-23 16:12:43 -08007069 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007070
7071 bp->rx_ticks = (u16) coal->rx_coalesce_usecs;
7072 if (bp->rx_ticks > 0x3ff) bp->rx_ticks = 0x3ff;
7073
Jeff Garzik6aa20a22006-09-13 13:24:59 -04007074 bp->rx_quick_cons_trip = (u16) coal->rx_max_coalesced_frames;
Michael Chanb6016b72005-05-26 13:03:09 -07007075 if (bp->rx_quick_cons_trip > 0xff) bp->rx_quick_cons_trip = 0xff;
7076
7077 bp->rx_ticks_int = (u16) coal->rx_coalesce_usecs_irq;
7078 if (bp->rx_ticks_int > 0x3ff) bp->rx_ticks_int = 0x3ff;
7079
7080 bp->rx_quick_cons_trip_int = (u16) coal->rx_max_coalesced_frames_irq;
7081 if (bp->rx_quick_cons_trip_int > 0xff)
7082 bp->rx_quick_cons_trip_int = 0xff;
7083
7084 bp->tx_ticks = (u16) coal->tx_coalesce_usecs;
7085 if (bp->tx_ticks > 0x3ff) bp->tx_ticks = 0x3ff;
7086
7087 bp->tx_quick_cons_trip = (u16) coal->tx_max_coalesced_frames;
7088 if (bp->tx_quick_cons_trip > 0xff) bp->tx_quick_cons_trip = 0xff;
7089
7090 bp->tx_ticks_int = (u16) coal->tx_coalesce_usecs_irq;
7091 if (bp->tx_ticks_int > 0x3ff) bp->tx_ticks_int = 0x3ff;
7092
7093 bp->tx_quick_cons_trip_int = (u16) coal->tx_max_coalesced_frames_irq;
7094 if (bp->tx_quick_cons_trip_int > 0xff) bp->tx_quick_cons_trip_int =
7095 0xff;
7096
7097 bp->stats_ticks = coal->stats_block_coalesce_usecs;
Michael Chan61d9e3f2009-08-21 16:20:46 +00007098 if (bp->flags & BNX2_FLAG_BROKEN_STATS) {
Michael Chan02537b062007-06-04 21:24:07 -07007099 if (bp->stats_ticks != 0 && bp->stats_ticks != USEC_PER_SEC)
7100 bp->stats_ticks = USEC_PER_SEC;
7101 }
Michael Chan7ea69202007-07-16 18:27:10 -07007102 if (bp->stats_ticks > BNX2_HC_STATS_TICKS_HC_STAT_TICKS)
7103 bp->stats_ticks = BNX2_HC_STATS_TICKS_HC_STAT_TICKS;
7104 bp->stats_ticks &= BNX2_HC_STATS_TICKS_HC_STAT_TICKS;
Michael Chanb6016b72005-05-26 13:03:09 -07007105
7106 if (netif_running(bp->dev)) {
Michael Chan212f9932010-04-27 11:28:10 +00007107 bnx2_netif_stop(bp, true);
Michael Chan9a120bc2008-05-16 22:17:45 -07007108 bnx2_init_nic(bp, 0);
Michael Chan212f9932010-04-27 11:28:10 +00007109 bnx2_netif_start(bp, true);
Michael Chanb6016b72005-05-26 13:03:09 -07007110 }
7111
7112 return 0;
7113}
7114
7115static void
7116bnx2_get_ringparam(struct net_device *dev, struct ethtool_ringparam *ering)
7117{
Michael Chan972ec0d2006-01-23 16:12:43 -08007118 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007119
Michael Chan13daffa2006-03-20 17:49:20 -08007120 ering->rx_max_pending = MAX_TOTAL_RX_DESC_CNT;
Michael Chanb6016b72005-05-26 13:03:09 -07007121 ering->rx_mini_max_pending = 0;
Michael Chan47bf4242007-12-12 11:19:12 -08007122 ering->rx_jumbo_max_pending = MAX_TOTAL_RX_PG_DESC_CNT;
Michael Chanb6016b72005-05-26 13:03:09 -07007123
7124 ering->rx_pending = bp->rx_ring_size;
7125 ering->rx_mini_pending = 0;
Michael Chan47bf4242007-12-12 11:19:12 -08007126 ering->rx_jumbo_pending = bp->rx_pg_ring_size;
Michael Chanb6016b72005-05-26 13:03:09 -07007127
7128 ering->tx_max_pending = MAX_TX_DESC_CNT;
7129 ering->tx_pending = bp->tx_ring_size;
7130}
7131
7132static int
Michael Chan5d5d0012007-12-12 11:17:43 -08007133bnx2_change_ring_size(struct bnx2 *bp, u32 rx, u32 tx)
Michael Chanb6016b72005-05-26 13:03:09 -07007134{
Michael Chan13daffa2006-03-20 17:49:20 -08007135 if (netif_running(bp->dev)) {
Michael Chan354fcd72010-01-17 07:30:44 +00007136 /* Reset will erase chipset stats; save them */
7137 bnx2_save_stats(bp);
7138
Michael Chan212f9932010-04-27 11:28:10 +00007139 bnx2_netif_stop(bp, true);
Michael Chan13daffa2006-03-20 17:49:20 -08007140 bnx2_reset_chip(bp, BNX2_DRV_MSG_CODE_RESET);
Michael Chana29ba9d2010-12-31 11:03:14 -08007141 __bnx2_free_irq(bp);
Michael Chan13daffa2006-03-20 17:49:20 -08007142 bnx2_free_skbs(bp);
7143 bnx2_free_mem(bp);
7144 }
7145
Michael Chan5d5d0012007-12-12 11:17:43 -08007146 bnx2_set_rx_ring_size(bp, rx);
7147 bp->tx_ring_size = tx;
Michael Chanb6016b72005-05-26 13:03:09 -07007148
7149 if (netif_running(bp->dev)) {
Michael Chan13daffa2006-03-20 17:49:20 -08007150 int rc;
7151
7152 rc = bnx2_alloc_mem(bp);
Michael Chan6fefb652009-08-21 16:20:45 +00007153 if (!rc)
Michael Chana29ba9d2010-12-31 11:03:14 -08007154 rc = bnx2_request_irq(bp);
7155
7156 if (!rc)
Michael Chan6fefb652009-08-21 16:20:45 +00007157 rc = bnx2_init_nic(bp, 0);
7158
7159 if (rc) {
7160 bnx2_napi_enable(bp);
7161 dev_close(bp->dev);
Michael Chan13daffa2006-03-20 17:49:20 -08007162 return rc;
Michael Chan6fefb652009-08-21 16:20:45 +00007163 }
Michael Chane9f26c42010-02-15 19:42:08 +00007164#ifdef BCM_CNIC
7165 mutex_lock(&bp->cnic_lock);
7166 /* Let cnic know about the new status block. */
7167 if (bp->cnic_eth_dev.drv_state & CNIC_DRV_STATE_REGD)
7168 bnx2_setup_cnic_irq_info(bp);
7169 mutex_unlock(&bp->cnic_lock);
7170#endif
Michael Chan212f9932010-04-27 11:28:10 +00007171 bnx2_netif_start(bp, true);
Michael Chanb6016b72005-05-26 13:03:09 -07007172 }
Michael Chanb6016b72005-05-26 13:03:09 -07007173 return 0;
7174}
7175
Michael Chan5d5d0012007-12-12 11:17:43 -08007176static int
7177bnx2_set_ringparam(struct net_device *dev, struct ethtool_ringparam *ering)
7178{
7179 struct bnx2 *bp = netdev_priv(dev);
7180 int rc;
7181
7182 if ((ering->rx_pending > MAX_TOTAL_RX_DESC_CNT) ||
7183 (ering->tx_pending > MAX_TX_DESC_CNT) ||
7184 (ering->tx_pending <= MAX_SKB_FRAGS)) {
7185
7186 return -EINVAL;
7187 }
7188 rc = bnx2_change_ring_size(bp, ering->rx_pending, ering->tx_pending);
7189 return rc;
7190}
7191
Michael Chanb6016b72005-05-26 13:03:09 -07007192static void
7193bnx2_get_pauseparam(struct net_device *dev, struct ethtool_pauseparam *epause)
7194{
Michael Chan972ec0d2006-01-23 16:12:43 -08007195 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007196
7197 epause->autoneg = ((bp->autoneg & AUTONEG_FLOW_CTRL) != 0);
7198 epause->rx_pause = ((bp->flow_ctrl & FLOW_CTRL_RX) != 0);
7199 epause->tx_pause = ((bp->flow_ctrl & FLOW_CTRL_TX) != 0);
7200}
7201
7202static int
7203bnx2_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam *epause)
7204{
Michael Chan972ec0d2006-01-23 16:12:43 -08007205 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007206
7207 bp->req_flow_ctrl = 0;
7208 if (epause->rx_pause)
7209 bp->req_flow_ctrl |= FLOW_CTRL_RX;
7210 if (epause->tx_pause)
7211 bp->req_flow_ctrl |= FLOW_CTRL_TX;
7212
7213 if (epause->autoneg) {
7214 bp->autoneg |= AUTONEG_FLOW_CTRL;
7215 }
7216 else {
7217 bp->autoneg &= ~AUTONEG_FLOW_CTRL;
7218 }
7219
Michael Chan9f52b562008-10-09 12:21:46 -07007220 if (netif_running(dev)) {
7221 spin_lock_bh(&bp->phy_lock);
7222 bnx2_setup_phy(bp, bp->phy_port);
7223 spin_unlock_bh(&bp->phy_lock);
7224 }
Michael Chanb6016b72005-05-26 13:03:09 -07007225
7226 return 0;
7227}
7228
Peter Hagervall14ab9b82005-08-10 14:18:16 -07007229static struct {
Michael Chanb6016b72005-05-26 13:03:09 -07007230 char string[ETH_GSTRING_LEN];
Michael Chan790dab22009-08-21 16:20:47 +00007231} bnx2_stats_str_arr[] = {
Michael Chanb6016b72005-05-26 13:03:09 -07007232 { "rx_bytes" },
7233 { "rx_error_bytes" },
7234 { "tx_bytes" },
7235 { "tx_error_bytes" },
7236 { "rx_ucast_packets" },
7237 { "rx_mcast_packets" },
7238 { "rx_bcast_packets" },
7239 { "tx_ucast_packets" },
7240 { "tx_mcast_packets" },
7241 { "tx_bcast_packets" },
7242 { "tx_mac_errors" },
7243 { "tx_carrier_errors" },
7244 { "rx_crc_errors" },
7245 { "rx_align_errors" },
7246 { "tx_single_collisions" },
7247 { "tx_multi_collisions" },
7248 { "tx_deferred" },
7249 { "tx_excess_collisions" },
7250 { "tx_late_collisions" },
7251 { "tx_total_collisions" },
7252 { "rx_fragments" },
7253 { "rx_jabbers" },
7254 { "rx_undersize_packets" },
7255 { "rx_oversize_packets" },
7256 { "rx_64_byte_packets" },
7257 { "rx_65_to_127_byte_packets" },
7258 { "rx_128_to_255_byte_packets" },
7259 { "rx_256_to_511_byte_packets" },
7260 { "rx_512_to_1023_byte_packets" },
7261 { "rx_1024_to_1522_byte_packets" },
7262 { "rx_1523_to_9022_byte_packets" },
7263 { "tx_64_byte_packets" },
7264 { "tx_65_to_127_byte_packets" },
7265 { "tx_128_to_255_byte_packets" },
7266 { "tx_256_to_511_byte_packets" },
7267 { "tx_512_to_1023_byte_packets" },
7268 { "tx_1024_to_1522_byte_packets" },
7269 { "tx_1523_to_9022_byte_packets" },
7270 { "rx_xon_frames" },
7271 { "rx_xoff_frames" },
7272 { "tx_xon_frames" },
7273 { "tx_xoff_frames" },
7274 { "rx_mac_ctrl_frames" },
7275 { "rx_filtered_packets" },
Michael Chan790dab22009-08-21 16:20:47 +00007276 { "rx_ftq_discards" },
Michael Chanb6016b72005-05-26 13:03:09 -07007277 { "rx_discards" },
Michael Chancea94db2006-06-12 22:16:13 -07007278 { "rx_fw_discards" },
Michael Chanb6016b72005-05-26 13:03:09 -07007279};
7280
Michael Chan790dab22009-08-21 16:20:47 +00007281#define BNX2_NUM_STATS (sizeof(bnx2_stats_str_arr)/\
7282 sizeof(bnx2_stats_str_arr[0]))
7283
Michael Chanb6016b72005-05-26 13:03:09 -07007284#define STATS_OFFSET32(offset_name) (offsetof(struct statistics_block, offset_name) / 4)
7285
Arjan van de Venf71e1302006-03-03 21:33:57 -05007286static const unsigned long bnx2_stats_offset_arr[BNX2_NUM_STATS] = {
Michael Chanb6016b72005-05-26 13:03:09 -07007287 STATS_OFFSET32(stat_IfHCInOctets_hi),
7288 STATS_OFFSET32(stat_IfHCInBadOctets_hi),
7289 STATS_OFFSET32(stat_IfHCOutOctets_hi),
7290 STATS_OFFSET32(stat_IfHCOutBadOctets_hi),
7291 STATS_OFFSET32(stat_IfHCInUcastPkts_hi),
7292 STATS_OFFSET32(stat_IfHCInMulticastPkts_hi),
7293 STATS_OFFSET32(stat_IfHCInBroadcastPkts_hi),
7294 STATS_OFFSET32(stat_IfHCOutUcastPkts_hi),
7295 STATS_OFFSET32(stat_IfHCOutMulticastPkts_hi),
7296 STATS_OFFSET32(stat_IfHCOutBroadcastPkts_hi),
7297 STATS_OFFSET32(stat_emac_tx_stat_dot3statsinternalmactransmiterrors),
Jeff Garzik6aa20a22006-09-13 13:24:59 -04007298 STATS_OFFSET32(stat_Dot3StatsCarrierSenseErrors),
7299 STATS_OFFSET32(stat_Dot3StatsFCSErrors),
7300 STATS_OFFSET32(stat_Dot3StatsAlignmentErrors),
7301 STATS_OFFSET32(stat_Dot3StatsSingleCollisionFrames),
7302 STATS_OFFSET32(stat_Dot3StatsMultipleCollisionFrames),
7303 STATS_OFFSET32(stat_Dot3StatsDeferredTransmissions),
7304 STATS_OFFSET32(stat_Dot3StatsExcessiveCollisions),
7305 STATS_OFFSET32(stat_Dot3StatsLateCollisions),
7306 STATS_OFFSET32(stat_EtherStatsCollisions),
7307 STATS_OFFSET32(stat_EtherStatsFragments),
7308 STATS_OFFSET32(stat_EtherStatsJabbers),
7309 STATS_OFFSET32(stat_EtherStatsUndersizePkts),
7310 STATS_OFFSET32(stat_EtherStatsOverrsizePkts),
7311 STATS_OFFSET32(stat_EtherStatsPktsRx64Octets),
7312 STATS_OFFSET32(stat_EtherStatsPktsRx65Octetsto127Octets),
7313 STATS_OFFSET32(stat_EtherStatsPktsRx128Octetsto255Octets),
7314 STATS_OFFSET32(stat_EtherStatsPktsRx256Octetsto511Octets),
7315 STATS_OFFSET32(stat_EtherStatsPktsRx512Octetsto1023Octets),
7316 STATS_OFFSET32(stat_EtherStatsPktsRx1024Octetsto1522Octets),
7317 STATS_OFFSET32(stat_EtherStatsPktsRx1523Octetsto9022Octets),
7318 STATS_OFFSET32(stat_EtherStatsPktsTx64Octets),
7319 STATS_OFFSET32(stat_EtherStatsPktsTx65Octetsto127Octets),
7320 STATS_OFFSET32(stat_EtherStatsPktsTx128Octetsto255Octets),
7321 STATS_OFFSET32(stat_EtherStatsPktsTx256Octetsto511Octets),
7322 STATS_OFFSET32(stat_EtherStatsPktsTx512Octetsto1023Octets),
7323 STATS_OFFSET32(stat_EtherStatsPktsTx1024Octetsto1522Octets),
7324 STATS_OFFSET32(stat_EtherStatsPktsTx1523Octetsto9022Octets),
7325 STATS_OFFSET32(stat_XonPauseFramesReceived),
7326 STATS_OFFSET32(stat_XoffPauseFramesReceived),
7327 STATS_OFFSET32(stat_OutXonSent),
7328 STATS_OFFSET32(stat_OutXoffSent),
7329 STATS_OFFSET32(stat_MacControlFramesReceived),
7330 STATS_OFFSET32(stat_IfInFramesL2FilterDiscards),
Michael Chan790dab22009-08-21 16:20:47 +00007331 STATS_OFFSET32(stat_IfInFTQDiscards),
Jeff Garzik6aa20a22006-09-13 13:24:59 -04007332 STATS_OFFSET32(stat_IfInMBUFDiscards),
Michael Chancea94db2006-06-12 22:16:13 -07007333 STATS_OFFSET32(stat_FwRxDrop),
Michael Chanb6016b72005-05-26 13:03:09 -07007334};
7335
7336/* stat_IfHCInBadOctets and stat_Dot3StatsCarrierSenseErrors are
7337 * skipped because of errata.
Jeff Garzik6aa20a22006-09-13 13:24:59 -04007338 */
Peter Hagervall14ab9b82005-08-10 14:18:16 -07007339static u8 bnx2_5706_stats_len_arr[BNX2_NUM_STATS] = {
Michael Chanb6016b72005-05-26 13:03:09 -07007340 8,0,8,8,8,8,8,8,8,8,
7341 4,0,4,4,4,4,4,4,4,4,
7342 4,4,4,4,4,4,4,4,4,4,
7343 4,4,4,4,4,4,4,4,4,4,
Michael Chan790dab22009-08-21 16:20:47 +00007344 4,4,4,4,4,4,4,
Michael Chanb6016b72005-05-26 13:03:09 -07007345};
7346
Michael Chan5b0c76a2005-11-04 08:45:49 -08007347static u8 bnx2_5708_stats_len_arr[BNX2_NUM_STATS] = {
7348 8,0,8,8,8,8,8,8,8,8,
7349 4,4,4,4,4,4,4,4,4,4,
7350 4,4,4,4,4,4,4,4,4,4,
7351 4,4,4,4,4,4,4,4,4,4,
Michael Chan790dab22009-08-21 16:20:47 +00007352 4,4,4,4,4,4,4,
Michael Chan5b0c76a2005-11-04 08:45:49 -08007353};
7354
Michael Chanb6016b72005-05-26 13:03:09 -07007355#define BNX2_NUM_TESTS 6
7356
Peter Hagervall14ab9b82005-08-10 14:18:16 -07007357static struct {
Michael Chanb6016b72005-05-26 13:03:09 -07007358 char string[ETH_GSTRING_LEN];
7359} bnx2_tests_str_arr[BNX2_NUM_TESTS] = {
7360 { "register_test (offline)" },
7361 { "memory_test (offline)" },
7362 { "loopback_test (offline)" },
7363 { "nvram_test (online)" },
7364 { "interrupt_test (online)" },
7365 { "link_test (online)" },
7366};
7367
7368static int
Jeff Garzikb9f2c042007-10-03 18:07:32 -07007369bnx2_get_sset_count(struct net_device *dev, int sset)
Michael Chanb6016b72005-05-26 13:03:09 -07007370{
Jeff Garzikb9f2c042007-10-03 18:07:32 -07007371 switch (sset) {
7372 case ETH_SS_TEST:
7373 return BNX2_NUM_TESTS;
7374 case ETH_SS_STATS:
7375 return BNX2_NUM_STATS;
7376 default:
7377 return -EOPNOTSUPP;
7378 }
Michael Chanb6016b72005-05-26 13:03:09 -07007379}
7380
7381static void
7382bnx2_self_test(struct net_device *dev, struct ethtool_test *etest, u64 *buf)
7383{
Michael Chan972ec0d2006-01-23 16:12:43 -08007384 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007385
Michael Chan9f52b562008-10-09 12:21:46 -07007386 bnx2_set_power_state(bp, PCI_D0);
7387
Michael Chanb6016b72005-05-26 13:03:09 -07007388 memset(buf, 0, sizeof(u64) * BNX2_NUM_TESTS);
7389 if (etest->flags & ETH_TEST_FL_OFFLINE) {
Michael Chan80be4432006-11-19 14:07:28 -08007390 int i;
7391
Michael Chan212f9932010-04-27 11:28:10 +00007392 bnx2_netif_stop(bp, true);
Michael Chanb6016b72005-05-26 13:03:09 -07007393 bnx2_reset_chip(bp, BNX2_DRV_MSG_CODE_DIAG);
7394 bnx2_free_skbs(bp);
7395
7396 if (bnx2_test_registers(bp) != 0) {
7397 buf[0] = 1;
7398 etest->flags |= ETH_TEST_FL_FAILED;
7399 }
7400 if (bnx2_test_memory(bp) != 0) {
7401 buf[1] = 1;
7402 etest->flags |= ETH_TEST_FL_FAILED;
7403 }
Michael Chanbc5a0692006-01-23 16:13:22 -08007404 if ((buf[2] = bnx2_test_loopback(bp)) != 0)
Michael Chanb6016b72005-05-26 13:03:09 -07007405 etest->flags |= ETH_TEST_FL_FAILED;
Michael Chanb6016b72005-05-26 13:03:09 -07007406
Michael Chan9f52b562008-10-09 12:21:46 -07007407 if (!netif_running(bp->dev))
7408 bnx2_shutdown_chip(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07007409 else {
Michael Chan9a120bc2008-05-16 22:17:45 -07007410 bnx2_init_nic(bp, 1);
Michael Chan212f9932010-04-27 11:28:10 +00007411 bnx2_netif_start(bp, true);
Michael Chanb6016b72005-05-26 13:03:09 -07007412 }
7413
7414 /* wait for link up */
Michael Chan80be4432006-11-19 14:07:28 -08007415 for (i = 0; i < 7; i++) {
7416 if (bp->link_up)
7417 break;
7418 msleep_interruptible(1000);
7419 }
Michael Chanb6016b72005-05-26 13:03:09 -07007420 }
7421
7422 if (bnx2_test_nvram(bp) != 0) {
7423 buf[3] = 1;
7424 etest->flags |= ETH_TEST_FL_FAILED;
7425 }
7426 if (bnx2_test_intr(bp) != 0) {
7427 buf[4] = 1;
7428 etest->flags |= ETH_TEST_FL_FAILED;
7429 }
7430
7431 if (bnx2_test_link(bp) != 0) {
7432 buf[5] = 1;
7433 etest->flags |= ETH_TEST_FL_FAILED;
7434
7435 }
Michael Chan9f52b562008-10-09 12:21:46 -07007436 if (!netif_running(bp->dev))
7437 bnx2_set_power_state(bp, PCI_D3hot);
Michael Chanb6016b72005-05-26 13:03:09 -07007438}
7439
7440static void
7441bnx2_get_strings(struct net_device *dev, u32 stringset, u8 *buf)
7442{
7443 switch (stringset) {
7444 case ETH_SS_STATS:
7445 memcpy(buf, bnx2_stats_str_arr,
7446 sizeof(bnx2_stats_str_arr));
7447 break;
7448 case ETH_SS_TEST:
7449 memcpy(buf, bnx2_tests_str_arr,
7450 sizeof(bnx2_tests_str_arr));
7451 break;
7452 }
7453}
7454
Michael Chanb6016b72005-05-26 13:03:09 -07007455static void
7456bnx2_get_ethtool_stats(struct net_device *dev,
7457 struct ethtool_stats *stats, u64 *buf)
7458{
Michael Chan972ec0d2006-01-23 16:12:43 -08007459 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007460 int i;
7461 u32 *hw_stats = (u32 *) bp->stats_blk;
Michael Chan354fcd72010-01-17 07:30:44 +00007462 u32 *temp_stats = (u32 *) bp->temp_stats_blk;
Peter Hagervall14ab9b82005-08-10 14:18:16 -07007463 u8 *stats_len_arr = NULL;
Michael Chanb6016b72005-05-26 13:03:09 -07007464
7465 if (hw_stats == NULL) {
7466 memset(buf, 0, sizeof(u64) * BNX2_NUM_STATS);
7467 return;
7468 }
7469
Michael Chan5b0c76a2005-11-04 08:45:49 -08007470 if ((CHIP_ID(bp) == CHIP_ID_5706_A0) ||
7471 (CHIP_ID(bp) == CHIP_ID_5706_A1) ||
7472 (CHIP_ID(bp) == CHIP_ID_5706_A2) ||
7473 (CHIP_ID(bp) == CHIP_ID_5708_A0))
Michael Chanb6016b72005-05-26 13:03:09 -07007474 stats_len_arr = bnx2_5706_stats_len_arr;
Michael Chan5b0c76a2005-11-04 08:45:49 -08007475 else
7476 stats_len_arr = bnx2_5708_stats_len_arr;
Michael Chanb6016b72005-05-26 13:03:09 -07007477
7478 for (i = 0; i < BNX2_NUM_STATS; i++) {
Michael Chan354fcd72010-01-17 07:30:44 +00007479 unsigned long offset;
7480
Michael Chanb6016b72005-05-26 13:03:09 -07007481 if (stats_len_arr[i] == 0) {
7482 /* skip this counter */
7483 buf[i] = 0;
7484 continue;
7485 }
Michael Chan354fcd72010-01-17 07:30:44 +00007486
7487 offset = bnx2_stats_offset_arr[i];
Michael Chanb6016b72005-05-26 13:03:09 -07007488 if (stats_len_arr[i] == 4) {
7489 /* 4-byte counter */
Michael Chan354fcd72010-01-17 07:30:44 +00007490 buf[i] = (u64) *(hw_stats + offset) +
7491 *(temp_stats + offset);
Michael Chanb6016b72005-05-26 13:03:09 -07007492 continue;
7493 }
7494 /* 8-byte counter */
Michael Chan354fcd72010-01-17 07:30:44 +00007495 buf[i] = (((u64) *(hw_stats + offset)) << 32) +
7496 *(hw_stats + offset + 1) +
7497 (((u64) *(temp_stats + offset)) << 32) +
7498 *(temp_stats + offset + 1);
Michael Chanb6016b72005-05-26 13:03:09 -07007499 }
7500}
7501
7502static int
stephen hemminger2e17e1a2011-04-04 11:06:36 +00007503bnx2_set_phys_id(struct net_device *dev, enum ethtool_phys_id_state state)
Michael Chanb6016b72005-05-26 13:03:09 -07007504{
Michael Chan972ec0d2006-01-23 16:12:43 -08007505 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007506
stephen hemminger2e17e1a2011-04-04 11:06:36 +00007507 switch (state) {
7508 case ETHTOOL_ID_ACTIVE:
7509 bnx2_set_power_state(bp, PCI_D0);
Michael Chan9f52b562008-10-09 12:21:46 -07007510
stephen hemminger2e17e1a2011-04-04 11:06:36 +00007511 bp->leds_save = REG_RD(bp, BNX2_MISC_CFG);
7512 REG_WR(bp, BNX2_MISC_CFG, BNX2_MISC_CFG_LEDMODE_MAC);
Allan, Bruce Wfce55922011-04-13 13:09:10 +00007513 return 1; /* cycle on/off once per second */
Michael Chanb6016b72005-05-26 13:03:09 -07007514
stephen hemminger2e17e1a2011-04-04 11:06:36 +00007515 case ETHTOOL_ID_ON:
7516 REG_WR(bp, BNX2_EMAC_LED, BNX2_EMAC_LED_OVERRIDE |
7517 BNX2_EMAC_LED_1000MB_OVERRIDE |
7518 BNX2_EMAC_LED_100MB_OVERRIDE |
7519 BNX2_EMAC_LED_10MB_OVERRIDE |
7520 BNX2_EMAC_LED_TRAFFIC_OVERRIDE |
7521 BNX2_EMAC_LED_TRAFFIC);
7522 break;
Michael Chanb6016b72005-05-26 13:03:09 -07007523
stephen hemminger2e17e1a2011-04-04 11:06:36 +00007524 case ETHTOOL_ID_OFF:
7525 REG_WR(bp, BNX2_EMAC_LED, BNX2_EMAC_LED_OVERRIDE);
7526 break;
7527
7528 case ETHTOOL_ID_INACTIVE:
7529 REG_WR(bp, BNX2_EMAC_LED, 0);
7530 REG_WR(bp, BNX2_MISC_CFG, bp->leds_save);
7531
7532 if (!netif_running(dev))
7533 bnx2_set_power_state(bp, PCI_D3hot);
7534 break;
Michael Chanb6016b72005-05-26 13:03:09 -07007535 }
Michael Chan9f52b562008-10-09 12:21:46 -07007536
Michael Chanb6016b72005-05-26 13:03:09 -07007537 return 0;
7538}
7539
Michał Mirosław8d7dfc22011-04-10 04:47:46 +00007540static u32
7541bnx2_fix_features(struct net_device *dev, u32 features)
Michael Chan4666f872007-05-03 13:22:28 -07007542{
7543 struct bnx2 *bp = netdev_priv(dev);
7544
Michał Mirosław8d7dfc22011-04-10 04:47:46 +00007545 if (!(bp->flags & BNX2_FLAG_CAN_KEEP_VLAN))
7546 features |= NETIF_F_HW_VLAN_RX;
7547
7548 return features;
Michael Chan4666f872007-05-03 13:22:28 -07007549}
7550
Michael Chanfdc85412010-07-03 20:42:16 +00007551static int
Michał Mirosław8d7dfc22011-04-10 04:47:46 +00007552bnx2_set_features(struct net_device *dev, u32 features)
Michael Chanfdc85412010-07-03 20:42:16 +00007553{
Jesse Gross7d0fd212010-10-20 13:56:09 +00007554 struct bnx2 *bp = netdev_priv(dev);
Jesse Gross7d0fd212010-10-20 13:56:09 +00007555
Michael Chan7c810472011-01-24 12:59:02 +00007556 /* TSO with VLAN tag won't work with current firmware */
Michał Mirosław8d7dfc22011-04-10 04:47:46 +00007557 if (features & NETIF_F_HW_VLAN_TX)
7558 dev->vlan_features |= (dev->hw_features & NETIF_F_ALL_TSO);
7559 else
7560 dev->vlan_features &= ~NETIF_F_ALL_TSO;
Michael Chan7c810472011-01-24 12:59:02 +00007561
Michał Mirosław8d7dfc22011-04-10 04:47:46 +00007562 if ((!!(features & NETIF_F_HW_VLAN_RX) !=
Jesse Gross7d0fd212010-10-20 13:56:09 +00007563 !!(bp->rx_mode & BNX2_EMAC_RX_MODE_KEEP_VLAN_TAG)) &&
7564 netif_running(dev)) {
7565 bnx2_netif_stop(bp, false);
Michał Mirosław8d7dfc22011-04-10 04:47:46 +00007566 dev->features = features;
Jesse Gross7d0fd212010-10-20 13:56:09 +00007567 bnx2_set_rx_mode(dev);
7568 bnx2_fw_sync(bp, BNX2_DRV_MSG_CODE_KEEP_VLAN_UPDATE, 0, 1);
7569 bnx2_netif_start(bp, false);
Michał Mirosław8d7dfc22011-04-10 04:47:46 +00007570 return 1;
Jesse Gross7d0fd212010-10-20 13:56:09 +00007571 }
7572
7573 return 0;
Michael Chanfdc85412010-07-03 20:42:16 +00007574}
7575
Jeff Garzik7282d492006-09-13 14:30:00 -04007576static const struct ethtool_ops bnx2_ethtool_ops = {
Michael Chanb6016b72005-05-26 13:03:09 -07007577 .get_settings = bnx2_get_settings,
7578 .set_settings = bnx2_set_settings,
7579 .get_drvinfo = bnx2_get_drvinfo,
Michael Chan244ac4f2006-03-20 17:48:46 -08007580 .get_regs_len = bnx2_get_regs_len,
7581 .get_regs = bnx2_get_regs,
Michael Chanb6016b72005-05-26 13:03:09 -07007582 .get_wol = bnx2_get_wol,
7583 .set_wol = bnx2_set_wol,
7584 .nway_reset = bnx2_nway_reset,
Ooiwa Naohiro7959ea22009-06-24 00:19:06 -07007585 .get_link = bnx2_get_link,
Michael Chanb6016b72005-05-26 13:03:09 -07007586 .get_eeprom_len = bnx2_get_eeprom_len,
7587 .get_eeprom = bnx2_get_eeprom,
7588 .set_eeprom = bnx2_set_eeprom,
7589 .get_coalesce = bnx2_get_coalesce,
7590 .set_coalesce = bnx2_set_coalesce,
7591 .get_ringparam = bnx2_get_ringparam,
7592 .set_ringparam = bnx2_set_ringparam,
7593 .get_pauseparam = bnx2_get_pauseparam,
7594 .set_pauseparam = bnx2_set_pauseparam,
Michael Chanb6016b72005-05-26 13:03:09 -07007595 .self_test = bnx2_self_test,
7596 .get_strings = bnx2_get_strings,
stephen hemminger2e17e1a2011-04-04 11:06:36 +00007597 .set_phys_id = bnx2_set_phys_id,
Michael Chanb6016b72005-05-26 13:03:09 -07007598 .get_ethtool_stats = bnx2_get_ethtool_stats,
Jeff Garzikb9f2c042007-10-03 18:07:32 -07007599 .get_sset_count = bnx2_get_sset_count,
Michael Chanb6016b72005-05-26 13:03:09 -07007600};
7601
7602/* Called with rtnl_lock */
7603static int
7604bnx2_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
7605{
Peter Hagervall14ab9b82005-08-10 14:18:16 -07007606 struct mii_ioctl_data *data = if_mii(ifr);
Michael Chan972ec0d2006-01-23 16:12:43 -08007607 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007608 int err;
7609
7610 switch(cmd) {
7611 case SIOCGMIIPHY:
7612 data->phy_id = bp->phy_addr;
7613
7614 /* fallthru */
7615 case SIOCGMIIREG: {
7616 u32 mii_regval;
7617
Michael Chan583c28e2008-01-21 19:51:35 -08007618 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
Michael Chan7b6b8342007-07-07 22:50:15 -07007619 return -EOPNOTSUPP;
7620
Michael Chandad3e452007-05-03 13:18:03 -07007621 if (!netif_running(dev))
7622 return -EAGAIN;
7623
Michael Chanc770a652005-08-25 15:38:39 -07007624 spin_lock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07007625 err = bnx2_read_phy(bp, data->reg_num & 0x1f, &mii_regval);
Michael Chanc770a652005-08-25 15:38:39 -07007626 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07007627
7628 data->val_out = mii_regval;
7629
7630 return err;
7631 }
7632
7633 case SIOCSMIIREG:
Michael Chan583c28e2008-01-21 19:51:35 -08007634 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
Michael Chan7b6b8342007-07-07 22:50:15 -07007635 return -EOPNOTSUPP;
7636
Michael Chandad3e452007-05-03 13:18:03 -07007637 if (!netif_running(dev))
7638 return -EAGAIN;
7639
Michael Chanc770a652005-08-25 15:38:39 -07007640 spin_lock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07007641 err = bnx2_write_phy(bp, data->reg_num & 0x1f, data->val_in);
Michael Chanc770a652005-08-25 15:38:39 -07007642 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07007643
7644 return err;
7645
7646 default:
7647 /* do nothing */
7648 break;
7649 }
7650 return -EOPNOTSUPP;
7651}
7652
7653/* Called with rtnl_lock */
7654static int
7655bnx2_change_mac_addr(struct net_device *dev, void *p)
7656{
7657 struct sockaddr *addr = p;
Michael Chan972ec0d2006-01-23 16:12:43 -08007658 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007659
Michael Chan73eef4c2005-08-25 15:39:15 -07007660 if (!is_valid_ether_addr(addr->sa_data))
7661 return -EINVAL;
7662
Michael Chanb6016b72005-05-26 13:03:09 -07007663 memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
7664 if (netif_running(dev))
Benjamin Li5fcaed02008-07-14 22:39:52 -07007665 bnx2_set_mac_addr(bp, bp->dev->dev_addr, 0);
Michael Chanb6016b72005-05-26 13:03:09 -07007666
7667 return 0;
7668}
7669
7670/* Called with rtnl_lock */
7671static int
7672bnx2_change_mtu(struct net_device *dev, int new_mtu)
7673{
Michael Chan972ec0d2006-01-23 16:12:43 -08007674 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007675
7676 if (((new_mtu + ETH_HLEN) > MAX_ETHERNET_JUMBO_PACKET_SIZE) ||
7677 ((new_mtu + ETH_HLEN) < MIN_ETHERNET_PACKET_SIZE))
7678 return -EINVAL;
7679
7680 dev->mtu = new_mtu;
Eric Dumazet807540b2010-09-23 05:40:09 +00007681 return bnx2_change_ring_size(bp, bp->rx_ring_size, bp->tx_ring_size);
Michael Chanb6016b72005-05-26 13:03:09 -07007682}
7683
Alexey Dobriyan257ddbd2010-01-27 10:17:41 +00007684#ifdef CONFIG_NET_POLL_CONTROLLER
Michael Chanb6016b72005-05-26 13:03:09 -07007685static void
7686poll_bnx2(struct net_device *dev)
7687{
Michael Chan972ec0d2006-01-23 16:12:43 -08007688 struct bnx2 *bp = netdev_priv(dev);
Neil Hormanb2af2c12008-11-12 16:23:44 -08007689 int i;
Michael Chanb6016b72005-05-26 13:03:09 -07007690
Neil Hormanb2af2c12008-11-12 16:23:44 -08007691 for (i = 0; i < bp->irq_nvecs; i++) {
Michael Chan1bf1e342010-03-23 13:13:12 +00007692 struct bnx2_irq *irq = &bp->irq_tbl[i];
7693
7694 disable_irq(irq->vector);
7695 irq->handler(irq->vector, &bp->bnx2_napi[i]);
7696 enable_irq(irq->vector);
Neil Hormanb2af2c12008-11-12 16:23:44 -08007697 }
Michael Chanb6016b72005-05-26 13:03:09 -07007698}
7699#endif
7700
Michael Chan253c8b752007-01-08 19:56:01 -08007701static void __devinit
7702bnx2_get_5709_media(struct bnx2 *bp)
7703{
7704 u32 val = REG_RD(bp, BNX2_MISC_DUAL_MEDIA_CTRL);
7705 u32 bond_id = val & BNX2_MISC_DUAL_MEDIA_CTRL_BOND_ID;
7706 u32 strap;
7707
7708 if (bond_id == BNX2_MISC_DUAL_MEDIA_CTRL_BOND_ID_C)
7709 return;
7710 else if (bond_id == BNX2_MISC_DUAL_MEDIA_CTRL_BOND_ID_S) {
Michael Chan583c28e2008-01-21 19:51:35 -08007711 bp->phy_flags |= BNX2_PHY_FLAG_SERDES;
Michael Chan253c8b752007-01-08 19:56:01 -08007712 return;
7713 }
7714
7715 if (val & BNX2_MISC_DUAL_MEDIA_CTRL_STRAP_OVERRIDE)
7716 strap = (val & BNX2_MISC_DUAL_MEDIA_CTRL_PHY_CTRL) >> 21;
7717 else
7718 strap = (val & BNX2_MISC_DUAL_MEDIA_CTRL_PHY_CTRL_STRAP) >> 8;
7719
7720 if (PCI_FUNC(bp->pdev->devfn) == 0) {
7721 switch (strap) {
7722 case 0x4:
7723 case 0x5:
7724 case 0x6:
Michael Chan583c28e2008-01-21 19:51:35 -08007725 bp->phy_flags |= BNX2_PHY_FLAG_SERDES;
Michael Chan253c8b752007-01-08 19:56:01 -08007726 return;
7727 }
7728 } else {
7729 switch (strap) {
7730 case 0x1:
7731 case 0x2:
7732 case 0x4:
Michael Chan583c28e2008-01-21 19:51:35 -08007733 bp->phy_flags |= BNX2_PHY_FLAG_SERDES;
Michael Chan253c8b752007-01-08 19:56:01 -08007734 return;
7735 }
7736 }
7737}
7738
Michael Chan883e5152007-05-03 13:25:11 -07007739static void __devinit
7740bnx2_get_pci_speed(struct bnx2 *bp)
7741{
7742 u32 reg;
7743
7744 reg = REG_RD(bp, BNX2_PCICFG_MISC_STATUS);
7745 if (reg & BNX2_PCICFG_MISC_STATUS_PCIX_DET) {
7746 u32 clkreg;
7747
David S. Millerf86e82f2008-01-21 17:15:40 -08007748 bp->flags |= BNX2_FLAG_PCIX;
Michael Chan883e5152007-05-03 13:25:11 -07007749
7750 clkreg = REG_RD(bp, BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS);
7751
7752 clkreg &= BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET;
7753 switch (clkreg) {
7754 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_133MHZ:
7755 bp->bus_speed_mhz = 133;
7756 break;
7757
7758 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_95MHZ:
7759 bp->bus_speed_mhz = 100;
7760 break;
7761
7762 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_66MHZ:
7763 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_80MHZ:
7764 bp->bus_speed_mhz = 66;
7765 break;
7766
7767 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_48MHZ:
7768 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_55MHZ:
7769 bp->bus_speed_mhz = 50;
7770 break;
7771
7772 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_LOW:
7773 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_32MHZ:
7774 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_38MHZ:
7775 bp->bus_speed_mhz = 33;
7776 break;
7777 }
7778 }
7779 else {
7780 if (reg & BNX2_PCICFG_MISC_STATUS_M66EN)
7781 bp->bus_speed_mhz = 66;
7782 else
7783 bp->bus_speed_mhz = 33;
7784 }
7785
7786 if (reg & BNX2_PCICFG_MISC_STATUS_32BIT_DET)
David S. Millerf86e82f2008-01-21 17:15:40 -08007787 bp->flags |= BNX2_FLAG_PCI_32BIT;
Michael Chan883e5152007-05-03 13:25:11 -07007788
7789}
7790
Michael Chan76d99062009-12-03 09:46:34 +00007791static void __devinit
7792bnx2_read_vpd_fw_ver(struct bnx2 *bp)
7793{
Matt Carlsondf25bc32010-02-26 14:04:44 +00007794 int rc, i, j;
Michael Chan76d99062009-12-03 09:46:34 +00007795 u8 *data;
Matt Carlsondf25bc32010-02-26 14:04:44 +00007796 unsigned int block_end, rosize, len;
Michael Chan76d99062009-12-03 09:46:34 +00007797
Michael Chan012093f2009-12-03 15:58:00 -08007798#define BNX2_VPD_NVRAM_OFFSET 0x300
7799#define BNX2_VPD_LEN 128
Michael Chan76d99062009-12-03 09:46:34 +00007800#define BNX2_MAX_VER_SLEN 30
7801
7802 data = kmalloc(256, GFP_KERNEL);
7803 if (!data)
7804 return;
7805
Michael Chan012093f2009-12-03 15:58:00 -08007806 rc = bnx2_nvram_read(bp, BNX2_VPD_NVRAM_OFFSET, data + BNX2_VPD_LEN,
7807 BNX2_VPD_LEN);
Michael Chan76d99062009-12-03 09:46:34 +00007808 if (rc)
7809 goto vpd_done;
7810
Michael Chan012093f2009-12-03 15:58:00 -08007811 for (i = 0; i < BNX2_VPD_LEN; i += 4) {
7812 data[i] = data[i + BNX2_VPD_LEN + 3];
7813 data[i + 1] = data[i + BNX2_VPD_LEN + 2];
7814 data[i + 2] = data[i + BNX2_VPD_LEN + 1];
7815 data[i + 3] = data[i + BNX2_VPD_LEN];
Michael Chan76d99062009-12-03 09:46:34 +00007816 }
7817
Matt Carlsondf25bc32010-02-26 14:04:44 +00007818 i = pci_vpd_find_tag(data, 0, BNX2_VPD_LEN, PCI_VPD_LRDT_RO_DATA);
7819 if (i < 0)
Michael Chan76d99062009-12-03 09:46:34 +00007820 goto vpd_done;
Matt Carlsondf25bc32010-02-26 14:04:44 +00007821
7822 rosize = pci_vpd_lrdt_size(&data[i]);
7823 i += PCI_VPD_LRDT_TAG_SIZE;
7824 block_end = i + rosize;
7825
7826 if (block_end > BNX2_VPD_LEN)
7827 goto vpd_done;
7828
7829 j = pci_vpd_find_info_keyword(data, i, rosize,
7830 PCI_VPD_RO_KEYWORD_MFR_ID);
7831 if (j < 0)
7832 goto vpd_done;
7833
7834 len = pci_vpd_info_field_size(&data[j]);
7835
7836 j += PCI_VPD_INFO_FLD_HDR_SIZE;
7837 if (j + len > block_end || len != 4 ||
7838 memcmp(&data[j], "1028", 4))
7839 goto vpd_done;
7840
7841 j = pci_vpd_find_info_keyword(data, i, rosize,
7842 PCI_VPD_RO_KEYWORD_VENDOR0);
7843 if (j < 0)
7844 goto vpd_done;
7845
7846 len = pci_vpd_info_field_size(&data[j]);
7847
7848 j += PCI_VPD_INFO_FLD_HDR_SIZE;
7849 if (j + len > block_end || len > BNX2_MAX_VER_SLEN)
7850 goto vpd_done;
7851
7852 memcpy(bp->fw_version, &data[j], len);
7853 bp->fw_version[len] = ' ';
Michael Chan76d99062009-12-03 09:46:34 +00007854
7855vpd_done:
7856 kfree(data);
7857}
7858
Michael Chanb6016b72005-05-26 13:03:09 -07007859static int __devinit
7860bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
7861{
7862 struct bnx2 *bp;
7863 unsigned long mem_len;
Michael Chan58fc2ea2007-07-07 22:52:02 -07007864 int rc, i, j;
Michael Chanb6016b72005-05-26 13:03:09 -07007865 u32 reg;
Michael Chan40453c82007-05-03 13:19:18 -07007866 u64 dma_mask, persist_dma_mask;
John Feeneycd709aa2010-08-22 17:45:53 +00007867 int err;
Michael Chanb6016b72005-05-26 13:03:09 -07007868
Michael Chanb6016b72005-05-26 13:03:09 -07007869 SET_NETDEV_DEV(dev, &pdev->dev);
Michael Chan972ec0d2006-01-23 16:12:43 -08007870 bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007871
7872 bp->flags = 0;
7873 bp->phy_flags = 0;
7874
Michael Chan354fcd72010-01-17 07:30:44 +00007875 bp->temp_stats_blk =
7876 kzalloc(sizeof(struct statistics_block), GFP_KERNEL);
7877
7878 if (bp->temp_stats_blk == NULL) {
7879 rc = -ENOMEM;
7880 goto err_out;
7881 }
7882
Michael Chanb6016b72005-05-26 13:03:09 -07007883 /* enable device (incl. PCI PM wakeup), and bus-mastering */
7884 rc = pci_enable_device(pdev);
7885 if (rc) {
Joe Perches3a9c6a42010-02-17 15:01:51 +00007886 dev_err(&pdev->dev, "Cannot enable PCI device, aborting\n");
Michael Chanb6016b72005-05-26 13:03:09 -07007887 goto err_out;
7888 }
7889
7890 if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) {
Jeff Garzik9b91cf92006-06-27 11:39:50 -04007891 dev_err(&pdev->dev,
Joe Perches3a9c6a42010-02-17 15:01:51 +00007892 "Cannot find PCI device base address, aborting\n");
Michael Chanb6016b72005-05-26 13:03:09 -07007893 rc = -ENODEV;
7894 goto err_out_disable;
7895 }
7896
7897 rc = pci_request_regions(pdev, DRV_MODULE_NAME);
7898 if (rc) {
Joe Perches3a9c6a42010-02-17 15:01:51 +00007899 dev_err(&pdev->dev, "Cannot obtain PCI resources, aborting\n");
Michael Chanb6016b72005-05-26 13:03:09 -07007900 goto err_out_disable;
7901 }
7902
7903 pci_set_master(pdev);
7904
7905 bp->pm_cap = pci_find_capability(pdev, PCI_CAP_ID_PM);
7906 if (bp->pm_cap == 0) {
Jeff Garzik9b91cf92006-06-27 11:39:50 -04007907 dev_err(&pdev->dev,
Joe Perches3a9c6a42010-02-17 15:01:51 +00007908 "Cannot find power management capability, aborting\n");
Michael Chanb6016b72005-05-26 13:03:09 -07007909 rc = -EIO;
7910 goto err_out_release;
7911 }
7912
Michael Chanb6016b72005-05-26 13:03:09 -07007913 bp->dev = dev;
7914 bp->pdev = pdev;
7915
7916 spin_lock_init(&bp->phy_lock);
Michael Chan1b8227c2007-05-03 13:24:05 -07007917 spin_lock_init(&bp->indirect_lock);
Michael Chanc5a88952009-08-14 15:49:45 +00007918#ifdef BCM_CNIC
7919 mutex_init(&bp->cnic_lock);
7920#endif
David Howellsc4028952006-11-22 14:57:56 +00007921 INIT_WORK(&bp->reset_task, bnx2_reset_task);
Michael Chanb6016b72005-05-26 13:03:09 -07007922
7923 dev->base_addr = dev->mem_start = pci_resource_start(pdev, 0);
Michael Chan4edd4732009-06-08 18:14:42 -07007924 mem_len = MB_GET_CID_ADDR(TX_TSS_CID + TX_MAX_TSS_RINGS + 1);
Michael Chanb6016b72005-05-26 13:03:09 -07007925 dev->mem_end = dev->mem_start + mem_len;
7926 dev->irq = pdev->irq;
7927
7928 bp->regview = ioremap_nocache(dev->base_addr, mem_len);
7929
7930 if (!bp->regview) {
Joe Perches3a9c6a42010-02-17 15:01:51 +00007931 dev_err(&pdev->dev, "Cannot map register space, aborting\n");
Michael Chanb6016b72005-05-26 13:03:09 -07007932 rc = -ENOMEM;
7933 goto err_out_release;
7934 }
7935
Michael Chanbe7ff1a2010-11-24 13:48:55 +00007936 bnx2_set_power_state(bp, PCI_D0);
7937
Michael Chanb6016b72005-05-26 13:03:09 -07007938 /* Configure byte swap and enable write to the reg_window registers.
7939 * Rely on CPU to do target byte swapping on big endian systems
7940 * The chip's target access swapping will not swap all accesses
7941 */
Michael Chanbe7ff1a2010-11-24 13:48:55 +00007942 REG_WR(bp, BNX2_PCICFG_MISC_CONFIG,
7943 BNX2_PCICFG_MISC_CONFIG_REG_WINDOW_ENA |
7944 BNX2_PCICFG_MISC_CONFIG_TARGET_MB_WORD_SWAP);
Michael Chanb6016b72005-05-26 13:03:09 -07007945
7946 bp->chip_id = REG_RD(bp, BNX2_MISC_ID);
7947
Michael Chan883e5152007-05-03 13:25:11 -07007948 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
Jon Masone82760e2011-06-27 07:44:43 +00007949 if (!pci_is_pcie(pdev)) {
7950 dev_err(&pdev->dev, "Not PCIE, aborting\n");
Michael Chan883e5152007-05-03 13:25:11 -07007951 rc = -EIO;
7952 goto err_out_unmap;
7953 }
David S. Millerf86e82f2008-01-21 17:15:40 -08007954 bp->flags |= BNX2_FLAG_PCIE;
Michael Chan2dd201d2008-01-21 17:06:09 -08007955 if (CHIP_REV(bp) == CHIP_REV_Ax)
David S. Millerf86e82f2008-01-21 17:15:40 -08007956 bp->flags |= BNX2_FLAG_JUMBO_BROKEN;
Michael Chanc239f272010-10-11 16:12:28 -07007957
7958 /* AER (Advanced Error Reporting) hooks */
7959 err = pci_enable_pcie_error_reporting(pdev);
Michael Chan4bb9ebc2011-01-25 22:14:51 +00007960 if (!err)
7961 bp->flags |= BNX2_FLAG_AER_ENABLED;
Michael Chanc239f272010-10-11 16:12:28 -07007962
Michael Chan883e5152007-05-03 13:25:11 -07007963 } else {
Michael Chan59b47d82006-11-19 14:10:45 -08007964 bp->pcix_cap = pci_find_capability(pdev, PCI_CAP_ID_PCIX);
7965 if (bp->pcix_cap == 0) {
7966 dev_err(&pdev->dev,
Joe Perches3a9c6a42010-02-17 15:01:51 +00007967 "Cannot find PCIX capability, aborting\n");
Michael Chan59b47d82006-11-19 14:10:45 -08007968 rc = -EIO;
7969 goto err_out_unmap;
7970 }
Michael Chan61d9e3f2009-08-21 16:20:46 +00007971 bp->flags |= BNX2_FLAG_BROKEN_STATS;
Michael Chan59b47d82006-11-19 14:10:45 -08007972 }
7973
Michael Chanb4b36042007-12-20 19:59:30 -08007974 if (CHIP_NUM(bp) == CHIP_NUM_5709 && CHIP_REV(bp) != CHIP_REV_Ax) {
7975 if (pci_find_capability(pdev, PCI_CAP_ID_MSIX))
David S. Millerf86e82f2008-01-21 17:15:40 -08007976 bp->flags |= BNX2_FLAG_MSIX_CAP;
Michael Chanb4b36042007-12-20 19:59:30 -08007977 }
7978
Michael Chan8e6a72c2007-05-03 13:24:48 -07007979 if (CHIP_ID(bp) != CHIP_ID_5706_A0 && CHIP_ID(bp) != CHIP_ID_5706_A1) {
7980 if (pci_find_capability(pdev, PCI_CAP_ID_MSI))
David S. Millerf86e82f2008-01-21 17:15:40 -08007981 bp->flags |= BNX2_FLAG_MSI_CAP;
Michael Chan8e6a72c2007-05-03 13:24:48 -07007982 }
7983
Michael Chan40453c82007-05-03 13:19:18 -07007984 /* 5708 cannot support DMA addresses > 40-bit. */
7985 if (CHIP_NUM(bp) == CHIP_NUM_5708)
Yang Hongyang50cf1562009-04-06 19:01:14 -07007986 persist_dma_mask = dma_mask = DMA_BIT_MASK(40);
Michael Chan40453c82007-05-03 13:19:18 -07007987 else
Yang Hongyang6a355282009-04-06 19:01:13 -07007988 persist_dma_mask = dma_mask = DMA_BIT_MASK(64);
Michael Chan40453c82007-05-03 13:19:18 -07007989
7990 /* Configure DMA attributes. */
7991 if (pci_set_dma_mask(pdev, dma_mask) == 0) {
7992 dev->features |= NETIF_F_HIGHDMA;
7993 rc = pci_set_consistent_dma_mask(pdev, persist_dma_mask);
7994 if (rc) {
7995 dev_err(&pdev->dev,
Joe Perches3a9c6a42010-02-17 15:01:51 +00007996 "pci_set_consistent_dma_mask failed, aborting\n");
Michael Chan40453c82007-05-03 13:19:18 -07007997 goto err_out_unmap;
7998 }
Yang Hongyang284901a2009-04-06 19:01:15 -07007999 } else if ((rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) != 0) {
Joe Perches3a9c6a42010-02-17 15:01:51 +00008000 dev_err(&pdev->dev, "System does not support DMA, aborting\n");
Michael Chan40453c82007-05-03 13:19:18 -07008001 goto err_out_unmap;
8002 }
8003
David S. Millerf86e82f2008-01-21 17:15:40 -08008004 if (!(bp->flags & BNX2_FLAG_PCIE))
Michael Chan883e5152007-05-03 13:25:11 -07008005 bnx2_get_pci_speed(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07008006
8007 /* 5706A0 may falsely detect SERR and PERR. */
8008 if (CHIP_ID(bp) == CHIP_ID_5706_A0) {
8009 reg = REG_RD(bp, PCI_COMMAND);
8010 reg &= ~(PCI_COMMAND_SERR | PCI_COMMAND_PARITY);
8011 REG_WR(bp, PCI_COMMAND, reg);
8012 }
8013 else if ((CHIP_ID(bp) == CHIP_ID_5706_A1) &&
David S. Millerf86e82f2008-01-21 17:15:40 -08008014 !(bp->flags & BNX2_FLAG_PCIX)) {
Michael Chanb6016b72005-05-26 13:03:09 -07008015
Jeff Garzik9b91cf92006-06-27 11:39:50 -04008016 dev_err(&pdev->dev,
Joe Perches3a9c6a42010-02-17 15:01:51 +00008017 "5706 A1 can only be used in a PCIX bus, aborting\n");
Michael Chanb6016b72005-05-26 13:03:09 -07008018 goto err_out_unmap;
8019 }
8020
8021 bnx2_init_nvram(bp);
8022
Michael Chan2726d6e2008-01-29 21:35:05 -08008023 reg = bnx2_reg_rd_ind(bp, BNX2_SHM_HDR_SIGNATURE);
Michael Chane3648b32005-11-04 08:51:21 -08008024
8025 if ((reg & BNX2_SHM_HDR_SIGNATURE_SIG_MASK) ==
Michael Chan24cb2302007-01-25 15:49:56 -08008026 BNX2_SHM_HDR_SIGNATURE_SIG) {
8027 u32 off = PCI_FUNC(pdev->devfn) << 2;
8028
Michael Chan2726d6e2008-01-29 21:35:05 -08008029 bp->shmem_base = bnx2_reg_rd_ind(bp, BNX2_SHM_HDR_ADDR_0 + off);
Michael Chan24cb2302007-01-25 15:49:56 -08008030 } else
Michael Chane3648b32005-11-04 08:51:21 -08008031 bp->shmem_base = HOST_VIEW_SHMEM_BASE;
8032
Michael Chanb6016b72005-05-26 13:03:09 -07008033 /* Get the permanent MAC address. First we need to make sure the
8034 * firmware is actually running.
8035 */
Michael Chan2726d6e2008-01-29 21:35:05 -08008036 reg = bnx2_shmem_rd(bp, BNX2_DEV_INFO_SIGNATURE);
Michael Chanb6016b72005-05-26 13:03:09 -07008037
8038 if ((reg & BNX2_DEV_INFO_SIGNATURE_MAGIC_MASK) !=
8039 BNX2_DEV_INFO_SIGNATURE_MAGIC) {
Joe Perches3a9c6a42010-02-17 15:01:51 +00008040 dev_err(&pdev->dev, "Firmware not running, aborting\n");
Michael Chanb6016b72005-05-26 13:03:09 -07008041 rc = -ENODEV;
8042 goto err_out_unmap;
8043 }
8044
Michael Chan76d99062009-12-03 09:46:34 +00008045 bnx2_read_vpd_fw_ver(bp);
8046
8047 j = strlen(bp->fw_version);
Michael Chan2726d6e2008-01-29 21:35:05 -08008048 reg = bnx2_shmem_rd(bp, BNX2_DEV_INFO_BC_REV);
Michael Chan76d99062009-12-03 09:46:34 +00008049 for (i = 0; i < 3 && j < 24; i++) {
Michael Chan58fc2ea2007-07-07 22:52:02 -07008050 u8 num, k, skip0;
8051
Michael Chan76d99062009-12-03 09:46:34 +00008052 if (i == 0) {
8053 bp->fw_version[j++] = 'b';
8054 bp->fw_version[j++] = 'c';
8055 bp->fw_version[j++] = ' ';
8056 }
Michael Chan58fc2ea2007-07-07 22:52:02 -07008057 num = (u8) (reg >> (24 - (i * 8)));
8058 for (k = 100, skip0 = 1; k >= 1; num %= k, k /= 10) {
8059 if (num >= k || !skip0 || k == 1) {
8060 bp->fw_version[j++] = (num / k) + '0';
8061 skip0 = 0;
8062 }
8063 }
8064 if (i != 2)
8065 bp->fw_version[j++] = '.';
8066 }
Michael Chan2726d6e2008-01-29 21:35:05 -08008067 reg = bnx2_shmem_rd(bp, BNX2_PORT_FEATURE);
Michael Chan846f5c62007-10-10 16:16:51 -07008068 if (reg & BNX2_PORT_FEATURE_WOL_ENABLED)
8069 bp->wol = 1;
8070
8071 if (reg & BNX2_PORT_FEATURE_ASF_ENABLED) {
David S. Millerf86e82f2008-01-21 17:15:40 -08008072 bp->flags |= BNX2_FLAG_ASF_ENABLE;
Michael Chanc2d3db82007-07-16 18:26:43 -07008073
8074 for (i = 0; i < 30; i++) {
Michael Chan2726d6e2008-01-29 21:35:05 -08008075 reg = bnx2_shmem_rd(bp, BNX2_BC_STATE_CONDITION);
Michael Chanc2d3db82007-07-16 18:26:43 -07008076 if (reg & BNX2_CONDITION_MFW_RUN_MASK)
8077 break;
8078 msleep(10);
8079 }
8080 }
Michael Chan2726d6e2008-01-29 21:35:05 -08008081 reg = bnx2_shmem_rd(bp, BNX2_BC_STATE_CONDITION);
Michael Chan58fc2ea2007-07-07 22:52:02 -07008082 reg &= BNX2_CONDITION_MFW_RUN_MASK;
8083 if (reg != BNX2_CONDITION_MFW_RUN_UNKNOWN &&
8084 reg != BNX2_CONDITION_MFW_RUN_NONE) {
Michael Chan2726d6e2008-01-29 21:35:05 -08008085 u32 addr = bnx2_shmem_rd(bp, BNX2_MFW_VER_PTR);
Michael Chan58fc2ea2007-07-07 22:52:02 -07008086
Michael Chan76d99062009-12-03 09:46:34 +00008087 if (j < 32)
8088 bp->fw_version[j++] = ' ';
8089 for (i = 0; i < 3 && j < 28; i++) {
Michael Chan2726d6e2008-01-29 21:35:05 -08008090 reg = bnx2_reg_rd_ind(bp, addr + i * 4);
Michael Chan58fc2ea2007-07-07 22:52:02 -07008091 reg = swab32(reg);
8092 memcpy(&bp->fw_version[j], &reg, 4);
8093 j += 4;
8094 }
8095 }
Michael Chanb6016b72005-05-26 13:03:09 -07008096
Michael Chan2726d6e2008-01-29 21:35:05 -08008097 reg = bnx2_shmem_rd(bp, BNX2_PORT_HW_CFG_MAC_UPPER);
Michael Chanb6016b72005-05-26 13:03:09 -07008098 bp->mac_addr[0] = (u8) (reg >> 8);
8099 bp->mac_addr[1] = (u8) reg;
8100
Michael Chan2726d6e2008-01-29 21:35:05 -08008101 reg = bnx2_shmem_rd(bp, BNX2_PORT_HW_CFG_MAC_LOWER);
Michael Chanb6016b72005-05-26 13:03:09 -07008102 bp->mac_addr[2] = (u8) (reg >> 24);
8103 bp->mac_addr[3] = (u8) (reg >> 16);
8104 bp->mac_addr[4] = (u8) (reg >> 8);
8105 bp->mac_addr[5] = (u8) reg;
8106
8107 bp->tx_ring_size = MAX_TX_DESC_CNT;
Michael Chan932f3772006-08-15 01:39:36 -07008108 bnx2_set_rx_ring_size(bp, 255);
Michael Chanb6016b72005-05-26 13:03:09 -07008109
Michael Chancf7474a2009-08-21 16:20:48 +00008110 bp->tx_quick_cons_trip_int = 2;
Michael Chanb6016b72005-05-26 13:03:09 -07008111 bp->tx_quick_cons_trip = 20;
Michael Chancf7474a2009-08-21 16:20:48 +00008112 bp->tx_ticks_int = 18;
Michael Chanb6016b72005-05-26 13:03:09 -07008113 bp->tx_ticks = 80;
Jeff Garzik6aa20a22006-09-13 13:24:59 -04008114
Michael Chancf7474a2009-08-21 16:20:48 +00008115 bp->rx_quick_cons_trip_int = 2;
8116 bp->rx_quick_cons_trip = 12;
Michael Chanb6016b72005-05-26 13:03:09 -07008117 bp->rx_ticks_int = 18;
8118 bp->rx_ticks = 18;
8119
Michael Chan7ea69202007-07-16 18:27:10 -07008120 bp->stats_ticks = USEC_PER_SEC & BNX2_HC_STATS_TICKS_HC_STAT_TICKS;
Michael Chanb6016b72005-05-26 13:03:09 -07008121
Benjamin Liac392ab2008-09-18 16:40:49 -07008122 bp->current_interval = BNX2_TIMER_INTERVAL;
Michael Chanb6016b72005-05-26 13:03:09 -07008123
Michael Chan5b0c76a2005-11-04 08:45:49 -08008124 bp->phy_addr = 1;
8125
Michael Chanb6016b72005-05-26 13:03:09 -07008126 /* Disable WOL support if we are running on a SERDES chip. */
Michael Chan253c8b752007-01-08 19:56:01 -08008127 if (CHIP_NUM(bp) == CHIP_NUM_5709)
8128 bnx2_get_5709_media(bp);
8129 else if (CHIP_BOND_ID(bp) & CHIP_BOND_ID_SERDES_BIT)
Michael Chan583c28e2008-01-21 19:51:35 -08008130 bp->phy_flags |= BNX2_PHY_FLAG_SERDES;
Michael Chanbac0dff2006-11-19 14:15:05 -08008131
Michael Chan0d8a6572007-07-07 22:49:43 -07008132 bp->phy_port = PORT_TP;
Michael Chan583c28e2008-01-21 19:51:35 -08008133 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Michael Chan0d8a6572007-07-07 22:49:43 -07008134 bp->phy_port = PORT_FIBRE;
Michael Chan2726d6e2008-01-29 21:35:05 -08008135 reg = bnx2_shmem_rd(bp, BNX2_SHARED_HW_CFG_CONFIG);
Michael Chan846f5c62007-10-10 16:16:51 -07008136 if (!(reg & BNX2_SHARED_HW_CFG_GIG_LINK_ON_VAUX)) {
David S. Millerf86e82f2008-01-21 17:15:40 -08008137 bp->flags |= BNX2_FLAG_NO_WOL;
Michael Chan846f5c62007-10-10 16:16:51 -07008138 bp->wol = 0;
8139 }
Michael Chan38ea3682008-02-23 19:48:57 -08008140 if (CHIP_NUM(bp) == CHIP_NUM_5706) {
8141 /* Don't do parallel detect on this board because of
8142 * some board problems. The link will not go down
8143 * if we do parallel detect.
8144 */
8145 if (pdev->subsystem_vendor == PCI_VENDOR_ID_HP &&
8146 pdev->subsystem_device == 0x310c)
8147 bp->phy_flags |= BNX2_PHY_FLAG_NO_PARALLEL;
8148 } else {
Michael Chan5b0c76a2005-11-04 08:45:49 -08008149 bp->phy_addr = 2;
Michael Chan5b0c76a2005-11-04 08:45:49 -08008150 if (reg & BNX2_SHARED_HW_CFG_PHY_2_5G)
Michael Chan583c28e2008-01-21 19:51:35 -08008151 bp->phy_flags |= BNX2_PHY_FLAG_2_5G_CAPABLE;
Michael Chan5b0c76a2005-11-04 08:45:49 -08008152 }
Michael Chan261dd5c2007-01-08 19:55:46 -08008153 } else if (CHIP_NUM(bp) == CHIP_NUM_5706 ||
8154 CHIP_NUM(bp) == CHIP_NUM_5708)
Michael Chan583c28e2008-01-21 19:51:35 -08008155 bp->phy_flags |= BNX2_PHY_FLAG_CRC_FIX;
Michael Chanfb0c18b2007-12-10 17:18:23 -08008156 else if (CHIP_NUM(bp) == CHIP_NUM_5709 &&
8157 (CHIP_REV(bp) == CHIP_REV_Ax ||
8158 CHIP_REV(bp) == CHIP_REV_Bx))
Michael Chan583c28e2008-01-21 19:51:35 -08008159 bp->phy_flags |= BNX2_PHY_FLAG_DIS_EARLY_DAC;
Michael Chanb6016b72005-05-26 13:03:09 -07008160
Michael Chan7c62e832008-07-14 22:39:03 -07008161 bnx2_init_fw_cap(bp);
8162
Michael Chan16088272006-06-12 22:16:43 -07008163 if ((CHIP_ID(bp) == CHIP_ID_5708_A0) ||
8164 (CHIP_ID(bp) == CHIP_ID_5708_B0) ||
Michael Chan5ec6d7b2008-11-12 16:01:41 -08008165 (CHIP_ID(bp) == CHIP_ID_5708_B1) ||
8166 !(REG_RD(bp, BNX2_PCI_CONFIG_3) & BNX2_PCI_CONFIG_3_VAUX_PRESET)) {
David S. Millerf86e82f2008-01-21 17:15:40 -08008167 bp->flags |= BNX2_FLAG_NO_WOL;
Michael Chan846f5c62007-10-10 16:16:51 -07008168 bp->wol = 0;
8169 }
Michael Chandda1e392006-01-23 16:08:14 -08008170
Michael Chanb6016b72005-05-26 13:03:09 -07008171 if (CHIP_ID(bp) == CHIP_ID_5706_A0) {
8172 bp->tx_quick_cons_trip_int =
8173 bp->tx_quick_cons_trip;
8174 bp->tx_ticks_int = bp->tx_ticks;
8175 bp->rx_quick_cons_trip_int =
8176 bp->rx_quick_cons_trip;
8177 bp->rx_ticks_int = bp->rx_ticks;
8178 bp->comp_prod_trip_int = bp->comp_prod_trip;
8179 bp->com_ticks_int = bp->com_ticks;
8180 bp->cmd_ticks_int = bp->cmd_ticks;
8181 }
8182
Michael Chanf9317a42006-09-29 17:06:23 -07008183 /* Disable MSI on 5706 if AMD 8132 bridge is found.
8184 *
8185 * MSI is defined to be 32-bit write. The 5706 does 64-bit MSI writes
8186 * with byte enables disabled on the unused 32-bit word. This is legal
8187 * but causes problems on the AMD 8132 which will eventually stop
8188 * responding after a while.
8189 *
8190 * AMD believes this incompatibility is unique to the 5706, and
Michael Ellerman88187df2007-01-25 19:34:07 +11008191 * prefers to locally disable MSI rather than globally disabling it.
Michael Chanf9317a42006-09-29 17:06:23 -07008192 */
8193 if (CHIP_NUM(bp) == CHIP_NUM_5706 && disable_msi == 0) {
8194 struct pci_dev *amd_8132 = NULL;
8195
8196 while ((amd_8132 = pci_get_device(PCI_VENDOR_ID_AMD,
8197 PCI_DEVICE_ID_AMD_8132_BRIDGE,
8198 amd_8132))) {
Michael Chanf9317a42006-09-29 17:06:23 -07008199
Auke Kok44c10132007-06-08 15:46:36 -07008200 if (amd_8132->revision >= 0x10 &&
8201 amd_8132->revision <= 0x13) {
Michael Chanf9317a42006-09-29 17:06:23 -07008202 disable_msi = 1;
8203 pci_dev_put(amd_8132);
8204 break;
8205 }
8206 }
8207 }
8208
Michael Chandeaf3912007-07-07 22:48:00 -07008209 bnx2_set_default_link(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07008210 bp->req_flow_ctrl = FLOW_CTRL_RX | FLOW_CTRL_TX;
8211
Michael Chancd339a02005-08-25 15:35:24 -07008212 init_timer(&bp->timer);
Benjamin Liac392ab2008-09-18 16:40:49 -07008213 bp->timer.expires = RUN_AT(BNX2_TIMER_INTERVAL);
Michael Chancd339a02005-08-25 15:35:24 -07008214 bp->timer.data = (unsigned long) bp;
8215 bp->timer.function = bnx2_timer;
8216
Michael Chan7625eb22011-06-08 19:29:36 +00008217#ifdef BCM_CNIC
8218 bp->cnic_eth_dev.max_iscsi_conn =
8219 bnx2_reg_rd_ind(bp, BNX2_FW_MAX_ISCSI_CONN);
8220#endif
Michael Chanc239f272010-10-11 16:12:28 -07008221 pci_save_state(pdev);
8222
Michael Chanb6016b72005-05-26 13:03:09 -07008223 return 0;
8224
8225err_out_unmap:
Michael Chan4bb9ebc2011-01-25 22:14:51 +00008226 if (bp->flags & BNX2_FLAG_AER_ENABLED) {
Michael Chanc239f272010-10-11 16:12:28 -07008227 pci_disable_pcie_error_reporting(pdev);
Michael Chan4bb9ebc2011-01-25 22:14:51 +00008228 bp->flags &= ~BNX2_FLAG_AER_ENABLED;
8229 }
Michael Chanc239f272010-10-11 16:12:28 -07008230
Michael Chanb6016b72005-05-26 13:03:09 -07008231 if (bp->regview) {
8232 iounmap(bp->regview);
Michael Chan73eef4c2005-08-25 15:39:15 -07008233 bp->regview = NULL;
Michael Chanb6016b72005-05-26 13:03:09 -07008234 }
8235
8236err_out_release:
8237 pci_release_regions(pdev);
8238
8239err_out_disable:
8240 pci_disable_device(pdev);
8241 pci_set_drvdata(pdev, NULL);
8242
8243err_out:
8244 return rc;
8245}
8246
Michael Chan883e5152007-05-03 13:25:11 -07008247static char * __devinit
8248bnx2_bus_string(struct bnx2 *bp, char *str)
8249{
8250 char *s = str;
8251
David S. Millerf86e82f2008-01-21 17:15:40 -08008252 if (bp->flags & BNX2_FLAG_PCIE) {
Michael Chan883e5152007-05-03 13:25:11 -07008253 s += sprintf(s, "PCI Express");
8254 } else {
8255 s += sprintf(s, "PCI");
David S. Millerf86e82f2008-01-21 17:15:40 -08008256 if (bp->flags & BNX2_FLAG_PCIX)
Michael Chan883e5152007-05-03 13:25:11 -07008257 s += sprintf(s, "-X");
David S. Millerf86e82f2008-01-21 17:15:40 -08008258 if (bp->flags & BNX2_FLAG_PCI_32BIT)
Michael Chan883e5152007-05-03 13:25:11 -07008259 s += sprintf(s, " 32-bit");
8260 else
8261 s += sprintf(s, " 64-bit");
8262 s += sprintf(s, " %dMHz", bp->bus_speed_mhz);
8263 }
8264 return str;
8265}
8266
Michael Chanf048fa92010-06-01 15:05:36 +00008267static void
8268bnx2_del_napi(struct bnx2 *bp)
8269{
8270 int i;
8271
8272 for (i = 0; i < bp->irq_nvecs; i++)
8273 netif_napi_del(&bp->bnx2_napi[i].napi);
8274}
8275
8276static void
Michael Chan35efa7c2007-12-20 19:56:37 -08008277bnx2_init_napi(struct bnx2 *bp)
8278{
Michael Chanb4b36042007-12-20 19:59:30 -08008279 int i;
Michael Chan35efa7c2007-12-20 19:56:37 -08008280
Benjamin Li4327ba42010-03-23 13:13:11 +00008281 for (i = 0; i < bp->irq_nvecs; i++) {
Michael Chan35e90102008-06-19 16:37:42 -07008282 struct bnx2_napi *bnapi = &bp->bnx2_napi[i];
8283 int (*poll)(struct napi_struct *, int);
8284
8285 if (i == 0)
8286 poll = bnx2_poll;
8287 else
Michael Chanf0ea2e62008-06-19 16:41:57 -07008288 poll = bnx2_poll_msix;
Michael Chan35e90102008-06-19 16:37:42 -07008289
8290 netif_napi_add(bp->dev, &bp->bnx2_napi[i].napi, poll, 64);
Michael Chanb4b36042007-12-20 19:59:30 -08008291 bnapi->bp = bp;
8292 }
Michael Chan35efa7c2007-12-20 19:56:37 -08008293}
8294
Stephen Hemminger0421eae2008-11-21 17:31:27 -08008295static const struct net_device_ops bnx2_netdev_ops = {
8296 .ndo_open = bnx2_open,
8297 .ndo_start_xmit = bnx2_start_xmit,
8298 .ndo_stop = bnx2_close,
Eric Dumazet5d07bf22010-07-08 04:08:43 +00008299 .ndo_get_stats64 = bnx2_get_stats64,
Stephen Hemminger0421eae2008-11-21 17:31:27 -08008300 .ndo_set_rx_mode = bnx2_set_rx_mode,
8301 .ndo_do_ioctl = bnx2_ioctl,
8302 .ndo_validate_addr = eth_validate_addr,
8303 .ndo_set_mac_address = bnx2_change_mac_addr,
8304 .ndo_change_mtu = bnx2_change_mtu,
Michał Mirosław8d7dfc22011-04-10 04:47:46 +00008305 .ndo_fix_features = bnx2_fix_features,
8306 .ndo_set_features = bnx2_set_features,
Stephen Hemminger0421eae2008-11-21 17:31:27 -08008307 .ndo_tx_timeout = bnx2_tx_timeout,
Alexey Dobriyan257ddbd2010-01-27 10:17:41 +00008308#ifdef CONFIG_NET_POLL_CONTROLLER
Stephen Hemminger0421eae2008-11-21 17:31:27 -08008309 .ndo_poll_controller = poll_bnx2,
8310#endif
8311};
8312
Michael Chan35efa7c2007-12-20 19:56:37 -08008313static int __devinit
Michael Chanb6016b72005-05-26 13:03:09 -07008314bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
8315{
8316 static int version_printed = 0;
8317 struct net_device *dev = NULL;
8318 struct bnx2 *bp;
Joe Perches0795af52007-10-03 17:59:30 -07008319 int rc;
Michael Chan883e5152007-05-03 13:25:11 -07008320 char str[40];
Michael Chanb6016b72005-05-26 13:03:09 -07008321
8322 if (version_printed++ == 0)
Joe Perches3a9c6a42010-02-17 15:01:51 +00008323 pr_info("%s", version);
Michael Chanb6016b72005-05-26 13:03:09 -07008324
8325 /* dev zeroed in init_etherdev */
Benjamin Li706bf242008-07-18 17:55:11 -07008326 dev = alloc_etherdev_mq(sizeof(*bp), TX_MAX_RINGS);
Michael Chanb6016b72005-05-26 13:03:09 -07008327
8328 if (!dev)
8329 return -ENOMEM;
8330
8331 rc = bnx2_init_board(pdev, dev);
8332 if (rc < 0) {
8333 free_netdev(dev);
8334 return rc;
8335 }
8336
Stephen Hemminger0421eae2008-11-21 17:31:27 -08008337 dev->netdev_ops = &bnx2_netdev_ops;
Michael Chanb6016b72005-05-26 13:03:09 -07008338 dev->watchdog_timeo = TX_TIMEOUT;
Michael Chanb6016b72005-05-26 13:03:09 -07008339 dev->ethtool_ops = &bnx2_ethtool_ops;
Michael Chanb6016b72005-05-26 13:03:09 -07008340
Michael Chan972ec0d2006-01-23 16:12:43 -08008341 bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07008342
Michael Chan1b2f9222007-05-03 13:20:19 -07008343 pci_set_drvdata(pdev, dev);
8344
Michael Chan57579f72009-04-04 16:51:14 -07008345 rc = bnx2_request_firmware(bp);
8346 if (rc)
8347 goto error;
8348
Michael Chan1b2f9222007-05-03 13:20:19 -07008349 memcpy(dev->dev_addr, bp->mac_addr, 6);
8350 memcpy(dev->perm_addr, bp->mac_addr, 6);
Michael Chan1b2f9222007-05-03 13:20:19 -07008351
Michał Mirosław8d7dfc22011-04-10 04:47:46 +00008352 dev->hw_features = NETIF_F_IP_CSUM | NETIF_F_SG |
8353 NETIF_F_TSO | NETIF_F_TSO_ECN |
8354 NETIF_F_RXHASH | NETIF_F_RXCSUM;
8355
8356 if (CHIP_NUM(bp) == CHIP_NUM_5709)
8357 dev->hw_features |= NETIF_F_IPV6_CSUM | NETIF_F_TSO6;
8358
8359 dev->vlan_features = dev->hw_features;
8360 dev->hw_features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
8361 dev->features |= dev->hw_features;
8362
Michael Chanb6016b72005-05-26 13:03:09 -07008363 if ((rc = register_netdev(dev))) {
Jeff Garzik9b91cf92006-06-27 11:39:50 -04008364 dev_err(&pdev->dev, "Cannot register net device\n");
Michael Chan57579f72009-04-04 16:51:14 -07008365 goto error;
Michael Chanb6016b72005-05-26 13:03:09 -07008366 }
8367
Joe Perches3a9c6a42010-02-17 15:01:51 +00008368 netdev_info(dev, "%s (%c%d) %s found at mem %lx, IRQ %d, node addr %pM\n",
8369 board_info[ent->driver_data].name,
8370 ((CHIP_ID(bp) & 0xf000) >> 12) + 'A',
8371 ((CHIP_ID(bp) & 0x0ff0) >> 4),
8372 bnx2_bus_string(bp, str),
8373 dev->base_addr,
8374 bp->pdev->irq, dev->dev_addr);
Michael Chanb6016b72005-05-26 13:03:09 -07008375
Michael Chanb6016b72005-05-26 13:03:09 -07008376 return 0;
Michael Chan57579f72009-04-04 16:51:14 -07008377
8378error:
8379 if (bp->mips_firmware)
8380 release_firmware(bp->mips_firmware);
8381 if (bp->rv2p_firmware)
8382 release_firmware(bp->rv2p_firmware);
8383
8384 if (bp->regview)
8385 iounmap(bp->regview);
8386 pci_release_regions(pdev);
8387 pci_disable_device(pdev);
8388 pci_set_drvdata(pdev, NULL);
8389 free_netdev(dev);
8390 return rc;
Michael Chanb6016b72005-05-26 13:03:09 -07008391}
8392
8393static void __devexit
8394bnx2_remove_one(struct pci_dev *pdev)
8395{
8396 struct net_device *dev = pci_get_drvdata(pdev);
Michael Chan972ec0d2006-01-23 16:12:43 -08008397 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07008398
8399 unregister_netdev(dev);
8400
Neil Horman8333a462011-04-26 10:30:11 +00008401 del_timer_sync(&bp->timer);
8402
Michael Chan57579f72009-04-04 16:51:14 -07008403 if (bp->mips_firmware)
8404 release_firmware(bp->mips_firmware);
8405 if (bp->rv2p_firmware)
8406 release_firmware(bp->rv2p_firmware);
8407
Michael Chanb6016b72005-05-26 13:03:09 -07008408 if (bp->regview)
8409 iounmap(bp->regview);
8410
Michael Chan354fcd72010-01-17 07:30:44 +00008411 kfree(bp->temp_stats_blk);
8412
Michael Chan4bb9ebc2011-01-25 22:14:51 +00008413 if (bp->flags & BNX2_FLAG_AER_ENABLED) {
Michael Chanc239f272010-10-11 16:12:28 -07008414 pci_disable_pcie_error_reporting(pdev);
Michael Chan4bb9ebc2011-01-25 22:14:51 +00008415 bp->flags &= ~BNX2_FLAG_AER_ENABLED;
8416 }
John Feeneycd709aa2010-08-22 17:45:53 +00008417
Michael Chanc239f272010-10-11 16:12:28 -07008418 free_netdev(dev);
John Feeneycd709aa2010-08-22 17:45:53 +00008419
Michael Chanb6016b72005-05-26 13:03:09 -07008420 pci_release_regions(pdev);
8421 pci_disable_device(pdev);
8422 pci_set_drvdata(pdev, NULL);
8423}
8424
8425static int
Pavel Machek829ca9a2005-09-03 15:56:56 -07008426bnx2_suspend(struct pci_dev *pdev, pm_message_t state)
Michael Chanb6016b72005-05-26 13:03:09 -07008427{
8428 struct net_device *dev = pci_get_drvdata(pdev);
Michael Chan972ec0d2006-01-23 16:12:43 -08008429 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07008430
Michael Chan6caebb02007-08-03 20:57:25 -07008431 /* PCI register 4 needs to be saved whether netif_running() or not.
8432 * MSI address and data need to be saved if using MSI and
8433 * netif_running().
8434 */
8435 pci_save_state(pdev);
Michael Chanb6016b72005-05-26 13:03:09 -07008436 if (!netif_running(dev))
8437 return 0;
8438
Tejun Heo23f333a2010-12-12 16:45:14 +01008439 cancel_work_sync(&bp->reset_task);
Michael Chan212f9932010-04-27 11:28:10 +00008440 bnx2_netif_stop(bp, true);
Michael Chanb6016b72005-05-26 13:03:09 -07008441 netif_device_detach(dev);
8442 del_timer_sync(&bp->timer);
Michael Chan74bf4ba2008-10-09 12:21:08 -07008443 bnx2_shutdown_chip(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07008444 bnx2_free_skbs(bp);
Pavel Machek829ca9a2005-09-03 15:56:56 -07008445 bnx2_set_power_state(bp, pci_choose_state(pdev, state));
Michael Chanb6016b72005-05-26 13:03:09 -07008446 return 0;
8447}
8448
8449static int
8450bnx2_resume(struct pci_dev *pdev)
8451{
8452 struct net_device *dev = pci_get_drvdata(pdev);
Michael Chan972ec0d2006-01-23 16:12:43 -08008453 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07008454
Michael Chan6caebb02007-08-03 20:57:25 -07008455 pci_restore_state(pdev);
Michael Chanb6016b72005-05-26 13:03:09 -07008456 if (!netif_running(dev))
8457 return 0;
8458
Pavel Machek829ca9a2005-09-03 15:56:56 -07008459 bnx2_set_power_state(bp, PCI_D0);
Michael Chanb6016b72005-05-26 13:03:09 -07008460 netif_device_attach(dev);
Michael Chan9a120bc2008-05-16 22:17:45 -07008461 bnx2_init_nic(bp, 1);
Michael Chan212f9932010-04-27 11:28:10 +00008462 bnx2_netif_start(bp, true);
Michael Chanb6016b72005-05-26 13:03:09 -07008463 return 0;
8464}
8465
Wendy Xiong6ff2da42008-05-16 22:18:21 -07008466/**
8467 * bnx2_io_error_detected - called when PCI error is detected
8468 * @pdev: Pointer to PCI device
8469 * @state: The current pci connection state
8470 *
8471 * This function is called after a PCI bus error affecting
8472 * this device has been detected.
8473 */
8474static pci_ers_result_t bnx2_io_error_detected(struct pci_dev *pdev,
8475 pci_channel_state_t state)
8476{
8477 struct net_device *dev = pci_get_drvdata(pdev);
8478 struct bnx2 *bp = netdev_priv(dev);
8479
8480 rtnl_lock();
8481 netif_device_detach(dev);
8482
Dean Nelson2ec3de22009-07-31 09:13:18 +00008483 if (state == pci_channel_io_perm_failure) {
8484 rtnl_unlock();
8485 return PCI_ERS_RESULT_DISCONNECT;
8486 }
8487
Wendy Xiong6ff2da42008-05-16 22:18:21 -07008488 if (netif_running(dev)) {
Michael Chan212f9932010-04-27 11:28:10 +00008489 bnx2_netif_stop(bp, true);
Wendy Xiong6ff2da42008-05-16 22:18:21 -07008490 del_timer_sync(&bp->timer);
8491 bnx2_reset_nic(bp, BNX2_DRV_MSG_CODE_RESET);
8492 }
8493
8494 pci_disable_device(pdev);
8495 rtnl_unlock();
8496
8497 /* Request a slot slot reset. */
8498 return PCI_ERS_RESULT_NEED_RESET;
8499}
8500
8501/**
8502 * bnx2_io_slot_reset - called after the pci bus has been reset.
8503 * @pdev: Pointer to PCI device
8504 *
8505 * Restart the card from scratch, as if from a cold-boot.
8506 */
8507static pci_ers_result_t bnx2_io_slot_reset(struct pci_dev *pdev)
8508{
8509 struct net_device *dev = pci_get_drvdata(pdev);
8510 struct bnx2 *bp = netdev_priv(dev);
John Feeneycd709aa2010-08-22 17:45:53 +00008511 pci_ers_result_t result;
8512 int err;
Wendy Xiong6ff2da42008-05-16 22:18:21 -07008513
8514 rtnl_lock();
8515 if (pci_enable_device(pdev)) {
8516 dev_err(&pdev->dev,
Joe Perches3a9c6a42010-02-17 15:01:51 +00008517 "Cannot re-enable PCI device after reset\n");
John Feeneycd709aa2010-08-22 17:45:53 +00008518 result = PCI_ERS_RESULT_DISCONNECT;
8519 } else {
8520 pci_set_master(pdev);
8521 pci_restore_state(pdev);
8522 pci_save_state(pdev);
Wendy Xiong6ff2da42008-05-16 22:18:21 -07008523
John Feeneycd709aa2010-08-22 17:45:53 +00008524 if (netif_running(dev)) {
8525 bnx2_set_power_state(bp, PCI_D0);
8526 bnx2_init_nic(bp, 1);
8527 }
8528 result = PCI_ERS_RESULT_RECOVERED;
Wendy Xiong6ff2da42008-05-16 22:18:21 -07008529 }
Wendy Xiong6ff2da42008-05-16 22:18:21 -07008530 rtnl_unlock();
John Feeneycd709aa2010-08-22 17:45:53 +00008531
Michael Chan4bb9ebc2011-01-25 22:14:51 +00008532 if (!(bp->flags & BNX2_FLAG_AER_ENABLED))
Michael Chanc239f272010-10-11 16:12:28 -07008533 return result;
8534
John Feeneycd709aa2010-08-22 17:45:53 +00008535 err = pci_cleanup_aer_uncorrect_error_status(pdev);
8536 if (err) {
8537 dev_err(&pdev->dev,
8538 "pci_cleanup_aer_uncorrect_error_status failed 0x%0x\n",
8539 err); /* non-fatal, continue */
8540 }
8541
8542 return result;
Wendy Xiong6ff2da42008-05-16 22:18:21 -07008543}
8544
8545/**
8546 * bnx2_io_resume - called when traffic can start flowing again.
8547 * @pdev: Pointer to PCI device
8548 *
8549 * This callback is called when the error recovery driver tells us that
8550 * its OK to resume normal operation.
8551 */
8552static void bnx2_io_resume(struct pci_dev *pdev)
8553{
8554 struct net_device *dev = pci_get_drvdata(pdev);
8555 struct bnx2 *bp = netdev_priv(dev);
8556
8557 rtnl_lock();
8558 if (netif_running(dev))
Michael Chan212f9932010-04-27 11:28:10 +00008559 bnx2_netif_start(bp, true);
Wendy Xiong6ff2da42008-05-16 22:18:21 -07008560
8561 netif_device_attach(dev);
8562 rtnl_unlock();
8563}
8564
8565static struct pci_error_handlers bnx2_err_handler = {
8566 .error_detected = bnx2_io_error_detected,
8567 .slot_reset = bnx2_io_slot_reset,
8568 .resume = bnx2_io_resume,
8569};
8570
Michael Chanb6016b72005-05-26 13:03:09 -07008571static struct pci_driver bnx2_pci_driver = {
Peter Hagervall14ab9b82005-08-10 14:18:16 -07008572 .name = DRV_MODULE_NAME,
8573 .id_table = bnx2_pci_tbl,
8574 .probe = bnx2_init_one,
8575 .remove = __devexit_p(bnx2_remove_one),
8576 .suspend = bnx2_suspend,
8577 .resume = bnx2_resume,
Wendy Xiong6ff2da42008-05-16 22:18:21 -07008578 .err_handler = &bnx2_err_handler,
Michael Chanb6016b72005-05-26 13:03:09 -07008579};
8580
8581static int __init bnx2_init(void)
8582{
Jeff Garzik29917622006-08-19 17:48:59 -04008583 return pci_register_driver(&bnx2_pci_driver);
Michael Chanb6016b72005-05-26 13:03:09 -07008584}
8585
8586static void __exit bnx2_cleanup(void)
8587{
8588 pci_unregister_driver(&bnx2_pci_driver);
8589}
8590
8591module_init(bnx2_init);
8592module_exit(bnx2_cleanup);
8593
8594
8595