blob: 5f0dda10f20d504c0a722f8bfbf400610f1b4b2e [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
Michael Chanf2a4f052006-03-23 01:13:12 -080012
13#include <linux/module.h>
14#include <linux/moduleparam.h>
15
16#include <linux/kernel.h>
17#include <linux/timer.h>
18#include <linux/errno.h>
19#include <linux/ioport.h>
20#include <linux/slab.h>
21#include <linux/vmalloc.h>
22#include <linux/interrupt.h>
23#include <linux/pci.h>
24#include <linux/init.h>
25#include <linux/netdevice.h>
26#include <linux/etherdevice.h>
27#include <linux/skbuff.h>
28#include <linux/dma-mapping.h>
Jiri Slaby1977f032007-10-18 23:40:25 -070029#include <linux/bitops.h>
Michael Chanf2a4f052006-03-23 01:13:12 -080030#include <asm/io.h>
31#include <asm/irq.h>
32#include <linux/delay.h>
33#include <asm/byteorder.h>
Michael Chanc86a31f2006-06-13 15:03:47 -070034#include <asm/page.h>
Michael Chanf2a4f052006-03-23 01:13:12 -080035#include <linux/time.h>
36#include <linux/ethtool.h>
37#include <linux/mii.h>
Michael Chanf2a4f052006-03-23 01:13:12 -080038#include <linux/if_vlan.h>
David S. Miller08013fa2008-08-15 19:46:01 -070039#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
Michael Chanf2a4f052006-03-23 01:13:12 -080040#define BCM_VLAN 1
41#endif
Michael Chanf2a4f052006-03-23 01:13:12 -080042#include <net/ip.h>
Linus Torvaldsde081fa2007-07-12 16:40:08 -070043#include <net/tcp.h>
Michael Chanf2a4f052006-03-23 01:13:12 -080044#include <net/checksum.h>
Michael Chanf2a4f052006-03-23 01:13:12 -080045#include <linux/workqueue.h>
46#include <linux/crc32.h>
47#include <linux/prefetch.h>
Michael Chan29b12172006-03-23 01:13:43 -080048#include <linux/cache.h>
Michael Chan57579f72009-04-04 16:51:14 -070049#include <linux/firmware.h>
Benjamin Li706bf242008-07-18 17:55:11 -070050#include <linux/log2.h>
Michael Chanf2a4f052006-03-23 01:13:12 -080051
Michael Chan4edd4732009-06-08 18:14:42 -070052#if defined(CONFIG_CNIC) || defined(CONFIG_CNIC_MODULE)
53#define BCM_CNIC 1
54#include "cnic_if.h"
55#endif
Michael Chanb6016b72005-05-26 13:03:09 -070056#include "bnx2.h"
57#include "bnx2_fw.h"
Denys Vlasenkob3448b02007-09-30 17:55:51 -070058
Michael Chanb6016b72005-05-26 13:03:09 -070059#define DRV_MODULE_NAME "bnx2"
60#define PFX DRV_MODULE_NAME ": "
Michael 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
Michael Chan35e90102008-06-19 16:37:42 -0700249static inline u32 bnx2_tx_avail(struct bnx2 *bp, struct bnx2_tx_ring_info *txr)
Michael Chane89bbf12005-08-25 15:36:58 -0700250{
Michael Chan2f8af122006-08-15 01:39:10 -0700251 u32 diff;
Michael Chane89bbf12005-08-25 15:36:58 -0700252
Michael Chan2f8af122006-08-15 01:39:10 -0700253 smp_mb();
Michael Chanfaac9c42006-12-14 15:56:32 -0800254
255 /* The ring uses 256 indices for 255 entries, one of them
256 * needs to be skipped.
257 */
Michael Chan35e90102008-06-19 16:37:42 -0700258 diff = txr->tx_prod - txr->tx_cons;
Michael Chanfaac9c42006-12-14 15:56:32 -0800259 if (unlikely(diff >= TX_DESC_CNT)) {
260 diff &= 0xffff;
261 if (diff == TX_DESC_CNT)
262 diff = MAX_TX_DESC_CNT;
263 }
Michael Chane89bbf12005-08-25 15:36:58 -0700264 return (bp->tx_ring_size - diff);
265}
266
Michael Chanb6016b72005-05-26 13:03:09 -0700267static u32
268bnx2_reg_rd_ind(struct bnx2 *bp, u32 offset)
269{
Michael Chan1b8227c2007-05-03 13:24:05 -0700270 u32 val;
271
272 spin_lock_bh(&bp->indirect_lock);
Michael Chanb6016b72005-05-26 13:03:09 -0700273 REG_WR(bp, BNX2_PCICFG_REG_WINDOW_ADDRESS, offset);
Michael Chan1b8227c2007-05-03 13:24:05 -0700274 val = REG_RD(bp, BNX2_PCICFG_REG_WINDOW);
275 spin_unlock_bh(&bp->indirect_lock);
276 return val;
Michael Chanb6016b72005-05-26 13:03:09 -0700277}
278
279static void
280bnx2_reg_wr_ind(struct bnx2 *bp, u32 offset, u32 val)
281{
Michael Chan1b8227c2007-05-03 13:24:05 -0700282 spin_lock_bh(&bp->indirect_lock);
Michael Chanb6016b72005-05-26 13:03:09 -0700283 REG_WR(bp, BNX2_PCICFG_REG_WINDOW_ADDRESS, offset);
284 REG_WR(bp, BNX2_PCICFG_REG_WINDOW, val);
Michael Chan1b8227c2007-05-03 13:24:05 -0700285 spin_unlock_bh(&bp->indirect_lock);
Michael Chanb6016b72005-05-26 13:03:09 -0700286}
287
288static void
Michael Chan2726d6e2008-01-29 21:35:05 -0800289bnx2_shmem_wr(struct bnx2 *bp, u32 offset, u32 val)
290{
291 bnx2_reg_wr_ind(bp, bp->shmem_base + offset, val);
292}
293
294static u32
295bnx2_shmem_rd(struct bnx2 *bp, u32 offset)
296{
297 return (bnx2_reg_rd_ind(bp, bp->shmem_base + offset));
298}
299
300static void
Michael Chanb6016b72005-05-26 13:03:09 -0700301bnx2_ctx_wr(struct bnx2 *bp, u32 cid_addr, u32 offset, u32 val)
302{
303 offset += cid_addr;
Michael Chan1b8227c2007-05-03 13:24:05 -0700304 spin_lock_bh(&bp->indirect_lock);
Michael Chan59b47d82006-11-19 14:10:45 -0800305 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
306 int i;
307
308 REG_WR(bp, BNX2_CTX_CTX_DATA, val);
309 REG_WR(bp, BNX2_CTX_CTX_CTRL,
310 offset | BNX2_CTX_CTX_CTRL_WRITE_REQ);
311 for (i = 0; i < 5; i++) {
Michael Chan59b47d82006-11-19 14:10:45 -0800312 val = REG_RD(bp, BNX2_CTX_CTX_CTRL);
313 if ((val & BNX2_CTX_CTX_CTRL_WRITE_REQ) == 0)
314 break;
315 udelay(5);
316 }
317 } else {
318 REG_WR(bp, BNX2_CTX_DATA_ADR, offset);
319 REG_WR(bp, BNX2_CTX_DATA, val);
320 }
Michael Chan1b8227c2007-05-03 13:24:05 -0700321 spin_unlock_bh(&bp->indirect_lock);
Michael Chanb6016b72005-05-26 13:03:09 -0700322}
323
Michael Chan4edd4732009-06-08 18:14:42 -0700324#ifdef BCM_CNIC
325static int
326bnx2_drv_ctl(struct net_device *dev, struct drv_ctl_info *info)
327{
328 struct bnx2 *bp = netdev_priv(dev);
329 struct drv_ctl_io *io = &info->data.io;
330
331 switch (info->cmd) {
332 case DRV_CTL_IO_WR_CMD:
333 bnx2_reg_wr_ind(bp, io->offset, io->data);
334 break;
335 case DRV_CTL_IO_RD_CMD:
336 io->data = bnx2_reg_rd_ind(bp, io->offset);
337 break;
338 case DRV_CTL_CTX_WR_CMD:
339 bnx2_ctx_wr(bp, io->cid_addr, io->offset, io->data);
340 break;
341 default:
342 return -EINVAL;
343 }
344 return 0;
345}
346
347static void bnx2_setup_cnic_irq_info(struct bnx2 *bp)
348{
349 struct cnic_eth_dev *cp = &bp->cnic_eth_dev;
350 struct bnx2_napi *bnapi = &bp->bnx2_napi[0];
351 int sb_id;
352
353 if (bp->flags & BNX2_FLAG_USING_MSIX) {
354 cp->drv_state |= CNIC_DRV_STATE_USING_MSIX;
355 bnapi->cnic_present = 0;
356 sb_id = bp->irq_nvecs;
357 cp->irq_arr[0].irq_flags |= CNIC_IRQ_FL_MSIX;
358 } else {
359 cp->drv_state &= ~CNIC_DRV_STATE_USING_MSIX;
360 bnapi->cnic_tag = bnapi->last_status_idx;
361 bnapi->cnic_present = 1;
362 sb_id = 0;
363 cp->irq_arr[0].irq_flags &= ~CNIC_IRQ_FL_MSIX;
364 }
365
366 cp->irq_arr[0].vector = bp->irq_tbl[sb_id].vector;
367 cp->irq_arr[0].status_blk = (void *)
368 ((unsigned long) bnapi->status_blk.msi +
369 (BNX2_SBLK_MSIX_ALIGN_SIZE * sb_id));
370 cp->irq_arr[0].status_blk_num = sb_id;
371 cp->num_irq = 1;
372}
373
374static int bnx2_register_cnic(struct net_device *dev, struct cnic_ops *ops,
375 void *data)
376{
377 struct bnx2 *bp = netdev_priv(dev);
378 struct cnic_eth_dev *cp = &bp->cnic_eth_dev;
379
380 if (ops == NULL)
381 return -EINVAL;
382
383 if (cp->drv_state & CNIC_DRV_STATE_REGD)
384 return -EBUSY;
385
386 bp->cnic_data = data;
387 rcu_assign_pointer(bp->cnic_ops, ops);
388
389 cp->num_irq = 0;
390 cp->drv_state = CNIC_DRV_STATE_REGD;
391
392 bnx2_setup_cnic_irq_info(bp);
393
394 return 0;
395}
396
397static int bnx2_unregister_cnic(struct net_device *dev)
398{
399 struct bnx2 *bp = netdev_priv(dev);
400 struct bnx2_napi *bnapi = &bp->bnx2_napi[0];
401 struct cnic_eth_dev *cp = &bp->cnic_eth_dev;
402
Michael Chanc5a88952009-08-14 15:49:45 +0000403 mutex_lock(&bp->cnic_lock);
Michael Chan4edd4732009-06-08 18:14:42 -0700404 cp->drv_state = 0;
405 bnapi->cnic_present = 0;
406 rcu_assign_pointer(bp->cnic_ops, NULL);
Michael Chanc5a88952009-08-14 15:49:45 +0000407 mutex_unlock(&bp->cnic_lock);
Michael Chan4edd4732009-06-08 18:14:42 -0700408 synchronize_rcu();
409 return 0;
410}
411
412struct cnic_eth_dev *bnx2_cnic_probe(struct net_device *dev)
413{
414 struct bnx2 *bp = netdev_priv(dev);
415 struct cnic_eth_dev *cp = &bp->cnic_eth_dev;
416
417 cp->drv_owner = THIS_MODULE;
418 cp->chip_id = bp->chip_id;
419 cp->pdev = bp->pdev;
420 cp->io_base = bp->regview;
421 cp->drv_ctl = bnx2_drv_ctl;
422 cp->drv_register_cnic = bnx2_register_cnic;
423 cp->drv_unregister_cnic = bnx2_unregister_cnic;
424
425 return cp;
426}
427EXPORT_SYMBOL(bnx2_cnic_probe);
428
429static void
430bnx2_cnic_stop(struct bnx2 *bp)
431{
432 struct cnic_ops *c_ops;
433 struct cnic_ctl_info info;
434
Michael Chanc5a88952009-08-14 15:49:45 +0000435 mutex_lock(&bp->cnic_lock);
436 c_ops = bp->cnic_ops;
Michael Chan4edd4732009-06-08 18:14:42 -0700437 if (c_ops) {
438 info.cmd = CNIC_CTL_STOP_CMD;
439 c_ops->cnic_ctl(bp->cnic_data, &info);
440 }
Michael Chanc5a88952009-08-14 15:49:45 +0000441 mutex_unlock(&bp->cnic_lock);
Michael Chan4edd4732009-06-08 18:14:42 -0700442}
443
444static void
445bnx2_cnic_start(struct bnx2 *bp)
446{
447 struct cnic_ops *c_ops;
448 struct cnic_ctl_info info;
449
Michael Chanc5a88952009-08-14 15:49:45 +0000450 mutex_lock(&bp->cnic_lock);
451 c_ops = bp->cnic_ops;
Michael Chan4edd4732009-06-08 18:14:42 -0700452 if (c_ops) {
453 if (!(bp->flags & BNX2_FLAG_USING_MSIX)) {
454 struct bnx2_napi *bnapi = &bp->bnx2_napi[0];
455
456 bnapi->cnic_tag = bnapi->last_status_idx;
457 }
458 info.cmd = CNIC_CTL_START_CMD;
459 c_ops->cnic_ctl(bp->cnic_data, &info);
460 }
Michael Chanc5a88952009-08-14 15:49:45 +0000461 mutex_unlock(&bp->cnic_lock);
Michael Chan4edd4732009-06-08 18:14:42 -0700462}
463
464#else
465
466static void
467bnx2_cnic_stop(struct bnx2 *bp)
468{
469}
470
471static void
472bnx2_cnic_start(struct bnx2 *bp)
473{
474}
475
476#endif
477
Michael Chanb6016b72005-05-26 13:03:09 -0700478static int
479bnx2_read_phy(struct bnx2 *bp, u32 reg, u32 *val)
480{
481 u32 val1;
482 int i, ret;
483
Michael Chan583c28e2008-01-21 19:51:35 -0800484 if (bp->phy_flags & BNX2_PHY_FLAG_INT_MODE_AUTO_POLLING) {
Michael Chanb6016b72005-05-26 13:03:09 -0700485 val1 = REG_RD(bp, BNX2_EMAC_MDIO_MODE);
486 val1 &= ~BNX2_EMAC_MDIO_MODE_AUTO_POLL;
487
488 REG_WR(bp, BNX2_EMAC_MDIO_MODE, val1);
489 REG_RD(bp, BNX2_EMAC_MDIO_MODE);
490
491 udelay(40);
492 }
493
494 val1 = (bp->phy_addr << 21) | (reg << 16) |
495 BNX2_EMAC_MDIO_COMM_COMMAND_READ | BNX2_EMAC_MDIO_COMM_DISEXT |
496 BNX2_EMAC_MDIO_COMM_START_BUSY;
497 REG_WR(bp, BNX2_EMAC_MDIO_COMM, val1);
498
499 for (i = 0; i < 50; i++) {
500 udelay(10);
501
502 val1 = REG_RD(bp, BNX2_EMAC_MDIO_COMM);
503 if (!(val1 & BNX2_EMAC_MDIO_COMM_START_BUSY)) {
504 udelay(5);
505
506 val1 = REG_RD(bp, BNX2_EMAC_MDIO_COMM);
507 val1 &= BNX2_EMAC_MDIO_COMM_DATA;
508
509 break;
510 }
511 }
512
513 if (val1 & BNX2_EMAC_MDIO_COMM_START_BUSY) {
514 *val = 0x0;
515 ret = -EBUSY;
516 }
517 else {
518 *val = val1;
519 ret = 0;
520 }
521
Michael Chan583c28e2008-01-21 19:51:35 -0800522 if (bp->phy_flags & BNX2_PHY_FLAG_INT_MODE_AUTO_POLLING) {
Michael Chanb6016b72005-05-26 13:03:09 -0700523 val1 = REG_RD(bp, BNX2_EMAC_MDIO_MODE);
524 val1 |= BNX2_EMAC_MDIO_MODE_AUTO_POLL;
525
526 REG_WR(bp, BNX2_EMAC_MDIO_MODE, val1);
527 REG_RD(bp, BNX2_EMAC_MDIO_MODE);
528
529 udelay(40);
530 }
531
532 return ret;
533}
534
535static int
536bnx2_write_phy(struct bnx2 *bp, u32 reg, u32 val)
537{
538 u32 val1;
539 int i, ret;
540
Michael Chan583c28e2008-01-21 19:51:35 -0800541 if (bp->phy_flags & BNX2_PHY_FLAG_INT_MODE_AUTO_POLLING) {
Michael Chanb6016b72005-05-26 13:03:09 -0700542 val1 = REG_RD(bp, BNX2_EMAC_MDIO_MODE);
543 val1 &= ~BNX2_EMAC_MDIO_MODE_AUTO_POLL;
544
545 REG_WR(bp, BNX2_EMAC_MDIO_MODE, val1);
546 REG_RD(bp, BNX2_EMAC_MDIO_MODE);
547
548 udelay(40);
549 }
550
551 val1 = (bp->phy_addr << 21) | (reg << 16) | val |
552 BNX2_EMAC_MDIO_COMM_COMMAND_WRITE |
553 BNX2_EMAC_MDIO_COMM_START_BUSY | BNX2_EMAC_MDIO_COMM_DISEXT;
554 REG_WR(bp, BNX2_EMAC_MDIO_COMM, val1);
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400555
Michael Chanb6016b72005-05-26 13:03:09 -0700556 for (i = 0; i < 50; i++) {
557 udelay(10);
558
559 val1 = REG_RD(bp, BNX2_EMAC_MDIO_COMM);
560 if (!(val1 & BNX2_EMAC_MDIO_COMM_START_BUSY)) {
561 udelay(5);
562 break;
563 }
564 }
565
566 if (val1 & BNX2_EMAC_MDIO_COMM_START_BUSY)
567 ret = -EBUSY;
568 else
569 ret = 0;
570
Michael Chan583c28e2008-01-21 19:51:35 -0800571 if (bp->phy_flags & BNX2_PHY_FLAG_INT_MODE_AUTO_POLLING) {
Michael Chanb6016b72005-05-26 13:03:09 -0700572 val1 = REG_RD(bp, BNX2_EMAC_MDIO_MODE);
573 val1 |= BNX2_EMAC_MDIO_MODE_AUTO_POLL;
574
575 REG_WR(bp, BNX2_EMAC_MDIO_MODE, val1);
576 REG_RD(bp, BNX2_EMAC_MDIO_MODE);
577
578 udelay(40);
579 }
580
581 return ret;
582}
583
584static void
585bnx2_disable_int(struct bnx2 *bp)
586{
Michael Chanb4b36042007-12-20 19:59:30 -0800587 int i;
588 struct bnx2_napi *bnapi;
589
590 for (i = 0; i < bp->irq_nvecs; i++) {
591 bnapi = &bp->bnx2_napi[i];
592 REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD, bnapi->int_num |
593 BNX2_PCICFG_INT_ACK_CMD_MASK_INT);
594 }
Michael Chanb6016b72005-05-26 13:03:09 -0700595 REG_RD(bp, BNX2_PCICFG_INT_ACK_CMD);
596}
597
598static void
599bnx2_enable_int(struct bnx2 *bp)
600{
Michael Chanb4b36042007-12-20 19:59:30 -0800601 int i;
602 struct bnx2_napi *bnapi;
Michael Chan1269a8a2006-01-23 16:11:03 -0800603
Michael Chanb4b36042007-12-20 19:59:30 -0800604 for (i = 0; i < bp->irq_nvecs; i++) {
605 bnapi = &bp->bnx2_napi[i];
Michael Chan35efa7c2007-12-20 19:56:37 -0800606
Michael Chanb4b36042007-12-20 19:59:30 -0800607 REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD, bnapi->int_num |
608 BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
609 BNX2_PCICFG_INT_ACK_CMD_MASK_INT |
610 bnapi->last_status_idx);
Michael Chanb6016b72005-05-26 13:03:09 -0700611
Michael Chanb4b36042007-12-20 19:59:30 -0800612 REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD, bnapi->int_num |
613 BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
614 bnapi->last_status_idx);
615 }
Michael Chanbf5295b2006-03-23 01:11:56 -0800616 REG_WR(bp, BNX2_HC_COMMAND, bp->hc_cmd | BNX2_HC_COMMAND_COAL_NOW);
Michael Chanb6016b72005-05-26 13:03:09 -0700617}
618
619static void
620bnx2_disable_int_sync(struct bnx2 *bp)
621{
Michael Chanb4b36042007-12-20 19:59:30 -0800622 int i;
623
Michael Chanb6016b72005-05-26 13:03:09 -0700624 atomic_inc(&bp->intr_sem);
Michael Chan37675462009-08-21 16:20:44 +0000625 if (!netif_running(bp->dev))
626 return;
627
Michael Chanb6016b72005-05-26 13:03:09 -0700628 bnx2_disable_int(bp);
Michael Chanb4b36042007-12-20 19:59:30 -0800629 for (i = 0; i < bp->irq_nvecs; i++)
630 synchronize_irq(bp->irq_tbl[i].vector);
Michael Chanb6016b72005-05-26 13:03:09 -0700631}
632
633static void
Michael Chan35efa7c2007-12-20 19:56:37 -0800634bnx2_napi_disable(struct bnx2 *bp)
635{
Michael Chanb4b36042007-12-20 19:59:30 -0800636 int i;
637
638 for (i = 0; i < bp->irq_nvecs; i++)
639 napi_disable(&bp->bnx2_napi[i].napi);
Michael Chan35efa7c2007-12-20 19:56:37 -0800640}
641
642static void
643bnx2_napi_enable(struct bnx2 *bp)
644{
Michael Chanb4b36042007-12-20 19:59:30 -0800645 int i;
646
647 for (i = 0; i < bp->irq_nvecs; i++)
648 napi_enable(&bp->bnx2_napi[i].napi);
Michael Chan35efa7c2007-12-20 19:56:37 -0800649}
650
651static void
Michael Chanb6016b72005-05-26 13:03:09 -0700652bnx2_netif_stop(struct bnx2 *bp)
653{
Michael Chan4edd4732009-06-08 18:14:42 -0700654 bnx2_cnic_stop(bp);
Michael Chanb6016b72005-05-26 13:03:09 -0700655 if (netif_running(bp->dev)) {
Breno Leitaoe6bf95f2009-12-18 20:35:34 -0800656 int i;
657
Michael Chan35efa7c2007-12-20 19:56:37 -0800658 bnx2_napi_disable(bp);
Michael Chanb6016b72005-05-26 13:03:09 -0700659 netif_tx_disable(bp->dev);
Breno Leitaoe6bf95f2009-12-18 20:35:34 -0800660 /* prevent tx timeout */
661 for (i = 0; i < bp->dev->num_tx_queues; i++) {
662 struct netdev_queue *txq;
663
664 txq = netdev_get_tx_queue(bp->dev, i);
665 txq->trans_start = jiffies;
666 }
Michael Chanb6016b72005-05-26 13:03:09 -0700667 }
Michael Chanb7466562009-12-20 18:40:18 -0800668 bnx2_disable_int_sync(bp);
Michael Chanb6016b72005-05-26 13:03:09 -0700669}
670
671static void
672bnx2_netif_start(struct bnx2 *bp)
673{
674 if (atomic_dec_and_test(&bp->intr_sem)) {
675 if (netif_running(bp->dev)) {
Benjamin Li706bf242008-07-18 17:55:11 -0700676 netif_tx_wake_all_queues(bp->dev);
Michael Chan35efa7c2007-12-20 19:56:37 -0800677 bnx2_napi_enable(bp);
Michael Chanb6016b72005-05-26 13:03:09 -0700678 bnx2_enable_int(bp);
Michael Chan4edd4732009-06-08 18:14:42 -0700679 bnx2_cnic_start(bp);
Michael Chanb6016b72005-05-26 13:03:09 -0700680 }
681 }
682}
683
684static void
Michael Chan35e90102008-06-19 16:37:42 -0700685bnx2_free_tx_mem(struct bnx2 *bp)
686{
687 int i;
688
689 for (i = 0; i < bp->num_tx_rings; i++) {
690 struct bnx2_napi *bnapi = &bp->bnx2_napi[i];
691 struct bnx2_tx_ring_info *txr = &bnapi->tx_ring;
692
693 if (txr->tx_desc_ring) {
694 pci_free_consistent(bp->pdev, TXBD_RING_SIZE,
695 txr->tx_desc_ring,
696 txr->tx_desc_mapping);
697 txr->tx_desc_ring = NULL;
698 }
699 kfree(txr->tx_buf_ring);
700 txr->tx_buf_ring = NULL;
701 }
702}
703
Michael Chanbb4f98a2008-06-19 16:38:19 -0700704static void
705bnx2_free_rx_mem(struct bnx2 *bp)
706{
707 int i;
708
709 for (i = 0; i < bp->num_rx_rings; i++) {
710 struct bnx2_napi *bnapi = &bp->bnx2_napi[i];
711 struct bnx2_rx_ring_info *rxr = &bnapi->rx_ring;
712 int j;
713
714 for (j = 0; j < bp->rx_max_ring; j++) {
715 if (rxr->rx_desc_ring[j])
716 pci_free_consistent(bp->pdev, RXBD_RING_SIZE,
717 rxr->rx_desc_ring[j],
718 rxr->rx_desc_mapping[j]);
719 rxr->rx_desc_ring[j] = NULL;
720 }
Breno Leitao25b0b992009-06-08 10:30:19 +0000721 vfree(rxr->rx_buf_ring);
Michael Chanbb4f98a2008-06-19 16:38:19 -0700722 rxr->rx_buf_ring = NULL;
723
724 for (j = 0; j < bp->rx_max_pg_ring; j++) {
725 if (rxr->rx_pg_desc_ring[j])
726 pci_free_consistent(bp->pdev, RXBD_RING_SIZE,
Michael Chan3298a732008-12-17 19:06:08 -0800727 rxr->rx_pg_desc_ring[j],
728 rxr->rx_pg_desc_mapping[j]);
729 rxr->rx_pg_desc_ring[j] = NULL;
Michael Chanbb4f98a2008-06-19 16:38:19 -0700730 }
Breno Leitao25b0b992009-06-08 10:30:19 +0000731 vfree(rxr->rx_pg_ring);
Michael Chanbb4f98a2008-06-19 16:38:19 -0700732 rxr->rx_pg_ring = NULL;
733 }
734}
735
Michael Chan35e90102008-06-19 16:37:42 -0700736static int
737bnx2_alloc_tx_mem(struct bnx2 *bp)
738{
739 int i;
740
741 for (i = 0; i < bp->num_tx_rings; i++) {
742 struct bnx2_napi *bnapi = &bp->bnx2_napi[i];
743 struct bnx2_tx_ring_info *txr = &bnapi->tx_ring;
744
745 txr->tx_buf_ring = kzalloc(SW_TXBD_RING_SIZE, GFP_KERNEL);
746 if (txr->tx_buf_ring == NULL)
747 return -ENOMEM;
748
749 txr->tx_desc_ring =
750 pci_alloc_consistent(bp->pdev, TXBD_RING_SIZE,
751 &txr->tx_desc_mapping);
752 if (txr->tx_desc_ring == NULL)
753 return -ENOMEM;
754 }
755 return 0;
756}
757
Michael Chanbb4f98a2008-06-19 16:38:19 -0700758static int
759bnx2_alloc_rx_mem(struct bnx2 *bp)
760{
761 int i;
762
763 for (i = 0; i < bp->num_rx_rings; i++) {
764 struct bnx2_napi *bnapi = &bp->bnx2_napi[i];
765 struct bnx2_rx_ring_info *rxr = &bnapi->rx_ring;
766 int j;
767
768 rxr->rx_buf_ring =
769 vmalloc(SW_RXBD_RING_SIZE * bp->rx_max_ring);
770 if (rxr->rx_buf_ring == NULL)
771 return -ENOMEM;
772
773 memset(rxr->rx_buf_ring, 0,
774 SW_RXBD_RING_SIZE * bp->rx_max_ring);
775
776 for (j = 0; j < bp->rx_max_ring; j++) {
777 rxr->rx_desc_ring[j] =
778 pci_alloc_consistent(bp->pdev, RXBD_RING_SIZE,
779 &rxr->rx_desc_mapping[j]);
780 if (rxr->rx_desc_ring[j] == NULL)
781 return -ENOMEM;
782
783 }
784
785 if (bp->rx_pg_ring_size) {
786 rxr->rx_pg_ring = vmalloc(SW_RXPG_RING_SIZE *
787 bp->rx_max_pg_ring);
788 if (rxr->rx_pg_ring == NULL)
789 return -ENOMEM;
790
791 memset(rxr->rx_pg_ring, 0, SW_RXPG_RING_SIZE *
792 bp->rx_max_pg_ring);
793 }
794
795 for (j = 0; j < bp->rx_max_pg_ring; j++) {
796 rxr->rx_pg_desc_ring[j] =
797 pci_alloc_consistent(bp->pdev, RXBD_RING_SIZE,
798 &rxr->rx_pg_desc_mapping[j]);
799 if (rxr->rx_pg_desc_ring[j] == NULL)
800 return -ENOMEM;
801
802 }
803 }
804 return 0;
805}
806
Michael Chan35e90102008-06-19 16:37:42 -0700807static void
Michael Chanb6016b72005-05-26 13:03:09 -0700808bnx2_free_mem(struct bnx2 *bp)
809{
Michael Chan13daffa2006-03-20 17:49:20 -0800810 int i;
Michael Chan43e80b82008-06-19 16:41:08 -0700811 struct bnx2_napi *bnapi = &bp->bnx2_napi[0];
Michael Chan13daffa2006-03-20 17:49:20 -0800812
Michael Chan35e90102008-06-19 16:37:42 -0700813 bnx2_free_tx_mem(bp);
Michael Chanbb4f98a2008-06-19 16:38:19 -0700814 bnx2_free_rx_mem(bp);
Michael Chan35e90102008-06-19 16:37:42 -0700815
Michael Chan59b47d82006-11-19 14:10:45 -0800816 for (i = 0; i < bp->ctx_pages; i++) {
817 if (bp->ctx_blk[i]) {
818 pci_free_consistent(bp->pdev, BCM_PAGE_SIZE,
819 bp->ctx_blk[i],
820 bp->ctx_blk_mapping[i]);
821 bp->ctx_blk[i] = NULL;
822 }
823 }
Michael Chan43e80b82008-06-19 16:41:08 -0700824 if (bnapi->status_blk.msi) {
Michael Chan0f31f992006-03-23 01:12:38 -0800825 pci_free_consistent(bp->pdev, bp->status_stats_size,
Michael Chan43e80b82008-06-19 16:41:08 -0700826 bnapi->status_blk.msi,
827 bp->status_blk_mapping);
828 bnapi->status_blk.msi = NULL;
Michael Chan0f31f992006-03-23 01:12:38 -0800829 bp->stats_blk = NULL;
Michael Chanb6016b72005-05-26 13:03:09 -0700830 }
Michael Chanb6016b72005-05-26 13:03:09 -0700831}
832
833static int
834bnx2_alloc_mem(struct bnx2 *bp)
835{
Michael Chan35e90102008-06-19 16:37:42 -0700836 int i, status_blk_size, err;
Michael Chan43e80b82008-06-19 16:41:08 -0700837 struct bnx2_napi *bnapi;
838 void *status_blk;
Michael Chanb6016b72005-05-26 13:03:09 -0700839
Michael Chan0f31f992006-03-23 01:12:38 -0800840 /* Combine status and statistics blocks into one allocation. */
841 status_blk_size = L1_CACHE_ALIGN(sizeof(struct status_block));
David S. Millerf86e82f2008-01-21 17:15:40 -0800842 if (bp->flags & BNX2_FLAG_MSIX_CAP)
Michael Chanb4b36042007-12-20 19:59:30 -0800843 status_blk_size = L1_CACHE_ALIGN(BNX2_MAX_MSIX_HW_VEC *
844 BNX2_SBLK_MSIX_ALIGN_SIZE);
Michael Chan0f31f992006-03-23 01:12:38 -0800845 bp->status_stats_size = status_blk_size +
846 sizeof(struct statistics_block);
847
Michael Chan43e80b82008-06-19 16:41:08 -0700848 status_blk = pci_alloc_consistent(bp->pdev, bp->status_stats_size,
849 &bp->status_blk_mapping);
850 if (status_blk == NULL)
Michael Chanb6016b72005-05-26 13:03:09 -0700851 goto alloc_mem_err;
852
Michael Chan43e80b82008-06-19 16:41:08 -0700853 memset(status_blk, 0, bp->status_stats_size);
Michael Chanb6016b72005-05-26 13:03:09 -0700854
Michael Chan43e80b82008-06-19 16:41:08 -0700855 bnapi = &bp->bnx2_napi[0];
856 bnapi->status_blk.msi = status_blk;
857 bnapi->hw_tx_cons_ptr =
858 &bnapi->status_blk.msi->status_tx_quick_consumer_index0;
859 bnapi->hw_rx_cons_ptr =
860 &bnapi->status_blk.msi->status_rx_quick_consumer_index0;
David S. Millerf86e82f2008-01-21 17:15:40 -0800861 if (bp->flags & BNX2_FLAG_MSIX_CAP) {
Michael Chanb4b36042007-12-20 19:59:30 -0800862 for (i = 1; i < BNX2_MAX_MSIX_VEC; i++) {
Michael Chan43e80b82008-06-19 16:41:08 -0700863 struct status_block_msix *sblk;
Michael Chanb4b36042007-12-20 19:59:30 -0800864
Michael Chan43e80b82008-06-19 16:41:08 -0700865 bnapi = &bp->bnx2_napi[i];
866
867 sblk = (void *) (status_blk +
868 BNX2_SBLK_MSIX_ALIGN_SIZE * i);
869 bnapi->status_blk.msix = sblk;
870 bnapi->hw_tx_cons_ptr =
871 &sblk->status_tx_quick_consumer_index;
872 bnapi->hw_rx_cons_ptr =
873 &sblk->status_rx_quick_consumer_index;
Michael Chanb4b36042007-12-20 19:59:30 -0800874 bnapi->int_num = i << 24;
875 }
876 }
Michael Chan35efa7c2007-12-20 19:56:37 -0800877
Michael Chan43e80b82008-06-19 16:41:08 -0700878 bp->stats_blk = status_blk + status_blk_size;
Michael Chanb6016b72005-05-26 13:03:09 -0700879
Michael Chan0f31f992006-03-23 01:12:38 -0800880 bp->stats_blk_mapping = bp->status_blk_mapping + status_blk_size;
Michael Chanb6016b72005-05-26 13:03:09 -0700881
Michael Chan59b47d82006-11-19 14:10:45 -0800882 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
883 bp->ctx_pages = 0x2000 / BCM_PAGE_SIZE;
884 if (bp->ctx_pages == 0)
885 bp->ctx_pages = 1;
886 for (i = 0; i < bp->ctx_pages; i++) {
887 bp->ctx_blk[i] = pci_alloc_consistent(bp->pdev,
888 BCM_PAGE_SIZE,
889 &bp->ctx_blk_mapping[i]);
890 if (bp->ctx_blk[i] == NULL)
891 goto alloc_mem_err;
892 }
893 }
Michael Chan35e90102008-06-19 16:37:42 -0700894
Michael Chanbb4f98a2008-06-19 16:38:19 -0700895 err = bnx2_alloc_rx_mem(bp);
896 if (err)
897 goto alloc_mem_err;
898
Michael Chan35e90102008-06-19 16:37:42 -0700899 err = bnx2_alloc_tx_mem(bp);
900 if (err)
901 goto alloc_mem_err;
902
Michael Chanb6016b72005-05-26 13:03:09 -0700903 return 0;
904
905alloc_mem_err:
906 bnx2_free_mem(bp);
907 return -ENOMEM;
908}
909
910static void
Michael Chane3648b32005-11-04 08:51:21 -0800911bnx2_report_fw_link(struct bnx2 *bp)
912{
913 u32 fw_link_status = 0;
914
Michael Chan583c28e2008-01-21 19:51:35 -0800915 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
Michael Chan0d8a6572007-07-07 22:49:43 -0700916 return;
917
Michael Chane3648b32005-11-04 08:51:21 -0800918 if (bp->link_up) {
919 u32 bmsr;
920
921 switch (bp->line_speed) {
922 case SPEED_10:
923 if (bp->duplex == DUPLEX_HALF)
924 fw_link_status = BNX2_LINK_STATUS_10HALF;
925 else
926 fw_link_status = BNX2_LINK_STATUS_10FULL;
927 break;
928 case SPEED_100:
929 if (bp->duplex == DUPLEX_HALF)
930 fw_link_status = BNX2_LINK_STATUS_100HALF;
931 else
932 fw_link_status = BNX2_LINK_STATUS_100FULL;
933 break;
934 case SPEED_1000:
935 if (bp->duplex == DUPLEX_HALF)
936 fw_link_status = BNX2_LINK_STATUS_1000HALF;
937 else
938 fw_link_status = BNX2_LINK_STATUS_1000FULL;
939 break;
940 case SPEED_2500:
941 if (bp->duplex == DUPLEX_HALF)
942 fw_link_status = BNX2_LINK_STATUS_2500HALF;
943 else
944 fw_link_status = BNX2_LINK_STATUS_2500FULL;
945 break;
946 }
947
948 fw_link_status |= BNX2_LINK_STATUS_LINK_UP;
949
950 if (bp->autoneg) {
951 fw_link_status |= BNX2_LINK_STATUS_AN_ENABLED;
952
Michael Chanca58c3a2007-05-03 13:22:52 -0700953 bnx2_read_phy(bp, bp->mii_bmsr, &bmsr);
954 bnx2_read_phy(bp, bp->mii_bmsr, &bmsr);
Michael Chane3648b32005-11-04 08:51:21 -0800955
956 if (!(bmsr & BMSR_ANEGCOMPLETE) ||
Michael Chan583c28e2008-01-21 19:51:35 -0800957 bp->phy_flags & BNX2_PHY_FLAG_PARALLEL_DETECT)
Michael Chane3648b32005-11-04 08:51:21 -0800958 fw_link_status |= BNX2_LINK_STATUS_PARALLEL_DET;
959 else
960 fw_link_status |= BNX2_LINK_STATUS_AN_COMPLETE;
961 }
962 }
963 else
964 fw_link_status = BNX2_LINK_STATUS_LINK_DOWN;
965
Michael Chan2726d6e2008-01-29 21:35:05 -0800966 bnx2_shmem_wr(bp, BNX2_LINK_STATUS, fw_link_status);
Michael Chane3648b32005-11-04 08:51:21 -0800967}
968
Michael Chan9b1084b2007-07-07 22:50:37 -0700969static char *
970bnx2_xceiver_str(struct bnx2 *bp)
971{
972 return ((bp->phy_port == PORT_FIBRE) ? "SerDes" :
Michael Chan583c28e2008-01-21 19:51:35 -0800973 ((bp->phy_flags & BNX2_PHY_FLAG_SERDES) ? "Remote Copper" :
Michael Chan9b1084b2007-07-07 22:50:37 -0700974 "Copper"));
975}
976
Michael Chane3648b32005-11-04 08:51:21 -0800977static void
Michael Chanb6016b72005-05-26 13:03:09 -0700978bnx2_report_link(struct bnx2 *bp)
979{
980 if (bp->link_up) {
981 netif_carrier_on(bp->dev);
Michael Chan9b1084b2007-07-07 22:50:37 -0700982 printk(KERN_INFO PFX "%s NIC %s Link is Up, ", bp->dev->name,
983 bnx2_xceiver_str(bp));
Michael Chanb6016b72005-05-26 13:03:09 -0700984
985 printk("%d Mbps ", bp->line_speed);
986
987 if (bp->duplex == DUPLEX_FULL)
988 printk("full duplex");
989 else
990 printk("half duplex");
991
992 if (bp->flow_ctrl) {
993 if (bp->flow_ctrl & FLOW_CTRL_RX) {
994 printk(", receive ");
995 if (bp->flow_ctrl & FLOW_CTRL_TX)
996 printk("& transmit ");
997 }
998 else {
999 printk(", transmit ");
1000 }
1001 printk("flow control ON");
1002 }
1003 printk("\n");
1004 }
1005 else {
1006 netif_carrier_off(bp->dev);
Michael Chan9b1084b2007-07-07 22:50:37 -07001007 printk(KERN_ERR PFX "%s NIC %s Link is Down\n", bp->dev->name,
1008 bnx2_xceiver_str(bp));
Michael Chanb6016b72005-05-26 13:03:09 -07001009 }
Michael Chane3648b32005-11-04 08:51:21 -08001010
1011 bnx2_report_fw_link(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07001012}
1013
1014static void
1015bnx2_resolve_flow_ctrl(struct bnx2 *bp)
1016{
1017 u32 local_adv, remote_adv;
1018
1019 bp->flow_ctrl = 0;
Jeff Garzik6aa20a22006-09-13 13:24:59 -04001020 if ((bp->autoneg & (AUTONEG_SPEED | AUTONEG_FLOW_CTRL)) !=
Michael Chanb6016b72005-05-26 13:03:09 -07001021 (AUTONEG_SPEED | AUTONEG_FLOW_CTRL)) {
1022
1023 if (bp->duplex == DUPLEX_FULL) {
1024 bp->flow_ctrl = bp->req_flow_ctrl;
1025 }
1026 return;
1027 }
1028
1029 if (bp->duplex != DUPLEX_FULL) {
1030 return;
1031 }
1032
Michael Chan583c28e2008-01-21 19:51:35 -08001033 if ((bp->phy_flags & BNX2_PHY_FLAG_SERDES) &&
Michael Chan5b0c76a2005-11-04 08:45:49 -08001034 (CHIP_NUM(bp) == CHIP_NUM_5708)) {
1035 u32 val;
1036
1037 bnx2_read_phy(bp, BCM5708S_1000X_STAT1, &val);
1038 if (val & BCM5708S_1000X_STAT1_TX_PAUSE)
1039 bp->flow_ctrl |= FLOW_CTRL_TX;
1040 if (val & BCM5708S_1000X_STAT1_RX_PAUSE)
1041 bp->flow_ctrl |= FLOW_CTRL_RX;
1042 return;
1043 }
1044
Michael Chanca58c3a2007-05-03 13:22:52 -07001045 bnx2_read_phy(bp, bp->mii_adv, &local_adv);
1046 bnx2_read_phy(bp, bp->mii_lpa, &remote_adv);
Michael Chanb6016b72005-05-26 13:03:09 -07001047
Michael Chan583c28e2008-01-21 19:51:35 -08001048 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Michael Chanb6016b72005-05-26 13:03:09 -07001049 u32 new_local_adv = 0;
1050 u32 new_remote_adv = 0;
1051
1052 if (local_adv & ADVERTISE_1000XPAUSE)
1053 new_local_adv |= ADVERTISE_PAUSE_CAP;
1054 if (local_adv & ADVERTISE_1000XPSE_ASYM)
1055 new_local_adv |= ADVERTISE_PAUSE_ASYM;
1056 if (remote_adv & ADVERTISE_1000XPAUSE)
1057 new_remote_adv |= ADVERTISE_PAUSE_CAP;
1058 if (remote_adv & ADVERTISE_1000XPSE_ASYM)
1059 new_remote_adv |= ADVERTISE_PAUSE_ASYM;
1060
1061 local_adv = new_local_adv;
1062 remote_adv = new_remote_adv;
1063 }
1064
1065 /* See Table 28B-3 of 802.3ab-1999 spec. */
1066 if (local_adv & ADVERTISE_PAUSE_CAP) {
1067 if(local_adv & ADVERTISE_PAUSE_ASYM) {
1068 if (remote_adv & ADVERTISE_PAUSE_CAP) {
1069 bp->flow_ctrl = FLOW_CTRL_TX | FLOW_CTRL_RX;
1070 }
1071 else if (remote_adv & ADVERTISE_PAUSE_ASYM) {
1072 bp->flow_ctrl = FLOW_CTRL_RX;
1073 }
1074 }
1075 else {
1076 if (remote_adv & ADVERTISE_PAUSE_CAP) {
1077 bp->flow_ctrl = FLOW_CTRL_TX | FLOW_CTRL_RX;
1078 }
1079 }
1080 }
1081 else if (local_adv & ADVERTISE_PAUSE_ASYM) {
1082 if ((remote_adv & ADVERTISE_PAUSE_CAP) &&
1083 (remote_adv & ADVERTISE_PAUSE_ASYM)) {
1084
1085 bp->flow_ctrl = FLOW_CTRL_TX;
1086 }
1087 }
1088}
1089
1090static int
Michael Chan27a005b2007-05-03 13:23:41 -07001091bnx2_5709s_linkup(struct bnx2 *bp)
1092{
1093 u32 val, speed;
1094
1095 bp->link_up = 1;
1096
1097 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_GP_STATUS);
1098 bnx2_read_phy(bp, MII_BNX2_GP_TOP_AN_STATUS1, &val);
1099 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
1100
1101 if ((bp->autoneg & AUTONEG_SPEED) == 0) {
1102 bp->line_speed = bp->req_line_speed;
1103 bp->duplex = bp->req_duplex;
1104 return 0;
1105 }
1106 speed = val & MII_BNX2_GP_TOP_AN_SPEED_MSK;
1107 switch (speed) {
1108 case MII_BNX2_GP_TOP_AN_SPEED_10:
1109 bp->line_speed = SPEED_10;
1110 break;
1111 case MII_BNX2_GP_TOP_AN_SPEED_100:
1112 bp->line_speed = SPEED_100;
1113 break;
1114 case MII_BNX2_GP_TOP_AN_SPEED_1G:
1115 case MII_BNX2_GP_TOP_AN_SPEED_1GKV:
1116 bp->line_speed = SPEED_1000;
1117 break;
1118 case MII_BNX2_GP_TOP_AN_SPEED_2_5G:
1119 bp->line_speed = SPEED_2500;
1120 break;
1121 }
1122 if (val & MII_BNX2_GP_TOP_AN_FD)
1123 bp->duplex = DUPLEX_FULL;
1124 else
1125 bp->duplex = DUPLEX_HALF;
1126 return 0;
1127}
1128
1129static int
Michael Chan5b0c76a2005-11-04 08:45:49 -08001130bnx2_5708s_linkup(struct bnx2 *bp)
1131{
1132 u32 val;
1133
1134 bp->link_up = 1;
1135 bnx2_read_phy(bp, BCM5708S_1000X_STAT1, &val);
1136 switch (val & BCM5708S_1000X_STAT1_SPEED_MASK) {
1137 case BCM5708S_1000X_STAT1_SPEED_10:
1138 bp->line_speed = SPEED_10;
1139 break;
1140 case BCM5708S_1000X_STAT1_SPEED_100:
1141 bp->line_speed = SPEED_100;
1142 break;
1143 case BCM5708S_1000X_STAT1_SPEED_1G:
1144 bp->line_speed = SPEED_1000;
1145 break;
1146 case BCM5708S_1000X_STAT1_SPEED_2G5:
1147 bp->line_speed = SPEED_2500;
1148 break;
1149 }
1150 if (val & BCM5708S_1000X_STAT1_FD)
1151 bp->duplex = DUPLEX_FULL;
1152 else
1153 bp->duplex = DUPLEX_HALF;
1154
1155 return 0;
1156}
1157
1158static int
1159bnx2_5706s_linkup(struct bnx2 *bp)
Michael Chanb6016b72005-05-26 13:03:09 -07001160{
1161 u32 bmcr, local_adv, remote_adv, common;
1162
1163 bp->link_up = 1;
1164 bp->line_speed = SPEED_1000;
1165
Michael Chanca58c3a2007-05-03 13:22:52 -07001166 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chanb6016b72005-05-26 13:03:09 -07001167 if (bmcr & BMCR_FULLDPLX) {
1168 bp->duplex = DUPLEX_FULL;
1169 }
1170 else {
1171 bp->duplex = DUPLEX_HALF;
1172 }
1173
1174 if (!(bmcr & BMCR_ANENABLE)) {
1175 return 0;
1176 }
1177
Michael Chanca58c3a2007-05-03 13:22:52 -07001178 bnx2_read_phy(bp, bp->mii_adv, &local_adv);
1179 bnx2_read_phy(bp, bp->mii_lpa, &remote_adv);
Michael Chanb6016b72005-05-26 13:03:09 -07001180
1181 common = local_adv & remote_adv;
1182 if (common & (ADVERTISE_1000XHALF | ADVERTISE_1000XFULL)) {
1183
1184 if (common & ADVERTISE_1000XFULL) {
1185 bp->duplex = DUPLEX_FULL;
1186 }
1187 else {
1188 bp->duplex = DUPLEX_HALF;
1189 }
1190 }
1191
1192 return 0;
1193}
1194
1195static int
1196bnx2_copper_linkup(struct bnx2 *bp)
1197{
1198 u32 bmcr;
1199
Michael Chanca58c3a2007-05-03 13:22:52 -07001200 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chanb6016b72005-05-26 13:03:09 -07001201 if (bmcr & BMCR_ANENABLE) {
1202 u32 local_adv, remote_adv, common;
1203
1204 bnx2_read_phy(bp, MII_CTRL1000, &local_adv);
1205 bnx2_read_phy(bp, MII_STAT1000, &remote_adv);
1206
1207 common = local_adv & (remote_adv >> 2);
1208 if (common & ADVERTISE_1000FULL) {
1209 bp->line_speed = SPEED_1000;
1210 bp->duplex = DUPLEX_FULL;
1211 }
1212 else if (common & ADVERTISE_1000HALF) {
1213 bp->line_speed = SPEED_1000;
1214 bp->duplex = DUPLEX_HALF;
1215 }
1216 else {
Michael Chanca58c3a2007-05-03 13:22:52 -07001217 bnx2_read_phy(bp, bp->mii_adv, &local_adv);
1218 bnx2_read_phy(bp, bp->mii_lpa, &remote_adv);
Michael Chanb6016b72005-05-26 13:03:09 -07001219
1220 common = local_adv & remote_adv;
1221 if (common & ADVERTISE_100FULL) {
1222 bp->line_speed = SPEED_100;
1223 bp->duplex = DUPLEX_FULL;
1224 }
1225 else if (common & ADVERTISE_100HALF) {
1226 bp->line_speed = SPEED_100;
1227 bp->duplex = DUPLEX_HALF;
1228 }
1229 else if (common & ADVERTISE_10FULL) {
1230 bp->line_speed = SPEED_10;
1231 bp->duplex = DUPLEX_FULL;
1232 }
1233 else if (common & ADVERTISE_10HALF) {
1234 bp->line_speed = SPEED_10;
1235 bp->duplex = DUPLEX_HALF;
1236 }
1237 else {
1238 bp->line_speed = 0;
1239 bp->link_up = 0;
1240 }
1241 }
1242 }
1243 else {
1244 if (bmcr & BMCR_SPEED100) {
1245 bp->line_speed = SPEED_100;
1246 }
1247 else {
1248 bp->line_speed = SPEED_10;
1249 }
1250 if (bmcr & BMCR_FULLDPLX) {
1251 bp->duplex = DUPLEX_FULL;
1252 }
1253 else {
1254 bp->duplex = DUPLEX_HALF;
1255 }
1256 }
1257
1258 return 0;
1259}
1260
Michael Chan83e3fc82008-01-29 21:37:17 -08001261static void
Michael Chanbb4f98a2008-06-19 16:38:19 -07001262bnx2_init_rx_context(struct bnx2 *bp, u32 cid)
Michael Chan83e3fc82008-01-29 21:37:17 -08001263{
Michael Chanbb4f98a2008-06-19 16:38:19 -07001264 u32 val, rx_cid_addr = GET_CID_ADDR(cid);
Michael Chan83e3fc82008-01-29 21:37:17 -08001265
1266 val = BNX2_L2CTX_CTX_TYPE_CTX_BD_CHN_TYPE_VALUE;
1267 val |= BNX2_L2CTX_CTX_TYPE_SIZE_L2;
1268 val |= 0x02 << 8;
1269
1270 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
1271 u32 lo_water, hi_water;
1272
1273 if (bp->flow_ctrl & FLOW_CTRL_TX)
1274 lo_water = BNX2_L2CTX_LO_WATER_MARK_DEFAULT;
1275 else
1276 lo_water = BNX2_L2CTX_LO_WATER_MARK_DIS;
1277 if (lo_water >= bp->rx_ring_size)
1278 lo_water = 0;
1279
Michael Chan57260262010-02-15 19:42:09 +00001280 hi_water = min_t(int, bp->rx_ring_size / 4, lo_water + 16);
Michael Chan83e3fc82008-01-29 21:37:17 -08001281
1282 if (hi_water <= lo_water)
1283 lo_water = 0;
1284
1285 hi_water /= BNX2_L2CTX_HI_WATER_MARK_SCALE;
1286 lo_water /= BNX2_L2CTX_LO_WATER_MARK_SCALE;
1287
1288 if (hi_water > 0xf)
1289 hi_water = 0xf;
1290 else if (hi_water == 0)
1291 lo_water = 0;
1292 val |= lo_water | (hi_water << BNX2_L2CTX_HI_WATER_MARK_SHIFT);
1293 }
1294 bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_CTX_TYPE, val);
1295}
1296
Michael Chanbb4f98a2008-06-19 16:38:19 -07001297static void
1298bnx2_init_all_rx_contexts(struct bnx2 *bp)
1299{
1300 int i;
1301 u32 cid;
1302
1303 for (i = 0, cid = RX_CID; i < bp->num_rx_rings; i++, cid++) {
1304 if (i == 1)
1305 cid = RX_RSS_CID;
1306 bnx2_init_rx_context(bp, cid);
1307 }
1308}
1309
Benjamin Li344478d2008-09-18 16:38:24 -07001310static void
Michael Chanb6016b72005-05-26 13:03:09 -07001311bnx2_set_mac_link(struct bnx2 *bp)
1312{
1313 u32 val;
1314
1315 REG_WR(bp, BNX2_EMAC_TX_LENGTHS, 0x2620);
1316 if (bp->link_up && (bp->line_speed == SPEED_1000) &&
1317 (bp->duplex == DUPLEX_HALF)) {
1318 REG_WR(bp, BNX2_EMAC_TX_LENGTHS, 0x26ff);
1319 }
1320
1321 /* Configure the EMAC mode register. */
1322 val = REG_RD(bp, BNX2_EMAC_MODE);
1323
1324 val &= ~(BNX2_EMAC_MODE_PORT | BNX2_EMAC_MODE_HALF_DUPLEX |
Michael Chan5b0c76a2005-11-04 08:45:49 -08001325 BNX2_EMAC_MODE_MAC_LOOP | BNX2_EMAC_MODE_FORCE_LINK |
Michael Chan59b47d82006-11-19 14:10:45 -08001326 BNX2_EMAC_MODE_25G_MODE);
Michael Chanb6016b72005-05-26 13:03:09 -07001327
1328 if (bp->link_up) {
Michael Chan5b0c76a2005-11-04 08:45:49 -08001329 switch (bp->line_speed) {
1330 case SPEED_10:
Michael Chan59b47d82006-11-19 14:10:45 -08001331 if (CHIP_NUM(bp) != CHIP_NUM_5706) {
1332 val |= BNX2_EMAC_MODE_PORT_MII_10M;
Michael Chan5b0c76a2005-11-04 08:45:49 -08001333 break;
1334 }
1335 /* fall through */
1336 case SPEED_100:
1337 val |= BNX2_EMAC_MODE_PORT_MII;
1338 break;
1339 case SPEED_2500:
Michael Chan59b47d82006-11-19 14:10:45 -08001340 val |= BNX2_EMAC_MODE_25G_MODE;
Michael Chan5b0c76a2005-11-04 08:45:49 -08001341 /* fall through */
1342 case SPEED_1000:
1343 val |= BNX2_EMAC_MODE_PORT_GMII;
1344 break;
1345 }
Michael Chanb6016b72005-05-26 13:03:09 -07001346 }
1347 else {
1348 val |= BNX2_EMAC_MODE_PORT_GMII;
1349 }
1350
1351 /* Set the MAC to operate in the appropriate duplex mode. */
1352 if (bp->duplex == DUPLEX_HALF)
1353 val |= BNX2_EMAC_MODE_HALF_DUPLEX;
1354 REG_WR(bp, BNX2_EMAC_MODE, val);
1355
1356 /* Enable/disable rx PAUSE. */
1357 bp->rx_mode &= ~BNX2_EMAC_RX_MODE_FLOW_EN;
1358
1359 if (bp->flow_ctrl & FLOW_CTRL_RX)
1360 bp->rx_mode |= BNX2_EMAC_RX_MODE_FLOW_EN;
1361 REG_WR(bp, BNX2_EMAC_RX_MODE, bp->rx_mode);
1362
1363 /* Enable/disable tx PAUSE. */
1364 val = REG_RD(bp, BNX2_EMAC_TX_MODE);
1365 val &= ~BNX2_EMAC_TX_MODE_FLOW_EN;
1366
1367 if (bp->flow_ctrl & FLOW_CTRL_TX)
1368 val |= BNX2_EMAC_TX_MODE_FLOW_EN;
1369 REG_WR(bp, BNX2_EMAC_TX_MODE, val);
1370
1371 /* Acknowledge the interrupt. */
1372 REG_WR(bp, BNX2_EMAC_STATUS, BNX2_EMAC_STATUS_LINK_CHANGE);
1373
Michael Chan83e3fc82008-01-29 21:37:17 -08001374 if (CHIP_NUM(bp) == CHIP_NUM_5709)
Michael Chanbb4f98a2008-06-19 16:38:19 -07001375 bnx2_init_all_rx_contexts(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07001376}
1377
Michael Chan27a005b2007-05-03 13:23:41 -07001378static void
1379bnx2_enable_bmsr1(struct bnx2 *bp)
1380{
Michael Chan583c28e2008-01-21 19:51:35 -08001381 if ((bp->phy_flags & BNX2_PHY_FLAG_SERDES) &&
Michael Chan27a005b2007-05-03 13:23:41 -07001382 (CHIP_NUM(bp) == CHIP_NUM_5709))
1383 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
1384 MII_BNX2_BLK_ADDR_GP_STATUS);
1385}
1386
1387static void
1388bnx2_disable_bmsr1(struct bnx2 *bp)
1389{
Michael Chan583c28e2008-01-21 19:51:35 -08001390 if ((bp->phy_flags & BNX2_PHY_FLAG_SERDES) &&
Michael Chan27a005b2007-05-03 13:23:41 -07001391 (CHIP_NUM(bp) == CHIP_NUM_5709))
1392 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
1393 MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
1394}
1395
Michael Chanb6016b72005-05-26 13:03:09 -07001396static int
Michael Chan605a9e22007-05-03 13:23:13 -07001397bnx2_test_and_enable_2g5(struct bnx2 *bp)
1398{
1399 u32 up1;
1400 int ret = 1;
1401
Michael Chan583c28e2008-01-21 19:51:35 -08001402 if (!(bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE))
Michael Chan605a9e22007-05-03 13:23:13 -07001403 return 0;
1404
1405 if (bp->autoneg & AUTONEG_SPEED)
1406 bp->advertising |= ADVERTISED_2500baseX_Full;
1407
Michael Chan27a005b2007-05-03 13:23:41 -07001408 if (CHIP_NUM(bp) == CHIP_NUM_5709)
1409 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_OVER1G);
1410
Michael Chan605a9e22007-05-03 13:23:13 -07001411 bnx2_read_phy(bp, bp->mii_up1, &up1);
1412 if (!(up1 & BCM5708S_UP1_2G5)) {
1413 up1 |= BCM5708S_UP1_2G5;
1414 bnx2_write_phy(bp, bp->mii_up1, up1);
1415 ret = 0;
1416 }
1417
Michael Chan27a005b2007-05-03 13:23:41 -07001418 if (CHIP_NUM(bp) == CHIP_NUM_5709)
1419 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
1420 MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
1421
Michael Chan605a9e22007-05-03 13:23:13 -07001422 return ret;
1423}
1424
1425static int
1426bnx2_test_and_disable_2g5(struct bnx2 *bp)
1427{
1428 u32 up1;
1429 int ret = 0;
1430
Michael Chan583c28e2008-01-21 19:51:35 -08001431 if (!(bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE))
Michael Chan605a9e22007-05-03 13:23:13 -07001432 return 0;
1433
Michael Chan27a005b2007-05-03 13:23:41 -07001434 if (CHIP_NUM(bp) == CHIP_NUM_5709)
1435 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_OVER1G);
1436
Michael Chan605a9e22007-05-03 13:23:13 -07001437 bnx2_read_phy(bp, bp->mii_up1, &up1);
1438 if (up1 & BCM5708S_UP1_2G5) {
1439 up1 &= ~BCM5708S_UP1_2G5;
1440 bnx2_write_phy(bp, bp->mii_up1, up1);
1441 ret = 1;
1442 }
1443
Michael Chan27a005b2007-05-03 13:23:41 -07001444 if (CHIP_NUM(bp) == CHIP_NUM_5709)
1445 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
1446 MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
1447
Michael Chan605a9e22007-05-03 13:23:13 -07001448 return ret;
1449}
1450
1451static void
1452bnx2_enable_forced_2g5(struct bnx2 *bp)
1453{
1454 u32 bmcr;
1455
Michael Chan583c28e2008-01-21 19:51:35 -08001456 if (!(bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE))
Michael Chan605a9e22007-05-03 13:23:13 -07001457 return;
1458
Michael Chan27a005b2007-05-03 13:23:41 -07001459 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
1460 u32 val;
1461
1462 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
1463 MII_BNX2_BLK_ADDR_SERDES_DIG);
1464 bnx2_read_phy(bp, MII_BNX2_SERDES_DIG_MISC1, &val);
1465 val &= ~MII_BNX2_SD_MISC1_FORCE_MSK;
1466 val |= MII_BNX2_SD_MISC1_FORCE | MII_BNX2_SD_MISC1_FORCE_2_5G;
1467 bnx2_write_phy(bp, MII_BNX2_SERDES_DIG_MISC1, val);
1468
1469 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
1470 MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
1471 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
1472
1473 } else if (CHIP_NUM(bp) == CHIP_NUM_5708) {
Michael Chan605a9e22007-05-03 13:23:13 -07001474 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
1475 bmcr |= BCM5708S_BMCR_FORCE_2500;
Eric Dumazetc7079852009-11-02 23:17:42 +00001476 } else {
1477 return;
Michael Chan605a9e22007-05-03 13:23:13 -07001478 }
1479
1480 if (bp->autoneg & AUTONEG_SPEED) {
1481 bmcr &= ~BMCR_ANENABLE;
1482 if (bp->req_duplex == DUPLEX_FULL)
1483 bmcr |= BMCR_FULLDPLX;
1484 }
1485 bnx2_write_phy(bp, bp->mii_bmcr, bmcr);
1486}
1487
1488static void
1489bnx2_disable_forced_2g5(struct bnx2 *bp)
1490{
1491 u32 bmcr;
1492
Michael Chan583c28e2008-01-21 19:51:35 -08001493 if (!(bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE))
Michael Chan605a9e22007-05-03 13:23:13 -07001494 return;
1495
Michael Chan27a005b2007-05-03 13:23:41 -07001496 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
1497 u32 val;
1498
1499 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
1500 MII_BNX2_BLK_ADDR_SERDES_DIG);
1501 bnx2_read_phy(bp, MII_BNX2_SERDES_DIG_MISC1, &val);
1502 val &= ~MII_BNX2_SD_MISC1_FORCE;
1503 bnx2_write_phy(bp, MII_BNX2_SERDES_DIG_MISC1, val);
1504
1505 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
1506 MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
1507 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
1508
1509 } else if (CHIP_NUM(bp) == CHIP_NUM_5708) {
Michael Chan605a9e22007-05-03 13:23:13 -07001510 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
1511 bmcr &= ~BCM5708S_BMCR_FORCE_2500;
Eric Dumazetc7079852009-11-02 23:17:42 +00001512 } else {
1513 return;
Michael Chan605a9e22007-05-03 13:23:13 -07001514 }
1515
1516 if (bp->autoneg & AUTONEG_SPEED)
1517 bmcr |= BMCR_SPEED1000 | BMCR_ANENABLE | BMCR_ANRESTART;
1518 bnx2_write_phy(bp, bp->mii_bmcr, bmcr);
1519}
1520
Michael Chanb2fadea2008-01-21 17:07:06 -08001521static void
1522bnx2_5706s_force_link_dn(struct bnx2 *bp, int start)
1523{
1524 u32 val;
1525
1526 bnx2_write_phy(bp, MII_BNX2_DSP_ADDRESS, MII_EXPAND_SERDES_CTL);
1527 bnx2_read_phy(bp, MII_BNX2_DSP_RW_PORT, &val);
1528 if (start)
1529 bnx2_write_phy(bp, MII_BNX2_DSP_RW_PORT, val & 0xff0f);
1530 else
1531 bnx2_write_phy(bp, MII_BNX2_DSP_RW_PORT, val | 0xc0);
1532}
1533
Michael Chan605a9e22007-05-03 13:23:13 -07001534static int
Michael Chanb6016b72005-05-26 13:03:09 -07001535bnx2_set_link(struct bnx2 *bp)
1536{
1537 u32 bmsr;
1538 u8 link_up;
1539
Michael Chan80be4432006-11-19 14:07:28 -08001540 if (bp->loopback == MAC_LOOPBACK || bp->loopback == PHY_LOOPBACK) {
Michael Chanb6016b72005-05-26 13:03:09 -07001541 bp->link_up = 1;
1542 return 0;
1543 }
1544
Michael Chan583c28e2008-01-21 19:51:35 -08001545 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
Michael Chan0d8a6572007-07-07 22:49:43 -07001546 return 0;
1547
Michael Chanb6016b72005-05-26 13:03:09 -07001548 link_up = bp->link_up;
1549
Michael Chan27a005b2007-05-03 13:23:41 -07001550 bnx2_enable_bmsr1(bp);
1551 bnx2_read_phy(bp, bp->mii_bmsr1, &bmsr);
1552 bnx2_read_phy(bp, bp->mii_bmsr1, &bmsr);
1553 bnx2_disable_bmsr1(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07001554
Michael Chan583c28e2008-01-21 19:51:35 -08001555 if ((bp->phy_flags & BNX2_PHY_FLAG_SERDES) &&
Michael Chanb6016b72005-05-26 13:03:09 -07001556 (CHIP_NUM(bp) == CHIP_NUM_5706)) {
Michael Chana2724e22008-02-23 19:47:44 -08001557 u32 val, an_dbg;
Michael Chanb6016b72005-05-26 13:03:09 -07001558
Michael Chan583c28e2008-01-21 19:51:35 -08001559 if (bp->phy_flags & BNX2_PHY_FLAG_FORCED_DOWN) {
Michael Chanb2fadea2008-01-21 17:07:06 -08001560 bnx2_5706s_force_link_dn(bp, 0);
Michael Chan583c28e2008-01-21 19:51:35 -08001561 bp->phy_flags &= ~BNX2_PHY_FLAG_FORCED_DOWN;
Michael Chanb2fadea2008-01-21 17:07:06 -08001562 }
Michael Chanb6016b72005-05-26 13:03:09 -07001563 val = REG_RD(bp, BNX2_EMAC_STATUS);
Michael Chana2724e22008-02-23 19:47:44 -08001564
1565 bnx2_write_phy(bp, MII_BNX2_MISC_SHADOW, MISC_SHDW_AN_DBG);
1566 bnx2_read_phy(bp, MII_BNX2_MISC_SHADOW, &an_dbg);
1567 bnx2_read_phy(bp, MII_BNX2_MISC_SHADOW, &an_dbg);
1568
1569 if ((val & BNX2_EMAC_STATUS_LINK) &&
1570 !(an_dbg & MISC_SHDW_AN_DBG_NOSYNC))
Michael Chanb6016b72005-05-26 13:03:09 -07001571 bmsr |= BMSR_LSTATUS;
1572 else
1573 bmsr &= ~BMSR_LSTATUS;
1574 }
1575
1576 if (bmsr & BMSR_LSTATUS) {
1577 bp->link_up = 1;
1578
Michael Chan583c28e2008-01-21 19:51:35 -08001579 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Michael Chan5b0c76a2005-11-04 08:45:49 -08001580 if (CHIP_NUM(bp) == CHIP_NUM_5706)
1581 bnx2_5706s_linkup(bp);
1582 else if (CHIP_NUM(bp) == CHIP_NUM_5708)
1583 bnx2_5708s_linkup(bp);
Michael Chan27a005b2007-05-03 13:23:41 -07001584 else if (CHIP_NUM(bp) == CHIP_NUM_5709)
1585 bnx2_5709s_linkup(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07001586 }
1587 else {
1588 bnx2_copper_linkup(bp);
1589 }
1590 bnx2_resolve_flow_ctrl(bp);
1591 }
1592 else {
Michael Chan583c28e2008-01-21 19:51:35 -08001593 if ((bp->phy_flags & BNX2_PHY_FLAG_SERDES) &&
Michael Chan605a9e22007-05-03 13:23:13 -07001594 (bp->autoneg & AUTONEG_SPEED))
1595 bnx2_disable_forced_2g5(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07001596
Michael Chan583c28e2008-01-21 19:51:35 -08001597 if (bp->phy_flags & BNX2_PHY_FLAG_PARALLEL_DETECT) {
Michael Chanb2fadea2008-01-21 17:07:06 -08001598 u32 bmcr;
1599
1600 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
1601 bmcr |= BMCR_ANENABLE;
1602 bnx2_write_phy(bp, bp->mii_bmcr, bmcr);
1603
Michael Chan583c28e2008-01-21 19:51:35 -08001604 bp->phy_flags &= ~BNX2_PHY_FLAG_PARALLEL_DETECT;
Michael Chanb2fadea2008-01-21 17:07:06 -08001605 }
Michael Chanb6016b72005-05-26 13:03:09 -07001606 bp->link_up = 0;
1607 }
1608
1609 if (bp->link_up != link_up) {
1610 bnx2_report_link(bp);
1611 }
1612
1613 bnx2_set_mac_link(bp);
1614
1615 return 0;
1616}
1617
1618static int
1619bnx2_reset_phy(struct bnx2 *bp)
1620{
1621 int i;
1622 u32 reg;
1623
Michael Chanca58c3a2007-05-03 13:22:52 -07001624 bnx2_write_phy(bp, bp->mii_bmcr, BMCR_RESET);
Michael Chanb6016b72005-05-26 13:03:09 -07001625
1626#define PHY_RESET_MAX_WAIT 100
1627 for (i = 0; i < PHY_RESET_MAX_WAIT; i++) {
1628 udelay(10);
1629
Michael Chanca58c3a2007-05-03 13:22:52 -07001630 bnx2_read_phy(bp, bp->mii_bmcr, &reg);
Michael Chanb6016b72005-05-26 13:03:09 -07001631 if (!(reg & BMCR_RESET)) {
1632 udelay(20);
1633 break;
1634 }
1635 }
1636 if (i == PHY_RESET_MAX_WAIT) {
1637 return -EBUSY;
1638 }
1639 return 0;
1640}
1641
1642static u32
1643bnx2_phy_get_pause_adv(struct bnx2 *bp)
1644{
1645 u32 adv = 0;
1646
1647 if ((bp->req_flow_ctrl & (FLOW_CTRL_RX | FLOW_CTRL_TX)) ==
1648 (FLOW_CTRL_RX | FLOW_CTRL_TX)) {
1649
Michael Chan583c28e2008-01-21 19:51:35 -08001650 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Michael Chanb6016b72005-05-26 13:03:09 -07001651 adv = ADVERTISE_1000XPAUSE;
1652 }
1653 else {
1654 adv = ADVERTISE_PAUSE_CAP;
1655 }
1656 }
1657 else if (bp->req_flow_ctrl & FLOW_CTRL_TX) {
Michael Chan583c28e2008-01-21 19:51:35 -08001658 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Michael Chanb6016b72005-05-26 13:03:09 -07001659 adv = ADVERTISE_1000XPSE_ASYM;
1660 }
1661 else {
1662 adv = ADVERTISE_PAUSE_ASYM;
1663 }
1664 }
1665 else if (bp->req_flow_ctrl & FLOW_CTRL_RX) {
Michael Chan583c28e2008-01-21 19:51:35 -08001666 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Michael Chanb6016b72005-05-26 13:03:09 -07001667 adv = ADVERTISE_1000XPAUSE | ADVERTISE_1000XPSE_ASYM;
1668 }
1669 else {
1670 adv = ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM;
1671 }
1672 }
1673 return adv;
1674}
1675
Michael Chana2f13892008-07-14 22:38:23 -07001676static int bnx2_fw_sync(struct bnx2 *, u32, int, int);
Michael Chan0d8a6572007-07-07 22:49:43 -07001677
Michael Chanb6016b72005-05-26 13:03:09 -07001678static int
Michael Chan0d8a6572007-07-07 22:49:43 -07001679bnx2_setup_remote_phy(struct bnx2 *bp, u8 port)
Harvey Harrison52d07b12009-01-19 17:27:06 -08001680__releases(&bp->phy_lock)
1681__acquires(&bp->phy_lock)
Michael Chan0d8a6572007-07-07 22:49:43 -07001682{
1683 u32 speed_arg = 0, pause_adv;
1684
1685 pause_adv = bnx2_phy_get_pause_adv(bp);
1686
1687 if (bp->autoneg & AUTONEG_SPEED) {
1688 speed_arg |= BNX2_NETLINK_SET_LINK_ENABLE_AUTONEG;
1689 if (bp->advertising & ADVERTISED_10baseT_Half)
1690 speed_arg |= BNX2_NETLINK_SET_LINK_SPEED_10HALF;
1691 if (bp->advertising & ADVERTISED_10baseT_Full)
1692 speed_arg |= BNX2_NETLINK_SET_LINK_SPEED_10FULL;
1693 if (bp->advertising & ADVERTISED_100baseT_Half)
1694 speed_arg |= BNX2_NETLINK_SET_LINK_SPEED_100HALF;
1695 if (bp->advertising & ADVERTISED_100baseT_Full)
1696 speed_arg |= BNX2_NETLINK_SET_LINK_SPEED_100FULL;
1697 if (bp->advertising & ADVERTISED_1000baseT_Full)
1698 speed_arg |= BNX2_NETLINK_SET_LINK_SPEED_1GFULL;
1699 if (bp->advertising & ADVERTISED_2500baseX_Full)
1700 speed_arg |= BNX2_NETLINK_SET_LINK_SPEED_2G5FULL;
1701 } else {
1702 if (bp->req_line_speed == SPEED_2500)
1703 speed_arg = BNX2_NETLINK_SET_LINK_SPEED_2G5FULL;
1704 else if (bp->req_line_speed == SPEED_1000)
1705 speed_arg = BNX2_NETLINK_SET_LINK_SPEED_1GFULL;
1706 else if (bp->req_line_speed == SPEED_100) {
1707 if (bp->req_duplex == DUPLEX_FULL)
1708 speed_arg = BNX2_NETLINK_SET_LINK_SPEED_100FULL;
1709 else
1710 speed_arg = BNX2_NETLINK_SET_LINK_SPEED_100HALF;
1711 } else if (bp->req_line_speed == SPEED_10) {
1712 if (bp->req_duplex == DUPLEX_FULL)
1713 speed_arg = BNX2_NETLINK_SET_LINK_SPEED_10FULL;
1714 else
1715 speed_arg = BNX2_NETLINK_SET_LINK_SPEED_10HALF;
1716 }
1717 }
1718
1719 if (pause_adv & (ADVERTISE_1000XPAUSE | ADVERTISE_PAUSE_CAP))
1720 speed_arg |= BNX2_NETLINK_SET_LINK_FC_SYM_PAUSE;
Michael Chanc26736e2008-01-31 17:07:21 -08001721 if (pause_adv & (ADVERTISE_1000XPSE_ASYM | ADVERTISE_PAUSE_ASYM))
Michael Chan0d8a6572007-07-07 22:49:43 -07001722 speed_arg |= BNX2_NETLINK_SET_LINK_FC_ASYM_PAUSE;
1723
1724 if (port == PORT_TP)
1725 speed_arg |= BNX2_NETLINK_SET_LINK_PHY_APP_REMOTE |
1726 BNX2_NETLINK_SET_LINK_ETH_AT_WIRESPEED;
1727
Michael Chan2726d6e2008-01-29 21:35:05 -08001728 bnx2_shmem_wr(bp, BNX2_DRV_MB_ARG0, speed_arg);
Michael Chan0d8a6572007-07-07 22:49:43 -07001729
1730 spin_unlock_bh(&bp->phy_lock);
Michael Chana2f13892008-07-14 22:38:23 -07001731 bnx2_fw_sync(bp, BNX2_DRV_MSG_CODE_CMD_SET_LINK, 1, 0);
Michael Chan0d8a6572007-07-07 22:49:43 -07001732 spin_lock_bh(&bp->phy_lock);
1733
1734 return 0;
1735}
1736
1737static int
1738bnx2_setup_serdes_phy(struct bnx2 *bp, u8 port)
Harvey Harrison52d07b12009-01-19 17:27:06 -08001739__releases(&bp->phy_lock)
1740__acquires(&bp->phy_lock)
Michael Chanb6016b72005-05-26 13:03:09 -07001741{
Michael Chan605a9e22007-05-03 13:23:13 -07001742 u32 adv, bmcr;
Michael Chanb6016b72005-05-26 13:03:09 -07001743 u32 new_adv = 0;
1744
Michael Chan583c28e2008-01-21 19:51:35 -08001745 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
Michael Chan0d8a6572007-07-07 22:49:43 -07001746 return (bnx2_setup_remote_phy(bp, port));
1747
Michael Chanb6016b72005-05-26 13:03:09 -07001748 if (!(bp->autoneg & AUTONEG_SPEED)) {
1749 u32 new_bmcr;
Michael Chan5b0c76a2005-11-04 08:45:49 -08001750 int force_link_down = 0;
1751
Michael Chan605a9e22007-05-03 13:23:13 -07001752 if (bp->req_line_speed == SPEED_2500) {
1753 if (!bnx2_test_and_enable_2g5(bp))
1754 force_link_down = 1;
1755 } else if (bp->req_line_speed == SPEED_1000) {
1756 if (bnx2_test_and_disable_2g5(bp))
1757 force_link_down = 1;
1758 }
Michael Chanca58c3a2007-05-03 13:22:52 -07001759 bnx2_read_phy(bp, bp->mii_adv, &adv);
Michael Chan80be4432006-11-19 14:07:28 -08001760 adv &= ~(ADVERTISE_1000XFULL | ADVERTISE_1000XHALF);
1761
Michael Chanca58c3a2007-05-03 13:22:52 -07001762 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chan605a9e22007-05-03 13:23:13 -07001763 new_bmcr = bmcr & ~BMCR_ANENABLE;
Michael Chan80be4432006-11-19 14:07:28 -08001764 new_bmcr |= BMCR_SPEED1000;
Michael Chan605a9e22007-05-03 13:23:13 -07001765
Michael Chan27a005b2007-05-03 13:23:41 -07001766 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
1767 if (bp->req_line_speed == SPEED_2500)
1768 bnx2_enable_forced_2g5(bp);
1769 else if (bp->req_line_speed == SPEED_1000) {
1770 bnx2_disable_forced_2g5(bp);
1771 new_bmcr &= ~0x2000;
1772 }
1773
1774 } else if (CHIP_NUM(bp) == CHIP_NUM_5708) {
Michael Chan605a9e22007-05-03 13:23:13 -07001775 if (bp->req_line_speed == SPEED_2500)
1776 new_bmcr |= BCM5708S_BMCR_FORCE_2500;
1777 else
1778 new_bmcr = bmcr & ~BCM5708S_BMCR_FORCE_2500;
Michael Chan5b0c76a2005-11-04 08:45:49 -08001779 }
1780
Michael Chanb6016b72005-05-26 13:03:09 -07001781 if (bp->req_duplex == DUPLEX_FULL) {
Michael Chan5b0c76a2005-11-04 08:45:49 -08001782 adv |= ADVERTISE_1000XFULL;
Michael Chanb6016b72005-05-26 13:03:09 -07001783 new_bmcr |= BMCR_FULLDPLX;
1784 }
1785 else {
Michael Chan5b0c76a2005-11-04 08:45:49 -08001786 adv |= ADVERTISE_1000XHALF;
Michael Chanb6016b72005-05-26 13:03:09 -07001787 new_bmcr &= ~BMCR_FULLDPLX;
1788 }
Michael Chan5b0c76a2005-11-04 08:45:49 -08001789 if ((new_bmcr != bmcr) || (force_link_down)) {
Michael Chanb6016b72005-05-26 13:03:09 -07001790 /* Force a link down visible on the other side */
1791 if (bp->link_up) {
Michael Chanca58c3a2007-05-03 13:22:52 -07001792 bnx2_write_phy(bp, bp->mii_adv, adv &
Michael Chan5b0c76a2005-11-04 08:45:49 -08001793 ~(ADVERTISE_1000XFULL |
1794 ADVERTISE_1000XHALF));
Michael Chanca58c3a2007-05-03 13:22:52 -07001795 bnx2_write_phy(bp, bp->mii_bmcr, bmcr |
Michael Chanb6016b72005-05-26 13:03:09 -07001796 BMCR_ANRESTART | BMCR_ANENABLE);
1797
1798 bp->link_up = 0;
1799 netif_carrier_off(bp->dev);
Michael Chanca58c3a2007-05-03 13:22:52 -07001800 bnx2_write_phy(bp, bp->mii_bmcr, new_bmcr);
Michael Chan80be4432006-11-19 14:07:28 -08001801 bnx2_report_link(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07001802 }
Michael Chanca58c3a2007-05-03 13:22:52 -07001803 bnx2_write_phy(bp, bp->mii_adv, adv);
1804 bnx2_write_phy(bp, bp->mii_bmcr, new_bmcr);
Michael Chan605a9e22007-05-03 13:23:13 -07001805 } else {
1806 bnx2_resolve_flow_ctrl(bp);
1807 bnx2_set_mac_link(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07001808 }
1809 return 0;
1810 }
1811
Michael Chan605a9e22007-05-03 13:23:13 -07001812 bnx2_test_and_enable_2g5(bp);
Michael Chan5b0c76a2005-11-04 08:45:49 -08001813
Michael Chanb6016b72005-05-26 13:03:09 -07001814 if (bp->advertising & ADVERTISED_1000baseT_Full)
1815 new_adv |= ADVERTISE_1000XFULL;
1816
1817 new_adv |= bnx2_phy_get_pause_adv(bp);
1818
Michael Chanca58c3a2007-05-03 13:22:52 -07001819 bnx2_read_phy(bp, bp->mii_adv, &adv);
1820 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chanb6016b72005-05-26 13:03:09 -07001821
1822 bp->serdes_an_pending = 0;
1823 if ((adv != new_adv) || ((bmcr & BMCR_ANENABLE) == 0)) {
1824 /* Force a link down visible on the other side */
1825 if (bp->link_up) {
Michael Chanca58c3a2007-05-03 13:22:52 -07001826 bnx2_write_phy(bp, bp->mii_bmcr, BMCR_LOOPBACK);
Michael Chan80be4432006-11-19 14:07:28 -08001827 spin_unlock_bh(&bp->phy_lock);
1828 msleep(20);
1829 spin_lock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07001830 }
1831
Michael Chanca58c3a2007-05-03 13:22:52 -07001832 bnx2_write_phy(bp, bp->mii_adv, new_adv);
1833 bnx2_write_phy(bp, bp->mii_bmcr, bmcr | BMCR_ANRESTART |
Michael Chanb6016b72005-05-26 13:03:09 -07001834 BMCR_ANENABLE);
Michael Chanf8dd0642006-11-19 14:08:29 -08001835 /* Speed up link-up time when the link partner
1836 * does not autonegotiate which is very common
1837 * in blade servers. Some blade servers use
1838 * IPMI for kerboard input and it's important
1839 * to minimize link disruptions. Autoneg. involves
1840 * exchanging base pages plus 3 next pages and
1841 * normally completes in about 120 msec.
1842 */
Michael Chan40105c02008-11-12 16:02:45 -08001843 bp->current_interval = BNX2_SERDES_AN_TIMEOUT;
Michael Chanf8dd0642006-11-19 14:08:29 -08001844 bp->serdes_an_pending = 1;
1845 mod_timer(&bp->timer, jiffies + bp->current_interval);
Michael Chan605a9e22007-05-03 13:23:13 -07001846 } else {
1847 bnx2_resolve_flow_ctrl(bp);
1848 bnx2_set_mac_link(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07001849 }
1850
1851 return 0;
1852}
1853
1854#define ETHTOOL_ALL_FIBRE_SPEED \
Michael Chan583c28e2008-01-21 19:51:35 -08001855 (bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE) ? \
Michael Chandeaf3912007-07-07 22:48:00 -07001856 (ADVERTISED_2500baseX_Full | ADVERTISED_1000baseT_Full) :\
1857 (ADVERTISED_1000baseT_Full)
Michael Chanb6016b72005-05-26 13:03:09 -07001858
1859#define ETHTOOL_ALL_COPPER_SPEED \
1860 (ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full | \
1861 ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full | \
1862 ADVERTISED_1000baseT_Full)
1863
1864#define PHY_ALL_10_100_SPEED (ADVERTISE_10HALF | ADVERTISE_10FULL | \
1865 ADVERTISE_100HALF | ADVERTISE_100FULL | ADVERTISE_CSMA)
Jeff Garzik6aa20a22006-09-13 13:24:59 -04001866
Michael Chanb6016b72005-05-26 13:03:09 -07001867#define PHY_ALL_1000_SPEED (ADVERTISE_1000HALF | ADVERTISE_1000FULL)
1868
Michael Chandeaf3912007-07-07 22:48:00 -07001869static void
Michael Chan0d8a6572007-07-07 22:49:43 -07001870bnx2_set_default_remote_link(struct bnx2 *bp)
1871{
1872 u32 link;
1873
1874 if (bp->phy_port == PORT_TP)
Michael Chan2726d6e2008-01-29 21:35:05 -08001875 link = bnx2_shmem_rd(bp, BNX2_RPHY_COPPER_LINK);
Michael Chan0d8a6572007-07-07 22:49:43 -07001876 else
Michael Chan2726d6e2008-01-29 21:35:05 -08001877 link = bnx2_shmem_rd(bp, BNX2_RPHY_SERDES_LINK);
Michael Chan0d8a6572007-07-07 22:49:43 -07001878
1879 if (link & BNX2_NETLINK_SET_LINK_ENABLE_AUTONEG) {
1880 bp->req_line_speed = 0;
1881 bp->autoneg |= AUTONEG_SPEED;
1882 bp->advertising = ADVERTISED_Autoneg;
1883 if (link & BNX2_NETLINK_SET_LINK_SPEED_10HALF)
1884 bp->advertising |= ADVERTISED_10baseT_Half;
1885 if (link & BNX2_NETLINK_SET_LINK_SPEED_10FULL)
1886 bp->advertising |= ADVERTISED_10baseT_Full;
1887 if (link & BNX2_NETLINK_SET_LINK_SPEED_100HALF)
1888 bp->advertising |= ADVERTISED_100baseT_Half;
1889 if (link & BNX2_NETLINK_SET_LINK_SPEED_100FULL)
1890 bp->advertising |= ADVERTISED_100baseT_Full;
1891 if (link & BNX2_NETLINK_SET_LINK_SPEED_1GFULL)
1892 bp->advertising |= ADVERTISED_1000baseT_Full;
1893 if (link & BNX2_NETLINK_SET_LINK_SPEED_2G5FULL)
1894 bp->advertising |= ADVERTISED_2500baseX_Full;
1895 } else {
1896 bp->autoneg = 0;
1897 bp->advertising = 0;
1898 bp->req_duplex = DUPLEX_FULL;
1899 if (link & BNX2_NETLINK_SET_LINK_SPEED_10) {
1900 bp->req_line_speed = SPEED_10;
1901 if (link & BNX2_NETLINK_SET_LINK_SPEED_10HALF)
1902 bp->req_duplex = DUPLEX_HALF;
1903 }
1904 if (link & BNX2_NETLINK_SET_LINK_SPEED_100) {
1905 bp->req_line_speed = SPEED_100;
1906 if (link & BNX2_NETLINK_SET_LINK_SPEED_100HALF)
1907 bp->req_duplex = DUPLEX_HALF;
1908 }
1909 if (link & BNX2_NETLINK_SET_LINK_SPEED_1GFULL)
1910 bp->req_line_speed = SPEED_1000;
1911 if (link & BNX2_NETLINK_SET_LINK_SPEED_2G5FULL)
1912 bp->req_line_speed = SPEED_2500;
1913 }
1914}
1915
1916static void
Michael Chandeaf3912007-07-07 22:48:00 -07001917bnx2_set_default_link(struct bnx2 *bp)
1918{
Harvey Harrisonab598592008-05-01 02:47:38 -07001919 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP) {
1920 bnx2_set_default_remote_link(bp);
1921 return;
1922 }
Michael Chan0d8a6572007-07-07 22:49:43 -07001923
Michael Chandeaf3912007-07-07 22:48:00 -07001924 bp->autoneg = AUTONEG_SPEED | AUTONEG_FLOW_CTRL;
1925 bp->req_line_speed = 0;
Michael Chan583c28e2008-01-21 19:51:35 -08001926 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Michael Chandeaf3912007-07-07 22:48:00 -07001927 u32 reg;
1928
1929 bp->advertising = ETHTOOL_ALL_FIBRE_SPEED | ADVERTISED_Autoneg;
1930
Michael Chan2726d6e2008-01-29 21:35:05 -08001931 reg = bnx2_shmem_rd(bp, BNX2_PORT_HW_CFG_CONFIG);
Michael Chandeaf3912007-07-07 22:48:00 -07001932 reg &= BNX2_PORT_HW_CFG_CFG_DFLT_LINK_MASK;
1933 if (reg == BNX2_PORT_HW_CFG_CFG_DFLT_LINK_1G) {
1934 bp->autoneg = 0;
1935 bp->req_line_speed = bp->line_speed = SPEED_1000;
1936 bp->req_duplex = DUPLEX_FULL;
1937 }
1938 } else
1939 bp->advertising = ETHTOOL_ALL_COPPER_SPEED | ADVERTISED_Autoneg;
1940}
1941
Michael Chan0d8a6572007-07-07 22:49:43 -07001942static void
Michael Chandf149d72007-07-07 22:51:36 -07001943bnx2_send_heart_beat(struct bnx2 *bp)
1944{
1945 u32 msg;
1946 u32 addr;
1947
1948 spin_lock(&bp->indirect_lock);
1949 msg = (u32) (++bp->fw_drv_pulse_wr_seq & BNX2_DRV_PULSE_SEQ_MASK);
1950 addr = bp->shmem_base + BNX2_DRV_PULSE_MB;
1951 REG_WR(bp, BNX2_PCICFG_REG_WINDOW_ADDRESS, addr);
1952 REG_WR(bp, BNX2_PCICFG_REG_WINDOW, msg);
1953 spin_unlock(&bp->indirect_lock);
1954}
1955
1956static void
Michael Chan0d8a6572007-07-07 22:49:43 -07001957bnx2_remote_phy_event(struct bnx2 *bp)
1958{
1959 u32 msg;
1960 u8 link_up = bp->link_up;
1961 u8 old_port;
1962
Michael Chan2726d6e2008-01-29 21:35:05 -08001963 msg = bnx2_shmem_rd(bp, BNX2_LINK_STATUS);
Michael Chan0d8a6572007-07-07 22:49:43 -07001964
Michael Chandf149d72007-07-07 22:51:36 -07001965 if (msg & BNX2_LINK_STATUS_HEART_BEAT_EXPIRED)
1966 bnx2_send_heart_beat(bp);
1967
1968 msg &= ~BNX2_LINK_STATUS_HEART_BEAT_EXPIRED;
1969
Michael Chan0d8a6572007-07-07 22:49:43 -07001970 if ((msg & BNX2_LINK_STATUS_LINK_UP) == BNX2_LINK_STATUS_LINK_DOWN)
1971 bp->link_up = 0;
1972 else {
1973 u32 speed;
1974
1975 bp->link_up = 1;
1976 speed = msg & BNX2_LINK_STATUS_SPEED_MASK;
1977 bp->duplex = DUPLEX_FULL;
1978 switch (speed) {
1979 case BNX2_LINK_STATUS_10HALF:
1980 bp->duplex = DUPLEX_HALF;
1981 case BNX2_LINK_STATUS_10FULL:
1982 bp->line_speed = SPEED_10;
1983 break;
1984 case BNX2_LINK_STATUS_100HALF:
1985 bp->duplex = DUPLEX_HALF;
1986 case BNX2_LINK_STATUS_100BASE_T4:
1987 case BNX2_LINK_STATUS_100FULL:
1988 bp->line_speed = SPEED_100;
1989 break;
1990 case BNX2_LINK_STATUS_1000HALF:
1991 bp->duplex = DUPLEX_HALF;
1992 case BNX2_LINK_STATUS_1000FULL:
1993 bp->line_speed = SPEED_1000;
1994 break;
1995 case BNX2_LINK_STATUS_2500HALF:
1996 bp->duplex = DUPLEX_HALF;
1997 case BNX2_LINK_STATUS_2500FULL:
1998 bp->line_speed = SPEED_2500;
1999 break;
2000 default:
2001 bp->line_speed = 0;
2002 break;
2003 }
2004
Michael Chan0d8a6572007-07-07 22:49:43 -07002005 bp->flow_ctrl = 0;
2006 if ((bp->autoneg & (AUTONEG_SPEED | AUTONEG_FLOW_CTRL)) !=
2007 (AUTONEG_SPEED | AUTONEG_FLOW_CTRL)) {
2008 if (bp->duplex == DUPLEX_FULL)
2009 bp->flow_ctrl = bp->req_flow_ctrl;
2010 } else {
2011 if (msg & BNX2_LINK_STATUS_TX_FC_ENABLED)
2012 bp->flow_ctrl |= FLOW_CTRL_TX;
2013 if (msg & BNX2_LINK_STATUS_RX_FC_ENABLED)
2014 bp->flow_ctrl |= FLOW_CTRL_RX;
2015 }
2016
2017 old_port = bp->phy_port;
2018 if (msg & BNX2_LINK_STATUS_SERDES_LINK)
2019 bp->phy_port = PORT_FIBRE;
2020 else
2021 bp->phy_port = PORT_TP;
2022
2023 if (old_port != bp->phy_port)
2024 bnx2_set_default_link(bp);
2025
Michael Chan0d8a6572007-07-07 22:49:43 -07002026 }
2027 if (bp->link_up != link_up)
2028 bnx2_report_link(bp);
2029
2030 bnx2_set_mac_link(bp);
2031}
2032
2033static int
2034bnx2_set_remote_link(struct bnx2 *bp)
2035{
2036 u32 evt_code;
2037
Michael Chan2726d6e2008-01-29 21:35:05 -08002038 evt_code = bnx2_shmem_rd(bp, BNX2_FW_EVT_CODE_MB);
Michael Chan0d8a6572007-07-07 22:49:43 -07002039 switch (evt_code) {
2040 case BNX2_FW_EVT_CODE_LINK_EVENT:
2041 bnx2_remote_phy_event(bp);
2042 break;
2043 case BNX2_FW_EVT_CODE_SW_TIMER_EXPIRATION_EVENT:
2044 default:
Michael Chandf149d72007-07-07 22:51:36 -07002045 bnx2_send_heart_beat(bp);
Michael Chan0d8a6572007-07-07 22:49:43 -07002046 break;
2047 }
2048 return 0;
2049}
2050
Michael Chanb6016b72005-05-26 13:03:09 -07002051static int
2052bnx2_setup_copper_phy(struct bnx2 *bp)
Harvey Harrison52d07b12009-01-19 17:27:06 -08002053__releases(&bp->phy_lock)
2054__acquires(&bp->phy_lock)
Michael Chanb6016b72005-05-26 13:03:09 -07002055{
2056 u32 bmcr;
2057 u32 new_bmcr;
2058
Michael Chanca58c3a2007-05-03 13:22:52 -07002059 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chanb6016b72005-05-26 13:03:09 -07002060
2061 if (bp->autoneg & AUTONEG_SPEED) {
2062 u32 adv_reg, adv1000_reg;
2063 u32 new_adv_reg = 0;
2064 u32 new_adv1000_reg = 0;
2065
Michael Chanca58c3a2007-05-03 13:22:52 -07002066 bnx2_read_phy(bp, bp->mii_adv, &adv_reg);
Michael Chanb6016b72005-05-26 13:03:09 -07002067 adv_reg &= (PHY_ALL_10_100_SPEED | ADVERTISE_PAUSE_CAP |
2068 ADVERTISE_PAUSE_ASYM);
2069
2070 bnx2_read_phy(bp, MII_CTRL1000, &adv1000_reg);
2071 adv1000_reg &= PHY_ALL_1000_SPEED;
2072
2073 if (bp->advertising & ADVERTISED_10baseT_Half)
2074 new_adv_reg |= ADVERTISE_10HALF;
2075 if (bp->advertising & ADVERTISED_10baseT_Full)
2076 new_adv_reg |= ADVERTISE_10FULL;
2077 if (bp->advertising & ADVERTISED_100baseT_Half)
2078 new_adv_reg |= ADVERTISE_100HALF;
2079 if (bp->advertising & ADVERTISED_100baseT_Full)
2080 new_adv_reg |= ADVERTISE_100FULL;
2081 if (bp->advertising & ADVERTISED_1000baseT_Full)
2082 new_adv1000_reg |= ADVERTISE_1000FULL;
Jeff Garzik6aa20a22006-09-13 13:24:59 -04002083
Michael Chanb6016b72005-05-26 13:03:09 -07002084 new_adv_reg |= ADVERTISE_CSMA;
2085
2086 new_adv_reg |= bnx2_phy_get_pause_adv(bp);
2087
2088 if ((adv1000_reg != new_adv1000_reg) ||
2089 (adv_reg != new_adv_reg) ||
2090 ((bmcr & BMCR_ANENABLE) == 0)) {
2091
Michael Chanca58c3a2007-05-03 13:22:52 -07002092 bnx2_write_phy(bp, bp->mii_adv, new_adv_reg);
Michael Chanb6016b72005-05-26 13:03:09 -07002093 bnx2_write_phy(bp, MII_CTRL1000, new_adv1000_reg);
Michael Chanca58c3a2007-05-03 13:22:52 -07002094 bnx2_write_phy(bp, bp->mii_bmcr, BMCR_ANRESTART |
Michael Chanb6016b72005-05-26 13:03:09 -07002095 BMCR_ANENABLE);
2096 }
2097 else if (bp->link_up) {
2098 /* Flow ctrl may have changed from auto to forced */
2099 /* or vice-versa. */
2100
2101 bnx2_resolve_flow_ctrl(bp);
2102 bnx2_set_mac_link(bp);
2103 }
2104 return 0;
2105 }
2106
2107 new_bmcr = 0;
2108 if (bp->req_line_speed == SPEED_100) {
2109 new_bmcr |= BMCR_SPEED100;
2110 }
2111 if (bp->req_duplex == DUPLEX_FULL) {
2112 new_bmcr |= BMCR_FULLDPLX;
2113 }
2114 if (new_bmcr != bmcr) {
2115 u32 bmsr;
Michael Chanb6016b72005-05-26 13:03:09 -07002116
Michael Chanca58c3a2007-05-03 13:22:52 -07002117 bnx2_read_phy(bp, bp->mii_bmsr, &bmsr);
2118 bnx2_read_phy(bp, bp->mii_bmsr, &bmsr);
Jeff Garzik6aa20a22006-09-13 13:24:59 -04002119
Michael Chanb6016b72005-05-26 13:03:09 -07002120 if (bmsr & BMSR_LSTATUS) {
2121 /* Force link down */
Michael Chanca58c3a2007-05-03 13:22:52 -07002122 bnx2_write_phy(bp, bp->mii_bmcr, BMCR_LOOPBACK);
Michael Chana16dda02006-11-19 14:08:56 -08002123 spin_unlock_bh(&bp->phy_lock);
2124 msleep(50);
2125 spin_lock_bh(&bp->phy_lock);
2126
Michael Chanca58c3a2007-05-03 13:22:52 -07002127 bnx2_read_phy(bp, bp->mii_bmsr, &bmsr);
2128 bnx2_read_phy(bp, bp->mii_bmsr, &bmsr);
Michael Chanb6016b72005-05-26 13:03:09 -07002129 }
2130
Michael Chanca58c3a2007-05-03 13:22:52 -07002131 bnx2_write_phy(bp, bp->mii_bmcr, new_bmcr);
Michael Chanb6016b72005-05-26 13:03:09 -07002132
2133 /* Normally, the new speed is setup after the link has
2134 * gone down and up again. In some cases, link will not go
2135 * down so we need to set up the new speed here.
2136 */
2137 if (bmsr & BMSR_LSTATUS) {
2138 bp->line_speed = bp->req_line_speed;
2139 bp->duplex = bp->req_duplex;
2140 bnx2_resolve_flow_ctrl(bp);
2141 bnx2_set_mac_link(bp);
2142 }
Michael Chan27a005b2007-05-03 13:23:41 -07002143 } else {
2144 bnx2_resolve_flow_ctrl(bp);
2145 bnx2_set_mac_link(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07002146 }
2147 return 0;
2148}
2149
2150static int
Michael Chan0d8a6572007-07-07 22:49:43 -07002151bnx2_setup_phy(struct bnx2 *bp, u8 port)
Harvey Harrison52d07b12009-01-19 17:27:06 -08002152__releases(&bp->phy_lock)
2153__acquires(&bp->phy_lock)
Michael Chanb6016b72005-05-26 13:03:09 -07002154{
2155 if (bp->loopback == MAC_LOOPBACK)
2156 return 0;
2157
Michael Chan583c28e2008-01-21 19:51:35 -08002158 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Michael Chan0d8a6572007-07-07 22:49:43 -07002159 return (bnx2_setup_serdes_phy(bp, port));
Michael Chanb6016b72005-05-26 13:03:09 -07002160 }
2161 else {
2162 return (bnx2_setup_copper_phy(bp));
2163 }
2164}
2165
2166static int
Michael Chan9a120bc2008-05-16 22:17:45 -07002167bnx2_init_5709s_phy(struct bnx2 *bp, int reset_phy)
Michael Chan27a005b2007-05-03 13:23:41 -07002168{
2169 u32 val;
2170
2171 bp->mii_bmcr = MII_BMCR + 0x10;
2172 bp->mii_bmsr = MII_BMSR + 0x10;
2173 bp->mii_bmsr1 = MII_BNX2_GP_TOP_AN_STATUS1;
2174 bp->mii_adv = MII_ADVERTISE + 0x10;
2175 bp->mii_lpa = MII_LPA + 0x10;
2176 bp->mii_up1 = MII_BNX2_OVER1G_UP1;
2177
2178 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_AER);
2179 bnx2_write_phy(bp, MII_BNX2_AER_AER, MII_BNX2_AER_AER_AN_MMD);
2180
2181 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
Michael Chan9a120bc2008-05-16 22:17:45 -07002182 if (reset_phy)
2183 bnx2_reset_phy(bp);
Michael Chan27a005b2007-05-03 13:23:41 -07002184
2185 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_SERDES_DIG);
2186
2187 bnx2_read_phy(bp, MII_BNX2_SERDES_DIG_1000XCTL1, &val);
2188 val &= ~MII_BNX2_SD_1000XCTL1_AUTODET;
2189 val |= MII_BNX2_SD_1000XCTL1_FIBER;
2190 bnx2_write_phy(bp, MII_BNX2_SERDES_DIG_1000XCTL1, val);
2191
2192 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_OVER1G);
2193 bnx2_read_phy(bp, MII_BNX2_OVER1G_UP1, &val);
Michael Chan583c28e2008-01-21 19:51:35 -08002194 if (bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE)
Michael Chan27a005b2007-05-03 13:23:41 -07002195 val |= BCM5708S_UP1_2G5;
2196 else
2197 val &= ~BCM5708S_UP1_2G5;
2198 bnx2_write_phy(bp, MII_BNX2_OVER1G_UP1, val);
2199
2200 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_BAM_NXTPG);
2201 bnx2_read_phy(bp, MII_BNX2_BAM_NXTPG_CTL, &val);
2202 val |= MII_BNX2_NXTPG_CTL_T2 | MII_BNX2_NXTPG_CTL_BAM;
2203 bnx2_write_phy(bp, MII_BNX2_BAM_NXTPG_CTL, val);
2204
2205 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_CL73_USERB0);
2206
2207 val = MII_BNX2_CL73_BAM_EN | MII_BNX2_CL73_BAM_STA_MGR_EN |
2208 MII_BNX2_CL73_BAM_NP_AFT_BP_EN;
2209 bnx2_write_phy(bp, MII_BNX2_CL73_BAM_CTL1, val);
2210
2211 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
2212
2213 return 0;
2214}
2215
2216static int
Michael Chan9a120bc2008-05-16 22:17:45 -07002217bnx2_init_5708s_phy(struct bnx2 *bp, int reset_phy)
Michael Chan5b0c76a2005-11-04 08:45:49 -08002218{
2219 u32 val;
2220
Michael Chan9a120bc2008-05-16 22:17:45 -07002221 if (reset_phy)
2222 bnx2_reset_phy(bp);
Michael Chan27a005b2007-05-03 13:23:41 -07002223
2224 bp->mii_up1 = BCM5708S_UP1;
2225
Michael Chan5b0c76a2005-11-04 08:45:49 -08002226 bnx2_write_phy(bp, BCM5708S_BLK_ADDR, BCM5708S_BLK_ADDR_DIG3);
2227 bnx2_write_phy(bp, BCM5708S_DIG_3_0, BCM5708S_DIG_3_0_USE_IEEE);
2228 bnx2_write_phy(bp, BCM5708S_BLK_ADDR, BCM5708S_BLK_ADDR_DIG);
2229
2230 bnx2_read_phy(bp, BCM5708S_1000X_CTL1, &val);
2231 val |= BCM5708S_1000X_CTL1_FIBER_MODE | BCM5708S_1000X_CTL1_AUTODET_EN;
2232 bnx2_write_phy(bp, BCM5708S_1000X_CTL1, val);
2233
2234 bnx2_read_phy(bp, BCM5708S_1000X_CTL2, &val);
2235 val |= BCM5708S_1000X_CTL2_PLLEL_DET_EN;
2236 bnx2_write_phy(bp, BCM5708S_1000X_CTL2, val);
2237
Michael Chan583c28e2008-01-21 19:51:35 -08002238 if (bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE) {
Michael Chan5b0c76a2005-11-04 08:45:49 -08002239 bnx2_read_phy(bp, BCM5708S_UP1, &val);
2240 val |= BCM5708S_UP1_2G5;
2241 bnx2_write_phy(bp, BCM5708S_UP1, val);
2242 }
2243
2244 if ((CHIP_ID(bp) == CHIP_ID_5708_A0) ||
Michael Chandda1e392006-01-23 16:08:14 -08002245 (CHIP_ID(bp) == CHIP_ID_5708_B0) ||
2246 (CHIP_ID(bp) == CHIP_ID_5708_B1)) {
Michael Chan5b0c76a2005-11-04 08:45:49 -08002247 /* increase tx signal amplitude */
2248 bnx2_write_phy(bp, BCM5708S_BLK_ADDR,
2249 BCM5708S_BLK_ADDR_TX_MISC);
2250 bnx2_read_phy(bp, BCM5708S_TX_ACTL1, &val);
2251 val &= ~BCM5708S_TX_ACTL1_DRIVER_VCM;
2252 bnx2_write_phy(bp, BCM5708S_TX_ACTL1, val);
2253 bnx2_write_phy(bp, BCM5708S_BLK_ADDR, BCM5708S_BLK_ADDR_DIG);
2254 }
2255
Michael Chan2726d6e2008-01-29 21:35:05 -08002256 val = bnx2_shmem_rd(bp, BNX2_PORT_HW_CFG_CONFIG) &
Michael Chan5b0c76a2005-11-04 08:45:49 -08002257 BNX2_PORT_HW_CFG_CFG_TXCTL3_MASK;
2258
2259 if (val) {
2260 u32 is_backplane;
2261
Michael Chan2726d6e2008-01-29 21:35:05 -08002262 is_backplane = bnx2_shmem_rd(bp, BNX2_SHARED_HW_CFG_CONFIG);
Michael Chan5b0c76a2005-11-04 08:45:49 -08002263 if (is_backplane & BNX2_SHARED_HW_CFG_PHY_BACKPLANE) {
2264 bnx2_write_phy(bp, BCM5708S_BLK_ADDR,
2265 BCM5708S_BLK_ADDR_TX_MISC);
2266 bnx2_write_phy(bp, BCM5708S_TX_ACTL3, val);
2267 bnx2_write_phy(bp, BCM5708S_BLK_ADDR,
2268 BCM5708S_BLK_ADDR_DIG);
2269 }
2270 }
2271 return 0;
2272}
2273
2274static int
Michael Chan9a120bc2008-05-16 22:17:45 -07002275bnx2_init_5706s_phy(struct bnx2 *bp, int reset_phy)
Michael Chanb6016b72005-05-26 13:03:09 -07002276{
Michael Chan9a120bc2008-05-16 22:17:45 -07002277 if (reset_phy)
2278 bnx2_reset_phy(bp);
Michael Chan27a005b2007-05-03 13:23:41 -07002279
Michael Chan583c28e2008-01-21 19:51:35 -08002280 bp->phy_flags &= ~BNX2_PHY_FLAG_PARALLEL_DETECT;
Michael Chanb6016b72005-05-26 13:03:09 -07002281
Michael Chan59b47d82006-11-19 14:10:45 -08002282 if (CHIP_NUM(bp) == CHIP_NUM_5706)
2283 REG_WR(bp, BNX2_MISC_GP_HW_CTL0, 0x300);
Michael Chanb6016b72005-05-26 13:03:09 -07002284
2285 if (bp->dev->mtu > 1500) {
2286 u32 val;
2287
2288 /* Set extended packet length bit */
2289 bnx2_write_phy(bp, 0x18, 0x7);
2290 bnx2_read_phy(bp, 0x18, &val);
2291 bnx2_write_phy(bp, 0x18, (val & 0xfff8) | 0x4000);
2292
2293 bnx2_write_phy(bp, 0x1c, 0x6c00);
2294 bnx2_read_phy(bp, 0x1c, &val);
2295 bnx2_write_phy(bp, 0x1c, (val & 0x3ff) | 0xec02);
2296 }
2297 else {
2298 u32 val;
2299
2300 bnx2_write_phy(bp, 0x18, 0x7);
2301 bnx2_read_phy(bp, 0x18, &val);
2302 bnx2_write_phy(bp, 0x18, val & ~0x4007);
2303
2304 bnx2_write_phy(bp, 0x1c, 0x6c00);
2305 bnx2_read_phy(bp, 0x1c, &val);
2306 bnx2_write_phy(bp, 0x1c, (val & 0x3fd) | 0xec00);
2307 }
2308
2309 return 0;
2310}
2311
2312static int
Michael Chan9a120bc2008-05-16 22:17:45 -07002313bnx2_init_copper_phy(struct bnx2 *bp, int reset_phy)
Michael Chanb6016b72005-05-26 13:03:09 -07002314{
Michael Chan5b0c76a2005-11-04 08:45:49 -08002315 u32 val;
2316
Michael Chan9a120bc2008-05-16 22:17:45 -07002317 if (reset_phy)
2318 bnx2_reset_phy(bp);
Michael Chan27a005b2007-05-03 13:23:41 -07002319
Michael Chan583c28e2008-01-21 19:51:35 -08002320 if (bp->phy_flags & BNX2_PHY_FLAG_CRC_FIX) {
Michael Chanb6016b72005-05-26 13:03:09 -07002321 bnx2_write_phy(bp, 0x18, 0x0c00);
2322 bnx2_write_phy(bp, 0x17, 0x000a);
2323 bnx2_write_phy(bp, 0x15, 0x310b);
2324 bnx2_write_phy(bp, 0x17, 0x201f);
2325 bnx2_write_phy(bp, 0x15, 0x9506);
2326 bnx2_write_phy(bp, 0x17, 0x401f);
2327 bnx2_write_phy(bp, 0x15, 0x14e2);
2328 bnx2_write_phy(bp, 0x18, 0x0400);
2329 }
2330
Michael Chan583c28e2008-01-21 19:51:35 -08002331 if (bp->phy_flags & BNX2_PHY_FLAG_DIS_EARLY_DAC) {
Michael Chanb659f442007-02-02 00:46:35 -08002332 bnx2_write_phy(bp, MII_BNX2_DSP_ADDRESS,
2333 MII_BNX2_DSP_EXPAND_REG | 0x8);
2334 bnx2_read_phy(bp, MII_BNX2_DSP_RW_PORT, &val);
2335 val &= ~(1 << 8);
2336 bnx2_write_phy(bp, MII_BNX2_DSP_RW_PORT, val);
2337 }
2338
Michael Chanb6016b72005-05-26 13:03:09 -07002339 if (bp->dev->mtu > 1500) {
Michael Chanb6016b72005-05-26 13:03:09 -07002340 /* Set extended packet length bit */
2341 bnx2_write_phy(bp, 0x18, 0x7);
2342 bnx2_read_phy(bp, 0x18, &val);
2343 bnx2_write_phy(bp, 0x18, val | 0x4000);
2344
2345 bnx2_read_phy(bp, 0x10, &val);
2346 bnx2_write_phy(bp, 0x10, val | 0x1);
2347 }
2348 else {
Michael Chanb6016b72005-05-26 13:03:09 -07002349 bnx2_write_phy(bp, 0x18, 0x7);
2350 bnx2_read_phy(bp, 0x18, &val);
2351 bnx2_write_phy(bp, 0x18, val & ~0x4007);
2352
2353 bnx2_read_phy(bp, 0x10, &val);
2354 bnx2_write_phy(bp, 0x10, val & ~0x1);
2355 }
2356
Michael Chan5b0c76a2005-11-04 08:45:49 -08002357 /* ethernet@wirespeed */
2358 bnx2_write_phy(bp, 0x18, 0x7007);
2359 bnx2_read_phy(bp, 0x18, &val);
2360 bnx2_write_phy(bp, 0x18, val | (1 << 15) | (1 << 4));
Michael Chanb6016b72005-05-26 13:03:09 -07002361 return 0;
2362}
2363
2364
2365static int
Michael Chan9a120bc2008-05-16 22:17:45 -07002366bnx2_init_phy(struct bnx2 *bp, int reset_phy)
Harvey Harrison52d07b12009-01-19 17:27:06 -08002367__releases(&bp->phy_lock)
2368__acquires(&bp->phy_lock)
Michael Chanb6016b72005-05-26 13:03:09 -07002369{
2370 u32 val;
2371 int rc = 0;
2372
Michael Chan583c28e2008-01-21 19:51:35 -08002373 bp->phy_flags &= ~BNX2_PHY_FLAG_INT_MODE_MASK;
2374 bp->phy_flags |= BNX2_PHY_FLAG_INT_MODE_LINK_READY;
Michael Chanb6016b72005-05-26 13:03:09 -07002375
Michael Chanca58c3a2007-05-03 13:22:52 -07002376 bp->mii_bmcr = MII_BMCR;
2377 bp->mii_bmsr = MII_BMSR;
Michael Chan27a005b2007-05-03 13:23:41 -07002378 bp->mii_bmsr1 = MII_BMSR;
Michael Chanca58c3a2007-05-03 13:22:52 -07002379 bp->mii_adv = MII_ADVERTISE;
2380 bp->mii_lpa = MII_LPA;
2381
Michael Chanb6016b72005-05-26 13:03:09 -07002382 REG_WR(bp, BNX2_EMAC_ATTENTION_ENA, BNX2_EMAC_ATTENTION_ENA_LINK);
2383
Michael Chan583c28e2008-01-21 19:51:35 -08002384 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
Michael Chan0d8a6572007-07-07 22:49:43 -07002385 goto setup_phy;
2386
Michael Chanb6016b72005-05-26 13:03:09 -07002387 bnx2_read_phy(bp, MII_PHYSID1, &val);
2388 bp->phy_id = val << 16;
2389 bnx2_read_phy(bp, MII_PHYSID2, &val);
2390 bp->phy_id |= val & 0xffff;
2391
Michael Chan583c28e2008-01-21 19:51:35 -08002392 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Michael Chan5b0c76a2005-11-04 08:45:49 -08002393 if (CHIP_NUM(bp) == CHIP_NUM_5706)
Michael Chan9a120bc2008-05-16 22:17:45 -07002394 rc = bnx2_init_5706s_phy(bp, reset_phy);
Michael Chan5b0c76a2005-11-04 08:45:49 -08002395 else if (CHIP_NUM(bp) == CHIP_NUM_5708)
Michael Chan9a120bc2008-05-16 22:17:45 -07002396 rc = bnx2_init_5708s_phy(bp, reset_phy);
Michael Chan27a005b2007-05-03 13:23:41 -07002397 else if (CHIP_NUM(bp) == CHIP_NUM_5709)
Michael Chan9a120bc2008-05-16 22:17:45 -07002398 rc = bnx2_init_5709s_phy(bp, reset_phy);
Michael Chanb6016b72005-05-26 13:03:09 -07002399 }
2400 else {
Michael Chan9a120bc2008-05-16 22:17:45 -07002401 rc = bnx2_init_copper_phy(bp, reset_phy);
Michael Chanb6016b72005-05-26 13:03:09 -07002402 }
2403
Michael Chan0d8a6572007-07-07 22:49:43 -07002404setup_phy:
2405 if (!rc)
2406 rc = bnx2_setup_phy(bp, bp->phy_port);
Michael Chanb6016b72005-05-26 13:03:09 -07002407
2408 return rc;
2409}
2410
2411static int
2412bnx2_set_mac_loopback(struct bnx2 *bp)
2413{
2414 u32 mac_mode;
2415
2416 mac_mode = REG_RD(bp, BNX2_EMAC_MODE);
2417 mac_mode &= ~BNX2_EMAC_MODE_PORT;
2418 mac_mode |= BNX2_EMAC_MODE_MAC_LOOP | BNX2_EMAC_MODE_FORCE_LINK;
2419 REG_WR(bp, BNX2_EMAC_MODE, mac_mode);
2420 bp->link_up = 1;
2421 return 0;
2422}
2423
Michael Chanbc5a0692006-01-23 16:13:22 -08002424static int bnx2_test_link(struct bnx2 *);
2425
2426static int
2427bnx2_set_phy_loopback(struct bnx2 *bp)
2428{
2429 u32 mac_mode;
2430 int rc, i;
2431
2432 spin_lock_bh(&bp->phy_lock);
Michael Chanca58c3a2007-05-03 13:22:52 -07002433 rc = bnx2_write_phy(bp, bp->mii_bmcr, BMCR_LOOPBACK | BMCR_FULLDPLX |
Michael Chanbc5a0692006-01-23 16:13:22 -08002434 BMCR_SPEED1000);
2435 spin_unlock_bh(&bp->phy_lock);
2436 if (rc)
2437 return rc;
2438
2439 for (i = 0; i < 10; i++) {
2440 if (bnx2_test_link(bp) == 0)
2441 break;
Michael Chan80be4432006-11-19 14:07:28 -08002442 msleep(100);
Michael Chanbc5a0692006-01-23 16:13:22 -08002443 }
2444
2445 mac_mode = REG_RD(bp, BNX2_EMAC_MODE);
2446 mac_mode &= ~(BNX2_EMAC_MODE_PORT | BNX2_EMAC_MODE_HALF_DUPLEX |
2447 BNX2_EMAC_MODE_MAC_LOOP | BNX2_EMAC_MODE_FORCE_LINK |
Michael Chan59b47d82006-11-19 14:10:45 -08002448 BNX2_EMAC_MODE_25G_MODE);
Michael Chanbc5a0692006-01-23 16:13:22 -08002449
2450 mac_mode |= BNX2_EMAC_MODE_PORT_GMII;
2451 REG_WR(bp, BNX2_EMAC_MODE, mac_mode);
2452 bp->link_up = 1;
2453 return 0;
2454}
2455
Michael Chanb6016b72005-05-26 13:03:09 -07002456static int
Michael Chana2f13892008-07-14 22:38:23 -07002457bnx2_fw_sync(struct bnx2 *bp, u32 msg_data, int ack, int silent)
Michael Chanb6016b72005-05-26 13:03:09 -07002458{
2459 int i;
2460 u32 val;
2461
Michael Chanb6016b72005-05-26 13:03:09 -07002462 bp->fw_wr_seq++;
2463 msg_data |= bp->fw_wr_seq;
2464
Michael Chan2726d6e2008-01-29 21:35:05 -08002465 bnx2_shmem_wr(bp, BNX2_DRV_MB, msg_data);
Michael Chanb6016b72005-05-26 13:03:09 -07002466
Michael Chana2f13892008-07-14 22:38:23 -07002467 if (!ack)
2468 return 0;
2469
Michael Chanb6016b72005-05-26 13:03:09 -07002470 /* wait for an acknowledgement. */
Michael Chan40105c02008-11-12 16:02:45 -08002471 for (i = 0; i < (BNX2_FW_ACK_TIME_OUT_MS / 10); i++) {
Michael Chanb090ae22006-01-23 16:07:10 -08002472 msleep(10);
Michael Chanb6016b72005-05-26 13:03:09 -07002473
Michael Chan2726d6e2008-01-29 21:35:05 -08002474 val = bnx2_shmem_rd(bp, BNX2_FW_MB);
Michael Chanb6016b72005-05-26 13:03:09 -07002475
2476 if ((val & BNX2_FW_MSG_ACK) == (msg_data & BNX2_DRV_MSG_SEQ))
2477 break;
2478 }
Michael Chanb090ae22006-01-23 16:07:10 -08002479 if ((msg_data & BNX2_DRV_MSG_DATA) == BNX2_DRV_MSG_DATA_WAIT0)
2480 return 0;
Michael Chanb6016b72005-05-26 13:03:09 -07002481
2482 /* If we timed out, inform the firmware that this is the case. */
Michael Chanb090ae22006-01-23 16:07:10 -08002483 if ((val & BNX2_FW_MSG_ACK) != (msg_data & BNX2_DRV_MSG_SEQ)) {
2484 if (!silent)
2485 printk(KERN_ERR PFX "fw sync timeout, reset code = "
2486 "%x\n", msg_data);
Michael Chanb6016b72005-05-26 13:03:09 -07002487
2488 msg_data &= ~BNX2_DRV_MSG_CODE;
2489 msg_data |= BNX2_DRV_MSG_CODE_FW_TIMEOUT;
2490
Michael Chan2726d6e2008-01-29 21:35:05 -08002491 bnx2_shmem_wr(bp, BNX2_DRV_MB, msg_data);
Michael Chanb6016b72005-05-26 13:03:09 -07002492
Michael Chanb6016b72005-05-26 13:03:09 -07002493 return -EBUSY;
2494 }
2495
Michael Chanb090ae22006-01-23 16:07:10 -08002496 if ((val & BNX2_FW_MSG_STATUS_MASK) != BNX2_FW_MSG_STATUS_OK)
2497 return -EIO;
2498
Michael Chanb6016b72005-05-26 13:03:09 -07002499 return 0;
2500}
2501
Michael Chan59b47d82006-11-19 14:10:45 -08002502static int
2503bnx2_init_5709_context(struct bnx2 *bp)
2504{
2505 int i, ret = 0;
2506 u32 val;
2507
2508 val = BNX2_CTX_COMMAND_ENABLED | BNX2_CTX_COMMAND_MEM_INIT | (1 << 12);
2509 val |= (BCM_PAGE_BITS - 8) << 16;
2510 REG_WR(bp, BNX2_CTX_COMMAND, val);
Michael Chan641bdcd2007-06-04 21:22:24 -07002511 for (i = 0; i < 10; i++) {
2512 val = REG_RD(bp, BNX2_CTX_COMMAND);
2513 if (!(val & BNX2_CTX_COMMAND_MEM_INIT))
2514 break;
2515 udelay(2);
2516 }
2517 if (val & BNX2_CTX_COMMAND_MEM_INIT)
2518 return -EBUSY;
2519
Michael Chan59b47d82006-11-19 14:10:45 -08002520 for (i = 0; i < bp->ctx_pages; i++) {
2521 int j;
2522
Michael Chan352f7682008-05-02 16:57:26 -07002523 if (bp->ctx_blk[i])
2524 memset(bp->ctx_blk[i], 0, BCM_PAGE_SIZE);
2525 else
2526 return -ENOMEM;
2527
Michael Chan59b47d82006-11-19 14:10:45 -08002528 REG_WR(bp, BNX2_CTX_HOST_PAGE_TBL_DATA0,
2529 (bp->ctx_blk_mapping[i] & 0xffffffff) |
2530 BNX2_CTX_HOST_PAGE_TBL_DATA0_VALID);
2531 REG_WR(bp, BNX2_CTX_HOST_PAGE_TBL_DATA1,
2532 (u64) bp->ctx_blk_mapping[i] >> 32);
2533 REG_WR(bp, BNX2_CTX_HOST_PAGE_TBL_CTRL, i |
2534 BNX2_CTX_HOST_PAGE_TBL_CTRL_WRITE_REQ);
2535 for (j = 0; j < 10; j++) {
2536
2537 val = REG_RD(bp, BNX2_CTX_HOST_PAGE_TBL_CTRL);
2538 if (!(val & BNX2_CTX_HOST_PAGE_TBL_CTRL_WRITE_REQ))
2539 break;
2540 udelay(5);
2541 }
2542 if (val & BNX2_CTX_HOST_PAGE_TBL_CTRL_WRITE_REQ) {
2543 ret = -EBUSY;
2544 break;
2545 }
2546 }
2547 return ret;
2548}
2549
Michael Chanb6016b72005-05-26 13:03:09 -07002550static void
2551bnx2_init_context(struct bnx2 *bp)
2552{
2553 u32 vcid;
2554
2555 vcid = 96;
2556 while (vcid) {
2557 u32 vcid_addr, pcid_addr, offset;
Michael Chan7947b202007-06-04 21:17:10 -07002558 int i;
Michael Chanb6016b72005-05-26 13:03:09 -07002559
2560 vcid--;
2561
2562 if (CHIP_ID(bp) == CHIP_ID_5706_A0) {
2563 u32 new_vcid;
2564
2565 vcid_addr = GET_PCID_ADDR(vcid);
2566 if (vcid & 0x8) {
2567 new_vcid = 0x60 + (vcid & 0xf0) + (vcid & 0x7);
2568 }
2569 else {
2570 new_vcid = vcid;
2571 }
2572 pcid_addr = GET_PCID_ADDR(new_vcid);
2573 }
2574 else {
2575 vcid_addr = GET_CID_ADDR(vcid);
2576 pcid_addr = vcid_addr;
2577 }
2578
Michael Chan7947b202007-06-04 21:17:10 -07002579 for (i = 0; i < (CTX_SIZE / PHY_CTX_SIZE); i++) {
2580 vcid_addr += (i << PHY_CTX_SHIFT);
2581 pcid_addr += (i << PHY_CTX_SHIFT);
Michael Chanb6016b72005-05-26 13:03:09 -07002582
Michael Chan5d5d0012007-12-12 11:17:43 -08002583 REG_WR(bp, BNX2_CTX_VIRT_ADDR, vcid_addr);
Michael Chan7947b202007-06-04 21:17:10 -07002584 REG_WR(bp, BNX2_CTX_PAGE_TBL, pcid_addr);
2585
2586 /* Zero out the context. */
2587 for (offset = 0; offset < PHY_CTX_SIZE; offset += 4)
Michael Chan62a83132008-01-29 21:35:40 -08002588 bnx2_ctx_wr(bp, vcid_addr, offset, 0);
Michael Chanb6016b72005-05-26 13:03:09 -07002589 }
Michael Chanb6016b72005-05-26 13:03:09 -07002590 }
2591}
2592
2593static int
2594bnx2_alloc_bad_rbuf(struct bnx2 *bp)
2595{
2596 u16 *good_mbuf;
2597 u32 good_mbuf_cnt;
2598 u32 val;
2599
2600 good_mbuf = kmalloc(512 * sizeof(u16), GFP_KERNEL);
2601 if (good_mbuf == NULL) {
2602 printk(KERN_ERR PFX "Failed to allocate memory in "
2603 "bnx2_alloc_bad_rbuf\n");
2604 return -ENOMEM;
2605 }
2606
2607 REG_WR(bp, BNX2_MISC_ENABLE_SET_BITS,
2608 BNX2_MISC_ENABLE_SET_BITS_RX_MBUF_ENABLE);
2609
2610 good_mbuf_cnt = 0;
2611
2612 /* Allocate a bunch of mbufs and save the good ones in an array. */
Michael Chan2726d6e2008-01-29 21:35:05 -08002613 val = bnx2_reg_rd_ind(bp, BNX2_RBUF_STATUS1);
Michael Chanb6016b72005-05-26 13:03:09 -07002614 while (val & BNX2_RBUF_STATUS1_FREE_COUNT) {
Michael Chan2726d6e2008-01-29 21:35:05 -08002615 bnx2_reg_wr_ind(bp, BNX2_RBUF_COMMAND,
2616 BNX2_RBUF_COMMAND_ALLOC_REQ);
Michael Chanb6016b72005-05-26 13:03:09 -07002617
Michael Chan2726d6e2008-01-29 21:35:05 -08002618 val = bnx2_reg_rd_ind(bp, BNX2_RBUF_FW_BUF_ALLOC);
Michael Chanb6016b72005-05-26 13:03:09 -07002619
2620 val &= BNX2_RBUF_FW_BUF_ALLOC_VALUE;
2621
2622 /* The addresses with Bit 9 set are bad memory blocks. */
2623 if (!(val & (1 << 9))) {
2624 good_mbuf[good_mbuf_cnt] = (u16) val;
2625 good_mbuf_cnt++;
2626 }
2627
Michael Chan2726d6e2008-01-29 21:35:05 -08002628 val = bnx2_reg_rd_ind(bp, BNX2_RBUF_STATUS1);
Michael Chanb6016b72005-05-26 13:03:09 -07002629 }
2630
2631 /* Free the good ones back to the mbuf pool thus discarding
2632 * all the bad ones. */
2633 while (good_mbuf_cnt) {
2634 good_mbuf_cnt--;
2635
2636 val = good_mbuf[good_mbuf_cnt];
2637 val = (val << 9) | val | 1;
2638
Michael Chan2726d6e2008-01-29 21:35:05 -08002639 bnx2_reg_wr_ind(bp, BNX2_RBUF_FW_BUF_FREE, val);
Michael Chanb6016b72005-05-26 13:03:09 -07002640 }
2641 kfree(good_mbuf);
2642 return 0;
2643}
2644
2645static void
Benjamin Li5fcaed02008-07-14 22:39:52 -07002646bnx2_set_mac_addr(struct bnx2 *bp, u8 *mac_addr, u32 pos)
Michael Chanb6016b72005-05-26 13:03:09 -07002647{
2648 u32 val;
Michael Chanb6016b72005-05-26 13:03:09 -07002649
2650 val = (mac_addr[0] << 8) | mac_addr[1];
2651
Benjamin Li5fcaed02008-07-14 22:39:52 -07002652 REG_WR(bp, BNX2_EMAC_MAC_MATCH0 + (pos * 8), val);
Michael Chanb6016b72005-05-26 13:03:09 -07002653
Jeff Garzik6aa20a22006-09-13 13:24:59 -04002654 val = (mac_addr[2] << 24) | (mac_addr[3] << 16) |
Michael Chanb6016b72005-05-26 13:03:09 -07002655 (mac_addr[4] << 8) | mac_addr[5];
2656
Benjamin Li5fcaed02008-07-14 22:39:52 -07002657 REG_WR(bp, BNX2_EMAC_MAC_MATCH1 + (pos * 8), val);
Michael Chanb6016b72005-05-26 13:03:09 -07002658}
2659
2660static inline int
Michael Chanbb4f98a2008-06-19 16:38:19 -07002661bnx2_alloc_rx_page(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr, u16 index)
Michael Chan47bf4242007-12-12 11:19:12 -08002662{
2663 dma_addr_t mapping;
Michael Chanbb4f98a2008-06-19 16:38:19 -07002664 struct sw_pg *rx_pg = &rxr->rx_pg_ring[index];
Michael Chan47bf4242007-12-12 11:19:12 -08002665 struct rx_bd *rxbd =
Michael Chanbb4f98a2008-06-19 16:38:19 -07002666 &rxr->rx_pg_desc_ring[RX_RING(index)][RX_IDX(index)];
Michael Chan47bf4242007-12-12 11:19:12 -08002667 struct page *page = alloc_page(GFP_ATOMIC);
2668
2669 if (!page)
2670 return -ENOMEM;
2671 mapping = pci_map_page(bp->pdev, page, 0, PAGE_SIZE,
2672 PCI_DMA_FROMDEVICE);
Benjamin Li3d16af82008-10-09 12:26:41 -07002673 if (pci_dma_mapping_error(bp->pdev, mapping)) {
2674 __free_page(page);
2675 return -EIO;
2676 }
2677
Michael Chan47bf4242007-12-12 11:19:12 -08002678 rx_pg->page = page;
2679 pci_unmap_addr_set(rx_pg, mapping, mapping);
2680 rxbd->rx_bd_haddr_hi = (u64) mapping >> 32;
2681 rxbd->rx_bd_haddr_lo = (u64) mapping & 0xffffffff;
2682 return 0;
2683}
2684
2685static void
Michael Chanbb4f98a2008-06-19 16:38:19 -07002686bnx2_free_rx_page(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr, u16 index)
Michael Chan47bf4242007-12-12 11:19:12 -08002687{
Michael Chanbb4f98a2008-06-19 16:38:19 -07002688 struct sw_pg *rx_pg = &rxr->rx_pg_ring[index];
Michael Chan47bf4242007-12-12 11:19:12 -08002689 struct page *page = rx_pg->page;
2690
2691 if (!page)
2692 return;
2693
2694 pci_unmap_page(bp->pdev, pci_unmap_addr(rx_pg, mapping), PAGE_SIZE,
2695 PCI_DMA_FROMDEVICE);
2696
2697 __free_page(page);
2698 rx_pg->page = NULL;
2699}
2700
2701static inline int
Michael Chanbb4f98a2008-06-19 16:38:19 -07002702bnx2_alloc_rx_skb(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr, u16 index)
Michael Chanb6016b72005-05-26 13:03:09 -07002703{
2704 struct sk_buff *skb;
Michael Chanbb4f98a2008-06-19 16:38:19 -07002705 struct sw_bd *rx_buf = &rxr->rx_buf_ring[index];
Michael Chanb6016b72005-05-26 13:03:09 -07002706 dma_addr_t mapping;
Michael Chanbb4f98a2008-06-19 16:38:19 -07002707 struct rx_bd *rxbd = &rxr->rx_desc_ring[RX_RING(index)][RX_IDX(index)];
Michael Chanb6016b72005-05-26 13:03:09 -07002708 unsigned long align;
2709
Michael Chan932f3772006-08-15 01:39:36 -07002710 skb = netdev_alloc_skb(bp->dev, bp->rx_buf_size);
Michael Chanb6016b72005-05-26 13:03:09 -07002711 if (skb == NULL) {
2712 return -ENOMEM;
2713 }
2714
Michael Chan59b47d82006-11-19 14:10:45 -08002715 if (unlikely((align = (unsigned long) skb->data & (BNX2_RX_ALIGN - 1))))
2716 skb_reserve(skb, BNX2_RX_ALIGN - align);
Michael Chanb6016b72005-05-26 13:03:09 -07002717
Michael Chanb6016b72005-05-26 13:03:09 -07002718 mapping = pci_map_single(bp->pdev, skb->data, bp->rx_buf_use_size,
2719 PCI_DMA_FROMDEVICE);
Benjamin Li3d16af82008-10-09 12:26:41 -07002720 if (pci_dma_mapping_error(bp->pdev, mapping)) {
2721 dev_kfree_skb(skb);
2722 return -EIO;
2723 }
Michael Chanb6016b72005-05-26 13:03:09 -07002724
2725 rx_buf->skb = skb;
2726 pci_unmap_addr_set(rx_buf, mapping, mapping);
2727
2728 rxbd->rx_bd_haddr_hi = (u64) mapping >> 32;
2729 rxbd->rx_bd_haddr_lo = (u64) mapping & 0xffffffff;
2730
Michael Chanbb4f98a2008-06-19 16:38:19 -07002731 rxr->rx_prod_bseq += bp->rx_buf_use_size;
Michael Chanb6016b72005-05-26 13:03:09 -07002732
2733 return 0;
2734}
2735
Michael Chanda3e4fb2007-05-03 13:24:23 -07002736static int
Michael Chan35efa7c2007-12-20 19:56:37 -08002737bnx2_phy_event_is_set(struct bnx2 *bp, struct bnx2_napi *bnapi, u32 event)
Michael Chanda3e4fb2007-05-03 13:24:23 -07002738{
Michael Chan43e80b82008-06-19 16:41:08 -07002739 struct status_block *sblk = bnapi->status_blk.msi;
Michael Chanda3e4fb2007-05-03 13:24:23 -07002740 u32 new_link_state, old_link_state;
2741 int is_set = 1;
2742
2743 new_link_state = sblk->status_attn_bits & event;
2744 old_link_state = sblk->status_attn_bits_ack & event;
2745 if (new_link_state != old_link_state) {
2746 if (new_link_state)
2747 REG_WR(bp, BNX2_PCICFG_STATUS_BIT_SET_CMD, event);
2748 else
2749 REG_WR(bp, BNX2_PCICFG_STATUS_BIT_CLEAR_CMD, event);
2750 } else
2751 is_set = 0;
2752
2753 return is_set;
2754}
2755
Michael Chanb6016b72005-05-26 13:03:09 -07002756static void
Michael Chan35efa7c2007-12-20 19:56:37 -08002757bnx2_phy_int(struct bnx2 *bp, struct bnx2_napi *bnapi)
Michael Chanb6016b72005-05-26 13:03:09 -07002758{
Michael Chan74ecc622008-05-02 16:56:16 -07002759 spin_lock(&bp->phy_lock);
2760
2761 if (bnx2_phy_event_is_set(bp, bnapi, STATUS_ATTN_BITS_LINK_STATE))
Michael Chanb6016b72005-05-26 13:03:09 -07002762 bnx2_set_link(bp);
Michael Chan35efa7c2007-12-20 19:56:37 -08002763 if (bnx2_phy_event_is_set(bp, bnapi, STATUS_ATTN_BITS_TIMER_ABORT))
Michael Chan0d8a6572007-07-07 22:49:43 -07002764 bnx2_set_remote_link(bp);
2765
Michael Chan74ecc622008-05-02 16:56:16 -07002766 spin_unlock(&bp->phy_lock);
2767
Michael Chanb6016b72005-05-26 13:03:09 -07002768}
2769
Michael Chanead72702007-12-20 19:55:39 -08002770static inline u16
Michael Chan35efa7c2007-12-20 19:56:37 -08002771bnx2_get_hw_tx_cons(struct bnx2_napi *bnapi)
Michael Chanead72702007-12-20 19:55:39 -08002772{
2773 u16 cons;
2774
Michael Chan43e80b82008-06-19 16:41:08 -07002775 /* Tell compiler that status block fields can change. */
2776 barrier();
2777 cons = *bnapi->hw_tx_cons_ptr;
Michael Chan581daf72009-05-06 16:46:47 -07002778 barrier();
Michael Chanead72702007-12-20 19:55:39 -08002779 if (unlikely((cons & MAX_TX_DESC_CNT) == MAX_TX_DESC_CNT))
2780 cons++;
2781 return cons;
2782}
2783
Michael Chan57851d82007-12-20 20:01:44 -08002784static int
2785bnx2_tx_int(struct bnx2 *bp, struct bnx2_napi *bnapi, int budget)
Michael Chanb6016b72005-05-26 13:03:09 -07002786{
Michael Chan35e90102008-06-19 16:37:42 -07002787 struct bnx2_tx_ring_info *txr = &bnapi->tx_ring;
Michael Chanb6016b72005-05-26 13:03:09 -07002788 u16 hw_cons, sw_cons, sw_ring_cons;
Benjamin Li706bf242008-07-18 17:55:11 -07002789 int tx_pkt = 0, index;
2790 struct netdev_queue *txq;
2791
2792 index = (bnapi - bp->bnx2_napi);
2793 txq = netdev_get_tx_queue(bp->dev, index);
Michael Chanb6016b72005-05-26 13:03:09 -07002794
Michael Chan35efa7c2007-12-20 19:56:37 -08002795 hw_cons = bnx2_get_hw_tx_cons(bnapi);
Michael Chan35e90102008-06-19 16:37:42 -07002796 sw_cons = txr->tx_cons;
Michael Chanb6016b72005-05-26 13:03:09 -07002797
2798 while (sw_cons != hw_cons) {
Benjamin Li3d16af82008-10-09 12:26:41 -07002799 struct sw_tx_bd *tx_buf;
Michael Chanb6016b72005-05-26 13:03:09 -07002800 struct sk_buff *skb;
2801 int i, last;
2802
2803 sw_ring_cons = TX_RING_IDX(sw_cons);
2804
Michael Chan35e90102008-06-19 16:37:42 -07002805 tx_buf = &txr->tx_buf_ring[sw_ring_cons];
Michael Chanb6016b72005-05-26 13:03:09 -07002806 skb = tx_buf->skb;
Arjan van de Ven1d39ed52006-12-12 14:06:23 +01002807
Eric Dumazetd62fda02009-05-12 20:48:02 +00002808 /* prefetch skb_end_pointer() to speedup skb_shinfo(skb) */
2809 prefetch(&skb->end);
2810
Michael Chanb6016b72005-05-26 13:03:09 -07002811 /* partial BD completions possible with TSO packets */
Eric Dumazetd62fda02009-05-12 20:48:02 +00002812 if (tx_buf->is_gso) {
Michael Chanb6016b72005-05-26 13:03:09 -07002813 u16 last_idx, last_ring_idx;
2814
Eric Dumazetd62fda02009-05-12 20:48:02 +00002815 last_idx = sw_cons + tx_buf->nr_frags + 1;
2816 last_ring_idx = sw_ring_cons + tx_buf->nr_frags + 1;
Michael Chanb6016b72005-05-26 13:03:09 -07002817 if (unlikely(last_ring_idx >= MAX_TX_DESC_CNT)) {
2818 last_idx++;
2819 }
2820 if (((s16) ((s16) last_idx - (s16) hw_cons)) > 0) {
2821 break;
2822 }
2823 }
Arjan van de Ven1d39ed52006-12-12 14:06:23 +01002824
Alexander Duycke95524a2009-12-02 16:47:57 +00002825 pci_unmap_single(bp->pdev, pci_unmap_addr(tx_buf, mapping),
2826 skb_headlen(skb), PCI_DMA_TODEVICE);
Michael Chanb6016b72005-05-26 13:03:09 -07002827
2828 tx_buf->skb = NULL;
Eric Dumazetd62fda02009-05-12 20:48:02 +00002829 last = tx_buf->nr_frags;
Michael Chanb6016b72005-05-26 13:03:09 -07002830
2831 for (i = 0; i < last; i++) {
2832 sw_cons = NEXT_TX_BD(sw_cons);
Alexander Duycke95524a2009-12-02 16:47:57 +00002833
2834 pci_unmap_page(bp->pdev,
2835 pci_unmap_addr(
2836 &txr->tx_buf_ring[TX_RING_IDX(sw_cons)],
2837 mapping),
2838 skb_shinfo(skb)->frags[i].size,
2839 PCI_DMA_TODEVICE);
Michael Chanb6016b72005-05-26 13:03:09 -07002840 }
2841
2842 sw_cons = NEXT_TX_BD(sw_cons);
2843
Michael Chan745720e2006-06-29 12:37:41 -07002844 dev_kfree_skb(skb);
Michael Chan57851d82007-12-20 20:01:44 -08002845 tx_pkt++;
2846 if (tx_pkt == budget)
2847 break;
Michael Chanb6016b72005-05-26 13:03:09 -07002848
Eric Dumazetd62fda02009-05-12 20:48:02 +00002849 if (hw_cons == sw_cons)
2850 hw_cons = bnx2_get_hw_tx_cons(bnapi);
Michael Chanb6016b72005-05-26 13:03:09 -07002851 }
2852
Michael Chan35e90102008-06-19 16:37:42 -07002853 txr->hw_tx_cons = hw_cons;
2854 txr->tx_cons = sw_cons;
Benjamin Li706bf242008-07-18 17:55:11 -07002855
Michael Chan2f8af122006-08-15 01:39:10 -07002856 /* Need to make the tx_cons update visible to bnx2_start_xmit()
Benjamin Li706bf242008-07-18 17:55:11 -07002857 * before checking for netif_tx_queue_stopped(). Without the
Michael Chan2f8af122006-08-15 01:39:10 -07002858 * memory barrier, there is a small possibility that bnx2_start_xmit()
2859 * will miss it and cause the queue to be stopped forever.
2860 */
2861 smp_mb();
Michael Chanb6016b72005-05-26 13:03:09 -07002862
Benjamin Li706bf242008-07-18 17:55:11 -07002863 if (unlikely(netif_tx_queue_stopped(txq)) &&
Michael Chan35e90102008-06-19 16:37:42 -07002864 (bnx2_tx_avail(bp, txr) > bp->tx_wake_thresh)) {
Benjamin Li706bf242008-07-18 17:55:11 -07002865 __netif_tx_lock(txq, smp_processor_id());
2866 if ((netif_tx_queue_stopped(txq)) &&
Michael Chan35e90102008-06-19 16:37:42 -07002867 (bnx2_tx_avail(bp, txr) > bp->tx_wake_thresh))
Benjamin Li706bf242008-07-18 17:55:11 -07002868 netif_tx_wake_queue(txq);
2869 __netif_tx_unlock(txq);
Michael Chanb6016b72005-05-26 13:03:09 -07002870 }
Benjamin Li706bf242008-07-18 17:55:11 -07002871
Michael Chan57851d82007-12-20 20:01:44 -08002872 return tx_pkt;
Michael Chanb6016b72005-05-26 13:03:09 -07002873}
2874
Michael Chan1db82f22007-12-12 11:19:35 -08002875static void
Michael Chanbb4f98a2008-06-19 16:38:19 -07002876bnx2_reuse_rx_skb_pages(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr,
Michael Chana1f60192007-12-20 19:57:19 -08002877 struct sk_buff *skb, int count)
Michael Chan1db82f22007-12-12 11:19:35 -08002878{
2879 struct sw_pg *cons_rx_pg, *prod_rx_pg;
2880 struct rx_bd *cons_bd, *prod_bd;
Michael Chan1db82f22007-12-12 11:19:35 -08002881 int i;
Benjamin Li3d16af82008-10-09 12:26:41 -07002882 u16 hw_prod, prod;
Michael Chanbb4f98a2008-06-19 16:38:19 -07002883 u16 cons = rxr->rx_pg_cons;
Michael Chan1db82f22007-12-12 11:19:35 -08002884
Benjamin Li3d16af82008-10-09 12:26:41 -07002885 cons_rx_pg = &rxr->rx_pg_ring[cons];
2886
2887 /* The caller was unable to allocate a new page to replace the
2888 * last one in the frags array, so we need to recycle that page
2889 * and then free the skb.
2890 */
2891 if (skb) {
2892 struct page *page;
2893 struct skb_shared_info *shinfo;
2894
2895 shinfo = skb_shinfo(skb);
2896 shinfo->nr_frags--;
2897 page = shinfo->frags[shinfo->nr_frags].page;
2898 shinfo->frags[shinfo->nr_frags].page = NULL;
2899
2900 cons_rx_pg->page = page;
2901 dev_kfree_skb(skb);
2902 }
2903
2904 hw_prod = rxr->rx_pg_prod;
2905
Michael Chan1db82f22007-12-12 11:19:35 -08002906 for (i = 0; i < count; i++) {
2907 prod = RX_PG_RING_IDX(hw_prod);
2908
Michael Chanbb4f98a2008-06-19 16:38:19 -07002909 prod_rx_pg = &rxr->rx_pg_ring[prod];
2910 cons_rx_pg = &rxr->rx_pg_ring[cons];
2911 cons_bd = &rxr->rx_pg_desc_ring[RX_RING(cons)][RX_IDX(cons)];
2912 prod_bd = &rxr->rx_pg_desc_ring[RX_RING(prod)][RX_IDX(prod)];
Michael Chan1db82f22007-12-12 11:19:35 -08002913
Michael Chan1db82f22007-12-12 11:19:35 -08002914 if (prod != cons) {
2915 prod_rx_pg->page = cons_rx_pg->page;
2916 cons_rx_pg->page = NULL;
2917 pci_unmap_addr_set(prod_rx_pg, mapping,
2918 pci_unmap_addr(cons_rx_pg, mapping));
2919
2920 prod_bd->rx_bd_haddr_hi = cons_bd->rx_bd_haddr_hi;
2921 prod_bd->rx_bd_haddr_lo = cons_bd->rx_bd_haddr_lo;
2922
2923 }
2924 cons = RX_PG_RING_IDX(NEXT_RX_BD(cons));
2925 hw_prod = NEXT_RX_BD(hw_prod);
2926 }
Michael Chanbb4f98a2008-06-19 16:38:19 -07002927 rxr->rx_pg_prod = hw_prod;
2928 rxr->rx_pg_cons = cons;
Michael Chan1db82f22007-12-12 11:19:35 -08002929}
2930
Michael Chanb6016b72005-05-26 13:03:09 -07002931static inline void
Michael Chanbb4f98a2008-06-19 16:38:19 -07002932bnx2_reuse_rx_skb(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr,
2933 struct sk_buff *skb, u16 cons, u16 prod)
Michael Chanb6016b72005-05-26 13:03:09 -07002934{
Michael Chan236b6392006-03-20 17:49:02 -08002935 struct sw_bd *cons_rx_buf, *prod_rx_buf;
2936 struct rx_bd *cons_bd, *prod_bd;
2937
Michael Chanbb4f98a2008-06-19 16:38:19 -07002938 cons_rx_buf = &rxr->rx_buf_ring[cons];
2939 prod_rx_buf = &rxr->rx_buf_ring[prod];
Michael Chanb6016b72005-05-26 13:03:09 -07002940
2941 pci_dma_sync_single_for_device(bp->pdev,
2942 pci_unmap_addr(cons_rx_buf, mapping),
Benjamin Li601d3d12008-05-16 22:19:35 -07002943 BNX2_RX_OFFSET + BNX2_RX_COPY_THRESH, PCI_DMA_FROMDEVICE);
Michael Chanb6016b72005-05-26 13:03:09 -07002944
Michael Chanbb4f98a2008-06-19 16:38:19 -07002945 rxr->rx_prod_bseq += bp->rx_buf_use_size;
Michael Chan236b6392006-03-20 17:49:02 -08002946
2947 prod_rx_buf->skb = skb;
2948
2949 if (cons == prod)
2950 return;
2951
Michael Chanb6016b72005-05-26 13:03:09 -07002952 pci_unmap_addr_set(prod_rx_buf, mapping,
2953 pci_unmap_addr(cons_rx_buf, mapping));
2954
Michael Chanbb4f98a2008-06-19 16:38:19 -07002955 cons_bd = &rxr->rx_desc_ring[RX_RING(cons)][RX_IDX(cons)];
2956 prod_bd = &rxr->rx_desc_ring[RX_RING(prod)][RX_IDX(prod)];
Michael Chan236b6392006-03-20 17:49:02 -08002957 prod_bd->rx_bd_haddr_hi = cons_bd->rx_bd_haddr_hi;
2958 prod_bd->rx_bd_haddr_lo = cons_bd->rx_bd_haddr_lo;
Michael Chanb6016b72005-05-26 13:03:09 -07002959}
2960
Michael Chan85833c62007-12-12 11:17:01 -08002961static int
Michael Chanbb4f98a2008-06-19 16:38:19 -07002962bnx2_rx_skb(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr, struct sk_buff *skb,
Michael Chana1f60192007-12-20 19:57:19 -08002963 unsigned int len, unsigned int hdr_len, dma_addr_t dma_addr,
2964 u32 ring_idx)
Michael Chan85833c62007-12-12 11:17:01 -08002965{
2966 int err;
2967 u16 prod = ring_idx & 0xffff;
2968
Michael Chanbb4f98a2008-06-19 16:38:19 -07002969 err = bnx2_alloc_rx_skb(bp, rxr, prod);
Michael Chan85833c62007-12-12 11:17:01 -08002970 if (unlikely(err)) {
Michael Chanbb4f98a2008-06-19 16:38:19 -07002971 bnx2_reuse_rx_skb(bp, rxr, skb, (u16) (ring_idx >> 16), prod);
Michael Chan1db82f22007-12-12 11:19:35 -08002972 if (hdr_len) {
2973 unsigned int raw_len = len + 4;
2974 int pages = PAGE_ALIGN(raw_len - hdr_len) >> PAGE_SHIFT;
2975
Michael Chanbb4f98a2008-06-19 16:38:19 -07002976 bnx2_reuse_rx_skb_pages(bp, rxr, NULL, pages);
Michael Chan1db82f22007-12-12 11:19:35 -08002977 }
Michael Chan85833c62007-12-12 11:17:01 -08002978 return err;
2979 }
2980
Benjamin Lid89cb6a2008-05-16 22:18:57 -07002981 skb_reserve(skb, BNX2_RX_OFFSET);
Michael Chan85833c62007-12-12 11:17:01 -08002982 pci_unmap_single(bp->pdev, dma_addr, bp->rx_buf_use_size,
2983 PCI_DMA_FROMDEVICE);
2984
Michael Chan1db82f22007-12-12 11:19:35 -08002985 if (hdr_len == 0) {
2986 skb_put(skb, len);
2987 return 0;
2988 } else {
2989 unsigned int i, frag_len, frag_size, pages;
2990 struct sw_pg *rx_pg;
Michael Chanbb4f98a2008-06-19 16:38:19 -07002991 u16 pg_cons = rxr->rx_pg_cons;
2992 u16 pg_prod = rxr->rx_pg_prod;
Michael Chan1db82f22007-12-12 11:19:35 -08002993
2994 frag_size = len + 4 - hdr_len;
2995 pages = PAGE_ALIGN(frag_size) >> PAGE_SHIFT;
2996 skb_put(skb, hdr_len);
2997
2998 for (i = 0; i < pages; i++) {
Benjamin Li3d16af82008-10-09 12:26:41 -07002999 dma_addr_t mapping_old;
3000
Michael Chan1db82f22007-12-12 11:19:35 -08003001 frag_len = min(frag_size, (unsigned int) PAGE_SIZE);
3002 if (unlikely(frag_len <= 4)) {
3003 unsigned int tail = 4 - frag_len;
3004
Michael Chanbb4f98a2008-06-19 16:38:19 -07003005 rxr->rx_pg_cons = pg_cons;
3006 rxr->rx_pg_prod = pg_prod;
3007 bnx2_reuse_rx_skb_pages(bp, rxr, NULL,
Michael Chana1f60192007-12-20 19:57:19 -08003008 pages - i);
Michael Chan1db82f22007-12-12 11:19:35 -08003009 skb->len -= tail;
3010 if (i == 0) {
3011 skb->tail -= tail;
3012 } else {
3013 skb_frag_t *frag =
3014 &skb_shinfo(skb)->frags[i - 1];
3015 frag->size -= tail;
3016 skb->data_len -= tail;
3017 skb->truesize -= tail;
3018 }
3019 return 0;
3020 }
Michael Chanbb4f98a2008-06-19 16:38:19 -07003021 rx_pg = &rxr->rx_pg_ring[pg_cons];
Michael Chan1db82f22007-12-12 11:19:35 -08003022
Benjamin Li3d16af82008-10-09 12:26:41 -07003023 /* Don't unmap yet. If we're unable to allocate a new
3024 * page, we need to recycle the page and the DMA addr.
3025 */
3026 mapping_old = pci_unmap_addr(rx_pg, mapping);
Michael Chan1db82f22007-12-12 11:19:35 -08003027 if (i == pages - 1)
3028 frag_len -= 4;
3029
3030 skb_fill_page_desc(skb, i, rx_pg->page, 0, frag_len);
3031 rx_pg->page = NULL;
3032
Michael Chanbb4f98a2008-06-19 16:38:19 -07003033 err = bnx2_alloc_rx_page(bp, rxr,
3034 RX_PG_RING_IDX(pg_prod));
Michael Chan1db82f22007-12-12 11:19:35 -08003035 if (unlikely(err)) {
Michael Chanbb4f98a2008-06-19 16:38:19 -07003036 rxr->rx_pg_cons = pg_cons;
3037 rxr->rx_pg_prod = pg_prod;
3038 bnx2_reuse_rx_skb_pages(bp, rxr, skb,
Michael Chana1f60192007-12-20 19:57:19 -08003039 pages - i);
Michael Chan1db82f22007-12-12 11:19:35 -08003040 return err;
3041 }
3042
Benjamin Li3d16af82008-10-09 12:26:41 -07003043 pci_unmap_page(bp->pdev, mapping_old,
3044 PAGE_SIZE, PCI_DMA_FROMDEVICE);
3045
Michael Chan1db82f22007-12-12 11:19:35 -08003046 frag_size -= frag_len;
3047 skb->data_len += frag_len;
3048 skb->truesize += frag_len;
3049 skb->len += frag_len;
3050
3051 pg_prod = NEXT_RX_BD(pg_prod);
3052 pg_cons = RX_PG_RING_IDX(NEXT_RX_BD(pg_cons));
3053 }
Michael Chanbb4f98a2008-06-19 16:38:19 -07003054 rxr->rx_pg_prod = pg_prod;
3055 rxr->rx_pg_cons = pg_cons;
Michael Chan1db82f22007-12-12 11:19:35 -08003056 }
Michael Chan85833c62007-12-12 11:17:01 -08003057 return 0;
3058}
3059
Michael Chanc09c2622007-12-10 17:18:37 -08003060static inline u16
Michael Chan35efa7c2007-12-20 19:56:37 -08003061bnx2_get_hw_rx_cons(struct bnx2_napi *bnapi)
Michael Chanc09c2622007-12-10 17:18:37 -08003062{
Michael Chanbb4f98a2008-06-19 16:38:19 -07003063 u16 cons;
3064
Michael Chan43e80b82008-06-19 16:41:08 -07003065 /* Tell compiler that status block fields can change. */
3066 barrier();
3067 cons = *bnapi->hw_rx_cons_ptr;
Michael Chan581daf72009-05-06 16:46:47 -07003068 barrier();
Michael Chanc09c2622007-12-10 17:18:37 -08003069 if (unlikely((cons & MAX_RX_DESC_CNT) == MAX_RX_DESC_CNT))
3070 cons++;
3071 return cons;
3072}
3073
Michael Chanb6016b72005-05-26 13:03:09 -07003074static int
Michael Chan35efa7c2007-12-20 19:56:37 -08003075bnx2_rx_int(struct bnx2 *bp, struct bnx2_napi *bnapi, int budget)
Michael Chanb6016b72005-05-26 13:03:09 -07003076{
Michael Chanbb4f98a2008-06-19 16:38:19 -07003077 struct bnx2_rx_ring_info *rxr = &bnapi->rx_ring;
Michael Chanb6016b72005-05-26 13:03:09 -07003078 u16 hw_cons, sw_cons, sw_ring_cons, sw_prod, sw_ring_prod;
3079 struct l2_fhdr *rx_hdr;
Michael Chan1db82f22007-12-12 11:19:35 -08003080 int rx_pkt = 0, pg_ring_used = 0;
Michael Chanb6016b72005-05-26 13:03:09 -07003081
Michael Chan35efa7c2007-12-20 19:56:37 -08003082 hw_cons = bnx2_get_hw_rx_cons(bnapi);
Michael Chanbb4f98a2008-06-19 16:38:19 -07003083 sw_cons = rxr->rx_cons;
3084 sw_prod = rxr->rx_prod;
Michael Chanb6016b72005-05-26 13:03:09 -07003085
3086 /* Memory barrier necessary as speculative reads of the rx
3087 * buffer can be ahead of the index in the status block
3088 */
3089 rmb();
3090 while (sw_cons != hw_cons) {
Michael Chan1db82f22007-12-12 11:19:35 -08003091 unsigned int len, hdr_len;
Michael Chanade2bfe2006-01-23 16:09:51 -08003092 u32 status;
Michael Chanb6016b72005-05-26 13:03:09 -07003093 struct sw_bd *rx_buf;
3094 struct sk_buff *skb;
Michael Chan236b6392006-03-20 17:49:02 -08003095 dma_addr_t dma_addr;
Michael Chanf22828e2008-08-14 15:30:14 -07003096 u16 vtag = 0;
3097 int hw_vlan __maybe_unused = 0;
Michael Chanb6016b72005-05-26 13:03:09 -07003098
3099 sw_ring_cons = RX_RING_IDX(sw_cons);
3100 sw_ring_prod = RX_RING_IDX(sw_prod);
3101
Michael Chanbb4f98a2008-06-19 16:38:19 -07003102 rx_buf = &rxr->rx_buf_ring[sw_ring_cons];
Michael Chanb6016b72005-05-26 13:03:09 -07003103 skb = rx_buf->skb;
Michael Chan236b6392006-03-20 17:49:02 -08003104
3105 rx_buf->skb = NULL;
3106
3107 dma_addr = pci_unmap_addr(rx_buf, mapping);
3108
3109 pci_dma_sync_single_for_cpu(bp->pdev, dma_addr,
Benjamin Li601d3d12008-05-16 22:19:35 -07003110 BNX2_RX_OFFSET + BNX2_RX_COPY_THRESH,
3111 PCI_DMA_FROMDEVICE);
Michael Chanb6016b72005-05-26 13:03:09 -07003112
3113 rx_hdr = (struct l2_fhdr *) skb->data;
Michael Chan1db82f22007-12-12 11:19:35 -08003114 len = rx_hdr->l2_fhdr_pkt_len;
Michael Chan990ec382009-02-12 16:54:13 -08003115 status = rx_hdr->l2_fhdr_status;
Michael Chanb6016b72005-05-26 13:03:09 -07003116
Michael Chan1db82f22007-12-12 11:19:35 -08003117 hdr_len = 0;
3118 if (status & L2_FHDR_STATUS_SPLIT) {
3119 hdr_len = rx_hdr->l2_fhdr_ip_xsum;
3120 pg_ring_used = 1;
3121 } else if (len > bp->rx_jumbo_thresh) {
3122 hdr_len = bp->rx_jumbo_thresh;
3123 pg_ring_used = 1;
3124 }
3125
Michael Chan990ec382009-02-12 16:54:13 -08003126 if (unlikely(status & (L2_FHDR_ERRORS_BAD_CRC |
3127 L2_FHDR_ERRORS_PHY_DECODE |
3128 L2_FHDR_ERRORS_ALIGNMENT |
3129 L2_FHDR_ERRORS_TOO_SHORT |
3130 L2_FHDR_ERRORS_GIANT_FRAME))) {
3131
3132 bnx2_reuse_rx_skb(bp, rxr, skb, sw_ring_cons,
3133 sw_ring_prod);
3134 if (pg_ring_used) {
3135 int pages;
3136
3137 pages = PAGE_ALIGN(len - hdr_len) >> PAGE_SHIFT;
3138
3139 bnx2_reuse_rx_skb_pages(bp, rxr, NULL, pages);
3140 }
3141 goto next_rx;
3142 }
3143
Michael Chan1db82f22007-12-12 11:19:35 -08003144 len -= 4;
Michael Chanb6016b72005-05-26 13:03:09 -07003145
Michael Chan5d5d0012007-12-12 11:17:43 -08003146 if (len <= bp->rx_copy_thresh) {
Michael Chanb6016b72005-05-26 13:03:09 -07003147 struct sk_buff *new_skb;
3148
Michael Chanf22828e2008-08-14 15:30:14 -07003149 new_skb = netdev_alloc_skb(bp->dev, len + 6);
Michael Chan85833c62007-12-12 11:17:01 -08003150 if (new_skb == NULL) {
Michael Chanbb4f98a2008-06-19 16:38:19 -07003151 bnx2_reuse_rx_skb(bp, rxr, skb, sw_ring_cons,
Michael Chan85833c62007-12-12 11:17:01 -08003152 sw_ring_prod);
3153 goto next_rx;
3154 }
Michael Chanb6016b72005-05-26 13:03:09 -07003155
3156 /* aligned copy */
Benjamin Lid89cb6a2008-05-16 22:18:57 -07003157 skb_copy_from_linear_data_offset(skb,
Michael Chanf22828e2008-08-14 15:30:14 -07003158 BNX2_RX_OFFSET - 6,
3159 new_skb->data, len + 6);
3160 skb_reserve(new_skb, 6);
Michael Chanb6016b72005-05-26 13:03:09 -07003161 skb_put(new_skb, len);
Michael Chanb6016b72005-05-26 13:03:09 -07003162
Michael Chanbb4f98a2008-06-19 16:38:19 -07003163 bnx2_reuse_rx_skb(bp, rxr, skb,
Michael Chanb6016b72005-05-26 13:03:09 -07003164 sw_ring_cons, sw_ring_prod);
3165
3166 skb = new_skb;
Michael Chanbb4f98a2008-06-19 16:38:19 -07003167 } else if (unlikely(bnx2_rx_skb(bp, rxr, skb, len, hdr_len,
Michael Chana1f60192007-12-20 19:57:19 -08003168 dma_addr, (sw_ring_cons << 16) | sw_ring_prod)))
Michael Chanb6016b72005-05-26 13:03:09 -07003169 goto next_rx;
Michael Chanb6016b72005-05-26 13:03:09 -07003170
Michael Chanf22828e2008-08-14 15:30:14 -07003171 if ((status & L2_FHDR_STATUS_L2_VLAN_TAG) &&
3172 !(bp->rx_mode & BNX2_EMAC_RX_MODE_KEEP_VLAN_TAG)) {
3173 vtag = rx_hdr->l2_fhdr_vlan_tag;
3174#ifdef BCM_VLAN
3175 if (bp->vlgrp)
3176 hw_vlan = 1;
3177 else
3178#endif
3179 {
3180 struct vlan_ethhdr *ve = (struct vlan_ethhdr *)
3181 __skb_push(skb, 4);
3182
3183 memmove(ve, skb->data + 4, ETH_ALEN * 2);
3184 ve->h_vlan_proto = htons(ETH_P_8021Q);
3185 ve->h_vlan_TCI = htons(vtag);
3186 len += 4;
3187 }
3188 }
3189
Michael Chanb6016b72005-05-26 13:03:09 -07003190 skb->protocol = eth_type_trans(skb, bp->dev);
3191
3192 if ((len > (bp->dev->mtu + ETH_HLEN)) &&
Alexey Dobriyand1e100b2006-06-11 20:57:17 -07003193 (ntohs(skb->protocol) != 0x8100)) {
Michael Chanb6016b72005-05-26 13:03:09 -07003194
Michael Chan745720e2006-06-29 12:37:41 -07003195 dev_kfree_skb(skb);
Michael Chanb6016b72005-05-26 13:03:09 -07003196 goto next_rx;
3197
3198 }
3199
Michael Chanb6016b72005-05-26 13:03:09 -07003200 skb->ip_summed = CHECKSUM_NONE;
3201 if (bp->rx_csum &&
3202 (status & (L2_FHDR_STATUS_TCP_SEGMENT |
3203 L2_FHDR_STATUS_UDP_DATAGRAM))) {
3204
Michael Chanade2bfe2006-01-23 16:09:51 -08003205 if (likely((status & (L2_FHDR_ERRORS_TCP_XSUM |
3206 L2_FHDR_ERRORS_UDP_XSUM)) == 0))
Michael Chanb6016b72005-05-26 13:03:09 -07003207 skb->ip_summed = CHECKSUM_UNNECESSARY;
3208 }
3209
David S. Miller0c8dfc82009-01-27 16:22:32 -08003210 skb_record_rx_queue(skb, bnapi - &bp->bnx2_napi[0]);
3211
Michael Chanb6016b72005-05-26 13:03:09 -07003212#ifdef BCM_VLAN
Michael Chanf22828e2008-08-14 15:30:14 -07003213 if (hw_vlan)
3214 vlan_hwaccel_receive_skb(skb, bp->vlgrp, vtag);
Michael Chanb6016b72005-05-26 13:03:09 -07003215 else
3216#endif
3217 netif_receive_skb(skb);
3218
Michael Chanb6016b72005-05-26 13:03:09 -07003219 rx_pkt++;
3220
3221next_rx:
Michael Chanb6016b72005-05-26 13:03:09 -07003222 sw_cons = NEXT_RX_BD(sw_cons);
3223 sw_prod = NEXT_RX_BD(sw_prod);
3224
3225 if ((rx_pkt == budget))
3226 break;
Michael Chanf4e418f2005-11-04 08:53:48 -08003227
3228 /* Refresh hw_cons to see if there is new work */
3229 if (sw_cons == hw_cons) {
Michael Chan35efa7c2007-12-20 19:56:37 -08003230 hw_cons = bnx2_get_hw_rx_cons(bnapi);
Michael Chanf4e418f2005-11-04 08:53:48 -08003231 rmb();
3232 }
Michael Chanb6016b72005-05-26 13:03:09 -07003233 }
Michael Chanbb4f98a2008-06-19 16:38:19 -07003234 rxr->rx_cons = sw_cons;
3235 rxr->rx_prod = sw_prod;
Michael Chanb6016b72005-05-26 13:03:09 -07003236
Michael Chan1db82f22007-12-12 11:19:35 -08003237 if (pg_ring_used)
Michael Chanbb4f98a2008-06-19 16:38:19 -07003238 REG_WR16(bp, rxr->rx_pg_bidx_addr, rxr->rx_pg_prod);
Michael Chan1db82f22007-12-12 11:19:35 -08003239
Michael Chanbb4f98a2008-06-19 16:38:19 -07003240 REG_WR16(bp, rxr->rx_bidx_addr, sw_prod);
Michael Chanb6016b72005-05-26 13:03:09 -07003241
Michael Chanbb4f98a2008-06-19 16:38:19 -07003242 REG_WR(bp, rxr->rx_bseq_addr, rxr->rx_prod_bseq);
Michael Chanb6016b72005-05-26 13:03:09 -07003243
3244 mmiowb();
3245
3246 return rx_pkt;
3247
3248}
3249
3250/* MSI ISR - The only difference between this and the INTx ISR
3251 * is that the MSI interrupt is always serviced.
3252 */
3253static irqreturn_t
David Howells7d12e782006-10-05 14:55:46 +01003254bnx2_msi(int irq, void *dev_instance)
Michael Chanb6016b72005-05-26 13:03:09 -07003255{
Michael Chanf0ea2e62008-06-19 16:41:57 -07003256 struct bnx2_napi *bnapi = dev_instance;
3257 struct bnx2 *bp = bnapi->bp;
Michael Chanb6016b72005-05-26 13:03:09 -07003258
Michael Chan43e80b82008-06-19 16:41:08 -07003259 prefetch(bnapi->status_blk.msi);
Michael Chanb6016b72005-05-26 13:03:09 -07003260 REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
3261 BNX2_PCICFG_INT_ACK_CMD_USE_INT_HC_PARAM |
3262 BNX2_PCICFG_INT_ACK_CMD_MASK_INT);
3263
3264 /* Return here if interrupt is disabled. */
Michael Chan73eef4c2005-08-25 15:39:15 -07003265 if (unlikely(atomic_read(&bp->intr_sem) != 0))
3266 return IRQ_HANDLED;
Michael Chanb6016b72005-05-26 13:03:09 -07003267
Ben Hutchings288379f2009-01-19 16:43:59 -08003268 napi_schedule(&bnapi->napi);
Michael Chanb6016b72005-05-26 13:03:09 -07003269
Michael Chan73eef4c2005-08-25 15:39:15 -07003270 return IRQ_HANDLED;
Michael Chanb6016b72005-05-26 13:03:09 -07003271}
3272
3273static irqreturn_t
Michael Chan8e6a72c2007-05-03 13:24:48 -07003274bnx2_msi_1shot(int irq, void *dev_instance)
3275{
Michael Chanf0ea2e62008-06-19 16:41:57 -07003276 struct bnx2_napi *bnapi = dev_instance;
3277 struct bnx2 *bp = bnapi->bp;
Michael Chan8e6a72c2007-05-03 13:24:48 -07003278
Michael Chan43e80b82008-06-19 16:41:08 -07003279 prefetch(bnapi->status_blk.msi);
Michael Chan8e6a72c2007-05-03 13:24:48 -07003280
3281 /* Return here if interrupt is disabled. */
3282 if (unlikely(atomic_read(&bp->intr_sem) != 0))
3283 return IRQ_HANDLED;
3284
Ben Hutchings288379f2009-01-19 16:43:59 -08003285 napi_schedule(&bnapi->napi);
Michael Chan8e6a72c2007-05-03 13:24:48 -07003286
3287 return IRQ_HANDLED;
3288}
3289
3290static irqreturn_t
David Howells7d12e782006-10-05 14:55:46 +01003291bnx2_interrupt(int irq, void *dev_instance)
Michael Chanb6016b72005-05-26 13:03:09 -07003292{
Michael Chanf0ea2e62008-06-19 16:41:57 -07003293 struct bnx2_napi *bnapi = dev_instance;
3294 struct bnx2 *bp = bnapi->bp;
Michael Chan43e80b82008-06-19 16:41:08 -07003295 struct status_block *sblk = bnapi->status_blk.msi;
Michael Chanb6016b72005-05-26 13:03:09 -07003296
3297 /* When using INTx, it is possible for the interrupt to arrive
3298 * at the CPU before the status block posted prior to the
3299 * interrupt. Reading a register will flush the status block.
3300 * When using MSI, the MSI message will always complete after
3301 * the status block write.
3302 */
Michael Chan35efa7c2007-12-20 19:56:37 -08003303 if ((sblk->status_idx == bnapi->last_status_idx) &&
Michael Chanb6016b72005-05-26 13:03:09 -07003304 (REG_RD(bp, BNX2_PCICFG_MISC_STATUS) &
3305 BNX2_PCICFG_MISC_STATUS_INTA_VALUE))
Michael Chan73eef4c2005-08-25 15:39:15 -07003306 return IRQ_NONE;
Michael Chanb6016b72005-05-26 13:03:09 -07003307
3308 REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
3309 BNX2_PCICFG_INT_ACK_CMD_USE_INT_HC_PARAM |
3310 BNX2_PCICFG_INT_ACK_CMD_MASK_INT);
3311
Michael Chanb8a7ce72007-07-07 22:51:03 -07003312 /* Read back to deassert IRQ immediately to avoid too many
3313 * spurious interrupts.
3314 */
3315 REG_RD(bp, BNX2_PCICFG_INT_ACK_CMD);
3316
Michael Chanb6016b72005-05-26 13:03:09 -07003317 /* Return here if interrupt is shared and is disabled. */
Michael Chan73eef4c2005-08-25 15:39:15 -07003318 if (unlikely(atomic_read(&bp->intr_sem) != 0))
3319 return IRQ_HANDLED;
Michael Chanb6016b72005-05-26 13:03:09 -07003320
Ben Hutchings288379f2009-01-19 16:43:59 -08003321 if (napi_schedule_prep(&bnapi->napi)) {
Michael Chan35efa7c2007-12-20 19:56:37 -08003322 bnapi->last_status_idx = sblk->status_idx;
Ben Hutchings288379f2009-01-19 16:43:59 -08003323 __napi_schedule(&bnapi->napi);
Michael Chanb8a7ce72007-07-07 22:51:03 -07003324 }
Michael Chanb6016b72005-05-26 13:03:09 -07003325
Michael Chan73eef4c2005-08-25 15:39:15 -07003326 return IRQ_HANDLED;
Michael Chanb6016b72005-05-26 13:03:09 -07003327}
3328
Michael Chan43e80b82008-06-19 16:41:08 -07003329static inline int
3330bnx2_has_fast_work(struct bnx2_napi *bnapi)
3331{
3332 struct bnx2_tx_ring_info *txr = &bnapi->tx_ring;
3333 struct bnx2_rx_ring_info *rxr = &bnapi->rx_ring;
3334
3335 if ((bnx2_get_hw_rx_cons(bnapi) != rxr->rx_cons) ||
3336 (bnx2_get_hw_tx_cons(bnapi) != txr->hw_tx_cons))
3337 return 1;
3338 return 0;
3339}
3340
Michael Chan0d8a6572007-07-07 22:49:43 -07003341#define STATUS_ATTN_EVENTS (STATUS_ATTN_BITS_LINK_STATE | \
3342 STATUS_ATTN_BITS_TIMER_ABORT)
Michael Chanda3e4fb2007-05-03 13:24:23 -07003343
Michael Chanf4e418f2005-11-04 08:53:48 -08003344static inline int
Michael Chan35efa7c2007-12-20 19:56:37 -08003345bnx2_has_work(struct bnx2_napi *bnapi)
Michael Chanf4e418f2005-11-04 08:53:48 -08003346{
Michael Chan43e80b82008-06-19 16:41:08 -07003347 struct status_block *sblk = bnapi->status_blk.msi;
Michael Chanf4e418f2005-11-04 08:53:48 -08003348
Michael Chan43e80b82008-06-19 16:41:08 -07003349 if (bnx2_has_fast_work(bnapi))
Michael Chanf4e418f2005-11-04 08:53:48 -08003350 return 1;
3351
Michael Chan4edd4732009-06-08 18:14:42 -07003352#ifdef BCM_CNIC
3353 if (bnapi->cnic_present && (bnapi->cnic_tag != sblk->status_idx))
3354 return 1;
3355#endif
3356
Michael Chanda3e4fb2007-05-03 13:24:23 -07003357 if ((sblk->status_attn_bits & STATUS_ATTN_EVENTS) !=
3358 (sblk->status_attn_bits_ack & STATUS_ATTN_EVENTS))
Michael Chanf4e418f2005-11-04 08:53:48 -08003359 return 1;
3360
3361 return 0;
3362}
3363
Michael Chanefba0182008-12-03 00:36:15 -08003364static void
3365bnx2_chk_missed_msi(struct bnx2 *bp)
3366{
3367 struct bnx2_napi *bnapi = &bp->bnx2_napi[0];
3368 u32 msi_ctrl;
3369
3370 if (bnx2_has_work(bnapi)) {
3371 msi_ctrl = REG_RD(bp, BNX2_PCICFG_MSI_CONTROL);
3372 if (!(msi_ctrl & BNX2_PCICFG_MSI_CONTROL_ENABLE))
3373 return;
3374
3375 if (bnapi->last_status_idx == bp->idle_chk_status_idx) {
3376 REG_WR(bp, BNX2_PCICFG_MSI_CONTROL, msi_ctrl &
3377 ~BNX2_PCICFG_MSI_CONTROL_ENABLE);
3378 REG_WR(bp, BNX2_PCICFG_MSI_CONTROL, msi_ctrl);
3379 bnx2_msi(bp->irq_tbl[0].vector, bnapi);
3380 }
3381 }
3382
3383 bp->idle_chk_status_idx = bnapi->last_status_idx;
3384}
3385
Michael Chan4edd4732009-06-08 18:14:42 -07003386#ifdef BCM_CNIC
3387static void bnx2_poll_cnic(struct bnx2 *bp, struct bnx2_napi *bnapi)
3388{
3389 struct cnic_ops *c_ops;
3390
3391 if (!bnapi->cnic_present)
3392 return;
3393
3394 rcu_read_lock();
3395 c_ops = rcu_dereference(bp->cnic_ops);
3396 if (c_ops)
3397 bnapi->cnic_tag = c_ops->cnic_handler(bp->cnic_data,
3398 bnapi->status_blk.msi);
3399 rcu_read_unlock();
3400}
3401#endif
3402
Michael Chan43e80b82008-06-19 16:41:08 -07003403static void bnx2_poll_link(struct bnx2 *bp, struct bnx2_napi *bnapi)
Michael Chanb6016b72005-05-26 13:03:09 -07003404{
Michael Chan43e80b82008-06-19 16:41:08 -07003405 struct status_block *sblk = bnapi->status_blk.msi;
Michael Chanda3e4fb2007-05-03 13:24:23 -07003406 u32 status_attn_bits = sblk->status_attn_bits;
3407 u32 status_attn_bits_ack = sblk->status_attn_bits_ack;
Michael Chanb6016b72005-05-26 13:03:09 -07003408
Michael Chanda3e4fb2007-05-03 13:24:23 -07003409 if ((status_attn_bits & STATUS_ATTN_EVENTS) !=
3410 (status_attn_bits_ack & STATUS_ATTN_EVENTS)) {
Michael Chanb6016b72005-05-26 13:03:09 -07003411
Michael Chan35efa7c2007-12-20 19:56:37 -08003412 bnx2_phy_int(bp, bnapi);
Michael Chanbf5295b2006-03-23 01:11:56 -08003413
3414 /* This is needed to take care of transient status
3415 * during link changes.
3416 */
3417 REG_WR(bp, BNX2_HC_COMMAND,
3418 bp->hc_cmd | BNX2_HC_COMMAND_COAL_NOW_WO_INT);
3419 REG_RD(bp, BNX2_HC_COMMAND);
Michael Chanb6016b72005-05-26 13:03:09 -07003420 }
Michael Chan43e80b82008-06-19 16:41:08 -07003421}
3422
3423static int bnx2_poll_work(struct bnx2 *bp, struct bnx2_napi *bnapi,
3424 int work_done, int budget)
3425{
3426 struct bnx2_tx_ring_info *txr = &bnapi->tx_ring;
3427 struct bnx2_rx_ring_info *rxr = &bnapi->rx_ring;
Michael Chanb6016b72005-05-26 13:03:09 -07003428
Michael Chan35e90102008-06-19 16:37:42 -07003429 if (bnx2_get_hw_tx_cons(bnapi) != txr->hw_tx_cons)
Michael Chan57851d82007-12-20 20:01:44 -08003430 bnx2_tx_int(bp, bnapi, 0);
Michael Chanb6016b72005-05-26 13:03:09 -07003431
Michael Chanbb4f98a2008-06-19 16:38:19 -07003432 if (bnx2_get_hw_rx_cons(bnapi) != rxr->rx_cons)
Michael Chan35efa7c2007-12-20 19:56:37 -08003433 work_done += bnx2_rx_int(bp, bnapi, budget - work_done);
Jeff Garzik6aa20a22006-09-13 13:24:59 -04003434
David S. Miller6f535762007-10-11 18:08:29 -07003435 return work_done;
3436}
Michael Chanf4e418f2005-11-04 08:53:48 -08003437
Michael Chanf0ea2e62008-06-19 16:41:57 -07003438static int bnx2_poll_msix(struct napi_struct *napi, int budget)
3439{
3440 struct bnx2_napi *bnapi = container_of(napi, struct bnx2_napi, napi);
3441 struct bnx2 *bp = bnapi->bp;
3442 int work_done = 0;
3443 struct status_block_msix *sblk = bnapi->status_blk.msix;
3444
3445 while (1) {
3446 work_done = bnx2_poll_work(bp, bnapi, work_done, budget);
3447 if (unlikely(work_done >= budget))
3448 break;
3449
3450 bnapi->last_status_idx = sblk->status_idx;
3451 /* status idx must be read before checking for more work. */
3452 rmb();
3453 if (likely(!bnx2_has_fast_work(bnapi))) {
3454
Ben Hutchings288379f2009-01-19 16:43:59 -08003455 napi_complete(napi);
Michael Chanf0ea2e62008-06-19 16:41:57 -07003456 REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD, bnapi->int_num |
3457 BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
3458 bnapi->last_status_idx);
3459 break;
3460 }
3461 }
3462 return work_done;
3463}
3464
David S. Miller6f535762007-10-11 18:08:29 -07003465static int bnx2_poll(struct napi_struct *napi, int budget)
3466{
Michael Chan35efa7c2007-12-20 19:56:37 -08003467 struct bnx2_napi *bnapi = container_of(napi, struct bnx2_napi, napi);
3468 struct bnx2 *bp = bnapi->bp;
David S. Miller6f535762007-10-11 18:08:29 -07003469 int work_done = 0;
Michael Chan43e80b82008-06-19 16:41:08 -07003470 struct status_block *sblk = bnapi->status_blk.msi;
David S. Miller6f535762007-10-11 18:08:29 -07003471
3472 while (1) {
Michael Chan43e80b82008-06-19 16:41:08 -07003473 bnx2_poll_link(bp, bnapi);
3474
Michael Chan35efa7c2007-12-20 19:56:37 -08003475 work_done = bnx2_poll_work(bp, bnapi, work_done, budget);
David S. Miller6f535762007-10-11 18:08:29 -07003476
Michael Chan4edd4732009-06-08 18:14:42 -07003477#ifdef BCM_CNIC
3478 bnx2_poll_cnic(bp, bnapi);
3479#endif
3480
Michael Chan35efa7c2007-12-20 19:56:37 -08003481 /* bnapi->last_status_idx is used below to tell the hw how
Michael Chan6dee6422007-10-12 01:40:38 -07003482 * much work has been processed, so we must read it before
3483 * checking for more work.
3484 */
Michael Chan35efa7c2007-12-20 19:56:37 -08003485 bnapi->last_status_idx = sblk->status_idx;
Michael Chanefba0182008-12-03 00:36:15 -08003486
3487 if (unlikely(work_done >= budget))
3488 break;
3489
Michael Chan6dee6422007-10-12 01:40:38 -07003490 rmb();
Michael Chan35efa7c2007-12-20 19:56:37 -08003491 if (likely(!bnx2_has_work(bnapi))) {
Ben Hutchings288379f2009-01-19 16:43:59 -08003492 napi_complete(napi);
David S. Millerf86e82f2008-01-21 17:15:40 -08003493 if (likely(bp->flags & BNX2_FLAG_USING_MSI_OR_MSIX)) {
David S. Miller6f535762007-10-11 18:08:29 -07003494 REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
3495 BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
Michael Chan35efa7c2007-12-20 19:56:37 -08003496 bnapi->last_status_idx);
Michael Chan6dee6422007-10-12 01:40:38 -07003497 break;
David S. Miller6f535762007-10-11 18:08:29 -07003498 }
3499 REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
3500 BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
3501 BNX2_PCICFG_INT_ACK_CMD_MASK_INT |
Michael Chan35efa7c2007-12-20 19:56:37 -08003502 bnapi->last_status_idx);
David S. Miller6f535762007-10-11 18:08:29 -07003503
Michael Chan1269a8a2006-01-23 16:11:03 -08003504 REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
3505 BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
Michael Chan35efa7c2007-12-20 19:56:37 -08003506 bnapi->last_status_idx);
David S. Miller6f535762007-10-11 18:08:29 -07003507 break;
Michael Chan1269a8a2006-01-23 16:11:03 -08003508 }
Michael Chanb6016b72005-05-26 13:03:09 -07003509 }
3510
Stephen Hemmingerbea33482007-10-03 16:41:36 -07003511 return work_done;
Michael Chanb6016b72005-05-26 13:03:09 -07003512}
3513
Herbert Xu932ff272006-06-09 12:20:56 -07003514/* Called with rtnl_lock from vlan functions and also netif_tx_lock
Michael Chanb6016b72005-05-26 13:03:09 -07003515 * from set_multicast.
3516 */
3517static void
3518bnx2_set_rx_mode(struct net_device *dev)
3519{
Michael Chan972ec0d2006-01-23 16:12:43 -08003520 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07003521 u32 rx_mode, sort_mode;
Jiri Pirkoccffad252009-05-22 23:22:17 +00003522 struct netdev_hw_addr *ha;
Michael Chanb6016b72005-05-26 13:03:09 -07003523 int i;
Michael Chanb6016b72005-05-26 13:03:09 -07003524
Michael Chan9f52b562008-10-09 12:21:46 -07003525 if (!netif_running(dev))
3526 return;
3527
Michael Chanc770a652005-08-25 15:38:39 -07003528 spin_lock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07003529
3530 rx_mode = bp->rx_mode & ~(BNX2_EMAC_RX_MODE_PROMISCUOUS |
3531 BNX2_EMAC_RX_MODE_KEEP_VLAN_TAG);
3532 sort_mode = 1 | BNX2_RPM_SORT_USER0_BC_EN;
3533#ifdef BCM_VLAN
Michael Chan7c6337a2008-08-14 15:29:09 -07003534 if (!bp->vlgrp && (bp->flags & BNX2_FLAG_CAN_KEEP_VLAN))
Michael Chanb6016b72005-05-26 13:03:09 -07003535 rx_mode |= BNX2_EMAC_RX_MODE_KEEP_VLAN_TAG;
Michael Chanb6016b72005-05-26 13:03:09 -07003536#else
Michael Chan7c6337a2008-08-14 15:29:09 -07003537 if (bp->flags & BNX2_FLAG_CAN_KEEP_VLAN)
Michael Chane29054f2006-01-23 16:06:06 -08003538 rx_mode |= BNX2_EMAC_RX_MODE_KEEP_VLAN_TAG;
Michael Chanb6016b72005-05-26 13:03:09 -07003539#endif
3540 if (dev->flags & IFF_PROMISC) {
3541 /* Promiscuous mode. */
3542 rx_mode |= BNX2_EMAC_RX_MODE_PROMISCUOUS;
Michael Chan75108732006-11-19 14:06:40 -08003543 sort_mode |= BNX2_RPM_SORT_USER0_PROM_EN |
3544 BNX2_RPM_SORT_USER0_PROM_VLAN;
Michael Chanb6016b72005-05-26 13:03:09 -07003545 }
3546 else if (dev->flags & IFF_ALLMULTI) {
3547 for (i = 0; i < NUM_MC_HASH_REGISTERS; i++) {
3548 REG_WR(bp, BNX2_EMAC_MULTICAST_HASH0 + (i * 4),
3549 0xffffffff);
3550 }
3551 sort_mode |= BNX2_RPM_SORT_USER0_MC_EN;
3552 }
3553 else {
3554 /* Accept one or more multicast(s). */
3555 struct dev_mc_list *mclist;
3556 u32 mc_filter[NUM_MC_HASH_REGISTERS];
3557 u32 regidx;
3558 u32 bit;
3559 u32 crc;
3560
3561 memset(mc_filter, 0, 4 * NUM_MC_HASH_REGISTERS);
3562
Jiri Pirko4cd24ea2010-02-08 04:30:35 +00003563 for (i = 0, mclist = dev->mc_list; mclist && i < netdev_mc_count(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07003564 i++, mclist = mclist->next) {
3565
3566 crc = ether_crc_le(ETH_ALEN, mclist->dmi_addr);
3567 bit = crc & 0xff;
3568 regidx = (bit & 0xe0) >> 5;
3569 bit &= 0x1f;
3570 mc_filter[regidx] |= (1 << bit);
3571 }
3572
3573 for (i = 0; i < NUM_MC_HASH_REGISTERS; i++) {
3574 REG_WR(bp, BNX2_EMAC_MULTICAST_HASH0 + (i * 4),
3575 mc_filter[i]);
3576 }
3577
3578 sort_mode |= BNX2_RPM_SORT_USER0_MC_HSH_EN;
3579 }
3580
Jiri Pirko32e7bfc2010-01-25 13:36:10 -08003581 if (netdev_uc_count(dev) > BNX2_MAX_UNICAST_ADDRESSES) {
Benjamin Li5fcaed02008-07-14 22:39:52 -07003582 rx_mode |= BNX2_EMAC_RX_MODE_PROMISCUOUS;
3583 sort_mode |= BNX2_RPM_SORT_USER0_PROM_EN |
3584 BNX2_RPM_SORT_USER0_PROM_VLAN;
3585 } else if (!(dev->flags & IFF_PROMISC)) {
Benjamin Li5fcaed02008-07-14 22:39:52 -07003586 /* Add all entries into to the match filter list */
Jiri Pirkoccffad252009-05-22 23:22:17 +00003587 i = 0;
Jiri Pirko32e7bfc2010-01-25 13:36:10 -08003588 netdev_for_each_uc_addr(ha, dev) {
Jiri Pirkoccffad252009-05-22 23:22:17 +00003589 bnx2_set_mac_addr(bp, ha->addr,
Benjamin Li5fcaed02008-07-14 22:39:52 -07003590 i + BNX2_START_UNICAST_ADDRESS_INDEX);
3591 sort_mode |= (1 <<
3592 (i + BNX2_START_UNICAST_ADDRESS_INDEX));
Jiri Pirkoccffad252009-05-22 23:22:17 +00003593 i++;
Benjamin Li5fcaed02008-07-14 22:39:52 -07003594 }
3595
3596 }
3597
Michael Chanb6016b72005-05-26 13:03:09 -07003598 if (rx_mode != bp->rx_mode) {
3599 bp->rx_mode = rx_mode;
3600 REG_WR(bp, BNX2_EMAC_RX_MODE, rx_mode);
3601 }
3602
3603 REG_WR(bp, BNX2_RPM_SORT_USER0, 0x0);
3604 REG_WR(bp, BNX2_RPM_SORT_USER0, sort_mode);
3605 REG_WR(bp, BNX2_RPM_SORT_USER0, sort_mode | BNX2_RPM_SORT_USER0_ENA);
3606
Michael Chanc770a652005-08-25 15:38:39 -07003607 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07003608}
3609
Michael Chan57579f72009-04-04 16:51:14 -07003610static int __devinit
3611check_fw_section(const struct firmware *fw,
3612 const struct bnx2_fw_file_section *section,
3613 u32 alignment, bool non_empty)
Michael Chanb6016b72005-05-26 13:03:09 -07003614{
Michael Chan57579f72009-04-04 16:51:14 -07003615 u32 offset = be32_to_cpu(section->offset);
3616 u32 len = be32_to_cpu(section->len);
Michael Chanb6016b72005-05-26 13:03:09 -07003617
Michael Chan57579f72009-04-04 16:51:14 -07003618 if ((offset == 0 && len != 0) || offset >= fw->size || offset & 3)
3619 return -EINVAL;
3620 if ((non_empty && len == 0) || len > fw->size - offset ||
3621 len & (alignment - 1))
3622 return -EINVAL;
3623 return 0;
3624}
3625
3626static int __devinit
3627check_mips_fw_entry(const struct firmware *fw,
3628 const struct bnx2_mips_fw_file_entry *entry)
3629{
3630 if (check_fw_section(fw, &entry->text, 4, true) ||
3631 check_fw_section(fw, &entry->data, 4, false) ||
3632 check_fw_section(fw, &entry->rodata, 4, false))
3633 return -EINVAL;
3634 return 0;
3635}
3636
3637static int __devinit
3638bnx2_request_firmware(struct bnx2 *bp)
3639{
3640 const char *mips_fw_file, *rv2p_fw_file;
Bastian Blank5ee1c322009-04-08 15:50:07 -07003641 const struct bnx2_mips_fw_file *mips_fw;
3642 const struct bnx2_rv2p_fw_file *rv2p_fw;
Michael Chan57579f72009-04-04 16:51:14 -07003643 int rc;
3644
3645 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
3646 mips_fw_file = FW_MIPS_FILE_09;
Michael Chan078b0732009-08-29 00:02:46 -07003647 if ((CHIP_ID(bp) == CHIP_ID_5709_A0) ||
3648 (CHIP_ID(bp) == CHIP_ID_5709_A1))
3649 rv2p_fw_file = FW_RV2P_FILE_09_Ax;
3650 else
3651 rv2p_fw_file = FW_RV2P_FILE_09;
Michael Chan57579f72009-04-04 16:51:14 -07003652 } else {
3653 mips_fw_file = FW_MIPS_FILE_06;
3654 rv2p_fw_file = FW_RV2P_FILE_06;
3655 }
3656
3657 rc = request_firmware(&bp->mips_firmware, mips_fw_file, &bp->pdev->dev);
3658 if (rc) {
3659 printk(KERN_ERR PFX "Can't load firmware file \"%s\"\n",
3660 mips_fw_file);
3661 return rc;
3662 }
3663
3664 rc = request_firmware(&bp->rv2p_firmware, rv2p_fw_file, &bp->pdev->dev);
3665 if (rc) {
3666 printk(KERN_ERR PFX "Can't load firmware file \"%s\"\n",
3667 rv2p_fw_file);
3668 return rc;
3669 }
Bastian Blank5ee1c322009-04-08 15:50:07 -07003670 mips_fw = (const struct bnx2_mips_fw_file *) bp->mips_firmware->data;
3671 rv2p_fw = (const struct bnx2_rv2p_fw_file *) bp->rv2p_firmware->data;
3672 if (bp->mips_firmware->size < sizeof(*mips_fw) ||
3673 check_mips_fw_entry(bp->mips_firmware, &mips_fw->com) ||
3674 check_mips_fw_entry(bp->mips_firmware, &mips_fw->cp) ||
3675 check_mips_fw_entry(bp->mips_firmware, &mips_fw->rxp) ||
3676 check_mips_fw_entry(bp->mips_firmware, &mips_fw->tpat) ||
3677 check_mips_fw_entry(bp->mips_firmware, &mips_fw->txp)) {
Michael Chan57579f72009-04-04 16:51:14 -07003678 printk(KERN_ERR PFX "Firmware file \"%s\" is invalid\n",
3679 mips_fw_file);
3680 return -EINVAL;
3681 }
Bastian Blank5ee1c322009-04-08 15:50:07 -07003682 if (bp->rv2p_firmware->size < sizeof(*rv2p_fw) ||
3683 check_fw_section(bp->rv2p_firmware, &rv2p_fw->proc1.rv2p, 8, true) ||
3684 check_fw_section(bp->rv2p_firmware, &rv2p_fw->proc2.rv2p, 8, true)) {
Michael Chan57579f72009-04-04 16:51:14 -07003685 printk(KERN_ERR PFX "Firmware file \"%s\" is invalid\n",
3686 rv2p_fw_file);
3687 return -EINVAL;
3688 }
3689
3690 return 0;
3691}
3692
3693static u32
3694rv2p_fw_fixup(u32 rv2p_proc, int idx, u32 loc, u32 rv2p_code)
3695{
3696 switch (idx) {
3697 case RV2P_P1_FIXUP_PAGE_SIZE_IDX:
3698 rv2p_code &= ~RV2P_BD_PAGE_SIZE_MSK;
3699 rv2p_code |= RV2P_BD_PAGE_SIZE;
3700 break;
3701 }
3702 return rv2p_code;
3703}
3704
3705static int
3706load_rv2p_fw(struct bnx2 *bp, u32 rv2p_proc,
3707 const struct bnx2_rv2p_fw_file_entry *fw_entry)
3708{
3709 u32 rv2p_code_len, file_offset;
3710 __be32 *rv2p_code;
3711 int i;
3712 u32 val, cmd, addr;
3713
3714 rv2p_code_len = be32_to_cpu(fw_entry->rv2p.len);
3715 file_offset = be32_to_cpu(fw_entry->rv2p.offset);
3716
3717 rv2p_code = (__be32 *)(bp->rv2p_firmware->data + file_offset);
3718
3719 if (rv2p_proc == RV2P_PROC1) {
3720 cmd = BNX2_RV2P_PROC1_ADDR_CMD_RDWR;
3721 addr = BNX2_RV2P_PROC1_ADDR_CMD;
3722 } else {
3723 cmd = BNX2_RV2P_PROC2_ADDR_CMD_RDWR;
3724 addr = BNX2_RV2P_PROC2_ADDR_CMD;
Michael Chand25be1d2008-05-02 16:57:59 -07003725 }
Michael Chanb6016b72005-05-26 13:03:09 -07003726
3727 for (i = 0; i < rv2p_code_len; i += 8) {
Michael Chan57579f72009-04-04 16:51:14 -07003728 REG_WR(bp, BNX2_RV2P_INSTR_HIGH, be32_to_cpu(*rv2p_code));
Michael Chanb6016b72005-05-26 13:03:09 -07003729 rv2p_code++;
Michael Chan57579f72009-04-04 16:51:14 -07003730 REG_WR(bp, BNX2_RV2P_INSTR_LOW, be32_to_cpu(*rv2p_code));
Michael Chanb6016b72005-05-26 13:03:09 -07003731 rv2p_code++;
3732
Michael Chan57579f72009-04-04 16:51:14 -07003733 val = (i / 8) | cmd;
3734 REG_WR(bp, addr, val);
3735 }
3736
3737 rv2p_code = (__be32 *)(bp->rv2p_firmware->data + file_offset);
3738 for (i = 0; i < 8; i++) {
3739 u32 loc, code;
3740
3741 loc = be32_to_cpu(fw_entry->fixup[i]);
3742 if (loc && ((loc * 4) < rv2p_code_len)) {
3743 code = be32_to_cpu(*(rv2p_code + loc - 1));
3744 REG_WR(bp, BNX2_RV2P_INSTR_HIGH, code);
3745 code = be32_to_cpu(*(rv2p_code + loc));
3746 code = rv2p_fw_fixup(rv2p_proc, i, loc, code);
3747 REG_WR(bp, BNX2_RV2P_INSTR_LOW, code);
3748
3749 val = (loc / 2) | cmd;
3750 REG_WR(bp, addr, val);
Michael Chanb6016b72005-05-26 13:03:09 -07003751 }
3752 }
3753
3754 /* Reset the processor, un-stall is done later. */
3755 if (rv2p_proc == RV2P_PROC1) {
3756 REG_WR(bp, BNX2_RV2P_COMMAND, BNX2_RV2P_COMMAND_PROC1_RESET);
3757 }
3758 else {
3759 REG_WR(bp, BNX2_RV2P_COMMAND, BNX2_RV2P_COMMAND_PROC2_RESET);
3760 }
Michael Chan57579f72009-04-04 16:51:14 -07003761
3762 return 0;
Michael Chanb6016b72005-05-26 13:03:09 -07003763}
3764
Michael Chanaf3ee512006-11-19 14:09:25 -08003765static int
Michael Chan57579f72009-04-04 16:51:14 -07003766load_cpu_fw(struct bnx2 *bp, const struct cpu_reg *cpu_reg,
3767 const struct bnx2_mips_fw_file_entry *fw_entry)
Michael Chanb6016b72005-05-26 13:03:09 -07003768{
Michael Chan57579f72009-04-04 16:51:14 -07003769 u32 addr, len, file_offset;
3770 __be32 *data;
Michael Chanb6016b72005-05-26 13:03:09 -07003771 u32 offset;
3772 u32 val;
3773
3774 /* Halt the CPU. */
Michael Chan2726d6e2008-01-29 21:35:05 -08003775 val = bnx2_reg_rd_ind(bp, cpu_reg->mode);
Michael Chanb6016b72005-05-26 13:03:09 -07003776 val |= cpu_reg->mode_value_halt;
Michael Chan2726d6e2008-01-29 21:35:05 -08003777 bnx2_reg_wr_ind(bp, cpu_reg->mode, val);
3778 bnx2_reg_wr_ind(bp, cpu_reg->state, cpu_reg->state_value_clear);
Michael Chanb6016b72005-05-26 13:03:09 -07003779
3780 /* Load the Text area. */
Michael Chan57579f72009-04-04 16:51:14 -07003781 addr = be32_to_cpu(fw_entry->text.addr);
3782 len = be32_to_cpu(fw_entry->text.len);
3783 file_offset = be32_to_cpu(fw_entry->text.offset);
3784 data = (__be32 *)(bp->mips_firmware->data + file_offset);
3785
3786 offset = cpu_reg->spad_base + (addr - cpu_reg->mips_view_base);
3787 if (len) {
Michael Chanb6016b72005-05-26 13:03:09 -07003788 int j;
3789
Michael Chan57579f72009-04-04 16:51:14 -07003790 for (j = 0; j < (len / 4); j++, offset += 4)
3791 bnx2_reg_wr_ind(bp, offset, be32_to_cpu(data[j]));
Michael Chanb6016b72005-05-26 13:03:09 -07003792 }
3793
3794 /* Load the Data area. */
Michael Chan57579f72009-04-04 16:51:14 -07003795 addr = be32_to_cpu(fw_entry->data.addr);
3796 len = be32_to_cpu(fw_entry->data.len);
3797 file_offset = be32_to_cpu(fw_entry->data.offset);
3798 data = (__be32 *)(bp->mips_firmware->data + file_offset);
3799
3800 offset = cpu_reg->spad_base + (addr - cpu_reg->mips_view_base);
3801 if (len) {
Michael Chanb6016b72005-05-26 13:03:09 -07003802 int j;
3803
Michael Chan57579f72009-04-04 16:51:14 -07003804 for (j = 0; j < (len / 4); j++, offset += 4)
3805 bnx2_reg_wr_ind(bp, offset, be32_to_cpu(data[j]));
Michael Chanb6016b72005-05-26 13:03:09 -07003806 }
3807
3808 /* Load the Read-Only area. */
Michael Chan57579f72009-04-04 16:51:14 -07003809 addr = be32_to_cpu(fw_entry->rodata.addr);
3810 len = be32_to_cpu(fw_entry->rodata.len);
3811 file_offset = be32_to_cpu(fw_entry->rodata.offset);
3812 data = (__be32 *)(bp->mips_firmware->data + file_offset);
3813
3814 offset = cpu_reg->spad_base + (addr - cpu_reg->mips_view_base);
3815 if (len) {
Michael Chanb6016b72005-05-26 13:03:09 -07003816 int j;
3817
Michael Chan57579f72009-04-04 16:51:14 -07003818 for (j = 0; j < (len / 4); j++, offset += 4)
3819 bnx2_reg_wr_ind(bp, offset, be32_to_cpu(data[j]));
Michael Chanb6016b72005-05-26 13:03:09 -07003820 }
3821
3822 /* Clear the pre-fetch instruction. */
Michael Chan2726d6e2008-01-29 21:35:05 -08003823 bnx2_reg_wr_ind(bp, cpu_reg->inst, 0);
Michael Chan57579f72009-04-04 16:51:14 -07003824
3825 val = be32_to_cpu(fw_entry->start_addr);
3826 bnx2_reg_wr_ind(bp, cpu_reg->pc, val);
Michael Chanb6016b72005-05-26 13:03:09 -07003827
3828 /* Start the CPU. */
Michael Chan2726d6e2008-01-29 21:35:05 -08003829 val = bnx2_reg_rd_ind(bp, cpu_reg->mode);
Michael Chanb6016b72005-05-26 13:03:09 -07003830 val &= ~cpu_reg->mode_value_halt;
Michael Chan2726d6e2008-01-29 21:35:05 -08003831 bnx2_reg_wr_ind(bp, cpu_reg->state, cpu_reg->state_value_clear);
3832 bnx2_reg_wr_ind(bp, cpu_reg->mode, val);
Michael Chanaf3ee512006-11-19 14:09:25 -08003833
3834 return 0;
Michael Chanb6016b72005-05-26 13:03:09 -07003835}
3836
Michael Chanfba9fe92006-06-12 22:21:25 -07003837static int
Michael Chanb6016b72005-05-26 13:03:09 -07003838bnx2_init_cpus(struct bnx2 *bp)
3839{
Michael Chan57579f72009-04-04 16:51:14 -07003840 const struct bnx2_mips_fw_file *mips_fw =
3841 (const struct bnx2_mips_fw_file *) bp->mips_firmware->data;
3842 const struct bnx2_rv2p_fw_file *rv2p_fw =
3843 (const struct bnx2_rv2p_fw_file *) bp->rv2p_firmware->data;
3844 int rc;
Michael Chanb6016b72005-05-26 13:03:09 -07003845
3846 /* Initialize the RV2P processor. */
Michael Chan57579f72009-04-04 16:51:14 -07003847 load_rv2p_fw(bp, RV2P_PROC1, &rv2p_fw->proc1);
3848 load_rv2p_fw(bp, RV2P_PROC2, &rv2p_fw->proc2);
Michael Chanb6016b72005-05-26 13:03:09 -07003849
3850 /* Initialize the RX Processor. */
Michael Chan57579f72009-04-04 16:51:14 -07003851 rc = load_cpu_fw(bp, &cpu_reg_rxp, &mips_fw->rxp);
Michael Chanfba9fe92006-06-12 22:21:25 -07003852 if (rc)
3853 goto init_cpu_err;
3854
Michael Chanb6016b72005-05-26 13:03:09 -07003855 /* Initialize the TX Processor. */
Michael Chan57579f72009-04-04 16:51:14 -07003856 rc = load_cpu_fw(bp, &cpu_reg_txp, &mips_fw->txp);
Michael Chanfba9fe92006-06-12 22:21:25 -07003857 if (rc)
3858 goto init_cpu_err;
3859
Michael Chanb6016b72005-05-26 13:03:09 -07003860 /* Initialize the TX Patch-up Processor. */
Michael Chan57579f72009-04-04 16:51:14 -07003861 rc = load_cpu_fw(bp, &cpu_reg_tpat, &mips_fw->tpat);
Michael Chanfba9fe92006-06-12 22:21:25 -07003862 if (rc)
3863 goto init_cpu_err;
3864
Michael Chanb6016b72005-05-26 13:03:09 -07003865 /* Initialize the Completion Processor. */
Michael Chan57579f72009-04-04 16:51:14 -07003866 rc = load_cpu_fw(bp, &cpu_reg_com, &mips_fw->com);
Michael Chanfba9fe92006-06-12 22:21:25 -07003867 if (rc)
3868 goto init_cpu_err;
3869
Michael Chand43584c2006-11-19 14:14:35 -08003870 /* Initialize the Command Processor. */
Michael Chan57579f72009-04-04 16:51:14 -07003871 rc = load_cpu_fw(bp, &cpu_reg_cp, &mips_fw->cp);
Michael Chan110d0ef2007-12-12 11:18:34 -08003872
Michael Chanfba9fe92006-06-12 22:21:25 -07003873init_cpu_err:
Michael Chanfba9fe92006-06-12 22:21:25 -07003874 return rc;
Michael Chanb6016b72005-05-26 13:03:09 -07003875}
3876
3877static int
Pavel Machek829ca9a2005-09-03 15:56:56 -07003878bnx2_set_power_state(struct bnx2 *bp, pci_power_t state)
Michael Chanb6016b72005-05-26 13:03:09 -07003879{
3880 u16 pmcsr;
3881
3882 pci_read_config_word(bp->pdev, bp->pm_cap + PCI_PM_CTRL, &pmcsr);
3883
3884 switch (state) {
Pavel Machek829ca9a2005-09-03 15:56:56 -07003885 case PCI_D0: {
Michael Chanb6016b72005-05-26 13:03:09 -07003886 u32 val;
3887
3888 pci_write_config_word(bp->pdev, bp->pm_cap + PCI_PM_CTRL,
3889 (pmcsr & ~PCI_PM_CTRL_STATE_MASK) |
3890 PCI_PM_CTRL_PME_STATUS);
3891
3892 if (pmcsr & PCI_PM_CTRL_STATE_MASK)
3893 /* delay required during transition out of D3hot */
3894 msleep(20);
3895
3896 val = REG_RD(bp, BNX2_EMAC_MODE);
3897 val |= BNX2_EMAC_MODE_MPKT_RCVD | BNX2_EMAC_MODE_ACPI_RCVD;
3898 val &= ~BNX2_EMAC_MODE_MPKT;
3899 REG_WR(bp, BNX2_EMAC_MODE, val);
3900
3901 val = REG_RD(bp, BNX2_RPM_CONFIG);
3902 val &= ~BNX2_RPM_CONFIG_ACPI_ENA;
3903 REG_WR(bp, BNX2_RPM_CONFIG, val);
3904 break;
3905 }
Pavel Machek829ca9a2005-09-03 15:56:56 -07003906 case PCI_D3hot: {
Michael Chanb6016b72005-05-26 13:03:09 -07003907 int i;
3908 u32 val, wol_msg;
3909
3910 if (bp->wol) {
3911 u32 advertising;
3912 u8 autoneg;
3913
3914 autoneg = bp->autoneg;
3915 advertising = bp->advertising;
3916
Michael Chan239cd342007-10-17 19:26:15 -07003917 if (bp->phy_port == PORT_TP) {
3918 bp->autoneg = AUTONEG_SPEED;
3919 bp->advertising = ADVERTISED_10baseT_Half |
3920 ADVERTISED_10baseT_Full |
3921 ADVERTISED_100baseT_Half |
3922 ADVERTISED_100baseT_Full |
3923 ADVERTISED_Autoneg;
3924 }
Michael Chanb6016b72005-05-26 13:03:09 -07003925
Michael Chan239cd342007-10-17 19:26:15 -07003926 spin_lock_bh(&bp->phy_lock);
3927 bnx2_setup_phy(bp, bp->phy_port);
3928 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07003929
3930 bp->autoneg = autoneg;
3931 bp->advertising = advertising;
3932
Benjamin Li5fcaed02008-07-14 22:39:52 -07003933 bnx2_set_mac_addr(bp, bp->dev->dev_addr, 0);
Michael Chanb6016b72005-05-26 13:03:09 -07003934
3935 val = REG_RD(bp, BNX2_EMAC_MODE);
3936
3937 /* Enable port mode. */
3938 val &= ~BNX2_EMAC_MODE_PORT;
Michael Chan239cd342007-10-17 19:26:15 -07003939 val |= BNX2_EMAC_MODE_MPKT_RCVD |
Michael Chanb6016b72005-05-26 13:03:09 -07003940 BNX2_EMAC_MODE_ACPI_RCVD |
Michael Chanb6016b72005-05-26 13:03:09 -07003941 BNX2_EMAC_MODE_MPKT;
Michael Chan239cd342007-10-17 19:26:15 -07003942 if (bp->phy_port == PORT_TP)
3943 val |= BNX2_EMAC_MODE_PORT_MII;
3944 else {
3945 val |= BNX2_EMAC_MODE_PORT_GMII;
3946 if (bp->line_speed == SPEED_2500)
3947 val |= BNX2_EMAC_MODE_25G_MODE;
3948 }
Michael Chanb6016b72005-05-26 13:03:09 -07003949
3950 REG_WR(bp, BNX2_EMAC_MODE, val);
3951
3952 /* receive all multicast */
3953 for (i = 0; i < NUM_MC_HASH_REGISTERS; i++) {
3954 REG_WR(bp, BNX2_EMAC_MULTICAST_HASH0 + (i * 4),
3955 0xffffffff);
3956 }
3957 REG_WR(bp, BNX2_EMAC_RX_MODE,
3958 BNX2_EMAC_RX_MODE_SORT_MODE);
3959
3960 val = 1 | BNX2_RPM_SORT_USER0_BC_EN |
3961 BNX2_RPM_SORT_USER0_MC_EN;
3962 REG_WR(bp, BNX2_RPM_SORT_USER0, 0x0);
3963 REG_WR(bp, BNX2_RPM_SORT_USER0, val);
3964 REG_WR(bp, BNX2_RPM_SORT_USER0, val |
3965 BNX2_RPM_SORT_USER0_ENA);
3966
3967 /* Need to enable EMAC and RPM for WOL. */
3968 REG_WR(bp, BNX2_MISC_ENABLE_SET_BITS,
3969 BNX2_MISC_ENABLE_SET_BITS_RX_PARSER_MAC_ENABLE |
3970 BNX2_MISC_ENABLE_SET_BITS_TX_HEADER_Q_ENABLE |
3971 BNX2_MISC_ENABLE_SET_BITS_EMAC_ENABLE);
3972
3973 val = REG_RD(bp, BNX2_RPM_CONFIG);
3974 val &= ~BNX2_RPM_CONFIG_ACPI_ENA;
3975 REG_WR(bp, BNX2_RPM_CONFIG, val);
3976
3977 wol_msg = BNX2_DRV_MSG_CODE_SUSPEND_WOL;
3978 }
3979 else {
3980 wol_msg = BNX2_DRV_MSG_CODE_SUSPEND_NO_WOL;
3981 }
3982
David S. Millerf86e82f2008-01-21 17:15:40 -08003983 if (!(bp->flags & BNX2_FLAG_NO_WOL))
Michael Chana2f13892008-07-14 22:38:23 -07003984 bnx2_fw_sync(bp, BNX2_DRV_MSG_DATA_WAIT3 | wol_msg,
3985 1, 0);
Michael Chanb6016b72005-05-26 13:03:09 -07003986
3987 pmcsr &= ~PCI_PM_CTRL_STATE_MASK;
3988 if ((CHIP_ID(bp) == CHIP_ID_5706_A0) ||
3989 (CHIP_ID(bp) == CHIP_ID_5706_A1)) {
3990
3991 if (bp->wol)
3992 pmcsr |= 3;
3993 }
3994 else {
3995 pmcsr |= 3;
3996 }
3997 if (bp->wol) {
3998 pmcsr |= PCI_PM_CTRL_PME_ENABLE;
3999 }
4000 pci_write_config_word(bp->pdev, bp->pm_cap + PCI_PM_CTRL,
4001 pmcsr);
4002
4003 /* No more memory access after this point until
4004 * device is brought back to D0.
4005 */
4006 udelay(50);
4007 break;
4008 }
4009 default:
4010 return -EINVAL;
4011 }
4012 return 0;
4013}
4014
4015static int
4016bnx2_acquire_nvram_lock(struct bnx2 *bp)
4017{
4018 u32 val;
4019 int j;
4020
4021 /* Request access to the flash interface. */
4022 REG_WR(bp, BNX2_NVM_SW_ARB, BNX2_NVM_SW_ARB_ARB_REQ_SET2);
4023 for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) {
4024 val = REG_RD(bp, BNX2_NVM_SW_ARB);
4025 if (val & BNX2_NVM_SW_ARB_ARB_ARB2)
4026 break;
4027
4028 udelay(5);
4029 }
4030
4031 if (j >= NVRAM_TIMEOUT_COUNT)
4032 return -EBUSY;
4033
4034 return 0;
4035}
4036
4037static int
4038bnx2_release_nvram_lock(struct bnx2 *bp)
4039{
4040 int j;
4041 u32 val;
4042
4043 /* Relinquish nvram interface. */
4044 REG_WR(bp, BNX2_NVM_SW_ARB, BNX2_NVM_SW_ARB_ARB_REQ_CLR2);
4045
4046 for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) {
4047 val = REG_RD(bp, BNX2_NVM_SW_ARB);
4048 if (!(val & BNX2_NVM_SW_ARB_ARB_ARB2))
4049 break;
4050
4051 udelay(5);
4052 }
4053
4054 if (j >= NVRAM_TIMEOUT_COUNT)
4055 return -EBUSY;
4056
4057 return 0;
4058}
4059
4060
4061static int
4062bnx2_enable_nvram_write(struct bnx2 *bp)
4063{
4064 u32 val;
4065
4066 val = REG_RD(bp, BNX2_MISC_CFG);
4067 REG_WR(bp, BNX2_MISC_CFG, val | BNX2_MISC_CFG_NVM_WR_EN_PCI);
4068
Michael Chane30372c2007-07-16 18:26:23 -07004069 if (bp->flash_info->flags & BNX2_NV_WREN) {
Michael Chanb6016b72005-05-26 13:03:09 -07004070 int j;
4071
4072 REG_WR(bp, BNX2_NVM_COMMAND, BNX2_NVM_COMMAND_DONE);
4073 REG_WR(bp, BNX2_NVM_COMMAND,
4074 BNX2_NVM_COMMAND_WREN | BNX2_NVM_COMMAND_DOIT);
4075
4076 for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) {
4077 udelay(5);
4078
4079 val = REG_RD(bp, BNX2_NVM_COMMAND);
4080 if (val & BNX2_NVM_COMMAND_DONE)
4081 break;
4082 }
4083
4084 if (j >= NVRAM_TIMEOUT_COUNT)
4085 return -EBUSY;
4086 }
4087 return 0;
4088}
4089
4090static void
4091bnx2_disable_nvram_write(struct bnx2 *bp)
4092{
4093 u32 val;
4094
4095 val = REG_RD(bp, BNX2_MISC_CFG);
4096 REG_WR(bp, BNX2_MISC_CFG, val & ~BNX2_MISC_CFG_NVM_WR_EN);
4097}
4098
4099
4100static void
4101bnx2_enable_nvram_access(struct bnx2 *bp)
4102{
4103 u32 val;
4104
4105 val = REG_RD(bp, BNX2_NVM_ACCESS_ENABLE);
4106 /* Enable both bits, even on read. */
Jeff Garzik6aa20a22006-09-13 13:24:59 -04004107 REG_WR(bp, BNX2_NVM_ACCESS_ENABLE,
Michael Chanb6016b72005-05-26 13:03:09 -07004108 val | BNX2_NVM_ACCESS_ENABLE_EN | BNX2_NVM_ACCESS_ENABLE_WR_EN);
4109}
4110
4111static void
4112bnx2_disable_nvram_access(struct bnx2 *bp)
4113{
4114 u32 val;
4115
4116 val = REG_RD(bp, BNX2_NVM_ACCESS_ENABLE);
4117 /* Disable both bits, even after read. */
Jeff Garzik6aa20a22006-09-13 13:24:59 -04004118 REG_WR(bp, BNX2_NVM_ACCESS_ENABLE,
Michael Chanb6016b72005-05-26 13:03:09 -07004119 val & ~(BNX2_NVM_ACCESS_ENABLE_EN |
4120 BNX2_NVM_ACCESS_ENABLE_WR_EN));
4121}
4122
4123static int
4124bnx2_nvram_erase_page(struct bnx2 *bp, u32 offset)
4125{
4126 u32 cmd;
4127 int j;
4128
Michael Chane30372c2007-07-16 18:26:23 -07004129 if (bp->flash_info->flags & BNX2_NV_BUFFERED)
Michael Chanb6016b72005-05-26 13:03:09 -07004130 /* Buffered flash, no erase needed */
4131 return 0;
4132
4133 /* Build an erase command */
4134 cmd = BNX2_NVM_COMMAND_ERASE | BNX2_NVM_COMMAND_WR |
4135 BNX2_NVM_COMMAND_DOIT;
4136
4137 /* Need to clear DONE bit separately. */
4138 REG_WR(bp, BNX2_NVM_COMMAND, BNX2_NVM_COMMAND_DONE);
4139
4140 /* Address of the NVRAM to read from. */
4141 REG_WR(bp, BNX2_NVM_ADDR, offset & BNX2_NVM_ADDR_NVM_ADDR_VALUE);
4142
4143 /* Issue an erase command. */
4144 REG_WR(bp, BNX2_NVM_COMMAND, cmd);
4145
4146 /* Wait for completion. */
4147 for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) {
4148 u32 val;
4149
4150 udelay(5);
4151
4152 val = REG_RD(bp, BNX2_NVM_COMMAND);
4153 if (val & BNX2_NVM_COMMAND_DONE)
4154 break;
4155 }
4156
4157 if (j >= NVRAM_TIMEOUT_COUNT)
4158 return -EBUSY;
4159
4160 return 0;
4161}
4162
4163static int
4164bnx2_nvram_read_dword(struct bnx2 *bp, u32 offset, u8 *ret_val, u32 cmd_flags)
4165{
4166 u32 cmd;
4167 int j;
4168
4169 /* Build the command word. */
4170 cmd = BNX2_NVM_COMMAND_DOIT | cmd_flags;
4171
Michael Chane30372c2007-07-16 18:26:23 -07004172 /* Calculate an offset of a buffered flash, not needed for 5709. */
4173 if (bp->flash_info->flags & BNX2_NV_TRANSLATE) {
Michael Chanb6016b72005-05-26 13:03:09 -07004174 offset = ((offset / bp->flash_info->page_size) <<
4175 bp->flash_info->page_bits) +
4176 (offset % bp->flash_info->page_size);
4177 }
4178
4179 /* Need to clear DONE bit separately. */
4180 REG_WR(bp, BNX2_NVM_COMMAND, BNX2_NVM_COMMAND_DONE);
4181
4182 /* Address of the NVRAM to read from. */
4183 REG_WR(bp, BNX2_NVM_ADDR, offset & BNX2_NVM_ADDR_NVM_ADDR_VALUE);
4184
4185 /* Issue a read command. */
4186 REG_WR(bp, BNX2_NVM_COMMAND, cmd);
4187
4188 /* Wait for completion. */
4189 for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) {
4190 u32 val;
4191
4192 udelay(5);
4193
4194 val = REG_RD(bp, BNX2_NVM_COMMAND);
4195 if (val & BNX2_NVM_COMMAND_DONE) {
Al Virob491edd2007-12-22 19:44:51 +00004196 __be32 v = cpu_to_be32(REG_RD(bp, BNX2_NVM_READ));
4197 memcpy(ret_val, &v, 4);
Michael Chanb6016b72005-05-26 13:03:09 -07004198 break;
4199 }
4200 }
4201 if (j >= NVRAM_TIMEOUT_COUNT)
4202 return -EBUSY;
4203
4204 return 0;
4205}
4206
4207
4208static int
4209bnx2_nvram_write_dword(struct bnx2 *bp, u32 offset, u8 *val, u32 cmd_flags)
4210{
Al Virob491edd2007-12-22 19:44:51 +00004211 u32 cmd;
4212 __be32 val32;
Michael Chanb6016b72005-05-26 13:03:09 -07004213 int j;
4214
4215 /* Build the command word. */
4216 cmd = BNX2_NVM_COMMAND_DOIT | BNX2_NVM_COMMAND_WR | cmd_flags;
4217
Michael Chane30372c2007-07-16 18:26:23 -07004218 /* Calculate an offset of a buffered flash, not needed for 5709. */
4219 if (bp->flash_info->flags & BNX2_NV_TRANSLATE) {
Michael Chanb6016b72005-05-26 13:03:09 -07004220 offset = ((offset / bp->flash_info->page_size) <<
4221 bp->flash_info->page_bits) +
4222 (offset % bp->flash_info->page_size);
4223 }
4224
4225 /* Need to clear DONE bit separately. */
4226 REG_WR(bp, BNX2_NVM_COMMAND, BNX2_NVM_COMMAND_DONE);
4227
4228 memcpy(&val32, val, 4);
Michael Chanb6016b72005-05-26 13:03:09 -07004229
4230 /* Write the data. */
Al Virob491edd2007-12-22 19:44:51 +00004231 REG_WR(bp, BNX2_NVM_WRITE, be32_to_cpu(val32));
Michael Chanb6016b72005-05-26 13:03:09 -07004232
4233 /* Address of the NVRAM to write to. */
4234 REG_WR(bp, BNX2_NVM_ADDR, offset & BNX2_NVM_ADDR_NVM_ADDR_VALUE);
4235
4236 /* Issue the write command. */
4237 REG_WR(bp, BNX2_NVM_COMMAND, cmd);
4238
4239 /* Wait for completion. */
4240 for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) {
4241 udelay(5);
4242
4243 if (REG_RD(bp, BNX2_NVM_COMMAND) & BNX2_NVM_COMMAND_DONE)
4244 break;
4245 }
4246 if (j >= NVRAM_TIMEOUT_COUNT)
4247 return -EBUSY;
4248
4249 return 0;
4250}
4251
4252static int
4253bnx2_init_nvram(struct bnx2 *bp)
4254{
4255 u32 val;
Michael Chane30372c2007-07-16 18:26:23 -07004256 int j, entry_count, rc = 0;
Michael Chan0ced9d02009-08-21 16:20:49 +00004257 const struct flash_spec *flash;
Michael Chanb6016b72005-05-26 13:03:09 -07004258
Michael Chane30372c2007-07-16 18:26:23 -07004259 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
4260 bp->flash_info = &flash_5709;
4261 goto get_flash_size;
4262 }
4263
Michael Chanb6016b72005-05-26 13:03:09 -07004264 /* Determine the selected interface. */
4265 val = REG_RD(bp, BNX2_NVM_CFG1);
4266
Denis Chengff8ac602007-09-02 18:30:18 +08004267 entry_count = ARRAY_SIZE(flash_table);
Michael Chanb6016b72005-05-26 13:03:09 -07004268
Michael Chanb6016b72005-05-26 13:03:09 -07004269 if (val & 0x40000000) {
4270
4271 /* Flash interface has been reconfigured */
4272 for (j = 0, flash = &flash_table[0]; j < entry_count;
Michael Chan37137702005-11-04 08:49:17 -08004273 j++, flash++) {
4274 if ((val & FLASH_BACKUP_STRAP_MASK) ==
4275 (flash->config1 & FLASH_BACKUP_STRAP_MASK)) {
Michael Chanb6016b72005-05-26 13:03:09 -07004276 bp->flash_info = flash;
4277 break;
4278 }
4279 }
4280 }
4281 else {
Michael Chan37137702005-11-04 08:49:17 -08004282 u32 mask;
Michael Chanb6016b72005-05-26 13:03:09 -07004283 /* Not yet been reconfigured */
4284
Michael Chan37137702005-11-04 08:49:17 -08004285 if (val & (1 << 23))
4286 mask = FLASH_BACKUP_STRAP_MASK;
4287 else
4288 mask = FLASH_STRAP_MASK;
4289
Michael Chanb6016b72005-05-26 13:03:09 -07004290 for (j = 0, flash = &flash_table[0]; j < entry_count;
4291 j++, flash++) {
4292
Michael Chan37137702005-11-04 08:49:17 -08004293 if ((val & mask) == (flash->strapping & mask)) {
Michael Chanb6016b72005-05-26 13:03:09 -07004294 bp->flash_info = flash;
4295
4296 /* Request access to the flash interface. */
4297 if ((rc = bnx2_acquire_nvram_lock(bp)) != 0)
4298 return rc;
4299
4300 /* Enable access to flash interface */
4301 bnx2_enable_nvram_access(bp);
4302
4303 /* Reconfigure the flash interface */
4304 REG_WR(bp, BNX2_NVM_CFG1, flash->config1);
4305 REG_WR(bp, BNX2_NVM_CFG2, flash->config2);
4306 REG_WR(bp, BNX2_NVM_CFG3, flash->config3);
4307 REG_WR(bp, BNX2_NVM_WRITE1, flash->write1);
4308
4309 /* Disable access to flash interface */
4310 bnx2_disable_nvram_access(bp);
4311 bnx2_release_nvram_lock(bp);
4312
4313 break;
4314 }
4315 }
4316 } /* if (val & 0x40000000) */
4317
4318 if (j == entry_count) {
4319 bp->flash_info = NULL;
John W. Linville2f23c522005-11-10 12:57:33 -08004320 printk(KERN_ALERT PFX "Unknown flash/EEPROM type.\n");
Michael Chan1122db72006-01-23 16:11:42 -08004321 return -ENODEV;
Michael Chanb6016b72005-05-26 13:03:09 -07004322 }
4323
Michael Chane30372c2007-07-16 18:26:23 -07004324get_flash_size:
Michael Chan2726d6e2008-01-29 21:35:05 -08004325 val = bnx2_shmem_rd(bp, BNX2_SHARED_HW_CFG_CONFIG2);
Michael Chan1122db72006-01-23 16:11:42 -08004326 val &= BNX2_SHARED_HW_CFG2_NVM_SIZE_MASK;
4327 if (val)
4328 bp->flash_size = val;
4329 else
4330 bp->flash_size = bp->flash_info->total_size;
4331
Michael Chanb6016b72005-05-26 13:03:09 -07004332 return rc;
4333}
4334
4335static int
4336bnx2_nvram_read(struct bnx2 *bp, u32 offset, u8 *ret_buf,
4337 int buf_size)
4338{
4339 int rc = 0;
4340 u32 cmd_flags, offset32, len32, extra;
4341
4342 if (buf_size == 0)
4343 return 0;
4344
4345 /* Request access to the flash interface. */
4346 if ((rc = bnx2_acquire_nvram_lock(bp)) != 0)
4347 return rc;
4348
4349 /* Enable access to flash interface */
4350 bnx2_enable_nvram_access(bp);
4351
4352 len32 = buf_size;
4353 offset32 = offset;
4354 extra = 0;
4355
4356 cmd_flags = 0;
4357
4358 if (offset32 & 3) {
4359 u8 buf[4];
4360 u32 pre_len;
4361
4362 offset32 &= ~3;
4363 pre_len = 4 - (offset & 3);
4364
4365 if (pre_len >= len32) {
4366 pre_len = len32;
4367 cmd_flags = BNX2_NVM_COMMAND_FIRST |
4368 BNX2_NVM_COMMAND_LAST;
4369 }
4370 else {
4371 cmd_flags = BNX2_NVM_COMMAND_FIRST;
4372 }
4373
4374 rc = bnx2_nvram_read_dword(bp, offset32, buf, cmd_flags);
4375
4376 if (rc)
4377 return rc;
4378
4379 memcpy(ret_buf, buf + (offset & 3), pre_len);
4380
4381 offset32 += 4;
4382 ret_buf += pre_len;
4383 len32 -= pre_len;
4384 }
4385 if (len32 & 3) {
4386 extra = 4 - (len32 & 3);
4387 len32 = (len32 + 4) & ~3;
4388 }
4389
4390 if (len32 == 4) {
4391 u8 buf[4];
4392
4393 if (cmd_flags)
4394 cmd_flags = BNX2_NVM_COMMAND_LAST;
4395 else
4396 cmd_flags = BNX2_NVM_COMMAND_FIRST |
4397 BNX2_NVM_COMMAND_LAST;
4398
4399 rc = bnx2_nvram_read_dword(bp, offset32, buf, cmd_flags);
4400
4401 memcpy(ret_buf, buf, 4 - extra);
4402 }
4403 else if (len32 > 0) {
4404 u8 buf[4];
4405
4406 /* Read the first word. */
4407 if (cmd_flags)
4408 cmd_flags = 0;
4409 else
4410 cmd_flags = BNX2_NVM_COMMAND_FIRST;
4411
4412 rc = bnx2_nvram_read_dword(bp, offset32, ret_buf, cmd_flags);
4413
4414 /* Advance to the next dword. */
4415 offset32 += 4;
4416 ret_buf += 4;
4417 len32 -= 4;
4418
4419 while (len32 > 4 && rc == 0) {
4420 rc = bnx2_nvram_read_dword(bp, offset32, ret_buf, 0);
4421
4422 /* Advance to the next dword. */
4423 offset32 += 4;
4424 ret_buf += 4;
4425 len32 -= 4;
4426 }
4427
4428 if (rc)
4429 return rc;
4430
4431 cmd_flags = BNX2_NVM_COMMAND_LAST;
4432 rc = bnx2_nvram_read_dword(bp, offset32, buf, cmd_flags);
4433
4434 memcpy(ret_buf, buf, 4 - extra);
4435 }
4436
4437 /* Disable access to flash interface */
4438 bnx2_disable_nvram_access(bp);
4439
4440 bnx2_release_nvram_lock(bp);
4441
4442 return rc;
4443}
4444
4445static int
4446bnx2_nvram_write(struct bnx2 *bp, u32 offset, u8 *data_buf,
4447 int buf_size)
4448{
4449 u32 written, offset32, len32;
Michael Chane6be7632007-01-08 19:56:13 -08004450 u8 *buf, start[4], end[4], *align_buf = NULL, *flash_buffer = NULL;
Michael Chanb6016b72005-05-26 13:03:09 -07004451 int rc = 0;
4452 int align_start, align_end;
4453
4454 buf = data_buf;
4455 offset32 = offset;
4456 len32 = buf_size;
4457 align_start = align_end = 0;
4458
4459 if ((align_start = (offset32 & 3))) {
4460 offset32 &= ~3;
Michael Chanc8738792007-03-30 14:53:06 -07004461 len32 += align_start;
4462 if (len32 < 4)
4463 len32 = 4;
Michael Chanb6016b72005-05-26 13:03:09 -07004464 if ((rc = bnx2_nvram_read(bp, offset32, start, 4)))
4465 return rc;
4466 }
4467
4468 if (len32 & 3) {
Michael Chanc8738792007-03-30 14:53:06 -07004469 align_end = 4 - (len32 & 3);
4470 len32 += align_end;
4471 if ((rc = bnx2_nvram_read(bp, offset32 + len32 - 4, end, 4)))
4472 return rc;
Michael Chanb6016b72005-05-26 13:03:09 -07004473 }
4474
4475 if (align_start || align_end) {
Michael Chane6be7632007-01-08 19:56:13 -08004476 align_buf = kmalloc(len32, GFP_KERNEL);
4477 if (align_buf == NULL)
Michael Chanb6016b72005-05-26 13:03:09 -07004478 return -ENOMEM;
4479 if (align_start) {
Michael Chane6be7632007-01-08 19:56:13 -08004480 memcpy(align_buf, start, 4);
Michael Chanb6016b72005-05-26 13:03:09 -07004481 }
4482 if (align_end) {
Michael Chane6be7632007-01-08 19:56:13 -08004483 memcpy(align_buf + len32 - 4, end, 4);
Michael Chanb6016b72005-05-26 13:03:09 -07004484 }
Michael Chane6be7632007-01-08 19:56:13 -08004485 memcpy(align_buf + align_start, data_buf, buf_size);
4486 buf = align_buf;
Michael Chanb6016b72005-05-26 13:03:09 -07004487 }
4488
Michael Chane30372c2007-07-16 18:26:23 -07004489 if (!(bp->flash_info->flags & BNX2_NV_BUFFERED)) {
Michael Chanae181bc2006-05-22 16:39:20 -07004490 flash_buffer = kmalloc(264, GFP_KERNEL);
4491 if (flash_buffer == NULL) {
4492 rc = -ENOMEM;
4493 goto nvram_write_end;
4494 }
4495 }
4496
Michael Chanb6016b72005-05-26 13:03:09 -07004497 written = 0;
4498 while ((written < len32) && (rc == 0)) {
4499 u32 page_start, page_end, data_start, data_end;
4500 u32 addr, cmd_flags;
4501 int i;
Michael Chanb6016b72005-05-26 13:03:09 -07004502
4503 /* Find the page_start addr */
4504 page_start = offset32 + written;
4505 page_start -= (page_start % bp->flash_info->page_size);
4506 /* Find the page_end addr */
4507 page_end = page_start + bp->flash_info->page_size;
4508 /* Find the data_start addr */
4509 data_start = (written == 0) ? offset32 : page_start;
4510 /* Find the data_end addr */
Jeff Garzik6aa20a22006-09-13 13:24:59 -04004511 data_end = (page_end > offset32 + len32) ?
Michael Chanb6016b72005-05-26 13:03:09 -07004512 (offset32 + len32) : page_end;
4513
4514 /* Request access to the flash interface. */
4515 if ((rc = bnx2_acquire_nvram_lock(bp)) != 0)
4516 goto nvram_write_end;
4517
4518 /* Enable access to flash interface */
4519 bnx2_enable_nvram_access(bp);
4520
4521 cmd_flags = BNX2_NVM_COMMAND_FIRST;
Michael Chane30372c2007-07-16 18:26:23 -07004522 if (!(bp->flash_info->flags & BNX2_NV_BUFFERED)) {
Michael Chanb6016b72005-05-26 13:03:09 -07004523 int j;
4524
4525 /* Read the whole page into the buffer
4526 * (non-buffer flash only) */
4527 for (j = 0; j < bp->flash_info->page_size; j += 4) {
4528 if (j == (bp->flash_info->page_size - 4)) {
4529 cmd_flags |= BNX2_NVM_COMMAND_LAST;
4530 }
4531 rc = bnx2_nvram_read_dword(bp,
Jeff Garzik6aa20a22006-09-13 13:24:59 -04004532 page_start + j,
4533 &flash_buffer[j],
Michael Chanb6016b72005-05-26 13:03:09 -07004534 cmd_flags);
4535
4536 if (rc)
4537 goto nvram_write_end;
4538
4539 cmd_flags = 0;
4540 }
4541 }
4542
4543 /* Enable writes to flash interface (unlock write-protect) */
4544 if ((rc = bnx2_enable_nvram_write(bp)) != 0)
4545 goto nvram_write_end;
4546
Michael Chanb6016b72005-05-26 13:03:09 -07004547 /* Loop to write back the buffer data from page_start to
4548 * data_start */
4549 i = 0;
Michael Chane30372c2007-07-16 18:26:23 -07004550 if (!(bp->flash_info->flags & BNX2_NV_BUFFERED)) {
Michael Chanc8738792007-03-30 14:53:06 -07004551 /* Erase the page */
4552 if ((rc = bnx2_nvram_erase_page(bp, page_start)) != 0)
4553 goto nvram_write_end;
4554
4555 /* Re-enable the write again for the actual write */
4556 bnx2_enable_nvram_write(bp);
4557
Michael Chanb6016b72005-05-26 13:03:09 -07004558 for (addr = page_start; addr < data_start;
4559 addr += 4, i += 4) {
Jeff Garzik6aa20a22006-09-13 13:24:59 -04004560
Michael Chanb6016b72005-05-26 13:03:09 -07004561 rc = bnx2_nvram_write_dword(bp, addr,
4562 &flash_buffer[i], cmd_flags);
4563
4564 if (rc != 0)
4565 goto nvram_write_end;
4566
4567 cmd_flags = 0;
4568 }
4569 }
4570
4571 /* Loop to write the new data from data_start to data_end */
Michael Chanbae25762006-05-22 16:38:38 -07004572 for (addr = data_start; addr < data_end; addr += 4, i += 4) {
Michael Chanb6016b72005-05-26 13:03:09 -07004573 if ((addr == page_end - 4) ||
Michael Chane30372c2007-07-16 18:26:23 -07004574 ((bp->flash_info->flags & BNX2_NV_BUFFERED) &&
Michael Chanb6016b72005-05-26 13:03:09 -07004575 (addr == data_end - 4))) {
4576
4577 cmd_flags |= BNX2_NVM_COMMAND_LAST;
4578 }
4579 rc = bnx2_nvram_write_dword(bp, addr, buf,
4580 cmd_flags);
4581
4582 if (rc != 0)
4583 goto nvram_write_end;
4584
4585 cmd_flags = 0;
4586 buf += 4;
4587 }
4588
4589 /* Loop to write back the buffer data from data_end
4590 * to page_end */
Michael Chane30372c2007-07-16 18:26:23 -07004591 if (!(bp->flash_info->flags & BNX2_NV_BUFFERED)) {
Michael Chanb6016b72005-05-26 13:03:09 -07004592 for (addr = data_end; addr < page_end;
4593 addr += 4, i += 4) {
Jeff Garzik6aa20a22006-09-13 13:24:59 -04004594
Michael Chanb6016b72005-05-26 13:03:09 -07004595 if (addr == page_end-4) {
4596 cmd_flags = BNX2_NVM_COMMAND_LAST;
4597 }
4598 rc = bnx2_nvram_write_dword(bp, addr,
4599 &flash_buffer[i], cmd_flags);
4600
4601 if (rc != 0)
4602 goto nvram_write_end;
4603
4604 cmd_flags = 0;
4605 }
4606 }
4607
4608 /* Disable writes to flash interface (lock write-protect) */
4609 bnx2_disable_nvram_write(bp);
4610
4611 /* Disable access to flash interface */
4612 bnx2_disable_nvram_access(bp);
4613 bnx2_release_nvram_lock(bp);
4614
4615 /* Increment written */
4616 written += data_end - data_start;
4617 }
4618
4619nvram_write_end:
Michael Chane6be7632007-01-08 19:56:13 -08004620 kfree(flash_buffer);
4621 kfree(align_buf);
Michael Chanb6016b72005-05-26 13:03:09 -07004622 return rc;
4623}
4624
Michael Chan0d8a6572007-07-07 22:49:43 -07004625static void
Michael Chan7c62e832008-07-14 22:39:03 -07004626bnx2_init_fw_cap(struct bnx2 *bp)
Michael Chan0d8a6572007-07-07 22:49:43 -07004627{
Michael Chan7c62e832008-07-14 22:39:03 -07004628 u32 val, sig = 0;
Michael Chan0d8a6572007-07-07 22:49:43 -07004629
Michael Chan583c28e2008-01-21 19:51:35 -08004630 bp->phy_flags &= ~BNX2_PHY_FLAG_REMOTE_PHY_CAP;
Michael Chan7c62e832008-07-14 22:39:03 -07004631 bp->flags &= ~BNX2_FLAG_CAN_KEEP_VLAN;
4632
4633 if (!(bp->flags & BNX2_FLAG_ASF_ENABLE))
4634 bp->flags |= BNX2_FLAG_CAN_KEEP_VLAN;
Michael Chan0d8a6572007-07-07 22:49:43 -07004635
Michael Chan2726d6e2008-01-29 21:35:05 -08004636 val = bnx2_shmem_rd(bp, BNX2_FW_CAP_MB);
Michael Chan0d8a6572007-07-07 22:49:43 -07004637 if ((val & BNX2_FW_CAP_SIGNATURE_MASK) != BNX2_FW_CAP_SIGNATURE)
4638 return;
4639
Michael Chan7c62e832008-07-14 22:39:03 -07004640 if ((val & BNX2_FW_CAP_CAN_KEEP_VLAN) == BNX2_FW_CAP_CAN_KEEP_VLAN) {
4641 bp->flags |= BNX2_FLAG_CAN_KEEP_VLAN;
4642 sig |= BNX2_DRV_ACK_CAP_SIGNATURE | BNX2_FW_CAP_CAN_KEEP_VLAN;
4643 }
4644
4645 if ((bp->phy_flags & BNX2_PHY_FLAG_SERDES) &&
4646 (val & BNX2_FW_CAP_REMOTE_PHY_CAPABLE)) {
4647 u32 link;
4648
Michael Chan583c28e2008-01-21 19:51:35 -08004649 bp->phy_flags |= BNX2_PHY_FLAG_REMOTE_PHY_CAP;
Michael Chan0d8a6572007-07-07 22:49:43 -07004650
Michael Chan7c62e832008-07-14 22:39:03 -07004651 link = bnx2_shmem_rd(bp, BNX2_LINK_STATUS);
4652 if (link & BNX2_LINK_STATUS_SERDES_LINK)
Michael Chan0d8a6572007-07-07 22:49:43 -07004653 bp->phy_port = PORT_FIBRE;
4654 else
4655 bp->phy_port = PORT_TP;
Michael Chan489310a2007-10-10 16:16:31 -07004656
Michael Chan7c62e832008-07-14 22:39:03 -07004657 sig |= BNX2_DRV_ACK_CAP_SIGNATURE |
4658 BNX2_FW_CAP_REMOTE_PHY_CAPABLE;
Michael Chan0d8a6572007-07-07 22:49:43 -07004659 }
Michael Chan7c62e832008-07-14 22:39:03 -07004660
4661 if (netif_running(bp->dev) && sig)
4662 bnx2_shmem_wr(bp, BNX2_DRV_ACK_CAP_MB, sig);
Michael Chan0d8a6572007-07-07 22:49:43 -07004663}
4664
Michael Chanb4b36042007-12-20 19:59:30 -08004665static void
4666bnx2_setup_msix_tbl(struct bnx2 *bp)
4667{
4668 REG_WR(bp, BNX2_PCI_GRC_WINDOW_ADDR, BNX2_PCI_GRC_WINDOW_ADDR_SEP_WIN);
4669
4670 REG_WR(bp, BNX2_PCI_GRC_WINDOW2_ADDR, BNX2_MSIX_TABLE_ADDR);
4671 REG_WR(bp, BNX2_PCI_GRC_WINDOW3_ADDR, BNX2_MSIX_PBA_ADDR);
4672}
4673
Michael Chanb6016b72005-05-26 13:03:09 -07004674static int
4675bnx2_reset_chip(struct bnx2 *bp, u32 reset_code)
4676{
4677 u32 val;
4678 int i, rc = 0;
Michael Chan489310a2007-10-10 16:16:31 -07004679 u8 old_port;
Michael Chanb6016b72005-05-26 13:03:09 -07004680
4681 /* Wait for the current PCI transaction to complete before
4682 * issuing a reset. */
4683 REG_WR(bp, BNX2_MISC_ENABLE_CLR_BITS,
4684 BNX2_MISC_ENABLE_CLR_BITS_TX_DMA_ENABLE |
4685 BNX2_MISC_ENABLE_CLR_BITS_DMA_ENGINE_ENABLE |
4686 BNX2_MISC_ENABLE_CLR_BITS_RX_DMA_ENABLE |
4687 BNX2_MISC_ENABLE_CLR_BITS_HOST_COALESCE_ENABLE);
4688 val = REG_RD(bp, BNX2_MISC_ENABLE_CLR_BITS);
4689 udelay(5);
4690
Michael Chanb090ae22006-01-23 16:07:10 -08004691 /* Wait for the firmware to tell us it is ok to issue a reset. */
Michael Chana2f13892008-07-14 22:38:23 -07004692 bnx2_fw_sync(bp, BNX2_DRV_MSG_DATA_WAIT0 | reset_code, 1, 1);
Michael Chanb090ae22006-01-23 16:07:10 -08004693
Michael Chanb6016b72005-05-26 13:03:09 -07004694 /* Deposit a driver reset signature so the firmware knows that
4695 * this is a soft reset. */
Michael Chan2726d6e2008-01-29 21:35:05 -08004696 bnx2_shmem_wr(bp, BNX2_DRV_RESET_SIGNATURE,
4697 BNX2_DRV_RESET_SIGNATURE_MAGIC);
Michael Chanb6016b72005-05-26 13:03:09 -07004698
Michael Chanb6016b72005-05-26 13:03:09 -07004699 /* Do a dummy read to force the chip to complete all current transaction
4700 * before we issue a reset. */
4701 val = REG_RD(bp, BNX2_MISC_ID);
4702
Michael Chan234754d2006-11-19 14:11:41 -08004703 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
4704 REG_WR(bp, BNX2_MISC_COMMAND, BNX2_MISC_COMMAND_SW_RESET);
4705 REG_RD(bp, BNX2_MISC_COMMAND);
4706 udelay(5);
Michael Chanb6016b72005-05-26 13:03:09 -07004707
Michael Chan234754d2006-11-19 14:11:41 -08004708 val = BNX2_PCICFG_MISC_CONFIG_REG_WINDOW_ENA |
4709 BNX2_PCICFG_MISC_CONFIG_TARGET_MB_WORD_SWAP;
Michael Chanb6016b72005-05-26 13:03:09 -07004710
Michael Chan234754d2006-11-19 14:11:41 -08004711 pci_write_config_dword(bp->pdev, BNX2_PCICFG_MISC_CONFIG, val);
Michael Chanb6016b72005-05-26 13:03:09 -07004712
Michael Chan234754d2006-11-19 14:11:41 -08004713 } else {
4714 val = BNX2_PCICFG_MISC_CONFIG_CORE_RST_REQ |
4715 BNX2_PCICFG_MISC_CONFIG_REG_WINDOW_ENA |
4716 BNX2_PCICFG_MISC_CONFIG_TARGET_MB_WORD_SWAP;
4717
4718 /* Chip reset. */
4719 REG_WR(bp, BNX2_PCICFG_MISC_CONFIG, val);
4720
Michael Chan594a9df2007-08-28 15:39:42 -07004721 /* Reading back any register after chip reset will hang the
4722 * bus on 5706 A0 and A1. The msleep below provides plenty
4723 * of margin for write posting.
4724 */
Michael Chan234754d2006-11-19 14:11:41 -08004725 if ((CHIP_ID(bp) == CHIP_ID_5706_A0) ||
Arjan van de Ven8e545882007-08-28 14:34:43 -07004726 (CHIP_ID(bp) == CHIP_ID_5706_A1))
4727 msleep(20);
Michael Chanb6016b72005-05-26 13:03:09 -07004728
Michael Chan234754d2006-11-19 14:11:41 -08004729 /* Reset takes approximate 30 usec */
4730 for (i = 0; i < 10; i++) {
4731 val = REG_RD(bp, BNX2_PCICFG_MISC_CONFIG);
4732 if ((val & (BNX2_PCICFG_MISC_CONFIG_CORE_RST_REQ |
4733 BNX2_PCICFG_MISC_CONFIG_CORE_RST_BSY)) == 0)
4734 break;
4735 udelay(10);
4736 }
4737
4738 if (val & (BNX2_PCICFG_MISC_CONFIG_CORE_RST_REQ |
4739 BNX2_PCICFG_MISC_CONFIG_CORE_RST_BSY)) {
4740 printk(KERN_ERR PFX "Chip reset did not complete\n");
4741 return -EBUSY;
4742 }
Michael Chanb6016b72005-05-26 13:03:09 -07004743 }
4744
4745 /* Make sure byte swapping is properly configured. */
4746 val = REG_RD(bp, BNX2_PCI_SWAP_DIAG0);
4747 if (val != 0x01020304) {
4748 printk(KERN_ERR PFX "Chip not in correct endian mode\n");
4749 return -ENODEV;
4750 }
4751
Michael Chanb6016b72005-05-26 13:03:09 -07004752 /* Wait for the firmware to finish its initialization. */
Michael Chana2f13892008-07-14 22:38:23 -07004753 rc = bnx2_fw_sync(bp, BNX2_DRV_MSG_DATA_WAIT1 | reset_code, 1, 0);
Michael Chanb090ae22006-01-23 16:07:10 -08004754 if (rc)
4755 return rc;
Michael Chanb6016b72005-05-26 13:03:09 -07004756
Michael Chan0d8a6572007-07-07 22:49:43 -07004757 spin_lock_bh(&bp->phy_lock);
Michael Chan489310a2007-10-10 16:16:31 -07004758 old_port = bp->phy_port;
Michael Chan7c62e832008-07-14 22:39:03 -07004759 bnx2_init_fw_cap(bp);
Michael Chan583c28e2008-01-21 19:51:35 -08004760 if ((bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP) &&
4761 old_port != bp->phy_port)
Michael Chan0d8a6572007-07-07 22:49:43 -07004762 bnx2_set_default_remote_link(bp);
4763 spin_unlock_bh(&bp->phy_lock);
4764
Michael Chanb6016b72005-05-26 13:03:09 -07004765 if (CHIP_ID(bp) == CHIP_ID_5706_A0) {
4766 /* Adjust the voltage regular to two steps lower. The default
4767 * of this register is 0x0000000e. */
4768 REG_WR(bp, BNX2_MISC_VREG_CONTROL, 0x000000fa);
4769
4770 /* Remove bad rbuf memory from the free pool. */
4771 rc = bnx2_alloc_bad_rbuf(bp);
4772 }
4773
David S. Millerf86e82f2008-01-21 17:15:40 -08004774 if (bp->flags & BNX2_FLAG_USING_MSIX)
Michael Chanb4b36042007-12-20 19:59:30 -08004775 bnx2_setup_msix_tbl(bp);
4776
Michael Chanb6016b72005-05-26 13:03:09 -07004777 return rc;
4778}
4779
4780static int
4781bnx2_init_chip(struct bnx2 *bp)
4782{
Michael Chand8026d92008-11-12 16:02:20 -08004783 u32 val, mtu;
Michael Chanb4b36042007-12-20 19:59:30 -08004784 int rc, i;
Michael Chanb6016b72005-05-26 13:03:09 -07004785
4786 /* Make sure the interrupt is not active. */
4787 REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD, BNX2_PCICFG_INT_ACK_CMD_MASK_INT);
4788
4789 val = BNX2_DMA_CONFIG_DATA_BYTE_SWAP |
4790 BNX2_DMA_CONFIG_DATA_WORD_SWAP |
4791#ifdef __BIG_ENDIAN
Jeff Garzik6aa20a22006-09-13 13:24:59 -04004792 BNX2_DMA_CONFIG_CNTL_BYTE_SWAP |
Michael Chanb6016b72005-05-26 13:03:09 -07004793#endif
Jeff Garzik6aa20a22006-09-13 13:24:59 -04004794 BNX2_DMA_CONFIG_CNTL_WORD_SWAP |
Michael Chanb6016b72005-05-26 13:03:09 -07004795 DMA_READ_CHANS << 12 |
4796 DMA_WRITE_CHANS << 16;
4797
4798 val |= (0x2 << 20) | (1 << 11);
4799
David S. Millerf86e82f2008-01-21 17:15:40 -08004800 if ((bp->flags & BNX2_FLAG_PCIX) && (bp->bus_speed_mhz == 133))
Michael Chanb6016b72005-05-26 13:03:09 -07004801 val |= (1 << 23);
4802
4803 if ((CHIP_NUM(bp) == CHIP_NUM_5706) &&
David S. Millerf86e82f2008-01-21 17:15:40 -08004804 (CHIP_ID(bp) != CHIP_ID_5706_A0) && !(bp->flags & BNX2_FLAG_PCIX))
Michael Chanb6016b72005-05-26 13:03:09 -07004805 val |= BNX2_DMA_CONFIG_CNTL_PING_PONG_DMA;
4806
4807 REG_WR(bp, BNX2_DMA_CONFIG, val);
4808
4809 if (CHIP_ID(bp) == CHIP_ID_5706_A0) {
4810 val = REG_RD(bp, BNX2_TDMA_CONFIG);
4811 val |= BNX2_TDMA_CONFIG_ONE_DMA;
4812 REG_WR(bp, BNX2_TDMA_CONFIG, val);
4813 }
4814
David S. Millerf86e82f2008-01-21 17:15:40 -08004815 if (bp->flags & BNX2_FLAG_PCIX) {
Michael Chanb6016b72005-05-26 13:03:09 -07004816 u16 val16;
4817
4818 pci_read_config_word(bp->pdev, bp->pcix_cap + PCI_X_CMD,
4819 &val16);
4820 pci_write_config_word(bp->pdev, bp->pcix_cap + PCI_X_CMD,
4821 val16 & ~PCI_X_CMD_ERO);
4822 }
4823
4824 REG_WR(bp, BNX2_MISC_ENABLE_SET_BITS,
4825 BNX2_MISC_ENABLE_SET_BITS_HOST_COALESCE_ENABLE |
4826 BNX2_MISC_ENABLE_STATUS_BITS_RX_V2P_ENABLE |
4827 BNX2_MISC_ENABLE_STATUS_BITS_CONTEXT_ENABLE);
4828
4829 /* Initialize context mapping and zero out the quick contexts. The
4830 * context block must have already been enabled. */
Michael Chan641bdcd2007-06-04 21:22:24 -07004831 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
4832 rc = bnx2_init_5709_context(bp);
4833 if (rc)
4834 return rc;
4835 } else
Michael Chan59b47d82006-11-19 14:10:45 -08004836 bnx2_init_context(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07004837
Michael Chanfba9fe92006-06-12 22:21:25 -07004838 if ((rc = bnx2_init_cpus(bp)) != 0)
4839 return rc;
4840
Michael Chanb6016b72005-05-26 13:03:09 -07004841 bnx2_init_nvram(bp);
4842
Benjamin Li5fcaed02008-07-14 22:39:52 -07004843 bnx2_set_mac_addr(bp, bp->dev->dev_addr, 0);
Michael Chanb6016b72005-05-26 13:03:09 -07004844
4845 val = REG_RD(bp, BNX2_MQ_CONFIG);
4846 val &= ~BNX2_MQ_CONFIG_KNL_BYP_BLK_SIZE;
4847 val |= BNX2_MQ_CONFIG_KNL_BYP_BLK_SIZE_256;
Michael Chan4edd4732009-06-08 18:14:42 -07004848 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
4849 val |= BNX2_MQ_CONFIG_BIN_MQ_MODE;
4850 if (CHIP_REV(bp) == CHIP_REV_Ax)
4851 val |= BNX2_MQ_CONFIG_HALT_DIS;
4852 }
Michael Chan68c9f752007-04-24 15:35:53 -07004853
Michael Chanb6016b72005-05-26 13:03:09 -07004854 REG_WR(bp, BNX2_MQ_CONFIG, val);
4855
4856 val = 0x10000 + (MAX_CID_CNT * MB_KERNEL_CTX_SIZE);
4857 REG_WR(bp, BNX2_MQ_KNL_BYP_WIND_START, val);
4858 REG_WR(bp, BNX2_MQ_KNL_WIND_END, val);
4859
4860 val = (BCM_PAGE_BITS - 8) << 24;
4861 REG_WR(bp, BNX2_RV2P_CONFIG, val);
4862
4863 /* Configure page size. */
4864 val = REG_RD(bp, BNX2_TBDR_CONFIG);
4865 val &= ~BNX2_TBDR_CONFIG_PAGE_SIZE;
4866 val |= (BCM_PAGE_BITS - 8) << 24 | 0x40;
4867 REG_WR(bp, BNX2_TBDR_CONFIG, val);
4868
4869 val = bp->mac_addr[0] +
4870 (bp->mac_addr[1] << 8) +
4871 (bp->mac_addr[2] << 16) +
4872 bp->mac_addr[3] +
4873 (bp->mac_addr[4] << 8) +
4874 (bp->mac_addr[5] << 16);
4875 REG_WR(bp, BNX2_EMAC_BACKOFF_SEED, val);
4876
4877 /* Program the MTU. Also include 4 bytes for CRC32. */
Michael Chand8026d92008-11-12 16:02:20 -08004878 mtu = bp->dev->mtu;
4879 val = mtu + ETH_HLEN + ETH_FCS_LEN;
Michael Chanb6016b72005-05-26 13:03:09 -07004880 if (val > (MAX_ETHERNET_PACKET_SIZE + 4))
4881 val |= BNX2_EMAC_RX_MTU_SIZE_JUMBO_ENA;
4882 REG_WR(bp, BNX2_EMAC_RX_MTU_SIZE, val);
4883
Michael Chand8026d92008-11-12 16:02:20 -08004884 if (mtu < 1500)
4885 mtu = 1500;
4886
4887 bnx2_reg_wr_ind(bp, BNX2_RBUF_CONFIG, BNX2_RBUF_CONFIG_VAL(mtu));
4888 bnx2_reg_wr_ind(bp, BNX2_RBUF_CONFIG2, BNX2_RBUF_CONFIG2_VAL(mtu));
4889 bnx2_reg_wr_ind(bp, BNX2_RBUF_CONFIG3, BNX2_RBUF_CONFIG3_VAL(mtu));
4890
Michael Chan155d5562009-08-21 16:20:43 +00004891 memset(bp->bnx2_napi[0].status_blk.msi, 0, bp->status_stats_size);
Michael Chanb4b36042007-12-20 19:59:30 -08004892 for (i = 0; i < BNX2_MAX_MSIX_VEC; i++)
4893 bp->bnx2_napi[i].last_status_idx = 0;
4894
Michael Chanefba0182008-12-03 00:36:15 -08004895 bp->idle_chk_status_idx = 0xffff;
4896
Michael Chanb6016b72005-05-26 13:03:09 -07004897 bp->rx_mode = BNX2_EMAC_RX_MODE_SORT_MODE;
4898
4899 /* Set up how to generate a link change interrupt. */
4900 REG_WR(bp, BNX2_EMAC_ATTENTION_ENA, BNX2_EMAC_ATTENTION_ENA_LINK);
4901
4902 REG_WR(bp, BNX2_HC_STATUS_ADDR_L,
4903 (u64) bp->status_blk_mapping & 0xffffffff);
4904 REG_WR(bp, BNX2_HC_STATUS_ADDR_H, (u64) bp->status_blk_mapping >> 32);
4905
4906 REG_WR(bp, BNX2_HC_STATISTICS_ADDR_L,
4907 (u64) bp->stats_blk_mapping & 0xffffffff);
4908 REG_WR(bp, BNX2_HC_STATISTICS_ADDR_H,
4909 (u64) bp->stats_blk_mapping >> 32);
4910
Jeff Garzik6aa20a22006-09-13 13:24:59 -04004911 REG_WR(bp, BNX2_HC_TX_QUICK_CONS_TRIP,
Michael Chanb6016b72005-05-26 13:03:09 -07004912 (bp->tx_quick_cons_trip_int << 16) | bp->tx_quick_cons_trip);
4913
4914 REG_WR(bp, BNX2_HC_RX_QUICK_CONS_TRIP,
4915 (bp->rx_quick_cons_trip_int << 16) | bp->rx_quick_cons_trip);
4916
4917 REG_WR(bp, BNX2_HC_COMP_PROD_TRIP,
4918 (bp->comp_prod_trip_int << 16) | bp->comp_prod_trip);
4919
4920 REG_WR(bp, BNX2_HC_TX_TICKS, (bp->tx_ticks_int << 16) | bp->tx_ticks);
4921
4922 REG_WR(bp, BNX2_HC_RX_TICKS, (bp->rx_ticks_int << 16) | bp->rx_ticks);
4923
4924 REG_WR(bp, BNX2_HC_COM_TICKS,
4925 (bp->com_ticks_int << 16) | bp->com_ticks);
4926
4927 REG_WR(bp, BNX2_HC_CMD_TICKS,
4928 (bp->cmd_ticks_int << 16) | bp->cmd_ticks);
4929
Michael Chan61d9e3f2009-08-21 16:20:46 +00004930 if (bp->flags & BNX2_FLAG_BROKEN_STATS)
Michael Chan02537b062007-06-04 21:24:07 -07004931 REG_WR(bp, BNX2_HC_STATS_TICKS, 0);
4932 else
Michael Chan7ea69202007-07-16 18:27:10 -07004933 REG_WR(bp, BNX2_HC_STATS_TICKS, bp->stats_ticks);
Michael Chanb6016b72005-05-26 13:03:09 -07004934 REG_WR(bp, BNX2_HC_STAT_COLLECT_TICKS, 0xbb8); /* 3ms */
4935
4936 if (CHIP_ID(bp) == CHIP_ID_5706_A1)
Michael Chan8e6a72c2007-05-03 13:24:48 -07004937 val = BNX2_HC_CONFIG_COLLECT_STATS;
Michael Chanb6016b72005-05-26 13:03:09 -07004938 else {
Michael Chan8e6a72c2007-05-03 13:24:48 -07004939 val = BNX2_HC_CONFIG_RX_TMR_MODE | BNX2_HC_CONFIG_TX_TMR_MODE |
4940 BNX2_HC_CONFIG_COLLECT_STATS;
Michael Chanb6016b72005-05-26 13:03:09 -07004941 }
4942
Michael Chanefde73a2010-02-15 19:42:07 +00004943 if (bp->flags & BNX2_FLAG_USING_MSIX) {
Michael Chanc76c0472007-12-20 20:01:19 -08004944 REG_WR(bp, BNX2_HC_MSIX_BIT_VECTOR,
4945 BNX2_HC_MSIX_BIT_VECTOR_VAL);
4946
Michael Chan5e9ad9e2008-06-19 16:43:17 -07004947 val |= BNX2_HC_CONFIG_SB_ADDR_INC_128B;
4948 }
4949
4950 if (bp->flags & BNX2_FLAG_ONE_SHOT_MSI)
Michael Chancf7474a2009-08-21 16:20:48 +00004951 val |= BNX2_HC_CONFIG_ONE_SHOT | BNX2_HC_CONFIG_USE_INT_PARAM;
Michael Chan5e9ad9e2008-06-19 16:43:17 -07004952
4953 REG_WR(bp, BNX2_HC_CONFIG, val);
4954
4955 for (i = 1; i < bp->irq_nvecs; i++) {
4956 u32 base = ((i - 1) * BNX2_HC_SB_CONFIG_SIZE) +
4957 BNX2_HC_SB_CONFIG_1;
4958
Michael Chan6f743ca2008-01-29 21:34:08 -08004959 REG_WR(bp, base,
Michael Chanc76c0472007-12-20 20:01:19 -08004960 BNX2_HC_SB_CONFIG_1_TX_TMR_MODE |
Michael Chan5e9ad9e2008-06-19 16:43:17 -07004961 BNX2_HC_SB_CONFIG_1_RX_TMR_MODE |
Michael Chanc76c0472007-12-20 20:01:19 -08004962 BNX2_HC_SB_CONFIG_1_ONE_SHOT);
4963
Michael Chan6f743ca2008-01-29 21:34:08 -08004964 REG_WR(bp, base + BNX2_HC_TX_QUICK_CONS_TRIP_OFF,
Michael Chanc76c0472007-12-20 20:01:19 -08004965 (bp->tx_quick_cons_trip_int << 16) |
4966 bp->tx_quick_cons_trip);
4967
Michael Chan6f743ca2008-01-29 21:34:08 -08004968 REG_WR(bp, base + BNX2_HC_TX_TICKS_OFF,
Michael Chanc76c0472007-12-20 20:01:19 -08004969 (bp->tx_ticks_int << 16) | bp->tx_ticks);
4970
Michael Chan5e9ad9e2008-06-19 16:43:17 -07004971 REG_WR(bp, base + BNX2_HC_RX_QUICK_CONS_TRIP_OFF,
4972 (bp->rx_quick_cons_trip_int << 16) |
4973 bp->rx_quick_cons_trip);
4974
4975 REG_WR(bp, base + BNX2_HC_RX_TICKS_OFF,
4976 (bp->rx_ticks_int << 16) | bp->rx_ticks);
Michael Chanc76c0472007-12-20 20:01:19 -08004977 }
4978
Michael Chanb6016b72005-05-26 13:03:09 -07004979 /* Clear internal stats counters. */
4980 REG_WR(bp, BNX2_HC_COMMAND, BNX2_HC_COMMAND_CLR_STAT_NOW);
4981
Michael Chanda3e4fb2007-05-03 13:24:23 -07004982 REG_WR(bp, BNX2_HC_ATTN_BITS_ENABLE, STATUS_ATTN_EVENTS);
Michael Chanb6016b72005-05-26 13:03:09 -07004983
4984 /* Initialize the receive filter. */
4985 bnx2_set_rx_mode(bp->dev);
4986
Michael Chan0aa38df2007-06-04 21:23:06 -07004987 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
4988 val = REG_RD(bp, BNX2_MISC_NEW_CORE_CTL);
4989 val |= BNX2_MISC_NEW_CORE_CTL_DMA_ENABLE;
4990 REG_WR(bp, BNX2_MISC_NEW_CORE_CTL, val);
4991 }
Michael Chanb090ae22006-01-23 16:07:10 -08004992 rc = bnx2_fw_sync(bp, BNX2_DRV_MSG_DATA_WAIT2 | BNX2_DRV_MSG_CODE_RESET,
Michael Chana2f13892008-07-14 22:38:23 -07004993 1, 0);
Michael Chanb6016b72005-05-26 13:03:09 -07004994
Michael Chandf149d72007-07-07 22:51:36 -07004995 REG_WR(bp, BNX2_MISC_ENABLE_SET_BITS, BNX2_MISC_ENABLE_DEFAULT);
Michael Chanb6016b72005-05-26 13:03:09 -07004996 REG_RD(bp, BNX2_MISC_ENABLE_SET_BITS);
4997
4998 udelay(20);
4999
Michael Chanbf5295b2006-03-23 01:11:56 -08005000 bp->hc_cmd = REG_RD(bp, BNX2_HC_COMMAND);
5001
Michael Chanb090ae22006-01-23 16:07:10 -08005002 return rc;
Michael Chanb6016b72005-05-26 13:03:09 -07005003}
5004
Michael Chan59b47d82006-11-19 14:10:45 -08005005static void
Michael Chanc76c0472007-12-20 20:01:19 -08005006bnx2_clear_ring_states(struct bnx2 *bp)
5007{
5008 struct bnx2_napi *bnapi;
Michael Chan35e90102008-06-19 16:37:42 -07005009 struct bnx2_tx_ring_info *txr;
Michael Chanbb4f98a2008-06-19 16:38:19 -07005010 struct bnx2_rx_ring_info *rxr;
Michael Chanc76c0472007-12-20 20:01:19 -08005011 int i;
5012
5013 for (i = 0; i < BNX2_MAX_MSIX_VEC; i++) {
5014 bnapi = &bp->bnx2_napi[i];
Michael Chan35e90102008-06-19 16:37:42 -07005015 txr = &bnapi->tx_ring;
Michael Chanbb4f98a2008-06-19 16:38:19 -07005016 rxr = &bnapi->rx_ring;
Michael Chanc76c0472007-12-20 20:01:19 -08005017
Michael Chan35e90102008-06-19 16:37:42 -07005018 txr->tx_cons = 0;
5019 txr->hw_tx_cons = 0;
Michael Chanbb4f98a2008-06-19 16:38:19 -07005020 rxr->rx_prod_bseq = 0;
5021 rxr->rx_prod = 0;
5022 rxr->rx_cons = 0;
5023 rxr->rx_pg_prod = 0;
5024 rxr->rx_pg_cons = 0;
Michael Chanc76c0472007-12-20 20:01:19 -08005025 }
5026}
5027
5028static void
Michael Chan35e90102008-06-19 16:37:42 -07005029bnx2_init_tx_context(struct bnx2 *bp, u32 cid, struct bnx2_tx_ring_info *txr)
Michael Chan59b47d82006-11-19 14:10:45 -08005030{
5031 u32 val, offset0, offset1, offset2, offset3;
Michael Chan62a83132008-01-29 21:35:40 -08005032 u32 cid_addr = GET_CID_ADDR(cid);
Michael Chan59b47d82006-11-19 14:10:45 -08005033
5034 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
5035 offset0 = BNX2_L2CTX_TYPE_XI;
5036 offset1 = BNX2_L2CTX_CMD_TYPE_XI;
5037 offset2 = BNX2_L2CTX_TBDR_BHADDR_HI_XI;
5038 offset3 = BNX2_L2CTX_TBDR_BHADDR_LO_XI;
5039 } else {
5040 offset0 = BNX2_L2CTX_TYPE;
5041 offset1 = BNX2_L2CTX_CMD_TYPE;
5042 offset2 = BNX2_L2CTX_TBDR_BHADDR_HI;
5043 offset3 = BNX2_L2CTX_TBDR_BHADDR_LO;
5044 }
5045 val = BNX2_L2CTX_TYPE_TYPE_L2 | BNX2_L2CTX_TYPE_SIZE_L2;
Michael Chan62a83132008-01-29 21:35:40 -08005046 bnx2_ctx_wr(bp, cid_addr, offset0, val);
Michael Chan59b47d82006-11-19 14:10:45 -08005047
5048 val = BNX2_L2CTX_CMD_TYPE_TYPE_L2 | (8 << 16);
Michael Chan62a83132008-01-29 21:35:40 -08005049 bnx2_ctx_wr(bp, cid_addr, offset1, val);
Michael Chan59b47d82006-11-19 14:10:45 -08005050
Michael Chan35e90102008-06-19 16:37:42 -07005051 val = (u64) txr->tx_desc_mapping >> 32;
Michael Chan62a83132008-01-29 21:35:40 -08005052 bnx2_ctx_wr(bp, cid_addr, offset2, val);
Michael Chan59b47d82006-11-19 14:10:45 -08005053
Michael Chan35e90102008-06-19 16:37:42 -07005054 val = (u64) txr->tx_desc_mapping & 0xffffffff;
Michael Chan62a83132008-01-29 21:35:40 -08005055 bnx2_ctx_wr(bp, cid_addr, offset3, val);
Michael Chan59b47d82006-11-19 14:10:45 -08005056}
Michael Chanb6016b72005-05-26 13:03:09 -07005057
5058static void
Michael Chan35e90102008-06-19 16:37:42 -07005059bnx2_init_tx_ring(struct bnx2 *bp, int ring_num)
Michael Chanb6016b72005-05-26 13:03:09 -07005060{
5061 struct tx_bd *txbd;
Michael Chanc76c0472007-12-20 20:01:19 -08005062 u32 cid = TX_CID;
5063 struct bnx2_napi *bnapi;
Michael Chan35e90102008-06-19 16:37:42 -07005064 struct bnx2_tx_ring_info *txr;
Michael Chanc76c0472007-12-20 20:01:19 -08005065
Michael Chan35e90102008-06-19 16:37:42 -07005066 bnapi = &bp->bnx2_napi[ring_num];
5067 txr = &bnapi->tx_ring;
5068
5069 if (ring_num == 0)
5070 cid = TX_CID;
5071 else
5072 cid = TX_TSS_CID + ring_num - 1;
Michael Chanb6016b72005-05-26 13:03:09 -07005073
Michael Chan2f8af122006-08-15 01:39:10 -07005074 bp->tx_wake_thresh = bp->tx_ring_size / 2;
5075
Michael Chan35e90102008-06-19 16:37:42 -07005076 txbd = &txr->tx_desc_ring[MAX_TX_DESC_CNT];
Jeff Garzik6aa20a22006-09-13 13:24:59 -04005077
Michael Chan35e90102008-06-19 16:37:42 -07005078 txbd->tx_bd_haddr_hi = (u64) txr->tx_desc_mapping >> 32;
5079 txbd->tx_bd_haddr_lo = (u64) txr->tx_desc_mapping & 0xffffffff;
Michael Chanb6016b72005-05-26 13:03:09 -07005080
Michael Chan35e90102008-06-19 16:37:42 -07005081 txr->tx_prod = 0;
5082 txr->tx_prod_bseq = 0;
Jeff Garzik6aa20a22006-09-13 13:24:59 -04005083
Michael Chan35e90102008-06-19 16:37:42 -07005084 txr->tx_bidx_addr = MB_GET_CID_ADDR(cid) + BNX2_L2CTX_TX_HOST_BIDX;
5085 txr->tx_bseq_addr = MB_GET_CID_ADDR(cid) + BNX2_L2CTX_TX_HOST_BSEQ;
Michael Chanb6016b72005-05-26 13:03:09 -07005086
Michael Chan35e90102008-06-19 16:37:42 -07005087 bnx2_init_tx_context(bp, cid, txr);
Michael Chanb6016b72005-05-26 13:03:09 -07005088}
5089
5090static void
Michael Chan5d5d0012007-12-12 11:17:43 -08005091bnx2_init_rxbd_rings(struct rx_bd *rx_ring[], dma_addr_t dma[], u32 buf_size,
5092 int num_rings)
Michael Chanb6016b72005-05-26 13:03:09 -07005093{
Michael Chanb6016b72005-05-26 13:03:09 -07005094 int i;
Michael Chan5d5d0012007-12-12 11:17:43 -08005095 struct rx_bd *rxbd;
Michael Chanb6016b72005-05-26 13:03:09 -07005096
Michael Chan5d5d0012007-12-12 11:17:43 -08005097 for (i = 0; i < num_rings; i++) {
Michael Chan13daffa2006-03-20 17:49:20 -08005098 int j;
Michael Chanb6016b72005-05-26 13:03:09 -07005099
Michael Chan5d5d0012007-12-12 11:17:43 -08005100 rxbd = &rx_ring[i][0];
Michael Chan13daffa2006-03-20 17:49:20 -08005101 for (j = 0; j < MAX_RX_DESC_CNT; j++, rxbd++) {
Michael Chan5d5d0012007-12-12 11:17:43 -08005102 rxbd->rx_bd_len = buf_size;
Michael Chan13daffa2006-03-20 17:49:20 -08005103 rxbd->rx_bd_flags = RX_BD_FLAGS_START | RX_BD_FLAGS_END;
5104 }
Michael Chan5d5d0012007-12-12 11:17:43 -08005105 if (i == (num_rings - 1))
Michael Chan13daffa2006-03-20 17:49:20 -08005106 j = 0;
5107 else
5108 j = i + 1;
Michael Chan5d5d0012007-12-12 11:17:43 -08005109 rxbd->rx_bd_haddr_hi = (u64) dma[j] >> 32;
5110 rxbd->rx_bd_haddr_lo = (u64) dma[j] & 0xffffffff;
Michael Chan13daffa2006-03-20 17:49:20 -08005111 }
Michael Chan5d5d0012007-12-12 11:17:43 -08005112}
5113
5114static void
Michael Chanbb4f98a2008-06-19 16:38:19 -07005115bnx2_init_rx_ring(struct bnx2 *bp, int ring_num)
Michael Chan5d5d0012007-12-12 11:17:43 -08005116{
5117 int i;
5118 u16 prod, ring_prod;
Michael Chanbb4f98a2008-06-19 16:38:19 -07005119 u32 cid, rx_cid_addr, val;
5120 struct bnx2_napi *bnapi = &bp->bnx2_napi[ring_num];
5121 struct bnx2_rx_ring_info *rxr = &bnapi->rx_ring;
Michael Chan5d5d0012007-12-12 11:17:43 -08005122
Michael Chanbb4f98a2008-06-19 16:38:19 -07005123 if (ring_num == 0)
5124 cid = RX_CID;
5125 else
5126 cid = RX_RSS_CID + ring_num - 1;
5127
5128 rx_cid_addr = GET_CID_ADDR(cid);
5129
5130 bnx2_init_rxbd_rings(rxr->rx_desc_ring, rxr->rx_desc_mapping,
Michael Chan5d5d0012007-12-12 11:17:43 -08005131 bp->rx_buf_use_size, bp->rx_max_ring);
5132
Michael Chanbb4f98a2008-06-19 16:38:19 -07005133 bnx2_init_rx_context(bp, cid);
Michael Chan83e3fc82008-01-29 21:37:17 -08005134
5135 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
5136 val = REG_RD(bp, BNX2_MQ_MAP_L2_5);
5137 REG_WR(bp, BNX2_MQ_MAP_L2_5, val | BNX2_MQ_MAP_L2_5_ARM);
5138 }
5139
Michael Chan62a83132008-01-29 21:35:40 -08005140 bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_PG_BUF_SIZE, 0);
Michael Chan47bf4242007-12-12 11:19:12 -08005141 if (bp->rx_pg_ring_size) {
Michael Chanbb4f98a2008-06-19 16:38:19 -07005142 bnx2_init_rxbd_rings(rxr->rx_pg_desc_ring,
5143 rxr->rx_pg_desc_mapping,
Michael Chan47bf4242007-12-12 11:19:12 -08005144 PAGE_SIZE, bp->rx_max_pg_ring);
5145 val = (bp->rx_buf_use_size << 16) | PAGE_SIZE;
Michael Chan62a83132008-01-29 21:35:40 -08005146 bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_PG_BUF_SIZE, val);
5147 bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_RBDC_KEY,
Michael Chan5e9ad9e2008-06-19 16:43:17 -07005148 BNX2_L2CTX_RBDC_JUMBO_KEY - ring_num);
Michael Chan47bf4242007-12-12 11:19:12 -08005149
Michael Chanbb4f98a2008-06-19 16:38:19 -07005150 val = (u64) rxr->rx_pg_desc_mapping[0] >> 32;
Michael Chan62a83132008-01-29 21:35:40 -08005151 bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_NX_PG_BDHADDR_HI, val);
Michael Chan47bf4242007-12-12 11:19:12 -08005152
Michael Chanbb4f98a2008-06-19 16:38:19 -07005153 val = (u64) rxr->rx_pg_desc_mapping[0] & 0xffffffff;
Michael Chan62a83132008-01-29 21:35:40 -08005154 bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_NX_PG_BDHADDR_LO, val);
Michael Chan47bf4242007-12-12 11:19:12 -08005155
5156 if (CHIP_NUM(bp) == CHIP_NUM_5709)
5157 REG_WR(bp, BNX2_MQ_MAP_L2_3, BNX2_MQ_MAP_L2_3_DEFAULT);
5158 }
Michael Chanb6016b72005-05-26 13:03:09 -07005159
Michael Chanbb4f98a2008-06-19 16:38:19 -07005160 val = (u64) rxr->rx_desc_mapping[0] >> 32;
Michael Chan62a83132008-01-29 21:35:40 -08005161 bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_NX_BDHADDR_HI, val);
Michael Chanb6016b72005-05-26 13:03:09 -07005162
Michael Chanbb4f98a2008-06-19 16:38:19 -07005163 val = (u64) rxr->rx_desc_mapping[0] & 0xffffffff;
Michael Chan62a83132008-01-29 21:35:40 -08005164 bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_NX_BDHADDR_LO, val);
Michael Chanb6016b72005-05-26 13:03:09 -07005165
Michael Chanbb4f98a2008-06-19 16:38:19 -07005166 ring_prod = prod = rxr->rx_pg_prod;
Michael Chan47bf4242007-12-12 11:19:12 -08005167 for (i = 0; i < bp->rx_pg_ring_size; i++) {
Michael Chanb929e532009-12-03 09:46:33 +00005168 if (bnx2_alloc_rx_page(bp, rxr, ring_prod) < 0) {
5169 printk(KERN_WARNING PFX "%s: init'ed rx page ring %d "
5170 "with %d/%d pages only\n",
5171 bp->dev->name, ring_num, i, bp->rx_pg_ring_size);
Michael Chan47bf4242007-12-12 11:19:12 -08005172 break;
Michael Chanb929e532009-12-03 09:46:33 +00005173 }
Michael Chan47bf4242007-12-12 11:19:12 -08005174 prod = NEXT_RX_BD(prod);
5175 ring_prod = RX_PG_RING_IDX(prod);
5176 }
Michael Chanbb4f98a2008-06-19 16:38:19 -07005177 rxr->rx_pg_prod = prod;
Michael Chan47bf4242007-12-12 11:19:12 -08005178
Michael Chanbb4f98a2008-06-19 16:38:19 -07005179 ring_prod = prod = rxr->rx_prod;
Michael Chan236b6392006-03-20 17:49:02 -08005180 for (i = 0; i < bp->rx_ring_size; i++) {
Michael Chanb929e532009-12-03 09:46:33 +00005181 if (bnx2_alloc_rx_skb(bp, rxr, ring_prod) < 0) {
5182 printk(KERN_WARNING PFX "%s: init'ed rx ring %d with "
5183 "%d/%d skbs only\n",
5184 bp->dev->name, ring_num, i, bp->rx_ring_size);
Michael Chanb6016b72005-05-26 13:03:09 -07005185 break;
Michael Chanb929e532009-12-03 09:46:33 +00005186 }
Michael Chanb6016b72005-05-26 13:03:09 -07005187 prod = NEXT_RX_BD(prod);
5188 ring_prod = RX_RING_IDX(prod);
5189 }
Michael Chanbb4f98a2008-06-19 16:38:19 -07005190 rxr->rx_prod = prod;
Michael Chanb6016b72005-05-26 13:03:09 -07005191
Michael Chanbb4f98a2008-06-19 16:38:19 -07005192 rxr->rx_bidx_addr = MB_GET_CID_ADDR(cid) + BNX2_L2CTX_HOST_BDIDX;
5193 rxr->rx_bseq_addr = MB_GET_CID_ADDR(cid) + BNX2_L2CTX_HOST_BSEQ;
5194 rxr->rx_pg_bidx_addr = MB_GET_CID_ADDR(cid) + BNX2_L2CTX_HOST_PG_BDIDX;
Michael Chanb6016b72005-05-26 13:03:09 -07005195
Michael Chanbb4f98a2008-06-19 16:38:19 -07005196 REG_WR16(bp, rxr->rx_pg_bidx_addr, rxr->rx_pg_prod);
5197 REG_WR16(bp, rxr->rx_bidx_addr, prod);
5198
5199 REG_WR(bp, rxr->rx_bseq_addr, rxr->rx_prod_bseq);
Michael Chanb6016b72005-05-26 13:03:09 -07005200}
5201
Michael Chan35e90102008-06-19 16:37:42 -07005202static void
5203bnx2_init_all_rings(struct bnx2 *bp)
5204{
5205 int i;
Michael Chan5e9ad9e2008-06-19 16:43:17 -07005206 u32 val;
Michael Chan35e90102008-06-19 16:37:42 -07005207
5208 bnx2_clear_ring_states(bp);
5209
5210 REG_WR(bp, BNX2_TSCH_TSS_CFG, 0);
5211 for (i = 0; i < bp->num_tx_rings; i++)
5212 bnx2_init_tx_ring(bp, i);
5213
5214 if (bp->num_tx_rings > 1)
5215 REG_WR(bp, BNX2_TSCH_TSS_CFG, ((bp->num_tx_rings - 1) << 24) |
5216 (TX_TSS_CID << 7));
5217
Michael Chan5e9ad9e2008-06-19 16:43:17 -07005218 REG_WR(bp, BNX2_RLUP_RSS_CONFIG, 0);
5219 bnx2_reg_wr_ind(bp, BNX2_RXP_SCRATCH_RSS_TBL_SZ, 0);
5220
Michael Chanbb4f98a2008-06-19 16:38:19 -07005221 for (i = 0; i < bp->num_rx_rings; i++)
5222 bnx2_init_rx_ring(bp, i);
Michael Chan5e9ad9e2008-06-19 16:43:17 -07005223
5224 if (bp->num_rx_rings > 1) {
5225 u32 tbl_32;
5226 u8 *tbl = (u8 *) &tbl_32;
5227
5228 bnx2_reg_wr_ind(bp, BNX2_RXP_SCRATCH_RSS_TBL_SZ,
5229 BNX2_RXP_SCRATCH_RSS_TBL_MAX_ENTRIES);
5230
5231 for (i = 0; i < BNX2_RXP_SCRATCH_RSS_TBL_MAX_ENTRIES; i++) {
5232 tbl[i % 4] = i % (bp->num_rx_rings - 1);
5233 if ((i % 4) == 3)
5234 bnx2_reg_wr_ind(bp,
5235 BNX2_RXP_SCRATCH_RSS_TBL + i,
5236 cpu_to_be32(tbl_32));
5237 }
5238
5239 val = BNX2_RLUP_RSS_CONFIG_IPV4_RSS_TYPE_ALL_XI |
5240 BNX2_RLUP_RSS_CONFIG_IPV6_RSS_TYPE_ALL_XI;
5241
5242 REG_WR(bp, BNX2_RLUP_RSS_CONFIG, val);
5243
5244 }
Michael Chan35e90102008-06-19 16:37:42 -07005245}
5246
Michael Chan5d5d0012007-12-12 11:17:43 -08005247static u32 bnx2_find_max_ring(u32 ring_size, u32 max_size)
Michael Chan13daffa2006-03-20 17:49:20 -08005248{
Michael Chan5d5d0012007-12-12 11:17:43 -08005249 u32 max, num_rings = 1;
Michael Chan13daffa2006-03-20 17:49:20 -08005250
Michael Chan5d5d0012007-12-12 11:17:43 -08005251 while (ring_size > MAX_RX_DESC_CNT) {
5252 ring_size -= MAX_RX_DESC_CNT;
Michael Chan13daffa2006-03-20 17:49:20 -08005253 num_rings++;
5254 }
5255 /* round to next power of 2 */
Michael Chan5d5d0012007-12-12 11:17:43 -08005256 max = max_size;
Michael Chan13daffa2006-03-20 17:49:20 -08005257 while ((max & num_rings) == 0)
5258 max >>= 1;
5259
5260 if (num_rings != max)
5261 max <<= 1;
5262
Michael Chan5d5d0012007-12-12 11:17:43 -08005263 return max;
5264}
5265
5266static void
5267bnx2_set_rx_ring_size(struct bnx2 *bp, u32 size)
5268{
Michael Chan84eaa182007-12-12 11:19:57 -08005269 u32 rx_size, rx_space, jumbo_size;
Michael Chan5d5d0012007-12-12 11:17:43 -08005270
5271 /* 8 for CRC and VLAN */
Benjamin Lid89cb6a2008-05-16 22:18:57 -07005272 rx_size = bp->dev->mtu + ETH_HLEN + BNX2_RX_OFFSET + 8;
Michael Chan5d5d0012007-12-12 11:17:43 -08005273
Michael Chan84eaa182007-12-12 11:19:57 -08005274 rx_space = SKB_DATA_ALIGN(rx_size + BNX2_RX_ALIGN) + NET_SKB_PAD +
5275 sizeof(struct skb_shared_info);
5276
Benjamin Li601d3d12008-05-16 22:19:35 -07005277 bp->rx_copy_thresh = BNX2_RX_COPY_THRESH;
Michael Chan47bf4242007-12-12 11:19:12 -08005278 bp->rx_pg_ring_size = 0;
5279 bp->rx_max_pg_ring = 0;
5280 bp->rx_max_pg_ring_idx = 0;
David S. Millerf86e82f2008-01-21 17:15:40 -08005281 if ((rx_space > PAGE_SIZE) && !(bp->flags & BNX2_FLAG_JUMBO_BROKEN)) {
Michael Chan84eaa182007-12-12 11:19:57 -08005282 int pages = PAGE_ALIGN(bp->dev->mtu - 40) >> PAGE_SHIFT;
5283
5284 jumbo_size = size * pages;
5285 if (jumbo_size > MAX_TOTAL_RX_PG_DESC_CNT)
5286 jumbo_size = MAX_TOTAL_RX_PG_DESC_CNT;
5287
5288 bp->rx_pg_ring_size = jumbo_size;
5289 bp->rx_max_pg_ring = bnx2_find_max_ring(jumbo_size,
5290 MAX_RX_PG_RINGS);
5291 bp->rx_max_pg_ring_idx = (bp->rx_max_pg_ring * RX_DESC_CNT) - 1;
Benjamin Li601d3d12008-05-16 22:19:35 -07005292 rx_size = BNX2_RX_COPY_THRESH + BNX2_RX_OFFSET;
Michael Chan84eaa182007-12-12 11:19:57 -08005293 bp->rx_copy_thresh = 0;
5294 }
Michael Chan5d5d0012007-12-12 11:17:43 -08005295
5296 bp->rx_buf_use_size = rx_size;
5297 /* hw alignment */
5298 bp->rx_buf_size = bp->rx_buf_use_size + BNX2_RX_ALIGN;
Benjamin Lid89cb6a2008-05-16 22:18:57 -07005299 bp->rx_jumbo_thresh = rx_size - BNX2_RX_OFFSET;
Michael Chan5d5d0012007-12-12 11:17:43 -08005300 bp->rx_ring_size = size;
5301 bp->rx_max_ring = bnx2_find_max_ring(size, MAX_RX_RINGS);
Michael Chan13daffa2006-03-20 17:49:20 -08005302 bp->rx_max_ring_idx = (bp->rx_max_ring * RX_DESC_CNT) - 1;
5303}
5304
5305static void
Michael Chanb6016b72005-05-26 13:03:09 -07005306bnx2_free_tx_skbs(struct bnx2 *bp)
5307{
5308 int i;
5309
Michael Chan35e90102008-06-19 16:37:42 -07005310 for (i = 0; i < bp->num_tx_rings; i++) {
5311 struct bnx2_napi *bnapi = &bp->bnx2_napi[i];
5312 struct bnx2_tx_ring_info *txr = &bnapi->tx_ring;
5313 int j;
Michael Chanb6016b72005-05-26 13:03:09 -07005314
Michael Chan35e90102008-06-19 16:37:42 -07005315 if (txr->tx_buf_ring == NULL)
Michael Chanb6016b72005-05-26 13:03:09 -07005316 continue;
Michael Chanb6016b72005-05-26 13:03:09 -07005317
Michael Chan35e90102008-06-19 16:37:42 -07005318 for (j = 0; j < TX_DESC_CNT; ) {
Benjamin Li3d16af82008-10-09 12:26:41 -07005319 struct sw_tx_bd *tx_buf = &txr->tx_buf_ring[j];
Michael Chan35e90102008-06-19 16:37:42 -07005320 struct sk_buff *skb = tx_buf->skb;
Alexander Duycke95524a2009-12-02 16:47:57 +00005321 int k, last;
Michael Chan35e90102008-06-19 16:37:42 -07005322
5323 if (skb == NULL) {
5324 j++;
5325 continue;
5326 }
5327
Alexander Duycke95524a2009-12-02 16:47:57 +00005328 pci_unmap_single(bp->pdev,
5329 pci_unmap_addr(tx_buf, mapping),
5330 skb_headlen(skb),
5331 PCI_DMA_TODEVICE);
Michael Chanb6016b72005-05-26 13:03:09 -07005332
Michael Chan35e90102008-06-19 16:37:42 -07005333 tx_buf->skb = NULL;
Michael Chanb6016b72005-05-26 13:03:09 -07005334
Alexander Duycke95524a2009-12-02 16:47:57 +00005335 last = tx_buf->nr_frags;
5336 j++;
5337 for (k = 0; k < last; k++, j++) {
5338 tx_buf = &txr->tx_buf_ring[TX_RING_IDX(j)];
5339 pci_unmap_page(bp->pdev,
5340 pci_unmap_addr(tx_buf, mapping),
5341 skb_shinfo(skb)->frags[k].size,
5342 PCI_DMA_TODEVICE);
5343 }
Michael Chan35e90102008-06-19 16:37:42 -07005344 dev_kfree_skb(skb);
Michael Chanb6016b72005-05-26 13:03:09 -07005345 }
Michael Chanb6016b72005-05-26 13:03:09 -07005346 }
Michael Chanb6016b72005-05-26 13:03:09 -07005347}
5348
5349static void
5350bnx2_free_rx_skbs(struct bnx2 *bp)
5351{
5352 int i;
5353
Michael Chanbb4f98a2008-06-19 16:38:19 -07005354 for (i = 0; i < bp->num_rx_rings; i++) {
5355 struct bnx2_napi *bnapi = &bp->bnx2_napi[i];
5356 struct bnx2_rx_ring_info *rxr = &bnapi->rx_ring;
5357 int j;
Michael Chanb6016b72005-05-26 13:03:09 -07005358
Michael Chanbb4f98a2008-06-19 16:38:19 -07005359 if (rxr->rx_buf_ring == NULL)
5360 return;
Michael Chanb6016b72005-05-26 13:03:09 -07005361
Michael Chanbb4f98a2008-06-19 16:38:19 -07005362 for (j = 0; j < bp->rx_max_ring_idx; j++) {
5363 struct sw_bd *rx_buf = &rxr->rx_buf_ring[j];
5364 struct sk_buff *skb = rx_buf->skb;
Michael Chanb6016b72005-05-26 13:03:09 -07005365
Michael Chanbb4f98a2008-06-19 16:38:19 -07005366 if (skb == NULL)
5367 continue;
Michael Chanb6016b72005-05-26 13:03:09 -07005368
Michael Chanbb4f98a2008-06-19 16:38:19 -07005369 pci_unmap_single(bp->pdev,
5370 pci_unmap_addr(rx_buf, mapping),
5371 bp->rx_buf_use_size,
5372 PCI_DMA_FROMDEVICE);
Michael Chanb6016b72005-05-26 13:03:09 -07005373
Michael Chanbb4f98a2008-06-19 16:38:19 -07005374 rx_buf->skb = NULL;
5375
5376 dev_kfree_skb(skb);
5377 }
5378 for (j = 0; j < bp->rx_max_pg_ring_idx; j++)
5379 bnx2_free_rx_page(bp, rxr, j);
Michael Chanb6016b72005-05-26 13:03:09 -07005380 }
5381}
5382
5383static void
5384bnx2_free_skbs(struct bnx2 *bp)
5385{
5386 bnx2_free_tx_skbs(bp);
5387 bnx2_free_rx_skbs(bp);
5388}
5389
5390static int
5391bnx2_reset_nic(struct bnx2 *bp, u32 reset_code)
5392{
5393 int rc;
5394
5395 rc = bnx2_reset_chip(bp, reset_code);
5396 bnx2_free_skbs(bp);
5397 if (rc)
5398 return rc;
5399
Michael Chanfba9fe92006-06-12 22:21:25 -07005400 if ((rc = bnx2_init_chip(bp)) != 0)
5401 return rc;
5402
Michael Chan35e90102008-06-19 16:37:42 -07005403 bnx2_init_all_rings(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07005404 return 0;
5405}
5406
5407static int
Michael Chan9a120bc2008-05-16 22:17:45 -07005408bnx2_init_nic(struct bnx2 *bp, int reset_phy)
Michael Chanb6016b72005-05-26 13:03:09 -07005409{
5410 int rc;
5411
5412 if ((rc = bnx2_reset_nic(bp, BNX2_DRV_MSG_CODE_RESET)) != 0)
5413 return rc;
5414
Michael Chan80be4432006-11-19 14:07:28 -08005415 spin_lock_bh(&bp->phy_lock);
Michael Chan9a120bc2008-05-16 22:17:45 -07005416 bnx2_init_phy(bp, reset_phy);
Michael Chanb6016b72005-05-26 13:03:09 -07005417 bnx2_set_link(bp);
Michael Chan543a8272008-05-02 16:56:44 -07005418 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
5419 bnx2_remote_phy_event(bp);
Michael Chan0d8a6572007-07-07 22:49:43 -07005420 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07005421 return 0;
5422}
5423
5424static int
Michael Chan74bf4ba2008-10-09 12:21:08 -07005425bnx2_shutdown_chip(struct bnx2 *bp)
5426{
5427 u32 reset_code;
5428
5429 if (bp->flags & BNX2_FLAG_NO_WOL)
5430 reset_code = BNX2_DRV_MSG_CODE_UNLOAD_LNK_DN;
5431 else if (bp->wol)
5432 reset_code = BNX2_DRV_MSG_CODE_SUSPEND_WOL;
5433 else
5434 reset_code = BNX2_DRV_MSG_CODE_SUSPEND_NO_WOL;
5435
5436 return bnx2_reset_chip(bp, reset_code);
5437}
5438
5439static int
Michael Chanb6016b72005-05-26 13:03:09 -07005440bnx2_test_registers(struct bnx2 *bp)
5441{
5442 int ret;
Michael Chan5bae30c2007-05-03 13:18:46 -07005443 int i, is_5709;
Arjan van de Venf71e1302006-03-03 21:33:57 -05005444 static const struct {
Michael Chanb6016b72005-05-26 13:03:09 -07005445 u16 offset;
5446 u16 flags;
Michael Chan5bae30c2007-05-03 13:18:46 -07005447#define BNX2_FL_NOT_5709 1
Michael Chanb6016b72005-05-26 13:03:09 -07005448 u32 rw_mask;
5449 u32 ro_mask;
5450 } reg_tbl[] = {
5451 { 0x006c, 0, 0x00000000, 0x0000003f },
5452 { 0x0090, 0, 0xffffffff, 0x00000000 },
5453 { 0x0094, 0, 0x00000000, 0x00000000 },
5454
Michael Chan5bae30c2007-05-03 13:18:46 -07005455 { 0x0404, BNX2_FL_NOT_5709, 0x00003f00, 0x00000000 },
5456 { 0x0418, BNX2_FL_NOT_5709, 0x00000000, 0xffffffff },
5457 { 0x041c, BNX2_FL_NOT_5709, 0x00000000, 0xffffffff },
5458 { 0x0420, BNX2_FL_NOT_5709, 0x00000000, 0x80ffffff },
5459 { 0x0424, BNX2_FL_NOT_5709, 0x00000000, 0x00000000 },
5460 { 0x0428, BNX2_FL_NOT_5709, 0x00000000, 0x00000001 },
5461 { 0x0450, BNX2_FL_NOT_5709, 0x00000000, 0x0000ffff },
5462 { 0x0454, BNX2_FL_NOT_5709, 0x00000000, 0xffffffff },
5463 { 0x0458, BNX2_FL_NOT_5709, 0x00000000, 0xffffffff },
Michael Chanb6016b72005-05-26 13:03:09 -07005464
Michael Chan5bae30c2007-05-03 13:18:46 -07005465 { 0x0808, BNX2_FL_NOT_5709, 0x00000000, 0xffffffff },
5466 { 0x0854, BNX2_FL_NOT_5709, 0x00000000, 0xffffffff },
5467 { 0x0868, BNX2_FL_NOT_5709, 0x00000000, 0x77777777 },
5468 { 0x086c, BNX2_FL_NOT_5709, 0x00000000, 0x77777777 },
5469 { 0x0870, BNX2_FL_NOT_5709, 0x00000000, 0x77777777 },
5470 { 0x0874, BNX2_FL_NOT_5709, 0x00000000, 0x77777777 },
Michael Chanb6016b72005-05-26 13:03:09 -07005471
Michael Chan5bae30c2007-05-03 13:18:46 -07005472 { 0x0c00, BNX2_FL_NOT_5709, 0x00000000, 0x00000001 },
5473 { 0x0c04, BNX2_FL_NOT_5709, 0x00000000, 0x03ff0001 },
5474 { 0x0c08, BNX2_FL_NOT_5709, 0x0f0ff073, 0x00000000 },
Michael Chanb6016b72005-05-26 13:03:09 -07005475
5476 { 0x1000, 0, 0x00000000, 0x00000001 },
Michael Chan15b169c2008-05-02 16:57:08 -07005477 { 0x1004, BNX2_FL_NOT_5709, 0x00000000, 0x000f0001 },
Michael Chanb6016b72005-05-26 13:03:09 -07005478
5479 { 0x1408, 0, 0x01c00800, 0x00000000 },
5480 { 0x149c, 0, 0x8000ffff, 0x00000000 },
5481 { 0x14a8, 0, 0x00000000, 0x000001ff },
Michael Chan5b0c76a2005-11-04 08:45:49 -08005482 { 0x14ac, 0, 0x0fffffff, 0x10000000 },
Michael Chanb6016b72005-05-26 13:03:09 -07005483 { 0x14b0, 0, 0x00000002, 0x00000001 },
5484 { 0x14b8, 0, 0x00000000, 0x00000000 },
5485 { 0x14c0, 0, 0x00000000, 0x00000009 },
5486 { 0x14c4, 0, 0x00003fff, 0x00000000 },
5487 { 0x14cc, 0, 0x00000000, 0x00000001 },
5488 { 0x14d0, 0, 0xffffffff, 0x00000000 },
Michael Chanb6016b72005-05-26 13:03:09 -07005489
5490 { 0x1800, 0, 0x00000000, 0x00000001 },
5491 { 0x1804, 0, 0x00000000, 0x00000003 },
Michael Chanb6016b72005-05-26 13:03:09 -07005492
5493 { 0x2800, 0, 0x00000000, 0x00000001 },
5494 { 0x2804, 0, 0x00000000, 0x00003f01 },
5495 { 0x2808, 0, 0x0f3f3f03, 0x00000000 },
5496 { 0x2810, 0, 0xffff0000, 0x00000000 },
5497 { 0x2814, 0, 0xffff0000, 0x00000000 },
5498 { 0x2818, 0, 0xffff0000, 0x00000000 },
5499 { 0x281c, 0, 0xffff0000, 0x00000000 },
5500 { 0x2834, 0, 0xffffffff, 0x00000000 },
5501 { 0x2840, 0, 0x00000000, 0xffffffff },
5502 { 0x2844, 0, 0x00000000, 0xffffffff },
5503 { 0x2848, 0, 0xffffffff, 0x00000000 },
5504 { 0x284c, 0, 0xf800f800, 0x07ff07ff },
5505
5506 { 0x2c00, 0, 0x00000000, 0x00000011 },
5507 { 0x2c04, 0, 0x00000000, 0x00030007 },
5508
Michael Chanb6016b72005-05-26 13:03:09 -07005509 { 0x3c00, 0, 0x00000000, 0x00000001 },
5510 { 0x3c04, 0, 0x00000000, 0x00070000 },
5511 { 0x3c08, 0, 0x00007f71, 0x07f00000 },
5512 { 0x3c0c, 0, 0x1f3ffffc, 0x00000000 },
5513 { 0x3c10, 0, 0xffffffff, 0x00000000 },
5514 { 0x3c14, 0, 0x00000000, 0xffffffff },
5515 { 0x3c18, 0, 0x00000000, 0xffffffff },
5516 { 0x3c1c, 0, 0xfffff000, 0x00000000 },
5517 { 0x3c20, 0, 0xffffff00, 0x00000000 },
Michael Chanb6016b72005-05-26 13:03:09 -07005518
5519 { 0x5004, 0, 0x00000000, 0x0000007f },
5520 { 0x5008, 0, 0x0f0007ff, 0x00000000 },
Michael Chanb6016b72005-05-26 13:03:09 -07005521
Michael Chanb6016b72005-05-26 13:03:09 -07005522 { 0x5c00, 0, 0x00000000, 0x00000001 },
5523 { 0x5c04, 0, 0x00000000, 0x0003000f },
5524 { 0x5c08, 0, 0x00000003, 0x00000000 },
5525 { 0x5c0c, 0, 0x0000fff8, 0x00000000 },
5526 { 0x5c10, 0, 0x00000000, 0xffffffff },
5527 { 0x5c80, 0, 0x00000000, 0x0f7113f1 },
5528 { 0x5c84, 0, 0x00000000, 0x0000f333 },
5529 { 0x5c88, 0, 0x00000000, 0x00077373 },
5530 { 0x5c8c, 0, 0x00000000, 0x0007f737 },
5531
5532 { 0x6808, 0, 0x0000ff7f, 0x00000000 },
5533 { 0x680c, 0, 0xffffffff, 0x00000000 },
5534 { 0x6810, 0, 0xffffffff, 0x00000000 },
5535 { 0x6814, 0, 0xffffffff, 0x00000000 },
5536 { 0x6818, 0, 0xffffffff, 0x00000000 },
5537 { 0x681c, 0, 0xffffffff, 0x00000000 },
5538 { 0x6820, 0, 0x00ff00ff, 0x00000000 },
5539 { 0x6824, 0, 0x00ff00ff, 0x00000000 },
5540 { 0x6828, 0, 0x00ff00ff, 0x00000000 },
5541 { 0x682c, 0, 0x03ff03ff, 0x00000000 },
5542 { 0x6830, 0, 0x03ff03ff, 0x00000000 },
5543 { 0x6834, 0, 0x03ff03ff, 0x00000000 },
5544 { 0x6838, 0, 0x03ff03ff, 0x00000000 },
5545 { 0x683c, 0, 0x0000ffff, 0x00000000 },
5546 { 0x6840, 0, 0x00000ff0, 0x00000000 },
5547 { 0x6844, 0, 0x00ffff00, 0x00000000 },
5548 { 0x684c, 0, 0xffffffff, 0x00000000 },
5549 { 0x6850, 0, 0x7f7f7f7f, 0x00000000 },
5550 { 0x6854, 0, 0x7f7f7f7f, 0x00000000 },
5551 { 0x6858, 0, 0x7f7f7f7f, 0x00000000 },
5552 { 0x685c, 0, 0x7f7f7f7f, 0x00000000 },
5553 { 0x6908, 0, 0x00000000, 0x0001ff0f },
5554 { 0x690c, 0, 0x00000000, 0x0ffe00f0 },
5555
5556 { 0xffff, 0, 0x00000000, 0x00000000 },
5557 };
5558
5559 ret = 0;
Michael Chan5bae30c2007-05-03 13:18:46 -07005560 is_5709 = 0;
5561 if (CHIP_NUM(bp) == CHIP_NUM_5709)
5562 is_5709 = 1;
5563
Michael Chanb6016b72005-05-26 13:03:09 -07005564 for (i = 0; reg_tbl[i].offset != 0xffff; i++) {
5565 u32 offset, rw_mask, ro_mask, save_val, val;
Michael Chan5bae30c2007-05-03 13:18:46 -07005566 u16 flags = reg_tbl[i].flags;
5567
5568 if (is_5709 && (flags & BNX2_FL_NOT_5709))
5569 continue;
Michael Chanb6016b72005-05-26 13:03:09 -07005570
5571 offset = (u32) reg_tbl[i].offset;
5572 rw_mask = reg_tbl[i].rw_mask;
5573 ro_mask = reg_tbl[i].ro_mask;
5574
Peter Hagervall14ab9b82005-08-10 14:18:16 -07005575 save_val = readl(bp->regview + offset);
Michael Chanb6016b72005-05-26 13:03:09 -07005576
Peter Hagervall14ab9b82005-08-10 14:18:16 -07005577 writel(0, bp->regview + offset);
Michael Chanb6016b72005-05-26 13:03:09 -07005578
Peter Hagervall14ab9b82005-08-10 14:18:16 -07005579 val = readl(bp->regview + offset);
Michael Chanb6016b72005-05-26 13:03:09 -07005580 if ((val & rw_mask) != 0) {
5581 goto reg_test_err;
5582 }
5583
5584 if ((val & ro_mask) != (save_val & ro_mask)) {
5585 goto reg_test_err;
5586 }
5587
Peter Hagervall14ab9b82005-08-10 14:18:16 -07005588 writel(0xffffffff, bp->regview + offset);
Michael Chanb6016b72005-05-26 13:03:09 -07005589
Peter Hagervall14ab9b82005-08-10 14:18:16 -07005590 val = readl(bp->regview + offset);
Michael Chanb6016b72005-05-26 13:03:09 -07005591 if ((val & rw_mask) != rw_mask) {
5592 goto reg_test_err;
5593 }
5594
5595 if ((val & ro_mask) != (save_val & ro_mask)) {
5596 goto reg_test_err;
5597 }
5598
Peter Hagervall14ab9b82005-08-10 14:18:16 -07005599 writel(save_val, bp->regview + offset);
Michael Chanb6016b72005-05-26 13:03:09 -07005600 continue;
5601
5602reg_test_err:
Peter Hagervall14ab9b82005-08-10 14:18:16 -07005603 writel(save_val, bp->regview + offset);
Michael Chanb6016b72005-05-26 13:03:09 -07005604 ret = -ENODEV;
5605 break;
5606 }
5607 return ret;
5608}
5609
5610static int
5611bnx2_do_mem_test(struct bnx2 *bp, u32 start, u32 size)
5612{
Arjan van de Venf71e1302006-03-03 21:33:57 -05005613 static const u32 test_pattern[] = { 0x00000000, 0xffffffff, 0x55555555,
Michael Chanb6016b72005-05-26 13:03:09 -07005614 0xaaaaaaaa , 0xaa55aa55, 0x55aa55aa };
5615 int i;
5616
5617 for (i = 0; i < sizeof(test_pattern) / 4; i++) {
5618 u32 offset;
5619
5620 for (offset = 0; offset < size; offset += 4) {
5621
Michael Chan2726d6e2008-01-29 21:35:05 -08005622 bnx2_reg_wr_ind(bp, start + offset, test_pattern[i]);
Michael Chanb6016b72005-05-26 13:03:09 -07005623
Michael Chan2726d6e2008-01-29 21:35:05 -08005624 if (bnx2_reg_rd_ind(bp, start + offset) !=
Michael Chanb6016b72005-05-26 13:03:09 -07005625 test_pattern[i]) {
5626 return -ENODEV;
5627 }
5628 }
5629 }
5630 return 0;
5631}
5632
5633static int
5634bnx2_test_memory(struct bnx2 *bp)
5635{
5636 int ret = 0;
5637 int i;
Michael Chan5bae30c2007-05-03 13:18:46 -07005638 static struct mem_entry {
Michael Chanb6016b72005-05-26 13:03:09 -07005639 u32 offset;
5640 u32 len;
Michael Chan5bae30c2007-05-03 13:18:46 -07005641 } mem_tbl_5706[] = {
Michael Chanb6016b72005-05-26 13:03:09 -07005642 { 0x60000, 0x4000 },
Michael Chan5b0c76a2005-11-04 08:45:49 -08005643 { 0xa0000, 0x3000 },
Michael Chanb6016b72005-05-26 13:03:09 -07005644 { 0xe0000, 0x4000 },
5645 { 0x120000, 0x4000 },
5646 { 0x1a0000, 0x4000 },
5647 { 0x160000, 0x4000 },
5648 { 0xffffffff, 0 },
Michael Chan5bae30c2007-05-03 13:18:46 -07005649 },
5650 mem_tbl_5709[] = {
5651 { 0x60000, 0x4000 },
5652 { 0xa0000, 0x3000 },
5653 { 0xe0000, 0x4000 },
5654 { 0x120000, 0x4000 },
5655 { 0x1a0000, 0x4000 },
5656 { 0xffffffff, 0 },
Michael Chanb6016b72005-05-26 13:03:09 -07005657 };
Michael Chan5bae30c2007-05-03 13:18:46 -07005658 struct mem_entry *mem_tbl;
5659
5660 if (CHIP_NUM(bp) == CHIP_NUM_5709)
5661 mem_tbl = mem_tbl_5709;
5662 else
5663 mem_tbl = mem_tbl_5706;
Michael Chanb6016b72005-05-26 13:03:09 -07005664
5665 for (i = 0; mem_tbl[i].offset != 0xffffffff; i++) {
5666 if ((ret = bnx2_do_mem_test(bp, mem_tbl[i].offset,
5667 mem_tbl[i].len)) != 0) {
5668 return ret;
5669 }
5670 }
Jeff Garzik6aa20a22006-09-13 13:24:59 -04005671
Michael Chanb6016b72005-05-26 13:03:09 -07005672 return ret;
5673}
5674
Michael Chanbc5a0692006-01-23 16:13:22 -08005675#define BNX2_MAC_LOOPBACK 0
5676#define BNX2_PHY_LOOPBACK 1
5677
Michael Chanb6016b72005-05-26 13:03:09 -07005678static int
Michael Chanbc5a0692006-01-23 16:13:22 -08005679bnx2_run_loopback(struct bnx2 *bp, int loopback_mode)
Michael Chanb6016b72005-05-26 13:03:09 -07005680{
5681 unsigned int pkt_size, num_pkts, i;
5682 struct sk_buff *skb, *rx_skb;
5683 unsigned char *packet;
Michael Chanbc5a0692006-01-23 16:13:22 -08005684 u16 rx_start_idx, rx_idx;
Michael Chanb6016b72005-05-26 13:03:09 -07005685 dma_addr_t map;
5686 struct tx_bd *txbd;
5687 struct sw_bd *rx_buf;
5688 struct l2_fhdr *rx_hdr;
5689 int ret = -ENODEV;
Michael Chanc76c0472007-12-20 20:01:19 -08005690 struct bnx2_napi *bnapi = &bp->bnx2_napi[0], *tx_napi;
Michael Chan35e90102008-06-19 16:37:42 -07005691 struct bnx2_tx_ring_info *txr = &bnapi->tx_ring;
Michael Chanbb4f98a2008-06-19 16:38:19 -07005692 struct bnx2_rx_ring_info *rxr = &bnapi->rx_ring;
Michael Chanc76c0472007-12-20 20:01:19 -08005693
5694 tx_napi = bnapi;
Michael Chanb6016b72005-05-26 13:03:09 -07005695
Michael Chan35e90102008-06-19 16:37:42 -07005696 txr = &tx_napi->tx_ring;
Michael Chanbb4f98a2008-06-19 16:38:19 -07005697 rxr = &bnapi->rx_ring;
Michael Chanbc5a0692006-01-23 16:13:22 -08005698 if (loopback_mode == BNX2_MAC_LOOPBACK) {
5699 bp->loopback = MAC_LOOPBACK;
5700 bnx2_set_mac_loopback(bp);
5701 }
5702 else if (loopback_mode == BNX2_PHY_LOOPBACK) {
Michael Chan583c28e2008-01-21 19:51:35 -08005703 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
Michael Chan489310a2007-10-10 16:16:31 -07005704 return 0;
5705
Michael Chan80be4432006-11-19 14:07:28 -08005706 bp->loopback = PHY_LOOPBACK;
Michael Chanbc5a0692006-01-23 16:13:22 -08005707 bnx2_set_phy_loopback(bp);
5708 }
5709 else
5710 return -EINVAL;
Michael Chanb6016b72005-05-26 13:03:09 -07005711
Michael Chan84eaa182007-12-12 11:19:57 -08005712 pkt_size = min(bp->dev->mtu + ETH_HLEN, bp->rx_jumbo_thresh - 4);
Michael Chan932f3772006-08-15 01:39:36 -07005713 skb = netdev_alloc_skb(bp->dev, pkt_size);
John W. Linvilleb6cbc3b62005-11-10 12:58:00 -08005714 if (!skb)
5715 return -ENOMEM;
Michael Chanb6016b72005-05-26 13:03:09 -07005716 packet = skb_put(skb, pkt_size);
Michael Chan66342922006-12-14 15:57:04 -08005717 memcpy(packet, bp->dev->dev_addr, 6);
Michael Chanb6016b72005-05-26 13:03:09 -07005718 memset(packet + 6, 0x0, 8);
5719 for (i = 14; i < pkt_size; i++)
5720 packet[i] = (unsigned char) (i & 0xff);
5721
Alexander Duycke95524a2009-12-02 16:47:57 +00005722 map = pci_map_single(bp->pdev, skb->data, pkt_size,
5723 PCI_DMA_TODEVICE);
5724 if (pci_dma_mapping_error(bp->pdev, map)) {
Benjamin Li3d16af82008-10-09 12:26:41 -07005725 dev_kfree_skb(skb);
5726 return -EIO;
5727 }
Michael Chanb6016b72005-05-26 13:03:09 -07005728
Michael Chanbf5295b2006-03-23 01:11:56 -08005729 REG_WR(bp, BNX2_HC_COMMAND,
5730 bp->hc_cmd | BNX2_HC_COMMAND_COAL_NOW_WO_INT);
5731
Michael Chanb6016b72005-05-26 13:03:09 -07005732 REG_RD(bp, BNX2_HC_COMMAND);
5733
5734 udelay(5);
Michael Chan35efa7c2007-12-20 19:56:37 -08005735 rx_start_idx = bnx2_get_hw_rx_cons(bnapi);
Michael Chanb6016b72005-05-26 13:03:09 -07005736
Michael Chanb6016b72005-05-26 13:03:09 -07005737 num_pkts = 0;
5738
Michael Chan35e90102008-06-19 16:37:42 -07005739 txbd = &txr->tx_desc_ring[TX_RING_IDX(txr->tx_prod)];
Michael Chanb6016b72005-05-26 13:03:09 -07005740
5741 txbd->tx_bd_haddr_hi = (u64) map >> 32;
5742 txbd->tx_bd_haddr_lo = (u64) map & 0xffffffff;
5743 txbd->tx_bd_mss_nbytes = pkt_size;
5744 txbd->tx_bd_vlan_tag_flags = TX_BD_FLAGS_START | TX_BD_FLAGS_END;
5745
5746 num_pkts++;
Michael Chan35e90102008-06-19 16:37:42 -07005747 txr->tx_prod = NEXT_TX_BD(txr->tx_prod);
5748 txr->tx_prod_bseq += pkt_size;
Michael Chanb6016b72005-05-26 13:03:09 -07005749
Michael Chan35e90102008-06-19 16:37:42 -07005750 REG_WR16(bp, txr->tx_bidx_addr, txr->tx_prod);
5751 REG_WR(bp, txr->tx_bseq_addr, txr->tx_prod_bseq);
Michael Chanb6016b72005-05-26 13:03:09 -07005752
5753 udelay(100);
5754
Michael Chanbf5295b2006-03-23 01:11:56 -08005755 REG_WR(bp, BNX2_HC_COMMAND,
5756 bp->hc_cmd | BNX2_HC_COMMAND_COAL_NOW_WO_INT);
5757
Michael Chanb6016b72005-05-26 13:03:09 -07005758 REG_RD(bp, BNX2_HC_COMMAND);
5759
5760 udelay(5);
5761
Alexander Duycke95524a2009-12-02 16:47:57 +00005762 pci_unmap_single(bp->pdev, map, pkt_size, PCI_DMA_TODEVICE);
Michael Chan745720e2006-06-29 12:37:41 -07005763 dev_kfree_skb(skb);
Michael Chanb6016b72005-05-26 13:03:09 -07005764
Michael Chan35e90102008-06-19 16:37:42 -07005765 if (bnx2_get_hw_tx_cons(tx_napi) != txr->tx_prod)
Michael Chanb6016b72005-05-26 13:03:09 -07005766 goto loopback_test_done;
Michael Chanb6016b72005-05-26 13:03:09 -07005767
Michael Chan35efa7c2007-12-20 19:56:37 -08005768 rx_idx = bnx2_get_hw_rx_cons(bnapi);
Michael Chanb6016b72005-05-26 13:03:09 -07005769 if (rx_idx != rx_start_idx + num_pkts) {
5770 goto loopback_test_done;
5771 }
5772
Michael Chanbb4f98a2008-06-19 16:38:19 -07005773 rx_buf = &rxr->rx_buf_ring[rx_start_idx];
Michael Chanb6016b72005-05-26 13:03:09 -07005774 rx_skb = rx_buf->skb;
5775
5776 rx_hdr = (struct l2_fhdr *) rx_skb->data;
Benjamin Lid89cb6a2008-05-16 22:18:57 -07005777 skb_reserve(rx_skb, BNX2_RX_OFFSET);
Michael Chanb6016b72005-05-26 13:03:09 -07005778
5779 pci_dma_sync_single_for_cpu(bp->pdev,
5780 pci_unmap_addr(rx_buf, mapping),
5781 bp->rx_buf_size, PCI_DMA_FROMDEVICE);
5782
Michael Chanade2bfe2006-01-23 16:09:51 -08005783 if (rx_hdr->l2_fhdr_status &
Michael Chanb6016b72005-05-26 13:03:09 -07005784 (L2_FHDR_ERRORS_BAD_CRC |
5785 L2_FHDR_ERRORS_PHY_DECODE |
5786 L2_FHDR_ERRORS_ALIGNMENT |
5787 L2_FHDR_ERRORS_TOO_SHORT |
5788 L2_FHDR_ERRORS_GIANT_FRAME)) {
5789
5790 goto loopback_test_done;
5791 }
5792
5793 if ((rx_hdr->l2_fhdr_pkt_len - 4) != pkt_size) {
5794 goto loopback_test_done;
5795 }
5796
5797 for (i = 14; i < pkt_size; i++) {
5798 if (*(rx_skb->data + i) != (unsigned char) (i & 0xff)) {
5799 goto loopback_test_done;
5800 }
5801 }
5802
5803 ret = 0;
5804
5805loopback_test_done:
5806 bp->loopback = 0;
5807 return ret;
5808}
5809
Michael Chanbc5a0692006-01-23 16:13:22 -08005810#define BNX2_MAC_LOOPBACK_FAILED 1
5811#define BNX2_PHY_LOOPBACK_FAILED 2
5812#define BNX2_LOOPBACK_FAILED (BNX2_MAC_LOOPBACK_FAILED | \
5813 BNX2_PHY_LOOPBACK_FAILED)
5814
5815static int
5816bnx2_test_loopback(struct bnx2 *bp)
5817{
5818 int rc = 0;
5819
5820 if (!netif_running(bp->dev))
5821 return BNX2_LOOPBACK_FAILED;
5822
5823 bnx2_reset_nic(bp, BNX2_DRV_MSG_CODE_RESET);
5824 spin_lock_bh(&bp->phy_lock);
Michael Chan9a120bc2008-05-16 22:17:45 -07005825 bnx2_init_phy(bp, 1);
Michael Chanbc5a0692006-01-23 16:13:22 -08005826 spin_unlock_bh(&bp->phy_lock);
5827 if (bnx2_run_loopback(bp, BNX2_MAC_LOOPBACK))
5828 rc |= BNX2_MAC_LOOPBACK_FAILED;
5829 if (bnx2_run_loopback(bp, BNX2_PHY_LOOPBACK))
5830 rc |= BNX2_PHY_LOOPBACK_FAILED;
5831 return rc;
5832}
5833
Michael Chanb6016b72005-05-26 13:03:09 -07005834#define NVRAM_SIZE 0x200
5835#define CRC32_RESIDUAL 0xdebb20e3
5836
5837static int
5838bnx2_test_nvram(struct bnx2 *bp)
5839{
Al Virob491edd2007-12-22 19:44:51 +00005840 __be32 buf[NVRAM_SIZE / 4];
Michael Chanb6016b72005-05-26 13:03:09 -07005841 u8 *data = (u8 *) buf;
5842 int rc = 0;
5843 u32 magic, csum;
5844
5845 if ((rc = bnx2_nvram_read(bp, 0, data, 4)) != 0)
5846 goto test_nvram_done;
5847
5848 magic = be32_to_cpu(buf[0]);
5849 if (magic != 0x669955aa) {
5850 rc = -ENODEV;
5851 goto test_nvram_done;
5852 }
5853
5854 if ((rc = bnx2_nvram_read(bp, 0x100, data, NVRAM_SIZE)) != 0)
5855 goto test_nvram_done;
5856
5857 csum = ether_crc_le(0x100, data);
5858 if (csum != CRC32_RESIDUAL) {
5859 rc = -ENODEV;
5860 goto test_nvram_done;
5861 }
5862
5863 csum = ether_crc_le(0x100, data + 0x100);
5864 if (csum != CRC32_RESIDUAL) {
5865 rc = -ENODEV;
5866 }
5867
5868test_nvram_done:
5869 return rc;
5870}
5871
5872static int
5873bnx2_test_link(struct bnx2 *bp)
5874{
5875 u32 bmsr;
5876
Michael Chan9f52b562008-10-09 12:21:46 -07005877 if (!netif_running(bp->dev))
5878 return -ENODEV;
5879
Michael Chan583c28e2008-01-21 19:51:35 -08005880 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP) {
Michael Chan489310a2007-10-10 16:16:31 -07005881 if (bp->link_up)
5882 return 0;
5883 return -ENODEV;
5884 }
Michael Chanc770a652005-08-25 15:38:39 -07005885 spin_lock_bh(&bp->phy_lock);
Michael Chan27a005b2007-05-03 13:23:41 -07005886 bnx2_enable_bmsr1(bp);
5887 bnx2_read_phy(bp, bp->mii_bmsr1, &bmsr);
5888 bnx2_read_phy(bp, bp->mii_bmsr1, &bmsr);
5889 bnx2_disable_bmsr1(bp);
Michael Chanc770a652005-08-25 15:38:39 -07005890 spin_unlock_bh(&bp->phy_lock);
Jeff Garzik6aa20a22006-09-13 13:24:59 -04005891
Michael Chanb6016b72005-05-26 13:03:09 -07005892 if (bmsr & BMSR_LSTATUS) {
5893 return 0;
5894 }
5895 return -ENODEV;
5896}
5897
5898static int
5899bnx2_test_intr(struct bnx2 *bp)
5900{
5901 int i;
Michael Chanb6016b72005-05-26 13:03:09 -07005902 u16 status_idx;
5903
5904 if (!netif_running(bp->dev))
5905 return -ENODEV;
5906
5907 status_idx = REG_RD(bp, BNX2_PCICFG_INT_ACK_CMD) & 0xffff;
5908
5909 /* This register is not touched during run-time. */
Michael Chanbf5295b2006-03-23 01:11:56 -08005910 REG_WR(bp, BNX2_HC_COMMAND, bp->hc_cmd | BNX2_HC_COMMAND_COAL_NOW);
Michael Chanb6016b72005-05-26 13:03:09 -07005911 REG_RD(bp, BNX2_HC_COMMAND);
5912
5913 for (i = 0; i < 10; i++) {
5914 if ((REG_RD(bp, BNX2_PCICFG_INT_ACK_CMD) & 0xffff) !=
5915 status_idx) {
5916
5917 break;
5918 }
5919
5920 msleep_interruptible(10);
5921 }
5922 if (i < 10)
5923 return 0;
5924
5925 return -ENODEV;
5926}
5927
Michael Chan38ea3682008-02-23 19:48:57 -08005928/* Determining link for parallel detection. */
Michael Chanb2fadea2008-01-21 17:07:06 -08005929static int
5930bnx2_5706_serdes_has_link(struct bnx2 *bp)
5931{
5932 u32 mode_ctl, an_dbg, exp;
5933
Michael Chan38ea3682008-02-23 19:48:57 -08005934 if (bp->phy_flags & BNX2_PHY_FLAG_NO_PARALLEL)
5935 return 0;
5936
Michael Chanb2fadea2008-01-21 17:07:06 -08005937 bnx2_write_phy(bp, MII_BNX2_MISC_SHADOW, MISC_SHDW_MODE_CTL);
5938 bnx2_read_phy(bp, MII_BNX2_MISC_SHADOW, &mode_ctl);
5939
5940 if (!(mode_ctl & MISC_SHDW_MODE_CTL_SIG_DET))
5941 return 0;
5942
5943 bnx2_write_phy(bp, MII_BNX2_MISC_SHADOW, MISC_SHDW_AN_DBG);
5944 bnx2_read_phy(bp, MII_BNX2_MISC_SHADOW, &an_dbg);
5945 bnx2_read_phy(bp, MII_BNX2_MISC_SHADOW, &an_dbg);
5946
Michael Chanf3014c02008-01-29 21:33:03 -08005947 if (an_dbg & (MISC_SHDW_AN_DBG_NOSYNC | MISC_SHDW_AN_DBG_RUDI_INVALID))
Michael Chanb2fadea2008-01-21 17:07:06 -08005948 return 0;
5949
5950 bnx2_write_phy(bp, MII_BNX2_DSP_ADDRESS, MII_EXPAND_REG1);
5951 bnx2_read_phy(bp, MII_BNX2_DSP_RW_PORT, &exp);
5952 bnx2_read_phy(bp, MII_BNX2_DSP_RW_PORT, &exp);
5953
5954 if (exp & MII_EXPAND_REG1_RUDI_C) /* receiving CONFIG */
5955 return 0;
5956
5957 return 1;
5958}
5959
Michael Chanb6016b72005-05-26 13:03:09 -07005960static void
Michael Chan48b01e22006-11-19 14:08:00 -08005961bnx2_5706_serdes_timer(struct bnx2 *bp)
5962{
Michael Chanb2fadea2008-01-21 17:07:06 -08005963 int check_link = 1;
5964
Michael Chan48b01e22006-11-19 14:08:00 -08005965 spin_lock(&bp->phy_lock);
Michael Chanb2fadea2008-01-21 17:07:06 -08005966 if (bp->serdes_an_pending) {
Michael Chan48b01e22006-11-19 14:08:00 -08005967 bp->serdes_an_pending--;
Michael Chanb2fadea2008-01-21 17:07:06 -08005968 check_link = 0;
5969 } else if ((bp->link_up == 0) && (bp->autoneg & AUTONEG_SPEED)) {
Michael Chan48b01e22006-11-19 14:08:00 -08005970 u32 bmcr;
5971
Benjamin Liac392ab2008-09-18 16:40:49 -07005972 bp->current_interval = BNX2_TIMER_INTERVAL;
Michael Chan48b01e22006-11-19 14:08:00 -08005973
Michael Chanca58c3a2007-05-03 13:22:52 -07005974 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chan48b01e22006-11-19 14:08:00 -08005975
5976 if (bmcr & BMCR_ANENABLE) {
Michael Chanb2fadea2008-01-21 17:07:06 -08005977 if (bnx2_5706_serdes_has_link(bp)) {
Michael Chan48b01e22006-11-19 14:08:00 -08005978 bmcr &= ~BMCR_ANENABLE;
5979 bmcr |= BMCR_SPEED1000 | BMCR_FULLDPLX;
Michael Chanca58c3a2007-05-03 13:22:52 -07005980 bnx2_write_phy(bp, bp->mii_bmcr, bmcr);
Michael Chan583c28e2008-01-21 19:51:35 -08005981 bp->phy_flags |= BNX2_PHY_FLAG_PARALLEL_DETECT;
Michael Chan48b01e22006-11-19 14:08:00 -08005982 }
5983 }
5984 }
5985 else if ((bp->link_up) && (bp->autoneg & AUTONEG_SPEED) &&
Michael Chan583c28e2008-01-21 19:51:35 -08005986 (bp->phy_flags & BNX2_PHY_FLAG_PARALLEL_DETECT)) {
Michael Chan48b01e22006-11-19 14:08:00 -08005987 u32 phy2;
5988
5989 bnx2_write_phy(bp, 0x17, 0x0f01);
5990 bnx2_read_phy(bp, 0x15, &phy2);
5991 if (phy2 & 0x20) {
5992 u32 bmcr;
5993
Michael Chanca58c3a2007-05-03 13:22:52 -07005994 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chan48b01e22006-11-19 14:08:00 -08005995 bmcr |= BMCR_ANENABLE;
Michael Chanca58c3a2007-05-03 13:22:52 -07005996 bnx2_write_phy(bp, bp->mii_bmcr, bmcr);
Michael Chan48b01e22006-11-19 14:08:00 -08005997
Michael Chan583c28e2008-01-21 19:51:35 -08005998 bp->phy_flags &= ~BNX2_PHY_FLAG_PARALLEL_DETECT;
Michael Chan48b01e22006-11-19 14:08:00 -08005999 }
6000 } else
Benjamin Liac392ab2008-09-18 16:40:49 -07006001 bp->current_interval = BNX2_TIMER_INTERVAL;
Michael Chan48b01e22006-11-19 14:08:00 -08006002
Michael Chana2724e22008-02-23 19:47:44 -08006003 if (check_link) {
Michael Chanb2fadea2008-01-21 17:07:06 -08006004 u32 val;
6005
6006 bnx2_write_phy(bp, MII_BNX2_MISC_SHADOW, MISC_SHDW_AN_DBG);
6007 bnx2_read_phy(bp, MII_BNX2_MISC_SHADOW, &val);
6008 bnx2_read_phy(bp, MII_BNX2_MISC_SHADOW, &val);
6009
Michael Chana2724e22008-02-23 19:47:44 -08006010 if (bp->link_up && (val & MISC_SHDW_AN_DBG_NOSYNC)) {
6011 if (!(bp->phy_flags & BNX2_PHY_FLAG_FORCED_DOWN)) {
6012 bnx2_5706s_force_link_dn(bp, 1);
6013 bp->phy_flags |= BNX2_PHY_FLAG_FORCED_DOWN;
6014 } else
6015 bnx2_set_link(bp);
6016 } else if (!bp->link_up && !(val & MISC_SHDW_AN_DBG_NOSYNC))
6017 bnx2_set_link(bp);
Michael Chanb2fadea2008-01-21 17:07:06 -08006018 }
Michael Chan48b01e22006-11-19 14:08:00 -08006019 spin_unlock(&bp->phy_lock);
6020}
6021
6022static void
Michael Chanf8dd0642006-11-19 14:08:29 -08006023bnx2_5708_serdes_timer(struct bnx2 *bp)
6024{
Michael Chan583c28e2008-01-21 19:51:35 -08006025 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
Michael Chan0d8a6572007-07-07 22:49:43 -07006026 return;
6027
Michael Chan583c28e2008-01-21 19:51:35 -08006028 if ((bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE) == 0) {
Michael Chanf8dd0642006-11-19 14:08:29 -08006029 bp->serdes_an_pending = 0;
6030 return;
6031 }
6032
6033 spin_lock(&bp->phy_lock);
6034 if (bp->serdes_an_pending)
6035 bp->serdes_an_pending--;
6036 else if ((bp->link_up == 0) && (bp->autoneg & AUTONEG_SPEED)) {
6037 u32 bmcr;
6038
Michael Chanca58c3a2007-05-03 13:22:52 -07006039 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chanf8dd0642006-11-19 14:08:29 -08006040 if (bmcr & BMCR_ANENABLE) {
Michael Chan605a9e22007-05-03 13:23:13 -07006041 bnx2_enable_forced_2g5(bp);
Michael Chan40105c02008-11-12 16:02:45 -08006042 bp->current_interval = BNX2_SERDES_FORCED_TIMEOUT;
Michael Chanf8dd0642006-11-19 14:08:29 -08006043 } else {
Michael Chan605a9e22007-05-03 13:23:13 -07006044 bnx2_disable_forced_2g5(bp);
Michael Chanf8dd0642006-11-19 14:08:29 -08006045 bp->serdes_an_pending = 2;
Benjamin Liac392ab2008-09-18 16:40:49 -07006046 bp->current_interval = BNX2_TIMER_INTERVAL;
Michael Chanf8dd0642006-11-19 14:08:29 -08006047 }
6048
6049 } else
Benjamin Liac392ab2008-09-18 16:40:49 -07006050 bp->current_interval = BNX2_TIMER_INTERVAL;
Michael Chanf8dd0642006-11-19 14:08:29 -08006051
6052 spin_unlock(&bp->phy_lock);
6053}
6054
6055static void
Michael Chanb6016b72005-05-26 13:03:09 -07006056bnx2_timer(unsigned long data)
6057{
6058 struct bnx2 *bp = (struct bnx2 *) data;
Michael Chanb6016b72005-05-26 13:03:09 -07006059
Michael Chancd339a02005-08-25 15:35:24 -07006060 if (!netif_running(bp->dev))
6061 return;
6062
Michael Chanb6016b72005-05-26 13:03:09 -07006063 if (atomic_read(&bp->intr_sem) != 0)
6064 goto bnx2_restart_timer;
6065
Michael Chanefba0182008-12-03 00:36:15 -08006066 if ((bp->flags & (BNX2_FLAG_USING_MSI | BNX2_FLAG_ONE_SHOT_MSI)) ==
6067 BNX2_FLAG_USING_MSI)
6068 bnx2_chk_missed_msi(bp);
6069
Michael Chandf149d72007-07-07 22:51:36 -07006070 bnx2_send_heart_beat(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07006071
Michael Chan2726d6e2008-01-29 21:35:05 -08006072 bp->stats_blk->stat_FwRxDrop =
6073 bnx2_reg_rd_ind(bp, BNX2_FW_RX_DROP_COUNT);
Michael Chancea94db2006-06-12 22:16:13 -07006074
Michael Chan02537b062007-06-04 21:24:07 -07006075 /* workaround occasional corrupted counters */
Michael Chan61d9e3f2009-08-21 16:20:46 +00006076 if ((bp->flags & BNX2_FLAG_BROKEN_STATS) && bp->stats_ticks)
Michael Chan02537b062007-06-04 21:24:07 -07006077 REG_WR(bp, BNX2_HC_COMMAND, bp->hc_cmd |
6078 BNX2_HC_COMMAND_STATS_NOW);
6079
Michael Chan583c28e2008-01-21 19:51:35 -08006080 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Michael Chanf8dd0642006-11-19 14:08:29 -08006081 if (CHIP_NUM(bp) == CHIP_NUM_5706)
6082 bnx2_5706_serdes_timer(bp);
Michael Chan27a005b2007-05-03 13:23:41 -07006083 else
Michael Chanf8dd0642006-11-19 14:08:29 -08006084 bnx2_5708_serdes_timer(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07006085 }
6086
6087bnx2_restart_timer:
Michael Chancd339a02005-08-25 15:35:24 -07006088 mod_timer(&bp->timer, jiffies + bp->current_interval);
Michael Chanb6016b72005-05-26 13:03:09 -07006089}
6090
Michael Chan8e6a72c2007-05-03 13:24:48 -07006091static int
6092bnx2_request_irq(struct bnx2 *bp)
6093{
Michael Chan6d866ff2007-12-20 19:56:09 -08006094 unsigned long flags;
Michael Chanb4b36042007-12-20 19:59:30 -08006095 struct bnx2_irq *irq;
6096 int rc = 0, i;
Michael Chan8e6a72c2007-05-03 13:24:48 -07006097
David S. Millerf86e82f2008-01-21 17:15:40 -08006098 if (bp->flags & BNX2_FLAG_USING_MSI_OR_MSIX)
Michael Chan6d866ff2007-12-20 19:56:09 -08006099 flags = 0;
6100 else
6101 flags = IRQF_SHARED;
Michael Chanb4b36042007-12-20 19:59:30 -08006102
6103 for (i = 0; i < bp->irq_nvecs; i++) {
6104 irq = &bp->irq_tbl[i];
Michael Chanc76c0472007-12-20 20:01:19 -08006105 rc = request_irq(irq->vector, irq->handler, flags, irq->name,
Michael Chanf0ea2e62008-06-19 16:41:57 -07006106 &bp->bnx2_napi[i]);
Michael Chanb4b36042007-12-20 19:59:30 -08006107 if (rc)
6108 break;
6109 irq->requested = 1;
6110 }
Michael Chan8e6a72c2007-05-03 13:24:48 -07006111 return rc;
6112}
6113
6114static void
6115bnx2_free_irq(struct bnx2 *bp)
6116{
Michael Chanb4b36042007-12-20 19:59:30 -08006117 struct bnx2_irq *irq;
6118 int i;
Michael Chan8e6a72c2007-05-03 13:24:48 -07006119
Michael Chanb4b36042007-12-20 19:59:30 -08006120 for (i = 0; i < bp->irq_nvecs; i++) {
6121 irq = &bp->irq_tbl[i];
6122 if (irq->requested)
Michael Chanf0ea2e62008-06-19 16:41:57 -07006123 free_irq(irq->vector, &bp->bnx2_napi[i]);
Michael Chanb4b36042007-12-20 19:59:30 -08006124 irq->requested = 0;
Michael Chan6d866ff2007-12-20 19:56:09 -08006125 }
David S. Millerf86e82f2008-01-21 17:15:40 -08006126 if (bp->flags & BNX2_FLAG_USING_MSI)
Michael Chanb4b36042007-12-20 19:59:30 -08006127 pci_disable_msi(bp->pdev);
David S. Millerf86e82f2008-01-21 17:15:40 -08006128 else if (bp->flags & BNX2_FLAG_USING_MSIX)
Michael Chanb4b36042007-12-20 19:59:30 -08006129 pci_disable_msix(bp->pdev);
6130
David S. Millerf86e82f2008-01-21 17:15:40 -08006131 bp->flags &= ~(BNX2_FLAG_USING_MSI_OR_MSIX | BNX2_FLAG_ONE_SHOT_MSI);
Michael Chanb4b36042007-12-20 19:59:30 -08006132}
6133
6134static void
Michael Chan5e9ad9e2008-06-19 16:43:17 -07006135bnx2_enable_msix(struct bnx2 *bp, int msix_vecs)
Michael Chanb4b36042007-12-20 19:59:30 -08006136{
Michael Chan57851d82007-12-20 20:01:44 -08006137 int i, rc;
6138 struct msix_entry msix_ent[BNX2_MAX_MSIX_VEC];
Michael Chan4e1d0de2008-12-16 20:27:45 -08006139 struct net_device *dev = bp->dev;
6140 const int len = sizeof(bp->irq_tbl[0].name);
Michael Chan57851d82007-12-20 20:01:44 -08006141
Michael Chanb4b36042007-12-20 19:59:30 -08006142 bnx2_setup_msix_tbl(bp);
6143 REG_WR(bp, BNX2_PCI_MSIX_CONTROL, BNX2_MAX_MSIX_HW_VEC - 1);
6144 REG_WR(bp, BNX2_PCI_MSIX_TBL_OFF_BIR, BNX2_PCI_GRC_WINDOW2_BASE);
6145 REG_WR(bp, BNX2_PCI_MSIX_PBA_OFF_BIT, BNX2_PCI_GRC_WINDOW3_BASE);
Michael Chan57851d82007-12-20 20:01:44 -08006146
Benjamin Lie2eb8e32010-01-08 00:51:21 -08006147 /* Need to flush the previous three writes to ensure MSI-X
6148 * is setup properly */
6149 REG_RD(bp, BNX2_PCI_MSIX_CONTROL);
6150
Michael Chan57851d82007-12-20 20:01:44 -08006151 for (i = 0; i < BNX2_MAX_MSIX_VEC; i++) {
6152 msix_ent[i].entry = i;
6153 msix_ent[i].vector = 0;
6154 }
6155
6156 rc = pci_enable_msix(bp->pdev, msix_ent, BNX2_MAX_MSIX_VEC);
6157 if (rc != 0)
6158 return;
6159
Michael Chan5e9ad9e2008-06-19 16:43:17 -07006160 bp->irq_nvecs = msix_vecs;
David S. Millerf86e82f2008-01-21 17:15:40 -08006161 bp->flags |= BNX2_FLAG_USING_MSIX | BNX2_FLAG_ONE_SHOT_MSI;
Michael Chan69010312009-03-18 18:11:51 -07006162 for (i = 0; i < BNX2_MAX_MSIX_VEC; i++) {
Michael Chan57851d82007-12-20 20:01:44 -08006163 bp->irq_tbl[i].vector = msix_ent[i].vector;
Michael Chan69010312009-03-18 18:11:51 -07006164 snprintf(bp->irq_tbl[i].name, len, "%s-%d", dev->name, i);
6165 bp->irq_tbl[i].handler = bnx2_msi_1shot;
6166 }
Michael Chan6d866ff2007-12-20 19:56:09 -08006167}
6168
6169static void
6170bnx2_setup_int_mode(struct bnx2 *bp, int dis_msi)
6171{
Michael Chan5e9ad9e2008-06-19 16:43:17 -07006172 int cpus = num_online_cpus();
Benjamin Li706bf242008-07-18 17:55:11 -07006173 int msix_vecs = min(cpus + 1, RX_MAX_RINGS);
Michael Chan5e9ad9e2008-06-19 16:43:17 -07006174
Michael Chan6d866ff2007-12-20 19:56:09 -08006175 bp->irq_tbl[0].handler = bnx2_interrupt;
6176 strcpy(bp->irq_tbl[0].name, bp->dev->name);
Michael Chanb4b36042007-12-20 19:59:30 -08006177 bp->irq_nvecs = 1;
6178 bp->irq_tbl[0].vector = bp->pdev->irq;
Michael Chan6d866ff2007-12-20 19:56:09 -08006179
Michael Chan5e9ad9e2008-06-19 16:43:17 -07006180 if ((bp->flags & BNX2_FLAG_MSIX_CAP) && !dis_msi && cpus > 1)
6181 bnx2_enable_msix(bp, msix_vecs);
Michael Chanb4b36042007-12-20 19:59:30 -08006182
David S. Millerf86e82f2008-01-21 17:15:40 -08006183 if ((bp->flags & BNX2_FLAG_MSI_CAP) && !dis_msi &&
6184 !(bp->flags & BNX2_FLAG_USING_MSIX)) {
Michael Chan6d866ff2007-12-20 19:56:09 -08006185 if (pci_enable_msi(bp->pdev) == 0) {
David S. Millerf86e82f2008-01-21 17:15:40 -08006186 bp->flags |= BNX2_FLAG_USING_MSI;
Michael Chan6d866ff2007-12-20 19:56:09 -08006187 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
David S. Millerf86e82f2008-01-21 17:15:40 -08006188 bp->flags |= BNX2_FLAG_ONE_SHOT_MSI;
Michael Chan6d866ff2007-12-20 19:56:09 -08006189 bp->irq_tbl[0].handler = bnx2_msi_1shot;
6190 } else
6191 bp->irq_tbl[0].handler = bnx2_msi;
Michael Chanb4b36042007-12-20 19:59:30 -08006192
6193 bp->irq_tbl[0].vector = bp->pdev->irq;
Michael Chan6d866ff2007-12-20 19:56:09 -08006194 }
6195 }
Benjamin Li706bf242008-07-18 17:55:11 -07006196
6197 bp->num_tx_rings = rounddown_pow_of_two(bp->irq_nvecs);
6198 bp->dev->real_num_tx_queues = bp->num_tx_rings;
6199
Michael Chan5e9ad9e2008-06-19 16:43:17 -07006200 bp->num_rx_rings = bp->irq_nvecs;
Michael Chan8e6a72c2007-05-03 13:24:48 -07006201}
6202
Michael Chanb6016b72005-05-26 13:03:09 -07006203/* Called with rtnl_lock */
6204static int
6205bnx2_open(struct net_device *dev)
6206{
Michael Chan972ec0d2006-01-23 16:12:43 -08006207 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006208 int rc;
6209
Michael Chan1b2f9222007-05-03 13:20:19 -07006210 netif_carrier_off(dev);
6211
Pavel Machek829ca9a2005-09-03 15:56:56 -07006212 bnx2_set_power_state(bp, PCI_D0);
Michael Chanb6016b72005-05-26 13:03:09 -07006213 bnx2_disable_int(bp);
6214
Michael Chan6d866ff2007-12-20 19:56:09 -08006215 bnx2_setup_int_mode(bp, disable_msi);
Michael Chan35efa7c2007-12-20 19:56:37 -08006216 bnx2_napi_enable(bp);
Michael Chan35e90102008-06-19 16:37:42 -07006217 rc = bnx2_alloc_mem(bp);
Michael Chan2739a8b2008-06-19 16:44:10 -07006218 if (rc)
6219 goto open_err;
Michael Chan35e90102008-06-19 16:37:42 -07006220
Michael Chan8e6a72c2007-05-03 13:24:48 -07006221 rc = bnx2_request_irq(bp);
Michael Chan2739a8b2008-06-19 16:44:10 -07006222 if (rc)
6223 goto open_err;
Michael Chanb6016b72005-05-26 13:03:09 -07006224
Michael Chan9a120bc2008-05-16 22:17:45 -07006225 rc = bnx2_init_nic(bp, 1);
Michael Chan2739a8b2008-06-19 16:44:10 -07006226 if (rc)
6227 goto open_err;
Jeff Garzik6aa20a22006-09-13 13:24:59 -04006228
Michael Chancd339a02005-08-25 15:35:24 -07006229 mod_timer(&bp->timer, jiffies + bp->current_interval);
Michael Chanb6016b72005-05-26 13:03:09 -07006230
6231 atomic_set(&bp->intr_sem, 0);
6232
Michael Chan354fcd72010-01-17 07:30:44 +00006233 memset(bp->temp_stats_blk, 0, sizeof(struct statistics_block));
6234
Michael Chanb6016b72005-05-26 13:03:09 -07006235 bnx2_enable_int(bp);
6236
David S. Millerf86e82f2008-01-21 17:15:40 -08006237 if (bp->flags & BNX2_FLAG_USING_MSI) {
Michael Chanb6016b72005-05-26 13:03:09 -07006238 /* Test MSI to make sure it is working
6239 * If MSI test fails, go back to INTx mode
6240 */
6241 if (bnx2_test_intr(bp) != 0) {
6242 printk(KERN_WARNING PFX "%s: No interrupt was generated"
6243 " using MSI, switching to INTx mode. Please"
6244 " report this failure to the PCI maintainer"
6245 " and include system chipset information.\n",
6246 bp->dev->name);
6247
6248 bnx2_disable_int(bp);
Michael Chan8e6a72c2007-05-03 13:24:48 -07006249 bnx2_free_irq(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07006250
Michael Chan6d866ff2007-12-20 19:56:09 -08006251 bnx2_setup_int_mode(bp, 1);
6252
Michael Chan9a120bc2008-05-16 22:17:45 -07006253 rc = bnx2_init_nic(bp, 0);
Michael Chanb6016b72005-05-26 13:03:09 -07006254
Michael Chan8e6a72c2007-05-03 13:24:48 -07006255 if (!rc)
6256 rc = bnx2_request_irq(bp);
6257
Michael Chanb6016b72005-05-26 13:03:09 -07006258 if (rc) {
Michael Chanb6016b72005-05-26 13:03:09 -07006259 del_timer_sync(&bp->timer);
Michael Chan2739a8b2008-06-19 16:44:10 -07006260 goto open_err;
Michael Chanb6016b72005-05-26 13:03:09 -07006261 }
6262 bnx2_enable_int(bp);
6263 }
6264 }
David S. Millerf86e82f2008-01-21 17:15:40 -08006265 if (bp->flags & BNX2_FLAG_USING_MSI)
Michael Chanb6016b72005-05-26 13:03:09 -07006266 printk(KERN_INFO PFX "%s: using MSI\n", dev->name);
David S. Millerf86e82f2008-01-21 17:15:40 -08006267 else if (bp->flags & BNX2_FLAG_USING_MSIX)
Michael Chan57851d82007-12-20 20:01:44 -08006268 printk(KERN_INFO PFX "%s: using MSIX\n", dev->name);
Michael Chanb6016b72005-05-26 13:03:09 -07006269
Benjamin Li706bf242008-07-18 17:55:11 -07006270 netif_tx_start_all_queues(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006271
6272 return 0;
Michael Chan2739a8b2008-06-19 16:44:10 -07006273
6274open_err:
6275 bnx2_napi_disable(bp);
6276 bnx2_free_skbs(bp);
6277 bnx2_free_irq(bp);
6278 bnx2_free_mem(bp);
6279 return rc;
Michael Chanb6016b72005-05-26 13:03:09 -07006280}
6281
6282static void
David Howellsc4028952006-11-22 14:57:56 +00006283bnx2_reset_task(struct work_struct *work)
Michael Chanb6016b72005-05-26 13:03:09 -07006284{
David Howellsc4028952006-11-22 14:57:56 +00006285 struct bnx2 *bp = container_of(work, struct bnx2, reset_task);
Michael Chanb6016b72005-05-26 13:03:09 -07006286
Michael Chan51bf6bb2009-12-03 09:46:31 +00006287 rtnl_lock();
6288 if (!netif_running(bp->dev)) {
6289 rtnl_unlock();
Michael Chanafdc08b2005-08-25 15:34:29 -07006290 return;
Michael Chan51bf6bb2009-12-03 09:46:31 +00006291 }
Michael Chanafdc08b2005-08-25 15:34:29 -07006292
Michael Chanb6016b72005-05-26 13:03:09 -07006293 bnx2_netif_stop(bp);
6294
Michael Chan9a120bc2008-05-16 22:17:45 -07006295 bnx2_init_nic(bp, 1);
Michael Chanb6016b72005-05-26 13:03:09 -07006296
6297 atomic_set(&bp->intr_sem, 1);
6298 bnx2_netif_start(bp);
Michael Chan51bf6bb2009-12-03 09:46:31 +00006299 rtnl_unlock();
Michael Chanb6016b72005-05-26 13:03:09 -07006300}
6301
6302static void
Michael Chan20175c52009-12-03 09:46:32 +00006303bnx2_dump_state(struct bnx2 *bp)
6304{
6305 struct net_device *dev = bp->dev;
6306
6307 printk(KERN_ERR PFX "%s DEBUG: intr_sem[%x]\n", dev->name,
6308 atomic_read(&bp->intr_sem));
6309 printk(KERN_ERR PFX "%s DEBUG: EMAC_TX_STATUS[%08x] "
6310 "RPM_MGMT_PKT_CTRL[%08x]\n", dev->name,
6311 REG_RD(bp, BNX2_EMAC_TX_STATUS),
6312 REG_RD(bp, BNX2_RPM_MGMT_PKT_CTRL));
6313 printk(KERN_ERR PFX "%s DEBUG: MCP_STATE_P0[%08x] MCP_STATE_P1[%08x]\n",
6314 dev->name, bnx2_reg_rd_ind(bp, BNX2_MCP_STATE_P0),
6315 bnx2_reg_rd_ind(bp, BNX2_MCP_STATE_P1));
6316 printk(KERN_ERR PFX "%s DEBUG: HC_STATS_INTERRUPT_STATUS[%08x]\n",
6317 dev->name, REG_RD(bp, BNX2_HC_STATS_INTERRUPT_STATUS));
6318 if (bp->flags & BNX2_FLAG_USING_MSIX)
6319 printk(KERN_ERR PFX "%s DEBUG: PBA[%08x]\n", dev->name,
6320 REG_RD(bp, BNX2_PCI_GRC_WINDOW3_BASE));
6321}
6322
6323static void
Michael Chanb6016b72005-05-26 13:03:09 -07006324bnx2_tx_timeout(struct net_device *dev)
6325{
Michael Chan972ec0d2006-01-23 16:12:43 -08006326 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006327
Michael Chan20175c52009-12-03 09:46:32 +00006328 bnx2_dump_state(bp);
6329
Michael Chanb6016b72005-05-26 13:03:09 -07006330 /* This allows the netif to be shutdown gracefully before resetting */
6331 schedule_work(&bp->reset_task);
6332}
6333
6334#ifdef BCM_VLAN
6335/* Called with rtnl_lock */
6336static void
6337bnx2_vlan_rx_register(struct net_device *dev, struct vlan_group *vlgrp)
6338{
Michael Chan972ec0d2006-01-23 16:12:43 -08006339 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006340
Michael Chan37675462009-08-21 16:20:44 +00006341 if (netif_running(dev))
6342 bnx2_netif_stop(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07006343
6344 bp->vlgrp = vlgrp;
Michael Chan37675462009-08-21 16:20:44 +00006345
6346 if (!netif_running(dev))
6347 return;
6348
Michael Chanb6016b72005-05-26 13:03:09 -07006349 bnx2_set_rx_mode(dev);
Michael Chan7c62e832008-07-14 22:39:03 -07006350 if (bp->flags & BNX2_FLAG_CAN_KEEP_VLAN)
6351 bnx2_fw_sync(bp, BNX2_DRV_MSG_CODE_KEEP_VLAN_UPDATE, 0, 1);
Michael Chanb6016b72005-05-26 13:03:09 -07006352
6353 bnx2_netif_start(bp);
6354}
Michael Chanb6016b72005-05-26 13:03:09 -07006355#endif
6356
Herbert Xu932ff272006-06-09 12:20:56 -07006357/* Called with netif_tx_lock.
Michael Chan2f8af122006-08-15 01:39:10 -07006358 * bnx2_tx_int() runs without netif_tx_lock unless it needs to call
6359 * netif_wake_queue().
Michael Chanb6016b72005-05-26 13:03:09 -07006360 */
Stephen Hemminger613573252009-08-31 19:50:58 +00006361static netdev_tx_t
Michael Chanb6016b72005-05-26 13:03:09 -07006362bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev)
6363{
Michael Chan972ec0d2006-01-23 16:12:43 -08006364 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006365 dma_addr_t mapping;
6366 struct tx_bd *txbd;
Benjamin Li3d16af82008-10-09 12:26:41 -07006367 struct sw_tx_bd *tx_buf;
Michael Chanb6016b72005-05-26 13:03:09 -07006368 u32 len, vlan_tag_flags, last_frag, mss;
6369 u16 prod, ring_prod;
6370 int i;
Benjamin Li706bf242008-07-18 17:55:11 -07006371 struct bnx2_napi *bnapi;
6372 struct bnx2_tx_ring_info *txr;
6373 struct netdev_queue *txq;
6374
6375 /* Determine which tx ring we will be placed on */
6376 i = skb_get_queue_mapping(skb);
6377 bnapi = &bp->bnx2_napi[i];
6378 txr = &bnapi->tx_ring;
6379 txq = netdev_get_tx_queue(dev, i);
Michael Chanb6016b72005-05-26 13:03:09 -07006380
Michael Chan35e90102008-06-19 16:37:42 -07006381 if (unlikely(bnx2_tx_avail(bp, txr) <
Michael Chana550c992007-12-20 19:56:59 -08006382 (skb_shinfo(skb)->nr_frags + 1))) {
Benjamin Li706bf242008-07-18 17:55:11 -07006383 netif_tx_stop_queue(txq);
Michael Chanb6016b72005-05-26 13:03:09 -07006384 printk(KERN_ERR PFX "%s: BUG! Tx ring full when queue awake!\n",
6385 dev->name);
6386
6387 return NETDEV_TX_BUSY;
6388 }
6389 len = skb_headlen(skb);
Michael Chan35e90102008-06-19 16:37:42 -07006390 prod = txr->tx_prod;
Michael Chanb6016b72005-05-26 13:03:09 -07006391 ring_prod = TX_RING_IDX(prod);
6392
6393 vlan_tag_flags = 0;
Patrick McHardy84fa7932006-08-29 16:44:56 -07006394 if (skb->ip_summed == CHECKSUM_PARTIAL) {
Michael Chanb6016b72005-05-26 13:03:09 -07006395 vlan_tag_flags |= TX_BD_FLAGS_TCP_UDP_CKSUM;
6396 }
6397
Michael Chan729b85c2008-08-14 15:29:39 -07006398#ifdef BCM_VLAN
Al Viro79ea13c2008-01-24 02:06:46 -08006399 if (bp->vlgrp && vlan_tx_tag_present(skb)) {
Michael Chanb6016b72005-05-26 13:03:09 -07006400 vlan_tag_flags |=
6401 (TX_BD_FLAGS_VLAN_TAG | (vlan_tx_tag_get(skb) << 16));
6402 }
Michael Chan729b85c2008-08-14 15:29:39 -07006403#endif
Michael Chanfde82052007-05-03 17:23:35 -07006404 if ((mss = skb_shinfo(skb)->gso_size)) {
Michael Chana1efb4b2008-10-09 12:24:39 -07006405 u32 tcp_opt_len;
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -07006406 struct iphdr *iph;
Michael Chanb6016b72005-05-26 13:03:09 -07006407
Michael Chanb6016b72005-05-26 13:03:09 -07006408 vlan_tag_flags |= TX_BD_FLAGS_SW_LSO;
6409
Michael Chan4666f872007-05-03 13:22:28 -07006410 tcp_opt_len = tcp_optlen(skb);
Arnaldo Carvalho de Meloab6a5bb2007-03-18 17:43:48 -07006411
Michael Chan4666f872007-05-03 13:22:28 -07006412 if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6) {
6413 u32 tcp_off = skb_transport_offset(skb) -
6414 sizeof(struct ipv6hdr) - ETH_HLEN;
Michael Chanb6016b72005-05-26 13:03:09 -07006415
Michael Chan4666f872007-05-03 13:22:28 -07006416 vlan_tag_flags |= ((tcp_opt_len >> 2) << 8) |
6417 TX_BD_FLAGS_SW_FLAGS;
6418 if (likely(tcp_off == 0))
6419 vlan_tag_flags &= ~TX_BD_FLAGS_TCP6_OFF0_MSK;
6420 else {
6421 tcp_off >>= 3;
6422 vlan_tag_flags |= ((tcp_off & 0x3) <<
6423 TX_BD_FLAGS_TCP6_OFF0_SHL) |
6424 ((tcp_off & 0x10) <<
6425 TX_BD_FLAGS_TCP6_OFF4_SHL);
6426 mss |= (tcp_off & 0xc) << TX_BD_TCP6_OFF2_SHL;
6427 }
6428 } else {
Michael Chan4666f872007-05-03 13:22:28 -07006429 iph = ip_hdr(skb);
Michael Chan4666f872007-05-03 13:22:28 -07006430 if (tcp_opt_len || (iph->ihl > 5)) {
6431 vlan_tag_flags |= ((iph->ihl - 5) +
6432 (tcp_opt_len >> 2)) << 8;
6433 }
Michael Chanb6016b72005-05-26 13:03:09 -07006434 }
Michael Chan4666f872007-05-03 13:22:28 -07006435 } else
Michael Chanb6016b72005-05-26 13:03:09 -07006436 mss = 0;
Michael Chanb6016b72005-05-26 13:03:09 -07006437
Alexander Duycke95524a2009-12-02 16:47:57 +00006438 mapping = pci_map_single(bp->pdev, skb->data, len, PCI_DMA_TODEVICE);
6439 if (pci_dma_mapping_error(bp->pdev, mapping)) {
Benjamin Li3d16af82008-10-09 12:26:41 -07006440 dev_kfree_skb(skb);
6441 return NETDEV_TX_OK;
6442 }
6443
Michael Chan35e90102008-06-19 16:37:42 -07006444 tx_buf = &txr->tx_buf_ring[ring_prod];
Michael Chanb6016b72005-05-26 13:03:09 -07006445 tx_buf->skb = skb;
Alexander Duycke95524a2009-12-02 16:47:57 +00006446 pci_unmap_addr_set(tx_buf, mapping, mapping);
Michael Chanb6016b72005-05-26 13:03:09 -07006447
Michael Chan35e90102008-06-19 16:37:42 -07006448 txbd = &txr->tx_desc_ring[ring_prod];
Michael Chanb6016b72005-05-26 13:03:09 -07006449
6450 txbd->tx_bd_haddr_hi = (u64) mapping >> 32;
6451 txbd->tx_bd_haddr_lo = (u64) mapping & 0xffffffff;
6452 txbd->tx_bd_mss_nbytes = len | (mss << 16);
6453 txbd->tx_bd_vlan_tag_flags = vlan_tag_flags | TX_BD_FLAGS_START;
6454
6455 last_frag = skb_shinfo(skb)->nr_frags;
Eric Dumazetd62fda02009-05-12 20:48:02 +00006456 tx_buf->nr_frags = last_frag;
6457 tx_buf->is_gso = skb_is_gso(skb);
Michael Chanb6016b72005-05-26 13:03:09 -07006458
6459 for (i = 0; i < last_frag; i++) {
6460 skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
6461
6462 prod = NEXT_TX_BD(prod);
6463 ring_prod = TX_RING_IDX(prod);
Michael Chan35e90102008-06-19 16:37:42 -07006464 txbd = &txr->tx_desc_ring[ring_prod];
Michael Chanb6016b72005-05-26 13:03:09 -07006465
6466 len = frag->size;
Alexander Duycke95524a2009-12-02 16:47:57 +00006467 mapping = pci_map_page(bp->pdev, frag->page, frag->page_offset,
6468 len, PCI_DMA_TODEVICE);
6469 if (pci_dma_mapping_error(bp->pdev, mapping))
6470 goto dma_error;
6471 pci_unmap_addr_set(&txr->tx_buf_ring[ring_prod], mapping,
6472 mapping);
Michael Chanb6016b72005-05-26 13:03:09 -07006473
6474 txbd->tx_bd_haddr_hi = (u64) mapping >> 32;
6475 txbd->tx_bd_haddr_lo = (u64) mapping & 0xffffffff;
6476 txbd->tx_bd_mss_nbytes = len | (mss << 16);
6477 txbd->tx_bd_vlan_tag_flags = vlan_tag_flags;
6478
6479 }
6480 txbd->tx_bd_vlan_tag_flags |= TX_BD_FLAGS_END;
6481
6482 prod = NEXT_TX_BD(prod);
Michael Chan35e90102008-06-19 16:37:42 -07006483 txr->tx_prod_bseq += skb->len;
Michael Chanb6016b72005-05-26 13:03:09 -07006484
Michael Chan35e90102008-06-19 16:37:42 -07006485 REG_WR16(bp, txr->tx_bidx_addr, prod);
6486 REG_WR(bp, txr->tx_bseq_addr, txr->tx_prod_bseq);
Michael Chanb6016b72005-05-26 13:03:09 -07006487
6488 mmiowb();
6489
Michael Chan35e90102008-06-19 16:37:42 -07006490 txr->tx_prod = prod;
Michael Chanb6016b72005-05-26 13:03:09 -07006491
Michael Chan35e90102008-06-19 16:37:42 -07006492 if (unlikely(bnx2_tx_avail(bp, txr) <= MAX_SKB_FRAGS)) {
Benjamin Li706bf242008-07-18 17:55:11 -07006493 netif_tx_stop_queue(txq);
Michael Chan35e90102008-06-19 16:37:42 -07006494 if (bnx2_tx_avail(bp, txr) > bp->tx_wake_thresh)
Benjamin Li706bf242008-07-18 17:55:11 -07006495 netif_tx_wake_queue(txq);
Michael Chanb6016b72005-05-26 13:03:09 -07006496 }
6497
6498 return NETDEV_TX_OK;
Alexander Duycke95524a2009-12-02 16:47:57 +00006499dma_error:
6500 /* save value of frag that failed */
6501 last_frag = i;
6502
6503 /* start back at beginning and unmap skb */
6504 prod = txr->tx_prod;
6505 ring_prod = TX_RING_IDX(prod);
6506 tx_buf = &txr->tx_buf_ring[ring_prod];
6507 tx_buf->skb = NULL;
6508 pci_unmap_single(bp->pdev, pci_unmap_addr(tx_buf, mapping),
6509 skb_headlen(skb), PCI_DMA_TODEVICE);
6510
6511 /* unmap remaining mapped pages */
6512 for (i = 0; i < last_frag; i++) {
6513 prod = NEXT_TX_BD(prod);
6514 ring_prod = TX_RING_IDX(prod);
6515 tx_buf = &txr->tx_buf_ring[ring_prod];
6516 pci_unmap_page(bp->pdev, pci_unmap_addr(tx_buf, mapping),
6517 skb_shinfo(skb)->frags[i].size,
6518 PCI_DMA_TODEVICE);
6519 }
6520
6521 dev_kfree_skb(skb);
6522 return NETDEV_TX_OK;
Michael Chanb6016b72005-05-26 13:03:09 -07006523}
6524
6525/* Called with rtnl_lock */
6526static int
6527bnx2_close(struct net_device *dev)
6528{
Michael Chan972ec0d2006-01-23 16:12:43 -08006529 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006530
David S. Miller4bb073c2008-06-12 02:22:02 -07006531 cancel_work_sync(&bp->reset_task);
Michael Chanafdc08b2005-08-25 15:34:29 -07006532
Stephen Hemmingerbea33482007-10-03 16:41:36 -07006533 bnx2_disable_int_sync(bp);
Michael Chan35efa7c2007-12-20 19:56:37 -08006534 bnx2_napi_disable(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07006535 del_timer_sync(&bp->timer);
Michael Chan74bf4ba2008-10-09 12:21:08 -07006536 bnx2_shutdown_chip(bp);
Michael Chan8e6a72c2007-05-03 13:24:48 -07006537 bnx2_free_irq(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07006538 bnx2_free_skbs(bp);
6539 bnx2_free_mem(bp);
6540 bp->link_up = 0;
6541 netif_carrier_off(bp->dev);
Pavel Machek829ca9a2005-09-03 15:56:56 -07006542 bnx2_set_power_state(bp, PCI_D3hot);
Michael Chanb6016b72005-05-26 13:03:09 -07006543 return 0;
6544}
6545
Michael Chan354fcd72010-01-17 07:30:44 +00006546static void
6547bnx2_save_stats(struct bnx2 *bp)
6548{
6549 u32 *hw_stats = (u32 *) bp->stats_blk;
6550 u32 *temp_stats = (u32 *) bp->temp_stats_blk;
6551 int i;
6552
6553 /* The 1st 10 counters are 64-bit counters */
6554 for (i = 0; i < 20; i += 2) {
6555 u32 hi;
6556 u64 lo;
6557
Patrick Rabauc9885fe2010-02-15 19:42:11 +00006558 hi = temp_stats[i] + hw_stats[i];
6559 lo = (u64) temp_stats[i + 1] + (u64) hw_stats[i + 1];
Michael Chan354fcd72010-01-17 07:30:44 +00006560 if (lo > 0xffffffff)
6561 hi++;
Patrick Rabauc9885fe2010-02-15 19:42:11 +00006562 temp_stats[i] = hi;
6563 temp_stats[i + 1] = lo & 0xffffffff;
Michael Chan354fcd72010-01-17 07:30:44 +00006564 }
6565
6566 for ( ; i < sizeof(struct statistics_block) / 4; i++)
Patrick Rabauc9885fe2010-02-15 19:42:11 +00006567 temp_stats[i] += hw_stats[i];
Michael Chan354fcd72010-01-17 07:30:44 +00006568}
6569
Michael Chana4743052010-01-17 07:30:43 +00006570#define GET_64BIT_NET_STATS64(ctr) \
Michael Chanb6016b72005-05-26 13:03:09 -07006571 (unsigned long) ((unsigned long) (ctr##_hi) << 32) + \
6572 (unsigned long) (ctr##_lo)
6573
Michael Chana4743052010-01-17 07:30:43 +00006574#define GET_64BIT_NET_STATS32(ctr) \
Michael Chanb6016b72005-05-26 13:03:09 -07006575 (ctr##_lo)
6576
6577#if (BITS_PER_LONG == 64)
Michael Chana4743052010-01-17 07:30:43 +00006578#define GET_64BIT_NET_STATS(ctr) \
Michael Chan354fcd72010-01-17 07:30:44 +00006579 GET_64BIT_NET_STATS64(bp->stats_blk->ctr) + \
6580 GET_64BIT_NET_STATS64(bp->temp_stats_blk->ctr)
Michael Chanb6016b72005-05-26 13:03:09 -07006581#else
Michael Chana4743052010-01-17 07:30:43 +00006582#define GET_64BIT_NET_STATS(ctr) \
Michael Chan354fcd72010-01-17 07:30:44 +00006583 GET_64BIT_NET_STATS32(bp->stats_blk->ctr) + \
6584 GET_64BIT_NET_STATS32(bp->temp_stats_blk->ctr)
Michael Chanb6016b72005-05-26 13:03:09 -07006585#endif
6586
Michael Chana4743052010-01-17 07:30:43 +00006587#define GET_32BIT_NET_STATS(ctr) \
Michael Chan354fcd72010-01-17 07:30:44 +00006588 (unsigned long) (bp->stats_blk->ctr + \
6589 bp->temp_stats_blk->ctr)
Michael Chana4743052010-01-17 07:30:43 +00006590
Michael Chanb6016b72005-05-26 13:03:09 -07006591static struct net_device_stats *
6592bnx2_get_stats(struct net_device *dev)
6593{
Michael Chan972ec0d2006-01-23 16:12:43 -08006594 struct bnx2 *bp = netdev_priv(dev);
Ilpo Järvinend8e80342008-11-28 15:52:43 -08006595 struct net_device_stats *net_stats = &dev->stats;
Michael Chanb6016b72005-05-26 13:03:09 -07006596
6597 if (bp->stats_blk == NULL) {
6598 return net_stats;
6599 }
6600 net_stats->rx_packets =
Michael Chana4743052010-01-17 07:30:43 +00006601 GET_64BIT_NET_STATS(stat_IfHCInUcastPkts) +
6602 GET_64BIT_NET_STATS(stat_IfHCInMulticastPkts) +
6603 GET_64BIT_NET_STATS(stat_IfHCInBroadcastPkts);
Michael Chanb6016b72005-05-26 13:03:09 -07006604
6605 net_stats->tx_packets =
Michael Chana4743052010-01-17 07:30:43 +00006606 GET_64BIT_NET_STATS(stat_IfHCOutUcastPkts) +
6607 GET_64BIT_NET_STATS(stat_IfHCOutMulticastPkts) +
6608 GET_64BIT_NET_STATS(stat_IfHCOutBroadcastPkts);
Michael Chanb6016b72005-05-26 13:03:09 -07006609
6610 net_stats->rx_bytes =
Michael Chana4743052010-01-17 07:30:43 +00006611 GET_64BIT_NET_STATS(stat_IfHCInOctets);
Michael Chanb6016b72005-05-26 13:03:09 -07006612
6613 net_stats->tx_bytes =
Michael Chana4743052010-01-17 07:30:43 +00006614 GET_64BIT_NET_STATS(stat_IfHCOutOctets);
Michael Chanb6016b72005-05-26 13:03:09 -07006615
Jeff Garzik6aa20a22006-09-13 13:24:59 -04006616 net_stats->multicast =
Michael Chana4743052010-01-17 07:30:43 +00006617 GET_64BIT_NET_STATS(stat_IfHCOutMulticastPkts);
Michael Chanb6016b72005-05-26 13:03:09 -07006618
Jeff Garzik6aa20a22006-09-13 13:24:59 -04006619 net_stats->collisions =
Michael Chana4743052010-01-17 07:30:43 +00006620 GET_32BIT_NET_STATS(stat_EtherStatsCollisions);
Michael Chanb6016b72005-05-26 13:03:09 -07006621
Jeff Garzik6aa20a22006-09-13 13:24:59 -04006622 net_stats->rx_length_errors =
Michael Chana4743052010-01-17 07:30:43 +00006623 GET_32BIT_NET_STATS(stat_EtherStatsUndersizePkts) +
6624 GET_32BIT_NET_STATS(stat_EtherStatsOverrsizePkts);
Michael Chanb6016b72005-05-26 13:03:09 -07006625
Jeff Garzik6aa20a22006-09-13 13:24:59 -04006626 net_stats->rx_over_errors =
Michael Chana4743052010-01-17 07:30:43 +00006627 GET_32BIT_NET_STATS(stat_IfInFTQDiscards) +
6628 GET_32BIT_NET_STATS(stat_IfInMBUFDiscards);
Michael Chanb6016b72005-05-26 13:03:09 -07006629
Jeff Garzik6aa20a22006-09-13 13:24:59 -04006630 net_stats->rx_frame_errors =
Michael Chana4743052010-01-17 07:30:43 +00006631 GET_32BIT_NET_STATS(stat_Dot3StatsAlignmentErrors);
Michael Chanb6016b72005-05-26 13:03:09 -07006632
Jeff Garzik6aa20a22006-09-13 13:24:59 -04006633 net_stats->rx_crc_errors =
Michael Chana4743052010-01-17 07:30:43 +00006634 GET_32BIT_NET_STATS(stat_Dot3StatsFCSErrors);
Michael Chanb6016b72005-05-26 13:03:09 -07006635
6636 net_stats->rx_errors = net_stats->rx_length_errors +
6637 net_stats->rx_over_errors + net_stats->rx_frame_errors +
6638 net_stats->rx_crc_errors;
6639
6640 net_stats->tx_aborted_errors =
Michael Chana4743052010-01-17 07:30:43 +00006641 GET_32BIT_NET_STATS(stat_Dot3StatsExcessiveCollisions) +
6642 GET_32BIT_NET_STATS(stat_Dot3StatsLateCollisions);
Michael Chanb6016b72005-05-26 13:03:09 -07006643
Michael Chan5b0c76a2005-11-04 08:45:49 -08006644 if ((CHIP_NUM(bp) == CHIP_NUM_5706) ||
6645 (CHIP_ID(bp) == CHIP_ID_5708_A0))
Michael Chanb6016b72005-05-26 13:03:09 -07006646 net_stats->tx_carrier_errors = 0;
6647 else {
6648 net_stats->tx_carrier_errors =
Michael Chana4743052010-01-17 07:30:43 +00006649 GET_32BIT_NET_STATS(stat_Dot3StatsCarrierSenseErrors);
Michael Chanb6016b72005-05-26 13:03:09 -07006650 }
6651
6652 net_stats->tx_errors =
Michael Chana4743052010-01-17 07:30:43 +00006653 GET_32BIT_NET_STATS(stat_emac_tx_stat_dot3statsinternalmactransmiterrors) +
Michael Chanb6016b72005-05-26 13:03:09 -07006654 net_stats->tx_aborted_errors +
6655 net_stats->tx_carrier_errors;
6656
Michael Chancea94db2006-06-12 22:16:13 -07006657 net_stats->rx_missed_errors =
Michael Chana4743052010-01-17 07:30:43 +00006658 GET_32BIT_NET_STATS(stat_IfInFTQDiscards) +
6659 GET_32BIT_NET_STATS(stat_IfInMBUFDiscards) +
6660 GET_32BIT_NET_STATS(stat_FwRxDrop);
Michael Chancea94db2006-06-12 22:16:13 -07006661
Michael Chanb6016b72005-05-26 13:03:09 -07006662 return net_stats;
6663}
6664
6665/* All ethtool functions called with rtnl_lock */
6666
6667static int
6668bnx2_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
6669{
Michael Chan972ec0d2006-01-23 16:12:43 -08006670 struct bnx2 *bp = netdev_priv(dev);
Michael Chan7b6b8342007-07-07 22:50:15 -07006671 int support_serdes = 0, support_copper = 0;
Michael Chanb6016b72005-05-26 13:03:09 -07006672
6673 cmd->supported = SUPPORTED_Autoneg;
Michael Chan583c28e2008-01-21 19:51:35 -08006674 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP) {
Michael Chan7b6b8342007-07-07 22:50:15 -07006675 support_serdes = 1;
6676 support_copper = 1;
6677 } else if (bp->phy_port == PORT_FIBRE)
6678 support_serdes = 1;
6679 else
6680 support_copper = 1;
6681
6682 if (support_serdes) {
Michael Chanb6016b72005-05-26 13:03:09 -07006683 cmd->supported |= SUPPORTED_1000baseT_Full |
6684 SUPPORTED_FIBRE;
Michael Chan583c28e2008-01-21 19:51:35 -08006685 if (bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE)
Michael Chan605a9e22007-05-03 13:23:13 -07006686 cmd->supported |= SUPPORTED_2500baseX_Full;
Michael Chanb6016b72005-05-26 13:03:09 -07006687
Michael Chanb6016b72005-05-26 13:03:09 -07006688 }
Michael Chan7b6b8342007-07-07 22:50:15 -07006689 if (support_copper) {
Michael Chanb6016b72005-05-26 13:03:09 -07006690 cmd->supported |= SUPPORTED_10baseT_Half |
6691 SUPPORTED_10baseT_Full |
6692 SUPPORTED_100baseT_Half |
6693 SUPPORTED_100baseT_Full |
6694 SUPPORTED_1000baseT_Full |
6695 SUPPORTED_TP;
6696
Michael Chanb6016b72005-05-26 13:03:09 -07006697 }
6698
Michael Chan7b6b8342007-07-07 22:50:15 -07006699 spin_lock_bh(&bp->phy_lock);
6700 cmd->port = bp->phy_port;
Michael Chanb6016b72005-05-26 13:03:09 -07006701 cmd->advertising = bp->advertising;
6702
6703 if (bp->autoneg & AUTONEG_SPEED) {
6704 cmd->autoneg = AUTONEG_ENABLE;
6705 }
6706 else {
6707 cmd->autoneg = AUTONEG_DISABLE;
6708 }
6709
6710 if (netif_carrier_ok(dev)) {
6711 cmd->speed = bp->line_speed;
6712 cmd->duplex = bp->duplex;
6713 }
6714 else {
6715 cmd->speed = -1;
6716 cmd->duplex = -1;
6717 }
Michael Chan7b6b8342007-07-07 22:50:15 -07006718 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07006719
6720 cmd->transceiver = XCVR_INTERNAL;
6721 cmd->phy_address = bp->phy_addr;
6722
6723 return 0;
6724}
Jeff Garzik6aa20a22006-09-13 13:24:59 -04006725
Michael Chanb6016b72005-05-26 13:03:09 -07006726static int
6727bnx2_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
6728{
Michael Chan972ec0d2006-01-23 16:12:43 -08006729 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006730 u8 autoneg = bp->autoneg;
6731 u8 req_duplex = bp->req_duplex;
6732 u16 req_line_speed = bp->req_line_speed;
6733 u32 advertising = bp->advertising;
Michael Chan7b6b8342007-07-07 22:50:15 -07006734 int err = -EINVAL;
6735
6736 spin_lock_bh(&bp->phy_lock);
6737
6738 if (cmd->port != PORT_TP && cmd->port != PORT_FIBRE)
6739 goto err_out_unlock;
6740
Michael Chan583c28e2008-01-21 19:51:35 -08006741 if (cmd->port != bp->phy_port &&
6742 !(bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP))
Michael Chan7b6b8342007-07-07 22:50:15 -07006743 goto err_out_unlock;
Michael Chanb6016b72005-05-26 13:03:09 -07006744
Michael Chand6b14482008-07-14 22:37:21 -07006745 /* If device is down, we can store the settings only if the user
6746 * is setting the currently active port.
6747 */
6748 if (!netif_running(dev) && cmd->port != bp->phy_port)
6749 goto err_out_unlock;
6750
Michael Chanb6016b72005-05-26 13:03:09 -07006751 if (cmd->autoneg == AUTONEG_ENABLE) {
6752 autoneg |= AUTONEG_SPEED;
6753
Michael Chanbeb499a2010-02-15 19:42:10 +00006754 advertising = cmd->advertising;
6755 if (cmd->port == PORT_TP) {
6756 advertising &= ETHTOOL_ALL_COPPER_SPEED;
6757 if (!advertising)
Michael Chanb6016b72005-05-26 13:03:09 -07006758 advertising = ETHTOOL_ALL_COPPER_SPEED;
Michael Chanbeb499a2010-02-15 19:42:10 +00006759 } else {
6760 advertising &= ETHTOOL_ALL_FIBRE_SPEED;
6761 if (!advertising)
6762 advertising = ETHTOOL_ALL_FIBRE_SPEED;
Michael Chanb6016b72005-05-26 13:03:09 -07006763 }
6764 advertising |= ADVERTISED_Autoneg;
6765 }
6766 else {
Michael Chan7b6b8342007-07-07 22:50:15 -07006767 if (cmd->port == PORT_FIBRE) {
Michael Chan80be4432006-11-19 14:07:28 -08006768 if ((cmd->speed != SPEED_1000 &&
6769 cmd->speed != SPEED_2500) ||
6770 (cmd->duplex != DUPLEX_FULL))
Michael Chan7b6b8342007-07-07 22:50:15 -07006771 goto err_out_unlock;
Michael Chan80be4432006-11-19 14:07:28 -08006772
6773 if (cmd->speed == SPEED_2500 &&
Michael Chan583c28e2008-01-21 19:51:35 -08006774 !(bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE))
Michael Chan7b6b8342007-07-07 22:50:15 -07006775 goto err_out_unlock;
Michael Chanb6016b72005-05-26 13:03:09 -07006776 }
Michael Chan7b6b8342007-07-07 22:50:15 -07006777 else if (cmd->speed == SPEED_1000 || cmd->speed == SPEED_2500)
6778 goto err_out_unlock;
6779
Michael Chanb6016b72005-05-26 13:03:09 -07006780 autoneg &= ~AUTONEG_SPEED;
6781 req_line_speed = cmd->speed;
6782 req_duplex = cmd->duplex;
6783 advertising = 0;
6784 }
6785
6786 bp->autoneg = autoneg;
6787 bp->advertising = advertising;
6788 bp->req_line_speed = req_line_speed;
6789 bp->req_duplex = req_duplex;
6790
Michael Chand6b14482008-07-14 22:37:21 -07006791 err = 0;
6792 /* If device is down, the new settings will be picked up when it is
6793 * brought up.
6794 */
6795 if (netif_running(dev))
6796 err = bnx2_setup_phy(bp, cmd->port);
Michael Chanb6016b72005-05-26 13:03:09 -07006797
Michael Chan7b6b8342007-07-07 22:50:15 -07006798err_out_unlock:
Michael Chanc770a652005-08-25 15:38:39 -07006799 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07006800
Michael Chan7b6b8342007-07-07 22:50:15 -07006801 return err;
Michael Chanb6016b72005-05-26 13:03:09 -07006802}
6803
6804static void
6805bnx2_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
6806{
Michael Chan972ec0d2006-01-23 16:12:43 -08006807 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006808
6809 strcpy(info->driver, DRV_MODULE_NAME);
6810 strcpy(info->version, DRV_MODULE_VERSION);
6811 strcpy(info->bus_info, pci_name(bp->pdev));
Michael Chan58fc2ea2007-07-07 22:52:02 -07006812 strcpy(info->fw_version, bp->fw_version);
Michael Chanb6016b72005-05-26 13:03:09 -07006813}
6814
Michael Chan244ac4f2006-03-20 17:48:46 -08006815#define BNX2_REGDUMP_LEN (32 * 1024)
6816
6817static int
6818bnx2_get_regs_len(struct net_device *dev)
6819{
6820 return BNX2_REGDUMP_LEN;
6821}
6822
6823static void
6824bnx2_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *_p)
6825{
6826 u32 *p = _p, i, offset;
6827 u8 *orig_p = _p;
6828 struct bnx2 *bp = netdev_priv(dev);
6829 u32 reg_boundaries[] = { 0x0000, 0x0098, 0x0400, 0x045c,
6830 0x0800, 0x0880, 0x0c00, 0x0c10,
6831 0x0c30, 0x0d08, 0x1000, 0x101c,
6832 0x1040, 0x1048, 0x1080, 0x10a4,
6833 0x1400, 0x1490, 0x1498, 0x14f0,
6834 0x1500, 0x155c, 0x1580, 0x15dc,
6835 0x1600, 0x1658, 0x1680, 0x16d8,
6836 0x1800, 0x1820, 0x1840, 0x1854,
6837 0x1880, 0x1894, 0x1900, 0x1984,
6838 0x1c00, 0x1c0c, 0x1c40, 0x1c54,
6839 0x1c80, 0x1c94, 0x1d00, 0x1d84,
6840 0x2000, 0x2030, 0x23c0, 0x2400,
6841 0x2800, 0x2820, 0x2830, 0x2850,
6842 0x2b40, 0x2c10, 0x2fc0, 0x3058,
6843 0x3c00, 0x3c94, 0x4000, 0x4010,
6844 0x4080, 0x4090, 0x43c0, 0x4458,
6845 0x4c00, 0x4c18, 0x4c40, 0x4c54,
6846 0x4fc0, 0x5010, 0x53c0, 0x5444,
6847 0x5c00, 0x5c18, 0x5c80, 0x5c90,
6848 0x5fc0, 0x6000, 0x6400, 0x6428,
6849 0x6800, 0x6848, 0x684c, 0x6860,
6850 0x6888, 0x6910, 0x8000 };
6851
6852 regs->version = 0;
6853
6854 memset(p, 0, BNX2_REGDUMP_LEN);
6855
6856 if (!netif_running(bp->dev))
6857 return;
6858
6859 i = 0;
6860 offset = reg_boundaries[0];
6861 p += offset;
6862 while (offset < BNX2_REGDUMP_LEN) {
6863 *p++ = REG_RD(bp, offset);
6864 offset += 4;
6865 if (offset == reg_boundaries[i + 1]) {
6866 offset = reg_boundaries[i + 2];
6867 p = (u32 *) (orig_p + offset);
6868 i += 2;
6869 }
6870 }
6871}
6872
Michael Chanb6016b72005-05-26 13:03:09 -07006873static void
6874bnx2_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
6875{
Michael Chan972ec0d2006-01-23 16:12:43 -08006876 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006877
David S. Millerf86e82f2008-01-21 17:15:40 -08006878 if (bp->flags & BNX2_FLAG_NO_WOL) {
Michael Chanb6016b72005-05-26 13:03:09 -07006879 wol->supported = 0;
6880 wol->wolopts = 0;
6881 }
6882 else {
6883 wol->supported = WAKE_MAGIC;
6884 if (bp->wol)
6885 wol->wolopts = WAKE_MAGIC;
6886 else
6887 wol->wolopts = 0;
6888 }
6889 memset(&wol->sopass, 0, sizeof(wol->sopass));
6890}
6891
6892static int
6893bnx2_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
6894{
Michael Chan972ec0d2006-01-23 16:12:43 -08006895 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006896
6897 if (wol->wolopts & ~WAKE_MAGIC)
6898 return -EINVAL;
6899
6900 if (wol->wolopts & WAKE_MAGIC) {
David S. Millerf86e82f2008-01-21 17:15:40 -08006901 if (bp->flags & BNX2_FLAG_NO_WOL)
Michael Chanb6016b72005-05-26 13:03:09 -07006902 return -EINVAL;
6903
6904 bp->wol = 1;
6905 }
6906 else {
6907 bp->wol = 0;
6908 }
6909 return 0;
6910}
6911
6912static int
6913bnx2_nway_reset(struct net_device *dev)
6914{
Michael Chan972ec0d2006-01-23 16:12:43 -08006915 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006916 u32 bmcr;
6917
Michael Chan9f52b562008-10-09 12:21:46 -07006918 if (!netif_running(dev))
6919 return -EAGAIN;
6920
Michael Chanb6016b72005-05-26 13:03:09 -07006921 if (!(bp->autoneg & AUTONEG_SPEED)) {
6922 return -EINVAL;
6923 }
6924
Michael Chanc770a652005-08-25 15:38:39 -07006925 spin_lock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07006926
Michael Chan583c28e2008-01-21 19:51:35 -08006927 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP) {
Michael Chan7b6b8342007-07-07 22:50:15 -07006928 int rc;
6929
6930 rc = bnx2_setup_remote_phy(bp, bp->phy_port);
6931 spin_unlock_bh(&bp->phy_lock);
6932 return rc;
6933 }
6934
Michael Chanb6016b72005-05-26 13:03:09 -07006935 /* Force a link down visible on the other side */
Michael Chan583c28e2008-01-21 19:51:35 -08006936 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Michael Chanca58c3a2007-05-03 13:22:52 -07006937 bnx2_write_phy(bp, bp->mii_bmcr, BMCR_LOOPBACK);
Michael Chanc770a652005-08-25 15:38:39 -07006938 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07006939
6940 msleep(20);
6941
Michael Chanc770a652005-08-25 15:38:39 -07006942 spin_lock_bh(&bp->phy_lock);
Michael Chanf8dd0642006-11-19 14:08:29 -08006943
Michael Chan40105c02008-11-12 16:02:45 -08006944 bp->current_interval = BNX2_SERDES_AN_TIMEOUT;
Michael Chanf8dd0642006-11-19 14:08:29 -08006945 bp->serdes_an_pending = 1;
6946 mod_timer(&bp->timer, jiffies + bp->current_interval);
Michael Chanb6016b72005-05-26 13:03:09 -07006947 }
6948
Michael Chanca58c3a2007-05-03 13:22:52 -07006949 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chanb6016b72005-05-26 13:03:09 -07006950 bmcr &= ~BMCR_LOOPBACK;
Michael Chanca58c3a2007-05-03 13:22:52 -07006951 bnx2_write_phy(bp, bp->mii_bmcr, bmcr | BMCR_ANRESTART | BMCR_ANENABLE);
Michael Chanb6016b72005-05-26 13:03:09 -07006952
Michael Chanc770a652005-08-25 15:38:39 -07006953 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07006954
6955 return 0;
6956}
6957
Ooiwa Naohiro7959ea22009-06-24 00:19:06 -07006958static u32
6959bnx2_get_link(struct net_device *dev)
6960{
6961 struct bnx2 *bp = netdev_priv(dev);
6962
6963 return bp->link_up;
6964}
6965
Michael Chanb6016b72005-05-26 13:03:09 -07006966static int
6967bnx2_get_eeprom_len(struct net_device *dev)
6968{
Michael Chan972ec0d2006-01-23 16:12:43 -08006969 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006970
Michael Chan1122db72006-01-23 16:11:42 -08006971 if (bp->flash_info == NULL)
Michael Chanb6016b72005-05-26 13:03:09 -07006972 return 0;
6973
Michael Chan1122db72006-01-23 16:11:42 -08006974 return (int) bp->flash_size;
Michael Chanb6016b72005-05-26 13:03:09 -07006975}
6976
6977static int
6978bnx2_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
6979 u8 *eebuf)
6980{
Michael Chan972ec0d2006-01-23 16:12:43 -08006981 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006982 int rc;
6983
Michael Chan9f52b562008-10-09 12:21:46 -07006984 if (!netif_running(dev))
6985 return -EAGAIN;
6986
John W. Linville1064e942005-11-10 12:58:24 -08006987 /* parameters already validated in ethtool_get_eeprom */
Michael Chanb6016b72005-05-26 13:03:09 -07006988
6989 rc = bnx2_nvram_read(bp, eeprom->offset, eebuf, eeprom->len);
6990
6991 return rc;
6992}
6993
6994static int
6995bnx2_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
6996 u8 *eebuf)
6997{
Michael Chan972ec0d2006-01-23 16:12:43 -08006998 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006999 int rc;
7000
Michael Chan9f52b562008-10-09 12:21:46 -07007001 if (!netif_running(dev))
7002 return -EAGAIN;
7003
John W. Linville1064e942005-11-10 12:58:24 -08007004 /* parameters already validated in ethtool_set_eeprom */
Michael Chanb6016b72005-05-26 13:03:09 -07007005
7006 rc = bnx2_nvram_write(bp, eeprom->offset, eebuf, eeprom->len);
7007
7008 return rc;
7009}
7010
7011static int
7012bnx2_get_coalesce(struct net_device *dev, struct ethtool_coalesce *coal)
7013{
Michael Chan972ec0d2006-01-23 16:12:43 -08007014 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007015
7016 memset(coal, 0, sizeof(struct ethtool_coalesce));
7017
7018 coal->rx_coalesce_usecs = bp->rx_ticks;
7019 coal->rx_max_coalesced_frames = bp->rx_quick_cons_trip;
7020 coal->rx_coalesce_usecs_irq = bp->rx_ticks_int;
7021 coal->rx_max_coalesced_frames_irq = bp->rx_quick_cons_trip_int;
7022
7023 coal->tx_coalesce_usecs = bp->tx_ticks;
7024 coal->tx_max_coalesced_frames = bp->tx_quick_cons_trip;
7025 coal->tx_coalesce_usecs_irq = bp->tx_ticks_int;
7026 coal->tx_max_coalesced_frames_irq = bp->tx_quick_cons_trip_int;
7027
7028 coal->stats_block_coalesce_usecs = bp->stats_ticks;
7029
7030 return 0;
7031}
7032
7033static int
7034bnx2_set_coalesce(struct net_device *dev, struct ethtool_coalesce *coal)
7035{
Michael Chan972ec0d2006-01-23 16:12:43 -08007036 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007037
7038 bp->rx_ticks = (u16) coal->rx_coalesce_usecs;
7039 if (bp->rx_ticks > 0x3ff) bp->rx_ticks = 0x3ff;
7040
Jeff Garzik6aa20a22006-09-13 13:24:59 -04007041 bp->rx_quick_cons_trip = (u16) coal->rx_max_coalesced_frames;
Michael Chanb6016b72005-05-26 13:03:09 -07007042 if (bp->rx_quick_cons_trip > 0xff) bp->rx_quick_cons_trip = 0xff;
7043
7044 bp->rx_ticks_int = (u16) coal->rx_coalesce_usecs_irq;
7045 if (bp->rx_ticks_int > 0x3ff) bp->rx_ticks_int = 0x3ff;
7046
7047 bp->rx_quick_cons_trip_int = (u16) coal->rx_max_coalesced_frames_irq;
7048 if (bp->rx_quick_cons_trip_int > 0xff)
7049 bp->rx_quick_cons_trip_int = 0xff;
7050
7051 bp->tx_ticks = (u16) coal->tx_coalesce_usecs;
7052 if (bp->tx_ticks > 0x3ff) bp->tx_ticks = 0x3ff;
7053
7054 bp->tx_quick_cons_trip = (u16) coal->tx_max_coalesced_frames;
7055 if (bp->tx_quick_cons_trip > 0xff) bp->tx_quick_cons_trip = 0xff;
7056
7057 bp->tx_ticks_int = (u16) coal->tx_coalesce_usecs_irq;
7058 if (bp->tx_ticks_int > 0x3ff) bp->tx_ticks_int = 0x3ff;
7059
7060 bp->tx_quick_cons_trip_int = (u16) coal->tx_max_coalesced_frames_irq;
7061 if (bp->tx_quick_cons_trip_int > 0xff) bp->tx_quick_cons_trip_int =
7062 0xff;
7063
7064 bp->stats_ticks = coal->stats_block_coalesce_usecs;
Michael Chan61d9e3f2009-08-21 16:20:46 +00007065 if (bp->flags & BNX2_FLAG_BROKEN_STATS) {
Michael Chan02537b062007-06-04 21:24:07 -07007066 if (bp->stats_ticks != 0 && bp->stats_ticks != USEC_PER_SEC)
7067 bp->stats_ticks = USEC_PER_SEC;
7068 }
Michael Chan7ea69202007-07-16 18:27:10 -07007069 if (bp->stats_ticks > BNX2_HC_STATS_TICKS_HC_STAT_TICKS)
7070 bp->stats_ticks = BNX2_HC_STATS_TICKS_HC_STAT_TICKS;
7071 bp->stats_ticks &= BNX2_HC_STATS_TICKS_HC_STAT_TICKS;
Michael Chanb6016b72005-05-26 13:03:09 -07007072
7073 if (netif_running(bp->dev)) {
7074 bnx2_netif_stop(bp);
Michael Chan9a120bc2008-05-16 22:17:45 -07007075 bnx2_init_nic(bp, 0);
Michael Chanb6016b72005-05-26 13:03:09 -07007076 bnx2_netif_start(bp);
7077 }
7078
7079 return 0;
7080}
7081
7082static void
7083bnx2_get_ringparam(struct net_device *dev, struct ethtool_ringparam *ering)
7084{
Michael Chan972ec0d2006-01-23 16:12:43 -08007085 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007086
Michael Chan13daffa2006-03-20 17:49:20 -08007087 ering->rx_max_pending = MAX_TOTAL_RX_DESC_CNT;
Michael Chanb6016b72005-05-26 13:03:09 -07007088 ering->rx_mini_max_pending = 0;
Michael Chan47bf4242007-12-12 11:19:12 -08007089 ering->rx_jumbo_max_pending = MAX_TOTAL_RX_PG_DESC_CNT;
Michael Chanb6016b72005-05-26 13:03:09 -07007090
7091 ering->rx_pending = bp->rx_ring_size;
7092 ering->rx_mini_pending = 0;
Michael Chan47bf4242007-12-12 11:19:12 -08007093 ering->rx_jumbo_pending = bp->rx_pg_ring_size;
Michael Chanb6016b72005-05-26 13:03:09 -07007094
7095 ering->tx_max_pending = MAX_TX_DESC_CNT;
7096 ering->tx_pending = bp->tx_ring_size;
7097}
7098
7099static int
Michael Chan5d5d0012007-12-12 11:17:43 -08007100bnx2_change_ring_size(struct bnx2 *bp, u32 rx, u32 tx)
Michael Chanb6016b72005-05-26 13:03:09 -07007101{
Michael Chan13daffa2006-03-20 17:49:20 -08007102 if (netif_running(bp->dev)) {
Michael Chan354fcd72010-01-17 07:30:44 +00007103 /* Reset will erase chipset stats; save them */
7104 bnx2_save_stats(bp);
7105
Michael Chan13daffa2006-03-20 17:49:20 -08007106 bnx2_netif_stop(bp);
7107 bnx2_reset_chip(bp, BNX2_DRV_MSG_CODE_RESET);
7108 bnx2_free_skbs(bp);
7109 bnx2_free_mem(bp);
7110 }
7111
Michael Chan5d5d0012007-12-12 11:17:43 -08007112 bnx2_set_rx_ring_size(bp, rx);
7113 bp->tx_ring_size = tx;
Michael Chanb6016b72005-05-26 13:03:09 -07007114
7115 if (netif_running(bp->dev)) {
Michael Chan13daffa2006-03-20 17:49:20 -08007116 int rc;
7117
7118 rc = bnx2_alloc_mem(bp);
Michael Chan6fefb65e2009-08-21 16:20:45 +00007119 if (!rc)
7120 rc = bnx2_init_nic(bp, 0);
7121
7122 if (rc) {
7123 bnx2_napi_enable(bp);
7124 dev_close(bp->dev);
Michael Chan13daffa2006-03-20 17:49:20 -08007125 return rc;
Michael Chan6fefb65e2009-08-21 16:20:45 +00007126 }
Michael Chane9f26c42010-02-15 19:42:08 +00007127#ifdef BCM_CNIC
7128 mutex_lock(&bp->cnic_lock);
7129 /* Let cnic know about the new status block. */
7130 if (bp->cnic_eth_dev.drv_state & CNIC_DRV_STATE_REGD)
7131 bnx2_setup_cnic_irq_info(bp);
7132 mutex_unlock(&bp->cnic_lock);
7133#endif
Michael Chanb6016b72005-05-26 13:03:09 -07007134 bnx2_netif_start(bp);
7135 }
Michael Chanb6016b72005-05-26 13:03:09 -07007136 return 0;
7137}
7138
Michael Chan5d5d0012007-12-12 11:17:43 -08007139static int
7140bnx2_set_ringparam(struct net_device *dev, struct ethtool_ringparam *ering)
7141{
7142 struct bnx2 *bp = netdev_priv(dev);
7143 int rc;
7144
7145 if ((ering->rx_pending > MAX_TOTAL_RX_DESC_CNT) ||
7146 (ering->tx_pending > MAX_TX_DESC_CNT) ||
7147 (ering->tx_pending <= MAX_SKB_FRAGS)) {
7148
7149 return -EINVAL;
7150 }
7151 rc = bnx2_change_ring_size(bp, ering->rx_pending, ering->tx_pending);
7152 return rc;
7153}
7154
Michael Chanb6016b72005-05-26 13:03:09 -07007155static void
7156bnx2_get_pauseparam(struct net_device *dev, struct ethtool_pauseparam *epause)
7157{
Michael Chan972ec0d2006-01-23 16:12:43 -08007158 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007159
7160 epause->autoneg = ((bp->autoneg & AUTONEG_FLOW_CTRL) != 0);
7161 epause->rx_pause = ((bp->flow_ctrl & FLOW_CTRL_RX) != 0);
7162 epause->tx_pause = ((bp->flow_ctrl & FLOW_CTRL_TX) != 0);
7163}
7164
7165static int
7166bnx2_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam *epause)
7167{
Michael Chan972ec0d2006-01-23 16:12:43 -08007168 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007169
7170 bp->req_flow_ctrl = 0;
7171 if (epause->rx_pause)
7172 bp->req_flow_ctrl |= FLOW_CTRL_RX;
7173 if (epause->tx_pause)
7174 bp->req_flow_ctrl |= FLOW_CTRL_TX;
7175
7176 if (epause->autoneg) {
7177 bp->autoneg |= AUTONEG_FLOW_CTRL;
7178 }
7179 else {
7180 bp->autoneg &= ~AUTONEG_FLOW_CTRL;
7181 }
7182
Michael Chan9f52b562008-10-09 12:21:46 -07007183 if (netif_running(dev)) {
7184 spin_lock_bh(&bp->phy_lock);
7185 bnx2_setup_phy(bp, bp->phy_port);
7186 spin_unlock_bh(&bp->phy_lock);
7187 }
Michael Chanb6016b72005-05-26 13:03:09 -07007188
7189 return 0;
7190}
7191
7192static u32
7193bnx2_get_rx_csum(struct net_device *dev)
7194{
Michael Chan972ec0d2006-01-23 16:12:43 -08007195 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007196
7197 return bp->rx_csum;
7198}
7199
7200static int
7201bnx2_set_rx_csum(struct net_device *dev, u32 data)
7202{
Michael Chan972ec0d2006-01-23 16:12:43 -08007203 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007204
7205 bp->rx_csum = data;
7206 return 0;
7207}
7208
Michael Chanb11d6212006-06-29 12:31:21 -07007209static int
7210bnx2_set_tso(struct net_device *dev, u32 data)
7211{
Michael Chan4666f872007-05-03 13:22:28 -07007212 struct bnx2 *bp = netdev_priv(dev);
7213
7214 if (data) {
Michael Chanb11d6212006-06-29 12:31:21 -07007215 dev->features |= NETIF_F_TSO | NETIF_F_TSO_ECN;
Michael Chan4666f872007-05-03 13:22:28 -07007216 if (CHIP_NUM(bp) == CHIP_NUM_5709)
7217 dev->features |= NETIF_F_TSO6;
7218 } else
7219 dev->features &= ~(NETIF_F_TSO | NETIF_F_TSO6 |
7220 NETIF_F_TSO_ECN);
Michael Chanb11d6212006-06-29 12:31:21 -07007221 return 0;
7222}
7223
Peter Hagervall14ab9b82005-08-10 14:18:16 -07007224static struct {
Michael Chanb6016b72005-05-26 13:03:09 -07007225 char string[ETH_GSTRING_LEN];
Michael Chan790dab22009-08-21 16:20:47 +00007226} bnx2_stats_str_arr[] = {
Michael Chanb6016b72005-05-26 13:03:09 -07007227 { "rx_bytes" },
7228 { "rx_error_bytes" },
7229 { "tx_bytes" },
7230 { "tx_error_bytes" },
7231 { "rx_ucast_packets" },
7232 { "rx_mcast_packets" },
7233 { "rx_bcast_packets" },
7234 { "tx_ucast_packets" },
7235 { "tx_mcast_packets" },
7236 { "tx_bcast_packets" },
7237 { "tx_mac_errors" },
7238 { "tx_carrier_errors" },
7239 { "rx_crc_errors" },
7240 { "rx_align_errors" },
7241 { "tx_single_collisions" },
7242 { "tx_multi_collisions" },
7243 { "tx_deferred" },
7244 { "tx_excess_collisions" },
7245 { "tx_late_collisions" },
7246 { "tx_total_collisions" },
7247 { "rx_fragments" },
7248 { "rx_jabbers" },
7249 { "rx_undersize_packets" },
7250 { "rx_oversize_packets" },
7251 { "rx_64_byte_packets" },
7252 { "rx_65_to_127_byte_packets" },
7253 { "rx_128_to_255_byte_packets" },
7254 { "rx_256_to_511_byte_packets" },
7255 { "rx_512_to_1023_byte_packets" },
7256 { "rx_1024_to_1522_byte_packets" },
7257 { "rx_1523_to_9022_byte_packets" },
7258 { "tx_64_byte_packets" },
7259 { "tx_65_to_127_byte_packets" },
7260 { "tx_128_to_255_byte_packets" },
7261 { "tx_256_to_511_byte_packets" },
7262 { "tx_512_to_1023_byte_packets" },
7263 { "tx_1024_to_1522_byte_packets" },
7264 { "tx_1523_to_9022_byte_packets" },
7265 { "rx_xon_frames" },
7266 { "rx_xoff_frames" },
7267 { "tx_xon_frames" },
7268 { "tx_xoff_frames" },
7269 { "rx_mac_ctrl_frames" },
7270 { "rx_filtered_packets" },
Michael Chan790dab22009-08-21 16:20:47 +00007271 { "rx_ftq_discards" },
Michael Chanb6016b72005-05-26 13:03:09 -07007272 { "rx_discards" },
Michael Chancea94db2006-06-12 22:16:13 -07007273 { "rx_fw_discards" },
Michael Chanb6016b72005-05-26 13:03:09 -07007274};
7275
Michael Chan790dab22009-08-21 16:20:47 +00007276#define BNX2_NUM_STATS (sizeof(bnx2_stats_str_arr)/\
7277 sizeof(bnx2_stats_str_arr[0]))
7278
Michael Chanb6016b72005-05-26 13:03:09 -07007279#define STATS_OFFSET32(offset_name) (offsetof(struct statistics_block, offset_name) / 4)
7280
Arjan van de Venf71e1302006-03-03 21:33:57 -05007281static const unsigned long bnx2_stats_offset_arr[BNX2_NUM_STATS] = {
Michael Chanb6016b72005-05-26 13:03:09 -07007282 STATS_OFFSET32(stat_IfHCInOctets_hi),
7283 STATS_OFFSET32(stat_IfHCInBadOctets_hi),
7284 STATS_OFFSET32(stat_IfHCOutOctets_hi),
7285 STATS_OFFSET32(stat_IfHCOutBadOctets_hi),
7286 STATS_OFFSET32(stat_IfHCInUcastPkts_hi),
7287 STATS_OFFSET32(stat_IfHCInMulticastPkts_hi),
7288 STATS_OFFSET32(stat_IfHCInBroadcastPkts_hi),
7289 STATS_OFFSET32(stat_IfHCOutUcastPkts_hi),
7290 STATS_OFFSET32(stat_IfHCOutMulticastPkts_hi),
7291 STATS_OFFSET32(stat_IfHCOutBroadcastPkts_hi),
7292 STATS_OFFSET32(stat_emac_tx_stat_dot3statsinternalmactransmiterrors),
Jeff Garzik6aa20a22006-09-13 13:24:59 -04007293 STATS_OFFSET32(stat_Dot3StatsCarrierSenseErrors),
7294 STATS_OFFSET32(stat_Dot3StatsFCSErrors),
7295 STATS_OFFSET32(stat_Dot3StatsAlignmentErrors),
7296 STATS_OFFSET32(stat_Dot3StatsSingleCollisionFrames),
7297 STATS_OFFSET32(stat_Dot3StatsMultipleCollisionFrames),
7298 STATS_OFFSET32(stat_Dot3StatsDeferredTransmissions),
7299 STATS_OFFSET32(stat_Dot3StatsExcessiveCollisions),
7300 STATS_OFFSET32(stat_Dot3StatsLateCollisions),
7301 STATS_OFFSET32(stat_EtherStatsCollisions),
7302 STATS_OFFSET32(stat_EtherStatsFragments),
7303 STATS_OFFSET32(stat_EtherStatsJabbers),
7304 STATS_OFFSET32(stat_EtherStatsUndersizePkts),
7305 STATS_OFFSET32(stat_EtherStatsOverrsizePkts),
7306 STATS_OFFSET32(stat_EtherStatsPktsRx64Octets),
7307 STATS_OFFSET32(stat_EtherStatsPktsRx65Octetsto127Octets),
7308 STATS_OFFSET32(stat_EtherStatsPktsRx128Octetsto255Octets),
7309 STATS_OFFSET32(stat_EtherStatsPktsRx256Octetsto511Octets),
7310 STATS_OFFSET32(stat_EtherStatsPktsRx512Octetsto1023Octets),
7311 STATS_OFFSET32(stat_EtherStatsPktsRx1024Octetsto1522Octets),
7312 STATS_OFFSET32(stat_EtherStatsPktsRx1523Octetsto9022Octets),
7313 STATS_OFFSET32(stat_EtherStatsPktsTx64Octets),
7314 STATS_OFFSET32(stat_EtherStatsPktsTx65Octetsto127Octets),
7315 STATS_OFFSET32(stat_EtherStatsPktsTx128Octetsto255Octets),
7316 STATS_OFFSET32(stat_EtherStatsPktsTx256Octetsto511Octets),
7317 STATS_OFFSET32(stat_EtherStatsPktsTx512Octetsto1023Octets),
7318 STATS_OFFSET32(stat_EtherStatsPktsTx1024Octetsto1522Octets),
7319 STATS_OFFSET32(stat_EtherStatsPktsTx1523Octetsto9022Octets),
7320 STATS_OFFSET32(stat_XonPauseFramesReceived),
7321 STATS_OFFSET32(stat_XoffPauseFramesReceived),
7322 STATS_OFFSET32(stat_OutXonSent),
7323 STATS_OFFSET32(stat_OutXoffSent),
7324 STATS_OFFSET32(stat_MacControlFramesReceived),
7325 STATS_OFFSET32(stat_IfInFramesL2FilterDiscards),
Michael Chan790dab22009-08-21 16:20:47 +00007326 STATS_OFFSET32(stat_IfInFTQDiscards),
Jeff Garzik6aa20a22006-09-13 13:24:59 -04007327 STATS_OFFSET32(stat_IfInMBUFDiscards),
Michael Chancea94db2006-06-12 22:16:13 -07007328 STATS_OFFSET32(stat_FwRxDrop),
Michael Chanb6016b72005-05-26 13:03:09 -07007329};
7330
7331/* stat_IfHCInBadOctets and stat_Dot3StatsCarrierSenseErrors are
7332 * skipped because of errata.
Jeff Garzik6aa20a22006-09-13 13:24:59 -04007333 */
Peter Hagervall14ab9b82005-08-10 14:18:16 -07007334static u8 bnx2_5706_stats_len_arr[BNX2_NUM_STATS] = {
Michael Chanb6016b72005-05-26 13:03:09 -07007335 8,0,8,8,8,8,8,8,8,8,
7336 4,0,4,4,4,4,4,4,4,4,
7337 4,4,4,4,4,4,4,4,4,4,
7338 4,4,4,4,4,4,4,4,4,4,
Michael Chan790dab22009-08-21 16:20:47 +00007339 4,4,4,4,4,4,4,
Michael Chanb6016b72005-05-26 13:03:09 -07007340};
7341
Michael Chan5b0c76a2005-11-04 08:45:49 -08007342static u8 bnx2_5708_stats_len_arr[BNX2_NUM_STATS] = {
7343 8,0,8,8,8,8,8,8,8,8,
7344 4,4,4,4,4,4,4,4,4,4,
7345 4,4,4,4,4,4,4,4,4,4,
7346 4,4,4,4,4,4,4,4,4,4,
Michael Chan790dab22009-08-21 16:20:47 +00007347 4,4,4,4,4,4,4,
Michael Chan5b0c76a2005-11-04 08:45:49 -08007348};
7349
Michael Chanb6016b72005-05-26 13:03:09 -07007350#define BNX2_NUM_TESTS 6
7351
Peter Hagervall14ab9b82005-08-10 14:18:16 -07007352static struct {
Michael Chanb6016b72005-05-26 13:03:09 -07007353 char string[ETH_GSTRING_LEN];
7354} bnx2_tests_str_arr[BNX2_NUM_TESTS] = {
7355 { "register_test (offline)" },
7356 { "memory_test (offline)" },
7357 { "loopback_test (offline)" },
7358 { "nvram_test (online)" },
7359 { "interrupt_test (online)" },
7360 { "link_test (online)" },
7361};
7362
7363static int
Jeff Garzikb9f2c042007-10-03 18:07:32 -07007364bnx2_get_sset_count(struct net_device *dev, int sset)
Michael Chanb6016b72005-05-26 13:03:09 -07007365{
Jeff Garzikb9f2c042007-10-03 18:07:32 -07007366 switch (sset) {
7367 case ETH_SS_TEST:
7368 return BNX2_NUM_TESTS;
7369 case ETH_SS_STATS:
7370 return BNX2_NUM_STATS;
7371 default:
7372 return -EOPNOTSUPP;
7373 }
Michael Chanb6016b72005-05-26 13:03:09 -07007374}
7375
7376static void
7377bnx2_self_test(struct net_device *dev, struct ethtool_test *etest, u64 *buf)
7378{
Michael Chan972ec0d2006-01-23 16:12:43 -08007379 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007380
Michael Chan9f52b562008-10-09 12:21:46 -07007381 bnx2_set_power_state(bp, PCI_D0);
7382
Michael Chanb6016b72005-05-26 13:03:09 -07007383 memset(buf, 0, sizeof(u64) * BNX2_NUM_TESTS);
7384 if (etest->flags & ETH_TEST_FL_OFFLINE) {
Michael Chan80be4432006-11-19 14:07:28 -08007385 int i;
7386
Michael Chanb6016b72005-05-26 13:03:09 -07007387 bnx2_netif_stop(bp);
7388 bnx2_reset_chip(bp, BNX2_DRV_MSG_CODE_DIAG);
7389 bnx2_free_skbs(bp);
7390
7391 if (bnx2_test_registers(bp) != 0) {
7392 buf[0] = 1;
7393 etest->flags |= ETH_TEST_FL_FAILED;
7394 }
7395 if (bnx2_test_memory(bp) != 0) {
7396 buf[1] = 1;
7397 etest->flags |= ETH_TEST_FL_FAILED;
7398 }
Michael Chanbc5a0692006-01-23 16:13:22 -08007399 if ((buf[2] = bnx2_test_loopback(bp)) != 0)
Michael Chanb6016b72005-05-26 13:03:09 -07007400 etest->flags |= ETH_TEST_FL_FAILED;
Michael Chanb6016b72005-05-26 13:03:09 -07007401
Michael Chan9f52b562008-10-09 12:21:46 -07007402 if (!netif_running(bp->dev))
7403 bnx2_shutdown_chip(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07007404 else {
Michael Chan9a120bc2008-05-16 22:17:45 -07007405 bnx2_init_nic(bp, 1);
Michael Chanb6016b72005-05-26 13:03:09 -07007406 bnx2_netif_start(bp);
7407 }
7408
7409 /* wait for link up */
Michael Chan80be4432006-11-19 14:07:28 -08007410 for (i = 0; i < 7; i++) {
7411 if (bp->link_up)
7412 break;
7413 msleep_interruptible(1000);
7414 }
Michael Chanb6016b72005-05-26 13:03:09 -07007415 }
7416
7417 if (bnx2_test_nvram(bp) != 0) {
7418 buf[3] = 1;
7419 etest->flags |= ETH_TEST_FL_FAILED;
7420 }
7421 if (bnx2_test_intr(bp) != 0) {
7422 buf[4] = 1;
7423 etest->flags |= ETH_TEST_FL_FAILED;
7424 }
7425
7426 if (bnx2_test_link(bp) != 0) {
7427 buf[5] = 1;
7428 etest->flags |= ETH_TEST_FL_FAILED;
7429
7430 }
Michael Chan9f52b562008-10-09 12:21:46 -07007431 if (!netif_running(bp->dev))
7432 bnx2_set_power_state(bp, PCI_D3hot);
Michael Chanb6016b72005-05-26 13:03:09 -07007433}
7434
7435static void
7436bnx2_get_strings(struct net_device *dev, u32 stringset, u8 *buf)
7437{
7438 switch (stringset) {
7439 case ETH_SS_STATS:
7440 memcpy(buf, bnx2_stats_str_arr,
7441 sizeof(bnx2_stats_str_arr));
7442 break;
7443 case ETH_SS_TEST:
7444 memcpy(buf, bnx2_tests_str_arr,
7445 sizeof(bnx2_tests_str_arr));
7446 break;
7447 }
7448}
7449
Michael Chanb6016b72005-05-26 13:03:09 -07007450static void
7451bnx2_get_ethtool_stats(struct net_device *dev,
7452 struct ethtool_stats *stats, u64 *buf)
7453{
Michael Chan972ec0d2006-01-23 16:12:43 -08007454 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007455 int i;
7456 u32 *hw_stats = (u32 *) bp->stats_blk;
Michael Chan354fcd72010-01-17 07:30:44 +00007457 u32 *temp_stats = (u32 *) bp->temp_stats_blk;
Peter Hagervall14ab9b82005-08-10 14:18:16 -07007458 u8 *stats_len_arr = NULL;
Michael Chanb6016b72005-05-26 13:03:09 -07007459
7460 if (hw_stats == NULL) {
7461 memset(buf, 0, sizeof(u64) * BNX2_NUM_STATS);
7462 return;
7463 }
7464
Michael Chan5b0c76a2005-11-04 08:45:49 -08007465 if ((CHIP_ID(bp) == CHIP_ID_5706_A0) ||
7466 (CHIP_ID(bp) == CHIP_ID_5706_A1) ||
7467 (CHIP_ID(bp) == CHIP_ID_5706_A2) ||
7468 (CHIP_ID(bp) == CHIP_ID_5708_A0))
Michael Chanb6016b72005-05-26 13:03:09 -07007469 stats_len_arr = bnx2_5706_stats_len_arr;
Michael Chan5b0c76a2005-11-04 08:45:49 -08007470 else
7471 stats_len_arr = bnx2_5708_stats_len_arr;
Michael Chanb6016b72005-05-26 13:03:09 -07007472
7473 for (i = 0; i < BNX2_NUM_STATS; i++) {
Michael Chan354fcd72010-01-17 07:30:44 +00007474 unsigned long offset;
7475
Michael Chanb6016b72005-05-26 13:03:09 -07007476 if (stats_len_arr[i] == 0) {
7477 /* skip this counter */
7478 buf[i] = 0;
7479 continue;
7480 }
Michael Chan354fcd72010-01-17 07:30:44 +00007481
7482 offset = bnx2_stats_offset_arr[i];
Michael Chanb6016b72005-05-26 13:03:09 -07007483 if (stats_len_arr[i] == 4) {
7484 /* 4-byte counter */
Michael Chan354fcd72010-01-17 07:30:44 +00007485 buf[i] = (u64) *(hw_stats + offset) +
7486 *(temp_stats + offset);
Michael Chanb6016b72005-05-26 13:03:09 -07007487 continue;
7488 }
7489 /* 8-byte counter */
Michael Chan354fcd72010-01-17 07:30:44 +00007490 buf[i] = (((u64) *(hw_stats + offset)) << 32) +
7491 *(hw_stats + offset + 1) +
7492 (((u64) *(temp_stats + offset)) << 32) +
7493 *(temp_stats + offset + 1);
Michael Chanb6016b72005-05-26 13:03:09 -07007494 }
7495}
7496
7497static int
7498bnx2_phys_id(struct net_device *dev, u32 data)
7499{
Michael Chan972ec0d2006-01-23 16:12:43 -08007500 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007501 int i;
7502 u32 save;
7503
Michael Chan9f52b562008-10-09 12:21:46 -07007504 bnx2_set_power_state(bp, PCI_D0);
7505
Michael Chanb6016b72005-05-26 13:03:09 -07007506 if (data == 0)
7507 data = 2;
7508
7509 save = REG_RD(bp, BNX2_MISC_CFG);
7510 REG_WR(bp, BNX2_MISC_CFG, BNX2_MISC_CFG_LEDMODE_MAC);
7511
7512 for (i = 0; i < (data * 2); i++) {
7513 if ((i % 2) == 0) {
7514 REG_WR(bp, BNX2_EMAC_LED, BNX2_EMAC_LED_OVERRIDE);
7515 }
7516 else {
7517 REG_WR(bp, BNX2_EMAC_LED, BNX2_EMAC_LED_OVERRIDE |
7518 BNX2_EMAC_LED_1000MB_OVERRIDE |
7519 BNX2_EMAC_LED_100MB_OVERRIDE |
7520 BNX2_EMAC_LED_10MB_OVERRIDE |
7521 BNX2_EMAC_LED_TRAFFIC_OVERRIDE |
7522 BNX2_EMAC_LED_TRAFFIC);
7523 }
7524 msleep_interruptible(500);
7525 if (signal_pending(current))
7526 break;
7527 }
7528 REG_WR(bp, BNX2_EMAC_LED, 0);
7529 REG_WR(bp, BNX2_MISC_CFG, save);
Michael Chan9f52b562008-10-09 12:21:46 -07007530
7531 if (!netif_running(dev))
7532 bnx2_set_power_state(bp, PCI_D3hot);
7533
Michael Chanb6016b72005-05-26 13:03:09 -07007534 return 0;
7535}
7536
Michael Chan4666f872007-05-03 13:22:28 -07007537static int
7538bnx2_set_tx_csum(struct net_device *dev, u32 data)
7539{
7540 struct bnx2 *bp = netdev_priv(dev);
7541
7542 if (CHIP_NUM(bp) == CHIP_NUM_5709)
Michael Chan6460d942007-07-14 19:07:52 -07007543 return (ethtool_op_set_tx_ipv6_csum(dev, data));
Michael Chan4666f872007-05-03 13:22:28 -07007544 else
7545 return (ethtool_op_set_tx_csum(dev, data));
7546}
7547
Jeff Garzik7282d492006-09-13 14:30:00 -04007548static const struct ethtool_ops bnx2_ethtool_ops = {
Michael Chanb6016b72005-05-26 13:03:09 -07007549 .get_settings = bnx2_get_settings,
7550 .set_settings = bnx2_set_settings,
7551 .get_drvinfo = bnx2_get_drvinfo,
Michael Chan244ac4f2006-03-20 17:48:46 -08007552 .get_regs_len = bnx2_get_regs_len,
7553 .get_regs = bnx2_get_regs,
Michael Chanb6016b72005-05-26 13:03:09 -07007554 .get_wol = bnx2_get_wol,
7555 .set_wol = bnx2_set_wol,
7556 .nway_reset = bnx2_nway_reset,
Ooiwa Naohiro7959ea22009-06-24 00:19:06 -07007557 .get_link = bnx2_get_link,
Michael Chanb6016b72005-05-26 13:03:09 -07007558 .get_eeprom_len = bnx2_get_eeprom_len,
7559 .get_eeprom = bnx2_get_eeprom,
7560 .set_eeprom = bnx2_set_eeprom,
7561 .get_coalesce = bnx2_get_coalesce,
7562 .set_coalesce = bnx2_set_coalesce,
7563 .get_ringparam = bnx2_get_ringparam,
7564 .set_ringparam = bnx2_set_ringparam,
7565 .get_pauseparam = bnx2_get_pauseparam,
7566 .set_pauseparam = bnx2_set_pauseparam,
7567 .get_rx_csum = bnx2_get_rx_csum,
7568 .set_rx_csum = bnx2_set_rx_csum,
Michael Chan4666f872007-05-03 13:22:28 -07007569 .set_tx_csum = bnx2_set_tx_csum,
Michael Chanb6016b72005-05-26 13:03:09 -07007570 .set_sg = ethtool_op_set_sg,
Michael Chanb11d6212006-06-29 12:31:21 -07007571 .set_tso = bnx2_set_tso,
Michael Chanb6016b72005-05-26 13:03:09 -07007572 .self_test = bnx2_self_test,
7573 .get_strings = bnx2_get_strings,
7574 .phys_id = bnx2_phys_id,
Michael Chanb6016b72005-05-26 13:03:09 -07007575 .get_ethtool_stats = bnx2_get_ethtool_stats,
Jeff Garzikb9f2c042007-10-03 18:07:32 -07007576 .get_sset_count = bnx2_get_sset_count,
Michael Chanb6016b72005-05-26 13:03:09 -07007577};
7578
7579/* Called with rtnl_lock */
7580static int
7581bnx2_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
7582{
Peter Hagervall14ab9b82005-08-10 14:18:16 -07007583 struct mii_ioctl_data *data = if_mii(ifr);
Michael Chan972ec0d2006-01-23 16:12:43 -08007584 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007585 int err;
7586
7587 switch(cmd) {
7588 case SIOCGMIIPHY:
7589 data->phy_id = bp->phy_addr;
7590
7591 /* fallthru */
7592 case SIOCGMIIREG: {
7593 u32 mii_regval;
7594
Michael Chan583c28e2008-01-21 19:51:35 -08007595 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
Michael Chan7b6b8342007-07-07 22:50:15 -07007596 return -EOPNOTSUPP;
7597
Michael Chandad3e452007-05-03 13:18:03 -07007598 if (!netif_running(dev))
7599 return -EAGAIN;
7600
Michael Chanc770a652005-08-25 15:38:39 -07007601 spin_lock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07007602 err = bnx2_read_phy(bp, data->reg_num & 0x1f, &mii_regval);
Michael Chanc770a652005-08-25 15:38:39 -07007603 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07007604
7605 data->val_out = mii_regval;
7606
7607 return err;
7608 }
7609
7610 case SIOCSMIIREG:
Michael Chan583c28e2008-01-21 19:51:35 -08007611 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
Michael Chan7b6b8342007-07-07 22:50:15 -07007612 return -EOPNOTSUPP;
7613
Michael Chandad3e452007-05-03 13:18:03 -07007614 if (!netif_running(dev))
7615 return -EAGAIN;
7616
Michael Chanc770a652005-08-25 15:38:39 -07007617 spin_lock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07007618 err = bnx2_write_phy(bp, data->reg_num & 0x1f, data->val_in);
Michael Chanc770a652005-08-25 15:38:39 -07007619 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07007620
7621 return err;
7622
7623 default:
7624 /* do nothing */
7625 break;
7626 }
7627 return -EOPNOTSUPP;
7628}
7629
7630/* Called with rtnl_lock */
7631static int
7632bnx2_change_mac_addr(struct net_device *dev, void *p)
7633{
7634 struct sockaddr *addr = p;
Michael Chan972ec0d2006-01-23 16:12:43 -08007635 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007636
Michael Chan73eef4c2005-08-25 15:39:15 -07007637 if (!is_valid_ether_addr(addr->sa_data))
7638 return -EINVAL;
7639
Michael Chanb6016b72005-05-26 13:03:09 -07007640 memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
7641 if (netif_running(dev))
Benjamin Li5fcaed02008-07-14 22:39:52 -07007642 bnx2_set_mac_addr(bp, bp->dev->dev_addr, 0);
Michael Chanb6016b72005-05-26 13:03:09 -07007643
7644 return 0;
7645}
7646
7647/* Called with rtnl_lock */
7648static int
7649bnx2_change_mtu(struct net_device *dev, int new_mtu)
7650{
Michael Chan972ec0d2006-01-23 16:12:43 -08007651 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007652
7653 if (((new_mtu + ETH_HLEN) > MAX_ETHERNET_JUMBO_PACKET_SIZE) ||
7654 ((new_mtu + ETH_HLEN) < MIN_ETHERNET_PACKET_SIZE))
7655 return -EINVAL;
7656
7657 dev->mtu = new_mtu;
Michael Chan5d5d0012007-12-12 11:17:43 -08007658 return (bnx2_change_ring_size(bp, bp->rx_ring_size, bp->tx_ring_size));
Michael Chanb6016b72005-05-26 13:03:09 -07007659}
7660
Alexey Dobriyan257ddbd2010-01-27 10:17:41 +00007661#ifdef CONFIG_NET_POLL_CONTROLLER
Michael Chanb6016b72005-05-26 13:03:09 -07007662static void
7663poll_bnx2(struct net_device *dev)
7664{
Michael Chan972ec0d2006-01-23 16:12:43 -08007665 struct bnx2 *bp = netdev_priv(dev);
Neil Hormanb2af2c12008-11-12 16:23:44 -08007666 int i;
Michael Chanb6016b72005-05-26 13:03:09 -07007667
Neil Hormanb2af2c12008-11-12 16:23:44 -08007668 for (i = 0; i < bp->irq_nvecs; i++) {
7669 disable_irq(bp->irq_tbl[i].vector);
7670 bnx2_interrupt(bp->irq_tbl[i].vector, &bp->bnx2_napi[i]);
7671 enable_irq(bp->irq_tbl[i].vector);
7672 }
Michael Chanb6016b72005-05-26 13:03:09 -07007673}
7674#endif
7675
Michael Chan253c8b72007-01-08 19:56:01 -08007676static void __devinit
7677bnx2_get_5709_media(struct bnx2 *bp)
7678{
7679 u32 val = REG_RD(bp, BNX2_MISC_DUAL_MEDIA_CTRL);
7680 u32 bond_id = val & BNX2_MISC_DUAL_MEDIA_CTRL_BOND_ID;
7681 u32 strap;
7682
7683 if (bond_id == BNX2_MISC_DUAL_MEDIA_CTRL_BOND_ID_C)
7684 return;
7685 else if (bond_id == BNX2_MISC_DUAL_MEDIA_CTRL_BOND_ID_S) {
Michael Chan583c28e2008-01-21 19:51:35 -08007686 bp->phy_flags |= BNX2_PHY_FLAG_SERDES;
Michael Chan253c8b72007-01-08 19:56:01 -08007687 return;
7688 }
7689
7690 if (val & BNX2_MISC_DUAL_MEDIA_CTRL_STRAP_OVERRIDE)
7691 strap = (val & BNX2_MISC_DUAL_MEDIA_CTRL_PHY_CTRL) >> 21;
7692 else
7693 strap = (val & BNX2_MISC_DUAL_MEDIA_CTRL_PHY_CTRL_STRAP) >> 8;
7694
7695 if (PCI_FUNC(bp->pdev->devfn) == 0) {
7696 switch (strap) {
7697 case 0x4:
7698 case 0x5:
7699 case 0x6:
Michael Chan583c28e2008-01-21 19:51:35 -08007700 bp->phy_flags |= BNX2_PHY_FLAG_SERDES;
Michael Chan253c8b72007-01-08 19:56:01 -08007701 return;
7702 }
7703 } else {
7704 switch (strap) {
7705 case 0x1:
7706 case 0x2:
7707 case 0x4:
Michael Chan583c28e2008-01-21 19:51:35 -08007708 bp->phy_flags |= BNX2_PHY_FLAG_SERDES;
Michael Chan253c8b72007-01-08 19:56:01 -08007709 return;
7710 }
7711 }
7712}
7713
Michael Chan883e5152007-05-03 13:25:11 -07007714static void __devinit
7715bnx2_get_pci_speed(struct bnx2 *bp)
7716{
7717 u32 reg;
7718
7719 reg = REG_RD(bp, BNX2_PCICFG_MISC_STATUS);
7720 if (reg & BNX2_PCICFG_MISC_STATUS_PCIX_DET) {
7721 u32 clkreg;
7722
David S. Millerf86e82f2008-01-21 17:15:40 -08007723 bp->flags |= BNX2_FLAG_PCIX;
Michael Chan883e5152007-05-03 13:25:11 -07007724
7725 clkreg = REG_RD(bp, BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS);
7726
7727 clkreg &= BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET;
7728 switch (clkreg) {
7729 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_133MHZ:
7730 bp->bus_speed_mhz = 133;
7731 break;
7732
7733 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_95MHZ:
7734 bp->bus_speed_mhz = 100;
7735 break;
7736
7737 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_66MHZ:
7738 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_80MHZ:
7739 bp->bus_speed_mhz = 66;
7740 break;
7741
7742 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_48MHZ:
7743 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_55MHZ:
7744 bp->bus_speed_mhz = 50;
7745 break;
7746
7747 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_LOW:
7748 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_32MHZ:
7749 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_38MHZ:
7750 bp->bus_speed_mhz = 33;
7751 break;
7752 }
7753 }
7754 else {
7755 if (reg & BNX2_PCICFG_MISC_STATUS_M66EN)
7756 bp->bus_speed_mhz = 66;
7757 else
7758 bp->bus_speed_mhz = 33;
7759 }
7760
7761 if (reg & BNX2_PCICFG_MISC_STATUS_32BIT_DET)
David S. Millerf86e82f2008-01-21 17:15:40 -08007762 bp->flags |= BNX2_FLAG_PCI_32BIT;
Michael Chan883e5152007-05-03 13:25:11 -07007763
7764}
7765
Michael Chan76d99062009-12-03 09:46:34 +00007766static void __devinit
7767bnx2_read_vpd_fw_ver(struct bnx2 *bp)
7768{
7769 int rc, i, v0_len = 0;
7770 u8 *data;
7771 u8 *v0_str = NULL;
7772 bool mn_match = false;
7773
Michael Chan012093f2009-12-03 15:58:00 -08007774#define BNX2_VPD_NVRAM_OFFSET 0x300
7775#define BNX2_VPD_LEN 128
Michael Chan76d99062009-12-03 09:46:34 +00007776#define BNX2_MAX_VER_SLEN 30
7777
7778 data = kmalloc(256, GFP_KERNEL);
7779 if (!data)
7780 return;
7781
Michael Chan012093f2009-12-03 15:58:00 -08007782 rc = bnx2_nvram_read(bp, BNX2_VPD_NVRAM_OFFSET, data + BNX2_VPD_LEN,
7783 BNX2_VPD_LEN);
Michael Chan76d99062009-12-03 09:46:34 +00007784 if (rc)
7785 goto vpd_done;
7786
Michael Chan012093f2009-12-03 15:58:00 -08007787 for (i = 0; i < BNX2_VPD_LEN; i += 4) {
7788 data[i] = data[i + BNX2_VPD_LEN + 3];
7789 data[i + 1] = data[i + BNX2_VPD_LEN + 2];
7790 data[i + 2] = data[i + BNX2_VPD_LEN + 1];
7791 data[i + 3] = data[i + BNX2_VPD_LEN];
Michael Chan76d99062009-12-03 09:46:34 +00007792 }
7793
Michael Chan012093f2009-12-03 15:58:00 -08007794 for (i = 0; i <= BNX2_VPD_LEN - 3; ) {
Michael Chan76d99062009-12-03 09:46:34 +00007795 unsigned char val = data[i];
7796 unsigned int block_end;
7797
7798 if (val == 0x82 || val == 0x91) {
7799 i = (i + 3 + (data[i + 1] + (data[i + 2] << 8)));
7800 continue;
7801 }
7802
7803 if (val != 0x90)
7804 goto vpd_done;
7805
7806 block_end = (i + 3 + (data[i + 1] + (data[i + 2] << 8)));
7807 i += 3;
7808
Michael Chan012093f2009-12-03 15:58:00 -08007809 if (block_end > BNX2_VPD_LEN)
Michael Chan76d99062009-12-03 09:46:34 +00007810 goto vpd_done;
7811
7812 while (i < (block_end - 2)) {
Michael Chan012093f2009-12-03 15:58:00 -08007813 int len = data[i + 2];
7814
7815 if (i + 3 + len > block_end)
7816 goto vpd_done;
7817
Michael Chan76d99062009-12-03 09:46:34 +00007818 if (data[i] == 'M' && data[i + 1] == 'N') {
Michael Chan012093f2009-12-03 15:58:00 -08007819 if (len != 4 ||
7820 memcmp(&data[i + 3], "1028", 4))
Michael Chan76d99062009-12-03 09:46:34 +00007821 goto vpd_done;
7822 mn_match = true;
Michael Chan76d99062009-12-03 09:46:34 +00007823
7824 } else if (data[i] == 'V' && data[i + 1] == '0') {
Michael Chan012093f2009-12-03 15:58:00 -08007825 if (len > BNX2_MAX_VER_SLEN)
Michael Chan76d99062009-12-03 09:46:34 +00007826 goto vpd_done;
7827
Michael Chan012093f2009-12-03 15:58:00 -08007828 v0_len = len;
7829 v0_str = &data[i + 3];
Michael Chan76d99062009-12-03 09:46:34 +00007830 }
Michael Chan012093f2009-12-03 15:58:00 -08007831 i += 3 + len;
Michael Chan76d99062009-12-03 09:46:34 +00007832
7833 if (mn_match && v0_str) {
7834 memcpy(bp->fw_version, v0_str, v0_len);
7835 bp->fw_version[v0_len] = ' ';
7836 goto vpd_done;
7837 }
7838 }
7839 goto vpd_done;
7840 }
7841
7842vpd_done:
7843 kfree(data);
7844}
7845
Michael Chanb6016b72005-05-26 13:03:09 -07007846static int __devinit
7847bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
7848{
7849 struct bnx2 *bp;
7850 unsigned long mem_len;
Michael Chan58fc2ea2007-07-07 22:52:02 -07007851 int rc, i, j;
Michael Chanb6016b72005-05-26 13:03:09 -07007852 u32 reg;
Michael Chan40453c82007-05-03 13:19:18 -07007853 u64 dma_mask, persist_dma_mask;
Michael Chanb6016b72005-05-26 13:03:09 -07007854
Michael Chanb6016b72005-05-26 13:03:09 -07007855 SET_NETDEV_DEV(dev, &pdev->dev);
Michael Chan972ec0d2006-01-23 16:12:43 -08007856 bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007857
7858 bp->flags = 0;
7859 bp->phy_flags = 0;
7860
Michael Chan354fcd72010-01-17 07:30:44 +00007861 bp->temp_stats_blk =
7862 kzalloc(sizeof(struct statistics_block), GFP_KERNEL);
7863
7864 if (bp->temp_stats_blk == NULL) {
7865 rc = -ENOMEM;
7866 goto err_out;
7867 }
7868
Michael Chanb6016b72005-05-26 13:03:09 -07007869 /* enable device (incl. PCI PM wakeup), and bus-mastering */
7870 rc = pci_enable_device(pdev);
7871 if (rc) {
Joe Perches898eb712007-10-18 03:06:30 -07007872 dev_err(&pdev->dev, "Cannot enable PCI device, aborting.\n");
Michael Chanb6016b72005-05-26 13:03:09 -07007873 goto err_out;
7874 }
7875
7876 if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) {
Jeff Garzik9b91cf92006-06-27 11:39:50 -04007877 dev_err(&pdev->dev,
Jeff Garzik2e8a5382006-06-27 10:47:51 -04007878 "Cannot find PCI device base address, aborting.\n");
Michael Chanb6016b72005-05-26 13:03:09 -07007879 rc = -ENODEV;
7880 goto err_out_disable;
7881 }
7882
7883 rc = pci_request_regions(pdev, DRV_MODULE_NAME);
7884 if (rc) {
Jeff Garzik9b91cf92006-06-27 11:39:50 -04007885 dev_err(&pdev->dev, "Cannot obtain PCI resources, aborting.\n");
Michael Chanb6016b72005-05-26 13:03:09 -07007886 goto err_out_disable;
7887 }
7888
7889 pci_set_master(pdev);
Wendy Xiong6ff2da42008-05-16 22:18:21 -07007890 pci_save_state(pdev);
Michael Chanb6016b72005-05-26 13:03:09 -07007891
7892 bp->pm_cap = pci_find_capability(pdev, PCI_CAP_ID_PM);
7893 if (bp->pm_cap == 0) {
Jeff Garzik9b91cf92006-06-27 11:39:50 -04007894 dev_err(&pdev->dev,
Jeff Garzik2e8a5382006-06-27 10:47:51 -04007895 "Cannot find power management capability, aborting.\n");
Michael Chanb6016b72005-05-26 13:03:09 -07007896 rc = -EIO;
7897 goto err_out_release;
7898 }
7899
Michael Chanb6016b72005-05-26 13:03:09 -07007900 bp->dev = dev;
7901 bp->pdev = pdev;
7902
7903 spin_lock_init(&bp->phy_lock);
Michael Chan1b8227c2007-05-03 13:24:05 -07007904 spin_lock_init(&bp->indirect_lock);
Michael Chanc5a88952009-08-14 15:49:45 +00007905#ifdef BCM_CNIC
7906 mutex_init(&bp->cnic_lock);
7907#endif
David Howellsc4028952006-11-22 14:57:56 +00007908 INIT_WORK(&bp->reset_task, bnx2_reset_task);
Michael Chanb6016b72005-05-26 13:03:09 -07007909
7910 dev->base_addr = dev->mem_start = pci_resource_start(pdev, 0);
Michael Chan4edd4732009-06-08 18:14:42 -07007911 mem_len = MB_GET_CID_ADDR(TX_TSS_CID + TX_MAX_TSS_RINGS + 1);
Michael Chanb6016b72005-05-26 13:03:09 -07007912 dev->mem_end = dev->mem_start + mem_len;
7913 dev->irq = pdev->irq;
7914
7915 bp->regview = ioremap_nocache(dev->base_addr, mem_len);
7916
7917 if (!bp->regview) {
Jeff Garzik9b91cf92006-06-27 11:39:50 -04007918 dev_err(&pdev->dev, "Cannot map register space, aborting.\n");
Michael Chanb6016b72005-05-26 13:03:09 -07007919 rc = -ENOMEM;
7920 goto err_out_release;
7921 }
7922
7923 /* Configure byte swap and enable write to the reg_window registers.
7924 * Rely on CPU to do target byte swapping on big endian systems
7925 * The chip's target access swapping will not swap all accesses
7926 */
7927 pci_write_config_dword(bp->pdev, BNX2_PCICFG_MISC_CONFIG,
7928 BNX2_PCICFG_MISC_CONFIG_REG_WINDOW_ENA |
7929 BNX2_PCICFG_MISC_CONFIG_TARGET_MB_WORD_SWAP);
7930
Pavel Machek829ca9a2005-09-03 15:56:56 -07007931 bnx2_set_power_state(bp, PCI_D0);
Michael Chanb6016b72005-05-26 13:03:09 -07007932
7933 bp->chip_id = REG_RD(bp, BNX2_MISC_ID);
7934
Michael Chan883e5152007-05-03 13:25:11 -07007935 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
7936 if (pci_find_capability(pdev, PCI_CAP_ID_EXP) == 0) {
7937 dev_err(&pdev->dev,
7938 "Cannot find PCIE capability, aborting.\n");
7939 rc = -EIO;
7940 goto err_out_unmap;
7941 }
David S. Millerf86e82f2008-01-21 17:15:40 -08007942 bp->flags |= BNX2_FLAG_PCIE;
Michael Chan2dd201d2008-01-21 17:06:09 -08007943 if (CHIP_REV(bp) == CHIP_REV_Ax)
David S. Millerf86e82f2008-01-21 17:15:40 -08007944 bp->flags |= BNX2_FLAG_JUMBO_BROKEN;
Michael Chan883e5152007-05-03 13:25:11 -07007945 } else {
Michael Chan59b47d82006-11-19 14:10:45 -08007946 bp->pcix_cap = pci_find_capability(pdev, PCI_CAP_ID_PCIX);
7947 if (bp->pcix_cap == 0) {
7948 dev_err(&pdev->dev,
7949 "Cannot find PCIX capability, aborting.\n");
7950 rc = -EIO;
7951 goto err_out_unmap;
7952 }
Michael Chan61d9e3f2009-08-21 16:20:46 +00007953 bp->flags |= BNX2_FLAG_BROKEN_STATS;
Michael Chan59b47d82006-11-19 14:10:45 -08007954 }
7955
Michael Chanb4b36042007-12-20 19:59:30 -08007956 if (CHIP_NUM(bp) == CHIP_NUM_5709 && CHIP_REV(bp) != CHIP_REV_Ax) {
7957 if (pci_find_capability(pdev, PCI_CAP_ID_MSIX))
David S. Millerf86e82f2008-01-21 17:15:40 -08007958 bp->flags |= BNX2_FLAG_MSIX_CAP;
Michael Chanb4b36042007-12-20 19:59:30 -08007959 }
7960
Michael Chan8e6a72c2007-05-03 13:24:48 -07007961 if (CHIP_ID(bp) != CHIP_ID_5706_A0 && CHIP_ID(bp) != CHIP_ID_5706_A1) {
7962 if (pci_find_capability(pdev, PCI_CAP_ID_MSI))
David S. Millerf86e82f2008-01-21 17:15:40 -08007963 bp->flags |= BNX2_FLAG_MSI_CAP;
Michael Chan8e6a72c2007-05-03 13:24:48 -07007964 }
7965
Michael Chan40453c82007-05-03 13:19:18 -07007966 /* 5708 cannot support DMA addresses > 40-bit. */
7967 if (CHIP_NUM(bp) == CHIP_NUM_5708)
Yang Hongyang50cf1562009-04-06 19:01:14 -07007968 persist_dma_mask = dma_mask = DMA_BIT_MASK(40);
Michael Chan40453c82007-05-03 13:19:18 -07007969 else
Yang Hongyang6a355282009-04-06 19:01:13 -07007970 persist_dma_mask = dma_mask = DMA_BIT_MASK(64);
Michael Chan40453c82007-05-03 13:19:18 -07007971
7972 /* Configure DMA attributes. */
7973 if (pci_set_dma_mask(pdev, dma_mask) == 0) {
7974 dev->features |= NETIF_F_HIGHDMA;
7975 rc = pci_set_consistent_dma_mask(pdev, persist_dma_mask);
7976 if (rc) {
7977 dev_err(&pdev->dev,
7978 "pci_set_consistent_dma_mask failed, aborting.\n");
7979 goto err_out_unmap;
7980 }
Yang Hongyang284901a2009-04-06 19:01:15 -07007981 } else if ((rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) != 0) {
Michael Chan40453c82007-05-03 13:19:18 -07007982 dev_err(&pdev->dev, "System does not support DMA, aborting.\n");
7983 goto err_out_unmap;
7984 }
7985
David S. Millerf86e82f2008-01-21 17:15:40 -08007986 if (!(bp->flags & BNX2_FLAG_PCIE))
Michael Chan883e5152007-05-03 13:25:11 -07007987 bnx2_get_pci_speed(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07007988
7989 /* 5706A0 may falsely detect SERR and PERR. */
7990 if (CHIP_ID(bp) == CHIP_ID_5706_A0) {
7991 reg = REG_RD(bp, PCI_COMMAND);
7992 reg &= ~(PCI_COMMAND_SERR | PCI_COMMAND_PARITY);
7993 REG_WR(bp, PCI_COMMAND, reg);
7994 }
7995 else if ((CHIP_ID(bp) == CHIP_ID_5706_A1) &&
David S. Millerf86e82f2008-01-21 17:15:40 -08007996 !(bp->flags & BNX2_FLAG_PCIX)) {
Michael Chanb6016b72005-05-26 13:03:09 -07007997
Jeff Garzik9b91cf92006-06-27 11:39:50 -04007998 dev_err(&pdev->dev,
Jeff Garzik2e8a5382006-06-27 10:47:51 -04007999 "5706 A1 can only be used in a PCIX bus, aborting.\n");
Michael Chanb6016b72005-05-26 13:03:09 -07008000 goto err_out_unmap;
8001 }
8002
8003 bnx2_init_nvram(bp);
8004
Michael Chan2726d6e2008-01-29 21:35:05 -08008005 reg = bnx2_reg_rd_ind(bp, BNX2_SHM_HDR_SIGNATURE);
Michael Chane3648b32005-11-04 08:51:21 -08008006
8007 if ((reg & BNX2_SHM_HDR_SIGNATURE_SIG_MASK) ==
Michael Chan24cb2302007-01-25 15:49:56 -08008008 BNX2_SHM_HDR_SIGNATURE_SIG) {
8009 u32 off = PCI_FUNC(pdev->devfn) << 2;
8010
Michael Chan2726d6e2008-01-29 21:35:05 -08008011 bp->shmem_base = bnx2_reg_rd_ind(bp, BNX2_SHM_HDR_ADDR_0 + off);
Michael Chan24cb2302007-01-25 15:49:56 -08008012 } else
Michael Chane3648b32005-11-04 08:51:21 -08008013 bp->shmem_base = HOST_VIEW_SHMEM_BASE;
8014
Michael Chanb6016b72005-05-26 13:03:09 -07008015 /* Get the permanent MAC address. First we need to make sure the
8016 * firmware is actually running.
8017 */
Michael Chan2726d6e2008-01-29 21:35:05 -08008018 reg = bnx2_shmem_rd(bp, BNX2_DEV_INFO_SIGNATURE);
Michael Chanb6016b72005-05-26 13:03:09 -07008019
8020 if ((reg & BNX2_DEV_INFO_SIGNATURE_MAGIC_MASK) !=
8021 BNX2_DEV_INFO_SIGNATURE_MAGIC) {
Jeff Garzik9b91cf92006-06-27 11:39:50 -04008022 dev_err(&pdev->dev, "Firmware not running, aborting.\n");
Michael Chanb6016b72005-05-26 13:03:09 -07008023 rc = -ENODEV;
8024 goto err_out_unmap;
8025 }
8026
Michael Chan76d99062009-12-03 09:46:34 +00008027 bnx2_read_vpd_fw_ver(bp);
8028
8029 j = strlen(bp->fw_version);
Michael Chan2726d6e2008-01-29 21:35:05 -08008030 reg = bnx2_shmem_rd(bp, BNX2_DEV_INFO_BC_REV);
Michael Chan76d99062009-12-03 09:46:34 +00008031 for (i = 0; i < 3 && j < 24; i++) {
Michael Chan58fc2ea2007-07-07 22:52:02 -07008032 u8 num, k, skip0;
8033
Michael Chan76d99062009-12-03 09:46:34 +00008034 if (i == 0) {
8035 bp->fw_version[j++] = 'b';
8036 bp->fw_version[j++] = 'c';
8037 bp->fw_version[j++] = ' ';
8038 }
Michael Chan58fc2ea2007-07-07 22:52:02 -07008039 num = (u8) (reg >> (24 - (i * 8)));
8040 for (k = 100, skip0 = 1; k >= 1; num %= k, k /= 10) {
8041 if (num >= k || !skip0 || k == 1) {
8042 bp->fw_version[j++] = (num / k) + '0';
8043 skip0 = 0;
8044 }
8045 }
8046 if (i != 2)
8047 bp->fw_version[j++] = '.';
8048 }
Michael Chan2726d6e2008-01-29 21:35:05 -08008049 reg = bnx2_shmem_rd(bp, BNX2_PORT_FEATURE);
Michael Chan846f5c62007-10-10 16:16:51 -07008050 if (reg & BNX2_PORT_FEATURE_WOL_ENABLED)
8051 bp->wol = 1;
8052
8053 if (reg & BNX2_PORT_FEATURE_ASF_ENABLED) {
David S. Millerf86e82f2008-01-21 17:15:40 -08008054 bp->flags |= BNX2_FLAG_ASF_ENABLE;
Michael Chanc2d3db82007-07-16 18:26:43 -07008055
8056 for (i = 0; i < 30; i++) {
Michael Chan2726d6e2008-01-29 21:35:05 -08008057 reg = bnx2_shmem_rd(bp, BNX2_BC_STATE_CONDITION);
Michael Chanc2d3db82007-07-16 18:26:43 -07008058 if (reg & BNX2_CONDITION_MFW_RUN_MASK)
8059 break;
8060 msleep(10);
8061 }
8062 }
Michael Chan2726d6e2008-01-29 21:35:05 -08008063 reg = bnx2_shmem_rd(bp, BNX2_BC_STATE_CONDITION);
Michael Chan58fc2ea2007-07-07 22:52:02 -07008064 reg &= BNX2_CONDITION_MFW_RUN_MASK;
8065 if (reg != BNX2_CONDITION_MFW_RUN_UNKNOWN &&
8066 reg != BNX2_CONDITION_MFW_RUN_NONE) {
Michael Chan2726d6e2008-01-29 21:35:05 -08008067 u32 addr = bnx2_shmem_rd(bp, BNX2_MFW_VER_PTR);
Michael Chan58fc2ea2007-07-07 22:52:02 -07008068
Michael Chan76d99062009-12-03 09:46:34 +00008069 if (j < 32)
8070 bp->fw_version[j++] = ' ';
8071 for (i = 0; i < 3 && j < 28; i++) {
Michael Chan2726d6e2008-01-29 21:35:05 -08008072 reg = bnx2_reg_rd_ind(bp, addr + i * 4);
Michael Chan58fc2ea2007-07-07 22:52:02 -07008073 reg = swab32(reg);
8074 memcpy(&bp->fw_version[j], &reg, 4);
8075 j += 4;
8076 }
8077 }
Michael Chanb6016b72005-05-26 13:03:09 -07008078
Michael Chan2726d6e2008-01-29 21:35:05 -08008079 reg = bnx2_shmem_rd(bp, BNX2_PORT_HW_CFG_MAC_UPPER);
Michael Chanb6016b72005-05-26 13:03:09 -07008080 bp->mac_addr[0] = (u8) (reg >> 8);
8081 bp->mac_addr[1] = (u8) reg;
8082
Michael Chan2726d6e2008-01-29 21:35:05 -08008083 reg = bnx2_shmem_rd(bp, BNX2_PORT_HW_CFG_MAC_LOWER);
Michael Chanb6016b72005-05-26 13:03:09 -07008084 bp->mac_addr[2] = (u8) (reg >> 24);
8085 bp->mac_addr[3] = (u8) (reg >> 16);
8086 bp->mac_addr[4] = (u8) (reg >> 8);
8087 bp->mac_addr[5] = (u8) reg;
8088
8089 bp->tx_ring_size = MAX_TX_DESC_CNT;
Michael Chan932f3772006-08-15 01:39:36 -07008090 bnx2_set_rx_ring_size(bp, 255);
Michael Chanb6016b72005-05-26 13:03:09 -07008091
8092 bp->rx_csum = 1;
8093
Michael Chancf7474a2009-08-21 16:20:48 +00008094 bp->tx_quick_cons_trip_int = 2;
Michael Chanb6016b72005-05-26 13:03:09 -07008095 bp->tx_quick_cons_trip = 20;
Michael Chancf7474a2009-08-21 16:20:48 +00008096 bp->tx_ticks_int = 18;
Michael Chanb6016b72005-05-26 13:03:09 -07008097 bp->tx_ticks = 80;
Jeff Garzik6aa20a22006-09-13 13:24:59 -04008098
Michael Chancf7474a2009-08-21 16:20:48 +00008099 bp->rx_quick_cons_trip_int = 2;
8100 bp->rx_quick_cons_trip = 12;
Michael Chanb6016b72005-05-26 13:03:09 -07008101 bp->rx_ticks_int = 18;
8102 bp->rx_ticks = 18;
8103
Michael Chan7ea69202007-07-16 18:27:10 -07008104 bp->stats_ticks = USEC_PER_SEC & BNX2_HC_STATS_TICKS_HC_STAT_TICKS;
Michael Chanb6016b72005-05-26 13:03:09 -07008105
Benjamin Liac392ab2008-09-18 16:40:49 -07008106 bp->current_interval = BNX2_TIMER_INTERVAL;
Michael Chanb6016b72005-05-26 13:03:09 -07008107
Michael Chan5b0c76a2005-11-04 08:45:49 -08008108 bp->phy_addr = 1;
8109
Michael Chanb6016b72005-05-26 13:03:09 -07008110 /* Disable WOL support if we are running on a SERDES chip. */
Michael Chan253c8b72007-01-08 19:56:01 -08008111 if (CHIP_NUM(bp) == CHIP_NUM_5709)
8112 bnx2_get_5709_media(bp);
8113 else if (CHIP_BOND_ID(bp) & CHIP_BOND_ID_SERDES_BIT)
Michael Chan583c28e2008-01-21 19:51:35 -08008114 bp->phy_flags |= BNX2_PHY_FLAG_SERDES;
Michael Chanbac0dff2006-11-19 14:15:05 -08008115
Michael Chan0d8a6572007-07-07 22:49:43 -07008116 bp->phy_port = PORT_TP;
Michael Chan583c28e2008-01-21 19:51:35 -08008117 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Michael Chan0d8a6572007-07-07 22:49:43 -07008118 bp->phy_port = PORT_FIBRE;
Michael Chan2726d6e2008-01-29 21:35:05 -08008119 reg = bnx2_shmem_rd(bp, BNX2_SHARED_HW_CFG_CONFIG);
Michael Chan846f5c62007-10-10 16:16:51 -07008120 if (!(reg & BNX2_SHARED_HW_CFG_GIG_LINK_ON_VAUX)) {
David S. Millerf86e82f2008-01-21 17:15:40 -08008121 bp->flags |= BNX2_FLAG_NO_WOL;
Michael Chan846f5c62007-10-10 16:16:51 -07008122 bp->wol = 0;
8123 }
Michael Chan38ea3682008-02-23 19:48:57 -08008124 if (CHIP_NUM(bp) == CHIP_NUM_5706) {
8125 /* Don't do parallel detect on this board because of
8126 * some board problems. The link will not go down
8127 * if we do parallel detect.
8128 */
8129 if (pdev->subsystem_vendor == PCI_VENDOR_ID_HP &&
8130 pdev->subsystem_device == 0x310c)
8131 bp->phy_flags |= BNX2_PHY_FLAG_NO_PARALLEL;
8132 } else {
Michael Chan5b0c76a2005-11-04 08:45:49 -08008133 bp->phy_addr = 2;
Michael Chan5b0c76a2005-11-04 08:45:49 -08008134 if (reg & BNX2_SHARED_HW_CFG_PHY_2_5G)
Michael Chan583c28e2008-01-21 19:51:35 -08008135 bp->phy_flags |= BNX2_PHY_FLAG_2_5G_CAPABLE;
Michael Chan5b0c76a2005-11-04 08:45:49 -08008136 }
Michael Chan261dd5c2007-01-08 19:55:46 -08008137 } else if (CHIP_NUM(bp) == CHIP_NUM_5706 ||
8138 CHIP_NUM(bp) == CHIP_NUM_5708)
Michael Chan583c28e2008-01-21 19:51:35 -08008139 bp->phy_flags |= BNX2_PHY_FLAG_CRC_FIX;
Michael Chanfb0c18b2007-12-10 17:18:23 -08008140 else if (CHIP_NUM(bp) == CHIP_NUM_5709 &&
8141 (CHIP_REV(bp) == CHIP_REV_Ax ||
8142 CHIP_REV(bp) == CHIP_REV_Bx))
Michael Chan583c28e2008-01-21 19:51:35 -08008143 bp->phy_flags |= BNX2_PHY_FLAG_DIS_EARLY_DAC;
Michael Chanb6016b72005-05-26 13:03:09 -07008144
Michael Chan7c62e832008-07-14 22:39:03 -07008145 bnx2_init_fw_cap(bp);
8146
Michael Chan16088272006-06-12 22:16:43 -07008147 if ((CHIP_ID(bp) == CHIP_ID_5708_A0) ||
8148 (CHIP_ID(bp) == CHIP_ID_5708_B0) ||
Michael Chan5ec6d7b2008-11-12 16:01:41 -08008149 (CHIP_ID(bp) == CHIP_ID_5708_B1) ||
8150 !(REG_RD(bp, BNX2_PCI_CONFIG_3) & BNX2_PCI_CONFIG_3_VAUX_PRESET)) {
David S. Millerf86e82f2008-01-21 17:15:40 -08008151 bp->flags |= BNX2_FLAG_NO_WOL;
Michael Chan846f5c62007-10-10 16:16:51 -07008152 bp->wol = 0;
8153 }
Michael Chandda1e392006-01-23 16:08:14 -08008154
Michael Chanb6016b72005-05-26 13:03:09 -07008155 if (CHIP_ID(bp) == CHIP_ID_5706_A0) {
8156 bp->tx_quick_cons_trip_int =
8157 bp->tx_quick_cons_trip;
8158 bp->tx_ticks_int = bp->tx_ticks;
8159 bp->rx_quick_cons_trip_int =
8160 bp->rx_quick_cons_trip;
8161 bp->rx_ticks_int = bp->rx_ticks;
8162 bp->comp_prod_trip_int = bp->comp_prod_trip;
8163 bp->com_ticks_int = bp->com_ticks;
8164 bp->cmd_ticks_int = bp->cmd_ticks;
8165 }
8166
Michael Chanf9317a42006-09-29 17:06:23 -07008167 /* Disable MSI on 5706 if AMD 8132 bridge is found.
8168 *
8169 * MSI is defined to be 32-bit write. The 5706 does 64-bit MSI writes
8170 * with byte enables disabled on the unused 32-bit word. This is legal
8171 * but causes problems on the AMD 8132 which will eventually stop
8172 * responding after a while.
8173 *
8174 * AMD believes this incompatibility is unique to the 5706, and
Michael Ellerman88187df2007-01-25 19:34:07 +11008175 * prefers to locally disable MSI rather than globally disabling it.
Michael Chanf9317a42006-09-29 17:06:23 -07008176 */
8177 if (CHIP_NUM(bp) == CHIP_NUM_5706 && disable_msi == 0) {
8178 struct pci_dev *amd_8132 = NULL;
8179
8180 while ((amd_8132 = pci_get_device(PCI_VENDOR_ID_AMD,
8181 PCI_DEVICE_ID_AMD_8132_BRIDGE,
8182 amd_8132))) {
Michael Chanf9317a42006-09-29 17:06:23 -07008183
Auke Kok44c10132007-06-08 15:46:36 -07008184 if (amd_8132->revision >= 0x10 &&
8185 amd_8132->revision <= 0x13) {
Michael Chanf9317a42006-09-29 17:06:23 -07008186 disable_msi = 1;
8187 pci_dev_put(amd_8132);
8188 break;
8189 }
8190 }
8191 }
8192
Michael Chandeaf3912007-07-07 22:48:00 -07008193 bnx2_set_default_link(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07008194 bp->req_flow_ctrl = FLOW_CTRL_RX | FLOW_CTRL_TX;
8195
Michael Chancd339a02005-08-25 15:35:24 -07008196 init_timer(&bp->timer);
Benjamin Liac392ab2008-09-18 16:40:49 -07008197 bp->timer.expires = RUN_AT(BNX2_TIMER_INTERVAL);
Michael Chancd339a02005-08-25 15:35:24 -07008198 bp->timer.data = (unsigned long) bp;
8199 bp->timer.function = bnx2_timer;
8200
Michael Chanb6016b72005-05-26 13:03:09 -07008201 return 0;
8202
8203err_out_unmap:
8204 if (bp->regview) {
8205 iounmap(bp->regview);
Michael Chan73eef4c2005-08-25 15:39:15 -07008206 bp->regview = NULL;
Michael Chanb6016b72005-05-26 13:03:09 -07008207 }
8208
8209err_out_release:
8210 pci_release_regions(pdev);
8211
8212err_out_disable:
8213 pci_disable_device(pdev);
8214 pci_set_drvdata(pdev, NULL);
8215
8216err_out:
8217 return rc;
8218}
8219
Michael Chan883e5152007-05-03 13:25:11 -07008220static char * __devinit
8221bnx2_bus_string(struct bnx2 *bp, char *str)
8222{
8223 char *s = str;
8224
David S. Millerf86e82f2008-01-21 17:15:40 -08008225 if (bp->flags & BNX2_FLAG_PCIE) {
Michael Chan883e5152007-05-03 13:25:11 -07008226 s += sprintf(s, "PCI Express");
8227 } else {
8228 s += sprintf(s, "PCI");
David S. Millerf86e82f2008-01-21 17:15:40 -08008229 if (bp->flags & BNX2_FLAG_PCIX)
Michael Chan883e5152007-05-03 13:25:11 -07008230 s += sprintf(s, "-X");
David S. Millerf86e82f2008-01-21 17:15:40 -08008231 if (bp->flags & BNX2_FLAG_PCI_32BIT)
Michael Chan883e5152007-05-03 13:25:11 -07008232 s += sprintf(s, " 32-bit");
8233 else
8234 s += sprintf(s, " 64-bit");
8235 s += sprintf(s, " %dMHz", bp->bus_speed_mhz);
8236 }
8237 return str;
8238}
8239
Michael Chan2ba582b2007-12-21 15:04:49 -08008240static void __devinit
Michael Chan35efa7c2007-12-20 19:56:37 -08008241bnx2_init_napi(struct bnx2 *bp)
8242{
Michael Chanb4b36042007-12-20 19:59:30 -08008243 int i;
Michael Chan35efa7c2007-12-20 19:56:37 -08008244
Michael Chanb4b36042007-12-20 19:59:30 -08008245 for (i = 0; i < BNX2_MAX_MSIX_VEC; i++) {
Michael Chan35e90102008-06-19 16:37:42 -07008246 struct bnx2_napi *bnapi = &bp->bnx2_napi[i];
8247 int (*poll)(struct napi_struct *, int);
8248
8249 if (i == 0)
8250 poll = bnx2_poll;
8251 else
Michael Chanf0ea2e62008-06-19 16:41:57 -07008252 poll = bnx2_poll_msix;
Michael Chan35e90102008-06-19 16:37:42 -07008253
8254 netif_napi_add(bp->dev, &bp->bnx2_napi[i].napi, poll, 64);
Michael Chanb4b36042007-12-20 19:59:30 -08008255 bnapi->bp = bp;
8256 }
Michael Chan35efa7c2007-12-20 19:56:37 -08008257}
8258
Stephen Hemminger0421eae2008-11-21 17:31:27 -08008259static const struct net_device_ops bnx2_netdev_ops = {
8260 .ndo_open = bnx2_open,
8261 .ndo_start_xmit = bnx2_start_xmit,
8262 .ndo_stop = bnx2_close,
8263 .ndo_get_stats = bnx2_get_stats,
8264 .ndo_set_rx_mode = bnx2_set_rx_mode,
8265 .ndo_do_ioctl = bnx2_ioctl,
8266 .ndo_validate_addr = eth_validate_addr,
8267 .ndo_set_mac_address = bnx2_change_mac_addr,
8268 .ndo_change_mtu = bnx2_change_mtu,
8269 .ndo_tx_timeout = bnx2_tx_timeout,
8270#ifdef BCM_VLAN
8271 .ndo_vlan_rx_register = bnx2_vlan_rx_register,
8272#endif
Alexey Dobriyan257ddbd2010-01-27 10:17:41 +00008273#ifdef CONFIG_NET_POLL_CONTROLLER
Stephen Hemminger0421eae2008-11-21 17:31:27 -08008274 .ndo_poll_controller = poll_bnx2,
8275#endif
8276};
8277
Eric Dumazet72dccb02009-07-23 02:01:38 +00008278static void inline vlan_features_add(struct net_device *dev, unsigned long flags)
8279{
8280#ifdef BCM_VLAN
8281 dev->vlan_features |= flags;
8282#endif
8283}
8284
Michael Chan35efa7c2007-12-20 19:56:37 -08008285static int __devinit
Michael Chanb6016b72005-05-26 13:03:09 -07008286bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
8287{
8288 static int version_printed = 0;
8289 struct net_device *dev = NULL;
8290 struct bnx2 *bp;
Joe Perches0795af52007-10-03 17:59:30 -07008291 int rc;
Michael Chan883e5152007-05-03 13:25:11 -07008292 char str[40];
Michael Chanb6016b72005-05-26 13:03:09 -07008293
8294 if (version_printed++ == 0)
8295 printk(KERN_INFO "%s", version);
8296
8297 /* dev zeroed in init_etherdev */
Benjamin Li706bf242008-07-18 17:55:11 -07008298 dev = alloc_etherdev_mq(sizeof(*bp), TX_MAX_RINGS);
Michael Chanb6016b72005-05-26 13:03:09 -07008299
8300 if (!dev)
8301 return -ENOMEM;
8302
8303 rc = bnx2_init_board(pdev, dev);
8304 if (rc < 0) {
8305 free_netdev(dev);
8306 return rc;
8307 }
8308
Stephen Hemminger0421eae2008-11-21 17:31:27 -08008309 dev->netdev_ops = &bnx2_netdev_ops;
Michael Chanb6016b72005-05-26 13:03:09 -07008310 dev->watchdog_timeo = TX_TIMEOUT;
Michael Chanb6016b72005-05-26 13:03:09 -07008311 dev->ethtool_ops = &bnx2_ethtool_ops;
Michael Chanb6016b72005-05-26 13:03:09 -07008312
Michael Chan972ec0d2006-01-23 16:12:43 -08008313 bp = netdev_priv(dev);
Michael Chan35efa7c2007-12-20 19:56:37 -08008314 bnx2_init_napi(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07008315
Michael Chan1b2f9222007-05-03 13:20:19 -07008316 pci_set_drvdata(pdev, dev);
8317
Michael Chan57579f72009-04-04 16:51:14 -07008318 rc = bnx2_request_firmware(bp);
8319 if (rc)
8320 goto error;
8321
Michael Chan1b2f9222007-05-03 13:20:19 -07008322 memcpy(dev->dev_addr, bp->mac_addr, 6);
8323 memcpy(dev->perm_addr, bp->mac_addr, 6);
Michael Chan1b2f9222007-05-03 13:20:19 -07008324
Stephen Hemmingerd212f872007-06-27 00:47:37 -07008325 dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG;
Eric Dumazet72dccb02009-07-23 02:01:38 +00008326 vlan_features_add(dev, NETIF_F_IP_CSUM | NETIF_F_SG);
8327 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
Stephen Hemmingerd212f872007-06-27 00:47:37 -07008328 dev->features |= NETIF_F_IPV6_CSUM;
Eric Dumazet72dccb02009-07-23 02:01:38 +00008329 vlan_features_add(dev, NETIF_F_IPV6_CSUM);
8330 }
Michael Chan1b2f9222007-05-03 13:20:19 -07008331#ifdef BCM_VLAN
8332 dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
8333#endif
8334 dev->features |= NETIF_F_TSO | NETIF_F_TSO_ECN;
Eric Dumazet72dccb02009-07-23 02:01:38 +00008335 vlan_features_add(dev, NETIF_F_TSO | NETIF_F_TSO_ECN);
8336 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
Michael Chan4666f872007-05-03 13:22:28 -07008337 dev->features |= NETIF_F_TSO6;
Eric Dumazet72dccb02009-07-23 02:01:38 +00008338 vlan_features_add(dev, NETIF_F_TSO6);
8339 }
Michael Chanb6016b72005-05-26 13:03:09 -07008340 if ((rc = register_netdev(dev))) {
Jeff Garzik9b91cf92006-06-27 11:39:50 -04008341 dev_err(&pdev->dev, "Cannot register net device\n");
Michael Chan57579f72009-04-04 16:51:14 -07008342 goto error;
Michael Chanb6016b72005-05-26 13:03:09 -07008343 }
8344
Michael Chan883e5152007-05-03 13:25:11 -07008345 printk(KERN_INFO "%s: %s (%c%d) %s found at mem %lx, "
Johannes Berge1749612008-10-27 15:59:26 -07008346 "IRQ %d, node addr %pM\n",
Michael Chanb6016b72005-05-26 13:03:09 -07008347 dev->name,
Benjamin Lifbbf68b2008-09-18 16:40:03 -07008348 board_info[ent->driver_data].name,
Michael Chanb6016b72005-05-26 13:03:09 -07008349 ((CHIP_ID(bp) & 0xf000) >> 12) + 'A',
8350 ((CHIP_ID(bp) & 0x0ff0) >> 4),
Michael Chan883e5152007-05-03 13:25:11 -07008351 bnx2_bus_string(bp, str),
Michael Chanb6016b72005-05-26 13:03:09 -07008352 dev->base_addr,
Johannes Berge1749612008-10-27 15:59:26 -07008353 bp->pdev->irq, dev->dev_addr);
Michael Chanb6016b72005-05-26 13:03:09 -07008354
Michael Chanb6016b72005-05-26 13:03:09 -07008355 return 0;
Michael Chan57579f72009-04-04 16:51:14 -07008356
8357error:
8358 if (bp->mips_firmware)
8359 release_firmware(bp->mips_firmware);
8360 if (bp->rv2p_firmware)
8361 release_firmware(bp->rv2p_firmware);
8362
8363 if (bp->regview)
8364 iounmap(bp->regview);
8365 pci_release_regions(pdev);
8366 pci_disable_device(pdev);
8367 pci_set_drvdata(pdev, NULL);
8368 free_netdev(dev);
8369 return rc;
Michael Chanb6016b72005-05-26 13:03:09 -07008370}
8371
8372static void __devexit
8373bnx2_remove_one(struct pci_dev *pdev)
8374{
8375 struct net_device *dev = pci_get_drvdata(pdev);
Michael Chan972ec0d2006-01-23 16:12:43 -08008376 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07008377
Michael Chanafdc08b2005-08-25 15:34:29 -07008378 flush_scheduled_work();
8379
Michael Chanb6016b72005-05-26 13:03:09 -07008380 unregister_netdev(dev);
8381
Michael Chan57579f72009-04-04 16:51:14 -07008382 if (bp->mips_firmware)
8383 release_firmware(bp->mips_firmware);
8384 if (bp->rv2p_firmware)
8385 release_firmware(bp->rv2p_firmware);
8386
Michael Chanb6016b72005-05-26 13:03:09 -07008387 if (bp->regview)
8388 iounmap(bp->regview);
8389
Michael Chan354fcd72010-01-17 07:30:44 +00008390 kfree(bp->temp_stats_blk);
8391
Michael Chanb6016b72005-05-26 13:03:09 -07008392 free_netdev(dev);
8393 pci_release_regions(pdev);
8394 pci_disable_device(pdev);
8395 pci_set_drvdata(pdev, NULL);
8396}
8397
8398static int
Pavel Machek829ca9a2005-09-03 15:56:56 -07008399bnx2_suspend(struct pci_dev *pdev, pm_message_t state)
Michael Chanb6016b72005-05-26 13:03:09 -07008400{
8401 struct net_device *dev = pci_get_drvdata(pdev);
Michael Chan972ec0d2006-01-23 16:12:43 -08008402 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07008403
Michael Chan6caebb02007-08-03 20:57:25 -07008404 /* PCI register 4 needs to be saved whether netif_running() or not.
8405 * MSI address and data need to be saved if using MSI and
8406 * netif_running().
8407 */
8408 pci_save_state(pdev);
Michael Chanb6016b72005-05-26 13:03:09 -07008409 if (!netif_running(dev))
8410 return 0;
8411
Michael Chan1d60290f2006-03-20 17:50:08 -08008412 flush_scheduled_work();
Michael Chanb6016b72005-05-26 13:03:09 -07008413 bnx2_netif_stop(bp);
8414 netif_device_detach(dev);
8415 del_timer_sync(&bp->timer);
Michael Chan74bf4ba2008-10-09 12:21:08 -07008416 bnx2_shutdown_chip(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07008417 bnx2_free_skbs(bp);
Pavel Machek829ca9a2005-09-03 15:56:56 -07008418 bnx2_set_power_state(bp, pci_choose_state(pdev, state));
Michael Chanb6016b72005-05-26 13:03:09 -07008419 return 0;
8420}
8421
8422static int
8423bnx2_resume(struct pci_dev *pdev)
8424{
8425 struct net_device *dev = pci_get_drvdata(pdev);
Michael Chan972ec0d2006-01-23 16:12:43 -08008426 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07008427
Michael Chan6caebb02007-08-03 20:57:25 -07008428 pci_restore_state(pdev);
Michael Chanb6016b72005-05-26 13:03:09 -07008429 if (!netif_running(dev))
8430 return 0;
8431
Pavel Machek829ca9a2005-09-03 15:56:56 -07008432 bnx2_set_power_state(bp, PCI_D0);
Michael Chanb6016b72005-05-26 13:03:09 -07008433 netif_device_attach(dev);
Michael Chan9a120bc2008-05-16 22:17:45 -07008434 bnx2_init_nic(bp, 1);
Michael Chanb6016b72005-05-26 13:03:09 -07008435 bnx2_netif_start(bp);
8436 return 0;
8437}
8438
Wendy Xiong6ff2da42008-05-16 22:18:21 -07008439/**
8440 * bnx2_io_error_detected - called when PCI error is detected
8441 * @pdev: Pointer to PCI device
8442 * @state: The current pci connection state
8443 *
8444 * This function is called after a PCI bus error affecting
8445 * this device has been detected.
8446 */
8447static pci_ers_result_t bnx2_io_error_detected(struct pci_dev *pdev,
8448 pci_channel_state_t state)
8449{
8450 struct net_device *dev = pci_get_drvdata(pdev);
8451 struct bnx2 *bp = netdev_priv(dev);
8452
8453 rtnl_lock();
8454 netif_device_detach(dev);
8455
Dean Nelson2ec3de22009-07-31 09:13:18 +00008456 if (state == pci_channel_io_perm_failure) {
8457 rtnl_unlock();
8458 return PCI_ERS_RESULT_DISCONNECT;
8459 }
8460
Wendy Xiong6ff2da42008-05-16 22:18:21 -07008461 if (netif_running(dev)) {
8462 bnx2_netif_stop(bp);
8463 del_timer_sync(&bp->timer);
8464 bnx2_reset_nic(bp, BNX2_DRV_MSG_CODE_RESET);
8465 }
8466
8467 pci_disable_device(pdev);
8468 rtnl_unlock();
8469
8470 /* Request a slot slot reset. */
8471 return PCI_ERS_RESULT_NEED_RESET;
8472}
8473
8474/**
8475 * bnx2_io_slot_reset - called after the pci bus has been reset.
8476 * @pdev: Pointer to PCI device
8477 *
8478 * Restart the card from scratch, as if from a cold-boot.
8479 */
8480static pci_ers_result_t bnx2_io_slot_reset(struct pci_dev *pdev)
8481{
8482 struct net_device *dev = pci_get_drvdata(pdev);
8483 struct bnx2 *bp = netdev_priv(dev);
8484
8485 rtnl_lock();
8486 if (pci_enable_device(pdev)) {
8487 dev_err(&pdev->dev,
8488 "Cannot re-enable PCI device after reset.\n");
8489 rtnl_unlock();
8490 return PCI_ERS_RESULT_DISCONNECT;
8491 }
8492 pci_set_master(pdev);
8493 pci_restore_state(pdev);
Breno Leitao529fab62009-11-26 07:31:49 +00008494 pci_save_state(pdev);
Wendy Xiong6ff2da42008-05-16 22:18:21 -07008495
8496 if (netif_running(dev)) {
8497 bnx2_set_power_state(bp, PCI_D0);
8498 bnx2_init_nic(bp, 1);
8499 }
8500
8501 rtnl_unlock();
8502 return PCI_ERS_RESULT_RECOVERED;
8503}
8504
8505/**
8506 * bnx2_io_resume - called when traffic can start flowing again.
8507 * @pdev: Pointer to PCI device
8508 *
8509 * This callback is called when the error recovery driver tells us that
8510 * its OK to resume normal operation.
8511 */
8512static void bnx2_io_resume(struct pci_dev *pdev)
8513{
8514 struct net_device *dev = pci_get_drvdata(pdev);
8515 struct bnx2 *bp = netdev_priv(dev);
8516
8517 rtnl_lock();
8518 if (netif_running(dev))
8519 bnx2_netif_start(bp);
8520
8521 netif_device_attach(dev);
8522 rtnl_unlock();
8523}
8524
8525static struct pci_error_handlers bnx2_err_handler = {
8526 .error_detected = bnx2_io_error_detected,
8527 .slot_reset = bnx2_io_slot_reset,
8528 .resume = bnx2_io_resume,
8529};
8530
Michael Chanb6016b72005-05-26 13:03:09 -07008531static struct pci_driver bnx2_pci_driver = {
Peter Hagervall14ab9b82005-08-10 14:18:16 -07008532 .name = DRV_MODULE_NAME,
8533 .id_table = bnx2_pci_tbl,
8534 .probe = bnx2_init_one,
8535 .remove = __devexit_p(bnx2_remove_one),
8536 .suspend = bnx2_suspend,
8537 .resume = bnx2_resume,
Wendy Xiong6ff2da42008-05-16 22:18:21 -07008538 .err_handler = &bnx2_err_handler,
Michael Chanb6016b72005-05-26 13:03:09 -07008539};
8540
8541static int __init bnx2_init(void)
8542{
Jeff Garzik29917622006-08-19 17:48:59 -04008543 return pci_register_driver(&bnx2_pci_driver);
Michael Chanb6016b72005-05-26 13:03:09 -07008544}
8545
8546static void __exit bnx2_cleanup(void)
8547{
8548 pci_unregister_driver(&bnx2_pci_driver);
8549}
8550
8551module_init(bnx2_init);
8552module_exit(bnx2_cleanup);
8553
8554
8555