blob: 949d7a9dcf9269b4ccef78703ffb7e1701767237 [file] [log] [blame]
Michael Chanb6016b72005-05-26 13:03:09 -07001/* bnx2.c: Broadcom NX2 network driver.
2 *
Michael Chanbec92042010-02-16 15:19:42 -08003 * Copyright (c) 2004-2010 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>
David S. Miller08013fa2008-08-15 19:46:01 -070040#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
Michael Chanf2a4f052006-03-23 01:13:12 -080041#define BCM_VLAN 1
42#endif
Michael Chanf2a4f052006-03-23 01:13:12 -080043#include <net/ip.h>
Linus Torvaldsde081fa2007-07-12 16:40:08 -070044#include <net/tcp.h>
Michael Chanf2a4f052006-03-23 01:13:12 -080045#include <net/checksum.h>
Michael Chanf2a4f052006-03-23 01:13:12 -080046#include <linux/workqueue.h>
47#include <linux/crc32.h>
48#include <linux/prefetch.h>
Michael Chan29b12172006-03-23 01:13:43 -080049#include <linux/cache.h>
Michael Chan57579f72009-04-04 16:51:14 -070050#include <linux/firmware.h>
Benjamin Li706bf242008-07-18 17:55:11 -070051#include <linux/log2.h>
Michael Chanf2a4f052006-03-23 01:13:12 -080052
Michael Chan4edd4732009-06-08 18:14:42 -070053#if defined(CONFIG_CNIC) || defined(CONFIG_CNIC_MODULE)
54#define BCM_CNIC 1
55#include "cnic_if.h"
56#endif
Michael Chanb6016b72005-05-26 13:03:09 -070057#include "bnx2.h"
58#include "bnx2_fw.h"
Denys Vlasenkob3448b02007-09-30 17:55:51 -070059
Michael Chanb6016b72005-05-26 13:03:09 -070060#define DRV_MODULE_NAME "bnx2"
Michael Chana931d292010-05-17 17:33:31 -070061#define DRV_MODULE_VERSION "2.0.15"
62#define DRV_MODULE_RELDATE "May 4, 2010"
Michael Chanbec92042010-02-16 15:19:42 -080063#define FW_MIPS_FILE_06 "bnx2/bnx2-mips-06-5.0.0.j6.fw"
Michael Chan078b0732009-08-29 00:02:46 -070064#define FW_RV2P_FILE_06 "bnx2/bnx2-rv2p-06-5.0.0.j3.fw"
Michael Chana931d292010-05-17 17:33:31 -070065#define FW_MIPS_FILE_09 "bnx2/bnx2-mips-09-5.0.0.j15.fw"
Michael Chanbec92042010-02-16 15:19:42 -080066#define FW_RV2P_FILE_09_Ax "bnx2/bnx2-rv2p-09ax-5.0.0.j10.fw"
67#define FW_RV2P_FILE_09 "bnx2/bnx2-rv2p-09-5.0.0.j10.fw"
Michael Chanb6016b72005-05-26 13:03:09 -070068
69#define RUN_AT(x) (jiffies + (x))
70
71/* Time in jiffies before concluding the transmitter is hung. */
72#define TX_TIMEOUT (5*HZ)
73
Andrew Mortonfefa8642008-02-09 23:17:15 -080074static char version[] __devinitdata =
Michael Chanb6016b72005-05-26 13:03:09 -070075 "Broadcom NetXtreme II Gigabit Ethernet Driver " DRV_MODULE_NAME " v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";
76
77MODULE_AUTHOR("Michael Chan <mchan@broadcom.com>");
Benjamin Li453a9c62008-09-18 16:39:16 -070078MODULE_DESCRIPTION("Broadcom NetXtreme II BCM5706/5708/5709/5716 Driver");
Michael Chanb6016b72005-05-26 13:03:09 -070079MODULE_LICENSE("GPL");
80MODULE_VERSION(DRV_MODULE_VERSION);
Michael Chan57579f72009-04-04 16:51:14 -070081MODULE_FIRMWARE(FW_MIPS_FILE_06);
82MODULE_FIRMWARE(FW_RV2P_FILE_06);
83MODULE_FIRMWARE(FW_MIPS_FILE_09);
84MODULE_FIRMWARE(FW_RV2P_FILE_09);
Michael Chan078b0732009-08-29 00:02:46 -070085MODULE_FIRMWARE(FW_RV2P_FILE_09_Ax);
Michael Chanb6016b72005-05-26 13:03:09 -070086
87static int disable_msi = 0;
88
89module_param(disable_msi, int, 0);
90MODULE_PARM_DESC(disable_msi, "Disable Message Signaled Interrupt (MSI)");
91
92typedef enum {
93 BCM5706 = 0,
94 NC370T,
95 NC370I,
96 BCM5706S,
97 NC370F,
Michael Chan5b0c76a2005-11-04 08:45:49 -080098 BCM5708,
99 BCM5708S,
Michael Chanbac0dff2006-11-19 14:15:05 -0800100 BCM5709,
Michael Chan27a005b2007-05-03 13:23:41 -0700101 BCM5709S,
Michael Chan7bb0a042008-07-14 22:37:47 -0700102 BCM5716,
Michael Chan1caacec2008-11-12 16:01:12 -0800103 BCM5716S,
Michael Chanb6016b72005-05-26 13:03:09 -0700104} board_t;
105
106/* indexed by board_t, above */
Andrew Mortonfefa8642008-02-09 23:17:15 -0800107static struct {
Michael Chanb6016b72005-05-26 13:03:09 -0700108 char *name;
109} board_info[] __devinitdata = {
110 { "Broadcom NetXtreme II BCM5706 1000Base-T" },
111 { "HP NC370T Multifunction Gigabit Server Adapter" },
112 { "HP NC370i Multifunction Gigabit Server Adapter" },
113 { "Broadcom NetXtreme II BCM5706 1000Base-SX" },
114 { "HP NC370F Multifunction Gigabit Server Adapter" },
Michael Chan5b0c76a2005-11-04 08:45:49 -0800115 { "Broadcom NetXtreme II BCM5708 1000Base-T" },
116 { "Broadcom NetXtreme II BCM5708 1000Base-SX" },
Michael Chanbac0dff2006-11-19 14:15:05 -0800117 { "Broadcom NetXtreme II BCM5709 1000Base-T" },
Michael Chan27a005b2007-05-03 13:23:41 -0700118 { "Broadcom NetXtreme II BCM5709 1000Base-SX" },
Michael Chan7bb0a042008-07-14 22:37:47 -0700119 { "Broadcom NetXtreme II BCM5716 1000Base-T" },
Michael Chan1caacec2008-11-12 16:01:12 -0800120 { "Broadcom NetXtreme II BCM5716 1000Base-SX" },
Michael Chanb6016b72005-05-26 13:03:09 -0700121 };
122
Michael Chan7bb0a042008-07-14 22:37:47 -0700123static DEFINE_PCI_DEVICE_TABLE(bnx2_pci_tbl) = {
Michael Chanb6016b72005-05-26 13:03:09 -0700124 { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5706,
125 PCI_VENDOR_ID_HP, 0x3101, 0, 0, NC370T },
126 { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5706,
127 PCI_VENDOR_ID_HP, 0x3106, 0, 0, NC370I },
128 { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5706,
129 PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5706 },
Michael Chan5b0c76a2005-11-04 08:45:49 -0800130 { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5708,
131 PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5708 },
Michael Chanb6016b72005-05-26 13:03:09 -0700132 { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5706S,
133 PCI_VENDOR_ID_HP, 0x3102, 0, 0, NC370F },
134 { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5706S,
135 PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5706S },
Michael Chan5b0c76a2005-11-04 08:45:49 -0800136 { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5708S,
137 PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5708S },
Michael Chanbac0dff2006-11-19 14:15:05 -0800138 { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5709,
139 PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5709 },
Michael Chan27a005b2007-05-03 13:23:41 -0700140 { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5709S,
141 PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5709S },
Michael Chan7bb0a042008-07-14 22:37:47 -0700142 { PCI_VENDOR_ID_BROADCOM, 0x163b,
143 PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5716 },
Michael Chan1caacec2008-11-12 16:01:12 -0800144 { PCI_VENDOR_ID_BROADCOM, 0x163c,
Michael Chan1f2435e2008-12-16 20:28:13 -0800145 PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5716S },
Michael Chanb6016b72005-05-26 13:03:09 -0700146 { 0, }
147};
148
Michael Chan0ced9d02009-08-21 16:20:49 +0000149static const struct flash_spec flash_table[] =
Michael Chanb6016b72005-05-26 13:03:09 -0700150{
Michael Chane30372c2007-07-16 18:26:23 -0700151#define BUFFERED_FLAGS (BNX2_NV_BUFFERED | BNX2_NV_TRANSLATE)
152#define NONBUFFERED_FLAGS (BNX2_NV_WREN)
Michael Chanb6016b72005-05-26 13:03:09 -0700153 /* Slow EEPROM */
Michael Chan37137702005-11-04 08:49:17 -0800154 {0x00000000, 0x40830380, 0x009f0081, 0xa184a053, 0xaf000400,
Michael Chane30372c2007-07-16 18:26:23 -0700155 BUFFERED_FLAGS, SEEPROM_PAGE_BITS, SEEPROM_PAGE_SIZE,
Michael Chanb6016b72005-05-26 13:03:09 -0700156 SEEPROM_BYTE_ADDR_MASK, SEEPROM_TOTAL_SIZE,
157 "EEPROM - slow"},
Michael Chan37137702005-11-04 08:49:17 -0800158 /* Expansion entry 0001 */
159 {0x08000002, 0x4b808201, 0x00050081, 0x03840253, 0xaf020406,
Michael Chane30372c2007-07-16 18:26:23 -0700160 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
Michael Chan37137702005-11-04 08:49:17 -0800161 SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
162 "Entry 0001"},
Michael Chanb6016b72005-05-26 13:03:09 -0700163 /* Saifun SA25F010 (non-buffered flash) */
164 /* strap, cfg1, & write1 need updates */
Michael Chan37137702005-11-04 08:49:17 -0800165 {0x04000001, 0x47808201, 0x00050081, 0x03840253, 0xaf020406,
Michael Chane30372c2007-07-16 18:26:23 -0700166 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
Michael Chanb6016b72005-05-26 13:03:09 -0700167 SAIFUN_FLASH_BYTE_ADDR_MASK, SAIFUN_FLASH_BASE_TOTAL_SIZE*2,
168 "Non-buffered flash (128kB)"},
169 /* Saifun SA25F020 (non-buffered flash) */
170 /* strap, cfg1, & write1 need updates */
Michael Chan37137702005-11-04 08:49:17 -0800171 {0x0c000003, 0x4f808201, 0x00050081, 0x03840253, 0xaf020406,
Michael Chane30372c2007-07-16 18:26:23 -0700172 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
Michael Chanb6016b72005-05-26 13:03:09 -0700173 SAIFUN_FLASH_BYTE_ADDR_MASK, SAIFUN_FLASH_BASE_TOTAL_SIZE*4,
174 "Non-buffered flash (256kB)"},
Michael Chan37137702005-11-04 08:49:17 -0800175 /* Expansion entry 0100 */
176 {0x11000000, 0x53808201, 0x00050081, 0x03840253, 0xaf020406,
Michael Chane30372c2007-07-16 18:26:23 -0700177 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
Michael Chan37137702005-11-04 08:49:17 -0800178 SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
179 "Entry 0100"},
180 /* Entry 0101: ST M45PE10 (non-buffered flash, TetonII B0) */
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400181 {0x19000002, 0x5b808201, 0x000500db, 0x03840253, 0xaf020406,
Michael Chane30372c2007-07-16 18:26:23 -0700182 NONBUFFERED_FLAGS, ST_MICRO_FLASH_PAGE_BITS, ST_MICRO_FLASH_PAGE_SIZE,
Michael Chan37137702005-11-04 08:49:17 -0800183 ST_MICRO_FLASH_BYTE_ADDR_MASK, ST_MICRO_FLASH_BASE_TOTAL_SIZE*2,
184 "Entry 0101: ST M45PE10 (128kB non-bufferred)"},
185 /* Entry 0110: ST M45PE20 (non-buffered flash)*/
186 {0x15000001, 0x57808201, 0x000500db, 0x03840253, 0xaf020406,
Michael Chane30372c2007-07-16 18:26:23 -0700187 NONBUFFERED_FLAGS, ST_MICRO_FLASH_PAGE_BITS, ST_MICRO_FLASH_PAGE_SIZE,
Michael Chan37137702005-11-04 08:49:17 -0800188 ST_MICRO_FLASH_BYTE_ADDR_MASK, ST_MICRO_FLASH_BASE_TOTAL_SIZE*4,
189 "Entry 0110: ST M45PE20 (256kB non-bufferred)"},
190 /* Saifun SA25F005 (non-buffered flash) */
191 /* strap, cfg1, & write1 need updates */
192 {0x1d000003, 0x5f808201, 0x00050081, 0x03840253, 0xaf020406,
Michael Chane30372c2007-07-16 18:26:23 -0700193 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
Michael Chan37137702005-11-04 08:49:17 -0800194 SAIFUN_FLASH_BYTE_ADDR_MASK, SAIFUN_FLASH_BASE_TOTAL_SIZE,
195 "Non-buffered flash (64kB)"},
196 /* Fast EEPROM */
197 {0x22000000, 0x62808380, 0x009f0081, 0xa184a053, 0xaf000400,
Michael Chane30372c2007-07-16 18:26:23 -0700198 BUFFERED_FLAGS, SEEPROM_PAGE_BITS, SEEPROM_PAGE_SIZE,
Michael Chan37137702005-11-04 08:49:17 -0800199 SEEPROM_BYTE_ADDR_MASK, SEEPROM_TOTAL_SIZE,
200 "EEPROM - fast"},
201 /* Expansion entry 1001 */
202 {0x2a000002, 0x6b808201, 0x00050081, 0x03840253, 0xaf020406,
Michael Chane30372c2007-07-16 18:26:23 -0700203 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
Michael Chan37137702005-11-04 08:49:17 -0800204 SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
205 "Entry 1001"},
206 /* Expansion entry 1010 */
207 {0x26000001, 0x67808201, 0x00050081, 0x03840253, 0xaf020406,
Michael Chane30372c2007-07-16 18:26:23 -0700208 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
Michael Chan37137702005-11-04 08:49:17 -0800209 SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
210 "Entry 1010"},
211 /* ATMEL AT45DB011B (buffered flash) */
212 {0x2e000003, 0x6e808273, 0x00570081, 0x68848353, 0xaf000400,
Michael Chane30372c2007-07-16 18:26:23 -0700213 BUFFERED_FLAGS, BUFFERED_FLASH_PAGE_BITS, BUFFERED_FLASH_PAGE_SIZE,
Michael Chan37137702005-11-04 08:49:17 -0800214 BUFFERED_FLASH_BYTE_ADDR_MASK, BUFFERED_FLASH_TOTAL_SIZE,
215 "Buffered flash (128kB)"},
216 /* Expansion entry 1100 */
217 {0x33000000, 0x73808201, 0x00050081, 0x03840253, 0xaf020406,
Michael Chane30372c2007-07-16 18:26:23 -0700218 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
Michael Chan37137702005-11-04 08:49:17 -0800219 SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
220 "Entry 1100"},
221 /* Expansion entry 1101 */
222 {0x3b000002, 0x7b808201, 0x00050081, 0x03840253, 0xaf020406,
Michael Chane30372c2007-07-16 18:26:23 -0700223 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
Michael Chan37137702005-11-04 08:49:17 -0800224 SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
225 "Entry 1101"},
226 /* Ateml Expansion entry 1110 */
227 {0x37000001, 0x76808273, 0x00570081, 0x68848353, 0xaf000400,
Michael Chane30372c2007-07-16 18:26:23 -0700228 BUFFERED_FLAGS, BUFFERED_FLASH_PAGE_BITS, BUFFERED_FLASH_PAGE_SIZE,
Michael Chan37137702005-11-04 08:49:17 -0800229 BUFFERED_FLASH_BYTE_ADDR_MASK, 0,
230 "Entry 1110 (Atmel)"},
231 /* ATMEL AT45DB021B (buffered flash) */
232 {0x3f000003, 0x7e808273, 0x00570081, 0x68848353, 0xaf000400,
Michael Chane30372c2007-07-16 18:26:23 -0700233 BUFFERED_FLAGS, BUFFERED_FLASH_PAGE_BITS, BUFFERED_FLASH_PAGE_SIZE,
Michael Chan37137702005-11-04 08:49:17 -0800234 BUFFERED_FLASH_BYTE_ADDR_MASK, BUFFERED_FLASH_TOTAL_SIZE*2,
235 "Buffered flash (256kB)"},
Michael Chanb6016b72005-05-26 13:03:09 -0700236};
237
Michael Chan0ced9d02009-08-21 16:20:49 +0000238static const struct flash_spec flash_5709 = {
Michael Chane30372c2007-07-16 18:26:23 -0700239 .flags = BNX2_NV_BUFFERED,
240 .page_bits = BCM5709_FLASH_PAGE_BITS,
241 .page_size = BCM5709_FLASH_PAGE_SIZE,
242 .addr_mask = BCM5709_FLASH_BYTE_ADDR_MASK,
243 .total_size = BUFFERED_FLASH_TOTAL_SIZE*2,
244 .name = "5709 Buffered flash (256kB)",
245};
246
Michael Chanb6016b72005-05-26 13:03:09 -0700247MODULE_DEVICE_TABLE(pci, bnx2_pci_tbl);
248
Benjamin Li4327ba42010-03-23 13:13:11 +0000249static void bnx2_init_napi(struct bnx2 *bp);
Michael Chanf048fa92010-06-01 15:05:36 +0000250static void bnx2_del_napi(struct bnx2 *bp);
Benjamin Li4327ba42010-03-23 13:13:11 +0000251
Michael Chan35e90102008-06-19 16:37:42 -0700252static inline u32 bnx2_tx_avail(struct bnx2 *bp, struct bnx2_tx_ring_info *txr)
Michael Chane89bbf12005-08-25 15:36:58 -0700253{
Michael Chan2f8af122006-08-15 01:39:10 -0700254 u32 diff;
Michael Chane89bbf12005-08-25 15:36:58 -0700255
Michael Chan2f8af122006-08-15 01:39:10 -0700256 smp_mb();
Michael Chanfaac9c42006-12-14 15:56:32 -0800257
258 /* The ring uses 256 indices for 255 entries, one of them
259 * needs to be skipped.
260 */
Michael Chan35e90102008-06-19 16:37:42 -0700261 diff = txr->tx_prod - txr->tx_cons;
Michael Chanfaac9c42006-12-14 15:56:32 -0800262 if (unlikely(diff >= TX_DESC_CNT)) {
263 diff &= 0xffff;
264 if (diff == TX_DESC_CNT)
265 diff = MAX_TX_DESC_CNT;
266 }
Michael Chane89bbf12005-08-25 15:36:58 -0700267 return (bp->tx_ring_size - diff);
268}
269
Michael Chanb6016b72005-05-26 13:03:09 -0700270static u32
271bnx2_reg_rd_ind(struct bnx2 *bp, u32 offset)
272{
Michael Chan1b8227c2007-05-03 13:24:05 -0700273 u32 val;
274
275 spin_lock_bh(&bp->indirect_lock);
Michael Chanb6016b72005-05-26 13:03:09 -0700276 REG_WR(bp, BNX2_PCICFG_REG_WINDOW_ADDRESS, offset);
Michael Chan1b8227c2007-05-03 13:24:05 -0700277 val = REG_RD(bp, BNX2_PCICFG_REG_WINDOW);
278 spin_unlock_bh(&bp->indirect_lock);
279 return val;
Michael Chanb6016b72005-05-26 13:03:09 -0700280}
281
282static void
283bnx2_reg_wr_ind(struct bnx2 *bp, u32 offset, u32 val)
284{
Michael Chan1b8227c2007-05-03 13:24:05 -0700285 spin_lock_bh(&bp->indirect_lock);
Michael Chanb6016b72005-05-26 13:03:09 -0700286 REG_WR(bp, BNX2_PCICFG_REG_WINDOW_ADDRESS, offset);
287 REG_WR(bp, BNX2_PCICFG_REG_WINDOW, val);
Michael Chan1b8227c2007-05-03 13:24:05 -0700288 spin_unlock_bh(&bp->indirect_lock);
Michael Chanb6016b72005-05-26 13:03:09 -0700289}
290
291static void
Michael Chan2726d6e2008-01-29 21:35:05 -0800292bnx2_shmem_wr(struct bnx2 *bp, u32 offset, u32 val)
293{
294 bnx2_reg_wr_ind(bp, bp->shmem_base + offset, val);
295}
296
297static u32
298bnx2_shmem_rd(struct bnx2 *bp, u32 offset)
299{
300 return (bnx2_reg_rd_ind(bp, bp->shmem_base + offset));
301}
302
303static void
Michael Chanb6016b72005-05-26 13:03:09 -0700304bnx2_ctx_wr(struct bnx2 *bp, u32 cid_addr, u32 offset, u32 val)
305{
306 offset += cid_addr;
Michael Chan1b8227c2007-05-03 13:24:05 -0700307 spin_lock_bh(&bp->indirect_lock);
Michael Chan59b47d82006-11-19 14:10:45 -0800308 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
309 int i;
310
311 REG_WR(bp, BNX2_CTX_CTX_DATA, val);
312 REG_WR(bp, BNX2_CTX_CTX_CTRL,
313 offset | BNX2_CTX_CTX_CTRL_WRITE_REQ);
314 for (i = 0; i < 5; i++) {
Michael Chan59b47d82006-11-19 14:10:45 -0800315 val = REG_RD(bp, BNX2_CTX_CTX_CTRL);
316 if ((val & BNX2_CTX_CTX_CTRL_WRITE_REQ) == 0)
317 break;
318 udelay(5);
319 }
320 } else {
321 REG_WR(bp, BNX2_CTX_DATA_ADR, offset);
322 REG_WR(bp, BNX2_CTX_DATA, val);
323 }
Michael Chan1b8227c2007-05-03 13:24:05 -0700324 spin_unlock_bh(&bp->indirect_lock);
Michael Chanb6016b72005-05-26 13:03:09 -0700325}
326
Michael Chan4edd4732009-06-08 18:14:42 -0700327#ifdef BCM_CNIC
328static int
329bnx2_drv_ctl(struct net_device *dev, struct drv_ctl_info *info)
330{
331 struct bnx2 *bp = netdev_priv(dev);
332 struct drv_ctl_io *io = &info->data.io;
333
334 switch (info->cmd) {
335 case DRV_CTL_IO_WR_CMD:
336 bnx2_reg_wr_ind(bp, io->offset, io->data);
337 break;
338 case DRV_CTL_IO_RD_CMD:
339 io->data = bnx2_reg_rd_ind(bp, io->offset);
340 break;
341 case DRV_CTL_CTX_WR_CMD:
342 bnx2_ctx_wr(bp, io->cid_addr, io->offset, io->data);
343 break;
344 default:
345 return -EINVAL;
346 }
347 return 0;
348}
349
350static void bnx2_setup_cnic_irq_info(struct bnx2 *bp)
351{
352 struct cnic_eth_dev *cp = &bp->cnic_eth_dev;
353 struct bnx2_napi *bnapi = &bp->bnx2_napi[0];
354 int sb_id;
355
356 if (bp->flags & BNX2_FLAG_USING_MSIX) {
357 cp->drv_state |= CNIC_DRV_STATE_USING_MSIX;
358 bnapi->cnic_present = 0;
359 sb_id = bp->irq_nvecs;
360 cp->irq_arr[0].irq_flags |= CNIC_IRQ_FL_MSIX;
361 } else {
362 cp->drv_state &= ~CNIC_DRV_STATE_USING_MSIX;
363 bnapi->cnic_tag = bnapi->last_status_idx;
364 bnapi->cnic_present = 1;
365 sb_id = 0;
366 cp->irq_arr[0].irq_flags &= ~CNIC_IRQ_FL_MSIX;
367 }
368
369 cp->irq_arr[0].vector = bp->irq_tbl[sb_id].vector;
370 cp->irq_arr[0].status_blk = (void *)
371 ((unsigned long) bnapi->status_blk.msi +
372 (BNX2_SBLK_MSIX_ALIGN_SIZE * sb_id));
373 cp->irq_arr[0].status_blk_num = sb_id;
374 cp->num_irq = 1;
375}
376
377static int bnx2_register_cnic(struct net_device *dev, struct cnic_ops *ops,
378 void *data)
379{
380 struct bnx2 *bp = netdev_priv(dev);
381 struct cnic_eth_dev *cp = &bp->cnic_eth_dev;
382
383 if (ops == NULL)
384 return -EINVAL;
385
386 if (cp->drv_state & CNIC_DRV_STATE_REGD)
387 return -EBUSY;
388
389 bp->cnic_data = data;
390 rcu_assign_pointer(bp->cnic_ops, ops);
391
392 cp->num_irq = 0;
393 cp->drv_state = CNIC_DRV_STATE_REGD;
394
395 bnx2_setup_cnic_irq_info(bp);
396
397 return 0;
398}
399
400static int bnx2_unregister_cnic(struct net_device *dev)
401{
402 struct bnx2 *bp = netdev_priv(dev);
403 struct bnx2_napi *bnapi = &bp->bnx2_napi[0];
404 struct cnic_eth_dev *cp = &bp->cnic_eth_dev;
405
Michael Chanc5a88952009-08-14 15:49:45 +0000406 mutex_lock(&bp->cnic_lock);
Michael Chan4edd4732009-06-08 18:14:42 -0700407 cp->drv_state = 0;
408 bnapi->cnic_present = 0;
409 rcu_assign_pointer(bp->cnic_ops, NULL);
Michael Chanc5a88952009-08-14 15:49:45 +0000410 mutex_unlock(&bp->cnic_lock);
Michael Chan4edd4732009-06-08 18:14:42 -0700411 synchronize_rcu();
412 return 0;
413}
414
415struct cnic_eth_dev *bnx2_cnic_probe(struct net_device *dev)
416{
417 struct bnx2 *bp = netdev_priv(dev);
418 struct cnic_eth_dev *cp = &bp->cnic_eth_dev;
419
420 cp->drv_owner = THIS_MODULE;
421 cp->chip_id = bp->chip_id;
422 cp->pdev = bp->pdev;
423 cp->io_base = bp->regview;
424 cp->drv_ctl = bnx2_drv_ctl;
425 cp->drv_register_cnic = bnx2_register_cnic;
426 cp->drv_unregister_cnic = bnx2_unregister_cnic;
427
428 return cp;
429}
430EXPORT_SYMBOL(bnx2_cnic_probe);
431
432static void
433bnx2_cnic_stop(struct bnx2 *bp)
434{
435 struct cnic_ops *c_ops;
436 struct cnic_ctl_info info;
437
Michael Chanc5a88952009-08-14 15:49:45 +0000438 mutex_lock(&bp->cnic_lock);
439 c_ops = bp->cnic_ops;
Michael Chan4edd4732009-06-08 18:14:42 -0700440 if (c_ops) {
441 info.cmd = CNIC_CTL_STOP_CMD;
442 c_ops->cnic_ctl(bp->cnic_data, &info);
443 }
Michael Chanc5a88952009-08-14 15:49:45 +0000444 mutex_unlock(&bp->cnic_lock);
Michael Chan4edd4732009-06-08 18:14:42 -0700445}
446
447static void
448bnx2_cnic_start(struct bnx2 *bp)
449{
450 struct cnic_ops *c_ops;
451 struct cnic_ctl_info info;
452
Michael Chanc5a88952009-08-14 15:49:45 +0000453 mutex_lock(&bp->cnic_lock);
454 c_ops = bp->cnic_ops;
Michael Chan4edd4732009-06-08 18:14:42 -0700455 if (c_ops) {
456 if (!(bp->flags & BNX2_FLAG_USING_MSIX)) {
457 struct bnx2_napi *bnapi = &bp->bnx2_napi[0];
458
459 bnapi->cnic_tag = bnapi->last_status_idx;
460 }
461 info.cmd = CNIC_CTL_START_CMD;
462 c_ops->cnic_ctl(bp->cnic_data, &info);
463 }
Michael Chanc5a88952009-08-14 15:49:45 +0000464 mutex_unlock(&bp->cnic_lock);
Michael Chan4edd4732009-06-08 18:14:42 -0700465}
466
467#else
468
469static void
470bnx2_cnic_stop(struct bnx2 *bp)
471{
472}
473
474static void
475bnx2_cnic_start(struct bnx2 *bp)
476{
477}
478
479#endif
480
Michael Chanb6016b72005-05-26 13:03:09 -0700481static int
482bnx2_read_phy(struct bnx2 *bp, u32 reg, u32 *val)
483{
484 u32 val1;
485 int i, ret;
486
Michael Chan583c28e2008-01-21 19:51:35 -0800487 if (bp->phy_flags & BNX2_PHY_FLAG_INT_MODE_AUTO_POLLING) {
Michael Chanb6016b72005-05-26 13:03:09 -0700488 val1 = REG_RD(bp, BNX2_EMAC_MDIO_MODE);
489 val1 &= ~BNX2_EMAC_MDIO_MODE_AUTO_POLL;
490
491 REG_WR(bp, BNX2_EMAC_MDIO_MODE, val1);
492 REG_RD(bp, BNX2_EMAC_MDIO_MODE);
493
494 udelay(40);
495 }
496
497 val1 = (bp->phy_addr << 21) | (reg << 16) |
498 BNX2_EMAC_MDIO_COMM_COMMAND_READ | BNX2_EMAC_MDIO_COMM_DISEXT |
499 BNX2_EMAC_MDIO_COMM_START_BUSY;
500 REG_WR(bp, BNX2_EMAC_MDIO_COMM, val1);
501
502 for (i = 0; i < 50; i++) {
503 udelay(10);
504
505 val1 = REG_RD(bp, BNX2_EMAC_MDIO_COMM);
506 if (!(val1 & BNX2_EMAC_MDIO_COMM_START_BUSY)) {
507 udelay(5);
508
509 val1 = REG_RD(bp, BNX2_EMAC_MDIO_COMM);
510 val1 &= BNX2_EMAC_MDIO_COMM_DATA;
511
512 break;
513 }
514 }
515
516 if (val1 & BNX2_EMAC_MDIO_COMM_START_BUSY) {
517 *val = 0x0;
518 ret = -EBUSY;
519 }
520 else {
521 *val = val1;
522 ret = 0;
523 }
524
Michael Chan583c28e2008-01-21 19:51:35 -0800525 if (bp->phy_flags & BNX2_PHY_FLAG_INT_MODE_AUTO_POLLING) {
Michael Chanb6016b72005-05-26 13:03:09 -0700526 val1 = REG_RD(bp, BNX2_EMAC_MDIO_MODE);
527 val1 |= BNX2_EMAC_MDIO_MODE_AUTO_POLL;
528
529 REG_WR(bp, BNX2_EMAC_MDIO_MODE, val1);
530 REG_RD(bp, BNX2_EMAC_MDIO_MODE);
531
532 udelay(40);
533 }
534
535 return ret;
536}
537
538static int
539bnx2_write_phy(struct bnx2 *bp, u32 reg, u32 val)
540{
541 u32 val1;
542 int i, ret;
543
Michael Chan583c28e2008-01-21 19:51:35 -0800544 if (bp->phy_flags & BNX2_PHY_FLAG_INT_MODE_AUTO_POLLING) {
Michael Chanb6016b72005-05-26 13:03:09 -0700545 val1 = REG_RD(bp, BNX2_EMAC_MDIO_MODE);
546 val1 &= ~BNX2_EMAC_MDIO_MODE_AUTO_POLL;
547
548 REG_WR(bp, BNX2_EMAC_MDIO_MODE, val1);
549 REG_RD(bp, BNX2_EMAC_MDIO_MODE);
550
551 udelay(40);
552 }
553
554 val1 = (bp->phy_addr << 21) | (reg << 16) | val |
555 BNX2_EMAC_MDIO_COMM_COMMAND_WRITE |
556 BNX2_EMAC_MDIO_COMM_START_BUSY | BNX2_EMAC_MDIO_COMM_DISEXT;
557 REG_WR(bp, BNX2_EMAC_MDIO_COMM, val1);
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400558
Michael Chanb6016b72005-05-26 13:03:09 -0700559 for (i = 0; i < 50; i++) {
560 udelay(10);
561
562 val1 = REG_RD(bp, BNX2_EMAC_MDIO_COMM);
563 if (!(val1 & BNX2_EMAC_MDIO_COMM_START_BUSY)) {
564 udelay(5);
565 break;
566 }
567 }
568
569 if (val1 & BNX2_EMAC_MDIO_COMM_START_BUSY)
570 ret = -EBUSY;
571 else
572 ret = 0;
573
Michael Chan583c28e2008-01-21 19:51:35 -0800574 if (bp->phy_flags & BNX2_PHY_FLAG_INT_MODE_AUTO_POLLING) {
Michael Chanb6016b72005-05-26 13:03:09 -0700575 val1 = REG_RD(bp, BNX2_EMAC_MDIO_MODE);
576 val1 |= BNX2_EMAC_MDIO_MODE_AUTO_POLL;
577
578 REG_WR(bp, BNX2_EMAC_MDIO_MODE, val1);
579 REG_RD(bp, BNX2_EMAC_MDIO_MODE);
580
581 udelay(40);
582 }
583
584 return ret;
585}
586
587static void
588bnx2_disable_int(struct bnx2 *bp)
589{
Michael Chanb4b36042007-12-20 19:59:30 -0800590 int i;
591 struct bnx2_napi *bnapi;
592
593 for (i = 0; i < bp->irq_nvecs; i++) {
594 bnapi = &bp->bnx2_napi[i];
595 REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD, bnapi->int_num |
596 BNX2_PCICFG_INT_ACK_CMD_MASK_INT);
597 }
Michael Chanb6016b72005-05-26 13:03:09 -0700598 REG_RD(bp, BNX2_PCICFG_INT_ACK_CMD);
599}
600
601static void
602bnx2_enable_int(struct bnx2 *bp)
603{
Michael Chanb4b36042007-12-20 19:59:30 -0800604 int i;
605 struct bnx2_napi *bnapi;
Michael Chan1269a8a2006-01-23 16:11:03 -0800606
Michael Chanb4b36042007-12-20 19:59:30 -0800607 for (i = 0; i < bp->irq_nvecs; i++) {
608 bnapi = &bp->bnx2_napi[i];
Michael Chan35efa7c2007-12-20 19:56:37 -0800609
Michael Chanb4b36042007-12-20 19:59:30 -0800610 REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD, bnapi->int_num |
611 BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
612 BNX2_PCICFG_INT_ACK_CMD_MASK_INT |
613 bnapi->last_status_idx);
Michael Chanb6016b72005-05-26 13:03:09 -0700614
Michael Chanb4b36042007-12-20 19:59:30 -0800615 REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD, bnapi->int_num |
616 BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
617 bnapi->last_status_idx);
618 }
Michael Chanbf5295b2006-03-23 01:11:56 -0800619 REG_WR(bp, BNX2_HC_COMMAND, bp->hc_cmd | BNX2_HC_COMMAND_COAL_NOW);
Michael Chanb6016b72005-05-26 13:03:09 -0700620}
621
622static void
623bnx2_disable_int_sync(struct bnx2 *bp)
624{
Michael Chanb4b36042007-12-20 19:59:30 -0800625 int i;
626
Michael Chanb6016b72005-05-26 13:03:09 -0700627 atomic_inc(&bp->intr_sem);
Michael Chan37675462009-08-21 16:20:44 +0000628 if (!netif_running(bp->dev))
629 return;
630
Michael Chanb6016b72005-05-26 13:03:09 -0700631 bnx2_disable_int(bp);
Michael Chanb4b36042007-12-20 19:59:30 -0800632 for (i = 0; i < bp->irq_nvecs; i++)
633 synchronize_irq(bp->irq_tbl[i].vector);
Michael Chanb6016b72005-05-26 13:03:09 -0700634}
635
636static void
Michael Chan35efa7c2007-12-20 19:56:37 -0800637bnx2_napi_disable(struct bnx2 *bp)
638{
Michael Chanb4b36042007-12-20 19:59:30 -0800639 int i;
640
641 for (i = 0; i < bp->irq_nvecs; i++)
642 napi_disable(&bp->bnx2_napi[i].napi);
Michael Chan35efa7c2007-12-20 19:56:37 -0800643}
644
645static void
646bnx2_napi_enable(struct bnx2 *bp)
647{
Michael Chanb4b36042007-12-20 19:59:30 -0800648 int i;
649
650 for (i = 0; i < bp->irq_nvecs; i++)
651 napi_enable(&bp->bnx2_napi[i].napi);
Michael Chan35efa7c2007-12-20 19:56:37 -0800652}
653
654static void
Michael Chan212f9932010-04-27 11:28:10 +0000655bnx2_netif_stop(struct bnx2 *bp, bool stop_cnic)
Michael Chanb6016b72005-05-26 13:03:09 -0700656{
Michael Chan212f9932010-04-27 11:28:10 +0000657 if (stop_cnic)
658 bnx2_cnic_stop(bp);
Michael Chanb6016b72005-05-26 13:03:09 -0700659 if (netif_running(bp->dev)) {
Michael Chan35efa7c2007-12-20 19:56:37 -0800660 bnx2_napi_disable(bp);
Michael Chanb6016b72005-05-26 13:03:09 -0700661 netif_tx_disable(bp->dev);
Michael Chanb6016b72005-05-26 13:03:09 -0700662 }
Michael Chanb7466562009-12-20 18:40:18 -0800663 bnx2_disable_int_sync(bp);
Michael Chana0ba6762010-05-17 17:34:43 -0700664 netif_carrier_off(bp->dev); /* prevent tx timeout */
Michael Chanb6016b72005-05-26 13:03:09 -0700665}
666
667static void
Michael Chan212f9932010-04-27 11:28:10 +0000668bnx2_netif_start(struct bnx2 *bp, bool start_cnic)
Michael Chanb6016b72005-05-26 13:03:09 -0700669{
670 if (atomic_dec_and_test(&bp->intr_sem)) {
671 if (netif_running(bp->dev)) {
Benjamin Li706bf242008-07-18 17:55:11 -0700672 netif_tx_wake_all_queues(bp->dev);
Michael Chana0ba6762010-05-17 17:34:43 -0700673 spin_lock_bh(&bp->phy_lock);
674 if (bp->link_up)
675 netif_carrier_on(bp->dev);
676 spin_unlock_bh(&bp->phy_lock);
Michael Chan35efa7c2007-12-20 19:56:37 -0800677 bnx2_napi_enable(bp);
Michael Chanb6016b72005-05-26 13:03:09 -0700678 bnx2_enable_int(bp);
Michael Chan212f9932010-04-27 11:28:10 +0000679 if (start_cnic)
680 bnx2_cnic_start(bp);
Michael Chanb6016b72005-05-26 13:03:09 -0700681 }
682 }
683}
684
685static void
Michael Chan35e90102008-06-19 16:37:42 -0700686bnx2_free_tx_mem(struct bnx2 *bp)
687{
688 int i;
689
690 for (i = 0; i < bp->num_tx_rings; i++) {
691 struct bnx2_napi *bnapi = &bp->bnx2_napi[i];
692 struct bnx2_tx_ring_info *txr = &bnapi->tx_ring;
693
694 if (txr->tx_desc_ring) {
695 pci_free_consistent(bp->pdev, TXBD_RING_SIZE,
696 txr->tx_desc_ring,
697 txr->tx_desc_mapping);
698 txr->tx_desc_ring = NULL;
699 }
700 kfree(txr->tx_buf_ring);
701 txr->tx_buf_ring = NULL;
702 }
703}
704
Michael Chanbb4f98a2008-06-19 16:38:19 -0700705static void
706bnx2_free_rx_mem(struct bnx2 *bp)
707{
708 int i;
709
710 for (i = 0; i < bp->num_rx_rings; i++) {
711 struct bnx2_napi *bnapi = &bp->bnx2_napi[i];
712 struct bnx2_rx_ring_info *rxr = &bnapi->rx_ring;
713 int j;
714
715 for (j = 0; j < bp->rx_max_ring; j++) {
716 if (rxr->rx_desc_ring[j])
717 pci_free_consistent(bp->pdev, RXBD_RING_SIZE,
718 rxr->rx_desc_ring[j],
719 rxr->rx_desc_mapping[j]);
720 rxr->rx_desc_ring[j] = NULL;
721 }
Breno Leitao25b0b992009-06-08 10:30:19 +0000722 vfree(rxr->rx_buf_ring);
Michael Chanbb4f98a2008-06-19 16:38:19 -0700723 rxr->rx_buf_ring = NULL;
724
725 for (j = 0; j < bp->rx_max_pg_ring; j++) {
726 if (rxr->rx_pg_desc_ring[j])
727 pci_free_consistent(bp->pdev, RXBD_RING_SIZE,
Michael Chan3298a732008-12-17 19:06:08 -0800728 rxr->rx_pg_desc_ring[j],
729 rxr->rx_pg_desc_mapping[j]);
730 rxr->rx_pg_desc_ring[j] = NULL;
Michael Chanbb4f98a2008-06-19 16:38:19 -0700731 }
Breno Leitao25b0b992009-06-08 10:30:19 +0000732 vfree(rxr->rx_pg_ring);
Michael Chanbb4f98a2008-06-19 16:38:19 -0700733 rxr->rx_pg_ring = NULL;
734 }
735}
736
Michael Chan35e90102008-06-19 16:37:42 -0700737static int
738bnx2_alloc_tx_mem(struct bnx2 *bp)
739{
740 int i;
741
742 for (i = 0; i < bp->num_tx_rings; i++) {
743 struct bnx2_napi *bnapi = &bp->bnx2_napi[i];
744 struct bnx2_tx_ring_info *txr = &bnapi->tx_ring;
745
746 txr->tx_buf_ring = kzalloc(SW_TXBD_RING_SIZE, GFP_KERNEL);
747 if (txr->tx_buf_ring == NULL)
748 return -ENOMEM;
749
750 txr->tx_desc_ring =
751 pci_alloc_consistent(bp->pdev, TXBD_RING_SIZE,
752 &txr->tx_desc_mapping);
753 if (txr->tx_desc_ring == NULL)
754 return -ENOMEM;
755 }
756 return 0;
757}
758
Michael Chanbb4f98a2008-06-19 16:38:19 -0700759static int
760bnx2_alloc_rx_mem(struct bnx2 *bp)
761{
762 int i;
763
764 for (i = 0; i < bp->num_rx_rings; i++) {
765 struct bnx2_napi *bnapi = &bp->bnx2_napi[i];
766 struct bnx2_rx_ring_info *rxr = &bnapi->rx_ring;
767 int j;
768
769 rxr->rx_buf_ring =
770 vmalloc(SW_RXBD_RING_SIZE * bp->rx_max_ring);
771 if (rxr->rx_buf_ring == NULL)
772 return -ENOMEM;
773
774 memset(rxr->rx_buf_ring, 0,
775 SW_RXBD_RING_SIZE * bp->rx_max_ring);
776
777 for (j = 0; j < bp->rx_max_ring; j++) {
778 rxr->rx_desc_ring[j] =
779 pci_alloc_consistent(bp->pdev, RXBD_RING_SIZE,
780 &rxr->rx_desc_mapping[j]);
781 if (rxr->rx_desc_ring[j] == NULL)
782 return -ENOMEM;
783
784 }
785
786 if (bp->rx_pg_ring_size) {
787 rxr->rx_pg_ring = vmalloc(SW_RXPG_RING_SIZE *
788 bp->rx_max_pg_ring);
789 if (rxr->rx_pg_ring == NULL)
790 return -ENOMEM;
791
792 memset(rxr->rx_pg_ring, 0, SW_RXPG_RING_SIZE *
793 bp->rx_max_pg_ring);
794 }
795
796 for (j = 0; j < bp->rx_max_pg_ring; j++) {
797 rxr->rx_pg_desc_ring[j] =
798 pci_alloc_consistent(bp->pdev, RXBD_RING_SIZE,
799 &rxr->rx_pg_desc_mapping[j]);
800 if (rxr->rx_pg_desc_ring[j] == NULL)
801 return -ENOMEM;
802
803 }
804 }
805 return 0;
806}
807
Michael Chan35e90102008-06-19 16:37:42 -0700808static void
Michael Chanb6016b72005-05-26 13:03:09 -0700809bnx2_free_mem(struct bnx2 *bp)
810{
Michael Chan13daffa2006-03-20 17:49:20 -0800811 int i;
Michael Chan43e80b82008-06-19 16:41:08 -0700812 struct bnx2_napi *bnapi = &bp->bnx2_napi[0];
Michael Chan13daffa2006-03-20 17:49:20 -0800813
Michael Chan35e90102008-06-19 16:37:42 -0700814 bnx2_free_tx_mem(bp);
Michael Chanbb4f98a2008-06-19 16:38:19 -0700815 bnx2_free_rx_mem(bp);
Michael Chan35e90102008-06-19 16:37:42 -0700816
Michael Chan59b47d82006-11-19 14:10:45 -0800817 for (i = 0; i < bp->ctx_pages; i++) {
818 if (bp->ctx_blk[i]) {
819 pci_free_consistent(bp->pdev, BCM_PAGE_SIZE,
820 bp->ctx_blk[i],
821 bp->ctx_blk_mapping[i]);
822 bp->ctx_blk[i] = NULL;
823 }
824 }
Michael Chan43e80b82008-06-19 16:41:08 -0700825 if (bnapi->status_blk.msi) {
Michael Chan0f31f992006-03-23 01:12:38 -0800826 pci_free_consistent(bp->pdev, bp->status_stats_size,
Michael Chan43e80b82008-06-19 16:41:08 -0700827 bnapi->status_blk.msi,
828 bp->status_blk_mapping);
829 bnapi->status_blk.msi = NULL;
Michael Chan0f31f992006-03-23 01:12:38 -0800830 bp->stats_blk = NULL;
Michael Chanb6016b72005-05-26 13:03:09 -0700831 }
Michael Chanb6016b72005-05-26 13:03:09 -0700832}
833
834static int
835bnx2_alloc_mem(struct bnx2 *bp)
836{
Michael Chan35e90102008-06-19 16:37:42 -0700837 int i, status_blk_size, err;
Michael Chan43e80b82008-06-19 16:41:08 -0700838 struct bnx2_napi *bnapi;
839 void *status_blk;
Michael Chanb6016b72005-05-26 13:03:09 -0700840
Michael Chan0f31f992006-03-23 01:12:38 -0800841 /* Combine status and statistics blocks into one allocation. */
842 status_blk_size = L1_CACHE_ALIGN(sizeof(struct status_block));
David S. Millerf86e82f2008-01-21 17:15:40 -0800843 if (bp->flags & BNX2_FLAG_MSIX_CAP)
Michael Chanb4b36042007-12-20 19:59:30 -0800844 status_blk_size = L1_CACHE_ALIGN(BNX2_MAX_MSIX_HW_VEC *
845 BNX2_SBLK_MSIX_ALIGN_SIZE);
Michael Chan0f31f992006-03-23 01:12:38 -0800846 bp->status_stats_size = status_blk_size +
847 sizeof(struct statistics_block);
848
Michael Chan43e80b82008-06-19 16:41:08 -0700849 status_blk = pci_alloc_consistent(bp->pdev, bp->status_stats_size,
850 &bp->status_blk_mapping);
851 if (status_blk == NULL)
Michael Chanb6016b72005-05-26 13:03:09 -0700852 goto alloc_mem_err;
853
Michael Chan43e80b82008-06-19 16:41:08 -0700854 memset(status_blk, 0, bp->status_stats_size);
Michael Chanb6016b72005-05-26 13:03:09 -0700855
Michael Chan43e80b82008-06-19 16:41:08 -0700856 bnapi = &bp->bnx2_napi[0];
857 bnapi->status_blk.msi = status_blk;
858 bnapi->hw_tx_cons_ptr =
859 &bnapi->status_blk.msi->status_tx_quick_consumer_index0;
860 bnapi->hw_rx_cons_ptr =
861 &bnapi->status_blk.msi->status_rx_quick_consumer_index0;
David S. Millerf86e82f2008-01-21 17:15:40 -0800862 if (bp->flags & BNX2_FLAG_MSIX_CAP) {
Michael Chanb4b36042007-12-20 19:59:30 -0800863 for (i = 1; i < BNX2_MAX_MSIX_VEC; i++) {
Michael Chan43e80b82008-06-19 16:41:08 -0700864 struct status_block_msix *sblk;
Michael Chanb4b36042007-12-20 19:59:30 -0800865
Michael Chan43e80b82008-06-19 16:41:08 -0700866 bnapi = &bp->bnx2_napi[i];
867
868 sblk = (void *) (status_blk +
869 BNX2_SBLK_MSIX_ALIGN_SIZE * i);
870 bnapi->status_blk.msix = sblk;
871 bnapi->hw_tx_cons_ptr =
872 &sblk->status_tx_quick_consumer_index;
873 bnapi->hw_rx_cons_ptr =
874 &sblk->status_rx_quick_consumer_index;
Michael Chanb4b36042007-12-20 19:59:30 -0800875 bnapi->int_num = i << 24;
876 }
877 }
Michael Chan35efa7c2007-12-20 19:56:37 -0800878
Michael Chan43e80b82008-06-19 16:41:08 -0700879 bp->stats_blk = status_blk + status_blk_size;
Michael Chanb6016b72005-05-26 13:03:09 -0700880
Michael Chan0f31f992006-03-23 01:12:38 -0800881 bp->stats_blk_mapping = bp->status_blk_mapping + status_blk_size;
Michael Chanb6016b72005-05-26 13:03:09 -0700882
Michael Chan59b47d82006-11-19 14:10:45 -0800883 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
884 bp->ctx_pages = 0x2000 / BCM_PAGE_SIZE;
885 if (bp->ctx_pages == 0)
886 bp->ctx_pages = 1;
887 for (i = 0; i < bp->ctx_pages; i++) {
888 bp->ctx_blk[i] = pci_alloc_consistent(bp->pdev,
889 BCM_PAGE_SIZE,
890 &bp->ctx_blk_mapping[i]);
891 if (bp->ctx_blk[i] == NULL)
892 goto alloc_mem_err;
893 }
894 }
Michael Chan35e90102008-06-19 16:37:42 -0700895
Michael Chanbb4f98a2008-06-19 16:38:19 -0700896 err = bnx2_alloc_rx_mem(bp);
897 if (err)
898 goto alloc_mem_err;
899
Michael Chan35e90102008-06-19 16:37:42 -0700900 err = bnx2_alloc_tx_mem(bp);
901 if (err)
902 goto alloc_mem_err;
903
Michael Chanb6016b72005-05-26 13:03:09 -0700904 return 0;
905
906alloc_mem_err:
907 bnx2_free_mem(bp);
908 return -ENOMEM;
909}
910
911static void
Michael Chane3648b32005-11-04 08:51:21 -0800912bnx2_report_fw_link(struct bnx2 *bp)
913{
914 u32 fw_link_status = 0;
915
Michael Chan583c28e2008-01-21 19:51:35 -0800916 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
Michael Chan0d8a6572007-07-07 22:49:43 -0700917 return;
918
Michael Chane3648b32005-11-04 08:51:21 -0800919 if (bp->link_up) {
920 u32 bmsr;
921
922 switch (bp->line_speed) {
923 case SPEED_10:
924 if (bp->duplex == DUPLEX_HALF)
925 fw_link_status = BNX2_LINK_STATUS_10HALF;
926 else
927 fw_link_status = BNX2_LINK_STATUS_10FULL;
928 break;
929 case SPEED_100:
930 if (bp->duplex == DUPLEX_HALF)
931 fw_link_status = BNX2_LINK_STATUS_100HALF;
932 else
933 fw_link_status = BNX2_LINK_STATUS_100FULL;
934 break;
935 case SPEED_1000:
936 if (bp->duplex == DUPLEX_HALF)
937 fw_link_status = BNX2_LINK_STATUS_1000HALF;
938 else
939 fw_link_status = BNX2_LINK_STATUS_1000FULL;
940 break;
941 case SPEED_2500:
942 if (bp->duplex == DUPLEX_HALF)
943 fw_link_status = BNX2_LINK_STATUS_2500HALF;
944 else
945 fw_link_status = BNX2_LINK_STATUS_2500FULL;
946 break;
947 }
948
949 fw_link_status |= BNX2_LINK_STATUS_LINK_UP;
950
951 if (bp->autoneg) {
952 fw_link_status |= BNX2_LINK_STATUS_AN_ENABLED;
953
Michael Chanca58c3a2007-05-03 13:22:52 -0700954 bnx2_read_phy(bp, bp->mii_bmsr, &bmsr);
955 bnx2_read_phy(bp, bp->mii_bmsr, &bmsr);
Michael Chane3648b32005-11-04 08:51:21 -0800956
957 if (!(bmsr & BMSR_ANEGCOMPLETE) ||
Michael Chan583c28e2008-01-21 19:51:35 -0800958 bp->phy_flags & BNX2_PHY_FLAG_PARALLEL_DETECT)
Michael Chane3648b32005-11-04 08:51:21 -0800959 fw_link_status |= BNX2_LINK_STATUS_PARALLEL_DET;
960 else
961 fw_link_status |= BNX2_LINK_STATUS_AN_COMPLETE;
962 }
963 }
964 else
965 fw_link_status = BNX2_LINK_STATUS_LINK_DOWN;
966
Michael Chan2726d6e2008-01-29 21:35:05 -0800967 bnx2_shmem_wr(bp, BNX2_LINK_STATUS, fw_link_status);
Michael Chane3648b32005-11-04 08:51:21 -0800968}
969
Michael Chan9b1084b2007-07-07 22:50:37 -0700970static char *
971bnx2_xceiver_str(struct bnx2 *bp)
972{
973 return ((bp->phy_port == PORT_FIBRE) ? "SerDes" :
Michael Chan583c28e2008-01-21 19:51:35 -0800974 ((bp->phy_flags & BNX2_PHY_FLAG_SERDES) ? "Remote Copper" :
Michael Chan9b1084b2007-07-07 22:50:37 -0700975 "Copper"));
976}
977
Michael Chane3648b32005-11-04 08:51:21 -0800978static void
Michael Chanb6016b72005-05-26 13:03:09 -0700979bnx2_report_link(struct bnx2 *bp)
980{
981 if (bp->link_up) {
982 netif_carrier_on(bp->dev);
Joe Perches3a9c6a42010-02-17 15:01:51 +0000983 netdev_info(bp->dev, "NIC %s Link is Up, %d Mbps %s duplex",
984 bnx2_xceiver_str(bp),
985 bp->line_speed,
986 bp->duplex == DUPLEX_FULL ? "full" : "half");
Michael Chanb6016b72005-05-26 13:03:09 -0700987
988 if (bp->flow_ctrl) {
989 if (bp->flow_ctrl & FLOW_CTRL_RX) {
Joe Perches3a9c6a42010-02-17 15:01:51 +0000990 pr_cont(", receive ");
Michael Chanb6016b72005-05-26 13:03:09 -0700991 if (bp->flow_ctrl & FLOW_CTRL_TX)
Joe Perches3a9c6a42010-02-17 15:01:51 +0000992 pr_cont("& transmit ");
Michael Chanb6016b72005-05-26 13:03:09 -0700993 }
994 else {
Joe Perches3a9c6a42010-02-17 15:01:51 +0000995 pr_cont(", transmit ");
Michael Chanb6016b72005-05-26 13:03:09 -0700996 }
Joe Perches3a9c6a42010-02-17 15:01:51 +0000997 pr_cont("flow control ON");
Michael Chanb6016b72005-05-26 13:03:09 -0700998 }
Joe Perches3a9c6a42010-02-17 15:01:51 +0000999 pr_cont("\n");
1000 } else {
Michael Chanb6016b72005-05-26 13:03:09 -07001001 netif_carrier_off(bp->dev);
Joe Perches3a9c6a42010-02-17 15:01:51 +00001002 netdev_err(bp->dev, "NIC %s Link is Down\n",
1003 bnx2_xceiver_str(bp));
Michael Chanb6016b72005-05-26 13:03:09 -07001004 }
Michael Chane3648b32005-11-04 08:51:21 -08001005
1006 bnx2_report_fw_link(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07001007}
1008
1009static void
1010bnx2_resolve_flow_ctrl(struct bnx2 *bp)
1011{
1012 u32 local_adv, remote_adv;
1013
1014 bp->flow_ctrl = 0;
Jeff Garzik6aa20a22006-09-13 13:24:59 -04001015 if ((bp->autoneg & (AUTONEG_SPEED | AUTONEG_FLOW_CTRL)) !=
Michael Chanb6016b72005-05-26 13:03:09 -07001016 (AUTONEG_SPEED | AUTONEG_FLOW_CTRL)) {
1017
1018 if (bp->duplex == DUPLEX_FULL) {
1019 bp->flow_ctrl = bp->req_flow_ctrl;
1020 }
1021 return;
1022 }
1023
1024 if (bp->duplex != DUPLEX_FULL) {
1025 return;
1026 }
1027
Michael Chan583c28e2008-01-21 19:51:35 -08001028 if ((bp->phy_flags & BNX2_PHY_FLAG_SERDES) &&
Michael Chan5b0c76a2005-11-04 08:45:49 -08001029 (CHIP_NUM(bp) == CHIP_NUM_5708)) {
1030 u32 val;
1031
1032 bnx2_read_phy(bp, BCM5708S_1000X_STAT1, &val);
1033 if (val & BCM5708S_1000X_STAT1_TX_PAUSE)
1034 bp->flow_ctrl |= FLOW_CTRL_TX;
1035 if (val & BCM5708S_1000X_STAT1_RX_PAUSE)
1036 bp->flow_ctrl |= FLOW_CTRL_RX;
1037 return;
1038 }
1039
Michael Chanca58c3a2007-05-03 13:22:52 -07001040 bnx2_read_phy(bp, bp->mii_adv, &local_adv);
1041 bnx2_read_phy(bp, bp->mii_lpa, &remote_adv);
Michael Chanb6016b72005-05-26 13:03:09 -07001042
Michael Chan583c28e2008-01-21 19:51:35 -08001043 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Michael Chanb6016b72005-05-26 13:03:09 -07001044 u32 new_local_adv = 0;
1045 u32 new_remote_adv = 0;
1046
1047 if (local_adv & ADVERTISE_1000XPAUSE)
1048 new_local_adv |= ADVERTISE_PAUSE_CAP;
1049 if (local_adv & ADVERTISE_1000XPSE_ASYM)
1050 new_local_adv |= ADVERTISE_PAUSE_ASYM;
1051 if (remote_adv & ADVERTISE_1000XPAUSE)
1052 new_remote_adv |= ADVERTISE_PAUSE_CAP;
1053 if (remote_adv & ADVERTISE_1000XPSE_ASYM)
1054 new_remote_adv |= ADVERTISE_PAUSE_ASYM;
1055
1056 local_adv = new_local_adv;
1057 remote_adv = new_remote_adv;
1058 }
1059
1060 /* See Table 28B-3 of 802.3ab-1999 spec. */
1061 if (local_adv & ADVERTISE_PAUSE_CAP) {
1062 if(local_adv & ADVERTISE_PAUSE_ASYM) {
1063 if (remote_adv & ADVERTISE_PAUSE_CAP) {
1064 bp->flow_ctrl = FLOW_CTRL_TX | FLOW_CTRL_RX;
1065 }
1066 else if (remote_adv & ADVERTISE_PAUSE_ASYM) {
1067 bp->flow_ctrl = FLOW_CTRL_RX;
1068 }
1069 }
1070 else {
1071 if (remote_adv & ADVERTISE_PAUSE_CAP) {
1072 bp->flow_ctrl = FLOW_CTRL_TX | FLOW_CTRL_RX;
1073 }
1074 }
1075 }
1076 else if (local_adv & ADVERTISE_PAUSE_ASYM) {
1077 if ((remote_adv & ADVERTISE_PAUSE_CAP) &&
1078 (remote_adv & ADVERTISE_PAUSE_ASYM)) {
1079
1080 bp->flow_ctrl = FLOW_CTRL_TX;
1081 }
1082 }
1083}
1084
1085static int
Michael Chan27a005b2007-05-03 13:23:41 -07001086bnx2_5709s_linkup(struct bnx2 *bp)
1087{
1088 u32 val, speed;
1089
1090 bp->link_up = 1;
1091
1092 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_GP_STATUS);
1093 bnx2_read_phy(bp, MII_BNX2_GP_TOP_AN_STATUS1, &val);
1094 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
1095
1096 if ((bp->autoneg & AUTONEG_SPEED) == 0) {
1097 bp->line_speed = bp->req_line_speed;
1098 bp->duplex = bp->req_duplex;
1099 return 0;
1100 }
1101 speed = val & MII_BNX2_GP_TOP_AN_SPEED_MSK;
1102 switch (speed) {
1103 case MII_BNX2_GP_TOP_AN_SPEED_10:
1104 bp->line_speed = SPEED_10;
1105 break;
1106 case MII_BNX2_GP_TOP_AN_SPEED_100:
1107 bp->line_speed = SPEED_100;
1108 break;
1109 case MII_BNX2_GP_TOP_AN_SPEED_1G:
1110 case MII_BNX2_GP_TOP_AN_SPEED_1GKV:
1111 bp->line_speed = SPEED_1000;
1112 break;
1113 case MII_BNX2_GP_TOP_AN_SPEED_2_5G:
1114 bp->line_speed = SPEED_2500;
1115 break;
1116 }
1117 if (val & MII_BNX2_GP_TOP_AN_FD)
1118 bp->duplex = DUPLEX_FULL;
1119 else
1120 bp->duplex = DUPLEX_HALF;
1121 return 0;
1122}
1123
1124static int
Michael Chan5b0c76a2005-11-04 08:45:49 -08001125bnx2_5708s_linkup(struct bnx2 *bp)
1126{
1127 u32 val;
1128
1129 bp->link_up = 1;
1130 bnx2_read_phy(bp, BCM5708S_1000X_STAT1, &val);
1131 switch (val & BCM5708S_1000X_STAT1_SPEED_MASK) {
1132 case BCM5708S_1000X_STAT1_SPEED_10:
1133 bp->line_speed = SPEED_10;
1134 break;
1135 case BCM5708S_1000X_STAT1_SPEED_100:
1136 bp->line_speed = SPEED_100;
1137 break;
1138 case BCM5708S_1000X_STAT1_SPEED_1G:
1139 bp->line_speed = SPEED_1000;
1140 break;
1141 case BCM5708S_1000X_STAT1_SPEED_2G5:
1142 bp->line_speed = SPEED_2500;
1143 break;
1144 }
1145 if (val & BCM5708S_1000X_STAT1_FD)
1146 bp->duplex = DUPLEX_FULL;
1147 else
1148 bp->duplex = DUPLEX_HALF;
1149
1150 return 0;
1151}
1152
1153static int
1154bnx2_5706s_linkup(struct bnx2 *bp)
Michael Chanb6016b72005-05-26 13:03:09 -07001155{
1156 u32 bmcr, local_adv, remote_adv, common;
1157
1158 bp->link_up = 1;
1159 bp->line_speed = SPEED_1000;
1160
Michael Chanca58c3a2007-05-03 13:22:52 -07001161 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chanb6016b72005-05-26 13:03:09 -07001162 if (bmcr & BMCR_FULLDPLX) {
1163 bp->duplex = DUPLEX_FULL;
1164 }
1165 else {
1166 bp->duplex = DUPLEX_HALF;
1167 }
1168
1169 if (!(bmcr & BMCR_ANENABLE)) {
1170 return 0;
1171 }
1172
Michael Chanca58c3a2007-05-03 13:22:52 -07001173 bnx2_read_phy(bp, bp->mii_adv, &local_adv);
1174 bnx2_read_phy(bp, bp->mii_lpa, &remote_adv);
Michael Chanb6016b72005-05-26 13:03:09 -07001175
1176 common = local_adv & remote_adv;
1177 if (common & (ADVERTISE_1000XHALF | ADVERTISE_1000XFULL)) {
1178
1179 if (common & ADVERTISE_1000XFULL) {
1180 bp->duplex = DUPLEX_FULL;
1181 }
1182 else {
1183 bp->duplex = DUPLEX_HALF;
1184 }
1185 }
1186
1187 return 0;
1188}
1189
1190static int
1191bnx2_copper_linkup(struct bnx2 *bp)
1192{
1193 u32 bmcr;
1194
Michael Chanca58c3a2007-05-03 13:22:52 -07001195 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chanb6016b72005-05-26 13:03:09 -07001196 if (bmcr & BMCR_ANENABLE) {
1197 u32 local_adv, remote_adv, common;
1198
1199 bnx2_read_phy(bp, MII_CTRL1000, &local_adv);
1200 bnx2_read_phy(bp, MII_STAT1000, &remote_adv);
1201
1202 common = local_adv & (remote_adv >> 2);
1203 if (common & ADVERTISE_1000FULL) {
1204 bp->line_speed = SPEED_1000;
1205 bp->duplex = DUPLEX_FULL;
1206 }
1207 else if (common & ADVERTISE_1000HALF) {
1208 bp->line_speed = SPEED_1000;
1209 bp->duplex = DUPLEX_HALF;
1210 }
1211 else {
Michael Chanca58c3a2007-05-03 13:22:52 -07001212 bnx2_read_phy(bp, bp->mii_adv, &local_adv);
1213 bnx2_read_phy(bp, bp->mii_lpa, &remote_adv);
Michael Chanb6016b72005-05-26 13:03:09 -07001214
1215 common = local_adv & remote_adv;
1216 if (common & ADVERTISE_100FULL) {
1217 bp->line_speed = SPEED_100;
1218 bp->duplex = DUPLEX_FULL;
1219 }
1220 else if (common & ADVERTISE_100HALF) {
1221 bp->line_speed = SPEED_100;
1222 bp->duplex = DUPLEX_HALF;
1223 }
1224 else if (common & ADVERTISE_10FULL) {
1225 bp->line_speed = SPEED_10;
1226 bp->duplex = DUPLEX_FULL;
1227 }
1228 else if (common & ADVERTISE_10HALF) {
1229 bp->line_speed = SPEED_10;
1230 bp->duplex = DUPLEX_HALF;
1231 }
1232 else {
1233 bp->line_speed = 0;
1234 bp->link_up = 0;
1235 }
1236 }
1237 }
1238 else {
1239 if (bmcr & BMCR_SPEED100) {
1240 bp->line_speed = SPEED_100;
1241 }
1242 else {
1243 bp->line_speed = SPEED_10;
1244 }
1245 if (bmcr & BMCR_FULLDPLX) {
1246 bp->duplex = DUPLEX_FULL;
1247 }
1248 else {
1249 bp->duplex = DUPLEX_HALF;
1250 }
1251 }
1252
1253 return 0;
1254}
1255
Michael Chan83e3fc82008-01-29 21:37:17 -08001256static void
Michael Chanbb4f98a2008-06-19 16:38:19 -07001257bnx2_init_rx_context(struct bnx2 *bp, u32 cid)
Michael Chan83e3fc82008-01-29 21:37:17 -08001258{
Michael Chanbb4f98a2008-06-19 16:38:19 -07001259 u32 val, rx_cid_addr = GET_CID_ADDR(cid);
Michael Chan83e3fc82008-01-29 21:37:17 -08001260
1261 val = BNX2_L2CTX_CTX_TYPE_CTX_BD_CHN_TYPE_VALUE;
1262 val |= BNX2_L2CTX_CTX_TYPE_SIZE_L2;
1263 val |= 0x02 << 8;
1264
1265 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
1266 u32 lo_water, hi_water;
1267
1268 if (bp->flow_ctrl & FLOW_CTRL_TX)
1269 lo_water = BNX2_L2CTX_LO_WATER_MARK_DEFAULT;
1270 else
1271 lo_water = BNX2_L2CTX_LO_WATER_MARK_DIS;
1272 if (lo_water >= bp->rx_ring_size)
1273 lo_water = 0;
1274
Michael Chan57260262010-02-15 19:42:09 +00001275 hi_water = min_t(int, bp->rx_ring_size / 4, lo_water + 16);
Michael Chan83e3fc82008-01-29 21:37:17 -08001276
1277 if (hi_water <= lo_water)
1278 lo_water = 0;
1279
1280 hi_water /= BNX2_L2CTX_HI_WATER_MARK_SCALE;
1281 lo_water /= BNX2_L2CTX_LO_WATER_MARK_SCALE;
1282
1283 if (hi_water > 0xf)
1284 hi_water = 0xf;
1285 else if (hi_water == 0)
1286 lo_water = 0;
1287 val |= lo_water | (hi_water << BNX2_L2CTX_HI_WATER_MARK_SHIFT);
1288 }
1289 bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_CTX_TYPE, val);
1290}
1291
Michael Chanbb4f98a2008-06-19 16:38:19 -07001292static void
1293bnx2_init_all_rx_contexts(struct bnx2 *bp)
1294{
1295 int i;
1296 u32 cid;
1297
1298 for (i = 0, cid = RX_CID; i < bp->num_rx_rings; i++, cid++) {
1299 if (i == 1)
1300 cid = RX_RSS_CID;
1301 bnx2_init_rx_context(bp, cid);
1302 }
1303}
1304
Benjamin Li344478d2008-09-18 16:38:24 -07001305static void
Michael Chanb6016b72005-05-26 13:03:09 -07001306bnx2_set_mac_link(struct bnx2 *bp)
1307{
1308 u32 val;
1309
1310 REG_WR(bp, BNX2_EMAC_TX_LENGTHS, 0x2620);
1311 if (bp->link_up && (bp->line_speed == SPEED_1000) &&
1312 (bp->duplex == DUPLEX_HALF)) {
1313 REG_WR(bp, BNX2_EMAC_TX_LENGTHS, 0x26ff);
1314 }
1315
1316 /* Configure the EMAC mode register. */
1317 val = REG_RD(bp, BNX2_EMAC_MODE);
1318
1319 val &= ~(BNX2_EMAC_MODE_PORT | BNX2_EMAC_MODE_HALF_DUPLEX |
Michael Chan5b0c76a2005-11-04 08:45:49 -08001320 BNX2_EMAC_MODE_MAC_LOOP | BNX2_EMAC_MODE_FORCE_LINK |
Michael Chan59b47d82006-11-19 14:10:45 -08001321 BNX2_EMAC_MODE_25G_MODE);
Michael Chanb6016b72005-05-26 13:03:09 -07001322
1323 if (bp->link_up) {
Michael Chan5b0c76a2005-11-04 08:45:49 -08001324 switch (bp->line_speed) {
1325 case SPEED_10:
Michael Chan59b47d82006-11-19 14:10:45 -08001326 if (CHIP_NUM(bp) != CHIP_NUM_5706) {
1327 val |= BNX2_EMAC_MODE_PORT_MII_10M;
Michael Chan5b0c76a2005-11-04 08:45:49 -08001328 break;
1329 }
1330 /* fall through */
1331 case SPEED_100:
1332 val |= BNX2_EMAC_MODE_PORT_MII;
1333 break;
1334 case SPEED_2500:
Michael Chan59b47d82006-11-19 14:10:45 -08001335 val |= BNX2_EMAC_MODE_25G_MODE;
Michael Chan5b0c76a2005-11-04 08:45:49 -08001336 /* fall through */
1337 case SPEED_1000:
1338 val |= BNX2_EMAC_MODE_PORT_GMII;
1339 break;
1340 }
Michael Chanb6016b72005-05-26 13:03:09 -07001341 }
1342 else {
1343 val |= BNX2_EMAC_MODE_PORT_GMII;
1344 }
1345
1346 /* Set the MAC to operate in the appropriate duplex mode. */
1347 if (bp->duplex == DUPLEX_HALF)
1348 val |= BNX2_EMAC_MODE_HALF_DUPLEX;
1349 REG_WR(bp, BNX2_EMAC_MODE, val);
1350
1351 /* Enable/disable rx PAUSE. */
1352 bp->rx_mode &= ~BNX2_EMAC_RX_MODE_FLOW_EN;
1353
1354 if (bp->flow_ctrl & FLOW_CTRL_RX)
1355 bp->rx_mode |= BNX2_EMAC_RX_MODE_FLOW_EN;
1356 REG_WR(bp, BNX2_EMAC_RX_MODE, bp->rx_mode);
1357
1358 /* Enable/disable tx PAUSE. */
1359 val = REG_RD(bp, BNX2_EMAC_TX_MODE);
1360 val &= ~BNX2_EMAC_TX_MODE_FLOW_EN;
1361
1362 if (bp->flow_ctrl & FLOW_CTRL_TX)
1363 val |= BNX2_EMAC_TX_MODE_FLOW_EN;
1364 REG_WR(bp, BNX2_EMAC_TX_MODE, val);
1365
1366 /* Acknowledge the interrupt. */
1367 REG_WR(bp, BNX2_EMAC_STATUS, BNX2_EMAC_STATUS_LINK_CHANGE);
1368
Michael Chan83e3fc82008-01-29 21:37:17 -08001369 if (CHIP_NUM(bp) == CHIP_NUM_5709)
Michael Chanbb4f98a2008-06-19 16:38:19 -07001370 bnx2_init_all_rx_contexts(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07001371}
1372
Michael Chan27a005b2007-05-03 13:23:41 -07001373static void
1374bnx2_enable_bmsr1(struct bnx2 *bp)
1375{
Michael Chan583c28e2008-01-21 19:51:35 -08001376 if ((bp->phy_flags & BNX2_PHY_FLAG_SERDES) &&
Michael Chan27a005b2007-05-03 13:23:41 -07001377 (CHIP_NUM(bp) == CHIP_NUM_5709))
1378 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
1379 MII_BNX2_BLK_ADDR_GP_STATUS);
1380}
1381
1382static void
1383bnx2_disable_bmsr1(struct bnx2 *bp)
1384{
Michael Chan583c28e2008-01-21 19:51:35 -08001385 if ((bp->phy_flags & BNX2_PHY_FLAG_SERDES) &&
Michael Chan27a005b2007-05-03 13:23:41 -07001386 (CHIP_NUM(bp) == CHIP_NUM_5709))
1387 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
1388 MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
1389}
1390
Michael Chanb6016b72005-05-26 13:03:09 -07001391static int
Michael Chan605a9e22007-05-03 13:23:13 -07001392bnx2_test_and_enable_2g5(struct bnx2 *bp)
1393{
1394 u32 up1;
1395 int ret = 1;
1396
Michael Chan583c28e2008-01-21 19:51:35 -08001397 if (!(bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE))
Michael Chan605a9e22007-05-03 13:23:13 -07001398 return 0;
1399
1400 if (bp->autoneg & AUTONEG_SPEED)
1401 bp->advertising |= ADVERTISED_2500baseX_Full;
1402
Michael Chan27a005b2007-05-03 13:23:41 -07001403 if (CHIP_NUM(bp) == CHIP_NUM_5709)
1404 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_OVER1G);
1405
Michael Chan605a9e22007-05-03 13:23:13 -07001406 bnx2_read_phy(bp, bp->mii_up1, &up1);
1407 if (!(up1 & BCM5708S_UP1_2G5)) {
1408 up1 |= BCM5708S_UP1_2G5;
1409 bnx2_write_phy(bp, bp->mii_up1, up1);
1410 ret = 0;
1411 }
1412
Michael Chan27a005b2007-05-03 13:23:41 -07001413 if (CHIP_NUM(bp) == CHIP_NUM_5709)
1414 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
1415 MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
1416
Michael Chan605a9e22007-05-03 13:23:13 -07001417 return ret;
1418}
1419
1420static int
1421bnx2_test_and_disable_2g5(struct bnx2 *bp)
1422{
1423 u32 up1;
1424 int ret = 0;
1425
Michael Chan583c28e2008-01-21 19:51:35 -08001426 if (!(bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE))
Michael Chan605a9e22007-05-03 13:23:13 -07001427 return 0;
1428
Michael Chan27a005b2007-05-03 13:23:41 -07001429 if (CHIP_NUM(bp) == CHIP_NUM_5709)
1430 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_OVER1G);
1431
Michael Chan605a9e22007-05-03 13:23:13 -07001432 bnx2_read_phy(bp, bp->mii_up1, &up1);
1433 if (up1 & BCM5708S_UP1_2G5) {
1434 up1 &= ~BCM5708S_UP1_2G5;
1435 bnx2_write_phy(bp, bp->mii_up1, up1);
1436 ret = 1;
1437 }
1438
Michael Chan27a005b2007-05-03 13:23:41 -07001439 if (CHIP_NUM(bp) == CHIP_NUM_5709)
1440 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
1441 MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
1442
Michael Chan605a9e22007-05-03 13:23:13 -07001443 return ret;
1444}
1445
1446static void
1447bnx2_enable_forced_2g5(struct bnx2 *bp)
1448{
1449 u32 bmcr;
1450
Michael Chan583c28e2008-01-21 19:51:35 -08001451 if (!(bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE))
Michael Chan605a9e22007-05-03 13:23:13 -07001452 return;
1453
Michael Chan27a005b2007-05-03 13:23:41 -07001454 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
1455 u32 val;
1456
1457 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
1458 MII_BNX2_BLK_ADDR_SERDES_DIG);
1459 bnx2_read_phy(bp, MII_BNX2_SERDES_DIG_MISC1, &val);
1460 val &= ~MII_BNX2_SD_MISC1_FORCE_MSK;
1461 val |= MII_BNX2_SD_MISC1_FORCE | MII_BNX2_SD_MISC1_FORCE_2_5G;
1462 bnx2_write_phy(bp, MII_BNX2_SERDES_DIG_MISC1, val);
1463
1464 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
1465 MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
1466 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
1467
1468 } else if (CHIP_NUM(bp) == CHIP_NUM_5708) {
Michael Chan605a9e22007-05-03 13:23:13 -07001469 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
1470 bmcr |= BCM5708S_BMCR_FORCE_2500;
Eric Dumazetc70798572009-11-02 23:17:42 +00001471 } else {
1472 return;
Michael Chan605a9e22007-05-03 13:23:13 -07001473 }
1474
1475 if (bp->autoneg & AUTONEG_SPEED) {
1476 bmcr &= ~BMCR_ANENABLE;
1477 if (bp->req_duplex == DUPLEX_FULL)
1478 bmcr |= BMCR_FULLDPLX;
1479 }
1480 bnx2_write_phy(bp, bp->mii_bmcr, bmcr);
1481}
1482
1483static void
1484bnx2_disable_forced_2g5(struct bnx2 *bp)
1485{
1486 u32 bmcr;
1487
Michael Chan583c28e2008-01-21 19:51:35 -08001488 if (!(bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE))
Michael Chan605a9e22007-05-03 13:23:13 -07001489 return;
1490
Michael Chan27a005b2007-05-03 13:23:41 -07001491 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
1492 u32 val;
1493
1494 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
1495 MII_BNX2_BLK_ADDR_SERDES_DIG);
1496 bnx2_read_phy(bp, MII_BNX2_SERDES_DIG_MISC1, &val);
1497 val &= ~MII_BNX2_SD_MISC1_FORCE;
1498 bnx2_write_phy(bp, MII_BNX2_SERDES_DIG_MISC1, val);
1499
1500 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
1501 MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
1502 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
1503
1504 } else if (CHIP_NUM(bp) == CHIP_NUM_5708) {
Michael Chan605a9e22007-05-03 13:23:13 -07001505 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
1506 bmcr &= ~BCM5708S_BMCR_FORCE_2500;
Eric Dumazetc70798572009-11-02 23:17:42 +00001507 } else {
1508 return;
Michael Chan605a9e22007-05-03 13:23:13 -07001509 }
1510
1511 if (bp->autoneg & AUTONEG_SPEED)
1512 bmcr |= BMCR_SPEED1000 | BMCR_ANENABLE | BMCR_ANRESTART;
1513 bnx2_write_phy(bp, bp->mii_bmcr, bmcr);
1514}
1515
Michael Chanb2fadea2008-01-21 17:07:06 -08001516static void
1517bnx2_5706s_force_link_dn(struct bnx2 *bp, int start)
1518{
1519 u32 val;
1520
1521 bnx2_write_phy(bp, MII_BNX2_DSP_ADDRESS, MII_EXPAND_SERDES_CTL);
1522 bnx2_read_phy(bp, MII_BNX2_DSP_RW_PORT, &val);
1523 if (start)
1524 bnx2_write_phy(bp, MII_BNX2_DSP_RW_PORT, val & 0xff0f);
1525 else
1526 bnx2_write_phy(bp, MII_BNX2_DSP_RW_PORT, val | 0xc0);
1527}
1528
Michael Chan605a9e22007-05-03 13:23:13 -07001529static int
Michael Chanb6016b72005-05-26 13:03:09 -07001530bnx2_set_link(struct bnx2 *bp)
1531{
1532 u32 bmsr;
1533 u8 link_up;
1534
Michael Chan80be4432006-11-19 14:07:28 -08001535 if (bp->loopback == MAC_LOOPBACK || bp->loopback == PHY_LOOPBACK) {
Michael Chanb6016b72005-05-26 13:03:09 -07001536 bp->link_up = 1;
1537 return 0;
1538 }
1539
Michael Chan583c28e2008-01-21 19:51:35 -08001540 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
Michael Chan0d8a6572007-07-07 22:49:43 -07001541 return 0;
1542
Michael Chanb6016b72005-05-26 13:03:09 -07001543 link_up = bp->link_up;
1544
Michael Chan27a005b2007-05-03 13:23:41 -07001545 bnx2_enable_bmsr1(bp);
1546 bnx2_read_phy(bp, bp->mii_bmsr1, &bmsr);
1547 bnx2_read_phy(bp, bp->mii_bmsr1, &bmsr);
1548 bnx2_disable_bmsr1(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07001549
Michael Chan583c28e2008-01-21 19:51:35 -08001550 if ((bp->phy_flags & BNX2_PHY_FLAG_SERDES) &&
Michael Chanb6016b72005-05-26 13:03:09 -07001551 (CHIP_NUM(bp) == CHIP_NUM_5706)) {
Michael Chana2724e22008-02-23 19:47:44 -08001552 u32 val, an_dbg;
Michael Chanb6016b72005-05-26 13:03:09 -07001553
Michael Chan583c28e2008-01-21 19:51:35 -08001554 if (bp->phy_flags & BNX2_PHY_FLAG_FORCED_DOWN) {
Michael Chanb2fadea2008-01-21 17:07:06 -08001555 bnx2_5706s_force_link_dn(bp, 0);
Michael Chan583c28e2008-01-21 19:51:35 -08001556 bp->phy_flags &= ~BNX2_PHY_FLAG_FORCED_DOWN;
Michael Chanb2fadea2008-01-21 17:07:06 -08001557 }
Michael Chanb6016b72005-05-26 13:03:09 -07001558 val = REG_RD(bp, BNX2_EMAC_STATUS);
Michael Chana2724e22008-02-23 19:47:44 -08001559
1560 bnx2_write_phy(bp, MII_BNX2_MISC_SHADOW, MISC_SHDW_AN_DBG);
1561 bnx2_read_phy(bp, MII_BNX2_MISC_SHADOW, &an_dbg);
1562 bnx2_read_phy(bp, MII_BNX2_MISC_SHADOW, &an_dbg);
1563
1564 if ((val & BNX2_EMAC_STATUS_LINK) &&
1565 !(an_dbg & MISC_SHDW_AN_DBG_NOSYNC))
Michael Chanb6016b72005-05-26 13:03:09 -07001566 bmsr |= BMSR_LSTATUS;
1567 else
1568 bmsr &= ~BMSR_LSTATUS;
1569 }
1570
1571 if (bmsr & BMSR_LSTATUS) {
1572 bp->link_up = 1;
1573
Michael Chan583c28e2008-01-21 19:51:35 -08001574 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Michael Chan5b0c76a2005-11-04 08:45:49 -08001575 if (CHIP_NUM(bp) == CHIP_NUM_5706)
1576 bnx2_5706s_linkup(bp);
1577 else if (CHIP_NUM(bp) == CHIP_NUM_5708)
1578 bnx2_5708s_linkup(bp);
Michael Chan27a005b2007-05-03 13:23:41 -07001579 else if (CHIP_NUM(bp) == CHIP_NUM_5709)
1580 bnx2_5709s_linkup(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07001581 }
1582 else {
1583 bnx2_copper_linkup(bp);
1584 }
1585 bnx2_resolve_flow_ctrl(bp);
1586 }
1587 else {
Michael Chan583c28e2008-01-21 19:51:35 -08001588 if ((bp->phy_flags & BNX2_PHY_FLAG_SERDES) &&
Michael Chan605a9e22007-05-03 13:23:13 -07001589 (bp->autoneg & AUTONEG_SPEED))
1590 bnx2_disable_forced_2g5(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07001591
Michael Chan583c28e2008-01-21 19:51:35 -08001592 if (bp->phy_flags & BNX2_PHY_FLAG_PARALLEL_DETECT) {
Michael Chanb2fadea2008-01-21 17:07:06 -08001593 u32 bmcr;
1594
1595 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
1596 bmcr |= BMCR_ANENABLE;
1597 bnx2_write_phy(bp, bp->mii_bmcr, bmcr);
1598
Michael Chan583c28e2008-01-21 19:51:35 -08001599 bp->phy_flags &= ~BNX2_PHY_FLAG_PARALLEL_DETECT;
Michael Chanb2fadea2008-01-21 17:07:06 -08001600 }
Michael Chanb6016b72005-05-26 13:03:09 -07001601 bp->link_up = 0;
1602 }
1603
1604 if (bp->link_up != link_up) {
1605 bnx2_report_link(bp);
1606 }
1607
1608 bnx2_set_mac_link(bp);
1609
1610 return 0;
1611}
1612
1613static int
1614bnx2_reset_phy(struct bnx2 *bp)
1615{
1616 int i;
1617 u32 reg;
1618
Michael Chanca58c3a2007-05-03 13:22:52 -07001619 bnx2_write_phy(bp, bp->mii_bmcr, BMCR_RESET);
Michael Chanb6016b72005-05-26 13:03:09 -07001620
1621#define PHY_RESET_MAX_WAIT 100
1622 for (i = 0; i < PHY_RESET_MAX_WAIT; i++) {
1623 udelay(10);
1624
Michael Chanca58c3a2007-05-03 13:22:52 -07001625 bnx2_read_phy(bp, bp->mii_bmcr, &reg);
Michael Chanb6016b72005-05-26 13:03:09 -07001626 if (!(reg & BMCR_RESET)) {
1627 udelay(20);
1628 break;
1629 }
1630 }
1631 if (i == PHY_RESET_MAX_WAIT) {
1632 return -EBUSY;
1633 }
1634 return 0;
1635}
1636
1637static u32
1638bnx2_phy_get_pause_adv(struct bnx2 *bp)
1639{
1640 u32 adv = 0;
1641
1642 if ((bp->req_flow_ctrl & (FLOW_CTRL_RX | FLOW_CTRL_TX)) ==
1643 (FLOW_CTRL_RX | FLOW_CTRL_TX)) {
1644
Michael Chan583c28e2008-01-21 19:51:35 -08001645 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Michael Chanb6016b72005-05-26 13:03:09 -07001646 adv = ADVERTISE_1000XPAUSE;
1647 }
1648 else {
1649 adv = ADVERTISE_PAUSE_CAP;
1650 }
1651 }
1652 else if (bp->req_flow_ctrl & FLOW_CTRL_TX) {
Michael Chan583c28e2008-01-21 19:51:35 -08001653 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Michael Chanb6016b72005-05-26 13:03:09 -07001654 adv = ADVERTISE_1000XPSE_ASYM;
1655 }
1656 else {
1657 adv = ADVERTISE_PAUSE_ASYM;
1658 }
1659 }
1660 else if (bp->req_flow_ctrl & FLOW_CTRL_RX) {
Michael Chan583c28e2008-01-21 19:51:35 -08001661 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Michael Chanb6016b72005-05-26 13:03:09 -07001662 adv = ADVERTISE_1000XPAUSE | ADVERTISE_1000XPSE_ASYM;
1663 }
1664 else {
1665 adv = ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM;
1666 }
1667 }
1668 return adv;
1669}
1670
Michael Chana2f13892008-07-14 22:38:23 -07001671static int bnx2_fw_sync(struct bnx2 *, u32, int, int);
Michael Chan0d8a6572007-07-07 22:49:43 -07001672
Michael Chanb6016b72005-05-26 13:03:09 -07001673static int
Michael Chan0d8a6572007-07-07 22:49:43 -07001674bnx2_setup_remote_phy(struct bnx2 *bp, u8 port)
Harvey Harrison52d07b12009-01-19 17:27:06 -08001675__releases(&bp->phy_lock)
1676__acquires(&bp->phy_lock)
Michael Chan0d8a6572007-07-07 22:49:43 -07001677{
1678 u32 speed_arg = 0, pause_adv;
1679
1680 pause_adv = bnx2_phy_get_pause_adv(bp);
1681
1682 if (bp->autoneg & AUTONEG_SPEED) {
1683 speed_arg |= BNX2_NETLINK_SET_LINK_ENABLE_AUTONEG;
1684 if (bp->advertising & ADVERTISED_10baseT_Half)
1685 speed_arg |= BNX2_NETLINK_SET_LINK_SPEED_10HALF;
1686 if (bp->advertising & ADVERTISED_10baseT_Full)
1687 speed_arg |= BNX2_NETLINK_SET_LINK_SPEED_10FULL;
1688 if (bp->advertising & ADVERTISED_100baseT_Half)
1689 speed_arg |= BNX2_NETLINK_SET_LINK_SPEED_100HALF;
1690 if (bp->advertising & ADVERTISED_100baseT_Full)
1691 speed_arg |= BNX2_NETLINK_SET_LINK_SPEED_100FULL;
1692 if (bp->advertising & ADVERTISED_1000baseT_Full)
1693 speed_arg |= BNX2_NETLINK_SET_LINK_SPEED_1GFULL;
1694 if (bp->advertising & ADVERTISED_2500baseX_Full)
1695 speed_arg |= BNX2_NETLINK_SET_LINK_SPEED_2G5FULL;
1696 } else {
1697 if (bp->req_line_speed == SPEED_2500)
1698 speed_arg = BNX2_NETLINK_SET_LINK_SPEED_2G5FULL;
1699 else if (bp->req_line_speed == SPEED_1000)
1700 speed_arg = BNX2_NETLINK_SET_LINK_SPEED_1GFULL;
1701 else if (bp->req_line_speed == SPEED_100) {
1702 if (bp->req_duplex == DUPLEX_FULL)
1703 speed_arg = BNX2_NETLINK_SET_LINK_SPEED_100FULL;
1704 else
1705 speed_arg = BNX2_NETLINK_SET_LINK_SPEED_100HALF;
1706 } else if (bp->req_line_speed == SPEED_10) {
1707 if (bp->req_duplex == DUPLEX_FULL)
1708 speed_arg = BNX2_NETLINK_SET_LINK_SPEED_10FULL;
1709 else
1710 speed_arg = BNX2_NETLINK_SET_LINK_SPEED_10HALF;
1711 }
1712 }
1713
1714 if (pause_adv & (ADVERTISE_1000XPAUSE | ADVERTISE_PAUSE_CAP))
1715 speed_arg |= BNX2_NETLINK_SET_LINK_FC_SYM_PAUSE;
Michael Chanc26736e2008-01-31 17:07:21 -08001716 if (pause_adv & (ADVERTISE_1000XPSE_ASYM | ADVERTISE_PAUSE_ASYM))
Michael Chan0d8a6572007-07-07 22:49:43 -07001717 speed_arg |= BNX2_NETLINK_SET_LINK_FC_ASYM_PAUSE;
1718
1719 if (port == PORT_TP)
1720 speed_arg |= BNX2_NETLINK_SET_LINK_PHY_APP_REMOTE |
1721 BNX2_NETLINK_SET_LINK_ETH_AT_WIRESPEED;
1722
Michael Chan2726d6e2008-01-29 21:35:05 -08001723 bnx2_shmem_wr(bp, BNX2_DRV_MB_ARG0, speed_arg);
Michael Chan0d8a6572007-07-07 22:49:43 -07001724
1725 spin_unlock_bh(&bp->phy_lock);
Michael Chana2f13892008-07-14 22:38:23 -07001726 bnx2_fw_sync(bp, BNX2_DRV_MSG_CODE_CMD_SET_LINK, 1, 0);
Michael Chan0d8a6572007-07-07 22:49:43 -07001727 spin_lock_bh(&bp->phy_lock);
1728
1729 return 0;
1730}
1731
1732static int
1733bnx2_setup_serdes_phy(struct bnx2 *bp, u8 port)
Harvey Harrison52d07b12009-01-19 17:27:06 -08001734__releases(&bp->phy_lock)
1735__acquires(&bp->phy_lock)
Michael Chanb6016b72005-05-26 13:03:09 -07001736{
Michael Chan605a9e22007-05-03 13:23:13 -07001737 u32 adv, bmcr;
Michael Chanb6016b72005-05-26 13:03:09 -07001738 u32 new_adv = 0;
1739
Michael Chan583c28e2008-01-21 19:51:35 -08001740 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
Michael Chan0d8a6572007-07-07 22:49:43 -07001741 return (bnx2_setup_remote_phy(bp, port));
1742
Michael Chanb6016b72005-05-26 13:03:09 -07001743 if (!(bp->autoneg & AUTONEG_SPEED)) {
1744 u32 new_bmcr;
Michael Chan5b0c76a2005-11-04 08:45:49 -08001745 int force_link_down = 0;
1746
Michael Chan605a9e22007-05-03 13:23:13 -07001747 if (bp->req_line_speed == SPEED_2500) {
1748 if (!bnx2_test_and_enable_2g5(bp))
1749 force_link_down = 1;
1750 } else if (bp->req_line_speed == SPEED_1000) {
1751 if (bnx2_test_and_disable_2g5(bp))
1752 force_link_down = 1;
1753 }
Michael Chanca58c3a2007-05-03 13:22:52 -07001754 bnx2_read_phy(bp, bp->mii_adv, &adv);
Michael Chan80be4432006-11-19 14:07:28 -08001755 adv &= ~(ADVERTISE_1000XFULL | ADVERTISE_1000XHALF);
1756
Michael Chanca58c3a2007-05-03 13:22:52 -07001757 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chan605a9e22007-05-03 13:23:13 -07001758 new_bmcr = bmcr & ~BMCR_ANENABLE;
Michael Chan80be4432006-11-19 14:07:28 -08001759 new_bmcr |= BMCR_SPEED1000;
Michael Chan605a9e22007-05-03 13:23:13 -07001760
Michael Chan27a005b2007-05-03 13:23:41 -07001761 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
1762 if (bp->req_line_speed == SPEED_2500)
1763 bnx2_enable_forced_2g5(bp);
1764 else if (bp->req_line_speed == SPEED_1000) {
1765 bnx2_disable_forced_2g5(bp);
1766 new_bmcr &= ~0x2000;
1767 }
1768
1769 } else if (CHIP_NUM(bp) == CHIP_NUM_5708) {
Michael Chan605a9e22007-05-03 13:23:13 -07001770 if (bp->req_line_speed == SPEED_2500)
1771 new_bmcr |= BCM5708S_BMCR_FORCE_2500;
1772 else
1773 new_bmcr = bmcr & ~BCM5708S_BMCR_FORCE_2500;
Michael Chan5b0c76a2005-11-04 08:45:49 -08001774 }
1775
Michael Chanb6016b72005-05-26 13:03:09 -07001776 if (bp->req_duplex == DUPLEX_FULL) {
Michael Chan5b0c76a2005-11-04 08:45:49 -08001777 adv |= ADVERTISE_1000XFULL;
Michael Chanb6016b72005-05-26 13:03:09 -07001778 new_bmcr |= BMCR_FULLDPLX;
1779 }
1780 else {
Michael Chan5b0c76a2005-11-04 08:45:49 -08001781 adv |= ADVERTISE_1000XHALF;
Michael Chanb6016b72005-05-26 13:03:09 -07001782 new_bmcr &= ~BMCR_FULLDPLX;
1783 }
Michael Chan5b0c76a2005-11-04 08:45:49 -08001784 if ((new_bmcr != bmcr) || (force_link_down)) {
Michael Chanb6016b72005-05-26 13:03:09 -07001785 /* Force a link down visible on the other side */
1786 if (bp->link_up) {
Michael Chanca58c3a2007-05-03 13:22:52 -07001787 bnx2_write_phy(bp, bp->mii_adv, adv &
Michael Chan5b0c76a2005-11-04 08:45:49 -08001788 ~(ADVERTISE_1000XFULL |
1789 ADVERTISE_1000XHALF));
Michael Chanca58c3a2007-05-03 13:22:52 -07001790 bnx2_write_phy(bp, bp->mii_bmcr, bmcr |
Michael Chanb6016b72005-05-26 13:03:09 -07001791 BMCR_ANRESTART | BMCR_ANENABLE);
1792
1793 bp->link_up = 0;
1794 netif_carrier_off(bp->dev);
Michael Chanca58c3a2007-05-03 13:22:52 -07001795 bnx2_write_phy(bp, bp->mii_bmcr, new_bmcr);
Michael Chan80be4432006-11-19 14:07:28 -08001796 bnx2_report_link(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07001797 }
Michael Chanca58c3a2007-05-03 13:22:52 -07001798 bnx2_write_phy(bp, bp->mii_adv, adv);
1799 bnx2_write_phy(bp, bp->mii_bmcr, new_bmcr);
Michael Chan605a9e22007-05-03 13:23:13 -07001800 } else {
1801 bnx2_resolve_flow_ctrl(bp);
1802 bnx2_set_mac_link(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07001803 }
1804 return 0;
1805 }
1806
Michael Chan605a9e22007-05-03 13:23:13 -07001807 bnx2_test_and_enable_2g5(bp);
Michael Chan5b0c76a2005-11-04 08:45:49 -08001808
Michael Chanb6016b72005-05-26 13:03:09 -07001809 if (bp->advertising & ADVERTISED_1000baseT_Full)
1810 new_adv |= ADVERTISE_1000XFULL;
1811
1812 new_adv |= bnx2_phy_get_pause_adv(bp);
1813
Michael Chanca58c3a2007-05-03 13:22:52 -07001814 bnx2_read_phy(bp, bp->mii_adv, &adv);
1815 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chanb6016b72005-05-26 13:03:09 -07001816
1817 bp->serdes_an_pending = 0;
1818 if ((adv != new_adv) || ((bmcr & BMCR_ANENABLE) == 0)) {
1819 /* Force a link down visible on the other side */
1820 if (bp->link_up) {
Michael Chanca58c3a2007-05-03 13:22:52 -07001821 bnx2_write_phy(bp, bp->mii_bmcr, BMCR_LOOPBACK);
Michael Chan80be4432006-11-19 14:07:28 -08001822 spin_unlock_bh(&bp->phy_lock);
1823 msleep(20);
1824 spin_lock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07001825 }
1826
Michael Chanca58c3a2007-05-03 13:22:52 -07001827 bnx2_write_phy(bp, bp->mii_adv, new_adv);
1828 bnx2_write_phy(bp, bp->mii_bmcr, bmcr | BMCR_ANRESTART |
Michael Chanb6016b72005-05-26 13:03:09 -07001829 BMCR_ANENABLE);
Michael Chanf8dd0642006-11-19 14:08:29 -08001830 /* Speed up link-up time when the link partner
1831 * does not autonegotiate which is very common
1832 * in blade servers. Some blade servers use
1833 * IPMI for kerboard input and it's important
1834 * to minimize link disruptions. Autoneg. involves
1835 * exchanging base pages plus 3 next pages and
1836 * normally completes in about 120 msec.
1837 */
Michael Chan40105c02008-11-12 16:02:45 -08001838 bp->current_interval = BNX2_SERDES_AN_TIMEOUT;
Michael Chanf8dd0642006-11-19 14:08:29 -08001839 bp->serdes_an_pending = 1;
1840 mod_timer(&bp->timer, jiffies + bp->current_interval);
Michael Chan605a9e22007-05-03 13:23:13 -07001841 } else {
1842 bnx2_resolve_flow_ctrl(bp);
1843 bnx2_set_mac_link(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07001844 }
1845
1846 return 0;
1847}
1848
1849#define ETHTOOL_ALL_FIBRE_SPEED \
Michael Chan583c28e2008-01-21 19:51:35 -08001850 (bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE) ? \
Michael Chandeaf3912007-07-07 22:48:00 -07001851 (ADVERTISED_2500baseX_Full | ADVERTISED_1000baseT_Full) :\
1852 (ADVERTISED_1000baseT_Full)
Michael Chanb6016b72005-05-26 13:03:09 -07001853
1854#define ETHTOOL_ALL_COPPER_SPEED \
1855 (ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full | \
1856 ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full | \
1857 ADVERTISED_1000baseT_Full)
1858
1859#define PHY_ALL_10_100_SPEED (ADVERTISE_10HALF | ADVERTISE_10FULL | \
1860 ADVERTISE_100HALF | ADVERTISE_100FULL | ADVERTISE_CSMA)
Jeff Garzik6aa20a22006-09-13 13:24:59 -04001861
Michael Chanb6016b72005-05-26 13:03:09 -07001862#define PHY_ALL_1000_SPEED (ADVERTISE_1000HALF | ADVERTISE_1000FULL)
1863
Michael Chandeaf3912007-07-07 22:48:00 -07001864static void
Michael Chan0d8a6572007-07-07 22:49:43 -07001865bnx2_set_default_remote_link(struct bnx2 *bp)
1866{
1867 u32 link;
1868
1869 if (bp->phy_port == PORT_TP)
Michael Chan2726d6e2008-01-29 21:35:05 -08001870 link = bnx2_shmem_rd(bp, BNX2_RPHY_COPPER_LINK);
Michael Chan0d8a6572007-07-07 22:49:43 -07001871 else
Michael Chan2726d6e2008-01-29 21:35:05 -08001872 link = bnx2_shmem_rd(bp, BNX2_RPHY_SERDES_LINK);
Michael Chan0d8a6572007-07-07 22:49:43 -07001873
1874 if (link & BNX2_NETLINK_SET_LINK_ENABLE_AUTONEG) {
1875 bp->req_line_speed = 0;
1876 bp->autoneg |= AUTONEG_SPEED;
1877 bp->advertising = ADVERTISED_Autoneg;
1878 if (link & BNX2_NETLINK_SET_LINK_SPEED_10HALF)
1879 bp->advertising |= ADVERTISED_10baseT_Half;
1880 if (link & BNX2_NETLINK_SET_LINK_SPEED_10FULL)
1881 bp->advertising |= ADVERTISED_10baseT_Full;
1882 if (link & BNX2_NETLINK_SET_LINK_SPEED_100HALF)
1883 bp->advertising |= ADVERTISED_100baseT_Half;
1884 if (link & BNX2_NETLINK_SET_LINK_SPEED_100FULL)
1885 bp->advertising |= ADVERTISED_100baseT_Full;
1886 if (link & BNX2_NETLINK_SET_LINK_SPEED_1GFULL)
1887 bp->advertising |= ADVERTISED_1000baseT_Full;
1888 if (link & BNX2_NETLINK_SET_LINK_SPEED_2G5FULL)
1889 bp->advertising |= ADVERTISED_2500baseX_Full;
1890 } else {
1891 bp->autoneg = 0;
1892 bp->advertising = 0;
1893 bp->req_duplex = DUPLEX_FULL;
1894 if (link & BNX2_NETLINK_SET_LINK_SPEED_10) {
1895 bp->req_line_speed = SPEED_10;
1896 if (link & BNX2_NETLINK_SET_LINK_SPEED_10HALF)
1897 bp->req_duplex = DUPLEX_HALF;
1898 }
1899 if (link & BNX2_NETLINK_SET_LINK_SPEED_100) {
1900 bp->req_line_speed = SPEED_100;
1901 if (link & BNX2_NETLINK_SET_LINK_SPEED_100HALF)
1902 bp->req_duplex = DUPLEX_HALF;
1903 }
1904 if (link & BNX2_NETLINK_SET_LINK_SPEED_1GFULL)
1905 bp->req_line_speed = SPEED_1000;
1906 if (link & BNX2_NETLINK_SET_LINK_SPEED_2G5FULL)
1907 bp->req_line_speed = SPEED_2500;
1908 }
1909}
1910
1911static void
Michael Chandeaf3912007-07-07 22:48:00 -07001912bnx2_set_default_link(struct bnx2 *bp)
1913{
Harvey Harrisonab598592008-05-01 02:47:38 -07001914 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP) {
1915 bnx2_set_default_remote_link(bp);
1916 return;
1917 }
Michael Chan0d8a6572007-07-07 22:49:43 -07001918
Michael Chandeaf3912007-07-07 22:48:00 -07001919 bp->autoneg = AUTONEG_SPEED | AUTONEG_FLOW_CTRL;
1920 bp->req_line_speed = 0;
Michael Chan583c28e2008-01-21 19:51:35 -08001921 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Michael Chandeaf3912007-07-07 22:48:00 -07001922 u32 reg;
1923
1924 bp->advertising = ETHTOOL_ALL_FIBRE_SPEED | ADVERTISED_Autoneg;
1925
Michael Chan2726d6e2008-01-29 21:35:05 -08001926 reg = bnx2_shmem_rd(bp, BNX2_PORT_HW_CFG_CONFIG);
Michael Chandeaf3912007-07-07 22:48:00 -07001927 reg &= BNX2_PORT_HW_CFG_CFG_DFLT_LINK_MASK;
1928 if (reg == BNX2_PORT_HW_CFG_CFG_DFLT_LINK_1G) {
1929 bp->autoneg = 0;
1930 bp->req_line_speed = bp->line_speed = SPEED_1000;
1931 bp->req_duplex = DUPLEX_FULL;
1932 }
1933 } else
1934 bp->advertising = ETHTOOL_ALL_COPPER_SPEED | ADVERTISED_Autoneg;
1935}
1936
Michael Chan0d8a6572007-07-07 22:49:43 -07001937static void
Michael Chandf149d72007-07-07 22:51:36 -07001938bnx2_send_heart_beat(struct bnx2 *bp)
1939{
1940 u32 msg;
1941 u32 addr;
1942
1943 spin_lock(&bp->indirect_lock);
1944 msg = (u32) (++bp->fw_drv_pulse_wr_seq & BNX2_DRV_PULSE_SEQ_MASK);
1945 addr = bp->shmem_base + BNX2_DRV_PULSE_MB;
1946 REG_WR(bp, BNX2_PCICFG_REG_WINDOW_ADDRESS, addr);
1947 REG_WR(bp, BNX2_PCICFG_REG_WINDOW, msg);
1948 spin_unlock(&bp->indirect_lock);
1949}
1950
1951static void
Michael Chan0d8a6572007-07-07 22:49:43 -07001952bnx2_remote_phy_event(struct bnx2 *bp)
1953{
1954 u32 msg;
1955 u8 link_up = bp->link_up;
1956 u8 old_port;
1957
Michael Chan2726d6e2008-01-29 21:35:05 -08001958 msg = bnx2_shmem_rd(bp, BNX2_LINK_STATUS);
Michael Chan0d8a6572007-07-07 22:49:43 -07001959
Michael Chandf149d72007-07-07 22:51:36 -07001960 if (msg & BNX2_LINK_STATUS_HEART_BEAT_EXPIRED)
1961 bnx2_send_heart_beat(bp);
1962
1963 msg &= ~BNX2_LINK_STATUS_HEART_BEAT_EXPIRED;
1964
Michael Chan0d8a6572007-07-07 22:49:43 -07001965 if ((msg & BNX2_LINK_STATUS_LINK_UP) == BNX2_LINK_STATUS_LINK_DOWN)
1966 bp->link_up = 0;
1967 else {
1968 u32 speed;
1969
1970 bp->link_up = 1;
1971 speed = msg & BNX2_LINK_STATUS_SPEED_MASK;
1972 bp->duplex = DUPLEX_FULL;
1973 switch (speed) {
1974 case BNX2_LINK_STATUS_10HALF:
1975 bp->duplex = DUPLEX_HALF;
1976 case BNX2_LINK_STATUS_10FULL:
1977 bp->line_speed = SPEED_10;
1978 break;
1979 case BNX2_LINK_STATUS_100HALF:
1980 bp->duplex = DUPLEX_HALF;
1981 case BNX2_LINK_STATUS_100BASE_T4:
1982 case BNX2_LINK_STATUS_100FULL:
1983 bp->line_speed = SPEED_100;
1984 break;
1985 case BNX2_LINK_STATUS_1000HALF:
1986 bp->duplex = DUPLEX_HALF;
1987 case BNX2_LINK_STATUS_1000FULL:
1988 bp->line_speed = SPEED_1000;
1989 break;
1990 case BNX2_LINK_STATUS_2500HALF:
1991 bp->duplex = DUPLEX_HALF;
1992 case BNX2_LINK_STATUS_2500FULL:
1993 bp->line_speed = SPEED_2500;
1994 break;
1995 default:
1996 bp->line_speed = 0;
1997 break;
1998 }
1999
Michael Chan0d8a6572007-07-07 22:49:43 -07002000 bp->flow_ctrl = 0;
2001 if ((bp->autoneg & (AUTONEG_SPEED | AUTONEG_FLOW_CTRL)) !=
2002 (AUTONEG_SPEED | AUTONEG_FLOW_CTRL)) {
2003 if (bp->duplex == DUPLEX_FULL)
2004 bp->flow_ctrl = bp->req_flow_ctrl;
2005 } else {
2006 if (msg & BNX2_LINK_STATUS_TX_FC_ENABLED)
2007 bp->flow_ctrl |= FLOW_CTRL_TX;
2008 if (msg & BNX2_LINK_STATUS_RX_FC_ENABLED)
2009 bp->flow_ctrl |= FLOW_CTRL_RX;
2010 }
2011
2012 old_port = bp->phy_port;
2013 if (msg & BNX2_LINK_STATUS_SERDES_LINK)
2014 bp->phy_port = PORT_FIBRE;
2015 else
2016 bp->phy_port = PORT_TP;
2017
2018 if (old_port != bp->phy_port)
2019 bnx2_set_default_link(bp);
2020
Michael Chan0d8a6572007-07-07 22:49:43 -07002021 }
2022 if (bp->link_up != link_up)
2023 bnx2_report_link(bp);
2024
2025 bnx2_set_mac_link(bp);
2026}
2027
2028static int
2029bnx2_set_remote_link(struct bnx2 *bp)
2030{
2031 u32 evt_code;
2032
Michael Chan2726d6e2008-01-29 21:35:05 -08002033 evt_code = bnx2_shmem_rd(bp, BNX2_FW_EVT_CODE_MB);
Michael Chan0d8a6572007-07-07 22:49:43 -07002034 switch (evt_code) {
2035 case BNX2_FW_EVT_CODE_LINK_EVENT:
2036 bnx2_remote_phy_event(bp);
2037 break;
2038 case BNX2_FW_EVT_CODE_SW_TIMER_EXPIRATION_EVENT:
2039 default:
Michael Chandf149d72007-07-07 22:51:36 -07002040 bnx2_send_heart_beat(bp);
Michael Chan0d8a6572007-07-07 22:49:43 -07002041 break;
2042 }
2043 return 0;
2044}
2045
Michael Chanb6016b72005-05-26 13:03:09 -07002046static int
2047bnx2_setup_copper_phy(struct bnx2 *bp)
Harvey Harrison52d07b12009-01-19 17:27:06 -08002048__releases(&bp->phy_lock)
2049__acquires(&bp->phy_lock)
Michael Chanb6016b72005-05-26 13:03:09 -07002050{
2051 u32 bmcr;
2052 u32 new_bmcr;
2053
Michael Chanca58c3a2007-05-03 13:22:52 -07002054 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chanb6016b72005-05-26 13:03:09 -07002055
2056 if (bp->autoneg & AUTONEG_SPEED) {
2057 u32 adv_reg, adv1000_reg;
2058 u32 new_adv_reg = 0;
2059 u32 new_adv1000_reg = 0;
2060
Michael Chanca58c3a2007-05-03 13:22:52 -07002061 bnx2_read_phy(bp, bp->mii_adv, &adv_reg);
Michael Chanb6016b72005-05-26 13:03:09 -07002062 adv_reg &= (PHY_ALL_10_100_SPEED | ADVERTISE_PAUSE_CAP |
2063 ADVERTISE_PAUSE_ASYM);
2064
2065 bnx2_read_phy(bp, MII_CTRL1000, &adv1000_reg);
2066 adv1000_reg &= PHY_ALL_1000_SPEED;
2067
2068 if (bp->advertising & ADVERTISED_10baseT_Half)
2069 new_adv_reg |= ADVERTISE_10HALF;
2070 if (bp->advertising & ADVERTISED_10baseT_Full)
2071 new_adv_reg |= ADVERTISE_10FULL;
2072 if (bp->advertising & ADVERTISED_100baseT_Half)
2073 new_adv_reg |= ADVERTISE_100HALF;
2074 if (bp->advertising & ADVERTISED_100baseT_Full)
2075 new_adv_reg |= ADVERTISE_100FULL;
2076 if (bp->advertising & ADVERTISED_1000baseT_Full)
2077 new_adv1000_reg |= ADVERTISE_1000FULL;
Jeff Garzik6aa20a22006-09-13 13:24:59 -04002078
Michael Chanb6016b72005-05-26 13:03:09 -07002079 new_adv_reg |= ADVERTISE_CSMA;
2080
2081 new_adv_reg |= bnx2_phy_get_pause_adv(bp);
2082
2083 if ((adv1000_reg != new_adv1000_reg) ||
2084 (adv_reg != new_adv_reg) ||
2085 ((bmcr & BMCR_ANENABLE) == 0)) {
2086
Michael Chanca58c3a2007-05-03 13:22:52 -07002087 bnx2_write_phy(bp, bp->mii_adv, new_adv_reg);
Michael Chanb6016b72005-05-26 13:03:09 -07002088 bnx2_write_phy(bp, MII_CTRL1000, new_adv1000_reg);
Michael Chanca58c3a2007-05-03 13:22:52 -07002089 bnx2_write_phy(bp, bp->mii_bmcr, BMCR_ANRESTART |
Michael Chanb6016b72005-05-26 13:03:09 -07002090 BMCR_ANENABLE);
2091 }
2092 else if (bp->link_up) {
2093 /* Flow ctrl may have changed from auto to forced */
2094 /* or vice-versa. */
2095
2096 bnx2_resolve_flow_ctrl(bp);
2097 bnx2_set_mac_link(bp);
2098 }
2099 return 0;
2100 }
2101
2102 new_bmcr = 0;
2103 if (bp->req_line_speed == SPEED_100) {
2104 new_bmcr |= BMCR_SPEED100;
2105 }
2106 if (bp->req_duplex == DUPLEX_FULL) {
2107 new_bmcr |= BMCR_FULLDPLX;
2108 }
2109 if (new_bmcr != bmcr) {
2110 u32 bmsr;
Michael Chanb6016b72005-05-26 13:03:09 -07002111
Michael Chanca58c3a2007-05-03 13:22:52 -07002112 bnx2_read_phy(bp, bp->mii_bmsr, &bmsr);
2113 bnx2_read_phy(bp, bp->mii_bmsr, &bmsr);
Jeff Garzik6aa20a22006-09-13 13:24:59 -04002114
Michael Chanb6016b72005-05-26 13:03:09 -07002115 if (bmsr & BMSR_LSTATUS) {
2116 /* Force link down */
Michael Chanca58c3a2007-05-03 13:22:52 -07002117 bnx2_write_phy(bp, bp->mii_bmcr, BMCR_LOOPBACK);
Michael Chana16dda02006-11-19 14:08:56 -08002118 spin_unlock_bh(&bp->phy_lock);
2119 msleep(50);
2120 spin_lock_bh(&bp->phy_lock);
2121
Michael Chanca58c3a2007-05-03 13:22:52 -07002122 bnx2_read_phy(bp, bp->mii_bmsr, &bmsr);
2123 bnx2_read_phy(bp, bp->mii_bmsr, &bmsr);
Michael Chanb6016b72005-05-26 13:03:09 -07002124 }
2125
Michael Chanca58c3a2007-05-03 13:22:52 -07002126 bnx2_write_phy(bp, bp->mii_bmcr, new_bmcr);
Michael Chanb6016b72005-05-26 13:03:09 -07002127
2128 /* Normally, the new speed is setup after the link has
2129 * gone down and up again. In some cases, link will not go
2130 * down so we need to set up the new speed here.
2131 */
2132 if (bmsr & BMSR_LSTATUS) {
2133 bp->line_speed = bp->req_line_speed;
2134 bp->duplex = bp->req_duplex;
2135 bnx2_resolve_flow_ctrl(bp);
2136 bnx2_set_mac_link(bp);
2137 }
Michael Chan27a005b2007-05-03 13:23:41 -07002138 } else {
2139 bnx2_resolve_flow_ctrl(bp);
2140 bnx2_set_mac_link(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07002141 }
2142 return 0;
2143}
2144
2145static int
Michael Chan0d8a6572007-07-07 22:49:43 -07002146bnx2_setup_phy(struct bnx2 *bp, u8 port)
Harvey Harrison52d07b12009-01-19 17:27:06 -08002147__releases(&bp->phy_lock)
2148__acquires(&bp->phy_lock)
Michael Chanb6016b72005-05-26 13:03:09 -07002149{
2150 if (bp->loopback == MAC_LOOPBACK)
2151 return 0;
2152
Michael Chan583c28e2008-01-21 19:51:35 -08002153 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Michael Chan0d8a6572007-07-07 22:49:43 -07002154 return (bnx2_setup_serdes_phy(bp, port));
Michael Chanb6016b72005-05-26 13:03:09 -07002155 }
2156 else {
2157 return (bnx2_setup_copper_phy(bp));
2158 }
2159}
2160
2161static int
Michael Chan9a120bc2008-05-16 22:17:45 -07002162bnx2_init_5709s_phy(struct bnx2 *bp, int reset_phy)
Michael Chan27a005b2007-05-03 13:23:41 -07002163{
2164 u32 val;
2165
2166 bp->mii_bmcr = MII_BMCR + 0x10;
2167 bp->mii_bmsr = MII_BMSR + 0x10;
2168 bp->mii_bmsr1 = MII_BNX2_GP_TOP_AN_STATUS1;
2169 bp->mii_adv = MII_ADVERTISE + 0x10;
2170 bp->mii_lpa = MII_LPA + 0x10;
2171 bp->mii_up1 = MII_BNX2_OVER1G_UP1;
2172
2173 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_AER);
2174 bnx2_write_phy(bp, MII_BNX2_AER_AER, MII_BNX2_AER_AER_AN_MMD);
2175
2176 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
Michael Chan9a120bc2008-05-16 22:17:45 -07002177 if (reset_phy)
2178 bnx2_reset_phy(bp);
Michael Chan27a005b2007-05-03 13:23:41 -07002179
2180 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_SERDES_DIG);
2181
2182 bnx2_read_phy(bp, MII_BNX2_SERDES_DIG_1000XCTL1, &val);
2183 val &= ~MII_BNX2_SD_1000XCTL1_AUTODET;
2184 val |= MII_BNX2_SD_1000XCTL1_FIBER;
2185 bnx2_write_phy(bp, MII_BNX2_SERDES_DIG_1000XCTL1, val);
2186
2187 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_OVER1G);
2188 bnx2_read_phy(bp, MII_BNX2_OVER1G_UP1, &val);
Michael Chan583c28e2008-01-21 19:51:35 -08002189 if (bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE)
Michael Chan27a005b2007-05-03 13:23:41 -07002190 val |= BCM5708S_UP1_2G5;
2191 else
2192 val &= ~BCM5708S_UP1_2G5;
2193 bnx2_write_phy(bp, MII_BNX2_OVER1G_UP1, val);
2194
2195 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_BAM_NXTPG);
2196 bnx2_read_phy(bp, MII_BNX2_BAM_NXTPG_CTL, &val);
2197 val |= MII_BNX2_NXTPG_CTL_T2 | MII_BNX2_NXTPG_CTL_BAM;
2198 bnx2_write_phy(bp, MII_BNX2_BAM_NXTPG_CTL, val);
2199
2200 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_CL73_USERB0);
2201
2202 val = MII_BNX2_CL73_BAM_EN | MII_BNX2_CL73_BAM_STA_MGR_EN |
2203 MII_BNX2_CL73_BAM_NP_AFT_BP_EN;
2204 bnx2_write_phy(bp, MII_BNX2_CL73_BAM_CTL1, val);
2205
2206 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
2207
2208 return 0;
2209}
2210
2211static int
Michael Chan9a120bc2008-05-16 22:17:45 -07002212bnx2_init_5708s_phy(struct bnx2 *bp, int reset_phy)
Michael Chan5b0c76a2005-11-04 08:45:49 -08002213{
2214 u32 val;
2215
Michael Chan9a120bc2008-05-16 22:17:45 -07002216 if (reset_phy)
2217 bnx2_reset_phy(bp);
Michael Chan27a005b2007-05-03 13:23:41 -07002218
2219 bp->mii_up1 = BCM5708S_UP1;
2220
Michael Chan5b0c76a2005-11-04 08:45:49 -08002221 bnx2_write_phy(bp, BCM5708S_BLK_ADDR, BCM5708S_BLK_ADDR_DIG3);
2222 bnx2_write_phy(bp, BCM5708S_DIG_3_0, BCM5708S_DIG_3_0_USE_IEEE);
2223 bnx2_write_phy(bp, BCM5708S_BLK_ADDR, BCM5708S_BLK_ADDR_DIG);
2224
2225 bnx2_read_phy(bp, BCM5708S_1000X_CTL1, &val);
2226 val |= BCM5708S_1000X_CTL1_FIBER_MODE | BCM5708S_1000X_CTL1_AUTODET_EN;
2227 bnx2_write_phy(bp, BCM5708S_1000X_CTL1, val);
2228
2229 bnx2_read_phy(bp, BCM5708S_1000X_CTL2, &val);
2230 val |= BCM5708S_1000X_CTL2_PLLEL_DET_EN;
2231 bnx2_write_phy(bp, BCM5708S_1000X_CTL2, val);
2232
Michael Chan583c28e2008-01-21 19:51:35 -08002233 if (bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE) {
Michael Chan5b0c76a2005-11-04 08:45:49 -08002234 bnx2_read_phy(bp, BCM5708S_UP1, &val);
2235 val |= BCM5708S_UP1_2G5;
2236 bnx2_write_phy(bp, BCM5708S_UP1, val);
2237 }
2238
2239 if ((CHIP_ID(bp) == CHIP_ID_5708_A0) ||
Michael Chandda1e392006-01-23 16:08:14 -08002240 (CHIP_ID(bp) == CHIP_ID_5708_B0) ||
2241 (CHIP_ID(bp) == CHIP_ID_5708_B1)) {
Michael Chan5b0c76a2005-11-04 08:45:49 -08002242 /* increase tx signal amplitude */
2243 bnx2_write_phy(bp, BCM5708S_BLK_ADDR,
2244 BCM5708S_BLK_ADDR_TX_MISC);
2245 bnx2_read_phy(bp, BCM5708S_TX_ACTL1, &val);
2246 val &= ~BCM5708S_TX_ACTL1_DRIVER_VCM;
2247 bnx2_write_phy(bp, BCM5708S_TX_ACTL1, val);
2248 bnx2_write_phy(bp, BCM5708S_BLK_ADDR, BCM5708S_BLK_ADDR_DIG);
2249 }
2250
Michael Chan2726d6e2008-01-29 21:35:05 -08002251 val = bnx2_shmem_rd(bp, BNX2_PORT_HW_CFG_CONFIG) &
Michael Chan5b0c76a2005-11-04 08:45:49 -08002252 BNX2_PORT_HW_CFG_CFG_TXCTL3_MASK;
2253
2254 if (val) {
2255 u32 is_backplane;
2256
Michael Chan2726d6e2008-01-29 21:35:05 -08002257 is_backplane = bnx2_shmem_rd(bp, BNX2_SHARED_HW_CFG_CONFIG);
Michael Chan5b0c76a2005-11-04 08:45:49 -08002258 if (is_backplane & BNX2_SHARED_HW_CFG_PHY_BACKPLANE) {
2259 bnx2_write_phy(bp, BCM5708S_BLK_ADDR,
2260 BCM5708S_BLK_ADDR_TX_MISC);
2261 bnx2_write_phy(bp, BCM5708S_TX_ACTL3, val);
2262 bnx2_write_phy(bp, BCM5708S_BLK_ADDR,
2263 BCM5708S_BLK_ADDR_DIG);
2264 }
2265 }
2266 return 0;
2267}
2268
2269static int
Michael Chan9a120bc2008-05-16 22:17:45 -07002270bnx2_init_5706s_phy(struct bnx2 *bp, int reset_phy)
Michael Chanb6016b72005-05-26 13:03:09 -07002271{
Michael Chan9a120bc2008-05-16 22:17:45 -07002272 if (reset_phy)
2273 bnx2_reset_phy(bp);
Michael Chan27a005b2007-05-03 13:23:41 -07002274
Michael Chan583c28e2008-01-21 19:51:35 -08002275 bp->phy_flags &= ~BNX2_PHY_FLAG_PARALLEL_DETECT;
Michael Chanb6016b72005-05-26 13:03:09 -07002276
Michael Chan59b47d82006-11-19 14:10:45 -08002277 if (CHIP_NUM(bp) == CHIP_NUM_5706)
2278 REG_WR(bp, BNX2_MISC_GP_HW_CTL0, 0x300);
Michael Chanb6016b72005-05-26 13:03:09 -07002279
2280 if (bp->dev->mtu > 1500) {
2281 u32 val;
2282
2283 /* Set extended packet length bit */
2284 bnx2_write_phy(bp, 0x18, 0x7);
2285 bnx2_read_phy(bp, 0x18, &val);
2286 bnx2_write_phy(bp, 0x18, (val & 0xfff8) | 0x4000);
2287
2288 bnx2_write_phy(bp, 0x1c, 0x6c00);
2289 bnx2_read_phy(bp, 0x1c, &val);
2290 bnx2_write_phy(bp, 0x1c, (val & 0x3ff) | 0xec02);
2291 }
2292 else {
2293 u32 val;
2294
2295 bnx2_write_phy(bp, 0x18, 0x7);
2296 bnx2_read_phy(bp, 0x18, &val);
2297 bnx2_write_phy(bp, 0x18, val & ~0x4007);
2298
2299 bnx2_write_phy(bp, 0x1c, 0x6c00);
2300 bnx2_read_phy(bp, 0x1c, &val);
2301 bnx2_write_phy(bp, 0x1c, (val & 0x3fd) | 0xec00);
2302 }
2303
2304 return 0;
2305}
2306
2307static int
Michael Chan9a120bc2008-05-16 22:17:45 -07002308bnx2_init_copper_phy(struct bnx2 *bp, int reset_phy)
Michael Chanb6016b72005-05-26 13:03:09 -07002309{
Michael Chan5b0c76a2005-11-04 08:45:49 -08002310 u32 val;
2311
Michael Chan9a120bc2008-05-16 22:17:45 -07002312 if (reset_phy)
2313 bnx2_reset_phy(bp);
Michael Chan27a005b2007-05-03 13:23:41 -07002314
Michael Chan583c28e2008-01-21 19:51:35 -08002315 if (bp->phy_flags & BNX2_PHY_FLAG_CRC_FIX) {
Michael Chanb6016b72005-05-26 13:03:09 -07002316 bnx2_write_phy(bp, 0x18, 0x0c00);
2317 bnx2_write_phy(bp, 0x17, 0x000a);
2318 bnx2_write_phy(bp, 0x15, 0x310b);
2319 bnx2_write_phy(bp, 0x17, 0x201f);
2320 bnx2_write_phy(bp, 0x15, 0x9506);
2321 bnx2_write_phy(bp, 0x17, 0x401f);
2322 bnx2_write_phy(bp, 0x15, 0x14e2);
2323 bnx2_write_phy(bp, 0x18, 0x0400);
2324 }
2325
Michael Chan583c28e2008-01-21 19:51:35 -08002326 if (bp->phy_flags & BNX2_PHY_FLAG_DIS_EARLY_DAC) {
Michael Chanb659f442007-02-02 00:46:35 -08002327 bnx2_write_phy(bp, MII_BNX2_DSP_ADDRESS,
2328 MII_BNX2_DSP_EXPAND_REG | 0x8);
2329 bnx2_read_phy(bp, MII_BNX2_DSP_RW_PORT, &val);
2330 val &= ~(1 << 8);
2331 bnx2_write_phy(bp, MII_BNX2_DSP_RW_PORT, val);
2332 }
2333
Michael Chanb6016b72005-05-26 13:03:09 -07002334 if (bp->dev->mtu > 1500) {
Michael Chanb6016b72005-05-26 13:03:09 -07002335 /* Set extended packet length bit */
2336 bnx2_write_phy(bp, 0x18, 0x7);
2337 bnx2_read_phy(bp, 0x18, &val);
2338 bnx2_write_phy(bp, 0x18, val | 0x4000);
2339
2340 bnx2_read_phy(bp, 0x10, &val);
2341 bnx2_write_phy(bp, 0x10, val | 0x1);
2342 }
2343 else {
Michael Chanb6016b72005-05-26 13:03:09 -07002344 bnx2_write_phy(bp, 0x18, 0x7);
2345 bnx2_read_phy(bp, 0x18, &val);
2346 bnx2_write_phy(bp, 0x18, val & ~0x4007);
2347
2348 bnx2_read_phy(bp, 0x10, &val);
2349 bnx2_write_phy(bp, 0x10, val & ~0x1);
2350 }
2351
Michael Chan5b0c76a2005-11-04 08:45:49 -08002352 /* ethernet@wirespeed */
2353 bnx2_write_phy(bp, 0x18, 0x7007);
2354 bnx2_read_phy(bp, 0x18, &val);
2355 bnx2_write_phy(bp, 0x18, val | (1 << 15) | (1 << 4));
Michael Chanb6016b72005-05-26 13:03:09 -07002356 return 0;
2357}
2358
2359
2360static int
Michael Chan9a120bc2008-05-16 22:17:45 -07002361bnx2_init_phy(struct bnx2 *bp, int reset_phy)
Harvey Harrison52d07b12009-01-19 17:27:06 -08002362__releases(&bp->phy_lock)
2363__acquires(&bp->phy_lock)
Michael Chanb6016b72005-05-26 13:03:09 -07002364{
2365 u32 val;
2366 int rc = 0;
2367
Michael Chan583c28e2008-01-21 19:51:35 -08002368 bp->phy_flags &= ~BNX2_PHY_FLAG_INT_MODE_MASK;
2369 bp->phy_flags |= BNX2_PHY_FLAG_INT_MODE_LINK_READY;
Michael Chanb6016b72005-05-26 13:03:09 -07002370
Michael Chanca58c3a2007-05-03 13:22:52 -07002371 bp->mii_bmcr = MII_BMCR;
2372 bp->mii_bmsr = MII_BMSR;
Michael Chan27a005b2007-05-03 13:23:41 -07002373 bp->mii_bmsr1 = MII_BMSR;
Michael Chanca58c3a2007-05-03 13:22:52 -07002374 bp->mii_adv = MII_ADVERTISE;
2375 bp->mii_lpa = MII_LPA;
2376
Michael Chanb6016b72005-05-26 13:03:09 -07002377 REG_WR(bp, BNX2_EMAC_ATTENTION_ENA, BNX2_EMAC_ATTENTION_ENA_LINK);
2378
Michael Chan583c28e2008-01-21 19:51:35 -08002379 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
Michael Chan0d8a6572007-07-07 22:49:43 -07002380 goto setup_phy;
2381
Michael Chanb6016b72005-05-26 13:03:09 -07002382 bnx2_read_phy(bp, MII_PHYSID1, &val);
2383 bp->phy_id = val << 16;
2384 bnx2_read_phy(bp, MII_PHYSID2, &val);
2385 bp->phy_id |= val & 0xffff;
2386
Michael Chan583c28e2008-01-21 19:51:35 -08002387 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Michael Chan5b0c76a2005-11-04 08:45:49 -08002388 if (CHIP_NUM(bp) == CHIP_NUM_5706)
Michael Chan9a120bc2008-05-16 22:17:45 -07002389 rc = bnx2_init_5706s_phy(bp, reset_phy);
Michael Chan5b0c76a2005-11-04 08:45:49 -08002390 else if (CHIP_NUM(bp) == CHIP_NUM_5708)
Michael Chan9a120bc2008-05-16 22:17:45 -07002391 rc = bnx2_init_5708s_phy(bp, reset_phy);
Michael Chan27a005b2007-05-03 13:23:41 -07002392 else if (CHIP_NUM(bp) == CHIP_NUM_5709)
Michael Chan9a120bc2008-05-16 22:17:45 -07002393 rc = bnx2_init_5709s_phy(bp, reset_phy);
Michael Chanb6016b72005-05-26 13:03:09 -07002394 }
2395 else {
Michael Chan9a120bc2008-05-16 22:17:45 -07002396 rc = bnx2_init_copper_phy(bp, reset_phy);
Michael Chanb6016b72005-05-26 13:03:09 -07002397 }
2398
Michael Chan0d8a6572007-07-07 22:49:43 -07002399setup_phy:
2400 if (!rc)
2401 rc = bnx2_setup_phy(bp, bp->phy_port);
Michael Chanb6016b72005-05-26 13:03:09 -07002402
2403 return rc;
2404}
2405
2406static int
2407bnx2_set_mac_loopback(struct bnx2 *bp)
2408{
2409 u32 mac_mode;
2410
2411 mac_mode = REG_RD(bp, BNX2_EMAC_MODE);
2412 mac_mode &= ~BNX2_EMAC_MODE_PORT;
2413 mac_mode |= BNX2_EMAC_MODE_MAC_LOOP | BNX2_EMAC_MODE_FORCE_LINK;
2414 REG_WR(bp, BNX2_EMAC_MODE, mac_mode);
2415 bp->link_up = 1;
2416 return 0;
2417}
2418
Michael Chanbc5a0692006-01-23 16:13:22 -08002419static int bnx2_test_link(struct bnx2 *);
2420
2421static int
2422bnx2_set_phy_loopback(struct bnx2 *bp)
2423{
2424 u32 mac_mode;
2425 int rc, i;
2426
2427 spin_lock_bh(&bp->phy_lock);
Michael Chanca58c3a2007-05-03 13:22:52 -07002428 rc = bnx2_write_phy(bp, bp->mii_bmcr, BMCR_LOOPBACK | BMCR_FULLDPLX |
Michael Chanbc5a0692006-01-23 16:13:22 -08002429 BMCR_SPEED1000);
2430 spin_unlock_bh(&bp->phy_lock);
2431 if (rc)
2432 return rc;
2433
2434 for (i = 0; i < 10; i++) {
2435 if (bnx2_test_link(bp) == 0)
2436 break;
Michael Chan80be4432006-11-19 14:07:28 -08002437 msleep(100);
Michael Chanbc5a0692006-01-23 16:13:22 -08002438 }
2439
2440 mac_mode = REG_RD(bp, BNX2_EMAC_MODE);
2441 mac_mode &= ~(BNX2_EMAC_MODE_PORT | BNX2_EMAC_MODE_HALF_DUPLEX |
2442 BNX2_EMAC_MODE_MAC_LOOP | BNX2_EMAC_MODE_FORCE_LINK |
Michael Chan59b47d82006-11-19 14:10:45 -08002443 BNX2_EMAC_MODE_25G_MODE);
Michael Chanbc5a0692006-01-23 16:13:22 -08002444
2445 mac_mode |= BNX2_EMAC_MODE_PORT_GMII;
2446 REG_WR(bp, BNX2_EMAC_MODE, mac_mode);
2447 bp->link_up = 1;
2448 return 0;
2449}
2450
Michael Chanb6016b72005-05-26 13:03:09 -07002451static int
Michael Chana2f13892008-07-14 22:38:23 -07002452bnx2_fw_sync(struct bnx2 *bp, u32 msg_data, int ack, int silent)
Michael Chanb6016b72005-05-26 13:03:09 -07002453{
2454 int i;
2455 u32 val;
2456
Michael Chanb6016b72005-05-26 13:03:09 -07002457 bp->fw_wr_seq++;
2458 msg_data |= bp->fw_wr_seq;
2459
Michael Chan2726d6e2008-01-29 21:35:05 -08002460 bnx2_shmem_wr(bp, BNX2_DRV_MB, msg_data);
Michael Chanb6016b72005-05-26 13:03:09 -07002461
Michael Chana2f13892008-07-14 22:38:23 -07002462 if (!ack)
2463 return 0;
2464
Michael Chanb6016b72005-05-26 13:03:09 -07002465 /* wait for an acknowledgement. */
Michael Chan40105c02008-11-12 16:02:45 -08002466 for (i = 0; i < (BNX2_FW_ACK_TIME_OUT_MS / 10); i++) {
Michael Chanb090ae22006-01-23 16:07:10 -08002467 msleep(10);
Michael Chanb6016b72005-05-26 13:03:09 -07002468
Michael Chan2726d6e2008-01-29 21:35:05 -08002469 val = bnx2_shmem_rd(bp, BNX2_FW_MB);
Michael Chanb6016b72005-05-26 13:03:09 -07002470
2471 if ((val & BNX2_FW_MSG_ACK) == (msg_data & BNX2_DRV_MSG_SEQ))
2472 break;
2473 }
Michael Chanb090ae22006-01-23 16:07:10 -08002474 if ((msg_data & BNX2_DRV_MSG_DATA) == BNX2_DRV_MSG_DATA_WAIT0)
2475 return 0;
Michael Chanb6016b72005-05-26 13:03:09 -07002476
2477 /* If we timed out, inform the firmware that this is the case. */
Michael Chanb090ae22006-01-23 16:07:10 -08002478 if ((val & BNX2_FW_MSG_ACK) != (msg_data & BNX2_DRV_MSG_SEQ)) {
2479 if (!silent)
Joe Perches3a9c6a42010-02-17 15:01:51 +00002480 pr_err("fw sync timeout, reset code = %x\n", msg_data);
Michael Chanb6016b72005-05-26 13:03:09 -07002481
2482 msg_data &= ~BNX2_DRV_MSG_CODE;
2483 msg_data |= BNX2_DRV_MSG_CODE_FW_TIMEOUT;
2484
Michael Chan2726d6e2008-01-29 21:35:05 -08002485 bnx2_shmem_wr(bp, BNX2_DRV_MB, msg_data);
Michael Chanb6016b72005-05-26 13:03:09 -07002486
Michael Chanb6016b72005-05-26 13:03:09 -07002487 return -EBUSY;
2488 }
2489
Michael Chanb090ae22006-01-23 16:07:10 -08002490 if ((val & BNX2_FW_MSG_STATUS_MASK) != BNX2_FW_MSG_STATUS_OK)
2491 return -EIO;
2492
Michael Chanb6016b72005-05-26 13:03:09 -07002493 return 0;
2494}
2495
Michael Chan59b47d82006-11-19 14:10:45 -08002496static int
2497bnx2_init_5709_context(struct bnx2 *bp)
2498{
2499 int i, ret = 0;
2500 u32 val;
2501
2502 val = BNX2_CTX_COMMAND_ENABLED | BNX2_CTX_COMMAND_MEM_INIT | (1 << 12);
2503 val |= (BCM_PAGE_BITS - 8) << 16;
2504 REG_WR(bp, BNX2_CTX_COMMAND, val);
Michael Chan641bdcd2007-06-04 21:22:24 -07002505 for (i = 0; i < 10; i++) {
2506 val = REG_RD(bp, BNX2_CTX_COMMAND);
2507 if (!(val & BNX2_CTX_COMMAND_MEM_INIT))
2508 break;
2509 udelay(2);
2510 }
2511 if (val & BNX2_CTX_COMMAND_MEM_INIT)
2512 return -EBUSY;
2513
Michael Chan59b47d82006-11-19 14:10:45 -08002514 for (i = 0; i < bp->ctx_pages; i++) {
2515 int j;
2516
Michael Chan352f7682008-05-02 16:57:26 -07002517 if (bp->ctx_blk[i])
2518 memset(bp->ctx_blk[i], 0, BCM_PAGE_SIZE);
2519 else
2520 return -ENOMEM;
2521
Michael Chan59b47d82006-11-19 14:10:45 -08002522 REG_WR(bp, BNX2_CTX_HOST_PAGE_TBL_DATA0,
2523 (bp->ctx_blk_mapping[i] & 0xffffffff) |
2524 BNX2_CTX_HOST_PAGE_TBL_DATA0_VALID);
2525 REG_WR(bp, BNX2_CTX_HOST_PAGE_TBL_DATA1,
2526 (u64) bp->ctx_blk_mapping[i] >> 32);
2527 REG_WR(bp, BNX2_CTX_HOST_PAGE_TBL_CTRL, i |
2528 BNX2_CTX_HOST_PAGE_TBL_CTRL_WRITE_REQ);
2529 for (j = 0; j < 10; j++) {
2530
2531 val = REG_RD(bp, BNX2_CTX_HOST_PAGE_TBL_CTRL);
2532 if (!(val & BNX2_CTX_HOST_PAGE_TBL_CTRL_WRITE_REQ))
2533 break;
2534 udelay(5);
2535 }
2536 if (val & BNX2_CTX_HOST_PAGE_TBL_CTRL_WRITE_REQ) {
2537 ret = -EBUSY;
2538 break;
2539 }
2540 }
2541 return ret;
2542}
2543
Michael Chanb6016b72005-05-26 13:03:09 -07002544static void
2545bnx2_init_context(struct bnx2 *bp)
2546{
2547 u32 vcid;
2548
2549 vcid = 96;
2550 while (vcid) {
2551 u32 vcid_addr, pcid_addr, offset;
Michael Chan7947b202007-06-04 21:17:10 -07002552 int i;
Michael Chanb6016b72005-05-26 13:03:09 -07002553
2554 vcid--;
2555
2556 if (CHIP_ID(bp) == CHIP_ID_5706_A0) {
2557 u32 new_vcid;
2558
2559 vcid_addr = GET_PCID_ADDR(vcid);
2560 if (vcid & 0x8) {
2561 new_vcid = 0x60 + (vcid & 0xf0) + (vcid & 0x7);
2562 }
2563 else {
2564 new_vcid = vcid;
2565 }
2566 pcid_addr = GET_PCID_ADDR(new_vcid);
2567 }
2568 else {
2569 vcid_addr = GET_CID_ADDR(vcid);
2570 pcid_addr = vcid_addr;
2571 }
2572
Michael Chan7947b202007-06-04 21:17:10 -07002573 for (i = 0; i < (CTX_SIZE / PHY_CTX_SIZE); i++) {
2574 vcid_addr += (i << PHY_CTX_SHIFT);
2575 pcid_addr += (i << PHY_CTX_SHIFT);
Michael Chanb6016b72005-05-26 13:03:09 -07002576
Michael Chan5d5d0012007-12-12 11:17:43 -08002577 REG_WR(bp, BNX2_CTX_VIRT_ADDR, vcid_addr);
Michael Chan7947b202007-06-04 21:17:10 -07002578 REG_WR(bp, BNX2_CTX_PAGE_TBL, pcid_addr);
2579
2580 /* Zero out the context. */
2581 for (offset = 0; offset < PHY_CTX_SIZE; offset += 4)
Michael Chan62a83132008-01-29 21:35:40 -08002582 bnx2_ctx_wr(bp, vcid_addr, offset, 0);
Michael Chanb6016b72005-05-26 13:03:09 -07002583 }
Michael Chanb6016b72005-05-26 13:03:09 -07002584 }
2585}
2586
2587static int
2588bnx2_alloc_bad_rbuf(struct bnx2 *bp)
2589{
2590 u16 *good_mbuf;
2591 u32 good_mbuf_cnt;
2592 u32 val;
2593
2594 good_mbuf = kmalloc(512 * sizeof(u16), GFP_KERNEL);
2595 if (good_mbuf == NULL) {
Joe Perches3a9c6a42010-02-17 15:01:51 +00002596 pr_err("Failed to allocate memory in %s\n", __func__);
Michael Chanb6016b72005-05-26 13:03:09 -07002597 return -ENOMEM;
2598 }
2599
2600 REG_WR(bp, BNX2_MISC_ENABLE_SET_BITS,
2601 BNX2_MISC_ENABLE_SET_BITS_RX_MBUF_ENABLE);
2602
2603 good_mbuf_cnt = 0;
2604
2605 /* Allocate a bunch of mbufs and save the good ones in an array. */
Michael Chan2726d6e2008-01-29 21:35:05 -08002606 val = bnx2_reg_rd_ind(bp, BNX2_RBUF_STATUS1);
Michael Chanb6016b72005-05-26 13:03:09 -07002607 while (val & BNX2_RBUF_STATUS1_FREE_COUNT) {
Michael Chan2726d6e2008-01-29 21:35:05 -08002608 bnx2_reg_wr_ind(bp, BNX2_RBUF_COMMAND,
2609 BNX2_RBUF_COMMAND_ALLOC_REQ);
Michael Chanb6016b72005-05-26 13:03:09 -07002610
Michael Chan2726d6e2008-01-29 21:35:05 -08002611 val = bnx2_reg_rd_ind(bp, BNX2_RBUF_FW_BUF_ALLOC);
Michael Chanb6016b72005-05-26 13:03:09 -07002612
2613 val &= BNX2_RBUF_FW_BUF_ALLOC_VALUE;
2614
2615 /* The addresses with Bit 9 set are bad memory blocks. */
2616 if (!(val & (1 << 9))) {
2617 good_mbuf[good_mbuf_cnt] = (u16) val;
2618 good_mbuf_cnt++;
2619 }
2620
Michael Chan2726d6e2008-01-29 21:35:05 -08002621 val = bnx2_reg_rd_ind(bp, BNX2_RBUF_STATUS1);
Michael Chanb6016b72005-05-26 13:03:09 -07002622 }
2623
2624 /* Free the good ones back to the mbuf pool thus discarding
2625 * all the bad ones. */
2626 while (good_mbuf_cnt) {
2627 good_mbuf_cnt--;
2628
2629 val = good_mbuf[good_mbuf_cnt];
2630 val = (val << 9) | val | 1;
2631
Michael Chan2726d6e2008-01-29 21:35:05 -08002632 bnx2_reg_wr_ind(bp, BNX2_RBUF_FW_BUF_FREE, val);
Michael Chanb6016b72005-05-26 13:03:09 -07002633 }
2634 kfree(good_mbuf);
2635 return 0;
2636}
2637
2638static void
Benjamin Li5fcaed02008-07-14 22:39:52 -07002639bnx2_set_mac_addr(struct bnx2 *bp, u8 *mac_addr, u32 pos)
Michael Chanb6016b72005-05-26 13:03:09 -07002640{
2641 u32 val;
Michael Chanb6016b72005-05-26 13:03:09 -07002642
2643 val = (mac_addr[0] << 8) | mac_addr[1];
2644
Benjamin Li5fcaed02008-07-14 22:39:52 -07002645 REG_WR(bp, BNX2_EMAC_MAC_MATCH0 + (pos * 8), val);
Michael Chanb6016b72005-05-26 13:03:09 -07002646
Jeff Garzik6aa20a22006-09-13 13:24:59 -04002647 val = (mac_addr[2] << 24) | (mac_addr[3] << 16) |
Michael Chanb6016b72005-05-26 13:03:09 -07002648 (mac_addr[4] << 8) | mac_addr[5];
2649
Benjamin Li5fcaed02008-07-14 22:39:52 -07002650 REG_WR(bp, BNX2_EMAC_MAC_MATCH1 + (pos * 8), val);
Michael Chanb6016b72005-05-26 13:03:09 -07002651}
2652
2653static inline int
Michael Chanbb4f98a2008-06-19 16:38:19 -07002654bnx2_alloc_rx_page(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr, u16 index)
Michael Chan47bf4242007-12-12 11:19:12 -08002655{
2656 dma_addr_t mapping;
Michael Chanbb4f98a2008-06-19 16:38:19 -07002657 struct sw_pg *rx_pg = &rxr->rx_pg_ring[index];
Michael Chan47bf4242007-12-12 11:19:12 -08002658 struct rx_bd *rxbd =
Michael Chanbb4f98a2008-06-19 16:38:19 -07002659 &rxr->rx_pg_desc_ring[RX_RING(index)][RX_IDX(index)];
Michael Chan47bf4242007-12-12 11:19:12 -08002660 struct page *page = alloc_page(GFP_ATOMIC);
2661
2662 if (!page)
2663 return -ENOMEM;
2664 mapping = pci_map_page(bp->pdev, page, 0, PAGE_SIZE,
2665 PCI_DMA_FROMDEVICE);
Benjamin Li3d16af82008-10-09 12:26:41 -07002666 if (pci_dma_mapping_error(bp->pdev, mapping)) {
2667 __free_page(page);
2668 return -EIO;
2669 }
2670
Michael Chan47bf4242007-12-12 11:19:12 -08002671 rx_pg->page = page;
FUJITA Tomonori1a4ccc22010-04-01 16:56:57 +00002672 dma_unmap_addr_set(rx_pg, mapping, mapping);
Michael Chan47bf4242007-12-12 11:19:12 -08002673 rxbd->rx_bd_haddr_hi = (u64) mapping >> 32;
2674 rxbd->rx_bd_haddr_lo = (u64) mapping & 0xffffffff;
2675 return 0;
2676}
2677
2678static void
Michael Chanbb4f98a2008-06-19 16:38:19 -07002679bnx2_free_rx_page(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr, u16 index)
Michael Chan47bf4242007-12-12 11:19:12 -08002680{
Michael Chanbb4f98a2008-06-19 16:38:19 -07002681 struct sw_pg *rx_pg = &rxr->rx_pg_ring[index];
Michael Chan47bf4242007-12-12 11:19:12 -08002682 struct page *page = rx_pg->page;
2683
2684 if (!page)
2685 return;
2686
FUJITA Tomonori1a4ccc22010-04-01 16:56:57 +00002687 pci_unmap_page(bp->pdev, dma_unmap_addr(rx_pg, mapping), PAGE_SIZE,
Michael Chan47bf4242007-12-12 11:19:12 -08002688 PCI_DMA_FROMDEVICE);
2689
2690 __free_page(page);
2691 rx_pg->page = NULL;
2692}
2693
2694static inline int
Michael Chanbb4f98a2008-06-19 16:38:19 -07002695bnx2_alloc_rx_skb(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr, u16 index)
Michael Chanb6016b72005-05-26 13:03:09 -07002696{
2697 struct sk_buff *skb;
Michael Chanbb4f98a2008-06-19 16:38:19 -07002698 struct sw_bd *rx_buf = &rxr->rx_buf_ring[index];
Michael Chanb6016b72005-05-26 13:03:09 -07002699 dma_addr_t mapping;
Michael Chanbb4f98a2008-06-19 16:38:19 -07002700 struct rx_bd *rxbd = &rxr->rx_desc_ring[RX_RING(index)][RX_IDX(index)];
Michael Chanb6016b72005-05-26 13:03:09 -07002701 unsigned long align;
2702
Michael Chan932f3772006-08-15 01:39:36 -07002703 skb = netdev_alloc_skb(bp->dev, bp->rx_buf_size);
Michael Chanb6016b72005-05-26 13:03:09 -07002704 if (skb == NULL) {
2705 return -ENOMEM;
2706 }
2707
Michael Chan59b47d82006-11-19 14:10:45 -08002708 if (unlikely((align = (unsigned long) skb->data & (BNX2_RX_ALIGN - 1))))
2709 skb_reserve(skb, BNX2_RX_ALIGN - align);
Michael Chanb6016b72005-05-26 13:03:09 -07002710
Michael Chanb6016b72005-05-26 13:03:09 -07002711 mapping = pci_map_single(bp->pdev, skb->data, bp->rx_buf_use_size,
2712 PCI_DMA_FROMDEVICE);
Benjamin Li3d16af82008-10-09 12:26:41 -07002713 if (pci_dma_mapping_error(bp->pdev, mapping)) {
2714 dev_kfree_skb(skb);
2715 return -EIO;
2716 }
Michael Chanb6016b72005-05-26 13:03:09 -07002717
2718 rx_buf->skb = skb;
Michael Chana33fa662010-05-06 08:58:13 +00002719 rx_buf->desc = (struct l2_fhdr *) skb->data;
FUJITA Tomonori1a4ccc22010-04-01 16:56:57 +00002720 dma_unmap_addr_set(rx_buf, mapping, mapping);
Michael Chanb6016b72005-05-26 13:03:09 -07002721
2722 rxbd->rx_bd_haddr_hi = (u64) mapping >> 32;
2723 rxbd->rx_bd_haddr_lo = (u64) mapping & 0xffffffff;
2724
Michael Chanbb4f98a2008-06-19 16:38:19 -07002725 rxr->rx_prod_bseq += bp->rx_buf_use_size;
Michael Chanb6016b72005-05-26 13:03:09 -07002726
2727 return 0;
2728}
2729
Michael Chanda3e4fb2007-05-03 13:24:23 -07002730static int
Michael Chan35efa7c2007-12-20 19:56:37 -08002731bnx2_phy_event_is_set(struct bnx2 *bp, struct bnx2_napi *bnapi, u32 event)
Michael Chanda3e4fb2007-05-03 13:24:23 -07002732{
Michael Chan43e80b82008-06-19 16:41:08 -07002733 struct status_block *sblk = bnapi->status_blk.msi;
Michael Chanda3e4fb2007-05-03 13:24:23 -07002734 u32 new_link_state, old_link_state;
2735 int is_set = 1;
2736
2737 new_link_state = sblk->status_attn_bits & event;
2738 old_link_state = sblk->status_attn_bits_ack & event;
2739 if (new_link_state != old_link_state) {
2740 if (new_link_state)
2741 REG_WR(bp, BNX2_PCICFG_STATUS_BIT_SET_CMD, event);
2742 else
2743 REG_WR(bp, BNX2_PCICFG_STATUS_BIT_CLEAR_CMD, event);
2744 } else
2745 is_set = 0;
2746
2747 return is_set;
2748}
2749
Michael Chanb6016b72005-05-26 13:03:09 -07002750static void
Michael Chan35efa7c2007-12-20 19:56:37 -08002751bnx2_phy_int(struct bnx2 *bp, struct bnx2_napi *bnapi)
Michael Chanb6016b72005-05-26 13:03:09 -07002752{
Michael Chan74ecc622008-05-02 16:56:16 -07002753 spin_lock(&bp->phy_lock);
2754
2755 if (bnx2_phy_event_is_set(bp, bnapi, STATUS_ATTN_BITS_LINK_STATE))
Michael Chanb6016b72005-05-26 13:03:09 -07002756 bnx2_set_link(bp);
Michael Chan35efa7c2007-12-20 19:56:37 -08002757 if (bnx2_phy_event_is_set(bp, bnapi, STATUS_ATTN_BITS_TIMER_ABORT))
Michael Chan0d8a6572007-07-07 22:49:43 -07002758 bnx2_set_remote_link(bp);
2759
Michael Chan74ecc622008-05-02 16:56:16 -07002760 spin_unlock(&bp->phy_lock);
2761
Michael Chanb6016b72005-05-26 13:03:09 -07002762}
2763
Michael Chanead72702007-12-20 19:55:39 -08002764static inline u16
Michael Chan35efa7c2007-12-20 19:56:37 -08002765bnx2_get_hw_tx_cons(struct bnx2_napi *bnapi)
Michael Chanead72702007-12-20 19:55:39 -08002766{
2767 u16 cons;
2768
Michael Chan43e80b82008-06-19 16:41:08 -07002769 /* Tell compiler that status block fields can change. */
2770 barrier();
2771 cons = *bnapi->hw_tx_cons_ptr;
Michael Chan581daf72009-05-06 16:46:47 -07002772 barrier();
Michael Chanead72702007-12-20 19:55:39 -08002773 if (unlikely((cons & MAX_TX_DESC_CNT) == MAX_TX_DESC_CNT))
2774 cons++;
2775 return cons;
2776}
2777
Michael Chan57851d82007-12-20 20:01:44 -08002778static int
2779bnx2_tx_int(struct bnx2 *bp, struct bnx2_napi *bnapi, int budget)
Michael Chanb6016b72005-05-26 13:03:09 -07002780{
Michael Chan35e90102008-06-19 16:37:42 -07002781 struct bnx2_tx_ring_info *txr = &bnapi->tx_ring;
Michael Chanb6016b72005-05-26 13:03:09 -07002782 u16 hw_cons, sw_cons, sw_ring_cons;
Benjamin Li706bf242008-07-18 17:55:11 -07002783 int tx_pkt = 0, index;
2784 struct netdev_queue *txq;
2785
2786 index = (bnapi - bp->bnx2_napi);
2787 txq = netdev_get_tx_queue(bp->dev, index);
Michael Chanb6016b72005-05-26 13:03:09 -07002788
Michael Chan35efa7c2007-12-20 19:56:37 -08002789 hw_cons = bnx2_get_hw_tx_cons(bnapi);
Michael Chan35e90102008-06-19 16:37:42 -07002790 sw_cons = txr->tx_cons;
Michael Chanb6016b72005-05-26 13:03:09 -07002791
2792 while (sw_cons != hw_cons) {
Benjamin Li3d16af82008-10-09 12:26:41 -07002793 struct sw_tx_bd *tx_buf;
Michael Chanb6016b72005-05-26 13:03:09 -07002794 struct sk_buff *skb;
2795 int i, last;
2796
2797 sw_ring_cons = TX_RING_IDX(sw_cons);
2798
Michael Chan35e90102008-06-19 16:37:42 -07002799 tx_buf = &txr->tx_buf_ring[sw_ring_cons];
Michael Chanb6016b72005-05-26 13:03:09 -07002800 skb = tx_buf->skb;
Arjan van de Ven1d39ed52006-12-12 14:06:23 +01002801
Eric Dumazetd62fda02009-05-12 20:48:02 +00002802 /* prefetch skb_end_pointer() to speedup skb_shinfo(skb) */
2803 prefetch(&skb->end);
2804
Michael Chanb6016b72005-05-26 13:03:09 -07002805 /* partial BD completions possible with TSO packets */
Eric Dumazetd62fda02009-05-12 20:48:02 +00002806 if (tx_buf->is_gso) {
Michael Chanb6016b72005-05-26 13:03:09 -07002807 u16 last_idx, last_ring_idx;
2808
Eric Dumazetd62fda02009-05-12 20:48:02 +00002809 last_idx = sw_cons + tx_buf->nr_frags + 1;
2810 last_ring_idx = sw_ring_cons + tx_buf->nr_frags + 1;
Michael Chanb6016b72005-05-26 13:03:09 -07002811 if (unlikely(last_ring_idx >= MAX_TX_DESC_CNT)) {
2812 last_idx++;
2813 }
2814 if (((s16) ((s16) last_idx - (s16) hw_cons)) > 0) {
2815 break;
2816 }
2817 }
Arjan van de Ven1d39ed52006-12-12 14:06:23 +01002818
FUJITA Tomonori1a4ccc22010-04-01 16:56:57 +00002819 pci_unmap_single(bp->pdev, dma_unmap_addr(tx_buf, mapping),
Alexander Duycke95524a2009-12-02 16:47:57 +00002820 skb_headlen(skb), PCI_DMA_TODEVICE);
Michael Chanb6016b72005-05-26 13:03:09 -07002821
2822 tx_buf->skb = NULL;
Eric Dumazetd62fda02009-05-12 20:48:02 +00002823 last = tx_buf->nr_frags;
Michael Chanb6016b72005-05-26 13:03:09 -07002824
2825 for (i = 0; i < last; i++) {
2826 sw_cons = NEXT_TX_BD(sw_cons);
Alexander Duycke95524a2009-12-02 16:47:57 +00002827
2828 pci_unmap_page(bp->pdev,
FUJITA Tomonori1a4ccc22010-04-01 16:56:57 +00002829 dma_unmap_addr(
Alexander Duycke95524a2009-12-02 16:47:57 +00002830 &txr->tx_buf_ring[TX_RING_IDX(sw_cons)],
2831 mapping),
2832 skb_shinfo(skb)->frags[i].size,
2833 PCI_DMA_TODEVICE);
Michael Chanb6016b72005-05-26 13:03:09 -07002834 }
2835
2836 sw_cons = NEXT_TX_BD(sw_cons);
2837
Michael Chan745720e2006-06-29 12:37:41 -07002838 dev_kfree_skb(skb);
Michael Chan57851d82007-12-20 20:01:44 -08002839 tx_pkt++;
2840 if (tx_pkt == budget)
2841 break;
Michael Chanb6016b72005-05-26 13:03:09 -07002842
Eric Dumazetd62fda02009-05-12 20:48:02 +00002843 if (hw_cons == sw_cons)
2844 hw_cons = bnx2_get_hw_tx_cons(bnapi);
Michael Chanb6016b72005-05-26 13:03:09 -07002845 }
2846
Michael Chan35e90102008-06-19 16:37:42 -07002847 txr->hw_tx_cons = hw_cons;
2848 txr->tx_cons = sw_cons;
Benjamin Li706bf242008-07-18 17:55:11 -07002849
Michael Chan2f8af122006-08-15 01:39:10 -07002850 /* Need to make the tx_cons update visible to bnx2_start_xmit()
Benjamin Li706bf242008-07-18 17:55:11 -07002851 * before checking for netif_tx_queue_stopped(). Without the
Michael Chan2f8af122006-08-15 01:39:10 -07002852 * memory barrier, there is a small possibility that bnx2_start_xmit()
2853 * will miss it and cause the queue to be stopped forever.
2854 */
2855 smp_mb();
Michael Chanb6016b72005-05-26 13:03:09 -07002856
Benjamin Li706bf242008-07-18 17:55:11 -07002857 if (unlikely(netif_tx_queue_stopped(txq)) &&
Michael Chan35e90102008-06-19 16:37:42 -07002858 (bnx2_tx_avail(bp, txr) > bp->tx_wake_thresh)) {
Benjamin Li706bf242008-07-18 17:55:11 -07002859 __netif_tx_lock(txq, smp_processor_id());
2860 if ((netif_tx_queue_stopped(txq)) &&
Michael Chan35e90102008-06-19 16:37:42 -07002861 (bnx2_tx_avail(bp, txr) > bp->tx_wake_thresh))
Benjamin Li706bf242008-07-18 17:55:11 -07002862 netif_tx_wake_queue(txq);
2863 __netif_tx_unlock(txq);
Michael Chanb6016b72005-05-26 13:03:09 -07002864 }
Benjamin Li706bf242008-07-18 17:55:11 -07002865
Michael Chan57851d82007-12-20 20:01:44 -08002866 return tx_pkt;
Michael Chanb6016b72005-05-26 13:03:09 -07002867}
2868
Michael Chan1db82f22007-12-12 11:19:35 -08002869static void
Michael Chanbb4f98a2008-06-19 16:38:19 -07002870bnx2_reuse_rx_skb_pages(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr,
Michael Chana1f60192007-12-20 19:57:19 -08002871 struct sk_buff *skb, int count)
Michael Chan1db82f22007-12-12 11:19:35 -08002872{
2873 struct sw_pg *cons_rx_pg, *prod_rx_pg;
2874 struct rx_bd *cons_bd, *prod_bd;
Michael Chan1db82f22007-12-12 11:19:35 -08002875 int i;
Benjamin Li3d16af82008-10-09 12:26:41 -07002876 u16 hw_prod, prod;
Michael Chanbb4f98a2008-06-19 16:38:19 -07002877 u16 cons = rxr->rx_pg_cons;
Michael Chan1db82f22007-12-12 11:19:35 -08002878
Benjamin Li3d16af82008-10-09 12:26:41 -07002879 cons_rx_pg = &rxr->rx_pg_ring[cons];
2880
2881 /* The caller was unable to allocate a new page to replace the
2882 * last one in the frags array, so we need to recycle that page
2883 * and then free the skb.
2884 */
2885 if (skb) {
2886 struct page *page;
2887 struct skb_shared_info *shinfo;
2888
2889 shinfo = skb_shinfo(skb);
2890 shinfo->nr_frags--;
2891 page = shinfo->frags[shinfo->nr_frags].page;
2892 shinfo->frags[shinfo->nr_frags].page = NULL;
2893
2894 cons_rx_pg->page = page;
2895 dev_kfree_skb(skb);
2896 }
2897
2898 hw_prod = rxr->rx_pg_prod;
2899
Michael Chan1db82f22007-12-12 11:19:35 -08002900 for (i = 0; i < count; i++) {
2901 prod = RX_PG_RING_IDX(hw_prod);
2902
Michael Chanbb4f98a2008-06-19 16:38:19 -07002903 prod_rx_pg = &rxr->rx_pg_ring[prod];
2904 cons_rx_pg = &rxr->rx_pg_ring[cons];
2905 cons_bd = &rxr->rx_pg_desc_ring[RX_RING(cons)][RX_IDX(cons)];
2906 prod_bd = &rxr->rx_pg_desc_ring[RX_RING(prod)][RX_IDX(prod)];
Michael Chan1db82f22007-12-12 11:19:35 -08002907
Michael Chan1db82f22007-12-12 11:19:35 -08002908 if (prod != cons) {
2909 prod_rx_pg->page = cons_rx_pg->page;
2910 cons_rx_pg->page = NULL;
FUJITA Tomonori1a4ccc22010-04-01 16:56:57 +00002911 dma_unmap_addr_set(prod_rx_pg, mapping,
2912 dma_unmap_addr(cons_rx_pg, mapping));
Michael Chan1db82f22007-12-12 11:19:35 -08002913
2914 prod_bd->rx_bd_haddr_hi = cons_bd->rx_bd_haddr_hi;
2915 prod_bd->rx_bd_haddr_lo = cons_bd->rx_bd_haddr_lo;
2916
2917 }
2918 cons = RX_PG_RING_IDX(NEXT_RX_BD(cons));
2919 hw_prod = NEXT_RX_BD(hw_prod);
2920 }
Michael Chanbb4f98a2008-06-19 16:38:19 -07002921 rxr->rx_pg_prod = hw_prod;
2922 rxr->rx_pg_cons = cons;
Michael Chan1db82f22007-12-12 11:19:35 -08002923}
2924
Michael Chanb6016b72005-05-26 13:03:09 -07002925static inline void
Michael Chanbb4f98a2008-06-19 16:38:19 -07002926bnx2_reuse_rx_skb(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr,
2927 struct sk_buff *skb, u16 cons, u16 prod)
Michael Chanb6016b72005-05-26 13:03:09 -07002928{
Michael Chan236b6392006-03-20 17:49:02 -08002929 struct sw_bd *cons_rx_buf, *prod_rx_buf;
2930 struct rx_bd *cons_bd, *prod_bd;
2931
Michael Chanbb4f98a2008-06-19 16:38:19 -07002932 cons_rx_buf = &rxr->rx_buf_ring[cons];
2933 prod_rx_buf = &rxr->rx_buf_ring[prod];
Michael Chanb6016b72005-05-26 13:03:09 -07002934
2935 pci_dma_sync_single_for_device(bp->pdev,
FUJITA Tomonori1a4ccc22010-04-01 16:56:57 +00002936 dma_unmap_addr(cons_rx_buf, mapping),
Benjamin Li601d3d12008-05-16 22:19:35 -07002937 BNX2_RX_OFFSET + BNX2_RX_COPY_THRESH, PCI_DMA_FROMDEVICE);
Michael Chanb6016b72005-05-26 13:03:09 -07002938
Michael Chanbb4f98a2008-06-19 16:38:19 -07002939 rxr->rx_prod_bseq += bp->rx_buf_use_size;
Michael Chan236b6392006-03-20 17:49:02 -08002940
2941 prod_rx_buf->skb = skb;
Michael Chana33fa662010-05-06 08:58:13 +00002942 prod_rx_buf->desc = (struct l2_fhdr *) skb->data;
Michael Chan236b6392006-03-20 17:49:02 -08002943
2944 if (cons == prod)
2945 return;
2946
FUJITA Tomonori1a4ccc22010-04-01 16:56:57 +00002947 dma_unmap_addr_set(prod_rx_buf, mapping,
2948 dma_unmap_addr(cons_rx_buf, mapping));
Michael Chanb6016b72005-05-26 13:03:09 -07002949
Michael Chanbb4f98a2008-06-19 16:38:19 -07002950 cons_bd = &rxr->rx_desc_ring[RX_RING(cons)][RX_IDX(cons)];
2951 prod_bd = &rxr->rx_desc_ring[RX_RING(prod)][RX_IDX(prod)];
Michael Chan236b6392006-03-20 17:49:02 -08002952 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;
Michael Chanb6016b72005-05-26 13:03:09 -07002954}
2955
Michael Chan85833c62007-12-12 11:17:01 -08002956static int
Michael Chanbb4f98a2008-06-19 16:38:19 -07002957bnx2_rx_skb(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr, struct sk_buff *skb,
Michael Chana1f60192007-12-20 19:57:19 -08002958 unsigned int len, unsigned int hdr_len, dma_addr_t dma_addr,
2959 u32 ring_idx)
Michael Chan85833c62007-12-12 11:17:01 -08002960{
2961 int err;
2962 u16 prod = ring_idx & 0xffff;
2963
Michael Chanbb4f98a2008-06-19 16:38:19 -07002964 err = bnx2_alloc_rx_skb(bp, rxr, prod);
Michael Chan85833c62007-12-12 11:17:01 -08002965 if (unlikely(err)) {
Michael Chanbb4f98a2008-06-19 16:38:19 -07002966 bnx2_reuse_rx_skb(bp, rxr, skb, (u16) (ring_idx >> 16), prod);
Michael Chan1db82f22007-12-12 11:19:35 -08002967 if (hdr_len) {
2968 unsigned int raw_len = len + 4;
2969 int pages = PAGE_ALIGN(raw_len - hdr_len) >> PAGE_SHIFT;
2970
Michael Chanbb4f98a2008-06-19 16:38:19 -07002971 bnx2_reuse_rx_skb_pages(bp, rxr, NULL, pages);
Michael Chan1db82f22007-12-12 11:19:35 -08002972 }
Michael Chan85833c62007-12-12 11:17:01 -08002973 return err;
2974 }
2975
Benjamin Lid89cb6a2008-05-16 22:18:57 -07002976 skb_reserve(skb, BNX2_RX_OFFSET);
Michael Chan85833c62007-12-12 11:17:01 -08002977 pci_unmap_single(bp->pdev, dma_addr, bp->rx_buf_use_size,
2978 PCI_DMA_FROMDEVICE);
2979
Michael Chan1db82f22007-12-12 11:19:35 -08002980 if (hdr_len == 0) {
2981 skb_put(skb, len);
2982 return 0;
2983 } else {
2984 unsigned int i, frag_len, frag_size, pages;
2985 struct sw_pg *rx_pg;
Michael Chanbb4f98a2008-06-19 16:38:19 -07002986 u16 pg_cons = rxr->rx_pg_cons;
2987 u16 pg_prod = rxr->rx_pg_prod;
Michael Chan1db82f22007-12-12 11:19:35 -08002988
2989 frag_size = len + 4 - hdr_len;
2990 pages = PAGE_ALIGN(frag_size) >> PAGE_SHIFT;
2991 skb_put(skb, hdr_len);
2992
2993 for (i = 0; i < pages; i++) {
Benjamin Li3d16af82008-10-09 12:26:41 -07002994 dma_addr_t mapping_old;
2995
Michael Chan1db82f22007-12-12 11:19:35 -08002996 frag_len = min(frag_size, (unsigned int) PAGE_SIZE);
2997 if (unlikely(frag_len <= 4)) {
2998 unsigned int tail = 4 - frag_len;
2999
Michael Chanbb4f98a2008-06-19 16:38:19 -07003000 rxr->rx_pg_cons = pg_cons;
3001 rxr->rx_pg_prod = pg_prod;
3002 bnx2_reuse_rx_skb_pages(bp, rxr, NULL,
Michael Chana1f60192007-12-20 19:57:19 -08003003 pages - i);
Michael Chan1db82f22007-12-12 11:19:35 -08003004 skb->len -= tail;
3005 if (i == 0) {
3006 skb->tail -= tail;
3007 } else {
3008 skb_frag_t *frag =
3009 &skb_shinfo(skb)->frags[i - 1];
3010 frag->size -= tail;
3011 skb->data_len -= tail;
3012 skb->truesize -= tail;
3013 }
3014 return 0;
3015 }
Michael Chanbb4f98a2008-06-19 16:38:19 -07003016 rx_pg = &rxr->rx_pg_ring[pg_cons];
Michael Chan1db82f22007-12-12 11:19:35 -08003017
Benjamin Li3d16af82008-10-09 12:26:41 -07003018 /* Don't unmap yet. If we're unable to allocate a new
3019 * page, we need to recycle the page and the DMA addr.
3020 */
FUJITA Tomonori1a4ccc22010-04-01 16:56:57 +00003021 mapping_old = dma_unmap_addr(rx_pg, mapping);
Michael Chan1db82f22007-12-12 11:19:35 -08003022 if (i == pages - 1)
3023 frag_len -= 4;
3024
3025 skb_fill_page_desc(skb, i, rx_pg->page, 0, frag_len);
3026 rx_pg->page = NULL;
3027
Michael Chanbb4f98a2008-06-19 16:38:19 -07003028 err = bnx2_alloc_rx_page(bp, rxr,
3029 RX_PG_RING_IDX(pg_prod));
Michael Chan1db82f22007-12-12 11:19:35 -08003030 if (unlikely(err)) {
Michael Chanbb4f98a2008-06-19 16:38:19 -07003031 rxr->rx_pg_cons = pg_cons;
3032 rxr->rx_pg_prod = pg_prod;
3033 bnx2_reuse_rx_skb_pages(bp, rxr, skb,
Michael Chana1f60192007-12-20 19:57:19 -08003034 pages - i);
Michael Chan1db82f22007-12-12 11:19:35 -08003035 return err;
3036 }
3037
Benjamin Li3d16af82008-10-09 12:26:41 -07003038 pci_unmap_page(bp->pdev, mapping_old,
3039 PAGE_SIZE, PCI_DMA_FROMDEVICE);
3040
Michael Chan1db82f22007-12-12 11:19:35 -08003041 frag_size -= frag_len;
3042 skb->data_len += frag_len;
3043 skb->truesize += frag_len;
3044 skb->len += frag_len;
3045
3046 pg_prod = NEXT_RX_BD(pg_prod);
3047 pg_cons = RX_PG_RING_IDX(NEXT_RX_BD(pg_cons));
3048 }
Michael Chanbb4f98a2008-06-19 16:38:19 -07003049 rxr->rx_pg_prod = pg_prod;
3050 rxr->rx_pg_cons = pg_cons;
Michael Chan1db82f22007-12-12 11:19:35 -08003051 }
Michael Chan85833c62007-12-12 11:17:01 -08003052 return 0;
3053}
3054
Michael Chanc09c2622007-12-10 17:18:37 -08003055static inline u16
Michael Chan35efa7c2007-12-20 19:56:37 -08003056bnx2_get_hw_rx_cons(struct bnx2_napi *bnapi)
Michael Chanc09c2622007-12-10 17:18:37 -08003057{
Michael Chanbb4f98a2008-06-19 16:38:19 -07003058 u16 cons;
3059
Michael Chan43e80b82008-06-19 16:41:08 -07003060 /* Tell compiler that status block fields can change. */
3061 barrier();
3062 cons = *bnapi->hw_rx_cons_ptr;
Michael Chan581daf72009-05-06 16:46:47 -07003063 barrier();
Michael Chanc09c2622007-12-10 17:18:37 -08003064 if (unlikely((cons & MAX_RX_DESC_CNT) == MAX_RX_DESC_CNT))
3065 cons++;
3066 return cons;
3067}
3068
Michael Chanb6016b72005-05-26 13:03:09 -07003069static int
Michael Chan35efa7c2007-12-20 19:56:37 -08003070bnx2_rx_int(struct bnx2 *bp, struct bnx2_napi *bnapi, int budget)
Michael Chanb6016b72005-05-26 13:03:09 -07003071{
Michael Chanbb4f98a2008-06-19 16:38:19 -07003072 struct bnx2_rx_ring_info *rxr = &bnapi->rx_ring;
Michael Chanb6016b72005-05-26 13:03:09 -07003073 u16 hw_cons, sw_cons, sw_ring_cons, sw_prod, sw_ring_prod;
3074 struct l2_fhdr *rx_hdr;
Michael Chan1db82f22007-12-12 11:19:35 -08003075 int rx_pkt = 0, pg_ring_used = 0;
Michael Chana33fa662010-05-06 08:58:13 +00003076 struct pci_dev *pdev = bp->pdev;
Michael Chanb6016b72005-05-26 13:03:09 -07003077
Michael Chan35efa7c2007-12-20 19:56:37 -08003078 hw_cons = bnx2_get_hw_rx_cons(bnapi);
Michael Chanbb4f98a2008-06-19 16:38:19 -07003079 sw_cons = rxr->rx_cons;
3080 sw_prod = rxr->rx_prod;
Michael Chanb6016b72005-05-26 13:03:09 -07003081
3082 /* Memory barrier necessary as speculative reads of the rx
3083 * buffer can be ahead of the index in the status block
3084 */
3085 rmb();
3086 while (sw_cons != hw_cons) {
Michael Chan1db82f22007-12-12 11:19:35 -08003087 unsigned int len, hdr_len;
Michael Chanade2bfe2006-01-23 16:09:51 -08003088 u32 status;
Michael Chana33fa662010-05-06 08:58:13 +00003089 struct sw_bd *rx_buf, *next_rx_buf;
Michael Chanb6016b72005-05-26 13:03:09 -07003090 struct sk_buff *skb;
Michael Chan236b6392006-03-20 17:49:02 -08003091 dma_addr_t dma_addr;
Michael Chanf22828e2008-08-14 15:30:14 -07003092 u16 vtag = 0;
3093 int hw_vlan __maybe_unused = 0;
Michael Chanb6016b72005-05-26 13:03:09 -07003094
3095 sw_ring_cons = RX_RING_IDX(sw_cons);
3096 sw_ring_prod = RX_RING_IDX(sw_prod);
3097
Michael Chanbb4f98a2008-06-19 16:38:19 -07003098 rx_buf = &rxr->rx_buf_ring[sw_ring_cons];
Michael Chanb6016b72005-05-26 13:03:09 -07003099 skb = rx_buf->skb;
Michael Chana33fa662010-05-06 08:58:13 +00003100 prefetchw(skb);
Michael Chan236b6392006-03-20 17:49:02 -08003101
Michael Chana33fa662010-05-06 08:58:13 +00003102 if (!get_dma_ops(&pdev->dev)->sync_single_for_cpu) {
3103 next_rx_buf =
3104 &rxr->rx_buf_ring[
3105 RX_RING_IDX(NEXT_RX_BD(sw_cons))];
3106 prefetch(next_rx_buf->desc);
3107 }
Michael Chan236b6392006-03-20 17:49:02 -08003108 rx_buf->skb = NULL;
3109
FUJITA Tomonori1a4ccc22010-04-01 16:56:57 +00003110 dma_addr = dma_unmap_addr(rx_buf, mapping);
Michael Chan236b6392006-03-20 17:49:02 -08003111
3112 pci_dma_sync_single_for_cpu(bp->pdev, dma_addr,
Benjamin Li601d3d12008-05-16 22:19:35 -07003113 BNX2_RX_OFFSET + BNX2_RX_COPY_THRESH,
3114 PCI_DMA_FROMDEVICE);
Michael Chanb6016b72005-05-26 13:03:09 -07003115
Michael Chana33fa662010-05-06 08:58:13 +00003116 rx_hdr = rx_buf->desc;
Michael Chan1db82f22007-12-12 11:19:35 -08003117 len = rx_hdr->l2_fhdr_pkt_len;
Michael Chan990ec382009-02-12 16:54:13 -08003118 status = rx_hdr->l2_fhdr_status;
Michael Chanb6016b72005-05-26 13:03:09 -07003119
Michael Chan1db82f22007-12-12 11:19:35 -08003120 hdr_len = 0;
3121 if (status & L2_FHDR_STATUS_SPLIT) {
3122 hdr_len = rx_hdr->l2_fhdr_ip_xsum;
3123 pg_ring_used = 1;
3124 } else if (len > bp->rx_jumbo_thresh) {
3125 hdr_len = bp->rx_jumbo_thresh;
3126 pg_ring_used = 1;
3127 }
3128
Michael Chan990ec382009-02-12 16:54:13 -08003129 if (unlikely(status & (L2_FHDR_ERRORS_BAD_CRC |
3130 L2_FHDR_ERRORS_PHY_DECODE |
3131 L2_FHDR_ERRORS_ALIGNMENT |
3132 L2_FHDR_ERRORS_TOO_SHORT |
3133 L2_FHDR_ERRORS_GIANT_FRAME))) {
3134
3135 bnx2_reuse_rx_skb(bp, rxr, skb, sw_ring_cons,
3136 sw_ring_prod);
3137 if (pg_ring_used) {
3138 int pages;
3139
3140 pages = PAGE_ALIGN(len - hdr_len) >> PAGE_SHIFT;
3141
3142 bnx2_reuse_rx_skb_pages(bp, rxr, NULL, pages);
3143 }
3144 goto next_rx;
3145 }
3146
Michael Chan1db82f22007-12-12 11:19:35 -08003147 len -= 4;
Michael Chanb6016b72005-05-26 13:03:09 -07003148
Michael Chan5d5d0012007-12-12 11:17:43 -08003149 if (len <= bp->rx_copy_thresh) {
Michael Chanb6016b72005-05-26 13:03:09 -07003150 struct sk_buff *new_skb;
3151
Michael Chanf22828e2008-08-14 15:30:14 -07003152 new_skb = netdev_alloc_skb(bp->dev, len + 6);
Michael Chan85833c62007-12-12 11:17:01 -08003153 if (new_skb == NULL) {
Michael Chanbb4f98a2008-06-19 16:38:19 -07003154 bnx2_reuse_rx_skb(bp, rxr, skb, sw_ring_cons,
Michael Chan85833c62007-12-12 11:17:01 -08003155 sw_ring_prod);
3156 goto next_rx;
3157 }
Michael Chanb6016b72005-05-26 13:03:09 -07003158
3159 /* aligned copy */
Benjamin Lid89cb6a2008-05-16 22:18:57 -07003160 skb_copy_from_linear_data_offset(skb,
Michael Chanf22828e2008-08-14 15:30:14 -07003161 BNX2_RX_OFFSET - 6,
3162 new_skb->data, len + 6);
3163 skb_reserve(new_skb, 6);
Michael Chanb6016b72005-05-26 13:03:09 -07003164 skb_put(new_skb, len);
Michael Chanb6016b72005-05-26 13:03:09 -07003165
Michael Chanbb4f98a2008-06-19 16:38:19 -07003166 bnx2_reuse_rx_skb(bp, rxr, skb,
Michael Chanb6016b72005-05-26 13:03:09 -07003167 sw_ring_cons, sw_ring_prod);
3168
3169 skb = new_skb;
Michael Chanbb4f98a2008-06-19 16:38:19 -07003170 } else if (unlikely(bnx2_rx_skb(bp, rxr, skb, len, hdr_len,
Michael Chana1f60192007-12-20 19:57:19 -08003171 dma_addr, (sw_ring_cons << 16) | sw_ring_prod)))
Michael Chanb6016b72005-05-26 13:03:09 -07003172 goto next_rx;
Michael Chanb6016b72005-05-26 13:03:09 -07003173
Michael Chanf22828e2008-08-14 15:30:14 -07003174 if ((status & L2_FHDR_STATUS_L2_VLAN_TAG) &&
3175 !(bp->rx_mode & BNX2_EMAC_RX_MODE_KEEP_VLAN_TAG)) {
3176 vtag = rx_hdr->l2_fhdr_vlan_tag;
3177#ifdef BCM_VLAN
3178 if (bp->vlgrp)
3179 hw_vlan = 1;
3180 else
3181#endif
3182 {
3183 struct vlan_ethhdr *ve = (struct vlan_ethhdr *)
3184 __skb_push(skb, 4);
3185
3186 memmove(ve, skb->data + 4, ETH_ALEN * 2);
3187 ve->h_vlan_proto = htons(ETH_P_8021Q);
3188 ve->h_vlan_TCI = htons(vtag);
3189 len += 4;
3190 }
3191 }
3192
Michael Chanb6016b72005-05-26 13:03:09 -07003193 skb->protocol = eth_type_trans(skb, bp->dev);
3194
3195 if ((len > (bp->dev->mtu + ETH_HLEN)) &&
Alexey Dobriyand1e100b2006-06-11 20:57:17 -07003196 (ntohs(skb->protocol) != 0x8100)) {
Michael Chanb6016b72005-05-26 13:03:09 -07003197
Michael Chan745720e2006-06-29 12:37:41 -07003198 dev_kfree_skb(skb);
Michael Chanb6016b72005-05-26 13:03:09 -07003199 goto next_rx;
3200
3201 }
3202
Michael Chanb6016b72005-05-26 13:03:09 -07003203 skb->ip_summed = CHECKSUM_NONE;
3204 if (bp->rx_csum &&
3205 (status & (L2_FHDR_STATUS_TCP_SEGMENT |
3206 L2_FHDR_STATUS_UDP_DATAGRAM))) {
3207
Michael Chanade2bfe2006-01-23 16:09:51 -08003208 if (likely((status & (L2_FHDR_ERRORS_TCP_XSUM |
3209 L2_FHDR_ERRORS_UDP_XSUM)) == 0))
Michael Chanb6016b72005-05-26 13:03:09 -07003210 skb->ip_summed = CHECKSUM_UNNECESSARY;
3211 }
3212
David S. Miller0c8dfc82009-01-27 16:22:32 -08003213 skb_record_rx_queue(skb, bnapi - &bp->bnx2_napi[0]);
3214
Michael Chanb6016b72005-05-26 13:03:09 -07003215#ifdef BCM_VLAN
Michael Chanf22828e2008-08-14 15:30:14 -07003216 if (hw_vlan)
Michael Chanc67938a2010-05-06 08:58:12 +00003217 vlan_gro_receive(&bnapi->napi, bp->vlgrp, vtag, skb);
Michael Chanb6016b72005-05-26 13:03:09 -07003218 else
3219#endif
Michael Chanc67938a2010-05-06 08:58:12 +00003220 napi_gro_receive(&bnapi->napi, skb);
Michael Chanb6016b72005-05-26 13:03:09 -07003221
Michael Chanb6016b72005-05-26 13:03:09 -07003222 rx_pkt++;
3223
3224next_rx:
Michael Chanb6016b72005-05-26 13:03:09 -07003225 sw_cons = NEXT_RX_BD(sw_cons);
3226 sw_prod = NEXT_RX_BD(sw_prod);
3227
3228 if ((rx_pkt == budget))
3229 break;
Michael Chanf4e418f2005-11-04 08:53:48 -08003230
3231 /* Refresh hw_cons to see if there is new work */
3232 if (sw_cons == hw_cons) {
Michael Chan35efa7c2007-12-20 19:56:37 -08003233 hw_cons = bnx2_get_hw_rx_cons(bnapi);
Michael Chanf4e418f2005-11-04 08:53:48 -08003234 rmb();
3235 }
Michael Chanb6016b72005-05-26 13:03:09 -07003236 }
Michael Chanbb4f98a2008-06-19 16:38:19 -07003237 rxr->rx_cons = sw_cons;
3238 rxr->rx_prod = sw_prod;
Michael Chanb6016b72005-05-26 13:03:09 -07003239
Michael Chan1db82f22007-12-12 11:19:35 -08003240 if (pg_ring_used)
Michael Chanbb4f98a2008-06-19 16:38:19 -07003241 REG_WR16(bp, rxr->rx_pg_bidx_addr, rxr->rx_pg_prod);
Michael Chan1db82f22007-12-12 11:19:35 -08003242
Michael Chanbb4f98a2008-06-19 16:38:19 -07003243 REG_WR16(bp, rxr->rx_bidx_addr, sw_prod);
Michael Chanb6016b72005-05-26 13:03:09 -07003244
Michael Chanbb4f98a2008-06-19 16:38:19 -07003245 REG_WR(bp, rxr->rx_bseq_addr, rxr->rx_prod_bseq);
Michael Chanb6016b72005-05-26 13:03:09 -07003246
3247 mmiowb();
3248
3249 return rx_pkt;
3250
3251}
3252
3253/* MSI ISR - The only difference between this and the INTx ISR
3254 * is that the MSI interrupt is always serviced.
3255 */
3256static irqreturn_t
David Howells7d12e782006-10-05 14:55:46 +01003257bnx2_msi(int irq, void *dev_instance)
Michael Chanb6016b72005-05-26 13:03:09 -07003258{
Michael Chanf0ea2e62008-06-19 16:41:57 -07003259 struct bnx2_napi *bnapi = dev_instance;
3260 struct bnx2 *bp = bnapi->bp;
Michael Chanb6016b72005-05-26 13:03:09 -07003261
Michael Chan43e80b82008-06-19 16:41:08 -07003262 prefetch(bnapi->status_blk.msi);
Michael Chanb6016b72005-05-26 13:03:09 -07003263 REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
3264 BNX2_PCICFG_INT_ACK_CMD_USE_INT_HC_PARAM |
3265 BNX2_PCICFG_INT_ACK_CMD_MASK_INT);
3266
3267 /* Return here if interrupt is disabled. */
Michael Chan73eef4c2005-08-25 15:39:15 -07003268 if (unlikely(atomic_read(&bp->intr_sem) != 0))
3269 return IRQ_HANDLED;
Michael Chanb6016b72005-05-26 13:03:09 -07003270
Ben Hutchings288379f2009-01-19 16:43:59 -08003271 napi_schedule(&bnapi->napi);
Michael Chanb6016b72005-05-26 13:03:09 -07003272
Michael Chan73eef4c2005-08-25 15:39:15 -07003273 return IRQ_HANDLED;
Michael Chanb6016b72005-05-26 13:03:09 -07003274}
3275
3276static irqreturn_t
Michael Chan8e6a72c2007-05-03 13:24:48 -07003277bnx2_msi_1shot(int irq, void *dev_instance)
3278{
Michael Chanf0ea2e62008-06-19 16:41:57 -07003279 struct bnx2_napi *bnapi = dev_instance;
3280 struct bnx2 *bp = bnapi->bp;
Michael Chan8e6a72c2007-05-03 13:24:48 -07003281
Michael Chan43e80b82008-06-19 16:41:08 -07003282 prefetch(bnapi->status_blk.msi);
Michael Chan8e6a72c2007-05-03 13:24:48 -07003283
3284 /* Return here if interrupt is disabled. */
3285 if (unlikely(atomic_read(&bp->intr_sem) != 0))
3286 return IRQ_HANDLED;
3287
Ben Hutchings288379f2009-01-19 16:43:59 -08003288 napi_schedule(&bnapi->napi);
Michael Chan8e6a72c2007-05-03 13:24:48 -07003289
3290 return IRQ_HANDLED;
3291}
3292
3293static irqreturn_t
David Howells7d12e782006-10-05 14:55:46 +01003294bnx2_interrupt(int irq, void *dev_instance)
Michael Chanb6016b72005-05-26 13:03:09 -07003295{
Michael Chanf0ea2e62008-06-19 16:41:57 -07003296 struct bnx2_napi *bnapi = dev_instance;
3297 struct bnx2 *bp = bnapi->bp;
Michael Chan43e80b82008-06-19 16:41:08 -07003298 struct status_block *sblk = bnapi->status_blk.msi;
Michael Chanb6016b72005-05-26 13:03:09 -07003299
3300 /* When using INTx, it is possible for the interrupt to arrive
3301 * at the CPU before the status block posted prior to the
3302 * interrupt. Reading a register will flush the status block.
3303 * When using MSI, the MSI message will always complete after
3304 * the status block write.
3305 */
Michael Chan35efa7c2007-12-20 19:56:37 -08003306 if ((sblk->status_idx == bnapi->last_status_idx) &&
Michael Chanb6016b72005-05-26 13:03:09 -07003307 (REG_RD(bp, BNX2_PCICFG_MISC_STATUS) &
3308 BNX2_PCICFG_MISC_STATUS_INTA_VALUE))
Michael Chan73eef4c2005-08-25 15:39:15 -07003309 return IRQ_NONE;
Michael Chanb6016b72005-05-26 13:03:09 -07003310
3311 REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
3312 BNX2_PCICFG_INT_ACK_CMD_USE_INT_HC_PARAM |
3313 BNX2_PCICFG_INT_ACK_CMD_MASK_INT);
3314
Michael Chanb8a7ce72007-07-07 22:51:03 -07003315 /* Read back to deassert IRQ immediately to avoid too many
3316 * spurious interrupts.
3317 */
3318 REG_RD(bp, BNX2_PCICFG_INT_ACK_CMD);
3319
Michael Chanb6016b72005-05-26 13:03:09 -07003320 /* Return here if interrupt is shared and is disabled. */
Michael Chan73eef4c2005-08-25 15:39:15 -07003321 if (unlikely(atomic_read(&bp->intr_sem) != 0))
3322 return IRQ_HANDLED;
Michael Chanb6016b72005-05-26 13:03:09 -07003323
Ben Hutchings288379f2009-01-19 16:43:59 -08003324 if (napi_schedule_prep(&bnapi->napi)) {
Michael Chan35efa7c2007-12-20 19:56:37 -08003325 bnapi->last_status_idx = sblk->status_idx;
Ben Hutchings288379f2009-01-19 16:43:59 -08003326 __napi_schedule(&bnapi->napi);
Michael Chanb8a7ce72007-07-07 22:51:03 -07003327 }
Michael Chanb6016b72005-05-26 13:03:09 -07003328
Michael Chan73eef4c2005-08-25 15:39:15 -07003329 return IRQ_HANDLED;
Michael Chanb6016b72005-05-26 13:03:09 -07003330}
3331
Michael Chan43e80b82008-06-19 16:41:08 -07003332static inline int
3333bnx2_has_fast_work(struct bnx2_napi *bnapi)
3334{
3335 struct bnx2_tx_ring_info *txr = &bnapi->tx_ring;
3336 struct bnx2_rx_ring_info *rxr = &bnapi->rx_ring;
3337
3338 if ((bnx2_get_hw_rx_cons(bnapi) != rxr->rx_cons) ||
3339 (bnx2_get_hw_tx_cons(bnapi) != txr->hw_tx_cons))
3340 return 1;
3341 return 0;
3342}
3343
Michael Chan0d8a6572007-07-07 22:49:43 -07003344#define STATUS_ATTN_EVENTS (STATUS_ATTN_BITS_LINK_STATE | \
3345 STATUS_ATTN_BITS_TIMER_ABORT)
Michael Chanda3e4fb2007-05-03 13:24:23 -07003346
Michael Chanf4e418f2005-11-04 08:53:48 -08003347static inline int
Michael Chan35efa7c2007-12-20 19:56:37 -08003348bnx2_has_work(struct bnx2_napi *bnapi)
Michael Chanf4e418f2005-11-04 08:53:48 -08003349{
Michael Chan43e80b82008-06-19 16:41:08 -07003350 struct status_block *sblk = bnapi->status_blk.msi;
Michael Chanf4e418f2005-11-04 08:53:48 -08003351
Michael Chan43e80b82008-06-19 16:41:08 -07003352 if (bnx2_has_fast_work(bnapi))
Michael Chanf4e418f2005-11-04 08:53:48 -08003353 return 1;
3354
Michael Chan4edd4732009-06-08 18:14:42 -07003355#ifdef BCM_CNIC
3356 if (bnapi->cnic_present && (bnapi->cnic_tag != sblk->status_idx))
3357 return 1;
3358#endif
3359
Michael Chanda3e4fb2007-05-03 13:24:23 -07003360 if ((sblk->status_attn_bits & STATUS_ATTN_EVENTS) !=
3361 (sblk->status_attn_bits_ack & STATUS_ATTN_EVENTS))
Michael Chanf4e418f2005-11-04 08:53:48 -08003362 return 1;
3363
3364 return 0;
3365}
3366
Michael Chanefba0182008-12-03 00:36:15 -08003367static void
3368bnx2_chk_missed_msi(struct bnx2 *bp)
3369{
3370 struct bnx2_napi *bnapi = &bp->bnx2_napi[0];
3371 u32 msi_ctrl;
3372
3373 if (bnx2_has_work(bnapi)) {
3374 msi_ctrl = REG_RD(bp, BNX2_PCICFG_MSI_CONTROL);
3375 if (!(msi_ctrl & BNX2_PCICFG_MSI_CONTROL_ENABLE))
3376 return;
3377
3378 if (bnapi->last_status_idx == bp->idle_chk_status_idx) {
3379 REG_WR(bp, BNX2_PCICFG_MSI_CONTROL, msi_ctrl &
3380 ~BNX2_PCICFG_MSI_CONTROL_ENABLE);
3381 REG_WR(bp, BNX2_PCICFG_MSI_CONTROL, msi_ctrl);
3382 bnx2_msi(bp->irq_tbl[0].vector, bnapi);
3383 }
3384 }
3385
3386 bp->idle_chk_status_idx = bnapi->last_status_idx;
3387}
3388
Michael Chan4edd4732009-06-08 18:14:42 -07003389#ifdef BCM_CNIC
3390static void bnx2_poll_cnic(struct bnx2 *bp, struct bnx2_napi *bnapi)
3391{
3392 struct cnic_ops *c_ops;
3393
3394 if (!bnapi->cnic_present)
3395 return;
3396
3397 rcu_read_lock();
3398 c_ops = rcu_dereference(bp->cnic_ops);
3399 if (c_ops)
3400 bnapi->cnic_tag = c_ops->cnic_handler(bp->cnic_data,
3401 bnapi->status_blk.msi);
3402 rcu_read_unlock();
3403}
3404#endif
3405
Michael Chan43e80b82008-06-19 16:41:08 -07003406static void bnx2_poll_link(struct bnx2 *bp, struct bnx2_napi *bnapi)
Michael Chanb6016b72005-05-26 13:03:09 -07003407{
Michael Chan43e80b82008-06-19 16:41:08 -07003408 struct status_block *sblk = bnapi->status_blk.msi;
Michael Chanda3e4fb2007-05-03 13:24:23 -07003409 u32 status_attn_bits = sblk->status_attn_bits;
3410 u32 status_attn_bits_ack = sblk->status_attn_bits_ack;
Michael Chanb6016b72005-05-26 13:03:09 -07003411
Michael Chanda3e4fb2007-05-03 13:24:23 -07003412 if ((status_attn_bits & STATUS_ATTN_EVENTS) !=
3413 (status_attn_bits_ack & STATUS_ATTN_EVENTS)) {
Michael Chanb6016b72005-05-26 13:03:09 -07003414
Michael Chan35efa7c2007-12-20 19:56:37 -08003415 bnx2_phy_int(bp, bnapi);
Michael Chanbf5295b2006-03-23 01:11:56 -08003416
3417 /* This is needed to take care of transient status
3418 * during link changes.
3419 */
3420 REG_WR(bp, BNX2_HC_COMMAND,
3421 bp->hc_cmd | BNX2_HC_COMMAND_COAL_NOW_WO_INT);
3422 REG_RD(bp, BNX2_HC_COMMAND);
Michael Chanb6016b72005-05-26 13:03:09 -07003423 }
Michael Chan43e80b82008-06-19 16:41:08 -07003424}
3425
3426static int bnx2_poll_work(struct bnx2 *bp, struct bnx2_napi *bnapi,
3427 int work_done, int budget)
3428{
3429 struct bnx2_tx_ring_info *txr = &bnapi->tx_ring;
3430 struct bnx2_rx_ring_info *rxr = &bnapi->rx_ring;
Michael Chanb6016b72005-05-26 13:03:09 -07003431
Michael Chan35e90102008-06-19 16:37:42 -07003432 if (bnx2_get_hw_tx_cons(bnapi) != txr->hw_tx_cons)
Michael Chan57851d82007-12-20 20:01:44 -08003433 bnx2_tx_int(bp, bnapi, 0);
Michael Chanb6016b72005-05-26 13:03:09 -07003434
Michael Chanbb4f98a2008-06-19 16:38:19 -07003435 if (bnx2_get_hw_rx_cons(bnapi) != rxr->rx_cons)
Michael Chan35efa7c2007-12-20 19:56:37 -08003436 work_done += bnx2_rx_int(bp, bnapi, budget - work_done);
Jeff Garzik6aa20a22006-09-13 13:24:59 -04003437
David S. Miller6f535762007-10-11 18:08:29 -07003438 return work_done;
3439}
Michael Chanf4e418f2005-11-04 08:53:48 -08003440
Michael Chanf0ea2e62008-06-19 16:41:57 -07003441static int bnx2_poll_msix(struct napi_struct *napi, int budget)
3442{
3443 struct bnx2_napi *bnapi = container_of(napi, struct bnx2_napi, napi);
3444 struct bnx2 *bp = bnapi->bp;
3445 int work_done = 0;
3446 struct status_block_msix *sblk = bnapi->status_blk.msix;
3447
3448 while (1) {
3449 work_done = bnx2_poll_work(bp, bnapi, work_done, budget);
3450 if (unlikely(work_done >= budget))
3451 break;
3452
3453 bnapi->last_status_idx = sblk->status_idx;
3454 /* status idx must be read before checking for more work. */
3455 rmb();
3456 if (likely(!bnx2_has_fast_work(bnapi))) {
3457
Ben Hutchings288379f2009-01-19 16:43:59 -08003458 napi_complete(napi);
Michael Chanf0ea2e62008-06-19 16:41:57 -07003459 REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD, bnapi->int_num |
3460 BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
3461 bnapi->last_status_idx);
3462 break;
3463 }
3464 }
3465 return work_done;
3466}
3467
David S. Miller6f535762007-10-11 18:08:29 -07003468static int bnx2_poll(struct napi_struct *napi, int budget)
3469{
Michael Chan35efa7c2007-12-20 19:56:37 -08003470 struct bnx2_napi *bnapi = container_of(napi, struct bnx2_napi, napi);
3471 struct bnx2 *bp = bnapi->bp;
David S. Miller6f535762007-10-11 18:08:29 -07003472 int work_done = 0;
Michael Chan43e80b82008-06-19 16:41:08 -07003473 struct status_block *sblk = bnapi->status_blk.msi;
David S. Miller6f535762007-10-11 18:08:29 -07003474
3475 while (1) {
Michael Chan43e80b82008-06-19 16:41:08 -07003476 bnx2_poll_link(bp, bnapi);
3477
Michael Chan35efa7c2007-12-20 19:56:37 -08003478 work_done = bnx2_poll_work(bp, bnapi, work_done, budget);
David S. Miller6f535762007-10-11 18:08:29 -07003479
Michael Chan4edd4732009-06-08 18:14:42 -07003480#ifdef BCM_CNIC
3481 bnx2_poll_cnic(bp, bnapi);
3482#endif
3483
Michael Chan35efa7c2007-12-20 19:56:37 -08003484 /* bnapi->last_status_idx is used below to tell the hw how
Michael Chan6dee6422007-10-12 01:40:38 -07003485 * much work has been processed, so we must read it before
3486 * checking for more work.
3487 */
Michael Chan35efa7c2007-12-20 19:56:37 -08003488 bnapi->last_status_idx = sblk->status_idx;
Michael Chanefba0182008-12-03 00:36:15 -08003489
3490 if (unlikely(work_done >= budget))
3491 break;
3492
Michael Chan6dee6422007-10-12 01:40:38 -07003493 rmb();
Michael Chan35efa7c2007-12-20 19:56:37 -08003494 if (likely(!bnx2_has_work(bnapi))) {
Ben Hutchings288379f2009-01-19 16:43:59 -08003495 napi_complete(napi);
David S. Millerf86e82f2008-01-21 17:15:40 -08003496 if (likely(bp->flags & BNX2_FLAG_USING_MSI_OR_MSIX)) {
David S. Miller6f535762007-10-11 18:08:29 -07003497 REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
3498 BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
Michael Chan35efa7c2007-12-20 19:56:37 -08003499 bnapi->last_status_idx);
Michael Chan6dee6422007-10-12 01:40:38 -07003500 break;
David S. Miller6f535762007-10-11 18:08:29 -07003501 }
3502 REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
3503 BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
3504 BNX2_PCICFG_INT_ACK_CMD_MASK_INT |
Michael Chan35efa7c2007-12-20 19:56:37 -08003505 bnapi->last_status_idx);
David S. Miller6f535762007-10-11 18:08:29 -07003506
Michael Chan1269a8a2006-01-23 16:11:03 -08003507 REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
3508 BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
Michael Chan35efa7c2007-12-20 19:56:37 -08003509 bnapi->last_status_idx);
David S. Miller6f535762007-10-11 18:08:29 -07003510 break;
Michael Chan1269a8a2006-01-23 16:11:03 -08003511 }
Michael Chanb6016b72005-05-26 13:03:09 -07003512 }
3513
Stephen Hemmingerbea33482007-10-03 16:41:36 -07003514 return work_done;
Michael Chanb6016b72005-05-26 13:03:09 -07003515}
3516
Herbert Xu932ff272006-06-09 12:20:56 -07003517/* Called with rtnl_lock from vlan functions and also netif_tx_lock
Michael Chanb6016b72005-05-26 13:03:09 -07003518 * from set_multicast.
3519 */
3520static void
3521bnx2_set_rx_mode(struct net_device *dev)
3522{
Michael Chan972ec0d2006-01-23 16:12:43 -08003523 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07003524 u32 rx_mode, sort_mode;
Jiri Pirkoccffad252009-05-22 23:22:17 +00003525 struct netdev_hw_addr *ha;
Michael Chanb6016b72005-05-26 13:03:09 -07003526 int i;
Michael Chanb6016b72005-05-26 13:03:09 -07003527
Michael Chan9f52b562008-10-09 12:21:46 -07003528 if (!netif_running(dev))
3529 return;
3530
Michael Chanc770a652005-08-25 15:38:39 -07003531 spin_lock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07003532
3533 rx_mode = bp->rx_mode & ~(BNX2_EMAC_RX_MODE_PROMISCUOUS |
3534 BNX2_EMAC_RX_MODE_KEEP_VLAN_TAG);
3535 sort_mode = 1 | BNX2_RPM_SORT_USER0_BC_EN;
3536#ifdef BCM_VLAN
Michael Chan7c6337a2008-08-14 15:29:09 -07003537 if (!bp->vlgrp && (bp->flags & BNX2_FLAG_CAN_KEEP_VLAN))
Michael Chanb6016b72005-05-26 13:03:09 -07003538 rx_mode |= BNX2_EMAC_RX_MODE_KEEP_VLAN_TAG;
Michael Chanb6016b72005-05-26 13:03:09 -07003539#else
Michael Chan7c6337a2008-08-14 15:29:09 -07003540 if (bp->flags & BNX2_FLAG_CAN_KEEP_VLAN)
Michael Chane29054f2006-01-23 16:06:06 -08003541 rx_mode |= BNX2_EMAC_RX_MODE_KEEP_VLAN_TAG;
Michael Chanb6016b72005-05-26 13:03:09 -07003542#endif
3543 if (dev->flags & IFF_PROMISC) {
3544 /* Promiscuous mode. */
3545 rx_mode |= BNX2_EMAC_RX_MODE_PROMISCUOUS;
Michael Chan75108732006-11-19 14:06:40 -08003546 sort_mode |= BNX2_RPM_SORT_USER0_PROM_EN |
3547 BNX2_RPM_SORT_USER0_PROM_VLAN;
Michael Chanb6016b72005-05-26 13:03:09 -07003548 }
3549 else if (dev->flags & IFF_ALLMULTI) {
3550 for (i = 0; i < NUM_MC_HASH_REGISTERS; i++) {
3551 REG_WR(bp, BNX2_EMAC_MULTICAST_HASH0 + (i * 4),
3552 0xffffffff);
3553 }
3554 sort_mode |= BNX2_RPM_SORT_USER0_MC_EN;
3555 }
3556 else {
3557 /* Accept one or more multicast(s). */
Michael Chanb6016b72005-05-26 13:03:09 -07003558 u32 mc_filter[NUM_MC_HASH_REGISTERS];
3559 u32 regidx;
3560 u32 bit;
3561 u32 crc;
3562
3563 memset(mc_filter, 0, 4 * NUM_MC_HASH_REGISTERS);
3564
Jiri Pirko22bedad32010-04-01 21:22:57 +00003565 netdev_for_each_mc_addr(ha, dev) {
3566 crc = ether_crc_le(ETH_ALEN, ha->addr);
Michael Chanb6016b72005-05-26 13:03:09 -07003567 bit = crc & 0xff;
3568 regidx = (bit & 0xe0) >> 5;
3569 bit &= 0x1f;
3570 mc_filter[regidx] |= (1 << bit);
3571 }
3572
3573 for (i = 0; i < NUM_MC_HASH_REGISTERS; i++) {
3574 REG_WR(bp, BNX2_EMAC_MULTICAST_HASH0 + (i * 4),
3575 mc_filter[i]);
3576 }
3577
3578 sort_mode |= BNX2_RPM_SORT_USER0_MC_HSH_EN;
3579 }
3580
Jiri Pirko32e7bfc2010-01-25 13:36:10 -08003581 if (netdev_uc_count(dev) > BNX2_MAX_UNICAST_ADDRESSES) {
Benjamin Li5fcaed02008-07-14 22:39:52 -07003582 rx_mode |= BNX2_EMAC_RX_MODE_PROMISCUOUS;
3583 sort_mode |= BNX2_RPM_SORT_USER0_PROM_EN |
3584 BNX2_RPM_SORT_USER0_PROM_VLAN;
3585 } else if (!(dev->flags & IFF_PROMISC)) {
Benjamin Li5fcaed02008-07-14 22:39:52 -07003586 /* Add all entries into to the match filter list */
Jiri Pirkoccffad252009-05-22 23:22:17 +00003587 i = 0;
Jiri Pirko32e7bfc2010-01-25 13:36:10 -08003588 netdev_for_each_uc_addr(ha, dev) {
Jiri Pirkoccffad252009-05-22 23:22:17 +00003589 bnx2_set_mac_addr(bp, ha->addr,
Benjamin Li5fcaed02008-07-14 22:39:52 -07003590 i + BNX2_START_UNICAST_ADDRESS_INDEX);
3591 sort_mode |= (1 <<
3592 (i + BNX2_START_UNICAST_ADDRESS_INDEX));
Jiri Pirkoccffad252009-05-22 23:22:17 +00003593 i++;
Benjamin Li5fcaed02008-07-14 22:39:52 -07003594 }
3595
3596 }
3597
Michael Chanb6016b72005-05-26 13:03:09 -07003598 if (rx_mode != bp->rx_mode) {
3599 bp->rx_mode = rx_mode;
3600 REG_WR(bp, BNX2_EMAC_RX_MODE, rx_mode);
3601 }
3602
3603 REG_WR(bp, BNX2_RPM_SORT_USER0, 0x0);
3604 REG_WR(bp, BNX2_RPM_SORT_USER0, sort_mode);
3605 REG_WR(bp, BNX2_RPM_SORT_USER0, sort_mode | BNX2_RPM_SORT_USER0_ENA);
3606
Michael Chanc770a652005-08-25 15:38:39 -07003607 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07003608}
3609
Michael Chan57579f72009-04-04 16:51:14 -07003610static int __devinit
3611check_fw_section(const struct firmware *fw,
3612 const struct bnx2_fw_file_section *section,
3613 u32 alignment, bool non_empty)
Michael Chanb6016b72005-05-26 13:03:09 -07003614{
Michael Chan57579f72009-04-04 16:51:14 -07003615 u32 offset = be32_to_cpu(section->offset);
3616 u32 len = be32_to_cpu(section->len);
Michael Chanb6016b72005-05-26 13:03:09 -07003617
Michael Chan57579f72009-04-04 16:51:14 -07003618 if ((offset == 0 && len != 0) || offset >= fw->size || offset & 3)
3619 return -EINVAL;
3620 if ((non_empty && len == 0) || len > fw->size - offset ||
3621 len & (alignment - 1))
3622 return -EINVAL;
3623 return 0;
3624}
3625
3626static int __devinit
3627check_mips_fw_entry(const struct firmware *fw,
3628 const struct bnx2_mips_fw_file_entry *entry)
3629{
3630 if (check_fw_section(fw, &entry->text, 4, true) ||
3631 check_fw_section(fw, &entry->data, 4, false) ||
3632 check_fw_section(fw, &entry->rodata, 4, false))
3633 return -EINVAL;
3634 return 0;
3635}
3636
3637static int __devinit
3638bnx2_request_firmware(struct bnx2 *bp)
3639{
3640 const char *mips_fw_file, *rv2p_fw_file;
Bastian Blank5ee1c322009-04-08 15:50:07 -07003641 const struct bnx2_mips_fw_file *mips_fw;
3642 const struct bnx2_rv2p_fw_file *rv2p_fw;
Michael Chan57579f72009-04-04 16:51:14 -07003643 int rc;
3644
3645 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
3646 mips_fw_file = FW_MIPS_FILE_09;
Michael Chan078b0732009-08-29 00:02:46 -07003647 if ((CHIP_ID(bp) == CHIP_ID_5709_A0) ||
3648 (CHIP_ID(bp) == CHIP_ID_5709_A1))
3649 rv2p_fw_file = FW_RV2P_FILE_09_Ax;
3650 else
3651 rv2p_fw_file = FW_RV2P_FILE_09;
Michael Chan57579f72009-04-04 16:51:14 -07003652 } else {
3653 mips_fw_file = FW_MIPS_FILE_06;
3654 rv2p_fw_file = FW_RV2P_FILE_06;
3655 }
3656
3657 rc = request_firmware(&bp->mips_firmware, mips_fw_file, &bp->pdev->dev);
3658 if (rc) {
Joe Perches3a9c6a42010-02-17 15:01:51 +00003659 pr_err("Can't load firmware file \"%s\"\n", mips_fw_file);
Michael Chan57579f72009-04-04 16:51:14 -07003660 return rc;
3661 }
3662
3663 rc = request_firmware(&bp->rv2p_firmware, rv2p_fw_file, &bp->pdev->dev);
3664 if (rc) {
Joe Perches3a9c6a42010-02-17 15:01:51 +00003665 pr_err("Can't load firmware file \"%s\"\n", rv2p_fw_file);
Michael Chan57579f72009-04-04 16:51:14 -07003666 return rc;
3667 }
Bastian Blank5ee1c322009-04-08 15:50:07 -07003668 mips_fw = (const struct bnx2_mips_fw_file *) bp->mips_firmware->data;
3669 rv2p_fw = (const struct bnx2_rv2p_fw_file *) bp->rv2p_firmware->data;
3670 if (bp->mips_firmware->size < sizeof(*mips_fw) ||
3671 check_mips_fw_entry(bp->mips_firmware, &mips_fw->com) ||
3672 check_mips_fw_entry(bp->mips_firmware, &mips_fw->cp) ||
3673 check_mips_fw_entry(bp->mips_firmware, &mips_fw->rxp) ||
3674 check_mips_fw_entry(bp->mips_firmware, &mips_fw->tpat) ||
3675 check_mips_fw_entry(bp->mips_firmware, &mips_fw->txp)) {
Joe Perches3a9c6a42010-02-17 15:01:51 +00003676 pr_err("Firmware file \"%s\" is invalid\n", mips_fw_file);
Michael Chan57579f72009-04-04 16:51:14 -07003677 return -EINVAL;
3678 }
Bastian Blank5ee1c322009-04-08 15:50:07 -07003679 if (bp->rv2p_firmware->size < sizeof(*rv2p_fw) ||
3680 check_fw_section(bp->rv2p_firmware, &rv2p_fw->proc1.rv2p, 8, true) ||
3681 check_fw_section(bp->rv2p_firmware, &rv2p_fw->proc2.rv2p, 8, true)) {
Joe Perches3a9c6a42010-02-17 15:01:51 +00003682 pr_err("Firmware file \"%s\" is invalid\n", rv2p_fw_file);
Michael Chan57579f72009-04-04 16:51:14 -07003683 return -EINVAL;
3684 }
3685
3686 return 0;
3687}
3688
3689static u32
3690rv2p_fw_fixup(u32 rv2p_proc, int idx, u32 loc, u32 rv2p_code)
3691{
3692 switch (idx) {
3693 case RV2P_P1_FIXUP_PAGE_SIZE_IDX:
3694 rv2p_code &= ~RV2P_BD_PAGE_SIZE_MSK;
3695 rv2p_code |= RV2P_BD_PAGE_SIZE;
3696 break;
3697 }
3698 return rv2p_code;
3699}
3700
3701static int
3702load_rv2p_fw(struct bnx2 *bp, u32 rv2p_proc,
3703 const struct bnx2_rv2p_fw_file_entry *fw_entry)
3704{
3705 u32 rv2p_code_len, file_offset;
3706 __be32 *rv2p_code;
3707 int i;
3708 u32 val, cmd, addr;
3709
3710 rv2p_code_len = be32_to_cpu(fw_entry->rv2p.len);
3711 file_offset = be32_to_cpu(fw_entry->rv2p.offset);
3712
3713 rv2p_code = (__be32 *)(bp->rv2p_firmware->data + file_offset);
3714
3715 if (rv2p_proc == RV2P_PROC1) {
3716 cmd = BNX2_RV2P_PROC1_ADDR_CMD_RDWR;
3717 addr = BNX2_RV2P_PROC1_ADDR_CMD;
3718 } else {
3719 cmd = BNX2_RV2P_PROC2_ADDR_CMD_RDWR;
3720 addr = BNX2_RV2P_PROC2_ADDR_CMD;
Michael Chand25be1d2008-05-02 16:57:59 -07003721 }
Michael Chanb6016b72005-05-26 13:03:09 -07003722
3723 for (i = 0; i < rv2p_code_len; i += 8) {
Michael Chan57579f72009-04-04 16:51:14 -07003724 REG_WR(bp, BNX2_RV2P_INSTR_HIGH, be32_to_cpu(*rv2p_code));
Michael Chanb6016b72005-05-26 13:03:09 -07003725 rv2p_code++;
Michael Chan57579f72009-04-04 16:51:14 -07003726 REG_WR(bp, BNX2_RV2P_INSTR_LOW, be32_to_cpu(*rv2p_code));
Michael Chanb6016b72005-05-26 13:03:09 -07003727 rv2p_code++;
3728
Michael Chan57579f72009-04-04 16:51:14 -07003729 val = (i / 8) | cmd;
3730 REG_WR(bp, addr, val);
3731 }
3732
3733 rv2p_code = (__be32 *)(bp->rv2p_firmware->data + file_offset);
3734 for (i = 0; i < 8; i++) {
3735 u32 loc, code;
3736
3737 loc = be32_to_cpu(fw_entry->fixup[i]);
3738 if (loc && ((loc * 4) < rv2p_code_len)) {
3739 code = be32_to_cpu(*(rv2p_code + loc - 1));
3740 REG_WR(bp, BNX2_RV2P_INSTR_HIGH, code);
3741 code = be32_to_cpu(*(rv2p_code + loc));
3742 code = rv2p_fw_fixup(rv2p_proc, i, loc, code);
3743 REG_WR(bp, BNX2_RV2P_INSTR_LOW, code);
3744
3745 val = (loc / 2) | cmd;
3746 REG_WR(bp, addr, val);
Michael Chanb6016b72005-05-26 13:03:09 -07003747 }
3748 }
3749
3750 /* Reset the processor, un-stall is done later. */
3751 if (rv2p_proc == RV2P_PROC1) {
3752 REG_WR(bp, BNX2_RV2P_COMMAND, BNX2_RV2P_COMMAND_PROC1_RESET);
3753 }
3754 else {
3755 REG_WR(bp, BNX2_RV2P_COMMAND, BNX2_RV2P_COMMAND_PROC2_RESET);
3756 }
Michael Chan57579f72009-04-04 16:51:14 -07003757
3758 return 0;
Michael Chanb6016b72005-05-26 13:03:09 -07003759}
3760
Michael Chanaf3ee512006-11-19 14:09:25 -08003761static int
Michael Chan57579f72009-04-04 16:51:14 -07003762load_cpu_fw(struct bnx2 *bp, const struct cpu_reg *cpu_reg,
3763 const struct bnx2_mips_fw_file_entry *fw_entry)
Michael Chanb6016b72005-05-26 13:03:09 -07003764{
Michael Chan57579f72009-04-04 16:51:14 -07003765 u32 addr, len, file_offset;
3766 __be32 *data;
Michael Chanb6016b72005-05-26 13:03:09 -07003767 u32 offset;
3768 u32 val;
3769
3770 /* Halt the CPU. */
Michael Chan2726d6e2008-01-29 21:35:05 -08003771 val = bnx2_reg_rd_ind(bp, cpu_reg->mode);
Michael Chanb6016b72005-05-26 13:03:09 -07003772 val |= cpu_reg->mode_value_halt;
Michael Chan2726d6e2008-01-29 21:35:05 -08003773 bnx2_reg_wr_ind(bp, cpu_reg->mode, val);
3774 bnx2_reg_wr_ind(bp, cpu_reg->state, cpu_reg->state_value_clear);
Michael Chanb6016b72005-05-26 13:03:09 -07003775
3776 /* Load the Text area. */
Michael Chan57579f72009-04-04 16:51:14 -07003777 addr = be32_to_cpu(fw_entry->text.addr);
3778 len = be32_to_cpu(fw_entry->text.len);
3779 file_offset = be32_to_cpu(fw_entry->text.offset);
3780 data = (__be32 *)(bp->mips_firmware->data + file_offset);
3781
3782 offset = cpu_reg->spad_base + (addr - cpu_reg->mips_view_base);
3783 if (len) {
Michael Chanb6016b72005-05-26 13:03:09 -07003784 int j;
3785
Michael Chan57579f72009-04-04 16:51:14 -07003786 for (j = 0; j < (len / 4); j++, offset += 4)
3787 bnx2_reg_wr_ind(bp, offset, be32_to_cpu(data[j]));
Michael Chanb6016b72005-05-26 13:03:09 -07003788 }
3789
3790 /* Load the Data area. */
Michael Chan57579f72009-04-04 16:51:14 -07003791 addr = be32_to_cpu(fw_entry->data.addr);
3792 len = be32_to_cpu(fw_entry->data.len);
3793 file_offset = be32_to_cpu(fw_entry->data.offset);
3794 data = (__be32 *)(bp->mips_firmware->data + file_offset);
3795
3796 offset = cpu_reg->spad_base + (addr - cpu_reg->mips_view_base);
3797 if (len) {
Michael Chanb6016b72005-05-26 13:03:09 -07003798 int j;
3799
Michael Chan57579f72009-04-04 16:51:14 -07003800 for (j = 0; j < (len / 4); j++, offset += 4)
3801 bnx2_reg_wr_ind(bp, offset, be32_to_cpu(data[j]));
Michael Chanb6016b72005-05-26 13:03:09 -07003802 }
3803
3804 /* Load the Read-Only area. */
Michael Chan57579f72009-04-04 16:51:14 -07003805 addr = be32_to_cpu(fw_entry->rodata.addr);
3806 len = be32_to_cpu(fw_entry->rodata.len);
3807 file_offset = be32_to_cpu(fw_entry->rodata.offset);
3808 data = (__be32 *)(bp->mips_firmware->data + file_offset);
3809
3810 offset = cpu_reg->spad_base + (addr - cpu_reg->mips_view_base);
3811 if (len) {
Michael Chanb6016b72005-05-26 13:03:09 -07003812 int j;
3813
Michael Chan57579f72009-04-04 16:51:14 -07003814 for (j = 0; j < (len / 4); j++, offset += 4)
3815 bnx2_reg_wr_ind(bp, offset, be32_to_cpu(data[j]));
Michael Chanb6016b72005-05-26 13:03:09 -07003816 }
3817
3818 /* Clear the pre-fetch instruction. */
Michael Chan2726d6e2008-01-29 21:35:05 -08003819 bnx2_reg_wr_ind(bp, cpu_reg->inst, 0);
Michael Chan57579f72009-04-04 16:51:14 -07003820
3821 val = be32_to_cpu(fw_entry->start_addr);
3822 bnx2_reg_wr_ind(bp, cpu_reg->pc, val);
Michael Chanb6016b72005-05-26 13:03:09 -07003823
3824 /* Start the CPU. */
Michael Chan2726d6e2008-01-29 21:35:05 -08003825 val = bnx2_reg_rd_ind(bp, cpu_reg->mode);
Michael Chanb6016b72005-05-26 13:03:09 -07003826 val &= ~cpu_reg->mode_value_halt;
Michael Chan2726d6e2008-01-29 21:35:05 -08003827 bnx2_reg_wr_ind(bp, cpu_reg->state, cpu_reg->state_value_clear);
3828 bnx2_reg_wr_ind(bp, cpu_reg->mode, val);
Michael Chanaf3ee512006-11-19 14:09:25 -08003829
3830 return 0;
Michael Chanb6016b72005-05-26 13:03:09 -07003831}
3832
Michael Chanfba9fe92006-06-12 22:21:25 -07003833static int
Michael Chanb6016b72005-05-26 13:03:09 -07003834bnx2_init_cpus(struct bnx2 *bp)
3835{
Michael Chan57579f72009-04-04 16:51:14 -07003836 const struct bnx2_mips_fw_file *mips_fw =
3837 (const struct bnx2_mips_fw_file *) bp->mips_firmware->data;
3838 const struct bnx2_rv2p_fw_file *rv2p_fw =
3839 (const struct bnx2_rv2p_fw_file *) bp->rv2p_firmware->data;
3840 int rc;
Michael Chanb6016b72005-05-26 13:03:09 -07003841
3842 /* Initialize the RV2P processor. */
Michael Chan57579f72009-04-04 16:51:14 -07003843 load_rv2p_fw(bp, RV2P_PROC1, &rv2p_fw->proc1);
3844 load_rv2p_fw(bp, RV2P_PROC2, &rv2p_fw->proc2);
Michael Chanb6016b72005-05-26 13:03:09 -07003845
3846 /* Initialize the RX Processor. */
Michael Chan57579f72009-04-04 16:51:14 -07003847 rc = load_cpu_fw(bp, &cpu_reg_rxp, &mips_fw->rxp);
Michael Chanfba9fe92006-06-12 22:21:25 -07003848 if (rc)
3849 goto init_cpu_err;
3850
Michael Chanb6016b72005-05-26 13:03:09 -07003851 /* Initialize the TX Processor. */
Michael Chan57579f72009-04-04 16:51:14 -07003852 rc = load_cpu_fw(bp, &cpu_reg_txp, &mips_fw->txp);
Michael Chanfba9fe92006-06-12 22:21:25 -07003853 if (rc)
3854 goto init_cpu_err;
3855
Michael Chanb6016b72005-05-26 13:03:09 -07003856 /* Initialize the TX Patch-up Processor. */
Michael Chan57579f72009-04-04 16:51:14 -07003857 rc = load_cpu_fw(bp, &cpu_reg_tpat, &mips_fw->tpat);
Michael Chanfba9fe92006-06-12 22:21:25 -07003858 if (rc)
3859 goto init_cpu_err;
3860
Michael Chanb6016b72005-05-26 13:03:09 -07003861 /* Initialize the Completion Processor. */
Michael Chan57579f72009-04-04 16:51:14 -07003862 rc = load_cpu_fw(bp, &cpu_reg_com, &mips_fw->com);
Michael Chanfba9fe92006-06-12 22:21:25 -07003863 if (rc)
3864 goto init_cpu_err;
3865
Michael Chand43584c2006-11-19 14:14:35 -08003866 /* Initialize the Command Processor. */
Michael Chan57579f72009-04-04 16:51:14 -07003867 rc = load_cpu_fw(bp, &cpu_reg_cp, &mips_fw->cp);
Michael Chan110d0ef2007-12-12 11:18:34 -08003868
Michael Chanfba9fe92006-06-12 22:21:25 -07003869init_cpu_err:
Michael Chanfba9fe92006-06-12 22:21:25 -07003870 return rc;
Michael Chanb6016b72005-05-26 13:03:09 -07003871}
3872
3873static int
Pavel Machek829ca9a2005-09-03 15:56:56 -07003874bnx2_set_power_state(struct bnx2 *bp, pci_power_t state)
Michael Chanb6016b72005-05-26 13:03:09 -07003875{
3876 u16 pmcsr;
3877
3878 pci_read_config_word(bp->pdev, bp->pm_cap + PCI_PM_CTRL, &pmcsr);
3879
3880 switch (state) {
Pavel Machek829ca9a2005-09-03 15:56:56 -07003881 case PCI_D0: {
Michael Chanb6016b72005-05-26 13:03:09 -07003882 u32 val;
3883
3884 pci_write_config_word(bp->pdev, bp->pm_cap + PCI_PM_CTRL,
3885 (pmcsr & ~PCI_PM_CTRL_STATE_MASK) |
3886 PCI_PM_CTRL_PME_STATUS);
3887
3888 if (pmcsr & PCI_PM_CTRL_STATE_MASK)
3889 /* delay required during transition out of D3hot */
3890 msleep(20);
3891
3892 val = REG_RD(bp, BNX2_EMAC_MODE);
3893 val |= BNX2_EMAC_MODE_MPKT_RCVD | BNX2_EMAC_MODE_ACPI_RCVD;
3894 val &= ~BNX2_EMAC_MODE_MPKT;
3895 REG_WR(bp, BNX2_EMAC_MODE, val);
3896
3897 val = REG_RD(bp, BNX2_RPM_CONFIG);
3898 val &= ~BNX2_RPM_CONFIG_ACPI_ENA;
3899 REG_WR(bp, BNX2_RPM_CONFIG, val);
3900 break;
3901 }
Pavel Machek829ca9a2005-09-03 15:56:56 -07003902 case PCI_D3hot: {
Michael Chanb6016b72005-05-26 13:03:09 -07003903 int i;
3904 u32 val, wol_msg;
3905
3906 if (bp->wol) {
3907 u32 advertising;
3908 u8 autoneg;
3909
3910 autoneg = bp->autoneg;
3911 advertising = bp->advertising;
3912
Michael Chan239cd342007-10-17 19:26:15 -07003913 if (bp->phy_port == PORT_TP) {
3914 bp->autoneg = AUTONEG_SPEED;
3915 bp->advertising = ADVERTISED_10baseT_Half |
3916 ADVERTISED_10baseT_Full |
3917 ADVERTISED_100baseT_Half |
3918 ADVERTISED_100baseT_Full |
3919 ADVERTISED_Autoneg;
3920 }
Michael Chanb6016b72005-05-26 13:03:09 -07003921
Michael Chan239cd342007-10-17 19:26:15 -07003922 spin_lock_bh(&bp->phy_lock);
3923 bnx2_setup_phy(bp, bp->phy_port);
3924 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07003925
3926 bp->autoneg = autoneg;
3927 bp->advertising = advertising;
3928
Benjamin Li5fcaed02008-07-14 22:39:52 -07003929 bnx2_set_mac_addr(bp, bp->dev->dev_addr, 0);
Michael Chanb6016b72005-05-26 13:03:09 -07003930
3931 val = REG_RD(bp, BNX2_EMAC_MODE);
3932
3933 /* Enable port mode. */
3934 val &= ~BNX2_EMAC_MODE_PORT;
Michael Chan239cd342007-10-17 19:26:15 -07003935 val |= BNX2_EMAC_MODE_MPKT_RCVD |
Michael Chanb6016b72005-05-26 13:03:09 -07003936 BNX2_EMAC_MODE_ACPI_RCVD |
Michael Chanb6016b72005-05-26 13:03:09 -07003937 BNX2_EMAC_MODE_MPKT;
Michael Chan239cd342007-10-17 19:26:15 -07003938 if (bp->phy_port == PORT_TP)
3939 val |= BNX2_EMAC_MODE_PORT_MII;
3940 else {
3941 val |= BNX2_EMAC_MODE_PORT_GMII;
3942 if (bp->line_speed == SPEED_2500)
3943 val |= BNX2_EMAC_MODE_25G_MODE;
3944 }
Michael Chanb6016b72005-05-26 13:03:09 -07003945
3946 REG_WR(bp, BNX2_EMAC_MODE, val);
3947
3948 /* receive all multicast */
3949 for (i = 0; i < NUM_MC_HASH_REGISTERS; i++) {
3950 REG_WR(bp, BNX2_EMAC_MULTICAST_HASH0 + (i * 4),
3951 0xffffffff);
3952 }
3953 REG_WR(bp, BNX2_EMAC_RX_MODE,
3954 BNX2_EMAC_RX_MODE_SORT_MODE);
3955
3956 val = 1 | BNX2_RPM_SORT_USER0_BC_EN |
3957 BNX2_RPM_SORT_USER0_MC_EN;
3958 REG_WR(bp, BNX2_RPM_SORT_USER0, 0x0);
3959 REG_WR(bp, BNX2_RPM_SORT_USER0, val);
3960 REG_WR(bp, BNX2_RPM_SORT_USER0, val |
3961 BNX2_RPM_SORT_USER0_ENA);
3962
3963 /* Need to enable EMAC and RPM for WOL. */
3964 REG_WR(bp, BNX2_MISC_ENABLE_SET_BITS,
3965 BNX2_MISC_ENABLE_SET_BITS_RX_PARSER_MAC_ENABLE |
3966 BNX2_MISC_ENABLE_SET_BITS_TX_HEADER_Q_ENABLE |
3967 BNX2_MISC_ENABLE_SET_BITS_EMAC_ENABLE);
3968
3969 val = REG_RD(bp, BNX2_RPM_CONFIG);
3970 val &= ~BNX2_RPM_CONFIG_ACPI_ENA;
3971 REG_WR(bp, BNX2_RPM_CONFIG, val);
3972
3973 wol_msg = BNX2_DRV_MSG_CODE_SUSPEND_WOL;
3974 }
3975 else {
3976 wol_msg = BNX2_DRV_MSG_CODE_SUSPEND_NO_WOL;
3977 }
3978
David S. Millerf86e82f2008-01-21 17:15:40 -08003979 if (!(bp->flags & BNX2_FLAG_NO_WOL))
Michael Chana2f13892008-07-14 22:38:23 -07003980 bnx2_fw_sync(bp, BNX2_DRV_MSG_DATA_WAIT3 | wol_msg,
3981 1, 0);
Michael Chanb6016b72005-05-26 13:03:09 -07003982
3983 pmcsr &= ~PCI_PM_CTRL_STATE_MASK;
3984 if ((CHIP_ID(bp) == CHIP_ID_5706_A0) ||
3985 (CHIP_ID(bp) == CHIP_ID_5706_A1)) {
3986
3987 if (bp->wol)
3988 pmcsr |= 3;
3989 }
3990 else {
3991 pmcsr |= 3;
3992 }
3993 if (bp->wol) {
3994 pmcsr |= PCI_PM_CTRL_PME_ENABLE;
3995 }
3996 pci_write_config_word(bp->pdev, bp->pm_cap + PCI_PM_CTRL,
3997 pmcsr);
3998
3999 /* No more memory access after this point until
4000 * device is brought back to D0.
4001 */
4002 udelay(50);
4003 break;
4004 }
4005 default:
4006 return -EINVAL;
4007 }
4008 return 0;
4009}
4010
4011static int
4012bnx2_acquire_nvram_lock(struct bnx2 *bp)
4013{
4014 u32 val;
4015 int j;
4016
4017 /* Request access to the flash interface. */
4018 REG_WR(bp, BNX2_NVM_SW_ARB, BNX2_NVM_SW_ARB_ARB_REQ_SET2);
4019 for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) {
4020 val = REG_RD(bp, BNX2_NVM_SW_ARB);
4021 if (val & BNX2_NVM_SW_ARB_ARB_ARB2)
4022 break;
4023
4024 udelay(5);
4025 }
4026
4027 if (j >= NVRAM_TIMEOUT_COUNT)
4028 return -EBUSY;
4029
4030 return 0;
4031}
4032
4033static int
4034bnx2_release_nvram_lock(struct bnx2 *bp)
4035{
4036 int j;
4037 u32 val;
4038
4039 /* Relinquish nvram interface. */
4040 REG_WR(bp, BNX2_NVM_SW_ARB, BNX2_NVM_SW_ARB_ARB_REQ_CLR2);
4041
4042 for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) {
4043 val = REG_RD(bp, BNX2_NVM_SW_ARB);
4044 if (!(val & BNX2_NVM_SW_ARB_ARB_ARB2))
4045 break;
4046
4047 udelay(5);
4048 }
4049
4050 if (j >= NVRAM_TIMEOUT_COUNT)
4051 return -EBUSY;
4052
4053 return 0;
4054}
4055
4056
4057static int
4058bnx2_enable_nvram_write(struct bnx2 *bp)
4059{
4060 u32 val;
4061
4062 val = REG_RD(bp, BNX2_MISC_CFG);
4063 REG_WR(bp, BNX2_MISC_CFG, val | BNX2_MISC_CFG_NVM_WR_EN_PCI);
4064
Michael Chane30372c2007-07-16 18:26:23 -07004065 if (bp->flash_info->flags & BNX2_NV_WREN) {
Michael Chanb6016b72005-05-26 13:03:09 -07004066 int j;
4067
4068 REG_WR(bp, BNX2_NVM_COMMAND, BNX2_NVM_COMMAND_DONE);
4069 REG_WR(bp, BNX2_NVM_COMMAND,
4070 BNX2_NVM_COMMAND_WREN | BNX2_NVM_COMMAND_DOIT);
4071
4072 for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) {
4073 udelay(5);
4074
4075 val = REG_RD(bp, BNX2_NVM_COMMAND);
4076 if (val & BNX2_NVM_COMMAND_DONE)
4077 break;
4078 }
4079
4080 if (j >= NVRAM_TIMEOUT_COUNT)
4081 return -EBUSY;
4082 }
4083 return 0;
4084}
4085
4086static void
4087bnx2_disable_nvram_write(struct bnx2 *bp)
4088{
4089 u32 val;
4090
4091 val = REG_RD(bp, BNX2_MISC_CFG);
4092 REG_WR(bp, BNX2_MISC_CFG, val & ~BNX2_MISC_CFG_NVM_WR_EN);
4093}
4094
4095
4096static void
4097bnx2_enable_nvram_access(struct bnx2 *bp)
4098{
4099 u32 val;
4100
4101 val = REG_RD(bp, BNX2_NVM_ACCESS_ENABLE);
4102 /* Enable both bits, even on read. */
Jeff Garzik6aa20a22006-09-13 13:24:59 -04004103 REG_WR(bp, BNX2_NVM_ACCESS_ENABLE,
Michael Chanb6016b72005-05-26 13:03:09 -07004104 val | BNX2_NVM_ACCESS_ENABLE_EN | BNX2_NVM_ACCESS_ENABLE_WR_EN);
4105}
4106
4107static void
4108bnx2_disable_nvram_access(struct bnx2 *bp)
4109{
4110 u32 val;
4111
4112 val = REG_RD(bp, BNX2_NVM_ACCESS_ENABLE);
4113 /* Disable both bits, even after read. */
Jeff Garzik6aa20a22006-09-13 13:24:59 -04004114 REG_WR(bp, BNX2_NVM_ACCESS_ENABLE,
Michael Chanb6016b72005-05-26 13:03:09 -07004115 val & ~(BNX2_NVM_ACCESS_ENABLE_EN |
4116 BNX2_NVM_ACCESS_ENABLE_WR_EN));
4117}
4118
4119static int
4120bnx2_nvram_erase_page(struct bnx2 *bp, u32 offset)
4121{
4122 u32 cmd;
4123 int j;
4124
Michael Chane30372c2007-07-16 18:26:23 -07004125 if (bp->flash_info->flags & BNX2_NV_BUFFERED)
Michael Chanb6016b72005-05-26 13:03:09 -07004126 /* Buffered flash, no erase needed */
4127 return 0;
4128
4129 /* Build an erase command */
4130 cmd = BNX2_NVM_COMMAND_ERASE | BNX2_NVM_COMMAND_WR |
4131 BNX2_NVM_COMMAND_DOIT;
4132
4133 /* Need to clear DONE bit separately. */
4134 REG_WR(bp, BNX2_NVM_COMMAND, BNX2_NVM_COMMAND_DONE);
4135
4136 /* Address of the NVRAM to read from. */
4137 REG_WR(bp, BNX2_NVM_ADDR, offset & BNX2_NVM_ADDR_NVM_ADDR_VALUE);
4138
4139 /* Issue an erase command. */
4140 REG_WR(bp, BNX2_NVM_COMMAND, cmd);
4141
4142 /* Wait for completion. */
4143 for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) {
4144 u32 val;
4145
4146 udelay(5);
4147
4148 val = REG_RD(bp, BNX2_NVM_COMMAND);
4149 if (val & BNX2_NVM_COMMAND_DONE)
4150 break;
4151 }
4152
4153 if (j >= NVRAM_TIMEOUT_COUNT)
4154 return -EBUSY;
4155
4156 return 0;
4157}
4158
4159static int
4160bnx2_nvram_read_dword(struct bnx2 *bp, u32 offset, u8 *ret_val, u32 cmd_flags)
4161{
4162 u32 cmd;
4163 int j;
4164
4165 /* Build the command word. */
4166 cmd = BNX2_NVM_COMMAND_DOIT | cmd_flags;
4167
Michael Chane30372c2007-07-16 18:26:23 -07004168 /* Calculate an offset of a buffered flash, not needed for 5709. */
4169 if (bp->flash_info->flags & BNX2_NV_TRANSLATE) {
Michael Chanb6016b72005-05-26 13:03:09 -07004170 offset = ((offset / bp->flash_info->page_size) <<
4171 bp->flash_info->page_bits) +
4172 (offset % bp->flash_info->page_size);
4173 }
4174
4175 /* Need to clear DONE bit separately. */
4176 REG_WR(bp, BNX2_NVM_COMMAND, BNX2_NVM_COMMAND_DONE);
4177
4178 /* Address of the NVRAM to read from. */
4179 REG_WR(bp, BNX2_NVM_ADDR, offset & BNX2_NVM_ADDR_NVM_ADDR_VALUE);
4180
4181 /* Issue a read command. */
4182 REG_WR(bp, BNX2_NVM_COMMAND, cmd);
4183
4184 /* Wait for completion. */
4185 for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) {
4186 u32 val;
4187
4188 udelay(5);
4189
4190 val = REG_RD(bp, BNX2_NVM_COMMAND);
4191 if (val & BNX2_NVM_COMMAND_DONE) {
Al Virob491edd2007-12-22 19:44:51 +00004192 __be32 v = cpu_to_be32(REG_RD(bp, BNX2_NVM_READ));
4193 memcpy(ret_val, &v, 4);
Michael Chanb6016b72005-05-26 13:03:09 -07004194 break;
4195 }
4196 }
4197 if (j >= NVRAM_TIMEOUT_COUNT)
4198 return -EBUSY;
4199
4200 return 0;
4201}
4202
4203
4204static int
4205bnx2_nvram_write_dword(struct bnx2 *bp, u32 offset, u8 *val, u32 cmd_flags)
4206{
Al Virob491edd2007-12-22 19:44:51 +00004207 u32 cmd;
4208 __be32 val32;
Michael Chanb6016b72005-05-26 13:03:09 -07004209 int j;
4210
4211 /* Build the command word. */
4212 cmd = BNX2_NVM_COMMAND_DOIT | BNX2_NVM_COMMAND_WR | cmd_flags;
4213
Michael Chane30372c2007-07-16 18:26:23 -07004214 /* Calculate an offset of a buffered flash, not needed for 5709. */
4215 if (bp->flash_info->flags & BNX2_NV_TRANSLATE) {
Michael Chanb6016b72005-05-26 13:03:09 -07004216 offset = ((offset / bp->flash_info->page_size) <<
4217 bp->flash_info->page_bits) +
4218 (offset % bp->flash_info->page_size);
4219 }
4220
4221 /* Need to clear DONE bit separately. */
4222 REG_WR(bp, BNX2_NVM_COMMAND, BNX2_NVM_COMMAND_DONE);
4223
4224 memcpy(&val32, val, 4);
Michael Chanb6016b72005-05-26 13:03:09 -07004225
4226 /* Write the data. */
Al Virob491edd2007-12-22 19:44:51 +00004227 REG_WR(bp, BNX2_NVM_WRITE, be32_to_cpu(val32));
Michael Chanb6016b72005-05-26 13:03:09 -07004228
4229 /* Address of the NVRAM to write to. */
4230 REG_WR(bp, BNX2_NVM_ADDR, offset & BNX2_NVM_ADDR_NVM_ADDR_VALUE);
4231
4232 /* Issue the write command. */
4233 REG_WR(bp, BNX2_NVM_COMMAND, cmd);
4234
4235 /* Wait for completion. */
4236 for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) {
4237 udelay(5);
4238
4239 if (REG_RD(bp, BNX2_NVM_COMMAND) & BNX2_NVM_COMMAND_DONE)
4240 break;
4241 }
4242 if (j >= NVRAM_TIMEOUT_COUNT)
4243 return -EBUSY;
4244
4245 return 0;
4246}
4247
4248static int
4249bnx2_init_nvram(struct bnx2 *bp)
4250{
4251 u32 val;
Michael Chane30372c2007-07-16 18:26:23 -07004252 int j, entry_count, rc = 0;
Michael Chan0ced9d02009-08-21 16:20:49 +00004253 const struct flash_spec *flash;
Michael Chanb6016b72005-05-26 13:03:09 -07004254
Michael Chane30372c2007-07-16 18:26:23 -07004255 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
4256 bp->flash_info = &flash_5709;
4257 goto get_flash_size;
4258 }
4259
Michael Chanb6016b72005-05-26 13:03:09 -07004260 /* Determine the selected interface. */
4261 val = REG_RD(bp, BNX2_NVM_CFG1);
4262
Denis Chengff8ac602007-09-02 18:30:18 +08004263 entry_count = ARRAY_SIZE(flash_table);
Michael Chanb6016b72005-05-26 13:03:09 -07004264
Michael Chanb6016b72005-05-26 13:03:09 -07004265 if (val & 0x40000000) {
4266
4267 /* Flash interface has been reconfigured */
4268 for (j = 0, flash = &flash_table[0]; j < entry_count;
Michael Chan37137702005-11-04 08:49:17 -08004269 j++, flash++) {
4270 if ((val & FLASH_BACKUP_STRAP_MASK) ==
4271 (flash->config1 & FLASH_BACKUP_STRAP_MASK)) {
Michael Chanb6016b72005-05-26 13:03:09 -07004272 bp->flash_info = flash;
4273 break;
4274 }
4275 }
4276 }
4277 else {
Michael Chan37137702005-11-04 08:49:17 -08004278 u32 mask;
Michael Chanb6016b72005-05-26 13:03:09 -07004279 /* Not yet been reconfigured */
4280
Michael Chan37137702005-11-04 08:49:17 -08004281 if (val & (1 << 23))
4282 mask = FLASH_BACKUP_STRAP_MASK;
4283 else
4284 mask = FLASH_STRAP_MASK;
4285
Michael Chanb6016b72005-05-26 13:03:09 -07004286 for (j = 0, flash = &flash_table[0]; j < entry_count;
4287 j++, flash++) {
4288
Michael Chan37137702005-11-04 08:49:17 -08004289 if ((val & mask) == (flash->strapping & mask)) {
Michael Chanb6016b72005-05-26 13:03:09 -07004290 bp->flash_info = flash;
4291
4292 /* Request access to the flash interface. */
4293 if ((rc = bnx2_acquire_nvram_lock(bp)) != 0)
4294 return rc;
4295
4296 /* Enable access to flash interface */
4297 bnx2_enable_nvram_access(bp);
4298
4299 /* Reconfigure the flash interface */
4300 REG_WR(bp, BNX2_NVM_CFG1, flash->config1);
4301 REG_WR(bp, BNX2_NVM_CFG2, flash->config2);
4302 REG_WR(bp, BNX2_NVM_CFG3, flash->config3);
4303 REG_WR(bp, BNX2_NVM_WRITE1, flash->write1);
4304
4305 /* Disable access to flash interface */
4306 bnx2_disable_nvram_access(bp);
4307 bnx2_release_nvram_lock(bp);
4308
4309 break;
4310 }
4311 }
4312 } /* if (val & 0x40000000) */
4313
4314 if (j == entry_count) {
4315 bp->flash_info = NULL;
Joe Perches3a9c6a42010-02-17 15:01:51 +00004316 pr_alert("Unknown flash/EEPROM type\n");
Michael Chan1122db72006-01-23 16:11:42 -08004317 return -ENODEV;
Michael Chanb6016b72005-05-26 13:03:09 -07004318 }
4319
Michael Chane30372c2007-07-16 18:26:23 -07004320get_flash_size:
Michael Chan2726d6e2008-01-29 21:35:05 -08004321 val = bnx2_shmem_rd(bp, BNX2_SHARED_HW_CFG_CONFIG2);
Michael Chan1122db72006-01-23 16:11:42 -08004322 val &= BNX2_SHARED_HW_CFG2_NVM_SIZE_MASK;
4323 if (val)
4324 bp->flash_size = val;
4325 else
4326 bp->flash_size = bp->flash_info->total_size;
4327
Michael Chanb6016b72005-05-26 13:03:09 -07004328 return rc;
4329}
4330
4331static int
4332bnx2_nvram_read(struct bnx2 *bp, u32 offset, u8 *ret_buf,
4333 int buf_size)
4334{
4335 int rc = 0;
4336 u32 cmd_flags, offset32, len32, extra;
4337
4338 if (buf_size == 0)
4339 return 0;
4340
4341 /* Request access to the flash interface. */
4342 if ((rc = bnx2_acquire_nvram_lock(bp)) != 0)
4343 return rc;
4344
4345 /* Enable access to flash interface */
4346 bnx2_enable_nvram_access(bp);
4347
4348 len32 = buf_size;
4349 offset32 = offset;
4350 extra = 0;
4351
4352 cmd_flags = 0;
4353
4354 if (offset32 & 3) {
4355 u8 buf[4];
4356 u32 pre_len;
4357
4358 offset32 &= ~3;
4359 pre_len = 4 - (offset & 3);
4360
4361 if (pre_len >= len32) {
4362 pre_len = len32;
4363 cmd_flags = BNX2_NVM_COMMAND_FIRST |
4364 BNX2_NVM_COMMAND_LAST;
4365 }
4366 else {
4367 cmd_flags = BNX2_NVM_COMMAND_FIRST;
4368 }
4369
4370 rc = bnx2_nvram_read_dword(bp, offset32, buf, cmd_flags);
4371
4372 if (rc)
4373 return rc;
4374
4375 memcpy(ret_buf, buf + (offset & 3), pre_len);
4376
4377 offset32 += 4;
4378 ret_buf += pre_len;
4379 len32 -= pre_len;
4380 }
4381 if (len32 & 3) {
4382 extra = 4 - (len32 & 3);
4383 len32 = (len32 + 4) & ~3;
4384 }
4385
4386 if (len32 == 4) {
4387 u8 buf[4];
4388
4389 if (cmd_flags)
4390 cmd_flags = BNX2_NVM_COMMAND_LAST;
4391 else
4392 cmd_flags = BNX2_NVM_COMMAND_FIRST |
4393 BNX2_NVM_COMMAND_LAST;
4394
4395 rc = bnx2_nvram_read_dword(bp, offset32, buf, cmd_flags);
4396
4397 memcpy(ret_buf, buf, 4 - extra);
4398 }
4399 else if (len32 > 0) {
4400 u8 buf[4];
4401
4402 /* Read the first word. */
4403 if (cmd_flags)
4404 cmd_flags = 0;
4405 else
4406 cmd_flags = BNX2_NVM_COMMAND_FIRST;
4407
4408 rc = bnx2_nvram_read_dword(bp, offset32, ret_buf, cmd_flags);
4409
4410 /* Advance to the next dword. */
4411 offset32 += 4;
4412 ret_buf += 4;
4413 len32 -= 4;
4414
4415 while (len32 > 4 && rc == 0) {
4416 rc = bnx2_nvram_read_dword(bp, offset32, ret_buf, 0);
4417
4418 /* Advance to the next dword. */
4419 offset32 += 4;
4420 ret_buf += 4;
4421 len32 -= 4;
4422 }
4423
4424 if (rc)
4425 return rc;
4426
4427 cmd_flags = BNX2_NVM_COMMAND_LAST;
4428 rc = bnx2_nvram_read_dword(bp, offset32, buf, cmd_flags);
4429
4430 memcpy(ret_buf, buf, 4 - extra);
4431 }
4432
4433 /* Disable access to flash interface */
4434 bnx2_disable_nvram_access(bp);
4435
4436 bnx2_release_nvram_lock(bp);
4437
4438 return rc;
4439}
4440
4441static int
4442bnx2_nvram_write(struct bnx2 *bp, u32 offset, u8 *data_buf,
4443 int buf_size)
4444{
4445 u32 written, offset32, len32;
Michael Chane6be7632007-01-08 19:56:13 -08004446 u8 *buf, start[4], end[4], *align_buf = NULL, *flash_buffer = NULL;
Michael Chanb6016b72005-05-26 13:03:09 -07004447 int rc = 0;
4448 int align_start, align_end;
4449
4450 buf = data_buf;
4451 offset32 = offset;
4452 len32 = buf_size;
4453 align_start = align_end = 0;
4454
4455 if ((align_start = (offset32 & 3))) {
4456 offset32 &= ~3;
Michael Chanc8738792007-03-30 14:53:06 -07004457 len32 += align_start;
4458 if (len32 < 4)
4459 len32 = 4;
Michael Chanb6016b72005-05-26 13:03:09 -07004460 if ((rc = bnx2_nvram_read(bp, offset32, start, 4)))
4461 return rc;
4462 }
4463
4464 if (len32 & 3) {
Michael Chanc8738792007-03-30 14:53:06 -07004465 align_end = 4 - (len32 & 3);
4466 len32 += align_end;
4467 if ((rc = bnx2_nvram_read(bp, offset32 + len32 - 4, end, 4)))
4468 return rc;
Michael Chanb6016b72005-05-26 13:03:09 -07004469 }
4470
4471 if (align_start || align_end) {
Michael Chane6be7632007-01-08 19:56:13 -08004472 align_buf = kmalloc(len32, GFP_KERNEL);
4473 if (align_buf == NULL)
Michael Chanb6016b72005-05-26 13:03:09 -07004474 return -ENOMEM;
4475 if (align_start) {
Michael Chane6be7632007-01-08 19:56:13 -08004476 memcpy(align_buf, start, 4);
Michael Chanb6016b72005-05-26 13:03:09 -07004477 }
4478 if (align_end) {
Michael Chane6be7632007-01-08 19:56:13 -08004479 memcpy(align_buf + len32 - 4, end, 4);
Michael Chanb6016b72005-05-26 13:03:09 -07004480 }
Michael Chane6be7632007-01-08 19:56:13 -08004481 memcpy(align_buf + align_start, data_buf, buf_size);
4482 buf = align_buf;
Michael Chanb6016b72005-05-26 13:03:09 -07004483 }
4484
Michael Chane30372c2007-07-16 18:26:23 -07004485 if (!(bp->flash_info->flags & BNX2_NV_BUFFERED)) {
Michael Chanae181bc2006-05-22 16:39:20 -07004486 flash_buffer = kmalloc(264, GFP_KERNEL);
4487 if (flash_buffer == NULL) {
4488 rc = -ENOMEM;
4489 goto nvram_write_end;
4490 }
4491 }
4492
Michael Chanb6016b72005-05-26 13:03:09 -07004493 written = 0;
4494 while ((written < len32) && (rc == 0)) {
4495 u32 page_start, page_end, data_start, data_end;
4496 u32 addr, cmd_flags;
4497 int i;
Michael Chanb6016b72005-05-26 13:03:09 -07004498
4499 /* Find the page_start addr */
4500 page_start = offset32 + written;
4501 page_start -= (page_start % bp->flash_info->page_size);
4502 /* Find the page_end addr */
4503 page_end = page_start + bp->flash_info->page_size;
4504 /* Find the data_start addr */
4505 data_start = (written == 0) ? offset32 : page_start;
4506 /* Find the data_end addr */
Jeff Garzik6aa20a22006-09-13 13:24:59 -04004507 data_end = (page_end > offset32 + len32) ?
Michael Chanb6016b72005-05-26 13:03:09 -07004508 (offset32 + len32) : page_end;
4509
4510 /* Request access to the flash interface. */
4511 if ((rc = bnx2_acquire_nvram_lock(bp)) != 0)
4512 goto nvram_write_end;
4513
4514 /* Enable access to flash interface */
4515 bnx2_enable_nvram_access(bp);
4516
4517 cmd_flags = BNX2_NVM_COMMAND_FIRST;
Michael Chane30372c2007-07-16 18:26:23 -07004518 if (!(bp->flash_info->flags & BNX2_NV_BUFFERED)) {
Michael Chanb6016b72005-05-26 13:03:09 -07004519 int j;
4520
4521 /* Read the whole page into the buffer
4522 * (non-buffer flash only) */
4523 for (j = 0; j < bp->flash_info->page_size; j += 4) {
4524 if (j == (bp->flash_info->page_size - 4)) {
4525 cmd_flags |= BNX2_NVM_COMMAND_LAST;
4526 }
4527 rc = bnx2_nvram_read_dword(bp,
Jeff Garzik6aa20a22006-09-13 13:24:59 -04004528 page_start + j,
4529 &flash_buffer[j],
Michael Chanb6016b72005-05-26 13:03:09 -07004530 cmd_flags);
4531
4532 if (rc)
4533 goto nvram_write_end;
4534
4535 cmd_flags = 0;
4536 }
4537 }
4538
4539 /* Enable writes to flash interface (unlock write-protect) */
4540 if ((rc = bnx2_enable_nvram_write(bp)) != 0)
4541 goto nvram_write_end;
4542
Michael Chanb6016b72005-05-26 13:03:09 -07004543 /* Loop to write back the buffer data from page_start to
4544 * data_start */
4545 i = 0;
Michael Chane30372c2007-07-16 18:26:23 -07004546 if (!(bp->flash_info->flags & BNX2_NV_BUFFERED)) {
Michael Chanc8738792007-03-30 14:53:06 -07004547 /* Erase the page */
4548 if ((rc = bnx2_nvram_erase_page(bp, page_start)) != 0)
4549 goto nvram_write_end;
4550
4551 /* Re-enable the write again for the actual write */
4552 bnx2_enable_nvram_write(bp);
4553
Michael Chanb6016b72005-05-26 13:03:09 -07004554 for (addr = page_start; addr < data_start;
4555 addr += 4, i += 4) {
Jeff Garzik6aa20a22006-09-13 13:24:59 -04004556
Michael Chanb6016b72005-05-26 13:03:09 -07004557 rc = bnx2_nvram_write_dword(bp, addr,
4558 &flash_buffer[i], cmd_flags);
4559
4560 if (rc != 0)
4561 goto nvram_write_end;
4562
4563 cmd_flags = 0;
4564 }
4565 }
4566
4567 /* Loop to write the new data from data_start to data_end */
Michael Chanbae25762006-05-22 16:38:38 -07004568 for (addr = data_start; addr < data_end; addr += 4, i += 4) {
Michael Chanb6016b72005-05-26 13:03:09 -07004569 if ((addr == page_end - 4) ||
Michael Chane30372c2007-07-16 18:26:23 -07004570 ((bp->flash_info->flags & BNX2_NV_BUFFERED) &&
Michael Chanb6016b72005-05-26 13:03:09 -07004571 (addr == data_end - 4))) {
4572
4573 cmd_flags |= BNX2_NVM_COMMAND_LAST;
4574 }
4575 rc = bnx2_nvram_write_dword(bp, addr, buf,
4576 cmd_flags);
4577
4578 if (rc != 0)
4579 goto nvram_write_end;
4580
4581 cmd_flags = 0;
4582 buf += 4;
4583 }
4584
4585 /* Loop to write back the buffer data from data_end
4586 * to page_end */
Michael Chane30372c2007-07-16 18:26:23 -07004587 if (!(bp->flash_info->flags & BNX2_NV_BUFFERED)) {
Michael Chanb6016b72005-05-26 13:03:09 -07004588 for (addr = data_end; addr < page_end;
4589 addr += 4, i += 4) {
Jeff Garzik6aa20a22006-09-13 13:24:59 -04004590
Michael Chanb6016b72005-05-26 13:03:09 -07004591 if (addr == page_end-4) {
4592 cmd_flags = BNX2_NVM_COMMAND_LAST;
4593 }
4594 rc = bnx2_nvram_write_dword(bp, addr,
4595 &flash_buffer[i], cmd_flags);
4596
4597 if (rc != 0)
4598 goto nvram_write_end;
4599
4600 cmd_flags = 0;
4601 }
4602 }
4603
4604 /* Disable writes to flash interface (lock write-protect) */
4605 bnx2_disable_nvram_write(bp);
4606
4607 /* Disable access to flash interface */
4608 bnx2_disable_nvram_access(bp);
4609 bnx2_release_nvram_lock(bp);
4610
4611 /* Increment written */
4612 written += data_end - data_start;
4613 }
4614
4615nvram_write_end:
Michael Chane6be7632007-01-08 19:56:13 -08004616 kfree(flash_buffer);
4617 kfree(align_buf);
Michael Chanb6016b72005-05-26 13:03:09 -07004618 return rc;
4619}
4620
Michael Chan0d8a6572007-07-07 22:49:43 -07004621static void
Michael Chan7c62e832008-07-14 22:39:03 -07004622bnx2_init_fw_cap(struct bnx2 *bp)
Michael Chan0d8a6572007-07-07 22:49:43 -07004623{
Michael Chan7c62e832008-07-14 22:39:03 -07004624 u32 val, sig = 0;
Michael Chan0d8a6572007-07-07 22:49:43 -07004625
Michael Chan583c28e2008-01-21 19:51:35 -08004626 bp->phy_flags &= ~BNX2_PHY_FLAG_REMOTE_PHY_CAP;
Michael Chan7c62e832008-07-14 22:39:03 -07004627 bp->flags &= ~BNX2_FLAG_CAN_KEEP_VLAN;
4628
4629 if (!(bp->flags & BNX2_FLAG_ASF_ENABLE))
4630 bp->flags |= BNX2_FLAG_CAN_KEEP_VLAN;
Michael Chan0d8a6572007-07-07 22:49:43 -07004631
Michael Chan2726d6e2008-01-29 21:35:05 -08004632 val = bnx2_shmem_rd(bp, BNX2_FW_CAP_MB);
Michael Chan0d8a6572007-07-07 22:49:43 -07004633 if ((val & BNX2_FW_CAP_SIGNATURE_MASK) != BNX2_FW_CAP_SIGNATURE)
4634 return;
4635
Michael Chan7c62e832008-07-14 22:39:03 -07004636 if ((val & BNX2_FW_CAP_CAN_KEEP_VLAN) == BNX2_FW_CAP_CAN_KEEP_VLAN) {
4637 bp->flags |= BNX2_FLAG_CAN_KEEP_VLAN;
4638 sig |= BNX2_DRV_ACK_CAP_SIGNATURE | BNX2_FW_CAP_CAN_KEEP_VLAN;
4639 }
4640
4641 if ((bp->phy_flags & BNX2_PHY_FLAG_SERDES) &&
4642 (val & BNX2_FW_CAP_REMOTE_PHY_CAPABLE)) {
4643 u32 link;
4644
Michael Chan583c28e2008-01-21 19:51:35 -08004645 bp->phy_flags |= BNX2_PHY_FLAG_REMOTE_PHY_CAP;
Michael Chan0d8a6572007-07-07 22:49:43 -07004646
Michael Chan7c62e832008-07-14 22:39:03 -07004647 link = bnx2_shmem_rd(bp, BNX2_LINK_STATUS);
4648 if (link & BNX2_LINK_STATUS_SERDES_LINK)
Michael Chan0d8a6572007-07-07 22:49:43 -07004649 bp->phy_port = PORT_FIBRE;
4650 else
4651 bp->phy_port = PORT_TP;
Michael Chan489310a2007-10-10 16:16:31 -07004652
Michael Chan7c62e832008-07-14 22:39:03 -07004653 sig |= BNX2_DRV_ACK_CAP_SIGNATURE |
4654 BNX2_FW_CAP_REMOTE_PHY_CAPABLE;
Michael Chan0d8a6572007-07-07 22:49:43 -07004655 }
Michael Chan7c62e832008-07-14 22:39:03 -07004656
4657 if (netif_running(bp->dev) && sig)
4658 bnx2_shmem_wr(bp, BNX2_DRV_ACK_CAP_MB, sig);
Michael Chan0d8a6572007-07-07 22:49:43 -07004659}
4660
Michael Chanb4b36042007-12-20 19:59:30 -08004661static void
4662bnx2_setup_msix_tbl(struct bnx2 *bp)
4663{
4664 REG_WR(bp, BNX2_PCI_GRC_WINDOW_ADDR, BNX2_PCI_GRC_WINDOW_ADDR_SEP_WIN);
4665
4666 REG_WR(bp, BNX2_PCI_GRC_WINDOW2_ADDR, BNX2_MSIX_TABLE_ADDR);
4667 REG_WR(bp, BNX2_PCI_GRC_WINDOW3_ADDR, BNX2_MSIX_PBA_ADDR);
4668}
4669
Michael Chanb6016b72005-05-26 13:03:09 -07004670static int
4671bnx2_reset_chip(struct bnx2 *bp, u32 reset_code)
4672{
4673 u32 val;
4674 int i, rc = 0;
Michael Chan489310a2007-10-10 16:16:31 -07004675 u8 old_port;
Michael Chanb6016b72005-05-26 13:03:09 -07004676
4677 /* Wait for the current PCI transaction to complete before
4678 * issuing a reset. */
4679 REG_WR(bp, BNX2_MISC_ENABLE_CLR_BITS,
4680 BNX2_MISC_ENABLE_CLR_BITS_TX_DMA_ENABLE |
4681 BNX2_MISC_ENABLE_CLR_BITS_DMA_ENGINE_ENABLE |
4682 BNX2_MISC_ENABLE_CLR_BITS_RX_DMA_ENABLE |
4683 BNX2_MISC_ENABLE_CLR_BITS_HOST_COALESCE_ENABLE);
4684 val = REG_RD(bp, BNX2_MISC_ENABLE_CLR_BITS);
4685 udelay(5);
4686
Michael Chanb090ae22006-01-23 16:07:10 -08004687 /* Wait for the firmware to tell us it is ok to issue a reset. */
Michael Chana2f13892008-07-14 22:38:23 -07004688 bnx2_fw_sync(bp, BNX2_DRV_MSG_DATA_WAIT0 | reset_code, 1, 1);
Michael Chanb090ae22006-01-23 16:07:10 -08004689
Michael Chanb6016b72005-05-26 13:03:09 -07004690 /* Deposit a driver reset signature so the firmware knows that
4691 * this is a soft reset. */
Michael Chan2726d6e2008-01-29 21:35:05 -08004692 bnx2_shmem_wr(bp, BNX2_DRV_RESET_SIGNATURE,
4693 BNX2_DRV_RESET_SIGNATURE_MAGIC);
Michael Chanb6016b72005-05-26 13:03:09 -07004694
Michael Chanb6016b72005-05-26 13:03:09 -07004695 /* Do a dummy read to force the chip to complete all current transaction
4696 * before we issue a reset. */
4697 val = REG_RD(bp, BNX2_MISC_ID);
4698
Michael Chan234754d2006-11-19 14:11:41 -08004699 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
4700 REG_WR(bp, BNX2_MISC_COMMAND, BNX2_MISC_COMMAND_SW_RESET);
4701 REG_RD(bp, BNX2_MISC_COMMAND);
4702 udelay(5);
Michael Chanb6016b72005-05-26 13:03:09 -07004703
Michael Chan234754d2006-11-19 14:11:41 -08004704 val = BNX2_PCICFG_MISC_CONFIG_REG_WINDOW_ENA |
4705 BNX2_PCICFG_MISC_CONFIG_TARGET_MB_WORD_SWAP;
Michael Chanb6016b72005-05-26 13:03:09 -07004706
Michael Chan234754d2006-11-19 14:11:41 -08004707 pci_write_config_dword(bp->pdev, BNX2_PCICFG_MISC_CONFIG, val);
Michael Chanb6016b72005-05-26 13:03:09 -07004708
Michael Chan234754d2006-11-19 14:11:41 -08004709 } else {
4710 val = BNX2_PCICFG_MISC_CONFIG_CORE_RST_REQ |
4711 BNX2_PCICFG_MISC_CONFIG_REG_WINDOW_ENA |
4712 BNX2_PCICFG_MISC_CONFIG_TARGET_MB_WORD_SWAP;
4713
4714 /* Chip reset. */
4715 REG_WR(bp, BNX2_PCICFG_MISC_CONFIG, val);
4716
Michael Chan594a9df2007-08-28 15:39:42 -07004717 /* Reading back any register after chip reset will hang the
4718 * bus on 5706 A0 and A1. The msleep below provides plenty
4719 * of margin for write posting.
4720 */
Michael Chan234754d2006-11-19 14:11:41 -08004721 if ((CHIP_ID(bp) == CHIP_ID_5706_A0) ||
Arjan van de Ven8e545882007-08-28 14:34:43 -07004722 (CHIP_ID(bp) == CHIP_ID_5706_A1))
4723 msleep(20);
Michael Chanb6016b72005-05-26 13:03:09 -07004724
Michael Chan234754d2006-11-19 14:11:41 -08004725 /* Reset takes approximate 30 usec */
4726 for (i = 0; i < 10; i++) {
4727 val = REG_RD(bp, BNX2_PCICFG_MISC_CONFIG);
4728 if ((val & (BNX2_PCICFG_MISC_CONFIG_CORE_RST_REQ |
4729 BNX2_PCICFG_MISC_CONFIG_CORE_RST_BSY)) == 0)
4730 break;
4731 udelay(10);
4732 }
4733
4734 if (val & (BNX2_PCICFG_MISC_CONFIG_CORE_RST_REQ |
4735 BNX2_PCICFG_MISC_CONFIG_CORE_RST_BSY)) {
Joe Perches3a9c6a42010-02-17 15:01:51 +00004736 pr_err("Chip reset did not complete\n");
Michael Chan234754d2006-11-19 14:11:41 -08004737 return -EBUSY;
4738 }
Michael Chanb6016b72005-05-26 13:03:09 -07004739 }
4740
4741 /* Make sure byte swapping is properly configured. */
4742 val = REG_RD(bp, BNX2_PCI_SWAP_DIAG0);
4743 if (val != 0x01020304) {
Joe Perches3a9c6a42010-02-17 15:01:51 +00004744 pr_err("Chip not in correct endian mode\n");
Michael Chanb6016b72005-05-26 13:03:09 -07004745 return -ENODEV;
4746 }
4747
Michael Chanb6016b72005-05-26 13:03:09 -07004748 /* Wait for the firmware to finish its initialization. */
Michael Chana2f13892008-07-14 22:38:23 -07004749 rc = bnx2_fw_sync(bp, BNX2_DRV_MSG_DATA_WAIT1 | reset_code, 1, 0);
Michael Chanb090ae22006-01-23 16:07:10 -08004750 if (rc)
4751 return rc;
Michael Chanb6016b72005-05-26 13:03:09 -07004752
Michael Chan0d8a6572007-07-07 22:49:43 -07004753 spin_lock_bh(&bp->phy_lock);
Michael Chan489310a2007-10-10 16:16:31 -07004754 old_port = bp->phy_port;
Michael Chan7c62e832008-07-14 22:39:03 -07004755 bnx2_init_fw_cap(bp);
Michael Chan583c28e2008-01-21 19:51:35 -08004756 if ((bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP) &&
4757 old_port != bp->phy_port)
Michael Chan0d8a6572007-07-07 22:49:43 -07004758 bnx2_set_default_remote_link(bp);
4759 spin_unlock_bh(&bp->phy_lock);
4760
Michael Chanb6016b72005-05-26 13:03:09 -07004761 if (CHIP_ID(bp) == CHIP_ID_5706_A0) {
4762 /* Adjust the voltage regular to two steps lower. The default
4763 * of this register is 0x0000000e. */
4764 REG_WR(bp, BNX2_MISC_VREG_CONTROL, 0x000000fa);
4765
4766 /* Remove bad rbuf memory from the free pool. */
4767 rc = bnx2_alloc_bad_rbuf(bp);
4768 }
4769
Michael Chanc441b8d2010-04-27 11:28:09 +00004770 if (bp->flags & BNX2_FLAG_USING_MSIX) {
Michael Chanb4b36042007-12-20 19:59:30 -08004771 bnx2_setup_msix_tbl(bp);
Michael Chanc441b8d2010-04-27 11:28:09 +00004772 /* Prevent MSIX table reads and write from timing out */
4773 REG_WR(bp, BNX2_MISC_ECO_HW_CTL,
4774 BNX2_MISC_ECO_HW_CTL_LARGE_GRC_TMOUT_EN);
4775 }
Michael Chanb4b36042007-12-20 19:59:30 -08004776
Michael Chanb6016b72005-05-26 13:03:09 -07004777 return rc;
4778}
4779
4780static int
4781bnx2_init_chip(struct bnx2 *bp)
4782{
Michael Chand8026d92008-11-12 16:02:20 -08004783 u32 val, mtu;
Michael Chanb4b36042007-12-20 19:59:30 -08004784 int rc, i;
Michael Chanb6016b72005-05-26 13:03:09 -07004785
4786 /* Make sure the interrupt is not active. */
4787 REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD, BNX2_PCICFG_INT_ACK_CMD_MASK_INT);
4788
4789 val = BNX2_DMA_CONFIG_DATA_BYTE_SWAP |
4790 BNX2_DMA_CONFIG_DATA_WORD_SWAP |
4791#ifdef __BIG_ENDIAN
Jeff Garzik6aa20a22006-09-13 13:24:59 -04004792 BNX2_DMA_CONFIG_CNTL_BYTE_SWAP |
Michael Chanb6016b72005-05-26 13:03:09 -07004793#endif
Jeff Garzik6aa20a22006-09-13 13:24:59 -04004794 BNX2_DMA_CONFIG_CNTL_WORD_SWAP |
Michael Chanb6016b72005-05-26 13:03:09 -07004795 DMA_READ_CHANS << 12 |
4796 DMA_WRITE_CHANS << 16;
4797
4798 val |= (0x2 << 20) | (1 << 11);
4799
David S. Millerf86e82f2008-01-21 17:15:40 -08004800 if ((bp->flags & BNX2_FLAG_PCIX) && (bp->bus_speed_mhz == 133))
Michael Chanb6016b72005-05-26 13:03:09 -07004801 val |= (1 << 23);
4802
4803 if ((CHIP_NUM(bp) == CHIP_NUM_5706) &&
David S. Millerf86e82f2008-01-21 17:15:40 -08004804 (CHIP_ID(bp) != CHIP_ID_5706_A0) && !(bp->flags & BNX2_FLAG_PCIX))
Michael Chanb6016b72005-05-26 13:03:09 -07004805 val |= BNX2_DMA_CONFIG_CNTL_PING_PONG_DMA;
4806
4807 REG_WR(bp, BNX2_DMA_CONFIG, val);
4808
4809 if (CHIP_ID(bp) == CHIP_ID_5706_A0) {
4810 val = REG_RD(bp, BNX2_TDMA_CONFIG);
4811 val |= BNX2_TDMA_CONFIG_ONE_DMA;
4812 REG_WR(bp, BNX2_TDMA_CONFIG, val);
4813 }
4814
David S. Millerf86e82f2008-01-21 17:15:40 -08004815 if (bp->flags & BNX2_FLAG_PCIX) {
Michael Chanb6016b72005-05-26 13:03:09 -07004816 u16 val16;
4817
4818 pci_read_config_word(bp->pdev, bp->pcix_cap + PCI_X_CMD,
4819 &val16);
4820 pci_write_config_word(bp->pdev, bp->pcix_cap + PCI_X_CMD,
4821 val16 & ~PCI_X_CMD_ERO);
4822 }
4823
4824 REG_WR(bp, BNX2_MISC_ENABLE_SET_BITS,
4825 BNX2_MISC_ENABLE_SET_BITS_HOST_COALESCE_ENABLE |
4826 BNX2_MISC_ENABLE_STATUS_BITS_RX_V2P_ENABLE |
4827 BNX2_MISC_ENABLE_STATUS_BITS_CONTEXT_ENABLE);
4828
4829 /* Initialize context mapping and zero out the quick contexts. The
4830 * context block must have already been enabled. */
Michael Chan641bdcd2007-06-04 21:22:24 -07004831 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
4832 rc = bnx2_init_5709_context(bp);
4833 if (rc)
4834 return rc;
4835 } else
Michael Chan59b47d82006-11-19 14:10:45 -08004836 bnx2_init_context(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07004837
Michael Chanfba9fe92006-06-12 22:21:25 -07004838 if ((rc = bnx2_init_cpus(bp)) != 0)
4839 return rc;
4840
Michael Chanb6016b72005-05-26 13:03:09 -07004841 bnx2_init_nvram(bp);
4842
Benjamin Li5fcaed02008-07-14 22:39:52 -07004843 bnx2_set_mac_addr(bp, bp->dev->dev_addr, 0);
Michael Chanb6016b72005-05-26 13:03:09 -07004844
4845 val = REG_RD(bp, BNX2_MQ_CONFIG);
4846 val &= ~BNX2_MQ_CONFIG_KNL_BYP_BLK_SIZE;
4847 val |= BNX2_MQ_CONFIG_KNL_BYP_BLK_SIZE_256;
Michael Chan4edd4732009-06-08 18:14:42 -07004848 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
4849 val |= BNX2_MQ_CONFIG_BIN_MQ_MODE;
4850 if (CHIP_REV(bp) == CHIP_REV_Ax)
4851 val |= BNX2_MQ_CONFIG_HALT_DIS;
4852 }
Michael Chan68c9f752007-04-24 15:35:53 -07004853
Michael Chanb6016b72005-05-26 13:03:09 -07004854 REG_WR(bp, BNX2_MQ_CONFIG, val);
4855
4856 val = 0x10000 + (MAX_CID_CNT * MB_KERNEL_CTX_SIZE);
4857 REG_WR(bp, BNX2_MQ_KNL_BYP_WIND_START, val);
4858 REG_WR(bp, BNX2_MQ_KNL_WIND_END, val);
4859
4860 val = (BCM_PAGE_BITS - 8) << 24;
4861 REG_WR(bp, BNX2_RV2P_CONFIG, val);
4862
4863 /* Configure page size. */
4864 val = REG_RD(bp, BNX2_TBDR_CONFIG);
4865 val &= ~BNX2_TBDR_CONFIG_PAGE_SIZE;
4866 val |= (BCM_PAGE_BITS - 8) << 24 | 0x40;
4867 REG_WR(bp, BNX2_TBDR_CONFIG, val);
4868
4869 val = bp->mac_addr[0] +
4870 (bp->mac_addr[1] << 8) +
4871 (bp->mac_addr[2] << 16) +
4872 bp->mac_addr[3] +
4873 (bp->mac_addr[4] << 8) +
4874 (bp->mac_addr[5] << 16);
4875 REG_WR(bp, BNX2_EMAC_BACKOFF_SEED, val);
4876
4877 /* Program the MTU. Also include 4 bytes for CRC32. */
Michael Chand8026d92008-11-12 16:02:20 -08004878 mtu = bp->dev->mtu;
4879 val = mtu + ETH_HLEN + ETH_FCS_LEN;
Michael Chanb6016b72005-05-26 13:03:09 -07004880 if (val > (MAX_ETHERNET_PACKET_SIZE + 4))
4881 val |= BNX2_EMAC_RX_MTU_SIZE_JUMBO_ENA;
4882 REG_WR(bp, BNX2_EMAC_RX_MTU_SIZE, val);
4883
Michael Chand8026d92008-11-12 16:02:20 -08004884 if (mtu < 1500)
4885 mtu = 1500;
4886
4887 bnx2_reg_wr_ind(bp, BNX2_RBUF_CONFIG, BNX2_RBUF_CONFIG_VAL(mtu));
4888 bnx2_reg_wr_ind(bp, BNX2_RBUF_CONFIG2, BNX2_RBUF_CONFIG2_VAL(mtu));
4889 bnx2_reg_wr_ind(bp, BNX2_RBUF_CONFIG3, BNX2_RBUF_CONFIG3_VAL(mtu));
4890
Michael Chan155d5562009-08-21 16:20:43 +00004891 memset(bp->bnx2_napi[0].status_blk.msi, 0, bp->status_stats_size);
Michael Chanb4b36042007-12-20 19:59:30 -08004892 for (i = 0; i < BNX2_MAX_MSIX_VEC; i++)
4893 bp->bnx2_napi[i].last_status_idx = 0;
4894
Michael Chanefba0182008-12-03 00:36:15 -08004895 bp->idle_chk_status_idx = 0xffff;
4896
Michael Chanb6016b72005-05-26 13:03:09 -07004897 bp->rx_mode = BNX2_EMAC_RX_MODE_SORT_MODE;
4898
4899 /* Set up how to generate a link change interrupt. */
4900 REG_WR(bp, BNX2_EMAC_ATTENTION_ENA, BNX2_EMAC_ATTENTION_ENA_LINK);
4901
4902 REG_WR(bp, BNX2_HC_STATUS_ADDR_L,
4903 (u64) bp->status_blk_mapping & 0xffffffff);
4904 REG_WR(bp, BNX2_HC_STATUS_ADDR_H, (u64) bp->status_blk_mapping >> 32);
4905
4906 REG_WR(bp, BNX2_HC_STATISTICS_ADDR_L,
4907 (u64) bp->stats_blk_mapping & 0xffffffff);
4908 REG_WR(bp, BNX2_HC_STATISTICS_ADDR_H,
4909 (u64) bp->stats_blk_mapping >> 32);
4910
Jeff Garzik6aa20a22006-09-13 13:24:59 -04004911 REG_WR(bp, BNX2_HC_TX_QUICK_CONS_TRIP,
Michael Chanb6016b72005-05-26 13:03:09 -07004912 (bp->tx_quick_cons_trip_int << 16) | bp->tx_quick_cons_trip);
4913
4914 REG_WR(bp, BNX2_HC_RX_QUICK_CONS_TRIP,
4915 (bp->rx_quick_cons_trip_int << 16) | bp->rx_quick_cons_trip);
4916
4917 REG_WR(bp, BNX2_HC_COMP_PROD_TRIP,
4918 (bp->comp_prod_trip_int << 16) | bp->comp_prod_trip);
4919
4920 REG_WR(bp, BNX2_HC_TX_TICKS, (bp->tx_ticks_int << 16) | bp->tx_ticks);
4921
4922 REG_WR(bp, BNX2_HC_RX_TICKS, (bp->rx_ticks_int << 16) | bp->rx_ticks);
4923
4924 REG_WR(bp, BNX2_HC_COM_TICKS,
4925 (bp->com_ticks_int << 16) | bp->com_ticks);
4926
4927 REG_WR(bp, BNX2_HC_CMD_TICKS,
4928 (bp->cmd_ticks_int << 16) | bp->cmd_ticks);
4929
Michael Chan61d9e3f2009-08-21 16:20:46 +00004930 if (bp->flags & BNX2_FLAG_BROKEN_STATS)
Michael Chan02537b062007-06-04 21:24:07 -07004931 REG_WR(bp, BNX2_HC_STATS_TICKS, 0);
4932 else
Michael Chan7ea69202007-07-16 18:27:10 -07004933 REG_WR(bp, BNX2_HC_STATS_TICKS, bp->stats_ticks);
Michael Chanb6016b72005-05-26 13:03:09 -07004934 REG_WR(bp, BNX2_HC_STAT_COLLECT_TICKS, 0xbb8); /* 3ms */
4935
4936 if (CHIP_ID(bp) == CHIP_ID_5706_A1)
Michael Chan8e6a72c2007-05-03 13:24:48 -07004937 val = BNX2_HC_CONFIG_COLLECT_STATS;
Michael Chanb6016b72005-05-26 13:03:09 -07004938 else {
Michael Chan8e6a72c2007-05-03 13:24:48 -07004939 val = BNX2_HC_CONFIG_RX_TMR_MODE | BNX2_HC_CONFIG_TX_TMR_MODE |
4940 BNX2_HC_CONFIG_COLLECT_STATS;
Michael Chanb6016b72005-05-26 13:03:09 -07004941 }
4942
Michael Chanefde73a2010-02-15 19:42:07 +00004943 if (bp->flags & BNX2_FLAG_USING_MSIX) {
Michael Chanc76c0472007-12-20 20:01:19 -08004944 REG_WR(bp, BNX2_HC_MSIX_BIT_VECTOR,
4945 BNX2_HC_MSIX_BIT_VECTOR_VAL);
4946
Michael Chan5e9ad9e2008-06-19 16:43:17 -07004947 val |= BNX2_HC_CONFIG_SB_ADDR_INC_128B;
4948 }
4949
4950 if (bp->flags & BNX2_FLAG_ONE_SHOT_MSI)
Michael Chancf7474a2009-08-21 16:20:48 +00004951 val |= BNX2_HC_CONFIG_ONE_SHOT | BNX2_HC_CONFIG_USE_INT_PARAM;
Michael Chan5e9ad9e2008-06-19 16:43:17 -07004952
4953 REG_WR(bp, BNX2_HC_CONFIG, val);
4954
4955 for (i = 1; i < bp->irq_nvecs; i++) {
4956 u32 base = ((i - 1) * BNX2_HC_SB_CONFIG_SIZE) +
4957 BNX2_HC_SB_CONFIG_1;
4958
Michael Chan6f743ca2008-01-29 21:34:08 -08004959 REG_WR(bp, base,
Michael Chanc76c0472007-12-20 20:01:19 -08004960 BNX2_HC_SB_CONFIG_1_TX_TMR_MODE |
Michael Chan5e9ad9e2008-06-19 16:43:17 -07004961 BNX2_HC_SB_CONFIG_1_RX_TMR_MODE |
Michael Chanc76c0472007-12-20 20:01:19 -08004962 BNX2_HC_SB_CONFIG_1_ONE_SHOT);
4963
Michael Chan6f743ca2008-01-29 21:34:08 -08004964 REG_WR(bp, base + BNX2_HC_TX_QUICK_CONS_TRIP_OFF,
Michael Chanc76c0472007-12-20 20:01:19 -08004965 (bp->tx_quick_cons_trip_int << 16) |
4966 bp->tx_quick_cons_trip);
4967
Michael Chan6f743ca2008-01-29 21:34:08 -08004968 REG_WR(bp, base + BNX2_HC_TX_TICKS_OFF,
Michael Chanc76c0472007-12-20 20:01:19 -08004969 (bp->tx_ticks_int << 16) | bp->tx_ticks);
4970
Michael Chan5e9ad9e2008-06-19 16:43:17 -07004971 REG_WR(bp, base + BNX2_HC_RX_QUICK_CONS_TRIP_OFF,
4972 (bp->rx_quick_cons_trip_int << 16) |
4973 bp->rx_quick_cons_trip);
4974
4975 REG_WR(bp, base + BNX2_HC_RX_TICKS_OFF,
4976 (bp->rx_ticks_int << 16) | bp->rx_ticks);
Michael Chanc76c0472007-12-20 20:01:19 -08004977 }
4978
Michael Chanb6016b72005-05-26 13:03:09 -07004979 /* Clear internal stats counters. */
4980 REG_WR(bp, BNX2_HC_COMMAND, BNX2_HC_COMMAND_CLR_STAT_NOW);
4981
Michael Chanda3e4fb2007-05-03 13:24:23 -07004982 REG_WR(bp, BNX2_HC_ATTN_BITS_ENABLE, STATUS_ATTN_EVENTS);
Michael Chanb6016b72005-05-26 13:03:09 -07004983
4984 /* Initialize the receive filter. */
4985 bnx2_set_rx_mode(bp->dev);
4986
Michael Chan0aa38df2007-06-04 21:23:06 -07004987 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
4988 val = REG_RD(bp, BNX2_MISC_NEW_CORE_CTL);
4989 val |= BNX2_MISC_NEW_CORE_CTL_DMA_ENABLE;
4990 REG_WR(bp, BNX2_MISC_NEW_CORE_CTL, val);
4991 }
Michael Chanb090ae22006-01-23 16:07:10 -08004992 rc = bnx2_fw_sync(bp, BNX2_DRV_MSG_DATA_WAIT2 | BNX2_DRV_MSG_CODE_RESET,
Michael Chana2f13892008-07-14 22:38:23 -07004993 1, 0);
Michael Chanb6016b72005-05-26 13:03:09 -07004994
Michael Chandf149d72007-07-07 22:51:36 -07004995 REG_WR(bp, BNX2_MISC_ENABLE_SET_BITS, BNX2_MISC_ENABLE_DEFAULT);
Michael Chanb6016b72005-05-26 13:03:09 -07004996 REG_RD(bp, BNX2_MISC_ENABLE_SET_BITS);
4997
4998 udelay(20);
4999
Michael Chanbf5295b2006-03-23 01:11:56 -08005000 bp->hc_cmd = REG_RD(bp, BNX2_HC_COMMAND);
5001
Michael Chanb090ae22006-01-23 16:07:10 -08005002 return rc;
Michael Chanb6016b72005-05-26 13:03:09 -07005003}
5004
Michael Chan59b47d82006-11-19 14:10:45 -08005005static void
Michael Chanc76c0472007-12-20 20:01:19 -08005006bnx2_clear_ring_states(struct bnx2 *bp)
5007{
5008 struct bnx2_napi *bnapi;
Michael Chan35e90102008-06-19 16:37:42 -07005009 struct bnx2_tx_ring_info *txr;
Michael Chanbb4f98a2008-06-19 16:38:19 -07005010 struct bnx2_rx_ring_info *rxr;
Michael Chanc76c0472007-12-20 20:01:19 -08005011 int i;
5012
5013 for (i = 0; i < BNX2_MAX_MSIX_VEC; i++) {
5014 bnapi = &bp->bnx2_napi[i];
Michael Chan35e90102008-06-19 16:37:42 -07005015 txr = &bnapi->tx_ring;
Michael Chanbb4f98a2008-06-19 16:38:19 -07005016 rxr = &bnapi->rx_ring;
Michael Chanc76c0472007-12-20 20:01:19 -08005017
Michael Chan35e90102008-06-19 16:37:42 -07005018 txr->tx_cons = 0;
5019 txr->hw_tx_cons = 0;
Michael Chanbb4f98a2008-06-19 16:38:19 -07005020 rxr->rx_prod_bseq = 0;
5021 rxr->rx_prod = 0;
5022 rxr->rx_cons = 0;
5023 rxr->rx_pg_prod = 0;
5024 rxr->rx_pg_cons = 0;
Michael Chanc76c0472007-12-20 20:01:19 -08005025 }
5026}
5027
5028static void
Michael Chan35e90102008-06-19 16:37:42 -07005029bnx2_init_tx_context(struct bnx2 *bp, u32 cid, struct bnx2_tx_ring_info *txr)
Michael Chan59b47d82006-11-19 14:10:45 -08005030{
5031 u32 val, offset0, offset1, offset2, offset3;
Michael Chan62a83132008-01-29 21:35:40 -08005032 u32 cid_addr = GET_CID_ADDR(cid);
Michael Chan59b47d82006-11-19 14:10:45 -08005033
5034 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
5035 offset0 = BNX2_L2CTX_TYPE_XI;
5036 offset1 = BNX2_L2CTX_CMD_TYPE_XI;
5037 offset2 = BNX2_L2CTX_TBDR_BHADDR_HI_XI;
5038 offset3 = BNX2_L2CTX_TBDR_BHADDR_LO_XI;
5039 } else {
5040 offset0 = BNX2_L2CTX_TYPE;
5041 offset1 = BNX2_L2CTX_CMD_TYPE;
5042 offset2 = BNX2_L2CTX_TBDR_BHADDR_HI;
5043 offset3 = BNX2_L2CTX_TBDR_BHADDR_LO;
5044 }
5045 val = BNX2_L2CTX_TYPE_TYPE_L2 | BNX2_L2CTX_TYPE_SIZE_L2;
Michael Chan62a83132008-01-29 21:35:40 -08005046 bnx2_ctx_wr(bp, cid_addr, offset0, val);
Michael Chan59b47d82006-11-19 14:10:45 -08005047
5048 val = BNX2_L2CTX_CMD_TYPE_TYPE_L2 | (8 << 16);
Michael Chan62a83132008-01-29 21:35:40 -08005049 bnx2_ctx_wr(bp, cid_addr, offset1, val);
Michael Chan59b47d82006-11-19 14:10:45 -08005050
Michael Chan35e90102008-06-19 16:37:42 -07005051 val = (u64) txr->tx_desc_mapping >> 32;
Michael Chan62a83132008-01-29 21:35:40 -08005052 bnx2_ctx_wr(bp, cid_addr, offset2, val);
Michael Chan59b47d82006-11-19 14:10:45 -08005053
Michael Chan35e90102008-06-19 16:37:42 -07005054 val = (u64) txr->tx_desc_mapping & 0xffffffff;
Michael Chan62a83132008-01-29 21:35:40 -08005055 bnx2_ctx_wr(bp, cid_addr, offset3, val);
Michael Chan59b47d82006-11-19 14:10:45 -08005056}
Michael Chanb6016b72005-05-26 13:03:09 -07005057
5058static void
Michael Chan35e90102008-06-19 16:37:42 -07005059bnx2_init_tx_ring(struct bnx2 *bp, int ring_num)
Michael Chanb6016b72005-05-26 13:03:09 -07005060{
5061 struct tx_bd *txbd;
Michael Chanc76c0472007-12-20 20:01:19 -08005062 u32 cid = TX_CID;
5063 struct bnx2_napi *bnapi;
Michael Chan35e90102008-06-19 16:37:42 -07005064 struct bnx2_tx_ring_info *txr;
Michael Chanc76c0472007-12-20 20:01:19 -08005065
Michael Chan35e90102008-06-19 16:37:42 -07005066 bnapi = &bp->bnx2_napi[ring_num];
5067 txr = &bnapi->tx_ring;
5068
5069 if (ring_num == 0)
5070 cid = TX_CID;
5071 else
5072 cid = TX_TSS_CID + ring_num - 1;
Michael Chanb6016b72005-05-26 13:03:09 -07005073
Michael Chan2f8af122006-08-15 01:39:10 -07005074 bp->tx_wake_thresh = bp->tx_ring_size / 2;
5075
Michael Chan35e90102008-06-19 16:37:42 -07005076 txbd = &txr->tx_desc_ring[MAX_TX_DESC_CNT];
Jeff Garzik6aa20a22006-09-13 13:24:59 -04005077
Michael Chan35e90102008-06-19 16:37:42 -07005078 txbd->tx_bd_haddr_hi = (u64) txr->tx_desc_mapping >> 32;
5079 txbd->tx_bd_haddr_lo = (u64) txr->tx_desc_mapping & 0xffffffff;
Michael Chanb6016b72005-05-26 13:03:09 -07005080
Michael Chan35e90102008-06-19 16:37:42 -07005081 txr->tx_prod = 0;
5082 txr->tx_prod_bseq = 0;
Jeff Garzik6aa20a22006-09-13 13:24:59 -04005083
Michael Chan35e90102008-06-19 16:37:42 -07005084 txr->tx_bidx_addr = MB_GET_CID_ADDR(cid) + BNX2_L2CTX_TX_HOST_BIDX;
5085 txr->tx_bseq_addr = MB_GET_CID_ADDR(cid) + BNX2_L2CTX_TX_HOST_BSEQ;
Michael Chanb6016b72005-05-26 13:03:09 -07005086
Michael Chan35e90102008-06-19 16:37:42 -07005087 bnx2_init_tx_context(bp, cid, txr);
Michael Chanb6016b72005-05-26 13:03:09 -07005088}
5089
5090static void
Michael Chan5d5d0012007-12-12 11:17:43 -08005091bnx2_init_rxbd_rings(struct rx_bd *rx_ring[], dma_addr_t dma[], u32 buf_size,
5092 int num_rings)
Michael Chanb6016b72005-05-26 13:03:09 -07005093{
Michael Chanb6016b72005-05-26 13:03:09 -07005094 int i;
Michael Chan5d5d0012007-12-12 11:17:43 -08005095 struct rx_bd *rxbd;
Michael Chanb6016b72005-05-26 13:03:09 -07005096
Michael Chan5d5d0012007-12-12 11:17:43 -08005097 for (i = 0; i < num_rings; i++) {
Michael Chan13daffa2006-03-20 17:49:20 -08005098 int j;
Michael Chanb6016b72005-05-26 13:03:09 -07005099
Michael Chan5d5d0012007-12-12 11:17:43 -08005100 rxbd = &rx_ring[i][0];
Michael Chan13daffa2006-03-20 17:49:20 -08005101 for (j = 0; j < MAX_RX_DESC_CNT; j++, rxbd++) {
Michael Chan5d5d0012007-12-12 11:17:43 -08005102 rxbd->rx_bd_len = buf_size;
Michael Chan13daffa2006-03-20 17:49:20 -08005103 rxbd->rx_bd_flags = RX_BD_FLAGS_START | RX_BD_FLAGS_END;
5104 }
Michael Chan5d5d0012007-12-12 11:17:43 -08005105 if (i == (num_rings - 1))
Michael Chan13daffa2006-03-20 17:49:20 -08005106 j = 0;
5107 else
5108 j = i + 1;
Michael Chan5d5d0012007-12-12 11:17:43 -08005109 rxbd->rx_bd_haddr_hi = (u64) dma[j] >> 32;
5110 rxbd->rx_bd_haddr_lo = (u64) dma[j] & 0xffffffff;
Michael Chan13daffa2006-03-20 17:49:20 -08005111 }
Michael Chan5d5d0012007-12-12 11:17:43 -08005112}
5113
5114static void
Michael Chanbb4f98a2008-06-19 16:38:19 -07005115bnx2_init_rx_ring(struct bnx2 *bp, int ring_num)
Michael Chan5d5d0012007-12-12 11:17:43 -08005116{
5117 int i;
5118 u16 prod, ring_prod;
Michael Chanbb4f98a2008-06-19 16:38:19 -07005119 u32 cid, rx_cid_addr, val;
5120 struct bnx2_napi *bnapi = &bp->bnx2_napi[ring_num];
5121 struct bnx2_rx_ring_info *rxr = &bnapi->rx_ring;
Michael Chan5d5d0012007-12-12 11:17:43 -08005122
Michael Chanbb4f98a2008-06-19 16:38:19 -07005123 if (ring_num == 0)
5124 cid = RX_CID;
5125 else
5126 cid = RX_RSS_CID + ring_num - 1;
5127
5128 rx_cid_addr = GET_CID_ADDR(cid);
5129
5130 bnx2_init_rxbd_rings(rxr->rx_desc_ring, rxr->rx_desc_mapping,
Michael Chan5d5d0012007-12-12 11:17:43 -08005131 bp->rx_buf_use_size, bp->rx_max_ring);
5132
Michael Chanbb4f98a2008-06-19 16:38:19 -07005133 bnx2_init_rx_context(bp, cid);
Michael Chan83e3fc82008-01-29 21:37:17 -08005134
5135 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
5136 val = REG_RD(bp, BNX2_MQ_MAP_L2_5);
5137 REG_WR(bp, BNX2_MQ_MAP_L2_5, val | BNX2_MQ_MAP_L2_5_ARM);
5138 }
5139
Michael Chan62a83132008-01-29 21:35:40 -08005140 bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_PG_BUF_SIZE, 0);
Michael Chan47bf4242007-12-12 11:19:12 -08005141 if (bp->rx_pg_ring_size) {
Michael Chanbb4f98a2008-06-19 16:38:19 -07005142 bnx2_init_rxbd_rings(rxr->rx_pg_desc_ring,
5143 rxr->rx_pg_desc_mapping,
Michael Chan47bf4242007-12-12 11:19:12 -08005144 PAGE_SIZE, bp->rx_max_pg_ring);
5145 val = (bp->rx_buf_use_size << 16) | PAGE_SIZE;
Michael Chan62a83132008-01-29 21:35:40 -08005146 bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_PG_BUF_SIZE, val);
5147 bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_RBDC_KEY,
Michael Chan5e9ad9e2008-06-19 16:43:17 -07005148 BNX2_L2CTX_RBDC_JUMBO_KEY - ring_num);
Michael Chan47bf4242007-12-12 11:19:12 -08005149
Michael Chanbb4f98a2008-06-19 16:38:19 -07005150 val = (u64) rxr->rx_pg_desc_mapping[0] >> 32;
Michael Chan62a83132008-01-29 21:35:40 -08005151 bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_NX_PG_BDHADDR_HI, val);
Michael Chan47bf4242007-12-12 11:19:12 -08005152
Michael Chanbb4f98a2008-06-19 16:38:19 -07005153 val = (u64) rxr->rx_pg_desc_mapping[0] & 0xffffffff;
Michael Chan62a83132008-01-29 21:35:40 -08005154 bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_NX_PG_BDHADDR_LO, val);
Michael Chan47bf4242007-12-12 11:19:12 -08005155
5156 if (CHIP_NUM(bp) == CHIP_NUM_5709)
5157 REG_WR(bp, BNX2_MQ_MAP_L2_3, BNX2_MQ_MAP_L2_3_DEFAULT);
5158 }
Michael Chanb6016b72005-05-26 13:03:09 -07005159
Michael Chanbb4f98a2008-06-19 16:38:19 -07005160 val = (u64) rxr->rx_desc_mapping[0] >> 32;
Michael Chan62a83132008-01-29 21:35:40 -08005161 bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_NX_BDHADDR_HI, val);
Michael Chanb6016b72005-05-26 13:03:09 -07005162
Michael Chanbb4f98a2008-06-19 16:38:19 -07005163 val = (u64) rxr->rx_desc_mapping[0] & 0xffffffff;
Michael Chan62a83132008-01-29 21:35:40 -08005164 bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_NX_BDHADDR_LO, val);
Michael Chanb6016b72005-05-26 13:03:09 -07005165
Michael Chanbb4f98a2008-06-19 16:38:19 -07005166 ring_prod = prod = rxr->rx_pg_prod;
Michael Chan47bf4242007-12-12 11:19:12 -08005167 for (i = 0; i < bp->rx_pg_ring_size; i++) {
Michael Chanb929e532009-12-03 09:46:33 +00005168 if (bnx2_alloc_rx_page(bp, rxr, ring_prod) < 0) {
Joe Perches3a9c6a42010-02-17 15:01:51 +00005169 netdev_warn(bp->dev, "init'ed rx page ring %d with %d/%d pages only\n",
5170 ring_num, i, bp->rx_pg_ring_size);
Michael Chan47bf4242007-12-12 11:19:12 -08005171 break;
Michael Chanb929e532009-12-03 09:46:33 +00005172 }
Michael Chan47bf4242007-12-12 11:19:12 -08005173 prod = NEXT_RX_BD(prod);
5174 ring_prod = RX_PG_RING_IDX(prod);
5175 }
Michael Chanbb4f98a2008-06-19 16:38:19 -07005176 rxr->rx_pg_prod = prod;
Michael Chan47bf4242007-12-12 11:19:12 -08005177
Michael Chanbb4f98a2008-06-19 16:38:19 -07005178 ring_prod = prod = rxr->rx_prod;
Michael Chan236b6392006-03-20 17:49:02 -08005179 for (i = 0; i < bp->rx_ring_size; i++) {
Michael Chanb929e532009-12-03 09:46:33 +00005180 if (bnx2_alloc_rx_skb(bp, rxr, ring_prod) < 0) {
Joe Perches3a9c6a42010-02-17 15:01:51 +00005181 netdev_warn(bp->dev, "init'ed rx ring %d with %d/%d skbs only\n",
5182 ring_num, i, bp->rx_ring_size);
Michael Chanb6016b72005-05-26 13:03:09 -07005183 break;
Michael Chanb929e532009-12-03 09:46:33 +00005184 }
Michael Chanb6016b72005-05-26 13:03:09 -07005185 prod = NEXT_RX_BD(prod);
5186 ring_prod = RX_RING_IDX(prod);
5187 }
Michael Chanbb4f98a2008-06-19 16:38:19 -07005188 rxr->rx_prod = prod;
Michael Chanb6016b72005-05-26 13:03:09 -07005189
Michael Chanbb4f98a2008-06-19 16:38:19 -07005190 rxr->rx_bidx_addr = MB_GET_CID_ADDR(cid) + BNX2_L2CTX_HOST_BDIDX;
5191 rxr->rx_bseq_addr = MB_GET_CID_ADDR(cid) + BNX2_L2CTX_HOST_BSEQ;
5192 rxr->rx_pg_bidx_addr = MB_GET_CID_ADDR(cid) + BNX2_L2CTX_HOST_PG_BDIDX;
Michael Chanb6016b72005-05-26 13:03:09 -07005193
Michael Chanbb4f98a2008-06-19 16:38:19 -07005194 REG_WR16(bp, rxr->rx_pg_bidx_addr, rxr->rx_pg_prod);
5195 REG_WR16(bp, rxr->rx_bidx_addr, prod);
5196
5197 REG_WR(bp, rxr->rx_bseq_addr, rxr->rx_prod_bseq);
Michael Chanb6016b72005-05-26 13:03:09 -07005198}
5199
Michael Chan35e90102008-06-19 16:37:42 -07005200static void
5201bnx2_init_all_rings(struct bnx2 *bp)
5202{
5203 int i;
Michael Chan5e9ad9e2008-06-19 16:43:17 -07005204 u32 val;
Michael Chan35e90102008-06-19 16:37:42 -07005205
5206 bnx2_clear_ring_states(bp);
5207
5208 REG_WR(bp, BNX2_TSCH_TSS_CFG, 0);
5209 for (i = 0; i < bp->num_tx_rings; i++)
5210 bnx2_init_tx_ring(bp, i);
5211
5212 if (bp->num_tx_rings > 1)
5213 REG_WR(bp, BNX2_TSCH_TSS_CFG, ((bp->num_tx_rings - 1) << 24) |
5214 (TX_TSS_CID << 7));
5215
Michael Chan5e9ad9e2008-06-19 16:43:17 -07005216 REG_WR(bp, BNX2_RLUP_RSS_CONFIG, 0);
5217 bnx2_reg_wr_ind(bp, BNX2_RXP_SCRATCH_RSS_TBL_SZ, 0);
5218
Michael Chanbb4f98a2008-06-19 16:38:19 -07005219 for (i = 0; i < bp->num_rx_rings; i++)
5220 bnx2_init_rx_ring(bp, i);
Michael Chan5e9ad9e2008-06-19 16:43:17 -07005221
5222 if (bp->num_rx_rings > 1) {
5223 u32 tbl_32;
5224 u8 *tbl = (u8 *) &tbl_32;
5225
5226 bnx2_reg_wr_ind(bp, BNX2_RXP_SCRATCH_RSS_TBL_SZ,
5227 BNX2_RXP_SCRATCH_RSS_TBL_MAX_ENTRIES);
5228
5229 for (i = 0; i < BNX2_RXP_SCRATCH_RSS_TBL_MAX_ENTRIES; i++) {
5230 tbl[i % 4] = i % (bp->num_rx_rings - 1);
5231 if ((i % 4) == 3)
5232 bnx2_reg_wr_ind(bp,
5233 BNX2_RXP_SCRATCH_RSS_TBL + i,
5234 cpu_to_be32(tbl_32));
5235 }
5236
5237 val = BNX2_RLUP_RSS_CONFIG_IPV4_RSS_TYPE_ALL_XI |
5238 BNX2_RLUP_RSS_CONFIG_IPV6_RSS_TYPE_ALL_XI;
5239
5240 REG_WR(bp, BNX2_RLUP_RSS_CONFIG, val);
5241
5242 }
Michael Chan35e90102008-06-19 16:37:42 -07005243}
5244
Michael Chan5d5d0012007-12-12 11:17:43 -08005245static u32 bnx2_find_max_ring(u32 ring_size, u32 max_size)
Michael Chan13daffa2006-03-20 17:49:20 -08005246{
Michael Chan5d5d0012007-12-12 11:17:43 -08005247 u32 max, num_rings = 1;
Michael Chan13daffa2006-03-20 17:49:20 -08005248
Michael Chan5d5d0012007-12-12 11:17:43 -08005249 while (ring_size > MAX_RX_DESC_CNT) {
5250 ring_size -= MAX_RX_DESC_CNT;
Michael Chan13daffa2006-03-20 17:49:20 -08005251 num_rings++;
5252 }
5253 /* round to next power of 2 */
Michael Chan5d5d0012007-12-12 11:17:43 -08005254 max = max_size;
Michael Chan13daffa2006-03-20 17:49:20 -08005255 while ((max & num_rings) == 0)
5256 max >>= 1;
5257
5258 if (num_rings != max)
5259 max <<= 1;
5260
Michael Chan5d5d0012007-12-12 11:17:43 -08005261 return max;
5262}
5263
5264static void
5265bnx2_set_rx_ring_size(struct bnx2 *bp, u32 size)
5266{
Michael Chan84eaa182007-12-12 11:19:57 -08005267 u32 rx_size, rx_space, jumbo_size;
Michael Chan5d5d0012007-12-12 11:17:43 -08005268
5269 /* 8 for CRC and VLAN */
Benjamin Lid89cb6a2008-05-16 22:18:57 -07005270 rx_size = bp->dev->mtu + ETH_HLEN + BNX2_RX_OFFSET + 8;
Michael Chan5d5d0012007-12-12 11:17:43 -08005271
Michael Chan84eaa182007-12-12 11:19:57 -08005272 rx_space = SKB_DATA_ALIGN(rx_size + BNX2_RX_ALIGN) + NET_SKB_PAD +
5273 sizeof(struct skb_shared_info);
5274
Benjamin Li601d3d12008-05-16 22:19:35 -07005275 bp->rx_copy_thresh = BNX2_RX_COPY_THRESH;
Michael Chan47bf4242007-12-12 11:19:12 -08005276 bp->rx_pg_ring_size = 0;
5277 bp->rx_max_pg_ring = 0;
5278 bp->rx_max_pg_ring_idx = 0;
David S. Millerf86e82f2008-01-21 17:15:40 -08005279 if ((rx_space > PAGE_SIZE) && !(bp->flags & BNX2_FLAG_JUMBO_BROKEN)) {
Michael Chan84eaa182007-12-12 11:19:57 -08005280 int pages = PAGE_ALIGN(bp->dev->mtu - 40) >> PAGE_SHIFT;
5281
5282 jumbo_size = size * pages;
5283 if (jumbo_size > MAX_TOTAL_RX_PG_DESC_CNT)
5284 jumbo_size = MAX_TOTAL_RX_PG_DESC_CNT;
5285
5286 bp->rx_pg_ring_size = jumbo_size;
5287 bp->rx_max_pg_ring = bnx2_find_max_ring(jumbo_size,
5288 MAX_RX_PG_RINGS);
5289 bp->rx_max_pg_ring_idx = (bp->rx_max_pg_ring * RX_DESC_CNT) - 1;
Benjamin Li601d3d12008-05-16 22:19:35 -07005290 rx_size = BNX2_RX_COPY_THRESH + BNX2_RX_OFFSET;
Michael Chan84eaa182007-12-12 11:19:57 -08005291 bp->rx_copy_thresh = 0;
5292 }
Michael Chan5d5d0012007-12-12 11:17:43 -08005293
5294 bp->rx_buf_use_size = rx_size;
5295 /* hw alignment */
5296 bp->rx_buf_size = bp->rx_buf_use_size + BNX2_RX_ALIGN;
Benjamin Lid89cb6a2008-05-16 22:18:57 -07005297 bp->rx_jumbo_thresh = rx_size - BNX2_RX_OFFSET;
Michael Chan5d5d0012007-12-12 11:17:43 -08005298 bp->rx_ring_size = size;
5299 bp->rx_max_ring = bnx2_find_max_ring(size, MAX_RX_RINGS);
Michael Chan13daffa2006-03-20 17:49:20 -08005300 bp->rx_max_ring_idx = (bp->rx_max_ring * RX_DESC_CNT) - 1;
5301}
5302
5303static void
Michael Chanb6016b72005-05-26 13:03:09 -07005304bnx2_free_tx_skbs(struct bnx2 *bp)
5305{
5306 int i;
5307
Michael Chan35e90102008-06-19 16:37:42 -07005308 for (i = 0; i < bp->num_tx_rings; i++) {
5309 struct bnx2_napi *bnapi = &bp->bnx2_napi[i];
5310 struct bnx2_tx_ring_info *txr = &bnapi->tx_ring;
5311 int j;
Michael Chanb6016b72005-05-26 13:03:09 -07005312
Michael Chan35e90102008-06-19 16:37:42 -07005313 if (txr->tx_buf_ring == NULL)
Michael Chanb6016b72005-05-26 13:03:09 -07005314 continue;
Michael Chanb6016b72005-05-26 13:03:09 -07005315
Michael Chan35e90102008-06-19 16:37:42 -07005316 for (j = 0; j < TX_DESC_CNT; ) {
Benjamin Li3d16af82008-10-09 12:26:41 -07005317 struct sw_tx_bd *tx_buf = &txr->tx_buf_ring[j];
Michael Chan35e90102008-06-19 16:37:42 -07005318 struct sk_buff *skb = tx_buf->skb;
Alexander Duycke95524a2009-12-02 16:47:57 +00005319 int k, last;
Michael Chan35e90102008-06-19 16:37:42 -07005320
5321 if (skb == NULL) {
5322 j++;
5323 continue;
5324 }
5325
Alexander Duycke95524a2009-12-02 16:47:57 +00005326 pci_unmap_single(bp->pdev,
FUJITA Tomonori1a4ccc22010-04-01 16:56:57 +00005327 dma_unmap_addr(tx_buf, mapping),
Alexander Duycke95524a2009-12-02 16:47:57 +00005328 skb_headlen(skb),
5329 PCI_DMA_TODEVICE);
Michael Chanb6016b72005-05-26 13:03:09 -07005330
Michael Chan35e90102008-06-19 16:37:42 -07005331 tx_buf->skb = NULL;
Michael Chanb6016b72005-05-26 13:03:09 -07005332
Alexander Duycke95524a2009-12-02 16:47:57 +00005333 last = tx_buf->nr_frags;
5334 j++;
5335 for (k = 0; k < last; k++, j++) {
5336 tx_buf = &txr->tx_buf_ring[TX_RING_IDX(j)];
5337 pci_unmap_page(bp->pdev,
FUJITA Tomonori1a4ccc22010-04-01 16:56:57 +00005338 dma_unmap_addr(tx_buf, mapping),
Alexander Duycke95524a2009-12-02 16:47:57 +00005339 skb_shinfo(skb)->frags[k].size,
5340 PCI_DMA_TODEVICE);
5341 }
Michael Chan35e90102008-06-19 16:37:42 -07005342 dev_kfree_skb(skb);
Michael Chanb6016b72005-05-26 13:03:09 -07005343 }
Michael Chanb6016b72005-05-26 13:03:09 -07005344 }
Michael Chanb6016b72005-05-26 13:03:09 -07005345}
5346
5347static void
5348bnx2_free_rx_skbs(struct bnx2 *bp)
5349{
5350 int i;
5351
Michael Chanbb4f98a2008-06-19 16:38:19 -07005352 for (i = 0; i < bp->num_rx_rings; i++) {
5353 struct bnx2_napi *bnapi = &bp->bnx2_napi[i];
5354 struct bnx2_rx_ring_info *rxr = &bnapi->rx_ring;
5355 int j;
Michael Chanb6016b72005-05-26 13:03:09 -07005356
Michael Chanbb4f98a2008-06-19 16:38:19 -07005357 if (rxr->rx_buf_ring == NULL)
5358 return;
Michael Chanb6016b72005-05-26 13:03:09 -07005359
Michael Chanbb4f98a2008-06-19 16:38:19 -07005360 for (j = 0; j < bp->rx_max_ring_idx; j++) {
5361 struct sw_bd *rx_buf = &rxr->rx_buf_ring[j];
5362 struct sk_buff *skb = rx_buf->skb;
Michael Chanb6016b72005-05-26 13:03:09 -07005363
Michael Chanbb4f98a2008-06-19 16:38:19 -07005364 if (skb == NULL)
5365 continue;
Michael Chanb6016b72005-05-26 13:03:09 -07005366
Michael Chanbb4f98a2008-06-19 16:38:19 -07005367 pci_unmap_single(bp->pdev,
FUJITA Tomonori1a4ccc22010-04-01 16:56:57 +00005368 dma_unmap_addr(rx_buf, mapping),
Michael Chanbb4f98a2008-06-19 16:38:19 -07005369 bp->rx_buf_use_size,
5370 PCI_DMA_FROMDEVICE);
Michael Chanb6016b72005-05-26 13:03:09 -07005371
Michael Chanbb4f98a2008-06-19 16:38:19 -07005372 rx_buf->skb = NULL;
5373
5374 dev_kfree_skb(skb);
5375 }
5376 for (j = 0; j < bp->rx_max_pg_ring_idx; j++)
5377 bnx2_free_rx_page(bp, rxr, j);
Michael Chanb6016b72005-05-26 13:03:09 -07005378 }
5379}
5380
5381static void
5382bnx2_free_skbs(struct bnx2 *bp)
5383{
5384 bnx2_free_tx_skbs(bp);
5385 bnx2_free_rx_skbs(bp);
5386}
5387
5388static int
5389bnx2_reset_nic(struct bnx2 *bp, u32 reset_code)
5390{
5391 int rc;
5392
5393 rc = bnx2_reset_chip(bp, reset_code);
5394 bnx2_free_skbs(bp);
5395 if (rc)
5396 return rc;
5397
Michael Chanfba9fe92006-06-12 22:21:25 -07005398 if ((rc = bnx2_init_chip(bp)) != 0)
5399 return rc;
5400
Michael Chan35e90102008-06-19 16:37:42 -07005401 bnx2_init_all_rings(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07005402 return 0;
5403}
5404
5405static int
Michael Chan9a120bc2008-05-16 22:17:45 -07005406bnx2_init_nic(struct bnx2 *bp, int reset_phy)
Michael Chanb6016b72005-05-26 13:03:09 -07005407{
5408 int rc;
5409
5410 if ((rc = bnx2_reset_nic(bp, BNX2_DRV_MSG_CODE_RESET)) != 0)
5411 return rc;
5412
Michael Chan80be4432006-11-19 14:07:28 -08005413 spin_lock_bh(&bp->phy_lock);
Michael Chan9a120bc2008-05-16 22:17:45 -07005414 bnx2_init_phy(bp, reset_phy);
Michael Chanb6016b72005-05-26 13:03:09 -07005415 bnx2_set_link(bp);
Michael Chan543a8272008-05-02 16:56:44 -07005416 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
5417 bnx2_remote_phy_event(bp);
Michael Chan0d8a6572007-07-07 22:49:43 -07005418 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07005419 return 0;
5420}
5421
5422static int
Michael Chan74bf4ba2008-10-09 12:21:08 -07005423bnx2_shutdown_chip(struct bnx2 *bp)
5424{
5425 u32 reset_code;
5426
5427 if (bp->flags & BNX2_FLAG_NO_WOL)
5428 reset_code = BNX2_DRV_MSG_CODE_UNLOAD_LNK_DN;
5429 else if (bp->wol)
5430 reset_code = BNX2_DRV_MSG_CODE_SUSPEND_WOL;
5431 else
5432 reset_code = BNX2_DRV_MSG_CODE_SUSPEND_NO_WOL;
5433
5434 return bnx2_reset_chip(bp, reset_code);
5435}
5436
5437static int
Michael Chanb6016b72005-05-26 13:03:09 -07005438bnx2_test_registers(struct bnx2 *bp)
5439{
5440 int ret;
Michael Chan5bae30c2007-05-03 13:18:46 -07005441 int i, is_5709;
Arjan van de Venf71e1302006-03-03 21:33:57 -05005442 static const struct {
Michael Chanb6016b72005-05-26 13:03:09 -07005443 u16 offset;
5444 u16 flags;
Michael Chan5bae30c2007-05-03 13:18:46 -07005445#define BNX2_FL_NOT_5709 1
Michael Chanb6016b72005-05-26 13:03:09 -07005446 u32 rw_mask;
5447 u32 ro_mask;
5448 } reg_tbl[] = {
5449 { 0x006c, 0, 0x00000000, 0x0000003f },
5450 { 0x0090, 0, 0xffffffff, 0x00000000 },
5451 { 0x0094, 0, 0x00000000, 0x00000000 },
5452
Michael Chan5bae30c2007-05-03 13:18:46 -07005453 { 0x0404, BNX2_FL_NOT_5709, 0x00003f00, 0x00000000 },
5454 { 0x0418, BNX2_FL_NOT_5709, 0x00000000, 0xffffffff },
5455 { 0x041c, BNX2_FL_NOT_5709, 0x00000000, 0xffffffff },
5456 { 0x0420, BNX2_FL_NOT_5709, 0x00000000, 0x80ffffff },
5457 { 0x0424, BNX2_FL_NOT_5709, 0x00000000, 0x00000000 },
5458 { 0x0428, BNX2_FL_NOT_5709, 0x00000000, 0x00000001 },
5459 { 0x0450, BNX2_FL_NOT_5709, 0x00000000, 0x0000ffff },
5460 { 0x0454, BNX2_FL_NOT_5709, 0x00000000, 0xffffffff },
5461 { 0x0458, BNX2_FL_NOT_5709, 0x00000000, 0xffffffff },
Michael Chanb6016b72005-05-26 13:03:09 -07005462
Michael Chan5bae30c2007-05-03 13:18:46 -07005463 { 0x0808, BNX2_FL_NOT_5709, 0x00000000, 0xffffffff },
5464 { 0x0854, BNX2_FL_NOT_5709, 0x00000000, 0xffffffff },
5465 { 0x0868, BNX2_FL_NOT_5709, 0x00000000, 0x77777777 },
5466 { 0x086c, BNX2_FL_NOT_5709, 0x00000000, 0x77777777 },
5467 { 0x0870, BNX2_FL_NOT_5709, 0x00000000, 0x77777777 },
5468 { 0x0874, BNX2_FL_NOT_5709, 0x00000000, 0x77777777 },
Michael Chanb6016b72005-05-26 13:03:09 -07005469
Michael Chan5bae30c2007-05-03 13:18:46 -07005470 { 0x0c00, BNX2_FL_NOT_5709, 0x00000000, 0x00000001 },
5471 { 0x0c04, BNX2_FL_NOT_5709, 0x00000000, 0x03ff0001 },
5472 { 0x0c08, BNX2_FL_NOT_5709, 0x0f0ff073, 0x00000000 },
Michael Chanb6016b72005-05-26 13:03:09 -07005473
5474 { 0x1000, 0, 0x00000000, 0x00000001 },
Michael Chan15b169c2008-05-02 16:57:08 -07005475 { 0x1004, BNX2_FL_NOT_5709, 0x00000000, 0x000f0001 },
Michael Chanb6016b72005-05-26 13:03:09 -07005476
5477 { 0x1408, 0, 0x01c00800, 0x00000000 },
5478 { 0x149c, 0, 0x8000ffff, 0x00000000 },
5479 { 0x14a8, 0, 0x00000000, 0x000001ff },
Michael Chan5b0c76a2005-11-04 08:45:49 -08005480 { 0x14ac, 0, 0x0fffffff, 0x10000000 },
Michael Chanb6016b72005-05-26 13:03:09 -07005481 { 0x14b0, 0, 0x00000002, 0x00000001 },
5482 { 0x14b8, 0, 0x00000000, 0x00000000 },
5483 { 0x14c0, 0, 0x00000000, 0x00000009 },
5484 { 0x14c4, 0, 0x00003fff, 0x00000000 },
5485 { 0x14cc, 0, 0x00000000, 0x00000001 },
5486 { 0x14d0, 0, 0xffffffff, 0x00000000 },
Michael Chanb6016b72005-05-26 13:03:09 -07005487
5488 { 0x1800, 0, 0x00000000, 0x00000001 },
5489 { 0x1804, 0, 0x00000000, 0x00000003 },
Michael Chanb6016b72005-05-26 13:03:09 -07005490
5491 { 0x2800, 0, 0x00000000, 0x00000001 },
5492 { 0x2804, 0, 0x00000000, 0x00003f01 },
5493 { 0x2808, 0, 0x0f3f3f03, 0x00000000 },
5494 { 0x2810, 0, 0xffff0000, 0x00000000 },
5495 { 0x2814, 0, 0xffff0000, 0x00000000 },
5496 { 0x2818, 0, 0xffff0000, 0x00000000 },
5497 { 0x281c, 0, 0xffff0000, 0x00000000 },
5498 { 0x2834, 0, 0xffffffff, 0x00000000 },
5499 { 0x2840, 0, 0x00000000, 0xffffffff },
5500 { 0x2844, 0, 0x00000000, 0xffffffff },
5501 { 0x2848, 0, 0xffffffff, 0x00000000 },
5502 { 0x284c, 0, 0xf800f800, 0x07ff07ff },
5503
5504 { 0x2c00, 0, 0x00000000, 0x00000011 },
5505 { 0x2c04, 0, 0x00000000, 0x00030007 },
5506
Michael Chanb6016b72005-05-26 13:03:09 -07005507 { 0x3c00, 0, 0x00000000, 0x00000001 },
5508 { 0x3c04, 0, 0x00000000, 0x00070000 },
5509 { 0x3c08, 0, 0x00007f71, 0x07f00000 },
5510 { 0x3c0c, 0, 0x1f3ffffc, 0x00000000 },
5511 { 0x3c10, 0, 0xffffffff, 0x00000000 },
5512 { 0x3c14, 0, 0x00000000, 0xffffffff },
5513 { 0x3c18, 0, 0x00000000, 0xffffffff },
5514 { 0x3c1c, 0, 0xfffff000, 0x00000000 },
5515 { 0x3c20, 0, 0xffffff00, 0x00000000 },
Michael Chanb6016b72005-05-26 13:03:09 -07005516
5517 { 0x5004, 0, 0x00000000, 0x0000007f },
5518 { 0x5008, 0, 0x0f0007ff, 0x00000000 },
Michael Chanb6016b72005-05-26 13:03:09 -07005519
Michael Chanb6016b72005-05-26 13:03:09 -07005520 { 0x5c00, 0, 0x00000000, 0x00000001 },
5521 { 0x5c04, 0, 0x00000000, 0x0003000f },
5522 { 0x5c08, 0, 0x00000003, 0x00000000 },
5523 { 0x5c0c, 0, 0x0000fff8, 0x00000000 },
5524 { 0x5c10, 0, 0x00000000, 0xffffffff },
5525 { 0x5c80, 0, 0x00000000, 0x0f7113f1 },
5526 { 0x5c84, 0, 0x00000000, 0x0000f333 },
5527 { 0x5c88, 0, 0x00000000, 0x00077373 },
5528 { 0x5c8c, 0, 0x00000000, 0x0007f737 },
5529
5530 { 0x6808, 0, 0x0000ff7f, 0x00000000 },
5531 { 0x680c, 0, 0xffffffff, 0x00000000 },
5532 { 0x6810, 0, 0xffffffff, 0x00000000 },
5533 { 0x6814, 0, 0xffffffff, 0x00000000 },
5534 { 0x6818, 0, 0xffffffff, 0x00000000 },
5535 { 0x681c, 0, 0xffffffff, 0x00000000 },
5536 { 0x6820, 0, 0x00ff00ff, 0x00000000 },
5537 { 0x6824, 0, 0x00ff00ff, 0x00000000 },
5538 { 0x6828, 0, 0x00ff00ff, 0x00000000 },
5539 { 0x682c, 0, 0x03ff03ff, 0x00000000 },
5540 { 0x6830, 0, 0x03ff03ff, 0x00000000 },
5541 { 0x6834, 0, 0x03ff03ff, 0x00000000 },
5542 { 0x6838, 0, 0x03ff03ff, 0x00000000 },
5543 { 0x683c, 0, 0x0000ffff, 0x00000000 },
5544 { 0x6840, 0, 0x00000ff0, 0x00000000 },
5545 { 0x6844, 0, 0x00ffff00, 0x00000000 },
5546 { 0x684c, 0, 0xffffffff, 0x00000000 },
5547 { 0x6850, 0, 0x7f7f7f7f, 0x00000000 },
5548 { 0x6854, 0, 0x7f7f7f7f, 0x00000000 },
5549 { 0x6858, 0, 0x7f7f7f7f, 0x00000000 },
5550 { 0x685c, 0, 0x7f7f7f7f, 0x00000000 },
5551 { 0x6908, 0, 0x00000000, 0x0001ff0f },
5552 { 0x690c, 0, 0x00000000, 0x0ffe00f0 },
5553
5554 { 0xffff, 0, 0x00000000, 0x00000000 },
5555 };
5556
5557 ret = 0;
Michael Chan5bae30c2007-05-03 13:18:46 -07005558 is_5709 = 0;
5559 if (CHIP_NUM(bp) == CHIP_NUM_5709)
5560 is_5709 = 1;
5561
Michael Chanb6016b72005-05-26 13:03:09 -07005562 for (i = 0; reg_tbl[i].offset != 0xffff; i++) {
5563 u32 offset, rw_mask, ro_mask, save_val, val;
Michael Chan5bae30c2007-05-03 13:18:46 -07005564 u16 flags = reg_tbl[i].flags;
5565
5566 if (is_5709 && (flags & BNX2_FL_NOT_5709))
5567 continue;
Michael Chanb6016b72005-05-26 13:03:09 -07005568
5569 offset = (u32) reg_tbl[i].offset;
5570 rw_mask = reg_tbl[i].rw_mask;
5571 ro_mask = reg_tbl[i].ro_mask;
5572
Peter Hagervall14ab9b82005-08-10 14:18:16 -07005573 save_val = readl(bp->regview + offset);
Michael Chanb6016b72005-05-26 13:03:09 -07005574
Peter Hagervall14ab9b82005-08-10 14:18:16 -07005575 writel(0, bp->regview + offset);
Michael Chanb6016b72005-05-26 13:03:09 -07005576
Peter Hagervall14ab9b82005-08-10 14:18:16 -07005577 val = readl(bp->regview + offset);
Michael Chanb6016b72005-05-26 13:03:09 -07005578 if ((val & rw_mask) != 0) {
5579 goto reg_test_err;
5580 }
5581
5582 if ((val & ro_mask) != (save_val & ro_mask)) {
5583 goto reg_test_err;
5584 }
5585
Peter Hagervall14ab9b82005-08-10 14:18:16 -07005586 writel(0xffffffff, bp->regview + offset);
Michael Chanb6016b72005-05-26 13:03:09 -07005587
Peter Hagervall14ab9b82005-08-10 14:18:16 -07005588 val = readl(bp->regview + offset);
Michael Chanb6016b72005-05-26 13:03:09 -07005589 if ((val & rw_mask) != rw_mask) {
5590 goto reg_test_err;
5591 }
5592
5593 if ((val & ro_mask) != (save_val & ro_mask)) {
5594 goto reg_test_err;
5595 }
5596
Peter Hagervall14ab9b82005-08-10 14:18:16 -07005597 writel(save_val, bp->regview + offset);
Michael Chanb6016b72005-05-26 13:03:09 -07005598 continue;
5599
5600reg_test_err:
Peter Hagervall14ab9b82005-08-10 14:18:16 -07005601 writel(save_val, bp->regview + offset);
Michael Chanb6016b72005-05-26 13:03:09 -07005602 ret = -ENODEV;
5603 break;
5604 }
5605 return ret;
5606}
5607
5608static int
5609bnx2_do_mem_test(struct bnx2 *bp, u32 start, u32 size)
5610{
Arjan van de Venf71e1302006-03-03 21:33:57 -05005611 static const u32 test_pattern[] = { 0x00000000, 0xffffffff, 0x55555555,
Michael Chanb6016b72005-05-26 13:03:09 -07005612 0xaaaaaaaa , 0xaa55aa55, 0x55aa55aa };
5613 int i;
5614
5615 for (i = 0; i < sizeof(test_pattern) / 4; i++) {
5616 u32 offset;
5617
5618 for (offset = 0; offset < size; offset += 4) {
5619
Michael Chan2726d6e2008-01-29 21:35:05 -08005620 bnx2_reg_wr_ind(bp, start + offset, test_pattern[i]);
Michael Chanb6016b72005-05-26 13:03:09 -07005621
Michael Chan2726d6e2008-01-29 21:35:05 -08005622 if (bnx2_reg_rd_ind(bp, start + offset) !=
Michael Chanb6016b72005-05-26 13:03:09 -07005623 test_pattern[i]) {
5624 return -ENODEV;
5625 }
5626 }
5627 }
5628 return 0;
5629}
5630
5631static int
5632bnx2_test_memory(struct bnx2 *bp)
5633{
5634 int ret = 0;
5635 int i;
Michael Chan5bae30c2007-05-03 13:18:46 -07005636 static struct mem_entry {
Michael Chanb6016b72005-05-26 13:03:09 -07005637 u32 offset;
5638 u32 len;
Michael Chan5bae30c2007-05-03 13:18:46 -07005639 } mem_tbl_5706[] = {
Michael Chanb6016b72005-05-26 13:03:09 -07005640 { 0x60000, 0x4000 },
Michael Chan5b0c76a2005-11-04 08:45:49 -08005641 { 0xa0000, 0x3000 },
Michael Chanb6016b72005-05-26 13:03:09 -07005642 { 0xe0000, 0x4000 },
5643 { 0x120000, 0x4000 },
5644 { 0x1a0000, 0x4000 },
5645 { 0x160000, 0x4000 },
5646 { 0xffffffff, 0 },
Michael Chan5bae30c2007-05-03 13:18:46 -07005647 },
5648 mem_tbl_5709[] = {
5649 { 0x60000, 0x4000 },
5650 { 0xa0000, 0x3000 },
5651 { 0xe0000, 0x4000 },
5652 { 0x120000, 0x4000 },
5653 { 0x1a0000, 0x4000 },
5654 { 0xffffffff, 0 },
Michael Chanb6016b72005-05-26 13:03:09 -07005655 };
Michael Chan5bae30c2007-05-03 13:18:46 -07005656 struct mem_entry *mem_tbl;
5657
5658 if (CHIP_NUM(bp) == CHIP_NUM_5709)
5659 mem_tbl = mem_tbl_5709;
5660 else
5661 mem_tbl = mem_tbl_5706;
Michael Chanb6016b72005-05-26 13:03:09 -07005662
5663 for (i = 0; mem_tbl[i].offset != 0xffffffff; i++) {
5664 if ((ret = bnx2_do_mem_test(bp, mem_tbl[i].offset,
5665 mem_tbl[i].len)) != 0) {
5666 return ret;
5667 }
5668 }
Jeff Garzik6aa20a22006-09-13 13:24:59 -04005669
Michael Chanb6016b72005-05-26 13:03:09 -07005670 return ret;
5671}
5672
Michael Chanbc5a0692006-01-23 16:13:22 -08005673#define BNX2_MAC_LOOPBACK 0
5674#define BNX2_PHY_LOOPBACK 1
5675
Michael Chanb6016b72005-05-26 13:03:09 -07005676static int
Michael Chanbc5a0692006-01-23 16:13:22 -08005677bnx2_run_loopback(struct bnx2 *bp, int loopback_mode)
Michael Chanb6016b72005-05-26 13:03:09 -07005678{
5679 unsigned int pkt_size, num_pkts, i;
5680 struct sk_buff *skb, *rx_skb;
5681 unsigned char *packet;
Michael Chanbc5a0692006-01-23 16:13:22 -08005682 u16 rx_start_idx, rx_idx;
Michael Chanb6016b72005-05-26 13:03:09 -07005683 dma_addr_t map;
5684 struct tx_bd *txbd;
5685 struct sw_bd *rx_buf;
5686 struct l2_fhdr *rx_hdr;
5687 int ret = -ENODEV;
Michael Chanc76c0472007-12-20 20:01:19 -08005688 struct bnx2_napi *bnapi = &bp->bnx2_napi[0], *tx_napi;
Michael Chan35e90102008-06-19 16:37:42 -07005689 struct bnx2_tx_ring_info *txr = &bnapi->tx_ring;
Michael Chanbb4f98a2008-06-19 16:38:19 -07005690 struct bnx2_rx_ring_info *rxr = &bnapi->rx_ring;
Michael Chanc76c0472007-12-20 20:01:19 -08005691
5692 tx_napi = bnapi;
Michael Chanb6016b72005-05-26 13:03:09 -07005693
Michael Chan35e90102008-06-19 16:37:42 -07005694 txr = &tx_napi->tx_ring;
Michael Chanbb4f98a2008-06-19 16:38:19 -07005695 rxr = &bnapi->rx_ring;
Michael Chanbc5a0692006-01-23 16:13:22 -08005696 if (loopback_mode == BNX2_MAC_LOOPBACK) {
5697 bp->loopback = MAC_LOOPBACK;
5698 bnx2_set_mac_loopback(bp);
5699 }
5700 else if (loopback_mode == BNX2_PHY_LOOPBACK) {
Michael Chan583c28e2008-01-21 19:51:35 -08005701 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
Michael Chan489310a2007-10-10 16:16:31 -07005702 return 0;
5703
Michael Chan80be4432006-11-19 14:07:28 -08005704 bp->loopback = PHY_LOOPBACK;
Michael Chanbc5a0692006-01-23 16:13:22 -08005705 bnx2_set_phy_loopback(bp);
5706 }
5707 else
5708 return -EINVAL;
Michael Chanb6016b72005-05-26 13:03:09 -07005709
Michael Chan84eaa182007-12-12 11:19:57 -08005710 pkt_size = min(bp->dev->mtu + ETH_HLEN, bp->rx_jumbo_thresh - 4);
Michael Chan932f3772006-08-15 01:39:36 -07005711 skb = netdev_alloc_skb(bp->dev, pkt_size);
John W. Linvilleb6cbc3b62005-11-10 12:58:00 -08005712 if (!skb)
5713 return -ENOMEM;
Michael Chanb6016b72005-05-26 13:03:09 -07005714 packet = skb_put(skb, pkt_size);
Michael Chan66342922006-12-14 15:57:04 -08005715 memcpy(packet, bp->dev->dev_addr, 6);
Michael Chanb6016b72005-05-26 13:03:09 -07005716 memset(packet + 6, 0x0, 8);
5717 for (i = 14; i < pkt_size; i++)
5718 packet[i] = (unsigned char) (i & 0xff);
5719
Alexander Duycke95524a2009-12-02 16:47:57 +00005720 map = pci_map_single(bp->pdev, skb->data, pkt_size,
5721 PCI_DMA_TODEVICE);
5722 if (pci_dma_mapping_error(bp->pdev, map)) {
Benjamin Li3d16af82008-10-09 12:26:41 -07005723 dev_kfree_skb(skb);
5724 return -EIO;
5725 }
Michael Chanb6016b72005-05-26 13:03:09 -07005726
Michael Chanbf5295b2006-03-23 01:11:56 -08005727 REG_WR(bp, BNX2_HC_COMMAND,
5728 bp->hc_cmd | BNX2_HC_COMMAND_COAL_NOW_WO_INT);
5729
Michael Chanb6016b72005-05-26 13:03:09 -07005730 REG_RD(bp, BNX2_HC_COMMAND);
5731
5732 udelay(5);
Michael Chan35efa7c2007-12-20 19:56:37 -08005733 rx_start_idx = bnx2_get_hw_rx_cons(bnapi);
Michael Chanb6016b72005-05-26 13:03:09 -07005734
Michael Chanb6016b72005-05-26 13:03:09 -07005735 num_pkts = 0;
5736
Michael Chan35e90102008-06-19 16:37:42 -07005737 txbd = &txr->tx_desc_ring[TX_RING_IDX(txr->tx_prod)];
Michael Chanb6016b72005-05-26 13:03:09 -07005738
5739 txbd->tx_bd_haddr_hi = (u64) map >> 32;
5740 txbd->tx_bd_haddr_lo = (u64) map & 0xffffffff;
5741 txbd->tx_bd_mss_nbytes = pkt_size;
5742 txbd->tx_bd_vlan_tag_flags = TX_BD_FLAGS_START | TX_BD_FLAGS_END;
5743
5744 num_pkts++;
Michael Chan35e90102008-06-19 16:37:42 -07005745 txr->tx_prod = NEXT_TX_BD(txr->tx_prod);
5746 txr->tx_prod_bseq += pkt_size;
Michael Chanb6016b72005-05-26 13:03:09 -07005747
Michael Chan35e90102008-06-19 16:37:42 -07005748 REG_WR16(bp, txr->tx_bidx_addr, txr->tx_prod);
5749 REG_WR(bp, txr->tx_bseq_addr, txr->tx_prod_bseq);
Michael Chanb6016b72005-05-26 13:03:09 -07005750
5751 udelay(100);
5752
Michael Chanbf5295b2006-03-23 01:11:56 -08005753 REG_WR(bp, BNX2_HC_COMMAND,
5754 bp->hc_cmd | BNX2_HC_COMMAND_COAL_NOW_WO_INT);
5755
Michael Chanb6016b72005-05-26 13:03:09 -07005756 REG_RD(bp, BNX2_HC_COMMAND);
5757
5758 udelay(5);
5759
Alexander Duycke95524a2009-12-02 16:47:57 +00005760 pci_unmap_single(bp->pdev, map, pkt_size, PCI_DMA_TODEVICE);
Michael Chan745720e2006-06-29 12:37:41 -07005761 dev_kfree_skb(skb);
Michael Chanb6016b72005-05-26 13:03:09 -07005762
Michael Chan35e90102008-06-19 16:37:42 -07005763 if (bnx2_get_hw_tx_cons(tx_napi) != txr->tx_prod)
Michael Chanb6016b72005-05-26 13:03:09 -07005764 goto loopback_test_done;
Michael Chanb6016b72005-05-26 13:03:09 -07005765
Michael Chan35efa7c2007-12-20 19:56:37 -08005766 rx_idx = bnx2_get_hw_rx_cons(bnapi);
Michael Chanb6016b72005-05-26 13:03:09 -07005767 if (rx_idx != rx_start_idx + num_pkts) {
5768 goto loopback_test_done;
5769 }
5770
Michael Chanbb4f98a2008-06-19 16:38:19 -07005771 rx_buf = &rxr->rx_buf_ring[rx_start_idx];
Michael Chanb6016b72005-05-26 13:03:09 -07005772 rx_skb = rx_buf->skb;
5773
Michael Chana33fa662010-05-06 08:58:13 +00005774 rx_hdr = rx_buf->desc;
Benjamin Lid89cb6a2008-05-16 22:18:57 -07005775 skb_reserve(rx_skb, BNX2_RX_OFFSET);
Michael Chanb6016b72005-05-26 13:03:09 -07005776
5777 pci_dma_sync_single_for_cpu(bp->pdev,
FUJITA Tomonori1a4ccc22010-04-01 16:56:57 +00005778 dma_unmap_addr(rx_buf, mapping),
Michael Chanb6016b72005-05-26 13:03:09 -07005779 bp->rx_buf_size, PCI_DMA_FROMDEVICE);
5780
Michael Chanade2bfe2006-01-23 16:09:51 -08005781 if (rx_hdr->l2_fhdr_status &
Michael Chanb6016b72005-05-26 13:03:09 -07005782 (L2_FHDR_ERRORS_BAD_CRC |
5783 L2_FHDR_ERRORS_PHY_DECODE |
5784 L2_FHDR_ERRORS_ALIGNMENT |
5785 L2_FHDR_ERRORS_TOO_SHORT |
5786 L2_FHDR_ERRORS_GIANT_FRAME)) {
5787
5788 goto loopback_test_done;
5789 }
5790
5791 if ((rx_hdr->l2_fhdr_pkt_len - 4) != pkt_size) {
5792 goto loopback_test_done;
5793 }
5794
5795 for (i = 14; i < pkt_size; i++) {
5796 if (*(rx_skb->data + i) != (unsigned char) (i & 0xff)) {
5797 goto loopback_test_done;
5798 }
5799 }
5800
5801 ret = 0;
5802
5803loopback_test_done:
5804 bp->loopback = 0;
5805 return ret;
5806}
5807
Michael Chanbc5a0692006-01-23 16:13:22 -08005808#define BNX2_MAC_LOOPBACK_FAILED 1
5809#define BNX2_PHY_LOOPBACK_FAILED 2
5810#define BNX2_LOOPBACK_FAILED (BNX2_MAC_LOOPBACK_FAILED | \
5811 BNX2_PHY_LOOPBACK_FAILED)
5812
5813static int
5814bnx2_test_loopback(struct bnx2 *bp)
5815{
5816 int rc = 0;
5817
5818 if (!netif_running(bp->dev))
5819 return BNX2_LOOPBACK_FAILED;
5820
5821 bnx2_reset_nic(bp, BNX2_DRV_MSG_CODE_RESET);
5822 spin_lock_bh(&bp->phy_lock);
Michael Chan9a120bc2008-05-16 22:17:45 -07005823 bnx2_init_phy(bp, 1);
Michael Chanbc5a0692006-01-23 16:13:22 -08005824 spin_unlock_bh(&bp->phy_lock);
5825 if (bnx2_run_loopback(bp, BNX2_MAC_LOOPBACK))
5826 rc |= BNX2_MAC_LOOPBACK_FAILED;
5827 if (bnx2_run_loopback(bp, BNX2_PHY_LOOPBACK))
5828 rc |= BNX2_PHY_LOOPBACK_FAILED;
5829 return rc;
5830}
5831
Michael Chanb6016b72005-05-26 13:03:09 -07005832#define NVRAM_SIZE 0x200
5833#define CRC32_RESIDUAL 0xdebb20e3
5834
5835static int
5836bnx2_test_nvram(struct bnx2 *bp)
5837{
Al Virob491edd2007-12-22 19:44:51 +00005838 __be32 buf[NVRAM_SIZE / 4];
Michael Chanb6016b72005-05-26 13:03:09 -07005839 u8 *data = (u8 *) buf;
5840 int rc = 0;
5841 u32 magic, csum;
5842
5843 if ((rc = bnx2_nvram_read(bp, 0, data, 4)) != 0)
5844 goto test_nvram_done;
5845
5846 magic = be32_to_cpu(buf[0]);
5847 if (magic != 0x669955aa) {
5848 rc = -ENODEV;
5849 goto test_nvram_done;
5850 }
5851
5852 if ((rc = bnx2_nvram_read(bp, 0x100, data, NVRAM_SIZE)) != 0)
5853 goto test_nvram_done;
5854
5855 csum = ether_crc_le(0x100, data);
5856 if (csum != CRC32_RESIDUAL) {
5857 rc = -ENODEV;
5858 goto test_nvram_done;
5859 }
5860
5861 csum = ether_crc_le(0x100, data + 0x100);
5862 if (csum != CRC32_RESIDUAL) {
5863 rc = -ENODEV;
5864 }
5865
5866test_nvram_done:
5867 return rc;
5868}
5869
5870static int
5871bnx2_test_link(struct bnx2 *bp)
5872{
5873 u32 bmsr;
5874
Michael Chan9f52b562008-10-09 12:21:46 -07005875 if (!netif_running(bp->dev))
5876 return -ENODEV;
5877
Michael Chan583c28e2008-01-21 19:51:35 -08005878 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP) {
Michael Chan489310a2007-10-10 16:16:31 -07005879 if (bp->link_up)
5880 return 0;
5881 return -ENODEV;
5882 }
Michael Chanc770a652005-08-25 15:38:39 -07005883 spin_lock_bh(&bp->phy_lock);
Michael Chan27a005b2007-05-03 13:23:41 -07005884 bnx2_enable_bmsr1(bp);
5885 bnx2_read_phy(bp, bp->mii_bmsr1, &bmsr);
5886 bnx2_read_phy(bp, bp->mii_bmsr1, &bmsr);
5887 bnx2_disable_bmsr1(bp);
Michael Chanc770a652005-08-25 15:38:39 -07005888 spin_unlock_bh(&bp->phy_lock);
Jeff Garzik6aa20a22006-09-13 13:24:59 -04005889
Michael Chanb6016b72005-05-26 13:03:09 -07005890 if (bmsr & BMSR_LSTATUS) {
5891 return 0;
5892 }
5893 return -ENODEV;
5894}
5895
5896static int
5897bnx2_test_intr(struct bnx2 *bp)
5898{
5899 int i;
Michael Chanb6016b72005-05-26 13:03:09 -07005900 u16 status_idx;
5901
5902 if (!netif_running(bp->dev))
5903 return -ENODEV;
5904
5905 status_idx = REG_RD(bp, BNX2_PCICFG_INT_ACK_CMD) & 0xffff;
5906
5907 /* This register is not touched during run-time. */
Michael Chanbf5295b2006-03-23 01:11:56 -08005908 REG_WR(bp, BNX2_HC_COMMAND, bp->hc_cmd | BNX2_HC_COMMAND_COAL_NOW);
Michael Chanb6016b72005-05-26 13:03:09 -07005909 REG_RD(bp, BNX2_HC_COMMAND);
5910
5911 for (i = 0; i < 10; i++) {
5912 if ((REG_RD(bp, BNX2_PCICFG_INT_ACK_CMD) & 0xffff) !=
5913 status_idx) {
5914
5915 break;
5916 }
5917
5918 msleep_interruptible(10);
5919 }
5920 if (i < 10)
5921 return 0;
5922
5923 return -ENODEV;
5924}
5925
Michael Chan38ea3682008-02-23 19:48:57 -08005926/* Determining link for parallel detection. */
Michael Chanb2fadea2008-01-21 17:07:06 -08005927static int
5928bnx2_5706_serdes_has_link(struct bnx2 *bp)
5929{
5930 u32 mode_ctl, an_dbg, exp;
5931
Michael Chan38ea3682008-02-23 19:48:57 -08005932 if (bp->phy_flags & BNX2_PHY_FLAG_NO_PARALLEL)
5933 return 0;
5934
Michael Chanb2fadea2008-01-21 17:07:06 -08005935 bnx2_write_phy(bp, MII_BNX2_MISC_SHADOW, MISC_SHDW_MODE_CTL);
5936 bnx2_read_phy(bp, MII_BNX2_MISC_SHADOW, &mode_ctl);
5937
5938 if (!(mode_ctl & MISC_SHDW_MODE_CTL_SIG_DET))
5939 return 0;
5940
5941 bnx2_write_phy(bp, MII_BNX2_MISC_SHADOW, MISC_SHDW_AN_DBG);
5942 bnx2_read_phy(bp, MII_BNX2_MISC_SHADOW, &an_dbg);
5943 bnx2_read_phy(bp, MII_BNX2_MISC_SHADOW, &an_dbg);
5944
Michael Chanf3014c0c2008-01-29 21:33:03 -08005945 if (an_dbg & (MISC_SHDW_AN_DBG_NOSYNC | MISC_SHDW_AN_DBG_RUDI_INVALID))
Michael Chanb2fadea2008-01-21 17:07:06 -08005946 return 0;
5947
5948 bnx2_write_phy(bp, MII_BNX2_DSP_ADDRESS, MII_EXPAND_REG1);
5949 bnx2_read_phy(bp, MII_BNX2_DSP_RW_PORT, &exp);
5950 bnx2_read_phy(bp, MII_BNX2_DSP_RW_PORT, &exp);
5951
5952 if (exp & MII_EXPAND_REG1_RUDI_C) /* receiving CONFIG */
5953 return 0;
5954
5955 return 1;
5956}
5957
Michael Chanb6016b72005-05-26 13:03:09 -07005958static void
Michael Chan48b01e22006-11-19 14:08:00 -08005959bnx2_5706_serdes_timer(struct bnx2 *bp)
5960{
Michael Chanb2fadea2008-01-21 17:07:06 -08005961 int check_link = 1;
5962
Michael Chan48b01e22006-11-19 14:08:00 -08005963 spin_lock(&bp->phy_lock);
Michael Chanb2fadea2008-01-21 17:07:06 -08005964 if (bp->serdes_an_pending) {
Michael Chan48b01e22006-11-19 14:08:00 -08005965 bp->serdes_an_pending--;
Michael Chanb2fadea2008-01-21 17:07:06 -08005966 check_link = 0;
5967 } else if ((bp->link_up == 0) && (bp->autoneg & AUTONEG_SPEED)) {
Michael Chan48b01e22006-11-19 14:08:00 -08005968 u32 bmcr;
5969
Benjamin Liac392ab2008-09-18 16:40:49 -07005970 bp->current_interval = BNX2_TIMER_INTERVAL;
Michael Chan48b01e22006-11-19 14:08:00 -08005971
Michael Chanca58c3a2007-05-03 13:22:52 -07005972 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chan48b01e22006-11-19 14:08:00 -08005973
5974 if (bmcr & BMCR_ANENABLE) {
Michael Chanb2fadea2008-01-21 17:07:06 -08005975 if (bnx2_5706_serdes_has_link(bp)) {
Michael Chan48b01e22006-11-19 14:08:00 -08005976 bmcr &= ~BMCR_ANENABLE;
5977 bmcr |= BMCR_SPEED1000 | BMCR_FULLDPLX;
Michael Chanca58c3a2007-05-03 13:22:52 -07005978 bnx2_write_phy(bp, bp->mii_bmcr, bmcr);
Michael Chan583c28e2008-01-21 19:51:35 -08005979 bp->phy_flags |= BNX2_PHY_FLAG_PARALLEL_DETECT;
Michael Chan48b01e22006-11-19 14:08:00 -08005980 }
5981 }
5982 }
5983 else if ((bp->link_up) && (bp->autoneg & AUTONEG_SPEED) &&
Michael Chan583c28e2008-01-21 19:51:35 -08005984 (bp->phy_flags & BNX2_PHY_FLAG_PARALLEL_DETECT)) {
Michael Chan48b01e22006-11-19 14:08:00 -08005985 u32 phy2;
5986
5987 bnx2_write_phy(bp, 0x17, 0x0f01);
5988 bnx2_read_phy(bp, 0x15, &phy2);
5989 if (phy2 & 0x20) {
5990 u32 bmcr;
5991
Michael Chanca58c3a2007-05-03 13:22:52 -07005992 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chan48b01e22006-11-19 14:08:00 -08005993 bmcr |= BMCR_ANENABLE;
Michael Chanca58c3a2007-05-03 13:22:52 -07005994 bnx2_write_phy(bp, bp->mii_bmcr, bmcr);
Michael Chan48b01e22006-11-19 14:08:00 -08005995
Michael Chan583c28e2008-01-21 19:51:35 -08005996 bp->phy_flags &= ~BNX2_PHY_FLAG_PARALLEL_DETECT;
Michael Chan48b01e22006-11-19 14:08:00 -08005997 }
5998 } else
Benjamin Liac392ab2008-09-18 16:40:49 -07005999 bp->current_interval = BNX2_TIMER_INTERVAL;
Michael Chan48b01e22006-11-19 14:08:00 -08006000
Michael Chana2724e22008-02-23 19:47:44 -08006001 if (check_link) {
Michael Chanb2fadea2008-01-21 17:07:06 -08006002 u32 val;
6003
6004 bnx2_write_phy(bp, MII_BNX2_MISC_SHADOW, MISC_SHDW_AN_DBG);
6005 bnx2_read_phy(bp, MII_BNX2_MISC_SHADOW, &val);
6006 bnx2_read_phy(bp, MII_BNX2_MISC_SHADOW, &val);
6007
Michael Chana2724e22008-02-23 19:47:44 -08006008 if (bp->link_up && (val & MISC_SHDW_AN_DBG_NOSYNC)) {
6009 if (!(bp->phy_flags & BNX2_PHY_FLAG_FORCED_DOWN)) {
6010 bnx2_5706s_force_link_dn(bp, 1);
6011 bp->phy_flags |= BNX2_PHY_FLAG_FORCED_DOWN;
6012 } else
6013 bnx2_set_link(bp);
6014 } else if (!bp->link_up && !(val & MISC_SHDW_AN_DBG_NOSYNC))
6015 bnx2_set_link(bp);
Michael Chanb2fadea2008-01-21 17:07:06 -08006016 }
Michael Chan48b01e22006-11-19 14:08:00 -08006017 spin_unlock(&bp->phy_lock);
6018}
6019
6020static void
Michael Chanf8dd0642006-11-19 14:08:29 -08006021bnx2_5708_serdes_timer(struct bnx2 *bp)
6022{
Michael Chan583c28e2008-01-21 19:51:35 -08006023 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
Michael Chan0d8a6572007-07-07 22:49:43 -07006024 return;
6025
Michael Chan583c28e2008-01-21 19:51:35 -08006026 if ((bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE) == 0) {
Michael Chanf8dd0642006-11-19 14:08:29 -08006027 bp->serdes_an_pending = 0;
6028 return;
6029 }
6030
6031 spin_lock(&bp->phy_lock);
6032 if (bp->serdes_an_pending)
6033 bp->serdes_an_pending--;
6034 else if ((bp->link_up == 0) && (bp->autoneg & AUTONEG_SPEED)) {
6035 u32 bmcr;
6036
Michael Chanca58c3a2007-05-03 13:22:52 -07006037 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chanf8dd0642006-11-19 14:08:29 -08006038 if (bmcr & BMCR_ANENABLE) {
Michael Chan605a9e22007-05-03 13:23:13 -07006039 bnx2_enable_forced_2g5(bp);
Michael Chan40105c02008-11-12 16:02:45 -08006040 bp->current_interval = BNX2_SERDES_FORCED_TIMEOUT;
Michael Chanf8dd0642006-11-19 14:08:29 -08006041 } else {
Michael Chan605a9e22007-05-03 13:23:13 -07006042 bnx2_disable_forced_2g5(bp);
Michael Chanf8dd0642006-11-19 14:08:29 -08006043 bp->serdes_an_pending = 2;
Benjamin Liac392ab2008-09-18 16:40:49 -07006044 bp->current_interval = BNX2_TIMER_INTERVAL;
Michael Chanf8dd0642006-11-19 14:08:29 -08006045 }
6046
6047 } else
Benjamin Liac392ab2008-09-18 16:40:49 -07006048 bp->current_interval = BNX2_TIMER_INTERVAL;
Michael Chanf8dd0642006-11-19 14:08:29 -08006049
6050 spin_unlock(&bp->phy_lock);
6051}
6052
6053static void
Michael Chanb6016b72005-05-26 13:03:09 -07006054bnx2_timer(unsigned long data)
6055{
6056 struct bnx2 *bp = (struct bnx2 *) data;
Michael Chanb6016b72005-05-26 13:03:09 -07006057
Michael Chancd339a02005-08-25 15:35:24 -07006058 if (!netif_running(bp->dev))
6059 return;
6060
Michael Chanb6016b72005-05-26 13:03:09 -07006061 if (atomic_read(&bp->intr_sem) != 0)
6062 goto bnx2_restart_timer;
6063
Michael Chanefba0182008-12-03 00:36:15 -08006064 if ((bp->flags & (BNX2_FLAG_USING_MSI | BNX2_FLAG_ONE_SHOT_MSI)) ==
6065 BNX2_FLAG_USING_MSI)
6066 bnx2_chk_missed_msi(bp);
6067
Michael Chandf149d72007-07-07 22:51:36 -07006068 bnx2_send_heart_beat(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07006069
Michael Chan2726d6e2008-01-29 21:35:05 -08006070 bp->stats_blk->stat_FwRxDrop =
6071 bnx2_reg_rd_ind(bp, BNX2_FW_RX_DROP_COUNT);
Michael Chancea94db2006-06-12 22:16:13 -07006072
Michael Chan02537b062007-06-04 21:24:07 -07006073 /* workaround occasional corrupted counters */
Michael Chan61d9e3f2009-08-21 16:20:46 +00006074 if ((bp->flags & BNX2_FLAG_BROKEN_STATS) && bp->stats_ticks)
Michael Chan02537b062007-06-04 21:24:07 -07006075 REG_WR(bp, BNX2_HC_COMMAND, bp->hc_cmd |
6076 BNX2_HC_COMMAND_STATS_NOW);
6077
Michael Chan583c28e2008-01-21 19:51:35 -08006078 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Michael Chanf8dd0642006-11-19 14:08:29 -08006079 if (CHIP_NUM(bp) == CHIP_NUM_5706)
6080 bnx2_5706_serdes_timer(bp);
Michael Chan27a005b2007-05-03 13:23:41 -07006081 else
Michael Chanf8dd0642006-11-19 14:08:29 -08006082 bnx2_5708_serdes_timer(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07006083 }
6084
6085bnx2_restart_timer:
Michael Chancd339a02005-08-25 15:35:24 -07006086 mod_timer(&bp->timer, jiffies + bp->current_interval);
Michael Chanb6016b72005-05-26 13:03:09 -07006087}
6088
Michael Chan8e6a72c2007-05-03 13:24:48 -07006089static int
6090bnx2_request_irq(struct bnx2 *bp)
6091{
Michael Chan6d866ff2007-12-20 19:56:09 -08006092 unsigned long flags;
Michael Chanb4b36042007-12-20 19:59:30 -08006093 struct bnx2_irq *irq;
6094 int rc = 0, i;
Michael Chan8e6a72c2007-05-03 13:24:48 -07006095
David S. Millerf86e82f2008-01-21 17:15:40 -08006096 if (bp->flags & BNX2_FLAG_USING_MSI_OR_MSIX)
Michael Chan6d866ff2007-12-20 19:56:09 -08006097 flags = 0;
6098 else
6099 flags = IRQF_SHARED;
Michael Chanb4b36042007-12-20 19:59:30 -08006100
6101 for (i = 0; i < bp->irq_nvecs; i++) {
6102 irq = &bp->irq_tbl[i];
Michael Chanc76c0472007-12-20 20:01:19 -08006103 rc = request_irq(irq->vector, irq->handler, flags, irq->name,
Michael Chanf0ea2e62008-06-19 16:41:57 -07006104 &bp->bnx2_napi[i]);
Michael Chanb4b36042007-12-20 19:59:30 -08006105 if (rc)
6106 break;
6107 irq->requested = 1;
6108 }
Michael Chan8e6a72c2007-05-03 13:24:48 -07006109 return rc;
6110}
6111
6112static void
6113bnx2_free_irq(struct bnx2 *bp)
6114{
Michael Chanb4b36042007-12-20 19:59:30 -08006115 struct bnx2_irq *irq;
6116 int i;
Michael Chan8e6a72c2007-05-03 13:24:48 -07006117
Michael Chanb4b36042007-12-20 19:59:30 -08006118 for (i = 0; i < bp->irq_nvecs; i++) {
6119 irq = &bp->irq_tbl[i];
6120 if (irq->requested)
Michael Chanf0ea2e62008-06-19 16:41:57 -07006121 free_irq(irq->vector, &bp->bnx2_napi[i]);
Michael Chanb4b36042007-12-20 19:59:30 -08006122 irq->requested = 0;
Michael Chan6d866ff2007-12-20 19:56:09 -08006123 }
David S. Millerf86e82f2008-01-21 17:15:40 -08006124 if (bp->flags & BNX2_FLAG_USING_MSI)
Michael Chanb4b36042007-12-20 19:59:30 -08006125 pci_disable_msi(bp->pdev);
David S. Millerf86e82f2008-01-21 17:15:40 -08006126 else if (bp->flags & BNX2_FLAG_USING_MSIX)
Michael Chanb4b36042007-12-20 19:59:30 -08006127 pci_disable_msix(bp->pdev);
6128
David S. Millerf86e82f2008-01-21 17:15:40 -08006129 bp->flags &= ~(BNX2_FLAG_USING_MSI_OR_MSIX | BNX2_FLAG_ONE_SHOT_MSI);
Michael Chanb4b36042007-12-20 19:59:30 -08006130}
6131
6132static void
Michael Chan5e9ad9e2008-06-19 16:43:17 -07006133bnx2_enable_msix(struct bnx2 *bp, int msix_vecs)
Michael Chanb4b36042007-12-20 19:59:30 -08006134{
Michael Chan57851d82007-12-20 20:01:44 -08006135 int i, rc;
6136 struct msix_entry msix_ent[BNX2_MAX_MSIX_VEC];
Michael Chan4e1d0de2008-12-16 20:27:45 -08006137 struct net_device *dev = bp->dev;
6138 const int len = sizeof(bp->irq_tbl[0].name);
Michael Chan57851d82007-12-20 20:01:44 -08006139
Michael Chanb4b36042007-12-20 19:59:30 -08006140 bnx2_setup_msix_tbl(bp);
6141 REG_WR(bp, BNX2_PCI_MSIX_CONTROL, BNX2_MAX_MSIX_HW_VEC - 1);
6142 REG_WR(bp, BNX2_PCI_MSIX_TBL_OFF_BIR, BNX2_PCI_GRC_WINDOW2_BASE);
6143 REG_WR(bp, BNX2_PCI_MSIX_PBA_OFF_BIT, BNX2_PCI_GRC_WINDOW3_BASE);
Michael Chan57851d82007-12-20 20:01:44 -08006144
Benjamin Lie2eb8e32010-01-08 00:51:21 -08006145 /* Need to flush the previous three writes to ensure MSI-X
6146 * is setup properly */
6147 REG_RD(bp, BNX2_PCI_MSIX_CONTROL);
6148
Michael Chan57851d82007-12-20 20:01:44 -08006149 for (i = 0; i < BNX2_MAX_MSIX_VEC; i++) {
6150 msix_ent[i].entry = i;
6151 msix_ent[i].vector = 0;
6152 }
6153
6154 rc = pci_enable_msix(bp->pdev, msix_ent, BNX2_MAX_MSIX_VEC);
6155 if (rc != 0)
6156 return;
6157
Michael Chan5e9ad9e2008-06-19 16:43:17 -07006158 bp->irq_nvecs = msix_vecs;
David S. Millerf86e82f2008-01-21 17:15:40 -08006159 bp->flags |= BNX2_FLAG_USING_MSIX | BNX2_FLAG_ONE_SHOT_MSI;
Michael Chan69010312009-03-18 18:11:51 -07006160 for (i = 0; i < BNX2_MAX_MSIX_VEC; i++) {
Michael Chan57851d82007-12-20 20:01:44 -08006161 bp->irq_tbl[i].vector = msix_ent[i].vector;
Michael Chan69010312009-03-18 18:11:51 -07006162 snprintf(bp->irq_tbl[i].name, len, "%s-%d", dev->name, i);
6163 bp->irq_tbl[i].handler = bnx2_msi_1shot;
6164 }
Michael Chan6d866ff2007-12-20 19:56:09 -08006165}
6166
6167static void
6168bnx2_setup_int_mode(struct bnx2 *bp, int dis_msi)
6169{
Michael Chan5e9ad9e2008-06-19 16:43:17 -07006170 int cpus = num_online_cpus();
Benjamin Li706bf242008-07-18 17:55:11 -07006171 int msix_vecs = min(cpus + 1, RX_MAX_RINGS);
Michael Chan5e9ad9e2008-06-19 16:43:17 -07006172
Michael Chan6d866ff2007-12-20 19:56:09 -08006173 bp->irq_tbl[0].handler = bnx2_interrupt;
6174 strcpy(bp->irq_tbl[0].name, bp->dev->name);
Michael Chanb4b36042007-12-20 19:59:30 -08006175 bp->irq_nvecs = 1;
6176 bp->irq_tbl[0].vector = bp->pdev->irq;
Michael Chan6d866ff2007-12-20 19:56:09 -08006177
Michael Chan5e9ad9e2008-06-19 16:43:17 -07006178 if ((bp->flags & BNX2_FLAG_MSIX_CAP) && !dis_msi && cpus > 1)
6179 bnx2_enable_msix(bp, msix_vecs);
Michael Chanb4b36042007-12-20 19:59:30 -08006180
David S. Millerf86e82f2008-01-21 17:15:40 -08006181 if ((bp->flags & BNX2_FLAG_MSI_CAP) && !dis_msi &&
6182 !(bp->flags & BNX2_FLAG_USING_MSIX)) {
Michael Chan6d866ff2007-12-20 19:56:09 -08006183 if (pci_enable_msi(bp->pdev) == 0) {
David S. Millerf86e82f2008-01-21 17:15:40 -08006184 bp->flags |= BNX2_FLAG_USING_MSI;
Michael Chan6d866ff2007-12-20 19:56:09 -08006185 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
David S. Millerf86e82f2008-01-21 17:15:40 -08006186 bp->flags |= BNX2_FLAG_ONE_SHOT_MSI;
Michael Chan6d866ff2007-12-20 19:56:09 -08006187 bp->irq_tbl[0].handler = bnx2_msi_1shot;
6188 } else
6189 bp->irq_tbl[0].handler = bnx2_msi;
Michael Chanb4b36042007-12-20 19:59:30 -08006190
6191 bp->irq_tbl[0].vector = bp->pdev->irq;
Michael Chan6d866ff2007-12-20 19:56:09 -08006192 }
6193 }
Benjamin Li706bf242008-07-18 17:55:11 -07006194
6195 bp->num_tx_rings = rounddown_pow_of_two(bp->irq_nvecs);
6196 bp->dev->real_num_tx_queues = bp->num_tx_rings;
6197
Michael Chan5e9ad9e2008-06-19 16:43:17 -07006198 bp->num_rx_rings = bp->irq_nvecs;
Michael Chan8e6a72c2007-05-03 13:24:48 -07006199}
6200
Michael Chanb6016b72005-05-26 13:03:09 -07006201/* Called with rtnl_lock */
6202static int
6203bnx2_open(struct net_device *dev)
6204{
Michael Chan972ec0d2006-01-23 16:12:43 -08006205 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006206 int rc;
6207
Michael Chan1b2f9222007-05-03 13:20:19 -07006208 netif_carrier_off(dev);
6209
Pavel Machek829ca9a2005-09-03 15:56:56 -07006210 bnx2_set_power_state(bp, PCI_D0);
Michael Chanb6016b72005-05-26 13:03:09 -07006211 bnx2_disable_int(bp);
6212
Michael Chan6d866ff2007-12-20 19:56:09 -08006213 bnx2_setup_int_mode(bp, disable_msi);
Benjamin Li4327ba42010-03-23 13:13:11 +00006214 bnx2_init_napi(bp);
Michael Chan35efa7c2007-12-20 19:56:37 -08006215 bnx2_napi_enable(bp);
Michael Chan35e90102008-06-19 16:37:42 -07006216 rc = bnx2_alloc_mem(bp);
Michael Chan2739a8b2008-06-19 16:44:10 -07006217 if (rc)
6218 goto open_err;
Michael Chan35e90102008-06-19 16:37:42 -07006219
Michael Chan8e6a72c2007-05-03 13:24:48 -07006220 rc = bnx2_request_irq(bp);
Michael Chan2739a8b2008-06-19 16:44:10 -07006221 if (rc)
6222 goto open_err;
Michael Chanb6016b72005-05-26 13:03:09 -07006223
Michael Chan9a120bc2008-05-16 22:17:45 -07006224 rc = bnx2_init_nic(bp, 1);
Michael Chan2739a8b2008-06-19 16:44:10 -07006225 if (rc)
6226 goto open_err;
Jeff Garzik6aa20a22006-09-13 13:24:59 -04006227
Michael Chancd339a02005-08-25 15:35:24 -07006228 mod_timer(&bp->timer, jiffies + bp->current_interval);
Michael Chanb6016b72005-05-26 13:03:09 -07006229
6230 atomic_set(&bp->intr_sem, 0);
6231
Michael Chan354fcd72010-01-17 07:30:44 +00006232 memset(bp->temp_stats_blk, 0, sizeof(struct statistics_block));
6233
Michael Chanb6016b72005-05-26 13:03:09 -07006234 bnx2_enable_int(bp);
6235
David S. Millerf86e82f2008-01-21 17:15:40 -08006236 if (bp->flags & BNX2_FLAG_USING_MSI) {
Michael Chanb6016b72005-05-26 13:03:09 -07006237 /* Test MSI to make sure it is working
6238 * If MSI test fails, go back to INTx mode
6239 */
6240 if (bnx2_test_intr(bp) != 0) {
Joe Perches3a9c6a42010-02-17 15:01:51 +00006241 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 -07006242
6243 bnx2_disable_int(bp);
Michael Chan8e6a72c2007-05-03 13:24:48 -07006244 bnx2_free_irq(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07006245
Michael Chan6d866ff2007-12-20 19:56:09 -08006246 bnx2_setup_int_mode(bp, 1);
6247
Michael Chan9a120bc2008-05-16 22:17:45 -07006248 rc = bnx2_init_nic(bp, 0);
Michael Chanb6016b72005-05-26 13:03:09 -07006249
Michael Chan8e6a72c2007-05-03 13:24:48 -07006250 if (!rc)
6251 rc = bnx2_request_irq(bp);
6252
Michael Chanb6016b72005-05-26 13:03:09 -07006253 if (rc) {
Michael Chanb6016b72005-05-26 13:03:09 -07006254 del_timer_sync(&bp->timer);
Michael Chan2739a8b2008-06-19 16:44:10 -07006255 goto open_err;
Michael Chanb6016b72005-05-26 13:03:09 -07006256 }
6257 bnx2_enable_int(bp);
6258 }
6259 }
David S. Millerf86e82f2008-01-21 17:15:40 -08006260 if (bp->flags & BNX2_FLAG_USING_MSI)
Joe Perches3a9c6a42010-02-17 15:01:51 +00006261 netdev_info(dev, "using MSI\n");
David S. Millerf86e82f2008-01-21 17:15:40 -08006262 else if (bp->flags & BNX2_FLAG_USING_MSIX)
Joe Perches3a9c6a42010-02-17 15:01:51 +00006263 netdev_info(dev, "using MSIX\n");
Michael Chanb6016b72005-05-26 13:03:09 -07006264
Benjamin Li706bf242008-07-18 17:55:11 -07006265 netif_tx_start_all_queues(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006266
6267 return 0;
Michael Chan2739a8b2008-06-19 16:44:10 -07006268
6269open_err:
6270 bnx2_napi_disable(bp);
6271 bnx2_free_skbs(bp);
6272 bnx2_free_irq(bp);
6273 bnx2_free_mem(bp);
Michael Chanf048fa92010-06-01 15:05:36 +00006274 bnx2_del_napi(bp);
Michael Chan2739a8b2008-06-19 16:44:10 -07006275 return rc;
Michael Chanb6016b72005-05-26 13:03:09 -07006276}
6277
6278static void
David Howellsc4028952006-11-22 14:57:56 +00006279bnx2_reset_task(struct work_struct *work)
Michael Chanb6016b72005-05-26 13:03:09 -07006280{
David Howellsc4028952006-11-22 14:57:56 +00006281 struct bnx2 *bp = container_of(work, struct bnx2, reset_task);
Michael Chanb6016b72005-05-26 13:03:09 -07006282
Michael Chan51bf6bb2009-12-03 09:46:31 +00006283 rtnl_lock();
6284 if (!netif_running(bp->dev)) {
6285 rtnl_unlock();
Michael Chanafdc08b2005-08-25 15:34:29 -07006286 return;
Michael Chan51bf6bb2009-12-03 09:46:31 +00006287 }
Michael Chanafdc08b2005-08-25 15:34:29 -07006288
Michael Chan212f9932010-04-27 11:28:10 +00006289 bnx2_netif_stop(bp, true);
Michael Chanb6016b72005-05-26 13:03:09 -07006290
Michael Chan9a120bc2008-05-16 22:17:45 -07006291 bnx2_init_nic(bp, 1);
Michael Chanb6016b72005-05-26 13:03:09 -07006292
6293 atomic_set(&bp->intr_sem, 1);
Michael Chan212f9932010-04-27 11:28:10 +00006294 bnx2_netif_start(bp, true);
Michael Chan51bf6bb2009-12-03 09:46:31 +00006295 rtnl_unlock();
Michael Chanb6016b72005-05-26 13:03:09 -07006296}
6297
6298static void
Michael Chan20175c52009-12-03 09:46:32 +00006299bnx2_dump_state(struct bnx2 *bp)
6300{
6301 struct net_device *dev = bp->dev;
Eddie Waib98eba52010-05-17 17:32:56 -07006302 u32 mcp_p0, mcp_p1;
Michael Chan20175c52009-12-03 09:46:32 +00006303
Joe Perches3a9c6a42010-02-17 15:01:51 +00006304 netdev_err(dev, "DEBUG: intr_sem[%x]\n", atomic_read(&bp->intr_sem));
Eddie Waib98eba52010-05-17 17:32:56 -07006305 netdev_err(dev, "DEBUG: EMAC_TX_STATUS[%08x] EMAC_RX_STATUS[%08x]\n",
Joe Perches3a9c6a42010-02-17 15:01:51 +00006306 REG_RD(bp, BNX2_EMAC_TX_STATUS),
Eddie Waib98eba52010-05-17 17:32:56 -07006307 REG_RD(bp, BNX2_EMAC_RX_STATUS));
6308 netdev_err(dev, "DEBUG: RPM_MGMT_PKT_CTRL[%08x]\n",
Joe Perches3a9c6a42010-02-17 15:01:51 +00006309 REG_RD(bp, BNX2_RPM_MGMT_PKT_CTRL));
Eddie Waib98eba52010-05-17 17:32:56 -07006310 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
6311 mcp_p0 = BNX2_MCP_STATE_P0;
6312 mcp_p1 = BNX2_MCP_STATE_P1;
6313 } else {
6314 mcp_p0 = BNX2_MCP_STATE_P0_5708;
6315 mcp_p1 = BNX2_MCP_STATE_P1_5708;
6316 }
Joe Perches3a9c6a42010-02-17 15:01:51 +00006317 netdev_err(dev, "DEBUG: MCP_STATE_P0[%08x] MCP_STATE_P1[%08x]\n",
Eddie Waib98eba52010-05-17 17:32:56 -07006318 bnx2_reg_rd_ind(bp, mcp_p0), bnx2_reg_rd_ind(bp, mcp_p1));
Joe Perches3a9c6a42010-02-17 15:01:51 +00006319 netdev_err(dev, "DEBUG: HC_STATS_INTERRUPT_STATUS[%08x]\n",
6320 REG_RD(bp, BNX2_HC_STATS_INTERRUPT_STATUS));
Michael Chan20175c52009-12-03 09:46:32 +00006321 if (bp->flags & BNX2_FLAG_USING_MSIX)
Joe Perches3a9c6a42010-02-17 15:01:51 +00006322 netdev_err(dev, "DEBUG: PBA[%08x]\n",
6323 REG_RD(bp, BNX2_PCI_GRC_WINDOW3_BASE));
Michael Chan20175c52009-12-03 09:46:32 +00006324}
6325
6326static void
Michael Chanb6016b72005-05-26 13:03:09 -07006327bnx2_tx_timeout(struct net_device *dev)
6328{
Michael Chan972ec0d2006-01-23 16:12:43 -08006329 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006330
Michael Chan20175c52009-12-03 09:46:32 +00006331 bnx2_dump_state(bp);
6332
Michael Chanb6016b72005-05-26 13:03:09 -07006333 /* This allows the netif to be shutdown gracefully before resetting */
6334 schedule_work(&bp->reset_task);
6335}
6336
6337#ifdef BCM_VLAN
6338/* Called with rtnl_lock */
6339static void
6340bnx2_vlan_rx_register(struct net_device *dev, struct vlan_group *vlgrp)
6341{
Michael Chan972ec0d2006-01-23 16:12:43 -08006342 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006343
Michael Chan37675462009-08-21 16:20:44 +00006344 if (netif_running(dev))
Michael Chan212f9932010-04-27 11:28:10 +00006345 bnx2_netif_stop(bp, false);
Michael Chanb6016b72005-05-26 13:03:09 -07006346
6347 bp->vlgrp = vlgrp;
Michael Chan37675462009-08-21 16:20:44 +00006348
6349 if (!netif_running(dev))
6350 return;
6351
Michael Chanb6016b72005-05-26 13:03:09 -07006352 bnx2_set_rx_mode(dev);
Michael Chan7c62e832008-07-14 22:39:03 -07006353 if (bp->flags & BNX2_FLAG_CAN_KEEP_VLAN)
6354 bnx2_fw_sync(bp, BNX2_DRV_MSG_CODE_KEEP_VLAN_UPDATE, 0, 1);
Michael Chanb6016b72005-05-26 13:03:09 -07006355
Michael Chan212f9932010-04-27 11:28:10 +00006356 bnx2_netif_start(bp, false);
Michael Chanb6016b72005-05-26 13:03:09 -07006357}
Michael Chanb6016b72005-05-26 13:03:09 -07006358#endif
6359
Herbert Xu932ff272006-06-09 12:20:56 -07006360/* Called with netif_tx_lock.
Michael Chan2f8af122006-08-15 01:39:10 -07006361 * bnx2_tx_int() runs without netif_tx_lock unless it needs to call
6362 * netif_wake_queue().
Michael Chanb6016b72005-05-26 13:03:09 -07006363 */
Stephen Hemminger613573252009-08-31 19:50:58 +00006364static netdev_tx_t
Michael Chanb6016b72005-05-26 13:03:09 -07006365bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev)
6366{
Michael Chan972ec0d2006-01-23 16:12:43 -08006367 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006368 dma_addr_t mapping;
6369 struct tx_bd *txbd;
Benjamin Li3d16af82008-10-09 12:26:41 -07006370 struct sw_tx_bd *tx_buf;
Michael Chanb6016b72005-05-26 13:03:09 -07006371 u32 len, vlan_tag_flags, last_frag, mss;
6372 u16 prod, ring_prod;
6373 int i;
Benjamin Li706bf242008-07-18 17:55:11 -07006374 struct bnx2_napi *bnapi;
6375 struct bnx2_tx_ring_info *txr;
6376 struct netdev_queue *txq;
6377
6378 /* Determine which tx ring we will be placed on */
6379 i = skb_get_queue_mapping(skb);
6380 bnapi = &bp->bnx2_napi[i];
6381 txr = &bnapi->tx_ring;
6382 txq = netdev_get_tx_queue(dev, i);
Michael Chanb6016b72005-05-26 13:03:09 -07006383
Michael Chan35e90102008-06-19 16:37:42 -07006384 if (unlikely(bnx2_tx_avail(bp, txr) <
Michael Chana550c992007-12-20 19:56:59 -08006385 (skb_shinfo(skb)->nr_frags + 1))) {
Benjamin Li706bf242008-07-18 17:55:11 -07006386 netif_tx_stop_queue(txq);
Joe Perches3a9c6a42010-02-17 15:01:51 +00006387 netdev_err(dev, "BUG! Tx ring full when queue awake!\n");
Michael Chanb6016b72005-05-26 13:03:09 -07006388
6389 return NETDEV_TX_BUSY;
6390 }
6391 len = skb_headlen(skb);
Michael Chan35e90102008-06-19 16:37:42 -07006392 prod = txr->tx_prod;
Michael Chanb6016b72005-05-26 13:03:09 -07006393 ring_prod = TX_RING_IDX(prod);
6394
6395 vlan_tag_flags = 0;
Patrick McHardy84fa7932006-08-29 16:44:56 -07006396 if (skb->ip_summed == CHECKSUM_PARTIAL) {
Michael Chanb6016b72005-05-26 13:03:09 -07006397 vlan_tag_flags |= TX_BD_FLAGS_TCP_UDP_CKSUM;
6398 }
6399
Michael Chan729b85c2008-08-14 15:29:39 -07006400#ifdef BCM_VLAN
Al Viro79ea13c2008-01-24 02:06:46 -08006401 if (bp->vlgrp && vlan_tx_tag_present(skb)) {
Michael Chanb6016b72005-05-26 13:03:09 -07006402 vlan_tag_flags |=
6403 (TX_BD_FLAGS_VLAN_TAG | (vlan_tx_tag_get(skb) << 16));
6404 }
Michael Chan729b85c2008-08-14 15:29:39 -07006405#endif
Michael Chanfde82052007-05-03 17:23:35 -07006406 if ((mss = skb_shinfo(skb)->gso_size)) {
Michael Chana1efb4b2008-10-09 12:24:39 -07006407 u32 tcp_opt_len;
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -07006408 struct iphdr *iph;
Michael Chanb6016b72005-05-26 13:03:09 -07006409
Michael Chanb6016b72005-05-26 13:03:09 -07006410 vlan_tag_flags |= TX_BD_FLAGS_SW_LSO;
6411
Michael Chan4666f872007-05-03 13:22:28 -07006412 tcp_opt_len = tcp_optlen(skb);
Arnaldo Carvalho de Meloab6a5bb2007-03-18 17:43:48 -07006413
Michael Chan4666f872007-05-03 13:22:28 -07006414 if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6) {
6415 u32 tcp_off = skb_transport_offset(skb) -
6416 sizeof(struct ipv6hdr) - ETH_HLEN;
Michael Chanb6016b72005-05-26 13:03:09 -07006417
Michael Chan4666f872007-05-03 13:22:28 -07006418 vlan_tag_flags |= ((tcp_opt_len >> 2) << 8) |
6419 TX_BD_FLAGS_SW_FLAGS;
6420 if (likely(tcp_off == 0))
6421 vlan_tag_flags &= ~TX_BD_FLAGS_TCP6_OFF0_MSK;
6422 else {
6423 tcp_off >>= 3;
6424 vlan_tag_flags |= ((tcp_off & 0x3) <<
6425 TX_BD_FLAGS_TCP6_OFF0_SHL) |
6426 ((tcp_off & 0x10) <<
6427 TX_BD_FLAGS_TCP6_OFF4_SHL);
6428 mss |= (tcp_off & 0xc) << TX_BD_TCP6_OFF2_SHL;
6429 }
6430 } else {
Michael Chan4666f872007-05-03 13:22:28 -07006431 iph = ip_hdr(skb);
Michael Chan4666f872007-05-03 13:22:28 -07006432 if (tcp_opt_len || (iph->ihl > 5)) {
6433 vlan_tag_flags |= ((iph->ihl - 5) +
6434 (tcp_opt_len >> 2)) << 8;
6435 }
Michael Chanb6016b72005-05-26 13:03:09 -07006436 }
Michael Chan4666f872007-05-03 13:22:28 -07006437 } else
Michael Chanb6016b72005-05-26 13:03:09 -07006438 mss = 0;
Michael Chanb6016b72005-05-26 13:03:09 -07006439
Alexander Duycke95524a2009-12-02 16:47:57 +00006440 mapping = pci_map_single(bp->pdev, skb->data, len, PCI_DMA_TODEVICE);
6441 if (pci_dma_mapping_error(bp->pdev, mapping)) {
Benjamin Li3d16af82008-10-09 12:26:41 -07006442 dev_kfree_skb(skb);
6443 return NETDEV_TX_OK;
6444 }
6445
Michael Chan35e90102008-06-19 16:37:42 -07006446 tx_buf = &txr->tx_buf_ring[ring_prod];
Michael Chanb6016b72005-05-26 13:03:09 -07006447 tx_buf->skb = skb;
FUJITA Tomonori1a4ccc22010-04-01 16:56:57 +00006448 dma_unmap_addr_set(tx_buf, mapping, mapping);
Michael Chanb6016b72005-05-26 13:03:09 -07006449
Michael Chan35e90102008-06-19 16:37:42 -07006450 txbd = &txr->tx_desc_ring[ring_prod];
Michael Chanb6016b72005-05-26 13:03:09 -07006451
6452 txbd->tx_bd_haddr_hi = (u64) mapping >> 32;
6453 txbd->tx_bd_haddr_lo = (u64) mapping & 0xffffffff;
6454 txbd->tx_bd_mss_nbytes = len | (mss << 16);
6455 txbd->tx_bd_vlan_tag_flags = vlan_tag_flags | TX_BD_FLAGS_START;
6456
6457 last_frag = skb_shinfo(skb)->nr_frags;
Eric Dumazetd62fda02009-05-12 20:48:02 +00006458 tx_buf->nr_frags = last_frag;
6459 tx_buf->is_gso = skb_is_gso(skb);
Michael Chanb6016b72005-05-26 13:03:09 -07006460
6461 for (i = 0; i < last_frag; i++) {
6462 skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
6463
6464 prod = NEXT_TX_BD(prod);
6465 ring_prod = TX_RING_IDX(prod);
Michael Chan35e90102008-06-19 16:37:42 -07006466 txbd = &txr->tx_desc_ring[ring_prod];
Michael Chanb6016b72005-05-26 13:03:09 -07006467
6468 len = frag->size;
Alexander Duycke95524a2009-12-02 16:47:57 +00006469 mapping = pci_map_page(bp->pdev, frag->page, frag->page_offset,
6470 len, PCI_DMA_TODEVICE);
6471 if (pci_dma_mapping_error(bp->pdev, mapping))
6472 goto dma_error;
FUJITA Tomonori1a4ccc22010-04-01 16:56:57 +00006473 dma_unmap_addr_set(&txr->tx_buf_ring[ring_prod], mapping,
Alexander Duycke95524a2009-12-02 16:47:57 +00006474 mapping);
Michael Chanb6016b72005-05-26 13:03:09 -07006475
6476 txbd->tx_bd_haddr_hi = (u64) mapping >> 32;
6477 txbd->tx_bd_haddr_lo = (u64) mapping & 0xffffffff;
6478 txbd->tx_bd_mss_nbytes = len | (mss << 16);
6479 txbd->tx_bd_vlan_tag_flags = vlan_tag_flags;
6480
6481 }
6482 txbd->tx_bd_vlan_tag_flags |= TX_BD_FLAGS_END;
6483
6484 prod = NEXT_TX_BD(prod);
Michael Chan35e90102008-06-19 16:37:42 -07006485 txr->tx_prod_bseq += skb->len;
Michael Chanb6016b72005-05-26 13:03:09 -07006486
Michael Chan35e90102008-06-19 16:37:42 -07006487 REG_WR16(bp, txr->tx_bidx_addr, prod);
6488 REG_WR(bp, txr->tx_bseq_addr, txr->tx_prod_bseq);
Michael Chanb6016b72005-05-26 13:03:09 -07006489
6490 mmiowb();
6491
Michael Chan35e90102008-06-19 16:37:42 -07006492 txr->tx_prod = prod;
Michael Chanb6016b72005-05-26 13:03:09 -07006493
Michael Chan35e90102008-06-19 16:37:42 -07006494 if (unlikely(bnx2_tx_avail(bp, txr) <= MAX_SKB_FRAGS)) {
Benjamin Li706bf242008-07-18 17:55:11 -07006495 netif_tx_stop_queue(txq);
Michael Chan35e90102008-06-19 16:37:42 -07006496 if (bnx2_tx_avail(bp, txr) > bp->tx_wake_thresh)
Benjamin Li706bf242008-07-18 17:55:11 -07006497 netif_tx_wake_queue(txq);
Michael Chanb6016b72005-05-26 13:03:09 -07006498 }
6499
6500 return NETDEV_TX_OK;
Alexander Duycke95524a2009-12-02 16:47:57 +00006501dma_error:
6502 /* save value of frag that failed */
6503 last_frag = i;
6504
6505 /* start back at beginning and unmap skb */
6506 prod = txr->tx_prod;
6507 ring_prod = TX_RING_IDX(prod);
6508 tx_buf = &txr->tx_buf_ring[ring_prod];
6509 tx_buf->skb = NULL;
FUJITA Tomonori1a4ccc22010-04-01 16:56:57 +00006510 pci_unmap_single(bp->pdev, dma_unmap_addr(tx_buf, mapping),
Alexander Duycke95524a2009-12-02 16:47:57 +00006511 skb_headlen(skb), PCI_DMA_TODEVICE);
6512
6513 /* unmap remaining mapped pages */
6514 for (i = 0; i < last_frag; i++) {
6515 prod = NEXT_TX_BD(prod);
6516 ring_prod = TX_RING_IDX(prod);
6517 tx_buf = &txr->tx_buf_ring[ring_prod];
FUJITA Tomonori1a4ccc22010-04-01 16:56:57 +00006518 pci_unmap_page(bp->pdev, dma_unmap_addr(tx_buf, mapping),
Alexander Duycke95524a2009-12-02 16:47:57 +00006519 skb_shinfo(skb)->frags[i].size,
6520 PCI_DMA_TODEVICE);
6521 }
6522
6523 dev_kfree_skb(skb);
6524 return NETDEV_TX_OK;
Michael Chanb6016b72005-05-26 13:03:09 -07006525}
6526
6527/* Called with rtnl_lock */
6528static int
6529bnx2_close(struct net_device *dev)
6530{
Michael Chan972ec0d2006-01-23 16:12:43 -08006531 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006532
David S. Miller4bb073c2008-06-12 02:22:02 -07006533 cancel_work_sync(&bp->reset_task);
Michael Chanafdc08b2005-08-25 15:34:29 -07006534
Stephen Hemmingerbea33482007-10-03 16:41:36 -07006535 bnx2_disable_int_sync(bp);
Michael Chan35efa7c2007-12-20 19:56:37 -08006536 bnx2_napi_disable(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07006537 del_timer_sync(&bp->timer);
Michael Chan74bf4ba2008-10-09 12:21:08 -07006538 bnx2_shutdown_chip(bp);
Michael Chan8e6a72c2007-05-03 13:24:48 -07006539 bnx2_free_irq(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07006540 bnx2_free_skbs(bp);
6541 bnx2_free_mem(bp);
Michael Chanf048fa92010-06-01 15:05:36 +00006542 bnx2_del_napi(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07006543 bp->link_up = 0;
6544 netif_carrier_off(bp->dev);
Pavel Machek829ca9a2005-09-03 15:56:56 -07006545 bnx2_set_power_state(bp, PCI_D3hot);
Michael Chanb6016b72005-05-26 13:03:09 -07006546 return 0;
6547}
6548
Michael Chan354fcd72010-01-17 07:30:44 +00006549static void
6550bnx2_save_stats(struct bnx2 *bp)
6551{
6552 u32 *hw_stats = (u32 *) bp->stats_blk;
6553 u32 *temp_stats = (u32 *) bp->temp_stats_blk;
6554 int i;
6555
6556 /* The 1st 10 counters are 64-bit counters */
6557 for (i = 0; i < 20; i += 2) {
6558 u32 hi;
6559 u64 lo;
6560
Patrick Rabauc9885fe2010-02-15 19:42:11 +00006561 hi = temp_stats[i] + hw_stats[i];
6562 lo = (u64) temp_stats[i + 1] + (u64) hw_stats[i + 1];
Michael Chan354fcd72010-01-17 07:30:44 +00006563 if (lo > 0xffffffff)
6564 hi++;
Patrick Rabauc9885fe2010-02-15 19:42:11 +00006565 temp_stats[i] = hi;
6566 temp_stats[i + 1] = lo & 0xffffffff;
Michael Chan354fcd72010-01-17 07:30:44 +00006567 }
6568
6569 for ( ; i < sizeof(struct statistics_block) / 4; i++)
Patrick Rabauc9885fe2010-02-15 19:42:11 +00006570 temp_stats[i] += hw_stats[i];
Michael Chan354fcd72010-01-17 07:30:44 +00006571}
6572
Michael Chana4743052010-01-17 07:30:43 +00006573#define GET_64BIT_NET_STATS64(ctr) \
Michael Chanb6016b72005-05-26 13:03:09 -07006574 (unsigned long) ((unsigned long) (ctr##_hi) << 32) + \
6575 (unsigned long) (ctr##_lo)
6576
Michael Chana4743052010-01-17 07:30:43 +00006577#define GET_64BIT_NET_STATS32(ctr) \
Michael Chanb6016b72005-05-26 13:03:09 -07006578 (ctr##_lo)
6579
6580#if (BITS_PER_LONG == 64)
Michael Chana4743052010-01-17 07:30:43 +00006581#define GET_64BIT_NET_STATS(ctr) \
Michael Chan354fcd72010-01-17 07:30:44 +00006582 GET_64BIT_NET_STATS64(bp->stats_blk->ctr) + \
6583 GET_64BIT_NET_STATS64(bp->temp_stats_blk->ctr)
Michael Chanb6016b72005-05-26 13:03:09 -07006584#else
Michael Chana4743052010-01-17 07:30:43 +00006585#define GET_64BIT_NET_STATS(ctr) \
Michael Chan354fcd72010-01-17 07:30:44 +00006586 GET_64BIT_NET_STATS32(bp->stats_blk->ctr) + \
6587 GET_64BIT_NET_STATS32(bp->temp_stats_blk->ctr)
Michael Chanb6016b72005-05-26 13:03:09 -07006588#endif
6589
Michael Chana4743052010-01-17 07:30:43 +00006590#define GET_32BIT_NET_STATS(ctr) \
Michael Chan354fcd72010-01-17 07:30:44 +00006591 (unsigned long) (bp->stats_blk->ctr + \
6592 bp->temp_stats_blk->ctr)
Michael Chana4743052010-01-17 07:30:43 +00006593
Michael Chanb6016b72005-05-26 13:03:09 -07006594static struct net_device_stats *
6595bnx2_get_stats(struct net_device *dev)
6596{
Michael Chan972ec0d2006-01-23 16:12:43 -08006597 struct bnx2 *bp = netdev_priv(dev);
Ilpo Järvinend8e80342008-11-28 15:52:43 -08006598 struct net_device_stats *net_stats = &dev->stats;
Michael Chanb6016b72005-05-26 13:03:09 -07006599
6600 if (bp->stats_blk == NULL) {
6601 return net_stats;
6602 }
6603 net_stats->rx_packets =
Michael Chana4743052010-01-17 07:30:43 +00006604 GET_64BIT_NET_STATS(stat_IfHCInUcastPkts) +
6605 GET_64BIT_NET_STATS(stat_IfHCInMulticastPkts) +
6606 GET_64BIT_NET_STATS(stat_IfHCInBroadcastPkts);
Michael Chanb6016b72005-05-26 13:03:09 -07006607
6608 net_stats->tx_packets =
Michael Chana4743052010-01-17 07:30:43 +00006609 GET_64BIT_NET_STATS(stat_IfHCOutUcastPkts) +
6610 GET_64BIT_NET_STATS(stat_IfHCOutMulticastPkts) +
6611 GET_64BIT_NET_STATS(stat_IfHCOutBroadcastPkts);
Michael Chanb6016b72005-05-26 13:03:09 -07006612
6613 net_stats->rx_bytes =
Michael Chana4743052010-01-17 07:30:43 +00006614 GET_64BIT_NET_STATS(stat_IfHCInOctets);
Michael Chanb6016b72005-05-26 13:03:09 -07006615
6616 net_stats->tx_bytes =
Michael Chana4743052010-01-17 07:30:43 +00006617 GET_64BIT_NET_STATS(stat_IfHCOutOctets);
Michael Chanb6016b72005-05-26 13:03:09 -07006618
Jeff Garzik6aa20a22006-09-13 13:24:59 -04006619 net_stats->multicast =
Michael Chana4743052010-01-17 07:30:43 +00006620 GET_64BIT_NET_STATS(stat_IfHCOutMulticastPkts);
Michael Chanb6016b72005-05-26 13:03:09 -07006621
Jeff Garzik6aa20a22006-09-13 13:24:59 -04006622 net_stats->collisions =
Michael Chana4743052010-01-17 07:30:43 +00006623 GET_32BIT_NET_STATS(stat_EtherStatsCollisions);
Michael Chanb6016b72005-05-26 13:03:09 -07006624
Jeff Garzik6aa20a22006-09-13 13:24:59 -04006625 net_stats->rx_length_errors =
Michael Chana4743052010-01-17 07:30:43 +00006626 GET_32BIT_NET_STATS(stat_EtherStatsUndersizePkts) +
6627 GET_32BIT_NET_STATS(stat_EtherStatsOverrsizePkts);
Michael Chanb6016b72005-05-26 13:03:09 -07006628
Jeff Garzik6aa20a22006-09-13 13:24:59 -04006629 net_stats->rx_over_errors =
Michael Chana4743052010-01-17 07:30:43 +00006630 GET_32BIT_NET_STATS(stat_IfInFTQDiscards) +
6631 GET_32BIT_NET_STATS(stat_IfInMBUFDiscards);
Michael Chanb6016b72005-05-26 13:03:09 -07006632
Jeff Garzik6aa20a22006-09-13 13:24:59 -04006633 net_stats->rx_frame_errors =
Michael Chana4743052010-01-17 07:30:43 +00006634 GET_32BIT_NET_STATS(stat_Dot3StatsAlignmentErrors);
Michael Chanb6016b72005-05-26 13:03:09 -07006635
Jeff Garzik6aa20a22006-09-13 13:24:59 -04006636 net_stats->rx_crc_errors =
Michael Chana4743052010-01-17 07:30:43 +00006637 GET_32BIT_NET_STATS(stat_Dot3StatsFCSErrors);
Michael Chanb6016b72005-05-26 13:03:09 -07006638
6639 net_stats->rx_errors = net_stats->rx_length_errors +
6640 net_stats->rx_over_errors + net_stats->rx_frame_errors +
6641 net_stats->rx_crc_errors;
6642
6643 net_stats->tx_aborted_errors =
Michael Chana4743052010-01-17 07:30:43 +00006644 GET_32BIT_NET_STATS(stat_Dot3StatsExcessiveCollisions) +
6645 GET_32BIT_NET_STATS(stat_Dot3StatsLateCollisions);
Michael Chanb6016b72005-05-26 13:03:09 -07006646
Michael Chan5b0c76a2005-11-04 08:45:49 -08006647 if ((CHIP_NUM(bp) == CHIP_NUM_5706) ||
6648 (CHIP_ID(bp) == CHIP_ID_5708_A0))
Michael Chanb6016b72005-05-26 13:03:09 -07006649 net_stats->tx_carrier_errors = 0;
6650 else {
6651 net_stats->tx_carrier_errors =
Michael Chana4743052010-01-17 07:30:43 +00006652 GET_32BIT_NET_STATS(stat_Dot3StatsCarrierSenseErrors);
Michael Chanb6016b72005-05-26 13:03:09 -07006653 }
6654
6655 net_stats->tx_errors =
Michael Chana4743052010-01-17 07:30:43 +00006656 GET_32BIT_NET_STATS(stat_emac_tx_stat_dot3statsinternalmactransmiterrors) +
Michael Chanb6016b72005-05-26 13:03:09 -07006657 net_stats->tx_aborted_errors +
6658 net_stats->tx_carrier_errors;
6659
Michael Chancea94db2006-06-12 22:16:13 -07006660 net_stats->rx_missed_errors =
Michael Chana4743052010-01-17 07:30:43 +00006661 GET_32BIT_NET_STATS(stat_IfInFTQDiscards) +
6662 GET_32BIT_NET_STATS(stat_IfInMBUFDiscards) +
6663 GET_32BIT_NET_STATS(stat_FwRxDrop);
Michael Chancea94db2006-06-12 22:16:13 -07006664
Michael Chanb6016b72005-05-26 13:03:09 -07006665 return net_stats;
6666}
6667
6668/* All ethtool functions called with rtnl_lock */
6669
6670static int
6671bnx2_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
6672{
Michael Chan972ec0d2006-01-23 16:12:43 -08006673 struct bnx2 *bp = netdev_priv(dev);
Michael Chan7b6b8342007-07-07 22:50:15 -07006674 int support_serdes = 0, support_copper = 0;
Michael Chanb6016b72005-05-26 13:03:09 -07006675
6676 cmd->supported = SUPPORTED_Autoneg;
Michael Chan583c28e2008-01-21 19:51:35 -08006677 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP) {
Michael Chan7b6b8342007-07-07 22:50:15 -07006678 support_serdes = 1;
6679 support_copper = 1;
6680 } else if (bp->phy_port == PORT_FIBRE)
6681 support_serdes = 1;
6682 else
6683 support_copper = 1;
6684
6685 if (support_serdes) {
Michael Chanb6016b72005-05-26 13:03:09 -07006686 cmd->supported |= SUPPORTED_1000baseT_Full |
6687 SUPPORTED_FIBRE;
Michael Chan583c28e2008-01-21 19:51:35 -08006688 if (bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE)
Michael Chan605a9e22007-05-03 13:23:13 -07006689 cmd->supported |= SUPPORTED_2500baseX_Full;
Michael Chanb6016b72005-05-26 13:03:09 -07006690
Michael Chanb6016b72005-05-26 13:03:09 -07006691 }
Michael Chan7b6b8342007-07-07 22:50:15 -07006692 if (support_copper) {
Michael Chanb6016b72005-05-26 13:03:09 -07006693 cmd->supported |= SUPPORTED_10baseT_Half |
6694 SUPPORTED_10baseT_Full |
6695 SUPPORTED_100baseT_Half |
6696 SUPPORTED_100baseT_Full |
6697 SUPPORTED_1000baseT_Full |
6698 SUPPORTED_TP;
6699
Michael Chanb6016b72005-05-26 13:03:09 -07006700 }
6701
Michael Chan7b6b8342007-07-07 22:50:15 -07006702 spin_lock_bh(&bp->phy_lock);
6703 cmd->port = bp->phy_port;
Michael Chanb6016b72005-05-26 13:03:09 -07006704 cmd->advertising = bp->advertising;
6705
6706 if (bp->autoneg & AUTONEG_SPEED) {
6707 cmd->autoneg = AUTONEG_ENABLE;
6708 }
6709 else {
6710 cmd->autoneg = AUTONEG_DISABLE;
6711 }
6712
6713 if (netif_carrier_ok(dev)) {
6714 cmd->speed = bp->line_speed;
6715 cmd->duplex = bp->duplex;
6716 }
6717 else {
6718 cmd->speed = -1;
6719 cmd->duplex = -1;
6720 }
Michael Chan7b6b8342007-07-07 22:50:15 -07006721 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07006722
6723 cmd->transceiver = XCVR_INTERNAL;
6724 cmd->phy_address = bp->phy_addr;
6725
6726 return 0;
6727}
Jeff Garzik6aa20a22006-09-13 13:24:59 -04006728
Michael Chanb6016b72005-05-26 13:03:09 -07006729static int
6730bnx2_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
6731{
Michael Chan972ec0d2006-01-23 16:12:43 -08006732 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006733 u8 autoneg = bp->autoneg;
6734 u8 req_duplex = bp->req_duplex;
6735 u16 req_line_speed = bp->req_line_speed;
6736 u32 advertising = bp->advertising;
Michael Chan7b6b8342007-07-07 22:50:15 -07006737 int err = -EINVAL;
6738
6739 spin_lock_bh(&bp->phy_lock);
6740
6741 if (cmd->port != PORT_TP && cmd->port != PORT_FIBRE)
6742 goto err_out_unlock;
6743
Michael Chan583c28e2008-01-21 19:51:35 -08006744 if (cmd->port != bp->phy_port &&
6745 !(bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP))
Michael Chan7b6b8342007-07-07 22:50:15 -07006746 goto err_out_unlock;
Michael Chanb6016b72005-05-26 13:03:09 -07006747
Michael Chand6b14482008-07-14 22:37:21 -07006748 /* If device is down, we can store the settings only if the user
6749 * is setting the currently active port.
6750 */
6751 if (!netif_running(dev) && cmd->port != bp->phy_port)
6752 goto err_out_unlock;
6753
Michael Chanb6016b72005-05-26 13:03:09 -07006754 if (cmd->autoneg == AUTONEG_ENABLE) {
6755 autoneg |= AUTONEG_SPEED;
6756
Michael Chanbeb499a2010-02-15 19:42:10 +00006757 advertising = cmd->advertising;
6758 if (cmd->port == PORT_TP) {
6759 advertising &= ETHTOOL_ALL_COPPER_SPEED;
6760 if (!advertising)
Michael Chanb6016b72005-05-26 13:03:09 -07006761 advertising = ETHTOOL_ALL_COPPER_SPEED;
Michael Chanbeb499a2010-02-15 19:42:10 +00006762 } else {
6763 advertising &= ETHTOOL_ALL_FIBRE_SPEED;
6764 if (!advertising)
6765 advertising = ETHTOOL_ALL_FIBRE_SPEED;
Michael Chanb6016b72005-05-26 13:03:09 -07006766 }
6767 advertising |= ADVERTISED_Autoneg;
6768 }
6769 else {
Michael Chan7b6b8342007-07-07 22:50:15 -07006770 if (cmd->port == PORT_FIBRE) {
Michael Chan80be4432006-11-19 14:07:28 -08006771 if ((cmd->speed != SPEED_1000 &&
6772 cmd->speed != SPEED_2500) ||
6773 (cmd->duplex != DUPLEX_FULL))
Michael Chan7b6b8342007-07-07 22:50:15 -07006774 goto err_out_unlock;
Michael Chan80be4432006-11-19 14:07:28 -08006775
6776 if (cmd->speed == SPEED_2500 &&
Michael Chan583c28e2008-01-21 19:51:35 -08006777 !(bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE))
Michael Chan7b6b8342007-07-07 22:50:15 -07006778 goto err_out_unlock;
Michael Chanb6016b72005-05-26 13:03:09 -07006779 }
Michael Chan7b6b8342007-07-07 22:50:15 -07006780 else if (cmd->speed == SPEED_1000 || cmd->speed == SPEED_2500)
6781 goto err_out_unlock;
6782
Michael Chanb6016b72005-05-26 13:03:09 -07006783 autoneg &= ~AUTONEG_SPEED;
6784 req_line_speed = cmd->speed;
6785 req_duplex = cmd->duplex;
6786 advertising = 0;
6787 }
6788
6789 bp->autoneg = autoneg;
6790 bp->advertising = advertising;
6791 bp->req_line_speed = req_line_speed;
6792 bp->req_duplex = req_duplex;
6793
Michael Chand6b14482008-07-14 22:37:21 -07006794 err = 0;
6795 /* If device is down, the new settings will be picked up when it is
6796 * brought up.
6797 */
6798 if (netif_running(dev))
6799 err = bnx2_setup_phy(bp, cmd->port);
Michael Chanb6016b72005-05-26 13:03:09 -07006800
Michael Chan7b6b8342007-07-07 22:50:15 -07006801err_out_unlock:
Michael Chanc770a652005-08-25 15:38:39 -07006802 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07006803
Michael Chan7b6b8342007-07-07 22:50:15 -07006804 return err;
Michael Chanb6016b72005-05-26 13:03:09 -07006805}
6806
6807static void
6808bnx2_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
6809{
Michael Chan972ec0d2006-01-23 16:12:43 -08006810 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006811
6812 strcpy(info->driver, DRV_MODULE_NAME);
6813 strcpy(info->version, DRV_MODULE_VERSION);
6814 strcpy(info->bus_info, pci_name(bp->pdev));
Michael Chan58fc2ea2007-07-07 22:52:02 -07006815 strcpy(info->fw_version, bp->fw_version);
Michael Chanb6016b72005-05-26 13:03:09 -07006816}
6817
Michael Chan244ac4f2006-03-20 17:48:46 -08006818#define BNX2_REGDUMP_LEN (32 * 1024)
6819
6820static int
6821bnx2_get_regs_len(struct net_device *dev)
6822{
6823 return BNX2_REGDUMP_LEN;
6824}
6825
6826static void
6827bnx2_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *_p)
6828{
6829 u32 *p = _p, i, offset;
6830 u8 *orig_p = _p;
6831 struct bnx2 *bp = netdev_priv(dev);
6832 u32 reg_boundaries[] = { 0x0000, 0x0098, 0x0400, 0x045c,
6833 0x0800, 0x0880, 0x0c00, 0x0c10,
6834 0x0c30, 0x0d08, 0x1000, 0x101c,
6835 0x1040, 0x1048, 0x1080, 0x10a4,
6836 0x1400, 0x1490, 0x1498, 0x14f0,
6837 0x1500, 0x155c, 0x1580, 0x15dc,
6838 0x1600, 0x1658, 0x1680, 0x16d8,
6839 0x1800, 0x1820, 0x1840, 0x1854,
6840 0x1880, 0x1894, 0x1900, 0x1984,
6841 0x1c00, 0x1c0c, 0x1c40, 0x1c54,
6842 0x1c80, 0x1c94, 0x1d00, 0x1d84,
6843 0x2000, 0x2030, 0x23c0, 0x2400,
6844 0x2800, 0x2820, 0x2830, 0x2850,
6845 0x2b40, 0x2c10, 0x2fc0, 0x3058,
6846 0x3c00, 0x3c94, 0x4000, 0x4010,
6847 0x4080, 0x4090, 0x43c0, 0x4458,
6848 0x4c00, 0x4c18, 0x4c40, 0x4c54,
6849 0x4fc0, 0x5010, 0x53c0, 0x5444,
6850 0x5c00, 0x5c18, 0x5c80, 0x5c90,
6851 0x5fc0, 0x6000, 0x6400, 0x6428,
6852 0x6800, 0x6848, 0x684c, 0x6860,
6853 0x6888, 0x6910, 0x8000 };
6854
6855 regs->version = 0;
6856
6857 memset(p, 0, BNX2_REGDUMP_LEN);
6858
6859 if (!netif_running(bp->dev))
6860 return;
6861
6862 i = 0;
6863 offset = reg_boundaries[0];
6864 p += offset;
6865 while (offset < BNX2_REGDUMP_LEN) {
6866 *p++ = REG_RD(bp, offset);
6867 offset += 4;
6868 if (offset == reg_boundaries[i + 1]) {
6869 offset = reg_boundaries[i + 2];
6870 p = (u32 *) (orig_p + offset);
6871 i += 2;
6872 }
6873 }
6874}
6875
Michael Chanb6016b72005-05-26 13:03:09 -07006876static void
6877bnx2_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
6878{
Michael Chan972ec0d2006-01-23 16:12:43 -08006879 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006880
David S. Millerf86e82f2008-01-21 17:15:40 -08006881 if (bp->flags & BNX2_FLAG_NO_WOL) {
Michael Chanb6016b72005-05-26 13:03:09 -07006882 wol->supported = 0;
6883 wol->wolopts = 0;
6884 }
6885 else {
6886 wol->supported = WAKE_MAGIC;
6887 if (bp->wol)
6888 wol->wolopts = WAKE_MAGIC;
6889 else
6890 wol->wolopts = 0;
6891 }
6892 memset(&wol->sopass, 0, sizeof(wol->sopass));
6893}
6894
6895static int
6896bnx2_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
6897{
Michael Chan972ec0d2006-01-23 16:12:43 -08006898 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006899
6900 if (wol->wolopts & ~WAKE_MAGIC)
6901 return -EINVAL;
6902
6903 if (wol->wolopts & WAKE_MAGIC) {
David S. Millerf86e82f2008-01-21 17:15:40 -08006904 if (bp->flags & BNX2_FLAG_NO_WOL)
Michael Chanb6016b72005-05-26 13:03:09 -07006905 return -EINVAL;
6906
6907 bp->wol = 1;
6908 }
6909 else {
6910 bp->wol = 0;
6911 }
6912 return 0;
6913}
6914
6915static int
6916bnx2_nway_reset(struct net_device *dev)
6917{
Michael Chan972ec0d2006-01-23 16:12:43 -08006918 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006919 u32 bmcr;
6920
Michael Chan9f52b562008-10-09 12:21:46 -07006921 if (!netif_running(dev))
6922 return -EAGAIN;
6923
Michael Chanb6016b72005-05-26 13:03:09 -07006924 if (!(bp->autoneg & AUTONEG_SPEED)) {
6925 return -EINVAL;
6926 }
6927
Michael Chanc770a652005-08-25 15:38:39 -07006928 spin_lock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07006929
Michael Chan583c28e2008-01-21 19:51:35 -08006930 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP) {
Michael Chan7b6b8342007-07-07 22:50:15 -07006931 int rc;
6932
6933 rc = bnx2_setup_remote_phy(bp, bp->phy_port);
6934 spin_unlock_bh(&bp->phy_lock);
6935 return rc;
6936 }
6937
Michael Chanb6016b72005-05-26 13:03:09 -07006938 /* Force a link down visible on the other side */
Michael Chan583c28e2008-01-21 19:51:35 -08006939 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Michael Chanca58c3a2007-05-03 13:22:52 -07006940 bnx2_write_phy(bp, bp->mii_bmcr, BMCR_LOOPBACK);
Michael Chanc770a652005-08-25 15:38:39 -07006941 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07006942
6943 msleep(20);
6944
Michael Chanc770a652005-08-25 15:38:39 -07006945 spin_lock_bh(&bp->phy_lock);
Michael Chanf8dd0642006-11-19 14:08:29 -08006946
Michael Chan40105c02008-11-12 16:02:45 -08006947 bp->current_interval = BNX2_SERDES_AN_TIMEOUT;
Michael Chanf8dd0642006-11-19 14:08:29 -08006948 bp->serdes_an_pending = 1;
6949 mod_timer(&bp->timer, jiffies + bp->current_interval);
Michael Chanb6016b72005-05-26 13:03:09 -07006950 }
6951
Michael Chanca58c3a2007-05-03 13:22:52 -07006952 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chanb6016b72005-05-26 13:03:09 -07006953 bmcr &= ~BMCR_LOOPBACK;
Michael Chanca58c3a2007-05-03 13:22:52 -07006954 bnx2_write_phy(bp, bp->mii_bmcr, bmcr | BMCR_ANRESTART | BMCR_ANENABLE);
Michael Chanb6016b72005-05-26 13:03:09 -07006955
Michael Chanc770a652005-08-25 15:38:39 -07006956 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07006957
6958 return 0;
6959}
6960
Ooiwa Naohiro7959ea22009-06-24 00:19:06 -07006961static u32
6962bnx2_get_link(struct net_device *dev)
6963{
6964 struct bnx2 *bp = netdev_priv(dev);
6965
6966 return bp->link_up;
6967}
6968
Michael Chanb6016b72005-05-26 13:03:09 -07006969static int
6970bnx2_get_eeprom_len(struct net_device *dev)
6971{
Michael Chan972ec0d2006-01-23 16:12:43 -08006972 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006973
Michael Chan1122db72006-01-23 16:11:42 -08006974 if (bp->flash_info == NULL)
Michael Chanb6016b72005-05-26 13:03:09 -07006975 return 0;
6976
Michael Chan1122db72006-01-23 16:11:42 -08006977 return (int) bp->flash_size;
Michael Chanb6016b72005-05-26 13:03:09 -07006978}
6979
6980static int
6981bnx2_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
6982 u8 *eebuf)
6983{
Michael Chan972ec0d2006-01-23 16:12:43 -08006984 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006985 int rc;
6986
Michael Chan9f52b562008-10-09 12:21:46 -07006987 if (!netif_running(dev))
6988 return -EAGAIN;
6989
John W. Linville1064e942005-11-10 12:58:24 -08006990 /* parameters already validated in ethtool_get_eeprom */
Michael Chanb6016b72005-05-26 13:03:09 -07006991
6992 rc = bnx2_nvram_read(bp, eeprom->offset, eebuf, eeprom->len);
6993
6994 return rc;
6995}
6996
6997static int
6998bnx2_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
6999 u8 *eebuf)
7000{
Michael Chan972ec0d2006-01-23 16:12:43 -08007001 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007002 int rc;
7003
Michael Chan9f52b562008-10-09 12:21:46 -07007004 if (!netif_running(dev))
7005 return -EAGAIN;
7006
John W. Linville1064e942005-11-10 12:58:24 -08007007 /* parameters already validated in ethtool_set_eeprom */
Michael Chanb6016b72005-05-26 13:03:09 -07007008
7009 rc = bnx2_nvram_write(bp, eeprom->offset, eebuf, eeprom->len);
7010
7011 return rc;
7012}
7013
7014static int
7015bnx2_get_coalesce(struct net_device *dev, struct ethtool_coalesce *coal)
7016{
Michael Chan972ec0d2006-01-23 16:12:43 -08007017 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007018
7019 memset(coal, 0, sizeof(struct ethtool_coalesce));
7020
7021 coal->rx_coalesce_usecs = bp->rx_ticks;
7022 coal->rx_max_coalesced_frames = bp->rx_quick_cons_trip;
7023 coal->rx_coalesce_usecs_irq = bp->rx_ticks_int;
7024 coal->rx_max_coalesced_frames_irq = bp->rx_quick_cons_trip_int;
7025
7026 coal->tx_coalesce_usecs = bp->tx_ticks;
7027 coal->tx_max_coalesced_frames = bp->tx_quick_cons_trip;
7028 coal->tx_coalesce_usecs_irq = bp->tx_ticks_int;
7029 coal->tx_max_coalesced_frames_irq = bp->tx_quick_cons_trip_int;
7030
7031 coal->stats_block_coalesce_usecs = bp->stats_ticks;
7032
7033 return 0;
7034}
7035
7036static int
7037bnx2_set_coalesce(struct net_device *dev, struct ethtool_coalesce *coal)
7038{
Michael Chan972ec0d2006-01-23 16:12:43 -08007039 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007040
7041 bp->rx_ticks = (u16) coal->rx_coalesce_usecs;
7042 if (bp->rx_ticks > 0x3ff) bp->rx_ticks = 0x3ff;
7043
Jeff Garzik6aa20a22006-09-13 13:24:59 -04007044 bp->rx_quick_cons_trip = (u16) coal->rx_max_coalesced_frames;
Michael Chanb6016b72005-05-26 13:03:09 -07007045 if (bp->rx_quick_cons_trip > 0xff) bp->rx_quick_cons_trip = 0xff;
7046
7047 bp->rx_ticks_int = (u16) coal->rx_coalesce_usecs_irq;
7048 if (bp->rx_ticks_int > 0x3ff) bp->rx_ticks_int = 0x3ff;
7049
7050 bp->rx_quick_cons_trip_int = (u16) coal->rx_max_coalesced_frames_irq;
7051 if (bp->rx_quick_cons_trip_int > 0xff)
7052 bp->rx_quick_cons_trip_int = 0xff;
7053
7054 bp->tx_ticks = (u16) coal->tx_coalesce_usecs;
7055 if (bp->tx_ticks > 0x3ff) bp->tx_ticks = 0x3ff;
7056
7057 bp->tx_quick_cons_trip = (u16) coal->tx_max_coalesced_frames;
7058 if (bp->tx_quick_cons_trip > 0xff) bp->tx_quick_cons_trip = 0xff;
7059
7060 bp->tx_ticks_int = (u16) coal->tx_coalesce_usecs_irq;
7061 if (bp->tx_ticks_int > 0x3ff) bp->tx_ticks_int = 0x3ff;
7062
7063 bp->tx_quick_cons_trip_int = (u16) coal->tx_max_coalesced_frames_irq;
7064 if (bp->tx_quick_cons_trip_int > 0xff) bp->tx_quick_cons_trip_int =
7065 0xff;
7066
7067 bp->stats_ticks = coal->stats_block_coalesce_usecs;
Michael Chan61d9e3f2009-08-21 16:20:46 +00007068 if (bp->flags & BNX2_FLAG_BROKEN_STATS) {
Michael Chan02537b062007-06-04 21:24:07 -07007069 if (bp->stats_ticks != 0 && bp->stats_ticks != USEC_PER_SEC)
7070 bp->stats_ticks = USEC_PER_SEC;
7071 }
Michael Chan7ea69202007-07-16 18:27:10 -07007072 if (bp->stats_ticks > BNX2_HC_STATS_TICKS_HC_STAT_TICKS)
7073 bp->stats_ticks = BNX2_HC_STATS_TICKS_HC_STAT_TICKS;
7074 bp->stats_ticks &= BNX2_HC_STATS_TICKS_HC_STAT_TICKS;
Michael Chanb6016b72005-05-26 13:03:09 -07007075
7076 if (netif_running(bp->dev)) {
Michael Chan212f9932010-04-27 11:28:10 +00007077 bnx2_netif_stop(bp, true);
Michael Chan9a120bc2008-05-16 22:17:45 -07007078 bnx2_init_nic(bp, 0);
Michael Chan212f9932010-04-27 11:28:10 +00007079 bnx2_netif_start(bp, true);
Michael Chanb6016b72005-05-26 13:03:09 -07007080 }
7081
7082 return 0;
7083}
7084
7085static void
7086bnx2_get_ringparam(struct net_device *dev, struct ethtool_ringparam *ering)
7087{
Michael Chan972ec0d2006-01-23 16:12:43 -08007088 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007089
Michael Chan13daffa2006-03-20 17:49:20 -08007090 ering->rx_max_pending = MAX_TOTAL_RX_DESC_CNT;
Michael Chanb6016b72005-05-26 13:03:09 -07007091 ering->rx_mini_max_pending = 0;
Michael Chan47bf4242007-12-12 11:19:12 -08007092 ering->rx_jumbo_max_pending = MAX_TOTAL_RX_PG_DESC_CNT;
Michael Chanb6016b72005-05-26 13:03:09 -07007093
7094 ering->rx_pending = bp->rx_ring_size;
7095 ering->rx_mini_pending = 0;
Michael Chan47bf4242007-12-12 11:19:12 -08007096 ering->rx_jumbo_pending = bp->rx_pg_ring_size;
Michael Chanb6016b72005-05-26 13:03:09 -07007097
7098 ering->tx_max_pending = MAX_TX_DESC_CNT;
7099 ering->tx_pending = bp->tx_ring_size;
7100}
7101
7102static int
Michael Chan5d5d0012007-12-12 11:17:43 -08007103bnx2_change_ring_size(struct bnx2 *bp, u32 rx, u32 tx)
Michael Chanb6016b72005-05-26 13:03:09 -07007104{
Michael Chan13daffa2006-03-20 17:49:20 -08007105 if (netif_running(bp->dev)) {
Michael Chan354fcd72010-01-17 07:30:44 +00007106 /* Reset will erase chipset stats; save them */
7107 bnx2_save_stats(bp);
7108
Michael Chan212f9932010-04-27 11:28:10 +00007109 bnx2_netif_stop(bp, true);
Michael Chan13daffa2006-03-20 17:49:20 -08007110 bnx2_reset_chip(bp, BNX2_DRV_MSG_CODE_RESET);
7111 bnx2_free_skbs(bp);
7112 bnx2_free_mem(bp);
7113 }
7114
Michael Chan5d5d0012007-12-12 11:17:43 -08007115 bnx2_set_rx_ring_size(bp, rx);
7116 bp->tx_ring_size = tx;
Michael Chanb6016b72005-05-26 13:03:09 -07007117
7118 if (netif_running(bp->dev)) {
Michael Chan13daffa2006-03-20 17:49:20 -08007119 int rc;
7120
7121 rc = bnx2_alloc_mem(bp);
Michael Chan6fefb652009-08-21 16:20:45 +00007122 if (!rc)
7123 rc = bnx2_init_nic(bp, 0);
7124
7125 if (rc) {
7126 bnx2_napi_enable(bp);
7127 dev_close(bp->dev);
Michael Chan13daffa2006-03-20 17:49:20 -08007128 return rc;
Michael Chan6fefb652009-08-21 16:20:45 +00007129 }
Michael Chane9f26c42010-02-15 19:42:08 +00007130#ifdef BCM_CNIC
7131 mutex_lock(&bp->cnic_lock);
7132 /* Let cnic know about the new status block. */
7133 if (bp->cnic_eth_dev.drv_state & CNIC_DRV_STATE_REGD)
7134 bnx2_setup_cnic_irq_info(bp);
7135 mutex_unlock(&bp->cnic_lock);
7136#endif
Michael Chan212f9932010-04-27 11:28:10 +00007137 bnx2_netif_start(bp, true);
Michael Chanb6016b72005-05-26 13:03:09 -07007138 }
Michael Chanb6016b72005-05-26 13:03:09 -07007139 return 0;
7140}
7141
Michael Chan5d5d0012007-12-12 11:17:43 -08007142static int
7143bnx2_set_ringparam(struct net_device *dev, struct ethtool_ringparam *ering)
7144{
7145 struct bnx2 *bp = netdev_priv(dev);
7146 int rc;
7147
7148 if ((ering->rx_pending > MAX_TOTAL_RX_DESC_CNT) ||
7149 (ering->tx_pending > MAX_TX_DESC_CNT) ||
7150 (ering->tx_pending <= MAX_SKB_FRAGS)) {
7151
7152 return -EINVAL;
7153 }
7154 rc = bnx2_change_ring_size(bp, ering->rx_pending, ering->tx_pending);
7155 return rc;
7156}
7157
Michael Chanb6016b72005-05-26 13:03:09 -07007158static void
7159bnx2_get_pauseparam(struct net_device *dev, struct ethtool_pauseparam *epause)
7160{
Michael Chan972ec0d2006-01-23 16:12:43 -08007161 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007162
7163 epause->autoneg = ((bp->autoneg & AUTONEG_FLOW_CTRL) != 0);
7164 epause->rx_pause = ((bp->flow_ctrl & FLOW_CTRL_RX) != 0);
7165 epause->tx_pause = ((bp->flow_ctrl & FLOW_CTRL_TX) != 0);
7166}
7167
7168static int
7169bnx2_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam *epause)
7170{
Michael Chan972ec0d2006-01-23 16:12:43 -08007171 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007172
7173 bp->req_flow_ctrl = 0;
7174 if (epause->rx_pause)
7175 bp->req_flow_ctrl |= FLOW_CTRL_RX;
7176 if (epause->tx_pause)
7177 bp->req_flow_ctrl |= FLOW_CTRL_TX;
7178
7179 if (epause->autoneg) {
7180 bp->autoneg |= AUTONEG_FLOW_CTRL;
7181 }
7182 else {
7183 bp->autoneg &= ~AUTONEG_FLOW_CTRL;
7184 }
7185
Michael Chan9f52b562008-10-09 12:21:46 -07007186 if (netif_running(dev)) {
7187 spin_lock_bh(&bp->phy_lock);
7188 bnx2_setup_phy(bp, bp->phy_port);
7189 spin_unlock_bh(&bp->phy_lock);
7190 }
Michael Chanb6016b72005-05-26 13:03:09 -07007191
7192 return 0;
7193}
7194
7195static u32
7196bnx2_get_rx_csum(struct net_device *dev)
7197{
Michael Chan972ec0d2006-01-23 16:12:43 -08007198 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007199
7200 return bp->rx_csum;
7201}
7202
7203static int
7204bnx2_set_rx_csum(struct net_device *dev, u32 data)
7205{
Michael Chan972ec0d2006-01-23 16:12:43 -08007206 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007207
7208 bp->rx_csum = data;
7209 return 0;
7210}
7211
Michael Chanb11d6212006-06-29 12:31:21 -07007212static int
7213bnx2_set_tso(struct net_device *dev, u32 data)
7214{
Michael Chan4666f872007-05-03 13:22:28 -07007215 struct bnx2 *bp = netdev_priv(dev);
7216
7217 if (data) {
Michael Chanb11d6212006-06-29 12:31:21 -07007218 dev->features |= NETIF_F_TSO | NETIF_F_TSO_ECN;
Michael Chan4666f872007-05-03 13:22:28 -07007219 if (CHIP_NUM(bp) == CHIP_NUM_5709)
7220 dev->features |= NETIF_F_TSO6;
7221 } else
7222 dev->features &= ~(NETIF_F_TSO | NETIF_F_TSO6 |
7223 NETIF_F_TSO_ECN);
Michael Chanb11d6212006-06-29 12:31:21 -07007224 return 0;
7225}
7226
Peter Hagervall14ab9b82005-08-10 14:18:16 -07007227static struct {
Michael Chanb6016b72005-05-26 13:03:09 -07007228 char string[ETH_GSTRING_LEN];
Michael Chan790dab22009-08-21 16:20:47 +00007229} bnx2_stats_str_arr[] = {
Michael Chanb6016b72005-05-26 13:03:09 -07007230 { "rx_bytes" },
7231 { "rx_error_bytes" },
7232 { "tx_bytes" },
7233 { "tx_error_bytes" },
7234 { "rx_ucast_packets" },
7235 { "rx_mcast_packets" },
7236 { "rx_bcast_packets" },
7237 { "tx_ucast_packets" },
7238 { "tx_mcast_packets" },
7239 { "tx_bcast_packets" },
7240 { "tx_mac_errors" },
7241 { "tx_carrier_errors" },
7242 { "rx_crc_errors" },
7243 { "rx_align_errors" },
7244 { "tx_single_collisions" },
7245 { "tx_multi_collisions" },
7246 { "tx_deferred" },
7247 { "tx_excess_collisions" },
7248 { "tx_late_collisions" },
7249 { "tx_total_collisions" },
7250 { "rx_fragments" },
7251 { "rx_jabbers" },
7252 { "rx_undersize_packets" },
7253 { "rx_oversize_packets" },
7254 { "rx_64_byte_packets" },
7255 { "rx_65_to_127_byte_packets" },
7256 { "rx_128_to_255_byte_packets" },
7257 { "rx_256_to_511_byte_packets" },
7258 { "rx_512_to_1023_byte_packets" },
7259 { "rx_1024_to_1522_byte_packets" },
7260 { "rx_1523_to_9022_byte_packets" },
7261 { "tx_64_byte_packets" },
7262 { "tx_65_to_127_byte_packets" },
7263 { "tx_128_to_255_byte_packets" },
7264 { "tx_256_to_511_byte_packets" },
7265 { "tx_512_to_1023_byte_packets" },
7266 { "tx_1024_to_1522_byte_packets" },
7267 { "tx_1523_to_9022_byte_packets" },
7268 { "rx_xon_frames" },
7269 { "rx_xoff_frames" },
7270 { "tx_xon_frames" },
7271 { "tx_xoff_frames" },
7272 { "rx_mac_ctrl_frames" },
7273 { "rx_filtered_packets" },
Michael Chan790dab22009-08-21 16:20:47 +00007274 { "rx_ftq_discards" },
Michael Chanb6016b72005-05-26 13:03:09 -07007275 { "rx_discards" },
Michael Chancea94db2006-06-12 22:16:13 -07007276 { "rx_fw_discards" },
Michael Chanb6016b72005-05-26 13:03:09 -07007277};
7278
Michael Chan790dab22009-08-21 16:20:47 +00007279#define BNX2_NUM_STATS (sizeof(bnx2_stats_str_arr)/\
7280 sizeof(bnx2_stats_str_arr[0]))
7281
Michael Chanb6016b72005-05-26 13:03:09 -07007282#define STATS_OFFSET32(offset_name) (offsetof(struct statistics_block, offset_name) / 4)
7283
Arjan van de Venf71e1302006-03-03 21:33:57 -05007284static const unsigned long bnx2_stats_offset_arr[BNX2_NUM_STATS] = {
Michael Chanb6016b72005-05-26 13:03:09 -07007285 STATS_OFFSET32(stat_IfHCInOctets_hi),
7286 STATS_OFFSET32(stat_IfHCInBadOctets_hi),
7287 STATS_OFFSET32(stat_IfHCOutOctets_hi),
7288 STATS_OFFSET32(stat_IfHCOutBadOctets_hi),
7289 STATS_OFFSET32(stat_IfHCInUcastPkts_hi),
7290 STATS_OFFSET32(stat_IfHCInMulticastPkts_hi),
7291 STATS_OFFSET32(stat_IfHCInBroadcastPkts_hi),
7292 STATS_OFFSET32(stat_IfHCOutUcastPkts_hi),
7293 STATS_OFFSET32(stat_IfHCOutMulticastPkts_hi),
7294 STATS_OFFSET32(stat_IfHCOutBroadcastPkts_hi),
7295 STATS_OFFSET32(stat_emac_tx_stat_dot3statsinternalmactransmiterrors),
Jeff Garzik6aa20a22006-09-13 13:24:59 -04007296 STATS_OFFSET32(stat_Dot3StatsCarrierSenseErrors),
7297 STATS_OFFSET32(stat_Dot3StatsFCSErrors),
7298 STATS_OFFSET32(stat_Dot3StatsAlignmentErrors),
7299 STATS_OFFSET32(stat_Dot3StatsSingleCollisionFrames),
7300 STATS_OFFSET32(stat_Dot3StatsMultipleCollisionFrames),
7301 STATS_OFFSET32(stat_Dot3StatsDeferredTransmissions),
7302 STATS_OFFSET32(stat_Dot3StatsExcessiveCollisions),
7303 STATS_OFFSET32(stat_Dot3StatsLateCollisions),
7304 STATS_OFFSET32(stat_EtherStatsCollisions),
7305 STATS_OFFSET32(stat_EtherStatsFragments),
7306 STATS_OFFSET32(stat_EtherStatsJabbers),
7307 STATS_OFFSET32(stat_EtherStatsUndersizePkts),
7308 STATS_OFFSET32(stat_EtherStatsOverrsizePkts),
7309 STATS_OFFSET32(stat_EtherStatsPktsRx64Octets),
7310 STATS_OFFSET32(stat_EtherStatsPktsRx65Octetsto127Octets),
7311 STATS_OFFSET32(stat_EtherStatsPktsRx128Octetsto255Octets),
7312 STATS_OFFSET32(stat_EtherStatsPktsRx256Octetsto511Octets),
7313 STATS_OFFSET32(stat_EtherStatsPktsRx512Octetsto1023Octets),
7314 STATS_OFFSET32(stat_EtherStatsPktsRx1024Octetsto1522Octets),
7315 STATS_OFFSET32(stat_EtherStatsPktsRx1523Octetsto9022Octets),
7316 STATS_OFFSET32(stat_EtherStatsPktsTx64Octets),
7317 STATS_OFFSET32(stat_EtherStatsPktsTx65Octetsto127Octets),
7318 STATS_OFFSET32(stat_EtherStatsPktsTx128Octetsto255Octets),
7319 STATS_OFFSET32(stat_EtherStatsPktsTx256Octetsto511Octets),
7320 STATS_OFFSET32(stat_EtherStatsPktsTx512Octetsto1023Octets),
7321 STATS_OFFSET32(stat_EtherStatsPktsTx1024Octetsto1522Octets),
7322 STATS_OFFSET32(stat_EtherStatsPktsTx1523Octetsto9022Octets),
7323 STATS_OFFSET32(stat_XonPauseFramesReceived),
7324 STATS_OFFSET32(stat_XoffPauseFramesReceived),
7325 STATS_OFFSET32(stat_OutXonSent),
7326 STATS_OFFSET32(stat_OutXoffSent),
7327 STATS_OFFSET32(stat_MacControlFramesReceived),
7328 STATS_OFFSET32(stat_IfInFramesL2FilterDiscards),
Michael Chan790dab22009-08-21 16:20:47 +00007329 STATS_OFFSET32(stat_IfInFTQDiscards),
Jeff Garzik6aa20a22006-09-13 13:24:59 -04007330 STATS_OFFSET32(stat_IfInMBUFDiscards),
Michael Chancea94db2006-06-12 22:16:13 -07007331 STATS_OFFSET32(stat_FwRxDrop),
Michael Chanb6016b72005-05-26 13:03:09 -07007332};
7333
7334/* stat_IfHCInBadOctets and stat_Dot3StatsCarrierSenseErrors are
7335 * skipped because of errata.
Jeff Garzik6aa20a22006-09-13 13:24:59 -04007336 */
Peter Hagervall14ab9b82005-08-10 14:18:16 -07007337static u8 bnx2_5706_stats_len_arr[BNX2_NUM_STATS] = {
Michael Chanb6016b72005-05-26 13:03:09 -07007338 8,0,8,8,8,8,8,8,8,8,
7339 4,0,4,4,4,4,4,4,4,4,
7340 4,4,4,4,4,4,4,4,4,4,
7341 4,4,4,4,4,4,4,4,4,4,
Michael Chan790dab22009-08-21 16:20:47 +00007342 4,4,4,4,4,4,4,
Michael Chanb6016b72005-05-26 13:03:09 -07007343};
7344
Michael Chan5b0c76a2005-11-04 08:45:49 -08007345static u8 bnx2_5708_stats_len_arr[BNX2_NUM_STATS] = {
7346 8,0,8,8,8,8,8,8,8,8,
7347 4,4,4,4,4,4,4,4,4,4,
7348 4,4,4,4,4,4,4,4,4,4,
7349 4,4,4,4,4,4,4,4,4,4,
Michael Chan790dab22009-08-21 16:20:47 +00007350 4,4,4,4,4,4,4,
Michael Chan5b0c76a2005-11-04 08:45:49 -08007351};
7352
Michael Chanb6016b72005-05-26 13:03:09 -07007353#define BNX2_NUM_TESTS 6
7354
Peter Hagervall14ab9b82005-08-10 14:18:16 -07007355static struct {
Michael Chanb6016b72005-05-26 13:03:09 -07007356 char string[ETH_GSTRING_LEN];
7357} bnx2_tests_str_arr[BNX2_NUM_TESTS] = {
7358 { "register_test (offline)" },
7359 { "memory_test (offline)" },
7360 { "loopback_test (offline)" },
7361 { "nvram_test (online)" },
7362 { "interrupt_test (online)" },
7363 { "link_test (online)" },
7364};
7365
7366static int
Jeff Garzikb9f2c042007-10-03 18:07:32 -07007367bnx2_get_sset_count(struct net_device *dev, int sset)
Michael Chanb6016b72005-05-26 13:03:09 -07007368{
Jeff Garzikb9f2c042007-10-03 18:07:32 -07007369 switch (sset) {
7370 case ETH_SS_TEST:
7371 return BNX2_NUM_TESTS;
7372 case ETH_SS_STATS:
7373 return BNX2_NUM_STATS;
7374 default:
7375 return -EOPNOTSUPP;
7376 }
Michael Chanb6016b72005-05-26 13:03:09 -07007377}
7378
7379static void
7380bnx2_self_test(struct net_device *dev, struct ethtool_test *etest, u64 *buf)
7381{
Michael Chan972ec0d2006-01-23 16:12:43 -08007382 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007383
Michael Chan9f52b562008-10-09 12:21:46 -07007384 bnx2_set_power_state(bp, PCI_D0);
7385
Michael Chanb6016b72005-05-26 13:03:09 -07007386 memset(buf, 0, sizeof(u64) * BNX2_NUM_TESTS);
7387 if (etest->flags & ETH_TEST_FL_OFFLINE) {
Michael Chan80be4432006-11-19 14:07:28 -08007388 int i;
7389
Michael Chan212f9932010-04-27 11:28:10 +00007390 bnx2_netif_stop(bp, true);
Michael Chanb6016b72005-05-26 13:03:09 -07007391 bnx2_reset_chip(bp, BNX2_DRV_MSG_CODE_DIAG);
7392 bnx2_free_skbs(bp);
7393
7394 if (bnx2_test_registers(bp) != 0) {
7395 buf[0] = 1;
7396 etest->flags |= ETH_TEST_FL_FAILED;
7397 }
7398 if (bnx2_test_memory(bp) != 0) {
7399 buf[1] = 1;
7400 etest->flags |= ETH_TEST_FL_FAILED;
7401 }
Michael Chanbc5a0692006-01-23 16:13:22 -08007402 if ((buf[2] = bnx2_test_loopback(bp)) != 0)
Michael Chanb6016b72005-05-26 13:03:09 -07007403 etest->flags |= ETH_TEST_FL_FAILED;
Michael Chanb6016b72005-05-26 13:03:09 -07007404
Michael Chan9f52b562008-10-09 12:21:46 -07007405 if (!netif_running(bp->dev))
7406 bnx2_shutdown_chip(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07007407 else {
Michael Chan9a120bc2008-05-16 22:17:45 -07007408 bnx2_init_nic(bp, 1);
Michael Chan212f9932010-04-27 11:28:10 +00007409 bnx2_netif_start(bp, true);
Michael Chanb6016b72005-05-26 13:03:09 -07007410 }
7411
7412 /* wait for link up */
Michael Chan80be4432006-11-19 14:07:28 -08007413 for (i = 0; i < 7; i++) {
7414 if (bp->link_up)
7415 break;
7416 msleep_interruptible(1000);
7417 }
Michael Chanb6016b72005-05-26 13:03:09 -07007418 }
7419
7420 if (bnx2_test_nvram(bp) != 0) {
7421 buf[3] = 1;
7422 etest->flags |= ETH_TEST_FL_FAILED;
7423 }
7424 if (bnx2_test_intr(bp) != 0) {
7425 buf[4] = 1;
7426 etest->flags |= ETH_TEST_FL_FAILED;
7427 }
7428
7429 if (bnx2_test_link(bp) != 0) {
7430 buf[5] = 1;
7431 etest->flags |= ETH_TEST_FL_FAILED;
7432
7433 }
Michael Chan9f52b562008-10-09 12:21:46 -07007434 if (!netif_running(bp->dev))
7435 bnx2_set_power_state(bp, PCI_D3hot);
Michael Chanb6016b72005-05-26 13:03:09 -07007436}
7437
7438static void
7439bnx2_get_strings(struct net_device *dev, u32 stringset, u8 *buf)
7440{
7441 switch (stringset) {
7442 case ETH_SS_STATS:
7443 memcpy(buf, bnx2_stats_str_arr,
7444 sizeof(bnx2_stats_str_arr));
7445 break;
7446 case ETH_SS_TEST:
7447 memcpy(buf, bnx2_tests_str_arr,
7448 sizeof(bnx2_tests_str_arr));
7449 break;
7450 }
7451}
7452
Michael Chanb6016b72005-05-26 13:03:09 -07007453static void
7454bnx2_get_ethtool_stats(struct net_device *dev,
7455 struct ethtool_stats *stats, u64 *buf)
7456{
Michael Chan972ec0d2006-01-23 16:12:43 -08007457 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007458 int i;
7459 u32 *hw_stats = (u32 *) bp->stats_blk;
Michael Chan354fcd72010-01-17 07:30:44 +00007460 u32 *temp_stats = (u32 *) bp->temp_stats_blk;
Peter Hagervall14ab9b82005-08-10 14:18:16 -07007461 u8 *stats_len_arr = NULL;
Michael Chanb6016b72005-05-26 13:03:09 -07007462
7463 if (hw_stats == NULL) {
7464 memset(buf, 0, sizeof(u64) * BNX2_NUM_STATS);
7465 return;
7466 }
7467
Michael Chan5b0c76a2005-11-04 08:45:49 -08007468 if ((CHIP_ID(bp) == CHIP_ID_5706_A0) ||
7469 (CHIP_ID(bp) == CHIP_ID_5706_A1) ||
7470 (CHIP_ID(bp) == CHIP_ID_5706_A2) ||
7471 (CHIP_ID(bp) == CHIP_ID_5708_A0))
Michael Chanb6016b72005-05-26 13:03:09 -07007472 stats_len_arr = bnx2_5706_stats_len_arr;
Michael Chan5b0c76a2005-11-04 08:45:49 -08007473 else
7474 stats_len_arr = bnx2_5708_stats_len_arr;
Michael Chanb6016b72005-05-26 13:03:09 -07007475
7476 for (i = 0; i < BNX2_NUM_STATS; i++) {
Michael Chan354fcd72010-01-17 07:30:44 +00007477 unsigned long offset;
7478
Michael Chanb6016b72005-05-26 13:03:09 -07007479 if (stats_len_arr[i] == 0) {
7480 /* skip this counter */
7481 buf[i] = 0;
7482 continue;
7483 }
Michael Chan354fcd72010-01-17 07:30:44 +00007484
7485 offset = bnx2_stats_offset_arr[i];
Michael Chanb6016b72005-05-26 13:03:09 -07007486 if (stats_len_arr[i] == 4) {
7487 /* 4-byte counter */
Michael Chan354fcd72010-01-17 07:30:44 +00007488 buf[i] = (u64) *(hw_stats + offset) +
7489 *(temp_stats + offset);
Michael Chanb6016b72005-05-26 13:03:09 -07007490 continue;
7491 }
7492 /* 8-byte counter */
Michael Chan354fcd72010-01-17 07:30:44 +00007493 buf[i] = (((u64) *(hw_stats + offset)) << 32) +
7494 *(hw_stats + offset + 1) +
7495 (((u64) *(temp_stats + offset)) << 32) +
7496 *(temp_stats + offset + 1);
Michael Chanb6016b72005-05-26 13:03:09 -07007497 }
7498}
7499
7500static int
7501bnx2_phys_id(struct net_device *dev, u32 data)
7502{
Michael Chan972ec0d2006-01-23 16:12:43 -08007503 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007504 int i;
7505 u32 save;
7506
Michael Chan9f52b562008-10-09 12:21:46 -07007507 bnx2_set_power_state(bp, PCI_D0);
7508
Michael Chanb6016b72005-05-26 13:03:09 -07007509 if (data == 0)
7510 data = 2;
7511
7512 save = REG_RD(bp, BNX2_MISC_CFG);
7513 REG_WR(bp, BNX2_MISC_CFG, BNX2_MISC_CFG_LEDMODE_MAC);
7514
7515 for (i = 0; i < (data * 2); i++) {
7516 if ((i % 2) == 0) {
7517 REG_WR(bp, BNX2_EMAC_LED, BNX2_EMAC_LED_OVERRIDE);
7518 }
7519 else {
7520 REG_WR(bp, BNX2_EMAC_LED, BNX2_EMAC_LED_OVERRIDE |
7521 BNX2_EMAC_LED_1000MB_OVERRIDE |
7522 BNX2_EMAC_LED_100MB_OVERRIDE |
7523 BNX2_EMAC_LED_10MB_OVERRIDE |
7524 BNX2_EMAC_LED_TRAFFIC_OVERRIDE |
7525 BNX2_EMAC_LED_TRAFFIC);
7526 }
7527 msleep_interruptible(500);
7528 if (signal_pending(current))
7529 break;
7530 }
7531 REG_WR(bp, BNX2_EMAC_LED, 0);
7532 REG_WR(bp, BNX2_MISC_CFG, save);
Michael Chan9f52b562008-10-09 12:21:46 -07007533
7534 if (!netif_running(dev))
7535 bnx2_set_power_state(bp, PCI_D3hot);
7536
Michael Chanb6016b72005-05-26 13:03:09 -07007537 return 0;
7538}
7539
Michael Chan4666f872007-05-03 13:22:28 -07007540static int
7541bnx2_set_tx_csum(struct net_device *dev, u32 data)
7542{
7543 struct bnx2 *bp = netdev_priv(dev);
7544
7545 if (CHIP_NUM(bp) == CHIP_NUM_5709)
Michael Chan6460d942007-07-14 19:07:52 -07007546 return (ethtool_op_set_tx_ipv6_csum(dev, data));
Michael Chan4666f872007-05-03 13:22:28 -07007547 else
7548 return (ethtool_op_set_tx_csum(dev, data));
7549}
7550
Jeff Garzik7282d492006-09-13 14:30:00 -04007551static const struct ethtool_ops bnx2_ethtool_ops = {
Michael Chanb6016b72005-05-26 13:03:09 -07007552 .get_settings = bnx2_get_settings,
7553 .set_settings = bnx2_set_settings,
7554 .get_drvinfo = bnx2_get_drvinfo,
Michael Chan244ac4f2006-03-20 17:48:46 -08007555 .get_regs_len = bnx2_get_regs_len,
7556 .get_regs = bnx2_get_regs,
Michael Chanb6016b72005-05-26 13:03:09 -07007557 .get_wol = bnx2_get_wol,
7558 .set_wol = bnx2_set_wol,
7559 .nway_reset = bnx2_nway_reset,
Ooiwa Naohiro7959ea22009-06-24 00:19:06 -07007560 .get_link = bnx2_get_link,
Michael Chanb6016b72005-05-26 13:03:09 -07007561 .get_eeprom_len = bnx2_get_eeprom_len,
7562 .get_eeprom = bnx2_get_eeprom,
7563 .set_eeprom = bnx2_set_eeprom,
7564 .get_coalesce = bnx2_get_coalesce,
7565 .set_coalesce = bnx2_set_coalesce,
7566 .get_ringparam = bnx2_get_ringparam,
7567 .set_ringparam = bnx2_set_ringparam,
7568 .get_pauseparam = bnx2_get_pauseparam,
7569 .set_pauseparam = bnx2_set_pauseparam,
7570 .get_rx_csum = bnx2_get_rx_csum,
7571 .set_rx_csum = bnx2_set_rx_csum,
Michael Chan4666f872007-05-03 13:22:28 -07007572 .set_tx_csum = bnx2_set_tx_csum,
Michael Chanb6016b72005-05-26 13:03:09 -07007573 .set_sg = ethtool_op_set_sg,
Michael Chanb11d6212006-06-29 12:31:21 -07007574 .set_tso = bnx2_set_tso,
Michael Chanb6016b72005-05-26 13:03:09 -07007575 .self_test = bnx2_self_test,
7576 .get_strings = bnx2_get_strings,
7577 .phys_id = bnx2_phys_id,
Michael Chanb6016b72005-05-26 13:03:09 -07007578 .get_ethtool_stats = bnx2_get_ethtool_stats,
Jeff Garzikb9f2c042007-10-03 18:07:32 -07007579 .get_sset_count = bnx2_get_sset_count,
Michael Chanb6016b72005-05-26 13:03:09 -07007580};
7581
7582/* Called with rtnl_lock */
7583static int
7584bnx2_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
7585{
Peter Hagervall14ab9b82005-08-10 14:18:16 -07007586 struct mii_ioctl_data *data = if_mii(ifr);
Michael Chan972ec0d2006-01-23 16:12:43 -08007587 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007588 int err;
7589
7590 switch(cmd) {
7591 case SIOCGMIIPHY:
7592 data->phy_id = bp->phy_addr;
7593
7594 /* fallthru */
7595 case SIOCGMIIREG: {
7596 u32 mii_regval;
7597
Michael Chan583c28e2008-01-21 19:51:35 -08007598 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
Michael Chan7b6b8342007-07-07 22:50:15 -07007599 return -EOPNOTSUPP;
7600
Michael Chandad3e452007-05-03 13:18:03 -07007601 if (!netif_running(dev))
7602 return -EAGAIN;
7603
Michael Chanc770a652005-08-25 15:38:39 -07007604 spin_lock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07007605 err = bnx2_read_phy(bp, data->reg_num & 0x1f, &mii_regval);
Michael Chanc770a652005-08-25 15:38:39 -07007606 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07007607
7608 data->val_out = mii_regval;
7609
7610 return err;
7611 }
7612
7613 case SIOCSMIIREG:
Michael Chan583c28e2008-01-21 19:51:35 -08007614 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
Michael Chan7b6b8342007-07-07 22:50:15 -07007615 return -EOPNOTSUPP;
7616
Michael Chandad3e452007-05-03 13:18:03 -07007617 if (!netif_running(dev))
7618 return -EAGAIN;
7619
Michael Chanc770a652005-08-25 15:38:39 -07007620 spin_lock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07007621 err = bnx2_write_phy(bp, data->reg_num & 0x1f, data->val_in);
Michael Chanc770a652005-08-25 15:38:39 -07007622 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07007623
7624 return err;
7625
7626 default:
7627 /* do nothing */
7628 break;
7629 }
7630 return -EOPNOTSUPP;
7631}
7632
7633/* Called with rtnl_lock */
7634static int
7635bnx2_change_mac_addr(struct net_device *dev, void *p)
7636{
7637 struct sockaddr *addr = p;
Michael Chan972ec0d2006-01-23 16:12:43 -08007638 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007639
Michael Chan73eef4c2005-08-25 15:39:15 -07007640 if (!is_valid_ether_addr(addr->sa_data))
7641 return -EINVAL;
7642
Michael Chanb6016b72005-05-26 13:03:09 -07007643 memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
7644 if (netif_running(dev))
Benjamin Li5fcaed02008-07-14 22:39:52 -07007645 bnx2_set_mac_addr(bp, bp->dev->dev_addr, 0);
Michael Chanb6016b72005-05-26 13:03:09 -07007646
7647 return 0;
7648}
7649
7650/* Called with rtnl_lock */
7651static int
7652bnx2_change_mtu(struct net_device *dev, int new_mtu)
7653{
Michael Chan972ec0d2006-01-23 16:12:43 -08007654 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007655
7656 if (((new_mtu + ETH_HLEN) > MAX_ETHERNET_JUMBO_PACKET_SIZE) ||
7657 ((new_mtu + ETH_HLEN) < MIN_ETHERNET_PACKET_SIZE))
7658 return -EINVAL;
7659
7660 dev->mtu = new_mtu;
Michael Chan5d5d0012007-12-12 11:17:43 -08007661 return (bnx2_change_ring_size(bp, bp->rx_ring_size, bp->tx_ring_size));
Michael Chanb6016b72005-05-26 13:03:09 -07007662}
7663
Alexey Dobriyan257ddbd2010-01-27 10:17:41 +00007664#ifdef CONFIG_NET_POLL_CONTROLLER
Michael Chanb6016b72005-05-26 13:03:09 -07007665static void
7666poll_bnx2(struct net_device *dev)
7667{
Michael Chan972ec0d2006-01-23 16:12:43 -08007668 struct bnx2 *bp = netdev_priv(dev);
Neil Hormanb2af2c12008-11-12 16:23:44 -08007669 int i;
Michael Chanb6016b72005-05-26 13:03:09 -07007670
Neil Hormanb2af2c12008-11-12 16:23:44 -08007671 for (i = 0; i < bp->irq_nvecs; i++) {
Michael Chan1bf1e342010-03-23 13:13:12 +00007672 struct bnx2_irq *irq = &bp->irq_tbl[i];
7673
7674 disable_irq(irq->vector);
7675 irq->handler(irq->vector, &bp->bnx2_napi[i]);
7676 enable_irq(irq->vector);
Neil Hormanb2af2c12008-11-12 16:23:44 -08007677 }
Michael Chanb6016b72005-05-26 13:03:09 -07007678}
7679#endif
7680
Michael Chan253c8b72007-01-08 19:56:01 -08007681static void __devinit
7682bnx2_get_5709_media(struct bnx2 *bp)
7683{
7684 u32 val = REG_RD(bp, BNX2_MISC_DUAL_MEDIA_CTRL);
7685 u32 bond_id = val & BNX2_MISC_DUAL_MEDIA_CTRL_BOND_ID;
7686 u32 strap;
7687
7688 if (bond_id == BNX2_MISC_DUAL_MEDIA_CTRL_BOND_ID_C)
7689 return;
7690 else if (bond_id == BNX2_MISC_DUAL_MEDIA_CTRL_BOND_ID_S) {
Michael Chan583c28e2008-01-21 19:51:35 -08007691 bp->phy_flags |= BNX2_PHY_FLAG_SERDES;
Michael Chan253c8b72007-01-08 19:56:01 -08007692 return;
7693 }
7694
7695 if (val & BNX2_MISC_DUAL_MEDIA_CTRL_STRAP_OVERRIDE)
7696 strap = (val & BNX2_MISC_DUAL_MEDIA_CTRL_PHY_CTRL) >> 21;
7697 else
7698 strap = (val & BNX2_MISC_DUAL_MEDIA_CTRL_PHY_CTRL_STRAP) >> 8;
7699
7700 if (PCI_FUNC(bp->pdev->devfn) == 0) {
7701 switch (strap) {
7702 case 0x4:
7703 case 0x5:
7704 case 0x6:
Michael Chan583c28e2008-01-21 19:51:35 -08007705 bp->phy_flags |= BNX2_PHY_FLAG_SERDES;
Michael Chan253c8b72007-01-08 19:56:01 -08007706 return;
7707 }
7708 } else {
7709 switch (strap) {
7710 case 0x1:
7711 case 0x2:
7712 case 0x4:
Michael Chan583c28e2008-01-21 19:51:35 -08007713 bp->phy_flags |= BNX2_PHY_FLAG_SERDES;
Michael Chan253c8b72007-01-08 19:56:01 -08007714 return;
7715 }
7716 }
7717}
7718
Michael Chan883e5152007-05-03 13:25:11 -07007719static void __devinit
7720bnx2_get_pci_speed(struct bnx2 *bp)
7721{
7722 u32 reg;
7723
7724 reg = REG_RD(bp, BNX2_PCICFG_MISC_STATUS);
7725 if (reg & BNX2_PCICFG_MISC_STATUS_PCIX_DET) {
7726 u32 clkreg;
7727
David S. Millerf86e82f2008-01-21 17:15:40 -08007728 bp->flags |= BNX2_FLAG_PCIX;
Michael Chan883e5152007-05-03 13:25:11 -07007729
7730 clkreg = REG_RD(bp, BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS);
7731
7732 clkreg &= BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET;
7733 switch (clkreg) {
7734 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_133MHZ:
7735 bp->bus_speed_mhz = 133;
7736 break;
7737
7738 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_95MHZ:
7739 bp->bus_speed_mhz = 100;
7740 break;
7741
7742 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_66MHZ:
7743 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_80MHZ:
7744 bp->bus_speed_mhz = 66;
7745 break;
7746
7747 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_48MHZ:
7748 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_55MHZ:
7749 bp->bus_speed_mhz = 50;
7750 break;
7751
7752 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_LOW:
7753 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_32MHZ:
7754 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_38MHZ:
7755 bp->bus_speed_mhz = 33;
7756 break;
7757 }
7758 }
7759 else {
7760 if (reg & BNX2_PCICFG_MISC_STATUS_M66EN)
7761 bp->bus_speed_mhz = 66;
7762 else
7763 bp->bus_speed_mhz = 33;
7764 }
7765
7766 if (reg & BNX2_PCICFG_MISC_STATUS_32BIT_DET)
David S. Millerf86e82f2008-01-21 17:15:40 -08007767 bp->flags |= BNX2_FLAG_PCI_32BIT;
Michael Chan883e5152007-05-03 13:25:11 -07007768
7769}
7770
Michael Chan76d99062009-12-03 09:46:34 +00007771static void __devinit
7772bnx2_read_vpd_fw_ver(struct bnx2 *bp)
7773{
Matt Carlsondf25bc32010-02-26 14:04:44 +00007774 int rc, i, j;
Michael Chan76d99062009-12-03 09:46:34 +00007775 u8 *data;
Matt Carlsondf25bc32010-02-26 14:04:44 +00007776 unsigned int block_end, rosize, len;
Michael Chan76d99062009-12-03 09:46:34 +00007777
Michael Chan012093f2009-12-03 15:58:00 -08007778#define BNX2_VPD_NVRAM_OFFSET 0x300
7779#define BNX2_VPD_LEN 128
Michael Chan76d99062009-12-03 09:46:34 +00007780#define BNX2_MAX_VER_SLEN 30
7781
7782 data = kmalloc(256, GFP_KERNEL);
7783 if (!data)
7784 return;
7785
Michael Chan012093f2009-12-03 15:58:00 -08007786 rc = bnx2_nvram_read(bp, BNX2_VPD_NVRAM_OFFSET, data + BNX2_VPD_LEN,
7787 BNX2_VPD_LEN);
Michael Chan76d99062009-12-03 09:46:34 +00007788 if (rc)
7789 goto vpd_done;
7790
Michael Chan012093f2009-12-03 15:58:00 -08007791 for (i = 0; i < BNX2_VPD_LEN; i += 4) {
7792 data[i] = data[i + BNX2_VPD_LEN + 3];
7793 data[i + 1] = data[i + BNX2_VPD_LEN + 2];
7794 data[i + 2] = data[i + BNX2_VPD_LEN + 1];
7795 data[i + 3] = data[i + BNX2_VPD_LEN];
Michael Chan76d99062009-12-03 09:46:34 +00007796 }
7797
Matt Carlsondf25bc32010-02-26 14:04:44 +00007798 i = pci_vpd_find_tag(data, 0, BNX2_VPD_LEN, PCI_VPD_LRDT_RO_DATA);
7799 if (i < 0)
Michael Chan76d99062009-12-03 09:46:34 +00007800 goto vpd_done;
Matt Carlsondf25bc32010-02-26 14:04:44 +00007801
7802 rosize = pci_vpd_lrdt_size(&data[i]);
7803 i += PCI_VPD_LRDT_TAG_SIZE;
7804 block_end = i + rosize;
7805
7806 if (block_end > BNX2_VPD_LEN)
7807 goto vpd_done;
7808
7809 j = pci_vpd_find_info_keyword(data, i, rosize,
7810 PCI_VPD_RO_KEYWORD_MFR_ID);
7811 if (j < 0)
7812 goto vpd_done;
7813
7814 len = pci_vpd_info_field_size(&data[j]);
7815
7816 j += PCI_VPD_INFO_FLD_HDR_SIZE;
7817 if (j + len > block_end || len != 4 ||
7818 memcmp(&data[j], "1028", 4))
7819 goto vpd_done;
7820
7821 j = pci_vpd_find_info_keyword(data, i, rosize,
7822 PCI_VPD_RO_KEYWORD_VENDOR0);
7823 if (j < 0)
7824 goto vpd_done;
7825
7826 len = pci_vpd_info_field_size(&data[j]);
7827
7828 j += PCI_VPD_INFO_FLD_HDR_SIZE;
7829 if (j + len > block_end || len > BNX2_MAX_VER_SLEN)
7830 goto vpd_done;
7831
7832 memcpy(bp->fw_version, &data[j], len);
7833 bp->fw_version[len] = ' ';
Michael Chan76d99062009-12-03 09:46:34 +00007834
7835vpd_done:
7836 kfree(data);
7837}
7838
Michael Chanb6016b72005-05-26 13:03:09 -07007839static int __devinit
7840bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
7841{
7842 struct bnx2 *bp;
7843 unsigned long mem_len;
Michael Chan58fc2ea2007-07-07 22:52:02 -07007844 int rc, i, j;
Michael Chanb6016b72005-05-26 13:03:09 -07007845 u32 reg;
Michael Chan40453c82007-05-03 13:19:18 -07007846 u64 dma_mask, persist_dma_mask;
Michael Chanb6016b72005-05-26 13:03:09 -07007847
Michael Chanb6016b72005-05-26 13:03:09 -07007848 SET_NETDEV_DEV(dev, &pdev->dev);
Michael Chan972ec0d2006-01-23 16:12:43 -08007849 bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007850
7851 bp->flags = 0;
7852 bp->phy_flags = 0;
7853
Michael Chan354fcd72010-01-17 07:30:44 +00007854 bp->temp_stats_blk =
7855 kzalloc(sizeof(struct statistics_block), GFP_KERNEL);
7856
7857 if (bp->temp_stats_blk == NULL) {
7858 rc = -ENOMEM;
7859 goto err_out;
7860 }
7861
Michael Chanb6016b72005-05-26 13:03:09 -07007862 /* enable device (incl. PCI PM wakeup), and bus-mastering */
7863 rc = pci_enable_device(pdev);
7864 if (rc) {
Joe Perches3a9c6a42010-02-17 15:01:51 +00007865 dev_err(&pdev->dev, "Cannot enable PCI device, aborting\n");
Michael Chanb6016b72005-05-26 13:03:09 -07007866 goto err_out;
7867 }
7868
7869 if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) {
Jeff Garzik9b91cf92006-06-27 11:39:50 -04007870 dev_err(&pdev->dev,
Joe Perches3a9c6a42010-02-17 15:01:51 +00007871 "Cannot find PCI device base address, aborting\n");
Michael Chanb6016b72005-05-26 13:03:09 -07007872 rc = -ENODEV;
7873 goto err_out_disable;
7874 }
7875
7876 rc = pci_request_regions(pdev, DRV_MODULE_NAME);
7877 if (rc) {
Joe Perches3a9c6a42010-02-17 15:01:51 +00007878 dev_err(&pdev->dev, "Cannot obtain PCI resources, aborting\n");
Michael Chanb6016b72005-05-26 13:03:09 -07007879 goto err_out_disable;
7880 }
7881
7882 pci_set_master(pdev);
Wendy Xiong6ff2da42008-05-16 22:18:21 -07007883 pci_save_state(pdev);
Michael Chanb6016b72005-05-26 13:03:09 -07007884
7885 bp->pm_cap = pci_find_capability(pdev, PCI_CAP_ID_PM);
7886 if (bp->pm_cap == 0) {
Jeff Garzik9b91cf92006-06-27 11:39:50 -04007887 dev_err(&pdev->dev,
Joe Perches3a9c6a42010-02-17 15:01:51 +00007888 "Cannot find power management capability, aborting\n");
Michael Chanb6016b72005-05-26 13:03:09 -07007889 rc = -EIO;
7890 goto err_out_release;
7891 }
7892
Michael Chanb6016b72005-05-26 13:03:09 -07007893 bp->dev = dev;
7894 bp->pdev = pdev;
7895
7896 spin_lock_init(&bp->phy_lock);
Michael Chan1b8227c2007-05-03 13:24:05 -07007897 spin_lock_init(&bp->indirect_lock);
Michael Chanc5a88952009-08-14 15:49:45 +00007898#ifdef BCM_CNIC
7899 mutex_init(&bp->cnic_lock);
7900#endif
David Howellsc4028952006-11-22 14:57:56 +00007901 INIT_WORK(&bp->reset_task, bnx2_reset_task);
Michael Chanb6016b72005-05-26 13:03:09 -07007902
7903 dev->base_addr = dev->mem_start = pci_resource_start(pdev, 0);
Michael Chan4edd4732009-06-08 18:14:42 -07007904 mem_len = MB_GET_CID_ADDR(TX_TSS_CID + TX_MAX_TSS_RINGS + 1);
Michael Chanb6016b72005-05-26 13:03:09 -07007905 dev->mem_end = dev->mem_start + mem_len;
7906 dev->irq = pdev->irq;
7907
7908 bp->regview = ioremap_nocache(dev->base_addr, mem_len);
7909
7910 if (!bp->regview) {
Joe Perches3a9c6a42010-02-17 15:01:51 +00007911 dev_err(&pdev->dev, "Cannot map register space, aborting\n");
Michael Chanb6016b72005-05-26 13:03:09 -07007912 rc = -ENOMEM;
7913 goto err_out_release;
7914 }
7915
7916 /* Configure byte swap and enable write to the reg_window registers.
7917 * Rely on CPU to do target byte swapping on big endian systems
7918 * The chip's target access swapping will not swap all accesses
7919 */
7920 pci_write_config_dword(bp->pdev, BNX2_PCICFG_MISC_CONFIG,
7921 BNX2_PCICFG_MISC_CONFIG_REG_WINDOW_ENA |
7922 BNX2_PCICFG_MISC_CONFIG_TARGET_MB_WORD_SWAP);
7923
Pavel Machek829ca9a2005-09-03 15:56:56 -07007924 bnx2_set_power_state(bp, PCI_D0);
Michael Chanb6016b72005-05-26 13:03:09 -07007925
7926 bp->chip_id = REG_RD(bp, BNX2_MISC_ID);
7927
Michael Chan883e5152007-05-03 13:25:11 -07007928 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
7929 if (pci_find_capability(pdev, PCI_CAP_ID_EXP) == 0) {
7930 dev_err(&pdev->dev,
Joe Perches3a9c6a42010-02-17 15:01:51 +00007931 "Cannot find PCIE capability, aborting\n");
Michael Chan883e5152007-05-03 13:25:11 -07007932 rc = -EIO;
7933 goto err_out_unmap;
7934 }
David S. Millerf86e82f2008-01-21 17:15:40 -08007935 bp->flags |= BNX2_FLAG_PCIE;
Michael Chan2dd201d2008-01-21 17:06:09 -08007936 if (CHIP_REV(bp) == CHIP_REV_Ax)
David S. Millerf86e82f2008-01-21 17:15:40 -08007937 bp->flags |= BNX2_FLAG_JUMBO_BROKEN;
Michael Chan883e5152007-05-03 13:25:11 -07007938 } else {
Michael Chan59b47d82006-11-19 14:10:45 -08007939 bp->pcix_cap = pci_find_capability(pdev, PCI_CAP_ID_PCIX);
7940 if (bp->pcix_cap == 0) {
7941 dev_err(&pdev->dev,
Joe Perches3a9c6a42010-02-17 15:01:51 +00007942 "Cannot find PCIX capability, aborting\n");
Michael Chan59b47d82006-11-19 14:10:45 -08007943 rc = -EIO;
7944 goto err_out_unmap;
7945 }
Michael Chan61d9e3f2009-08-21 16:20:46 +00007946 bp->flags |= BNX2_FLAG_BROKEN_STATS;
Michael Chan59b47d82006-11-19 14:10:45 -08007947 }
7948
Michael Chanb4b36042007-12-20 19:59:30 -08007949 if (CHIP_NUM(bp) == CHIP_NUM_5709 && CHIP_REV(bp) != CHIP_REV_Ax) {
7950 if (pci_find_capability(pdev, PCI_CAP_ID_MSIX))
David S. Millerf86e82f2008-01-21 17:15:40 -08007951 bp->flags |= BNX2_FLAG_MSIX_CAP;
Michael Chanb4b36042007-12-20 19:59:30 -08007952 }
7953
Michael Chan8e6a72c2007-05-03 13:24:48 -07007954 if (CHIP_ID(bp) != CHIP_ID_5706_A0 && CHIP_ID(bp) != CHIP_ID_5706_A1) {
7955 if (pci_find_capability(pdev, PCI_CAP_ID_MSI))
David S. Millerf86e82f2008-01-21 17:15:40 -08007956 bp->flags |= BNX2_FLAG_MSI_CAP;
Michael Chan8e6a72c2007-05-03 13:24:48 -07007957 }
7958
Michael Chan40453c82007-05-03 13:19:18 -07007959 /* 5708 cannot support DMA addresses > 40-bit. */
7960 if (CHIP_NUM(bp) == CHIP_NUM_5708)
Yang Hongyang50cf1562009-04-06 19:01:14 -07007961 persist_dma_mask = dma_mask = DMA_BIT_MASK(40);
Michael Chan40453c82007-05-03 13:19:18 -07007962 else
Yang Hongyang6a355282009-04-06 19:01:13 -07007963 persist_dma_mask = dma_mask = DMA_BIT_MASK(64);
Michael Chan40453c82007-05-03 13:19:18 -07007964
7965 /* Configure DMA attributes. */
7966 if (pci_set_dma_mask(pdev, dma_mask) == 0) {
7967 dev->features |= NETIF_F_HIGHDMA;
7968 rc = pci_set_consistent_dma_mask(pdev, persist_dma_mask);
7969 if (rc) {
7970 dev_err(&pdev->dev,
Joe Perches3a9c6a42010-02-17 15:01:51 +00007971 "pci_set_consistent_dma_mask failed, aborting\n");
Michael Chan40453c82007-05-03 13:19:18 -07007972 goto err_out_unmap;
7973 }
Yang Hongyang284901a2009-04-06 19:01:15 -07007974 } else if ((rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) != 0) {
Joe Perches3a9c6a42010-02-17 15:01:51 +00007975 dev_err(&pdev->dev, "System does not support DMA, aborting\n");
Michael Chan40453c82007-05-03 13:19:18 -07007976 goto err_out_unmap;
7977 }
7978
David S. Millerf86e82f2008-01-21 17:15:40 -08007979 if (!(bp->flags & BNX2_FLAG_PCIE))
Michael Chan883e5152007-05-03 13:25:11 -07007980 bnx2_get_pci_speed(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07007981
7982 /* 5706A0 may falsely detect SERR and PERR. */
7983 if (CHIP_ID(bp) == CHIP_ID_5706_A0) {
7984 reg = REG_RD(bp, PCI_COMMAND);
7985 reg &= ~(PCI_COMMAND_SERR | PCI_COMMAND_PARITY);
7986 REG_WR(bp, PCI_COMMAND, reg);
7987 }
7988 else if ((CHIP_ID(bp) == CHIP_ID_5706_A1) &&
David S. Millerf86e82f2008-01-21 17:15:40 -08007989 !(bp->flags & BNX2_FLAG_PCIX)) {
Michael Chanb6016b72005-05-26 13:03:09 -07007990
Jeff Garzik9b91cf92006-06-27 11:39:50 -04007991 dev_err(&pdev->dev,
Joe Perches3a9c6a42010-02-17 15:01:51 +00007992 "5706 A1 can only be used in a PCIX bus, aborting\n");
Michael Chanb6016b72005-05-26 13:03:09 -07007993 goto err_out_unmap;
7994 }
7995
7996 bnx2_init_nvram(bp);
7997
Michael Chan2726d6e2008-01-29 21:35:05 -08007998 reg = bnx2_reg_rd_ind(bp, BNX2_SHM_HDR_SIGNATURE);
Michael Chane3648b32005-11-04 08:51:21 -08007999
8000 if ((reg & BNX2_SHM_HDR_SIGNATURE_SIG_MASK) ==
Michael Chan24cb2302007-01-25 15:49:56 -08008001 BNX2_SHM_HDR_SIGNATURE_SIG) {
8002 u32 off = PCI_FUNC(pdev->devfn) << 2;
8003
Michael Chan2726d6e2008-01-29 21:35:05 -08008004 bp->shmem_base = bnx2_reg_rd_ind(bp, BNX2_SHM_HDR_ADDR_0 + off);
Michael Chan24cb2302007-01-25 15:49:56 -08008005 } else
Michael Chane3648b32005-11-04 08:51:21 -08008006 bp->shmem_base = HOST_VIEW_SHMEM_BASE;
8007
Michael Chanb6016b72005-05-26 13:03:09 -07008008 /* Get the permanent MAC address. First we need to make sure the
8009 * firmware is actually running.
8010 */
Michael Chan2726d6e2008-01-29 21:35:05 -08008011 reg = bnx2_shmem_rd(bp, BNX2_DEV_INFO_SIGNATURE);
Michael Chanb6016b72005-05-26 13:03:09 -07008012
8013 if ((reg & BNX2_DEV_INFO_SIGNATURE_MAGIC_MASK) !=
8014 BNX2_DEV_INFO_SIGNATURE_MAGIC) {
Joe Perches3a9c6a42010-02-17 15:01:51 +00008015 dev_err(&pdev->dev, "Firmware not running, aborting\n");
Michael Chanb6016b72005-05-26 13:03:09 -07008016 rc = -ENODEV;
8017 goto err_out_unmap;
8018 }
8019
Michael Chan76d99062009-12-03 09:46:34 +00008020 bnx2_read_vpd_fw_ver(bp);
8021
8022 j = strlen(bp->fw_version);
Michael Chan2726d6e2008-01-29 21:35:05 -08008023 reg = bnx2_shmem_rd(bp, BNX2_DEV_INFO_BC_REV);
Michael Chan76d99062009-12-03 09:46:34 +00008024 for (i = 0; i < 3 && j < 24; i++) {
Michael Chan58fc2ea2007-07-07 22:52:02 -07008025 u8 num, k, skip0;
8026
Michael Chan76d99062009-12-03 09:46:34 +00008027 if (i == 0) {
8028 bp->fw_version[j++] = 'b';
8029 bp->fw_version[j++] = 'c';
8030 bp->fw_version[j++] = ' ';
8031 }
Michael Chan58fc2ea2007-07-07 22:52:02 -07008032 num = (u8) (reg >> (24 - (i * 8)));
8033 for (k = 100, skip0 = 1; k >= 1; num %= k, k /= 10) {
8034 if (num >= k || !skip0 || k == 1) {
8035 bp->fw_version[j++] = (num / k) + '0';
8036 skip0 = 0;
8037 }
8038 }
8039 if (i != 2)
8040 bp->fw_version[j++] = '.';
8041 }
Michael Chan2726d6e2008-01-29 21:35:05 -08008042 reg = bnx2_shmem_rd(bp, BNX2_PORT_FEATURE);
Michael Chan846f5c62007-10-10 16:16:51 -07008043 if (reg & BNX2_PORT_FEATURE_WOL_ENABLED)
8044 bp->wol = 1;
8045
8046 if (reg & BNX2_PORT_FEATURE_ASF_ENABLED) {
David S. Millerf86e82f2008-01-21 17:15:40 -08008047 bp->flags |= BNX2_FLAG_ASF_ENABLE;
Michael Chanc2d3db82007-07-16 18:26:43 -07008048
8049 for (i = 0; i < 30; i++) {
Michael Chan2726d6e2008-01-29 21:35:05 -08008050 reg = bnx2_shmem_rd(bp, BNX2_BC_STATE_CONDITION);
Michael Chanc2d3db82007-07-16 18:26:43 -07008051 if (reg & BNX2_CONDITION_MFW_RUN_MASK)
8052 break;
8053 msleep(10);
8054 }
8055 }
Michael Chan2726d6e2008-01-29 21:35:05 -08008056 reg = bnx2_shmem_rd(bp, BNX2_BC_STATE_CONDITION);
Michael Chan58fc2ea2007-07-07 22:52:02 -07008057 reg &= BNX2_CONDITION_MFW_RUN_MASK;
8058 if (reg != BNX2_CONDITION_MFW_RUN_UNKNOWN &&
8059 reg != BNX2_CONDITION_MFW_RUN_NONE) {
Michael Chan2726d6e2008-01-29 21:35:05 -08008060 u32 addr = bnx2_shmem_rd(bp, BNX2_MFW_VER_PTR);
Michael Chan58fc2ea2007-07-07 22:52:02 -07008061
Michael Chan76d99062009-12-03 09:46:34 +00008062 if (j < 32)
8063 bp->fw_version[j++] = ' ';
8064 for (i = 0; i < 3 && j < 28; i++) {
Michael Chan2726d6e2008-01-29 21:35:05 -08008065 reg = bnx2_reg_rd_ind(bp, addr + i * 4);
Michael Chan58fc2ea2007-07-07 22:52:02 -07008066 reg = swab32(reg);
8067 memcpy(&bp->fw_version[j], &reg, 4);
8068 j += 4;
8069 }
8070 }
Michael Chanb6016b72005-05-26 13:03:09 -07008071
Michael Chan2726d6e2008-01-29 21:35:05 -08008072 reg = bnx2_shmem_rd(bp, BNX2_PORT_HW_CFG_MAC_UPPER);
Michael Chanb6016b72005-05-26 13:03:09 -07008073 bp->mac_addr[0] = (u8) (reg >> 8);
8074 bp->mac_addr[1] = (u8) reg;
8075
Michael Chan2726d6e2008-01-29 21:35:05 -08008076 reg = bnx2_shmem_rd(bp, BNX2_PORT_HW_CFG_MAC_LOWER);
Michael Chanb6016b72005-05-26 13:03:09 -07008077 bp->mac_addr[2] = (u8) (reg >> 24);
8078 bp->mac_addr[3] = (u8) (reg >> 16);
8079 bp->mac_addr[4] = (u8) (reg >> 8);
8080 bp->mac_addr[5] = (u8) reg;
8081
8082 bp->tx_ring_size = MAX_TX_DESC_CNT;
Michael Chan932f3772006-08-15 01:39:36 -07008083 bnx2_set_rx_ring_size(bp, 255);
Michael Chanb6016b72005-05-26 13:03:09 -07008084
8085 bp->rx_csum = 1;
8086
Michael Chancf7474a2009-08-21 16:20:48 +00008087 bp->tx_quick_cons_trip_int = 2;
Michael Chanb6016b72005-05-26 13:03:09 -07008088 bp->tx_quick_cons_trip = 20;
Michael Chancf7474a2009-08-21 16:20:48 +00008089 bp->tx_ticks_int = 18;
Michael Chanb6016b72005-05-26 13:03:09 -07008090 bp->tx_ticks = 80;
Jeff Garzik6aa20a22006-09-13 13:24:59 -04008091
Michael Chancf7474a2009-08-21 16:20:48 +00008092 bp->rx_quick_cons_trip_int = 2;
8093 bp->rx_quick_cons_trip = 12;
Michael Chanb6016b72005-05-26 13:03:09 -07008094 bp->rx_ticks_int = 18;
8095 bp->rx_ticks = 18;
8096
Michael Chan7ea69202007-07-16 18:27:10 -07008097 bp->stats_ticks = USEC_PER_SEC & BNX2_HC_STATS_TICKS_HC_STAT_TICKS;
Michael Chanb6016b72005-05-26 13:03:09 -07008098
Benjamin Liac392ab2008-09-18 16:40:49 -07008099 bp->current_interval = BNX2_TIMER_INTERVAL;
Michael Chanb6016b72005-05-26 13:03:09 -07008100
Michael Chan5b0c76a2005-11-04 08:45:49 -08008101 bp->phy_addr = 1;
8102
Michael Chanb6016b72005-05-26 13:03:09 -07008103 /* Disable WOL support if we are running on a SERDES chip. */
Michael Chan253c8b72007-01-08 19:56:01 -08008104 if (CHIP_NUM(bp) == CHIP_NUM_5709)
8105 bnx2_get_5709_media(bp);
8106 else if (CHIP_BOND_ID(bp) & CHIP_BOND_ID_SERDES_BIT)
Michael Chan583c28e2008-01-21 19:51:35 -08008107 bp->phy_flags |= BNX2_PHY_FLAG_SERDES;
Michael Chanbac0dff2006-11-19 14:15:05 -08008108
Michael Chan0d8a6572007-07-07 22:49:43 -07008109 bp->phy_port = PORT_TP;
Michael Chan583c28e2008-01-21 19:51:35 -08008110 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Michael Chan0d8a6572007-07-07 22:49:43 -07008111 bp->phy_port = PORT_FIBRE;
Michael Chan2726d6e2008-01-29 21:35:05 -08008112 reg = bnx2_shmem_rd(bp, BNX2_SHARED_HW_CFG_CONFIG);
Michael Chan846f5c62007-10-10 16:16:51 -07008113 if (!(reg & BNX2_SHARED_HW_CFG_GIG_LINK_ON_VAUX)) {
David S. Millerf86e82f2008-01-21 17:15:40 -08008114 bp->flags |= BNX2_FLAG_NO_WOL;
Michael Chan846f5c62007-10-10 16:16:51 -07008115 bp->wol = 0;
8116 }
Michael Chan38ea3682008-02-23 19:48:57 -08008117 if (CHIP_NUM(bp) == CHIP_NUM_5706) {
8118 /* Don't do parallel detect on this board because of
8119 * some board problems. The link will not go down
8120 * if we do parallel detect.
8121 */
8122 if (pdev->subsystem_vendor == PCI_VENDOR_ID_HP &&
8123 pdev->subsystem_device == 0x310c)
8124 bp->phy_flags |= BNX2_PHY_FLAG_NO_PARALLEL;
8125 } else {
Michael Chan5b0c76a2005-11-04 08:45:49 -08008126 bp->phy_addr = 2;
Michael Chan5b0c76a2005-11-04 08:45:49 -08008127 if (reg & BNX2_SHARED_HW_CFG_PHY_2_5G)
Michael Chan583c28e2008-01-21 19:51:35 -08008128 bp->phy_flags |= BNX2_PHY_FLAG_2_5G_CAPABLE;
Michael Chan5b0c76a2005-11-04 08:45:49 -08008129 }
Michael Chan261dd5c2007-01-08 19:55:46 -08008130 } else if (CHIP_NUM(bp) == CHIP_NUM_5706 ||
8131 CHIP_NUM(bp) == CHIP_NUM_5708)
Michael Chan583c28e2008-01-21 19:51:35 -08008132 bp->phy_flags |= BNX2_PHY_FLAG_CRC_FIX;
Michael Chanfb0c18b2007-12-10 17:18:23 -08008133 else if (CHIP_NUM(bp) == CHIP_NUM_5709 &&
8134 (CHIP_REV(bp) == CHIP_REV_Ax ||
8135 CHIP_REV(bp) == CHIP_REV_Bx))
Michael Chan583c28e2008-01-21 19:51:35 -08008136 bp->phy_flags |= BNX2_PHY_FLAG_DIS_EARLY_DAC;
Michael Chanb6016b72005-05-26 13:03:09 -07008137
Michael Chan7c62e832008-07-14 22:39:03 -07008138 bnx2_init_fw_cap(bp);
8139
Michael Chan16088272006-06-12 22:16:43 -07008140 if ((CHIP_ID(bp) == CHIP_ID_5708_A0) ||
8141 (CHIP_ID(bp) == CHIP_ID_5708_B0) ||
Michael Chan5ec6d7b2008-11-12 16:01:41 -08008142 (CHIP_ID(bp) == CHIP_ID_5708_B1) ||
8143 !(REG_RD(bp, BNX2_PCI_CONFIG_3) & BNX2_PCI_CONFIG_3_VAUX_PRESET)) {
David S. Millerf86e82f2008-01-21 17:15:40 -08008144 bp->flags |= BNX2_FLAG_NO_WOL;
Michael Chan846f5c62007-10-10 16:16:51 -07008145 bp->wol = 0;
8146 }
Michael Chandda1e392006-01-23 16:08:14 -08008147
Michael Chanb6016b72005-05-26 13:03:09 -07008148 if (CHIP_ID(bp) == CHIP_ID_5706_A0) {
8149 bp->tx_quick_cons_trip_int =
8150 bp->tx_quick_cons_trip;
8151 bp->tx_ticks_int = bp->tx_ticks;
8152 bp->rx_quick_cons_trip_int =
8153 bp->rx_quick_cons_trip;
8154 bp->rx_ticks_int = bp->rx_ticks;
8155 bp->comp_prod_trip_int = bp->comp_prod_trip;
8156 bp->com_ticks_int = bp->com_ticks;
8157 bp->cmd_ticks_int = bp->cmd_ticks;
8158 }
8159
Michael Chanf9317a42006-09-29 17:06:23 -07008160 /* Disable MSI on 5706 if AMD 8132 bridge is found.
8161 *
8162 * MSI is defined to be 32-bit write. The 5706 does 64-bit MSI writes
8163 * with byte enables disabled on the unused 32-bit word. This is legal
8164 * but causes problems on the AMD 8132 which will eventually stop
8165 * responding after a while.
8166 *
8167 * AMD believes this incompatibility is unique to the 5706, and
Michael Ellerman88187df2007-01-25 19:34:07 +11008168 * prefers to locally disable MSI rather than globally disabling it.
Michael Chanf9317a42006-09-29 17:06:23 -07008169 */
8170 if (CHIP_NUM(bp) == CHIP_NUM_5706 && disable_msi == 0) {
8171 struct pci_dev *amd_8132 = NULL;
8172
8173 while ((amd_8132 = pci_get_device(PCI_VENDOR_ID_AMD,
8174 PCI_DEVICE_ID_AMD_8132_BRIDGE,
8175 amd_8132))) {
Michael Chanf9317a42006-09-29 17:06:23 -07008176
Auke Kok44c10132007-06-08 15:46:36 -07008177 if (amd_8132->revision >= 0x10 &&
8178 amd_8132->revision <= 0x13) {
Michael Chanf9317a42006-09-29 17:06:23 -07008179 disable_msi = 1;
8180 pci_dev_put(amd_8132);
8181 break;
8182 }
8183 }
8184 }
8185
Michael Chandeaf3912007-07-07 22:48:00 -07008186 bnx2_set_default_link(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07008187 bp->req_flow_ctrl = FLOW_CTRL_RX | FLOW_CTRL_TX;
8188
Michael Chancd339a02005-08-25 15:35:24 -07008189 init_timer(&bp->timer);
Benjamin Liac392ab2008-09-18 16:40:49 -07008190 bp->timer.expires = RUN_AT(BNX2_TIMER_INTERVAL);
Michael Chancd339a02005-08-25 15:35:24 -07008191 bp->timer.data = (unsigned long) bp;
8192 bp->timer.function = bnx2_timer;
8193
Michael Chanb6016b72005-05-26 13:03:09 -07008194 return 0;
8195
8196err_out_unmap:
8197 if (bp->regview) {
8198 iounmap(bp->regview);
Michael Chan73eef4c2005-08-25 15:39:15 -07008199 bp->regview = NULL;
Michael Chanb6016b72005-05-26 13:03:09 -07008200 }
8201
8202err_out_release:
8203 pci_release_regions(pdev);
8204
8205err_out_disable:
8206 pci_disable_device(pdev);
8207 pci_set_drvdata(pdev, NULL);
8208
8209err_out:
8210 return rc;
8211}
8212
Michael Chan883e5152007-05-03 13:25:11 -07008213static char * __devinit
8214bnx2_bus_string(struct bnx2 *bp, char *str)
8215{
8216 char *s = str;
8217
David S. Millerf86e82f2008-01-21 17:15:40 -08008218 if (bp->flags & BNX2_FLAG_PCIE) {
Michael Chan883e5152007-05-03 13:25:11 -07008219 s += sprintf(s, "PCI Express");
8220 } else {
8221 s += sprintf(s, "PCI");
David S. Millerf86e82f2008-01-21 17:15:40 -08008222 if (bp->flags & BNX2_FLAG_PCIX)
Michael Chan883e5152007-05-03 13:25:11 -07008223 s += sprintf(s, "-X");
David S. Millerf86e82f2008-01-21 17:15:40 -08008224 if (bp->flags & BNX2_FLAG_PCI_32BIT)
Michael Chan883e5152007-05-03 13:25:11 -07008225 s += sprintf(s, " 32-bit");
8226 else
8227 s += sprintf(s, " 64-bit");
8228 s += sprintf(s, " %dMHz", bp->bus_speed_mhz);
8229 }
8230 return str;
8231}
8232
Michael Chanf048fa92010-06-01 15:05:36 +00008233static void
8234bnx2_del_napi(struct bnx2 *bp)
8235{
8236 int i;
8237
8238 for (i = 0; i < bp->irq_nvecs; i++)
8239 netif_napi_del(&bp->bnx2_napi[i].napi);
8240}
8241
8242static void
Michael Chan35efa7c2007-12-20 19:56:37 -08008243bnx2_init_napi(struct bnx2 *bp)
8244{
Michael Chanb4b36042007-12-20 19:59:30 -08008245 int i;
Michael Chan35efa7c2007-12-20 19:56:37 -08008246
Benjamin Li4327ba42010-03-23 13:13:11 +00008247 for (i = 0; i < bp->irq_nvecs; i++) {
Michael Chan35e90102008-06-19 16:37:42 -07008248 struct bnx2_napi *bnapi = &bp->bnx2_napi[i];
8249 int (*poll)(struct napi_struct *, int);
8250
8251 if (i == 0)
8252 poll = bnx2_poll;
8253 else
Michael Chanf0ea2e62008-06-19 16:41:57 -07008254 poll = bnx2_poll_msix;
Michael Chan35e90102008-06-19 16:37:42 -07008255
8256 netif_napi_add(bp->dev, &bp->bnx2_napi[i].napi, poll, 64);
Michael Chanb4b36042007-12-20 19:59:30 -08008257 bnapi->bp = bp;
8258 }
Michael Chan35efa7c2007-12-20 19:56:37 -08008259}
8260
Stephen Hemminger0421eae2008-11-21 17:31:27 -08008261static const struct net_device_ops bnx2_netdev_ops = {
8262 .ndo_open = bnx2_open,
8263 .ndo_start_xmit = bnx2_start_xmit,
8264 .ndo_stop = bnx2_close,
8265 .ndo_get_stats = bnx2_get_stats,
8266 .ndo_set_rx_mode = bnx2_set_rx_mode,
8267 .ndo_do_ioctl = bnx2_ioctl,
8268 .ndo_validate_addr = eth_validate_addr,
8269 .ndo_set_mac_address = bnx2_change_mac_addr,
8270 .ndo_change_mtu = bnx2_change_mtu,
8271 .ndo_tx_timeout = bnx2_tx_timeout,
8272#ifdef BCM_VLAN
8273 .ndo_vlan_rx_register = bnx2_vlan_rx_register,
8274#endif
Alexey Dobriyan257ddbd2010-01-27 10:17:41 +00008275#ifdef CONFIG_NET_POLL_CONTROLLER
Stephen Hemminger0421eae2008-11-21 17:31:27 -08008276 .ndo_poll_controller = poll_bnx2,
8277#endif
8278};
8279
Eric Dumazet72dccb02009-07-23 02:01:38 +00008280static void inline vlan_features_add(struct net_device *dev, unsigned long flags)
8281{
8282#ifdef BCM_VLAN
8283 dev->vlan_features |= flags;
8284#endif
8285}
8286
Michael Chan35efa7c2007-12-20 19:56:37 -08008287static int __devinit
Michael Chanb6016b72005-05-26 13:03:09 -07008288bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
8289{
8290 static int version_printed = 0;
8291 struct net_device *dev = NULL;
8292 struct bnx2 *bp;
Joe Perches0795af52007-10-03 17:59:30 -07008293 int rc;
Michael Chan883e5152007-05-03 13:25:11 -07008294 char str[40];
Michael Chanb6016b72005-05-26 13:03:09 -07008295
8296 if (version_printed++ == 0)
Joe Perches3a9c6a42010-02-17 15:01:51 +00008297 pr_info("%s", version);
Michael Chanb6016b72005-05-26 13:03:09 -07008298
8299 /* dev zeroed in init_etherdev */
Benjamin Li706bf242008-07-18 17:55:11 -07008300 dev = alloc_etherdev_mq(sizeof(*bp), TX_MAX_RINGS);
Michael Chanb6016b72005-05-26 13:03:09 -07008301
8302 if (!dev)
8303 return -ENOMEM;
8304
8305 rc = bnx2_init_board(pdev, dev);
8306 if (rc < 0) {
8307 free_netdev(dev);
8308 return rc;
8309 }
8310
Stephen Hemminger0421eae2008-11-21 17:31:27 -08008311 dev->netdev_ops = &bnx2_netdev_ops;
Michael Chanb6016b72005-05-26 13:03:09 -07008312 dev->watchdog_timeo = TX_TIMEOUT;
Michael Chanb6016b72005-05-26 13:03:09 -07008313 dev->ethtool_ops = &bnx2_ethtool_ops;
Michael Chanb6016b72005-05-26 13:03:09 -07008314
Michael Chan972ec0d2006-01-23 16:12:43 -08008315 bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07008316
Michael Chan1b2f9222007-05-03 13:20:19 -07008317 pci_set_drvdata(pdev, dev);
8318
Michael Chan57579f72009-04-04 16:51:14 -07008319 rc = bnx2_request_firmware(bp);
8320 if (rc)
8321 goto error;
8322
Michael Chan1b2f9222007-05-03 13:20:19 -07008323 memcpy(dev->dev_addr, bp->mac_addr, 6);
8324 memcpy(dev->perm_addr, bp->mac_addr, 6);
Michael Chan1b2f9222007-05-03 13:20:19 -07008325
Michael Chanc67938a2010-05-06 08:58:12 +00008326 dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG | NETIF_F_GRO;
Eric Dumazet72dccb02009-07-23 02:01:38 +00008327 vlan_features_add(dev, NETIF_F_IP_CSUM | NETIF_F_SG);
8328 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
Stephen Hemmingerd212f872007-06-27 00:47:37 -07008329 dev->features |= NETIF_F_IPV6_CSUM;
Eric Dumazet72dccb02009-07-23 02:01:38 +00008330 vlan_features_add(dev, NETIF_F_IPV6_CSUM);
8331 }
Michael Chan1b2f9222007-05-03 13:20:19 -07008332#ifdef BCM_VLAN
8333 dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
8334#endif
8335 dev->features |= NETIF_F_TSO | NETIF_F_TSO_ECN;
Eric Dumazet72dccb02009-07-23 02:01:38 +00008336 vlan_features_add(dev, NETIF_F_TSO | NETIF_F_TSO_ECN);
8337 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
Michael Chan4666f872007-05-03 13:22:28 -07008338 dev->features |= NETIF_F_TSO6;
Eric Dumazet72dccb02009-07-23 02:01:38 +00008339 vlan_features_add(dev, NETIF_F_TSO6);
8340 }
Michael Chanb6016b72005-05-26 13:03:09 -07008341 if ((rc = register_netdev(dev))) {
Jeff Garzik9b91cf92006-06-27 11:39:50 -04008342 dev_err(&pdev->dev, "Cannot register net device\n");
Michael Chan57579f72009-04-04 16:51:14 -07008343 goto error;
Michael Chanb6016b72005-05-26 13:03:09 -07008344 }
8345
Joe Perches3a9c6a42010-02-17 15:01:51 +00008346 netdev_info(dev, "%s (%c%d) %s found at mem %lx, IRQ %d, node addr %pM\n",
8347 board_info[ent->driver_data].name,
8348 ((CHIP_ID(bp) & 0xf000) >> 12) + 'A',
8349 ((CHIP_ID(bp) & 0x0ff0) >> 4),
8350 bnx2_bus_string(bp, str),
8351 dev->base_addr,
8352 bp->pdev->irq, dev->dev_addr);
Michael Chanb6016b72005-05-26 13:03:09 -07008353
Michael Chanb6016b72005-05-26 13:03:09 -07008354 return 0;
Michael Chan57579f72009-04-04 16:51:14 -07008355
8356error:
8357 if (bp->mips_firmware)
8358 release_firmware(bp->mips_firmware);
8359 if (bp->rv2p_firmware)
8360 release_firmware(bp->rv2p_firmware);
8361
8362 if (bp->regview)
8363 iounmap(bp->regview);
8364 pci_release_regions(pdev);
8365 pci_disable_device(pdev);
8366 pci_set_drvdata(pdev, NULL);
8367 free_netdev(dev);
8368 return rc;
Michael Chanb6016b72005-05-26 13:03:09 -07008369}
8370
8371static void __devexit
8372bnx2_remove_one(struct pci_dev *pdev)
8373{
8374 struct net_device *dev = pci_get_drvdata(pdev);
Michael Chan972ec0d2006-01-23 16:12:43 -08008375 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07008376
Michael Chanafdc08b2005-08-25 15:34:29 -07008377 flush_scheduled_work();
8378
Michael Chanb6016b72005-05-26 13:03:09 -07008379 unregister_netdev(dev);
8380
Michael Chan57579f72009-04-04 16:51:14 -07008381 if (bp->mips_firmware)
8382 release_firmware(bp->mips_firmware);
8383 if (bp->rv2p_firmware)
8384 release_firmware(bp->rv2p_firmware);
8385
Michael Chanb6016b72005-05-26 13:03:09 -07008386 if (bp->regview)
8387 iounmap(bp->regview);
8388
Michael Chan354fcd72010-01-17 07:30:44 +00008389 kfree(bp->temp_stats_blk);
8390
Michael Chanb6016b72005-05-26 13:03:09 -07008391 free_netdev(dev);
8392 pci_release_regions(pdev);
8393 pci_disable_device(pdev);
8394 pci_set_drvdata(pdev, NULL);
8395}
8396
8397static int
Pavel Machek829ca9a2005-09-03 15:56:56 -07008398bnx2_suspend(struct pci_dev *pdev, pm_message_t state)
Michael Chanb6016b72005-05-26 13:03:09 -07008399{
8400 struct net_device *dev = pci_get_drvdata(pdev);
Michael Chan972ec0d2006-01-23 16:12:43 -08008401 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07008402
Michael Chan6caebb02007-08-03 20:57:25 -07008403 /* PCI register 4 needs to be saved whether netif_running() or not.
8404 * MSI address and data need to be saved if using MSI and
8405 * netif_running().
8406 */
8407 pci_save_state(pdev);
Michael Chanb6016b72005-05-26 13:03:09 -07008408 if (!netif_running(dev))
8409 return 0;
8410
Michael Chan1d602902006-03-20 17:50:08 -08008411 flush_scheduled_work();
Michael Chan212f9932010-04-27 11:28:10 +00008412 bnx2_netif_stop(bp, true);
Michael Chanb6016b72005-05-26 13:03:09 -07008413 netif_device_detach(dev);
8414 del_timer_sync(&bp->timer);
Michael Chan74bf4ba2008-10-09 12:21:08 -07008415 bnx2_shutdown_chip(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07008416 bnx2_free_skbs(bp);
Pavel Machek829ca9a2005-09-03 15:56:56 -07008417 bnx2_set_power_state(bp, pci_choose_state(pdev, state));
Michael Chanb6016b72005-05-26 13:03:09 -07008418 return 0;
8419}
8420
8421static int
8422bnx2_resume(struct pci_dev *pdev)
8423{
8424 struct net_device *dev = pci_get_drvdata(pdev);
Michael Chan972ec0d2006-01-23 16:12:43 -08008425 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07008426
Michael Chan6caebb02007-08-03 20:57:25 -07008427 pci_restore_state(pdev);
Michael Chanb6016b72005-05-26 13:03:09 -07008428 if (!netif_running(dev))
8429 return 0;
8430
Pavel Machek829ca9a2005-09-03 15:56:56 -07008431 bnx2_set_power_state(bp, PCI_D0);
Michael Chanb6016b72005-05-26 13:03:09 -07008432 netif_device_attach(dev);
Michael Chan9a120bc2008-05-16 22:17:45 -07008433 bnx2_init_nic(bp, 1);
Michael Chan212f9932010-04-27 11:28:10 +00008434 bnx2_netif_start(bp, true);
Michael Chanb6016b72005-05-26 13:03:09 -07008435 return 0;
8436}
8437
Wendy Xiong6ff2da42008-05-16 22:18:21 -07008438/**
8439 * bnx2_io_error_detected - called when PCI error is detected
8440 * @pdev: Pointer to PCI device
8441 * @state: The current pci connection state
8442 *
8443 * This function is called after a PCI bus error affecting
8444 * this device has been detected.
8445 */
8446static pci_ers_result_t bnx2_io_error_detected(struct pci_dev *pdev,
8447 pci_channel_state_t state)
8448{
8449 struct net_device *dev = pci_get_drvdata(pdev);
8450 struct bnx2 *bp = netdev_priv(dev);
8451
8452 rtnl_lock();
8453 netif_device_detach(dev);
8454
Dean Nelson2ec3de22009-07-31 09:13:18 +00008455 if (state == pci_channel_io_perm_failure) {
8456 rtnl_unlock();
8457 return PCI_ERS_RESULT_DISCONNECT;
8458 }
8459
Wendy Xiong6ff2da42008-05-16 22:18:21 -07008460 if (netif_running(dev)) {
Michael Chan212f9932010-04-27 11:28:10 +00008461 bnx2_netif_stop(bp, true);
Wendy Xiong6ff2da42008-05-16 22:18:21 -07008462 del_timer_sync(&bp->timer);
8463 bnx2_reset_nic(bp, BNX2_DRV_MSG_CODE_RESET);
8464 }
8465
8466 pci_disable_device(pdev);
8467 rtnl_unlock();
8468
8469 /* Request a slot slot reset. */
8470 return PCI_ERS_RESULT_NEED_RESET;
8471}
8472
8473/**
8474 * bnx2_io_slot_reset - called after the pci bus has been reset.
8475 * @pdev: Pointer to PCI device
8476 *
8477 * Restart the card from scratch, as if from a cold-boot.
8478 */
8479static pci_ers_result_t bnx2_io_slot_reset(struct pci_dev *pdev)
8480{
8481 struct net_device *dev = pci_get_drvdata(pdev);
8482 struct bnx2 *bp = netdev_priv(dev);
8483
8484 rtnl_lock();
8485 if (pci_enable_device(pdev)) {
8486 dev_err(&pdev->dev,
Joe Perches3a9c6a42010-02-17 15:01:51 +00008487 "Cannot re-enable PCI device after reset\n");
Wendy Xiong6ff2da42008-05-16 22:18:21 -07008488 rtnl_unlock();
8489 return PCI_ERS_RESULT_DISCONNECT;
8490 }
8491 pci_set_master(pdev);
8492 pci_restore_state(pdev);
Breno Leitao529fab62009-11-26 07:31:49 +00008493 pci_save_state(pdev);
Wendy Xiong6ff2da42008-05-16 22:18:21 -07008494
8495 if (netif_running(dev)) {
8496 bnx2_set_power_state(bp, PCI_D0);
8497 bnx2_init_nic(bp, 1);
8498 }
8499
8500 rtnl_unlock();
8501 return PCI_ERS_RESULT_RECOVERED;
8502}
8503
8504/**
8505 * bnx2_io_resume - called when traffic can start flowing again.
8506 * @pdev: Pointer to PCI device
8507 *
8508 * This callback is called when the error recovery driver tells us that
8509 * its OK to resume normal operation.
8510 */
8511static void bnx2_io_resume(struct pci_dev *pdev)
8512{
8513 struct net_device *dev = pci_get_drvdata(pdev);
8514 struct bnx2 *bp = netdev_priv(dev);
8515
8516 rtnl_lock();
8517 if (netif_running(dev))
Michael Chan212f9932010-04-27 11:28:10 +00008518 bnx2_netif_start(bp, true);
Wendy Xiong6ff2da42008-05-16 22:18:21 -07008519
8520 netif_device_attach(dev);
8521 rtnl_unlock();
8522}
8523
8524static struct pci_error_handlers bnx2_err_handler = {
8525 .error_detected = bnx2_io_error_detected,
8526 .slot_reset = bnx2_io_slot_reset,
8527 .resume = bnx2_io_resume,
8528};
8529
Michael Chanb6016b72005-05-26 13:03:09 -07008530static struct pci_driver bnx2_pci_driver = {
Peter Hagervall14ab9b82005-08-10 14:18:16 -07008531 .name = DRV_MODULE_NAME,
8532 .id_table = bnx2_pci_tbl,
8533 .probe = bnx2_init_one,
8534 .remove = __devexit_p(bnx2_remove_one),
8535 .suspend = bnx2_suspend,
8536 .resume = bnx2_resume,
Wendy Xiong6ff2da42008-05-16 22:18:21 -07008537 .err_handler = &bnx2_err_handler,
Michael Chanb6016b72005-05-26 13:03:09 -07008538};
8539
8540static int __init bnx2_init(void)
8541{
Jeff Garzik29917622006-08-19 17:48:59 -04008542 return pci_register_driver(&bnx2_pci_driver);
Michael Chanb6016b72005-05-26 13:03:09 -07008543}
8544
8545static void __exit bnx2_cleanup(void)
8546{
8547 pci_unregister_driver(&bnx2_pci_driver);
8548}
8549
8550module_init(bnx2_init);
8551module_exit(bnx2_cleanup);
8552
8553
8554