blob: 802b538502ebeaaf361d9025cb10a5611aa4c4a1 [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 Chanbec92042010-02-16 15:19:42 -080061#define DRV_MODULE_VERSION "2.0.8"
62#define DRV_MODULE_RELDATE "Feb 15, 2010"
63#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 Chanbec92042010-02-16 15:19:42 -080065#define FW_MIPS_FILE_09 "bnx2/bnx2-mips-09-5.0.0.j9.fw"
66#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);
250
Michael Chan35e90102008-06-19 16:37:42 -0700251static inline u32 bnx2_tx_avail(struct bnx2 *bp, struct bnx2_tx_ring_info *txr)
Michael Chane89bbf12005-08-25 15:36:58 -0700252{
Michael Chan2f8af122006-08-15 01:39:10 -0700253 u32 diff;
Michael Chane89bbf12005-08-25 15:36:58 -0700254
Michael Chan2f8af122006-08-15 01:39:10 -0700255 smp_mb();
Michael Chanfaac9c42006-12-14 15:56:32 -0800256
257 /* The ring uses 256 indices for 255 entries, one of them
258 * needs to be skipped.
259 */
Michael Chan35e90102008-06-19 16:37:42 -0700260 diff = txr->tx_prod - txr->tx_cons;
Michael Chanfaac9c42006-12-14 15:56:32 -0800261 if (unlikely(diff >= TX_DESC_CNT)) {
262 diff &= 0xffff;
263 if (diff == TX_DESC_CNT)
264 diff = MAX_TX_DESC_CNT;
265 }
Michael Chane89bbf12005-08-25 15:36:58 -0700266 return (bp->tx_ring_size - diff);
267}
268
Michael Chanb6016b72005-05-26 13:03:09 -0700269static u32
270bnx2_reg_rd_ind(struct bnx2 *bp, u32 offset)
271{
Michael Chan1b8227c2007-05-03 13:24:05 -0700272 u32 val;
273
274 spin_lock_bh(&bp->indirect_lock);
Michael Chanb6016b72005-05-26 13:03:09 -0700275 REG_WR(bp, BNX2_PCICFG_REG_WINDOW_ADDRESS, offset);
Michael Chan1b8227c2007-05-03 13:24:05 -0700276 val = REG_RD(bp, BNX2_PCICFG_REG_WINDOW);
277 spin_unlock_bh(&bp->indirect_lock);
278 return val;
Michael Chanb6016b72005-05-26 13:03:09 -0700279}
280
281static void
282bnx2_reg_wr_ind(struct bnx2 *bp, u32 offset, u32 val)
283{
Michael Chan1b8227c2007-05-03 13:24:05 -0700284 spin_lock_bh(&bp->indirect_lock);
Michael Chanb6016b72005-05-26 13:03:09 -0700285 REG_WR(bp, BNX2_PCICFG_REG_WINDOW_ADDRESS, offset);
286 REG_WR(bp, BNX2_PCICFG_REG_WINDOW, val);
Michael Chan1b8227c2007-05-03 13:24:05 -0700287 spin_unlock_bh(&bp->indirect_lock);
Michael Chanb6016b72005-05-26 13:03:09 -0700288}
289
290static void
Michael Chan2726d6e2008-01-29 21:35:05 -0800291bnx2_shmem_wr(struct bnx2 *bp, u32 offset, u32 val)
292{
293 bnx2_reg_wr_ind(bp, bp->shmem_base + offset, val);
294}
295
296static u32
297bnx2_shmem_rd(struct bnx2 *bp, u32 offset)
298{
299 return (bnx2_reg_rd_ind(bp, bp->shmem_base + offset));
300}
301
302static void
Michael Chanb6016b72005-05-26 13:03:09 -0700303bnx2_ctx_wr(struct bnx2 *bp, u32 cid_addr, u32 offset, u32 val)
304{
305 offset += cid_addr;
Michael Chan1b8227c2007-05-03 13:24:05 -0700306 spin_lock_bh(&bp->indirect_lock);
Michael Chan59b47d82006-11-19 14:10:45 -0800307 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
308 int i;
309
310 REG_WR(bp, BNX2_CTX_CTX_DATA, val);
311 REG_WR(bp, BNX2_CTX_CTX_CTRL,
312 offset | BNX2_CTX_CTX_CTRL_WRITE_REQ);
313 for (i = 0; i < 5; i++) {
Michael Chan59b47d82006-11-19 14:10:45 -0800314 val = REG_RD(bp, BNX2_CTX_CTX_CTRL);
315 if ((val & BNX2_CTX_CTX_CTRL_WRITE_REQ) == 0)
316 break;
317 udelay(5);
318 }
319 } else {
320 REG_WR(bp, BNX2_CTX_DATA_ADR, offset);
321 REG_WR(bp, BNX2_CTX_DATA, val);
322 }
Michael Chan1b8227c2007-05-03 13:24:05 -0700323 spin_unlock_bh(&bp->indirect_lock);
Michael Chanb6016b72005-05-26 13:03:09 -0700324}
325
Michael Chan4edd4732009-06-08 18:14:42 -0700326#ifdef BCM_CNIC
327static int
328bnx2_drv_ctl(struct net_device *dev, struct drv_ctl_info *info)
329{
330 struct bnx2 *bp = netdev_priv(dev);
331 struct drv_ctl_io *io = &info->data.io;
332
333 switch (info->cmd) {
334 case DRV_CTL_IO_WR_CMD:
335 bnx2_reg_wr_ind(bp, io->offset, io->data);
336 break;
337 case DRV_CTL_IO_RD_CMD:
338 io->data = bnx2_reg_rd_ind(bp, io->offset);
339 break;
340 case DRV_CTL_CTX_WR_CMD:
341 bnx2_ctx_wr(bp, io->cid_addr, io->offset, io->data);
342 break;
343 default:
344 return -EINVAL;
345 }
346 return 0;
347}
348
349static void bnx2_setup_cnic_irq_info(struct bnx2 *bp)
350{
351 struct cnic_eth_dev *cp = &bp->cnic_eth_dev;
352 struct bnx2_napi *bnapi = &bp->bnx2_napi[0];
353 int sb_id;
354
355 if (bp->flags & BNX2_FLAG_USING_MSIX) {
356 cp->drv_state |= CNIC_DRV_STATE_USING_MSIX;
357 bnapi->cnic_present = 0;
358 sb_id = bp->irq_nvecs;
359 cp->irq_arr[0].irq_flags |= CNIC_IRQ_FL_MSIX;
360 } else {
361 cp->drv_state &= ~CNIC_DRV_STATE_USING_MSIX;
362 bnapi->cnic_tag = bnapi->last_status_idx;
363 bnapi->cnic_present = 1;
364 sb_id = 0;
365 cp->irq_arr[0].irq_flags &= ~CNIC_IRQ_FL_MSIX;
366 }
367
368 cp->irq_arr[0].vector = bp->irq_tbl[sb_id].vector;
369 cp->irq_arr[0].status_blk = (void *)
370 ((unsigned long) bnapi->status_blk.msi +
371 (BNX2_SBLK_MSIX_ALIGN_SIZE * sb_id));
372 cp->irq_arr[0].status_blk_num = sb_id;
373 cp->num_irq = 1;
374}
375
376static int bnx2_register_cnic(struct net_device *dev, struct cnic_ops *ops,
377 void *data)
378{
379 struct bnx2 *bp = netdev_priv(dev);
380 struct cnic_eth_dev *cp = &bp->cnic_eth_dev;
381
382 if (ops == NULL)
383 return -EINVAL;
384
385 if (cp->drv_state & CNIC_DRV_STATE_REGD)
386 return -EBUSY;
387
388 bp->cnic_data = data;
389 rcu_assign_pointer(bp->cnic_ops, ops);
390
391 cp->num_irq = 0;
392 cp->drv_state = CNIC_DRV_STATE_REGD;
393
394 bnx2_setup_cnic_irq_info(bp);
395
396 return 0;
397}
398
399static int bnx2_unregister_cnic(struct net_device *dev)
400{
401 struct bnx2 *bp = netdev_priv(dev);
402 struct bnx2_napi *bnapi = &bp->bnx2_napi[0];
403 struct cnic_eth_dev *cp = &bp->cnic_eth_dev;
404
Michael Chanc5a88952009-08-14 15:49:45 +0000405 mutex_lock(&bp->cnic_lock);
Michael Chan4edd4732009-06-08 18:14:42 -0700406 cp->drv_state = 0;
407 bnapi->cnic_present = 0;
408 rcu_assign_pointer(bp->cnic_ops, NULL);
Michael Chanc5a88952009-08-14 15:49:45 +0000409 mutex_unlock(&bp->cnic_lock);
Michael Chan4edd4732009-06-08 18:14:42 -0700410 synchronize_rcu();
411 return 0;
412}
413
414struct cnic_eth_dev *bnx2_cnic_probe(struct net_device *dev)
415{
416 struct bnx2 *bp = netdev_priv(dev);
417 struct cnic_eth_dev *cp = &bp->cnic_eth_dev;
418
419 cp->drv_owner = THIS_MODULE;
420 cp->chip_id = bp->chip_id;
421 cp->pdev = bp->pdev;
422 cp->io_base = bp->regview;
423 cp->drv_ctl = bnx2_drv_ctl;
424 cp->drv_register_cnic = bnx2_register_cnic;
425 cp->drv_unregister_cnic = bnx2_unregister_cnic;
426
427 return cp;
428}
429EXPORT_SYMBOL(bnx2_cnic_probe);
430
431static void
432bnx2_cnic_stop(struct bnx2 *bp)
433{
434 struct cnic_ops *c_ops;
435 struct cnic_ctl_info info;
436
Michael Chanc5a88952009-08-14 15:49:45 +0000437 mutex_lock(&bp->cnic_lock);
438 c_ops = bp->cnic_ops;
Michael Chan4edd4732009-06-08 18:14:42 -0700439 if (c_ops) {
440 info.cmd = CNIC_CTL_STOP_CMD;
441 c_ops->cnic_ctl(bp->cnic_data, &info);
442 }
Michael Chanc5a88952009-08-14 15:49:45 +0000443 mutex_unlock(&bp->cnic_lock);
Michael Chan4edd4732009-06-08 18:14:42 -0700444}
445
446static void
447bnx2_cnic_start(struct bnx2 *bp)
448{
449 struct cnic_ops *c_ops;
450 struct cnic_ctl_info info;
451
Michael Chanc5a88952009-08-14 15:49:45 +0000452 mutex_lock(&bp->cnic_lock);
453 c_ops = bp->cnic_ops;
Michael Chan4edd4732009-06-08 18:14:42 -0700454 if (c_ops) {
455 if (!(bp->flags & BNX2_FLAG_USING_MSIX)) {
456 struct bnx2_napi *bnapi = &bp->bnx2_napi[0];
457
458 bnapi->cnic_tag = bnapi->last_status_idx;
459 }
460 info.cmd = CNIC_CTL_START_CMD;
461 c_ops->cnic_ctl(bp->cnic_data, &info);
462 }
Michael Chanc5a88952009-08-14 15:49:45 +0000463 mutex_unlock(&bp->cnic_lock);
Michael Chan4edd4732009-06-08 18:14:42 -0700464}
465
466#else
467
468static void
469bnx2_cnic_stop(struct bnx2 *bp)
470{
471}
472
473static void
474bnx2_cnic_start(struct bnx2 *bp)
475{
476}
477
478#endif
479
Michael Chanb6016b72005-05-26 13:03:09 -0700480static int
481bnx2_read_phy(struct bnx2 *bp, u32 reg, u32 *val)
482{
483 u32 val1;
484 int i, ret;
485
Michael Chan583c28e2008-01-21 19:51:35 -0800486 if (bp->phy_flags & BNX2_PHY_FLAG_INT_MODE_AUTO_POLLING) {
Michael Chanb6016b72005-05-26 13:03:09 -0700487 val1 = REG_RD(bp, BNX2_EMAC_MDIO_MODE);
488 val1 &= ~BNX2_EMAC_MDIO_MODE_AUTO_POLL;
489
490 REG_WR(bp, BNX2_EMAC_MDIO_MODE, val1);
491 REG_RD(bp, BNX2_EMAC_MDIO_MODE);
492
493 udelay(40);
494 }
495
496 val1 = (bp->phy_addr << 21) | (reg << 16) |
497 BNX2_EMAC_MDIO_COMM_COMMAND_READ | BNX2_EMAC_MDIO_COMM_DISEXT |
498 BNX2_EMAC_MDIO_COMM_START_BUSY;
499 REG_WR(bp, BNX2_EMAC_MDIO_COMM, val1);
500
501 for (i = 0; i < 50; i++) {
502 udelay(10);
503
504 val1 = REG_RD(bp, BNX2_EMAC_MDIO_COMM);
505 if (!(val1 & BNX2_EMAC_MDIO_COMM_START_BUSY)) {
506 udelay(5);
507
508 val1 = REG_RD(bp, BNX2_EMAC_MDIO_COMM);
509 val1 &= BNX2_EMAC_MDIO_COMM_DATA;
510
511 break;
512 }
513 }
514
515 if (val1 & BNX2_EMAC_MDIO_COMM_START_BUSY) {
516 *val = 0x0;
517 ret = -EBUSY;
518 }
519 else {
520 *val = val1;
521 ret = 0;
522 }
523
Michael Chan583c28e2008-01-21 19:51:35 -0800524 if (bp->phy_flags & BNX2_PHY_FLAG_INT_MODE_AUTO_POLLING) {
Michael Chanb6016b72005-05-26 13:03:09 -0700525 val1 = REG_RD(bp, BNX2_EMAC_MDIO_MODE);
526 val1 |= BNX2_EMAC_MDIO_MODE_AUTO_POLL;
527
528 REG_WR(bp, BNX2_EMAC_MDIO_MODE, val1);
529 REG_RD(bp, BNX2_EMAC_MDIO_MODE);
530
531 udelay(40);
532 }
533
534 return ret;
535}
536
537static int
538bnx2_write_phy(struct bnx2 *bp, u32 reg, u32 val)
539{
540 u32 val1;
541 int i, ret;
542
Michael Chan583c28e2008-01-21 19:51:35 -0800543 if (bp->phy_flags & BNX2_PHY_FLAG_INT_MODE_AUTO_POLLING) {
Michael Chanb6016b72005-05-26 13:03:09 -0700544 val1 = REG_RD(bp, BNX2_EMAC_MDIO_MODE);
545 val1 &= ~BNX2_EMAC_MDIO_MODE_AUTO_POLL;
546
547 REG_WR(bp, BNX2_EMAC_MDIO_MODE, val1);
548 REG_RD(bp, BNX2_EMAC_MDIO_MODE);
549
550 udelay(40);
551 }
552
553 val1 = (bp->phy_addr << 21) | (reg << 16) | val |
554 BNX2_EMAC_MDIO_COMM_COMMAND_WRITE |
555 BNX2_EMAC_MDIO_COMM_START_BUSY | BNX2_EMAC_MDIO_COMM_DISEXT;
556 REG_WR(bp, BNX2_EMAC_MDIO_COMM, val1);
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400557
Michael Chanb6016b72005-05-26 13:03:09 -0700558 for (i = 0; i < 50; i++) {
559 udelay(10);
560
561 val1 = REG_RD(bp, BNX2_EMAC_MDIO_COMM);
562 if (!(val1 & BNX2_EMAC_MDIO_COMM_START_BUSY)) {
563 udelay(5);
564 break;
565 }
566 }
567
568 if (val1 & BNX2_EMAC_MDIO_COMM_START_BUSY)
569 ret = -EBUSY;
570 else
571 ret = 0;
572
Michael Chan583c28e2008-01-21 19:51:35 -0800573 if (bp->phy_flags & BNX2_PHY_FLAG_INT_MODE_AUTO_POLLING) {
Michael Chanb6016b72005-05-26 13:03:09 -0700574 val1 = REG_RD(bp, BNX2_EMAC_MDIO_MODE);
575 val1 |= BNX2_EMAC_MDIO_MODE_AUTO_POLL;
576
577 REG_WR(bp, BNX2_EMAC_MDIO_MODE, val1);
578 REG_RD(bp, BNX2_EMAC_MDIO_MODE);
579
580 udelay(40);
581 }
582
583 return ret;
584}
585
586static void
587bnx2_disable_int(struct bnx2 *bp)
588{
Michael Chanb4b36042007-12-20 19:59:30 -0800589 int i;
590 struct bnx2_napi *bnapi;
591
592 for (i = 0; i < bp->irq_nvecs; i++) {
593 bnapi = &bp->bnx2_napi[i];
594 REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD, bnapi->int_num |
595 BNX2_PCICFG_INT_ACK_CMD_MASK_INT);
596 }
Michael Chanb6016b72005-05-26 13:03:09 -0700597 REG_RD(bp, BNX2_PCICFG_INT_ACK_CMD);
598}
599
600static void
601bnx2_enable_int(struct bnx2 *bp)
602{
Michael Chanb4b36042007-12-20 19:59:30 -0800603 int i;
604 struct bnx2_napi *bnapi;
Michael Chan1269a8a2006-01-23 16:11:03 -0800605
Michael Chanb4b36042007-12-20 19:59:30 -0800606 for (i = 0; i < bp->irq_nvecs; i++) {
607 bnapi = &bp->bnx2_napi[i];
Michael Chan35efa7c2007-12-20 19:56:37 -0800608
Michael Chanb4b36042007-12-20 19:59:30 -0800609 REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD, bnapi->int_num |
610 BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
611 BNX2_PCICFG_INT_ACK_CMD_MASK_INT |
612 bnapi->last_status_idx);
Michael Chanb6016b72005-05-26 13:03:09 -0700613
Michael Chanb4b36042007-12-20 19:59:30 -0800614 REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD, bnapi->int_num |
615 BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
616 bnapi->last_status_idx);
617 }
Michael Chanbf5295b2006-03-23 01:11:56 -0800618 REG_WR(bp, BNX2_HC_COMMAND, bp->hc_cmd | BNX2_HC_COMMAND_COAL_NOW);
Michael Chanb6016b72005-05-26 13:03:09 -0700619}
620
621static void
622bnx2_disable_int_sync(struct bnx2 *bp)
623{
Michael Chanb4b36042007-12-20 19:59:30 -0800624 int i;
625
Michael Chanb6016b72005-05-26 13:03:09 -0700626 atomic_inc(&bp->intr_sem);
Michael Chan37675462009-08-21 16:20:44 +0000627 if (!netif_running(bp->dev))
628 return;
629
Michael Chanb6016b72005-05-26 13:03:09 -0700630 bnx2_disable_int(bp);
Michael Chanb4b36042007-12-20 19:59:30 -0800631 for (i = 0; i < bp->irq_nvecs; i++)
632 synchronize_irq(bp->irq_tbl[i].vector);
Michael Chanb6016b72005-05-26 13:03:09 -0700633}
634
635static void
Michael Chan35efa7c2007-12-20 19:56:37 -0800636bnx2_napi_disable(struct bnx2 *bp)
637{
Michael Chanb4b36042007-12-20 19:59:30 -0800638 int i;
639
640 for (i = 0; i < bp->irq_nvecs; i++)
641 napi_disable(&bp->bnx2_napi[i].napi);
Michael Chan35efa7c2007-12-20 19:56:37 -0800642}
643
644static void
645bnx2_napi_enable(struct bnx2 *bp)
646{
Michael Chanb4b36042007-12-20 19:59:30 -0800647 int i;
648
649 for (i = 0; i < bp->irq_nvecs; i++)
650 napi_enable(&bp->bnx2_napi[i].napi);
Michael Chan35efa7c2007-12-20 19:56:37 -0800651}
652
653static void
Michael Chanb6016b72005-05-26 13:03:09 -0700654bnx2_netif_stop(struct bnx2 *bp)
655{
Michael Chan4edd4732009-06-08 18:14:42 -0700656 bnx2_cnic_stop(bp);
Michael Chanb6016b72005-05-26 13:03:09 -0700657 if (netif_running(bp->dev)) {
Breno Leitaoe6bf95f2009-12-18 20:35:34 -0800658 int i;
659
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);
Breno Leitaoe6bf95f2009-12-18 20:35:34 -0800662 /* prevent tx timeout */
663 for (i = 0; i < bp->dev->num_tx_queues; i++) {
664 struct netdev_queue *txq;
665
666 txq = netdev_get_tx_queue(bp->dev, i);
667 txq->trans_start = jiffies;
668 }
Michael Chanb6016b72005-05-26 13:03:09 -0700669 }
Michael Chanb7466562009-12-20 18:40:18 -0800670 bnx2_disable_int_sync(bp);
Michael Chanb6016b72005-05-26 13:03:09 -0700671}
672
673static void
674bnx2_netif_start(struct bnx2 *bp)
675{
676 if (atomic_dec_and_test(&bp->intr_sem)) {
677 if (netif_running(bp->dev)) {
Benjamin Li706bf242008-07-18 17:55:11 -0700678 netif_tx_wake_all_queues(bp->dev);
Michael Chan35efa7c2007-12-20 19:56:37 -0800679 bnx2_napi_enable(bp);
Michael Chanb6016b72005-05-26 13:03:09 -0700680 bnx2_enable_int(bp);
Michael Chan4edd4732009-06-08 18:14:42 -0700681 bnx2_cnic_start(bp);
Michael Chanb6016b72005-05-26 13:03:09 -0700682 }
683 }
684}
685
686static void
Michael Chan35e90102008-06-19 16:37:42 -0700687bnx2_free_tx_mem(struct bnx2 *bp)
688{
689 int i;
690
691 for (i = 0; i < bp->num_tx_rings; i++) {
692 struct bnx2_napi *bnapi = &bp->bnx2_napi[i];
693 struct bnx2_tx_ring_info *txr = &bnapi->tx_ring;
694
695 if (txr->tx_desc_ring) {
696 pci_free_consistent(bp->pdev, TXBD_RING_SIZE,
697 txr->tx_desc_ring,
698 txr->tx_desc_mapping);
699 txr->tx_desc_ring = NULL;
700 }
701 kfree(txr->tx_buf_ring);
702 txr->tx_buf_ring = NULL;
703 }
704}
705
Michael Chanbb4f98a2008-06-19 16:38:19 -0700706static void
707bnx2_free_rx_mem(struct bnx2 *bp)
708{
709 int i;
710
711 for (i = 0; i < bp->num_rx_rings; i++) {
712 struct bnx2_napi *bnapi = &bp->bnx2_napi[i];
713 struct bnx2_rx_ring_info *rxr = &bnapi->rx_ring;
714 int j;
715
716 for (j = 0; j < bp->rx_max_ring; j++) {
717 if (rxr->rx_desc_ring[j])
718 pci_free_consistent(bp->pdev, RXBD_RING_SIZE,
719 rxr->rx_desc_ring[j],
720 rxr->rx_desc_mapping[j]);
721 rxr->rx_desc_ring[j] = NULL;
722 }
Breno Leitao25b0b992009-06-08 10:30:19 +0000723 vfree(rxr->rx_buf_ring);
Michael Chanbb4f98a2008-06-19 16:38:19 -0700724 rxr->rx_buf_ring = NULL;
725
726 for (j = 0; j < bp->rx_max_pg_ring; j++) {
727 if (rxr->rx_pg_desc_ring[j])
728 pci_free_consistent(bp->pdev, RXBD_RING_SIZE,
Michael Chan3298a732008-12-17 19:06:08 -0800729 rxr->rx_pg_desc_ring[j],
730 rxr->rx_pg_desc_mapping[j]);
731 rxr->rx_pg_desc_ring[j] = NULL;
Michael Chanbb4f98a2008-06-19 16:38:19 -0700732 }
Breno Leitao25b0b992009-06-08 10:30:19 +0000733 vfree(rxr->rx_pg_ring);
Michael Chanbb4f98a2008-06-19 16:38:19 -0700734 rxr->rx_pg_ring = NULL;
735 }
736}
737
Michael Chan35e90102008-06-19 16:37:42 -0700738static int
739bnx2_alloc_tx_mem(struct bnx2 *bp)
740{
741 int i;
742
743 for (i = 0; i < bp->num_tx_rings; i++) {
744 struct bnx2_napi *bnapi = &bp->bnx2_napi[i];
745 struct bnx2_tx_ring_info *txr = &bnapi->tx_ring;
746
747 txr->tx_buf_ring = kzalloc(SW_TXBD_RING_SIZE, GFP_KERNEL);
748 if (txr->tx_buf_ring == NULL)
749 return -ENOMEM;
750
751 txr->tx_desc_ring =
752 pci_alloc_consistent(bp->pdev, TXBD_RING_SIZE,
753 &txr->tx_desc_mapping);
754 if (txr->tx_desc_ring == NULL)
755 return -ENOMEM;
756 }
757 return 0;
758}
759
Michael Chanbb4f98a2008-06-19 16:38:19 -0700760static int
761bnx2_alloc_rx_mem(struct bnx2 *bp)
762{
763 int i;
764
765 for (i = 0; i < bp->num_rx_rings; i++) {
766 struct bnx2_napi *bnapi = &bp->bnx2_napi[i];
767 struct bnx2_rx_ring_info *rxr = &bnapi->rx_ring;
768 int j;
769
770 rxr->rx_buf_ring =
771 vmalloc(SW_RXBD_RING_SIZE * bp->rx_max_ring);
772 if (rxr->rx_buf_ring == NULL)
773 return -ENOMEM;
774
775 memset(rxr->rx_buf_ring, 0,
776 SW_RXBD_RING_SIZE * bp->rx_max_ring);
777
778 for (j = 0; j < bp->rx_max_ring; j++) {
779 rxr->rx_desc_ring[j] =
780 pci_alloc_consistent(bp->pdev, RXBD_RING_SIZE,
781 &rxr->rx_desc_mapping[j]);
782 if (rxr->rx_desc_ring[j] == NULL)
783 return -ENOMEM;
784
785 }
786
787 if (bp->rx_pg_ring_size) {
788 rxr->rx_pg_ring = vmalloc(SW_RXPG_RING_SIZE *
789 bp->rx_max_pg_ring);
790 if (rxr->rx_pg_ring == NULL)
791 return -ENOMEM;
792
793 memset(rxr->rx_pg_ring, 0, SW_RXPG_RING_SIZE *
794 bp->rx_max_pg_ring);
795 }
796
797 for (j = 0; j < bp->rx_max_pg_ring; j++) {
798 rxr->rx_pg_desc_ring[j] =
799 pci_alloc_consistent(bp->pdev, RXBD_RING_SIZE,
800 &rxr->rx_pg_desc_mapping[j]);
801 if (rxr->rx_pg_desc_ring[j] == NULL)
802 return -ENOMEM;
803
804 }
805 }
806 return 0;
807}
808
Michael Chan35e90102008-06-19 16:37:42 -0700809static void
Michael Chanb6016b72005-05-26 13:03:09 -0700810bnx2_free_mem(struct bnx2 *bp)
811{
Michael Chan13daffa2006-03-20 17:49:20 -0800812 int i;
Michael Chan43e80b82008-06-19 16:41:08 -0700813 struct bnx2_napi *bnapi = &bp->bnx2_napi[0];
Michael Chan13daffa2006-03-20 17:49:20 -0800814
Michael Chan35e90102008-06-19 16:37:42 -0700815 bnx2_free_tx_mem(bp);
Michael Chanbb4f98a2008-06-19 16:38:19 -0700816 bnx2_free_rx_mem(bp);
Michael Chan35e90102008-06-19 16:37:42 -0700817
Michael Chan59b47d82006-11-19 14:10:45 -0800818 for (i = 0; i < bp->ctx_pages; i++) {
819 if (bp->ctx_blk[i]) {
820 pci_free_consistent(bp->pdev, BCM_PAGE_SIZE,
821 bp->ctx_blk[i],
822 bp->ctx_blk_mapping[i]);
823 bp->ctx_blk[i] = NULL;
824 }
825 }
Michael Chan43e80b82008-06-19 16:41:08 -0700826 if (bnapi->status_blk.msi) {
Michael Chan0f31f992006-03-23 01:12:38 -0800827 pci_free_consistent(bp->pdev, bp->status_stats_size,
Michael Chan43e80b82008-06-19 16:41:08 -0700828 bnapi->status_blk.msi,
829 bp->status_blk_mapping);
830 bnapi->status_blk.msi = NULL;
Michael Chan0f31f992006-03-23 01:12:38 -0800831 bp->stats_blk = NULL;
Michael Chanb6016b72005-05-26 13:03:09 -0700832 }
Michael Chanb6016b72005-05-26 13:03:09 -0700833}
834
835static int
836bnx2_alloc_mem(struct bnx2 *bp)
837{
Michael Chan35e90102008-06-19 16:37:42 -0700838 int i, status_blk_size, err;
Michael Chan43e80b82008-06-19 16:41:08 -0700839 struct bnx2_napi *bnapi;
840 void *status_blk;
Michael Chanb6016b72005-05-26 13:03:09 -0700841
Michael Chan0f31f992006-03-23 01:12:38 -0800842 /* Combine status and statistics blocks into one allocation. */
843 status_blk_size = L1_CACHE_ALIGN(sizeof(struct status_block));
David S. Millerf86e82f2008-01-21 17:15:40 -0800844 if (bp->flags & BNX2_FLAG_MSIX_CAP)
Michael Chanb4b36042007-12-20 19:59:30 -0800845 status_blk_size = L1_CACHE_ALIGN(BNX2_MAX_MSIX_HW_VEC *
846 BNX2_SBLK_MSIX_ALIGN_SIZE);
Michael Chan0f31f992006-03-23 01:12:38 -0800847 bp->status_stats_size = status_blk_size +
848 sizeof(struct statistics_block);
849
Michael Chan43e80b82008-06-19 16:41:08 -0700850 status_blk = pci_alloc_consistent(bp->pdev, bp->status_stats_size,
851 &bp->status_blk_mapping);
852 if (status_blk == NULL)
Michael Chanb6016b72005-05-26 13:03:09 -0700853 goto alloc_mem_err;
854
Michael Chan43e80b82008-06-19 16:41:08 -0700855 memset(status_blk, 0, bp->status_stats_size);
Michael Chanb6016b72005-05-26 13:03:09 -0700856
Michael Chan43e80b82008-06-19 16:41:08 -0700857 bnapi = &bp->bnx2_napi[0];
858 bnapi->status_blk.msi = status_blk;
859 bnapi->hw_tx_cons_ptr =
860 &bnapi->status_blk.msi->status_tx_quick_consumer_index0;
861 bnapi->hw_rx_cons_ptr =
862 &bnapi->status_blk.msi->status_rx_quick_consumer_index0;
David S. Millerf86e82f2008-01-21 17:15:40 -0800863 if (bp->flags & BNX2_FLAG_MSIX_CAP) {
Michael Chanb4b36042007-12-20 19:59:30 -0800864 for (i = 1; i < BNX2_MAX_MSIX_VEC; i++) {
Michael Chan43e80b82008-06-19 16:41:08 -0700865 struct status_block_msix *sblk;
Michael Chanb4b36042007-12-20 19:59:30 -0800866
Michael Chan43e80b82008-06-19 16:41:08 -0700867 bnapi = &bp->bnx2_napi[i];
868
869 sblk = (void *) (status_blk +
870 BNX2_SBLK_MSIX_ALIGN_SIZE * i);
871 bnapi->status_blk.msix = sblk;
872 bnapi->hw_tx_cons_ptr =
873 &sblk->status_tx_quick_consumer_index;
874 bnapi->hw_rx_cons_ptr =
875 &sblk->status_rx_quick_consumer_index;
Michael Chanb4b36042007-12-20 19:59:30 -0800876 bnapi->int_num = i << 24;
877 }
878 }
Michael Chan35efa7c2007-12-20 19:56:37 -0800879
Michael Chan43e80b82008-06-19 16:41:08 -0700880 bp->stats_blk = status_blk + status_blk_size;
Michael Chanb6016b72005-05-26 13:03:09 -0700881
Michael Chan0f31f992006-03-23 01:12:38 -0800882 bp->stats_blk_mapping = bp->status_blk_mapping + status_blk_size;
Michael Chanb6016b72005-05-26 13:03:09 -0700883
Michael Chan59b47d82006-11-19 14:10:45 -0800884 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
885 bp->ctx_pages = 0x2000 / BCM_PAGE_SIZE;
886 if (bp->ctx_pages == 0)
887 bp->ctx_pages = 1;
888 for (i = 0; i < bp->ctx_pages; i++) {
889 bp->ctx_blk[i] = pci_alloc_consistent(bp->pdev,
890 BCM_PAGE_SIZE,
891 &bp->ctx_blk_mapping[i]);
892 if (bp->ctx_blk[i] == NULL)
893 goto alloc_mem_err;
894 }
895 }
Michael Chan35e90102008-06-19 16:37:42 -0700896
Michael Chanbb4f98a2008-06-19 16:38:19 -0700897 err = bnx2_alloc_rx_mem(bp);
898 if (err)
899 goto alloc_mem_err;
900
Michael Chan35e90102008-06-19 16:37:42 -0700901 err = bnx2_alloc_tx_mem(bp);
902 if (err)
903 goto alloc_mem_err;
904
Michael Chanb6016b72005-05-26 13:03:09 -0700905 return 0;
906
907alloc_mem_err:
908 bnx2_free_mem(bp);
909 return -ENOMEM;
910}
911
912static void
Michael Chane3648b32005-11-04 08:51:21 -0800913bnx2_report_fw_link(struct bnx2 *bp)
914{
915 u32 fw_link_status = 0;
916
Michael Chan583c28e2008-01-21 19:51:35 -0800917 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
Michael Chan0d8a6572007-07-07 22:49:43 -0700918 return;
919
Michael Chane3648b32005-11-04 08:51:21 -0800920 if (bp->link_up) {
921 u32 bmsr;
922
923 switch (bp->line_speed) {
924 case SPEED_10:
925 if (bp->duplex == DUPLEX_HALF)
926 fw_link_status = BNX2_LINK_STATUS_10HALF;
927 else
928 fw_link_status = BNX2_LINK_STATUS_10FULL;
929 break;
930 case SPEED_100:
931 if (bp->duplex == DUPLEX_HALF)
932 fw_link_status = BNX2_LINK_STATUS_100HALF;
933 else
934 fw_link_status = BNX2_LINK_STATUS_100FULL;
935 break;
936 case SPEED_1000:
937 if (bp->duplex == DUPLEX_HALF)
938 fw_link_status = BNX2_LINK_STATUS_1000HALF;
939 else
940 fw_link_status = BNX2_LINK_STATUS_1000FULL;
941 break;
942 case SPEED_2500:
943 if (bp->duplex == DUPLEX_HALF)
944 fw_link_status = BNX2_LINK_STATUS_2500HALF;
945 else
946 fw_link_status = BNX2_LINK_STATUS_2500FULL;
947 break;
948 }
949
950 fw_link_status |= BNX2_LINK_STATUS_LINK_UP;
951
952 if (bp->autoneg) {
953 fw_link_status |= BNX2_LINK_STATUS_AN_ENABLED;
954
Michael Chanca58c3a2007-05-03 13:22:52 -0700955 bnx2_read_phy(bp, bp->mii_bmsr, &bmsr);
956 bnx2_read_phy(bp, bp->mii_bmsr, &bmsr);
Michael Chane3648b32005-11-04 08:51:21 -0800957
958 if (!(bmsr & BMSR_ANEGCOMPLETE) ||
Michael Chan583c28e2008-01-21 19:51:35 -0800959 bp->phy_flags & BNX2_PHY_FLAG_PARALLEL_DETECT)
Michael Chane3648b32005-11-04 08:51:21 -0800960 fw_link_status |= BNX2_LINK_STATUS_PARALLEL_DET;
961 else
962 fw_link_status |= BNX2_LINK_STATUS_AN_COMPLETE;
963 }
964 }
965 else
966 fw_link_status = BNX2_LINK_STATUS_LINK_DOWN;
967
Michael Chan2726d6e2008-01-29 21:35:05 -0800968 bnx2_shmem_wr(bp, BNX2_LINK_STATUS, fw_link_status);
Michael Chane3648b32005-11-04 08:51:21 -0800969}
970
Michael Chan9b1084b2007-07-07 22:50:37 -0700971static char *
972bnx2_xceiver_str(struct bnx2 *bp)
973{
974 return ((bp->phy_port == PORT_FIBRE) ? "SerDes" :
Michael Chan583c28e2008-01-21 19:51:35 -0800975 ((bp->phy_flags & BNX2_PHY_FLAG_SERDES) ? "Remote Copper" :
Michael Chan9b1084b2007-07-07 22:50:37 -0700976 "Copper"));
977}
978
Michael Chane3648b32005-11-04 08:51:21 -0800979static void
Michael Chanb6016b72005-05-26 13:03:09 -0700980bnx2_report_link(struct bnx2 *bp)
981{
982 if (bp->link_up) {
983 netif_carrier_on(bp->dev);
Joe Perches3a9c6a42010-02-17 15:01:51 +0000984 netdev_info(bp->dev, "NIC %s Link is Up, %d Mbps %s duplex",
985 bnx2_xceiver_str(bp),
986 bp->line_speed,
987 bp->duplex == DUPLEX_FULL ? "full" : "half");
Michael Chanb6016b72005-05-26 13:03:09 -0700988
989 if (bp->flow_ctrl) {
990 if (bp->flow_ctrl & FLOW_CTRL_RX) {
Joe Perches3a9c6a42010-02-17 15:01:51 +0000991 pr_cont(", receive ");
Michael Chanb6016b72005-05-26 13:03:09 -0700992 if (bp->flow_ctrl & FLOW_CTRL_TX)
Joe Perches3a9c6a42010-02-17 15:01:51 +0000993 pr_cont("& transmit ");
Michael Chanb6016b72005-05-26 13:03:09 -0700994 }
995 else {
Joe Perches3a9c6a42010-02-17 15:01:51 +0000996 pr_cont(", transmit ");
Michael Chanb6016b72005-05-26 13:03:09 -0700997 }
Joe Perches3a9c6a42010-02-17 15:01:51 +0000998 pr_cont("flow control ON");
Michael Chanb6016b72005-05-26 13:03:09 -0700999 }
Joe Perches3a9c6a42010-02-17 15:01:51 +00001000 pr_cont("\n");
1001 } else {
Michael Chanb6016b72005-05-26 13:03:09 -07001002 netif_carrier_off(bp->dev);
Joe Perches3a9c6a42010-02-17 15:01:51 +00001003 netdev_err(bp->dev, "NIC %s Link is Down\n",
1004 bnx2_xceiver_str(bp));
Michael Chanb6016b72005-05-26 13:03:09 -07001005 }
Michael Chane3648b32005-11-04 08:51:21 -08001006
1007 bnx2_report_fw_link(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07001008}
1009
1010static void
1011bnx2_resolve_flow_ctrl(struct bnx2 *bp)
1012{
1013 u32 local_adv, remote_adv;
1014
1015 bp->flow_ctrl = 0;
Jeff Garzik6aa20a22006-09-13 13:24:59 -04001016 if ((bp->autoneg & (AUTONEG_SPEED | AUTONEG_FLOW_CTRL)) !=
Michael Chanb6016b72005-05-26 13:03:09 -07001017 (AUTONEG_SPEED | AUTONEG_FLOW_CTRL)) {
1018
1019 if (bp->duplex == DUPLEX_FULL) {
1020 bp->flow_ctrl = bp->req_flow_ctrl;
1021 }
1022 return;
1023 }
1024
1025 if (bp->duplex != DUPLEX_FULL) {
1026 return;
1027 }
1028
Michael Chan583c28e2008-01-21 19:51:35 -08001029 if ((bp->phy_flags & BNX2_PHY_FLAG_SERDES) &&
Michael Chan5b0c76a2005-11-04 08:45:49 -08001030 (CHIP_NUM(bp) == CHIP_NUM_5708)) {
1031 u32 val;
1032
1033 bnx2_read_phy(bp, BCM5708S_1000X_STAT1, &val);
1034 if (val & BCM5708S_1000X_STAT1_TX_PAUSE)
1035 bp->flow_ctrl |= FLOW_CTRL_TX;
1036 if (val & BCM5708S_1000X_STAT1_RX_PAUSE)
1037 bp->flow_ctrl |= FLOW_CTRL_RX;
1038 return;
1039 }
1040
Michael Chanca58c3a2007-05-03 13:22:52 -07001041 bnx2_read_phy(bp, bp->mii_adv, &local_adv);
1042 bnx2_read_phy(bp, bp->mii_lpa, &remote_adv);
Michael Chanb6016b72005-05-26 13:03:09 -07001043
Michael Chan583c28e2008-01-21 19:51:35 -08001044 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Michael Chanb6016b72005-05-26 13:03:09 -07001045 u32 new_local_adv = 0;
1046 u32 new_remote_adv = 0;
1047
1048 if (local_adv & ADVERTISE_1000XPAUSE)
1049 new_local_adv |= ADVERTISE_PAUSE_CAP;
1050 if (local_adv & ADVERTISE_1000XPSE_ASYM)
1051 new_local_adv |= ADVERTISE_PAUSE_ASYM;
1052 if (remote_adv & ADVERTISE_1000XPAUSE)
1053 new_remote_adv |= ADVERTISE_PAUSE_CAP;
1054 if (remote_adv & ADVERTISE_1000XPSE_ASYM)
1055 new_remote_adv |= ADVERTISE_PAUSE_ASYM;
1056
1057 local_adv = new_local_adv;
1058 remote_adv = new_remote_adv;
1059 }
1060
1061 /* See Table 28B-3 of 802.3ab-1999 spec. */
1062 if (local_adv & ADVERTISE_PAUSE_CAP) {
1063 if(local_adv & ADVERTISE_PAUSE_ASYM) {
1064 if (remote_adv & ADVERTISE_PAUSE_CAP) {
1065 bp->flow_ctrl = FLOW_CTRL_TX | FLOW_CTRL_RX;
1066 }
1067 else if (remote_adv & ADVERTISE_PAUSE_ASYM) {
1068 bp->flow_ctrl = FLOW_CTRL_RX;
1069 }
1070 }
1071 else {
1072 if (remote_adv & ADVERTISE_PAUSE_CAP) {
1073 bp->flow_ctrl = FLOW_CTRL_TX | FLOW_CTRL_RX;
1074 }
1075 }
1076 }
1077 else if (local_adv & ADVERTISE_PAUSE_ASYM) {
1078 if ((remote_adv & ADVERTISE_PAUSE_CAP) &&
1079 (remote_adv & ADVERTISE_PAUSE_ASYM)) {
1080
1081 bp->flow_ctrl = FLOW_CTRL_TX;
1082 }
1083 }
1084}
1085
1086static int
Michael Chan27a005b2007-05-03 13:23:41 -07001087bnx2_5709s_linkup(struct bnx2 *bp)
1088{
1089 u32 val, speed;
1090
1091 bp->link_up = 1;
1092
1093 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_GP_STATUS);
1094 bnx2_read_phy(bp, MII_BNX2_GP_TOP_AN_STATUS1, &val);
1095 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
1096
1097 if ((bp->autoneg & AUTONEG_SPEED) == 0) {
1098 bp->line_speed = bp->req_line_speed;
1099 bp->duplex = bp->req_duplex;
1100 return 0;
1101 }
1102 speed = val & MII_BNX2_GP_TOP_AN_SPEED_MSK;
1103 switch (speed) {
1104 case MII_BNX2_GP_TOP_AN_SPEED_10:
1105 bp->line_speed = SPEED_10;
1106 break;
1107 case MII_BNX2_GP_TOP_AN_SPEED_100:
1108 bp->line_speed = SPEED_100;
1109 break;
1110 case MII_BNX2_GP_TOP_AN_SPEED_1G:
1111 case MII_BNX2_GP_TOP_AN_SPEED_1GKV:
1112 bp->line_speed = SPEED_1000;
1113 break;
1114 case MII_BNX2_GP_TOP_AN_SPEED_2_5G:
1115 bp->line_speed = SPEED_2500;
1116 break;
1117 }
1118 if (val & MII_BNX2_GP_TOP_AN_FD)
1119 bp->duplex = DUPLEX_FULL;
1120 else
1121 bp->duplex = DUPLEX_HALF;
1122 return 0;
1123}
1124
1125static int
Michael Chan5b0c76a2005-11-04 08:45:49 -08001126bnx2_5708s_linkup(struct bnx2 *bp)
1127{
1128 u32 val;
1129
1130 bp->link_up = 1;
1131 bnx2_read_phy(bp, BCM5708S_1000X_STAT1, &val);
1132 switch (val & BCM5708S_1000X_STAT1_SPEED_MASK) {
1133 case BCM5708S_1000X_STAT1_SPEED_10:
1134 bp->line_speed = SPEED_10;
1135 break;
1136 case BCM5708S_1000X_STAT1_SPEED_100:
1137 bp->line_speed = SPEED_100;
1138 break;
1139 case BCM5708S_1000X_STAT1_SPEED_1G:
1140 bp->line_speed = SPEED_1000;
1141 break;
1142 case BCM5708S_1000X_STAT1_SPEED_2G5:
1143 bp->line_speed = SPEED_2500;
1144 break;
1145 }
1146 if (val & BCM5708S_1000X_STAT1_FD)
1147 bp->duplex = DUPLEX_FULL;
1148 else
1149 bp->duplex = DUPLEX_HALF;
1150
1151 return 0;
1152}
1153
1154static int
1155bnx2_5706s_linkup(struct bnx2 *bp)
Michael Chanb6016b72005-05-26 13:03:09 -07001156{
1157 u32 bmcr, local_adv, remote_adv, common;
1158
1159 bp->link_up = 1;
1160 bp->line_speed = SPEED_1000;
1161
Michael Chanca58c3a2007-05-03 13:22:52 -07001162 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chanb6016b72005-05-26 13:03:09 -07001163 if (bmcr & BMCR_FULLDPLX) {
1164 bp->duplex = DUPLEX_FULL;
1165 }
1166 else {
1167 bp->duplex = DUPLEX_HALF;
1168 }
1169
1170 if (!(bmcr & BMCR_ANENABLE)) {
1171 return 0;
1172 }
1173
Michael Chanca58c3a2007-05-03 13:22:52 -07001174 bnx2_read_phy(bp, bp->mii_adv, &local_adv);
1175 bnx2_read_phy(bp, bp->mii_lpa, &remote_adv);
Michael Chanb6016b72005-05-26 13:03:09 -07001176
1177 common = local_adv & remote_adv;
1178 if (common & (ADVERTISE_1000XHALF | ADVERTISE_1000XFULL)) {
1179
1180 if (common & ADVERTISE_1000XFULL) {
1181 bp->duplex = DUPLEX_FULL;
1182 }
1183 else {
1184 bp->duplex = DUPLEX_HALF;
1185 }
1186 }
1187
1188 return 0;
1189}
1190
1191static int
1192bnx2_copper_linkup(struct bnx2 *bp)
1193{
1194 u32 bmcr;
1195
Michael Chanca58c3a2007-05-03 13:22:52 -07001196 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chanb6016b72005-05-26 13:03:09 -07001197 if (bmcr & BMCR_ANENABLE) {
1198 u32 local_adv, remote_adv, common;
1199
1200 bnx2_read_phy(bp, MII_CTRL1000, &local_adv);
1201 bnx2_read_phy(bp, MII_STAT1000, &remote_adv);
1202
1203 common = local_adv & (remote_adv >> 2);
1204 if (common & ADVERTISE_1000FULL) {
1205 bp->line_speed = SPEED_1000;
1206 bp->duplex = DUPLEX_FULL;
1207 }
1208 else if (common & ADVERTISE_1000HALF) {
1209 bp->line_speed = SPEED_1000;
1210 bp->duplex = DUPLEX_HALF;
1211 }
1212 else {
Michael Chanca58c3a2007-05-03 13:22:52 -07001213 bnx2_read_phy(bp, bp->mii_adv, &local_adv);
1214 bnx2_read_phy(bp, bp->mii_lpa, &remote_adv);
Michael Chanb6016b72005-05-26 13:03:09 -07001215
1216 common = local_adv & remote_adv;
1217 if (common & ADVERTISE_100FULL) {
1218 bp->line_speed = SPEED_100;
1219 bp->duplex = DUPLEX_FULL;
1220 }
1221 else if (common & ADVERTISE_100HALF) {
1222 bp->line_speed = SPEED_100;
1223 bp->duplex = DUPLEX_HALF;
1224 }
1225 else if (common & ADVERTISE_10FULL) {
1226 bp->line_speed = SPEED_10;
1227 bp->duplex = DUPLEX_FULL;
1228 }
1229 else if (common & ADVERTISE_10HALF) {
1230 bp->line_speed = SPEED_10;
1231 bp->duplex = DUPLEX_HALF;
1232 }
1233 else {
1234 bp->line_speed = 0;
1235 bp->link_up = 0;
1236 }
1237 }
1238 }
1239 else {
1240 if (bmcr & BMCR_SPEED100) {
1241 bp->line_speed = SPEED_100;
1242 }
1243 else {
1244 bp->line_speed = SPEED_10;
1245 }
1246 if (bmcr & BMCR_FULLDPLX) {
1247 bp->duplex = DUPLEX_FULL;
1248 }
1249 else {
1250 bp->duplex = DUPLEX_HALF;
1251 }
1252 }
1253
1254 return 0;
1255}
1256
Michael Chan83e3fc82008-01-29 21:37:17 -08001257static void
Michael Chanbb4f98a2008-06-19 16:38:19 -07001258bnx2_init_rx_context(struct bnx2 *bp, u32 cid)
Michael Chan83e3fc82008-01-29 21:37:17 -08001259{
Michael Chanbb4f98a2008-06-19 16:38:19 -07001260 u32 val, rx_cid_addr = GET_CID_ADDR(cid);
Michael Chan83e3fc82008-01-29 21:37:17 -08001261
1262 val = BNX2_L2CTX_CTX_TYPE_CTX_BD_CHN_TYPE_VALUE;
1263 val |= BNX2_L2CTX_CTX_TYPE_SIZE_L2;
1264 val |= 0x02 << 8;
1265
1266 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
1267 u32 lo_water, hi_water;
1268
1269 if (bp->flow_ctrl & FLOW_CTRL_TX)
1270 lo_water = BNX2_L2CTX_LO_WATER_MARK_DEFAULT;
1271 else
1272 lo_water = BNX2_L2CTX_LO_WATER_MARK_DIS;
1273 if (lo_water >= bp->rx_ring_size)
1274 lo_water = 0;
1275
Michael Chan57260262010-02-15 19:42:09 +00001276 hi_water = min_t(int, bp->rx_ring_size / 4, lo_water + 16);
Michael Chan83e3fc82008-01-29 21:37:17 -08001277
1278 if (hi_water <= lo_water)
1279 lo_water = 0;
1280
1281 hi_water /= BNX2_L2CTX_HI_WATER_MARK_SCALE;
1282 lo_water /= BNX2_L2CTX_LO_WATER_MARK_SCALE;
1283
1284 if (hi_water > 0xf)
1285 hi_water = 0xf;
1286 else if (hi_water == 0)
1287 lo_water = 0;
1288 val |= lo_water | (hi_water << BNX2_L2CTX_HI_WATER_MARK_SHIFT);
1289 }
1290 bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_CTX_TYPE, val);
1291}
1292
Michael Chanbb4f98a2008-06-19 16:38:19 -07001293static void
1294bnx2_init_all_rx_contexts(struct bnx2 *bp)
1295{
1296 int i;
1297 u32 cid;
1298
1299 for (i = 0, cid = RX_CID; i < bp->num_rx_rings; i++, cid++) {
1300 if (i == 1)
1301 cid = RX_RSS_CID;
1302 bnx2_init_rx_context(bp, cid);
1303 }
1304}
1305
Benjamin Li344478d2008-09-18 16:38:24 -07001306static void
Michael Chanb6016b72005-05-26 13:03:09 -07001307bnx2_set_mac_link(struct bnx2 *bp)
1308{
1309 u32 val;
1310
1311 REG_WR(bp, BNX2_EMAC_TX_LENGTHS, 0x2620);
1312 if (bp->link_up && (bp->line_speed == SPEED_1000) &&
1313 (bp->duplex == DUPLEX_HALF)) {
1314 REG_WR(bp, BNX2_EMAC_TX_LENGTHS, 0x26ff);
1315 }
1316
1317 /* Configure the EMAC mode register. */
1318 val = REG_RD(bp, BNX2_EMAC_MODE);
1319
1320 val &= ~(BNX2_EMAC_MODE_PORT | BNX2_EMAC_MODE_HALF_DUPLEX |
Michael Chan5b0c76a2005-11-04 08:45:49 -08001321 BNX2_EMAC_MODE_MAC_LOOP | BNX2_EMAC_MODE_FORCE_LINK |
Michael Chan59b47d82006-11-19 14:10:45 -08001322 BNX2_EMAC_MODE_25G_MODE);
Michael Chanb6016b72005-05-26 13:03:09 -07001323
1324 if (bp->link_up) {
Michael Chan5b0c76a2005-11-04 08:45:49 -08001325 switch (bp->line_speed) {
1326 case SPEED_10:
Michael Chan59b47d82006-11-19 14:10:45 -08001327 if (CHIP_NUM(bp) != CHIP_NUM_5706) {
1328 val |= BNX2_EMAC_MODE_PORT_MII_10M;
Michael Chan5b0c76a2005-11-04 08:45:49 -08001329 break;
1330 }
1331 /* fall through */
1332 case SPEED_100:
1333 val |= BNX2_EMAC_MODE_PORT_MII;
1334 break;
1335 case SPEED_2500:
Michael Chan59b47d82006-11-19 14:10:45 -08001336 val |= BNX2_EMAC_MODE_25G_MODE;
Michael Chan5b0c76a2005-11-04 08:45:49 -08001337 /* fall through */
1338 case SPEED_1000:
1339 val |= BNX2_EMAC_MODE_PORT_GMII;
1340 break;
1341 }
Michael Chanb6016b72005-05-26 13:03:09 -07001342 }
1343 else {
1344 val |= BNX2_EMAC_MODE_PORT_GMII;
1345 }
1346
1347 /* Set the MAC to operate in the appropriate duplex mode. */
1348 if (bp->duplex == DUPLEX_HALF)
1349 val |= BNX2_EMAC_MODE_HALF_DUPLEX;
1350 REG_WR(bp, BNX2_EMAC_MODE, val);
1351
1352 /* Enable/disable rx PAUSE. */
1353 bp->rx_mode &= ~BNX2_EMAC_RX_MODE_FLOW_EN;
1354
1355 if (bp->flow_ctrl & FLOW_CTRL_RX)
1356 bp->rx_mode |= BNX2_EMAC_RX_MODE_FLOW_EN;
1357 REG_WR(bp, BNX2_EMAC_RX_MODE, bp->rx_mode);
1358
1359 /* Enable/disable tx PAUSE. */
1360 val = REG_RD(bp, BNX2_EMAC_TX_MODE);
1361 val &= ~BNX2_EMAC_TX_MODE_FLOW_EN;
1362
1363 if (bp->flow_ctrl & FLOW_CTRL_TX)
1364 val |= BNX2_EMAC_TX_MODE_FLOW_EN;
1365 REG_WR(bp, BNX2_EMAC_TX_MODE, val);
1366
1367 /* Acknowledge the interrupt. */
1368 REG_WR(bp, BNX2_EMAC_STATUS, BNX2_EMAC_STATUS_LINK_CHANGE);
1369
Michael Chan83e3fc82008-01-29 21:37:17 -08001370 if (CHIP_NUM(bp) == CHIP_NUM_5709)
Michael Chanbb4f98a2008-06-19 16:38:19 -07001371 bnx2_init_all_rx_contexts(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07001372}
1373
Michael Chan27a005b2007-05-03 13:23:41 -07001374static void
1375bnx2_enable_bmsr1(struct bnx2 *bp)
1376{
Michael Chan583c28e2008-01-21 19:51:35 -08001377 if ((bp->phy_flags & BNX2_PHY_FLAG_SERDES) &&
Michael Chan27a005b2007-05-03 13:23:41 -07001378 (CHIP_NUM(bp) == CHIP_NUM_5709))
1379 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
1380 MII_BNX2_BLK_ADDR_GP_STATUS);
1381}
1382
1383static void
1384bnx2_disable_bmsr1(struct bnx2 *bp)
1385{
Michael Chan583c28e2008-01-21 19:51:35 -08001386 if ((bp->phy_flags & BNX2_PHY_FLAG_SERDES) &&
Michael Chan27a005b2007-05-03 13:23:41 -07001387 (CHIP_NUM(bp) == CHIP_NUM_5709))
1388 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
1389 MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
1390}
1391
Michael Chanb6016b72005-05-26 13:03:09 -07001392static int
Michael Chan605a9e22007-05-03 13:23:13 -07001393bnx2_test_and_enable_2g5(struct bnx2 *bp)
1394{
1395 u32 up1;
1396 int ret = 1;
1397
Michael Chan583c28e2008-01-21 19:51:35 -08001398 if (!(bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE))
Michael Chan605a9e22007-05-03 13:23:13 -07001399 return 0;
1400
1401 if (bp->autoneg & AUTONEG_SPEED)
1402 bp->advertising |= ADVERTISED_2500baseX_Full;
1403
Michael Chan27a005b2007-05-03 13:23:41 -07001404 if (CHIP_NUM(bp) == CHIP_NUM_5709)
1405 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_OVER1G);
1406
Michael Chan605a9e22007-05-03 13:23:13 -07001407 bnx2_read_phy(bp, bp->mii_up1, &up1);
1408 if (!(up1 & BCM5708S_UP1_2G5)) {
1409 up1 |= BCM5708S_UP1_2G5;
1410 bnx2_write_phy(bp, bp->mii_up1, up1);
1411 ret = 0;
1412 }
1413
Michael Chan27a005b2007-05-03 13:23:41 -07001414 if (CHIP_NUM(bp) == CHIP_NUM_5709)
1415 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
1416 MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
1417
Michael Chan605a9e22007-05-03 13:23:13 -07001418 return ret;
1419}
1420
1421static int
1422bnx2_test_and_disable_2g5(struct bnx2 *bp)
1423{
1424 u32 up1;
1425 int ret = 0;
1426
Michael Chan583c28e2008-01-21 19:51:35 -08001427 if (!(bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE))
Michael Chan605a9e22007-05-03 13:23:13 -07001428 return 0;
1429
Michael Chan27a005b2007-05-03 13:23:41 -07001430 if (CHIP_NUM(bp) == CHIP_NUM_5709)
1431 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_OVER1G);
1432
Michael Chan605a9e22007-05-03 13:23:13 -07001433 bnx2_read_phy(bp, bp->mii_up1, &up1);
1434 if (up1 & BCM5708S_UP1_2G5) {
1435 up1 &= ~BCM5708S_UP1_2G5;
1436 bnx2_write_phy(bp, bp->mii_up1, up1);
1437 ret = 1;
1438 }
1439
Michael Chan27a005b2007-05-03 13:23:41 -07001440 if (CHIP_NUM(bp) == CHIP_NUM_5709)
1441 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
1442 MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
1443
Michael Chan605a9e22007-05-03 13:23:13 -07001444 return ret;
1445}
1446
1447static void
1448bnx2_enable_forced_2g5(struct bnx2 *bp)
1449{
1450 u32 bmcr;
1451
Michael Chan583c28e2008-01-21 19:51:35 -08001452 if (!(bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE))
Michael Chan605a9e22007-05-03 13:23:13 -07001453 return;
1454
Michael Chan27a005b2007-05-03 13:23:41 -07001455 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
1456 u32 val;
1457
1458 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
1459 MII_BNX2_BLK_ADDR_SERDES_DIG);
1460 bnx2_read_phy(bp, MII_BNX2_SERDES_DIG_MISC1, &val);
1461 val &= ~MII_BNX2_SD_MISC1_FORCE_MSK;
1462 val |= MII_BNX2_SD_MISC1_FORCE | MII_BNX2_SD_MISC1_FORCE_2_5G;
1463 bnx2_write_phy(bp, MII_BNX2_SERDES_DIG_MISC1, val);
1464
1465 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
1466 MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
1467 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
1468
1469 } else if (CHIP_NUM(bp) == CHIP_NUM_5708) {
Michael Chan605a9e22007-05-03 13:23:13 -07001470 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
1471 bmcr |= BCM5708S_BMCR_FORCE_2500;
Eric Dumazetc70798572009-11-02 23:17:42 +00001472 } else {
1473 return;
Michael Chan605a9e22007-05-03 13:23:13 -07001474 }
1475
1476 if (bp->autoneg & AUTONEG_SPEED) {
1477 bmcr &= ~BMCR_ANENABLE;
1478 if (bp->req_duplex == DUPLEX_FULL)
1479 bmcr |= BMCR_FULLDPLX;
1480 }
1481 bnx2_write_phy(bp, bp->mii_bmcr, bmcr);
1482}
1483
1484static void
1485bnx2_disable_forced_2g5(struct bnx2 *bp)
1486{
1487 u32 bmcr;
1488
Michael Chan583c28e2008-01-21 19:51:35 -08001489 if (!(bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE))
Michael Chan605a9e22007-05-03 13:23:13 -07001490 return;
1491
Michael Chan27a005b2007-05-03 13:23:41 -07001492 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
1493 u32 val;
1494
1495 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
1496 MII_BNX2_BLK_ADDR_SERDES_DIG);
1497 bnx2_read_phy(bp, MII_BNX2_SERDES_DIG_MISC1, &val);
1498 val &= ~MII_BNX2_SD_MISC1_FORCE;
1499 bnx2_write_phy(bp, MII_BNX2_SERDES_DIG_MISC1, val);
1500
1501 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
1502 MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
1503 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
1504
1505 } else if (CHIP_NUM(bp) == CHIP_NUM_5708) {
Michael Chan605a9e22007-05-03 13:23:13 -07001506 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
1507 bmcr &= ~BCM5708S_BMCR_FORCE_2500;
Eric Dumazetc70798572009-11-02 23:17:42 +00001508 } else {
1509 return;
Michael Chan605a9e22007-05-03 13:23:13 -07001510 }
1511
1512 if (bp->autoneg & AUTONEG_SPEED)
1513 bmcr |= BMCR_SPEED1000 | BMCR_ANENABLE | BMCR_ANRESTART;
1514 bnx2_write_phy(bp, bp->mii_bmcr, bmcr);
1515}
1516
Michael Chanb2fadea2008-01-21 17:07:06 -08001517static void
1518bnx2_5706s_force_link_dn(struct bnx2 *bp, int start)
1519{
1520 u32 val;
1521
1522 bnx2_write_phy(bp, MII_BNX2_DSP_ADDRESS, MII_EXPAND_SERDES_CTL);
1523 bnx2_read_phy(bp, MII_BNX2_DSP_RW_PORT, &val);
1524 if (start)
1525 bnx2_write_phy(bp, MII_BNX2_DSP_RW_PORT, val & 0xff0f);
1526 else
1527 bnx2_write_phy(bp, MII_BNX2_DSP_RW_PORT, val | 0xc0);
1528}
1529
Michael Chan605a9e22007-05-03 13:23:13 -07001530static int
Michael Chanb6016b72005-05-26 13:03:09 -07001531bnx2_set_link(struct bnx2 *bp)
1532{
1533 u32 bmsr;
1534 u8 link_up;
1535
Michael Chan80be4432006-11-19 14:07:28 -08001536 if (bp->loopback == MAC_LOOPBACK || bp->loopback == PHY_LOOPBACK) {
Michael Chanb6016b72005-05-26 13:03:09 -07001537 bp->link_up = 1;
1538 return 0;
1539 }
1540
Michael Chan583c28e2008-01-21 19:51:35 -08001541 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
Michael Chan0d8a6572007-07-07 22:49:43 -07001542 return 0;
1543
Michael Chanb6016b72005-05-26 13:03:09 -07001544 link_up = bp->link_up;
1545
Michael Chan27a005b2007-05-03 13:23:41 -07001546 bnx2_enable_bmsr1(bp);
1547 bnx2_read_phy(bp, bp->mii_bmsr1, &bmsr);
1548 bnx2_read_phy(bp, bp->mii_bmsr1, &bmsr);
1549 bnx2_disable_bmsr1(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07001550
Michael Chan583c28e2008-01-21 19:51:35 -08001551 if ((bp->phy_flags & BNX2_PHY_FLAG_SERDES) &&
Michael Chanb6016b72005-05-26 13:03:09 -07001552 (CHIP_NUM(bp) == CHIP_NUM_5706)) {
Michael Chana2724e22008-02-23 19:47:44 -08001553 u32 val, an_dbg;
Michael Chanb6016b72005-05-26 13:03:09 -07001554
Michael Chan583c28e2008-01-21 19:51:35 -08001555 if (bp->phy_flags & BNX2_PHY_FLAG_FORCED_DOWN) {
Michael Chanb2fadea2008-01-21 17:07:06 -08001556 bnx2_5706s_force_link_dn(bp, 0);
Michael Chan583c28e2008-01-21 19:51:35 -08001557 bp->phy_flags &= ~BNX2_PHY_FLAG_FORCED_DOWN;
Michael Chanb2fadea2008-01-21 17:07:06 -08001558 }
Michael Chanb6016b72005-05-26 13:03:09 -07001559 val = REG_RD(bp, BNX2_EMAC_STATUS);
Michael Chana2724e22008-02-23 19:47:44 -08001560
1561 bnx2_write_phy(bp, MII_BNX2_MISC_SHADOW, MISC_SHDW_AN_DBG);
1562 bnx2_read_phy(bp, MII_BNX2_MISC_SHADOW, &an_dbg);
1563 bnx2_read_phy(bp, MII_BNX2_MISC_SHADOW, &an_dbg);
1564
1565 if ((val & BNX2_EMAC_STATUS_LINK) &&
1566 !(an_dbg & MISC_SHDW_AN_DBG_NOSYNC))
Michael Chanb6016b72005-05-26 13:03:09 -07001567 bmsr |= BMSR_LSTATUS;
1568 else
1569 bmsr &= ~BMSR_LSTATUS;
1570 }
1571
1572 if (bmsr & BMSR_LSTATUS) {
1573 bp->link_up = 1;
1574
Michael Chan583c28e2008-01-21 19:51:35 -08001575 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Michael Chan5b0c76a2005-11-04 08:45:49 -08001576 if (CHIP_NUM(bp) == CHIP_NUM_5706)
1577 bnx2_5706s_linkup(bp);
1578 else if (CHIP_NUM(bp) == CHIP_NUM_5708)
1579 bnx2_5708s_linkup(bp);
Michael Chan27a005b2007-05-03 13:23:41 -07001580 else if (CHIP_NUM(bp) == CHIP_NUM_5709)
1581 bnx2_5709s_linkup(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07001582 }
1583 else {
1584 bnx2_copper_linkup(bp);
1585 }
1586 bnx2_resolve_flow_ctrl(bp);
1587 }
1588 else {
Michael Chan583c28e2008-01-21 19:51:35 -08001589 if ((bp->phy_flags & BNX2_PHY_FLAG_SERDES) &&
Michael Chan605a9e22007-05-03 13:23:13 -07001590 (bp->autoneg & AUTONEG_SPEED))
1591 bnx2_disable_forced_2g5(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07001592
Michael Chan583c28e2008-01-21 19:51:35 -08001593 if (bp->phy_flags & BNX2_PHY_FLAG_PARALLEL_DETECT) {
Michael Chanb2fadea2008-01-21 17:07:06 -08001594 u32 bmcr;
1595
1596 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
1597 bmcr |= BMCR_ANENABLE;
1598 bnx2_write_phy(bp, bp->mii_bmcr, bmcr);
1599
Michael Chan583c28e2008-01-21 19:51:35 -08001600 bp->phy_flags &= ~BNX2_PHY_FLAG_PARALLEL_DETECT;
Michael Chanb2fadea2008-01-21 17:07:06 -08001601 }
Michael Chanb6016b72005-05-26 13:03:09 -07001602 bp->link_up = 0;
1603 }
1604
1605 if (bp->link_up != link_up) {
1606 bnx2_report_link(bp);
1607 }
1608
1609 bnx2_set_mac_link(bp);
1610
1611 return 0;
1612}
1613
1614static int
1615bnx2_reset_phy(struct bnx2 *bp)
1616{
1617 int i;
1618 u32 reg;
1619
Michael Chanca58c3a2007-05-03 13:22:52 -07001620 bnx2_write_phy(bp, bp->mii_bmcr, BMCR_RESET);
Michael Chanb6016b72005-05-26 13:03:09 -07001621
1622#define PHY_RESET_MAX_WAIT 100
1623 for (i = 0; i < PHY_RESET_MAX_WAIT; i++) {
1624 udelay(10);
1625
Michael Chanca58c3a2007-05-03 13:22:52 -07001626 bnx2_read_phy(bp, bp->mii_bmcr, &reg);
Michael Chanb6016b72005-05-26 13:03:09 -07001627 if (!(reg & BMCR_RESET)) {
1628 udelay(20);
1629 break;
1630 }
1631 }
1632 if (i == PHY_RESET_MAX_WAIT) {
1633 return -EBUSY;
1634 }
1635 return 0;
1636}
1637
1638static u32
1639bnx2_phy_get_pause_adv(struct bnx2 *bp)
1640{
1641 u32 adv = 0;
1642
1643 if ((bp->req_flow_ctrl & (FLOW_CTRL_RX | FLOW_CTRL_TX)) ==
1644 (FLOW_CTRL_RX | FLOW_CTRL_TX)) {
1645
Michael Chan583c28e2008-01-21 19:51:35 -08001646 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Michael Chanb6016b72005-05-26 13:03:09 -07001647 adv = ADVERTISE_1000XPAUSE;
1648 }
1649 else {
1650 adv = ADVERTISE_PAUSE_CAP;
1651 }
1652 }
1653 else if (bp->req_flow_ctrl & FLOW_CTRL_TX) {
Michael Chan583c28e2008-01-21 19:51:35 -08001654 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Michael Chanb6016b72005-05-26 13:03:09 -07001655 adv = ADVERTISE_1000XPSE_ASYM;
1656 }
1657 else {
1658 adv = ADVERTISE_PAUSE_ASYM;
1659 }
1660 }
1661 else if (bp->req_flow_ctrl & FLOW_CTRL_RX) {
Michael Chan583c28e2008-01-21 19:51:35 -08001662 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Michael Chanb6016b72005-05-26 13:03:09 -07001663 adv = ADVERTISE_1000XPAUSE | ADVERTISE_1000XPSE_ASYM;
1664 }
1665 else {
1666 adv = ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM;
1667 }
1668 }
1669 return adv;
1670}
1671
Michael Chana2f13892008-07-14 22:38:23 -07001672static int bnx2_fw_sync(struct bnx2 *, u32, int, int);
Michael Chan0d8a6572007-07-07 22:49:43 -07001673
Michael Chanb6016b72005-05-26 13:03:09 -07001674static int
Michael Chan0d8a6572007-07-07 22:49:43 -07001675bnx2_setup_remote_phy(struct bnx2 *bp, u8 port)
Harvey Harrison52d07b12009-01-19 17:27:06 -08001676__releases(&bp->phy_lock)
1677__acquires(&bp->phy_lock)
Michael Chan0d8a6572007-07-07 22:49:43 -07001678{
1679 u32 speed_arg = 0, pause_adv;
1680
1681 pause_adv = bnx2_phy_get_pause_adv(bp);
1682
1683 if (bp->autoneg & AUTONEG_SPEED) {
1684 speed_arg |= BNX2_NETLINK_SET_LINK_ENABLE_AUTONEG;
1685 if (bp->advertising & ADVERTISED_10baseT_Half)
1686 speed_arg |= BNX2_NETLINK_SET_LINK_SPEED_10HALF;
1687 if (bp->advertising & ADVERTISED_10baseT_Full)
1688 speed_arg |= BNX2_NETLINK_SET_LINK_SPEED_10FULL;
1689 if (bp->advertising & ADVERTISED_100baseT_Half)
1690 speed_arg |= BNX2_NETLINK_SET_LINK_SPEED_100HALF;
1691 if (bp->advertising & ADVERTISED_100baseT_Full)
1692 speed_arg |= BNX2_NETLINK_SET_LINK_SPEED_100FULL;
1693 if (bp->advertising & ADVERTISED_1000baseT_Full)
1694 speed_arg |= BNX2_NETLINK_SET_LINK_SPEED_1GFULL;
1695 if (bp->advertising & ADVERTISED_2500baseX_Full)
1696 speed_arg |= BNX2_NETLINK_SET_LINK_SPEED_2G5FULL;
1697 } else {
1698 if (bp->req_line_speed == SPEED_2500)
1699 speed_arg = BNX2_NETLINK_SET_LINK_SPEED_2G5FULL;
1700 else if (bp->req_line_speed == SPEED_1000)
1701 speed_arg = BNX2_NETLINK_SET_LINK_SPEED_1GFULL;
1702 else if (bp->req_line_speed == SPEED_100) {
1703 if (bp->req_duplex == DUPLEX_FULL)
1704 speed_arg = BNX2_NETLINK_SET_LINK_SPEED_100FULL;
1705 else
1706 speed_arg = BNX2_NETLINK_SET_LINK_SPEED_100HALF;
1707 } else if (bp->req_line_speed == SPEED_10) {
1708 if (bp->req_duplex == DUPLEX_FULL)
1709 speed_arg = BNX2_NETLINK_SET_LINK_SPEED_10FULL;
1710 else
1711 speed_arg = BNX2_NETLINK_SET_LINK_SPEED_10HALF;
1712 }
1713 }
1714
1715 if (pause_adv & (ADVERTISE_1000XPAUSE | ADVERTISE_PAUSE_CAP))
1716 speed_arg |= BNX2_NETLINK_SET_LINK_FC_SYM_PAUSE;
Michael Chanc26736e2008-01-31 17:07:21 -08001717 if (pause_adv & (ADVERTISE_1000XPSE_ASYM | ADVERTISE_PAUSE_ASYM))
Michael Chan0d8a6572007-07-07 22:49:43 -07001718 speed_arg |= BNX2_NETLINK_SET_LINK_FC_ASYM_PAUSE;
1719
1720 if (port == PORT_TP)
1721 speed_arg |= BNX2_NETLINK_SET_LINK_PHY_APP_REMOTE |
1722 BNX2_NETLINK_SET_LINK_ETH_AT_WIRESPEED;
1723
Michael Chan2726d6e2008-01-29 21:35:05 -08001724 bnx2_shmem_wr(bp, BNX2_DRV_MB_ARG0, speed_arg);
Michael Chan0d8a6572007-07-07 22:49:43 -07001725
1726 spin_unlock_bh(&bp->phy_lock);
Michael Chana2f13892008-07-14 22:38:23 -07001727 bnx2_fw_sync(bp, BNX2_DRV_MSG_CODE_CMD_SET_LINK, 1, 0);
Michael Chan0d8a6572007-07-07 22:49:43 -07001728 spin_lock_bh(&bp->phy_lock);
1729
1730 return 0;
1731}
1732
1733static int
1734bnx2_setup_serdes_phy(struct bnx2 *bp, u8 port)
Harvey Harrison52d07b12009-01-19 17:27:06 -08001735__releases(&bp->phy_lock)
1736__acquires(&bp->phy_lock)
Michael Chanb6016b72005-05-26 13:03:09 -07001737{
Michael Chan605a9e22007-05-03 13:23:13 -07001738 u32 adv, bmcr;
Michael Chanb6016b72005-05-26 13:03:09 -07001739 u32 new_adv = 0;
1740
Michael Chan583c28e2008-01-21 19:51:35 -08001741 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
Michael Chan0d8a6572007-07-07 22:49:43 -07001742 return (bnx2_setup_remote_phy(bp, port));
1743
Michael Chanb6016b72005-05-26 13:03:09 -07001744 if (!(bp->autoneg & AUTONEG_SPEED)) {
1745 u32 new_bmcr;
Michael Chan5b0c76a2005-11-04 08:45:49 -08001746 int force_link_down = 0;
1747
Michael Chan605a9e22007-05-03 13:23:13 -07001748 if (bp->req_line_speed == SPEED_2500) {
1749 if (!bnx2_test_and_enable_2g5(bp))
1750 force_link_down = 1;
1751 } else if (bp->req_line_speed == SPEED_1000) {
1752 if (bnx2_test_and_disable_2g5(bp))
1753 force_link_down = 1;
1754 }
Michael Chanca58c3a2007-05-03 13:22:52 -07001755 bnx2_read_phy(bp, bp->mii_adv, &adv);
Michael Chan80be4432006-11-19 14:07:28 -08001756 adv &= ~(ADVERTISE_1000XFULL | ADVERTISE_1000XHALF);
1757
Michael Chanca58c3a2007-05-03 13:22:52 -07001758 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chan605a9e22007-05-03 13:23:13 -07001759 new_bmcr = bmcr & ~BMCR_ANENABLE;
Michael Chan80be4432006-11-19 14:07:28 -08001760 new_bmcr |= BMCR_SPEED1000;
Michael Chan605a9e22007-05-03 13:23:13 -07001761
Michael Chan27a005b2007-05-03 13:23:41 -07001762 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
1763 if (bp->req_line_speed == SPEED_2500)
1764 bnx2_enable_forced_2g5(bp);
1765 else if (bp->req_line_speed == SPEED_1000) {
1766 bnx2_disable_forced_2g5(bp);
1767 new_bmcr &= ~0x2000;
1768 }
1769
1770 } else if (CHIP_NUM(bp) == CHIP_NUM_5708) {
Michael Chan605a9e22007-05-03 13:23:13 -07001771 if (bp->req_line_speed == SPEED_2500)
1772 new_bmcr |= BCM5708S_BMCR_FORCE_2500;
1773 else
1774 new_bmcr = bmcr & ~BCM5708S_BMCR_FORCE_2500;
Michael Chan5b0c76a2005-11-04 08:45:49 -08001775 }
1776
Michael Chanb6016b72005-05-26 13:03:09 -07001777 if (bp->req_duplex == DUPLEX_FULL) {
Michael Chan5b0c76a2005-11-04 08:45:49 -08001778 adv |= ADVERTISE_1000XFULL;
Michael Chanb6016b72005-05-26 13:03:09 -07001779 new_bmcr |= BMCR_FULLDPLX;
1780 }
1781 else {
Michael Chan5b0c76a2005-11-04 08:45:49 -08001782 adv |= ADVERTISE_1000XHALF;
Michael Chanb6016b72005-05-26 13:03:09 -07001783 new_bmcr &= ~BMCR_FULLDPLX;
1784 }
Michael Chan5b0c76a2005-11-04 08:45:49 -08001785 if ((new_bmcr != bmcr) || (force_link_down)) {
Michael Chanb6016b72005-05-26 13:03:09 -07001786 /* Force a link down visible on the other side */
1787 if (bp->link_up) {
Michael Chanca58c3a2007-05-03 13:22:52 -07001788 bnx2_write_phy(bp, bp->mii_adv, adv &
Michael Chan5b0c76a2005-11-04 08:45:49 -08001789 ~(ADVERTISE_1000XFULL |
1790 ADVERTISE_1000XHALF));
Michael Chanca58c3a2007-05-03 13:22:52 -07001791 bnx2_write_phy(bp, bp->mii_bmcr, bmcr |
Michael Chanb6016b72005-05-26 13:03:09 -07001792 BMCR_ANRESTART | BMCR_ANENABLE);
1793
1794 bp->link_up = 0;
1795 netif_carrier_off(bp->dev);
Michael Chanca58c3a2007-05-03 13:22:52 -07001796 bnx2_write_phy(bp, bp->mii_bmcr, new_bmcr);
Michael Chan80be4432006-11-19 14:07:28 -08001797 bnx2_report_link(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07001798 }
Michael Chanca58c3a2007-05-03 13:22:52 -07001799 bnx2_write_phy(bp, bp->mii_adv, adv);
1800 bnx2_write_phy(bp, bp->mii_bmcr, new_bmcr);
Michael Chan605a9e22007-05-03 13:23:13 -07001801 } else {
1802 bnx2_resolve_flow_ctrl(bp);
1803 bnx2_set_mac_link(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07001804 }
1805 return 0;
1806 }
1807
Michael Chan605a9e22007-05-03 13:23:13 -07001808 bnx2_test_and_enable_2g5(bp);
Michael Chan5b0c76a2005-11-04 08:45:49 -08001809
Michael Chanb6016b72005-05-26 13:03:09 -07001810 if (bp->advertising & ADVERTISED_1000baseT_Full)
1811 new_adv |= ADVERTISE_1000XFULL;
1812
1813 new_adv |= bnx2_phy_get_pause_adv(bp);
1814
Michael Chanca58c3a2007-05-03 13:22:52 -07001815 bnx2_read_phy(bp, bp->mii_adv, &adv);
1816 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chanb6016b72005-05-26 13:03:09 -07001817
1818 bp->serdes_an_pending = 0;
1819 if ((adv != new_adv) || ((bmcr & BMCR_ANENABLE) == 0)) {
1820 /* Force a link down visible on the other side */
1821 if (bp->link_up) {
Michael Chanca58c3a2007-05-03 13:22:52 -07001822 bnx2_write_phy(bp, bp->mii_bmcr, BMCR_LOOPBACK);
Michael Chan80be4432006-11-19 14:07:28 -08001823 spin_unlock_bh(&bp->phy_lock);
1824 msleep(20);
1825 spin_lock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07001826 }
1827
Michael Chanca58c3a2007-05-03 13:22:52 -07001828 bnx2_write_phy(bp, bp->mii_adv, new_adv);
1829 bnx2_write_phy(bp, bp->mii_bmcr, bmcr | BMCR_ANRESTART |
Michael Chanb6016b72005-05-26 13:03:09 -07001830 BMCR_ANENABLE);
Michael Chanf8dd0642006-11-19 14:08:29 -08001831 /* Speed up link-up time when the link partner
1832 * does not autonegotiate which is very common
1833 * in blade servers. Some blade servers use
1834 * IPMI for kerboard input and it's important
1835 * to minimize link disruptions. Autoneg. involves
1836 * exchanging base pages plus 3 next pages and
1837 * normally completes in about 120 msec.
1838 */
Michael Chan40105c02008-11-12 16:02:45 -08001839 bp->current_interval = BNX2_SERDES_AN_TIMEOUT;
Michael Chanf8dd0642006-11-19 14:08:29 -08001840 bp->serdes_an_pending = 1;
1841 mod_timer(&bp->timer, jiffies + bp->current_interval);
Michael Chan605a9e22007-05-03 13:23:13 -07001842 } else {
1843 bnx2_resolve_flow_ctrl(bp);
1844 bnx2_set_mac_link(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07001845 }
1846
1847 return 0;
1848}
1849
1850#define ETHTOOL_ALL_FIBRE_SPEED \
Michael Chan583c28e2008-01-21 19:51:35 -08001851 (bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE) ? \
Michael Chandeaf3912007-07-07 22:48:00 -07001852 (ADVERTISED_2500baseX_Full | ADVERTISED_1000baseT_Full) :\
1853 (ADVERTISED_1000baseT_Full)
Michael Chanb6016b72005-05-26 13:03:09 -07001854
1855#define ETHTOOL_ALL_COPPER_SPEED \
1856 (ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full | \
1857 ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full | \
1858 ADVERTISED_1000baseT_Full)
1859
1860#define PHY_ALL_10_100_SPEED (ADVERTISE_10HALF | ADVERTISE_10FULL | \
1861 ADVERTISE_100HALF | ADVERTISE_100FULL | ADVERTISE_CSMA)
Jeff Garzik6aa20a22006-09-13 13:24:59 -04001862
Michael Chanb6016b72005-05-26 13:03:09 -07001863#define PHY_ALL_1000_SPEED (ADVERTISE_1000HALF | ADVERTISE_1000FULL)
1864
Michael Chandeaf3912007-07-07 22:48:00 -07001865static void
Michael Chan0d8a6572007-07-07 22:49:43 -07001866bnx2_set_default_remote_link(struct bnx2 *bp)
1867{
1868 u32 link;
1869
1870 if (bp->phy_port == PORT_TP)
Michael Chan2726d6e2008-01-29 21:35:05 -08001871 link = bnx2_shmem_rd(bp, BNX2_RPHY_COPPER_LINK);
Michael Chan0d8a6572007-07-07 22:49:43 -07001872 else
Michael Chan2726d6e2008-01-29 21:35:05 -08001873 link = bnx2_shmem_rd(bp, BNX2_RPHY_SERDES_LINK);
Michael Chan0d8a6572007-07-07 22:49:43 -07001874
1875 if (link & BNX2_NETLINK_SET_LINK_ENABLE_AUTONEG) {
1876 bp->req_line_speed = 0;
1877 bp->autoneg |= AUTONEG_SPEED;
1878 bp->advertising = ADVERTISED_Autoneg;
1879 if (link & BNX2_NETLINK_SET_LINK_SPEED_10HALF)
1880 bp->advertising |= ADVERTISED_10baseT_Half;
1881 if (link & BNX2_NETLINK_SET_LINK_SPEED_10FULL)
1882 bp->advertising |= ADVERTISED_10baseT_Full;
1883 if (link & BNX2_NETLINK_SET_LINK_SPEED_100HALF)
1884 bp->advertising |= ADVERTISED_100baseT_Half;
1885 if (link & BNX2_NETLINK_SET_LINK_SPEED_100FULL)
1886 bp->advertising |= ADVERTISED_100baseT_Full;
1887 if (link & BNX2_NETLINK_SET_LINK_SPEED_1GFULL)
1888 bp->advertising |= ADVERTISED_1000baseT_Full;
1889 if (link & BNX2_NETLINK_SET_LINK_SPEED_2G5FULL)
1890 bp->advertising |= ADVERTISED_2500baseX_Full;
1891 } else {
1892 bp->autoneg = 0;
1893 bp->advertising = 0;
1894 bp->req_duplex = DUPLEX_FULL;
1895 if (link & BNX2_NETLINK_SET_LINK_SPEED_10) {
1896 bp->req_line_speed = SPEED_10;
1897 if (link & BNX2_NETLINK_SET_LINK_SPEED_10HALF)
1898 bp->req_duplex = DUPLEX_HALF;
1899 }
1900 if (link & BNX2_NETLINK_SET_LINK_SPEED_100) {
1901 bp->req_line_speed = SPEED_100;
1902 if (link & BNX2_NETLINK_SET_LINK_SPEED_100HALF)
1903 bp->req_duplex = DUPLEX_HALF;
1904 }
1905 if (link & BNX2_NETLINK_SET_LINK_SPEED_1GFULL)
1906 bp->req_line_speed = SPEED_1000;
1907 if (link & BNX2_NETLINK_SET_LINK_SPEED_2G5FULL)
1908 bp->req_line_speed = SPEED_2500;
1909 }
1910}
1911
1912static void
Michael Chandeaf3912007-07-07 22:48:00 -07001913bnx2_set_default_link(struct bnx2 *bp)
1914{
Harvey Harrisonab598592008-05-01 02:47:38 -07001915 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP) {
1916 bnx2_set_default_remote_link(bp);
1917 return;
1918 }
Michael Chan0d8a6572007-07-07 22:49:43 -07001919
Michael Chandeaf3912007-07-07 22:48:00 -07001920 bp->autoneg = AUTONEG_SPEED | AUTONEG_FLOW_CTRL;
1921 bp->req_line_speed = 0;
Michael Chan583c28e2008-01-21 19:51:35 -08001922 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Michael Chandeaf3912007-07-07 22:48:00 -07001923 u32 reg;
1924
1925 bp->advertising = ETHTOOL_ALL_FIBRE_SPEED | ADVERTISED_Autoneg;
1926
Michael Chan2726d6e2008-01-29 21:35:05 -08001927 reg = bnx2_shmem_rd(bp, BNX2_PORT_HW_CFG_CONFIG);
Michael Chandeaf3912007-07-07 22:48:00 -07001928 reg &= BNX2_PORT_HW_CFG_CFG_DFLT_LINK_MASK;
1929 if (reg == BNX2_PORT_HW_CFG_CFG_DFLT_LINK_1G) {
1930 bp->autoneg = 0;
1931 bp->req_line_speed = bp->line_speed = SPEED_1000;
1932 bp->req_duplex = DUPLEX_FULL;
1933 }
1934 } else
1935 bp->advertising = ETHTOOL_ALL_COPPER_SPEED | ADVERTISED_Autoneg;
1936}
1937
Michael Chan0d8a6572007-07-07 22:49:43 -07001938static void
Michael Chandf149d72007-07-07 22:51:36 -07001939bnx2_send_heart_beat(struct bnx2 *bp)
1940{
1941 u32 msg;
1942 u32 addr;
1943
1944 spin_lock(&bp->indirect_lock);
1945 msg = (u32) (++bp->fw_drv_pulse_wr_seq & BNX2_DRV_PULSE_SEQ_MASK);
1946 addr = bp->shmem_base + BNX2_DRV_PULSE_MB;
1947 REG_WR(bp, BNX2_PCICFG_REG_WINDOW_ADDRESS, addr);
1948 REG_WR(bp, BNX2_PCICFG_REG_WINDOW, msg);
1949 spin_unlock(&bp->indirect_lock);
1950}
1951
1952static void
Michael Chan0d8a6572007-07-07 22:49:43 -07001953bnx2_remote_phy_event(struct bnx2 *bp)
1954{
1955 u32 msg;
1956 u8 link_up = bp->link_up;
1957 u8 old_port;
1958
Michael Chan2726d6e2008-01-29 21:35:05 -08001959 msg = bnx2_shmem_rd(bp, BNX2_LINK_STATUS);
Michael Chan0d8a6572007-07-07 22:49:43 -07001960
Michael Chandf149d72007-07-07 22:51:36 -07001961 if (msg & BNX2_LINK_STATUS_HEART_BEAT_EXPIRED)
1962 bnx2_send_heart_beat(bp);
1963
1964 msg &= ~BNX2_LINK_STATUS_HEART_BEAT_EXPIRED;
1965
Michael Chan0d8a6572007-07-07 22:49:43 -07001966 if ((msg & BNX2_LINK_STATUS_LINK_UP) == BNX2_LINK_STATUS_LINK_DOWN)
1967 bp->link_up = 0;
1968 else {
1969 u32 speed;
1970
1971 bp->link_up = 1;
1972 speed = msg & BNX2_LINK_STATUS_SPEED_MASK;
1973 bp->duplex = DUPLEX_FULL;
1974 switch (speed) {
1975 case BNX2_LINK_STATUS_10HALF:
1976 bp->duplex = DUPLEX_HALF;
1977 case BNX2_LINK_STATUS_10FULL:
1978 bp->line_speed = SPEED_10;
1979 break;
1980 case BNX2_LINK_STATUS_100HALF:
1981 bp->duplex = DUPLEX_HALF;
1982 case BNX2_LINK_STATUS_100BASE_T4:
1983 case BNX2_LINK_STATUS_100FULL:
1984 bp->line_speed = SPEED_100;
1985 break;
1986 case BNX2_LINK_STATUS_1000HALF:
1987 bp->duplex = DUPLEX_HALF;
1988 case BNX2_LINK_STATUS_1000FULL:
1989 bp->line_speed = SPEED_1000;
1990 break;
1991 case BNX2_LINK_STATUS_2500HALF:
1992 bp->duplex = DUPLEX_HALF;
1993 case BNX2_LINK_STATUS_2500FULL:
1994 bp->line_speed = SPEED_2500;
1995 break;
1996 default:
1997 bp->line_speed = 0;
1998 break;
1999 }
2000
Michael Chan0d8a6572007-07-07 22:49:43 -07002001 bp->flow_ctrl = 0;
2002 if ((bp->autoneg & (AUTONEG_SPEED | AUTONEG_FLOW_CTRL)) !=
2003 (AUTONEG_SPEED | AUTONEG_FLOW_CTRL)) {
2004 if (bp->duplex == DUPLEX_FULL)
2005 bp->flow_ctrl = bp->req_flow_ctrl;
2006 } else {
2007 if (msg & BNX2_LINK_STATUS_TX_FC_ENABLED)
2008 bp->flow_ctrl |= FLOW_CTRL_TX;
2009 if (msg & BNX2_LINK_STATUS_RX_FC_ENABLED)
2010 bp->flow_ctrl |= FLOW_CTRL_RX;
2011 }
2012
2013 old_port = bp->phy_port;
2014 if (msg & BNX2_LINK_STATUS_SERDES_LINK)
2015 bp->phy_port = PORT_FIBRE;
2016 else
2017 bp->phy_port = PORT_TP;
2018
2019 if (old_port != bp->phy_port)
2020 bnx2_set_default_link(bp);
2021
Michael Chan0d8a6572007-07-07 22:49:43 -07002022 }
2023 if (bp->link_up != link_up)
2024 bnx2_report_link(bp);
2025
2026 bnx2_set_mac_link(bp);
2027}
2028
2029static int
2030bnx2_set_remote_link(struct bnx2 *bp)
2031{
2032 u32 evt_code;
2033
Michael Chan2726d6e2008-01-29 21:35:05 -08002034 evt_code = bnx2_shmem_rd(bp, BNX2_FW_EVT_CODE_MB);
Michael Chan0d8a6572007-07-07 22:49:43 -07002035 switch (evt_code) {
2036 case BNX2_FW_EVT_CODE_LINK_EVENT:
2037 bnx2_remote_phy_event(bp);
2038 break;
2039 case BNX2_FW_EVT_CODE_SW_TIMER_EXPIRATION_EVENT:
2040 default:
Michael Chandf149d72007-07-07 22:51:36 -07002041 bnx2_send_heart_beat(bp);
Michael Chan0d8a6572007-07-07 22:49:43 -07002042 break;
2043 }
2044 return 0;
2045}
2046
Michael Chanb6016b72005-05-26 13:03:09 -07002047static int
2048bnx2_setup_copper_phy(struct bnx2 *bp)
Harvey Harrison52d07b12009-01-19 17:27:06 -08002049__releases(&bp->phy_lock)
2050__acquires(&bp->phy_lock)
Michael Chanb6016b72005-05-26 13:03:09 -07002051{
2052 u32 bmcr;
2053 u32 new_bmcr;
2054
Michael Chanca58c3a2007-05-03 13:22:52 -07002055 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chanb6016b72005-05-26 13:03:09 -07002056
2057 if (bp->autoneg & AUTONEG_SPEED) {
2058 u32 adv_reg, adv1000_reg;
2059 u32 new_adv_reg = 0;
2060 u32 new_adv1000_reg = 0;
2061
Michael Chanca58c3a2007-05-03 13:22:52 -07002062 bnx2_read_phy(bp, bp->mii_adv, &adv_reg);
Michael Chanb6016b72005-05-26 13:03:09 -07002063 adv_reg &= (PHY_ALL_10_100_SPEED | ADVERTISE_PAUSE_CAP |
2064 ADVERTISE_PAUSE_ASYM);
2065
2066 bnx2_read_phy(bp, MII_CTRL1000, &adv1000_reg);
2067 adv1000_reg &= PHY_ALL_1000_SPEED;
2068
2069 if (bp->advertising & ADVERTISED_10baseT_Half)
2070 new_adv_reg |= ADVERTISE_10HALF;
2071 if (bp->advertising & ADVERTISED_10baseT_Full)
2072 new_adv_reg |= ADVERTISE_10FULL;
2073 if (bp->advertising & ADVERTISED_100baseT_Half)
2074 new_adv_reg |= ADVERTISE_100HALF;
2075 if (bp->advertising & ADVERTISED_100baseT_Full)
2076 new_adv_reg |= ADVERTISE_100FULL;
2077 if (bp->advertising & ADVERTISED_1000baseT_Full)
2078 new_adv1000_reg |= ADVERTISE_1000FULL;
Jeff Garzik6aa20a22006-09-13 13:24:59 -04002079
Michael Chanb6016b72005-05-26 13:03:09 -07002080 new_adv_reg |= ADVERTISE_CSMA;
2081
2082 new_adv_reg |= bnx2_phy_get_pause_adv(bp);
2083
2084 if ((adv1000_reg != new_adv1000_reg) ||
2085 (adv_reg != new_adv_reg) ||
2086 ((bmcr & BMCR_ANENABLE) == 0)) {
2087
Michael Chanca58c3a2007-05-03 13:22:52 -07002088 bnx2_write_phy(bp, bp->mii_adv, new_adv_reg);
Michael Chanb6016b72005-05-26 13:03:09 -07002089 bnx2_write_phy(bp, MII_CTRL1000, new_adv1000_reg);
Michael Chanca58c3a2007-05-03 13:22:52 -07002090 bnx2_write_phy(bp, bp->mii_bmcr, BMCR_ANRESTART |
Michael Chanb6016b72005-05-26 13:03:09 -07002091 BMCR_ANENABLE);
2092 }
2093 else if (bp->link_up) {
2094 /* Flow ctrl may have changed from auto to forced */
2095 /* or vice-versa. */
2096
2097 bnx2_resolve_flow_ctrl(bp);
2098 bnx2_set_mac_link(bp);
2099 }
2100 return 0;
2101 }
2102
2103 new_bmcr = 0;
2104 if (bp->req_line_speed == SPEED_100) {
2105 new_bmcr |= BMCR_SPEED100;
2106 }
2107 if (bp->req_duplex == DUPLEX_FULL) {
2108 new_bmcr |= BMCR_FULLDPLX;
2109 }
2110 if (new_bmcr != bmcr) {
2111 u32 bmsr;
Michael Chanb6016b72005-05-26 13:03:09 -07002112
Michael Chanca58c3a2007-05-03 13:22:52 -07002113 bnx2_read_phy(bp, bp->mii_bmsr, &bmsr);
2114 bnx2_read_phy(bp, bp->mii_bmsr, &bmsr);
Jeff Garzik6aa20a22006-09-13 13:24:59 -04002115
Michael Chanb6016b72005-05-26 13:03:09 -07002116 if (bmsr & BMSR_LSTATUS) {
2117 /* Force link down */
Michael Chanca58c3a2007-05-03 13:22:52 -07002118 bnx2_write_phy(bp, bp->mii_bmcr, BMCR_LOOPBACK);
Michael Chana16dda02006-11-19 14:08:56 -08002119 spin_unlock_bh(&bp->phy_lock);
2120 msleep(50);
2121 spin_lock_bh(&bp->phy_lock);
2122
Michael Chanca58c3a2007-05-03 13:22:52 -07002123 bnx2_read_phy(bp, bp->mii_bmsr, &bmsr);
2124 bnx2_read_phy(bp, bp->mii_bmsr, &bmsr);
Michael Chanb6016b72005-05-26 13:03:09 -07002125 }
2126
Michael Chanca58c3a2007-05-03 13:22:52 -07002127 bnx2_write_phy(bp, bp->mii_bmcr, new_bmcr);
Michael Chanb6016b72005-05-26 13:03:09 -07002128
2129 /* Normally, the new speed is setup after the link has
2130 * gone down and up again. In some cases, link will not go
2131 * down so we need to set up the new speed here.
2132 */
2133 if (bmsr & BMSR_LSTATUS) {
2134 bp->line_speed = bp->req_line_speed;
2135 bp->duplex = bp->req_duplex;
2136 bnx2_resolve_flow_ctrl(bp);
2137 bnx2_set_mac_link(bp);
2138 }
Michael Chan27a005b2007-05-03 13:23:41 -07002139 } else {
2140 bnx2_resolve_flow_ctrl(bp);
2141 bnx2_set_mac_link(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07002142 }
2143 return 0;
2144}
2145
2146static int
Michael Chan0d8a6572007-07-07 22:49:43 -07002147bnx2_setup_phy(struct bnx2 *bp, u8 port)
Harvey Harrison52d07b12009-01-19 17:27:06 -08002148__releases(&bp->phy_lock)
2149__acquires(&bp->phy_lock)
Michael Chanb6016b72005-05-26 13:03:09 -07002150{
2151 if (bp->loopback == MAC_LOOPBACK)
2152 return 0;
2153
Michael Chan583c28e2008-01-21 19:51:35 -08002154 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Michael Chan0d8a6572007-07-07 22:49:43 -07002155 return (bnx2_setup_serdes_phy(bp, port));
Michael Chanb6016b72005-05-26 13:03:09 -07002156 }
2157 else {
2158 return (bnx2_setup_copper_phy(bp));
2159 }
2160}
2161
2162static int
Michael Chan9a120bc2008-05-16 22:17:45 -07002163bnx2_init_5709s_phy(struct bnx2 *bp, int reset_phy)
Michael Chan27a005b2007-05-03 13:23:41 -07002164{
2165 u32 val;
2166
2167 bp->mii_bmcr = MII_BMCR + 0x10;
2168 bp->mii_bmsr = MII_BMSR + 0x10;
2169 bp->mii_bmsr1 = MII_BNX2_GP_TOP_AN_STATUS1;
2170 bp->mii_adv = MII_ADVERTISE + 0x10;
2171 bp->mii_lpa = MII_LPA + 0x10;
2172 bp->mii_up1 = MII_BNX2_OVER1G_UP1;
2173
2174 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_AER);
2175 bnx2_write_phy(bp, MII_BNX2_AER_AER, MII_BNX2_AER_AER_AN_MMD);
2176
2177 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
Michael Chan9a120bc2008-05-16 22:17:45 -07002178 if (reset_phy)
2179 bnx2_reset_phy(bp);
Michael Chan27a005b2007-05-03 13:23:41 -07002180
2181 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_SERDES_DIG);
2182
2183 bnx2_read_phy(bp, MII_BNX2_SERDES_DIG_1000XCTL1, &val);
2184 val &= ~MII_BNX2_SD_1000XCTL1_AUTODET;
2185 val |= MII_BNX2_SD_1000XCTL1_FIBER;
2186 bnx2_write_phy(bp, MII_BNX2_SERDES_DIG_1000XCTL1, val);
2187
2188 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_OVER1G);
2189 bnx2_read_phy(bp, MII_BNX2_OVER1G_UP1, &val);
Michael Chan583c28e2008-01-21 19:51:35 -08002190 if (bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE)
Michael Chan27a005b2007-05-03 13:23:41 -07002191 val |= BCM5708S_UP1_2G5;
2192 else
2193 val &= ~BCM5708S_UP1_2G5;
2194 bnx2_write_phy(bp, MII_BNX2_OVER1G_UP1, val);
2195
2196 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_BAM_NXTPG);
2197 bnx2_read_phy(bp, MII_BNX2_BAM_NXTPG_CTL, &val);
2198 val |= MII_BNX2_NXTPG_CTL_T2 | MII_BNX2_NXTPG_CTL_BAM;
2199 bnx2_write_phy(bp, MII_BNX2_BAM_NXTPG_CTL, val);
2200
2201 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_CL73_USERB0);
2202
2203 val = MII_BNX2_CL73_BAM_EN | MII_BNX2_CL73_BAM_STA_MGR_EN |
2204 MII_BNX2_CL73_BAM_NP_AFT_BP_EN;
2205 bnx2_write_phy(bp, MII_BNX2_CL73_BAM_CTL1, val);
2206
2207 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
2208
2209 return 0;
2210}
2211
2212static int
Michael Chan9a120bc2008-05-16 22:17:45 -07002213bnx2_init_5708s_phy(struct bnx2 *bp, int reset_phy)
Michael Chan5b0c76a2005-11-04 08:45:49 -08002214{
2215 u32 val;
2216
Michael Chan9a120bc2008-05-16 22:17:45 -07002217 if (reset_phy)
2218 bnx2_reset_phy(bp);
Michael Chan27a005b2007-05-03 13:23:41 -07002219
2220 bp->mii_up1 = BCM5708S_UP1;
2221
Michael Chan5b0c76a2005-11-04 08:45:49 -08002222 bnx2_write_phy(bp, BCM5708S_BLK_ADDR, BCM5708S_BLK_ADDR_DIG3);
2223 bnx2_write_phy(bp, BCM5708S_DIG_3_0, BCM5708S_DIG_3_0_USE_IEEE);
2224 bnx2_write_phy(bp, BCM5708S_BLK_ADDR, BCM5708S_BLK_ADDR_DIG);
2225
2226 bnx2_read_phy(bp, BCM5708S_1000X_CTL1, &val);
2227 val |= BCM5708S_1000X_CTL1_FIBER_MODE | BCM5708S_1000X_CTL1_AUTODET_EN;
2228 bnx2_write_phy(bp, BCM5708S_1000X_CTL1, val);
2229
2230 bnx2_read_phy(bp, BCM5708S_1000X_CTL2, &val);
2231 val |= BCM5708S_1000X_CTL2_PLLEL_DET_EN;
2232 bnx2_write_phy(bp, BCM5708S_1000X_CTL2, val);
2233
Michael Chan583c28e2008-01-21 19:51:35 -08002234 if (bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE) {
Michael Chan5b0c76a2005-11-04 08:45:49 -08002235 bnx2_read_phy(bp, BCM5708S_UP1, &val);
2236 val |= BCM5708S_UP1_2G5;
2237 bnx2_write_phy(bp, BCM5708S_UP1, val);
2238 }
2239
2240 if ((CHIP_ID(bp) == CHIP_ID_5708_A0) ||
Michael Chandda1e392006-01-23 16:08:14 -08002241 (CHIP_ID(bp) == CHIP_ID_5708_B0) ||
2242 (CHIP_ID(bp) == CHIP_ID_5708_B1)) {
Michael Chan5b0c76a2005-11-04 08:45:49 -08002243 /* increase tx signal amplitude */
2244 bnx2_write_phy(bp, BCM5708S_BLK_ADDR,
2245 BCM5708S_BLK_ADDR_TX_MISC);
2246 bnx2_read_phy(bp, BCM5708S_TX_ACTL1, &val);
2247 val &= ~BCM5708S_TX_ACTL1_DRIVER_VCM;
2248 bnx2_write_phy(bp, BCM5708S_TX_ACTL1, val);
2249 bnx2_write_phy(bp, BCM5708S_BLK_ADDR, BCM5708S_BLK_ADDR_DIG);
2250 }
2251
Michael Chan2726d6e2008-01-29 21:35:05 -08002252 val = bnx2_shmem_rd(bp, BNX2_PORT_HW_CFG_CONFIG) &
Michael Chan5b0c76a2005-11-04 08:45:49 -08002253 BNX2_PORT_HW_CFG_CFG_TXCTL3_MASK;
2254
2255 if (val) {
2256 u32 is_backplane;
2257
Michael Chan2726d6e2008-01-29 21:35:05 -08002258 is_backplane = bnx2_shmem_rd(bp, BNX2_SHARED_HW_CFG_CONFIG);
Michael Chan5b0c76a2005-11-04 08:45:49 -08002259 if (is_backplane & BNX2_SHARED_HW_CFG_PHY_BACKPLANE) {
2260 bnx2_write_phy(bp, BCM5708S_BLK_ADDR,
2261 BCM5708S_BLK_ADDR_TX_MISC);
2262 bnx2_write_phy(bp, BCM5708S_TX_ACTL3, val);
2263 bnx2_write_phy(bp, BCM5708S_BLK_ADDR,
2264 BCM5708S_BLK_ADDR_DIG);
2265 }
2266 }
2267 return 0;
2268}
2269
2270static int
Michael Chan9a120bc2008-05-16 22:17:45 -07002271bnx2_init_5706s_phy(struct bnx2 *bp, int reset_phy)
Michael Chanb6016b72005-05-26 13:03:09 -07002272{
Michael Chan9a120bc2008-05-16 22:17:45 -07002273 if (reset_phy)
2274 bnx2_reset_phy(bp);
Michael Chan27a005b2007-05-03 13:23:41 -07002275
Michael Chan583c28e2008-01-21 19:51:35 -08002276 bp->phy_flags &= ~BNX2_PHY_FLAG_PARALLEL_DETECT;
Michael Chanb6016b72005-05-26 13:03:09 -07002277
Michael Chan59b47d82006-11-19 14:10:45 -08002278 if (CHIP_NUM(bp) == CHIP_NUM_5706)
2279 REG_WR(bp, BNX2_MISC_GP_HW_CTL0, 0x300);
Michael Chanb6016b72005-05-26 13:03:09 -07002280
2281 if (bp->dev->mtu > 1500) {
2282 u32 val;
2283
2284 /* Set extended packet length bit */
2285 bnx2_write_phy(bp, 0x18, 0x7);
2286 bnx2_read_phy(bp, 0x18, &val);
2287 bnx2_write_phy(bp, 0x18, (val & 0xfff8) | 0x4000);
2288
2289 bnx2_write_phy(bp, 0x1c, 0x6c00);
2290 bnx2_read_phy(bp, 0x1c, &val);
2291 bnx2_write_phy(bp, 0x1c, (val & 0x3ff) | 0xec02);
2292 }
2293 else {
2294 u32 val;
2295
2296 bnx2_write_phy(bp, 0x18, 0x7);
2297 bnx2_read_phy(bp, 0x18, &val);
2298 bnx2_write_phy(bp, 0x18, val & ~0x4007);
2299
2300 bnx2_write_phy(bp, 0x1c, 0x6c00);
2301 bnx2_read_phy(bp, 0x1c, &val);
2302 bnx2_write_phy(bp, 0x1c, (val & 0x3fd) | 0xec00);
2303 }
2304
2305 return 0;
2306}
2307
2308static int
Michael Chan9a120bc2008-05-16 22:17:45 -07002309bnx2_init_copper_phy(struct bnx2 *bp, int reset_phy)
Michael Chanb6016b72005-05-26 13:03:09 -07002310{
Michael Chan5b0c76a2005-11-04 08:45:49 -08002311 u32 val;
2312
Michael Chan9a120bc2008-05-16 22:17:45 -07002313 if (reset_phy)
2314 bnx2_reset_phy(bp);
Michael Chan27a005b2007-05-03 13:23:41 -07002315
Michael Chan583c28e2008-01-21 19:51:35 -08002316 if (bp->phy_flags & BNX2_PHY_FLAG_CRC_FIX) {
Michael Chanb6016b72005-05-26 13:03:09 -07002317 bnx2_write_phy(bp, 0x18, 0x0c00);
2318 bnx2_write_phy(bp, 0x17, 0x000a);
2319 bnx2_write_phy(bp, 0x15, 0x310b);
2320 bnx2_write_phy(bp, 0x17, 0x201f);
2321 bnx2_write_phy(bp, 0x15, 0x9506);
2322 bnx2_write_phy(bp, 0x17, 0x401f);
2323 bnx2_write_phy(bp, 0x15, 0x14e2);
2324 bnx2_write_phy(bp, 0x18, 0x0400);
2325 }
2326
Michael Chan583c28e2008-01-21 19:51:35 -08002327 if (bp->phy_flags & BNX2_PHY_FLAG_DIS_EARLY_DAC) {
Michael Chanb659f442007-02-02 00:46:35 -08002328 bnx2_write_phy(bp, MII_BNX2_DSP_ADDRESS,
2329 MII_BNX2_DSP_EXPAND_REG | 0x8);
2330 bnx2_read_phy(bp, MII_BNX2_DSP_RW_PORT, &val);
2331 val &= ~(1 << 8);
2332 bnx2_write_phy(bp, MII_BNX2_DSP_RW_PORT, val);
2333 }
2334
Michael Chanb6016b72005-05-26 13:03:09 -07002335 if (bp->dev->mtu > 1500) {
Michael Chanb6016b72005-05-26 13:03:09 -07002336 /* Set extended packet length bit */
2337 bnx2_write_phy(bp, 0x18, 0x7);
2338 bnx2_read_phy(bp, 0x18, &val);
2339 bnx2_write_phy(bp, 0x18, val | 0x4000);
2340
2341 bnx2_read_phy(bp, 0x10, &val);
2342 bnx2_write_phy(bp, 0x10, val | 0x1);
2343 }
2344 else {
Michael Chanb6016b72005-05-26 13:03:09 -07002345 bnx2_write_phy(bp, 0x18, 0x7);
2346 bnx2_read_phy(bp, 0x18, &val);
2347 bnx2_write_phy(bp, 0x18, val & ~0x4007);
2348
2349 bnx2_read_phy(bp, 0x10, &val);
2350 bnx2_write_phy(bp, 0x10, val & ~0x1);
2351 }
2352
Michael Chan5b0c76a2005-11-04 08:45:49 -08002353 /* ethernet@wirespeed */
2354 bnx2_write_phy(bp, 0x18, 0x7007);
2355 bnx2_read_phy(bp, 0x18, &val);
2356 bnx2_write_phy(bp, 0x18, val | (1 << 15) | (1 << 4));
Michael Chanb6016b72005-05-26 13:03:09 -07002357 return 0;
2358}
2359
2360
2361static int
Michael Chan9a120bc2008-05-16 22:17:45 -07002362bnx2_init_phy(struct bnx2 *bp, int reset_phy)
Harvey Harrison52d07b12009-01-19 17:27:06 -08002363__releases(&bp->phy_lock)
2364__acquires(&bp->phy_lock)
Michael Chanb6016b72005-05-26 13:03:09 -07002365{
2366 u32 val;
2367 int rc = 0;
2368
Michael Chan583c28e2008-01-21 19:51:35 -08002369 bp->phy_flags &= ~BNX2_PHY_FLAG_INT_MODE_MASK;
2370 bp->phy_flags |= BNX2_PHY_FLAG_INT_MODE_LINK_READY;
Michael Chanb6016b72005-05-26 13:03:09 -07002371
Michael Chanca58c3a2007-05-03 13:22:52 -07002372 bp->mii_bmcr = MII_BMCR;
2373 bp->mii_bmsr = MII_BMSR;
Michael Chan27a005b2007-05-03 13:23:41 -07002374 bp->mii_bmsr1 = MII_BMSR;
Michael Chanca58c3a2007-05-03 13:22:52 -07002375 bp->mii_adv = MII_ADVERTISE;
2376 bp->mii_lpa = MII_LPA;
2377
Michael Chanb6016b72005-05-26 13:03:09 -07002378 REG_WR(bp, BNX2_EMAC_ATTENTION_ENA, BNX2_EMAC_ATTENTION_ENA_LINK);
2379
Michael Chan583c28e2008-01-21 19:51:35 -08002380 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
Michael Chan0d8a6572007-07-07 22:49:43 -07002381 goto setup_phy;
2382
Michael Chanb6016b72005-05-26 13:03:09 -07002383 bnx2_read_phy(bp, MII_PHYSID1, &val);
2384 bp->phy_id = val << 16;
2385 bnx2_read_phy(bp, MII_PHYSID2, &val);
2386 bp->phy_id |= val & 0xffff;
2387
Michael Chan583c28e2008-01-21 19:51:35 -08002388 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Michael Chan5b0c76a2005-11-04 08:45:49 -08002389 if (CHIP_NUM(bp) == CHIP_NUM_5706)
Michael Chan9a120bc2008-05-16 22:17:45 -07002390 rc = bnx2_init_5706s_phy(bp, reset_phy);
Michael Chan5b0c76a2005-11-04 08:45:49 -08002391 else if (CHIP_NUM(bp) == CHIP_NUM_5708)
Michael Chan9a120bc2008-05-16 22:17:45 -07002392 rc = bnx2_init_5708s_phy(bp, reset_phy);
Michael Chan27a005b2007-05-03 13:23:41 -07002393 else if (CHIP_NUM(bp) == CHIP_NUM_5709)
Michael Chan9a120bc2008-05-16 22:17:45 -07002394 rc = bnx2_init_5709s_phy(bp, reset_phy);
Michael Chanb6016b72005-05-26 13:03:09 -07002395 }
2396 else {
Michael Chan9a120bc2008-05-16 22:17:45 -07002397 rc = bnx2_init_copper_phy(bp, reset_phy);
Michael Chanb6016b72005-05-26 13:03:09 -07002398 }
2399
Michael Chan0d8a6572007-07-07 22:49:43 -07002400setup_phy:
2401 if (!rc)
2402 rc = bnx2_setup_phy(bp, bp->phy_port);
Michael Chanb6016b72005-05-26 13:03:09 -07002403
2404 return rc;
2405}
2406
2407static int
2408bnx2_set_mac_loopback(struct bnx2 *bp)
2409{
2410 u32 mac_mode;
2411
2412 mac_mode = REG_RD(bp, BNX2_EMAC_MODE);
2413 mac_mode &= ~BNX2_EMAC_MODE_PORT;
2414 mac_mode |= BNX2_EMAC_MODE_MAC_LOOP | BNX2_EMAC_MODE_FORCE_LINK;
2415 REG_WR(bp, BNX2_EMAC_MODE, mac_mode);
2416 bp->link_up = 1;
2417 return 0;
2418}
2419
Michael Chanbc5a0692006-01-23 16:13:22 -08002420static int bnx2_test_link(struct bnx2 *);
2421
2422static int
2423bnx2_set_phy_loopback(struct bnx2 *bp)
2424{
2425 u32 mac_mode;
2426 int rc, i;
2427
2428 spin_lock_bh(&bp->phy_lock);
Michael Chanca58c3a2007-05-03 13:22:52 -07002429 rc = bnx2_write_phy(bp, bp->mii_bmcr, BMCR_LOOPBACK | BMCR_FULLDPLX |
Michael Chanbc5a0692006-01-23 16:13:22 -08002430 BMCR_SPEED1000);
2431 spin_unlock_bh(&bp->phy_lock);
2432 if (rc)
2433 return rc;
2434
2435 for (i = 0; i < 10; i++) {
2436 if (bnx2_test_link(bp) == 0)
2437 break;
Michael Chan80be4432006-11-19 14:07:28 -08002438 msleep(100);
Michael Chanbc5a0692006-01-23 16:13:22 -08002439 }
2440
2441 mac_mode = REG_RD(bp, BNX2_EMAC_MODE);
2442 mac_mode &= ~(BNX2_EMAC_MODE_PORT | BNX2_EMAC_MODE_HALF_DUPLEX |
2443 BNX2_EMAC_MODE_MAC_LOOP | BNX2_EMAC_MODE_FORCE_LINK |
Michael Chan59b47d82006-11-19 14:10:45 -08002444 BNX2_EMAC_MODE_25G_MODE);
Michael Chanbc5a0692006-01-23 16:13:22 -08002445
2446 mac_mode |= BNX2_EMAC_MODE_PORT_GMII;
2447 REG_WR(bp, BNX2_EMAC_MODE, mac_mode);
2448 bp->link_up = 1;
2449 return 0;
2450}
2451
Michael Chanb6016b72005-05-26 13:03:09 -07002452static int
Michael Chana2f13892008-07-14 22:38:23 -07002453bnx2_fw_sync(struct bnx2 *bp, u32 msg_data, int ack, int silent)
Michael Chanb6016b72005-05-26 13:03:09 -07002454{
2455 int i;
2456 u32 val;
2457
Michael Chanb6016b72005-05-26 13:03:09 -07002458 bp->fw_wr_seq++;
2459 msg_data |= bp->fw_wr_seq;
2460
Michael Chan2726d6e2008-01-29 21:35:05 -08002461 bnx2_shmem_wr(bp, BNX2_DRV_MB, msg_data);
Michael Chanb6016b72005-05-26 13:03:09 -07002462
Michael Chana2f13892008-07-14 22:38:23 -07002463 if (!ack)
2464 return 0;
2465
Michael Chanb6016b72005-05-26 13:03:09 -07002466 /* wait for an acknowledgement. */
Michael Chan40105c02008-11-12 16:02:45 -08002467 for (i = 0; i < (BNX2_FW_ACK_TIME_OUT_MS / 10); i++) {
Michael Chanb090ae22006-01-23 16:07:10 -08002468 msleep(10);
Michael Chanb6016b72005-05-26 13:03:09 -07002469
Michael Chan2726d6e2008-01-29 21:35:05 -08002470 val = bnx2_shmem_rd(bp, BNX2_FW_MB);
Michael Chanb6016b72005-05-26 13:03:09 -07002471
2472 if ((val & BNX2_FW_MSG_ACK) == (msg_data & BNX2_DRV_MSG_SEQ))
2473 break;
2474 }
Michael Chanb090ae22006-01-23 16:07:10 -08002475 if ((msg_data & BNX2_DRV_MSG_DATA) == BNX2_DRV_MSG_DATA_WAIT0)
2476 return 0;
Michael Chanb6016b72005-05-26 13:03:09 -07002477
2478 /* If we timed out, inform the firmware that this is the case. */
Michael Chanb090ae22006-01-23 16:07:10 -08002479 if ((val & BNX2_FW_MSG_ACK) != (msg_data & BNX2_DRV_MSG_SEQ)) {
2480 if (!silent)
Joe Perches3a9c6a42010-02-17 15:01:51 +00002481 pr_err("fw sync timeout, reset code = %x\n", msg_data);
Michael Chanb6016b72005-05-26 13:03:09 -07002482
2483 msg_data &= ~BNX2_DRV_MSG_CODE;
2484 msg_data |= BNX2_DRV_MSG_CODE_FW_TIMEOUT;
2485
Michael Chan2726d6e2008-01-29 21:35:05 -08002486 bnx2_shmem_wr(bp, BNX2_DRV_MB, msg_data);
Michael Chanb6016b72005-05-26 13:03:09 -07002487
Michael Chanb6016b72005-05-26 13:03:09 -07002488 return -EBUSY;
2489 }
2490
Michael Chanb090ae22006-01-23 16:07:10 -08002491 if ((val & BNX2_FW_MSG_STATUS_MASK) != BNX2_FW_MSG_STATUS_OK)
2492 return -EIO;
2493
Michael Chanb6016b72005-05-26 13:03:09 -07002494 return 0;
2495}
2496
Michael Chan59b47d82006-11-19 14:10:45 -08002497static int
2498bnx2_init_5709_context(struct bnx2 *bp)
2499{
2500 int i, ret = 0;
2501 u32 val;
2502
2503 val = BNX2_CTX_COMMAND_ENABLED | BNX2_CTX_COMMAND_MEM_INIT | (1 << 12);
2504 val |= (BCM_PAGE_BITS - 8) << 16;
2505 REG_WR(bp, BNX2_CTX_COMMAND, val);
Michael Chan641bdcd2007-06-04 21:22:24 -07002506 for (i = 0; i < 10; i++) {
2507 val = REG_RD(bp, BNX2_CTX_COMMAND);
2508 if (!(val & BNX2_CTX_COMMAND_MEM_INIT))
2509 break;
2510 udelay(2);
2511 }
2512 if (val & BNX2_CTX_COMMAND_MEM_INIT)
2513 return -EBUSY;
2514
Michael Chan59b47d82006-11-19 14:10:45 -08002515 for (i = 0; i < bp->ctx_pages; i++) {
2516 int j;
2517
Michael Chan352f7682008-05-02 16:57:26 -07002518 if (bp->ctx_blk[i])
2519 memset(bp->ctx_blk[i], 0, BCM_PAGE_SIZE);
2520 else
2521 return -ENOMEM;
2522
Michael Chan59b47d82006-11-19 14:10:45 -08002523 REG_WR(bp, BNX2_CTX_HOST_PAGE_TBL_DATA0,
2524 (bp->ctx_blk_mapping[i] & 0xffffffff) |
2525 BNX2_CTX_HOST_PAGE_TBL_DATA0_VALID);
2526 REG_WR(bp, BNX2_CTX_HOST_PAGE_TBL_DATA1,
2527 (u64) bp->ctx_blk_mapping[i] >> 32);
2528 REG_WR(bp, BNX2_CTX_HOST_PAGE_TBL_CTRL, i |
2529 BNX2_CTX_HOST_PAGE_TBL_CTRL_WRITE_REQ);
2530 for (j = 0; j < 10; j++) {
2531
2532 val = REG_RD(bp, BNX2_CTX_HOST_PAGE_TBL_CTRL);
2533 if (!(val & BNX2_CTX_HOST_PAGE_TBL_CTRL_WRITE_REQ))
2534 break;
2535 udelay(5);
2536 }
2537 if (val & BNX2_CTX_HOST_PAGE_TBL_CTRL_WRITE_REQ) {
2538 ret = -EBUSY;
2539 break;
2540 }
2541 }
2542 return ret;
2543}
2544
Michael Chanb6016b72005-05-26 13:03:09 -07002545static void
2546bnx2_init_context(struct bnx2 *bp)
2547{
2548 u32 vcid;
2549
2550 vcid = 96;
2551 while (vcid) {
2552 u32 vcid_addr, pcid_addr, offset;
Michael Chan7947b202007-06-04 21:17:10 -07002553 int i;
Michael Chanb6016b72005-05-26 13:03:09 -07002554
2555 vcid--;
2556
2557 if (CHIP_ID(bp) == CHIP_ID_5706_A0) {
2558 u32 new_vcid;
2559
2560 vcid_addr = GET_PCID_ADDR(vcid);
2561 if (vcid & 0x8) {
2562 new_vcid = 0x60 + (vcid & 0xf0) + (vcid & 0x7);
2563 }
2564 else {
2565 new_vcid = vcid;
2566 }
2567 pcid_addr = GET_PCID_ADDR(new_vcid);
2568 }
2569 else {
2570 vcid_addr = GET_CID_ADDR(vcid);
2571 pcid_addr = vcid_addr;
2572 }
2573
Michael Chan7947b202007-06-04 21:17:10 -07002574 for (i = 0; i < (CTX_SIZE / PHY_CTX_SIZE); i++) {
2575 vcid_addr += (i << PHY_CTX_SHIFT);
2576 pcid_addr += (i << PHY_CTX_SHIFT);
Michael Chanb6016b72005-05-26 13:03:09 -07002577
Michael Chan5d5d0012007-12-12 11:17:43 -08002578 REG_WR(bp, BNX2_CTX_VIRT_ADDR, vcid_addr);
Michael Chan7947b202007-06-04 21:17:10 -07002579 REG_WR(bp, BNX2_CTX_PAGE_TBL, pcid_addr);
2580
2581 /* Zero out the context. */
2582 for (offset = 0; offset < PHY_CTX_SIZE; offset += 4)
Michael Chan62a83132008-01-29 21:35:40 -08002583 bnx2_ctx_wr(bp, vcid_addr, offset, 0);
Michael Chanb6016b72005-05-26 13:03:09 -07002584 }
Michael Chanb6016b72005-05-26 13:03:09 -07002585 }
2586}
2587
2588static int
2589bnx2_alloc_bad_rbuf(struct bnx2 *bp)
2590{
2591 u16 *good_mbuf;
2592 u32 good_mbuf_cnt;
2593 u32 val;
2594
2595 good_mbuf = kmalloc(512 * sizeof(u16), GFP_KERNEL);
2596 if (good_mbuf == NULL) {
Joe Perches3a9c6a42010-02-17 15:01:51 +00002597 pr_err("Failed to allocate memory in %s\n", __func__);
Michael Chanb6016b72005-05-26 13:03:09 -07002598 return -ENOMEM;
2599 }
2600
2601 REG_WR(bp, BNX2_MISC_ENABLE_SET_BITS,
2602 BNX2_MISC_ENABLE_SET_BITS_RX_MBUF_ENABLE);
2603
2604 good_mbuf_cnt = 0;
2605
2606 /* Allocate a bunch of mbufs and save the good ones in an array. */
Michael Chan2726d6e2008-01-29 21:35:05 -08002607 val = bnx2_reg_rd_ind(bp, BNX2_RBUF_STATUS1);
Michael Chanb6016b72005-05-26 13:03:09 -07002608 while (val & BNX2_RBUF_STATUS1_FREE_COUNT) {
Michael Chan2726d6e2008-01-29 21:35:05 -08002609 bnx2_reg_wr_ind(bp, BNX2_RBUF_COMMAND,
2610 BNX2_RBUF_COMMAND_ALLOC_REQ);
Michael Chanb6016b72005-05-26 13:03:09 -07002611
Michael Chan2726d6e2008-01-29 21:35:05 -08002612 val = bnx2_reg_rd_ind(bp, BNX2_RBUF_FW_BUF_ALLOC);
Michael Chanb6016b72005-05-26 13:03:09 -07002613
2614 val &= BNX2_RBUF_FW_BUF_ALLOC_VALUE;
2615
2616 /* The addresses with Bit 9 set are bad memory blocks. */
2617 if (!(val & (1 << 9))) {
2618 good_mbuf[good_mbuf_cnt] = (u16) val;
2619 good_mbuf_cnt++;
2620 }
2621
Michael Chan2726d6e2008-01-29 21:35:05 -08002622 val = bnx2_reg_rd_ind(bp, BNX2_RBUF_STATUS1);
Michael Chanb6016b72005-05-26 13:03:09 -07002623 }
2624
2625 /* Free the good ones back to the mbuf pool thus discarding
2626 * all the bad ones. */
2627 while (good_mbuf_cnt) {
2628 good_mbuf_cnt--;
2629
2630 val = good_mbuf[good_mbuf_cnt];
2631 val = (val << 9) | val | 1;
2632
Michael Chan2726d6e2008-01-29 21:35:05 -08002633 bnx2_reg_wr_ind(bp, BNX2_RBUF_FW_BUF_FREE, val);
Michael Chanb6016b72005-05-26 13:03:09 -07002634 }
2635 kfree(good_mbuf);
2636 return 0;
2637}
2638
2639static void
Benjamin Li5fcaed02008-07-14 22:39:52 -07002640bnx2_set_mac_addr(struct bnx2 *bp, u8 *mac_addr, u32 pos)
Michael Chanb6016b72005-05-26 13:03:09 -07002641{
2642 u32 val;
Michael Chanb6016b72005-05-26 13:03:09 -07002643
2644 val = (mac_addr[0] << 8) | mac_addr[1];
2645
Benjamin Li5fcaed02008-07-14 22:39:52 -07002646 REG_WR(bp, BNX2_EMAC_MAC_MATCH0 + (pos * 8), val);
Michael Chanb6016b72005-05-26 13:03:09 -07002647
Jeff Garzik6aa20a22006-09-13 13:24:59 -04002648 val = (mac_addr[2] << 24) | (mac_addr[3] << 16) |
Michael Chanb6016b72005-05-26 13:03:09 -07002649 (mac_addr[4] << 8) | mac_addr[5];
2650
Benjamin Li5fcaed02008-07-14 22:39:52 -07002651 REG_WR(bp, BNX2_EMAC_MAC_MATCH1 + (pos * 8), val);
Michael Chanb6016b72005-05-26 13:03:09 -07002652}
2653
2654static inline int
Michael Chanbb4f98a2008-06-19 16:38:19 -07002655bnx2_alloc_rx_page(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr, u16 index)
Michael Chan47bf4242007-12-12 11:19:12 -08002656{
2657 dma_addr_t mapping;
Michael Chanbb4f98a2008-06-19 16:38:19 -07002658 struct sw_pg *rx_pg = &rxr->rx_pg_ring[index];
Michael Chan47bf4242007-12-12 11:19:12 -08002659 struct rx_bd *rxbd =
Michael Chanbb4f98a2008-06-19 16:38:19 -07002660 &rxr->rx_pg_desc_ring[RX_RING(index)][RX_IDX(index)];
Michael Chan47bf4242007-12-12 11:19:12 -08002661 struct page *page = alloc_page(GFP_ATOMIC);
2662
2663 if (!page)
2664 return -ENOMEM;
2665 mapping = pci_map_page(bp->pdev, page, 0, PAGE_SIZE,
2666 PCI_DMA_FROMDEVICE);
Benjamin Li3d16af82008-10-09 12:26:41 -07002667 if (pci_dma_mapping_error(bp->pdev, mapping)) {
2668 __free_page(page);
2669 return -EIO;
2670 }
2671
Michael Chan47bf4242007-12-12 11:19:12 -08002672 rx_pg->page = page;
2673 pci_unmap_addr_set(rx_pg, mapping, mapping);
2674 rxbd->rx_bd_haddr_hi = (u64) mapping >> 32;
2675 rxbd->rx_bd_haddr_lo = (u64) mapping & 0xffffffff;
2676 return 0;
2677}
2678
2679static void
Michael Chanbb4f98a2008-06-19 16:38:19 -07002680bnx2_free_rx_page(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr, u16 index)
Michael Chan47bf4242007-12-12 11:19:12 -08002681{
Michael Chanbb4f98a2008-06-19 16:38:19 -07002682 struct sw_pg *rx_pg = &rxr->rx_pg_ring[index];
Michael Chan47bf4242007-12-12 11:19:12 -08002683 struct page *page = rx_pg->page;
2684
2685 if (!page)
2686 return;
2687
2688 pci_unmap_page(bp->pdev, pci_unmap_addr(rx_pg, mapping), PAGE_SIZE,
2689 PCI_DMA_FROMDEVICE);
2690
2691 __free_page(page);
2692 rx_pg->page = NULL;
2693}
2694
2695static inline int
Michael Chanbb4f98a2008-06-19 16:38:19 -07002696bnx2_alloc_rx_skb(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr, u16 index)
Michael Chanb6016b72005-05-26 13:03:09 -07002697{
2698 struct sk_buff *skb;
Michael Chanbb4f98a2008-06-19 16:38:19 -07002699 struct sw_bd *rx_buf = &rxr->rx_buf_ring[index];
Michael Chanb6016b72005-05-26 13:03:09 -07002700 dma_addr_t mapping;
Michael Chanbb4f98a2008-06-19 16:38:19 -07002701 struct rx_bd *rxbd = &rxr->rx_desc_ring[RX_RING(index)][RX_IDX(index)];
Michael Chanb6016b72005-05-26 13:03:09 -07002702 unsigned long align;
2703
Michael Chan932f3772006-08-15 01:39:36 -07002704 skb = netdev_alloc_skb(bp->dev, bp->rx_buf_size);
Michael Chanb6016b72005-05-26 13:03:09 -07002705 if (skb == NULL) {
2706 return -ENOMEM;
2707 }
2708
Michael Chan59b47d82006-11-19 14:10:45 -08002709 if (unlikely((align = (unsigned long) skb->data & (BNX2_RX_ALIGN - 1))))
2710 skb_reserve(skb, BNX2_RX_ALIGN - align);
Michael Chanb6016b72005-05-26 13:03:09 -07002711
Michael Chanb6016b72005-05-26 13:03:09 -07002712 mapping = pci_map_single(bp->pdev, skb->data, bp->rx_buf_use_size,
2713 PCI_DMA_FROMDEVICE);
Benjamin Li3d16af82008-10-09 12:26:41 -07002714 if (pci_dma_mapping_error(bp->pdev, mapping)) {
2715 dev_kfree_skb(skb);
2716 return -EIO;
2717 }
Michael Chanb6016b72005-05-26 13:03:09 -07002718
2719 rx_buf->skb = skb;
2720 pci_unmap_addr_set(rx_buf, mapping, mapping);
2721
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
Alexander Duycke95524a2009-12-02 16:47:57 +00002819 pci_unmap_single(bp->pdev, pci_unmap_addr(tx_buf, mapping),
2820 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,
2829 pci_unmap_addr(
2830 &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;
2911 pci_unmap_addr_set(prod_rx_pg, mapping,
2912 pci_unmap_addr(cons_rx_pg, mapping));
2913
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,
2936 pci_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;
2942
2943 if (cons == prod)
2944 return;
2945
Michael Chanb6016b72005-05-26 13:03:09 -07002946 pci_unmap_addr_set(prod_rx_buf, mapping,
2947 pci_unmap_addr(cons_rx_buf, mapping));
2948
Michael Chanbb4f98a2008-06-19 16:38:19 -07002949 cons_bd = &rxr->rx_desc_ring[RX_RING(cons)][RX_IDX(cons)];
2950 prod_bd = &rxr->rx_desc_ring[RX_RING(prod)][RX_IDX(prod)];
Michael Chan236b6392006-03-20 17:49:02 -08002951 prod_bd->rx_bd_haddr_hi = cons_bd->rx_bd_haddr_hi;
2952 prod_bd->rx_bd_haddr_lo = cons_bd->rx_bd_haddr_lo;
Michael Chanb6016b72005-05-26 13:03:09 -07002953}
2954
Michael Chan85833c62007-12-12 11:17:01 -08002955static int
Michael Chanbb4f98a2008-06-19 16:38:19 -07002956bnx2_rx_skb(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr, struct sk_buff *skb,
Michael Chana1f60192007-12-20 19:57:19 -08002957 unsigned int len, unsigned int hdr_len, dma_addr_t dma_addr,
2958 u32 ring_idx)
Michael Chan85833c62007-12-12 11:17:01 -08002959{
2960 int err;
2961 u16 prod = ring_idx & 0xffff;
2962
Michael Chanbb4f98a2008-06-19 16:38:19 -07002963 err = bnx2_alloc_rx_skb(bp, rxr, prod);
Michael Chan85833c62007-12-12 11:17:01 -08002964 if (unlikely(err)) {
Michael Chanbb4f98a2008-06-19 16:38:19 -07002965 bnx2_reuse_rx_skb(bp, rxr, skb, (u16) (ring_idx >> 16), prod);
Michael Chan1db82f22007-12-12 11:19:35 -08002966 if (hdr_len) {
2967 unsigned int raw_len = len + 4;
2968 int pages = PAGE_ALIGN(raw_len - hdr_len) >> PAGE_SHIFT;
2969
Michael Chanbb4f98a2008-06-19 16:38:19 -07002970 bnx2_reuse_rx_skb_pages(bp, rxr, NULL, pages);
Michael Chan1db82f22007-12-12 11:19:35 -08002971 }
Michael Chan85833c62007-12-12 11:17:01 -08002972 return err;
2973 }
2974
Benjamin Lid89cb6a2008-05-16 22:18:57 -07002975 skb_reserve(skb, BNX2_RX_OFFSET);
Michael Chan85833c62007-12-12 11:17:01 -08002976 pci_unmap_single(bp->pdev, dma_addr, bp->rx_buf_use_size,
2977 PCI_DMA_FROMDEVICE);
2978
Michael Chan1db82f22007-12-12 11:19:35 -08002979 if (hdr_len == 0) {
2980 skb_put(skb, len);
2981 return 0;
2982 } else {
2983 unsigned int i, frag_len, frag_size, pages;
2984 struct sw_pg *rx_pg;
Michael Chanbb4f98a2008-06-19 16:38:19 -07002985 u16 pg_cons = rxr->rx_pg_cons;
2986 u16 pg_prod = rxr->rx_pg_prod;
Michael Chan1db82f22007-12-12 11:19:35 -08002987
2988 frag_size = len + 4 - hdr_len;
2989 pages = PAGE_ALIGN(frag_size) >> PAGE_SHIFT;
2990 skb_put(skb, hdr_len);
2991
2992 for (i = 0; i < pages; i++) {
Benjamin Li3d16af82008-10-09 12:26:41 -07002993 dma_addr_t mapping_old;
2994
Michael Chan1db82f22007-12-12 11:19:35 -08002995 frag_len = min(frag_size, (unsigned int) PAGE_SIZE);
2996 if (unlikely(frag_len <= 4)) {
2997 unsigned int tail = 4 - frag_len;
2998
Michael Chanbb4f98a2008-06-19 16:38:19 -07002999 rxr->rx_pg_cons = pg_cons;
3000 rxr->rx_pg_prod = pg_prod;
3001 bnx2_reuse_rx_skb_pages(bp, rxr, NULL,
Michael Chana1f60192007-12-20 19:57:19 -08003002 pages - i);
Michael Chan1db82f22007-12-12 11:19:35 -08003003 skb->len -= tail;
3004 if (i == 0) {
3005 skb->tail -= tail;
3006 } else {
3007 skb_frag_t *frag =
3008 &skb_shinfo(skb)->frags[i - 1];
3009 frag->size -= tail;
3010 skb->data_len -= tail;
3011 skb->truesize -= tail;
3012 }
3013 return 0;
3014 }
Michael Chanbb4f98a2008-06-19 16:38:19 -07003015 rx_pg = &rxr->rx_pg_ring[pg_cons];
Michael Chan1db82f22007-12-12 11:19:35 -08003016
Benjamin Li3d16af82008-10-09 12:26:41 -07003017 /* Don't unmap yet. If we're unable to allocate a new
3018 * page, we need to recycle the page and the DMA addr.
3019 */
3020 mapping_old = pci_unmap_addr(rx_pg, mapping);
Michael Chan1db82f22007-12-12 11:19:35 -08003021 if (i == pages - 1)
3022 frag_len -= 4;
3023
3024 skb_fill_page_desc(skb, i, rx_pg->page, 0, frag_len);
3025 rx_pg->page = NULL;
3026
Michael Chanbb4f98a2008-06-19 16:38:19 -07003027 err = bnx2_alloc_rx_page(bp, rxr,
3028 RX_PG_RING_IDX(pg_prod));
Michael Chan1db82f22007-12-12 11:19:35 -08003029 if (unlikely(err)) {
Michael Chanbb4f98a2008-06-19 16:38:19 -07003030 rxr->rx_pg_cons = pg_cons;
3031 rxr->rx_pg_prod = pg_prod;
3032 bnx2_reuse_rx_skb_pages(bp, rxr, skb,
Michael Chana1f60192007-12-20 19:57:19 -08003033 pages - i);
Michael Chan1db82f22007-12-12 11:19:35 -08003034 return err;
3035 }
3036
Benjamin Li3d16af82008-10-09 12:26:41 -07003037 pci_unmap_page(bp->pdev, mapping_old,
3038 PAGE_SIZE, PCI_DMA_FROMDEVICE);
3039
Michael Chan1db82f22007-12-12 11:19:35 -08003040 frag_size -= frag_len;
3041 skb->data_len += frag_len;
3042 skb->truesize += frag_len;
3043 skb->len += frag_len;
3044
3045 pg_prod = NEXT_RX_BD(pg_prod);
3046 pg_cons = RX_PG_RING_IDX(NEXT_RX_BD(pg_cons));
3047 }
Michael Chanbb4f98a2008-06-19 16:38:19 -07003048 rxr->rx_pg_prod = pg_prod;
3049 rxr->rx_pg_cons = pg_cons;
Michael Chan1db82f22007-12-12 11:19:35 -08003050 }
Michael Chan85833c62007-12-12 11:17:01 -08003051 return 0;
3052}
3053
Michael Chanc09c2622007-12-10 17:18:37 -08003054static inline u16
Michael Chan35efa7c2007-12-20 19:56:37 -08003055bnx2_get_hw_rx_cons(struct bnx2_napi *bnapi)
Michael Chanc09c2622007-12-10 17:18:37 -08003056{
Michael Chanbb4f98a2008-06-19 16:38:19 -07003057 u16 cons;
3058
Michael Chan43e80b82008-06-19 16:41:08 -07003059 /* Tell compiler that status block fields can change. */
3060 barrier();
3061 cons = *bnapi->hw_rx_cons_ptr;
Michael Chan581daf72009-05-06 16:46:47 -07003062 barrier();
Michael Chanc09c2622007-12-10 17:18:37 -08003063 if (unlikely((cons & MAX_RX_DESC_CNT) == MAX_RX_DESC_CNT))
3064 cons++;
3065 return cons;
3066}
3067
Michael Chanb6016b72005-05-26 13:03:09 -07003068static int
Michael Chan35efa7c2007-12-20 19:56:37 -08003069bnx2_rx_int(struct bnx2 *bp, struct bnx2_napi *bnapi, int budget)
Michael Chanb6016b72005-05-26 13:03:09 -07003070{
Michael Chanbb4f98a2008-06-19 16:38:19 -07003071 struct bnx2_rx_ring_info *rxr = &bnapi->rx_ring;
Michael Chanb6016b72005-05-26 13:03:09 -07003072 u16 hw_cons, sw_cons, sw_ring_cons, sw_prod, sw_ring_prod;
3073 struct l2_fhdr *rx_hdr;
Michael Chan1db82f22007-12-12 11:19:35 -08003074 int rx_pkt = 0, pg_ring_used = 0;
Michael Chanb6016b72005-05-26 13:03:09 -07003075
Michael Chan35efa7c2007-12-20 19:56:37 -08003076 hw_cons = bnx2_get_hw_rx_cons(bnapi);
Michael Chanbb4f98a2008-06-19 16:38:19 -07003077 sw_cons = rxr->rx_cons;
3078 sw_prod = rxr->rx_prod;
Michael Chanb6016b72005-05-26 13:03:09 -07003079
3080 /* Memory barrier necessary as speculative reads of the rx
3081 * buffer can be ahead of the index in the status block
3082 */
3083 rmb();
3084 while (sw_cons != hw_cons) {
Michael Chan1db82f22007-12-12 11:19:35 -08003085 unsigned int len, hdr_len;
Michael Chanade2bfe2006-01-23 16:09:51 -08003086 u32 status;
Michael Chanb6016b72005-05-26 13:03:09 -07003087 struct sw_bd *rx_buf;
3088 struct sk_buff *skb;
Michael Chan236b6392006-03-20 17:49:02 -08003089 dma_addr_t dma_addr;
Michael Chanf22828e2008-08-14 15:30:14 -07003090 u16 vtag = 0;
3091 int hw_vlan __maybe_unused = 0;
Michael Chanb6016b72005-05-26 13:03:09 -07003092
3093 sw_ring_cons = RX_RING_IDX(sw_cons);
3094 sw_ring_prod = RX_RING_IDX(sw_prod);
3095
Michael Chanbb4f98a2008-06-19 16:38:19 -07003096 rx_buf = &rxr->rx_buf_ring[sw_ring_cons];
Michael Chanb6016b72005-05-26 13:03:09 -07003097 skb = rx_buf->skb;
Michael Chan236b6392006-03-20 17:49:02 -08003098
3099 rx_buf->skb = NULL;
3100
3101 dma_addr = pci_unmap_addr(rx_buf, mapping);
3102
3103 pci_dma_sync_single_for_cpu(bp->pdev, dma_addr,
Benjamin Li601d3d12008-05-16 22:19:35 -07003104 BNX2_RX_OFFSET + BNX2_RX_COPY_THRESH,
3105 PCI_DMA_FROMDEVICE);
Michael Chanb6016b72005-05-26 13:03:09 -07003106
3107 rx_hdr = (struct l2_fhdr *) skb->data;
Michael Chan1db82f22007-12-12 11:19:35 -08003108 len = rx_hdr->l2_fhdr_pkt_len;
Michael Chan990ec382009-02-12 16:54:13 -08003109 status = rx_hdr->l2_fhdr_status;
Michael Chanb6016b72005-05-26 13:03:09 -07003110
Michael Chan1db82f22007-12-12 11:19:35 -08003111 hdr_len = 0;
3112 if (status & L2_FHDR_STATUS_SPLIT) {
3113 hdr_len = rx_hdr->l2_fhdr_ip_xsum;
3114 pg_ring_used = 1;
3115 } else if (len > bp->rx_jumbo_thresh) {
3116 hdr_len = bp->rx_jumbo_thresh;
3117 pg_ring_used = 1;
3118 }
3119
Michael Chan990ec382009-02-12 16:54:13 -08003120 if (unlikely(status & (L2_FHDR_ERRORS_BAD_CRC |
3121 L2_FHDR_ERRORS_PHY_DECODE |
3122 L2_FHDR_ERRORS_ALIGNMENT |
3123 L2_FHDR_ERRORS_TOO_SHORT |
3124 L2_FHDR_ERRORS_GIANT_FRAME))) {
3125
3126 bnx2_reuse_rx_skb(bp, rxr, skb, sw_ring_cons,
3127 sw_ring_prod);
3128 if (pg_ring_used) {
3129 int pages;
3130
3131 pages = PAGE_ALIGN(len - hdr_len) >> PAGE_SHIFT;
3132
3133 bnx2_reuse_rx_skb_pages(bp, rxr, NULL, pages);
3134 }
3135 goto next_rx;
3136 }
3137
Michael Chan1db82f22007-12-12 11:19:35 -08003138 len -= 4;
Michael Chanb6016b72005-05-26 13:03:09 -07003139
Michael Chan5d5d0012007-12-12 11:17:43 -08003140 if (len <= bp->rx_copy_thresh) {
Michael Chanb6016b72005-05-26 13:03:09 -07003141 struct sk_buff *new_skb;
3142
Michael Chanf22828e2008-08-14 15:30:14 -07003143 new_skb = netdev_alloc_skb(bp->dev, len + 6);
Michael Chan85833c62007-12-12 11:17:01 -08003144 if (new_skb == NULL) {
Michael Chanbb4f98a2008-06-19 16:38:19 -07003145 bnx2_reuse_rx_skb(bp, rxr, skb, sw_ring_cons,
Michael Chan85833c62007-12-12 11:17:01 -08003146 sw_ring_prod);
3147 goto next_rx;
3148 }
Michael Chanb6016b72005-05-26 13:03:09 -07003149
3150 /* aligned copy */
Benjamin Lid89cb6a2008-05-16 22:18:57 -07003151 skb_copy_from_linear_data_offset(skb,
Michael Chanf22828e2008-08-14 15:30:14 -07003152 BNX2_RX_OFFSET - 6,
3153 new_skb->data, len + 6);
3154 skb_reserve(new_skb, 6);
Michael Chanb6016b72005-05-26 13:03:09 -07003155 skb_put(new_skb, len);
Michael Chanb6016b72005-05-26 13:03:09 -07003156
Michael Chanbb4f98a2008-06-19 16:38:19 -07003157 bnx2_reuse_rx_skb(bp, rxr, skb,
Michael Chanb6016b72005-05-26 13:03:09 -07003158 sw_ring_cons, sw_ring_prod);
3159
3160 skb = new_skb;
Michael Chanbb4f98a2008-06-19 16:38:19 -07003161 } else if (unlikely(bnx2_rx_skb(bp, rxr, skb, len, hdr_len,
Michael Chana1f60192007-12-20 19:57:19 -08003162 dma_addr, (sw_ring_cons << 16) | sw_ring_prod)))
Michael Chanb6016b72005-05-26 13:03:09 -07003163 goto next_rx;
Michael Chanb6016b72005-05-26 13:03:09 -07003164
Michael Chanf22828e2008-08-14 15:30:14 -07003165 if ((status & L2_FHDR_STATUS_L2_VLAN_TAG) &&
3166 !(bp->rx_mode & BNX2_EMAC_RX_MODE_KEEP_VLAN_TAG)) {
3167 vtag = rx_hdr->l2_fhdr_vlan_tag;
3168#ifdef BCM_VLAN
3169 if (bp->vlgrp)
3170 hw_vlan = 1;
3171 else
3172#endif
3173 {
3174 struct vlan_ethhdr *ve = (struct vlan_ethhdr *)
3175 __skb_push(skb, 4);
3176
3177 memmove(ve, skb->data + 4, ETH_ALEN * 2);
3178 ve->h_vlan_proto = htons(ETH_P_8021Q);
3179 ve->h_vlan_TCI = htons(vtag);
3180 len += 4;
3181 }
3182 }
3183
Michael Chanb6016b72005-05-26 13:03:09 -07003184 skb->protocol = eth_type_trans(skb, bp->dev);
3185
3186 if ((len > (bp->dev->mtu + ETH_HLEN)) &&
Alexey Dobriyand1e100b2006-06-11 20:57:17 -07003187 (ntohs(skb->protocol) != 0x8100)) {
Michael Chanb6016b72005-05-26 13:03:09 -07003188
Michael Chan745720e2006-06-29 12:37:41 -07003189 dev_kfree_skb(skb);
Michael Chanb6016b72005-05-26 13:03:09 -07003190 goto next_rx;
3191
3192 }
3193
Michael Chanb6016b72005-05-26 13:03:09 -07003194 skb->ip_summed = CHECKSUM_NONE;
3195 if (bp->rx_csum &&
3196 (status & (L2_FHDR_STATUS_TCP_SEGMENT |
3197 L2_FHDR_STATUS_UDP_DATAGRAM))) {
3198
Michael Chanade2bfe2006-01-23 16:09:51 -08003199 if (likely((status & (L2_FHDR_ERRORS_TCP_XSUM |
3200 L2_FHDR_ERRORS_UDP_XSUM)) == 0))
Michael Chanb6016b72005-05-26 13:03:09 -07003201 skb->ip_summed = CHECKSUM_UNNECESSARY;
3202 }
3203
David S. Miller0c8dfc82009-01-27 16:22:32 -08003204 skb_record_rx_queue(skb, bnapi - &bp->bnx2_napi[0]);
3205
Michael Chanb6016b72005-05-26 13:03:09 -07003206#ifdef BCM_VLAN
Michael Chanf22828e2008-08-14 15:30:14 -07003207 if (hw_vlan)
3208 vlan_hwaccel_receive_skb(skb, bp->vlgrp, vtag);
Michael Chanb6016b72005-05-26 13:03:09 -07003209 else
3210#endif
3211 netif_receive_skb(skb);
3212
Michael Chanb6016b72005-05-26 13:03:09 -07003213 rx_pkt++;
3214
3215next_rx:
Michael Chanb6016b72005-05-26 13:03:09 -07003216 sw_cons = NEXT_RX_BD(sw_cons);
3217 sw_prod = NEXT_RX_BD(sw_prod);
3218
3219 if ((rx_pkt == budget))
3220 break;
Michael Chanf4e418f2005-11-04 08:53:48 -08003221
3222 /* Refresh hw_cons to see if there is new work */
3223 if (sw_cons == hw_cons) {
Michael Chan35efa7c2007-12-20 19:56:37 -08003224 hw_cons = bnx2_get_hw_rx_cons(bnapi);
Michael Chanf4e418f2005-11-04 08:53:48 -08003225 rmb();
3226 }
Michael Chanb6016b72005-05-26 13:03:09 -07003227 }
Michael Chanbb4f98a2008-06-19 16:38:19 -07003228 rxr->rx_cons = sw_cons;
3229 rxr->rx_prod = sw_prod;
Michael Chanb6016b72005-05-26 13:03:09 -07003230
Michael Chan1db82f22007-12-12 11:19:35 -08003231 if (pg_ring_used)
Michael Chanbb4f98a2008-06-19 16:38:19 -07003232 REG_WR16(bp, rxr->rx_pg_bidx_addr, rxr->rx_pg_prod);
Michael Chan1db82f22007-12-12 11:19:35 -08003233
Michael Chanbb4f98a2008-06-19 16:38:19 -07003234 REG_WR16(bp, rxr->rx_bidx_addr, sw_prod);
Michael Chanb6016b72005-05-26 13:03:09 -07003235
Michael Chanbb4f98a2008-06-19 16:38:19 -07003236 REG_WR(bp, rxr->rx_bseq_addr, rxr->rx_prod_bseq);
Michael Chanb6016b72005-05-26 13:03:09 -07003237
3238 mmiowb();
3239
3240 return rx_pkt;
3241
3242}
3243
3244/* MSI ISR - The only difference between this and the INTx ISR
3245 * is that the MSI interrupt is always serviced.
3246 */
3247static irqreturn_t
David Howells7d12e782006-10-05 14:55:46 +01003248bnx2_msi(int irq, void *dev_instance)
Michael Chanb6016b72005-05-26 13:03:09 -07003249{
Michael Chanf0ea2e62008-06-19 16:41:57 -07003250 struct bnx2_napi *bnapi = dev_instance;
3251 struct bnx2 *bp = bnapi->bp;
Michael Chanb6016b72005-05-26 13:03:09 -07003252
Michael Chan43e80b82008-06-19 16:41:08 -07003253 prefetch(bnapi->status_blk.msi);
Michael Chanb6016b72005-05-26 13:03:09 -07003254 REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
3255 BNX2_PCICFG_INT_ACK_CMD_USE_INT_HC_PARAM |
3256 BNX2_PCICFG_INT_ACK_CMD_MASK_INT);
3257
3258 /* Return here if interrupt is disabled. */
Michael Chan73eef4c2005-08-25 15:39:15 -07003259 if (unlikely(atomic_read(&bp->intr_sem) != 0))
3260 return IRQ_HANDLED;
Michael Chanb6016b72005-05-26 13:03:09 -07003261
Ben Hutchings288379f2009-01-19 16:43:59 -08003262 napi_schedule(&bnapi->napi);
Michael Chanb6016b72005-05-26 13:03:09 -07003263
Michael Chan73eef4c2005-08-25 15:39:15 -07003264 return IRQ_HANDLED;
Michael Chanb6016b72005-05-26 13:03:09 -07003265}
3266
3267static irqreturn_t
Michael Chan8e6a72c2007-05-03 13:24:48 -07003268bnx2_msi_1shot(int irq, void *dev_instance)
3269{
Michael Chanf0ea2e62008-06-19 16:41:57 -07003270 struct bnx2_napi *bnapi = dev_instance;
3271 struct bnx2 *bp = bnapi->bp;
Michael Chan8e6a72c2007-05-03 13:24:48 -07003272
Michael Chan43e80b82008-06-19 16:41:08 -07003273 prefetch(bnapi->status_blk.msi);
Michael Chan8e6a72c2007-05-03 13:24:48 -07003274
3275 /* Return here if interrupt is disabled. */
3276 if (unlikely(atomic_read(&bp->intr_sem) != 0))
3277 return IRQ_HANDLED;
3278
Ben Hutchings288379f2009-01-19 16:43:59 -08003279 napi_schedule(&bnapi->napi);
Michael Chan8e6a72c2007-05-03 13:24:48 -07003280
3281 return IRQ_HANDLED;
3282}
3283
3284static irqreturn_t
David Howells7d12e782006-10-05 14:55:46 +01003285bnx2_interrupt(int irq, void *dev_instance)
Michael Chanb6016b72005-05-26 13:03:09 -07003286{
Michael Chanf0ea2e62008-06-19 16:41:57 -07003287 struct bnx2_napi *bnapi = dev_instance;
3288 struct bnx2 *bp = bnapi->bp;
Michael Chan43e80b82008-06-19 16:41:08 -07003289 struct status_block *sblk = bnapi->status_blk.msi;
Michael Chanb6016b72005-05-26 13:03:09 -07003290
3291 /* When using INTx, it is possible for the interrupt to arrive
3292 * at the CPU before the status block posted prior to the
3293 * interrupt. Reading a register will flush the status block.
3294 * When using MSI, the MSI message will always complete after
3295 * the status block write.
3296 */
Michael Chan35efa7c2007-12-20 19:56:37 -08003297 if ((sblk->status_idx == bnapi->last_status_idx) &&
Michael Chanb6016b72005-05-26 13:03:09 -07003298 (REG_RD(bp, BNX2_PCICFG_MISC_STATUS) &
3299 BNX2_PCICFG_MISC_STATUS_INTA_VALUE))
Michael Chan73eef4c2005-08-25 15:39:15 -07003300 return IRQ_NONE;
Michael Chanb6016b72005-05-26 13:03:09 -07003301
3302 REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
3303 BNX2_PCICFG_INT_ACK_CMD_USE_INT_HC_PARAM |
3304 BNX2_PCICFG_INT_ACK_CMD_MASK_INT);
3305
Michael Chanb8a7ce72007-07-07 22:51:03 -07003306 /* Read back to deassert IRQ immediately to avoid too many
3307 * spurious interrupts.
3308 */
3309 REG_RD(bp, BNX2_PCICFG_INT_ACK_CMD);
3310
Michael Chanb6016b72005-05-26 13:03:09 -07003311 /* Return here if interrupt is shared and is disabled. */
Michael Chan73eef4c2005-08-25 15:39:15 -07003312 if (unlikely(atomic_read(&bp->intr_sem) != 0))
3313 return IRQ_HANDLED;
Michael Chanb6016b72005-05-26 13:03:09 -07003314
Ben Hutchings288379f2009-01-19 16:43:59 -08003315 if (napi_schedule_prep(&bnapi->napi)) {
Michael Chan35efa7c2007-12-20 19:56:37 -08003316 bnapi->last_status_idx = sblk->status_idx;
Ben Hutchings288379f2009-01-19 16:43:59 -08003317 __napi_schedule(&bnapi->napi);
Michael Chanb8a7ce72007-07-07 22:51:03 -07003318 }
Michael Chanb6016b72005-05-26 13:03:09 -07003319
Michael Chan73eef4c2005-08-25 15:39:15 -07003320 return IRQ_HANDLED;
Michael Chanb6016b72005-05-26 13:03:09 -07003321}
3322
Michael Chan43e80b82008-06-19 16:41:08 -07003323static inline int
3324bnx2_has_fast_work(struct bnx2_napi *bnapi)
3325{
3326 struct bnx2_tx_ring_info *txr = &bnapi->tx_ring;
3327 struct bnx2_rx_ring_info *rxr = &bnapi->rx_ring;
3328
3329 if ((bnx2_get_hw_rx_cons(bnapi) != rxr->rx_cons) ||
3330 (bnx2_get_hw_tx_cons(bnapi) != txr->hw_tx_cons))
3331 return 1;
3332 return 0;
3333}
3334
Michael Chan0d8a6572007-07-07 22:49:43 -07003335#define STATUS_ATTN_EVENTS (STATUS_ATTN_BITS_LINK_STATE | \
3336 STATUS_ATTN_BITS_TIMER_ABORT)
Michael Chanda3e4fb2007-05-03 13:24:23 -07003337
Michael Chanf4e418f2005-11-04 08:53:48 -08003338static inline int
Michael Chan35efa7c2007-12-20 19:56:37 -08003339bnx2_has_work(struct bnx2_napi *bnapi)
Michael Chanf4e418f2005-11-04 08:53:48 -08003340{
Michael Chan43e80b82008-06-19 16:41:08 -07003341 struct status_block *sblk = bnapi->status_blk.msi;
Michael Chanf4e418f2005-11-04 08:53:48 -08003342
Michael Chan43e80b82008-06-19 16:41:08 -07003343 if (bnx2_has_fast_work(bnapi))
Michael Chanf4e418f2005-11-04 08:53:48 -08003344 return 1;
3345
Michael Chan4edd4732009-06-08 18:14:42 -07003346#ifdef BCM_CNIC
3347 if (bnapi->cnic_present && (bnapi->cnic_tag != sblk->status_idx))
3348 return 1;
3349#endif
3350
Michael Chanda3e4fb2007-05-03 13:24:23 -07003351 if ((sblk->status_attn_bits & STATUS_ATTN_EVENTS) !=
3352 (sblk->status_attn_bits_ack & STATUS_ATTN_EVENTS))
Michael Chanf4e418f2005-11-04 08:53:48 -08003353 return 1;
3354
3355 return 0;
3356}
3357
Michael Chanefba0182008-12-03 00:36:15 -08003358static void
3359bnx2_chk_missed_msi(struct bnx2 *bp)
3360{
3361 struct bnx2_napi *bnapi = &bp->bnx2_napi[0];
3362 u32 msi_ctrl;
3363
3364 if (bnx2_has_work(bnapi)) {
3365 msi_ctrl = REG_RD(bp, BNX2_PCICFG_MSI_CONTROL);
3366 if (!(msi_ctrl & BNX2_PCICFG_MSI_CONTROL_ENABLE))
3367 return;
3368
3369 if (bnapi->last_status_idx == bp->idle_chk_status_idx) {
3370 REG_WR(bp, BNX2_PCICFG_MSI_CONTROL, msi_ctrl &
3371 ~BNX2_PCICFG_MSI_CONTROL_ENABLE);
3372 REG_WR(bp, BNX2_PCICFG_MSI_CONTROL, msi_ctrl);
3373 bnx2_msi(bp->irq_tbl[0].vector, bnapi);
3374 }
3375 }
3376
3377 bp->idle_chk_status_idx = bnapi->last_status_idx;
3378}
3379
Michael Chan4edd4732009-06-08 18:14:42 -07003380#ifdef BCM_CNIC
3381static void bnx2_poll_cnic(struct bnx2 *bp, struct bnx2_napi *bnapi)
3382{
3383 struct cnic_ops *c_ops;
3384
3385 if (!bnapi->cnic_present)
3386 return;
3387
3388 rcu_read_lock();
3389 c_ops = rcu_dereference(bp->cnic_ops);
3390 if (c_ops)
3391 bnapi->cnic_tag = c_ops->cnic_handler(bp->cnic_data,
3392 bnapi->status_blk.msi);
3393 rcu_read_unlock();
3394}
3395#endif
3396
Michael Chan43e80b82008-06-19 16:41:08 -07003397static void bnx2_poll_link(struct bnx2 *bp, struct bnx2_napi *bnapi)
Michael Chanb6016b72005-05-26 13:03:09 -07003398{
Michael Chan43e80b82008-06-19 16:41:08 -07003399 struct status_block *sblk = bnapi->status_blk.msi;
Michael Chanda3e4fb2007-05-03 13:24:23 -07003400 u32 status_attn_bits = sblk->status_attn_bits;
3401 u32 status_attn_bits_ack = sblk->status_attn_bits_ack;
Michael Chanb6016b72005-05-26 13:03:09 -07003402
Michael Chanda3e4fb2007-05-03 13:24:23 -07003403 if ((status_attn_bits & STATUS_ATTN_EVENTS) !=
3404 (status_attn_bits_ack & STATUS_ATTN_EVENTS)) {
Michael Chanb6016b72005-05-26 13:03:09 -07003405
Michael Chan35efa7c2007-12-20 19:56:37 -08003406 bnx2_phy_int(bp, bnapi);
Michael Chanbf5295b2006-03-23 01:11:56 -08003407
3408 /* This is needed to take care of transient status
3409 * during link changes.
3410 */
3411 REG_WR(bp, BNX2_HC_COMMAND,
3412 bp->hc_cmd | BNX2_HC_COMMAND_COAL_NOW_WO_INT);
3413 REG_RD(bp, BNX2_HC_COMMAND);
Michael Chanb6016b72005-05-26 13:03:09 -07003414 }
Michael Chan43e80b82008-06-19 16:41:08 -07003415}
3416
3417static int bnx2_poll_work(struct bnx2 *bp, struct bnx2_napi *bnapi,
3418 int work_done, int budget)
3419{
3420 struct bnx2_tx_ring_info *txr = &bnapi->tx_ring;
3421 struct bnx2_rx_ring_info *rxr = &bnapi->rx_ring;
Michael Chanb6016b72005-05-26 13:03:09 -07003422
Michael Chan35e90102008-06-19 16:37:42 -07003423 if (bnx2_get_hw_tx_cons(bnapi) != txr->hw_tx_cons)
Michael Chan57851d82007-12-20 20:01:44 -08003424 bnx2_tx_int(bp, bnapi, 0);
Michael Chanb6016b72005-05-26 13:03:09 -07003425
Michael Chanbb4f98a2008-06-19 16:38:19 -07003426 if (bnx2_get_hw_rx_cons(bnapi) != rxr->rx_cons)
Michael Chan35efa7c2007-12-20 19:56:37 -08003427 work_done += bnx2_rx_int(bp, bnapi, budget - work_done);
Jeff Garzik6aa20a22006-09-13 13:24:59 -04003428
David S. Miller6f535762007-10-11 18:08:29 -07003429 return work_done;
3430}
Michael Chanf4e418f2005-11-04 08:53:48 -08003431
Michael Chanf0ea2e62008-06-19 16:41:57 -07003432static int bnx2_poll_msix(struct napi_struct *napi, int budget)
3433{
3434 struct bnx2_napi *bnapi = container_of(napi, struct bnx2_napi, napi);
3435 struct bnx2 *bp = bnapi->bp;
3436 int work_done = 0;
3437 struct status_block_msix *sblk = bnapi->status_blk.msix;
3438
3439 while (1) {
3440 work_done = bnx2_poll_work(bp, bnapi, work_done, budget);
3441 if (unlikely(work_done >= budget))
3442 break;
3443
3444 bnapi->last_status_idx = sblk->status_idx;
3445 /* status idx must be read before checking for more work. */
3446 rmb();
3447 if (likely(!bnx2_has_fast_work(bnapi))) {
3448
Ben Hutchings288379f2009-01-19 16:43:59 -08003449 napi_complete(napi);
Michael Chanf0ea2e62008-06-19 16:41:57 -07003450 REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD, bnapi->int_num |
3451 BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
3452 bnapi->last_status_idx);
3453 break;
3454 }
3455 }
3456 return work_done;
3457}
3458
David S. Miller6f535762007-10-11 18:08:29 -07003459static int bnx2_poll(struct napi_struct *napi, int budget)
3460{
Michael Chan35efa7c2007-12-20 19:56:37 -08003461 struct bnx2_napi *bnapi = container_of(napi, struct bnx2_napi, napi);
3462 struct bnx2 *bp = bnapi->bp;
David S. Miller6f535762007-10-11 18:08:29 -07003463 int work_done = 0;
Michael Chan43e80b82008-06-19 16:41:08 -07003464 struct status_block *sblk = bnapi->status_blk.msi;
David S. Miller6f535762007-10-11 18:08:29 -07003465
3466 while (1) {
Michael Chan43e80b82008-06-19 16:41:08 -07003467 bnx2_poll_link(bp, bnapi);
3468
Michael Chan35efa7c2007-12-20 19:56:37 -08003469 work_done = bnx2_poll_work(bp, bnapi, work_done, budget);
David S. Miller6f535762007-10-11 18:08:29 -07003470
Michael Chan4edd4732009-06-08 18:14:42 -07003471#ifdef BCM_CNIC
3472 bnx2_poll_cnic(bp, bnapi);
3473#endif
3474
Michael Chan35efa7c2007-12-20 19:56:37 -08003475 /* bnapi->last_status_idx is used below to tell the hw how
Michael Chan6dee6422007-10-12 01:40:38 -07003476 * much work has been processed, so we must read it before
3477 * checking for more work.
3478 */
Michael Chan35efa7c2007-12-20 19:56:37 -08003479 bnapi->last_status_idx = sblk->status_idx;
Michael Chanefba0182008-12-03 00:36:15 -08003480
3481 if (unlikely(work_done >= budget))
3482 break;
3483
Michael Chan6dee6422007-10-12 01:40:38 -07003484 rmb();
Michael Chan35efa7c2007-12-20 19:56:37 -08003485 if (likely(!bnx2_has_work(bnapi))) {
Ben Hutchings288379f2009-01-19 16:43:59 -08003486 napi_complete(napi);
David S. Millerf86e82f2008-01-21 17:15:40 -08003487 if (likely(bp->flags & BNX2_FLAG_USING_MSI_OR_MSIX)) {
David S. Miller6f535762007-10-11 18:08:29 -07003488 REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
3489 BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
Michael Chan35efa7c2007-12-20 19:56:37 -08003490 bnapi->last_status_idx);
Michael Chan6dee6422007-10-12 01:40:38 -07003491 break;
David S. Miller6f535762007-10-11 18:08:29 -07003492 }
3493 REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
3494 BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
3495 BNX2_PCICFG_INT_ACK_CMD_MASK_INT |
Michael Chan35efa7c2007-12-20 19:56:37 -08003496 bnapi->last_status_idx);
David S. Miller6f535762007-10-11 18:08:29 -07003497
Michael Chan1269a8a2006-01-23 16:11:03 -08003498 REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
3499 BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
Michael Chan35efa7c2007-12-20 19:56:37 -08003500 bnapi->last_status_idx);
David S. Miller6f535762007-10-11 18:08:29 -07003501 break;
Michael Chan1269a8a2006-01-23 16:11:03 -08003502 }
Michael Chanb6016b72005-05-26 13:03:09 -07003503 }
3504
Stephen Hemmingerbea33482007-10-03 16:41:36 -07003505 return work_done;
Michael Chanb6016b72005-05-26 13:03:09 -07003506}
3507
Herbert Xu932ff272006-06-09 12:20:56 -07003508/* Called with rtnl_lock from vlan functions and also netif_tx_lock
Michael Chanb6016b72005-05-26 13:03:09 -07003509 * from set_multicast.
3510 */
3511static void
3512bnx2_set_rx_mode(struct net_device *dev)
3513{
Michael Chan972ec0d2006-01-23 16:12:43 -08003514 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07003515 u32 rx_mode, sort_mode;
Jiri Pirkoccffad252009-05-22 23:22:17 +00003516 struct netdev_hw_addr *ha;
Michael Chanb6016b72005-05-26 13:03:09 -07003517 int i;
Michael Chanb6016b72005-05-26 13:03:09 -07003518
Michael Chan9f52b562008-10-09 12:21:46 -07003519 if (!netif_running(dev))
3520 return;
3521
Michael Chanc770a652005-08-25 15:38:39 -07003522 spin_lock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07003523
3524 rx_mode = bp->rx_mode & ~(BNX2_EMAC_RX_MODE_PROMISCUOUS |
3525 BNX2_EMAC_RX_MODE_KEEP_VLAN_TAG);
3526 sort_mode = 1 | BNX2_RPM_SORT_USER0_BC_EN;
3527#ifdef BCM_VLAN
Michael Chan7c6337a2008-08-14 15:29:09 -07003528 if (!bp->vlgrp && (bp->flags & BNX2_FLAG_CAN_KEEP_VLAN))
Michael Chanb6016b72005-05-26 13:03:09 -07003529 rx_mode |= BNX2_EMAC_RX_MODE_KEEP_VLAN_TAG;
Michael Chanb6016b72005-05-26 13:03:09 -07003530#else
Michael Chan7c6337a2008-08-14 15:29:09 -07003531 if (bp->flags & BNX2_FLAG_CAN_KEEP_VLAN)
Michael Chane29054f2006-01-23 16:06:06 -08003532 rx_mode |= BNX2_EMAC_RX_MODE_KEEP_VLAN_TAG;
Michael Chanb6016b72005-05-26 13:03:09 -07003533#endif
3534 if (dev->flags & IFF_PROMISC) {
3535 /* Promiscuous mode. */
3536 rx_mode |= BNX2_EMAC_RX_MODE_PROMISCUOUS;
Michael Chan75108732006-11-19 14:06:40 -08003537 sort_mode |= BNX2_RPM_SORT_USER0_PROM_EN |
3538 BNX2_RPM_SORT_USER0_PROM_VLAN;
Michael Chanb6016b72005-05-26 13:03:09 -07003539 }
3540 else if (dev->flags & IFF_ALLMULTI) {
3541 for (i = 0; i < NUM_MC_HASH_REGISTERS; i++) {
3542 REG_WR(bp, BNX2_EMAC_MULTICAST_HASH0 + (i * 4),
3543 0xffffffff);
3544 }
3545 sort_mode |= BNX2_RPM_SORT_USER0_MC_EN;
3546 }
3547 else {
3548 /* Accept one or more multicast(s). */
Michael Chanb6016b72005-05-26 13:03:09 -07003549 u32 mc_filter[NUM_MC_HASH_REGISTERS];
3550 u32 regidx;
3551 u32 bit;
3552 u32 crc;
3553
3554 memset(mc_filter, 0, 4 * NUM_MC_HASH_REGISTERS);
3555
Jiri Pirko22bedad32010-04-01 21:22:57 +00003556 netdev_for_each_mc_addr(ha, dev) {
3557 crc = ether_crc_le(ETH_ALEN, ha->addr);
Michael Chanb6016b72005-05-26 13:03:09 -07003558 bit = crc & 0xff;
3559 regidx = (bit & 0xe0) >> 5;
3560 bit &= 0x1f;
3561 mc_filter[regidx] |= (1 << bit);
3562 }
3563
3564 for (i = 0; i < NUM_MC_HASH_REGISTERS; i++) {
3565 REG_WR(bp, BNX2_EMAC_MULTICAST_HASH0 + (i * 4),
3566 mc_filter[i]);
3567 }
3568
3569 sort_mode |= BNX2_RPM_SORT_USER0_MC_HSH_EN;
3570 }
3571
Jiri Pirko32e7bfc2010-01-25 13:36:10 -08003572 if (netdev_uc_count(dev) > BNX2_MAX_UNICAST_ADDRESSES) {
Benjamin Li5fcaed02008-07-14 22:39:52 -07003573 rx_mode |= BNX2_EMAC_RX_MODE_PROMISCUOUS;
3574 sort_mode |= BNX2_RPM_SORT_USER0_PROM_EN |
3575 BNX2_RPM_SORT_USER0_PROM_VLAN;
3576 } else if (!(dev->flags & IFF_PROMISC)) {
Benjamin Li5fcaed02008-07-14 22:39:52 -07003577 /* Add all entries into to the match filter list */
Jiri Pirkoccffad252009-05-22 23:22:17 +00003578 i = 0;
Jiri Pirko32e7bfc2010-01-25 13:36:10 -08003579 netdev_for_each_uc_addr(ha, dev) {
Jiri Pirkoccffad252009-05-22 23:22:17 +00003580 bnx2_set_mac_addr(bp, ha->addr,
Benjamin Li5fcaed02008-07-14 22:39:52 -07003581 i + BNX2_START_UNICAST_ADDRESS_INDEX);
3582 sort_mode |= (1 <<
3583 (i + BNX2_START_UNICAST_ADDRESS_INDEX));
Jiri Pirkoccffad252009-05-22 23:22:17 +00003584 i++;
Benjamin Li5fcaed02008-07-14 22:39:52 -07003585 }
3586
3587 }
3588
Michael Chanb6016b72005-05-26 13:03:09 -07003589 if (rx_mode != bp->rx_mode) {
3590 bp->rx_mode = rx_mode;
3591 REG_WR(bp, BNX2_EMAC_RX_MODE, rx_mode);
3592 }
3593
3594 REG_WR(bp, BNX2_RPM_SORT_USER0, 0x0);
3595 REG_WR(bp, BNX2_RPM_SORT_USER0, sort_mode);
3596 REG_WR(bp, BNX2_RPM_SORT_USER0, sort_mode | BNX2_RPM_SORT_USER0_ENA);
3597
Michael Chanc770a652005-08-25 15:38:39 -07003598 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07003599}
3600
Michael Chan57579f72009-04-04 16:51:14 -07003601static int __devinit
3602check_fw_section(const struct firmware *fw,
3603 const struct bnx2_fw_file_section *section,
3604 u32 alignment, bool non_empty)
Michael Chanb6016b72005-05-26 13:03:09 -07003605{
Michael Chan57579f72009-04-04 16:51:14 -07003606 u32 offset = be32_to_cpu(section->offset);
3607 u32 len = be32_to_cpu(section->len);
Michael Chanb6016b72005-05-26 13:03:09 -07003608
Michael Chan57579f72009-04-04 16:51:14 -07003609 if ((offset == 0 && len != 0) || offset >= fw->size || offset & 3)
3610 return -EINVAL;
3611 if ((non_empty && len == 0) || len > fw->size - offset ||
3612 len & (alignment - 1))
3613 return -EINVAL;
3614 return 0;
3615}
3616
3617static int __devinit
3618check_mips_fw_entry(const struct firmware *fw,
3619 const struct bnx2_mips_fw_file_entry *entry)
3620{
3621 if (check_fw_section(fw, &entry->text, 4, true) ||
3622 check_fw_section(fw, &entry->data, 4, false) ||
3623 check_fw_section(fw, &entry->rodata, 4, false))
3624 return -EINVAL;
3625 return 0;
3626}
3627
3628static int __devinit
3629bnx2_request_firmware(struct bnx2 *bp)
3630{
3631 const char *mips_fw_file, *rv2p_fw_file;
Bastian Blank5ee1c322009-04-08 15:50:07 -07003632 const struct bnx2_mips_fw_file *mips_fw;
3633 const struct bnx2_rv2p_fw_file *rv2p_fw;
Michael Chan57579f72009-04-04 16:51:14 -07003634 int rc;
3635
3636 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
3637 mips_fw_file = FW_MIPS_FILE_09;
Michael Chan078b0732009-08-29 00:02:46 -07003638 if ((CHIP_ID(bp) == CHIP_ID_5709_A0) ||
3639 (CHIP_ID(bp) == CHIP_ID_5709_A1))
3640 rv2p_fw_file = FW_RV2P_FILE_09_Ax;
3641 else
3642 rv2p_fw_file = FW_RV2P_FILE_09;
Michael Chan57579f72009-04-04 16:51:14 -07003643 } else {
3644 mips_fw_file = FW_MIPS_FILE_06;
3645 rv2p_fw_file = FW_RV2P_FILE_06;
3646 }
3647
3648 rc = request_firmware(&bp->mips_firmware, mips_fw_file, &bp->pdev->dev);
3649 if (rc) {
Joe Perches3a9c6a42010-02-17 15:01:51 +00003650 pr_err("Can't load firmware file \"%s\"\n", mips_fw_file);
Michael Chan57579f72009-04-04 16:51:14 -07003651 return rc;
3652 }
3653
3654 rc = request_firmware(&bp->rv2p_firmware, rv2p_fw_file, &bp->pdev->dev);
3655 if (rc) {
Joe Perches3a9c6a42010-02-17 15:01:51 +00003656 pr_err("Can't load firmware file \"%s\"\n", rv2p_fw_file);
Michael Chan57579f72009-04-04 16:51:14 -07003657 return rc;
3658 }
Bastian Blank5ee1c322009-04-08 15:50:07 -07003659 mips_fw = (const struct bnx2_mips_fw_file *) bp->mips_firmware->data;
3660 rv2p_fw = (const struct bnx2_rv2p_fw_file *) bp->rv2p_firmware->data;
3661 if (bp->mips_firmware->size < sizeof(*mips_fw) ||
3662 check_mips_fw_entry(bp->mips_firmware, &mips_fw->com) ||
3663 check_mips_fw_entry(bp->mips_firmware, &mips_fw->cp) ||
3664 check_mips_fw_entry(bp->mips_firmware, &mips_fw->rxp) ||
3665 check_mips_fw_entry(bp->mips_firmware, &mips_fw->tpat) ||
3666 check_mips_fw_entry(bp->mips_firmware, &mips_fw->txp)) {
Joe Perches3a9c6a42010-02-17 15:01:51 +00003667 pr_err("Firmware file \"%s\" is invalid\n", mips_fw_file);
Michael Chan57579f72009-04-04 16:51:14 -07003668 return -EINVAL;
3669 }
Bastian Blank5ee1c322009-04-08 15:50:07 -07003670 if (bp->rv2p_firmware->size < sizeof(*rv2p_fw) ||
3671 check_fw_section(bp->rv2p_firmware, &rv2p_fw->proc1.rv2p, 8, true) ||
3672 check_fw_section(bp->rv2p_firmware, &rv2p_fw->proc2.rv2p, 8, true)) {
Joe Perches3a9c6a42010-02-17 15:01:51 +00003673 pr_err("Firmware file \"%s\" is invalid\n", rv2p_fw_file);
Michael Chan57579f72009-04-04 16:51:14 -07003674 return -EINVAL;
3675 }
3676
3677 return 0;
3678}
3679
3680static u32
3681rv2p_fw_fixup(u32 rv2p_proc, int idx, u32 loc, u32 rv2p_code)
3682{
3683 switch (idx) {
3684 case RV2P_P1_FIXUP_PAGE_SIZE_IDX:
3685 rv2p_code &= ~RV2P_BD_PAGE_SIZE_MSK;
3686 rv2p_code |= RV2P_BD_PAGE_SIZE;
3687 break;
3688 }
3689 return rv2p_code;
3690}
3691
3692static int
3693load_rv2p_fw(struct bnx2 *bp, u32 rv2p_proc,
3694 const struct bnx2_rv2p_fw_file_entry *fw_entry)
3695{
3696 u32 rv2p_code_len, file_offset;
3697 __be32 *rv2p_code;
3698 int i;
3699 u32 val, cmd, addr;
3700
3701 rv2p_code_len = be32_to_cpu(fw_entry->rv2p.len);
3702 file_offset = be32_to_cpu(fw_entry->rv2p.offset);
3703
3704 rv2p_code = (__be32 *)(bp->rv2p_firmware->data + file_offset);
3705
3706 if (rv2p_proc == RV2P_PROC1) {
3707 cmd = BNX2_RV2P_PROC1_ADDR_CMD_RDWR;
3708 addr = BNX2_RV2P_PROC1_ADDR_CMD;
3709 } else {
3710 cmd = BNX2_RV2P_PROC2_ADDR_CMD_RDWR;
3711 addr = BNX2_RV2P_PROC2_ADDR_CMD;
Michael Chand25be1d2008-05-02 16:57:59 -07003712 }
Michael Chanb6016b72005-05-26 13:03:09 -07003713
3714 for (i = 0; i < rv2p_code_len; i += 8) {
Michael Chan57579f72009-04-04 16:51:14 -07003715 REG_WR(bp, BNX2_RV2P_INSTR_HIGH, be32_to_cpu(*rv2p_code));
Michael Chanb6016b72005-05-26 13:03:09 -07003716 rv2p_code++;
Michael Chan57579f72009-04-04 16:51:14 -07003717 REG_WR(bp, BNX2_RV2P_INSTR_LOW, be32_to_cpu(*rv2p_code));
Michael Chanb6016b72005-05-26 13:03:09 -07003718 rv2p_code++;
3719
Michael Chan57579f72009-04-04 16:51:14 -07003720 val = (i / 8) | cmd;
3721 REG_WR(bp, addr, val);
3722 }
3723
3724 rv2p_code = (__be32 *)(bp->rv2p_firmware->data + file_offset);
3725 for (i = 0; i < 8; i++) {
3726 u32 loc, code;
3727
3728 loc = be32_to_cpu(fw_entry->fixup[i]);
3729 if (loc && ((loc * 4) < rv2p_code_len)) {
3730 code = be32_to_cpu(*(rv2p_code + loc - 1));
3731 REG_WR(bp, BNX2_RV2P_INSTR_HIGH, code);
3732 code = be32_to_cpu(*(rv2p_code + loc));
3733 code = rv2p_fw_fixup(rv2p_proc, i, loc, code);
3734 REG_WR(bp, BNX2_RV2P_INSTR_LOW, code);
3735
3736 val = (loc / 2) | cmd;
3737 REG_WR(bp, addr, val);
Michael Chanb6016b72005-05-26 13:03:09 -07003738 }
3739 }
3740
3741 /* Reset the processor, un-stall is done later. */
3742 if (rv2p_proc == RV2P_PROC1) {
3743 REG_WR(bp, BNX2_RV2P_COMMAND, BNX2_RV2P_COMMAND_PROC1_RESET);
3744 }
3745 else {
3746 REG_WR(bp, BNX2_RV2P_COMMAND, BNX2_RV2P_COMMAND_PROC2_RESET);
3747 }
Michael Chan57579f72009-04-04 16:51:14 -07003748
3749 return 0;
Michael Chanb6016b72005-05-26 13:03:09 -07003750}
3751
Michael Chanaf3ee512006-11-19 14:09:25 -08003752static int
Michael Chan57579f72009-04-04 16:51:14 -07003753load_cpu_fw(struct bnx2 *bp, const struct cpu_reg *cpu_reg,
3754 const struct bnx2_mips_fw_file_entry *fw_entry)
Michael Chanb6016b72005-05-26 13:03:09 -07003755{
Michael Chan57579f72009-04-04 16:51:14 -07003756 u32 addr, len, file_offset;
3757 __be32 *data;
Michael Chanb6016b72005-05-26 13:03:09 -07003758 u32 offset;
3759 u32 val;
3760
3761 /* Halt the CPU. */
Michael Chan2726d6e2008-01-29 21:35:05 -08003762 val = bnx2_reg_rd_ind(bp, cpu_reg->mode);
Michael Chanb6016b72005-05-26 13:03:09 -07003763 val |= cpu_reg->mode_value_halt;
Michael Chan2726d6e2008-01-29 21:35:05 -08003764 bnx2_reg_wr_ind(bp, cpu_reg->mode, val);
3765 bnx2_reg_wr_ind(bp, cpu_reg->state, cpu_reg->state_value_clear);
Michael Chanb6016b72005-05-26 13:03:09 -07003766
3767 /* Load the Text area. */
Michael Chan57579f72009-04-04 16:51:14 -07003768 addr = be32_to_cpu(fw_entry->text.addr);
3769 len = be32_to_cpu(fw_entry->text.len);
3770 file_offset = be32_to_cpu(fw_entry->text.offset);
3771 data = (__be32 *)(bp->mips_firmware->data + file_offset);
3772
3773 offset = cpu_reg->spad_base + (addr - cpu_reg->mips_view_base);
3774 if (len) {
Michael Chanb6016b72005-05-26 13:03:09 -07003775 int j;
3776
Michael Chan57579f72009-04-04 16:51:14 -07003777 for (j = 0; j < (len / 4); j++, offset += 4)
3778 bnx2_reg_wr_ind(bp, offset, be32_to_cpu(data[j]));
Michael Chanb6016b72005-05-26 13:03:09 -07003779 }
3780
3781 /* Load the Data area. */
Michael Chan57579f72009-04-04 16:51:14 -07003782 addr = be32_to_cpu(fw_entry->data.addr);
3783 len = be32_to_cpu(fw_entry->data.len);
3784 file_offset = be32_to_cpu(fw_entry->data.offset);
3785 data = (__be32 *)(bp->mips_firmware->data + file_offset);
3786
3787 offset = cpu_reg->spad_base + (addr - cpu_reg->mips_view_base);
3788 if (len) {
Michael Chanb6016b72005-05-26 13:03:09 -07003789 int j;
3790
Michael Chan57579f72009-04-04 16:51:14 -07003791 for (j = 0; j < (len / 4); j++, offset += 4)
3792 bnx2_reg_wr_ind(bp, offset, be32_to_cpu(data[j]));
Michael Chanb6016b72005-05-26 13:03:09 -07003793 }
3794
3795 /* Load the Read-Only area. */
Michael Chan57579f72009-04-04 16:51:14 -07003796 addr = be32_to_cpu(fw_entry->rodata.addr);
3797 len = be32_to_cpu(fw_entry->rodata.len);
3798 file_offset = be32_to_cpu(fw_entry->rodata.offset);
3799 data = (__be32 *)(bp->mips_firmware->data + file_offset);
3800
3801 offset = cpu_reg->spad_base + (addr - cpu_reg->mips_view_base);
3802 if (len) {
Michael Chanb6016b72005-05-26 13:03:09 -07003803 int j;
3804
Michael Chan57579f72009-04-04 16:51:14 -07003805 for (j = 0; j < (len / 4); j++, offset += 4)
3806 bnx2_reg_wr_ind(bp, offset, be32_to_cpu(data[j]));
Michael Chanb6016b72005-05-26 13:03:09 -07003807 }
3808
3809 /* Clear the pre-fetch instruction. */
Michael Chan2726d6e2008-01-29 21:35:05 -08003810 bnx2_reg_wr_ind(bp, cpu_reg->inst, 0);
Michael Chan57579f72009-04-04 16:51:14 -07003811
3812 val = be32_to_cpu(fw_entry->start_addr);
3813 bnx2_reg_wr_ind(bp, cpu_reg->pc, val);
Michael Chanb6016b72005-05-26 13:03:09 -07003814
3815 /* Start the CPU. */
Michael Chan2726d6e2008-01-29 21:35:05 -08003816 val = bnx2_reg_rd_ind(bp, cpu_reg->mode);
Michael Chanb6016b72005-05-26 13:03:09 -07003817 val &= ~cpu_reg->mode_value_halt;
Michael Chan2726d6e2008-01-29 21:35:05 -08003818 bnx2_reg_wr_ind(bp, cpu_reg->state, cpu_reg->state_value_clear);
3819 bnx2_reg_wr_ind(bp, cpu_reg->mode, val);
Michael Chanaf3ee512006-11-19 14:09:25 -08003820
3821 return 0;
Michael Chanb6016b72005-05-26 13:03:09 -07003822}
3823
Michael Chanfba9fe92006-06-12 22:21:25 -07003824static int
Michael Chanb6016b72005-05-26 13:03:09 -07003825bnx2_init_cpus(struct bnx2 *bp)
3826{
Michael Chan57579f72009-04-04 16:51:14 -07003827 const struct bnx2_mips_fw_file *mips_fw =
3828 (const struct bnx2_mips_fw_file *) bp->mips_firmware->data;
3829 const struct bnx2_rv2p_fw_file *rv2p_fw =
3830 (const struct bnx2_rv2p_fw_file *) bp->rv2p_firmware->data;
3831 int rc;
Michael Chanb6016b72005-05-26 13:03:09 -07003832
3833 /* Initialize the RV2P processor. */
Michael Chan57579f72009-04-04 16:51:14 -07003834 load_rv2p_fw(bp, RV2P_PROC1, &rv2p_fw->proc1);
3835 load_rv2p_fw(bp, RV2P_PROC2, &rv2p_fw->proc2);
Michael Chanb6016b72005-05-26 13:03:09 -07003836
3837 /* Initialize the RX Processor. */
Michael Chan57579f72009-04-04 16:51:14 -07003838 rc = load_cpu_fw(bp, &cpu_reg_rxp, &mips_fw->rxp);
Michael Chanfba9fe92006-06-12 22:21:25 -07003839 if (rc)
3840 goto init_cpu_err;
3841
Michael Chanb6016b72005-05-26 13:03:09 -07003842 /* Initialize the TX Processor. */
Michael Chan57579f72009-04-04 16:51:14 -07003843 rc = load_cpu_fw(bp, &cpu_reg_txp, &mips_fw->txp);
Michael Chanfba9fe92006-06-12 22:21:25 -07003844 if (rc)
3845 goto init_cpu_err;
3846
Michael Chanb6016b72005-05-26 13:03:09 -07003847 /* Initialize the TX Patch-up Processor. */
Michael Chan57579f72009-04-04 16:51:14 -07003848 rc = load_cpu_fw(bp, &cpu_reg_tpat, &mips_fw->tpat);
Michael Chanfba9fe92006-06-12 22:21:25 -07003849 if (rc)
3850 goto init_cpu_err;
3851
Michael Chanb6016b72005-05-26 13:03:09 -07003852 /* Initialize the Completion Processor. */
Michael Chan57579f72009-04-04 16:51:14 -07003853 rc = load_cpu_fw(bp, &cpu_reg_com, &mips_fw->com);
Michael Chanfba9fe92006-06-12 22:21:25 -07003854 if (rc)
3855 goto init_cpu_err;
3856
Michael Chand43584c2006-11-19 14:14:35 -08003857 /* Initialize the Command Processor. */
Michael Chan57579f72009-04-04 16:51:14 -07003858 rc = load_cpu_fw(bp, &cpu_reg_cp, &mips_fw->cp);
Michael Chan110d0ef2007-12-12 11:18:34 -08003859
Michael Chanfba9fe92006-06-12 22:21:25 -07003860init_cpu_err:
Michael Chanfba9fe92006-06-12 22:21:25 -07003861 return rc;
Michael Chanb6016b72005-05-26 13:03:09 -07003862}
3863
3864static int
Pavel Machek829ca9a2005-09-03 15:56:56 -07003865bnx2_set_power_state(struct bnx2 *bp, pci_power_t state)
Michael Chanb6016b72005-05-26 13:03:09 -07003866{
3867 u16 pmcsr;
3868
3869 pci_read_config_word(bp->pdev, bp->pm_cap + PCI_PM_CTRL, &pmcsr);
3870
3871 switch (state) {
Pavel Machek829ca9a2005-09-03 15:56:56 -07003872 case PCI_D0: {
Michael Chanb6016b72005-05-26 13:03:09 -07003873 u32 val;
3874
3875 pci_write_config_word(bp->pdev, bp->pm_cap + PCI_PM_CTRL,
3876 (pmcsr & ~PCI_PM_CTRL_STATE_MASK) |
3877 PCI_PM_CTRL_PME_STATUS);
3878
3879 if (pmcsr & PCI_PM_CTRL_STATE_MASK)
3880 /* delay required during transition out of D3hot */
3881 msleep(20);
3882
3883 val = REG_RD(bp, BNX2_EMAC_MODE);
3884 val |= BNX2_EMAC_MODE_MPKT_RCVD | BNX2_EMAC_MODE_ACPI_RCVD;
3885 val &= ~BNX2_EMAC_MODE_MPKT;
3886 REG_WR(bp, BNX2_EMAC_MODE, val);
3887
3888 val = REG_RD(bp, BNX2_RPM_CONFIG);
3889 val &= ~BNX2_RPM_CONFIG_ACPI_ENA;
3890 REG_WR(bp, BNX2_RPM_CONFIG, val);
3891 break;
3892 }
Pavel Machek829ca9a2005-09-03 15:56:56 -07003893 case PCI_D3hot: {
Michael Chanb6016b72005-05-26 13:03:09 -07003894 int i;
3895 u32 val, wol_msg;
3896
3897 if (bp->wol) {
3898 u32 advertising;
3899 u8 autoneg;
3900
3901 autoneg = bp->autoneg;
3902 advertising = bp->advertising;
3903
Michael Chan239cd342007-10-17 19:26:15 -07003904 if (bp->phy_port == PORT_TP) {
3905 bp->autoneg = AUTONEG_SPEED;
3906 bp->advertising = ADVERTISED_10baseT_Half |
3907 ADVERTISED_10baseT_Full |
3908 ADVERTISED_100baseT_Half |
3909 ADVERTISED_100baseT_Full |
3910 ADVERTISED_Autoneg;
3911 }
Michael Chanb6016b72005-05-26 13:03:09 -07003912
Michael Chan239cd342007-10-17 19:26:15 -07003913 spin_lock_bh(&bp->phy_lock);
3914 bnx2_setup_phy(bp, bp->phy_port);
3915 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07003916
3917 bp->autoneg = autoneg;
3918 bp->advertising = advertising;
3919
Benjamin Li5fcaed02008-07-14 22:39:52 -07003920 bnx2_set_mac_addr(bp, bp->dev->dev_addr, 0);
Michael Chanb6016b72005-05-26 13:03:09 -07003921
3922 val = REG_RD(bp, BNX2_EMAC_MODE);
3923
3924 /* Enable port mode. */
3925 val &= ~BNX2_EMAC_MODE_PORT;
Michael Chan239cd342007-10-17 19:26:15 -07003926 val |= BNX2_EMAC_MODE_MPKT_RCVD |
Michael Chanb6016b72005-05-26 13:03:09 -07003927 BNX2_EMAC_MODE_ACPI_RCVD |
Michael Chanb6016b72005-05-26 13:03:09 -07003928 BNX2_EMAC_MODE_MPKT;
Michael Chan239cd342007-10-17 19:26:15 -07003929 if (bp->phy_port == PORT_TP)
3930 val |= BNX2_EMAC_MODE_PORT_MII;
3931 else {
3932 val |= BNX2_EMAC_MODE_PORT_GMII;
3933 if (bp->line_speed == SPEED_2500)
3934 val |= BNX2_EMAC_MODE_25G_MODE;
3935 }
Michael Chanb6016b72005-05-26 13:03:09 -07003936
3937 REG_WR(bp, BNX2_EMAC_MODE, val);
3938
3939 /* receive all multicast */
3940 for (i = 0; i < NUM_MC_HASH_REGISTERS; i++) {
3941 REG_WR(bp, BNX2_EMAC_MULTICAST_HASH0 + (i * 4),
3942 0xffffffff);
3943 }
3944 REG_WR(bp, BNX2_EMAC_RX_MODE,
3945 BNX2_EMAC_RX_MODE_SORT_MODE);
3946
3947 val = 1 | BNX2_RPM_SORT_USER0_BC_EN |
3948 BNX2_RPM_SORT_USER0_MC_EN;
3949 REG_WR(bp, BNX2_RPM_SORT_USER0, 0x0);
3950 REG_WR(bp, BNX2_RPM_SORT_USER0, val);
3951 REG_WR(bp, BNX2_RPM_SORT_USER0, val |
3952 BNX2_RPM_SORT_USER0_ENA);
3953
3954 /* Need to enable EMAC and RPM for WOL. */
3955 REG_WR(bp, BNX2_MISC_ENABLE_SET_BITS,
3956 BNX2_MISC_ENABLE_SET_BITS_RX_PARSER_MAC_ENABLE |
3957 BNX2_MISC_ENABLE_SET_BITS_TX_HEADER_Q_ENABLE |
3958 BNX2_MISC_ENABLE_SET_BITS_EMAC_ENABLE);
3959
3960 val = REG_RD(bp, BNX2_RPM_CONFIG);
3961 val &= ~BNX2_RPM_CONFIG_ACPI_ENA;
3962 REG_WR(bp, BNX2_RPM_CONFIG, val);
3963
3964 wol_msg = BNX2_DRV_MSG_CODE_SUSPEND_WOL;
3965 }
3966 else {
3967 wol_msg = BNX2_DRV_MSG_CODE_SUSPEND_NO_WOL;
3968 }
3969
David S. Millerf86e82f2008-01-21 17:15:40 -08003970 if (!(bp->flags & BNX2_FLAG_NO_WOL))
Michael Chana2f13892008-07-14 22:38:23 -07003971 bnx2_fw_sync(bp, BNX2_DRV_MSG_DATA_WAIT3 | wol_msg,
3972 1, 0);
Michael Chanb6016b72005-05-26 13:03:09 -07003973
3974 pmcsr &= ~PCI_PM_CTRL_STATE_MASK;
3975 if ((CHIP_ID(bp) == CHIP_ID_5706_A0) ||
3976 (CHIP_ID(bp) == CHIP_ID_5706_A1)) {
3977
3978 if (bp->wol)
3979 pmcsr |= 3;
3980 }
3981 else {
3982 pmcsr |= 3;
3983 }
3984 if (bp->wol) {
3985 pmcsr |= PCI_PM_CTRL_PME_ENABLE;
3986 }
3987 pci_write_config_word(bp->pdev, bp->pm_cap + PCI_PM_CTRL,
3988 pmcsr);
3989
3990 /* No more memory access after this point until
3991 * device is brought back to D0.
3992 */
3993 udelay(50);
3994 break;
3995 }
3996 default:
3997 return -EINVAL;
3998 }
3999 return 0;
4000}
4001
4002static int
4003bnx2_acquire_nvram_lock(struct bnx2 *bp)
4004{
4005 u32 val;
4006 int j;
4007
4008 /* Request access to the flash interface. */
4009 REG_WR(bp, BNX2_NVM_SW_ARB, BNX2_NVM_SW_ARB_ARB_REQ_SET2);
4010 for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) {
4011 val = REG_RD(bp, BNX2_NVM_SW_ARB);
4012 if (val & BNX2_NVM_SW_ARB_ARB_ARB2)
4013 break;
4014
4015 udelay(5);
4016 }
4017
4018 if (j >= NVRAM_TIMEOUT_COUNT)
4019 return -EBUSY;
4020
4021 return 0;
4022}
4023
4024static int
4025bnx2_release_nvram_lock(struct bnx2 *bp)
4026{
4027 int j;
4028 u32 val;
4029
4030 /* Relinquish nvram interface. */
4031 REG_WR(bp, BNX2_NVM_SW_ARB, BNX2_NVM_SW_ARB_ARB_REQ_CLR2);
4032
4033 for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) {
4034 val = REG_RD(bp, BNX2_NVM_SW_ARB);
4035 if (!(val & BNX2_NVM_SW_ARB_ARB_ARB2))
4036 break;
4037
4038 udelay(5);
4039 }
4040
4041 if (j >= NVRAM_TIMEOUT_COUNT)
4042 return -EBUSY;
4043
4044 return 0;
4045}
4046
4047
4048static int
4049bnx2_enable_nvram_write(struct bnx2 *bp)
4050{
4051 u32 val;
4052
4053 val = REG_RD(bp, BNX2_MISC_CFG);
4054 REG_WR(bp, BNX2_MISC_CFG, val | BNX2_MISC_CFG_NVM_WR_EN_PCI);
4055
Michael Chane30372c2007-07-16 18:26:23 -07004056 if (bp->flash_info->flags & BNX2_NV_WREN) {
Michael Chanb6016b72005-05-26 13:03:09 -07004057 int j;
4058
4059 REG_WR(bp, BNX2_NVM_COMMAND, BNX2_NVM_COMMAND_DONE);
4060 REG_WR(bp, BNX2_NVM_COMMAND,
4061 BNX2_NVM_COMMAND_WREN | BNX2_NVM_COMMAND_DOIT);
4062
4063 for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) {
4064 udelay(5);
4065
4066 val = REG_RD(bp, BNX2_NVM_COMMAND);
4067 if (val & BNX2_NVM_COMMAND_DONE)
4068 break;
4069 }
4070
4071 if (j >= NVRAM_TIMEOUT_COUNT)
4072 return -EBUSY;
4073 }
4074 return 0;
4075}
4076
4077static void
4078bnx2_disable_nvram_write(struct bnx2 *bp)
4079{
4080 u32 val;
4081
4082 val = REG_RD(bp, BNX2_MISC_CFG);
4083 REG_WR(bp, BNX2_MISC_CFG, val & ~BNX2_MISC_CFG_NVM_WR_EN);
4084}
4085
4086
4087static void
4088bnx2_enable_nvram_access(struct bnx2 *bp)
4089{
4090 u32 val;
4091
4092 val = REG_RD(bp, BNX2_NVM_ACCESS_ENABLE);
4093 /* Enable both bits, even on read. */
Jeff Garzik6aa20a22006-09-13 13:24:59 -04004094 REG_WR(bp, BNX2_NVM_ACCESS_ENABLE,
Michael Chanb6016b72005-05-26 13:03:09 -07004095 val | BNX2_NVM_ACCESS_ENABLE_EN | BNX2_NVM_ACCESS_ENABLE_WR_EN);
4096}
4097
4098static void
4099bnx2_disable_nvram_access(struct bnx2 *bp)
4100{
4101 u32 val;
4102
4103 val = REG_RD(bp, BNX2_NVM_ACCESS_ENABLE);
4104 /* Disable both bits, even after read. */
Jeff Garzik6aa20a22006-09-13 13:24:59 -04004105 REG_WR(bp, BNX2_NVM_ACCESS_ENABLE,
Michael Chanb6016b72005-05-26 13:03:09 -07004106 val & ~(BNX2_NVM_ACCESS_ENABLE_EN |
4107 BNX2_NVM_ACCESS_ENABLE_WR_EN));
4108}
4109
4110static int
4111bnx2_nvram_erase_page(struct bnx2 *bp, u32 offset)
4112{
4113 u32 cmd;
4114 int j;
4115
Michael Chane30372c2007-07-16 18:26:23 -07004116 if (bp->flash_info->flags & BNX2_NV_BUFFERED)
Michael Chanb6016b72005-05-26 13:03:09 -07004117 /* Buffered flash, no erase needed */
4118 return 0;
4119
4120 /* Build an erase command */
4121 cmd = BNX2_NVM_COMMAND_ERASE | BNX2_NVM_COMMAND_WR |
4122 BNX2_NVM_COMMAND_DOIT;
4123
4124 /* Need to clear DONE bit separately. */
4125 REG_WR(bp, BNX2_NVM_COMMAND, BNX2_NVM_COMMAND_DONE);
4126
4127 /* Address of the NVRAM to read from. */
4128 REG_WR(bp, BNX2_NVM_ADDR, offset & BNX2_NVM_ADDR_NVM_ADDR_VALUE);
4129
4130 /* Issue an erase command. */
4131 REG_WR(bp, BNX2_NVM_COMMAND, cmd);
4132
4133 /* Wait for completion. */
4134 for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) {
4135 u32 val;
4136
4137 udelay(5);
4138
4139 val = REG_RD(bp, BNX2_NVM_COMMAND);
4140 if (val & BNX2_NVM_COMMAND_DONE)
4141 break;
4142 }
4143
4144 if (j >= NVRAM_TIMEOUT_COUNT)
4145 return -EBUSY;
4146
4147 return 0;
4148}
4149
4150static int
4151bnx2_nvram_read_dword(struct bnx2 *bp, u32 offset, u8 *ret_val, u32 cmd_flags)
4152{
4153 u32 cmd;
4154 int j;
4155
4156 /* Build the command word. */
4157 cmd = BNX2_NVM_COMMAND_DOIT | cmd_flags;
4158
Michael Chane30372c2007-07-16 18:26:23 -07004159 /* Calculate an offset of a buffered flash, not needed for 5709. */
4160 if (bp->flash_info->flags & BNX2_NV_TRANSLATE) {
Michael Chanb6016b72005-05-26 13:03:09 -07004161 offset = ((offset / bp->flash_info->page_size) <<
4162 bp->flash_info->page_bits) +
4163 (offset % bp->flash_info->page_size);
4164 }
4165
4166 /* Need to clear DONE bit separately. */
4167 REG_WR(bp, BNX2_NVM_COMMAND, BNX2_NVM_COMMAND_DONE);
4168
4169 /* Address of the NVRAM to read from. */
4170 REG_WR(bp, BNX2_NVM_ADDR, offset & BNX2_NVM_ADDR_NVM_ADDR_VALUE);
4171
4172 /* Issue a read command. */
4173 REG_WR(bp, BNX2_NVM_COMMAND, cmd);
4174
4175 /* Wait for completion. */
4176 for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) {
4177 u32 val;
4178
4179 udelay(5);
4180
4181 val = REG_RD(bp, BNX2_NVM_COMMAND);
4182 if (val & BNX2_NVM_COMMAND_DONE) {
Al Virob491edd2007-12-22 19:44:51 +00004183 __be32 v = cpu_to_be32(REG_RD(bp, BNX2_NVM_READ));
4184 memcpy(ret_val, &v, 4);
Michael Chanb6016b72005-05-26 13:03:09 -07004185 break;
4186 }
4187 }
4188 if (j >= NVRAM_TIMEOUT_COUNT)
4189 return -EBUSY;
4190
4191 return 0;
4192}
4193
4194
4195static int
4196bnx2_nvram_write_dword(struct bnx2 *bp, u32 offset, u8 *val, u32 cmd_flags)
4197{
Al Virob491edd2007-12-22 19:44:51 +00004198 u32 cmd;
4199 __be32 val32;
Michael Chanb6016b72005-05-26 13:03:09 -07004200 int j;
4201
4202 /* Build the command word. */
4203 cmd = BNX2_NVM_COMMAND_DOIT | BNX2_NVM_COMMAND_WR | cmd_flags;
4204
Michael Chane30372c2007-07-16 18:26:23 -07004205 /* Calculate an offset of a buffered flash, not needed for 5709. */
4206 if (bp->flash_info->flags & BNX2_NV_TRANSLATE) {
Michael Chanb6016b72005-05-26 13:03:09 -07004207 offset = ((offset / bp->flash_info->page_size) <<
4208 bp->flash_info->page_bits) +
4209 (offset % bp->flash_info->page_size);
4210 }
4211
4212 /* Need to clear DONE bit separately. */
4213 REG_WR(bp, BNX2_NVM_COMMAND, BNX2_NVM_COMMAND_DONE);
4214
4215 memcpy(&val32, val, 4);
Michael Chanb6016b72005-05-26 13:03:09 -07004216
4217 /* Write the data. */
Al Virob491edd2007-12-22 19:44:51 +00004218 REG_WR(bp, BNX2_NVM_WRITE, be32_to_cpu(val32));
Michael Chanb6016b72005-05-26 13:03:09 -07004219
4220 /* Address of the NVRAM to write to. */
4221 REG_WR(bp, BNX2_NVM_ADDR, offset & BNX2_NVM_ADDR_NVM_ADDR_VALUE);
4222
4223 /* Issue the write command. */
4224 REG_WR(bp, BNX2_NVM_COMMAND, cmd);
4225
4226 /* Wait for completion. */
4227 for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) {
4228 udelay(5);
4229
4230 if (REG_RD(bp, BNX2_NVM_COMMAND) & BNX2_NVM_COMMAND_DONE)
4231 break;
4232 }
4233 if (j >= NVRAM_TIMEOUT_COUNT)
4234 return -EBUSY;
4235
4236 return 0;
4237}
4238
4239static int
4240bnx2_init_nvram(struct bnx2 *bp)
4241{
4242 u32 val;
Michael Chane30372c2007-07-16 18:26:23 -07004243 int j, entry_count, rc = 0;
Michael Chan0ced9d02009-08-21 16:20:49 +00004244 const struct flash_spec *flash;
Michael Chanb6016b72005-05-26 13:03:09 -07004245
Michael Chane30372c2007-07-16 18:26:23 -07004246 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
4247 bp->flash_info = &flash_5709;
4248 goto get_flash_size;
4249 }
4250
Michael Chanb6016b72005-05-26 13:03:09 -07004251 /* Determine the selected interface. */
4252 val = REG_RD(bp, BNX2_NVM_CFG1);
4253
Denis Chengff8ac602007-09-02 18:30:18 +08004254 entry_count = ARRAY_SIZE(flash_table);
Michael Chanb6016b72005-05-26 13:03:09 -07004255
Michael Chanb6016b72005-05-26 13:03:09 -07004256 if (val & 0x40000000) {
4257
4258 /* Flash interface has been reconfigured */
4259 for (j = 0, flash = &flash_table[0]; j < entry_count;
Michael Chan37137702005-11-04 08:49:17 -08004260 j++, flash++) {
4261 if ((val & FLASH_BACKUP_STRAP_MASK) ==
4262 (flash->config1 & FLASH_BACKUP_STRAP_MASK)) {
Michael Chanb6016b72005-05-26 13:03:09 -07004263 bp->flash_info = flash;
4264 break;
4265 }
4266 }
4267 }
4268 else {
Michael Chan37137702005-11-04 08:49:17 -08004269 u32 mask;
Michael Chanb6016b72005-05-26 13:03:09 -07004270 /* Not yet been reconfigured */
4271
Michael Chan37137702005-11-04 08:49:17 -08004272 if (val & (1 << 23))
4273 mask = FLASH_BACKUP_STRAP_MASK;
4274 else
4275 mask = FLASH_STRAP_MASK;
4276
Michael Chanb6016b72005-05-26 13:03:09 -07004277 for (j = 0, flash = &flash_table[0]; j < entry_count;
4278 j++, flash++) {
4279
Michael Chan37137702005-11-04 08:49:17 -08004280 if ((val & mask) == (flash->strapping & mask)) {
Michael Chanb6016b72005-05-26 13:03:09 -07004281 bp->flash_info = flash;
4282
4283 /* Request access to the flash interface. */
4284 if ((rc = bnx2_acquire_nvram_lock(bp)) != 0)
4285 return rc;
4286
4287 /* Enable access to flash interface */
4288 bnx2_enable_nvram_access(bp);
4289
4290 /* Reconfigure the flash interface */
4291 REG_WR(bp, BNX2_NVM_CFG1, flash->config1);
4292 REG_WR(bp, BNX2_NVM_CFG2, flash->config2);
4293 REG_WR(bp, BNX2_NVM_CFG3, flash->config3);
4294 REG_WR(bp, BNX2_NVM_WRITE1, flash->write1);
4295
4296 /* Disable access to flash interface */
4297 bnx2_disable_nvram_access(bp);
4298 bnx2_release_nvram_lock(bp);
4299
4300 break;
4301 }
4302 }
4303 } /* if (val & 0x40000000) */
4304
4305 if (j == entry_count) {
4306 bp->flash_info = NULL;
Joe Perches3a9c6a42010-02-17 15:01:51 +00004307 pr_alert("Unknown flash/EEPROM type\n");
Michael Chan1122db72006-01-23 16:11:42 -08004308 return -ENODEV;
Michael Chanb6016b72005-05-26 13:03:09 -07004309 }
4310
Michael Chane30372c2007-07-16 18:26:23 -07004311get_flash_size:
Michael Chan2726d6e2008-01-29 21:35:05 -08004312 val = bnx2_shmem_rd(bp, BNX2_SHARED_HW_CFG_CONFIG2);
Michael Chan1122db72006-01-23 16:11:42 -08004313 val &= BNX2_SHARED_HW_CFG2_NVM_SIZE_MASK;
4314 if (val)
4315 bp->flash_size = val;
4316 else
4317 bp->flash_size = bp->flash_info->total_size;
4318
Michael Chanb6016b72005-05-26 13:03:09 -07004319 return rc;
4320}
4321
4322static int
4323bnx2_nvram_read(struct bnx2 *bp, u32 offset, u8 *ret_buf,
4324 int buf_size)
4325{
4326 int rc = 0;
4327 u32 cmd_flags, offset32, len32, extra;
4328
4329 if (buf_size == 0)
4330 return 0;
4331
4332 /* Request access to the flash interface. */
4333 if ((rc = bnx2_acquire_nvram_lock(bp)) != 0)
4334 return rc;
4335
4336 /* Enable access to flash interface */
4337 bnx2_enable_nvram_access(bp);
4338
4339 len32 = buf_size;
4340 offset32 = offset;
4341 extra = 0;
4342
4343 cmd_flags = 0;
4344
4345 if (offset32 & 3) {
4346 u8 buf[4];
4347 u32 pre_len;
4348
4349 offset32 &= ~3;
4350 pre_len = 4 - (offset & 3);
4351
4352 if (pre_len >= len32) {
4353 pre_len = len32;
4354 cmd_flags = BNX2_NVM_COMMAND_FIRST |
4355 BNX2_NVM_COMMAND_LAST;
4356 }
4357 else {
4358 cmd_flags = BNX2_NVM_COMMAND_FIRST;
4359 }
4360
4361 rc = bnx2_nvram_read_dword(bp, offset32, buf, cmd_flags);
4362
4363 if (rc)
4364 return rc;
4365
4366 memcpy(ret_buf, buf + (offset & 3), pre_len);
4367
4368 offset32 += 4;
4369 ret_buf += pre_len;
4370 len32 -= pre_len;
4371 }
4372 if (len32 & 3) {
4373 extra = 4 - (len32 & 3);
4374 len32 = (len32 + 4) & ~3;
4375 }
4376
4377 if (len32 == 4) {
4378 u8 buf[4];
4379
4380 if (cmd_flags)
4381 cmd_flags = BNX2_NVM_COMMAND_LAST;
4382 else
4383 cmd_flags = BNX2_NVM_COMMAND_FIRST |
4384 BNX2_NVM_COMMAND_LAST;
4385
4386 rc = bnx2_nvram_read_dword(bp, offset32, buf, cmd_flags);
4387
4388 memcpy(ret_buf, buf, 4 - extra);
4389 }
4390 else if (len32 > 0) {
4391 u8 buf[4];
4392
4393 /* Read the first word. */
4394 if (cmd_flags)
4395 cmd_flags = 0;
4396 else
4397 cmd_flags = BNX2_NVM_COMMAND_FIRST;
4398
4399 rc = bnx2_nvram_read_dword(bp, offset32, ret_buf, cmd_flags);
4400
4401 /* Advance to the next dword. */
4402 offset32 += 4;
4403 ret_buf += 4;
4404 len32 -= 4;
4405
4406 while (len32 > 4 && rc == 0) {
4407 rc = bnx2_nvram_read_dword(bp, offset32, ret_buf, 0);
4408
4409 /* Advance to the next dword. */
4410 offset32 += 4;
4411 ret_buf += 4;
4412 len32 -= 4;
4413 }
4414
4415 if (rc)
4416 return rc;
4417
4418 cmd_flags = BNX2_NVM_COMMAND_LAST;
4419 rc = bnx2_nvram_read_dword(bp, offset32, buf, cmd_flags);
4420
4421 memcpy(ret_buf, buf, 4 - extra);
4422 }
4423
4424 /* Disable access to flash interface */
4425 bnx2_disable_nvram_access(bp);
4426
4427 bnx2_release_nvram_lock(bp);
4428
4429 return rc;
4430}
4431
4432static int
4433bnx2_nvram_write(struct bnx2 *bp, u32 offset, u8 *data_buf,
4434 int buf_size)
4435{
4436 u32 written, offset32, len32;
Michael Chane6be7632007-01-08 19:56:13 -08004437 u8 *buf, start[4], end[4], *align_buf = NULL, *flash_buffer = NULL;
Michael Chanb6016b72005-05-26 13:03:09 -07004438 int rc = 0;
4439 int align_start, align_end;
4440
4441 buf = data_buf;
4442 offset32 = offset;
4443 len32 = buf_size;
4444 align_start = align_end = 0;
4445
4446 if ((align_start = (offset32 & 3))) {
4447 offset32 &= ~3;
Michael Chanc8738792007-03-30 14:53:06 -07004448 len32 += align_start;
4449 if (len32 < 4)
4450 len32 = 4;
Michael Chanb6016b72005-05-26 13:03:09 -07004451 if ((rc = bnx2_nvram_read(bp, offset32, start, 4)))
4452 return rc;
4453 }
4454
4455 if (len32 & 3) {
Michael Chanc8738792007-03-30 14:53:06 -07004456 align_end = 4 - (len32 & 3);
4457 len32 += align_end;
4458 if ((rc = bnx2_nvram_read(bp, offset32 + len32 - 4, end, 4)))
4459 return rc;
Michael Chanb6016b72005-05-26 13:03:09 -07004460 }
4461
4462 if (align_start || align_end) {
Michael Chane6be7632007-01-08 19:56:13 -08004463 align_buf = kmalloc(len32, GFP_KERNEL);
4464 if (align_buf == NULL)
Michael Chanb6016b72005-05-26 13:03:09 -07004465 return -ENOMEM;
4466 if (align_start) {
Michael Chane6be7632007-01-08 19:56:13 -08004467 memcpy(align_buf, start, 4);
Michael Chanb6016b72005-05-26 13:03:09 -07004468 }
4469 if (align_end) {
Michael Chane6be7632007-01-08 19:56:13 -08004470 memcpy(align_buf + len32 - 4, end, 4);
Michael Chanb6016b72005-05-26 13:03:09 -07004471 }
Michael Chane6be7632007-01-08 19:56:13 -08004472 memcpy(align_buf + align_start, data_buf, buf_size);
4473 buf = align_buf;
Michael Chanb6016b72005-05-26 13:03:09 -07004474 }
4475
Michael Chane30372c2007-07-16 18:26:23 -07004476 if (!(bp->flash_info->flags & BNX2_NV_BUFFERED)) {
Michael Chanae181bc2006-05-22 16:39:20 -07004477 flash_buffer = kmalloc(264, GFP_KERNEL);
4478 if (flash_buffer == NULL) {
4479 rc = -ENOMEM;
4480 goto nvram_write_end;
4481 }
4482 }
4483
Michael Chanb6016b72005-05-26 13:03:09 -07004484 written = 0;
4485 while ((written < len32) && (rc == 0)) {
4486 u32 page_start, page_end, data_start, data_end;
4487 u32 addr, cmd_flags;
4488 int i;
Michael Chanb6016b72005-05-26 13:03:09 -07004489
4490 /* Find the page_start addr */
4491 page_start = offset32 + written;
4492 page_start -= (page_start % bp->flash_info->page_size);
4493 /* Find the page_end addr */
4494 page_end = page_start + bp->flash_info->page_size;
4495 /* Find the data_start addr */
4496 data_start = (written == 0) ? offset32 : page_start;
4497 /* Find the data_end addr */
Jeff Garzik6aa20a22006-09-13 13:24:59 -04004498 data_end = (page_end > offset32 + len32) ?
Michael Chanb6016b72005-05-26 13:03:09 -07004499 (offset32 + len32) : page_end;
4500
4501 /* Request access to the flash interface. */
4502 if ((rc = bnx2_acquire_nvram_lock(bp)) != 0)
4503 goto nvram_write_end;
4504
4505 /* Enable access to flash interface */
4506 bnx2_enable_nvram_access(bp);
4507
4508 cmd_flags = BNX2_NVM_COMMAND_FIRST;
Michael Chane30372c2007-07-16 18:26:23 -07004509 if (!(bp->flash_info->flags & BNX2_NV_BUFFERED)) {
Michael Chanb6016b72005-05-26 13:03:09 -07004510 int j;
4511
4512 /* Read the whole page into the buffer
4513 * (non-buffer flash only) */
4514 for (j = 0; j < bp->flash_info->page_size; j += 4) {
4515 if (j == (bp->flash_info->page_size - 4)) {
4516 cmd_flags |= BNX2_NVM_COMMAND_LAST;
4517 }
4518 rc = bnx2_nvram_read_dword(bp,
Jeff Garzik6aa20a22006-09-13 13:24:59 -04004519 page_start + j,
4520 &flash_buffer[j],
Michael Chanb6016b72005-05-26 13:03:09 -07004521 cmd_flags);
4522
4523 if (rc)
4524 goto nvram_write_end;
4525
4526 cmd_flags = 0;
4527 }
4528 }
4529
4530 /* Enable writes to flash interface (unlock write-protect) */
4531 if ((rc = bnx2_enable_nvram_write(bp)) != 0)
4532 goto nvram_write_end;
4533
Michael Chanb6016b72005-05-26 13:03:09 -07004534 /* Loop to write back the buffer data from page_start to
4535 * data_start */
4536 i = 0;
Michael Chane30372c2007-07-16 18:26:23 -07004537 if (!(bp->flash_info->flags & BNX2_NV_BUFFERED)) {
Michael Chanc8738792007-03-30 14:53:06 -07004538 /* Erase the page */
4539 if ((rc = bnx2_nvram_erase_page(bp, page_start)) != 0)
4540 goto nvram_write_end;
4541
4542 /* Re-enable the write again for the actual write */
4543 bnx2_enable_nvram_write(bp);
4544
Michael Chanb6016b72005-05-26 13:03:09 -07004545 for (addr = page_start; addr < data_start;
4546 addr += 4, i += 4) {
Jeff Garzik6aa20a22006-09-13 13:24:59 -04004547
Michael Chanb6016b72005-05-26 13:03:09 -07004548 rc = bnx2_nvram_write_dword(bp, addr,
4549 &flash_buffer[i], cmd_flags);
4550
4551 if (rc != 0)
4552 goto nvram_write_end;
4553
4554 cmd_flags = 0;
4555 }
4556 }
4557
4558 /* Loop to write the new data from data_start to data_end */
Michael Chanbae25762006-05-22 16:38:38 -07004559 for (addr = data_start; addr < data_end; addr += 4, i += 4) {
Michael Chanb6016b72005-05-26 13:03:09 -07004560 if ((addr == page_end - 4) ||
Michael Chane30372c2007-07-16 18:26:23 -07004561 ((bp->flash_info->flags & BNX2_NV_BUFFERED) &&
Michael Chanb6016b72005-05-26 13:03:09 -07004562 (addr == data_end - 4))) {
4563
4564 cmd_flags |= BNX2_NVM_COMMAND_LAST;
4565 }
4566 rc = bnx2_nvram_write_dword(bp, addr, buf,
4567 cmd_flags);
4568
4569 if (rc != 0)
4570 goto nvram_write_end;
4571
4572 cmd_flags = 0;
4573 buf += 4;
4574 }
4575
4576 /* Loop to write back the buffer data from data_end
4577 * to page_end */
Michael Chane30372c2007-07-16 18:26:23 -07004578 if (!(bp->flash_info->flags & BNX2_NV_BUFFERED)) {
Michael Chanb6016b72005-05-26 13:03:09 -07004579 for (addr = data_end; addr < page_end;
4580 addr += 4, i += 4) {
Jeff Garzik6aa20a22006-09-13 13:24:59 -04004581
Michael Chanb6016b72005-05-26 13:03:09 -07004582 if (addr == page_end-4) {
4583 cmd_flags = BNX2_NVM_COMMAND_LAST;
4584 }
4585 rc = bnx2_nvram_write_dword(bp, addr,
4586 &flash_buffer[i], cmd_flags);
4587
4588 if (rc != 0)
4589 goto nvram_write_end;
4590
4591 cmd_flags = 0;
4592 }
4593 }
4594
4595 /* Disable writes to flash interface (lock write-protect) */
4596 bnx2_disable_nvram_write(bp);
4597
4598 /* Disable access to flash interface */
4599 bnx2_disable_nvram_access(bp);
4600 bnx2_release_nvram_lock(bp);
4601
4602 /* Increment written */
4603 written += data_end - data_start;
4604 }
4605
4606nvram_write_end:
Michael Chane6be7632007-01-08 19:56:13 -08004607 kfree(flash_buffer);
4608 kfree(align_buf);
Michael Chanb6016b72005-05-26 13:03:09 -07004609 return rc;
4610}
4611
Michael Chan0d8a6572007-07-07 22:49:43 -07004612static void
Michael Chan7c62e832008-07-14 22:39:03 -07004613bnx2_init_fw_cap(struct bnx2 *bp)
Michael Chan0d8a6572007-07-07 22:49:43 -07004614{
Michael Chan7c62e832008-07-14 22:39:03 -07004615 u32 val, sig = 0;
Michael Chan0d8a6572007-07-07 22:49:43 -07004616
Michael Chan583c28e2008-01-21 19:51:35 -08004617 bp->phy_flags &= ~BNX2_PHY_FLAG_REMOTE_PHY_CAP;
Michael Chan7c62e832008-07-14 22:39:03 -07004618 bp->flags &= ~BNX2_FLAG_CAN_KEEP_VLAN;
4619
4620 if (!(bp->flags & BNX2_FLAG_ASF_ENABLE))
4621 bp->flags |= BNX2_FLAG_CAN_KEEP_VLAN;
Michael Chan0d8a6572007-07-07 22:49:43 -07004622
Michael Chan2726d6e2008-01-29 21:35:05 -08004623 val = bnx2_shmem_rd(bp, BNX2_FW_CAP_MB);
Michael Chan0d8a6572007-07-07 22:49:43 -07004624 if ((val & BNX2_FW_CAP_SIGNATURE_MASK) != BNX2_FW_CAP_SIGNATURE)
4625 return;
4626
Michael Chan7c62e832008-07-14 22:39:03 -07004627 if ((val & BNX2_FW_CAP_CAN_KEEP_VLAN) == BNX2_FW_CAP_CAN_KEEP_VLAN) {
4628 bp->flags |= BNX2_FLAG_CAN_KEEP_VLAN;
4629 sig |= BNX2_DRV_ACK_CAP_SIGNATURE | BNX2_FW_CAP_CAN_KEEP_VLAN;
4630 }
4631
4632 if ((bp->phy_flags & BNX2_PHY_FLAG_SERDES) &&
4633 (val & BNX2_FW_CAP_REMOTE_PHY_CAPABLE)) {
4634 u32 link;
4635
Michael Chan583c28e2008-01-21 19:51:35 -08004636 bp->phy_flags |= BNX2_PHY_FLAG_REMOTE_PHY_CAP;
Michael Chan0d8a6572007-07-07 22:49:43 -07004637
Michael Chan7c62e832008-07-14 22:39:03 -07004638 link = bnx2_shmem_rd(bp, BNX2_LINK_STATUS);
4639 if (link & BNX2_LINK_STATUS_SERDES_LINK)
Michael Chan0d8a6572007-07-07 22:49:43 -07004640 bp->phy_port = PORT_FIBRE;
4641 else
4642 bp->phy_port = PORT_TP;
Michael Chan489310a2007-10-10 16:16:31 -07004643
Michael Chan7c62e832008-07-14 22:39:03 -07004644 sig |= BNX2_DRV_ACK_CAP_SIGNATURE |
4645 BNX2_FW_CAP_REMOTE_PHY_CAPABLE;
Michael Chan0d8a6572007-07-07 22:49:43 -07004646 }
Michael Chan7c62e832008-07-14 22:39:03 -07004647
4648 if (netif_running(bp->dev) && sig)
4649 bnx2_shmem_wr(bp, BNX2_DRV_ACK_CAP_MB, sig);
Michael Chan0d8a6572007-07-07 22:49:43 -07004650}
4651
Michael Chanb4b36042007-12-20 19:59:30 -08004652static void
4653bnx2_setup_msix_tbl(struct bnx2 *bp)
4654{
4655 REG_WR(bp, BNX2_PCI_GRC_WINDOW_ADDR, BNX2_PCI_GRC_WINDOW_ADDR_SEP_WIN);
4656
4657 REG_WR(bp, BNX2_PCI_GRC_WINDOW2_ADDR, BNX2_MSIX_TABLE_ADDR);
4658 REG_WR(bp, BNX2_PCI_GRC_WINDOW3_ADDR, BNX2_MSIX_PBA_ADDR);
4659}
4660
Michael Chanb6016b72005-05-26 13:03:09 -07004661static int
4662bnx2_reset_chip(struct bnx2 *bp, u32 reset_code)
4663{
4664 u32 val;
4665 int i, rc = 0;
Michael Chan489310a2007-10-10 16:16:31 -07004666 u8 old_port;
Michael Chanb6016b72005-05-26 13:03:09 -07004667
4668 /* Wait for the current PCI transaction to complete before
4669 * issuing a reset. */
4670 REG_WR(bp, BNX2_MISC_ENABLE_CLR_BITS,
4671 BNX2_MISC_ENABLE_CLR_BITS_TX_DMA_ENABLE |
4672 BNX2_MISC_ENABLE_CLR_BITS_DMA_ENGINE_ENABLE |
4673 BNX2_MISC_ENABLE_CLR_BITS_RX_DMA_ENABLE |
4674 BNX2_MISC_ENABLE_CLR_BITS_HOST_COALESCE_ENABLE);
4675 val = REG_RD(bp, BNX2_MISC_ENABLE_CLR_BITS);
4676 udelay(5);
4677
Michael Chanb090ae22006-01-23 16:07:10 -08004678 /* Wait for the firmware to tell us it is ok to issue a reset. */
Michael Chana2f13892008-07-14 22:38:23 -07004679 bnx2_fw_sync(bp, BNX2_DRV_MSG_DATA_WAIT0 | reset_code, 1, 1);
Michael Chanb090ae22006-01-23 16:07:10 -08004680
Michael Chanb6016b72005-05-26 13:03:09 -07004681 /* Deposit a driver reset signature so the firmware knows that
4682 * this is a soft reset. */
Michael Chan2726d6e2008-01-29 21:35:05 -08004683 bnx2_shmem_wr(bp, BNX2_DRV_RESET_SIGNATURE,
4684 BNX2_DRV_RESET_SIGNATURE_MAGIC);
Michael Chanb6016b72005-05-26 13:03:09 -07004685
Michael Chanb6016b72005-05-26 13:03:09 -07004686 /* Do a dummy read to force the chip to complete all current transaction
4687 * before we issue a reset. */
4688 val = REG_RD(bp, BNX2_MISC_ID);
4689
Michael Chan234754d2006-11-19 14:11:41 -08004690 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
4691 REG_WR(bp, BNX2_MISC_COMMAND, BNX2_MISC_COMMAND_SW_RESET);
4692 REG_RD(bp, BNX2_MISC_COMMAND);
4693 udelay(5);
Michael Chanb6016b72005-05-26 13:03:09 -07004694
Michael Chan234754d2006-11-19 14:11:41 -08004695 val = BNX2_PCICFG_MISC_CONFIG_REG_WINDOW_ENA |
4696 BNX2_PCICFG_MISC_CONFIG_TARGET_MB_WORD_SWAP;
Michael Chanb6016b72005-05-26 13:03:09 -07004697
Michael Chan234754d2006-11-19 14:11:41 -08004698 pci_write_config_dword(bp->pdev, BNX2_PCICFG_MISC_CONFIG, val);
Michael Chanb6016b72005-05-26 13:03:09 -07004699
Michael Chan234754d2006-11-19 14:11:41 -08004700 } else {
4701 val = BNX2_PCICFG_MISC_CONFIG_CORE_RST_REQ |
4702 BNX2_PCICFG_MISC_CONFIG_REG_WINDOW_ENA |
4703 BNX2_PCICFG_MISC_CONFIG_TARGET_MB_WORD_SWAP;
4704
4705 /* Chip reset. */
4706 REG_WR(bp, BNX2_PCICFG_MISC_CONFIG, val);
4707
Michael Chan594a9df2007-08-28 15:39:42 -07004708 /* Reading back any register after chip reset will hang the
4709 * bus on 5706 A0 and A1. The msleep below provides plenty
4710 * of margin for write posting.
4711 */
Michael Chan234754d2006-11-19 14:11:41 -08004712 if ((CHIP_ID(bp) == CHIP_ID_5706_A0) ||
Arjan van de Ven8e545882007-08-28 14:34:43 -07004713 (CHIP_ID(bp) == CHIP_ID_5706_A1))
4714 msleep(20);
Michael Chanb6016b72005-05-26 13:03:09 -07004715
Michael Chan234754d2006-11-19 14:11:41 -08004716 /* Reset takes approximate 30 usec */
4717 for (i = 0; i < 10; i++) {
4718 val = REG_RD(bp, BNX2_PCICFG_MISC_CONFIG);
4719 if ((val & (BNX2_PCICFG_MISC_CONFIG_CORE_RST_REQ |
4720 BNX2_PCICFG_MISC_CONFIG_CORE_RST_BSY)) == 0)
4721 break;
4722 udelay(10);
4723 }
4724
4725 if (val & (BNX2_PCICFG_MISC_CONFIG_CORE_RST_REQ |
4726 BNX2_PCICFG_MISC_CONFIG_CORE_RST_BSY)) {
Joe Perches3a9c6a42010-02-17 15:01:51 +00004727 pr_err("Chip reset did not complete\n");
Michael Chan234754d2006-11-19 14:11:41 -08004728 return -EBUSY;
4729 }
Michael Chanb6016b72005-05-26 13:03:09 -07004730 }
4731
4732 /* Make sure byte swapping is properly configured. */
4733 val = REG_RD(bp, BNX2_PCI_SWAP_DIAG0);
4734 if (val != 0x01020304) {
Joe Perches3a9c6a42010-02-17 15:01:51 +00004735 pr_err("Chip not in correct endian mode\n");
Michael Chanb6016b72005-05-26 13:03:09 -07004736 return -ENODEV;
4737 }
4738
Michael Chanb6016b72005-05-26 13:03:09 -07004739 /* Wait for the firmware to finish its initialization. */
Michael Chana2f13892008-07-14 22:38:23 -07004740 rc = bnx2_fw_sync(bp, BNX2_DRV_MSG_DATA_WAIT1 | reset_code, 1, 0);
Michael Chanb090ae22006-01-23 16:07:10 -08004741 if (rc)
4742 return rc;
Michael Chanb6016b72005-05-26 13:03:09 -07004743
Michael Chan0d8a6572007-07-07 22:49:43 -07004744 spin_lock_bh(&bp->phy_lock);
Michael Chan489310a2007-10-10 16:16:31 -07004745 old_port = bp->phy_port;
Michael Chan7c62e832008-07-14 22:39:03 -07004746 bnx2_init_fw_cap(bp);
Michael Chan583c28e2008-01-21 19:51:35 -08004747 if ((bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP) &&
4748 old_port != bp->phy_port)
Michael Chan0d8a6572007-07-07 22:49:43 -07004749 bnx2_set_default_remote_link(bp);
4750 spin_unlock_bh(&bp->phy_lock);
4751
Michael Chanb6016b72005-05-26 13:03:09 -07004752 if (CHIP_ID(bp) == CHIP_ID_5706_A0) {
4753 /* Adjust the voltage regular to two steps lower. The default
4754 * of this register is 0x0000000e. */
4755 REG_WR(bp, BNX2_MISC_VREG_CONTROL, 0x000000fa);
4756
4757 /* Remove bad rbuf memory from the free pool. */
4758 rc = bnx2_alloc_bad_rbuf(bp);
4759 }
4760
David S. Millerf86e82f2008-01-21 17:15:40 -08004761 if (bp->flags & BNX2_FLAG_USING_MSIX)
Michael Chanb4b36042007-12-20 19:59:30 -08004762 bnx2_setup_msix_tbl(bp);
4763
Michael Chanb6016b72005-05-26 13:03:09 -07004764 return rc;
4765}
4766
4767static int
4768bnx2_init_chip(struct bnx2 *bp)
4769{
Michael Chand8026d92008-11-12 16:02:20 -08004770 u32 val, mtu;
Michael Chanb4b36042007-12-20 19:59:30 -08004771 int rc, i;
Michael Chanb6016b72005-05-26 13:03:09 -07004772
4773 /* Make sure the interrupt is not active. */
4774 REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD, BNX2_PCICFG_INT_ACK_CMD_MASK_INT);
4775
4776 val = BNX2_DMA_CONFIG_DATA_BYTE_SWAP |
4777 BNX2_DMA_CONFIG_DATA_WORD_SWAP |
4778#ifdef __BIG_ENDIAN
Jeff Garzik6aa20a22006-09-13 13:24:59 -04004779 BNX2_DMA_CONFIG_CNTL_BYTE_SWAP |
Michael Chanb6016b72005-05-26 13:03:09 -07004780#endif
Jeff Garzik6aa20a22006-09-13 13:24:59 -04004781 BNX2_DMA_CONFIG_CNTL_WORD_SWAP |
Michael Chanb6016b72005-05-26 13:03:09 -07004782 DMA_READ_CHANS << 12 |
4783 DMA_WRITE_CHANS << 16;
4784
4785 val |= (0x2 << 20) | (1 << 11);
4786
David S. Millerf86e82f2008-01-21 17:15:40 -08004787 if ((bp->flags & BNX2_FLAG_PCIX) && (bp->bus_speed_mhz == 133))
Michael Chanb6016b72005-05-26 13:03:09 -07004788 val |= (1 << 23);
4789
4790 if ((CHIP_NUM(bp) == CHIP_NUM_5706) &&
David S. Millerf86e82f2008-01-21 17:15:40 -08004791 (CHIP_ID(bp) != CHIP_ID_5706_A0) && !(bp->flags & BNX2_FLAG_PCIX))
Michael Chanb6016b72005-05-26 13:03:09 -07004792 val |= BNX2_DMA_CONFIG_CNTL_PING_PONG_DMA;
4793
4794 REG_WR(bp, BNX2_DMA_CONFIG, val);
4795
4796 if (CHIP_ID(bp) == CHIP_ID_5706_A0) {
4797 val = REG_RD(bp, BNX2_TDMA_CONFIG);
4798 val |= BNX2_TDMA_CONFIG_ONE_DMA;
4799 REG_WR(bp, BNX2_TDMA_CONFIG, val);
4800 }
4801
David S. Millerf86e82f2008-01-21 17:15:40 -08004802 if (bp->flags & BNX2_FLAG_PCIX) {
Michael Chanb6016b72005-05-26 13:03:09 -07004803 u16 val16;
4804
4805 pci_read_config_word(bp->pdev, bp->pcix_cap + PCI_X_CMD,
4806 &val16);
4807 pci_write_config_word(bp->pdev, bp->pcix_cap + PCI_X_CMD,
4808 val16 & ~PCI_X_CMD_ERO);
4809 }
4810
4811 REG_WR(bp, BNX2_MISC_ENABLE_SET_BITS,
4812 BNX2_MISC_ENABLE_SET_BITS_HOST_COALESCE_ENABLE |
4813 BNX2_MISC_ENABLE_STATUS_BITS_RX_V2P_ENABLE |
4814 BNX2_MISC_ENABLE_STATUS_BITS_CONTEXT_ENABLE);
4815
4816 /* Initialize context mapping and zero out the quick contexts. The
4817 * context block must have already been enabled. */
Michael Chan641bdcd2007-06-04 21:22:24 -07004818 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
4819 rc = bnx2_init_5709_context(bp);
4820 if (rc)
4821 return rc;
4822 } else
Michael Chan59b47d82006-11-19 14:10:45 -08004823 bnx2_init_context(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07004824
Michael Chanfba9fe92006-06-12 22:21:25 -07004825 if ((rc = bnx2_init_cpus(bp)) != 0)
4826 return rc;
4827
Michael Chanb6016b72005-05-26 13:03:09 -07004828 bnx2_init_nvram(bp);
4829
Benjamin Li5fcaed02008-07-14 22:39:52 -07004830 bnx2_set_mac_addr(bp, bp->dev->dev_addr, 0);
Michael Chanb6016b72005-05-26 13:03:09 -07004831
4832 val = REG_RD(bp, BNX2_MQ_CONFIG);
4833 val &= ~BNX2_MQ_CONFIG_KNL_BYP_BLK_SIZE;
4834 val |= BNX2_MQ_CONFIG_KNL_BYP_BLK_SIZE_256;
Michael Chan4edd4732009-06-08 18:14:42 -07004835 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
4836 val |= BNX2_MQ_CONFIG_BIN_MQ_MODE;
4837 if (CHIP_REV(bp) == CHIP_REV_Ax)
4838 val |= BNX2_MQ_CONFIG_HALT_DIS;
4839 }
Michael Chan68c9f752007-04-24 15:35:53 -07004840
Michael Chanb6016b72005-05-26 13:03:09 -07004841 REG_WR(bp, BNX2_MQ_CONFIG, val);
4842
4843 val = 0x10000 + (MAX_CID_CNT * MB_KERNEL_CTX_SIZE);
4844 REG_WR(bp, BNX2_MQ_KNL_BYP_WIND_START, val);
4845 REG_WR(bp, BNX2_MQ_KNL_WIND_END, val);
4846
4847 val = (BCM_PAGE_BITS - 8) << 24;
4848 REG_WR(bp, BNX2_RV2P_CONFIG, val);
4849
4850 /* Configure page size. */
4851 val = REG_RD(bp, BNX2_TBDR_CONFIG);
4852 val &= ~BNX2_TBDR_CONFIG_PAGE_SIZE;
4853 val |= (BCM_PAGE_BITS - 8) << 24 | 0x40;
4854 REG_WR(bp, BNX2_TBDR_CONFIG, val);
4855
4856 val = bp->mac_addr[0] +
4857 (bp->mac_addr[1] << 8) +
4858 (bp->mac_addr[2] << 16) +
4859 bp->mac_addr[3] +
4860 (bp->mac_addr[4] << 8) +
4861 (bp->mac_addr[5] << 16);
4862 REG_WR(bp, BNX2_EMAC_BACKOFF_SEED, val);
4863
4864 /* Program the MTU. Also include 4 bytes for CRC32. */
Michael Chand8026d92008-11-12 16:02:20 -08004865 mtu = bp->dev->mtu;
4866 val = mtu + ETH_HLEN + ETH_FCS_LEN;
Michael Chanb6016b72005-05-26 13:03:09 -07004867 if (val > (MAX_ETHERNET_PACKET_SIZE + 4))
4868 val |= BNX2_EMAC_RX_MTU_SIZE_JUMBO_ENA;
4869 REG_WR(bp, BNX2_EMAC_RX_MTU_SIZE, val);
4870
Michael Chand8026d92008-11-12 16:02:20 -08004871 if (mtu < 1500)
4872 mtu = 1500;
4873
4874 bnx2_reg_wr_ind(bp, BNX2_RBUF_CONFIG, BNX2_RBUF_CONFIG_VAL(mtu));
4875 bnx2_reg_wr_ind(bp, BNX2_RBUF_CONFIG2, BNX2_RBUF_CONFIG2_VAL(mtu));
4876 bnx2_reg_wr_ind(bp, BNX2_RBUF_CONFIG3, BNX2_RBUF_CONFIG3_VAL(mtu));
4877
Michael Chan155d5562009-08-21 16:20:43 +00004878 memset(bp->bnx2_napi[0].status_blk.msi, 0, bp->status_stats_size);
Michael Chanb4b36042007-12-20 19:59:30 -08004879 for (i = 0; i < BNX2_MAX_MSIX_VEC; i++)
4880 bp->bnx2_napi[i].last_status_idx = 0;
4881
Michael Chanefba0182008-12-03 00:36:15 -08004882 bp->idle_chk_status_idx = 0xffff;
4883
Michael Chanb6016b72005-05-26 13:03:09 -07004884 bp->rx_mode = BNX2_EMAC_RX_MODE_SORT_MODE;
4885
4886 /* Set up how to generate a link change interrupt. */
4887 REG_WR(bp, BNX2_EMAC_ATTENTION_ENA, BNX2_EMAC_ATTENTION_ENA_LINK);
4888
4889 REG_WR(bp, BNX2_HC_STATUS_ADDR_L,
4890 (u64) bp->status_blk_mapping & 0xffffffff);
4891 REG_WR(bp, BNX2_HC_STATUS_ADDR_H, (u64) bp->status_blk_mapping >> 32);
4892
4893 REG_WR(bp, BNX2_HC_STATISTICS_ADDR_L,
4894 (u64) bp->stats_blk_mapping & 0xffffffff);
4895 REG_WR(bp, BNX2_HC_STATISTICS_ADDR_H,
4896 (u64) bp->stats_blk_mapping >> 32);
4897
Jeff Garzik6aa20a22006-09-13 13:24:59 -04004898 REG_WR(bp, BNX2_HC_TX_QUICK_CONS_TRIP,
Michael Chanb6016b72005-05-26 13:03:09 -07004899 (bp->tx_quick_cons_trip_int << 16) | bp->tx_quick_cons_trip);
4900
4901 REG_WR(bp, BNX2_HC_RX_QUICK_CONS_TRIP,
4902 (bp->rx_quick_cons_trip_int << 16) | bp->rx_quick_cons_trip);
4903
4904 REG_WR(bp, BNX2_HC_COMP_PROD_TRIP,
4905 (bp->comp_prod_trip_int << 16) | bp->comp_prod_trip);
4906
4907 REG_WR(bp, BNX2_HC_TX_TICKS, (bp->tx_ticks_int << 16) | bp->tx_ticks);
4908
4909 REG_WR(bp, BNX2_HC_RX_TICKS, (bp->rx_ticks_int << 16) | bp->rx_ticks);
4910
4911 REG_WR(bp, BNX2_HC_COM_TICKS,
4912 (bp->com_ticks_int << 16) | bp->com_ticks);
4913
4914 REG_WR(bp, BNX2_HC_CMD_TICKS,
4915 (bp->cmd_ticks_int << 16) | bp->cmd_ticks);
4916
Michael Chan61d9e3f2009-08-21 16:20:46 +00004917 if (bp->flags & BNX2_FLAG_BROKEN_STATS)
Michael Chan02537b062007-06-04 21:24:07 -07004918 REG_WR(bp, BNX2_HC_STATS_TICKS, 0);
4919 else
Michael Chan7ea69202007-07-16 18:27:10 -07004920 REG_WR(bp, BNX2_HC_STATS_TICKS, bp->stats_ticks);
Michael Chanb6016b72005-05-26 13:03:09 -07004921 REG_WR(bp, BNX2_HC_STAT_COLLECT_TICKS, 0xbb8); /* 3ms */
4922
4923 if (CHIP_ID(bp) == CHIP_ID_5706_A1)
Michael Chan8e6a72c2007-05-03 13:24:48 -07004924 val = BNX2_HC_CONFIG_COLLECT_STATS;
Michael Chanb6016b72005-05-26 13:03:09 -07004925 else {
Michael Chan8e6a72c2007-05-03 13:24:48 -07004926 val = BNX2_HC_CONFIG_RX_TMR_MODE | BNX2_HC_CONFIG_TX_TMR_MODE |
4927 BNX2_HC_CONFIG_COLLECT_STATS;
Michael Chanb6016b72005-05-26 13:03:09 -07004928 }
4929
Michael Chanefde73a2010-02-15 19:42:07 +00004930 if (bp->flags & BNX2_FLAG_USING_MSIX) {
Michael Chanc76c0472007-12-20 20:01:19 -08004931 REG_WR(bp, BNX2_HC_MSIX_BIT_VECTOR,
4932 BNX2_HC_MSIX_BIT_VECTOR_VAL);
4933
Michael Chan5e9ad9e2008-06-19 16:43:17 -07004934 val |= BNX2_HC_CONFIG_SB_ADDR_INC_128B;
4935 }
4936
4937 if (bp->flags & BNX2_FLAG_ONE_SHOT_MSI)
Michael Chancf7474a2009-08-21 16:20:48 +00004938 val |= BNX2_HC_CONFIG_ONE_SHOT | BNX2_HC_CONFIG_USE_INT_PARAM;
Michael Chan5e9ad9e2008-06-19 16:43:17 -07004939
4940 REG_WR(bp, BNX2_HC_CONFIG, val);
4941
4942 for (i = 1; i < bp->irq_nvecs; i++) {
4943 u32 base = ((i - 1) * BNX2_HC_SB_CONFIG_SIZE) +
4944 BNX2_HC_SB_CONFIG_1;
4945
Michael Chan6f743ca2008-01-29 21:34:08 -08004946 REG_WR(bp, base,
Michael Chanc76c0472007-12-20 20:01:19 -08004947 BNX2_HC_SB_CONFIG_1_TX_TMR_MODE |
Michael Chan5e9ad9e2008-06-19 16:43:17 -07004948 BNX2_HC_SB_CONFIG_1_RX_TMR_MODE |
Michael Chanc76c0472007-12-20 20:01:19 -08004949 BNX2_HC_SB_CONFIG_1_ONE_SHOT);
4950
Michael Chan6f743ca2008-01-29 21:34:08 -08004951 REG_WR(bp, base + BNX2_HC_TX_QUICK_CONS_TRIP_OFF,
Michael Chanc76c0472007-12-20 20:01:19 -08004952 (bp->tx_quick_cons_trip_int << 16) |
4953 bp->tx_quick_cons_trip);
4954
Michael Chan6f743ca2008-01-29 21:34:08 -08004955 REG_WR(bp, base + BNX2_HC_TX_TICKS_OFF,
Michael Chanc76c0472007-12-20 20:01:19 -08004956 (bp->tx_ticks_int << 16) | bp->tx_ticks);
4957
Michael Chan5e9ad9e2008-06-19 16:43:17 -07004958 REG_WR(bp, base + BNX2_HC_RX_QUICK_CONS_TRIP_OFF,
4959 (bp->rx_quick_cons_trip_int << 16) |
4960 bp->rx_quick_cons_trip);
4961
4962 REG_WR(bp, base + BNX2_HC_RX_TICKS_OFF,
4963 (bp->rx_ticks_int << 16) | bp->rx_ticks);
Michael Chanc76c0472007-12-20 20:01:19 -08004964 }
4965
Michael Chanb6016b72005-05-26 13:03:09 -07004966 /* Clear internal stats counters. */
4967 REG_WR(bp, BNX2_HC_COMMAND, BNX2_HC_COMMAND_CLR_STAT_NOW);
4968
Michael Chanda3e4fb2007-05-03 13:24:23 -07004969 REG_WR(bp, BNX2_HC_ATTN_BITS_ENABLE, STATUS_ATTN_EVENTS);
Michael Chanb6016b72005-05-26 13:03:09 -07004970
4971 /* Initialize the receive filter. */
4972 bnx2_set_rx_mode(bp->dev);
4973
Michael Chan0aa38df2007-06-04 21:23:06 -07004974 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
4975 val = REG_RD(bp, BNX2_MISC_NEW_CORE_CTL);
4976 val |= BNX2_MISC_NEW_CORE_CTL_DMA_ENABLE;
4977 REG_WR(bp, BNX2_MISC_NEW_CORE_CTL, val);
4978 }
Michael Chanb090ae22006-01-23 16:07:10 -08004979 rc = bnx2_fw_sync(bp, BNX2_DRV_MSG_DATA_WAIT2 | BNX2_DRV_MSG_CODE_RESET,
Michael Chana2f13892008-07-14 22:38:23 -07004980 1, 0);
Michael Chanb6016b72005-05-26 13:03:09 -07004981
Michael Chandf149d72007-07-07 22:51:36 -07004982 REG_WR(bp, BNX2_MISC_ENABLE_SET_BITS, BNX2_MISC_ENABLE_DEFAULT);
Michael Chanb6016b72005-05-26 13:03:09 -07004983 REG_RD(bp, BNX2_MISC_ENABLE_SET_BITS);
4984
4985 udelay(20);
4986
Michael Chanbf5295b2006-03-23 01:11:56 -08004987 bp->hc_cmd = REG_RD(bp, BNX2_HC_COMMAND);
4988
Michael Chanb090ae22006-01-23 16:07:10 -08004989 return rc;
Michael Chanb6016b72005-05-26 13:03:09 -07004990}
4991
Michael Chan59b47d82006-11-19 14:10:45 -08004992static void
Michael Chanc76c0472007-12-20 20:01:19 -08004993bnx2_clear_ring_states(struct bnx2 *bp)
4994{
4995 struct bnx2_napi *bnapi;
Michael Chan35e90102008-06-19 16:37:42 -07004996 struct bnx2_tx_ring_info *txr;
Michael Chanbb4f98a2008-06-19 16:38:19 -07004997 struct bnx2_rx_ring_info *rxr;
Michael Chanc76c0472007-12-20 20:01:19 -08004998 int i;
4999
5000 for (i = 0; i < BNX2_MAX_MSIX_VEC; i++) {
5001 bnapi = &bp->bnx2_napi[i];
Michael Chan35e90102008-06-19 16:37:42 -07005002 txr = &bnapi->tx_ring;
Michael Chanbb4f98a2008-06-19 16:38:19 -07005003 rxr = &bnapi->rx_ring;
Michael Chanc76c0472007-12-20 20:01:19 -08005004
Michael Chan35e90102008-06-19 16:37:42 -07005005 txr->tx_cons = 0;
5006 txr->hw_tx_cons = 0;
Michael Chanbb4f98a2008-06-19 16:38:19 -07005007 rxr->rx_prod_bseq = 0;
5008 rxr->rx_prod = 0;
5009 rxr->rx_cons = 0;
5010 rxr->rx_pg_prod = 0;
5011 rxr->rx_pg_cons = 0;
Michael Chanc76c0472007-12-20 20:01:19 -08005012 }
5013}
5014
5015static void
Michael Chan35e90102008-06-19 16:37:42 -07005016bnx2_init_tx_context(struct bnx2 *bp, u32 cid, struct bnx2_tx_ring_info *txr)
Michael Chan59b47d82006-11-19 14:10:45 -08005017{
5018 u32 val, offset0, offset1, offset2, offset3;
Michael Chan62a83132008-01-29 21:35:40 -08005019 u32 cid_addr = GET_CID_ADDR(cid);
Michael Chan59b47d82006-11-19 14:10:45 -08005020
5021 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
5022 offset0 = BNX2_L2CTX_TYPE_XI;
5023 offset1 = BNX2_L2CTX_CMD_TYPE_XI;
5024 offset2 = BNX2_L2CTX_TBDR_BHADDR_HI_XI;
5025 offset3 = BNX2_L2CTX_TBDR_BHADDR_LO_XI;
5026 } else {
5027 offset0 = BNX2_L2CTX_TYPE;
5028 offset1 = BNX2_L2CTX_CMD_TYPE;
5029 offset2 = BNX2_L2CTX_TBDR_BHADDR_HI;
5030 offset3 = BNX2_L2CTX_TBDR_BHADDR_LO;
5031 }
5032 val = BNX2_L2CTX_TYPE_TYPE_L2 | BNX2_L2CTX_TYPE_SIZE_L2;
Michael Chan62a83132008-01-29 21:35:40 -08005033 bnx2_ctx_wr(bp, cid_addr, offset0, val);
Michael Chan59b47d82006-11-19 14:10:45 -08005034
5035 val = BNX2_L2CTX_CMD_TYPE_TYPE_L2 | (8 << 16);
Michael Chan62a83132008-01-29 21:35:40 -08005036 bnx2_ctx_wr(bp, cid_addr, offset1, val);
Michael Chan59b47d82006-11-19 14:10:45 -08005037
Michael Chan35e90102008-06-19 16:37:42 -07005038 val = (u64) txr->tx_desc_mapping >> 32;
Michael Chan62a83132008-01-29 21:35:40 -08005039 bnx2_ctx_wr(bp, cid_addr, offset2, val);
Michael Chan59b47d82006-11-19 14:10:45 -08005040
Michael Chan35e90102008-06-19 16:37:42 -07005041 val = (u64) txr->tx_desc_mapping & 0xffffffff;
Michael Chan62a83132008-01-29 21:35:40 -08005042 bnx2_ctx_wr(bp, cid_addr, offset3, val);
Michael Chan59b47d82006-11-19 14:10:45 -08005043}
Michael Chanb6016b72005-05-26 13:03:09 -07005044
5045static void
Michael Chan35e90102008-06-19 16:37:42 -07005046bnx2_init_tx_ring(struct bnx2 *bp, int ring_num)
Michael Chanb6016b72005-05-26 13:03:09 -07005047{
5048 struct tx_bd *txbd;
Michael Chanc76c0472007-12-20 20:01:19 -08005049 u32 cid = TX_CID;
5050 struct bnx2_napi *bnapi;
Michael Chan35e90102008-06-19 16:37:42 -07005051 struct bnx2_tx_ring_info *txr;
Michael Chanc76c0472007-12-20 20:01:19 -08005052
Michael Chan35e90102008-06-19 16:37:42 -07005053 bnapi = &bp->bnx2_napi[ring_num];
5054 txr = &bnapi->tx_ring;
5055
5056 if (ring_num == 0)
5057 cid = TX_CID;
5058 else
5059 cid = TX_TSS_CID + ring_num - 1;
Michael Chanb6016b72005-05-26 13:03:09 -07005060
Michael Chan2f8af122006-08-15 01:39:10 -07005061 bp->tx_wake_thresh = bp->tx_ring_size / 2;
5062
Michael Chan35e90102008-06-19 16:37:42 -07005063 txbd = &txr->tx_desc_ring[MAX_TX_DESC_CNT];
Jeff Garzik6aa20a22006-09-13 13:24:59 -04005064
Michael Chan35e90102008-06-19 16:37:42 -07005065 txbd->tx_bd_haddr_hi = (u64) txr->tx_desc_mapping >> 32;
5066 txbd->tx_bd_haddr_lo = (u64) txr->tx_desc_mapping & 0xffffffff;
Michael Chanb6016b72005-05-26 13:03:09 -07005067
Michael Chan35e90102008-06-19 16:37:42 -07005068 txr->tx_prod = 0;
5069 txr->tx_prod_bseq = 0;
Jeff Garzik6aa20a22006-09-13 13:24:59 -04005070
Michael Chan35e90102008-06-19 16:37:42 -07005071 txr->tx_bidx_addr = MB_GET_CID_ADDR(cid) + BNX2_L2CTX_TX_HOST_BIDX;
5072 txr->tx_bseq_addr = MB_GET_CID_ADDR(cid) + BNX2_L2CTX_TX_HOST_BSEQ;
Michael Chanb6016b72005-05-26 13:03:09 -07005073
Michael Chan35e90102008-06-19 16:37:42 -07005074 bnx2_init_tx_context(bp, cid, txr);
Michael Chanb6016b72005-05-26 13:03:09 -07005075}
5076
5077static void
Michael Chan5d5d0012007-12-12 11:17:43 -08005078bnx2_init_rxbd_rings(struct rx_bd *rx_ring[], dma_addr_t dma[], u32 buf_size,
5079 int num_rings)
Michael Chanb6016b72005-05-26 13:03:09 -07005080{
Michael Chanb6016b72005-05-26 13:03:09 -07005081 int i;
Michael Chan5d5d0012007-12-12 11:17:43 -08005082 struct rx_bd *rxbd;
Michael Chanb6016b72005-05-26 13:03:09 -07005083
Michael Chan5d5d0012007-12-12 11:17:43 -08005084 for (i = 0; i < num_rings; i++) {
Michael Chan13daffa2006-03-20 17:49:20 -08005085 int j;
Michael Chanb6016b72005-05-26 13:03:09 -07005086
Michael Chan5d5d0012007-12-12 11:17:43 -08005087 rxbd = &rx_ring[i][0];
Michael Chan13daffa2006-03-20 17:49:20 -08005088 for (j = 0; j < MAX_RX_DESC_CNT; j++, rxbd++) {
Michael Chan5d5d0012007-12-12 11:17:43 -08005089 rxbd->rx_bd_len = buf_size;
Michael Chan13daffa2006-03-20 17:49:20 -08005090 rxbd->rx_bd_flags = RX_BD_FLAGS_START | RX_BD_FLAGS_END;
5091 }
Michael Chan5d5d0012007-12-12 11:17:43 -08005092 if (i == (num_rings - 1))
Michael Chan13daffa2006-03-20 17:49:20 -08005093 j = 0;
5094 else
5095 j = i + 1;
Michael Chan5d5d0012007-12-12 11:17:43 -08005096 rxbd->rx_bd_haddr_hi = (u64) dma[j] >> 32;
5097 rxbd->rx_bd_haddr_lo = (u64) dma[j] & 0xffffffff;
Michael Chan13daffa2006-03-20 17:49:20 -08005098 }
Michael Chan5d5d0012007-12-12 11:17:43 -08005099}
5100
5101static void
Michael Chanbb4f98a2008-06-19 16:38:19 -07005102bnx2_init_rx_ring(struct bnx2 *bp, int ring_num)
Michael Chan5d5d0012007-12-12 11:17:43 -08005103{
5104 int i;
5105 u16 prod, ring_prod;
Michael Chanbb4f98a2008-06-19 16:38:19 -07005106 u32 cid, rx_cid_addr, val;
5107 struct bnx2_napi *bnapi = &bp->bnx2_napi[ring_num];
5108 struct bnx2_rx_ring_info *rxr = &bnapi->rx_ring;
Michael Chan5d5d0012007-12-12 11:17:43 -08005109
Michael Chanbb4f98a2008-06-19 16:38:19 -07005110 if (ring_num == 0)
5111 cid = RX_CID;
5112 else
5113 cid = RX_RSS_CID + ring_num - 1;
5114
5115 rx_cid_addr = GET_CID_ADDR(cid);
5116
5117 bnx2_init_rxbd_rings(rxr->rx_desc_ring, rxr->rx_desc_mapping,
Michael Chan5d5d0012007-12-12 11:17:43 -08005118 bp->rx_buf_use_size, bp->rx_max_ring);
5119
Michael Chanbb4f98a2008-06-19 16:38:19 -07005120 bnx2_init_rx_context(bp, cid);
Michael Chan83e3fc82008-01-29 21:37:17 -08005121
5122 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
5123 val = REG_RD(bp, BNX2_MQ_MAP_L2_5);
5124 REG_WR(bp, BNX2_MQ_MAP_L2_5, val | BNX2_MQ_MAP_L2_5_ARM);
5125 }
5126
Michael Chan62a83132008-01-29 21:35:40 -08005127 bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_PG_BUF_SIZE, 0);
Michael Chan47bf4242007-12-12 11:19:12 -08005128 if (bp->rx_pg_ring_size) {
Michael Chanbb4f98a2008-06-19 16:38:19 -07005129 bnx2_init_rxbd_rings(rxr->rx_pg_desc_ring,
5130 rxr->rx_pg_desc_mapping,
Michael Chan47bf4242007-12-12 11:19:12 -08005131 PAGE_SIZE, bp->rx_max_pg_ring);
5132 val = (bp->rx_buf_use_size << 16) | PAGE_SIZE;
Michael Chan62a83132008-01-29 21:35:40 -08005133 bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_PG_BUF_SIZE, val);
5134 bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_RBDC_KEY,
Michael Chan5e9ad9e2008-06-19 16:43:17 -07005135 BNX2_L2CTX_RBDC_JUMBO_KEY - ring_num);
Michael Chan47bf4242007-12-12 11:19:12 -08005136
Michael Chanbb4f98a2008-06-19 16:38:19 -07005137 val = (u64) rxr->rx_pg_desc_mapping[0] >> 32;
Michael Chan62a83132008-01-29 21:35:40 -08005138 bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_NX_PG_BDHADDR_HI, val);
Michael Chan47bf4242007-12-12 11:19:12 -08005139
Michael Chanbb4f98a2008-06-19 16:38:19 -07005140 val = (u64) rxr->rx_pg_desc_mapping[0] & 0xffffffff;
Michael Chan62a83132008-01-29 21:35:40 -08005141 bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_NX_PG_BDHADDR_LO, val);
Michael Chan47bf4242007-12-12 11:19:12 -08005142
5143 if (CHIP_NUM(bp) == CHIP_NUM_5709)
5144 REG_WR(bp, BNX2_MQ_MAP_L2_3, BNX2_MQ_MAP_L2_3_DEFAULT);
5145 }
Michael Chanb6016b72005-05-26 13:03:09 -07005146
Michael Chanbb4f98a2008-06-19 16:38:19 -07005147 val = (u64) rxr->rx_desc_mapping[0] >> 32;
Michael Chan62a83132008-01-29 21:35:40 -08005148 bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_NX_BDHADDR_HI, val);
Michael Chanb6016b72005-05-26 13:03:09 -07005149
Michael Chanbb4f98a2008-06-19 16:38:19 -07005150 val = (u64) rxr->rx_desc_mapping[0] & 0xffffffff;
Michael Chan62a83132008-01-29 21:35:40 -08005151 bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_NX_BDHADDR_LO, val);
Michael Chanb6016b72005-05-26 13:03:09 -07005152
Michael Chanbb4f98a2008-06-19 16:38:19 -07005153 ring_prod = prod = rxr->rx_pg_prod;
Michael Chan47bf4242007-12-12 11:19:12 -08005154 for (i = 0; i < bp->rx_pg_ring_size; i++) {
Michael Chanb929e532009-12-03 09:46:33 +00005155 if (bnx2_alloc_rx_page(bp, rxr, ring_prod) < 0) {
Joe Perches3a9c6a42010-02-17 15:01:51 +00005156 netdev_warn(bp->dev, "init'ed rx page ring %d with %d/%d pages only\n",
5157 ring_num, i, bp->rx_pg_ring_size);
Michael Chan47bf4242007-12-12 11:19:12 -08005158 break;
Michael Chanb929e532009-12-03 09:46:33 +00005159 }
Michael Chan47bf4242007-12-12 11:19:12 -08005160 prod = NEXT_RX_BD(prod);
5161 ring_prod = RX_PG_RING_IDX(prod);
5162 }
Michael Chanbb4f98a2008-06-19 16:38:19 -07005163 rxr->rx_pg_prod = prod;
Michael Chan47bf4242007-12-12 11:19:12 -08005164
Michael Chanbb4f98a2008-06-19 16:38:19 -07005165 ring_prod = prod = rxr->rx_prod;
Michael Chan236b6392006-03-20 17:49:02 -08005166 for (i = 0; i < bp->rx_ring_size; i++) {
Michael Chanb929e532009-12-03 09:46:33 +00005167 if (bnx2_alloc_rx_skb(bp, rxr, ring_prod) < 0) {
Joe Perches3a9c6a42010-02-17 15:01:51 +00005168 netdev_warn(bp->dev, "init'ed rx ring %d with %d/%d skbs only\n",
5169 ring_num, i, bp->rx_ring_size);
Michael Chanb6016b72005-05-26 13:03:09 -07005170 break;
Michael Chanb929e532009-12-03 09:46:33 +00005171 }
Michael Chanb6016b72005-05-26 13:03:09 -07005172 prod = NEXT_RX_BD(prod);
5173 ring_prod = RX_RING_IDX(prod);
5174 }
Michael Chanbb4f98a2008-06-19 16:38:19 -07005175 rxr->rx_prod = prod;
Michael Chanb6016b72005-05-26 13:03:09 -07005176
Michael Chanbb4f98a2008-06-19 16:38:19 -07005177 rxr->rx_bidx_addr = MB_GET_CID_ADDR(cid) + BNX2_L2CTX_HOST_BDIDX;
5178 rxr->rx_bseq_addr = MB_GET_CID_ADDR(cid) + BNX2_L2CTX_HOST_BSEQ;
5179 rxr->rx_pg_bidx_addr = MB_GET_CID_ADDR(cid) + BNX2_L2CTX_HOST_PG_BDIDX;
Michael Chanb6016b72005-05-26 13:03:09 -07005180
Michael Chanbb4f98a2008-06-19 16:38:19 -07005181 REG_WR16(bp, rxr->rx_pg_bidx_addr, rxr->rx_pg_prod);
5182 REG_WR16(bp, rxr->rx_bidx_addr, prod);
5183
5184 REG_WR(bp, rxr->rx_bseq_addr, rxr->rx_prod_bseq);
Michael Chanb6016b72005-05-26 13:03:09 -07005185}
5186
Michael Chan35e90102008-06-19 16:37:42 -07005187static void
5188bnx2_init_all_rings(struct bnx2 *bp)
5189{
5190 int i;
Michael Chan5e9ad9e2008-06-19 16:43:17 -07005191 u32 val;
Michael Chan35e90102008-06-19 16:37:42 -07005192
5193 bnx2_clear_ring_states(bp);
5194
5195 REG_WR(bp, BNX2_TSCH_TSS_CFG, 0);
5196 for (i = 0; i < bp->num_tx_rings; i++)
5197 bnx2_init_tx_ring(bp, i);
5198
5199 if (bp->num_tx_rings > 1)
5200 REG_WR(bp, BNX2_TSCH_TSS_CFG, ((bp->num_tx_rings - 1) << 24) |
5201 (TX_TSS_CID << 7));
5202
Michael Chan5e9ad9e2008-06-19 16:43:17 -07005203 REG_WR(bp, BNX2_RLUP_RSS_CONFIG, 0);
5204 bnx2_reg_wr_ind(bp, BNX2_RXP_SCRATCH_RSS_TBL_SZ, 0);
5205
Michael Chanbb4f98a2008-06-19 16:38:19 -07005206 for (i = 0; i < bp->num_rx_rings; i++)
5207 bnx2_init_rx_ring(bp, i);
Michael Chan5e9ad9e2008-06-19 16:43:17 -07005208
5209 if (bp->num_rx_rings > 1) {
5210 u32 tbl_32;
5211 u8 *tbl = (u8 *) &tbl_32;
5212
5213 bnx2_reg_wr_ind(bp, BNX2_RXP_SCRATCH_RSS_TBL_SZ,
5214 BNX2_RXP_SCRATCH_RSS_TBL_MAX_ENTRIES);
5215
5216 for (i = 0; i < BNX2_RXP_SCRATCH_RSS_TBL_MAX_ENTRIES; i++) {
5217 tbl[i % 4] = i % (bp->num_rx_rings - 1);
5218 if ((i % 4) == 3)
5219 bnx2_reg_wr_ind(bp,
5220 BNX2_RXP_SCRATCH_RSS_TBL + i,
5221 cpu_to_be32(tbl_32));
5222 }
5223
5224 val = BNX2_RLUP_RSS_CONFIG_IPV4_RSS_TYPE_ALL_XI |
5225 BNX2_RLUP_RSS_CONFIG_IPV6_RSS_TYPE_ALL_XI;
5226
5227 REG_WR(bp, BNX2_RLUP_RSS_CONFIG, val);
5228
5229 }
Michael Chan35e90102008-06-19 16:37:42 -07005230}
5231
Michael Chan5d5d0012007-12-12 11:17:43 -08005232static u32 bnx2_find_max_ring(u32 ring_size, u32 max_size)
Michael Chan13daffa2006-03-20 17:49:20 -08005233{
Michael Chan5d5d0012007-12-12 11:17:43 -08005234 u32 max, num_rings = 1;
Michael Chan13daffa2006-03-20 17:49:20 -08005235
Michael Chan5d5d0012007-12-12 11:17:43 -08005236 while (ring_size > MAX_RX_DESC_CNT) {
5237 ring_size -= MAX_RX_DESC_CNT;
Michael Chan13daffa2006-03-20 17:49:20 -08005238 num_rings++;
5239 }
5240 /* round to next power of 2 */
Michael Chan5d5d0012007-12-12 11:17:43 -08005241 max = max_size;
Michael Chan13daffa2006-03-20 17:49:20 -08005242 while ((max & num_rings) == 0)
5243 max >>= 1;
5244
5245 if (num_rings != max)
5246 max <<= 1;
5247
Michael Chan5d5d0012007-12-12 11:17:43 -08005248 return max;
5249}
5250
5251static void
5252bnx2_set_rx_ring_size(struct bnx2 *bp, u32 size)
5253{
Michael Chan84eaa182007-12-12 11:19:57 -08005254 u32 rx_size, rx_space, jumbo_size;
Michael Chan5d5d0012007-12-12 11:17:43 -08005255
5256 /* 8 for CRC and VLAN */
Benjamin Lid89cb6a2008-05-16 22:18:57 -07005257 rx_size = bp->dev->mtu + ETH_HLEN + BNX2_RX_OFFSET + 8;
Michael Chan5d5d0012007-12-12 11:17:43 -08005258
Michael Chan84eaa182007-12-12 11:19:57 -08005259 rx_space = SKB_DATA_ALIGN(rx_size + BNX2_RX_ALIGN) + NET_SKB_PAD +
5260 sizeof(struct skb_shared_info);
5261
Benjamin Li601d3d12008-05-16 22:19:35 -07005262 bp->rx_copy_thresh = BNX2_RX_COPY_THRESH;
Michael Chan47bf4242007-12-12 11:19:12 -08005263 bp->rx_pg_ring_size = 0;
5264 bp->rx_max_pg_ring = 0;
5265 bp->rx_max_pg_ring_idx = 0;
David S. Millerf86e82f2008-01-21 17:15:40 -08005266 if ((rx_space > PAGE_SIZE) && !(bp->flags & BNX2_FLAG_JUMBO_BROKEN)) {
Michael Chan84eaa182007-12-12 11:19:57 -08005267 int pages = PAGE_ALIGN(bp->dev->mtu - 40) >> PAGE_SHIFT;
5268
5269 jumbo_size = size * pages;
5270 if (jumbo_size > MAX_TOTAL_RX_PG_DESC_CNT)
5271 jumbo_size = MAX_TOTAL_RX_PG_DESC_CNT;
5272
5273 bp->rx_pg_ring_size = jumbo_size;
5274 bp->rx_max_pg_ring = bnx2_find_max_ring(jumbo_size,
5275 MAX_RX_PG_RINGS);
5276 bp->rx_max_pg_ring_idx = (bp->rx_max_pg_ring * RX_DESC_CNT) - 1;
Benjamin Li601d3d12008-05-16 22:19:35 -07005277 rx_size = BNX2_RX_COPY_THRESH + BNX2_RX_OFFSET;
Michael Chan84eaa182007-12-12 11:19:57 -08005278 bp->rx_copy_thresh = 0;
5279 }
Michael Chan5d5d0012007-12-12 11:17:43 -08005280
5281 bp->rx_buf_use_size = rx_size;
5282 /* hw alignment */
5283 bp->rx_buf_size = bp->rx_buf_use_size + BNX2_RX_ALIGN;
Benjamin Lid89cb6a2008-05-16 22:18:57 -07005284 bp->rx_jumbo_thresh = rx_size - BNX2_RX_OFFSET;
Michael Chan5d5d0012007-12-12 11:17:43 -08005285 bp->rx_ring_size = size;
5286 bp->rx_max_ring = bnx2_find_max_ring(size, MAX_RX_RINGS);
Michael Chan13daffa2006-03-20 17:49:20 -08005287 bp->rx_max_ring_idx = (bp->rx_max_ring * RX_DESC_CNT) - 1;
5288}
5289
5290static void
Michael Chanb6016b72005-05-26 13:03:09 -07005291bnx2_free_tx_skbs(struct bnx2 *bp)
5292{
5293 int i;
5294
Michael Chan35e90102008-06-19 16:37:42 -07005295 for (i = 0; i < bp->num_tx_rings; i++) {
5296 struct bnx2_napi *bnapi = &bp->bnx2_napi[i];
5297 struct bnx2_tx_ring_info *txr = &bnapi->tx_ring;
5298 int j;
Michael Chanb6016b72005-05-26 13:03:09 -07005299
Michael Chan35e90102008-06-19 16:37:42 -07005300 if (txr->tx_buf_ring == NULL)
Michael Chanb6016b72005-05-26 13:03:09 -07005301 continue;
Michael Chanb6016b72005-05-26 13:03:09 -07005302
Michael Chan35e90102008-06-19 16:37:42 -07005303 for (j = 0; j < TX_DESC_CNT; ) {
Benjamin Li3d16af82008-10-09 12:26:41 -07005304 struct sw_tx_bd *tx_buf = &txr->tx_buf_ring[j];
Michael Chan35e90102008-06-19 16:37:42 -07005305 struct sk_buff *skb = tx_buf->skb;
Alexander Duycke95524a2009-12-02 16:47:57 +00005306 int k, last;
Michael Chan35e90102008-06-19 16:37:42 -07005307
5308 if (skb == NULL) {
5309 j++;
5310 continue;
5311 }
5312
Alexander Duycke95524a2009-12-02 16:47:57 +00005313 pci_unmap_single(bp->pdev,
5314 pci_unmap_addr(tx_buf, mapping),
5315 skb_headlen(skb),
5316 PCI_DMA_TODEVICE);
Michael Chanb6016b72005-05-26 13:03:09 -07005317
Michael Chan35e90102008-06-19 16:37:42 -07005318 tx_buf->skb = NULL;
Michael Chanb6016b72005-05-26 13:03:09 -07005319
Alexander Duycke95524a2009-12-02 16:47:57 +00005320 last = tx_buf->nr_frags;
5321 j++;
5322 for (k = 0; k < last; k++, j++) {
5323 tx_buf = &txr->tx_buf_ring[TX_RING_IDX(j)];
5324 pci_unmap_page(bp->pdev,
5325 pci_unmap_addr(tx_buf, mapping),
5326 skb_shinfo(skb)->frags[k].size,
5327 PCI_DMA_TODEVICE);
5328 }
Michael Chan35e90102008-06-19 16:37:42 -07005329 dev_kfree_skb(skb);
Michael Chanb6016b72005-05-26 13:03:09 -07005330 }
Michael Chanb6016b72005-05-26 13:03:09 -07005331 }
Michael Chanb6016b72005-05-26 13:03:09 -07005332}
5333
5334static void
5335bnx2_free_rx_skbs(struct bnx2 *bp)
5336{
5337 int i;
5338
Michael Chanbb4f98a2008-06-19 16:38:19 -07005339 for (i = 0; i < bp->num_rx_rings; i++) {
5340 struct bnx2_napi *bnapi = &bp->bnx2_napi[i];
5341 struct bnx2_rx_ring_info *rxr = &bnapi->rx_ring;
5342 int j;
Michael Chanb6016b72005-05-26 13:03:09 -07005343
Michael Chanbb4f98a2008-06-19 16:38:19 -07005344 if (rxr->rx_buf_ring == NULL)
5345 return;
Michael Chanb6016b72005-05-26 13:03:09 -07005346
Michael Chanbb4f98a2008-06-19 16:38:19 -07005347 for (j = 0; j < bp->rx_max_ring_idx; j++) {
5348 struct sw_bd *rx_buf = &rxr->rx_buf_ring[j];
5349 struct sk_buff *skb = rx_buf->skb;
Michael Chanb6016b72005-05-26 13:03:09 -07005350
Michael Chanbb4f98a2008-06-19 16:38:19 -07005351 if (skb == NULL)
5352 continue;
Michael Chanb6016b72005-05-26 13:03:09 -07005353
Michael Chanbb4f98a2008-06-19 16:38:19 -07005354 pci_unmap_single(bp->pdev,
5355 pci_unmap_addr(rx_buf, mapping),
5356 bp->rx_buf_use_size,
5357 PCI_DMA_FROMDEVICE);
Michael Chanb6016b72005-05-26 13:03:09 -07005358
Michael Chanbb4f98a2008-06-19 16:38:19 -07005359 rx_buf->skb = NULL;
5360
5361 dev_kfree_skb(skb);
5362 }
5363 for (j = 0; j < bp->rx_max_pg_ring_idx; j++)
5364 bnx2_free_rx_page(bp, rxr, j);
Michael Chanb6016b72005-05-26 13:03:09 -07005365 }
5366}
5367
5368static void
5369bnx2_free_skbs(struct bnx2 *bp)
5370{
5371 bnx2_free_tx_skbs(bp);
5372 bnx2_free_rx_skbs(bp);
5373}
5374
5375static int
5376bnx2_reset_nic(struct bnx2 *bp, u32 reset_code)
5377{
5378 int rc;
5379
5380 rc = bnx2_reset_chip(bp, reset_code);
5381 bnx2_free_skbs(bp);
5382 if (rc)
5383 return rc;
5384
Michael Chanfba9fe92006-06-12 22:21:25 -07005385 if ((rc = bnx2_init_chip(bp)) != 0)
5386 return rc;
5387
Michael Chan35e90102008-06-19 16:37:42 -07005388 bnx2_init_all_rings(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07005389 return 0;
5390}
5391
5392static int
Michael Chan9a120bc2008-05-16 22:17:45 -07005393bnx2_init_nic(struct bnx2 *bp, int reset_phy)
Michael Chanb6016b72005-05-26 13:03:09 -07005394{
5395 int rc;
5396
5397 if ((rc = bnx2_reset_nic(bp, BNX2_DRV_MSG_CODE_RESET)) != 0)
5398 return rc;
5399
Michael Chan80be4432006-11-19 14:07:28 -08005400 spin_lock_bh(&bp->phy_lock);
Michael Chan9a120bc2008-05-16 22:17:45 -07005401 bnx2_init_phy(bp, reset_phy);
Michael Chanb6016b72005-05-26 13:03:09 -07005402 bnx2_set_link(bp);
Michael Chan543a8272008-05-02 16:56:44 -07005403 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
5404 bnx2_remote_phy_event(bp);
Michael Chan0d8a6572007-07-07 22:49:43 -07005405 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07005406 return 0;
5407}
5408
5409static int
Michael Chan74bf4ba2008-10-09 12:21:08 -07005410bnx2_shutdown_chip(struct bnx2 *bp)
5411{
5412 u32 reset_code;
5413
5414 if (bp->flags & BNX2_FLAG_NO_WOL)
5415 reset_code = BNX2_DRV_MSG_CODE_UNLOAD_LNK_DN;
5416 else if (bp->wol)
5417 reset_code = BNX2_DRV_MSG_CODE_SUSPEND_WOL;
5418 else
5419 reset_code = BNX2_DRV_MSG_CODE_SUSPEND_NO_WOL;
5420
5421 return bnx2_reset_chip(bp, reset_code);
5422}
5423
5424static int
Michael Chanb6016b72005-05-26 13:03:09 -07005425bnx2_test_registers(struct bnx2 *bp)
5426{
5427 int ret;
Michael Chan5bae30c2007-05-03 13:18:46 -07005428 int i, is_5709;
Arjan van de Venf71e1302006-03-03 21:33:57 -05005429 static const struct {
Michael Chanb6016b72005-05-26 13:03:09 -07005430 u16 offset;
5431 u16 flags;
Michael Chan5bae30c2007-05-03 13:18:46 -07005432#define BNX2_FL_NOT_5709 1
Michael Chanb6016b72005-05-26 13:03:09 -07005433 u32 rw_mask;
5434 u32 ro_mask;
5435 } reg_tbl[] = {
5436 { 0x006c, 0, 0x00000000, 0x0000003f },
5437 { 0x0090, 0, 0xffffffff, 0x00000000 },
5438 { 0x0094, 0, 0x00000000, 0x00000000 },
5439
Michael Chan5bae30c2007-05-03 13:18:46 -07005440 { 0x0404, BNX2_FL_NOT_5709, 0x00003f00, 0x00000000 },
5441 { 0x0418, BNX2_FL_NOT_5709, 0x00000000, 0xffffffff },
5442 { 0x041c, BNX2_FL_NOT_5709, 0x00000000, 0xffffffff },
5443 { 0x0420, BNX2_FL_NOT_5709, 0x00000000, 0x80ffffff },
5444 { 0x0424, BNX2_FL_NOT_5709, 0x00000000, 0x00000000 },
5445 { 0x0428, BNX2_FL_NOT_5709, 0x00000000, 0x00000001 },
5446 { 0x0450, BNX2_FL_NOT_5709, 0x00000000, 0x0000ffff },
5447 { 0x0454, BNX2_FL_NOT_5709, 0x00000000, 0xffffffff },
5448 { 0x0458, BNX2_FL_NOT_5709, 0x00000000, 0xffffffff },
Michael Chanb6016b72005-05-26 13:03:09 -07005449
Michael Chan5bae30c2007-05-03 13:18:46 -07005450 { 0x0808, BNX2_FL_NOT_5709, 0x00000000, 0xffffffff },
5451 { 0x0854, BNX2_FL_NOT_5709, 0x00000000, 0xffffffff },
5452 { 0x0868, BNX2_FL_NOT_5709, 0x00000000, 0x77777777 },
5453 { 0x086c, BNX2_FL_NOT_5709, 0x00000000, 0x77777777 },
5454 { 0x0870, BNX2_FL_NOT_5709, 0x00000000, 0x77777777 },
5455 { 0x0874, BNX2_FL_NOT_5709, 0x00000000, 0x77777777 },
Michael Chanb6016b72005-05-26 13:03:09 -07005456
Michael Chan5bae30c2007-05-03 13:18:46 -07005457 { 0x0c00, BNX2_FL_NOT_5709, 0x00000000, 0x00000001 },
5458 { 0x0c04, BNX2_FL_NOT_5709, 0x00000000, 0x03ff0001 },
5459 { 0x0c08, BNX2_FL_NOT_5709, 0x0f0ff073, 0x00000000 },
Michael Chanb6016b72005-05-26 13:03:09 -07005460
5461 { 0x1000, 0, 0x00000000, 0x00000001 },
Michael Chan15b169c2008-05-02 16:57:08 -07005462 { 0x1004, BNX2_FL_NOT_5709, 0x00000000, 0x000f0001 },
Michael Chanb6016b72005-05-26 13:03:09 -07005463
5464 { 0x1408, 0, 0x01c00800, 0x00000000 },
5465 { 0x149c, 0, 0x8000ffff, 0x00000000 },
5466 { 0x14a8, 0, 0x00000000, 0x000001ff },
Michael Chan5b0c76a2005-11-04 08:45:49 -08005467 { 0x14ac, 0, 0x0fffffff, 0x10000000 },
Michael Chanb6016b72005-05-26 13:03:09 -07005468 { 0x14b0, 0, 0x00000002, 0x00000001 },
5469 { 0x14b8, 0, 0x00000000, 0x00000000 },
5470 { 0x14c0, 0, 0x00000000, 0x00000009 },
5471 { 0x14c4, 0, 0x00003fff, 0x00000000 },
5472 { 0x14cc, 0, 0x00000000, 0x00000001 },
5473 { 0x14d0, 0, 0xffffffff, 0x00000000 },
Michael Chanb6016b72005-05-26 13:03:09 -07005474
5475 { 0x1800, 0, 0x00000000, 0x00000001 },
5476 { 0x1804, 0, 0x00000000, 0x00000003 },
Michael Chanb6016b72005-05-26 13:03:09 -07005477
5478 { 0x2800, 0, 0x00000000, 0x00000001 },
5479 { 0x2804, 0, 0x00000000, 0x00003f01 },
5480 { 0x2808, 0, 0x0f3f3f03, 0x00000000 },
5481 { 0x2810, 0, 0xffff0000, 0x00000000 },
5482 { 0x2814, 0, 0xffff0000, 0x00000000 },
5483 { 0x2818, 0, 0xffff0000, 0x00000000 },
5484 { 0x281c, 0, 0xffff0000, 0x00000000 },
5485 { 0x2834, 0, 0xffffffff, 0x00000000 },
5486 { 0x2840, 0, 0x00000000, 0xffffffff },
5487 { 0x2844, 0, 0x00000000, 0xffffffff },
5488 { 0x2848, 0, 0xffffffff, 0x00000000 },
5489 { 0x284c, 0, 0xf800f800, 0x07ff07ff },
5490
5491 { 0x2c00, 0, 0x00000000, 0x00000011 },
5492 { 0x2c04, 0, 0x00000000, 0x00030007 },
5493
Michael Chanb6016b72005-05-26 13:03:09 -07005494 { 0x3c00, 0, 0x00000000, 0x00000001 },
5495 { 0x3c04, 0, 0x00000000, 0x00070000 },
5496 { 0x3c08, 0, 0x00007f71, 0x07f00000 },
5497 { 0x3c0c, 0, 0x1f3ffffc, 0x00000000 },
5498 { 0x3c10, 0, 0xffffffff, 0x00000000 },
5499 { 0x3c14, 0, 0x00000000, 0xffffffff },
5500 { 0x3c18, 0, 0x00000000, 0xffffffff },
5501 { 0x3c1c, 0, 0xfffff000, 0x00000000 },
5502 { 0x3c20, 0, 0xffffff00, 0x00000000 },
Michael Chanb6016b72005-05-26 13:03:09 -07005503
5504 { 0x5004, 0, 0x00000000, 0x0000007f },
5505 { 0x5008, 0, 0x0f0007ff, 0x00000000 },
Michael Chanb6016b72005-05-26 13:03:09 -07005506
Michael Chanb6016b72005-05-26 13:03:09 -07005507 { 0x5c00, 0, 0x00000000, 0x00000001 },
5508 { 0x5c04, 0, 0x00000000, 0x0003000f },
5509 { 0x5c08, 0, 0x00000003, 0x00000000 },
5510 { 0x5c0c, 0, 0x0000fff8, 0x00000000 },
5511 { 0x5c10, 0, 0x00000000, 0xffffffff },
5512 { 0x5c80, 0, 0x00000000, 0x0f7113f1 },
5513 { 0x5c84, 0, 0x00000000, 0x0000f333 },
5514 { 0x5c88, 0, 0x00000000, 0x00077373 },
5515 { 0x5c8c, 0, 0x00000000, 0x0007f737 },
5516
5517 { 0x6808, 0, 0x0000ff7f, 0x00000000 },
5518 { 0x680c, 0, 0xffffffff, 0x00000000 },
5519 { 0x6810, 0, 0xffffffff, 0x00000000 },
5520 { 0x6814, 0, 0xffffffff, 0x00000000 },
5521 { 0x6818, 0, 0xffffffff, 0x00000000 },
5522 { 0x681c, 0, 0xffffffff, 0x00000000 },
5523 { 0x6820, 0, 0x00ff00ff, 0x00000000 },
5524 { 0x6824, 0, 0x00ff00ff, 0x00000000 },
5525 { 0x6828, 0, 0x00ff00ff, 0x00000000 },
5526 { 0x682c, 0, 0x03ff03ff, 0x00000000 },
5527 { 0x6830, 0, 0x03ff03ff, 0x00000000 },
5528 { 0x6834, 0, 0x03ff03ff, 0x00000000 },
5529 { 0x6838, 0, 0x03ff03ff, 0x00000000 },
5530 { 0x683c, 0, 0x0000ffff, 0x00000000 },
5531 { 0x6840, 0, 0x00000ff0, 0x00000000 },
5532 { 0x6844, 0, 0x00ffff00, 0x00000000 },
5533 { 0x684c, 0, 0xffffffff, 0x00000000 },
5534 { 0x6850, 0, 0x7f7f7f7f, 0x00000000 },
5535 { 0x6854, 0, 0x7f7f7f7f, 0x00000000 },
5536 { 0x6858, 0, 0x7f7f7f7f, 0x00000000 },
5537 { 0x685c, 0, 0x7f7f7f7f, 0x00000000 },
5538 { 0x6908, 0, 0x00000000, 0x0001ff0f },
5539 { 0x690c, 0, 0x00000000, 0x0ffe00f0 },
5540
5541 { 0xffff, 0, 0x00000000, 0x00000000 },
5542 };
5543
5544 ret = 0;
Michael Chan5bae30c2007-05-03 13:18:46 -07005545 is_5709 = 0;
5546 if (CHIP_NUM(bp) == CHIP_NUM_5709)
5547 is_5709 = 1;
5548
Michael Chanb6016b72005-05-26 13:03:09 -07005549 for (i = 0; reg_tbl[i].offset != 0xffff; i++) {
5550 u32 offset, rw_mask, ro_mask, save_val, val;
Michael Chan5bae30c2007-05-03 13:18:46 -07005551 u16 flags = reg_tbl[i].flags;
5552
5553 if (is_5709 && (flags & BNX2_FL_NOT_5709))
5554 continue;
Michael Chanb6016b72005-05-26 13:03:09 -07005555
5556 offset = (u32) reg_tbl[i].offset;
5557 rw_mask = reg_tbl[i].rw_mask;
5558 ro_mask = reg_tbl[i].ro_mask;
5559
Peter Hagervall14ab9b82005-08-10 14:18:16 -07005560 save_val = readl(bp->regview + offset);
Michael Chanb6016b72005-05-26 13:03:09 -07005561
Peter Hagervall14ab9b82005-08-10 14:18:16 -07005562 writel(0, bp->regview + offset);
Michael Chanb6016b72005-05-26 13:03:09 -07005563
Peter Hagervall14ab9b82005-08-10 14:18:16 -07005564 val = readl(bp->regview + offset);
Michael Chanb6016b72005-05-26 13:03:09 -07005565 if ((val & rw_mask) != 0) {
5566 goto reg_test_err;
5567 }
5568
5569 if ((val & ro_mask) != (save_val & ro_mask)) {
5570 goto reg_test_err;
5571 }
5572
Peter Hagervall14ab9b82005-08-10 14:18:16 -07005573 writel(0xffffffff, bp->regview + offset);
Michael Chanb6016b72005-05-26 13:03:09 -07005574
Peter Hagervall14ab9b82005-08-10 14:18:16 -07005575 val = readl(bp->regview + offset);
Michael Chanb6016b72005-05-26 13:03:09 -07005576 if ((val & rw_mask) != rw_mask) {
5577 goto reg_test_err;
5578 }
5579
5580 if ((val & ro_mask) != (save_val & ro_mask)) {
5581 goto reg_test_err;
5582 }
5583
Peter Hagervall14ab9b82005-08-10 14:18:16 -07005584 writel(save_val, bp->regview + offset);
Michael Chanb6016b72005-05-26 13:03:09 -07005585 continue;
5586
5587reg_test_err:
Peter Hagervall14ab9b82005-08-10 14:18:16 -07005588 writel(save_val, bp->regview + offset);
Michael Chanb6016b72005-05-26 13:03:09 -07005589 ret = -ENODEV;
5590 break;
5591 }
5592 return ret;
5593}
5594
5595static int
5596bnx2_do_mem_test(struct bnx2 *bp, u32 start, u32 size)
5597{
Arjan van de Venf71e1302006-03-03 21:33:57 -05005598 static const u32 test_pattern[] = { 0x00000000, 0xffffffff, 0x55555555,
Michael Chanb6016b72005-05-26 13:03:09 -07005599 0xaaaaaaaa , 0xaa55aa55, 0x55aa55aa };
5600 int i;
5601
5602 for (i = 0; i < sizeof(test_pattern) / 4; i++) {
5603 u32 offset;
5604
5605 for (offset = 0; offset < size; offset += 4) {
5606
Michael Chan2726d6e2008-01-29 21:35:05 -08005607 bnx2_reg_wr_ind(bp, start + offset, test_pattern[i]);
Michael Chanb6016b72005-05-26 13:03:09 -07005608
Michael Chan2726d6e2008-01-29 21:35:05 -08005609 if (bnx2_reg_rd_ind(bp, start + offset) !=
Michael Chanb6016b72005-05-26 13:03:09 -07005610 test_pattern[i]) {
5611 return -ENODEV;
5612 }
5613 }
5614 }
5615 return 0;
5616}
5617
5618static int
5619bnx2_test_memory(struct bnx2 *bp)
5620{
5621 int ret = 0;
5622 int i;
Michael Chan5bae30c2007-05-03 13:18:46 -07005623 static struct mem_entry {
Michael Chanb6016b72005-05-26 13:03:09 -07005624 u32 offset;
5625 u32 len;
Michael Chan5bae30c2007-05-03 13:18:46 -07005626 } mem_tbl_5706[] = {
Michael Chanb6016b72005-05-26 13:03:09 -07005627 { 0x60000, 0x4000 },
Michael Chan5b0c76a2005-11-04 08:45:49 -08005628 { 0xa0000, 0x3000 },
Michael Chanb6016b72005-05-26 13:03:09 -07005629 { 0xe0000, 0x4000 },
5630 { 0x120000, 0x4000 },
5631 { 0x1a0000, 0x4000 },
5632 { 0x160000, 0x4000 },
5633 { 0xffffffff, 0 },
Michael Chan5bae30c2007-05-03 13:18:46 -07005634 },
5635 mem_tbl_5709[] = {
5636 { 0x60000, 0x4000 },
5637 { 0xa0000, 0x3000 },
5638 { 0xe0000, 0x4000 },
5639 { 0x120000, 0x4000 },
5640 { 0x1a0000, 0x4000 },
5641 { 0xffffffff, 0 },
Michael Chanb6016b72005-05-26 13:03:09 -07005642 };
Michael Chan5bae30c2007-05-03 13:18:46 -07005643 struct mem_entry *mem_tbl;
5644
5645 if (CHIP_NUM(bp) == CHIP_NUM_5709)
5646 mem_tbl = mem_tbl_5709;
5647 else
5648 mem_tbl = mem_tbl_5706;
Michael Chanb6016b72005-05-26 13:03:09 -07005649
5650 for (i = 0; mem_tbl[i].offset != 0xffffffff; i++) {
5651 if ((ret = bnx2_do_mem_test(bp, mem_tbl[i].offset,
5652 mem_tbl[i].len)) != 0) {
5653 return ret;
5654 }
5655 }
Jeff Garzik6aa20a22006-09-13 13:24:59 -04005656
Michael Chanb6016b72005-05-26 13:03:09 -07005657 return ret;
5658}
5659
Michael Chanbc5a0692006-01-23 16:13:22 -08005660#define BNX2_MAC_LOOPBACK 0
5661#define BNX2_PHY_LOOPBACK 1
5662
Michael Chanb6016b72005-05-26 13:03:09 -07005663static int
Michael Chanbc5a0692006-01-23 16:13:22 -08005664bnx2_run_loopback(struct bnx2 *bp, int loopback_mode)
Michael Chanb6016b72005-05-26 13:03:09 -07005665{
5666 unsigned int pkt_size, num_pkts, i;
5667 struct sk_buff *skb, *rx_skb;
5668 unsigned char *packet;
Michael Chanbc5a0692006-01-23 16:13:22 -08005669 u16 rx_start_idx, rx_idx;
Michael Chanb6016b72005-05-26 13:03:09 -07005670 dma_addr_t map;
5671 struct tx_bd *txbd;
5672 struct sw_bd *rx_buf;
5673 struct l2_fhdr *rx_hdr;
5674 int ret = -ENODEV;
Michael Chanc76c0472007-12-20 20:01:19 -08005675 struct bnx2_napi *bnapi = &bp->bnx2_napi[0], *tx_napi;
Michael Chan35e90102008-06-19 16:37:42 -07005676 struct bnx2_tx_ring_info *txr = &bnapi->tx_ring;
Michael Chanbb4f98a2008-06-19 16:38:19 -07005677 struct bnx2_rx_ring_info *rxr = &bnapi->rx_ring;
Michael Chanc76c0472007-12-20 20:01:19 -08005678
5679 tx_napi = bnapi;
Michael Chanb6016b72005-05-26 13:03:09 -07005680
Michael Chan35e90102008-06-19 16:37:42 -07005681 txr = &tx_napi->tx_ring;
Michael Chanbb4f98a2008-06-19 16:38:19 -07005682 rxr = &bnapi->rx_ring;
Michael Chanbc5a0692006-01-23 16:13:22 -08005683 if (loopback_mode == BNX2_MAC_LOOPBACK) {
5684 bp->loopback = MAC_LOOPBACK;
5685 bnx2_set_mac_loopback(bp);
5686 }
5687 else if (loopback_mode == BNX2_PHY_LOOPBACK) {
Michael Chan583c28e2008-01-21 19:51:35 -08005688 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
Michael Chan489310a2007-10-10 16:16:31 -07005689 return 0;
5690
Michael Chan80be4432006-11-19 14:07:28 -08005691 bp->loopback = PHY_LOOPBACK;
Michael Chanbc5a0692006-01-23 16:13:22 -08005692 bnx2_set_phy_loopback(bp);
5693 }
5694 else
5695 return -EINVAL;
Michael Chanb6016b72005-05-26 13:03:09 -07005696
Michael Chan84eaa182007-12-12 11:19:57 -08005697 pkt_size = min(bp->dev->mtu + ETH_HLEN, bp->rx_jumbo_thresh - 4);
Michael Chan932f3772006-08-15 01:39:36 -07005698 skb = netdev_alloc_skb(bp->dev, pkt_size);
John W. Linvilleb6cbc3b62005-11-10 12:58:00 -08005699 if (!skb)
5700 return -ENOMEM;
Michael Chanb6016b72005-05-26 13:03:09 -07005701 packet = skb_put(skb, pkt_size);
Michael Chan66342922006-12-14 15:57:04 -08005702 memcpy(packet, bp->dev->dev_addr, 6);
Michael Chanb6016b72005-05-26 13:03:09 -07005703 memset(packet + 6, 0x0, 8);
5704 for (i = 14; i < pkt_size; i++)
5705 packet[i] = (unsigned char) (i & 0xff);
5706
Alexander Duycke95524a2009-12-02 16:47:57 +00005707 map = pci_map_single(bp->pdev, skb->data, pkt_size,
5708 PCI_DMA_TODEVICE);
5709 if (pci_dma_mapping_error(bp->pdev, map)) {
Benjamin Li3d16af82008-10-09 12:26:41 -07005710 dev_kfree_skb(skb);
5711 return -EIO;
5712 }
Michael Chanb6016b72005-05-26 13:03:09 -07005713
Michael Chanbf5295b2006-03-23 01:11:56 -08005714 REG_WR(bp, BNX2_HC_COMMAND,
5715 bp->hc_cmd | BNX2_HC_COMMAND_COAL_NOW_WO_INT);
5716
Michael Chanb6016b72005-05-26 13:03:09 -07005717 REG_RD(bp, BNX2_HC_COMMAND);
5718
5719 udelay(5);
Michael Chan35efa7c2007-12-20 19:56:37 -08005720 rx_start_idx = bnx2_get_hw_rx_cons(bnapi);
Michael Chanb6016b72005-05-26 13:03:09 -07005721
Michael Chanb6016b72005-05-26 13:03:09 -07005722 num_pkts = 0;
5723
Michael Chan35e90102008-06-19 16:37:42 -07005724 txbd = &txr->tx_desc_ring[TX_RING_IDX(txr->tx_prod)];
Michael Chanb6016b72005-05-26 13:03:09 -07005725
5726 txbd->tx_bd_haddr_hi = (u64) map >> 32;
5727 txbd->tx_bd_haddr_lo = (u64) map & 0xffffffff;
5728 txbd->tx_bd_mss_nbytes = pkt_size;
5729 txbd->tx_bd_vlan_tag_flags = TX_BD_FLAGS_START | TX_BD_FLAGS_END;
5730
5731 num_pkts++;
Michael Chan35e90102008-06-19 16:37:42 -07005732 txr->tx_prod = NEXT_TX_BD(txr->tx_prod);
5733 txr->tx_prod_bseq += pkt_size;
Michael Chanb6016b72005-05-26 13:03:09 -07005734
Michael Chan35e90102008-06-19 16:37:42 -07005735 REG_WR16(bp, txr->tx_bidx_addr, txr->tx_prod);
5736 REG_WR(bp, txr->tx_bseq_addr, txr->tx_prod_bseq);
Michael Chanb6016b72005-05-26 13:03:09 -07005737
5738 udelay(100);
5739
Michael Chanbf5295b2006-03-23 01:11:56 -08005740 REG_WR(bp, BNX2_HC_COMMAND,
5741 bp->hc_cmd | BNX2_HC_COMMAND_COAL_NOW_WO_INT);
5742
Michael Chanb6016b72005-05-26 13:03:09 -07005743 REG_RD(bp, BNX2_HC_COMMAND);
5744
5745 udelay(5);
5746
Alexander Duycke95524a2009-12-02 16:47:57 +00005747 pci_unmap_single(bp->pdev, map, pkt_size, PCI_DMA_TODEVICE);
Michael Chan745720e2006-06-29 12:37:41 -07005748 dev_kfree_skb(skb);
Michael Chanb6016b72005-05-26 13:03:09 -07005749
Michael Chan35e90102008-06-19 16:37:42 -07005750 if (bnx2_get_hw_tx_cons(tx_napi) != txr->tx_prod)
Michael Chanb6016b72005-05-26 13:03:09 -07005751 goto loopback_test_done;
Michael Chanb6016b72005-05-26 13:03:09 -07005752
Michael Chan35efa7c2007-12-20 19:56:37 -08005753 rx_idx = bnx2_get_hw_rx_cons(bnapi);
Michael Chanb6016b72005-05-26 13:03:09 -07005754 if (rx_idx != rx_start_idx + num_pkts) {
5755 goto loopback_test_done;
5756 }
5757
Michael Chanbb4f98a2008-06-19 16:38:19 -07005758 rx_buf = &rxr->rx_buf_ring[rx_start_idx];
Michael Chanb6016b72005-05-26 13:03:09 -07005759 rx_skb = rx_buf->skb;
5760
5761 rx_hdr = (struct l2_fhdr *) rx_skb->data;
Benjamin Lid89cb6a2008-05-16 22:18:57 -07005762 skb_reserve(rx_skb, BNX2_RX_OFFSET);
Michael Chanb6016b72005-05-26 13:03:09 -07005763
5764 pci_dma_sync_single_for_cpu(bp->pdev,
5765 pci_unmap_addr(rx_buf, mapping),
5766 bp->rx_buf_size, PCI_DMA_FROMDEVICE);
5767
Michael Chanade2bfe2006-01-23 16:09:51 -08005768 if (rx_hdr->l2_fhdr_status &
Michael Chanb6016b72005-05-26 13:03:09 -07005769 (L2_FHDR_ERRORS_BAD_CRC |
5770 L2_FHDR_ERRORS_PHY_DECODE |
5771 L2_FHDR_ERRORS_ALIGNMENT |
5772 L2_FHDR_ERRORS_TOO_SHORT |
5773 L2_FHDR_ERRORS_GIANT_FRAME)) {
5774
5775 goto loopback_test_done;
5776 }
5777
5778 if ((rx_hdr->l2_fhdr_pkt_len - 4) != pkt_size) {
5779 goto loopback_test_done;
5780 }
5781
5782 for (i = 14; i < pkt_size; i++) {
5783 if (*(rx_skb->data + i) != (unsigned char) (i & 0xff)) {
5784 goto loopback_test_done;
5785 }
5786 }
5787
5788 ret = 0;
5789
5790loopback_test_done:
5791 bp->loopback = 0;
5792 return ret;
5793}
5794
Michael Chanbc5a0692006-01-23 16:13:22 -08005795#define BNX2_MAC_LOOPBACK_FAILED 1
5796#define BNX2_PHY_LOOPBACK_FAILED 2
5797#define BNX2_LOOPBACK_FAILED (BNX2_MAC_LOOPBACK_FAILED | \
5798 BNX2_PHY_LOOPBACK_FAILED)
5799
5800static int
5801bnx2_test_loopback(struct bnx2 *bp)
5802{
5803 int rc = 0;
5804
5805 if (!netif_running(bp->dev))
5806 return BNX2_LOOPBACK_FAILED;
5807
5808 bnx2_reset_nic(bp, BNX2_DRV_MSG_CODE_RESET);
5809 spin_lock_bh(&bp->phy_lock);
Michael Chan9a120bc2008-05-16 22:17:45 -07005810 bnx2_init_phy(bp, 1);
Michael Chanbc5a0692006-01-23 16:13:22 -08005811 spin_unlock_bh(&bp->phy_lock);
5812 if (bnx2_run_loopback(bp, BNX2_MAC_LOOPBACK))
5813 rc |= BNX2_MAC_LOOPBACK_FAILED;
5814 if (bnx2_run_loopback(bp, BNX2_PHY_LOOPBACK))
5815 rc |= BNX2_PHY_LOOPBACK_FAILED;
5816 return rc;
5817}
5818
Michael Chanb6016b72005-05-26 13:03:09 -07005819#define NVRAM_SIZE 0x200
5820#define CRC32_RESIDUAL 0xdebb20e3
5821
5822static int
5823bnx2_test_nvram(struct bnx2 *bp)
5824{
Al Virob491edd2007-12-22 19:44:51 +00005825 __be32 buf[NVRAM_SIZE / 4];
Michael Chanb6016b72005-05-26 13:03:09 -07005826 u8 *data = (u8 *) buf;
5827 int rc = 0;
5828 u32 magic, csum;
5829
5830 if ((rc = bnx2_nvram_read(bp, 0, data, 4)) != 0)
5831 goto test_nvram_done;
5832
5833 magic = be32_to_cpu(buf[0]);
5834 if (magic != 0x669955aa) {
5835 rc = -ENODEV;
5836 goto test_nvram_done;
5837 }
5838
5839 if ((rc = bnx2_nvram_read(bp, 0x100, data, NVRAM_SIZE)) != 0)
5840 goto test_nvram_done;
5841
5842 csum = ether_crc_le(0x100, data);
5843 if (csum != CRC32_RESIDUAL) {
5844 rc = -ENODEV;
5845 goto test_nvram_done;
5846 }
5847
5848 csum = ether_crc_le(0x100, data + 0x100);
5849 if (csum != CRC32_RESIDUAL) {
5850 rc = -ENODEV;
5851 }
5852
5853test_nvram_done:
5854 return rc;
5855}
5856
5857static int
5858bnx2_test_link(struct bnx2 *bp)
5859{
5860 u32 bmsr;
5861
Michael Chan9f52b562008-10-09 12:21:46 -07005862 if (!netif_running(bp->dev))
5863 return -ENODEV;
5864
Michael Chan583c28e2008-01-21 19:51:35 -08005865 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP) {
Michael Chan489310a2007-10-10 16:16:31 -07005866 if (bp->link_up)
5867 return 0;
5868 return -ENODEV;
5869 }
Michael Chanc770a652005-08-25 15:38:39 -07005870 spin_lock_bh(&bp->phy_lock);
Michael Chan27a005b2007-05-03 13:23:41 -07005871 bnx2_enable_bmsr1(bp);
5872 bnx2_read_phy(bp, bp->mii_bmsr1, &bmsr);
5873 bnx2_read_phy(bp, bp->mii_bmsr1, &bmsr);
5874 bnx2_disable_bmsr1(bp);
Michael Chanc770a652005-08-25 15:38:39 -07005875 spin_unlock_bh(&bp->phy_lock);
Jeff Garzik6aa20a22006-09-13 13:24:59 -04005876
Michael Chanb6016b72005-05-26 13:03:09 -07005877 if (bmsr & BMSR_LSTATUS) {
5878 return 0;
5879 }
5880 return -ENODEV;
5881}
5882
5883static int
5884bnx2_test_intr(struct bnx2 *bp)
5885{
5886 int i;
Michael Chanb6016b72005-05-26 13:03:09 -07005887 u16 status_idx;
5888
5889 if (!netif_running(bp->dev))
5890 return -ENODEV;
5891
5892 status_idx = REG_RD(bp, BNX2_PCICFG_INT_ACK_CMD) & 0xffff;
5893
5894 /* This register is not touched during run-time. */
Michael Chanbf5295b2006-03-23 01:11:56 -08005895 REG_WR(bp, BNX2_HC_COMMAND, bp->hc_cmd | BNX2_HC_COMMAND_COAL_NOW);
Michael Chanb6016b72005-05-26 13:03:09 -07005896 REG_RD(bp, BNX2_HC_COMMAND);
5897
5898 for (i = 0; i < 10; i++) {
5899 if ((REG_RD(bp, BNX2_PCICFG_INT_ACK_CMD) & 0xffff) !=
5900 status_idx) {
5901
5902 break;
5903 }
5904
5905 msleep_interruptible(10);
5906 }
5907 if (i < 10)
5908 return 0;
5909
5910 return -ENODEV;
5911}
5912
Michael Chan38ea3682008-02-23 19:48:57 -08005913/* Determining link for parallel detection. */
Michael Chanb2fadea2008-01-21 17:07:06 -08005914static int
5915bnx2_5706_serdes_has_link(struct bnx2 *bp)
5916{
5917 u32 mode_ctl, an_dbg, exp;
5918
Michael Chan38ea3682008-02-23 19:48:57 -08005919 if (bp->phy_flags & BNX2_PHY_FLAG_NO_PARALLEL)
5920 return 0;
5921
Michael Chanb2fadea2008-01-21 17:07:06 -08005922 bnx2_write_phy(bp, MII_BNX2_MISC_SHADOW, MISC_SHDW_MODE_CTL);
5923 bnx2_read_phy(bp, MII_BNX2_MISC_SHADOW, &mode_ctl);
5924
5925 if (!(mode_ctl & MISC_SHDW_MODE_CTL_SIG_DET))
5926 return 0;
5927
5928 bnx2_write_phy(bp, MII_BNX2_MISC_SHADOW, MISC_SHDW_AN_DBG);
5929 bnx2_read_phy(bp, MII_BNX2_MISC_SHADOW, &an_dbg);
5930 bnx2_read_phy(bp, MII_BNX2_MISC_SHADOW, &an_dbg);
5931
Michael Chanf3014c0c2008-01-29 21:33:03 -08005932 if (an_dbg & (MISC_SHDW_AN_DBG_NOSYNC | MISC_SHDW_AN_DBG_RUDI_INVALID))
Michael Chanb2fadea2008-01-21 17:07:06 -08005933 return 0;
5934
5935 bnx2_write_phy(bp, MII_BNX2_DSP_ADDRESS, MII_EXPAND_REG1);
5936 bnx2_read_phy(bp, MII_BNX2_DSP_RW_PORT, &exp);
5937 bnx2_read_phy(bp, MII_BNX2_DSP_RW_PORT, &exp);
5938
5939 if (exp & MII_EXPAND_REG1_RUDI_C) /* receiving CONFIG */
5940 return 0;
5941
5942 return 1;
5943}
5944
Michael Chanb6016b72005-05-26 13:03:09 -07005945static void
Michael Chan48b01e22006-11-19 14:08:00 -08005946bnx2_5706_serdes_timer(struct bnx2 *bp)
5947{
Michael Chanb2fadea2008-01-21 17:07:06 -08005948 int check_link = 1;
5949
Michael Chan48b01e22006-11-19 14:08:00 -08005950 spin_lock(&bp->phy_lock);
Michael Chanb2fadea2008-01-21 17:07:06 -08005951 if (bp->serdes_an_pending) {
Michael Chan48b01e22006-11-19 14:08:00 -08005952 bp->serdes_an_pending--;
Michael Chanb2fadea2008-01-21 17:07:06 -08005953 check_link = 0;
5954 } else if ((bp->link_up == 0) && (bp->autoneg & AUTONEG_SPEED)) {
Michael Chan48b01e22006-11-19 14:08:00 -08005955 u32 bmcr;
5956
Benjamin Liac392ab2008-09-18 16:40:49 -07005957 bp->current_interval = BNX2_TIMER_INTERVAL;
Michael Chan48b01e22006-11-19 14:08:00 -08005958
Michael Chanca58c3a2007-05-03 13:22:52 -07005959 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chan48b01e22006-11-19 14:08:00 -08005960
5961 if (bmcr & BMCR_ANENABLE) {
Michael Chanb2fadea2008-01-21 17:07:06 -08005962 if (bnx2_5706_serdes_has_link(bp)) {
Michael Chan48b01e22006-11-19 14:08:00 -08005963 bmcr &= ~BMCR_ANENABLE;
5964 bmcr |= BMCR_SPEED1000 | BMCR_FULLDPLX;
Michael Chanca58c3a2007-05-03 13:22:52 -07005965 bnx2_write_phy(bp, bp->mii_bmcr, bmcr);
Michael Chan583c28e2008-01-21 19:51:35 -08005966 bp->phy_flags |= BNX2_PHY_FLAG_PARALLEL_DETECT;
Michael Chan48b01e22006-11-19 14:08:00 -08005967 }
5968 }
5969 }
5970 else if ((bp->link_up) && (bp->autoneg & AUTONEG_SPEED) &&
Michael Chan583c28e2008-01-21 19:51:35 -08005971 (bp->phy_flags & BNX2_PHY_FLAG_PARALLEL_DETECT)) {
Michael Chan48b01e22006-11-19 14:08:00 -08005972 u32 phy2;
5973
5974 bnx2_write_phy(bp, 0x17, 0x0f01);
5975 bnx2_read_phy(bp, 0x15, &phy2);
5976 if (phy2 & 0x20) {
5977 u32 bmcr;
5978
Michael Chanca58c3a2007-05-03 13:22:52 -07005979 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chan48b01e22006-11-19 14:08:00 -08005980 bmcr |= BMCR_ANENABLE;
Michael Chanca58c3a2007-05-03 13:22:52 -07005981 bnx2_write_phy(bp, bp->mii_bmcr, bmcr);
Michael Chan48b01e22006-11-19 14:08:00 -08005982
Michael Chan583c28e2008-01-21 19:51:35 -08005983 bp->phy_flags &= ~BNX2_PHY_FLAG_PARALLEL_DETECT;
Michael Chan48b01e22006-11-19 14:08:00 -08005984 }
5985 } else
Benjamin Liac392ab2008-09-18 16:40:49 -07005986 bp->current_interval = BNX2_TIMER_INTERVAL;
Michael Chan48b01e22006-11-19 14:08:00 -08005987
Michael Chana2724e22008-02-23 19:47:44 -08005988 if (check_link) {
Michael Chanb2fadea2008-01-21 17:07:06 -08005989 u32 val;
5990
5991 bnx2_write_phy(bp, MII_BNX2_MISC_SHADOW, MISC_SHDW_AN_DBG);
5992 bnx2_read_phy(bp, MII_BNX2_MISC_SHADOW, &val);
5993 bnx2_read_phy(bp, MII_BNX2_MISC_SHADOW, &val);
5994
Michael Chana2724e22008-02-23 19:47:44 -08005995 if (bp->link_up && (val & MISC_SHDW_AN_DBG_NOSYNC)) {
5996 if (!(bp->phy_flags & BNX2_PHY_FLAG_FORCED_DOWN)) {
5997 bnx2_5706s_force_link_dn(bp, 1);
5998 bp->phy_flags |= BNX2_PHY_FLAG_FORCED_DOWN;
5999 } else
6000 bnx2_set_link(bp);
6001 } else if (!bp->link_up && !(val & MISC_SHDW_AN_DBG_NOSYNC))
6002 bnx2_set_link(bp);
Michael Chanb2fadea2008-01-21 17:07:06 -08006003 }
Michael Chan48b01e22006-11-19 14:08:00 -08006004 spin_unlock(&bp->phy_lock);
6005}
6006
6007static void
Michael Chanf8dd0642006-11-19 14:08:29 -08006008bnx2_5708_serdes_timer(struct bnx2 *bp)
6009{
Michael Chan583c28e2008-01-21 19:51:35 -08006010 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
Michael Chan0d8a6572007-07-07 22:49:43 -07006011 return;
6012
Michael Chan583c28e2008-01-21 19:51:35 -08006013 if ((bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE) == 0) {
Michael Chanf8dd0642006-11-19 14:08:29 -08006014 bp->serdes_an_pending = 0;
6015 return;
6016 }
6017
6018 spin_lock(&bp->phy_lock);
6019 if (bp->serdes_an_pending)
6020 bp->serdes_an_pending--;
6021 else if ((bp->link_up == 0) && (bp->autoneg & AUTONEG_SPEED)) {
6022 u32 bmcr;
6023
Michael Chanca58c3a2007-05-03 13:22:52 -07006024 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chanf8dd0642006-11-19 14:08:29 -08006025 if (bmcr & BMCR_ANENABLE) {
Michael Chan605a9e22007-05-03 13:23:13 -07006026 bnx2_enable_forced_2g5(bp);
Michael Chan40105c02008-11-12 16:02:45 -08006027 bp->current_interval = BNX2_SERDES_FORCED_TIMEOUT;
Michael Chanf8dd0642006-11-19 14:08:29 -08006028 } else {
Michael Chan605a9e22007-05-03 13:23:13 -07006029 bnx2_disable_forced_2g5(bp);
Michael Chanf8dd0642006-11-19 14:08:29 -08006030 bp->serdes_an_pending = 2;
Benjamin Liac392ab2008-09-18 16:40:49 -07006031 bp->current_interval = BNX2_TIMER_INTERVAL;
Michael Chanf8dd0642006-11-19 14:08:29 -08006032 }
6033
6034 } else
Benjamin Liac392ab2008-09-18 16:40:49 -07006035 bp->current_interval = BNX2_TIMER_INTERVAL;
Michael Chanf8dd0642006-11-19 14:08:29 -08006036
6037 spin_unlock(&bp->phy_lock);
6038}
6039
6040static void
Michael Chanb6016b72005-05-26 13:03:09 -07006041bnx2_timer(unsigned long data)
6042{
6043 struct bnx2 *bp = (struct bnx2 *) data;
Michael Chanb6016b72005-05-26 13:03:09 -07006044
Michael Chancd339a02005-08-25 15:35:24 -07006045 if (!netif_running(bp->dev))
6046 return;
6047
Michael Chanb6016b72005-05-26 13:03:09 -07006048 if (atomic_read(&bp->intr_sem) != 0)
6049 goto bnx2_restart_timer;
6050
Michael Chanefba0182008-12-03 00:36:15 -08006051 if ((bp->flags & (BNX2_FLAG_USING_MSI | BNX2_FLAG_ONE_SHOT_MSI)) ==
6052 BNX2_FLAG_USING_MSI)
6053 bnx2_chk_missed_msi(bp);
6054
Michael Chandf149d72007-07-07 22:51:36 -07006055 bnx2_send_heart_beat(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07006056
Michael Chan2726d6e2008-01-29 21:35:05 -08006057 bp->stats_blk->stat_FwRxDrop =
6058 bnx2_reg_rd_ind(bp, BNX2_FW_RX_DROP_COUNT);
Michael Chancea94db2006-06-12 22:16:13 -07006059
Michael Chan02537b062007-06-04 21:24:07 -07006060 /* workaround occasional corrupted counters */
Michael Chan61d9e3f2009-08-21 16:20:46 +00006061 if ((bp->flags & BNX2_FLAG_BROKEN_STATS) && bp->stats_ticks)
Michael Chan02537b062007-06-04 21:24:07 -07006062 REG_WR(bp, BNX2_HC_COMMAND, bp->hc_cmd |
6063 BNX2_HC_COMMAND_STATS_NOW);
6064
Michael Chan583c28e2008-01-21 19:51:35 -08006065 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Michael Chanf8dd0642006-11-19 14:08:29 -08006066 if (CHIP_NUM(bp) == CHIP_NUM_5706)
6067 bnx2_5706_serdes_timer(bp);
Michael Chan27a005b2007-05-03 13:23:41 -07006068 else
Michael Chanf8dd0642006-11-19 14:08:29 -08006069 bnx2_5708_serdes_timer(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07006070 }
6071
6072bnx2_restart_timer:
Michael Chancd339a02005-08-25 15:35:24 -07006073 mod_timer(&bp->timer, jiffies + bp->current_interval);
Michael Chanb6016b72005-05-26 13:03:09 -07006074}
6075
Michael Chan8e6a72c2007-05-03 13:24:48 -07006076static int
6077bnx2_request_irq(struct bnx2 *bp)
6078{
Michael Chan6d866ff2007-12-20 19:56:09 -08006079 unsigned long flags;
Michael Chanb4b36042007-12-20 19:59:30 -08006080 struct bnx2_irq *irq;
6081 int rc = 0, i;
Michael Chan8e6a72c2007-05-03 13:24:48 -07006082
David S. Millerf86e82f2008-01-21 17:15:40 -08006083 if (bp->flags & BNX2_FLAG_USING_MSI_OR_MSIX)
Michael Chan6d866ff2007-12-20 19:56:09 -08006084 flags = 0;
6085 else
6086 flags = IRQF_SHARED;
Michael Chanb4b36042007-12-20 19:59:30 -08006087
6088 for (i = 0; i < bp->irq_nvecs; i++) {
6089 irq = &bp->irq_tbl[i];
Michael Chanc76c0472007-12-20 20:01:19 -08006090 rc = request_irq(irq->vector, irq->handler, flags, irq->name,
Michael Chanf0ea2e62008-06-19 16:41:57 -07006091 &bp->bnx2_napi[i]);
Michael Chanb4b36042007-12-20 19:59:30 -08006092 if (rc)
6093 break;
6094 irq->requested = 1;
6095 }
Michael Chan8e6a72c2007-05-03 13:24:48 -07006096 return rc;
6097}
6098
6099static void
6100bnx2_free_irq(struct bnx2 *bp)
6101{
Michael Chanb4b36042007-12-20 19:59:30 -08006102 struct bnx2_irq *irq;
6103 int i;
Michael Chan8e6a72c2007-05-03 13:24:48 -07006104
Michael Chanb4b36042007-12-20 19:59:30 -08006105 for (i = 0; i < bp->irq_nvecs; i++) {
6106 irq = &bp->irq_tbl[i];
6107 if (irq->requested)
Michael Chanf0ea2e62008-06-19 16:41:57 -07006108 free_irq(irq->vector, &bp->bnx2_napi[i]);
Michael Chanb4b36042007-12-20 19:59:30 -08006109 irq->requested = 0;
Michael Chan6d866ff2007-12-20 19:56:09 -08006110 }
David S. Millerf86e82f2008-01-21 17:15:40 -08006111 if (bp->flags & BNX2_FLAG_USING_MSI)
Michael Chanb4b36042007-12-20 19:59:30 -08006112 pci_disable_msi(bp->pdev);
David S. Millerf86e82f2008-01-21 17:15:40 -08006113 else if (bp->flags & BNX2_FLAG_USING_MSIX)
Michael Chanb4b36042007-12-20 19:59:30 -08006114 pci_disable_msix(bp->pdev);
6115
David S. Millerf86e82f2008-01-21 17:15:40 -08006116 bp->flags &= ~(BNX2_FLAG_USING_MSI_OR_MSIX | BNX2_FLAG_ONE_SHOT_MSI);
Michael Chanb4b36042007-12-20 19:59:30 -08006117}
6118
6119static void
Michael Chan5e9ad9e2008-06-19 16:43:17 -07006120bnx2_enable_msix(struct bnx2 *bp, int msix_vecs)
Michael Chanb4b36042007-12-20 19:59:30 -08006121{
Michael Chan57851d82007-12-20 20:01:44 -08006122 int i, rc;
6123 struct msix_entry msix_ent[BNX2_MAX_MSIX_VEC];
Michael Chan4e1d0de2008-12-16 20:27:45 -08006124 struct net_device *dev = bp->dev;
6125 const int len = sizeof(bp->irq_tbl[0].name);
Michael Chan57851d82007-12-20 20:01:44 -08006126
Michael Chanb4b36042007-12-20 19:59:30 -08006127 bnx2_setup_msix_tbl(bp);
6128 REG_WR(bp, BNX2_PCI_MSIX_CONTROL, BNX2_MAX_MSIX_HW_VEC - 1);
6129 REG_WR(bp, BNX2_PCI_MSIX_TBL_OFF_BIR, BNX2_PCI_GRC_WINDOW2_BASE);
6130 REG_WR(bp, BNX2_PCI_MSIX_PBA_OFF_BIT, BNX2_PCI_GRC_WINDOW3_BASE);
Michael Chan57851d82007-12-20 20:01:44 -08006131
Benjamin Lie2eb8e32010-01-08 00:51:21 -08006132 /* Need to flush the previous three writes to ensure MSI-X
6133 * is setup properly */
6134 REG_RD(bp, BNX2_PCI_MSIX_CONTROL);
6135
Michael Chan57851d82007-12-20 20:01:44 -08006136 for (i = 0; i < BNX2_MAX_MSIX_VEC; i++) {
6137 msix_ent[i].entry = i;
6138 msix_ent[i].vector = 0;
6139 }
6140
6141 rc = pci_enable_msix(bp->pdev, msix_ent, BNX2_MAX_MSIX_VEC);
6142 if (rc != 0)
6143 return;
6144
Michael Chan5e9ad9e2008-06-19 16:43:17 -07006145 bp->irq_nvecs = msix_vecs;
David S. Millerf86e82f2008-01-21 17:15:40 -08006146 bp->flags |= BNX2_FLAG_USING_MSIX | BNX2_FLAG_ONE_SHOT_MSI;
Michael Chan69010312009-03-18 18:11:51 -07006147 for (i = 0; i < BNX2_MAX_MSIX_VEC; i++) {
Michael Chan57851d82007-12-20 20:01:44 -08006148 bp->irq_tbl[i].vector = msix_ent[i].vector;
Michael Chan69010312009-03-18 18:11:51 -07006149 snprintf(bp->irq_tbl[i].name, len, "%s-%d", dev->name, i);
6150 bp->irq_tbl[i].handler = bnx2_msi_1shot;
6151 }
Michael Chan6d866ff2007-12-20 19:56:09 -08006152}
6153
6154static void
6155bnx2_setup_int_mode(struct bnx2 *bp, int dis_msi)
6156{
Michael Chan5e9ad9e2008-06-19 16:43:17 -07006157 int cpus = num_online_cpus();
Benjamin Li706bf242008-07-18 17:55:11 -07006158 int msix_vecs = min(cpus + 1, RX_MAX_RINGS);
Michael Chan5e9ad9e2008-06-19 16:43:17 -07006159
Michael Chan6d866ff2007-12-20 19:56:09 -08006160 bp->irq_tbl[0].handler = bnx2_interrupt;
6161 strcpy(bp->irq_tbl[0].name, bp->dev->name);
Michael Chanb4b36042007-12-20 19:59:30 -08006162 bp->irq_nvecs = 1;
6163 bp->irq_tbl[0].vector = bp->pdev->irq;
Michael Chan6d866ff2007-12-20 19:56:09 -08006164
Michael Chan5e9ad9e2008-06-19 16:43:17 -07006165 if ((bp->flags & BNX2_FLAG_MSIX_CAP) && !dis_msi && cpus > 1)
6166 bnx2_enable_msix(bp, msix_vecs);
Michael Chanb4b36042007-12-20 19:59:30 -08006167
David S. Millerf86e82f2008-01-21 17:15:40 -08006168 if ((bp->flags & BNX2_FLAG_MSI_CAP) && !dis_msi &&
6169 !(bp->flags & BNX2_FLAG_USING_MSIX)) {
Michael Chan6d866ff2007-12-20 19:56:09 -08006170 if (pci_enable_msi(bp->pdev) == 0) {
David S. Millerf86e82f2008-01-21 17:15:40 -08006171 bp->flags |= BNX2_FLAG_USING_MSI;
Michael Chan6d866ff2007-12-20 19:56:09 -08006172 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
David S. Millerf86e82f2008-01-21 17:15:40 -08006173 bp->flags |= BNX2_FLAG_ONE_SHOT_MSI;
Michael Chan6d866ff2007-12-20 19:56:09 -08006174 bp->irq_tbl[0].handler = bnx2_msi_1shot;
6175 } else
6176 bp->irq_tbl[0].handler = bnx2_msi;
Michael Chanb4b36042007-12-20 19:59:30 -08006177
6178 bp->irq_tbl[0].vector = bp->pdev->irq;
Michael Chan6d866ff2007-12-20 19:56:09 -08006179 }
6180 }
Benjamin Li706bf242008-07-18 17:55:11 -07006181
6182 bp->num_tx_rings = rounddown_pow_of_two(bp->irq_nvecs);
6183 bp->dev->real_num_tx_queues = bp->num_tx_rings;
6184
Michael Chan5e9ad9e2008-06-19 16:43:17 -07006185 bp->num_rx_rings = bp->irq_nvecs;
Michael Chan8e6a72c2007-05-03 13:24:48 -07006186}
6187
Michael Chanb6016b72005-05-26 13:03:09 -07006188/* Called with rtnl_lock */
6189static int
6190bnx2_open(struct net_device *dev)
6191{
Michael Chan972ec0d2006-01-23 16:12:43 -08006192 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006193 int rc;
6194
Michael Chan1b2f9222007-05-03 13:20:19 -07006195 netif_carrier_off(dev);
6196
Pavel Machek829ca9a2005-09-03 15:56:56 -07006197 bnx2_set_power_state(bp, PCI_D0);
Michael Chanb6016b72005-05-26 13:03:09 -07006198 bnx2_disable_int(bp);
6199
Michael Chan6d866ff2007-12-20 19:56:09 -08006200 bnx2_setup_int_mode(bp, disable_msi);
Benjamin Li4327ba42010-03-23 13:13:11 +00006201 bnx2_init_napi(bp);
Michael Chan35efa7c2007-12-20 19:56:37 -08006202 bnx2_napi_enable(bp);
Michael Chan35e90102008-06-19 16:37:42 -07006203 rc = bnx2_alloc_mem(bp);
Michael Chan2739a8b2008-06-19 16:44:10 -07006204 if (rc)
6205 goto open_err;
Michael Chan35e90102008-06-19 16:37:42 -07006206
Michael Chan8e6a72c2007-05-03 13:24:48 -07006207 rc = bnx2_request_irq(bp);
Michael Chan2739a8b2008-06-19 16:44:10 -07006208 if (rc)
6209 goto open_err;
Michael Chanb6016b72005-05-26 13:03:09 -07006210
Michael Chan9a120bc2008-05-16 22:17:45 -07006211 rc = bnx2_init_nic(bp, 1);
Michael Chan2739a8b2008-06-19 16:44:10 -07006212 if (rc)
6213 goto open_err;
Jeff Garzik6aa20a22006-09-13 13:24:59 -04006214
Michael Chancd339a02005-08-25 15:35:24 -07006215 mod_timer(&bp->timer, jiffies + bp->current_interval);
Michael Chanb6016b72005-05-26 13:03:09 -07006216
6217 atomic_set(&bp->intr_sem, 0);
6218
Michael Chan354fcd72010-01-17 07:30:44 +00006219 memset(bp->temp_stats_blk, 0, sizeof(struct statistics_block));
6220
Michael Chanb6016b72005-05-26 13:03:09 -07006221 bnx2_enable_int(bp);
6222
David S. Millerf86e82f2008-01-21 17:15:40 -08006223 if (bp->flags & BNX2_FLAG_USING_MSI) {
Michael Chanb6016b72005-05-26 13:03:09 -07006224 /* Test MSI to make sure it is working
6225 * If MSI test fails, go back to INTx mode
6226 */
6227 if (bnx2_test_intr(bp) != 0) {
Joe Perches3a9c6a42010-02-17 15:01:51 +00006228 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 -07006229
6230 bnx2_disable_int(bp);
Michael Chan8e6a72c2007-05-03 13:24:48 -07006231 bnx2_free_irq(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07006232
Michael Chan6d866ff2007-12-20 19:56:09 -08006233 bnx2_setup_int_mode(bp, 1);
6234
Michael Chan9a120bc2008-05-16 22:17:45 -07006235 rc = bnx2_init_nic(bp, 0);
Michael Chanb6016b72005-05-26 13:03:09 -07006236
Michael Chan8e6a72c2007-05-03 13:24:48 -07006237 if (!rc)
6238 rc = bnx2_request_irq(bp);
6239
Michael Chanb6016b72005-05-26 13:03:09 -07006240 if (rc) {
Michael Chanb6016b72005-05-26 13:03:09 -07006241 del_timer_sync(&bp->timer);
Michael Chan2739a8b2008-06-19 16:44:10 -07006242 goto open_err;
Michael Chanb6016b72005-05-26 13:03:09 -07006243 }
6244 bnx2_enable_int(bp);
6245 }
6246 }
David S. Millerf86e82f2008-01-21 17:15:40 -08006247 if (bp->flags & BNX2_FLAG_USING_MSI)
Joe Perches3a9c6a42010-02-17 15:01:51 +00006248 netdev_info(dev, "using MSI\n");
David S. Millerf86e82f2008-01-21 17:15:40 -08006249 else if (bp->flags & BNX2_FLAG_USING_MSIX)
Joe Perches3a9c6a42010-02-17 15:01:51 +00006250 netdev_info(dev, "using MSIX\n");
Michael Chanb6016b72005-05-26 13:03:09 -07006251
Benjamin Li706bf242008-07-18 17:55:11 -07006252 netif_tx_start_all_queues(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006253
6254 return 0;
Michael Chan2739a8b2008-06-19 16:44:10 -07006255
6256open_err:
6257 bnx2_napi_disable(bp);
6258 bnx2_free_skbs(bp);
6259 bnx2_free_irq(bp);
6260 bnx2_free_mem(bp);
6261 return rc;
Michael Chanb6016b72005-05-26 13:03:09 -07006262}
6263
6264static void
David Howellsc4028952006-11-22 14:57:56 +00006265bnx2_reset_task(struct work_struct *work)
Michael Chanb6016b72005-05-26 13:03:09 -07006266{
David Howellsc4028952006-11-22 14:57:56 +00006267 struct bnx2 *bp = container_of(work, struct bnx2, reset_task);
Michael Chanb6016b72005-05-26 13:03:09 -07006268
Michael Chan51bf6bb2009-12-03 09:46:31 +00006269 rtnl_lock();
6270 if (!netif_running(bp->dev)) {
6271 rtnl_unlock();
Michael Chanafdc08b2005-08-25 15:34:29 -07006272 return;
Michael Chan51bf6bb2009-12-03 09:46:31 +00006273 }
Michael Chanafdc08b2005-08-25 15:34:29 -07006274
Michael Chanb6016b72005-05-26 13:03:09 -07006275 bnx2_netif_stop(bp);
6276
Michael Chan9a120bc2008-05-16 22:17:45 -07006277 bnx2_init_nic(bp, 1);
Michael Chanb6016b72005-05-26 13:03:09 -07006278
6279 atomic_set(&bp->intr_sem, 1);
6280 bnx2_netif_start(bp);
Michael Chan51bf6bb2009-12-03 09:46:31 +00006281 rtnl_unlock();
Michael Chanb6016b72005-05-26 13:03:09 -07006282}
6283
6284static void
Michael Chan20175c52009-12-03 09:46:32 +00006285bnx2_dump_state(struct bnx2 *bp)
6286{
6287 struct net_device *dev = bp->dev;
6288
Joe Perches3a9c6a42010-02-17 15:01:51 +00006289 netdev_err(dev, "DEBUG: intr_sem[%x]\n", atomic_read(&bp->intr_sem));
6290 netdev_err(dev, "DEBUG: EMAC_TX_STATUS[%08x] RPM_MGMT_PKT_CTRL[%08x]\n",
6291 REG_RD(bp, BNX2_EMAC_TX_STATUS),
6292 REG_RD(bp, BNX2_RPM_MGMT_PKT_CTRL));
6293 netdev_err(dev, "DEBUG: MCP_STATE_P0[%08x] MCP_STATE_P1[%08x]\n",
6294 bnx2_reg_rd_ind(bp, BNX2_MCP_STATE_P0),
6295 bnx2_reg_rd_ind(bp, BNX2_MCP_STATE_P1));
6296 netdev_err(dev, "DEBUG: HC_STATS_INTERRUPT_STATUS[%08x]\n",
6297 REG_RD(bp, BNX2_HC_STATS_INTERRUPT_STATUS));
Michael Chan20175c52009-12-03 09:46:32 +00006298 if (bp->flags & BNX2_FLAG_USING_MSIX)
Joe Perches3a9c6a42010-02-17 15:01:51 +00006299 netdev_err(dev, "DEBUG: PBA[%08x]\n",
6300 REG_RD(bp, BNX2_PCI_GRC_WINDOW3_BASE));
Michael Chan20175c52009-12-03 09:46:32 +00006301}
6302
6303static void
Michael Chanb6016b72005-05-26 13:03:09 -07006304bnx2_tx_timeout(struct net_device *dev)
6305{
Michael Chan972ec0d2006-01-23 16:12:43 -08006306 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006307
Michael Chan20175c52009-12-03 09:46:32 +00006308 bnx2_dump_state(bp);
6309
Michael Chanb6016b72005-05-26 13:03:09 -07006310 /* This allows the netif to be shutdown gracefully before resetting */
6311 schedule_work(&bp->reset_task);
6312}
6313
6314#ifdef BCM_VLAN
6315/* Called with rtnl_lock */
6316static void
6317bnx2_vlan_rx_register(struct net_device *dev, struct vlan_group *vlgrp)
6318{
Michael Chan972ec0d2006-01-23 16:12:43 -08006319 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006320
Michael Chan37675462009-08-21 16:20:44 +00006321 if (netif_running(dev))
6322 bnx2_netif_stop(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07006323
6324 bp->vlgrp = vlgrp;
Michael Chan37675462009-08-21 16:20:44 +00006325
6326 if (!netif_running(dev))
6327 return;
6328
Michael Chanb6016b72005-05-26 13:03:09 -07006329 bnx2_set_rx_mode(dev);
Michael Chan7c62e832008-07-14 22:39:03 -07006330 if (bp->flags & BNX2_FLAG_CAN_KEEP_VLAN)
6331 bnx2_fw_sync(bp, BNX2_DRV_MSG_CODE_KEEP_VLAN_UPDATE, 0, 1);
Michael Chanb6016b72005-05-26 13:03:09 -07006332
6333 bnx2_netif_start(bp);
6334}
Michael Chanb6016b72005-05-26 13:03:09 -07006335#endif
6336
Herbert Xu932ff272006-06-09 12:20:56 -07006337/* Called with netif_tx_lock.
Michael Chan2f8af122006-08-15 01:39:10 -07006338 * bnx2_tx_int() runs without netif_tx_lock unless it needs to call
6339 * netif_wake_queue().
Michael Chanb6016b72005-05-26 13:03:09 -07006340 */
Stephen Hemminger613573252009-08-31 19:50:58 +00006341static netdev_tx_t
Michael Chanb6016b72005-05-26 13:03:09 -07006342bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev)
6343{
Michael Chan972ec0d2006-01-23 16:12:43 -08006344 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006345 dma_addr_t mapping;
6346 struct tx_bd *txbd;
Benjamin Li3d16af82008-10-09 12:26:41 -07006347 struct sw_tx_bd *tx_buf;
Michael Chanb6016b72005-05-26 13:03:09 -07006348 u32 len, vlan_tag_flags, last_frag, mss;
6349 u16 prod, ring_prod;
6350 int i;
Benjamin Li706bf242008-07-18 17:55:11 -07006351 struct bnx2_napi *bnapi;
6352 struct bnx2_tx_ring_info *txr;
6353 struct netdev_queue *txq;
6354
6355 /* Determine which tx ring we will be placed on */
6356 i = skb_get_queue_mapping(skb);
6357 bnapi = &bp->bnx2_napi[i];
6358 txr = &bnapi->tx_ring;
6359 txq = netdev_get_tx_queue(dev, i);
Michael Chanb6016b72005-05-26 13:03:09 -07006360
Michael Chan35e90102008-06-19 16:37:42 -07006361 if (unlikely(bnx2_tx_avail(bp, txr) <
Michael Chana550c992007-12-20 19:56:59 -08006362 (skb_shinfo(skb)->nr_frags + 1))) {
Benjamin Li706bf242008-07-18 17:55:11 -07006363 netif_tx_stop_queue(txq);
Joe Perches3a9c6a42010-02-17 15:01:51 +00006364 netdev_err(dev, "BUG! Tx ring full when queue awake!\n");
Michael Chanb6016b72005-05-26 13:03:09 -07006365
6366 return NETDEV_TX_BUSY;
6367 }
6368 len = skb_headlen(skb);
Michael Chan35e90102008-06-19 16:37:42 -07006369 prod = txr->tx_prod;
Michael Chanb6016b72005-05-26 13:03:09 -07006370 ring_prod = TX_RING_IDX(prod);
6371
6372 vlan_tag_flags = 0;
Patrick McHardy84fa7932006-08-29 16:44:56 -07006373 if (skb->ip_summed == CHECKSUM_PARTIAL) {
Michael Chanb6016b72005-05-26 13:03:09 -07006374 vlan_tag_flags |= TX_BD_FLAGS_TCP_UDP_CKSUM;
6375 }
6376
Michael Chan729b85c2008-08-14 15:29:39 -07006377#ifdef BCM_VLAN
Al Viro79ea13c2008-01-24 02:06:46 -08006378 if (bp->vlgrp && vlan_tx_tag_present(skb)) {
Michael Chanb6016b72005-05-26 13:03:09 -07006379 vlan_tag_flags |=
6380 (TX_BD_FLAGS_VLAN_TAG | (vlan_tx_tag_get(skb) << 16));
6381 }
Michael Chan729b85c2008-08-14 15:29:39 -07006382#endif
Michael Chanfde82052007-05-03 17:23:35 -07006383 if ((mss = skb_shinfo(skb)->gso_size)) {
Michael Chana1efb4b2008-10-09 12:24:39 -07006384 u32 tcp_opt_len;
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -07006385 struct iphdr *iph;
Michael Chanb6016b72005-05-26 13:03:09 -07006386
Michael Chanb6016b72005-05-26 13:03:09 -07006387 vlan_tag_flags |= TX_BD_FLAGS_SW_LSO;
6388
Michael Chan4666f872007-05-03 13:22:28 -07006389 tcp_opt_len = tcp_optlen(skb);
Arnaldo Carvalho de Meloab6a5bb2007-03-18 17:43:48 -07006390
Michael Chan4666f872007-05-03 13:22:28 -07006391 if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6) {
6392 u32 tcp_off = skb_transport_offset(skb) -
6393 sizeof(struct ipv6hdr) - ETH_HLEN;
Michael Chanb6016b72005-05-26 13:03:09 -07006394
Michael Chan4666f872007-05-03 13:22:28 -07006395 vlan_tag_flags |= ((tcp_opt_len >> 2) << 8) |
6396 TX_BD_FLAGS_SW_FLAGS;
6397 if (likely(tcp_off == 0))
6398 vlan_tag_flags &= ~TX_BD_FLAGS_TCP6_OFF0_MSK;
6399 else {
6400 tcp_off >>= 3;
6401 vlan_tag_flags |= ((tcp_off & 0x3) <<
6402 TX_BD_FLAGS_TCP6_OFF0_SHL) |
6403 ((tcp_off & 0x10) <<
6404 TX_BD_FLAGS_TCP6_OFF4_SHL);
6405 mss |= (tcp_off & 0xc) << TX_BD_TCP6_OFF2_SHL;
6406 }
6407 } else {
Michael Chan4666f872007-05-03 13:22:28 -07006408 iph = ip_hdr(skb);
Michael Chan4666f872007-05-03 13:22:28 -07006409 if (tcp_opt_len || (iph->ihl > 5)) {
6410 vlan_tag_flags |= ((iph->ihl - 5) +
6411 (tcp_opt_len >> 2)) << 8;
6412 }
Michael Chanb6016b72005-05-26 13:03:09 -07006413 }
Michael Chan4666f872007-05-03 13:22:28 -07006414 } else
Michael Chanb6016b72005-05-26 13:03:09 -07006415 mss = 0;
Michael Chanb6016b72005-05-26 13:03:09 -07006416
Alexander Duycke95524a2009-12-02 16:47:57 +00006417 mapping = pci_map_single(bp->pdev, skb->data, len, PCI_DMA_TODEVICE);
6418 if (pci_dma_mapping_error(bp->pdev, mapping)) {
Benjamin Li3d16af82008-10-09 12:26:41 -07006419 dev_kfree_skb(skb);
6420 return NETDEV_TX_OK;
6421 }
6422
Michael Chan35e90102008-06-19 16:37:42 -07006423 tx_buf = &txr->tx_buf_ring[ring_prod];
Michael Chanb6016b72005-05-26 13:03:09 -07006424 tx_buf->skb = skb;
Alexander Duycke95524a2009-12-02 16:47:57 +00006425 pci_unmap_addr_set(tx_buf, mapping, mapping);
Michael Chanb6016b72005-05-26 13:03:09 -07006426
Michael Chan35e90102008-06-19 16:37:42 -07006427 txbd = &txr->tx_desc_ring[ring_prod];
Michael Chanb6016b72005-05-26 13:03:09 -07006428
6429 txbd->tx_bd_haddr_hi = (u64) mapping >> 32;
6430 txbd->tx_bd_haddr_lo = (u64) mapping & 0xffffffff;
6431 txbd->tx_bd_mss_nbytes = len | (mss << 16);
6432 txbd->tx_bd_vlan_tag_flags = vlan_tag_flags | TX_BD_FLAGS_START;
6433
6434 last_frag = skb_shinfo(skb)->nr_frags;
Eric Dumazetd62fda02009-05-12 20:48:02 +00006435 tx_buf->nr_frags = last_frag;
6436 tx_buf->is_gso = skb_is_gso(skb);
Michael Chanb6016b72005-05-26 13:03:09 -07006437
6438 for (i = 0; i < last_frag; i++) {
6439 skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
6440
6441 prod = NEXT_TX_BD(prod);
6442 ring_prod = TX_RING_IDX(prod);
Michael Chan35e90102008-06-19 16:37:42 -07006443 txbd = &txr->tx_desc_ring[ring_prod];
Michael Chanb6016b72005-05-26 13:03:09 -07006444
6445 len = frag->size;
Alexander Duycke95524a2009-12-02 16:47:57 +00006446 mapping = pci_map_page(bp->pdev, frag->page, frag->page_offset,
6447 len, PCI_DMA_TODEVICE);
6448 if (pci_dma_mapping_error(bp->pdev, mapping))
6449 goto dma_error;
6450 pci_unmap_addr_set(&txr->tx_buf_ring[ring_prod], mapping,
6451 mapping);
Michael Chanb6016b72005-05-26 13:03:09 -07006452
6453 txbd->tx_bd_haddr_hi = (u64) mapping >> 32;
6454 txbd->tx_bd_haddr_lo = (u64) mapping & 0xffffffff;
6455 txbd->tx_bd_mss_nbytes = len | (mss << 16);
6456 txbd->tx_bd_vlan_tag_flags = vlan_tag_flags;
6457
6458 }
6459 txbd->tx_bd_vlan_tag_flags |= TX_BD_FLAGS_END;
6460
6461 prod = NEXT_TX_BD(prod);
Michael Chan35e90102008-06-19 16:37:42 -07006462 txr->tx_prod_bseq += skb->len;
Michael Chanb6016b72005-05-26 13:03:09 -07006463
Michael Chan35e90102008-06-19 16:37:42 -07006464 REG_WR16(bp, txr->tx_bidx_addr, prod);
6465 REG_WR(bp, txr->tx_bseq_addr, txr->tx_prod_bseq);
Michael Chanb6016b72005-05-26 13:03:09 -07006466
6467 mmiowb();
6468
Michael Chan35e90102008-06-19 16:37:42 -07006469 txr->tx_prod = prod;
Michael Chanb6016b72005-05-26 13:03:09 -07006470
Michael Chan35e90102008-06-19 16:37:42 -07006471 if (unlikely(bnx2_tx_avail(bp, txr) <= MAX_SKB_FRAGS)) {
Benjamin Li706bf242008-07-18 17:55:11 -07006472 netif_tx_stop_queue(txq);
Michael Chan35e90102008-06-19 16:37:42 -07006473 if (bnx2_tx_avail(bp, txr) > bp->tx_wake_thresh)
Benjamin Li706bf242008-07-18 17:55:11 -07006474 netif_tx_wake_queue(txq);
Michael Chanb6016b72005-05-26 13:03:09 -07006475 }
6476
6477 return NETDEV_TX_OK;
Alexander Duycke95524a2009-12-02 16:47:57 +00006478dma_error:
6479 /* save value of frag that failed */
6480 last_frag = i;
6481
6482 /* start back at beginning and unmap skb */
6483 prod = txr->tx_prod;
6484 ring_prod = TX_RING_IDX(prod);
6485 tx_buf = &txr->tx_buf_ring[ring_prod];
6486 tx_buf->skb = NULL;
6487 pci_unmap_single(bp->pdev, pci_unmap_addr(tx_buf, mapping),
6488 skb_headlen(skb), PCI_DMA_TODEVICE);
6489
6490 /* unmap remaining mapped pages */
6491 for (i = 0; i < last_frag; i++) {
6492 prod = NEXT_TX_BD(prod);
6493 ring_prod = TX_RING_IDX(prod);
6494 tx_buf = &txr->tx_buf_ring[ring_prod];
6495 pci_unmap_page(bp->pdev, pci_unmap_addr(tx_buf, mapping),
6496 skb_shinfo(skb)->frags[i].size,
6497 PCI_DMA_TODEVICE);
6498 }
6499
6500 dev_kfree_skb(skb);
6501 return NETDEV_TX_OK;
Michael Chanb6016b72005-05-26 13:03:09 -07006502}
6503
6504/* Called with rtnl_lock */
6505static int
6506bnx2_close(struct net_device *dev)
6507{
Michael Chan972ec0d2006-01-23 16:12:43 -08006508 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006509
David S. Miller4bb073c2008-06-12 02:22:02 -07006510 cancel_work_sync(&bp->reset_task);
Michael Chanafdc08b2005-08-25 15:34:29 -07006511
Stephen Hemmingerbea33482007-10-03 16:41:36 -07006512 bnx2_disable_int_sync(bp);
Michael Chan35efa7c2007-12-20 19:56:37 -08006513 bnx2_napi_disable(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07006514 del_timer_sync(&bp->timer);
Michael Chan74bf4ba2008-10-09 12:21:08 -07006515 bnx2_shutdown_chip(bp);
Michael Chan8e6a72c2007-05-03 13:24:48 -07006516 bnx2_free_irq(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07006517 bnx2_free_skbs(bp);
6518 bnx2_free_mem(bp);
6519 bp->link_up = 0;
6520 netif_carrier_off(bp->dev);
Pavel Machek829ca9a2005-09-03 15:56:56 -07006521 bnx2_set_power_state(bp, PCI_D3hot);
Michael Chanb6016b72005-05-26 13:03:09 -07006522 return 0;
6523}
6524
Michael Chan354fcd72010-01-17 07:30:44 +00006525static void
6526bnx2_save_stats(struct bnx2 *bp)
6527{
6528 u32 *hw_stats = (u32 *) bp->stats_blk;
6529 u32 *temp_stats = (u32 *) bp->temp_stats_blk;
6530 int i;
6531
6532 /* The 1st 10 counters are 64-bit counters */
6533 for (i = 0; i < 20; i += 2) {
6534 u32 hi;
6535 u64 lo;
6536
Patrick Rabauc9885fe2010-02-15 19:42:11 +00006537 hi = temp_stats[i] + hw_stats[i];
6538 lo = (u64) temp_stats[i + 1] + (u64) hw_stats[i + 1];
Michael Chan354fcd72010-01-17 07:30:44 +00006539 if (lo > 0xffffffff)
6540 hi++;
Patrick Rabauc9885fe2010-02-15 19:42:11 +00006541 temp_stats[i] = hi;
6542 temp_stats[i + 1] = lo & 0xffffffff;
Michael Chan354fcd72010-01-17 07:30:44 +00006543 }
6544
6545 for ( ; i < sizeof(struct statistics_block) / 4; i++)
Patrick Rabauc9885fe2010-02-15 19:42:11 +00006546 temp_stats[i] += hw_stats[i];
Michael Chan354fcd72010-01-17 07:30:44 +00006547}
6548
Michael Chana4743052010-01-17 07:30:43 +00006549#define GET_64BIT_NET_STATS64(ctr) \
Michael Chanb6016b72005-05-26 13:03:09 -07006550 (unsigned long) ((unsigned long) (ctr##_hi) << 32) + \
6551 (unsigned long) (ctr##_lo)
6552
Michael Chana4743052010-01-17 07:30:43 +00006553#define GET_64BIT_NET_STATS32(ctr) \
Michael Chanb6016b72005-05-26 13:03:09 -07006554 (ctr##_lo)
6555
6556#if (BITS_PER_LONG == 64)
Michael Chana4743052010-01-17 07:30:43 +00006557#define GET_64BIT_NET_STATS(ctr) \
Michael Chan354fcd72010-01-17 07:30:44 +00006558 GET_64BIT_NET_STATS64(bp->stats_blk->ctr) + \
6559 GET_64BIT_NET_STATS64(bp->temp_stats_blk->ctr)
Michael Chanb6016b72005-05-26 13:03:09 -07006560#else
Michael Chana4743052010-01-17 07:30:43 +00006561#define GET_64BIT_NET_STATS(ctr) \
Michael Chan354fcd72010-01-17 07:30:44 +00006562 GET_64BIT_NET_STATS32(bp->stats_blk->ctr) + \
6563 GET_64BIT_NET_STATS32(bp->temp_stats_blk->ctr)
Michael Chanb6016b72005-05-26 13:03:09 -07006564#endif
6565
Michael Chana4743052010-01-17 07:30:43 +00006566#define GET_32BIT_NET_STATS(ctr) \
Michael Chan354fcd72010-01-17 07:30:44 +00006567 (unsigned long) (bp->stats_blk->ctr + \
6568 bp->temp_stats_blk->ctr)
Michael Chana4743052010-01-17 07:30:43 +00006569
Michael Chanb6016b72005-05-26 13:03:09 -07006570static struct net_device_stats *
6571bnx2_get_stats(struct net_device *dev)
6572{
Michael Chan972ec0d2006-01-23 16:12:43 -08006573 struct bnx2 *bp = netdev_priv(dev);
Ilpo Järvinend8e80342008-11-28 15:52:43 -08006574 struct net_device_stats *net_stats = &dev->stats;
Michael Chanb6016b72005-05-26 13:03:09 -07006575
6576 if (bp->stats_blk == NULL) {
6577 return net_stats;
6578 }
6579 net_stats->rx_packets =
Michael Chana4743052010-01-17 07:30:43 +00006580 GET_64BIT_NET_STATS(stat_IfHCInUcastPkts) +
6581 GET_64BIT_NET_STATS(stat_IfHCInMulticastPkts) +
6582 GET_64BIT_NET_STATS(stat_IfHCInBroadcastPkts);
Michael Chanb6016b72005-05-26 13:03:09 -07006583
6584 net_stats->tx_packets =
Michael Chana4743052010-01-17 07:30:43 +00006585 GET_64BIT_NET_STATS(stat_IfHCOutUcastPkts) +
6586 GET_64BIT_NET_STATS(stat_IfHCOutMulticastPkts) +
6587 GET_64BIT_NET_STATS(stat_IfHCOutBroadcastPkts);
Michael Chanb6016b72005-05-26 13:03:09 -07006588
6589 net_stats->rx_bytes =
Michael Chana4743052010-01-17 07:30:43 +00006590 GET_64BIT_NET_STATS(stat_IfHCInOctets);
Michael Chanb6016b72005-05-26 13:03:09 -07006591
6592 net_stats->tx_bytes =
Michael Chana4743052010-01-17 07:30:43 +00006593 GET_64BIT_NET_STATS(stat_IfHCOutOctets);
Michael Chanb6016b72005-05-26 13:03:09 -07006594
Jeff Garzik6aa20a22006-09-13 13:24:59 -04006595 net_stats->multicast =
Michael Chana4743052010-01-17 07:30:43 +00006596 GET_64BIT_NET_STATS(stat_IfHCOutMulticastPkts);
Michael Chanb6016b72005-05-26 13:03:09 -07006597
Jeff Garzik6aa20a22006-09-13 13:24:59 -04006598 net_stats->collisions =
Michael Chana4743052010-01-17 07:30:43 +00006599 GET_32BIT_NET_STATS(stat_EtherStatsCollisions);
Michael Chanb6016b72005-05-26 13:03:09 -07006600
Jeff Garzik6aa20a22006-09-13 13:24:59 -04006601 net_stats->rx_length_errors =
Michael Chana4743052010-01-17 07:30:43 +00006602 GET_32BIT_NET_STATS(stat_EtherStatsUndersizePkts) +
6603 GET_32BIT_NET_STATS(stat_EtherStatsOverrsizePkts);
Michael Chanb6016b72005-05-26 13:03:09 -07006604
Jeff Garzik6aa20a22006-09-13 13:24:59 -04006605 net_stats->rx_over_errors =
Michael Chana4743052010-01-17 07:30:43 +00006606 GET_32BIT_NET_STATS(stat_IfInFTQDiscards) +
6607 GET_32BIT_NET_STATS(stat_IfInMBUFDiscards);
Michael Chanb6016b72005-05-26 13:03:09 -07006608
Jeff Garzik6aa20a22006-09-13 13:24:59 -04006609 net_stats->rx_frame_errors =
Michael Chana4743052010-01-17 07:30:43 +00006610 GET_32BIT_NET_STATS(stat_Dot3StatsAlignmentErrors);
Michael Chanb6016b72005-05-26 13:03:09 -07006611
Jeff Garzik6aa20a22006-09-13 13:24:59 -04006612 net_stats->rx_crc_errors =
Michael Chana4743052010-01-17 07:30:43 +00006613 GET_32BIT_NET_STATS(stat_Dot3StatsFCSErrors);
Michael Chanb6016b72005-05-26 13:03:09 -07006614
6615 net_stats->rx_errors = net_stats->rx_length_errors +
6616 net_stats->rx_over_errors + net_stats->rx_frame_errors +
6617 net_stats->rx_crc_errors;
6618
6619 net_stats->tx_aborted_errors =
Michael Chana4743052010-01-17 07:30:43 +00006620 GET_32BIT_NET_STATS(stat_Dot3StatsExcessiveCollisions) +
6621 GET_32BIT_NET_STATS(stat_Dot3StatsLateCollisions);
Michael Chanb6016b72005-05-26 13:03:09 -07006622
Michael Chan5b0c76a2005-11-04 08:45:49 -08006623 if ((CHIP_NUM(bp) == CHIP_NUM_5706) ||
6624 (CHIP_ID(bp) == CHIP_ID_5708_A0))
Michael Chanb6016b72005-05-26 13:03:09 -07006625 net_stats->tx_carrier_errors = 0;
6626 else {
6627 net_stats->tx_carrier_errors =
Michael Chana4743052010-01-17 07:30:43 +00006628 GET_32BIT_NET_STATS(stat_Dot3StatsCarrierSenseErrors);
Michael Chanb6016b72005-05-26 13:03:09 -07006629 }
6630
6631 net_stats->tx_errors =
Michael Chana4743052010-01-17 07:30:43 +00006632 GET_32BIT_NET_STATS(stat_emac_tx_stat_dot3statsinternalmactransmiterrors) +
Michael Chanb6016b72005-05-26 13:03:09 -07006633 net_stats->tx_aborted_errors +
6634 net_stats->tx_carrier_errors;
6635
Michael Chancea94db2006-06-12 22:16:13 -07006636 net_stats->rx_missed_errors =
Michael Chana4743052010-01-17 07:30:43 +00006637 GET_32BIT_NET_STATS(stat_IfInFTQDiscards) +
6638 GET_32BIT_NET_STATS(stat_IfInMBUFDiscards) +
6639 GET_32BIT_NET_STATS(stat_FwRxDrop);
Michael Chancea94db2006-06-12 22:16:13 -07006640
Michael Chanb6016b72005-05-26 13:03:09 -07006641 return net_stats;
6642}
6643
6644/* All ethtool functions called with rtnl_lock */
6645
6646static int
6647bnx2_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
6648{
Michael Chan972ec0d2006-01-23 16:12:43 -08006649 struct bnx2 *bp = netdev_priv(dev);
Michael Chan7b6b8342007-07-07 22:50:15 -07006650 int support_serdes = 0, support_copper = 0;
Michael Chanb6016b72005-05-26 13:03:09 -07006651
6652 cmd->supported = SUPPORTED_Autoneg;
Michael Chan583c28e2008-01-21 19:51:35 -08006653 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP) {
Michael Chan7b6b8342007-07-07 22:50:15 -07006654 support_serdes = 1;
6655 support_copper = 1;
6656 } else if (bp->phy_port == PORT_FIBRE)
6657 support_serdes = 1;
6658 else
6659 support_copper = 1;
6660
6661 if (support_serdes) {
Michael Chanb6016b72005-05-26 13:03:09 -07006662 cmd->supported |= SUPPORTED_1000baseT_Full |
6663 SUPPORTED_FIBRE;
Michael Chan583c28e2008-01-21 19:51:35 -08006664 if (bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE)
Michael Chan605a9e22007-05-03 13:23:13 -07006665 cmd->supported |= SUPPORTED_2500baseX_Full;
Michael Chanb6016b72005-05-26 13:03:09 -07006666
Michael Chanb6016b72005-05-26 13:03:09 -07006667 }
Michael Chan7b6b8342007-07-07 22:50:15 -07006668 if (support_copper) {
Michael Chanb6016b72005-05-26 13:03:09 -07006669 cmd->supported |= SUPPORTED_10baseT_Half |
6670 SUPPORTED_10baseT_Full |
6671 SUPPORTED_100baseT_Half |
6672 SUPPORTED_100baseT_Full |
6673 SUPPORTED_1000baseT_Full |
6674 SUPPORTED_TP;
6675
Michael Chanb6016b72005-05-26 13:03:09 -07006676 }
6677
Michael Chan7b6b8342007-07-07 22:50:15 -07006678 spin_lock_bh(&bp->phy_lock);
6679 cmd->port = bp->phy_port;
Michael Chanb6016b72005-05-26 13:03:09 -07006680 cmd->advertising = bp->advertising;
6681
6682 if (bp->autoneg & AUTONEG_SPEED) {
6683 cmd->autoneg = AUTONEG_ENABLE;
6684 }
6685 else {
6686 cmd->autoneg = AUTONEG_DISABLE;
6687 }
6688
6689 if (netif_carrier_ok(dev)) {
6690 cmd->speed = bp->line_speed;
6691 cmd->duplex = bp->duplex;
6692 }
6693 else {
6694 cmd->speed = -1;
6695 cmd->duplex = -1;
6696 }
Michael Chan7b6b8342007-07-07 22:50:15 -07006697 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07006698
6699 cmd->transceiver = XCVR_INTERNAL;
6700 cmd->phy_address = bp->phy_addr;
6701
6702 return 0;
6703}
Jeff Garzik6aa20a22006-09-13 13:24:59 -04006704
Michael Chanb6016b72005-05-26 13:03:09 -07006705static int
6706bnx2_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
6707{
Michael Chan972ec0d2006-01-23 16:12:43 -08006708 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006709 u8 autoneg = bp->autoneg;
6710 u8 req_duplex = bp->req_duplex;
6711 u16 req_line_speed = bp->req_line_speed;
6712 u32 advertising = bp->advertising;
Michael Chan7b6b8342007-07-07 22:50:15 -07006713 int err = -EINVAL;
6714
6715 spin_lock_bh(&bp->phy_lock);
6716
6717 if (cmd->port != PORT_TP && cmd->port != PORT_FIBRE)
6718 goto err_out_unlock;
6719
Michael Chan583c28e2008-01-21 19:51:35 -08006720 if (cmd->port != bp->phy_port &&
6721 !(bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP))
Michael Chan7b6b8342007-07-07 22:50:15 -07006722 goto err_out_unlock;
Michael Chanb6016b72005-05-26 13:03:09 -07006723
Michael Chand6b14482008-07-14 22:37:21 -07006724 /* If device is down, we can store the settings only if the user
6725 * is setting the currently active port.
6726 */
6727 if (!netif_running(dev) && cmd->port != bp->phy_port)
6728 goto err_out_unlock;
6729
Michael Chanb6016b72005-05-26 13:03:09 -07006730 if (cmd->autoneg == AUTONEG_ENABLE) {
6731 autoneg |= AUTONEG_SPEED;
6732
Michael Chanbeb499a2010-02-15 19:42:10 +00006733 advertising = cmd->advertising;
6734 if (cmd->port == PORT_TP) {
6735 advertising &= ETHTOOL_ALL_COPPER_SPEED;
6736 if (!advertising)
Michael Chanb6016b72005-05-26 13:03:09 -07006737 advertising = ETHTOOL_ALL_COPPER_SPEED;
Michael Chanbeb499a2010-02-15 19:42:10 +00006738 } else {
6739 advertising &= ETHTOOL_ALL_FIBRE_SPEED;
6740 if (!advertising)
6741 advertising = ETHTOOL_ALL_FIBRE_SPEED;
Michael Chanb6016b72005-05-26 13:03:09 -07006742 }
6743 advertising |= ADVERTISED_Autoneg;
6744 }
6745 else {
Michael Chan7b6b8342007-07-07 22:50:15 -07006746 if (cmd->port == PORT_FIBRE) {
Michael Chan80be4432006-11-19 14:07:28 -08006747 if ((cmd->speed != SPEED_1000 &&
6748 cmd->speed != SPEED_2500) ||
6749 (cmd->duplex != DUPLEX_FULL))
Michael Chan7b6b8342007-07-07 22:50:15 -07006750 goto err_out_unlock;
Michael Chan80be4432006-11-19 14:07:28 -08006751
6752 if (cmd->speed == SPEED_2500 &&
Michael Chan583c28e2008-01-21 19:51:35 -08006753 !(bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE))
Michael Chan7b6b8342007-07-07 22:50:15 -07006754 goto err_out_unlock;
Michael Chanb6016b72005-05-26 13:03:09 -07006755 }
Michael Chan7b6b8342007-07-07 22:50:15 -07006756 else if (cmd->speed == SPEED_1000 || cmd->speed == SPEED_2500)
6757 goto err_out_unlock;
6758
Michael Chanb6016b72005-05-26 13:03:09 -07006759 autoneg &= ~AUTONEG_SPEED;
6760 req_line_speed = cmd->speed;
6761 req_duplex = cmd->duplex;
6762 advertising = 0;
6763 }
6764
6765 bp->autoneg = autoneg;
6766 bp->advertising = advertising;
6767 bp->req_line_speed = req_line_speed;
6768 bp->req_duplex = req_duplex;
6769
Michael Chand6b14482008-07-14 22:37:21 -07006770 err = 0;
6771 /* If device is down, the new settings will be picked up when it is
6772 * brought up.
6773 */
6774 if (netif_running(dev))
6775 err = bnx2_setup_phy(bp, cmd->port);
Michael Chanb6016b72005-05-26 13:03:09 -07006776
Michael Chan7b6b8342007-07-07 22:50:15 -07006777err_out_unlock:
Michael Chanc770a652005-08-25 15:38:39 -07006778 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07006779
Michael Chan7b6b8342007-07-07 22:50:15 -07006780 return err;
Michael Chanb6016b72005-05-26 13:03:09 -07006781}
6782
6783static void
6784bnx2_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
6785{
Michael Chan972ec0d2006-01-23 16:12:43 -08006786 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006787
6788 strcpy(info->driver, DRV_MODULE_NAME);
6789 strcpy(info->version, DRV_MODULE_VERSION);
6790 strcpy(info->bus_info, pci_name(bp->pdev));
Michael Chan58fc2ea2007-07-07 22:52:02 -07006791 strcpy(info->fw_version, bp->fw_version);
Michael Chanb6016b72005-05-26 13:03:09 -07006792}
6793
Michael Chan244ac4f2006-03-20 17:48:46 -08006794#define BNX2_REGDUMP_LEN (32 * 1024)
6795
6796static int
6797bnx2_get_regs_len(struct net_device *dev)
6798{
6799 return BNX2_REGDUMP_LEN;
6800}
6801
6802static void
6803bnx2_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *_p)
6804{
6805 u32 *p = _p, i, offset;
6806 u8 *orig_p = _p;
6807 struct bnx2 *bp = netdev_priv(dev);
6808 u32 reg_boundaries[] = { 0x0000, 0x0098, 0x0400, 0x045c,
6809 0x0800, 0x0880, 0x0c00, 0x0c10,
6810 0x0c30, 0x0d08, 0x1000, 0x101c,
6811 0x1040, 0x1048, 0x1080, 0x10a4,
6812 0x1400, 0x1490, 0x1498, 0x14f0,
6813 0x1500, 0x155c, 0x1580, 0x15dc,
6814 0x1600, 0x1658, 0x1680, 0x16d8,
6815 0x1800, 0x1820, 0x1840, 0x1854,
6816 0x1880, 0x1894, 0x1900, 0x1984,
6817 0x1c00, 0x1c0c, 0x1c40, 0x1c54,
6818 0x1c80, 0x1c94, 0x1d00, 0x1d84,
6819 0x2000, 0x2030, 0x23c0, 0x2400,
6820 0x2800, 0x2820, 0x2830, 0x2850,
6821 0x2b40, 0x2c10, 0x2fc0, 0x3058,
6822 0x3c00, 0x3c94, 0x4000, 0x4010,
6823 0x4080, 0x4090, 0x43c0, 0x4458,
6824 0x4c00, 0x4c18, 0x4c40, 0x4c54,
6825 0x4fc0, 0x5010, 0x53c0, 0x5444,
6826 0x5c00, 0x5c18, 0x5c80, 0x5c90,
6827 0x5fc0, 0x6000, 0x6400, 0x6428,
6828 0x6800, 0x6848, 0x684c, 0x6860,
6829 0x6888, 0x6910, 0x8000 };
6830
6831 regs->version = 0;
6832
6833 memset(p, 0, BNX2_REGDUMP_LEN);
6834
6835 if (!netif_running(bp->dev))
6836 return;
6837
6838 i = 0;
6839 offset = reg_boundaries[0];
6840 p += offset;
6841 while (offset < BNX2_REGDUMP_LEN) {
6842 *p++ = REG_RD(bp, offset);
6843 offset += 4;
6844 if (offset == reg_boundaries[i + 1]) {
6845 offset = reg_boundaries[i + 2];
6846 p = (u32 *) (orig_p + offset);
6847 i += 2;
6848 }
6849 }
6850}
6851
Michael Chanb6016b72005-05-26 13:03:09 -07006852static void
6853bnx2_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
6854{
Michael Chan972ec0d2006-01-23 16:12:43 -08006855 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006856
David S. Millerf86e82f2008-01-21 17:15:40 -08006857 if (bp->flags & BNX2_FLAG_NO_WOL) {
Michael Chanb6016b72005-05-26 13:03:09 -07006858 wol->supported = 0;
6859 wol->wolopts = 0;
6860 }
6861 else {
6862 wol->supported = WAKE_MAGIC;
6863 if (bp->wol)
6864 wol->wolopts = WAKE_MAGIC;
6865 else
6866 wol->wolopts = 0;
6867 }
6868 memset(&wol->sopass, 0, sizeof(wol->sopass));
6869}
6870
6871static int
6872bnx2_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
6873{
Michael Chan972ec0d2006-01-23 16:12:43 -08006874 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006875
6876 if (wol->wolopts & ~WAKE_MAGIC)
6877 return -EINVAL;
6878
6879 if (wol->wolopts & WAKE_MAGIC) {
David S. Millerf86e82f2008-01-21 17:15:40 -08006880 if (bp->flags & BNX2_FLAG_NO_WOL)
Michael Chanb6016b72005-05-26 13:03:09 -07006881 return -EINVAL;
6882
6883 bp->wol = 1;
6884 }
6885 else {
6886 bp->wol = 0;
6887 }
6888 return 0;
6889}
6890
6891static int
6892bnx2_nway_reset(struct net_device *dev)
6893{
Michael Chan972ec0d2006-01-23 16:12:43 -08006894 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006895 u32 bmcr;
6896
Michael Chan9f52b562008-10-09 12:21:46 -07006897 if (!netif_running(dev))
6898 return -EAGAIN;
6899
Michael Chanb6016b72005-05-26 13:03:09 -07006900 if (!(bp->autoneg & AUTONEG_SPEED)) {
6901 return -EINVAL;
6902 }
6903
Michael Chanc770a652005-08-25 15:38:39 -07006904 spin_lock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07006905
Michael Chan583c28e2008-01-21 19:51:35 -08006906 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP) {
Michael Chan7b6b8342007-07-07 22:50:15 -07006907 int rc;
6908
6909 rc = bnx2_setup_remote_phy(bp, bp->phy_port);
6910 spin_unlock_bh(&bp->phy_lock);
6911 return rc;
6912 }
6913
Michael Chanb6016b72005-05-26 13:03:09 -07006914 /* Force a link down visible on the other side */
Michael Chan583c28e2008-01-21 19:51:35 -08006915 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Michael Chanca58c3a2007-05-03 13:22:52 -07006916 bnx2_write_phy(bp, bp->mii_bmcr, BMCR_LOOPBACK);
Michael Chanc770a652005-08-25 15:38:39 -07006917 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07006918
6919 msleep(20);
6920
Michael Chanc770a652005-08-25 15:38:39 -07006921 spin_lock_bh(&bp->phy_lock);
Michael Chanf8dd0642006-11-19 14:08:29 -08006922
Michael Chan40105c02008-11-12 16:02:45 -08006923 bp->current_interval = BNX2_SERDES_AN_TIMEOUT;
Michael Chanf8dd0642006-11-19 14:08:29 -08006924 bp->serdes_an_pending = 1;
6925 mod_timer(&bp->timer, jiffies + bp->current_interval);
Michael Chanb6016b72005-05-26 13:03:09 -07006926 }
6927
Michael Chanca58c3a2007-05-03 13:22:52 -07006928 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chanb6016b72005-05-26 13:03:09 -07006929 bmcr &= ~BMCR_LOOPBACK;
Michael Chanca58c3a2007-05-03 13:22:52 -07006930 bnx2_write_phy(bp, bp->mii_bmcr, bmcr | BMCR_ANRESTART | BMCR_ANENABLE);
Michael Chanb6016b72005-05-26 13:03:09 -07006931
Michael Chanc770a652005-08-25 15:38:39 -07006932 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07006933
6934 return 0;
6935}
6936
Ooiwa Naohiro7959ea22009-06-24 00:19:06 -07006937static u32
6938bnx2_get_link(struct net_device *dev)
6939{
6940 struct bnx2 *bp = netdev_priv(dev);
6941
6942 return bp->link_up;
6943}
6944
Michael Chanb6016b72005-05-26 13:03:09 -07006945static int
6946bnx2_get_eeprom_len(struct net_device *dev)
6947{
Michael Chan972ec0d2006-01-23 16:12:43 -08006948 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006949
Michael Chan1122db72006-01-23 16:11:42 -08006950 if (bp->flash_info == NULL)
Michael Chanb6016b72005-05-26 13:03:09 -07006951 return 0;
6952
Michael Chan1122db72006-01-23 16:11:42 -08006953 return (int) bp->flash_size;
Michael Chanb6016b72005-05-26 13:03:09 -07006954}
6955
6956static int
6957bnx2_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
6958 u8 *eebuf)
6959{
Michael Chan972ec0d2006-01-23 16:12:43 -08006960 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006961 int rc;
6962
Michael Chan9f52b562008-10-09 12:21:46 -07006963 if (!netif_running(dev))
6964 return -EAGAIN;
6965
John W. Linville1064e942005-11-10 12:58:24 -08006966 /* parameters already validated in ethtool_get_eeprom */
Michael Chanb6016b72005-05-26 13:03:09 -07006967
6968 rc = bnx2_nvram_read(bp, eeprom->offset, eebuf, eeprom->len);
6969
6970 return rc;
6971}
6972
6973static int
6974bnx2_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
6975 u8 *eebuf)
6976{
Michael Chan972ec0d2006-01-23 16:12:43 -08006977 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006978 int rc;
6979
Michael Chan9f52b562008-10-09 12:21:46 -07006980 if (!netif_running(dev))
6981 return -EAGAIN;
6982
John W. Linville1064e942005-11-10 12:58:24 -08006983 /* parameters already validated in ethtool_set_eeprom */
Michael Chanb6016b72005-05-26 13:03:09 -07006984
6985 rc = bnx2_nvram_write(bp, eeprom->offset, eebuf, eeprom->len);
6986
6987 return rc;
6988}
6989
6990static int
6991bnx2_get_coalesce(struct net_device *dev, struct ethtool_coalesce *coal)
6992{
Michael Chan972ec0d2006-01-23 16:12:43 -08006993 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006994
6995 memset(coal, 0, sizeof(struct ethtool_coalesce));
6996
6997 coal->rx_coalesce_usecs = bp->rx_ticks;
6998 coal->rx_max_coalesced_frames = bp->rx_quick_cons_trip;
6999 coal->rx_coalesce_usecs_irq = bp->rx_ticks_int;
7000 coal->rx_max_coalesced_frames_irq = bp->rx_quick_cons_trip_int;
7001
7002 coal->tx_coalesce_usecs = bp->tx_ticks;
7003 coal->tx_max_coalesced_frames = bp->tx_quick_cons_trip;
7004 coal->tx_coalesce_usecs_irq = bp->tx_ticks_int;
7005 coal->tx_max_coalesced_frames_irq = bp->tx_quick_cons_trip_int;
7006
7007 coal->stats_block_coalesce_usecs = bp->stats_ticks;
7008
7009 return 0;
7010}
7011
7012static int
7013bnx2_set_coalesce(struct net_device *dev, struct ethtool_coalesce *coal)
7014{
Michael Chan972ec0d2006-01-23 16:12:43 -08007015 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007016
7017 bp->rx_ticks = (u16) coal->rx_coalesce_usecs;
7018 if (bp->rx_ticks > 0x3ff) bp->rx_ticks = 0x3ff;
7019
Jeff Garzik6aa20a22006-09-13 13:24:59 -04007020 bp->rx_quick_cons_trip = (u16) coal->rx_max_coalesced_frames;
Michael Chanb6016b72005-05-26 13:03:09 -07007021 if (bp->rx_quick_cons_trip > 0xff) bp->rx_quick_cons_trip = 0xff;
7022
7023 bp->rx_ticks_int = (u16) coal->rx_coalesce_usecs_irq;
7024 if (bp->rx_ticks_int > 0x3ff) bp->rx_ticks_int = 0x3ff;
7025
7026 bp->rx_quick_cons_trip_int = (u16) coal->rx_max_coalesced_frames_irq;
7027 if (bp->rx_quick_cons_trip_int > 0xff)
7028 bp->rx_quick_cons_trip_int = 0xff;
7029
7030 bp->tx_ticks = (u16) coal->tx_coalesce_usecs;
7031 if (bp->tx_ticks > 0x3ff) bp->tx_ticks = 0x3ff;
7032
7033 bp->tx_quick_cons_trip = (u16) coal->tx_max_coalesced_frames;
7034 if (bp->tx_quick_cons_trip > 0xff) bp->tx_quick_cons_trip = 0xff;
7035
7036 bp->tx_ticks_int = (u16) coal->tx_coalesce_usecs_irq;
7037 if (bp->tx_ticks_int > 0x3ff) bp->tx_ticks_int = 0x3ff;
7038
7039 bp->tx_quick_cons_trip_int = (u16) coal->tx_max_coalesced_frames_irq;
7040 if (bp->tx_quick_cons_trip_int > 0xff) bp->tx_quick_cons_trip_int =
7041 0xff;
7042
7043 bp->stats_ticks = coal->stats_block_coalesce_usecs;
Michael Chan61d9e3f2009-08-21 16:20:46 +00007044 if (bp->flags & BNX2_FLAG_BROKEN_STATS) {
Michael Chan02537b062007-06-04 21:24:07 -07007045 if (bp->stats_ticks != 0 && bp->stats_ticks != USEC_PER_SEC)
7046 bp->stats_ticks = USEC_PER_SEC;
7047 }
Michael Chan7ea69202007-07-16 18:27:10 -07007048 if (bp->stats_ticks > BNX2_HC_STATS_TICKS_HC_STAT_TICKS)
7049 bp->stats_ticks = BNX2_HC_STATS_TICKS_HC_STAT_TICKS;
7050 bp->stats_ticks &= BNX2_HC_STATS_TICKS_HC_STAT_TICKS;
Michael Chanb6016b72005-05-26 13:03:09 -07007051
7052 if (netif_running(bp->dev)) {
7053 bnx2_netif_stop(bp);
Michael Chan9a120bc2008-05-16 22:17:45 -07007054 bnx2_init_nic(bp, 0);
Michael Chanb6016b72005-05-26 13:03:09 -07007055 bnx2_netif_start(bp);
7056 }
7057
7058 return 0;
7059}
7060
7061static void
7062bnx2_get_ringparam(struct net_device *dev, struct ethtool_ringparam *ering)
7063{
Michael Chan972ec0d2006-01-23 16:12:43 -08007064 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007065
Michael Chan13daffa2006-03-20 17:49:20 -08007066 ering->rx_max_pending = MAX_TOTAL_RX_DESC_CNT;
Michael Chanb6016b72005-05-26 13:03:09 -07007067 ering->rx_mini_max_pending = 0;
Michael Chan47bf4242007-12-12 11:19:12 -08007068 ering->rx_jumbo_max_pending = MAX_TOTAL_RX_PG_DESC_CNT;
Michael Chanb6016b72005-05-26 13:03:09 -07007069
7070 ering->rx_pending = bp->rx_ring_size;
7071 ering->rx_mini_pending = 0;
Michael Chan47bf4242007-12-12 11:19:12 -08007072 ering->rx_jumbo_pending = bp->rx_pg_ring_size;
Michael Chanb6016b72005-05-26 13:03:09 -07007073
7074 ering->tx_max_pending = MAX_TX_DESC_CNT;
7075 ering->tx_pending = bp->tx_ring_size;
7076}
7077
7078static int
Michael Chan5d5d0012007-12-12 11:17:43 -08007079bnx2_change_ring_size(struct bnx2 *bp, u32 rx, u32 tx)
Michael Chanb6016b72005-05-26 13:03:09 -07007080{
Michael Chan13daffa2006-03-20 17:49:20 -08007081 if (netif_running(bp->dev)) {
Michael Chan354fcd72010-01-17 07:30:44 +00007082 /* Reset will erase chipset stats; save them */
7083 bnx2_save_stats(bp);
7084
Michael Chan13daffa2006-03-20 17:49:20 -08007085 bnx2_netif_stop(bp);
7086 bnx2_reset_chip(bp, BNX2_DRV_MSG_CODE_RESET);
7087 bnx2_free_skbs(bp);
7088 bnx2_free_mem(bp);
7089 }
7090
Michael Chan5d5d0012007-12-12 11:17:43 -08007091 bnx2_set_rx_ring_size(bp, rx);
7092 bp->tx_ring_size = tx;
Michael Chanb6016b72005-05-26 13:03:09 -07007093
7094 if (netif_running(bp->dev)) {
Michael Chan13daffa2006-03-20 17:49:20 -08007095 int rc;
7096
7097 rc = bnx2_alloc_mem(bp);
Michael Chan6fefb652009-08-21 16:20:45 +00007098 if (!rc)
7099 rc = bnx2_init_nic(bp, 0);
7100
7101 if (rc) {
7102 bnx2_napi_enable(bp);
7103 dev_close(bp->dev);
Michael Chan13daffa2006-03-20 17:49:20 -08007104 return rc;
Michael Chan6fefb652009-08-21 16:20:45 +00007105 }
Michael Chane9f26c42010-02-15 19:42:08 +00007106#ifdef BCM_CNIC
7107 mutex_lock(&bp->cnic_lock);
7108 /* Let cnic know about the new status block. */
7109 if (bp->cnic_eth_dev.drv_state & CNIC_DRV_STATE_REGD)
7110 bnx2_setup_cnic_irq_info(bp);
7111 mutex_unlock(&bp->cnic_lock);
7112#endif
Michael Chanb6016b72005-05-26 13:03:09 -07007113 bnx2_netif_start(bp);
7114 }
Michael Chanb6016b72005-05-26 13:03:09 -07007115 return 0;
7116}
7117
Michael Chan5d5d0012007-12-12 11:17:43 -08007118static int
7119bnx2_set_ringparam(struct net_device *dev, struct ethtool_ringparam *ering)
7120{
7121 struct bnx2 *bp = netdev_priv(dev);
7122 int rc;
7123
7124 if ((ering->rx_pending > MAX_TOTAL_RX_DESC_CNT) ||
7125 (ering->tx_pending > MAX_TX_DESC_CNT) ||
7126 (ering->tx_pending <= MAX_SKB_FRAGS)) {
7127
7128 return -EINVAL;
7129 }
7130 rc = bnx2_change_ring_size(bp, ering->rx_pending, ering->tx_pending);
7131 return rc;
7132}
7133
Michael Chanb6016b72005-05-26 13:03:09 -07007134static void
7135bnx2_get_pauseparam(struct net_device *dev, struct ethtool_pauseparam *epause)
7136{
Michael Chan972ec0d2006-01-23 16:12:43 -08007137 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007138
7139 epause->autoneg = ((bp->autoneg & AUTONEG_FLOW_CTRL) != 0);
7140 epause->rx_pause = ((bp->flow_ctrl & FLOW_CTRL_RX) != 0);
7141 epause->tx_pause = ((bp->flow_ctrl & FLOW_CTRL_TX) != 0);
7142}
7143
7144static int
7145bnx2_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam *epause)
7146{
Michael Chan972ec0d2006-01-23 16:12:43 -08007147 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007148
7149 bp->req_flow_ctrl = 0;
7150 if (epause->rx_pause)
7151 bp->req_flow_ctrl |= FLOW_CTRL_RX;
7152 if (epause->tx_pause)
7153 bp->req_flow_ctrl |= FLOW_CTRL_TX;
7154
7155 if (epause->autoneg) {
7156 bp->autoneg |= AUTONEG_FLOW_CTRL;
7157 }
7158 else {
7159 bp->autoneg &= ~AUTONEG_FLOW_CTRL;
7160 }
7161
Michael Chan9f52b562008-10-09 12:21:46 -07007162 if (netif_running(dev)) {
7163 spin_lock_bh(&bp->phy_lock);
7164 bnx2_setup_phy(bp, bp->phy_port);
7165 spin_unlock_bh(&bp->phy_lock);
7166 }
Michael Chanb6016b72005-05-26 13:03:09 -07007167
7168 return 0;
7169}
7170
7171static u32
7172bnx2_get_rx_csum(struct net_device *dev)
7173{
Michael Chan972ec0d2006-01-23 16:12:43 -08007174 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007175
7176 return bp->rx_csum;
7177}
7178
7179static int
7180bnx2_set_rx_csum(struct net_device *dev, u32 data)
7181{
Michael Chan972ec0d2006-01-23 16:12:43 -08007182 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007183
7184 bp->rx_csum = data;
7185 return 0;
7186}
7187
Michael Chanb11d6212006-06-29 12:31:21 -07007188static int
7189bnx2_set_tso(struct net_device *dev, u32 data)
7190{
Michael Chan4666f872007-05-03 13:22:28 -07007191 struct bnx2 *bp = netdev_priv(dev);
7192
7193 if (data) {
Michael Chanb11d6212006-06-29 12:31:21 -07007194 dev->features |= NETIF_F_TSO | NETIF_F_TSO_ECN;
Michael Chan4666f872007-05-03 13:22:28 -07007195 if (CHIP_NUM(bp) == CHIP_NUM_5709)
7196 dev->features |= NETIF_F_TSO6;
7197 } else
7198 dev->features &= ~(NETIF_F_TSO | NETIF_F_TSO6 |
7199 NETIF_F_TSO_ECN);
Michael Chanb11d6212006-06-29 12:31:21 -07007200 return 0;
7201}
7202
Peter Hagervall14ab9b82005-08-10 14:18:16 -07007203static struct {
Michael Chanb6016b72005-05-26 13:03:09 -07007204 char string[ETH_GSTRING_LEN];
Michael Chan790dab22009-08-21 16:20:47 +00007205} bnx2_stats_str_arr[] = {
Michael Chanb6016b72005-05-26 13:03:09 -07007206 { "rx_bytes" },
7207 { "rx_error_bytes" },
7208 { "tx_bytes" },
7209 { "tx_error_bytes" },
7210 { "rx_ucast_packets" },
7211 { "rx_mcast_packets" },
7212 { "rx_bcast_packets" },
7213 { "tx_ucast_packets" },
7214 { "tx_mcast_packets" },
7215 { "tx_bcast_packets" },
7216 { "tx_mac_errors" },
7217 { "tx_carrier_errors" },
7218 { "rx_crc_errors" },
7219 { "rx_align_errors" },
7220 { "tx_single_collisions" },
7221 { "tx_multi_collisions" },
7222 { "tx_deferred" },
7223 { "tx_excess_collisions" },
7224 { "tx_late_collisions" },
7225 { "tx_total_collisions" },
7226 { "rx_fragments" },
7227 { "rx_jabbers" },
7228 { "rx_undersize_packets" },
7229 { "rx_oversize_packets" },
7230 { "rx_64_byte_packets" },
7231 { "rx_65_to_127_byte_packets" },
7232 { "rx_128_to_255_byte_packets" },
7233 { "rx_256_to_511_byte_packets" },
7234 { "rx_512_to_1023_byte_packets" },
7235 { "rx_1024_to_1522_byte_packets" },
7236 { "rx_1523_to_9022_byte_packets" },
7237 { "tx_64_byte_packets" },
7238 { "tx_65_to_127_byte_packets" },
7239 { "tx_128_to_255_byte_packets" },
7240 { "tx_256_to_511_byte_packets" },
7241 { "tx_512_to_1023_byte_packets" },
7242 { "tx_1024_to_1522_byte_packets" },
7243 { "tx_1523_to_9022_byte_packets" },
7244 { "rx_xon_frames" },
7245 { "rx_xoff_frames" },
7246 { "tx_xon_frames" },
7247 { "tx_xoff_frames" },
7248 { "rx_mac_ctrl_frames" },
7249 { "rx_filtered_packets" },
Michael Chan790dab22009-08-21 16:20:47 +00007250 { "rx_ftq_discards" },
Michael Chanb6016b72005-05-26 13:03:09 -07007251 { "rx_discards" },
Michael Chancea94db2006-06-12 22:16:13 -07007252 { "rx_fw_discards" },
Michael Chanb6016b72005-05-26 13:03:09 -07007253};
7254
Michael Chan790dab22009-08-21 16:20:47 +00007255#define BNX2_NUM_STATS (sizeof(bnx2_stats_str_arr)/\
7256 sizeof(bnx2_stats_str_arr[0]))
7257
Michael Chanb6016b72005-05-26 13:03:09 -07007258#define STATS_OFFSET32(offset_name) (offsetof(struct statistics_block, offset_name) / 4)
7259
Arjan van de Venf71e1302006-03-03 21:33:57 -05007260static const unsigned long bnx2_stats_offset_arr[BNX2_NUM_STATS] = {
Michael Chanb6016b72005-05-26 13:03:09 -07007261 STATS_OFFSET32(stat_IfHCInOctets_hi),
7262 STATS_OFFSET32(stat_IfHCInBadOctets_hi),
7263 STATS_OFFSET32(stat_IfHCOutOctets_hi),
7264 STATS_OFFSET32(stat_IfHCOutBadOctets_hi),
7265 STATS_OFFSET32(stat_IfHCInUcastPkts_hi),
7266 STATS_OFFSET32(stat_IfHCInMulticastPkts_hi),
7267 STATS_OFFSET32(stat_IfHCInBroadcastPkts_hi),
7268 STATS_OFFSET32(stat_IfHCOutUcastPkts_hi),
7269 STATS_OFFSET32(stat_IfHCOutMulticastPkts_hi),
7270 STATS_OFFSET32(stat_IfHCOutBroadcastPkts_hi),
7271 STATS_OFFSET32(stat_emac_tx_stat_dot3statsinternalmactransmiterrors),
Jeff Garzik6aa20a22006-09-13 13:24:59 -04007272 STATS_OFFSET32(stat_Dot3StatsCarrierSenseErrors),
7273 STATS_OFFSET32(stat_Dot3StatsFCSErrors),
7274 STATS_OFFSET32(stat_Dot3StatsAlignmentErrors),
7275 STATS_OFFSET32(stat_Dot3StatsSingleCollisionFrames),
7276 STATS_OFFSET32(stat_Dot3StatsMultipleCollisionFrames),
7277 STATS_OFFSET32(stat_Dot3StatsDeferredTransmissions),
7278 STATS_OFFSET32(stat_Dot3StatsExcessiveCollisions),
7279 STATS_OFFSET32(stat_Dot3StatsLateCollisions),
7280 STATS_OFFSET32(stat_EtherStatsCollisions),
7281 STATS_OFFSET32(stat_EtherStatsFragments),
7282 STATS_OFFSET32(stat_EtherStatsJabbers),
7283 STATS_OFFSET32(stat_EtherStatsUndersizePkts),
7284 STATS_OFFSET32(stat_EtherStatsOverrsizePkts),
7285 STATS_OFFSET32(stat_EtherStatsPktsRx64Octets),
7286 STATS_OFFSET32(stat_EtherStatsPktsRx65Octetsto127Octets),
7287 STATS_OFFSET32(stat_EtherStatsPktsRx128Octetsto255Octets),
7288 STATS_OFFSET32(stat_EtherStatsPktsRx256Octetsto511Octets),
7289 STATS_OFFSET32(stat_EtherStatsPktsRx512Octetsto1023Octets),
7290 STATS_OFFSET32(stat_EtherStatsPktsRx1024Octetsto1522Octets),
7291 STATS_OFFSET32(stat_EtherStatsPktsRx1523Octetsto9022Octets),
7292 STATS_OFFSET32(stat_EtherStatsPktsTx64Octets),
7293 STATS_OFFSET32(stat_EtherStatsPktsTx65Octetsto127Octets),
7294 STATS_OFFSET32(stat_EtherStatsPktsTx128Octetsto255Octets),
7295 STATS_OFFSET32(stat_EtherStatsPktsTx256Octetsto511Octets),
7296 STATS_OFFSET32(stat_EtherStatsPktsTx512Octetsto1023Octets),
7297 STATS_OFFSET32(stat_EtherStatsPktsTx1024Octetsto1522Octets),
7298 STATS_OFFSET32(stat_EtherStatsPktsTx1523Octetsto9022Octets),
7299 STATS_OFFSET32(stat_XonPauseFramesReceived),
7300 STATS_OFFSET32(stat_XoffPauseFramesReceived),
7301 STATS_OFFSET32(stat_OutXonSent),
7302 STATS_OFFSET32(stat_OutXoffSent),
7303 STATS_OFFSET32(stat_MacControlFramesReceived),
7304 STATS_OFFSET32(stat_IfInFramesL2FilterDiscards),
Michael Chan790dab22009-08-21 16:20:47 +00007305 STATS_OFFSET32(stat_IfInFTQDiscards),
Jeff Garzik6aa20a22006-09-13 13:24:59 -04007306 STATS_OFFSET32(stat_IfInMBUFDiscards),
Michael Chancea94db2006-06-12 22:16:13 -07007307 STATS_OFFSET32(stat_FwRxDrop),
Michael Chanb6016b72005-05-26 13:03:09 -07007308};
7309
7310/* stat_IfHCInBadOctets and stat_Dot3StatsCarrierSenseErrors are
7311 * skipped because of errata.
Jeff Garzik6aa20a22006-09-13 13:24:59 -04007312 */
Peter Hagervall14ab9b82005-08-10 14:18:16 -07007313static u8 bnx2_5706_stats_len_arr[BNX2_NUM_STATS] = {
Michael Chanb6016b72005-05-26 13:03:09 -07007314 8,0,8,8,8,8,8,8,8,8,
7315 4,0,4,4,4,4,4,4,4,4,
7316 4,4,4,4,4,4,4,4,4,4,
7317 4,4,4,4,4,4,4,4,4,4,
Michael Chan790dab22009-08-21 16:20:47 +00007318 4,4,4,4,4,4,4,
Michael Chanb6016b72005-05-26 13:03:09 -07007319};
7320
Michael Chan5b0c76a2005-11-04 08:45:49 -08007321static u8 bnx2_5708_stats_len_arr[BNX2_NUM_STATS] = {
7322 8,0,8,8,8,8,8,8,8,8,
7323 4,4,4,4,4,4,4,4,4,4,
7324 4,4,4,4,4,4,4,4,4,4,
7325 4,4,4,4,4,4,4,4,4,4,
Michael Chan790dab22009-08-21 16:20:47 +00007326 4,4,4,4,4,4,4,
Michael Chan5b0c76a2005-11-04 08:45:49 -08007327};
7328
Michael Chanb6016b72005-05-26 13:03:09 -07007329#define BNX2_NUM_TESTS 6
7330
Peter Hagervall14ab9b82005-08-10 14:18:16 -07007331static struct {
Michael Chanb6016b72005-05-26 13:03:09 -07007332 char string[ETH_GSTRING_LEN];
7333} bnx2_tests_str_arr[BNX2_NUM_TESTS] = {
7334 { "register_test (offline)" },
7335 { "memory_test (offline)" },
7336 { "loopback_test (offline)" },
7337 { "nvram_test (online)" },
7338 { "interrupt_test (online)" },
7339 { "link_test (online)" },
7340};
7341
7342static int
Jeff Garzikb9f2c042007-10-03 18:07:32 -07007343bnx2_get_sset_count(struct net_device *dev, int sset)
Michael Chanb6016b72005-05-26 13:03:09 -07007344{
Jeff Garzikb9f2c042007-10-03 18:07:32 -07007345 switch (sset) {
7346 case ETH_SS_TEST:
7347 return BNX2_NUM_TESTS;
7348 case ETH_SS_STATS:
7349 return BNX2_NUM_STATS;
7350 default:
7351 return -EOPNOTSUPP;
7352 }
Michael Chanb6016b72005-05-26 13:03:09 -07007353}
7354
7355static void
7356bnx2_self_test(struct net_device *dev, struct ethtool_test *etest, u64 *buf)
7357{
Michael Chan972ec0d2006-01-23 16:12:43 -08007358 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007359
Michael Chan9f52b562008-10-09 12:21:46 -07007360 bnx2_set_power_state(bp, PCI_D0);
7361
Michael Chanb6016b72005-05-26 13:03:09 -07007362 memset(buf, 0, sizeof(u64) * BNX2_NUM_TESTS);
7363 if (etest->flags & ETH_TEST_FL_OFFLINE) {
Michael Chan80be4432006-11-19 14:07:28 -08007364 int i;
7365
Michael Chanb6016b72005-05-26 13:03:09 -07007366 bnx2_netif_stop(bp);
7367 bnx2_reset_chip(bp, BNX2_DRV_MSG_CODE_DIAG);
7368 bnx2_free_skbs(bp);
7369
7370 if (bnx2_test_registers(bp) != 0) {
7371 buf[0] = 1;
7372 etest->flags |= ETH_TEST_FL_FAILED;
7373 }
7374 if (bnx2_test_memory(bp) != 0) {
7375 buf[1] = 1;
7376 etest->flags |= ETH_TEST_FL_FAILED;
7377 }
Michael Chanbc5a0692006-01-23 16:13:22 -08007378 if ((buf[2] = bnx2_test_loopback(bp)) != 0)
Michael Chanb6016b72005-05-26 13:03:09 -07007379 etest->flags |= ETH_TEST_FL_FAILED;
Michael Chanb6016b72005-05-26 13:03:09 -07007380
Michael Chan9f52b562008-10-09 12:21:46 -07007381 if (!netif_running(bp->dev))
7382 bnx2_shutdown_chip(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07007383 else {
Michael Chan9a120bc2008-05-16 22:17:45 -07007384 bnx2_init_nic(bp, 1);
Michael Chanb6016b72005-05-26 13:03:09 -07007385 bnx2_netif_start(bp);
7386 }
7387
7388 /* wait for link up */
Michael Chan80be4432006-11-19 14:07:28 -08007389 for (i = 0; i < 7; i++) {
7390 if (bp->link_up)
7391 break;
7392 msleep_interruptible(1000);
7393 }
Michael Chanb6016b72005-05-26 13:03:09 -07007394 }
7395
7396 if (bnx2_test_nvram(bp) != 0) {
7397 buf[3] = 1;
7398 etest->flags |= ETH_TEST_FL_FAILED;
7399 }
7400 if (bnx2_test_intr(bp) != 0) {
7401 buf[4] = 1;
7402 etest->flags |= ETH_TEST_FL_FAILED;
7403 }
7404
7405 if (bnx2_test_link(bp) != 0) {
7406 buf[5] = 1;
7407 etest->flags |= ETH_TEST_FL_FAILED;
7408
7409 }
Michael Chan9f52b562008-10-09 12:21:46 -07007410 if (!netif_running(bp->dev))
7411 bnx2_set_power_state(bp, PCI_D3hot);
Michael Chanb6016b72005-05-26 13:03:09 -07007412}
7413
7414static void
7415bnx2_get_strings(struct net_device *dev, u32 stringset, u8 *buf)
7416{
7417 switch (stringset) {
7418 case ETH_SS_STATS:
7419 memcpy(buf, bnx2_stats_str_arr,
7420 sizeof(bnx2_stats_str_arr));
7421 break;
7422 case ETH_SS_TEST:
7423 memcpy(buf, bnx2_tests_str_arr,
7424 sizeof(bnx2_tests_str_arr));
7425 break;
7426 }
7427}
7428
Michael Chanb6016b72005-05-26 13:03:09 -07007429static void
7430bnx2_get_ethtool_stats(struct net_device *dev,
7431 struct ethtool_stats *stats, u64 *buf)
7432{
Michael Chan972ec0d2006-01-23 16:12:43 -08007433 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007434 int i;
7435 u32 *hw_stats = (u32 *) bp->stats_blk;
Michael Chan354fcd72010-01-17 07:30:44 +00007436 u32 *temp_stats = (u32 *) bp->temp_stats_blk;
Peter Hagervall14ab9b82005-08-10 14:18:16 -07007437 u8 *stats_len_arr = NULL;
Michael Chanb6016b72005-05-26 13:03:09 -07007438
7439 if (hw_stats == NULL) {
7440 memset(buf, 0, sizeof(u64) * BNX2_NUM_STATS);
7441 return;
7442 }
7443
Michael Chan5b0c76a2005-11-04 08:45:49 -08007444 if ((CHIP_ID(bp) == CHIP_ID_5706_A0) ||
7445 (CHIP_ID(bp) == CHIP_ID_5706_A1) ||
7446 (CHIP_ID(bp) == CHIP_ID_5706_A2) ||
7447 (CHIP_ID(bp) == CHIP_ID_5708_A0))
Michael Chanb6016b72005-05-26 13:03:09 -07007448 stats_len_arr = bnx2_5706_stats_len_arr;
Michael Chan5b0c76a2005-11-04 08:45:49 -08007449 else
7450 stats_len_arr = bnx2_5708_stats_len_arr;
Michael Chanb6016b72005-05-26 13:03:09 -07007451
7452 for (i = 0; i < BNX2_NUM_STATS; i++) {
Michael Chan354fcd72010-01-17 07:30:44 +00007453 unsigned long offset;
7454
Michael Chanb6016b72005-05-26 13:03:09 -07007455 if (stats_len_arr[i] == 0) {
7456 /* skip this counter */
7457 buf[i] = 0;
7458 continue;
7459 }
Michael Chan354fcd72010-01-17 07:30:44 +00007460
7461 offset = bnx2_stats_offset_arr[i];
Michael Chanb6016b72005-05-26 13:03:09 -07007462 if (stats_len_arr[i] == 4) {
7463 /* 4-byte counter */
Michael Chan354fcd72010-01-17 07:30:44 +00007464 buf[i] = (u64) *(hw_stats + offset) +
7465 *(temp_stats + offset);
Michael Chanb6016b72005-05-26 13:03:09 -07007466 continue;
7467 }
7468 /* 8-byte counter */
Michael Chan354fcd72010-01-17 07:30:44 +00007469 buf[i] = (((u64) *(hw_stats + offset)) << 32) +
7470 *(hw_stats + offset + 1) +
7471 (((u64) *(temp_stats + offset)) << 32) +
7472 *(temp_stats + offset + 1);
Michael Chanb6016b72005-05-26 13:03:09 -07007473 }
7474}
7475
7476static int
7477bnx2_phys_id(struct net_device *dev, u32 data)
7478{
Michael Chan972ec0d2006-01-23 16:12:43 -08007479 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007480 int i;
7481 u32 save;
7482
Michael Chan9f52b562008-10-09 12:21:46 -07007483 bnx2_set_power_state(bp, PCI_D0);
7484
Michael Chanb6016b72005-05-26 13:03:09 -07007485 if (data == 0)
7486 data = 2;
7487
7488 save = REG_RD(bp, BNX2_MISC_CFG);
7489 REG_WR(bp, BNX2_MISC_CFG, BNX2_MISC_CFG_LEDMODE_MAC);
7490
7491 for (i = 0; i < (data * 2); i++) {
7492 if ((i % 2) == 0) {
7493 REG_WR(bp, BNX2_EMAC_LED, BNX2_EMAC_LED_OVERRIDE);
7494 }
7495 else {
7496 REG_WR(bp, BNX2_EMAC_LED, BNX2_EMAC_LED_OVERRIDE |
7497 BNX2_EMAC_LED_1000MB_OVERRIDE |
7498 BNX2_EMAC_LED_100MB_OVERRIDE |
7499 BNX2_EMAC_LED_10MB_OVERRIDE |
7500 BNX2_EMAC_LED_TRAFFIC_OVERRIDE |
7501 BNX2_EMAC_LED_TRAFFIC);
7502 }
7503 msleep_interruptible(500);
7504 if (signal_pending(current))
7505 break;
7506 }
7507 REG_WR(bp, BNX2_EMAC_LED, 0);
7508 REG_WR(bp, BNX2_MISC_CFG, save);
Michael Chan9f52b562008-10-09 12:21:46 -07007509
7510 if (!netif_running(dev))
7511 bnx2_set_power_state(bp, PCI_D3hot);
7512
Michael Chanb6016b72005-05-26 13:03:09 -07007513 return 0;
7514}
7515
Michael Chan4666f872007-05-03 13:22:28 -07007516static int
7517bnx2_set_tx_csum(struct net_device *dev, u32 data)
7518{
7519 struct bnx2 *bp = netdev_priv(dev);
7520
7521 if (CHIP_NUM(bp) == CHIP_NUM_5709)
Michael Chan6460d942007-07-14 19:07:52 -07007522 return (ethtool_op_set_tx_ipv6_csum(dev, data));
Michael Chan4666f872007-05-03 13:22:28 -07007523 else
7524 return (ethtool_op_set_tx_csum(dev, data));
7525}
7526
Jeff Garzik7282d492006-09-13 14:30:00 -04007527static const struct ethtool_ops bnx2_ethtool_ops = {
Michael Chanb6016b72005-05-26 13:03:09 -07007528 .get_settings = bnx2_get_settings,
7529 .set_settings = bnx2_set_settings,
7530 .get_drvinfo = bnx2_get_drvinfo,
Michael Chan244ac4f2006-03-20 17:48:46 -08007531 .get_regs_len = bnx2_get_regs_len,
7532 .get_regs = bnx2_get_regs,
Michael Chanb6016b72005-05-26 13:03:09 -07007533 .get_wol = bnx2_get_wol,
7534 .set_wol = bnx2_set_wol,
7535 .nway_reset = bnx2_nway_reset,
Ooiwa Naohiro7959ea22009-06-24 00:19:06 -07007536 .get_link = bnx2_get_link,
Michael Chanb6016b72005-05-26 13:03:09 -07007537 .get_eeprom_len = bnx2_get_eeprom_len,
7538 .get_eeprom = bnx2_get_eeprom,
7539 .set_eeprom = bnx2_set_eeprom,
7540 .get_coalesce = bnx2_get_coalesce,
7541 .set_coalesce = bnx2_set_coalesce,
7542 .get_ringparam = bnx2_get_ringparam,
7543 .set_ringparam = bnx2_set_ringparam,
7544 .get_pauseparam = bnx2_get_pauseparam,
7545 .set_pauseparam = bnx2_set_pauseparam,
7546 .get_rx_csum = bnx2_get_rx_csum,
7547 .set_rx_csum = bnx2_set_rx_csum,
Michael Chan4666f872007-05-03 13:22:28 -07007548 .set_tx_csum = bnx2_set_tx_csum,
Michael Chanb6016b72005-05-26 13:03:09 -07007549 .set_sg = ethtool_op_set_sg,
Michael Chanb11d6212006-06-29 12:31:21 -07007550 .set_tso = bnx2_set_tso,
Michael Chanb6016b72005-05-26 13:03:09 -07007551 .self_test = bnx2_self_test,
7552 .get_strings = bnx2_get_strings,
7553 .phys_id = bnx2_phys_id,
Michael Chanb6016b72005-05-26 13:03:09 -07007554 .get_ethtool_stats = bnx2_get_ethtool_stats,
Jeff Garzikb9f2c042007-10-03 18:07:32 -07007555 .get_sset_count = bnx2_get_sset_count,
Michael Chanb6016b72005-05-26 13:03:09 -07007556};
7557
7558/* Called with rtnl_lock */
7559static int
7560bnx2_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
7561{
Peter Hagervall14ab9b82005-08-10 14:18:16 -07007562 struct mii_ioctl_data *data = if_mii(ifr);
Michael Chan972ec0d2006-01-23 16:12:43 -08007563 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007564 int err;
7565
7566 switch(cmd) {
7567 case SIOCGMIIPHY:
7568 data->phy_id = bp->phy_addr;
7569
7570 /* fallthru */
7571 case SIOCGMIIREG: {
7572 u32 mii_regval;
7573
Michael Chan583c28e2008-01-21 19:51:35 -08007574 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
Michael Chan7b6b8342007-07-07 22:50:15 -07007575 return -EOPNOTSUPP;
7576
Michael Chandad3e452007-05-03 13:18:03 -07007577 if (!netif_running(dev))
7578 return -EAGAIN;
7579
Michael Chanc770a652005-08-25 15:38:39 -07007580 spin_lock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07007581 err = bnx2_read_phy(bp, data->reg_num & 0x1f, &mii_regval);
Michael Chanc770a652005-08-25 15:38:39 -07007582 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07007583
7584 data->val_out = mii_regval;
7585
7586 return err;
7587 }
7588
7589 case SIOCSMIIREG:
Michael Chan583c28e2008-01-21 19:51:35 -08007590 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
Michael Chan7b6b8342007-07-07 22:50:15 -07007591 return -EOPNOTSUPP;
7592
Michael Chandad3e452007-05-03 13:18:03 -07007593 if (!netif_running(dev))
7594 return -EAGAIN;
7595
Michael Chanc770a652005-08-25 15:38:39 -07007596 spin_lock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07007597 err = bnx2_write_phy(bp, data->reg_num & 0x1f, data->val_in);
Michael Chanc770a652005-08-25 15:38:39 -07007598 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07007599
7600 return err;
7601
7602 default:
7603 /* do nothing */
7604 break;
7605 }
7606 return -EOPNOTSUPP;
7607}
7608
7609/* Called with rtnl_lock */
7610static int
7611bnx2_change_mac_addr(struct net_device *dev, void *p)
7612{
7613 struct sockaddr *addr = p;
Michael Chan972ec0d2006-01-23 16:12:43 -08007614 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007615
Michael Chan73eef4c2005-08-25 15:39:15 -07007616 if (!is_valid_ether_addr(addr->sa_data))
7617 return -EINVAL;
7618
Michael Chanb6016b72005-05-26 13:03:09 -07007619 memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
7620 if (netif_running(dev))
Benjamin Li5fcaed02008-07-14 22:39:52 -07007621 bnx2_set_mac_addr(bp, bp->dev->dev_addr, 0);
Michael Chanb6016b72005-05-26 13:03:09 -07007622
7623 return 0;
7624}
7625
7626/* Called with rtnl_lock */
7627static int
7628bnx2_change_mtu(struct net_device *dev, int new_mtu)
7629{
Michael Chan972ec0d2006-01-23 16:12:43 -08007630 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007631
7632 if (((new_mtu + ETH_HLEN) > MAX_ETHERNET_JUMBO_PACKET_SIZE) ||
7633 ((new_mtu + ETH_HLEN) < MIN_ETHERNET_PACKET_SIZE))
7634 return -EINVAL;
7635
7636 dev->mtu = new_mtu;
Michael Chan5d5d0012007-12-12 11:17:43 -08007637 return (bnx2_change_ring_size(bp, bp->rx_ring_size, bp->tx_ring_size));
Michael Chanb6016b72005-05-26 13:03:09 -07007638}
7639
Alexey Dobriyan257ddbd2010-01-27 10:17:41 +00007640#ifdef CONFIG_NET_POLL_CONTROLLER
Michael Chanb6016b72005-05-26 13:03:09 -07007641static void
7642poll_bnx2(struct net_device *dev)
7643{
Michael Chan972ec0d2006-01-23 16:12:43 -08007644 struct bnx2 *bp = netdev_priv(dev);
Neil Hormanb2af2c12008-11-12 16:23:44 -08007645 int i;
Michael Chanb6016b72005-05-26 13:03:09 -07007646
Neil Hormanb2af2c12008-11-12 16:23:44 -08007647 for (i = 0; i < bp->irq_nvecs; i++) {
Michael Chan1bf1e342010-03-23 13:13:12 +00007648 struct bnx2_irq *irq = &bp->irq_tbl[i];
7649
7650 disable_irq(irq->vector);
7651 irq->handler(irq->vector, &bp->bnx2_napi[i]);
7652 enable_irq(irq->vector);
Neil Hormanb2af2c12008-11-12 16:23:44 -08007653 }
Michael Chanb6016b72005-05-26 13:03:09 -07007654}
7655#endif
7656
Michael Chan253c8b752007-01-08 19:56:01 -08007657static void __devinit
7658bnx2_get_5709_media(struct bnx2 *bp)
7659{
7660 u32 val = REG_RD(bp, BNX2_MISC_DUAL_MEDIA_CTRL);
7661 u32 bond_id = val & BNX2_MISC_DUAL_MEDIA_CTRL_BOND_ID;
7662 u32 strap;
7663
7664 if (bond_id == BNX2_MISC_DUAL_MEDIA_CTRL_BOND_ID_C)
7665 return;
7666 else if (bond_id == BNX2_MISC_DUAL_MEDIA_CTRL_BOND_ID_S) {
Michael Chan583c28e2008-01-21 19:51:35 -08007667 bp->phy_flags |= BNX2_PHY_FLAG_SERDES;
Michael Chan253c8b752007-01-08 19:56:01 -08007668 return;
7669 }
7670
7671 if (val & BNX2_MISC_DUAL_MEDIA_CTRL_STRAP_OVERRIDE)
7672 strap = (val & BNX2_MISC_DUAL_MEDIA_CTRL_PHY_CTRL) >> 21;
7673 else
7674 strap = (val & BNX2_MISC_DUAL_MEDIA_CTRL_PHY_CTRL_STRAP) >> 8;
7675
7676 if (PCI_FUNC(bp->pdev->devfn) == 0) {
7677 switch (strap) {
7678 case 0x4:
7679 case 0x5:
7680 case 0x6:
Michael Chan583c28e2008-01-21 19:51:35 -08007681 bp->phy_flags |= BNX2_PHY_FLAG_SERDES;
Michael Chan253c8b752007-01-08 19:56:01 -08007682 return;
7683 }
7684 } else {
7685 switch (strap) {
7686 case 0x1:
7687 case 0x2:
7688 case 0x4:
Michael Chan583c28e2008-01-21 19:51:35 -08007689 bp->phy_flags |= BNX2_PHY_FLAG_SERDES;
Michael Chan253c8b752007-01-08 19:56:01 -08007690 return;
7691 }
7692 }
7693}
7694
Michael Chan883e5152007-05-03 13:25:11 -07007695static void __devinit
7696bnx2_get_pci_speed(struct bnx2 *bp)
7697{
7698 u32 reg;
7699
7700 reg = REG_RD(bp, BNX2_PCICFG_MISC_STATUS);
7701 if (reg & BNX2_PCICFG_MISC_STATUS_PCIX_DET) {
7702 u32 clkreg;
7703
David S. Millerf86e82f2008-01-21 17:15:40 -08007704 bp->flags |= BNX2_FLAG_PCIX;
Michael Chan883e5152007-05-03 13:25:11 -07007705
7706 clkreg = REG_RD(bp, BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS);
7707
7708 clkreg &= BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET;
7709 switch (clkreg) {
7710 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_133MHZ:
7711 bp->bus_speed_mhz = 133;
7712 break;
7713
7714 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_95MHZ:
7715 bp->bus_speed_mhz = 100;
7716 break;
7717
7718 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_66MHZ:
7719 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_80MHZ:
7720 bp->bus_speed_mhz = 66;
7721 break;
7722
7723 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_48MHZ:
7724 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_55MHZ:
7725 bp->bus_speed_mhz = 50;
7726 break;
7727
7728 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_LOW:
7729 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_32MHZ:
7730 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_38MHZ:
7731 bp->bus_speed_mhz = 33;
7732 break;
7733 }
7734 }
7735 else {
7736 if (reg & BNX2_PCICFG_MISC_STATUS_M66EN)
7737 bp->bus_speed_mhz = 66;
7738 else
7739 bp->bus_speed_mhz = 33;
7740 }
7741
7742 if (reg & BNX2_PCICFG_MISC_STATUS_32BIT_DET)
David S. Millerf86e82f2008-01-21 17:15:40 -08007743 bp->flags |= BNX2_FLAG_PCI_32BIT;
Michael Chan883e5152007-05-03 13:25:11 -07007744
7745}
7746
Michael Chan76d99062009-12-03 09:46:34 +00007747static void __devinit
7748bnx2_read_vpd_fw_ver(struct bnx2 *bp)
7749{
Matt Carlsondf25bc32010-02-26 14:04:44 +00007750 int rc, i, j;
Michael Chan76d99062009-12-03 09:46:34 +00007751 u8 *data;
Matt Carlsondf25bc32010-02-26 14:04:44 +00007752 unsigned int block_end, rosize, len;
Michael Chan76d99062009-12-03 09:46:34 +00007753
Michael Chan012093f2009-12-03 15:58:00 -08007754#define BNX2_VPD_NVRAM_OFFSET 0x300
7755#define BNX2_VPD_LEN 128
Michael Chan76d99062009-12-03 09:46:34 +00007756#define BNX2_MAX_VER_SLEN 30
7757
7758 data = kmalloc(256, GFP_KERNEL);
7759 if (!data)
7760 return;
7761
Michael Chan012093f2009-12-03 15:58:00 -08007762 rc = bnx2_nvram_read(bp, BNX2_VPD_NVRAM_OFFSET, data + BNX2_VPD_LEN,
7763 BNX2_VPD_LEN);
Michael Chan76d99062009-12-03 09:46:34 +00007764 if (rc)
7765 goto vpd_done;
7766
Michael Chan012093f2009-12-03 15:58:00 -08007767 for (i = 0; i < BNX2_VPD_LEN; i += 4) {
7768 data[i] = data[i + BNX2_VPD_LEN + 3];
7769 data[i + 1] = data[i + BNX2_VPD_LEN + 2];
7770 data[i + 2] = data[i + BNX2_VPD_LEN + 1];
7771 data[i + 3] = data[i + BNX2_VPD_LEN];
Michael Chan76d99062009-12-03 09:46:34 +00007772 }
7773
Matt Carlsondf25bc32010-02-26 14:04:44 +00007774 i = pci_vpd_find_tag(data, 0, BNX2_VPD_LEN, PCI_VPD_LRDT_RO_DATA);
7775 if (i < 0)
Michael Chan76d99062009-12-03 09:46:34 +00007776 goto vpd_done;
Matt Carlsondf25bc32010-02-26 14:04:44 +00007777
7778 rosize = pci_vpd_lrdt_size(&data[i]);
7779 i += PCI_VPD_LRDT_TAG_SIZE;
7780 block_end = i + rosize;
7781
7782 if (block_end > BNX2_VPD_LEN)
7783 goto vpd_done;
7784
7785 j = pci_vpd_find_info_keyword(data, i, rosize,
7786 PCI_VPD_RO_KEYWORD_MFR_ID);
7787 if (j < 0)
7788 goto vpd_done;
7789
7790 len = pci_vpd_info_field_size(&data[j]);
7791
7792 j += PCI_VPD_INFO_FLD_HDR_SIZE;
7793 if (j + len > block_end || len != 4 ||
7794 memcmp(&data[j], "1028", 4))
7795 goto vpd_done;
7796
7797 j = pci_vpd_find_info_keyword(data, i, rosize,
7798 PCI_VPD_RO_KEYWORD_VENDOR0);
7799 if (j < 0)
7800 goto vpd_done;
7801
7802 len = pci_vpd_info_field_size(&data[j]);
7803
7804 j += PCI_VPD_INFO_FLD_HDR_SIZE;
7805 if (j + len > block_end || len > BNX2_MAX_VER_SLEN)
7806 goto vpd_done;
7807
7808 memcpy(bp->fw_version, &data[j], len);
7809 bp->fw_version[len] = ' ';
Michael Chan76d99062009-12-03 09:46:34 +00007810
7811vpd_done:
7812 kfree(data);
7813}
7814
Michael Chanb6016b72005-05-26 13:03:09 -07007815static int __devinit
7816bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
7817{
7818 struct bnx2 *bp;
7819 unsigned long mem_len;
Michael Chan58fc2ea2007-07-07 22:52:02 -07007820 int rc, i, j;
Michael Chanb6016b72005-05-26 13:03:09 -07007821 u32 reg;
Michael Chan40453c82007-05-03 13:19:18 -07007822 u64 dma_mask, persist_dma_mask;
Michael Chanb6016b72005-05-26 13:03:09 -07007823
Michael Chanb6016b72005-05-26 13:03:09 -07007824 SET_NETDEV_DEV(dev, &pdev->dev);
Michael Chan972ec0d2006-01-23 16:12:43 -08007825 bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007826
7827 bp->flags = 0;
7828 bp->phy_flags = 0;
7829
Michael Chan354fcd72010-01-17 07:30:44 +00007830 bp->temp_stats_blk =
7831 kzalloc(sizeof(struct statistics_block), GFP_KERNEL);
7832
7833 if (bp->temp_stats_blk == NULL) {
7834 rc = -ENOMEM;
7835 goto err_out;
7836 }
7837
Michael Chanb6016b72005-05-26 13:03:09 -07007838 /* enable device (incl. PCI PM wakeup), and bus-mastering */
7839 rc = pci_enable_device(pdev);
7840 if (rc) {
Joe Perches3a9c6a42010-02-17 15:01:51 +00007841 dev_err(&pdev->dev, "Cannot enable PCI device, aborting\n");
Michael Chanb6016b72005-05-26 13:03:09 -07007842 goto err_out;
7843 }
7844
7845 if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) {
Jeff Garzik9b91cf92006-06-27 11:39:50 -04007846 dev_err(&pdev->dev,
Joe Perches3a9c6a42010-02-17 15:01:51 +00007847 "Cannot find PCI device base address, aborting\n");
Michael Chanb6016b72005-05-26 13:03:09 -07007848 rc = -ENODEV;
7849 goto err_out_disable;
7850 }
7851
7852 rc = pci_request_regions(pdev, DRV_MODULE_NAME);
7853 if (rc) {
Joe Perches3a9c6a42010-02-17 15:01:51 +00007854 dev_err(&pdev->dev, "Cannot obtain PCI resources, aborting\n");
Michael Chanb6016b72005-05-26 13:03:09 -07007855 goto err_out_disable;
7856 }
7857
7858 pci_set_master(pdev);
Wendy Xiong6ff2da42008-05-16 22:18:21 -07007859 pci_save_state(pdev);
Michael Chanb6016b72005-05-26 13:03:09 -07007860
7861 bp->pm_cap = pci_find_capability(pdev, PCI_CAP_ID_PM);
7862 if (bp->pm_cap == 0) {
Jeff Garzik9b91cf92006-06-27 11:39:50 -04007863 dev_err(&pdev->dev,
Joe Perches3a9c6a42010-02-17 15:01:51 +00007864 "Cannot find power management capability, aborting\n");
Michael Chanb6016b72005-05-26 13:03:09 -07007865 rc = -EIO;
7866 goto err_out_release;
7867 }
7868
Michael Chanb6016b72005-05-26 13:03:09 -07007869 bp->dev = dev;
7870 bp->pdev = pdev;
7871
7872 spin_lock_init(&bp->phy_lock);
Michael Chan1b8227c2007-05-03 13:24:05 -07007873 spin_lock_init(&bp->indirect_lock);
Michael Chanc5a88952009-08-14 15:49:45 +00007874#ifdef BCM_CNIC
7875 mutex_init(&bp->cnic_lock);
7876#endif
David Howellsc4028952006-11-22 14:57:56 +00007877 INIT_WORK(&bp->reset_task, bnx2_reset_task);
Michael Chanb6016b72005-05-26 13:03:09 -07007878
7879 dev->base_addr = dev->mem_start = pci_resource_start(pdev, 0);
Michael Chan4edd4732009-06-08 18:14:42 -07007880 mem_len = MB_GET_CID_ADDR(TX_TSS_CID + TX_MAX_TSS_RINGS + 1);
Michael Chanb6016b72005-05-26 13:03:09 -07007881 dev->mem_end = dev->mem_start + mem_len;
7882 dev->irq = pdev->irq;
7883
7884 bp->regview = ioremap_nocache(dev->base_addr, mem_len);
7885
7886 if (!bp->regview) {
Joe Perches3a9c6a42010-02-17 15:01:51 +00007887 dev_err(&pdev->dev, "Cannot map register space, aborting\n");
Michael Chanb6016b72005-05-26 13:03:09 -07007888 rc = -ENOMEM;
7889 goto err_out_release;
7890 }
7891
7892 /* Configure byte swap and enable write to the reg_window registers.
7893 * Rely on CPU to do target byte swapping on big endian systems
7894 * The chip's target access swapping will not swap all accesses
7895 */
7896 pci_write_config_dword(bp->pdev, BNX2_PCICFG_MISC_CONFIG,
7897 BNX2_PCICFG_MISC_CONFIG_REG_WINDOW_ENA |
7898 BNX2_PCICFG_MISC_CONFIG_TARGET_MB_WORD_SWAP);
7899
Pavel Machek829ca9a2005-09-03 15:56:56 -07007900 bnx2_set_power_state(bp, PCI_D0);
Michael Chanb6016b72005-05-26 13:03:09 -07007901
7902 bp->chip_id = REG_RD(bp, BNX2_MISC_ID);
7903
Michael Chan883e5152007-05-03 13:25:11 -07007904 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
7905 if (pci_find_capability(pdev, PCI_CAP_ID_EXP) == 0) {
7906 dev_err(&pdev->dev,
Joe Perches3a9c6a42010-02-17 15:01:51 +00007907 "Cannot find PCIE capability, aborting\n");
Michael Chan883e5152007-05-03 13:25:11 -07007908 rc = -EIO;
7909 goto err_out_unmap;
7910 }
David S. Millerf86e82f2008-01-21 17:15:40 -08007911 bp->flags |= BNX2_FLAG_PCIE;
Michael Chan2dd201d2008-01-21 17:06:09 -08007912 if (CHIP_REV(bp) == CHIP_REV_Ax)
David S. Millerf86e82f2008-01-21 17:15:40 -08007913 bp->flags |= BNX2_FLAG_JUMBO_BROKEN;
Michael Chan883e5152007-05-03 13:25:11 -07007914 } else {
Michael Chan59b47d82006-11-19 14:10:45 -08007915 bp->pcix_cap = pci_find_capability(pdev, PCI_CAP_ID_PCIX);
7916 if (bp->pcix_cap == 0) {
7917 dev_err(&pdev->dev,
Joe Perches3a9c6a42010-02-17 15:01:51 +00007918 "Cannot find PCIX capability, aborting\n");
Michael Chan59b47d82006-11-19 14:10:45 -08007919 rc = -EIO;
7920 goto err_out_unmap;
7921 }
Michael Chan61d9e3f2009-08-21 16:20:46 +00007922 bp->flags |= BNX2_FLAG_BROKEN_STATS;
Michael Chan59b47d82006-11-19 14:10:45 -08007923 }
7924
Michael Chanb4b36042007-12-20 19:59:30 -08007925 if (CHIP_NUM(bp) == CHIP_NUM_5709 && CHIP_REV(bp) != CHIP_REV_Ax) {
7926 if (pci_find_capability(pdev, PCI_CAP_ID_MSIX))
David S. Millerf86e82f2008-01-21 17:15:40 -08007927 bp->flags |= BNX2_FLAG_MSIX_CAP;
Michael Chanb4b36042007-12-20 19:59:30 -08007928 }
7929
Michael Chan8e6a72c2007-05-03 13:24:48 -07007930 if (CHIP_ID(bp) != CHIP_ID_5706_A0 && CHIP_ID(bp) != CHIP_ID_5706_A1) {
7931 if (pci_find_capability(pdev, PCI_CAP_ID_MSI))
David S. Millerf86e82f2008-01-21 17:15:40 -08007932 bp->flags |= BNX2_FLAG_MSI_CAP;
Michael Chan8e6a72c2007-05-03 13:24:48 -07007933 }
7934
Michael Chan40453c82007-05-03 13:19:18 -07007935 /* 5708 cannot support DMA addresses > 40-bit. */
7936 if (CHIP_NUM(bp) == CHIP_NUM_5708)
Yang Hongyang50cf1562009-04-06 19:01:14 -07007937 persist_dma_mask = dma_mask = DMA_BIT_MASK(40);
Michael Chan40453c82007-05-03 13:19:18 -07007938 else
Yang Hongyang6a355282009-04-06 19:01:13 -07007939 persist_dma_mask = dma_mask = DMA_BIT_MASK(64);
Michael Chan40453c82007-05-03 13:19:18 -07007940
7941 /* Configure DMA attributes. */
7942 if (pci_set_dma_mask(pdev, dma_mask) == 0) {
7943 dev->features |= NETIF_F_HIGHDMA;
7944 rc = pci_set_consistent_dma_mask(pdev, persist_dma_mask);
7945 if (rc) {
7946 dev_err(&pdev->dev,
Joe Perches3a9c6a42010-02-17 15:01:51 +00007947 "pci_set_consistent_dma_mask failed, aborting\n");
Michael Chan40453c82007-05-03 13:19:18 -07007948 goto err_out_unmap;
7949 }
Yang Hongyang284901a2009-04-06 19:01:15 -07007950 } else if ((rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) != 0) {
Joe Perches3a9c6a42010-02-17 15:01:51 +00007951 dev_err(&pdev->dev, "System does not support DMA, aborting\n");
Michael Chan40453c82007-05-03 13:19:18 -07007952 goto err_out_unmap;
7953 }
7954
David S. Millerf86e82f2008-01-21 17:15:40 -08007955 if (!(bp->flags & BNX2_FLAG_PCIE))
Michael Chan883e5152007-05-03 13:25:11 -07007956 bnx2_get_pci_speed(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07007957
7958 /* 5706A0 may falsely detect SERR and PERR. */
7959 if (CHIP_ID(bp) == CHIP_ID_5706_A0) {
7960 reg = REG_RD(bp, PCI_COMMAND);
7961 reg &= ~(PCI_COMMAND_SERR | PCI_COMMAND_PARITY);
7962 REG_WR(bp, PCI_COMMAND, reg);
7963 }
7964 else if ((CHIP_ID(bp) == CHIP_ID_5706_A1) &&
David S. Millerf86e82f2008-01-21 17:15:40 -08007965 !(bp->flags & BNX2_FLAG_PCIX)) {
Michael Chanb6016b72005-05-26 13:03:09 -07007966
Jeff Garzik9b91cf92006-06-27 11:39:50 -04007967 dev_err(&pdev->dev,
Joe Perches3a9c6a42010-02-17 15:01:51 +00007968 "5706 A1 can only be used in a PCIX bus, aborting\n");
Michael Chanb6016b72005-05-26 13:03:09 -07007969 goto err_out_unmap;
7970 }
7971
7972 bnx2_init_nvram(bp);
7973
Michael Chan2726d6e2008-01-29 21:35:05 -08007974 reg = bnx2_reg_rd_ind(bp, BNX2_SHM_HDR_SIGNATURE);
Michael Chane3648b32005-11-04 08:51:21 -08007975
7976 if ((reg & BNX2_SHM_HDR_SIGNATURE_SIG_MASK) ==
Michael Chan24cb2302007-01-25 15:49:56 -08007977 BNX2_SHM_HDR_SIGNATURE_SIG) {
7978 u32 off = PCI_FUNC(pdev->devfn) << 2;
7979
Michael Chan2726d6e2008-01-29 21:35:05 -08007980 bp->shmem_base = bnx2_reg_rd_ind(bp, BNX2_SHM_HDR_ADDR_0 + off);
Michael Chan24cb2302007-01-25 15:49:56 -08007981 } else
Michael Chane3648b32005-11-04 08:51:21 -08007982 bp->shmem_base = HOST_VIEW_SHMEM_BASE;
7983
Michael Chanb6016b72005-05-26 13:03:09 -07007984 /* Get the permanent MAC address. First we need to make sure the
7985 * firmware is actually running.
7986 */
Michael Chan2726d6e2008-01-29 21:35:05 -08007987 reg = bnx2_shmem_rd(bp, BNX2_DEV_INFO_SIGNATURE);
Michael Chanb6016b72005-05-26 13:03:09 -07007988
7989 if ((reg & BNX2_DEV_INFO_SIGNATURE_MAGIC_MASK) !=
7990 BNX2_DEV_INFO_SIGNATURE_MAGIC) {
Joe Perches3a9c6a42010-02-17 15:01:51 +00007991 dev_err(&pdev->dev, "Firmware not running, aborting\n");
Michael Chanb6016b72005-05-26 13:03:09 -07007992 rc = -ENODEV;
7993 goto err_out_unmap;
7994 }
7995
Michael Chan76d99062009-12-03 09:46:34 +00007996 bnx2_read_vpd_fw_ver(bp);
7997
7998 j = strlen(bp->fw_version);
Michael Chan2726d6e2008-01-29 21:35:05 -08007999 reg = bnx2_shmem_rd(bp, BNX2_DEV_INFO_BC_REV);
Michael Chan76d99062009-12-03 09:46:34 +00008000 for (i = 0; i < 3 && j < 24; i++) {
Michael Chan58fc2ea2007-07-07 22:52:02 -07008001 u8 num, k, skip0;
8002
Michael Chan76d99062009-12-03 09:46:34 +00008003 if (i == 0) {
8004 bp->fw_version[j++] = 'b';
8005 bp->fw_version[j++] = 'c';
8006 bp->fw_version[j++] = ' ';
8007 }
Michael Chan58fc2ea2007-07-07 22:52:02 -07008008 num = (u8) (reg >> (24 - (i * 8)));
8009 for (k = 100, skip0 = 1; k >= 1; num %= k, k /= 10) {
8010 if (num >= k || !skip0 || k == 1) {
8011 bp->fw_version[j++] = (num / k) + '0';
8012 skip0 = 0;
8013 }
8014 }
8015 if (i != 2)
8016 bp->fw_version[j++] = '.';
8017 }
Michael Chan2726d6e2008-01-29 21:35:05 -08008018 reg = bnx2_shmem_rd(bp, BNX2_PORT_FEATURE);
Michael Chan846f5c62007-10-10 16:16:51 -07008019 if (reg & BNX2_PORT_FEATURE_WOL_ENABLED)
8020 bp->wol = 1;
8021
8022 if (reg & BNX2_PORT_FEATURE_ASF_ENABLED) {
David S. Millerf86e82f2008-01-21 17:15:40 -08008023 bp->flags |= BNX2_FLAG_ASF_ENABLE;
Michael Chanc2d3db82007-07-16 18:26:43 -07008024
8025 for (i = 0; i < 30; i++) {
Michael Chan2726d6e2008-01-29 21:35:05 -08008026 reg = bnx2_shmem_rd(bp, BNX2_BC_STATE_CONDITION);
Michael Chanc2d3db82007-07-16 18:26:43 -07008027 if (reg & BNX2_CONDITION_MFW_RUN_MASK)
8028 break;
8029 msleep(10);
8030 }
8031 }
Michael Chan2726d6e2008-01-29 21:35:05 -08008032 reg = bnx2_shmem_rd(bp, BNX2_BC_STATE_CONDITION);
Michael Chan58fc2ea2007-07-07 22:52:02 -07008033 reg &= BNX2_CONDITION_MFW_RUN_MASK;
8034 if (reg != BNX2_CONDITION_MFW_RUN_UNKNOWN &&
8035 reg != BNX2_CONDITION_MFW_RUN_NONE) {
Michael Chan2726d6e2008-01-29 21:35:05 -08008036 u32 addr = bnx2_shmem_rd(bp, BNX2_MFW_VER_PTR);
Michael Chan58fc2ea2007-07-07 22:52:02 -07008037
Michael Chan76d99062009-12-03 09:46:34 +00008038 if (j < 32)
8039 bp->fw_version[j++] = ' ';
8040 for (i = 0; i < 3 && j < 28; i++) {
Michael Chan2726d6e2008-01-29 21:35:05 -08008041 reg = bnx2_reg_rd_ind(bp, addr + i * 4);
Michael Chan58fc2ea2007-07-07 22:52:02 -07008042 reg = swab32(reg);
8043 memcpy(&bp->fw_version[j], &reg, 4);
8044 j += 4;
8045 }
8046 }
Michael Chanb6016b72005-05-26 13:03:09 -07008047
Michael Chan2726d6e2008-01-29 21:35:05 -08008048 reg = bnx2_shmem_rd(bp, BNX2_PORT_HW_CFG_MAC_UPPER);
Michael Chanb6016b72005-05-26 13:03:09 -07008049 bp->mac_addr[0] = (u8) (reg >> 8);
8050 bp->mac_addr[1] = (u8) reg;
8051
Michael Chan2726d6e2008-01-29 21:35:05 -08008052 reg = bnx2_shmem_rd(bp, BNX2_PORT_HW_CFG_MAC_LOWER);
Michael Chanb6016b72005-05-26 13:03:09 -07008053 bp->mac_addr[2] = (u8) (reg >> 24);
8054 bp->mac_addr[3] = (u8) (reg >> 16);
8055 bp->mac_addr[4] = (u8) (reg >> 8);
8056 bp->mac_addr[5] = (u8) reg;
8057
8058 bp->tx_ring_size = MAX_TX_DESC_CNT;
Michael Chan932f3772006-08-15 01:39:36 -07008059 bnx2_set_rx_ring_size(bp, 255);
Michael Chanb6016b72005-05-26 13:03:09 -07008060
8061 bp->rx_csum = 1;
8062
Michael Chancf7474a2009-08-21 16:20:48 +00008063 bp->tx_quick_cons_trip_int = 2;
Michael Chanb6016b72005-05-26 13:03:09 -07008064 bp->tx_quick_cons_trip = 20;
Michael Chancf7474a2009-08-21 16:20:48 +00008065 bp->tx_ticks_int = 18;
Michael Chanb6016b72005-05-26 13:03:09 -07008066 bp->tx_ticks = 80;
Jeff Garzik6aa20a22006-09-13 13:24:59 -04008067
Michael Chancf7474a2009-08-21 16:20:48 +00008068 bp->rx_quick_cons_trip_int = 2;
8069 bp->rx_quick_cons_trip = 12;
Michael Chanb6016b72005-05-26 13:03:09 -07008070 bp->rx_ticks_int = 18;
8071 bp->rx_ticks = 18;
8072
Michael Chan7ea69202007-07-16 18:27:10 -07008073 bp->stats_ticks = USEC_PER_SEC & BNX2_HC_STATS_TICKS_HC_STAT_TICKS;
Michael Chanb6016b72005-05-26 13:03:09 -07008074
Benjamin Liac392ab2008-09-18 16:40:49 -07008075 bp->current_interval = BNX2_TIMER_INTERVAL;
Michael Chanb6016b72005-05-26 13:03:09 -07008076
Michael Chan5b0c76a2005-11-04 08:45:49 -08008077 bp->phy_addr = 1;
8078
Michael Chanb6016b72005-05-26 13:03:09 -07008079 /* Disable WOL support if we are running on a SERDES chip. */
Michael Chan253c8b752007-01-08 19:56:01 -08008080 if (CHIP_NUM(bp) == CHIP_NUM_5709)
8081 bnx2_get_5709_media(bp);
8082 else if (CHIP_BOND_ID(bp) & CHIP_BOND_ID_SERDES_BIT)
Michael Chan583c28e2008-01-21 19:51:35 -08008083 bp->phy_flags |= BNX2_PHY_FLAG_SERDES;
Michael Chanbac0dff2006-11-19 14:15:05 -08008084
Michael Chan0d8a6572007-07-07 22:49:43 -07008085 bp->phy_port = PORT_TP;
Michael Chan583c28e2008-01-21 19:51:35 -08008086 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Michael Chan0d8a6572007-07-07 22:49:43 -07008087 bp->phy_port = PORT_FIBRE;
Michael Chan2726d6e2008-01-29 21:35:05 -08008088 reg = bnx2_shmem_rd(bp, BNX2_SHARED_HW_CFG_CONFIG);
Michael Chan846f5c62007-10-10 16:16:51 -07008089 if (!(reg & BNX2_SHARED_HW_CFG_GIG_LINK_ON_VAUX)) {
David S. Millerf86e82f2008-01-21 17:15:40 -08008090 bp->flags |= BNX2_FLAG_NO_WOL;
Michael Chan846f5c62007-10-10 16:16:51 -07008091 bp->wol = 0;
8092 }
Michael Chan38ea3682008-02-23 19:48:57 -08008093 if (CHIP_NUM(bp) == CHIP_NUM_5706) {
8094 /* Don't do parallel detect on this board because of
8095 * some board problems. The link will not go down
8096 * if we do parallel detect.
8097 */
8098 if (pdev->subsystem_vendor == PCI_VENDOR_ID_HP &&
8099 pdev->subsystem_device == 0x310c)
8100 bp->phy_flags |= BNX2_PHY_FLAG_NO_PARALLEL;
8101 } else {
Michael Chan5b0c76a2005-11-04 08:45:49 -08008102 bp->phy_addr = 2;
Michael Chan5b0c76a2005-11-04 08:45:49 -08008103 if (reg & BNX2_SHARED_HW_CFG_PHY_2_5G)
Michael Chan583c28e2008-01-21 19:51:35 -08008104 bp->phy_flags |= BNX2_PHY_FLAG_2_5G_CAPABLE;
Michael Chan5b0c76a2005-11-04 08:45:49 -08008105 }
Michael Chan261dd5c2007-01-08 19:55:46 -08008106 } else if (CHIP_NUM(bp) == CHIP_NUM_5706 ||
8107 CHIP_NUM(bp) == CHIP_NUM_5708)
Michael Chan583c28e2008-01-21 19:51:35 -08008108 bp->phy_flags |= BNX2_PHY_FLAG_CRC_FIX;
Michael Chanfb0c18b2007-12-10 17:18:23 -08008109 else if (CHIP_NUM(bp) == CHIP_NUM_5709 &&
8110 (CHIP_REV(bp) == CHIP_REV_Ax ||
8111 CHIP_REV(bp) == CHIP_REV_Bx))
Michael Chan583c28e2008-01-21 19:51:35 -08008112 bp->phy_flags |= BNX2_PHY_FLAG_DIS_EARLY_DAC;
Michael Chanb6016b72005-05-26 13:03:09 -07008113
Michael Chan7c62e832008-07-14 22:39:03 -07008114 bnx2_init_fw_cap(bp);
8115
Michael Chan16088272006-06-12 22:16:43 -07008116 if ((CHIP_ID(bp) == CHIP_ID_5708_A0) ||
8117 (CHIP_ID(bp) == CHIP_ID_5708_B0) ||
Michael Chan5ec6d7b2008-11-12 16:01:41 -08008118 (CHIP_ID(bp) == CHIP_ID_5708_B1) ||
8119 !(REG_RD(bp, BNX2_PCI_CONFIG_3) & BNX2_PCI_CONFIG_3_VAUX_PRESET)) {
David S. Millerf86e82f2008-01-21 17:15:40 -08008120 bp->flags |= BNX2_FLAG_NO_WOL;
Michael Chan846f5c62007-10-10 16:16:51 -07008121 bp->wol = 0;
8122 }
Michael Chandda1e392006-01-23 16:08:14 -08008123
Michael Chanb6016b72005-05-26 13:03:09 -07008124 if (CHIP_ID(bp) == CHIP_ID_5706_A0) {
8125 bp->tx_quick_cons_trip_int =
8126 bp->tx_quick_cons_trip;
8127 bp->tx_ticks_int = bp->tx_ticks;
8128 bp->rx_quick_cons_trip_int =
8129 bp->rx_quick_cons_trip;
8130 bp->rx_ticks_int = bp->rx_ticks;
8131 bp->comp_prod_trip_int = bp->comp_prod_trip;
8132 bp->com_ticks_int = bp->com_ticks;
8133 bp->cmd_ticks_int = bp->cmd_ticks;
8134 }
8135
Michael Chanf9317a42006-09-29 17:06:23 -07008136 /* Disable MSI on 5706 if AMD 8132 bridge is found.
8137 *
8138 * MSI is defined to be 32-bit write. The 5706 does 64-bit MSI writes
8139 * with byte enables disabled on the unused 32-bit word. This is legal
8140 * but causes problems on the AMD 8132 which will eventually stop
8141 * responding after a while.
8142 *
8143 * AMD believes this incompatibility is unique to the 5706, and
Michael Ellerman88187df2007-01-25 19:34:07 +11008144 * prefers to locally disable MSI rather than globally disabling it.
Michael Chanf9317a42006-09-29 17:06:23 -07008145 */
8146 if (CHIP_NUM(bp) == CHIP_NUM_5706 && disable_msi == 0) {
8147 struct pci_dev *amd_8132 = NULL;
8148
8149 while ((amd_8132 = pci_get_device(PCI_VENDOR_ID_AMD,
8150 PCI_DEVICE_ID_AMD_8132_BRIDGE,
8151 amd_8132))) {
Michael Chanf9317a42006-09-29 17:06:23 -07008152
Auke Kok44c10132007-06-08 15:46:36 -07008153 if (amd_8132->revision >= 0x10 &&
8154 amd_8132->revision <= 0x13) {
Michael Chanf9317a42006-09-29 17:06:23 -07008155 disable_msi = 1;
8156 pci_dev_put(amd_8132);
8157 break;
8158 }
8159 }
8160 }
8161
Michael Chandeaf3912007-07-07 22:48:00 -07008162 bnx2_set_default_link(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07008163 bp->req_flow_ctrl = FLOW_CTRL_RX | FLOW_CTRL_TX;
8164
Michael Chancd339a02005-08-25 15:35:24 -07008165 init_timer(&bp->timer);
Benjamin Liac392ab2008-09-18 16:40:49 -07008166 bp->timer.expires = RUN_AT(BNX2_TIMER_INTERVAL);
Michael Chancd339a02005-08-25 15:35:24 -07008167 bp->timer.data = (unsigned long) bp;
8168 bp->timer.function = bnx2_timer;
8169
Michael Chanb6016b72005-05-26 13:03:09 -07008170 return 0;
8171
8172err_out_unmap:
8173 if (bp->regview) {
8174 iounmap(bp->regview);
Michael Chan73eef4c2005-08-25 15:39:15 -07008175 bp->regview = NULL;
Michael Chanb6016b72005-05-26 13:03:09 -07008176 }
8177
8178err_out_release:
8179 pci_release_regions(pdev);
8180
8181err_out_disable:
8182 pci_disable_device(pdev);
8183 pci_set_drvdata(pdev, NULL);
8184
8185err_out:
8186 return rc;
8187}
8188
Michael Chan883e5152007-05-03 13:25:11 -07008189static char * __devinit
8190bnx2_bus_string(struct bnx2 *bp, char *str)
8191{
8192 char *s = str;
8193
David S. Millerf86e82f2008-01-21 17:15:40 -08008194 if (bp->flags & BNX2_FLAG_PCIE) {
Michael Chan883e5152007-05-03 13:25:11 -07008195 s += sprintf(s, "PCI Express");
8196 } else {
8197 s += sprintf(s, "PCI");
David S. Millerf86e82f2008-01-21 17:15:40 -08008198 if (bp->flags & BNX2_FLAG_PCIX)
Michael Chan883e5152007-05-03 13:25:11 -07008199 s += sprintf(s, "-X");
David S. Millerf86e82f2008-01-21 17:15:40 -08008200 if (bp->flags & BNX2_FLAG_PCI_32BIT)
Michael Chan883e5152007-05-03 13:25:11 -07008201 s += sprintf(s, " 32-bit");
8202 else
8203 s += sprintf(s, " 64-bit");
8204 s += sprintf(s, " %dMHz", bp->bus_speed_mhz);
8205 }
8206 return str;
8207}
8208
Michael Chan2ba582b2007-12-21 15:04:49 -08008209static void __devinit
Michael Chan35efa7c2007-12-20 19:56:37 -08008210bnx2_init_napi(struct bnx2 *bp)
8211{
Michael Chanb4b36042007-12-20 19:59:30 -08008212 int i;
Michael Chan35efa7c2007-12-20 19:56:37 -08008213
Benjamin Li4327ba42010-03-23 13:13:11 +00008214 for (i = 0; i < bp->irq_nvecs; i++) {
Michael Chan35e90102008-06-19 16:37:42 -07008215 struct bnx2_napi *bnapi = &bp->bnx2_napi[i];
8216 int (*poll)(struct napi_struct *, int);
8217
8218 if (i == 0)
8219 poll = bnx2_poll;
8220 else
Michael Chanf0ea2e62008-06-19 16:41:57 -07008221 poll = bnx2_poll_msix;
Michael Chan35e90102008-06-19 16:37:42 -07008222
8223 netif_napi_add(bp->dev, &bp->bnx2_napi[i].napi, poll, 64);
Michael Chanb4b36042007-12-20 19:59:30 -08008224 bnapi->bp = bp;
8225 }
Michael Chan35efa7c2007-12-20 19:56:37 -08008226}
8227
Stephen Hemminger0421eae2008-11-21 17:31:27 -08008228static const struct net_device_ops bnx2_netdev_ops = {
8229 .ndo_open = bnx2_open,
8230 .ndo_start_xmit = bnx2_start_xmit,
8231 .ndo_stop = bnx2_close,
8232 .ndo_get_stats = bnx2_get_stats,
8233 .ndo_set_rx_mode = bnx2_set_rx_mode,
8234 .ndo_do_ioctl = bnx2_ioctl,
8235 .ndo_validate_addr = eth_validate_addr,
8236 .ndo_set_mac_address = bnx2_change_mac_addr,
8237 .ndo_change_mtu = bnx2_change_mtu,
8238 .ndo_tx_timeout = bnx2_tx_timeout,
8239#ifdef BCM_VLAN
8240 .ndo_vlan_rx_register = bnx2_vlan_rx_register,
8241#endif
Alexey Dobriyan257ddbd2010-01-27 10:17:41 +00008242#ifdef CONFIG_NET_POLL_CONTROLLER
Stephen Hemminger0421eae2008-11-21 17:31:27 -08008243 .ndo_poll_controller = poll_bnx2,
8244#endif
8245};
8246
Eric Dumazet72dccb02009-07-23 02:01:38 +00008247static void inline vlan_features_add(struct net_device *dev, unsigned long flags)
8248{
8249#ifdef BCM_VLAN
8250 dev->vlan_features |= flags;
8251#endif
8252}
8253
Michael Chan35efa7c2007-12-20 19:56:37 -08008254static int __devinit
Michael Chanb6016b72005-05-26 13:03:09 -07008255bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
8256{
8257 static int version_printed = 0;
8258 struct net_device *dev = NULL;
8259 struct bnx2 *bp;
Joe Perches0795af52007-10-03 17:59:30 -07008260 int rc;
Michael Chan883e5152007-05-03 13:25:11 -07008261 char str[40];
Michael Chanb6016b72005-05-26 13:03:09 -07008262
8263 if (version_printed++ == 0)
Joe Perches3a9c6a42010-02-17 15:01:51 +00008264 pr_info("%s", version);
Michael Chanb6016b72005-05-26 13:03:09 -07008265
8266 /* dev zeroed in init_etherdev */
Benjamin Li706bf242008-07-18 17:55:11 -07008267 dev = alloc_etherdev_mq(sizeof(*bp), TX_MAX_RINGS);
Michael Chanb6016b72005-05-26 13:03:09 -07008268
8269 if (!dev)
8270 return -ENOMEM;
8271
8272 rc = bnx2_init_board(pdev, dev);
8273 if (rc < 0) {
8274 free_netdev(dev);
8275 return rc;
8276 }
8277
Stephen Hemminger0421eae2008-11-21 17:31:27 -08008278 dev->netdev_ops = &bnx2_netdev_ops;
Michael Chanb6016b72005-05-26 13:03:09 -07008279 dev->watchdog_timeo = TX_TIMEOUT;
Michael Chanb6016b72005-05-26 13:03:09 -07008280 dev->ethtool_ops = &bnx2_ethtool_ops;
Michael Chanb6016b72005-05-26 13:03:09 -07008281
Michael Chan972ec0d2006-01-23 16:12:43 -08008282 bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07008283
Michael Chan1b2f9222007-05-03 13:20:19 -07008284 pci_set_drvdata(pdev, dev);
8285
Michael Chan57579f72009-04-04 16:51:14 -07008286 rc = bnx2_request_firmware(bp);
8287 if (rc)
8288 goto error;
8289
Michael Chan1b2f9222007-05-03 13:20:19 -07008290 memcpy(dev->dev_addr, bp->mac_addr, 6);
8291 memcpy(dev->perm_addr, bp->mac_addr, 6);
Michael Chan1b2f9222007-05-03 13:20:19 -07008292
Stephen Hemmingerd212f872007-06-27 00:47:37 -07008293 dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG;
Eric Dumazet72dccb02009-07-23 02:01:38 +00008294 vlan_features_add(dev, NETIF_F_IP_CSUM | NETIF_F_SG);
8295 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
Stephen Hemmingerd212f872007-06-27 00:47:37 -07008296 dev->features |= NETIF_F_IPV6_CSUM;
Eric Dumazet72dccb02009-07-23 02:01:38 +00008297 vlan_features_add(dev, NETIF_F_IPV6_CSUM);
8298 }
Michael Chan1b2f9222007-05-03 13:20:19 -07008299#ifdef BCM_VLAN
8300 dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
8301#endif
8302 dev->features |= NETIF_F_TSO | NETIF_F_TSO_ECN;
Eric Dumazet72dccb02009-07-23 02:01:38 +00008303 vlan_features_add(dev, NETIF_F_TSO | NETIF_F_TSO_ECN);
8304 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
Michael Chan4666f872007-05-03 13:22:28 -07008305 dev->features |= NETIF_F_TSO6;
Eric Dumazet72dccb02009-07-23 02:01:38 +00008306 vlan_features_add(dev, NETIF_F_TSO6);
8307 }
Michael Chanb6016b72005-05-26 13:03:09 -07008308 if ((rc = register_netdev(dev))) {
Jeff Garzik9b91cf92006-06-27 11:39:50 -04008309 dev_err(&pdev->dev, "Cannot register net device\n");
Michael Chan57579f72009-04-04 16:51:14 -07008310 goto error;
Michael Chanb6016b72005-05-26 13:03:09 -07008311 }
8312
Joe Perches3a9c6a42010-02-17 15:01:51 +00008313 netdev_info(dev, "%s (%c%d) %s found at mem %lx, IRQ %d, node addr %pM\n",
8314 board_info[ent->driver_data].name,
8315 ((CHIP_ID(bp) & 0xf000) >> 12) + 'A',
8316 ((CHIP_ID(bp) & 0x0ff0) >> 4),
8317 bnx2_bus_string(bp, str),
8318 dev->base_addr,
8319 bp->pdev->irq, dev->dev_addr);
Michael Chanb6016b72005-05-26 13:03:09 -07008320
Michael Chanb6016b72005-05-26 13:03:09 -07008321 return 0;
Michael Chan57579f72009-04-04 16:51:14 -07008322
8323error:
8324 if (bp->mips_firmware)
8325 release_firmware(bp->mips_firmware);
8326 if (bp->rv2p_firmware)
8327 release_firmware(bp->rv2p_firmware);
8328
8329 if (bp->regview)
8330 iounmap(bp->regview);
8331 pci_release_regions(pdev);
8332 pci_disable_device(pdev);
8333 pci_set_drvdata(pdev, NULL);
8334 free_netdev(dev);
8335 return rc;
Michael Chanb6016b72005-05-26 13:03:09 -07008336}
8337
8338static void __devexit
8339bnx2_remove_one(struct pci_dev *pdev)
8340{
8341 struct net_device *dev = pci_get_drvdata(pdev);
Michael Chan972ec0d2006-01-23 16:12:43 -08008342 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07008343
Michael Chanafdc08b2005-08-25 15:34:29 -07008344 flush_scheduled_work();
8345
Michael Chanb6016b72005-05-26 13:03:09 -07008346 unregister_netdev(dev);
8347
Michael Chan57579f72009-04-04 16:51:14 -07008348 if (bp->mips_firmware)
8349 release_firmware(bp->mips_firmware);
8350 if (bp->rv2p_firmware)
8351 release_firmware(bp->rv2p_firmware);
8352
Michael Chanb6016b72005-05-26 13:03:09 -07008353 if (bp->regview)
8354 iounmap(bp->regview);
8355
Michael Chan354fcd72010-01-17 07:30:44 +00008356 kfree(bp->temp_stats_blk);
8357
Michael Chanb6016b72005-05-26 13:03:09 -07008358 free_netdev(dev);
8359 pci_release_regions(pdev);
8360 pci_disable_device(pdev);
8361 pci_set_drvdata(pdev, NULL);
8362}
8363
8364static int
Pavel Machek829ca9a2005-09-03 15:56:56 -07008365bnx2_suspend(struct pci_dev *pdev, pm_message_t state)
Michael Chanb6016b72005-05-26 13:03:09 -07008366{
8367 struct net_device *dev = pci_get_drvdata(pdev);
Michael Chan972ec0d2006-01-23 16:12:43 -08008368 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07008369
Michael Chan6caebb02007-08-03 20:57:25 -07008370 /* PCI register 4 needs to be saved whether netif_running() or not.
8371 * MSI address and data need to be saved if using MSI and
8372 * netif_running().
8373 */
8374 pci_save_state(pdev);
Michael Chanb6016b72005-05-26 13:03:09 -07008375 if (!netif_running(dev))
8376 return 0;
8377
Michael Chan1d602902006-03-20 17:50:08 -08008378 flush_scheduled_work();
Michael Chanb6016b72005-05-26 13:03:09 -07008379 bnx2_netif_stop(bp);
8380 netif_device_detach(dev);
8381 del_timer_sync(&bp->timer);
Michael Chan74bf4ba2008-10-09 12:21:08 -07008382 bnx2_shutdown_chip(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07008383 bnx2_free_skbs(bp);
Pavel Machek829ca9a2005-09-03 15:56:56 -07008384 bnx2_set_power_state(bp, pci_choose_state(pdev, state));
Michael Chanb6016b72005-05-26 13:03:09 -07008385 return 0;
8386}
8387
8388static int
8389bnx2_resume(struct pci_dev *pdev)
8390{
8391 struct net_device *dev = pci_get_drvdata(pdev);
Michael Chan972ec0d2006-01-23 16:12:43 -08008392 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07008393
Michael Chan6caebb02007-08-03 20:57:25 -07008394 pci_restore_state(pdev);
Michael Chanb6016b72005-05-26 13:03:09 -07008395 if (!netif_running(dev))
8396 return 0;
8397
Pavel Machek829ca9a2005-09-03 15:56:56 -07008398 bnx2_set_power_state(bp, PCI_D0);
Michael Chanb6016b72005-05-26 13:03:09 -07008399 netif_device_attach(dev);
Michael Chan9a120bc2008-05-16 22:17:45 -07008400 bnx2_init_nic(bp, 1);
Michael Chanb6016b72005-05-26 13:03:09 -07008401 bnx2_netif_start(bp);
8402 return 0;
8403}
8404
Wendy Xiong6ff2da42008-05-16 22:18:21 -07008405/**
8406 * bnx2_io_error_detected - called when PCI error is detected
8407 * @pdev: Pointer to PCI device
8408 * @state: The current pci connection state
8409 *
8410 * This function is called after a PCI bus error affecting
8411 * this device has been detected.
8412 */
8413static pci_ers_result_t bnx2_io_error_detected(struct pci_dev *pdev,
8414 pci_channel_state_t state)
8415{
8416 struct net_device *dev = pci_get_drvdata(pdev);
8417 struct bnx2 *bp = netdev_priv(dev);
8418
8419 rtnl_lock();
8420 netif_device_detach(dev);
8421
Dean Nelson2ec3de22009-07-31 09:13:18 +00008422 if (state == pci_channel_io_perm_failure) {
8423 rtnl_unlock();
8424 return PCI_ERS_RESULT_DISCONNECT;
8425 }
8426
Wendy Xiong6ff2da42008-05-16 22:18:21 -07008427 if (netif_running(dev)) {
8428 bnx2_netif_stop(bp);
8429 del_timer_sync(&bp->timer);
8430 bnx2_reset_nic(bp, BNX2_DRV_MSG_CODE_RESET);
8431 }
8432
8433 pci_disable_device(pdev);
8434 rtnl_unlock();
8435
8436 /* Request a slot slot reset. */
8437 return PCI_ERS_RESULT_NEED_RESET;
8438}
8439
8440/**
8441 * bnx2_io_slot_reset - called after the pci bus has been reset.
8442 * @pdev: Pointer to PCI device
8443 *
8444 * Restart the card from scratch, as if from a cold-boot.
8445 */
8446static pci_ers_result_t bnx2_io_slot_reset(struct pci_dev *pdev)
8447{
8448 struct net_device *dev = pci_get_drvdata(pdev);
8449 struct bnx2 *bp = netdev_priv(dev);
8450
8451 rtnl_lock();
8452 if (pci_enable_device(pdev)) {
8453 dev_err(&pdev->dev,
Joe Perches3a9c6a42010-02-17 15:01:51 +00008454 "Cannot re-enable PCI device after reset\n");
Wendy Xiong6ff2da42008-05-16 22:18:21 -07008455 rtnl_unlock();
8456 return PCI_ERS_RESULT_DISCONNECT;
8457 }
8458 pci_set_master(pdev);
8459 pci_restore_state(pdev);
Breno Leitao529fab62009-11-26 07:31:49 +00008460 pci_save_state(pdev);
Wendy Xiong6ff2da42008-05-16 22:18:21 -07008461
8462 if (netif_running(dev)) {
8463 bnx2_set_power_state(bp, PCI_D0);
8464 bnx2_init_nic(bp, 1);
8465 }
8466
8467 rtnl_unlock();
8468 return PCI_ERS_RESULT_RECOVERED;
8469}
8470
8471/**
8472 * bnx2_io_resume - called when traffic can start flowing again.
8473 * @pdev: Pointer to PCI device
8474 *
8475 * This callback is called when the error recovery driver tells us that
8476 * its OK to resume normal operation.
8477 */
8478static void bnx2_io_resume(struct pci_dev *pdev)
8479{
8480 struct net_device *dev = pci_get_drvdata(pdev);
8481 struct bnx2 *bp = netdev_priv(dev);
8482
8483 rtnl_lock();
8484 if (netif_running(dev))
8485 bnx2_netif_start(bp);
8486
8487 netif_device_attach(dev);
8488 rtnl_unlock();
8489}
8490
8491static struct pci_error_handlers bnx2_err_handler = {
8492 .error_detected = bnx2_io_error_detected,
8493 .slot_reset = bnx2_io_slot_reset,
8494 .resume = bnx2_io_resume,
8495};
8496
Michael Chanb6016b72005-05-26 13:03:09 -07008497static struct pci_driver bnx2_pci_driver = {
Peter Hagervall14ab9b82005-08-10 14:18:16 -07008498 .name = DRV_MODULE_NAME,
8499 .id_table = bnx2_pci_tbl,
8500 .probe = bnx2_init_one,
8501 .remove = __devexit_p(bnx2_remove_one),
8502 .suspend = bnx2_suspend,
8503 .resume = bnx2_resume,
Wendy Xiong6ff2da42008-05-16 22:18:21 -07008504 .err_handler = &bnx2_err_handler,
Michael Chanb6016b72005-05-26 13:03:09 -07008505};
8506
8507static int __init bnx2_init(void)
8508{
Jeff Garzik29917622006-08-19 17:48:59 -04008509 return pci_register_driver(&bnx2_pci_driver);
Michael Chanb6016b72005-05-26 13:03:09 -07008510}
8511
8512static void __exit bnx2_cleanup(void)
8513{
8514 pci_unregister_driver(&bnx2_pci_driver);
8515}
8516
8517module_init(bnx2_init);
8518module_exit(bnx2_cleanup);
8519
8520
8521