blob: ecfaad102f70c8d984c42471d17d6586acc6c662 [file] [log] [blame]
Michael Chanb6016b72005-05-26 13:03:09 -07001/* bnx2.c: Broadcom NX2 network driver.
2 *
Michael Chan72fbaeb2007-05-03 13:25:32 -07003 * Copyright (c) 2004-2007 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>
38#ifdef NETIF_F_HW_VLAN_TX
39#include <linux/if_vlan.h>
40#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 Chanfba9fe92006-06-12 22:21:25 -070049#include <linux/zlib.h>
Michael Chanf2a4f052006-03-23 01:13:12 -080050
Michael Chanb6016b72005-05-26 13:03:09 -070051#include "bnx2.h"
52#include "bnx2_fw.h"
Michael Chand43584c2006-11-19 14:14:35 -080053#include "bnx2_fw2.h"
Michael Chanb6016b72005-05-26 13:03:09 -070054
Michael Chan110d0ef2007-12-12 11:18:34 -080055#define FW_BUF_SIZE 0x10000
Denys Vlasenkob3448b02007-09-30 17:55:51 -070056
Michael Chanb6016b72005-05-26 13:03:09 -070057#define DRV_MODULE_NAME "bnx2"
58#define PFX DRV_MODULE_NAME ": "
Michael Chana0d142c2007-12-12 11:20:22 -080059#define DRV_MODULE_VERSION "1.7.0"
60#define DRV_MODULE_RELDATE "December 11, 2007"
Michael Chanb6016b72005-05-26 13:03:09 -070061
62#define RUN_AT(x) (jiffies + (x))
63
64/* Time in jiffies before concluding the transmitter is hung. */
65#define TX_TIMEOUT (5*HZ)
66
Randy Dunlape19360f2006-04-10 23:22:06 -070067static const char version[] __devinitdata =
Michael Chanb6016b72005-05-26 13:03:09 -070068 "Broadcom NetXtreme II Gigabit Ethernet Driver " DRV_MODULE_NAME " v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";
69
70MODULE_AUTHOR("Michael Chan <mchan@broadcom.com>");
Michael Chan05d0f1c2005-11-04 08:53:48 -080071MODULE_DESCRIPTION("Broadcom NetXtreme II BCM5706/5708 Driver");
Michael Chanb6016b72005-05-26 13:03:09 -070072MODULE_LICENSE("GPL");
73MODULE_VERSION(DRV_MODULE_VERSION);
74
75static int disable_msi = 0;
76
77module_param(disable_msi, int, 0);
78MODULE_PARM_DESC(disable_msi, "Disable Message Signaled Interrupt (MSI)");
79
80typedef enum {
81 BCM5706 = 0,
82 NC370T,
83 NC370I,
84 BCM5706S,
85 NC370F,
Michael Chan5b0c76a2005-11-04 08:45:49 -080086 BCM5708,
87 BCM5708S,
Michael Chanbac0dff2006-11-19 14:15:05 -080088 BCM5709,
Michael Chan27a005b2007-05-03 13:23:41 -070089 BCM5709S,
Michael Chanb6016b72005-05-26 13:03:09 -070090} board_t;
91
92/* indexed by board_t, above */
Arjan van de Venf71e1302006-03-03 21:33:57 -050093static const struct {
Michael Chanb6016b72005-05-26 13:03:09 -070094 char *name;
95} board_info[] __devinitdata = {
96 { "Broadcom NetXtreme II BCM5706 1000Base-T" },
97 { "HP NC370T Multifunction Gigabit Server Adapter" },
98 { "HP NC370i Multifunction Gigabit Server Adapter" },
99 { "Broadcom NetXtreme II BCM5706 1000Base-SX" },
100 { "HP NC370F Multifunction Gigabit Server Adapter" },
Michael Chan5b0c76a2005-11-04 08:45:49 -0800101 { "Broadcom NetXtreme II BCM5708 1000Base-T" },
102 { "Broadcom NetXtreme II BCM5708 1000Base-SX" },
Michael Chanbac0dff2006-11-19 14:15:05 -0800103 { "Broadcom NetXtreme II BCM5709 1000Base-T" },
Michael Chan27a005b2007-05-03 13:23:41 -0700104 { "Broadcom NetXtreme II BCM5709 1000Base-SX" },
Michael Chanb6016b72005-05-26 13:03:09 -0700105 };
106
107static struct pci_device_id bnx2_pci_tbl[] = {
108 { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5706,
109 PCI_VENDOR_ID_HP, 0x3101, 0, 0, NC370T },
110 { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5706,
111 PCI_VENDOR_ID_HP, 0x3106, 0, 0, NC370I },
112 { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5706,
113 PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5706 },
Michael Chan5b0c76a2005-11-04 08:45:49 -0800114 { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5708,
115 PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5708 },
Michael Chanb6016b72005-05-26 13:03:09 -0700116 { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5706S,
117 PCI_VENDOR_ID_HP, 0x3102, 0, 0, NC370F },
118 { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5706S,
119 PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5706S },
Michael Chan5b0c76a2005-11-04 08:45:49 -0800120 { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5708S,
121 PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5708S },
Michael Chanbac0dff2006-11-19 14:15:05 -0800122 { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5709,
123 PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5709 },
Michael Chan27a005b2007-05-03 13:23:41 -0700124 { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5709S,
125 PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5709S },
Michael Chanb6016b72005-05-26 13:03:09 -0700126 { 0, }
127};
128
129static struct flash_spec flash_table[] =
130{
Michael Chane30372c2007-07-16 18:26:23 -0700131#define BUFFERED_FLAGS (BNX2_NV_BUFFERED | BNX2_NV_TRANSLATE)
132#define NONBUFFERED_FLAGS (BNX2_NV_WREN)
Michael Chanb6016b72005-05-26 13:03:09 -0700133 /* Slow EEPROM */
Michael Chan37137702005-11-04 08:49:17 -0800134 {0x00000000, 0x40830380, 0x009f0081, 0xa184a053, 0xaf000400,
Michael Chane30372c2007-07-16 18:26:23 -0700135 BUFFERED_FLAGS, SEEPROM_PAGE_BITS, SEEPROM_PAGE_SIZE,
Michael Chanb6016b72005-05-26 13:03:09 -0700136 SEEPROM_BYTE_ADDR_MASK, SEEPROM_TOTAL_SIZE,
137 "EEPROM - slow"},
Michael Chan37137702005-11-04 08:49:17 -0800138 /* Expansion entry 0001 */
139 {0x08000002, 0x4b808201, 0x00050081, 0x03840253, 0xaf020406,
Michael Chane30372c2007-07-16 18:26:23 -0700140 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
Michael Chan37137702005-11-04 08:49:17 -0800141 SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
142 "Entry 0001"},
Michael Chanb6016b72005-05-26 13:03:09 -0700143 /* Saifun SA25F010 (non-buffered flash) */
144 /* strap, cfg1, & write1 need updates */
Michael Chan37137702005-11-04 08:49:17 -0800145 {0x04000001, 0x47808201, 0x00050081, 0x03840253, 0xaf020406,
Michael Chane30372c2007-07-16 18:26:23 -0700146 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
Michael Chanb6016b72005-05-26 13:03:09 -0700147 SAIFUN_FLASH_BYTE_ADDR_MASK, SAIFUN_FLASH_BASE_TOTAL_SIZE*2,
148 "Non-buffered flash (128kB)"},
149 /* Saifun SA25F020 (non-buffered flash) */
150 /* strap, cfg1, & write1 need updates */
Michael Chan37137702005-11-04 08:49:17 -0800151 {0x0c000003, 0x4f808201, 0x00050081, 0x03840253, 0xaf020406,
Michael Chane30372c2007-07-16 18:26:23 -0700152 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
Michael Chanb6016b72005-05-26 13:03:09 -0700153 SAIFUN_FLASH_BYTE_ADDR_MASK, SAIFUN_FLASH_BASE_TOTAL_SIZE*4,
154 "Non-buffered flash (256kB)"},
Michael Chan37137702005-11-04 08:49:17 -0800155 /* Expansion entry 0100 */
156 {0x11000000, 0x53808201, 0x00050081, 0x03840253, 0xaf020406,
Michael Chane30372c2007-07-16 18:26:23 -0700157 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
Michael Chan37137702005-11-04 08:49:17 -0800158 SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
159 "Entry 0100"},
160 /* Entry 0101: ST M45PE10 (non-buffered flash, TetonII B0) */
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400161 {0x19000002, 0x5b808201, 0x000500db, 0x03840253, 0xaf020406,
Michael Chane30372c2007-07-16 18:26:23 -0700162 NONBUFFERED_FLAGS, ST_MICRO_FLASH_PAGE_BITS, ST_MICRO_FLASH_PAGE_SIZE,
Michael Chan37137702005-11-04 08:49:17 -0800163 ST_MICRO_FLASH_BYTE_ADDR_MASK, ST_MICRO_FLASH_BASE_TOTAL_SIZE*2,
164 "Entry 0101: ST M45PE10 (128kB non-bufferred)"},
165 /* Entry 0110: ST M45PE20 (non-buffered flash)*/
166 {0x15000001, 0x57808201, 0x000500db, 0x03840253, 0xaf020406,
Michael Chane30372c2007-07-16 18:26:23 -0700167 NONBUFFERED_FLAGS, ST_MICRO_FLASH_PAGE_BITS, ST_MICRO_FLASH_PAGE_SIZE,
Michael Chan37137702005-11-04 08:49:17 -0800168 ST_MICRO_FLASH_BYTE_ADDR_MASK, ST_MICRO_FLASH_BASE_TOTAL_SIZE*4,
169 "Entry 0110: ST M45PE20 (256kB non-bufferred)"},
170 /* Saifun SA25F005 (non-buffered flash) */
171 /* strap, cfg1, & write1 need updates */
172 {0x1d000003, 0x5f808201, 0x00050081, 0x03840253, 0xaf020406,
Michael Chane30372c2007-07-16 18:26:23 -0700173 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
Michael Chan37137702005-11-04 08:49:17 -0800174 SAIFUN_FLASH_BYTE_ADDR_MASK, SAIFUN_FLASH_BASE_TOTAL_SIZE,
175 "Non-buffered flash (64kB)"},
176 /* Fast EEPROM */
177 {0x22000000, 0x62808380, 0x009f0081, 0xa184a053, 0xaf000400,
Michael Chane30372c2007-07-16 18:26:23 -0700178 BUFFERED_FLAGS, SEEPROM_PAGE_BITS, SEEPROM_PAGE_SIZE,
Michael Chan37137702005-11-04 08:49:17 -0800179 SEEPROM_BYTE_ADDR_MASK, SEEPROM_TOTAL_SIZE,
180 "EEPROM - fast"},
181 /* Expansion entry 1001 */
182 {0x2a000002, 0x6b808201, 0x00050081, 0x03840253, 0xaf020406,
Michael Chane30372c2007-07-16 18:26:23 -0700183 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
Michael Chan37137702005-11-04 08:49:17 -0800184 SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
185 "Entry 1001"},
186 /* Expansion entry 1010 */
187 {0x26000001, 0x67808201, 0x00050081, 0x03840253, 0xaf020406,
Michael Chane30372c2007-07-16 18:26:23 -0700188 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
Michael Chan37137702005-11-04 08:49:17 -0800189 SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
190 "Entry 1010"},
191 /* ATMEL AT45DB011B (buffered flash) */
192 {0x2e000003, 0x6e808273, 0x00570081, 0x68848353, 0xaf000400,
Michael Chane30372c2007-07-16 18:26:23 -0700193 BUFFERED_FLAGS, BUFFERED_FLASH_PAGE_BITS, BUFFERED_FLASH_PAGE_SIZE,
Michael Chan37137702005-11-04 08:49:17 -0800194 BUFFERED_FLASH_BYTE_ADDR_MASK, BUFFERED_FLASH_TOTAL_SIZE,
195 "Buffered flash (128kB)"},
196 /* Expansion entry 1100 */
197 {0x33000000, 0x73808201, 0x00050081, 0x03840253, 0xaf020406,
Michael Chane30372c2007-07-16 18:26:23 -0700198 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
Michael Chan37137702005-11-04 08:49:17 -0800199 SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
200 "Entry 1100"},
201 /* Expansion entry 1101 */
202 {0x3b000002, 0x7b808201, 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 1101"},
206 /* Ateml Expansion entry 1110 */
207 {0x37000001, 0x76808273, 0x00570081, 0x68848353, 0xaf000400,
Michael Chane30372c2007-07-16 18:26:23 -0700208 BUFFERED_FLAGS, BUFFERED_FLASH_PAGE_BITS, BUFFERED_FLASH_PAGE_SIZE,
Michael Chan37137702005-11-04 08:49:17 -0800209 BUFFERED_FLASH_BYTE_ADDR_MASK, 0,
210 "Entry 1110 (Atmel)"},
211 /* ATMEL AT45DB021B (buffered flash) */
212 {0x3f000003, 0x7e808273, 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*2,
215 "Buffered flash (256kB)"},
Michael Chanb6016b72005-05-26 13:03:09 -0700216};
217
Michael Chane30372c2007-07-16 18:26:23 -0700218static struct flash_spec flash_5709 = {
219 .flags = BNX2_NV_BUFFERED,
220 .page_bits = BCM5709_FLASH_PAGE_BITS,
221 .page_size = BCM5709_FLASH_PAGE_SIZE,
222 .addr_mask = BCM5709_FLASH_BYTE_ADDR_MASK,
223 .total_size = BUFFERED_FLASH_TOTAL_SIZE*2,
224 .name = "5709 Buffered flash (256kB)",
225};
226
Michael Chanb6016b72005-05-26 13:03:09 -0700227MODULE_DEVICE_TABLE(pci, bnx2_pci_tbl);
228
Michael Chana550c992007-12-20 19:56:59 -0800229static inline u32 bnx2_tx_avail(struct bnx2 *bp, struct bnx2_napi *bnapi)
Michael Chane89bbf12005-08-25 15:36:58 -0700230{
Michael Chan2f8af122006-08-15 01:39:10 -0700231 u32 diff;
Michael Chane89bbf12005-08-25 15:36:58 -0700232
Michael Chan2f8af122006-08-15 01:39:10 -0700233 smp_mb();
Michael Chanfaac9c42006-12-14 15:56:32 -0800234
235 /* The ring uses 256 indices for 255 entries, one of them
236 * needs to be skipped.
237 */
Michael Chana550c992007-12-20 19:56:59 -0800238 diff = bp->tx_prod - bnapi->tx_cons;
Michael Chanfaac9c42006-12-14 15:56:32 -0800239 if (unlikely(diff >= TX_DESC_CNT)) {
240 diff &= 0xffff;
241 if (diff == TX_DESC_CNT)
242 diff = MAX_TX_DESC_CNT;
243 }
Michael Chane89bbf12005-08-25 15:36:58 -0700244 return (bp->tx_ring_size - diff);
245}
246
Michael Chanb6016b72005-05-26 13:03:09 -0700247static u32
248bnx2_reg_rd_ind(struct bnx2 *bp, u32 offset)
249{
Michael Chan1b8227c2007-05-03 13:24:05 -0700250 u32 val;
251
252 spin_lock_bh(&bp->indirect_lock);
Michael Chanb6016b72005-05-26 13:03:09 -0700253 REG_WR(bp, BNX2_PCICFG_REG_WINDOW_ADDRESS, offset);
Michael Chan1b8227c2007-05-03 13:24:05 -0700254 val = REG_RD(bp, BNX2_PCICFG_REG_WINDOW);
255 spin_unlock_bh(&bp->indirect_lock);
256 return val;
Michael Chanb6016b72005-05-26 13:03:09 -0700257}
258
259static void
260bnx2_reg_wr_ind(struct bnx2 *bp, u32 offset, u32 val)
261{
Michael Chan1b8227c2007-05-03 13:24:05 -0700262 spin_lock_bh(&bp->indirect_lock);
Michael Chanb6016b72005-05-26 13:03:09 -0700263 REG_WR(bp, BNX2_PCICFG_REG_WINDOW_ADDRESS, offset);
264 REG_WR(bp, BNX2_PCICFG_REG_WINDOW, val);
Michael Chan1b8227c2007-05-03 13:24:05 -0700265 spin_unlock_bh(&bp->indirect_lock);
Michael Chanb6016b72005-05-26 13:03:09 -0700266}
267
268static void
269bnx2_ctx_wr(struct bnx2 *bp, u32 cid_addr, u32 offset, u32 val)
270{
271 offset += cid_addr;
Michael Chan1b8227c2007-05-03 13:24:05 -0700272 spin_lock_bh(&bp->indirect_lock);
Michael Chan59b47d82006-11-19 14:10:45 -0800273 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
274 int i;
275
276 REG_WR(bp, BNX2_CTX_CTX_DATA, val);
277 REG_WR(bp, BNX2_CTX_CTX_CTRL,
278 offset | BNX2_CTX_CTX_CTRL_WRITE_REQ);
279 for (i = 0; i < 5; i++) {
280 u32 val;
281 val = REG_RD(bp, BNX2_CTX_CTX_CTRL);
282 if ((val & BNX2_CTX_CTX_CTRL_WRITE_REQ) == 0)
283 break;
284 udelay(5);
285 }
286 } else {
287 REG_WR(bp, BNX2_CTX_DATA_ADR, offset);
288 REG_WR(bp, BNX2_CTX_DATA, val);
289 }
Michael Chan1b8227c2007-05-03 13:24:05 -0700290 spin_unlock_bh(&bp->indirect_lock);
Michael Chanb6016b72005-05-26 13:03:09 -0700291}
292
293static int
294bnx2_read_phy(struct bnx2 *bp, u32 reg, u32 *val)
295{
296 u32 val1;
297 int i, ret;
298
299 if (bp->phy_flags & PHY_INT_MODE_AUTO_POLLING_FLAG) {
300 val1 = REG_RD(bp, BNX2_EMAC_MDIO_MODE);
301 val1 &= ~BNX2_EMAC_MDIO_MODE_AUTO_POLL;
302
303 REG_WR(bp, BNX2_EMAC_MDIO_MODE, val1);
304 REG_RD(bp, BNX2_EMAC_MDIO_MODE);
305
306 udelay(40);
307 }
308
309 val1 = (bp->phy_addr << 21) | (reg << 16) |
310 BNX2_EMAC_MDIO_COMM_COMMAND_READ | BNX2_EMAC_MDIO_COMM_DISEXT |
311 BNX2_EMAC_MDIO_COMM_START_BUSY;
312 REG_WR(bp, BNX2_EMAC_MDIO_COMM, val1);
313
314 for (i = 0; i < 50; i++) {
315 udelay(10);
316
317 val1 = REG_RD(bp, BNX2_EMAC_MDIO_COMM);
318 if (!(val1 & BNX2_EMAC_MDIO_COMM_START_BUSY)) {
319 udelay(5);
320
321 val1 = REG_RD(bp, BNX2_EMAC_MDIO_COMM);
322 val1 &= BNX2_EMAC_MDIO_COMM_DATA;
323
324 break;
325 }
326 }
327
328 if (val1 & BNX2_EMAC_MDIO_COMM_START_BUSY) {
329 *val = 0x0;
330 ret = -EBUSY;
331 }
332 else {
333 *val = val1;
334 ret = 0;
335 }
336
337 if (bp->phy_flags & PHY_INT_MODE_AUTO_POLLING_FLAG) {
338 val1 = REG_RD(bp, BNX2_EMAC_MDIO_MODE);
339 val1 |= BNX2_EMAC_MDIO_MODE_AUTO_POLL;
340
341 REG_WR(bp, BNX2_EMAC_MDIO_MODE, val1);
342 REG_RD(bp, BNX2_EMAC_MDIO_MODE);
343
344 udelay(40);
345 }
346
347 return ret;
348}
349
350static int
351bnx2_write_phy(struct bnx2 *bp, u32 reg, u32 val)
352{
353 u32 val1;
354 int i, ret;
355
356 if (bp->phy_flags & PHY_INT_MODE_AUTO_POLLING_FLAG) {
357 val1 = REG_RD(bp, BNX2_EMAC_MDIO_MODE);
358 val1 &= ~BNX2_EMAC_MDIO_MODE_AUTO_POLL;
359
360 REG_WR(bp, BNX2_EMAC_MDIO_MODE, val1);
361 REG_RD(bp, BNX2_EMAC_MDIO_MODE);
362
363 udelay(40);
364 }
365
366 val1 = (bp->phy_addr << 21) | (reg << 16) | val |
367 BNX2_EMAC_MDIO_COMM_COMMAND_WRITE |
368 BNX2_EMAC_MDIO_COMM_START_BUSY | BNX2_EMAC_MDIO_COMM_DISEXT;
369 REG_WR(bp, BNX2_EMAC_MDIO_COMM, val1);
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400370
Michael Chanb6016b72005-05-26 13:03:09 -0700371 for (i = 0; i < 50; i++) {
372 udelay(10);
373
374 val1 = REG_RD(bp, BNX2_EMAC_MDIO_COMM);
375 if (!(val1 & BNX2_EMAC_MDIO_COMM_START_BUSY)) {
376 udelay(5);
377 break;
378 }
379 }
380
381 if (val1 & BNX2_EMAC_MDIO_COMM_START_BUSY)
382 ret = -EBUSY;
383 else
384 ret = 0;
385
386 if (bp->phy_flags & PHY_INT_MODE_AUTO_POLLING_FLAG) {
387 val1 = REG_RD(bp, BNX2_EMAC_MDIO_MODE);
388 val1 |= BNX2_EMAC_MDIO_MODE_AUTO_POLL;
389
390 REG_WR(bp, BNX2_EMAC_MDIO_MODE, val1);
391 REG_RD(bp, BNX2_EMAC_MDIO_MODE);
392
393 udelay(40);
394 }
395
396 return ret;
397}
398
399static void
400bnx2_disable_int(struct bnx2 *bp)
401{
402 REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
403 BNX2_PCICFG_INT_ACK_CMD_MASK_INT);
404 REG_RD(bp, BNX2_PCICFG_INT_ACK_CMD);
405}
406
407static void
408bnx2_enable_int(struct bnx2 *bp)
409{
Michael Chan35efa7c2007-12-20 19:56:37 -0800410 struct bnx2_napi *bnapi = &bp->bnx2_napi;
Michael Chan1269a8a2006-01-23 16:11:03 -0800411
412 REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
Michael Chan35efa7c2007-12-20 19:56:37 -0800413 BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
414 BNX2_PCICFG_INT_ACK_CMD_MASK_INT | bnapi->last_status_idx);
415
416 REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
417 BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID | bnapi->last_status_idx);
Michael Chanb6016b72005-05-26 13:03:09 -0700418
Michael Chanbf5295b2006-03-23 01:11:56 -0800419 REG_WR(bp, BNX2_HC_COMMAND, bp->hc_cmd | BNX2_HC_COMMAND_COAL_NOW);
Michael Chanb6016b72005-05-26 13:03:09 -0700420}
421
422static void
423bnx2_disable_int_sync(struct bnx2 *bp)
424{
425 atomic_inc(&bp->intr_sem);
426 bnx2_disable_int(bp);
427 synchronize_irq(bp->pdev->irq);
428}
429
430static void
Michael Chan35efa7c2007-12-20 19:56:37 -0800431bnx2_napi_disable(struct bnx2 *bp)
432{
433 napi_disable(&bp->bnx2_napi.napi);
434}
435
436static void
437bnx2_napi_enable(struct bnx2 *bp)
438{
439 napi_enable(&bp->bnx2_napi.napi);
440}
441
442static void
Michael Chanb6016b72005-05-26 13:03:09 -0700443bnx2_netif_stop(struct bnx2 *bp)
444{
445 bnx2_disable_int_sync(bp);
446 if (netif_running(bp->dev)) {
Michael Chan35efa7c2007-12-20 19:56:37 -0800447 bnx2_napi_disable(bp);
Michael Chanb6016b72005-05-26 13:03:09 -0700448 netif_tx_disable(bp->dev);
449 bp->dev->trans_start = jiffies; /* prevent tx timeout */
450 }
451}
452
453static void
454bnx2_netif_start(struct bnx2 *bp)
455{
456 if (atomic_dec_and_test(&bp->intr_sem)) {
457 if (netif_running(bp->dev)) {
458 netif_wake_queue(bp->dev);
Michael Chan35efa7c2007-12-20 19:56:37 -0800459 bnx2_napi_enable(bp);
Michael Chanb6016b72005-05-26 13:03:09 -0700460 bnx2_enable_int(bp);
461 }
462 }
463}
464
465static void
466bnx2_free_mem(struct bnx2 *bp)
467{
Michael Chan13daffa2006-03-20 17:49:20 -0800468 int i;
469
Michael Chan59b47d82006-11-19 14:10:45 -0800470 for (i = 0; i < bp->ctx_pages; i++) {
471 if (bp->ctx_blk[i]) {
472 pci_free_consistent(bp->pdev, BCM_PAGE_SIZE,
473 bp->ctx_blk[i],
474 bp->ctx_blk_mapping[i]);
475 bp->ctx_blk[i] = NULL;
476 }
477 }
Michael Chanb6016b72005-05-26 13:03:09 -0700478 if (bp->status_blk) {
Michael Chan0f31f992006-03-23 01:12:38 -0800479 pci_free_consistent(bp->pdev, bp->status_stats_size,
Michael Chanb6016b72005-05-26 13:03:09 -0700480 bp->status_blk, bp->status_blk_mapping);
481 bp->status_blk = NULL;
Michael Chan0f31f992006-03-23 01:12:38 -0800482 bp->stats_blk = NULL;
Michael Chanb6016b72005-05-26 13:03:09 -0700483 }
484 if (bp->tx_desc_ring) {
Michael Chane343d552007-12-12 11:16:19 -0800485 pci_free_consistent(bp->pdev, TXBD_RING_SIZE,
Michael Chanb6016b72005-05-26 13:03:09 -0700486 bp->tx_desc_ring, bp->tx_desc_mapping);
487 bp->tx_desc_ring = NULL;
488 }
Jesper Juhlb4558ea2005-10-28 16:53:13 -0400489 kfree(bp->tx_buf_ring);
490 bp->tx_buf_ring = NULL;
Michael Chan13daffa2006-03-20 17:49:20 -0800491 for (i = 0; i < bp->rx_max_ring; i++) {
492 if (bp->rx_desc_ring[i])
Michael Chane343d552007-12-12 11:16:19 -0800493 pci_free_consistent(bp->pdev, RXBD_RING_SIZE,
Michael Chan13daffa2006-03-20 17:49:20 -0800494 bp->rx_desc_ring[i],
495 bp->rx_desc_mapping[i]);
496 bp->rx_desc_ring[i] = NULL;
Michael Chanb6016b72005-05-26 13:03:09 -0700497 }
Michael Chan13daffa2006-03-20 17:49:20 -0800498 vfree(bp->rx_buf_ring);
Jesper Juhlb4558ea2005-10-28 16:53:13 -0400499 bp->rx_buf_ring = NULL;
Michael Chan47bf4242007-12-12 11:19:12 -0800500 for (i = 0; i < bp->rx_max_pg_ring; i++) {
501 if (bp->rx_pg_desc_ring[i])
502 pci_free_consistent(bp->pdev, RXBD_RING_SIZE,
503 bp->rx_pg_desc_ring[i],
504 bp->rx_pg_desc_mapping[i]);
505 bp->rx_pg_desc_ring[i] = NULL;
506 }
507 if (bp->rx_pg_ring)
508 vfree(bp->rx_pg_ring);
509 bp->rx_pg_ring = NULL;
Michael Chanb6016b72005-05-26 13:03:09 -0700510}
511
512static int
513bnx2_alloc_mem(struct bnx2 *bp)
514{
Michael Chan0f31f992006-03-23 01:12:38 -0800515 int i, status_blk_size;
Michael Chan13daffa2006-03-20 17:49:20 -0800516
Michael Chane343d552007-12-12 11:16:19 -0800517 bp->tx_buf_ring = kzalloc(SW_TXBD_RING_SIZE, GFP_KERNEL);
Michael Chanb6016b72005-05-26 13:03:09 -0700518 if (bp->tx_buf_ring == NULL)
519 return -ENOMEM;
520
Michael Chane343d552007-12-12 11:16:19 -0800521 bp->tx_desc_ring = pci_alloc_consistent(bp->pdev, TXBD_RING_SIZE,
Michael Chanb6016b72005-05-26 13:03:09 -0700522 &bp->tx_desc_mapping);
523 if (bp->tx_desc_ring == NULL)
524 goto alloc_mem_err;
525
Michael Chane343d552007-12-12 11:16:19 -0800526 bp->rx_buf_ring = vmalloc(SW_RXBD_RING_SIZE * bp->rx_max_ring);
Michael Chanb6016b72005-05-26 13:03:09 -0700527 if (bp->rx_buf_ring == NULL)
528 goto alloc_mem_err;
529
Michael Chane343d552007-12-12 11:16:19 -0800530 memset(bp->rx_buf_ring, 0, SW_RXBD_RING_SIZE * bp->rx_max_ring);
Michael Chan13daffa2006-03-20 17:49:20 -0800531
532 for (i = 0; i < bp->rx_max_ring; i++) {
533 bp->rx_desc_ring[i] =
Michael Chane343d552007-12-12 11:16:19 -0800534 pci_alloc_consistent(bp->pdev, RXBD_RING_SIZE,
Michael Chan13daffa2006-03-20 17:49:20 -0800535 &bp->rx_desc_mapping[i]);
536 if (bp->rx_desc_ring[i] == NULL)
537 goto alloc_mem_err;
538
539 }
Michael Chanb6016b72005-05-26 13:03:09 -0700540
Michael Chan47bf4242007-12-12 11:19:12 -0800541 if (bp->rx_pg_ring_size) {
542 bp->rx_pg_ring = vmalloc(SW_RXPG_RING_SIZE *
543 bp->rx_max_pg_ring);
544 if (bp->rx_pg_ring == NULL)
545 goto alloc_mem_err;
546
547 memset(bp->rx_pg_ring, 0, SW_RXPG_RING_SIZE *
548 bp->rx_max_pg_ring);
549 }
550
551 for (i = 0; i < bp->rx_max_pg_ring; i++) {
552 bp->rx_pg_desc_ring[i] =
553 pci_alloc_consistent(bp->pdev, RXBD_RING_SIZE,
554 &bp->rx_pg_desc_mapping[i]);
555 if (bp->rx_pg_desc_ring[i] == NULL)
556 goto alloc_mem_err;
557
558 }
559
Michael Chan0f31f992006-03-23 01:12:38 -0800560 /* Combine status and statistics blocks into one allocation. */
561 status_blk_size = L1_CACHE_ALIGN(sizeof(struct status_block));
562 bp->status_stats_size = status_blk_size +
563 sizeof(struct statistics_block);
564
565 bp->status_blk = pci_alloc_consistent(bp->pdev, bp->status_stats_size,
Michael Chanb6016b72005-05-26 13:03:09 -0700566 &bp->status_blk_mapping);
567 if (bp->status_blk == NULL)
568 goto alloc_mem_err;
569
Michael Chan0f31f992006-03-23 01:12:38 -0800570 memset(bp->status_blk, 0, bp->status_stats_size);
Michael Chanb6016b72005-05-26 13:03:09 -0700571
Michael Chan35efa7c2007-12-20 19:56:37 -0800572 bp->bnx2_napi.status_blk = bp->status_blk;
573
Michael Chan0f31f992006-03-23 01:12:38 -0800574 bp->stats_blk = (void *) ((unsigned long) bp->status_blk +
575 status_blk_size);
Michael Chanb6016b72005-05-26 13:03:09 -0700576
Michael Chan0f31f992006-03-23 01:12:38 -0800577 bp->stats_blk_mapping = bp->status_blk_mapping + status_blk_size;
Michael Chanb6016b72005-05-26 13:03:09 -0700578
Michael Chan59b47d82006-11-19 14:10:45 -0800579 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
580 bp->ctx_pages = 0x2000 / BCM_PAGE_SIZE;
581 if (bp->ctx_pages == 0)
582 bp->ctx_pages = 1;
583 for (i = 0; i < bp->ctx_pages; i++) {
584 bp->ctx_blk[i] = pci_alloc_consistent(bp->pdev,
585 BCM_PAGE_SIZE,
586 &bp->ctx_blk_mapping[i]);
587 if (bp->ctx_blk[i] == NULL)
588 goto alloc_mem_err;
589 }
590 }
Michael Chanb6016b72005-05-26 13:03:09 -0700591 return 0;
592
593alloc_mem_err:
594 bnx2_free_mem(bp);
595 return -ENOMEM;
596}
597
598static void
Michael Chane3648b32005-11-04 08:51:21 -0800599bnx2_report_fw_link(struct bnx2 *bp)
600{
601 u32 fw_link_status = 0;
602
Michael Chan0d8a6572007-07-07 22:49:43 -0700603 if (bp->phy_flags & REMOTE_PHY_CAP_FLAG)
604 return;
605
Michael Chane3648b32005-11-04 08:51:21 -0800606 if (bp->link_up) {
607 u32 bmsr;
608
609 switch (bp->line_speed) {
610 case SPEED_10:
611 if (bp->duplex == DUPLEX_HALF)
612 fw_link_status = BNX2_LINK_STATUS_10HALF;
613 else
614 fw_link_status = BNX2_LINK_STATUS_10FULL;
615 break;
616 case SPEED_100:
617 if (bp->duplex == DUPLEX_HALF)
618 fw_link_status = BNX2_LINK_STATUS_100HALF;
619 else
620 fw_link_status = BNX2_LINK_STATUS_100FULL;
621 break;
622 case SPEED_1000:
623 if (bp->duplex == DUPLEX_HALF)
624 fw_link_status = BNX2_LINK_STATUS_1000HALF;
625 else
626 fw_link_status = BNX2_LINK_STATUS_1000FULL;
627 break;
628 case SPEED_2500:
629 if (bp->duplex == DUPLEX_HALF)
630 fw_link_status = BNX2_LINK_STATUS_2500HALF;
631 else
632 fw_link_status = BNX2_LINK_STATUS_2500FULL;
633 break;
634 }
635
636 fw_link_status |= BNX2_LINK_STATUS_LINK_UP;
637
638 if (bp->autoneg) {
639 fw_link_status |= BNX2_LINK_STATUS_AN_ENABLED;
640
Michael Chanca58c3a2007-05-03 13:22:52 -0700641 bnx2_read_phy(bp, bp->mii_bmsr, &bmsr);
642 bnx2_read_phy(bp, bp->mii_bmsr, &bmsr);
Michael Chane3648b32005-11-04 08:51:21 -0800643
644 if (!(bmsr & BMSR_ANEGCOMPLETE) ||
645 bp->phy_flags & PHY_PARALLEL_DETECT_FLAG)
646 fw_link_status |= BNX2_LINK_STATUS_PARALLEL_DET;
647 else
648 fw_link_status |= BNX2_LINK_STATUS_AN_COMPLETE;
649 }
650 }
651 else
652 fw_link_status = BNX2_LINK_STATUS_LINK_DOWN;
653
654 REG_WR_IND(bp, bp->shmem_base + BNX2_LINK_STATUS, fw_link_status);
655}
656
Michael Chan9b1084b2007-07-07 22:50:37 -0700657static char *
658bnx2_xceiver_str(struct bnx2 *bp)
659{
660 return ((bp->phy_port == PORT_FIBRE) ? "SerDes" :
661 ((bp->phy_flags & PHY_SERDES_FLAG) ? "Remote Copper" :
662 "Copper"));
663}
664
Michael Chane3648b32005-11-04 08:51:21 -0800665static void
Michael Chanb6016b72005-05-26 13:03:09 -0700666bnx2_report_link(struct bnx2 *bp)
667{
668 if (bp->link_up) {
669 netif_carrier_on(bp->dev);
Michael Chan9b1084b2007-07-07 22:50:37 -0700670 printk(KERN_INFO PFX "%s NIC %s Link is Up, ", bp->dev->name,
671 bnx2_xceiver_str(bp));
Michael Chanb6016b72005-05-26 13:03:09 -0700672
673 printk("%d Mbps ", bp->line_speed);
674
675 if (bp->duplex == DUPLEX_FULL)
676 printk("full duplex");
677 else
678 printk("half duplex");
679
680 if (bp->flow_ctrl) {
681 if (bp->flow_ctrl & FLOW_CTRL_RX) {
682 printk(", receive ");
683 if (bp->flow_ctrl & FLOW_CTRL_TX)
684 printk("& transmit ");
685 }
686 else {
687 printk(", transmit ");
688 }
689 printk("flow control ON");
690 }
691 printk("\n");
692 }
693 else {
694 netif_carrier_off(bp->dev);
Michael Chan9b1084b2007-07-07 22:50:37 -0700695 printk(KERN_ERR PFX "%s NIC %s Link is Down\n", bp->dev->name,
696 bnx2_xceiver_str(bp));
Michael Chanb6016b72005-05-26 13:03:09 -0700697 }
Michael Chane3648b32005-11-04 08:51:21 -0800698
699 bnx2_report_fw_link(bp);
Michael Chanb6016b72005-05-26 13:03:09 -0700700}
701
702static void
703bnx2_resolve_flow_ctrl(struct bnx2 *bp)
704{
705 u32 local_adv, remote_adv;
706
707 bp->flow_ctrl = 0;
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400708 if ((bp->autoneg & (AUTONEG_SPEED | AUTONEG_FLOW_CTRL)) !=
Michael Chanb6016b72005-05-26 13:03:09 -0700709 (AUTONEG_SPEED | AUTONEG_FLOW_CTRL)) {
710
711 if (bp->duplex == DUPLEX_FULL) {
712 bp->flow_ctrl = bp->req_flow_ctrl;
713 }
714 return;
715 }
716
717 if (bp->duplex != DUPLEX_FULL) {
718 return;
719 }
720
Michael Chan5b0c76a2005-11-04 08:45:49 -0800721 if ((bp->phy_flags & PHY_SERDES_FLAG) &&
722 (CHIP_NUM(bp) == CHIP_NUM_5708)) {
723 u32 val;
724
725 bnx2_read_phy(bp, BCM5708S_1000X_STAT1, &val);
726 if (val & BCM5708S_1000X_STAT1_TX_PAUSE)
727 bp->flow_ctrl |= FLOW_CTRL_TX;
728 if (val & BCM5708S_1000X_STAT1_RX_PAUSE)
729 bp->flow_ctrl |= FLOW_CTRL_RX;
730 return;
731 }
732
Michael Chanca58c3a2007-05-03 13:22:52 -0700733 bnx2_read_phy(bp, bp->mii_adv, &local_adv);
734 bnx2_read_phy(bp, bp->mii_lpa, &remote_adv);
Michael Chanb6016b72005-05-26 13:03:09 -0700735
736 if (bp->phy_flags & PHY_SERDES_FLAG) {
737 u32 new_local_adv = 0;
738 u32 new_remote_adv = 0;
739
740 if (local_adv & ADVERTISE_1000XPAUSE)
741 new_local_adv |= ADVERTISE_PAUSE_CAP;
742 if (local_adv & ADVERTISE_1000XPSE_ASYM)
743 new_local_adv |= ADVERTISE_PAUSE_ASYM;
744 if (remote_adv & ADVERTISE_1000XPAUSE)
745 new_remote_adv |= ADVERTISE_PAUSE_CAP;
746 if (remote_adv & ADVERTISE_1000XPSE_ASYM)
747 new_remote_adv |= ADVERTISE_PAUSE_ASYM;
748
749 local_adv = new_local_adv;
750 remote_adv = new_remote_adv;
751 }
752
753 /* See Table 28B-3 of 802.3ab-1999 spec. */
754 if (local_adv & ADVERTISE_PAUSE_CAP) {
755 if(local_adv & ADVERTISE_PAUSE_ASYM) {
756 if (remote_adv & ADVERTISE_PAUSE_CAP) {
757 bp->flow_ctrl = FLOW_CTRL_TX | FLOW_CTRL_RX;
758 }
759 else if (remote_adv & ADVERTISE_PAUSE_ASYM) {
760 bp->flow_ctrl = FLOW_CTRL_RX;
761 }
762 }
763 else {
764 if (remote_adv & ADVERTISE_PAUSE_CAP) {
765 bp->flow_ctrl = FLOW_CTRL_TX | FLOW_CTRL_RX;
766 }
767 }
768 }
769 else if (local_adv & ADVERTISE_PAUSE_ASYM) {
770 if ((remote_adv & ADVERTISE_PAUSE_CAP) &&
771 (remote_adv & ADVERTISE_PAUSE_ASYM)) {
772
773 bp->flow_ctrl = FLOW_CTRL_TX;
774 }
775 }
776}
777
778static int
Michael Chan27a005b2007-05-03 13:23:41 -0700779bnx2_5709s_linkup(struct bnx2 *bp)
780{
781 u32 val, speed;
782
783 bp->link_up = 1;
784
785 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_GP_STATUS);
786 bnx2_read_phy(bp, MII_BNX2_GP_TOP_AN_STATUS1, &val);
787 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
788
789 if ((bp->autoneg & AUTONEG_SPEED) == 0) {
790 bp->line_speed = bp->req_line_speed;
791 bp->duplex = bp->req_duplex;
792 return 0;
793 }
794 speed = val & MII_BNX2_GP_TOP_AN_SPEED_MSK;
795 switch (speed) {
796 case MII_BNX2_GP_TOP_AN_SPEED_10:
797 bp->line_speed = SPEED_10;
798 break;
799 case MII_BNX2_GP_TOP_AN_SPEED_100:
800 bp->line_speed = SPEED_100;
801 break;
802 case MII_BNX2_GP_TOP_AN_SPEED_1G:
803 case MII_BNX2_GP_TOP_AN_SPEED_1GKV:
804 bp->line_speed = SPEED_1000;
805 break;
806 case MII_BNX2_GP_TOP_AN_SPEED_2_5G:
807 bp->line_speed = SPEED_2500;
808 break;
809 }
810 if (val & MII_BNX2_GP_TOP_AN_FD)
811 bp->duplex = DUPLEX_FULL;
812 else
813 bp->duplex = DUPLEX_HALF;
814 return 0;
815}
816
817static int
Michael Chan5b0c76a2005-11-04 08:45:49 -0800818bnx2_5708s_linkup(struct bnx2 *bp)
819{
820 u32 val;
821
822 bp->link_up = 1;
823 bnx2_read_phy(bp, BCM5708S_1000X_STAT1, &val);
824 switch (val & BCM5708S_1000X_STAT1_SPEED_MASK) {
825 case BCM5708S_1000X_STAT1_SPEED_10:
826 bp->line_speed = SPEED_10;
827 break;
828 case BCM5708S_1000X_STAT1_SPEED_100:
829 bp->line_speed = SPEED_100;
830 break;
831 case BCM5708S_1000X_STAT1_SPEED_1G:
832 bp->line_speed = SPEED_1000;
833 break;
834 case BCM5708S_1000X_STAT1_SPEED_2G5:
835 bp->line_speed = SPEED_2500;
836 break;
837 }
838 if (val & BCM5708S_1000X_STAT1_FD)
839 bp->duplex = DUPLEX_FULL;
840 else
841 bp->duplex = DUPLEX_HALF;
842
843 return 0;
844}
845
846static int
847bnx2_5706s_linkup(struct bnx2 *bp)
Michael Chanb6016b72005-05-26 13:03:09 -0700848{
849 u32 bmcr, local_adv, remote_adv, common;
850
851 bp->link_up = 1;
852 bp->line_speed = SPEED_1000;
853
Michael Chanca58c3a2007-05-03 13:22:52 -0700854 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chanb6016b72005-05-26 13:03:09 -0700855 if (bmcr & BMCR_FULLDPLX) {
856 bp->duplex = DUPLEX_FULL;
857 }
858 else {
859 bp->duplex = DUPLEX_HALF;
860 }
861
862 if (!(bmcr & BMCR_ANENABLE)) {
863 return 0;
864 }
865
Michael Chanca58c3a2007-05-03 13:22:52 -0700866 bnx2_read_phy(bp, bp->mii_adv, &local_adv);
867 bnx2_read_phy(bp, bp->mii_lpa, &remote_adv);
Michael Chanb6016b72005-05-26 13:03:09 -0700868
869 common = local_adv & remote_adv;
870 if (common & (ADVERTISE_1000XHALF | ADVERTISE_1000XFULL)) {
871
872 if (common & ADVERTISE_1000XFULL) {
873 bp->duplex = DUPLEX_FULL;
874 }
875 else {
876 bp->duplex = DUPLEX_HALF;
877 }
878 }
879
880 return 0;
881}
882
883static int
884bnx2_copper_linkup(struct bnx2 *bp)
885{
886 u32 bmcr;
887
Michael Chanca58c3a2007-05-03 13:22:52 -0700888 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chanb6016b72005-05-26 13:03:09 -0700889 if (bmcr & BMCR_ANENABLE) {
890 u32 local_adv, remote_adv, common;
891
892 bnx2_read_phy(bp, MII_CTRL1000, &local_adv);
893 bnx2_read_phy(bp, MII_STAT1000, &remote_adv);
894
895 common = local_adv & (remote_adv >> 2);
896 if (common & ADVERTISE_1000FULL) {
897 bp->line_speed = SPEED_1000;
898 bp->duplex = DUPLEX_FULL;
899 }
900 else if (common & ADVERTISE_1000HALF) {
901 bp->line_speed = SPEED_1000;
902 bp->duplex = DUPLEX_HALF;
903 }
904 else {
Michael Chanca58c3a2007-05-03 13:22:52 -0700905 bnx2_read_phy(bp, bp->mii_adv, &local_adv);
906 bnx2_read_phy(bp, bp->mii_lpa, &remote_adv);
Michael Chanb6016b72005-05-26 13:03:09 -0700907
908 common = local_adv & remote_adv;
909 if (common & ADVERTISE_100FULL) {
910 bp->line_speed = SPEED_100;
911 bp->duplex = DUPLEX_FULL;
912 }
913 else if (common & ADVERTISE_100HALF) {
914 bp->line_speed = SPEED_100;
915 bp->duplex = DUPLEX_HALF;
916 }
917 else if (common & ADVERTISE_10FULL) {
918 bp->line_speed = SPEED_10;
919 bp->duplex = DUPLEX_FULL;
920 }
921 else if (common & ADVERTISE_10HALF) {
922 bp->line_speed = SPEED_10;
923 bp->duplex = DUPLEX_HALF;
924 }
925 else {
926 bp->line_speed = 0;
927 bp->link_up = 0;
928 }
929 }
930 }
931 else {
932 if (bmcr & BMCR_SPEED100) {
933 bp->line_speed = SPEED_100;
934 }
935 else {
936 bp->line_speed = SPEED_10;
937 }
938 if (bmcr & BMCR_FULLDPLX) {
939 bp->duplex = DUPLEX_FULL;
940 }
941 else {
942 bp->duplex = DUPLEX_HALF;
943 }
944 }
945
946 return 0;
947}
948
949static int
950bnx2_set_mac_link(struct bnx2 *bp)
951{
952 u32 val;
953
954 REG_WR(bp, BNX2_EMAC_TX_LENGTHS, 0x2620);
955 if (bp->link_up && (bp->line_speed == SPEED_1000) &&
956 (bp->duplex == DUPLEX_HALF)) {
957 REG_WR(bp, BNX2_EMAC_TX_LENGTHS, 0x26ff);
958 }
959
960 /* Configure the EMAC mode register. */
961 val = REG_RD(bp, BNX2_EMAC_MODE);
962
963 val &= ~(BNX2_EMAC_MODE_PORT | BNX2_EMAC_MODE_HALF_DUPLEX |
Michael Chan5b0c76a2005-11-04 08:45:49 -0800964 BNX2_EMAC_MODE_MAC_LOOP | BNX2_EMAC_MODE_FORCE_LINK |
Michael Chan59b47d82006-11-19 14:10:45 -0800965 BNX2_EMAC_MODE_25G_MODE);
Michael Chanb6016b72005-05-26 13:03:09 -0700966
967 if (bp->link_up) {
Michael Chan5b0c76a2005-11-04 08:45:49 -0800968 switch (bp->line_speed) {
969 case SPEED_10:
Michael Chan59b47d82006-11-19 14:10:45 -0800970 if (CHIP_NUM(bp) != CHIP_NUM_5706) {
971 val |= BNX2_EMAC_MODE_PORT_MII_10M;
Michael Chan5b0c76a2005-11-04 08:45:49 -0800972 break;
973 }
974 /* fall through */
975 case SPEED_100:
976 val |= BNX2_EMAC_MODE_PORT_MII;
977 break;
978 case SPEED_2500:
Michael Chan59b47d82006-11-19 14:10:45 -0800979 val |= BNX2_EMAC_MODE_25G_MODE;
Michael Chan5b0c76a2005-11-04 08:45:49 -0800980 /* fall through */
981 case SPEED_1000:
982 val |= BNX2_EMAC_MODE_PORT_GMII;
983 break;
984 }
Michael Chanb6016b72005-05-26 13:03:09 -0700985 }
986 else {
987 val |= BNX2_EMAC_MODE_PORT_GMII;
988 }
989
990 /* Set the MAC to operate in the appropriate duplex mode. */
991 if (bp->duplex == DUPLEX_HALF)
992 val |= BNX2_EMAC_MODE_HALF_DUPLEX;
993 REG_WR(bp, BNX2_EMAC_MODE, val);
994
995 /* Enable/disable rx PAUSE. */
996 bp->rx_mode &= ~BNX2_EMAC_RX_MODE_FLOW_EN;
997
998 if (bp->flow_ctrl & FLOW_CTRL_RX)
999 bp->rx_mode |= BNX2_EMAC_RX_MODE_FLOW_EN;
1000 REG_WR(bp, BNX2_EMAC_RX_MODE, bp->rx_mode);
1001
1002 /* Enable/disable tx PAUSE. */
1003 val = REG_RD(bp, BNX2_EMAC_TX_MODE);
1004 val &= ~BNX2_EMAC_TX_MODE_FLOW_EN;
1005
1006 if (bp->flow_ctrl & FLOW_CTRL_TX)
1007 val |= BNX2_EMAC_TX_MODE_FLOW_EN;
1008 REG_WR(bp, BNX2_EMAC_TX_MODE, val);
1009
1010 /* Acknowledge the interrupt. */
1011 REG_WR(bp, BNX2_EMAC_STATUS, BNX2_EMAC_STATUS_LINK_CHANGE);
1012
1013 return 0;
1014}
1015
Michael Chan27a005b2007-05-03 13:23:41 -07001016static void
1017bnx2_enable_bmsr1(struct bnx2 *bp)
1018{
1019 if ((bp->phy_flags & PHY_SERDES_FLAG) &&
1020 (CHIP_NUM(bp) == CHIP_NUM_5709))
1021 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
1022 MII_BNX2_BLK_ADDR_GP_STATUS);
1023}
1024
1025static void
1026bnx2_disable_bmsr1(struct bnx2 *bp)
1027{
1028 if ((bp->phy_flags & PHY_SERDES_FLAG) &&
1029 (CHIP_NUM(bp) == CHIP_NUM_5709))
1030 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
1031 MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
1032}
1033
Michael Chanb6016b72005-05-26 13:03:09 -07001034static int
Michael Chan605a9e22007-05-03 13:23:13 -07001035bnx2_test_and_enable_2g5(struct bnx2 *bp)
1036{
1037 u32 up1;
1038 int ret = 1;
1039
1040 if (!(bp->phy_flags & PHY_2_5G_CAPABLE_FLAG))
1041 return 0;
1042
1043 if (bp->autoneg & AUTONEG_SPEED)
1044 bp->advertising |= ADVERTISED_2500baseX_Full;
1045
Michael Chan27a005b2007-05-03 13:23:41 -07001046 if (CHIP_NUM(bp) == CHIP_NUM_5709)
1047 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_OVER1G);
1048
Michael Chan605a9e22007-05-03 13:23:13 -07001049 bnx2_read_phy(bp, bp->mii_up1, &up1);
1050 if (!(up1 & BCM5708S_UP1_2G5)) {
1051 up1 |= BCM5708S_UP1_2G5;
1052 bnx2_write_phy(bp, bp->mii_up1, up1);
1053 ret = 0;
1054 }
1055
Michael Chan27a005b2007-05-03 13:23:41 -07001056 if (CHIP_NUM(bp) == CHIP_NUM_5709)
1057 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
1058 MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
1059
Michael Chan605a9e22007-05-03 13:23:13 -07001060 return ret;
1061}
1062
1063static int
1064bnx2_test_and_disable_2g5(struct bnx2 *bp)
1065{
1066 u32 up1;
1067 int ret = 0;
1068
1069 if (!(bp->phy_flags & PHY_2_5G_CAPABLE_FLAG))
1070 return 0;
1071
Michael Chan27a005b2007-05-03 13:23:41 -07001072 if (CHIP_NUM(bp) == CHIP_NUM_5709)
1073 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_OVER1G);
1074
Michael Chan605a9e22007-05-03 13:23:13 -07001075 bnx2_read_phy(bp, bp->mii_up1, &up1);
1076 if (up1 & BCM5708S_UP1_2G5) {
1077 up1 &= ~BCM5708S_UP1_2G5;
1078 bnx2_write_phy(bp, bp->mii_up1, up1);
1079 ret = 1;
1080 }
1081
Michael Chan27a005b2007-05-03 13:23:41 -07001082 if (CHIP_NUM(bp) == CHIP_NUM_5709)
1083 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
1084 MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
1085
Michael Chan605a9e22007-05-03 13:23:13 -07001086 return ret;
1087}
1088
1089static void
1090bnx2_enable_forced_2g5(struct bnx2 *bp)
1091{
1092 u32 bmcr;
1093
1094 if (!(bp->phy_flags & PHY_2_5G_CAPABLE_FLAG))
1095 return;
1096
Michael Chan27a005b2007-05-03 13:23:41 -07001097 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
1098 u32 val;
1099
1100 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
1101 MII_BNX2_BLK_ADDR_SERDES_DIG);
1102 bnx2_read_phy(bp, MII_BNX2_SERDES_DIG_MISC1, &val);
1103 val &= ~MII_BNX2_SD_MISC1_FORCE_MSK;
1104 val |= MII_BNX2_SD_MISC1_FORCE | MII_BNX2_SD_MISC1_FORCE_2_5G;
1105 bnx2_write_phy(bp, MII_BNX2_SERDES_DIG_MISC1, val);
1106
1107 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
1108 MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
1109 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
1110
1111 } else if (CHIP_NUM(bp) == CHIP_NUM_5708) {
Michael Chan605a9e22007-05-03 13:23:13 -07001112 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
1113 bmcr |= BCM5708S_BMCR_FORCE_2500;
1114 }
1115
1116 if (bp->autoneg & AUTONEG_SPEED) {
1117 bmcr &= ~BMCR_ANENABLE;
1118 if (bp->req_duplex == DUPLEX_FULL)
1119 bmcr |= BMCR_FULLDPLX;
1120 }
1121 bnx2_write_phy(bp, bp->mii_bmcr, bmcr);
1122}
1123
1124static void
1125bnx2_disable_forced_2g5(struct bnx2 *bp)
1126{
1127 u32 bmcr;
1128
1129 if (!(bp->phy_flags & PHY_2_5G_CAPABLE_FLAG))
1130 return;
1131
Michael Chan27a005b2007-05-03 13:23:41 -07001132 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
1133 u32 val;
1134
1135 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
1136 MII_BNX2_BLK_ADDR_SERDES_DIG);
1137 bnx2_read_phy(bp, MII_BNX2_SERDES_DIG_MISC1, &val);
1138 val &= ~MII_BNX2_SD_MISC1_FORCE;
1139 bnx2_write_phy(bp, MII_BNX2_SERDES_DIG_MISC1, val);
1140
1141 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
1142 MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
1143 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
1144
1145 } else if (CHIP_NUM(bp) == CHIP_NUM_5708) {
Michael Chan605a9e22007-05-03 13:23:13 -07001146 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
1147 bmcr &= ~BCM5708S_BMCR_FORCE_2500;
1148 }
1149
1150 if (bp->autoneg & AUTONEG_SPEED)
1151 bmcr |= BMCR_SPEED1000 | BMCR_ANENABLE | BMCR_ANRESTART;
1152 bnx2_write_phy(bp, bp->mii_bmcr, bmcr);
1153}
1154
1155static int
Michael Chanb6016b72005-05-26 13:03:09 -07001156bnx2_set_link(struct bnx2 *bp)
1157{
1158 u32 bmsr;
1159 u8 link_up;
1160
Michael Chan80be4432006-11-19 14:07:28 -08001161 if (bp->loopback == MAC_LOOPBACK || bp->loopback == PHY_LOOPBACK) {
Michael Chanb6016b72005-05-26 13:03:09 -07001162 bp->link_up = 1;
1163 return 0;
1164 }
1165
Michael Chan0d8a6572007-07-07 22:49:43 -07001166 if (bp->phy_flags & REMOTE_PHY_CAP_FLAG)
1167 return 0;
1168
Michael Chanb6016b72005-05-26 13:03:09 -07001169 link_up = bp->link_up;
1170
Michael Chan27a005b2007-05-03 13:23:41 -07001171 bnx2_enable_bmsr1(bp);
1172 bnx2_read_phy(bp, bp->mii_bmsr1, &bmsr);
1173 bnx2_read_phy(bp, bp->mii_bmsr1, &bmsr);
1174 bnx2_disable_bmsr1(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07001175
1176 if ((bp->phy_flags & PHY_SERDES_FLAG) &&
1177 (CHIP_NUM(bp) == CHIP_NUM_5706)) {
1178 u32 val;
1179
1180 val = REG_RD(bp, BNX2_EMAC_STATUS);
1181 if (val & BNX2_EMAC_STATUS_LINK)
1182 bmsr |= BMSR_LSTATUS;
1183 else
1184 bmsr &= ~BMSR_LSTATUS;
1185 }
1186
1187 if (bmsr & BMSR_LSTATUS) {
1188 bp->link_up = 1;
1189
1190 if (bp->phy_flags & PHY_SERDES_FLAG) {
Michael Chan5b0c76a2005-11-04 08:45:49 -08001191 if (CHIP_NUM(bp) == CHIP_NUM_5706)
1192 bnx2_5706s_linkup(bp);
1193 else if (CHIP_NUM(bp) == CHIP_NUM_5708)
1194 bnx2_5708s_linkup(bp);
Michael Chan27a005b2007-05-03 13:23:41 -07001195 else if (CHIP_NUM(bp) == CHIP_NUM_5709)
1196 bnx2_5709s_linkup(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07001197 }
1198 else {
1199 bnx2_copper_linkup(bp);
1200 }
1201 bnx2_resolve_flow_ctrl(bp);
1202 }
1203 else {
1204 if ((bp->phy_flags & PHY_SERDES_FLAG) &&
Michael Chan605a9e22007-05-03 13:23:13 -07001205 (bp->autoneg & AUTONEG_SPEED))
1206 bnx2_disable_forced_2g5(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07001207
Michael Chanb6016b72005-05-26 13:03:09 -07001208 bp->phy_flags &= ~PHY_PARALLEL_DETECT_FLAG;
1209 bp->link_up = 0;
1210 }
1211
1212 if (bp->link_up != link_up) {
1213 bnx2_report_link(bp);
1214 }
1215
1216 bnx2_set_mac_link(bp);
1217
1218 return 0;
1219}
1220
1221static int
1222bnx2_reset_phy(struct bnx2 *bp)
1223{
1224 int i;
1225 u32 reg;
1226
Michael Chanca58c3a2007-05-03 13:22:52 -07001227 bnx2_write_phy(bp, bp->mii_bmcr, BMCR_RESET);
Michael Chanb6016b72005-05-26 13:03:09 -07001228
1229#define PHY_RESET_MAX_WAIT 100
1230 for (i = 0; i < PHY_RESET_MAX_WAIT; i++) {
1231 udelay(10);
1232
Michael Chanca58c3a2007-05-03 13:22:52 -07001233 bnx2_read_phy(bp, bp->mii_bmcr, &reg);
Michael Chanb6016b72005-05-26 13:03:09 -07001234 if (!(reg & BMCR_RESET)) {
1235 udelay(20);
1236 break;
1237 }
1238 }
1239 if (i == PHY_RESET_MAX_WAIT) {
1240 return -EBUSY;
1241 }
1242 return 0;
1243}
1244
1245static u32
1246bnx2_phy_get_pause_adv(struct bnx2 *bp)
1247{
1248 u32 adv = 0;
1249
1250 if ((bp->req_flow_ctrl & (FLOW_CTRL_RX | FLOW_CTRL_TX)) ==
1251 (FLOW_CTRL_RX | FLOW_CTRL_TX)) {
1252
1253 if (bp->phy_flags & PHY_SERDES_FLAG) {
1254 adv = ADVERTISE_1000XPAUSE;
1255 }
1256 else {
1257 adv = ADVERTISE_PAUSE_CAP;
1258 }
1259 }
1260 else if (bp->req_flow_ctrl & FLOW_CTRL_TX) {
1261 if (bp->phy_flags & PHY_SERDES_FLAG) {
1262 adv = ADVERTISE_1000XPSE_ASYM;
1263 }
1264 else {
1265 adv = ADVERTISE_PAUSE_ASYM;
1266 }
1267 }
1268 else if (bp->req_flow_ctrl & FLOW_CTRL_RX) {
1269 if (bp->phy_flags & PHY_SERDES_FLAG) {
1270 adv = ADVERTISE_1000XPAUSE | ADVERTISE_1000XPSE_ASYM;
1271 }
1272 else {
1273 adv = ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM;
1274 }
1275 }
1276 return adv;
1277}
1278
Michael Chan0d8a6572007-07-07 22:49:43 -07001279static int bnx2_fw_sync(struct bnx2 *, u32, int);
1280
Michael Chanb6016b72005-05-26 13:03:09 -07001281static int
Michael Chan0d8a6572007-07-07 22:49:43 -07001282bnx2_setup_remote_phy(struct bnx2 *bp, u8 port)
1283{
1284 u32 speed_arg = 0, pause_adv;
1285
1286 pause_adv = bnx2_phy_get_pause_adv(bp);
1287
1288 if (bp->autoneg & AUTONEG_SPEED) {
1289 speed_arg |= BNX2_NETLINK_SET_LINK_ENABLE_AUTONEG;
1290 if (bp->advertising & ADVERTISED_10baseT_Half)
1291 speed_arg |= BNX2_NETLINK_SET_LINK_SPEED_10HALF;
1292 if (bp->advertising & ADVERTISED_10baseT_Full)
1293 speed_arg |= BNX2_NETLINK_SET_LINK_SPEED_10FULL;
1294 if (bp->advertising & ADVERTISED_100baseT_Half)
1295 speed_arg |= BNX2_NETLINK_SET_LINK_SPEED_100HALF;
1296 if (bp->advertising & ADVERTISED_100baseT_Full)
1297 speed_arg |= BNX2_NETLINK_SET_LINK_SPEED_100FULL;
1298 if (bp->advertising & ADVERTISED_1000baseT_Full)
1299 speed_arg |= BNX2_NETLINK_SET_LINK_SPEED_1GFULL;
1300 if (bp->advertising & ADVERTISED_2500baseX_Full)
1301 speed_arg |= BNX2_NETLINK_SET_LINK_SPEED_2G5FULL;
1302 } else {
1303 if (bp->req_line_speed == SPEED_2500)
1304 speed_arg = BNX2_NETLINK_SET_LINK_SPEED_2G5FULL;
1305 else if (bp->req_line_speed == SPEED_1000)
1306 speed_arg = BNX2_NETLINK_SET_LINK_SPEED_1GFULL;
1307 else if (bp->req_line_speed == SPEED_100) {
1308 if (bp->req_duplex == DUPLEX_FULL)
1309 speed_arg = BNX2_NETLINK_SET_LINK_SPEED_100FULL;
1310 else
1311 speed_arg = BNX2_NETLINK_SET_LINK_SPEED_100HALF;
1312 } else if (bp->req_line_speed == SPEED_10) {
1313 if (bp->req_duplex == DUPLEX_FULL)
1314 speed_arg = BNX2_NETLINK_SET_LINK_SPEED_10FULL;
1315 else
1316 speed_arg = BNX2_NETLINK_SET_LINK_SPEED_10HALF;
1317 }
1318 }
1319
1320 if (pause_adv & (ADVERTISE_1000XPAUSE | ADVERTISE_PAUSE_CAP))
1321 speed_arg |= BNX2_NETLINK_SET_LINK_FC_SYM_PAUSE;
1322 if (pause_adv & (ADVERTISE_1000XPSE_ASYM | ADVERTISE_1000XPSE_ASYM))
1323 speed_arg |= BNX2_NETLINK_SET_LINK_FC_ASYM_PAUSE;
1324
1325 if (port == PORT_TP)
1326 speed_arg |= BNX2_NETLINK_SET_LINK_PHY_APP_REMOTE |
1327 BNX2_NETLINK_SET_LINK_ETH_AT_WIRESPEED;
1328
1329 REG_WR_IND(bp, bp->shmem_base + BNX2_DRV_MB_ARG0, speed_arg);
1330
1331 spin_unlock_bh(&bp->phy_lock);
1332 bnx2_fw_sync(bp, BNX2_DRV_MSG_CODE_CMD_SET_LINK, 0);
1333 spin_lock_bh(&bp->phy_lock);
1334
1335 return 0;
1336}
1337
1338static int
1339bnx2_setup_serdes_phy(struct bnx2 *bp, u8 port)
Michael Chanb6016b72005-05-26 13:03:09 -07001340{
Michael Chan605a9e22007-05-03 13:23:13 -07001341 u32 adv, bmcr;
Michael Chanb6016b72005-05-26 13:03:09 -07001342 u32 new_adv = 0;
1343
Michael Chan0d8a6572007-07-07 22:49:43 -07001344 if (bp->phy_flags & REMOTE_PHY_CAP_FLAG)
1345 return (bnx2_setup_remote_phy(bp, port));
1346
Michael Chanb6016b72005-05-26 13:03:09 -07001347 if (!(bp->autoneg & AUTONEG_SPEED)) {
1348 u32 new_bmcr;
Michael Chan5b0c76a2005-11-04 08:45:49 -08001349 int force_link_down = 0;
1350
Michael Chan605a9e22007-05-03 13:23:13 -07001351 if (bp->req_line_speed == SPEED_2500) {
1352 if (!bnx2_test_and_enable_2g5(bp))
1353 force_link_down = 1;
1354 } else if (bp->req_line_speed == SPEED_1000) {
1355 if (bnx2_test_and_disable_2g5(bp))
1356 force_link_down = 1;
1357 }
Michael Chanca58c3a2007-05-03 13:22:52 -07001358 bnx2_read_phy(bp, bp->mii_adv, &adv);
Michael Chan80be4432006-11-19 14:07:28 -08001359 adv &= ~(ADVERTISE_1000XFULL | ADVERTISE_1000XHALF);
1360
Michael Chanca58c3a2007-05-03 13:22:52 -07001361 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chan605a9e22007-05-03 13:23:13 -07001362 new_bmcr = bmcr & ~BMCR_ANENABLE;
Michael Chan80be4432006-11-19 14:07:28 -08001363 new_bmcr |= BMCR_SPEED1000;
Michael Chan605a9e22007-05-03 13:23:13 -07001364
Michael Chan27a005b2007-05-03 13:23:41 -07001365 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
1366 if (bp->req_line_speed == SPEED_2500)
1367 bnx2_enable_forced_2g5(bp);
1368 else if (bp->req_line_speed == SPEED_1000) {
1369 bnx2_disable_forced_2g5(bp);
1370 new_bmcr &= ~0x2000;
1371 }
1372
1373 } else if (CHIP_NUM(bp) == CHIP_NUM_5708) {
Michael Chan605a9e22007-05-03 13:23:13 -07001374 if (bp->req_line_speed == SPEED_2500)
1375 new_bmcr |= BCM5708S_BMCR_FORCE_2500;
1376 else
1377 new_bmcr = bmcr & ~BCM5708S_BMCR_FORCE_2500;
Michael Chan5b0c76a2005-11-04 08:45:49 -08001378 }
1379
Michael Chanb6016b72005-05-26 13:03:09 -07001380 if (bp->req_duplex == DUPLEX_FULL) {
Michael Chan5b0c76a2005-11-04 08:45:49 -08001381 adv |= ADVERTISE_1000XFULL;
Michael Chanb6016b72005-05-26 13:03:09 -07001382 new_bmcr |= BMCR_FULLDPLX;
1383 }
1384 else {
Michael Chan5b0c76a2005-11-04 08:45:49 -08001385 adv |= ADVERTISE_1000XHALF;
Michael Chanb6016b72005-05-26 13:03:09 -07001386 new_bmcr &= ~BMCR_FULLDPLX;
1387 }
Michael Chan5b0c76a2005-11-04 08:45:49 -08001388 if ((new_bmcr != bmcr) || (force_link_down)) {
Michael Chanb6016b72005-05-26 13:03:09 -07001389 /* Force a link down visible on the other side */
1390 if (bp->link_up) {
Michael Chanca58c3a2007-05-03 13:22:52 -07001391 bnx2_write_phy(bp, bp->mii_adv, adv &
Michael Chan5b0c76a2005-11-04 08:45:49 -08001392 ~(ADVERTISE_1000XFULL |
1393 ADVERTISE_1000XHALF));
Michael Chanca58c3a2007-05-03 13:22:52 -07001394 bnx2_write_phy(bp, bp->mii_bmcr, bmcr |
Michael Chanb6016b72005-05-26 13:03:09 -07001395 BMCR_ANRESTART | BMCR_ANENABLE);
1396
1397 bp->link_up = 0;
1398 netif_carrier_off(bp->dev);
Michael Chanca58c3a2007-05-03 13:22:52 -07001399 bnx2_write_phy(bp, bp->mii_bmcr, new_bmcr);
Michael Chan80be4432006-11-19 14:07:28 -08001400 bnx2_report_link(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07001401 }
Michael Chanca58c3a2007-05-03 13:22:52 -07001402 bnx2_write_phy(bp, bp->mii_adv, adv);
1403 bnx2_write_phy(bp, bp->mii_bmcr, new_bmcr);
Michael Chan605a9e22007-05-03 13:23:13 -07001404 } else {
1405 bnx2_resolve_flow_ctrl(bp);
1406 bnx2_set_mac_link(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07001407 }
1408 return 0;
1409 }
1410
Michael Chan605a9e22007-05-03 13:23:13 -07001411 bnx2_test_and_enable_2g5(bp);
Michael Chan5b0c76a2005-11-04 08:45:49 -08001412
Michael Chanb6016b72005-05-26 13:03:09 -07001413 if (bp->advertising & ADVERTISED_1000baseT_Full)
1414 new_adv |= ADVERTISE_1000XFULL;
1415
1416 new_adv |= bnx2_phy_get_pause_adv(bp);
1417
Michael Chanca58c3a2007-05-03 13:22:52 -07001418 bnx2_read_phy(bp, bp->mii_adv, &adv);
1419 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chanb6016b72005-05-26 13:03:09 -07001420
1421 bp->serdes_an_pending = 0;
1422 if ((adv != new_adv) || ((bmcr & BMCR_ANENABLE) == 0)) {
1423 /* Force a link down visible on the other side */
1424 if (bp->link_up) {
Michael Chanca58c3a2007-05-03 13:22:52 -07001425 bnx2_write_phy(bp, bp->mii_bmcr, BMCR_LOOPBACK);
Michael Chan80be4432006-11-19 14:07:28 -08001426 spin_unlock_bh(&bp->phy_lock);
1427 msleep(20);
1428 spin_lock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07001429 }
1430
Michael Chanca58c3a2007-05-03 13:22:52 -07001431 bnx2_write_phy(bp, bp->mii_adv, new_adv);
1432 bnx2_write_phy(bp, bp->mii_bmcr, bmcr | BMCR_ANRESTART |
Michael Chanb6016b72005-05-26 13:03:09 -07001433 BMCR_ANENABLE);
Michael Chanf8dd0642006-11-19 14:08:29 -08001434 /* Speed up link-up time when the link partner
1435 * does not autonegotiate which is very common
1436 * in blade servers. Some blade servers use
1437 * IPMI for kerboard input and it's important
1438 * to minimize link disruptions. Autoneg. involves
1439 * exchanging base pages plus 3 next pages and
1440 * normally completes in about 120 msec.
1441 */
1442 bp->current_interval = SERDES_AN_TIMEOUT;
1443 bp->serdes_an_pending = 1;
1444 mod_timer(&bp->timer, jiffies + bp->current_interval);
Michael Chan605a9e22007-05-03 13:23:13 -07001445 } else {
1446 bnx2_resolve_flow_ctrl(bp);
1447 bnx2_set_mac_link(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07001448 }
1449
1450 return 0;
1451}
1452
1453#define ETHTOOL_ALL_FIBRE_SPEED \
Michael Chandeaf3912007-07-07 22:48:00 -07001454 (bp->phy_flags & PHY_2_5G_CAPABLE_FLAG) ? \
1455 (ADVERTISED_2500baseX_Full | ADVERTISED_1000baseT_Full) :\
1456 (ADVERTISED_1000baseT_Full)
Michael Chanb6016b72005-05-26 13:03:09 -07001457
1458#define ETHTOOL_ALL_COPPER_SPEED \
1459 (ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full | \
1460 ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full | \
1461 ADVERTISED_1000baseT_Full)
1462
1463#define PHY_ALL_10_100_SPEED (ADVERTISE_10HALF | ADVERTISE_10FULL | \
1464 ADVERTISE_100HALF | ADVERTISE_100FULL | ADVERTISE_CSMA)
Jeff Garzik6aa20a22006-09-13 13:24:59 -04001465
Michael Chanb6016b72005-05-26 13:03:09 -07001466#define PHY_ALL_1000_SPEED (ADVERTISE_1000HALF | ADVERTISE_1000FULL)
1467
Michael Chandeaf3912007-07-07 22:48:00 -07001468static void
Michael Chan0d8a6572007-07-07 22:49:43 -07001469bnx2_set_default_remote_link(struct bnx2 *bp)
1470{
1471 u32 link;
1472
1473 if (bp->phy_port == PORT_TP)
1474 link = REG_RD_IND(bp, bp->shmem_base + BNX2_RPHY_COPPER_LINK);
1475 else
1476 link = REG_RD_IND(bp, bp->shmem_base + BNX2_RPHY_SERDES_LINK);
1477
1478 if (link & BNX2_NETLINK_SET_LINK_ENABLE_AUTONEG) {
1479 bp->req_line_speed = 0;
1480 bp->autoneg |= AUTONEG_SPEED;
1481 bp->advertising = ADVERTISED_Autoneg;
1482 if (link & BNX2_NETLINK_SET_LINK_SPEED_10HALF)
1483 bp->advertising |= ADVERTISED_10baseT_Half;
1484 if (link & BNX2_NETLINK_SET_LINK_SPEED_10FULL)
1485 bp->advertising |= ADVERTISED_10baseT_Full;
1486 if (link & BNX2_NETLINK_SET_LINK_SPEED_100HALF)
1487 bp->advertising |= ADVERTISED_100baseT_Half;
1488 if (link & BNX2_NETLINK_SET_LINK_SPEED_100FULL)
1489 bp->advertising |= ADVERTISED_100baseT_Full;
1490 if (link & BNX2_NETLINK_SET_LINK_SPEED_1GFULL)
1491 bp->advertising |= ADVERTISED_1000baseT_Full;
1492 if (link & BNX2_NETLINK_SET_LINK_SPEED_2G5FULL)
1493 bp->advertising |= ADVERTISED_2500baseX_Full;
1494 } else {
1495 bp->autoneg = 0;
1496 bp->advertising = 0;
1497 bp->req_duplex = DUPLEX_FULL;
1498 if (link & BNX2_NETLINK_SET_LINK_SPEED_10) {
1499 bp->req_line_speed = SPEED_10;
1500 if (link & BNX2_NETLINK_SET_LINK_SPEED_10HALF)
1501 bp->req_duplex = DUPLEX_HALF;
1502 }
1503 if (link & BNX2_NETLINK_SET_LINK_SPEED_100) {
1504 bp->req_line_speed = SPEED_100;
1505 if (link & BNX2_NETLINK_SET_LINK_SPEED_100HALF)
1506 bp->req_duplex = DUPLEX_HALF;
1507 }
1508 if (link & BNX2_NETLINK_SET_LINK_SPEED_1GFULL)
1509 bp->req_line_speed = SPEED_1000;
1510 if (link & BNX2_NETLINK_SET_LINK_SPEED_2G5FULL)
1511 bp->req_line_speed = SPEED_2500;
1512 }
1513}
1514
1515static void
Michael Chandeaf3912007-07-07 22:48:00 -07001516bnx2_set_default_link(struct bnx2 *bp)
1517{
Michael Chan0d8a6572007-07-07 22:49:43 -07001518 if (bp->phy_flags & REMOTE_PHY_CAP_FLAG)
1519 return bnx2_set_default_remote_link(bp);
1520
Michael Chandeaf3912007-07-07 22:48:00 -07001521 bp->autoneg = AUTONEG_SPEED | AUTONEG_FLOW_CTRL;
1522 bp->req_line_speed = 0;
1523 if (bp->phy_flags & PHY_SERDES_FLAG) {
1524 u32 reg;
1525
1526 bp->advertising = ETHTOOL_ALL_FIBRE_SPEED | ADVERTISED_Autoneg;
1527
1528 reg = REG_RD_IND(bp, bp->shmem_base + BNX2_PORT_HW_CFG_CONFIG);
1529 reg &= BNX2_PORT_HW_CFG_CFG_DFLT_LINK_MASK;
1530 if (reg == BNX2_PORT_HW_CFG_CFG_DFLT_LINK_1G) {
1531 bp->autoneg = 0;
1532 bp->req_line_speed = bp->line_speed = SPEED_1000;
1533 bp->req_duplex = DUPLEX_FULL;
1534 }
1535 } else
1536 bp->advertising = ETHTOOL_ALL_COPPER_SPEED | ADVERTISED_Autoneg;
1537}
1538
Michael Chan0d8a6572007-07-07 22:49:43 -07001539static void
Michael Chandf149d72007-07-07 22:51:36 -07001540bnx2_send_heart_beat(struct bnx2 *bp)
1541{
1542 u32 msg;
1543 u32 addr;
1544
1545 spin_lock(&bp->indirect_lock);
1546 msg = (u32) (++bp->fw_drv_pulse_wr_seq & BNX2_DRV_PULSE_SEQ_MASK);
1547 addr = bp->shmem_base + BNX2_DRV_PULSE_MB;
1548 REG_WR(bp, BNX2_PCICFG_REG_WINDOW_ADDRESS, addr);
1549 REG_WR(bp, BNX2_PCICFG_REG_WINDOW, msg);
1550 spin_unlock(&bp->indirect_lock);
1551}
1552
1553static void
Michael Chan0d8a6572007-07-07 22:49:43 -07001554bnx2_remote_phy_event(struct bnx2 *bp)
1555{
1556 u32 msg;
1557 u8 link_up = bp->link_up;
1558 u8 old_port;
1559
1560 msg = REG_RD_IND(bp, bp->shmem_base + BNX2_LINK_STATUS);
1561
Michael Chandf149d72007-07-07 22:51:36 -07001562 if (msg & BNX2_LINK_STATUS_HEART_BEAT_EXPIRED)
1563 bnx2_send_heart_beat(bp);
1564
1565 msg &= ~BNX2_LINK_STATUS_HEART_BEAT_EXPIRED;
1566
Michael Chan0d8a6572007-07-07 22:49:43 -07001567 if ((msg & BNX2_LINK_STATUS_LINK_UP) == BNX2_LINK_STATUS_LINK_DOWN)
1568 bp->link_up = 0;
1569 else {
1570 u32 speed;
1571
1572 bp->link_up = 1;
1573 speed = msg & BNX2_LINK_STATUS_SPEED_MASK;
1574 bp->duplex = DUPLEX_FULL;
1575 switch (speed) {
1576 case BNX2_LINK_STATUS_10HALF:
1577 bp->duplex = DUPLEX_HALF;
1578 case BNX2_LINK_STATUS_10FULL:
1579 bp->line_speed = SPEED_10;
1580 break;
1581 case BNX2_LINK_STATUS_100HALF:
1582 bp->duplex = DUPLEX_HALF;
1583 case BNX2_LINK_STATUS_100BASE_T4:
1584 case BNX2_LINK_STATUS_100FULL:
1585 bp->line_speed = SPEED_100;
1586 break;
1587 case BNX2_LINK_STATUS_1000HALF:
1588 bp->duplex = DUPLEX_HALF;
1589 case BNX2_LINK_STATUS_1000FULL:
1590 bp->line_speed = SPEED_1000;
1591 break;
1592 case BNX2_LINK_STATUS_2500HALF:
1593 bp->duplex = DUPLEX_HALF;
1594 case BNX2_LINK_STATUS_2500FULL:
1595 bp->line_speed = SPEED_2500;
1596 break;
1597 default:
1598 bp->line_speed = 0;
1599 break;
1600 }
1601
1602 spin_lock(&bp->phy_lock);
1603 bp->flow_ctrl = 0;
1604 if ((bp->autoneg & (AUTONEG_SPEED | AUTONEG_FLOW_CTRL)) !=
1605 (AUTONEG_SPEED | AUTONEG_FLOW_CTRL)) {
1606 if (bp->duplex == DUPLEX_FULL)
1607 bp->flow_ctrl = bp->req_flow_ctrl;
1608 } else {
1609 if (msg & BNX2_LINK_STATUS_TX_FC_ENABLED)
1610 bp->flow_ctrl |= FLOW_CTRL_TX;
1611 if (msg & BNX2_LINK_STATUS_RX_FC_ENABLED)
1612 bp->flow_ctrl |= FLOW_CTRL_RX;
1613 }
1614
1615 old_port = bp->phy_port;
1616 if (msg & BNX2_LINK_STATUS_SERDES_LINK)
1617 bp->phy_port = PORT_FIBRE;
1618 else
1619 bp->phy_port = PORT_TP;
1620
1621 if (old_port != bp->phy_port)
1622 bnx2_set_default_link(bp);
1623
1624 spin_unlock(&bp->phy_lock);
1625 }
1626 if (bp->link_up != link_up)
1627 bnx2_report_link(bp);
1628
1629 bnx2_set_mac_link(bp);
1630}
1631
1632static int
1633bnx2_set_remote_link(struct bnx2 *bp)
1634{
1635 u32 evt_code;
1636
1637 evt_code = REG_RD_IND(bp, bp->shmem_base + BNX2_FW_EVT_CODE_MB);
1638 switch (evt_code) {
1639 case BNX2_FW_EVT_CODE_LINK_EVENT:
1640 bnx2_remote_phy_event(bp);
1641 break;
1642 case BNX2_FW_EVT_CODE_SW_TIMER_EXPIRATION_EVENT:
1643 default:
Michael Chandf149d72007-07-07 22:51:36 -07001644 bnx2_send_heart_beat(bp);
Michael Chan0d8a6572007-07-07 22:49:43 -07001645 break;
1646 }
1647 return 0;
1648}
1649
Michael Chanb6016b72005-05-26 13:03:09 -07001650static int
1651bnx2_setup_copper_phy(struct bnx2 *bp)
1652{
1653 u32 bmcr;
1654 u32 new_bmcr;
1655
Michael Chanca58c3a2007-05-03 13:22:52 -07001656 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chanb6016b72005-05-26 13:03:09 -07001657
1658 if (bp->autoneg & AUTONEG_SPEED) {
1659 u32 adv_reg, adv1000_reg;
1660 u32 new_adv_reg = 0;
1661 u32 new_adv1000_reg = 0;
1662
Michael Chanca58c3a2007-05-03 13:22:52 -07001663 bnx2_read_phy(bp, bp->mii_adv, &adv_reg);
Michael Chanb6016b72005-05-26 13:03:09 -07001664 adv_reg &= (PHY_ALL_10_100_SPEED | ADVERTISE_PAUSE_CAP |
1665 ADVERTISE_PAUSE_ASYM);
1666
1667 bnx2_read_phy(bp, MII_CTRL1000, &adv1000_reg);
1668 adv1000_reg &= PHY_ALL_1000_SPEED;
1669
1670 if (bp->advertising & ADVERTISED_10baseT_Half)
1671 new_adv_reg |= ADVERTISE_10HALF;
1672 if (bp->advertising & ADVERTISED_10baseT_Full)
1673 new_adv_reg |= ADVERTISE_10FULL;
1674 if (bp->advertising & ADVERTISED_100baseT_Half)
1675 new_adv_reg |= ADVERTISE_100HALF;
1676 if (bp->advertising & ADVERTISED_100baseT_Full)
1677 new_adv_reg |= ADVERTISE_100FULL;
1678 if (bp->advertising & ADVERTISED_1000baseT_Full)
1679 new_adv1000_reg |= ADVERTISE_1000FULL;
Jeff Garzik6aa20a22006-09-13 13:24:59 -04001680
Michael Chanb6016b72005-05-26 13:03:09 -07001681 new_adv_reg |= ADVERTISE_CSMA;
1682
1683 new_adv_reg |= bnx2_phy_get_pause_adv(bp);
1684
1685 if ((adv1000_reg != new_adv1000_reg) ||
1686 (adv_reg != new_adv_reg) ||
1687 ((bmcr & BMCR_ANENABLE) == 0)) {
1688
Michael Chanca58c3a2007-05-03 13:22:52 -07001689 bnx2_write_phy(bp, bp->mii_adv, new_adv_reg);
Michael Chanb6016b72005-05-26 13:03:09 -07001690 bnx2_write_phy(bp, MII_CTRL1000, new_adv1000_reg);
Michael Chanca58c3a2007-05-03 13:22:52 -07001691 bnx2_write_phy(bp, bp->mii_bmcr, BMCR_ANRESTART |
Michael Chanb6016b72005-05-26 13:03:09 -07001692 BMCR_ANENABLE);
1693 }
1694 else if (bp->link_up) {
1695 /* Flow ctrl may have changed from auto to forced */
1696 /* or vice-versa. */
1697
1698 bnx2_resolve_flow_ctrl(bp);
1699 bnx2_set_mac_link(bp);
1700 }
1701 return 0;
1702 }
1703
1704 new_bmcr = 0;
1705 if (bp->req_line_speed == SPEED_100) {
1706 new_bmcr |= BMCR_SPEED100;
1707 }
1708 if (bp->req_duplex == DUPLEX_FULL) {
1709 new_bmcr |= BMCR_FULLDPLX;
1710 }
1711 if (new_bmcr != bmcr) {
1712 u32 bmsr;
Michael Chanb6016b72005-05-26 13:03:09 -07001713
Michael Chanca58c3a2007-05-03 13:22:52 -07001714 bnx2_read_phy(bp, bp->mii_bmsr, &bmsr);
1715 bnx2_read_phy(bp, bp->mii_bmsr, &bmsr);
Jeff Garzik6aa20a22006-09-13 13:24:59 -04001716
Michael Chanb6016b72005-05-26 13:03:09 -07001717 if (bmsr & BMSR_LSTATUS) {
1718 /* Force link down */
Michael Chanca58c3a2007-05-03 13:22:52 -07001719 bnx2_write_phy(bp, bp->mii_bmcr, BMCR_LOOPBACK);
Michael Chana16dda02006-11-19 14:08:56 -08001720 spin_unlock_bh(&bp->phy_lock);
1721 msleep(50);
1722 spin_lock_bh(&bp->phy_lock);
1723
Michael Chanca58c3a2007-05-03 13:22:52 -07001724 bnx2_read_phy(bp, bp->mii_bmsr, &bmsr);
1725 bnx2_read_phy(bp, bp->mii_bmsr, &bmsr);
Michael Chanb6016b72005-05-26 13:03:09 -07001726 }
1727
Michael Chanca58c3a2007-05-03 13:22:52 -07001728 bnx2_write_phy(bp, bp->mii_bmcr, new_bmcr);
Michael Chanb6016b72005-05-26 13:03:09 -07001729
1730 /* Normally, the new speed is setup after the link has
1731 * gone down and up again. In some cases, link will not go
1732 * down so we need to set up the new speed here.
1733 */
1734 if (bmsr & BMSR_LSTATUS) {
1735 bp->line_speed = bp->req_line_speed;
1736 bp->duplex = bp->req_duplex;
1737 bnx2_resolve_flow_ctrl(bp);
1738 bnx2_set_mac_link(bp);
1739 }
Michael Chan27a005b2007-05-03 13:23:41 -07001740 } else {
1741 bnx2_resolve_flow_ctrl(bp);
1742 bnx2_set_mac_link(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07001743 }
1744 return 0;
1745}
1746
1747static int
Michael Chan0d8a6572007-07-07 22:49:43 -07001748bnx2_setup_phy(struct bnx2 *bp, u8 port)
Michael Chanb6016b72005-05-26 13:03:09 -07001749{
1750 if (bp->loopback == MAC_LOOPBACK)
1751 return 0;
1752
1753 if (bp->phy_flags & PHY_SERDES_FLAG) {
Michael Chan0d8a6572007-07-07 22:49:43 -07001754 return (bnx2_setup_serdes_phy(bp, port));
Michael Chanb6016b72005-05-26 13:03:09 -07001755 }
1756 else {
1757 return (bnx2_setup_copper_phy(bp));
1758 }
1759}
1760
1761static int
Michael Chan27a005b2007-05-03 13:23:41 -07001762bnx2_init_5709s_phy(struct bnx2 *bp)
1763{
1764 u32 val;
1765
1766 bp->mii_bmcr = MII_BMCR + 0x10;
1767 bp->mii_bmsr = MII_BMSR + 0x10;
1768 bp->mii_bmsr1 = MII_BNX2_GP_TOP_AN_STATUS1;
1769 bp->mii_adv = MII_ADVERTISE + 0x10;
1770 bp->mii_lpa = MII_LPA + 0x10;
1771 bp->mii_up1 = MII_BNX2_OVER1G_UP1;
1772
1773 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_AER);
1774 bnx2_write_phy(bp, MII_BNX2_AER_AER, MII_BNX2_AER_AER_AN_MMD);
1775
1776 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
1777 bnx2_reset_phy(bp);
1778
1779 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_SERDES_DIG);
1780
1781 bnx2_read_phy(bp, MII_BNX2_SERDES_DIG_1000XCTL1, &val);
1782 val &= ~MII_BNX2_SD_1000XCTL1_AUTODET;
1783 val |= MII_BNX2_SD_1000XCTL1_FIBER;
1784 bnx2_write_phy(bp, MII_BNX2_SERDES_DIG_1000XCTL1, val);
1785
1786 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_OVER1G);
1787 bnx2_read_phy(bp, MII_BNX2_OVER1G_UP1, &val);
1788 if (bp->phy_flags & PHY_2_5G_CAPABLE_FLAG)
1789 val |= BCM5708S_UP1_2G5;
1790 else
1791 val &= ~BCM5708S_UP1_2G5;
1792 bnx2_write_phy(bp, MII_BNX2_OVER1G_UP1, val);
1793
1794 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_BAM_NXTPG);
1795 bnx2_read_phy(bp, MII_BNX2_BAM_NXTPG_CTL, &val);
1796 val |= MII_BNX2_NXTPG_CTL_T2 | MII_BNX2_NXTPG_CTL_BAM;
1797 bnx2_write_phy(bp, MII_BNX2_BAM_NXTPG_CTL, val);
1798
1799 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_CL73_USERB0);
1800
1801 val = MII_BNX2_CL73_BAM_EN | MII_BNX2_CL73_BAM_STA_MGR_EN |
1802 MII_BNX2_CL73_BAM_NP_AFT_BP_EN;
1803 bnx2_write_phy(bp, MII_BNX2_CL73_BAM_CTL1, val);
1804
1805 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
1806
1807 return 0;
1808}
1809
1810static int
Michael Chan5b0c76a2005-11-04 08:45:49 -08001811bnx2_init_5708s_phy(struct bnx2 *bp)
1812{
1813 u32 val;
1814
Michael Chan27a005b2007-05-03 13:23:41 -07001815 bnx2_reset_phy(bp);
1816
1817 bp->mii_up1 = BCM5708S_UP1;
1818
Michael Chan5b0c76a2005-11-04 08:45:49 -08001819 bnx2_write_phy(bp, BCM5708S_BLK_ADDR, BCM5708S_BLK_ADDR_DIG3);
1820 bnx2_write_phy(bp, BCM5708S_DIG_3_0, BCM5708S_DIG_3_0_USE_IEEE);
1821 bnx2_write_phy(bp, BCM5708S_BLK_ADDR, BCM5708S_BLK_ADDR_DIG);
1822
1823 bnx2_read_phy(bp, BCM5708S_1000X_CTL1, &val);
1824 val |= BCM5708S_1000X_CTL1_FIBER_MODE | BCM5708S_1000X_CTL1_AUTODET_EN;
1825 bnx2_write_phy(bp, BCM5708S_1000X_CTL1, val);
1826
1827 bnx2_read_phy(bp, BCM5708S_1000X_CTL2, &val);
1828 val |= BCM5708S_1000X_CTL2_PLLEL_DET_EN;
1829 bnx2_write_phy(bp, BCM5708S_1000X_CTL2, val);
1830
1831 if (bp->phy_flags & PHY_2_5G_CAPABLE_FLAG) {
1832 bnx2_read_phy(bp, BCM5708S_UP1, &val);
1833 val |= BCM5708S_UP1_2G5;
1834 bnx2_write_phy(bp, BCM5708S_UP1, val);
1835 }
1836
1837 if ((CHIP_ID(bp) == CHIP_ID_5708_A0) ||
Michael Chandda1e392006-01-23 16:08:14 -08001838 (CHIP_ID(bp) == CHIP_ID_5708_B0) ||
1839 (CHIP_ID(bp) == CHIP_ID_5708_B1)) {
Michael Chan5b0c76a2005-11-04 08:45:49 -08001840 /* increase tx signal amplitude */
1841 bnx2_write_phy(bp, BCM5708S_BLK_ADDR,
1842 BCM5708S_BLK_ADDR_TX_MISC);
1843 bnx2_read_phy(bp, BCM5708S_TX_ACTL1, &val);
1844 val &= ~BCM5708S_TX_ACTL1_DRIVER_VCM;
1845 bnx2_write_phy(bp, BCM5708S_TX_ACTL1, val);
1846 bnx2_write_phy(bp, BCM5708S_BLK_ADDR, BCM5708S_BLK_ADDR_DIG);
1847 }
1848
Michael Chane3648b32005-11-04 08:51:21 -08001849 val = REG_RD_IND(bp, bp->shmem_base + BNX2_PORT_HW_CFG_CONFIG) &
Michael Chan5b0c76a2005-11-04 08:45:49 -08001850 BNX2_PORT_HW_CFG_CFG_TXCTL3_MASK;
1851
1852 if (val) {
1853 u32 is_backplane;
1854
Michael Chane3648b32005-11-04 08:51:21 -08001855 is_backplane = REG_RD_IND(bp, bp->shmem_base +
Michael Chan5b0c76a2005-11-04 08:45:49 -08001856 BNX2_SHARED_HW_CFG_CONFIG);
1857 if (is_backplane & BNX2_SHARED_HW_CFG_PHY_BACKPLANE) {
1858 bnx2_write_phy(bp, BCM5708S_BLK_ADDR,
1859 BCM5708S_BLK_ADDR_TX_MISC);
1860 bnx2_write_phy(bp, BCM5708S_TX_ACTL3, val);
1861 bnx2_write_phy(bp, BCM5708S_BLK_ADDR,
1862 BCM5708S_BLK_ADDR_DIG);
1863 }
1864 }
1865 return 0;
1866}
1867
1868static int
1869bnx2_init_5706s_phy(struct bnx2 *bp)
Michael Chanb6016b72005-05-26 13:03:09 -07001870{
Michael Chan27a005b2007-05-03 13:23:41 -07001871 bnx2_reset_phy(bp);
1872
Michael Chanb6016b72005-05-26 13:03:09 -07001873 bp->phy_flags &= ~PHY_PARALLEL_DETECT_FLAG;
1874
Michael Chan59b47d82006-11-19 14:10:45 -08001875 if (CHIP_NUM(bp) == CHIP_NUM_5706)
1876 REG_WR(bp, BNX2_MISC_GP_HW_CTL0, 0x300);
Michael Chanb6016b72005-05-26 13:03:09 -07001877
1878 if (bp->dev->mtu > 1500) {
1879 u32 val;
1880
1881 /* Set extended packet length bit */
1882 bnx2_write_phy(bp, 0x18, 0x7);
1883 bnx2_read_phy(bp, 0x18, &val);
1884 bnx2_write_phy(bp, 0x18, (val & 0xfff8) | 0x4000);
1885
1886 bnx2_write_phy(bp, 0x1c, 0x6c00);
1887 bnx2_read_phy(bp, 0x1c, &val);
1888 bnx2_write_phy(bp, 0x1c, (val & 0x3ff) | 0xec02);
1889 }
1890 else {
1891 u32 val;
1892
1893 bnx2_write_phy(bp, 0x18, 0x7);
1894 bnx2_read_phy(bp, 0x18, &val);
1895 bnx2_write_phy(bp, 0x18, val & ~0x4007);
1896
1897 bnx2_write_phy(bp, 0x1c, 0x6c00);
1898 bnx2_read_phy(bp, 0x1c, &val);
1899 bnx2_write_phy(bp, 0x1c, (val & 0x3fd) | 0xec00);
1900 }
1901
1902 return 0;
1903}
1904
1905static int
1906bnx2_init_copper_phy(struct bnx2 *bp)
1907{
Michael Chan5b0c76a2005-11-04 08:45:49 -08001908 u32 val;
1909
Michael Chan27a005b2007-05-03 13:23:41 -07001910 bnx2_reset_phy(bp);
1911
Michael Chanb6016b72005-05-26 13:03:09 -07001912 if (bp->phy_flags & PHY_CRC_FIX_FLAG) {
1913 bnx2_write_phy(bp, 0x18, 0x0c00);
1914 bnx2_write_phy(bp, 0x17, 0x000a);
1915 bnx2_write_phy(bp, 0x15, 0x310b);
1916 bnx2_write_phy(bp, 0x17, 0x201f);
1917 bnx2_write_phy(bp, 0x15, 0x9506);
1918 bnx2_write_phy(bp, 0x17, 0x401f);
1919 bnx2_write_phy(bp, 0x15, 0x14e2);
1920 bnx2_write_phy(bp, 0x18, 0x0400);
1921 }
1922
Michael Chanb659f442007-02-02 00:46:35 -08001923 if (bp->phy_flags & PHY_DIS_EARLY_DAC_FLAG) {
1924 bnx2_write_phy(bp, MII_BNX2_DSP_ADDRESS,
1925 MII_BNX2_DSP_EXPAND_REG | 0x8);
1926 bnx2_read_phy(bp, MII_BNX2_DSP_RW_PORT, &val);
1927 val &= ~(1 << 8);
1928 bnx2_write_phy(bp, MII_BNX2_DSP_RW_PORT, val);
1929 }
1930
Michael Chanb6016b72005-05-26 13:03:09 -07001931 if (bp->dev->mtu > 1500) {
Michael Chanb6016b72005-05-26 13:03:09 -07001932 /* Set extended packet length bit */
1933 bnx2_write_phy(bp, 0x18, 0x7);
1934 bnx2_read_phy(bp, 0x18, &val);
1935 bnx2_write_phy(bp, 0x18, val | 0x4000);
1936
1937 bnx2_read_phy(bp, 0x10, &val);
1938 bnx2_write_phy(bp, 0x10, val | 0x1);
1939 }
1940 else {
Michael Chanb6016b72005-05-26 13:03:09 -07001941 bnx2_write_phy(bp, 0x18, 0x7);
1942 bnx2_read_phy(bp, 0x18, &val);
1943 bnx2_write_phy(bp, 0x18, val & ~0x4007);
1944
1945 bnx2_read_phy(bp, 0x10, &val);
1946 bnx2_write_phy(bp, 0x10, val & ~0x1);
1947 }
1948
Michael Chan5b0c76a2005-11-04 08:45:49 -08001949 /* ethernet@wirespeed */
1950 bnx2_write_phy(bp, 0x18, 0x7007);
1951 bnx2_read_phy(bp, 0x18, &val);
1952 bnx2_write_phy(bp, 0x18, val | (1 << 15) | (1 << 4));
Michael Chanb6016b72005-05-26 13:03:09 -07001953 return 0;
1954}
1955
1956
1957static int
1958bnx2_init_phy(struct bnx2 *bp)
1959{
1960 u32 val;
1961 int rc = 0;
1962
1963 bp->phy_flags &= ~PHY_INT_MODE_MASK_FLAG;
1964 bp->phy_flags |= PHY_INT_MODE_LINK_READY_FLAG;
1965
Michael Chanca58c3a2007-05-03 13:22:52 -07001966 bp->mii_bmcr = MII_BMCR;
1967 bp->mii_bmsr = MII_BMSR;
Michael Chan27a005b2007-05-03 13:23:41 -07001968 bp->mii_bmsr1 = MII_BMSR;
Michael Chanca58c3a2007-05-03 13:22:52 -07001969 bp->mii_adv = MII_ADVERTISE;
1970 bp->mii_lpa = MII_LPA;
1971
Michael Chanb6016b72005-05-26 13:03:09 -07001972 REG_WR(bp, BNX2_EMAC_ATTENTION_ENA, BNX2_EMAC_ATTENTION_ENA_LINK);
1973
Michael Chan0d8a6572007-07-07 22:49:43 -07001974 if (bp->phy_flags & REMOTE_PHY_CAP_FLAG)
1975 goto setup_phy;
1976
Michael Chanb6016b72005-05-26 13:03:09 -07001977 bnx2_read_phy(bp, MII_PHYSID1, &val);
1978 bp->phy_id = val << 16;
1979 bnx2_read_phy(bp, MII_PHYSID2, &val);
1980 bp->phy_id |= val & 0xffff;
1981
1982 if (bp->phy_flags & PHY_SERDES_FLAG) {
Michael Chan5b0c76a2005-11-04 08:45:49 -08001983 if (CHIP_NUM(bp) == CHIP_NUM_5706)
1984 rc = bnx2_init_5706s_phy(bp);
1985 else if (CHIP_NUM(bp) == CHIP_NUM_5708)
1986 rc = bnx2_init_5708s_phy(bp);
Michael Chan27a005b2007-05-03 13:23:41 -07001987 else if (CHIP_NUM(bp) == CHIP_NUM_5709)
1988 rc = bnx2_init_5709s_phy(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07001989 }
1990 else {
1991 rc = bnx2_init_copper_phy(bp);
1992 }
1993
Michael Chan0d8a6572007-07-07 22:49:43 -07001994setup_phy:
1995 if (!rc)
1996 rc = bnx2_setup_phy(bp, bp->phy_port);
Michael Chanb6016b72005-05-26 13:03:09 -07001997
1998 return rc;
1999}
2000
2001static int
2002bnx2_set_mac_loopback(struct bnx2 *bp)
2003{
2004 u32 mac_mode;
2005
2006 mac_mode = REG_RD(bp, BNX2_EMAC_MODE);
2007 mac_mode &= ~BNX2_EMAC_MODE_PORT;
2008 mac_mode |= BNX2_EMAC_MODE_MAC_LOOP | BNX2_EMAC_MODE_FORCE_LINK;
2009 REG_WR(bp, BNX2_EMAC_MODE, mac_mode);
2010 bp->link_up = 1;
2011 return 0;
2012}
2013
Michael Chanbc5a0692006-01-23 16:13:22 -08002014static int bnx2_test_link(struct bnx2 *);
2015
2016static int
2017bnx2_set_phy_loopback(struct bnx2 *bp)
2018{
2019 u32 mac_mode;
2020 int rc, i;
2021
2022 spin_lock_bh(&bp->phy_lock);
Michael Chanca58c3a2007-05-03 13:22:52 -07002023 rc = bnx2_write_phy(bp, bp->mii_bmcr, BMCR_LOOPBACK | BMCR_FULLDPLX |
Michael Chanbc5a0692006-01-23 16:13:22 -08002024 BMCR_SPEED1000);
2025 spin_unlock_bh(&bp->phy_lock);
2026 if (rc)
2027 return rc;
2028
2029 for (i = 0; i < 10; i++) {
2030 if (bnx2_test_link(bp) == 0)
2031 break;
Michael Chan80be4432006-11-19 14:07:28 -08002032 msleep(100);
Michael Chanbc5a0692006-01-23 16:13:22 -08002033 }
2034
2035 mac_mode = REG_RD(bp, BNX2_EMAC_MODE);
2036 mac_mode &= ~(BNX2_EMAC_MODE_PORT | BNX2_EMAC_MODE_HALF_DUPLEX |
2037 BNX2_EMAC_MODE_MAC_LOOP | BNX2_EMAC_MODE_FORCE_LINK |
Michael Chan59b47d82006-11-19 14:10:45 -08002038 BNX2_EMAC_MODE_25G_MODE);
Michael Chanbc5a0692006-01-23 16:13:22 -08002039
2040 mac_mode |= BNX2_EMAC_MODE_PORT_GMII;
2041 REG_WR(bp, BNX2_EMAC_MODE, mac_mode);
2042 bp->link_up = 1;
2043 return 0;
2044}
2045
Michael Chanb6016b72005-05-26 13:03:09 -07002046static int
Michael Chanb090ae22006-01-23 16:07:10 -08002047bnx2_fw_sync(struct bnx2 *bp, u32 msg_data, int silent)
Michael Chanb6016b72005-05-26 13:03:09 -07002048{
2049 int i;
2050 u32 val;
2051
Michael Chanb6016b72005-05-26 13:03:09 -07002052 bp->fw_wr_seq++;
2053 msg_data |= bp->fw_wr_seq;
2054
Michael Chane3648b32005-11-04 08:51:21 -08002055 REG_WR_IND(bp, bp->shmem_base + BNX2_DRV_MB, msg_data);
Michael Chanb6016b72005-05-26 13:03:09 -07002056
2057 /* wait for an acknowledgement. */
Michael Chanb090ae22006-01-23 16:07:10 -08002058 for (i = 0; i < (FW_ACK_TIME_OUT_MS / 10); i++) {
2059 msleep(10);
Michael Chanb6016b72005-05-26 13:03:09 -07002060
Michael Chane3648b32005-11-04 08:51:21 -08002061 val = REG_RD_IND(bp, bp->shmem_base + BNX2_FW_MB);
Michael Chanb6016b72005-05-26 13:03:09 -07002062
2063 if ((val & BNX2_FW_MSG_ACK) == (msg_data & BNX2_DRV_MSG_SEQ))
2064 break;
2065 }
Michael Chanb090ae22006-01-23 16:07:10 -08002066 if ((msg_data & BNX2_DRV_MSG_DATA) == BNX2_DRV_MSG_DATA_WAIT0)
2067 return 0;
Michael Chanb6016b72005-05-26 13:03:09 -07002068
2069 /* If we timed out, inform the firmware that this is the case. */
Michael Chanb090ae22006-01-23 16:07:10 -08002070 if ((val & BNX2_FW_MSG_ACK) != (msg_data & BNX2_DRV_MSG_SEQ)) {
2071 if (!silent)
2072 printk(KERN_ERR PFX "fw sync timeout, reset code = "
2073 "%x\n", msg_data);
Michael Chanb6016b72005-05-26 13:03:09 -07002074
2075 msg_data &= ~BNX2_DRV_MSG_CODE;
2076 msg_data |= BNX2_DRV_MSG_CODE_FW_TIMEOUT;
2077
Michael Chane3648b32005-11-04 08:51:21 -08002078 REG_WR_IND(bp, bp->shmem_base + BNX2_DRV_MB, msg_data);
Michael Chanb6016b72005-05-26 13:03:09 -07002079
Michael Chanb6016b72005-05-26 13:03:09 -07002080 return -EBUSY;
2081 }
2082
Michael Chanb090ae22006-01-23 16:07:10 -08002083 if ((val & BNX2_FW_MSG_STATUS_MASK) != BNX2_FW_MSG_STATUS_OK)
2084 return -EIO;
2085
Michael Chanb6016b72005-05-26 13:03:09 -07002086 return 0;
2087}
2088
Michael Chan59b47d82006-11-19 14:10:45 -08002089static int
2090bnx2_init_5709_context(struct bnx2 *bp)
2091{
2092 int i, ret = 0;
2093 u32 val;
2094
2095 val = BNX2_CTX_COMMAND_ENABLED | BNX2_CTX_COMMAND_MEM_INIT | (1 << 12);
2096 val |= (BCM_PAGE_BITS - 8) << 16;
2097 REG_WR(bp, BNX2_CTX_COMMAND, val);
Michael Chan641bdcd2007-06-04 21:22:24 -07002098 for (i = 0; i < 10; i++) {
2099 val = REG_RD(bp, BNX2_CTX_COMMAND);
2100 if (!(val & BNX2_CTX_COMMAND_MEM_INIT))
2101 break;
2102 udelay(2);
2103 }
2104 if (val & BNX2_CTX_COMMAND_MEM_INIT)
2105 return -EBUSY;
2106
Michael Chan59b47d82006-11-19 14:10:45 -08002107 for (i = 0; i < bp->ctx_pages; i++) {
2108 int j;
2109
2110 REG_WR(bp, BNX2_CTX_HOST_PAGE_TBL_DATA0,
2111 (bp->ctx_blk_mapping[i] & 0xffffffff) |
2112 BNX2_CTX_HOST_PAGE_TBL_DATA0_VALID);
2113 REG_WR(bp, BNX2_CTX_HOST_PAGE_TBL_DATA1,
2114 (u64) bp->ctx_blk_mapping[i] >> 32);
2115 REG_WR(bp, BNX2_CTX_HOST_PAGE_TBL_CTRL, i |
2116 BNX2_CTX_HOST_PAGE_TBL_CTRL_WRITE_REQ);
2117 for (j = 0; j < 10; j++) {
2118
2119 val = REG_RD(bp, BNX2_CTX_HOST_PAGE_TBL_CTRL);
2120 if (!(val & BNX2_CTX_HOST_PAGE_TBL_CTRL_WRITE_REQ))
2121 break;
2122 udelay(5);
2123 }
2124 if (val & BNX2_CTX_HOST_PAGE_TBL_CTRL_WRITE_REQ) {
2125 ret = -EBUSY;
2126 break;
2127 }
2128 }
2129 return ret;
2130}
2131
Michael Chanb6016b72005-05-26 13:03:09 -07002132static void
2133bnx2_init_context(struct bnx2 *bp)
2134{
2135 u32 vcid;
2136
2137 vcid = 96;
2138 while (vcid) {
2139 u32 vcid_addr, pcid_addr, offset;
Michael Chan7947b202007-06-04 21:17:10 -07002140 int i;
Michael Chanb6016b72005-05-26 13:03:09 -07002141
2142 vcid--;
2143
2144 if (CHIP_ID(bp) == CHIP_ID_5706_A0) {
2145 u32 new_vcid;
2146
2147 vcid_addr = GET_PCID_ADDR(vcid);
2148 if (vcid & 0x8) {
2149 new_vcid = 0x60 + (vcid & 0xf0) + (vcid & 0x7);
2150 }
2151 else {
2152 new_vcid = vcid;
2153 }
2154 pcid_addr = GET_PCID_ADDR(new_vcid);
2155 }
2156 else {
2157 vcid_addr = GET_CID_ADDR(vcid);
2158 pcid_addr = vcid_addr;
2159 }
2160
Michael Chan7947b202007-06-04 21:17:10 -07002161 for (i = 0; i < (CTX_SIZE / PHY_CTX_SIZE); i++) {
2162 vcid_addr += (i << PHY_CTX_SHIFT);
2163 pcid_addr += (i << PHY_CTX_SHIFT);
Michael Chanb6016b72005-05-26 13:03:09 -07002164
Michael Chan5d5d0012007-12-12 11:17:43 -08002165 REG_WR(bp, BNX2_CTX_VIRT_ADDR, vcid_addr);
Michael Chan7947b202007-06-04 21:17:10 -07002166 REG_WR(bp, BNX2_CTX_PAGE_TBL, pcid_addr);
2167
2168 /* Zero out the context. */
2169 for (offset = 0; offset < PHY_CTX_SIZE; offset += 4)
Michael Chan5d5d0012007-12-12 11:17:43 -08002170 CTX_WR(bp, vcid_addr, offset, 0);
Michael Chanb6016b72005-05-26 13:03:09 -07002171 }
Michael Chanb6016b72005-05-26 13:03:09 -07002172 }
2173}
2174
2175static int
2176bnx2_alloc_bad_rbuf(struct bnx2 *bp)
2177{
2178 u16 *good_mbuf;
2179 u32 good_mbuf_cnt;
2180 u32 val;
2181
2182 good_mbuf = kmalloc(512 * sizeof(u16), GFP_KERNEL);
2183 if (good_mbuf == NULL) {
2184 printk(KERN_ERR PFX "Failed to allocate memory in "
2185 "bnx2_alloc_bad_rbuf\n");
2186 return -ENOMEM;
2187 }
2188
2189 REG_WR(bp, BNX2_MISC_ENABLE_SET_BITS,
2190 BNX2_MISC_ENABLE_SET_BITS_RX_MBUF_ENABLE);
2191
2192 good_mbuf_cnt = 0;
2193
2194 /* Allocate a bunch of mbufs and save the good ones in an array. */
2195 val = REG_RD_IND(bp, BNX2_RBUF_STATUS1);
2196 while (val & BNX2_RBUF_STATUS1_FREE_COUNT) {
2197 REG_WR_IND(bp, BNX2_RBUF_COMMAND, BNX2_RBUF_COMMAND_ALLOC_REQ);
2198
2199 val = REG_RD_IND(bp, BNX2_RBUF_FW_BUF_ALLOC);
2200
2201 val &= BNX2_RBUF_FW_BUF_ALLOC_VALUE;
2202
2203 /* The addresses with Bit 9 set are bad memory blocks. */
2204 if (!(val & (1 << 9))) {
2205 good_mbuf[good_mbuf_cnt] = (u16) val;
2206 good_mbuf_cnt++;
2207 }
2208
2209 val = REG_RD_IND(bp, BNX2_RBUF_STATUS1);
2210 }
2211
2212 /* Free the good ones back to the mbuf pool thus discarding
2213 * all the bad ones. */
2214 while (good_mbuf_cnt) {
2215 good_mbuf_cnt--;
2216
2217 val = good_mbuf[good_mbuf_cnt];
2218 val = (val << 9) | val | 1;
2219
2220 REG_WR_IND(bp, BNX2_RBUF_FW_BUF_FREE, val);
2221 }
2222 kfree(good_mbuf);
2223 return 0;
2224}
2225
2226static void
Jeff Garzik6aa20a22006-09-13 13:24:59 -04002227bnx2_set_mac_addr(struct bnx2 *bp)
Michael Chanb6016b72005-05-26 13:03:09 -07002228{
2229 u32 val;
2230 u8 *mac_addr = bp->dev->dev_addr;
2231
2232 val = (mac_addr[0] << 8) | mac_addr[1];
2233
2234 REG_WR(bp, BNX2_EMAC_MAC_MATCH0, val);
2235
Jeff Garzik6aa20a22006-09-13 13:24:59 -04002236 val = (mac_addr[2] << 24) | (mac_addr[3] << 16) |
Michael Chanb6016b72005-05-26 13:03:09 -07002237 (mac_addr[4] << 8) | mac_addr[5];
2238
2239 REG_WR(bp, BNX2_EMAC_MAC_MATCH1, val);
2240}
2241
2242static inline int
Michael Chan47bf4242007-12-12 11:19:12 -08002243bnx2_alloc_rx_page(struct bnx2 *bp, u16 index)
2244{
2245 dma_addr_t mapping;
2246 struct sw_pg *rx_pg = &bp->rx_pg_ring[index];
2247 struct rx_bd *rxbd =
2248 &bp->rx_pg_desc_ring[RX_RING(index)][RX_IDX(index)];
2249 struct page *page = alloc_page(GFP_ATOMIC);
2250
2251 if (!page)
2252 return -ENOMEM;
2253 mapping = pci_map_page(bp->pdev, page, 0, PAGE_SIZE,
2254 PCI_DMA_FROMDEVICE);
2255 rx_pg->page = page;
2256 pci_unmap_addr_set(rx_pg, mapping, mapping);
2257 rxbd->rx_bd_haddr_hi = (u64) mapping >> 32;
2258 rxbd->rx_bd_haddr_lo = (u64) mapping & 0xffffffff;
2259 return 0;
2260}
2261
2262static void
2263bnx2_free_rx_page(struct bnx2 *bp, u16 index)
2264{
2265 struct sw_pg *rx_pg = &bp->rx_pg_ring[index];
2266 struct page *page = rx_pg->page;
2267
2268 if (!page)
2269 return;
2270
2271 pci_unmap_page(bp->pdev, pci_unmap_addr(rx_pg, mapping), PAGE_SIZE,
2272 PCI_DMA_FROMDEVICE);
2273
2274 __free_page(page);
2275 rx_pg->page = NULL;
2276}
2277
2278static inline int
Michael Chana1f60192007-12-20 19:57:19 -08002279bnx2_alloc_rx_skb(struct bnx2 *bp, struct bnx2_napi *bnapi, u16 index)
Michael Chanb6016b72005-05-26 13:03:09 -07002280{
2281 struct sk_buff *skb;
2282 struct sw_bd *rx_buf = &bp->rx_buf_ring[index];
2283 dma_addr_t mapping;
Michael Chan13daffa2006-03-20 17:49:20 -08002284 struct rx_bd *rxbd = &bp->rx_desc_ring[RX_RING(index)][RX_IDX(index)];
Michael Chanb6016b72005-05-26 13:03:09 -07002285 unsigned long align;
2286
Michael Chan932f3772006-08-15 01:39:36 -07002287 skb = netdev_alloc_skb(bp->dev, bp->rx_buf_size);
Michael Chanb6016b72005-05-26 13:03:09 -07002288 if (skb == NULL) {
2289 return -ENOMEM;
2290 }
2291
Michael Chan59b47d82006-11-19 14:10:45 -08002292 if (unlikely((align = (unsigned long) skb->data & (BNX2_RX_ALIGN - 1))))
2293 skb_reserve(skb, BNX2_RX_ALIGN - align);
Michael Chanb6016b72005-05-26 13:03:09 -07002294
Michael Chanb6016b72005-05-26 13:03:09 -07002295 mapping = pci_map_single(bp->pdev, skb->data, bp->rx_buf_use_size,
2296 PCI_DMA_FROMDEVICE);
2297
2298 rx_buf->skb = skb;
2299 pci_unmap_addr_set(rx_buf, mapping, mapping);
2300
2301 rxbd->rx_bd_haddr_hi = (u64) mapping >> 32;
2302 rxbd->rx_bd_haddr_lo = (u64) mapping & 0xffffffff;
2303
Michael Chana1f60192007-12-20 19:57:19 -08002304 bnapi->rx_prod_bseq += bp->rx_buf_use_size;
Michael Chanb6016b72005-05-26 13:03:09 -07002305
2306 return 0;
2307}
2308
Michael Chanda3e4fb2007-05-03 13:24:23 -07002309static int
Michael Chan35efa7c2007-12-20 19:56:37 -08002310bnx2_phy_event_is_set(struct bnx2 *bp, struct bnx2_napi *bnapi, u32 event)
Michael Chanda3e4fb2007-05-03 13:24:23 -07002311{
Michael Chan35efa7c2007-12-20 19:56:37 -08002312 struct status_block *sblk = bnapi->status_blk;
Michael Chanda3e4fb2007-05-03 13:24:23 -07002313 u32 new_link_state, old_link_state;
2314 int is_set = 1;
2315
2316 new_link_state = sblk->status_attn_bits & event;
2317 old_link_state = sblk->status_attn_bits_ack & event;
2318 if (new_link_state != old_link_state) {
2319 if (new_link_state)
2320 REG_WR(bp, BNX2_PCICFG_STATUS_BIT_SET_CMD, event);
2321 else
2322 REG_WR(bp, BNX2_PCICFG_STATUS_BIT_CLEAR_CMD, event);
2323 } else
2324 is_set = 0;
2325
2326 return is_set;
2327}
2328
Michael Chanb6016b72005-05-26 13:03:09 -07002329static void
Michael Chan35efa7c2007-12-20 19:56:37 -08002330bnx2_phy_int(struct bnx2 *bp, struct bnx2_napi *bnapi)
Michael Chanb6016b72005-05-26 13:03:09 -07002331{
Michael Chan35efa7c2007-12-20 19:56:37 -08002332 if (bnx2_phy_event_is_set(bp, bnapi, STATUS_ATTN_BITS_LINK_STATE)) {
Michael Chanda3e4fb2007-05-03 13:24:23 -07002333 spin_lock(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07002334 bnx2_set_link(bp);
Michael Chanda3e4fb2007-05-03 13:24:23 -07002335 spin_unlock(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07002336 }
Michael Chan35efa7c2007-12-20 19:56:37 -08002337 if (bnx2_phy_event_is_set(bp, bnapi, STATUS_ATTN_BITS_TIMER_ABORT))
Michael Chan0d8a6572007-07-07 22:49:43 -07002338 bnx2_set_remote_link(bp);
2339
Michael Chanb6016b72005-05-26 13:03:09 -07002340}
2341
Michael Chanead72702007-12-20 19:55:39 -08002342static inline u16
Michael Chan35efa7c2007-12-20 19:56:37 -08002343bnx2_get_hw_tx_cons(struct bnx2_napi *bnapi)
Michael Chanead72702007-12-20 19:55:39 -08002344{
2345 u16 cons;
2346
Michael Chan35efa7c2007-12-20 19:56:37 -08002347 cons = bnapi->status_blk->status_tx_quick_consumer_index0;
Michael Chanead72702007-12-20 19:55:39 -08002348
2349 if (unlikely((cons & MAX_TX_DESC_CNT) == MAX_TX_DESC_CNT))
2350 cons++;
2351 return cons;
2352}
2353
Michael Chanb6016b72005-05-26 13:03:09 -07002354static void
Michael Chan35efa7c2007-12-20 19:56:37 -08002355bnx2_tx_int(struct bnx2 *bp, struct bnx2_napi *bnapi)
Michael Chanb6016b72005-05-26 13:03:09 -07002356{
2357 u16 hw_cons, sw_cons, sw_ring_cons;
2358 int tx_free_bd = 0;
2359
Michael Chan35efa7c2007-12-20 19:56:37 -08002360 hw_cons = bnx2_get_hw_tx_cons(bnapi);
Michael Chana550c992007-12-20 19:56:59 -08002361 sw_cons = bnapi->tx_cons;
Michael Chanb6016b72005-05-26 13:03:09 -07002362
2363 while (sw_cons != hw_cons) {
2364 struct sw_bd *tx_buf;
2365 struct sk_buff *skb;
2366 int i, last;
2367
2368 sw_ring_cons = TX_RING_IDX(sw_cons);
2369
2370 tx_buf = &bp->tx_buf_ring[sw_ring_cons];
2371 skb = tx_buf->skb;
Arjan van de Ven1d39ed52006-12-12 14:06:23 +01002372
Michael Chanb6016b72005-05-26 13:03:09 -07002373 /* partial BD completions possible with TSO packets */
Herbert Xu89114af2006-07-08 13:34:32 -07002374 if (skb_is_gso(skb)) {
Michael Chanb6016b72005-05-26 13:03:09 -07002375 u16 last_idx, last_ring_idx;
2376
2377 last_idx = sw_cons +
2378 skb_shinfo(skb)->nr_frags + 1;
2379 last_ring_idx = sw_ring_cons +
2380 skb_shinfo(skb)->nr_frags + 1;
2381 if (unlikely(last_ring_idx >= MAX_TX_DESC_CNT)) {
2382 last_idx++;
2383 }
2384 if (((s16) ((s16) last_idx - (s16) hw_cons)) > 0) {
2385 break;
2386 }
2387 }
Arjan van de Ven1d39ed52006-12-12 14:06:23 +01002388
Michael Chanb6016b72005-05-26 13:03:09 -07002389 pci_unmap_single(bp->pdev, pci_unmap_addr(tx_buf, mapping),
2390 skb_headlen(skb), PCI_DMA_TODEVICE);
2391
2392 tx_buf->skb = NULL;
2393 last = skb_shinfo(skb)->nr_frags;
2394
2395 for (i = 0; i < last; i++) {
2396 sw_cons = NEXT_TX_BD(sw_cons);
2397
2398 pci_unmap_page(bp->pdev,
2399 pci_unmap_addr(
2400 &bp->tx_buf_ring[TX_RING_IDX(sw_cons)],
2401 mapping),
2402 skb_shinfo(skb)->frags[i].size,
2403 PCI_DMA_TODEVICE);
2404 }
2405
2406 sw_cons = NEXT_TX_BD(sw_cons);
2407
2408 tx_free_bd += last + 1;
2409
Michael Chan745720e2006-06-29 12:37:41 -07002410 dev_kfree_skb(skb);
Michael Chanb6016b72005-05-26 13:03:09 -07002411
Michael Chan35efa7c2007-12-20 19:56:37 -08002412 hw_cons = bnx2_get_hw_tx_cons(bnapi);
Michael Chanb6016b72005-05-26 13:03:09 -07002413 }
2414
Michael Chana550c992007-12-20 19:56:59 -08002415 bnapi->hw_tx_cons = hw_cons;
2416 bnapi->tx_cons = sw_cons;
Michael Chan2f8af122006-08-15 01:39:10 -07002417 /* Need to make the tx_cons update visible to bnx2_start_xmit()
2418 * before checking for netif_queue_stopped(). Without the
2419 * memory barrier, there is a small possibility that bnx2_start_xmit()
2420 * will miss it and cause the queue to be stopped forever.
2421 */
2422 smp_mb();
Michael Chanb6016b72005-05-26 13:03:09 -07002423
Michael Chan2f8af122006-08-15 01:39:10 -07002424 if (unlikely(netif_queue_stopped(bp->dev)) &&
Michael Chana550c992007-12-20 19:56:59 -08002425 (bnx2_tx_avail(bp, bnapi) > bp->tx_wake_thresh)) {
Michael Chan2f8af122006-08-15 01:39:10 -07002426 netif_tx_lock(bp->dev);
Michael Chanb6016b72005-05-26 13:03:09 -07002427 if ((netif_queue_stopped(bp->dev)) &&
Michael Chana550c992007-12-20 19:56:59 -08002428 (bnx2_tx_avail(bp, bnapi) > bp->tx_wake_thresh))
Michael Chanb6016b72005-05-26 13:03:09 -07002429 netif_wake_queue(bp->dev);
Michael Chan2f8af122006-08-15 01:39:10 -07002430 netif_tx_unlock(bp->dev);
Michael Chanb6016b72005-05-26 13:03:09 -07002431 }
Michael Chanb6016b72005-05-26 13:03:09 -07002432}
2433
Michael Chan1db82f22007-12-12 11:19:35 -08002434static void
Michael Chana1f60192007-12-20 19:57:19 -08002435bnx2_reuse_rx_skb_pages(struct bnx2 *bp, struct bnx2_napi *bnapi,
2436 struct sk_buff *skb, int count)
Michael Chan1db82f22007-12-12 11:19:35 -08002437{
2438 struct sw_pg *cons_rx_pg, *prod_rx_pg;
2439 struct rx_bd *cons_bd, *prod_bd;
2440 dma_addr_t mapping;
2441 int i;
Michael Chana1f60192007-12-20 19:57:19 -08002442 u16 hw_prod = bnapi->rx_pg_prod, prod;
2443 u16 cons = bnapi->rx_pg_cons;
Michael Chan1db82f22007-12-12 11:19:35 -08002444
2445 for (i = 0; i < count; i++) {
2446 prod = RX_PG_RING_IDX(hw_prod);
2447
2448 prod_rx_pg = &bp->rx_pg_ring[prod];
2449 cons_rx_pg = &bp->rx_pg_ring[cons];
2450 cons_bd = &bp->rx_pg_desc_ring[RX_RING(cons)][RX_IDX(cons)];
2451 prod_bd = &bp->rx_pg_desc_ring[RX_RING(prod)][RX_IDX(prod)];
2452
2453 if (i == 0 && skb) {
2454 struct page *page;
2455 struct skb_shared_info *shinfo;
2456
2457 shinfo = skb_shinfo(skb);
2458 shinfo->nr_frags--;
2459 page = shinfo->frags[shinfo->nr_frags].page;
2460 shinfo->frags[shinfo->nr_frags].page = NULL;
2461 mapping = pci_map_page(bp->pdev, page, 0, PAGE_SIZE,
2462 PCI_DMA_FROMDEVICE);
2463 cons_rx_pg->page = page;
2464 pci_unmap_addr_set(cons_rx_pg, mapping, mapping);
2465 dev_kfree_skb(skb);
2466 }
2467 if (prod != cons) {
2468 prod_rx_pg->page = cons_rx_pg->page;
2469 cons_rx_pg->page = NULL;
2470 pci_unmap_addr_set(prod_rx_pg, mapping,
2471 pci_unmap_addr(cons_rx_pg, mapping));
2472
2473 prod_bd->rx_bd_haddr_hi = cons_bd->rx_bd_haddr_hi;
2474 prod_bd->rx_bd_haddr_lo = cons_bd->rx_bd_haddr_lo;
2475
2476 }
2477 cons = RX_PG_RING_IDX(NEXT_RX_BD(cons));
2478 hw_prod = NEXT_RX_BD(hw_prod);
2479 }
Michael Chana1f60192007-12-20 19:57:19 -08002480 bnapi->rx_pg_prod = hw_prod;
2481 bnapi->rx_pg_cons = cons;
Michael Chan1db82f22007-12-12 11:19:35 -08002482}
2483
Michael Chanb6016b72005-05-26 13:03:09 -07002484static inline void
Michael Chana1f60192007-12-20 19:57:19 -08002485bnx2_reuse_rx_skb(struct bnx2 *bp, struct bnx2_napi *bnapi, struct sk_buff *skb,
Michael Chanb6016b72005-05-26 13:03:09 -07002486 u16 cons, u16 prod)
2487{
Michael Chan236b6392006-03-20 17:49:02 -08002488 struct sw_bd *cons_rx_buf, *prod_rx_buf;
2489 struct rx_bd *cons_bd, *prod_bd;
2490
2491 cons_rx_buf = &bp->rx_buf_ring[cons];
2492 prod_rx_buf = &bp->rx_buf_ring[prod];
Michael Chanb6016b72005-05-26 13:03:09 -07002493
2494 pci_dma_sync_single_for_device(bp->pdev,
2495 pci_unmap_addr(cons_rx_buf, mapping),
2496 bp->rx_offset + RX_COPY_THRESH, PCI_DMA_FROMDEVICE);
2497
Michael Chana1f60192007-12-20 19:57:19 -08002498 bnapi->rx_prod_bseq += bp->rx_buf_use_size;
Michael Chan236b6392006-03-20 17:49:02 -08002499
2500 prod_rx_buf->skb = skb;
2501
2502 if (cons == prod)
2503 return;
2504
Michael Chanb6016b72005-05-26 13:03:09 -07002505 pci_unmap_addr_set(prod_rx_buf, mapping,
2506 pci_unmap_addr(cons_rx_buf, mapping));
2507
Michael Chan3fdfcc22006-03-20 17:49:49 -08002508 cons_bd = &bp->rx_desc_ring[RX_RING(cons)][RX_IDX(cons)];
2509 prod_bd = &bp->rx_desc_ring[RX_RING(prod)][RX_IDX(prod)];
Michael Chan236b6392006-03-20 17:49:02 -08002510 prod_bd->rx_bd_haddr_hi = cons_bd->rx_bd_haddr_hi;
2511 prod_bd->rx_bd_haddr_lo = cons_bd->rx_bd_haddr_lo;
Michael Chanb6016b72005-05-26 13:03:09 -07002512}
2513
Michael Chan85833c62007-12-12 11:17:01 -08002514static int
Michael Chana1f60192007-12-20 19:57:19 -08002515bnx2_rx_skb(struct bnx2 *bp, struct bnx2_napi *bnapi, struct sk_buff *skb,
2516 unsigned int len, unsigned int hdr_len, dma_addr_t dma_addr,
2517 u32 ring_idx)
Michael Chan85833c62007-12-12 11:17:01 -08002518{
2519 int err;
2520 u16 prod = ring_idx & 0xffff;
2521
Michael Chana1f60192007-12-20 19:57:19 -08002522 err = bnx2_alloc_rx_skb(bp, bnapi, prod);
Michael Chan85833c62007-12-12 11:17:01 -08002523 if (unlikely(err)) {
Michael Chana1f60192007-12-20 19:57:19 -08002524 bnx2_reuse_rx_skb(bp, bnapi, skb, (u16) (ring_idx >> 16), prod);
Michael Chan1db82f22007-12-12 11:19:35 -08002525 if (hdr_len) {
2526 unsigned int raw_len = len + 4;
2527 int pages = PAGE_ALIGN(raw_len - hdr_len) >> PAGE_SHIFT;
2528
Michael Chana1f60192007-12-20 19:57:19 -08002529 bnx2_reuse_rx_skb_pages(bp, bnapi, NULL, pages);
Michael Chan1db82f22007-12-12 11:19:35 -08002530 }
Michael Chan85833c62007-12-12 11:17:01 -08002531 return err;
2532 }
2533
2534 skb_reserve(skb, bp->rx_offset);
2535 pci_unmap_single(bp->pdev, dma_addr, bp->rx_buf_use_size,
2536 PCI_DMA_FROMDEVICE);
2537
Michael Chan1db82f22007-12-12 11:19:35 -08002538 if (hdr_len == 0) {
2539 skb_put(skb, len);
2540 return 0;
2541 } else {
2542 unsigned int i, frag_len, frag_size, pages;
2543 struct sw_pg *rx_pg;
Michael Chana1f60192007-12-20 19:57:19 -08002544 u16 pg_cons = bnapi->rx_pg_cons;
2545 u16 pg_prod = bnapi->rx_pg_prod;
Michael Chan1db82f22007-12-12 11:19:35 -08002546
2547 frag_size = len + 4 - hdr_len;
2548 pages = PAGE_ALIGN(frag_size) >> PAGE_SHIFT;
2549 skb_put(skb, hdr_len);
2550
2551 for (i = 0; i < pages; i++) {
2552 frag_len = min(frag_size, (unsigned int) PAGE_SIZE);
2553 if (unlikely(frag_len <= 4)) {
2554 unsigned int tail = 4 - frag_len;
2555
Michael Chana1f60192007-12-20 19:57:19 -08002556 bnapi->rx_pg_cons = pg_cons;
2557 bnapi->rx_pg_prod = pg_prod;
2558 bnx2_reuse_rx_skb_pages(bp, bnapi, NULL,
2559 pages - i);
Michael Chan1db82f22007-12-12 11:19:35 -08002560 skb->len -= tail;
2561 if (i == 0) {
2562 skb->tail -= tail;
2563 } else {
2564 skb_frag_t *frag =
2565 &skb_shinfo(skb)->frags[i - 1];
2566 frag->size -= tail;
2567 skb->data_len -= tail;
2568 skb->truesize -= tail;
2569 }
2570 return 0;
2571 }
2572 rx_pg = &bp->rx_pg_ring[pg_cons];
2573
2574 pci_unmap_page(bp->pdev, pci_unmap_addr(rx_pg, mapping),
2575 PAGE_SIZE, PCI_DMA_FROMDEVICE);
2576
2577 if (i == pages - 1)
2578 frag_len -= 4;
2579
2580 skb_fill_page_desc(skb, i, rx_pg->page, 0, frag_len);
2581 rx_pg->page = NULL;
2582
2583 err = bnx2_alloc_rx_page(bp, RX_PG_RING_IDX(pg_prod));
2584 if (unlikely(err)) {
Michael Chana1f60192007-12-20 19:57:19 -08002585 bnapi->rx_pg_cons = pg_cons;
2586 bnapi->rx_pg_prod = pg_prod;
2587 bnx2_reuse_rx_skb_pages(bp, bnapi, skb,
2588 pages - i);
Michael Chan1db82f22007-12-12 11:19:35 -08002589 return err;
2590 }
2591
2592 frag_size -= frag_len;
2593 skb->data_len += frag_len;
2594 skb->truesize += frag_len;
2595 skb->len += frag_len;
2596
2597 pg_prod = NEXT_RX_BD(pg_prod);
2598 pg_cons = RX_PG_RING_IDX(NEXT_RX_BD(pg_cons));
2599 }
Michael Chana1f60192007-12-20 19:57:19 -08002600 bnapi->rx_pg_prod = pg_prod;
2601 bnapi->rx_pg_cons = pg_cons;
Michael Chan1db82f22007-12-12 11:19:35 -08002602 }
Michael Chan85833c62007-12-12 11:17:01 -08002603 return 0;
2604}
2605
Michael Chanc09c2622007-12-10 17:18:37 -08002606static inline u16
Michael Chan35efa7c2007-12-20 19:56:37 -08002607bnx2_get_hw_rx_cons(struct bnx2_napi *bnapi)
Michael Chanc09c2622007-12-10 17:18:37 -08002608{
Michael Chan35efa7c2007-12-20 19:56:37 -08002609 u16 cons = bnapi->status_blk->status_rx_quick_consumer_index0;
Michael Chanc09c2622007-12-10 17:18:37 -08002610
2611 if (unlikely((cons & MAX_RX_DESC_CNT) == MAX_RX_DESC_CNT))
2612 cons++;
2613 return cons;
2614}
2615
Michael Chanb6016b72005-05-26 13:03:09 -07002616static int
Michael Chan35efa7c2007-12-20 19:56:37 -08002617bnx2_rx_int(struct bnx2 *bp, struct bnx2_napi *bnapi, int budget)
Michael Chanb6016b72005-05-26 13:03:09 -07002618{
2619 u16 hw_cons, sw_cons, sw_ring_cons, sw_prod, sw_ring_prod;
2620 struct l2_fhdr *rx_hdr;
Michael Chan1db82f22007-12-12 11:19:35 -08002621 int rx_pkt = 0, pg_ring_used = 0;
Michael Chanb6016b72005-05-26 13:03:09 -07002622
Michael Chan35efa7c2007-12-20 19:56:37 -08002623 hw_cons = bnx2_get_hw_rx_cons(bnapi);
Michael Chana1f60192007-12-20 19:57:19 -08002624 sw_cons = bnapi->rx_cons;
2625 sw_prod = bnapi->rx_prod;
Michael Chanb6016b72005-05-26 13:03:09 -07002626
2627 /* Memory barrier necessary as speculative reads of the rx
2628 * buffer can be ahead of the index in the status block
2629 */
2630 rmb();
2631 while (sw_cons != hw_cons) {
Michael Chan1db82f22007-12-12 11:19:35 -08002632 unsigned int len, hdr_len;
Michael Chanade2bfe2006-01-23 16:09:51 -08002633 u32 status;
Michael Chanb6016b72005-05-26 13:03:09 -07002634 struct sw_bd *rx_buf;
2635 struct sk_buff *skb;
Michael Chan236b6392006-03-20 17:49:02 -08002636 dma_addr_t dma_addr;
Michael Chanb6016b72005-05-26 13:03:09 -07002637
2638 sw_ring_cons = RX_RING_IDX(sw_cons);
2639 sw_ring_prod = RX_RING_IDX(sw_prod);
2640
2641 rx_buf = &bp->rx_buf_ring[sw_ring_cons];
2642 skb = rx_buf->skb;
Michael Chan236b6392006-03-20 17:49:02 -08002643
2644 rx_buf->skb = NULL;
2645
2646 dma_addr = pci_unmap_addr(rx_buf, mapping);
2647
2648 pci_dma_sync_single_for_cpu(bp->pdev, dma_addr,
Michael Chanb6016b72005-05-26 13:03:09 -07002649 bp->rx_offset + RX_COPY_THRESH, PCI_DMA_FROMDEVICE);
2650
2651 rx_hdr = (struct l2_fhdr *) skb->data;
Michael Chan1db82f22007-12-12 11:19:35 -08002652 len = rx_hdr->l2_fhdr_pkt_len;
Michael Chanb6016b72005-05-26 13:03:09 -07002653
Michael Chanade2bfe2006-01-23 16:09:51 -08002654 if ((status = rx_hdr->l2_fhdr_status) &
Michael Chanb6016b72005-05-26 13:03:09 -07002655 (L2_FHDR_ERRORS_BAD_CRC |
2656 L2_FHDR_ERRORS_PHY_DECODE |
2657 L2_FHDR_ERRORS_ALIGNMENT |
2658 L2_FHDR_ERRORS_TOO_SHORT |
2659 L2_FHDR_ERRORS_GIANT_FRAME)) {
2660
Michael Chana1f60192007-12-20 19:57:19 -08002661 bnx2_reuse_rx_skb(bp, bnapi, skb, sw_ring_cons,
2662 sw_ring_prod);
Michael Chan85833c62007-12-12 11:17:01 -08002663 goto next_rx;
Michael Chanb6016b72005-05-26 13:03:09 -07002664 }
Michael Chan1db82f22007-12-12 11:19:35 -08002665 hdr_len = 0;
2666 if (status & L2_FHDR_STATUS_SPLIT) {
2667 hdr_len = rx_hdr->l2_fhdr_ip_xsum;
2668 pg_ring_used = 1;
2669 } else if (len > bp->rx_jumbo_thresh) {
2670 hdr_len = bp->rx_jumbo_thresh;
2671 pg_ring_used = 1;
2672 }
2673
2674 len -= 4;
Michael Chanb6016b72005-05-26 13:03:09 -07002675
Michael Chan5d5d0012007-12-12 11:17:43 -08002676 if (len <= bp->rx_copy_thresh) {
Michael Chanb6016b72005-05-26 13:03:09 -07002677 struct sk_buff *new_skb;
2678
Michael Chan932f3772006-08-15 01:39:36 -07002679 new_skb = netdev_alloc_skb(bp->dev, len + 2);
Michael Chan85833c62007-12-12 11:17:01 -08002680 if (new_skb == NULL) {
Michael Chana1f60192007-12-20 19:57:19 -08002681 bnx2_reuse_rx_skb(bp, bnapi, skb, sw_ring_cons,
Michael Chan85833c62007-12-12 11:17:01 -08002682 sw_ring_prod);
2683 goto next_rx;
2684 }
Michael Chanb6016b72005-05-26 13:03:09 -07002685
2686 /* aligned copy */
Arnaldo Carvalho de Melod626f622007-03-27 18:55:52 -03002687 skb_copy_from_linear_data_offset(skb, bp->rx_offset - 2,
2688 new_skb->data, len + 2);
Michael Chanb6016b72005-05-26 13:03:09 -07002689 skb_reserve(new_skb, 2);
2690 skb_put(new_skb, len);
Michael Chanb6016b72005-05-26 13:03:09 -07002691
Michael Chana1f60192007-12-20 19:57:19 -08002692 bnx2_reuse_rx_skb(bp, bnapi, skb,
Michael Chanb6016b72005-05-26 13:03:09 -07002693 sw_ring_cons, sw_ring_prod);
2694
2695 skb = new_skb;
Michael Chana1f60192007-12-20 19:57:19 -08002696 } else if (unlikely(bnx2_rx_skb(bp, bnapi, skb, len, hdr_len,
2697 dma_addr, (sw_ring_cons << 16) | sw_ring_prod)))
Michael Chanb6016b72005-05-26 13:03:09 -07002698 goto next_rx;
Michael Chanb6016b72005-05-26 13:03:09 -07002699
2700 skb->protocol = eth_type_trans(skb, bp->dev);
2701
2702 if ((len > (bp->dev->mtu + ETH_HLEN)) &&
Alexey Dobriyand1e100b2006-06-11 20:57:17 -07002703 (ntohs(skb->protocol) != 0x8100)) {
Michael Chanb6016b72005-05-26 13:03:09 -07002704
Michael Chan745720e2006-06-29 12:37:41 -07002705 dev_kfree_skb(skb);
Michael Chanb6016b72005-05-26 13:03:09 -07002706 goto next_rx;
2707
2708 }
2709
Michael Chanb6016b72005-05-26 13:03:09 -07002710 skb->ip_summed = CHECKSUM_NONE;
2711 if (bp->rx_csum &&
2712 (status & (L2_FHDR_STATUS_TCP_SEGMENT |
2713 L2_FHDR_STATUS_UDP_DATAGRAM))) {
2714
Michael Chanade2bfe2006-01-23 16:09:51 -08002715 if (likely((status & (L2_FHDR_ERRORS_TCP_XSUM |
2716 L2_FHDR_ERRORS_UDP_XSUM)) == 0))
Michael Chanb6016b72005-05-26 13:03:09 -07002717 skb->ip_summed = CHECKSUM_UNNECESSARY;
2718 }
2719
2720#ifdef BCM_VLAN
2721 if ((status & L2_FHDR_STATUS_L2_VLAN_TAG) && (bp->vlgrp != 0)) {
2722 vlan_hwaccel_receive_skb(skb, bp->vlgrp,
2723 rx_hdr->l2_fhdr_vlan_tag);
2724 }
2725 else
2726#endif
2727 netif_receive_skb(skb);
2728
2729 bp->dev->last_rx = jiffies;
2730 rx_pkt++;
2731
2732next_rx:
Michael Chanb6016b72005-05-26 13:03:09 -07002733 sw_cons = NEXT_RX_BD(sw_cons);
2734 sw_prod = NEXT_RX_BD(sw_prod);
2735
2736 if ((rx_pkt == budget))
2737 break;
Michael Chanf4e418f2005-11-04 08:53:48 -08002738
2739 /* Refresh hw_cons to see if there is new work */
2740 if (sw_cons == hw_cons) {
Michael Chan35efa7c2007-12-20 19:56:37 -08002741 hw_cons = bnx2_get_hw_rx_cons(bnapi);
Michael Chanf4e418f2005-11-04 08:53:48 -08002742 rmb();
2743 }
Michael Chanb6016b72005-05-26 13:03:09 -07002744 }
Michael Chana1f60192007-12-20 19:57:19 -08002745 bnapi->rx_cons = sw_cons;
2746 bnapi->rx_prod = sw_prod;
Michael Chanb6016b72005-05-26 13:03:09 -07002747
Michael Chan1db82f22007-12-12 11:19:35 -08002748 if (pg_ring_used)
2749 REG_WR16(bp, MB_RX_CID_ADDR + BNX2_L2CTX_HOST_PG_BDIDX,
Michael Chana1f60192007-12-20 19:57:19 -08002750 bnapi->rx_pg_prod);
Michael Chan1db82f22007-12-12 11:19:35 -08002751
Michael Chanb6016b72005-05-26 13:03:09 -07002752 REG_WR16(bp, MB_RX_CID_ADDR + BNX2_L2CTX_HOST_BDIDX, sw_prod);
2753
Michael Chana1f60192007-12-20 19:57:19 -08002754 REG_WR(bp, MB_RX_CID_ADDR + BNX2_L2CTX_HOST_BSEQ, bnapi->rx_prod_bseq);
Michael Chanb6016b72005-05-26 13:03:09 -07002755
2756 mmiowb();
2757
2758 return rx_pkt;
2759
2760}
2761
2762/* MSI ISR - The only difference between this and the INTx ISR
2763 * is that the MSI interrupt is always serviced.
2764 */
2765static irqreturn_t
David Howells7d12e782006-10-05 14:55:46 +01002766bnx2_msi(int irq, void *dev_instance)
Michael Chanb6016b72005-05-26 13:03:09 -07002767{
2768 struct net_device *dev = dev_instance;
Michael Chan972ec0d2006-01-23 16:12:43 -08002769 struct bnx2 *bp = netdev_priv(dev);
Michael Chan35efa7c2007-12-20 19:56:37 -08002770 struct bnx2_napi *bnapi = &bp->bnx2_napi;
Michael Chanb6016b72005-05-26 13:03:09 -07002771
Michael Chan35efa7c2007-12-20 19:56:37 -08002772 prefetch(bnapi->status_blk);
Michael Chanb6016b72005-05-26 13:03:09 -07002773 REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
2774 BNX2_PCICFG_INT_ACK_CMD_USE_INT_HC_PARAM |
2775 BNX2_PCICFG_INT_ACK_CMD_MASK_INT);
2776
2777 /* Return here if interrupt is disabled. */
Michael Chan73eef4c2005-08-25 15:39:15 -07002778 if (unlikely(atomic_read(&bp->intr_sem) != 0))
2779 return IRQ_HANDLED;
Michael Chanb6016b72005-05-26 13:03:09 -07002780
Michael Chan35efa7c2007-12-20 19:56:37 -08002781 netif_rx_schedule(dev, &bnapi->napi);
Michael Chanb6016b72005-05-26 13:03:09 -07002782
Michael Chan73eef4c2005-08-25 15:39:15 -07002783 return IRQ_HANDLED;
Michael Chanb6016b72005-05-26 13:03:09 -07002784}
2785
2786static irqreturn_t
Michael Chan8e6a72c2007-05-03 13:24:48 -07002787bnx2_msi_1shot(int irq, void *dev_instance)
2788{
2789 struct net_device *dev = dev_instance;
2790 struct bnx2 *bp = netdev_priv(dev);
Michael Chan35efa7c2007-12-20 19:56:37 -08002791 struct bnx2_napi *bnapi = &bp->bnx2_napi;
Michael Chan8e6a72c2007-05-03 13:24:48 -07002792
Michael Chan35efa7c2007-12-20 19:56:37 -08002793 prefetch(bnapi->status_blk);
Michael Chan8e6a72c2007-05-03 13:24:48 -07002794
2795 /* Return here if interrupt is disabled. */
2796 if (unlikely(atomic_read(&bp->intr_sem) != 0))
2797 return IRQ_HANDLED;
2798
Michael Chan35efa7c2007-12-20 19:56:37 -08002799 netif_rx_schedule(dev, &bnapi->napi);
Michael Chan8e6a72c2007-05-03 13:24:48 -07002800
2801 return IRQ_HANDLED;
2802}
2803
2804static irqreturn_t
David Howells7d12e782006-10-05 14:55:46 +01002805bnx2_interrupt(int irq, void *dev_instance)
Michael Chanb6016b72005-05-26 13:03:09 -07002806{
2807 struct net_device *dev = dev_instance;
Michael Chan972ec0d2006-01-23 16:12:43 -08002808 struct bnx2 *bp = netdev_priv(dev);
Michael Chan35efa7c2007-12-20 19:56:37 -08002809 struct bnx2_napi *bnapi = &bp->bnx2_napi;
2810 struct status_block *sblk = bnapi->status_blk;
Michael Chanb6016b72005-05-26 13:03:09 -07002811
2812 /* When using INTx, it is possible for the interrupt to arrive
2813 * at the CPU before the status block posted prior to the
2814 * interrupt. Reading a register will flush the status block.
2815 * When using MSI, the MSI message will always complete after
2816 * the status block write.
2817 */
Michael Chan35efa7c2007-12-20 19:56:37 -08002818 if ((sblk->status_idx == bnapi->last_status_idx) &&
Michael Chanb6016b72005-05-26 13:03:09 -07002819 (REG_RD(bp, BNX2_PCICFG_MISC_STATUS) &
2820 BNX2_PCICFG_MISC_STATUS_INTA_VALUE))
Michael Chan73eef4c2005-08-25 15:39:15 -07002821 return IRQ_NONE;
Michael Chanb6016b72005-05-26 13:03:09 -07002822
2823 REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
2824 BNX2_PCICFG_INT_ACK_CMD_USE_INT_HC_PARAM |
2825 BNX2_PCICFG_INT_ACK_CMD_MASK_INT);
2826
Michael Chanb8a7ce72007-07-07 22:51:03 -07002827 /* Read back to deassert IRQ immediately to avoid too many
2828 * spurious interrupts.
2829 */
2830 REG_RD(bp, BNX2_PCICFG_INT_ACK_CMD);
2831
Michael Chanb6016b72005-05-26 13:03:09 -07002832 /* Return here if interrupt is shared and is disabled. */
Michael Chan73eef4c2005-08-25 15:39:15 -07002833 if (unlikely(atomic_read(&bp->intr_sem) != 0))
2834 return IRQ_HANDLED;
Michael Chanb6016b72005-05-26 13:03:09 -07002835
Michael Chan35efa7c2007-12-20 19:56:37 -08002836 if (netif_rx_schedule_prep(dev, &bnapi->napi)) {
2837 bnapi->last_status_idx = sblk->status_idx;
2838 __netif_rx_schedule(dev, &bnapi->napi);
Michael Chanb8a7ce72007-07-07 22:51:03 -07002839 }
Michael Chanb6016b72005-05-26 13:03:09 -07002840
Michael Chan73eef4c2005-08-25 15:39:15 -07002841 return IRQ_HANDLED;
Michael Chanb6016b72005-05-26 13:03:09 -07002842}
2843
Michael Chan0d8a6572007-07-07 22:49:43 -07002844#define STATUS_ATTN_EVENTS (STATUS_ATTN_BITS_LINK_STATE | \
2845 STATUS_ATTN_BITS_TIMER_ABORT)
Michael Chanda3e4fb2007-05-03 13:24:23 -07002846
Michael Chanf4e418f2005-11-04 08:53:48 -08002847static inline int
Michael Chan35efa7c2007-12-20 19:56:37 -08002848bnx2_has_work(struct bnx2_napi *bnapi)
Michael Chanf4e418f2005-11-04 08:53:48 -08002849{
Michael Chan35efa7c2007-12-20 19:56:37 -08002850 struct bnx2 *bp = bnapi->bp;
Michael Chanf4e418f2005-11-04 08:53:48 -08002851 struct status_block *sblk = bp->status_blk;
2852
Michael Chana1f60192007-12-20 19:57:19 -08002853 if ((bnx2_get_hw_rx_cons(bnapi) != bnapi->rx_cons) ||
Michael Chana550c992007-12-20 19:56:59 -08002854 (bnx2_get_hw_tx_cons(bnapi) != bnapi->hw_tx_cons))
Michael Chanf4e418f2005-11-04 08:53:48 -08002855 return 1;
2856
Michael Chanda3e4fb2007-05-03 13:24:23 -07002857 if ((sblk->status_attn_bits & STATUS_ATTN_EVENTS) !=
2858 (sblk->status_attn_bits_ack & STATUS_ATTN_EVENTS))
Michael Chanf4e418f2005-11-04 08:53:48 -08002859 return 1;
2860
2861 return 0;
2862}
2863
Michael Chan35efa7c2007-12-20 19:56:37 -08002864static int bnx2_poll_work(struct bnx2 *bp, struct bnx2_napi *bnapi,
2865 int work_done, int budget)
Michael Chanb6016b72005-05-26 13:03:09 -07002866{
Michael Chan35efa7c2007-12-20 19:56:37 -08002867 struct status_block *sblk = bnapi->status_blk;
Michael Chanda3e4fb2007-05-03 13:24:23 -07002868 u32 status_attn_bits = sblk->status_attn_bits;
2869 u32 status_attn_bits_ack = sblk->status_attn_bits_ack;
Michael Chanb6016b72005-05-26 13:03:09 -07002870
Michael Chanda3e4fb2007-05-03 13:24:23 -07002871 if ((status_attn_bits & STATUS_ATTN_EVENTS) !=
2872 (status_attn_bits_ack & STATUS_ATTN_EVENTS)) {
Michael Chanb6016b72005-05-26 13:03:09 -07002873
Michael Chan35efa7c2007-12-20 19:56:37 -08002874 bnx2_phy_int(bp, bnapi);
Michael Chanbf5295b2006-03-23 01:11:56 -08002875
2876 /* This is needed to take care of transient status
2877 * during link changes.
2878 */
2879 REG_WR(bp, BNX2_HC_COMMAND,
2880 bp->hc_cmd | BNX2_HC_COMMAND_COAL_NOW_WO_INT);
2881 REG_RD(bp, BNX2_HC_COMMAND);
Michael Chanb6016b72005-05-26 13:03:09 -07002882 }
2883
Michael Chana550c992007-12-20 19:56:59 -08002884 if (bnx2_get_hw_tx_cons(bnapi) != bnapi->hw_tx_cons)
Michael Chan35efa7c2007-12-20 19:56:37 -08002885 bnx2_tx_int(bp, bnapi);
Michael Chanb6016b72005-05-26 13:03:09 -07002886
Michael Chana1f60192007-12-20 19:57:19 -08002887 if (bnx2_get_hw_rx_cons(bnapi) != bnapi->rx_cons)
Michael Chan35efa7c2007-12-20 19:56:37 -08002888 work_done += bnx2_rx_int(bp, bnapi, budget - work_done);
Jeff Garzik6aa20a22006-09-13 13:24:59 -04002889
David S. Miller6f535762007-10-11 18:08:29 -07002890 return work_done;
2891}
Michael Chanf4e418f2005-11-04 08:53:48 -08002892
David S. Miller6f535762007-10-11 18:08:29 -07002893static int bnx2_poll(struct napi_struct *napi, int budget)
2894{
Michael Chan35efa7c2007-12-20 19:56:37 -08002895 struct bnx2_napi *bnapi = container_of(napi, struct bnx2_napi, napi);
2896 struct bnx2 *bp = bnapi->bp;
David S. Miller6f535762007-10-11 18:08:29 -07002897 int work_done = 0;
Michael Chan35efa7c2007-12-20 19:56:37 -08002898 struct status_block *sblk = bnapi->status_blk;
David S. Miller6f535762007-10-11 18:08:29 -07002899
2900 while (1) {
Michael Chan35efa7c2007-12-20 19:56:37 -08002901 work_done = bnx2_poll_work(bp, bnapi, work_done, budget);
David S. Miller6f535762007-10-11 18:08:29 -07002902
2903 if (unlikely(work_done >= budget))
2904 break;
2905
Michael Chan35efa7c2007-12-20 19:56:37 -08002906 /* bnapi->last_status_idx is used below to tell the hw how
Michael Chan6dee6422007-10-12 01:40:38 -07002907 * much work has been processed, so we must read it before
2908 * checking for more work.
2909 */
Michael Chan35efa7c2007-12-20 19:56:37 -08002910 bnapi->last_status_idx = sblk->status_idx;
Michael Chan6dee6422007-10-12 01:40:38 -07002911 rmb();
Michael Chan35efa7c2007-12-20 19:56:37 -08002912 if (likely(!bnx2_has_work(bnapi))) {
David S. Miller6f535762007-10-11 18:08:29 -07002913 netif_rx_complete(bp->dev, napi);
2914 if (likely(bp->flags & USING_MSI_FLAG)) {
2915 REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
2916 BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
Michael Chan35efa7c2007-12-20 19:56:37 -08002917 bnapi->last_status_idx);
Michael Chan6dee6422007-10-12 01:40:38 -07002918 break;
David S. Miller6f535762007-10-11 18:08:29 -07002919 }
2920 REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
2921 BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
2922 BNX2_PCICFG_INT_ACK_CMD_MASK_INT |
Michael Chan35efa7c2007-12-20 19:56:37 -08002923 bnapi->last_status_idx);
David S. Miller6f535762007-10-11 18:08:29 -07002924
Michael Chan1269a8a2006-01-23 16:11:03 -08002925 REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
2926 BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
Michael Chan35efa7c2007-12-20 19:56:37 -08002927 bnapi->last_status_idx);
David S. Miller6f535762007-10-11 18:08:29 -07002928 break;
Michael Chan1269a8a2006-01-23 16:11:03 -08002929 }
Michael Chanb6016b72005-05-26 13:03:09 -07002930 }
2931
Stephen Hemmingerbea33482007-10-03 16:41:36 -07002932 return work_done;
Michael Chanb6016b72005-05-26 13:03:09 -07002933}
2934
Herbert Xu932ff272006-06-09 12:20:56 -07002935/* Called with rtnl_lock from vlan functions and also netif_tx_lock
Michael Chanb6016b72005-05-26 13:03:09 -07002936 * from set_multicast.
2937 */
2938static void
2939bnx2_set_rx_mode(struct net_device *dev)
2940{
Michael Chan972ec0d2006-01-23 16:12:43 -08002941 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07002942 u32 rx_mode, sort_mode;
2943 int i;
Michael Chanb6016b72005-05-26 13:03:09 -07002944
Michael Chanc770a652005-08-25 15:38:39 -07002945 spin_lock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07002946
2947 rx_mode = bp->rx_mode & ~(BNX2_EMAC_RX_MODE_PROMISCUOUS |
2948 BNX2_EMAC_RX_MODE_KEEP_VLAN_TAG);
2949 sort_mode = 1 | BNX2_RPM_SORT_USER0_BC_EN;
2950#ifdef BCM_VLAN
Michael Chane29054f2006-01-23 16:06:06 -08002951 if (!bp->vlgrp && !(bp->flags & ASF_ENABLE_FLAG))
Michael Chanb6016b72005-05-26 13:03:09 -07002952 rx_mode |= BNX2_EMAC_RX_MODE_KEEP_VLAN_TAG;
Michael Chanb6016b72005-05-26 13:03:09 -07002953#else
Michael Chane29054f2006-01-23 16:06:06 -08002954 if (!(bp->flags & ASF_ENABLE_FLAG))
2955 rx_mode |= BNX2_EMAC_RX_MODE_KEEP_VLAN_TAG;
Michael Chanb6016b72005-05-26 13:03:09 -07002956#endif
2957 if (dev->flags & IFF_PROMISC) {
2958 /* Promiscuous mode. */
2959 rx_mode |= BNX2_EMAC_RX_MODE_PROMISCUOUS;
Michael Chan75108732006-11-19 14:06:40 -08002960 sort_mode |= BNX2_RPM_SORT_USER0_PROM_EN |
2961 BNX2_RPM_SORT_USER0_PROM_VLAN;
Michael Chanb6016b72005-05-26 13:03:09 -07002962 }
2963 else if (dev->flags & IFF_ALLMULTI) {
2964 for (i = 0; i < NUM_MC_HASH_REGISTERS; i++) {
2965 REG_WR(bp, BNX2_EMAC_MULTICAST_HASH0 + (i * 4),
2966 0xffffffff);
2967 }
2968 sort_mode |= BNX2_RPM_SORT_USER0_MC_EN;
2969 }
2970 else {
2971 /* Accept one or more multicast(s). */
2972 struct dev_mc_list *mclist;
2973 u32 mc_filter[NUM_MC_HASH_REGISTERS];
2974 u32 regidx;
2975 u32 bit;
2976 u32 crc;
2977
2978 memset(mc_filter, 0, 4 * NUM_MC_HASH_REGISTERS);
2979
2980 for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
2981 i++, mclist = mclist->next) {
2982
2983 crc = ether_crc_le(ETH_ALEN, mclist->dmi_addr);
2984 bit = crc & 0xff;
2985 regidx = (bit & 0xe0) >> 5;
2986 bit &= 0x1f;
2987 mc_filter[regidx] |= (1 << bit);
2988 }
2989
2990 for (i = 0; i < NUM_MC_HASH_REGISTERS; i++) {
2991 REG_WR(bp, BNX2_EMAC_MULTICAST_HASH0 + (i * 4),
2992 mc_filter[i]);
2993 }
2994
2995 sort_mode |= BNX2_RPM_SORT_USER0_MC_HSH_EN;
2996 }
2997
2998 if (rx_mode != bp->rx_mode) {
2999 bp->rx_mode = rx_mode;
3000 REG_WR(bp, BNX2_EMAC_RX_MODE, rx_mode);
3001 }
3002
3003 REG_WR(bp, BNX2_RPM_SORT_USER0, 0x0);
3004 REG_WR(bp, BNX2_RPM_SORT_USER0, sort_mode);
3005 REG_WR(bp, BNX2_RPM_SORT_USER0, sort_mode | BNX2_RPM_SORT_USER0_ENA);
3006
Michael Chanc770a652005-08-25 15:38:39 -07003007 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07003008}
3009
3010static void
3011load_rv2p_fw(struct bnx2 *bp, u32 *rv2p_code, u32 rv2p_code_len,
3012 u32 rv2p_proc)
3013{
3014 int i;
3015 u32 val;
3016
3017
3018 for (i = 0; i < rv2p_code_len; i += 8) {
Michael Chanfba9fe92006-06-12 22:21:25 -07003019 REG_WR(bp, BNX2_RV2P_INSTR_HIGH, cpu_to_le32(*rv2p_code));
Michael Chanb6016b72005-05-26 13:03:09 -07003020 rv2p_code++;
Michael Chanfba9fe92006-06-12 22:21:25 -07003021 REG_WR(bp, BNX2_RV2P_INSTR_LOW, cpu_to_le32(*rv2p_code));
Michael Chanb6016b72005-05-26 13:03:09 -07003022 rv2p_code++;
3023
3024 if (rv2p_proc == RV2P_PROC1) {
3025 val = (i / 8) | BNX2_RV2P_PROC1_ADDR_CMD_RDWR;
3026 REG_WR(bp, BNX2_RV2P_PROC1_ADDR_CMD, val);
3027 }
3028 else {
3029 val = (i / 8) | BNX2_RV2P_PROC2_ADDR_CMD_RDWR;
3030 REG_WR(bp, BNX2_RV2P_PROC2_ADDR_CMD, val);
3031 }
3032 }
3033
3034 /* Reset the processor, un-stall is done later. */
3035 if (rv2p_proc == RV2P_PROC1) {
3036 REG_WR(bp, BNX2_RV2P_COMMAND, BNX2_RV2P_COMMAND_PROC1_RESET);
3037 }
3038 else {
3039 REG_WR(bp, BNX2_RV2P_COMMAND, BNX2_RV2P_COMMAND_PROC2_RESET);
3040 }
3041}
3042
Michael Chanaf3ee512006-11-19 14:09:25 -08003043static int
Michael Chanb6016b72005-05-26 13:03:09 -07003044load_cpu_fw(struct bnx2 *bp, struct cpu_reg *cpu_reg, struct fw_info *fw)
3045{
3046 u32 offset;
3047 u32 val;
Michael Chanaf3ee512006-11-19 14:09:25 -08003048 int rc;
Michael Chanb6016b72005-05-26 13:03:09 -07003049
3050 /* Halt the CPU. */
3051 val = REG_RD_IND(bp, cpu_reg->mode);
3052 val |= cpu_reg->mode_value_halt;
3053 REG_WR_IND(bp, cpu_reg->mode, val);
3054 REG_WR_IND(bp, cpu_reg->state, cpu_reg->state_value_clear);
3055
3056 /* Load the Text area. */
3057 offset = cpu_reg->spad_base + (fw->text_addr - cpu_reg->mips_view_base);
Michael Chanaf3ee512006-11-19 14:09:25 -08003058 if (fw->gz_text) {
Michael Chanb6016b72005-05-26 13:03:09 -07003059 int j;
3060
Michael Chanea1f8d52007-10-02 16:27:35 -07003061 rc = zlib_inflate_blob(fw->text, FW_BUF_SIZE, fw->gz_text,
3062 fw->gz_text_len);
3063 if (rc < 0)
Denys Vlasenkob3448b02007-09-30 17:55:51 -07003064 return rc;
Michael Chanea1f8d52007-10-02 16:27:35 -07003065
Michael Chanb6016b72005-05-26 13:03:09 -07003066 for (j = 0; j < (fw->text_len / 4); j++, offset += 4) {
Michael Chanea1f8d52007-10-02 16:27:35 -07003067 REG_WR_IND(bp, offset, cpu_to_le32(fw->text[j]));
Michael Chanb6016b72005-05-26 13:03:09 -07003068 }
3069 }
3070
3071 /* Load the Data area. */
3072 offset = cpu_reg->spad_base + (fw->data_addr - cpu_reg->mips_view_base);
3073 if (fw->data) {
3074 int j;
3075
3076 for (j = 0; j < (fw->data_len / 4); j++, offset += 4) {
3077 REG_WR_IND(bp, offset, fw->data[j]);
3078 }
3079 }
3080
3081 /* Load the SBSS area. */
3082 offset = cpu_reg->spad_base + (fw->sbss_addr - cpu_reg->mips_view_base);
Michael Chanea1f8d52007-10-02 16:27:35 -07003083 if (fw->sbss_len) {
Michael Chanb6016b72005-05-26 13:03:09 -07003084 int j;
3085
3086 for (j = 0; j < (fw->sbss_len / 4); j++, offset += 4) {
Michael Chanea1f8d52007-10-02 16:27:35 -07003087 REG_WR_IND(bp, offset, 0);
Michael Chanb6016b72005-05-26 13:03:09 -07003088 }
3089 }
3090
3091 /* Load the BSS area. */
3092 offset = cpu_reg->spad_base + (fw->bss_addr - cpu_reg->mips_view_base);
Michael Chanea1f8d52007-10-02 16:27:35 -07003093 if (fw->bss_len) {
Michael Chanb6016b72005-05-26 13:03:09 -07003094 int j;
3095
3096 for (j = 0; j < (fw->bss_len/4); j++, offset += 4) {
Michael Chanea1f8d52007-10-02 16:27:35 -07003097 REG_WR_IND(bp, offset, 0);
Michael Chanb6016b72005-05-26 13:03:09 -07003098 }
3099 }
3100
3101 /* Load the Read-Only area. */
3102 offset = cpu_reg->spad_base +
3103 (fw->rodata_addr - cpu_reg->mips_view_base);
3104 if (fw->rodata) {
3105 int j;
3106
3107 for (j = 0; j < (fw->rodata_len / 4); j++, offset += 4) {
3108 REG_WR_IND(bp, offset, fw->rodata[j]);
3109 }
3110 }
3111
3112 /* Clear the pre-fetch instruction. */
3113 REG_WR_IND(bp, cpu_reg->inst, 0);
3114 REG_WR_IND(bp, cpu_reg->pc, fw->start_addr);
3115
3116 /* Start the CPU. */
3117 val = REG_RD_IND(bp, cpu_reg->mode);
3118 val &= ~cpu_reg->mode_value_halt;
3119 REG_WR_IND(bp, cpu_reg->state, cpu_reg->state_value_clear);
3120 REG_WR_IND(bp, cpu_reg->mode, val);
Michael Chanaf3ee512006-11-19 14:09:25 -08003121
3122 return 0;
Michael Chanb6016b72005-05-26 13:03:09 -07003123}
3124
Michael Chanfba9fe92006-06-12 22:21:25 -07003125static int
Michael Chanb6016b72005-05-26 13:03:09 -07003126bnx2_init_cpus(struct bnx2 *bp)
3127{
3128 struct cpu_reg cpu_reg;
Michael Chanaf3ee512006-11-19 14:09:25 -08003129 struct fw_info *fw;
Michael Chan110d0ef2007-12-12 11:18:34 -08003130 int rc, rv2p_len;
3131 void *text, *rv2p;
Michael Chanb6016b72005-05-26 13:03:09 -07003132
3133 /* Initialize the RV2P processor. */
Denys Vlasenkob3448b02007-09-30 17:55:51 -07003134 text = vmalloc(FW_BUF_SIZE);
3135 if (!text)
3136 return -ENOMEM;
Michael Chan110d0ef2007-12-12 11:18:34 -08003137 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
3138 rv2p = bnx2_xi_rv2p_proc1;
3139 rv2p_len = sizeof(bnx2_xi_rv2p_proc1);
3140 } else {
3141 rv2p = bnx2_rv2p_proc1;
3142 rv2p_len = sizeof(bnx2_rv2p_proc1);
3143 }
3144 rc = zlib_inflate_blob(text, FW_BUF_SIZE, rv2p, rv2p_len);
Michael Chanea1f8d52007-10-02 16:27:35 -07003145 if (rc < 0)
Michael Chanfba9fe92006-06-12 22:21:25 -07003146 goto init_cpu_err;
Michael Chanea1f8d52007-10-02 16:27:35 -07003147
Denys Vlasenkob3448b02007-09-30 17:55:51 -07003148 load_rv2p_fw(bp, text, rc /* == len */, RV2P_PROC1);
Michael Chanfba9fe92006-06-12 22:21:25 -07003149
Michael Chan110d0ef2007-12-12 11:18:34 -08003150 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
3151 rv2p = bnx2_xi_rv2p_proc2;
3152 rv2p_len = sizeof(bnx2_xi_rv2p_proc2);
3153 } else {
3154 rv2p = bnx2_rv2p_proc2;
3155 rv2p_len = sizeof(bnx2_rv2p_proc2);
3156 }
3157 rc = zlib_inflate_blob(text, FW_BUF_SIZE, rv2p, rv2p_len);
Michael Chanea1f8d52007-10-02 16:27:35 -07003158 if (rc < 0)
Michael Chanfba9fe92006-06-12 22:21:25 -07003159 goto init_cpu_err;
Michael Chanea1f8d52007-10-02 16:27:35 -07003160
Denys Vlasenkob3448b02007-09-30 17:55:51 -07003161 load_rv2p_fw(bp, text, rc /* == len */, RV2P_PROC2);
Michael Chanb6016b72005-05-26 13:03:09 -07003162
3163 /* Initialize the RX Processor. */
3164 cpu_reg.mode = BNX2_RXP_CPU_MODE;
3165 cpu_reg.mode_value_halt = BNX2_RXP_CPU_MODE_SOFT_HALT;
3166 cpu_reg.mode_value_sstep = BNX2_RXP_CPU_MODE_STEP_ENA;
3167 cpu_reg.state = BNX2_RXP_CPU_STATE;
3168 cpu_reg.state_value_clear = 0xffffff;
3169 cpu_reg.gpr0 = BNX2_RXP_CPU_REG_FILE;
3170 cpu_reg.evmask = BNX2_RXP_CPU_EVENT_MASK;
3171 cpu_reg.pc = BNX2_RXP_CPU_PROGRAM_COUNTER;
3172 cpu_reg.inst = BNX2_RXP_CPU_INSTRUCTION;
3173 cpu_reg.bp = BNX2_RXP_CPU_HW_BREAKPOINT;
3174 cpu_reg.spad_base = BNX2_RXP_SCRATCH;
3175 cpu_reg.mips_view_base = 0x8000000;
Jeff Garzik6aa20a22006-09-13 13:24:59 -04003176
Michael Chand43584c2006-11-19 14:14:35 -08003177 if (CHIP_NUM(bp) == CHIP_NUM_5709)
3178 fw = &bnx2_rxp_fw_09;
3179 else
3180 fw = &bnx2_rxp_fw_06;
Michael Chanb6016b72005-05-26 13:03:09 -07003181
Michael Chanea1f8d52007-10-02 16:27:35 -07003182 fw->text = text;
Michael Chanaf3ee512006-11-19 14:09:25 -08003183 rc = load_cpu_fw(bp, &cpu_reg, fw);
Michael Chanfba9fe92006-06-12 22:21:25 -07003184 if (rc)
3185 goto init_cpu_err;
3186
Michael Chanb6016b72005-05-26 13:03:09 -07003187 /* Initialize the TX Processor. */
3188 cpu_reg.mode = BNX2_TXP_CPU_MODE;
3189 cpu_reg.mode_value_halt = BNX2_TXP_CPU_MODE_SOFT_HALT;
3190 cpu_reg.mode_value_sstep = BNX2_TXP_CPU_MODE_STEP_ENA;
3191 cpu_reg.state = BNX2_TXP_CPU_STATE;
3192 cpu_reg.state_value_clear = 0xffffff;
3193 cpu_reg.gpr0 = BNX2_TXP_CPU_REG_FILE;
3194 cpu_reg.evmask = BNX2_TXP_CPU_EVENT_MASK;
3195 cpu_reg.pc = BNX2_TXP_CPU_PROGRAM_COUNTER;
3196 cpu_reg.inst = BNX2_TXP_CPU_INSTRUCTION;
3197 cpu_reg.bp = BNX2_TXP_CPU_HW_BREAKPOINT;
3198 cpu_reg.spad_base = BNX2_TXP_SCRATCH;
3199 cpu_reg.mips_view_base = 0x8000000;
Jeff Garzik6aa20a22006-09-13 13:24:59 -04003200
Michael Chand43584c2006-11-19 14:14:35 -08003201 if (CHIP_NUM(bp) == CHIP_NUM_5709)
3202 fw = &bnx2_txp_fw_09;
3203 else
3204 fw = &bnx2_txp_fw_06;
Michael Chanb6016b72005-05-26 13:03:09 -07003205
Michael Chanea1f8d52007-10-02 16:27:35 -07003206 fw->text = text;
Michael Chanaf3ee512006-11-19 14:09:25 -08003207 rc = load_cpu_fw(bp, &cpu_reg, fw);
Michael Chanfba9fe92006-06-12 22:21:25 -07003208 if (rc)
3209 goto init_cpu_err;
3210
Michael Chanb6016b72005-05-26 13:03:09 -07003211 /* Initialize the TX Patch-up Processor. */
3212 cpu_reg.mode = BNX2_TPAT_CPU_MODE;
3213 cpu_reg.mode_value_halt = BNX2_TPAT_CPU_MODE_SOFT_HALT;
3214 cpu_reg.mode_value_sstep = BNX2_TPAT_CPU_MODE_STEP_ENA;
3215 cpu_reg.state = BNX2_TPAT_CPU_STATE;
3216 cpu_reg.state_value_clear = 0xffffff;
3217 cpu_reg.gpr0 = BNX2_TPAT_CPU_REG_FILE;
3218 cpu_reg.evmask = BNX2_TPAT_CPU_EVENT_MASK;
3219 cpu_reg.pc = BNX2_TPAT_CPU_PROGRAM_COUNTER;
3220 cpu_reg.inst = BNX2_TPAT_CPU_INSTRUCTION;
3221 cpu_reg.bp = BNX2_TPAT_CPU_HW_BREAKPOINT;
3222 cpu_reg.spad_base = BNX2_TPAT_SCRATCH;
3223 cpu_reg.mips_view_base = 0x8000000;
Jeff Garzik6aa20a22006-09-13 13:24:59 -04003224
Michael Chand43584c2006-11-19 14:14:35 -08003225 if (CHIP_NUM(bp) == CHIP_NUM_5709)
3226 fw = &bnx2_tpat_fw_09;
3227 else
3228 fw = &bnx2_tpat_fw_06;
Michael Chanb6016b72005-05-26 13:03:09 -07003229
Michael Chanea1f8d52007-10-02 16:27:35 -07003230 fw->text = text;
Michael Chanaf3ee512006-11-19 14:09:25 -08003231 rc = load_cpu_fw(bp, &cpu_reg, fw);
Michael Chanfba9fe92006-06-12 22:21:25 -07003232 if (rc)
3233 goto init_cpu_err;
3234
Michael Chanb6016b72005-05-26 13:03:09 -07003235 /* Initialize the Completion Processor. */
3236 cpu_reg.mode = BNX2_COM_CPU_MODE;
3237 cpu_reg.mode_value_halt = BNX2_COM_CPU_MODE_SOFT_HALT;
3238 cpu_reg.mode_value_sstep = BNX2_COM_CPU_MODE_STEP_ENA;
3239 cpu_reg.state = BNX2_COM_CPU_STATE;
3240 cpu_reg.state_value_clear = 0xffffff;
3241 cpu_reg.gpr0 = BNX2_COM_CPU_REG_FILE;
3242 cpu_reg.evmask = BNX2_COM_CPU_EVENT_MASK;
3243 cpu_reg.pc = BNX2_COM_CPU_PROGRAM_COUNTER;
3244 cpu_reg.inst = BNX2_COM_CPU_INSTRUCTION;
3245 cpu_reg.bp = BNX2_COM_CPU_HW_BREAKPOINT;
3246 cpu_reg.spad_base = BNX2_COM_SCRATCH;
3247 cpu_reg.mips_view_base = 0x8000000;
Jeff Garzik6aa20a22006-09-13 13:24:59 -04003248
Michael Chand43584c2006-11-19 14:14:35 -08003249 if (CHIP_NUM(bp) == CHIP_NUM_5709)
3250 fw = &bnx2_com_fw_09;
3251 else
3252 fw = &bnx2_com_fw_06;
Michael Chanb6016b72005-05-26 13:03:09 -07003253
Michael Chanea1f8d52007-10-02 16:27:35 -07003254 fw->text = text;
Michael Chanaf3ee512006-11-19 14:09:25 -08003255 rc = load_cpu_fw(bp, &cpu_reg, fw);
Michael Chanfba9fe92006-06-12 22:21:25 -07003256 if (rc)
3257 goto init_cpu_err;
3258
Michael Chand43584c2006-11-19 14:14:35 -08003259 /* Initialize the Command Processor. */
3260 cpu_reg.mode = BNX2_CP_CPU_MODE;
3261 cpu_reg.mode_value_halt = BNX2_CP_CPU_MODE_SOFT_HALT;
3262 cpu_reg.mode_value_sstep = BNX2_CP_CPU_MODE_STEP_ENA;
3263 cpu_reg.state = BNX2_CP_CPU_STATE;
3264 cpu_reg.state_value_clear = 0xffffff;
3265 cpu_reg.gpr0 = BNX2_CP_CPU_REG_FILE;
3266 cpu_reg.evmask = BNX2_CP_CPU_EVENT_MASK;
3267 cpu_reg.pc = BNX2_CP_CPU_PROGRAM_COUNTER;
3268 cpu_reg.inst = BNX2_CP_CPU_INSTRUCTION;
3269 cpu_reg.bp = BNX2_CP_CPU_HW_BREAKPOINT;
3270 cpu_reg.spad_base = BNX2_CP_SCRATCH;
3271 cpu_reg.mips_view_base = 0x8000000;
Michael Chanb6016b72005-05-26 13:03:09 -07003272
Michael Chan110d0ef2007-12-12 11:18:34 -08003273 if (CHIP_NUM(bp) == CHIP_NUM_5709)
Michael Chand43584c2006-11-19 14:14:35 -08003274 fw = &bnx2_cp_fw_09;
Michael Chan110d0ef2007-12-12 11:18:34 -08003275 else
3276 fw = &bnx2_cp_fw_06;
Michael Chanb6016b72005-05-26 13:03:09 -07003277
Michael Chan110d0ef2007-12-12 11:18:34 -08003278 fw->text = text;
3279 rc = load_cpu_fw(bp, &cpu_reg, fw);
3280
Michael Chanfba9fe92006-06-12 22:21:25 -07003281init_cpu_err:
Michael Chanea1f8d52007-10-02 16:27:35 -07003282 vfree(text);
Michael Chanfba9fe92006-06-12 22:21:25 -07003283 return rc;
Michael Chanb6016b72005-05-26 13:03:09 -07003284}
3285
3286static int
Pavel Machek829ca9a2005-09-03 15:56:56 -07003287bnx2_set_power_state(struct bnx2 *bp, pci_power_t state)
Michael Chanb6016b72005-05-26 13:03:09 -07003288{
3289 u16 pmcsr;
3290
3291 pci_read_config_word(bp->pdev, bp->pm_cap + PCI_PM_CTRL, &pmcsr);
3292
3293 switch (state) {
Pavel Machek829ca9a2005-09-03 15:56:56 -07003294 case PCI_D0: {
Michael Chanb6016b72005-05-26 13:03:09 -07003295 u32 val;
3296
3297 pci_write_config_word(bp->pdev, bp->pm_cap + PCI_PM_CTRL,
3298 (pmcsr & ~PCI_PM_CTRL_STATE_MASK) |
3299 PCI_PM_CTRL_PME_STATUS);
3300
3301 if (pmcsr & PCI_PM_CTRL_STATE_MASK)
3302 /* delay required during transition out of D3hot */
3303 msleep(20);
3304
3305 val = REG_RD(bp, BNX2_EMAC_MODE);
3306 val |= BNX2_EMAC_MODE_MPKT_RCVD | BNX2_EMAC_MODE_ACPI_RCVD;
3307 val &= ~BNX2_EMAC_MODE_MPKT;
3308 REG_WR(bp, BNX2_EMAC_MODE, val);
3309
3310 val = REG_RD(bp, BNX2_RPM_CONFIG);
3311 val &= ~BNX2_RPM_CONFIG_ACPI_ENA;
3312 REG_WR(bp, BNX2_RPM_CONFIG, val);
3313 break;
3314 }
Pavel Machek829ca9a2005-09-03 15:56:56 -07003315 case PCI_D3hot: {
Michael Chanb6016b72005-05-26 13:03:09 -07003316 int i;
3317 u32 val, wol_msg;
3318
3319 if (bp->wol) {
3320 u32 advertising;
3321 u8 autoneg;
3322
3323 autoneg = bp->autoneg;
3324 advertising = bp->advertising;
3325
Michael Chan239cd342007-10-17 19:26:15 -07003326 if (bp->phy_port == PORT_TP) {
3327 bp->autoneg = AUTONEG_SPEED;
3328 bp->advertising = ADVERTISED_10baseT_Half |
3329 ADVERTISED_10baseT_Full |
3330 ADVERTISED_100baseT_Half |
3331 ADVERTISED_100baseT_Full |
3332 ADVERTISED_Autoneg;
3333 }
Michael Chanb6016b72005-05-26 13:03:09 -07003334
Michael Chan239cd342007-10-17 19:26:15 -07003335 spin_lock_bh(&bp->phy_lock);
3336 bnx2_setup_phy(bp, bp->phy_port);
3337 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07003338
3339 bp->autoneg = autoneg;
3340 bp->advertising = advertising;
3341
3342 bnx2_set_mac_addr(bp);
3343
3344 val = REG_RD(bp, BNX2_EMAC_MODE);
3345
3346 /* Enable port mode. */
3347 val &= ~BNX2_EMAC_MODE_PORT;
Michael Chan239cd342007-10-17 19:26:15 -07003348 val |= BNX2_EMAC_MODE_MPKT_RCVD |
Michael Chanb6016b72005-05-26 13:03:09 -07003349 BNX2_EMAC_MODE_ACPI_RCVD |
Michael Chanb6016b72005-05-26 13:03:09 -07003350 BNX2_EMAC_MODE_MPKT;
Michael Chan239cd342007-10-17 19:26:15 -07003351 if (bp->phy_port == PORT_TP)
3352 val |= BNX2_EMAC_MODE_PORT_MII;
3353 else {
3354 val |= BNX2_EMAC_MODE_PORT_GMII;
3355 if (bp->line_speed == SPEED_2500)
3356 val |= BNX2_EMAC_MODE_25G_MODE;
3357 }
Michael Chanb6016b72005-05-26 13:03:09 -07003358
3359 REG_WR(bp, BNX2_EMAC_MODE, val);
3360
3361 /* receive all multicast */
3362 for (i = 0; i < NUM_MC_HASH_REGISTERS; i++) {
3363 REG_WR(bp, BNX2_EMAC_MULTICAST_HASH0 + (i * 4),
3364 0xffffffff);
3365 }
3366 REG_WR(bp, BNX2_EMAC_RX_MODE,
3367 BNX2_EMAC_RX_MODE_SORT_MODE);
3368
3369 val = 1 | BNX2_RPM_SORT_USER0_BC_EN |
3370 BNX2_RPM_SORT_USER0_MC_EN;
3371 REG_WR(bp, BNX2_RPM_SORT_USER0, 0x0);
3372 REG_WR(bp, BNX2_RPM_SORT_USER0, val);
3373 REG_WR(bp, BNX2_RPM_SORT_USER0, val |
3374 BNX2_RPM_SORT_USER0_ENA);
3375
3376 /* Need to enable EMAC and RPM for WOL. */
3377 REG_WR(bp, BNX2_MISC_ENABLE_SET_BITS,
3378 BNX2_MISC_ENABLE_SET_BITS_RX_PARSER_MAC_ENABLE |
3379 BNX2_MISC_ENABLE_SET_BITS_TX_HEADER_Q_ENABLE |
3380 BNX2_MISC_ENABLE_SET_BITS_EMAC_ENABLE);
3381
3382 val = REG_RD(bp, BNX2_RPM_CONFIG);
3383 val &= ~BNX2_RPM_CONFIG_ACPI_ENA;
3384 REG_WR(bp, BNX2_RPM_CONFIG, val);
3385
3386 wol_msg = BNX2_DRV_MSG_CODE_SUSPEND_WOL;
3387 }
3388 else {
3389 wol_msg = BNX2_DRV_MSG_CODE_SUSPEND_NO_WOL;
3390 }
3391
Michael Chandda1e392006-01-23 16:08:14 -08003392 if (!(bp->flags & NO_WOL_FLAG))
3393 bnx2_fw_sync(bp, BNX2_DRV_MSG_DATA_WAIT3 | wol_msg, 0);
Michael Chanb6016b72005-05-26 13:03:09 -07003394
3395 pmcsr &= ~PCI_PM_CTRL_STATE_MASK;
3396 if ((CHIP_ID(bp) == CHIP_ID_5706_A0) ||
3397 (CHIP_ID(bp) == CHIP_ID_5706_A1)) {
3398
3399 if (bp->wol)
3400 pmcsr |= 3;
3401 }
3402 else {
3403 pmcsr |= 3;
3404 }
3405 if (bp->wol) {
3406 pmcsr |= PCI_PM_CTRL_PME_ENABLE;
3407 }
3408 pci_write_config_word(bp->pdev, bp->pm_cap + PCI_PM_CTRL,
3409 pmcsr);
3410
3411 /* No more memory access after this point until
3412 * device is brought back to D0.
3413 */
3414 udelay(50);
3415 break;
3416 }
3417 default:
3418 return -EINVAL;
3419 }
3420 return 0;
3421}
3422
3423static int
3424bnx2_acquire_nvram_lock(struct bnx2 *bp)
3425{
3426 u32 val;
3427 int j;
3428
3429 /* Request access to the flash interface. */
3430 REG_WR(bp, BNX2_NVM_SW_ARB, BNX2_NVM_SW_ARB_ARB_REQ_SET2);
3431 for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) {
3432 val = REG_RD(bp, BNX2_NVM_SW_ARB);
3433 if (val & BNX2_NVM_SW_ARB_ARB_ARB2)
3434 break;
3435
3436 udelay(5);
3437 }
3438
3439 if (j >= NVRAM_TIMEOUT_COUNT)
3440 return -EBUSY;
3441
3442 return 0;
3443}
3444
3445static int
3446bnx2_release_nvram_lock(struct bnx2 *bp)
3447{
3448 int j;
3449 u32 val;
3450
3451 /* Relinquish nvram interface. */
3452 REG_WR(bp, BNX2_NVM_SW_ARB, BNX2_NVM_SW_ARB_ARB_REQ_CLR2);
3453
3454 for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) {
3455 val = REG_RD(bp, BNX2_NVM_SW_ARB);
3456 if (!(val & BNX2_NVM_SW_ARB_ARB_ARB2))
3457 break;
3458
3459 udelay(5);
3460 }
3461
3462 if (j >= NVRAM_TIMEOUT_COUNT)
3463 return -EBUSY;
3464
3465 return 0;
3466}
3467
3468
3469static int
3470bnx2_enable_nvram_write(struct bnx2 *bp)
3471{
3472 u32 val;
3473
3474 val = REG_RD(bp, BNX2_MISC_CFG);
3475 REG_WR(bp, BNX2_MISC_CFG, val | BNX2_MISC_CFG_NVM_WR_EN_PCI);
3476
Michael Chane30372c2007-07-16 18:26:23 -07003477 if (bp->flash_info->flags & BNX2_NV_WREN) {
Michael Chanb6016b72005-05-26 13:03:09 -07003478 int j;
3479
3480 REG_WR(bp, BNX2_NVM_COMMAND, BNX2_NVM_COMMAND_DONE);
3481 REG_WR(bp, BNX2_NVM_COMMAND,
3482 BNX2_NVM_COMMAND_WREN | BNX2_NVM_COMMAND_DOIT);
3483
3484 for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) {
3485 udelay(5);
3486
3487 val = REG_RD(bp, BNX2_NVM_COMMAND);
3488 if (val & BNX2_NVM_COMMAND_DONE)
3489 break;
3490 }
3491
3492 if (j >= NVRAM_TIMEOUT_COUNT)
3493 return -EBUSY;
3494 }
3495 return 0;
3496}
3497
3498static void
3499bnx2_disable_nvram_write(struct bnx2 *bp)
3500{
3501 u32 val;
3502
3503 val = REG_RD(bp, BNX2_MISC_CFG);
3504 REG_WR(bp, BNX2_MISC_CFG, val & ~BNX2_MISC_CFG_NVM_WR_EN);
3505}
3506
3507
3508static void
3509bnx2_enable_nvram_access(struct bnx2 *bp)
3510{
3511 u32 val;
3512
3513 val = REG_RD(bp, BNX2_NVM_ACCESS_ENABLE);
3514 /* Enable both bits, even on read. */
Jeff Garzik6aa20a22006-09-13 13:24:59 -04003515 REG_WR(bp, BNX2_NVM_ACCESS_ENABLE,
Michael Chanb6016b72005-05-26 13:03:09 -07003516 val | BNX2_NVM_ACCESS_ENABLE_EN | BNX2_NVM_ACCESS_ENABLE_WR_EN);
3517}
3518
3519static void
3520bnx2_disable_nvram_access(struct bnx2 *bp)
3521{
3522 u32 val;
3523
3524 val = REG_RD(bp, BNX2_NVM_ACCESS_ENABLE);
3525 /* Disable both bits, even after read. */
Jeff Garzik6aa20a22006-09-13 13:24:59 -04003526 REG_WR(bp, BNX2_NVM_ACCESS_ENABLE,
Michael Chanb6016b72005-05-26 13:03:09 -07003527 val & ~(BNX2_NVM_ACCESS_ENABLE_EN |
3528 BNX2_NVM_ACCESS_ENABLE_WR_EN));
3529}
3530
3531static int
3532bnx2_nvram_erase_page(struct bnx2 *bp, u32 offset)
3533{
3534 u32 cmd;
3535 int j;
3536
Michael Chane30372c2007-07-16 18:26:23 -07003537 if (bp->flash_info->flags & BNX2_NV_BUFFERED)
Michael Chanb6016b72005-05-26 13:03:09 -07003538 /* Buffered flash, no erase needed */
3539 return 0;
3540
3541 /* Build an erase command */
3542 cmd = BNX2_NVM_COMMAND_ERASE | BNX2_NVM_COMMAND_WR |
3543 BNX2_NVM_COMMAND_DOIT;
3544
3545 /* Need to clear DONE bit separately. */
3546 REG_WR(bp, BNX2_NVM_COMMAND, BNX2_NVM_COMMAND_DONE);
3547
3548 /* Address of the NVRAM to read from. */
3549 REG_WR(bp, BNX2_NVM_ADDR, offset & BNX2_NVM_ADDR_NVM_ADDR_VALUE);
3550
3551 /* Issue an erase command. */
3552 REG_WR(bp, BNX2_NVM_COMMAND, cmd);
3553
3554 /* Wait for completion. */
3555 for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) {
3556 u32 val;
3557
3558 udelay(5);
3559
3560 val = REG_RD(bp, BNX2_NVM_COMMAND);
3561 if (val & BNX2_NVM_COMMAND_DONE)
3562 break;
3563 }
3564
3565 if (j >= NVRAM_TIMEOUT_COUNT)
3566 return -EBUSY;
3567
3568 return 0;
3569}
3570
3571static int
3572bnx2_nvram_read_dword(struct bnx2 *bp, u32 offset, u8 *ret_val, u32 cmd_flags)
3573{
3574 u32 cmd;
3575 int j;
3576
3577 /* Build the command word. */
3578 cmd = BNX2_NVM_COMMAND_DOIT | cmd_flags;
3579
Michael Chane30372c2007-07-16 18:26:23 -07003580 /* Calculate an offset of a buffered flash, not needed for 5709. */
3581 if (bp->flash_info->flags & BNX2_NV_TRANSLATE) {
Michael Chanb6016b72005-05-26 13:03:09 -07003582 offset = ((offset / bp->flash_info->page_size) <<
3583 bp->flash_info->page_bits) +
3584 (offset % bp->flash_info->page_size);
3585 }
3586
3587 /* Need to clear DONE bit separately. */
3588 REG_WR(bp, BNX2_NVM_COMMAND, BNX2_NVM_COMMAND_DONE);
3589
3590 /* Address of the NVRAM to read from. */
3591 REG_WR(bp, BNX2_NVM_ADDR, offset & BNX2_NVM_ADDR_NVM_ADDR_VALUE);
3592
3593 /* Issue a read command. */
3594 REG_WR(bp, BNX2_NVM_COMMAND, cmd);
3595
3596 /* Wait for completion. */
3597 for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) {
3598 u32 val;
3599
3600 udelay(5);
3601
3602 val = REG_RD(bp, BNX2_NVM_COMMAND);
3603 if (val & BNX2_NVM_COMMAND_DONE) {
3604 val = REG_RD(bp, BNX2_NVM_READ);
3605
3606 val = be32_to_cpu(val);
3607 memcpy(ret_val, &val, 4);
3608 break;
3609 }
3610 }
3611 if (j >= NVRAM_TIMEOUT_COUNT)
3612 return -EBUSY;
3613
3614 return 0;
3615}
3616
3617
3618static int
3619bnx2_nvram_write_dword(struct bnx2 *bp, u32 offset, u8 *val, u32 cmd_flags)
3620{
3621 u32 cmd, val32;
3622 int j;
3623
3624 /* Build the command word. */
3625 cmd = BNX2_NVM_COMMAND_DOIT | BNX2_NVM_COMMAND_WR | cmd_flags;
3626
Michael Chane30372c2007-07-16 18:26:23 -07003627 /* Calculate an offset of a buffered flash, not needed for 5709. */
3628 if (bp->flash_info->flags & BNX2_NV_TRANSLATE) {
Michael Chanb6016b72005-05-26 13:03:09 -07003629 offset = ((offset / bp->flash_info->page_size) <<
3630 bp->flash_info->page_bits) +
3631 (offset % bp->flash_info->page_size);
3632 }
3633
3634 /* Need to clear DONE bit separately. */
3635 REG_WR(bp, BNX2_NVM_COMMAND, BNX2_NVM_COMMAND_DONE);
3636
3637 memcpy(&val32, val, 4);
3638 val32 = cpu_to_be32(val32);
3639
3640 /* Write the data. */
3641 REG_WR(bp, BNX2_NVM_WRITE, val32);
3642
3643 /* Address of the NVRAM to write to. */
3644 REG_WR(bp, BNX2_NVM_ADDR, offset & BNX2_NVM_ADDR_NVM_ADDR_VALUE);
3645
3646 /* Issue the write command. */
3647 REG_WR(bp, BNX2_NVM_COMMAND, cmd);
3648
3649 /* Wait for completion. */
3650 for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) {
3651 udelay(5);
3652
3653 if (REG_RD(bp, BNX2_NVM_COMMAND) & BNX2_NVM_COMMAND_DONE)
3654 break;
3655 }
3656 if (j >= NVRAM_TIMEOUT_COUNT)
3657 return -EBUSY;
3658
3659 return 0;
3660}
3661
3662static int
3663bnx2_init_nvram(struct bnx2 *bp)
3664{
3665 u32 val;
Michael Chane30372c2007-07-16 18:26:23 -07003666 int j, entry_count, rc = 0;
Michael Chanb6016b72005-05-26 13:03:09 -07003667 struct flash_spec *flash;
3668
Michael Chane30372c2007-07-16 18:26:23 -07003669 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
3670 bp->flash_info = &flash_5709;
3671 goto get_flash_size;
3672 }
3673
Michael Chanb6016b72005-05-26 13:03:09 -07003674 /* Determine the selected interface. */
3675 val = REG_RD(bp, BNX2_NVM_CFG1);
3676
Denis Chengff8ac602007-09-02 18:30:18 +08003677 entry_count = ARRAY_SIZE(flash_table);
Michael Chanb6016b72005-05-26 13:03:09 -07003678
Michael Chanb6016b72005-05-26 13:03:09 -07003679 if (val & 0x40000000) {
3680
3681 /* Flash interface has been reconfigured */
3682 for (j = 0, flash = &flash_table[0]; j < entry_count;
Michael Chan37137702005-11-04 08:49:17 -08003683 j++, flash++) {
3684 if ((val & FLASH_BACKUP_STRAP_MASK) ==
3685 (flash->config1 & FLASH_BACKUP_STRAP_MASK)) {
Michael Chanb6016b72005-05-26 13:03:09 -07003686 bp->flash_info = flash;
3687 break;
3688 }
3689 }
3690 }
3691 else {
Michael Chan37137702005-11-04 08:49:17 -08003692 u32 mask;
Michael Chanb6016b72005-05-26 13:03:09 -07003693 /* Not yet been reconfigured */
3694
Michael Chan37137702005-11-04 08:49:17 -08003695 if (val & (1 << 23))
3696 mask = FLASH_BACKUP_STRAP_MASK;
3697 else
3698 mask = FLASH_STRAP_MASK;
3699
Michael Chanb6016b72005-05-26 13:03:09 -07003700 for (j = 0, flash = &flash_table[0]; j < entry_count;
3701 j++, flash++) {
3702
Michael Chan37137702005-11-04 08:49:17 -08003703 if ((val & mask) == (flash->strapping & mask)) {
Michael Chanb6016b72005-05-26 13:03:09 -07003704 bp->flash_info = flash;
3705
3706 /* Request access to the flash interface. */
3707 if ((rc = bnx2_acquire_nvram_lock(bp)) != 0)
3708 return rc;
3709
3710 /* Enable access to flash interface */
3711 bnx2_enable_nvram_access(bp);
3712
3713 /* Reconfigure the flash interface */
3714 REG_WR(bp, BNX2_NVM_CFG1, flash->config1);
3715 REG_WR(bp, BNX2_NVM_CFG2, flash->config2);
3716 REG_WR(bp, BNX2_NVM_CFG3, flash->config3);
3717 REG_WR(bp, BNX2_NVM_WRITE1, flash->write1);
3718
3719 /* Disable access to flash interface */
3720 bnx2_disable_nvram_access(bp);
3721 bnx2_release_nvram_lock(bp);
3722
3723 break;
3724 }
3725 }
3726 } /* if (val & 0x40000000) */
3727
3728 if (j == entry_count) {
3729 bp->flash_info = NULL;
John W. Linville2f23c522005-11-10 12:57:33 -08003730 printk(KERN_ALERT PFX "Unknown flash/EEPROM type.\n");
Michael Chan1122db72006-01-23 16:11:42 -08003731 return -ENODEV;
Michael Chanb6016b72005-05-26 13:03:09 -07003732 }
3733
Michael Chane30372c2007-07-16 18:26:23 -07003734get_flash_size:
Michael Chan1122db72006-01-23 16:11:42 -08003735 val = REG_RD_IND(bp, bp->shmem_base + BNX2_SHARED_HW_CFG_CONFIG2);
3736 val &= BNX2_SHARED_HW_CFG2_NVM_SIZE_MASK;
3737 if (val)
3738 bp->flash_size = val;
3739 else
3740 bp->flash_size = bp->flash_info->total_size;
3741
Michael Chanb6016b72005-05-26 13:03:09 -07003742 return rc;
3743}
3744
3745static int
3746bnx2_nvram_read(struct bnx2 *bp, u32 offset, u8 *ret_buf,
3747 int buf_size)
3748{
3749 int rc = 0;
3750 u32 cmd_flags, offset32, len32, extra;
3751
3752 if (buf_size == 0)
3753 return 0;
3754
3755 /* Request access to the flash interface. */
3756 if ((rc = bnx2_acquire_nvram_lock(bp)) != 0)
3757 return rc;
3758
3759 /* Enable access to flash interface */
3760 bnx2_enable_nvram_access(bp);
3761
3762 len32 = buf_size;
3763 offset32 = offset;
3764 extra = 0;
3765
3766 cmd_flags = 0;
3767
3768 if (offset32 & 3) {
3769 u8 buf[4];
3770 u32 pre_len;
3771
3772 offset32 &= ~3;
3773 pre_len = 4 - (offset & 3);
3774
3775 if (pre_len >= len32) {
3776 pre_len = len32;
3777 cmd_flags = BNX2_NVM_COMMAND_FIRST |
3778 BNX2_NVM_COMMAND_LAST;
3779 }
3780 else {
3781 cmd_flags = BNX2_NVM_COMMAND_FIRST;
3782 }
3783
3784 rc = bnx2_nvram_read_dword(bp, offset32, buf, cmd_flags);
3785
3786 if (rc)
3787 return rc;
3788
3789 memcpy(ret_buf, buf + (offset & 3), pre_len);
3790
3791 offset32 += 4;
3792 ret_buf += pre_len;
3793 len32 -= pre_len;
3794 }
3795 if (len32 & 3) {
3796 extra = 4 - (len32 & 3);
3797 len32 = (len32 + 4) & ~3;
3798 }
3799
3800 if (len32 == 4) {
3801 u8 buf[4];
3802
3803 if (cmd_flags)
3804 cmd_flags = BNX2_NVM_COMMAND_LAST;
3805 else
3806 cmd_flags = BNX2_NVM_COMMAND_FIRST |
3807 BNX2_NVM_COMMAND_LAST;
3808
3809 rc = bnx2_nvram_read_dword(bp, offset32, buf, cmd_flags);
3810
3811 memcpy(ret_buf, buf, 4 - extra);
3812 }
3813 else if (len32 > 0) {
3814 u8 buf[4];
3815
3816 /* Read the first word. */
3817 if (cmd_flags)
3818 cmd_flags = 0;
3819 else
3820 cmd_flags = BNX2_NVM_COMMAND_FIRST;
3821
3822 rc = bnx2_nvram_read_dword(bp, offset32, ret_buf, cmd_flags);
3823
3824 /* Advance to the next dword. */
3825 offset32 += 4;
3826 ret_buf += 4;
3827 len32 -= 4;
3828
3829 while (len32 > 4 && rc == 0) {
3830 rc = bnx2_nvram_read_dword(bp, offset32, ret_buf, 0);
3831
3832 /* Advance to the next dword. */
3833 offset32 += 4;
3834 ret_buf += 4;
3835 len32 -= 4;
3836 }
3837
3838 if (rc)
3839 return rc;
3840
3841 cmd_flags = BNX2_NVM_COMMAND_LAST;
3842 rc = bnx2_nvram_read_dword(bp, offset32, buf, cmd_flags);
3843
3844 memcpy(ret_buf, buf, 4 - extra);
3845 }
3846
3847 /* Disable access to flash interface */
3848 bnx2_disable_nvram_access(bp);
3849
3850 bnx2_release_nvram_lock(bp);
3851
3852 return rc;
3853}
3854
3855static int
3856bnx2_nvram_write(struct bnx2 *bp, u32 offset, u8 *data_buf,
3857 int buf_size)
3858{
3859 u32 written, offset32, len32;
Michael Chane6be7632007-01-08 19:56:13 -08003860 u8 *buf, start[4], end[4], *align_buf = NULL, *flash_buffer = NULL;
Michael Chanb6016b72005-05-26 13:03:09 -07003861 int rc = 0;
3862 int align_start, align_end;
3863
3864 buf = data_buf;
3865 offset32 = offset;
3866 len32 = buf_size;
3867 align_start = align_end = 0;
3868
3869 if ((align_start = (offset32 & 3))) {
3870 offset32 &= ~3;
Michael Chanc8738792007-03-30 14:53:06 -07003871 len32 += align_start;
3872 if (len32 < 4)
3873 len32 = 4;
Michael Chanb6016b72005-05-26 13:03:09 -07003874 if ((rc = bnx2_nvram_read(bp, offset32, start, 4)))
3875 return rc;
3876 }
3877
3878 if (len32 & 3) {
Michael Chanc8738792007-03-30 14:53:06 -07003879 align_end = 4 - (len32 & 3);
3880 len32 += align_end;
3881 if ((rc = bnx2_nvram_read(bp, offset32 + len32 - 4, end, 4)))
3882 return rc;
Michael Chanb6016b72005-05-26 13:03:09 -07003883 }
3884
3885 if (align_start || align_end) {
Michael Chane6be7632007-01-08 19:56:13 -08003886 align_buf = kmalloc(len32, GFP_KERNEL);
3887 if (align_buf == NULL)
Michael Chanb6016b72005-05-26 13:03:09 -07003888 return -ENOMEM;
3889 if (align_start) {
Michael Chane6be7632007-01-08 19:56:13 -08003890 memcpy(align_buf, start, 4);
Michael Chanb6016b72005-05-26 13:03:09 -07003891 }
3892 if (align_end) {
Michael Chane6be7632007-01-08 19:56:13 -08003893 memcpy(align_buf + len32 - 4, end, 4);
Michael Chanb6016b72005-05-26 13:03:09 -07003894 }
Michael Chane6be7632007-01-08 19:56:13 -08003895 memcpy(align_buf + align_start, data_buf, buf_size);
3896 buf = align_buf;
Michael Chanb6016b72005-05-26 13:03:09 -07003897 }
3898
Michael Chane30372c2007-07-16 18:26:23 -07003899 if (!(bp->flash_info->flags & BNX2_NV_BUFFERED)) {
Michael Chanae181bc2006-05-22 16:39:20 -07003900 flash_buffer = kmalloc(264, GFP_KERNEL);
3901 if (flash_buffer == NULL) {
3902 rc = -ENOMEM;
3903 goto nvram_write_end;
3904 }
3905 }
3906
Michael Chanb6016b72005-05-26 13:03:09 -07003907 written = 0;
3908 while ((written < len32) && (rc == 0)) {
3909 u32 page_start, page_end, data_start, data_end;
3910 u32 addr, cmd_flags;
3911 int i;
Michael Chanb6016b72005-05-26 13:03:09 -07003912
3913 /* Find the page_start addr */
3914 page_start = offset32 + written;
3915 page_start -= (page_start % bp->flash_info->page_size);
3916 /* Find the page_end addr */
3917 page_end = page_start + bp->flash_info->page_size;
3918 /* Find the data_start addr */
3919 data_start = (written == 0) ? offset32 : page_start;
3920 /* Find the data_end addr */
Jeff Garzik6aa20a22006-09-13 13:24:59 -04003921 data_end = (page_end > offset32 + len32) ?
Michael Chanb6016b72005-05-26 13:03:09 -07003922 (offset32 + len32) : page_end;
3923
3924 /* Request access to the flash interface. */
3925 if ((rc = bnx2_acquire_nvram_lock(bp)) != 0)
3926 goto nvram_write_end;
3927
3928 /* Enable access to flash interface */
3929 bnx2_enable_nvram_access(bp);
3930
3931 cmd_flags = BNX2_NVM_COMMAND_FIRST;
Michael Chane30372c2007-07-16 18:26:23 -07003932 if (!(bp->flash_info->flags & BNX2_NV_BUFFERED)) {
Michael Chanb6016b72005-05-26 13:03:09 -07003933 int j;
3934
3935 /* Read the whole page into the buffer
3936 * (non-buffer flash only) */
3937 for (j = 0; j < bp->flash_info->page_size; j += 4) {
3938 if (j == (bp->flash_info->page_size - 4)) {
3939 cmd_flags |= BNX2_NVM_COMMAND_LAST;
3940 }
3941 rc = bnx2_nvram_read_dword(bp,
Jeff Garzik6aa20a22006-09-13 13:24:59 -04003942 page_start + j,
3943 &flash_buffer[j],
Michael Chanb6016b72005-05-26 13:03:09 -07003944 cmd_flags);
3945
3946 if (rc)
3947 goto nvram_write_end;
3948
3949 cmd_flags = 0;
3950 }
3951 }
3952
3953 /* Enable writes to flash interface (unlock write-protect) */
3954 if ((rc = bnx2_enable_nvram_write(bp)) != 0)
3955 goto nvram_write_end;
3956
Michael Chanb6016b72005-05-26 13:03:09 -07003957 /* Loop to write back the buffer data from page_start to
3958 * data_start */
3959 i = 0;
Michael Chane30372c2007-07-16 18:26:23 -07003960 if (!(bp->flash_info->flags & BNX2_NV_BUFFERED)) {
Michael Chanc8738792007-03-30 14:53:06 -07003961 /* Erase the page */
3962 if ((rc = bnx2_nvram_erase_page(bp, page_start)) != 0)
3963 goto nvram_write_end;
3964
3965 /* Re-enable the write again for the actual write */
3966 bnx2_enable_nvram_write(bp);
3967
Michael Chanb6016b72005-05-26 13:03:09 -07003968 for (addr = page_start; addr < data_start;
3969 addr += 4, i += 4) {
Jeff Garzik6aa20a22006-09-13 13:24:59 -04003970
Michael Chanb6016b72005-05-26 13:03:09 -07003971 rc = bnx2_nvram_write_dword(bp, addr,
3972 &flash_buffer[i], cmd_flags);
3973
3974 if (rc != 0)
3975 goto nvram_write_end;
3976
3977 cmd_flags = 0;
3978 }
3979 }
3980
3981 /* Loop to write the new data from data_start to data_end */
Michael Chanbae25762006-05-22 16:38:38 -07003982 for (addr = data_start; addr < data_end; addr += 4, i += 4) {
Michael Chanb6016b72005-05-26 13:03:09 -07003983 if ((addr == page_end - 4) ||
Michael Chane30372c2007-07-16 18:26:23 -07003984 ((bp->flash_info->flags & BNX2_NV_BUFFERED) &&
Michael Chanb6016b72005-05-26 13:03:09 -07003985 (addr == data_end - 4))) {
3986
3987 cmd_flags |= BNX2_NVM_COMMAND_LAST;
3988 }
3989 rc = bnx2_nvram_write_dword(bp, addr, buf,
3990 cmd_flags);
3991
3992 if (rc != 0)
3993 goto nvram_write_end;
3994
3995 cmd_flags = 0;
3996 buf += 4;
3997 }
3998
3999 /* Loop to write back the buffer data from data_end
4000 * to page_end */
Michael Chane30372c2007-07-16 18:26:23 -07004001 if (!(bp->flash_info->flags & BNX2_NV_BUFFERED)) {
Michael Chanb6016b72005-05-26 13:03:09 -07004002 for (addr = data_end; addr < page_end;
4003 addr += 4, i += 4) {
Jeff Garzik6aa20a22006-09-13 13:24:59 -04004004
Michael Chanb6016b72005-05-26 13:03:09 -07004005 if (addr == page_end-4) {
4006 cmd_flags = BNX2_NVM_COMMAND_LAST;
4007 }
4008 rc = bnx2_nvram_write_dword(bp, addr,
4009 &flash_buffer[i], cmd_flags);
4010
4011 if (rc != 0)
4012 goto nvram_write_end;
4013
4014 cmd_flags = 0;
4015 }
4016 }
4017
4018 /* Disable writes to flash interface (lock write-protect) */
4019 bnx2_disable_nvram_write(bp);
4020
4021 /* Disable access to flash interface */
4022 bnx2_disable_nvram_access(bp);
4023 bnx2_release_nvram_lock(bp);
4024
4025 /* Increment written */
4026 written += data_end - data_start;
4027 }
4028
4029nvram_write_end:
Michael Chane6be7632007-01-08 19:56:13 -08004030 kfree(flash_buffer);
4031 kfree(align_buf);
Michael Chanb6016b72005-05-26 13:03:09 -07004032 return rc;
4033}
4034
Michael Chan0d8a6572007-07-07 22:49:43 -07004035static void
4036bnx2_init_remote_phy(struct bnx2 *bp)
4037{
4038 u32 val;
4039
4040 bp->phy_flags &= ~REMOTE_PHY_CAP_FLAG;
4041 if (!(bp->phy_flags & PHY_SERDES_FLAG))
4042 return;
4043
4044 val = REG_RD_IND(bp, bp->shmem_base + BNX2_FW_CAP_MB);
4045 if ((val & BNX2_FW_CAP_SIGNATURE_MASK) != BNX2_FW_CAP_SIGNATURE)
4046 return;
4047
4048 if (val & BNX2_FW_CAP_REMOTE_PHY_CAPABLE) {
Michael Chan0d8a6572007-07-07 22:49:43 -07004049 bp->phy_flags |= REMOTE_PHY_CAP_FLAG;
4050
4051 val = REG_RD_IND(bp, bp->shmem_base + BNX2_LINK_STATUS);
4052 if (val & BNX2_LINK_STATUS_SERDES_LINK)
4053 bp->phy_port = PORT_FIBRE;
4054 else
4055 bp->phy_port = PORT_TP;
Michael Chan489310a2007-10-10 16:16:31 -07004056
4057 if (netif_running(bp->dev)) {
4058 u32 sig;
4059
4060 if (val & BNX2_LINK_STATUS_LINK_UP) {
4061 bp->link_up = 1;
4062 netif_carrier_on(bp->dev);
4063 } else {
4064 bp->link_up = 0;
4065 netif_carrier_off(bp->dev);
4066 }
4067 sig = BNX2_DRV_ACK_CAP_SIGNATURE |
4068 BNX2_FW_CAP_REMOTE_PHY_CAPABLE;
4069 REG_WR_IND(bp, bp->shmem_base + BNX2_DRV_ACK_CAP_MB,
4070 sig);
4071 }
Michael Chan0d8a6572007-07-07 22:49:43 -07004072 }
4073}
4074
Michael Chanb6016b72005-05-26 13:03:09 -07004075static int
4076bnx2_reset_chip(struct bnx2 *bp, u32 reset_code)
4077{
4078 u32 val;
4079 int i, rc = 0;
Michael Chan489310a2007-10-10 16:16:31 -07004080 u8 old_port;
Michael Chanb6016b72005-05-26 13:03:09 -07004081
4082 /* Wait for the current PCI transaction to complete before
4083 * issuing a reset. */
4084 REG_WR(bp, BNX2_MISC_ENABLE_CLR_BITS,
4085 BNX2_MISC_ENABLE_CLR_BITS_TX_DMA_ENABLE |
4086 BNX2_MISC_ENABLE_CLR_BITS_DMA_ENGINE_ENABLE |
4087 BNX2_MISC_ENABLE_CLR_BITS_RX_DMA_ENABLE |
4088 BNX2_MISC_ENABLE_CLR_BITS_HOST_COALESCE_ENABLE);
4089 val = REG_RD(bp, BNX2_MISC_ENABLE_CLR_BITS);
4090 udelay(5);
4091
Michael Chanb090ae22006-01-23 16:07:10 -08004092 /* Wait for the firmware to tell us it is ok to issue a reset. */
4093 bnx2_fw_sync(bp, BNX2_DRV_MSG_DATA_WAIT0 | reset_code, 1);
4094
Michael Chanb6016b72005-05-26 13:03:09 -07004095 /* Deposit a driver reset signature so the firmware knows that
4096 * this is a soft reset. */
Michael Chane3648b32005-11-04 08:51:21 -08004097 REG_WR_IND(bp, bp->shmem_base + BNX2_DRV_RESET_SIGNATURE,
Michael Chanb6016b72005-05-26 13:03:09 -07004098 BNX2_DRV_RESET_SIGNATURE_MAGIC);
4099
Michael Chanb6016b72005-05-26 13:03:09 -07004100 /* Do a dummy read to force the chip to complete all current transaction
4101 * before we issue a reset. */
4102 val = REG_RD(bp, BNX2_MISC_ID);
4103
Michael Chan234754d2006-11-19 14:11:41 -08004104 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
4105 REG_WR(bp, BNX2_MISC_COMMAND, BNX2_MISC_COMMAND_SW_RESET);
4106 REG_RD(bp, BNX2_MISC_COMMAND);
4107 udelay(5);
Michael Chanb6016b72005-05-26 13:03:09 -07004108
Michael Chan234754d2006-11-19 14:11:41 -08004109 val = BNX2_PCICFG_MISC_CONFIG_REG_WINDOW_ENA |
4110 BNX2_PCICFG_MISC_CONFIG_TARGET_MB_WORD_SWAP;
Michael Chanb6016b72005-05-26 13:03:09 -07004111
Michael Chan234754d2006-11-19 14:11:41 -08004112 pci_write_config_dword(bp->pdev, BNX2_PCICFG_MISC_CONFIG, val);
Michael Chanb6016b72005-05-26 13:03:09 -07004113
Michael Chan234754d2006-11-19 14:11:41 -08004114 } else {
4115 val = BNX2_PCICFG_MISC_CONFIG_CORE_RST_REQ |
4116 BNX2_PCICFG_MISC_CONFIG_REG_WINDOW_ENA |
4117 BNX2_PCICFG_MISC_CONFIG_TARGET_MB_WORD_SWAP;
4118
4119 /* Chip reset. */
4120 REG_WR(bp, BNX2_PCICFG_MISC_CONFIG, val);
4121
Michael Chan594a9df2007-08-28 15:39:42 -07004122 /* Reading back any register after chip reset will hang the
4123 * bus on 5706 A0 and A1. The msleep below provides plenty
4124 * of margin for write posting.
4125 */
Michael Chan234754d2006-11-19 14:11:41 -08004126 if ((CHIP_ID(bp) == CHIP_ID_5706_A0) ||
Arjan van de Ven8e545882007-08-28 14:34:43 -07004127 (CHIP_ID(bp) == CHIP_ID_5706_A1))
4128 msleep(20);
Michael Chanb6016b72005-05-26 13:03:09 -07004129
Michael Chan234754d2006-11-19 14:11:41 -08004130 /* Reset takes approximate 30 usec */
4131 for (i = 0; i < 10; i++) {
4132 val = REG_RD(bp, BNX2_PCICFG_MISC_CONFIG);
4133 if ((val & (BNX2_PCICFG_MISC_CONFIG_CORE_RST_REQ |
4134 BNX2_PCICFG_MISC_CONFIG_CORE_RST_BSY)) == 0)
4135 break;
4136 udelay(10);
4137 }
4138
4139 if (val & (BNX2_PCICFG_MISC_CONFIG_CORE_RST_REQ |
4140 BNX2_PCICFG_MISC_CONFIG_CORE_RST_BSY)) {
4141 printk(KERN_ERR PFX "Chip reset did not complete\n");
4142 return -EBUSY;
4143 }
Michael Chanb6016b72005-05-26 13:03:09 -07004144 }
4145
4146 /* Make sure byte swapping is properly configured. */
4147 val = REG_RD(bp, BNX2_PCI_SWAP_DIAG0);
4148 if (val != 0x01020304) {
4149 printk(KERN_ERR PFX "Chip not in correct endian mode\n");
4150 return -ENODEV;
4151 }
4152
Michael Chanb6016b72005-05-26 13:03:09 -07004153 /* Wait for the firmware to finish its initialization. */
Michael Chanb090ae22006-01-23 16:07:10 -08004154 rc = bnx2_fw_sync(bp, BNX2_DRV_MSG_DATA_WAIT1 | reset_code, 0);
4155 if (rc)
4156 return rc;
Michael Chanb6016b72005-05-26 13:03:09 -07004157
Michael Chan0d8a6572007-07-07 22:49:43 -07004158 spin_lock_bh(&bp->phy_lock);
Michael Chan489310a2007-10-10 16:16:31 -07004159 old_port = bp->phy_port;
Michael Chan0d8a6572007-07-07 22:49:43 -07004160 bnx2_init_remote_phy(bp);
Michael Chan489310a2007-10-10 16:16:31 -07004161 if ((bp->phy_flags & REMOTE_PHY_CAP_FLAG) && old_port != bp->phy_port)
Michael Chan0d8a6572007-07-07 22:49:43 -07004162 bnx2_set_default_remote_link(bp);
4163 spin_unlock_bh(&bp->phy_lock);
4164
Michael Chanb6016b72005-05-26 13:03:09 -07004165 if (CHIP_ID(bp) == CHIP_ID_5706_A0) {
4166 /* Adjust the voltage regular to two steps lower. The default
4167 * of this register is 0x0000000e. */
4168 REG_WR(bp, BNX2_MISC_VREG_CONTROL, 0x000000fa);
4169
4170 /* Remove bad rbuf memory from the free pool. */
4171 rc = bnx2_alloc_bad_rbuf(bp);
4172 }
4173
4174 return rc;
4175}
4176
4177static int
4178bnx2_init_chip(struct bnx2 *bp)
4179{
4180 u32 val;
Michael Chanb090ae22006-01-23 16:07:10 -08004181 int rc;
Michael Chanb6016b72005-05-26 13:03:09 -07004182
4183 /* Make sure the interrupt is not active. */
4184 REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD, BNX2_PCICFG_INT_ACK_CMD_MASK_INT);
4185
4186 val = BNX2_DMA_CONFIG_DATA_BYTE_SWAP |
4187 BNX2_DMA_CONFIG_DATA_WORD_SWAP |
4188#ifdef __BIG_ENDIAN
Jeff Garzik6aa20a22006-09-13 13:24:59 -04004189 BNX2_DMA_CONFIG_CNTL_BYTE_SWAP |
Michael Chanb6016b72005-05-26 13:03:09 -07004190#endif
Jeff Garzik6aa20a22006-09-13 13:24:59 -04004191 BNX2_DMA_CONFIG_CNTL_WORD_SWAP |
Michael Chanb6016b72005-05-26 13:03:09 -07004192 DMA_READ_CHANS << 12 |
4193 DMA_WRITE_CHANS << 16;
4194
4195 val |= (0x2 << 20) | (1 << 11);
4196
Michael Chandda1e392006-01-23 16:08:14 -08004197 if ((bp->flags & PCIX_FLAG) && (bp->bus_speed_mhz == 133))
Michael Chanb6016b72005-05-26 13:03:09 -07004198 val |= (1 << 23);
4199
4200 if ((CHIP_NUM(bp) == CHIP_NUM_5706) &&
4201 (CHIP_ID(bp) != CHIP_ID_5706_A0) && !(bp->flags & PCIX_FLAG))
4202 val |= BNX2_DMA_CONFIG_CNTL_PING_PONG_DMA;
4203
4204 REG_WR(bp, BNX2_DMA_CONFIG, val);
4205
4206 if (CHIP_ID(bp) == CHIP_ID_5706_A0) {
4207 val = REG_RD(bp, BNX2_TDMA_CONFIG);
4208 val |= BNX2_TDMA_CONFIG_ONE_DMA;
4209 REG_WR(bp, BNX2_TDMA_CONFIG, val);
4210 }
4211
4212 if (bp->flags & PCIX_FLAG) {
4213 u16 val16;
4214
4215 pci_read_config_word(bp->pdev, bp->pcix_cap + PCI_X_CMD,
4216 &val16);
4217 pci_write_config_word(bp->pdev, bp->pcix_cap + PCI_X_CMD,
4218 val16 & ~PCI_X_CMD_ERO);
4219 }
4220
4221 REG_WR(bp, BNX2_MISC_ENABLE_SET_BITS,
4222 BNX2_MISC_ENABLE_SET_BITS_HOST_COALESCE_ENABLE |
4223 BNX2_MISC_ENABLE_STATUS_BITS_RX_V2P_ENABLE |
4224 BNX2_MISC_ENABLE_STATUS_BITS_CONTEXT_ENABLE);
4225
4226 /* Initialize context mapping and zero out the quick contexts. The
4227 * context block must have already been enabled. */
Michael Chan641bdcd2007-06-04 21:22:24 -07004228 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
4229 rc = bnx2_init_5709_context(bp);
4230 if (rc)
4231 return rc;
4232 } else
Michael Chan59b47d82006-11-19 14:10:45 -08004233 bnx2_init_context(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07004234
Michael Chanfba9fe92006-06-12 22:21:25 -07004235 if ((rc = bnx2_init_cpus(bp)) != 0)
4236 return rc;
4237
Michael Chanb6016b72005-05-26 13:03:09 -07004238 bnx2_init_nvram(bp);
4239
4240 bnx2_set_mac_addr(bp);
4241
4242 val = REG_RD(bp, BNX2_MQ_CONFIG);
4243 val &= ~BNX2_MQ_CONFIG_KNL_BYP_BLK_SIZE;
4244 val |= BNX2_MQ_CONFIG_KNL_BYP_BLK_SIZE_256;
Michael Chan68c9f752007-04-24 15:35:53 -07004245 if (CHIP_ID(bp) == CHIP_ID_5709_A0 || CHIP_ID(bp) == CHIP_ID_5709_A1)
4246 val |= BNX2_MQ_CONFIG_HALT_DIS;
4247
Michael Chanb6016b72005-05-26 13:03:09 -07004248 REG_WR(bp, BNX2_MQ_CONFIG, val);
4249
4250 val = 0x10000 + (MAX_CID_CNT * MB_KERNEL_CTX_SIZE);
4251 REG_WR(bp, BNX2_MQ_KNL_BYP_WIND_START, val);
4252 REG_WR(bp, BNX2_MQ_KNL_WIND_END, val);
4253
4254 val = (BCM_PAGE_BITS - 8) << 24;
4255 REG_WR(bp, BNX2_RV2P_CONFIG, val);
4256
4257 /* Configure page size. */
4258 val = REG_RD(bp, BNX2_TBDR_CONFIG);
4259 val &= ~BNX2_TBDR_CONFIG_PAGE_SIZE;
4260 val |= (BCM_PAGE_BITS - 8) << 24 | 0x40;
4261 REG_WR(bp, BNX2_TBDR_CONFIG, val);
4262
4263 val = bp->mac_addr[0] +
4264 (bp->mac_addr[1] << 8) +
4265 (bp->mac_addr[2] << 16) +
4266 bp->mac_addr[3] +
4267 (bp->mac_addr[4] << 8) +
4268 (bp->mac_addr[5] << 16);
4269 REG_WR(bp, BNX2_EMAC_BACKOFF_SEED, val);
4270
4271 /* Program the MTU. Also include 4 bytes for CRC32. */
4272 val = bp->dev->mtu + ETH_HLEN + 4;
4273 if (val > (MAX_ETHERNET_PACKET_SIZE + 4))
4274 val |= BNX2_EMAC_RX_MTU_SIZE_JUMBO_ENA;
4275 REG_WR(bp, BNX2_EMAC_RX_MTU_SIZE, val);
4276
Michael Chan35efa7c2007-12-20 19:56:37 -08004277 bp->bnx2_napi.last_status_idx = 0;
Michael Chanb6016b72005-05-26 13:03:09 -07004278 bp->rx_mode = BNX2_EMAC_RX_MODE_SORT_MODE;
4279
4280 /* Set up how to generate a link change interrupt. */
4281 REG_WR(bp, BNX2_EMAC_ATTENTION_ENA, BNX2_EMAC_ATTENTION_ENA_LINK);
4282
4283 REG_WR(bp, BNX2_HC_STATUS_ADDR_L,
4284 (u64) bp->status_blk_mapping & 0xffffffff);
4285 REG_WR(bp, BNX2_HC_STATUS_ADDR_H, (u64) bp->status_blk_mapping >> 32);
4286
4287 REG_WR(bp, BNX2_HC_STATISTICS_ADDR_L,
4288 (u64) bp->stats_blk_mapping & 0xffffffff);
4289 REG_WR(bp, BNX2_HC_STATISTICS_ADDR_H,
4290 (u64) bp->stats_blk_mapping >> 32);
4291
Jeff Garzik6aa20a22006-09-13 13:24:59 -04004292 REG_WR(bp, BNX2_HC_TX_QUICK_CONS_TRIP,
Michael Chanb6016b72005-05-26 13:03:09 -07004293 (bp->tx_quick_cons_trip_int << 16) | bp->tx_quick_cons_trip);
4294
4295 REG_WR(bp, BNX2_HC_RX_QUICK_CONS_TRIP,
4296 (bp->rx_quick_cons_trip_int << 16) | bp->rx_quick_cons_trip);
4297
4298 REG_WR(bp, BNX2_HC_COMP_PROD_TRIP,
4299 (bp->comp_prod_trip_int << 16) | bp->comp_prod_trip);
4300
4301 REG_WR(bp, BNX2_HC_TX_TICKS, (bp->tx_ticks_int << 16) | bp->tx_ticks);
4302
4303 REG_WR(bp, BNX2_HC_RX_TICKS, (bp->rx_ticks_int << 16) | bp->rx_ticks);
4304
4305 REG_WR(bp, BNX2_HC_COM_TICKS,
4306 (bp->com_ticks_int << 16) | bp->com_ticks);
4307
4308 REG_WR(bp, BNX2_HC_CMD_TICKS,
4309 (bp->cmd_ticks_int << 16) | bp->cmd_ticks);
4310
Michael Chan02537b062007-06-04 21:24:07 -07004311 if (CHIP_NUM(bp) == CHIP_NUM_5708)
4312 REG_WR(bp, BNX2_HC_STATS_TICKS, 0);
4313 else
Michael Chan7ea69202007-07-16 18:27:10 -07004314 REG_WR(bp, BNX2_HC_STATS_TICKS, bp->stats_ticks);
Michael Chanb6016b72005-05-26 13:03:09 -07004315 REG_WR(bp, BNX2_HC_STAT_COLLECT_TICKS, 0xbb8); /* 3ms */
4316
4317 if (CHIP_ID(bp) == CHIP_ID_5706_A1)
Michael Chan8e6a72c2007-05-03 13:24:48 -07004318 val = BNX2_HC_CONFIG_COLLECT_STATS;
Michael Chanb6016b72005-05-26 13:03:09 -07004319 else {
Michael Chan8e6a72c2007-05-03 13:24:48 -07004320 val = BNX2_HC_CONFIG_RX_TMR_MODE | BNX2_HC_CONFIG_TX_TMR_MODE |
4321 BNX2_HC_CONFIG_COLLECT_STATS;
Michael Chanb6016b72005-05-26 13:03:09 -07004322 }
4323
Michael Chan8e6a72c2007-05-03 13:24:48 -07004324 if (bp->flags & ONE_SHOT_MSI_FLAG)
4325 val |= BNX2_HC_CONFIG_ONE_SHOT;
4326
4327 REG_WR(bp, BNX2_HC_CONFIG, val);
4328
Michael Chanb6016b72005-05-26 13:03:09 -07004329 /* Clear internal stats counters. */
4330 REG_WR(bp, BNX2_HC_COMMAND, BNX2_HC_COMMAND_CLR_STAT_NOW);
4331
Michael Chanda3e4fb2007-05-03 13:24:23 -07004332 REG_WR(bp, BNX2_HC_ATTN_BITS_ENABLE, STATUS_ATTN_EVENTS);
Michael Chanb6016b72005-05-26 13:03:09 -07004333
4334 /* Initialize the receive filter. */
4335 bnx2_set_rx_mode(bp->dev);
4336
Michael Chan0aa38df2007-06-04 21:23:06 -07004337 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
4338 val = REG_RD(bp, BNX2_MISC_NEW_CORE_CTL);
4339 val |= BNX2_MISC_NEW_CORE_CTL_DMA_ENABLE;
4340 REG_WR(bp, BNX2_MISC_NEW_CORE_CTL, val);
4341 }
Michael Chanb090ae22006-01-23 16:07:10 -08004342 rc = bnx2_fw_sync(bp, BNX2_DRV_MSG_DATA_WAIT2 | BNX2_DRV_MSG_CODE_RESET,
4343 0);
Michael Chanb6016b72005-05-26 13:03:09 -07004344
Michael Chandf149d72007-07-07 22:51:36 -07004345 REG_WR(bp, BNX2_MISC_ENABLE_SET_BITS, BNX2_MISC_ENABLE_DEFAULT);
Michael Chanb6016b72005-05-26 13:03:09 -07004346 REG_RD(bp, BNX2_MISC_ENABLE_SET_BITS);
4347
4348 udelay(20);
4349
Michael Chanbf5295b2006-03-23 01:11:56 -08004350 bp->hc_cmd = REG_RD(bp, BNX2_HC_COMMAND);
4351
Michael Chanb090ae22006-01-23 16:07:10 -08004352 return rc;
Michael Chanb6016b72005-05-26 13:03:09 -07004353}
4354
Michael Chan59b47d82006-11-19 14:10:45 -08004355static void
4356bnx2_init_tx_context(struct bnx2 *bp, u32 cid)
4357{
4358 u32 val, offset0, offset1, offset2, offset3;
4359
4360 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
4361 offset0 = BNX2_L2CTX_TYPE_XI;
4362 offset1 = BNX2_L2CTX_CMD_TYPE_XI;
4363 offset2 = BNX2_L2CTX_TBDR_BHADDR_HI_XI;
4364 offset3 = BNX2_L2CTX_TBDR_BHADDR_LO_XI;
4365 } else {
4366 offset0 = BNX2_L2CTX_TYPE;
4367 offset1 = BNX2_L2CTX_CMD_TYPE;
4368 offset2 = BNX2_L2CTX_TBDR_BHADDR_HI;
4369 offset3 = BNX2_L2CTX_TBDR_BHADDR_LO;
4370 }
4371 val = BNX2_L2CTX_TYPE_TYPE_L2 | BNX2_L2CTX_TYPE_SIZE_L2;
4372 CTX_WR(bp, GET_CID_ADDR(cid), offset0, val);
4373
4374 val = BNX2_L2CTX_CMD_TYPE_TYPE_L2 | (8 << 16);
4375 CTX_WR(bp, GET_CID_ADDR(cid), offset1, val);
4376
4377 val = (u64) bp->tx_desc_mapping >> 32;
4378 CTX_WR(bp, GET_CID_ADDR(cid), offset2, val);
4379
4380 val = (u64) bp->tx_desc_mapping & 0xffffffff;
4381 CTX_WR(bp, GET_CID_ADDR(cid), offset3, val);
4382}
Michael Chanb6016b72005-05-26 13:03:09 -07004383
4384static void
4385bnx2_init_tx_ring(struct bnx2 *bp)
4386{
4387 struct tx_bd *txbd;
Michael Chan59b47d82006-11-19 14:10:45 -08004388 u32 cid;
Michael Chana550c992007-12-20 19:56:59 -08004389 struct bnx2_napi *bnapi = &bp->bnx2_napi;
Michael Chanb6016b72005-05-26 13:03:09 -07004390
Michael Chan2f8af122006-08-15 01:39:10 -07004391 bp->tx_wake_thresh = bp->tx_ring_size / 2;
4392
Michael Chanb6016b72005-05-26 13:03:09 -07004393 txbd = &bp->tx_desc_ring[MAX_TX_DESC_CNT];
Jeff Garzik6aa20a22006-09-13 13:24:59 -04004394
Michael Chanb6016b72005-05-26 13:03:09 -07004395 txbd->tx_bd_haddr_hi = (u64) bp->tx_desc_mapping >> 32;
4396 txbd->tx_bd_haddr_lo = (u64) bp->tx_desc_mapping & 0xffffffff;
4397
4398 bp->tx_prod = 0;
Michael Chana550c992007-12-20 19:56:59 -08004399 bnapi->tx_cons = 0;
4400 bnapi->hw_tx_cons = 0;
Michael Chanb6016b72005-05-26 13:03:09 -07004401 bp->tx_prod_bseq = 0;
Jeff Garzik6aa20a22006-09-13 13:24:59 -04004402
Michael Chan59b47d82006-11-19 14:10:45 -08004403 cid = TX_CID;
4404 bp->tx_bidx_addr = MB_GET_CID_ADDR(cid) + BNX2_L2CTX_TX_HOST_BIDX;
4405 bp->tx_bseq_addr = MB_GET_CID_ADDR(cid) + BNX2_L2CTX_TX_HOST_BSEQ;
Michael Chanb6016b72005-05-26 13:03:09 -07004406
Michael Chan59b47d82006-11-19 14:10:45 -08004407 bnx2_init_tx_context(bp, cid);
Michael Chanb6016b72005-05-26 13:03:09 -07004408}
4409
4410static void
Michael Chan5d5d0012007-12-12 11:17:43 -08004411bnx2_init_rxbd_rings(struct rx_bd *rx_ring[], dma_addr_t dma[], u32 buf_size,
4412 int num_rings)
Michael Chanb6016b72005-05-26 13:03:09 -07004413{
Michael Chanb6016b72005-05-26 13:03:09 -07004414 int i;
Michael Chan5d5d0012007-12-12 11:17:43 -08004415 struct rx_bd *rxbd;
Michael Chanb6016b72005-05-26 13:03:09 -07004416
Michael Chan5d5d0012007-12-12 11:17:43 -08004417 for (i = 0; i < num_rings; i++) {
Michael Chan13daffa2006-03-20 17:49:20 -08004418 int j;
Michael Chanb6016b72005-05-26 13:03:09 -07004419
Michael Chan5d5d0012007-12-12 11:17:43 -08004420 rxbd = &rx_ring[i][0];
Michael Chan13daffa2006-03-20 17:49:20 -08004421 for (j = 0; j < MAX_RX_DESC_CNT; j++, rxbd++) {
Michael Chan5d5d0012007-12-12 11:17:43 -08004422 rxbd->rx_bd_len = buf_size;
Michael Chan13daffa2006-03-20 17:49:20 -08004423 rxbd->rx_bd_flags = RX_BD_FLAGS_START | RX_BD_FLAGS_END;
4424 }
Michael Chan5d5d0012007-12-12 11:17:43 -08004425 if (i == (num_rings - 1))
Michael Chan13daffa2006-03-20 17:49:20 -08004426 j = 0;
4427 else
4428 j = i + 1;
Michael Chan5d5d0012007-12-12 11:17:43 -08004429 rxbd->rx_bd_haddr_hi = (u64) dma[j] >> 32;
4430 rxbd->rx_bd_haddr_lo = (u64) dma[j] & 0xffffffff;
Michael Chan13daffa2006-03-20 17:49:20 -08004431 }
Michael Chan5d5d0012007-12-12 11:17:43 -08004432}
4433
4434static void
4435bnx2_init_rx_ring(struct bnx2 *bp)
4436{
4437 int i;
4438 u16 prod, ring_prod;
4439 u32 val, rx_cid_addr = GET_CID_ADDR(RX_CID);
Michael Chana1f60192007-12-20 19:57:19 -08004440 struct bnx2_napi *bnapi = &bp->bnx2_napi;
Michael Chan5d5d0012007-12-12 11:17:43 -08004441
Michael Chana1f60192007-12-20 19:57:19 -08004442 bnapi->rx_prod = 0;
4443 bnapi->rx_cons = 0;
4444 bnapi->rx_prod_bseq = 0;
4445 bnapi->rx_pg_prod = 0;
4446 bnapi->rx_pg_cons = 0;
Michael Chan5d5d0012007-12-12 11:17:43 -08004447
4448 bnx2_init_rxbd_rings(bp->rx_desc_ring, bp->rx_desc_mapping,
4449 bp->rx_buf_use_size, bp->rx_max_ring);
4450
4451 CTX_WR(bp, rx_cid_addr, BNX2_L2CTX_PG_BUF_SIZE, 0);
Michael Chan47bf4242007-12-12 11:19:12 -08004452 if (bp->rx_pg_ring_size) {
4453 bnx2_init_rxbd_rings(bp->rx_pg_desc_ring,
4454 bp->rx_pg_desc_mapping,
4455 PAGE_SIZE, bp->rx_max_pg_ring);
4456 val = (bp->rx_buf_use_size << 16) | PAGE_SIZE;
4457 CTX_WR(bp, rx_cid_addr, BNX2_L2CTX_PG_BUF_SIZE, val);
4458 CTX_WR(bp, rx_cid_addr, BNX2_L2CTX_RBDC_KEY,
4459 BNX2_L2CTX_RBDC_JUMBO_KEY);
4460
4461 val = (u64) bp->rx_pg_desc_mapping[0] >> 32;
4462 CTX_WR(bp, rx_cid_addr, BNX2_L2CTX_NX_PG_BDHADDR_HI, val);
4463
4464 val = (u64) bp->rx_pg_desc_mapping[0] & 0xffffffff;
4465 CTX_WR(bp, rx_cid_addr, BNX2_L2CTX_NX_PG_BDHADDR_LO, val);
4466
4467 if (CHIP_NUM(bp) == CHIP_NUM_5709)
4468 REG_WR(bp, BNX2_MQ_MAP_L2_3, BNX2_MQ_MAP_L2_3_DEFAULT);
4469 }
Michael Chanb6016b72005-05-26 13:03:09 -07004470
4471 val = BNX2_L2CTX_CTX_TYPE_CTX_BD_CHN_TYPE_VALUE;
4472 val |= BNX2_L2CTX_CTX_TYPE_SIZE_L2;
4473 val |= 0x02 << 8;
Michael Chan5d5d0012007-12-12 11:17:43 -08004474 CTX_WR(bp, rx_cid_addr, BNX2_L2CTX_CTX_TYPE, val);
Michael Chanb6016b72005-05-26 13:03:09 -07004475
Michael Chan13daffa2006-03-20 17:49:20 -08004476 val = (u64) bp->rx_desc_mapping[0] >> 32;
Michael Chan5d5d0012007-12-12 11:17:43 -08004477 CTX_WR(bp, rx_cid_addr, BNX2_L2CTX_NX_BDHADDR_HI, val);
Michael Chanb6016b72005-05-26 13:03:09 -07004478
Michael Chan13daffa2006-03-20 17:49:20 -08004479 val = (u64) bp->rx_desc_mapping[0] & 0xffffffff;
Michael Chan5d5d0012007-12-12 11:17:43 -08004480 CTX_WR(bp, rx_cid_addr, BNX2_L2CTX_NX_BDHADDR_LO, val);
Michael Chanb6016b72005-05-26 13:03:09 -07004481
Michael Chana1f60192007-12-20 19:57:19 -08004482 ring_prod = prod = bnapi->rx_pg_prod;
Michael Chan47bf4242007-12-12 11:19:12 -08004483 for (i = 0; i < bp->rx_pg_ring_size; i++) {
4484 if (bnx2_alloc_rx_page(bp, ring_prod) < 0)
4485 break;
4486 prod = NEXT_RX_BD(prod);
4487 ring_prod = RX_PG_RING_IDX(prod);
4488 }
Michael Chana1f60192007-12-20 19:57:19 -08004489 bnapi->rx_pg_prod = prod;
Michael Chan47bf4242007-12-12 11:19:12 -08004490
Michael Chana1f60192007-12-20 19:57:19 -08004491 ring_prod = prod = bnapi->rx_prod;
Michael Chan236b6392006-03-20 17:49:02 -08004492 for (i = 0; i < bp->rx_ring_size; i++) {
Michael Chana1f60192007-12-20 19:57:19 -08004493 if (bnx2_alloc_rx_skb(bp, bnapi, ring_prod) < 0) {
Michael Chanb6016b72005-05-26 13:03:09 -07004494 break;
4495 }
4496 prod = NEXT_RX_BD(prod);
4497 ring_prod = RX_RING_IDX(prod);
4498 }
Michael Chana1f60192007-12-20 19:57:19 -08004499 bnapi->rx_prod = prod;
Michael Chanb6016b72005-05-26 13:03:09 -07004500
Michael Chana1f60192007-12-20 19:57:19 -08004501 REG_WR16(bp, MB_RX_CID_ADDR + BNX2_L2CTX_HOST_PG_BDIDX,
4502 bnapi->rx_pg_prod);
Michael Chanb6016b72005-05-26 13:03:09 -07004503 REG_WR16(bp, MB_RX_CID_ADDR + BNX2_L2CTX_HOST_BDIDX, prod);
4504
Michael Chana1f60192007-12-20 19:57:19 -08004505 REG_WR(bp, MB_RX_CID_ADDR + BNX2_L2CTX_HOST_BSEQ, bnapi->rx_prod_bseq);
Michael Chanb6016b72005-05-26 13:03:09 -07004506}
4507
Michael Chan5d5d0012007-12-12 11:17:43 -08004508static u32 bnx2_find_max_ring(u32 ring_size, u32 max_size)
Michael Chan13daffa2006-03-20 17:49:20 -08004509{
Michael Chan5d5d0012007-12-12 11:17:43 -08004510 u32 max, num_rings = 1;
Michael Chan13daffa2006-03-20 17:49:20 -08004511
Michael Chan5d5d0012007-12-12 11:17:43 -08004512 while (ring_size > MAX_RX_DESC_CNT) {
4513 ring_size -= MAX_RX_DESC_CNT;
Michael Chan13daffa2006-03-20 17:49:20 -08004514 num_rings++;
4515 }
4516 /* round to next power of 2 */
Michael Chan5d5d0012007-12-12 11:17:43 -08004517 max = max_size;
Michael Chan13daffa2006-03-20 17:49:20 -08004518 while ((max & num_rings) == 0)
4519 max >>= 1;
4520
4521 if (num_rings != max)
4522 max <<= 1;
4523
Michael Chan5d5d0012007-12-12 11:17:43 -08004524 return max;
4525}
4526
4527static void
4528bnx2_set_rx_ring_size(struct bnx2 *bp, u32 size)
4529{
Michael Chan84eaa182007-12-12 11:19:57 -08004530 u32 rx_size, rx_space, jumbo_size;
Michael Chan5d5d0012007-12-12 11:17:43 -08004531
4532 /* 8 for CRC and VLAN */
4533 rx_size = bp->dev->mtu + ETH_HLEN + bp->rx_offset + 8;
4534
Michael Chan84eaa182007-12-12 11:19:57 -08004535 rx_space = SKB_DATA_ALIGN(rx_size + BNX2_RX_ALIGN) + NET_SKB_PAD +
4536 sizeof(struct skb_shared_info);
4537
Michael Chan5d5d0012007-12-12 11:17:43 -08004538 bp->rx_copy_thresh = RX_COPY_THRESH;
Michael Chan47bf4242007-12-12 11:19:12 -08004539 bp->rx_pg_ring_size = 0;
4540 bp->rx_max_pg_ring = 0;
4541 bp->rx_max_pg_ring_idx = 0;
Michael Chan84eaa182007-12-12 11:19:57 -08004542 if (rx_space > PAGE_SIZE) {
4543 int pages = PAGE_ALIGN(bp->dev->mtu - 40) >> PAGE_SHIFT;
4544
4545 jumbo_size = size * pages;
4546 if (jumbo_size > MAX_TOTAL_RX_PG_DESC_CNT)
4547 jumbo_size = MAX_TOTAL_RX_PG_DESC_CNT;
4548
4549 bp->rx_pg_ring_size = jumbo_size;
4550 bp->rx_max_pg_ring = bnx2_find_max_ring(jumbo_size,
4551 MAX_RX_PG_RINGS);
4552 bp->rx_max_pg_ring_idx = (bp->rx_max_pg_ring * RX_DESC_CNT) - 1;
4553 rx_size = RX_COPY_THRESH + bp->rx_offset;
4554 bp->rx_copy_thresh = 0;
4555 }
Michael Chan5d5d0012007-12-12 11:17:43 -08004556
4557 bp->rx_buf_use_size = rx_size;
4558 /* hw alignment */
4559 bp->rx_buf_size = bp->rx_buf_use_size + BNX2_RX_ALIGN;
Michael Chan1db82f22007-12-12 11:19:35 -08004560 bp->rx_jumbo_thresh = rx_size - bp->rx_offset;
Michael Chan5d5d0012007-12-12 11:17:43 -08004561 bp->rx_ring_size = size;
4562 bp->rx_max_ring = bnx2_find_max_ring(size, MAX_RX_RINGS);
Michael Chan13daffa2006-03-20 17:49:20 -08004563 bp->rx_max_ring_idx = (bp->rx_max_ring * RX_DESC_CNT) - 1;
4564}
4565
4566static void
Michael Chanb6016b72005-05-26 13:03:09 -07004567bnx2_free_tx_skbs(struct bnx2 *bp)
4568{
4569 int i;
4570
4571 if (bp->tx_buf_ring == NULL)
4572 return;
4573
4574 for (i = 0; i < TX_DESC_CNT; ) {
4575 struct sw_bd *tx_buf = &bp->tx_buf_ring[i];
4576 struct sk_buff *skb = tx_buf->skb;
4577 int j, last;
4578
4579 if (skb == NULL) {
4580 i++;
4581 continue;
4582 }
4583
4584 pci_unmap_single(bp->pdev, pci_unmap_addr(tx_buf, mapping),
4585 skb_headlen(skb), PCI_DMA_TODEVICE);
4586
4587 tx_buf->skb = NULL;
4588
4589 last = skb_shinfo(skb)->nr_frags;
4590 for (j = 0; j < last; j++) {
4591 tx_buf = &bp->tx_buf_ring[i + j + 1];
4592 pci_unmap_page(bp->pdev,
4593 pci_unmap_addr(tx_buf, mapping),
4594 skb_shinfo(skb)->frags[j].size,
4595 PCI_DMA_TODEVICE);
4596 }
Michael Chan745720e2006-06-29 12:37:41 -07004597 dev_kfree_skb(skb);
Michael Chanb6016b72005-05-26 13:03:09 -07004598 i += j + 1;
4599 }
4600
4601}
4602
4603static void
4604bnx2_free_rx_skbs(struct bnx2 *bp)
4605{
4606 int i;
4607
4608 if (bp->rx_buf_ring == NULL)
4609 return;
4610
Michael Chan13daffa2006-03-20 17:49:20 -08004611 for (i = 0; i < bp->rx_max_ring_idx; i++) {
Michael Chanb6016b72005-05-26 13:03:09 -07004612 struct sw_bd *rx_buf = &bp->rx_buf_ring[i];
4613 struct sk_buff *skb = rx_buf->skb;
4614
Michael Chan05d0f1c2005-11-04 08:53:48 -08004615 if (skb == NULL)
Michael Chanb6016b72005-05-26 13:03:09 -07004616 continue;
4617
4618 pci_unmap_single(bp->pdev, pci_unmap_addr(rx_buf, mapping),
4619 bp->rx_buf_use_size, PCI_DMA_FROMDEVICE);
4620
4621 rx_buf->skb = NULL;
4622
Michael Chan745720e2006-06-29 12:37:41 -07004623 dev_kfree_skb(skb);
Michael Chanb6016b72005-05-26 13:03:09 -07004624 }
Michael Chan47bf4242007-12-12 11:19:12 -08004625 for (i = 0; i < bp->rx_max_pg_ring_idx; i++)
4626 bnx2_free_rx_page(bp, i);
Michael Chanb6016b72005-05-26 13:03:09 -07004627}
4628
4629static void
4630bnx2_free_skbs(struct bnx2 *bp)
4631{
4632 bnx2_free_tx_skbs(bp);
4633 bnx2_free_rx_skbs(bp);
4634}
4635
4636static int
4637bnx2_reset_nic(struct bnx2 *bp, u32 reset_code)
4638{
4639 int rc;
4640
4641 rc = bnx2_reset_chip(bp, reset_code);
4642 bnx2_free_skbs(bp);
4643 if (rc)
4644 return rc;
4645
Michael Chanfba9fe92006-06-12 22:21:25 -07004646 if ((rc = bnx2_init_chip(bp)) != 0)
4647 return rc;
4648
Michael Chanb6016b72005-05-26 13:03:09 -07004649 bnx2_init_tx_ring(bp);
4650 bnx2_init_rx_ring(bp);
4651 return 0;
4652}
4653
4654static int
4655bnx2_init_nic(struct bnx2 *bp)
4656{
4657 int rc;
4658
4659 if ((rc = bnx2_reset_nic(bp, BNX2_DRV_MSG_CODE_RESET)) != 0)
4660 return rc;
4661
Michael Chan80be4432006-11-19 14:07:28 -08004662 spin_lock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07004663 bnx2_init_phy(bp);
4664 bnx2_set_link(bp);
Michael Chan0d8a6572007-07-07 22:49:43 -07004665 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07004666 return 0;
4667}
4668
4669static int
4670bnx2_test_registers(struct bnx2 *bp)
4671{
4672 int ret;
Michael Chan5bae30c2007-05-03 13:18:46 -07004673 int i, is_5709;
Arjan van de Venf71e1302006-03-03 21:33:57 -05004674 static const struct {
Michael Chanb6016b72005-05-26 13:03:09 -07004675 u16 offset;
4676 u16 flags;
Michael Chan5bae30c2007-05-03 13:18:46 -07004677#define BNX2_FL_NOT_5709 1
Michael Chanb6016b72005-05-26 13:03:09 -07004678 u32 rw_mask;
4679 u32 ro_mask;
4680 } reg_tbl[] = {
4681 { 0x006c, 0, 0x00000000, 0x0000003f },
4682 { 0x0090, 0, 0xffffffff, 0x00000000 },
4683 { 0x0094, 0, 0x00000000, 0x00000000 },
4684
Michael Chan5bae30c2007-05-03 13:18:46 -07004685 { 0x0404, BNX2_FL_NOT_5709, 0x00003f00, 0x00000000 },
4686 { 0x0418, BNX2_FL_NOT_5709, 0x00000000, 0xffffffff },
4687 { 0x041c, BNX2_FL_NOT_5709, 0x00000000, 0xffffffff },
4688 { 0x0420, BNX2_FL_NOT_5709, 0x00000000, 0x80ffffff },
4689 { 0x0424, BNX2_FL_NOT_5709, 0x00000000, 0x00000000 },
4690 { 0x0428, BNX2_FL_NOT_5709, 0x00000000, 0x00000001 },
4691 { 0x0450, BNX2_FL_NOT_5709, 0x00000000, 0x0000ffff },
4692 { 0x0454, BNX2_FL_NOT_5709, 0x00000000, 0xffffffff },
4693 { 0x0458, BNX2_FL_NOT_5709, 0x00000000, 0xffffffff },
Michael Chanb6016b72005-05-26 13:03:09 -07004694
Michael Chan5bae30c2007-05-03 13:18:46 -07004695 { 0x0808, BNX2_FL_NOT_5709, 0x00000000, 0xffffffff },
4696 { 0x0854, BNX2_FL_NOT_5709, 0x00000000, 0xffffffff },
4697 { 0x0868, BNX2_FL_NOT_5709, 0x00000000, 0x77777777 },
4698 { 0x086c, BNX2_FL_NOT_5709, 0x00000000, 0x77777777 },
4699 { 0x0870, BNX2_FL_NOT_5709, 0x00000000, 0x77777777 },
4700 { 0x0874, BNX2_FL_NOT_5709, 0x00000000, 0x77777777 },
Michael Chanb6016b72005-05-26 13:03:09 -07004701
Michael Chan5bae30c2007-05-03 13:18:46 -07004702 { 0x0c00, BNX2_FL_NOT_5709, 0x00000000, 0x00000001 },
4703 { 0x0c04, BNX2_FL_NOT_5709, 0x00000000, 0x03ff0001 },
4704 { 0x0c08, BNX2_FL_NOT_5709, 0x0f0ff073, 0x00000000 },
Michael Chanb6016b72005-05-26 13:03:09 -07004705
4706 { 0x1000, 0, 0x00000000, 0x00000001 },
4707 { 0x1004, 0, 0x00000000, 0x000f0001 },
Michael Chanb6016b72005-05-26 13:03:09 -07004708
4709 { 0x1408, 0, 0x01c00800, 0x00000000 },
4710 { 0x149c, 0, 0x8000ffff, 0x00000000 },
4711 { 0x14a8, 0, 0x00000000, 0x000001ff },
Michael Chan5b0c76a2005-11-04 08:45:49 -08004712 { 0x14ac, 0, 0x0fffffff, 0x10000000 },
Michael Chanb6016b72005-05-26 13:03:09 -07004713 { 0x14b0, 0, 0x00000002, 0x00000001 },
4714 { 0x14b8, 0, 0x00000000, 0x00000000 },
4715 { 0x14c0, 0, 0x00000000, 0x00000009 },
4716 { 0x14c4, 0, 0x00003fff, 0x00000000 },
4717 { 0x14cc, 0, 0x00000000, 0x00000001 },
4718 { 0x14d0, 0, 0xffffffff, 0x00000000 },
Michael Chanb6016b72005-05-26 13:03:09 -07004719
4720 { 0x1800, 0, 0x00000000, 0x00000001 },
4721 { 0x1804, 0, 0x00000000, 0x00000003 },
Michael Chanb6016b72005-05-26 13:03:09 -07004722
4723 { 0x2800, 0, 0x00000000, 0x00000001 },
4724 { 0x2804, 0, 0x00000000, 0x00003f01 },
4725 { 0x2808, 0, 0x0f3f3f03, 0x00000000 },
4726 { 0x2810, 0, 0xffff0000, 0x00000000 },
4727 { 0x2814, 0, 0xffff0000, 0x00000000 },
4728 { 0x2818, 0, 0xffff0000, 0x00000000 },
4729 { 0x281c, 0, 0xffff0000, 0x00000000 },
4730 { 0x2834, 0, 0xffffffff, 0x00000000 },
4731 { 0x2840, 0, 0x00000000, 0xffffffff },
4732 { 0x2844, 0, 0x00000000, 0xffffffff },
4733 { 0x2848, 0, 0xffffffff, 0x00000000 },
4734 { 0x284c, 0, 0xf800f800, 0x07ff07ff },
4735
4736 { 0x2c00, 0, 0x00000000, 0x00000011 },
4737 { 0x2c04, 0, 0x00000000, 0x00030007 },
4738
Michael Chanb6016b72005-05-26 13:03:09 -07004739 { 0x3c00, 0, 0x00000000, 0x00000001 },
4740 { 0x3c04, 0, 0x00000000, 0x00070000 },
4741 { 0x3c08, 0, 0x00007f71, 0x07f00000 },
4742 { 0x3c0c, 0, 0x1f3ffffc, 0x00000000 },
4743 { 0x3c10, 0, 0xffffffff, 0x00000000 },
4744 { 0x3c14, 0, 0x00000000, 0xffffffff },
4745 { 0x3c18, 0, 0x00000000, 0xffffffff },
4746 { 0x3c1c, 0, 0xfffff000, 0x00000000 },
4747 { 0x3c20, 0, 0xffffff00, 0x00000000 },
Michael Chanb6016b72005-05-26 13:03:09 -07004748
4749 { 0x5004, 0, 0x00000000, 0x0000007f },
4750 { 0x5008, 0, 0x0f0007ff, 0x00000000 },
Michael Chanb6016b72005-05-26 13:03:09 -07004751
Michael Chanb6016b72005-05-26 13:03:09 -07004752 { 0x5c00, 0, 0x00000000, 0x00000001 },
4753 { 0x5c04, 0, 0x00000000, 0x0003000f },
4754 { 0x5c08, 0, 0x00000003, 0x00000000 },
4755 { 0x5c0c, 0, 0x0000fff8, 0x00000000 },
4756 { 0x5c10, 0, 0x00000000, 0xffffffff },
4757 { 0x5c80, 0, 0x00000000, 0x0f7113f1 },
4758 { 0x5c84, 0, 0x00000000, 0x0000f333 },
4759 { 0x5c88, 0, 0x00000000, 0x00077373 },
4760 { 0x5c8c, 0, 0x00000000, 0x0007f737 },
4761
4762 { 0x6808, 0, 0x0000ff7f, 0x00000000 },
4763 { 0x680c, 0, 0xffffffff, 0x00000000 },
4764 { 0x6810, 0, 0xffffffff, 0x00000000 },
4765 { 0x6814, 0, 0xffffffff, 0x00000000 },
4766 { 0x6818, 0, 0xffffffff, 0x00000000 },
4767 { 0x681c, 0, 0xffffffff, 0x00000000 },
4768 { 0x6820, 0, 0x00ff00ff, 0x00000000 },
4769 { 0x6824, 0, 0x00ff00ff, 0x00000000 },
4770 { 0x6828, 0, 0x00ff00ff, 0x00000000 },
4771 { 0x682c, 0, 0x03ff03ff, 0x00000000 },
4772 { 0x6830, 0, 0x03ff03ff, 0x00000000 },
4773 { 0x6834, 0, 0x03ff03ff, 0x00000000 },
4774 { 0x6838, 0, 0x03ff03ff, 0x00000000 },
4775 { 0x683c, 0, 0x0000ffff, 0x00000000 },
4776 { 0x6840, 0, 0x00000ff0, 0x00000000 },
4777 { 0x6844, 0, 0x00ffff00, 0x00000000 },
4778 { 0x684c, 0, 0xffffffff, 0x00000000 },
4779 { 0x6850, 0, 0x7f7f7f7f, 0x00000000 },
4780 { 0x6854, 0, 0x7f7f7f7f, 0x00000000 },
4781 { 0x6858, 0, 0x7f7f7f7f, 0x00000000 },
4782 { 0x685c, 0, 0x7f7f7f7f, 0x00000000 },
4783 { 0x6908, 0, 0x00000000, 0x0001ff0f },
4784 { 0x690c, 0, 0x00000000, 0x0ffe00f0 },
4785
4786 { 0xffff, 0, 0x00000000, 0x00000000 },
4787 };
4788
4789 ret = 0;
Michael Chan5bae30c2007-05-03 13:18:46 -07004790 is_5709 = 0;
4791 if (CHIP_NUM(bp) == CHIP_NUM_5709)
4792 is_5709 = 1;
4793
Michael Chanb6016b72005-05-26 13:03:09 -07004794 for (i = 0; reg_tbl[i].offset != 0xffff; i++) {
4795 u32 offset, rw_mask, ro_mask, save_val, val;
Michael Chan5bae30c2007-05-03 13:18:46 -07004796 u16 flags = reg_tbl[i].flags;
4797
4798 if (is_5709 && (flags & BNX2_FL_NOT_5709))
4799 continue;
Michael Chanb6016b72005-05-26 13:03:09 -07004800
4801 offset = (u32) reg_tbl[i].offset;
4802 rw_mask = reg_tbl[i].rw_mask;
4803 ro_mask = reg_tbl[i].ro_mask;
4804
Peter Hagervall14ab9b82005-08-10 14:18:16 -07004805 save_val = readl(bp->regview + offset);
Michael Chanb6016b72005-05-26 13:03:09 -07004806
Peter Hagervall14ab9b82005-08-10 14:18:16 -07004807 writel(0, bp->regview + offset);
Michael Chanb6016b72005-05-26 13:03:09 -07004808
Peter Hagervall14ab9b82005-08-10 14:18:16 -07004809 val = readl(bp->regview + offset);
Michael Chanb6016b72005-05-26 13:03:09 -07004810 if ((val & rw_mask) != 0) {
4811 goto reg_test_err;
4812 }
4813
4814 if ((val & ro_mask) != (save_val & ro_mask)) {
4815 goto reg_test_err;
4816 }
4817
Peter Hagervall14ab9b82005-08-10 14:18:16 -07004818 writel(0xffffffff, bp->regview + offset);
Michael Chanb6016b72005-05-26 13:03:09 -07004819
Peter Hagervall14ab9b82005-08-10 14:18:16 -07004820 val = readl(bp->regview + offset);
Michael Chanb6016b72005-05-26 13:03:09 -07004821 if ((val & rw_mask) != rw_mask) {
4822 goto reg_test_err;
4823 }
4824
4825 if ((val & ro_mask) != (save_val & ro_mask)) {
4826 goto reg_test_err;
4827 }
4828
Peter Hagervall14ab9b82005-08-10 14:18:16 -07004829 writel(save_val, bp->regview + offset);
Michael Chanb6016b72005-05-26 13:03:09 -07004830 continue;
4831
4832reg_test_err:
Peter Hagervall14ab9b82005-08-10 14:18:16 -07004833 writel(save_val, bp->regview + offset);
Michael Chanb6016b72005-05-26 13:03:09 -07004834 ret = -ENODEV;
4835 break;
4836 }
4837 return ret;
4838}
4839
4840static int
4841bnx2_do_mem_test(struct bnx2 *bp, u32 start, u32 size)
4842{
Arjan van de Venf71e1302006-03-03 21:33:57 -05004843 static const u32 test_pattern[] = { 0x00000000, 0xffffffff, 0x55555555,
Michael Chanb6016b72005-05-26 13:03:09 -07004844 0xaaaaaaaa , 0xaa55aa55, 0x55aa55aa };
4845 int i;
4846
4847 for (i = 0; i < sizeof(test_pattern) / 4; i++) {
4848 u32 offset;
4849
4850 for (offset = 0; offset < size; offset += 4) {
4851
4852 REG_WR_IND(bp, start + offset, test_pattern[i]);
4853
4854 if (REG_RD_IND(bp, start + offset) !=
4855 test_pattern[i]) {
4856 return -ENODEV;
4857 }
4858 }
4859 }
4860 return 0;
4861}
4862
4863static int
4864bnx2_test_memory(struct bnx2 *bp)
4865{
4866 int ret = 0;
4867 int i;
Michael Chan5bae30c2007-05-03 13:18:46 -07004868 static struct mem_entry {
Michael Chanb6016b72005-05-26 13:03:09 -07004869 u32 offset;
4870 u32 len;
Michael Chan5bae30c2007-05-03 13:18:46 -07004871 } mem_tbl_5706[] = {
Michael Chanb6016b72005-05-26 13:03:09 -07004872 { 0x60000, 0x4000 },
Michael Chan5b0c76a2005-11-04 08:45:49 -08004873 { 0xa0000, 0x3000 },
Michael Chanb6016b72005-05-26 13:03:09 -07004874 { 0xe0000, 0x4000 },
4875 { 0x120000, 0x4000 },
4876 { 0x1a0000, 0x4000 },
4877 { 0x160000, 0x4000 },
4878 { 0xffffffff, 0 },
Michael Chan5bae30c2007-05-03 13:18:46 -07004879 },
4880 mem_tbl_5709[] = {
4881 { 0x60000, 0x4000 },
4882 { 0xa0000, 0x3000 },
4883 { 0xe0000, 0x4000 },
4884 { 0x120000, 0x4000 },
4885 { 0x1a0000, 0x4000 },
4886 { 0xffffffff, 0 },
Michael Chanb6016b72005-05-26 13:03:09 -07004887 };
Michael Chan5bae30c2007-05-03 13:18:46 -07004888 struct mem_entry *mem_tbl;
4889
4890 if (CHIP_NUM(bp) == CHIP_NUM_5709)
4891 mem_tbl = mem_tbl_5709;
4892 else
4893 mem_tbl = mem_tbl_5706;
Michael Chanb6016b72005-05-26 13:03:09 -07004894
4895 for (i = 0; mem_tbl[i].offset != 0xffffffff; i++) {
4896 if ((ret = bnx2_do_mem_test(bp, mem_tbl[i].offset,
4897 mem_tbl[i].len)) != 0) {
4898 return ret;
4899 }
4900 }
Jeff Garzik6aa20a22006-09-13 13:24:59 -04004901
Michael Chanb6016b72005-05-26 13:03:09 -07004902 return ret;
4903}
4904
Michael Chanbc5a0692006-01-23 16:13:22 -08004905#define BNX2_MAC_LOOPBACK 0
4906#define BNX2_PHY_LOOPBACK 1
4907
Michael Chanb6016b72005-05-26 13:03:09 -07004908static int
Michael Chanbc5a0692006-01-23 16:13:22 -08004909bnx2_run_loopback(struct bnx2 *bp, int loopback_mode)
Michael Chanb6016b72005-05-26 13:03:09 -07004910{
4911 unsigned int pkt_size, num_pkts, i;
4912 struct sk_buff *skb, *rx_skb;
4913 unsigned char *packet;
Michael Chanbc5a0692006-01-23 16:13:22 -08004914 u16 rx_start_idx, rx_idx;
Michael Chanb6016b72005-05-26 13:03:09 -07004915 dma_addr_t map;
4916 struct tx_bd *txbd;
4917 struct sw_bd *rx_buf;
4918 struct l2_fhdr *rx_hdr;
4919 int ret = -ENODEV;
Michael Chan35efa7c2007-12-20 19:56:37 -08004920 struct bnx2_napi *bnapi = &bp->bnx2_napi;
Michael Chanb6016b72005-05-26 13:03:09 -07004921
Michael Chanbc5a0692006-01-23 16:13:22 -08004922 if (loopback_mode == BNX2_MAC_LOOPBACK) {
4923 bp->loopback = MAC_LOOPBACK;
4924 bnx2_set_mac_loopback(bp);
4925 }
4926 else if (loopback_mode == BNX2_PHY_LOOPBACK) {
Michael Chan489310a2007-10-10 16:16:31 -07004927 if (bp->phy_flags & REMOTE_PHY_CAP_FLAG)
4928 return 0;
4929
Michael Chan80be4432006-11-19 14:07:28 -08004930 bp->loopback = PHY_LOOPBACK;
Michael Chanbc5a0692006-01-23 16:13:22 -08004931 bnx2_set_phy_loopback(bp);
4932 }
4933 else
4934 return -EINVAL;
Michael Chanb6016b72005-05-26 13:03:09 -07004935
Michael Chan84eaa182007-12-12 11:19:57 -08004936 pkt_size = min(bp->dev->mtu + ETH_HLEN, bp->rx_jumbo_thresh - 4);
Michael Chan932f3772006-08-15 01:39:36 -07004937 skb = netdev_alloc_skb(bp->dev, pkt_size);
John W. Linvilleb6cbc3b62005-11-10 12:58:00 -08004938 if (!skb)
4939 return -ENOMEM;
Michael Chanb6016b72005-05-26 13:03:09 -07004940 packet = skb_put(skb, pkt_size);
Michael Chan66342922006-12-14 15:57:04 -08004941 memcpy(packet, bp->dev->dev_addr, 6);
Michael Chanb6016b72005-05-26 13:03:09 -07004942 memset(packet + 6, 0x0, 8);
4943 for (i = 14; i < pkt_size; i++)
4944 packet[i] = (unsigned char) (i & 0xff);
4945
4946 map = pci_map_single(bp->pdev, skb->data, pkt_size,
4947 PCI_DMA_TODEVICE);
4948
Michael Chanbf5295b2006-03-23 01:11:56 -08004949 REG_WR(bp, BNX2_HC_COMMAND,
4950 bp->hc_cmd | BNX2_HC_COMMAND_COAL_NOW_WO_INT);
4951
Michael Chanb6016b72005-05-26 13:03:09 -07004952 REG_RD(bp, BNX2_HC_COMMAND);
4953
4954 udelay(5);
Michael Chan35efa7c2007-12-20 19:56:37 -08004955 rx_start_idx = bnx2_get_hw_rx_cons(bnapi);
Michael Chanb6016b72005-05-26 13:03:09 -07004956
Michael Chanb6016b72005-05-26 13:03:09 -07004957 num_pkts = 0;
4958
Michael Chanbc5a0692006-01-23 16:13:22 -08004959 txbd = &bp->tx_desc_ring[TX_RING_IDX(bp->tx_prod)];
Michael Chanb6016b72005-05-26 13:03:09 -07004960
4961 txbd->tx_bd_haddr_hi = (u64) map >> 32;
4962 txbd->tx_bd_haddr_lo = (u64) map & 0xffffffff;
4963 txbd->tx_bd_mss_nbytes = pkt_size;
4964 txbd->tx_bd_vlan_tag_flags = TX_BD_FLAGS_START | TX_BD_FLAGS_END;
4965
4966 num_pkts++;
Michael Chanbc5a0692006-01-23 16:13:22 -08004967 bp->tx_prod = NEXT_TX_BD(bp->tx_prod);
4968 bp->tx_prod_bseq += pkt_size;
Michael Chanb6016b72005-05-26 13:03:09 -07004969
Michael Chan234754d2006-11-19 14:11:41 -08004970 REG_WR16(bp, bp->tx_bidx_addr, bp->tx_prod);
4971 REG_WR(bp, bp->tx_bseq_addr, bp->tx_prod_bseq);
Michael Chanb6016b72005-05-26 13:03:09 -07004972
4973 udelay(100);
4974
Michael Chanbf5295b2006-03-23 01:11:56 -08004975 REG_WR(bp, BNX2_HC_COMMAND,
4976 bp->hc_cmd | BNX2_HC_COMMAND_COAL_NOW_WO_INT);
4977
Michael Chanb6016b72005-05-26 13:03:09 -07004978 REG_RD(bp, BNX2_HC_COMMAND);
4979
4980 udelay(5);
4981
4982 pci_unmap_single(bp->pdev, map, pkt_size, PCI_DMA_TODEVICE);
Michael Chan745720e2006-06-29 12:37:41 -07004983 dev_kfree_skb(skb);
Michael Chanb6016b72005-05-26 13:03:09 -07004984
Michael Chan35efa7c2007-12-20 19:56:37 -08004985 if (bnx2_get_hw_tx_cons(bnapi) != bp->tx_prod)
Michael Chanb6016b72005-05-26 13:03:09 -07004986 goto loopback_test_done;
Michael Chanb6016b72005-05-26 13:03:09 -07004987
Michael Chan35efa7c2007-12-20 19:56:37 -08004988 rx_idx = bnx2_get_hw_rx_cons(bnapi);
Michael Chanb6016b72005-05-26 13:03:09 -07004989 if (rx_idx != rx_start_idx + num_pkts) {
4990 goto loopback_test_done;
4991 }
4992
4993 rx_buf = &bp->rx_buf_ring[rx_start_idx];
4994 rx_skb = rx_buf->skb;
4995
4996 rx_hdr = (struct l2_fhdr *) rx_skb->data;
4997 skb_reserve(rx_skb, bp->rx_offset);
4998
4999 pci_dma_sync_single_for_cpu(bp->pdev,
5000 pci_unmap_addr(rx_buf, mapping),
5001 bp->rx_buf_size, PCI_DMA_FROMDEVICE);
5002
Michael Chanade2bfe2006-01-23 16:09:51 -08005003 if (rx_hdr->l2_fhdr_status &
Michael Chanb6016b72005-05-26 13:03:09 -07005004 (L2_FHDR_ERRORS_BAD_CRC |
5005 L2_FHDR_ERRORS_PHY_DECODE |
5006 L2_FHDR_ERRORS_ALIGNMENT |
5007 L2_FHDR_ERRORS_TOO_SHORT |
5008 L2_FHDR_ERRORS_GIANT_FRAME)) {
5009
5010 goto loopback_test_done;
5011 }
5012
5013 if ((rx_hdr->l2_fhdr_pkt_len - 4) != pkt_size) {
5014 goto loopback_test_done;
5015 }
5016
5017 for (i = 14; i < pkt_size; i++) {
5018 if (*(rx_skb->data + i) != (unsigned char) (i & 0xff)) {
5019 goto loopback_test_done;
5020 }
5021 }
5022
5023 ret = 0;
5024
5025loopback_test_done:
5026 bp->loopback = 0;
5027 return ret;
5028}
5029
Michael Chanbc5a0692006-01-23 16:13:22 -08005030#define BNX2_MAC_LOOPBACK_FAILED 1
5031#define BNX2_PHY_LOOPBACK_FAILED 2
5032#define BNX2_LOOPBACK_FAILED (BNX2_MAC_LOOPBACK_FAILED | \
5033 BNX2_PHY_LOOPBACK_FAILED)
5034
5035static int
5036bnx2_test_loopback(struct bnx2 *bp)
5037{
5038 int rc = 0;
5039
5040 if (!netif_running(bp->dev))
5041 return BNX2_LOOPBACK_FAILED;
5042
5043 bnx2_reset_nic(bp, BNX2_DRV_MSG_CODE_RESET);
5044 spin_lock_bh(&bp->phy_lock);
5045 bnx2_init_phy(bp);
5046 spin_unlock_bh(&bp->phy_lock);
5047 if (bnx2_run_loopback(bp, BNX2_MAC_LOOPBACK))
5048 rc |= BNX2_MAC_LOOPBACK_FAILED;
5049 if (bnx2_run_loopback(bp, BNX2_PHY_LOOPBACK))
5050 rc |= BNX2_PHY_LOOPBACK_FAILED;
5051 return rc;
5052}
5053
Michael Chanb6016b72005-05-26 13:03:09 -07005054#define NVRAM_SIZE 0x200
5055#define CRC32_RESIDUAL 0xdebb20e3
5056
5057static int
5058bnx2_test_nvram(struct bnx2 *bp)
5059{
5060 u32 buf[NVRAM_SIZE / 4];
5061 u8 *data = (u8 *) buf;
5062 int rc = 0;
5063 u32 magic, csum;
5064
5065 if ((rc = bnx2_nvram_read(bp, 0, data, 4)) != 0)
5066 goto test_nvram_done;
5067
5068 magic = be32_to_cpu(buf[0]);
5069 if (magic != 0x669955aa) {
5070 rc = -ENODEV;
5071 goto test_nvram_done;
5072 }
5073
5074 if ((rc = bnx2_nvram_read(bp, 0x100, data, NVRAM_SIZE)) != 0)
5075 goto test_nvram_done;
5076
5077 csum = ether_crc_le(0x100, data);
5078 if (csum != CRC32_RESIDUAL) {
5079 rc = -ENODEV;
5080 goto test_nvram_done;
5081 }
5082
5083 csum = ether_crc_le(0x100, data + 0x100);
5084 if (csum != CRC32_RESIDUAL) {
5085 rc = -ENODEV;
5086 }
5087
5088test_nvram_done:
5089 return rc;
5090}
5091
5092static int
5093bnx2_test_link(struct bnx2 *bp)
5094{
5095 u32 bmsr;
5096
Michael Chan489310a2007-10-10 16:16:31 -07005097 if (bp->phy_flags & REMOTE_PHY_CAP_FLAG) {
5098 if (bp->link_up)
5099 return 0;
5100 return -ENODEV;
5101 }
Michael Chanc770a652005-08-25 15:38:39 -07005102 spin_lock_bh(&bp->phy_lock);
Michael Chan27a005b2007-05-03 13:23:41 -07005103 bnx2_enable_bmsr1(bp);
5104 bnx2_read_phy(bp, bp->mii_bmsr1, &bmsr);
5105 bnx2_read_phy(bp, bp->mii_bmsr1, &bmsr);
5106 bnx2_disable_bmsr1(bp);
Michael Chanc770a652005-08-25 15:38:39 -07005107 spin_unlock_bh(&bp->phy_lock);
Jeff Garzik6aa20a22006-09-13 13:24:59 -04005108
Michael Chanb6016b72005-05-26 13:03:09 -07005109 if (bmsr & BMSR_LSTATUS) {
5110 return 0;
5111 }
5112 return -ENODEV;
5113}
5114
5115static int
5116bnx2_test_intr(struct bnx2 *bp)
5117{
5118 int i;
Michael Chanb6016b72005-05-26 13:03:09 -07005119 u16 status_idx;
5120
5121 if (!netif_running(bp->dev))
5122 return -ENODEV;
5123
5124 status_idx = REG_RD(bp, BNX2_PCICFG_INT_ACK_CMD) & 0xffff;
5125
5126 /* This register is not touched during run-time. */
Michael Chanbf5295b2006-03-23 01:11:56 -08005127 REG_WR(bp, BNX2_HC_COMMAND, bp->hc_cmd | BNX2_HC_COMMAND_COAL_NOW);
Michael Chanb6016b72005-05-26 13:03:09 -07005128 REG_RD(bp, BNX2_HC_COMMAND);
5129
5130 for (i = 0; i < 10; i++) {
5131 if ((REG_RD(bp, BNX2_PCICFG_INT_ACK_CMD) & 0xffff) !=
5132 status_idx) {
5133
5134 break;
5135 }
5136
5137 msleep_interruptible(10);
5138 }
5139 if (i < 10)
5140 return 0;
5141
5142 return -ENODEV;
5143}
5144
5145static void
Michael Chan48b01e22006-11-19 14:08:00 -08005146bnx2_5706_serdes_timer(struct bnx2 *bp)
5147{
5148 spin_lock(&bp->phy_lock);
5149 if (bp->serdes_an_pending)
5150 bp->serdes_an_pending--;
5151 else if ((bp->link_up == 0) && (bp->autoneg & AUTONEG_SPEED)) {
5152 u32 bmcr;
5153
5154 bp->current_interval = bp->timer_interval;
5155
Michael Chanca58c3a2007-05-03 13:22:52 -07005156 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chan48b01e22006-11-19 14:08:00 -08005157
5158 if (bmcr & BMCR_ANENABLE) {
5159 u32 phy1, phy2;
5160
5161 bnx2_write_phy(bp, 0x1c, 0x7c00);
5162 bnx2_read_phy(bp, 0x1c, &phy1);
5163
5164 bnx2_write_phy(bp, 0x17, 0x0f01);
5165 bnx2_read_phy(bp, 0x15, &phy2);
5166 bnx2_write_phy(bp, 0x17, 0x0f01);
5167 bnx2_read_phy(bp, 0x15, &phy2);
5168
5169 if ((phy1 & 0x10) && /* SIGNAL DETECT */
5170 !(phy2 & 0x20)) { /* no CONFIG */
5171
5172 bmcr &= ~BMCR_ANENABLE;
5173 bmcr |= BMCR_SPEED1000 | BMCR_FULLDPLX;
Michael Chanca58c3a2007-05-03 13:22:52 -07005174 bnx2_write_phy(bp, bp->mii_bmcr, bmcr);
Michael Chan48b01e22006-11-19 14:08:00 -08005175 bp->phy_flags |= PHY_PARALLEL_DETECT_FLAG;
5176 }
5177 }
5178 }
5179 else if ((bp->link_up) && (bp->autoneg & AUTONEG_SPEED) &&
5180 (bp->phy_flags & PHY_PARALLEL_DETECT_FLAG)) {
5181 u32 phy2;
5182
5183 bnx2_write_phy(bp, 0x17, 0x0f01);
5184 bnx2_read_phy(bp, 0x15, &phy2);
5185 if (phy2 & 0x20) {
5186 u32 bmcr;
5187
Michael Chanca58c3a2007-05-03 13:22:52 -07005188 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chan48b01e22006-11-19 14:08:00 -08005189 bmcr |= BMCR_ANENABLE;
Michael Chanca58c3a2007-05-03 13:22:52 -07005190 bnx2_write_phy(bp, bp->mii_bmcr, bmcr);
Michael Chan48b01e22006-11-19 14:08:00 -08005191
5192 bp->phy_flags &= ~PHY_PARALLEL_DETECT_FLAG;
5193 }
5194 } else
5195 bp->current_interval = bp->timer_interval;
5196
5197 spin_unlock(&bp->phy_lock);
5198}
5199
5200static void
Michael Chanf8dd0642006-11-19 14:08:29 -08005201bnx2_5708_serdes_timer(struct bnx2 *bp)
5202{
Michael Chan0d8a6572007-07-07 22:49:43 -07005203 if (bp->phy_flags & REMOTE_PHY_CAP_FLAG)
5204 return;
5205
Michael Chanf8dd0642006-11-19 14:08:29 -08005206 if ((bp->phy_flags & PHY_2_5G_CAPABLE_FLAG) == 0) {
5207 bp->serdes_an_pending = 0;
5208 return;
5209 }
5210
5211 spin_lock(&bp->phy_lock);
5212 if (bp->serdes_an_pending)
5213 bp->serdes_an_pending--;
5214 else if ((bp->link_up == 0) && (bp->autoneg & AUTONEG_SPEED)) {
5215 u32 bmcr;
5216
Michael Chanca58c3a2007-05-03 13:22:52 -07005217 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chanf8dd0642006-11-19 14:08:29 -08005218 if (bmcr & BMCR_ANENABLE) {
Michael Chan605a9e22007-05-03 13:23:13 -07005219 bnx2_enable_forced_2g5(bp);
Michael Chanf8dd0642006-11-19 14:08:29 -08005220 bp->current_interval = SERDES_FORCED_TIMEOUT;
5221 } else {
Michael Chan605a9e22007-05-03 13:23:13 -07005222 bnx2_disable_forced_2g5(bp);
Michael Chanf8dd0642006-11-19 14:08:29 -08005223 bp->serdes_an_pending = 2;
5224 bp->current_interval = bp->timer_interval;
5225 }
5226
5227 } else
5228 bp->current_interval = bp->timer_interval;
5229
5230 spin_unlock(&bp->phy_lock);
5231}
5232
5233static void
Michael Chanb6016b72005-05-26 13:03:09 -07005234bnx2_timer(unsigned long data)
5235{
5236 struct bnx2 *bp = (struct bnx2 *) data;
Michael Chanb6016b72005-05-26 13:03:09 -07005237
Michael Chancd339a02005-08-25 15:35:24 -07005238 if (!netif_running(bp->dev))
5239 return;
5240
Michael Chanb6016b72005-05-26 13:03:09 -07005241 if (atomic_read(&bp->intr_sem) != 0)
5242 goto bnx2_restart_timer;
5243
Michael Chandf149d72007-07-07 22:51:36 -07005244 bnx2_send_heart_beat(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07005245
Michael Chancea94db2006-06-12 22:16:13 -07005246 bp->stats_blk->stat_FwRxDrop = REG_RD_IND(bp, BNX2_FW_RX_DROP_COUNT);
5247
Michael Chan02537b062007-06-04 21:24:07 -07005248 /* workaround occasional corrupted counters */
5249 if (CHIP_NUM(bp) == CHIP_NUM_5708 && bp->stats_ticks)
5250 REG_WR(bp, BNX2_HC_COMMAND, bp->hc_cmd |
5251 BNX2_HC_COMMAND_STATS_NOW);
5252
Michael Chanf8dd0642006-11-19 14:08:29 -08005253 if (bp->phy_flags & PHY_SERDES_FLAG) {
5254 if (CHIP_NUM(bp) == CHIP_NUM_5706)
5255 bnx2_5706_serdes_timer(bp);
Michael Chan27a005b2007-05-03 13:23:41 -07005256 else
Michael Chanf8dd0642006-11-19 14:08:29 -08005257 bnx2_5708_serdes_timer(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07005258 }
5259
5260bnx2_restart_timer:
Michael Chancd339a02005-08-25 15:35:24 -07005261 mod_timer(&bp->timer, jiffies + bp->current_interval);
Michael Chanb6016b72005-05-26 13:03:09 -07005262}
5263
Michael Chan8e6a72c2007-05-03 13:24:48 -07005264static int
5265bnx2_request_irq(struct bnx2 *bp)
5266{
5267 struct net_device *dev = bp->dev;
Michael Chan6d866ff2007-12-20 19:56:09 -08005268 unsigned long flags;
5269 struct bnx2_irq *irq = &bp->irq_tbl[0];
5270 int rc;
Michael Chan8e6a72c2007-05-03 13:24:48 -07005271
Michael Chan6d866ff2007-12-20 19:56:09 -08005272 if (bp->flags & USING_MSI_FLAG)
5273 flags = 0;
5274 else
5275 flags = IRQF_SHARED;
5276 rc = request_irq(irq->vector, irq->handler, flags, dev->name, dev);
Michael Chan8e6a72c2007-05-03 13:24:48 -07005277 return rc;
5278}
5279
5280static void
5281bnx2_free_irq(struct bnx2 *bp)
5282{
5283 struct net_device *dev = bp->dev;
5284
Michael Chan6d866ff2007-12-20 19:56:09 -08005285 free_irq(bp->irq_tbl[0].vector, dev);
Michael Chan8e6a72c2007-05-03 13:24:48 -07005286 if (bp->flags & USING_MSI_FLAG) {
Michael Chan8e6a72c2007-05-03 13:24:48 -07005287 pci_disable_msi(bp->pdev);
5288 bp->flags &= ~(USING_MSI_FLAG | ONE_SHOT_MSI_FLAG);
Michael Chan6d866ff2007-12-20 19:56:09 -08005289 }
5290}
5291
5292static void
5293bnx2_setup_int_mode(struct bnx2 *bp, int dis_msi)
5294{
5295 bp->irq_tbl[0].handler = bnx2_interrupt;
5296 strcpy(bp->irq_tbl[0].name, bp->dev->name);
5297
5298 if ((bp->flags & MSI_CAP_FLAG) && !dis_msi) {
5299 if (pci_enable_msi(bp->pdev) == 0) {
5300 bp->flags |= USING_MSI_FLAG;
5301 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
5302 bp->flags |= ONE_SHOT_MSI_FLAG;
5303 bp->irq_tbl[0].handler = bnx2_msi_1shot;
5304 } else
5305 bp->irq_tbl[0].handler = bnx2_msi;
5306 }
5307 }
5308
5309 bp->irq_tbl[0].vector = bp->pdev->irq;
Michael Chan8e6a72c2007-05-03 13:24:48 -07005310}
5311
Michael Chanb6016b72005-05-26 13:03:09 -07005312/* Called with rtnl_lock */
5313static int
5314bnx2_open(struct net_device *dev)
5315{
Michael Chan972ec0d2006-01-23 16:12:43 -08005316 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07005317 int rc;
5318
Michael Chan1b2f9222007-05-03 13:20:19 -07005319 netif_carrier_off(dev);
5320
Pavel Machek829ca9a2005-09-03 15:56:56 -07005321 bnx2_set_power_state(bp, PCI_D0);
Michael Chanb6016b72005-05-26 13:03:09 -07005322 bnx2_disable_int(bp);
5323
5324 rc = bnx2_alloc_mem(bp);
5325 if (rc)
5326 return rc;
5327
Michael Chan6d866ff2007-12-20 19:56:09 -08005328 bnx2_setup_int_mode(bp, disable_msi);
Michael Chan35efa7c2007-12-20 19:56:37 -08005329 bnx2_napi_enable(bp);
Michael Chan8e6a72c2007-05-03 13:24:48 -07005330 rc = bnx2_request_irq(bp);
5331
Michael Chanb6016b72005-05-26 13:03:09 -07005332 if (rc) {
Michael Chan35efa7c2007-12-20 19:56:37 -08005333 bnx2_napi_disable(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07005334 bnx2_free_mem(bp);
5335 return rc;
5336 }
5337
5338 rc = bnx2_init_nic(bp);
5339
5340 if (rc) {
Michael Chan35efa7c2007-12-20 19:56:37 -08005341 bnx2_napi_disable(bp);
Michael Chan8e6a72c2007-05-03 13:24:48 -07005342 bnx2_free_irq(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07005343 bnx2_free_skbs(bp);
5344 bnx2_free_mem(bp);
5345 return rc;
5346 }
Jeff Garzik6aa20a22006-09-13 13:24:59 -04005347
Michael Chancd339a02005-08-25 15:35:24 -07005348 mod_timer(&bp->timer, jiffies + bp->current_interval);
Michael Chanb6016b72005-05-26 13:03:09 -07005349
5350 atomic_set(&bp->intr_sem, 0);
5351
5352 bnx2_enable_int(bp);
5353
5354 if (bp->flags & USING_MSI_FLAG) {
5355 /* Test MSI to make sure it is working
5356 * If MSI test fails, go back to INTx mode
5357 */
5358 if (bnx2_test_intr(bp) != 0) {
5359 printk(KERN_WARNING PFX "%s: No interrupt was generated"
5360 " using MSI, switching to INTx mode. Please"
5361 " report this failure to the PCI maintainer"
5362 " and include system chipset information.\n",
5363 bp->dev->name);
5364
5365 bnx2_disable_int(bp);
Michael Chan8e6a72c2007-05-03 13:24:48 -07005366 bnx2_free_irq(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07005367
Michael Chan6d866ff2007-12-20 19:56:09 -08005368 bnx2_setup_int_mode(bp, 1);
5369
Michael Chanb6016b72005-05-26 13:03:09 -07005370 rc = bnx2_init_nic(bp);
5371
Michael Chan8e6a72c2007-05-03 13:24:48 -07005372 if (!rc)
5373 rc = bnx2_request_irq(bp);
5374
Michael Chanb6016b72005-05-26 13:03:09 -07005375 if (rc) {
Michael Chan35efa7c2007-12-20 19:56:37 -08005376 bnx2_napi_disable(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07005377 bnx2_free_skbs(bp);
5378 bnx2_free_mem(bp);
5379 del_timer_sync(&bp->timer);
5380 return rc;
5381 }
5382 bnx2_enable_int(bp);
5383 }
5384 }
5385 if (bp->flags & USING_MSI_FLAG) {
5386 printk(KERN_INFO PFX "%s: using MSI\n", dev->name);
5387 }
5388
5389 netif_start_queue(dev);
5390
5391 return 0;
5392}
5393
5394static void
David Howellsc4028952006-11-22 14:57:56 +00005395bnx2_reset_task(struct work_struct *work)
Michael Chanb6016b72005-05-26 13:03:09 -07005396{
David Howellsc4028952006-11-22 14:57:56 +00005397 struct bnx2 *bp = container_of(work, struct bnx2, reset_task);
Michael Chanb6016b72005-05-26 13:03:09 -07005398
Michael Chanafdc08b2005-08-25 15:34:29 -07005399 if (!netif_running(bp->dev))
5400 return;
5401
5402 bp->in_reset_task = 1;
Michael Chanb6016b72005-05-26 13:03:09 -07005403 bnx2_netif_stop(bp);
5404
5405 bnx2_init_nic(bp);
5406
5407 atomic_set(&bp->intr_sem, 1);
5408 bnx2_netif_start(bp);
Michael Chanafdc08b2005-08-25 15:34:29 -07005409 bp->in_reset_task = 0;
Michael Chanb6016b72005-05-26 13:03:09 -07005410}
5411
5412static void
5413bnx2_tx_timeout(struct net_device *dev)
5414{
Michael Chan972ec0d2006-01-23 16:12:43 -08005415 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07005416
5417 /* This allows the netif to be shutdown gracefully before resetting */
5418 schedule_work(&bp->reset_task);
5419}
5420
5421#ifdef BCM_VLAN
5422/* Called with rtnl_lock */
5423static void
5424bnx2_vlan_rx_register(struct net_device *dev, struct vlan_group *vlgrp)
5425{
Michael Chan972ec0d2006-01-23 16:12:43 -08005426 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07005427
5428 bnx2_netif_stop(bp);
5429
5430 bp->vlgrp = vlgrp;
5431 bnx2_set_rx_mode(dev);
5432
5433 bnx2_netif_start(bp);
5434}
Michael Chanb6016b72005-05-26 13:03:09 -07005435#endif
5436
Herbert Xu932ff272006-06-09 12:20:56 -07005437/* Called with netif_tx_lock.
Michael Chan2f8af122006-08-15 01:39:10 -07005438 * bnx2_tx_int() runs without netif_tx_lock unless it needs to call
5439 * netif_wake_queue().
Michael Chanb6016b72005-05-26 13:03:09 -07005440 */
5441static int
5442bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev)
5443{
Michael Chan972ec0d2006-01-23 16:12:43 -08005444 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07005445 dma_addr_t mapping;
5446 struct tx_bd *txbd;
5447 struct sw_bd *tx_buf;
5448 u32 len, vlan_tag_flags, last_frag, mss;
5449 u16 prod, ring_prod;
5450 int i;
Michael Chana550c992007-12-20 19:56:59 -08005451 struct bnx2_napi *bnapi = &bp->bnx2_napi;
Michael Chanb6016b72005-05-26 13:03:09 -07005452
Michael Chana550c992007-12-20 19:56:59 -08005453 if (unlikely(bnx2_tx_avail(bp, bnapi) <
5454 (skb_shinfo(skb)->nr_frags + 1))) {
Michael Chanb6016b72005-05-26 13:03:09 -07005455 netif_stop_queue(dev);
5456 printk(KERN_ERR PFX "%s: BUG! Tx ring full when queue awake!\n",
5457 dev->name);
5458
5459 return NETDEV_TX_BUSY;
5460 }
5461 len = skb_headlen(skb);
5462 prod = bp->tx_prod;
5463 ring_prod = TX_RING_IDX(prod);
5464
5465 vlan_tag_flags = 0;
Patrick McHardy84fa7932006-08-29 16:44:56 -07005466 if (skb->ip_summed == CHECKSUM_PARTIAL) {
Michael Chanb6016b72005-05-26 13:03:09 -07005467 vlan_tag_flags |= TX_BD_FLAGS_TCP_UDP_CKSUM;
5468 }
5469
5470 if (bp->vlgrp != 0 && vlan_tx_tag_present(skb)) {
5471 vlan_tag_flags |=
5472 (TX_BD_FLAGS_VLAN_TAG | (vlan_tx_tag_get(skb) << 16));
5473 }
Michael Chanfde82052007-05-03 17:23:35 -07005474 if ((mss = skb_shinfo(skb)->gso_size)) {
Michael Chanb6016b72005-05-26 13:03:09 -07005475 u32 tcp_opt_len, ip_tcp_len;
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -07005476 struct iphdr *iph;
Michael Chanb6016b72005-05-26 13:03:09 -07005477
Michael Chanb6016b72005-05-26 13:03:09 -07005478 vlan_tag_flags |= TX_BD_FLAGS_SW_LSO;
5479
Michael Chan4666f872007-05-03 13:22:28 -07005480 tcp_opt_len = tcp_optlen(skb);
Arnaldo Carvalho de Meloab6a5bb2007-03-18 17:43:48 -07005481
Michael Chan4666f872007-05-03 13:22:28 -07005482 if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6) {
5483 u32 tcp_off = skb_transport_offset(skb) -
5484 sizeof(struct ipv6hdr) - ETH_HLEN;
Michael Chanb6016b72005-05-26 13:03:09 -07005485
Michael Chan4666f872007-05-03 13:22:28 -07005486 vlan_tag_flags |= ((tcp_opt_len >> 2) << 8) |
5487 TX_BD_FLAGS_SW_FLAGS;
5488 if (likely(tcp_off == 0))
5489 vlan_tag_flags &= ~TX_BD_FLAGS_TCP6_OFF0_MSK;
5490 else {
5491 tcp_off >>= 3;
5492 vlan_tag_flags |= ((tcp_off & 0x3) <<
5493 TX_BD_FLAGS_TCP6_OFF0_SHL) |
5494 ((tcp_off & 0x10) <<
5495 TX_BD_FLAGS_TCP6_OFF4_SHL);
5496 mss |= (tcp_off & 0xc) << TX_BD_TCP6_OFF2_SHL;
5497 }
5498 } else {
5499 if (skb_header_cloned(skb) &&
5500 pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) {
5501 dev_kfree_skb(skb);
5502 return NETDEV_TX_OK;
5503 }
5504
5505 ip_tcp_len = ip_hdrlen(skb) + sizeof(struct tcphdr);
5506
5507 iph = ip_hdr(skb);
5508 iph->check = 0;
5509 iph->tot_len = htons(mss + ip_tcp_len + tcp_opt_len);
5510 tcp_hdr(skb)->check = ~csum_tcpudp_magic(iph->saddr,
5511 iph->daddr, 0,
5512 IPPROTO_TCP,
5513 0);
5514 if (tcp_opt_len || (iph->ihl > 5)) {
5515 vlan_tag_flags |= ((iph->ihl - 5) +
5516 (tcp_opt_len >> 2)) << 8;
5517 }
Michael Chanb6016b72005-05-26 13:03:09 -07005518 }
Michael Chan4666f872007-05-03 13:22:28 -07005519 } else
Michael Chanb6016b72005-05-26 13:03:09 -07005520 mss = 0;
Michael Chanb6016b72005-05-26 13:03:09 -07005521
5522 mapping = pci_map_single(bp->pdev, skb->data, len, PCI_DMA_TODEVICE);
Jeff Garzik6aa20a22006-09-13 13:24:59 -04005523
Michael Chanb6016b72005-05-26 13:03:09 -07005524 tx_buf = &bp->tx_buf_ring[ring_prod];
5525 tx_buf->skb = skb;
5526 pci_unmap_addr_set(tx_buf, mapping, mapping);
5527
5528 txbd = &bp->tx_desc_ring[ring_prod];
5529
5530 txbd->tx_bd_haddr_hi = (u64) mapping >> 32;
5531 txbd->tx_bd_haddr_lo = (u64) mapping & 0xffffffff;
5532 txbd->tx_bd_mss_nbytes = len | (mss << 16);
5533 txbd->tx_bd_vlan_tag_flags = vlan_tag_flags | TX_BD_FLAGS_START;
5534
5535 last_frag = skb_shinfo(skb)->nr_frags;
5536
5537 for (i = 0; i < last_frag; i++) {
5538 skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
5539
5540 prod = NEXT_TX_BD(prod);
5541 ring_prod = TX_RING_IDX(prod);
5542 txbd = &bp->tx_desc_ring[ring_prod];
5543
5544 len = frag->size;
5545 mapping = pci_map_page(bp->pdev, frag->page, frag->page_offset,
5546 len, PCI_DMA_TODEVICE);
5547 pci_unmap_addr_set(&bp->tx_buf_ring[ring_prod],
5548 mapping, mapping);
5549
5550 txbd->tx_bd_haddr_hi = (u64) mapping >> 32;
5551 txbd->tx_bd_haddr_lo = (u64) mapping & 0xffffffff;
5552 txbd->tx_bd_mss_nbytes = len | (mss << 16);
5553 txbd->tx_bd_vlan_tag_flags = vlan_tag_flags;
5554
5555 }
5556 txbd->tx_bd_vlan_tag_flags |= TX_BD_FLAGS_END;
5557
5558 prod = NEXT_TX_BD(prod);
5559 bp->tx_prod_bseq += skb->len;
5560
Michael Chan234754d2006-11-19 14:11:41 -08005561 REG_WR16(bp, bp->tx_bidx_addr, prod);
5562 REG_WR(bp, bp->tx_bseq_addr, bp->tx_prod_bseq);
Michael Chanb6016b72005-05-26 13:03:09 -07005563
5564 mmiowb();
5565
5566 bp->tx_prod = prod;
5567 dev->trans_start = jiffies;
5568
Michael Chana550c992007-12-20 19:56:59 -08005569 if (unlikely(bnx2_tx_avail(bp, bnapi) <= MAX_SKB_FRAGS)) {
Michael Chane89bbf12005-08-25 15:36:58 -07005570 netif_stop_queue(dev);
Michael Chana550c992007-12-20 19:56:59 -08005571 if (bnx2_tx_avail(bp, bnapi) > bp->tx_wake_thresh)
Michael Chane89bbf12005-08-25 15:36:58 -07005572 netif_wake_queue(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07005573 }
5574
5575 return NETDEV_TX_OK;
5576}
5577
5578/* Called with rtnl_lock */
5579static int
5580bnx2_close(struct net_device *dev)
5581{
Michael Chan972ec0d2006-01-23 16:12:43 -08005582 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07005583 u32 reset_code;
5584
Michael Chanafdc08b2005-08-25 15:34:29 -07005585 /* Calling flush_scheduled_work() may deadlock because
5586 * linkwatch_event() may be on the workqueue and it will try to get
5587 * the rtnl_lock which we are holding.
5588 */
5589 while (bp->in_reset_task)
5590 msleep(1);
5591
Stephen Hemmingerbea33482007-10-03 16:41:36 -07005592 bnx2_disable_int_sync(bp);
Michael Chan35efa7c2007-12-20 19:56:37 -08005593 bnx2_napi_disable(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07005594 del_timer_sync(&bp->timer);
Michael Chandda1e392006-01-23 16:08:14 -08005595 if (bp->flags & NO_WOL_FLAG)
Michael Chan6c4f0952006-06-29 12:38:15 -07005596 reset_code = BNX2_DRV_MSG_CODE_UNLOAD_LNK_DN;
Michael Chandda1e392006-01-23 16:08:14 -08005597 else if (bp->wol)
Michael Chanb6016b72005-05-26 13:03:09 -07005598 reset_code = BNX2_DRV_MSG_CODE_SUSPEND_WOL;
5599 else
5600 reset_code = BNX2_DRV_MSG_CODE_SUSPEND_NO_WOL;
5601 bnx2_reset_chip(bp, reset_code);
Michael Chan8e6a72c2007-05-03 13:24:48 -07005602 bnx2_free_irq(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07005603 bnx2_free_skbs(bp);
5604 bnx2_free_mem(bp);
5605 bp->link_up = 0;
5606 netif_carrier_off(bp->dev);
Pavel Machek829ca9a2005-09-03 15:56:56 -07005607 bnx2_set_power_state(bp, PCI_D3hot);
Michael Chanb6016b72005-05-26 13:03:09 -07005608 return 0;
5609}
5610
5611#define GET_NET_STATS64(ctr) \
5612 (unsigned long) ((unsigned long) (ctr##_hi) << 32) + \
5613 (unsigned long) (ctr##_lo)
5614
5615#define GET_NET_STATS32(ctr) \
5616 (ctr##_lo)
5617
5618#if (BITS_PER_LONG == 64)
5619#define GET_NET_STATS GET_NET_STATS64
5620#else
5621#define GET_NET_STATS GET_NET_STATS32
5622#endif
5623
5624static struct net_device_stats *
5625bnx2_get_stats(struct net_device *dev)
5626{
Michael Chan972ec0d2006-01-23 16:12:43 -08005627 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07005628 struct statistics_block *stats_blk = bp->stats_blk;
5629 struct net_device_stats *net_stats = &bp->net_stats;
5630
5631 if (bp->stats_blk == NULL) {
5632 return net_stats;
5633 }
5634 net_stats->rx_packets =
5635 GET_NET_STATS(stats_blk->stat_IfHCInUcastPkts) +
5636 GET_NET_STATS(stats_blk->stat_IfHCInMulticastPkts) +
5637 GET_NET_STATS(stats_blk->stat_IfHCInBroadcastPkts);
5638
5639 net_stats->tx_packets =
5640 GET_NET_STATS(stats_blk->stat_IfHCOutUcastPkts) +
5641 GET_NET_STATS(stats_blk->stat_IfHCOutMulticastPkts) +
5642 GET_NET_STATS(stats_blk->stat_IfHCOutBroadcastPkts);
5643
5644 net_stats->rx_bytes =
5645 GET_NET_STATS(stats_blk->stat_IfHCInOctets);
5646
5647 net_stats->tx_bytes =
5648 GET_NET_STATS(stats_blk->stat_IfHCOutOctets);
5649
Jeff Garzik6aa20a22006-09-13 13:24:59 -04005650 net_stats->multicast =
Michael Chanb6016b72005-05-26 13:03:09 -07005651 GET_NET_STATS(stats_blk->stat_IfHCOutMulticastPkts);
5652
Jeff Garzik6aa20a22006-09-13 13:24:59 -04005653 net_stats->collisions =
Michael Chanb6016b72005-05-26 13:03:09 -07005654 (unsigned long) stats_blk->stat_EtherStatsCollisions;
5655
Jeff Garzik6aa20a22006-09-13 13:24:59 -04005656 net_stats->rx_length_errors =
Michael Chanb6016b72005-05-26 13:03:09 -07005657 (unsigned long) (stats_blk->stat_EtherStatsUndersizePkts +
5658 stats_blk->stat_EtherStatsOverrsizePkts);
5659
Jeff Garzik6aa20a22006-09-13 13:24:59 -04005660 net_stats->rx_over_errors =
Michael Chanb6016b72005-05-26 13:03:09 -07005661 (unsigned long) stats_blk->stat_IfInMBUFDiscards;
5662
Jeff Garzik6aa20a22006-09-13 13:24:59 -04005663 net_stats->rx_frame_errors =
Michael Chanb6016b72005-05-26 13:03:09 -07005664 (unsigned long) stats_blk->stat_Dot3StatsAlignmentErrors;
5665
Jeff Garzik6aa20a22006-09-13 13:24:59 -04005666 net_stats->rx_crc_errors =
Michael Chanb6016b72005-05-26 13:03:09 -07005667 (unsigned long) stats_blk->stat_Dot3StatsFCSErrors;
5668
5669 net_stats->rx_errors = net_stats->rx_length_errors +
5670 net_stats->rx_over_errors + net_stats->rx_frame_errors +
5671 net_stats->rx_crc_errors;
5672
5673 net_stats->tx_aborted_errors =
5674 (unsigned long) (stats_blk->stat_Dot3StatsExcessiveCollisions +
5675 stats_blk->stat_Dot3StatsLateCollisions);
5676
Michael Chan5b0c76a2005-11-04 08:45:49 -08005677 if ((CHIP_NUM(bp) == CHIP_NUM_5706) ||
5678 (CHIP_ID(bp) == CHIP_ID_5708_A0))
Michael Chanb6016b72005-05-26 13:03:09 -07005679 net_stats->tx_carrier_errors = 0;
5680 else {
5681 net_stats->tx_carrier_errors =
5682 (unsigned long)
5683 stats_blk->stat_Dot3StatsCarrierSenseErrors;
5684 }
5685
5686 net_stats->tx_errors =
Jeff Garzik6aa20a22006-09-13 13:24:59 -04005687 (unsigned long)
Michael Chanb6016b72005-05-26 13:03:09 -07005688 stats_blk->stat_emac_tx_stat_dot3statsinternalmactransmiterrors
5689 +
5690 net_stats->tx_aborted_errors +
5691 net_stats->tx_carrier_errors;
5692
Michael Chancea94db2006-06-12 22:16:13 -07005693 net_stats->rx_missed_errors =
5694 (unsigned long) (stats_blk->stat_IfInMBUFDiscards +
5695 stats_blk->stat_FwRxDrop);
5696
Michael Chanb6016b72005-05-26 13:03:09 -07005697 return net_stats;
5698}
5699
5700/* All ethtool functions called with rtnl_lock */
5701
5702static int
5703bnx2_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
5704{
Michael Chan972ec0d2006-01-23 16:12:43 -08005705 struct bnx2 *bp = netdev_priv(dev);
Michael Chan7b6b8342007-07-07 22:50:15 -07005706 int support_serdes = 0, support_copper = 0;
Michael Chanb6016b72005-05-26 13:03:09 -07005707
5708 cmd->supported = SUPPORTED_Autoneg;
Michael Chan7b6b8342007-07-07 22:50:15 -07005709 if (bp->phy_flags & REMOTE_PHY_CAP_FLAG) {
5710 support_serdes = 1;
5711 support_copper = 1;
5712 } else if (bp->phy_port == PORT_FIBRE)
5713 support_serdes = 1;
5714 else
5715 support_copper = 1;
5716
5717 if (support_serdes) {
Michael Chanb6016b72005-05-26 13:03:09 -07005718 cmd->supported |= SUPPORTED_1000baseT_Full |
5719 SUPPORTED_FIBRE;
Michael Chan605a9e22007-05-03 13:23:13 -07005720 if (bp->phy_flags & PHY_2_5G_CAPABLE_FLAG)
5721 cmd->supported |= SUPPORTED_2500baseX_Full;
Michael Chanb6016b72005-05-26 13:03:09 -07005722
Michael Chanb6016b72005-05-26 13:03:09 -07005723 }
Michael Chan7b6b8342007-07-07 22:50:15 -07005724 if (support_copper) {
Michael Chanb6016b72005-05-26 13:03:09 -07005725 cmd->supported |= SUPPORTED_10baseT_Half |
5726 SUPPORTED_10baseT_Full |
5727 SUPPORTED_100baseT_Half |
5728 SUPPORTED_100baseT_Full |
5729 SUPPORTED_1000baseT_Full |
5730 SUPPORTED_TP;
5731
Michael Chanb6016b72005-05-26 13:03:09 -07005732 }
5733
Michael Chan7b6b8342007-07-07 22:50:15 -07005734 spin_lock_bh(&bp->phy_lock);
5735 cmd->port = bp->phy_port;
Michael Chanb6016b72005-05-26 13:03:09 -07005736 cmd->advertising = bp->advertising;
5737
5738 if (bp->autoneg & AUTONEG_SPEED) {
5739 cmd->autoneg = AUTONEG_ENABLE;
5740 }
5741 else {
5742 cmd->autoneg = AUTONEG_DISABLE;
5743 }
5744
5745 if (netif_carrier_ok(dev)) {
5746 cmd->speed = bp->line_speed;
5747 cmd->duplex = bp->duplex;
5748 }
5749 else {
5750 cmd->speed = -1;
5751 cmd->duplex = -1;
5752 }
Michael Chan7b6b8342007-07-07 22:50:15 -07005753 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07005754
5755 cmd->transceiver = XCVR_INTERNAL;
5756 cmd->phy_address = bp->phy_addr;
5757
5758 return 0;
5759}
Jeff Garzik6aa20a22006-09-13 13:24:59 -04005760
Michael Chanb6016b72005-05-26 13:03:09 -07005761static int
5762bnx2_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
5763{
Michael Chan972ec0d2006-01-23 16:12:43 -08005764 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07005765 u8 autoneg = bp->autoneg;
5766 u8 req_duplex = bp->req_duplex;
5767 u16 req_line_speed = bp->req_line_speed;
5768 u32 advertising = bp->advertising;
Michael Chan7b6b8342007-07-07 22:50:15 -07005769 int err = -EINVAL;
5770
5771 spin_lock_bh(&bp->phy_lock);
5772
5773 if (cmd->port != PORT_TP && cmd->port != PORT_FIBRE)
5774 goto err_out_unlock;
5775
5776 if (cmd->port != bp->phy_port && !(bp->phy_flags & REMOTE_PHY_CAP_FLAG))
5777 goto err_out_unlock;
Michael Chanb6016b72005-05-26 13:03:09 -07005778
5779 if (cmd->autoneg == AUTONEG_ENABLE) {
5780 autoneg |= AUTONEG_SPEED;
5781
Jeff Garzik6aa20a22006-09-13 13:24:59 -04005782 cmd->advertising &= ETHTOOL_ALL_COPPER_SPEED;
Michael Chanb6016b72005-05-26 13:03:09 -07005783
5784 /* allow advertising 1 speed */
5785 if ((cmd->advertising == ADVERTISED_10baseT_Half) ||
5786 (cmd->advertising == ADVERTISED_10baseT_Full) ||
5787 (cmd->advertising == ADVERTISED_100baseT_Half) ||
5788 (cmd->advertising == ADVERTISED_100baseT_Full)) {
5789
Michael Chan7b6b8342007-07-07 22:50:15 -07005790 if (cmd->port == PORT_FIBRE)
5791 goto err_out_unlock;
Michael Chanb6016b72005-05-26 13:03:09 -07005792
5793 advertising = cmd->advertising;
5794
Michael Chan27a005b2007-05-03 13:23:41 -07005795 } else if (cmd->advertising == ADVERTISED_2500baseX_Full) {
Michael Chan7b6b8342007-07-07 22:50:15 -07005796 if (!(bp->phy_flags & PHY_2_5G_CAPABLE_FLAG) ||
5797 (cmd->port == PORT_TP))
5798 goto err_out_unlock;
5799 } else if (cmd->advertising == ADVERTISED_1000baseT_Full)
Michael Chanb6016b72005-05-26 13:03:09 -07005800 advertising = cmd->advertising;
Michael Chan7b6b8342007-07-07 22:50:15 -07005801 else if (cmd->advertising == ADVERTISED_1000baseT_Half)
5802 goto err_out_unlock;
Michael Chanb6016b72005-05-26 13:03:09 -07005803 else {
Michael Chan7b6b8342007-07-07 22:50:15 -07005804 if (cmd->port == PORT_FIBRE)
Michael Chanb6016b72005-05-26 13:03:09 -07005805 advertising = ETHTOOL_ALL_FIBRE_SPEED;
Michael Chan7b6b8342007-07-07 22:50:15 -07005806 else
Michael Chanb6016b72005-05-26 13:03:09 -07005807 advertising = ETHTOOL_ALL_COPPER_SPEED;
Michael Chanb6016b72005-05-26 13:03:09 -07005808 }
5809 advertising |= ADVERTISED_Autoneg;
5810 }
5811 else {
Michael Chan7b6b8342007-07-07 22:50:15 -07005812 if (cmd->port == PORT_FIBRE) {
Michael Chan80be4432006-11-19 14:07:28 -08005813 if ((cmd->speed != SPEED_1000 &&
5814 cmd->speed != SPEED_2500) ||
5815 (cmd->duplex != DUPLEX_FULL))
Michael Chan7b6b8342007-07-07 22:50:15 -07005816 goto err_out_unlock;
Michael Chan80be4432006-11-19 14:07:28 -08005817
5818 if (cmd->speed == SPEED_2500 &&
5819 !(bp->phy_flags & PHY_2_5G_CAPABLE_FLAG))
Michael Chan7b6b8342007-07-07 22:50:15 -07005820 goto err_out_unlock;
Michael Chanb6016b72005-05-26 13:03:09 -07005821 }
Michael Chan7b6b8342007-07-07 22:50:15 -07005822 else if (cmd->speed == SPEED_1000 || cmd->speed == SPEED_2500)
5823 goto err_out_unlock;
5824
Michael Chanb6016b72005-05-26 13:03:09 -07005825 autoneg &= ~AUTONEG_SPEED;
5826 req_line_speed = cmd->speed;
5827 req_duplex = cmd->duplex;
5828 advertising = 0;
5829 }
5830
5831 bp->autoneg = autoneg;
5832 bp->advertising = advertising;
5833 bp->req_line_speed = req_line_speed;
5834 bp->req_duplex = req_duplex;
5835
Michael Chan7b6b8342007-07-07 22:50:15 -07005836 err = bnx2_setup_phy(bp, cmd->port);
Michael Chanb6016b72005-05-26 13:03:09 -07005837
Michael Chan7b6b8342007-07-07 22:50:15 -07005838err_out_unlock:
Michael Chanc770a652005-08-25 15:38:39 -07005839 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07005840
Michael Chan7b6b8342007-07-07 22:50:15 -07005841 return err;
Michael Chanb6016b72005-05-26 13:03:09 -07005842}
5843
5844static void
5845bnx2_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
5846{
Michael Chan972ec0d2006-01-23 16:12:43 -08005847 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07005848
5849 strcpy(info->driver, DRV_MODULE_NAME);
5850 strcpy(info->version, DRV_MODULE_VERSION);
5851 strcpy(info->bus_info, pci_name(bp->pdev));
Michael Chan58fc2ea2007-07-07 22:52:02 -07005852 strcpy(info->fw_version, bp->fw_version);
Michael Chanb6016b72005-05-26 13:03:09 -07005853}
5854
Michael Chan244ac4f2006-03-20 17:48:46 -08005855#define BNX2_REGDUMP_LEN (32 * 1024)
5856
5857static int
5858bnx2_get_regs_len(struct net_device *dev)
5859{
5860 return BNX2_REGDUMP_LEN;
5861}
5862
5863static void
5864bnx2_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *_p)
5865{
5866 u32 *p = _p, i, offset;
5867 u8 *orig_p = _p;
5868 struct bnx2 *bp = netdev_priv(dev);
5869 u32 reg_boundaries[] = { 0x0000, 0x0098, 0x0400, 0x045c,
5870 0x0800, 0x0880, 0x0c00, 0x0c10,
5871 0x0c30, 0x0d08, 0x1000, 0x101c,
5872 0x1040, 0x1048, 0x1080, 0x10a4,
5873 0x1400, 0x1490, 0x1498, 0x14f0,
5874 0x1500, 0x155c, 0x1580, 0x15dc,
5875 0x1600, 0x1658, 0x1680, 0x16d8,
5876 0x1800, 0x1820, 0x1840, 0x1854,
5877 0x1880, 0x1894, 0x1900, 0x1984,
5878 0x1c00, 0x1c0c, 0x1c40, 0x1c54,
5879 0x1c80, 0x1c94, 0x1d00, 0x1d84,
5880 0x2000, 0x2030, 0x23c0, 0x2400,
5881 0x2800, 0x2820, 0x2830, 0x2850,
5882 0x2b40, 0x2c10, 0x2fc0, 0x3058,
5883 0x3c00, 0x3c94, 0x4000, 0x4010,
5884 0x4080, 0x4090, 0x43c0, 0x4458,
5885 0x4c00, 0x4c18, 0x4c40, 0x4c54,
5886 0x4fc0, 0x5010, 0x53c0, 0x5444,
5887 0x5c00, 0x5c18, 0x5c80, 0x5c90,
5888 0x5fc0, 0x6000, 0x6400, 0x6428,
5889 0x6800, 0x6848, 0x684c, 0x6860,
5890 0x6888, 0x6910, 0x8000 };
5891
5892 regs->version = 0;
5893
5894 memset(p, 0, BNX2_REGDUMP_LEN);
5895
5896 if (!netif_running(bp->dev))
5897 return;
5898
5899 i = 0;
5900 offset = reg_boundaries[0];
5901 p += offset;
5902 while (offset < BNX2_REGDUMP_LEN) {
5903 *p++ = REG_RD(bp, offset);
5904 offset += 4;
5905 if (offset == reg_boundaries[i + 1]) {
5906 offset = reg_boundaries[i + 2];
5907 p = (u32 *) (orig_p + offset);
5908 i += 2;
5909 }
5910 }
5911}
5912
Michael Chanb6016b72005-05-26 13:03:09 -07005913static void
5914bnx2_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
5915{
Michael Chan972ec0d2006-01-23 16:12:43 -08005916 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07005917
5918 if (bp->flags & NO_WOL_FLAG) {
5919 wol->supported = 0;
5920 wol->wolopts = 0;
5921 }
5922 else {
5923 wol->supported = WAKE_MAGIC;
5924 if (bp->wol)
5925 wol->wolopts = WAKE_MAGIC;
5926 else
5927 wol->wolopts = 0;
5928 }
5929 memset(&wol->sopass, 0, sizeof(wol->sopass));
5930}
5931
5932static int
5933bnx2_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
5934{
Michael Chan972ec0d2006-01-23 16:12:43 -08005935 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07005936
5937 if (wol->wolopts & ~WAKE_MAGIC)
5938 return -EINVAL;
5939
5940 if (wol->wolopts & WAKE_MAGIC) {
5941 if (bp->flags & NO_WOL_FLAG)
5942 return -EINVAL;
5943
5944 bp->wol = 1;
5945 }
5946 else {
5947 bp->wol = 0;
5948 }
5949 return 0;
5950}
5951
5952static int
5953bnx2_nway_reset(struct net_device *dev)
5954{
Michael Chan972ec0d2006-01-23 16:12:43 -08005955 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07005956 u32 bmcr;
5957
5958 if (!(bp->autoneg & AUTONEG_SPEED)) {
5959 return -EINVAL;
5960 }
5961
Michael Chanc770a652005-08-25 15:38:39 -07005962 spin_lock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07005963
Michael Chan7b6b8342007-07-07 22:50:15 -07005964 if (bp->phy_flags & REMOTE_PHY_CAP_FLAG) {
5965 int rc;
5966
5967 rc = bnx2_setup_remote_phy(bp, bp->phy_port);
5968 spin_unlock_bh(&bp->phy_lock);
5969 return rc;
5970 }
5971
Michael Chanb6016b72005-05-26 13:03:09 -07005972 /* Force a link down visible on the other side */
5973 if (bp->phy_flags & PHY_SERDES_FLAG) {
Michael Chanca58c3a2007-05-03 13:22:52 -07005974 bnx2_write_phy(bp, bp->mii_bmcr, BMCR_LOOPBACK);
Michael Chanc770a652005-08-25 15:38:39 -07005975 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07005976
5977 msleep(20);
5978
Michael Chanc770a652005-08-25 15:38:39 -07005979 spin_lock_bh(&bp->phy_lock);
Michael Chanf8dd0642006-11-19 14:08:29 -08005980
5981 bp->current_interval = SERDES_AN_TIMEOUT;
5982 bp->serdes_an_pending = 1;
5983 mod_timer(&bp->timer, jiffies + bp->current_interval);
Michael Chanb6016b72005-05-26 13:03:09 -07005984 }
5985
Michael Chanca58c3a2007-05-03 13:22:52 -07005986 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chanb6016b72005-05-26 13:03:09 -07005987 bmcr &= ~BMCR_LOOPBACK;
Michael Chanca58c3a2007-05-03 13:22:52 -07005988 bnx2_write_phy(bp, bp->mii_bmcr, bmcr | BMCR_ANRESTART | BMCR_ANENABLE);
Michael Chanb6016b72005-05-26 13:03:09 -07005989
Michael Chanc770a652005-08-25 15:38:39 -07005990 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07005991
5992 return 0;
5993}
5994
5995static int
5996bnx2_get_eeprom_len(struct net_device *dev)
5997{
Michael Chan972ec0d2006-01-23 16:12:43 -08005998 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07005999
Michael Chan1122db72006-01-23 16:11:42 -08006000 if (bp->flash_info == NULL)
Michael Chanb6016b72005-05-26 13:03:09 -07006001 return 0;
6002
Michael Chan1122db72006-01-23 16:11:42 -08006003 return (int) bp->flash_size;
Michael Chanb6016b72005-05-26 13:03:09 -07006004}
6005
6006static int
6007bnx2_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
6008 u8 *eebuf)
6009{
Michael Chan972ec0d2006-01-23 16:12:43 -08006010 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006011 int rc;
6012
John W. Linville1064e942005-11-10 12:58:24 -08006013 /* parameters already validated in ethtool_get_eeprom */
Michael Chanb6016b72005-05-26 13:03:09 -07006014
6015 rc = bnx2_nvram_read(bp, eeprom->offset, eebuf, eeprom->len);
6016
6017 return rc;
6018}
6019
6020static int
6021bnx2_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
6022 u8 *eebuf)
6023{
Michael Chan972ec0d2006-01-23 16:12:43 -08006024 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006025 int rc;
6026
John W. Linville1064e942005-11-10 12:58:24 -08006027 /* parameters already validated in ethtool_set_eeprom */
Michael Chanb6016b72005-05-26 13:03:09 -07006028
6029 rc = bnx2_nvram_write(bp, eeprom->offset, eebuf, eeprom->len);
6030
6031 return rc;
6032}
6033
6034static int
6035bnx2_get_coalesce(struct net_device *dev, struct ethtool_coalesce *coal)
6036{
Michael Chan972ec0d2006-01-23 16:12:43 -08006037 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006038
6039 memset(coal, 0, sizeof(struct ethtool_coalesce));
6040
6041 coal->rx_coalesce_usecs = bp->rx_ticks;
6042 coal->rx_max_coalesced_frames = bp->rx_quick_cons_trip;
6043 coal->rx_coalesce_usecs_irq = bp->rx_ticks_int;
6044 coal->rx_max_coalesced_frames_irq = bp->rx_quick_cons_trip_int;
6045
6046 coal->tx_coalesce_usecs = bp->tx_ticks;
6047 coal->tx_max_coalesced_frames = bp->tx_quick_cons_trip;
6048 coal->tx_coalesce_usecs_irq = bp->tx_ticks_int;
6049 coal->tx_max_coalesced_frames_irq = bp->tx_quick_cons_trip_int;
6050
6051 coal->stats_block_coalesce_usecs = bp->stats_ticks;
6052
6053 return 0;
6054}
6055
6056static int
6057bnx2_set_coalesce(struct net_device *dev, struct ethtool_coalesce *coal)
6058{
Michael Chan972ec0d2006-01-23 16:12:43 -08006059 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006060
6061 bp->rx_ticks = (u16) coal->rx_coalesce_usecs;
6062 if (bp->rx_ticks > 0x3ff) bp->rx_ticks = 0x3ff;
6063
Jeff Garzik6aa20a22006-09-13 13:24:59 -04006064 bp->rx_quick_cons_trip = (u16) coal->rx_max_coalesced_frames;
Michael Chanb6016b72005-05-26 13:03:09 -07006065 if (bp->rx_quick_cons_trip > 0xff) bp->rx_quick_cons_trip = 0xff;
6066
6067 bp->rx_ticks_int = (u16) coal->rx_coalesce_usecs_irq;
6068 if (bp->rx_ticks_int > 0x3ff) bp->rx_ticks_int = 0x3ff;
6069
6070 bp->rx_quick_cons_trip_int = (u16) coal->rx_max_coalesced_frames_irq;
6071 if (bp->rx_quick_cons_trip_int > 0xff)
6072 bp->rx_quick_cons_trip_int = 0xff;
6073
6074 bp->tx_ticks = (u16) coal->tx_coalesce_usecs;
6075 if (bp->tx_ticks > 0x3ff) bp->tx_ticks = 0x3ff;
6076
6077 bp->tx_quick_cons_trip = (u16) coal->tx_max_coalesced_frames;
6078 if (bp->tx_quick_cons_trip > 0xff) bp->tx_quick_cons_trip = 0xff;
6079
6080 bp->tx_ticks_int = (u16) coal->tx_coalesce_usecs_irq;
6081 if (bp->tx_ticks_int > 0x3ff) bp->tx_ticks_int = 0x3ff;
6082
6083 bp->tx_quick_cons_trip_int = (u16) coal->tx_max_coalesced_frames_irq;
6084 if (bp->tx_quick_cons_trip_int > 0xff) bp->tx_quick_cons_trip_int =
6085 0xff;
6086
6087 bp->stats_ticks = coal->stats_block_coalesce_usecs;
Michael Chan02537b062007-06-04 21:24:07 -07006088 if (CHIP_NUM(bp) == CHIP_NUM_5708) {
6089 if (bp->stats_ticks != 0 && bp->stats_ticks != USEC_PER_SEC)
6090 bp->stats_ticks = USEC_PER_SEC;
6091 }
Michael Chan7ea69202007-07-16 18:27:10 -07006092 if (bp->stats_ticks > BNX2_HC_STATS_TICKS_HC_STAT_TICKS)
6093 bp->stats_ticks = BNX2_HC_STATS_TICKS_HC_STAT_TICKS;
6094 bp->stats_ticks &= BNX2_HC_STATS_TICKS_HC_STAT_TICKS;
Michael Chanb6016b72005-05-26 13:03:09 -07006095
6096 if (netif_running(bp->dev)) {
6097 bnx2_netif_stop(bp);
6098 bnx2_init_nic(bp);
6099 bnx2_netif_start(bp);
6100 }
6101
6102 return 0;
6103}
6104
6105static void
6106bnx2_get_ringparam(struct net_device *dev, struct ethtool_ringparam *ering)
6107{
Michael Chan972ec0d2006-01-23 16:12:43 -08006108 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006109
Michael Chan13daffa2006-03-20 17:49:20 -08006110 ering->rx_max_pending = MAX_TOTAL_RX_DESC_CNT;
Michael Chanb6016b72005-05-26 13:03:09 -07006111 ering->rx_mini_max_pending = 0;
Michael Chan47bf4242007-12-12 11:19:12 -08006112 ering->rx_jumbo_max_pending = MAX_TOTAL_RX_PG_DESC_CNT;
Michael Chanb6016b72005-05-26 13:03:09 -07006113
6114 ering->rx_pending = bp->rx_ring_size;
6115 ering->rx_mini_pending = 0;
Michael Chan47bf4242007-12-12 11:19:12 -08006116 ering->rx_jumbo_pending = bp->rx_pg_ring_size;
Michael Chanb6016b72005-05-26 13:03:09 -07006117
6118 ering->tx_max_pending = MAX_TX_DESC_CNT;
6119 ering->tx_pending = bp->tx_ring_size;
6120}
6121
6122static int
Michael Chan5d5d0012007-12-12 11:17:43 -08006123bnx2_change_ring_size(struct bnx2 *bp, u32 rx, u32 tx)
Michael Chanb6016b72005-05-26 13:03:09 -07006124{
Michael Chan13daffa2006-03-20 17:49:20 -08006125 if (netif_running(bp->dev)) {
6126 bnx2_netif_stop(bp);
6127 bnx2_reset_chip(bp, BNX2_DRV_MSG_CODE_RESET);
6128 bnx2_free_skbs(bp);
6129 bnx2_free_mem(bp);
6130 }
6131
Michael Chan5d5d0012007-12-12 11:17:43 -08006132 bnx2_set_rx_ring_size(bp, rx);
6133 bp->tx_ring_size = tx;
Michael Chanb6016b72005-05-26 13:03:09 -07006134
6135 if (netif_running(bp->dev)) {
Michael Chan13daffa2006-03-20 17:49:20 -08006136 int rc;
6137
6138 rc = bnx2_alloc_mem(bp);
6139 if (rc)
6140 return rc;
Michael Chanb6016b72005-05-26 13:03:09 -07006141 bnx2_init_nic(bp);
6142 bnx2_netif_start(bp);
6143 }
Michael Chanb6016b72005-05-26 13:03:09 -07006144 return 0;
6145}
6146
Michael Chan5d5d0012007-12-12 11:17:43 -08006147static int
6148bnx2_set_ringparam(struct net_device *dev, struct ethtool_ringparam *ering)
6149{
6150 struct bnx2 *bp = netdev_priv(dev);
6151 int rc;
6152
6153 if ((ering->rx_pending > MAX_TOTAL_RX_DESC_CNT) ||
6154 (ering->tx_pending > MAX_TX_DESC_CNT) ||
6155 (ering->tx_pending <= MAX_SKB_FRAGS)) {
6156
6157 return -EINVAL;
6158 }
6159 rc = bnx2_change_ring_size(bp, ering->rx_pending, ering->tx_pending);
6160 return rc;
6161}
6162
Michael Chanb6016b72005-05-26 13:03:09 -07006163static void
6164bnx2_get_pauseparam(struct net_device *dev, struct ethtool_pauseparam *epause)
6165{
Michael Chan972ec0d2006-01-23 16:12:43 -08006166 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006167
6168 epause->autoneg = ((bp->autoneg & AUTONEG_FLOW_CTRL) != 0);
6169 epause->rx_pause = ((bp->flow_ctrl & FLOW_CTRL_RX) != 0);
6170 epause->tx_pause = ((bp->flow_ctrl & FLOW_CTRL_TX) != 0);
6171}
6172
6173static int
6174bnx2_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam *epause)
6175{
Michael Chan972ec0d2006-01-23 16:12:43 -08006176 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006177
6178 bp->req_flow_ctrl = 0;
6179 if (epause->rx_pause)
6180 bp->req_flow_ctrl |= FLOW_CTRL_RX;
6181 if (epause->tx_pause)
6182 bp->req_flow_ctrl |= FLOW_CTRL_TX;
6183
6184 if (epause->autoneg) {
6185 bp->autoneg |= AUTONEG_FLOW_CTRL;
6186 }
6187 else {
6188 bp->autoneg &= ~AUTONEG_FLOW_CTRL;
6189 }
6190
Michael Chanc770a652005-08-25 15:38:39 -07006191 spin_lock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07006192
Michael Chan0d8a6572007-07-07 22:49:43 -07006193 bnx2_setup_phy(bp, bp->phy_port);
Michael Chanb6016b72005-05-26 13:03:09 -07006194
Michael Chanc770a652005-08-25 15:38:39 -07006195 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07006196
6197 return 0;
6198}
6199
6200static u32
6201bnx2_get_rx_csum(struct net_device *dev)
6202{
Michael Chan972ec0d2006-01-23 16:12:43 -08006203 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006204
6205 return bp->rx_csum;
6206}
6207
6208static int
6209bnx2_set_rx_csum(struct net_device *dev, u32 data)
6210{
Michael Chan972ec0d2006-01-23 16:12:43 -08006211 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006212
6213 bp->rx_csum = data;
6214 return 0;
6215}
6216
Michael Chanb11d6212006-06-29 12:31:21 -07006217static int
6218bnx2_set_tso(struct net_device *dev, u32 data)
6219{
Michael Chan4666f872007-05-03 13:22:28 -07006220 struct bnx2 *bp = netdev_priv(dev);
6221
6222 if (data) {
Michael Chanb11d6212006-06-29 12:31:21 -07006223 dev->features |= NETIF_F_TSO | NETIF_F_TSO_ECN;
Michael Chan4666f872007-05-03 13:22:28 -07006224 if (CHIP_NUM(bp) == CHIP_NUM_5709)
6225 dev->features |= NETIF_F_TSO6;
6226 } else
6227 dev->features &= ~(NETIF_F_TSO | NETIF_F_TSO6 |
6228 NETIF_F_TSO_ECN);
Michael Chanb11d6212006-06-29 12:31:21 -07006229 return 0;
6230}
6231
Michael Chancea94db2006-06-12 22:16:13 -07006232#define BNX2_NUM_STATS 46
Michael Chanb6016b72005-05-26 13:03:09 -07006233
Peter Hagervall14ab9b82005-08-10 14:18:16 -07006234static struct {
Michael Chanb6016b72005-05-26 13:03:09 -07006235 char string[ETH_GSTRING_LEN];
6236} bnx2_stats_str_arr[BNX2_NUM_STATS] = {
6237 { "rx_bytes" },
6238 { "rx_error_bytes" },
6239 { "tx_bytes" },
6240 { "tx_error_bytes" },
6241 { "rx_ucast_packets" },
6242 { "rx_mcast_packets" },
6243 { "rx_bcast_packets" },
6244 { "tx_ucast_packets" },
6245 { "tx_mcast_packets" },
6246 { "tx_bcast_packets" },
6247 { "tx_mac_errors" },
6248 { "tx_carrier_errors" },
6249 { "rx_crc_errors" },
6250 { "rx_align_errors" },
6251 { "tx_single_collisions" },
6252 { "tx_multi_collisions" },
6253 { "tx_deferred" },
6254 { "tx_excess_collisions" },
6255 { "tx_late_collisions" },
6256 { "tx_total_collisions" },
6257 { "rx_fragments" },
6258 { "rx_jabbers" },
6259 { "rx_undersize_packets" },
6260 { "rx_oversize_packets" },
6261 { "rx_64_byte_packets" },
6262 { "rx_65_to_127_byte_packets" },
6263 { "rx_128_to_255_byte_packets" },
6264 { "rx_256_to_511_byte_packets" },
6265 { "rx_512_to_1023_byte_packets" },
6266 { "rx_1024_to_1522_byte_packets" },
6267 { "rx_1523_to_9022_byte_packets" },
6268 { "tx_64_byte_packets" },
6269 { "tx_65_to_127_byte_packets" },
6270 { "tx_128_to_255_byte_packets" },
6271 { "tx_256_to_511_byte_packets" },
6272 { "tx_512_to_1023_byte_packets" },
6273 { "tx_1024_to_1522_byte_packets" },
6274 { "tx_1523_to_9022_byte_packets" },
6275 { "rx_xon_frames" },
6276 { "rx_xoff_frames" },
6277 { "tx_xon_frames" },
6278 { "tx_xoff_frames" },
6279 { "rx_mac_ctrl_frames" },
6280 { "rx_filtered_packets" },
6281 { "rx_discards" },
Michael Chancea94db2006-06-12 22:16:13 -07006282 { "rx_fw_discards" },
Michael Chanb6016b72005-05-26 13:03:09 -07006283};
6284
6285#define STATS_OFFSET32(offset_name) (offsetof(struct statistics_block, offset_name) / 4)
6286
Arjan van de Venf71e1302006-03-03 21:33:57 -05006287static const unsigned long bnx2_stats_offset_arr[BNX2_NUM_STATS] = {
Michael Chanb6016b72005-05-26 13:03:09 -07006288 STATS_OFFSET32(stat_IfHCInOctets_hi),
6289 STATS_OFFSET32(stat_IfHCInBadOctets_hi),
6290 STATS_OFFSET32(stat_IfHCOutOctets_hi),
6291 STATS_OFFSET32(stat_IfHCOutBadOctets_hi),
6292 STATS_OFFSET32(stat_IfHCInUcastPkts_hi),
6293 STATS_OFFSET32(stat_IfHCInMulticastPkts_hi),
6294 STATS_OFFSET32(stat_IfHCInBroadcastPkts_hi),
6295 STATS_OFFSET32(stat_IfHCOutUcastPkts_hi),
6296 STATS_OFFSET32(stat_IfHCOutMulticastPkts_hi),
6297 STATS_OFFSET32(stat_IfHCOutBroadcastPkts_hi),
6298 STATS_OFFSET32(stat_emac_tx_stat_dot3statsinternalmactransmiterrors),
Jeff Garzik6aa20a22006-09-13 13:24:59 -04006299 STATS_OFFSET32(stat_Dot3StatsCarrierSenseErrors),
6300 STATS_OFFSET32(stat_Dot3StatsFCSErrors),
6301 STATS_OFFSET32(stat_Dot3StatsAlignmentErrors),
6302 STATS_OFFSET32(stat_Dot3StatsSingleCollisionFrames),
6303 STATS_OFFSET32(stat_Dot3StatsMultipleCollisionFrames),
6304 STATS_OFFSET32(stat_Dot3StatsDeferredTransmissions),
6305 STATS_OFFSET32(stat_Dot3StatsExcessiveCollisions),
6306 STATS_OFFSET32(stat_Dot3StatsLateCollisions),
6307 STATS_OFFSET32(stat_EtherStatsCollisions),
6308 STATS_OFFSET32(stat_EtherStatsFragments),
6309 STATS_OFFSET32(stat_EtherStatsJabbers),
6310 STATS_OFFSET32(stat_EtherStatsUndersizePkts),
6311 STATS_OFFSET32(stat_EtherStatsOverrsizePkts),
6312 STATS_OFFSET32(stat_EtherStatsPktsRx64Octets),
6313 STATS_OFFSET32(stat_EtherStatsPktsRx65Octetsto127Octets),
6314 STATS_OFFSET32(stat_EtherStatsPktsRx128Octetsto255Octets),
6315 STATS_OFFSET32(stat_EtherStatsPktsRx256Octetsto511Octets),
6316 STATS_OFFSET32(stat_EtherStatsPktsRx512Octetsto1023Octets),
6317 STATS_OFFSET32(stat_EtherStatsPktsRx1024Octetsto1522Octets),
6318 STATS_OFFSET32(stat_EtherStatsPktsRx1523Octetsto9022Octets),
6319 STATS_OFFSET32(stat_EtherStatsPktsTx64Octets),
6320 STATS_OFFSET32(stat_EtherStatsPktsTx65Octetsto127Octets),
6321 STATS_OFFSET32(stat_EtherStatsPktsTx128Octetsto255Octets),
6322 STATS_OFFSET32(stat_EtherStatsPktsTx256Octetsto511Octets),
6323 STATS_OFFSET32(stat_EtherStatsPktsTx512Octetsto1023Octets),
6324 STATS_OFFSET32(stat_EtherStatsPktsTx1024Octetsto1522Octets),
6325 STATS_OFFSET32(stat_EtherStatsPktsTx1523Octetsto9022Octets),
6326 STATS_OFFSET32(stat_XonPauseFramesReceived),
6327 STATS_OFFSET32(stat_XoffPauseFramesReceived),
6328 STATS_OFFSET32(stat_OutXonSent),
6329 STATS_OFFSET32(stat_OutXoffSent),
6330 STATS_OFFSET32(stat_MacControlFramesReceived),
6331 STATS_OFFSET32(stat_IfInFramesL2FilterDiscards),
6332 STATS_OFFSET32(stat_IfInMBUFDiscards),
Michael Chancea94db2006-06-12 22:16:13 -07006333 STATS_OFFSET32(stat_FwRxDrop),
Michael Chanb6016b72005-05-26 13:03:09 -07006334};
6335
6336/* stat_IfHCInBadOctets and stat_Dot3StatsCarrierSenseErrors are
6337 * skipped because of errata.
Jeff Garzik6aa20a22006-09-13 13:24:59 -04006338 */
Peter Hagervall14ab9b82005-08-10 14:18:16 -07006339static u8 bnx2_5706_stats_len_arr[BNX2_NUM_STATS] = {
Michael Chanb6016b72005-05-26 13:03:09 -07006340 8,0,8,8,8,8,8,8,8,8,
6341 4,0,4,4,4,4,4,4,4,4,
6342 4,4,4,4,4,4,4,4,4,4,
6343 4,4,4,4,4,4,4,4,4,4,
Michael Chancea94db2006-06-12 22:16:13 -07006344 4,4,4,4,4,4,
Michael Chanb6016b72005-05-26 13:03:09 -07006345};
6346
Michael Chan5b0c76a2005-11-04 08:45:49 -08006347static u8 bnx2_5708_stats_len_arr[BNX2_NUM_STATS] = {
6348 8,0,8,8,8,8,8,8,8,8,
6349 4,4,4,4,4,4,4,4,4,4,
6350 4,4,4,4,4,4,4,4,4,4,
6351 4,4,4,4,4,4,4,4,4,4,
Michael Chancea94db2006-06-12 22:16:13 -07006352 4,4,4,4,4,4,
Michael Chan5b0c76a2005-11-04 08:45:49 -08006353};
6354
Michael Chanb6016b72005-05-26 13:03:09 -07006355#define BNX2_NUM_TESTS 6
6356
Peter Hagervall14ab9b82005-08-10 14:18:16 -07006357static struct {
Michael Chanb6016b72005-05-26 13:03:09 -07006358 char string[ETH_GSTRING_LEN];
6359} bnx2_tests_str_arr[BNX2_NUM_TESTS] = {
6360 { "register_test (offline)" },
6361 { "memory_test (offline)" },
6362 { "loopback_test (offline)" },
6363 { "nvram_test (online)" },
6364 { "interrupt_test (online)" },
6365 { "link_test (online)" },
6366};
6367
6368static int
Jeff Garzikb9f2c042007-10-03 18:07:32 -07006369bnx2_get_sset_count(struct net_device *dev, int sset)
Michael Chanb6016b72005-05-26 13:03:09 -07006370{
Jeff Garzikb9f2c042007-10-03 18:07:32 -07006371 switch (sset) {
6372 case ETH_SS_TEST:
6373 return BNX2_NUM_TESTS;
6374 case ETH_SS_STATS:
6375 return BNX2_NUM_STATS;
6376 default:
6377 return -EOPNOTSUPP;
6378 }
Michael Chanb6016b72005-05-26 13:03:09 -07006379}
6380
6381static void
6382bnx2_self_test(struct net_device *dev, struct ethtool_test *etest, u64 *buf)
6383{
Michael Chan972ec0d2006-01-23 16:12:43 -08006384 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006385
6386 memset(buf, 0, sizeof(u64) * BNX2_NUM_TESTS);
6387 if (etest->flags & ETH_TEST_FL_OFFLINE) {
Michael Chan80be4432006-11-19 14:07:28 -08006388 int i;
6389
Michael Chanb6016b72005-05-26 13:03:09 -07006390 bnx2_netif_stop(bp);
6391 bnx2_reset_chip(bp, BNX2_DRV_MSG_CODE_DIAG);
6392 bnx2_free_skbs(bp);
6393
6394 if (bnx2_test_registers(bp) != 0) {
6395 buf[0] = 1;
6396 etest->flags |= ETH_TEST_FL_FAILED;
6397 }
6398 if (bnx2_test_memory(bp) != 0) {
6399 buf[1] = 1;
6400 etest->flags |= ETH_TEST_FL_FAILED;
6401 }
Michael Chanbc5a0692006-01-23 16:13:22 -08006402 if ((buf[2] = bnx2_test_loopback(bp)) != 0)
Michael Chanb6016b72005-05-26 13:03:09 -07006403 etest->flags |= ETH_TEST_FL_FAILED;
Michael Chanb6016b72005-05-26 13:03:09 -07006404
6405 if (!netif_running(bp->dev)) {
6406 bnx2_reset_chip(bp, BNX2_DRV_MSG_CODE_RESET);
6407 }
6408 else {
6409 bnx2_init_nic(bp);
6410 bnx2_netif_start(bp);
6411 }
6412
6413 /* wait for link up */
Michael Chan80be4432006-11-19 14:07:28 -08006414 for (i = 0; i < 7; i++) {
6415 if (bp->link_up)
6416 break;
6417 msleep_interruptible(1000);
6418 }
Michael Chanb6016b72005-05-26 13:03:09 -07006419 }
6420
6421 if (bnx2_test_nvram(bp) != 0) {
6422 buf[3] = 1;
6423 etest->flags |= ETH_TEST_FL_FAILED;
6424 }
6425 if (bnx2_test_intr(bp) != 0) {
6426 buf[4] = 1;
6427 etest->flags |= ETH_TEST_FL_FAILED;
6428 }
6429
6430 if (bnx2_test_link(bp) != 0) {
6431 buf[5] = 1;
6432 etest->flags |= ETH_TEST_FL_FAILED;
6433
6434 }
6435}
6436
6437static void
6438bnx2_get_strings(struct net_device *dev, u32 stringset, u8 *buf)
6439{
6440 switch (stringset) {
6441 case ETH_SS_STATS:
6442 memcpy(buf, bnx2_stats_str_arr,
6443 sizeof(bnx2_stats_str_arr));
6444 break;
6445 case ETH_SS_TEST:
6446 memcpy(buf, bnx2_tests_str_arr,
6447 sizeof(bnx2_tests_str_arr));
6448 break;
6449 }
6450}
6451
Michael Chanb6016b72005-05-26 13:03:09 -07006452static void
6453bnx2_get_ethtool_stats(struct net_device *dev,
6454 struct ethtool_stats *stats, u64 *buf)
6455{
Michael Chan972ec0d2006-01-23 16:12:43 -08006456 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006457 int i;
6458 u32 *hw_stats = (u32 *) bp->stats_blk;
Peter Hagervall14ab9b82005-08-10 14:18:16 -07006459 u8 *stats_len_arr = NULL;
Michael Chanb6016b72005-05-26 13:03:09 -07006460
6461 if (hw_stats == NULL) {
6462 memset(buf, 0, sizeof(u64) * BNX2_NUM_STATS);
6463 return;
6464 }
6465
Michael Chan5b0c76a2005-11-04 08:45:49 -08006466 if ((CHIP_ID(bp) == CHIP_ID_5706_A0) ||
6467 (CHIP_ID(bp) == CHIP_ID_5706_A1) ||
6468 (CHIP_ID(bp) == CHIP_ID_5706_A2) ||
6469 (CHIP_ID(bp) == CHIP_ID_5708_A0))
Michael Chanb6016b72005-05-26 13:03:09 -07006470 stats_len_arr = bnx2_5706_stats_len_arr;
Michael Chan5b0c76a2005-11-04 08:45:49 -08006471 else
6472 stats_len_arr = bnx2_5708_stats_len_arr;
Michael Chanb6016b72005-05-26 13:03:09 -07006473
6474 for (i = 0; i < BNX2_NUM_STATS; i++) {
6475 if (stats_len_arr[i] == 0) {
6476 /* skip this counter */
6477 buf[i] = 0;
6478 continue;
6479 }
6480 if (stats_len_arr[i] == 4) {
6481 /* 4-byte counter */
6482 buf[i] = (u64)
6483 *(hw_stats + bnx2_stats_offset_arr[i]);
6484 continue;
6485 }
6486 /* 8-byte counter */
6487 buf[i] = (((u64) *(hw_stats +
6488 bnx2_stats_offset_arr[i])) << 32) +
6489 *(hw_stats + bnx2_stats_offset_arr[i] + 1);
6490 }
6491}
6492
6493static int
6494bnx2_phys_id(struct net_device *dev, u32 data)
6495{
Michael Chan972ec0d2006-01-23 16:12:43 -08006496 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006497 int i;
6498 u32 save;
6499
6500 if (data == 0)
6501 data = 2;
6502
6503 save = REG_RD(bp, BNX2_MISC_CFG);
6504 REG_WR(bp, BNX2_MISC_CFG, BNX2_MISC_CFG_LEDMODE_MAC);
6505
6506 for (i = 0; i < (data * 2); i++) {
6507 if ((i % 2) == 0) {
6508 REG_WR(bp, BNX2_EMAC_LED, BNX2_EMAC_LED_OVERRIDE);
6509 }
6510 else {
6511 REG_WR(bp, BNX2_EMAC_LED, BNX2_EMAC_LED_OVERRIDE |
6512 BNX2_EMAC_LED_1000MB_OVERRIDE |
6513 BNX2_EMAC_LED_100MB_OVERRIDE |
6514 BNX2_EMAC_LED_10MB_OVERRIDE |
6515 BNX2_EMAC_LED_TRAFFIC_OVERRIDE |
6516 BNX2_EMAC_LED_TRAFFIC);
6517 }
6518 msleep_interruptible(500);
6519 if (signal_pending(current))
6520 break;
6521 }
6522 REG_WR(bp, BNX2_EMAC_LED, 0);
6523 REG_WR(bp, BNX2_MISC_CFG, save);
6524 return 0;
6525}
6526
Michael Chan4666f872007-05-03 13:22:28 -07006527static int
6528bnx2_set_tx_csum(struct net_device *dev, u32 data)
6529{
6530 struct bnx2 *bp = netdev_priv(dev);
6531
6532 if (CHIP_NUM(bp) == CHIP_NUM_5709)
Michael Chan6460d942007-07-14 19:07:52 -07006533 return (ethtool_op_set_tx_ipv6_csum(dev, data));
Michael Chan4666f872007-05-03 13:22:28 -07006534 else
6535 return (ethtool_op_set_tx_csum(dev, data));
6536}
6537
Jeff Garzik7282d492006-09-13 14:30:00 -04006538static const struct ethtool_ops bnx2_ethtool_ops = {
Michael Chanb6016b72005-05-26 13:03:09 -07006539 .get_settings = bnx2_get_settings,
6540 .set_settings = bnx2_set_settings,
6541 .get_drvinfo = bnx2_get_drvinfo,
Michael Chan244ac4f2006-03-20 17:48:46 -08006542 .get_regs_len = bnx2_get_regs_len,
6543 .get_regs = bnx2_get_regs,
Michael Chanb6016b72005-05-26 13:03:09 -07006544 .get_wol = bnx2_get_wol,
6545 .set_wol = bnx2_set_wol,
6546 .nway_reset = bnx2_nway_reset,
6547 .get_link = ethtool_op_get_link,
6548 .get_eeprom_len = bnx2_get_eeprom_len,
6549 .get_eeprom = bnx2_get_eeprom,
6550 .set_eeprom = bnx2_set_eeprom,
6551 .get_coalesce = bnx2_get_coalesce,
6552 .set_coalesce = bnx2_set_coalesce,
6553 .get_ringparam = bnx2_get_ringparam,
6554 .set_ringparam = bnx2_set_ringparam,
6555 .get_pauseparam = bnx2_get_pauseparam,
6556 .set_pauseparam = bnx2_set_pauseparam,
6557 .get_rx_csum = bnx2_get_rx_csum,
6558 .set_rx_csum = bnx2_set_rx_csum,
Michael Chan4666f872007-05-03 13:22:28 -07006559 .set_tx_csum = bnx2_set_tx_csum,
Michael Chanb6016b72005-05-26 13:03:09 -07006560 .set_sg = ethtool_op_set_sg,
Michael Chanb11d6212006-06-29 12:31:21 -07006561 .set_tso = bnx2_set_tso,
Michael Chanb6016b72005-05-26 13:03:09 -07006562 .self_test = bnx2_self_test,
6563 .get_strings = bnx2_get_strings,
6564 .phys_id = bnx2_phys_id,
Michael Chanb6016b72005-05-26 13:03:09 -07006565 .get_ethtool_stats = bnx2_get_ethtool_stats,
Jeff Garzikb9f2c042007-10-03 18:07:32 -07006566 .get_sset_count = bnx2_get_sset_count,
Michael Chanb6016b72005-05-26 13:03:09 -07006567};
6568
6569/* Called with rtnl_lock */
6570static int
6571bnx2_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
6572{
Peter Hagervall14ab9b82005-08-10 14:18:16 -07006573 struct mii_ioctl_data *data = if_mii(ifr);
Michael Chan972ec0d2006-01-23 16:12:43 -08006574 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006575 int err;
6576
6577 switch(cmd) {
6578 case SIOCGMIIPHY:
6579 data->phy_id = bp->phy_addr;
6580
6581 /* fallthru */
6582 case SIOCGMIIREG: {
6583 u32 mii_regval;
6584
Michael Chan7b6b8342007-07-07 22:50:15 -07006585 if (bp->phy_flags & REMOTE_PHY_CAP_FLAG)
6586 return -EOPNOTSUPP;
6587
Michael Chandad3e452007-05-03 13:18:03 -07006588 if (!netif_running(dev))
6589 return -EAGAIN;
6590
Michael Chanc770a652005-08-25 15:38:39 -07006591 spin_lock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07006592 err = bnx2_read_phy(bp, data->reg_num & 0x1f, &mii_regval);
Michael Chanc770a652005-08-25 15:38:39 -07006593 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07006594
6595 data->val_out = mii_regval;
6596
6597 return err;
6598 }
6599
6600 case SIOCSMIIREG:
6601 if (!capable(CAP_NET_ADMIN))
6602 return -EPERM;
6603
Michael Chan7b6b8342007-07-07 22:50:15 -07006604 if (bp->phy_flags & REMOTE_PHY_CAP_FLAG)
6605 return -EOPNOTSUPP;
6606
Michael Chandad3e452007-05-03 13:18:03 -07006607 if (!netif_running(dev))
6608 return -EAGAIN;
6609
Michael Chanc770a652005-08-25 15:38:39 -07006610 spin_lock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07006611 err = bnx2_write_phy(bp, data->reg_num & 0x1f, data->val_in);
Michael Chanc770a652005-08-25 15:38:39 -07006612 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07006613
6614 return err;
6615
6616 default:
6617 /* do nothing */
6618 break;
6619 }
6620 return -EOPNOTSUPP;
6621}
6622
6623/* Called with rtnl_lock */
6624static int
6625bnx2_change_mac_addr(struct net_device *dev, void *p)
6626{
6627 struct sockaddr *addr = p;
Michael Chan972ec0d2006-01-23 16:12:43 -08006628 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006629
Michael Chan73eef4c2005-08-25 15:39:15 -07006630 if (!is_valid_ether_addr(addr->sa_data))
6631 return -EINVAL;
6632
Michael Chanb6016b72005-05-26 13:03:09 -07006633 memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
6634 if (netif_running(dev))
6635 bnx2_set_mac_addr(bp);
6636
6637 return 0;
6638}
6639
6640/* Called with rtnl_lock */
6641static int
6642bnx2_change_mtu(struct net_device *dev, int new_mtu)
6643{
Michael Chan972ec0d2006-01-23 16:12:43 -08006644 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006645
6646 if (((new_mtu + ETH_HLEN) > MAX_ETHERNET_JUMBO_PACKET_SIZE) ||
6647 ((new_mtu + ETH_HLEN) < MIN_ETHERNET_PACKET_SIZE))
6648 return -EINVAL;
6649
6650 dev->mtu = new_mtu;
Michael Chan5d5d0012007-12-12 11:17:43 -08006651 return (bnx2_change_ring_size(bp, bp->rx_ring_size, bp->tx_ring_size));
Michael Chanb6016b72005-05-26 13:03:09 -07006652}
6653
6654#if defined(HAVE_POLL_CONTROLLER) || defined(CONFIG_NET_POLL_CONTROLLER)
6655static void
6656poll_bnx2(struct net_device *dev)
6657{
Michael Chan972ec0d2006-01-23 16:12:43 -08006658 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006659
6660 disable_irq(bp->pdev->irq);
David Howells7d12e782006-10-05 14:55:46 +01006661 bnx2_interrupt(bp->pdev->irq, dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006662 enable_irq(bp->pdev->irq);
6663}
6664#endif
6665
Michael Chan253c8b72007-01-08 19:56:01 -08006666static void __devinit
6667bnx2_get_5709_media(struct bnx2 *bp)
6668{
6669 u32 val = REG_RD(bp, BNX2_MISC_DUAL_MEDIA_CTRL);
6670 u32 bond_id = val & BNX2_MISC_DUAL_MEDIA_CTRL_BOND_ID;
6671 u32 strap;
6672
6673 if (bond_id == BNX2_MISC_DUAL_MEDIA_CTRL_BOND_ID_C)
6674 return;
6675 else if (bond_id == BNX2_MISC_DUAL_MEDIA_CTRL_BOND_ID_S) {
6676 bp->phy_flags |= PHY_SERDES_FLAG;
6677 return;
6678 }
6679
6680 if (val & BNX2_MISC_DUAL_MEDIA_CTRL_STRAP_OVERRIDE)
6681 strap = (val & BNX2_MISC_DUAL_MEDIA_CTRL_PHY_CTRL) >> 21;
6682 else
6683 strap = (val & BNX2_MISC_DUAL_MEDIA_CTRL_PHY_CTRL_STRAP) >> 8;
6684
6685 if (PCI_FUNC(bp->pdev->devfn) == 0) {
6686 switch (strap) {
6687 case 0x4:
6688 case 0x5:
6689 case 0x6:
6690 bp->phy_flags |= PHY_SERDES_FLAG;
6691 return;
6692 }
6693 } else {
6694 switch (strap) {
6695 case 0x1:
6696 case 0x2:
6697 case 0x4:
6698 bp->phy_flags |= PHY_SERDES_FLAG;
6699 return;
6700 }
6701 }
6702}
6703
Michael Chan883e5152007-05-03 13:25:11 -07006704static void __devinit
6705bnx2_get_pci_speed(struct bnx2 *bp)
6706{
6707 u32 reg;
6708
6709 reg = REG_RD(bp, BNX2_PCICFG_MISC_STATUS);
6710 if (reg & BNX2_PCICFG_MISC_STATUS_PCIX_DET) {
6711 u32 clkreg;
6712
6713 bp->flags |= PCIX_FLAG;
6714
6715 clkreg = REG_RD(bp, BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS);
6716
6717 clkreg &= BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET;
6718 switch (clkreg) {
6719 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_133MHZ:
6720 bp->bus_speed_mhz = 133;
6721 break;
6722
6723 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_95MHZ:
6724 bp->bus_speed_mhz = 100;
6725 break;
6726
6727 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_66MHZ:
6728 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_80MHZ:
6729 bp->bus_speed_mhz = 66;
6730 break;
6731
6732 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_48MHZ:
6733 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_55MHZ:
6734 bp->bus_speed_mhz = 50;
6735 break;
6736
6737 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_LOW:
6738 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_32MHZ:
6739 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_38MHZ:
6740 bp->bus_speed_mhz = 33;
6741 break;
6742 }
6743 }
6744 else {
6745 if (reg & BNX2_PCICFG_MISC_STATUS_M66EN)
6746 bp->bus_speed_mhz = 66;
6747 else
6748 bp->bus_speed_mhz = 33;
6749 }
6750
6751 if (reg & BNX2_PCICFG_MISC_STATUS_32BIT_DET)
6752 bp->flags |= PCI_32BIT_FLAG;
6753
6754}
6755
Michael Chanb6016b72005-05-26 13:03:09 -07006756static int __devinit
6757bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
6758{
6759 struct bnx2 *bp;
6760 unsigned long mem_len;
Michael Chan58fc2ea2007-07-07 22:52:02 -07006761 int rc, i, j;
Michael Chanb6016b72005-05-26 13:03:09 -07006762 u32 reg;
Michael Chan40453c82007-05-03 13:19:18 -07006763 u64 dma_mask, persist_dma_mask;
Michael Chanb6016b72005-05-26 13:03:09 -07006764
Michael Chanb6016b72005-05-26 13:03:09 -07006765 SET_NETDEV_DEV(dev, &pdev->dev);
Michael Chan972ec0d2006-01-23 16:12:43 -08006766 bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006767
6768 bp->flags = 0;
6769 bp->phy_flags = 0;
6770
6771 /* enable device (incl. PCI PM wakeup), and bus-mastering */
6772 rc = pci_enable_device(pdev);
6773 if (rc) {
Joe Perches898eb712007-10-18 03:06:30 -07006774 dev_err(&pdev->dev, "Cannot enable PCI device, aborting.\n");
Michael Chanb6016b72005-05-26 13:03:09 -07006775 goto err_out;
6776 }
6777
6778 if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) {
Jeff Garzik9b91cf92006-06-27 11:39:50 -04006779 dev_err(&pdev->dev,
Jeff Garzik2e8a5382006-06-27 10:47:51 -04006780 "Cannot find PCI device base address, aborting.\n");
Michael Chanb6016b72005-05-26 13:03:09 -07006781 rc = -ENODEV;
6782 goto err_out_disable;
6783 }
6784
6785 rc = pci_request_regions(pdev, DRV_MODULE_NAME);
6786 if (rc) {
Jeff Garzik9b91cf92006-06-27 11:39:50 -04006787 dev_err(&pdev->dev, "Cannot obtain PCI resources, aborting.\n");
Michael Chanb6016b72005-05-26 13:03:09 -07006788 goto err_out_disable;
6789 }
6790
6791 pci_set_master(pdev);
6792
6793 bp->pm_cap = pci_find_capability(pdev, PCI_CAP_ID_PM);
6794 if (bp->pm_cap == 0) {
Jeff Garzik9b91cf92006-06-27 11:39:50 -04006795 dev_err(&pdev->dev,
Jeff Garzik2e8a5382006-06-27 10:47:51 -04006796 "Cannot find power management capability, aborting.\n");
Michael Chanb6016b72005-05-26 13:03:09 -07006797 rc = -EIO;
6798 goto err_out_release;
6799 }
6800
Michael Chanb6016b72005-05-26 13:03:09 -07006801 bp->dev = dev;
6802 bp->pdev = pdev;
6803
6804 spin_lock_init(&bp->phy_lock);
Michael Chan1b8227c2007-05-03 13:24:05 -07006805 spin_lock_init(&bp->indirect_lock);
David Howellsc4028952006-11-22 14:57:56 +00006806 INIT_WORK(&bp->reset_task, bnx2_reset_task);
Michael Chanb6016b72005-05-26 13:03:09 -07006807
6808 dev->base_addr = dev->mem_start = pci_resource_start(pdev, 0);
Michael Chan59b47d82006-11-19 14:10:45 -08006809 mem_len = MB_GET_CID_ADDR(TX_TSS_CID + 1);
Michael Chanb6016b72005-05-26 13:03:09 -07006810 dev->mem_end = dev->mem_start + mem_len;
6811 dev->irq = pdev->irq;
6812
6813 bp->regview = ioremap_nocache(dev->base_addr, mem_len);
6814
6815 if (!bp->regview) {
Jeff Garzik9b91cf92006-06-27 11:39:50 -04006816 dev_err(&pdev->dev, "Cannot map register space, aborting.\n");
Michael Chanb6016b72005-05-26 13:03:09 -07006817 rc = -ENOMEM;
6818 goto err_out_release;
6819 }
6820
6821 /* Configure byte swap and enable write to the reg_window registers.
6822 * Rely on CPU to do target byte swapping on big endian systems
6823 * The chip's target access swapping will not swap all accesses
6824 */
6825 pci_write_config_dword(bp->pdev, BNX2_PCICFG_MISC_CONFIG,
6826 BNX2_PCICFG_MISC_CONFIG_REG_WINDOW_ENA |
6827 BNX2_PCICFG_MISC_CONFIG_TARGET_MB_WORD_SWAP);
6828
Pavel Machek829ca9a2005-09-03 15:56:56 -07006829 bnx2_set_power_state(bp, PCI_D0);
Michael Chanb6016b72005-05-26 13:03:09 -07006830
6831 bp->chip_id = REG_RD(bp, BNX2_MISC_ID);
6832
Michael Chan883e5152007-05-03 13:25:11 -07006833 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
6834 if (pci_find_capability(pdev, PCI_CAP_ID_EXP) == 0) {
6835 dev_err(&pdev->dev,
6836 "Cannot find PCIE capability, aborting.\n");
6837 rc = -EIO;
6838 goto err_out_unmap;
6839 }
6840 bp->flags |= PCIE_FLAG;
6841 } else {
Michael Chan59b47d82006-11-19 14:10:45 -08006842 bp->pcix_cap = pci_find_capability(pdev, PCI_CAP_ID_PCIX);
6843 if (bp->pcix_cap == 0) {
6844 dev_err(&pdev->dev,
6845 "Cannot find PCIX capability, aborting.\n");
6846 rc = -EIO;
6847 goto err_out_unmap;
6848 }
6849 }
6850
Michael Chan8e6a72c2007-05-03 13:24:48 -07006851 if (CHIP_ID(bp) != CHIP_ID_5706_A0 && CHIP_ID(bp) != CHIP_ID_5706_A1) {
6852 if (pci_find_capability(pdev, PCI_CAP_ID_MSI))
6853 bp->flags |= MSI_CAP_FLAG;
6854 }
6855
Michael Chan40453c82007-05-03 13:19:18 -07006856 /* 5708 cannot support DMA addresses > 40-bit. */
6857 if (CHIP_NUM(bp) == CHIP_NUM_5708)
6858 persist_dma_mask = dma_mask = DMA_40BIT_MASK;
6859 else
6860 persist_dma_mask = dma_mask = DMA_64BIT_MASK;
6861
6862 /* Configure DMA attributes. */
6863 if (pci_set_dma_mask(pdev, dma_mask) == 0) {
6864 dev->features |= NETIF_F_HIGHDMA;
6865 rc = pci_set_consistent_dma_mask(pdev, persist_dma_mask);
6866 if (rc) {
6867 dev_err(&pdev->dev,
6868 "pci_set_consistent_dma_mask failed, aborting.\n");
6869 goto err_out_unmap;
6870 }
6871 } else if ((rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK)) != 0) {
6872 dev_err(&pdev->dev, "System does not support DMA, aborting.\n");
6873 goto err_out_unmap;
6874 }
6875
Michael Chan883e5152007-05-03 13:25:11 -07006876 if (!(bp->flags & PCIE_FLAG))
6877 bnx2_get_pci_speed(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07006878
6879 /* 5706A0 may falsely detect SERR and PERR. */
6880 if (CHIP_ID(bp) == CHIP_ID_5706_A0) {
6881 reg = REG_RD(bp, PCI_COMMAND);
6882 reg &= ~(PCI_COMMAND_SERR | PCI_COMMAND_PARITY);
6883 REG_WR(bp, PCI_COMMAND, reg);
6884 }
6885 else if ((CHIP_ID(bp) == CHIP_ID_5706_A1) &&
6886 !(bp->flags & PCIX_FLAG)) {
6887
Jeff Garzik9b91cf92006-06-27 11:39:50 -04006888 dev_err(&pdev->dev,
Jeff Garzik2e8a5382006-06-27 10:47:51 -04006889 "5706 A1 can only be used in a PCIX bus, aborting.\n");
Michael Chanb6016b72005-05-26 13:03:09 -07006890 goto err_out_unmap;
6891 }
6892
6893 bnx2_init_nvram(bp);
6894
Michael Chane3648b32005-11-04 08:51:21 -08006895 reg = REG_RD_IND(bp, BNX2_SHM_HDR_SIGNATURE);
6896
6897 if ((reg & BNX2_SHM_HDR_SIGNATURE_SIG_MASK) ==
Michael Chan24cb2302007-01-25 15:49:56 -08006898 BNX2_SHM_HDR_SIGNATURE_SIG) {
6899 u32 off = PCI_FUNC(pdev->devfn) << 2;
6900
6901 bp->shmem_base = REG_RD_IND(bp, BNX2_SHM_HDR_ADDR_0 + off);
6902 } else
Michael Chane3648b32005-11-04 08:51:21 -08006903 bp->shmem_base = HOST_VIEW_SHMEM_BASE;
6904
Michael Chanb6016b72005-05-26 13:03:09 -07006905 /* Get the permanent MAC address. First we need to make sure the
6906 * firmware is actually running.
6907 */
Michael Chane3648b32005-11-04 08:51:21 -08006908 reg = REG_RD_IND(bp, bp->shmem_base + BNX2_DEV_INFO_SIGNATURE);
Michael Chanb6016b72005-05-26 13:03:09 -07006909
6910 if ((reg & BNX2_DEV_INFO_SIGNATURE_MAGIC_MASK) !=
6911 BNX2_DEV_INFO_SIGNATURE_MAGIC) {
Jeff Garzik9b91cf92006-06-27 11:39:50 -04006912 dev_err(&pdev->dev, "Firmware not running, aborting.\n");
Michael Chanb6016b72005-05-26 13:03:09 -07006913 rc = -ENODEV;
6914 goto err_out_unmap;
6915 }
6916
Michael Chan58fc2ea2007-07-07 22:52:02 -07006917 reg = REG_RD_IND(bp, bp->shmem_base + BNX2_DEV_INFO_BC_REV);
6918 for (i = 0, j = 0; i < 3; i++) {
6919 u8 num, k, skip0;
6920
6921 num = (u8) (reg >> (24 - (i * 8)));
6922 for (k = 100, skip0 = 1; k >= 1; num %= k, k /= 10) {
6923 if (num >= k || !skip0 || k == 1) {
6924 bp->fw_version[j++] = (num / k) + '0';
6925 skip0 = 0;
6926 }
6927 }
6928 if (i != 2)
6929 bp->fw_version[j++] = '.';
6930 }
Michael Chan846f5c62007-10-10 16:16:51 -07006931 reg = REG_RD_IND(bp, bp->shmem_base + BNX2_PORT_FEATURE);
6932 if (reg & BNX2_PORT_FEATURE_WOL_ENABLED)
6933 bp->wol = 1;
6934
6935 if (reg & BNX2_PORT_FEATURE_ASF_ENABLED) {
Michael Chanc2d3db82007-07-16 18:26:43 -07006936 bp->flags |= ASF_ENABLE_FLAG;
6937
6938 for (i = 0; i < 30; i++) {
6939 reg = REG_RD_IND(bp, bp->shmem_base +
6940 BNX2_BC_STATE_CONDITION);
6941 if (reg & BNX2_CONDITION_MFW_RUN_MASK)
6942 break;
6943 msleep(10);
6944 }
6945 }
Michael Chan58fc2ea2007-07-07 22:52:02 -07006946 reg = REG_RD_IND(bp, bp->shmem_base + BNX2_BC_STATE_CONDITION);
6947 reg &= BNX2_CONDITION_MFW_RUN_MASK;
6948 if (reg != BNX2_CONDITION_MFW_RUN_UNKNOWN &&
6949 reg != BNX2_CONDITION_MFW_RUN_NONE) {
6950 int i;
6951 u32 addr = REG_RD_IND(bp, bp->shmem_base + BNX2_MFW_VER_PTR);
6952
6953 bp->fw_version[j++] = ' ';
6954 for (i = 0; i < 3; i++) {
6955 reg = REG_RD_IND(bp, addr + i * 4);
6956 reg = swab32(reg);
6957 memcpy(&bp->fw_version[j], &reg, 4);
6958 j += 4;
6959 }
6960 }
Michael Chanb6016b72005-05-26 13:03:09 -07006961
Michael Chane3648b32005-11-04 08:51:21 -08006962 reg = REG_RD_IND(bp, bp->shmem_base + BNX2_PORT_HW_CFG_MAC_UPPER);
Michael Chanb6016b72005-05-26 13:03:09 -07006963 bp->mac_addr[0] = (u8) (reg >> 8);
6964 bp->mac_addr[1] = (u8) reg;
6965
Michael Chane3648b32005-11-04 08:51:21 -08006966 reg = REG_RD_IND(bp, bp->shmem_base + BNX2_PORT_HW_CFG_MAC_LOWER);
Michael Chanb6016b72005-05-26 13:03:09 -07006967 bp->mac_addr[2] = (u8) (reg >> 24);
6968 bp->mac_addr[3] = (u8) (reg >> 16);
6969 bp->mac_addr[4] = (u8) (reg >> 8);
6970 bp->mac_addr[5] = (u8) reg;
6971
Michael Chan5d5d0012007-12-12 11:17:43 -08006972 bp->rx_offset = sizeof(struct l2_fhdr) + 2;
6973
Michael Chanb6016b72005-05-26 13:03:09 -07006974 bp->tx_ring_size = MAX_TX_DESC_CNT;
Michael Chan932f3772006-08-15 01:39:36 -07006975 bnx2_set_rx_ring_size(bp, 255);
Michael Chanb6016b72005-05-26 13:03:09 -07006976
6977 bp->rx_csum = 1;
6978
Michael Chanb6016b72005-05-26 13:03:09 -07006979 bp->tx_quick_cons_trip_int = 20;
6980 bp->tx_quick_cons_trip = 20;
6981 bp->tx_ticks_int = 80;
6982 bp->tx_ticks = 80;
Jeff Garzik6aa20a22006-09-13 13:24:59 -04006983
Michael Chanb6016b72005-05-26 13:03:09 -07006984 bp->rx_quick_cons_trip_int = 6;
6985 bp->rx_quick_cons_trip = 6;
6986 bp->rx_ticks_int = 18;
6987 bp->rx_ticks = 18;
6988
Michael Chan7ea69202007-07-16 18:27:10 -07006989 bp->stats_ticks = USEC_PER_SEC & BNX2_HC_STATS_TICKS_HC_STAT_TICKS;
Michael Chanb6016b72005-05-26 13:03:09 -07006990
6991 bp->timer_interval = HZ;
Michael Chancd339a02005-08-25 15:35:24 -07006992 bp->current_interval = HZ;
Michael Chanb6016b72005-05-26 13:03:09 -07006993
Michael Chan5b0c76a2005-11-04 08:45:49 -08006994 bp->phy_addr = 1;
6995
Michael Chanb6016b72005-05-26 13:03:09 -07006996 /* Disable WOL support if we are running on a SERDES chip. */
Michael Chan253c8b72007-01-08 19:56:01 -08006997 if (CHIP_NUM(bp) == CHIP_NUM_5709)
6998 bnx2_get_5709_media(bp);
6999 else if (CHIP_BOND_ID(bp) & CHIP_BOND_ID_SERDES_BIT)
Michael Chanb6016b72005-05-26 13:03:09 -07007000 bp->phy_flags |= PHY_SERDES_FLAG;
Michael Chanbac0dff2006-11-19 14:15:05 -08007001
Michael Chan0d8a6572007-07-07 22:49:43 -07007002 bp->phy_port = PORT_TP;
Michael Chanbac0dff2006-11-19 14:15:05 -08007003 if (bp->phy_flags & PHY_SERDES_FLAG) {
Michael Chan0d8a6572007-07-07 22:49:43 -07007004 bp->phy_port = PORT_FIBRE;
Michael Chan846f5c62007-10-10 16:16:51 -07007005 reg = REG_RD_IND(bp, bp->shmem_base +
7006 BNX2_SHARED_HW_CFG_CONFIG);
7007 if (!(reg & BNX2_SHARED_HW_CFG_GIG_LINK_ON_VAUX)) {
7008 bp->flags |= NO_WOL_FLAG;
7009 bp->wol = 0;
7010 }
Michael Chanbac0dff2006-11-19 14:15:05 -08007011 if (CHIP_NUM(bp) != CHIP_NUM_5706) {
Michael Chan5b0c76a2005-11-04 08:45:49 -08007012 bp->phy_addr = 2;
Michael Chan5b0c76a2005-11-04 08:45:49 -08007013 if (reg & BNX2_SHARED_HW_CFG_PHY_2_5G)
7014 bp->phy_flags |= PHY_2_5G_CAPABLE_FLAG;
7015 }
Michael Chan0d8a6572007-07-07 22:49:43 -07007016 bnx2_init_remote_phy(bp);
7017
Michael Chan261dd5c2007-01-08 19:55:46 -08007018 } else if (CHIP_NUM(bp) == CHIP_NUM_5706 ||
7019 CHIP_NUM(bp) == CHIP_NUM_5708)
7020 bp->phy_flags |= PHY_CRC_FIX_FLAG;
Michael Chanfb0c18b2007-12-10 17:18:23 -08007021 else if (CHIP_NUM(bp) == CHIP_NUM_5709 &&
7022 (CHIP_REV(bp) == CHIP_REV_Ax ||
7023 CHIP_REV(bp) == CHIP_REV_Bx))
Michael Chanb659f442007-02-02 00:46:35 -08007024 bp->phy_flags |= PHY_DIS_EARLY_DAC_FLAG;
Michael Chanb6016b72005-05-26 13:03:09 -07007025
Michael Chan16088272006-06-12 22:16:43 -07007026 if ((CHIP_ID(bp) == CHIP_ID_5708_A0) ||
7027 (CHIP_ID(bp) == CHIP_ID_5708_B0) ||
Michael Chan846f5c62007-10-10 16:16:51 -07007028 (CHIP_ID(bp) == CHIP_ID_5708_B1)) {
Michael Chandda1e392006-01-23 16:08:14 -08007029 bp->flags |= NO_WOL_FLAG;
Michael Chan846f5c62007-10-10 16:16:51 -07007030 bp->wol = 0;
7031 }
Michael Chandda1e392006-01-23 16:08:14 -08007032
Michael Chanb6016b72005-05-26 13:03:09 -07007033 if (CHIP_ID(bp) == CHIP_ID_5706_A0) {
7034 bp->tx_quick_cons_trip_int =
7035 bp->tx_quick_cons_trip;
7036 bp->tx_ticks_int = bp->tx_ticks;
7037 bp->rx_quick_cons_trip_int =
7038 bp->rx_quick_cons_trip;
7039 bp->rx_ticks_int = bp->rx_ticks;
7040 bp->comp_prod_trip_int = bp->comp_prod_trip;
7041 bp->com_ticks_int = bp->com_ticks;
7042 bp->cmd_ticks_int = bp->cmd_ticks;
7043 }
7044
Michael Chanf9317a42006-09-29 17:06:23 -07007045 /* Disable MSI on 5706 if AMD 8132 bridge is found.
7046 *
7047 * MSI is defined to be 32-bit write. The 5706 does 64-bit MSI writes
7048 * with byte enables disabled on the unused 32-bit word. This is legal
7049 * but causes problems on the AMD 8132 which will eventually stop
7050 * responding after a while.
7051 *
7052 * AMD believes this incompatibility is unique to the 5706, and
Michael Ellerman88187df2007-01-25 19:34:07 +11007053 * prefers to locally disable MSI rather than globally disabling it.
Michael Chanf9317a42006-09-29 17:06:23 -07007054 */
7055 if (CHIP_NUM(bp) == CHIP_NUM_5706 && disable_msi == 0) {
7056 struct pci_dev *amd_8132 = NULL;
7057
7058 while ((amd_8132 = pci_get_device(PCI_VENDOR_ID_AMD,
7059 PCI_DEVICE_ID_AMD_8132_BRIDGE,
7060 amd_8132))) {
Michael Chanf9317a42006-09-29 17:06:23 -07007061
Auke Kok44c10132007-06-08 15:46:36 -07007062 if (amd_8132->revision >= 0x10 &&
7063 amd_8132->revision <= 0x13) {
Michael Chanf9317a42006-09-29 17:06:23 -07007064 disable_msi = 1;
7065 pci_dev_put(amd_8132);
7066 break;
7067 }
7068 }
7069 }
7070
Michael Chandeaf3912007-07-07 22:48:00 -07007071 bnx2_set_default_link(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07007072 bp->req_flow_ctrl = FLOW_CTRL_RX | FLOW_CTRL_TX;
7073
Michael Chancd339a02005-08-25 15:35:24 -07007074 init_timer(&bp->timer);
7075 bp->timer.expires = RUN_AT(bp->timer_interval);
7076 bp->timer.data = (unsigned long) bp;
7077 bp->timer.function = bnx2_timer;
7078
Michael Chanb6016b72005-05-26 13:03:09 -07007079 return 0;
7080
7081err_out_unmap:
7082 if (bp->regview) {
7083 iounmap(bp->regview);
Michael Chan73eef4c2005-08-25 15:39:15 -07007084 bp->regview = NULL;
Michael Chanb6016b72005-05-26 13:03:09 -07007085 }
7086
7087err_out_release:
7088 pci_release_regions(pdev);
7089
7090err_out_disable:
7091 pci_disable_device(pdev);
7092 pci_set_drvdata(pdev, NULL);
7093
7094err_out:
7095 return rc;
7096}
7097
Michael Chan883e5152007-05-03 13:25:11 -07007098static char * __devinit
7099bnx2_bus_string(struct bnx2 *bp, char *str)
7100{
7101 char *s = str;
7102
7103 if (bp->flags & PCIE_FLAG) {
7104 s += sprintf(s, "PCI Express");
7105 } else {
7106 s += sprintf(s, "PCI");
7107 if (bp->flags & PCIX_FLAG)
7108 s += sprintf(s, "-X");
7109 if (bp->flags & PCI_32BIT_FLAG)
7110 s += sprintf(s, " 32-bit");
7111 else
7112 s += sprintf(s, " 64-bit");
7113 s += sprintf(s, " %dMHz", bp->bus_speed_mhz);
7114 }
7115 return str;
7116}
7117
Michael Chanb6016b72005-05-26 13:03:09 -07007118static int __devinit
Michael Chan35efa7c2007-12-20 19:56:37 -08007119bnx2_init_napi(struct bnx2 *bp)
7120{
7121 struct bnx2_napi *bnapi = &bp->bnx2_napi;
7122
7123 bnapi->bp = bp;
7124 netif_napi_add(bp->dev, &bnapi->napi, bnx2_poll, 64);
7125}
7126
7127static int __devinit
Michael Chanb6016b72005-05-26 13:03:09 -07007128bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
7129{
7130 static int version_printed = 0;
7131 struct net_device *dev = NULL;
7132 struct bnx2 *bp;
Joe Perches0795af52007-10-03 17:59:30 -07007133 int rc;
Michael Chan883e5152007-05-03 13:25:11 -07007134 char str[40];
Joe Perches0795af52007-10-03 17:59:30 -07007135 DECLARE_MAC_BUF(mac);
Michael Chanb6016b72005-05-26 13:03:09 -07007136
7137 if (version_printed++ == 0)
7138 printk(KERN_INFO "%s", version);
7139
7140 /* dev zeroed in init_etherdev */
7141 dev = alloc_etherdev(sizeof(*bp));
7142
7143 if (!dev)
7144 return -ENOMEM;
7145
7146 rc = bnx2_init_board(pdev, dev);
7147 if (rc < 0) {
7148 free_netdev(dev);
7149 return rc;
7150 }
7151
7152 dev->open = bnx2_open;
7153 dev->hard_start_xmit = bnx2_start_xmit;
7154 dev->stop = bnx2_close;
7155 dev->get_stats = bnx2_get_stats;
7156 dev->set_multicast_list = bnx2_set_rx_mode;
7157 dev->do_ioctl = bnx2_ioctl;
7158 dev->set_mac_address = bnx2_change_mac_addr;
7159 dev->change_mtu = bnx2_change_mtu;
7160 dev->tx_timeout = bnx2_tx_timeout;
7161 dev->watchdog_timeo = TX_TIMEOUT;
7162#ifdef BCM_VLAN
7163 dev->vlan_rx_register = bnx2_vlan_rx_register;
Michael Chanb6016b72005-05-26 13:03:09 -07007164#endif
Michael Chanb6016b72005-05-26 13:03:09 -07007165 dev->ethtool_ops = &bnx2_ethtool_ops;
Michael Chanb6016b72005-05-26 13:03:09 -07007166
Michael Chan972ec0d2006-01-23 16:12:43 -08007167 bp = netdev_priv(dev);
Michael Chan35efa7c2007-12-20 19:56:37 -08007168 bnx2_init_napi(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07007169
7170#if defined(HAVE_POLL_CONTROLLER) || defined(CONFIG_NET_POLL_CONTROLLER)
7171 dev->poll_controller = poll_bnx2;
7172#endif
7173
Michael Chan1b2f9222007-05-03 13:20:19 -07007174 pci_set_drvdata(pdev, dev);
7175
7176 memcpy(dev->dev_addr, bp->mac_addr, 6);
7177 memcpy(dev->perm_addr, bp->mac_addr, 6);
7178 bp->name = board_info[ent->driver_data].name;
7179
Stephen Hemmingerd212f872007-06-27 00:47:37 -07007180 dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG;
Michael Chan4666f872007-05-03 13:22:28 -07007181 if (CHIP_NUM(bp) == CHIP_NUM_5709)
Stephen Hemmingerd212f872007-06-27 00:47:37 -07007182 dev->features |= NETIF_F_IPV6_CSUM;
7183
Michael Chan1b2f9222007-05-03 13:20:19 -07007184#ifdef BCM_VLAN
7185 dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
7186#endif
7187 dev->features |= NETIF_F_TSO | NETIF_F_TSO_ECN;
Michael Chan4666f872007-05-03 13:22:28 -07007188 if (CHIP_NUM(bp) == CHIP_NUM_5709)
7189 dev->features |= NETIF_F_TSO6;
Michael Chan1b2f9222007-05-03 13:20:19 -07007190
Michael Chanb6016b72005-05-26 13:03:09 -07007191 if ((rc = register_netdev(dev))) {
Jeff Garzik9b91cf92006-06-27 11:39:50 -04007192 dev_err(&pdev->dev, "Cannot register net device\n");
Michael Chanb6016b72005-05-26 13:03:09 -07007193 if (bp->regview)
7194 iounmap(bp->regview);
7195 pci_release_regions(pdev);
7196 pci_disable_device(pdev);
7197 pci_set_drvdata(pdev, NULL);
7198 free_netdev(dev);
7199 return rc;
7200 }
7201
Michael Chan883e5152007-05-03 13:25:11 -07007202 printk(KERN_INFO "%s: %s (%c%d) %s found at mem %lx, "
Joe Perches0795af52007-10-03 17:59:30 -07007203 "IRQ %d, node addr %s\n",
Michael Chanb6016b72005-05-26 13:03:09 -07007204 dev->name,
7205 bp->name,
7206 ((CHIP_ID(bp) & 0xf000) >> 12) + 'A',
7207 ((CHIP_ID(bp) & 0x0ff0) >> 4),
Michael Chan883e5152007-05-03 13:25:11 -07007208 bnx2_bus_string(bp, str),
Michael Chanb6016b72005-05-26 13:03:09 -07007209 dev->base_addr,
Joe Perches0795af52007-10-03 17:59:30 -07007210 bp->pdev->irq, print_mac(mac, dev->dev_addr));
Michael Chanb6016b72005-05-26 13:03:09 -07007211
Michael Chanb6016b72005-05-26 13:03:09 -07007212 return 0;
7213}
7214
7215static void __devexit
7216bnx2_remove_one(struct pci_dev *pdev)
7217{
7218 struct net_device *dev = pci_get_drvdata(pdev);
Michael Chan972ec0d2006-01-23 16:12:43 -08007219 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007220
Michael Chanafdc08b2005-08-25 15:34:29 -07007221 flush_scheduled_work();
7222
Michael Chanb6016b72005-05-26 13:03:09 -07007223 unregister_netdev(dev);
7224
7225 if (bp->regview)
7226 iounmap(bp->regview);
7227
7228 free_netdev(dev);
7229 pci_release_regions(pdev);
7230 pci_disable_device(pdev);
7231 pci_set_drvdata(pdev, NULL);
7232}
7233
7234static int
Pavel Machek829ca9a2005-09-03 15:56:56 -07007235bnx2_suspend(struct pci_dev *pdev, pm_message_t state)
Michael Chanb6016b72005-05-26 13:03:09 -07007236{
7237 struct net_device *dev = pci_get_drvdata(pdev);
Michael Chan972ec0d2006-01-23 16:12:43 -08007238 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007239 u32 reset_code;
7240
Michael Chan6caebb02007-08-03 20:57:25 -07007241 /* PCI register 4 needs to be saved whether netif_running() or not.
7242 * MSI address and data need to be saved if using MSI and
7243 * netif_running().
7244 */
7245 pci_save_state(pdev);
Michael Chanb6016b72005-05-26 13:03:09 -07007246 if (!netif_running(dev))
7247 return 0;
7248
Michael Chan1d60290f2006-03-20 17:50:08 -08007249 flush_scheduled_work();
Michael Chanb6016b72005-05-26 13:03:09 -07007250 bnx2_netif_stop(bp);
7251 netif_device_detach(dev);
7252 del_timer_sync(&bp->timer);
Michael Chandda1e392006-01-23 16:08:14 -08007253 if (bp->flags & NO_WOL_FLAG)
Michael Chan6c4f0952006-06-29 12:38:15 -07007254 reset_code = BNX2_DRV_MSG_CODE_UNLOAD_LNK_DN;
Michael Chandda1e392006-01-23 16:08:14 -08007255 else if (bp->wol)
Michael Chanb6016b72005-05-26 13:03:09 -07007256 reset_code = BNX2_DRV_MSG_CODE_SUSPEND_WOL;
7257 else
7258 reset_code = BNX2_DRV_MSG_CODE_SUSPEND_NO_WOL;
7259 bnx2_reset_chip(bp, reset_code);
7260 bnx2_free_skbs(bp);
Pavel Machek829ca9a2005-09-03 15:56:56 -07007261 bnx2_set_power_state(bp, pci_choose_state(pdev, state));
Michael Chanb6016b72005-05-26 13:03:09 -07007262 return 0;
7263}
7264
7265static int
7266bnx2_resume(struct pci_dev *pdev)
7267{
7268 struct net_device *dev = pci_get_drvdata(pdev);
Michael Chan972ec0d2006-01-23 16:12:43 -08007269 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007270
Michael Chan6caebb02007-08-03 20:57:25 -07007271 pci_restore_state(pdev);
Michael Chanb6016b72005-05-26 13:03:09 -07007272 if (!netif_running(dev))
7273 return 0;
7274
Pavel Machek829ca9a2005-09-03 15:56:56 -07007275 bnx2_set_power_state(bp, PCI_D0);
Michael Chanb6016b72005-05-26 13:03:09 -07007276 netif_device_attach(dev);
7277 bnx2_init_nic(bp);
7278 bnx2_netif_start(bp);
7279 return 0;
7280}
7281
7282static struct pci_driver bnx2_pci_driver = {
Peter Hagervall14ab9b82005-08-10 14:18:16 -07007283 .name = DRV_MODULE_NAME,
7284 .id_table = bnx2_pci_tbl,
7285 .probe = bnx2_init_one,
7286 .remove = __devexit_p(bnx2_remove_one),
7287 .suspend = bnx2_suspend,
7288 .resume = bnx2_resume,
Michael Chanb6016b72005-05-26 13:03:09 -07007289};
7290
7291static int __init bnx2_init(void)
7292{
Jeff Garzik29917622006-08-19 17:48:59 -04007293 return pci_register_driver(&bnx2_pci_driver);
Michael Chanb6016b72005-05-26 13:03:09 -07007294}
7295
7296static void __exit bnx2_cleanup(void)
7297{
7298 pci_unregister_driver(&bnx2_pci_driver);
7299}
7300
7301module_init(bnx2_init);
7302module_exit(bnx2_cleanup);
7303
7304
7305