blob: 73d4a579790c5761f42aac5ddb3000ec0ba26d73 [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>
29#include <asm/bitops.h>
30#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
Denys Vlasenkob3448b02007-09-30 17:55:51 -070055#define FW_BUF_SIZE 0x8000
56
Michael Chanb6016b72005-05-26 13:03:09 -070057#define DRV_MODULE_NAME "bnx2"
58#define PFX DRV_MODULE_NAME ": "
Michael Chancd461712007-09-20 11:04:58 -070059#define DRV_MODULE_VERSION "1.6.5"
60#define DRV_MODULE_RELDATE "September 20, 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 Chane89bbf12005-08-25 15:36:58 -0700229static inline u32 bnx2_tx_avail(struct bnx2 *bp)
230{
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 */
238 diff = bp->tx_prod - bp->tx_cons;
239 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 Chanb6016b72005-05-26 13:03:09 -0700410 REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
Michael Chan1269a8a2006-01-23 16:11:03 -0800411 BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
412 BNX2_PCICFG_INT_ACK_CMD_MASK_INT | bp->last_status_idx);
413
414 REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
Michael Chanb6016b72005-05-26 13:03:09 -0700415 BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID | bp->last_status_idx);
416
Michael Chanbf5295b2006-03-23 01:11:56 -0800417 REG_WR(bp, BNX2_HC_COMMAND, bp->hc_cmd | BNX2_HC_COMMAND_COAL_NOW);
Michael Chanb6016b72005-05-26 13:03:09 -0700418}
419
420static void
421bnx2_disable_int_sync(struct bnx2 *bp)
422{
423 atomic_inc(&bp->intr_sem);
424 bnx2_disable_int(bp);
425 synchronize_irq(bp->pdev->irq);
426}
427
428static void
429bnx2_netif_stop(struct bnx2 *bp)
430{
431 bnx2_disable_int_sync(bp);
432 if (netif_running(bp->dev)) {
Stephen Hemmingerbea33482007-10-03 16:41:36 -0700433 napi_disable(&bp->napi);
Michael Chanb6016b72005-05-26 13:03:09 -0700434 netif_tx_disable(bp->dev);
435 bp->dev->trans_start = jiffies; /* prevent tx timeout */
436 }
437}
438
439static void
440bnx2_netif_start(struct bnx2 *bp)
441{
442 if (atomic_dec_and_test(&bp->intr_sem)) {
443 if (netif_running(bp->dev)) {
444 netif_wake_queue(bp->dev);
Stephen Hemmingerbea33482007-10-03 16:41:36 -0700445 napi_enable(&bp->napi);
Michael Chanb6016b72005-05-26 13:03:09 -0700446 bnx2_enable_int(bp);
447 }
448 }
449}
450
451static void
452bnx2_free_mem(struct bnx2 *bp)
453{
Michael Chan13daffa2006-03-20 17:49:20 -0800454 int i;
455
Michael Chan59b47d82006-11-19 14:10:45 -0800456 for (i = 0; i < bp->ctx_pages; i++) {
457 if (bp->ctx_blk[i]) {
458 pci_free_consistent(bp->pdev, BCM_PAGE_SIZE,
459 bp->ctx_blk[i],
460 bp->ctx_blk_mapping[i]);
461 bp->ctx_blk[i] = NULL;
462 }
463 }
Michael Chanb6016b72005-05-26 13:03:09 -0700464 if (bp->status_blk) {
Michael Chan0f31f992006-03-23 01:12:38 -0800465 pci_free_consistent(bp->pdev, bp->status_stats_size,
Michael Chanb6016b72005-05-26 13:03:09 -0700466 bp->status_blk, bp->status_blk_mapping);
467 bp->status_blk = NULL;
Michael Chan0f31f992006-03-23 01:12:38 -0800468 bp->stats_blk = NULL;
Michael Chanb6016b72005-05-26 13:03:09 -0700469 }
470 if (bp->tx_desc_ring) {
471 pci_free_consistent(bp->pdev,
472 sizeof(struct tx_bd) * TX_DESC_CNT,
473 bp->tx_desc_ring, bp->tx_desc_mapping);
474 bp->tx_desc_ring = NULL;
475 }
Jesper Juhlb4558ea2005-10-28 16:53:13 -0400476 kfree(bp->tx_buf_ring);
477 bp->tx_buf_ring = NULL;
Michael Chan13daffa2006-03-20 17:49:20 -0800478 for (i = 0; i < bp->rx_max_ring; i++) {
479 if (bp->rx_desc_ring[i])
480 pci_free_consistent(bp->pdev,
481 sizeof(struct rx_bd) * RX_DESC_CNT,
482 bp->rx_desc_ring[i],
483 bp->rx_desc_mapping[i]);
484 bp->rx_desc_ring[i] = NULL;
Michael Chanb6016b72005-05-26 13:03:09 -0700485 }
Michael Chan13daffa2006-03-20 17:49:20 -0800486 vfree(bp->rx_buf_ring);
Jesper Juhlb4558ea2005-10-28 16:53:13 -0400487 bp->rx_buf_ring = NULL;
Michael Chanb6016b72005-05-26 13:03:09 -0700488}
489
490static int
491bnx2_alloc_mem(struct bnx2 *bp)
492{
Michael Chan0f31f992006-03-23 01:12:38 -0800493 int i, status_blk_size;
Michael Chan13daffa2006-03-20 17:49:20 -0800494
Michael Chan0f31f992006-03-23 01:12:38 -0800495 bp->tx_buf_ring = kzalloc(sizeof(struct sw_bd) * TX_DESC_CNT,
496 GFP_KERNEL);
Michael Chanb6016b72005-05-26 13:03:09 -0700497 if (bp->tx_buf_ring == NULL)
498 return -ENOMEM;
499
Michael Chanb6016b72005-05-26 13:03:09 -0700500 bp->tx_desc_ring = pci_alloc_consistent(bp->pdev,
501 sizeof(struct tx_bd) *
502 TX_DESC_CNT,
503 &bp->tx_desc_mapping);
504 if (bp->tx_desc_ring == NULL)
505 goto alloc_mem_err;
506
Michael Chan13daffa2006-03-20 17:49:20 -0800507 bp->rx_buf_ring = vmalloc(sizeof(struct sw_bd) * RX_DESC_CNT *
508 bp->rx_max_ring);
Michael Chanb6016b72005-05-26 13:03:09 -0700509 if (bp->rx_buf_ring == NULL)
510 goto alloc_mem_err;
511
Michael Chan13daffa2006-03-20 17:49:20 -0800512 memset(bp->rx_buf_ring, 0, sizeof(struct sw_bd) * RX_DESC_CNT *
513 bp->rx_max_ring);
514
515 for (i = 0; i < bp->rx_max_ring; i++) {
516 bp->rx_desc_ring[i] =
517 pci_alloc_consistent(bp->pdev,
518 sizeof(struct rx_bd) * RX_DESC_CNT,
519 &bp->rx_desc_mapping[i]);
520 if (bp->rx_desc_ring[i] == NULL)
521 goto alloc_mem_err;
522
523 }
Michael Chanb6016b72005-05-26 13:03:09 -0700524
Michael Chan0f31f992006-03-23 01:12:38 -0800525 /* Combine status and statistics blocks into one allocation. */
526 status_blk_size = L1_CACHE_ALIGN(sizeof(struct status_block));
527 bp->status_stats_size = status_blk_size +
528 sizeof(struct statistics_block);
529
530 bp->status_blk = pci_alloc_consistent(bp->pdev, bp->status_stats_size,
Michael Chanb6016b72005-05-26 13:03:09 -0700531 &bp->status_blk_mapping);
532 if (bp->status_blk == NULL)
533 goto alloc_mem_err;
534
Michael Chan0f31f992006-03-23 01:12:38 -0800535 memset(bp->status_blk, 0, bp->status_stats_size);
Michael Chanb6016b72005-05-26 13:03:09 -0700536
Michael Chan0f31f992006-03-23 01:12:38 -0800537 bp->stats_blk = (void *) ((unsigned long) bp->status_blk +
538 status_blk_size);
Michael Chanb6016b72005-05-26 13:03:09 -0700539
Michael Chan0f31f992006-03-23 01:12:38 -0800540 bp->stats_blk_mapping = bp->status_blk_mapping + status_blk_size;
Michael Chanb6016b72005-05-26 13:03:09 -0700541
Michael Chan59b47d82006-11-19 14:10:45 -0800542 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
543 bp->ctx_pages = 0x2000 / BCM_PAGE_SIZE;
544 if (bp->ctx_pages == 0)
545 bp->ctx_pages = 1;
546 for (i = 0; i < bp->ctx_pages; i++) {
547 bp->ctx_blk[i] = pci_alloc_consistent(bp->pdev,
548 BCM_PAGE_SIZE,
549 &bp->ctx_blk_mapping[i]);
550 if (bp->ctx_blk[i] == NULL)
551 goto alloc_mem_err;
552 }
553 }
Michael Chanb6016b72005-05-26 13:03:09 -0700554 return 0;
555
556alloc_mem_err:
557 bnx2_free_mem(bp);
558 return -ENOMEM;
559}
560
561static void
Michael Chane3648b32005-11-04 08:51:21 -0800562bnx2_report_fw_link(struct bnx2 *bp)
563{
564 u32 fw_link_status = 0;
565
Michael Chan0d8a6572007-07-07 22:49:43 -0700566 if (bp->phy_flags & REMOTE_PHY_CAP_FLAG)
567 return;
568
Michael Chane3648b32005-11-04 08:51:21 -0800569 if (bp->link_up) {
570 u32 bmsr;
571
572 switch (bp->line_speed) {
573 case SPEED_10:
574 if (bp->duplex == DUPLEX_HALF)
575 fw_link_status = BNX2_LINK_STATUS_10HALF;
576 else
577 fw_link_status = BNX2_LINK_STATUS_10FULL;
578 break;
579 case SPEED_100:
580 if (bp->duplex == DUPLEX_HALF)
581 fw_link_status = BNX2_LINK_STATUS_100HALF;
582 else
583 fw_link_status = BNX2_LINK_STATUS_100FULL;
584 break;
585 case SPEED_1000:
586 if (bp->duplex == DUPLEX_HALF)
587 fw_link_status = BNX2_LINK_STATUS_1000HALF;
588 else
589 fw_link_status = BNX2_LINK_STATUS_1000FULL;
590 break;
591 case SPEED_2500:
592 if (bp->duplex == DUPLEX_HALF)
593 fw_link_status = BNX2_LINK_STATUS_2500HALF;
594 else
595 fw_link_status = BNX2_LINK_STATUS_2500FULL;
596 break;
597 }
598
599 fw_link_status |= BNX2_LINK_STATUS_LINK_UP;
600
601 if (bp->autoneg) {
602 fw_link_status |= BNX2_LINK_STATUS_AN_ENABLED;
603
Michael Chanca58c3a2007-05-03 13:22:52 -0700604 bnx2_read_phy(bp, bp->mii_bmsr, &bmsr);
605 bnx2_read_phy(bp, bp->mii_bmsr, &bmsr);
Michael Chane3648b32005-11-04 08:51:21 -0800606
607 if (!(bmsr & BMSR_ANEGCOMPLETE) ||
608 bp->phy_flags & PHY_PARALLEL_DETECT_FLAG)
609 fw_link_status |= BNX2_LINK_STATUS_PARALLEL_DET;
610 else
611 fw_link_status |= BNX2_LINK_STATUS_AN_COMPLETE;
612 }
613 }
614 else
615 fw_link_status = BNX2_LINK_STATUS_LINK_DOWN;
616
617 REG_WR_IND(bp, bp->shmem_base + BNX2_LINK_STATUS, fw_link_status);
618}
619
Michael Chan9b1084b2007-07-07 22:50:37 -0700620static char *
621bnx2_xceiver_str(struct bnx2 *bp)
622{
623 return ((bp->phy_port == PORT_FIBRE) ? "SerDes" :
624 ((bp->phy_flags & PHY_SERDES_FLAG) ? "Remote Copper" :
625 "Copper"));
626}
627
Michael Chane3648b32005-11-04 08:51:21 -0800628static void
Michael Chanb6016b72005-05-26 13:03:09 -0700629bnx2_report_link(struct bnx2 *bp)
630{
631 if (bp->link_up) {
632 netif_carrier_on(bp->dev);
Michael Chan9b1084b2007-07-07 22:50:37 -0700633 printk(KERN_INFO PFX "%s NIC %s Link is Up, ", bp->dev->name,
634 bnx2_xceiver_str(bp));
Michael Chanb6016b72005-05-26 13:03:09 -0700635
636 printk("%d Mbps ", bp->line_speed);
637
638 if (bp->duplex == DUPLEX_FULL)
639 printk("full duplex");
640 else
641 printk("half duplex");
642
643 if (bp->flow_ctrl) {
644 if (bp->flow_ctrl & FLOW_CTRL_RX) {
645 printk(", receive ");
646 if (bp->flow_ctrl & FLOW_CTRL_TX)
647 printk("& transmit ");
648 }
649 else {
650 printk(", transmit ");
651 }
652 printk("flow control ON");
653 }
654 printk("\n");
655 }
656 else {
657 netif_carrier_off(bp->dev);
Michael Chan9b1084b2007-07-07 22:50:37 -0700658 printk(KERN_ERR PFX "%s NIC %s Link is Down\n", bp->dev->name,
659 bnx2_xceiver_str(bp));
Michael Chanb6016b72005-05-26 13:03:09 -0700660 }
Michael Chane3648b32005-11-04 08:51:21 -0800661
662 bnx2_report_fw_link(bp);
Michael Chanb6016b72005-05-26 13:03:09 -0700663}
664
665static void
666bnx2_resolve_flow_ctrl(struct bnx2 *bp)
667{
668 u32 local_adv, remote_adv;
669
670 bp->flow_ctrl = 0;
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400671 if ((bp->autoneg & (AUTONEG_SPEED | AUTONEG_FLOW_CTRL)) !=
Michael Chanb6016b72005-05-26 13:03:09 -0700672 (AUTONEG_SPEED | AUTONEG_FLOW_CTRL)) {
673
674 if (bp->duplex == DUPLEX_FULL) {
675 bp->flow_ctrl = bp->req_flow_ctrl;
676 }
677 return;
678 }
679
680 if (bp->duplex != DUPLEX_FULL) {
681 return;
682 }
683
Michael Chan5b0c76a2005-11-04 08:45:49 -0800684 if ((bp->phy_flags & PHY_SERDES_FLAG) &&
685 (CHIP_NUM(bp) == CHIP_NUM_5708)) {
686 u32 val;
687
688 bnx2_read_phy(bp, BCM5708S_1000X_STAT1, &val);
689 if (val & BCM5708S_1000X_STAT1_TX_PAUSE)
690 bp->flow_ctrl |= FLOW_CTRL_TX;
691 if (val & BCM5708S_1000X_STAT1_RX_PAUSE)
692 bp->flow_ctrl |= FLOW_CTRL_RX;
693 return;
694 }
695
Michael Chanca58c3a2007-05-03 13:22:52 -0700696 bnx2_read_phy(bp, bp->mii_adv, &local_adv);
697 bnx2_read_phy(bp, bp->mii_lpa, &remote_adv);
Michael Chanb6016b72005-05-26 13:03:09 -0700698
699 if (bp->phy_flags & PHY_SERDES_FLAG) {
700 u32 new_local_adv = 0;
701 u32 new_remote_adv = 0;
702
703 if (local_adv & ADVERTISE_1000XPAUSE)
704 new_local_adv |= ADVERTISE_PAUSE_CAP;
705 if (local_adv & ADVERTISE_1000XPSE_ASYM)
706 new_local_adv |= ADVERTISE_PAUSE_ASYM;
707 if (remote_adv & ADVERTISE_1000XPAUSE)
708 new_remote_adv |= ADVERTISE_PAUSE_CAP;
709 if (remote_adv & ADVERTISE_1000XPSE_ASYM)
710 new_remote_adv |= ADVERTISE_PAUSE_ASYM;
711
712 local_adv = new_local_adv;
713 remote_adv = new_remote_adv;
714 }
715
716 /* See Table 28B-3 of 802.3ab-1999 spec. */
717 if (local_adv & ADVERTISE_PAUSE_CAP) {
718 if(local_adv & ADVERTISE_PAUSE_ASYM) {
719 if (remote_adv & ADVERTISE_PAUSE_CAP) {
720 bp->flow_ctrl = FLOW_CTRL_TX | FLOW_CTRL_RX;
721 }
722 else if (remote_adv & ADVERTISE_PAUSE_ASYM) {
723 bp->flow_ctrl = FLOW_CTRL_RX;
724 }
725 }
726 else {
727 if (remote_adv & ADVERTISE_PAUSE_CAP) {
728 bp->flow_ctrl = FLOW_CTRL_TX | FLOW_CTRL_RX;
729 }
730 }
731 }
732 else if (local_adv & ADVERTISE_PAUSE_ASYM) {
733 if ((remote_adv & ADVERTISE_PAUSE_CAP) &&
734 (remote_adv & ADVERTISE_PAUSE_ASYM)) {
735
736 bp->flow_ctrl = FLOW_CTRL_TX;
737 }
738 }
739}
740
741static int
Michael Chan27a005b2007-05-03 13:23:41 -0700742bnx2_5709s_linkup(struct bnx2 *bp)
743{
744 u32 val, speed;
745
746 bp->link_up = 1;
747
748 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_GP_STATUS);
749 bnx2_read_phy(bp, MII_BNX2_GP_TOP_AN_STATUS1, &val);
750 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
751
752 if ((bp->autoneg & AUTONEG_SPEED) == 0) {
753 bp->line_speed = bp->req_line_speed;
754 bp->duplex = bp->req_duplex;
755 return 0;
756 }
757 speed = val & MII_BNX2_GP_TOP_AN_SPEED_MSK;
758 switch (speed) {
759 case MII_BNX2_GP_TOP_AN_SPEED_10:
760 bp->line_speed = SPEED_10;
761 break;
762 case MII_BNX2_GP_TOP_AN_SPEED_100:
763 bp->line_speed = SPEED_100;
764 break;
765 case MII_BNX2_GP_TOP_AN_SPEED_1G:
766 case MII_BNX2_GP_TOP_AN_SPEED_1GKV:
767 bp->line_speed = SPEED_1000;
768 break;
769 case MII_BNX2_GP_TOP_AN_SPEED_2_5G:
770 bp->line_speed = SPEED_2500;
771 break;
772 }
773 if (val & MII_BNX2_GP_TOP_AN_FD)
774 bp->duplex = DUPLEX_FULL;
775 else
776 bp->duplex = DUPLEX_HALF;
777 return 0;
778}
779
780static int
Michael Chan5b0c76a2005-11-04 08:45:49 -0800781bnx2_5708s_linkup(struct bnx2 *bp)
782{
783 u32 val;
784
785 bp->link_up = 1;
786 bnx2_read_phy(bp, BCM5708S_1000X_STAT1, &val);
787 switch (val & BCM5708S_1000X_STAT1_SPEED_MASK) {
788 case BCM5708S_1000X_STAT1_SPEED_10:
789 bp->line_speed = SPEED_10;
790 break;
791 case BCM5708S_1000X_STAT1_SPEED_100:
792 bp->line_speed = SPEED_100;
793 break;
794 case BCM5708S_1000X_STAT1_SPEED_1G:
795 bp->line_speed = SPEED_1000;
796 break;
797 case BCM5708S_1000X_STAT1_SPEED_2G5:
798 bp->line_speed = SPEED_2500;
799 break;
800 }
801 if (val & BCM5708S_1000X_STAT1_FD)
802 bp->duplex = DUPLEX_FULL;
803 else
804 bp->duplex = DUPLEX_HALF;
805
806 return 0;
807}
808
809static int
810bnx2_5706s_linkup(struct bnx2 *bp)
Michael Chanb6016b72005-05-26 13:03:09 -0700811{
812 u32 bmcr, local_adv, remote_adv, common;
813
814 bp->link_up = 1;
815 bp->line_speed = SPEED_1000;
816
Michael Chanca58c3a2007-05-03 13:22:52 -0700817 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chanb6016b72005-05-26 13:03:09 -0700818 if (bmcr & BMCR_FULLDPLX) {
819 bp->duplex = DUPLEX_FULL;
820 }
821 else {
822 bp->duplex = DUPLEX_HALF;
823 }
824
825 if (!(bmcr & BMCR_ANENABLE)) {
826 return 0;
827 }
828
Michael Chanca58c3a2007-05-03 13:22:52 -0700829 bnx2_read_phy(bp, bp->mii_adv, &local_adv);
830 bnx2_read_phy(bp, bp->mii_lpa, &remote_adv);
Michael Chanb6016b72005-05-26 13:03:09 -0700831
832 common = local_adv & remote_adv;
833 if (common & (ADVERTISE_1000XHALF | ADVERTISE_1000XFULL)) {
834
835 if (common & ADVERTISE_1000XFULL) {
836 bp->duplex = DUPLEX_FULL;
837 }
838 else {
839 bp->duplex = DUPLEX_HALF;
840 }
841 }
842
843 return 0;
844}
845
846static int
847bnx2_copper_linkup(struct bnx2 *bp)
848{
849 u32 bmcr;
850
Michael Chanca58c3a2007-05-03 13:22:52 -0700851 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chanb6016b72005-05-26 13:03:09 -0700852 if (bmcr & BMCR_ANENABLE) {
853 u32 local_adv, remote_adv, common;
854
855 bnx2_read_phy(bp, MII_CTRL1000, &local_adv);
856 bnx2_read_phy(bp, MII_STAT1000, &remote_adv);
857
858 common = local_adv & (remote_adv >> 2);
859 if (common & ADVERTISE_1000FULL) {
860 bp->line_speed = SPEED_1000;
861 bp->duplex = DUPLEX_FULL;
862 }
863 else if (common & ADVERTISE_1000HALF) {
864 bp->line_speed = SPEED_1000;
865 bp->duplex = DUPLEX_HALF;
866 }
867 else {
Michael Chanca58c3a2007-05-03 13:22:52 -0700868 bnx2_read_phy(bp, bp->mii_adv, &local_adv);
869 bnx2_read_phy(bp, bp->mii_lpa, &remote_adv);
Michael Chanb6016b72005-05-26 13:03:09 -0700870
871 common = local_adv & remote_adv;
872 if (common & ADVERTISE_100FULL) {
873 bp->line_speed = SPEED_100;
874 bp->duplex = DUPLEX_FULL;
875 }
876 else if (common & ADVERTISE_100HALF) {
877 bp->line_speed = SPEED_100;
878 bp->duplex = DUPLEX_HALF;
879 }
880 else if (common & ADVERTISE_10FULL) {
881 bp->line_speed = SPEED_10;
882 bp->duplex = DUPLEX_FULL;
883 }
884 else if (common & ADVERTISE_10HALF) {
885 bp->line_speed = SPEED_10;
886 bp->duplex = DUPLEX_HALF;
887 }
888 else {
889 bp->line_speed = 0;
890 bp->link_up = 0;
891 }
892 }
893 }
894 else {
895 if (bmcr & BMCR_SPEED100) {
896 bp->line_speed = SPEED_100;
897 }
898 else {
899 bp->line_speed = SPEED_10;
900 }
901 if (bmcr & BMCR_FULLDPLX) {
902 bp->duplex = DUPLEX_FULL;
903 }
904 else {
905 bp->duplex = DUPLEX_HALF;
906 }
907 }
908
909 return 0;
910}
911
912static int
913bnx2_set_mac_link(struct bnx2 *bp)
914{
915 u32 val;
916
917 REG_WR(bp, BNX2_EMAC_TX_LENGTHS, 0x2620);
918 if (bp->link_up && (bp->line_speed == SPEED_1000) &&
919 (bp->duplex == DUPLEX_HALF)) {
920 REG_WR(bp, BNX2_EMAC_TX_LENGTHS, 0x26ff);
921 }
922
923 /* Configure the EMAC mode register. */
924 val = REG_RD(bp, BNX2_EMAC_MODE);
925
926 val &= ~(BNX2_EMAC_MODE_PORT | BNX2_EMAC_MODE_HALF_DUPLEX |
Michael Chan5b0c76a2005-11-04 08:45:49 -0800927 BNX2_EMAC_MODE_MAC_LOOP | BNX2_EMAC_MODE_FORCE_LINK |
Michael Chan59b47d82006-11-19 14:10:45 -0800928 BNX2_EMAC_MODE_25G_MODE);
Michael Chanb6016b72005-05-26 13:03:09 -0700929
930 if (bp->link_up) {
Michael Chan5b0c76a2005-11-04 08:45:49 -0800931 switch (bp->line_speed) {
932 case SPEED_10:
Michael Chan59b47d82006-11-19 14:10:45 -0800933 if (CHIP_NUM(bp) != CHIP_NUM_5706) {
934 val |= BNX2_EMAC_MODE_PORT_MII_10M;
Michael Chan5b0c76a2005-11-04 08:45:49 -0800935 break;
936 }
937 /* fall through */
938 case SPEED_100:
939 val |= BNX2_EMAC_MODE_PORT_MII;
940 break;
941 case SPEED_2500:
Michael Chan59b47d82006-11-19 14:10:45 -0800942 val |= BNX2_EMAC_MODE_25G_MODE;
Michael Chan5b0c76a2005-11-04 08:45:49 -0800943 /* fall through */
944 case SPEED_1000:
945 val |= BNX2_EMAC_MODE_PORT_GMII;
946 break;
947 }
Michael Chanb6016b72005-05-26 13:03:09 -0700948 }
949 else {
950 val |= BNX2_EMAC_MODE_PORT_GMII;
951 }
952
953 /* Set the MAC to operate in the appropriate duplex mode. */
954 if (bp->duplex == DUPLEX_HALF)
955 val |= BNX2_EMAC_MODE_HALF_DUPLEX;
956 REG_WR(bp, BNX2_EMAC_MODE, val);
957
958 /* Enable/disable rx PAUSE. */
959 bp->rx_mode &= ~BNX2_EMAC_RX_MODE_FLOW_EN;
960
961 if (bp->flow_ctrl & FLOW_CTRL_RX)
962 bp->rx_mode |= BNX2_EMAC_RX_MODE_FLOW_EN;
963 REG_WR(bp, BNX2_EMAC_RX_MODE, bp->rx_mode);
964
965 /* Enable/disable tx PAUSE. */
966 val = REG_RD(bp, BNX2_EMAC_TX_MODE);
967 val &= ~BNX2_EMAC_TX_MODE_FLOW_EN;
968
969 if (bp->flow_ctrl & FLOW_CTRL_TX)
970 val |= BNX2_EMAC_TX_MODE_FLOW_EN;
971 REG_WR(bp, BNX2_EMAC_TX_MODE, val);
972
973 /* Acknowledge the interrupt. */
974 REG_WR(bp, BNX2_EMAC_STATUS, BNX2_EMAC_STATUS_LINK_CHANGE);
975
976 return 0;
977}
978
Michael Chan27a005b2007-05-03 13:23:41 -0700979static void
980bnx2_enable_bmsr1(struct bnx2 *bp)
981{
982 if ((bp->phy_flags & PHY_SERDES_FLAG) &&
983 (CHIP_NUM(bp) == CHIP_NUM_5709))
984 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
985 MII_BNX2_BLK_ADDR_GP_STATUS);
986}
987
988static void
989bnx2_disable_bmsr1(struct bnx2 *bp)
990{
991 if ((bp->phy_flags & PHY_SERDES_FLAG) &&
992 (CHIP_NUM(bp) == CHIP_NUM_5709))
993 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
994 MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
995}
996
Michael Chanb6016b72005-05-26 13:03:09 -0700997static int
Michael Chan605a9e22007-05-03 13:23:13 -0700998bnx2_test_and_enable_2g5(struct bnx2 *bp)
999{
1000 u32 up1;
1001 int ret = 1;
1002
1003 if (!(bp->phy_flags & PHY_2_5G_CAPABLE_FLAG))
1004 return 0;
1005
1006 if (bp->autoneg & AUTONEG_SPEED)
1007 bp->advertising |= ADVERTISED_2500baseX_Full;
1008
Michael Chan27a005b2007-05-03 13:23:41 -07001009 if (CHIP_NUM(bp) == CHIP_NUM_5709)
1010 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_OVER1G);
1011
Michael Chan605a9e22007-05-03 13:23:13 -07001012 bnx2_read_phy(bp, bp->mii_up1, &up1);
1013 if (!(up1 & BCM5708S_UP1_2G5)) {
1014 up1 |= BCM5708S_UP1_2G5;
1015 bnx2_write_phy(bp, bp->mii_up1, up1);
1016 ret = 0;
1017 }
1018
Michael Chan27a005b2007-05-03 13:23:41 -07001019 if (CHIP_NUM(bp) == CHIP_NUM_5709)
1020 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
1021 MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
1022
Michael Chan605a9e22007-05-03 13:23:13 -07001023 return ret;
1024}
1025
1026static int
1027bnx2_test_and_disable_2g5(struct bnx2 *bp)
1028{
1029 u32 up1;
1030 int ret = 0;
1031
1032 if (!(bp->phy_flags & PHY_2_5G_CAPABLE_FLAG))
1033 return 0;
1034
Michael Chan27a005b2007-05-03 13:23:41 -07001035 if (CHIP_NUM(bp) == CHIP_NUM_5709)
1036 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_OVER1G);
1037
Michael Chan605a9e22007-05-03 13:23:13 -07001038 bnx2_read_phy(bp, bp->mii_up1, &up1);
1039 if (up1 & BCM5708S_UP1_2G5) {
1040 up1 &= ~BCM5708S_UP1_2G5;
1041 bnx2_write_phy(bp, bp->mii_up1, up1);
1042 ret = 1;
1043 }
1044
Michael Chan27a005b2007-05-03 13:23:41 -07001045 if (CHIP_NUM(bp) == CHIP_NUM_5709)
1046 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
1047 MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
1048
Michael Chan605a9e22007-05-03 13:23:13 -07001049 return ret;
1050}
1051
1052static void
1053bnx2_enable_forced_2g5(struct bnx2 *bp)
1054{
1055 u32 bmcr;
1056
1057 if (!(bp->phy_flags & PHY_2_5G_CAPABLE_FLAG))
1058 return;
1059
Michael Chan27a005b2007-05-03 13:23:41 -07001060 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
1061 u32 val;
1062
1063 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
1064 MII_BNX2_BLK_ADDR_SERDES_DIG);
1065 bnx2_read_phy(bp, MII_BNX2_SERDES_DIG_MISC1, &val);
1066 val &= ~MII_BNX2_SD_MISC1_FORCE_MSK;
1067 val |= MII_BNX2_SD_MISC1_FORCE | MII_BNX2_SD_MISC1_FORCE_2_5G;
1068 bnx2_write_phy(bp, MII_BNX2_SERDES_DIG_MISC1, val);
1069
1070 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
1071 MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
1072 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
1073
1074 } else if (CHIP_NUM(bp) == CHIP_NUM_5708) {
Michael Chan605a9e22007-05-03 13:23:13 -07001075 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
1076 bmcr |= BCM5708S_BMCR_FORCE_2500;
1077 }
1078
1079 if (bp->autoneg & AUTONEG_SPEED) {
1080 bmcr &= ~BMCR_ANENABLE;
1081 if (bp->req_duplex == DUPLEX_FULL)
1082 bmcr |= BMCR_FULLDPLX;
1083 }
1084 bnx2_write_phy(bp, bp->mii_bmcr, bmcr);
1085}
1086
1087static void
1088bnx2_disable_forced_2g5(struct bnx2 *bp)
1089{
1090 u32 bmcr;
1091
1092 if (!(bp->phy_flags & PHY_2_5G_CAPABLE_FLAG))
1093 return;
1094
Michael Chan27a005b2007-05-03 13:23:41 -07001095 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
1096 u32 val;
1097
1098 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
1099 MII_BNX2_BLK_ADDR_SERDES_DIG);
1100 bnx2_read_phy(bp, MII_BNX2_SERDES_DIG_MISC1, &val);
1101 val &= ~MII_BNX2_SD_MISC1_FORCE;
1102 bnx2_write_phy(bp, MII_BNX2_SERDES_DIG_MISC1, val);
1103
1104 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
1105 MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
1106 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
1107
1108 } else if (CHIP_NUM(bp) == CHIP_NUM_5708) {
Michael Chan605a9e22007-05-03 13:23:13 -07001109 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
1110 bmcr &= ~BCM5708S_BMCR_FORCE_2500;
1111 }
1112
1113 if (bp->autoneg & AUTONEG_SPEED)
1114 bmcr |= BMCR_SPEED1000 | BMCR_ANENABLE | BMCR_ANRESTART;
1115 bnx2_write_phy(bp, bp->mii_bmcr, bmcr);
1116}
1117
1118static int
Michael Chanb6016b72005-05-26 13:03:09 -07001119bnx2_set_link(struct bnx2 *bp)
1120{
1121 u32 bmsr;
1122 u8 link_up;
1123
Michael Chan80be4432006-11-19 14:07:28 -08001124 if (bp->loopback == MAC_LOOPBACK || bp->loopback == PHY_LOOPBACK) {
Michael Chanb6016b72005-05-26 13:03:09 -07001125 bp->link_up = 1;
1126 return 0;
1127 }
1128
Michael Chan0d8a6572007-07-07 22:49:43 -07001129 if (bp->phy_flags & REMOTE_PHY_CAP_FLAG)
1130 return 0;
1131
Michael Chanb6016b72005-05-26 13:03:09 -07001132 link_up = bp->link_up;
1133
Michael Chan27a005b2007-05-03 13:23:41 -07001134 bnx2_enable_bmsr1(bp);
1135 bnx2_read_phy(bp, bp->mii_bmsr1, &bmsr);
1136 bnx2_read_phy(bp, bp->mii_bmsr1, &bmsr);
1137 bnx2_disable_bmsr1(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07001138
1139 if ((bp->phy_flags & PHY_SERDES_FLAG) &&
1140 (CHIP_NUM(bp) == CHIP_NUM_5706)) {
1141 u32 val;
1142
1143 val = REG_RD(bp, BNX2_EMAC_STATUS);
1144 if (val & BNX2_EMAC_STATUS_LINK)
1145 bmsr |= BMSR_LSTATUS;
1146 else
1147 bmsr &= ~BMSR_LSTATUS;
1148 }
1149
1150 if (bmsr & BMSR_LSTATUS) {
1151 bp->link_up = 1;
1152
1153 if (bp->phy_flags & PHY_SERDES_FLAG) {
Michael Chan5b0c76a2005-11-04 08:45:49 -08001154 if (CHIP_NUM(bp) == CHIP_NUM_5706)
1155 bnx2_5706s_linkup(bp);
1156 else if (CHIP_NUM(bp) == CHIP_NUM_5708)
1157 bnx2_5708s_linkup(bp);
Michael Chan27a005b2007-05-03 13:23:41 -07001158 else if (CHIP_NUM(bp) == CHIP_NUM_5709)
1159 bnx2_5709s_linkup(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07001160 }
1161 else {
1162 bnx2_copper_linkup(bp);
1163 }
1164 bnx2_resolve_flow_ctrl(bp);
1165 }
1166 else {
1167 if ((bp->phy_flags & PHY_SERDES_FLAG) &&
Michael Chan605a9e22007-05-03 13:23:13 -07001168 (bp->autoneg & AUTONEG_SPEED))
1169 bnx2_disable_forced_2g5(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07001170
Michael Chanb6016b72005-05-26 13:03:09 -07001171 bp->phy_flags &= ~PHY_PARALLEL_DETECT_FLAG;
1172 bp->link_up = 0;
1173 }
1174
1175 if (bp->link_up != link_up) {
1176 bnx2_report_link(bp);
1177 }
1178
1179 bnx2_set_mac_link(bp);
1180
1181 return 0;
1182}
1183
1184static int
1185bnx2_reset_phy(struct bnx2 *bp)
1186{
1187 int i;
1188 u32 reg;
1189
Michael Chanca58c3a2007-05-03 13:22:52 -07001190 bnx2_write_phy(bp, bp->mii_bmcr, BMCR_RESET);
Michael Chanb6016b72005-05-26 13:03:09 -07001191
1192#define PHY_RESET_MAX_WAIT 100
1193 for (i = 0; i < PHY_RESET_MAX_WAIT; i++) {
1194 udelay(10);
1195
Michael Chanca58c3a2007-05-03 13:22:52 -07001196 bnx2_read_phy(bp, bp->mii_bmcr, &reg);
Michael Chanb6016b72005-05-26 13:03:09 -07001197 if (!(reg & BMCR_RESET)) {
1198 udelay(20);
1199 break;
1200 }
1201 }
1202 if (i == PHY_RESET_MAX_WAIT) {
1203 return -EBUSY;
1204 }
1205 return 0;
1206}
1207
1208static u32
1209bnx2_phy_get_pause_adv(struct bnx2 *bp)
1210{
1211 u32 adv = 0;
1212
1213 if ((bp->req_flow_ctrl & (FLOW_CTRL_RX | FLOW_CTRL_TX)) ==
1214 (FLOW_CTRL_RX | FLOW_CTRL_TX)) {
1215
1216 if (bp->phy_flags & PHY_SERDES_FLAG) {
1217 adv = ADVERTISE_1000XPAUSE;
1218 }
1219 else {
1220 adv = ADVERTISE_PAUSE_CAP;
1221 }
1222 }
1223 else if (bp->req_flow_ctrl & FLOW_CTRL_TX) {
1224 if (bp->phy_flags & PHY_SERDES_FLAG) {
1225 adv = ADVERTISE_1000XPSE_ASYM;
1226 }
1227 else {
1228 adv = ADVERTISE_PAUSE_ASYM;
1229 }
1230 }
1231 else if (bp->req_flow_ctrl & FLOW_CTRL_RX) {
1232 if (bp->phy_flags & PHY_SERDES_FLAG) {
1233 adv = ADVERTISE_1000XPAUSE | ADVERTISE_1000XPSE_ASYM;
1234 }
1235 else {
1236 adv = ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM;
1237 }
1238 }
1239 return adv;
1240}
1241
Michael Chan0d8a6572007-07-07 22:49:43 -07001242static int bnx2_fw_sync(struct bnx2 *, u32, int);
1243
Michael Chanb6016b72005-05-26 13:03:09 -07001244static int
Michael Chan0d8a6572007-07-07 22:49:43 -07001245bnx2_setup_remote_phy(struct bnx2 *bp, u8 port)
1246{
1247 u32 speed_arg = 0, pause_adv;
1248
1249 pause_adv = bnx2_phy_get_pause_adv(bp);
1250
1251 if (bp->autoneg & AUTONEG_SPEED) {
1252 speed_arg |= BNX2_NETLINK_SET_LINK_ENABLE_AUTONEG;
1253 if (bp->advertising & ADVERTISED_10baseT_Half)
1254 speed_arg |= BNX2_NETLINK_SET_LINK_SPEED_10HALF;
1255 if (bp->advertising & ADVERTISED_10baseT_Full)
1256 speed_arg |= BNX2_NETLINK_SET_LINK_SPEED_10FULL;
1257 if (bp->advertising & ADVERTISED_100baseT_Half)
1258 speed_arg |= BNX2_NETLINK_SET_LINK_SPEED_100HALF;
1259 if (bp->advertising & ADVERTISED_100baseT_Full)
1260 speed_arg |= BNX2_NETLINK_SET_LINK_SPEED_100FULL;
1261 if (bp->advertising & ADVERTISED_1000baseT_Full)
1262 speed_arg |= BNX2_NETLINK_SET_LINK_SPEED_1GFULL;
1263 if (bp->advertising & ADVERTISED_2500baseX_Full)
1264 speed_arg |= BNX2_NETLINK_SET_LINK_SPEED_2G5FULL;
1265 } else {
1266 if (bp->req_line_speed == SPEED_2500)
1267 speed_arg = BNX2_NETLINK_SET_LINK_SPEED_2G5FULL;
1268 else if (bp->req_line_speed == SPEED_1000)
1269 speed_arg = BNX2_NETLINK_SET_LINK_SPEED_1GFULL;
1270 else if (bp->req_line_speed == SPEED_100) {
1271 if (bp->req_duplex == DUPLEX_FULL)
1272 speed_arg = BNX2_NETLINK_SET_LINK_SPEED_100FULL;
1273 else
1274 speed_arg = BNX2_NETLINK_SET_LINK_SPEED_100HALF;
1275 } else if (bp->req_line_speed == SPEED_10) {
1276 if (bp->req_duplex == DUPLEX_FULL)
1277 speed_arg = BNX2_NETLINK_SET_LINK_SPEED_10FULL;
1278 else
1279 speed_arg = BNX2_NETLINK_SET_LINK_SPEED_10HALF;
1280 }
1281 }
1282
1283 if (pause_adv & (ADVERTISE_1000XPAUSE | ADVERTISE_PAUSE_CAP))
1284 speed_arg |= BNX2_NETLINK_SET_LINK_FC_SYM_PAUSE;
1285 if (pause_adv & (ADVERTISE_1000XPSE_ASYM | ADVERTISE_1000XPSE_ASYM))
1286 speed_arg |= BNX2_NETLINK_SET_LINK_FC_ASYM_PAUSE;
1287
1288 if (port == PORT_TP)
1289 speed_arg |= BNX2_NETLINK_SET_LINK_PHY_APP_REMOTE |
1290 BNX2_NETLINK_SET_LINK_ETH_AT_WIRESPEED;
1291
1292 REG_WR_IND(bp, bp->shmem_base + BNX2_DRV_MB_ARG0, speed_arg);
1293
1294 spin_unlock_bh(&bp->phy_lock);
1295 bnx2_fw_sync(bp, BNX2_DRV_MSG_CODE_CMD_SET_LINK, 0);
1296 spin_lock_bh(&bp->phy_lock);
1297
1298 return 0;
1299}
1300
1301static int
1302bnx2_setup_serdes_phy(struct bnx2 *bp, u8 port)
Michael Chanb6016b72005-05-26 13:03:09 -07001303{
Michael Chan605a9e22007-05-03 13:23:13 -07001304 u32 adv, bmcr;
Michael Chanb6016b72005-05-26 13:03:09 -07001305 u32 new_adv = 0;
1306
Michael Chan0d8a6572007-07-07 22:49:43 -07001307 if (bp->phy_flags & REMOTE_PHY_CAP_FLAG)
1308 return (bnx2_setup_remote_phy(bp, port));
1309
Michael Chanb6016b72005-05-26 13:03:09 -07001310 if (!(bp->autoneg & AUTONEG_SPEED)) {
1311 u32 new_bmcr;
Michael Chan5b0c76a2005-11-04 08:45:49 -08001312 int force_link_down = 0;
1313
Michael Chan605a9e22007-05-03 13:23:13 -07001314 if (bp->req_line_speed == SPEED_2500) {
1315 if (!bnx2_test_and_enable_2g5(bp))
1316 force_link_down = 1;
1317 } else if (bp->req_line_speed == SPEED_1000) {
1318 if (bnx2_test_and_disable_2g5(bp))
1319 force_link_down = 1;
1320 }
Michael Chanca58c3a2007-05-03 13:22:52 -07001321 bnx2_read_phy(bp, bp->mii_adv, &adv);
Michael Chan80be4432006-11-19 14:07:28 -08001322 adv &= ~(ADVERTISE_1000XFULL | ADVERTISE_1000XHALF);
1323
Michael Chanca58c3a2007-05-03 13:22:52 -07001324 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chan605a9e22007-05-03 13:23:13 -07001325 new_bmcr = bmcr & ~BMCR_ANENABLE;
Michael Chan80be4432006-11-19 14:07:28 -08001326 new_bmcr |= BMCR_SPEED1000;
Michael Chan605a9e22007-05-03 13:23:13 -07001327
Michael Chan27a005b2007-05-03 13:23:41 -07001328 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
1329 if (bp->req_line_speed == SPEED_2500)
1330 bnx2_enable_forced_2g5(bp);
1331 else if (bp->req_line_speed == SPEED_1000) {
1332 bnx2_disable_forced_2g5(bp);
1333 new_bmcr &= ~0x2000;
1334 }
1335
1336 } else if (CHIP_NUM(bp) == CHIP_NUM_5708) {
Michael Chan605a9e22007-05-03 13:23:13 -07001337 if (bp->req_line_speed == SPEED_2500)
1338 new_bmcr |= BCM5708S_BMCR_FORCE_2500;
1339 else
1340 new_bmcr = bmcr & ~BCM5708S_BMCR_FORCE_2500;
Michael Chan5b0c76a2005-11-04 08:45:49 -08001341 }
1342
Michael Chanb6016b72005-05-26 13:03:09 -07001343 if (bp->req_duplex == DUPLEX_FULL) {
Michael Chan5b0c76a2005-11-04 08:45:49 -08001344 adv |= ADVERTISE_1000XFULL;
Michael Chanb6016b72005-05-26 13:03:09 -07001345 new_bmcr |= BMCR_FULLDPLX;
1346 }
1347 else {
Michael Chan5b0c76a2005-11-04 08:45:49 -08001348 adv |= ADVERTISE_1000XHALF;
Michael Chanb6016b72005-05-26 13:03:09 -07001349 new_bmcr &= ~BMCR_FULLDPLX;
1350 }
Michael Chan5b0c76a2005-11-04 08:45:49 -08001351 if ((new_bmcr != bmcr) || (force_link_down)) {
Michael Chanb6016b72005-05-26 13:03:09 -07001352 /* Force a link down visible on the other side */
1353 if (bp->link_up) {
Michael Chanca58c3a2007-05-03 13:22:52 -07001354 bnx2_write_phy(bp, bp->mii_adv, adv &
Michael Chan5b0c76a2005-11-04 08:45:49 -08001355 ~(ADVERTISE_1000XFULL |
1356 ADVERTISE_1000XHALF));
Michael Chanca58c3a2007-05-03 13:22:52 -07001357 bnx2_write_phy(bp, bp->mii_bmcr, bmcr |
Michael Chanb6016b72005-05-26 13:03:09 -07001358 BMCR_ANRESTART | BMCR_ANENABLE);
1359
1360 bp->link_up = 0;
1361 netif_carrier_off(bp->dev);
Michael Chanca58c3a2007-05-03 13:22:52 -07001362 bnx2_write_phy(bp, bp->mii_bmcr, new_bmcr);
Michael Chan80be4432006-11-19 14:07:28 -08001363 bnx2_report_link(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07001364 }
Michael Chanca58c3a2007-05-03 13:22:52 -07001365 bnx2_write_phy(bp, bp->mii_adv, adv);
1366 bnx2_write_phy(bp, bp->mii_bmcr, new_bmcr);
Michael Chan605a9e22007-05-03 13:23:13 -07001367 } else {
1368 bnx2_resolve_flow_ctrl(bp);
1369 bnx2_set_mac_link(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07001370 }
1371 return 0;
1372 }
1373
Michael Chan605a9e22007-05-03 13:23:13 -07001374 bnx2_test_and_enable_2g5(bp);
Michael Chan5b0c76a2005-11-04 08:45:49 -08001375
Michael Chanb6016b72005-05-26 13:03:09 -07001376 if (bp->advertising & ADVERTISED_1000baseT_Full)
1377 new_adv |= ADVERTISE_1000XFULL;
1378
1379 new_adv |= bnx2_phy_get_pause_adv(bp);
1380
Michael Chanca58c3a2007-05-03 13:22:52 -07001381 bnx2_read_phy(bp, bp->mii_adv, &adv);
1382 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chanb6016b72005-05-26 13:03:09 -07001383
1384 bp->serdes_an_pending = 0;
1385 if ((adv != new_adv) || ((bmcr & BMCR_ANENABLE) == 0)) {
1386 /* Force a link down visible on the other side */
1387 if (bp->link_up) {
Michael Chanca58c3a2007-05-03 13:22:52 -07001388 bnx2_write_phy(bp, bp->mii_bmcr, BMCR_LOOPBACK);
Michael Chan80be4432006-11-19 14:07:28 -08001389 spin_unlock_bh(&bp->phy_lock);
1390 msleep(20);
1391 spin_lock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07001392 }
1393
Michael Chanca58c3a2007-05-03 13:22:52 -07001394 bnx2_write_phy(bp, bp->mii_adv, new_adv);
1395 bnx2_write_phy(bp, bp->mii_bmcr, bmcr | BMCR_ANRESTART |
Michael Chanb6016b72005-05-26 13:03:09 -07001396 BMCR_ANENABLE);
Michael Chanf8dd0642006-11-19 14:08:29 -08001397 /* Speed up link-up time when the link partner
1398 * does not autonegotiate which is very common
1399 * in blade servers. Some blade servers use
1400 * IPMI for kerboard input and it's important
1401 * to minimize link disruptions. Autoneg. involves
1402 * exchanging base pages plus 3 next pages and
1403 * normally completes in about 120 msec.
1404 */
1405 bp->current_interval = SERDES_AN_TIMEOUT;
1406 bp->serdes_an_pending = 1;
1407 mod_timer(&bp->timer, jiffies + bp->current_interval);
Michael Chan605a9e22007-05-03 13:23:13 -07001408 } else {
1409 bnx2_resolve_flow_ctrl(bp);
1410 bnx2_set_mac_link(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07001411 }
1412
1413 return 0;
1414}
1415
1416#define ETHTOOL_ALL_FIBRE_SPEED \
Michael Chandeaf3912007-07-07 22:48:00 -07001417 (bp->phy_flags & PHY_2_5G_CAPABLE_FLAG) ? \
1418 (ADVERTISED_2500baseX_Full | ADVERTISED_1000baseT_Full) :\
1419 (ADVERTISED_1000baseT_Full)
Michael Chanb6016b72005-05-26 13:03:09 -07001420
1421#define ETHTOOL_ALL_COPPER_SPEED \
1422 (ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full | \
1423 ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full | \
1424 ADVERTISED_1000baseT_Full)
1425
1426#define PHY_ALL_10_100_SPEED (ADVERTISE_10HALF | ADVERTISE_10FULL | \
1427 ADVERTISE_100HALF | ADVERTISE_100FULL | ADVERTISE_CSMA)
Jeff Garzik6aa20a22006-09-13 13:24:59 -04001428
Michael Chanb6016b72005-05-26 13:03:09 -07001429#define PHY_ALL_1000_SPEED (ADVERTISE_1000HALF | ADVERTISE_1000FULL)
1430
Michael Chandeaf3912007-07-07 22:48:00 -07001431static void
Michael Chan0d8a6572007-07-07 22:49:43 -07001432bnx2_set_default_remote_link(struct bnx2 *bp)
1433{
1434 u32 link;
1435
1436 if (bp->phy_port == PORT_TP)
1437 link = REG_RD_IND(bp, bp->shmem_base + BNX2_RPHY_COPPER_LINK);
1438 else
1439 link = REG_RD_IND(bp, bp->shmem_base + BNX2_RPHY_SERDES_LINK);
1440
1441 if (link & BNX2_NETLINK_SET_LINK_ENABLE_AUTONEG) {
1442 bp->req_line_speed = 0;
1443 bp->autoneg |= AUTONEG_SPEED;
1444 bp->advertising = ADVERTISED_Autoneg;
1445 if (link & BNX2_NETLINK_SET_LINK_SPEED_10HALF)
1446 bp->advertising |= ADVERTISED_10baseT_Half;
1447 if (link & BNX2_NETLINK_SET_LINK_SPEED_10FULL)
1448 bp->advertising |= ADVERTISED_10baseT_Full;
1449 if (link & BNX2_NETLINK_SET_LINK_SPEED_100HALF)
1450 bp->advertising |= ADVERTISED_100baseT_Half;
1451 if (link & BNX2_NETLINK_SET_LINK_SPEED_100FULL)
1452 bp->advertising |= ADVERTISED_100baseT_Full;
1453 if (link & BNX2_NETLINK_SET_LINK_SPEED_1GFULL)
1454 bp->advertising |= ADVERTISED_1000baseT_Full;
1455 if (link & BNX2_NETLINK_SET_LINK_SPEED_2G5FULL)
1456 bp->advertising |= ADVERTISED_2500baseX_Full;
1457 } else {
1458 bp->autoneg = 0;
1459 bp->advertising = 0;
1460 bp->req_duplex = DUPLEX_FULL;
1461 if (link & BNX2_NETLINK_SET_LINK_SPEED_10) {
1462 bp->req_line_speed = SPEED_10;
1463 if (link & BNX2_NETLINK_SET_LINK_SPEED_10HALF)
1464 bp->req_duplex = DUPLEX_HALF;
1465 }
1466 if (link & BNX2_NETLINK_SET_LINK_SPEED_100) {
1467 bp->req_line_speed = SPEED_100;
1468 if (link & BNX2_NETLINK_SET_LINK_SPEED_100HALF)
1469 bp->req_duplex = DUPLEX_HALF;
1470 }
1471 if (link & BNX2_NETLINK_SET_LINK_SPEED_1GFULL)
1472 bp->req_line_speed = SPEED_1000;
1473 if (link & BNX2_NETLINK_SET_LINK_SPEED_2G5FULL)
1474 bp->req_line_speed = SPEED_2500;
1475 }
1476}
1477
1478static void
Michael Chandeaf3912007-07-07 22:48:00 -07001479bnx2_set_default_link(struct bnx2 *bp)
1480{
Michael Chan0d8a6572007-07-07 22:49:43 -07001481 if (bp->phy_flags & REMOTE_PHY_CAP_FLAG)
1482 return bnx2_set_default_remote_link(bp);
1483
Michael Chandeaf3912007-07-07 22:48:00 -07001484 bp->autoneg = AUTONEG_SPEED | AUTONEG_FLOW_CTRL;
1485 bp->req_line_speed = 0;
1486 if (bp->phy_flags & PHY_SERDES_FLAG) {
1487 u32 reg;
1488
1489 bp->advertising = ETHTOOL_ALL_FIBRE_SPEED | ADVERTISED_Autoneg;
1490
1491 reg = REG_RD_IND(bp, bp->shmem_base + BNX2_PORT_HW_CFG_CONFIG);
1492 reg &= BNX2_PORT_HW_CFG_CFG_DFLT_LINK_MASK;
1493 if (reg == BNX2_PORT_HW_CFG_CFG_DFLT_LINK_1G) {
1494 bp->autoneg = 0;
1495 bp->req_line_speed = bp->line_speed = SPEED_1000;
1496 bp->req_duplex = DUPLEX_FULL;
1497 }
1498 } else
1499 bp->advertising = ETHTOOL_ALL_COPPER_SPEED | ADVERTISED_Autoneg;
1500}
1501
Michael Chan0d8a6572007-07-07 22:49:43 -07001502static void
Michael Chandf149d72007-07-07 22:51:36 -07001503bnx2_send_heart_beat(struct bnx2 *bp)
1504{
1505 u32 msg;
1506 u32 addr;
1507
1508 spin_lock(&bp->indirect_lock);
1509 msg = (u32) (++bp->fw_drv_pulse_wr_seq & BNX2_DRV_PULSE_SEQ_MASK);
1510 addr = bp->shmem_base + BNX2_DRV_PULSE_MB;
1511 REG_WR(bp, BNX2_PCICFG_REG_WINDOW_ADDRESS, addr);
1512 REG_WR(bp, BNX2_PCICFG_REG_WINDOW, msg);
1513 spin_unlock(&bp->indirect_lock);
1514}
1515
1516static void
Michael Chan0d8a6572007-07-07 22:49:43 -07001517bnx2_remote_phy_event(struct bnx2 *bp)
1518{
1519 u32 msg;
1520 u8 link_up = bp->link_up;
1521 u8 old_port;
1522
1523 msg = REG_RD_IND(bp, bp->shmem_base + BNX2_LINK_STATUS);
1524
Michael Chandf149d72007-07-07 22:51:36 -07001525 if (msg & BNX2_LINK_STATUS_HEART_BEAT_EXPIRED)
1526 bnx2_send_heart_beat(bp);
1527
1528 msg &= ~BNX2_LINK_STATUS_HEART_BEAT_EXPIRED;
1529
Michael Chan0d8a6572007-07-07 22:49:43 -07001530 if ((msg & BNX2_LINK_STATUS_LINK_UP) == BNX2_LINK_STATUS_LINK_DOWN)
1531 bp->link_up = 0;
1532 else {
1533 u32 speed;
1534
1535 bp->link_up = 1;
1536 speed = msg & BNX2_LINK_STATUS_SPEED_MASK;
1537 bp->duplex = DUPLEX_FULL;
1538 switch (speed) {
1539 case BNX2_LINK_STATUS_10HALF:
1540 bp->duplex = DUPLEX_HALF;
1541 case BNX2_LINK_STATUS_10FULL:
1542 bp->line_speed = SPEED_10;
1543 break;
1544 case BNX2_LINK_STATUS_100HALF:
1545 bp->duplex = DUPLEX_HALF;
1546 case BNX2_LINK_STATUS_100BASE_T4:
1547 case BNX2_LINK_STATUS_100FULL:
1548 bp->line_speed = SPEED_100;
1549 break;
1550 case BNX2_LINK_STATUS_1000HALF:
1551 bp->duplex = DUPLEX_HALF;
1552 case BNX2_LINK_STATUS_1000FULL:
1553 bp->line_speed = SPEED_1000;
1554 break;
1555 case BNX2_LINK_STATUS_2500HALF:
1556 bp->duplex = DUPLEX_HALF;
1557 case BNX2_LINK_STATUS_2500FULL:
1558 bp->line_speed = SPEED_2500;
1559 break;
1560 default:
1561 bp->line_speed = 0;
1562 break;
1563 }
1564
1565 spin_lock(&bp->phy_lock);
1566 bp->flow_ctrl = 0;
1567 if ((bp->autoneg & (AUTONEG_SPEED | AUTONEG_FLOW_CTRL)) !=
1568 (AUTONEG_SPEED | AUTONEG_FLOW_CTRL)) {
1569 if (bp->duplex == DUPLEX_FULL)
1570 bp->flow_ctrl = bp->req_flow_ctrl;
1571 } else {
1572 if (msg & BNX2_LINK_STATUS_TX_FC_ENABLED)
1573 bp->flow_ctrl |= FLOW_CTRL_TX;
1574 if (msg & BNX2_LINK_STATUS_RX_FC_ENABLED)
1575 bp->flow_ctrl |= FLOW_CTRL_RX;
1576 }
1577
1578 old_port = bp->phy_port;
1579 if (msg & BNX2_LINK_STATUS_SERDES_LINK)
1580 bp->phy_port = PORT_FIBRE;
1581 else
1582 bp->phy_port = PORT_TP;
1583
1584 if (old_port != bp->phy_port)
1585 bnx2_set_default_link(bp);
1586
1587 spin_unlock(&bp->phy_lock);
1588 }
1589 if (bp->link_up != link_up)
1590 bnx2_report_link(bp);
1591
1592 bnx2_set_mac_link(bp);
1593}
1594
1595static int
1596bnx2_set_remote_link(struct bnx2 *bp)
1597{
1598 u32 evt_code;
1599
1600 evt_code = REG_RD_IND(bp, bp->shmem_base + BNX2_FW_EVT_CODE_MB);
1601 switch (evt_code) {
1602 case BNX2_FW_EVT_CODE_LINK_EVENT:
1603 bnx2_remote_phy_event(bp);
1604 break;
1605 case BNX2_FW_EVT_CODE_SW_TIMER_EXPIRATION_EVENT:
1606 default:
Michael Chandf149d72007-07-07 22:51:36 -07001607 bnx2_send_heart_beat(bp);
Michael Chan0d8a6572007-07-07 22:49:43 -07001608 break;
1609 }
1610 return 0;
1611}
1612
Michael Chanb6016b72005-05-26 13:03:09 -07001613static int
1614bnx2_setup_copper_phy(struct bnx2 *bp)
1615{
1616 u32 bmcr;
1617 u32 new_bmcr;
1618
Michael Chanca58c3a2007-05-03 13:22:52 -07001619 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chanb6016b72005-05-26 13:03:09 -07001620
1621 if (bp->autoneg & AUTONEG_SPEED) {
1622 u32 adv_reg, adv1000_reg;
1623 u32 new_adv_reg = 0;
1624 u32 new_adv1000_reg = 0;
1625
Michael Chanca58c3a2007-05-03 13:22:52 -07001626 bnx2_read_phy(bp, bp->mii_adv, &adv_reg);
Michael Chanb6016b72005-05-26 13:03:09 -07001627 adv_reg &= (PHY_ALL_10_100_SPEED | ADVERTISE_PAUSE_CAP |
1628 ADVERTISE_PAUSE_ASYM);
1629
1630 bnx2_read_phy(bp, MII_CTRL1000, &adv1000_reg);
1631 adv1000_reg &= PHY_ALL_1000_SPEED;
1632
1633 if (bp->advertising & ADVERTISED_10baseT_Half)
1634 new_adv_reg |= ADVERTISE_10HALF;
1635 if (bp->advertising & ADVERTISED_10baseT_Full)
1636 new_adv_reg |= ADVERTISE_10FULL;
1637 if (bp->advertising & ADVERTISED_100baseT_Half)
1638 new_adv_reg |= ADVERTISE_100HALF;
1639 if (bp->advertising & ADVERTISED_100baseT_Full)
1640 new_adv_reg |= ADVERTISE_100FULL;
1641 if (bp->advertising & ADVERTISED_1000baseT_Full)
1642 new_adv1000_reg |= ADVERTISE_1000FULL;
Jeff Garzik6aa20a22006-09-13 13:24:59 -04001643
Michael Chanb6016b72005-05-26 13:03:09 -07001644 new_adv_reg |= ADVERTISE_CSMA;
1645
1646 new_adv_reg |= bnx2_phy_get_pause_adv(bp);
1647
1648 if ((adv1000_reg != new_adv1000_reg) ||
1649 (adv_reg != new_adv_reg) ||
1650 ((bmcr & BMCR_ANENABLE) == 0)) {
1651
Michael Chanca58c3a2007-05-03 13:22:52 -07001652 bnx2_write_phy(bp, bp->mii_adv, new_adv_reg);
Michael Chanb6016b72005-05-26 13:03:09 -07001653 bnx2_write_phy(bp, MII_CTRL1000, new_adv1000_reg);
Michael Chanca58c3a2007-05-03 13:22:52 -07001654 bnx2_write_phy(bp, bp->mii_bmcr, BMCR_ANRESTART |
Michael Chanb6016b72005-05-26 13:03:09 -07001655 BMCR_ANENABLE);
1656 }
1657 else if (bp->link_up) {
1658 /* Flow ctrl may have changed from auto to forced */
1659 /* or vice-versa. */
1660
1661 bnx2_resolve_flow_ctrl(bp);
1662 bnx2_set_mac_link(bp);
1663 }
1664 return 0;
1665 }
1666
1667 new_bmcr = 0;
1668 if (bp->req_line_speed == SPEED_100) {
1669 new_bmcr |= BMCR_SPEED100;
1670 }
1671 if (bp->req_duplex == DUPLEX_FULL) {
1672 new_bmcr |= BMCR_FULLDPLX;
1673 }
1674 if (new_bmcr != bmcr) {
1675 u32 bmsr;
Michael Chanb6016b72005-05-26 13:03:09 -07001676
Michael Chanca58c3a2007-05-03 13:22:52 -07001677 bnx2_read_phy(bp, bp->mii_bmsr, &bmsr);
1678 bnx2_read_phy(bp, bp->mii_bmsr, &bmsr);
Jeff Garzik6aa20a22006-09-13 13:24:59 -04001679
Michael Chanb6016b72005-05-26 13:03:09 -07001680 if (bmsr & BMSR_LSTATUS) {
1681 /* Force link down */
Michael Chanca58c3a2007-05-03 13:22:52 -07001682 bnx2_write_phy(bp, bp->mii_bmcr, BMCR_LOOPBACK);
Michael Chana16dda02006-11-19 14:08:56 -08001683 spin_unlock_bh(&bp->phy_lock);
1684 msleep(50);
1685 spin_lock_bh(&bp->phy_lock);
1686
Michael Chanca58c3a2007-05-03 13:22:52 -07001687 bnx2_read_phy(bp, bp->mii_bmsr, &bmsr);
1688 bnx2_read_phy(bp, bp->mii_bmsr, &bmsr);
Michael Chanb6016b72005-05-26 13:03:09 -07001689 }
1690
Michael Chanca58c3a2007-05-03 13:22:52 -07001691 bnx2_write_phy(bp, bp->mii_bmcr, new_bmcr);
Michael Chanb6016b72005-05-26 13:03:09 -07001692
1693 /* Normally, the new speed is setup after the link has
1694 * gone down and up again. In some cases, link will not go
1695 * down so we need to set up the new speed here.
1696 */
1697 if (bmsr & BMSR_LSTATUS) {
1698 bp->line_speed = bp->req_line_speed;
1699 bp->duplex = bp->req_duplex;
1700 bnx2_resolve_flow_ctrl(bp);
1701 bnx2_set_mac_link(bp);
1702 }
Michael Chan27a005b2007-05-03 13:23:41 -07001703 } else {
1704 bnx2_resolve_flow_ctrl(bp);
1705 bnx2_set_mac_link(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07001706 }
1707 return 0;
1708}
1709
1710static int
Michael Chan0d8a6572007-07-07 22:49:43 -07001711bnx2_setup_phy(struct bnx2 *bp, u8 port)
Michael Chanb6016b72005-05-26 13:03:09 -07001712{
1713 if (bp->loopback == MAC_LOOPBACK)
1714 return 0;
1715
1716 if (bp->phy_flags & PHY_SERDES_FLAG) {
Michael Chan0d8a6572007-07-07 22:49:43 -07001717 return (bnx2_setup_serdes_phy(bp, port));
Michael Chanb6016b72005-05-26 13:03:09 -07001718 }
1719 else {
1720 return (bnx2_setup_copper_phy(bp));
1721 }
1722}
1723
1724static int
Michael Chan27a005b2007-05-03 13:23:41 -07001725bnx2_init_5709s_phy(struct bnx2 *bp)
1726{
1727 u32 val;
1728
1729 bp->mii_bmcr = MII_BMCR + 0x10;
1730 bp->mii_bmsr = MII_BMSR + 0x10;
1731 bp->mii_bmsr1 = MII_BNX2_GP_TOP_AN_STATUS1;
1732 bp->mii_adv = MII_ADVERTISE + 0x10;
1733 bp->mii_lpa = MII_LPA + 0x10;
1734 bp->mii_up1 = MII_BNX2_OVER1G_UP1;
1735
1736 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_AER);
1737 bnx2_write_phy(bp, MII_BNX2_AER_AER, MII_BNX2_AER_AER_AN_MMD);
1738
1739 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
1740 bnx2_reset_phy(bp);
1741
1742 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_SERDES_DIG);
1743
1744 bnx2_read_phy(bp, MII_BNX2_SERDES_DIG_1000XCTL1, &val);
1745 val &= ~MII_BNX2_SD_1000XCTL1_AUTODET;
1746 val |= MII_BNX2_SD_1000XCTL1_FIBER;
1747 bnx2_write_phy(bp, MII_BNX2_SERDES_DIG_1000XCTL1, val);
1748
1749 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_OVER1G);
1750 bnx2_read_phy(bp, MII_BNX2_OVER1G_UP1, &val);
1751 if (bp->phy_flags & PHY_2_5G_CAPABLE_FLAG)
1752 val |= BCM5708S_UP1_2G5;
1753 else
1754 val &= ~BCM5708S_UP1_2G5;
1755 bnx2_write_phy(bp, MII_BNX2_OVER1G_UP1, val);
1756
1757 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_BAM_NXTPG);
1758 bnx2_read_phy(bp, MII_BNX2_BAM_NXTPG_CTL, &val);
1759 val |= MII_BNX2_NXTPG_CTL_T2 | MII_BNX2_NXTPG_CTL_BAM;
1760 bnx2_write_phy(bp, MII_BNX2_BAM_NXTPG_CTL, val);
1761
1762 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_CL73_USERB0);
1763
1764 val = MII_BNX2_CL73_BAM_EN | MII_BNX2_CL73_BAM_STA_MGR_EN |
1765 MII_BNX2_CL73_BAM_NP_AFT_BP_EN;
1766 bnx2_write_phy(bp, MII_BNX2_CL73_BAM_CTL1, val);
1767
1768 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
1769
1770 return 0;
1771}
1772
1773static int
Michael Chan5b0c76a2005-11-04 08:45:49 -08001774bnx2_init_5708s_phy(struct bnx2 *bp)
1775{
1776 u32 val;
1777
Michael Chan27a005b2007-05-03 13:23:41 -07001778 bnx2_reset_phy(bp);
1779
1780 bp->mii_up1 = BCM5708S_UP1;
1781
Michael Chan5b0c76a2005-11-04 08:45:49 -08001782 bnx2_write_phy(bp, BCM5708S_BLK_ADDR, BCM5708S_BLK_ADDR_DIG3);
1783 bnx2_write_phy(bp, BCM5708S_DIG_3_0, BCM5708S_DIG_3_0_USE_IEEE);
1784 bnx2_write_phy(bp, BCM5708S_BLK_ADDR, BCM5708S_BLK_ADDR_DIG);
1785
1786 bnx2_read_phy(bp, BCM5708S_1000X_CTL1, &val);
1787 val |= BCM5708S_1000X_CTL1_FIBER_MODE | BCM5708S_1000X_CTL1_AUTODET_EN;
1788 bnx2_write_phy(bp, BCM5708S_1000X_CTL1, val);
1789
1790 bnx2_read_phy(bp, BCM5708S_1000X_CTL2, &val);
1791 val |= BCM5708S_1000X_CTL2_PLLEL_DET_EN;
1792 bnx2_write_phy(bp, BCM5708S_1000X_CTL2, val);
1793
1794 if (bp->phy_flags & PHY_2_5G_CAPABLE_FLAG) {
1795 bnx2_read_phy(bp, BCM5708S_UP1, &val);
1796 val |= BCM5708S_UP1_2G5;
1797 bnx2_write_phy(bp, BCM5708S_UP1, val);
1798 }
1799
1800 if ((CHIP_ID(bp) == CHIP_ID_5708_A0) ||
Michael Chandda1e392006-01-23 16:08:14 -08001801 (CHIP_ID(bp) == CHIP_ID_5708_B0) ||
1802 (CHIP_ID(bp) == CHIP_ID_5708_B1)) {
Michael Chan5b0c76a2005-11-04 08:45:49 -08001803 /* increase tx signal amplitude */
1804 bnx2_write_phy(bp, BCM5708S_BLK_ADDR,
1805 BCM5708S_BLK_ADDR_TX_MISC);
1806 bnx2_read_phy(bp, BCM5708S_TX_ACTL1, &val);
1807 val &= ~BCM5708S_TX_ACTL1_DRIVER_VCM;
1808 bnx2_write_phy(bp, BCM5708S_TX_ACTL1, val);
1809 bnx2_write_phy(bp, BCM5708S_BLK_ADDR, BCM5708S_BLK_ADDR_DIG);
1810 }
1811
Michael Chane3648b32005-11-04 08:51:21 -08001812 val = REG_RD_IND(bp, bp->shmem_base + BNX2_PORT_HW_CFG_CONFIG) &
Michael Chan5b0c76a2005-11-04 08:45:49 -08001813 BNX2_PORT_HW_CFG_CFG_TXCTL3_MASK;
1814
1815 if (val) {
1816 u32 is_backplane;
1817
Michael Chane3648b32005-11-04 08:51:21 -08001818 is_backplane = REG_RD_IND(bp, bp->shmem_base +
Michael Chan5b0c76a2005-11-04 08:45:49 -08001819 BNX2_SHARED_HW_CFG_CONFIG);
1820 if (is_backplane & BNX2_SHARED_HW_CFG_PHY_BACKPLANE) {
1821 bnx2_write_phy(bp, BCM5708S_BLK_ADDR,
1822 BCM5708S_BLK_ADDR_TX_MISC);
1823 bnx2_write_phy(bp, BCM5708S_TX_ACTL3, val);
1824 bnx2_write_phy(bp, BCM5708S_BLK_ADDR,
1825 BCM5708S_BLK_ADDR_DIG);
1826 }
1827 }
1828 return 0;
1829}
1830
1831static int
1832bnx2_init_5706s_phy(struct bnx2 *bp)
Michael Chanb6016b72005-05-26 13:03:09 -07001833{
Michael Chan27a005b2007-05-03 13:23:41 -07001834 bnx2_reset_phy(bp);
1835
Michael Chanb6016b72005-05-26 13:03:09 -07001836 bp->phy_flags &= ~PHY_PARALLEL_DETECT_FLAG;
1837
Michael Chan59b47d82006-11-19 14:10:45 -08001838 if (CHIP_NUM(bp) == CHIP_NUM_5706)
1839 REG_WR(bp, BNX2_MISC_GP_HW_CTL0, 0x300);
Michael Chanb6016b72005-05-26 13:03:09 -07001840
1841 if (bp->dev->mtu > 1500) {
1842 u32 val;
1843
1844 /* Set extended packet length bit */
1845 bnx2_write_phy(bp, 0x18, 0x7);
1846 bnx2_read_phy(bp, 0x18, &val);
1847 bnx2_write_phy(bp, 0x18, (val & 0xfff8) | 0x4000);
1848
1849 bnx2_write_phy(bp, 0x1c, 0x6c00);
1850 bnx2_read_phy(bp, 0x1c, &val);
1851 bnx2_write_phy(bp, 0x1c, (val & 0x3ff) | 0xec02);
1852 }
1853 else {
1854 u32 val;
1855
1856 bnx2_write_phy(bp, 0x18, 0x7);
1857 bnx2_read_phy(bp, 0x18, &val);
1858 bnx2_write_phy(bp, 0x18, val & ~0x4007);
1859
1860 bnx2_write_phy(bp, 0x1c, 0x6c00);
1861 bnx2_read_phy(bp, 0x1c, &val);
1862 bnx2_write_phy(bp, 0x1c, (val & 0x3fd) | 0xec00);
1863 }
1864
1865 return 0;
1866}
1867
1868static int
1869bnx2_init_copper_phy(struct bnx2 *bp)
1870{
Michael Chan5b0c76a2005-11-04 08:45:49 -08001871 u32 val;
1872
Michael Chan27a005b2007-05-03 13:23:41 -07001873 bnx2_reset_phy(bp);
1874
Michael Chanb6016b72005-05-26 13:03:09 -07001875 if (bp->phy_flags & PHY_CRC_FIX_FLAG) {
1876 bnx2_write_phy(bp, 0x18, 0x0c00);
1877 bnx2_write_phy(bp, 0x17, 0x000a);
1878 bnx2_write_phy(bp, 0x15, 0x310b);
1879 bnx2_write_phy(bp, 0x17, 0x201f);
1880 bnx2_write_phy(bp, 0x15, 0x9506);
1881 bnx2_write_phy(bp, 0x17, 0x401f);
1882 bnx2_write_phy(bp, 0x15, 0x14e2);
1883 bnx2_write_phy(bp, 0x18, 0x0400);
1884 }
1885
Michael Chanb659f442007-02-02 00:46:35 -08001886 if (bp->phy_flags & PHY_DIS_EARLY_DAC_FLAG) {
1887 bnx2_write_phy(bp, MII_BNX2_DSP_ADDRESS,
1888 MII_BNX2_DSP_EXPAND_REG | 0x8);
1889 bnx2_read_phy(bp, MII_BNX2_DSP_RW_PORT, &val);
1890 val &= ~(1 << 8);
1891 bnx2_write_phy(bp, MII_BNX2_DSP_RW_PORT, val);
1892 }
1893
Michael Chanb6016b72005-05-26 13:03:09 -07001894 if (bp->dev->mtu > 1500) {
Michael Chanb6016b72005-05-26 13:03:09 -07001895 /* Set extended packet length bit */
1896 bnx2_write_phy(bp, 0x18, 0x7);
1897 bnx2_read_phy(bp, 0x18, &val);
1898 bnx2_write_phy(bp, 0x18, val | 0x4000);
1899
1900 bnx2_read_phy(bp, 0x10, &val);
1901 bnx2_write_phy(bp, 0x10, val | 0x1);
1902 }
1903 else {
Michael Chanb6016b72005-05-26 13:03:09 -07001904 bnx2_write_phy(bp, 0x18, 0x7);
1905 bnx2_read_phy(bp, 0x18, &val);
1906 bnx2_write_phy(bp, 0x18, val & ~0x4007);
1907
1908 bnx2_read_phy(bp, 0x10, &val);
1909 bnx2_write_phy(bp, 0x10, val & ~0x1);
1910 }
1911
Michael Chan5b0c76a2005-11-04 08:45:49 -08001912 /* ethernet@wirespeed */
1913 bnx2_write_phy(bp, 0x18, 0x7007);
1914 bnx2_read_phy(bp, 0x18, &val);
1915 bnx2_write_phy(bp, 0x18, val | (1 << 15) | (1 << 4));
Michael Chanb6016b72005-05-26 13:03:09 -07001916 return 0;
1917}
1918
1919
1920static int
1921bnx2_init_phy(struct bnx2 *bp)
1922{
1923 u32 val;
1924 int rc = 0;
1925
1926 bp->phy_flags &= ~PHY_INT_MODE_MASK_FLAG;
1927 bp->phy_flags |= PHY_INT_MODE_LINK_READY_FLAG;
1928
Michael Chanca58c3a2007-05-03 13:22:52 -07001929 bp->mii_bmcr = MII_BMCR;
1930 bp->mii_bmsr = MII_BMSR;
Michael Chan27a005b2007-05-03 13:23:41 -07001931 bp->mii_bmsr1 = MII_BMSR;
Michael Chanca58c3a2007-05-03 13:22:52 -07001932 bp->mii_adv = MII_ADVERTISE;
1933 bp->mii_lpa = MII_LPA;
1934
Michael Chanb6016b72005-05-26 13:03:09 -07001935 REG_WR(bp, BNX2_EMAC_ATTENTION_ENA, BNX2_EMAC_ATTENTION_ENA_LINK);
1936
Michael Chan0d8a6572007-07-07 22:49:43 -07001937 if (bp->phy_flags & REMOTE_PHY_CAP_FLAG)
1938 goto setup_phy;
1939
Michael Chanb6016b72005-05-26 13:03:09 -07001940 bnx2_read_phy(bp, MII_PHYSID1, &val);
1941 bp->phy_id = val << 16;
1942 bnx2_read_phy(bp, MII_PHYSID2, &val);
1943 bp->phy_id |= val & 0xffff;
1944
1945 if (bp->phy_flags & PHY_SERDES_FLAG) {
Michael Chan5b0c76a2005-11-04 08:45:49 -08001946 if (CHIP_NUM(bp) == CHIP_NUM_5706)
1947 rc = bnx2_init_5706s_phy(bp);
1948 else if (CHIP_NUM(bp) == CHIP_NUM_5708)
1949 rc = bnx2_init_5708s_phy(bp);
Michael Chan27a005b2007-05-03 13:23:41 -07001950 else if (CHIP_NUM(bp) == CHIP_NUM_5709)
1951 rc = bnx2_init_5709s_phy(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07001952 }
1953 else {
1954 rc = bnx2_init_copper_phy(bp);
1955 }
1956
Michael Chan0d8a6572007-07-07 22:49:43 -07001957setup_phy:
1958 if (!rc)
1959 rc = bnx2_setup_phy(bp, bp->phy_port);
Michael Chanb6016b72005-05-26 13:03:09 -07001960
1961 return rc;
1962}
1963
1964static int
1965bnx2_set_mac_loopback(struct bnx2 *bp)
1966{
1967 u32 mac_mode;
1968
1969 mac_mode = REG_RD(bp, BNX2_EMAC_MODE);
1970 mac_mode &= ~BNX2_EMAC_MODE_PORT;
1971 mac_mode |= BNX2_EMAC_MODE_MAC_LOOP | BNX2_EMAC_MODE_FORCE_LINK;
1972 REG_WR(bp, BNX2_EMAC_MODE, mac_mode);
1973 bp->link_up = 1;
1974 return 0;
1975}
1976
Michael Chanbc5a0692006-01-23 16:13:22 -08001977static int bnx2_test_link(struct bnx2 *);
1978
1979static int
1980bnx2_set_phy_loopback(struct bnx2 *bp)
1981{
1982 u32 mac_mode;
1983 int rc, i;
1984
1985 spin_lock_bh(&bp->phy_lock);
Michael Chanca58c3a2007-05-03 13:22:52 -07001986 rc = bnx2_write_phy(bp, bp->mii_bmcr, BMCR_LOOPBACK | BMCR_FULLDPLX |
Michael Chanbc5a0692006-01-23 16:13:22 -08001987 BMCR_SPEED1000);
1988 spin_unlock_bh(&bp->phy_lock);
1989 if (rc)
1990 return rc;
1991
1992 for (i = 0; i < 10; i++) {
1993 if (bnx2_test_link(bp) == 0)
1994 break;
Michael Chan80be4432006-11-19 14:07:28 -08001995 msleep(100);
Michael Chanbc5a0692006-01-23 16:13:22 -08001996 }
1997
1998 mac_mode = REG_RD(bp, BNX2_EMAC_MODE);
1999 mac_mode &= ~(BNX2_EMAC_MODE_PORT | BNX2_EMAC_MODE_HALF_DUPLEX |
2000 BNX2_EMAC_MODE_MAC_LOOP | BNX2_EMAC_MODE_FORCE_LINK |
Michael Chan59b47d82006-11-19 14:10:45 -08002001 BNX2_EMAC_MODE_25G_MODE);
Michael Chanbc5a0692006-01-23 16:13:22 -08002002
2003 mac_mode |= BNX2_EMAC_MODE_PORT_GMII;
2004 REG_WR(bp, BNX2_EMAC_MODE, mac_mode);
2005 bp->link_up = 1;
2006 return 0;
2007}
2008
Michael Chanb6016b72005-05-26 13:03:09 -07002009static int
Michael Chanb090ae22006-01-23 16:07:10 -08002010bnx2_fw_sync(struct bnx2 *bp, u32 msg_data, int silent)
Michael Chanb6016b72005-05-26 13:03:09 -07002011{
2012 int i;
2013 u32 val;
2014
Michael Chanb6016b72005-05-26 13:03:09 -07002015 bp->fw_wr_seq++;
2016 msg_data |= bp->fw_wr_seq;
2017
Michael Chane3648b32005-11-04 08:51:21 -08002018 REG_WR_IND(bp, bp->shmem_base + BNX2_DRV_MB, msg_data);
Michael Chanb6016b72005-05-26 13:03:09 -07002019
2020 /* wait for an acknowledgement. */
Michael Chanb090ae22006-01-23 16:07:10 -08002021 for (i = 0; i < (FW_ACK_TIME_OUT_MS / 10); i++) {
2022 msleep(10);
Michael Chanb6016b72005-05-26 13:03:09 -07002023
Michael Chane3648b32005-11-04 08:51:21 -08002024 val = REG_RD_IND(bp, bp->shmem_base + BNX2_FW_MB);
Michael Chanb6016b72005-05-26 13:03:09 -07002025
2026 if ((val & BNX2_FW_MSG_ACK) == (msg_data & BNX2_DRV_MSG_SEQ))
2027 break;
2028 }
Michael Chanb090ae22006-01-23 16:07:10 -08002029 if ((msg_data & BNX2_DRV_MSG_DATA) == BNX2_DRV_MSG_DATA_WAIT0)
2030 return 0;
Michael Chanb6016b72005-05-26 13:03:09 -07002031
2032 /* If we timed out, inform the firmware that this is the case. */
Michael Chanb090ae22006-01-23 16:07:10 -08002033 if ((val & BNX2_FW_MSG_ACK) != (msg_data & BNX2_DRV_MSG_SEQ)) {
2034 if (!silent)
2035 printk(KERN_ERR PFX "fw sync timeout, reset code = "
2036 "%x\n", msg_data);
Michael Chanb6016b72005-05-26 13:03:09 -07002037
2038 msg_data &= ~BNX2_DRV_MSG_CODE;
2039 msg_data |= BNX2_DRV_MSG_CODE_FW_TIMEOUT;
2040
Michael Chane3648b32005-11-04 08:51:21 -08002041 REG_WR_IND(bp, bp->shmem_base + BNX2_DRV_MB, msg_data);
Michael Chanb6016b72005-05-26 13:03:09 -07002042
Michael Chanb6016b72005-05-26 13:03:09 -07002043 return -EBUSY;
2044 }
2045
Michael Chanb090ae22006-01-23 16:07:10 -08002046 if ((val & BNX2_FW_MSG_STATUS_MASK) != BNX2_FW_MSG_STATUS_OK)
2047 return -EIO;
2048
Michael Chanb6016b72005-05-26 13:03:09 -07002049 return 0;
2050}
2051
Michael Chan59b47d82006-11-19 14:10:45 -08002052static int
2053bnx2_init_5709_context(struct bnx2 *bp)
2054{
2055 int i, ret = 0;
2056 u32 val;
2057
2058 val = BNX2_CTX_COMMAND_ENABLED | BNX2_CTX_COMMAND_MEM_INIT | (1 << 12);
2059 val |= (BCM_PAGE_BITS - 8) << 16;
2060 REG_WR(bp, BNX2_CTX_COMMAND, val);
Michael Chan641bdcd2007-06-04 21:22:24 -07002061 for (i = 0; i < 10; i++) {
2062 val = REG_RD(bp, BNX2_CTX_COMMAND);
2063 if (!(val & BNX2_CTX_COMMAND_MEM_INIT))
2064 break;
2065 udelay(2);
2066 }
2067 if (val & BNX2_CTX_COMMAND_MEM_INIT)
2068 return -EBUSY;
2069
Michael Chan59b47d82006-11-19 14:10:45 -08002070 for (i = 0; i < bp->ctx_pages; i++) {
2071 int j;
2072
2073 REG_WR(bp, BNX2_CTX_HOST_PAGE_TBL_DATA0,
2074 (bp->ctx_blk_mapping[i] & 0xffffffff) |
2075 BNX2_CTX_HOST_PAGE_TBL_DATA0_VALID);
2076 REG_WR(bp, BNX2_CTX_HOST_PAGE_TBL_DATA1,
2077 (u64) bp->ctx_blk_mapping[i] >> 32);
2078 REG_WR(bp, BNX2_CTX_HOST_PAGE_TBL_CTRL, i |
2079 BNX2_CTX_HOST_PAGE_TBL_CTRL_WRITE_REQ);
2080 for (j = 0; j < 10; j++) {
2081
2082 val = REG_RD(bp, BNX2_CTX_HOST_PAGE_TBL_CTRL);
2083 if (!(val & BNX2_CTX_HOST_PAGE_TBL_CTRL_WRITE_REQ))
2084 break;
2085 udelay(5);
2086 }
2087 if (val & BNX2_CTX_HOST_PAGE_TBL_CTRL_WRITE_REQ) {
2088 ret = -EBUSY;
2089 break;
2090 }
2091 }
2092 return ret;
2093}
2094
Michael Chanb6016b72005-05-26 13:03:09 -07002095static void
2096bnx2_init_context(struct bnx2 *bp)
2097{
2098 u32 vcid;
2099
2100 vcid = 96;
2101 while (vcid) {
2102 u32 vcid_addr, pcid_addr, offset;
Michael Chan7947b202007-06-04 21:17:10 -07002103 int i;
Michael Chanb6016b72005-05-26 13:03:09 -07002104
2105 vcid--;
2106
2107 if (CHIP_ID(bp) == CHIP_ID_5706_A0) {
2108 u32 new_vcid;
2109
2110 vcid_addr = GET_PCID_ADDR(vcid);
2111 if (vcid & 0x8) {
2112 new_vcid = 0x60 + (vcid & 0xf0) + (vcid & 0x7);
2113 }
2114 else {
2115 new_vcid = vcid;
2116 }
2117 pcid_addr = GET_PCID_ADDR(new_vcid);
2118 }
2119 else {
2120 vcid_addr = GET_CID_ADDR(vcid);
2121 pcid_addr = vcid_addr;
2122 }
2123
Michael Chan7947b202007-06-04 21:17:10 -07002124 for (i = 0; i < (CTX_SIZE / PHY_CTX_SIZE); i++) {
2125 vcid_addr += (i << PHY_CTX_SHIFT);
2126 pcid_addr += (i << PHY_CTX_SHIFT);
Michael Chanb6016b72005-05-26 13:03:09 -07002127
Michael Chan7947b202007-06-04 21:17:10 -07002128 REG_WR(bp, BNX2_CTX_VIRT_ADDR, 0x00);
2129 REG_WR(bp, BNX2_CTX_PAGE_TBL, pcid_addr);
2130
2131 /* Zero out the context. */
2132 for (offset = 0; offset < PHY_CTX_SIZE; offset += 4)
2133 CTX_WR(bp, 0x00, offset, 0);
2134
2135 REG_WR(bp, BNX2_CTX_VIRT_ADDR, vcid_addr);
2136 REG_WR(bp, BNX2_CTX_PAGE_TBL, pcid_addr);
Michael Chanb6016b72005-05-26 13:03:09 -07002137 }
Michael Chanb6016b72005-05-26 13:03:09 -07002138 }
2139}
2140
2141static int
2142bnx2_alloc_bad_rbuf(struct bnx2 *bp)
2143{
2144 u16 *good_mbuf;
2145 u32 good_mbuf_cnt;
2146 u32 val;
2147
2148 good_mbuf = kmalloc(512 * sizeof(u16), GFP_KERNEL);
2149 if (good_mbuf == NULL) {
2150 printk(KERN_ERR PFX "Failed to allocate memory in "
2151 "bnx2_alloc_bad_rbuf\n");
2152 return -ENOMEM;
2153 }
2154
2155 REG_WR(bp, BNX2_MISC_ENABLE_SET_BITS,
2156 BNX2_MISC_ENABLE_SET_BITS_RX_MBUF_ENABLE);
2157
2158 good_mbuf_cnt = 0;
2159
2160 /* Allocate a bunch of mbufs and save the good ones in an array. */
2161 val = REG_RD_IND(bp, BNX2_RBUF_STATUS1);
2162 while (val & BNX2_RBUF_STATUS1_FREE_COUNT) {
2163 REG_WR_IND(bp, BNX2_RBUF_COMMAND, BNX2_RBUF_COMMAND_ALLOC_REQ);
2164
2165 val = REG_RD_IND(bp, BNX2_RBUF_FW_BUF_ALLOC);
2166
2167 val &= BNX2_RBUF_FW_BUF_ALLOC_VALUE;
2168
2169 /* The addresses with Bit 9 set are bad memory blocks. */
2170 if (!(val & (1 << 9))) {
2171 good_mbuf[good_mbuf_cnt] = (u16) val;
2172 good_mbuf_cnt++;
2173 }
2174
2175 val = REG_RD_IND(bp, BNX2_RBUF_STATUS1);
2176 }
2177
2178 /* Free the good ones back to the mbuf pool thus discarding
2179 * all the bad ones. */
2180 while (good_mbuf_cnt) {
2181 good_mbuf_cnt--;
2182
2183 val = good_mbuf[good_mbuf_cnt];
2184 val = (val << 9) | val | 1;
2185
2186 REG_WR_IND(bp, BNX2_RBUF_FW_BUF_FREE, val);
2187 }
2188 kfree(good_mbuf);
2189 return 0;
2190}
2191
2192static void
Jeff Garzik6aa20a22006-09-13 13:24:59 -04002193bnx2_set_mac_addr(struct bnx2 *bp)
Michael Chanb6016b72005-05-26 13:03:09 -07002194{
2195 u32 val;
2196 u8 *mac_addr = bp->dev->dev_addr;
2197
2198 val = (mac_addr[0] << 8) | mac_addr[1];
2199
2200 REG_WR(bp, BNX2_EMAC_MAC_MATCH0, val);
2201
Jeff Garzik6aa20a22006-09-13 13:24:59 -04002202 val = (mac_addr[2] << 24) | (mac_addr[3] << 16) |
Michael Chanb6016b72005-05-26 13:03:09 -07002203 (mac_addr[4] << 8) | mac_addr[5];
2204
2205 REG_WR(bp, BNX2_EMAC_MAC_MATCH1, val);
2206}
2207
2208static inline int
2209bnx2_alloc_rx_skb(struct bnx2 *bp, u16 index)
2210{
2211 struct sk_buff *skb;
2212 struct sw_bd *rx_buf = &bp->rx_buf_ring[index];
2213 dma_addr_t mapping;
Michael Chan13daffa2006-03-20 17:49:20 -08002214 struct rx_bd *rxbd = &bp->rx_desc_ring[RX_RING(index)][RX_IDX(index)];
Michael Chanb6016b72005-05-26 13:03:09 -07002215 unsigned long align;
2216
Michael Chan932f3772006-08-15 01:39:36 -07002217 skb = netdev_alloc_skb(bp->dev, bp->rx_buf_size);
Michael Chanb6016b72005-05-26 13:03:09 -07002218 if (skb == NULL) {
2219 return -ENOMEM;
2220 }
2221
Michael Chan59b47d82006-11-19 14:10:45 -08002222 if (unlikely((align = (unsigned long) skb->data & (BNX2_RX_ALIGN - 1))))
2223 skb_reserve(skb, BNX2_RX_ALIGN - align);
Michael Chanb6016b72005-05-26 13:03:09 -07002224
Michael Chanb6016b72005-05-26 13:03:09 -07002225 mapping = pci_map_single(bp->pdev, skb->data, bp->rx_buf_use_size,
2226 PCI_DMA_FROMDEVICE);
2227
2228 rx_buf->skb = skb;
2229 pci_unmap_addr_set(rx_buf, mapping, mapping);
2230
2231 rxbd->rx_bd_haddr_hi = (u64) mapping >> 32;
2232 rxbd->rx_bd_haddr_lo = (u64) mapping & 0xffffffff;
2233
2234 bp->rx_prod_bseq += bp->rx_buf_use_size;
2235
2236 return 0;
2237}
2238
Michael Chanda3e4fb2007-05-03 13:24:23 -07002239static int
2240bnx2_phy_event_is_set(struct bnx2 *bp, u32 event)
2241{
2242 struct status_block *sblk = bp->status_blk;
2243 u32 new_link_state, old_link_state;
2244 int is_set = 1;
2245
2246 new_link_state = sblk->status_attn_bits & event;
2247 old_link_state = sblk->status_attn_bits_ack & event;
2248 if (new_link_state != old_link_state) {
2249 if (new_link_state)
2250 REG_WR(bp, BNX2_PCICFG_STATUS_BIT_SET_CMD, event);
2251 else
2252 REG_WR(bp, BNX2_PCICFG_STATUS_BIT_CLEAR_CMD, event);
2253 } else
2254 is_set = 0;
2255
2256 return is_set;
2257}
2258
Michael Chanb6016b72005-05-26 13:03:09 -07002259static void
2260bnx2_phy_int(struct bnx2 *bp)
2261{
Michael Chanda3e4fb2007-05-03 13:24:23 -07002262 if (bnx2_phy_event_is_set(bp, STATUS_ATTN_BITS_LINK_STATE)) {
2263 spin_lock(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07002264 bnx2_set_link(bp);
Michael Chanda3e4fb2007-05-03 13:24:23 -07002265 spin_unlock(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07002266 }
Michael Chan0d8a6572007-07-07 22:49:43 -07002267 if (bnx2_phy_event_is_set(bp, STATUS_ATTN_BITS_TIMER_ABORT))
2268 bnx2_set_remote_link(bp);
2269
Michael Chanb6016b72005-05-26 13:03:09 -07002270}
2271
2272static void
2273bnx2_tx_int(struct bnx2 *bp)
2274{
Michael Chanf4e418f2005-11-04 08:53:48 -08002275 struct status_block *sblk = bp->status_blk;
Michael Chanb6016b72005-05-26 13:03:09 -07002276 u16 hw_cons, sw_cons, sw_ring_cons;
2277 int tx_free_bd = 0;
2278
Michael Chanf4e418f2005-11-04 08:53:48 -08002279 hw_cons = bp->hw_tx_cons = sblk->status_tx_quick_consumer_index0;
Michael Chanb6016b72005-05-26 13:03:09 -07002280 if ((hw_cons & MAX_TX_DESC_CNT) == MAX_TX_DESC_CNT) {
2281 hw_cons++;
2282 }
2283 sw_cons = bp->tx_cons;
2284
2285 while (sw_cons != hw_cons) {
2286 struct sw_bd *tx_buf;
2287 struct sk_buff *skb;
2288 int i, last;
2289
2290 sw_ring_cons = TX_RING_IDX(sw_cons);
2291
2292 tx_buf = &bp->tx_buf_ring[sw_ring_cons];
2293 skb = tx_buf->skb;
Arjan van de Ven1d39ed52006-12-12 14:06:23 +01002294
Michael Chanb6016b72005-05-26 13:03:09 -07002295 /* partial BD completions possible with TSO packets */
Herbert Xu89114af2006-07-08 13:34:32 -07002296 if (skb_is_gso(skb)) {
Michael Chanb6016b72005-05-26 13:03:09 -07002297 u16 last_idx, last_ring_idx;
2298
2299 last_idx = sw_cons +
2300 skb_shinfo(skb)->nr_frags + 1;
2301 last_ring_idx = sw_ring_cons +
2302 skb_shinfo(skb)->nr_frags + 1;
2303 if (unlikely(last_ring_idx >= MAX_TX_DESC_CNT)) {
2304 last_idx++;
2305 }
2306 if (((s16) ((s16) last_idx - (s16) hw_cons)) > 0) {
2307 break;
2308 }
2309 }
Arjan van de Ven1d39ed52006-12-12 14:06:23 +01002310
Michael Chanb6016b72005-05-26 13:03:09 -07002311 pci_unmap_single(bp->pdev, pci_unmap_addr(tx_buf, mapping),
2312 skb_headlen(skb), PCI_DMA_TODEVICE);
2313
2314 tx_buf->skb = NULL;
2315 last = skb_shinfo(skb)->nr_frags;
2316
2317 for (i = 0; i < last; i++) {
2318 sw_cons = NEXT_TX_BD(sw_cons);
2319
2320 pci_unmap_page(bp->pdev,
2321 pci_unmap_addr(
2322 &bp->tx_buf_ring[TX_RING_IDX(sw_cons)],
2323 mapping),
2324 skb_shinfo(skb)->frags[i].size,
2325 PCI_DMA_TODEVICE);
2326 }
2327
2328 sw_cons = NEXT_TX_BD(sw_cons);
2329
2330 tx_free_bd += last + 1;
2331
Michael Chan745720e2006-06-29 12:37:41 -07002332 dev_kfree_skb(skb);
Michael Chanb6016b72005-05-26 13:03:09 -07002333
Michael Chanf4e418f2005-11-04 08:53:48 -08002334 hw_cons = bp->hw_tx_cons =
2335 sblk->status_tx_quick_consumer_index0;
2336
Michael Chanb6016b72005-05-26 13:03:09 -07002337 if ((hw_cons & MAX_TX_DESC_CNT) == MAX_TX_DESC_CNT) {
2338 hw_cons++;
2339 }
2340 }
2341
Michael Chane89bbf12005-08-25 15:36:58 -07002342 bp->tx_cons = sw_cons;
Michael Chan2f8af122006-08-15 01:39:10 -07002343 /* Need to make the tx_cons update visible to bnx2_start_xmit()
2344 * before checking for netif_queue_stopped(). Without the
2345 * memory barrier, there is a small possibility that bnx2_start_xmit()
2346 * will miss it and cause the queue to be stopped forever.
2347 */
2348 smp_mb();
Michael Chanb6016b72005-05-26 13:03:09 -07002349
Michael Chan2f8af122006-08-15 01:39:10 -07002350 if (unlikely(netif_queue_stopped(bp->dev)) &&
2351 (bnx2_tx_avail(bp) > bp->tx_wake_thresh)) {
2352 netif_tx_lock(bp->dev);
Michael Chanb6016b72005-05-26 13:03:09 -07002353 if ((netif_queue_stopped(bp->dev)) &&
Michael Chan2f8af122006-08-15 01:39:10 -07002354 (bnx2_tx_avail(bp) > bp->tx_wake_thresh))
Michael Chanb6016b72005-05-26 13:03:09 -07002355 netif_wake_queue(bp->dev);
Michael Chan2f8af122006-08-15 01:39:10 -07002356 netif_tx_unlock(bp->dev);
Michael Chanb6016b72005-05-26 13:03:09 -07002357 }
Michael Chanb6016b72005-05-26 13:03:09 -07002358}
2359
2360static inline void
2361bnx2_reuse_rx_skb(struct bnx2 *bp, struct sk_buff *skb,
2362 u16 cons, u16 prod)
2363{
Michael Chan236b6392006-03-20 17:49:02 -08002364 struct sw_bd *cons_rx_buf, *prod_rx_buf;
2365 struct rx_bd *cons_bd, *prod_bd;
2366
2367 cons_rx_buf = &bp->rx_buf_ring[cons];
2368 prod_rx_buf = &bp->rx_buf_ring[prod];
Michael Chanb6016b72005-05-26 13:03:09 -07002369
2370 pci_dma_sync_single_for_device(bp->pdev,
2371 pci_unmap_addr(cons_rx_buf, mapping),
2372 bp->rx_offset + RX_COPY_THRESH, PCI_DMA_FROMDEVICE);
2373
Michael Chan236b6392006-03-20 17:49:02 -08002374 bp->rx_prod_bseq += bp->rx_buf_use_size;
2375
2376 prod_rx_buf->skb = skb;
2377
2378 if (cons == prod)
2379 return;
2380
Michael Chanb6016b72005-05-26 13:03:09 -07002381 pci_unmap_addr_set(prod_rx_buf, mapping,
2382 pci_unmap_addr(cons_rx_buf, mapping));
2383
Michael Chan3fdfcc22006-03-20 17:49:49 -08002384 cons_bd = &bp->rx_desc_ring[RX_RING(cons)][RX_IDX(cons)];
2385 prod_bd = &bp->rx_desc_ring[RX_RING(prod)][RX_IDX(prod)];
Michael Chan236b6392006-03-20 17:49:02 -08002386 prod_bd->rx_bd_haddr_hi = cons_bd->rx_bd_haddr_hi;
2387 prod_bd->rx_bd_haddr_lo = cons_bd->rx_bd_haddr_lo;
Michael Chanb6016b72005-05-26 13:03:09 -07002388}
2389
2390static int
2391bnx2_rx_int(struct bnx2 *bp, int budget)
2392{
Michael Chanf4e418f2005-11-04 08:53:48 -08002393 struct status_block *sblk = bp->status_blk;
Michael Chanb6016b72005-05-26 13:03:09 -07002394 u16 hw_cons, sw_cons, sw_ring_cons, sw_prod, sw_ring_prod;
2395 struct l2_fhdr *rx_hdr;
2396 int rx_pkt = 0;
2397
Michael Chanf4e418f2005-11-04 08:53:48 -08002398 hw_cons = bp->hw_rx_cons = sblk->status_rx_quick_consumer_index0;
Michael Chanb6016b72005-05-26 13:03:09 -07002399 if ((hw_cons & MAX_RX_DESC_CNT) == MAX_RX_DESC_CNT) {
2400 hw_cons++;
2401 }
2402 sw_cons = bp->rx_cons;
2403 sw_prod = bp->rx_prod;
2404
2405 /* Memory barrier necessary as speculative reads of the rx
2406 * buffer can be ahead of the index in the status block
2407 */
2408 rmb();
2409 while (sw_cons != hw_cons) {
2410 unsigned int len;
Michael Chanade2bfe2006-01-23 16:09:51 -08002411 u32 status;
Michael Chanb6016b72005-05-26 13:03:09 -07002412 struct sw_bd *rx_buf;
2413 struct sk_buff *skb;
Michael Chan236b6392006-03-20 17:49:02 -08002414 dma_addr_t dma_addr;
Michael Chanb6016b72005-05-26 13:03:09 -07002415
2416 sw_ring_cons = RX_RING_IDX(sw_cons);
2417 sw_ring_prod = RX_RING_IDX(sw_prod);
2418
2419 rx_buf = &bp->rx_buf_ring[sw_ring_cons];
2420 skb = rx_buf->skb;
Michael Chan236b6392006-03-20 17:49:02 -08002421
2422 rx_buf->skb = NULL;
2423
2424 dma_addr = pci_unmap_addr(rx_buf, mapping);
2425
2426 pci_dma_sync_single_for_cpu(bp->pdev, dma_addr,
Michael Chanb6016b72005-05-26 13:03:09 -07002427 bp->rx_offset + RX_COPY_THRESH, PCI_DMA_FROMDEVICE);
2428
2429 rx_hdr = (struct l2_fhdr *) skb->data;
2430 len = rx_hdr->l2_fhdr_pkt_len - 4;
2431
Michael Chanade2bfe2006-01-23 16:09:51 -08002432 if ((status = rx_hdr->l2_fhdr_status) &
Michael Chanb6016b72005-05-26 13:03:09 -07002433 (L2_FHDR_ERRORS_BAD_CRC |
2434 L2_FHDR_ERRORS_PHY_DECODE |
2435 L2_FHDR_ERRORS_ALIGNMENT |
2436 L2_FHDR_ERRORS_TOO_SHORT |
2437 L2_FHDR_ERRORS_GIANT_FRAME)) {
2438
2439 goto reuse_rx;
2440 }
2441
2442 /* Since we don't have a jumbo ring, copy small packets
2443 * if mtu > 1500
2444 */
2445 if ((bp->dev->mtu > 1500) && (len <= RX_COPY_THRESH)) {
2446 struct sk_buff *new_skb;
2447
Michael Chan932f3772006-08-15 01:39:36 -07002448 new_skb = netdev_alloc_skb(bp->dev, len + 2);
Michael Chanb6016b72005-05-26 13:03:09 -07002449 if (new_skb == NULL)
2450 goto reuse_rx;
2451
2452 /* aligned copy */
Arnaldo Carvalho de Melod626f622007-03-27 18:55:52 -03002453 skb_copy_from_linear_data_offset(skb, bp->rx_offset - 2,
2454 new_skb->data, len + 2);
Michael Chanb6016b72005-05-26 13:03:09 -07002455 skb_reserve(new_skb, 2);
2456 skb_put(new_skb, len);
Michael Chanb6016b72005-05-26 13:03:09 -07002457
2458 bnx2_reuse_rx_skb(bp, skb,
2459 sw_ring_cons, sw_ring_prod);
2460
2461 skb = new_skb;
2462 }
2463 else if (bnx2_alloc_rx_skb(bp, sw_ring_prod) == 0) {
Michael Chan236b6392006-03-20 17:49:02 -08002464 pci_unmap_single(bp->pdev, dma_addr,
Michael Chanb6016b72005-05-26 13:03:09 -07002465 bp->rx_buf_use_size, PCI_DMA_FROMDEVICE);
2466
2467 skb_reserve(skb, bp->rx_offset);
2468 skb_put(skb, len);
2469 }
2470 else {
2471reuse_rx:
2472 bnx2_reuse_rx_skb(bp, skb,
2473 sw_ring_cons, sw_ring_prod);
2474 goto next_rx;
2475 }
2476
2477 skb->protocol = eth_type_trans(skb, bp->dev);
2478
2479 if ((len > (bp->dev->mtu + ETH_HLEN)) &&
Alexey Dobriyand1e100b2006-06-11 20:57:17 -07002480 (ntohs(skb->protocol) != 0x8100)) {
Michael Chanb6016b72005-05-26 13:03:09 -07002481
Michael Chan745720e2006-06-29 12:37:41 -07002482 dev_kfree_skb(skb);
Michael Chanb6016b72005-05-26 13:03:09 -07002483 goto next_rx;
2484
2485 }
2486
Michael Chanb6016b72005-05-26 13:03:09 -07002487 skb->ip_summed = CHECKSUM_NONE;
2488 if (bp->rx_csum &&
2489 (status & (L2_FHDR_STATUS_TCP_SEGMENT |
2490 L2_FHDR_STATUS_UDP_DATAGRAM))) {
2491
Michael Chanade2bfe2006-01-23 16:09:51 -08002492 if (likely((status & (L2_FHDR_ERRORS_TCP_XSUM |
2493 L2_FHDR_ERRORS_UDP_XSUM)) == 0))
Michael Chanb6016b72005-05-26 13:03:09 -07002494 skb->ip_summed = CHECKSUM_UNNECESSARY;
2495 }
2496
2497#ifdef BCM_VLAN
2498 if ((status & L2_FHDR_STATUS_L2_VLAN_TAG) && (bp->vlgrp != 0)) {
2499 vlan_hwaccel_receive_skb(skb, bp->vlgrp,
2500 rx_hdr->l2_fhdr_vlan_tag);
2501 }
2502 else
2503#endif
2504 netif_receive_skb(skb);
2505
2506 bp->dev->last_rx = jiffies;
2507 rx_pkt++;
2508
2509next_rx:
Michael Chanb6016b72005-05-26 13:03:09 -07002510 sw_cons = NEXT_RX_BD(sw_cons);
2511 sw_prod = NEXT_RX_BD(sw_prod);
2512
2513 if ((rx_pkt == budget))
2514 break;
Michael Chanf4e418f2005-11-04 08:53:48 -08002515
2516 /* Refresh hw_cons to see if there is new work */
2517 if (sw_cons == hw_cons) {
2518 hw_cons = bp->hw_rx_cons =
2519 sblk->status_rx_quick_consumer_index0;
2520 if ((hw_cons & MAX_RX_DESC_CNT) == MAX_RX_DESC_CNT)
2521 hw_cons++;
2522 rmb();
2523 }
Michael Chanb6016b72005-05-26 13:03:09 -07002524 }
2525 bp->rx_cons = sw_cons;
2526 bp->rx_prod = sw_prod;
2527
2528 REG_WR16(bp, MB_RX_CID_ADDR + BNX2_L2CTX_HOST_BDIDX, sw_prod);
2529
2530 REG_WR(bp, MB_RX_CID_ADDR + BNX2_L2CTX_HOST_BSEQ, bp->rx_prod_bseq);
2531
2532 mmiowb();
2533
2534 return rx_pkt;
2535
2536}
2537
2538/* MSI ISR - The only difference between this and the INTx ISR
2539 * is that the MSI interrupt is always serviced.
2540 */
2541static irqreturn_t
David Howells7d12e782006-10-05 14:55:46 +01002542bnx2_msi(int irq, void *dev_instance)
Michael Chanb6016b72005-05-26 13:03:09 -07002543{
2544 struct net_device *dev = dev_instance;
Michael Chan972ec0d2006-01-23 16:12:43 -08002545 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07002546
Michael Chanc921e4c2005-09-08 13:15:32 -07002547 prefetch(bp->status_blk);
Michael Chanb6016b72005-05-26 13:03:09 -07002548 REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
2549 BNX2_PCICFG_INT_ACK_CMD_USE_INT_HC_PARAM |
2550 BNX2_PCICFG_INT_ACK_CMD_MASK_INT);
2551
2552 /* Return here if interrupt is disabled. */
Michael Chan73eef4c2005-08-25 15:39:15 -07002553 if (unlikely(atomic_read(&bp->intr_sem) != 0))
2554 return IRQ_HANDLED;
Michael Chanb6016b72005-05-26 13:03:09 -07002555
Stephen Hemmingerbea33482007-10-03 16:41:36 -07002556 netif_rx_schedule(dev, &bp->napi);
Michael Chanb6016b72005-05-26 13:03:09 -07002557
Michael Chan73eef4c2005-08-25 15:39:15 -07002558 return IRQ_HANDLED;
Michael Chanb6016b72005-05-26 13:03:09 -07002559}
2560
2561static irqreturn_t
Michael Chan8e6a72c2007-05-03 13:24:48 -07002562bnx2_msi_1shot(int irq, void *dev_instance)
2563{
2564 struct net_device *dev = dev_instance;
2565 struct bnx2 *bp = netdev_priv(dev);
2566
2567 prefetch(bp->status_blk);
2568
2569 /* Return here if interrupt is disabled. */
2570 if (unlikely(atomic_read(&bp->intr_sem) != 0))
2571 return IRQ_HANDLED;
2572
Stephen Hemmingerbea33482007-10-03 16:41:36 -07002573 netif_rx_schedule(dev, &bp->napi);
Michael Chan8e6a72c2007-05-03 13:24:48 -07002574
2575 return IRQ_HANDLED;
2576}
2577
2578static irqreturn_t
David Howells7d12e782006-10-05 14:55:46 +01002579bnx2_interrupt(int irq, void *dev_instance)
Michael Chanb6016b72005-05-26 13:03:09 -07002580{
2581 struct net_device *dev = dev_instance;
Michael Chan972ec0d2006-01-23 16:12:43 -08002582 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb8a7ce72007-07-07 22:51:03 -07002583 struct status_block *sblk = bp->status_blk;
Michael Chanb6016b72005-05-26 13:03:09 -07002584
2585 /* When using INTx, it is possible for the interrupt to arrive
2586 * at the CPU before the status block posted prior to the
2587 * interrupt. Reading a register will flush the status block.
2588 * When using MSI, the MSI message will always complete after
2589 * the status block write.
2590 */
Michael Chanb8a7ce72007-07-07 22:51:03 -07002591 if ((sblk->status_idx == bp->last_status_idx) &&
Michael Chanb6016b72005-05-26 13:03:09 -07002592 (REG_RD(bp, BNX2_PCICFG_MISC_STATUS) &
2593 BNX2_PCICFG_MISC_STATUS_INTA_VALUE))
Michael Chan73eef4c2005-08-25 15:39:15 -07002594 return IRQ_NONE;
Michael Chanb6016b72005-05-26 13:03:09 -07002595
2596 REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
2597 BNX2_PCICFG_INT_ACK_CMD_USE_INT_HC_PARAM |
2598 BNX2_PCICFG_INT_ACK_CMD_MASK_INT);
2599
Michael Chanb8a7ce72007-07-07 22:51:03 -07002600 /* Read back to deassert IRQ immediately to avoid too many
2601 * spurious interrupts.
2602 */
2603 REG_RD(bp, BNX2_PCICFG_INT_ACK_CMD);
2604
Michael Chanb6016b72005-05-26 13:03:09 -07002605 /* Return here if interrupt is shared and is disabled. */
Michael Chan73eef4c2005-08-25 15:39:15 -07002606 if (unlikely(atomic_read(&bp->intr_sem) != 0))
2607 return IRQ_HANDLED;
Michael Chanb6016b72005-05-26 13:03:09 -07002608
Stephen Hemmingerbea33482007-10-03 16:41:36 -07002609 if (netif_rx_schedule_prep(dev, &bp->napi)) {
Michael Chanb8a7ce72007-07-07 22:51:03 -07002610 bp->last_status_idx = sblk->status_idx;
Stephen Hemmingerbea33482007-10-03 16:41:36 -07002611 __netif_rx_schedule(dev, &bp->napi);
Michael Chanb8a7ce72007-07-07 22:51:03 -07002612 }
Michael Chanb6016b72005-05-26 13:03:09 -07002613
Michael Chan73eef4c2005-08-25 15:39:15 -07002614 return IRQ_HANDLED;
Michael Chanb6016b72005-05-26 13:03:09 -07002615}
2616
Michael Chan0d8a6572007-07-07 22:49:43 -07002617#define STATUS_ATTN_EVENTS (STATUS_ATTN_BITS_LINK_STATE | \
2618 STATUS_ATTN_BITS_TIMER_ABORT)
Michael Chanda3e4fb2007-05-03 13:24:23 -07002619
Michael Chanf4e418f2005-11-04 08:53:48 -08002620static inline int
2621bnx2_has_work(struct bnx2 *bp)
2622{
2623 struct status_block *sblk = bp->status_blk;
2624
2625 if ((sblk->status_rx_quick_consumer_index0 != bp->hw_rx_cons) ||
2626 (sblk->status_tx_quick_consumer_index0 != bp->hw_tx_cons))
2627 return 1;
2628
Michael Chanda3e4fb2007-05-03 13:24:23 -07002629 if ((sblk->status_attn_bits & STATUS_ATTN_EVENTS) !=
2630 (sblk->status_attn_bits_ack & STATUS_ATTN_EVENTS))
Michael Chanf4e418f2005-11-04 08:53:48 -08002631 return 1;
2632
2633 return 0;
2634}
2635
Michael Chanb6016b72005-05-26 13:03:09 -07002636static int
Stephen Hemmingerbea33482007-10-03 16:41:36 -07002637bnx2_poll(struct napi_struct *napi, int budget)
Michael Chanb6016b72005-05-26 13:03:09 -07002638{
Stephen Hemmingerbea33482007-10-03 16:41:36 -07002639 struct bnx2 *bp = container_of(napi, struct bnx2, napi);
2640 struct net_device *dev = bp->dev;
Michael Chanda3e4fb2007-05-03 13:24:23 -07002641 struct status_block *sblk = bp->status_blk;
2642 u32 status_attn_bits = sblk->status_attn_bits;
2643 u32 status_attn_bits_ack = sblk->status_attn_bits_ack;
Stephen Hemmingerbea33482007-10-03 16:41:36 -07002644 int work_done = 0;
Michael Chanb6016b72005-05-26 13:03:09 -07002645
Michael Chanda3e4fb2007-05-03 13:24:23 -07002646 if ((status_attn_bits & STATUS_ATTN_EVENTS) !=
2647 (status_attn_bits_ack & STATUS_ATTN_EVENTS)) {
Michael Chanb6016b72005-05-26 13:03:09 -07002648
Michael Chanb6016b72005-05-26 13:03:09 -07002649 bnx2_phy_int(bp);
Michael Chanbf5295b2006-03-23 01:11:56 -08002650
2651 /* This is needed to take care of transient status
2652 * during link changes.
2653 */
2654 REG_WR(bp, BNX2_HC_COMMAND,
2655 bp->hc_cmd | BNX2_HC_COMMAND_COAL_NOW_WO_INT);
2656 REG_RD(bp, BNX2_HC_COMMAND);
Michael Chanb6016b72005-05-26 13:03:09 -07002657 }
2658
Michael Chanf4e418f2005-11-04 08:53:48 -08002659 if (bp->status_blk->status_tx_quick_consumer_index0 != bp->hw_tx_cons)
Michael Chanb6016b72005-05-26 13:03:09 -07002660 bnx2_tx_int(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07002661
Stephen Hemmingerbea33482007-10-03 16:41:36 -07002662 if (bp->status_blk->status_rx_quick_consumer_index0 != bp->hw_rx_cons)
2663 work_done = bnx2_rx_int(bp, budget);
Jeff Garzik6aa20a22006-09-13 13:24:59 -04002664
Michael Chanf4e418f2005-11-04 08:53:48 -08002665 bp->last_status_idx = bp->status_blk->status_idx;
2666 rmb();
2667
2668 if (!bnx2_has_work(bp)) {
Stephen Hemmingerbea33482007-10-03 16:41:36 -07002669 netif_rx_complete(dev, napi);
Michael Chan1269a8a2006-01-23 16:11:03 -08002670 if (likely(bp->flags & USING_MSI_FLAG)) {
2671 REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
2672 BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
2673 bp->last_status_idx);
2674 return 0;
2675 }
Michael Chanb6016b72005-05-26 13:03:09 -07002676 REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
Michael Chan1269a8a2006-01-23 16:11:03 -08002677 BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
2678 BNX2_PCICFG_INT_ACK_CMD_MASK_INT |
2679 bp->last_status_idx);
2680
2681 REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
2682 BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
2683 bp->last_status_idx);
Michael Chanb6016b72005-05-26 13:03:09 -07002684 }
2685
Stephen Hemmingerbea33482007-10-03 16:41:36 -07002686 return work_done;
Michael Chanb6016b72005-05-26 13:03:09 -07002687}
2688
Herbert Xu932ff272006-06-09 12:20:56 -07002689/* Called with rtnl_lock from vlan functions and also netif_tx_lock
Michael Chanb6016b72005-05-26 13:03:09 -07002690 * from set_multicast.
2691 */
2692static void
2693bnx2_set_rx_mode(struct net_device *dev)
2694{
Michael Chan972ec0d2006-01-23 16:12:43 -08002695 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07002696 u32 rx_mode, sort_mode;
2697 int i;
Michael Chanb6016b72005-05-26 13:03:09 -07002698
Michael Chanc770a652005-08-25 15:38:39 -07002699 spin_lock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07002700
2701 rx_mode = bp->rx_mode & ~(BNX2_EMAC_RX_MODE_PROMISCUOUS |
2702 BNX2_EMAC_RX_MODE_KEEP_VLAN_TAG);
2703 sort_mode = 1 | BNX2_RPM_SORT_USER0_BC_EN;
2704#ifdef BCM_VLAN
Michael Chane29054f2006-01-23 16:06:06 -08002705 if (!bp->vlgrp && !(bp->flags & ASF_ENABLE_FLAG))
Michael Chanb6016b72005-05-26 13:03:09 -07002706 rx_mode |= BNX2_EMAC_RX_MODE_KEEP_VLAN_TAG;
Michael Chanb6016b72005-05-26 13:03:09 -07002707#else
Michael Chane29054f2006-01-23 16:06:06 -08002708 if (!(bp->flags & ASF_ENABLE_FLAG))
2709 rx_mode |= BNX2_EMAC_RX_MODE_KEEP_VLAN_TAG;
Michael Chanb6016b72005-05-26 13:03:09 -07002710#endif
2711 if (dev->flags & IFF_PROMISC) {
2712 /* Promiscuous mode. */
2713 rx_mode |= BNX2_EMAC_RX_MODE_PROMISCUOUS;
Michael Chan75108732006-11-19 14:06:40 -08002714 sort_mode |= BNX2_RPM_SORT_USER0_PROM_EN |
2715 BNX2_RPM_SORT_USER0_PROM_VLAN;
Michael Chanb6016b72005-05-26 13:03:09 -07002716 }
2717 else if (dev->flags & IFF_ALLMULTI) {
2718 for (i = 0; i < NUM_MC_HASH_REGISTERS; i++) {
2719 REG_WR(bp, BNX2_EMAC_MULTICAST_HASH0 + (i * 4),
2720 0xffffffff);
2721 }
2722 sort_mode |= BNX2_RPM_SORT_USER0_MC_EN;
2723 }
2724 else {
2725 /* Accept one or more multicast(s). */
2726 struct dev_mc_list *mclist;
2727 u32 mc_filter[NUM_MC_HASH_REGISTERS];
2728 u32 regidx;
2729 u32 bit;
2730 u32 crc;
2731
2732 memset(mc_filter, 0, 4 * NUM_MC_HASH_REGISTERS);
2733
2734 for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
2735 i++, mclist = mclist->next) {
2736
2737 crc = ether_crc_le(ETH_ALEN, mclist->dmi_addr);
2738 bit = crc & 0xff;
2739 regidx = (bit & 0xe0) >> 5;
2740 bit &= 0x1f;
2741 mc_filter[regidx] |= (1 << bit);
2742 }
2743
2744 for (i = 0; i < NUM_MC_HASH_REGISTERS; i++) {
2745 REG_WR(bp, BNX2_EMAC_MULTICAST_HASH0 + (i * 4),
2746 mc_filter[i]);
2747 }
2748
2749 sort_mode |= BNX2_RPM_SORT_USER0_MC_HSH_EN;
2750 }
2751
2752 if (rx_mode != bp->rx_mode) {
2753 bp->rx_mode = rx_mode;
2754 REG_WR(bp, BNX2_EMAC_RX_MODE, rx_mode);
2755 }
2756
2757 REG_WR(bp, BNX2_RPM_SORT_USER0, 0x0);
2758 REG_WR(bp, BNX2_RPM_SORT_USER0, sort_mode);
2759 REG_WR(bp, BNX2_RPM_SORT_USER0, sort_mode | BNX2_RPM_SORT_USER0_ENA);
2760
Michael Chanc770a652005-08-25 15:38:39 -07002761 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07002762}
2763
Denys Vlasenkob3448b02007-09-30 17:55:51 -07002764/* To be moved to generic lib/ */
Michael Chanfba9fe92006-06-12 22:21:25 -07002765static int
Denys Vlasenkob3448b02007-09-30 17:55:51 -07002766bnx2_gunzip(void *gunzip_buf, unsigned sz, u8 *zbuf, int len)
Michael Chanfba9fe92006-06-12 22:21:25 -07002767{
Denys Vlasenkob3448b02007-09-30 17:55:51 -07002768 struct z_stream_s *strm;
2769 int rc;
Michael Chanfba9fe92006-06-12 22:21:25 -07002770
Denys Vlasenkob3448b02007-09-30 17:55:51 -07002771 /* gzip header (1f,8b,08... 10 bytes total + possible asciz filename)
2772 * is stripped */
2773
2774 rc = -ENOMEM;
2775 strm = kmalloc(sizeof(*strm), GFP_KERNEL);
2776 if (strm == NULL)
Michael Chanfba9fe92006-06-12 22:21:25 -07002777 goto gunzip_nomem2;
Denys Vlasenkob3448b02007-09-30 17:55:51 -07002778 strm->workspace = kmalloc(zlib_inflate_workspacesize(), GFP_KERNEL);
2779 if (strm->workspace == NULL)
Michael Chanfba9fe92006-06-12 22:21:25 -07002780 goto gunzip_nomem3;
2781
Denys Vlasenkob3448b02007-09-30 17:55:51 -07002782 strm->next_in = zbuf;
2783 strm->avail_in = len;
2784 strm->next_out = gunzip_buf;
2785 strm->avail_out = sz;
Michael Chanfba9fe92006-06-12 22:21:25 -07002786
Denys Vlasenkob3448b02007-09-30 17:55:51 -07002787 rc = zlib_inflateInit2(strm, -MAX_WBITS);
2788 if (rc == Z_OK) {
2789 rc = zlib_inflate(strm, Z_FINISH);
2790 /* after Z_FINISH, only Z_STREAM_END is "we unpacked it all" */
2791 if (rc == Z_STREAM_END)
2792 rc = sz - strm->avail_out;
2793 else
2794 rc = -EINVAL;
2795 zlib_inflateEnd(strm);
2796 } else
2797 rc = -EINVAL;
2798
2799 kfree(strm->workspace);
Michael Chanfba9fe92006-06-12 22:21:25 -07002800gunzip_nomem3:
Denys Vlasenkob3448b02007-09-30 17:55:51 -07002801 kfree(strm);
Michael Chanfba9fe92006-06-12 22:21:25 -07002802gunzip_nomem2:
Michael Chanfba9fe92006-06-12 22:21:25 -07002803 return rc;
2804}
2805
Michael Chanb6016b72005-05-26 13:03:09 -07002806static void
2807load_rv2p_fw(struct bnx2 *bp, u32 *rv2p_code, u32 rv2p_code_len,
2808 u32 rv2p_proc)
2809{
2810 int i;
2811 u32 val;
2812
2813
2814 for (i = 0; i < rv2p_code_len; i += 8) {
Michael Chanfba9fe92006-06-12 22:21:25 -07002815 REG_WR(bp, BNX2_RV2P_INSTR_HIGH, cpu_to_le32(*rv2p_code));
Michael Chanb6016b72005-05-26 13:03:09 -07002816 rv2p_code++;
Michael Chanfba9fe92006-06-12 22:21:25 -07002817 REG_WR(bp, BNX2_RV2P_INSTR_LOW, cpu_to_le32(*rv2p_code));
Michael Chanb6016b72005-05-26 13:03:09 -07002818 rv2p_code++;
2819
2820 if (rv2p_proc == RV2P_PROC1) {
2821 val = (i / 8) | BNX2_RV2P_PROC1_ADDR_CMD_RDWR;
2822 REG_WR(bp, BNX2_RV2P_PROC1_ADDR_CMD, val);
2823 }
2824 else {
2825 val = (i / 8) | BNX2_RV2P_PROC2_ADDR_CMD_RDWR;
2826 REG_WR(bp, BNX2_RV2P_PROC2_ADDR_CMD, val);
2827 }
2828 }
2829
2830 /* Reset the processor, un-stall is done later. */
2831 if (rv2p_proc == RV2P_PROC1) {
2832 REG_WR(bp, BNX2_RV2P_COMMAND, BNX2_RV2P_COMMAND_PROC1_RESET);
2833 }
2834 else {
2835 REG_WR(bp, BNX2_RV2P_COMMAND, BNX2_RV2P_COMMAND_PROC2_RESET);
2836 }
2837}
2838
Michael Chanaf3ee512006-11-19 14:09:25 -08002839static int
Michael Chanb6016b72005-05-26 13:03:09 -07002840load_cpu_fw(struct bnx2 *bp, struct cpu_reg *cpu_reg, struct fw_info *fw)
2841{
2842 u32 offset;
2843 u32 val;
Michael Chanaf3ee512006-11-19 14:09:25 -08002844 int rc;
Michael Chanb6016b72005-05-26 13:03:09 -07002845
2846 /* Halt the CPU. */
2847 val = REG_RD_IND(bp, cpu_reg->mode);
2848 val |= cpu_reg->mode_value_halt;
2849 REG_WR_IND(bp, cpu_reg->mode, val);
2850 REG_WR_IND(bp, cpu_reg->state, cpu_reg->state_value_clear);
2851
2852 /* Load the Text area. */
2853 offset = cpu_reg->spad_base + (fw->text_addr - cpu_reg->mips_view_base);
Michael Chanaf3ee512006-11-19 14:09:25 -08002854 if (fw->gz_text) {
Denys Vlasenkob3448b02007-09-30 17:55:51 -07002855 u32 *text;
Michael Chanb6016b72005-05-26 13:03:09 -07002856 int j;
2857
Denys Vlasenkob3448b02007-09-30 17:55:51 -07002858 text = vmalloc(FW_BUF_SIZE);
2859 if (!text)
2860 return -ENOMEM;
2861 rc = bnx2_gunzip(text, FW_BUF_SIZE, fw->gz_text, fw->gz_text_len);
2862 if (rc < 0) {
2863 vfree(text);
2864 return rc;
2865 }
Michael Chanb6016b72005-05-26 13:03:09 -07002866 for (j = 0; j < (fw->text_len / 4); j++, offset += 4) {
Denys Vlasenkob3448b02007-09-30 17:55:51 -07002867 REG_WR_IND(bp, offset, cpu_to_le32(text[j]));
Michael Chanb6016b72005-05-26 13:03:09 -07002868 }
Denys Vlasenkob3448b02007-09-30 17:55:51 -07002869 vfree(text);
Michael Chanb6016b72005-05-26 13:03:09 -07002870 }
2871
2872 /* Load the Data area. */
2873 offset = cpu_reg->spad_base + (fw->data_addr - cpu_reg->mips_view_base);
2874 if (fw->data) {
2875 int j;
2876
2877 for (j = 0; j < (fw->data_len / 4); j++, offset += 4) {
2878 REG_WR_IND(bp, offset, fw->data[j]);
2879 }
2880 }
2881
2882 /* Load the SBSS area. */
2883 offset = cpu_reg->spad_base + (fw->sbss_addr - cpu_reg->mips_view_base);
2884 if (fw->sbss) {
2885 int j;
2886
2887 for (j = 0; j < (fw->sbss_len / 4); j++, offset += 4) {
2888 REG_WR_IND(bp, offset, fw->sbss[j]);
2889 }
2890 }
2891
2892 /* Load the BSS area. */
2893 offset = cpu_reg->spad_base + (fw->bss_addr - cpu_reg->mips_view_base);
2894 if (fw->bss) {
2895 int j;
2896
2897 for (j = 0; j < (fw->bss_len/4); j++, offset += 4) {
2898 REG_WR_IND(bp, offset, fw->bss[j]);
2899 }
2900 }
2901
2902 /* Load the Read-Only area. */
2903 offset = cpu_reg->spad_base +
2904 (fw->rodata_addr - cpu_reg->mips_view_base);
2905 if (fw->rodata) {
2906 int j;
2907
2908 for (j = 0; j < (fw->rodata_len / 4); j++, offset += 4) {
2909 REG_WR_IND(bp, offset, fw->rodata[j]);
2910 }
2911 }
2912
2913 /* Clear the pre-fetch instruction. */
2914 REG_WR_IND(bp, cpu_reg->inst, 0);
2915 REG_WR_IND(bp, cpu_reg->pc, fw->start_addr);
2916
2917 /* Start the CPU. */
2918 val = REG_RD_IND(bp, cpu_reg->mode);
2919 val &= ~cpu_reg->mode_value_halt;
2920 REG_WR_IND(bp, cpu_reg->state, cpu_reg->state_value_clear);
2921 REG_WR_IND(bp, cpu_reg->mode, val);
Michael Chanaf3ee512006-11-19 14:09:25 -08002922
2923 return 0;
Michael Chanb6016b72005-05-26 13:03:09 -07002924}
2925
Michael Chanfba9fe92006-06-12 22:21:25 -07002926static int
Michael Chanb6016b72005-05-26 13:03:09 -07002927bnx2_init_cpus(struct bnx2 *bp)
2928{
2929 struct cpu_reg cpu_reg;
Michael Chanaf3ee512006-11-19 14:09:25 -08002930 struct fw_info *fw;
Denys Vlasenkob3448b02007-09-30 17:55:51 -07002931 int rc;
Michael Chanfba9fe92006-06-12 22:21:25 -07002932 void *text;
Michael Chanb6016b72005-05-26 13:03:09 -07002933
2934 /* Initialize the RV2P processor. */
Denys Vlasenkob3448b02007-09-30 17:55:51 -07002935 text = vmalloc(FW_BUF_SIZE);
2936 if (!text)
2937 return -ENOMEM;
2938 rc = bnx2_gunzip(text, FW_BUF_SIZE, bnx2_rv2p_proc1, sizeof(bnx2_rv2p_proc1));
2939 if (rc < 0) {
2940 vfree(text);
Michael Chanfba9fe92006-06-12 22:21:25 -07002941 goto init_cpu_err;
Denys Vlasenkob3448b02007-09-30 17:55:51 -07002942 }
2943 load_rv2p_fw(bp, text, rc /* == len */, RV2P_PROC1);
Michael Chanfba9fe92006-06-12 22:21:25 -07002944
Denys Vlasenkob3448b02007-09-30 17:55:51 -07002945 rc = bnx2_gunzip(text, FW_BUF_SIZE, bnx2_rv2p_proc2, sizeof(bnx2_rv2p_proc2));
2946 if (rc < 0) {
2947 vfree(text);
Michael Chanfba9fe92006-06-12 22:21:25 -07002948 goto init_cpu_err;
Denys Vlasenkob3448b02007-09-30 17:55:51 -07002949 }
2950 load_rv2p_fw(bp, text, rc /* == len */, RV2P_PROC2);
2951 vfree(text);
Michael Chanb6016b72005-05-26 13:03:09 -07002952
2953 /* Initialize the RX Processor. */
2954 cpu_reg.mode = BNX2_RXP_CPU_MODE;
2955 cpu_reg.mode_value_halt = BNX2_RXP_CPU_MODE_SOFT_HALT;
2956 cpu_reg.mode_value_sstep = BNX2_RXP_CPU_MODE_STEP_ENA;
2957 cpu_reg.state = BNX2_RXP_CPU_STATE;
2958 cpu_reg.state_value_clear = 0xffffff;
2959 cpu_reg.gpr0 = BNX2_RXP_CPU_REG_FILE;
2960 cpu_reg.evmask = BNX2_RXP_CPU_EVENT_MASK;
2961 cpu_reg.pc = BNX2_RXP_CPU_PROGRAM_COUNTER;
2962 cpu_reg.inst = BNX2_RXP_CPU_INSTRUCTION;
2963 cpu_reg.bp = BNX2_RXP_CPU_HW_BREAKPOINT;
2964 cpu_reg.spad_base = BNX2_RXP_SCRATCH;
2965 cpu_reg.mips_view_base = 0x8000000;
Jeff Garzik6aa20a22006-09-13 13:24:59 -04002966
Michael Chand43584c2006-11-19 14:14:35 -08002967 if (CHIP_NUM(bp) == CHIP_NUM_5709)
2968 fw = &bnx2_rxp_fw_09;
2969 else
2970 fw = &bnx2_rxp_fw_06;
Michael Chanb6016b72005-05-26 13:03:09 -07002971
Michael Chanaf3ee512006-11-19 14:09:25 -08002972 rc = load_cpu_fw(bp, &cpu_reg, fw);
Michael Chanfba9fe92006-06-12 22:21:25 -07002973 if (rc)
2974 goto init_cpu_err;
2975
Michael Chanb6016b72005-05-26 13:03:09 -07002976 /* Initialize the TX Processor. */
2977 cpu_reg.mode = BNX2_TXP_CPU_MODE;
2978 cpu_reg.mode_value_halt = BNX2_TXP_CPU_MODE_SOFT_HALT;
2979 cpu_reg.mode_value_sstep = BNX2_TXP_CPU_MODE_STEP_ENA;
2980 cpu_reg.state = BNX2_TXP_CPU_STATE;
2981 cpu_reg.state_value_clear = 0xffffff;
2982 cpu_reg.gpr0 = BNX2_TXP_CPU_REG_FILE;
2983 cpu_reg.evmask = BNX2_TXP_CPU_EVENT_MASK;
2984 cpu_reg.pc = BNX2_TXP_CPU_PROGRAM_COUNTER;
2985 cpu_reg.inst = BNX2_TXP_CPU_INSTRUCTION;
2986 cpu_reg.bp = BNX2_TXP_CPU_HW_BREAKPOINT;
2987 cpu_reg.spad_base = BNX2_TXP_SCRATCH;
2988 cpu_reg.mips_view_base = 0x8000000;
Jeff Garzik6aa20a22006-09-13 13:24:59 -04002989
Michael Chand43584c2006-11-19 14:14:35 -08002990 if (CHIP_NUM(bp) == CHIP_NUM_5709)
2991 fw = &bnx2_txp_fw_09;
2992 else
2993 fw = &bnx2_txp_fw_06;
Michael Chanb6016b72005-05-26 13:03:09 -07002994
Michael Chanaf3ee512006-11-19 14:09:25 -08002995 rc = load_cpu_fw(bp, &cpu_reg, fw);
Michael Chanfba9fe92006-06-12 22:21:25 -07002996 if (rc)
2997 goto init_cpu_err;
2998
Michael Chanb6016b72005-05-26 13:03:09 -07002999 /* Initialize the TX Patch-up Processor. */
3000 cpu_reg.mode = BNX2_TPAT_CPU_MODE;
3001 cpu_reg.mode_value_halt = BNX2_TPAT_CPU_MODE_SOFT_HALT;
3002 cpu_reg.mode_value_sstep = BNX2_TPAT_CPU_MODE_STEP_ENA;
3003 cpu_reg.state = BNX2_TPAT_CPU_STATE;
3004 cpu_reg.state_value_clear = 0xffffff;
3005 cpu_reg.gpr0 = BNX2_TPAT_CPU_REG_FILE;
3006 cpu_reg.evmask = BNX2_TPAT_CPU_EVENT_MASK;
3007 cpu_reg.pc = BNX2_TPAT_CPU_PROGRAM_COUNTER;
3008 cpu_reg.inst = BNX2_TPAT_CPU_INSTRUCTION;
3009 cpu_reg.bp = BNX2_TPAT_CPU_HW_BREAKPOINT;
3010 cpu_reg.spad_base = BNX2_TPAT_SCRATCH;
3011 cpu_reg.mips_view_base = 0x8000000;
Jeff Garzik6aa20a22006-09-13 13:24:59 -04003012
Michael Chand43584c2006-11-19 14:14:35 -08003013 if (CHIP_NUM(bp) == CHIP_NUM_5709)
3014 fw = &bnx2_tpat_fw_09;
3015 else
3016 fw = &bnx2_tpat_fw_06;
Michael Chanb6016b72005-05-26 13:03:09 -07003017
Michael Chanaf3ee512006-11-19 14:09:25 -08003018 rc = load_cpu_fw(bp, &cpu_reg, fw);
Michael Chanfba9fe92006-06-12 22:21:25 -07003019 if (rc)
3020 goto init_cpu_err;
3021
Michael Chanb6016b72005-05-26 13:03:09 -07003022 /* Initialize the Completion Processor. */
3023 cpu_reg.mode = BNX2_COM_CPU_MODE;
3024 cpu_reg.mode_value_halt = BNX2_COM_CPU_MODE_SOFT_HALT;
3025 cpu_reg.mode_value_sstep = BNX2_COM_CPU_MODE_STEP_ENA;
3026 cpu_reg.state = BNX2_COM_CPU_STATE;
3027 cpu_reg.state_value_clear = 0xffffff;
3028 cpu_reg.gpr0 = BNX2_COM_CPU_REG_FILE;
3029 cpu_reg.evmask = BNX2_COM_CPU_EVENT_MASK;
3030 cpu_reg.pc = BNX2_COM_CPU_PROGRAM_COUNTER;
3031 cpu_reg.inst = BNX2_COM_CPU_INSTRUCTION;
3032 cpu_reg.bp = BNX2_COM_CPU_HW_BREAKPOINT;
3033 cpu_reg.spad_base = BNX2_COM_SCRATCH;
3034 cpu_reg.mips_view_base = 0x8000000;
Jeff Garzik6aa20a22006-09-13 13:24:59 -04003035
Michael Chand43584c2006-11-19 14:14:35 -08003036 if (CHIP_NUM(bp) == CHIP_NUM_5709)
3037 fw = &bnx2_com_fw_09;
3038 else
3039 fw = &bnx2_com_fw_06;
Michael Chanb6016b72005-05-26 13:03:09 -07003040
Michael Chanaf3ee512006-11-19 14:09:25 -08003041 rc = load_cpu_fw(bp, &cpu_reg, fw);
Michael Chanfba9fe92006-06-12 22:21:25 -07003042 if (rc)
3043 goto init_cpu_err;
3044
Michael Chand43584c2006-11-19 14:14:35 -08003045 /* Initialize the Command Processor. */
3046 cpu_reg.mode = BNX2_CP_CPU_MODE;
3047 cpu_reg.mode_value_halt = BNX2_CP_CPU_MODE_SOFT_HALT;
3048 cpu_reg.mode_value_sstep = BNX2_CP_CPU_MODE_STEP_ENA;
3049 cpu_reg.state = BNX2_CP_CPU_STATE;
3050 cpu_reg.state_value_clear = 0xffffff;
3051 cpu_reg.gpr0 = BNX2_CP_CPU_REG_FILE;
3052 cpu_reg.evmask = BNX2_CP_CPU_EVENT_MASK;
3053 cpu_reg.pc = BNX2_CP_CPU_PROGRAM_COUNTER;
3054 cpu_reg.inst = BNX2_CP_CPU_INSTRUCTION;
3055 cpu_reg.bp = BNX2_CP_CPU_HW_BREAKPOINT;
3056 cpu_reg.spad_base = BNX2_CP_SCRATCH;
3057 cpu_reg.mips_view_base = 0x8000000;
Michael Chanb6016b72005-05-26 13:03:09 -07003058
Michael Chand43584c2006-11-19 14:14:35 -08003059 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
3060 fw = &bnx2_cp_fw_09;
Michael Chanb6016b72005-05-26 13:03:09 -07003061
Adrian Bunk6c1bbcc2006-12-07 15:10:06 -08003062 rc = load_cpu_fw(bp, &cpu_reg, fw);
Michael Chand43584c2006-11-19 14:14:35 -08003063 if (rc)
3064 goto init_cpu_err;
3065 }
Michael Chanfba9fe92006-06-12 22:21:25 -07003066init_cpu_err:
Michael Chanfba9fe92006-06-12 22:21:25 -07003067 return rc;
Michael Chanb6016b72005-05-26 13:03:09 -07003068}
3069
3070static int
Pavel Machek829ca9a2005-09-03 15:56:56 -07003071bnx2_set_power_state(struct bnx2 *bp, pci_power_t state)
Michael Chanb6016b72005-05-26 13:03:09 -07003072{
3073 u16 pmcsr;
3074
3075 pci_read_config_word(bp->pdev, bp->pm_cap + PCI_PM_CTRL, &pmcsr);
3076
3077 switch (state) {
Pavel Machek829ca9a2005-09-03 15:56:56 -07003078 case PCI_D0: {
Michael Chanb6016b72005-05-26 13:03:09 -07003079 u32 val;
3080
3081 pci_write_config_word(bp->pdev, bp->pm_cap + PCI_PM_CTRL,
3082 (pmcsr & ~PCI_PM_CTRL_STATE_MASK) |
3083 PCI_PM_CTRL_PME_STATUS);
3084
3085 if (pmcsr & PCI_PM_CTRL_STATE_MASK)
3086 /* delay required during transition out of D3hot */
3087 msleep(20);
3088
3089 val = REG_RD(bp, BNX2_EMAC_MODE);
3090 val |= BNX2_EMAC_MODE_MPKT_RCVD | BNX2_EMAC_MODE_ACPI_RCVD;
3091 val &= ~BNX2_EMAC_MODE_MPKT;
3092 REG_WR(bp, BNX2_EMAC_MODE, val);
3093
3094 val = REG_RD(bp, BNX2_RPM_CONFIG);
3095 val &= ~BNX2_RPM_CONFIG_ACPI_ENA;
3096 REG_WR(bp, BNX2_RPM_CONFIG, val);
3097 break;
3098 }
Pavel Machek829ca9a2005-09-03 15:56:56 -07003099 case PCI_D3hot: {
Michael Chanb6016b72005-05-26 13:03:09 -07003100 int i;
3101 u32 val, wol_msg;
3102
3103 if (bp->wol) {
3104 u32 advertising;
3105 u8 autoneg;
3106
3107 autoneg = bp->autoneg;
3108 advertising = bp->advertising;
3109
3110 bp->autoneg = AUTONEG_SPEED;
3111 bp->advertising = ADVERTISED_10baseT_Half |
3112 ADVERTISED_10baseT_Full |
3113 ADVERTISED_100baseT_Half |
3114 ADVERTISED_100baseT_Full |
3115 ADVERTISED_Autoneg;
3116
3117 bnx2_setup_copper_phy(bp);
3118
3119 bp->autoneg = autoneg;
3120 bp->advertising = advertising;
3121
3122 bnx2_set_mac_addr(bp);
3123
3124 val = REG_RD(bp, BNX2_EMAC_MODE);
3125
3126 /* Enable port mode. */
3127 val &= ~BNX2_EMAC_MODE_PORT;
3128 val |= BNX2_EMAC_MODE_PORT_MII |
3129 BNX2_EMAC_MODE_MPKT_RCVD |
3130 BNX2_EMAC_MODE_ACPI_RCVD |
Michael Chanb6016b72005-05-26 13:03:09 -07003131 BNX2_EMAC_MODE_MPKT;
3132
3133 REG_WR(bp, BNX2_EMAC_MODE, val);
3134
3135 /* receive all multicast */
3136 for (i = 0; i < NUM_MC_HASH_REGISTERS; i++) {
3137 REG_WR(bp, BNX2_EMAC_MULTICAST_HASH0 + (i * 4),
3138 0xffffffff);
3139 }
3140 REG_WR(bp, BNX2_EMAC_RX_MODE,
3141 BNX2_EMAC_RX_MODE_SORT_MODE);
3142
3143 val = 1 | BNX2_RPM_SORT_USER0_BC_EN |
3144 BNX2_RPM_SORT_USER0_MC_EN;
3145 REG_WR(bp, BNX2_RPM_SORT_USER0, 0x0);
3146 REG_WR(bp, BNX2_RPM_SORT_USER0, val);
3147 REG_WR(bp, BNX2_RPM_SORT_USER0, val |
3148 BNX2_RPM_SORT_USER0_ENA);
3149
3150 /* Need to enable EMAC and RPM for WOL. */
3151 REG_WR(bp, BNX2_MISC_ENABLE_SET_BITS,
3152 BNX2_MISC_ENABLE_SET_BITS_RX_PARSER_MAC_ENABLE |
3153 BNX2_MISC_ENABLE_SET_BITS_TX_HEADER_Q_ENABLE |
3154 BNX2_MISC_ENABLE_SET_BITS_EMAC_ENABLE);
3155
3156 val = REG_RD(bp, BNX2_RPM_CONFIG);
3157 val &= ~BNX2_RPM_CONFIG_ACPI_ENA;
3158 REG_WR(bp, BNX2_RPM_CONFIG, val);
3159
3160 wol_msg = BNX2_DRV_MSG_CODE_SUSPEND_WOL;
3161 }
3162 else {
3163 wol_msg = BNX2_DRV_MSG_CODE_SUSPEND_NO_WOL;
3164 }
3165
Michael Chandda1e392006-01-23 16:08:14 -08003166 if (!(bp->flags & NO_WOL_FLAG))
3167 bnx2_fw_sync(bp, BNX2_DRV_MSG_DATA_WAIT3 | wol_msg, 0);
Michael Chanb6016b72005-05-26 13:03:09 -07003168
3169 pmcsr &= ~PCI_PM_CTRL_STATE_MASK;
3170 if ((CHIP_ID(bp) == CHIP_ID_5706_A0) ||
3171 (CHIP_ID(bp) == CHIP_ID_5706_A1)) {
3172
3173 if (bp->wol)
3174 pmcsr |= 3;
3175 }
3176 else {
3177 pmcsr |= 3;
3178 }
3179 if (bp->wol) {
3180 pmcsr |= PCI_PM_CTRL_PME_ENABLE;
3181 }
3182 pci_write_config_word(bp->pdev, bp->pm_cap + PCI_PM_CTRL,
3183 pmcsr);
3184
3185 /* No more memory access after this point until
3186 * device is brought back to D0.
3187 */
3188 udelay(50);
3189 break;
3190 }
3191 default:
3192 return -EINVAL;
3193 }
3194 return 0;
3195}
3196
3197static int
3198bnx2_acquire_nvram_lock(struct bnx2 *bp)
3199{
3200 u32 val;
3201 int j;
3202
3203 /* Request access to the flash interface. */
3204 REG_WR(bp, BNX2_NVM_SW_ARB, BNX2_NVM_SW_ARB_ARB_REQ_SET2);
3205 for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) {
3206 val = REG_RD(bp, BNX2_NVM_SW_ARB);
3207 if (val & BNX2_NVM_SW_ARB_ARB_ARB2)
3208 break;
3209
3210 udelay(5);
3211 }
3212
3213 if (j >= NVRAM_TIMEOUT_COUNT)
3214 return -EBUSY;
3215
3216 return 0;
3217}
3218
3219static int
3220bnx2_release_nvram_lock(struct bnx2 *bp)
3221{
3222 int j;
3223 u32 val;
3224
3225 /* Relinquish nvram interface. */
3226 REG_WR(bp, BNX2_NVM_SW_ARB, BNX2_NVM_SW_ARB_ARB_REQ_CLR2);
3227
3228 for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) {
3229 val = REG_RD(bp, BNX2_NVM_SW_ARB);
3230 if (!(val & BNX2_NVM_SW_ARB_ARB_ARB2))
3231 break;
3232
3233 udelay(5);
3234 }
3235
3236 if (j >= NVRAM_TIMEOUT_COUNT)
3237 return -EBUSY;
3238
3239 return 0;
3240}
3241
3242
3243static int
3244bnx2_enable_nvram_write(struct bnx2 *bp)
3245{
3246 u32 val;
3247
3248 val = REG_RD(bp, BNX2_MISC_CFG);
3249 REG_WR(bp, BNX2_MISC_CFG, val | BNX2_MISC_CFG_NVM_WR_EN_PCI);
3250
Michael Chane30372c2007-07-16 18:26:23 -07003251 if (bp->flash_info->flags & BNX2_NV_WREN) {
Michael Chanb6016b72005-05-26 13:03:09 -07003252 int j;
3253
3254 REG_WR(bp, BNX2_NVM_COMMAND, BNX2_NVM_COMMAND_DONE);
3255 REG_WR(bp, BNX2_NVM_COMMAND,
3256 BNX2_NVM_COMMAND_WREN | BNX2_NVM_COMMAND_DOIT);
3257
3258 for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) {
3259 udelay(5);
3260
3261 val = REG_RD(bp, BNX2_NVM_COMMAND);
3262 if (val & BNX2_NVM_COMMAND_DONE)
3263 break;
3264 }
3265
3266 if (j >= NVRAM_TIMEOUT_COUNT)
3267 return -EBUSY;
3268 }
3269 return 0;
3270}
3271
3272static void
3273bnx2_disable_nvram_write(struct bnx2 *bp)
3274{
3275 u32 val;
3276
3277 val = REG_RD(bp, BNX2_MISC_CFG);
3278 REG_WR(bp, BNX2_MISC_CFG, val & ~BNX2_MISC_CFG_NVM_WR_EN);
3279}
3280
3281
3282static void
3283bnx2_enable_nvram_access(struct bnx2 *bp)
3284{
3285 u32 val;
3286
3287 val = REG_RD(bp, BNX2_NVM_ACCESS_ENABLE);
3288 /* Enable both bits, even on read. */
Jeff Garzik6aa20a22006-09-13 13:24:59 -04003289 REG_WR(bp, BNX2_NVM_ACCESS_ENABLE,
Michael Chanb6016b72005-05-26 13:03:09 -07003290 val | BNX2_NVM_ACCESS_ENABLE_EN | BNX2_NVM_ACCESS_ENABLE_WR_EN);
3291}
3292
3293static void
3294bnx2_disable_nvram_access(struct bnx2 *bp)
3295{
3296 u32 val;
3297
3298 val = REG_RD(bp, BNX2_NVM_ACCESS_ENABLE);
3299 /* Disable both bits, even after read. */
Jeff Garzik6aa20a22006-09-13 13:24:59 -04003300 REG_WR(bp, BNX2_NVM_ACCESS_ENABLE,
Michael Chanb6016b72005-05-26 13:03:09 -07003301 val & ~(BNX2_NVM_ACCESS_ENABLE_EN |
3302 BNX2_NVM_ACCESS_ENABLE_WR_EN));
3303}
3304
3305static int
3306bnx2_nvram_erase_page(struct bnx2 *bp, u32 offset)
3307{
3308 u32 cmd;
3309 int j;
3310
Michael Chane30372c2007-07-16 18:26:23 -07003311 if (bp->flash_info->flags & BNX2_NV_BUFFERED)
Michael Chanb6016b72005-05-26 13:03:09 -07003312 /* Buffered flash, no erase needed */
3313 return 0;
3314
3315 /* Build an erase command */
3316 cmd = BNX2_NVM_COMMAND_ERASE | BNX2_NVM_COMMAND_WR |
3317 BNX2_NVM_COMMAND_DOIT;
3318
3319 /* Need to clear DONE bit separately. */
3320 REG_WR(bp, BNX2_NVM_COMMAND, BNX2_NVM_COMMAND_DONE);
3321
3322 /* Address of the NVRAM to read from. */
3323 REG_WR(bp, BNX2_NVM_ADDR, offset & BNX2_NVM_ADDR_NVM_ADDR_VALUE);
3324
3325 /* Issue an erase command. */
3326 REG_WR(bp, BNX2_NVM_COMMAND, cmd);
3327
3328 /* Wait for completion. */
3329 for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) {
3330 u32 val;
3331
3332 udelay(5);
3333
3334 val = REG_RD(bp, BNX2_NVM_COMMAND);
3335 if (val & BNX2_NVM_COMMAND_DONE)
3336 break;
3337 }
3338
3339 if (j >= NVRAM_TIMEOUT_COUNT)
3340 return -EBUSY;
3341
3342 return 0;
3343}
3344
3345static int
3346bnx2_nvram_read_dword(struct bnx2 *bp, u32 offset, u8 *ret_val, u32 cmd_flags)
3347{
3348 u32 cmd;
3349 int j;
3350
3351 /* Build the command word. */
3352 cmd = BNX2_NVM_COMMAND_DOIT | cmd_flags;
3353
Michael Chane30372c2007-07-16 18:26:23 -07003354 /* Calculate an offset of a buffered flash, not needed for 5709. */
3355 if (bp->flash_info->flags & BNX2_NV_TRANSLATE) {
Michael Chanb6016b72005-05-26 13:03:09 -07003356 offset = ((offset / bp->flash_info->page_size) <<
3357 bp->flash_info->page_bits) +
3358 (offset % bp->flash_info->page_size);
3359 }
3360
3361 /* Need to clear DONE bit separately. */
3362 REG_WR(bp, BNX2_NVM_COMMAND, BNX2_NVM_COMMAND_DONE);
3363
3364 /* Address of the NVRAM to read from. */
3365 REG_WR(bp, BNX2_NVM_ADDR, offset & BNX2_NVM_ADDR_NVM_ADDR_VALUE);
3366
3367 /* Issue a read command. */
3368 REG_WR(bp, BNX2_NVM_COMMAND, cmd);
3369
3370 /* Wait for completion. */
3371 for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) {
3372 u32 val;
3373
3374 udelay(5);
3375
3376 val = REG_RD(bp, BNX2_NVM_COMMAND);
3377 if (val & BNX2_NVM_COMMAND_DONE) {
3378 val = REG_RD(bp, BNX2_NVM_READ);
3379
3380 val = be32_to_cpu(val);
3381 memcpy(ret_val, &val, 4);
3382 break;
3383 }
3384 }
3385 if (j >= NVRAM_TIMEOUT_COUNT)
3386 return -EBUSY;
3387
3388 return 0;
3389}
3390
3391
3392static int
3393bnx2_nvram_write_dword(struct bnx2 *bp, u32 offset, u8 *val, u32 cmd_flags)
3394{
3395 u32 cmd, val32;
3396 int j;
3397
3398 /* Build the command word. */
3399 cmd = BNX2_NVM_COMMAND_DOIT | BNX2_NVM_COMMAND_WR | cmd_flags;
3400
Michael Chane30372c2007-07-16 18:26:23 -07003401 /* Calculate an offset of a buffered flash, not needed for 5709. */
3402 if (bp->flash_info->flags & BNX2_NV_TRANSLATE) {
Michael Chanb6016b72005-05-26 13:03:09 -07003403 offset = ((offset / bp->flash_info->page_size) <<
3404 bp->flash_info->page_bits) +
3405 (offset % bp->flash_info->page_size);
3406 }
3407
3408 /* Need to clear DONE bit separately. */
3409 REG_WR(bp, BNX2_NVM_COMMAND, BNX2_NVM_COMMAND_DONE);
3410
3411 memcpy(&val32, val, 4);
3412 val32 = cpu_to_be32(val32);
3413
3414 /* Write the data. */
3415 REG_WR(bp, BNX2_NVM_WRITE, val32);
3416
3417 /* Address of the NVRAM to write to. */
3418 REG_WR(bp, BNX2_NVM_ADDR, offset & BNX2_NVM_ADDR_NVM_ADDR_VALUE);
3419
3420 /* Issue the write command. */
3421 REG_WR(bp, BNX2_NVM_COMMAND, cmd);
3422
3423 /* Wait for completion. */
3424 for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) {
3425 udelay(5);
3426
3427 if (REG_RD(bp, BNX2_NVM_COMMAND) & BNX2_NVM_COMMAND_DONE)
3428 break;
3429 }
3430 if (j >= NVRAM_TIMEOUT_COUNT)
3431 return -EBUSY;
3432
3433 return 0;
3434}
3435
3436static int
3437bnx2_init_nvram(struct bnx2 *bp)
3438{
3439 u32 val;
Michael Chane30372c2007-07-16 18:26:23 -07003440 int j, entry_count, rc = 0;
Michael Chanb6016b72005-05-26 13:03:09 -07003441 struct flash_spec *flash;
3442
Michael Chane30372c2007-07-16 18:26:23 -07003443 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
3444 bp->flash_info = &flash_5709;
3445 goto get_flash_size;
3446 }
3447
Michael Chanb6016b72005-05-26 13:03:09 -07003448 /* Determine the selected interface. */
3449 val = REG_RD(bp, BNX2_NVM_CFG1);
3450
Denis Chengff8ac602007-09-02 18:30:18 +08003451 entry_count = ARRAY_SIZE(flash_table);
Michael Chanb6016b72005-05-26 13:03:09 -07003452
Michael Chanb6016b72005-05-26 13:03:09 -07003453 if (val & 0x40000000) {
3454
3455 /* Flash interface has been reconfigured */
3456 for (j = 0, flash = &flash_table[0]; j < entry_count;
Michael Chan37137702005-11-04 08:49:17 -08003457 j++, flash++) {
3458 if ((val & FLASH_BACKUP_STRAP_MASK) ==
3459 (flash->config1 & FLASH_BACKUP_STRAP_MASK)) {
Michael Chanb6016b72005-05-26 13:03:09 -07003460 bp->flash_info = flash;
3461 break;
3462 }
3463 }
3464 }
3465 else {
Michael Chan37137702005-11-04 08:49:17 -08003466 u32 mask;
Michael Chanb6016b72005-05-26 13:03:09 -07003467 /* Not yet been reconfigured */
3468
Michael Chan37137702005-11-04 08:49:17 -08003469 if (val & (1 << 23))
3470 mask = FLASH_BACKUP_STRAP_MASK;
3471 else
3472 mask = FLASH_STRAP_MASK;
3473
Michael Chanb6016b72005-05-26 13:03:09 -07003474 for (j = 0, flash = &flash_table[0]; j < entry_count;
3475 j++, flash++) {
3476
Michael Chan37137702005-11-04 08:49:17 -08003477 if ((val & mask) == (flash->strapping & mask)) {
Michael Chanb6016b72005-05-26 13:03:09 -07003478 bp->flash_info = flash;
3479
3480 /* Request access to the flash interface. */
3481 if ((rc = bnx2_acquire_nvram_lock(bp)) != 0)
3482 return rc;
3483
3484 /* Enable access to flash interface */
3485 bnx2_enable_nvram_access(bp);
3486
3487 /* Reconfigure the flash interface */
3488 REG_WR(bp, BNX2_NVM_CFG1, flash->config1);
3489 REG_WR(bp, BNX2_NVM_CFG2, flash->config2);
3490 REG_WR(bp, BNX2_NVM_CFG3, flash->config3);
3491 REG_WR(bp, BNX2_NVM_WRITE1, flash->write1);
3492
3493 /* Disable access to flash interface */
3494 bnx2_disable_nvram_access(bp);
3495 bnx2_release_nvram_lock(bp);
3496
3497 break;
3498 }
3499 }
3500 } /* if (val & 0x40000000) */
3501
3502 if (j == entry_count) {
3503 bp->flash_info = NULL;
John W. Linville2f23c522005-11-10 12:57:33 -08003504 printk(KERN_ALERT PFX "Unknown flash/EEPROM type.\n");
Michael Chan1122db72006-01-23 16:11:42 -08003505 return -ENODEV;
Michael Chanb6016b72005-05-26 13:03:09 -07003506 }
3507
Michael Chane30372c2007-07-16 18:26:23 -07003508get_flash_size:
Michael Chan1122db72006-01-23 16:11:42 -08003509 val = REG_RD_IND(bp, bp->shmem_base + BNX2_SHARED_HW_CFG_CONFIG2);
3510 val &= BNX2_SHARED_HW_CFG2_NVM_SIZE_MASK;
3511 if (val)
3512 bp->flash_size = val;
3513 else
3514 bp->flash_size = bp->flash_info->total_size;
3515
Michael Chanb6016b72005-05-26 13:03:09 -07003516 return rc;
3517}
3518
3519static int
3520bnx2_nvram_read(struct bnx2 *bp, u32 offset, u8 *ret_buf,
3521 int buf_size)
3522{
3523 int rc = 0;
3524 u32 cmd_flags, offset32, len32, extra;
3525
3526 if (buf_size == 0)
3527 return 0;
3528
3529 /* Request access to the flash interface. */
3530 if ((rc = bnx2_acquire_nvram_lock(bp)) != 0)
3531 return rc;
3532
3533 /* Enable access to flash interface */
3534 bnx2_enable_nvram_access(bp);
3535
3536 len32 = buf_size;
3537 offset32 = offset;
3538 extra = 0;
3539
3540 cmd_flags = 0;
3541
3542 if (offset32 & 3) {
3543 u8 buf[4];
3544 u32 pre_len;
3545
3546 offset32 &= ~3;
3547 pre_len = 4 - (offset & 3);
3548
3549 if (pre_len >= len32) {
3550 pre_len = len32;
3551 cmd_flags = BNX2_NVM_COMMAND_FIRST |
3552 BNX2_NVM_COMMAND_LAST;
3553 }
3554 else {
3555 cmd_flags = BNX2_NVM_COMMAND_FIRST;
3556 }
3557
3558 rc = bnx2_nvram_read_dword(bp, offset32, buf, cmd_flags);
3559
3560 if (rc)
3561 return rc;
3562
3563 memcpy(ret_buf, buf + (offset & 3), pre_len);
3564
3565 offset32 += 4;
3566 ret_buf += pre_len;
3567 len32 -= pre_len;
3568 }
3569 if (len32 & 3) {
3570 extra = 4 - (len32 & 3);
3571 len32 = (len32 + 4) & ~3;
3572 }
3573
3574 if (len32 == 4) {
3575 u8 buf[4];
3576
3577 if (cmd_flags)
3578 cmd_flags = BNX2_NVM_COMMAND_LAST;
3579 else
3580 cmd_flags = BNX2_NVM_COMMAND_FIRST |
3581 BNX2_NVM_COMMAND_LAST;
3582
3583 rc = bnx2_nvram_read_dword(bp, offset32, buf, cmd_flags);
3584
3585 memcpy(ret_buf, buf, 4 - extra);
3586 }
3587 else if (len32 > 0) {
3588 u8 buf[4];
3589
3590 /* Read the first word. */
3591 if (cmd_flags)
3592 cmd_flags = 0;
3593 else
3594 cmd_flags = BNX2_NVM_COMMAND_FIRST;
3595
3596 rc = bnx2_nvram_read_dword(bp, offset32, ret_buf, cmd_flags);
3597
3598 /* Advance to the next dword. */
3599 offset32 += 4;
3600 ret_buf += 4;
3601 len32 -= 4;
3602
3603 while (len32 > 4 && rc == 0) {
3604 rc = bnx2_nvram_read_dword(bp, offset32, ret_buf, 0);
3605
3606 /* Advance to the next dword. */
3607 offset32 += 4;
3608 ret_buf += 4;
3609 len32 -= 4;
3610 }
3611
3612 if (rc)
3613 return rc;
3614
3615 cmd_flags = BNX2_NVM_COMMAND_LAST;
3616 rc = bnx2_nvram_read_dword(bp, offset32, buf, cmd_flags);
3617
3618 memcpy(ret_buf, buf, 4 - extra);
3619 }
3620
3621 /* Disable access to flash interface */
3622 bnx2_disable_nvram_access(bp);
3623
3624 bnx2_release_nvram_lock(bp);
3625
3626 return rc;
3627}
3628
3629static int
3630bnx2_nvram_write(struct bnx2 *bp, u32 offset, u8 *data_buf,
3631 int buf_size)
3632{
3633 u32 written, offset32, len32;
Michael Chane6be7632007-01-08 19:56:13 -08003634 u8 *buf, start[4], end[4], *align_buf = NULL, *flash_buffer = NULL;
Michael Chanb6016b72005-05-26 13:03:09 -07003635 int rc = 0;
3636 int align_start, align_end;
3637
3638 buf = data_buf;
3639 offset32 = offset;
3640 len32 = buf_size;
3641 align_start = align_end = 0;
3642
3643 if ((align_start = (offset32 & 3))) {
3644 offset32 &= ~3;
Michael Chanc8738792007-03-30 14:53:06 -07003645 len32 += align_start;
3646 if (len32 < 4)
3647 len32 = 4;
Michael Chanb6016b72005-05-26 13:03:09 -07003648 if ((rc = bnx2_nvram_read(bp, offset32, start, 4)))
3649 return rc;
3650 }
3651
3652 if (len32 & 3) {
Michael Chanc8738792007-03-30 14:53:06 -07003653 align_end = 4 - (len32 & 3);
3654 len32 += align_end;
3655 if ((rc = bnx2_nvram_read(bp, offset32 + len32 - 4, end, 4)))
3656 return rc;
Michael Chanb6016b72005-05-26 13:03:09 -07003657 }
3658
3659 if (align_start || align_end) {
Michael Chane6be7632007-01-08 19:56:13 -08003660 align_buf = kmalloc(len32, GFP_KERNEL);
3661 if (align_buf == NULL)
Michael Chanb6016b72005-05-26 13:03:09 -07003662 return -ENOMEM;
3663 if (align_start) {
Michael Chane6be7632007-01-08 19:56:13 -08003664 memcpy(align_buf, start, 4);
Michael Chanb6016b72005-05-26 13:03:09 -07003665 }
3666 if (align_end) {
Michael Chane6be7632007-01-08 19:56:13 -08003667 memcpy(align_buf + len32 - 4, end, 4);
Michael Chanb6016b72005-05-26 13:03:09 -07003668 }
Michael Chane6be7632007-01-08 19:56:13 -08003669 memcpy(align_buf + align_start, data_buf, buf_size);
3670 buf = align_buf;
Michael Chanb6016b72005-05-26 13:03:09 -07003671 }
3672
Michael Chane30372c2007-07-16 18:26:23 -07003673 if (!(bp->flash_info->flags & BNX2_NV_BUFFERED)) {
Michael Chanae181bc2006-05-22 16:39:20 -07003674 flash_buffer = kmalloc(264, GFP_KERNEL);
3675 if (flash_buffer == NULL) {
3676 rc = -ENOMEM;
3677 goto nvram_write_end;
3678 }
3679 }
3680
Michael Chanb6016b72005-05-26 13:03:09 -07003681 written = 0;
3682 while ((written < len32) && (rc == 0)) {
3683 u32 page_start, page_end, data_start, data_end;
3684 u32 addr, cmd_flags;
3685 int i;
Michael Chanb6016b72005-05-26 13:03:09 -07003686
3687 /* Find the page_start addr */
3688 page_start = offset32 + written;
3689 page_start -= (page_start % bp->flash_info->page_size);
3690 /* Find the page_end addr */
3691 page_end = page_start + bp->flash_info->page_size;
3692 /* Find the data_start addr */
3693 data_start = (written == 0) ? offset32 : page_start;
3694 /* Find the data_end addr */
Jeff Garzik6aa20a22006-09-13 13:24:59 -04003695 data_end = (page_end > offset32 + len32) ?
Michael Chanb6016b72005-05-26 13:03:09 -07003696 (offset32 + len32) : page_end;
3697
3698 /* Request access to the flash interface. */
3699 if ((rc = bnx2_acquire_nvram_lock(bp)) != 0)
3700 goto nvram_write_end;
3701
3702 /* Enable access to flash interface */
3703 bnx2_enable_nvram_access(bp);
3704
3705 cmd_flags = BNX2_NVM_COMMAND_FIRST;
Michael Chane30372c2007-07-16 18:26:23 -07003706 if (!(bp->flash_info->flags & BNX2_NV_BUFFERED)) {
Michael Chanb6016b72005-05-26 13:03:09 -07003707 int j;
3708
3709 /* Read the whole page into the buffer
3710 * (non-buffer flash only) */
3711 for (j = 0; j < bp->flash_info->page_size; j += 4) {
3712 if (j == (bp->flash_info->page_size - 4)) {
3713 cmd_flags |= BNX2_NVM_COMMAND_LAST;
3714 }
3715 rc = bnx2_nvram_read_dword(bp,
Jeff Garzik6aa20a22006-09-13 13:24:59 -04003716 page_start + j,
3717 &flash_buffer[j],
Michael Chanb6016b72005-05-26 13:03:09 -07003718 cmd_flags);
3719
3720 if (rc)
3721 goto nvram_write_end;
3722
3723 cmd_flags = 0;
3724 }
3725 }
3726
3727 /* Enable writes to flash interface (unlock write-protect) */
3728 if ((rc = bnx2_enable_nvram_write(bp)) != 0)
3729 goto nvram_write_end;
3730
Michael Chanb6016b72005-05-26 13:03:09 -07003731 /* Loop to write back the buffer data from page_start to
3732 * data_start */
3733 i = 0;
Michael Chane30372c2007-07-16 18:26:23 -07003734 if (!(bp->flash_info->flags & BNX2_NV_BUFFERED)) {
Michael Chanc8738792007-03-30 14:53:06 -07003735 /* Erase the page */
3736 if ((rc = bnx2_nvram_erase_page(bp, page_start)) != 0)
3737 goto nvram_write_end;
3738
3739 /* Re-enable the write again for the actual write */
3740 bnx2_enable_nvram_write(bp);
3741
Michael Chanb6016b72005-05-26 13:03:09 -07003742 for (addr = page_start; addr < data_start;
3743 addr += 4, i += 4) {
Jeff Garzik6aa20a22006-09-13 13:24:59 -04003744
Michael Chanb6016b72005-05-26 13:03:09 -07003745 rc = bnx2_nvram_write_dword(bp, addr,
3746 &flash_buffer[i], cmd_flags);
3747
3748 if (rc != 0)
3749 goto nvram_write_end;
3750
3751 cmd_flags = 0;
3752 }
3753 }
3754
3755 /* Loop to write the new data from data_start to data_end */
Michael Chanbae25762006-05-22 16:38:38 -07003756 for (addr = data_start; addr < data_end; addr += 4, i += 4) {
Michael Chanb6016b72005-05-26 13:03:09 -07003757 if ((addr == page_end - 4) ||
Michael Chane30372c2007-07-16 18:26:23 -07003758 ((bp->flash_info->flags & BNX2_NV_BUFFERED) &&
Michael Chanb6016b72005-05-26 13:03:09 -07003759 (addr == data_end - 4))) {
3760
3761 cmd_flags |= BNX2_NVM_COMMAND_LAST;
3762 }
3763 rc = bnx2_nvram_write_dword(bp, addr, buf,
3764 cmd_flags);
3765
3766 if (rc != 0)
3767 goto nvram_write_end;
3768
3769 cmd_flags = 0;
3770 buf += 4;
3771 }
3772
3773 /* Loop to write back the buffer data from data_end
3774 * to page_end */
Michael Chane30372c2007-07-16 18:26:23 -07003775 if (!(bp->flash_info->flags & BNX2_NV_BUFFERED)) {
Michael Chanb6016b72005-05-26 13:03:09 -07003776 for (addr = data_end; addr < page_end;
3777 addr += 4, i += 4) {
Jeff Garzik6aa20a22006-09-13 13:24:59 -04003778
Michael Chanb6016b72005-05-26 13:03:09 -07003779 if (addr == page_end-4) {
3780 cmd_flags = BNX2_NVM_COMMAND_LAST;
3781 }
3782 rc = bnx2_nvram_write_dword(bp, addr,
3783 &flash_buffer[i], cmd_flags);
3784
3785 if (rc != 0)
3786 goto nvram_write_end;
3787
3788 cmd_flags = 0;
3789 }
3790 }
3791
3792 /* Disable writes to flash interface (lock write-protect) */
3793 bnx2_disable_nvram_write(bp);
3794
3795 /* Disable access to flash interface */
3796 bnx2_disable_nvram_access(bp);
3797 bnx2_release_nvram_lock(bp);
3798
3799 /* Increment written */
3800 written += data_end - data_start;
3801 }
3802
3803nvram_write_end:
Michael Chane6be7632007-01-08 19:56:13 -08003804 kfree(flash_buffer);
3805 kfree(align_buf);
Michael Chanb6016b72005-05-26 13:03:09 -07003806 return rc;
3807}
3808
Michael Chan0d8a6572007-07-07 22:49:43 -07003809static void
3810bnx2_init_remote_phy(struct bnx2 *bp)
3811{
3812 u32 val;
3813
3814 bp->phy_flags &= ~REMOTE_PHY_CAP_FLAG;
3815 if (!(bp->phy_flags & PHY_SERDES_FLAG))
3816 return;
3817
3818 val = REG_RD_IND(bp, bp->shmem_base + BNX2_FW_CAP_MB);
3819 if ((val & BNX2_FW_CAP_SIGNATURE_MASK) != BNX2_FW_CAP_SIGNATURE)
3820 return;
3821
3822 if (val & BNX2_FW_CAP_REMOTE_PHY_CAPABLE) {
3823 if (netif_running(bp->dev)) {
3824 val = BNX2_DRV_ACK_CAP_SIGNATURE |
3825 BNX2_FW_CAP_REMOTE_PHY_CAPABLE;
3826 REG_WR_IND(bp, bp->shmem_base + BNX2_DRV_ACK_CAP_MB,
3827 val);
3828 }
3829 bp->phy_flags |= REMOTE_PHY_CAP_FLAG;
3830
3831 val = REG_RD_IND(bp, bp->shmem_base + BNX2_LINK_STATUS);
3832 if (val & BNX2_LINK_STATUS_SERDES_LINK)
3833 bp->phy_port = PORT_FIBRE;
3834 else
3835 bp->phy_port = PORT_TP;
3836 }
3837}
3838
Michael Chanb6016b72005-05-26 13:03:09 -07003839static int
3840bnx2_reset_chip(struct bnx2 *bp, u32 reset_code)
3841{
3842 u32 val;
3843 int i, rc = 0;
3844
3845 /* Wait for the current PCI transaction to complete before
3846 * issuing a reset. */
3847 REG_WR(bp, BNX2_MISC_ENABLE_CLR_BITS,
3848 BNX2_MISC_ENABLE_CLR_BITS_TX_DMA_ENABLE |
3849 BNX2_MISC_ENABLE_CLR_BITS_DMA_ENGINE_ENABLE |
3850 BNX2_MISC_ENABLE_CLR_BITS_RX_DMA_ENABLE |
3851 BNX2_MISC_ENABLE_CLR_BITS_HOST_COALESCE_ENABLE);
3852 val = REG_RD(bp, BNX2_MISC_ENABLE_CLR_BITS);
3853 udelay(5);
3854
Michael Chanb090ae22006-01-23 16:07:10 -08003855 /* Wait for the firmware to tell us it is ok to issue a reset. */
3856 bnx2_fw_sync(bp, BNX2_DRV_MSG_DATA_WAIT0 | reset_code, 1);
3857
Michael Chanb6016b72005-05-26 13:03:09 -07003858 /* Deposit a driver reset signature so the firmware knows that
3859 * this is a soft reset. */
Michael Chane3648b32005-11-04 08:51:21 -08003860 REG_WR_IND(bp, bp->shmem_base + BNX2_DRV_RESET_SIGNATURE,
Michael Chanb6016b72005-05-26 13:03:09 -07003861 BNX2_DRV_RESET_SIGNATURE_MAGIC);
3862
Michael Chanb6016b72005-05-26 13:03:09 -07003863 /* Do a dummy read to force the chip to complete all current transaction
3864 * before we issue a reset. */
3865 val = REG_RD(bp, BNX2_MISC_ID);
3866
Michael Chan234754d2006-11-19 14:11:41 -08003867 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
3868 REG_WR(bp, BNX2_MISC_COMMAND, BNX2_MISC_COMMAND_SW_RESET);
3869 REG_RD(bp, BNX2_MISC_COMMAND);
3870 udelay(5);
Michael Chanb6016b72005-05-26 13:03:09 -07003871
Michael Chan234754d2006-11-19 14:11:41 -08003872 val = BNX2_PCICFG_MISC_CONFIG_REG_WINDOW_ENA |
3873 BNX2_PCICFG_MISC_CONFIG_TARGET_MB_WORD_SWAP;
Michael Chanb6016b72005-05-26 13:03:09 -07003874
Michael Chan234754d2006-11-19 14:11:41 -08003875 pci_write_config_dword(bp->pdev, BNX2_PCICFG_MISC_CONFIG, val);
Michael Chanb6016b72005-05-26 13:03:09 -07003876
Michael Chan234754d2006-11-19 14:11:41 -08003877 } else {
3878 val = BNX2_PCICFG_MISC_CONFIG_CORE_RST_REQ |
3879 BNX2_PCICFG_MISC_CONFIG_REG_WINDOW_ENA |
3880 BNX2_PCICFG_MISC_CONFIG_TARGET_MB_WORD_SWAP;
3881
3882 /* Chip reset. */
3883 REG_WR(bp, BNX2_PCICFG_MISC_CONFIG, val);
3884
Michael Chan594a9df2007-08-28 15:39:42 -07003885 /* Reading back any register after chip reset will hang the
3886 * bus on 5706 A0 and A1. The msleep below provides plenty
3887 * of margin for write posting.
3888 */
Michael Chan234754d2006-11-19 14:11:41 -08003889 if ((CHIP_ID(bp) == CHIP_ID_5706_A0) ||
Arjan van de Ven8e545882007-08-28 14:34:43 -07003890 (CHIP_ID(bp) == CHIP_ID_5706_A1))
3891 msleep(20);
Michael Chanb6016b72005-05-26 13:03:09 -07003892
Michael Chan234754d2006-11-19 14:11:41 -08003893 /* Reset takes approximate 30 usec */
3894 for (i = 0; i < 10; i++) {
3895 val = REG_RD(bp, BNX2_PCICFG_MISC_CONFIG);
3896 if ((val & (BNX2_PCICFG_MISC_CONFIG_CORE_RST_REQ |
3897 BNX2_PCICFG_MISC_CONFIG_CORE_RST_BSY)) == 0)
3898 break;
3899 udelay(10);
3900 }
3901
3902 if (val & (BNX2_PCICFG_MISC_CONFIG_CORE_RST_REQ |
3903 BNX2_PCICFG_MISC_CONFIG_CORE_RST_BSY)) {
3904 printk(KERN_ERR PFX "Chip reset did not complete\n");
3905 return -EBUSY;
3906 }
Michael Chanb6016b72005-05-26 13:03:09 -07003907 }
3908
3909 /* Make sure byte swapping is properly configured. */
3910 val = REG_RD(bp, BNX2_PCI_SWAP_DIAG0);
3911 if (val != 0x01020304) {
3912 printk(KERN_ERR PFX "Chip not in correct endian mode\n");
3913 return -ENODEV;
3914 }
3915
Michael Chanb6016b72005-05-26 13:03:09 -07003916 /* Wait for the firmware to finish its initialization. */
Michael Chanb090ae22006-01-23 16:07:10 -08003917 rc = bnx2_fw_sync(bp, BNX2_DRV_MSG_DATA_WAIT1 | reset_code, 0);
3918 if (rc)
3919 return rc;
Michael Chanb6016b72005-05-26 13:03:09 -07003920
Michael Chan0d8a6572007-07-07 22:49:43 -07003921 spin_lock_bh(&bp->phy_lock);
3922 bnx2_init_remote_phy(bp);
3923 if (bp->phy_flags & REMOTE_PHY_CAP_FLAG)
3924 bnx2_set_default_remote_link(bp);
3925 spin_unlock_bh(&bp->phy_lock);
3926
Michael Chanb6016b72005-05-26 13:03:09 -07003927 if (CHIP_ID(bp) == CHIP_ID_5706_A0) {
3928 /* Adjust the voltage regular to two steps lower. The default
3929 * of this register is 0x0000000e. */
3930 REG_WR(bp, BNX2_MISC_VREG_CONTROL, 0x000000fa);
3931
3932 /* Remove bad rbuf memory from the free pool. */
3933 rc = bnx2_alloc_bad_rbuf(bp);
3934 }
3935
3936 return rc;
3937}
3938
3939static int
3940bnx2_init_chip(struct bnx2 *bp)
3941{
3942 u32 val;
Michael Chanb090ae22006-01-23 16:07:10 -08003943 int rc;
Michael Chanb6016b72005-05-26 13:03:09 -07003944
3945 /* Make sure the interrupt is not active. */
3946 REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD, BNX2_PCICFG_INT_ACK_CMD_MASK_INT);
3947
3948 val = BNX2_DMA_CONFIG_DATA_BYTE_SWAP |
3949 BNX2_DMA_CONFIG_DATA_WORD_SWAP |
3950#ifdef __BIG_ENDIAN
Jeff Garzik6aa20a22006-09-13 13:24:59 -04003951 BNX2_DMA_CONFIG_CNTL_BYTE_SWAP |
Michael Chanb6016b72005-05-26 13:03:09 -07003952#endif
Jeff Garzik6aa20a22006-09-13 13:24:59 -04003953 BNX2_DMA_CONFIG_CNTL_WORD_SWAP |
Michael Chanb6016b72005-05-26 13:03:09 -07003954 DMA_READ_CHANS << 12 |
3955 DMA_WRITE_CHANS << 16;
3956
3957 val |= (0x2 << 20) | (1 << 11);
3958
Michael Chandda1e392006-01-23 16:08:14 -08003959 if ((bp->flags & PCIX_FLAG) && (bp->bus_speed_mhz == 133))
Michael Chanb6016b72005-05-26 13:03:09 -07003960 val |= (1 << 23);
3961
3962 if ((CHIP_NUM(bp) == CHIP_NUM_5706) &&
3963 (CHIP_ID(bp) != CHIP_ID_5706_A0) && !(bp->flags & PCIX_FLAG))
3964 val |= BNX2_DMA_CONFIG_CNTL_PING_PONG_DMA;
3965
3966 REG_WR(bp, BNX2_DMA_CONFIG, val);
3967
3968 if (CHIP_ID(bp) == CHIP_ID_5706_A0) {
3969 val = REG_RD(bp, BNX2_TDMA_CONFIG);
3970 val |= BNX2_TDMA_CONFIG_ONE_DMA;
3971 REG_WR(bp, BNX2_TDMA_CONFIG, val);
3972 }
3973
3974 if (bp->flags & PCIX_FLAG) {
3975 u16 val16;
3976
3977 pci_read_config_word(bp->pdev, bp->pcix_cap + PCI_X_CMD,
3978 &val16);
3979 pci_write_config_word(bp->pdev, bp->pcix_cap + PCI_X_CMD,
3980 val16 & ~PCI_X_CMD_ERO);
3981 }
3982
3983 REG_WR(bp, BNX2_MISC_ENABLE_SET_BITS,
3984 BNX2_MISC_ENABLE_SET_BITS_HOST_COALESCE_ENABLE |
3985 BNX2_MISC_ENABLE_STATUS_BITS_RX_V2P_ENABLE |
3986 BNX2_MISC_ENABLE_STATUS_BITS_CONTEXT_ENABLE);
3987
3988 /* Initialize context mapping and zero out the quick contexts. The
3989 * context block must have already been enabled. */
Michael Chan641bdcd2007-06-04 21:22:24 -07003990 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
3991 rc = bnx2_init_5709_context(bp);
3992 if (rc)
3993 return rc;
3994 } else
Michael Chan59b47d82006-11-19 14:10:45 -08003995 bnx2_init_context(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07003996
Michael Chanfba9fe92006-06-12 22:21:25 -07003997 if ((rc = bnx2_init_cpus(bp)) != 0)
3998 return rc;
3999
Michael Chanb6016b72005-05-26 13:03:09 -07004000 bnx2_init_nvram(bp);
4001
4002 bnx2_set_mac_addr(bp);
4003
4004 val = REG_RD(bp, BNX2_MQ_CONFIG);
4005 val &= ~BNX2_MQ_CONFIG_KNL_BYP_BLK_SIZE;
4006 val |= BNX2_MQ_CONFIG_KNL_BYP_BLK_SIZE_256;
Michael Chan68c9f752007-04-24 15:35:53 -07004007 if (CHIP_ID(bp) == CHIP_ID_5709_A0 || CHIP_ID(bp) == CHIP_ID_5709_A1)
4008 val |= BNX2_MQ_CONFIG_HALT_DIS;
4009
Michael Chanb6016b72005-05-26 13:03:09 -07004010 REG_WR(bp, BNX2_MQ_CONFIG, val);
4011
4012 val = 0x10000 + (MAX_CID_CNT * MB_KERNEL_CTX_SIZE);
4013 REG_WR(bp, BNX2_MQ_KNL_BYP_WIND_START, val);
4014 REG_WR(bp, BNX2_MQ_KNL_WIND_END, val);
4015
4016 val = (BCM_PAGE_BITS - 8) << 24;
4017 REG_WR(bp, BNX2_RV2P_CONFIG, val);
4018
4019 /* Configure page size. */
4020 val = REG_RD(bp, BNX2_TBDR_CONFIG);
4021 val &= ~BNX2_TBDR_CONFIG_PAGE_SIZE;
4022 val |= (BCM_PAGE_BITS - 8) << 24 | 0x40;
4023 REG_WR(bp, BNX2_TBDR_CONFIG, val);
4024
4025 val = bp->mac_addr[0] +
4026 (bp->mac_addr[1] << 8) +
4027 (bp->mac_addr[2] << 16) +
4028 bp->mac_addr[3] +
4029 (bp->mac_addr[4] << 8) +
4030 (bp->mac_addr[5] << 16);
4031 REG_WR(bp, BNX2_EMAC_BACKOFF_SEED, val);
4032
4033 /* Program the MTU. Also include 4 bytes for CRC32. */
4034 val = bp->dev->mtu + ETH_HLEN + 4;
4035 if (val > (MAX_ETHERNET_PACKET_SIZE + 4))
4036 val |= BNX2_EMAC_RX_MTU_SIZE_JUMBO_ENA;
4037 REG_WR(bp, BNX2_EMAC_RX_MTU_SIZE, val);
4038
4039 bp->last_status_idx = 0;
4040 bp->rx_mode = BNX2_EMAC_RX_MODE_SORT_MODE;
4041
4042 /* Set up how to generate a link change interrupt. */
4043 REG_WR(bp, BNX2_EMAC_ATTENTION_ENA, BNX2_EMAC_ATTENTION_ENA_LINK);
4044
4045 REG_WR(bp, BNX2_HC_STATUS_ADDR_L,
4046 (u64) bp->status_blk_mapping & 0xffffffff);
4047 REG_WR(bp, BNX2_HC_STATUS_ADDR_H, (u64) bp->status_blk_mapping >> 32);
4048
4049 REG_WR(bp, BNX2_HC_STATISTICS_ADDR_L,
4050 (u64) bp->stats_blk_mapping & 0xffffffff);
4051 REG_WR(bp, BNX2_HC_STATISTICS_ADDR_H,
4052 (u64) bp->stats_blk_mapping >> 32);
4053
Jeff Garzik6aa20a22006-09-13 13:24:59 -04004054 REG_WR(bp, BNX2_HC_TX_QUICK_CONS_TRIP,
Michael Chanb6016b72005-05-26 13:03:09 -07004055 (bp->tx_quick_cons_trip_int << 16) | bp->tx_quick_cons_trip);
4056
4057 REG_WR(bp, BNX2_HC_RX_QUICK_CONS_TRIP,
4058 (bp->rx_quick_cons_trip_int << 16) | bp->rx_quick_cons_trip);
4059
4060 REG_WR(bp, BNX2_HC_COMP_PROD_TRIP,
4061 (bp->comp_prod_trip_int << 16) | bp->comp_prod_trip);
4062
4063 REG_WR(bp, BNX2_HC_TX_TICKS, (bp->tx_ticks_int << 16) | bp->tx_ticks);
4064
4065 REG_WR(bp, BNX2_HC_RX_TICKS, (bp->rx_ticks_int << 16) | bp->rx_ticks);
4066
4067 REG_WR(bp, BNX2_HC_COM_TICKS,
4068 (bp->com_ticks_int << 16) | bp->com_ticks);
4069
4070 REG_WR(bp, BNX2_HC_CMD_TICKS,
4071 (bp->cmd_ticks_int << 16) | bp->cmd_ticks);
4072
Michael Chan02537b062007-06-04 21:24:07 -07004073 if (CHIP_NUM(bp) == CHIP_NUM_5708)
4074 REG_WR(bp, BNX2_HC_STATS_TICKS, 0);
4075 else
Michael Chan7ea69202007-07-16 18:27:10 -07004076 REG_WR(bp, BNX2_HC_STATS_TICKS, bp->stats_ticks);
Michael Chanb6016b72005-05-26 13:03:09 -07004077 REG_WR(bp, BNX2_HC_STAT_COLLECT_TICKS, 0xbb8); /* 3ms */
4078
4079 if (CHIP_ID(bp) == CHIP_ID_5706_A1)
Michael Chan8e6a72c2007-05-03 13:24:48 -07004080 val = BNX2_HC_CONFIG_COLLECT_STATS;
Michael Chanb6016b72005-05-26 13:03:09 -07004081 else {
Michael Chan8e6a72c2007-05-03 13:24:48 -07004082 val = BNX2_HC_CONFIG_RX_TMR_MODE | BNX2_HC_CONFIG_TX_TMR_MODE |
4083 BNX2_HC_CONFIG_COLLECT_STATS;
Michael Chanb6016b72005-05-26 13:03:09 -07004084 }
4085
Michael Chan8e6a72c2007-05-03 13:24:48 -07004086 if (bp->flags & ONE_SHOT_MSI_FLAG)
4087 val |= BNX2_HC_CONFIG_ONE_SHOT;
4088
4089 REG_WR(bp, BNX2_HC_CONFIG, val);
4090
Michael Chanb6016b72005-05-26 13:03:09 -07004091 /* Clear internal stats counters. */
4092 REG_WR(bp, BNX2_HC_COMMAND, BNX2_HC_COMMAND_CLR_STAT_NOW);
4093
Michael Chanda3e4fb2007-05-03 13:24:23 -07004094 REG_WR(bp, BNX2_HC_ATTN_BITS_ENABLE, STATUS_ATTN_EVENTS);
Michael Chanb6016b72005-05-26 13:03:09 -07004095
4096 /* Initialize the receive filter. */
4097 bnx2_set_rx_mode(bp->dev);
4098
Michael Chan0aa38df2007-06-04 21:23:06 -07004099 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
4100 val = REG_RD(bp, BNX2_MISC_NEW_CORE_CTL);
4101 val |= BNX2_MISC_NEW_CORE_CTL_DMA_ENABLE;
4102 REG_WR(bp, BNX2_MISC_NEW_CORE_CTL, val);
4103 }
Michael Chanb090ae22006-01-23 16:07:10 -08004104 rc = bnx2_fw_sync(bp, BNX2_DRV_MSG_DATA_WAIT2 | BNX2_DRV_MSG_CODE_RESET,
4105 0);
Michael Chanb6016b72005-05-26 13:03:09 -07004106
Michael Chandf149d72007-07-07 22:51:36 -07004107 REG_WR(bp, BNX2_MISC_ENABLE_SET_BITS, BNX2_MISC_ENABLE_DEFAULT);
Michael Chanb6016b72005-05-26 13:03:09 -07004108 REG_RD(bp, BNX2_MISC_ENABLE_SET_BITS);
4109
4110 udelay(20);
4111
Michael Chanbf5295b2006-03-23 01:11:56 -08004112 bp->hc_cmd = REG_RD(bp, BNX2_HC_COMMAND);
4113
Michael Chanb090ae22006-01-23 16:07:10 -08004114 return rc;
Michael Chanb6016b72005-05-26 13:03:09 -07004115}
4116
Michael Chan59b47d82006-11-19 14:10:45 -08004117static void
4118bnx2_init_tx_context(struct bnx2 *bp, u32 cid)
4119{
4120 u32 val, offset0, offset1, offset2, offset3;
4121
4122 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
4123 offset0 = BNX2_L2CTX_TYPE_XI;
4124 offset1 = BNX2_L2CTX_CMD_TYPE_XI;
4125 offset2 = BNX2_L2CTX_TBDR_BHADDR_HI_XI;
4126 offset3 = BNX2_L2CTX_TBDR_BHADDR_LO_XI;
4127 } else {
4128 offset0 = BNX2_L2CTX_TYPE;
4129 offset1 = BNX2_L2CTX_CMD_TYPE;
4130 offset2 = BNX2_L2CTX_TBDR_BHADDR_HI;
4131 offset3 = BNX2_L2CTX_TBDR_BHADDR_LO;
4132 }
4133 val = BNX2_L2CTX_TYPE_TYPE_L2 | BNX2_L2CTX_TYPE_SIZE_L2;
4134 CTX_WR(bp, GET_CID_ADDR(cid), offset0, val);
4135
4136 val = BNX2_L2CTX_CMD_TYPE_TYPE_L2 | (8 << 16);
4137 CTX_WR(bp, GET_CID_ADDR(cid), offset1, val);
4138
4139 val = (u64) bp->tx_desc_mapping >> 32;
4140 CTX_WR(bp, GET_CID_ADDR(cid), offset2, val);
4141
4142 val = (u64) bp->tx_desc_mapping & 0xffffffff;
4143 CTX_WR(bp, GET_CID_ADDR(cid), offset3, val);
4144}
Michael Chanb6016b72005-05-26 13:03:09 -07004145
4146static void
4147bnx2_init_tx_ring(struct bnx2 *bp)
4148{
4149 struct tx_bd *txbd;
Michael Chan59b47d82006-11-19 14:10:45 -08004150 u32 cid;
Michael Chanb6016b72005-05-26 13:03:09 -07004151
Michael Chan2f8af122006-08-15 01:39:10 -07004152 bp->tx_wake_thresh = bp->tx_ring_size / 2;
4153
Michael Chanb6016b72005-05-26 13:03:09 -07004154 txbd = &bp->tx_desc_ring[MAX_TX_DESC_CNT];
Jeff Garzik6aa20a22006-09-13 13:24:59 -04004155
Michael Chanb6016b72005-05-26 13:03:09 -07004156 txbd->tx_bd_haddr_hi = (u64) bp->tx_desc_mapping >> 32;
4157 txbd->tx_bd_haddr_lo = (u64) bp->tx_desc_mapping & 0xffffffff;
4158
4159 bp->tx_prod = 0;
4160 bp->tx_cons = 0;
Michael Chanf4e418f2005-11-04 08:53:48 -08004161 bp->hw_tx_cons = 0;
Michael Chanb6016b72005-05-26 13:03:09 -07004162 bp->tx_prod_bseq = 0;
Jeff Garzik6aa20a22006-09-13 13:24:59 -04004163
Michael Chan59b47d82006-11-19 14:10:45 -08004164 cid = TX_CID;
4165 bp->tx_bidx_addr = MB_GET_CID_ADDR(cid) + BNX2_L2CTX_TX_HOST_BIDX;
4166 bp->tx_bseq_addr = MB_GET_CID_ADDR(cid) + BNX2_L2CTX_TX_HOST_BSEQ;
Michael Chanb6016b72005-05-26 13:03:09 -07004167
Michael Chan59b47d82006-11-19 14:10:45 -08004168 bnx2_init_tx_context(bp, cid);
Michael Chanb6016b72005-05-26 13:03:09 -07004169}
4170
4171static void
4172bnx2_init_rx_ring(struct bnx2 *bp)
4173{
4174 struct rx_bd *rxbd;
4175 int i;
Jeff Garzik6aa20a22006-09-13 13:24:59 -04004176 u16 prod, ring_prod;
Michael Chanb6016b72005-05-26 13:03:09 -07004177 u32 val;
4178
4179 /* 8 for CRC and VLAN */
4180 bp->rx_buf_use_size = bp->dev->mtu + ETH_HLEN + bp->rx_offset + 8;
Michael Chan59b47d82006-11-19 14:10:45 -08004181 /* hw alignment */
4182 bp->rx_buf_size = bp->rx_buf_use_size + BNX2_RX_ALIGN;
Michael Chanb6016b72005-05-26 13:03:09 -07004183
4184 ring_prod = prod = bp->rx_prod = 0;
4185 bp->rx_cons = 0;
Michael Chanf4e418f2005-11-04 08:53:48 -08004186 bp->hw_rx_cons = 0;
Michael Chanb6016b72005-05-26 13:03:09 -07004187 bp->rx_prod_bseq = 0;
Jeff Garzik6aa20a22006-09-13 13:24:59 -04004188
Michael Chan13daffa2006-03-20 17:49:20 -08004189 for (i = 0; i < bp->rx_max_ring; i++) {
4190 int j;
Michael Chanb6016b72005-05-26 13:03:09 -07004191
Michael Chan13daffa2006-03-20 17:49:20 -08004192 rxbd = &bp->rx_desc_ring[i][0];
4193 for (j = 0; j < MAX_RX_DESC_CNT; j++, rxbd++) {
4194 rxbd->rx_bd_len = bp->rx_buf_use_size;
4195 rxbd->rx_bd_flags = RX_BD_FLAGS_START | RX_BD_FLAGS_END;
4196 }
4197 if (i == (bp->rx_max_ring - 1))
4198 j = 0;
4199 else
4200 j = i + 1;
4201 rxbd->rx_bd_haddr_hi = (u64) bp->rx_desc_mapping[j] >> 32;
4202 rxbd->rx_bd_haddr_lo = (u64) bp->rx_desc_mapping[j] &
4203 0xffffffff;
4204 }
Michael Chanb6016b72005-05-26 13:03:09 -07004205
4206 val = BNX2_L2CTX_CTX_TYPE_CTX_BD_CHN_TYPE_VALUE;
4207 val |= BNX2_L2CTX_CTX_TYPE_SIZE_L2;
4208 val |= 0x02 << 8;
4209 CTX_WR(bp, GET_CID_ADDR(RX_CID), BNX2_L2CTX_CTX_TYPE, val);
4210
Michael Chan13daffa2006-03-20 17:49:20 -08004211 val = (u64) bp->rx_desc_mapping[0] >> 32;
Michael Chanb6016b72005-05-26 13:03:09 -07004212 CTX_WR(bp, GET_CID_ADDR(RX_CID), BNX2_L2CTX_NX_BDHADDR_HI, val);
4213
Michael Chan13daffa2006-03-20 17:49:20 -08004214 val = (u64) bp->rx_desc_mapping[0] & 0xffffffff;
Michael Chanb6016b72005-05-26 13:03:09 -07004215 CTX_WR(bp, GET_CID_ADDR(RX_CID), BNX2_L2CTX_NX_BDHADDR_LO, val);
4216
Michael Chan236b6392006-03-20 17:49:02 -08004217 for (i = 0; i < bp->rx_ring_size; i++) {
Michael Chanb6016b72005-05-26 13:03:09 -07004218 if (bnx2_alloc_rx_skb(bp, ring_prod) < 0) {
4219 break;
4220 }
4221 prod = NEXT_RX_BD(prod);
4222 ring_prod = RX_RING_IDX(prod);
4223 }
4224 bp->rx_prod = prod;
4225
4226 REG_WR16(bp, MB_RX_CID_ADDR + BNX2_L2CTX_HOST_BDIDX, prod);
4227
4228 REG_WR(bp, MB_RX_CID_ADDR + BNX2_L2CTX_HOST_BSEQ, bp->rx_prod_bseq);
4229}
4230
4231static void
Michael Chan13daffa2006-03-20 17:49:20 -08004232bnx2_set_rx_ring_size(struct bnx2 *bp, u32 size)
4233{
4234 u32 num_rings, max;
4235
4236 bp->rx_ring_size = size;
4237 num_rings = 1;
4238 while (size > MAX_RX_DESC_CNT) {
4239 size -= MAX_RX_DESC_CNT;
4240 num_rings++;
4241 }
4242 /* round to next power of 2 */
4243 max = MAX_RX_RINGS;
4244 while ((max & num_rings) == 0)
4245 max >>= 1;
4246
4247 if (num_rings != max)
4248 max <<= 1;
4249
4250 bp->rx_max_ring = max;
4251 bp->rx_max_ring_idx = (bp->rx_max_ring * RX_DESC_CNT) - 1;
4252}
4253
4254static void
Michael Chanb6016b72005-05-26 13:03:09 -07004255bnx2_free_tx_skbs(struct bnx2 *bp)
4256{
4257 int i;
4258
4259 if (bp->tx_buf_ring == NULL)
4260 return;
4261
4262 for (i = 0; i < TX_DESC_CNT; ) {
4263 struct sw_bd *tx_buf = &bp->tx_buf_ring[i];
4264 struct sk_buff *skb = tx_buf->skb;
4265 int j, last;
4266
4267 if (skb == NULL) {
4268 i++;
4269 continue;
4270 }
4271
4272 pci_unmap_single(bp->pdev, pci_unmap_addr(tx_buf, mapping),
4273 skb_headlen(skb), PCI_DMA_TODEVICE);
4274
4275 tx_buf->skb = NULL;
4276
4277 last = skb_shinfo(skb)->nr_frags;
4278 for (j = 0; j < last; j++) {
4279 tx_buf = &bp->tx_buf_ring[i + j + 1];
4280 pci_unmap_page(bp->pdev,
4281 pci_unmap_addr(tx_buf, mapping),
4282 skb_shinfo(skb)->frags[j].size,
4283 PCI_DMA_TODEVICE);
4284 }
Michael Chan745720e2006-06-29 12:37:41 -07004285 dev_kfree_skb(skb);
Michael Chanb6016b72005-05-26 13:03:09 -07004286 i += j + 1;
4287 }
4288
4289}
4290
4291static void
4292bnx2_free_rx_skbs(struct bnx2 *bp)
4293{
4294 int i;
4295
4296 if (bp->rx_buf_ring == NULL)
4297 return;
4298
Michael Chan13daffa2006-03-20 17:49:20 -08004299 for (i = 0; i < bp->rx_max_ring_idx; i++) {
Michael Chanb6016b72005-05-26 13:03:09 -07004300 struct sw_bd *rx_buf = &bp->rx_buf_ring[i];
4301 struct sk_buff *skb = rx_buf->skb;
4302
Michael Chan05d0f1c2005-11-04 08:53:48 -08004303 if (skb == NULL)
Michael Chanb6016b72005-05-26 13:03:09 -07004304 continue;
4305
4306 pci_unmap_single(bp->pdev, pci_unmap_addr(rx_buf, mapping),
4307 bp->rx_buf_use_size, PCI_DMA_FROMDEVICE);
4308
4309 rx_buf->skb = NULL;
4310
Michael Chan745720e2006-06-29 12:37:41 -07004311 dev_kfree_skb(skb);
Michael Chanb6016b72005-05-26 13:03:09 -07004312 }
4313}
4314
4315static void
4316bnx2_free_skbs(struct bnx2 *bp)
4317{
4318 bnx2_free_tx_skbs(bp);
4319 bnx2_free_rx_skbs(bp);
4320}
4321
4322static int
4323bnx2_reset_nic(struct bnx2 *bp, u32 reset_code)
4324{
4325 int rc;
4326
4327 rc = bnx2_reset_chip(bp, reset_code);
4328 bnx2_free_skbs(bp);
4329 if (rc)
4330 return rc;
4331
Michael Chanfba9fe92006-06-12 22:21:25 -07004332 if ((rc = bnx2_init_chip(bp)) != 0)
4333 return rc;
4334
Michael Chanb6016b72005-05-26 13:03:09 -07004335 bnx2_init_tx_ring(bp);
4336 bnx2_init_rx_ring(bp);
4337 return 0;
4338}
4339
4340static int
4341bnx2_init_nic(struct bnx2 *bp)
4342{
4343 int rc;
4344
4345 if ((rc = bnx2_reset_nic(bp, BNX2_DRV_MSG_CODE_RESET)) != 0)
4346 return rc;
4347
Michael Chan80be4432006-11-19 14:07:28 -08004348 spin_lock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07004349 bnx2_init_phy(bp);
4350 bnx2_set_link(bp);
Michael Chan0d8a6572007-07-07 22:49:43 -07004351 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07004352 return 0;
4353}
4354
4355static int
4356bnx2_test_registers(struct bnx2 *bp)
4357{
4358 int ret;
Michael Chan5bae30c2007-05-03 13:18:46 -07004359 int i, is_5709;
Arjan van de Venf71e1302006-03-03 21:33:57 -05004360 static const struct {
Michael Chanb6016b72005-05-26 13:03:09 -07004361 u16 offset;
4362 u16 flags;
Michael Chan5bae30c2007-05-03 13:18:46 -07004363#define BNX2_FL_NOT_5709 1
Michael Chanb6016b72005-05-26 13:03:09 -07004364 u32 rw_mask;
4365 u32 ro_mask;
4366 } reg_tbl[] = {
4367 { 0x006c, 0, 0x00000000, 0x0000003f },
4368 { 0x0090, 0, 0xffffffff, 0x00000000 },
4369 { 0x0094, 0, 0x00000000, 0x00000000 },
4370
Michael Chan5bae30c2007-05-03 13:18:46 -07004371 { 0x0404, BNX2_FL_NOT_5709, 0x00003f00, 0x00000000 },
4372 { 0x0418, BNX2_FL_NOT_5709, 0x00000000, 0xffffffff },
4373 { 0x041c, BNX2_FL_NOT_5709, 0x00000000, 0xffffffff },
4374 { 0x0420, BNX2_FL_NOT_5709, 0x00000000, 0x80ffffff },
4375 { 0x0424, BNX2_FL_NOT_5709, 0x00000000, 0x00000000 },
4376 { 0x0428, BNX2_FL_NOT_5709, 0x00000000, 0x00000001 },
4377 { 0x0450, BNX2_FL_NOT_5709, 0x00000000, 0x0000ffff },
4378 { 0x0454, BNX2_FL_NOT_5709, 0x00000000, 0xffffffff },
4379 { 0x0458, BNX2_FL_NOT_5709, 0x00000000, 0xffffffff },
Michael Chanb6016b72005-05-26 13:03:09 -07004380
Michael Chan5bae30c2007-05-03 13:18:46 -07004381 { 0x0808, BNX2_FL_NOT_5709, 0x00000000, 0xffffffff },
4382 { 0x0854, BNX2_FL_NOT_5709, 0x00000000, 0xffffffff },
4383 { 0x0868, BNX2_FL_NOT_5709, 0x00000000, 0x77777777 },
4384 { 0x086c, BNX2_FL_NOT_5709, 0x00000000, 0x77777777 },
4385 { 0x0870, BNX2_FL_NOT_5709, 0x00000000, 0x77777777 },
4386 { 0x0874, BNX2_FL_NOT_5709, 0x00000000, 0x77777777 },
Michael Chanb6016b72005-05-26 13:03:09 -07004387
Michael Chan5bae30c2007-05-03 13:18:46 -07004388 { 0x0c00, BNX2_FL_NOT_5709, 0x00000000, 0x00000001 },
4389 { 0x0c04, BNX2_FL_NOT_5709, 0x00000000, 0x03ff0001 },
4390 { 0x0c08, BNX2_FL_NOT_5709, 0x0f0ff073, 0x00000000 },
Michael Chanb6016b72005-05-26 13:03:09 -07004391
4392 { 0x1000, 0, 0x00000000, 0x00000001 },
4393 { 0x1004, 0, 0x00000000, 0x000f0001 },
Michael Chanb6016b72005-05-26 13:03:09 -07004394
4395 { 0x1408, 0, 0x01c00800, 0x00000000 },
4396 { 0x149c, 0, 0x8000ffff, 0x00000000 },
4397 { 0x14a8, 0, 0x00000000, 0x000001ff },
Michael Chan5b0c76a2005-11-04 08:45:49 -08004398 { 0x14ac, 0, 0x0fffffff, 0x10000000 },
Michael Chanb6016b72005-05-26 13:03:09 -07004399 { 0x14b0, 0, 0x00000002, 0x00000001 },
4400 { 0x14b8, 0, 0x00000000, 0x00000000 },
4401 { 0x14c0, 0, 0x00000000, 0x00000009 },
4402 { 0x14c4, 0, 0x00003fff, 0x00000000 },
4403 { 0x14cc, 0, 0x00000000, 0x00000001 },
4404 { 0x14d0, 0, 0xffffffff, 0x00000000 },
Michael Chanb6016b72005-05-26 13:03:09 -07004405
4406 { 0x1800, 0, 0x00000000, 0x00000001 },
4407 { 0x1804, 0, 0x00000000, 0x00000003 },
Michael Chanb6016b72005-05-26 13:03:09 -07004408
4409 { 0x2800, 0, 0x00000000, 0x00000001 },
4410 { 0x2804, 0, 0x00000000, 0x00003f01 },
4411 { 0x2808, 0, 0x0f3f3f03, 0x00000000 },
4412 { 0x2810, 0, 0xffff0000, 0x00000000 },
4413 { 0x2814, 0, 0xffff0000, 0x00000000 },
4414 { 0x2818, 0, 0xffff0000, 0x00000000 },
4415 { 0x281c, 0, 0xffff0000, 0x00000000 },
4416 { 0x2834, 0, 0xffffffff, 0x00000000 },
4417 { 0x2840, 0, 0x00000000, 0xffffffff },
4418 { 0x2844, 0, 0x00000000, 0xffffffff },
4419 { 0x2848, 0, 0xffffffff, 0x00000000 },
4420 { 0x284c, 0, 0xf800f800, 0x07ff07ff },
4421
4422 { 0x2c00, 0, 0x00000000, 0x00000011 },
4423 { 0x2c04, 0, 0x00000000, 0x00030007 },
4424
Michael Chanb6016b72005-05-26 13:03:09 -07004425 { 0x3c00, 0, 0x00000000, 0x00000001 },
4426 { 0x3c04, 0, 0x00000000, 0x00070000 },
4427 { 0x3c08, 0, 0x00007f71, 0x07f00000 },
4428 { 0x3c0c, 0, 0x1f3ffffc, 0x00000000 },
4429 { 0x3c10, 0, 0xffffffff, 0x00000000 },
4430 { 0x3c14, 0, 0x00000000, 0xffffffff },
4431 { 0x3c18, 0, 0x00000000, 0xffffffff },
4432 { 0x3c1c, 0, 0xfffff000, 0x00000000 },
4433 { 0x3c20, 0, 0xffffff00, 0x00000000 },
Michael Chanb6016b72005-05-26 13:03:09 -07004434
4435 { 0x5004, 0, 0x00000000, 0x0000007f },
4436 { 0x5008, 0, 0x0f0007ff, 0x00000000 },
Michael Chanb6016b72005-05-26 13:03:09 -07004437
Michael Chanb6016b72005-05-26 13:03:09 -07004438 { 0x5c00, 0, 0x00000000, 0x00000001 },
4439 { 0x5c04, 0, 0x00000000, 0x0003000f },
4440 { 0x5c08, 0, 0x00000003, 0x00000000 },
4441 { 0x5c0c, 0, 0x0000fff8, 0x00000000 },
4442 { 0x5c10, 0, 0x00000000, 0xffffffff },
4443 { 0x5c80, 0, 0x00000000, 0x0f7113f1 },
4444 { 0x5c84, 0, 0x00000000, 0x0000f333 },
4445 { 0x5c88, 0, 0x00000000, 0x00077373 },
4446 { 0x5c8c, 0, 0x00000000, 0x0007f737 },
4447
4448 { 0x6808, 0, 0x0000ff7f, 0x00000000 },
4449 { 0x680c, 0, 0xffffffff, 0x00000000 },
4450 { 0x6810, 0, 0xffffffff, 0x00000000 },
4451 { 0x6814, 0, 0xffffffff, 0x00000000 },
4452 { 0x6818, 0, 0xffffffff, 0x00000000 },
4453 { 0x681c, 0, 0xffffffff, 0x00000000 },
4454 { 0x6820, 0, 0x00ff00ff, 0x00000000 },
4455 { 0x6824, 0, 0x00ff00ff, 0x00000000 },
4456 { 0x6828, 0, 0x00ff00ff, 0x00000000 },
4457 { 0x682c, 0, 0x03ff03ff, 0x00000000 },
4458 { 0x6830, 0, 0x03ff03ff, 0x00000000 },
4459 { 0x6834, 0, 0x03ff03ff, 0x00000000 },
4460 { 0x6838, 0, 0x03ff03ff, 0x00000000 },
4461 { 0x683c, 0, 0x0000ffff, 0x00000000 },
4462 { 0x6840, 0, 0x00000ff0, 0x00000000 },
4463 { 0x6844, 0, 0x00ffff00, 0x00000000 },
4464 { 0x684c, 0, 0xffffffff, 0x00000000 },
4465 { 0x6850, 0, 0x7f7f7f7f, 0x00000000 },
4466 { 0x6854, 0, 0x7f7f7f7f, 0x00000000 },
4467 { 0x6858, 0, 0x7f7f7f7f, 0x00000000 },
4468 { 0x685c, 0, 0x7f7f7f7f, 0x00000000 },
4469 { 0x6908, 0, 0x00000000, 0x0001ff0f },
4470 { 0x690c, 0, 0x00000000, 0x0ffe00f0 },
4471
4472 { 0xffff, 0, 0x00000000, 0x00000000 },
4473 };
4474
4475 ret = 0;
Michael Chan5bae30c2007-05-03 13:18:46 -07004476 is_5709 = 0;
4477 if (CHIP_NUM(bp) == CHIP_NUM_5709)
4478 is_5709 = 1;
4479
Michael Chanb6016b72005-05-26 13:03:09 -07004480 for (i = 0; reg_tbl[i].offset != 0xffff; i++) {
4481 u32 offset, rw_mask, ro_mask, save_val, val;
Michael Chan5bae30c2007-05-03 13:18:46 -07004482 u16 flags = reg_tbl[i].flags;
4483
4484 if (is_5709 && (flags & BNX2_FL_NOT_5709))
4485 continue;
Michael Chanb6016b72005-05-26 13:03:09 -07004486
4487 offset = (u32) reg_tbl[i].offset;
4488 rw_mask = reg_tbl[i].rw_mask;
4489 ro_mask = reg_tbl[i].ro_mask;
4490
Peter Hagervall14ab9b82005-08-10 14:18:16 -07004491 save_val = readl(bp->regview + offset);
Michael Chanb6016b72005-05-26 13:03:09 -07004492
Peter Hagervall14ab9b82005-08-10 14:18:16 -07004493 writel(0, bp->regview + offset);
Michael Chanb6016b72005-05-26 13:03:09 -07004494
Peter Hagervall14ab9b82005-08-10 14:18:16 -07004495 val = readl(bp->regview + offset);
Michael Chanb6016b72005-05-26 13:03:09 -07004496 if ((val & rw_mask) != 0) {
4497 goto reg_test_err;
4498 }
4499
4500 if ((val & ro_mask) != (save_val & ro_mask)) {
4501 goto reg_test_err;
4502 }
4503
Peter Hagervall14ab9b82005-08-10 14:18:16 -07004504 writel(0xffffffff, bp->regview + offset);
Michael Chanb6016b72005-05-26 13:03:09 -07004505
Peter Hagervall14ab9b82005-08-10 14:18:16 -07004506 val = readl(bp->regview + offset);
Michael Chanb6016b72005-05-26 13:03:09 -07004507 if ((val & rw_mask) != rw_mask) {
4508 goto reg_test_err;
4509 }
4510
4511 if ((val & ro_mask) != (save_val & ro_mask)) {
4512 goto reg_test_err;
4513 }
4514
Peter Hagervall14ab9b82005-08-10 14:18:16 -07004515 writel(save_val, bp->regview + offset);
Michael Chanb6016b72005-05-26 13:03:09 -07004516 continue;
4517
4518reg_test_err:
Peter Hagervall14ab9b82005-08-10 14:18:16 -07004519 writel(save_val, bp->regview + offset);
Michael Chanb6016b72005-05-26 13:03:09 -07004520 ret = -ENODEV;
4521 break;
4522 }
4523 return ret;
4524}
4525
4526static int
4527bnx2_do_mem_test(struct bnx2 *bp, u32 start, u32 size)
4528{
Arjan van de Venf71e1302006-03-03 21:33:57 -05004529 static const u32 test_pattern[] = { 0x00000000, 0xffffffff, 0x55555555,
Michael Chanb6016b72005-05-26 13:03:09 -07004530 0xaaaaaaaa , 0xaa55aa55, 0x55aa55aa };
4531 int i;
4532
4533 for (i = 0; i < sizeof(test_pattern) / 4; i++) {
4534 u32 offset;
4535
4536 for (offset = 0; offset < size; offset += 4) {
4537
4538 REG_WR_IND(bp, start + offset, test_pattern[i]);
4539
4540 if (REG_RD_IND(bp, start + offset) !=
4541 test_pattern[i]) {
4542 return -ENODEV;
4543 }
4544 }
4545 }
4546 return 0;
4547}
4548
4549static int
4550bnx2_test_memory(struct bnx2 *bp)
4551{
4552 int ret = 0;
4553 int i;
Michael Chan5bae30c2007-05-03 13:18:46 -07004554 static struct mem_entry {
Michael Chanb6016b72005-05-26 13:03:09 -07004555 u32 offset;
4556 u32 len;
Michael Chan5bae30c2007-05-03 13:18:46 -07004557 } mem_tbl_5706[] = {
Michael Chanb6016b72005-05-26 13:03:09 -07004558 { 0x60000, 0x4000 },
Michael Chan5b0c76a2005-11-04 08:45:49 -08004559 { 0xa0000, 0x3000 },
Michael Chanb6016b72005-05-26 13:03:09 -07004560 { 0xe0000, 0x4000 },
4561 { 0x120000, 0x4000 },
4562 { 0x1a0000, 0x4000 },
4563 { 0x160000, 0x4000 },
4564 { 0xffffffff, 0 },
Michael Chan5bae30c2007-05-03 13:18:46 -07004565 },
4566 mem_tbl_5709[] = {
4567 { 0x60000, 0x4000 },
4568 { 0xa0000, 0x3000 },
4569 { 0xe0000, 0x4000 },
4570 { 0x120000, 0x4000 },
4571 { 0x1a0000, 0x4000 },
4572 { 0xffffffff, 0 },
Michael Chanb6016b72005-05-26 13:03:09 -07004573 };
Michael Chan5bae30c2007-05-03 13:18:46 -07004574 struct mem_entry *mem_tbl;
4575
4576 if (CHIP_NUM(bp) == CHIP_NUM_5709)
4577 mem_tbl = mem_tbl_5709;
4578 else
4579 mem_tbl = mem_tbl_5706;
Michael Chanb6016b72005-05-26 13:03:09 -07004580
4581 for (i = 0; mem_tbl[i].offset != 0xffffffff; i++) {
4582 if ((ret = bnx2_do_mem_test(bp, mem_tbl[i].offset,
4583 mem_tbl[i].len)) != 0) {
4584 return ret;
4585 }
4586 }
Jeff Garzik6aa20a22006-09-13 13:24:59 -04004587
Michael Chanb6016b72005-05-26 13:03:09 -07004588 return ret;
4589}
4590
Michael Chanbc5a0692006-01-23 16:13:22 -08004591#define BNX2_MAC_LOOPBACK 0
4592#define BNX2_PHY_LOOPBACK 1
4593
Michael Chanb6016b72005-05-26 13:03:09 -07004594static int
Michael Chanbc5a0692006-01-23 16:13:22 -08004595bnx2_run_loopback(struct bnx2 *bp, int loopback_mode)
Michael Chanb6016b72005-05-26 13:03:09 -07004596{
4597 unsigned int pkt_size, num_pkts, i;
4598 struct sk_buff *skb, *rx_skb;
4599 unsigned char *packet;
Michael Chanbc5a0692006-01-23 16:13:22 -08004600 u16 rx_start_idx, rx_idx;
Michael Chanb6016b72005-05-26 13:03:09 -07004601 dma_addr_t map;
4602 struct tx_bd *txbd;
4603 struct sw_bd *rx_buf;
4604 struct l2_fhdr *rx_hdr;
4605 int ret = -ENODEV;
4606
Michael Chanbc5a0692006-01-23 16:13:22 -08004607 if (loopback_mode == BNX2_MAC_LOOPBACK) {
4608 bp->loopback = MAC_LOOPBACK;
4609 bnx2_set_mac_loopback(bp);
4610 }
4611 else if (loopback_mode == BNX2_PHY_LOOPBACK) {
Michael Chan80be4432006-11-19 14:07:28 -08004612 bp->loopback = PHY_LOOPBACK;
Michael Chanbc5a0692006-01-23 16:13:22 -08004613 bnx2_set_phy_loopback(bp);
4614 }
4615 else
4616 return -EINVAL;
Michael Chanb6016b72005-05-26 13:03:09 -07004617
4618 pkt_size = 1514;
Michael Chan932f3772006-08-15 01:39:36 -07004619 skb = netdev_alloc_skb(bp->dev, pkt_size);
John W. Linvilleb6cbc3b62005-11-10 12:58:00 -08004620 if (!skb)
4621 return -ENOMEM;
Michael Chanb6016b72005-05-26 13:03:09 -07004622 packet = skb_put(skb, pkt_size);
Michael Chan66342922006-12-14 15:57:04 -08004623 memcpy(packet, bp->dev->dev_addr, 6);
Michael Chanb6016b72005-05-26 13:03:09 -07004624 memset(packet + 6, 0x0, 8);
4625 for (i = 14; i < pkt_size; i++)
4626 packet[i] = (unsigned char) (i & 0xff);
4627
4628 map = pci_map_single(bp->pdev, skb->data, pkt_size,
4629 PCI_DMA_TODEVICE);
4630
Michael Chanbf5295b2006-03-23 01:11:56 -08004631 REG_WR(bp, BNX2_HC_COMMAND,
4632 bp->hc_cmd | BNX2_HC_COMMAND_COAL_NOW_WO_INT);
4633
Michael Chanb6016b72005-05-26 13:03:09 -07004634 REG_RD(bp, BNX2_HC_COMMAND);
4635
4636 udelay(5);
4637 rx_start_idx = bp->status_blk->status_rx_quick_consumer_index0;
4638
Michael Chanb6016b72005-05-26 13:03:09 -07004639 num_pkts = 0;
4640
Michael Chanbc5a0692006-01-23 16:13:22 -08004641 txbd = &bp->tx_desc_ring[TX_RING_IDX(bp->tx_prod)];
Michael Chanb6016b72005-05-26 13:03:09 -07004642
4643 txbd->tx_bd_haddr_hi = (u64) map >> 32;
4644 txbd->tx_bd_haddr_lo = (u64) map & 0xffffffff;
4645 txbd->tx_bd_mss_nbytes = pkt_size;
4646 txbd->tx_bd_vlan_tag_flags = TX_BD_FLAGS_START | TX_BD_FLAGS_END;
4647
4648 num_pkts++;
Michael Chanbc5a0692006-01-23 16:13:22 -08004649 bp->tx_prod = NEXT_TX_BD(bp->tx_prod);
4650 bp->tx_prod_bseq += pkt_size;
Michael Chanb6016b72005-05-26 13:03:09 -07004651
Michael Chan234754d2006-11-19 14:11:41 -08004652 REG_WR16(bp, bp->tx_bidx_addr, bp->tx_prod);
4653 REG_WR(bp, bp->tx_bseq_addr, bp->tx_prod_bseq);
Michael Chanb6016b72005-05-26 13:03:09 -07004654
4655 udelay(100);
4656
Michael Chanbf5295b2006-03-23 01:11:56 -08004657 REG_WR(bp, BNX2_HC_COMMAND,
4658 bp->hc_cmd | BNX2_HC_COMMAND_COAL_NOW_WO_INT);
4659
Michael Chanb6016b72005-05-26 13:03:09 -07004660 REG_RD(bp, BNX2_HC_COMMAND);
4661
4662 udelay(5);
4663
4664 pci_unmap_single(bp->pdev, map, pkt_size, PCI_DMA_TODEVICE);
Michael Chan745720e2006-06-29 12:37:41 -07004665 dev_kfree_skb(skb);
Michael Chanb6016b72005-05-26 13:03:09 -07004666
Michael Chanbc5a0692006-01-23 16:13:22 -08004667 if (bp->status_blk->status_tx_quick_consumer_index0 != bp->tx_prod) {
Michael Chanb6016b72005-05-26 13:03:09 -07004668 goto loopback_test_done;
4669 }
4670
4671 rx_idx = bp->status_blk->status_rx_quick_consumer_index0;
4672 if (rx_idx != rx_start_idx + num_pkts) {
4673 goto loopback_test_done;
4674 }
4675
4676 rx_buf = &bp->rx_buf_ring[rx_start_idx];
4677 rx_skb = rx_buf->skb;
4678
4679 rx_hdr = (struct l2_fhdr *) rx_skb->data;
4680 skb_reserve(rx_skb, bp->rx_offset);
4681
4682 pci_dma_sync_single_for_cpu(bp->pdev,
4683 pci_unmap_addr(rx_buf, mapping),
4684 bp->rx_buf_size, PCI_DMA_FROMDEVICE);
4685
Michael Chanade2bfe2006-01-23 16:09:51 -08004686 if (rx_hdr->l2_fhdr_status &
Michael Chanb6016b72005-05-26 13:03:09 -07004687 (L2_FHDR_ERRORS_BAD_CRC |
4688 L2_FHDR_ERRORS_PHY_DECODE |
4689 L2_FHDR_ERRORS_ALIGNMENT |
4690 L2_FHDR_ERRORS_TOO_SHORT |
4691 L2_FHDR_ERRORS_GIANT_FRAME)) {
4692
4693 goto loopback_test_done;
4694 }
4695
4696 if ((rx_hdr->l2_fhdr_pkt_len - 4) != pkt_size) {
4697 goto loopback_test_done;
4698 }
4699
4700 for (i = 14; i < pkt_size; i++) {
4701 if (*(rx_skb->data + i) != (unsigned char) (i & 0xff)) {
4702 goto loopback_test_done;
4703 }
4704 }
4705
4706 ret = 0;
4707
4708loopback_test_done:
4709 bp->loopback = 0;
4710 return ret;
4711}
4712
Michael Chanbc5a0692006-01-23 16:13:22 -08004713#define BNX2_MAC_LOOPBACK_FAILED 1
4714#define BNX2_PHY_LOOPBACK_FAILED 2
4715#define BNX2_LOOPBACK_FAILED (BNX2_MAC_LOOPBACK_FAILED | \
4716 BNX2_PHY_LOOPBACK_FAILED)
4717
4718static int
4719bnx2_test_loopback(struct bnx2 *bp)
4720{
4721 int rc = 0;
4722
4723 if (!netif_running(bp->dev))
4724 return BNX2_LOOPBACK_FAILED;
4725
4726 bnx2_reset_nic(bp, BNX2_DRV_MSG_CODE_RESET);
4727 spin_lock_bh(&bp->phy_lock);
4728 bnx2_init_phy(bp);
4729 spin_unlock_bh(&bp->phy_lock);
4730 if (bnx2_run_loopback(bp, BNX2_MAC_LOOPBACK))
4731 rc |= BNX2_MAC_LOOPBACK_FAILED;
4732 if (bnx2_run_loopback(bp, BNX2_PHY_LOOPBACK))
4733 rc |= BNX2_PHY_LOOPBACK_FAILED;
4734 return rc;
4735}
4736
Michael Chanb6016b72005-05-26 13:03:09 -07004737#define NVRAM_SIZE 0x200
4738#define CRC32_RESIDUAL 0xdebb20e3
4739
4740static int
4741bnx2_test_nvram(struct bnx2 *bp)
4742{
4743 u32 buf[NVRAM_SIZE / 4];
4744 u8 *data = (u8 *) buf;
4745 int rc = 0;
4746 u32 magic, csum;
4747
4748 if ((rc = bnx2_nvram_read(bp, 0, data, 4)) != 0)
4749 goto test_nvram_done;
4750
4751 magic = be32_to_cpu(buf[0]);
4752 if (magic != 0x669955aa) {
4753 rc = -ENODEV;
4754 goto test_nvram_done;
4755 }
4756
4757 if ((rc = bnx2_nvram_read(bp, 0x100, data, NVRAM_SIZE)) != 0)
4758 goto test_nvram_done;
4759
4760 csum = ether_crc_le(0x100, data);
4761 if (csum != CRC32_RESIDUAL) {
4762 rc = -ENODEV;
4763 goto test_nvram_done;
4764 }
4765
4766 csum = ether_crc_le(0x100, data + 0x100);
4767 if (csum != CRC32_RESIDUAL) {
4768 rc = -ENODEV;
4769 }
4770
4771test_nvram_done:
4772 return rc;
4773}
4774
4775static int
4776bnx2_test_link(struct bnx2 *bp)
4777{
4778 u32 bmsr;
4779
Michael Chanc770a652005-08-25 15:38:39 -07004780 spin_lock_bh(&bp->phy_lock);
Michael Chan27a005b2007-05-03 13:23:41 -07004781 bnx2_enable_bmsr1(bp);
4782 bnx2_read_phy(bp, bp->mii_bmsr1, &bmsr);
4783 bnx2_read_phy(bp, bp->mii_bmsr1, &bmsr);
4784 bnx2_disable_bmsr1(bp);
Michael Chanc770a652005-08-25 15:38:39 -07004785 spin_unlock_bh(&bp->phy_lock);
Jeff Garzik6aa20a22006-09-13 13:24:59 -04004786
Michael Chanb6016b72005-05-26 13:03:09 -07004787 if (bmsr & BMSR_LSTATUS) {
4788 return 0;
4789 }
4790 return -ENODEV;
4791}
4792
4793static int
4794bnx2_test_intr(struct bnx2 *bp)
4795{
4796 int i;
Michael Chanb6016b72005-05-26 13:03:09 -07004797 u16 status_idx;
4798
4799 if (!netif_running(bp->dev))
4800 return -ENODEV;
4801
4802 status_idx = REG_RD(bp, BNX2_PCICFG_INT_ACK_CMD) & 0xffff;
4803
4804 /* This register is not touched during run-time. */
Michael Chanbf5295b2006-03-23 01:11:56 -08004805 REG_WR(bp, BNX2_HC_COMMAND, bp->hc_cmd | BNX2_HC_COMMAND_COAL_NOW);
Michael Chanb6016b72005-05-26 13:03:09 -07004806 REG_RD(bp, BNX2_HC_COMMAND);
4807
4808 for (i = 0; i < 10; i++) {
4809 if ((REG_RD(bp, BNX2_PCICFG_INT_ACK_CMD) & 0xffff) !=
4810 status_idx) {
4811
4812 break;
4813 }
4814
4815 msleep_interruptible(10);
4816 }
4817 if (i < 10)
4818 return 0;
4819
4820 return -ENODEV;
4821}
4822
4823static void
Michael Chan48b01e22006-11-19 14:08:00 -08004824bnx2_5706_serdes_timer(struct bnx2 *bp)
4825{
4826 spin_lock(&bp->phy_lock);
4827 if (bp->serdes_an_pending)
4828 bp->serdes_an_pending--;
4829 else if ((bp->link_up == 0) && (bp->autoneg & AUTONEG_SPEED)) {
4830 u32 bmcr;
4831
4832 bp->current_interval = bp->timer_interval;
4833
Michael Chanca58c3a2007-05-03 13:22:52 -07004834 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chan48b01e22006-11-19 14:08:00 -08004835
4836 if (bmcr & BMCR_ANENABLE) {
4837 u32 phy1, phy2;
4838
4839 bnx2_write_phy(bp, 0x1c, 0x7c00);
4840 bnx2_read_phy(bp, 0x1c, &phy1);
4841
4842 bnx2_write_phy(bp, 0x17, 0x0f01);
4843 bnx2_read_phy(bp, 0x15, &phy2);
4844 bnx2_write_phy(bp, 0x17, 0x0f01);
4845 bnx2_read_phy(bp, 0x15, &phy2);
4846
4847 if ((phy1 & 0x10) && /* SIGNAL DETECT */
4848 !(phy2 & 0x20)) { /* no CONFIG */
4849
4850 bmcr &= ~BMCR_ANENABLE;
4851 bmcr |= BMCR_SPEED1000 | BMCR_FULLDPLX;
Michael Chanca58c3a2007-05-03 13:22:52 -07004852 bnx2_write_phy(bp, bp->mii_bmcr, bmcr);
Michael Chan48b01e22006-11-19 14:08:00 -08004853 bp->phy_flags |= PHY_PARALLEL_DETECT_FLAG;
4854 }
4855 }
4856 }
4857 else if ((bp->link_up) && (bp->autoneg & AUTONEG_SPEED) &&
4858 (bp->phy_flags & PHY_PARALLEL_DETECT_FLAG)) {
4859 u32 phy2;
4860
4861 bnx2_write_phy(bp, 0x17, 0x0f01);
4862 bnx2_read_phy(bp, 0x15, &phy2);
4863 if (phy2 & 0x20) {
4864 u32 bmcr;
4865
Michael Chanca58c3a2007-05-03 13:22:52 -07004866 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chan48b01e22006-11-19 14:08:00 -08004867 bmcr |= BMCR_ANENABLE;
Michael Chanca58c3a2007-05-03 13:22:52 -07004868 bnx2_write_phy(bp, bp->mii_bmcr, bmcr);
Michael Chan48b01e22006-11-19 14:08:00 -08004869
4870 bp->phy_flags &= ~PHY_PARALLEL_DETECT_FLAG;
4871 }
4872 } else
4873 bp->current_interval = bp->timer_interval;
4874
4875 spin_unlock(&bp->phy_lock);
4876}
4877
4878static void
Michael Chanf8dd0642006-11-19 14:08:29 -08004879bnx2_5708_serdes_timer(struct bnx2 *bp)
4880{
Michael Chan0d8a6572007-07-07 22:49:43 -07004881 if (bp->phy_flags & REMOTE_PHY_CAP_FLAG)
4882 return;
4883
Michael Chanf8dd0642006-11-19 14:08:29 -08004884 if ((bp->phy_flags & PHY_2_5G_CAPABLE_FLAG) == 0) {
4885 bp->serdes_an_pending = 0;
4886 return;
4887 }
4888
4889 spin_lock(&bp->phy_lock);
4890 if (bp->serdes_an_pending)
4891 bp->serdes_an_pending--;
4892 else if ((bp->link_up == 0) && (bp->autoneg & AUTONEG_SPEED)) {
4893 u32 bmcr;
4894
Michael Chanca58c3a2007-05-03 13:22:52 -07004895 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chanf8dd0642006-11-19 14:08:29 -08004896 if (bmcr & BMCR_ANENABLE) {
Michael Chan605a9e22007-05-03 13:23:13 -07004897 bnx2_enable_forced_2g5(bp);
Michael Chanf8dd0642006-11-19 14:08:29 -08004898 bp->current_interval = SERDES_FORCED_TIMEOUT;
4899 } else {
Michael Chan605a9e22007-05-03 13:23:13 -07004900 bnx2_disable_forced_2g5(bp);
Michael Chanf8dd0642006-11-19 14:08:29 -08004901 bp->serdes_an_pending = 2;
4902 bp->current_interval = bp->timer_interval;
4903 }
4904
4905 } else
4906 bp->current_interval = bp->timer_interval;
4907
4908 spin_unlock(&bp->phy_lock);
4909}
4910
4911static void
Michael Chanb6016b72005-05-26 13:03:09 -07004912bnx2_timer(unsigned long data)
4913{
4914 struct bnx2 *bp = (struct bnx2 *) data;
Michael Chanb6016b72005-05-26 13:03:09 -07004915
Michael Chancd339a02005-08-25 15:35:24 -07004916 if (!netif_running(bp->dev))
4917 return;
4918
Michael Chanb6016b72005-05-26 13:03:09 -07004919 if (atomic_read(&bp->intr_sem) != 0)
4920 goto bnx2_restart_timer;
4921
Michael Chandf149d72007-07-07 22:51:36 -07004922 bnx2_send_heart_beat(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07004923
Michael Chancea94db2006-06-12 22:16:13 -07004924 bp->stats_blk->stat_FwRxDrop = REG_RD_IND(bp, BNX2_FW_RX_DROP_COUNT);
4925
Michael Chan02537b062007-06-04 21:24:07 -07004926 /* workaround occasional corrupted counters */
4927 if (CHIP_NUM(bp) == CHIP_NUM_5708 && bp->stats_ticks)
4928 REG_WR(bp, BNX2_HC_COMMAND, bp->hc_cmd |
4929 BNX2_HC_COMMAND_STATS_NOW);
4930
Michael Chanf8dd0642006-11-19 14:08:29 -08004931 if (bp->phy_flags & PHY_SERDES_FLAG) {
4932 if (CHIP_NUM(bp) == CHIP_NUM_5706)
4933 bnx2_5706_serdes_timer(bp);
Michael Chan27a005b2007-05-03 13:23:41 -07004934 else
Michael Chanf8dd0642006-11-19 14:08:29 -08004935 bnx2_5708_serdes_timer(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07004936 }
4937
4938bnx2_restart_timer:
Michael Chancd339a02005-08-25 15:35:24 -07004939 mod_timer(&bp->timer, jiffies + bp->current_interval);
Michael Chanb6016b72005-05-26 13:03:09 -07004940}
4941
Michael Chan8e6a72c2007-05-03 13:24:48 -07004942static int
4943bnx2_request_irq(struct bnx2 *bp)
4944{
4945 struct net_device *dev = bp->dev;
4946 int rc = 0;
4947
4948 if (bp->flags & USING_MSI_FLAG) {
4949 irq_handler_t fn = bnx2_msi;
4950
4951 if (bp->flags & ONE_SHOT_MSI_FLAG)
4952 fn = bnx2_msi_1shot;
4953
4954 rc = request_irq(bp->pdev->irq, fn, 0, dev->name, dev);
4955 } else
4956 rc = request_irq(bp->pdev->irq, bnx2_interrupt,
4957 IRQF_SHARED, dev->name, dev);
4958 return rc;
4959}
4960
4961static void
4962bnx2_free_irq(struct bnx2 *bp)
4963{
4964 struct net_device *dev = bp->dev;
4965
4966 if (bp->flags & USING_MSI_FLAG) {
4967 free_irq(bp->pdev->irq, dev);
4968 pci_disable_msi(bp->pdev);
4969 bp->flags &= ~(USING_MSI_FLAG | ONE_SHOT_MSI_FLAG);
4970 } else
4971 free_irq(bp->pdev->irq, dev);
4972}
4973
Michael Chanb6016b72005-05-26 13:03:09 -07004974/* Called with rtnl_lock */
4975static int
4976bnx2_open(struct net_device *dev)
4977{
Michael Chan972ec0d2006-01-23 16:12:43 -08004978 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07004979 int rc;
4980
Michael Chan1b2f9222007-05-03 13:20:19 -07004981 netif_carrier_off(dev);
4982
Pavel Machek829ca9a2005-09-03 15:56:56 -07004983 bnx2_set_power_state(bp, PCI_D0);
Michael Chanb6016b72005-05-26 13:03:09 -07004984 bnx2_disable_int(bp);
4985
4986 rc = bnx2_alloc_mem(bp);
4987 if (rc)
4988 return rc;
4989
Stephen Hemmingerbea33482007-10-03 16:41:36 -07004990 napi_enable(&bp->napi);
4991
Michael Chan8e6a72c2007-05-03 13:24:48 -07004992 if ((bp->flags & MSI_CAP_FLAG) && !disable_msi) {
Michael Chanb6016b72005-05-26 13:03:09 -07004993 if (pci_enable_msi(bp->pdev) == 0) {
4994 bp->flags |= USING_MSI_FLAG;
Michael Chan8e6a72c2007-05-03 13:24:48 -07004995 if (CHIP_NUM(bp) == CHIP_NUM_5709)
4996 bp->flags |= ONE_SHOT_MSI_FLAG;
Michael Chanb6016b72005-05-26 13:03:09 -07004997 }
4998 }
Michael Chan8e6a72c2007-05-03 13:24:48 -07004999 rc = bnx2_request_irq(bp);
5000
Michael Chanb6016b72005-05-26 13:03:09 -07005001 if (rc) {
Stephen Hemmingerbea33482007-10-03 16:41:36 -07005002 napi_disable(&bp->napi);
Michael Chanb6016b72005-05-26 13:03:09 -07005003 bnx2_free_mem(bp);
5004 return rc;
5005 }
5006
5007 rc = bnx2_init_nic(bp);
5008
5009 if (rc) {
Stephen Hemmingerbea33482007-10-03 16:41:36 -07005010 napi_disable(&bp->napi);
Michael Chan8e6a72c2007-05-03 13:24:48 -07005011 bnx2_free_irq(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07005012 bnx2_free_skbs(bp);
5013 bnx2_free_mem(bp);
5014 return rc;
5015 }
Jeff Garzik6aa20a22006-09-13 13:24:59 -04005016
Michael Chancd339a02005-08-25 15:35:24 -07005017 mod_timer(&bp->timer, jiffies + bp->current_interval);
Michael Chanb6016b72005-05-26 13:03:09 -07005018
5019 atomic_set(&bp->intr_sem, 0);
5020
5021 bnx2_enable_int(bp);
5022
5023 if (bp->flags & USING_MSI_FLAG) {
5024 /* Test MSI to make sure it is working
5025 * If MSI test fails, go back to INTx mode
5026 */
5027 if (bnx2_test_intr(bp) != 0) {
5028 printk(KERN_WARNING PFX "%s: No interrupt was generated"
5029 " using MSI, switching to INTx mode. Please"
5030 " report this failure to the PCI maintainer"
5031 " and include system chipset information.\n",
5032 bp->dev->name);
5033
5034 bnx2_disable_int(bp);
Michael Chan8e6a72c2007-05-03 13:24:48 -07005035 bnx2_free_irq(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07005036
5037 rc = bnx2_init_nic(bp);
5038
Michael Chan8e6a72c2007-05-03 13:24:48 -07005039 if (!rc)
5040 rc = bnx2_request_irq(bp);
5041
Michael Chanb6016b72005-05-26 13:03:09 -07005042 if (rc) {
Stephen Hemmingerbea33482007-10-03 16:41:36 -07005043 napi_disable(&bp->napi);
Michael Chanb6016b72005-05-26 13:03:09 -07005044 bnx2_free_skbs(bp);
5045 bnx2_free_mem(bp);
5046 del_timer_sync(&bp->timer);
5047 return rc;
5048 }
5049 bnx2_enable_int(bp);
5050 }
5051 }
5052 if (bp->flags & USING_MSI_FLAG) {
5053 printk(KERN_INFO PFX "%s: using MSI\n", dev->name);
5054 }
5055
5056 netif_start_queue(dev);
5057
5058 return 0;
5059}
5060
5061static void
David Howellsc4028952006-11-22 14:57:56 +00005062bnx2_reset_task(struct work_struct *work)
Michael Chanb6016b72005-05-26 13:03:09 -07005063{
David Howellsc4028952006-11-22 14:57:56 +00005064 struct bnx2 *bp = container_of(work, struct bnx2, reset_task);
Michael Chanb6016b72005-05-26 13:03:09 -07005065
Michael Chanafdc08b2005-08-25 15:34:29 -07005066 if (!netif_running(bp->dev))
5067 return;
5068
5069 bp->in_reset_task = 1;
Michael Chanb6016b72005-05-26 13:03:09 -07005070 bnx2_netif_stop(bp);
5071
5072 bnx2_init_nic(bp);
5073
5074 atomic_set(&bp->intr_sem, 1);
5075 bnx2_netif_start(bp);
Michael Chanafdc08b2005-08-25 15:34:29 -07005076 bp->in_reset_task = 0;
Michael Chanb6016b72005-05-26 13:03:09 -07005077}
5078
5079static void
5080bnx2_tx_timeout(struct net_device *dev)
5081{
Michael Chan972ec0d2006-01-23 16:12:43 -08005082 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07005083
5084 /* This allows the netif to be shutdown gracefully before resetting */
5085 schedule_work(&bp->reset_task);
5086}
5087
5088#ifdef BCM_VLAN
5089/* Called with rtnl_lock */
5090static void
5091bnx2_vlan_rx_register(struct net_device *dev, struct vlan_group *vlgrp)
5092{
Michael Chan972ec0d2006-01-23 16:12:43 -08005093 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07005094
5095 bnx2_netif_stop(bp);
5096
5097 bp->vlgrp = vlgrp;
5098 bnx2_set_rx_mode(dev);
5099
5100 bnx2_netif_start(bp);
5101}
Michael Chanb6016b72005-05-26 13:03:09 -07005102#endif
5103
Herbert Xu932ff272006-06-09 12:20:56 -07005104/* Called with netif_tx_lock.
Michael Chan2f8af122006-08-15 01:39:10 -07005105 * bnx2_tx_int() runs without netif_tx_lock unless it needs to call
5106 * netif_wake_queue().
Michael Chanb6016b72005-05-26 13:03:09 -07005107 */
5108static int
5109bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev)
5110{
Michael Chan972ec0d2006-01-23 16:12:43 -08005111 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07005112 dma_addr_t mapping;
5113 struct tx_bd *txbd;
5114 struct sw_bd *tx_buf;
5115 u32 len, vlan_tag_flags, last_frag, mss;
5116 u16 prod, ring_prod;
5117 int i;
5118
Michael Chane89bbf12005-08-25 15:36:58 -07005119 if (unlikely(bnx2_tx_avail(bp) < (skb_shinfo(skb)->nr_frags + 1))) {
Michael Chanb6016b72005-05-26 13:03:09 -07005120 netif_stop_queue(dev);
5121 printk(KERN_ERR PFX "%s: BUG! Tx ring full when queue awake!\n",
5122 dev->name);
5123
5124 return NETDEV_TX_BUSY;
5125 }
5126 len = skb_headlen(skb);
5127 prod = bp->tx_prod;
5128 ring_prod = TX_RING_IDX(prod);
5129
5130 vlan_tag_flags = 0;
Patrick McHardy84fa7932006-08-29 16:44:56 -07005131 if (skb->ip_summed == CHECKSUM_PARTIAL) {
Michael Chanb6016b72005-05-26 13:03:09 -07005132 vlan_tag_flags |= TX_BD_FLAGS_TCP_UDP_CKSUM;
5133 }
5134
5135 if (bp->vlgrp != 0 && vlan_tx_tag_present(skb)) {
5136 vlan_tag_flags |=
5137 (TX_BD_FLAGS_VLAN_TAG | (vlan_tx_tag_get(skb) << 16));
5138 }
Michael Chanfde82052007-05-03 17:23:35 -07005139 if ((mss = skb_shinfo(skb)->gso_size)) {
Michael Chanb6016b72005-05-26 13:03:09 -07005140 u32 tcp_opt_len, ip_tcp_len;
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -07005141 struct iphdr *iph;
Michael Chanb6016b72005-05-26 13:03:09 -07005142
Michael Chanb6016b72005-05-26 13:03:09 -07005143 vlan_tag_flags |= TX_BD_FLAGS_SW_LSO;
5144
Michael Chan4666f872007-05-03 13:22:28 -07005145 tcp_opt_len = tcp_optlen(skb);
Arnaldo Carvalho de Meloab6a5bb2007-03-18 17:43:48 -07005146
Michael Chan4666f872007-05-03 13:22:28 -07005147 if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6) {
5148 u32 tcp_off = skb_transport_offset(skb) -
5149 sizeof(struct ipv6hdr) - ETH_HLEN;
Michael Chanb6016b72005-05-26 13:03:09 -07005150
Michael Chan4666f872007-05-03 13:22:28 -07005151 vlan_tag_flags |= ((tcp_opt_len >> 2) << 8) |
5152 TX_BD_FLAGS_SW_FLAGS;
5153 if (likely(tcp_off == 0))
5154 vlan_tag_flags &= ~TX_BD_FLAGS_TCP6_OFF0_MSK;
5155 else {
5156 tcp_off >>= 3;
5157 vlan_tag_flags |= ((tcp_off & 0x3) <<
5158 TX_BD_FLAGS_TCP6_OFF0_SHL) |
5159 ((tcp_off & 0x10) <<
5160 TX_BD_FLAGS_TCP6_OFF4_SHL);
5161 mss |= (tcp_off & 0xc) << TX_BD_TCP6_OFF2_SHL;
5162 }
5163 } else {
5164 if (skb_header_cloned(skb) &&
5165 pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) {
5166 dev_kfree_skb(skb);
5167 return NETDEV_TX_OK;
5168 }
5169
5170 ip_tcp_len = ip_hdrlen(skb) + sizeof(struct tcphdr);
5171
5172 iph = ip_hdr(skb);
5173 iph->check = 0;
5174 iph->tot_len = htons(mss + ip_tcp_len + tcp_opt_len);
5175 tcp_hdr(skb)->check = ~csum_tcpudp_magic(iph->saddr,
5176 iph->daddr, 0,
5177 IPPROTO_TCP,
5178 0);
5179 if (tcp_opt_len || (iph->ihl > 5)) {
5180 vlan_tag_flags |= ((iph->ihl - 5) +
5181 (tcp_opt_len >> 2)) << 8;
5182 }
Michael Chanb6016b72005-05-26 13:03:09 -07005183 }
Michael Chan4666f872007-05-03 13:22:28 -07005184 } else
Michael Chanb6016b72005-05-26 13:03:09 -07005185 mss = 0;
Michael Chanb6016b72005-05-26 13:03:09 -07005186
5187 mapping = pci_map_single(bp->pdev, skb->data, len, PCI_DMA_TODEVICE);
Jeff Garzik6aa20a22006-09-13 13:24:59 -04005188
Michael Chanb6016b72005-05-26 13:03:09 -07005189 tx_buf = &bp->tx_buf_ring[ring_prod];
5190 tx_buf->skb = skb;
5191 pci_unmap_addr_set(tx_buf, mapping, mapping);
5192
5193 txbd = &bp->tx_desc_ring[ring_prod];
5194
5195 txbd->tx_bd_haddr_hi = (u64) mapping >> 32;
5196 txbd->tx_bd_haddr_lo = (u64) mapping & 0xffffffff;
5197 txbd->tx_bd_mss_nbytes = len | (mss << 16);
5198 txbd->tx_bd_vlan_tag_flags = vlan_tag_flags | TX_BD_FLAGS_START;
5199
5200 last_frag = skb_shinfo(skb)->nr_frags;
5201
5202 for (i = 0; i < last_frag; i++) {
5203 skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
5204
5205 prod = NEXT_TX_BD(prod);
5206 ring_prod = TX_RING_IDX(prod);
5207 txbd = &bp->tx_desc_ring[ring_prod];
5208
5209 len = frag->size;
5210 mapping = pci_map_page(bp->pdev, frag->page, frag->page_offset,
5211 len, PCI_DMA_TODEVICE);
5212 pci_unmap_addr_set(&bp->tx_buf_ring[ring_prod],
5213 mapping, mapping);
5214
5215 txbd->tx_bd_haddr_hi = (u64) mapping >> 32;
5216 txbd->tx_bd_haddr_lo = (u64) mapping & 0xffffffff;
5217 txbd->tx_bd_mss_nbytes = len | (mss << 16);
5218 txbd->tx_bd_vlan_tag_flags = vlan_tag_flags;
5219
5220 }
5221 txbd->tx_bd_vlan_tag_flags |= TX_BD_FLAGS_END;
5222
5223 prod = NEXT_TX_BD(prod);
5224 bp->tx_prod_bseq += skb->len;
5225
Michael Chan234754d2006-11-19 14:11:41 -08005226 REG_WR16(bp, bp->tx_bidx_addr, prod);
5227 REG_WR(bp, bp->tx_bseq_addr, bp->tx_prod_bseq);
Michael Chanb6016b72005-05-26 13:03:09 -07005228
5229 mmiowb();
5230
5231 bp->tx_prod = prod;
5232 dev->trans_start = jiffies;
5233
Michael Chane89bbf12005-08-25 15:36:58 -07005234 if (unlikely(bnx2_tx_avail(bp) <= MAX_SKB_FRAGS)) {
Michael Chane89bbf12005-08-25 15:36:58 -07005235 netif_stop_queue(dev);
Michael Chan2f8af122006-08-15 01:39:10 -07005236 if (bnx2_tx_avail(bp) > bp->tx_wake_thresh)
Michael Chane89bbf12005-08-25 15:36:58 -07005237 netif_wake_queue(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07005238 }
5239
5240 return NETDEV_TX_OK;
5241}
5242
5243/* Called with rtnl_lock */
5244static int
5245bnx2_close(struct net_device *dev)
5246{
Michael Chan972ec0d2006-01-23 16:12:43 -08005247 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07005248 u32 reset_code;
5249
Michael Chanafdc08b2005-08-25 15:34:29 -07005250 /* Calling flush_scheduled_work() may deadlock because
5251 * linkwatch_event() may be on the workqueue and it will try to get
5252 * the rtnl_lock which we are holding.
5253 */
5254 while (bp->in_reset_task)
5255 msleep(1);
5256
Stephen Hemmingerbea33482007-10-03 16:41:36 -07005257 bnx2_disable_int_sync(bp);
5258 napi_disable(&bp->napi);
Michael Chanb6016b72005-05-26 13:03:09 -07005259 del_timer_sync(&bp->timer);
Michael Chandda1e392006-01-23 16:08:14 -08005260 if (bp->flags & NO_WOL_FLAG)
Michael Chan6c4f0952006-06-29 12:38:15 -07005261 reset_code = BNX2_DRV_MSG_CODE_UNLOAD_LNK_DN;
Michael Chandda1e392006-01-23 16:08:14 -08005262 else if (bp->wol)
Michael Chanb6016b72005-05-26 13:03:09 -07005263 reset_code = BNX2_DRV_MSG_CODE_SUSPEND_WOL;
5264 else
5265 reset_code = BNX2_DRV_MSG_CODE_SUSPEND_NO_WOL;
5266 bnx2_reset_chip(bp, reset_code);
Michael Chan8e6a72c2007-05-03 13:24:48 -07005267 bnx2_free_irq(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07005268 bnx2_free_skbs(bp);
5269 bnx2_free_mem(bp);
5270 bp->link_up = 0;
5271 netif_carrier_off(bp->dev);
Pavel Machek829ca9a2005-09-03 15:56:56 -07005272 bnx2_set_power_state(bp, PCI_D3hot);
Michael Chanb6016b72005-05-26 13:03:09 -07005273 return 0;
5274}
5275
5276#define GET_NET_STATS64(ctr) \
5277 (unsigned long) ((unsigned long) (ctr##_hi) << 32) + \
5278 (unsigned long) (ctr##_lo)
5279
5280#define GET_NET_STATS32(ctr) \
5281 (ctr##_lo)
5282
5283#if (BITS_PER_LONG == 64)
5284#define GET_NET_STATS GET_NET_STATS64
5285#else
5286#define GET_NET_STATS GET_NET_STATS32
5287#endif
5288
5289static struct net_device_stats *
5290bnx2_get_stats(struct net_device *dev)
5291{
Michael Chan972ec0d2006-01-23 16:12:43 -08005292 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07005293 struct statistics_block *stats_blk = bp->stats_blk;
5294 struct net_device_stats *net_stats = &bp->net_stats;
5295
5296 if (bp->stats_blk == NULL) {
5297 return net_stats;
5298 }
5299 net_stats->rx_packets =
5300 GET_NET_STATS(stats_blk->stat_IfHCInUcastPkts) +
5301 GET_NET_STATS(stats_blk->stat_IfHCInMulticastPkts) +
5302 GET_NET_STATS(stats_blk->stat_IfHCInBroadcastPkts);
5303
5304 net_stats->tx_packets =
5305 GET_NET_STATS(stats_blk->stat_IfHCOutUcastPkts) +
5306 GET_NET_STATS(stats_blk->stat_IfHCOutMulticastPkts) +
5307 GET_NET_STATS(stats_blk->stat_IfHCOutBroadcastPkts);
5308
5309 net_stats->rx_bytes =
5310 GET_NET_STATS(stats_blk->stat_IfHCInOctets);
5311
5312 net_stats->tx_bytes =
5313 GET_NET_STATS(stats_blk->stat_IfHCOutOctets);
5314
Jeff Garzik6aa20a22006-09-13 13:24:59 -04005315 net_stats->multicast =
Michael Chanb6016b72005-05-26 13:03:09 -07005316 GET_NET_STATS(stats_blk->stat_IfHCOutMulticastPkts);
5317
Jeff Garzik6aa20a22006-09-13 13:24:59 -04005318 net_stats->collisions =
Michael Chanb6016b72005-05-26 13:03:09 -07005319 (unsigned long) stats_blk->stat_EtherStatsCollisions;
5320
Jeff Garzik6aa20a22006-09-13 13:24:59 -04005321 net_stats->rx_length_errors =
Michael Chanb6016b72005-05-26 13:03:09 -07005322 (unsigned long) (stats_blk->stat_EtherStatsUndersizePkts +
5323 stats_blk->stat_EtherStatsOverrsizePkts);
5324
Jeff Garzik6aa20a22006-09-13 13:24:59 -04005325 net_stats->rx_over_errors =
Michael Chanb6016b72005-05-26 13:03:09 -07005326 (unsigned long) stats_blk->stat_IfInMBUFDiscards;
5327
Jeff Garzik6aa20a22006-09-13 13:24:59 -04005328 net_stats->rx_frame_errors =
Michael Chanb6016b72005-05-26 13:03:09 -07005329 (unsigned long) stats_blk->stat_Dot3StatsAlignmentErrors;
5330
Jeff Garzik6aa20a22006-09-13 13:24:59 -04005331 net_stats->rx_crc_errors =
Michael Chanb6016b72005-05-26 13:03:09 -07005332 (unsigned long) stats_blk->stat_Dot3StatsFCSErrors;
5333
5334 net_stats->rx_errors = net_stats->rx_length_errors +
5335 net_stats->rx_over_errors + net_stats->rx_frame_errors +
5336 net_stats->rx_crc_errors;
5337
5338 net_stats->tx_aborted_errors =
5339 (unsigned long) (stats_blk->stat_Dot3StatsExcessiveCollisions +
5340 stats_blk->stat_Dot3StatsLateCollisions);
5341
Michael Chan5b0c76a2005-11-04 08:45:49 -08005342 if ((CHIP_NUM(bp) == CHIP_NUM_5706) ||
5343 (CHIP_ID(bp) == CHIP_ID_5708_A0))
Michael Chanb6016b72005-05-26 13:03:09 -07005344 net_stats->tx_carrier_errors = 0;
5345 else {
5346 net_stats->tx_carrier_errors =
5347 (unsigned long)
5348 stats_blk->stat_Dot3StatsCarrierSenseErrors;
5349 }
5350
5351 net_stats->tx_errors =
Jeff Garzik6aa20a22006-09-13 13:24:59 -04005352 (unsigned long)
Michael Chanb6016b72005-05-26 13:03:09 -07005353 stats_blk->stat_emac_tx_stat_dot3statsinternalmactransmiterrors
5354 +
5355 net_stats->tx_aborted_errors +
5356 net_stats->tx_carrier_errors;
5357
Michael Chancea94db2006-06-12 22:16:13 -07005358 net_stats->rx_missed_errors =
5359 (unsigned long) (stats_blk->stat_IfInMBUFDiscards +
5360 stats_blk->stat_FwRxDrop);
5361
Michael Chanb6016b72005-05-26 13:03:09 -07005362 return net_stats;
5363}
5364
5365/* All ethtool functions called with rtnl_lock */
5366
5367static int
5368bnx2_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
5369{
Michael Chan972ec0d2006-01-23 16:12:43 -08005370 struct bnx2 *bp = netdev_priv(dev);
Michael Chan7b6b8342007-07-07 22:50:15 -07005371 int support_serdes = 0, support_copper = 0;
Michael Chanb6016b72005-05-26 13:03:09 -07005372
5373 cmd->supported = SUPPORTED_Autoneg;
Michael Chan7b6b8342007-07-07 22:50:15 -07005374 if (bp->phy_flags & REMOTE_PHY_CAP_FLAG) {
5375 support_serdes = 1;
5376 support_copper = 1;
5377 } else if (bp->phy_port == PORT_FIBRE)
5378 support_serdes = 1;
5379 else
5380 support_copper = 1;
5381
5382 if (support_serdes) {
Michael Chanb6016b72005-05-26 13:03:09 -07005383 cmd->supported |= SUPPORTED_1000baseT_Full |
5384 SUPPORTED_FIBRE;
Michael Chan605a9e22007-05-03 13:23:13 -07005385 if (bp->phy_flags & PHY_2_5G_CAPABLE_FLAG)
5386 cmd->supported |= SUPPORTED_2500baseX_Full;
Michael Chanb6016b72005-05-26 13:03:09 -07005387
Michael Chanb6016b72005-05-26 13:03:09 -07005388 }
Michael Chan7b6b8342007-07-07 22:50:15 -07005389 if (support_copper) {
Michael Chanb6016b72005-05-26 13:03:09 -07005390 cmd->supported |= SUPPORTED_10baseT_Half |
5391 SUPPORTED_10baseT_Full |
5392 SUPPORTED_100baseT_Half |
5393 SUPPORTED_100baseT_Full |
5394 SUPPORTED_1000baseT_Full |
5395 SUPPORTED_TP;
5396
Michael Chanb6016b72005-05-26 13:03:09 -07005397 }
5398
Michael Chan7b6b8342007-07-07 22:50:15 -07005399 spin_lock_bh(&bp->phy_lock);
5400 cmd->port = bp->phy_port;
Michael Chanb6016b72005-05-26 13:03:09 -07005401 cmd->advertising = bp->advertising;
5402
5403 if (bp->autoneg & AUTONEG_SPEED) {
5404 cmd->autoneg = AUTONEG_ENABLE;
5405 }
5406 else {
5407 cmd->autoneg = AUTONEG_DISABLE;
5408 }
5409
5410 if (netif_carrier_ok(dev)) {
5411 cmd->speed = bp->line_speed;
5412 cmd->duplex = bp->duplex;
5413 }
5414 else {
5415 cmd->speed = -1;
5416 cmd->duplex = -1;
5417 }
Michael Chan7b6b8342007-07-07 22:50:15 -07005418 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07005419
5420 cmd->transceiver = XCVR_INTERNAL;
5421 cmd->phy_address = bp->phy_addr;
5422
5423 return 0;
5424}
Jeff Garzik6aa20a22006-09-13 13:24:59 -04005425
Michael Chanb6016b72005-05-26 13:03:09 -07005426static int
5427bnx2_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
5428{
Michael Chan972ec0d2006-01-23 16:12:43 -08005429 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07005430 u8 autoneg = bp->autoneg;
5431 u8 req_duplex = bp->req_duplex;
5432 u16 req_line_speed = bp->req_line_speed;
5433 u32 advertising = bp->advertising;
Michael Chan7b6b8342007-07-07 22:50:15 -07005434 int err = -EINVAL;
5435
5436 spin_lock_bh(&bp->phy_lock);
5437
5438 if (cmd->port != PORT_TP && cmd->port != PORT_FIBRE)
5439 goto err_out_unlock;
5440
5441 if (cmd->port != bp->phy_port && !(bp->phy_flags & REMOTE_PHY_CAP_FLAG))
5442 goto err_out_unlock;
Michael Chanb6016b72005-05-26 13:03:09 -07005443
5444 if (cmd->autoneg == AUTONEG_ENABLE) {
5445 autoneg |= AUTONEG_SPEED;
5446
Jeff Garzik6aa20a22006-09-13 13:24:59 -04005447 cmd->advertising &= ETHTOOL_ALL_COPPER_SPEED;
Michael Chanb6016b72005-05-26 13:03:09 -07005448
5449 /* allow advertising 1 speed */
5450 if ((cmd->advertising == ADVERTISED_10baseT_Half) ||
5451 (cmd->advertising == ADVERTISED_10baseT_Full) ||
5452 (cmd->advertising == ADVERTISED_100baseT_Half) ||
5453 (cmd->advertising == ADVERTISED_100baseT_Full)) {
5454
Michael Chan7b6b8342007-07-07 22:50:15 -07005455 if (cmd->port == PORT_FIBRE)
5456 goto err_out_unlock;
Michael Chanb6016b72005-05-26 13:03:09 -07005457
5458 advertising = cmd->advertising;
5459
Michael Chan27a005b2007-05-03 13:23:41 -07005460 } else if (cmd->advertising == ADVERTISED_2500baseX_Full) {
Michael Chan7b6b8342007-07-07 22:50:15 -07005461 if (!(bp->phy_flags & PHY_2_5G_CAPABLE_FLAG) ||
5462 (cmd->port == PORT_TP))
5463 goto err_out_unlock;
5464 } else if (cmd->advertising == ADVERTISED_1000baseT_Full)
Michael Chanb6016b72005-05-26 13:03:09 -07005465 advertising = cmd->advertising;
Michael Chan7b6b8342007-07-07 22:50:15 -07005466 else if (cmd->advertising == ADVERTISED_1000baseT_Half)
5467 goto err_out_unlock;
Michael Chanb6016b72005-05-26 13:03:09 -07005468 else {
Michael Chan7b6b8342007-07-07 22:50:15 -07005469 if (cmd->port == PORT_FIBRE)
Michael Chanb6016b72005-05-26 13:03:09 -07005470 advertising = ETHTOOL_ALL_FIBRE_SPEED;
Michael Chan7b6b8342007-07-07 22:50:15 -07005471 else
Michael Chanb6016b72005-05-26 13:03:09 -07005472 advertising = ETHTOOL_ALL_COPPER_SPEED;
Michael Chanb6016b72005-05-26 13:03:09 -07005473 }
5474 advertising |= ADVERTISED_Autoneg;
5475 }
5476 else {
Michael Chan7b6b8342007-07-07 22:50:15 -07005477 if (cmd->port == PORT_FIBRE) {
Michael Chan80be4432006-11-19 14:07:28 -08005478 if ((cmd->speed != SPEED_1000 &&
5479 cmd->speed != SPEED_2500) ||
5480 (cmd->duplex != DUPLEX_FULL))
Michael Chan7b6b8342007-07-07 22:50:15 -07005481 goto err_out_unlock;
Michael Chan80be4432006-11-19 14:07:28 -08005482
5483 if (cmd->speed == SPEED_2500 &&
5484 !(bp->phy_flags & PHY_2_5G_CAPABLE_FLAG))
Michael Chan7b6b8342007-07-07 22:50:15 -07005485 goto err_out_unlock;
Michael Chanb6016b72005-05-26 13:03:09 -07005486 }
Michael Chan7b6b8342007-07-07 22:50:15 -07005487 else if (cmd->speed == SPEED_1000 || cmd->speed == SPEED_2500)
5488 goto err_out_unlock;
5489
Michael Chanb6016b72005-05-26 13:03:09 -07005490 autoneg &= ~AUTONEG_SPEED;
5491 req_line_speed = cmd->speed;
5492 req_duplex = cmd->duplex;
5493 advertising = 0;
5494 }
5495
5496 bp->autoneg = autoneg;
5497 bp->advertising = advertising;
5498 bp->req_line_speed = req_line_speed;
5499 bp->req_duplex = req_duplex;
5500
Michael Chan7b6b8342007-07-07 22:50:15 -07005501 err = bnx2_setup_phy(bp, cmd->port);
Michael Chanb6016b72005-05-26 13:03:09 -07005502
Michael Chan7b6b8342007-07-07 22:50:15 -07005503err_out_unlock:
Michael Chanc770a652005-08-25 15:38:39 -07005504 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07005505
Michael Chan7b6b8342007-07-07 22:50:15 -07005506 return err;
Michael Chanb6016b72005-05-26 13:03:09 -07005507}
5508
5509static void
5510bnx2_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
5511{
Michael Chan972ec0d2006-01-23 16:12:43 -08005512 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07005513
5514 strcpy(info->driver, DRV_MODULE_NAME);
5515 strcpy(info->version, DRV_MODULE_VERSION);
5516 strcpy(info->bus_info, pci_name(bp->pdev));
Michael Chan58fc2ea2007-07-07 22:52:02 -07005517 strcpy(info->fw_version, bp->fw_version);
Michael Chanb6016b72005-05-26 13:03:09 -07005518}
5519
Michael Chan244ac4f2006-03-20 17:48:46 -08005520#define BNX2_REGDUMP_LEN (32 * 1024)
5521
5522static int
5523bnx2_get_regs_len(struct net_device *dev)
5524{
5525 return BNX2_REGDUMP_LEN;
5526}
5527
5528static void
5529bnx2_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *_p)
5530{
5531 u32 *p = _p, i, offset;
5532 u8 *orig_p = _p;
5533 struct bnx2 *bp = netdev_priv(dev);
5534 u32 reg_boundaries[] = { 0x0000, 0x0098, 0x0400, 0x045c,
5535 0x0800, 0x0880, 0x0c00, 0x0c10,
5536 0x0c30, 0x0d08, 0x1000, 0x101c,
5537 0x1040, 0x1048, 0x1080, 0x10a4,
5538 0x1400, 0x1490, 0x1498, 0x14f0,
5539 0x1500, 0x155c, 0x1580, 0x15dc,
5540 0x1600, 0x1658, 0x1680, 0x16d8,
5541 0x1800, 0x1820, 0x1840, 0x1854,
5542 0x1880, 0x1894, 0x1900, 0x1984,
5543 0x1c00, 0x1c0c, 0x1c40, 0x1c54,
5544 0x1c80, 0x1c94, 0x1d00, 0x1d84,
5545 0x2000, 0x2030, 0x23c0, 0x2400,
5546 0x2800, 0x2820, 0x2830, 0x2850,
5547 0x2b40, 0x2c10, 0x2fc0, 0x3058,
5548 0x3c00, 0x3c94, 0x4000, 0x4010,
5549 0x4080, 0x4090, 0x43c0, 0x4458,
5550 0x4c00, 0x4c18, 0x4c40, 0x4c54,
5551 0x4fc0, 0x5010, 0x53c0, 0x5444,
5552 0x5c00, 0x5c18, 0x5c80, 0x5c90,
5553 0x5fc0, 0x6000, 0x6400, 0x6428,
5554 0x6800, 0x6848, 0x684c, 0x6860,
5555 0x6888, 0x6910, 0x8000 };
5556
5557 regs->version = 0;
5558
5559 memset(p, 0, BNX2_REGDUMP_LEN);
5560
5561 if (!netif_running(bp->dev))
5562 return;
5563
5564 i = 0;
5565 offset = reg_boundaries[0];
5566 p += offset;
5567 while (offset < BNX2_REGDUMP_LEN) {
5568 *p++ = REG_RD(bp, offset);
5569 offset += 4;
5570 if (offset == reg_boundaries[i + 1]) {
5571 offset = reg_boundaries[i + 2];
5572 p = (u32 *) (orig_p + offset);
5573 i += 2;
5574 }
5575 }
5576}
5577
Michael Chanb6016b72005-05-26 13:03:09 -07005578static void
5579bnx2_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
5580{
Michael Chan972ec0d2006-01-23 16:12:43 -08005581 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07005582
5583 if (bp->flags & NO_WOL_FLAG) {
5584 wol->supported = 0;
5585 wol->wolopts = 0;
5586 }
5587 else {
5588 wol->supported = WAKE_MAGIC;
5589 if (bp->wol)
5590 wol->wolopts = WAKE_MAGIC;
5591 else
5592 wol->wolopts = 0;
5593 }
5594 memset(&wol->sopass, 0, sizeof(wol->sopass));
5595}
5596
5597static int
5598bnx2_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
5599{
Michael Chan972ec0d2006-01-23 16:12:43 -08005600 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07005601
5602 if (wol->wolopts & ~WAKE_MAGIC)
5603 return -EINVAL;
5604
5605 if (wol->wolopts & WAKE_MAGIC) {
5606 if (bp->flags & NO_WOL_FLAG)
5607 return -EINVAL;
5608
5609 bp->wol = 1;
5610 }
5611 else {
5612 bp->wol = 0;
5613 }
5614 return 0;
5615}
5616
5617static int
5618bnx2_nway_reset(struct net_device *dev)
5619{
Michael Chan972ec0d2006-01-23 16:12:43 -08005620 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07005621 u32 bmcr;
5622
5623 if (!(bp->autoneg & AUTONEG_SPEED)) {
5624 return -EINVAL;
5625 }
5626
Michael Chanc770a652005-08-25 15:38:39 -07005627 spin_lock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07005628
Michael Chan7b6b8342007-07-07 22:50:15 -07005629 if (bp->phy_flags & REMOTE_PHY_CAP_FLAG) {
5630 int rc;
5631
5632 rc = bnx2_setup_remote_phy(bp, bp->phy_port);
5633 spin_unlock_bh(&bp->phy_lock);
5634 return rc;
5635 }
5636
Michael Chanb6016b72005-05-26 13:03:09 -07005637 /* Force a link down visible on the other side */
5638 if (bp->phy_flags & PHY_SERDES_FLAG) {
Michael Chanca58c3a2007-05-03 13:22:52 -07005639 bnx2_write_phy(bp, bp->mii_bmcr, BMCR_LOOPBACK);
Michael Chanc770a652005-08-25 15:38:39 -07005640 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07005641
5642 msleep(20);
5643
Michael Chanc770a652005-08-25 15:38:39 -07005644 spin_lock_bh(&bp->phy_lock);
Michael Chanf8dd0642006-11-19 14:08:29 -08005645
5646 bp->current_interval = SERDES_AN_TIMEOUT;
5647 bp->serdes_an_pending = 1;
5648 mod_timer(&bp->timer, jiffies + bp->current_interval);
Michael Chanb6016b72005-05-26 13:03:09 -07005649 }
5650
Michael Chanca58c3a2007-05-03 13:22:52 -07005651 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chanb6016b72005-05-26 13:03:09 -07005652 bmcr &= ~BMCR_LOOPBACK;
Michael Chanca58c3a2007-05-03 13:22:52 -07005653 bnx2_write_phy(bp, bp->mii_bmcr, bmcr | BMCR_ANRESTART | BMCR_ANENABLE);
Michael Chanb6016b72005-05-26 13:03:09 -07005654
Michael Chanc770a652005-08-25 15:38:39 -07005655 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07005656
5657 return 0;
5658}
5659
5660static int
5661bnx2_get_eeprom_len(struct net_device *dev)
5662{
Michael Chan972ec0d2006-01-23 16:12:43 -08005663 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07005664
Michael Chan1122db72006-01-23 16:11:42 -08005665 if (bp->flash_info == NULL)
Michael Chanb6016b72005-05-26 13:03:09 -07005666 return 0;
5667
Michael Chan1122db72006-01-23 16:11:42 -08005668 return (int) bp->flash_size;
Michael Chanb6016b72005-05-26 13:03:09 -07005669}
5670
5671static int
5672bnx2_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
5673 u8 *eebuf)
5674{
Michael Chan972ec0d2006-01-23 16:12:43 -08005675 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07005676 int rc;
5677
John W. Linville1064e942005-11-10 12:58:24 -08005678 /* parameters already validated in ethtool_get_eeprom */
Michael Chanb6016b72005-05-26 13:03:09 -07005679
5680 rc = bnx2_nvram_read(bp, eeprom->offset, eebuf, eeprom->len);
5681
5682 return rc;
5683}
5684
5685static int
5686bnx2_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
5687 u8 *eebuf)
5688{
Michael Chan972ec0d2006-01-23 16:12:43 -08005689 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07005690 int rc;
5691
John W. Linville1064e942005-11-10 12:58:24 -08005692 /* parameters already validated in ethtool_set_eeprom */
Michael Chanb6016b72005-05-26 13:03:09 -07005693
5694 rc = bnx2_nvram_write(bp, eeprom->offset, eebuf, eeprom->len);
5695
5696 return rc;
5697}
5698
5699static int
5700bnx2_get_coalesce(struct net_device *dev, struct ethtool_coalesce *coal)
5701{
Michael Chan972ec0d2006-01-23 16:12:43 -08005702 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07005703
5704 memset(coal, 0, sizeof(struct ethtool_coalesce));
5705
5706 coal->rx_coalesce_usecs = bp->rx_ticks;
5707 coal->rx_max_coalesced_frames = bp->rx_quick_cons_trip;
5708 coal->rx_coalesce_usecs_irq = bp->rx_ticks_int;
5709 coal->rx_max_coalesced_frames_irq = bp->rx_quick_cons_trip_int;
5710
5711 coal->tx_coalesce_usecs = bp->tx_ticks;
5712 coal->tx_max_coalesced_frames = bp->tx_quick_cons_trip;
5713 coal->tx_coalesce_usecs_irq = bp->tx_ticks_int;
5714 coal->tx_max_coalesced_frames_irq = bp->tx_quick_cons_trip_int;
5715
5716 coal->stats_block_coalesce_usecs = bp->stats_ticks;
5717
5718 return 0;
5719}
5720
5721static int
5722bnx2_set_coalesce(struct net_device *dev, struct ethtool_coalesce *coal)
5723{
Michael Chan972ec0d2006-01-23 16:12:43 -08005724 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07005725
5726 bp->rx_ticks = (u16) coal->rx_coalesce_usecs;
5727 if (bp->rx_ticks > 0x3ff) bp->rx_ticks = 0x3ff;
5728
Jeff Garzik6aa20a22006-09-13 13:24:59 -04005729 bp->rx_quick_cons_trip = (u16) coal->rx_max_coalesced_frames;
Michael Chanb6016b72005-05-26 13:03:09 -07005730 if (bp->rx_quick_cons_trip > 0xff) bp->rx_quick_cons_trip = 0xff;
5731
5732 bp->rx_ticks_int = (u16) coal->rx_coalesce_usecs_irq;
5733 if (bp->rx_ticks_int > 0x3ff) bp->rx_ticks_int = 0x3ff;
5734
5735 bp->rx_quick_cons_trip_int = (u16) coal->rx_max_coalesced_frames_irq;
5736 if (bp->rx_quick_cons_trip_int > 0xff)
5737 bp->rx_quick_cons_trip_int = 0xff;
5738
5739 bp->tx_ticks = (u16) coal->tx_coalesce_usecs;
5740 if (bp->tx_ticks > 0x3ff) bp->tx_ticks = 0x3ff;
5741
5742 bp->tx_quick_cons_trip = (u16) coal->tx_max_coalesced_frames;
5743 if (bp->tx_quick_cons_trip > 0xff) bp->tx_quick_cons_trip = 0xff;
5744
5745 bp->tx_ticks_int = (u16) coal->tx_coalesce_usecs_irq;
5746 if (bp->tx_ticks_int > 0x3ff) bp->tx_ticks_int = 0x3ff;
5747
5748 bp->tx_quick_cons_trip_int = (u16) coal->tx_max_coalesced_frames_irq;
5749 if (bp->tx_quick_cons_trip_int > 0xff) bp->tx_quick_cons_trip_int =
5750 0xff;
5751
5752 bp->stats_ticks = coal->stats_block_coalesce_usecs;
Michael Chan02537b062007-06-04 21:24:07 -07005753 if (CHIP_NUM(bp) == CHIP_NUM_5708) {
5754 if (bp->stats_ticks != 0 && bp->stats_ticks != USEC_PER_SEC)
5755 bp->stats_ticks = USEC_PER_SEC;
5756 }
Michael Chan7ea69202007-07-16 18:27:10 -07005757 if (bp->stats_ticks > BNX2_HC_STATS_TICKS_HC_STAT_TICKS)
5758 bp->stats_ticks = BNX2_HC_STATS_TICKS_HC_STAT_TICKS;
5759 bp->stats_ticks &= BNX2_HC_STATS_TICKS_HC_STAT_TICKS;
Michael Chanb6016b72005-05-26 13:03:09 -07005760
5761 if (netif_running(bp->dev)) {
5762 bnx2_netif_stop(bp);
5763 bnx2_init_nic(bp);
5764 bnx2_netif_start(bp);
5765 }
5766
5767 return 0;
5768}
5769
5770static void
5771bnx2_get_ringparam(struct net_device *dev, struct ethtool_ringparam *ering)
5772{
Michael Chan972ec0d2006-01-23 16:12:43 -08005773 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07005774
Michael Chan13daffa2006-03-20 17:49:20 -08005775 ering->rx_max_pending = MAX_TOTAL_RX_DESC_CNT;
Michael Chanb6016b72005-05-26 13:03:09 -07005776 ering->rx_mini_max_pending = 0;
5777 ering->rx_jumbo_max_pending = 0;
5778
5779 ering->rx_pending = bp->rx_ring_size;
5780 ering->rx_mini_pending = 0;
5781 ering->rx_jumbo_pending = 0;
5782
5783 ering->tx_max_pending = MAX_TX_DESC_CNT;
5784 ering->tx_pending = bp->tx_ring_size;
5785}
5786
5787static int
5788bnx2_set_ringparam(struct net_device *dev, struct ethtool_ringparam *ering)
5789{
Michael Chan972ec0d2006-01-23 16:12:43 -08005790 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07005791
Michael Chan13daffa2006-03-20 17:49:20 -08005792 if ((ering->rx_pending > MAX_TOTAL_RX_DESC_CNT) ||
Michael Chanb6016b72005-05-26 13:03:09 -07005793 (ering->tx_pending > MAX_TX_DESC_CNT) ||
5794 (ering->tx_pending <= MAX_SKB_FRAGS)) {
5795
5796 return -EINVAL;
5797 }
Michael Chan13daffa2006-03-20 17:49:20 -08005798 if (netif_running(bp->dev)) {
5799 bnx2_netif_stop(bp);
5800 bnx2_reset_chip(bp, BNX2_DRV_MSG_CODE_RESET);
5801 bnx2_free_skbs(bp);
5802 bnx2_free_mem(bp);
5803 }
5804
5805 bnx2_set_rx_ring_size(bp, ering->rx_pending);
Michael Chanb6016b72005-05-26 13:03:09 -07005806 bp->tx_ring_size = ering->tx_pending;
5807
5808 if (netif_running(bp->dev)) {
Michael Chan13daffa2006-03-20 17:49:20 -08005809 int rc;
5810
5811 rc = bnx2_alloc_mem(bp);
5812 if (rc)
5813 return rc;
Michael Chanb6016b72005-05-26 13:03:09 -07005814 bnx2_init_nic(bp);
5815 bnx2_netif_start(bp);
5816 }
5817
5818 return 0;
5819}
5820
5821static void
5822bnx2_get_pauseparam(struct net_device *dev, struct ethtool_pauseparam *epause)
5823{
Michael Chan972ec0d2006-01-23 16:12:43 -08005824 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07005825
5826 epause->autoneg = ((bp->autoneg & AUTONEG_FLOW_CTRL) != 0);
5827 epause->rx_pause = ((bp->flow_ctrl & FLOW_CTRL_RX) != 0);
5828 epause->tx_pause = ((bp->flow_ctrl & FLOW_CTRL_TX) != 0);
5829}
5830
5831static int
5832bnx2_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam *epause)
5833{
Michael Chan972ec0d2006-01-23 16:12:43 -08005834 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07005835
5836 bp->req_flow_ctrl = 0;
5837 if (epause->rx_pause)
5838 bp->req_flow_ctrl |= FLOW_CTRL_RX;
5839 if (epause->tx_pause)
5840 bp->req_flow_ctrl |= FLOW_CTRL_TX;
5841
5842 if (epause->autoneg) {
5843 bp->autoneg |= AUTONEG_FLOW_CTRL;
5844 }
5845 else {
5846 bp->autoneg &= ~AUTONEG_FLOW_CTRL;
5847 }
5848
Michael Chanc770a652005-08-25 15:38:39 -07005849 spin_lock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07005850
Michael Chan0d8a6572007-07-07 22:49:43 -07005851 bnx2_setup_phy(bp, bp->phy_port);
Michael Chanb6016b72005-05-26 13:03:09 -07005852
Michael Chanc770a652005-08-25 15:38:39 -07005853 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07005854
5855 return 0;
5856}
5857
5858static u32
5859bnx2_get_rx_csum(struct net_device *dev)
5860{
Michael Chan972ec0d2006-01-23 16:12:43 -08005861 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07005862
5863 return bp->rx_csum;
5864}
5865
5866static int
5867bnx2_set_rx_csum(struct net_device *dev, u32 data)
5868{
Michael Chan972ec0d2006-01-23 16:12:43 -08005869 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07005870
5871 bp->rx_csum = data;
5872 return 0;
5873}
5874
Michael Chanb11d6212006-06-29 12:31:21 -07005875static int
5876bnx2_set_tso(struct net_device *dev, u32 data)
5877{
Michael Chan4666f872007-05-03 13:22:28 -07005878 struct bnx2 *bp = netdev_priv(dev);
5879
5880 if (data) {
Michael Chanb11d6212006-06-29 12:31:21 -07005881 dev->features |= NETIF_F_TSO | NETIF_F_TSO_ECN;
Michael Chan4666f872007-05-03 13:22:28 -07005882 if (CHIP_NUM(bp) == CHIP_NUM_5709)
5883 dev->features |= NETIF_F_TSO6;
5884 } else
5885 dev->features &= ~(NETIF_F_TSO | NETIF_F_TSO6 |
5886 NETIF_F_TSO_ECN);
Michael Chanb11d6212006-06-29 12:31:21 -07005887 return 0;
5888}
5889
Michael Chancea94db2006-06-12 22:16:13 -07005890#define BNX2_NUM_STATS 46
Michael Chanb6016b72005-05-26 13:03:09 -07005891
Peter Hagervall14ab9b82005-08-10 14:18:16 -07005892static struct {
Michael Chanb6016b72005-05-26 13:03:09 -07005893 char string[ETH_GSTRING_LEN];
5894} bnx2_stats_str_arr[BNX2_NUM_STATS] = {
5895 { "rx_bytes" },
5896 { "rx_error_bytes" },
5897 { "tx_bytes" },
5898 { "tx_error_bytes" },
5899 { "rx_ucast_packets" },
5900 { "rx_mcast_packets" },
5901 { "rx_bcast_packets" },
5902 { "tx_ucast_packets" },
5903 { "tx_mcast_packets" },
5904 { "tx_bcast_packets" },
5905 { "tx_mac_errors" },
5906 { "tx_carrier_errors" },
5907 { "rx_crc_errors" },
5908 { "rx_align_errors" },
5909 { "tx_single_collisions" },
5910 { "tx_multi_collisions" },
5911 { "tx_deferred" },
5912 { "tx_excess_collisions" },
5913 { "tx_late_collisions" },
5914 { "tx_total_collisions" },
5915 { "rx_fragments" },
5916 { "rx_jabbers" },
5917 { "rx_undersize_packets" },
5918 { "rx_oversize_packets" },
5919 { "rx_64_byte_packets" },
5920 { "rx_65_to_127_byte_packets" },
5921 { "rx_128_to_255_byte_packets" },
5922 { "rx_256_to_511_byte_packets" },
5923 { "rx_512_to_1023_byte_packets" },
5924 { "rx_1024_to_1522_byte_packets" },
5925 { "rx_1523_to_9022_byte_packets" },
5926 { "tx_64_byte_packets" },
5927 { "tx_65_to_127_byte_packets" },
5928 { "tx_128_to_255_byte_packets" },
5929 { "tx_256_to_511_byte_packets" },
5930 { "tx_512_to_1023_byte_packets" },
5931 { "tx_1024_to_1522_byte_packets" },
5932 { "tx_1523_to_9022_byte_packets" },
5933 { "rx_xon_frames" },
5934 { "rx_xoff_frames" },
5935 { "tx_xon_frames" },
5936 { "tx_xoff_frames" },
5937 { "rx_mac_ctrl_frames" },
5938 { "rx_filtered_packets" },
5939 { "rx_discards" },
Michael Chancea94db2006-06-12 22:16:13 -07005940 { "rx_fw_discards" },
Michael Chanb6016b72005-05-26 13:03:09 -07005941};
5942
5943#define STATS_OFFSET32(offset_name) (offsetof(struct statistics_block, offset_name) / 4)
5944
Arjan van de Venf71e1302006-03-03 21:33:57 -05005945static const unsigned long bnx2_stats_offset_arr[BNX2_NUM_STATS] = {
Michael Chanb6016b72005-05-26 13:03:09 -07005946 STATS_OFFSET32(stat_IfHCInOctets_hi),
5947 STATS_OFFSET32(stat_IfHCInBadOctets_hi),
5948 STATS_OFFSET32(stat_IfHCOutOctets_hi),
5949 STATS_OFFSET32(stat_IfHCOutBadOctets_hi),
5950 STATS_OFFSET32(stat_IfHCInUcastPkts_hi),
5951 STATS_OFFSET32(stat_IfHCInMulticastPkts_hi),
5952 STATS_OFFSET32(stat_IfHCInBroadcastPkts_hi),
5953 STATS_OFFSET32(stat_IfHCOutUcastPkts_hi),
5954 STATS_OFFSET32(stat_IfHCOutMulticastPkts_hi),
5955 STATS_OFFSET32(stat_IfHCOutBroadcastPkts_hi),
5956 STATS_OFFSET32(stat_emac_tx_stat_dot3statsinternalmactransmiterrors),
Jeff Garzik6aa20a22006-09-13 13:24:59 -04005957 STATS_OFFSET32(stat_Dot3StatsCarrierSenseErrors),
5958 STATS_OFFSET32(stat_Dot3StatsFCSErrors),
5959 STATS_OFFSET32(stat_Dot3StatsAlignmentErrors),
5960 STATS_OFFSET32(stat_Dot3StatsSingleCollisionFrames),
5961 STATS_OFFSET32(stat_Dot3StatsMultipleCollisionFrames),
5962 STATS_OFFSET32(stat_Dot3StatsDeferredTransmissions),
5963 STATS_OFFSET32(stat_Dot3StatsExcessiveCollisions),
5964 STATS_OFFSET32(stat_Dot3StatsLateCollisions),
5965 STATS_OFFSET32(stat_EtherStatsCollisions),
5966 STATS_OFFSET32(stat_EtherStatsFragments),
5967 STATS_OFFSET32(stat_EtherStatsJabbers),
5968 STATS_OFFSET32(stat_EtherStatsUndersizePkts),
5969 STATS_OFFSET32(stat_EtherStatsOverrsizePkts),
5970 STATS_OFFSET32(stat_EtherStatsPktsRx64Octets),
5971 STATS_OFFSET32(stat_EtherStatsPktsRx65Octetsto127Octets),
5972 STATS_OFFSET32(stat_EtherStatsPktsRx128Octetsto255Octets),
5973 STATS_OFFSET32(stat_EtherStatsPktsRx256Octetsto511Octets),
5974 STATS_OFFSET32(stat_EtherStatsPktsRx512Octetsto1023Octets),
5975 STATS_OFFSET32(stat_EtherStatsPktsRx1024Octetsto1522Octets),
5976 STATS_OFFSET32(stat_EtherStatsPktsRx1523Octetsto9022Octets),
5977 STATS_OFFSET32(stat_EtherStatsPktsTx64Octets),
5978 STATS_OFFSET32(stat_EtherStatsPktsTx65Octetsto127Octets),
5979 STATS_OFFSET32(stat_EtherStatsPktsTx128Octetsto255Octets),
5980 STATS_OFFSET32(stat_EtherStatsPktsTx256Octetsto511Octets),
5981 STATS_OFFSET32(stat_EtherStatsPktsTx512Octetsto1023Octets),
5982 STATS_OFFSET32(stat_EtherStatsPktsTx1024Octetsto1522Octets),
5983 STATS_OFFSET32(stat_EtherStatsPktsTx1523Octetsto9022Octets),
5984 STATS_OFFSET32(stat_XonPauseFramesReceived),
5985 STATS_OFFSET32(stat_XoffPauseFramesReceived),
5986 STATS_OFFSET32(stat_OutXonSent),
5987 STATS_OFFSET32(stat_OutXoffSent),
5988 STATS_OFFSET32(stat_MacControlFramesReceived),
5989 STATS_OFFSET32(stat_IfInFramesL2FilterDiscards),
5990 STATS_OFFSET32(stat_IfInMBUFDiscards),
Michael Chancea94db2006-06-12 22:16:13 -07005991 STATS_OFFSET32(stat_FwRxDrop),
Michael Chanb6016b72005-05-26 13:03:09 -07005992};
5993
5994/* stat_IfHCInBadOctets and stat_Dot3StatsCarrierSenseErrors are
5995 * skipped because of errata.
Jeff Garzik6aa20a22006-09-13 13:24:59 -04005996 */
Peter Hagervall14ab9b82005-08-10 14:18:16 -07005997static u8 bnx2_5706_stats_len_arr[BNX2_NUM_STATS] = {
Michael Chanb6016b72005-05-26 13:03:09 -07005998 8,0,8,8,8,8,8,8,8,8,
5999 4,0,4,4,4,4,4,4,4,4,
6000 4,4,4,4,4,4,4,4,4,4,
6001 4,4,4,4,4,4,4,4,4,4,
Michael Chancea94db2006-06-12 22:16:13 -07006002 4,4,4,4,4,4,
Michael Chanb6016b72005-05-26 13:03:09 -07006003};
6004
Michael Chan5b0c76a2005-11-04 08:45:49 -08006005static u8 bnx2_5708_stats_len_arr[BNX2_NUM_STATS] = {
6006 8,0,8,8,8,8,8,8,8,8,
6007 4,4,4,4,4,4,4,4,4,4,
6008 4,4,4,4,4,4,4,4,4,4,
6009 4,4,4,4,4,4,4,4,4,4,
Michael Chancea94db2006-06-12 22:16:13 -07006010 4,4,4,4,4,4,
Michael Chan5b0c76a2005-11-04 08:45:49 -08006011};
6012
Michael Chanb6016b72005-05-26 13:03:09 -07006013#define BNX2_NUM_TESTS 6
6014
Peter Hagervall14ab9b82005-08-10 14:18:16 -07006015static struct {
Michael Chanb6016b72005-05-26 13:03:09 -07006016 char string[ETH_GSTRING_LEN];
6017} bnx2_tests_str_arr[BNX2_NUM_TESTS] = {
6018 { "register_test (offline)" },
6019 { "memory_test (offline)" },
6020 { "loopback_test (offline)" },
6021 { "nvram_test (online)" },
6022 { "interrupt_test (online)" },
6023 { "link_test (online)" },
6024};
6025
6026static int
Jeff Garzikb9f2c042007-10-03 18:07:32 -07006027bnx2_get_sset_count(struct net_device *dev, int sset)
Michael Chanb6016b72005-05-26 13:03:09 -07006028{
Jeff Garzikb9f2c042007-10-03 18:07:32 -07006029 switch (sset) {
6030 case ETH_SS_TEST:
6031 return BNX2_NUM_TESTS;
6032 case ETH_SS_STATS:
6033 return BNX2_NUM_STATS;
6034 default:
6035 return -EOPNOTSUPP;
6036 }
Michael Chanb6016b72005-05-26 13:03:09 -07006037}
6038
6039static void
6040bnx2_self_test(struct net_device *dev, struct ethtool_test *etest, u64 *buf)
6041{
Michael Chan972ec0d2006-01-23 16:12:43 -08006042 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006043
6044 memset(buf, 0, sizeof(u64) * BNX2_NUM_TESTS);
6045 if (etest->flags & ETH_TEST_FL_OFFLINE) {
Michael Chan80be4432006-11-19 14:07:28 -08006046 int i;
6047
Michael Chanb6016b72005-05-26 13:03:09 -07006048 bnx2_netif_stop(bp);
6049 bnx2_reset_chip(bp, BNX2_DRV_MSG_CODE_DIAG);
6050 bnx2_free_skbs(bp);
6051
6052 if (bnx2_test_registers(bp) != 0) {
6053 buf[0] = 1;
6054 etest->flags |= ETH_TEST_FL_FAILED;
6055 }
6056 if (bnx2_test_memory(bp) != 0) {
6057 buf[1] = 1;
6058 etest->flags |= ETH_TEST_FL_FAILED;
6059 }
Michael Chanbc5a0692006-01-23 16:13:22 -08006060 if ((buf[2] = bnx2_test_loopback(bp)) != 0)
Michael Chanb6016b72005-05-26 13:03:09 -07006061 etest->flags |= ETH_TEST_FL_FAILED;
Michael Chanb6016b72005-05-26 13:03:09 -07006062
6063 if (!netif_running(bp->dev)) {
6064 bnx2_reset_chip(bp, BNX2_DRV_MSG_CODE_RESET);
6065 }
6066 else {
6067 bnx2_init_nic(bp);
6068 bnx2_netif_start(bp);
6069 }
6070
6071 /* wait for link up */
Michael Chan80be4432006-11-19 14:07:28 -08006072 for (i = 0; i < 7; i++) {
6073 if (bp->link_up)
6074 break;
6075 msleep_interruptible(1000);
6076 }
Michael Chanb6016b72005-05-26 13:03:09 -07006077 }
6078
6079 if (bnx2_test_nvram(bp) != 0) {
6080 buf[3] = 1;
6081 etest->flags |= ETH_TEST_FL_FAILED;
6082 }
6083 if (bnx2_test_intr(bp) != 0) {
6084 buf[4] = 1;
6085 etest->flags |= ETH_TEST_FL_FAILED;
6086 }
6087
6088 if (bnx2_test_link(bp) != 0) {
6089 buf[5] = 1;
6090 etest->flags |= ETH_TEST_FL_FAILED;
6091
6092 }
6093}
6094
6095static void
6096bnx2_get_strings(struct net_device *dev, u32 stringset, u8 *buf)
6097{
6098 switch (stringset) {
6099 case ETH_SS_STATS:
6100 memcpy(buf, bnx2_stats_str_arr,
6101 sizeof(bnx2_stats_str_arr));
6102 break;
6103 case ETH_SS_TEST:
6104 memcpy(buf, bnx2_tests_str_arr,
6105 sizeof(bnx2_tests_str_arr));
6106 break;
6107 }
6108}
6109
Michael Chanb6016b72005-05-26 13:03:09 -07006110static void
6111bnx2_get_ethtool_stats(struct net_device *dev,
6112 struct ethtool_stats *stats, u64 *buf)
6113{
Michael Chan972ec0d2006-01-23 16:12:43 -08006114 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006115 int i;
6116 u32 *hw_stats = (u32 *) bp->stats_blk;
Peter Hagervall14ab9b82005-08-10 14:18:16 -07006117 u8 *stats_len_arr = NULL;
Michael Chanb6016b72005-05-26 13:03:09 -07006118
6119 if (hw_stats == NULL) {
6120 memset(buf, 0, sizeof(u64) * BNX2_NUM_STATS);
6121 return;
6122 }
6123
Michael Chan5b0c76a2005-11-04 08:45:49 -08006124 if ((CHIP_ID(bp) == CHIP_ID_5706_A0) ||
6125 (CHIP_ID(bp) == CHIP_ID_5706_A1) ||
6126 (CHIP_ID(bp) == CHIP_ID_5706_A2) ||
6127 (CHIP_ID(bp) == CHIP_ID_5708_A0))
Michael Chanb6016b72005-05-26 13:03:09 -07006128 stats_len_arr = bnx2_5706_stats_len_arr;
Michael Chan5b0c76a2005-11-04 08:45:49 -08006129 else
6130 stats_len_arr = bnx2_5708_stats_len_arr;
Michael Chanb6016b72005-05-26 13:03:09 -07006131
6132 for (i = 0; i < BNX2_NUM_STATS; i++) {
6133 if (stats_len_arr[i] == 0) {
6134 /* skip this counter */
6135 buf[i] = 0;
6136 continue;
6137 }
6138 if (stats_len_arr[i] == 4) {
6139 /* 4-byte counter */
6140 buf[i] = (u64)
6141 *(hw_stats + bnx2_stats_offset_arr[i]);
6142 continue;
6143 }
6144 /* 8-byte counter */
6145 buf[i] = (((u64) *(hw_stats +
6146 bnx2_stats_offset_arr[i])) << 32) +
6147 *(hw_stats + bnx2_stats_offset_arr[i] + 1);
6148 }
6149}
6150
6151static int
6152bnx2_phys_id(struct net_device *dev, u32 data)
6153{
Michael Chan972ec0d2006-01-23 16:12:43 -08006154 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006155 int i;
6156 u32 save;
6157
6158 if (data == 0)
6159 data = 2;
6160
6161 save = REG_RD(bp, BNX2_MISC_CFG);
6162 REG_WR(bp, BNX2_MISC_CFG, BNX2_MISC_CFG_LEDMODE_MAC);
6163
6164 for (i = 0; i < (data * 2); i++) {
6165 if ((i % 2) == 0) {
6166 REG_WR(bp, BNX2_EMAC_LED, BNX2_EMAC_LED_OVERRIDE);
6167 }
6168 else {
6169 REG_WR(bp, BNX2_EMAC_LED, BNX2_EMAC_LED_OVERRIDE |
6170 BNX2_EMAC_LED_1000MB_OVERRIDE |
6171 BNX2_EMAC_LED_100MB_OVERRIDE |
6172 BNX2_EMAC_LED_10MB_OVERRIDE |
6173 BNX2_EMAC_LED_TRAFFIC_OVERRIDE |
6174 BNX2_EMAC_LED_TRAFFIC);
6175 }
6176 msleep_interruptible(500);
6177 if (signal_pending(current))
6178 break;
6179 }
6180 REG_WR(bp, BNX2_EMAC_LED, 0);
6181 REG_WR(bp, BNX2_MISC_CFG, save);
6182 return 0;
6183}
6184
Michael Chan4666f872007-05-03 13:22:28 -07006185static int
6186bnx2_set_tx_csum(struct net_device *dev, u32 data)
6187{
6188 struct bnx2 *bp = netdev_priv(dev);
6189
6190 if (CHIP_NUM(bp) == CHIP_NUM_5709)
Michael Chan6460d942007-07-14 19:07:52 -07006191 return (ethtool_op_set_tx_ipv6_csum(dev, data));
Michael Chan4666f872007-05-03 13:22:28 -07006192 else
6193 return (ethtool_op_set_tx_csum(dev, data));
6194}
6195
Jeff Garzik7282d492006-09-13 14:30:00 -04006196static const struct ethtool_ops bnx2_ethtool_ops = {
Michael Chanb6016b72005-05-26 13:03:09 -07006197 .get_settings = bnx2_get_settings,
6198 .set_settings = bnx2_set_settings,
6199 .get_drvinfo = bnx2_get_drvinfo,
Michael Chan244ac4f2006-03-20 17:48:46 -08006200 .get_regs_len = bnx2_get_regs_len,
6201 .get_regs = bnx2_get_regs,
Michael Chanb6016b72005-05-26 13:03:09 -07006202 .get_wol = bnx2_get_wol,
6203 .set_wol = bnx2_set_wol,
6204 .nway_reset = bnx2_nway_reset,
6205 .get_link = ethtool_op_get_link,
6206 .get_eeprom_len = bnx2_get_eeprom_len,
6207 .get_eeprom = bnx2_get_eeprom,
6208 .set_eeprom = bnx2_set_eeprom,
6209 .get_coalesce = bnx2_get_coalesce,
6210 .set_coalesce = bnx2_set_coalesce,
6211 .get_ringparam = bnx2_get_ringparam,
6212 .set_ringparam = bnx2_set_ringparam,
6213 .get_pauseparam = bnx2_get_pauseparam,
6214 .set_pauseparam = bnx2_set_pauseparam,
6215 .get_rx_csum = bnx2_get_rx_csum,
6216 .set_rx_csum = bnx2_set_rx_csum,
Michael Chan4666f872007-05-03 13:22:28 -07006217 .set_tx_csum = bnx2_set_tx_csum,
Michael Chanb6016b72005-05-26 13:03:09 -07006218 .set_sg = ethtool_op_set_sg,
Michael Chanb11d6212006-06-29 12:31:21 -07006219 .set_tso = bnx2_set_tso,
Michael Chanb6016b72005-05-26 13:03:09 -07006220 .self_test = bnx2_self_test,
6221 .get_strings = bnx2_get_strings,
6222 .phys_id = bnx2_phys_id,
Michael Chanb6016b72005-05-26 13:03:09 -07006223 .get_ethtool_stats = bnx2_get_ethtool_stats,
Jeff Garzikb9f2c042007-10-03 18:07:32 -07006224 .get_sset_count = bnx2_get_sset_count,
Michael Chanb6016b72005-05-26 13:03:09 -07006225};
6226
6227/* Called with rtnl_lock */
6228static int
6229bnx2_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
6230{
Peter Hagervall14ab9b82005-08-10 14:18:16 -07006231 struct mii_ioctl_data *data = if_mii(ifr);
Michael Chan972ec0d2006-01-23 16:12:43 -08006232 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006233 int err;
6234
6235 switch(cmd) {
6236 case SIOCGMIIPHY:
6237 data->phy_id = bp->phy_addr;
6238
6239 /* fallthru */
6240 case SIOCGMIIREG: {
6241 u32 mii_regval;
6242
Michael Chan7b6b8342007-07-07 22:50:15 -07006243 if (bp->phy_flags & REMOTE_PHY_CAP_FLAG)
6244 return -EOPNOTSUPP;
6245
Michael Chandad3e452007-05-03 13:18:03 -07006246 if (!netif_running(dev))
6247 return -EAGAIN;
6248
Michael Chanc770a652005-08-25 15:38:39 -07006249 spin_lock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07006250 err = bnx2_read_phy(bp, data->reg_num & 0x1f, &mii_regval);
Michael Chanc770a652005-08-25 15:38:39 -07006251 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07006252
6253 data->val_out = mii_regval;
6254
6255 return err;
6256 }
6257
6258 case SIOCSMIIREG:
6259 if (!capable(CAP_NET_ADMIN))
6260 return -EPERM;
6261
Michael Chan7b6b8342007-07-07 22:50:15 -07006262 if (bp->phy_flags & REMOTE_PHY_CAP_FLAG)
6263 return -EOPNOTSUPP;
6264
Michael Chandad3e452007-05-03 13:18:03 -07006265 if (!netif_running(dev))
6266 return -EAGAIN;
6267
Michael Chanc770a652005-08-25 15:38:39 -07006268 spin_lock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07006269 err = bnx2_write_phy(bp, data->reg_num & 0x1f, data->val_in);
Michael Chanc770a652005-08-25 15:38:39 -07006270 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07006271
6272 return err;
6273
6274 default:
6275 /* do nothing */
6276 break;
6277 }
6278 return -EOPNOTSUPP;
6279}
6280
6281/* Called with rtnl_lock */
6282static int
6283bnx2_change_mac_addr(struct net_device *dev, void *p)
6284{
6285 struct sockaddr *addr = p;
Michael Chan972ec0d2006-01-23 16:12:43 -08006286 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006287
Michael Chan73eef4c2005-08-25 15:39:15 -07006288 if (!is_valid_ether_addr(addr->sa_data))
6289 return -EINVAL;
6290
Michael Chanb6016b72005-05-26 13:03:09 -07006291 memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
6292 if (netif_running(dev))
6293 bnx2_set_mac_addr(bp);
6294
6295 return 0;
6296}
6297
6298/* Called with rtnl_lock */
6299static int
6300bnx2_change_mtu(struct net_device *dev, int new_mtu)
6301{
Michael Chan972ec0d2006-01-23 16:12:43 -08006302 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006303
6304 if (((new_mtu + ETH_HLEN) > MAX_ETHERNET_JUMBO_PACKET_SIZE) ||
6305 ((new_mtu + ETH_HLEN) < MIN_ETHERNET_PACKET_SIZE))
6306 return -EINVAL;
6307
6308 dev->mtu = new_mtu;
6309 if (netif_running(dev)) {
6310 bnx2_netif_stop(bp);
6311
6312 bnx2_init_nic(bp);
6313
6314 bnx2_netif_start(bp);
6315 }
6316 return 0;
6317}
6318
6319#if defined(HAVE_POLL_CONTROLLER) || defined(CONFIG_NET_POLL_CONTROLLER)
6320static void
6321poll_bnx2(struct net_device *dev)
6322{
Michael Chan972ec0d2006-01-23 16:12:43 -08006323 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006324
6325 disable_irq(bp->pdev->irq);
David Howells7d12e782006-10-05 14:55:46 +01006326 bnx2_interrupt(bp->pdev->irq, dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006327 enable_irq(bp->pdev->irq);
6328}
6329#endif
6330
Michael Chan253c8b72007-01-08 19:56:01 -08006331static void __devinit
6332bnx2_get_5709_media(struct bnx2 *bp)
6333{
6334 u32 val = REG_RD(bp, BNX2_MISC_DUAL_MEDIA_CTRL);
6335 u32 bond_id = val & BNX2_MISC_DUAL_MEDIA_CTRL_BOND_ID;
6336 u32 strap;
6337
6338 if (bond_id == BNX2_MISC_DUAL_MEDIA_CTRL_BOND_ID_C)
6339 return;
6340 else if (bond_id == BNX2_MISC_DUAL_MEDIA_CTRL_BOND_ID_S) {
6341 bp->phy_flags |= PHY_SERDES_FLAG;
6342 return;
6343 }
6344
6345 if (val & BNX2_MISC_DUAL_MEDIA_CTRL_STRAP_OVERRIDE)
6346 strap = (val & BNX2_MISC_DUAL_MEDIA_CTRL_PHY_CTRL) >> 21;
6347 else
6348 strap = (val & BNX2_MISC_DUAL_MEDIA_CTRL_PHY_CTRL_STRAP) >> 8;
6349
6350 if (PCI_FUNC(bp->pdev->devfn) == 0) {
6351 switch (strap) {
6352 case 0x4:
6353 case 0x5:
6354 case 0x6:
6355 bp->phy_flags |= PHY_SERDES_FLAG;
6356 return;
6357 }
6358 } else {
6359 switch (strap) {
6360 case 0x1:
6361 case 0x2:
6362 case 0x4:
6363 bp->phy_flags |= PHY_SERDES_FLAG;
6364 return;
6365 }
6366 }
6367}
6368
Michael Chan883e5152007-05-03 13:25:11 -07006369static void __devinit
6370bnx2_get_pci_speed(struct bnx2 *bp)
6371{
6372 u32 reg;
6373
6374 reg = REG_RD(bp, BNX2_PCICFG_MISC_STATUS);
6375 if (reg & BNX2_PCICFG_MISC_STATUS_PCIX_DET) {
6376 u32 clkreg;
6377
6378 bp->flags |= PCIX_FLAG;
6379
6380 clkreg = REG_RD(bp, BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS);
6381
6382 clkreg &= BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET;
6383 switch (clkreg) {
6384 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_133MHZ:
6385 bp->bus_speed_mhz = 133;
6386 break;
6387
6388 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_95MHZ:
6389 bp->bus_speed_mhz = 100;
6390 break;
6391
6392 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_66MHZ:
6393 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_80MHZ:
6394 bp->bus_speed_mhz = 66;
6395 break;
6396
6397 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_48MHZ:
6398 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_55MHZ:
6399 bp->bus_speed_mhz = 50;
6400 break;
6401
6402 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_LOW:
6403 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_32MHZ:
6404 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_38MHZ:
6405 bp->bus_speed_mhz = 33;
6406 break;
6407 }
6408 }
6409 else {
6410 if (reg & BNX2_PCICFG_MISC_STATUS_M66EN)
6411 bp->bus_speed_mhz = 66;
6412 else
6413 bp->bus_speed_mhz = 33;
6414 }
6415
6416 if (reg & BNX2_PCICFG_MISC_STATUS_32BIT_DET)
6417 bp->flags |= PCI_32BIT_FLAG;
6418
6419}
6420
Michael Chanb6016b72005-05-26 13:03:09 -07006421static int __devinit
6422bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
6423{
6424 struct bnx2 *bp;
6425 unsigned long mem_len;
Michael Chan58fc2ea2007-07-07 22:52:02 -07006426 int rc, i, j;
Michael Chanb6016b72005-05-26 13:03:09 -07006427 u32 reg;
Michael Chan40453c82007-05-03 13:19:18 -07006428 u64 dma_mask, persist_dma_mask;
Michael Chanb6016b72005-05-26 13:03:09 -07006429
Michael Chanb6016b72005-05-26 13:03:09 -07006430 SET_NETDEV_DEV(dev, &pdev->dev);
Michael Chan972ec0d2006-01-23 16:12:43 -08006431 bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006432
6433 bp->flags = 0;
6434 bp->phy_flags = 0;
6435
6436 /* enable device (incl. PCI PM wakeup), and bus-mastering */
6437 rc = pci_enable_device(pdev);
6438 if (rc) {
Jeff Garzik9b91cf92006-06-27 11:39:50 -04006439 dev_err(&pdev->dev, "Cannot enable PCI device, aborting.");
Michael Chanb6016b72005-05-26 13:03:09 -07006440 goto err_out;
6441 }
6442
6443 if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) {
Jeff Garzik9b91cf92006-06-27 11:39:50 -04006444 dev_err(&pdev->dev,
Jeff Garzik2e8a5382006-06-27 10:47:51 -04006445 "Cannot find PCI device base address, aborting.\n");
Michael Chanb6016b72005-05-26 13:03:09 -07006446 rc = -ENODEV;
6447 goto err_out_disable;
6448 }
6449
6450 rc = pci_request_regions(pdev, DRV_MODULE_NAME);
6451 if (rc) {
Jeff Garzik9b91cf92006-06-27 11:39:50 -04006452 dev_err(&pdev->dev, "Cannot obtain PCI resources, aborting.\n");
Michael Chanb6016b72005-05-26 13:03:09 -07006453 goto err_out_disable;
6454 }
6455
6456 pci_set_master(pdev);
6457
6458 bp->pm_cap = pci_find_capability(pdev, PCI_CAP_ID_PM);
6459 if (bp->pm_cap == 0) {
Jeff Garzik9b91cf92006-06-27 11:39:50 -04006460 dev_err(&pdev->dev,
Jeff Garzik2e8a5382006-06-27 10:47:51 -04006461 "Cannot find power management capability, aborting.\n");
Michael Chanb6016b72005-05-26 13:03:09 -07006462 rc = -EIO;
6463 goto err_out_release;
6464 }
6465
Michael Chanb6016b72005-05-26 13:03:09 -07006466 bp->dev = dev;
6467 bp->pdev = pdev;
6468
6469 spin_lock_init(&bp->phy_lock);
Michael Chan1b8227c2007-05-03 13:24:05 -07006470 spin_lock_init(&bp->indirect_lock);
David Howellsc4028952006-11-22 14:57:56 +00006471 INIT_WORK(&bp->reset_task, bnx2_reset_task);
Michael Chanb6016b72005-05-26 13:03:09 -07006472
6473 dev->base_addr = dev->mem_start = pci_resource_start(pdev, 0);
Michael Chan59b47d82006-11-19 14:10:45 -08006474 mem_len = MB_GET_CID_ADDR(TX_TSS_CID + 1);
Michael Chanb6016b72005-05-26 13:03:09 -07006475 dev->mem_end = dev->mem_start + mem_len;
6476 dev->irq = pdev->irq;
6477
6478 bp->regview = ioremap_nocache(dev->base_addr, mem_len);
6479
6480 if (!bp->regview) {
Jeff Garzik9b91cf92006-06-27 11:39:50 -04006481 dev_err(&pdev->dev, "Cannot map register space, aborting.\n");
Michael Chanb6016b72005-05-26 13:03:09 -07006482 rc = -ENOMEM;
6483 goto err_out_release;
6484 }
6485
6486 /* Configure byte swap and enable write to the reg_window registers.
6487 * Rely on CPU to do target byte swapping on big endian systems
6488 * The chip's target access swapping will not swap all accesses
6489 */
6490 pci_write_config_dword(bp->pdev, BNX2_PCICFG_MISC_CONFIG,
6491 BNX2_PCICFG_MISC_CONFIG_REG_WINDOW_ENA |
6492 BNX2_PCICFG_MISC_CONFIG_TARGET_MB_WORD_SWAP);
6493
Pavel Machek829ca9a2005-09-03 15:56:56 -07006494 bnx2_set_power_state(bp, PCI_D0);
Michael Chanb6016b72005-05-26 13:03:09 -07006495
6496 bp->chip_id = REG_RD(bp, BNX2_MISC_ID);
6497
Michael Chan883e5152007-05-03 13:25:11 -07006498 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
6499 if (pci_find_capability(pdev, PCI_CAP_ID_EXP) == 0) {
6500 dev_err(&pdev->dev,
6501 "Cannot find PCIE capability, aborting.\n");
6502 rc = -EIO;
6503 goto err_out_unmap;
6504 }
6505 bp->flags |= PCIE_FLAG;
6506 } else {
Michael Chan59b47d82006-11-19 14:10:45 -08006507 bp->pcix_cap = pci_find_capability(pdev, PCI_CAP_ID_PCIX);
6508 if (bp->pcix_cap == 0) {
6509 dev_err(&pdev->dev,
6510 "Cannot find PCIX capability, aborting.\n");
6511 rc = -EIO;
6512 goto err_out_unmap;
6513 }
6514 }
6515
Michael Chan8e6a72c2007-05-03 13:24:48 -07006516 if (CHIP_ID(bp) != CHIP_ID_5706_A0 && CHIP_ID(bp) != CHIP_ID_5706_A1) {
6517 if (pci_find_capability(pdev, PCI_CAP_ID_MSI))
6518 bp->flags |= MSI_CAP_FLAG;
6519 }
6520
Michael Chan40453c82007-05-03 13:19:18 -07006521 /* 5708 cannot support DMA addresses > 40-bit. */
6522 if (CHIP_NUM(bp) == CHIP_NUM_5708)
6523 persist_dma_mask = dma_mask = DMA_40BIT_MASK;
6524 else
6525 persist_dma_mask = dma_mask = DMA_64BIT_MASK;
6526
6527 /* Configure DMA attributes. */
6528 if (pci_set_dma_mask(pdev, dma_mask) == 0) {
6529 dev->features |= NETIF_F_HIGHDMA;
6530 rc = pci_set_consistent_dma_mask(pdev, persist_dma_mask);
6531 if (rc) {
6532 dev_err(&pdev->dev,
6533 "pci_set_consistent_dma_mask failed, aborting.\n");
6534 goto err_out_unmap;
6535 }
6536 } else if ((rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK)) != 0) {
6537 dev_err(&pdev->dev, "System does not support DMA, aborting.\n");
6538 goto err_out_unmap;
6539 }
6540
Michael Chan883e5152007-05-03 13:25:11 -07006541 if (!(bp->flags & PCIE_FLAG))
6542 bnx2_get_pci_speed(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07006543
6544 /* 5706A0 may falsely detect SERR and PERR. */
6545 if (CHIP_ID(bp) == CHIP_ID_5706_A0) {
6546 reg = REG_RD(bp, PCI_COMMAND);
6547 reg &= ~(PCI_COMMAND_SERR | PCI_COMMAND_PARITY);
6548 REG_WR(bp, PCI_COMMAND, reg);
6549 }
6550 else if ((CHIP_ID(bp) == CHIP_ID_5706_A1) &&
6551 !(bp->flags & PCIX_FLAG)) {
6552
Jeff Garzik9b91cf92006-06-27 11:39:50 -04006553 dev_err(&pdev->dev,
Jeff Garzik2e8a5382006-06-27 10:47:51 -04006554 "5706 A1 can only be used in a PCIX bus, aborting.\n");
Michael Chanb6016b72005-05-26 13:03:09 -07006555 goto err_out_unmap;
6556 }
6557
6558 bnx2_init_nvram(bp);
6559
Michael Chane3648b32005-11-04 08:51:21 -08006560 reg = REG_RD_IND(bp, BNX2_SHM_HDR_SIGNATURE);
6561
6562 if ((reg & BNX2_SHM_HDR_SIGNATURE_SIG_MASK) ==
Michael Chan24cb2302007-01-25 15:49:56 -08006563 BNX2_SHM_HDR_SIGNATURE_SIG) {
6564 u32 off = PCI_FUNC(pdev->devfn) << 2;
6565
6566 bp->shmem_base = REG_RD_IND(bp, BNX2_SHM_HDR_ADDR_0 + off);
6567 } else
Michael Chane3648b32005-11-04 08:51:21 -08006568 bp->shmem_base = HOST_VIEW_SHMEM_BASE;
6569
Michael Chanb6016b72005-05-26 13:03:09 -07006570 /* Get the permanent MAC address. First we need to make sure the
6571 * firmware is actually running.
6572 */
Michael Chane3648b32005-11-04 08:51:21 -08006573 reg = REG_RD_IND(bp, bp->shmem_base + BNX2_DEV_INFO_SIGNATURE);
Michael Chanb6016b72005-05-26 13:03:09 -07006574
6575 if ((reg & BNX2_DEV_INFO_SIGNATURE_MAGIC_MASK) !=
6576 BNX2_DEV_INFO_SIGNATURE_MAGIC) {
Jeff Garzik9b91cf92006-06-27 11:39:50 -04006577 dev_err(&pdev->dev, "Firmware not running, aborting.\n");
Michael Chanb6016b72005-05-26 13:03:09 -07006578 rc = -ENODEV;
6579 goto err_out_unmap;
6580 }
6581
Michael Chan58fc2ea2007-07-07 22:52:02 -07006582 reg = REG_RD_IND(bp, bp->shmem_base + BNX2_DEV_INFO_BC_REV);
6583 for (i = 0, j = 0; i < 3; i++) {
6584 u8 num, k, skip0;
6585
6586 num = (u8) (reg >> (24 - (i * 8)));
6587 for (k = 100, skip0 = 1; k >= 1; num %= k, k /= 10) {
6588 if (num >= k || !skip0 || k == 1) {
6589 bp->fw_version[j++] = (num / k) + '0';
6590 skip0 = 0;
6591 }
6592 }
6593 if (i != 2)
6594 bp->fw_version[j++] = '.';
6595 }
Michael Chanc2d3db82007-07-16 18:26:43 -07006596 if (REG_RD_IND(bp, bp->shmem_base + BNX2_PORT_FEATURE) &
6597 BNX2_PORT_FEATURE_ASF_ENABLED) {
6598 bp->flags |= ASF_ENABLE_FLAG;
6599
6600 for (i = 0; i < 30; i++) {
6601 reg = REG_RD_IND(bp, bp->shmem_base +
6602 BNX2_BC_STATE_CONDITION);
6603 if (reg & BNX2_CONDITION_MFW_RUN_MASK)
6604 break;
6605 msleep(10);
6606 }
6607 }
Michael Chan58fc2ea2007-07-07 22:52:02 -07006608 reg = REG_RD_IND(bp, bp->shmem_base + BNX2_BC_STATE_CONDITION);
6609 reg &= BNX2_CONDITION_MFW_RUN_MASK;
6610 if (reg != BNX2_CONDITION_MFW_RUN_UNKNOWN &&
6611 reg != BNX2_CONDITION_MFW_RUN_NONE) {
6612 int i;
6613 u32 addr = REG_RD_IND(bp, bp->shmem_base + BNX2_MFW_VER_PTR);
6614
6615 bp->fw_version[j++] = ' ';
6616 for (i = 0; i < 3; i++) {
6617 reg = REG_RD_IND(bp, addr + i * 4);
6618 reg = swab32(reg);
6619 memcpy(&bp->fw_version[j], &reg, 4);
6620 j += 4;
6621 }
6622 }
Michael Chanb6016b72005-05-26 13:03:09 -07006623
Michael Chane3648b32005-11-04 08:51:21 -08006624 reg = REG_RD_IND(bp, bp->shmem_base + BNX2_PORT_HW_CFG_MAC_UPPER);
Michael Chanb6016b72005-05-26 13:03:09 -07006625 bp->mac_addr[0] = (u8) (reg >> 8);
6626 bp->mac_addr[1] = (u8) reg;
6627
Michael Chane3648b32005-11-04 08:51:21 -08006628 reg = REG_RD_IND(bp, bp->shmem_base + BNX2_PORT_HW_CFG_MAC_LOWER);
Michael Chanb6016b72005-05-26 13:03:09 -07006629 bp->mac_addr[2] = (u8) (reg >> 24);
6630 bp->mac_addr[3] = (u8) (reg >> 16);
6631 bp->mac_addr[4] = (u8) (reg >> 8);
6632 bp->mac_addr[5] = (u8) reg;
6633
6634 bp->tx_ring_size = MAX_TX_DESC_CNT;
Michael Chan932f3772006-08-15 01:39:36 -07006635 bnx2_set_rx_ring_size(bp, 255);
Michael Chanb6016b72005-05-26 13:03:09 -07006636
6637 bp->rx_csum = 1;
6638
6639 bp->rx_offset = sizeof(struct l2_fhdr) + 2;
6640
6641 bp->tx_quick_cons_trip_int = 20;
6642 bp->tx_quick_cons_trip = 20;
6643 bp->tx_ticks_int = 80;
6644 bp->tx_ticks = 80;
Jeff Garzik6aa20a22006-09-13 13:24:59 -04006645
Michael Chanb6016b72005-05-26 13:03:09 -07006646 bp->rx_quick_cons_trip_int = 6;
6647 bp->rx_quick_cons_trip = 6;
6648 bp->rx_ticks_int = 18;
6649 bp->rx_ticks = 18;
6650
Michael Chan7ea69202007-07-16 18:27:10 -07006651 bp->stats_ticks = USEC_PER_SEC & BNX2_HC_STATS_TICKS_HC_STAT_TICKS;
Michael Chanb6016b72005-05-26 13:03:09 -07006652
6653 bp->timer_interval = HZ;
Michael Chancd339a02005-08-25 15:35:24 -07006654 bp->current_interval = HZ;
Michael Chanb6016b72005-05-26 13:03:09 -07006655
Michael Chan5b0c76a2005-11-04 08:45:49 -08006656 bp->phy_addr = 1;
6657
Michael Chanb6016b72005-05-26 13:03:09 -07006658 /* Disable WOL support if we are running on a SERDES chip. */
Michael Chan253c8b72007-01-08 19:56:01 -08006659 if (CHIP_NUM(bp) == CHIP_NUM_5709)
6660 bnx2_get_5709_media(bp);
6661 else if (CHIP_BOND_ID(bp) & CHIP_BOND_ID_SERDES_BIT)
Michael Chanb6016b72005-05-26 13:03:09 -07006662 bp->phy_flags |= PHY_SERDES_FLAG;
Michael Chanbac0dff2006-11-19 14:15:05 -08006663
Michael Chan0d8a6572007-07-07 22:49:43 -07006664 bp->phy_port = PORT_TP;
Michael Chanbac0dff2006-11-19 14:15:05 -08006665 if (bp->phy_flags & PHY_SERDES_FLAG) {
Michael Chan0d8a6572007-07-07 22:49:43 -07006666 bp->phy_port = PORT_FIBRE;
Michael Chanb6016b72005-05-26 13:03:09 -07006667 bp->flags |= NO_WOL_FLAG;
Michael Chanbac0dff2006-11-19 14:15:05 -08006668 if (CHIP_NUM(bp) != CHIP_NUM_5706) {
Michael Chan5b0c76a2005-11-04 08:45:49 -08006669 bp->phy_addr = 2;
Michael Chane3648b32005-11-04 08:51:21 -08006670 reg = REG_RD_IND(bp, bp->shmem_base +
Michael Chan5b0c76a2005-11-04 08:45:49 -08006671 BNX2_SHARED_HW_CFG_CONFIG);
6672 if (reg & BNX2_SHARED_HW_CFG_PHY_2_5G)
6673 bp->phy_flags |= PHY_2_5G_CAPABLE_FLAG;
6674 }
Michael Chan0d8a6572007-07-07 22:49:43 -07006675 bnx2_init_remote_phy(bp);
6676
Michael Chan261dd5c2007-01-08 19:55:46 -08006677 } else if (CHIP_NUM(bp) == CHIP_NUM_5706 ||
6678 CHIP_NUM(bp) == CHIP_NUM_5708)
6679 bp->phy_flags |= PHY_CRC_FIX_FLAG;
Michael Chancd461712007-09-20 11:04:58 -07006680 else if (CHIP_ID(bp) == CHIP_ID_5709_A0 ||
6681 CHIP_ID(bp) == CHIP_ID_5709_A1)
Michael Chanb659f442007-02-02 00:46:35 -08006682 bp->phy_flags |= PHY_DIS_EARLY_DAC_FLAG;
Michael Chanb6016b72005-05-26 13:03:09 -07006683
Michael Chan16088272006-06-12 22:16:43 -07006684 if ((CHIP_ID(bp) == CHIP_ID_5708_A0) ||
6685 (CHIP_ID(bp) == CHIP_ID_5708_B0) ||
6686 (CHIP_ID(bp) == CHIP_ID_5708_B1))
Michael Chandda1e392006-01-23 16:08:14 -08006687 bp->flags |= NO_WOL_FLAG;
6688
Michael Chanb6016b72005-05-26 13:03:09 -07006689 if (CHIP_ID(bp) == CHIP_ID_5706_A0) {
6690 bp->tx_quick_cons_trip_int =
6691 bp->tx_quick_cons_trip;
6692 bp->tx_ticks_int = bp->tx_ticks;
6693 bp->rx_quick_cons_trip_int =
6694 bp->rx_quick_cons_trip;
6695 bp->rx_ticks_int = bp->rx_ticks;
6696 bp->comp_prod_trip_int = bp->comp_prod_trip;
6697 bp->com_ticks_int = bp->com_ticks;
6698 bp->cmd_ticks_int = bp->cmd_ticks;
6699 }
6700
Michael Chanf9317a42006-09-29 17:06:23 -07006701 /* Disable MSI on 5706 if AMD 8132 bridge is found.
6702 *
6703 * MSI is defined to be 32-bit write. The 5706 does 64-bit MSI writes
6704 * with byte enables disabled on the unused 32-bit word. This is legal
6705 * but causes problems on the AMD 8132 which will eventually stop
6706 * responding after a while.
6707 *
6708 * AMD believes this incompatibility is unique to the 5706, and
Michael Ellerman88187df2007-01-25 19:34:07 +11006709 * prefers to locally disable MSI rather than globally disabling it.
Michael Chanf9317a42006-09-29 17:06:23 -07006710 */
6711 if (CHIP_NUM(bp) == CHIP_NUM_5706 && disable_msi == 0) {
6712 struct pci_dev *amd_8132 = NULL;
6713
6714 while ((amd_8132 = pci_get_device(PCI_VENDOR_ID_AMD,
6715 PCI_DEVICE_ID_AMD_8132_BRIDGE,
6716 amd_8132))) {
Michael Chanf9317a42006-09-29 17:06:23 -07006717
Auke Kok44c10132007-06-08 15:46:36 -07006718 if (amd_8132->revision >= 0x10 &&
6719 amd_8132->revision <= 0x13) {
Michael Chanf9317a42006-09-29 17:06:23 -07006720 disable_msi = 1;
6721 pci_dev_put(amd_8132);
6722 break;
6723 }
6724 }
6725 }
6726
Michael Chandeaf3912007-07-07 22:48:00 -07006727 bnx2_set_default_link(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07006728 bp->req_flow_ctrl = FLOW_CTRL_RX | FLOW_CTRL_TX;
6729
Michael Chancd339a02005-08-25 15:35:24 -07006730 init_timer(&bp->timer);
6731 bp->timer.expires = RUN_AT(bp->timer_interval);
6732 bp->timer.data = (unsigned long) bp;
6733 bp->timer.function = bnx2_timer;
6734
Michael Chanb6016b72005-05-26 13:03:09 -07006735 return 0;
6736
6737err_out_unmap:
6738 if (bp->regview) {
6739 iounmap(bp->regview);
Michael Chan73eef4c2005-08-25 15:39:15 -07006740 bp->regview = NULL;
Michael Chanb6016b72005-05-26 13:03:09 -07006741 }
6742
6743err_out_release:
6744 pci_release_regions(pdev);
6745
6746err_out_disable:
6747 pci_disable_device(pdev);
6748 pci_set_drvdata(pdev, NULL);
6749
6750err_out:
6751 return rc;
6752}
6753
Michael Chan883e5152007-05-03 13:25:11 -07006754static char * __devinit
6755bnx2_bus_string(struct bnx2 *bp, char *str)
6756{
6757 char *s = str;
6758
6759 if (bp->flags & PCIE_FLAG) {
6760 s += sprintf(s, "PCI Express");
6761 } else {
6762 s += sprintf(s, "PCI");
6763 if (bp->flags & PCIX_FLAG)
6764 s += sprintf(s, "-X");
6765 if (bp->flags & PCI_32BIT_FLAG)
6766 s += sprintf(s, " 32-bit");
6767 else
6768 s += sprintf(s, " 64-bit");
6769 s += sprintf(s, " %dMHz", bp->bus_speed_mhz);
6770 }
6771 return str;
6772}
6773
Michael Chanb6016b72005-05-26 13:03:09 -07006774static int __devinit
6775bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
6776{
6777 static int version_printed = 0;
6778 struct net_device *dev = NULL;
6779 struct bnx2 *bp;
Joe Perches0795af52007-10-03 17:59:30 -07006780 int rc;
Michael Chan883e5152007-05-03 13:25:11 -07006781 char str[40];
Joe Perches0795af52007-10-03 17:59:30 -07006782 DECLARE_MAC_BUF(mac);
Michael Chanb6016b72005-05-26 13:03:09 -07006783
6784 if (version_printed++ == 0)
6785 printk(KERN_INFO "%s", version);
6786
6787 /* dev zeroed in init_etherdev */
6788 dev = alloc_etherdev(sizeof(*bp));
6789
6790 if (!dev)
6791 return -ENOMEM;
6792
6793 rc = bnx2_init_board(pdev, dev);
6794 if (rc < 0) {
6795 free_netdev(dev);
6796 return rc;
6797 }
6798
6799 dev->open = bnx2_open;
6800 dev->hard_start_xmit = bnx2_start_xmit;
6801 dev->stop = bnx2_close;
6802 dev->get_stats = bnx2_get_stats;
6803 dev->set_multicast_list = bnx2_set_rx_mode;
6804 dev->do_ioctl = bnx2_ioctl;
6805 dev->set_mac_address = bnx2_change_mac_addr;
6806 dev->change_mtu = bnx2_change_mtu;
6807 dev->tx_timeout = bnx2_tx_timeout;
6808 dev->watchdog_timeo = TX_TIMEOUT;
6809#ifdef BCM_VLAN
6810 dev->vlan_rx_register = bnx2_vlan_rx_register;
Michael Chanb6016b72005-05-26 13:03:09 -07006811#endif
Michael Chanb6016b72005-05-26 13:03:09 -07006812 dev->ethtool_ops = &bnx2_ethtool_ops;
Michael Chanb6016b72005-05-26 13:03:09 -07006813
Michael Chan972ec0d2006-01-23 16:12:43 -08006814 bp = netdev_priv(dev);
Stephen Hemmingerbea33482007-10-03 16:41:36 -07006815 netif_napi_add(dev, &bp->napi, bnx2_poll, 64);
Michael Chanb6016b72005-05-26 13:03:09 -07006816
6817#if defined(HAVE_POLL_CONTROLLER) || defined(CONFIG_NET_POLL_CONTROLLER)
6818 dev->poll_controller = poll_bnx2;
6819#endif
6820
Michael Chan1b2f9222007-05-03 13:20:19 -07006821 pci_set_drvdata(pdev, dev);
6822
6823 memcpy(dev->dev_addr, bp->mac_addr, 6);
6824 memcpy(dev->perm_addr, bp->mac_addr, 6);
6825 bp->name = board_info[ent->driver_data].name;
6826
Stephen Hemmingerd212f872007-06-27 00:47:37 -07006827 dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG;
Michael Chan4666f872007-05-03 13:22:28 -07006828 if (CHIP_NUM(bp) == CHIP_NUM_5709)
Stephen Hemmingerd212f872007-06-27 00:47:37 -07006829 dev->features |= NETIF_F_IPV6_CSUM;
6830
Michael Chan1b2f9222007-05-03 13:20:19 -07006831#ifdef BCM_VLAN
6832 dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
6833#endif
6834 dev->features |= NETIF_F_TSO | NETIF_F_TSO_ECN;
Michael Chan4666f872007-05-03 13:22:28 -07006835 if (CHIP_NUM(bp) == CHIP_NUM_5709)
6836 dev->features |= NETIF_F_TSO6;
Michael Chan1b2f9222007-05-03 13:20:19 -07006837
Michael Chanb6016b72005-05-26 13:03:09 -07006838 if ((rc = register_netdev(dev))) {
Jeff Garzik9b91cf92006-06-27 11:39:50 -04006839 dev_err(&pdev->dev, "Cannot register net device\n");
Michael Chanb6016b72005-05-26 13:03:09 -07006840 if (bp->regview)
6841 iounmap(bp->regview);
6842 pci_release_regions(pdev);
6843 pci_disable_device(pdev);
6844 pci_set_drvdata(pdev, NULL);
6845 free_netdev(dev);
6846 return rc;
6847 }
6848
Michael Chan883e5152007-05-03 13:25:11 -07006849 printk(KERN_INFO "%s: %s (%c%d) %s found at mem %lx, "
Joe Perches0795af52007-10-03 17:59:30 -07006850 "IRQ %d, node addr %s\n",
Michael Chanb6016b72005-05-26 13:03:09 -07006851 dev->name,
6852 bp->name,
6853 ((CHIP_ID(bp) & 0xf000) >> 12) + 'A',
6854 ((CHIP_ID(bp) & 0x0ff0) >> 4),
Michael Chan883e5152007-05-03 13:25:11 -07006855 bnx2_bus_string(bp, str),
Michael Chanb6016b72005-05-26 13:03:09 -07006856 dev->base_addr,
Joe Perches0795af52007-10-03 17:59:30 -07006857 bp->pdev->irq, print_mac(mac, dev->dev_addr));
Michael Chanb6016b72005-05-26 13:03:09 -07006858
Michael Chanb6016b72005-05-26 13:03:09 -07006859 return 0;
6860}
6861
6862static void __devexit
6863bnx2_remove_one(struct pci_dev *pdev)
6864{
6865 struct net_device *dev = pci_get_drvdata(pdev);
Michael Chan972ec0d2006-01-23 16:12:43 -08006866 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006867
Michael Chanafdc08b2005-08-25 15:34:29 -07006868 flush_scheduled_work();
6869
Michael Chanb6016b72005-05-26 13:03:09 -07006870 unregister_netdev(dev);
6871
6872 if (bp->regview)
6873 iounmap(bp->regview);
6874
6875 free_netdev(dev);
6876 pci_release_regions(pdev);
6877 pci_disable_device(pdev);
6878 pci_set_drvdata(pdev, NULL);
6879}
6880
6881static int
Pavel Machek829ca9a2005-09-03 15:56:56 -07006882bnx2_suspend(struct pci_dev *pdev, pm_message_t state)
Michael Chanb6016b72005-05-26 13:03:09 -07006883{
6884 struct net_device *dev = pci_get_drvdata(pdev);
Michael Chan972ec0d2006-01-23 16:12:43 -08006885 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006886 u32 reset_code;
6887
Michael Chan6caebb02007-08-03 20:57:25 -07006888 /* PCI register 4 needs to be saved whether netif_running() or not.
6889 * MSI address and data need to be saved if using MSI and
6890 * netif_running().
6891 */
6892 pci_save_state(pdev);
Michael Chanb6016b72005-05-26 13:03:09 -07006893 if (!netif_running(dev))
6894 return 0;
6895
Michael Chan1d60290f2006-03-20 17:50:08 -08006896 flush_scheduled_work();
Michael Chanb6016b72005-05-26 13:03:09 -07006897 bnx2_netif_stop(bp);
6898 netif_device_detach(dev);
6899 del_timer_sync(&bp->timer);
Michael Chandda1e392006-01-23 16:08:14 -08006900 if (bp->flags & NO_WOL_FLAG)
Michael Chan6c4f0952006-06-29 12:38:15 -07006901 reset_code = BNX2_DRV_MSG_CODE_UNLOAD_LNK_DN;
Michael Chandda1e392006-01-23 16:08:14 -08006902 else if (bp->wol)
Michael Chanb6016b72005-05-26 13:03:09 -07006903 reset_code = BNX2_DRV_MSG_CODE_SUSPEND_WOL;
6904 else
6905 reset_code = BNX2_DRV_MSG_CODE_SUSPEND_NO_WOL;
6906 bnx2_reset_chip(bp, reset_code);
6907 bnx2_free_skbs(bp);
Pavel Machek829ca9a2005-09-03 15:56:56 -07006908 bnx2_set_power_state(bp, pci_choose_state(pdev, state));
Michael Chanb6016b72005-05-26 13:03:09 -07006909 return 0;
6910}
6911
6912static int
6913bnx2_resume(struct pci_dev *pdev)
6914{
6915 struct net_device *dev = pci_get_drvdata(pdev);
Michael Chan972ec0d2006-01-23 16:12:43 -08006916 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006917
Michael Chan6caebb02007-08-03 20:57:25 -07006918 pci_restore_state(pdev);
Michael Chanb6016b72005-05-26 13:03:09 -07006919 if (!netif_running(dev))
6920 return 0;
6921
Pavel Machek829ca9a2005-09-03 15:56:56 -07006922 bnx2_set_power_state(bp, PCI_D0);
Michael Chanb6016b72005-05-26 13:03:09 -07006923 netif_device_attach(dev);
6924 bnx2_init_nic(bp);
6925 bnx2_netif_start(bp);
6926 return 0;
6927}
6928
6929static struct pci_driver bnx2_pci_driver = {
Peter Hagervall14ab9b82005-08-10 14:18:16 -07006930 .name = DRV_MODULE_NAME,
6931 .id_table = bnx2_pci_tbl,
6932 .probe = bnx2_init_one,
6933 .remove = __devexit_p(bnx2_remove_one),
6934 .suspend = bnx2_suspend,
6935 .resume = bnx2_resume,
Michael Chanb6016b72005-05-26 13:03:09 -07006936};
6937
6938static int __init bnx2_init(void)
6939{
Jeff Garzik29917622006-08-19 17:48:59 -04006940 return pci_register_driver(&bnx2_pci_driver);
Michael Chanb6016b72005-05-26 13:03:09 -07006941}
6942
6943static void __exit bnx2_cleanup(void)
6944{
6945 pci_unregister_driver(&bnx2_pci_driver);
6946}
6947
6948module_init(bnx2_init);
6949module_exit(bnx2_cleanup);
6950
6951
6952