blob: 861387928e6db0c1f0fad79994aa2b2dcb7e14e1 [file] [log] [blame]
Michael Chanb6016b72005-05-26 13:03:09 -07001/* bnx2.c: Broadcom NX2 network driver.
2 *
Michael Chanfeebb332008-01-21 17:07:29 -08003 * Copyright (c) 2004-2008 Broadcom Corporation
Michael Chanb6016b72005-05-26 13:03:09 -07004 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation.
8 *
9 * Written by: Michael Chan (mchan@broadcom.com)
10 */
11
Michael Chanf2a4f052006-03-23 01:13:12 -080012
13#include <linux/module.h>
14#include <linux/moduleparam.h>
15
16#include <linux/kernel.h>
17#include <linux/timer.h>
18#include <linux/errno.h>
19#include <linux/ioport.h>
20#include <linux/slab.h>
21#include <linux/vmalloc.h>
22#include <linux/interrupt.h>
23#include <linux/pci.h>
24#include <linux/init.h>
25#include <linux/netdevice.h>
26#include <linux/etherdevice.h>
27#include <linux/skbuff.h>
28#include <linux/dma-mapping.h>
Jiri Slaby1977f032007-10-18 23:40:25 -070029#include <linux/bitops.h>
Michael Chanf2a4f052006-03-23 01:13:12 -080030#include <asm/io.h>
31#include <asm/irq.h>
32#include <linux/delay.h>
33#include <asm/byteorder.h>
Michael Chanc86a31f2006-06-13 15:03:47 -070034#include <asm/page.h>
Michael Chanf2a4f052006-03-23 01:13:12 -080035#include <linux/time.h>
36#include <linux/ethtool.h>
37#include <linux/mii.h>
38#ifdef NETIF_F_HW_VLAN_TX
39#include <linux/if_vlan.h>
40#define BCM_VLAN 1
41#endif
Michael Chanf2a4f052006-03-23 01:13:12 -080042#include <net/ip.h>
Linus Torvaldsde081fa2007-07-12 16:40:08 -070043#include <net/tcp.h>
Michael Chanf2a4f052006-03-23 01:13:12 -080044#include <net/checksum.h>
Michael Chanf2a4f052006-03-23 01:13:12 -080045#include <linux/workqueue.h>
46#include <linux/crc32.h>
47#include <linux/prefetch.h>
Michael Chan29b12172006-03-23 01:13:43 -080048#include <linux/cache.h>
Michael Chanfba9fe92006-06-12 22:21:25 -070049#include <linux/zlib.h>
Michael Chanf2a4f052006-03-23 01:13:12 -080050
Michael Chanb6016b72005-05-26 13:03:09 -070051#include "bnx2.h"
52#include "bnx2_fw.h"
Michael Chand43584c2006-11-19 14:14:35 -080053#include "bnx2_fw2.h"
Michael Chanb6016b72005-05-26 13:03:09 -070054
Michael Chan110d0ef2007-12-12 11:18:34 -080055#define FW_BUF_SIZE 0x10000
Denys Vlasenkob3448b02007-09-30 17:55:51 -070056
Michael Chanb6016b72005-05-26 13:03:09 -070057#define DRV_MODULE_NAME "bnx2"
58#define PFX DRV_MODULE_NAME ": "
Michael Chanc73b1d12008-02-23 19:49:48 -080059#define DRV_MODULE_VERSION "1.7.4"
60#define DRV_MODULE_RELDATE "February 18, 2008"
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
Andrew Mortonfefa8642008-02-09 23:17:15 -080067static 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 */
Andrew Mortonfefa8642008-02-09 23:17:15 -080093static struct {
Michael Chanb6016b72005-05-26 13:03:09 -070094 char *name;
95} board_info[] __devinitdata = {
96 { "Broadcom NetXtreme II BCM5706 1000Base-T" },
97 { "HP NC370T Multifunction Gigabit Server Adapter" },
98 { "HP NC370i Multifunction Gigabit Server Adapter" },
99 { "Broadcom NetXtreme II BCM5706 1000Base-SX" },
100 { "HP NC370F Multifunction Gigabit Server Adapter" },
Michael Chan5b0c76a2005-11-04 08:45:49 -0800101 { "Broadcom NetXtreme II BCM5708 1000Base-T" },
102 { "Broadcom NetXtreme II BCM5708 1000Base-SX" },
Michael Chanbac0dff2006-11-19 14:15:05 -0800103 { "Broadcom NetXtreme II BCM5709 1000Base-T" },
Michael Chan27a005b2007-05-03 13:23:41 -0700104 { "Broadcom NetXtreme II BCM5709 1000Base-SX" },
Michael Chanb6016b72005-05-26 13:03:09 -0700105 };
106
107static struct pci_device_id bnx2_pci_tbl[] = {
108 { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5706,
109 PCI_VENDOR_ID_HP, 0x3101, 0, 0, NC370T },
110 { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5706,
111 PCI_VENDOR_ID_HP, 0x3106, 0, 0, NC370I },
112 { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5706,
113 PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5706 },
Michael Chan5b0c76a2005-11-04 08:45:49 -0800114 { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5708,
115 PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5708 },
Michael Chanb6016b72005-05-26 13:03:09 -0700116 { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5706S,
117 PCI_VENDOR_ID_HP, 0x3102, 0, 0, NC370F },
118 { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5706S,
119 PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5706S },
Michael Chan5b0c76a2005-11-04 08:45:49 -0800120 { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5708S,
121 PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5708S },
Michael Chanbac0dff2006-11-19 14:15:05 -0800122 { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5709,
123 PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5709 },
Michael Chan27a005b2007-05-03 13:23:41 -0700124 { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5709S,
125 PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5709S },
Michael Chanb6016b72005-05-26 13:03:09 -0700126 { 0, }
127};
128
129static struct flash_spec flash_table[] =
130{
Michael Chane30372c2007-07-16 18:26:23 -0700131#define BUFFERED_FLAGS (BNX2_NV_BUFFERED | BNX2_NV_TRANSLATE)
132#define NONBUFFERED_FLAGS (BNX2_NV_WREN)
Michael Chanb6016b72005-05-26 13:03:09 -0700133 /* Slow EEPROM */
Michael Chan37137702005-11-04 08:49:17 -0800134 {0x00000000, 0x40830380, 0x009f0081, 0xa184a053, 0xaf000400,
Michael Chane30372c2007-07-16 18:26:23 -0700135 BUFFERED_FLAGS, SEEPROM_PAGE_BITS, SEEPROM_PAGE_SIZE,
Michael Chanb6016b72005-05-26 13:03:09 -0700136 SEEPROM_BYTE_ADDR_MASK, SEEPROM_TOTAL_SIZE,
137 "EEPROM - slow"},
Michael Chan37137702005-11-04 08:49:17 -0800138 /* Expansion entry 0001 */
139 {0x08000002, 0x4b808201, 0x00050081, 0x03840253, 0xaf020406,
Michael Chane30372c2007-07-16 18:26:23 -0700140 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
Michael Chan37137702005-11-04 08:49:17 -0800141 SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
142 "Entry 0001"},
Michael Chanb6016b72005-05-26 13:03:09 -0700143 /* Saifun SA25F010 (non-buffered flash) */
144 /* strap, cfg1, & write1 need updates */
Michael Chan37137702005-11-04 08:49:17 -0800145 {0x04000001, 0x47808201, 0x00050081, 0x03840253, 0xaf020406,
Michael Chane30372c2007-07-16 18:26:23 -0700146 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
Michael Chanb6016b72005-05-26 13:03:09 -0700147 SAIFUN_FLASH_BYTE_ADDR_MASK, SAIFUN_FLASH_BASE_TOTAL_SIZE*2,
148 "Non-buffered flash (128kB)"},
149 /* Saifun SA25F020 (non-buffered flash) */
150 /* strap, cfg1, & write1 need updates */
Michael Chan37137702005-11-04 08:49:17 -0800151 {0x0c000003, 0x4f808201, 0x00050081, 0x03840253, 0xaf020406,
Michael Chane30372c2007-07-16 18:26:23 -0700152 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
Michael Chanb6016b72005-05-26 13:03:09 -0700153 SAIFUN_FLASH_BYTE_ADDR_MASK, SAIFUN_FLASH_BASE_TOTAL_SIZE*4,
154 "Non-buffered flash (256kB)"},
Michael Chan37137702005-11-04 08:49:17 -0800155 /* Expansion entry 0100 */
156 {0x11000000, 0x53808201, 0x00050081, 0x03840253, 0xaf020406,
Michael Chane30372c2007-07-16 18:26:23 -0700157 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
Michael Chan37137702005-11-04 08:49:17 -0800158 SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
159 "Entry 0100"},
160 /* Entry 0101: ST M45PE10 (non-buffered flash, TetonII B0) */
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400161 {0x19000002, 0x5b808201, 0x000500db, 0x03840253, 0xaf020406,
Michael Chane30372c2007-07-16 18:26:23 -0700162 NONBUFFERED_FLAGS, ST_MICRO_FLASH_PAGE_BITS, ST_MICRO_FLASH_PAGE_SIZE,
Michael Chan37137702005-11-04 08:49:17 -0800163 ST_MICRO_FLASH_BYTE_ADDR_MASK, ST_MICRO_FLASH_BASE_TOTAL_SIZE*2,
164 "Entry 0101: ST M45PE10 (128kB non-bufferred)"},
165 /* Entry 0110: ST M45PE20 (non-buffered flash)*/
166 {0x15000001, 0x57808201, 0x000500db, 0x03840253, 0xaf020406,
Michael Chane30372c2007-07-16 18:26:23 -0700167 NONBUFFERED_FLAGS, ST_MICRO_FLASH_PAGE_BITS, ST_MICRO_FLASH_PAGE_SIZE,
Michael Chan37137702005-11-04 08:49:17 -0800168 ST_MICRO_FLASH_BYTE_ADDR_MASK, ST_MICRO_FLASH_BASE_TOTAL_SIZE*4,
169 "Entry 0110: ST M45PE20 (256kB non-bufferred)"},
170 /* Saifun SA25F005 (non-buffered flash) */
171 /* strap, cfg1, & write1 need updates */
172 {0x1d000003, 0x5f808201, 0x00050081, 0x03840253, 0xaf020406,
Michael Chane30372c2007-07-16 18:26:23 -0700173 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
Michael Chan37137702005-11-04 08:49:17 -0800174 SAIFUN_FLASH_BYTE_ADDR_MASK, SAIFUN_FLASH_BASE_TOTAL_SIZE,
175 "Non-buffered flash (64kB)"},
176 /* Fast EEPROM */
177 {0x22000000, 0x62808380, 0x009f0081, 0xa184a053, 0xaf000400,
Michael Chane30372c2007-07-16 18:26:23 -0700178 BUFFERED_FLAGS, SEEPROM_PAGE_BITS, SEEPROM_PAGE_SIZE,
Michael Chan37137702005-11-04 08:49:17 -0800179 SEEPROM_BYTE_ADDR_MASK, SEEPROM_TOTAL_SIZE,
180 "EEPROM - fast"},
181 /* Expansion entry 1001 */
182 {0x2a000002, 0x6b808201, 0x00050081, 0x03840253, 0xaf020406,
Michael Chane30372c2007-07-16 18:26:23 -0700183 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
Michael Chan37137702005-11-04 08:49:17 -0800184 SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
185 "Entry 1001"},
186 /* Expansion entry 1010 */
187 {0x26000001, 0x67808201, 0x00050081, 0x03840253, 0xaf020406,
Michael Chane30372c2007-07-16 18:26:23 -0700188 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
Michael Chan37137702005-11-04 08:49:17 -0800189 SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
190 "Entry 1010"},
191 /* ATMEL AT45DB011B (buffered flash) */
192 {0x2e000003, 0x6e808273, 0x00570081, 0x68848353, 0xaf000400,
Michael Chane30372c2007-07-16 18:26:23 -0700193 BUFFERED_FLAGS, BUFFERED_FLASH_PAGE_BITS, BUFFERED_FLASH_PAGE_SIZE,
Michael Chan37137702005-11-04 08:49:17 -0800194 BUFFERED_FLASH_BYTE_ADDR_MASK, BUFFERED_FLASH_TOTAL_SIZE,
195 "Buffered flash (128kB)"},
196 /* Expansion entry 1100 */
197 {0x33000000, 0x73808201, 0x00050081, 0x03840253, 0xaf020406,
Michael Chane30372c2007-07-16 18:26:23 -0700198 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
Michael Chan37137702005-11-04 08:49:17 -0800199 SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
200 "Entry 1100"},
201 /* Expansion entry 1101 */
202 {0x3b000002, 0x7b808201, 0x00050081, 0x03840253, 0xaf020406,
Michael Chane30372c2007-07-16 18:26:23 -0700203 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
Michael Chan37137702005-11-04 08:49:17 -0800204 SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
205 "Entry 1101"},
206 /* Ateml Expansion entry 1110 */
207 {0x37000001, 0x76808273, 0x00570081, 0x68848353, 0xaf000400,
Michael Chane30372c2007-07-16 18:26:23 -0700208 BUFFERED_FLAGS, BUFFERED_FLASH_PAGE_BITS, BUFFERED_FLASH_PAGE_SIZE,
Michael Chan37137702005-11-04 08:49:17 -0800209 BUFFERED_FLASH_BYTE_ADDR_MASK, 0,
210 "Entry 1110 (Atmel)"},
211 /* ATMEL AT45DB021B (buffered flash) */
212 {0x3f000003, 0x7e808273, 0x00570081, 0x68848353, 0xaf000400,
Michael Chane30372c2007-07-16 18:26:23 -0700213 BUFFERED_FLAGS, BUFFERED_FLASH_PAGE_BITS, BUFFERED_FLASH_PAGE_SIZE,
Michael Chan37137702005-11-04 08:49:17 -0800214 BUFFERED_FLASH_BYTE_ADDR_MASK, BUFFERED_FLASH_TOTAL_SIZE*2,
215 "Buffered flash (256kB)"},
Michael Chanb6016b72005-05-26 13:03:09 -0700216};
217
Michael Chane30372c2007-07-16 18:26:23 -0700218static struct flash_spec flash_5709 = {
219 .flags = BNX2_NV_BUFFERED,
220 .page_bits = BCM5709_FLASH_PAGE_BITS,
221 .page_size = BCM5709_FLASH_PAGE_SIZE,
222 .addr_mask = BCM5709_FLASH_BYTE_ADDR_MASK,
223 .total_size = BUFFERED_FLASH_TOTAL_SIZE*2,
224 .name = "5709 Buffered flash (256kB)",
225};
226
Michael Chanb6016b72005-05-26 13:03:09 -0700227MODULE_DEVICE_TABLE(pci, bnx2_pci_tbl);
228
Michael Chana550c992007-12-20 19:56:59 -0800229static inline u32 bnx2_tx_avail(struct bnx2 *bp, struct bnx2_napi *bnapi)
Michael Chane89bbf12005-08-25 15:36:58 -0700230{
Michael Chan2f8af122006-08-15 01:39:10 -0700231 u32 diff;
Michael Chane89bbf12005-08-25 15:36:58 -0700232
Michael Chan2f8af122006-08-15 01:39:10 -0700233 smp_mb();
Michael Chanfaac9c42006-12-14 15:56:32 -0800234
235 /* The ring uses 256 indices for 255 entries, one of them
236 * needs to be skipped.
237 */
Michael Chana550c992007-12-20 19:56:59 -0800238 diff = bp->tx_prod - bnapi->tx_cons;
Michael Chanfaac9c42006-12-14 15:56:32 -0800239 if (unlikely(diff >= TX_DESC_CNT)) {
240 diff &= 0xffff;
241 if (diff == TX_DESC_CNT)
242 diff = MAX_TX_DESC_CNT;
243 }
Michael Chane89bbf12005-08-25 15:36:58 -0700244 return (bp->tx_ring_size - diff);
245}
246
Michael Chanb6016b72005-05-26 13:03:09 -0700247static u32
248bnx2_reg_rd_ind(struct bnx2 *bp, u32 offset)
249{
Michael Chan1b8227c2007-05-03 13:24:05 -0700250 u32 val;
251
252 spin_lock_bh(&bp->indirect_lock);
Michael Chanb6016b72005-05-26 13:03:09 -0700253 REG_WR(bp, BNX2_PCICFG_REG_WINDOW_ADDRESS, offset);
Michael Chan1b8227c2007-05-03 13:24:05 -0700254 val = REG_RD(bp, BNX2_PCICFG_REG_WINDOW);
255 spin_unlock_bh(&bp->indirect_lock);
256 return val;
Michael Chanb6016b72005-05-26 13:03:09 -0700257}
258
259static void
260bnx2_reg_wr_ind(struct bnx2 *bp, u32 offset, u32 val)
261{
Michael Chan1b8227c2007-05-03 13:24:05 -0700262 spin_lock_bh(&bp->indirect_lock);
Michael Chanb6016b72005-05-26 13:03:09 -0700263 REG_WR(bp, BNX2_PCICFG_REG_WINDOW_ADDRESS, offset);
264 REG_WR(bp, BNX2_PCICFG_REG_WINDOW, val);
Michael Chan1b8227c2007-05-03 13:24:05 -0700265 spin_unlock_bh(&bp->indirect_lock);
Michael Chanb6016b72005-05-26 13:03:09 -0700266}
267
268static void
Michael Chan2726d6e2008-01-29 21:35:05 -0800269bnx2_shmem_wr(struct bnx2 *bp, u32 offset, u32 val)
270{
271 bnx2_reg_wr_ind(bp, bp->shmem_base + offset, val);
272}
273
274static u32
275bnx2_shmem_rd(struct bnx2 *bp, u32 offset)
276{
277 return (bnx2_reg_rd_ind(bp, bp->shmem_base + offset));
278}
279
280static void
Michael Chanb6016b72005-05-26 13:03:09 -0700281bnx2_ctx_wr(struct bnx2 *bp, u32 cid_addr, u32 offset, u32 val)
282{
283 offset += cid_addr;
Michael Chan1b8227c2007-05-03 13:24:05 -0700284 spin_lock_bh(&bp->indirect_lock);
Michael Chan59b47d82006-11-19 14:10:45 -0800285 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
286 int i;
287
288 REG_WR(bp, BNX2_CTX_CTX_DATA, val);
289 REG_WR(bp, BNX2_CTX_CTX_CTRL,
290 offset | BNX2_CTX_CTX_CTRL_WRITE_REQ);
291 for (i = 0; i < 5; i++) {
292 u32 val;
293 val = REG_RD(bp, BNX2_CTX_CTX_CTRL);
294 if ((val & BNX2_CTX_CTX_CTRL_WRITE_REQ) == 0)
295 break;
296 udelay(5);
297 }
298 } else {
299 REG_WR(bp, BNX2_CTX_DATA_ADR, offset);
300 REG_WR(bp, BNX2_CTX_DATA, val);
301 }
Michael Chan1b8227c2007-05-03 13:24:05 -0700302 spin_unlock_bh(&bp->indirect_lock);
Michael Chanb6016b72005-05-26 13:03:09 -0700303}
304
305static int
306bnx2_read_phy(struct bnx2 *bp, u32 reg, u32 *val)
307{
308 u32 val1;
309 int i, ret;
310
Michael Chan583c28e2008-01-21 19:51:35 -0800311 if (bp->phy_flags & BNX2_PHY_FLAG_INT_MODE_AUTO_POLLING) {
Michael Chanb6016b72005-05-26 13:03:09 -0700312 val1 = REG_RD(bp, BNX2_EMAC_MDIO_MODE);
313 val1 &= ~BNX2_EMAC_MDIO_MODE_AUTO_POLL;
314
315 REG_WR(bp, BNX2_EMAC_MDIO_MODE, val1);
316 REG_RD(bp, BNX2_EMAC_MDIO_MODE);
317
318 udelay(40);
319 }
320
321 val1 = (bp->phy_addr << 21) | (reg << 16) |
322 BNX2_EMAC_MDIO_COMM_COMMAND_READ | BNX2_EMAC_MDIO_COMM_DISEXT |
323 BNX2_EMAC_MDIO_COMM_START_BUSY;
324 REG_WR(bp, BNX2_EMAC_MDIO_COMM, val1);
325
326 for (i = 0; i < 50; i++) {
327 udelay(10);
328
329 val1 = REG_RD(bp, BNX2_EMAC_MDIO_COMM);
330 if (!(val1 & BNX2_EMAC_MDIO_COMM_START_BUSY)) {
331 udelay(5);
332
333 val1 = REG_RD(bp, BNX2_EMAC_MDIO_COMM);
334 val1 &= BNX2_EMAC_MDIO_COMM_DATA;
335
336 break;
337 }
338 }
339
340 if (val1 & BNX2_EMAC_MDIO_COMM_START_BUSY) {
341 *val = 0x0;
342 ret = -EBUSY;
343 }
344 else {
345 *val = val1;
346 ret = 0;
347 }
348
Michael Chan583c28e2008-01-21 19:51:35 -0800349 if (bp->phy_flags & BNX2_PHY_FLAG_INT_MODE_AUTO_POLLING) {
Michael Chanb6016b72005-05-26 13:03:09 -0700350 val1 = REG_RD(bp, BNX2_EMAC_MDIO_MODE);
351 val1 |= BNX2_EMAC_MDIO_MODE_AUTO_POLL;
352
353 REG_WR(bp, BNX2_EMAC_MDIO_MODE, val1);
354 REG_RD(bp, BNX2_EMAC_MDIO_MODE);
355
356 udelay(40);
357 }
358
359 return ret;
360}
361
362static int
363bnx2_write_phy(struct bnx2 *bp, u32 reg, u32 val)
364{
365 u32 val1;
366 int i, ret;
367
Michael Chan583c28e2008-01-21 19:51:35 -0800368 if (bp->phy_flags & BNX2_PHY_FLAG_INT_MODE_AUTO_POLLING) {
Michael Chanb6016b72005-05-26 13:03:09 -0700369 val1 = REG_RD(bp, BNX2_EMAC_MDIO_MODE);
370 val1 &= ~BNX2_EMAC_MDIO_MODE_AUTO_POLL;
371
372 REG_WR(bp, BNX2_EMAC_MDIO_MODE, val1);
373 REG_RD(bp, BNX2_EMAC_MDIO_MODE);
374
375 udelay(40);
376 }
377
378 val1 = (bp->phy_addr << 21) | (reg << 16) | val |
379 BNX2_EMAC_MDIO_COMM_COMMAND_WRITE |
380 BNX2_EMAC_MDIO_COMM_START_BUSY | BNX2_EMAC_MDIO_COMM_DISEXT;
381 REG_WR(bp, BNX2_EMAC_MDIO_COMM, val1);
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400382
Michael Chanb6016b72005-05-26 13:03:09 -0700383 for (i = 0; i < 50; i++) {
384 udelay(10);
385
386 val1 = REG_RD(bp, BNX2_EMAC_MDIO_COMM);
387 if (!(val1 & BNX2_EMAC_MDIO_COMM_START_BUSY)) {
388 udelay(5);
389 break;
390 }
391 }
392
393 if (val1 & BNX2_EMAC_MDIO_COMM_START_BUSY)
394 ret = -EBUSY;
395 else
396 ret = 0;
397
Michael Chan583c28e2008-01-21 19:51:35 -0800398 if (bp->phy_flags & BNX2_PHY_FLAG_INT_MODE_AUTO_POLLING) {
Michael Chanb6016b72005-05-26 13:03:09 -0700399 val1 = REG_RD(bp, BNX2_EMAC_MDIO_MODE);
400 val1 |= BNX2_EMAC_MDIO_MODE_AUTO_POLL;
401
402 REG_WR(bp, BNX2_EMAC_MDIO_MODE, val1);
403 REG_RD(bp, BNX2_EMAC_MDIO_MODE);
404
405 udelay(40);
406 }
407
408 return ret;
409}
410
411static void
412bnx2_disable_int(struct bnx2 *bp)
413{
Michael Chanb4b36042007-12-20 19:59:30 -0800414 int i;
415 struct bnx2_napi *bnapi;
416
417 for (i = 0; i < bp->irq_nvecs; i++) {
418 bnapi = &bp->bnx2_napi[i];
419 REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD, bnapi->int_num |
420 BNX2_PCICFG_INT_ACK_CMD_MASK_INT);
421 }
Michael Chanb6016b72005-05-26 13:03:09 -0700422 REG_RD(bp, BNX2_PCICFG_INT_ACK_CMD);
423}
424
425static void
426bnx2_enable_int(struct bnx2 *bp)
427{
Michael Chanb4b36042007-12-20 19:59:30 -0800428 int i;
429 struct bnx2_napi *bnapi;
Michael Chan1269a8a2006-01-23 16:11:03 -0800430
Michael Chanb4b36042007-12-20 19:59:30 -0800431 for (i = 0; i < bp->irq_nvecs; i++) {
432 bnapi = &bp->bnx2_napi[i];
Michael Chan35efa7c2007-12-20 19:56:37 -0800433
Michael Chanb4b36042007-12-20 19:59:30 -0800434 REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD, bnapi->int_num |
435 BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
436 BNX2_PCICFG_INT_ACK_CMD_MASK_INT |
437 bnapi->last_status_idx);
Michael Chanb6016b72005-05-26 13:03:09 -0700438
Michael Chanb4b36042007-12-20 19:59:30 -0800439 REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD, bnapi->int_num |
440 BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
441 bnapi->last_status_idx);
442 }
Michael Chanbf5295b2006-03-23 01:11:56 -0800443 REG_WR(bp, BNX2_HC_COMMAND, bp->hc_cmd | BNX2_HC_COMMAND_COAL_NOW);
Michael Chanb6016b72005-05-26 13:03:09 -0700444}
445
446static void
447bnx2_disable_int_sync(struct bnx2 *bp)
448{
Michael Chanb4b36042007-12-20 19:59:30 -0800449 int i;
450
Michael Chanb6016b72005-05-26 13:03:09 -0700451 atomic_inc(&bp->intr_sem);
452 bnx2_disable_int(bp);
Michael Chanb4b36042007-12-20 19:59:30 -0800453 for (i = 0; i < bp->irq_nvecs; i++)
454 synchronize_irq(bp->irq_tbl[i].vector);
Michael Chanb6016b72005-05-26 13:03:09 -0700455}
456
457static void
Michael Chan35efa7c2007-12-20 19:56:37 -0800458bnx2_napi_disable(struct bnx2 *bp)
459{
Michael Chanb4b36042007-12-20 19:59:30 -0800460 int i;
461
462 for (i = 0; i < bp->irq_nvecs; i++)
463 napi_disable(&bp->bnx2_napi[i].napi);
Michael Chan35efa7c2007-12-20 19:56:37 -0800464}
465
466static void
467bnx2_napi_enable(struct bnx2 *bp)
468{
Michael Chanb4b36042007-12-20 19:59:30 -0800469 int i;
470
471 for (i = 0; i < bp->irq_nvecs; i++)
472 napi_enable(&bp->bnx2_napi[i].napi);
Michael Chan35efa7c2007-12-20 19:56:37 -0800473}
474
475static void
Michael Chanb6016b72005-05-26 13:03:09 -0700476bnx2_netif_stop(struct bnx2 *bp)
477{
478 bnx2_disable_int_sync(bp);
479 if (netif_running(bp->dev)) {
Michael Chan35efa7c2007-12-20 19:56:37 -0800480 bnx2_napi_disable(bp);
Michael Chanb6016b72005-05-26 13:03:09 -0700481 netif_tx_disable(bp->dev);
482 bp->dev->trans_start = jiffies; /* prevent tx timeout */
483 }
484}
485
486static void
487bnx2_netif_start(struct bnx2 *bp)
488{
489 if (atomic_dec_and_test(&bp->intr_sem)) {
490 if (netif_running(bp->dev)) {
491 netif_wake_queue(bp->dev);
Michael Chan35efa7c2007-12-20 19:56:37 -0800492 bnx2_napi_enable(bp);
Michael Chanb6016b72005-05-26 13:03:09 -0700493 bnx2_enable_int(bp);
494 }
495 }
496}
497
498static void
499bnx2_free_mem(struct bnx2 *bp)
500{
Michael Chan13daffa2006-03-20 17:49:20 -0800501 int i;
502
Michael Chan59b47d82006-11-19 14:10:45 -0800503 for (i = 0; i < bp->ctx_pages; i++) {
504 if (bp->ctx_blk[i]) {
505 pci_free_consistent(bp->pdev, BCM_PAGE_SIZE,
506 bp->ctx_blk[i],
507 bp->ctx_blk_mapping[i]);
508 bp->ctx_blk[i] = NULL;
509 }
510 }
Michael Chanb6016b72005-05-26 13:03:09 -0700511 if (bp->status_blk) {
Michael Chan0f31f992006-03-23 01:12:38 -0800512 pci_free_consistent(bp->pdev, bp->status_stats_size,
Michael Chanb6016b72005-05-26 13:03:09 -0700513 bp->status_blk, bp->status_blk_mapping);
514 bp->status_blk = NULL;
Michael Chan0f31f992006-03-23 01:12:38 -0800515 bp->stats_blk = NULL;
Michael Chanb6016b72005-05-26 13:03:09 -0700516 }
517 if (bp->tx_desc_ring) {
Michael Chane343d552007-12-12 11:16:19 -0800518 pci_free_consistent(bp->pdev, TXBD_RING_SIZE,
Michael Chanb6016b72005-05-26 13:03:09 -0700519 bp->tx_desc_ring, bp->tx_desc_mapping);
520 bp->tx_desc_ring = NULL;
521 }
Jesper Juhlb4558ea2005-10-28 16:53:13 -0400522 kfree(bp->tx_buf_ring);
523 bp->tx_buf_ring = NULL;
Michael Chan13daffa2006-03-20 17:49:20 -0800524 for (i = 0; i < bp->rx_max_ring; i++) {
525 if (bp->rx_desc_ring[i])
Michael Chane343d552007-12-12 11:16:19 -0800526 pci_free_consistent(bp->pdev, RXBD_RING_SIZE,
Michael Chan13daffa2006-03-20 17:49:20 -0800527 bp->rx_desc_ring[i],
528 bp->rx_desc_mapping[i]);
529 bp->rx_desc_ring[i] = NULL;
Michael Chanb6016b72005-05-26 13:03:09 -0700530 }
Michael Chan13daffa2006-03-20 17:49:20 -0800531 vfree(bp->rx_buf_ring);
Jesper Juhlb4558ea2005-10-28 16:53:13 -0400532 bp->rx_buf_ring = NULL;
Michael Chan47bf4242007-12-12 11:19:12 -0800533 for (i = 0; i < bp->rx_max_pg_ring; i++) {
534 if (bp->rx_pg_desc_ring[i])
535 pci_free_consistent(bp->pdev, RXBD_RING_SIZE,
536 bp->rx_pg_desc_ring[i],
537 bp->rx_pg_desc_mapping[i]);
538 bp->rx_pg_desc_ring[i] = NULL;
539 }
540 if (bp->rx_pg_ring)
541 vfree(bp->rx_pg_ring);
542 bp->rx_pg_ring = NULL;
Michael Chanb6016b72005-05-26 13:03:09 -0700543}
544
545static int
546bnx2_alloc_mem(struct bnx2 *bp)
547{
Michael Chan0f31f992006-03-23 01:12:38 -0800548 int i, status_blk_size;
Michael Chan13daffa2006-03-20 17:49:20 -0800549
Michael Chane343d552007-12-12 11:16:19 -0800550 bp->tx_buf_ring = kzalloc(SW_TXBD_RING_SIZE, GFP_KERNEL);
Michael Chanb6016b72005-05-26 13:03:09 -0700551 if (bp->tx_buf_ring == NULL)
552 return -ENOMEM;
553
Michael Chane343d552007-12-12 11:16:19 -0800554 bp->tx_desc_ring = pci_alloc_consistent(bp->pdev, TXBD_RING_SIZE,
Michael Chanb6016b72005-05-26 13:03:09 -0700555 &bp->tx_desc_mapping);
556 if (bp->tx_desc_ring == NULL)
557 goto alloc_mem_err;
558
Michael Chane343d552007-12-12 11:16:19 -0800559 bp->rx_buf_ring = vmalloc(SW_RXBD_RING_SIZE * bp->rx_max_ring);
Michael Chanb6016b72005-05-26 13:03:09 -0700560 if (bp->rx_buf_ring == NULL)
561 goto alloc_mem_err;
562
Michael Chane343d552007-12-12 11:16:19 -0800563 memset(bp->rx_buf_ring, 0, SW_RXBD_RING_SIZE * bp->rx_max_ring);
Michael Chan13daffa2006-03-20 17:49:20 -0800564
565 for (i = 0; i < bp->rx_max_ring; i++) {
566 bp->rx_desc_ring[i] =
Michael Chane343d552007-12-12 11:16:19 -0800567 pci_alloc_consistent(bp->pdev, RXBD_RING_SIZE,
Michael Chan13daffa2006-03-20 17:49:20 -0800568 &bp->rx_desc_mapping[i]);
569 if (bp->rx_desc_ring[i] == NULL)
570 goto alloc_mem_err;
571
572 }
Michael Chanb6016b72005-05-26 13:03:09 -0700573
Michael Chan47bf4242007-12-12 11:19:12 -0800574 if (bp->rx_pg_ring_size) {
575 bp->rx_pg_ring = vmalloc(SW_RXPG_RING_SIZE *
576 bp->rx_max_pg_ring);
577 if (bp->rx_pg_ring == NULL)
578 goto alloc_mem_err;
579
580 memset(bp->rx_pg_ring, 0, SW_RXPG_RING_SIZE *
581 bp->rx_max_pg_ring);
582 }
583
584 for (i = 0; i < bp->rx_max_pg_ring; i++) {
585 bp->rx_pg_desc_ring[i] =
586 pci_alloc_consistent(bp->pdev, RXBD_RING_SIZE,
587 &bp->rx_pg_desc_mapping[i]);
588 if (bp->rx_pg_desc_ring[i] == NULL)
589 goto alloc_mem_err;
590
591 }
592
Michael Chan0f31f992006-03-23 01:12:38 -0800593 /* Combine status and statistics blocks into one allocation. */
594 status_blk_size = L1_CACHE_ALIGN(sizeof(struct status_block));
David S. Millerf86e82f2008-01-21 17:15:40 -0800595 if (bp->flags & BNX2_FLAG_MSIX_CAP)
Michael Chanb4b36042007-12-20 19:59:30 -0800596 status_blk_size = L1_CACHE_ALIGN(BNX2_MAX_MSIX_HW_VEC *
597 BNX2_SBLK_MSIX_ALIGN_SIZE);
Michael Chan0f31f992006-03-23 01:12:38 -0800598 bp->status_stats_size = status_blk_size +
599 sizeof(struct statistics_block);
600
601 bp->status_blk = pci_alloc_consistent(bp->pdev, bp->status_stats_size,
Michael Chanb6016b72005-05-26 13:03:09 -0700602 &bp->status_blk_mapping);
603 if (bp->status_blk == NULL)
604 goto alloc_mem_err;
605
Michael Chan0f31f992006-03-23 01:12:38 -0800606 memset(bp->status_blk, 0, bp->status_stats_size);
Michael Chanb6016b72005-05-26 13:03:09 -0700607
Michael Chanb4b36042007-12-20 19:59:30 -0800608 bp->bnx2_napi[0].status_blk = bp->status_blk;
David S. Millerf86e82f2008-01-21 17:15:40 -0800609 if (bp->flags & BNX2_FLAG_MSIX_CAP) {
Michael Chanb4b36042007-12-20 19:59:30 -0800610 for (i = 1; i < BNX2_MAX_MSIX_VEC; i++) {
611 struct bnx2_napi *bnapi = &bp->bnx2_napi[i];
612
Michael Chan57851d82007-12-20 20:01:44 -0800613 bnapi->status_blk_msix = (void *)
Michael Chanb4b36042007-12-20 19:59:30 -0800614 ((unsigned long) bp->status_blk +
615 BNX2_SBLK_MSIX_ALIGN_SIZE * i);
616 bnapi->int_num = i << 24;
617 }
618 }
Michael Chan35efa7c2007-12-20 19:56:37 -0800619
Michael Chan0f31f992006-03-23 01:12:38 -0800620 bp->stats_blk = (void *) ((unsigned long) bp->status_blk +
621 status_blk_size);
Michael Chanb6016b72005-05-26 13:03:09 -0700622
Michael Chan0f31f992006-03-23 01:12:38 -0800623 bp->stats_blk_mapping = bp->status_blk_mapping + status_blk_size;
Michael Chanb6016b72005-05-26 13:03:09 -0700624
Michael Chan59b47d82006-11-19 14:10:45 -0800625 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
626 bp->ctx_pages = 0x2000 / BCM_PAGE_SIZE;
627 if (bp->ctx_pages == 0)
628 bp->ctx_pages = 1;
629 for (i = 0; i < bp->ctx_pages; i++) {
630 bp->ctx_blk[i] = pci_alloc_consistent(bp->pdev,
631 BCM_PAGE_SIZE,
632 &bp->ctx_blk_mapping[i]);
633 if (bp->ctx_blk[i] == NULL)
634 goto alloc_mem_err;
635 }
636 }
Michael Chanb6016b72005-05-26 13:03:09 -0700637 return 0;
638
639alloc_mem_err:
640 bnx2_free_mem(bp);
641 return -ENOMEM;
642}
643
644static void
Michael Chane3648b32005-11-04 08:51:21 -0800645bnx2_report_fw_link(struct bnx2 *bp)
646{
647 u32 fw_link_status = 0;
648
Michael Chan583c28e2008-01-21 19:51:35 -0800649 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
Michael Chan0d8a6572007-07-07 22:49:43 -0700650 return;
651
Michael Chane3648b32005-11-04 08:51:21 -0800652 if (bp->link_up) {
653 u32 bmsr;
654
655 switch (bp->line_speed) {
656 case SPEED_10:
657 if (bp->duplex == DUPLEX_HALF)
658 fw_link_status = BNX2_LINK_STATUS_10HALF;
659 else
660 fw_link_status = BNX2_LINK_STATUS_10FULL;
661 break;
662 case SPEED_100:
663 if (bp->duplex == DUPLEX_HALF)
664 fw_link_status = BNX2_LINK_STATUS_100HALF;
665 else
666 fw_link_status = BNX2_LINK_STATUS_100FULL;
667 break;
668 case SPEED_1000:
669 if (bp->duplex == DUPLEX_HALF)
670 fw_link_status = BNX2_LINK_STATUS_1000HALF;
671 else
672 fw_link_status = BNX2_LINK_STATUS_1000FULL;
673 break;
674 case SPEED_2500:
675 if (bp->duplex == DUPLEX_HALF)
676 fw_link_status = BNX2_LINK_STATUS_2500HALF;
677 else
678 fw_link_status = BNX2_LINK_STATUS_2500FULL;
679 break;
680 }
681
682 fw_link_status |= BNX2_LINK_STATUS_LINK_UP;
683
684 if (bp->autoneg) {
685 fw_link_status |= BNX2_LINK_STATUS_AN_ENABLED;
686
Michael Chanca58c3a2007-05-03 13:22:52 -0700687 bnx2_read_phy(bp, bp->mii_bmsr, &bmsr);
688 bnx2_read_phy(bp, bp->mii_bmsr, &bmsr);
Michael Chane3648b32005-11-04 08:51:21 -0800689
690 if (!(bmsr & BMSR_ANEGCOMPLETE) ||
Michael Chan583c28e2008-01-21 19:51:35 -0800691 bp->phy_flags & BNX2_PHY_FLAG_PARALLEL_DETECT)
Michael Chane3648b32005-11-04 08:51:21 -0800692 fw_link_status |= BNX2_LINK_STATUS_PARALLEL_DET;
693 else
694 fw_link_status |= BNX2_LINK_STATUS_AN_COMPLETE;
695 }
696 }
697 else
698 fw_link_status = BNX2_LINK_STATUS_LINK_DOWN;
699
Michael Chan2726d6e2008-01-29 21:35:05 -0800700 bnx2_shmem_wr(bp, BNX2_LINK_STATUS, fw_link_status);
Michael Chane3648b32005-11-04 08:51:21 -0800701}
702
Michael Chan9b1084b2007-07-07 22:50:37 -0700703static char *
704bnx2_xceiver_str(struct bnx2 *bp)
705{
706 return ((bp->phy_port == PORT_FIBRE) ? "SerDes" :
Michael Chan583c28e2008-01-21 19:51:35 -0800707 ((bp->phy_flags & BNX2_PHY_FLAG_SERDES) ? "Remote Copper" :
Michael Chan9b1084b2007-07-07 22:50:37 -0700708 "Copper"));
709}
710
Michael Chane3648b32005-11-04 08:51:21 -0800711static void
Michael Chanb6016b72005-05-26 13:03:09 -0700712bnx2_report_link(struct bnx2 *bp)
713{
714 if (bp->link_up) {
715 netif_carrier_on(bp->dev);
Michael Chan9b1084b2007-07-07 22:50:37 -0700716 printk(KERN_INFO PFX "%s NIC %s Link is Up, ", bp->dev->name,
717 bnx2_xceiver_str(bp));
Michael Chanb6016b72005-05-26 13:03:09 -0700718
719 printk("%d Mbps ", bp->line_speed);
720
721 if (bp->duplex == DUPLEX_FULL)
722 printk("full duplex");
723 else
724 printk("half duplex");
725
726 if (bp->flow_ctrl) {
727 if (bp->flow_ctrl & FLOW_CTRL_RX) {
728 printk(", receive ");
729 if (bp->flow_ctrl & FLOW_CTRL_TX)
730 printk("& transmit ");
731 }
732 else {
733 printk(", transmit ");
734 }
735 printk("flow control ON");
736 }
737 printk("\n");
738 }
739 else {
740 netif_carrier_off(bp->dev);
Michael Chan9b1084b2007-07-07 22:50:37 -0700741 printk(KERN_ERR PFX "%s NIC %s Link is Down\n", bp->dev->name,
742 bnx2_xceiver_str(bp));
Michael Chanb6016b72005-05-26 13:03:09 -0700743 }
Michael Chane3648b32005-11-04 08:51:21 -0800744
745 bnx2_report_fw_link(bp);
Michael Chanb6016b72005-05-26 13:03:09 -0700746}
747
748static void
749bnx2_resolve_flow_ctrl(struct bnx2 *bp)
750{
751 u32 local_adv, remote_adv;
752
753 bp->flow_ctrl = 0;
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400754 if ((bp->autoneg & (AUTONEG_SPEED | AUTONEG_FLOW_CTRL)) !=
Michael Chanb6016b72005-05-26 13:03:09 -0700755 (AUTONEG_SPEED | AUTONEG_FLOW_CTRL)) {
756
757 if (bp->duplex == DUPLEX_FULL) {
758 bp->flow_ctrl = bp->req_flow_ctrl;
759 }
760 return;
761 }
762
763 if (bp->duplex != DUPLEX_FULL) {
764 return;
765 }
766
Michael Chan583c28e2008-01-21 19:51:35 -0800767 if ((bp->phy_flags & BNX2_PHY_FLAG_SERDES) &&
Michael Chan5b0c76a2005-11-04 08:45:49 -0800768 (CHIP_NUM(bp) == CHIP_NUM_5708)) {
769 u32 val;
770
771 bnx2_read_phy(bp, BCM5708S_1000X_STAT1, &val);
772 if (val & BCM5708S_1000X_STAT1_TX_PAUSE)
773 bp->flow_ctrl |= FLOW_CTRL_TX;
774 if (val & BCM5708S_1000X_STAT1_RX_PAUSE)
775 bp->flow_ctrl |= FLOW_CTRL_RX;
776 return;
777 }
778
Michael Chanca58c3a2007-05-03 13:22:52 -0700779 bnx2_read_phy(bp, bp->mii_adv, &local_adv);
780 bnx2_read_phy(bp, bp->mii_lpa, &remote_adv);
Michael Chanb6016b72005-05-26 13:03:09 -0700781
Michael Chan583c28e2008-01-21 19:51:35 -0800782 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Michael Chanb6016b72005-05-26 13:03:09 -0700783 u32 new_local_adv = 0;
784 u32 new_remote_adv = 0;
785
786 if (local_adv & ADVERTISE_1000XPAUSE)
787 new_local_adv |= ADVERTISE_PAUSE_CAP;
788 if (local_adv & ADVERTISE_1000XPSE_ASYM)
789 new_local_adv |= ADVERTISE_PAUSE_ASYM;
790 if (remote_adv & ADVERTISE_1000XPAUSE)
791 new_remote_adv |= ADVERTISE_PAUSE_CAP;
792 if (remote_adv & ADVERTISE_1000XPSE_ASYM)
793 new_remote_adv |= ADVERTISE_PAUSE_ASYM;
794
795 local_adv = new_local_adv;
796 remote_adv = new_remote_adv;
797 }
798
799 /* See Table 28B-3 of 802.3ab-1999 spec. */
800 if (local_adv & ADVERTISE_PAUSE_CAP) {
801 if(local_adv & ADVERTISE_PAUSE_ASYM) {
802 if (remote_adv & ADVERTISE_PAUSE_CAP) {
803 bp->flow_ctrl = FLOW_CTRL_TX | FLOW_CTRL_RX;
804 }
805 else if (remote_adv & ADVERTISE_PAUSE_ASYM) {
806 bp->flow_ctrl = FLOW_CTRL_RX;
807 }
808 }
809 else {
810 if (remote_adv & ADVERTISE_PAUSE_CAP) {
811 bp->flow_ctrl = FLOW_CTRL_TX | FLOW_CTRL_RX;
812 }
813 }
814 }
815 else if (local_adv & ADVERTISE_PAUSE_ASYM) {
816 if ((remote_adv & ADVERTISE_PAUSE_CAP) &&
817 (remote_adv & ADVERTISE_PAUSE_ASYM)) {
818
819 bp->flow_ctrl = FLOW_CTRL_TX;
820 }
821 }
822}
823
824static int
Michael Chan27a005b2007-05-03 13:23:41 -0700825bnx2_5709s_linkup(struct bnx2 *bp)
826{
827 u32 val, speed;
828
829 bp->link_up = 1;
830
831 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_GP_STATUS);
832 bnx2_read_phy(bp, MII_BNX2_GP_TOP_AN_STATUS1, &val);
833 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
834
835 if ((bp->autoneg & AUTONEG_SPEED) == 0) {
836 bp->line_speed = bp->req_line_speed;
837 bp->duplex = bp->req_duplex;
838 return 0;
839 }
840 speed = val & MII_BNX2_GP_TOP_AN_SPEED_MSK;
841 switch (speed) {
842 case MII_BNX2_GP_TOP_AN_SPEED_10:
843 bp->line_speed = SPEED_10;
844 break;
845 case MII_BNX2_GP_TOP_AN_SPEED_100:
846 bp->line_speed = SPEED_100;
847 break;
848 case MII_BNX2_GP_TOP_AN_SPEED_1G:
849 case MII_BNX2_GP_TOP_AN_SPEED_1GKV:
850 bp->line_speed = SPEED_1000;
851 break;
852 case MII_BNX2_GP_TOP_AN_SPEED_2_5G:
853 bp->line_speed = SPEED_2500;
854 break;
855 }
856 if (val & MII_BNX2_GP_TOP_AN_FD)
857 bp->duplex = DUPLEX_FULL;
858 else
859 bp->duplex = DUPLEX_HALF;
860 return 0;
861}
862
863static int
Michael Chan5b0c76a2005-11-04 08:45:49 -0800864bnx2_5708s_linkup(struct bnx2 *bp)
865{
866 u32 val;
867
868 bp->link_up = 1;
869 bnx2_read_phy(bp, BCM5708S_1000X_STAT1, &val);
870 switch (val & BCM5708S_1000X_STAT1_SPEED_MASK) {
871 case BCM5708S_1000X_STAT1_SPEED_10:
872 bp->line_speed = SPEED_10;
873 break;
874 case BCM5708S_1000X_STAT1_SPEED_100:
875 bp->line_speed = SPEED_100;
876 break;
877 case BCM5708S_1000X_STAT1_SPEED_1G:
878 bp->line_speed = SPEED_1000;
879 break;
880 case BCM5708S_1000X_STAT1_SPEED_2G5:
881 bp->line_speed = SPEED_2500;
882 break;
883 }
884 if (val & BCM5708S_1000X_STAT1_FD)
885 bp->duplex = DUPLEX_FULL;
886 else
887 bp->duplex = DUPLEX_HALF;
888
889 return 0;
890}
891
892static int
893bnx2_5706s_linkup(struct bnx2 *bp)
Michael Chanb6016b72005-05-26 13:03:09 -0700894{
895 u32 bmcr, local_adv, remote_adv, common;
896
897 bp->link_up = 1;
898 bp->line_speed = SPEED_1000;
899
Michael Chanca58c3a2007-05-03 13:22:52 -0700900 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chanb6016b72005-05-26 13:03:09 -0700901 if (bmcr & BMCR_FULLDPLX) {
902 bp->duplex = DUPLEX_FULL;
903 }
904 else {
905 bp->duplex = DUPLEX_HALF;
906 }
907
908 if (!(bmcr & BMCR_ANENABLE)) {
909 return 0;
910 }
911
Michael Chanca58c3a2007-05-03 13:22:52 -0700912 bnx2_read_phy(bp, bp->mii_adv, &local_adv);
913 bnx2_read_phy(bp, bp->mii_lpa, &remote_adv);
Michael Chanb6016b72005-05-26 13:03:09 -0700914
915 common = local_adv & remote_adv;
916 if (common & (ADVERTISE_1000XHALF | ADVERTISE_1000XFULL)) {
917
918 if (common & ADVERTISE_1000XFULL) {
919 bp->duplex = DUPLEX_FULL;
920 }
921 else {
922 bp->duplex = DUPLEX_HALF;
923 }
924 }
925
926 return 0;
927}
928
929static int
930bnx2_copper_linkup(struct bnx2 *bp)
931{
932 u32 bmcr;
933
Michael Chanca58c3a2007-05-03 13:22:52 -0700934 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chanb6016b72005-05-26 13:03:09 -0700935 if (bmcr & BMCR_ANENABLE) {
936 u32 local_adv, remote_adv, common;
937
938 bnx2_read_phy(bp, MII_CTRL1000, &local_adv);
939 bnx2_read_phy(bp, MII_STAT1000, &remote_adv);
940
941 common = local_adv & (remote_adv >> 2);
942 if (common & ADVERTISE_1000FULL) {
943 bp->line_speed = SPEED_1000;
944 bp->duplex = DUPLEX_FULL;
945 }
946 else if (common & ADVERTISE_1000HALF) {
947 bp->line_speed = SPEED_1000;
948 bp->duplex = DUPLEX_HALF;
949 }
950 else {
Michael Chanca58c3a2007-05-03 13:22:52 -0700951 bnx2_read_phy(bp, bp->mii_adv, &local_adv);
952 bnx2_read_phy(bp, bp->mii_lpa, &remote_adv);
Michael Chanb6016b72005-05-26 13:03:09 -0700953
954 common = local_adv & remote_adv;
955 if (common & ADVERTISE_100FULL) {
956 bp->line_speed = SPEED_100;
957 bp->duplex = DUPLEX_FULL;
958 }
959 else if (common & ADVERTISE_100HALF) {
960 bp->line_speed = SPEED_100;
961 bp->duplex = DUPLEX_HALF;
962 }
963 else if (common & ADVERTISE_10FULL) {
964 bp->line_speed = SPEED_10;
965 bp->duplex = DUPLEX_FULL;
966 }
967 else if (common & ADVERTISE_10HALF) {
968 bp->line_speed = SPEED_10;
969 bp->duplex = DUPLEX_HALF;
970 }
971 else {
972 bp->line_speed = 0;
973 bp->link_up = 0;
974 }
975 }
976 }
977 else {
978 if (bmcr & BMCR_SPEED100) {
979 bp->line_speed = SPEED_100;
980 }
981 else {
982 bp->line_speed = SPEED_10;
983 }
984 if (bmcr & BMCR_FULLDPLX) {
985 bp->duplex = DUPLEX_FULL;
986 }
987 else {
988 bp->duplex = DUPLEX_HALF;
989 }
990 }
991
992 return 0;
993}
994
Michael Chan83e3fc82008-01-29 21:37:17 -0800995static void
996bnx2_init_rx_context0(struct bnx2 *bp)
997{
998 u32 val, rx_cid_addr = GET_CID_ADDR(RX_CID);
999
1000 val = BNX2_L2CTX_CTX_TYPE_CTX_BD_CHN_TYPE_VALUE;
1001 val |= BNX2_L2CTX_CTX_TYPE_SIZE_L2;
1002 val |= 0x02 << 8;
1003
1004 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
1005 u32 lo_water, hi_water;
1006
1007 if (bp->flow_ctrl & FLOW_CTRL_TX)
1008 lo_water = BNX2_L2CTX_LO_WATER_MARK_DEFAULT;
1009 else
1010 lo_water = BNX2_L2CTX_LO_WATER_MARK_DIS;
1011 if (lo_water >= bp->rx_ring_size)
1012 lo_water = 0;
1013
1014 hi_water = bp->rx_ring_size / 4;
1015
1016 if (hi_water <= lo_water)
1017 lo_water = 0;
1018
1019 hi_water /= BNX2_L2CTX_HI_WATER_MARK_SCALE;
1020 lo_water /= BNX2_L2CTX_LO_WATER_MARK_SCALE;
1021
1022 if (hi_water > 0xf)
1023 hi_water = 0xf;
1024 else if (hi_water == 0)
1025 lo_water = 0;
1026 val |= lo_water | (hi_water << BNX2_L2CTX_HI_WATER_MARK_SHIFT);
1027 }
1028 bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_CTX_TYPE, val);
1029}
1030
Michael Chanb6016b72005-05-26 13:03:09 -07001031static int
1032bnx2_set_mac_link(struct bnx2 *bp)
1033{
1034 u32 val;
1035
1036 REG_WR(bp, BNX2_EMAC_TX_LENGTHS, 0x2620);
1037 if (bp->link_up && (bp->line_speed == SPEED_1000) &&
1038 (bp->duplex == DUPLEX_HALF)) {
1039 REG_WR(bp, BNX2_EMAC_TX_LENGTHS, 0x26ff);
1040 }
1041
1042 /* Configure the EMAC mode register. */
1043 val = REG_RD(bp, BNX2_EMAC_MODE);
1044
1045 val &= ~(BNX2_EMAC_MODE_PORT | BNX2_EMAC_MODE_HALF_DUPLEX |
Michael Chan5b0c76a2005-11-04 08:45:49 -08001046 BNX2_EMAC_MODE_MAC_LOOP | BNX2_EMAC_MODE_FORCE_LINK |
Michael Chan59b47d82006-11-19 14:10:45 -08001047 BNX2_EMAC_MODE_25G_MODE);
Michael Chanb6016b72005-05-26 13:03:09 -07001048
1049 if (bp->link_up) {
Michael Chan5b0c76a2005-11-04 08:45:49 -08001050 switch (bp->line_speed) {
1051 case SPEED_10:
Michael Chan59b47d82006-11-19 14:10:45 -08001052 if (CHIP_NUM(bp) != CHIP_NUM_5706) {
1053 val |= BNX2_EMAC_MODE_PORT_MII_10M;
Michael Chan5b0c76a2005-11-04 08:45:49 -08001054 break;
1055 }
1056 /* fall through */
1057 case SPEED_100:
1058 val |= BNX2_EMAC_MODE_PORT_MII;
1059 break;
1060 case SPEED_2500:
Michael Chan59b47d82006-11-19 14:10:45 -08001061 val |= BNX2_EMAC_MODE_25G_MODE;
Michael Chan5b0c76a2005-11-04 08:45:49 -08001062 /* fall through */
1063 case SPEED_1000:
1064 val |= BNX2_EMAC_MODE_PORT_GMII;
1065 break;
1066 }
Michael Chanb6016b72005-05-26 13:03:09 -07001067 }
1068 else {
1069 val |= BNX2_EMAC_MODE_PORT_GMII;
1070 }
1071
1072 /* Set the MAC to operate in the appropriate duplex mode. */
1073 if (bp->duplex == DUPLEX_HALF)
1074 val |= BNX2_EMAC_MODE_HALF_DUPLEX;
1075 REG_WR(bp, BNX2_EMAC_MODE, val);
1076
1077 /* Enable/disable rx PAUSE. */
1078 bp->rx_mode &= ~BNX2_EMAC_RX_MODE_FLOW_EN;
1079
1080 if (bp->flow_ctrl & FLOW_CTRL_RX)
1081 bp->rx_mode |= BNX2_EMAC_RX_MODE_FLOW_EN;
1082 REG_WR(bp, BNX2_EMAC_RX_MODE, bp->rx_mode);
1083
1084 /* Enable/disable tx PAUSE. */
1085 val = REG_RD(bp, BNX2_EMAC_TX_MODE);
1086 val &= ~BNX2_EMAC_TX_MODE_FLOW_EN;
1087
1088 if (bp->flow_ctrl & FLOW_CTRL_TX)
1089 val |= BNX2_EMAC_TX_MODE_FLOW_EN;
1090 REG_WR(bp, BNX2_EMAC_TX_MODE, val);
1091
1092 /* Acknowledge the interrupt. */
1093 REG_WR(bp, BNX2_EMAC_STATUS, BNX2_EMAC_STATUS_LINK_CHANGE);
1094
Michael Chan83e3fc82008-01-29 21:37:17 -08001095 if (CHIP_NUM(bp) == CHIP_NUM_5709)
1096 bnx2_init_rx_context0(bp);
1097
Michael Chanb6016b72005-05-26 13:03:09 -07001098 return 0;
1099}
1100
Michael Chan27a005b2007-05-03 13:23:41 -07001101static void
1102bnx2_enable_bmsr1(struct bnx2 *bp)
1103{
Michael Chan583c28e2008-01-21 19:51:35 -08001104 if ((bp->phy_flags & BNX2_PHY_FLAG_SERDES) &&
Michael Chan27a005b2007-05-03 13:23:41 -07001105 (CHIP_NUM(bp) == CHIP_NUM_5709))
1106 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
1107 MII_BNX2_BLK_ADDR_GP_STATUS);
1108}
1109
1110static void
1111bnx2_disable_bmsr1(struct bnx2 *bp)
1112{
Michael Chan583c28e2008-01-21 19:51:35 -08001113 if ((bp->phy_flags & BNX2_PHY_FLAG_SERDES) &&
Michael Chan27a005b2007-05-03 13:23:41 -07001114 (CHIP_NUM(bp) == CHIP_NUM_5709))
1115 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
1116 MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
1117}
1118
Michael Chanb6016b72005-05-26 13:03:09 -07001119static int
Michael Chan605a9e22007-05-03 13:23:13 -07001120bnx2_test_and_enable_2g5(struct bnx2 *bp)
1121{
1122 u32 up1;
1123 int ret = 1;
1124
Michael Chan583c28e2008-01-21 19:51:35 -08001125 if (!(bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE))
Michael Chan605a9e22007-05-03 13:23:13 -07001126 return 0;
1127
1128 if (bp->autoneg & AUTONEG_SPEED)
1129 bp->advertising |= ADVERTISED_2500baseX_Full;
1130
Michael Chan27a005b2007-05-03 13:23:41 -07001131 if (CHIP_NUM(bp) == CHIP_NUM_5709)
1132 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_OVER1G);
1133
Michael Chan605a9e22007-05-03 13:23:13 -07001134 bnx2_read_phy(bp, bp->mii_up1, &up1);
1135 if (!(up1 & BCM5708S_UP1_2G5)) {
1136 up1 |= BCM5708S_UP1_2G5;
1137 bnx2_write_phy(bp, bp->mii_up1, up1);
1138 ret = 0;
1139 }
1140
Michael Chan27a005b2007-05-03 13:23:41 -07001141 if (CHIP_NUM(bp) == CHIP_NUM_5709)
1142 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
1143 MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
1144
Michael Chan605a9e22007-05-03 13:23:13 -07001145 return ret;
1146}
1147
1148static int
1149bnx2_test_and_disable_2g5(struct bnx2 *bp)
1150{
1151 u32 up1;
1152 int ret = 0;
1153
Michael Chan583c28e2008-01-21 19:51:35 -08001154 if (!(bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE))
Michael Chan605a9e22007-05-03 13:23:13 -07001155 return 0;
1156
Michael Chan27a005b2007-05-03 13:23:41 -07001157 if (CHIP_NUM(bp) == CHIP_NUM_5709)
1158 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_OVER1G);
1159
Michael Chan605a9e22007-05-03 13:23:13 -07001160 bnx2_read_phy(bp, bp->mii_up1, &up1);
1161 if (up1 & BCM5708S_UP1_2G5) {
1162 up1 &= ~BCM5708S_UP1_2G5;
1163 bnx2_write_phy(bp, bp->mii_up1, up1);
1164 ret = 1;
1165 }
1166
Michael Chan27a005b2007-05-03 13:23:41 -07001167 if (CHIP_NUM(bp) == CHIP_NUM_5709)
1168 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
1169 MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
1170
Michael Chan605a9e22007-05-03 13:23:13 -07001171 return ret;
1172}
1173
1174static void
1175bnx2_enable_forced_2g5(struct bnx2 *bp)
1176{
1177 u32 bmcr;
1178
Michael Chan583c28e2008-01-21 19:51:35 -08001179 if (!(bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE))
Michael Chan605a9e22007-05-03 13:23:13 -07001180 return;
1181
Michael Chan27a005b2007-05-03 13:23:41 -07001182 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
1183 u32 val;
1184
1185 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
1186 MII_BNX2_BLK_ADDR_SERDES_DIG);
1187 bnx2_read_phy(bp, MII_BNX2_SERDES_DIG_MISC1, &val);
1188 val &= ~MII_BNX2_SD_MISC1_FORCE_MSK;
1189 val |= MII_BNX2_SD_MISC1_FORCE | MII_BNX2_SD_MISC1_FORCE_2_5G;
1190 bnx2_write_phy(bp, MII_BNX2_SERDES_DIG_MISC1, val);
1191
1192 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
1193 MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
1194 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
1195
1196 } else if (CHIP_NUM(bp) == CHIP_NUM_5708) {
Michael Chan605a9e22007-05-03 13:23:13 -07001197 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
1198 bmcr |= BCM5708S_BMCR_FORCE_2500;
1199 }
1200
1201 if (bp->autoneg & AUTONEG_SPEED) {
1202 bmcr &= ~BMCR_ANENABLE;
1203 if (bp->req_duplex == DUPLEX_FULL)
1204 bmcr |= BMCR_FULLDPLX;
1205 }
1206 bnx2_write_phy(bp, bp->mii_bmcr, bmcr);
1207}
1208
1209static void
1210bnx2_disable_forced_2g5(struct bnx2 *bp)
1211{
1212 u32 bmcr;
1213
Michael Chan583c28e2008-01-21 19:51:35 -08001214 if (!(bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE))
Michael Chan605a9e22007-05-03 13:23:13 -07001215 return;
1216
Michael Chan27a005b2007-05-03 13:23:41 -07001217 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
1218 u32 val;
1219
1220 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
1221 MII_BNX2_BLK_ADDR_SERDES_DIG);
1222 bnx2_read_phy(bp, MII_BNX2_SERDES_DIG_MISC1, &val);
1223 val &= ~MII_BNX2_SD_MISC1_FORCE;
1224 bnx2_write_phy(bp, MII_BNX2_SERDES_DIG_MISC1, val);
1225
1226 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
1227 MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
1228 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
1229
1230 } else if (CHIP_NUM(bp) == CHIP_NUM_5708) {
Michael Chan605a9e22007-05-03 13:23:13 -07001231 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
1232 bmcr &= ~BCM5708S_BMCR_FORCE_2500;
1233 }
1234
1235 if (bp->autoneg & AUTONEG_SPEED)
1236 bmcr |= BMCR_SPEED1000 | BMCR_ANENABLE | BMCR_ANRESTART;
1237 bnx2_write_phy(bp, bp->mii_bmcr, bmcr);
1238}
1239
Michael Chanb2fadea2008-01-21 17:07:06 -08001240static void
1241bnx2_5706s_force_link_dn(struct bnx2 *bp, int start)
1242{
1243 u32 val;
1244
1245 bnx2_write_phy(bp, MII_BNX2_DSP_ADDRESS, MII_EXPAND_SERDES_CTL);
1246 bnx2_read_phy(bp, MII_BNX2_DSP_RW_PORT, &val);
1247 if (start)
1248 bnx2_write_phy(bp, MII_BNX2_DSP_RW_PORT, val & 0xff0f);
1249 else
1250 bnx2_write_phy(bp, MII_BNX2_DSP_RW_PORT, val | 0xc0);
1251}
1252
Michael Chan605a9e22007-05-03 13:23:13 -07001253static int
Michael Chanb6016b72005-05-26 13:03:09 -07001254bnx2_set_link(struct bnx2 *bp)
1255{
1256 u32 bmsr;
1257 u8 link_up;
1258
Michael Chan80be4432006-11-19 14:07:28 -08001259 if (bp->loopback == MAC_LOOPBACK || bp->loopback == PHY_LOOPBACK) {
Michael Chanb6016b72005-05-26 13:03:09 -07001260 bp->link_up = 1;
1261 return 0;
1262 }
1263
Michael Chan583c28e2008-01-21 19:51:35 -08001264 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
Michael Chan0d8a6572007-07-07 22:49:43 -07001265 return 0;
1266
Michael Chanb6016b72005-05-26 13:03:09 -07001267 link_up = bp->link_up;
1268
Michael Chan27a005b2007-05-03 13:23:41 -07001269 bnx2_enable_bmsr1(bp);
1270 bnx2_read_phy(bp, bp->mii_bmsr1, &bmsr);
1271 bnx2_read_phy(bp, bp->mii_bmsr1, &bmsr);
1272 bnx2_disable_bmsr1(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07001273
Michael Chan583c28e2008-01-21 19:51:35 -08001274 if ((bp->phy_flags & BNX2_PHY_FLAG_SERDES) &&
Michael Chanb6016b72005-05-26 13:03:09 -07001275 (CHIP_NUM(bp) == CHIP_NUM_5706)) {
Michael Chana2724e22008-02-23 19:47:44 -08001276 u32 val, an_dbg;
Michael Chanb6016b72005-05-26 13:03:09 -07001277
Michael Chan583c28e2008-01-21 19:51:35 -08001278 if (bp->phy_flags & BNX2_PHY_FLAG_FORCED_DOWN) {
Michael Chanb2fadea2008-01-21 17:07:06 -08001279 bnx2_5706s_force_link_dn(bp, 0);
Michael Chan583c28e2008-01-21 19:51:35 -08001280 bp->phy_flags &= ~BNX2_PHY_FLAG_FORCED_DOWN;
Michael Chanb2fadea2008-01-21 17:07:06 -08001281 }
Michael Chanb6016b72005-05-26 13:03:09 -07001282 val = REG_RD(bp, BNX2_EMAC_STATUS);
Michael Chana2724e22008-02-23 19:47:44 -08001283
1284 bnx2_write_phy(bp, MII_BNX2_MISC_SHADOW, MISC_SHDW_AN_DBG);
1285 bnx2_read_phy(bp, MII_BNX2_MISC_SHADOW, &an_dbg);
1286 bnx2_read_phy(bp, MII_BNX2_MISC_SHADOW, &an_dbg);
1287
1288 if ((val & BNX2_EMAC_STATUS_LINK) &&
1289 !(an_dbg & MISC_SHDW_AN_DBG_NOSYNC))
Michael Chanb6016b72005-05-26 13:03:09 -07001290 bmsr |= BMSR_LSTATUS;
1291 else
1292 bmsr &= ~BMSR_LSTATUS;
1293 }
1294
1295 if (bmsr & BMSR_LSTATUS) {
1296 bp->link_up = 1;
1297
Michael Chan583c28e2008-01-21 19:51:35 -08001298 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Michael Chan5b0c76a2005-11-04 08:45:49 -08001299 if (CHIP_NUM(bp) == CHIP_NUM_5706)
1300 bnx2_5706s_linkup(bp);
1301 else if (CHIP_NUM(bp) == CHIP_NUM_5708)
1302 bnx2_5708s_linkup(bp);
Michael Chan27a005b2007-05-03 13:23:41 -07001303 else if (CHIP_NUM(bp) == CHIP_NUM_5709)
1304 bnx2_5709s_linkup(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07001305 }
1306 else {
1307 bnx2_copper_linkup(bp);
1308 }
1309 bnx2_resolve_flow_ctrl(bp);
1310 }
1311 else {
Michael Chan583c28e2008-01-21 19:51:35 -08001312 if ((bp->phy_flags & BNX2_PHY_FLAG_SERDES) &&
Michael Chan605a9e22007-05-03 13:23:13 -07001313 (bp->autoneg & AUTONEG_SPEED))
1314 bnx2_disable_forced_2g5(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07001315
Michael Chan583c28e2008-01-21 19:51:35 -08001316 if (bp->phy_flags & BNX2_PHY_FLAG_PARALLEL_DETECT) {
Michael Chanb2fadea2008-01-21 17:07:06 -08001317 u32 bmcr;
1318
1319 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
1320 bmcr |= BMCR_ANENABLE;
1321 bnx2_write_phy(bp, bp->mii_bmcr, bmcr);
1322
Michael Chan583c28e2008-01-21 19:51:35 -08001323 bp->phy_flags &= ~BNX2_PHY_FLAG_PARALLEL_DETECT;
Michael Chanb2fadea2008-01-21 17:07:06 -08001324 }
Michael Chanb6016b72005-05-26 13:03:09 -07001325 bp->link_up = 0;
1326 }
1327
1328 if (bp->link_up != link_up) {
1329 bnx2_report_link(bp);
1330 }
1331
1332 bnx2_set_mac_link(bp);
1333
1334 return 0;
1335}
1336
1337static int
1338bnx2_reset_phy(struct bnx2 *bp)
1339{
1340 int i;
1341 u32 reg;
1342
Michael Chanca58c3a2007-05-03 13:22:52 -07001343 bnx2_write_phy(bp, bp->mii_bmcr, BMCR_RESET);
Michael Chanb6016b72005-05-26 13:03:09 -07001344
1345#define PHY_RESET_MAX_WAIT 100
1346 for (i = 0; i < PHY_RESET_MAX_WAIT; i++) {
1347 udelay(10);
1348
Michael Chanca58c3a2007-05-03 13:22:52 -07001349 bnx2_read_phy(bp, bp->mii_bmcr, &reg);
Michael Chanb6016b72005-05-26 13:03:09 -07001350 if (!(reg & BMCR_RESET)) {
1351 udelay(20);
1352 break;
1353 }
1354 }
1355 if (i == PHY_RESET_MAX_WAIT) {
1356 return -EBUSY;
1357 }
1358 return 0;
1359}
1360
1361static u32
1362bnx2_phy_get_pause_adv(struct bnx2 *bp)
1363{
1364 u32 adv = 0;
1365
1366 if ((bp->req_flow_ctrl & (FLOW_CTRL_RX | FLOW_CTRL_TX)) ==
1367 (FLOW_CTRL_RX | FLOW_CTRL_TX)) {
1368
Michael Chan583c28e2008-01-21 19:51:35 -08001369 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Michael Chanb6016b72005-05-26 13:03:09 -07001370 adv = ADVERTISE_1000XPAUSE;
1371 }
1372 else {
1373 adv = ADVERTISE_PAUSE_CAP;
1374 }
1375 }
1376 else if (bp->req_flow_ctrl & FLOW_CTRL_TX) {
Michael Chan583c28e2008-01-21 19:51:35 -08001377 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Michael Chanb6016b72005-05-26 13:03:09 -07001378 adv = ADVERTISE_1000XPSE_ASYM;
1379 }
1380 else {
1381 adv = ADVERTISE_PAUSE_ASYM;
1382 }
1383 }
1384 else if (bp->req_flow_ctrl & FLOW_CTRL_RX) {
Michael Chan583c28e2008-01-21 19:51:35 -08001385 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Michael Chanb6016b72005-05-26 13:03:09 -07001386 adv = ADVERTISE_1000XPAUSE | ADVERTISE_1000XPSE_ASYM;
1387 }
1388 else {
1389 adv = ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM;
1390 }
1391 }
1392 return adv;
1393}
1394
Michael Chan0d8a6572007-07-07 22:49:43 -07001395static int bnx2_fw_sync(struct bnx2 *, u32, int);
1396
Michael Chanb6016b72005-05-26 13:03:09 -07001397static int
Michael Chan0d8a6572007-07-07 22:49:43 -07001398bnx2_setup_remote_phy(struct bnx2 *bp, u8 port)
1399{
1400 u32 speed_arg = 0, pause_adv;
1401
1402 pause_adv = bnx2_phy_get_pause_adv(bp);
1403
1404 if (bp->autoneg & AUTONEG_SPEED) {
1405 speed_arg |= BNX2_NETLINK_SET_LINK_ENABLE_AUTONEG;
1406 if (bp->advertising & ADVERTISED_10baseT_Half)
1407 speed_arg |= BNX2_NETLINK_SET_LINK_SPEED_10HALF;
1408 if (bp->advertising & ADVERTISED_10baseT_Full)
1409 speed_arg |= BNX2_NETLINK_SET_LINK_SPEED_10FULL;
1410 if (bp->advertising & ADVERTISED_100baseT_Half)
1411 speed_arg |= BNX2_NETLINK_SET_LINK_SPEED_100HALF;
1412 if (bp->advertising & ADVERTISED_100baseT_Full)
1413 speed_arg |= BNX2_NETLINK_SET_LINK_SPEED_100FULL;
1414 if (bp->advertising & ADVERTISED_1000baseT_Full)
1415 speed_arg |= BNX2_NETLINK_SET_LINK_SPEED_1GFULL;
1416 if (bp->advertising & ADVERTISED_2500baseX_Full)
1417 speed_arg |= BNX2_NETLINK_SET_LINK_SPEED_2G5FULL;
1418 } else {
1419 if (bp->req_line_speed == SPEED_2500)
1420 speed_arg = BNX2_NETLINK_SET_LINK_SPEED_2G5FULL;
1421 else if (bp->req_line_speed == SPEED_1000)
1422 speed_arg = BNX2_NETLINK_SET_LINK_SPEED_1GFULL;
1423 else if (bp->req_line_speed == SPEED_100) {
1424 if (bp->req_duplex == DUPLEX_FULL)
1425 speed_arg = BNX2_NETLINK_SET_LINK_SPEED_100FULL;
1426 else
1427 speed_arg = BNX2_NETLINK_SET_LINK_SPEED_100HALF;
1428 } else if (bp->req_line_speed == SPEED_10) {
1429 if (bp->req_duplex == DUPLEX_FULL)
1430 speed_arg = BNX2_NETLINK_SET_LINK_SPEED_10FULL;
1431 else
1432 speed_arg = BNX2_NETLINK_SET_LINK_SPEED_10HALF;
1433 }
1434 }
1435
1436 if (pause_adv & (ADVERTISE_1000XPAUSE | ADVERTISE_PAUSE_CAP))
1437 speed_arg |= BNX2_NETLINK_SET_LINK_FC_SYM_PAUSE;
Michael Chanc26736e2008-01-31 17:07:21 -08001438 if (pause_adv & (ADVERTISE_1000XPSE_ASYM | ADVERTISE_PAUSE_ASYM))
Michael Chan0d8a6572007-07-07 22:49:43 -07001439 speed_arg |= BNX2_NETLINK_SET_LINK_FC_ASYM_PAUSE;
1440
1441 if (port == PORT_TP)
1442 speed_arg |= BNX2_NETLINK_SET_LINK_PHY_APP_REMOTE |
1443 BNX2_NETLINK_SET_LINK_ETH_AT_WIRESPEED;
1444
Michael Chan2726d6e2008-01-29 21:35:05 -08001445 bnx2_shmem_wr(bp, BNX2_DRV_MB_ARG0, speed_arg);
Michael Chan0d8a6572007-07-07 22:49:43 -07001446
1447 spin_unlock_bh(&bp->phy_lock);
1448 bnx2_fw_sync(bp, BNX2_DRV_MSG_CODE_CMD_SET_LINK, 0);
1449 spin_lock_bh(&bp->phy_lock);
1450
1451 return 0;
1452}
1453
1454static int
1455bnx2_setup_serdes_phy(struct bnx2 *bp, u8 port)
Michael Chanb6016b72005-05-26 13:03:09 -07001456{
Michael Chan605a9e22007-05-03 13:23:13 -07001457 u32 adv, bmcr;
Michael Chanb6016b72005-05-26 13:03:09 -07001458 u32 new_adv = 0;
1459
Michael Chan583c28e2008-01-21 19:51:35 -08001460 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
Michael Chan0d8a6572007-07-07 22:49:43 -07001461 return (bnx2_setup_remote_phy(bp, port));
1462
Michael Chanb6016b72005-05-26 13:03:09 -07001463 if (!(bp->autoneg & AUTONEG_SPEED)) {
1464 u32 new_bmcr;
Michael Chan5b0c76a2005-11-04 08:45:49 -08001465 int force_link_down = 0;
1466
Michael Chan605a9e22007-05-03 13:23:13 -07001467 if (bp->req_line_speed == SPEED_2500) {
1468 if (!bnx2_test_and_enable_2g5(bp))
1469 force_link_down = 1;
1470 } else if (bp->req_line_speed == SPEED_1000) {
1471 if (bnx2_test_and_disable_2g5(bp))
1472 force_link_down = 1;
1473 }
Michael Chanca58c3a2007-05-03 13:22:52 -07001474 bnx2_read_phy(bp, bp->mii_adv, &adv);
Michael Chan80be4432006-11-19 14:07:28 -08001475 adv &= ~(ADVERTISE_1000XFULL | ADVERTISE_1000XHALF);
1476
Michael Chanca58c3a2007-05-03 13:22:52 -07001477 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chan605a9e22007-05-03 13:23:13 -07001478 new_bmcr = bmcr & ~BMCR_ANENABLE;
Michael Chan80be4432006-11-19 14:07:28 -08001479 new_bmcr |= BMCR_SPEED1000;
Michael Chan605a9e22007-05-03 13:23:13 -07001480
Michael Chan27a005b2007-05-03 13:23:41 -07001481 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
1482 if (bp->req_line_speed == SPEED_2500)
1483 bnx2_enable_forced_2g5(bp);
1484 else if (bp->req_line_speed == SPEED_1000) {
1485 bnx2_disable_forced_2g5(bp);
1486 new_bmcr &= ~0x2000;
1487 }
1488
1489 } else if (CHIP_NUM(bp) == CHIP_NUM_5708) {
Michael Chan605a9e22007-05-03 13:23:13 -07001490 if (bp->req_line_speed == SPEED_2500)
1491 new_bmcr |= BCM5708S_BMCR_FORCE_2500;
1492 else
1493 new_bmcr = bmcr & ~BCM5708S_BMCR_FORCE_2500;
Michael Chan5b0c76a2005-11-04 08:45:49 -08001494 }
1495
Michael Chanb6016b72005-05-26 13:03:09 -07001496 if (bp->req_duplex == DUPLEX_FULL) {
Michael Chan5b0c76a2005-11-04 08:45:49 -08001497 adv |= ADVERTISE_1000XFULL;
Michael Chanb6016b72005-05-26 13:03:09 -07001498 new_bmcr |= BMCR_FULLDPLX;
1499 }
1500 else {
Michael Chan5b0c76a2005-11-04 08:45:49 -08001501 adv |= ADVERTISE_1000XHALF;
Michael Chanb6016b72005-05-26 13:03:09 -07001502 new_bmcr &= ~BMCR_FULLDPLX;
1503 }
Michael Chan5b0c76a2005-11-04 08:45:49 -08001504 if ((new_bmcr != bmcr) || (force_link_down)) {
Michael Chanb6016b72005-05-26 13:03:09 -07001505 /* Force a link down visible on the other side */
1506 if (bp->link_up) {
Michael Chanca58c3a2007-05-03 13:22:52 -07001507 bnx2_write_phy(bp, bp->mii_adv, adv &
Michael Chan5b0c76a2005-11-04 08:45:49 -08001508 ~(ADVERTISE_1000XFULL |
1509 ADVERTISE_1000XHALF));
Michael Chanca58c3a2007-05-03 13:22:52 -07001510 bnx2_write_phy(bp, bp->mii_bmcr, bmcr |
Michael Chanb6016b72005-05-26 13:03:09 -07001511 BMCR_ANRESTART | BMCR_ANENABLE);
1512
1513 bp->link_up = 0;
1514 netif_carrier_off(bp->dev);
Michael Chanca58c3a2007-05-03 13:22:52 -07001515 bnx2_write_phy(bp, bp->mii_bmcr, new_bmcr);
Michael Chan80be4432006-11-19 14:07:28 -08001516 bnx2_report_link(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07001517 }
Michael Chanca58c3a2007-05-03 13:22:52 -07001518 bnx2_write_phy(bp, bp->mii_adv, adv);
1519 bnx2_write_phy(bp, bp->mii_bmcr, new_bmcr);
Michael Chan605a9e22007-05-03 13:23:13 -07001520 } else {
1521 bnx2_resolve_flow_ctrl(bp);
1522 bnx2_set_mac_link(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07001523 }
1524 return 0;
1525 }
1526
Michael Chan605a9e22007-05-03 13:23:13 -07001527 bnx2_test_and_enable_2g5(bp);
Michael Chan5b0c76a2005-11-04 08:45:49 -08001528
Michael Chanb6016b72005-05-26 13:03:09 -07001529 if (bp->advertising & ADVERTISED_1000baseT_Full)
1530 new_adv |= ADVERTISE_1000XFULL;
1531
1532 new_adv |= bnx2_phy_get_pause_adv(bp);
1533
Michael Chanca58c3a2007-05-03 13:22:52 -07001534 bnx2_read_phy(bp, bp->mii_adv, &adv);
1535 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chanb6016b72005-05-26 13:03:09 -07001536
1537 bp->serdes_an_pending = 0;
1538 if ((adv != new_adv) || ((bmcr & BMCR_ANENABLE) == 0)) {
1539 /* Force a link down visible on the other side */
1540 if (bp->link_up) {
Michael Chanca58c3a2007-05-03 13:22:52 -07001541 bnx2_write_phy(bp, bp->mii_bmcr, BMCR_LOOPBACK);
Michael Chan80be4432006-11-19 14:07:28 -08001542 spin_unlock_bh(&bp->phy_lock);
1543 msleep(20);
1544 spin_lock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07001545 }
1546
Michael Chanca58c3a2007-05-03 13:22:52 -07001547 bnx2_write_phy(bp, bp->mii_adv, new_adv);
1548 bnx2_write_phy(bp, bp->mii_bmcr, bmcr | BMCR_ANRESTART |
Michael Chanb6016b72005-05-26 13:03:09 -07001549 BMCR_ANENABLE);
Michael Chanf8dd0642006-11-19 14:08:29 -08001550 /* Speed up link-up time when the link partner
1551 * does not autonegotiate which is very common
1552 * in blade servers. Some blade servers use
1553 * IPMI for kerboard input and it's important
1554 * to minimize link disruptions. Autoneg. involves
1555 * exchanging base pages plus 3 next pages and
1556 * normally completes in about 120 msec.
1557 */
1558 bp->current_interval = SERDES_AN_TIMEOUT;
1559 bp->serdes_an_pending = 1;
1560 mod_timer(&bp->timer, jiffies + bp->current_interval);
Michael Chan605a9e22007-05-03 13:23:13 -07001561 } else {
1562 bnx2_resolve_flow_ctrl(bp);
1563 bnx2_set_mac_link(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07001564 }
1565
1566 return 0;
1567}
1568
1569#define ETHTOOL_ALL_FIBRE_SPEED \
Michael Chan583c28e2008-01-21 19:51:35 -08001570 (bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE) ? \
Michael Chandeaf3912007-07-07 22:48:00 -07001571 (ADVERTISED_2500baseX_Full | ADVERTISED_1000baseT_Full) :\
1572 (ADVERTISED_1000baseT_Full)
Michael Chanb6016b72005-05-26 13:03:09 -07001573
1574#define ETHTOOL_ALL_COPPER_SPEED \
1575 (ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full | \
1576 ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full | \
1577 ADVERTISED_1000baseT_Full)
1578
1579#define PHY_ALL_10_100_SPEED (ADVERTISE_10HALF | ADVERTISE_10FULL | \
1580 ADVERTISE_100HALF | ADVERTISE_100FULL | ADVERTISE_CSMA)
Jeff Garzik6aa20a22006-09-13 13:24:59 -04001581
Michael Chanb6016b72005-05-26 13:03:09 -07001582#define PHY_ALL_1000_SPEED (ADVERTISE_1000HALF | ADVERTISE_1000FULL)
1583
Michael Chandeaf3912007-07-07 22:48:00 -07001584static void
Michael Chan0d8a6572007-07-07 22:49:43 -07001585bnx2_set_default_remote_link(struct bnx2 *bp)
1586{
1587 u32 link;
1588
1589 if (bp->phy_port == PORT_TP)
Michael Chan2726d6e2008-01-29 21:35:05 -08001590 link = bnx2_shmem_rd(bp, BNX2_RPHY_COPPER_LINK);
Michael Chan0d8a6572007-07-07 22:49:43 -07001591 else
Michael Chan2726d6e2008-01-29 21:35:05 -08001592 link = bnx2_shmem_rd(bp, BNX2_RPHY_SERDES_LINK);
Michael Chan0d8a6572007-07-07 22:49:43 -07001593
1594 if (link & BNX2_NETLINK_SET_LINK_ENABLE_AUTONEG) {
1595 bp->req_line_speed = 0;
1596 bp->autoneg |= AUTONEG_SPEED;
1597 bp->advertising = ADVERTISED_Autoneg;
1598 if (link & BNX2_NETLINK_SET_LINK_SPEED_10HALF)
1599 bp->advertising |= ADVERTISED_10baseT_Half;
1600 if (link & BNX2_NETLINK_SET_LINK_SPEED_10FULL)
1601 bp->advertising |= ADVERTISED_10baseT_Full;
1602 if (link & BNX2_NETLINK_SET_LINK_SPEED_100HALF)
1603 bp->advertising |= ADVERTISED_100baseT_Half;
1604 if (link & BNX2_NETLINK_SET_LINK_SPEED_100FULL)
1605 bp->advertising |= ADVERTISED_100baseT_Full;
1606 if (link & BNX2_NETLINK_SET_LINK_SPEED_1GFULL)
1607 bp->advertising |= ADVERTISED_1000baseT_Full;
1608 if (link & BNX2_NETLINK_SET_LINK_SPEED_2G5FULL)
1609 bp->advertising |= ADVERTISED_2500baseX_Full;
1610 } else {
1611 bp->autoneg = 0;
1612 bp->advertising = 0;
1613 bp->req_duplex = DUPLEX_FULL;
1614 if (link & BNX2_NETLINK_SET_LINK_SPEED_10) {
1615 bp->req_line_speed = SPEED_10;
1616 if (link & BNX2_NETLINK_SET_LINK_SPEED_10HALF)
1617 bp->req_duplex = DUPLEX_HALF;
1618 }
1619 if (link & BNX2_NETLINK_SET_LINK_SPEED_100) {
1620 bp->req_line_speed = SPEED_100;
1621 if (link & BNX2_NETLINK_SET_LINK_SPEED_100HALF)
1622 bp->req_duplex = DUPLEX_HALF;
1623 }
1624 if (link & BNX2_NETLINK_SET_LINK_SPEED_1GFULL)
1625 bp->req_line_speed = SPEED_1000;
1626 if (link & BNX2_NETLINK_SET_LINK_SPEED_2G5FULL)
1627 bp->req_line_speed = SPEED_2500;
1628 }
1629}
1630
1631static void
Michael Chandeaf3912007-07-07 22:48:00 -07001632bnx2_set_default_link(struct bnx2 *bp)
1633{
Harvey Harrisonab598592008-05-01 02:47:38 -07001634 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP) {
1635 bnx2_set_default_remote_link(bp);
1636 return;
1637 }
Michael Chan0d8a6572007-07-07 22:49:43 -07001638
Michael Chandeaf3912007-07-07 22:48:00 -07001639 bp->autoneg = AUTONEG_SPEED | AUTONEG_FLOW_CTRL;
1640 bp->req_line_speed = 0;
Michael Chan583c28e2008-01-21 19:51:35 -08001641 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Michael Chandeaf3912007-07-07 22:48:00 -07001642 u32 reg;
1643
1644 bp->advertising = ETHTOOL_ALL_FIBRE_SPEED | ADVERTISED_Autoneg;
1645
Michael Chan2726d6e2008-01-29 21:35:05 -08001646 reg = bnx2_shmem_rd(bp, BNX2_PORT_HW_CFG_CONFIG);
Michael Chandeaf3912007-07-07 22:48:00 -07001647 reg &= BNX2_PORT_HW_CFG_CFG_DFLT_LINK_MASK;
1648 if (reg == BNX2_PORT_HW_CFG_CFG_DFLT_LINK_1G) {
1649 bp->autoneg = 0;
1650 bp->req_line_speed = bp->line_speed = SPEED_1000;
1651 bp->req_duplex = DUPLEX_FULL;
1652 }
1653 } else
1654 bp->advertising = ETHTOOL_ALL_COPPER_SPEED | ADVERTISED_Autoneg;
1655}
1656
Michael Chan0d8a6572007-07-07 22:49:43 -07001657static void
Michael Chandf149d72007-07-07 22:51:36 -07001658bnx2_send_heart_beat(struct bnx2 *bp)
1659{
1660 u32 msg;
1661 u32 addr;
1662
1663 spin_lock(&bp->indirect_lock);
1664 msg = (u32) (++bp->fw_drv_pulse_wr_seq & BNX2_DRV_PULSE_SEQ_MASK);
1665 addr = bp->shmem_base + BNX2_DRV_PULSE_MB;
1666 REG_WR(bp, BNX2_PCICFG_REG_WINDOW_ADDRESS, addr);
1667 REG_WR(bp, BNX2_PCICFG_REG_WINDOW, msg);
1668 spin_unlock(&bp->indirect_lock);
1669}
1670
1671static void
Michael Chan0d8a6572007-07-07 22:49:43 -07001672bnx2_remote_phy_event(struct bnx2 *bp)
1673{
1674 u32 msg;
1675 u8 link_up = bp->link_up;
1676 u8 old_port;
1677
Michael Chan2726d6e2008-01-29 21:35:05 -08001678 msg = bnx2_shmem_rd(bp, BNX2_LINK_STATUS);
Michael Chan0d8a6572007-07-07 22:49:43 -07001679
Michael Chandf149d72007-07-07 22:51:36 -07001680 if (msg & BNX2_LINK_STATUS_HEART_BEAT_EXPIRED)
1681 bnx2_send_heart_beat(bp);
1682
1683 msg &= ~BNX2_LINK_STATUS_HEART_BEAT_EXPIRED;
1684
Michael Chan0d8a6572007-07-07 22:49:43 -07001685 if ((msg & BNX2_LINK_STATUS_LINK_UP) == BNX2_LINK_STATUS_LINK_DOWN)
1686 bp->link_up = 0;
1687 else {
1688 u32 speed;
1689
1690 bp->link_up = 1;
1691 speed = msg & BNX2_LINK_STATUS_SPEED_MASK;
1692 bp->duplex = DUPLEX_FULL;
1693 switch (speed) {
1694 case BNX2_LINK_STATUS_10HALF:
1695 bp->duplex = DUPLEX_HALF;
1696 case BNX2_LINK_STATUS_10FULL:
1697 bp->line_speed = SPEED_10;
1698 break;
1699 case BNX2_LINK_STATUS_100HALF:
1700 bp->duplex = DUPLEX_HALF;
1701 case BNX2_LINK_STATUS_100BASE_T4:
1702 case BNX2_LINK_STATUS_100FULL:
1703 bp->line_speed = SPEED_100;
1704 break;
1705 case BNX2_LINK_STATUS_1000HALF:
1706 bp->duplex = DUPLEX_HALF;
1707 case BNX2_LINK_STATUS_1000FULL:
1708 bp->line_speed = SPEED_1000;
1709 break;
1710 case BNX2_LINK_STATUS_2500HALF:
1711 bp->duplex = DUPLEX_HALF;
1712 case BNX2_LINK_STATUS_2500FULL:
1713 bp->line_speed = SPEED_2500;
1714 break;
1715 default:
1716 bp->line_speed = 0;
1717 break;
1718 }
1719
1720 spin_lock(&bp->phy_lock);
1721 bp->flow_ctrl = 0;
1722 if ((bp->autoneg & (AUTONEG_SPEED | AUTONEG_FLOW_CTRL)) !=
1723 (AUTONEG_SPEED | AUTONEG_FLOW_CTRL)) {
1724 if (bp->duplex == DUPLEX_FULL)
1725 bp->flow_ctrl = bp->req_flow_ctrl;
1726 } else {
1727 if (msg & BNX2_LINK_STATUS_TX_FC_ENABLED)
1728 bp->flow_ctrl |= FLOW_CTRL_TX;
1729 if (msg & BNX2_LINK_STATUS_RX_FC_ENABLED)
1730 bp->flow_ctrl |= FLOW_CTRL_RX;
1731 }
1732
1733 old_port = bp->phy_port;
1734 if (msg & BNX2_LINK_STATUS_SERDES_LINK)
1735 bp->phy_port = PORT_FIBRE;
1736 else
1737 bp->phy_port = PORT_TP;
1738
1739 if (old_port != bp->phy_port)
1740 bnx2_set_default_link(bp);
1741
1742 spin_unlock(&bp->phy_lock);
1743 }
1744 if (bp->link_up != link_up)
1745 bnx2_report_link(bp);
1746
1747 bnx2_set_mac_link(bp);
1748}
1749
1750static int
1751bnx2_set_remote_link(struct bnx2 *bp)
1752{
1753 u32 evt_code;
1754
Michael Chan2726d6e2008-01-29 21:35:05 -08001755 evt_code = bnx2_shmem_rd(bp, BNX2_FW_EVT_CODE_MB);
Michael Chan0d8a6572007-07-07 22:49:43 -07001756 switch (evt_code) {
1757 case BNX2_FW_EVT_CODE_LINK_EVENT:
1758 bnx2_remote_phy_event(bp);
1759 break;
1760 case BNX2_FW_EVT_CODE_SW_TIMER_EXPIRATION_EVENT:
1761 default:
Michael Chandf149d72007-07-07 22:51:36 -07001762 bnx2_send_heart_beat(bp);
Michael Chan0d8a6572007-07-07 22:49:43 -07001763 break;
1764 }
1765 return 0;
1766}
1767
Michael Chanb6016b72005-05-26 13:03:09 -07001768static int
1769bnx2_setup_copper_phy(struct bnx2 *bp)
1770{
1771 u32 bmcr;
1772 u32 new_bmcr;
1773
Michael Chanca58c3a2007-05-03 13:22:52 -07001774 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chanb6016b72005-05-26 13:03:09 -07001775
1776 if (bp->autoneg & AUTONEG_SPEED) {
1777 u32 adv_reg, adv1000_reg;
1778 u32 new_adv_reg = 0;
1779 u32 new_adv1000_reg = 0;
1780
Michael Chanca58c3a2007-05-03 13:22:52 -07001781 bnx2_read_phy(bp, bp->mii_adv, &adv_reg);
Michael Chanb6016b72005-05-26 13:03:09 -07001782 adv_reg &= (PHY_ALL_10_100_SPEED | ADVERTISE_PAUSE_CAP |
1783 ADVERTISE_PAUSE_ASYM);
1784
1785 bnx2_read_phy(bp, MII_CTRL1000, &adv1000_reg);
1786 adv1000_reg &= PHY_ALL_1000_SPEED;
1787
1788 if (bp->advertising & ADVERTISED_10baseT_Half)
1789 new_adv_reg |= ADVERTISE_10HALF;
1790 if (bp->advertising & ADVERTISED_10baseT_Full)
1791 new_adv_reg |= ADVERTISE_10FULL;
1792 if (bp->advertising & ADVERTISED_100baseT_Half)
1793 new_adv_reg |= ADVERTISE_100HALF;
1794 if (bp->advertising & ADVERTISED_100baseT_Full)
1795 new_adv_reg |= ADVERTISE_100FULL;
1796 if (bp->advertising & ADVERTISED_1000baseT_Full)
1797 new_adv1000_reg |= ADVERTISE_1000FULL;
Jeff Garzik6aa20a22006-09-13 13:24:59 -04001798
Michael Chanb6016b72005-05-26 13:03:09 -07001799 new_adv_reg |= ADVERTISE_CSMA;
1800
1801 new_adv_reg |= bnx2_phy_get_pause_adv(bp);
1802
1803 if ((adv1000_reg != new_adv1000_reg) ||
1804 (adv_reg != new_adv_reg) ||
1805 ((bmcr & BMCR_ANENABLE) == 0)) {
1806
Michael Chanca58c3a2007-05-03 13:22:52 -07001807 bnx2_write_phy(bp, bp->mii_adv, new_adv_reg);
Michael Chanb6016b72005-05-26 13:03:09 -07001808 bnx2_write_phy(bp, MII_CTRL1000, new_adv1000_reg);
Michael Chanca58c3a2007-05-03 13:22:52 -07001809 bnx2_write_phy(bp, bp->mii_bmcr, BMCR_ANRESTART |
Michael Chanb6016b72005-05-26 13:03:09 -07001810 BMCR_ANENABLE);
1811 }
1812 else if (bp->link_up) {
1813 /* Flow ctrl may have changed from auto to forced */
1814 /* or vice-versa. */
1815
1816 bnx2_resolve_flow_ctrl(bp);
1817 bnx2_set_mac_link(bp);
1818 }
1819 return 0;
1820 }
1821
1822 new_bmcr = 0;
1823 if (bp->req_line_speed == SPEED_100) {
1824 new_bmcr |= BMCR_SPEED100;
1825 }
1826 if (bp->req_duplex == DUPLEX_FULL) {
1827 new_bmcr |= BMCR_FULLDPLX;
1828 }
1829 if (new_bmcr != bmcr) {
1830 u32 bmsr;
Michael Chanb6016b72005-05-26 13:03:09 -07001831
Michael Chanca58c3a2007-05-03 13:22:52 -07001832 bnx2_read_phy(bp, bp->mii_bmsr, &bmsr);
1833 bnx2_read_phy(bp, bp->mii_bmsr, &bmsr);
Jeff Garzik6aa20a22006-09-13 13:24:59 -04001834
Michael Chanb6016b72005-05-26 13:03:09 -07001835 if (bmsr & BMSR_LSTATUS) {
1836 /* Force link down */
Michael Chanca58c3a2007-05-03 13:22:52 -07001837 bnx2_write_phy(bp, bp->mii_bmcr, BMCR_LOOPBACK);
Michael Chana16dda02006-11-19 14:08:56 -08001838 spin_unlock_bh(&bp->phy_lock);
1839 msleep(50);
1840 spin_lock_bh(&bp->phy_lock);
1841
Michael Chanca58c3a2007-05-03 13:22:52 -07001842 bnx2_read_phy(bp, bp->mii_bmsr, &bmsr);
1843 bnx2_read_phy(bp, bp->mii_bmsr, &bmsr);
Michael Chanb6016b72005-05-26 13:03:09 -07001844 }
1845
Michael Chanca58c3a2007-05-03 13:22:52 -07001846 bnx2_write_phy(bp, bp->mii_bmcr, new_bmcr);
Michael Chanb6016b72005-05-26 13:03:09 -07001847
1848 /* Normally, the new speed is setup after the link has
1849 * gone down and up again. In some cases, link will not go
1850 * down so we need to set up the new speed here.
1851 */
1852 if (bmsr & BMSR_LSTATUS) {
1853 bp->line_speed = bp->req_line_speed;
1854 bp->duplex = bp->req_duplex;
1855 bnx2_resolve_flow_ctrl(bp);
1856 bnx2_set_mac_link(bp);
1857 }
Michael Chan27a005b2007-05-03 13:23:41 -07001858 } else {
1859 bnx2_resolve_flow_ctrl(bp);
1860 bnx2_set_mac_link(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07001861 }
1862 return 0;
1863}
1864
1865static int
Michael Chan0d8a6572007-07-07 22:49:43 -07001866bnx2_setup_phy(struct bnx2 *bp, u8 port)
Michael Chanb6016b72005-05-26 13:03:09 -07001867{
1868 if (bp->loopback == MAC_LOOPBACK)
1869 return 0;
1870
Michael Chan583c28e2008-01-21 19:51:35 -08001871 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Michael Chan0d8a6572007-07-07 22:49:43 -07001872 return (bnx2_setup_serdes_phy(bp, port));
Michael Chanb6016b72005-05-26 13:03:09 -07001873 }
1874 else {
1875 return (bnx2_setup_copper_phy(bp));
1876 }
1877}
1878
1879static int
Michael Chan27a005b2007-05-03 13:23:41 -07001880bnx2_init_5709s_phy(struct bnx2 *bp)
1881{
1882 u32 val;
1883
1884 bp->mii_bmcr = MII_BMCR + 0x10;
1885 bp->mii_bmsr = MII_BMSR + 0x10;
1886 bp->mii_bmsr1 = MII_BNX2_GP_TOP_AN_STATUS1;
1887 bp->mii_adv = MII_ADVERTISE + 0x10;
1888 bp->mii_lpa = MII_LPA + 0x10;
1889 bp->mii_up1 = MII_BNX2_OVER1G_UP1;
1890
1891 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_AER);
1892 bnx2_write_phy(bp, MII_BNX2_AER_AER, MII_BNX2_AER_AER_AN_MMD);
1893
1894 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
1895 bnx2_reset_phy(bp);
1896
1897 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_SERDES_DIG);
1898
1899 bnx2_read_phy(bp, MII_BNX2_SERDES_DIG_1000XCTL1, &val);
1900 val &= ~MII_BNX2_SD_1000XCTL1_AUTODET;
1901 val |= MII_BNX2_SD_1000XCTL1_FIBER;
1902 bnx2_write_phy(bp, MII_BNX2_SERDES_DIG_1000XCTL1, val);
1903
1904 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_OVER1G);
1905 bnx2_read_phy(bp, MII_BNX2_OVER1G_UP1, &val);
Michael Chan583c28e2008-01-21 19:51:35 -08001906 if (bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE)
Michael Chan27a005b2007-05-03 13:23:41 -07001907 val |= BCM5708S_UP1_2G5;
1908 else
1909 val &= ~BCM5708S_UP1_2G5;
1910 bnx2_write_phy(bp, MII_BNX2_OVER1G_UP1, val);
1911
1912 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_BAM_NXTPG);
1913 bnx2_read_phy(bp, MII_BNX2_BAM_NXTPG_CTL, &val);
1914 val |= MII_BNX2_NXTPG_CTL_T2 | MII_BNX2_NXTPG_CTL_BAM;
1915 bnx2_write_phy(bp, MII_BNX2_BAM_NXTPG_CTL, val);
1916
1917 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_CL73_USERB0);
1918
1919 val = MII_BNX2_CL73_BAM_EN | MII_BNX2_CL73_BAM_STA_MGR_EN |
1920 MII_BNX2_CL73_BAM_NP_AFT_BP_EN;
1921 bnx2_write_phy(bp, MII_BNX2_CL73_BAM_CTL1, val);
1922
1923 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
1924
1925 return 0;
1926}
1927
1928static int
Michael Chan5b0c76a2005-11-04 08:45:49 -08001929bnx2_init_5708s_phy(struct bnx2 *bp)
1930{
1931 u32 val;
1932
Michael Chan27a005b2007-05-03 13:23:41 -07001933 bnx2_reset_phy(bp);
1934
1935 bp->mii_up1 = BCM5708S_UP1;
1936
Michael Chan5b0c76a2005-11-04 08:45:49 -08001937 bnx2_write_phy(bp, BCM5708S_BLK_ADDR, BCM5708S_BLK_ADDR_DIG3);
1938 bnx2_write_phy(bp, BCM5708S_DIG_3_0, BCM5708S_DIG_3_0_USE_IEEE);
1939 bnx2_write_phy(bp, BCM5708S_BLK_ADDR, BCM5708S_BLK_ADDR_DIG);
1940
1941 bnx2_read_phy(bp, BCM5708S_1000X_CTL1, &val);
1942 val |= BCM5708S_1000X_CTL1_FIBER_MODE | BCM5708S_1000X_CTL1_AUTODET_EN;
1943 bnx2_write_phy(bp, BCM5708S_1000X_CTL1, val);
1944
1945 bnx2_read_phy(bp, BCM5708S_1000X_CTL2, &val);
1946 val |= BCM5708S_1000X_CTL2_PLLEL_DET_EN;
1947 bnx2_write_phy(bp, BCM5708S_1000X_CTL2, val);
1948
Michael Chan583c28e2008-01-21 19:51:35 -08001949 if (bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE) {
Michael Chan5b0c76a2005-11-04 08:45:49 -08001950 bnx2_read_phy(bp, BCM5708S_UP1, &val);
1951 val |= BCM5708S_UP1_2G5;
1952 bnx2_write_phy(bp, BCM5708S_UP1, val);
1953 }
1954
1955 if ((CHIP_ID(bp) == CHIP_ID_5708_A0) ||
Michael Chandda1e392006-01-23 16:08:14 -08001956 (CHIP_ID(bp) == CHIP_ID_5708_B0) ||
1957 (CHIP_ID(bp) == CHIP_ID_5708_B1)) {
Michael Chan5b0c76a2005-11-04 08:45:49 -08001958 /* increase tx signal amplitude */
1959 bnx2_write_phy(bp, BCM5708S_BLK_ADDR,
1960 BCM5708S_BLK_ADDR_TX_MISC);
1961 bnx2_read_phy(bp, BCM5708S_TX_ACTL1, &val);
1962 val &= ~BCM5708S_TX_ACTL1_DRIVER_VCM;
1963 bnx2_write_phy(bp, BCM5708S_TX_ACTL1, val);
1964 bnx2_write_phy(bp, BCM5708S_BLK_ADDR, BCM5708S_BLK_ADDR_DIG);
1965 }
1966
Michael Chan2726d6e2008-01-29 21:35:05 -08001967 val = bnx2_shmem_rd(bp, BNX2_PORT_HW_CFG_CONFIG) &
Michael Chan5b0c76a2005-11-04 08:45:49 -08001968 BNX2_PORT_HW_CFG_CFG_TXCTL3_MASK;
1969
1970 if (val) {
1971 u32 is_backplane;
1972
Michael Chan2726d6e2008-01-29 21:35:05 -08001973 is_backplane = bnx2_shmem_rd(bp, BNX2_SHARED_HW_CFG_CONFIG);
Michael Chan5b0c76a2005-11-04 08:45:49 -08001974 if (is_backplane & BNX2_SHARED_HW_CFG_PHY_BACKPLANE) {
1975 bnx2_write_phy(bp, BCM5708S_BLK_ADDR,
1976 BCM5708S_BLK_ADDR_TX_MISC);
1977 bnx2_write_phy(bp, BCM5708S_TX_ACTL3, val);
1978 bnx2_write_phy(bp, BCM5708S_BLK_ADDR,
1979 BCM5708S_BLK_ADDR_DIG);
1980 }
1981 }
1982 return 0;
1983}
1984
1985static int
1986bnx2_init_5706s_phy(struct bnx2 *bp)
Michael Chanb6016b72005-05-26 13:03:09 -07001987{
Michael Chan27a005b2007-05-03 13:23:41 -07001988 bnx2_reset_phy(bp);
1989
Michael Chan583c28e2008-01-21 19:51:35 -08001990 bp->phy_flags &= ~BNX2_PHY_FLAG_PARALLEL_DETECT;
Michael Chanb6016b72005-05-26 13:03:09 -07001991
Michael Chan59b47d82006-11-19 14:10:45 -08001992 if (CHIP_NUM(bp) == CHIP_NUM_5706)
1993 REG_WR(bp, BNX2_MISC_GP_HW_CTL0, 0x300);
Michael Chanb6016b72005-05-26 13:03:09 -07001994
1995 if (bp->dev->mtu > 1500) {
1996 u32 val;
1997
1998 /* Set extended packet length bit */
1999 bnx2_write_phy(bp, 0x18, 0x7);
2000 bnx2_read_phy(bp, 0x18, &val);
2001 bnx2_write_phy(bp, 0x18, (val & 0xfff8) | 0x4000);
2002
2003 bnx2_write_phy(bp, 0x1c, 0x6c00);
2004 bnx2_read_phy(bp, 0x1c, &val);
2005 bnx2_write_phy(bp, 0x1c, (val & 0x3ff) | 0xec02);
2006 }
2007 else {
2008 u32 val;
2009
2010 bnx2_write_phy(bp, 0x18, 0x7);
2011 bnx2_read_phy(bp, 0x18, &val);
2012 bnx2_write_phy(bp, 0x18, val & ~0x4007);
2013
2014 bnx2_write_phy(bp, 0x1c, 0x6c00);
2015 bnx2_read_phy(bp, 0x1c, &val);
2016 bnx2_write_phy(bp, 0x1c, (val & 0x3fd) | 0xec00);
2017 }
2018
2019 return 0;
2020}
2021
2022static int
2023bnx2_init_copper_phy(struct bnx2 *bp)
2024{
Michael Chan5b0c76a2005-11-04 08:45:49 -08002025 u32 val;
2026
Michael Chan27a005b2007-05-03 13:23:41 -07002027 bnx2_reset_phy(bp);
2028
Michael Chan583c28e2008-01-21 19:51:35 -08002029 if (bp->phy_flags & BNX2_PHY_FLAG_CRC_FIX) {
Michael Chanb6016b72005-05-26 13:03:09 -07002030 bnx2_write_phy(bp, 0x18, 0x0c00);
2031 bnx2_write_phy(bp, 0x17, 0x000a);
2032 bnx2_write_phy(bp, 0x15, 0x310b);
2033 bnx2_write_phy(bp, 0x17, 0x201f);
2034 bnx2_write_phy(bp, 0x15, 0x9506);
2035 bnx2_write_phy(bp, 0x17, 0x401f);
2036 bnx2_write_phy(bp, 0x15, 0x14e2);
2037 bnx2_write_phy(bp, 0x18, 0x0400);
2038 }
2039
Michael Chan583c28e2008-01-21 19:51:35 -08002040 if (bp->phy_flags & BNX2_PHY_FLAG_DIS_EARLY_DAC) {
Michael Chanb659f442007-02-02 00:46:35 -08002041 bnx2_write_phy(bp, MII_BNX2_DSP_ADDRESS,
2042 MII_BNX2_DSP_EXPAND_REG | 0x8);
2043 bnx2_read_phy(bp, MII_BNX2_DSP_RW_PORT, &val);
2044 val &= ~(1 << 8);
2045 bnx2_write_phy(bp, MII_BNX2_DSP_RW_PORT, val);
2046 }
2047
Michael Chanb6016b72005-05-26 13:03:09 -07002048 if (bp->dev->mtu > 1500) {
Michael Chanb6016b72005-05-26 13:03:09 -07002049 /* Set extended packet length bit */
2050 bnx2_write_phy(bp, 0x18, 0x7);
2051 bnx2_read_phy(bp, 0x18, &val);
2052 bnx2_write_phy(bp, 0x18, val | 0x4000);
2053
2054 bnx2_read_phy(bp, 0x10, &val);
2055 bnx2_write_phy(bp, 0x10, val | 0x1);
2056 }
2057 else {
Michael Chanb6016b72005-05-26 13:03:09 -07002058 bnx2_write_phy(bp, 0x18, 0x7);
2059 bnx2_read_phy(bp, 0x18, &val);
2060 bnx2_write_phy(bp, 0x18, val & ~0x4007);
2061
2062 bnx2_read_phy(bp, 0x10, &val);
2063 bnx2_write_phy(bp, 0x10, val & ~0x1);
2064 }
2065
Michael Chan5b0c76a2005-11-04 08:45:49 -08002066 /* ethernet@wirespeed */
2067 bnx2_write_phy(bp, 0x18, 0x7007);
2068 bnx2_read_phy(bp, 0x18, &val);
2069 bnx2_write_phy(bp, 0x18, val | (1 << 15) | (1 << 4));
Michael Chanb6016b72005-05-26 13:03:09 -07002070 return 0;
2071}
2072
2073
2074static int
2075bnx2_init_phy(struct bnx2 *bp)
2076{
2077 u32 val;
2078 int rc = 0;
2079
Michael Chan583c28e2008-01-21 19:51:35 -08002080 bp->phy_flags &= ~BNX2_PHY_FLAG_INT_MODE_MASK;
2081 bp->phy_flags |= BNX2_PHY_FLAG_INT_MODE_LINK_READY;
Michael Chanb6016b72005-05-26 13:03:09 -07002082
Michael Chanca58c3a2007-05-03 13:22:52 -07002083 bp->mii_bmcr = MII_BMCR;
2084 bp->mii_bmsr = MII_BMSR;
Michael Chan27a005b2007-05-03 13:23:41 -07002085 bp->mii_bmsr1 = MII_BMSR;
Michael Chanca58c3a2007-05-03 13:22:52 -07002086 bp->mii_adv = MII_ADVERTISE;
2087 bp->mii_lpa = MII_LPA;
2088
Michael Chanb6016b72005-05-26 13:03:09 -07002089 REG_WR(bp, BNX2_EMAC_ATTENTION_ENA, BNX2_EMAC_ATTENTION_ENA_LINK);
2090
Michael Chan583c28e2008-01-21 19:51:35 -08002091 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
Michael Chan0d8a6572007-07-07 22:49:43 -07002092 goto setup_phy;
2093
Michael Chanb6016b72005-05-26 13:03:09 -07002094 bnx2_read_phy(bp, MII_PHYSID1, &val);
2095 bp->phy_id = val << 16;
2096 bnx2_read_phy(bp, MII_PHYSID2, &val);
2097 bp->phy_id |= val & 0xffff;
2098
Michael Chan583c28e2008-01-21 19:51:35 -08002099 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Michael Chan5b0c76a2005-11-04 08:45:49 -08002100 if (CHIP_NUM(bp) == CHIP_NUM_5706)
2101 rc = bnx2_init_5706s_phy(bp);
2102 else if (CHIP_NUM(bp) == CHIP_NUM_5708)
2103 rc = bnx2_init_5708s_phy(bp);
Michael Chan27a005b2007-05-03 13:23:41 -07002104 else if (CHIP_NUM(bp) == CHIP_NUM_5709)
2105 rc = bnx2_init_5709s_phy(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07002106 }
2107 else {
2108 rc = bnx2_init_copper_phy(bp);
2109 }
2110
Michael Chan0d8a6572007-07-07 22:49:43 -07002111setup_phy:
2112 if (!rc)
2113 rc = bnx2_setup_phy(bp, bp->phy_port);
Michael Chanb6016b72005-05-26 13:03:09 -07002114
2115 return rc;
2116}
2117
2118static int
2119bnx2_set_mac_loopback(struct bnx2 *bp)
2120{
2121 u32 mac_mode;
2122
2123 mac_mode = REG_RD(bp, BNX2_EMAC_MODE);
2124 mac_mode &= ~BNX2_EMAC_MODE_PORT;
2125 mac_mode |= BNX2_EMAC_MODE_MAC_LOOP | BNX2_EMAC_MODE_FORCE_LINK;
2126 REG_WR(bp, BNX2_EMAC_MODE, mac_mode);
2127 bp->link_up = 1;
2128 return 0;
2129}
2130
Michael Chanbc5a0692006-01-23 16:13:22 -08002131static int bnx2_test_link(struct bnx2 *);
2132
2133static int
2134bnx2_set_phy_loopback(struct bnx2 *bp)
2135{
2136 u32 mac_mode;
2137 int rc, i;
2138
2139 spin_lock_bh(&bp->phy_lock);
Michael Chanca58c3a2007-05-03 13:22:52 -07002140 rc = bnx2_write_phy(bp, bp->mii_bmcr, BMCR_LOOPBACK | BMCR_FULLDPLX |
Michael Chanbc5a0692006-01-23 16:13:22 -08002141 BMCR_SPEED1000);
2142 spin_unlock_bh(&bp->phy_lock);
2143 if (rc)
2144 return rc;
2145
2146 for (i = 0; i < 10; i++) {
2147 if (bnx2_test_link(bp) == 0)
2148 break;
Michael Chan80be4432006-11-19 14:07:28 -08002149 msleep(100);
Michael Chanbc5a0692006-01-23 16:13:22 -08002150 }
2151
2152 mac_mode = REG_RD(bp, BNX2_EMAC_MODE);
2153 mac_mode &= ~(BNX2_EMAC_MODE_PORT | BNX2_EMAC_MODE_HALF_DUPLEX |
2154 BNX2_EMAC_MODE_MAC_LOOP | BNX2_EMAC_MODE_FORCE_LINK |
Michael Chan59b47d82006-11-19 14:10:45 -08002155 BNX2_EMAC_MODE_25G_MODE);
Michael Chanbc5a0692006-01-23 16:13:22 -08002156
2157 mac_mode |= BNX2_EMAC_MODE_PORT_GMII;
2158 REG_WR(bp, BNX2_EMAC_MODE, mac_mode);
2159 bp->link_up = 1;
2160 return 0;
2161}
2162
Michael Chanb6016b72005-05-26 13:03:09 -07002163static int
Michael Chanb090ae22006-01-23 16:07:10 -08002164bnx2_fw_sync(struct bnx2 *bp, u32 msg_data, int silent)
Michael Chanb6016b72005-05-26 13:03:09 -07002165{
2166 int i;
2167 u32 val;
2168
Michael Chanb6016b72005-05-26 13:03:09 -07002169 bp->fw_wr_seq++;
2170 msg_data |= bp->fw_wr_seq;
2171
Michael Chan2726d6e2008-01-29 21:35:05 -08002172 bnx2_shmem_wr(bp, BNX2_DRV_MB, msg_data);
Michael Chanb6016b72005-05-26 13:03:09 -07002173
2174 /* wait for an acknowledgement. */
Michael Chanb090ae22006-01-23 16:07:10 -08002175 for (i = 0; i < (FW_ACK_TIME_OUT_MS / 10); i++) {
2176 msleep(10);
Michael Chanb6016b72005-05-26 13:03:09 -07002177
Michael Chan2726d6e2008-01-29 21:35:05 -08002178 val = bnx2_shmem_rd(bp, BNX2_FW_MB);
Michael Chanb6016b72005-05-26 13:03:09 -07002179
2180 if ((val & BNX2_FW_MSG_ACK) == (msg_data & BNX2_DRV_MSG_SEQ))
2181 break;
2182 }
Michael Chanb090ae22006-01-23 16:07:10 -08002183 if ((msg_data & BNX2_DRV_MSG_DATA) == BNX2_DRV_MSG_DATA_WAIT0)
2184 return 0;
Michael Chanb6016b72005-05-26 13:03:09 -07002185
2186 /* If we timed out, inform the firmware that this is the case. */
Michael Chanb090ae22006-01-23 16:07:10 -08002187 if ((val & BNX2_FW_MSG_ACK) != (msg_data & BNX2_DRV_MSG_SEQ)) {
2188 if (!silent)
2189 printk(KERN_ERR PFX "fw sync timeout, reset code = "
2190 "%x\n", msg_data);
Michael Chanb6016b72005-05-26 13:03:09 -07002191
2192 msg_data &= ~BNX2_DRV_MSG_CODE;
2193 msg_data |= BNX2_DRV_MSG_CODE_FW_TIMEOUT;
2194
Michael Chan2726d6e2008-01-29 21:35:05 -08002195 bnx2_shmem_wr(bp, BNX2_DRV_MB, msg_data);
Michael Chanb6016b72005-05-26 13:03:09 -07002196
Michael Chanb6016b72005-05-26 13:03:09 -07002197 return -EBUSY;
2198 }
2199
Michael Chanb090ae22006-01-23 16:07:10 -08002200 if ((val & BNX2_FW_MSG_STATUS_MASK) != BNX2_FW_MSG_STATUS_OK)
2201 return -EIO;
2202
Michael Chanb6016b72005-05-26 13:03:09 -07002203 return 0;
2204}
2205
Michael Chan59b47d82006-11-19 14:10:45 -08002206static int
2207bnx2_init_5709_context(struct bnx2 *bp)
2208{
2209 int i, ret = 0;
2210 u32 val;
2211
2212 val = BNX2_CTX_COMMAND_ENABLED | BNX2_CTX_COMMAND_MEM_INIT | (1 << 12);
2213 val |= (BCM_PAGE_BITS - 8) << 16;
2214 REG_WR(bp, BNX2_CTX_COMMAND, val);
Michael Chan641bdcd2007-06-04 21:22:24 -07002215 for (i = 0; i < 10; i++) {
2216 val = REG_RD(bp, BNX2_CTX_COMMAND);
2217 if (!(val & BNX2_CTX_COMMAND_MEM_INIT))
2218 break;
2219 udelay(2);
2220 }
2221 if (val & BNX2_CTX_COMMAND_MEM_INIT)
2222 return -EBUSY;
2223
Michael Chan59b47d82006-11-19 14:10:45 -08002224 for (i = 0; i < bp->ctx_pages; i++) {
2225 int j;
2226
2227 REG_WR(bp, BNX2_CTX_HOST_PAGE_TBL_DATA0,
2228 (bp->ctx_blk_mapping[i] & 0xffffffff) |
2229 BNX2_CTX_HOST_PAGE_TBL_DATA0_VALID);
2230 REG_WR(bp, BNX2_CTX_HOST_PAGE_TBL_DATA1,
2231 (u64) bp->ctx_blk_mapping[i] >> 32);
2232 REG_WR(bp, BNX2_CTX_HOST_PAGE_TBL_CTRL, i |
2233 BNX2_CTX_HOST_PAGE_TBL_CTRL_WRITE_REQ);
2234 for (j = 0; j < 10; j++) {
2235
2236 val = REG_RD(bp, BNX2_CTX_HOST_PAGE_TBL_CTRL);
2237 if (!(val & BNX2_CTX_HOST_PAGE_TBL_CTRL_WRITE_REQ))
2238 break;
2239 udelay(5);
2240 }
2241 if (val & BNX2_CTX_HOST_PAGE_TBL_CTRL_WRITE_REQ) {
2242 ret = -EBUSY;
2243 break;
2244 }
2245 }
2246 return ret;
2247}
2248
Michael Chanb6016b72005-05-26 13:03:09 -07002249static void
2250bnx2_init_context(struct bnx2 *bp)
2251{
2252 u32 vcid;
2253
2254 vcid = 96;
2255 while (vcid) {
2256 u32 vcid_addr, pcid_addr, offset;
Michael Chan7947b202007-06-04 21:17:10 -07002257 int i;
Michael Chanb6016b72005-05-26 13:03:09 -07002258
2259 vcid--;
2260
2261 if (CHIP_ID(bp) == CHIP_ID_5706_A0) {
2262 u32 new_vcid;
2263
2264 vcid_addr = GET_PCID_ADDR(vcid);
2265 if (vcid & 0x8) {
2266 new_vcid = 0x60 + (vcid & 0xf0) + (vcid & 0x7);
2267 }
2268 else {
2269 new_vcid = vcid;
2270 }
2271 pcid_addr = GET_PCID_ADDR(new_vcid);
2272 }
2273 else {
2274 vcid_addr = GET_CID_ADDR(vcid);
2275 pcid_addr = vcid_addr;
2276 }
2277
Michael Chan7947b202007-06-04 21:17:10 -07002278 for (i = 0; i < (CTX_SIZE / PHY_CTX_SIZE); i++) {
2279 vcid_addr += (i << PHY_CTX_SHIFT);
2280 pcid_addr += (i << PHY_CTX_SHIFT);
Michael Chanb6016b72005-05-26 13:03:09 -07002281
Michael Chan5d5d0012007-12-12 11:17:43 -08002282 REG_WR(bp, BNX2_CTX_VIRT_ADDR, vcid_addr);
Michael Chan7947b202007-06-04 21:17:10 -07002283 REG_WR(bp, BNX2_CTX_PAGE_TBL, pcid_addr);
2284
2285 /* Zero out the context. */
2286 for (offset = 0; offset < PHY_CTX_SIZE; offset += 4)
Michael Chan62a83132008-01-29 21:35:40 -08002287 bnx2_ctx_wr(bp, vcid_addr, offset, 0);
Michael Chanb6016b72005-05-26 13:03:09 -07002288 }
Michael Chanb6016b72005-05-26 13:03:09 -07002289 }
2290}
2291
2292static int
2293bnx2_alloc_bad_rbuf(struct bnx2 *bp)
2294{
2295 u16 *good_mbuf;
2296 u32 good_mbuf_cnt;
2297 u32 val;
2298
2299 good_mbuf = kmalloc(512 * sizeof(u16), GFP_KERNEL);
2300 if (good_mbuf == NULL) {
2301 printk(KERN_ERR PFX "Failed to allocate memory in "
2302 "bnx2_alloc_bad_rbuf\n");
2303 return -ENOMEM;
2304 }
2305
2306 REG_WR(bp, BNX2_MISC_ENABLE_SET_BITS,
2307 BNX2_MISC_ENABLE_SET_BITS_RX_MBUF_ENABLE);
2308
2309 good_mbuf_cnt = 0;
2310
2311 /* Allocate a bunch of mbufs and save the good ones in an array. */
Michael Chan2726d6e2008-01-29 21:35:05 -08002312 val = bnx2_reg_rd_ind(bp, BNX2_RBUF_STATUS1);
Michael Chanb6016b72005-05-26 13:03:09 -07002313 while (val & BNX2_RBUF_STATUS1_FREE_COUNT) {
Michael Chan2726d6e2008-01-29 21:35:05 -08002314 bnx2_reg_wr_ind(bp, BNX2_RBUF_COMMAND,
2315 BNX2_RBUF_COMMAND_ALLOC_REQ);
Michael Chanb6016b72005-05-26 13:03:09 -07002316
Michael Chan2726d6e2008-01-29 21:35:05 -08002317 val = bnx2_reg_rd_ind(bp, BNX2_RBUF_FW_BUF_ALLOC);
Michael Chanb6016b72005-05-26 13:03:09 -07002318
2319 val &= BNX2_RBUF_FW_BUF_ALLOC_VALUE;
2320
2321 /* The addresses with Bit 9 set are bad memory blocks. */
2322 if (!(val & (1 << 9))) {
2323 good_mbuf[good_mbuf_cnt] = (u16) val;
2324 good_mbuf_cnt++;
2325 }
2326
Michael Chan2726d6e2008-01-29 21:35:05 -08002327 val = bnx2_reg_rd_ind(bp, BNX2_RBUF_STATUS1);
Michael Chanb6016b72005-05-26 13:03:09 -07002328 }
2329
2330 /* Free the good ones back to the mbuf pool thus discarding
2331 * all the bad ones. */
2332 while (good_mbuf_cnt) {
2333 good_mbuf_cnt--;
2334
2335 val = good_mbuf[good_mbuf_cnt];
2336 val = (val << 9) | val | 1;
2337
Michael Chan2726d6e2008-01-29 21:35:05 -08002338 bnx2_reg_wr_ind(bp, BNX2_RBUF_FW_BUF_FREE, val);
Michael Chanb6016b72005-05-26 13:03:09 -07002339 }
2340 kfree(good_mbuf);
2341 return 0;
2342}
2343
2344static void
Jeff Garzik6aa20a22006-09-13 13:24:59 -04002345bnx2_set_mac_addr(struct bnx2 *bp)
Michael Chanb6016b72005-05-26 13:03:09 -07002346{
2347 u32 val;
2348 u8 *mac_addr = bp->dev->dev_addr;
2349
2350 val = (mac_addr[0] << 8) | mac_addr[1];
2351
2352 REG_WR(bp, BNX2_EMAC_MAC_MATCH0, val);
2353
Jeff Garzik6aa20a22006-09-13 13:24:59 -04002354 val = (mac_addr[2] << 24) | (mac_addr[3] << 16) |
Michael Chanb6016b72005-05-26 13:03:09 -07002355 (mac_addr[4] << 8) | mac_addr[5];
2356
2357 REG_WR(bp, BNX2_EMAC_MAC_MATCH1, val);
2358}
2359
2360static inline int
Michael Chan47bf4242007-12-12 11:19:12 -08002361bnx2_alloc_rx_page(struct bnx2 *bp, u16 index)
2362{
2363 dma_addr_t mapping;
2364 struct sw_pg *rx_pg = &bp->rx_pg_ring[index];
2365 struct rx_bd *rxbd =
2366 &bp->rx_pg_desc_ring[RX_RING(index)][RX_IDX(index)];
2367 struct page *page = alloc_page(GFP_ATOMIC);
2368
2369 if (!page)
2370 return -ENOMEM;
2371 mapping = pci_map_page(bp->pdev, page, 0, PAGE_SIZE,
2372 PCI_DMA_FROMDEVICE);
2373 rx_pg->page = page;
2374 pci_unmap_addr_set(rx_pg, mapping, mapping);
2375 rxbd->rx_bd_haddr_hi = (u64) mapping >> 32;
2376 rxbd->rx_bd_haddr_lo = (u64) mapping & 0xffffffff;
2377 return 0;
2378}
2379
2380static void
2381bnx2_free_rx_page(struct bnx2 *bp, u16 index)
2382{
2383 struct sw_pg *rx_pg = &bp->rx_pg_ring[index];
2384 struct page *page = rx_pg->page;
2385
2386 if (!page)
2387 return;
2388
2389 pci_unmap_page(bp->pdev, pci_unmap_addr(rx_pg, mapping), PAGE_SIZE,
2390 PCI_DMA_FROMDEVICE);
2391
2392 __free_page(page);
2393 rx_pg->page = NULL;
2394}
2395
2396static inline int
Michael Chana1f60192007-12-20 19:57:19 -08002397bnx2_alloc_rx_skb(struct bnx2 *bp, struct bnx2_napi *bnapi, u16 index)
Michael Chanb6016b72005-05-26 13:03:09 -07002398{
2399 struct sk_buff *skb;
2400 struct sw_bd *rx_buf = &bp->rx_buf_ring[index];
2401 dma_addr_t mapping;
Michael Chan13daffa2006-03-20 17:49:20 -08002402 struct rx_bd *rxbd = &bp->rx_desc_ring[RX_RING(index)][RX_IDX(index)];
Michael Chanb6016b72005-05-26 13:03:09 -07002403 unsigned long align;
2404
Michael Chan932f3772006-08-15 01:39:36 -07002405 skb = netdev_alloc_skb(bp->dev, bp->rx_buf_size);
Michael Chanb6016b72005-05-26 13:03:09 -07002406 if (skb == NULL) {
2407 return -ENOMEM;
2408 }
2409
Michael Chan59b47d82006-11-19 14:10:45 -08002410 if (unlikely((align = (unsigned long) skb->data & (BNX2_RX_ALIGN - 1))))
2411 skb_reserve(skb, BNX2_RX_ALIGN - align);
Michael Chanb6016b72005-05-26 13:03:09 -07002412
Michael Chanb6016b72005-05-26 13:03:09 -07002413 mapping = pci_map_single(bp->pdev, skb->data, bp->rx_buf_use_size,
2414 PCI_DMA_FROMDEVICE);
2415
2416 rx_buf->skb = skb;
2417 pci_unmap_addr_set(rx_buf, mapping, mapping);
2418
2419 rxbd->rx_bd_haddr_hi = (u64) mapping >> 32;
2420 rxbd->rx_bd_haddr_lo = (u64) mapping & 0xffffffff;
2421
Michael Chana1f60192007-12-20 19:57:19 -08002422 bnapi->rx_prod_bseq += bp->rx_buf_use_size;
Michael Chanb6016b72005-05-26 13:03:09 -07002423
2424 return 0;
2425}
2426
Michael Chanda3e4fb2007-05-03 13:24:23 -07002427static int
Michael Chan35efa7c2007-12-20 19:56:37 -08002428bnx2_phy_event_is_set(struct bnx2 *bp, struct bnx2_napi *bnapi, u32 event)
Michael Chanda3e4fb2007-05-03 13:24:23 -07002429{
Michael Chan35efa7c2007-12-20 19:56:37 -08002430 struct status_block *sblk = bnapi->status_blk;
Michael Chanda3e4fb2007-05-03 13:24:23 -07002431 u32 new_link_state, old_link_state;
2432 int is_set = 1;
2433
2434 new_link_state = sblk->status_attn_bits & event;
2435 old_link_state = sblk->status_attn_bits_ack & event;
2436 if (new_link_state != old_link_state) {
2437 if (new_link_state)
2438 REG_WR(bp, BNX2_PCICFG_STATUS_BIT_SET_CMD, event);
2439 else
2440 REG_WR(bp, BNX2_PCICFG_STATUS_BIT_CLEAR_CMD, event);
2441 } else
2442 is_set = 0;
2443
2444 return is_set;
2445}
2446
Michael Chanb6016b72005-05-26 13:03:09 -07002447static void
Michael Chan35efa7c2007-12-20 19:56:37 -08002448bnx2_phy_int(struct bnx2 *bp, struct bnx2_napi *bnapi)
Michael Chanb6016b72005-05-26 13:03:09 -07002449{
Michael Chan35efa7c2007-12-20 19:56:37 -08002450 if (bnx2_phy_event_is_set(bp, bnapi, STATUS_ATTN_BITS_LINK_STATE)) {
Michael Chanda3e4fb2007-05-03 13:24:23 -07002451 spin_lock(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07002452 bnx2_set_link(bp);
Michael Chanda3e4fb2007-05-03 13:24:23 -07002453 spin_unlock(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07002454 }
Michael Chan35efa7c2007-12-20 19:56:37 -08002455 if (bnx2_phy_event_is_set(bp, bnapi, STATUS_ATTN_BITS_TIMER_ABORT))
Michael Chan0d8a6572007-07-07 22:49:43 -07002456 bnx2_set_remote_link(bp);
2457
Michael Chanb6016b72005-05-26 13:03:09 -07002458}
2459
Michael Chanead72702007-12-20 19:55:39 -08002460static inline u16
Michael Chan35efa7c2007-12-20 19:56:37 -08002461bnx2_get_hw_tx_cons(struct bnx2_napi *bnapi)
Michael Chanead72702007-12-20 19:55:39 -08002462{
2463 u16 cons;
2464
Michael Chanc76c0472007-12-20 20:01:19 -08002465 if (bnapi->int_num == 0)
2466 cons = bnapi->status_blk->status_tx_quick_consumer_index0;
2467 else
2468 cons = bnapi->status_blk_msix->status_tx_quick_consumer_index;
Michael Chanead72702007-12-20 19:55:39 -08002469
2470 if (unlikely((cons & MAX_TX_DESC_CNT) == MAX_TX_DESC_CNT))
2471 cons++;
2472 return cons;
2473}
2474
Michael Chan57851d82007-12-20 20:01:44 -08002475static int
2476bnx2_tx_int(struct bnx2 *bp, struct bnx2_napi *bnapi, int budget)
Michael Chanb6016b72005-05-26 13:03:09 -07002477{
2478 u16 hw_cons, sw_cons, sw_ring_cons;
Michael Chan57851d82007-12-20 20:01:44 -08002479 int tx_pkt = 0;
Michael Chanb6016b72005-05-26 13:03:09 -07002480
Michael Chan35efa7c2007-12-20 19:56:37 -08002481 hw_cons = bnx2_get_hw_tx_cons(bnapi);
Michael Chana550c992007-12-20 19:56:59 -08002482 sw_cons = bnapi->tx_cons;
Michael Chanb6016b72005-05-26 13:03:09 -07002483
2484 while (sw_cons != hw_cons) {
2485 struct sw_bd *tx_buf;
2486 struct sk_buff *skb;
2487 int i, last;
2488
2489 sw_ring_cons = TX_RING_IDX(sw_cons);
2490
2491 tx_buf = &bp->tx_buf_ring[sw_ring_cons];
2492 skb = tx_buf->skb;
Arjan van de Ven1d39ed52006-12-12 14:06:23 +01002493
Michael Chanb6016b72005-05-26 13:03:09 -07002494 /* partial BD completions possible with TSO packets */
Herbert Xu89114af2006-07-08 13:34:32 -07002495 if (skb_is_gso(skb)) {
Michael Chanb6016b72005-05-26 13:03:09 -07002496 u16 last_idx, last_ring_idx;
2497
2498 last_idx = sw_cons +
2499 skb_shinfo(skb)->nr_frags + 1;
2500 last_ring_idx = sw_ring_cons +
2501 skb_shinfo(skb)->nr_frags + 1;
2502 if (unlikely(last_ring_idx >= MAX_TX_DESC_CNT)) {
2503 last_idx++;
2504 }
2505 if (((s16) ((s16) last_idx - (s16) hw_cons)) > 0) {
2506 break;
2507 }
2508 }
Arjan van de Ven1d39ed52006-12-12 14:06:23 +01002509
Michael Chanb6016b72005-05-26 13:03:09 -07002510 pci_unmap_single(bp->pdev, pci_unmap_addr(tx_buf, mapping),
2511 skb_headlen(skb), PCI_DMA_TODEVICE);
2512
2513 tx_buf->skb = NULL;
2514 last = skb_shinfo(skb)->nr_frags;
2515
2516 for (i = 0; i < last; i++) {
2517 sw_cons = NEXT_TX_BD(sw_cons);
2518
2519 pci_unmap_page(bp->pdev,
2520 pci_unmap_addr(
2521 &bp->tx_buf_ring[TX_RING_IDX(sw_cons)],
2522 mapping),
2523 skb_shinfo(skb)->frags[i].size,
2524 PCI_DMA_TODEVICE);
2525 }
2526
2527 sw_cons = NEXT_TX_BD(sw_cons);
2528
Michael Chan745720e2006-06-29 12:37:41 -07002529 dev_kfree_skb(skb);
Michael Chan57851d82007-12-20 20:01:44 -08002530 tx_pkt++;
2531 if (tx_pkt == budget)
2532 break;
Michael Chanb6016b72005-05-26 13:03:09 -07002533
Michael Chan35efa7c2007-12-20 19:56:37 -08002534 hw_cons = bnx2_get_hw_tx_cons(bnapi);
Michael Chanb6016b72005-05-26 13:03:09 -07002535 }
2536
Michael Chana550c992007-12-20 19:56:59 -08002537 bnapi->hw_tx_cons = hw_cons;
2538 bnapi->tx_cons = sw_cons;
Michael Chan2f8af122006-08-15 01:39:10 -07002539 /* Need to make the tx_cons update visible to bnx2_start_xmit()
2540 * before checking for netif_queue_stopped(). Without the
2541 * memory barrier, there is a small possibility that bnx2_start_xmit()
2542 * will miss it and cause the queue to be stopped forever.
2543 */
2544 smp_mb();
Michael Chanb6016b72005-05-26 13:03:09 -07002545
Michael Chan2f8af122006-08-15 01:39:10 -07002546 if (unlikely(netif_queue_stopped(bp->dev)) &&
Michael Chana550c992007-12-20 19:56:59 -08002547 (bnx2_tx_avail(bp, bnapi) > bp->tx_wake_thresh)) {
Michael Chan2f8af122006-08-15 01:39:10 -07002548 netif_tx_lock(bp->dev);
Michael Chanb6016b72005-05-26 13:03:09 -07002549 if ((netif_queue_stopped(bp->dev)) &&
Michael Chana550c992007-12-20 19:56:59 -08002550 (bnx2_tx_avail(bp, bnapi) > bp->tx_wake_thresh))
Michael Chanb6016b72005-05-26 13:03:09 -07002551 netif_wake_queue(bp->dev);
Michael Chan2f8af122006-08-15 01:39:10 -07002552 netif_tx_unlock(bp->dev);
Michael Chanb6016b72005-05-26 13:03:09 -07002553 }
Michael Chan57851d82007-12-20 20:01:44 -08002554 return tx_pkt;
Michael Chanb6016b72005-05-26 13:03:09 -07002555}
2556
Michael Chan1db82f22007-12-12 11:19:35 -08002557static void
Michael Chana1f60192007-12-20 19:57:19 -08002558bnx2_reuse_rx_skb_pages(struct bnx2 *bp, struct bnx2_napi *bnapi,
2559 struct sk_buff *skb, int count)
Michael Chan1db82f22007-12-12 11:19:35 -08002560{
2561 struct sw_pg *cons_rx_pg, *prod_rx_pg;
2562 struct rx_bd *cons_bd, *prod_bd;
2563 dma_addr_t mapping;
2564 int i;
Michael Chana1f60192007-12-20 19:57:19 -08002565 u16 hw_prod = bnapi->rx_pg_prod, prod;
2566 u16 cons = bnapi->rx_pg_cons;
Michael Chan1db82f22007-12-12 11:19:35 -08002567
2568 for (i = 0; i < count; i++) {
2569 prod = RX_PG_RING_IDX(hw_prod);
2570
2571 prod_rx_pg = &bp->rx_pg_ring[prod];
2572 cons_rx_pg = &bp->rx_pg_ring[cons];
2573 cons_bd = &bp->rx_pg_desc_ring[RX_RING(cons)][RX_IDX(cons)];
2574 prod_bd = &bp->rx_pg_desc_ring[RX_RING(prod)][RX_IDX(prod)];
2575
2576 if (i == 0 && skb) {
2577 struct page *page;
2578 struct skb_shared_info *shinfo;
2579
2580 shinfo = skb_shinfo(skb);
2581 shinfo->nr_frags--;
2582 page = shinfo->frags[shinfo->nr_frags].page;
2583 shinfo->frags[shinfo->nr_frags].page = NULL;
2584 mapping = pci_map_page(bp->pdev, page, 0, PAGE_SIZE,
2585 PCI_DMA_FROMDEVICE);
2586 cons_rx_pg->page = page;
2587 pci_unmap_addr_set(cons_rx_pg, mapping, mapping);
2588 dev_kfree_skb(skb);
2589 }
2590 if (prod != cons) {
2591 prod_rx_pg->page = cons_rx_pg->page;
2592 cons_rx_pg->page = NULL;
2593 pci_unmap_addr_set(prod_rx_pg, mapping,
2594 pci_unmap_addr(cons_rx_pg, mapping));
2595
2596 prod_bd->rx_bd_haddr_hi = cons_bd->rx_bd_haddr_hi;
2597 prod_bd->rx_bd_haddr_lo = cons_bd->rx_bd_haddr_lo;
2598
2599 }
2600 cons = RX_PG_RING_IDX(NEXT_RX_BD(cons));
2601 hw_prod = NEXT_RX_BD(hw_prod);
2602 }
Michael Chana1f60192007-12-20 19:57:19 -08002603 bnapi->rx_pg_prod = hw_prod;
2604 bnapi->rx_pg_cons = cons;
Michael Chan1db82f22007-12-12 11:19:35 -08002605}
2606
Michael Chanb6016b72005-05-26 13:03:09 -07002607static inline void
Michael Chana1f60192007-12-20 19:57:19 -08002608bnx2_reuse_rx_skb(struct bnx2 *bp, struct bnx2_napi *bnapi, struct sk_buff *skb,
Michael Chanb6016b72005-05-26 13:03:09 -07002609 u16 cons, u16 prod)
2610{
Michael Chan236b6392006-03-20 17:49:02 -08002611 struct sw_bd *cons_rx_buf, *prod_rx_buf;
2612 struct rx_bd *cons_bd, *prod_bd;
2613
2614 cons_rx_buf = &bp->rx_buf_ring[cons];
2615 prod_rx_buf = &bp->rx_buf_ring[prod];
Michael Chanb6016b72005-05-26 13:03:09 -07002616
2617 pci_dma_sync_single_for_device(bp->pdev,
2618 pci_unmap_addr(cons_rx_buf, mapping),
2619 bp->rx_offset + RX_COPY_THRESH, PCI_DMA_FROMDEVICE);
2620
Michael Chana1f60192007-12-20 19:57:19 -08002621 bnapi->rx_prod_bseq += bp->rx_buf_use_size;
Michael Chan236b6392006-03-20 17:49:02 -08002622
2623 prod_rx_buf->skb = skb;
2624
2625 if (cons == prod)
2626 return;
2627
Michael Chanb6016b72005-05-26 13:03:09 -07002628 pci_unmap_addr_set(prod_rx_buf, mapping,
2629 pci_unmap_addr(cons_rx_buf, mapping));
2630
Michael Chan3fdfcc22006-03-20 17:49:49 -08002631 cons_bd = &bp->rx_desc_ring[RX_RING(cons)][RX_IDX(cons)];
2632 prod_bd = &bp->rx_desc_ring[RX_RING(prod)][RX_IDX(prod)];
Michael Chan236b6392006-03-20 17:49:02 -08002633 prod_bd->rx_bd_haddr_hi = cons_bd->rx_bd_haddr_hi;
2634 prod_bd->rx_bd_haddr_lo = cons_bd->rx_bd_haddr_lo;
Michael Chanb6016b72005-05-26 13:03:09 -07002635}
2636
Michael Chan85833c62007-12-12 11:17:01 -08002637static int
Michael Chana1f60192007-12-20 19:57:19 -08002638bnx2_rx_skb(struct bnx2 *bp, struct bnx2_napi *bnapi, struct sk_buff *skb,
2639 unsigned int len, unsigned int hdr_len, dma_addr_t dma_addr,
2640 u32 ring_idx)
Michael Chan85833c62007-12-12 11:17:01 -08002641{
2642 int err;
2643 u16 prod = ring_idx & 0xffff;
2644
Michael Chana1f60192007-12-20 19:57:19 -08002645 err = bnx2_alloc_rx_skb(bp, bnapi, prod);
Michael Chan85833c62007-12-12 11:17:01 -08002646 if (unlikely(err)) {
Michael Chana1f60192007-12-20 19:57:19 -08002647 bnx2_reuse_rx_skb(bp, bnapi, skb, (u16) (ring_idx >> 16), prod);
Michael Chan1db82f22007-12-12 11:19:35 -08002648 if (hdr_len) {
2649 unsigned int raw_len = len + 4;
2650 int pages = PAGE_ALIGN(raw_len - hdr_len) >> PAGE_SHIFT;
2651
Michael Chana1f60192007-12-20 19:57:19 -08002652 bnx2_reuse_rx_skb_pages(bp, bnapi, NULL, pages);
Michael Chan1db82f22007-12-12 11:19:35 -08002653 }
Michael Chan85833c62007-12-12 11:17:01 -08002654 return err;
2655 }
2656
2657 skb_reserve(skb, bp->rx_offset);
2658 pci_unmap_single(bp->pdev, dma_addr, bp->rx_buf_use_size,
2659 PCI_DMA_FROMDEVICE);
2660
Michael Chan1db82f22007-12-12 11:19:35 -08002661 if (hdr_len == 0) {
2662 skb_put(skb, len);
2663 return 0;
2664 } else {
2665 unsigned int i, frag_len, frag_size, pages;
2666 struct sw_pg *rx_pg;
Michael Chana1f60192007-12-20 19:57:19 -08002667 u16 pg_cons = bnapi->rx_pg_cons;
2668 u16 pg_prod = bnapi->rx_pg_prod;
Michael Chan1db82f22007-12-12 11:19:35 -08002669
2670 frag_size = len + 4 - hdr_len;
2671 pages = PAGE_ALIGN(frag_size) >> PAGE_SHIFT;
2672 skb_put(skb, hdr_len);
2673
2674 for (i = 0; i < pages; i++) {
2675 frag_len = min(frag_size, (unsigned int) PAGE_SIZE);
2676 if (unlikely(frag_len <= 4)) {
2677 unsigned int tail = 4 - frag_len;
2678
Michael Chana1f60192007-12-20 19:57:19 -08002679 bnapi->rx_pg_cons = pg_cons;
2680 bnapi->rx_pg_prod = pg_prod;
2681 bnx2_reuse_rx_skb_pages(bp, bnapi, NULL,
2682 pages - i);
Michael Chan1db82f22007-12-12 11:19:35 -08002683 skb->len -= tail;
2684 if (i == 0) {
2685 skb->tail -= tail;
2686 } else {
2687 skb_frag_t *frag =
2688 &skb_shinfo(skb)->frags[i - 1];
2689 frag->size -= tail;
2690 skb->data_len -= tail;
2691 skb->truesize -= tail;
2692 }
2693 return 0;
2694 }
2695 rx_pg = &bp->rx_pg_ring[pg_cons];
2696
2697 pci_unmap_page(bp->pdev, pci_unmap_addr(rx_pg, mapping),
2698 PAGE_SIZE, PCI_DMA_FROMDEVICE);
2699
2700 if (i == pages - 1)
2701 frag_len -= 4;
2702
2703 skb_fill_page_desc(skb, i, rx_pg->page, 0, frag_len);
2704 rx_pg->page = NULL;
2705
2706 err = bnx2_alloc_rx_page(bp, RX_PG_RING_IDX(pg_prod));
2707 if (unlikely(err)) {
Michael Chana1f60192007-12-20 19:57:19 -08002708 bnapi->rx_pg_cons = pg_cons;
2709 bnapi->rx_pg_prod = pg_prod;
2710 bnx2_reuse_rx_skb_pages(bp, bnapi, skb,
2711 pages - i);
Michael Chan1db82f22007-12-12 11:19:35 -08002712 return err;
2713 }
2714
2715 frag_size -= frag_len;
2716 skb->data_len += frag_len;
2717 skb->truesize += frag_len;
2718 skb->len += frag_len;
2719
2720 pg_prod = NEXT_RX_BD(pg_prod);
2721 pg_cons = RX_PG_RING_IDX(NEXT_RX_BD(pg_cons));
2722 }
Michael Chana1f60192007-12-20 19:57:19 -08002723 bnapi->rx_pg_prod = pg_prod;
2724 bnapi->rx_pg_cons = pg_cons;
Michael Chan1db82f22007-12-12 11:19:35 -08002725 }
Michael Chan85833c62007-12-12 11:17:01 -08002726 return 0;
2727}
2728
Michael Chanc09c2622007-12-10 17:18:37 -08002729static inline u16
Michael Chan35efa7c2007-12-20 19:56:37 -08002730bnx2_get_hw_rx_cons(struct bnx2_napi *bnapi)
Michael Chanc09c2622007-12-10 17:18:37 -08002731{
Michael Chan35efa7c2007-12-20 19:56:37 -08002732 u16 cons = bnapi->status_blk->status_rx_quick_consumer_index0;
Michael Chanc09c2622007-12-10 17:18:37 -08002733
2734 if (unlikely((cons & MAX_RX_DESC_CNT) == MAX_RX_DESC_CNT))
2735 cons++;
2736 return cons;
2737}
2738
Michael Chanb6016b72005-05-26 13:03:09 -07002739static int
Michael Chan35efa7c2007-12-20 19:56:37 -08002740bnx2_rx_int(struct bnx2 *bp, struct bnx2_napi *bnapi, int budget)
Michael Chanb6016b72005-05-26 13:03:09 -07002741{
2742 u16 hw_cons, sw_cons, sw_ring_cons, sw_prod, sw_ring_prod;
2743 struct l2_fhdr *rx_hdr;
Michael Chan1db82f22007-12-12 11:19:35 -08002744 int rx_pkt = 0, pg_ring_used = 0;
Michael Chanb6016b72005-05-26 13:03:09 -07002745
Michael Chan35efa7c2007-12-20 19:56:37 -08002746 hw_cons = bnx2_get_hw_rx_cons(bnapi);
Michael Chana1f60192007-12-20 19:57:19 -08002747 sw_cons = bnapi->rx_cons;
2748 sw_prod = bnapi->rx_prod;
Michael Chanb6016b72005-05-26 13:03:09 -07002749
2750 /* Memory barrier necessary as speculative reads of the rx
2751 * buffer can be ahead of the index in the status block
2752 */
2753 rmb();
2754 while (sw_cons != hw_cons) {
Michael Chan1db82f22007-12-12 11:19:35 -08002755 unsigned int len, hdr_len;
Michael Chanade2bfe2006-01-23 16:09:51 -08002756 u32 status;
Michael Chanb6016b72005-05-26 13:03:09 -07002757 struct sw_bd *rx_buf;
2758 struct sk_buff *skb;
Michael Chan236b6392006-03-20 17:49:02 -08002759 dma_addr_t dma_addr;
Michael Chanb6016b72005-05-26 13:03:09 -07002760
2761 sw_ring_cons = RX_RING_IDX(sw_cons);
2762 sw_ring_prod = RX_RING_IDX(sw_prod);
2763
2764 rx_buf = &bp->rx_buf_ring[sw_ring_cons];
2765 skb = rx_buf->skb;
Michael Chan236b6392006-03-20 17:49:02 -08002766
2767 rx_buf->skb = NULL;
2768
2769 dma_addr = pci_unmap_addr(rx_buf, mapping);
2770
2771 pci_dma_sync_single_for_cpu(bp->pdev, dma_addr,
Michael Chanb6016b72005-05-26 13:03:09 -07002772 bp->rx_offset + RX_COPY_THRESH, PCI_DMA_FROMDEVICE);
2773
2774 rx_hdr = (struct l2_fhdr *) skb->data;
Michael Chan1db82f22007-12-12 11:19:35 -08002775 len = rx_hdr->l2_fhdr_pkt_len;
Michael Chanb6016b72005-05-26 13:03:09 -07002776
Michael Chanade2bfe2006-01-23 16:09:51 -08002777 if ((status = rx_hdr->l2_fhdr_status) &
Michael Chanb6016b72005-05-26 13:03:09 -07002778 (L2_FHDR_ERRORS_BAD_CRC |
2779 L2_FHDR_ERRORS_PHY_DECODE |
2780 L2_FHDR_ERRORS_ALIGNMENT |
2781 L2_FHDR_ERRORS_TOO_SHORT |
2782 L2_FHDR_ERRORS_GIANT_FRAME)) {
2783
Michael Chana1f60192007-12-20 19:57:19 -08002784 bnx2_reuse_rx_skb(bp, bnapi, skb, sw_ring_cons,
2785 sw_ring_prod);
Michael Chan85833c62007-12-12 11:17:01 -08002786 goto next_rx;
Michael Chanb6016b72005-05-26 13:03:09 -07002787 }
Michael Chan1db82f22007-12-12 11:19:35 -08002788 hdr_len = 0;
2789 if (status & L2_FHDR_STATUS_SPLIT) {
2790 hdr_len = rx_hdr->l2_fhdr_ip_xsum;
2791 pg_ring_used = 1;
2792 } else if (len > bp->rx_jumbo_thresh) {
2793 hdr_len = bp->rx_jumbo_thresh;
2794 pg_ring_used = 1;
2795 }
2796
2797 len -= 4;
Michael Chanb6016b72005-05-26 13:03:09 -07002798
Michael Chan5d5d0012007-12-12 11:17:43 -08002799 if (len <= bp->rx_copy_thresh) {
Michael Chanb6016b72005-05-26 13:03:09 -07002800 struct sk_buff *new_skb;
2801
Michael Chan932f3772006-08-15 01:39:36 -07002802 new_skb = netdev_alloc_skb(bp->dev, len + 2);
Michael Chan85833c62007-12-12 11:17:01 -08002803 if (new_skb == NULL) {
Michael Chana1f60192007-12-20 19:57:19 -08002804 bnx2_reuse_rx_skb(bp, bnapi, skb, sw_ring_cons,
Michael Chan85833c62007-12-12 11:17:01 -08002805 sw_ring_prod);
2806 goto next_rx;
2807 }
Michael Chanb6016b72005-05-26 13:03:09 -07002808
2809 /* aligned copy */
Arnaldo Carvalho de Melod626f622007-03-27 18:55:52 -03002810 skb_copy_from_linear_data_offset(skb, bp->rx_offset - 2,
2811 new_skb->data, len + 2);
Michael Chanb6016b72005-05-26 13:03:09 -07002812 skb_reserve(new_skb, 2);
2813 skb_put(new_skb, len);
Michael Chanb6016b72005-05-26 13:03:09 -07002814
Michael Chana1f60192007-12-20 19:57:19 -08002815 bnx2_reuse_rx_skb(bp, bnapi, skb,
Michael Chanb6016b72005-05-26 13:03:09 -07002816 sw_ring_cons, sw_ring_prod);
2817
2818 skb = new_skb;
Michael Chana1f60192007-12-20 19:57:19 -08002819 } else if (unlikely(bnx2_rx_skb(bp, bnapi, skb, len, hdr_len,
2820 dma_addr, (sw_ring_cons << 16) | sw_ring_prod)))
Michael Chanb6016b72005-05-26 13:03:09 -07002821 goto next_rx;
Michael Chanb6016b72005-05-26 13:03:09 -07002822
2823 skb->protocol = eth_type_trans(skb, bp->dev);
2824
2825 if ((len > (bp->dev->mtu + ETH_HLEN)) &&
Alexey Dobriyand1e100b2006-06-11 20:57:17 -07002826 (ntohs(skb->protocol) != 0x8100)) {
Michael Chanb6016b72005-05-26 13:03:09 -07002827
Michael Chan745720e2006-06-29 12:37:41 -07002828 dev_kfree_skb(skb);
Michael Chanb6016b72005-05-26 13:03:09 -07002829 goto next_rx;
2830
2831 }
2832
Michael Chanb6016b72005-05-26 13:03:09 -07002833 skb->ip_summed = CHECKSUM_NONE;
2834 if (bp->rx_csum &&
2835 (status & (L2_FHDR_STATUS_TCP_SEGMENT |
2836 L2_FHDR_STATUS_UDP_DATAGRAM))) {
2837
Michael Chanade2bfe2006-01-23 16:09:51 -08002838 if (likely((status & (L2_FHDR_ERRORS_TCP_XSUM |
2839 L2_FHDR_ERRORS_UDP_XSUM)) == 0))
Michael Chanb6016b72005-05-26 13:03:09 -07002840 skb->ip_summed = CHECKSUM_UNNECESSARY;
2841 }
2842
2843#ifdef BCM_VLAN
Al Viro79ea13c2008-01-24 02:06:46 -08002844 if ((status & L2_FHDR_STATUS_L2_VLAN_TAG) && bp->vlgrp) {
Michael Chanb6016b72005-05-26 13:03:09 -07002845 vlan_hwaccel_receive_skb(skb, bp->vlgrp,
2846 rx_hdr->l2_fhdr_vlan_tag);
2847 }
2848 else
2849#endif
2850 netif_receive_skb(skb);
2851
2852 bp->dev->last_rx = jiffies;
2853 rx_pkt++;
2854
2855next_rx:
Michael Chanb6016b72005-05-26 13:03:09 -07002856 sw_cons = NEXT_RX_BD(sw_cons);
2857 sw_prod = NEXT_RX_BD(sw_prod);
2858
2859 if ((rx_pkt == budget))
2860 break;
Michael Chanf4e418f2005-11-04 08:53:48 -08002861
2862 /* Refresh hw_cons to see if there is new work */
2863 if (sw_cons == hw_cons) {
Michael Chan35efa7c2007-12-20 19:56:37 -08002864 hw_cons = bnx2_get_hw_rx_cons(bnapi);
Michael Chanf4e418f2005-11-04 08:53:48 -08002865 rmb();
2866 }
Michael Chanb6016b72005-05-26 13:03:09 -07002867 }
Michael Chana1f60192007-12-20 19:57:19 -08002868 bnapi->rx_cons = sw_cons;
2869 bnapi->rx_prod = sw_prod;
Michael Chanb6016b72005-05-26 13:03:09 -07002870
Michael Chan1db82f22007-12-12 11:19:35 -08002871 if (pg_ring_used)
2872 REG_WR16(bp, MB_RX_CID_ADDR + BNX2_L2CTX_HOST_PG_BDIDX,
Michael Chana1f60192007-12-20 19:57:19 -08002873 bnapi->rx_pg_prod);
Michael Chan1db82f22007-12-12 11:19:35 -08002874
Michael Chanb6016b72005-05-26 13:03:09 -07002875 REG_WR16(bp, MB_RX_CID_ADDR + BNX2_L2CTX_HOST_BDIDX, sw_prod);
2876
Michael Chana1f60192007-12-20 19:57:19 -08002877 REG_WR(bp, MB_RX_CID_ADDR + BNX2_L2CTX_HOST_BSEQ, bnapi->rx_prod_bseq);
Michael Chanb6016b72005-05-26 13:03:09 -07002878
2879 mmiowb();
2880
2881 return rx_pkt;
2882
2883}
2884
2885/* MSI ISR - The only difference between this and the INTx ISR
2886 * is that the MSI interrupt is always serviced.
2887 */
2888static irqreturn_t
David Howells7d12e782006-10-05 14:55:46 +01002889bnx2_msi(int irq, void *dev_instance)
Michael Chanb6016b72005-05-26 13:03:09 -07002890{
2891 struct net_device *dev = dev_instance;
Michael Chan972ec0d2006-01-23 16:12:43 -08002892 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb4b36042007-12-20 19:59:30 -08002893 struct bnx2_napi *bnapi = &bp->bnx2_napi[0];
Michael Chanb6016b72005-05-26 13:03:09 -07002894
Michael Chan35efa7c2007-12-20 19:56:37 -08002895 prefetch(bnapi->status_blk);
Michael Chanb6016b72005-05-26 13:03:09 -07002896 REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
2897 BNX2_PCICFG_INT_ACK_CMD_USE_INT_HC_PARAM |
2898 BNX2_PCICFG_INT_ACK_CMD_MASK_INT);
2899
2900 /* Return here if interrupt is disabled. */
Michael Chan73eef4c2005-08-25 15:39:15 -07002901 if (unlikely(atomic_read(&bp->intr_sem) != 0))
2902 return IRQ_HANDLED;
Michael Chanb6016b72005-05-26 13:03:09 -07002903
Michael Chan35efa7c2007-12-20 19:56:37 -08002904 netif_rx_schedule(dev, &bnapi->napi);
Michael Chanb6016b72005-05-26 13:03:09 -07002905
Michael Chan73eef4c2005-08-25 15:39:15 -07002906 return IRQ_HANDLED;
Michael Chanb6016b72005-05-26 13:03:09 -07002907}
2908
2909static irqreturn_t
Michael Chan8e6a72c2007-05-03 13:24:48 -07002910bnx2_msi_1shot(int irq, void *dev_instance)
2911{
2912 struct net_device *dev = dev_instance;
2913 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb4b36042007-12-20 19:59:30 -08002914 struct bnx2_napi *bnapi = &bp->bnx2_napi[0];
Michael Chan8e6a72c2007-05-03 13:24:48 -07002915
Michael Chan35efa7c2007-12-20 19:56:37 -08002916 prefetch(bnapi->status_blk);
Michael Chan8e6a72c2007-05-03 13:24:48 -07002917
2918 /* Return here if interrupt is disabled. */
2919 if (unlikely(atomic_read(&bp->intr_sem) != 0))
2920 return IRQ_HANDLED;
2921
Michael Chan35efa7c2007-12-20 19:56:37 -08002922 netif_rx_schedule(dev, &bnapi->napi);
Michael Chan8e6a72c2007-05-03 13:24:48 -07002923
2924 return IRQ_HANDLED;
2925}
2926
2927static irqreturn_t
David Howells7d12e782006-10-05 14:55:46 +01002928bnx2_interrupt(int irq, void *dev_instance)
Michael Chanb6016b72005-05-26 13:03:09 -07002929{
2930 struct net_device *dev = dev_instance;
Michael Chan972ec0d2006-01-23 16:12:43 -08002931 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb4b36042007-12-20 19:59:30 -08002932 struct bnx2_napi *bnapi = &bp->bnx2_napi[0];
Michael Chan35efa7c2007-12-20 19:56:37 -08002933 struct status_block *sblk = bnapi->status_blk;
Michael Chanb6016b72005-05-26 13:03:09 -07002934
2935 /* When using INTx, it is possible for the interrupt to arrive
2936 * at the CPU before the status block posted prior to the
2937 * interrupt. Reading a register will flush the status block.
2938 * When using MSI, the MSI message will always complete after
2939 * the status block write.
2940 */
Michael Chan35efa7c2007-12-20 19:56:37 -08002941 if ((sblk->status_idx == bnapi->last_status_idx) &&
Michael Chanb6016b72005-05-26 13:03:09 -07002942 (REG_RD(bp, BNX2_PCICFG_MISC_STATUS) &
2943 BNX2_PCICFG_MISC_STATUS_INTA_VALUE))
Michael Chan73eef4c2005-08-25 15:39:15 -07002944 return IRQ_NONE;
Michael Chanb6016b72005-05-26 13:03:09 -07002945
2946 REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
2947 BNX2_PCICFG_INT_ACK_CMD_USE_INT_HC_PARAM |
2948 BNX2_PCICFG_INT_ACK_CMD_MASK_INT);
2949
Michael Chanb8a7ce72007-07-07 22:51:03 -07002950 /* Read back to deassert IRQ immediately to avoid too many
2951 * spurious interrupts.
2952 */
2953 REG_RD(bp, BNX2_PCICFG_INT_ACK_CMD);
2954
Michael Chanb6016b72005-05-26 13:03:09 -07002955 /* Return here if interrupt is shared and is disabled. */
Michael Chan73eef4c2005-08-25 15:39:15 -07002956 if (unlikely(atomic_read(&bp->intr_sem) != 0))
2957 return IRQ_HANDLED;
Michael Chanb6016b72005-05-26 13:03:09 -07002958
Michael Chan35efa7c2007-12-20 19:56:37 -08002959 if (netif_rx_schedule_prep(dev, &bnapi->napi)) {
2960 bnapi->last_status_idx = sblk->status_idx;
2961 __netif_rx_schedule(dev, &bnapi->napi);
Michael Chanb8a7ce72007-07-07 22:51:03 -07002962 }
Michael Chanb6016b72005-05-26 13:03:09 -07002963
Michael Chan73eef4c2005-08-25 15:39:15 -07002964 return IRQ_HANDLED;
Michael Chanb6016b72005-05-26 13:03:09 -07002965}
2966
Michael Chan57851d82007-12-20 20:01:44 -08002967static irqreturn_t
2968bnx2_tx_msix(int irq, void *dev_instance)
2969{
2970 struct net_device *dev = dev_instance;
2971 struct bnx2 *bp = netdev_priv(dev);
2972 struct bnx2_napi *bnapi = &bp->bnx2_napi[BNX2_TX_VEC];
2973
2974 prefetch(bnapi->status_blk_msix);
2975
2976 /* Return here if interrupt is disabled. */
2977 if (unlikely(atomic_read(&bp->intr_sem) != 0))
2978 return IRQ_HANDLED;
2979
2980 netif_rx_schedule(dev, &bnapi->napi);
2981 return IRQ_HANDLED;
2982}
2983
Michael Chan0d8a6572007-07-07 22:49:43 -07002984#define STATUS_ATTN_EVENTS (STATUS_ATTN_BITS_LINK_STATE | \
2985 STATUS_ATTN_BITS_TIMER_ABORT)
Michael Chanda3e4fb2007-05-03 13:24:23 -07002986
Michael Chanf4e418f2005-11-04 08:53:48 -08002987static inline int
Michael Chan35efa7c2007-12-20 19:56:37 -08002988bnx2_has_work(struct bnx2_napi *bnapi)
Michael Chanf4e418f2005-11-04 08:53:48 -08002989{
Michael Chan1097f5e2008-01-21 17:06:41 -08002990 struct status_block *sblk = bnapi->status_blk;
Michael Chanf4e418f2005-11-04 08:53:48 -08002991
Michael Chana1f60192007-12-20 19:57:19 -08002992 if ((bnx2_get_hw_rx_cons(bnapi) != bnapi->rx_cons) ||
Michael Chana550c992007-12-20 19:56:59 -08002993 (bnx2_get_hw_tx_cons(bnapi) != bnapi->hw_tx_cons))
Michael Chanf4e418f2005-11-04 08:53:48 -08002994 return 1;
2995
Michael Chanda3e4fb2007-05-03 13:24:23 -07002996 if ((sblk->status_attn_bits & STATUS_ATTN_EVENTS) !=
2997 (sblk->status_attn_bits_ack & STATUS_ATTN_EVENTS))
Michael Chanf4e418f2005-11-04 08:53:48 -08002998 return 1;
2999
3000 return 0;
3001}
3002
Michael Chan57851d82007-12-20 20:01:44 -08003003static int bnx2_tx_poll(struct napi_struct *napi, int budget)
3004{
3005 struct bnx2_napi *bnapi = container_of(napi, struct bnx2_napi, napi);
3006 struct bnx2 *bp = bnapi->bp;
3007 int work_done = 0;
3008 struct status_block_msix *sblk = bnapi->status_blk_msix;
3009
3010 do {
3011 work_done += bnx2_tx_int(bp, bnapi, budget - work_done);
3012 if (unlikely(work_done >= budget))
3013 return work_done;
3014
3015 bnapi->last_status_idx = sblk->status_idx;
3016 rmb();
3017 } while (bnx2_get_hw_tx_cons(bnapi) != bnapi->hw_tx_cons);
3018
3019 netif_rx_complete(bp->dev, napi);
3020 REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD, bnapi->int_num |
3021 BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
3022 bnapi->last_status_idx);
3023 return work_done;
3024}
3025
Michael Chan35efa7c2007-12-20 19:56:37 -08003026static int bnx2_poll_work(struct bnx2 *bp, struct bnx2_napi *bnapi,
3027 int work_done, int budget)
Michael Chanb6016b72005-05-26 13:03:09 -07003028{
Michael Chan35efa7c2007-12-20 19:56:37 -08003029 struct status_block *sblk = bnapi->status_blk;
Michael Chanda3e4fb2007-05-03 13:24:23 -07003030 u32 status_attn_bits = sblk->status_attn_bits;
3031 u32 status_attn_bits_ack = sblk->status_attn_bits_ack;
Michael Chanb6016b72005-05-26 13:03:09 -07003032
Michael Chanda3e4fb2007-05-03 13:24:23 -07003033 if ((status_attn_bits & STATUS_ATTN_EVENTS) !=
3034 (status_attn_bits_ack & STATUS_ATTN_EVENTS)) {
Michael Chanb6016b72005-05-26 13:03:09 -07003035
Michael Chan35efa7c2007-12-20 19:56:37 -08003036 bnx2_phy_int(bp, bnapi);
Michael Chanbf5295b2006-03-23 01:11:56 -08003037
3038 /* This is needed to take care of transient status
3039 * during link changes.
3040 */
3041 REG_WR(bp, BNX2_HC_COMMAND,
3042 bp->hc_cmd | BNX2_HC_COMMAND_COAL_NOW_WO_INT);
3043 REG_RD(bp, BNX2_HC_COMMAND);
Michael Chanb6016b72005-05-26 13:03:09 -07003044 }
3045
Michael Chana550c992007-12-20 19:56:59 -08003046 if (bnx2_get_hw_tx_cons(bnapi) != bnapi->hw_tx_cons)
Michael Chan57851d82007-12-20 20:01:44 -08003047 bnx2_tx_int(bp, bnapi, 0);
Michael Chanb6016b72005-05-26 13:03:09 -07003048
Michael Chana1f60192007-12-20 19:57:19 -08003049 if (bnx2_get_hw_rx_cons(bnapi) != bnapi->rx_cons)
Michael Chan35efa7c2007-12-20 19:56:37 -08003050 work_done += bnx2_rx_int(bp, bnapi, budget - work_done);
Jeff Garzik6aa20a22006-09-13 13:24:59 -04003051
David S. Miller6f535762007-10-11 18:08:29 -07003052 return work_done;
3053}
Michael Chanf4e418f2005-11-04 08:53:48 -08003054
David S. Miller6f535762007-10-11 18:08:29 -07003055static int bnx2_poll(struct napi_struct *napi, int budget)
3056{
Michael Chan35efa7c2007-12-20 19:56:37 -08003057 struct bnx2_napi *bnapi = container_of(napi, struct bnx2_napi, napi);
3058 struct bnx2 *bp = bnapi->bp;
David S. Miller6f535762007-10-11 18:08:29 -07003059 int work_done = 0;
Michael Chan35efa7c2007-12-20 19:56:37 -08003060 struct status_block *sblk = bnapi->status_blk;
David S. Miller6f535762007-10-11 18:08:29 -07003061
3062 while (1) {
Michael Chan35efa7c2007-12-20 19:56:37 -08003063 work_done = bnx2_poll_work(bp, bnapi, work_done, budget);
David S. Miller6f535762007-10-11 18:08:29 -07003064
3065 if (unlikely(work_done >= budget))
3066 break;
3067
Michael Chan35efa7c2007-12-20 19:56:37 -08003068 /* bnapi->last_status_idx is used below to tell the hw how
Michael Chan6dee6422007-10-12 01:40:38 -07003069 * much work has been processed, so we must read it before
3070 * checking for more work.
3071 */
Michael Chan35efa7c2007-12-20 19:56:37 -08003072 bnapi->last_status_idx = sblk->status_idx;
Michael Chan6dee6422007-10-12 01:40:38 -07003073 rmb();
Michael Chan35efa7c2007-12-20 19:56:37 -08003074 if (likely(!bnx2_has_work(bnapi))) {
David S. Miller6f535762007-10-11 18:08:29 -07003075 netif_rx_complete(bp->dev, napi);
David S. Millerf86e82f2008-01-21 17:15:40 -08003076 if (likely(bp->flags & BNX2_FLAG_USING_MSI_OR_MSIX)) {
David S. Miller6f535762007-10-11 18:08:29 -07003077 REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
3078 BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
Michael Chan35efa7c2007-12-20 19:56:37 -08003079 bnapi->last_status_idx);
Michael Chan6dee6422007-10-12 01:40:38 -07003080 break;
David S. Miller6f535762007-10-11 18:08:29 -07003081 }
3082 REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
3083 BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
3084 BNX2_PCICFG_INT_ACK_CMD_MASK_INT |
Michael Chan35efa7c2007-12-20 19:56:37 -08003085 bnapi->last_status_idx);
David S. Miller6f535762007-10-11 18:08:29 -07003086
Michael Chan1269a8a2006-01-23 16:11:03 -08003087 REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
3088 BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
Michael Chan35efa7c2007-12-20 19:56:37 -08003089 bnapi->last_status_idx);
David S. Miller6f535762007-10-11 18:08:29 -07003090 break;
Michael Chan1269a8a2006-01-23 16:11:03 -08003091 }
Michael Chanb6016b72005-05-26 13:03:09 -07003092 }
3093
Stephen Hemmingerbea33482007-10-03 16:41:36 -07003094 return work_done;
Michael Chanb6016b72005-05-26 13:03:09 -07003095}
3096
Herbert Xu932ff272006-06-09 12:20:56 -07003097/* Called with rtnl_lock from vlan functions and also netif_tx_lock
Michael Chanb6016b72005-05-26 13:03:09 -07003098 * from set_multicast.
3099 */
3100static void
3101bnx2_set_rx_mode(struct net_device *dev)
3102{
Michael Chan972ec0d2006-01-23 16:12:43 -08003103 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07003104 u32 rx_mode, sort_mode;
3105 int i;
Michael Chanb6016b72005-05-26 13:03:09 -07003106
Michael Chanc770a652005-08-25 15:38:39 -07003107 spin_lock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07003108
3109 rx_mode = bp->rx_mode & ~(BNX2_EMAC_RX_MODE_PROMISCUOUS |
3110 BNX2_EMAC_RX_MODE_KEEP_VLAN_TAG);
3111 sort_mode = 1 | BNX2_RPM_SORT_USER0_BC_EN;
3112#ifdef BCM_VLAN
David S. Millerf86e82f2008-01-21 17:15:40 -08003113 if (!bp->vlgrp && !(bp->flags & BNX2_FLAG_ASF_ENABLE))
Michael Chanb6016b72005-05-26 13:03:09 -07003114 rx_mode |= BNX2_EMAC_RX_MODE_KEEP_VLAN_TAG;
Michael Chanb6016b72005-05-26 13:03:09 -07003115#else
David S. Millerf86e82f2008-01-21 17:15:40 -08003116 if (!(bp->flags & BNX2_FLAG_ASF_ENABLE))
Michael Chane29054f2006-01-23 16:06:06 -08003117 rx_mode |= BNX2_EMAC_RX_MODE_KEEP_VLAN_TAG;
Michael Chanb6016b72005-05-26 13:03:09 -07003118#endif
3119 if (dev->flags & IFF_PROMISC) {
3120 /* Promiscuous mode. */
3121 rx_mode |= BNX2_EMAC_RX_MODE_PROMISCUOUS;
Michael Chan75108732006-11-19 14:06:40 -08003122 sort_mode |= BNX2_RPM_SORT_USER0_PROM_EN |
3123 BNX2_RPM_SORT_USER0_PROM_VLAN;
Michael Chanb6016b72005-05-26 13:03:09 -07003124 }
3125 else if (dev->flags & IFF_ALLMULTI) {
3126 for (i = 0; i < NUM_MC_HASH_REGISTERS; i++) {
3127 REG_WR(bp, BNX2_EMAC_MULTICAST_HASH0 + (i * 4),
3128 0xffffffff);
3129 }
3130 sort_mode |= BNX2_RPM_SORT_USER0_MC_EN;
3131 }
3132 else {
3133 /* Accept one or more multicast(s). */
3134 struct dev_mc_list *mclist;
3135 u32 mc_filter[NUM_MC_HASH_REGISTERS];
3136 u32 regidx;
3137 u32 bit;
3138 u32 crc;
3139
3140 memset(mc_filter, 0, 4 * NUM_MC_HASH_REGISTERS);
3141
3142 for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
3143 i++, mclist = mclist->next) {
3144
3145 crc = ether_crc_le(ETH_ALEN, mclist->dmi_addr);
3146 bit = crc & 0xff;
3147 regidx = (bit & 0xe0) >> 5;
3148 bit &= 0x1f;
3149 mc_filter[regidx] |= (1 << bit);
3150 }
3151
3152 for (i = 0; i < NUM_MC_HASH_REGISTERS; i++) {
3153 REG_WR(bp, BNX2_EMAC_MULTICAST_HASH0 + (i * 4),
3154 mc_filter[i]);
3155 }
3156
3157 sort_mode |= BNX2_RPM_SORT_USER0_MC_HSH_EN;
3158 }
3159
3160 if (rx_mode != bp->rx_mode) {
3161 bp->rx_mode = rx_mode;
3162 REG_WR(bp, BNX2_EMAC_RX_MODE, rx_mode);
3163 }
3164
3165 REG_WR(bp, BNX2_RPM_SORT_USER0, 0x0);
3166 REG_WR(bp, BNX2_RPM_SORT_USER0, sort_mode);
3167 REG_WR(bp, BNX2_RPM_SORT_USER0, sort_mode | BNX2_RPM_SORT_USER0_ENA);
3168
Michael Chanc770a652005-08-25 15:38:39 -07003169 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07003170}
3171
3172static void
Al Virob491edd2007-12-22 19:44:51 +00003173load_rv2p_fw(struct bnx2 *bp, __le32 *rv2p_code, u32 rv2p_code_len,
Michael Chanb6016b72005-05-26 13:03:09 -07003174 u32 rv2p_proc)
3175{
3176 int i;
3177 u32 val;
3178
3179
3180 for (i = 0; i < rv2p_code_len; i += 8) {
Al Virob491edd2007-12-22 19:44:51 +00003181 REG_WR(bp, BNX2_RV2P_INSTR_HIGH, le32_to_cpu(*rv2p_code));
Michael Chanb6016b72005-05-26 13:03:09 -07003182 rv2p_code++;
Al Virob491edd2007-12-22 19:44:51 +00003183 REG_WR(bp, BNX2_RV2P_INSTR_LOW, le32_to_cpu(*rv2p_code));
Michael Chanb6016b72005-05-26 13:03:09 -07003184 rv2p_code++;
3185
3186 if (rv2p_proc == RV2P_PROC1) {
3187 val = (i / 8) | BNX2_RV2P_PROC1_ADDR_CMD_RDWR;
3188 REG_WR(bp, BNX2_RV2P_PROC1_ADDR_CMD, val);
3189 }
3190 else {
3191 val = (i / 8) | BNX2_RV2P_PROC2_ADDR_CMD_RDWR;
3192 REG_WR(bp, BNX2_RV2P_PROC2_ADDR_CMD, val);
3193 }
3194 }
3195
3196 /* Reset the processor, un-stall is done later. */
3197 if (rv2p_proc == RV2P_PROC1) {
3198 REG_WR(bp, BNX2_RV2P_COMMAND, BNX2_RV2P_COMMAND_PROC1_RESET);
3199 }
3200 else {
3201 REG_WR(bp, BNX2_RV2P_COMMAND, BNX2_RV2P_COMMAND_PROC2_RESET);
3202 }
3203}
3204
Michael Chanaf3ee512006-11-19 14:09:25 -08003205static int
Michael Chanb6016b72005-05-26 13:03:09 -07003206load_cpu_fw(struct bnx2 *bp, struct cpu_reg *cpu_reg, struct fw_info *fw)
3207{
3208 u32 offset;
3209 u32 val;
Michael Chanaf3ee512006-11-19 14:09:25 -08003210 int rc;
Michael Chanb6016b72005-05-26 13:03:09 -07003211
3212 /* Halt the CPU. */
Michael Chan2726d6e2008-01-29 21:35:05 -08003213 val = bnx2_reg_rd_ind(bp, cpu_reg->mode);
Michael Chanb6016b72005-05-26 13:03:09 -07003214 val |= cpu_reg->mode_value_halt;
Michael Chan2726d6e2008-01-29 21:35:05 -08003215 bnx2_reg_wr_ind(bp, cpu_reg->mode, val);
3216 bnx2_reg_wr_ind(bp, cpu_reg->state, cpu_reg->state_value_clear);
Michael Chanb6016b72005-05-26 13:03:09 -07003217
3218 /* Load the Text area. */
3219 offset = cpu_reg->spad_base + (fw->text_addr - cpu_reg->mips_view_base);
Michael Chanaf3ee512006-11-19 14:09:25 -08003220 if (fw->gz_text) {
Michael Chanb6016b72005-05-26 13:03:09 -07003221 int j;
3222
Michael Chanea1f8d52007-10-02 16:27:35 -07003223 rc = zlib_inflate_blob(fw->text, FW_BUF_SIZE, fw->gz_text,
3224 fw->gz_text_len);
3225 if (rc < 0)
Denys Vlasenkob3448b02007-09-30 17:55:51 -07003226 return rc;
Michael Chanea1f8d52007-10-02 16:27:35 -07003227
Michael Chanb6016b72005-05-26 13:03:09 -07003228 for (j = 0; j < (fw->text_len / 4); j++, offset += 4) {
Michael Chan2726d6e2008-01-29 21:35:05 -08003229 bnx2_reg_wr_ind(bp, offset, le32_to_cpu(fw->text[j]));
Michael Chanb6016b72005-05-26 13:03:09 -07003230 }
3231 }
3232
3233 /* Load the Data area. */
3234 offset = cpu_reg->spad_base + (fw->data_addr - cpu_reg->mips_view_base);
3235 if (fw->data) {
3236 int j;
3237
3238 for (j = 0; j < (fw->data_len / 4); j++, offset += 4) {
Michael Chan2726d6e2008-01-29 21:35:05 -08003239 bnx2_reg_wr_ind(bp, offset, fw->data[j]);
Michael Chanb6016b72005-05-26 13:03:09 -07003240 }
3241 }
3242
3243 /* Load the SBSS area. */
3244 offset = cpu_reg->spad_base + (fw->sbss_addr - cpu_reg->mips_view_base);
Michael Chanea1f8d52007-10-02 16:27:35 -07003245 if (fw->sbss_len) {
Michael Chanb6016b72005-05-26 13:03:09 -07003246 int j;
3247
3248 for (j = 0; j < (fw->sbss_len / 4); j++, offset += 4) {
Michael Chan2726d6e2008-01-29 21:35:05 -08003249 bnx2_reg_wr_ind(bp, offset, 0);
Michael Chanb6016b72005-05-26 13:03:09 -07003250 }
3251 }
3252
3253 /* Load the BSS area. */
3254 offset = cpu_reg->spad_base + (fw->bss_addr - cpu_reg->mips_view_base);
Michael Chanea1f8d52007-10-02 16:27:35 -07003255 if (fw->bss_len) {
Michael Chanb6016b72005-05-26 13:03:09 -07003256 int j;
3257
3258 for (j = 0; j < (fw->bss_len/4); j++, offset += 4) {
Michael Chan2726d6e2008-01-29 21:35:05 -08003259 bnx2_reg_wr_ind(bp, offset, 0);
Michael Chanb6016b72005-05-26 13:03:09 -07003260 }
3261 }
3262
3263 /* Load the Read-Only area. */
3264 offset = cpu_reg->spad_base +
3265 (fw->rodata_addr - cpu_reg->mips_view_base);
3266 if (fw->rodata) {
3267 int j;
3268
3269 for (j = 0; j < (fw->rodata_len / 4); j++, offset += 4) {
Michael Chan2726d6e2008-01-29 21:35:05 -08003270 bnx2_reg_wr_ind(bp, offset, fw->rodata[j]);
Michael Chanb6016b72005-05-26 13:03:09 -07003271 }
3272 }
3273
3274 /* Clear the pre-fetch instruction. */
Michael Chan2726d6e2008-01-29 21:35:05 -08003275 bnx2_reg_wr_ind(bp, cpu_reg->inst, 0);
3276 bnx2_reg_wr_ind(bp, cpu_reg->pc, fw->start_addr);
Michael Chanb6016b72005-05-26 13:03:09 -07003277
3278 /* Start the CPU. */
Michael Chan2726d6e2008-01-29 21:35:05 -08003279 val = bnx2_reg_rd_ind(bp, cpu_reg->mode);
Michael Chanb6016b72005-05-26 13:03:09 -07003280 val &= ~cpu_reg->mode_value_halt;
Michael Chan2726d6e2008-01-29 21:35:05 -08003281 bnx2_reg_wr_ind(bp, cpu_reg->state, cpu_reg->state_value_clear);
3282 bnx2_reg_wr_ind(bp, cpu_reg->mode, val);
Michael Chanaf3ee512006-11-19 14:09:25 -08003283
3284 return 0;
Michael Chanb6016b72005-05-26 13:03:09 -07003285}
3286
Michael Chanfba9fe92006-06-12 22:21:25 -07003287static int
Michael Chanb6016b72005-05-26 13:03:09 -07003288bnx2_init_cpus(struct bnx2 *bp)
3289{
3290 struct cpu_reg cpu_reg;
Michael Chanaf3ee512006-11-19 14:09:25 -08003291 struct fw_info *fw;
Michael Chan110d0ef2007-12-12 11:18:34 -08003292 int rc, rv2p_len;
3293 void *text, *rv2p;
Michael Chanb6016b72005-05-26 13:03:09 -07003294
3295 /* Initialize the RV2P processor. */
Denys Vlasenkob3448b02007-09-30 17:55:51 -07003296 text = vmalloc(FW_BUF_SIZE);
3297 if (!text)
3298 return -ENOMEM;
Michael Chan110d0ef2007-12-12 11:18:34 -08003299 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
3300 rv2p = bnx2_xi_rv2p_proc1;
3301 rv2p_len = sizeof(bnx2_xi_rv2p_proc1);
3302 } else {
3303 rv2p = bnx2_rv2p_proc1;
3304 rv2p_len = sizeof(bnx2_rv2p_proc1);
3305 }
3306 rc = zlib_inflate_blob(text, FW_BUF_SIZE, rv2p, rv2p_len);
Michael Chanea1f8d52007-10-02 16:27:35 -07003307 if (rc < 0)
Michael Chanfba9fe92006-06-12 22:21:25 -07003308 goto init_cpu_err;
Michael Chanea1f8d52007-10-02 16:27:35 -07003309
Denys Vlasenkob3448b02007-09-30 17:55:51 -07003310 load_rv2p_fw(bp, text, rc /* == len */, RV2P_PROC1);
Michael Chanfba9fe92006-06-12 22:21:25 -07003311
Michael Chan110d0ef2007-12-12 11:18:34 -08003312 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
3313 rv2p = bnx2_xi_rv2p_proc2;
3314 rv2p_len = sizeof(bnx2_xi_rv2p_proc2);
3315 } else {
3316 rv2p = bnx2_rv2p_proc2;
3317 rv2p_len = sizeof(bnx2_rv2p_proc2);
3318 }
3319 rc = zlib_inflate_blob(text, FW_BUF_SIZE, rv2p, rv2p_len);
Michael Chanea1f8d52007-10-02 16:27:35 -07003320 if (rc < 0)
Michael Chanfba9fe92006-06-12 22:21:25 -07003321 goto init_cpu_err;
Michael Chanea1f8d52007-10-02 16:27:35 -07003322
Denys Vlasenkob3448b02007-09-30 17:55:51 -07003323 load_rv2p_fw(bp, text, rc /* == len */, RV2P_PROC2);
Michael Chanb6016b72005-05-26 13:03:09 -07003324
3325 /* Initialize the RX Processor. */
3326 cpu_reg.mode = BNX2_RXP_CPU_MODE;
3327 cpu_reg.mode_value_halt = BNX2_RXP_CPU_MODE_SOFT_HALT;
3328 cpu_reg.mode_value_sstep = BNX2_RXP_CPU_MODE_STEP_ENA;
3329 cpu_reg.state = BNX2_RXP_CPU_STATE;
3330 cpu_reg.state_value_clear = 0xffffff;
3331 cpu_reg.gpr0 = BNX2_RXP_CPU_REG_FILE;
3332 cpu_reg.evmask = BNX2_RXP_CPU_EVENT_MASK;
3333 cpu_reg.pc = BNX2_RXP_CPU_PROGRAM_COUNTER;
3334 cpu_reg.inst = BNX2_RXP_CPU_INSTRUCTION;
3335 cpu_reg.bp = BNX2_RXP_CPU_HW_BREAKPOINT;
3336 cpu_reg.spad_base = BNX2_RXP_SCRATCH;
3337 cpu_reg.mips_view_base = 0x8000000;
Jeff Garzik6aa20a22006-09-13 13:24:59 -04003338
Michael Chand43584c2006-11-19 14:14:35 -08003339 if (CHIP_NUM(bp) == CHIP_NUM_5709)
3340 fw = &bnx2_rxp_fw_09;
3341 else
3342 fw = &bnx2_rxp_fw_06;
Michael Chanb6016b72005-05-26 13:03:09 -07003343
Michael Chanea1f8d52007-10-02 16:27:35 -07003344 fw->text = text;
Michael Chanaf3ee512006-11-19 14:09:25 -08003345 rc = load_cpu_fw(bp, &cpu_reg, fw);
Michael Chanfba9fe92006-06-12 22:21:25 -07003346 if (rc)
3347 goto init_cpu_err;
3348
Michael Chanb6016b72005-05-26 13:03:09 -07003349 /* Initialize the TX Processor. */
3350 cpu_reg.mode = BNX2_TXP_CPU_MODE;
3351 cpu_reg.mode_value_halt = BNX2_TXP_CPU_MODE_SOFT_HALT;
3352 cpu_reg.mode_value_sstep = BNX2_TXP_CPU_MODE_STEP_ENA;
3353 cpu_reg.state = BNX2_TXP_CPU_STATE;
3354 cpu_reg.state_value_clear = 0xffffff;
3355 cpu_reg.gpr0 = BNX2_TXP_CPU_REG_FILE;
3356 cpu_reg.evmask = BNX2_TXP_CPU_EVENT_MASK;
3357 cpu_reg.pc = BNX2_TXP_CPU_PROGRAM_COUNTER;
3358 cpu_reg.inst = BNX2_TXP_CPU_INSTRUCTION;
3359 cpu_reg.bp = BNX2_TXP_CPU_HW_BREAKPOINT;
3360 cpu_reg.spad_base = BNX2_TXP_SCRATCH;
3361 cpu_reg.mips_view_base = 0x8000000;
Jeff Garzik6aa20a22006-09-13 13:24:59 -04003362
Michael Chand43584c2006-11-19 14:14:35 -08003363 if (CHIP_NUM(bp) == CHIP_NUM_5709)
3364 fw = &bnx2_txp_fw_09;
3365 else
3366 fw = &bnx2_txp_fw_06;
Michael Chanb6016b72005-05-26 13:03:09 -07003367
Michael Chanea1f8d52007-10-02 16:27:35 -07003368 fw->text = text;
Michael Chanaf3ee512006-11-19 14:09:25 -08003369 rc = load_cpu_fw(bp, &cpu_reg, fw);
Michael Chanfba9fe92006-06-12 22:21:25 -07003370 if (rc)
3371 goto init_cpu_err;
3372
Michael Chanb6016b72005-05-26 13:03:09 -07003373 /* Initialize the TX Patch-up Processor. */
3374 cpu_reg.mode = BNX2_TPAT_CPU_MODE;
3375 cpu_reg.mode_value_halt = BNX2_TPAT_CPU_MODE_SOFT_HALT;
3376 cpu_reg.mode_value_sstep = BNX2_TPAT_CPU_MODE_STEP_ENA;
3377 cpu_reg.state = BNX2_TPAT_CPU_STATE;
3378 cpu_reg.state_value_clear = 0xffffff;
3379 cpu_reg.gpr0 = BNX2_TPAT_CPU_REG_FILE;
3380 cpu_reg.evmask = BNX2_TPAT_CPU_EVENT_MASK;
3381 cpu_reg.pc = BNX2_TPAT_CPU_PROGRAM_COUNTER;
3382 cpu_reg.inst = BNX2_TPAT_CPU_INSTRUCTION;
3383 cpu_reg.bp = BNX2_TPAT_CPU_HW_BREAKPOINT;
3384 cpu_reg.spad_base = BNX2_TPAT_SCRATCH;
3385 cpu_reg.mips_view_base = 0x8000000;
Jeff Garzik6aa20a22006-09-13 13:24:59 -04003386
Michael Chand43584c2006-11-19 14:14:35 -08003387 if (CHIP_NUM(bp) == CHIP_NUM_5709)
3388 fw = &bnx2_tpat_fw_09;
3389 else
3390 fw = &bnx2_tpat_fw_06;
Michael Chanb6016b72005-05-26 13:03:09 -07003391
Michael Chanea1f8d52007-10-02 16:27:35 -07003392 fw->text = text;
Michael Chanaf3ee512006-11-19 14:09:25 -08003393 rc = load_cpu_fw(bp, &cpu_reg, fw);
Michael Chanfba9fe92006-06-12 22:21:25 -07003394 if (rc)
3395 goto init_cpu_err;
3396
Michael Chanb6016b72005-05-26 13:03:09 -07003397 /* Initialize the Completion Processor. */
3398 cpu_reg.mode = BNX2_COM_CPU_MODE;
3399 cpu_reg.mode_value_halt = BNX2_COM_CPU_MODE_SOFT_HALT;
3400 cpu_reg.mode_value_sstep = BNX2_COM_CPU_MODE_STEP_ENA;
3401 cpu_reg.state = BNX2_COM_CPU_STATE;
3402 cpu_reg.state_value_clear = 0xffffff;
3403 cpu_reg.gpr0 = BNX2_COM_CPU_REG_FILE;
3404 cpu_reg.evmask = BNX2_COM_CPU_EVENT_MASK;
3405 cpu_reg.pc = BNX2_COM_CPU_PROGRAM_COUNTER;
3406 cpu_reg.inst = BNX2_COM_CPU_INSTRUCTION;
3407 cpu_reg.bp = BNX2_COM_CPU_HW_BREAKPOINT;
3408 cpu_reg.spad_base = BNX2_COM_SCRATCH;
3409 cpu_reg.mips_view_base = 0x8000000;
Jeff Garzik6aa20a22006-09-13 13:24:59 -04003410
Michael Chand43584c2006-11-19 14:14:35 -08003411 if (CHIP_NUM(bp) == CHIP_NUM_5709)
3412 fw = &bnx2_com_fw_09;
3413 else
3414 fw = &bnx2_com_fw_06;
Michael Chanb6016b72005-05-26 13:03:09 -07003415
Michael Chanea1f8d52007-10-02 16:27:35 -07003416 fw->text = text;
Michael Chanaf3ee512006-11-19 14:09:25 -08003417 rc = load_cpu_fw(bp, &cpu_reg, fw);
Michael Chanfba9fe92006-06-12 22:21:25 -07003418 if (rc)
3419 goto init_cpu_err;
3420
Michael Chand43584c2006-11-19 14:14:35 -08003421 /* Initialize the Command Processor. */
3422 cpu_reg.mode = BNX2_CP_CPU_MODE;
3423 cpu_reg.mode_value_halt = BNX2_CP_CPU_MODE_SOFT_HALT;
3424 cpu_reg.mode_value_sstep = BNX2_CP_CPU_MODE_STEP_ENA;
3425 cpu_reg.state = BNX2_CP_CPU_STATE;
3426 cpu_reg.state_value_clear = 0xffffff;
3427 cpu_reg.gpr0 = BNX2_CP_CPU_REG_FILE;
3428 cpu_reg.evmask = BNX2_CP_CPU_EVENT_MASK;
3429 cpu_reg.pc = BNX2_CP_CPU_PROGRAM_COUNTER;
3430 cpu_reg.inst = BNX2_CP_CPU_INSTRUCTION;
3431 cpu_reg.bp = BNX2_CP_CPU_HW_BREAKPOINT;
3432 cpu_reg.spad_base = BNX2_CP_SCRATCH;
3433 cpu_reg.mips_view_base = 0x8000000;
Michael Chanb6016b72005-05-26 13:03:09 -07003434
Michael Chan110d0ef2007-12-12 11:18:34 -08003435 if (CHIP_NUM(bp) == CHIP_NUM_5709)
Michael Chand43584c2006-11-19 14:14:35 -08003436 fw = &bnx2_cp_fw_09;
Michael Chan110d0ef2007-12-12 11:18:34 -08003437 else
3438 fw = &bnx2_cp_fw_06;
Michael Chanb6016b72005-05-26 13:03:09 -07003439
Michael Chan110d0ef2007-12-12 11:18:34 -08003440 fw->text = text;
3441 rc = load_cpu_fw(bp, &cpu_reg, fw);
3442
Michael Chanfba9fe92006-06-12 22:21:25 -07003443init_cpu_err:
Michael Chanea1f8d52007-10-02 16:27:35 -07003444 vfree(text);
Michael Chanfba9fe92006-06-12 22:21:25 -07003445 return rc;
Michael Chanb6016b72005-05-26 13:03:09 -07003446}
3447
3448static int
Pavel Machek829ca9a2005-09-03 15:56:56 -07003449bnx2_set_power_state(struct bnx2 *bp, pci_power_t state)
Michael Chanb6016b72005-05-26 13:03:09 -07003450{
3451 u16 pmcsr;
3452
3453 pci_read_config_word(bp->pdev, bp->pm_cap + PCI_PM_CTRL, &pmcsr);
3454
3455 switch (state) {
Pavel Machek829ca9a2005-09-03 15:56:56 -07003456 case PCI_D0: {
Michael Chanb6016b72005-05-26 13:03:09 -07003457 u32 val;
3458
3459 pci_write_config_word(bp->pdev, bp->pm_cap + PCI_PM_CTRL,
3460 (pmcsr & ~PCI_PM_CTRL_STATE_MASK) |
3461 PCI_PM_CTRL_PME_STATUS);
3462
3463 if (pmcsr & PCI_PM_CTRL_STATE_MASK)
3464 /* delay required during transition out of D3hot */
3465 msleep(20);
3466
3467 val = REG_RD(bp, BNX2_EMAC_MODE);
3468 val |= BNX2_EMAC_MODE_MPKT_RCVD | BNX2_EMAC_MODE_ACPI_RCVD;
3469 val &= ~BNX2_EMAC_MODE_MPKT;
3470 REG_WR(bp, BNX2_EMAC_MODE, val);
3471
3472 val = REG_RD(bp, BNX2_RPM_CONFIG);
3473 val &= ~BNX2_RPM_CONFIG_ACPI_ENA;
3474 REG_WR(bp, BNX2_RPM_CONFIG, val);
3475 break;
3476 }
Pavel Machek829ca9a2005-09-03 15:56:56 -07003477 case PCI_D3hot: {
Michael Chanb6016b72005-05-26 13:03:09 -07003478 int i;
3479 u32 val, wol_msg;
3480
3481 if (bp->wol) {
3482 u32 advertising;
3483 u8 autoneg;
3484
3485 autoneg = bp->autoneg;
3486 advertising = bp->advertising;
3487
Michael Chan239cd342007-10-17 19:26:15 -07003488 if (bp->phy_port == PORT_TP) {
3489 bp->autoneg = AUTONEG_SPEED;
3490 bp->advertising = ADVERTISED_10baseT_Half |
3491 ADVERTISED_10baseT_Full |
3492 ADVERTISED_100baseT_Half |
3493 ADVERTISED_100baseT_Full |
3494 ADVERTISED_Autoneg;
3495 }
Michael Chanb6016b72005-05-26 13:03:09 -07003496
Michael Chan239cd342007-10-17 19:26:15 -07003497 spin_lock_bh(&bp->phy_lock);
3498 bnx2_setup_phy(bp, bp->phy_port);
3499 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07003500
3501 bp->autoneg = autoneg;
3502 bp->advertising = advertising;
3503
3504 bnx2_set_mac_addr(bp);
3505
3506 val = REG_RD(bp, BNX2_EMAC_MODE);
3507
3508 /* Enable port mode. */
3509 val &= ~BNX2_EMAC_MODE_PORT;
Michael Chan239cd342007-10-17 19:26:15 -07003510 val |= BNX2_EMAC_MODE_MPKT_RCVD |
Michael Chanb6016b72005-05-26 13:03:09 -07003511 BNX2_EMAC_MODE_ACPI_RCVD |
Michael Chanb6016b72005-05-26 13:03:09 -07003512 BNX2_EMAC_MODE_MPKT;
Michael Chan239cd342007-10-17 19:26:15 -07003513 if (bp->phy_port == PORT_TP)
3514 val |= BNX2_EMAC_MODE_PORT_MII;
3515 else {
3516 val |= BNX2_EMAC_MODE_PORT_GMII;
3517 if (bp->line_speed == SPEED_2500)
3518 val |= BNX2_EMAC_MODE_25G_MODE;
3519 }
Michael Chanb6016b72005-05-26 13:03:09 -07003520
3521 REG_WR(bp, BNX2_EMAC_MODE, val);
3522
3523 /* receive all multicast */
3524 for (i = 0; i < NUM_MC_HASH_REGISTERS; i++) {
3525 REG_WR(bp, BNX2_EMAC_MULTICAST_HASH0 + (i * 4),
3526 0xffffffff);
3527 }
3528 REG_WR(bp, BNX2_EMAC_RX_MODE,
3529 BNX2_EMAC_RX_MODE_SORT_MODE);
3530
3531 val = 1 | BNX2_RPM_SORT_USER0_BC_EN |
3532 BNX2_RPM_SORT_USER0_MC_EN;
3533 REG_WR(bp, BNX2_RPM_SORT_USER0, 0x0);
3534 REG_WR(bp, BNX2_RPM_SORT_USER0, val);
3535 REG_WR(bp, BNX2_RPM_SORT_USER0, val |
3536 BNX2_RPM_SORT_USER0_ENA);
3537
3538 /* Need to enable EMAC and RPM for WOL. */
3539 REG_WR(bp, BNX2_MISC_ENABLE_SET_BITS,
3540 BNX2_MISC_ENABLE_SET_BITS_RX_PARSER_MAC_ENABLE |
3541 BNX2_MISC_ENABLE_SET_BITS_TX_HEADER_Q_ENABLE |
3542 BNX2_MISC_ENABLE_SET_BITS_EMAC_ENABLE);
3543
3544 val = REG_RD(bp, BNX2_RPM_CONFIG);
3545 val &= ~BNX2_RPM_CONFIG_ACPI_ENA;
3546 REG_WR(bp, BNX2_RPM_CONFIG, val);
3547
3548 wol_msg = BNX2_DRV_MSG_CODE_SUSPEND_WOL;
3549 }
3550 else {
3551 wol_msg = BNX2_DRV_MSG_CODE_SUSPEND_NO_WOL;
3552 }
3553
David S. Millerf86e82f2008-01-21 17:15:40 -08003554 if (!(bp->flags & BNX2_FLAG_NO_WOL))
Michael Chandda1e392006-01-23 16:08:14 -08003555 bnx2_fw_sync(bp, BNX2_DRV_MSG_DATA_WAIT3 | wol_msg, 0);
Michael Chanb6016b72005-05-26 13:03:09 -07003556
3557 pmcsr &= ~PCI_PM_CTRL_STATE_MASK;
3558 if ((CHIP_ID(bp) == CHIP_ID_5706_A0) ||
3559 (CHIP_ID(bp) == CHIP_ID_5706_A1)) {
3560
3561 if (bp->wol)
3562 pmcsr |= 3;
3563 }
3564 else {
3565 pmcsr |= 3;
3566 }
3567 if (bp->wol) {
3568 pmcsr |= PCI_PM_CTRL_PME_ENABLE;
3569 }
3570 pci_write_config_word(bp->pdev, bp->pm_cap + PCI_PM_CTRL,
3571 pmcsr);
3572
3573 /* No more memory access after this point until
3574 * device is brought back to D0.
3575 */
3576 udelay(50);
3577 break;
3578 }
3579 default:
3580 return -EINVAL;
3581 }
3582 return 0;
3583}
3584
3585static int
3586bnx2_acquire_nvram_lock(struct bnx2 *bp)
3587{
3588 u32 val;
3589 int j;
3590
3591 /* Request access to the flash interface. */
3592 REG_WR(bp, BNX2_NVM_SW_ARB, BNX2_NVM_SW_ARB_ARB_REQ_SET2);
3593 for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) {
3594 val = REG_RD(bp, BNX2_NVM_SW_ARB);
3595 if (val & BNX2_NVM_SW_ARB_ARB_ARB2)
3596 break;
3597
3598 udelay(5);
3599 }
3600
3601 if (j >= NVRAM_TIMEOUT_COUNT)
3602 return -EBUSY;
3603
3604 return 0;
3605}
3606
3607static int
3608bnx2_release_nvram_lock(struct bnx2 *bp)
3609{
3610 int j;
3611 u32 val;
3612
3613 /* Relinquish nvram interface. */
3614 REG_WR(bp, BNX2_NVM_SW_ARB, BNX2_NVM_SW_ARB_ARB_REQ_CLR2);
3615
3616 for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) {
3617 val = REG_RD(bp, BNX2_NVM_SW_ARB);
3618 if (!(val & BNX2_NVM_SW_ARB_ARB_ARB2))
3619 break;
3620
3621 udelay(5);
3622 }
3623
3624 if (j >= NVRAM_TIMEOUT_COUNT)
3625 return -EBUSY;
3626
3627 return 0;
3628}
3629
3630
3631static int
3632bnx2_enable_nvram_write(struct bnx2 *bp)
3633{
3634 u32 val;
3635
3636 val = REG_RD(bp, BNX2_MISC_CFG);
3637 REG_WR(bp, BNX2_MISC_CFG, val | BNX2_MISC_CFG_NVM_WR_EN_PCI);
3638
Michael Chane30372c2007-07-16 18:26:23 -07003639 if (bp->flash_info->flags & BNX2_NV_WREN) {
Michael Chanb6016b72005-05-26 13:03:09 -07003640 int j;
3641
3642 REG_WR(bp, BNX2_NVM_COMMAND, BNX2_NVM_COMMAND_DONE);
3643 REG_WR(bp, BNX2_NVM_COMMAND,
3644 BNX2_NVM_COMMAND_WREN | BNX2_NVM_COMMAND_DOIT);
3645
3646 for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) {
3647 udelay(5);
3648
3649 val = REG_RD(bp, BNX2_NVM_COMMAND);
3650 if (val & BNX2_NVM_COMMAND_DONE)
3651 break;
3652 }
3653
3654 if (j >= NVRAM_TIMEOUT_COUNT)
3655 return -EBUSY;
3656 }
3657 return 0;
3658}
3659
3660static void
3661bnx2_disable_nvram_write(struct bnx2 *bp)
3662{
3663 u32 val;
3664
3665 val = REG_RD(bp, BNX2_MISC_CFG);
3666 REG_WR(bp, BNX2_MISC_CFG, val & ~BNX2_MISC_CFG_NVM_WR_EN);
3667}
3668
3669
3670static void
3671bnx2_enable_nvram_access(struct bnx2 *bp)
3672{
3673 u32 val;
3674
3675 val = REG_RD(bp, BNX2_NVM_ACCESS_ENABLE);
3676 /* Enable both bits, even on read. */
Jeff Garzik6aa20a22006-09-13 13:24:59 -04003677 REG_WR(bp, BNX2_NVM_ACCESS_ENABLE,
Michael Chanb6016b72005-05-26 13:03:09 -07003678 val | BNX2_NVM_ACCESS_ENABLE_EN | BNX2_NVM_ACCESS_ENABLE_WR_EN);
3679}
3680
3681static void
3682bnx2_disable_nvram_access(struct bnx2 *bp)
3683{
3684 u32 val;
3685
3686 val = REG_RD(bp, BNX2_NVM_ACCESS_ENABLE);
3687 /* Disable both bits, even after read. */
Jeff Garzik6aa20a22006-09-13 13:24:59 -04003688 REG_WR(bp, BNX2_NVM_ACCESS_ENABLE,
Michael Chanb6016b72005-05-26 13:03:09 -07003689 val & ~(BNX2_NVM_ACCESS_ENABLE_EN |
3690 BNX2_NVM_ACCESS_ENABLE_WR_EN));
3691}
3692
3693static int
3694bnx2_nvram_erase_page(struct bnx2 *bp, u32 offset)
3695{
3696 u32 cmd;
3697 int j;
3698
Michael Chane30372c2007-07-16 18:26:23 -07003699 if (bp->flash_info->flags & BNX2_NV_BUFFERED)
Michael Chanb6016b72005-05-26 13:03:09 -07003700 /* Buffered flash, no erase needed */
3701 return 0;
3702
3703 /* Build an erase command */
3704 cmd = BNX2_NVM_COMMAND_ERASE | BNX2_NVM_COMMAND_WR |
3705 BNX2_NVM_COMMAND_DOIT;
3706
3707 /* Need to clear DONE bit separately. */
3708 REG_WR(bp, BNX2_NVM_COMMAND, BNX2_NVM_COMMAND_DONE);
3709
3710 /* Address of the NVRAM to read from. */
3711 REG_WR(bp, BNX2_NVM_ADDR, offset & BNX2_NVM_ADDR_NVM_ADDR_VALUE);
3712
3713 /* Issue an erase command. */
3714 REG_WR(bp, BNX2_NVM_COMMAND, cmd);
3715
3716 /* Wait for completion. */
3717 for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) {
3718 u32 val;
3719
3720 udelay(5);
3721
3722 val = REG_RD(bp, BNX2_NVM_COMMAND);
3723 if (val & BNX2_NVM_COMMAND_DONE)
3724 break;
3725 }
3726
3727 if (j >= NVRAM_TIMEOUT_COUNT)
3728 return -EBUSY;
3729
3730 return 0;
3731}
3732
3733static int
3734bnx2_nvram_read_dword(struct bnx2 *bp, u32 offset, u8 *ret_val, u32 cmd_flags)
3735{
3736 u32 cmd;
3737 int j;
3738
3739 /* Build the command word. */
3740 cmd = BNX2_NVM_COMMAND_DOIT | cmd_flags;
3741
Michael Chane30372c2007-07-16 18:26:23 -07003742 /* Calculate an offset of a buffered flash, not needed for 5709. */
3743 if (bp->flash_info->flags & BNX2_NV_TRANSLATE) {
Michael Chanb6016b72005-05-26 13:03:09 -07003744 offset = ((offset / bp->flash_info->page_size) <<
3745 bp->flash_info->page_bits) +
3746 (offset % bp->flash_info->page_size);
3747 }
3748
3749 /* Need to clear DONE bit separately. */
3750 REG_WR(bp, BNX2_NVM_COMMAND, BNX2_NVM_COMMAND_DONE);
3751
3752 /* Address of the NVRAM to read from. */
3753 REG_WR(bp, BNX2_NVM_ADDR, offset & BNX2_NVM_ADDR_NVM_ADDR_VALUE);
3754
3755 /* Issue a read command. */
3756 REG_WR(bp, BNX2_NVM_COMMAND, cmd);
3757
3758 /* Wait for completion. */
3759 for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) {
3760 u32 val;
3761
3762 udelay(5);
3763
3764 val = REG_RD(bp, BNX2_NVM_COMMAND);
3765 if (val & BNX2_NVM_COMMAND_DONE) {
Al Virob491edd2007-12-22 19:44:51 +00003766 __be32 v = cpu_to_be32(REG_RD(bp, BNX2_NVM_READ));
3767 memcpy(ret_val, &v, 4);
Michael Chanb6016b72005-05-26 13:03:09 -07003768 break;
3769 }
3770 }
3771 if (j >= NVRAM_TIMEOUT_COUNT)
3772 return -EBUSY;
3773
3774 return 0;
3775}
3776
3777
3778static int
3779bnx2_nvram_write_dword(struct bnx2 *bp, u32 offset, u8 *val, u32 cmd_flags)
3780{
Al Virob491edd2007-12-22 19:44:51 +00003781 u32 cmd;
3782 __be32 val32;
Michael Chanb6016b72005-05-26 13:03:09 -07003783 int j;
3784
3785 /* Build the command word. */
3786 cmd = BNX2_NVM_COMMAND_DOIT | BNX2_NVM_COMMAND_WR | cmd_flags;
3787
Michael Chane30372c2007-07-16 18:26:23 -07003788 /* Calculate an offset of a buffered flash, not needed for 5709. */
3789 if (bp->flash_info->flags & BNX2_NV_TRANSLATE) {
Michael Chanb6016b72005-05-26 13:03:09 -07003790 offset = ((offset / bp->flash_info->page_size) <<
3791 bp->flash_info->page_bits) +
3792 (offset % bp->flash_info->page_size);
3793 }
3794
3795 /* Need to clear DONE bit separately. */
3796 REG_WR(bp, BNX2_NVM_COMMAND, BNX2_NVM_COMMAND_DONE);
3797
3798 memcpy(&val32, val, 4);
Michael Chanb6016b72005-05-26 13:03:09 -07003799
3800 /* Write the data. */
Al Virob491edd2007-12-22 19:44:51 +00003801 REG_WR(bp, BNX2_NVM_WRITE, be32_to_cpu(val32));
Michael Chanb6016b72005-05-26 13:03:09 -07003802
3803 /* Address of the NVRAM to write to. */
3804 REG_WR(bp, BNX2_NVM_ADDR, offset & BNX2_NVM_ADDR_NVM_ADDR_VALUE);
3805
3806 /* Issue the write command. */
3807 REG_WR(bp, BNX2_NVM_COMMAND, cmd);
3808
3809 /* Wait for completion. */
3810 for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) {
3811 udelay(5);
3812
3813 if (REG_RD(bp, BNX2_NVM_COMMAND) & BNX2_NVM_COMMAND_DONE)
3814 break;
3815 }
3816 if (j >= NVRAM_TIMEOUT_COUNT)
3817 return -EBUSY;
3818
3819 return 0;
3820}
3821
3822static int
3823bnx2_init_nvram(struct bnx2 *bp)
3824{
3825 u32 val;
Michael Chane30372c2007-07-16 18:26:23 -07003826 int j, entry_count, rc = 0;
Michael Chanb6016b72005-05-26 13:03:09 -07003827 struct flash_spec *flash;
3828
Michael Chane30372c2007-07-16 18:26:23 -07003829 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
3830 bp->flash_info = &flash_5709;
3831 goto get_flash_size;
3832 }
3833
Michael Chanb6016b72005-05-26 13:03:09 -07003834 /* Determine the selected interface. */
3835 val = REG_RD(bp, BNX2_NVM_CFG1);
3836
Denis Chengff8ac602007-09-02 18:30:18 +08003837 entry_count = ARRAY_SIZE(flash_table);
Michael Chanb6016b72005-05-26 13:03:09 -07003838
Michael Chanb6016b72005-05-26 13:03:09 -07003839 if (val & 0x40000000) {
3840
3841 /* Flash interface has been reconfigured */
3842 for (j = 0, flash = &flash_table[0]; j < entry_count;
Michael Chan37137702005-11-04 08:49:17 -08003843 j++, flash++) {
3844 if ((val & FLASH_BACKUP_STRAP_MASK) ==
3845 (flash->config1 & FLASH_BACKUP_STRAP_MASK)) {
Michael Chanb6016b72005-05-26 13:03:09 -07003846 bp->flash_info = flash;
3847 break;
3848 }
3849 }
3850 }
3851 else {
Michael Chan37137702005-11-04 08:49:17 -08003852 u32 mask;
Michael Chanb6016b72005-05-26 13:03:09 -07003853 /* Not yet been reconfigured */
3854
Michael Chan37137702005-11-04 08:49:17 -08003855 if (val & (1 << 23))
3856 mask = FLASH_BACKUP_STRAP_MASK;
3857 else
3858 mask = FLASH_STRAP_MASK;
3859
Michael Chanb6016b72005-05-26 13:03:09 -07003860 for (j = 0, flash = &flash_table[0]; j < entry_count;
3861 j++, flash++) {
3862
Michael Chan37137702005-11-04 08:49:17 -08003863 if ((val & mask) == (flash->strapping & mask)) {
Michael Chanb6016b72005-05-26 13:03:09 -07003864 bp->flash_info = flash;
3865
3866 /* Request access to the flash interface. */
3867 if ((rc = bnx2_acquire_nvram_lock(bp)) != 0)
3868 return rc;
3869
3870 /* Enable access to flash interface */
3871 bnx2_enable_nvram_access(bp);
3872
3873 /* Reconfigure the flash interface */
3874 REG_WR(bp, BNX2_NVM_CFG1, flash->config1);
3875 REG_WR(bp, BNX2_NVM_CFG2, flash->config2);
3876 REG_WR(bp, BNX2_NVM_CFG3, flash->config3);
3877 REG_WR(bp, BNX2_NVM_WRITE1, flash->write1);
3878
3879 /* Disable access to flash interface */
3880 bnx2_disable_nvram_access(bp);
3881 bnx2_release_nvram_lock(bp);
3882
3883 break;
3884 }
3885 }
3886 } /* if (val & 0x40000000) */
3887
3888 if (j == entry_count) {
3889 bp->flash_info = NULL;
John W. Linville2f23c522005-11-10 12:57:33 -08003890 printk(KERN_ALERT PFX "Unknown flash/EEPROM type.\n");
Michael Chan1122db72006-01-23 16:11:42 -08003891 return -ENODEV;
Michael Chanb6016b72005-05-26 13:03:09 -07003892 }
3893
Michael Chane30372c2007-07-16 18:26:23 -07003894get_flash_size:
Michael Chan2726d6e2008-01-29 21:35:05 -08003895 val = bnx2_shmem_rd(bp, BNX2_SHARED_HW_CFG_CONFIG2);
Michael Chan1122db72006-01-23 16:11:42 -08003896 val &= BNX2_SHARED_HW_CFG2_NVM_SIZE_MASK;
3897 if (val)
3898 bp->flash_size = val;
3899 else
3900 bp->flash_size = bp->flash_info->total_size;
3901
Michael Chanb6016b72005-05-26 13:03:09 -07003902 return rc;
3903}
3904
3905static int
3906bnx2_nvram_read(struct bnx2 *bp, u32 offset, u8 *ret_buf,
3907 int buf_size)
3908{
3909 int rc = 0;
3910 u32 cmd_flags, offset32, len32, extra;
3911
3912 if (buf_size == 0)
3913 return 0;
3914
3915 /* Request access to the flash interface. */
3916 if ((rc = bnx2_acquire_nvram_lock(bp)) != 0)
3917 return rc;
3918
3919 /* Enable access to flash interface */
3920 bnx2_enable_nvram_access(bp);
3921
3922 len32 = buf_size;
3923 offset32 = offset;
3924 extra = 0;
3925
3926 cmd_flags = 0;
3927
3928 if (offset32 & 3) {
3929 u8 buf[4];
3930 u32 pre_len;
3931
3932 offset32 &= ~3;
3933 pre_len = 4 - (offset & 3);
3934
3935 if (pre_len >= len32) {
3936 pre_len = len32;
3937 cmd_flags = BNX2_NVM_COMMAND_FIRST |
3938 BNX2_NVM_COMMAND_LAST;
3939 }
3940 else {
3941 cmd_flags = BNX2_NVM_COMMAND_FIRST;
3942 }
3943
3944 rc = bnx2_nvram_read_dword(bp, offset32, buf, cmd_flags);
3945
3946 if (rc)
3947 return rc;
3948
3949 memcpy(ret_buf, buf + (offset & 3), pre_len);
3950
3951 offset32 += 4;
3952 ret_buf += pre_len;
3953 len32 -= pre_len;
3954 }
3955 if (len32 & 3) {
3956 extra = 4 - (len32 & 3);
3957 len32 = (len32 + 4) & ~3;
3958 }
3959
3960 if (len32 == 4) {
3961 u8 buf[4];
3962
3963 if (cmd_flags)
3964 cmd_flags = BNX2_NVM_COMMAND_LAST;
3965 else
3966 cmd_flags = BNX2_NVM_COMMAND_FIRST |
3967 BNX2_NVM_COMMAND_LAST;
3968
3969 rc = bnx2_nvram_read_dword(bp, offset32, buf, cmd_flags);
3970
3971 memcpy(ret_buf, buf, 4 - extra);
3972 }
3973 else if (len32 > 0) {
3974 u8 buf[4];
3975
3976 /* Read the first word. */
3977 if (cmd_flags)
3978 cmd_flags = 0;
3979 else
3980 cmd_flags = BNX2_NVM_COMMAND_FIRST;
3981
3982 rc = bnx2_nvram_read_dword(bp, offset32, ret_buf, cmd_flags);
3983
3984 /* Advance to the next dword. */
3985 offset32 += 4;
3986 ret_buf += 4;
3987 len32 -= 4;
3988
3989 while (len32 > 4 && rc == 0) {
3990 rc = bnx2_nvram_read_dword(bp, offset32, ret_buf, 0);
3991
3992 /* Advance to the next dword. */
3993 offset32 += 4;
3994 ret_buf += 4;
3995 len32 -= 4;
3996 }
3997
3998 if (rc)
3999 return rc;
4000
4001 cmd_flags = BNX2_NVM_COMMAND_LAST;
4002 rc = bnx2_nvram_read_dword(bp, offset32, buf, cmd_flags);
4003
4004 memcpy(ret_buf, buf, 4 - extra);
4005 }
4006
4007 /* Disable access to flash interface */
4008 bnx2_disable_nvram_access(bp);
4009
4010 bnx2_release_nvram_lock(bp);
4011
4012 return rc;
4013}
4014
4015static int
4016bnx2_nvram_write(struct bnx2 *bp, u32 offset, u8 *data_buf,
4017 int buf_size)
4018{
4019 u32 written, offset32, len32;
Michael Chane6be7632007-01-08 19:56:13 -08004020 u8 *buf, start[4], end[4], *align_buf = NULL, *flash_buffer = NULL;
Michael Chanb6016b72005-05-26 13:03:09 -07004021 int rc = 0;
4022 int align_start, align_end;
4023
4024 buf = data_buf;
4025 offset32 = offset;
4026 len32 = buf_size;
4027 align_start = align_end = 0;
4028
4029 if ((align_start = (offset32 & 3))) {
4030 offset32 &= ~3;
Michael Chanc8738792007-03-30 14:53:06 -07004031 len32 += align_start;
4032 if (len32 < 4)
4033 len32 = 4;
Michael Chanb6016b72005-05-26 13:03:09 -07004034 if ((rc = bnx2_nvram_read(bp, offset32, start, 4)))
4035 return rc;
4036 }
4037
4038 if (len32 & 3) {
Michael Chanc8738792007-03-30 14:53:06 -07004039 align_end = 4 - (len32 & 3);
4040 len32 += align_end;
4041 if ((rc = bnx2_nvram_read(bp, offset32 + len32 - 4, end, 4)))
4042 return rc;
Michael Chanb6016b72005-05-26 13:03:09 -07004043 }
4044
4045 if (align_start || align_end) {
Michael Chane6be7632007-01-08 19:56:13 -08004046 align_buf = kmalloc(len32, GFP_KERNEL);
4047 if (align_buf == NULL)
Michael Chanb6016b72005-05-26 13:03:09 -07004048 return -ENOMEM;
4049 if (align_start) {
Michael Chane6be7632007-01-08 19:56:13 -08004050 memcpy(align_buf, start, 4);
Michael Chanb6016b72005-05-26 13:03:09 -07004051 }
4052 if (align_end) {
Michael Chane6be7632007-01-08 19:56:13 -08004053 memcpy(align_buf + len32 - 4, end, 4);
Michael Chanb6016b72005-05-26 13:03:09 -07004054 }
Michael Chane6be7632007-01-08 19:56:13 -08004055 memcpy(align_buf + align_start, data_buf, buf_size);
4056 buf = align_buf;
Michael Chanb6016b72005-05-26 13:03:09 -07004057 }
4058
Michael Chane30372c2007-07-16 18:26:23 -07004059 if (!(bp->flash_info->flags & BNX2_NV_BUFFERED)) {
Michael Chanae181bc2006-05-22 16:39:20 -07004060 flash_buffer = kmalloc(264, GFP_KERNEL);
4061 if (flash_buffer == NULL) {
4062 rc = -ENOMEM;
4063 goto nvram_write_end;
4064 }
4065 }
4066
Michael Chanb6016b72005-05-26 13:03:09 -07004067 written = 0;
4068 while ((written < len32) && (rc == 0)) {
4069 u32 page_start, page_end, data_start, data_end;
4070 u32 addr, cmd_flags;
4071 int i;
Michael Chanb6016b72005-05-26 13:03:09 -07004072
4073 /* Find the page_start addr */
4074 page_start = offset32 + written;
4075 page_start -= (page_start % bp->flash_info->page_size);
4076 /* Find the page_end addr */
4077 page_end = page_start + bp->flash_info->page_size;
4078 /* Find the data_start addr */
4079 data_start = (written == 0) ? offset32 : page_start;
4080 /* Find the data_end addr */
Jeff Garzik6aa20a22006-09-13 13:24:59 -04004081 data_end = (page_end > offset32 + len32) ?
Michael Chanb6016b72005-05-26 13:03:09 -07004082 (offset32 + len32) : page_end;
4083
4084 /* Request access to the flash interface. */
4085 if ((rc = bnx2_acquire_nvram_lock(bp)) != 0)
4086 goto nvram_write_end;
4087
4088 /* Enable access to flash interface */
4089 bnx2_enable_nvram_access(bp);
4090
4091 cmd_flags = BNX2_NVM_COMMAND_FIRST;
Michael Chane30372c2007-07-16 18:26:23 -07004092 if (!(bp->flash_info->flags & BNX2_NV_BUFFERED)) {
Michael Chanb6016b72005-05-26 13:03:09 -07004093 int j;
4094
4095 /* Read the whole page into the buffer
4096 * (non-buffer flash only) */
4097 for (j = 0; j < bp->flash_info->page_size; j += 4) {
4098 if (j == (bp->flash_info->page_size - 4)) {
4099 cmd_flags |= BNX2_NVM_COMMAND_LAST;
4100 }
4101 rc = bnx2_nvram_read_dword(bp,
Jeff Garzik6aa20a22006-09-13 13:24:59 -04004102 page_start + j,
4103 &flash_buffer[j],
Michael Chanb6016b72005-05-26 13:03:09 -07004104 cmd_flags);
4105
4106 if (rc)
4107 goto nvram_write_end;
4108
4109 cmd_flags = 0;
4110 }
4111 }
4112
4113 /* Enable writes to flash interface (unlock write-protect) */
4114 if ((rc = bnx2_enable_nvram_write(bp)) != 0)
4115 goto nvram_write_end;
4116
Michael Chanb6016b72005-05-26 13:03:09 -07004117 /* Loop to write back the buffer data from page_start to
4118 * data_start */
4119 i = 0;
Michael Chane30372c2007-07-16 18:26:23 -07004120 if (!(bp->flash_info->flags & BNX2_NV_BUFFERED)) {
Michael Chanc8738792007-03-30 14:53:06 -07004121 /* Erase the page */
4122 if ((rc = bnx2_nvram_erase_page(bp, page_start)) != 0)
4123 goto nvram_write_end;
4124
4125 /* Re-enable the write again for the actual write */
4126 bnx2_enable_nvram_write(bp);
4127
Michael Chanb6016b72005-05-26 13:03:09 -07004128 for (addr = page_start; addr < data_start;
4129 addr += 4, i += 4) {
Jeff Garzik6aa20a22006-09-13 13:24:59 -04004130
Michael Chanb6016b72005-05-26 13:03:09 -07004131 rc = bnx2_nvram_write_dword(bp, addr,
4132 &flash_buffer[i], cmd_flags);
4133
4134 if (rc != 0)
4135 goto nvram_write_end;
4136
4137 cmd_flags = 0;
4138 }
4139 }
4140
4141 /* Loop to write the new data from data_start to data_end */
Michael Chanbae25762006-05-22 16:38:38 -07004142 for (addr = data_start; addr < data_end; addr += 4, i += 4) {
Michael Chanb6016b72005-05-26 13:03:09 -07004143 if ((addr == page_end - 4) ||
Michael Chane30372c2007-07-16 18:26:23 -07004144 ((bp->flash_info->flags & BNX2_NV_BUFFERED) &&
Michael Chanb6016b72005-05-26 13:03:09 -07004145 (addr == data_end - 4))) {
4146
4147 cmd_flags |= BNX2_NVM_COMMAND_LAST;
4148 }
4149 rc = bnx2_nvram_write_dword(bp, addr, buf,
4150 cmd_flags);
4151
4152 if (rc != 0)
4153 goto nvram_write_end;
4154
4155 cmd_flags = 0;
4156 buf += 4;
4157 }
4158
4159 /* Loop to write back the buffer data from data_end
4160 * to page_end */
Michael Chane30372c2007-07-16 18:26:23 -07004161 if (!(bp->flash_info->flags & BNX2_NV_BUFFERED)) {
Michael Chanb6016b72005-05-26 13:03:09 -07004162 for (addr = data_end; addr < page_end;
4163 addr += 4, i += 4) {
Jeff Garzik6aa20a22006-09-13 13:24:59 -04004164
Michael Chanb6016b72005-05-26 13:03:09 -07004165 if (addr == page_end-4) {
4166 cmd_flags = BNX2_NVM_COMMAND_LAST;
4167 }
4168 rc = bnx2_nvram_write_dword(bp, addr,
4169 &flash_buffer[i], cmd_flags);
4170
4171 if (rc != 0)
4172 goto nvram_write_end;
4173
4174 cmd_flags = 0;
4175 }
4176 }
4177
4178 /* Disable writes to flash interface (lock write-protect) */
4179 bnx2_disable_nvram_write(bp);
4180
4181 /* Disable access to flash interface */
4182 bnx2_disable_nvram_access(bp);
4183 bnx2_release_nvram_lock(bp);
4184
4185 /* Increment written */
4186 written += data_end - data_start;
4187 }
4188
4189nvram_write_end:
Michael Chane6be7632007-01-08 19:56:13 -08004190 kfree(flash_buffer);
4191 kfree(align_buf);
Michael Chanb6016b72005-05-26 13:03:09 -07004192 return rc;
4193}
4194
Michael Chan0d8a6572007-07-07 22:49:43 -07004195static void
4196bnx2_init_remote_phy(struct bnx2 *bp)
4197{
4198 u32 val;
4199
Michael Chan583c28e2008-01-21 19:51:35 -08004200 bp->phy_flags &= ~BNX2_PHY_FLAG_REMOTE_PHY_CAP;
4201 if (!(bp->phy_flags & BNX2_PHY_FLAG_SERDES))
Michael Chan0d8a6572007-07-07 22:49:43 -07004202 return;
4203
Michael Chan2726d6e2008-01-29 21:35:05 -08004204 val = bnx2_shmem_rd(bp, BNX2_FW_CAP_MB);
Michael Chan0d8a6572007-07-07 22:49:43 -07004205 if ((val & BNX2_FW_CAP_SIGNATURE_MASK) != BNX2_FW_CAP_SIGNATURE)
4206 return;
4207
4208 if (val & BNX2_FW_CAP_REMOTE_PHY_CAPABLE) {
Michael Chan583c28e2008-01-21 19:51:35 -08004209 bp->phy_flags |= BNX2_PHY_FLAG_REMOTE_PHY_CAP;
Michael Chan0d8a6572007-07-07 22:49:43 -07004210
Michael Chan2726d6e2008-01-29 21:35:05 -08004211 val = bnx2_shmem_rd(bp, BNX2_LINK_STATUS);
Michael Chan0d8a6572007-07-07 22:49:43 -07004212 if (val & BNX2_LINK_STATUS_SERDES_LINK)
4213 bp->phy_port = PORT_FIBRE;
4214 else
4215 bp->phy_port = PORT_TP;
Michael Chan489310a2007-10-10 16:16:31 -07004216
4217 if (netif_running(bp->dev)) {
4218 u32 sig;
4219
4220 if (val & BNX2_LINK_STATUS_LINK_UP) {
4221 bp->link_up = 1;
4222 netif_carrier_on(bp->dev);
4223 } else {
4224 bp->link_up = 0;
4225 netif_carrier_off(bp->dev);
4226 }
4227 sig = BNX2_DRV_ACK_CAP_SIGNATURE |
4228 BNX2_FW_CAP_REMOTE_PHY_CAPABLE;
Michael Chan2726d6e2008-01-29 21:35:05 -08004229 bnx2_shmem_wr(bp, BNX2_DRV_ACK_CAP_MB, sig);
Michael Chan489310a2007-10-10 16:16:31 -07004230 }
Michael Chan0d8a6572007-07-07 22:49:43 -07004231 }
4232}
4233
Michael Chanb4b36042007-12-20 19:59:30 -08004234static void
4235bnx2_setup_msix_tbl(struct bnx2 *bp)
4236{
4237 REG_WR(bp, BNX2_PCI_GRC_WINDOW_ADDR, BNX2_PCI_GRC_WINDOW_ADDR_SEP_WIN);
4238
4239 REG_WR(bp, BNX2_PCI_GRC_WINDOW2_ADDR, BNX2_MSIX_TABLE_ADDR);
4240 REG_WR(bp, BNX2_PCI_GRC_WINDOW3_ADDR, BNX2_MSIX_PBA_ADDR);
4241}
4242
Michael Chanb6016b72005-05-26 13:03:09 -07004243static int
4244bnx2_reset_chip(struct bnx2 *bp, u32 reset_code)
4245{
4246 u32 val;
4247 int i, rc = 0;
Michael Chan489310a2007-10-10 16:16:31 -07004248 u8 old_port;
Michael Chanb6016b72005-05-26 13:03:09 -07004249
4250 /* Wait for the current PCI transaction to complete before
4251 * issuing a reset. */
4252 REG_WR(bp, BNX2_MISC_ENABLE_CLR_BITS,
4253 BNX2_MISC_ENABLE_CLR_BITS_TX_DMA_ENABLE |
4254 BNX2_MISC_ENABLE_CLR_BITS_DMA_ENGINE_ENABLE |
4255 BNX2_MISC_ENABLE_CLR_BITS_RX_DMA_ENABLE |
4256 BNX2_MISC_ENABLE_CLR_BITS_HOST_COALESCE_ENABLE);
4257 val = REG_RD(bp, BNX2_MISC_ENABLE_CLR_BITS);
4258 udelay(5);
4259
Michael Chanb090ae22006-01-23 16:07:10 -08004260 /* Wait for the firmware to tell us it is ok to issue a reset. */
4261 bnx2_fw_sync(bp, BNX2_DRV_MSG_DATA_WAIT0 | reset_code, 1);
4262
Michael Chanb6016b72005-05-26 13:03:09 -07004263 /* Deposit a driver reset signature so the firmware knows that
4264 * this is a soft reset. */
Michael Chan2726d6e2008-01-29 21:35:05 -08004265 bnx2_shmem_wr(bp, BNX2_DRV_RESET_SIGNATURE,
4266 BNX2_DRV_RESET_SIGNATURE_MAGIC);
Michael Chanb6016b72005-05-26 13:03:09 -07004267
Michael Chanb6016b72005-05-26 13:03:09 -07004268 /* Do a dummy read to force the chip to complete all current transaction
4269 * before we issue a reset. */
4270 val = REG_RD(bp, BNX2_MISC_ID);
4271
Michael Chan234754d2006-11-19 14:11:41 -08004272 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
4273 REG_WR(bp, BNX2_MISC_COMMAND, BNX2_MISC_COMMAND_SW_RESET);
4274 REG_RD(bp, BNX2_MISC_COMMAND);
4275 udelay(5);
Michael Chanb6016b72005-05-26 13:03:09 -07004276
Michael Chan234754d2006-11-19 14:11:41 -08004277 val = BNX2_PCICFG_MISC_CONFIG_REG_WINDOW_ENA |
4278 BNX2_PCICFG_MISC_CONFIG_TARGET_MB_WORD_SWAP;
Michael Chanb6016b72005-05-26 13:03:09 -07004279
Michael Chan234754d2006-11-19 14:11:41 -08004280 pci_write_config_dword(bp->pdev, BNX2_PCICFG_MISC_CONFIG, val);
Michael Chanb6016b72005-05-26 13:03:09 -07004281
Michael Chan234754d2006-11-19 14:11:41 -08004282 } else {
4283 val = BNX2_PCICFG_MISC_CONFIG_CORE_RST_REQ |
4284 BNX2_PCICFG_MISC_CONFIG_REG_WINDOW_ENA |
4285 BNX2_PCICFG_MISC_CONFIG_TARGET_MB_WORD_SWAP;
4286
4287 /* Chip reset. */
4288 REG_WR(bp, BNX2_PCICFG_MISC_CONFIG, val);
4289
Michael Chan594a9df2007-08-28 15:39:42 -07004290 /* Reading back any register after chip reset will hang the
4291 * bus on 5706 A0 and A1. The msleep below provides plenty
4292 * of margin for write posting.
4293 */
Michael Chan234754d2006-11-19 14:11:41 -08004294 if ((CHIP_ID(bp) == CHIP_ID_5706_A0) ||
Arjan van de Ven8e545882007-08-28 14:34:43 -07004295 (CHIP_ID(bp) == CHIP_ID_5706_A1))
4296 msleep(20);
Michael Chanb6016b72005-05-26 13:03:09 -07004297
Michael Chan234754d2006-11-19 14:11:41 -08004298 /* Reset takes approximate 30 usec */
4299 for (i = 0; i < 10; i++) {
4300 val = REG_RD(bp, BNX2_PCICFG_MISC_CONFIG);
4301 if ((val & (BNX2_PCICFG_MISC_CONFIG_CORE_RST_REQ |
4302 BNX2_PCICFG_MISC_CONFIG_CORE_RST_BSY)) == 0)
4303 break;
4304 udelay(10);
4305 }
4306
4307 if (val & (BNX2_PCICFG_MISC_CONFIG_CORE_RST_REQ |
4308 BNX2_PCICFG_MISC_CONFIG_CORE_RST_BSY)) {
4309 printk(KERN_ERR PFX "Chip reset did not complete\n");
4310 return -EBUSY;
4311 }
Michael Chanb6016b72005-05-26 13:03:09 -07004312 }
4313
4314 /* Make sure byte swapping is properly configured. */
4315 val = REG_RD(bp, BNX2_PCI_SWAP_DIAG0);
4316 if (val != 0x01020304) {
4317 printk(KERN_ERR PFX "Chip not in correct endian mode\n");
4318 return -ENODEV;
4319 }
4320
Michael Chanb6016b72005-05-26 13:03:09 -07004321 /* Wait for the firmware to finish its initialization. */
Michael Chanb090ae22006-01-23 16:07:10 -08004322 rc = bnx2_fw_sync(bp, BNX2_DRV_MSG_DATA_WAIT1 | reset_code, 0);
4323 if (rc)
4324 return rc;
Michael Chanb6016b72005-05-26 13:03:09 -07004325
Michael Chan0d8a6572007-07-07 22:49:43 -07004326 spin_lock_bh(&bp->phy_lock);
Michael Chan489310a2007-10-10 16:16:31 -07004327 old_port = bp->phy_port;
Michael Chan0d8a6572007-07-07 22:49:43 -07004328 bnx2_init_remote_phy(bp);
Michael Chan583c28e2008-01-21 19:51:35 -08004329 if ((bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP) &&
4330 old_port != bp->phy_port)
Michael Chan0d8a6572007-07-07 22:49:43 -07004331 bnx2_set_default_remote_link(bp);
4332 spin_unlock_bh(&bp->phy_lock);
4333
Michael Chanb6016b72005-05-26 13:03:09 -07004334 if (CHIP_ID(bp) == CHIP_ID_5706_A0) {
4335 /* Adjust the voltage regular to two steps lower. The default
4336 * of this register is 0x0000000e. */
4337 REG_WR(bp, BNX2_MISC_VREG_CONTROL, 0x000000fa);
4338
4339 /* Remove bad rbuf memory from the free pool. */
4340 rc = bnx2_alloc_bad_rbuf(bp);
4341 }
4342
David S. Millerf86e82f2008-01-21 17:15:40 -08004343 if (bp->flags & BNX2_FLAG_USING_MSIX)
Michael Chanb4b36042007-12-20 19:59:30 -08004344 bnx2_setup_msix_tbl(bp);
4345
Michael Chanb6016b72005-05-26 13:03:09 -07004346 return rc;
4347}
4348
4349static int
4350bnx2_init_chip(struct bnx2 *bp)
4351{
4352 u32 val;
Michael Chanb4b36042007-12-20 19:59:30 -08004353 int rc, i;
Michael Chanb6016b72005-05-26 13:03:09 -07004354
4355 /* Make sure the interrupt is not active. */
4356 REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD, BNX2_PCICFG_INT_ACK_CMD_MASK_INT);
4357
4358 val = BNX2_DMA_CONFIG_DATA_BYTE_SWAP |
4359 BNX2_DMA_CONFIG_DATA_WORD_SWAP |
4360#ifdef __BIG_ENDIAN
Jeff Garzik6aa20a22006-09-13 13:24:59 -04004361 BNX2_DMA_CONFIG_CNTL_BYTE_SWAP |
Michael Chanb6016b72005-05-26 13:03:09 -07004362#endif
Jeff Garzik6aa20a22006-09-13 13:24:59 -04004363 BNX2_DMA_CONFIG_CNTL_WORD_SWAP |
Michael Chanb6016b72005-05-26 13:03:09 -07004364 DMA_READ_CHANS << 12 |
4365 DMA_WRITE_CHANS << 16;
4366
4367 val |= (0x2 << 20) | (1 << 11);
4368
David S. Millerf86e82f2008-01-21 17:15:40 -08004369 if ((bp->flags & BNX2_FLAG_PCIX) && (bp->bus_speed_mhz == 133))
Michael Chanb6016b72005-05-26 13:03:09 -07004370 val |= (1 << 23);
4371
4372 if ((CHIP_NUM(bp) == CHIP_NUM_5706) &&
David S. Millerf86e82f2008-01-21 17:15:40 -08004373 (CHIP_ID(bp) != CHIP_ID_5706_A0) && !(bp->flags & BNX2_FLAG_PCIX))
Michael Chanb6016b72005-05-26 13:03:09 -07004374 val |= BNX2_DMA_CONFIG_CNTL_PING_PONG_DMA;
4375
4376 REG_WR(bp, BNX2_DMA_CONFIG, val);
4377
4378 if (CHIP_ID(bp) == CHIP_ID_5706_A0) {
4379 val = REG_RD(bp, BNX2_TDMA_CONFIG);
4380 val |= BNX2_TDMA_CONFIG_ONE_DMA;
4381 REG_WR(bp, BNX2_TDMA_CONFIG, val);
4382 }
4383
David S. Millerf86e82f2008-01-21 17:15:40 -08004384 if (bp->flags & BNX2_FLAG_PCIX) {
Michael Chanb6016b72005-05-26 13:03:09 -07004385 u16 val16;
4386
4387 pci_read_config_word(bp->pdev, bp->pcix_cap + PCI_X_CMD,
4388 &val16);
4389 pci_write_config_word(bp->pdev, bp->pcix_cap + PCI_X_CMD,
4390 val16 & ~PCI_X_CMD_ERO);
4391 }
4392
4393 REG_WR(bp, BNX2_MISC_ENABLE_SET_BITS,
4394 BNX2_MISC_ENABLE_SET_BITS_HOST_COALESCE_ENABLE |
4395 BNX2_MISC_ENABLE_STATUS_BITS_RX_V2P_ENABLE |
4396 BNX2_MISC_ENABLE_STATUS_BITS_CONTEXT_ENABLE);
4397
4398 /* Initialize context mapping and zero out the quick contexts. The
4399 * context block must have already been enabled. */
Michael Chan641bdcd2007-06-04 21:22:24 -07004400 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
4401 rc = bnx2_init_5709_context(bp);
4402 if (rc)
4403 return rc;
4404 } else
Michael Chan59b47d82006-11-19 14:10:45 -08004405 bnx2_init_context(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07004406
Michael Chanfba9fe92006-06-12 22:21:25 -07004407 if ((rc = bnx2_init_cpus(bp)) != 0)
4408 return rc;
4409
Michael Chanb6016b72005-05-26 13:03:09 -07004410 bnx2_init_nvram(bp);
4411
4412 bnx2_set_mac_addr(bp);
4413
4414 val = REG_RD(bp, BNX2_MQ_CONFIG);
4415 val &= ~BNX2_MQ_CONFIG_KNL_BYP_BLK_SIZE;
4416 val |= BNX2_MQ_CONFIG_KNL_BYP_BLK_SIZE_256;
Michael Chan68c9f752007-04-24 15:35:53 -07004417 if (CHIP_ID(bp) == CHIP_ID_5709_A0 || CHIP_ID(bp) == CHIP_ID_5709_A1)
4418 val |= BNX2_MQ_CONFIG_HALT_DIS;
4419
Michael Chanb6016b72005-05-26 13:03:09 -07004420 REG_WR(bp, BNX2_MQ_CONFIG, val);
4421
4422 val = 0x10000 + (MAX_CID_CNT * MB_KERNEL_CTX_SIZE);
4423 REG_WR(bp, BNX2_MQ_KNL_BYP_WIND_START, val);
4424 REG_WR(bp, BNX2_MQ_KNL_WIND_END, val);
4425
4426 val = (BCM_PAGE_BITS - 8) << 24;
4427 REG_WR(bp, BNX2_RV2P_CONFIG, val);
4428
4429 /* Configure page size. */
4430 val = REG_RD(bp, BNX2_TBDR_CONFIG);
4431 val &= ~BNX2_TBDR_CONFIG_PAGE_SIZE;
4432 val |= (BCM_PAGE_BITS - 8) << 24 | 0x40;
4433 REG_WR(bp, BNX2_TBDR_CONFIG, val);
4434
4435 val = bp->mac_addr[0] +
4436 (bp->mac_addr[1] << 8) +
4437 (bp->mac_addr[2] << 16) +
4438 bp->mac_addr[3] +
4439 (bp->mac_addr[4] << 8) +
4440 (bp->mac_addr[5] << 16);
4441 REG_WR(bp, BNX2_EMAC_BACKOFF_SEED, val);
4442
4443 /* Program the MTU. Also include 4 bytes for CRC32. */
4444 val = bp->dev->mtu + ETH_HLEN + 4;
4445 if (val > (MAX_ETHERNET_PACKET_SIZE + 4))
4446 val |= BNX2_EMAC_RX_MTU_SIZE_JUMBO_ENA;
4447 REG_WR(bp, BNX2_EMAC_RX_MTU_SIZE, val);
4448
Michael Chanb4b36042007-12-20 19:59:30 -08004449 for (i = 0; i < BNX2_MAX_MSIX_VEC; i++)
4450 bp->bnx2_napi[i].last_status_idx = 0;
4451
Michael Chanb6016b72005-05-26 13:03:09 -07004452 bp->rx_mode = BNX2_EMAC_RX_MODE_SORT_MODE;
4453
4454 /* Set up how to generate a link change interrupt. */
4455 REG_WR(bp, BNX2_EMAC_ATTENTION_ENA, BNX2_EMAC_ATTENTION_ENA_LINK);
4456
4457 REG_WR(bp, BNX2_HC_STATUS_ADDR_L,
4458 (u64) bp->status_blk_mapping & 0xffffffff);
4459 REG_WR(bp, BNX2_HC_STATUS_ADDR_H, (u64) bp->status_blk_mapping >> 32);
4460
4461 REG_WR(bp, BNX2_HC_STATISTICS_ADDR_L,
4462 (u64) bp->stats_blk_mapping & 0xffffffff);
4463 REG_WR(bp, BNX2_HC_STATISTICS_ADDR_H,
4464 (u64) bp->stats_blk_mapping >> 32);
4465
Jeff Garzik6aa20a22006-09-13 13:24:59 -04004466 REG_WR(bp, BNX2_HC_TX_QUICK_CONS_TRIP,
Michael Chanb6016b72005-05-26 13:03:09 -07004467 (bp->tx_quick_cons_trip_int << 16) | bp->tx_quick_cons_trip);
4468
4469 REG_WR(bp, BNX2_HC_RX_QUICK_CONS_TRIP,
4470 (bp->rx_quick_cons_trip_int << 16) | bp->rx_quick_cons_trip);
4471
4472 REG_WR(bp, BNX2_HC_COMP_PROD_TRIP,
4473 (bp->comp_prod_trip_int << 16) | bp->comp_prod_trip);
4474
4475 REG_WR(bp, BNX2_HC_TX_TICKS, (bp->tx_ticks_int << 16) | bp->tx_ticks);
4476
4477 REG_WR(bp, BNX2_HC_RX_TICKS, (bp->rx_ticks_int << 16) | bp->rx_ticks);
4478
4479 REG_WR(bp, BNX2_HC_COM_TICKS,
4480 (bp->com_ticks_int << 16) | bp->com_ticks);
4481
4482 REG_WR(bp, BNX2_HC_CMD_TICKS,
4483 (bp->cmd_ticks_int << 16) | bp->cmd_ticks);
4484
Michael Chan02537b062007-06-04 21:24:07 -07004485 if (CHIP_NUM(bp) == CHIP_NUM_5708)
4486 REG_WR(bp, BNX2_HC_STATS_TICKS, 0);
4487 else
Michael Chan7ea69202007-07-16 18:27:10 -07004488 REG_WR(bp, BNX2_HC_STATS_TICKS, bp->stats_ticks);
Michael Chanb6016b72005-05-26 13:03:09 -07004489 REG_WR(bp, BNX2_HC_STAT_COLLECT_TICKS, 0xbb8); /* 3ms */
4490
4491 if (CHIP_ID(bp) == CHIP_ID_5706_A1)
Michael Chan8e6a72c2007-05-03 13:24:48 -07004492 val = BNX2_HC_CONFIG_COLLECT_STATS;
Michael Chanb6016b72005-05-26 13:03:09 -07004493 else {
Michael Chan8e6a72c2007-05-03 13:24:48 -07004494 val = BNX2_HC_CONFIG_RX_TMR_MODE | BNX2_HC_CONFIG_TX_TMR_MODE |
4495 BNX2_HC_CONFIG_COLLECT_STATS;
Michael Chanb6016b72005-05-26 13:03:09 -07004496 }
4497
David S. Millerf86e82f2008-01-21 17:15:40 -08004498 if (bp->flags & BNX2_FLAG_USING_MSIX) {
Michael Chan6f743ca2008-01-29 21:34:08 -08004499 u32 base = ((BNX2_TX_VEC - 1) * BNX2_HC_SB_CONFIG_SIZE) +
4500 BNX2_HC_SB_CONFIG_1;
4501
Michael Chanc76c0472007-12-20 20:01:19 -08004502 REG_WR(bp, BNX2_HC_MSIX_BIT_VECTOR,
4503 BNX2_HC_MSIX_BIT_VECTOR_VAL);
4504
Michael Chan6f743ca2008-01-29 21:34:08 -08004505 REG_WR(bp, base,
Michael Chanc76c0472007-12-20 20:01:19 -08004506 BNX2_HC_SB_CONFIG_1_TX_TMR_MODE |
4507 BNX2_HC_SB_CONFIG_1_ONE_SHOT);
4508
Michael Chan6f743ca2008-01-29 21:34:08 -08004509 REG_WR(bp, base + BNX2_HC_TX_QUICK_CONS_TRIP_OFF,
Michael Chanc76c0472007-12-20 20:01:19 -08004510 (bp->tx_quick_cons_trip_int << 16) |
4511 bp->tx_quick_cons_trip);
4512
Michael Chan6f743ca2008-01-29 21:34:08 -08004513 REG_WR(bp, base + BNX2_HC_TX_TICKS_OFF,
Michael Chanc76c0472007-12-20 20:01:19 -08004514 (bp->tx_ticks_int << 16) | bp->tx_ticks);
4515
4516 val |= BNX2_HC_CONFIG_SB_ADDR_INC_128B;
4517 }
4518
David S. Millerf86e82f2008-01-21 17:15:40 -08004519 if (bp->flags & BNX2_FLAG_ONE_SHOT_MSI)
Michael Chan8e6a72c2007-05-03 13:24:48 -07004520 val |= BNX2_HC_CONFIG_ONE_SHOT;
4521
4522 REG_WR(bp, BNX2_HC_CONFIG, val);
4523
Michael Chanb6016b72005-05-26 13:03:09 -07004524 /* Clear internal stats counters. */
4525 REG_WR(bp, BNX2_HC_COMMAND, BNX2_HC_COMMAND_CLR_STAT_NOW);
4526
Michael Chanda3e4fb2007-05-03 13:24:23 -07004527 REG_WR(bp, BNX2_HC_ATTN_BITS_ENABLE, STATUS_ATTN_EVENTS);
Michael Chanb6016b72005-05-26 13:03:09 -07004528
4529 /* Initialize the receive filter. */
4530 bnx2_set_rx_mode(bp->dev);
4531
Michael Chan0aa38df2007-06-04 21:23:06 -07004532 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
4533 val = REG_RD(bp, BNX2_MISC_NEW_CORE_CTL);
4534 val |= BNX2_MISC_NEW_CORE_CTL_DMA_ENABLE;
4535 REG_WR(bp, BNX2_MISC_NEW_CORE_CTL, val);
4536 }
Michael Chanb090ae22006-01-23 16:07:10 -08004537 rc = bnx2_fw_sync(bp, BNX2_DRV_MSG_DATA_WAIT2 | BNX2_DRV_MSG_CODE_RESET,
4538 0);
Michael Chanb6016b72005-05-26 13:03:09 -07004539
Michael Chandf149d72007-07-07 22:51:36 -07004540 REG_WR(bp, BNX2_MISC_ENABLE_SET_BITS, BNX2_MISC_ENABLE_DEFAULT);
Michael Chanb6016b72005-05-26 13:03:09 -07004541 REG_RD(bp, BNX2_MISC_ENABLE_SET_BITS);
4542
4543 udelay(20);
4544
Michael Chanbf5295b2006-03-23 01:11:56 -08004545 bp->hc_cmd = REG_RD(bp, BNX2_HC_COMMAND);
4546
Michael Chanb090ae22006-01-23 16:07:10 -08004547 return rc;
Michael Chanb6016b72005-05-26 13:03:09 -07004548}
4549
Michael Chan59b47d82006-11-19 14:10:45 -08004550static void
Michael Chanc76c0472007-12-20 20:01:19 -08004551bnx2_clear_ring_states(struct bnx2 *bp)
4552{
4553 struct bnx2_napi *bnapi;
4554 int i;
4555
4556 for (i = 0; i < BNX2_MAX_MSIX_VEC; i++) {
4557 bnapi = &bp->bnx2_napi[i];
4558
4559 bnapi->tx_cons = 0;
4560 bnapi->hw_tx_cons = 0;
4561 bnapi->rx_prod_bseq = 0;
4562 bnapi->rx_prod = 0;
4563 bnapi->rx_cons = 0;
4564 bnapi->rx_pg_prod = 0;
4565 bnapi->rx_pg_cons = 0;
4566 }
4567}
4568
4569static void
Michael Chan59b47d82006-11-19 14:10:45 -08004570bnx2_init_tx_context(struct bnx2 *bp, u32 cid)
4571{
4572 u32 val, offset0, offset1, offset2, offset3;
Michael Chan62a83132008-01-29 21:35:40 -08004573 u32 cid_addr = GET_CID_ADDR(cid);
Michael Chan59b47d82006-11-19 14:10:45 -08004574
4575 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
4576 offset0 = BNX2_L2CTX_TYPE_XI;
4577 offset1 = BNX2_L2CTX_CMD_TYPE_XI;
4578 offset2 = BNX2_L2CTX_TBDR_BHADDR_HI_XI;
4579 offset3 = BNX2_L2CTX_TBDR_BHADDR_LO_XI;
4580 } else {
4581 offset0 = BNX2_L2CTX_TYPE;
4582 offset1 = BNX2_L2CTX_CMD_TYPE;
4583 offset2 = BNX2_L2CTX_TBDR_BHADDR_HI;
4584 offset3 = BNX2_L2CTX_TBDR_BHADDR_LO;
4585 }
4586 val = BNX2_L2CTX_TYPE_TYPE_L2 | BNX2_L2CTX_TYPE_SIZE_L2;
Michael Chan62a83132008-01-29 21:35:40 -08004587 bnx2_ctx_wr(bp, cid_addr, offset0, val);
Michael Chan59b47d82006-11-19 14:10:45 -08004588
4589 val = BNX2_L2CTX_CMD_TYPE_TYPE_L2 | (8 << 16);
Michael Chan62a83132008-01-29 21:35:40 -08004590 bnx2_ctx_wr(bp, cid_addr, offset1, val);
Michael Chan59b47d82006-11-19 14:10:45 -08004591
4592 val = (u64) bp->tx_desc_mapping >> 32;
Michael Chan62a83132008-01-29 21:35:40 -08004593 bnx2_ctx_wr(bp, cid_addr, offset2, val);
Michael Chan59b47d82006-11-19 14:10:45 -08004594
4595 val = (u64) bp->tx_desc_mapping & 0xffffffff;
Michael Chan62a83132008-01-29 21:35:40 -08004596 bnx2_ctx_wr(bp, cid_addr, offset3, val);
Michael Chan59b47d82006-11-19 14:10:45 -08004597}
Michael Chanb6016b72005-05-26 13:03:09 -07004598
4599static void
4600bnx2_init_tx_ring(struct bnx2 *bp)
4601{
4602 struct tx_bd *txbd;
Michael Chanc76c0472007-12-20 20:01:19 -08004603 u32 cid = TX_CID;
4604 struct bnx2_napi *bnapi;
4605
4606 bp->tx_vec = 0;
David S. Millerf86e82f2008-01-21 17:15:40 -08004607 if (bp->flags & BNX2_FLAG_USING_MSIX) {
Michael Chanc76c0472007-12-20 20:01:19 -08004608 cid = TX_TSS_CID;
4609 bp->tx_vec = BNX2_TX_VEC;
4610 REG_WR(bp, BNX2_TSCH_TSS_CFG, BNX2_TX_INT_NUM |
4611 (TX_TSS_CID << 7));
4612 }
4613 bnapi = &bp->bnx2_napi[bp->tx_vec];
Michael Chanb6016b72005-05-26 13:03:09 -07004614
Michael Chan2f8af122006-08-15 01:39:10 -07004615 bp->tx_wake_thresh = bp->tx_ring_size / 2;
4616
Michael Chanb6016b72005-05-26 13:03:09 -07004617 txbd = &bp->tx_desc_ring[MAX_TX_DESC_CNT];
Jeff Garzik6aa20a22006-09-13 13:24:59 -04004618
Michael Chanb6016b72005-05-26 13:03:09 -07004619 txbd->tx_bd_haddr_hi = (u64) bp->tx_desc_mapping >> 32;
4620 txbd->tx_bd_haddr_lo = (u64) bp->tx_desc_mapping & 0xffffffff;
4621
4622 bp->tx_prod = 0;
Michael Chanb6016b72005-05-26 13:03:09 -07004623 bp->tx_prod_bseq = 0;
Jeff Garzik6aa20a22006-09-13 13:24:59 -04004624
Michael Chan59b47d82006-11-19 14:10:45 -08004625 bp->tx_bidx_addr = MB_GET_CID_ADDR(cid) + BNX2_L2CTX_TX_HOST_BIDX;
4626 bp->tx_bseq_addr = MB_GET_CID_ADDR(cid) + BNX2_L2CTX_TX_HOST_BSEQ;
Michael Chanb6016b72005-05-26 13:03:09 -07004627
Michael Chan59b47d82006-11-19 14:10:45 -08004628 bnx2_init_tx_context(bp, cid);
Michael Chanb6016b72005-05-26 13:03:09 -07004629}
4630
4631static void
Michael Chan5d5d0012007-12-12 11:17:43 -08004632bnx2_init_rxbd_rings(struct rx_bd *rx_ring[], dma_addr_t dma[], u32 buf_size,
4633 int num_rings)
Michael Chanb6016b72005-05-26 13:03:09 -07004634{
Michael Chanb6016b72005-05-26 13:03:09 -07004635 int i;
Michael Chan5d5d0012007-12-12 11:17:43 -08004636 struct rx_bd *rxbd;
Michael Chanb6016b72005-05-26 13:03:09 -07004637
Michael Chan5d5d0012007-12-12 11:17:43 -08004638 for (i = 0; i < num_rings; i++) {
Michael Chan13daffa2006-03-20 17:49:20 -08004639 int j;
Michael Chanb6016b72005-05-26 13:03:09 -07004640
Michael Chan5d5d0012007-12-12 11:17:43 -08004641 rxbd = &rx_ring[i][0];
Michael Chan13daffa2006-03-20 17:49:20 -08004642 for (j = 0; j < MAX_RX_DESC_CNT; j++, rxbd++) {
Michael Chan5d5d0012007-12-12 11:17:43 -08004643 rxbd->rx_bd_len = buf_size;
Michael Chan13daffa2006-03-20 17:49:20 -08004644 rxbd->rx_bd_flags = RX_BD_FLAGS_START | RX_BD_FLAGS_END;
4645 }
Michael Chan5d5d0012007-12-12 11:17:43 -08004646 if (i == (num_rings - 1))
Michael Chan13daffa2006-03-20 17:49:20 -08004647 j = 0;
4648 else
4649 j = i + 1;
Michael Chan5d5d0012007-12-12 11:17:43 -08004650 rxbd->rx_bd_haddr_hi = (u64) dma[j] >> 32;
4651 rxbd->rx_bd_haddr_lo = (u64) dma[j] & 0xffffffff;
Michael Chan13daffa2006-03-20 17:49:20 -08004652 }
Michael Chan5d5d0012007-12-12 11:17:43 -08004653}
4654
4655static void
4656bnx2_init_rx_ring(struct bnx2 *bp)
4657{
4658 int i;
4659 u16 prod, ring_prod;
4660 u32 val, rx_cid_addr = GET_CID_ADDR(RX_CID);
Michael Chanb4b36042007-12-20 19:59:30 -08004661 struct bnx2_napi *bnapi = &bp->bnx2_napi[0];
Michael Chan5d5d0012007-12-12 11:17:43 -08004662
Michael Chan5d5d0012007-12-12 11:17:43 -08004663 bnx2_init_rxbd_rings(bp->rx_desc_ring, bp->rx_desc_mapping,
4664 bp->rx_buf_use_size, bp->rx_max_ring);
4665
Michael Chan83e3fc82008-01-29 21:37:17 -08004666 bnx2_init_rx_context0(bp);
4667
4668 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
4669 val = REG_RD(bp, BNX2_MQ_MAP_L2_5);
4670 REG_WR(bp, BNX2_MQ_MAP_L2_5, val | BNX2_MQ_MAP_L2_5_ARM);
4671 }
4672
Michael Chan62a83132008-01-29 21:35:40 -08004673 bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_PG_BUF_SIZE, 0);
Michael Chan47bf4242007-12-12 11:19:12 -08004674 if (bp->rx_pg_ring_size) {
4675 bnx2_init_rxbd_rings(bp->rx_pg_desc_ring,
4676 bp->rx_pg_desc_mapping,
4677 PAGE_SIZE, bp->rx_max_pg_ring);
4678 val = (bp->rx_buf_use_size << 16) | PAGE_SIZE;
Michael Chan62a83132008-01-29 21:35:40 -08004679 bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_PG_BUF_SIZE, val);
4680 bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_RBDC_KEY,
Michael Chan47bf4242007-12-12 11:19:12 -08004681 BNX2_L2CTX_RBDC_JUMBO_KEY);
4682
4683 val = (u64) bp->rx_pg_desc_mapping[0] >> 32;
Michael Chan62a83132008-01-29 21:35:40 -08004684 bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_NX_PG_BDHADDR_HI, val);
Michael Chan47bf4242007-12-12 11:19:12 -08004685
4686 val = (u64) bp->rx_pg_desc_mapping[0] & 0xffffffff;
Michael Chan62a83132008-01-29 21:35:40 -08004687 bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_NX_PG_BDHADDR_LO, val);
Michael Chan47bf4242007-12-12 11:19:12 -08004688
4689 if (CHIP_NUM(bp) == CHIP_NUM_5709)
4690 REG_WR(bp, BNX2_MQ_MAP_L2_3, BNX2_MQ_MAP_L2_3_DEFAULT);
4691 }
Michael Chanb6016b72005-05-26 13:03:09 -07004692
Michael Chan13daffa2006-03-20 17:49:20 -08004693 val = (u64) bp->rx_desc_mapping[0] >> 32;
Michael Chan62a83132008-01-29 21:35:40 -08004694 bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_NX_BDHADDR_HI, val);
Michael Chanb6016b72005-05-26 13:03:09 -07004695
Michael Chan13daffa2006-03-20 17:49:20 -08004696 val = (u64) bp->rx_desc_mapping[0] & 0xffffffff;
Michael Chan62a83132008-01-29 21:35:40 -08004697 bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_NX_BDHADDR_LO, val);
Michael Chanb6016b72005-05-26 13:03:09 -07004698
Michael Chana1f60192007-12-20 19:57:19 -08004699 ring_prod = prod = bnapi->rx_pg_prod;
Michael Chan47bf4242007-12-12 11:19:12 -08004700 for (i = 0; i < bp->rx_pg_ring_size; i++) {
4701 if (bnx2_alloc_rx_page(bp, ring_prod) < 0)
4702 break;
4703 prod = NEXT_RX_BD(prod);
4704 ring_prod = RX_PG_RING_IDX(prod);
4705 }
Michael Chana1f60192007-12-20 19:57:19 -08004706 bnapi->rx_pg_prod = prod;
Michael Chan47bf4242007-12-12 11:19:12 -08004707
Michael Chana1f60192007-12-20 19:57:19 -08004708 ring_prod = prod = bnapi->rx_prod;
Michael Chan236b6392006-03-20 17:49:02 -08004709 for (i = 0; i < bp->rx_ring_size; i++) {
Michael Chana1f60192007-12-20 19:57:19 -08004710 if (bnx2_alloc_rx_skb(bp, bnapi, ring_prod) < 0) {
Michael Chanb6016b72005-05-26 13:03:09 -07004711 break;
4712 }
4713 prod = NEXT_RX_BD(prod);
4714 ring_prod = RX_RING_IDX(prod);
4715 }
Michael Chana1f60192007-12-20 19:57:19 -08004716 bnapi->rx_prod = prod;
Michael Chanb6016b72005-05-26 13:03:09 -07004717
Michael Chana1f60192007-12-20 19:57:19 -08004718 REG_WR16(bp, MB_RX_CID_ADDR + BNX2_L2CTX_HOST_PG_BDIDX,
4719 bnapi->rx_pg_prod);
Michael Chanb6016b72005-05-26 13:03:09 -07004720 REG_WR16(bp, MB_RX_CID_ADDR + BNX2_L2CTX_HOST_BDIDX, prod);
4721
Michael Chana1f60192007-12-20 19:57:19 -08004722 REG_WR(bp, MB_RX_CID_ADDR + BNX2_L2CTX_HOST_BSEQ, bnapi->rx_prod_bseq);
Michael Chanb6016b72005-05-26 13:03:09 -07004723}
4724
Michael Chan5d5d0012007-12-12 11:17:43 -08004725static u32 bnx2_find_max_ring(u32 ring_size, u32 max_size)
Michael Chan13daffa2006-03-20 17:49:20 -08004726{
Michael Chan5d5d0012007-12-12 11:17:43 -08004727 u32 max, num_rings = 1;
Michael Chan13daffa2006-03-20 17:49:20 -08004728
Michael Chan5d5d0012007-12-12 11:17:43 -08004729 while (ring_size > MAX_RX_DESC_CNT) {
4730 ring_size -= MAX_RX_DESC_CNT;
Michael Chan13daffa2006-03-20 17:49:20 -08004731 num_rings++;
4732 }
4733 /* round to next power of 2 */
Michael Chan5d5d0012007-12-12 11:17:43 -08004734 max = max_size;
Michael Chan13daffa2006-03-20 17:49:20 -08004735 while ((max & num_rings) == 0)
4736 max >>= 1;
4737
4738 if (num_rings != max)
4739 max <<= 1;
4740
Michael Chan5d5d0012007-12-12 11:17:43 -08004741 return max;
4742}
4743
4744static void
4745bnx2_set_rx_ring_size(struct bnx2 *bp, u32 size)
4746{
Michael Chan84eaa182007-12-12 11:19:57 -08004747 u32 rx_size, rx_space, jumbo_size;
Michael Chan5d5d0012007-12-12 11:17:43 -08004748
4749 /* 8 for CRC and VLAN */
4750 rx_size = bp->dev->mtu + ETH_HLEN + bp->rx_offset + 8;
4751
Michael Chan84eaa182007-12-12 11:19:57 -08004752 rx_space = SKB_DATA_ALIGN(rx_size + BNX2_RX_ALIGN) + NET_SKB_PAD +
4753 sizeof(struct skb_shared_info);
4754
Michael Chan5d5d0012007-12-12 11:17:43 -08004755 bp->rx_copy_thresh = RX_COPY_THRESH;
Michael Chan47bf4242007-12-12 11:19:12 -08004756 bp->rx_pg_ring_size = 0;
4757 bp->rx_max_pg_ring = 0;
4758 bp->rx_max_pg_ring_idx = 0;
David S. Millerf86e82f2008-01-21 17:15:40 -08004759 if ((rx_space > PAGE_SIZE) && !(bp->flags & BNX2_FLAG_JUMBO_BROKEN)) {
Michael Chan84eaa182007-12-12 11:19:57 -08004760 int pages = PAGE_ALIGN(bp->dev->mtu - 40) >> PAGE_SHIFT;
4761
4762 jumbo_size = size * pages;
4763 if (jumbo_size > MAX_TOTAL_RX_PG_DESC_CNT)
4764 jumbo_size = MAX_TOTAL_RX_PG_DESC_CNT;
4765
4766 bp->rx_pg_ring_size = jumbo_size;
4767 bp->rx_max_pg_ring = bnx2_find_max_ring(jumbo_size,
4768 MAX_RX_PG_RINGS);
4769 bp->rx_max_pg_ring_idx = (bp->rx_max_pg_ring * RX_DESC_CNT) - 1;
4770 rx_size = RX_COPY_THRESH + bp->rx_offset;
4771 bp->rx_copy_thresh = 0;
4772 }
Michael Chan5d5d0012007-12-12 11:17:43 -08004773
4774 bp->rx_buf_use_size = rx_size;
4775 /* hw alignment */
4776 bp->rx_buf_size = bp->rx_buf_use_size + BNX2_RX_ALIGN;
Michael Chan1db82f22007-12-12 11:19:35 -08004777 bp->rx_jumbo_thresh = rx_size - bp->rx_offset;
Michael Chan5d5d0012007-12-12 11:17:43 -08004778 bp->rx_ring_size = size;
4779 bp->rx_max_ring = bnx2_find_max_ring(size, MAX_RX_RINGS);
Michael Chan13daffa2006-03-20 17:49:20 -08004780 bp->rx_max_ring_idx = (bp->rx_max_ring * RX_DESC_CNT) - 1;
4781}
4782
4783static void
Michael Chanb6016b72005-05-26 13:03:09 -07004784bnx2_free_tx_skbs(struct bnx2 *bp)
4785{
4786 int i;
4787
4788 if (bp->tx_buf_ring == NULL)
4789 return;
4790
4791 for (i = 0; i < TX_DESC_CNT; ) {
4792 struct sw_bd *tx_buf = &bp->tx_buf_ring[i];
4793 struct sk_buff *skb = tx_buf->skb;
4794 int j, last;
4795
4796 if (skb == NULL) {
4797 i++;
4798 continue;
4799 }
4800
4801 pci_unmap_single(bp->pdev, pci_unmap_addr(tx_buf, mapping),
4802 skb_headlen(skb), PCI_DMA_TODEVICE);
4803
4804 tx_buf->skb = NULL;
4805
4806 last = skb_shinfo(skb)->nr_frags;
4807 for (j = 0; j < last; j++) {
4808 tx_buf = &bp->tx_buf_ring[i + j + 1];
4809 pci_unmap_page(bp->pdev,
4810 pci_unmap_addr(tx_buf, mapping),
4811 skb_shinfo(skb)->frags[j].size,
4812 PCI_DMA_TODEVICE);
4813 }
Michael Chan745720e2006-06-29 12:37:41 -07004814 dev_kfree_skb(skb);
Michael Chanb6016b72005-05-26 13:03:09 -07004815 i += j + 1;
4816 }
4817
4818}
4819
4820static void
4821bnx2_free_rx_skbs(struct bnx2 *bp)
4822{
4823 int i;
4824
4825 if (bp->rx_buf_ring == NULL)
4826 return;
4827
Michael Chan13daffa2006-03-20 17:49:20 -08004828 for (i = 0; i < bp->rx_max_ring_idx; i++) {
Michael Chanb6016b72005-05-26 13:03:09 -07004829 struct sw_bd *rx_buf = &bp->rx_buf_ring[i];
4830 struct sk_buff *skb = rx_buf->skb;
4831
Michael Chan05d0f1c2005-11-04 08:53:48 -08004832 if (skb == NULL)
Michael Chanb6016b72005-05-26 13:03:09 -07004833 continue;
4834
4835 pci_unmap_single(bp->pdev, pci_unmap_addr(rx_buf, mapping),
4836 bp->rx_buf_use_size, PCI_DMA_FROMDEVICE);
4837
4838 rx_buf->skb = NULL;
4839
Michael Chan745720e2006-06-29 12:37:41 -07004840 dev_kfree_skb(skb);
Michael Chanb6016b72005-05-26 13:03:09 -07004841 }
Michael Chan47bf4242007-12-12 11:19:12 -08004842 for (i = 0; i < bp->rx_max_pg_ring_idx; i++)
4843 bnx2_free_rx_page(bp, i);
Michael Chanb6016b72005-05-26 13:03:09 -07004844}
4845
4846static void
4847bnx2_free_skbs(struct bnx2 *bp)
4848{
4849 bnx2_free_tx_skbs(bp);
4850 bnx2_free_rx_skbs(bp);
4851}
4852
4853static int
4854bnx2_reset_nic(struct bnx2 *bp, u32 reset_code)
4855{
4856 int rc;
4857
4858 rc = bnx2_reset_chip(bp, reset_code);
4859 bnx2_free_skbs(bp);
4860 if (rc)
4861 return rc;
4862
Michael Chanfba9fe92006-06-12 22:21:25 -07004863 if ((rc = bnx2_init_chip(bp)) != 0)
4864 return rc;
4865
Michael Chanc76c0472007-12-20 20:01:19 -08004866 bnx2_clear_ring_states(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07004867 bnx2_init_tx_ring(bp);
4868 bnx2_init_rx_ring(bp);
4869 return 0;
4870}
4871
4872static int
4873bnx2_init_nic(struct bnx2 *bp)
4874{
4875 int rc;
4876
4877 if ((rc = bnx2_reset_nic(bp, BNX2_DRV_MSG_CODE_RESET)) != 0)
4878 return rc;
4879
Michael Chan80be4432006-11-19 14:07:28 -08004880 spin_lock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07004881 bnx2_init_phy(bp);
4882 bnx2_set_link(bp);
Michael Chan0d8a6572007-07-07 22:49:43 -07004883 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07004884 return 0;
4885}
4886
4887static int
4888bnx2_test_registers(struct bnx2 *bp)
4889{
4890 int ret;
Michael Chan5bae30c2007-05-03 13:18:46 -07004891 int i, is_5709;
Arjan van de Venf71e1302006-03-03 21:33:57 -05004892 static const struct {
Michael Chanb6016b72005-05-26 13:03:09 -07004893 u16 offset;
4894 u16 flags;
Michael Chan5bae30c2007-05-03 13:18:46 -07004895#define BNX2_FL_NOT_5709 1
Michael Chanb6016b72005-05-26 13:03:09 -07004896 u32 rw_mask;
4897 u32 ro_mask;
4898 } reg_tbl[] = {
4899 { 0x006c, 0, 0x00000000, 0x0000003f },
4900 { 0x0090, 0, 0xffffffff, 0x00000000 },
4901 { 0x0094, 0, 0x00000000, 0x00000000 },
4902
Michael Chan5bae30c2007-05-03 13:18:46 -07004903 { 0x0404, BNX2_FL_NOT_5709, 0x00003f00, 0x00000000 },
4904 { 0x0418, BNX2_FL_NOT_5709, 0x00000000, 0xffffffff },
4905 { 0x041c, BNX2_FL_NOT_5709, 0x00000000, 0xffffffff },
4906 { 0x0420, BNX2_FL_NOT_5709, 0x00000000, 0x80ffffff },
4907 { 0x0424, BNX2_FL_NOT_5709, 0x00000000, 0x00000000 },
4908 { 0x0428, BNX2_FL_NOT_5709, 0x00000000, 0x00000001 },
4909 { 0x0450, BNX2_FL_NOT_5709, 0x00000000, 0x0000ffff },
4910 { 0x0454, BNX2_FL_NOT_5709, 0x00000000, 0xffffffff },
4911 { 0x0458, BNX2_FL_NOT_5709, 0x00000000, 0xffffffff },
Michael Chanb6016b72005-05-26 13:03:09 -07004912
Michael Chan5bae30c2007-05-03 13:18:46 -07004913 { 0x0808, BNX2_FL_NOT_5709, 0x00000000, 0xffffffff },
4914 { 0x0854, BNX2_FL_NOT_5709, 0x00000000, 0xffffffff },
4915 { 0x0868, BNX2_FL_NOT_5709, 0x00000000, 0x77777777 },
4916 { 0x086c, BNX2_FL_NOT_5709, 0x00000000, 0x77777777 },
4917 { 0x0870, BNX2_FL_NOT_5709, 0x00000000, 0x77777777 },
4918 { 0x0874, BNX2_FL_NOT_5709, 0x00000000, 0x77777777 },
Michael Chanb6016b72005-05-26 13:03:09 -07004919
Michael Chan5bae30c2007-05-03 13:18:46 -07004920 { 0x0c00, BNX2_FL_NOT_5709, 0x00000000, 0x00000001 },
4921 { 0x0c04, BNX2_FL_NOT_5709, 0x00000000, 0x03ff0001 },
4922 { 0x0c08, BNX2_FL_NOT_5709, 0x0f0ff073, 0x00000000 },
Michael Chanb6016b72005-05-26 13:03:09 -07004923
4924 { 0x1000, 0, 0x00000000, 0x00000001 },
4925 { 0x1004, 0, 0x00000000, 0x000f0001 },
Michael Chanb6016b72005-05-26 13:03:09 -07004926
4927 { 0x1408, 0, 0x01c00800, 0x00000000 },
4928 { 0x149c, 0, 0x8000ffff, 0x00000000 },
4929 { 0x14a8, 0, 0x00000000, 0x000001ff },
Michael Chan5b0c76a2005-11-04 08:45:49 -08004930 { 0x14ac, 0, 0x0fffffff, 0x10000000 },
Michael Chanb6016b72005-05-26 13:03:09 -07004931 { 0x14b0, 0, 0x00000002, 0x00000001 },
4932 { 0x14b8, 0, 0x00000000, 0x00000000 },
4933 { 0x14c0, 0, 0x00000000, 0x00000009 },
4934 { 0x14c4, 0, 0x00003fff, 0x00000000 },
4935 { 0x14cc, 0, 0x00000000, 0x00000001 },
4936 { 0x14d0, 0, 0xffffffff, 0x00000000 },
Michael Chanb6016b72005-05-26 13:03:09 -07004937
4938 { 0x1800, 0, 0x00000000, 0x00000001 },
4939 { 0x1804, 0, 0x00000000, 0x00000003 },
Michael Chanb6016b72005-05-26 13:03:09 -07004940
4941 { 0x2800, 0, 0x00000000, 0x00000001 },
4942 { 0x2804, 0, 0x00000000, 0x00003f01 },
4943 { 0x2808, 0, 0x0f3f3f03, 0x00000000 },
4944 { 0x2810, 0, 0xffff0000, 0x00000000 },
4945 { 0x2814, 0, 0xffff0000, 0x00000000 },
4946 { 0x2818, 0, 0xffff0000, 0x00000000 },
4947 { 0x281c, 0, 0xffff0000, 0x00000000 },
4948 { 0x2834, 0, 0xffffffff, 0x00000000 },
4949 { 0x2840, 0, 0x00000000, 0xffffffff },
4950 { 0x2844, 0, 0x00000000, 0xffffffff },
4951 { 0x2848, 0, 0xffffffff, 0x00000000 },
4952 { 0x284c, 0, 0xf800f800, 0x07ff07ff },
4953
4954 { 0x2c00, 0, 0x00000000, 0x00000011 },
4955 { 0x2c04, 0, 0x00000000, 0x00030007 },
4956
Michael Chanb6016b72005-05-26 13:03:09 -07004957 { 0x3c00, 0, 0x00000000, 0x00000001 },
4958 { 0x3c04, 0, 0x00000000, 0x00070000 },
4959 { 0x3c08, 0, 0x00007f71, 0x07f00000 },
4960 { 0x3c0c, 0, 0x1f3ffffc, 0x00000000 },
4961 { 0x3c10, 0, 0xffffffff, 0x00000000 },
4962 { 0x3c14, 0, 0x00000000, 0xffffffff },
4963 { 0x3c18, 0, 0x00000000, 0xffffffff },
4964 { 0x3c1c, 0, 0xfffff000, 0x00000000 },
4965 { 0x3c20, 0, 0xffffff00, 0x00000000 },
Michael Chanb6016b72005-05-26 13:03:09 -07004966
4967 { 0x5004, 0, 0x00000000, 0x0000007f },
4968 { 0x5008, 0, 0x0f0007ff, 0x00000000 },
Michael Chanb6016b72005-05-26 13:03:09 -07004969
Michael Chanb6016b72005-05-26 13:03:09 -07004970 { 0x5c00, 0, 0x00000000, 0x00000001 },
4971 { 0x5c04, 0, 0x00000000, 0x0003000f },
4972 { 0x5c08, 0, 0x00000003, 0x00000000 },
4973 { 0x5c0c, 0, 0x0000fff8, 0x00000000 },
4974 { 0x5c10, 0, 0x00000000, 0xffffffff },
4975 { 0x5c80, 0, 0x00000000, 0x0f7113f1 },
4976 { 0x5c84, 0, 0x00000000, 0x0000f333 },
4977 { 0x5c88, 0, 0x00000000, 0x00077373 },
4978 { 0x5c8c, 0, 0x00000000, 0x0007f737 },
4979
4980 { 0x6808, 0, 0x0000ff7f, 0x00000000 },
4981 { 0x680c, 0, 0xffffffff, 0x00000000 },
4982 { 0x6810, 0, 0xffffffff, 0x00000000 },
4983 { 0x6814, 0, 0xffffffff, 0x00000000 },
4984 { 0x6818, 0, 0xffffffff, 0x00000000 },
4985 { 0x681c, 0, 0xffffffff, 0x00000000 },
4986 { 0x6820, 0, 0x00ff00ff, 0x00000000 },
4987 { 0x6824, 0, 0x00ff00ff, 0x00000000 },
4988 { 0x6828, 0, 0x00ff00ff, 0x00000000 },
4989 { 0x682c, 0, 0x03ff03ff, 0x00000000 },
4990 { 0x6830, 0, 0x03ff03ff, 0x00000000 },
4991 { 0x6834, 0, 0x03ff03ff, 0x00000000 },
4992 { 0x6838, 0, 0x03ff03ff, 0x00000000 },
4993 { 0x683c, 0, 0x0000ffff, 0x00000000 },
4994 { 0x6840, 0, 0x00000ff0, 0x00000000 },
4995 { 0x6844, 0, 0x00ffff00, 0x00000000 },
4996 { 0x684c, 0, 0xffffffff, 0x00000000 },
4997 { 0x6850, 0, 0x7f7f7f7f, 0x00000000 },
4998 { 0x6854, 0, 0x7f7f7f7f, 0x00000000 },
4999 { 0x6858, 0, 0x7f7f7f7f, 0x00000000 },
5000 { 0x685c, 0, 0x7f7f7f7f, 0x00000000 },
5001 { 0x6908, 0, 0x00000000, 0x0001ff0f },
5002 { 0x690c, 0, 0x00000000, 0x0ffe00f0 },
5003
5004 { 0xffff, 0, 0x00000000, 0x00000000 },
5005 };
5006
5007 ret = 0;
Michael Chan5bae30c2007-05-03 13:18:46 -07005008 is_5709 = 0;
5009 if (CHIP_NUM(bp) == CHIP_NUM_5709)
5010 is_5709 = 1;
5011
Michael Chanb6016b72005-05-26 13:03:09 -07005012 for (i = 0; reg_tbl[i].offset != 0xffff; i++) {
5013 u32 offset, rw_mask, ro_mask, save_val, val;
Michael Chan5bae30c2007-05-03 13:18:46 -07005014 u16 flags = reg_tbl[i].flags;
5015
5016 if (is_5709 && (flags & BNX2_FL_NOT_5709))
5017 continue;
Michael Chanb6016b72005-05-26 13:03:09 -07005018
5019 offset = (u32) reg_tbl[i].offset;
5020 rw_mask = reg_tbl[i].rw_mask;
5021 ro_mask = reg_tbl[i].ro_mask;
5022
Peter Hagervall14ab9b82005-08-10 14:18:16 -07005023 save_val = readl(bp->regview + offset);
Michael Chanb6016b72005-05-26 13:03:09 -07005024
Peter Hagervall14ab9b82005-08-10 14:18:16 -07005025 writel(0, bp->regview + offset);
Michael Chanb6016b72005-05-26 13:03:09 -07005026
Peter Hagervall14ab9b82005-08-10 14:18:16 -07005027 val = readl(bp->regview + offset);
Michael Chanb6016b72005-05-26 13:03:09 -07005028 if ((val & rw_mask) != 0) {
5029 goto reg_test_err;
5030 }
5031
5032 if ((val & ro_mask) != (save_val & ro_mask)) {
5033 goto reg_test_err;
5034 }
5035
Peter Hagervall14ab9b82005-08-10 14:18:16 -07005036 writel(0xffffffff, bp->regview + offset);
Michael Chanb6016b72005-05-26 13:03:09 -07005037
Peter Hagervall14ab9b82005-08-10 14:18:16 -07005038 val = readl(bp->regview + offset);
Michael Chanb6016b72005-05-26 13:03:09 -07005039 if ((val & rw_mask) != rw_mask) {
5040 goto reg_test_err;
5041 }
5042
5043 if ((val & ro_mask) != (save_val & ro_mask)) {
5044 goto reg_test_err;
5045 }
5046
Peter Hagervall14ab9b82005-08-10 14:18:16 -07005047 writel(save_val, bp->regview + offset);
Michael Chanb6016b72005-05-26 13:03:09 -07005048 continue;
5049
5050reg_test_err:
Peter Hagervall14ab9b82005-08-10 14:18:16 -07005051 writel(save_val, bp->regview + offset);
Michael Chanb6016b72005-05-26 13:03:09 -07005052 ret = -ENODEV;
5053 break;
5054 }
5055 return ret;
5056}
5057
5058static int
5059bnx2_do_mem_test(struct bnx2 *bp, u32 start, u32 size)
5060{
Arjan van de Venf71e1302006-03-03 21:33:57 -05005061 static const u32 test_pattern[] = { 0x00000000, 0xffffffff, 0x55555555,
Michael Chanb6016b72005-05-26 13:03:09 -07005062 0xaaaaaaaa , 0xaa55aa55, 0x55aa55aa };
5063 int i;
5064
5065 for (i = 0; i < sizeof(test_pattern) / 4; i++) {
5066 u32 offset;
5067
5068 for (offset = 0; offset < size; offset += 4) {
5069
Michael Chan2726d6e2008-01-29 21:35:05 -08005070 bnx2_reg_wr_ind(bp, start + offset, test_pattern[i]);
Michael Chanb6016b72005-05-26 13:03:09 -07005071
Michael Chan2726d6e2008-01-29 21:35:05 -08005072 if (bnx2_reg_rd_ind(bp, start + offset) !=
Michael Chanb6016b72005-05-26 13:03:09 -07005073 test_pattern[i]) {
5074 return -ENODEV;
5075 }
5076 }
5077 }
5078 return 0;
5079}
5080
5081static int
5082bnx2_test_memory(struct bnx2 *bp)
5083{
5084 int ret = 0;
5085 int i;
Michael Chan5bae30c2007-05-03 13:18:46 -07005086 static struct mem_entry {
Michael Chanb6016b72005-05-26 13:03:09 -07005087 u32 offset;
5088 u32 len;
Michael Chan5bae30c2007-05-03 13:18:46 -07005089 } mem_tbl_5706[] = {
Michael Chanb6016b72005-05-26 13:03:09 -07005090 { 0x60000, 0x4000 },
Michael Chan5b0c76a2005-11-04 08:45:49 -08005091 { 0xa0000, 0x3000 },
Michael Chanb6016b72005-05-26 13:03:09 -07005092 { 0xe0000, 0x4000 },
5093 { 0x120000, 0x4000 },
5094 { 0x1a0000, 0x4000 },
5095 { 0x160000, 0x4000 },
5096 { 0xffffffff, 0 },
Michael Chan5bae30c2007-05-03 13:18:46 -07005097 },
5098 mem_tbl_5709[] = {
5099 { 0x60000, 0x4000 },
5100 { 0xa0000, 0x3000 },
5101 { 0xe0000, 0x4000 },
5102 { 0x120000, 0x4000 },
5103 { 0x1a0000, 0x4000 },
5104 { 0xffffffff, 0 },
Michael Chanb6016b72005-05-26 13:03:09 -07005105 };
Michael Chan5bae30c2007-05-03 13:18:46 -07005106 struct mem_entry *mem_tbl;
5107
5108 if (CHIP_NUM(bp) == CHIP_NUM_5709)
5109 mem_tbl = mem_tbl_5709;
5110 else
5111 mem_tbl = mem_tbl_5706;
Michael Chanb6016b72005-05-26 13:03:09 -07005112
5113 for (i = 0; mem_tbl[i].offset != 0xffffffff; i++) {
5114 if ((ret = bnx2_do_mem_test(bp, mem_tbl[i].offset,
5115 mem_tbl[i].len)) != 0) {
5116 return ret;
5117 }
5118 }
Jeff Garzik6aa20a22006-09-13 13:24:59 -04005119
Michael Chanb6016b72005-05-26 13:03:09 -07005120 return ret;
5121}
5122
Michael Chanbc5a0692006-01-23 16:13:22 -08005123#define BNX2_MAC_LOOPBACK 0
5124#define BNX2_PHY_LOOPBACK 1
5125
Michael Chanb6016b72005-05-26 13:03:09 -07005126static int
Michael Chanbc5a0692006-01-23 16:13:22 -08005127bnx2_run_loopback(struct bnx2 *bp, int loopback_mode)
Michael Chanb6016b72005-05-26 13:03:09 -07005128{
5129 unsigned int pkt_size, num_pkts, i;
5130 struct sk_buff *skb, *rx_skb;
5131 unsigned char *packet;
Michael Chanbc5a0692006-01-23 16:13:22 -08005132 u16 rx_start_idx, rx_idx;
Michael Chanb6016b72005-05-26 13:03:09 -07005133 dma_addr_t map;
5134 struct tx_bd *txbd;
5135 struct sw_bd *rx_buf;
5136 struct l2_fhdr *rx_hdr;
5137 int ret = -ENODEV;
Michael Chanc76c0472007-12-20 20:01:19 -08005138 struct bnx2_napi *bnapi = &bp->bnx2_napi[0], *tx_napi;
5139
5140 tx_napi = bnapi;
David S. Millerf86e82f2008-01-21 17:15:40 -08005141 if (bp->flags & BNX2_FLAG_USING_MSIX)
Michael Chanc76c0472007-12-20 20:01:19 -08005142 tx_napi = &bp->bnx2_napi[BNX2_TX_VEC];
Michael Chanb6016b72005-05-26 13:03:09 -07005143
Michael Chanbc5a0692006-01-23 16:13:22 -08005144 if (loopback_mode == BNX2_MAC_LOOPBACK) {
5145 bp->loopback = MAC_LOOPBACK;
5146 bnx2_set_mac_loopback(bp);
5147 }
5148 else if (loopback_mode == BNX2_PHY_LOOPBACK) {
Michael Chan583c28e2008-01-21 19:51:35 -08005149 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
Michael Chan489310a2007-10-10 16:16:31 -07005150 return 0;
5151
Michael Chan80be4432006-11-19 14:07:28 -08005152 bp->loopback = PHY_LOOPBACK;
Michael Chanbc5a0692006-01-23 16:13:22 -08005153 bnx2_set_phy_loopback(bp);
5154 }
5155 else
5156 return -EINVAL;
Michael Chanb6016b72005-05-26 13:03:09 -07005157
Michael Chan84eaa182007-12-12 11:19:57 -08005158 pkt_size = min(bp->dev->mtu + ETH_HLEN, bp->rx_jumbo_thresh - 4);
Michael Chan932f3772006-08-15 01:39:36 -07005159 skb = netdev_alloc_skb(bp->dev, pkt_size);
John W. Linvilleb6cbc3b62005-11-10 12:58:00 -08005160 if (!skb)
5161 return -ENOMEM;
Michael Chanb6016b72005-05-26 13:03:09 -07005162 packet = skb_put(skb, pkt_size);
Michael Chan66342922006-12-14 15:57:04 -08005163 memcpy(packet, bp->dev->dev_addr, 6);
Michael Chanb6016b72005-05-26 13:03:09 -07005164 memset(packet + 6, 0x0, 8);
5165 for (i = 14; i < pkt_size; i++)
5166 packet[i] = (unsigned char) (i & 0xff);
5167
5168 map = pci_map_single(bp->pdev, skb->data, pkt_size,
5169 PCI_DMA_TODEVICE);
5170
Michael Chanbf5295b2006-03-23 01:11:56 -08005171 REG_WR(bp, BNX2_HC_COMMAND,
5172 bp->hc_cmd | BNX2_HC_COMMAND_COAL_NOW_WO_INT);
5173
Michael Chanb6016b72005-05-26 13:03:09 -07005174 REG_RD(bp, BNX2_HC_COMMAND);
5175
5176 udelay(5);
Michael Chan35efa7c2007-12-20 19:56:37 -08005177 rx_start_idx = bnx2_get_hw_rx_cons(bnapi);
Michael Chanb6016b72005-05-26 13:03:09 -07005178
Michael Chanb6016b72005-05-26 13:03:09 -07005179 num_pkts = 0;
5180
Michael Chanbc5a0692006-01-23 16:13:22 -08005181 txbd = &bp->tx_desc_ring[TX_RING_IDX(bp->tx_prod)];
Michael Chanb6016b72005-05-26 13:03:09 -07005182
5183 txbd->tx_bd_haddr_hi = (u64) map >> 32;
5184 txbd->tx_bd_haddr_lo = (u64) map & 0xffffffff;
5185 txbd->tx_bd_mss_nbytes = pkt_size;
5186 txbd->tx_bd_vlan_tag_flags = TX_BD_FLAGS_START | TX_BD_FLAGS_END;
5187
5188 num_pkts++;
Michael Chanbc5a0692006-01-23 16:13:22 -08005189 bp->tx_prod = NEXT_TX_BD(bp->tx_prod);
5190 bp->tx_prod_bseq += pkt_size;
Michael Chanb6016b72005-05-26 13:03:09 -07005191
Michael Chan234754d2006-11-19 14:11:41 -08005192 REG_WR16(bp, bp->tx_bidx_addr, bp->tx_prod);
5193 REG_WR(bp, bp->tx_bseq_addr, bp->tx_prod_bseq);
Michael Chanb6016b72005-05-26 13:03:09 -07005194
5195 udelay(100);
5196
Michael Chanbf5295b2006-03-23 01:11:56 -08005197 REG_WR(bp, BNX2_HC_COMMAND,
5198 bp->hc_cmd | BNX2_HC_COMMAND_COAL_NOW_WO_INT);
5199
Michael Chanb6016b72005-05-26 13:03:09 -07005200 REG_RD(bp, BNX2_HC_COMMAND);
5201
5202 udelay(5);
5203
5204 pci_unmap_single(bp->pdev, map, pkt_size, PCI_DMA_TODEVICE);
Michael Chan745720e2006-06-29 12:37:41 -07005205 dev_kfree_skb(skb);
Michael Chanb6016b72005-05-26 13:03:09 -07005206
Michael Chanc76c0472007-12-20 20:01:19 -08005207 if (bnx2_get_hw_tx_cons(tx_napi) != bp->tx_prod)
Michael Chanb6016b72005-05-26 13:03:09 -07005208 goto loopback_test_done;
Michael Chanb6016b72005-05-26 13:03:09 -07005209
Michael Chan35efa7c2007-12-20 19:56:37 -08005210 rx_idx = bnx2_get_hw_rx_cons(bnapi);
Michael Chanb6016b72005-05-26 13:03:09 -07005211 if (rx_idx != rx_start_idx + num_pkts) {
5212 goto loopback_test_done;
5213 }
5214
5215 rx_buf = &bp->rx_buf_ring[rx_start_idx];
5216 rx_skb = rx_buf->skb;
5217
5218 rx_hdr = (struct l2_fhdr *) rx_skb->data;
5219 skb_reserve(rx_skb, bp->rx_offset);
5220
5221 pci_dma_sync_single_for_cpu(bp->pdev,
5222 pci_unmap_addr(rx_buf, mapping),
5223 bp->rx_buf_size, PCI_DMA_FROMDEVICE);
5224
Michael Chanade2bfe2006-01-23 16:09:51 -08005225 if (rx_hdr->l2_fhdr_status &
Michael Chanb6016b72005-05-26 13:03:09 -07005226 (L2_FHDR_ERRORS_BAD_CRC |
5227 L2_FHDR_ERRORS_PHY_DECODE |
5228 L2_FHDR_ERRORS_ALIGNMENT |
5229 L2_FHDR_ERRORS_TOO_SHORT |
5230 L2_FHDR_ERRORS_GIANT_FRAME)) {
5231
5232 goto loopback_test_done;
5233 }
5234
5235 if ((rx_hdr->l2_fhdr_pkt_len - 4) != pkt_size) {
5236 goto loopback_test_done;
5237 }
5238
5239 for (i = 14; i < pkt_size; i++) {
5240 if (*(rx_skb->data + i) != (unsigned char) (i & 0xff)) {
5241 goto loopback_test_done;
5242 }
5243 }
5244
5245 ret = 0;
5246
5247loopback_test_done:
5248 bp->loopback = 0;
5249 return ret;
5250}
5251
Michael Chanbc5a0692006-01-23 16:13:22 -08005252#define BNX2_MAC_LOOPBACK_FAILED 1
5253#define BNX2_PHY_LOOPBACK_FAILED 2
5254#define BNX2_LOOPBACK_FAILED (BNX2_MAC_LOOPBACK_FAILED | \
5255 BNX2_PHY_LOOPBACK_FAILED)
5256
5257static int
5258bnx2_test_loopback(struct bnx2 *bp)
5259{
5260 int rc = 0;
5261
5262 if (!netif_running(bp->dev))
5263 return BNX2_LOOPBACK_FAILED;
5264
5265 bnx2_reset_nic(bp, BNX2_DRV_MSG_CODE_RESET);
5266 spin_lock_bh(&bp->phy_lock);
5267 bnx2_init_phy(bp);
5268 spin_unlock_bh(&bp->phy_lock);
5269 if (bnx2_run_loopback(bp, BNX2_MAC_LOOPBACK))
5270 rc |= BNX2_MAC_LOOPBACK_FAILED;
5271 if (bnx2_run_loopback(bp, BNX2_PHY_LOOPBACK))
5272 rc |= BNX2_PHY_LOOPBACK_FAILED;
5273 return rc;
5274}
5275
Michael Chanb6016b72005-05-26 13:03:09 -07005276#define NVRAM_SIZE 0x200
5277#define CRC32_RESIDUAL 0xdebb20e3
5278
5279static int
5280bnx2_test_nvram(struct bnx2 *bp)
5281{
Al Virob491edd2007-12-22 19:44:51 +00005282 __be32 buf[NVRAM_SIZE / 4];
Michael Chanb6016b72005-05-26 13:03:09 -07005283 u8 *data = (u8 *) buf;
5284 int rc = 0;
5285 u32 magic, csum;
5286
5287 if ((rc = bnx2_nvram_read(bp, 0, data, 4)) != 0)
5288 goto test_nvram_done;
5289
5290 magic = be32_to_cpu(buf[0]);
5291 if (magic != 0x669955aa) {
5292 rc = -ENODEV;
5293 goto test_nvram_done;
5294 }
5295
5296 if ((rc = bnx2_nvram_read(bp, 0x100, data, NVRAM_SIZE)) != 0)
5297 goto test_nvram_done;
5298
5299 csum = ether_crc_le(0x100, data);
5300 if (csum != CRC32_RESIDUAL) {
5301 rc = -ENODEV;
5302 goto test_nvram_done;
5303 }
5304
5305 csum = ether_crc_le(0x100, data + 0x100);
5306 if (csum != CRC32_RESIDUAL) {
5307 rc = -ENODEV;
5308 }
5309
5310test_nvram_done:
5311 return rc;
5312}
5313
5314static int
5315bnx2_test_link(struct bnx2 *bp)
5316{
5317 u32 bmsr;
5318
Michael Chan583c28e2008-01-21 19:51:35 -08005319 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP) {
Michael Chan489310a2007-10-10 16:16:31 -07005320 if (bp->link_up)
5321 return 0;
5322 return -ENODEV;
5323 }
Michael Chanc770a652005-08-25 15:38:39 -07005324 spin_lock_bh(&bp->phy_lock);
Michael Chan27a005b2007-05-03 13:23:41 -07005325 bnx2_enable_bmsr1(bp);
5326 bnx2_read_phy(bp, bp->mii_bmsr1, &bmsr);
5327 bnx2_read_phy(bp, bp->mii_bmsr1, &bmsr);
5328 bnx2_disable_bmsr1(bp);
Michael Chanc770a652005-08-25 15:38:39 -07005329 spin_unlock_bh(&bp->phy_lock);
Jeff Garzik6aa20a22006-09-13 13:24:59 -04005330
Michael Chanb6016b72005-05-26 13:03:09 -07005331 if (bmsr & BMSR_LSTATUS) {
5332 return 0;
5333 }
5334 return -ENODEV;
5335}
5336
5337static int
5338bnx2_test_intr(struct bnx2 *bp)
5339{
5340 int i;
Michael Chanb6016b72005-05-26 13:03:09 -07005341 u16 status_idx;
5342
5343 if (!netif_running(bp->dev))
5344 return -ENODEV;
5345
5346 status_idx = REG_RD(bp, BNX2_PCICFG_INT_ACK_CMD) & 0xffff;
5347
5348 /* This register is not touched during run-time. */
Michael Chanbf5295b2006-03-23 01:11:56 -08005349 REG_WR(bp, BNX2_HC_COMMAND, bp->hc_cmd | BNX2_HC_COMMAND_COAL_NOW);
Michael Chanb6016b72005-05-26 13:03:09 -07005350 REG_RD(bp, BNX2_HC_COMMAND);
5351
5352 for (i = 0; i < 10; i++) {
5353 if ((REG_RD(bp, BNX2_PCICFG_INT_ACK_CMD) & 0xffff) !=
5354 status_idx) {
5355
5356 break;
5357 }
5358
5359 msleep_interruptible(10);
5360 }
5361 if (i < 10)
5362 return 0;
5363
5364 return -ENODEV;
5365}
5366
Michael Chan38ea3682008-02-23 19:48:57 -08005367/* Determining link for parallel detection. */
Michael Chanb2fadea2008-01-21 17:07:06 -08005368static int
5369bnx2_5706_serdes_has_link(struct bnx2 *bp)
5370{
5371 u32 mode_ctl, an_dbg, exp;
5372
Michael Chan38ea3682008-02-23 19:48:57 -08005373 if (bp->phy_flags & BNX2_PHY_FLAG_NO_PARALLEL)
5374 return 0;
5375
Michael Chanb2fadea2008-01-21 17:07:06 -08005376 bnx2_write_phy(bp, MII_BNX2_MISC_SHADOW, MISC_SHDW_MODE_CTL);
5377 bnx2_read_phy(bp, MII_BNX2_MISC_SHADOW, &mode_ctl);
5378
5379 if (!(mode_ctl & MISC_SHDW_MODE_CTL_SIG_DET))
5380 return 0;
5381
5382 bnx2_write_phy(bp, MII_BNX2_MISC_SHADOW, MISC_SHDW_AN_DBG);
5383 bnx2_read_phy(bp, MII_BNX2_MISC_SHADOW, &an_dbg);
5384 bnx2_read_phy(bp, MII_BNX2_MISC_SHADOW, &an_dbg);
5385
Michael Chanf3014c02008-01-29 21:33:03 -08005386 if (an_dbg & (MISC_SHDW_AN_DBG_NOSYNC | MISC_SHDW_AN_DBG_RUDI_INVALID))
Michael Chanb2fadea2008-01-21 17:07:06 -08005387 return 0;
5388
5389 bnx2_write_phy(bp, MII_BNX2_DSP_ADDRESS, MII_EXPAND_REG1);
5390 bnx2_read_phy(bp, MII_BNX2_DSP_RW_PORT, &exp);
5391 bnx2_read_phy(bp, MII_BNX2_DSP_RW_PORT, &exp);
5392
5393 if (exp & MII_EXPAND_REG1_RUDI_C) /* receiving CONFIG */
5394 return 0;
5395
5396 return 1;
5397}
5398
Michael Chanb6016b72005-05-26 13:03:09 -07005399static void
Michael Chan48b01e22006-11-19 14:08:00 -08005400bnx2_5706_serdes_timer(struct bnx2 *bp)
5401{
Michael Chanb2fadea2008-01-21 17:07:06 -08005402 int check_link = 1;
5403
Michael Chan48b01e22006-11-19 14:08:00 -08005404 spin_lock(&bp->phy_lock);
Michael Chanb2fadea2008-01-21 17:07:06 -08005405 if (bp->serdes_an_pending) {
Michael Chan48b01e22006-11-19 14:08:00 -08005406 bp->serdes_an_pending--;
Michael Chanb2fadea2008-01-21 17:07:06 -08005407 check_link = 0;
5408 } else if ((bp->link_up == 0) && (bp->autoneg & AUTONEG_SPEED)) {
Michael Chan48b01e22006-11-19 14:08:00 -08005409 u32 bmcr;
5410
5411 bp->current_interval = bp->timer_interval;
5412
Michael Chanca58c3a2007-05-03 13:22:52 -07005413 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chan48b01e22006-11-19 14:08:00 -08005414
5415 if (bmcr & BMCR_ANENABLE) {
Michael Chanb2fadea2008-01-21 17:07:06 -08005416 if (bnx2_5706_serdes_has_link(bp)) {
Michael Chan48b01e22006-11-19 14:08:00 -08005417 bmcr &= ~BMCR_ANENABLE;
5418 bmcr |= BMCR_SPEED1000 | BMCR_FULLDPLX;
Michael Chanca58c3a2007-05-03 13:22:52 -07005419 bnx2_write_phy(bp, bp->mii_bmcr, bmcr);
Michael Chan583c28e2008-01-21 19:51:35 -08005420 bp->phy_flags |= BNX2_PHY_FLAG_PARALLEL_DETECT;
Michael Chan48b01e22006-11-19 14:08:00 -08005421 }
5422 }
5423 }
5424 else if ((bp->link_up) && (bp->autoneg & AUTONEG_SPEED) &&
Michael Chan583c28e2008-01-21 19:51:35 -08005425 (bp->phy_flags & BNX2_PHY_FLAG_PARALLEL_DETECT)) {
Michael Chan48b01e22006-11-19 14:08:00 -08005426 u32 phy2;
5427
5428 bnx2_write_phy(bp, 0x17, 0x0f01);
5429 bnx2_read_phy(bp, 0x15, &phy2);
5430 if (phy2 & 0x20) {
5431 u32 bmcr;
5432
Michael Chanca58c3a2007-05-03 13:22:52 -07005433 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chan48b01e22006-11-19 14:08:00 -08005434 bmcr |= BMCR_ANENABLE;
Michael Chanca58c3a2007-05-03 13:22:52 -07005435 bnx2_write_phy(bp, bp->mii_bmcr, bmcr);
Michael Chan48b01e22006-11-19 14:08:00 -08005436
Michael Chan583c28e2008-01-21 19:51:35 -08005437 bp->phy_flags &= ~BNX2_PHY_FLAG_PARALLEL_DETECT;
Michael Chan48b01e22006-11-19 14:08:00 -08005438 }
5439 } else
5440 bp->current_interval = bp->timer_interval;
5441
Michael Chana2724e22008-02-23 19:47:44 -08005442 if (check_link) {
Michael Chanb2fadea2008-01-21 17:07:06 -08005443 u32 val;
5444
5445 bnx2_write_phy(bp, MII_BNX2_MISC_SHADOW, MISC_SHDW_AN_DBG);
5446 bnx2_read_phy(bp, MII_BNX2_MISC_SHADOW, &val);
5447 bnx2_read_phy(bp, MII_BNX2_MISC_SHADOW, &val);
5448
Michael Chana2724e22008-02-23 19:47:44 -08005449 if (bp->link_up && (val & MISC_SHDW_AN_DBG_NOSYNC)) {
5450 if (!(bp->phy_flags & BNX2_PHY_FLAG_FORCED_DOWN)) {
5451 bnx2_5706s_force_link_dn(bp, 1);
5452 bp->phy_flags |= BNX2_PHY_FLAG_FORCED_DOWN;
5453 } else
5454 bnx2_set_link(bp);
5455 } else if (!bp->link_up && !(val & MISC_SHDW_AN_DBG_NOSYNC))
5456 bnx2_set_link(bp);
Michael Chanb2fadea2008-01-21 17:07:06 -08005457 }
Michael Chan48b01e22006-11-19 14:08:00 -08005458 spin_unlock(&bp->phy_lock);
5459}
5460
5461static void
Michael Chanf8dd0642006-11-19 14:08:29 -08005462bnx2_5708_serdes_timer(struct bnx2 *bp)
5463{
Michael Chan583c28e2008-01-21 19:51:35 -08005464 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
Michael Chan0d8a6572007-07-07 22:49:43 -07005465 return;
5466
Michael Chan583c28e2008-01-21 19:51:35 -08005467 if ((bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE) == 0) {
Michael Chanf8dd0642006-11-19 14:08:29 -08005468 bp->serdes_an_pending = 0;
5469 return;
5470 }
5471
5472 spin_lock(&bp->phy_lock);
5473 if (bp->serdes_an_pending)
5474 bp->serdes_an_pending--;
5475 else if ((bp->link_up == 0) && (bp->autoneg & AUTONEG_SPEED)) {
5476 u32 bmcr;
5477
Michael Chanca58c3a2007-05-03 13:22:52 -07005478 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chanf8dd0642006-11-19 14:08:29 -08005479 if (bmcr & BMCR_ANENABLE) {
Michael Chan605a9e22007-05-03 13:23:13 -07005480 bnx2_enable_forced_2g5(bp);
Michael Chanf8dd0642006-11-19 14:08:29 -08005481 bp->current_interval = SERDES_FORCED_TIMEOUT;
5482 } else {
Michael Chan605a9e22007-05-03 13:23:13 -07005483 bnx2_disable_forced_2g5(bp);
Michael Chanf8dd0642006-11-19 14:08:29 -08005484 bp->serdes_an_pending = 2;
5485 bp->current_interval = bp->timer_interval;
5486 }
5487
5488 } else
5489 bp->current_interval = bp->timer_interval;
5490
5491 spin_unlock(&bp->phy_lock);
5492}
5493
5494static void
Michael Chanb6016b72005-05-26 13:03:09 -07005495bnx2_timer(unsigned long data)
5496{
5497 struct bnx2 *bp = (struct bnx2 *) data;
Michael Chanb6016b72005-05-26 13:03:09 -07005498
Michael Chancd339a02005-08-25 15:35:24 -07005499 if (!netif_running(bp->dev))
5500 return;
5501
Michael Chanb6016b72005-05-26 13:03:09 -07005502 if (atomic_read(&bp->intr_sem) != 0)
5503 goto bnx2_restart_timer;
5504
Michael Chandf149d72007-07-07 22:51:36 -07005505 bnx2_send_heart_beat(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07005506
Michael Chan2726d6e2008-01-29 21:35:05 -08005507 bp->stats_blk->stat_FwRxDrop =
5508 bnx2_reg_rd_ind(bp, BNX2_FW_RX_DROP_COUNT);
Michael Chancea94db2006-06-12 22:16:13 -07005509
Michael Chan02537b062007-06-04 21:24:07 -07005510 /* workaround occasional corrupted counters */
5511 if (CHIP_NUM(bp) == CHIP_NUM_5708 && bp->stats_ticks)
5512 REG_WR(bp, BNX2_HC_COMMAND, bp->hc_cmd |
5513 BNX2_HC_COMMAND_STATS_NOW);
5514
Michael Chan583c28e2008-01-21 19:51:35 -08005515 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Michael Chanf8dd0642006-11-19 14:08:29 -08005516 if (CHIP_NUM(bp) == CHIP_NUM_5706)
5517 bnx2_5706_serdes_timer(bp);
Michael Chan27a005b2007-05-03 13:23:41 -07005518 else
Michael Chanf8dd0642006-11-19 14:08:29 -08005519 bnx2_5708_serdes_timer(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07005520 }
5521
5522bnx2_restart_timer:
Michael Chancd339a02005-08-25 15:35:24 -07005523 mod_timer(&bp->timer, jiffies + bp->current_interval);
Michael Chanb6016b72005-05-26 13:03:09 -07005524}
5525
Michael Chan8e6a72c2007-05-03 13:24:48 -07005526static int
5527bnx2_request_irq(struct bnx2 *bp)
5528{
5529 struct net_device *dev = bp->dev;
Michael Chan6d866ff2007-12-20 19:56:09 -08005530 unsigned long flags;
Michael Chanb4b36042007-12-20 19:59:30 -08005531 struct bnx2_irq *irq;
5532 int rc = 0, i;
Michael Chan8e6a72c2007-05-03 13:24:48 -07005533
David S. Millerf86e82f2008-01-21 17:15:40 -08005534 if (bp->flags & BNX2_FLAG_USING_MSI_OR_MSIX)
Michael Chan6d866ff2007-12-20 19:56:09 -08005535 flags = 0;
5536 else
5537 flags = IRQF_SHARED;
Michael Chanb4b36042007-12-20 19:59:30 -08005538
5539 for (i = 0; i < bp->irq_nvecs; i++) {
5540 irq = &bp->irq_tbl[i];
Michael Chanc76c0472007-12-20 20:01:19 -08005541 rc = request_irq(irq->vector, irq->handler, flags, irq->name,
Michael Chanb4b36042007-12-20 19:59:30 -08005542 dev);
5543 if (rc)
5544 break;
5545 irq->requested = 1;
5546 }
Michael Chan8e6a72c2007-05-03 13:24:48 -07005547 return rc;
5548}
5549
5550static void
5551bnx2_free_irq(struct bnx2 *bp)
5552{
5553 struct net_device *dev = bp->dev;
Michael Chanb4b36042007-12-20 19:59:30 -08005554 struct bnx2_irq *irq;
5555 int i;
Michael Chan8e6a72c2007-05-03 13:24:48 -07005556
Michael Chanb4b36042007-12-20 19:59:30 -08005557 for (i = 0; i < bp->irq_nvecs; i++) {
5558 irq = &bp->irq_tbl[i];
5559 if (irq->requested)
5560 free_irq(irq->vector, dev);
5561 irq->requested = 0;
Michael Chan6d866ff2007-12-20 19:56:09 -08005562 }
David S. Millerf86e82f2008-01-21 17:15:40 -08005563 if (bp->flags & BNX2_FLAG_USING_MSI)
Michael Chanb4b36042007-12-20 19:59:30 -08005564 pci_disable_msi(bp->pdev);
David S. Millerf86e82f2008-01-21 17:15:40 -08005565 else if (bp->flags & BNX2_FLAG_USING_MSIX)
Michael Chanb4b36042007-12-20 19:59:30 -08005566 pci_disable_msix(bp->pdev);
5567
David S. Millerf86e82f2008-01-21 17:15:40 -08005568 bp->flags &= ~(BNX2_FLAG_USING_MSI_OR_MSIX | BNX2_FLAG_ONE_SHOT_MSI);
Michael Chanb4b36042007-12-20 19:59:30 -08005569}
5570
5571static void
5572bnx2_enable_msix(struct bnx2 *bp)
5573{
Michael Chan57851d82007-12-20 20:01:44 -08005574 int i, rc;
5575 struct msix_entry msix_ent[BNX2_MAX_MSIX_VEC];
5576
Michael Chanb4b36042007-12-20 19:59:30 -08005577 bnx2_setup_msix_tbl(bp);
5578 REG_WR(bp, BNX2_PCI_MSIX_CONTROL, BNX2_MAX_MSIX_HW_VEC - 1);
5579 REG_WR(bp, BNX2_PCI_MSIX_TBL_OFF_BIR, BNX2_PCI_GRC_WINDOW2_BASE);
5580 REG_WR(bp, BNX2_PCI_MSIX_PBA_OFF_BIT, BNX2_PCI_GRC_WINDOW3_BASE);
Michael Chan57851d82007-12-20 20:01:44 -08005581
5582 for (i = 0; i < BNX2_MAX_MSIX_VEC; i++) {
5583 msix_ent[i].entry = i;
5584 msix_ent[i].vector = 0;
5585 }
5586
5587 rc = pci_enable_msix(bp->pdev, msix_ent, BNX2_MAX_MSIX_VEC);
5588 if (rc != 0)
5589 return;
5590
5591 bp->irq_tbl[BNX2_BASE_VEC].handler = bnx2_msi_1shot;
5592 bp->irq_tbl[BNX2_TX_VEC].handler = bnx2_tx_msix;
5593
5594 strcpy(bp->irq_tbl[BNX2_BASE_VEC].name, bp->dev->name);
5595 strcat(bp->irq_tbl[BNX2_BASE_VEC].name, "-base");
5596 strcpy(bp->irq_tbl[BNX2_TX_VEC].name, bp->dev->name);
5597 strcat(bp->irq_tbl[BNX2_TX_VEC].name, "-tx");
5598
5599 bp->irq_nvecs = BNX2_MAX_MSIX_VEC;
David S. Millerf86e82f2008-01-21 17:15:40 -08005600 bp->flags |= BNX2_FLAG_USING_MSIX | BNX2_FLAG_ONE_SHOT_MSI;
Michael Chan57851d82007-12-20 20:01:44 -08005601 for (i = 0; i < BNX2_MAX_MSIX_VEC; i++)
5602 bp->irq_tbl[i].vector = msix_ent[i].vector;
Michael Chan6d866ff2007-12-20 19:56:09 -08005603}
5604
5605static void
5606bnx2_setup_int_mode(struct bnx2 *bp, int dis_msi)
5607{
5608 bp->irq_tbl[0].handler = bnx2_interrupt;
5609 strcpy(bp->irq_tbl[0].name, bp->dev->name);
Michael Chanb4b36042007-12-20 19:59:30 -08005610 bp->irq_nvecs = 1;
5611 bp->irq_tbl[0].vector = bp->pdev->irq;
Michael Chan6d866ff2007-12-20 19:56:09 -08005612
David S. Millerf86e82f2008-01-21 17:15:40 -08005613 if ((bp->flags & BNX2_FLAG_MSIX_CAP) && !dis_msi)
Michael Chanb4b36042007-12-20 19:59:30 -08005614 bnx2_enable_msix(bp);
5615
David S. Millerf86e82f2008-01-21 17:15:40 -08005616 if ((bp->flags & BNX2_FLAG_MSI_CAP) && !dis_msi &&
5617 !(bp->flags & BNX2_FLAG_USING_MSIX)) {
Michael Chan6d866ff2007-12-20 19:56:09 -08005618 if (pci_enable_msi(bp->pdev) == 0) {
David S. Millerf86e82f2008-01-21 17:15:40 -08005619 bp->flags |= BNX2_FLAG_USING_MSI;
Michael Chan6d866ff2007-12-20 19:56:09 -08005620 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
David S. Millerf86e82f2008-01-21 17:15:40 -08005621 bp->flags |= BNX2_FLAG_ONE_SHOT_MSI;
Michael Chan6d866ff2007-12-20 19:56:09 -08005622 bp->irq_tbl[0].handler = bnx2_msi_1shot;
5623 } else
5624 bp->irq_tbl[0].handler = bnx2_msi;
Michael Chanb4b36042007-12-20 19:59:30 -08005625
5626 bp->irq_tbl[0].vector = bp->pdev->irq;
Michael Chan6d866ff2007-12-20 19:56:09 -08005627 }
5628 }
Michael Chan8e6a72c2007-05-03 13:24:48 -07005629}
5630
Michael Chanb6016b72005-05-26 13:03:09 -07005631/* Called with rtnl_lock */
5632static int
5633bnx2_open(struct net_device *dev)
5634{
Michael Chan972ec0d2006-01-23 16:12:43 -08005635 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07005636 int rc;
5637
Michael Chan1b2f9222007-05-03 13:20:19 -07005638 netif_carrier_off(dev);
5639
Pavel Machek829ca9a2005-09-03 15:56:56 -07005640 bnx2_set_power_state(bp, PCI_D0);
Michael Chanb6016b72005-05-26 13:03:09 -07005641 bnx2_disable_int(bp);
5642
5643 rc = bnx2_alloc_mem(bp);
5644 if (rc)
5645 return rc;
5646
Michael Chan6d866ff2007-12-20 19:56:09 -08005647 bnx2_setup_int_mode(bp, disable_msi);
Michael Chan35efa7c2007-12-20 19:56:37 -08005648 bnx2_napi_enable(bp);
Michael Chan8e6a72c2007-05-03 13:24:48 -07005649 rc = bnx2_request_irq(bp);
5650
Michael Chanb6016b72005-05-26 13:03:09 -07005651 if (rc) {
Michael Chan35efa7c2007-12-20 19:56:37 -08005652 bnx2_napi_disable(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07005653 bnx2_free_mem(bp);
5654 return rc;
5655 }
5656
5657 rc = bnx2_init_nic(bp);
5658
5659 if (rc) {
Michael Chan35efa7c2007-12-20 19:56:37 -08005660 bnx2_napi_disable(bp);
Michael Chan8e6a72c2007-05-03 13:24:48 -07005661 bnx2_free_irq(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07005662 bnx2_free_skbs(bp);
5663 bnx2_free_mem(bp);
5664 return rc;
5665 }
Jeff Garzik6aa20a22006-09-13 13:24:59 -04005666
Michael Chancd339a02005-08-25 15:35:24 -07005667 mod_timer(&bp->timer, jiffies + bp->current_interval);
Michael Chanb6016b72005-05-26 13:03:09 -07005668
5669 atomic_set(&bp->intr_sem, 0);
5670
5671 bnx2_enable_int(bp);
5672
David S. Millerf86e82f2008-01-21 17:15:40 -08005673 if (bp->flags & BNX2_FLAG_USING_MSI) {
Michael Chanb6016b72005-05-26 13:03:09 -07005674 /* Test MSI to make sure it is working
5675 * If MSI test fails, go back to INTx mode
5676 */
5677 if (bnx2_test_intr(bp) != 0) {
5678 printk(KERN_WARNING PFX "%s: No interrupt was generated"
5679 " using MSI, switching to INTx mode. Please"
5680 " report this failure to the PCI maintainer"
5681 " and include system chipset information.\n",
5682 bp->dev->name);
5683
5684 bnx2_disable_int(bp);
Michael Chan8e6a72c2007-05-03 13:24:48 -07005685 bnx2_free_irq(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07005686
Michael Chan6d866ff2007-12-20 19:56:09 -08005687 bnx2_setup_int_mode(bp, 1);
5688
Michael Chanb6016b72005-05-26 13:03:09 -07005689 rc = bnx2_init_nic(bp);
5690
Michael Chan8e6a72c2007-05-03 13:24:48 -07005691 if (!rc)
5692 rc = bnx2_request_irq(bp);
5693
Michael Chanb6016b72005-05-26 13:03:09 -07005694 if (rc) {
Michael Chan35efa7c2007-12-20 19:56:37 -08005695 bnx2_napi_disable(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07005696 bnx2_free_skbs(bp);
5697 bnx2_free_mem(bp);
5698 del_timer_sync(&bp->timer);
5699 return rc;
5700 }
5701 bnx2_enable_int(bp);
5702 }
5703 }
David S. Millerf86e82f2008-01-21 17:15:40 -08005704 if (bp->flags & BNX2_FLAG_USING_MSI)
Michael Chanb6016b72005-05-26 13:03:09 -07005705 printk(KERN_INFO PFX "%s: using MSI\n", dev->name);
David S. Millerf86e82f2008-01-21 17:15:40 -08005706 else if (bp->flags & BNX2_FLAG_USING_MSIX)
Michael Chan57851d82007-12-20 20:01:44 -08005707 printk(KERN_INFO PFX "%s: using MSIX\n", dev->name);
Michael Chanb6016b72005-05-26 13:03:09 -07005708
5709 netif_start_queue(dev);
5710
5711 return 0;
5712}
5713
5714static void
David Howellsc4028952006-11-22 14:57:56 +00005715bnx2_reset_task(struct work_struct *work)
Michael Chanb6016b72005-05-26 13:03:09 -07005716{
David Howellsc4028952006-11-22 14:57:56 +00005717 struct bnx2 *bp = container_of(work, struct bnx2, reset_task);
Michael Chanb6016b72005-05-26 13:03:09 -07005718
Michael Chanafdc08b2005-08-25 15:34:29 -07005719 if (!netif_running(bp->dev))
5720 return;
5721
5722 bp->in_reset_task = 1;
Michael Chanb6016b72005-05-26 13:03:09 -07005723 bnx2_netif_stop(bp);
5724
5725 bnx2_init_nic(bp);
5726
5727 atomic_set(&bp->intr_sem, 1);
5728 bnx2_netif_start(bp);
Michael Chanafdc08b2005-08-25 15:34:29 -07005729 bp->in_reset_task = 0;
Michael Chanb6016b72005-05-26 13:03:09 -07005730}
5731
5732static void
5733bnx2_tx_timeout(struct net_device *dev)
5734{
Michael Chan972ec0d2006-01-23 16:12:43 -08005735 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07005736
5737 /* This allows the netif to be shutdown gracefully before resetting */
5738 schedule_work(&bp->reset_task);
5739}
5740
5741#ifdef BCM_VLAN
5742/* Called with rtnl_lock */
5743static void
5744bnx2_vlan_rx_register(struct net_device *dev, struct vlan_group *vlgrp)
5745{
Michael Chan972ec0d2006-01-23 16:12:43 -08005746 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07005747
5748 bnx2_netif_stop(bp);
5749
5750 bp->vlgrp = vlgrp;
5751 bnx2_set_rx_mode(dev);
5752
5753 bnx2_netif_start(bp);
5754}
Michael Chanb6016b72005-05-26 13:03:09 -07005755#endif
5756
Herbert Xu932ff272006-06-09 12:20:56 -07005757/* Called with netif_tx_lock.
Michael Chan2f8af122006-08-15 01:39:10 -07005758 * bnx2_tx_int() runs without netif_tx_lock unless it needs to call
5759 * netif_wake_queue().
Michael Chanb6016b72005-05-26 13:03:09 -07005760 */
5761static int
5762bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev)
5763{
Michael Chan972ec0d2006-01-23 16:12:43 -08005764 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07005765 dma_addr_t mapping;
5766 struct tx_bd *txbd;
5767 struct sw_bd *tx_buf;
5768 u32 len, vlan_tag_flags, last_frag, mss;
5769 u16 prod, ring_prod;
5770 int i;
Michael Chan57851d82007-12-20 20:01:44 -08005771 struct bnx2_napi *bnapi = &bp->bnx2_napi[bp->tx_vec];
Michael Chanb6016b72005-05-26 13:03:09 -07005772
Michael Chana550c992007-12-20 19:56:59 -08005773 if (unlikely(bnx2_tx_avail(bp, bnapi) <
5774 (skb_shinfo(skb)->nr_frags + 1))) {
Michael Chanb6016b72005-05-26 13:03:09 -07005775 netif_stop_queue(dev);
5776 printk(KERN_ERR PFX "%s: BUG! Tx ring full when queue awake!\n",
5777 dev->name);
5778
5779 return NETDEV_TX_BUSY;
5780 }
5781 len = skb_headlen(skb);
5782 prod = bp->tx_prod;
5783 ring_prod = TX_RING_IDX(prod);
5784
5785 vlan_tag_flags = 0;
Patrick McHardy84fa7932006-08-29 16:44:56 -07005786 if (skb->ip_summed == CHECKSUM_PARTIAL) {
Michael Chanb6016b72005-05-26 13:03:09 -07005787 vlan_tag_flags |= TX_BD_FLAGS_TCP_UDP_CKSUM;
5788 }
5789
Al Viro79ea13c2008-01-24 02:06:46 -08005790 if (bp->vlgrp && vlan_tx_tag_present(skb)) {
Michael Chanb6016b72005-05-26 13:03:09 -07005791 vlan_tag_flags |=
5792 (TX_BD_FLAGS_VLAN_TAG | (vlan_tx_tag_get(skb) << 16));
5793 }
Michael Chanfde82052007-05-03 17:23:35 -07005794 if ((mss = skb_shinfo(skb)->gso_size)) {
Michael Chanb6016b72005-05-26 13:03:09 -07005795 u32 tcp_opt_len, ip_tcp_len;
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -07005796 struct iphdr *iph;
Michael Chanb6016b72005-05-26 13:03:09 -07005797
Michael Chanb6016b72005-05-26 13:03:09 -07005798 vlan_tag_flags |= TX_BD_FLAGS_SW_LSO;
5799
Michael Chan4666f872007-05-03 13:22:28 -07005800 tcp_opt_len = tcp_optlen(skb);
Arnaldo Carvalho de Meloab6a5bb2007-03-18 17:43:48 -07005801
Michael Chan4666f872007-05-03 13:22:28 -07005802 if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6) {
5803 u32 tcp_off = skb_transport_offset(skb) -
5804 sizeof(struct ipv6hdr) - ETH_HLEN;
Michael Chanb6016b72005-05-26 13:03:09 -07005805
Michael Chan4666f872007-05-03 13:22:28 -07005806 vlan_tag_flags |= ((tcp_opt_len >> 2) << 8) |
5807 TX_BD_FLAGS_SW_FLAGS;
5808 if (likely(tcp_off == 0))
5809 vlan_tag_flags &= ~TX_BD_FLAGS_TCP6_OFF0_MSK;
5810 else {
5811 tcp_off >>= 3;
5812 vlan_tag_flags |= ((tcp_off & 0x3) <<
5813 TX_BD_FLAGS_TCP6_OFF0_SHL) |
5814 ((tcp_off & 0x10) <<
5815 TX_BD_FLAGS_TCP6_OFF4_SHL);
5816 mss |= (tcp_off & 0xc) << TX_BD_TCP6_OFF2_SHL;
5817 }
5818 } else {
5819 if (skb_header_cloned(skb) &&
5820 pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) {
5821 dev_kfree_skb(skb);
5822 return NETDEV_TX_OK;
5823 }
5824
5825 ip_tcp_len = ip_hdrlen(skb) + sizeof(struct tcphdr);
5826
5827 iph = ip_hdr(skb);
5828 iph->check = 0;
5829 iph->tot_len = htons(mss + ip_tcp_len + tcp_opt_len);
5830 tcp_hdr(skb)->check = ~csum_tcpudp_magic(iph->saddr,
5831 iph->daddr, 0,
5832 IPPROTO_TCP,
5833 0);
5834 if (tcp_opt_len || (iph->ihl > 5)) {
5835 vlan_tag_flags |= ((iph->ihl - 5) +
5836 (tcp_opt_len >> 2)) << 8;
5837 }
Michael Chanb6016b72005-05-26 13:03:09 -07005838 }
Michael Chan4666f872007-05-03 13:22:28 -07005839 } else
Michael Chanb6016b72005-05-26 13:03:09 -07005840 mss = 0;
Michael Chanb6016b72005-05-26 13:03:09 -07005841
5842 mapping = pci_map_single(bp->pdev, skb->data, len, PCI_DMA_TODEVICE);
Jeff Garzik6aa20a22006-09-13 13:24:59 -04005843
Michael Chanb6016b72005-05-26 13:03:09 -07005844 tx_buf = &bp->tx_buf_ring[ring_prod];
5845 tx_buf->skb = skb;
5846 pci_unmap_addr_set(tx_buf, mapping, mapping);
5847
5848 txbd = &bp->tx_desc_ring[ring_prod];
5849
5850 txbd->tx_bd_haddr_hi = (u64) mapping >> 32;
5851 txbd->tx_bd_haddr_lo = (u64) mapping & 0xffffffff;
5852 txbd->tx_bd_mss_nbytes = len | (mss << 16);
5853 txbd->tx_bd_vlan_tag_flags = vlan_tag_flags | TX_BD_FLAGS_START;
5854
5855 last_frag = skb_shinfo(skb)->nr_frags;
5856
5857 for (i = 0; i < last_frag; i++) {
5858 skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
5859
5860 prod = NEXT_TX_BD(prod);
5861 ring_prod = TX_RING_IDX(prod);
5862 txbd = &bp->tx_desc_ring[ring_prod];
5863
5864 len = frag->size;
5865 mapping = pci_map_page(bp->pdev, frag->page, frag->page_offset,
5866 len, PCI_DMA_TODEVICE);
5867 pci_unmap_addr_set(&bp->tx_buf_ring[ring_prod],
5868 mapping, mapping);
5869
5870 txbd->tx_bd_haddr_hi = (u64) mapping >> 32;
5871 txbd->tx_bd_haddr_lo = (u64) mapping & 0xffffffff;
5872 txbd->tx_bd_mss_nbytes = len | (mss << 16);
5873 txbd->tx_bd_vlan_tag_flags = vlan_tag_flags;
5874
5875 }
5876 txbd->tx_bd_vlan_tag_flags |= TX_BD_FLAGS_END;
5877
5878 prod = NEXT_TX_BD(prod);
5879 bp->tx_prod_bseq += skb->len;
5880
Michael Chan234754d2006-11-19 14:11:41 -08005881 REG_WR16(bp, bp->tx_bidx_addr, prod);
5882 REG_WR(bp, bp->tx_bseq_addr, bp->tx_prod_bseq);
Michael Chanb6016b72005-05-26 13:03:09 -07005883
5884 mmiowb();
5885
5886 bp->tx_prod = prod;
5887 dev->trans_start = jiffies;
5888
Michael Chana550c992007-12-20 19:56:59 -08005889 if (unlikely(bnx2_tx_avail(bp, bnapi) <= MAX_SKB_FRAGS)) {
Michael Chane89bbf12005-08-25 15:36:58 -07005890 netif_stop_queue(dev);
Michael Chana550c992007-12-20 19:56:59 -08005891 if (bnx2_tx_avail(bp, bnapi) > bp->tx_wake_thresh)
Michael Chane89bbf12005-08-25 15:36:58 -07005892 netif_wake_queue(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07005893 }
5894
5895 return NETDEV_TX_OK;
5896}
5897
5898/* Called with rtnl_lock */
5899static int
5900bnx2_close(struct net_device *dev)
5901{
Michael Chan972ec0d2006-01-23 16:12:43 -08005902 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07005903 u32 reset_code;
5904
Michael Chanafdc08b2005-08-25 15:34:29 -07005905 /* Calling flush_scheduled_work() may deadlock because
5906 * linkwatch_event() may be on the workqueue and it will try to get
5907 * the rtnl_lock which we are holding.
5908 */
5909 while (bp->in_reset_task)
5910 msleep(1);
5911
Stephen Hemmingerbea33482007-10-03 16:41:36 -07005912 bnx2_disable_int_sync(bp);
Michael Chan35efa7c2007-12-20 19:56:37 -08005913 bnx2_napi_disable(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07005914 del_timer_sync(&bp->timer);
David S. Millerf86e82f2008-01-21 17:15:40 -08005915 if (bp->flags & BNX2_FLAG_NO_WOL)
Michael Chan6c4f0952006-06-29 12:38:15 -07005916 reset_code = BNX2_DRV_MSG_CODE_UNLOAD_LNK_DN;
Michael Chandda1e392006-01-23 16:08:14 -08005917 else if (bp->wol)
Michael Chanb6016b72005-05-26 13:03:09 -07005918 reset_code = BNX2_DRV_MSG_CODE_SUSPEND_WOL;
5919 else
5920 reset_code = BNX2_DRV_MSG_CODE_SUSPEND_NO_WOL;
5921 bnx2_reset_chip(bp, reset_code);
Michael Chan8e6a72c2007-05-03 13:24:48 -07005922 bnx2_free_irq(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07005923 bnx2_free_skbs(bp);
5924 bnx2_free_mem(bp);
5925 bp->link_up = 0;
5926 netif_carrier_off(bp->dev);
Pavel Machek829ca9a2005-09-03 15:56:56 -07005927 bnx2_set_power_state(bp, PCI_D3hot);
Michael Chanb6016b72005-05-26 13:03:09 -07005928 return 0;
5929}
5930
5931#define GET_NET_STATS64(ctr) \
5932 (unsigned long) ((unsigned long) (ctr##_hi) << 32) + \
5933 (unsigned long) (ctr##_lo)
5934
5935#define GET_NET_STATS32(ctr) \
5936 (ctr##_lo)
5937
5938#if (BITS_PER_LONG == 64)
5939#define GET_NET_STATS GET_NET_STATS64
5940#else
5941#define GET_NET_STATS GET_NET_STATS32
5942#endif
5943
5944static struct net_device_stats *
5945bnx2_get_stats(struct net_device *dev)
5946{
Michael Chan972ec0d2006-01-23 16:12:43 -08005947 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07005948 struct statistics_block *stats_blk = bp->stats_blk;
5949 struct net_device_stats *net_stats = &bp->net_stats;
5950
5951 if (bp->stats_blk == NULL) {
5952 return net_stats;
5953 }
5954 net_stats->rx_packets =
5955 GET_NET_STATS(stats_blk->stat_IfHCInUcastPkts) +
5956 GET_NET_STATS(stats_blk->stat_IfHCInMulticastPkts) +
5957 GET_NET_STATS(stats_blk->stat_IfHCInBroadcastPkts);
5958
5959 net_stats->tx_packets =
5960 GET_NET_STATS(stats_blk->stat_IfHCOutUcastPkts) +
5961 GET_NET_STATS(stats_blk->stat_IfHCOutMulticastPkts) +
5962 GET_NET_STATS(stats_blk->stat_IfHCOutBroadcastPkts);
5963
5964 net_stats->rx_bytes =
5965 GET_NET_STATS(stats_blk->stat_IfHCInOctets);
5966
5967 net_stats->tx_bytes =
5968 GET_NET_STATS(stats_blk->stat_IfHCOutOctets);
5969
Jeff Garzik6aa20a22006-09-13 13:24:59 -04005970 net_stats->multicast =
Michael Chanb6016b72005-05-26 13:03:09 -07005971 GET_NET_STATS(stats_blk->stat_IfHCOutMulticastPkts);
5972
Jeff Garzik6aa20a22006-09-13 13:24:59 -04005973 net_stats->collisions =
Michael Chanb6016b72005-05-26 13:03:09 -07005974 (unsigned long) stats_blk->stat_EtherStatsCollisions;
5975
Jeff Garzik6aa20a22006-09-13 13:24:59 -04005976 net_stats->rx_length_errors =
Michael Chanb6016b72005-05-26 13:03:09 -07005977 (unsigned long) (stats_blk->stat_EtherStatsUndersizePkts +
5978 stats_blk->stat_EtherStatsOverrsizePkts);
5979
Jeff Garzik6aa20a22006-09-13 13:24:59 -04005980 net_stats->rx_over_errors =
Michael Chanb6016b72005-05-26 13:03:09 -07005981 (unsigned long) stats_blk->stat_IfInMBUFDiscards;
5982
Jeff Garzik6aa20a22006-09-13 13:24:59 -04005983 net_stats->rx_frame_errors =
Michael Chanb6016b72005-05-26 13:03:09 -07005984 (unsigned long) stats_blk->stat_Dot3StatsAlignmentErrors;
5985
Jeff Garzik6aa20a22006-09-13 13:24:59 -04005986 net_stats->rx_crc_errors =
Michael Chanb6016b72005-05-26 13:03:09 -07005987 (unsigned long) stats_blk->stat_Dot3StatsFCSErrors;
5988
5989 net_stats->rx_errors = net_stats->rx_length_errors +
5990 net_stats->rx_over_errors + net_stats->rx_frame_errors +
5991 net_stats->rx_crc_errors;
5992
5993 net_stats->tx_aborted_errors =
5994 (unsigned long) (stats_blk->stat_Dot3StatsExcessiveCollisions +
5995 stats_blk->stat_Dot3StatsLateCollisions);
5996
Michael Chan5b0c76a2005-11-04 08:45:49 -08005997 if ((CHIP_NUM(bp) == CHIP_NUM_5706) ||
5998 (CHIP_ID(bp) == CHIP_ID_5708_A0))
Michael Chanb6016b72005-05-26 13:03:09 -07005999 net_stats->tx_carrier_errors = 0;
6000 else {
6001 net_stats->tx_carrier_errors =
6002 (unsigned long)
6003 stats_blk->stat_Dot3StatsCarrierSenseErrors;
6004 }
6005
6006 net_stats->tx_errors =
Jeff Garzik6aa20a22006-09-13 13:24:59 -04006007 (unsigned long)
Michael Chanb6016b72005-05-26 13:03:09 -07006008 stats_blk->stat_emac_tx_stat_dot3statsinternalmactransmiterrors
6009 +
6010 net_stats->tx_aborted_errors +
6011 net_stats->tx_carrier_errors;
6012
Michael Chancea94db2006-06-12 22:16:13 -07006013 net_stats->rx_missed_errors =
6014 (unsigned long) (stats_blk->stat_IfInMBUFDiscards +
6015 stats_blk->stat_FwRxDrop);
6016
Michael Chanb6016b72005-05-26 13:03:09 -07006017 return net_stats;
6018}
6019
6020/* All ethtool functions called with rtnl_lock */
6021
6022static int
6023bnx2_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
6024{
Michael Chan972ec0d2006-01-23 16:12:43 -08006025 struct bnx2 *bp = netdev_priv(dev);
Michael Chan7b6b8342007-07-07 22:50:15 -07006026 int support_serdes = 0, support_copper = 0;
Michael Chanb6016b72005-05-26 13:03:09 -07006027
6028 cmd->supported = SUPPORTED_Autoneg;
Michael Chan583c28e2008-01-21 19:51:35 -08006029 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP) {
Michael Chan7b6b8342007-07-07 22:50:15 -07006030 support_serdes = 1;
6031 support_copper = 1;
6032 } else if (bp->phy_port == PORT_FIBRE)
6033 support_serdes = 1;
6034 else
6035 support_copper = 1;
6036
6037 if (support_serdes) {
Michael Chanb6016b72005-05-26 13:03:09 -07006038 cmd->supported |= SUPPORTED_1000baseT_Full |
6039 SUPPORTED_FIBRE;
Michael Chan583c28e2008-01-21 19:51:35 -08006040 if (bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE)
Michael Chan605a9e22007-05-03 13:23:13 -07006041 cmd->supported |= SUPPORTED_2500baseX_Full;
Michael Chanb6016b72005-05-26 13:03:09 -07006042
Michael Chanb6016b72005-05-26 13:03:09 -07006043 }
Michael Chan7b6b8342007-07-07 22:50:15 -07006044 if (support_copper) {
Michael Chanb6016b72005-05-26 13:03:09 -07006045 cmd->supported |= SUPPORTED_10baseT_Half |
6046 SUPPORTED_10baseT_Full |
6047 SUPPORTED_100baseT_Half |
6048 SUPPORTED_100baseT_Full |
6049 SUPPORTED_1000baseT_Full |
6050 SUPPORTED_TP;
6051
Michael Chanb6016b72005-05-26 13:03:09 -07006052 }
6053
Michael Chan7b6b8342007-07-07 22:50:15 -07006054 spin_lock_bh(&bp->phy_lock);
6055 cmd->port = bp->phy_port;
Michael Chanb6016b72005-05-26 13:03:09 -07006056 cmd->advertising = bp->advertising;
6057
6058 if (bp->autoneg & AUTONEG_SPEED) {
6059 cmd->autoneg = AUTONEG_ENABLE;
6060 }
6061 else {
6062 cmd->autoneg = AUTONEG_DISABLE;
6063 }
6064
6065 if (netif_carrier_ok(dev)) {
6066 cmd->speed = bp->line_speed;
6067 cmd->duplex = bp->duplex;
6068 }
6069 else {
6070 cmd->speed = -1;
6071 cmd->duplex = -1;
6072 }
Michael Chan7b6b8342007-07-07 22:50:15 -07006073 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07006074
6075 cmd->transceiver = XCVR_INTERNAL;
6076 cmd->phy_address = bp->phy_addr;
6077
6078 return 0;
6079}
Jeff Garzik6aa20a22006-09-13 13:24:59 -04006080
Michael Chanb6016b72005-05-26 13:03:09 -07006081static int
6082bnx2_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
6083{
Michael Chan972ec0d2006-01-23 16:12:43 -08006084 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006085 u8 autoneg = bp->autoneg;
6086 u8 req_duplex = bp->req_duplex;
6087 u16 req_line_speed = bp->req_line_speed;
6088 u32 advertising = bp->advertising;
Michael Chan7b6b8342007-07-07 22:50:15 -07006089 int err = -EINVAL;
6090
6091 spin_lock_bh(&bp->phy_lock);
6092
6093 if (cmd->port != PORT_TP && cmd->port != PORT_FIBRE)
6094 goto err_out_unlock;
6095
Michael Chan583c28e2008-01-21 19:51:35 -08006096 if (cmd->port != bp->phy_port &&
6097 !(bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP))
Michael Chan7b6b8342007-07-07 22:50:15 -07006098 goto err_out_unlock;
Michael Chanb6016b72005-05-26 13:03:09 -07006099
6100 if (cmd->autoneg == AUTONEG_ENABLE) {
6101 autoneg |= AUTONEG_SPEED;
6102
Jeff Garzik6aa20a22006-09-13 13:24:59 -04006103 cmd->advertising &= ETHTOOL_ALL_COPPER_SPEED;
Michael Chanb6016b72005-05-26 13:03:09 -07006104
6105 /* allow advertising 1 speed */
6106 if ((cmd->advertising == ADVERTISED_10baseT_Half) ||
6107 (cmd->advertising == ADVERTISED_10baseT_Full) ||
6108 (cmd->advertising == ADVERTISED_100baseT_Half) ||
6109 (cmd->advertising == ADVERTISED_100baseT_Full)) {
6110
Michael Chan7b6b8342007-07-07 22:50:15 -07006111 if (cmd->port == PORT_FIBRE)
6112 goto err_out_unlock;
Michael Chanb6016b72005-05-26 13:03:09 -07006113
6114 advertising = cmd->advertising;
6115
Michael Chan27a005b2007-05-03 13:23:41 -07006116 } else if (cmd->advertising == ADVERTISED_2500baseX_Full) {
Michael Chan583c28e2008-01-21 19:51:35 -08006117 if (!(bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE) ||
Michael Chan7b6b8342007-07-07 22:50:15 -07006118 (cmd->port == PORT_TP))
6119 goto err_out_unlock;
6120 } else if (cmd->advertising == ADVERTISED_1000baseT_Full)
Michael Chanb6016b72005-05-26 13:03:09 -07006121 advertising = cmd->advertising;
Michael Chan7b6b8342007-07-07 22:50:15 -07006122 else if (cmd->advertising == ADVERTISED_1000baseT_Half)
6123 goto err_out_unlock;
Michael Chanb6016b72005-05-26 13:03:09 -07006124 else {
Michael Chan7b6b8342007-07-07 22:50:15 -07006125 if (cmd->port == PORT_FIBRE)
Michael Chanb6016b72005-05-26 13:03:09 -07006126 advertising = ETHTOOL_ALL_FIBRE_SPEED;
Michael Chan7b6b8342007-07-07 22:50:15 -07006127 else
Michael Chanb6016b72005-05-26 13:03:09 -07006128 advertising = ETHTOOL_ALL_COPPER_SPEED;
Michael Chanb6016b72005-05-26 13:03:09 -07006129 }
6130 advertising |= ADVERTISED_Autoneg;
6131 }
6132 else {
Michael Chan7b6b8342007-07-07 22:50:15 -07006133 if (cmd->port == PORT_FIBRE) {
Michael Chan80be4432006-11-19 14:07:28 -08006134 if ((cmd->speed != SPEED_1000 &&
6135 cmd->speed != SPEED_2500) ||
6136 (cmd->duplex != DUPLEX_FULL))
Michael Chan7b6b8342007-07-07 22:50:15 -07006137 goto err_out_unlock;
Michael Chan80be4432006-11-19 14:07:28 -08006138
6139 if (cmd->speed == SPEED_2500 &&
Michael Chan583c28e2008-01-21 19:51:35 -08006140 !(bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE))
Michael Chan7b6b8342007-07-07 22:50:15 -07006141 goto err_out_unlock;
Michael Chanb6016b72005-05-26 13:03:09 -07006142 }
Michael Chan7b6b8342007-07-07 22:50:15 -07006143 else if (cmd->speed == SPEED_1000 || cmd->speed == SPEED_2500)
6144 goto err_out_unlock;
6145
Michael Chanb6016b72005-05-26 13:03:09 -07006146 autoneg &= ~AUTONEG_SPEED;
6147 req_line_speed = cmd->speed;
6148 req_duplex = cmd->duplex;
6149 advertising = 0;
6150 }
6151
6152 bp->autoneg = autoneg;
6153 bp->advertising = advertising;
6154 bp->req_line_speed = req_line_speed;
6155 bp->req_duplex = req_duplex;
6156
Michael Chan7b6b8342007-07-07 22:50:15 -07006157 err = bnx2_setup_phy(bp, cmd->port);
Michael Chanb6016b72005-05-26 13:03:09 -07006158
Michael Chan7b6b8342007-07-07 22:50:15 -07006159err_out_unlock:
Michael Chanc770a652005-08-25 15:38:39 -07006160 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07006161
Michael Chan7b6b8342007-07-07 22:50:15 -07006162 return err;
Michael Chanb6016b72005-05-26 13:03:09 -07006163}
6164
6165static void
6166bnx2_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
6167{
Michael Chan972ec0d2006-01-23 16:12:43 -08006168 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006169
6170 strcpy(info->driver, DRV_MODULE_NAME);
6171 strcpy(info->version, DRV_MODULE_VERSION);
6172 strcpy(info->bus_info, pci_name(bp->pdev));
Michael Chan58fc2ea2007-07-07 22:52:02 -07006173 strcpy(info->fw_version, bp->fw_version);
Michael Chanb6016b72005-05-26 13:03:09 -07006174}
6175
Michael Chan244ac4f2006-03-20 17:48:46 -08006176#define BNX2_REGDUMP_LEN (32 * 1024)
6177
6178static int
6179bnx2_get_regs_len(struct net_device *dev)
6180{
6181 return BNX2_REGDUMP_LEN;
6182}
6183
6184static void
6185bnx2_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *_p)
6186{
6187 u32 *p = _p, i, offset;
6188 u8 *orig_p = _p;
6189 struct bnx2 *bp = netdev_priv(dev);
6190 u32 reg_boundaries[] = { 0x0000, 0x0098, 0x0400, 0x045c,
6191 0x0800, 0x0880, 0x0c00, 0x0c10,
6192 0x0c30, 0x0d08, 0x1000, 0x101c,
6193 0x1040, 0x1048, 0x1080, 0x10a4,
6194 0x1400, 0x1490, 0x1498, 0x14f0,
6195 0x1500, 0x155c, 0x1580, 0x15dc,
6196 0x1600, 0x1658, 0x1680, 0x16d8,
6197 0x1800, 0x1820, 0x1840, 0x1854,
6198 0x1880, 0x1894, 0x1900, 0x1984,
6199 0x1c00, 0x1c0c, 0x1c40, 0x1c54,
6200 0x1c80, 0x1c94, 0x1d00, 0x1d84,
6201 0x2000, 0x2030, 0x23c0, 0x2400,
6202 0x2800, 0x2820, 0x2830, 0x2850,
6203 0x2b40, 0x2c10, 0x2fc0, 0x3058,
6204 0x3c00, 0x3c94, 0x4000, 0x4010,
6205 0x4080, 0x4090, 0x43c0, 0x4458,
6206 0x4c00, 0x4c18, 0x4c40, 0x4c54,
6207 0x4fc0, 0x5010, 0x53c0, 0x5444,
6208 0x5c00, 0x5c18, 0x5c80, 0x5c90,
6209 0x5fc0, 0x6000, 0x6400, 0x6428,
6210 0x6800, 0x6848, 0x684c, 0x6860,
6211 0x6888, 0x6910, 0x8000 };
6212
6213 regs->version = 0;
6214
6215 memset(p, 0, BNX2_REGDUMP_LEN);
6216
6217 if (!netif_running(bp->dev))
6218 return;
6219
6220 i = 0;
6221 offset = reg_boundaries[0];
6222 p += offset;
6223 while (offset < BNX2_REGDUMP_LEN) {
6224 *p++ = REG_RD(bp, offset);
6225 offset += 4;
6226 if (offset == reg_boundaries[i + 1]) {
6227 offset = reg_boundaries[i + 2];
6228 p = (u32 *) (orig_p + offset);
6229 i += 2;
6230 }
6231 }
6232}
6233
Michael Chanb6016b72005-05-26 13:03:09 -07006234static void
6235bnx2_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
6236{
Michael Chan972ec0d2006-01-23 16:12:43 -08006237 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006238
David S. Millerf86e82f2008-01-21 17:15:40 -08006239 if (bp->flags & BNX2_FLAG_NO_WOL) {
Michael Chanb6016b72005-05-26 13:03:09 -07006240 wol->supported = 0;
6241 wol->wolopts = 0;
6242 }
6243 else {
6244 wol->supported = WAKE_MAGIC;
6245 if (bp->wol)
6246 wol->wolopts = WAKE_MAGIC;
6247 else
6248 wol->wolopts = 0;
6249 }
6250 memset(&wol->sopass, 0, sizeof(wol->sopass));
6251}
6252
6253static int
6254bnx2_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
6255{
Michael Chan972ec0d2006-01-23 16:12:43 -08006256 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006257
6258 if (wol->wolopts & ~WAKE_MAGIC)
6259 return -EINVAL;
6260
6261 if (wol->wolopts & WAKE_MAGIC) {
David S. Millerf86e82f2008-01-21 17:15:40 -08006262 if (bp->flags & BNX2_FLAG_NO_WOL)
Michael Chanb6016b72005-05-26 13:03:09 -07006263 return -EINVAL;
6264
6265 bp->wol = 1;
6266 }
6267 else {
6268 bp->wol = 0;
6269 }
6270 return 0;
6271}
6272
6273static int
6274bnx2_nway_reset(struct net_device *dev)
6275{
Michael Chan972ec0d2006-01-23 16:12:43 -08006276 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006277 u32 bmcr;
6278
6279 if (!(bp->autoneg & AUTONEG_SPEED)) {
6280 return -EINVAL;
6281 }
6282
Michael Chanc770a652005-08-25 15:38:39 -07006283 spin_lock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07006284
Michael Chan583c28e2008-01-21 19:51:35 -08006285 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP) {
Michael Chan7b6b8342007-07-07 22:50:15 -07006286 int rc;
6287
6288 rc = bnx2_setup_remote_phy(bp, bp->phy_port);
6289 spin_unlock_bh(&bp->phy_lock);
6290 return rc;
6291 }
6292
Michael Chanb6016b72005-05-26 13:03:09 -07006293 /* Force a link down visible on the other side */
Michael Chan583c28e2008-01-21 19:51:35 -08006294 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Michael Chanca58c3a2007-05-03 13:22:52 -07006295 bnx2_write_phy(bp, bp->mii_bmcr, BMCR_LOOPBACK);
Michael Chanc770a652005-08-25 15:38:39 -07006296 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07006297
6298 msleep(20);
6299
Michael Chanc770a652005-08-25 15:38:39 -07006300 spin_lock_bh(&bp->phy_lock);
Michael Chanf8dd0642006-11-19 14:08:29 -08006301
6302 bp->current_interval = SERDES_AN_TIMEOUT;
6303 bp->serdes_an_pending = 1;
6304 mod_timer(&bp->timer, jiffies + bp->current_interval);
Michael Chanb6016b72005-05-26 13:03:09 -07006305 }
6306
Michael Chanca58c3a2007-05-03 13:22:52 -07006307 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chanb6016b72005-05-26 13:03:09 -07006308 bmcr &= ~BMCR_LOOPBACK;
Michael Chanca58c3a2007-05-03 13:22:52 -07006309 bnx2_write_phy(bp, bp->mii_bmcr, bmcr | BMCR_ANRESTART | BMCR_ANENABLE);
Michael Chanb6016b72005-05-26 13:03:09 -07006310
Michael Chanc770a652005-08-25 15:38:39 -07006311 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07006312
6313 return 0;
6314}
6315
6316static int
6317bnx2_get_eeprom_len(struct net_device *dev)
6318{
Michael Chan972ec0d2006-01-23 16:12:43 -08006319 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006320
Michael Chan1122db72006-01-23 16:11:42 -08006321 if (bp->flash_info == NULL)
Michael Chanb6016b72005-05-26 13:03:09 -07006322 return 0;
6323
Michael Chan1122db72006-01-23 16:11:42 -08006324 return (int) bp->flash_size;
Michael Chanb6016b72005-05-26 13:03:09 -07006325}
6326
6327static int
6328bnx2_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
6329 u8 *eebuf)
6330{
Michael Chan972ec0d2006-01-23 16:12:43 -08006331 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006332 int rc;
6333
John W. Linville1064e942005-11-10 12:58:24 -08006334 /* parameters already validated in ethtool_get_eeprom */
Michael Chanb6016b72005-05-26 13:03:09 -07006335
6336 rc = bnx2_nvram_read(bp, eeprom->offset, eebuf, eeprom->len);
6337
6338 return rc;
6339}
6340
6341static int
6342bnx2_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
6343 u8 *eebuf)
6344{
Michael Chan972ec0d2006-01-23 16:12:43 -08006345 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006346 int rc;
6347
John W. Linville1064e942005-11-10 12:58:24 -08006348 /* parameters already validated in ethtool_set_eeprom */
Michael Chanb6016b72005-05-26 13:03:09 -07006349
6350 rc = bnx2_nvram_write(bp, eeprom->offset, eebuf, eeprom->len);
6351
6352 return rc;
6353}
6354
6355static int
6356bnx2_get_coalesce(struct net_device *dev, struct ethtool_coalesce *coal)
6357{
Michael Chan972ec0d2006-01-23 16:12:43 -08006358 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006359
6360 memset(coal, 0, sizeof(struct ethtool_coalesce));
6361
6362 coal->rx_coalesce_usecs = bp->rx_ticks;
6363 coal->rx_max_coalesced_frames = bp->rx_quick_cons_trip;
6364 coal->rx_coalesce_usecs_irq = bp->rx_ticks_int;
6365 coal->rx_max_coalesced_frames_irq = bp->rx_quick_cons_trip_int;
6366
6367 coal->tx_coalesce_usecs = bp->tx_ticks;
6368 coal->tx_max_coalesced_frames = bp->tx_quick_cons_trip;
6369 coal->tx_coalesce_usecs_irq = bp->tx_ticks_int;
6370 coal->tx_max_coalesced_frames_irq = bp->tx_quick_cons_trip_int;
6371
6372 coal->stats_block_coalesce_usecs = bp->stats_ticks;
6373
6374 return 0;
6375}
6376
6377static int
6378bnx2_set_coalesce(struct net_device *dev, struct ethtool_coalesce *coal)
6379{
Michael Chan972ec0d2006-01-23 16:12:43 -08006380 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006381
6382 bp->rx_ticks = (u16) coal->rx_coalesce_usecs;
6383 if (bp->rx_ticks > 0x3ff) bp->rx_ticks = 0x3ff;
6384
Jeff Garzik6aa20a22006-09-13 13:24:59 -04006385 bp->rx_quick_cons_trip = (u16) coal->rx_max_coalesced_frames;
Michael Chanb6016b72005-05-26 13:03:09 -07006386 if (bp->rx_quick_cons_trip > 0xff) bp->rx_quick_cons_trip = 0xff;
6387
6388 bp->rx_ticks_int = (u16) coal->rx_coalesce_usecs_irq;
6389 if (bp->rx_ticks_int > 0x3ff) bp->rx_ticks_int = 0x3ff;
6390
6391 bp->rx_quick_cons_trip_int = (u16) coal->rx_max_coalesced_frames_irq;
6392 if (bp->rx_quick_cons_trip_int > 0xff)
6393 bp->rx_quick_cons_trip_int = 0xff;
6394
6395 bp->tx_ticks = (u16) coal->tx_coalesce_usecs;
6396 if (bp->tx_ticks > 0x3ff) bp->tx_ticks = 0x3ff;
6397
6398 bp->tx_quick_cons_trip = (u16) coal->tx_max_coalesced_frames;
6399 if (bp->tx_quick_cons_trip > 0xff) bp->tx_quick_cons_trip = 0xff;
6400
6401 bp->tx_ticks_int = (u16) coal->tx_coalesce_usecs_irq;
6402 if (bp->tx_ticks_int > 0x3ff) bp->tx_ticks_int = 0x3ff;
6403
6404 bp->tx_quick_cons_trip_int = (u16) coal->tx_max_coalesced_frames_irq;
6405 if (bp->tx_quick_cons_trip_int > 0xff) bp->tx_quick_cons_trip_int =
6406 0xff;
6407
6408 bp->stats_ticks = coal->stats_block_coalesce_usecs;
Michael Chan02537b062007-06-04 21:24:07 -07006409 if (CHIP_NUM(bp) == CHIP_NUM_5708) {
6410 if (bp->stats_ticks != 0 && bp->stats_ticks != USEC_PER_SEC)
6411 bp->stats_ticks = USEC_PER_SEC;
6412 }
Michael Chan7ea69202007-07-16 18:27:10 -07006413 if (bp->stats_ticks > BNX2_HC_STATS_TICKS_HC_STAT_TICKS)
6414 bp->stats_ticks = BNX2_HC_STATS_TICKS_HC_STAT_TICKS;
6415 bp->stats_ticks &= BNX2_HC_STATS_TICKS_HC_STAT_TICKS;
Michael Chanb6016b72005-05-26 13:03:09 -07006416
6417 if (netif_running(bp->dev)) {
6418 bnx2_netif_stop(bp);
6419 bnx2_init_nic(bp);
6420 bnx2_netif_start(bp);
6421 }
6422
6423 return 0;
6424}
6425
6426static void
6427bnx2_get_ringparam(struct net_device *dev, struct ethtool_ringparam *ering)
6428{
Michael Chan972ec0d2006-01-23 16:12:43 -08006429 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006430
Michael Chan13daffa2006-03-20 17:49:20 -08006431 ering->rx_max_pending = MAX_TOTAL_RX_DESC_CNT;
Michael Chanb6016b72005-05-26 13:03:09 -07006432 ering->rx_mini_max_pending = 0;
Michael Chan47bf4242007-12-12 11:19:12 -08006433 ering->rx_jumbo_max_pending = MAX_TOTAL_RX_PG_DESC_CNT;
Michael Chanb6016b72005-05-26 13:03:09 -07006434
6435 ering->rx_pending = bp->rx_ring_size;
6436 ering->rx_mini_pending = 0;
Michael Chan47bf4242007-12-12 11:19:12 -08006437 ering->rx_jumbo_pending = bp->rx_pg_ring_size;
Michael Chanb6016b72005-05-26 13:03:09 -07006438
6439 ering->tx_max_pending = MAX_TX_DESC_CNT;
6440 ering->tx_pending = bp->tx_ring_size;
6441}
6442
6443static int
Michael Chan5d5d0012007-12-12 11:17:43 -08006444bnx2_change_ring_size(struct bnx2 *bp, u32 rx, u32 tx)
Michael Chanb6016b72005-05-26 13:03:09 -07006445{
Michael Chan13daffa2006-03-20 17:49:20 -08006446 if (netif_running(bp->dev)) {
6447 bnx2_netif_stop(bp);
6448 bnx2_reset_chip(bp, BNX2_DRV_MSG_CODE_RESET);
6449 bnx2_free_skbs(bp);
6450 bnx2_free_mem(bp);
6451 }
6452
Michael Chan5d5d0012007-12-12 11:17:43 -08006453 bnx2_set_rx_ring_size(bp, rx);
6454 bp->tx_ring_size = tx;
Michael Chanb6016b72005-05-26 13:03:09 -07006455
6456 if (netif_running(bp->dev)) {
Michael Chan13daffa2006-03-20 17:49:20 -08006457 int rc;
6458
6459 rc = bnx2_alloc_mem(bp);
6460 if (rc)
6461 return rc;
Michael Chanb6016b72005-05-26 13:03:09 -07006462 bnx2_init_nic(bp);
6463 bnx2_netif_start(bp);
6464 }
Michael Chanb6016b72005-05-26 13:03:09 -07006465 return 0;
6466}
6467
Michael Chan5d5d0012007-12-12 11:17:43 -08006468static int
6469bnx2_set_ringparam(struct net_device *dev, struct ethtool_ringparam *ering)
6470{
6471 struct bnx2 *bp = netdev_priv(dev);
6472 int rc;
6473
6474 if ((ering->rx_pending > MAX_TOTAL_RX_DESC_CNT) ||
6475 (ering->tx_pending > MAX_TX_DESC_CNT) ||
6476 (ering->tx_pending <= MAX_SKB_FRAGS)) {
6477
6478 return -EINVAL;
6479 }
6480 rc = bnx2_change_ring_size(bp, ering->rx_pending, ering->tx_pending);
6481 return rc;
6482}
6483
Michael Chanb6016b72005-05-26 13:03:09 -07006484static void
6485bnx2_get_pauseparam(struct net_device *dev, struct ethtool_pauseparam *epause)
6486{
Michael Chan972ec0d2006-01-23 16:12:43 -08006487 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006488
6489 epause->autoneg = ((bp->autoneg & AUTONEG_FLOW_CTRL) != 0);
6490 epause->rx_pause = ((bp->flow_ctrl & FLOW_CTRL_RX) != 0);
6491 epause->tx_pause = ((bp->flow_ctrl & FLOW_CTRL_TX) != 0);
6492}
6493
6494static int
6495bnx2_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam *epause)
6496{
Michael Chan972ec0d2006-01-23 16:12:43 -08006497 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006498
6499 bp->req_flow_ctrl = 0;
6500 if (epause->rx_pause)
6501 bp->req_flow_ctrl |= FLOW_CTRL_RX;
6502 if (epause->tx_pause)
6503 bp->req_flow_ctrl |= FLOW_CTRL_TX;
6504
6505 if (epause->autoneg) {
6506 bp->autoneg |= AUTONEG_FLOW_CTRL;
6507 }
6508 else {
6509 bp->autoneg &= ~AUTONEG_FLOW_CTRL;
6510 }
6511
Michael Chanc770a652005-08-25 15:38:39 -07006512 spin_lock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07006513
Michael Chan0d8a6572007-07-07 22:49:43 -07006514 bnx2_setup_phy(bp, bp->phy_port);
Michael Chanb6016b72005-05-26 13:03:09 -07006515
Michael Chanc770a652005-08-25 15:38:39 -07006516 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07006517
6518 return 0;
6519}
6520
6521static u32
6522bnx2_get_rx_csum(struct net_device *dev)
6523{
Michael Chan972ec0d2006-01-23 16:12:43 -08006524 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006525
6526 return bp->rx_csum;
6527}
6528
6529static int
6530bnx2_set_rx_csum(struct net_device *dev, u32 data)
6531{
Michael Chan972ec0d2006-01-23 16:12:43 -08006532 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006533
6534 bp->rx_csum = data;
6535 return 0;
6536}
6537
Michael Chanb11d6212006-06-29 12:31:21 -07006538static int
6539bnx2_set_tso(struct net_device *dev, u32 data)
6540{
Michael Chan4666f872007-05-03 13:22:28 -07006541 struct bnx2 *bp = netdev_priv(dev);
6542
6543 if (data) {
Michael Chanb11d6212006-06-29 12:31:21 -07006544 dev->features |= NETIF_F_TSO | NETIF_F_TSO_ECN;
Michael Chan4666f872007-05-03 13:22:28 -07006545 if (CHIP_NUM(bp) == CHIP_NUM_5709)
6546 dev->features |= NETIF_F_TSO6;
6547 } else
6548 dev->features &= ~(NETIF_F_TSO | NETIF_F_TSO6 |
6549 NETIF_F_TSO_ECN);
Michael Chanb11d6212006-06-29 12:31:21 -07006550 return 0;
6551}
6552
Michael Chancea94db2006-06-12 22:16:13 -07006553#define BNX2_NUM_STATS 46
Michael Chanb6016b72005-05-26 13:03:09 -07006554
Peter Hagervall14ab9b82005-08-10 14:18:16 -07006555static struct {
Michael Chanb6016b72005-05-26 13:03:09 -07006556 char string[ETH_GSTRING_LEN];
6557} bnx2_stats_str_arr[BNX2_NUM_STATS] = {
6558 { "rx_bytes" },
6559 { "rx_error_bytes" },
6560 { "tx_bytes" },
6561 { "tx_error_bytes" },
6562 { "rx_ucast_packets" },
6563 { "rx_mcast_packets" },
6564 { "rx_bcast_packets" },
6565 { "tx_ucast_packets" },
6566 { "tx_mcast_packets" },
6567 { "tx_bcast_packets" },
6568 { "tx_mac_errors" },
6569 { "tx_carrier_errors" },
6570 { "rx_crc_errors" },
6571 { "rx_align_errors" },
6572 { "tx_single_collisions" },
6573 { "tx_multi_collisions" },
6574 { "tx_deferred" },
6575 { "tx_excess_collisions" },
6576 { "tx_late_collisions" },
6577 { "tx_total_collisions" },
6578 { "rx_fragments" },
6579 { "rx_jabbers" },
6580 { "rx_undersize_packets" },
6581 { "rx_oversize_packets" },
6582 { "rx_64_byte_packets" },
6583 { "rx_65_to_127_byte_packets" },
6584 { "rx_128_to_255_byte_packets" },
6585 { "rx_256_to_511_byte_packets" },
6586 { "rx_512_to_1023_byte_packets" },
6587 { "rx_1024_to_1522_byte_packets" },
6588 { "rx_1523_to_9022_byte_packets" },
6589 { "tx_64_byte_packets" },
6590 { "tx_65_to_127_byte_packets" },
6591 { "tx_128_to_255_byte_packets" },
6592 { "tx_256_to_511_byte_packets" },
6593 { "tx_512_to_1023_byte_packets" },
6594 { "tx_1024_to_1522_byte_packets" },
6595 { "tx_1523_to_9022_byte_packets" },
6596 { "rx_xon_frames" },
6597 { "rx_xoff_frames" },
6598 { "tx_xon_frames" },
6599 { "tx_xoff_frames" },
6600 { "rx_mac_ctrl_frames" },
6601 { "rx_filtered_packets" },
6602 { "rx_discards" },
Michael Chancea94db2006-06-12 22:16:13 -07006603 { "rx_fw_discards" },
Michael Chanb6016b72005-05-26 13:03:09 -07006604};
6605
6606#define STATS_OFFSET32(offset_name) (offsetof(struct statistics_block, offset_name) / 4)
6607
Arjan van de Venf71e1302006-03-03 21:33:57 -05006608static const unsigned long bnx2_stats_offset_arr[BNX2_NUM_STATS] = {
Michael Chanb6016b72005-05-26 13:03:09 -07006609 STATS_OFFSET32(stat_IfHCInOctets_hi),
6610 STATS_OFFSET32(stat_IfHCInBadOctets_hi),
6611 STATS_OFFSET32(stat_IfHCOutOctets_hi),
6612 STATS_OFFSET32(stat_IfHCOutBadOctets_hi),
6613 STATS_OFFSET32(stat_IfHCInUcastPkts_hi),
6614 STATS_OFFSET32(stat_IfHCInMulticastPkts_hi),
6615 STATS_OFFSET32(stat_IfHCInBroadcastPkts_hi),
6616 STATS_OFFSET32(stat_IfHCOutUcastPkts_hi),
6617 STATS_OFFSET32(stat_IfHCOutMulticastPkts_hi),
6618 STATS_OFFSET32(stat_IfHCOutBroadcastPkts_hi),
6619 STATS_OFFSET32(stat_emac_tx_stat_dot3statsinternalmactransmiterrors),
Jeff Garzik6aa20a22006-09-13 13:24:59 -04006620 STATS_OFFSET32(stat_Dot3StatsCarrierSenseErrors),
6621 STATS_OFFSET32(stat_Dot3StatsFCSErrors),
6622 STATS_OFFSET32(stat_Dot3StatsAlignmentErrors),
6623 STATS_OFFSET32(stat_Dot3StatsSingleCollisionFrames),
6624 STATS_OFFSET32(stat_Dot3StatsMultipleCollisionFrames),
6625 STATS_OFFSET32(stat_Dot3StatsDeferredTransmissions),
6626 STATS_OFFSET32(stat_Dot3StatsExcessiveCollisions),
6627 STATS_OFFSET32(stat_Dot3StatsLateCollisions),
6628 STATS_OFFSET32(stat_EtherStatsCollisions),
6629 STATS_OFFSET32(stat_EtherStatsFragments),
6630 STATS_OFFSET32(stat_EtherStatsJabbers),
6631 STATS_OFFSET32(stat_EtherStatsUndersizePkts),
6632 STATS_OFFSET32(stat_EtherStatsOverrsizePkts),
6633 STATS_OFFSET32(stat_EtherStatsPktsRx64Octets),
6634 STATS_OFFSET32(stat_EtherStatsPktsRx65Octetsto127Octets),
6635 STATS_OFFSET32(stat_EtherStatsPktsRx128Octetsto255Octets),
6636 STATS_OFFSET32(stat_EtherStatsPktsRx256Octetsto511Octets),
6637 STATS_OFFSET32(stat_EtherStatsPktsRx512Octetsto1023Octets),
6638 STATS_OFFSET32(stat_EtherStatsPktsRx1024Octetsto1522Octets),
6639 STATS_OFFSET32(stat_EtherStatsPktsRx1523Octetsto9022Octets),
6640 STATS_OFFSET32(stat_EtherStatsPktsTx64Octets),
6641 STATS_OFFSET32(stat_EtherStatsPktsTx65Octetsto127Octets),
6642 STATS_OFFSET32(stat_EtherStatsPktsTx128Octetsto255Octets),
6643 STATS_OFFSET32(stat_EtherStatsPktsTx256Octetsto511Octets),
6644 STATS_OFFSET32(stat_EtherStatsPktsTx512Octetsto1023Octets),
6645 STATS_OFFSET32(stat_EtherStatsPktsTx1024Octetsto1522Octets),
6646 STATS_OFFSET32(stat_EtherStatsPktsTx1523Octetsto9022Octets),
6647 STATS_OFFSET32(stat_XonPauseFramesReceived),
6648 STATS_OFFSET32(stat_XoffPauseFramesReceived),
6649 STATS_OFFSET32(stat_OutXonSent),
6650 STATS_OFFSET32(stat_OutXoffSent),
6651 STATS_OFFSET32(stat_MacControlFramesReceived),
6652 STATS_OFFSET32(stat_IfInFramesL2FilterDiscards),
6653 STATS_OFFSET32(stat_IfInMBUFDiscards),
Michael Chancea94db2006-06-12 22:16:13 -07006654 STATS_OFFSET32(stat_FwRxDrop),
Michael Chanb6016b72005-05-26 13:03:09 -07006655};
6656
6657/* stat_IfHCInBadOctets and stat_Dot3StatsCarrierSenseErrors are
6658 * skipped because of errata.
Jeff Garzik6aa20a22006-09-13 13:24:59 -04006659 */
Peter Hagervall14ab9b82005-08-10 14:18:16 -07006660static u8 bnx2_5706_stats_len_arr[BNX2_NUM_STATS] = {
Michael Chanb6016b72005-05-26 13:03:09 -07006661 8,0,8,8,8,8,8,8,8,8,
6662 4,0,4,4,4,4,4,4,4,4,
6663 4,4,4,4,4,4,4,4,4,4,
6664 4,4,4,4,4,4,4,4,4,4,
Michael Chancea94db2006-06-12 22:16:13 -07006665 4,4,4,4,4,4,
Michael Chanb6016b72005-05-26 13:03:09 -07006666};
6667
Michael Chan5b0c76a2005-11-04 08:45:49 -08006668static u8 bnx2_5708_stats_len_arr[BNX2_NUM_STATS] = {
6669 8,0,8,8,8,8,8,8,8,8,
6670 4,4,4,4,4,4,4,4,4,4,
6671 4,4,4,4,4,4,4,4,4,4,
6672 4,4,4,4,4,4,4,4,4,4,
Michael Chancea94db2006-06-12 22:16:13 -07006673 4,4,4,4,4,4,
Michael Chan5b0c76a2005-11-04 08:45:49 -08006674};
6675
Michael Chanb6016b72005-05-26 13:03:09 -07006676#define BNX2_NUM_TESTS 6
6677
Peter Hagervall14ab9b82005-08-10 14:18:16 -07006678static struct {
Michael Chanb6016b72005-05-26 13:03:09 -07006679 char string[ETH_GSTRING_LEN];
6680} bnx2_tests_str_arr[BNX2_NUM_TESTS] = {
6681 { "register_test (offline)" },
6682 { "memory_test (offline)" },
6683 { "loopback_test (offline)" },
6684 { "nvram_test (online)" },
6685 { "interrupt_test (online)" },
6686 { "link_test (online)" },
6687};
6688
6689static int
Jeff Garzikb9f2c042007-10-03 18:07:32 -07006690bnx2_get_sset_count(struct net_device *dev, int sset)
Michael Chanb6016b72005-05-26 13:03:09 -07006691{
Jeff Garzikb9f2c042007-10-03 18:07:32 -07006692 switch (sset) {
6693 case ETH_SS_TEST:
6694 return BNX2_NUM_TESTS;
6695 case ETH_SS_STATS:
6696 return BNX2_NUM_STATS;
6697 default:
6698 return -EOPNOTSUPP;
6699 }
Michael Chanb6016b72005-05-26 13:03:09 -07006700}
6701
6702static void
6703bnx2_self_test(struct net_device *dev, struct ethtool_test *etest, u64 *buf)
6704{
Michael Chan972ec0d2006-01-23 16:12:43 -08006705 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006706
6707 memset(buf, 0, sizeof(u64) * BNX2_NUM_TESTS);
6708 if (etest->flags & ETH_TEST_FL_OFFLINE) {
Michael Chan80be4432006-11-19 14:07:28 -08006709 int i;
6710
Michael Chanb6016b72005-05-26 13:03:09 -07006711 bnx2_netif_stop(bp);
6712 bnx2_reset_chip(bp, BNX2_DRV_MSG_CODE_DIAG);
6713 bnx2_free_skbs(bp);
6714
6715 if (bnx2_test_registers(bp) != 0) {
6716 buf[0] = 1;
6717 etest->flags |= ETH_TEST_FL_FAILED;
6718 }
6719 if (bnx2_test_memory(bp) != 0) {
6720 buf[1] = 1;
6721 etest->flags |= ETH_TEST_FL_FAILED;
6722 }
Michael Chanbc5a0692006-01-23 16:13:22 -08006723 if ((buf[2] = bnx2_test_loopback(bp)) != 0)
Michael Chanb6016b72005-05-26 13:03:09 -07006724 etest->flags |= ETH_TEST_FL_FAILED;
Michael Chanb6016b72005-05-26 13:03:09 -07006725
6726 if (!netif_running(bp->dev)) {
6727 bnx2_reset_chip(bp, BNX2_DRV_MSG_CODE_RESET);
6728 }
6729 else {
6730 bnx2_init_nic(bp);
6731 bnx2_netif_start(bp);
6732 }
6733
6734 /* wait for link up */
Michael Chan80be4432006-11-19 14:07:28 -08006735 for (i = 0; i < 7; i++) {
6736 if (bp->link_up)
6737 break;
6738 msleep_interruptible(1000);
6739 }
Michael Chanb6016b72005-05-26 13:03:09 -07006740 }
6741
6742 if (bnx2_test_nvram(bp) != 0) {
6743 buf[3] = 1;
6744 etest->flags |= ETH_TEST_FL_FAILED;
6745 }
6746 if (bnx2_test_intr(bp) != 0) {
6747 buf[4] = 1;
6748 etest->flags |= ETH_TEST_FL_FAILED;
6749 }
6750
6751 if (bnx2_test_link(bp) != 0) {
6752 buf[5] = 1;
6753 etest->flags |= ETH_TEST_FL_FAILED;
6754
6755 }
6756}
6757
6758static void
6759bnx2_get_strings(struct net_device *dev, u32 stringset, u8 *buf)
6760{
6761 switch (stringset) {
6762 case ETH_SS_STATS:
6763 memcpy(buf, bnx2_stats_str_arr,
6764 sizeof(bnx2_stats_str_arr));
6765 break;
6766 case ETH_SS_TEST:
6767 memcpy(buf, bnx2_tests_str_arr,
6768 sizeof(bnx2_tests_str_arr));
6769 break;
6770 }
6771}
6772
Michael Chanb6016b72005-05-26 13:03:09 -07006773static void
6774bnx2_get_ethtool_stats(struct net_device *dev,
6775 struct ethtool_stats *stats, u64 *buf)
6776{
Michael Chan972ec0d2006-01-23 16:12:43 -08006777 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006778 int i;
6779 u32 *hw_stats = (u32 *) bp->stats_blk;
Peter Hagervall14ab9b82005-08-10 14:18:16 -07006780 u8 *stats_len_arr = NULL;
Michael Chanb6016b72005-05-26 13:03:09 -07006781
6782 if (hw_stats == NULL) {
6783 memset(buf, 0, sizeof(u64) * BNX2_NUM_STATS);
6784 return;
6785 }
6786
Michael Chan5b0c76a2005-11-04 08:45:49 -08006787 if ((CHIP_ID(bp) == CHIP_ID_5706_A0) ||
6788 (CHIP_ID(bp) == CHIP_ID_5706_A1) ||
6789 (CHIP_ID(bp) == CHIP_ID_5706_A2) ||
6790 (CHIP_ID(bp) == CHIP_ID_5708_A0))
Michael Chanb6016b72005-05-26 13:03:09 -07006791 stats_len_arr = bnx2_5706_stats_len_arr;
Michael Chan5b0c76a2005-11-04 08:45:49 -08006792 else
6793 stats_len_arr = bnx2_5708_stats_len_arr;
Michael Chanb6016b72005-05-26 13:03:09 -07006794
6795 for (i = 0; i < BNX2_NUM_STATS; i++) {
6796 if (stats_len_arr[i] == 0) {
6797 /* skip this counter */
6798 buf[i] = 0;
6799 continue;
6800 }
6801 if (stats_len_arr[i] == 4) {
6802 /* 4-byte counter */
6803 buf[i] = (u64)
6804 *(hw_stats + bnx2_stats_offset_arr[i]);
6805 continue;
6806 }
6807 /* 8-byte counter */
6808 buf[i] = (((u64) *(hw_stats +
6809 bnx2_stats_offset_arr[i])) << 32) +
6810 *(hw_stats + bnx2_stats_offset_arr[i] + 1);
6811 }
6812}
6813
6814static int
6815bnx2_phys_id(struct net_device *dev, u32 data)
6816{
Michael Chan972ec0d2006-01-23 16:12:43 -08006817 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006818 int i;
6819 u32 save;
6820
6821 if (data == 0)
6822 data = 2;
6823
6824 save = REG_RD(bp, BNX2_MISC_CFG);
6825 REG_WR(bp, BNX2_MISC_CFG, BNX2_MISC_CFG_LEDMODE_MAC);
6826
6827 for (i = 0; i < (data * 2); i++) {
6828 if ((i % 2) == 0) {
6829 REG_WR(bp, BNX2_EMAC_LED, BNX2_EMAC_LED_OVERRIDE);
6830 }
6831 else {
6832 REG_WR(bp, BNX2_EMAC_LED, BNX2_EMAC_LED_OVERRIDE |
6833 BNX2_EMAC_LED_1000MB_OVERRIDE |
6834 BNX2_EMAC_LED_100MB_OVERRIDE |
6835 BNX2_EMAC_LED_10MB_OVERRIDE |
6836 BNX2_EMAC_LED_TRAFFIC_OVERRIDE |
6837 BNX2_EMAC_LED_TRAFFIC);
6838 }
6839 msleep_interruptible(500);
6840 if (signal_pending(current))
6841 break;
6842 }
6843 REG_WR(bp, BNX2_EMAC_LED, 0);
6844 REG_WR(bp, BNX2_MISC_CFG, save);
6845 return 0;
6846}
6847
Michael Chan4666f872007-05-03 13:22:28 -07006848static int
6849bnx2_set_tx_csum(struct net_device *dev, u32 data)
6850{
6851 struct bnx2 *bp = netdev_priv(dev);
6852
6853 if (CHIP_NUM(bp) == CHIP_NUM_5709)
Michael Chan6460d942007-07-14 19:07:52 -07006854 return (ethtool_op_set_tx_ipv6_csum(dev, data));
Michael Chan4666f872007-05-03 13:22:28 -07006855 else
6856 return (ethtool_op_set_tx_csum(dev, data));
6857}
6858
Jeff Garzik7282d492006-09-13 14:30:00 -04006859static const struct ethtool_ops bnx2_ethtool_ops = {
Michael Chanb6016b72005-05-26 13:03:09 -07006860 .get_settings = bnx2_get_settings,
6861 .set_settings = bnx2_set_settings,
6862 .get_drvinfo = bnx2_get_drvinfo,
Michael Chan244ac4f2006-03-20 17:48:46 -08006863 .get_regs_len = bnx2_get_regs_len,
6864 .get_regs = bnx2_get_regs,
Michael Chanb6016b72005-05-26 13:03:09 -07006865 .get_wol = bnx2_get_wol,
6866 .set_wol = bnx2_set_wol,
6867 .nway_reset = bnx2_nway_reset,
6868 .get_link = ethtool_op_get_link,
6869 .get_eeprom_len = bnx2_get_eeprom_len,
6870 .get_eeprom = bnx2_get_eeprom,
6871 .set_eeprom = bnx2_set_eeprom,
6872 .get_coalesce = bnx2_get_coalesce,
6873 .set_coalesce = bnx2_set_coalesce,
6874 .get_ringparam = bnx2_get_ringparam,
6875 .set_ringparam = bnx2_set_ringparam,
6876 .get_pauseparam = bnx2_get_pauseparam,
6877 .set_pauseparam = bnx2_set_pauseparam,
6878 .get_rx_csum = bnx2_get_rx_csum,
6879 .set_rx_csum = bnx2_set_rx_csum,
Michael Chan4666f872007-05-03 13:22:28 -07006880 .set_tx_csum = bnx2_set_tx_csum,
Michael Chanb6016b72005-05-26 13:03:09 -07006881 .set_sg = ethtool_op_set_sg,
Michael Chanb11d6212006-06-29 12:31:21 -07006882 .set_tso = bnx2_set_tso,
Michael Chanb6016b72005-05-26 13:03:09 -07006883 .self_test = bnx2_self_test,
6884 .get_strings = bnx2_get_strings,
6885 .phys_id = bnx2_phys_id,
Michael Chanb6016b72005-05-26 13:03:09 -07006886 .get_ethtool_stats = bnx2_get_ethtool_stats,
Jeff Garzikb9f2c042007-10-03 18:07:32 -07006887 .get_sset_count = bnx2_get_sset_count,
Michael Chanb6016b72005-05-26 13:03:09 -07006888};
6889
6890/* Called with rtnl_lock */
6891static int
6892bnx2_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
6893{
Peter Hagervall14ab9b82005-08-10 14:18:16 -07006894 struct mii_ioctl_data *data = if_mii(ifr);
Michael Chan972ec0d2006-01-23 16:12:43 -08006895 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006896 int err;
6897
6898 switch(cmd) {
6899 case SIOCGMIIPHY:
6900 data->phy_id = bp->phy_addr;
6901
6902 /* fallthru */
6903 case SIOCGMIIREG: {
6904 u32 mii_regval;
6905
Michael Chan583c28e2008-01-21 19:51:35 -08006906 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
Michael Chan7b6b8342007-07-07 22:50:15 -07006907 return -EOPNOTSUPP;
6908
Michael Chandad3e452007-05-03 13:18:03 -07006909 if (!netif_running(dev))
6910 return -EAGAIN;
6911
Michael Chanc770a652005-08-25 15:38:39 -07006912 spin_lock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07006913 err = bnx2_read_phy(bp, data->reg_num & 0x1f, &mii_regval);
Michael Chanc770a652005-08-25 15:38:39 -07006914 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07006915
6916 data->val_out = mii_regval;
6917
6918 return err;
6919 }
6920
6921 case SIOCSMIIREG:
6922 if (!capable(CAP_NET_ADMIN))
6923 return -EPERM;
6924
Michael Chan583c28e2008-01-21 19:51:35 -08006925 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
Michael Chan7b6b8342007-07-07 22:50:15 -07006926 return -EOPNOTSUPP;
6927
Michael Chandad3e452007-05-03 13:18:03 -07006928 if (!netif_running(dev))
6929 return -EAGAIN;
6930
Michael Chanc770a652005-08-25 15:38:39 -07006931 spin_lock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07006932 err = bnx2_write_phy(bp, data->reg_num & 0x1f, data->val_in);
Michael Chanc770a652005-08-25 15:38:39 -07006933 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07006934
6935 return err;
6936
6937 default:
6938 /* do nothing */
6939 break;
6940 }
6941 return -EOPNOTSUPP;
6942}
6943
6944/* Called with rtnl_lock */
6945static int
6946bnx2_change_mac_addr(struct net_device *dev, void *p)
6947{
6948 struct sockaddr *addr = p;
Michael Chan972ec0d2006-01-23 16:12:43 -08006949 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006950
Michael Chan73eef4c2005-08-25 15:39:15 -07006951 if (!is_valid_ether_addr(addr->sa_data))
6952 return -EINVAL;
6953
Michael Chanb6016b72005-05-26 13:03:09 -07006954 memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
6955 if (netif_running(dev))
6956 bnx2_set_mac_addr(bp);
6957
6958 return 0;
6959}
6960
6961/* Called with rtnl_lock */
6962static int
6963bnx2_change_mtu(struct net_device *dev, int new_mtu)
6964{
Michael Chan972ec0d2006-01-23 16:12:43 -08006965 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006966
6967 if (((new_mtu + ETH_HLEN) > MAX_ETHERNET_JUMBO_PACKET_SIZE) ||
6968 ((new_mtu + ETH_HLEN) < MIN_ETHERNET_PACKET_SIZE))
6969 return -EINVAL;
6970
6971 dev->mtu = new_mtu;
Michael Chan5d5d0012007-12-12 11:17:43 -08006972 return (bnx2_change_ring_size(bp, bp->rx_ring_size, bp->tx_ring_size));
Michael Chanb6016b72005-05-26 13:03:09 -07006973}
6974
6975#if defined(HAVE_POLL_CONTROLLER) || defined(CONFIG_NET_POLL_CONTROLLER)
6976static void
6977poll_bnx2(struct net_device *dev)
6978{
Michael Chan972ec0d2006-01-23 16:12:43 -08006979 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006980
6981 disable_irq(bp->pdev->irq);
David Howells7d12e782006-10-05 14:55:46 +01006982 bnx2_interrupt(bp->pdev->irq, dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006983 enable_irq(bp->pdev->irq);
6984}
6985#endif
6986
Michael Chan253c8b72007-01-08 19:56:01 -08006987static void __devinit
6988bnx2_get_5709_media(struct bnx2 *bp)
6989{
6990 u32 val = REG_RD(bp, BNX2_MISC_DUAL_MEDIA_CTRL);
6991 u32 bond_id = val & BNX2_MISC_DUAL_MEDIA_CTRL_BOND_ID;
6992 u32 strap;
6993
6994 if (bond_id == BNX2_MISC_DUAL_MEDIA_CTRL_BOND_ID_C)
6995 return;
6996 else if (bond_id == BNX2_MISC_DUAL_MEDIA_CTRL_BOND_ID_S) {
Michael Chan583c28e2008-01-21 19:51:35 -08006997 bp->phy_flags |= BNX2_PHY_FLAG_SERDES;
Michael Chan253c8b72007-01-08 19:56:01 -08006998 return;
6999 }
7000
7001 if (val & BNX2_MISC_DUAL_MEDIA_CTRL_STRAP_OVERRIDE)
7002 strap = (val & BNX2_MISC_DUAL_MEDIA_CTRL_PHY_CTRL) >> 21;
7003 else
7004 strap = (val & BNX2_MISC_DUAL_MEDIA_CTRL_PHY_CTRL_STRAP) >> 8;
7005
7006 if (PCI_FUNC(bp->pdev->devfn) == 0) {
7007 switch (strap) {
7008 case 0x4:
7009 case 0x5:
7010 case 0x6:
Michael Chan583c28e2008-01-21 19:51:35 -08007011 bp->phy_flags |= BNX2_PHY_FLAG_SERDES;
Michael Chan253c8b72007-01-08 19:56:01 -08007012 return;
7013 }
7014 } else {
7015 switch (strap) {
7016 case 0x1:
7017 case 0x2:
7018 case 0x4:
Michael Chan583c28e2008-01-21 19:51:35 -08007019 bp->phy_flags |= BNX2_PHY_FLAG_SERDES;
Michael Chan253c8b72007-01-08 19:56:01 -08007020 return;
7021 }
7022 }
7023}
7024
Michael Chan883e5152007-05-03 13:25:11 -07007025static void __devinit
7026bnx2_get_pci_speed(struct bnx2 *bp)
7027{
7028 u32 reg;
7029
7030 reg = REG_RD(bp, BNX2_PCICFG_MISC_STATUS);
7031 if (reg & BNX2_PCICFG_MISC_STATUS_PCIX_DET) {
7032 u32 clkreg;
7033
David S. Millerf86e82f2008-01-21 17:15:40 -08007034 bp->flags |= BNX2_FLAG_PCIX;
Michael Chan883e5152007-05-03 13:25:11 -07007035
7036 clkreg = REG_RD(bp, BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS);
7037
7038 clkreg &= BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET;
7039 switch (clkreg) {
7040 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_133MHZ:
7041 bp->bus_speed_mhz = 133;
7042 break;
7043
7044 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_95MHZ:
7045 bp->bus_speed_mhz = 100;
7046 break;
7047
7048 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_66MHZ:
7049 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_80MHZ:
7050 bp->bus_speed_mhz = 66;
7051 break;
7052
7053 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_48MHZ:
7054 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_55MHZ:
7055 bp->bus_speed_mhz = 50;
7056 break;
7057
7058 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_LOW:
7059 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_32MHZ:
7060 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_38MHZ:
7061 bp->bus_speed_mhz = 33;
7062 break;
7063 }
7064 }
7065 else {
7066 if (reg & BNX2_PCICFG_MISC_STATUS_M66EN)
7067 bp->bus_speed_mhz = 66;
7068 else
7069 bp->bus_speed_mhz = 33;
7070 }
7071
7072 if (reg & BNX2_PCICFG_MISC_STATUS_32BIT_DET)
David S. Millerf86e82f2008-01-21 17:15:40 -08007073 bp->flags |= BNX2_FLAG_PCI_32BIT;
Michael Chan883e5152007-05-03 13:25:11 -07007074
7075}
7076
Michael Chanb6016b72005-05-26 13:03:09 -07007077static int __devinit
7078bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
7079{
7080 struct bnx2 *bp;
7081 unsigned long mem_len;
Michael Chan58fc2ea2007-07-07 22:52:02 -07007082 int rc, i, j;
Michael Chanb6016b72005-05-26 13:03:09 -07007083 u32 reg;
Michael Chan40453c82007-05-03 13:19:18 -07007084 u64 dma_mask, persist_dma_mask;
Michael Chanb6016b72005-05-26 13:03:09 -07007085
Michael Chanb6016b72005-05-26 13:03:09 -07007086 SET_NETDEV_DEV(dev, &pdev->dev);
Michael Chan972ec0d2006-01-23 16:12:43 -08007087 bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007088
7089 bp->flags = 0;
7090 bp->phy_flags = 0;
7091
7092 /* enable device (incl. PCI PM wakeup), and bus-mastering */
7093 rc = pci_enable_device(pdev);
7094 if (rc) {
Joe Perches898eb712007-10-18 03:06:30 -07007095 dev_err(&pdev->dev, "Cannot enable PCI device, aborting.\n");
Michael Chanb6016b72005-05-26 13:03:09 -07007096 goto err_out;
7097 }
7098
7099 if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) {
Jeff Garzik9b91cf92006-06-27 11:39:50 -04007100 dev_err(&pdev->dev,
Jeff Garzik2e8a5382006-06-27 10:47:51 -04007101 "Cannot find PCI device base address, aborting.\n");
Michael Chanb6016b72005-05-26 13:03:09 -07007102 rc = -ENODEV;
7103 goto err_out_disable;
7104 }
7105
7106 rc = pci_request_regions(pdev, DRV_MODULE_NAME);
7107 if (rc) {
Jeff Garzik9b91cf92006-06-27 11:39:50 -04007108 dev_err(&pdev->dev, "Cannot obtain PCI resources, aborting.\n");
Michael Chanb6016b72005-05-26 13:03:09 -07007109 goto err_out_disable;
7110 }
7111
7112 pci_set_master(pdev);
7113
7114 bp->pm_cap = pci_find_capability(pdev, PCI_CAP_ID_PM);
7115 if (bp->pm_cap == 0) {
Jeff Garzik9b91cf92006-06-27 11:39:50 -04007116 dev_err(&pdev->dev,
Jeff Garzik2e8a5382006-06-27 10:47:51 -04007117 "Cannot find power management capability, aborting.\n");
Michael Chanb6016b72005-05-26 13:03:09 -07007118 rc = -EIO;
7119 goto err_out_release;
7120 }
7121
Michael Chanb6016b72005-05-26 13:03:09 -07007122 bp->dev = dev;
7123 bp->pdev = pdev;
7124
7125 spin_lock_init(&bp->phy_lock);
Michael Chan1b8227c2007-05-03 13:24:05 -07007126 spin_lock_init(&bp->indirect_lock);
David Howellsc4028952006-11-22 14:57:56 +00007127 INIT_WORK(&bp->reset_task, bnx2_reset_task);
Michael Chanb6016b72005-05-26 13:03:09 -07007128
7129 dev->base_addr = dev->mem_start = pci_resource_start(pdev, 0);
Michael Chan59b47d82006-11-19 14:10:45 -08007130 mem_len = MB_GET_CID_ADDR(TX_TSS_CID + 1);
Michael Chanb6016b72005-05-26 13:03:09 -07007131 dev->mem_end = dev->mem_start + mem_len;
7132 dev->irq = pdev->irq;
7133
7134 bp->regview = ioremap_nocache(dev->base_addr, mem_len);
7135
7136 if (!bp->regview) {
Jeff Garzik9b91cf92006-06-27 11:39:50 -04007137 dev_err(&pdev->dev, "Cannot map register space, aborting.\n");
Michael Chanb6016b72005-05-26 13:03:09 -07007138 rc = -ENOMEM;
7139 goto err_out_release;
7140 }
7141
7142 /* Configure byte swap and enable write to the reg_window registers.
7143 * Rely on CPU to do target byte swapping on big endian systems
7144 * The chip's target access swapping will not swap all accesses
7145 */
7146 pci_write_config_dword(bp->pdev, BNX2_PCICFG_MISC_CONFIG,
7147 BNX2_PCICFG_MISC_CONFIG_REG_WINDOW_ENA |
7148 BNX2_PCICFG_MISC_CONFIG_TARGET_MB_WORD_SWAP);
7149
Pavel Machek829ca9a2005-09-03 15:56:56 -07007150 bnx2_set_power_state(bp, PCI_D0);
Michael Chanb6016b72005-05-26 13:03:09 -07007151
7152 bp->chip_id = REG_RD(bp, BNX2_MISC_ID);
7153
Michael Chan883e5152007-05-03 13:25:11 -07007154 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
7155 if (pci_find_capability(pdev, PCI_CAP_ID_EXP) == 0) {
7156 dev_err(&pdev->dev,
7157 "Cannot find PCIE capability, aborting.\n");
7158 rc = -EIO;
7159 goto err_out_unmap;
7160 }
David S. Millerf86e82f2008-01-21 17:15:40 -08007161 bp->flags |= BNX2_FLAG_PCIE;
Michael Chan2dd201d2008-01-21 17:06:09 -08007162 if (CHIP_REV(bp) == CHIP_REV_Ax)
David S. Millerf86e82f2008-01-21 17:15:40 -08007163 bp->flags |= BNX2_FLAG_JUMBO_BROKEN;
Michael Chan883e5152007-05-03 13:25:11 -07007164 } else {
Michael Chan59b47d82006-11-19 14:10:45 -08007165 bp->pcix_cap = pci_find_capability(pdev, PCI_CAP_ID_PCIX);
7166 if (bp->pcix_cap == 0) {
7167 dev_err(&pdev->dev,
7168 "Cannot find PCIX capability, aborting.\n");
7169 rc = -EIO;
7170 goto err_out_unmap;
7171 }
7172 }
7173
Michael Chanb4b36042007-12-20 19:59:30 -08007174 if (CHIP_NUM(bp) == CHIP_NUM_5709 && CHIP_REV(bp) != CHIP_REV_Ax) {
7175 if (pci_find_capability(pdev, PCI_CAP_ID_MSIX))
David S. Millerf86e82f2008-01-21 17:15:40 -08007176 bp->flags |= BNX2_FLAG_MSIX_CAP;
Michael Chanb4b36042007-12-20 19:59:30 -08007177 }
7178
Michael Chan8e6a72c2007-05-03 13:24:48 -07007179 if (CHIP_ID(bp) != CHIP_ID_5706_A0 && CHIP_ID(bp) != CHIP_ID_5706_A1) {
7180 if (pci_find_capability(pdev, PCI_CAP_ID_MSI))
David S. Millerf86e82f2008-01-21 17:15:40 -08007181 bp->flags |= BNX2_FLAG_MSI_CAP;
Michael Chan8e6a72c2007-05-03 13:24:48 -07007182 }
7183
Michael Chan40453c82007-05-03 13:19:18 -07007184 /* 5708 cannot support DMA addresses > 40-bit. */
7185 if (CHIP_NUM(bp) == CHIP_NUM_5708)
7186 persist_dma_mask = dma_mask = DMA_40BIT_MASK;
7187 else
7188 persist_dma_mask = dma_mask = DMA_64BIT_MASK;
7189
7190 /* Configure DMA attributes. */
7191 if (pci_set_dma_mask(pdev, dma_mask) == 0) {
7192 dev->features |= NETIF_F_HIGHDMA;
7193 rc = pci_set_consistent_dma_mask(pdev, persist_dma_mask);
7194 if (rc) {
7195 dev_err(&pdev->dev,
7196 "pci_set_consistent_dma_mask failed, aborting.\n");
7197 goto err_out_unmap;
7198 }
7199 } else if ((rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK)) != 0) {
7200 dev_err(&pdev->dev, "System does not support DMA, aborting.\n");
7201 goto err_out_unmap;
7202 }
7203
David S. Millerf86e82f2008-01-21 17:15:40 -08007204 if (!(bp->flags & BNX2_FLAG_PCIE))
Michael Chan883e5152007-05-03 13:25:11 -07007205 bnx2_get_pci_speed(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07007206
7207 /* 5706A0 may falsely detect SERR and PERR. */
7208 if (CHIP_ID(bp) == CHIP_ID_5706_A0) {
7209 reg = REG_RD(bp, PCI_COMMAND);
7210 reg &= ~(PCI_COMMAND_SERR | PCI_COMMAND_PARITY);
7211 REG_WR(bp, PCI_COMMAND, reg);
7212 }
7213 else if ((CHIP_ID(bp) == CHIP_ID_5706_A1) &&
David S. Millerf86e82f2008-01-21 17:15:40 -08007214 !(bp->flags & BNX2_FLAG_PCIX)) {
Michael Chanb6016b72005-05-26 13:03:09 -07007215
Jeff Garzik9b91cf92006-06-27 11:39:50 -04007216 dev_err(&pdev->dev,
Jeff Garzik2e8a5382006-06-27 10:47:51 -04007217 "5706 A1 can only be used in a PCIX bus, aborting.\n");
Michael Chanb6016b72005-05-26 13:03:09 -07007218 goto err_out_unmap;
7219 }
7220
7221 bnx2_init_nvram(bp);
7222
Michael Chan2726d6e2008-01-29 21:35:05 -08007223 reg = bnx2_reg_rd_ind(bp, BNX2_SHM_HDR_SIGNATURE);
Michael Chane3648b32005-11-04 08:51:21 -08007224
7225 if ((reg & BNX2_SHM_HDR_SIGNATURE_SIG_MASK) ==
Michael Chan24cb2302007-01-25 15:49:56 -08007226 BNX2_SHM_HDR_SIGNATURE_SIG) {
7227 u32 off = PCI_FUNC(pdev->devfn) << 2;
7228
Michael Chan2726d6e2008-01-29 21:35:05 -08007229 bp->shmem_base = bnx2_reg_rd_ind(bp, BNX2_SHM_HDR_ADDR_0 + off);
Michael Chan24cb2302007-01-25 15:49:56 -08007230 } else
Michael Chane3648b32005-11-04 08:51:21 -08007231 bp->shmem_base = HOST_VIEW_SHMEM_BASE;
7232
Michael Chanb6016b72005-05-26 13:03:09 -07007233 /* Get the permanent MAC address. First we need to make sure the
7234 * firmware is actually running.
7235 */
Michael Chan2726d6e2008-01-29 21:35:05 -08007236 reg = bnx2_shmem_rd(bp, BNX2_DEV_INFO_SIGNATURE);
Michael Chanb6016b72005-05-26 13:03:09 -07007237
7238 if ((reg & BNX2_DEV_INFO_SIGNATURE_MAGIC_MASK) !=
7239 BNX2_DEV_INFO_SIGNATURE_MAGIC) {
Jeff Garzik9b91cf92006-06-27 11:39:50 -04007240 dev_err(&pdev->dev, "Firmware not running, aborting.\n");
Michael Chanb6016b72005-05-26 13:03:09 -07007241 rc = -ENODEV;
7242 goto err_out_unmap;
7243 }
7244
Michael Chan2726d6e2008-01-29 21:35:05 -08007245 reg = bnx2_shmem_rd(bp, BNX2_DEV_INFO_BC_REV);
Michael Chan58fc2ea2007-07-07 22:52:02 -07007246 for (i = 0, j = 0; i < 3; i++) {
7247 u8 num, k, skip0;
7248
7249 num = (u8) (reg >> (24 - (i * 8)));
7250 for (k = 100, skip0 = 1; k >= 1; num %= k, k /= 10) {
7251 if (num >= k || !skip0 || k == 1) {
7252 bp->fw_version[j++] = (num / k) + '0';
7253 skip0 = 0;
7254 }
7255 }
7256 if (i != 2)
7257 bp->fw_version[j++] = '.';
7258 }
Michael Chan2726d6e2008-01-29 21:35:05 -08007259 reg = bnx2_shmem_rd(bp, BNX2_PORT_FEATURE);
Michael Chan846f5c62007-10-10 16:16:51 -07007260 if (reg & BNX2_PORT_FEATURE_WOL_ENABLED)
7261 bp->wol = 1;
7262
7263 if (reg & BNX2_PORT_FEATURE_ASF_ENABLED) {
David S. Millerf86e82f2008-01-21 17:15:40 -08007264 bp->flags |= BNX2_FLAG_ASF_ENABLE;
Michael Chanc2d3db82007-07-16 18:26:43 -07007265
7266 for (i = 0; i < 30; i++) {
Michael Chan2726d6e2008-01-29 21:35:05 -08007267 reg = bnx2_shmem_rd(bp, BNX2_BC_STATE_CONDITION);
Michael Chanc2d3db82007-07-16 18:26:43 -07007268 if (reg & BNX2_CONDITION_MFW_RUN_MASK)
7269 break;
7270 msleep(10);
7271 }
7272 }
Michael Chan2726d6e2008-01-29 21:35:05 -08007273 reg = bnx2_shmem_rd(bp, BNX2_BC_STATE_CONDITION);
Michael Chan58fc2ea2007-07-07 22:52:02 -07007274 reg &= BNX2_CONDITION_MFW_RUN_MASK;
7275 if (reg != BNX2_CONDITION_MFW_RUN_UNKNOWN &&
7276 reg != BNX2_CONDITION_MFW_RUN_NONE) {
7277 int i;
Michael Chan2726d6e2008-01-29 21:35:05 -08007278 u32 addr = bnx2_shmem_rd(bp, BNX2_MFW_VER_PTR);
Michael Chan58fc2ea2007-07-07 22:52:02 -07007279
7280 bp->fw_version[j++] = ' ';
7281 for (i = 0; i < 3; i++) {
Michael Chan2726d6e2008-01-29 21:35:05 -08007282 reg = bnx2_reg_rd_ind(bp, addr + i * 4);
Michael Chan58fc2ea2007-07-07 22:52:02 -07007283 reg = swab32(reg);
7284 memcpy(&bp->fw_version[j], &reg, 4);
7285 j += 4;
7286 }
7287 }
Michael Chanb6016b72005-05-26 13:03:09 -07007288
Michael Chan2726d6e2008-01-29 21:35:05 -08007289 reg = bnx2_shmem_rd(bp, BNX2_PORT_HW_CFG_MAC_UPPER);
Michael Chanb6016b72005-05-26 13:03:09 -07007290 bp->mac_addr[0] = (u8) (reg >> 8);
7291 bp->mac_addr[1] = (u8) reg;
7292
Michael Chan2726d6e2008-01-29 21:35:05 -08007293 reg = bnx2_shmem_rd(bp, BNX2_PORT_HW_CFG_MAC_LOWER);
Michael Chanb6016b72005-05-26 13:03:09 -07007294 bp->mac_addr[2] = (u8) (reg >> 24);
7295 bp->mac_addr[3] = (u8) (reg >> 16);
7296 bp->mac_addr[4] = (u8) (reg >> 8);
7297 bp->mac_addr[5] = (u8) reg;
7298
Michael Chan5d5d0012007-12-12 11:17:43 -08007299 bp->rx_offset = sizeof(struct l2_fhdr) + 2;
7300
Michael Chanb6016b72005-05-26 13:03:09 -07007301 bp->tx_ring_size = MAX_TX_DESC_CNT;
Michael Chan932f3772006-08-15 01:39:36 -07007302 bnx2_set_rx_ring_size(bp, 255);
Michael Chanb6016b72005-05-26 13:03:09 -07007303
7304 bp->rx_csum = 1;
7305
Michael Chanb6016b72005-05-26 13:03:09 -07007306 bp->tx_quick_cons_trip_int = 20;
7307 bp->tx_quick_cons_trip = 20;
7308 bp->tx_ticks_int = 80;
7309 bp->tx_ticks = 80;
Jeff Garzik6aa20a22006-09-13 13:24:59 -04007310
Michael Chanb6016b72005-05-26 13:03:09 -07007311 bp->rx_quick_cons_trip_int = 6;
7312 bp->rx_quick_cons_trip = 6;
7313 bp->rx_ticks_int = 18;
7314 bp->rx_ticks = 18;
7315
Michael Chan7ea69202007-07-16 18:27:10 -07007316 bp->stats_ticks = USEC_PER_SEC & BNX2_HC_STATS_TICKS_HC_STAT_TICKS;
Michael Chanb6016b72005-05-26 13:03:09 -07007317
7318 bp->timer_interval = HZ;
Michael Chancd339a02005-08-25 15:35:24 -07007319 bp->current_interval = HZ;
Michael Chanb6016b72005-05-26 13:03:09 -07007320
Michael Chan5b0c76a2005-11-04 08:45:49 -08007321 bp->phy_addr = 1;
7322
Michael Chanb6016b72005-05-26 13:03:09 -07007323 /* Disable WOL support if we are running on a SERDES chip. */
Michael Chan253c8b72007-01-08 19:56:01 -08007324 if (CHIP_NUM(bp) == CHIP_NUM_5709)
7325 bnx2_get_5709_media(bp);
7326 else if (CHIP_BOND_ID(bp) & CHIP_BOND_ID_SERDES_BIT)
Michael Chan583c28e2008-01-21 19:51:35 -08007327 bp->phy_flags |= BNX2_PHY_FLAG_SERDES;
Michael Chanbac0dff2006-11-19 14:15:05 -08007328
Michael Chan0d8a6572007-07-07 22:49:43 -07007329 bp->phy_port = PORT_TP;
Michael Chan583c28e2008-01-21 19:51:35 -08007330 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Michael Chan0d8a6572007-07-07 22:49:43 -07007331 bp->phy_port = PORT_FIBRE;
Michael Chan2726d6e2008-01-29 21:35:05 -08007332 reg = bnx2_shmem_rd(bp, BNX2_SHARED_HW_CFG_CONFIG);
Michael Chan846f5c62007-10-10 16:16:51 -07007333 if (!(reg & BNX2_SHARED_HW_CFG_GIG_LINK_ON_VAUX)) {
David S. Millerf86e82f2008-01-21 17:15:40 -08007334 bp->flags |= BNX2_FLAG_NO_WOL;
Michael Chan846f5c62007-10-10 16:16:51 -07007335 bp->wol = 0;
7336 }
Michael Chan38ea3682008-02-23 19:48:57 -08007337 if (CHIP_NUM(bp) == CHIP_NUM_5706) {
7338 /* Don't do parallel detect on this board because of
7339 * some board problems. The link will not go down
7340 * if we do parallel detect.
7341 */
7342 if (pdev->subsystem_vendor == PCI_VENDOR_ID_HP &&
7343 pdev->subsystem_device == 0x310c)
7344 bp->phy_flags |= BNX2_PHY_FLAG_NO_PARALLEL;
7345 } else {
Michael Chan5b0c76a2005-11-04 08:45:49 -08007346 bp->phy_addr = 2;
Michael Chan5b0c76a2005-11-04 08:45:49 -08007347 if (reg & BNX2_SHARED_HW_CFG_PHY_2_5G)
Michael Chan583c28e2008-01-21 19:51:35 -08007348 bp->phy_flags |= BNX2_PHY_FLAG_2_5G_CAPABLE;
Michael Chan5b0c76a2005-11-04 08:45:49 -08007349 }
Michael Chan0d8a6572007-07-07 22:49:43 -07007350 bnx2_init_remote_phy(bp);
7351
Michael Chan261dd5c2007-01-08 19:55:46 -08007352 } else if (CHIP_NUM(bp) == CHIP_NUM_5706 ||
7353 CHIP_NUM(bp) == CHIP_NUM_5708)
Michael Chan583c28e2008-01-21 19:51:35 -08007354 bp->phy_flags |= BNX2_PHY_FLAG_CRC_FIX;
Michael Chanfb0c18b2007-12-10 17:18:23 -08007355 else if (CHIP_NUM(bp) == CHIP_NUM_5709 &&
7356 (CHIP_REV(bp) == CHIP_REV_Ax ||
7357 CHIP_REV(bp) == CHIP_REV_Bx))
Michael Chan583c28e2008-01-21 19:51:35 -08007358 bp->phy_flags |= BNX2_PHY_FLAG_DIS_EARLY_DAC;
Michael Chanb6016b72005-05-26 13:03:09 -07007359
Michael Chan16088272006-06-12 22:16:43 -07007360 if ((CHIP_ID(bp) == CHIP_ID_5708_A0) ||
7361 (CHIP_ID(bp) == CHIP_ID_5708_B0) ||
Michael Chan846f5c62007-10-10 16:16:51 -07007362 (CHIP_ID(bp) == CHIP_ID_5708_B1)) {
David S. Millerf86e82f2008-01-21 17:15:40 -08007363 bp->flags |= BNX2_FLAG_NO_WOL;
Michael Chan846f5c62007-10-10 16:16:51 -07007364 bp->wol = 0;
7365 }
Michael Chandda1e392006-01-23 16:08:14 -08007366
Michael Chanb6016b72005-05-26 13:03:09 -07007367 if (CHIP_ID(bp) == CHIP_ID_5706_A0) {
7368 bp->tx_quick_cons_trip_int =
7369 bp->tx_quick_cons_trip;
7370 bp->tx_ticks_int = bp->tx_ticks;
7371 bp->rx_quick_cons_trip_int =
7372 bp->rx_quick_cons_trip;
7373 bp->rx_ticks_int = bp->rx_ticks;
7374 bp->comp_prod_trip_int = bp->comp_prod_trip;
7375 bp->com_ticks_int = bp->com_ticks;
7376 bp->cmd_ticks_int = bp->cmd_ticks;
7377 }
7378
Michael Chanf9317a42006-09-29 17:06:23 -07007379 /* Disable MSI on 5706 if AMD 8132 bridge is found.
7380 *
7381 * MSI is defined to be 32-bit write. The 5706 does 64-bit MSI writes
7382 * with byte enables disabled on the unused 32-bit word. This is legal
7383 * but causes problems on the AMD 8132 which will eventually stop
7384 * responding after a while.
7385 *
7386 * AMD believes this incompatibility is unique to the 5706, and
Michael Ellerman88187df2007-01-25 19:34:07 +11007387 * prefers to locally disable MSI rather than globally disabling it.
Michael Chanf9317a42006-09-29 17:06:23 -07007388 */
7389 if (CHIP_NUM(bp) == CHIP_NUM_5706 && disable_msi == 0) {
7390 struct pci_dev *amd_8132 = NULL;
7391
7392 while ((amd_8132 = pci_get_device(PCI_VENDOR_ID_AMD,
7393 PCI_DEVICE_ID_AMD_8132_BRIDGE,
7394 amd_8132))) {
Michael Chanf9317a42006-09-29 17:06:23 -07007395
Auke Kok44c10132007-06-08 15:46:36 -07007396 if (amd_8132->revision >= 0x10 &&
7397 amd_8132->revision <= 0x13) {
Michael Chanf9317a42006-09-29 17:06:23 -07007398 disable_msi = 1;
7399 pci_dev_put(amd_8132);
7400 break;
7401 }
7402 }
7403 }
7404
Michael Chandeaf3912007-07-07 22:48:00 -07007405 bnx2_set_default_link(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07007406 bp->req_flow_ctrl = FLOW_CTRL_RX | FLOW_CTRL_TX;
7407
Michael Chancd339a02005-08-25 15:35:24 -07007408 init_timer(&bp->timer);
7409 bp->timer.expires = RUN_AT(bp->timer_interval);
7410 bp->timer.data = (unsigned long) bp;
7411 bp->timer.function = bnx2_timer;
7412
Michael Chanb6016b72005-05-26 13:03:09 -07007413 return 0;
7414
7415err_out_unmap:
7416 if (bp->regview) {
7417 iounmap(bp->regview);
Michael Chan73eef4c2005-08-25 15:39:15 -07007418 bp->regview = NULL;
Michael Chanb6016b72005-05-26 13:03:09 -07007419 }
7420
7421err_out_release:
7422 pci_release_regions(pdev);
7423
7424err_out_disable:
7425 pci_disable_device(pdev);
7426 pci_set_drvdata(pdev, NULL);
7427
7428err_out:
7429 return rc;
7430}
7431
Michael Chan883e5152007-05-03 13:25:11 -07007432static char * __devinit
7433bnx2_bus_string(struct bnx2 *bp, char *str)
7434{
7435 char *s = str;
7436
David S. Millerf86e82f2008-01-21 17:15:40 -08007437 if (bp->flags & BNX2_FLAG_PCIE) {
Michael Chan883e5152007-05-03 13:25:11 -07007438 s += sprintf(s, "PCI Express");
7439 } else {
7440 s += sprintf(s, "PCI");
David S. Millerf86e82f2008-01-21 17:15:40 -08007441 if (bp->flags & BNX2_FLAG_PCIX)
Michael Chan883e5152007-05-03 13:25:11 -07007442 s += sprintf(s, "-X");
David S. Millerf86e82f2008-01-21 17:15:40 -08007443 if (bp->flags & BNX2_FLAG_PCI_32BIT)
Michael Chan883e5152007-05-03 13:25:11 -07007444 s += sprintf(s, " 32-bit");
7445 else
7446 s += sprintf(s, " 64-bit");
7447 s += sprintf(s, " %dMHz", bp->bus_speed_mhz);
7448 }
7449 return str;
7450}
7451
Michael Chan2ba582b2007-12-21 15:04:49 -08007452static void __devinit
Michael Chan35efa7c2007-12-20 19:56:37 -08007453bnx2_init_napi(struct bnx2 *bp)
7454{
Michael Chanb4b36042007-12-20 19:59:30 -08007455 int i;
7456 struct bnx2_napi *bnapi;
Michael Chan35efa7c2007-12-20 19:56:37 -08007457
Michael Chanb4b36042007-12-20 19:59:30 -08007458 for (i = 0; i < BNX2_MAX_MSIX_VEC; i++) {
7459 bnapi = &bp->bnx2_napi[i];
7460 bnapi->bp = bp;
7461 }
7462 netif_napi_add(bp->dev, &bp->bnx2_napi[0].napi, bnx2_poll, 64);
Michael Chan57851d82007-12-20 20:01:44 -08007463 netif_napi_add(bp->dev, &bp->bnx2_napi[BNX2_TX_VEC].napi, bnx2_tx_poll,
7464 64);
Michael Chan35efa7c2007-12-20 19:56:37 -08007465}
7466
7467static int __devinit
Michael Chanb6016b72005-05-26 13:03:09 -07007468bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
7469{
7470 static int version_printed = 0;
7471 struct net_device *dev = NULL;
7472 struct bnx2 *bp;
Joe Perches0795af52007-10-03 17:59:30 -07007473 int rc;
Michael Chan883e5152007-05-03 13:25:11 -07007474 char str[40];
Joe Perches0795af52007-10-03 17:59:30 -07007475 DECLARE_MAC_BUF(mac);
Michael Chanb6016b72005-05-26 13:03:09 -07007476
7477 if (version_printed++ == 0)
7478 printk(KERN_INFO "%s", version);
7479
7480 /* dev zeroed in init_etherdev */
7481 dev = alloc_etherdev(sizeof(*bp));
7482
7483 if (!dev)
7484 return -ENOMEM;
7485
7486 rc = bnx2_init_board(pdev, dev);
7487 if (rc < 0) {
7488 free_netdev(dev);
7489 return rc;
7490 }
7491
7492 dev->open = bnx2_open;
7493 dev->hard_start_xmit = bnx2_start_xmit;
7494 dev->stop = bnx2_close;
7495 dev->get_stats = bnx2_get_stats;
7496 dev->set_multicast_list = bnx2_set_rx_mode;
7497 dev->do_ioctl = bnx2_ioctl;
7498 dev->set_mac_address = bnx2_change_mac_addr;
7499 dev->change_mtu = bnx2_change_mtu;
7500 dev->tx_timeout = bnx2_tx_timeout;
7501 dev->watchdog_timeo = TX_TIMEOUT;
7502#ifdef BCM_VLAN
7503 dev->vlan_rx_register = bnx2_vlan_rx_register;
Michael Chanb6016b72005-05-26 13:03:09 -07007504#endif
Michael Chanb6016b72005-05-26 13:03:09 -07007505 dev->ethtool_ops = &bnx2_ethtool_ops;
Michael Chanb6016b72005-05-26 13:03:09 -07007506
Michael Chan972ec0d2006-01-23 16:12:43 -08007507 bp = netdev_priv(dev);
Michael Chan35efa7c2007-12-20 19:56:37 -08007508 bnx2_init_napi(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07007509
7510#if defined(HAVE_POLL_CONTROLLER) || defined(CONFIG_NET_POLL_CONTROLLER)
7511 dev->poll_controller = poll_bnx2;
7512#endif
7513
Michael Chan1b2f9222007-05-03 13:20:19 -07007514 pci_set_drvdata(pdev, dev);
7515
7516 memcpy(dev->dev_addr, bp->mac_addr, 6);
7517 memcpy(dev->perm_addr, bp->mac_addr, 6);
7518 bp->name = board_info[ent->driver_data].name;
7519
Stephen Hemmingerd212f872007-06-27 00:47:37 -07007520 dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG;
Michael Chan4666f872007-05-03 13:22:28 -07007521 if (CHIP_NUM(bp) == CHIP_NUM_5709)
Stephen Hemmingerd212f872007-06-27 00:47:37 -07007522 dev->features |= NETIF_F_IPV6_CSUM;
7523
Michael Chan1b2f9222007-05-03 13:20:19 -07007524#ifdef BCM_VLAN
7525 dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
7526#endif
7527 dev->features |= NETIF_F_TSO | NETIF_F_TSO_ECN;
Michael Chan4666f872007-05-03 13:22:28 -07007528 if (CHIP_NUM(bp) == CHIP_NUM_5709)
7529 dev->features |= NETIF_F_TSO6;
Michael Chan1b2f9222007-05-03 13:20:19 -07007530
Michael Chanb6016b72005-05-26 13:03:09 -07007531 if ((rc = register_netdev(dev))) {
Jeff Garzik9b91cf92006-06-27 11:39:50 -04007532 dev_err(&pdev->dev, "Cannot register net device\n");
Michael Chanb6016b72005-05-26 13:03:09 -07007533 if (bp->regview)
7534 iounmap(bp->regview);
7535 pci_release_regions(pdev);
7536 pci_disable_device(pdev);
7537 pci_set_drvdata(pdev, NULL);
7538 free_netdev(dev);
7539 return rc;
7540 }
7541
Michael Chan883e5152007-05-03 13:25:11 -07007542 printk(KERN_INFO "%s: %s (%c%d) %s found at mem %lx, "
Joe Perches0795af52007-10-03 17:59:30 -07007543 "IRQ %d, node addr %s\n",
Michael Chanb6016b72005-05-26 13:03:09 -07007544 dev->name,
7545 bp->name,
7546 ((CHIP_ID(bp) & 0xf000) >> 12) + 'A',
7547 ((CHIP_ID(bp) & 0x0ff0) >> 4),
Michael Chan883e5152007-05-03 13:25:11 -07007548 bnx2_bus_string(bp, str),
Michael Chanb6016b72005-05-26 13:03:09 -07007549 dev->base_addr,
Joe Perches0795af52007-10-03 17:59:30 -07007550 bp->pdev->irq, print_mac(mac, dev->dev_addr));
Michael Chanb6016b72005-05-26 13:03:09 -07007551
Michael Chanb6016b72005-05-26 13:03:09 -07007552 return 0;
7553}
7554
7555static void __devexit
7556bnx2_remove_one(struct pci_dev *pdev)
7557{
7558 struct net_device *dev = pci_get_drvdata(pdev);
Michael Chan972ec0d2006-01-23 16:12:43 -08007559 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007560
Michael Chanafdc08b2005-08-25 15:34:29 -07007561 flush_scheduled_work();
7562
Michael Chanb6016b72005-05-26 13:03:09 -07007563 unregister_netdev(dev);
7564
7565 if (bp->regview)
7566 iounmap(bp->regview);
7567
7568 free_netdev(dev);
7569 pci_release_regions(pdev);
7570 pci_disable_device(pdev);
7571 pci_set_drvdata(pdev, NULL);
7572}
7573
7574static int
Pavel Machek829ca9a2005-09-03 15:56:56 -07007575bnx2_suspend(struct pci_dev *pdev, pm_message_t state)
Michael Chanb6016b72005-05-26 13:03:09 -07007576{
7577 struct net_device *dev = pci_get_drvdata(pdev);
Michael Chan972ec0d2006-01-23 16:12:43 -08007578 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007579 u32 reset_code;
7580
Michael Chan6caebb02007-08-03 20:57:25 -07007581 /* PCI register 4 needs to be saved whether netif_running() or not.
7582 * MSI address and data need to be saved if using MSI and
7583 * netif_running().
7584 */
7585 pci_save_state(pdev);
Michael Chanb6016b72005-05-26 13:03:09 -07007586 if (!netif_running(dev))
7587 return 0;
7588
Michael Chan1d60290f2006-03-20 17:50:08 -08007589 flush_scheduled_work();
Michael Chanb6016b72005-05-26 13:03:09 -07007590 bnx2_netif_stop(bp);
7591 netif_device_detach(dev);
7592 del_timer_sync(&bp->timer);
David S. Millerf86e82f2008-01-21 17:15:40 -08007593 if (bp->flags & BNX2_FLAG_NO_WOL)
Michael Chan6c4f0952006-06-29 12:38:15 -07007594 reset_code = BNX2_DRV_MSG_CODE_UNLOAD_LNK_DN;
Michael Chandda1e392006-01-23 16:08:14 -08007595 else if (bp->wol)
Michael Chanb6016b72005-05-26 13:03:09 -07007596 reset_code = BNX2_DRV_MSG_CODE_SUSPEND_WOL;
7597 else
7598 reset_code = BNX2_DRV_MSG_CODE_SUSPEND_NO_WOL;
7599 bnx2_reset_chip(bp, reset_code);
7600 bnx2_free_skbs(bp);
Pavel Machek829ca9a2005-09-03 15:56:56 -07007601 bnx2_set_power_state(bp, pci_choose_state(pdev, state));
Michael Chanb6016b72005-05-26 13:03:09 -07007602 return 0;
7603}
7604
7605static int
7606bnx2_resume(struct pci_dev *pdev)
7607{
7608 struct net_device *dev = pci_get_drvdata(pdev);
Michael Chan972ec0d2006-01-23 16:12:43 -08007609 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007610
Michael Chan6caebb02007-08-03 20:57:25 -07007611 pci_restore_state(pdev);
Michael Chanb6016b72005-05-26 13:03:09 -07007612 if (!netif_running(dev))
7613 return 0;
7614
Pavel Machek829ca9a2005-09-03 15:56:56 -07007615 bnx2_set_power_state(bp, PCI_D0);
Michael Chanb6016b72005-05-26 13:03:09 -07007616 netif_device_attach(dev);
7617 bnx2_init_nic(bp);
7618 bnx2_netif_start(bp);
7619 return 0;
7620}
7621
7622static struct pci_driver bnx2_pci_driver = {
Peter Hagervall14ab9b82005-08-10 14:18:16 -07007623 .name = DRV_MODULE_NAME,
7624 .id_table = bnx2_pci_tbl,
7625 .probe = bnx2_init_one,
7626 .remove = __devexit_p(bnx2_remove_one),
7627 .suspend = bnx2_suspend,
7628 .resume = bnx2_resume,
Michael Chanb6016b72005-05-26 13:03:09 -07007629};
7630
7631static int __init bnx2_init(void)
7632{
Jeff Garzik29917622006-08-19 17:48:59 -04007633 return pci_register_driver(&bnx2_pci_driver);
Michael Chanb6016b72005-05-26 13:03:09 -07007634}
7635
7636static void __exit bnx2_cleanup(void)
7637{
7638 pci_unregister_driver(&bnx2_pci_driver);
7639}
7640
7641module_init(bnx2_init);
7642module_exit(bnx2_cleanup);
7643
7644
7645