12e0bf125SRasesh Mody /* bnx2.c: QLogic bnx2 network driver.
2adfc5217SJeff Kirsher  *
328c4ec0dSJitendra Kalsaria  * Copyright (c) 2004-2014 Broadcom Corporation
42e0bf125SRasesh Mody  * Copyright (c) 2014-2015 QLogic Corporation
5adfc5217SJeff Kirsher  *
6adfc5217SJeff Kirsher  * This program is free software; you can redistribute it and/or modify
7adfc5217SJeff Kirsher  * it under the terms of the GNU General Public License as published by
8adfc5217SJeff Kirsher  * the Free Software Foundation.
9adfc5217SJeff Kirsher  *
10adfc5217SJeff Kirsher  * Written by: Michael Chan  (mchan@broadcom.com)
11adfc5217SJeff Kirsher  */
12adfc5217SJeff Kirsher 
13adfc5217SJeff Kirsher #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
14adfc5217SJeff Kirsher 
15adfc5217SJeff Kirsher #include <linux/module.h>
16adfc5217SJeff Kirsher #include <linux/moduleparam.h>
17adfc5217SJeff Kirsher 
18555069daSMichael Chan #include <linux/stringify.h>
19adfc5217SJeff Kirsher #include <linux/kernel.h>
20adfc5217SJeff Kirsher #include <linux/timer.h>
21adfc5217SJeff Kirsher #include <linux/errno.h>
22adfc5217SJeff Kirsher #include <linux/ioport.h>
23adfc5217SJeff Kirsher #include <linux/slab.h>
24adfc5217SJeff Kirsher #include <linux/vmalloc.h>
25adfc5217SJeff Kirsher #include <linux/interrupt.h>
26adfc5217SJeff Kirsher #include <linux/pci.h>
27adfc5217SJeff Kirsher #include <linux/netdevice.h>
28adfc5217SJeff Kirsher #include <linux/etherdevice.h>
29adfc5217SJeff Kirsher #include <linux/skbuff.h>
30adfc5217SJeff Kirsher #include <linux/dma-mapping.h>
31adfc5217SJeff Kirsher #include <linux/bitops.h>
32adfc5217SJeff Kirsher #include <asm/io.h>
33adfc5217SJeff Kirsher #include <asm/irq.h>
34adfc5217SJeff Kirsher #include <linux/delay.h>
35adfc5217SJeff Kirsher #include <asm/byteorder.h>
36adfc5217SJeff Kirsher #include <asm/page.h>
37adfc5217SJeff Kirsher #include <linux/time.h>
38adfc5217SJeff Kirsher #include <linux/ethtool.h>
39adfc5217SJeff Kirsher #include <linux/mii.h>
4001789349SJiri Pirko #include <linux/if.h>
41adfc5217SJeff Kirsher #include <linux/if_vlan.h>
42adfc5217SJeff Kirsher #include <net/ip.h>
43adfc5217SJeff Kirsher #include <net/tcp.h>
44adfc5217SJeff Kirsher #include <net/checksum.h>
45adfc5217SJeff Kirsher #include <linux/workqueue.h>
46adfc5217SJeff Kirsher #include <linux/crc32.h>
47adfc5217SJeff Kirsher #include <linux/prefetch.h>
48adfc5217SJeff Kirsher #include <linux/cache.h>
49adfc5217SJeff Kirsher #include <linux/firmware.h>
50adfc5217SJeff Kirsher #include <linux/log2.h>
51adfc5217SJeff Kirsher #include <linux/aer.h>
526df77862SBaoquan He #include <linux/crash_dump.h>
53adfc5217SJeff Kirsher 
54da556d6aSJavier Martinez Canillas #if IS_ENABLED(CONFIG_CNIC)
55adfc5217SJeff Kirsher #define BCM_CNIC 1
56adfc5217SJeff Kirsher #include "cnic_if.h"
57adfc5217SJeff Kirsher #endif
58adfc5217SJeff Kirsher #include "bnx2.h"
59adfc5217SJeff Kirsher #include "bnx2_fw.h"
60adfc5217SJeff Kirsher 
61adfc5217SJeff Kirsher #define DRV_MODULE_NAME		"bnx2"
6285fe7cd2SRasesh Mody #define DRV_MODULE_VERSION	"2.2.6"
6385fe7cd2SRasesh Mody #define DRV_MODULE_RELDATE	"January 29, 2014"
64c2c20ef4SMichael Chan #define FW_MIPS_FILE_06		"bnx2/bnx2-mips-06-6.2.3.fw"
65adfc5217SJeff Kirsher #define FW_RV2P_FILE_06		"bnx2/bnx2-rv2p-06-6.0.15.fw"
66c2c20ef4SMichael Chan #define FW_MIPS_FILE_09		"bnx2/bnx2-mips-09-6.2.1b.fw"
67adfc5217SJeff Kirsher #define FW_RV2P_FILE_09_Ax	"bnx2/bnx2-rv2p-09ax-6.0.17.fw"
68adfc5217SJeff Kirsher #define FW_RV2P_FILE_09		"bnx2/bnx2-rv2p-09-6.0.17.fw"
69adfc5217SJeff Kirsher 
70adfc5217SJeff Kirsher #define RUN_AT(x) (jiffies + (x))
71adfc5217SJeff Kirsher 
72adfc5217SJeff Kirsher /* Time in jiffies before concluding the transmitter is hung. */
73adfc5217SJeff Kirsher #define TX_TIMEOUT  (5*HZ)
74adfc5217SJeff Kirsher 
75cfd95a63SBill Pemberton static char version[] =
762e0bf125SRasesh Mody 	"QLogic " DRV_MODULE_NAME " Gigabit Ethernet Driver v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";
77adfc5217SJeff Kirsher 
78adfc5217SJeff Kirsher MODULE_AUTHOR("Michael Chan <mchan@broadcom.com>");
792e0bf125SRasesh Mody MODULE_DESCRIPTION("QLogic BCM5706/5708/5709/5716 Driver");
80adfc5217SJeff Kirsher MODULE_LICENSE("GPL");
81adfc5217SJeff Kirsher MODULE_VERSION(DRV_MODULE_VERSION);
82adfc5217SJeff Kirsher MODULE_FIRMWARE(FW_MIPS_FILE_06);
83adfc5217SJeff Kirsher MODULE_FIRMWARE(FW_RV2P_FILE_06);
84adfc5217SJeff Kirsher MODULE_FIRMWARE(FW_MIPS_FILE_09);
85adfc5217SJeff Kirsher MODULE_FIRMWARE(FW_RV2P_FILE_09);
86adfc5217SJeff Kirsher MODULE_FIRMWARE(FW_RV2P_FILE_09_Ax);
87adfc5217SJeff Kirsher 
88adfc5217SJeff Kirsher static int disable_msi = 0;
89adfc5217SJeff Kirsher 
90d3757ba4SJoe Perches module_param(disable_msi, int, 0444);
91adfc5217SJeff Kirsher MODULE_PARM_DESC(disable_msi, "Disable Message Signaled Interrupt (MSI)");
92adfc5217SJeff Kirsher 
93adfc5217SJeff Kirsher typedef enum {
94adfc5217SJeff Kirsher 	BCM5706 = 0,
95adfc5217SJeff Kirsher 	NC370T,
96adfc5217SJeff Kirsher 	NC370I,
97adfc5217SJeff Kirsher 	BCM5706S,
98adfc5217SJeff Kirsher 	NC370F,
99adfc5217SJeff Kirsher 	BCM5708,
100adfc5217SJeff Kirsher 	BCM5708S,
101adfc5217SJeff Kirsher 	BCM5709,
102adfc5217SJeff Kirsher 	BCM5709S,
103adfc5217SJeff Kirsher 	BCM5716,
104adfc5217SJeff Kirsher 	BCM5716S,
105adfc5217SJeff Kirsher } board_t;
106adfc5217SJeff Kirsher 
107adfc5217SJeff Kirsher /* indexed by board_t, above */
108adfc5217SJeff Kirsher static struct {
109adfc5217SJeff Kirsher 	char *name;
110cfd95a63SBill Pemberton } board_info[] = {
111adfc5217SJeff Kirsher 	{ "Broadcom NetXtreme II BCM5706 1000Base-T" },
112adfc5217SJeff Kirsher 	{ "HP NC370T Multifunction Gigabit Server Adapter" },
113adfc5217SJeff Kirsher 	{ "HP NC370i Multifunction Gigabit Server Adapter" },
114adfc5217SJeff Kirsher 	{ "Broadcom NetXtreme II BCM5706 1000Base-SX" },
115adfc5217SJeff Kirsher 	{ "HP NC370F Multifunction Gigabit Server Adapter" },
116adfc5217SJeff Kirsher 	{ "Broadcom NetXtreme II BCM5708 1000Base-T" },
117adfc5217SJeff Kirsher 	{ "Broadcom NetXtreme II BCM5708 1000Base-SX" },
118adfc5217SJeff Kirsher 	{ "Broadcom NetXtreme II BCM5709 1000Base-T" },
119adfc5217SJeff Kirsher 	{ "Broadcom NetXtreme II BCM5709 1000Base-SX" },
120adfc5217SJeff Kirsher 	{ "Broadcom NetXtreme II BCM5716 1000Base-T" },
121adfc5217SJeff Kirsher 	{ "Broadcom NetXtreme II BCM5716 1000Base-SX" },
122adfc5217SJeff Kirsher 	};
123adfc5217SJeff Kirsher 
1249baa3c34SBenoit Taine static const struct pci_device_id bnx2_pci_tbl[] = {
125adfc5217SJeff Kirsher 	{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5706,
126adfc5217SJeff Kirsher 	  PCI_VENDOR_ID_HP, 0x3101, 0, 0, NC370T },
127adfc5217SJeff Kirsher 	{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5706,
128adfc5217SJeff Kirsher 	  PCI_VENDOR_ID_HP, 0x3106, 0, 0, NC370I },
129adfc5217SJeff Kirsher 	{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5706,
130adfc5217SJeff Kirsher 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5706 },
131adfc5217SJeff Kirsher 	{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5708,
132adfc5217SJeff Kirsher 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5708 },
133adfc5217SJeff Kirsher 	{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5706S,
134adfc5217SJeff Kirsher 	  PCI_VENDOR_ID_HP, 0x3102, 0, 0, NC370F },
135adfc5217SJeff Kirsher 	{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5706S,
136adfc5217SJeff Kirsher 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5706S },
137adfc5217SJeff Kirsher 	{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5708S,
138adfc5217SJeff Kirsher 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5708S },
139adfc5217SJeff Kirsher 	{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5709,
140adfc5217SJeff Kirsher 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5709 },
141adfc5217SJeff Kirsher 	{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5709S,
142adfc5217SJeff Kirsher 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5709S },
143adfc5217SJeff Kirsher 	{ PCI_VENDOR_ID_BROADCOM, 0x163b,
144adfc5217SJeff Kirsher 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5716 },
145adfc5217SJeff Kirsher 	{ PCI_VENDOR_ID_BROADCOM, 0x163c,
146adfc5217SJeff Kirsher 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5716S },
147adfc5217SJeff Kirsher 	{ 0, }
148adfc5217SJeff Kirsher };
149adfc5217SJeff Kirsher 
150adfc5217SJeff Kirsher static const struct flash_spec flash_table[] =
151adfc5217SJeff Kirsher {
152adfc5217SJeff Kirsher #define BUFFERED_FLAGS		(BNX2_NV_BUFFERED | BNX2_NV_TRANSLATE)
153adfc5217SJeff Kirsher #define NONBUFFERED_FLAGS	(BNX2_NV_WREN)
154adfc5217SJeff Kirsher 	/* Slow EEPROM */
155adfc5217SJeff Kirsher 	{0x00000000, 0x40830380, 0x009f0081, 0xa184a053, 0xaf000400,
156adfc5217SJeff Kirsher 	 BUFFERED_FLAGS, SEEPROM_PAGE_BITS, SEEPROM_PAGE_SIZE,
157adfc5217SJeff Kirsher 	 SEEPROM_BYTE_ADDR_MASK, SEEPROM_TOTAL_SIZE,
158adfc5217SJeff Kirsher 	 "EEPROM - slow"},
159adfc5217SJeff Kirsher 	/* Expansion entry 0001 */
160adfc5217SJeff Kirsher 	{0x08000002, 0x4b808201, 0x00050081, 0x03840253, 0xaf020406,
161adfc5217SJeff Kirsher 	 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
162adfc5217SJeff Kirsher 	 SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
163adfc5217SJeff Kirsher 	 "Entry 0001"},
164adfc5217SJeff Kirsher 	/* Saifun SA25F010 (non-buffered flash) */
165adfc5217SJeff Kirsher 	/* strap, cfg1, & write1 need updates */
166adfc5217SJeff Kirsher 	{0x04000001, 0x47808201, 0x00050081, 0x03840253, 0xaf020406,
167adfc5217SJeff Kirsher 	 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
168adfc5217SJeff Kirsher 	 SAIFUN_FLASH_BYTE_ADDR_MASK, SAIFUN_FLASH_BASE_TOTAL_SIZE*2,
169adfc5217SJeff Kirsher 	 "Non-buffered flash (128kB)"},
170adfc5217SJeff Kirsher 	/* Saifun SA25F020 (non-buffered flash) */
171adfc5217SJeff Kirsher 	/* strap, cfg1, & write1 need updates */
172adfc5217SJeff Kirsher 	{0x0c000003, 0x4f808201, 0x00050081, 0x03840253, 0xaf020406,
173adfc5217SJeff Kirsher 	 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
174adfc5217SJeff Kirsher 	 SAIFUN_FLASH_BYTE_ADDR_MASK, SAIFUN_FLASH_BASE_TOTAL_SIZE*4,
175adfc5217SJeff Kirsher 	 "Non-buffered flash (256kB)"},
176adfc5217SJeff Kirsher 	/* Expansion entry 0100 */
177adfc5217SJeff Kirsher 	{0x11000000, 0x53808201, 0x00050081, 0x03840253, 0xaf020406,
178adfc5217SJeff Kirsher 	 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
179adfc5217SJeff Kirsher 	 SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
180adfc5217SJeff Kirsher 	 "Entry 0100"},
181adfc5217SJeff Kirsher 	/* Entry 0101: ST M45PE10 (non-buffered flash, TetonII B0) */
182adfc5217SJeff Kirsher 	{0x19000002, 0x5b808201, 0x000500db, 0x03840253, 0xaf020406,
183adfc5217SJeff Kirsher 	 NONBUFFERED_FLAGS, ST_MICRO_FLASH_PAGE_BITS, ST_MICRO_FLASH_PAGE_SIZE,
184adfc5217SJeff Kirsher 	 ST_MICRO_FLASH_BYTE_ADDR_MASK, ST_MICRO_FLASH_BASE_TOTAL_SIZE*2,
185adfc5217SJeff Kirsher 	 "Entry 0101: ST M45PE10 (128kB non-bufferred)"},
186adfc5217SJeff Kirsher 	/* Entry 0110: ST M45PE20 (non-buffered flash)*/
187adfc5217SJeff Kirsher 	{0x15000001, 0x57808201, 0x000500db, 0x03840253, 0xaf020406,
188adfc5217SJeff Kirsher 	 NONBUFFERED_FLAGS, ST_MICRO_FLASH_PAGE_BITS, ST_MICRO_FLASH_PAGE_SIZE,
189adfc5217SJeff Kirsher 	 ST_MICRO_FLASH_BYTE_ADDR_MASK, ST_MICRO_FLASH_BASE_TOTAL_SIZE*4,
190adfc5217SJeff Kirsher 	 "Entry 0110: ST M45PE20 (256kB non-bufferred)"},
191adfc5217SJeff Kirsher 	/* Saifun SA25F005 (non-buffered flash) */
192adfc5217SJeff Kirsher 	/* strap, cfg1, & write1 need updates */
193adfc5217SJeff Kirsher 	{0x1d000003, 0x5f808201, 0x00050081, 0x03840253, 0xaf020406,
194adfc5217SJeff Kirsher 	 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
195adfc5217SJeff Kirsher 	 SAIFUN_FLASH_BYTE_ADDR_MASK, SAIFUN_FLASH_BASE_TOTAL_SIZE,
196adfc5217SJeff Kirsher 	 "Non-buffered flash (64kB)"},
197adfc5217SJeff Kirsher 	/* Fast EEPROM */
198adfc5217SJeff Kirsher 	{0x22000000, 0x62808380, 0x009f0081, 0xa184a053, 0xaf000400,
199adfc5217SJeff Kirsher 	 BUFFERED_FLAGS, SEEPROM_PAGE_BITS, SEEPROM_PAGE_SIZE,
200adfc5217SJeff Kirsher 	 SEEPROM_BYTE_ADDR_MASK, SEEPROM_TOTAL_SIZE,
201adfc5217SJeff Kirsher 	 "EEPROM - fast"},
202adfc5217SJeff Kirsher 	/* Expansion entry 1001 */
203adfc5217SJeff Kirsher 	{0x2a000002, 0x6b808201, 0x00050081, 0x03840253, 0xaf020406,
204adfc5217SJeff Kirsher 	 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
205adfc5217SJeff Kirsher 	 SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
206adfc5217SJeff Kirsher 	 "Entry 1001"},
207adfc5217SJeff Kirsher 	/* Expansion entry 1010 */
208adfc5217SJeff Kirsher 	{0x26000001, 0x67808201, 0x00050081, 0x03840253, 0xaf020406,
209adfc5217SJeff Kirsher 	 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
210adfc5217SJeff Kirsher 	 SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
211adfc5217SJeff Kirsher 	 "Entry 1010"},
212adfc5217SJeff Kirsher 	/* ATMEL AT45DB011B (buffered flash) */
213adfc5217SJeff Kirsher 	{0x2e000003, 0x6e808273, 0x00570081, 0x68848353, 0xaf000400,
214adfc5217SJeff Kirsher 	 BUFFERED_FLAGS, BUFFERED_FLASH_PAGE_BITS, BUFFERED_FLASH_PAGE_SIZE,
215adfc5217SJeff Kirsher 	 BUFFERED_FLASH_BYTE_ADDR_MASK, BUFFERED_FLASH_TOTAL_SIZE,
216adfc5217SJeff Kirsher 	 "Buffered flash (128kB)"},
217adfc5217SJeff Kirsher 	/* Expansion entry 1100 */
218adfc5217SJeff Kirsher 	{0x33000000, 0x73808201, 0x00050081, 0x03840253, 0xaf020406,
219adfc5217SJeff Kirsher 	 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
220adfc5217SJeff Kirsher 	 SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
221adfc5217SJeff Kirsher 	 "Entry 1100"},
222adfc5217SJeff Kirsher 	/* Expansion entry 1101 */
223adfc5217SJeff Kirsher 	{0x3b000002, 0x7b808201, 0x00050081, 0x03840253, 0xaf020406,
224adfc5217SJeff Kirsher 	 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
225adfc5217SJeff Kirsher 	 SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
226adfc5217SJeff Kirsher 	 "Entry 1101"},
227adfc5217SJeff Kirsher 	/* Ateml Expansion entry 1110 */
228adfc5217SJeff Kirsher 	{0x37000001, 0x76808273, 0x00570081, 0x68848353, 0xaf000400,
229adfc5217SJeff Kirsher 	 BUFFERED_FLAGS, BUFFERED_FLASH_PAGE_BITS, BUFFERED_FLASH_PAGE_SIZE,
230adfc5217SJeff Kirsher 	 BUFFERED_FLASH_BYTE_ADDR_MASK, 0,
231adfc5217SJeff Kirsher 	 "Entry 1110 (Atmel)"},
232adfc5217SJeff Kirsher 	/* ATMEL AT45DB021B (buffered flash) */
233adfc5217SJeff Kirsher 	{0x3f000003, 0x7e808273, 0x00570081, 0x68848353, 0xaf000400,
234adfc5217SJeff Kirsher 	 BUFFERED_FLAGS, BUFFERED_FLASH_PAGE_BITS, BUFFERED_FLASH_PAGE_SIZE,
235adfc5217SJeff Kirsher 	 BUFFERED_FLASH_BYTE_ADDR_MASK, BUFFERED_FLASH_TOTAL_SIZE*2,
236adfc5217SJeff Kirsher 	 "Buffered flash (256kB)"},
237adfc5217SJeff Kirsher };
238adfc5217SJeff Kirsher 
239adfc5217SJeff Kirsher static const struct flash_spec flash_5709 = {
240adfc5217SJeff Kirsher 	.flags		= BNX2_NV_BUFFERED,
241adfc5217SJeff Kirsher 	.page_bits	= BCM5709_FLASH_PAGE_BITS,
242adfc5217SJeff Kirsher 	.page_size	= BCM5709_FLASH_PAGE_SIZE,
243adfc5217SJeff Kirsher 	.addr_mask	= BCM5709_FLASH_BYTE_ADDR_MASK,
244adfc5217SJeff Kirsher 	.total_size	= BUFFERED_FLASH_TOTAL_SIZE*2,
245adfc5217SJeff Kirsher 	.name		= "5709 Buffered flash (256kB)",
246adfc5217SJeff Kirsher };
247adfc5217SJeff Kirsher 
248adfc5217SJeff Kirsher MODULE_DEVICE_TABLE(pci, bnx2_pci_tbl);
249adfc5217SJeff Kirsher 
250adfc5217SJeff Kirsher static void bnx2_init_napi(struct bnx2 *bp);
251adfc5217SJeff Kirsher static void bnx2_del_napi(struct bnx2 *bp);
252adfc5217SJeff Kirsher 
253adfc5217SJeff Kirsher static inline u32 bnx2_tx_avail(struct bnx2 *bp, struct bnx2_tx_ring_info *txr)
254adfc5217SJeff Kirsher {
255adfc5217SJeff Kirsher 	u32 diff;
256adfc5217SJeff Kirsher 
257adfc5217SJeff Kirsher 	/* The ring uses 256 indices for 255 entries, one of them
258adfc5217SJeff Kirsher 	 * needs to be skipped.
259adfc5217SJeff Kirsher 	 */
260b668534cSEric Dumazet 	diff = READ_ONCE(txr->tx_prod) - READ_ONCE(txr->tx_cons);
2612bc4078eSMichael Chan 	if (unlikely(diff >= BNX2_TX_DESC_CNT)) {
262adfc5217SJeff Kirsher 		diff &= 0xffff;
2632bc4078eSMichael Chan 		if (diff == BNX2_TX_DESC_CNT)
2642bc4078eSMichael Chan 			diff = BNX2_MAX_TX_DESC_CNT;
265adfc5217SJeff Kirsher 	}
266adfc5217SJeff Kirsher 	return bp->tx_ring_size - diff;
267adfc5217SJeff Kirsher }
268adfc5217SJeff Kirsher 
269adfc5217SJeff Kirsher static u32
270adfc5217SJeff Kirsher bnx2_reg_rd_ind(struct bnx2 *bp, u32 offset)
271adfc5217SJeff Kirsher {
2726bc80629SIvan Vecera 	unsigned long flags;
273adfc5217SJeff Kirsher 	u32 val;
274adfc5217SJeff Kirsher 
2756bc80629SIvan Vecera 	spin_lock_irqsave(&bp->indirect_lock, flags);
276e503e066SMichael Chan 	BNX2_WR(bp, BNX2_PCICFG_REG_WINDOW_ADDRESS, offset);
277e503e066SMichael Chan 	val = BNX2_RD(bp, BNX2_PCICFG_REG_WINDOW);
2786bc80629SIvan Vecera 	spin_unlock_irqrestore(&bp->indirect_lock, flags);
279adfc5217SJeff Kirsher 	return val;
280adfc5217SJeff Kirsher }
281adfc5217SJeff Kirsher 
282adfc5217SJeff Kirsher static void
283adfc5217SJeff Kirsher bnx2_reg_wr_ind(struct bnx2 *bp, u32 offset, u32 val)
284adfc5217SJeff Kirsher {
2856bc80629SIvan Vecera 	unsigned long flags;
2866bc80629SIvan Vecera 
2876bc80629SIvan Vecera 	spin_lock_irqsave(&bp->indirect_lock, flags);
288e503e066SMichael Chan 	BNX2_WR(bp, BNX2_PCICFG_REG_WINDOW_ADDRESS, offset);
289e503e066SMichael Chan 	BNX2_WR(bp, BNX2_PCICFG_REG_WINDOW, val);
2906bc80629SIvan Vecera 	spin_unlock_irqrestore(&bp->indirect_lock, flags);
291adfc5217SJeff Kirsher }
292adfc5217SJeff Kirsher 
293adfc5217SJeff Kirsher static void
294adfc5217SJeff Kirsher bnx2_shmem_wr(struct bnx2 *bp, u32 offset, u32 val)
295adfc5217SJeff Kirsher {
296adfc5217SJeff Kirsher 	bnx2_reg_wr_ind(bp, bp->shmem_base + offset, val);
297adfc5217SJeff Kirsher }
298adfc5217SJeff Kirsher 
299adfc5217SJeff Kirsher static u32
300adfc5217SJeff Kirsher bnx2_shmem_rd(struct bnx2 *bp, u32 offset)
301adfc5217SJeff Kirsher {
302adfc5217SJeff Kirsher 	return bnx2_reg_rd_ind(bp, bp->shmem_base + offset);
303adfc5217SJeff Kirsher }
304adfc5217SJeff Kirsher 
305adfc5217SJeff Kirsher static void
306adfc5217SJeff Kirsher bnx2_ctx_wr(struct bnx2 *bp, u32 cid_addr, u32 offset, u32 val)
307adfc5217SJeff Kirsher {
3086bc80629SIvan Vecera 	unsigned long flags;
3096bc80629SIvan Vecera 
310adfc5217SJeff Kirsher 	offset += cid_addr;
3116bc80629SIvan Vecera 	spin_lock_irqsave(&bp->indirect_lock, flags);
3124ce45e02SMichael Chan 	if (BNX2_CHIP(bp) == BNX2_CHIP_5709) {
313adfc5217SJeff Kirsher 		int i;
314adfc5217SJeff Kirsher 
315e503e066SMichael Chan 		BNX2_WR(bp, BNX2_CTX_CTX_DATA, val);
316e503e066SMichael Chan 		BNX2_WR(bp, BNX2_CTX_CTX_CTRL,
317adfc5217SJeff Kirsher 			offset | BNX2_CTX_CTX_CTRL_WRITE_REQ);
318adfc5217SJeff Kirsher 		for (i = 0; i < 5; i++) {
319e503e066SMichael Chan 			val = BNX2_RD(bp, BNX2_CTX_CTX_CTRL);
320adfc5217SJeff Kirsher 			if ((val & BNX2_CTX_CTX_CTRL_WRITE_REQ) == 0)
321adfc5217SJeff Kirsher 				break;
322adfc5217SJeff Kirsher 			udelay(5);
323adfc5217SJeff Kirsher 		}
324adfc5217SJeff Kirsher 	} else {
325e503e066SMichael Chan 		BNX2_WR(bp, BNX2_CTX_DATA_ADR, offset);
326e503e066SMichael Chan 		BNX2_WR(bp, BNX2_CTX_DATA, val);
327adfc5217SJeff Kirsher 	}
3286bc80629SIvan Vecera 	spin_unlock_irqrestore(&bp->indirect_lock, flags);
329adfc5217SJeff Kirsher }
330adfc5217SJeff Kirsher 
331adfc5217SJeff Kirsher #ifdef BCM_CNIC
332adfc5217SJeff Kirsher static int
333adfc5217SJeff Kirsher bnx2_drv_ctl(struct net_device *dev, struct drv_ctl_info *info)
334adfc5217SJeff Kirsher {
335adfc5217SJeff Kirsher 	struct bnx2 *bp = netdev_priv(dev);
336adfc5217SJeff Kirsher 	struct drv_ctl_io *io = &info->data.io;
337adfc5217SJeff Kirsher 
338adfc5217SJeff Kirsher 	switch (info->cmd) {
339adfc5217SJeff Kirsher 	case DRV_CTL_IO_WR_CMD:
340adfc5217SJeff Kirsher 		bnx2_reg_wr_ind(bp, io->offset, io->data);
341adfc5217SJeff Kirsher 		break;
342adfc5217SJeff Kirsher 	case DRV_CTL_IO_RD_CMD:
343adfc5217SJeff Kirsher 		io->data = bnx2_reg_rd_ind(bp, io->offset);
344adfc5217SJeff Kirsher 		break;
345adfc5217SJeff Kirsher 	case DRV_CTL_CTX_WR_CMD:
346adfc5217SJeff Kirsher 		bnx2_ctx_wr(bp, io->cid_addr, io->offset, io->data);
347adfc5217SJeff Kirsher 		break;
348adfc5217SJeff Kirsher 	default:
349adfc5217SJeff Kirsher 		return -EINVAL;
350adfc5217SJeff Kirsher 	}
351adfc5217SJeff Kirsher 	return 0;
352adfc5217SJeff Kirsher }
353adfc5217SJeff Kirsher 
354adfc5217SJeff Kirsher static void bnx2_setup_cnic_irq_info(struct bnx2 *bp)
355adfc5217SJeff Kirsher {
356adfc5217SJeff Kirsher 	struct cnic_eth_dev *cp = &bp->cnic_eth_dev;
357adfc5217SJeff Kirsher 	struct bnx2_napi *bnapi = &bp->bnx2_napi[0];
358adfc5217SJeff Kirsher 	int sb_id;
359adfc5217SJeff Kirsher 
360adfc5217SJeff Kirsher 	if (bp->flags & BNX2_FLAG_USING_MSIX) {
361adfc5217SJeff Kirsher 		cp->drv_state |= CNIC_DRV_STATE_USING_MSIX;
362adfc5217SJeff Kirsher 		bnapi->cnic_present = 0;
363adfc5217SJeff Kirsher 		sb_id = bp->irq_nvecs;
364adfc5217SJeff Kirsher 		cp->irq_arr[0].irq_flags |= CNIC_IRQ_FL_MSIX;
365adfc5217SJeff Kirsher 	} else {
366adfc5217SJeff Kirsher 		cp->drv_state &= ~CNIC_DRV_STATE_USING_MSIX;
367adfc5217SJeff Kirsher 		bnapi->cnic_tag = bnapi->last_status_idx;
368adfc5217SJeff Kirsher 		bnapi->cnic_present = 1;
369adfc5217SJeff Kirsher 		sb_id = 0;
370adfc5217SJeff Kirsher 		cp->irq_arr[0].irq_flags &= ~CNIC_IRQ_FL_MSIX;
371adfc5217SJeff Kirsher 	}
372adfc5217SJeff Kirsher 
373adfc5217SJeff Kirsher 	cp->irq_arr[0].vector = bp->irq_tbl[sb_id].vector;
374adfc5217SJeff Kirsher 	cp->irq_arr[0].status_blk = (void *)
375adfc5217SJeff Kirsher 		((unsigned long) bnapi->status_blk.msi +
376adfc5217SJeff Kirsher 		(BNX2_SBLK_MSIX_ALIGN_SIZE * sb_id));
377adfc5217SJeff Kirsher 	cp->irq_arr[0].status_blk_num = sb_id;
378adfc5217SJeff Kirsher 	cp->num_irq = 1;
379adfc5217SJeff Kirsher }
380adfc5217SJeff Kirsher 
381adfc5217SJeff Kirsher static int bnx2_register_cnic(struct net_device *dev, struct cnic_ops *ops,
382adfc5217SJeff Kirsher 			      void *data)
383adfc5217SJeff Kirsher {
384adfc5217SJeff Kirsher 	struct bnx2 *bp = netdev_priv(dev);
385adfc5217SJeff Kirsher 	struct cnic_eth_dev *cp = &bp->cnic_eth_dev;
386adfc5217SJeff Kirsher 
387b8aac410SVarsha Rao 	if (!ops)
388adfc5217SJeff Kirsher 		return -EINVAL;
389adfc5217SJeff Kirsher 
390adfc5217SJeff Kirsher 	if (cp->drv_state & CNIC_DRV_STATE_REGD)
391adfc5217SJeff Kirsher 		return -EBUSY;
392adfc5217SJeff Kirsher 
393adfc5217SJeff Kirsher 	if (!bnx2_reg_rd_ind(bp, BNX2_FW_MAX_ISCSI_CONN))
394adfc5217SJeff Kirsher 		return -ENODEV;
395adfc5217SJeff Kirsher 
396adfc5217SJeff Kirsher 	bp->cnic_data = data;
397adfc5217SJeff Kirsher 	rcu_assign_pointer(bp->cnic_ops, ops);
398adfc5217SJeff Kirsher 
399adfc5217SJeff Kirsher 	cp->num_irq = 0;
400adfc5217SJeff Kirsher 	cp->drv_state = CNIC_DRV_STATE_REGD;
401adfc5217SJeff Kirsher 
402adfc5217SJeff Kirsher 	bnx2_setup_cnic_irq_info(bp);
403adfc5217SJeff Kirsher 
404adfc5217SJeff Kirsher 	return 0;
405adfc5217SJeff Kirsher }
406adfc5217SJeff Kirsher 
407adfc5217SJeff Kirsher static int bnx2_unregister_cnic(struct net_device *dev)
408adfc5217SJeff Kirsher {
409adfc5217SJeff Kirsher 	struct bnx2 *bp = netdev_priv(dev);
410adfc5217SJeff Kirsher 	struct bnx2_napi *bnapi = &bp->bnx2_napi[0];
411adfc5217SJeff Kirsher 	struct cnic_eth_dev *cp = &bp->cnic_eth_dev;
412adfc5217SJeff Kirsher 
413adfc5217SJeff Kirsher 	mutex_lock(&bp->cnic_lock);
414adfc5217SJeff Kirsher 	cp->drv_state = 0;
415adfc5217SJeff Kirsher 	bnapi->cnic_present = 0;
4162cfa5a04SEric Dumazet 	RCU_INIT_POINTER(bp->cnic_ops, NULL);
417adfc5217SJeff Kirsher 	mutex_unlock(&bp->cnic_lock);
418adfc5217SJeff Kirsher 	synchronize_rcu();
419adfc5217SJeff Kirsher 	return 0;
420adfc5217SJeff Kirsher }
421adfc5217SJeff Kirsher 
42261c2fc4bSstephen hemminger static struct cnic_eth_dev *bnx2_cnic_probe(struct net_device *dev)
423adfc5217SJeff Kirsher {
424adfc5217SJeff Kirsher 	struct bnx2 *bp = netdev_priv(dev);
425adfc5217SJeff Kirsher 	struct cnic_eth_dev *cp = &bp->cnic_eth_dev;
426adfc5217SJeff Kirsher 
427adfc5217SJeff Kirsher 	if (!cp->max_iscsi_conn)
428adfc5217SJeff Kirsher 		return NULL;
429adfc5217SJeff Kirsher 
430adfc5217SJeff Kirsher 	cp->drv_owner = THIS_MODULE;
431adfc5217SJeff Kirsher 	cp->chip_id = bp->chip_id;
432adfc5217SJeff Kirsher 	cp->pdev = bp->pdev;
433adfc5217SJeff Kirsher 	cp->io_base = bp->regview;
434adfc5217SJeff Kirsher 	cp->drv_ctl = bnx2_drv_ctl;
435adfc5217SJeff Kirsher 	cp->drv_register_cnic = bnx2_register_cnic;
436adfc5217SJeff Kirsher 	cp->drv_unregister_cnic = bnx2_unregister_cnic;
437adfc5217SJeff Kirsher 
438adfc5217SJeff Kirsher 	return cp;
439adfc5217SJeff Kirsher }
440adfc5217SJeff Kirsher 
441adfc5217SJeff Kirsher static void
442adfc5217SJeff Kirsher bnx2_cnic_stop(struct bnx2 *bp)
443adfc5217SJeff Kirsher {
444adfc5217SJeff Kirsher 	struct cnic_ops *c_ops;
445adfc5217SJeff Kirsher 	struct cnic_ctl_info info;
446adfc5217SJeff Kirsher 
447adfc5217SJeff Kirsher 	mutex_lock(&bp->cnic_lock);
448adfc5217SJeff Kirsher 	c_ops = rcu_dereference_protected(bp->cnic_ops,
449adfc5217SJeff Kirsher 					  lockdep_is_held(&bp->cnic_lock));
450adfc5217SJeff Kirsher 	if (c_ops) {
451adfc5217SJeff Kirsher 		info.cmd = CNIC_CTL_STOP_CMD;
452adfc5217SJeff Kirsher 		c_ops->cnic_ctl(bp->cnic_data, &info);
453adfc5217SJeff Kirsher 	}
454adfc5217SJeff Kirsher 	mutex_unlock(&bp->cnic_lock);
455adfc5217SJeff Kirsher }
456adfc5217SJeff Kirsher 
457adfc5217SJeff Kirsher static void
458adfc5217SJeff Kirsher bnx2_cnic_start(struct bnx2 *bp)
459adfc5217SJeff Kirsher {
460adfc5217SJeff Kirsher 	struct cnic_ops *c_ops;
461adfc5217SJeff Kirsher 	struct cnic_ctl_info info;
462adfc5217SJeff Kirsher 
463adfc5217SJeff Kirsher 	mutex_lock(&bp->cnic_lock);
464adfc5217SJeff Kirsher 	c_ops = rcu_dereference_protected(bp->cnic_ops,
465adfc5217SJeff Kirsher 					  lockdep_is_held(&bp->cnic_lock));
466adfc5217SJeff Kirsher 	if (c_ops) {
467adfc5217SJeff Kirsher 		if (!(bp->flags & BNX2_FLAG_USING_MSIX)) {
468adfc5217SJeff Kirsher 			struct bnx2_napi *bnapi = &bp->bnx2_napi[0];
469adfc5217SJeff Kirsher 
470adfc5217SJeff Kirsher 			bnapi->cnic_tag = bnapi->last_status_idx;
471adfc5217SJeff Kirsher 		}
472adfc5217SJeff Kirsher 		info.cmd = CNIC_CTL_START_CMD;
473adfc5217SJeff Kirsher 		c_ops->cnic_ctl(bp->cnic_data, &info);
474adfc5217SJeff Kirsher 	}
475adfc5217SJeff Kirsher 	mutex_unlock(&bp->cnic_lock);
476adfc5217SJeff Kirsher }
477adfc5217SJeff Kirsher 
478adfc5217SJeff Kirsher #else
479adfc5217SJeff Kirsher 
480adfc5217SJeff Kirsher static void
481adfc5217SJeff Kirsher bnx2_cnic_stop(struct bnx2 *bp)
482adfc5217SJeff Kirsher {
483adfc5217SJeff Kirsher }
484adfc5217SJeff Kirsher 
485adfc5217SJeff Kirsher static void
486adfc5217SJeff Kirsher bnx2_cnic_start(struct bnx2 *bp)
487adfc5217SJeff Kirsher {
488adfc5217SJeff Kirsher }
489adfc5217SJeff Kirsher 
490adfc5217SJeff Kirsher #endif
491adfc5217SJeff Kirsher 
492adfc5217SJeff Kirsher static int
493adfc5217SJeff Kirsher bnx2_read_phy(struct bnx2 *bp, u32 reg, u32 *val)
494adfc5217SJeff Kirsher {
495adfc5217SJeff Kirsher 	u32 val1;
496adfc5217SJeff Kirsher 	int i, ret;
497adfc5217SJeff Kirsher 
498adfc5217SJeff Kirsher 	if (bp->phy_flags & BNX2_PHY_FLAG_INT_MODE_AUTO_POLLING) {
499e503e066SMichael Chan 		val1 = BNX2_RD(bp, BNX2_EMAC_MDIO_MODE);
500adfc5217SJeff Kirsher 		val1 &= ~BNX2_EMAC_MDIO_MODE_AUTO_POLL;
501adfc5217SJeff Kirsher 
502e503e066SMichael Chan 		BNX2_WR(bp, BNX2_EMAC_MDIO_MODE, val1);
503e503e066SMichael Chan 		BNX2_RD(bp, BNX2_EMAC_MDIO_MODE);
504adfc5217SJeff Kirsher 
505adfc5217SJeff Kirsher 		udelay(40);
506adfc5217SJeff Kirsher 	}
507adfc5217SJeff Kirsher 
508adfc5217SJeff Kirsher 	val1 = (bp->phy_addr << 21) | (reg << 16) |
509adfc5217SJeff Kirsher 		BNX2_EMAC_MDIO_COMM_COMMAND_READ | BNX2_EMAC_MDIO_COMM_DISEXT |
510adfc5217SJeff Kirsher 		BNX2_EMAC_MDIO_COMM_START_BUSY;
511e503e066SMichael Chan 	BNX2_WR(bp, BNX2_EMAC_MDIO_COMM, val1);
512adfc5217SJeff Kirsher 
513adfc5217SJeff Kirsher 	for (i = 0; i < 50; i++) {
514adfc5217SJeff Kirsher 		udelay(10);
515adfc5217SJeff Kirsher 
516e503e066SMichael Chan 		val1 = BNX2_RD(bp, BNX2_EMAC_MDIO_COMM);
517adfc5217SJeff Kirsher 		if (!(val1 & BNX2_EMAC_MDIO_COMM_START_BUSY)) {
518adfc5217SJeff Kirsher 			udelay(5);
519adfc5217SJeff Kirsher 
520e503e066SMichael Chan 			val1 = BNX2_RD(bp, BNX2_EMAC_MDIO_COMM);
521adfc5217SJeff Kirsher 			val1 &= BNX2_EMAC_MDIO_COMM_DATA;
522adfc5217SJeff Kirsher 
523adfc5217SJeff Kirsher 			break;
524adfc5217SJeff Kirsher 		}
525adfc5217SJeff Kirsher 	}
526adfc5217SJeff Kirsher 
527adfc5217SJeff Kirsher 	if (val1 & BNX2_EMAC_MDIO_COMM_START_BUSY) {
528adfc5217SJeff Kirsher 		*val = 0x0;
529adfc5217SJeff Kirsher 		ret = -EBUSY;
530adfc5217SJeff Kirsher 	}
531adfc5217SJeff Kirsher 	else {
532adfc5217SJeff Kirsher 		*val = val1;
533adfc5217SJeff Kirsher 		ret = 0;
534adfc5217SJeff Kirsher 	}
535adfc5217SJeff Kirsher 
536adfc5217SJeff Kirsher 	if (bp->phy_flags & BNX2_PHY_FLAG_INT_MODE_AUTO_POLLING) {
537e503e066SMichael Chan 		val1 = BNX2_RD(bp, BNX2_EMAC_MDIO_MODE);
538adfc5217SJeff Kirsher 		val1 |= BNX2_EMAC_MDIO_MODE_AUTO_POLL;
539adfc5217SJeff Kirsher 
540e503e066SMichael Chan 		BNX2_WR(bp, BNX2_EMAC_MDIO_MODE, val1);
541e503e066SMichael Chan 		BNX2_RD(bp, BNX2_EMAC_MDIO_MODE);
542adfc5217SJeff Kirsher 
543adfc5217SJeff Kirsher 		udelay(40);
544adfc5217SJeff Kirsher 	}
545adfc5217SJeff Kirsher 
546adfc5217SJeff Kirsher 	return ret;
547adfc5217SJeff Kirsher }
548adfc5217SJeff Kirsher 
549adfc5217SJeff Kirsher static int
550adfc5217SJeff Kirsher bnx2_write_phy(struct bnx2 *bp, u32 reg, u32 val)
551adfc5217SJeff Kirsher {
552adfc5217SJeff Kirsher 	u32 val1;
553adfc5217SJeff Kirsher 	int i, ret;
554adfc5217SJeff Kirsher 
555adfc5217SJeff Kirsher 	if (bp->phy_flags & BNX2_PHY_FLAG_INT_MODE_AUTO_POLLING) {
556e503e066SMichael Chan 		val1 = BNX2_RD(bp, BNX2_EMAC_MDIO_MODE);
557adfc5217SJeff Kirsher 		val1 &= ~BNX2_EMAC_MDIO_MODE_AUTO_POLL;
558adfc5217SJeff Kirsher 
559e503e066SMichael Chan 		BNX2_WR(bp, BNX2_EMAC_MDIO_MODE, val1);
560e503e066SMichael Chan 		BNX2_RD(bp, BNX2_EMAC_MDIO_MODE);
561adfc5217SJeff Kirsher 
562adfc5217SJeff Kirsher 		udelay(40);
563adfc5217SJeff Kirsher 	}
564adfc5217SJeff Kirsher 
565adfc5217SJeff Kirsher 	val1 = (bp->phy_addr << 21) | (reg << 16) | val |
566adfc5217SJeff Kirsher 		BNX2_EMAC_MDIO_COMM_COMMAND_WRITE |
567adfc5217SJeff Kirsher 		BNX2_EMAC_MDIO_COMM_START_BUSY | BNX2_EMAC_MDIO_COMM_DISEXT;
568e503e066SMichael Chan 	BNX2_WR(bp, BNX2_EMAC_MDIO_COMM, val1);
569adfc5217SJeff Kirsher 
570adfc5217SJeff Kirsher 	for (i = 0; i < 50; i++) {
571adfc5217SJeff Kirsher 		udelay(10);
572adfc5217SJeff Kirsher 
573e503e066SMichael Chan 		val1 = BNX2_RD(bp, BNX2_EMAC_MDIO_COMM);
574adfc5217SJeff Kirsher 		if (!(val1 & BNX2_EMAC_MDIO_COMM_START_BUSY)) {
575adfc5217SJeff Kirsher 			udelay(5);
576adfc5217SJeff Kirsher 			break;
577adfc5217SJeff Kirsher 		}
578adfc5217SJeff Kirsher 	}
579adfc5217SJeff Kirsher 
580adfc5217SJeff Kirsher 	if (val1 & BNX2_EMAC_MDIO_COMM_START_BUSY)
581adfc5217SJeff Kirsher         	ret = -EBUSY;
582adfc5217SJeff Kirsher 	else
583adfc5217SJeff Kirsher 		ret = 0;
584adfc5217SJeff Kirsher 
585adfc5217SJeff Kirsher 	if (bp->phy_flags & BNX2_PHY_FLAG_INT_MODE_AUTO_POLLING) {
586e503e066SMichael Chan 		val1 = BNX2_RD(bp, BNX2_EMAC_MDIO_MODE);
587adfc5217SJeff Kirsher 		val1 |= BNX2_EMAC_MDIO_MODE_AUTO_POLL;
588adfc5217SJeff Kirsher 
589e503e066SMichael Chan 		BNX2_WR(bp, BNX2_EMAC_MDIO_MODE, val1);
590e503e066SMichael Chan 		BNX2_RD(bp, BNX2_EMAC_MDIO_MODE);
591adfc5217SJeff Kirsher 
592adfc5217SJeff Kirsher 		udelay(40);
593adfc5217SJeff Kirsher 	}
594adfc5217SJeff Kirsher 
595adfc5217SJeff Kirsher 	return ret;
596adfc5217SJeff Kirsher }
597adfc5217SJeff Kirsher 
598adfc5217SJeff Kirsher static void
599adfc5217SJeff Kirsher bnx2_disable_int(struct bnx2 *bp)
600adfc5217SJeff Kirsher {
601adfc5217SJeff Kirsher 	int i;
602adfc5217SJeff Kirsher 	struct bnx2_napi *bnapi;
603adfc5217SJeff Kirsher 
604adfc5217SJeff Kirsher 	for (i = 0; i < bp->irq_nvecs; i++) {
605adfc5217SJeff Kirsher 		bnapi = &bp->bnx2_napi[i];
606e503e066SMichael Chan 		BNX2_WR(bp, BNX2_PCICFG_INT_ACK_CMD, bnapi->int_num |
607adfc5217SJeff Kirsher 		       BNX2_PCICFG_INT_ACK_CMD_MASK_INT);
608adfc5217SJeff Kirsher 	}
609e503e066SMichael Chan 	BNX2_RD(bp, BNX2_PCICFG_INT_ACK_CMD);
610adfc5217SJeff Kirsher }
611adfc5217SJeff Kirsher 
612adfc5217SJeff Kirsher static void
613adfc5217SJeff Kirsher bnx2_enable_int(struct bnx2 *bp)
614adfc5217SJeff Kirsher {
615adfc5217SJeff Kirsher 	int i;
616adfc5217SJeff Kirsher 	struct bnx2_napi *bnapi;
617adfc5217SJeff Kirsher 
618adfc5217SJeff Kirsher 	for (i = 0; i < bp->irq_nvecs; i++) {
619adfc5217SJeff Kirsher 		bnapi = &bp->bnx2_napi[i];
620adfc5217SJeff Kirsher 
621e503e066SMichael Chan 		BNX2_WR(bp, BNX2_PCICFG_INT_ACK_CMD, bnapi->int_num |
622adfc5217SJeff Kirsher 			BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
623adfc5217SJeff Kirsher 			BNX2_PCICFG_INT_ACK_CMD_MASK_INT |
624adfc5217SJeff Kirsher 			bnapi->last_status_idx);
625adfc5217SJeff Kirsher 
626e503e066SMichael Chan 		BNX2_WR(bp, BNX2_PCICFG_INT_ACK_CMD, bnapi->int_num |
627adfc5217SJeff Kirsher 			BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
628adfc5217SJeff Kirsher 			bnapi->last_status_idx);
629adfc5217SJeff Kirsher 	}
630e503e066SMichael Chan 	BNX2_WR(bp, BNX2_HC_COMMAND, bp->hc_cmd | BNX2_HC_COMMAND_COAL_NOW);
631adfc5217SJeff Kirsher }
632adfc5217SJeff Kirsher 
633adfc5217SJeff Kirsher static void
634adfc5217SJeff Kirsher bnx2_disable_int_sync(struct bnx2 *bp)
635adfc5217SJeff Kirsher {
636adfc5217SJeff Kirsher 	int i;
637adfc5217SJeff Kirsher 
638adfc5217SJeff Kirsher 	atomic_inc(&bp->intr_sem);
639adfc5217SJeff Kirsher 	if (!netif_running(bp->dev))
640adfc5217SJeff Kirsher 		return;
641adfc5217SJeff Kirsher 
642adfc5217SJeff Kirsher 	bnx2_disable_int(bp);
643adfc5217SJeff Kirsher 	for (i = 0; i < bp->irq_nvecs; i++)
644adfc5217SJeff Kirsher 		synchronize_irq(bp->irq_tbl[i].vector);
645adfc5217SJeff Kirsher }
646adfc5217SJeff Kirsher 
647adfc5217SJeff Kirsher static void
648adfc5217SJeff Kirsher bnx2_napi_disable(struct bnx2 *bp)
649adfc5217SJeff Kirsher {
650adfc5217SJeff Kirsher 	int i;
651adfc5217SJeff Kirsher 
652adfc5217SJeff Kirsher 	for (i = 0; i < bp->irq_nvecs; i++)
653adfc5217SJeff Kirsher 		napi_disable(&bp->bnx2_napi[i].napi);
654adfc5217SJeff Kirsher }
655adfc5217SJeff Kirsher 
656adfc5217SJeff Kirsher static void
657adfc5217SJeff Kirsher bnx2_napi_enable(struct bnx2 *bp)
658adfc5217SJeff Kirsher {
659adfc5217SJeff Kirsher 	int i;
660adfc5217SJeff Kirsher 
661adfc5217SJeff Kirsher 	for (i = 0; i < bp->irq_nvecs; i++)
662adfc5217SJeff Kirsher 		napi_enable(&bp->bnx2_napi[i].napi);
663adfc5217SJeff Kirsher }
664adfc5217SJeff Kirsher 
665adfc5217SJeff Kirsher static void
666adfc5217SJeff Kirsher bnx2_netif_stop(struct bnx2 *bp, bool stop_cnic)
667adfc5217SJeff Kirsher {
668adfc5217SJeff Kirsher 	if (stop_cnic)
669adfc5217SJeff Kirsher 		bnx2_cnic_stop(bp);
670adfc5217SJeff Kirsher 	if (netif_running(bp->dev)) {
671adfc5217SJeff Kirsher 		bnx2_napi_disable(bp);
672adfc5217SJeff Kirsher 		netif_tx_disable(bp->dev);
673adfc5217SJeff Kirsher 	}
674adfc5217SJeff Kirsher 	bnx2_disable_int_sync(bp);
675adfc5217SJeff Kirsher 	netif_carrier_off(bp->dev);	/* prevent tx timeout */
676adfc5217SJeff Kirsher }
677adfc5217SJeff Kirsher 
678adfc5217SJeff Kirsher static void
679adfc5217SJeff Kirsher bnx2_netif_start(struct bnx2 *bp, bool start_cnic)
680adfc5217SJeff Kirsher {
681adfc5217SJeff Kirsher 	if (atomic_dec_and_test(&bp->intr_sem)) {
682adfc5217SJeff Kirsher 		if (netif_running(bp->dev)) {
683adfc5217SJeff Kirsher 			netif_tx_wake_all_queues(bp->dev);
684adfc5217SJeff Kirsher 			spin_lock_bh(&bp->phy_lock);
685adfc5217SJeff Kirsher 			if (bp->link_up)
686adfc5217SJeff Kirsher 				netif_carrier_on(bp->dev);
687adfc5217SJeff Kirsher 			spin_unlock_bh(&bp->phy_lock);
688adfc5217SJeff Kirsher 			bnx2_napi_enable(bp);
689adfc5217SJeff Kirsher 			bnx2_enable_int(bp);
690adfc5217SJeff Kirsher 			if (start_cnic)
691adfc5217SJeff Kirsher 				bnx2_cnic_start(bp);
692adfc5217SJeff Kirsher 		}
693adfc5217SJeff Kirsher 	}
694adfc5217SJeff Kirsher }
695adfc5217SJeff Kirsher 
696adfc5217SJeff Kirsher static void
697adfc5217SJeff Kirsher bnx2_free_tx_mem(struct bnx2 *bp)
698adfc5217SJeff Kirsher {
699adfc5217SJeff Kirsher 	int i;
700adfc5217SJeff Kirsher 
701adfc5217SJeff Kirsher 	for (i = 0; i < bp->num_tx_rings; i++) {
702adfc5217SJeff Kirsher 		struct bnx2_napi *bnapi = &bp->bnx2_napi[i];
703adfc5217SJeff Kirsher 		struct bnx2_tx_ring_info *txr = &bnapi->tx_ring;
704adfc5217SJeff Kirsher 
705adfc5217SJeff Kirsher 		if (txr->tx_desc_ring) {
706adfc5217SJeff Kirsher 			dma_free_coherent(&bp->pdev->dev, TXBD_RING_SIZE,
707adfc5217SJeff Kirsher 					  txr->tx_desc_ring,
708adfc5217SJeff Kirsher 					  txr->tx_desc_mapping);
709adfc5217SJeff Kirsher 			txr->tx_desc_ring = NULL;
710adfc5217SJeff Kirsher 		}
711adfc5217SJeff Kirsher 		kfree(txr->tx_buf_ring);
712adfc5217SJeff Kirsher 		txr->tx_buf_ring = NULL;
713adfc5217SJeff Kirsher 	}
714adfc5217SJeff Kirsher }
715adfc5217SJeff Kirsher 
716adfc5217SJeff Kirsher static void
717adfc5217SJeff Kirsher bnx2_free_rx_mem(struct bnx2 *bp)
718adfc5217SJeff Kirsher {
719adfc5217SJeff Kirsher 	int i;
720adfc5217SJeff Kirsher 
721adfc5217SJeff Kirsher 	for (i = 0; i < bp->num_rx_rings; i++) {
722adfc5217SJeff Kirsher 		struct bnx2_napi *bnapi = &bp->bnx2_napi[i];
723adfc5217SJeff Kirsher 		struct bnx2_rx_ring_info *rxr = &bnapi->rx_ring;
724adfc5217SJeff Kirsher 		int j;
725adfc5217SJeff Kirsher 
726adfc5217SJeff Kirsher 		for (j = 0; j < bp->rx_max_ring; j++) {
727adfc5217SJeff Kirsher 			if (rxr->rx_desc_ring[j])
728adfc5217SJeff Kirsher 				dma_free_coherent(&bp->pdev->dev, RXBD_RING_SIZE,
729adfc5217SJeff Kirsher 						  rxr->rx_desc_ring[j],
730adfc5217SJeff Kirsher 						  rxr->rx_desc_mapping[j]);
731adfc5217SJeff Kirsher 			rxr->rx_desc_ring[j] = NULL;
732adfc5217SJeff Kirsher 		}
733adfc5217SJeff Kirsher 		vfree(rxr->rx_buf_ring);
734adfc5217SJeff Kirsher 		rxr->rx_buf_ring = NULL;
735adfc5217SJeff Kirsher 
736adfc5217SJeff Kirsher 		for (j = 0; j < bp->rx_max_pg_ring; j++) {
737adfc5217SJeff Kirsher 			if (rxr->rx_pg_desc_ring[j])
738adfc5217SJeff Kirsher 				dma_free_coherent(&bp->pdev->dev, RXBD_RING_SIZE,
739adfc5217SJeff Kirsher 						  rxr->rx_pg_desc_ring[j],
740adfc5217SJeff Kirsher 						  rxr->rx_pg_desc_mapping[j]);
741adfc5217SJeff Kirsher 			rxr->rx_pg_desc_ring[j] = NULL;
742adfc5217SJeff Kirsher 		}
743adfc5217SJeff Kirsher 		vfree(rxr->rx_pg_ring);
744adfc5217SJeff Kirsher 		rxr->rx_pg_ring = NULL;
745adfc5217SJeff Kirsher 	}
746adfc5217SJeff Kirsher }
747adfc5217SJeff Kirsher 
748adfc5217SJeff Kirsher static int
749adfc5217SJeff Kirsher bnx2_alloc_tx_mem(struct bnx2 *bp)
750adfc5217SJeff Kirsher {
751adfc5217SJeff Kirsher 	int i;
752adfc5217SJeff Kirsher 
753adfc5217SJeff Kirsher 	for (i = 0; i < bp->num_tx_rings; i++) {
754adfc5217SJeff Kirsher 		struct bnx2_napi *bnapi = &bp->bnx2_napi[i];
755adfc5217SJeff Kirsher 		struct bnx2_tx_ring_info *txr = &bnapi->tx_ring;
756adfc5217SJeff Kirsher 
757adfc5217SJeff Kirsher 		txr->tx_buf_ring = kzalloc(SW_TXBD_RING_SIZE, GFP_KERNEL);
758b8aac410SVarsha Rao 		if (!txr->tx_buf_ring)
759adfc5217SJeff Kirsher 			return -ENOMEM;
760adfc5217SJeff Kirsher 
761adfc5217SJeff Kirsher 		txr->tx_desc_ring =
762adfc5217SJeff Kirsher 			dma_alloc_coherent(&bp->pdev->dev, TXBD_RING_SIZE,
763adfc5217SJeff Kirsher 					   &txr->tx_desc_mapping, GFP_KERNEL);
764b8aac410SVarsha Rao 		if (!txr->tx_desc_ring)
765adfc5217SJeff Kirsher 			return -ENOMEM;
766adfc5217SJeff Kirsher 	}
767adfc5217SJeff Kirsher 	return 0;
768adfc5217SJeff Kirsher }
769adfc5217SJeff Kirsher 
770adfc5217SJeff Kirsher static int
771adfc5217SJeff Kirsher bnx2_alloc_rx_mem(struct bnx2 *bp)
772adfc5217SJeff Kirsher {
773adfc5217SJeff Kirsher 	int i;
774adfc5217SJeff Kirsher 
775adfc5217SJeff Kirsher 	for (i = 0; i < bp->num_rx_rings; i++) {
776adfc5217SJeff Kirsher 		struct bnx2_napi *bnapi = &bp->bnx2_napi[i];
777adfc5217SJeff Kirsher 		struct bnx2_rx_ring_info *rxr = &bnapi->rx_ring;
778adfc5217SJeff Kirsher 		int j;
779adfc5217SJeff Kirsher 
780adfc5217SJeff Kirsher 		rxr->rx_buf_ring =
781adfc5217SJeff Kirsher 			vzalloc(SW_RXBD_RING_SIZE * bp->rx_max_ring);
782b8aac410SVarsha Rao 		if (!rxr->rx_buf_ring)
783adfc5217SJeff Kirsher 			return -ENOMEM;
784adfc5217SJeff Kirsher 
785adfc5217SJeff Kirsher 		for (j = 0; j < bp->rx_max_ring; j++) {
786adfc5217SJeff Kirsher 			rxr->rx_desc_ring[j] =
787adfc5217SJeff Kirsher 				dma_alloc_coherent(&bp->pdev->dev,
788adfc5217SJeff Kirsher 						   RXBD_RING_SIZE,
789adfc5217SJeff Kirsher 						   &rxr->rx_desc_mapping[j],
790adfc5217SJeff Kirsher 						   GFP_KERNEL);
791b8aac410SVarsha Rao 			if (!rxr->rx_desc_ring[j])
792adfc5217SJeff Kirsher 				return -ENOMEM;
793adfc5217SJeff Kirsher 
794adfc5217SJeff Kirsher 		}
795adfc5217SJeff Kirsher 
796adfc5217SJeff Kirsher 		if (bp->rx_pg_ring_size) {
797adfc5217SJeff Kirsher 			rxr->rx_pg_ring = vzalloc(SW_RXPG_RING_SIZE *
798adfc5217SJeff Kirsher 						  bp->rx_max_pg_ring);
799b8aac410SVarsha Rao 			if (!rxr->rx_pg_ring)
800adfc5217SJeff Kirsher 				return -ENOMEM;
801adfc5217SJeff Kirsher 
802adfc5217SJeff Kirsher 		}
803adfc5217SJeff Kirsher 
804adfc5217SJeff Kirsher 		for (j = 0; j < bp->rx_max_pg_ring; j++) {
805adfc5217SJeff Kirsher 			rxr->rx_pg_desc_ring[j] =
806adfc5217SJeff Kirsher 				dma_alloc_coherent(&bp->pdev->dev,
807adfc5217SJeff Kirsher 						   RXBD_RING_SIZE,
808adfc5217SJeff Kirsher 						   &rxr->rx_pg_desc_mapping[j],
809adfc5217SJeff Kirsher 						   GFP_KERNEL);
810b8aac410SVarsha Rao 			if (!rxr->rx_pg_desc_ring[j])
811adfc5217SJeff Kirsher 				return -ENOMEM;
812adfc5217SJeff Kirsher 
813adfc5217SJeff Kirsher 		}
814adfc5217SJeff Kirsher 	}
815adfc5217SJeff Kirsher 	return 0;
816adfc5217SJeff Kirsher }
817adfc5217SJeff Kirsher 
818adfc5217SJeff Kirsher static void
8198fae307cSwangweidong bnx2_free_stats_blk(struct net_device *dev)
8208fae307cSwangweidong {
8218fae307cSwangweidong 	struct bnx2 *bp = netdev_priv(dev);
8228fae307cSwangweidong 
8238fae307cSwangweidong 	if (bp->status_blk) {
8248fae307cSwangweidong 		dma_free_coherent(&bp->pdev->dev, bp->status_stats_size,
8258fae307cSwangweidong 				  bp->status_blk,
8268fae307cSwangweidong 				  bp->status_blk_mapping);
8278fae307cSwangweidong 		bp->status_blk = NULL;
8288fae307cSwangweidong 		bp->stats_blk = NULL;
8298fae307cSwangweidong 	}
8308fae307cSwangweidong }
8318fae307cSwangweidong 
8328fae307cSwangweidong static int
8338fae307cSwangweidong bnx2_alloc_stats_blk(struct net_device *dev)
8348fae307cSwangweidong {
8358fae307cSwangweidong 	int status_blk_size;
8368fae307cSwangweidong 	void *status_blk;
8378fae307cSwangweidong 	struct bnx2 *bp = netdev_priv(dev);
8388fae307cSwangweidong 
8398fae307cSwangweidong 	/* Combine status and statistics blocks into one allocation. */
8408fae307cSwangweidong 	status_blk_size = L1_CACHE_ALIGN(sizeof(struct status_block));
8418fae307cSwangweidong 	if (bp->flags & BNX2_FLAG_MSIX_CAP)
8428fae307cSwangweidong 		status_blk_size = L1_CACHE_ALIGN(BNX2_MAX_MSIX_HW_VEC *
8438fae307cSwangweidong 						 BNX2_SBLK_MSIX_ALIGN_SIZE);
8448fae307cSwangweidong 	bp->status_stats_size = status_blk_size +
8458fae307cSwangweidong 				sizeof(struct statistics_block);
8468fae307cSwangweidong 	status_blk = dma_zalloc_coherent(&bp->pdev->dev, bp->status_stats_size,
8478fae307cSwangweidong 					 &bp->status_blk_mapping, GFP_KERNEL);
848b8aac410SVarsha Rao 	if (!status_blk)
8498fae307cSwangweidong 		return -ENOMEM;
8508fae307cSwangweidong 
8518fae307cSwangweidong 	bp->status_blk = status_blk;
8528fae307cSwangweidong 	bp->stats_blk = status_blk + status_blk_size;
8538fae307cSwangweidong 	bp->stats_blk_mapping = bp->status_blk_mapping + status_blk_size;
8548fae307cSwangweidong 
8558fae307cSwangweidong 	return 0;
8568fae307cSwangweidong }
8578fae307cSwangweidong 
8588fae307cSwangweidong static void
859adfc5217SJeff Kirsher bnx2_free_mem(struct bnx2 *bp)
860adfc5217SJeff Kirsher {
861adfc5217SJeff Kirsher 	int i;
862adfc5217SJeff Kirsher 	struct bnx2_napi *bnapi = &bp->bnx2_napi[0];
863adfc5217SJeff Kirsher 
864adfc5217SJeff Kirsher 	bnx2_free_tx_mem(bp);
865adfc5217SJeff Kirsher 	bnx2_free_rx_mem(bp);
866adfc5217SJeff Kirsher 
867adfc5217SJeff Kirsher 	for (i = 0; i < bp->ctx_pages; i++) {
868adfc5217SJeff Kirsher 		if (bp->ctx_blk[i]) {
8692bc4078eSMichael Chan 			dma_free_coherent(&bp->pdev->dev, BNX2_PAGE_SIZE,
870adfc5217SJeff Kirsher 					  bp->ctx_blk[i],
871adfc5217SJeff Kirsher 					  bp->ctx_blk_mapping[i]);
872adfc5217SJeff Kirsher 			bp->ctx_blk[i] = NULL;
873adfc5217SJeff Kirsher 		}
874adfc5217SJeff Kirsher 	}
8758fae307cSwangweidong 
8768fae307cSwangweidong 	if (bnapi->status_blk.msi)
877adfc5217SJeff Kirsher 		bnapi->status_blk.msi = NULL;
878adfc5217SJeff Kirsher }
879adfc5217SJeff Kirsher 
880adfc5217SJeff Kirsher static int
881adfc5217SJeff Kirsher bnx2_alloc_mem(struct bnx2 *bp)
882adfc5217SJeff Kirsher {
8838fae307cSwangweidong 	int i, err;
884adfc5217SJeff Kirsher 	struct bnx2_napi *bnapi;
885adfc5217SJeff Kirsher 
886adfc5217SJeff Kirsher 	bnapi = &bp->bnx2_napi[0];
8878fae307cSwangweidong 	bnapi->status_blk.msi = bp->status_blk;
888adfc5217SJeff Kirsher 	bnapi->hw_tx_cons_ptr =
889adfc5217SJeff Kirsher 		&bnapi->status_blk.msi->status_tx_quick_consumer_index0;
890adfc5217SJeff Kirsher 	bnapi->hw_rx_cons_ptr =
891adfc5217SJeff Kirsher 		&bnapi->status_blk.msi->status_rx_quick_consumer_index0;
892adfc5217SJeff Kirsher 	if (bp->flags & BNX2_FLAG_MSIX_CAP) {
893adfc5217SJeff Kirsher 		for (i = 1; i < bp->irq_nvecs; i++) {
894adfc5217SJeff Kirsher 			struct status_block_msix *sblk;
895adfc5217SJeff Kirsher 
896adfc5217SJeff Kirsher 			bnapi = &bp->bnx2_napi[i];
897adfc5217SJeff Kirsher 
8988fae307cSwangweidong 			sblk = (bp->status_blk + BNX2_SBLK_MSIX_ALIGN_SIZE * i);
899adfc5217SJeff Kirsher 			bnapi->status_blk.msix = sblk;
900adfc5217SJeff Kirsher 			bnapi->hw_tx_cons_ptr =
901adfc5217SJeff Kirsher 				&sblk->status_tx_quick_consumer_index;
902adfc5217SJeff Kirsher 			bnapi->hw_rx_cons_ptr =
903adfc5217SJeff Kirsher 				&sblk->status_rx_quick_consumer_index;
904adfc5217SJeff Kirsher 			bnapi->int_num = i << 24;
905adfc5217SJeff Kirsher 		}
906adfc5217SJeff Kirsher 	}
907adfc5217SJeff Kirsher 
9084ce45e02SMichael Chan 	if (BNX2_CHIP(bp) == BNX2_CHIP_5709) {
9092bc4078eSMichael Chan 		bp->ctx_pages = 0x2000 / BNX2_PAGE_SIZE;
910adfc5217SJeff Kirsher 		if (bp->ctx_pages == 0)
911adfc5217SJeff Kirsher 			bp->ctx_pages = 1;
912adfc5217SJeff Kirsher 		for (i = 0; i < bp->ctx_pages; i++) {
913adfc5217SJeff Kirsher 			bp->ctx_blk[i] = dma_alloc_coherent(&bp->pdev->dev,
9142bc4078eSMichael Chan 						BNX2_PAGE_SIZE,
915adfc5217SJeff Kirsher 						&bp->ctx_blk_mapping[i],
916adfc5217SJeff Kirsher 						GFP_KERNEL);
917b8aac410SVarsha Rao 			if (!bp->ctx_blk[i])
918adfc5217SJeff Kirsher 				goto alloc_mem_err;
919adfc5217SJeff Kirsher 		}
920adfc5217SJeff Kirsher 	}
921adfc5217SJeff Kirsher 
922adfc5217SJeff Kirsher 	err = bnx2_alloc_rx_mem(bp);
923adfc5217SJeff Kirsher 	if (err)
924adfc5217SJeff Kirsher 		goto alloc_mem_err;
925adfc5217SJeff Kirsher 
926adfc5217SJeff Kirsher 	err = bnx2_alloc_tx_mem(bp);
927adfc5217SJeff Kirsher 	if (err)
928adfc5217SJeff Kirsher 		goto alloc_mem_err;
929adfc5217SJeff Kirsher 
930adfc5217SJeff Kirsher 	return 0;
931adfc5217SJeff Kirsher 
932adfc5217SJeff Kirsher alloc_mem_err:
933adfc5217SJeff Kirsher 	bnx2_free_mem(bp);
934adfc5217SJeff Kirsher 	return -ENOMEM;
935adfc5217SJeff Kirsher }
936adfc5217SJeff Kirsher 
937adfc5217SJeff Kirsher static void
938adfc5217SJeff Kirsher bnx2_report_fw_link(struct bnx2 *bp)
939adfc5217SJeff Kirsher {
940adfc5217SJeff Kirsher 	u32 fw_link_status = 0;
941adfc5217SJeff Kirsher 
942adfc5217SJeff Kirsher 	if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
943adfc5217SJeff Kirsher 		return;
944adfc5217SJeff Kirsher 
945adfc5217SJeff Kirsher 	if (bp->link_up) {
946adfc5217SJeff Kirsher 		u32 bmsr;
947adfc5217SJeff Kirsher 
948adfc5217SJeff Kirsher 		switch (bp->line_speed) {
949adfc5217SJeff Kirsher 		case SPEED_10:
950adfc5217SJeff Kirsher 			if (bp->duplex == DUPLEX_HALF)
951adfc5217SJeff Kirsher 				fw_link_status = BNX2_LINK_STATUS_10HALF;
952adfc5217SJeff Kirsher 			else
953adfc5217SJeff Kirsher 				fw_link_status = BNX2_LINK_STATUS_10FULL;
954adfc5217SJeff Kirsher 			break;
955adfc5217SJeff Kirsher 		case SPEED_100:
956adfc5217SJeff Kirsher 			if (bp->duplex == DUPLEX_HALF)
957adfc5217SJeff Kirsher 				fw_link_status = BNX2_LINK_STATUS_100HALF;
958adfc5217SJeff Kirsher 			else
959adfc5217SJeff Kirsher 				fw_link_status = BNX2_LINK_STATUS_100FULL;
960adfc5217SJeff Kirsher 			break;
961adfc5217SJeff Kirsher 		case SPEED_1000:
962adfc5217SJeff Kirsher 			if (bp->duplex == DUPLEX_HALF)
963adfc5217SJeff Kirsher 				fw_link_status = BNX2_LINK_STATUS_1000HALF;
964adfc5217SJeff Kirsher 			else
965adfc5217SJeff Kirsher 				fw_link_status = BNX2_LINK_STATUS_1000FULL;
966adfc5217SJeff Kirsher 			break;
967adfc5217SJeff Kirsher 		case SPEED_2500:
968adfc5217SJeff Kirsher 			if (bp->duplex == DUPLEX_HALF)
969adfc5217SJeff Kirsher 				fw_link_status = BNX2_LINK_STATUS_2500HALF;
970adfc5217SJeff Kirsher 			else
971adfc5217SJeff Kirsher 				fw_link_status = BNX2_LINK_STATUS_2500FULL;
972adfc5217SJeff Kirsher 			break;
973adfc5217SJeff Kirsher 		}
974adfc5217SJeff Kirsher 
975adfc5217SJeff Kirsher 		fw_link_status |= BNX2_LINK_STATUS_LINK_UP;
976adfc5217SJeff Kirsher 
977adfc5217SJeff Kirsher 		if (bp->autoneg) {
978adfc5217SJeff Kirsher 			fw_link_status |= BNX2_LINK_STATUS_AN_ENABLED;
979adfc5217SJeff Kirsher 
980adfc5217SJeff Kirsher 			bnx2_read_phy(bp, bp->mii_bmsr, &bmsr);
981adfc5217SJeff Kirsher 			bnx2_read_phy(bp, bp->mii_bmsr, &bmsr);
982adfc5217SJeff Kirsher 
983adfc5217SJeff Kirsher 			if (!(bmsr & BMSR_ANEGCOMPLETE) ||
984adfc5217SJeff Kirsher 			    bp->phy_flags & BNX2_PHY_FLAG_PARALLEL_DETECT)
985adfc5217SJeff Kirsher 				fw_link_status |= BNX2_LINK_STATUS_PARALLEL_DET;
986adfc5217SJeff Kirsher 			else
987adfc5217SJeff Kirsher 				fw_link_status |= BNX2_LINK_STATUS_AN_COMPLETE;
988adfc5217SJeff Kirsher 		}
989adfc5217SJeff Kirsher 	}
990adfc5217SJeff Kirsher 	else
991adfc5217SJeff Kirsher 		fw_link_status = BNX2_LINK_STATUS_LINK_DOWN;
992adfc5217SJeff Kirsher 
993adfc5217SJeff Kirsher 	bnx2_shmem_wr(bp, BNX2_LINK_STATUS, fw_link_status);
994adfc5217SJeff Kirsher }
995adfc5217SJeff Kirsher 
996adfc5217SJeff Kirsher static char *
997adfc5217SJeff Kirsher bnx2_xceiver_str(struct bnx2 *bp)
998adfc5217SJeff Kirsher {
999adfc5217SJeff Kirsher 	return (bp->phy_port == PORT_FIBRE) ? "SerDes" :
1000adfc5217SJeff Kirsher 		((bp->phy_flags & BNX2_PHY_FLAG_SERDES) ? "Remote Copper" :
1001adfc5217SJeff Kirsher 		 "Copper");
1002adfc5217SJeff Kirsher }
1003adfc5217SJeff Kirsher 
1004adfc5217SJeff Kirsher static void
1005adfc5217SJeff Kirsher bnx2_report_link(struct bnx2 *bp)
1006adfc5217SJeff Kirsher {
1007adfc5217SJeff Kirsher 	if (bp->link_up) {
1008adfc5217SJeff Kirsher 		netif_carrier_on(bp->dev);
1009adfc5217SJeff Kirsher 		netdev_info(bp->dev, "NIC %s Link is Up, %d Mbps %s duplex",
1010adfc5217SJeff Kirsher 			    bnx2_xceiver_str(bp),
1011adfc5217SJeff Kirsher 			    bp->line_speed,
1012adfc5217SJeff Kirsher 			    bp->duplex == DUPLEX_FULL ? "full" : "half");
1013adfc5217SJeff Kirsher 
1014adfc5217SJeff Kirsher 		if (bp->flow_ctrl) {
1015adfc5217SJeff Kirsher 			if (bp->flow_ctrl & FLOW_CTRL_RX) {
1016adfc5217SJeff Kirsher 				pr_cont(", receive ");
1017adfc5217SJeff Kirsher 				if (bp->flow_ctrl & FLOW_CTRL_TX)
1018adfc5217SJeff Kirsher 					pr_cont("& transmit ");
1019adfc5217SJeff Kirsher 			}
1020adfc5217SJeff Kirsher 			else {
1021adfc5217SJeff Kirsher 				pr_cont(", transmit ");
1022adfc5217SJeff Kirsher 			}
1023adfc5217SJeff Kirsher 			pr_cont("flow control ON");
1024adfc5217SJeff Kirsher 		}
1025adfc5217SJeff Kirsher 		pr_cont("\n");
1026adfc5217SJeff Kirsher 	} else {
1027adfc5217SJeff Kirsher 		netif_carrier_off(bp->dev);
1028adfc5217SJeff Kirsher 		netdev_err(bp->dev, "NIC %s Link is Down\n",
1029adfc5217SJeff Kirsher 			   bnx2_xceiver_str(bp));
1030adfc5217SJeff Kirsher 	}
1031adfc5217SJeff Kirsher 
1032adfc5217SJeff Kirsher 	bnx2_report_fw_link(bp);
1033adfc5217SJeff Kirsher }
1034adfc5217SJeff Kirsher 
1035adfc5217SJeff Kirsher static void
1036adfc5217SJeff Kirsher bnx2_resolve_flow_ctrl(struct bnx2 *bp)
1037adfc5217SJeff Kirsher {
1038adfc5217SJeff Kirsher 	u32 local_adv, remote_adv;
1039adfc5217SJeff Kirsher 
1040adfc5217SJeff Kirsher 	bp->flow_ctrl = 0;
1041adfc5217SJeff Kirsher 	if ((bp->autoneg & (AUTONEG_SPEED | AUTONEG_FLOW_CTRL)) !=
1042adfc5217SJeff Kirsher 		(AUTONEG_SPEED | AUTONEG_FLOW_CTRL)) {
1043adfc5217SJeff Kirsher 
1044adfc5217SJeff Kirsher 		if (bp->duplex == DUPLEX_FULL) {
1045adfc5217SJeff Kirsher 			bp->flow_ctrl = bp->req_flow_ctrl;
1046adfc5217SJeff Kirsher 		}
1047adfc5217SJeff Kirsher 		return;
1048adfc5217SJeff Kirsher 	}
1049adfc5217SJeff Kirsher 
1050adfc5217SJeff Kirsher 	if (bp->duplex != DUPLEX_FULL) {
1051adfc5217SJeff Kirsher 		return;
1052adfc5217SJeff Kirsher 	}
1053adfc5217SJeff Kirsher 
1054adfc5217SJeff Kirsher 	if ((bp->phy_flags & BNX2_PHY_FLAG_SERDES) &&
10554ce45e02SMichael Chan 	    (BNX2_CHIP(bp) == BNX2_CHIP_5708)) {
1056adfc5217SJeff Kirsher 		u32 val;
1057adfc5217SJeff Kirsher 
1058adfc5217SJeff Kirsher 		bnx2_read_phy(bp, BCM5708S_1000X_STAT1, &val);
1059adfc5217SJeff Kirsher 		if (val & BCM5708S_1000X_STAT1_TX_PAUSE)
1060adfc5217SJeff Kirsher 			bp->flow_ctrl |= FLOW_CTRL_TX;
1061adfc5217SJeff Kirsher 		if (val & BCM5708S_1000X_STAT1_RX_PAUSE)
1062adfc5217SJeff Kirsher 			bp->flow_ctrl |= FLOW_CTRL_RX;
1063adfc5217SJeff Kirsher 		return;
1064adfc5217SJeff Kirsher 	}
1065adfc5217SJeff Kirsher 
1066adfc5217SJeff Kirsher 	bnx2_read_phy(bp, bp->mii_adv, &local_adv);
1067adfc5217SJeff Kirsher 	bnx2_read_phy(bp, bp->mii_lpa, &remote_adv);
1068adfc5217SJeff Kirsher 
1069adfc5217SJeff Kirsher 	if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
1070adfc5217SJeff Kirsher 		u32 new_local_adv = 0;
1071adfc5217SJeff Kirsher 		u32 new_remote_adv = 0;
1072adfc5217SJeff Kirsher 
1073adfc5217SJeff Kirsher 		if (local_adv & ADVERTISE_1000XPAUSE)
1074adfc5217SJeff Kirsher 			new_local_adv |= ADVERTISE_PAUSE_CAP;
1075adfc5217SJeff Kirsher 		if (local_adv & ADVERTISE_1000XPSE_ASYM)
1076adfc5217SJeff Kirsher 			new_local_adv |= ADVERTISE_PAUSE_ASYM;
1077adfc5217SJeff Kirsher 		if (remote_adv & ADVERTISE_1000XPAUSE)
1078adfc5217SJeff Kirsher 			new_remote_adv |= ADVERTISE_PAUSE_CAP;
1079adfc5217SJeff Kirsher 		if (remote_adv & ADVERTISE_1000XPSE_ASYM)
1080adfc5217SJeff Kirsher 			new_remote_adv |= ADVERTISE_PAUSE_ASYM;
1081adfc5217SJeff Kirsher 
1082adfc5217SJeff Kirsher 		local_adv = new_local_adv;
1083adfc5217SJeff Kirsher 		remote_adv = new_remote_adv;
1084adfc5217SJeff Kirsher 	}
1085adfc5217SJeff Kirsher 
1086adfc5217SJeff Kirsher 	/* See Table 28B-3 of 802.3ab-1999 spec. */
1087adfc5217SJeff Kirsher 	if (local_adv & ADVERTISE_PAUSE_CAP) {
1088adfc5217SJeff Kirsher 		if(local_adv & ADVERTISE_PAUSE_ASYM) {
1089adfc5217SJeff Kirsher 	                if (remote_adv & ADVERTISE_PAUSE_CAP) {
1090adfc5217SJeff Kirsher 				bp->flow_ctrl = FLOW_CTRL_TX | FLOW_CTRL_RX;
1091adfc5217SJeff Kirsher 			}
1092adfc5217SJeff Kirsher 			else if (remote_adv & ADVERTISE_PAUSE_ASYM) {
1093adfc5217SJeff Kirsher 				bp->flow_ctrl = FLOW_CTRL_RX;
1094adfc5217SJeff Kirsher 			}
1095adfc5217SJeff Kirsher 		}
1096adfc5217SJeff Kirsher 		else {
1097adfc5217SJeff Kirsher 			if (remote_adv & ADVERTISE_PAUSE_CAP) {
1098adfc5217SJeff Kirsher 				bp->flow_ctrl = FLOW_CTRL_TX | FLOW_CTRL_RX;
1099adfc5217SJeff Kirsher 			}
1100adfc5217SJeff Kirsher 		}
1101adfc5217SJeff Kirsher 	}
1102adfc5217SJeff Kirsher 	else if (local_adv & ADVERTISE_PAUSE_ASYM) {
1103adfc5217SJeff Kirsher 		if ((remote_adv & ADVERTISE_PAUSE_CAP) &&
1104adfc5217SJeff Kirsher 			(remote_adv & ADVERTISE_PAUSE_ASYM)) {
1105adfc5217SJeff Kirsher 
1106adfc5217SJeff Kirsher 			bp->flow_ctrl = FLOW_CTRL_TX;
1107adfc5217SJeff Kirsher 		}
1108adfc5217SJeff Kirsher 	}
1109adfc5217SJeff Kirsher }
1110adfc5217SJeff Kirsher 
1111adfc5217SJeff Kirsher static int
1112adfc5217SJeff Kirsher bnx2_5709s_linkup(struct bnx2 *bp)
1113adfc5217SJeff Kirsher {
1114adfc5217SJeff Kirsher 	u32 val, speed;
1115adfc5217SJeff Kirsher 
1116adfc5217SJeff Kirsher 	bp->link_up = 1;
1117adfc5217SJeff Kirsher 
1118adfc5217SJeff Kirsher 	bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_GP_STATUS);
1119adfc5217SJeff Kirsher 	bnx2_read_phy(bp, MII_BNX2_GP_TOP_AN_STATUS1, &val);
1120adfc5217SJeff Kirsher 	bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
1121adfc5217SJeff Kirsher 
1122adfc5217SJeff Kirsher 	if ((bp->autoneg & AUTONEG_SPEED) == 0) {
1123adfc5217SJeff Kirsher 		bp->line_speed = bp->req_line_speed;
1124adfc5217SJeff Kirsher 		bp->duplex = bp->req_duplex;
1125adfc5217SJeff Kirsher 		return 0;
1126adfc5217SJeff Kirsher 	}
1127adfc5217SJeff Kirsher 	speed = val & MII_BNX2_GP_TOP_AN_SPEED_MSK;
1128adfc5217SJeff Kirsher 	switch (speed) {
1129adfc5217SJeff Kirsher 		case MII_BNX2_GP_TOP_AN_SPEED_10:
1130adfc5217SJeff Kirsher 			bp->line_speed = SPEED_10;
1131adfc5217SJeff Kirsher 			break;
1132adfc5217SJeff Kirsher 		case MII_BNX2_GP_TOP_AN_SPEED_100:
1133adfc5217SJeff Kirsher 			bp->line_speed = SPEED_100;
1134adfc5217SJeff Kirsher 			break;
1135adfc5217SJeff Kirsher 		case MII_BNX2_GP_TOP_AN_SPEED_1G:
1136adfc5217SJeff Kirsher 		case MII_BNX2_GP_TOP_AN_SPEED_1GKV:
1137adfc5217SJeff Kirsher 			bp->line_speed = SPEED_1000;
1138adfc5217SJeff Kirsher 			break;
1139adfc5217SJeff Kirsher 		case MII_BNX2_GP_TOP_AN_SPEED_2_5G:
1140adfc5217SJeff Kirsher 			bp->line_speed = SPEED_2500;
1141adfc5217SJeff Kirsher 			break;
1142adfc5217SJeff Kirsher 	}
1143adfc5217SJeff Kirsher 	if (val & MII_BNX2_GP_TOP_AN_FD)
1144adfc5217SJeff Kirsher 		bp->duplex = DUPLEX_FULL;
1145adfc5217SJeff Kirsher 	else
1146adfc5217SJeff Kirsher 		bp->duplex = DUPLEX_HALF;
1147adfc5217SJeff Kirsher 	return 0;
1148adfc5217SJeff Kirsher }
1149adfc5217SJeff Kirsher 
1150adfc5217SJeff Kirsher static int
1151adfc5217SJeff Kirsher bnx2_5708s_linkup(struct bnx2 *bp)
1152adfc5217SJeff Kirsher {
1153adfc5217SJeff Kirsher 	u32 val;
1154adfc5217SJeff Kirsher 
1155adfc5217SJeff Kirsher 	bp->link_up = 1;
1156adfc5217SJeff Kirsher 	bnx2_read_phy(bp, BCM5708S_1000X_STAT1, &val);
1157adfc5217SJeff Kirsher 	switch (val & BCM5708S_1000X_STAT1_SPEED_MASK) {
1158adfc5217SJeff Kirsher 		case BCM5708S_1000X_STAT1_SPEED_10:
1159adfc5217SJeff Kirsher 			bp->line_speed = SPEED_10;
1160adfc5217SJeff Kirsher 			break;
1161adfc5217SJeff Kirsher 		case BCM5708S_1000X_STAT1_SPEED_100:
1162adfc5217SJeff Kirsher 			bp->line_speed = SPEED_100;
1163adfc5217SJeff Kirsher 			break;
1164adfc5217SJeff Kirsher 		case BCM5708S_1000X_STAT1_SPEED_1G:
1165adfc5217SJeff Kirsher 			bp->line_speed = SPEED_1000;
1166adfc5217SJeff Kirsher 			break;
1167adfc5217SJeff Kirsher 		case BCM5708S_1000X_STAT1_SPEED_2G5:
1168adfc5217SJeff Kirsher 			bp->line_speed = SPEED_2500;
1169adfc5217SJeff Kirsher 			break;
1170adfc5217SJeff Kirsher 	}
1171adfc5217SJeff Kirsher 	if (val & BCM5708S_1000X_STAT1_FD)
1172adfc5217SJeff Kirsher 		bp->duplex = DUPLEX_FULL;
1173adfc5217SJeff Kirsher 	else
1174adfc5217SJeff Kirsher 		bp->duplex = DUPLEX_HALF;
1175adfc5217SJeff Kirsher 
1176adfc5217SJeff Kirsher 	return 0;
1177adfc5217SJeff Kirsher }
1178adfc5217SJeff Kirsher 
1179adfc5217SJeff Kirsher static int
1180adfc5217SJeff Kirsher bnx2_5706s_linkup(struct bnx2 *bp)
1181adfc5217SJeff Kirsher {
1182adfc5217SJeff Kirsher 	u32 bmcr, local_adv, remote_adv, common;
1183adfc5217SJeff Kirsher 
1184adfc5217SJeff Kirsher 	bp->link_up = 1;
1185adfc5217SJeff Kirsher 	bp->line_speed = SPEED_1000;
1186adfc5217SJeff Kirsher 
1187adfc5217SJeff Kirsher 	bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
1188adfc5217SJeff Kirsher 	if (bmcr & BMCR_FULLDPLX) {
1189adfc5217SJeff Kirsher 		bp->duplex = DUPLEX_FULL;
1190adfc5217SJeff Kirsher 	}
1191adfc5217SJeff Kirsher 	else {
1192adfc5217SJeff Kirsher 		bp->duplex = DUPLEX_HALF;
1193adfc5217SJeff Kirsher 	}
1194adfc5217SJeff Kirsher 
1195adfc5217SJeff Kirsher 	if (!(bmcr & BMCR_ANENABLE)) {
1196adfc5217SJeff Kirsher 		return 0;
1197adfc5217SJeff Kirsher 	}
1198adfc5217SJeff Kirsher 
1199adfc5217SJeff Kirsher 	bnx2_read_phy(bp, bp->mii_adv, &local_adv);
1200adfc5217SJeff Kirsher 	bnx2_read_phy(bp, bp->mii_lpa, &remote_adv);
1201adfc5217SJeff Kirsher 
1202adfc5217SJeff Kirsher 	common = local_adv & remote_adv;
1203adfc5217SJeff Kirsher 	if (common & (ADVERTISE_1000XHALF | ADVERTISE_1000XFULL)) {
1204adfc5217SJeff Kirsher 
1205adfc5217SJeff Kirsher 		if (common & ADVERTISE_1000XFULL) {
1206adfc5217SJeff Kirsher 			bp->duplex = DUPLEX_FULL;
1207adfc5217SJeff Kirsher 		}
1208adfc5217SJeff Kirsher 		else {
1209adfc5217SJeff Kirsher 			bp->duplex = DUPLEX_HALF;
1210adfc5217SJeff Kirsher 		}
1211adfc5217SJeff Kirsher 	}
1212adfc5217SJeff Kirsher 
1213adfc5217SJeff Kirsher 	return 0;
1214adfc5217SJeff Kirsher }
1215adfc5217SJeff Kirsher 
1216adfc5217SJeff Kirsher static int
1217adfc5217SJeff Kirsher bnx2_copper_linkup(struct bnx2 *bp)
1218adfc5217SJeff Kirsher {
1219adfc5217SJeff Kirsher 	u32 bmcr;
1220adfc5217SJeff Kirsher 
12214016baddSMichael Chan 	bp->phy_flags &= ~BNX2_PHY_FLAG_MDIX;
12224016baddSMichael Chan 
1223adfc5217SJeff Kirsher 	bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
1224adfc5217SJeff Kirsher 	if (bmcr & BMCR_ANENABLE) {
1225adfc5217SJeff Kirsher 		u32 local_adv, remote_adv, common;
1226adfc5217SJeff Kirsher 
1227adfc5217SJeff Kirsher 		bnx2_read_phy(bp, MII_CTRL1000, &local_adv);
1228adfc5217SJeff Kirsher 		bnx2_read_phy(bp, MII_STAT1000, &remote_adv);
1229adfc5217SJeff Kirsher 
1230adfc5217SJeff Kirsher 		common = local_adv & (remote_adv >> 2);
1231adfc5217SJeff Kirsher 		if (common & ADVERTISE_1000FULL) {
1232adfc5217SJeff Kirsher 			bp->line_speed = SPEED_1000;
1233adfc5217SJeff Kirsher 			bp->duplex = DUPLEX_FULL;
1234adfc5217SJeff Kirsher 		}
1235adfc5217SJeff Kirsher 		else if (common & ADVERTISE_1000HALF) {
1236adfc5217SJeff Kirsher 			bp->line_speed = SPEED_1000;
1237adfc5217SJeff Kirsher 			bp->duplex = DUPLEX_HALF;
1238adfc5217SJeff Kirsher 		}
1239adfc5217SJeff Kirsher 		else {
1240adfc5217SJeff Kirsher 			bnx2_read_phy(bp, bp->mii_adv, &local_adv);
1241adfc5217SJeff Kirsher 			bnx2_read_phy(bp, bp->mii_lpa, &remote_adv);
1242adfc5217SJeff Kirsher 
1243adfc5217SJeff Kirsher 			common = local_adv & remote_adv;
1244adfc5217SJeff Kirsher 			if (common & ADVERTISE_100FULL) {
1245adfc5217SJeff Kirsher 				bp->line_speed = SPEED_100;
1246adfc5217SJeff Kirsher 				bp->duplex = DUPLEX_FULL;
1247adfc5217SJeff Kirsher 			}
1248adfc5217SJeff Kirsher 			else if (common & ADVERTISE_100HALF) {
1249adfc5217SJeff Kirsher 				bp->line_speed = SPEED_100;
1250adfc5217SJeff Kirsher 				bp->duplex = DUPLEX_HALF;
1251adfc5217SJeff Kirsher 			}
1252adfc5217SJeff Kirsher 			else if (common & ADVERTISE_10FULL) {
1253adfc5217SJeff Kirsher 				bp->line_speed = SPEED_10;
1254adfc5217SJeff Kirsher 				bp->duplex = DUPLEX_FULL;
1255adfc5217SJeff Kirsher 			}
1256adfc5217SJeff Kirsher 			else if (common & ADVERTISE_10HALF) {
1257adfc5217SJeff Kirsher 				bp->line_speed = SPEED_10;
1258adfc5217SJeff Kirsher 				bp->duplex = DUPLEX_HALF;
1259adfc5217SJeff Kirsher 			}
1260adfc5217SJeff Kirsher 			else {
1261adfc5217SJeff Kirsher 				bp->line_speed = 0;
1262adfc5217SJeff Kirsher 				bp->link_up = 0;
1263adfc5217SJeff Kirsher 			}
1264adfc5217SJeff Kirsher 		}
1265adfc5217SJeff Kirsher 	}
1266adfc5217SJeff Kirsher 	else {
1267adfc5217SJeff Kirsher 		if (bmcr & BMCR_SPEED100) {
1268adfc5217SJeff Kirsher 			bp->line_speed = SPEED_100;
1269adfc5217SJeff Kirsher 		}
1270adfc5217SJeff Kirsher 		else {
1271adfc5217SJeff Kirsher 			bp->line_speed = SPEED_10;
1272adfc5217SJeff Kirsher 		}
1273adfc5217SJeff Kirsher 		if (bmcr & BMCR_FULLDPLX) {
1274adfc5217SJeff Kirsher 			bp->duplex = DUPLEX_FULL;
1275adfc5217SJeff Kirsher 		}
1276adfc5217SJeff Kirsher 		else {
1277adfc5217SJeff Kirsher 			bp->duplex = DUPLEX_HALF;
1278adfc5217SJeff Kirsher 		}
1279adfc5217SJeff Kirsher 	}
1280adfc5217SJeff Kirsher 
12814016baddSMichael Chan 	if (bp->link_up) {
12824016baddSMichael Chan 		u32 ext_status;
12834016baddSMichael Chan 
12844016baddSMichael Chan 		bnx2_read_phy(bp, MII_BNX2_EXT_STATUS, &ext_status);
12854016baddSMichael Chan 		if (ext_status & EXT_STATUS_MDIX)
12864016baddSMichael Chan 			bp->phy_flags |= BNX2_PHY_FLAG_MDIX;
12874016baddSMichael Chan 	}
12884016baddSMichael Chan 
1289adfc5217SJeff Kirsher 	return 0;
1290adfc5217SJeff Kirsher }
1291adfc5217SJeff Kirsher 
1292adfc5217SJeff Kirsher static void
1293adfc5217SJeff Kirsher bnx2_init_rx_context(struct bnx2 *bp, u32 cid)
1294adfc5217SJeff Kirsher {
1295adfc5217SJeff Kirsher 	u32 val, rx_cid_addr = GET_CID_ADDR(cid);
1296adfc5217SJeff Kirsher 
1297adfc5217SJeff Kirsher 	val = BNX2_L2CTX_CTX_TYPE_CTX_BD_CHN_TYPE_VALUE;
1298adfc5217SJeff Kirsher 	val |= BNX2_L2CTX_CTX_TYPE_SIZE_L2;
1299adfc5217SJeff Kirsher 	val |= 0x02 << 8;
1300adfc5217SJeff Kirsher 
1301adfc5217SJeff Kirsher 	if (bp->flow_ctrl & FLOW_CTRL_TX)
1302adfc5217SJeff Kirsher 		val |= BNX2_L2CTX_FLOW_CTRL_ENABLE;
1303adfc5217SJeff Kirsher 
1304adfc5217SJeff Kirsher 	bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_CTX_TYPE, val);
1305adfc5217SJeff Kirsher }
1306adfc5217SJeff Kirsher 
1307adfc5217SJeff Kirsher static void
1308adfc5217SJeff Kirsher bnx2_init_all_rx_contexts(struct bnx2 *bp)
1309adfc5217SJeff Kirsher {
1310adfc5217SJeff Kirsher 	int i;
1311adfc5217SJeff Kirsher 	u32 cid;
1312adfc5217SJeff Kirsher 
1313adfc5217SJeff Kirsher 	for (i = 0, cid = RX_CID; i < bp->num_rx_rings; i++, cid++) {
1314adfc5217SJeff Kirsher 		if (i == 1)
1315adfc5217SJeff Kirsher 			cid = RX_RSS_CID;
1316adfc5217SJeff Kirsher 		bnx2_init_rx_context(bp, cid);
1317adfc5217SJeff Kirsher 	}
1318adfc5217SJeff Kirsher }
1319adfc5217SJeff Kirsher 
1320adfc5217SJeff Kirsher static void
1321adfc5217SJeff Kirsher bnx2_set_mac_link(struct bnx2 *bp)
1322adfc5217SJeff Kirsher {
1323adfc5217SJeff Kirsher 	u32 val;
1324adfc5217SJeff Kirsher 
1325e503e066SMichael Chan 	BNX2_WR(bp, BNX2_EMAC_TX_LENGTHS, 0x2620);
1326adfc5217SJeff Kirsher 	if (bp->link_up && (bp->line_speed == SPEED_1000) &&
1327adfc5217SJeff Kirsher 		(bp->duplex == DUPLEX_HALF)) {
1328e503e066SMichael Chan 		BNX2_WR(bp, BNX2_EMAC_TX_LENGTHS, 0x26ff);
1329adfc5217SJeff Kirsher 	}
1330adfc5217SJeff Kirsher 
1331adfc5217SJeff Kirsher 	/* Configure the EMAC mode register. */
1332e503e066SMichael Chan 	val = BNX2_RD(bp, BNX2_EMAC_MODE);
1333adfc5217SJeff Kirsher 
1334adfc5217SJeff Kirsher 	val &= ~(BNX2_EMAC_MODE_PORT | BNX2_EMAC_MODE_HALF_DUPLEX |
1335adfc5217SJeff Kirsher 		BNX2_EMAC_MODE_MAC_LOOP | BNX2_EMAC_MODE_FORCE_LINK |
1336adfc5217SJeff Kirsher 		BNX2_EMAC_MODE_25G_MODE);
1337adfc5217SJeff Kirsher 
1338adfc5217SJeff Kirsher 	if (bp->link_up) {
1339adfc5217SJeff Kirsher 		switch (bp->line_speed) {
1340adfc5217SJeff Kirsher 			case SPEED_10:
13414ce45e02SMichael Chan 				if (BNX2_CHIP(bp) != BNX2_CHIP_5706) {
1342adfc5217SJeff Kirsher 					val |= BNX2_EMAC_MODE_PORT_MII_10M;
1343adfc5217SJeff Kirsher 					break;
1344adfc5217SJeff Kirsher 				}
1345adfc5217SJeff Kirsher 				/* fall through */
1346adfc5217SJeff Kirsher 			case SPEED_100:
1347adfc5217SJeff Kirsher 				val |= BNX2_EMAC_MODE_PORT_MII;
1348adfc5217SJeff Kirsher 				break;
1349adfc5217SJeff Kirsher 			case SPEED_2500:
1350adfc5217SJeff Kirsher 				val |= BNX2_EMAC_MODE_25G_MODE;
1351adfc5217SJeff Kirsher 				/* fall through */
1352adfc5217SJeff Kirsher 			case SPEED_1000:
1353adfc5217SJeff Kirsher 				val |= BNX2_EMAC_MODE_PORT_GMII;
1354adfc5217SJeff Kirsher 				break;
1355adfc5217SJeff Kirsher 		}
1356adfc5217SJeff Kirsher 	}
1357adfc5217SJeff Kirsher 	else {
1358adfc5217SJeff Kirsher 		val |= BNX2_EMAC_MODE_PORT_GMII;
1359adfc5217SJeff Kirsher 	}
1360adfc5217SJeff Kirsher 
1361adfc5217SJeff Kirsher 	/* Set the MAC to operate in the appropriate duplex mode. */
1362adfc5217SJeff Kirsher 	if (bp->duplex == DUPLEX_HALF)
1363adfc5217SJeff Kirsher 		val |= BNX2_EMAC_MODE_HALF_DUPLEX;
1364e503e066SMichael Chan 	BNX2_WR(bp, BNX2_EMAC_MODE, val);
1365adfc5217SJeff Kirsher 
1366adfc5217SJeff Kirsher 	/* Enable/disable rx PAUSE. */
1367adfc5217SJeff Kirsher 	bp->rx_mode &= ~BNX2_EMAC_RX_MODE_FLOW_EN;
1368adfc5217SJeff Kirsher 
1369adfc5217SJeff Kirsher 	if (bp->flow_ctrl & FLOW_CTRL_RX)
1370adfc5217SJeff Kirsher 		bp->rx_mode |= BNX2_EMAC_RX_MODE_FLOW_EN;
1371e503e066SMichael Chan 	BNX2_WR(bp, BNX2_EMAC_RX_MODE, bp->rx_mode);
1372adfc5217SJeff Kirsher 
1373adfc5217SJeff Kirsher 	/* Enable/disable tx PAUSE. */
1374e503e066SMichael Chan 	val = BNX2_RD(bp, BNX2_EMAC_TX_MODE);
1375adfc5217SJeff Kirsher 	val &= ~BNX2_EMAC_TX_MODE_FLOW_EN;
1376adfc5217SJeff Kirsher 
1377adfc5217SJeff Kirsher 	if (bp->flow_ctrl & FLOW_CTRL_TX)
1378adfc5217SJeff Kirsher 		val |= BNX2_EMAC_TX_MODE_FLOW_EN;
1379e503e066SMichael Chan 	BNX2_WR(bp, BNX2_EMAC_TX_MODE, val);
1380adfc5217SJeff Kirsher 
1381adfc5217SJeff Kirsher 	/* Acknowledge the interrupt. */
1382e503e066SMichael Chan 	BNX2_WR(bp, BNX2_EMAC_STATUS, BNX2_EMAC_STATUS_LINK_CHANGE);
1383adfc5217SJeff Kirsher 
1384adfc5217SJeff Kirsher 	bnx2_init_all_rx_contexts(bp);
1385adfc5217SJeff Kirsher }
1386adfc5217SJeff Kirsher 
1387adfc5217SJeff Kirsher static void
1388adfc5217SJeff Kirsher bnx2_enable_bmsr1(struct bnx2 *bp)
1389adfc5217SJeff Kirsher {
1390adfc5217SJeff Kirsher 	if ((bp->phy_flags & BNX2_PHY_FLAG_SERDES) &&
13914ce45e02SMichael Chan 	    (BNX2_CHIP(bp) == BNX2_CHIP_5709))
1392adfc5217SJeff Kirsher 		bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
1393adfc5217SJeff Kirsher 			       MII_BNX2_BLK_ADDR_GP_STATUS);
1394adfc5217SJeff Kirsher }
1395adfc5217SJeff Kirsher 
1396adfc5217SJeff Kirsher static void
1397adfc5217SJeff Kirsher bnx2_disable_bmsr1(struct bnx2 *bp)
1398adfc5217SJeff Kirsher {
1399adfc5217SJeff Kirsher 	if ((bp->phy_flags & BNX2_PHY_FLAG_SERDES) &&
14004ce45e02SMichael Chan 	    (BNX2_CHIP(bp) == BNX2_CHIP_5709))
1401adfc5217SJeff Kirsher 		bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
1402adfc5217SJeff Kirsher 			       MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
1403adfc5217SJeff Kirsher }
1404adfc5217SJeff Kirsher 
1405adfc5217SJeff Kirsher static int
1406adfc5217SJeff Kirsher bnx2_test_and_enable_2g5(struct bnx2 *bp)
1407adfc5217SJeff Kirsher {
1408adfc5217SJeff Kirsher 	u32 up1;
1409adfc5217SJeff Kirsher 	int ret = 1;
1410adfc5217SJeff Kirsher 
1411adfc5217SJeff Kirsher 	if (!(bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE))
1412adfc5217SJeff Kirsher 		return 0;
1413adfc5217SJeff Kirsher 
1414adfc5217SJeff Kirsher 	if (bp->autoneg & AUTONEG_SPEED)
1415adfc5217SJeff Kirsher 		bp->advertising |= ADVERTISED_2500baseX_Full;
1416adfc5217SJeff Kirsher 
14174ce45e02SMichael Chan 	if (BNX2_CHIP(bp) == BNX2_CHIP_5709)
1418adfc5217SJeff Kirsher 		bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_OVER1G);
1419adfc5217SJeff Kirsher 
1420adfc5217SJeff Kirsher 	bnx2_read_phy(bp, bp->mii_up1, &up1);
1421adfc5217SJeff Kirsher 	if (!(up1 & BCM5708S_UP1_2G5)) {
1422adfc5217SJeff Kirsher 		up1 |= BCM5708S_UP1_2G5;
1423adfc5217SJeff Kirsher 		bnx2_write_phy(bp, bp->mii_up1, up1);
1424adfc5217SJeff Kirsher 		ret = 0;
1425adfc5217SJeff Kirsher 	}
1426adfc5217SJeff Kirsher 
14274ce45e02SMichael Chan 	if (BNX2_CHIP(bp) == BNX2_CHIP_5709)
1428adfc5217SJeff Kirsher 		bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
1429adfc5217SJeff Kirsher 			       MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
1430adfc5217SJeff Kirsher 
1431adfc5217SJeff Kirsher 	return ret;
1432adfc5217SJeff Kirsher }
1433adfc5217SJeff Kirsher 
1434adfc5217SJeff Kirsher static int
1435adfc5217SJeff Kirsher bnx2_test_and_disable_2g5(struct bnx2 *bp)
1436adfc5217SJeff Kirsher {
1437adfc5217SJeff Kirsher 	u32 up1;
1438adfc5217SJeff Kirsher 	int ret = 0;
1439adfc5217SJeff Kirsher 
1440adfc5217SJeff Kirsher 	if (!(bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE))
1441adfc5217SJeff Kirsher 		return 0;
1442adfc5217SJeff Kirsher 
14434ce45e02SMichael Chan 	if (BNX2_CHIP(bp) == BNX2_CHIP_5709)
1444adfc5217SJeff Kirsher 		bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_OVER1G);
1445adfc5217SJeff Kirsher 
1446adfc5217SJeff Kirsher 	bnx2_read_phy(bp, bp->mii_up1, &up1);
1447adfc5217SJeff Kirsher 	if (up1 & BCM5708S_UP1_2G5) {
1448adfc5217SJeff Kirsher 		up1 &= ~BCM5708S_UP1_2G5;
1449adfc5217SJeff Kirsher 		bnx2_write_phy(bp, bp->mii_up1, up1);
1450adfc5217SJeff Kirsher 		ret = 1;
1451adfc5217SJeff Kirsher 	}
1452adfc5217SJeff Kirsher 
14534ce45e02SMichael Chan 	if (BNX2_CHIP(bp) == BNX2_CHIP_5709)
1454adfc5217SJeff Kirsher 		bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
1455adfc5217SJeff Kirsher 			       MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
1456adfc5217SJeff Kirsher 
1457adfc5217SJeff Kirsher 	return ret;
1458adfc5217SJeff Kirsher }
1459adfc5217SJeff Kirsher 
1460adfc5217SJeff Kirsher static void
1461adfc5217SJeff Kirsher bnx2_enable_forced_2g5(struct bnx2 *bp)
1462adfc5217SJeff Kirsher {
1463adfc5217SJeff Kirsher 	u32 uninitialized_var(bmcr);
1464adfc5217SJeff Kirsher 	int err;
1465adfc5217SJeff Kirsher 
1466adfc5217SJeff Kirsher 	if (!(bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE))
1467adfc5217SJeff Kirsher 		return;
1468adfc5217SJeff Kirsher 
14694ce45e02SMichael Chan 	if (BNX2_CHIP(bp) == BNX2_CHIP_5709) {
1470adfc5217SJeff Kirsher 		u32 val;
1471adfc5217SJeff Kirsher 
1472adfc5217SJeff Kirsher 		bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
1473adfc5217SJeff Kirsher 			       MII_BNX2_BLK_ADDR_SERDES_DIG);
1474adfc5217SJeff Kirsher 		if (!bnx2_read_phy(bp, MII_BNX2_SERDES_DIG_MISC1, &val)) {
1475adfc5217SJeff Kirsher 			val &= ~MII_BNX2_SD_MISC1_FORCE_MSK;
1476adfc5217SJeff Kirsher 			val |= MII_BNX2_SD_MISC1_FORCE |
1477adfc5217SJeff Kirsher 				MII_BNX2_SD_MISC1_FORCE_2_5G;
1478adfc5217SJeff Kirsher 			bnx2_write_phy(bp, MII_BNX2_SERDES_DIG_MISC1, val);
1479adfc5217SJeff Kirsher 		}
1480adfc5217SJeff Kirsher 
1481adfc5217SJeff Kirsher 		bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
1482adfc5217SJeff Kirsher 			       MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
1483adfc5217SJeff Kirsher 		err = bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
1484adfc5217SJeff Kirsher 
14854ce45e02SMichael Chan 	} else if (BNX2_CHIP(bp) == BNX2_CHIP_5708) {
1486adfc5217SJeff Kirsher 		err = bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
1487adfc5217SJeff Kirsher 		if (!err)
1488adfc5217SJeff Kirsher 			bmcr |= BCM5708S_BMCR_FORCE_2500;
1489adfc5217SJeff Kirsher 	} else {
1490adfc5217SJeff Kirsher 		return;
1491adfc5217SJeff Kirsher 	}
1492adfc5217SJeff Kirsher 
1493adfc5217SJeff Kirsher 	if (err)
1494adfc5217SJeff Kirsher 		return;
1495adfc5217SJeff Kirsher 
1496adfc5217SJeff Kirsher 	if (bp->autoneg & AUTONEG_SPEED) {
1497adfc5217SJeff Kirsher 		bmcr &= ~BMCR_ANENABLE;
1498adfc5217SJeff Kirsher 		if (bp->req_duplex == DUPLEX_FULL)
1499adfc5217SJeff Kirsher 			bmcr |= BMCR_FULLDPLX;
1500adfc5217SJeff Kirsher 	}
1501adfc5217SJeff Kirsher 	bnx2_write_phy(bp, bp->mii_bmcr, bmcr);
1502adfc5217SJeff Kirsher }
1503adfc5217SJeff Kirsher 
1504adfc5217SJeff Kirsher static void
1505adfc5217SJeff Kirsher bnx2_disable_forced_2g5(struct bnx2 *bp)
1506adfc5217SJeff Kirsher {
1507adfc5217SJeff Kirsher 	u32 uninitialized_var(bmcr);
1508adfc5217SJeff Kirsher 	int err;
1509adfc5217SJeff Kirsher 
1510adfc5217SJeff Kirsher 	if (!(bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE))
1511adfc5217SJeff Kirsher 		return;
1512adfc5217SJeff Kirsher 
15134ce45e02SMichael Chan 	if (BNX2_CHIP(bp) == BNX2_CHIP_5709) {
1514adfc5217SJeff Kirsher 		u32 val;
1515adfc5217SJeff Kirsher 
1516adfc5217SJeff Kirsher 		bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
1517adfc5217SJeff Kirsher 			       MII_BNX2_BLK_ADDR_SERDES_DIG);
1518adfc5217SJeff Kirsher 		if (!bnx2_read_phy(bp, MII_BNX2_SERDES_DIG_MISC1, &val)) {
1519adfc5217SJeff Kirsher 			val &= ~MII_BNX2_SD_MISC1_FORCE;
1520adfc5217SJeff Kirsher 			bnx2_write_phy(bp, MII_BNX2_SERDES_DIG_MISC1, val);
1521adfc5217SJeff Kirsher 		}
1522adfc5217SJeff Kirsher 
1523adfc5217SJeff Kirsher 		bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
1524adfc5217SJeff Kirsher 			       MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
1525adfc5217SJeff Kirsher 		err = bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
1526adfc5217SJeff Kirsher 
15274ce45e02SMichael Chan 	} else if (BNX2_CHIP(bp) == BNX2_CHIP_5708) {
1528adfc5217SJeff Kirsher 		err = bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
1529adfc5217SJeff Kirsher 		if (!err)
1530adfc5217SJeff Kirsher 			bmcr &= ~BCM5708S_BMCR_FORCE_2500;
1531adfc5217SJeff Kirsher 	} else {
1532adfc5217SJeff Kirsher 		return;
1533adfc5217SJeff Kirsher 	}
1534adfc5217SJeff Kirsher 
1535adfc5217SJeff Kirsher 	if (err)
1536adfc5217SJeff Kirsher 		return;
1537adfc5217SJeff Kirsher 
1538adfc5217SJeff Kirsher 	if (bp->autoneg & AUTONEG_SPEED)
1539adfc5217SJeff Kirsher 		bmcr |= BMCR_SPEED1000 | BMCR_ANENABLE | BMCR_ANRESTART;
1540adfc5217SJeff Kirsher 	bnx2_write_phy(bp, bp->mii_bmcr, bmcr);
1541adfc5217SJeff Kirsher }
1542adfc5217SJeff Kirsher 
1543adfc5217SJeff Kirsher static void
1544adfc5217SJeff Kirsher bnx2_5706s_force_link_dn(struct bnx2 *bp, int start)
1545adfc5217SJeff Kirsher {
1546adfc5217SJeff Kirsher 	u32 val;
1547adfc5217SJeff Kirsher 
1548adfc5217SJeff Kirsher 	bnx2_write_phy(bp, MII_BNX2_DSP_ADDRESS, MII_EXPAND_SERDES_CTL);
1549adfc5217SJeff Kirsher 	bnx2_read_phy(bp, MII_BNX2_DSP_RW_PORT, &val);
1550adfc5217SJeff Kirsher 	if (start)
1551adfc5217SJeff Kirsher 		bnx2_write_phy(bp, MII_BNX2_DSP_RW_PORT, val & 0xff0f);
1552adfc5217SJeff Kirsher 	else
1553adfc5217SJeff Kirsher 		bnx2_write_phy(bp, MII_BNX2_DSP_RW_PORT, val | 0xc0);
1554adfc5217SJeff Kirsher }
1555adfc5217SJeff Kirsher 
1556adfc5217SJeff Kirsher static int
1557adfc5217SJeff Kirsher bnx2_set_link(struct bnx2 *bp)
1558adfc5217SJeff Kirsher {
1559adfc5217SJeff Kirsher 	u32 bmsr;
1560adfc5217SJeff Kirsher 	u8 link_up;
1561adfc5217SJeff Kirsher 
1562adfc5217SJeff Kirsher 	if (bp->loopback == MAC_LOOPBACK || bp->loopback == PHY_LOOPBACK) {
1563adfc5217SJeff Kirsher 		bp->link_up = 1;
1564adfc5217SJeff Kirsher 		return 0;
1565adfc5217SJeff Kirsher 	}
1566adfc5217SJeff Kirsher 
1567adfc5217SJeff Kirsher 	if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
1568adfc5217SJeff Kirsher 		return 0;
1569adfc5217SJeff Kirsher 
1570adfc5217SJeff Kirsher 	link_up = bp->link_up;
1571adfc5217SJeff Kirsher 
1572adfc5217SJeff Kirsher 	bnx2_enable_bmsr1(bp);
1573adfc5217SJeff Kirsher 	bnx2_read_phy(bp, bp->mii_bmsr1, &bmsr);
1574adfc5217SJeff Kirsher 	bnx2_read_phy(bp, bp->mii_bmsr1, &bmsr);
1575adfc5217SJeff Kirsher 	bnx2_disable_bmsr1(bp);
1576adfc5217SJeff Kirsher 
1577adfc5217SJeff Kirsher 	if ((bp->phy_flags & BNX2_PHY_FLAG_SERDES) &&
15784ce45e02SMichael Chan 	    (BNX2_CHIP(bp) == BNX2_CHIP_5706)) {
1579adfc5217SJeff Kirsher 		u32 val, an_dbg;
1580adfc5217SJeff Kirsher 
1581adfc5217SJeff Kirsher 		if (bp->phy_flags & BNX2_PHY_FLAG_FORCED_DOWN) {
1582adfc5217SJeff Kirsher 			bnx2_5706s_force_link_dn(bp, 0);
1583adfc5217SJeff Kirsher 			bp->phy_flags &= ~BNX2_PHY_FLAG_FORCED_DOWN;
1584adfc5217SJeff Kirsher 		}
1585e503e066SMichael Chan 		val = BNX2_RD(bp, BNX2_EMAC_STATUS);
1586adfc5217SJeff Kirsher 
1587adfc5217SJeff Kirsher 		bnx2_write_phy(bp, MII_BNX2_MISC_SHADOW, MISC_SHDW_AN_DBG);
1588adfc5217SJeff Kirsher 		bnx2_read_phy(bp, MII_BNX2_MISC_SHADOW, &an_dbg);
1589adfc5217SJeff Kirsher 		bnx2_read_phy(bp, MII_BNX2_MISC_SHADOW, &an_dbg);
1590adfc5217SJeff Kirsher 
1591adfc5217SJeff Kirsher 		if ((val & BNX2_EMAC_STATUS_LINK) &&
1592adfc5217SJeff Kirsher 		    !(an_dbg & MISC_SHDW_AN_DBG_NOSYNC))
1593adfc5217SJeff Kirsher 			bmsr |= BMSR_LSTATUS;
1594adfc5217SJeff Kirsher 		else
1595adfc5217SJeff Kirsher 			bmsr &= ~BMSR_LSTATUS;
1596adfc5217SJeff Kirsher 	}
1597adfc5217SJeff Kirsher 
1598adfc5217SJeff Kirsher 	if (bmsr & BMSR_LSTATUS) {
1599adfc5217SJeff Kirsher 		bp->link_up = 1;
1600adfc5217SJeff Kirsher 
1601adfc5217SJeff Kirsher 		if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
16024ce45e02SMichael Chan 			if (BNX2_CHIP(bp) == BNX2_CHIP_5706)
1603adfc5217SJeff Kirsher 				bnx2_5706s_linkup(bp);
16044ce45e02SMichael Chan 			else if (BNX2_CHIP(bp) == BNX2_CHIP_5708)
1605adfc5217SJeff Kirsher 				bnx2_5708s_linkup(bp);
16064ce45e02SMichael Chan 			else if (BNX2_CHIP(bp) == BNX2_CHIP_5709)
1607adfc5217SJeff Kirsher 				bnx2_5709s_linkup(bp);
1608adfc5217SJeff Kirsher 		}
1609adfc5217SJeff Kirsher 		else {
1610adfc5217SJeff Kirsher 			bnx2_copper_linkup(bp);
1611adfc5217SJeff Kirsher 		}
1612adfc5217SJeff Kirsher 		bnx2_resolve_flow_ctrl(bp);
1613adfc5217SJeff Kirsher 	}
1614adfc5217SJeff Kirsher 	else {
1615adfc5217SJeff Kirsher 		if ((bp->phy_flags & BNX2_PHY_FLAG_SERDES) &&
1616adfc5217SJeff Kirsher 		    (bp->autoneg & AUTONEG_SPEED))
1617adfc5217SJeff Kirsher 			bnx2_disable_forced_2g5(bp);
1618adfc5217SJeff Kirsher 
1619adfc5217SJeff Kirsher 		if (bp->phy_flags & BNX2_PHY_FLAG_PARALLEL_DETECT) {
1620adfc5217SJeff Kirsher 			u32 bmcr;
1621adfc5217SJeff Kirsher 
1622adfc5217SJeff Kirsher 			bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
1623adfc5217SJeff Kirsher 			bmcr |= BMCR_ANENABLE;
1624adfc5217SJeff Kirsher 			bnx2_write_phy(bp, bp->mii_bmcr, bmcr);
1625adfc5217SJeff Kirsher 
1626adfc5217SJeff Kirsher 			bp->phy_flags &= ~BNX2_PHY_FLAG_PARALLEL_DETECT;
1627adfc5217SJeff Kirsher 		}
1628adfc5217SJeff Kirsher 		bp->link_up = 0;
1629adfc5217SJeff Kirsher 	}
1630adfc5217SJeff Kirsher 
1631adfc5217SJeff Kirsher 	if (bp->link_up != link_up) {
1632adfc5217SJeff Kirsher 		bnx2_report_link(bp);
1633adfc5217SJeff Kirsher 	}
1634adfc5217SJeff Kirsher 
1635adfc5217SJeff Kirsher 	bnx2_set_mac_link(bp);
1636adfc5217SJeff Kirsher 
1637adfc5217SJeff Kirsher 	return 0;
1638adfc5217SJeff Kirsher }
1639adfc5217SJeff Kirsher 
1640adfc5217SJeff Kirsher static int
1641adfc5217SJeff Kirsher bnx2_reset_phy(struct bnx2 *bp)
1642adfc5217SJeff Kirsher {
1643adfc5217SJeff Kirsher 	int i;
1644adfc5217SJeff Kirsher 	u32 reg;
1645adfc5217SJeff Kirsher 
1646adfc5217SJeff Kirsher         bnx2_write_phy(bp, bp->mii_bmcr, BMCR_RESET);
1647adfc5217SJeff Kirsher 
1648adfc5217SJeff Kirsher #define PHY_RESET_MAX_WAIT 100
1649adfc5217SJeff Kirsher 	for (i = 0; i < PHY_RESET_MAX_WAIT; i++) {
1650adfc5217SJeff Kirsher 		udelay(10);
1651adfc5217SJeff Kirsher 
1652adfc5217SJeff Kirsher 		bnx2_read_phy(bp, bp->mii_bmcr, &reg);
1653adfc5217SJeff Kirsher 		if (!(reg & BMCR_RESET)) {
1654adfc5217SJeff Kirsher 			udelay(20);
1655adfc5217SJeff Kirsher 			break;
1656adfc5217SJeff Kirsher 		}
1657adfc5217SJeff Kirsher 	}
1658adfc5217SJeff Kirsher 	if (i == PHY_RESET_MAX_WAIT) {
1659adfc5217SJeff Kirsher 		return -EBUSY;
1660adfc5217SJeff Kirsher 	}
1661adfc5217SJeff Kirsher 	return 0;
1662adfc5217SJeff Kirsher }
1663adfc5217SJeff Kirsher 
1664adfc5217SJeff Kirsher static u32
1665adfc5217SJeff Kirsher bnx2_phy_get_pause_adv(struct bnx2 *bp)
1666adfc5217SJeff Kirsher {
1667adfc5217SJeff Kirsher 	u32 adv = 0;
1668adfc5217SJeff Kirsher 
1669adfc5217SJeff Kirsher 	if ((bp->req_flow_ctrl & (FLOW_CTRL_RX | FLOW_CTRL_TX)) ==
1670adfc5217SJeff Kirsher 		(FLOW_CTRL_RX | FLOW_CTRL_TX)) {
1671adfc5217SJeff Kirsher 
1672adfc5217SJeff Kirsher 		if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
1673adfc5217SJeff Kirsher 			adv = ADVERTISE_1000XPAUSE;
1674adfc5217SJeff Kirsher 		}
1675adfc5217SJeff Kirsher 		else {
1676adfc5217SJeff Kirsher 			adv = ADVERTISE_PAUSE_CAP;
1677adfc5217SJeff Kirsher 		}
1678adfc5217SJeff Kirsher 	}
1679adfc5217SJeff Kirsher 	else if (bp->req_flow_ctrl & FLOW_CTRL_TX) {
1680adfc5217SJeff Kirsher 		if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
1681adfc5217SJeff Kirsher 			adv = ADVERTISE_1000XPSE_ASYM;
1682adfc5217SJeff Kirsher 		}
1683adfc5217SJeff Kirsher 		else {
1684adfc5217SJeff Kirsher 			adv = ADVERTISE_PAUSE_ASYM;
1685adfc5217SJeff Kirsher 		}
1686adfc5217SJeff Kirsher 	}
1687adfc5217SJeff Kirsher 	else if (bp->req_flow_ctrl & FLOW_CTRL_RX) {
1688adfc5217SJeff Kirsher 		if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
1689adfc5217SJeff Kirsher 			adv = ADVERTISE_1000XPAUSE | ADVERTISE_1000XPSE_ASYM;
1690adfc5217SJeff Kirsher 		}
1691adfc5217SJeff Kirsher 		else {
1692adfc5217SJeff Kirsher 			adv = ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM;
1693adfc5217SJeff Kirsher 		}
1694adfc5217SJeff Kirsher 	}
1695adfc5217SJeff Kirsher 	return adv;
1696adfc5217SJeff Kirsher }
1697adfc5217SJeff Kirsher 
1698adfc5217SJeff Kirsher static int bnx2_fw_sync(struct bnx2 *, u32, int, int);
1699adfc5217SJeff Kirsher 
1700adfc5217SJeff Kirsher static int
1701adfc5217SJeff Kirsher bnx2_setup_remote_phy(struct bnx2 *bp, u8 port)
1702adfc5217SJeff Kirsher __releases(&bp->phy_lock)
1703adfc5217SJeff Kirsher __acquires(&bp->phy_lock)
1704adfc5217SJeff Kirsher {
1705adfc5217SJeff Kirsher 	u32 speed_arg = 0, pause_adv;
1706adfc5217SJeff Kirsher 
1707adfc5217SJeff Kirsher 	pause_adv = bnx2_phy_get_pause_adv(bp);
1708adfc5217SJeff Kirsher 
1709adfc5217SJeff Kirsher 	if (bp->autoneg & AUTONEG_SPEED) {
1710adfc5217SJeff Kirsher 		speed_arg |= BNX2_NETLINK_SET_LINK_ENABLE_AUTONEG;
1711adfc5217SJeff Kirsher 		if (bp->advertising & ADVERTISED_10baseT_Half)
1712adfc5217SJeff Kirsher 			speed_arg |= BNX2_NETLINK_SET_LINK_SPEED_10HALF;
1713adfc5217SJeff Kirsher 		if (bp->advertising & ADVERTISED_10baseT_Full)
1714adfc5217SJeff Kirsher 			speed_arg |= BNX2_NETLINK_SET_LINK_SPEED_10FULL;
1715adfc5217SJeff Kirsher 		if (bp->advertising & ADVERTISED_100baseT_Half)
1716adfc5217SJeff Kirsher 			speed_arg |= BNX2_NETLINK_SET_LINK_SPEED_100HALF;
1717adfc5217SJeff Kirsher 		if (bp->advertising & ADVERTISED_100baseT_Full)
1718adfc5217SJeff Kirsher 			speed_arg |= BNX2_NETLINK_SET_LINK_SPEED_100FULL;
1719adfc5217SJeff Kirsher 		if (bp->advertising & ADVERTISED_1000baseT_Full)
1720adfc5217SJeff Kirsher 			speed_arg |= BNX2_NETLINK_SET_LINK_SPEED_1GFULL;
1721adfc5217SJeff Kirsher 		if (bp->advertising & ADVERTISED_2500baseX_Full)
1722adfc5217SJeff Kirsher 			speed_arg |= BNX2_NETLINK_SET_LINK_SPEED_2G5FULL;
1723adfc5217SJeff Kirsher 	} else {
1724adfc5217SJeff Kirsher 		if (bp->req_line_speed == SPEED_2500)
1725adfc5217SJeff Kirsher 			speed_arg = BNX2_NETLINK_SET_LINK_SPEED_2G5FULL;
1726adfc5217SJeff Kirsher 		else if (bp->req_line_speed == SPEED_1000)
1727adfc5217SJeff Kirsher 			speed_arg = BNX2_NETLINK_SET_LINK_SPEED_1GFULL;
1728adfc5217SJeff Kirsher 		else if (bp->req_line_speed == SPEED_100) {
1729adfc5217SJeff Kirsher 			if (bp->req_duplex == DUPLEX_FULL)
1730adfc5217SJeff Kirsher 				speed_arg = BNX2_NETLINK_SET_LINK_SPEED_100FULL;
1731adfc5217SJeff Kirsher 			else
1732adfc5217SJeff Kirsher 				speed_arg = BNX2_NETLINK_SET_LINK_SPEED_100HALF;
1733adfc5217SJeff Kirsher 		} else if (bp->req_line_speed == SPEED_10) {
1734adfc5217SJeff Kirsher 			if (bp->req_duplex == DUPLEX_FULL)
1735adfc5217SJeff Kirsher 				speed_arg = BNX2_NETLINK_SET_LINK_SPEED_10FULL;
1736adfc5217SJeff Kirsher 			else
1737adfc5217SJeff Kirsher 				speed_arg = BNX2_NETLINK_SET_LINK_SPEED_10HALF;
1738adfc5217SJeff Kirsher 		}
1739adfc5217SJeff Kirsher 	}
1740adfc5217SJeff Kirsher 
1741adfc5217SJeff Kirsher 	if (pause_adv & (ADVERTISE_1000XPAUSE | ADVERTISE_PAUSE_CAP))
1742adfc5217SJeff Kirsher 		speed_arg |= BNX2_NETLINK_SET_LINK_FC_SYM_PAUSE;
1743adfc5217SJeff Kirsher 	if (pause_adv & (ADVERTISE_1000XPSE_ASYM | ADVERTISE_PAUSE_ASYM))
1744adfc5217SJeff Kirsher 		speed_arg |= BNX2_NETLINK_SET_LINK_FC_ASYM_PAUSE;
1745adfc5217SJeff Kirsher 
1746adfc5217SJeff Kirsher 	if (port == PORT_TP)
1747adfc5217SJeff Kirsher 		speed_arg |= BNX2_NETLINK_SET_LINK_PHY_APP_REMOTE |
1748adfc5217SJeff Kirsher 			     BNX2_NETLINK_SET_LINK_ETH_AT_WIRESPEED;
1749adfc5217SJeff Kirsher 
1750adfc5217SJeff Kirsher 	bnx2_shmem_wr(bp, BNX2_DRV_MB_ARG0, speed_arg);
1751adfc5217SJeff Kirsher 
1752adfc5217SJeff Kirsher 	spin_unlock_bh(&bp->phy_lock);
1753adfc5217SJeff Kirsher 	bnx2_fw_sync(bp, BNX2_DRV_MSG_CODE_CMD_SET_LINK, 1, 0);
1754adfc5217SJeff Kirsher 	spin_lock_bh(&bp->phy_lock);
1755adfc5217SJeff Kirsher 
1756adfc5217SJeff Kirsher 	return 0;
1757adfc5217SJeff Kirsher }
1758adfc5217SJeff Kirsher 
1759adfc5217SJeff Kirsher static int
1760adfc5217SJeff Kirsher bnx2_setup_serdes_phy(struct bnx2 *bp, u8 port)
1761adfc5217SJeff Kirsher __releases(&bp->phy_lock)
1762adfc5217SJeff Kirsher __acquires(&bp->phy_lock)
1763adfc5217SJeff Kirsher {
1764adfc5217SJeff Kirsher 	u32 adv, bmcr;
1765adfc5217SJeff Kirsher 	u32 new_adv = 0;
1766adfc5217SJeff Kirsher 
1767adfc5217SJeff Kirsher 	if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
1768adfc5217SJeff Kirsher 		return bnx2_setup_remote_phy(bp, port);
1769adfc5217SJeff Kirsher 
1770adfc5217SJeff Kirsher 	if (!(bp->autoneg & AUTONEG_SPEED)) {
1771adfc5217SJeff Kirsher 		u32 new_bmcr;
1772adfc5217SJeff Kirsher 		int force_link_down = 0;
1773adfc5217SJeff Kirsher 
1774adfc5217SJeff Kirsher 		if (bp->req_line_speed == SPEED_2500) {
1775adfc5217SJeff Kirsher 			if (!bnx2_test_and_enable_2g5(bp))
1776adfc5217SJeff Kirsher 				force_link_down = 1;
1777adfc5217SJeff Kirsher 		} else if (bp->req_line_speed == SPEED_1000) {
1778adfc5217SJeff Kirsher 			if (bnx2_test_and_disable_2g5(bp))
1779adfc5217SJeff Kirsher 				force_link_down = 1;
1780adfc5217SJeff Kirsher 		}
1781adfc5217SJeff Kirsher 		bnx2_read_phy(bp, bp->mii_adv, &adv);
1782adfc5217SJeff Kirsher 		adv &= ~(ADVERTISE_1000XFULL | ADVERTISE_1000XHALF);
1783adfc5217SJeff Kirsher 
1784adfc5217SJeff Kirsher 		bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
1785adfc5217SJeff Kirsher 		new_bmcr = bmcr & ~BMCR_ANENABLE;
1786adfc5217SJeff Kirsher 		new_bmcr |= BMCR_SPEED1000;
1787adfc5217SJeff Kirsher 
17884ce45e02SMichael Chan 		if (BNX2_CHIP(bp) == BNX2_CHIP_5709) {
1789adfc5217SJeff Kirsher 			if (bp->req_line_speed == SPEED_2500)
1790adfc5217SJeff Kirsher 				bnx2_enable_forced_2g5(bp);
1791adfc5217SJeff Kirsher 			else if (bp->req_line_speed == SPEED_1000) {
1792adfc5217SJeff Kirsher 				bnx2_disable_forced_2g5(bp);
1793adfc5217SJeff Kirsher 				new_bmcr &= ~0x2000;
1794adfc5217SJeff Kirsher 			}
1795adfc5217SJeff Kirsher 
17964ce45e02SMichael Chan 		} else if (BNX2_CHIP(bp) == BNX2_CHIP_5708) {
1797adfc5217SJeff Kirsher 			if (bp->req_line_speed == SPEED_2500)
1798adfc5217SJeff Kirsher 				new_bmcr |= BCM5708S_BMCR_FORCE_2500;
1799adfc5217SJeff Kirsher 			else
1800adfc5217SJeff Kirsher 				new_bmcr = bmcr & ~BCM5708S_BMCR_FORCE_2500;
1801adfc5217SJeff Kirsher 		}
1802adfc5217SJeff Kirsher 
1803adfc5217SJeff Kirsher 		if (bp->req_duplex == DUPLEX_FULL) {
1804adfc5217SJeff Kirsher 			adv |= ADVERTISE_1000XFULL;
1805adfc5217SJeff Kirsher 			new_bmcr |= BMCR_FULLDPLX;
1806adfc5217SJeff Kirsher 		}
1807adfc5217SJeff Kirsher 		else {
1808adfc5217SJeff Kirsher 			adv |= ADVERTISE_1000XHALF;
1809adfc5217SJeff Kirsher 			new_bmcr &= ~BMCR_FULLDPLX;
1810adfc5217SJeff Kirsher 		}
1811adfc5217SJeff Kirsher 		if ((new_bmcr != bmcr) || (force_link_down)) {
1812adfc5217SJeff Kirsher 			/* Force a link down visible on the other side */
1813adfc5217SJeff Kirsher 			if (bp->link_up) {
1814adfc5217SJeff Kirsher 				bnx2_write_phy(bp, bp->mii_adv, adv &
1815adfc5217SJeff Kirsher 					       ~(ADVERTISE_1000XFULL |
1816adfc5217SJeff Kirsher 						 ADVERTISE_1000XHALF));
1817adfc5217SJeff Kirsher 				bnx2_write_phy(bp, bp->mii_bmcr, bmcr |
1818adfc5217SJeff Kirsher 					BMCR_ANRESTART | BMCR_ANENABLE);
1819adfc5217SJeff Kirsher 
1820adfc5217SJeff Kirsher 				bp->link_up = 0;
1821adfc5217SJeff Kirsher 				netif_carrier_off(bp->dev);
1822adfc5217SJeff Kirsher 				bnx2_write_phy(bp, bp->mii_bmcr, new_bmcr);
1823adfc5217SJeff Kirsher 				bnx2_report_link(bp);
1824adfc5217SJeff Kirsher 			}
1825adfc5217SJeff Kirsher 			bnx2_write_phy(bp, bp->mii_adv, adv);
1826adfc5217SJeff Kirsher 			bnx2_write_phy(bp, bp->mii_bmcr, new_bmcr);
1827adfc5217SJeff Kirsher 		} else {
1828adfc5217SJeff Kirsher 			bnx2_resolve_flow_ctrl(bp);
1829adfc5217SJeff Kirsher 			bnx2_set_mac_link(bp);
1830adfc5217SJeff Kirsher 		}
1831adfc5217SJeff Kirsher 		return 0;
1832adfc5217SJeff Kirsher 	}
1833adfc5217SJeff Kirsher 
1834adfc5217SJeff Kirsher 	bnx2_test_and_enable_2g5(bp);
1835adfc5217SJeff Kirsher 
1836adfc5217SJeff Kirsher 	if (bp->advertising & ADVERTISED_1000baseT_Full)
1837adfc5217SJeff Kirsher 		new_adv |= ADVERTISE_1000XFULL;
1838adfc5217SJeff Kirsher 
1839adfc5217SJeff Kirsher 	new_adv |= bnx2_phy_get_pause_adv(bp);
1840adfc5217SJeff Kirsher 
1841adfc5217SJeff Kirsher 	bnx2_read_phy(bp, bp->mii_adv, &adv);
1842adfc5217SJeff Kirsher 	bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
1843adfc5217SJeff Kirsher 
1844adfc5217SJeff Kirsher 	bp->serdes_an_pending = 0;
1845adfc5217SJeff Kirsher 	if ((adv != new_adv) || ((bmcr & BMCR_ANENABLE) == 0)) {
1846adfc5217SJeff Kirsher 		/* Force a link down visible on the other side */
1847adfc5217SJeff Kirsher 		if (bp->link_up) {
1848adfc5217SJeff Kirsher 			bnx2_write_phy(bp, bp->mii_bmcr, BMCR_LOOPBACK);
1849adfc5217SJeff Kirsher 			spin_unlock_bh(&bp->phy_lock);
1850adfc5217SJeff Kirsher 			msleep(20);
1851adfc5217SJeff Kirsher 			spin_lock_bh(&bp->phy_lock);
1852adfc5217SJeff Kirsher 		}
1853adfc5217SJeff Kirsher 
1854adfc5217SJeff Kirsher 		bnx2_write_phy(bp, bp->mii_adv, new_adv);
1855adfc5217SJeff Kirsher 		bnx2_write_phy(bp, bp->mii_bmcr, bmcr | BMCR_ANRESTART |
1856adfc5217SJeff Kirsher 			BMCR_ANENABLE);
1857adfc5217SJeff Kirsher 		/* Speed up link-up time when the link partner
1858adfc5217SJeff Kirsher 		 * does not autonegotiate which is very common
1859adfc5217SJeff Kirsher 		 * in blade servers. Some blade servers use
1860adfc5217SJeff Kirsher 		 * IPMI for kerboard input and it's important
1861adfc5217SJeff Kirsher 		 * to minimize link disruptions. Autoneg. involves
1862adfc5217SJeff Kirsher 		 * exchanging base pages plus 3 next pages and
1863adfc5217SJeff Kirsher 		 * normally completes in about 120 msec.
1864adfc5217SJeff Kirsher 		 */
1865adfc5217SJeff Kirsher 		bp->current_interval = BNX2_SERDES_AN_TIMEOUT;
1866adfc5217SJeff Kirsher 		bp->serdes_an_pending = 1;
1867adfc5217SJeff Kirsher 		mod_timer(&bp->timer, jiffies + bp->current_interval);
1868adfc5217SJeff Kirsher 	} else {
1869adfc5217SJeff Kirsher 		bnx2_resolve_flow_ctrl(bp);
1870adfc5217SJeff Kirsher 		bnx2_set_mac_link(bp);
1871adfc5217SJeff Kirsher 	}
1872adfc5217SJeff Kirsher 
1873adfc5217SJeff Kirsher 	return 0;
1874adfc5217SJeff Kirsher }
1875adfc5217SJeff Kirsher 
1876adfc5217SJeff Kirsher #define ETHTOOL_ALL_FIBRE_SPEED						\
1877adfc5217SJeff Kirsher 	(bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE) ?			\
1878adfc5217SJeff Kirsher 		(ADVERTISED_2500baseX_Full | ADVERTISED_1000baseT_Full) :\
1879adfc5217SJeff Kirsher 		(ADVERTISED_1000baseT_Full)
1880adfc5217SJeff Kirsher 
1881adfc5217SJeff Kirsher #define ETHTOOL_ALL_COPPER_SPEED					\
1882adfc5217SJeff Kirsher 	(ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full |		\
1883adfc5217SJeff Kirsher 	ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full |		\
1884adfc5217SJeff Kirsher 	ADVERTISED_1000baseT_Full)
1885adfc5217SJeff Kirsher 
1886adfc5217SJeff Kirsher #define PHY_ALL_10_100_SPEED (ADVERTISE_10HALF | ADVERTISE_10FULL | \
1887adfc5217SJeff Kirsher 	ADVERTISE_100HALF | ADVERTISE_100FULL | ADVERTISE_CSMA)
1888adfc5217SJeff Kirsher 
1889adfc5217SJeff Kirsher #define PHY_ALL_1000_SPEED (ADVERTISE_1000HALF | ADVERTISE_1000FULL)
1890adfc5217SJeff Kirsher 
1891adfc5217SJeff Kirsher static void
1892adfc5217SJeff Kirsher bnx2_set_default_remote_link(struct bnx2 *bp)
1893adfc5217SJeff Kirsher {
1894adfc5217SJeff Kirsher 	u32 link;
1895adfc5217SJeff Kirsher 
1896adfc5217SJeff Kirsher 	if (bp->phy_port == PORT_TP)
1897adfc5217SJeff Kirsher 		link = bnx2_shmem_rd(bp, BNX2_RPHY_COPPER_LINK);
1898adfc5217SJeff Kirsher 	else
1899adfc5217SJeff Kirsher 		link = bnx2_shmem_rd(bp, BNX2_RPHY_SERDES_LINK);
1900adfc5217SJeff Kirsher 
1901adfc5217SJeff Kirsher 	if (link & BNX2_NETLINK_SET_LINK_ENABLE_AUTONEG) {
1902adfc5217SJeff Kirsher 		bp->req_line_speed = 0;
1903adfc5217SJeff Kirsher 		bp->autoneg |= AUTONEG_SPEED;
1904adfc5217SJeff Kirsher 		bp->advertising = ADVERTISED_Autoneg;
1905adfc5217SJeff Kirsher 		if (link & BNX2_NETLINK_SET_LINK_SPEED_10HALF)
1906adfc5217SJeff Kirsher 			bp->advertising |= ADVERTISED_10baseT_Half;
1907adfc5217SJeff Kirsher 		if (link & BNX2_NETLINK_SET_LINK_SPEED_10FULL)
1908adfc5217SJeff Kirsher 			bp->advertising |= ADVERTISED_10baseT_Full;
1909adfc5217SJeff Kirsher 		if (link & BNX2_NETLINK_SET_LINK_SPEED_100HALF)
1910adfc5217SJeff Kirsher 			bp->advertising |= ADVERTISED_100baseT_Half;
1911adfc5217SJeff Kirsher 		if (link & BNX2_NETLINK_SET_LINK_SPEED_100FULL)
1912adfc5217SJeff Kirsher 			bp->advertising |= ADVERTISED_100baseT_Full;
1913adfc5217SJeff Kirsher 		if (link & BNX2_NETLINK_SET_LINK_SPEED_1GFULL)
1914adfc5217SJeff Kirsher 			bp->advertising |= ADVERTISED_1000baseT_Full;
1915adfc5217SJeff Kirsher 		if (link & BNX2_NETLINK_SET_LINK_SPEED_2G5FULL)
1916adfc5217SJeff Kirsher 			bp->advertising |= ADVERTISED_2500baseX_Full;
1917adfc5217SJeff Kirsher 	} else {
1918adfc5217SJeff Kirsher 		bp->autoneg = 0;
1919adfc5217SJeff Kirsher 		bp->advertising = 0;
1920adfc5217SJeff Kirsher 		bp->req_duplex = DUPLEX_FULL;
1921adfc5217SJeff Kirsher 		if (link & BNX2_NETLINK_SET_LINK_SPEED_10) {
1922adfc5217SJeff Kirsher 			bp->req_line_speed = SPEED_10;
1923adfc5217SJeff Kirsher 			if (link & BNX2_NETLINK_SET_LINK_SPEED_10HALF)
1924adfc5217SJeff Kirsher 				bp->req_duplex = DUPLEX_HALF;
1925adfc5217SJeff Kirsher 		}
1926adfc5217SJeff Kirsher 		if (link & BNX2_NETLINK_SET_LINK_SPEED_100) {
1927adfc5217SJeff Kirsher 			bp->req_line_speed = SPEED_100;
1928adfc5217SJeff Kirsher 			if (link & BNX2_NETLINK_SET_LINK_SPEED_100HALF)
1929adfc5217SJeff Kirsher 				bp->req_duplex = DUPLEX_HALF;
1930adfc5217SJeff Kirsher 		}
1931adfc5217SJeff Kirsher 		if (link & BNX2_NETLINK_SET_LINK_SPEED_1GFULL)
1932adfc5217SJeff Kirsher 			bp->req_line_speed = SPEED_1000;
1933adfc5217SJeff Kirsher 		if (link & BNX2_NETLINK_SET_LINK_SPEED_2G5FULL)
1934adfc5217SJeff Kirsher 			bp->req_line_speed = SPEED_2500;
1935adfc5217SJeff Kirsher 	}
1936adfc5217SJeff Kirsher }
1937adfc5217SJeff Kirsher 
1938adfc5217SJeff Kirsher static void
1939adfc5217SJeff Kirsher bnx2_set_default_link(struct bnx2 *bp)
1940adfc5217SJeff Kirsher {
1941adfc5217SJeff Kirsher 	if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP) {
1942adfc5217SJeff Kirsher 		bnx2_set_default_remote_link(bp);
1943adfc5217SJeff Kirsher 		return;
1944adfc5217SJeff Kirsher 	}
1945adfc5217SJeff Kirsher 
1946adfc5217SJeff Kirsher 	bp->autoneg = AUTONEG_SPEED | AUTONEG_FLOW_CTRL;
1947adfc5217SJeff Kirsher 	bp->req_line_speed = 0;
1948adfc5217SJeff Kirsher 	if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
1949adfc5217SJeff Kirsher 		u32 reg;
1950adfc5217SJeff Kirsher 
1951adfc5217SJeff Kirsher 		bp->advertising = ETHTOOL_ALL_FIBRE_SPEED | ADVERTISED_Autoneg;
1952adfc5217SJeff Kirsher 
1953adfc5217SJeff Kirsher 		reg = bnx2_shmem_rd(bp, BNX2_PORT_HW_CFG_CONFIG);
1954adfc5217SJeff Kirsher 		reg &= BNX2_PORT_HW_CFG_CFG_DFLT_LINK_MASK;
1955adfc5217SJeff Kirsher 		if (reg == BNX2_PORT_HW_CFG_CFG_DFLT_LINK_1G) {
1956adfc5217SJeff Kirsher 			bp->autoneg = 0;
1957adfc5217SJeff Kirsher 			bp->req_line_speed = bp->line_speed = SPEED_1000;
1958adfc5217SJeff Kirsher 			bp->req_duplex = DUPLEX_FULL;
1959adfc5217SJeff Kirsher 		}
1960adfc5217SJeff Kirsher 	} else
1961adfc5217SJeff Kirsher 		bp->advertising = ETHTOOL_ALL_COPPER_SPEED | ADVERTISED_Autoneg;
1962adfc5217SJeff Kirsher }
1963adfc5217SJeff Kirsher 
1964adfc5217SJeff Kirsher static void
1965adfc5217SJeff Kirsher bnx2_send_heart_beat(struct bnx2 *bp)
1966adfc5217SJeff Kirsher {
1967adfc5217SJeff Kirsher 	u32 msg;
1968adfc5217SJeff Kirsher 	u32 addr;
1969adfc5217SJeff Kirsher 
1970adfc5217SJeff Kirsher 	spin_lock(&bp->indirect_lock);
1971adfc5217SJeff Kirsher 	msg = (u32) (++bp->fw_drv_pulse_wr_seq & BNX2_DRV_PULSE_SEQ_MASK);
1972adfc5217SJeff Kirsher 	addr = bp->shmem_base + BNX2_DRV_PULSE_MB;
1973e503e066SMichael Chan 	BNX2_WR(bp, BNX2_PCICFG_REG_WINDOW_ADDRESS, addr);
1974e503e066SMichael Chan 	BNX2_WR(bp, BNX2_PCICFG_REG_WINDOW, msg);
1975adfc5217SJeff Kirsher 	spin_unlock(&bp->indirect_lock);
1976adfc5217SJeff Kirsher }
1977adfc5217SJeff Kirsher 
1978adfc5217SJeff Kirsher static void
1979adfc5217SJeff Kirsher bnx2_remote_phy_event(struct bnx2 *bp)
1980adfc5217SJeff Kirsher {
1981adfc5217SJeff Kirsher 	u32 msg;
1982adfc5217SJeff Kirsher 	u8 link_up = bp->link_up;
1983adfc5217SJeff Kirsher 	u8 old_port;
1984adfc5217SJeff Kirsher 
1985adfc5217SJeff Kirsher 	msg = bnx2_shmem_rd(bp, BNX2_LINK_STATUS);
1986adfc5217SJeff Kirsher 
1987adfc5217SJeff Kirsher 	if (msg & BNX2_LINK_STATUS_HEART_BEAT_EXPIRED)
1988adfc5217SJeff Kirsher 		bnx2_send_heart_beat(bp);
1989adfc5217SJeff Kirsher 
1990adfc5217SJeff Kirsher 	msg &= ~BNX2_LINK_STATUS_HEART_BEAT_EXPIRED;
1991adfc5217SJeff Kirsher 
1992adfc5217SJeff Kirsher 	if ((msg & BNX2_LINK_STATUS_LINK_UP) == BNX2_LINK_STATUS_LINK_DOWN)
1993adfc5217SJeff Kirsher 		bp->link_up = 0;
1994adfc5217SJeff Kirsher 	else {
1995adfc5217SJeff Kirsher 		u32 speed;
1996adfc5217SJeff Kirsher 
1997adfc5217SJeff Kirsher 		bp->link_up = 1;
1998adfc5217SJeff Kirsher 		speed = msg & BNX2_LINK_STATUS_SPEED_MASK;
1999adfc5217SJeff Kirsher 		bp->duplex = DUPLEX_FULL;
2000adfc5217SJeff Kirsher 		switch (speed) {
2001adfc5217SJeff Kirsher 			case BNX2_LINK_STATUS_10HALF:
2002adfc5217SJeff Kirsher 				bp->duplex = DUPLEX_HALF;
20037947c9ceSMichael Chan 				/* fall through */
2004adfc5217SJeff Kirsher 			case BNX2_LINK_STATUS_10FULL:
2005adfc5217SJeff Kirsher 				bp->line_speed = SPEED_10;
2006adfc5217SJeff Kirsher 				break;
2007adfc5217SJeff Kirsher 			case BNX2_LINK_STATUS_100HALF:
2008adfc5217SJeff Kirsher 				bp->duplex = DUPLEX_HALF;
20097947c9ceSMichael Chan 				/* fall through */
2010adfc5217SJeff Kirsher 			case BNX2_LINK_STATUS_100BASE_T4:
2011adfc5217SJeff Kirsher 			case BNX2_LINK_STATUS_100FULL:
2012adfc5217SJeff Kirsher 				bp->line_speed = SPEED_100;
2013adfc5217SJeff Kirsher 				break;
2014adfc5217SJeff Kirsher 			case BNX2_LINK_STATUS_1000HALF:
2015adfc5217SJeff Kirsher 				bp->duplex = DUPLEX_HALF;
20167947c9ceSMichael Chan 				/* fall through */
2017adfc5217SJeff Kirsher 			case BNX2_LINK_STATUS_1000FULL:
2018adfc5217SJeff Kirsher 				bp->line_speed = SPEED_1000;
2019adfc5217SJeff Kirsher 				break;
2020adfc5217SJeff Kirsher 			case BNX2_LINK_STATUS_2500HALF:
2021adfc5217SJeff Kirsher 				bp->duplex = DUPLEX_HALF;
20227947c9ceSMichael Chan 				/* fall through */
2023adfc5217SJeff Kirsher 			case BNX2_LINK_STATUS_2500FULL:
2024adfc5217SJeff Kirsher 				bp->line_speed = SPEED_2500;
2025adfc5217SJeff Kirsher 				break;
2026adfc5217SJeff Kirsher 			default:
2027adfc5217SJeff Kirsher 				bp->line_speed = 0;
2028adfc5217SJeff Kirsher 				break;
2029adfc5217SJeff Kirsher 		}
2030adfc5217SJeff Kirsher 
2031adfc5217SJeff Kirsher 		bp->flow_ctrl = 0;
2032adfc5217SJeff Kirsher 		if ((bp->autoneg & (AUTONEG_SPEED | AUTONEG_FLOW_CTRL)) !=
2033adfc5217SJeff Kirsher 		    (AUTONEG_SPEED | AUTONEG_FLOW_CTRL)) {
2034adfc5217SJeff Kirsher 			if (bp->duplex == DUPLEX_FULL)
2035adfc5217SJeff Kirsher 				bp->flow_ctrl = bp->req_flow_ctrl;
2036adfc5217SJeff Kirsher 		} else {
2037adfc5217SJeff Kirsher 			if (msg & BNX2_LINK_STATUS_TX_FC_ENABLED)
2038adfc5217SJeff Kirsher 				bp->flow_ctrl |= FLOW_CTRL_TX;
2039adfc5217SJeff Kirsher 			if (msg & BNX2_LINK_STATUS_RX_FC_ENABLED)
2040adfc5217SJeff Kirsher 				bp->flow_ctrl |= FLOW_CTRL_RX;
2041adfc5217SJeff Kirsher 		}
2042adfc5217SJeff Kirsher 
2043adfc5217SJeff Kirsher 		old_port = bp->phy_port;
2044adfc5217SJeff Kirsher 		if (msg & BNX2_LINK_STATUS_SERDES_LINK)
2045adfc5217SJeff Kirsher 			bp->phy_port = PORT_FIBRE;
2046adfc5217SJeff Kirsher 		else
2047adfc5217SJeff Kirsher 			bp->phy_port = PORT_TP;
2048adfc5217SJeff Kirsher 
2049adfc5217SJeff Kirsher 		if (old_port != bp->phy_port)
2050adfc5217SJeff Kirsher 			bnx2_set_default_link(bp);
2051adfc5217SJeff Kirsher 
2052adfc5217SJeff Kirsher 	}
2053adfc5217SJeff Kirsher 	if (bp->link_up != link_up)
2054adfc5217SJeff Kirsher 		bnx2_report_link(bp);
2055adfc5217SJeff Kirsher 
2056adfc5217SJeff Kirsher 	bnx2_set_mac_link(bp);
2057adfc5217SJeff Kirsher }
2058adfc5217SJeff Kirsher 
2059adfc5217SJeff Kirsher static int
2060adfc5217SJeff Kirsher bnx2_set_remote_link(struct bnx2 *bp)
2061adfc5217SJeff Kirsher {
2062adfc5217SJeff Kirsher 	u32 evt_code;
2063adfc5217SJeff Kirsher 
2064adfc5217SJeff Kirsher 	evt_code = bnx2_shmem_rd(bp, BNX2_FW_EVT_CODE_MB);
2065adfc5217SJeff Kirsher 	switch (evt_code) {
2066adfc5217SJeff Kirsher 		case BNX2_FW_EVT_CODE_LINK_EVENT:
2067adfc5217SJeff Kirsher 			bnx2_remote_phy_event(bp);
2068adfc5217SJeff Kirsher 			break;
2069adfc5217SJeff Kirsher 		case BNX2_FW_EVT_CODE_SW_TIMER_EXPIRATION_EVENT:
2070adfc5217SJeff Kirsher 		default:
2071adfc5217SJeff Kirsher 			bnx2_send_heart_beat(bp);
2072adfc5217SJeff Kirsher 			break;
2073adfc5217SJeff Kirsher 	}
2074adfc5217SJeff Kirsher 	return 0;
2075adfc5217SJeff Kirsher }
2076adfc5217SJeff Kirsher 
2077adfc5217SJeff Kirsher static int
2078adfc5217SJeff Kirsher bnx2_setup_copper_phy(struct bnx2 *bp)
2079adfc5217SJeff Kirsher __releases(&bp->phy_lock)
2080adfc5217SJeff Kirsher __acquires(&bp->phy_lock)
2081adfc5217SJeff Kirsher {
2082d17e53bdSMichael Chan 	u32 bmcr, adv_reg, new_adv = 0;
2083adfc5217SJeff Kirsher 	u32 new_bmcr;
2084adfc5217SJeff Kirsher 
2085adfc5217SJeff Kirsher 	bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
2086adfc5217SJeff Kirsher 
2087adfc5217SJeff Kirsher 	bnx2_read_phy(bp, bp->mii_adv, &adv_reg);
2088adfc5217SJeff Kirsher 	adv_reg &= (PHY_ALL_10_100_SPEED | ADVERTISE_PAUSE_CAP |
2089adfc5217SJeff Kirsher 		    ADVERTISE_PAUSE_ASYM);
2090adfc5217SJeff Kirsher 
2091d17e53bdSMichael Chan 	new_adv = ADVERTISE_CSMA | ethtool_adv_to_mii_adv_t(bp->advertising);
2092d17e53bdSMichael Chan 
2093d17e53bdSMichael Chan 	if (bp->autoneg & AUTONEG_SPEED) {
2094d17e53bdSMichael Chan 		u32 adv1000_reg;
2095d17e53bdSMichael Chan 		u32 new_adv1000 = 0;
2096d17e53bdSMichael Chan 
2097d17e53bdSMichael Chan 		new_adv |= bnx2_phy_get_pause_adv(bp);
2098d17e53bdSMichael Chan 
2099adfc5217SJeff Kirsher 		bnx2_read_phy(bp, MII_CTRL1000, &adv1000_reg);
2100adfc5217SJeff Kirsher 		adv1000_reg &= PHY_ALL_1000_SPEED;
2101adfc5217SJeff Kirsher 
210237f07023SMatt Carlson 		new_adv1000 |= ethtool_adv_to_mii_ctrl1000_t(bp->advertising);
210337f07023SMatt Carlson 		if ((adv1000_reg != new_adv1000) ||
210437f07023SMatt Carlson 			(adv_reg != new_adv) ||
2105adfc5217SJeff Kirsher 			((bmcr & BMCR_ANENABLE) == 0)) {
2106adfc5217SJeff Kirsher 
210737f07023SMatt Carlson 			bnx2_write_phy(bp, bp->mii_adv, new_adv);
210837f07023SMatt Carlson 			bnx2_write_phy(bp, MII_CTRL1000, new_adv1000);
2109adfc5217SJeff Kirsher 			bnx2_write_phy(bp, bp->mii_bmcr, BMCR_ANRESTART |
2110adfc5217SJeff Kirsher 				BMCR_ANENABLE);
2111adfc5217SJeff Kirsher 		}
2112adfc5217SJeff Kirsher 		else if (bp->link_up) {
2113adfc5217SJeff Kirsher 			/* Flow ctrl may have changed from auto to forced */
2114adfc5217SJeff Kirsher 			/* or vice-versa. */
2115adfc5217SJeff Kirsher 
2116adfc5217SJeff Kirsher 			bnx2_resolve_flow_ctrl(bp);
2117adfc5217SJeff Kirsher 			bnx2_set_mac_link(bp);
2118adfc5217SJeff Kirsher 		}
2119adfc5217SJeff Kirsher 		return 0;
2120adfc5217SJeff Kirsher 	}
2121adfc5217SJeff Kirsher 
2122d17e53bdSMichael Chan 	/* advertise nothing when forcing speed */
2123d17e53bdSMichael Chan 	if (adv_reg != new_adv)
2124d17e53bdSMichael Chan 		bnx2_write_phy(bp, bp->mii_adv, new_adv);
2125d17e53bdSMichael Chan 
2126adfc5217SJeff Kirsher 	new_bmcr = 0;
2127adfc5217SJeff Kirsher 	if (bp->req_line_speed == SPEED_100) {
2128adfc5217SJeff Kirsher 		new_bmcr |= BMCR_SPEED100;
2129adfc5217SJeff Kirsher 	}
2130adfc5217SJeff Kirsher 	if (bp->req_duplex == DUPLEX_FULL) {
2131adfc5217SJeff Kirsher 		new_bmcr |= BMCR_FULLDPLX;
2132adfc5217SJeff Kirsher 	}
2133adfc5217SJeff Kirsher 	if (new_bmcr != bmcr) {
2134adfc5217SJeff Kirsher 		u32 bmsr;
2135adfc5217SJeff Kirsher 
2136adfc5217SJeff Kirsher 		bnx2_read_phy(bp, bp->mii_bmsr, &bmsr);
2137adfc5217SJeff Kirsher 		bnx2_read_phy(bp, bp->mii_bmsr, &bmsr);
2138adfc5217SJeff Kirsher 
2139adfc5217SJeff Kirsher 		if (bmsr & BMSR_LSTATUS) {
2140adfc5217SJeff Kirsher 			/* Force link down */
2141adfc5217SJeff Kirsher 			bnx2_write_phy(bp, bp->mii_bmcr, BMCR_LOOPBACK);
2142adfc5217SJeff Kirsher 			spin_unlock_bh(&bp->phy_lock);
2143adfc5217SJeff Kirsher 			msleep(50);
2144adfc5217SJeff Kirsher 			spin_lock_bh(&bp->phy_lock);
2145adfc5217SJeff Kirsher 
2146adfc5217SJeff Kirsher 			bnx2_read_phy(bp, bp->mii_bmsr, &bmsr);
2147adfc5217SJeff Kirsher 			bnx2_read_phy(bp, bp->mii_bmsr, &bmsr);
2148adfc5217SJeff Kirsher 		}
2149adfc5217SJeff Kirsher 
2150adfc5217SJeff Kirsher 		bnx2_write_phy(bp, bp->mii_bmcr, new_bmcr);
2151adfc5217SJeff Kirsher 
2152adfc5217SJeff Kirsher 		/* Normally, the new speed is setup after the link has
2153adfc5217SJeff Kirsher 		 * gone down and up again. In some cases, link will not go
2154adfc5217SJeff Kirsher 		 * down so we need to set up the new speed here.
2155adfc5217SJeff Kirsher 		 */
2156adfc5217SJeff Kirsher 		if (bmsr & BMSR_LSTATUS) {
2157adfc5217SJeff Kirsher 			bp->line_speed = bp->req_line_speed;
2158adfc5217SJeff Kirsher 			bp->duplex = bp->req_duplex;
2159adfc5217SJeff Kirsher 			bnx2_resolve_flow_ctrl(bp);
2160adfc5217SJeff Kirsher 			bnx2_set_mac_link(bp);
2161adfc5217SJeff Kirsher 		}
2162adfc5217SJeff Kirsher 	} else {
2163adfc5217SJeff Kirsher 		bnx2_resolve_flow_ctrl(bp);
2164adfc5217SJeff Kirsher 		bnx2_set_mac_link(bp);
2165adfc5217SJeff Kirsher 	}
2166adfc5217SJeff Kirsher 	return 0;
2167adfc5217SJeff Kirsher }
2168adfc5217SJeff Kirsher 
2169adfc5217SJeff Kirsher static int
2170adfc5217SJeff Kirsher bnx2_setup_phy(struct bnx2 *bp, u8 port)
2171adfc5217SJeff Kirsher __releases(&bp->phy_lock)
2172adfc5217SJeff Kirsher __acquires(&bp->phy_lock)
2173adfc5217SJeff Kirsher {
2174adfc5217SJeff Kirsher 	if (bp->loopback == MAC_LOOPBACK)
2175adfc5217SJeff Kirsher 		return 0;
2176adfc5217SJeff Kirsher 
2177adfc5217SJeff Kirsher 	if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
2178adfc5217SJeff Kirsher 		return bnx2_setup_serdes_phy(bp, port);
2179adfc5217SJeff Kirsher 	}
2180adfc5217SJeff Kirsher 	else {
2181adfc5217SJeff Kirsher 		return bnx2_setup_copper_phy(bp);
2182adfc5217SJeff Kirsher 	}
2183adfc5217SJeff Kirsher }
2184adfc5217SJeff Kirsher 
2185adfc5217SJeff Kirsher static int
2186adfc5217SJeff Kirsher bnx2_init_5709s_phy(struct bnx2 *bp, int reset_phy)
2187adfc5217SJeff Kirsher {
2188adfc5217SJeff Kirsher 	u32 val;
2189adfc5217SJeff Kirsher 
2190adfc5217SJeff Kirsher 	bp->mii_bmcr = MII_BMCR + 0x10;
2191adfc5217SJeff Kirsher 	bp->mii_bmsr = MII_BMSR + 0x10;
2192adfc5217SJeff Kirsher 	bp->mii_bmsr1 = MII_BNX2_GP_TOP_AN_STATUS1;
2193adfc5217SJeff Kirsher 	bp->mii_adv = MII_ADVERTISE + 0x10;
2194adfc5217SJeff Kirsher 	bp->mii_lpa = MII_LPA + 0x10;
2195adfc5217SJeff Kirsher 	bp->mii_up1 = MII_BNX2_OVER1G_UP1;
2196adfc5217SJeff Kirsher 
2197adfc5217SJeff Kirsher 	bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_AER);
2198adfc5217SJeff Kirsher 	bnx2_write_phy(bp, MII_BNX2_AER_AER, MII_BNX2_AER_AER_AN_MMD);
2199adfc5217SJeff Kirsher 
2200adfc5217SJeff Kirsher 	bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
2201adfc5217SJeff Kirsher 	if (reset_phy)
2202adfc5217SJeff Kirsher 		bnx2_reset_phy(bp);
2203adfc5217SJeff Kirsher 
2204adfc5217SJeff Kirsher 	bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_SERDES_DIG);
2205adfc5217SJeff Kirsher 
2206adfc5217SJeff Kirsher 	bnx2_read_phy(bp, MII_BNX2_SERDES_DIG_1000XCTL1, &val);
2207adfc5217SJeff Kirsher 	val &= ~MII_BNX2_SD_1000XCTL1_AUTODET;
2208adfc5217SJeff Kirsher 	val |= MII_BNX2_SD_1000XCTL1_FIBER;
2209adfc5217SJeff Kirsher 	bnx2_write_phy(bp, MII_BNX2_SERDES_DIG_1000XCTL1, val);
2210adfc5217SJeff Kirsher 
2211adfc5217SJeff Kirsher 	bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_OVER1G);
2212adfc5217SJeff Kirsher 	bnx2_read_phy(bp, MII_BNX2_OVER1G_UP1, &val);
2213adfc5217SJeff Kirsher 	if (bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE)
2214adfc5217SJeff Kirsher 		val |= BCM5708S_UP1_2G5;
2215adfc5217SJeff Kirsher 	else
2216adfc5217SJeff Kirsher 		val &= ~BCM5708S_UP1_2G5;
2217adfc5217SJeff Kirsher 	bnx2_write_phy(bp, MII_BNX2_OVER1G_UP1, val);
2218adfc5217SJeff Kirsher 
2219adfc5217SJeff Kirsher 	bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_BAM_NXTPG);
2220adfc5217SJeff Kirsher 	bnx2_read_phy(bp, MII_BNX2_BAM_NXTPG_CTL, &val);
2221adfc5217SJeff Kirsher 	val |= MII_BNX2_NXTPG_CTL_T2 | MII_BNX2_NXTPG_CTL_BAM;
2222adfc5217SJeff Kirsher 	bnx2_write_phy(bp, MII_BNX2_BAM_NXTPG_CTL, val);
2223adfc5217SJeff Kirsher 
2224adfc5217SJeff Kirsher 	bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_CL73_USERB0);
2225adfc5217SJeff Kirsher 
2226adfc5217SJeff Kirsher 	val = MII_BNX2_CL73_BAM_EN | MII_BNX2_CL73_BAM_STA_MGR_EN |
2227adfc5217SJeff Kirsher 	      MII_BNX2_CL73_BAM_NP_AFT_BP_EN;
2228adfc5217SJeff Kirsher 	bnx2_write_phy(bp, MII_BNX2_CL73_BAM_CTL1, val);
2229adfc5217SJeff Kirsher 
2230adfc5217SJeff Kirsher 	bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
2231adfc5217SJeff Kirsher 
2232adfc5217SJeff Kirsher 	return 0;
2233adfc5217SJeff Kirsher }
2234adfc5217SJeff Kirsher 
2235adfc5217SJeff Kirsher static int
2236adfc5217SJeff Kirsher bnx2_init_5708s_phy(struct bnx2 *bp, int reset_phy)
2237adfc5217SJeff Kirsher {
2238adfc5217SJeff Kirsher 	u32 val;
2239adfc5217SJeff Kirsher 
2240adfc5217SJeff Kirsher 	if (reset_phy)
2241adfc5217SJeff Kirsher 		bnx2_reset_phy(bp);
2242adfc5217SJeff Kirsher 
2243adfc5217SJeff Kirsher 	bp->mii_up1 = BCM5708S_UP1;
2244adfc5217SJeff Kirsher 
2245adfc5217SJeff Kirsher 	bnx2_write_phy(bp, BCM5708S_BLK_ADDR, BCM5708S_BLK_ADDR_DIG3);
2246adfc5217SJeff Kirsher 	bnx2_write_phy(bp, BCM5708S_DIG_3_0, BCM5708S_DIG_3_0_USE_IEEE);
2247adfc5217SJeff Kirsher 	bnx2_write_phy(bp, BCM5708S_BLK_ADDR, BCM5708S_BLK_ADDR_DIG);
2248adfc5217SJeff Kirsher 
2249adfc5217SJeff Kirsher 	bnx2_read_phy(bp, BCM5708S_1000X_CTL1, &val);
2250adfc5217SJeff Kirsher 	val |= BCM5708S_1000X_CTL1_FIBER_MODE | BCM5708S_1000X_CTL1_AUTODET_EN;
2251adfc5217SJeff Kirsher 	bnx2_write_phy(bp, BCM5708S_1000X_CTL1, val);
2252adfc5217SJeff Kirsher 
2253adfc5217SJeff Kirsher 	bnx2_read_phy(bp, BCM5708S_1000X_CTL2, &val);
2254adfc5217SJeff Kirsher 	val |= BCM5708S_1000X_CTL2_PLLEL_DET_EN;
2255adfc5217SJeff Kirsher 	bnx2_write_phy(bp, BCM5708S_1000X_CTL2, val);
2256adfc5217SJeff Kirsher 
2257adfc5217SJeff Kirsher 	if (bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE) {
2258adfc5217SJeff Kirsher 		bnx2_read_phy(bp, BCM5708S_UP1, &val);
2259adfc5217SJeff Kirsher 		val |= BCM5708S_UP1_2G5;
2260adfc5217SJeff Kirsher 		bnx2_write_phy(bp, BCM5708S_UP1, val);
2261adfc5217SJeff Kirsher 	}
2262adfc5217SJeff Kirsher 
22634ce45e02SMichael Chan 	if ((BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5708_A0) ||
22644ce45e02SMichael Chan 	    (BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5708_B0) ||
22654ce45e02SMichael Chan 	    (BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5708_B1)) {
2266adfc5217SJeff Kirsher 		/* increase tx signal amplitude */
2267adfc5217SJeff Kirsher 		bnx2_write_phy(bp, BCM5708S_BLK_ADDR,
2268adfc5217SJeff Kirsher 			       BCM5708S_BLK_ADDR_TX_MISC);
2269adfc5217SJeff Kirsher 		bnx2_read_phy(bp, BCM5708S_TX_ACTL1, &val);
2270adfc5217SJeff Kirsher 		val &= ~BCM5708S_TX_ACTL1_DRIVER_VCM;
2271adfc5217SJeff Kirsher 		bnx2_write_phy(bp, BCM5708S_TX_ACTL1, val);
2272adfc5217SJeff Kirsher 		bnx2_write_phy(bp, BCM5708S_BLK_ADDR, BCM5708S_BLK_ADDR_DIG);
2273adfc5217SJeff Kirsher 	}
2274adfc5217SJeff Kirsher 
2275adfc5217SJeff Kirsher 	val = bnx2_shmem_rd(bp, BNX2_PORT_HW_CFG_CONFIG) &
2276adfc5217SJeff Kirsher 	      BNX2_PORT_HW_CFG_CFG_TXCTL3_MASK;
2277adfc5217SJeff Kirsher 
2278adfc5217SJeff Kirsher 	if (val) {
2279adfc5217SJeff Kirsher 		u32 is_backplane;
2280adfc5217SJeff Kirsher 
2281adfc5217SJeff Kirsher 		is_backplane = bnx2_shmem_rd(bp, BNX2_SHARED_HW_CFG_CONFIG);
2282adfc5217SJeff Kirsher 		if (is_backplane & BNX2_SHARED_HW_CFG_PHY_BACKPLANE) {
2283adfc5217SJeff Kirsher 			bnx2_write_phy(bp, BCM5708S_BLK_ADDR,
2284adfc5217SJeff Kirsher 				       BCM5708S_BLK_ADDR_TX_MISC);
2285adfc5217SJeff Kirsher 			bnx2_write_phy(bp, BCM5708S_TX_ACTL3, val);
2286adfc5217SJeff Kirsher 			bnx2_write_phy(bp, BCM5708S_BLK_ADDR,
2287adfc5217SJeff Kirsher 				       BCM5708S_BLK_ADDR_DIG);
2288adfc5217SJeff Kirsher 		}
2289adfc5217SJeff Kirsher 	}
2290adfc5217SJeff Kirsher 	return 0;
2291adfc5217SJeff Kirsher }
2292adfc5217SJeff Kirsher 
2293adfc5217SJeff Kirsher static int
2294adfc5217SJeff Kirsher bnx2_init_5706s_phy(struct bnx2 *bp, int reset_phy)
2295adfc5217SJeff Kirsher {
2296adfc5217SJeff Kirsher 	if (reset_phy)
2297adfc5217SJeff Kirsher 		bnx2_reset_phy(bp);
2298adfc5217SJeff Kirsher 
2299adfc5217SJeff Kirsher 	bp->phy_flags &= ~BNX2_PHY_FLAG_PARALLEL_DETECT;
2300adfc5217SJeff Kirsher 
23014ce45e02SMichael Chan 	if (BNX2_CHIP(bp) == BNX2_CHIP_5706)
2302e503e066SMichael Chan 		BNX2_WR(bp, BNX2_MISC_GP_HW_CTL0, 0x300);
2303adfc5217SJeff Kirsher 
2304e1c6dccaSJarod Wilson 	if (bp->dev->mtu > ETH_DATA_LEN) {
2305adfc5217SJeff Kirsher 		u32 val;
2306adfc5217SJeff Kirsher 
2307adfc5217SJeff Kirsher 		/* Set extended packet length bit */
2308adfc5217SJeff Kirsher 		bnx2_write_phy(bp, 0x18, 0x7);
2309adfc5217SJeff Kirsher 		bnx2_read_phy(bp, 0x18, &val);
2310adfc5217SJeff Kirsher 		bnx2_write_phy(bp, 0x18, (val & 0xfff8) | 0x4000);
2311adfc5217SJeff Kirsher 
2312adfc5217SJeff Kirsher 		bnx2_write_phy(bp, 0x1c, 0x6c00);
2313adfc5217SJeff Kirsher 		bnx2_read_phy(bp, 0x1c, &val);
2314adfc5217SJeff Kirsher 		bnx2_write_phy(bp, 0x1c, (val & 0x3ff) | 0xec02);
2315adfc5217SJeff Kirsher 	}
2316adfc5217SJeff Kirsher 	else {
2317adfc5217SJeff Kirsher 		u32 val;
2318adfc5217SJeff Kirsher 
2319adfc5217SJeff Kirsher 		bnx2_write_phy(bp, 0x18, 0x7);
2320adfc5217SJeff Kirsher 		bnx2_read_phy(bp, 0x18, &val);
2321adfc5217SJeff Kirsher 		bnx2_write_phy(bp, 0x18, val & ~0x4007);
2322adfc5217SJeff Kirsher 
2323adfc5217SJeff Kirsher 		bnx2_write_phy(bp, 0x1c, 0x6c00);
2324adfc5217SJeff Kirsher 		bnx2_read_phy(bp, 0x1c, &val);
2325adfc5217SJeff Kirsher 		bnx2_write_phy(bp, 0x1c, (val & 0x3fd) | 0xec00);
2326adfc5217SJeff Kirsher 	}
2327adfc5217SJeff Kirsher 
2328adfc5217SJeff Kirsher 	return 0;
2329adfc5217SJeff Kirsher }
2330adfc5217SJeff Kirsher 
2331adfc5217SJeff Kirsher static int
2332adfc5217SJeff Kirsher bnx2_init_copper_phy(struct bnx2 *bp, int reset_phy)
2333adfc5217SJeff Kirsher {
2334adfc5217SJeff Kirsher 	u32 val;
2335adfc5217SJeff Kirsher 
2336adfc5217SJeff Kirsher 	if (reset_phy)
2337adfc5217SJeff Kirsher 		bnx2_reset_phy(bp);
2338adfc5217SJeff Kirsher 
2339adfc5217SJeff Kirsher 	if (bp->phy_flags & BNX2_PHY_FLAG_CRC_FIX) {
2340adfc5217SJeff Kirsher 		bnx2_write_phy(bp, 0x18, 0x0c00);
2341adfc5217SJeff Kirsher 		bnx2_write_phy(bp, 0x17, 0x000a);
2342adfc5217SJeff Kirsher 		bnx2_write_phy(bp, 0x15, 0x310b);
2343adfc5217SJeff Kirsher 		bnx2_write_phy(bp, 0x17, 0x201f);
2344adfc5217SJeff Kirsher 		bnx2_write_phy(bp, 0x15, 0x9506);
2345adfc5217SJeff Kirsher 		bnx2_write_phy(bp, 0x17, 0x401f);
2346adfc5217SJeff Kirsher 		bnx2_write_phy(bp, 0x15, 0x14e2);
2347adfc5217SJeff Kirsher 		bnx2_write_phy(bp, 0x18, 0x0400);
2348adfc5217SJeff Kirsher 	}
2349adfc5217SJeff Kirsher 
2350adfc5217SJeff Kirsher 	if (bp->phy_flags & BNX2_PHY_FLAG_DIS_EARLY_DAC) {
2351adfc5217SJeff Kirsher 		bnx2_write_phy(bp, MII_BNX2_DSP_ADDRESS,
2352adfc5217SJeff Kirsher 			       MII_BNX2_DSP_EXPAND_REG | 0x8);
2353adfc5217SJeff Kirsher 		bnx2_read_phy(bp, MII_BNX2_DSP_RW_PORT, &val);
2354adfc5217SJeff Kirsher 		val &= ~(1 << 8);
2355adfc5217SJeff Kirsher 		bnx2_write_phy(bp, MII_BNX2_DSP_RW_PORT, val);
2356adfc5217SJeff Kirsher 	}
2357adfc5217SJeff Kirsher 
2358e1c6dccaSJarod Wilson 	if (bp->dev->mtu > ETH_DATA_LEN) {
2359adfc5217SJeff Kirsher 		/* Set extended packet length bit */
2360adfc5217SJeff Kirsher 		bnx2_write_phy(bp, 0x18, 0x7);
2361adfc5217SJeff Kirsher 		bnx2_read_phy(bp, 0x18, &val);
2362adfc5217SJeff Kirsher 		bnx2_write_phy(bp, 0x18, val | 0x4000);
2363adfc5217SJeff Kirsher 
2364adfc5217SJeff Kirsher 		bnx2_read_phy(bp, 0x10, &val);
2365adfc5217SJeff Kirsher 		bnx2_write_phy(bp, 0x10, val | 0x1);
2366adfc5217SJeff Kirsher 	}
2367adfc5217SJeff Kirsher 	else {
2368adfc5217SJeff Kirsher 		bnx2_write_phy(bp, 0x18, 0x7);
2369adfc5217SJeff Kirsher 		bnx2_read_phy(bp, 0x18, &val);
2370adfc5217SJeff Kirsher 		bnx2_write_phy(bp, 0x18, val & ~0x4007);
2371adfc5217SJeff Kirsher 
2372adfc5217SJeff Kirsher 		bnx2_read_phy(bp, 0x10, &val);
2373adfc5217SJeff Kirsher 		bnx2_write_phy(bp, 0x10, val & ~0x1);
2374adfc5217SJeff Kirsher 	}
2375adfc5217SJeff Kirsher 
2376adfc5217SJeff Kirsher 	/* ethernet@wirespeed */
237741033b65SMichael Chan 	bnx2_write_phy(bp, MII_BNX2_AUX_CTL, AUX_CTL_MISC_CTL);
237841033b65SMichael Chan 	bnx2_read_phy(bp, MII_BNX2_AUX_CTL, &val);
237941033b65SMichael Chan 	val |=  AUX_CTL_MISC_CTL_WR | AUX_CTL_MISC_CTL_WIRESPEED;
238041033b65SMichael Chan 
238141033b65SMichael Chan 	/* auto-mdix */
238241033b65SMichael Chan 	if (BNX2_CHIP(bp) == BNX2_CHIP_5709)
238341033b65SMichael Chan 		val |=  AUX_CTL_MISC_CTL_AUTOMDIX;
238441033b65SMichael Chan 
238541033b65SMichael Chan 	bnx2_write_phy(bp, MII_BNX2_AUX_CTL, val);
2386adfc5217SJeff Kirsher 	return 0;
2387adfc5217SJeff Kirsher }
2388adfc5217SJeff Kirsher 
2389adfc5217SJeff Kirsher 
2390adfc5217SJeff Kirsher static int
2391adfc5217SJeff Kirsher bnx2_init_phy(struct bnx2 *bp, int reset_phy)
2392adfc5217SJeff Kirsher __releases(&bp->phy_lock)
2393adfc5217SJeff Kirsher __acquires(&bp->phy_lock)
2394adfc5217SJeff Kirsher {
2395adfc5217SJeff Kirsher 	u32 val;
2396adfc5217SJeff Kirsher 	int rc = 0;
2397adfc5217SJeff Kirsher 
2398adfc5217SJeff Kirsher 	bp->phy_flags &= ~BNX2_PHY_FLAG_INT_MODE_MASK;
2399adfc5217SJeff Kirsher 	bp->phy_flags |= BNX2_PHY_FLAG_INT_MODE_LINK_READY;
2400adfc5217SJeff Kirsher 
2401adfc5217SJeff Kirsher 	bp->mii_bmcr = MII_BMCR;
2402adfc5217SJeff Kirsher 	bp->mii_bmsr = MII_BMSR;
2403adfc5217SJeff Kirsher 	bp->mii_bmsr1 = MII_BMSR;
2404adfc5217SJeff Kirsher 	bp->mii_adv = MII_ADVERTISE;
2405adfc5217SJeff Kirsher 	bp->mii_lpa = MII_LPA;
2406adfc5217SJeff Kirsher 
2407e503e066SMichael Chan 	BNX2_WR(bp, BNX2_EMAC_ATTENTION_ENA, BNX2_EMAC_ATTENTION_ENA_LINK);
2408adfc5217SJeff Kirsher 
2409adfc5217SJeff Kirsher 	if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
2410adfc5217SJeff Kirsher 		goto setup_phy;
2411adfc5217SJeff Kirsher 
2412adfc5217SJeff Kirsher 	bnx2_read_phy(bp, MII_PHYSID1, &val);
2413adfc5217SJeff Kirsher 	bp->phy_id = val << 16;
2414adfc5217SJeff Kirsher 	bnx2_read_phy(bp, MII_PHYSID2, &val);
2415adfc5217SJeff Kirsher 	bp->phy_id |= val & 0xffff;
2416adfc5217SJeff Kirsher 
2417adfc5217SJeff Kirsher 	if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
24184ce45e02SMichael Chan 		if (BNX2_CHIP(bp) == BNX2_CHIP_5706)
2419adfc5217SJeff Kirsher 			rc = bnx2_init_5706s_phy(bp, reset_phy);
24204ce45e02SMichael Chan 		else if (BNX2_CHIP(bp) == BNX2_CHIP_5708)
2421adfc5217SJeff Kirsher 			rc = bnx2_init_5708s_phy(bp, reset_phy);
24224ce45e02SMichael Chan 		else if (BNX2_CHIP(bp) == BNX2_CHIP_5709)
2423adfc5217SJeff Kirsher 			rc = bnx2_init_5709s_phy(bp, reset_phy);
2424adfc5217SJeff Kirsher 	}
2425adfc5217SJeff Kirsher 	else {
2426adfc5217SJeff Kirsher 		rc = bnx2_init_copper_phy(bp, reset_phy);
2427adfc5217SJeff Kirsher 	}
2428adfc5217SJeff Kirsher 
2429adfc5217SJeff Kirsher setup_phy:
2430adfc5217SJeff Kirsher 	if (!rc)
2431adfc5217SJeff Kirsher 		rc = bnx2_setup_phy(bp, bp->phy_port);
2432adfc5217SJeff Kirsher 
2433adfc5217SJeff Kirsher 	return rc;
2434adfc5217SJeff Kirsher }
2435adfc5217SJeff Kirsher 
2436adfc5217SJeff Kirsher static int
2437adfc5217SJeff Kirsher bnx2_set_mac_loopback(struct bnx2 *bp)
2438adfc5217SJeff Kirsher {
2439adfc5217SJeff Kirsher 	u32 mac_mode;
2440adfc5217SJeff Kirsher 
2441e503e066SMichael Chan 	mac_mode = BNX2_RD(bp, BNX2_EMAC_MODE);
2442adfc5217SJeff Kirsher 	mac_mode &= ~BNX2_EMAC_MODE_PORT;
2443adfc5217SJeff Kirsher 	mac_mode |= BNX2_EMAC_MODE_MAC_LOOP | BNX2_EMAC_MODE_FORCE_LINK;
2444e503e066SMichael Chan 	BNX2_WR(bp, BNX2_EMAC_MODE, mac_mode);
2445adfc5217SJeff Kirsher 	bp->link_up = 1;
2446adfc5217SJeff Kirsher 	return 0;
2447adfc5217SJeff Kirsher }
2448adfc5217SJeff Kirsher 
2449adfc5217SJeff Kirsher static int bnx2_test_link(struct bnx2 *);
2450adfc5217SJeff Kirsher 
2451adfc5217SJeff Kirsher static int
2452adfc5217SJeff Kirsher bnx2_set_phy_loopback(struct bnx2 *bp)
2453adfc5217SJeff Kirsher {
2454adfc5217SJeff Kirsher 	u32 mac_mode;
2455adfc5217SJeff Kirsher 	int rc, i;
2456adfc5217SJeff Kirsher 
2457adfc5217SJeff Kirsher 	spin_lock_bh(&bp->phy_lock);
2458adfc5217SJeff Kirsher 	rc = bnx2_write_phy(bp, bp->mii_bmcr, BMCR_LOOPBACK | BMCR_FULLDPLX |
2459adfc5217SJeff Kirsher 			    BMCR_SPEED1000);
2460adfc5217SJeff Kirsher 	spin_unlock_bh(&bp->phy_lock);
2461adfc5217SJeff Kirsher 	if (rc)
2462adfc5217SJeff Kirsher 		return rc;
2463adfc5217SJeff Kirsher 
2464adfc5217SJeff Kirsher 	for (i = 0; i < 10; i++) {
2465adfc5217SJeff Kirsher 		if (bnx2_test_link(bp) == 0)
2466adfc5217SJeff Kirsher 			break;
2467adfc5217SJeff Kirsher 		msleep(100);
2468adfc5217SJeff Kirsher 	}
2469adfc5217SJeff Kirsher 
2470e503e066SMichael Chan 	mac_mode = BNX2_RD(bp, BNX2_EMAC_MODE);
2471adfc5217SJeff Kirsher 	mac_mode &= ~(BNX2_EMAC_MODE_PORT | BNX2_EMAC_MODE_HALF_DUPLEX |
2472adfc5217SJeff Kirsher 		      BNX2_EMAC_MODE_MAC_LOOP | BNX2_EMAC_MODE_FORCE_LINK |
2473adfc5217SJeff Kirsher 		      BNX2_EMAC_MODE_25G_MODE);
2474adfc5217SJeff Kirsher 
2475adfc5217SJeff Kirsher 	mac_mode |= BNX2_EMAC_MODE_PORT_GMII;
2476e503e066SMichael Chan 	BNX2_WR(bp, BNX2_EMAC_MODE, mac_mode);
2477adfc5217SJeff Kirsher 	bp->link_up = 1;
2478adfc5217SJeff Kirsher 	return 0;
2479adfc5217SJeff Kirsher }
2480adfc5217SJeff Kirsher 
2481adfc5217SJeff Kirsher static void
2482adfc5217SJeff Kirsher bnx2_dump_mcp_state(struct bnx2 *bp)
2483adfc5217SJeff Kirsher {
2484adfc5217SJeff Kirsher 	struct net_device *dev = bp->dev;
2485adfc5217SJeff Kirsher 	u32 mcp_p0, mcp_p1;
2486adfc5217SJeff Kirsher 
2487adfc5217SJeff Kirsher 	netdev_err(dev, "<--- start MCP states dump --->\n");
24884ce45e02SMichael Chan 	if (BNX2_CHIP(bp) == BNX2_CHIP_5709) {
2489adfc5217SJeff Kirsher 		mcp_p0 = BNX2_MCP_STATE_P0;
2490adfc5217SJeff Kirsher 		mcp_p1 = BNX2_MCP_STATE_P1;
2491adfc5217SJeff Kirsher 	} else {
2492adfc5217SJeff Kirsher 		mcp_p0 = BNX2_MCP_STATE_P0_5708;
2493adfc5217SJeff Kirsher 		mcp_p1 = BNX2_MCP_STATE_P1_5708;
2494adfc5217SJeff Kirsher 	}
2495adfc5217SJeff Kirsher 	netdev_err(dev, "DEBUG: MCP_STATE_P0[%08x] MCP_STATE_P1[%08x]\n",
2496adfc5217SJeff Kirsher 		   bnx2_reg_rd_ind(bp, mcp_p0), bnx2_reg_rd_ind(bp, mcp_p1));
2497adfc5217SJeff Kirsher 	netdev_err(dev, "DEBUG: MCP mode[%08x] state[%08x] evt_mask[%08x]\n",
2498adfc5217SJeff Kirsher 		   bnx2_reg_rd_ind(bp, BNX2_MCP_CPU_MODE),
2499adfc5217SJeff Kirsher 		   bnx2_reg_rd_ind(bp, BNX2_MCP_CPU_STATE),
2500adfc5217SJeff Kirsher 		   bnx2_reg_rd_ind(bp, BNX2_MCP_CPU_EVENT_MASK));
2501adfc5217SJeff Kirsher 	netdev_err(dev, "DEBUG: pc[%08x] pc[%08x] instr[%08x]\n",
2502adfc5217SJeff Kirsher 		   bnx2_reg_rd_ind(bp, BNX2_MCP_CPU_PROGRAM_COUNTER),
2503adfc5217SJeff Kirsher 		   bnx2_reg_rd_ind(bp, BNX2_MCP_CPU_PROGRAM_COUNTER),
2504adfc5217SJeff Kirsher 		   bnx2_reg_rd_ind(bp, BNX2_MCP_CPU_INSTRUCTION));
2505adfc5217SJeff Kirsher 	netdev_err(dev, "DEBUG: shmem states:\n");
2506adfc5217SJeff Kirsher 	netdev_err(dev, "DEBUG: drv_mb[%08x] fw_mb[%08x] link_status[%08x]",
2507adfc5217SJeff Kirsher 		   bnx2_shmem_rd(bp, BNX2_DRV_MB),
2508adfc5217SJeff Kirsher 		   bnx2_shmem_rd(bp, BNX2_FW_MB),
2509adfc5217SJeff Kirsher 		   bnx2_shmem_rd(bp, BNX2_LINK_STATUS));
2510adfc5217SJeff Kirsher 	pr_cont(" drv_pulse_mb[%08x]\n", bnx2_shmem_rd(bp, BNX2_DRV_PULSE_MB));
2511adfc5217SJeff Kirsher 	netdev_err(dev, "DEBUG: dev_info_signature[%08x] reset_type[%08x]",
2512adfc5217SJeff Kirsher 		   bnx2_shmem_rd(bp, BNX2_DEV_INFO_SIGNATURE),
2513adfc5217SJeff Kirsher 		   bnx2_shmem_rd(bp, BNX2_BC_STATE_RESET_TYPE));
2514adfc5217SJeff Kirsher 	pr_cont(" condition[%08x]\n",
2515adfc5217SJeff Kirsher 		bnx2_shmem_rd(bp, BNX2_BC_STATE_CONDITION));
251613e63517SMichael Chan 	DP_SHMEM_LINE(bp, BNX2_BC_RESET_TYPE);
2517adfc5217SJeff Kirsher 	DP_SHMEM_LINE(bp, 0x3cc);
2518adfc5217SJeff Kirsher 	DP_SHMEM_LINE(bp, 0x3dc);
2519adfc5217SJeff Kirsher 	DP_SHMEM_LINE(bp, 0x3ec);
2520adfc5217SJeff Kirsher 	netdev_err(dev, "DEBUG: 0x3fc[%08x]\n", bnx2_shmem_rd(bp, 0x3fc));
2521adfc5217SJeff Kirsher 	netdev_err(dev, "<--- end MCP states dump --->\n");
2522adfc5217SJeff Kirsher }
2523adfc5217SJeff Kirsher 
2524adfc5217SJeff Kirsher static int
2525adfc5217SJeff Kirsher bnx2_fw_sync(struct bnx2 *bp, u32 msg_data, int ack, int silent)
2526adfc5217SJeff Kirsher {
2527adfc5217SJeff Kirsher 	int i;
2528adfc5217SJeff Kirsher 	u32 val;
2529adfc5217SJeff Kirsher 
2530adfc5217SJeff Kirsher 	bp->fw_wr_seq++;
2531adfc5217SJeff Kirsher 	msg_data |= bp->fw_wr_seq;
2532a8d9bc2eSMichael Chan 	bp->fw_last_msg = msg_data;
2533adfc5217SJeff Kirsher 
2534adfc5217SJeff Kirsher 	bnx2_shmem_wr(bp, BNX2_DRV_MB, msg_data);
2535adfc5217SJeff Kirsher 
2536adfc5217SJeff Kirsher 	if (!ack)
2537adfc5217SJeff Kirsher 		return 0;
2538adfc5217SJeff Kirsher 
2539adfc5217SJeff Kirsher 	/* wait for an acknowledgement. */
2540adfc5217SJeff Kirsher 	for (i = 0; i < (BNX2_FW_ACK_TIME_OUT_MS / 10); i++) {
2541adfc5217SJeff Kirsher 		msleep(10);
2542adfc5217SJeff Kirsher 
2543adfc5217SJeff Kirsher 		val = bnx2_shmem_rd(bp, BNX2_FW_MB);
2544adfc5217SJeff Kirsher 
2545adfc5217SJeff Kirsher 		if ((val & BNX2_FW_MSG_ACK) == (msg_data & BNX2_DRV_MSG_SEQ))
2546adfc5217SJeff Kirsher 			break;
2547adfc5217SJeff Kirsher 	}
2548adfc5217SJeff Kirsher 	if ((msg_data & BNX2_DRV_MSG_DATA) == BNX2_DRV_MSG_DATA_WAIT0)
2549adfc5217SJeff Kirsher 		return 0;
2550adfc5217SJeff Kirsher 
2551adfc5217SJeff Kirsher 	/* If we timed out, inform the firmware that this is the case. */
2552adfc5217SJeff Kirsher 	if ((val & BNX2_FW_MSG_ACK) != (msg_data & BNX2_DRV_MSG_SEQ)) {
2553adfc5217SJeff Kirsher 		msg_data &= ~BNX2_DRV_MSG_CODE;
2554adfc5217SJeff Kirsher 		msg_data |= BNX2_DRV_MSG_CODE_FW_TIMEOUT;
2555adfc5217SJeff Kirsher 
2556adfc5217SJeff Kirsher 		bnx2_shmem_wr(bp, BNX2_DRV_MB, msg_data);
2557adfc5217SJeff Kirsher 		if (!silent) {
2558adfc5217SJeff Kirsher 			pr_err("fw sync timeout, reset code = %x\n", msg_data);
2559adfc5217SJeff Kirsher 			bnx2_dump_mcp_state(bp);
2560adfc5217SJeff Kirsher 		}
2561adfc5217SJeff Kirsher 
2562adfc5217SJeff Kirsher 		return -EBUSY;
2563adfc5217SJeff Kirsher 	}
2564adfc5217SJeff Kirsher 
2565adfc5217SJeff Kirsher 	if ((val & BNX2_FW_MSG_STATUS_MASK) != BNX2_FW_MSG_STATUS_OK)
2566adfc5217SJeff Kirsher 		return -EIO;
2567adfc5217SJeff Kirsher 
2568adfc5217SJeff Kirsher 	return 0;
2569adfc5217SJeff Kirsher }
2570adfc5217SJeff Kirsher 
2571adfc5217SJeff Kirsher static int
2572adfc5217SJeff Kirsher bnx2_init_5709_context(struct bnx2 *bp)
2573adfc5217SJeff Kirsher {
2574adfc5217SJeff Kirsher 	int i, ret = 0;
2575adfc5217SJeff Kirsher 	u32 val;
2576adfc5217SJeff Kirsher 
2577adfc5217SJeff Kirsher 	val = BNX2_CTX_COMMAND_ENABLED | BNX2_CTX_COMMAND_MEM_INIT | (1 << 12);
25782bc4078eSMichael Chan 	val |= (BNX2_PAGE_BITS - 8) << 16;
2579e503e066SMichael Chan 	BNX2_WR(bp, BNX2_CTX_COMMAND, val);
2580adfc5217SJeff Kirsher 	for (i = 0; i < 10; i++) {
2581e503e066SMichael Chan 		val = BNX2_RD(bp, BNX2_CTX_COMMAND);
2582adfc5217SJeff Kirsher 		if (!(val & BNX2_CTX_COMMAND_MEM_INIT))
2583adfc5217SJeff Kirsher 			break;
2584adfc5217SJeff Kirsher 		udelay(2);
2585adfc5217SJeff Kirsher 	}
2586adfc5217SJeff Kirsher 	if (val & BNX2_CTX_COMMAND_MEM_INIT)
2587adfc5217SJeff Kirsher 		return -EBUSY;
2588adfc5217SJeff Kirsher 
2589adfc5217SJeff Kirsher 	for (i = 0; i < bp->ctx_pages; i++) {
2590adfc5217SJeff Kirsher 		int j;
2591adfc5217SJeff Kirsher 
2592adfc5217SJeff Kirsher 		if (bp->ctx_blk[i])
25932bc4078eSMichael Chan 			memset(bp->ctx_blk[i], 0, BNX2_PAGE_SIZE);
2594adfc5217SJeff Kirsher 		else
2595adfc5217SJeff Kirsher 			return -ENOMEM;
2596adfc5217SJeff Kirsher 
2597e503e066SMichael Chan 		BNX2_WR(bp, BNX2_CTX_HOST_PAGE_TBL_DATA0,
2598adfc5217SJeff Kirsher 			(bp->ctx_blk_mapping[i] & 0xffffffff) |
2599adfc5217SJeff Kirsher 			BNX2_CTX_HOST_PAGE_TBL_DATA0_VALID);
2600e503e066SMichael Chan 		BNX2_WR(bp, BNX2_CTX_HOST_PAGE_TBL_DATA1,
2601adfc5217SJeff Kirsher 			(u64) bp->ctx_blk_mapping[i] >> 32);
2602e503e066SMichael Chan 		BNX2_WR(bp, BNX2_CTX_HOST_PAGE_TBL_CTRL, i |
2603adfc5217SJeff Kirsher 			BNX2_CTX_HOST_PAGE_TBL_CTRL_WRITE_REQ);
2604adfc5217SJeff Kirsher 		for (j = 0; j < 10; j++) {
2605adfc5217SJeff Kirsher 
2606e503e066SMichael Chan 			val = BNX2_RD(bp, BNX2_CTX_HOST_PAGE_TBL_CTRL);
2607adfc5217SJeff Kirsher 			if (!(val & BNX2_CTX_HOST_PAGE_TBL_CTRL_WRITE_REQ))
2608adfc5217SJeff Kirsher 				break;
2609adfc5217SJeff Kirsher 			udelay(5);
2610adfc5217SJeff Kirsher 		}
2611adfc5217SJeff Kirsher 		if (val & BNX2_CTX_HOST_PAGE_TBL_CTRL_WRITE_REQ) {
2612adfc5217SJeff Kirsher 			ret = -EBUSY;
2613adfc5217SJeff Kirsher 			break;
2614adfc5217SJeff Kirsher 		}
2615adfc5217SJeff Kirsher 	}
2616adfc5217SJeff Kirsher 	return ret;
2617adfc5217SJeff Kirsher }
2618adfc5217SJeff Kirsher 
2619adfc5217SJeff Kirsher static void
2620adfc5217SJeff Kirsher bnx2_init_context(struct bnx2 *bp)
2621adfc5217SJeff Kirsher {
2622adfc5217SJeff Kirsher 	u32 vcid;
2623adfc5217SJeff Kirsher 
2624adfc5217SJeff Kirsher 	vcid = 96;
2625adfc5217SJeff Kirsher 	while (vcid) {
2626adfc5217SJeff Kirsher 		u32 vcid_addr, pcid_addr, offset;
2627adfc5217SJeff Kirsher 		int i;
2628adfc5217SJeff Kirsher 
2629adfc5217SJeff Kirsher 		vcid--;
2630adfc5217SJeff Kirsher 
26314ce45e02SMichael Chan 		if (BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5706_A0) {
2632adfc5217SJeff Kirsher 			u32 new_vcid;
2633adfc5217SJeff Kirsher 
2634adfc5217SJeff Kirsher 			vcid_addr = GET_PCID_ADDR(vcid);
2635adfc5217SJeff Kirsher 			if (vcid & 0x8) {
2636adfc5217SJeff Kirsher 				new_vcid = 0x60 + (vcid & 0xf0) + (vcid & 0x7);
2637adfc5217SJeff Kirsher 			}
2638adfc5217SJeff Kirsher 			else {
2639adfc5217SJeff Kirsher 				new_vcid = vcid;
2640adfc5217SJeff Kirsher 			}
2641adfc5217SJeff Kirsher 			pcid_addr = GET_PCID_ADDR(new_vcid);
2642adfc5217SJeff Kirsher 		}
2643adfc5217SJeff Kirsher 		else {
2644adfc5217SJeff Kirsher 	    		vcid_addr = GET_CID_ADDR(vcid);
2645adfc5217SJeff Kirsher 			pcid_addr = vcid_addr;
2646adfc5217SJeff Kirsher 		}
2647adfc5217SJeff Kirsher 
2648adfc5217SJeff Kirsher 		for (i = 0; i < (CTX_SIZE / PHY_CTX_SIZE); i++) {
2649adfc5217SJeff Kirsher 			vcid_addr += (i << PHY_CTX_SHIFT);
2650adfc5217SJeff Kirsher 			pcid_addr += (i << PHY_CTX_SHIFT);
2651adfc5217SJeff Kirsher 
2652e503e066SMichael Chan 			BNX2_WR(bp, BNX2_CTX_VIRT_ADDR, vcid_addr);
2653e503e066SMichael Chan 			BNX2_WR(bp, BNX2_CTX_PAGE_TBL, pcid_addr);
2654adfc5217SJeff Kirsher 
2655adfc5217SJeff Kirsher 			/* Zero out the context. */
2656adfc5217SJeff Kirsher 			for (offset = 0; offset < PHY_CTX_SIZE; offset += 4)
2657adfc5217SJeff Kirsher 				bnx2_ctx_wr(bp, vcid_addr, offset, 0);
2658adfc5217SJeff Kirsher 		}
2659adfc5217SJeff Kirsher 	}
2660adfc5217SJeff Kirsher }
2661adfc5217SJeff Kirsher 
2662adfc5217SJeff Kirsher static int
2663adfc5217SJeff Kirsher bnx2_alloc_bad_rbuf(struct bnx2 *bp)
2664adfc5217SJeff Kirsher {
2665adfc5217SJeff Kirsher 	u16 *good_mbuf;
2666adfc5217SJeff Kirsher 	u32 good_mbuf_cnt;
2667adfc5217SJeff Kirsher 	u32 val;
2668adfc5217SJeff Kirsher 
26696da2ec56SKees Cook 	good_mbuf = kmalloc_array(512, sizeof(u16), GFP_KERNEL);
2670b8aac410SVarsha Rao 	if (!good_mbuf)
2671adfc5217SJeff Kirsher 		return -ENOMEM;
2672adfc5217SJeff Kirsher 
2673e503e066SMichael Chan 	BNX2_WR(bp, BNX2_MISC_ENABLE_SET_BITS,
2674adfc5217SJeff Kirsher 		BNX2_MISC_ENABLE_SET_BITS_RX_MBUF_ENABLE);
2675adfc5217SJeff Kirsher 
2676adfc5217SJeff Kirsher 	good_mbuf_cnt = 0;
2677adfc5217SJeff Kirsher 
2678adfc5217SJeff Kirsher 	/* Allocate a bunch of mbufs and save the good ones in an array. */
2679adfc5217SJeff Kirsher 	val = bnx2_reg_rd_ind(bp, BNX2_RBUF_STATUS1);
2680adfc5217SJeff Kirsher 	while (val & BNX2_RBUF_STATUS1_FREE_COUNT) {
2681adfc5217SJeff Kirsher 		bnx2_reg_wr_ind(bp, BNX2_RBUF_COMMAND,
2682adfc5217SJeff Kirsher 				BNX2_RBUF_COMMAND_ALLOC_REQ);
2683adfc5217SJeff Kirsher 
2684adfc5217SJeff Kirsher 		val = bnx2_reg_rd_ind(bp, BNX2_RBUF_FW_BUF_ALLOC);
2685adfc5217SJeff Kirsher 
2686adfc5217SJeff Kirsher 		val &= BNX2_RBUF_FW_BUF_ALLOC_VALUE;
2687adfc5217SJeff Kirsher 
2688adfc5217SJeff Kirsher 		/* The addresses with Bit 9 set are bad memory blocks. */
2689adfc5217SJeff Kirsher 		if (!(val & (1 << 9))) {
2690adfc5217SJeff Kirsher 			good_mbuf[good_mbuf_cnt] = (u16) val;
2691adfc5217SJeff Kirsher 			good_mbuf_cnt++;
2692adfc5217SJeff Kirsher 		}
2693adfc5217SJeff Kirsher 
2694adfc5217SJeff Kirsher 		val = bnx2_reg_rd_ind(bp, BNX2_RBUF_STATUS1);
2695adfc5217SJeff Kirsher 	}
2696adfc5217SJeff Kirsher 
2697adfc5217SJeff Kirsher 	/* Free the good ones back to the mbuf pool thus discarding
2698adfc5217SJeff Kirsher 	 * all the bad ones. */
2699adfc5217SJeff Kirsher 	while (good_mbuf_cnt) {
2700adfc5217SJeff Kirsher 		good_mbuf_cnt--;
2701adfc5217SJeff Kirsher 
2702adfc5217SJeff Kirsher 		val = good_mbuf[good_mbuf_cnt];
2703adfc5217SJeff Kirsher 		val = (val << 9) | val | 1;
2704adfc5217SJeff Kirsher 
2705adfc5217SJeff Kirsher 		bnx2_reg_wr_ind(bp, BNX2_RBUF_FW_BUF_FREE, val);
2706adfc5217SJeff Kirsher 	}
2707adfc5217SJeff Kirsher 	kfree(good_mbuf);
2708adfc5217SJeff Kirsher 	return 0;
2709adfc5217SJeff Kirsher }
2710adfc5217SJeff Kirsher 
2711adfc5217SJeff Kirsher static void
2712adfc5217SJeff Kirsher bnx2_set_mac_addr(struct bnx2 *bp, u8 *mac_addr, u32 pos)
2713adfc5217SJeff Kirsher {
2714adfc5217SJeff Kirsher 	u32 val;
2715adfc5217SJeff Kirsher 
2716adfc5217SJeff Kirsher 	val = (mac_addr[0] << 8) | mac_addr[1];
2717adfc5217SJeff Kirsher 
2718e503e066SMichael Chan 	BNX2_WR(bp, BNX2_EMAC_MAC_MATCH0 + (pos * 8), val);
2719adfc5217SJeff Kirsher 
2720adfc5217SJeff Kirsher 	val = (mac_addr[2] << 24) | (mac_addr[3] << 16) |
2721adfc5217SJeff Kirsher 		(mac_addr[4] << 8) | mac_addr[5];
2722adfc5217SJeff Kirsher 
2723e503e066SMichael Chan 	BNX2_WR(bp, BNX2_EMAC_MAC_MATCH1 + (pos * 8), val);
2724adfc5217SJeff Kirsher }
2725adfc5217SJeff Kirsher 
2726adfc5217SJeff Kirsher static inline int
2727adfc5217SJeff Kirsher bnx2_alloc_rx_page(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr, u16 index, gfp_t gfp)
2728adfc5217SJeff Kirsher {
2729adfc5217SJeff Kirsher 	dma_addr_t mapping;
27302bc4078eSMichael Chan 	struct bnx2_sw_pg *rx_pg = &rxr->rx_pg_ring[index];
27312bc4078eSMichael Chan 	struct bnx2_rx_bd *rxbd =
27322bc4078eSMichael Chan 		&rxr->rx_pg_desc_ring[BNX2_RX_RING(index)][BNX2_RX_IDX(index)];
2733adfc5217SJeff Kirsher 	struct page *page = alloc_page(gfp);
2734adfc5217SJeff Kirsher 
2735adfc5217SJeff Kirsher 	if (!page)
2736adfc5217SJeff Kirsher 		return -ENOMEM;
2737adfc5217SJeff Kirsher 	mapping = dma_map_page(&bp->pdev->dev, page, 0, PAGE_SIZE,
2738adfc5217SJeff Kirsher 			       PCI_DMA_FROMDEVICE);
2739adfc5217SJeff Kirsher 	if (dma_mapping_error(&bp->pdev->dev, mapping)) {
2740adfc5217SJeff Kirsher 		__free_page(page);
2741adfc5217SJeff Kirsher 		return -EIO;
2742adfc5217SJeff Kirsher 	}
2743adfc5217SJeff Kirsher 
2744adfc5217SJeff Kirsher 	rx_pg->page = page;
2745adfc5217SJeff Kirsher 	dma_unmap_addr_set(rx_pg, mapping, mapping);
2746adfc5217SJeff Kirsher 	rxbd->rx_bd_haddr_hi = (u64) mapping >> 32;
2747adfc5217SJeff Kirsher 	rxbd->rx_bd_haddr_lo = (u64) mapping & 0xffffffff;
2748adfc5217SJeff Kirsher 	return 0;
2749adfc5217SJeff Kirsher }
2750adfc5217SJeff Kirsher 
2751adfc5217SJeff Kirsher static void
2752adfc5217SJeff Kirsher bnx2_free_rx_page(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr, u16 index)
2753adfc5217SJeff Kirsher {
27542bc4078eSMichael Chan 	struct bnx2_sw_pg *rx_pg = &rxr->rx_pg_ring[index];
2755adfc5217SJeff Kirsher 	struct page *page = rx_pg->page;
2756adfc5217SJeff Kirsher 
2757adfc5217SJeff Kirsher 	if (!page)
2758adfc5217SJeff Kirsher 		return;
2759adfc5217SJeff Kirsher 
2760adfc5217SJeff Kirsher 	dma_unmap_page(&bp->pdev->dev, dma_unmap_addr(rx_pg, mapping),
2761adfc5217SJeff Kirsher 		       PAGE_SIZE, PCI_DMA_FROMDEVICE);
2762adfc5217SJeff Kirsher 
2763adfc5217SJeff Kirsher 	__free_page(page);
2764adfc5217SJeff Kirsher 	rx_pg->page = NULL;
2765adfc5217SJeff Kirsher }
2766adfc5217SJeff Kirsher 
2767adfc5217SJeff Kirsher static inline int
2768dd2bc8e9SEric Dumazet bnx2_alloc_rx_data(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr, u16 index, gfp_t gfp)
2769adfc5217SJeff Kirsher {
2770dd2bc8e9SEric Dumazet 	u8 *data;
27712bc4078eSMichael Chan 	struct bnx2_sw_bd *rx_buf = &rxr->rx_buf_ring[index];
2772adfc5217SJeff Kirsher 	dma_addr_t mapping;
27732bc4078eSMichael Chan 	struct bnx2_rx_bd *rxbd =
27742bc4078eSMichael Chan 		&rxr->rx_desc_ring[BNX2_RX_RING(index)][BNX2_RX_IDX(index)];
2775adfc5217SJeff Kirsher 
2776dd2bc8e9SEric Dumazet 	data = kmalloc(bp->rx_buf_size, gfp);
2777dd2bc8e9SEric Dumazet 	if (!data)
2778adfc5217SJeff Kirsher 		return -ENOMEM;
2779adfc5217SJeff Kirsher 
2780dd2bc8e9SEric Dumazet 	mapping = dma_map_single(&bp->pdev->dev,
2781dd2bc8e9SEric Dumazet 				 get_l2_fhdr(data),
2782dd2bc8e9SEric Dumazet 				 bp->rx_buf_use_size,
2783adfc5217SJeff Kirsher 				 PCI_DMA_FROMDEVICE);
2784adfc5217SJeff Kirsher 	if (dma_mapping_error(&bp->pdev->dev, mapping)) {
2785dd2bc8e9SEric Dumazet 		kfree(data);
2786adfc5217SJeff Kirsher 		return -EIO;
2787adfc5217SJeff Kirsher 	}
2788adfc5217SJeff Kirsher 
2789dd2bc8e9SEric Dumazet 	rx_buf->data = data;
2790adfc5217SJeff Kirsher 	dma_unmap_addr_set(rx_buf, mapping, mapping);
2791adfc5217SJeff Kirsher 
2792adfc5217SJeff Kirsher 	rxbd->rx_bd_haddr_hi = (u64) mapping >> 32;
2793adfc5217SJeff Kirsher 	rxbd->rx_bd_haddr_lo = (u64) mapping & 0xffffffff;
2794adfc5217SJeff Kirsher 
2795adfc5217SJeff Kirsher 	rxr->rx_prod_bseq += bp->rx_buf_use_size;
2796adfc5217SJeff Kirsher 
2797adfc5217SJeff Kirsher 	return 0;
2798adfc5217SJeff Kirsher }
2799adfc5217SJeff Kirsher 
2800adfc5217SJeff Kirsher static int
2801adfc5217SJeff Kirsher bnx2_phy_event_is_set(struct bnx2 *bp, struct bnx2_napi *bnapi, u32 event)
2802adfc5217SJeff Kirsher {
2803adfc5217SJeff Kirsher 	struct status_block *sblk = bnapi->status_blk.msi;
2804adfc5217SJeff Kirsher 	u32 new_link_state, old_link_state;
2805adfc5217SJeff Kirsher 	int is_set = 1;
2806adfc5217SJeff Kirsher 
2807adfc5217SJeff Kirsher 	new_link_state = sblk->status_attn_bits & event;
2808adfc5217SJeff Kirsher 	old_link_state = sblk->status_attn_bits_ack & event;
2809adfc5217SJeff Kirsher 	if (new_link_state != old_link_state) {
2810adfc5217SJeff Kirsher 		if (new_link_state)
2811e503e066SMichael Chan 			BNX2_WR(bp, BNX2_PCICFG_STATUS_BIT_SET_CMD, event);
2812adfc5217SJeff Kirsher 		else
2813e503e066SMichael Chan 			BNX2_WR(bp, BNX2_PCICFG_STATUS_BIT_CLEAR_CMD, event);
2814adfc5217SJeff Kirsher 	} else
2815adfc5217SJeff Kirsher 		is_set = 0;
2816adfc5217SJeff Kirsher 
2817adfc5217SJeff Kirsher 	return is_set;
2818adfc5217SJeff Kirsher }
2819adfc5217SJeff Kirsher 
2820adfc5217SJeff Kirsher static void
2821adfc5217SJeff Kirsher bnx2_phy_int(struct bnx2 *bp, struct bnx2_napi *bnapi)
2822adfc5217SJeff Kirsher {
2823adfc5217SJeff Kirsher 	spin_lock(&bp->phy_lock);
2824adfc5217SJeff Kirsher 
2825adfc5217SJeff Kirsher 	if (bnx2_phy_event_is_set(bp, bnapi, STATUS_ATTN_BITS_LINK_STATE))
2826adfc5217SJeff Kirsher 		bnx2_set_link(bp);
2827adfc5217SJeff Kirsher 	if (bnx2_phy_event_is_set(bp, bnapi, STATUS_ATTN_BITS_TIMER_ABORT))
2828adfc5217SJeff Kirsher 		bnx2_set_remote_link(bp);
2829adfc5217SJeff Kirsher 
2830adfc5217SJeff Kirsher 	spin_unlock(&bp->phy_lock);
2831adfc5217SJeff Kirsher 
2832adfc5217SJeff Kirsher }
2833adfc5217SJeff Kirsher 
2834adfc5217SJeff Kirsher static inline u16
2835adfc5217SJeff Kirsher bnx2_get_hw_tx_cons(struct bnx2_napi *bnapi)
2836adfc5217SJeff Kirsher {
2837adfc5217SJeff Kirsher 	u16 cons;
2838adfc5217SJeff Kirsher 
2839b668534cSEric Dumazet 	cons = READ_ONCE(*bnapi->hw_tx_cons_ptr);
2840b668534cSEric Dumazet 
28412bc4078eSMichael Chan 	if (unlikely((cons & BNX2_MAX_TX_DESC_CNT) == BNX2_MAX_TX_DESC_CNT))
2842adfc5217SJeff Kirsher 		cons++;
2843adfc5217SJeff Kirsher 	return cons;
2844adfc5217SJeff Kirsher }
2845adfc5217SJeff Kirsher 
2846adfc5217SJeff Kirsher static int
2847adfc5217SJeff Kirsher bnx2_tx_int(struct bnx2 *bp, struct bnx2_napi *bnapi, int budget)
2848adfc5217SJeff Kirsher {
2849adfc5217SJeff Kirsher 	struct bnx2_tx_ring_info *txr = &bnapi->tx_ring;
2850adfc5217SJeff Kirsher 	u16 hw_cons, sw_cons, sw_ring_cons;
2851adfc5217SJeff Kirsher 	int tx_pkt = 0, index;
2852e9831909SEric Dumazet 	unsigned int tx_bytes = 0;
2853adfc5217SJeff Kirsher 	struct netdev_queue *txq;
2854adfc5217SJeff Kirsher 
2855adfc5217SJeff Kirsher 	index = (bnapi - bp->bnx2_napi);
2856adfc5217SJeff Kirsher 	txq = netdev_get_tx_queue(bp->dev, index);
2857adfc5217SJeff Kirsher 
2858adfc5217SJeff Kirsher 	hw_cons = bnx2_get_hw_tx_cons(bnapi);
2859adfc5217SJeff Kirsher 	sw_cons = txr->tx_cons;
2860adfc5217SJeff Kirsher 
2861adfc5217SJeff Kirsher 	while (sw_cons != hw_cons) {
28622bc4078eSMichael Chan 		struct bnx2_sw_tx_bd *tx_buf;
2863adfc5217SJeff Kirsher 		struct sk_buff *skb;
2864adfc5217SJeff Kirsher 		int i, last;
2865adfc5217SJeff Kirsher 
28662bc4078eSMichael Chan 		sw_ring_cons = BNX2_TX_RING_IDX(sw_cons);
2867adfc5217SJeff Kirsher 
2868adfc5217SJeff Kirsher 		tx_buf = &txr->tx_buf_ring[sw_ring_cons];
2869adfc5217SJeff Kirsher 		skb = tx_buf->skb;
2870adfc5217SJeff Kirsher 
2871adfc5217SJeff Kirsher 		/* prefetch skb_end_pointer() to speedup skb_shinfo(skb) */
2872adfc5217SJeff Kirsher 		prefetch(&skb->end);
2873adfc5217SJeff Kirsher 
2874adfc5217SJeff Kirsher 		/* partial BD completions possible with TSO packets */
2875adfc5217SJeff Kirsher 		if (tx_buf->is_gso) {
2876adfc5217SJeff Kirsher 			u16 last_idx, last_ring_idx;
2877adfc5217SJeff Kirsher 
2878adfc5217SJeff Kirsher 			last_idx = sw_cons + tx_buf->nr_frags + 1;
2879adfc5217SJeff Kirsher 			last_ring_idx = sw_ring_cons + tx_buf->nr_frags + 1;
28802bc4078eSMichael Chan 			if (unlikely(last_ring_idx >= BNX2_MAX_TX_DESC_CNT)) {
2881adfc5217SJeff Kirsher 				last_idx++;
2882adfc5217SJeff Kirsher 			}
2883adfc5217SJeff Kirsher 			if (((s16) ((s16) last_idx - (s16) hw_cons)) > 0) {
2884adfc5217SJeff Kirsher 				break;
2885adfc5217SJeff Kirsher 			}
2886adfc5217SJeff Kirsher 		}
2887adfc5217SJeff Kirsher 
2888adfc5217SJeff Kirsher 		dma_unmap_single(&bp->pdev->dev, dma_unmap_addr(tx_buf, mapping),
2889adfc5217SJeff Kirsher 			skb_headlen(skb), PCI_DMA_TODEVICE);
2890adfc5217SJeff Kirsher 
2891adfc5217SJeff Kirsher 		tx_buf->skb = NULL;
2892adfc5217SJeff Kirsher 		last = tx_buf->nr_frags;
2893adfc5217SJeff Kirsher 
2894adfc5217SJeff Kirsher 		for (i = 0; i < last; i++) {
28952bc4078eSMichael Chan 			struct bnx2_sw_tx_bd *tx_buf;
2896adfc5217SJeff Kirsher 
28972bc4078eSMichael Chan 			sw_cons = BNX2_NEXT_TX_BD(sw_cons);
28982bc4078eSMichael Chan 
28992bc4078eSMichael Chan 			tx_buf = &txr->tx_buf_ring[BNX2_TX_RING_IDX(sw_cons)];
2900adfc5217SJeff Kirsher 			dma_unmap_page(&bp->pdev->dev,
29012bc4078eSMichael Chan 				dma_unmap_addr(tx_buf, mapping),
29029e903e08SEric Dumazet 				skb_frag_size(&skb_shinfo(skb)->frags[i]),
2903adfc5217SJeff Kirsher 				PCI_DMA_TODEVICE);
2904adfc5217SJeff Kirsher 		}
2905adfc5217SJeff Kirsher 
29062bc4078eSMichael Chan 		sw_cons = BNX2_NEXT_TX_BD(sw_cons);
2907adfc5217SJeff Kirsher 
2908e9831909SEric Dumazet 		tx_bytes += skb->len;
2909f458b2eeSEric W. Biederman 		dev_kfree_skb_any(skb);
2910adfc5217SJeff Kirsher 		tx_pkt++;
2911adfc5217SJeff Kirsher 		if (tx_pkt == budget)
2912adfc5217SJeff Kirsher 			break;
2913adfc5217SJeff Kirsher 
2914adfc5217SJeff Kirsher 		if (hw_cons == sw_cons)
2915adfc5217SJeff Kirsher 			hw_cons = bnx2_get_hw_tx_cons(bnapi);
2916adfc5217SJeff Kirsher 	}
2917adfc5217SJeff Kirsher 
2918e9831909SEric Dumazet 	netdev_tx_completed_queue(txq, tx_pkt, tx_bytes);
2919adfc5217SJeff Kirsher 	txr->hw_tx_cons = hw_cons;
2920adfc5217SJeff Kirsher 	txr->tx_cons = sw_cons;
2921adfc5217SJeff Kirsher 
2922adfc5217SJeff Kirsher 	/* Need to make the tx_cons update visible to bnx2_start_xmit()
2923adfc5217SJeff Kirsher 	 * before checking for netif_tx_queue_stopped().  Without the
2924adfc5217SJeff Kirsher 	 * memory barrier, there is a small possibility that bnx2_start_xmit()
2925adfc5217SJeff Kirsher 	 * will miss it and cause the queue to be stopped forever.
2926adfc5217SJeff Kirsher 	 */
2927adfc5217SJeff Kirsher 	smp_mb();
2928adfc5217SJeff Kirsher 
2929adfc5217SJeff Kirsher 	if (unlikely(netif_tx_queue_stopped(txq)) &&
2930adfc5217SJeff Kirsher 		     (bnx2_tx_avail(bp, txr) > bp->tx_wake_thresh)) {
2931adfc5217SJeff Kirsher 		__netif_tx_lock(txq, smp_processor_id());
2932adfc5217SJeff Kirsher 		if ((netif_tx_queue_stopped(txq)) &&
2933adfc5217SJeff Kirsher 		    (bnx2_tx_avail(bp, txr) > bp->tx_wake_thresh))
2934adfc5217SJeff Kirsher 			netif_tx_wake_queue(txq);
2935adfc5217SJeff Kirsher 		__netif_tx_unlock(txq);
2936adfc5217SJeff Kirsher 	}
2937adfc5217SJeff Kirsher 
2938adfc5217SJeff Kirsher 	return tx_pkt;
2939adfc5217SJeff Kirsher }
2940adfc5217SJeff Kirsher 
2941adfc5217SJeff Kirsher static void
2942adfc5217SJeff Kirsher bnx2_reuse_rx_skb_pages(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr,
2943adfc5217SJeff Kirsher 			struct sk_buff *skb, int count)
2944adfc5217SJeff Kirsher {
29452bc4078eSMichael Chan 	struct bnx2_sw_pg *cons_rx_pg, *prod_rx_pg;
29462bc4078eSMichael Chan 	struct bnx2_rx_bd *cons_bd, *prod_bd;
2947adfc5217SJeff Kirsher 	int i;
2948adfc5217SJeff Kirsher 	u16 hw_prod, prod;
2949adfc5217SJeff Kirsher 	u16 cons = rxr->rx_pg_cons;
2950adfc5217SJeff Kirsher 
2951adfc5217SJeff Kirsher 	cons_rx_pg = &rxr->rx_pg_ring[cons];
2952adfc5217SJeff Kirsher 
2953adfc5217SJeff Kirsher 	/* The caller was unable to allocate a new page to replace the
2954adfc5217SJeff Kirsher 	 * last one in the frags array, so we need to recycle that page
2955adfc5217SJeff Kirsher 	 * and then free the skb.
2956adfc5217SJeff Kirsher 	 */
2957adfc5217SJeff Kirsher 	if (skb) {
2958adfc5217SJeff Kirsher 		struct page *page;
2959adfc5217SJeff Kirsher 		struct skb_shared_info *shinfo;
2960adfc5217SJeff Kirsher 
2961adfc5217SJeff Kirsher 		shinfo = skb_shinfo(skb);
2962adfc5217SJeff Kirsher 		shinfo->nr_frags--;
2963b7b6a688SIan Campbell 		page = skb_frag_page(&shinfo->frags[shinfo->nr_frags]);
2964b7b6a688SIan Campbell 		__skb_frag_set_page(&shinfo->frags[shinfo->nr_frags], NULL);
2965adfc5217SJeff Kirsher 
2966adfc5217SJeff Kirsher 		cons_rx_pg->page = page;
2967adfc5217SJeff Kirsher 		dev_kfree_skb(skb);
2968adfc5217SJeff Kirsher 	}
2969adfc5217SJeff Kirsher 
2970adfc5217SJeff Kirsher 	hw_prod = rxr->rx_pg_prod;
2971adfc5217SJeff Kirsher 
2972adfc5217SJeff Kirsher 	for (i = 0; i < count; i++) {
29732bc4078eSMichael Chan 		prod = BNX2_RX_PG_RING_IDX(hw_prod);
2974adfc5217SJeff Kirsher 
2975adfc5217SJeff Kirsher 		prod_rx_pg = &rxr->rx_pg_ring[prod];
2976adfc5217SJeff Kirsher 		cons_rx_pg = &rxr->rx_pg_ring[cons];
29772bc4078eSMichael Chan 		cons_bd = &rxr->rx_pg_desc_ring[BNX2_RX_RING(cons)]
29782bc4078eSMichael Chan 						[BNX2_RX_IDX(cons)];
29792bc4078eSMichael Chan 		prod_bd = &rxr->rx_pg_desc_ring[BNX2_RX_RING(prod)]
29802bc4078eSMichael Chan 						[BNX2_RX_IDX(prod)];
2981adfc5217SJeff Kirsher 
2982adfc5217SJeff Kirsher 		if (prod != cons) {
2983adfc5217SJeff Kirsher 			prod_rx_pg->page = cons_rx_pg->page;
2984adfc5217SJeff Kirsher 			cons_rx_pg->page = NULL;
2985adfc5217SJeff Kirsher 			dma_unmap_addr_set(prod_rx_pg, mapping,
2986adfc5217SJeff Kirsher 				dma_unmap_addr(cons_rx_pg, mapping));
2987adfc5217SJeff Kirsher 
2988adfc5217SJeff Kirsher 			prod_bd->rx_bd_haddr_hi = cons_bd->rx_bd_haddr_hi;
2989adfc5217SJeff Kirsher 			prod_bd->rx_bd_haddr_lo = cons_bd->rx_bd_haddr_lo;
2990adfc5217SJeff Kirsher 
2991adfc5217SJeff Kirsher 		}
29922bc4078eSMichael Chan 		cons = BNX2_RX_PG_RING_IDX(BNX2_NEXT_RX_BD(cons));
29932bc4078eSMichael Chan 		hw_prod = BNX2_NEXT_RX_BD(hw_prod);
2994adfc5217SJeff Kirsher 	}
2995adfc5217SJeff Kirsher 	rxr->rx_pg_prod = hw_prod;
2996adfc5217SJeff Kirsher 	rxr->rx_pg_cons = cons;
2997adfc5217SJeff Kirsher }
2998adfc5217SJeff Kirsher 
2999adfc5217SJeff Kirsher static inline void
3000dd2bc8e9SEric Dumazet bnx2_reuse_rx_data(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr,
3001dd2bc8e9SEric Dumazet 		   u8 *data, u16 cons, u16 prod)
3002adfc5217SJeff Kirsher {
30032bc4078eSMichael Chan 	struct bnx2_sw_bd *cons_rx_buf, *prod_rx_buf;
30042bc4078eSMichael Chan 	struct bnx2_rx_bd *cons_bd, *prod_bd;
3005adfc5217SJeff Kirsher 
3006adfc5217SJeff Kirsher 	cons_rx_buf = &rxr->rx_buf_ring[cons];
3007adfc5217SJeff Kirsher 	prod_rx_buf = &rxr->rx_buf_ring[prod];
3008adfc5217SJeff Kirsher 
3009adfc5217SJeff Kirsher 	dma_sync_single_for_device(&bp->pdev->dev,
3010adfc5217SJeff Kirsher 		dma_unmap_addr(cons_rx_buf, mapping),
3011adfc5217SJeff Kirsher 		BNX2_RX_OFFSET + BNX2_RX_COPY_THRESH, PCI_DMA_FROMDEVICE);
3012adfc5217SJeff Kirsher 
3013adfc5217SJeff Kirsher 	rxr->rx_prod_bseq += bp->rx_buf_use_size;
3014adfc5217SJeff Kirsher 
3015dd2bc8e9SEric Dumazet 	prod_rx_buf->data = data;
3016adfc5217SJeff Kirsher 
3017adfc5217SJeff Kirsher 	if (cons == prod)
3018adfc5217SJeff Kirsher 		return;
3019adfc5217SJeff Kirsher 
3020adfc5217SJeff Kirsher 	dma_unmap_addr_set(prod_rx_buf, mapping,
3021adfc5217SJeff Kirsher 			dma_unmap_addr(cons_rx_buf, mapping));
3022adfc5217SJeff Kirsher 
30232bc4078eSMichael Chan 	cons_bd = &rxr->rx_desc_ring[BNX2_RX_RING(cons)][BNX2_RX_IDX(cons)];
30242bc4078eSMichael Chan 	prod_bd = &rxr->rx_desc_ring[BNX2_RX_RING(prod)][BNX2_RX_IDX(prod)];
3025adfc5217SJeff Kirsher 	prod_bd->rx_bd_haddr_hi = cons_bd->rx_bd_haddr_hi;
3026adfc5217SJeff Kirsher 	prod_bd->rx_bd_haddr_lo = cons_bd->rx_bd_haddr_lo;
3027adfc5217SJeff Kirsher }
3028adfc5217SJeff Kirsher 
3029dd2bc8e9SEric Dumazet static struct sk_buff *
3030dd2bc8e9SEric Dumazet bnx2_rx_skb(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr, u8 *data,
3031adfc5217SJeff Kirsher 	    unsigned int len, unsigned int hdr_len, dma_addr_t dma_addr,
3032adfc5217SJeff Kirsher 	    u32 ring_idx)
3033adfc5217SJeff Kirsher {
3034adfc5217SJeff Kirsher 	int err;
3035adfc5217SJeff Kirsher 	u16 prod = ring_idx & 0xffff;
3036dd2bc8e9SEric Dumazet 	struct sk_buff *skb;
3037adfc5217SJeff Kirsher 
3038dd2bc8e9SEric Dumazet 	err = bnx2_alloc_rx_data(bp, rxr, prod, GFP_ATOMIC);
3039adfc5217SJeff Kirsher 	if (unlikely(err)) {
3040dd2bc8e9SEric Dumazet 		bnx2_reuse_rx_data(bp, rxr, data, (u16) (ring_idx >> 16), prod);
3041dd2bc8e9SEric Dumazet error:
3042adfc5217SJeff Kirsher 		if (hdr_len) {
3043adfc5217SJeff Kirsher 			unsigned int raw_len = len + 4;
3044adfc5217SJeff Kirsher 			int pages = PAGE_ALIGN(raw_len - hdr_len) >> PAGE_SHIFT;
3045adfc5217SJeff Kirsher 
3046adfc5217SJeff Kirsher 			bnx2_reuse_rx_skb_pages(bp, rxr, NULL, pages);
3047adfc5217SJeff Kirsher 		}
3048dd2bc8e9SEric Dumazet 		return NULL;
3049adfc5217SJeff Kirsher 	}
3050adfc5217SJeff Kirsher 
3051adfc5217SJeff Kirsher 	dma_unmap_single(&bp->pdev->dev, dma_addr, bp->rx_buf_use_size,
3052adfc5217SJeff Kirsher 			 PCI_DMA_FROMDEVICE);
3053d3836f21SEric Dumazet 	skb = build_skb(data, 0);
3054dd2bc8e9SEric Dumazet 	if (!skb) {
3055dd2bc8e9SEric Dumazet 		kfree(data);
3056dd2bc8e9SEric Dumazet 		goto error;
3057dd2bc8e9SEric Dumazet 	}
3058dd2bc8e9SEric Dumazet 	skb_reserve(skb, ((u8 *)get_l2_fhdr(data) - data) + BNX2_RX_OFFSET);
3059adfc5217SJeff Kirsher 	if (hdr_len == 0) {
3060adfc5217SJeff Kirsher 		skb_put(skb, len);
3061dd2bc8e9SEric Dumazet 		return skb;
3062adfc5217SJeff Kirsher 	} else {
3063adfc5217SJeff Kirsher 		unsigned int i, frag_len, frag_size, pages;
30642bc4078eSMichael Chan 		struct bnx2_sw_pg *rx_pg;
3065adfc5217SJeff Kirsher 		u16 pg_cons = rxr->rx_pg_cons;
3066adfc5217SJeff Kirsher 		u16 pg_prod = rxr->rx_pg_prod;
3067adfc5217SJeff Kirsher 
3068adfc5217SJeff Kirsher 		frag_size = len + 4 - hdr_len;
3069adfc5217SJeff Kirsher 		pages = PAGE_ALIGN(frag_size) >> PAGE_SHIFT;
3070adfc5217SJeff Kirsher 		skb_put(skb, hdr_len);
3071adfc5217SJeff Kirsher 
3072adfc5217SJeff Kirsher 		for (i = 0; i < pages; i++) {
3073adfc5217SJeff Kirsher 			dma_addr_t mapping_old;
3074adfc5217SJeff Kirsher 
3075adfc5217SJeff Kirsher 			frag_len = min(frag_size, (unsigned int) PAGE_SIZE);
3076adfc5217SJeff Kirsher 			if (unlikely(frag_len <= 4)) {
3077adfc5217SJeff Kirsher 				unsigned int tail = 4 - frag_len;
3078adfc5217SJeff Kirsher 
3079adfc5217SJeff Kirsher 				rxr->rx_pg_cons = pg_cons;
3080adfc5217SJeff Kirsher 				rxr->rx_pg_prod = pg_prod;
3081adfc5217SJeff Kirsher 				bnx2_reuse_rx_skb_pages(bp, rxr, NULL,
3082adfc5217SJeff Kirsher 							pages - i);
3083adfc5217SJeff Kirsher 				skb->len -= tail;
3084adfc5217SJeff Kirsher 				if (i == 0) {
3085adfc5217SJeff Kirsher 					skb->tail -= tail;
3086adfc5217SJeff Kirsher 				} else {
3087adfc5217SJeff Kirsher 					skb_frag_t *frag =
3088adfc5217SJeff Kirsher 						&skb_shinfo(skb)->frags[i - 1];
30899e903e08SEric Dumazet 					skb_frag_size_sub(frag, tail);
3090adfc5217SJeff Kirsher 					skb->data_len -= tail;
3091adfc5217SJeff Kirsher 				}
3092dd2bc8e9SEric Dumazet 				return skb;
3093adfc5217SJeff Kirsher 			}
3094adfc5217SJeff Kirsher 			rx_pg = &rxr->rx_pg_ring[pg_cons];
3095adfc5217SJeff Kirsher 
3096adfc5217SJeff Kirsher 			/* Don't unmap yet.  If we're unable to allocate a new
3097adfc5217SJeff Kirsher 			 * page, we need to recycle the page and the DMA addr.
3098adfc5217SJeff Kirsher 			 */
3099adfc5217SJeff Kirsher 			mapping_old = dma_unmap_addr(rx_pg, mapping);
3100adfc5217SJeff Kirsher 			if (i == pages - 1)
3101adfc5217SJeff Kirsher 				frag_len -= 4;
3102adfc5217SJeff Kirsher 
3103adfc5217SJeff Kirsher 			skb_fill_page_desc(skb, i, rx_pg->page, 0, frag_len);
3104adfc5217SJeff Kirsher 			rx_pg->page = NULL;
3105adfc5217SJeff Kirsher 
3106adfc5217SJeff Kirsher 			err = bnx2_alloc_rx_page(bp, rxr,
31072bc4078eSMichael Chan 						 BNX2_RX_PG_RING_IDX(pg_prod),
3108adfc5217SJeff Kirsher 						 GFP_ATOMIC);
3109adfc5217SJeff Kirsher 			if (unlikely(err)) {
3110adfc5217SJeff Kirsher 				rxr->rx_pg_cons = pg_cons;
3111adfc5217SJeff Kirsher 				rxr->rx_pg_prod = pg_prod;
3112adfc5217SJeff Kirsher 				bnx2_reuse_rx_skb_pages(bp, rxr, skb,
3113adfc5217SJeff Kirsher 							pages - i);
3114dd2bc8e9SEric Dumazet 				return NULL;
3115adfc5217SJeff Kirsher 			}
3116adfc5217SJeff Kirsher 
3117adfc5217SJeff Kirsher 			dma_unmap_page(&bp->pdev->dev, mapping_old,
3118adfc5217SJeff Kirsher 				       PAGE_SIZE, PCI_DMA_FROMDEVICE);
3119adfc5217SJeff Kirsher 
3120adfc5217SJeff Kirsher 			frag_size -= frag_len;
3121adfc5217SJeff Kirsher 			skb->data_len += frag_len;
3122a1f4e8bcSEric Dumazet 			skb->truesize += PAGE_SIZE;
3123adfc5217SJeff Kirsher 			skb->len += frag_len;
3124adfc5217SJeff Kirsher 
31252bc4078eSMichael Chan 			pg_prod = BNX2_NEXT_RX_BD(pg_prod);
31262bc4078eSMichael Chan 			pg_cons = BNX2_RX_PG_RING_IDX(BNX2_NEXT_RX_BD(pg_cons));
3127adfc5217SJeff Kirsher 		}
3128adfc5217SJeff Kirsher 		rxr->rx_pg_prod = pg_prod;
3129adfc5217SJeff Kirsher 		rxr->rx_pg_cons = pg_cons;
3130adfc5217SJeff Kirsher 	}
3131dd2bc8e9SEric Dumazet 	return skb;
3132adfc5217SJeff Kirsher }
3133adfc5217SJeff Kirsher 
3134adfc5217SJeff Kirsher static inline u16
3135adfc5217SJeff Kirsher bnx2_get_hw_rx_cons(struct bnx2_napi *bnapi)
3136adfc5217SJeff Kirsher {
3137adfc5217SJeff Kirsher 	u16 cons;
3138adfc5217SJeff Kirsher 
3139b668534cSEric Dumazet 	cons = READ_ONCE(*bnapi->hw_rx_cons_ptr);
3140b668534cSEric Dumazet 
31412bc4078eSMichael Chan 	if (unlikely((cons & BNX2_MAX_RX_DESC_CNT) == BNX2_MAX_RX_DESC_CNT))
3142adfc5217SJeff Kirsher 		cons++;
3143adfc5217SJeff Kirsher 	return cons;
3144adfc5217SJeff Kirsher }
3145adfc5217SJeff Kirsher 
3146adfc5217SJeff Kirsher static int
3147adfc5217SJeff Kirsher bnx2_rx_int(struct bnx2 *bp, struct bnx2_napi *bnapi, int budget)
3148adfc5217SJeff Kirsher {
3149adfc5217SJeff Kirsher 	struct bnx2_rx_ring_info *rxr = &bnapi->rx_ring;
3150adfc5217SJeff Kirsher 	u16 hw_cons, sw_cons, sw_ring_cons, sw_prod, sw_ring_prod;
3151adfc5217SJeff Kirsher 	struct l2_fhdr *rx_hdr;
3152adfc5217SJeff Kirsher 	int rx_pkt = 0, pg_ring_used = 0;
3153adfc5217SJeff Kirsher 
3154310c4d4eSEric W. Biederman 	if (budget <= 0)
3155310c4d4eSEric W. Biederman 		return rx_pkt;
3156310c4d4eSEric W. Biederman 
3157adfc5217SJeff Kirsher 	hw_cons = bnx2_get_hw_rx_cons(bnapi);
3158adfc5217SJeff Kirsher 	sw_cons = rxr->rx_cons;
3159adfc5217SJeff Kirsher 	sw_prod = rxr->rx_prod;
3160adfc5217SJeff Kirsher 
3161adfc5217SJeff Kirsher 	/* Memory barrier necessary as speculative reads of the rx
3162adfc5217SJeff Kirsher 	 * buffer can be ahead of the index in the status block
3163adfc5217SJeff Kirsher 	 */
3164adfc5217SJeff Kirsher 	rmb();
3165adfc5217SJeff Kirsher 	while (sw_cons != hw_cons) {
3166adfc5217SJeff Kirsher 		unsigned int len, hdr_len;
3167adfc5217SJeff Kirsher 		u32 status;
31682bc4078eSMichael Chan 		struct bnx2_sw_bd *rx_buf, *next_rx_buf;
3169adfc5217SJeff Kirsher 		struct sk_buff *skb;
3170adfc5217SJeff Kirsher 		dma_addr_t dma_addr;
3171dd2bc8e9SEric Dumazet 		u8 *data;
31722bc4078eSMichael Chan 		u16 next_ring_idx;
3173adfc5217SJeff Kirsher 
31742bc4078eSMichael Chan 		sw_ring_cons = BNX2_RX_RING_IDX(sw_cons);
31752bc4078eSMichael Chan 		sw_ring_prod = BNX2_RX_RING_IDX(sw_prod);
3176adfc5217SJeff Kirsher 
3177adfc5217SJeff Kirsher 		rx_buf = &rxr->rx_buf_ring[sw_ring_cons];
3178dd2bc8e9SEric Dumazet 		data = rx_buf->data;
3179dd2bc8e9SEric Dumazet 		rx_buf->data = NULL;
3180adfc5217SJeff Kirsher 
3181dd2bc8e9SEric Dumazet 		rx_hdr = get_l2_fhdr(data);
3182dd2bc8e9SEric Dumazet 		prefetch(rx_hdr);
3183adfc5217SJeff Kirsher 
3184adfc5217SJeff Kirsher 		dma_addr = dma_unmap_addr(rx_buf, mapping);
3185adfc5217SJeff Kirsher 
3186adfc5217SJeff Kirsher 		dma_sync_single_for_cpu(&bp->pdev->dev, dma_addr,
3187adfc5217SJeff Kirsher 			BNX2_RX_OFFSET + BNX2_RX_COPY_THRESH,
3188adfc5217SJeff Kirsher 			PCI_DMA_FROMDEVICE);
3189adfc5217SJeff Kirsher 
31902bc4078eSMichael Chan 		next_ring_idx = BNX2_RX_RING_IDX(BNX2_NEXT_RX_BD(sw_cons));
31912bc4078eSMichael Chan 		next_rx_buf = &rxr->rx_buf_ring[next_ring_idx];
3192dd2bc8e9SEric Dumazet 		prefetch(get_l2_fhdr(next_rx_buf->data));
3193dd2bc8e9SEric Dumazet 
3194adfc5217SJeff Kirsher 		len = rx_hdr->l2_fhdr_pkt_len;
3195adfc5217SJeff Kirsher 		status = rx_hdr->l2_fhdr_status;
3196adfc5217SJeff Kirsher 
3197adfc5217SJeff Kirsher 		hdr_len = 0;
3198adfc5217SJeff Kirsher 		if (status & L2_FHDR_STATUS_SPLIT) {
3199adfc5217SJeff Kirsher 			hdr_len = rx_hdr->l2_fhdr_ip_xsum;
3200adfc5217SJeff Kirsher 			pg_ring_used = 1;
3201adfc5217SJeff Kirsher 		} else if (len > bp->rx_jumbo_thresh) {
3202adfc5217SJeff Kirsher 			hdr_len = bp->rx_jumbo_thresh;
3203adfc5217SJeff Kirsher 			pg_ring_used = 1;
3204adfc5217SJeff Kirsher 		}
3205adfc5217SJeff Kirsher 
3206adfc5217SJeff Kirsher 		if (unlikely(status & (L2_FHDR_ERRORS_BAD_CRC |
3207adfc5217SJeff Kirsher 				       L2_FHDR_ERRORS_PHY_DECODE |
3208adfc5217SJeff Kirsher 				       L2_FHDR_ERRORS_ALIGNMENT |
3209adfc5217SJeff Kirsher 				       L2_FHDR_ERRORS_TOO_SHORT |
3210adfc5217SJeff Kirsher 				       L2_FHDR_ERRORS_GIANT_FRAME))) {
3211adfc5217SJeff Kirsher 
3212dd2bc8e9SEric Dumazet 			bnx2_reuse_rx_data(bp, rxr, data, sw_ring_cons,
3213adfc5217SJeff Kirsher 					  sw_ring_prod);
3214adfc5217SJeff Kirsher 			if (pg_ring_used) {
3215adfc5217SJeff Kirsher 				int pages;
3216adfc5217SJeff Kirsher 
3217adfc5217SJeff Kirsher 				pages = PAGE_ALIGN(len - hdr_len) >> PAGE_SHIFT;
3218adfc5217SJeff Kirsher 
3219adfc5217SJeff Kirsher 				bnx2_reuse_rx_skb_pages(bp, rxr, NULL, pages);
3220adfc5217SJeff Kirsher 			}
3221adfc5217SJeff Kirsher 			goto next_rx;
3222adfc5217SJeff Kirsher 		}
3223adfc5217SJeff Kirsher 
3224adfc5217SJeff Kirsher 		len -= 4;
3225adfc5217SJeff Kirsher 
3226adfc5217SJeff Kirsher 		if (len <= bp->rx_copy_thresh) {
3227dd2bc8e9SEric Dumazet 			skb = netdev_alloc_skb(bp->dev, len + 6);
3228b8aac410SVarsha Rao 			if (!skb) {
3229dd2bc8e9SEric Dumazet 				bnx2_reuse_rx_data(bp, rxr, data, sw_ring_cons,
3230adfc5217SJeff Kirsher 						  sw_ring_prod);
3231adfc5217SJeff Kirsher 				goto next_rx;
3232adfc5217SJeff Kirsher 			}
3233adfc5217SJeff Kirsher 
3234adfc5217SJeff Kirsher 			/* aligned copy */
3235dd2bc8e9SEric Dumazet 			memcpy(skb->data,
3236dd2bc8e9SEric Dumazet 			       (u8 *)rx_hdr + BNX2_RX_OFFSET - 6,
3237dd2bc8e9SEric Dumazet 			       len + 6);
3238dd2bc8e9SEric Dumazet 			skb_reserve(skb, 6);
3239dd2bc8e9SEric Dumazet 			skb_put(skb, len);
3240adfc5217SJeff Kirsher 
3241dd2bc8e9SEric Dumazet 			bnx2_reuse_rx_data(bp, rxr, data,
3242adfc5217SJeff Kirsher 				sw_ring_cons, sw_ring_prod);
3243adfc5217SJeff Kirsher 
3244dd2bc8e9SEric Dumazet 		} else {
3245dd2bc8e9SEric Dumazet 			skb = bnx2_rx_skb(bp, rxr, data, len, hdr_len, dma_addr,
3246dd2bc8e9SEric Dumazet 					  (sw_ring_cons << 16) | sw_ring_prod);
3247dd2bc8e9SEric Dumazet 			if (!skb)
3248adfc5217SJeff Kirsher 				goto next_rx;
3249dd2bc8e9SEric Dumazet 		}
3250adfc5217SJeff Kirsher 		if ((status & L2_FHDR_STATUS_L2_VLAN_TAG) &&
3251adfc5217SJeff Kirsher 		    !(bp->rx_mode & BNX2_EMAC_RX_MODE_KEEP_VLAN_TAG))
325286a9bad3SPatrick McHardy 			__vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), rx_hdr->l2_fhdr_vlan_tag);
3253adfc5217SJeff Kirsher 
3254adfc5217SJeff Kirsher 		skb->protocol = eth_type_trans(skb, bp->dev);
3255adfc5217SJeff Kirsher 
32561b0ecb28SVlad Yasevich 		if (len > (bp->dev->mtu + ETH_HLEN) &&
32571b0ecb28SVlad Yasevich 		    skb->protocol != htons(0x8100) &&
32581b0ecb28SVlad Yasevich 		    skb->protocol != htons(ETH_P_8021AD)) {
3259adfc5217SJeff Kirsher 
3260adfc5217SJeff Kirsher 			dev_kfree_skb(skb);
3261adfc5217SJeff Kirsher 			goto next_rx;
3262adfc5217SJeff Kirsher 
3263adfc5217SJeff Kirsher 		}
3264adfc5217SJeff Kirsher 
3265adfc5217SJeff Kirsher 		skb_checksum_none_assert(skb);
3266adfc5217SJeff Kirsher 		if ((bp->dev->features & NETIF_F_RXCSUM) &&
3267adfc5217SJeff Kirsher 			(status & (L2_FHDR_STATUS_TCP_SEGMENT |
3268adfc5217SJeff Kirsher 			L2_FHDR_STATUS_UDP_DATAGRAM))) {
3269adfc5217SJeff Kirsher 
3270adfc5217SJeff Kirsher 			if (likely((status & (L2_FHDR_ERRORS_TCP_XSUM |
3271adfc5217SJeff Kirsher 					      L2_FHDR_ERRORS_UDP_XSUM)) == 0))
3272adfc5217SJeff Kirsher 				skb->ip_summed = CHECKSUM_UNNECESSARY;
3273adfc5217SJeff Kirsher 		}
3274adfc5217SJeff Kirsher 		if ((bp->dev->features & NETIF_F_RXHASH) &&
3275adfc5217SJeff Kirsher 		    ((status & L2_FHDR_STATUS_USE_RXHASH) ==
3276adfc5217SJeff Kirsher 		     L2_FHDR_STATUS_USE_RXHASH))
3277cf1bfd6aSTom Herbert 			skb_set_hash(skb, rx_hdr->l2_fhdr_hash,
3278cf1bfd6aSTom Herbert 				     PKT_HASH_TYPE_L3);
3279adfc5217SJeff Kirsher 
3280adfc5217SJeff Kirsher 		skb_record_rx_queue(skb, bnapi - &bp->bnx2_napi[0]);
3281adfc5217SJeff Kirsher 		napi_gro_receive(&bnapi->napi, skb);
3282adfc5217SJeff Kirsher 		rx_pkt++;
3283adfc5217SJeff Kirsher 
3284adfc5217SJeff Kirsher next_rx:
32852bc4078eSMichael Chan 		sw_cons = BNX2_NEXT_RX_BD(sw_cons);
32862bc4078eSMichael Chan 		sw_prod = BNX2_NEXT_RX_BD(sw_prod);
3287adfc5217SJeff Kirsher 
32886dc5aa21SVarsha Rao 		if (rx_pkt == budget)
3289adfc5217SJeff Kirsher 			break;
3290adfc5217SJeff Kirsher 
3291adfc5217SJeff Kirsher 		/* Refresh hw_cons to see if there is new work */
3292adfc5217SJeff Kirsher 		if (sw_cons == hw_cons) {
3293adfc5217SJeff Kirsher 			hw_cons = bnx2_get_hw_rx_cons(bnapi);
3294adfc5217SJeff Kirsher 			rmb();
3295adfc5217SJeff Kirsher 		}
3296adfc5217SJeff Kirsher 	}
3297adfc5217SJeff Kirsher 	rxr->rx_cons = sw_cons;
3298adfc5217SJeff Kirsher 	rxr->rx_prod = sw_prod;
3299adfc5217SJeff Kirsher 
3300adfc5217SJeff Kirsher 	if (pg_ring_used)
3301e503e066SMichael Chan 		BNX2_WR16(bp, rxr->rx_pg_bidx_addr, rxr->rx_pg_prod);
3302adfc5217SJeff Kirsher 
3303e503e066SMichael Chan 	BNX2_WR16(bp, rxr->rx_bidx_addr, sw_prod);
3304adfc5217SJeff Kirsher 
3305e503e066SMichael Chan 	BNX2_WR(bp, rxr->rx_bseq_addr, rxr->rx_prod_bseq);
3306adfc5217SJeff Kirsher 
3307adfc5217SJeff Kirsher 	mmiowb();
3308adfc5217SJeff Kirsher 
3309adfc5217SJeff Kirsher 	return rx_pkt;
3310adfc5217SJeff Kirsher 
3311adfc5217SJeff Kirsher }
3312adfc5217SJeff Kirsher 
3313adfc5217SJeff Kirsher /* MSI ISR - The only difference between this and the INTx ISR
3314adfc5217SJeff Kirsher  * is that the MSI interrupt is always serviced.
3315adfc5217SJeff Kirsher  */
3316adfc5217SJeff Kirsher static irqreturn_t
3317adfc5217SJeff Kirsher bnx2_msi(int irq, void *dev_instance)
3318adfc5217SJeff Kirsher {
3319adfc5217SJeff Kirsher 	struct bnx2_napi *bnapi = dev_instance;
3320adfc5217SJeff Kirsher 	struct bnx2 *bp = bnapi->bp;
3321adfc5217SJeff Kirsher 
3322adfc5217SJeff Kirsher 	prefetch(bnapi->status_blk.msi);
3323e503e066SMichael Chan 	BNX2_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
3324adfc5217SJeff Kirsher 		BNX2_PCICFG_INT_ACK_CMD_USE_INT_HC_PARAM |
3325adfc5217SJeff Kirsher 		BNX2_PCICFG_INT_ACK_CMD_MASK_INT);
3326adfc5217SJeff Kirsher 
3327adfc5217SJeff Kirsher 	/* Return here if interrupt is disabled. */
3328adfc5217SJeff Kirsher 	if (unlikely(atomic_read(&bp->intr_sem) != 0))
3329adfc5217SJeff Kirsher 		return IRQ_HANDLED;
3330adfc5217SJeff Kirsher 
3331adfc5217SJeff Kirsher 	napi_schedule(&bnapi->napi);
3332adfc5217SJeff Kirsher 
3333adfc5217SJeff Kirsher 	return IRQ_HANDLED;
3334adfc5217SJeff Kirsher }
3335adfc5217SJeff Kirsher 
3336adfc5217SJeff Kirsher static irqreturn_t
3337adfc5217SJeff Kirsher bnx2_msi_1shot(int irq, void *dev_instance)
3338adfc5217SJeff Kirsher {
3339adfc5217SJeff Kirsher 	struct bnx2_napi *bnapi = dev_instance;
3340adfc5217SJeff Kirsher 	struct bnx2 *bp = bnapi->bp;
3341adfc5217SJeff Kirsher 
3342adfc5217SJeff Kirsher 	prefetch(bnapi->status_blk.msi);
3343adfc5217SJeff Kirsher 
3344adfc5217SJeff Kirsher 	/* Return here if interrupt is disabled. */
3345adfc5217SJeff Kirsher 	if (unlikely(atomic_read(&bp->intr_sem) != 0))
3346adfc5217SJeff Kirsher 		return IRQ_HANDLED;
3347adfc5217SJeff Kirsher 
3348adfc5217SJeff Kirsher 	napi_schedule(&bnapi->napi);
3349adfc5217SJeff Kirsher 
3350adfc5217SJeff Kirsher 	return IRQ_HANDLED;
3351adfc5217SJeff Kirsher }
3352adfc5217SJeff Kirsher 
3353adfc5217SJeff Kirsher static irqreturn_t
3354adfc5217SJeff Kirsher bnx2_interrupt(int irq, void *dev_instance)
3355adfc5217SJeff Kirsher {
3356adfc5217SJeff Kirsher 	struct bnx2_napi *bnapi = dev_instance;
3357adfc5217SJeff Kirsher 	struct bnx2 *bp = bnapi->bp;
3358adfc5217SJeff Kirsher 	struct status_block *sblk = bnapi->status_blk.msi;
3359adfc5217SJeff Kirsher 
3360adfc5217SJeff Kirsher 	/* When using INTx, it is possible for the interrupt to arrive
3361adfc5217SJeff Kirsher 	 * at the CPU before the status block posted prior to the
3362adfc5217SJeff Kirsher 	 * interrupt. Reading a register will flush the status block.
3363adfc5217SJeff Kirsher 	 * When using MSI, the MSI message will always complete after
3364adfc5217SJeff Kirsher 	 * the status block write.
3365adfc5217SJeff Kirsher 	 */
3366adfc5217SJeff Kirsher 	if ((sblk->status_idx == bnapi->last_status_idx) &&
3367e503e066SMichael Chan 	    (BNX2_RD(bp, BNX2_PCICFG_MISC_STATUS) &
3368adfc5217SJeff Kirsher 	     BNX2_PCICFG_MISC_STATUS_INTA_VALUE))
3369adfc5217SJeff Kirsher 		return IRQ_NONE;
3370adfc5217SJeff Kirsher 
3371e503e066SMichael Chan 	BNX2_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
3372adfc5217SJeff Kirsher 		BNX2_PCICFG_INT_ACK_CMD_USE_INT_HC_PARAM |
3373adfc5217SJeff Kirsher 		BNX2_PCICFG_INT_ACK_CMD_MASK_INT);
3374adfc5217SJeff Kirsher 
3375adfc5217SJeff Kirsher 	/* Read back to deassert IRQ immediately to avoid too many
3376adfc5217SJeff Kirsher 	 * spurious interrupts.
3377adfc5217SJeff Kirsher 	 */
3378e503e066SMichael Chan 	BNX2_RD(bp, BNX2_PCICFG_INT_ACK_CMD);
3379adfc5217SJeff Kirsher 
3380adfc5217SJeff Kirsher 	/* Return here if interrupt is shared and is disabled. */
3381adfc5217SJeff Kirsher 	if (unlikely(atomic_read(&bp->intr_sem) != 0))
3382adfc5217SJeff Kirsher 		return IRQ_HANDLED;
3383adfc5217SJeff Kirsher 
3384adfc5217SJeff Kirsher 	if (napi_schedule_prep(&bnapi->napi)) {
3385adfc5217SJeff Kirsher 		bnapi->last_status_idx = sblk->status_idx;
3386adfc5217SJeff Kirsher 		__napi_schedule(&bnapi->napi);
3387adfc5217SJeff Kirsher 	}
3388adfc5217SJeff Kirsher 
3389adfc5217SJeff Kirsher 	return IRQ_HANDLED;
3390adfc5217SJeff Kirsher }
3391adfc5217SJeff Kirsher 
3392adfc5217SJeff Kirsher static inline int
3393adfc5217SJeff Kirsher bnx2_has_fast_work(struct bnx2_napi *bnapi)
3394adfc5217SJeff Kirsher {
3395adfc5217SJeff Kirsher 	struct bnx2_tx_ring_info *txr = &bnapi->tx_ring;
3396adfc5217SJeff Kirsher 	struct bnx2_rx_ring_info *rxr = &bnapi->rx_ring;
3397adfc5217SJeff Kirsher 
3398adfc5217SJeff Kirsher 	if ((bnx2_get_hw_rx_cons(bnapi) != rxr->rx_cons) ||
3399adfc5217SJeff Kirsher 	    (bnx2_get_hw_tx_cons(bnapi) != txr->hw_tx_cons))
3400adfc5217SJeff Kirsher 		return 1;
3401adfc5217SJeff Kirsher 	return 0;
3402adfc5217SJeff Kirsher }
3403adfc5217SJeff Kirsher 
3404adfc5217SJeff Kirsher #define STATUS_ATTN_EVENTS	(STATUS_ATTN_BITS_LINK_STATE | \
3405adfc5217SJeff Kirsher 				 STATUS_ATTN_BITS_TIMER_ABORT)
3406adfc5217SJeff Kirsher 
3407adfc5217SJeff Kirsher static inline int
3408adfc5217SJeff Kirsher bnx2_has_work(struct bnx2_napi *bnapi)
3409adfc5217SJeff Kirsher {
3410adfc5217SJeff Kirsher 	struct status_block *sblk = bnapi->status_blk.msi;
3411adfc5217SJeff Kirsher 
3412adfc5217SJeff Kirsher 	if (bnx2_has_fast_work(bnapi))
3413adfc5217SJeff Kirsher 		return 1;
3414adfc5217SJeff Kirsher 
3415adfc5217SJeff Kirsher #ifdef BCM_CNIC
3416adfc5217SJeff Kirsher 	if (bnapi->cnic_present && (bnapi->cnic_tag != sblk->status_idx))
3417adfc5217SJeff Kirsher 		return 1;
3418adfc5217SJeff Kirsher #endif
3419adfc5217SJeff Kirsher 
3420adfc5217SJeff Kirsher 	if ((sblk->status_attn_bits & STATUS_ATTN_EVENTS) !=
3421adfc5217SJeff Kirsher 	    (sblk->status_attn_bits_ack & STATUS_ATTN_EVENTS))
3422adfc5217SJeff Kirsher 		return 1;
3423adfc5217SJeff Kirsher 
3424adfc5217SJeff Kirsher 	return 0;
3425adfc5217SJeff Kirsher }
3426adfc5217SJeff Kirsher 
3427adfc5217SJeff Kirsher static void
3428adfc5217SJeff Kirsher bnx2_chk_missed_msi(struct bnx2 *bp)
3429adfc5217SJeff Kirsher {
3430adfc5217SJeff Kirsher 	struct bnx2_napi *bnapi = &bp->bnx2_napi[0];
3431adfc5217SJeff Kirsher 	u32 msi_ctrl;
3432adfc5217SJeff Kirsher 
3433adfc5217SJeff Kirsher 	if (bnx2_has_work(bnapi)) {
3434e503e066SMichael Chan 		msi_ctrl = BNX2_RD(bp, BNX2_PCICFG_MSI_CONTROL);
3435adfc5217SJeff Kirsher 		if (!(msi_ctrl & BNX2_PCICFG_MSI_CONTROL_ENABLE))
3436adfc5217SJeff Kirsher 			return;
3437adfc5217SJeff Kirsher 
3438adfc5217SJeff Kirsher 		if (bnapi->last_status_idx == bp->idle_chk_status_idx) {
3439e503e066SMichael Chan 			BNX2_WR(bp, BNX2_PCICFG_MSI_CONTROL, msi_ctrl &
3440adfc5217SJeff Kirsher 				~BNX2_PCICFG_MSI_CONTROL_ENABLE);
3441e503e066SMichael Chan 			BNX2_WR(bp, BNX2_PCICFG_MSI_CONTROL, msi_ctrl);
3442adfc5217SJeff Kirsher 			bnx2_msi(bp->irq_tbl[0].vector, bnapi);
3443adfc5217SJeff Kirsher 		}
3444adfc5217SJeff Kirsher 	}
3445adfc5217SJeff Kirsher 
3446adfc5217SJeff Kirsher 	bp->idle_chk_status_idx = bnapi->last_status_idx;
3447adfc5217SJeff Kirsher }
3448adfc5217SJeff Kirsher 
3449adfc5217SJeff Kirsher #ifdef BCM_CNIC
3450adfc5217SJeff Kirsher static void bnx2_poll_cnic(struct bnx2 *bp, struct bnx2_napi *bnapi)
3451adfc5217SJeff Kirsher {
3452adfc5217SJeff Kirsher 	struct cnic_ops *c_ops;
3453adfc5217SJeff Kirsher 
3454adfc5217SJeff Kirsher 	if (!bnapi->cnic_present)
3455adfc5217SJeff Kirsher 		return;
3456adfc5217SJeff Kirsher 
3457adfc5217SJeff Kirsher 	rcu_read_lock();
3458adfc5217SJeff Kirsher 	c_ops = rcu_dereference(bp->cnic_ops);
3459adfc5217SJeff Kirsher 	if (c_ops)
3460adfc5217SJeff Kirsher 		bnapi->cnic_tag = c_ops->cnic_handler(bp->cnic_data,
3461adfc5217SJeff Kirsher 						      bnapi->status_blk.msi);
3462adfc5217SJeff Kirsher 	rcu_read_unlock();
3463adfc5217SJeff Kirsher }
3464adfc5217SJeff Kirsher #endif
3465adfc5217SJeff Kirsher 
3466adfc5217SJeff Kirsher static void bnx2_poll_link(struct bnx2 *bp, struct bnx2_napi *bnapi)
3467adfc5217SJeff Kirsher {
3468adfc5217SJeff Kirsher 	struct status_block *sblk = bnapi->status_blk.msi;
3469adfc5217SJeff Kirsher 	u32 status_attn_bits = sblk->status_attn_bits;
3470adfc5217SJeff Kirsher 	u32 status_attn_bits_ack = sblk->status_attn_bits_ack;
3471adfc5217SJeff Kirsher 
3472adfc5217SJeff Kirsher 	if ((status_attn_bits & STATUS_ATTN_EVENTS) !=
3473adfc5217SJeff Kirsher 	    (status_attn_bits_ack & STATUS_ATTN_EVENTS)) {
3474adfc5217SJeff Kirsher 
3475adfc5217SJeff Kirsher 		bnx2_phy_int(bp, bnapi);
3476adfc5217SJeff Kirsher 
3477adfc5217SJeff Kirsher 		/* This is needed to take care of transient status
3478adfc5217SJeff Kirsher 		 * during link changes.
3479adfc5217SJeff Kirsher 		 */
3480e503e066SMichael Chan 		BNX2_WR(bp, BNX2_HC_COMMAND,
3481adfc5217SJeff Kirsher 			bp->hc_cmd | BNX2_HC_COMMAND_COAL_NOW_WO_INT);
3482e503e066SMichael Chan 		BNX2_RD(bp, BNX2_HC_COMMAND);
3483adfc5217SJeff Kirsher 	}
3484adfc5217SJeff Kirsher }
3485adfc5217SJeff Kirsher 
3486adfc5217SJeff Kirsher static int bnx2_poll_work(struct bnx2 *bp, struct bnx2_napi *bnapi,
3487adfc5217SJeff Kirsher 			  int work_done, int budget)
3488adfc5217SJeff Kirsher {
3489adfc5217SJeff Kirsher 	struct bnx2_tx_ring_info *txr = &bnapi->tx_ring;
3490adfc5217SJeff Kirsher 	struct bnx2_rx_ring_info *rxr = &bnapi->rx_ring;
3491adfc5217SJeff Kirsher 
3492adfc5217SJeff Kirsher 	if (bnx2_get_hw_tx_cons(bnapi) != txr->hw_tx_cons)
3493adfc5217SJeff Kirsher 		bnx2_tx_int(bp, bnapi, 0);
3494adfc5217SJeff Kirsher 
3495adfc5217SJeff Kirsher 	if (bnx2_get_hw_rx_cons(bnapi) != rxr->rx_cons)
3496adfc5217SJeff Kirsher 		work_done += bnx2_rx_int(bp, bnapi, budget - work_done);
3497adfc5217SJeff Kirsher 
3498adfc5217SJeff Kirsher 	return work_done;
3499adfc5217SJeff Kirsher }
3500adfc5217SJeff Kirsher 
3501adfc5217SJeff Kirsher static int bnx2_poll_msix(struct napi_struct *napi, int budget)
3502adfc5217SJeff Kirsher {
3503adfc5217SJeff Kirsher 	struct bnx2_napi *bnapi = container_of(napi, struct bnx2_napi, napi);
3504adfc5217SJeff Kirsher 	struct bnx2 *bp = bnapi->bp;
3505adfc5217SJeff Kirsher 	int work_done = 0;
3506adfc5217SJeff Kirsher 	struct status_block_msix *sblk = bnapi->status_blk.msix;
3507adfc5217SJeff Kirsher 
3508adfc5217SJeff Kirsher 	while (1) {
3509adfc5217SJeff Kirsher 		work_done = bnx2_poll_work(bp, bnapi, work_done, budget);
3510adfc5217SJeff Kirsher 		if (unlikely(work_done >= budget))
3511adfc5217SJeff Kirsher 			break;
3512adfc5217SJeff Kirsher 
3513adfc5217SJeff Kirsher 		bnapi->last_status_idx = sblk->status_idx;
3514adfc5217SJeff Kirsher 		/* status idx must be read before checking for more work. */
3515adfc5217SJeff Kirsher 		rmb();
3516adfc5217SJeff Kirsher 		if (likely(!bnx2_has_fast_work(bnapi))) {
3517adfc5217SJeff Kirsher 
35186ad20165SEric Dumazet 			napi_complete_done(napi, work_done);
3519e503e066SMichael Chan 			BNX2_WR(bp, BNX2_PCICFG_INT_ACK_CMD, bnapi->int_num |
3520adfc5217SJeff Kirsher 				BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
3521adfc5217SJeff Kirsher 				bnapi->last_status_idx);
3522adfc5217SJeff Kirsher 			break;
3523adfc5217SJeff Kirsher 		}
3524adfc5217SJeff Kirsher 	}
3525adfc5217SJeff Kirsher 	return work_done;
3526adfc5217SJeff Kirsher }
3527adfc5217SJeff Kirsher 
3528adfc5217SJeff Kirsher static int bnx2_poll(struct napi_struct *napi, int budget)
3529adfc5217SJeff Kirsher {
3530adfc5217SJeff Kirsher 	struct bnx2_napi *bnapi = container_of(napi, struct bnx2_napi, napi);
3531adfc5217SJeff Kirsher 	struct bnx2 *bp = bnapi->bp;
3532adfc5217SJeff Kirsher 	int work_done = 0;
3533adfc5217SJeff Kirsher 	struct status_block *sblk = bnapi->status_blk.msi;
3534adfc5217SJeff Kirsher 
3535adfc5217SJeff Kirsher 	while (1) {
3536adfc5217SJeff Kirsher 		bnx2_poll_link(bp, bnapi);
3537adfc5217SJeff Kirsher 
3538adfc5217SJeff Kirsher 		work_done = bnx2_poll_work(bp, bnapi, work_done, budget);
3539adfc5217SJeff Kirsher 
3540adfc5217SJeff Kirsher #ifdef BCM_CNIC
3541adfc5217SJeff Kirsher 		bnx2_poll_cnic(bp, bnapi);
3542adfc5217SJeff Kirsher #endif
3543adfc5217SJeff Kirsher 
3544adfc5217SJeff Kirsher 		/* bnapi->last_status_idx is used below to tell the hw how
3545adfc5217SJeff Kirsher 		 * much work has been processed, so we must read it before
3546adfc5217SJeff Kirsher 		 * checking for more work.
3547adfc5217SJeff Kirsher 		 */
3548adfc5217SJeff Kirsher 		bnapi->last_status_idx = sblk->status_idx;
3549adfc5217SJeff Kirsher 
3550adfc5217SJeff Kirsher 		if (unlikely(work_done >= budget))
3551adfc5217SJeff Kirsher 			break;
3552adfc5217SJeff Kirsher 
3553adfc5217SJeff Kirsher 		rmb();
3554adfc5217SJeff Kirsher 		if (likely(!bnx2_has_work(bnapi))) {
35556ad20165SEric Dumazet 			napi_complete_done(napi, work_done);
3556adfc5217SJeff Kirsher 			if (likely(bp->flags & BNX2_FLAG_USING_MSI_OR_MSIX)) {
3557e503e066SMichael Chan 				BNX2_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
3558adfc5217SJeff Kirsher 					BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
3559adfc5217SJeff Kirsher 					bnapi->last_status_idx);
3560adfc5217SJeff Kirsher 				break;
3561adfc5217SJeff Kirsher 			}
3562e503e066SMichael Chan 			BNX2_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
3563adfc5217SJeff Kirsher 				BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
3564adfc5217SJeff Kirsher 				BNX2_PCICFG_INT_ACK_CMD_MASK_INT |
3565adfc5217SJeff Kirsher 				bnapi->last_status_idx);
3566adfc5217SJeff Kirsher 
3567e503e066SMichael Chan 			BNX2_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
3568adfc5217SJeff Kirsher 				BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
3569adfc5217SJeff Kirsher 				bnapi->last_status_idx);
3570adfc5217SJeff Kirsher 			break;
3571adfc5217SJeff Kirsher 		}
3572adfc5217SJeff Kirsher 	}
3573adfc5217SJeff Kirsher 
3574adfc5217SJeff Kirsher 	return work_done;
3575adfc5217SJeff Kirsher }
3576adfc5217SJeff Kirsher 
3577adfc5217SJeff Kirsher /* Called with rtnl_lock from vlan functions and also netif_tx_lock
3578adfc5217SJeff Kirsher  * from set_multicast.
3579adfc5217SJeff Kirsher  */
3580adfc5217SJeff Kirsher static void
3581adfc5217SJeff Kirsher bnx2_set_rx_mode(struct net_device *dev)
3582adfc5217SJeff Kirsher {
3583adfc5217SJeff Kirsher 	struct bnx2 *bp = netdev_priv(dev);
3584adfc5217SJeff Kirsher 	u32 rx_mode, sort_mode;
3585adfc5217SJeff Kirsher 	struct netdev_hw_addr *ha;
3586adfc5217SJeff Kirsher 	int i;
3587adfc5217SJeff Kirsher 
3588adfc5217SJeff Kirsher 	if (!netif_running(dev))
3589adfc5217SJeff Kirsher 		return;
3590adfc5217SJeff Kirsher 
3591adfc5217SJeff Kirsher 	spin_lock_bh(&bp->phy_lock);
3592adfc5217SJeff Kirsher 
3593adfc5217SJeff Kirsher 	rx_mode = bp->rx_mode & ~(BNX2_EMAC_RX_MODE_PROMISCUOUS |
3594adfc5217SJeff Kirsher 				  BNX2_EMAC_RX_MODE_KEEP_VLAN_TAG);
3595adfc5217SJeff Kirsher 	sort_mode = 1 | BNX2_RPM_SORT_USER0_BC_EN;
3596f646968fSPatrick McHardy 	if (!(dev->features & NETIF_F_HW_VLAN_CTAG_RX) &&
3597adfc5217SJeff Kirsher 	     (bp->flags & BNX2_FLAG_CAN_KEEP_VLAN))
3598adfc5217SJeff Kirsher 		rx_mode |= BNX2_EMAC_RX_MODE_KEEP_VLAN_TAG;
3599adfc5217SJeff Kirsher 	if (dev->flags & IFF_PROMISC) {
3600adfc5217SJeff Kirsher 		/* Promiscuous mode. */
3601adfc5217SJeff Kirsher 		rx_mode |= BNX2_EMAC_RX_MODE_PROMISCUOUS;
3602adfc5217SJeff Kirsher 		sort_mode |= BNX2_RPM_SORT_USER0_PROM_EN |
3603adfc5217SJeff Kirsher 			     BNX2_RPM_SORT_USER0_PROM_VLAN;
3604adfc5217SJeff Kirsher 	}
3605adfc5217SJeff Kirsher 	else if (dev->flags & IFF_ALLMULTI) {
3606adfc5217SJeff Kirsher 		for (i = 0; i < NUM_MC_HASH_REGISTERS; i++) {
3607e503e066SMichael Chan 			BNX2_WR(bp, BNX2_EMAC_MULTICAST_HASH0 + (i * 4),
3608adfc5217SJeff Kirsher 				0xffffffff);
3609adfc5217SJeff Kirsher         	}
3610adfc5217SJeff Kirsher 		sort_mode |= BNX2_RPM_SORT_USER0_MC_EN;
3611adfc5217SJeff Kirsher 	}
3612adfc5217SJeff Kirsher 	else {
3613adfc5217SJeff Kirsher 		/* Accept one or more multicast(s). */
3614adfc5217SJeff Kirsher 		u32 mc_filter[NUM_MC_HASH_REGISTERS];
3615adfc5217SJeff Kirsher 		u32 regidx;
3616adfc5217SJeff Kirsher 		u32 bit;
3617adfc5217SJeff Kirsher 		u32 crc;
3618adfc5217SJeff Kirsher 
3619adfc5217SJeff Kirsher 		memset(mc_filter, 0, 4 * NUM_MC_HASH_REGISTERS);
3620adfc5217SJeff Kirsher 
3621adfc5217SJeff Kirsher 		netdev_for_each_mc_addr(ha, dev) {
3622adfc5217SJeff Kirsher 			crc = ether_crc_le(ETH_ALEN, ha->addr);
3623adfc5217SJeff Kirsher 			bit = crc & 0xff;
3624adfc5217SJeff Kirsher 			regidx = (bit & 0xe0) >> 5;
3625adfc5217SJeff Kirsher 			bit &= 0x1f;
3626adfc5217SJeff Kirsher 			mc_filter[regidx] |= (1 << bit);
3627adfc5217SJeff Kirsher 		}
3628adfc5217SJeff Kirsher 
3629adfc5217SJeff Kirsher 		for (i = 0; i < NUM_MC_HASH_REGISTERS; i++) {
3630e503e066SMichael Chan 			BNX2_WR(bp, BNX2_EMAC_MULTICAST_HASH0 + (i * 4),
3631adfc5217SJeff Kirsher 				mc_filter[i]);
3632adfc5217SJeff Kirsher 		}
3633adfc5217SJeff Kirsher 
3634adfc5217SJeff Kirsher 		sort_mode |= BNX2_RPM_SORT_USER0_MC_HSH_EN;
3635adfc5217SJeff Kirsher 	}
3636adfc5217SJeff Kirsher 
3637adfc5217SJeff Kirsher 	if (netdev_uc_count(dev) > BNX2_MAX_UNICAST_ADDRESSES) {
3638adfc5217SJeff Kirsher 		rx_mode |= BNX2_EMAC_RX_MODE_PROMISCUOUS;
3639adfc5217SJeff Kirsher 		sort_mode |= BNX2_RPM_SORT_USER0_PROM_EN |
3640adfc5217SJeff Kirsher 			     BNX2_RPM_SORT_USER0_PROM_VLAN;
3641adfc5217SJeff Kirsher 	} else if (!(dev->flags & IFF_PROMISC)) {
3642adfc5217SJeff Kirsher 		/* Add all entries into to the match filter list */
3643adfc5217SJeff Kirsher 		i = 0;
3644adfc5217SJeff Kirsher 		netdev_for_each_uc_addr(ha, dev) {
3645adfc5217SJeff Kirsher 			bnx2_set_mac_addr(bp, ha->addr,
3646adfc5217SJeff Kirsher 					  i + BNX2_START_UNICAST_ADDRESS_INDEX);
3647adfc5217SJeff Kirsher 			sort_mode |= (1 <<
3648adfc5217SJeff Kirsher 				      (i + BNX2_START_UNICAST_ADDRESS_INDEX));
3649adfc5217SJeff Kirsher 			i++;
3650adfc5217SJeff Kirsher 		}
3651adfc5217SJeff Kirsher 
3652adfc5217SJeff Kirsher 	}
3653adfc5217SJeff Kirsher 
3654adfc5217SJeff Kirsher 	if (rx_mode != bp->rx_mode) {
3655adfc5217SJeff Kirsher 		bp->rx_mode = rx_mode;
3656e503e066SMichael Chan 		BNX2_WR(bp, BNX2_EMAC_RX_MODE, rx_mode);
3657adfc5217SJeff Kirsher 	}
3658adfc5217SJeff Kirsher 
3659e503e066SMichael Chan 	BNX2_WR(bp, BNX2_RPM_SORT_USER0, 0x0);
3660e503e066SMichael Chan 	BNX2_WR(bp, BNX2_RPM_SORT_USER0, sort_mode);
3661e503e066SMichael Chan 	BNX2_WR(bp, BNX2_RPM_SORT_USER0, sort_mode | BNX2_RPM_SORT_USER0_ENA);
3662adfc5217SJeff Kirsher 
3663adfc5217SJeff Kirsher 	spin_unlock_bh(&bp->phy_lock);
3664adfc5217SJeff Kirsher }
3665adfc5217SJeff Kirsher 
36667880b72eSfrançois romieu static int
3667adfc5217SJeff Kirsher check_fw_section(const struct firmware *fw,
3668adfc5217SJeff Kirsher 		 const struct bnx2_fw_file_section *section,
3669adfc5217SJeff Kirsher 		 u32 alignment, bool non_empty)
3670adfc5217SJeff Kirsher {
3671adfc5217SJeff Kirsher 	u32 offset = be32_to_cpu(section->offset);
3672adfc5217SJeff Kirsher 	u32 len = be32_to_cpu(section->len);
3673adfc5217SJeff Kirsher 
3674adfc5217SJeff Kirsher 	if ((offset == 0 && len != 0) || offset >= fw->size || offset & 3)
3675adfc5217SJeff Kirsher 		return -EINVAL;
3676adfc5217SJeff Kirsher 	if ((non_empty && len == 0) || len > fw->size - offset ||
3677adfc5217SJeff Kirsher 	    len & (alignment - 1))
3678adfc5217SJeff Kirsher 		return -EINVAL;
3679adfc5217SJeff Kirsher 	return 0;
3680adfc5217SJeff Kirsher }
3681adfc5217SJeff Kirsher 
36827880b72eSfrançois romieu static int
3683adfc5217SJeff Kirsher check_mips_fw_entry(const struct firmware *fw,
3684adfc5217SJeff Kirsher 		    const struct bnx2_mips_fw_file_entry *entry)
3685adfc5217SJeff Kirsher {
3686adfc5217SJeff Kirsher 	if (check_fw_section(fw, &entry->text, 4, true) ||
3687adfc5217SJeff Kirsher 	    check_fw_section(fw, &entry->data, 4, false) ||
3688adfc5217SJeff Kirsher 	    check_fw_section(fw, &entry->rodata, 4, false))
3689adfc5217SJeff Kirsher 		return -EINVAL;
3690adfc5217SJeff Kirsher 	return 0;
3691adfc5217SJeff Kirsher }
3692adfc5217SJeff Kirsher 
36937880b72eSfrançois romieu static void bnx2_release_firmware(struct bnx2 *bp)
36947880b72eSfrançois romieu {
36957880b72eSfrançois romieu 	if (bp->rv2p_firmware) {
36967880b72eSfrançois romieu 		release_firmware(bp->mips_firmware);
36977880b72eSfrançois romieu 		release_firmware(bp->rv2p_firmware);
36987880b72eSfrançois romieu 		bp->rv2p_firmware = NULL;
36997880b72eSfrançois romieu 	}
37007880b72eSfrançois romieu }
37017880b72eSfrançois romieu 
37027880b72eSfrançois romieu static int bnx2_request_uncached_firmware(struct bnx2 *bp)
3703adfc5217SJeff Kirsher {
3704adfc5217SJeff Kirsher 	const char *mips_fw_file, *rv2p_fw_file;
3705adfc5217SJeff Kirsher 	const struct bnx2_mips_fw_file *mips_fw;
3706adfc5217SJeff Kirsher 	const struct bnx2_rv2p_fw_file *rv2p_fw;
3707adfc5217SJeff Kirsher 	int rc;
3708adfc5217SJeff Kirsher 
37094ce45e02SMichael Chan 	if (BNX2_CHIP(bp) == BNX2_CHIP_5709) {
3710adfc5217SJeff Kirsher 		mips_fw_file = FW_MIPS_FILE_09;
37114ce45e02SMichael Chan 		if ((BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5709_A0) ||
37124ce45e02SMichael Chan 		    (BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5709_A1))
3713adfc5217SJeff Kirsher 			rv2p_fw_file = FW_RV2P_FILE_09_Ax;
3714adfc5217SJeff Kirsher 		else
3715adfc5217SJeff Kirsher 			rv2p_fw_file = FW_RV2P_FILE_09;
3716adfc5217SJeff Kirsher 	} else {
3717adfc5217SJeff Kirsher 		mips_fw_file = FW_MIPS_FILE_06;
3718adfc5217SJeff Kirsher 		rv2p_fw_file = FW_RV2P_FILE_06;
3719adfc5217SJeff Kirsher 	}
3720adfc5217SJeff Kirsher 
3721adfc5217SJeff Kirsher 	rc = request_firmware(&bp->mips_firmware, mips_fw_file, &bp->pdev->dev);
3722adfc5217SJeff Kirsher 	if (rc) {
3723adfc5217SJeff Kirsher 		pr_err("Can't load firmware file \"%s\"\n", mips_fw_file);
37247880b72eSfrançois romieu 		goto out;
3725adfc5217SJeff Kirsher 	}
3726adfc5217SJeff Kirsher 
3727adfc5217SJeff Kirsher 	rc = request_firmware(&bp->rv2p_firmware, rv2p_fw_file, &bp->pdev->dev);
3728adfc5217SJeff Kirsher 	if (rc) {
3729adfc5217SJeff Kirsher 		pr_err("Can't load firmware file \"%s\"\n", rv2p_fw_file);
37307880b72eSfrançois romieu 		goto err_release_mips_firmware;
3731adfc5217SJeff Kirsher 	}
3732adfc5217SJeff Kirsher 	mips_fw = (const struct bnx2_mips_fw_file *) bp->mips_firmware->data;
3733adfc5217SJeff Kirsher 	rv2p_fw = (const struct bnx2_rv2p_fw_file *) bp->rv2p_firmware->data;
3734adfc5217SJeff Kirsher 	if (bp->mips_firmware->size < sizeof(*mips_fw) ||
3735adfc5217SJeff Kirsher 	    check_mips_fw_entry(bp->mips_firmware, &mips_fw->com) ||
3736adfc5217SJeff Kirsher 	    check_mips_fw_entry(bp->mips_firmware, &mips_fw->cp) ||
3737adfc5217SJeff Kirsher 	    check_mips_fw_entry(bp->mips_firmware, &mips_fw->rxp) ||
3738adfc5217SJeff Kirsher 	    check_mips_fw_entry(bp->mips_firmware, &mips_fw->tpat) ||
3739adfc5217SJeff Kirsher 	    check_mips_fw_entry(bp->mips_firmware, &mips_fw->txp)) {
3740adfc5217SJeff Kirsher 		pr_err("Firmware file \"%s\" is invalid\n", mips_fw_file);
37417880b72eSfrançois romieu 		rc = -EINVAL;
37427880b72eSfrançois romieu 		goto err_release_firmware;
3743adfc5217SJeff Kirsher 	}
3744adfc5217SJeff Kirsher 	if (bp->rv2p_firmware->size < sizeof(*rv2p_fw) ||
3745adfc5217SJeff Kirsher 	    check_fw_section(bp->rv2p_firmware, &rv2p_fw->proc1.rv2p, 8, true) ||
3746adfc5217SJeff Kirsher 	    check_fw_section(bp->rv2p_firmware, &rv2p_fw->proc2.rv2p, 8, true)) {
3747adfc5217SJeff Kirsher 		pr_err("Firmware file \"%s\" is invalid\n", rv2p_fw_file);
37487880b72eSfrançois romieu 		rc = -EINVAL;
37497880b72eSfrançois romieu 		goto err_release_firmware;
37507880b72eSfrançois romieu 	}
37517880b72eSfrançois romieu out:
37527880b72eSfrançois romieu 	return rc;
37537880b72eSfrançois romieu 
37547880b72eSfrançois romieu err_release_firmware:
37557880b72eSfrançois romieu 	release_firmware(bp->rv2p_firmware);
37567880b72eSfrançois romieu 	bp->rv2p_firmware = NULL;
37577880b72eSfrançois romieu err_release_mips_firmware:
37587880b72eSfrançois romieu 	release_firmware(bp->mips_firmware);
37597880b72eSfrançois romieu 	goto out;
3760adfc5217SJeff Kirsher }
3761adfc5217SJeff Kirsher 
37627880b72eSfrançois romieu static int bnx2_request_firmware(struct bnx2 *bp)
37637880b72eSfrançois romieu {
37647880b72eSfrançois romieu 	return bp->rv2p_firmware ? 0 : bnx2_request_uncached_firmware(bp);
3765adfc5217SJeff Kirsher }
3766adfc5217SJeff Kirsher 
3767adfc5217SJeff Kirsher static u32
3768adfc5217SJeff Kirsher rv2p_fw_fixup(u32 rv2p_proc, int idx, u32 loc, u32 rv2p_code)
3769adfc5217SJeff Kirsher {
3770adfc5217SJeff Kirsher 	switch (idx) {
3771adfc5217SJeff Kirsher 	case RV2P_P1_FIXUP_PAGE_SIZE_IDX:
3772adfc5217SJeff Kirsher 		rv2p_code &= ~RV2P_BD_PAGE_SIZE_MSK;
3773adfc5217SJeff Kirsher 		rv2p_code |= RV2P_BD_PAGE_SIZE;
3774adfc5217SJeff Kirsher 		break;
3775adfc5217SJeff Kirsher 	}
3776adfc5217SJeff Kirsher 	return rv2p_code;
3777adfc5217SJeff Kirsher }
3778adfc5217SJeff Kirsher 
3779adfc5217SJeff Kirsher static int
3780adfc5217SJeff Kirsher load_rv2p_fw(struct bnx2 *bp, u32 rv2p_proc,
3781adfc5217SJeff Kirsher 	     const struct bnx2_rv2p_fw_file_entry *fw_entry)
3782adfc5217SJeff Kirsher {
3783adfc5217SJeff Kirsher 	u32 rv2p_code_len, file_offset;
3784adfc5217SJeff Kirsher 	__be32 *rv2p_code;
3785adfc5217SJeff Kirsher 	int i;
3786adfc5217SJeff Kirsher 	u32 val, cmd, addr;
3787adfc5217SJeff Kirsher 
3788adfc5217SJeff Kirsher 	rv2p_code_len = be32_to_cpu(fw_entry->rv2p.len);
3789adfc5217SJeff Kirsher 	file_offset = be32_to_cpu(fw_entry->rv2p.offset);
3790adfc5217SJeff Kirsher 
3791adfc5217SJeff Kirsher 	rv2p_code = (__be32 *)(bp->rv2p_firmware->data + file_offset);
3792adfc5217SJeff Kirsher 
3793adfc5217SJeff Kirsher 	if (rv2p_proc == RV2P_PROC1) {
3794adfc5217SJeff Kirsher 		cmd = BNX2_RV2P_PROC1_ADDR_CMD_RDWR;
3795adfc5217SJeff Kirsher 		addr = BNX2_RV2P_PROC1_ADDR_CMD;
3796adfc5217SJeff Kirsher 	} else {
3797adfc5217SJeff Kirsher 		cmd = BNX2_RV2P_PROC2_ADDR_CMD_RDWR;
3798adfc5217SJeff Kirsher 		addr = BNX2_RV2P_PROC2_ADDR_CMD;
3799adfc5217SJeff Kirsher 	}
3800adfc5217SJeff Kirsher 
3801adfc5217SJeff Kirsher 	for (i = 0; i < rv2p_code_len; i += 8) {
3802e503e066SMichael Chan 		BNX2_WR(bp, BNX2_RV2P_INSTR_HIGH, be32_to_cpu(*rv2p_code));
3803adfc5217SJeff Kirsher 		rv2p_code++;
3804e503e066SMichael Chan 		BNX2_WR(bp, BNX2_RV2P_INSTR_LOW, be32_to_cpu(*rv2p_code));
3805adfc5217SJeff Kirsher 		rv2p_code++;
3806adfc5217SJeff Kirsher 
3807adfc5217SJeff Kirsher 		val = (i / 8) | cmd;
3808e503e066SMichael Chan 		BNX2_WR(bp, addr, val);
3809adfc5217SJeff Kirsher 	}
3810adfc5217SJeff Kirsher 
3811adfc5217SJeff Kirsher 	rv2p_code = (__be32 *)(bp->rv2p_firmware->data + file_offset);
3812adfc5217SJeff Kirsher 	for (i = 0; i < 8; i++) {
3813adfc5217SJeff Kirsher 		u32 loc, code;
3814adfc5217SJeff Kirsher 
3815adfc5217SJeff Kirsher 		loc = be32_to_cpu(fw_entry->fixup[i]);
3816adfc5217SJeff Kirsher 		if (loc && ((loc * 4) < rv2p_code_len)) {
3817adfc5217SJeff Kirsher 			code = be32_to_cpu(*(rv2p_code + loc - 1));
3818e503e066SMichael Chan 			BNX2_WR(bp, BNX2_RV2P_INSTR_HIGH, code);
3819adfc5217SJeff Kirsher 			code = be32_to_cpu(*(rv2p_code + loc));
3820adfc5217SJeff Kirsher 			code = rv2p_fw_fixup(rv2p_proc, i, loc, code);
3821e503e066SMichael Chan 			BNX2_WR(bp, BNX2_RV2P_INSTR_LOW, code);
3822adfc5217SJeff Kirsher 
3823adfc5217SJeff Kirsher 			val = (loc / 2) | cmd;
3824e503e066SMichael Chan 			BNX2_WR(bp, addr, val);
3825adfc5217SJeff Kirsher 		}
3826adfc5217SJeff Kirsher 	}
3827adfc5217SJeff Kirsher 
3828adfc5217SJeff Kirsher 	/* Reset the processor, un-stall is done later. */
3829adfc5217SJeff Kirsher 	if (rv2p_proc == RV2P_PROC1) {
3830e503e066SMichael Chan 		BNX2_WR(bp, BNX2_RV2P_COMMAND, BNX2_RV2P_COMMAND_PROC1_RESET);
3831adfc5217SJeff Kirsher 	}
3832adfc5217SJeff Kirsher 	else {
3833e503e066SMichael Chan 		BNX2_WR(bp, BNX2_RV2P_COMMAND, BNX2_RV2P_COMMAND_PROC2_RESET);
3834adfc5217SJeff Kirsher 	}
3835adfc5217SJeff Kirsher 
3836adfc5217SJeff Kirsher 	return 0;
3837adfc5217SJeff Kirsher }
3838adfc5217SJeff Kirsher 
3839adfc5217SJeff Kirsher static int
3840adfc5217SJeff Kirsher load_cpu_fw(struct bnx2 *bp, const struct cpu_reg *cpu_reg,
3841adfc5217SJeff Kirsher 	    const struct bnx2_mips_fw_file_entry *fw_entry)
3842adfc5217SJeff Kirsher {
3843adfc5217SJeff Kirsher 	u32 addr, len, file_offset;
3844adfc5217SJeff Kirsher 	__be32 *data;
3845adfc5217SJeff Kirsher 	u32 offset;
3846adfc5217SJeff Kirsher 	u32 val;
3847adfc5217SJeff Kirsher 
3848adfc5217SJeff Kirsher 	/* Halt the CPU. */
3849adfc5217SJeff Kirsher 	val = bnx2_reg_rd_ind(bp, cpu_reg->mode);
3850adfc5217SJeff Kirsher 	val |= cpu_reg->mode_value_halt;
3851adfc5217SJeff Kirsher 	bnx2_reg_wr_ind(bp, cpu_reg->mode, val);
3852adfc5217SJeff Kirsher 	bnx2_reg_wr_ind(bp, cpu_reg->state, cpu_reg->state_value_clear);
3853adfc5217SJeff Kirsher 
3854adfc5217SJeff Kirsher 	/* Load the Text area. */
3855adfc5217SJeff Kirsher 	addr = be32_to_cpu(fw_entry->text.addr);
3856adfc5217SJeff Kirsher 	len = be32_to_cpu(fw_entry->text.len);
3857adfc5217SJeff Kirsher 	file_offset = be32_to_cpu(fw_entry->text.offset);
3858adfc5217SJeff Kirsher 	data = (__be32 *)(bp->mips_firmware->data + file_offset);
3859adfc5217SJeff Kirsher 
3860adfc5217SJeff Kirsher 	offset = cpu_reg->spad_base + (addr - cpu_reg->mips_view_base);
3861adfc5217SJeff Kirsher 	if (len) {
3862adfc5217SJeff Kirsher 		int j;
3863adfc5217SJeff Kirsher 
3864adfc5217SJeff Kirsher 		for (j = 0; j < (len / 4); j++, offset += 4)
3865adfc5217SJeff Kirsher 			bnx2_reg_wr_ind(bp, offset, be32_to_cpu(data[j]));
3866adfc5217SJeff Kirsher 	}
3867adfc5217SJeff Kirsher 
3868adfc5217SJeff Kirsher 	/* Load the Data area. */
3869adfc5217SJeff Kirsher 	addr = be32_to_cpu(fw_entry->data.addr);
3870adfc5217SJeff Kirsher 	len = be32_to_cpu(fw_entry->data.len);
3871adfc5217SJeff Kirsher 	file_offset = be32_to_cpu(fw_entry->data.offset);
3872adfc5217SJeff Kirsher 	data = (__be32 *)(bp->mips_firmware->data + file_offset);
3873adfc5217SJeff Kirsher 
3874adfc5217SJeff Kirsher 	offset = cpu_reg->spad_base + (addr - cpu_reg->mips_view_base);
3875adfc5217SJeff Kirsher 	if (len) {
3876adfc5217SJeff Kirsher 		int j;
3877adfc5217SJeff Kirsher 
3878adfc5217SJeff Kirsher 		for (j = 0; j < (len / 4); j++, offset += 4)
3879adfc5217SJeff Kirsher 			bnx2_reg_wr_ind(bp, offset, be32_to_cpu(data[j]));
3880adfc5217SJeff Kirsher 	}
3881adfc5217SJeff Kirsher 
3882adfc5217SJeff Kirsher 	/* Load the Read-Only area. */
3883adfc5217SJeff Kirsher 	addr = be32_to_cpu(fw_entry->rodata.addr);
3884adfc5217SJeff Kirsher 	len = be32_to_cpu(fw_entry->rodata.len);
3885adfc5217SJeff Kirsher 	file_offset = be32_to_cpu(fw_entry->rodata.offset);
3886adfc5217SJeff Kirsher 	data = (__be32 *)(bp->mips_firmware->data + file_offset);
3887adfc5217SJeff Kirsher 
3888adfc5217SJeff Kirsher 	offset = cpu_reg->spad_base + (addr - cpu_reg->mips_view_base);
3889adfc5217SJeff Kirsher 	if (len) {
3890adfc5217SJeff Kirsher 		int j;
3891adfc5217SJeff Kirsher 
3892adfc5217SJeff Kirsher 		for (j = 0; j < (len / 4); j++, offset += 4)
3893adfc5217SJeff Kirsher 			bnx2_reg_wr_ind(bp, offset, be32_to_cpu(data[j]));
3894adfc5217SJeff Kirsher 	}
3895adfc5217SJeff Kirsher 
3896adfc5217SJeff Kirsher 	/* Clear the pre-fetch instruction. */
3897adfc5217SJeff Kirsher 	bnx2_reg_wr_ind(bp, cpu_reg->inst, 0);
3898adfc5217SJeff Kirsher 
3899adfc5217SJeff Kirsher 	val = be32_to_cpu(fw_entry->start_addr);
3900adfc5217SJeff Kirsher 	bnx2_reg_wr_ind(bp, cpu_reg->pc, val);
3901adfc5217SJeff Kirsher 
3902adfc5217SJeff Kirsher 	/* Start the CPU. */
3903adfc5217SJeff Kirsher 	val = bnx2_reg_rd_ind(bp, cpu_reg->mode);
3904adfc5217SJeff Kirsher 	val &= ~cpu_reg->mode_value_halt;
3905adfc5217SJeff Kirsher 	bnx2_reg_wr_ind(bp, cpu_reg->state, cpu_reg->state_value_clear);
3906adfc5217SJeff Kirsher 	bnx2_reg_wr_ind(bp, cpu_reg->mode, val);
3907adfc5217SJeff Kirsher 
3908adfc5217SJeff Kirsher 	return 0;
3909adfc5217SJeff Kirsher }
3910adfc5217SJeff Kirsher 
3911adfc5217SJeff Kirsher static int
3912adfc5217SJeff Kirsher bnx2_init_cpus(struct bnx2 *bp)
3913adfc5217SJeff Kirsher {
3914adfc5217SJeff Kirsher 	const struct bnx2_mips_fw_file *mips_fw =
3915adfc5217SJeff Kirsher 		(const struct bnx2_mips_fw_file *) bp->mips_firmware->data;
3916adfc5217SJeff Kirsher 	const struct bnx2_rv2p_fw_file *rv2p_fw =
3917adfc5217SJeff Kirsher 		(const struct bnx2_rv2p_fw_file *) bp->rv2p_firmware->data;
3918adfc5217SJeff Kirsher 	int rc;
3919adfc5217SJeff Kirsher 
3920adfc5217SJeff Kirsher 	/* Initialize the RV2P processor. */
3921adfc5217SJeff Kirsher 	load_rv2p_fw(bp, RV2P_PROC1, &rv2p_fw->proc1);
3922adfc5217SJeff Kirsher 	load_rv2p_fw(bp, RV2P_PROC2, &rv2p_fw->proc2);
3923adfc5217SJeff Kirsher 
3924adfc5217SJeff Kirsher 	/* Initialize the RX Processor. */
3925adfc5217SJeff Kirsher 	rc = load_cpu_fw(bp, &cpu_reg_rxp, &mips_fw->rxp);
3926adfc5217SJeff Kirsher 	if (rc)
3927adfc5217SJeff Kirsher 		goto init_cpu_err;
3928adfc5217SJeff Kirsher 
3929adfc5217SJeff Kirsher 	/* Initialize the TX Processor. */
3930adfc5217SJeff Kirsher 	rc = load_cpu_fw(bp, &cpu_reg_txp, &mips_fw->txp);
3931adfc5217SJeff Kirsher 	if (rc)
3932adfc5217SJeff Kirsher 		goto init_cpu_err;
3933adfc5217SJeff Kirsher 
3934adfc5217SJeff Kirsher 	/* Initialize the TX Patch-up Processor. */
3935adfc5217SJeff Kirsher 	rc = load_cpu_fw(bp, &cpu_reg_tpat, &mips_fw->tpat);
3936adfc5217SJeff Kirsher 	if (rc)
3937adfc5217SJeff Kirsher 		goto init_cpu_err;
3938adfc5217SJeff Kirsher 
3939adfc5217SJeff Kirsher 	/* Initialize the Completion Processor. */
3940adfc5217SJeff Kirsher 	rc = load_cpu_fw(bp, &cpu_reg_com, &mips_fw->com);
3941adfc5217SJeff Kirsher 	if (rc)
3942adfc5217SJeff Kirsher 		goto init_cpu_err;
3943adfc5217SJeff Kirsher 
3944adfc5217SJeff Kirsher 	/* Initialize the Command Processor. */
3945adfc5217SJeff Kirsher 	rc = load_cpu_fw(bp, &cpu_reg_cp, &mips_fw->cp);
3946adfc5217SJeff Kirsher 
3947adfc5217SJeff Kirsher init_cpu_err:
3948adfc5217SJeff Kirsher 	return rc;
3949adfc5217SJeff Kirsher }
3950adfc5217SJeff Kirsher 
3951b6a23e91SMichael Chan static void
3952b6a23e91SMichael Chan bnx2_setup_wol(struct bnx2 *bp)
3953adfc5217SJeff Kirsher {
3954adfc5217SJeff Kirsher 	int i;
3955adfc5217SJeff Kirsher 	u32 val, wol_msg;
3956adfc5217SJeff Kirsher 
3957adfc5217SJeff Kirsher 	if (bp->wol) {
3958adfc5217SJeff Kirsher 		u32 advertising;
3959adfc5217SJeff Kirsher 		u8 autoneg;
3960adfc5217SJeff Kirsher 
3961adfc5217SJeff Kirsher 		autoneg = bp->autoneg;
3962adfc5217SJeff Kirsher 		advertising = bp->advertising;
3963adfc5217SJeff Kirsher 
3964adfc5217SJeff Kirsher 		if (bp->phy_port == PORT_TP) {
3965adfc5217SJeff Kirsher 			bp->autoneg = AUTONEG_SPEED;
3966adfc5217SJeff Kirsher 			bp->advertising = ADVERTISED_10baseT_Half |
3967adfc5217SJeff Kirsher 				ADVERTISED_10baseT_Full |
3968adfc5217SJeff Kirsher 				ADVERTISED_100baseT_Half |
3969adfc5217SJeff Kirsher 				ADVERTISED_100baseT_Full |
3970adfc5217SJeff Kirsher 				ADVERTISED_Autoneg;
3971adfc5217SJeff Kirsher 		}
3972adfc5217SJeff Kirsher 
3973adfc5217SJeff Kirsher 		spin_lock_bh(&bp->phy_lock);
3974adfc5217SJeff Kirsher 		bnx2_setup_phy(bp, bp->phy_port);
3975adfc5217SJeff Kirsher 		spin_unlock_bh(&bp->phy_lock);
3976adfc5217SJeff Kirsher 
3977adfc5217SJeff Kirsher 		bp->autoneg = autoneg;
3978adfc5217SJeff Kirsher 		bp->advertising = advertising;
3979adfc5217SJeff Kirsher 
3980adfc5217SJeff Kirsher 		bnx2_set_mac_addr(bp, bp->dev->dev_addr, 0);
3981adfc5217SJeff Kirsher 
3982e503e066SMichael Chan 		val = BNX2_RD(bp, BNX2_EMAC_MODE);
3983adfc5217SJeff Kirsher 
3984adfc5217SJeff Kirsher 		/* Enable port mode. */
3985adfc5217SJeff Kirsher 		val &= ~BNX2_EMAC_MODE_PORT;
3986adfc5217SJeff Kirsher 		val |= BNX2_EMAC_MODE_MPKT_RCVD |
3987adfc5217SJeff Kirsher 		       BNX2_EMAC_MODE_ACPI_RCVD |
3988adfc5217SJeff Kirsher 		       BNX2_EMAC_MODE_MPKT;
3989b6a23e91SMichael Chan 		if (bp->phy_port == PORT_TP) {
3990adfc5217SJeff Kirsher 			val |= BNX2_EMAC_MODE_PORT_MII;
3991b6a23e91SMichael Chan 		} else {
3992adfc5217SJeff Kirsher 			val |= BNX2_EMAC_MODE_PORT_GMII;
3993adfc5217SJeff Kirsher 			if (bp->line_speed == SPEED_2500)
3994adfc5217SJeff Kirsher 				val |= BNX2_EMAC_MODE_25G_MODE;
3995adfc5217SJeff Kirsher 		}
3996adfc5217SJeff Kirsher 
3997e503e066SMichael Chan 		BNX2_WR(bp, BNX2_EMAC_MODE, val);
3998adfc5217SJeff Kirsher 
3999adfc5217SJeff Kirsher 		/* receive all multicast */
4000adfc5217SJeff Kirsher 		for (i = 0; i < NUM_MC_HASH_REGISTERS; i++) {
4001e503e066SMichael Chan 			BNX2_WR(bp, BNX2_EMAC_MULTICAST_HASH0 + (i * 4),
4002adfc5217SJeff Kirsher 				0xffffffff);
4003adfc5217SJeff Kirsher 		}
4004b6a23e91SMichael Chan 		BNX2_WR(bp, BNX2_EMAC_RX_MODE, BNX2_EMAC_RX_MODE_SORT_MODE);
4005adfc5217SJeff Kirsher 
4006b6a23e91SMichael Chan 		val = 1 | BNX2_RPM_SORT_USER0_BC_EN | BNX2_RPM_SORT_USER0_MC_EN;
4007e503e066SMichael Chan 		BNX2_WR(bp, BNX2_RPM_SORT_USER0, 0x0);
4008e503e066SMichael Chan 		BNX2_WR(bp, BNX2_RPM_SORT_USER0, val);
4009b6a23e91SMichael Chan 		BNX2_WR(bp, BNX2_RPM_SORT_USER0, val | BNX2_RPM_SORT_USER0_ENA);
4010adfc5217SJeff Kirsher 
4011adfc5217SJeff Kirsher 		/* Need to enable EMAC and RPM for WOL. */
4012e503e066SMichael Chan 		BNX2_WR(bp, BNX2_MISC_ENABLE_SET_BITS,
4013adfc5217SJeff Kirsher 			BNX2_MISC_ENABLE_SET_BITS_RX_PARSER_MAC_ENABLE |
4014adfc5217SJeff Kirsher 			BNX2_MISC_ENABLE_SET_BITS_TX_HEADER_Q_ENABLE |
4015adfc5217SJeff Kirsher 			BNX2_MISC_ENABLE_SET_BITS_EMAC_ENABLE);
4016adfc5217SJeff Kirsher 
4017e503e066SMichael Chan 		val = BNX2_RD(bp, BNX2_RPM_CONFIG);
4018adfc5217SJeff Kirsher 		val &= ~BNX2_RPM_CONFIG_ACPI_ENA;
4019e503e066SMichael Chan 		BNX2_WR(bp, BNX2_RPM_CONFIG, val);
4020adfc5217SJeff Kirsher 
4021adfc5217SJeff Kirsher 		wol_msg = BNX2_DRV_MSG_CODE_SUSPEND_WOL;
4022b6a23e91SMichael Chan 	} else {
4023adfc5217SJeff Kirsher 			wol_msg = BNX2_DRV_MSG_CODE_SUSPEND_NO_WOL;
4024adfc5217SJeff Kirsher 	}
4025adfc5217SJeff Kirsher 
4026a8d9bc2eSMichael Chan 	if (!(bp->flags & BNX2_FLAG_NO_WOL)) {
4027a8d9bc2eSMichael Chan 		u32 val;
4028a8d9bc2eSMichael Chan 
4029a8d9bc2eSMichael Chan 		wol_msg |= BNX2_DRV_MSG_DATA_WAIT3;
4030a8d9bc2eSMichael Chan 		if (bp->fw_last_msg || BNX2_CHIP(bp) != BNX2_CHIP_5709) {
4031a8d9bc2eSMichael Chan 			bnx2_fw_sync(bp, wol_msg, 1, 0);
4032a8d9bc2eSMichael Chan 			return;
4033a8d9bc2eSMichael Chan 		}
4034a8d9bc2eSMichael Chan 		/* Tell firmware not to power down the PHY yet, otherwise
4035a8d9bc2eSMichael Chan 		 * the chip will take a long time to respond to MMIO reads.
4036a8d9bc2eSMichael Chan 		 */
4037a8d9bc2eSMichael Chan 		val = bnx2_shmem_rd(bp, BNX2_PORT_FEATURE);
4038a8d9bc2eSMichael Chan 		bnx2_shmem_wr(bp, BNX2_PORT_FEATURE,
4039a8d9bc2eSMichael Chan 			      val | BNX2_PORT_FEATURE_ASF_ENABLED);
4040a8d9bc2eSMichael Chan 		bnx2_fw_sync(bp, wol_msg, 1, 0);
4041a8d9bc2eSMichael Chan 		bnx2_shmem_wr(bp, BNX2_PORT_FEATURE, val);
4042a8d9bc2eSMichael Chan 	}
4043adfc5217SJeff Kirsher 
4044b6a23e91SMichael Chan }
4045b6a23e91SMichael Chan 
4046b6a23e91SMichael Chan static int
4047b6a23e91SMichael Chan bnx2_set_power_state(struct bnx2 *bp, pci_power_t state)
4048b6a23e91SMichael Chan {
4049b6a23e91SMichael Chan 	switch (state) {
4050b6a23e91SMichael Chan 	case PCI_D0: {
4051b6a23e91SMichael Chan 		u32 val;
4052b6a23e91SMichael Chan 
4053b6a23e91SMichael Chan 		pci_enable_wake(bp->pdev, PCI_D0, false);
4054b6a23e91SMichael Chan 		pci_set_power_state(bp->pdev, PCI_D0);
4055b6a23e91SMichael Chan 
4056b6a23e91SMichael Chan 		val = BNX2_RD(bp, BNX2_EMAC_MODE);
4057b6a23e91SMichael Chan 		val |= BNX2_EMAC_MODE_MPKT_RCVD | BNX2_EMAC_MODE_ACPI_RCVD;
4058b6a23e91SMichael Chan 		val &= ~BNX2_EMAC_MODE_MPKT;
4059b6a23e91SMichael Chan 		BNX2_WR(bp, BNX2_EMAC_MODE, val);
4060b6a23e91SMichael Chan 
4061b6a23e91SMichael Chan 		val = BNX2_RD(bp, BNX2_RPM_CONFIG);
4062b6a23e91SMichael Chan 		val &= ~BNX2_RPM_CONFIG_ACPI_ENA;
4063b6a23e91SMichael Chan 		BNX2_WR(bp, BNX2_RPM_CONFIG, val);
4064b6a23e91SMichael Chan 		break;
4065b6a23e91SMichael Chan 	}
4066b6a23e91SMichael Chan 	case PCI_D3hot: {
4067b6a23e91SMichael Chan 		bnx2_setup_wol(bp);
40686d5e85c7SMichael Chan 		pci_wake_from_d3(bp->pdev, bp->wol);
40694ce45e02SMichael Chan 		if ((BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5706_A0) ||
40704ce45e02SMichael Chan 		    (BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5706_A1)) {
4071adfc5217SJeff Kirsher 
4072adfc5217SJeff Kirsher 			if (bp->wol)
40736d5e85c7SMichael Chan 				pci_set_power_state(bp->pdev, PCI_D3hot);
4074a8d9bc2eSMichael Chan 			break;
4075a8d9bc2eSMichael Chan 
4076adfc5217SJeff Kirsher 		}
4077a8d9bc2eSMichael Chan 		if (!bp->fw_last_msg && BNX2_CHIP(bp) == BNX2_CHIP_5709) {
4078a8d9bc2eSMichael Chan 			u32 val;
4079a8d9bc2eSMichael Chan 
4080a8d9bc2eSMichael Chan 			/* Tell firmware not to power down the PHY yet,
4081a8d9bc2eSMichael Chan 			 * otherwise the other port may not respond to
4082a8d9bc2eSMichael Chan 			 * MMIO reads.
4083a8d9bc2eSMichael Chan 			 */
4084a8d9bc2eSMichael Chan 			val = bnx2_shmem_rd(bp, BNX2_BC_STATE_CONDITION);
4085a8d9bc2eSMichael Chan 			val &= ~BNX2_CONDITION_PM_STATE_MASK;
4086a8d9bc2eSMichael Chan 			val |= BNX2_CONDITION_PM_STATE_UNPREP;
4087a8d9bc2eSMichael Chan 			bnx2_shmem_wr(bp, BNX2_BC_STATE_CONDITION, val);
4088a8d9bc2eSMichael Chan 		}
4089a8d9bc2eSMichael Chan 		pci_set_power_state(bp->pdev, PCI_D3hot);
4090adfc5217SJeff Kirsher 
4091adfc5217SJeff Kirsher 		/* No more memory access after this point until
4092adfc5217SJeff Kirsher 		 * device is brought back to D0.
4093adfc5217SJeff Kirsher 		 */
4094adfc5217SJeff Kirsher 		break;
4095adfc5217SJeff Kirsher 	}
4096adfc5217SJeff Kirsher 	default:
4097adfc5217SJeff Kirsher 		return -EINVAL;
4098adfc5217SJeff Kirsher 	}
4099adfc5217SJeff Kirsher 	return 0;
4100adfc5217SJeff Kirsher }
4101adfc5217SJeff Kirsher 
4102adfc5217SJeff Kirsher static int
4103adfc5217SJeff Kirsher bnx2_acquire_nvram_lock(struct bnx2 *bp)
4104adfc5217SJeff Kirsher {
4105adfc5217SJeff Kirsher 	u32 val;
4106adfc5217SJeff Kirsher 	int j;
4107adfc5217SJeff Kirsher 
4108adfc5217SJeff Kirsher 	/* Request access to the flash interface. */
4109e503e066SMichael Chan 	BNX2_WR(bp, BNX2_NVM_SW_ARB, BNX2_NVM_SW_ARB_ARB_REQ_SET2);
4110adfc5217SJeff Kirsher 	for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) {
4111e503e066SMichael Chan 		val = BNX2_RD(bp, BNX2_NVM_SW_ARB);
4112adfc5217SJeff Kirsher 		if (val & BNX2_NVM_SW_ARB_ARB_ARB2)
4113adfc5217SJeff Kirsher 			break;
4114adfc5217SJeff Kirsher 
4115adfc5217SJeff Kirsher 		udelay(5);
4116adfc5217SJeff Kirsher 	}
4117adfc5217SJeff Kirsher 
4118adfc5217SJeff Kirsher 	if (j >= NVRAM_TIMEOUT_COUNT)
4119adfc5217SJeff Kirsher 		return -EBUSY;
4120adfc5217SJeff Kirsher 
4121adfc5217SJeff Kirsher 	return 0;
4122adfc5217SJeff Kirsher }
4123adfc5217SJeff Kirsher 
4124adfc5217SJeff Kirsher static int
4125adfc5217SJeff Kirsher bnx2_release_nvram_lock(struct bnx2 *bp)
4126adfc5217SJeff Kirsher {
4127adfc5217SJeff Kirsher 	int j;
4128adfc5217SJeff Kirsher 	u32 val;
4129adfc5217SJeff Kirsher 
4130adfc5217SJeff Kirsher 	/* Relinquish nvram interface. */
4131e503e066SMichael Chan 	BNX2_WR(bp, BNX2_NVM_SW_ARB, BNX2_NVM_SW_ARB_ARB_REQ_CLR2);
4132adfc5217SJeff Kirsher 
4133adfc5217SJeff Kirsher 	for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) {
4134e503e066SMichael Chan 		val = BNX2_RD(bp, BNX2_NVM_SW_ARB);
4135adfc5217SJeff Kirsher 		if (!(val & BNX2_NVM_SW_ARB_ARB_ARB2))
4136adfc5217SJeff Kirsher 			break;
4137adfc5217SJeff Kirsher 
4138adfc5217SJeff Kirsher 		udelay(5);
4139adfc5217SJeff Kirsher 	}
4140adfc5217SJeff Kirsher 
4141adfc5217SJeff Kirsher 	if (j >= NVRAM_TIMEOUT_COUNT)
4142adfc5217SJeff Kirsher 		return -EBUSY;
4143adfc5217SJeff Kirsher 
4144adfc5217SJeff Kirsher 	return 0;
4145adfc5217SJeff Kirsher }
4146adfc5217SJeff Kirsher 
4147adfc5217SJeff Kirsher 
4148adfc5217SJeff Kirsher static int
4149adfc5217SJeff Kirsher bnx2_enable_nvram_write(struct bnx2 *bp)
4150adfc5217SJeff Kirsher {
4151adfc5217SJeff Kirsher 	u32 val;
4152adfc5217SJeff Kirsher 
4153e503e066SMichael Chan 	val = BNX2_RD(bp, BNX2_MISC_CFG);
4154e503e066SMichael Chan 	BNX2_WR(bp, BNX2_MISC_CFG, val | BNX2_MISC_CFG_NVM_WR_EN_PCI);
4155adfc5217SJeff Kirsher 
4156adfc5217SJeff Kirsher 	if (bp->flash_info->flags & BNX2_NV_WREN) {
4157adfc5217SJeff Kirsher 		int j;
4158adfc5217SJeff Kirsher 
4159e503e066SMichael Chan 		BNX2_WR(bp, BNX2_NVM_COMMAND, BNX2_NVM_COMMAND_DONE);
4160e503e066SMichael Chan 		BNX2_WR(bp, BNX2_NVM_COMMAND,
4161adfc5217SJeff Kirsher 			BNX2_NVM_COMMAND_WREN | BNX2_NVM_COMMAND_DOIT);
4162adfc5217SJeff Kirsher 
4163adfc5217SJeff Kirsher 		for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) {
4164adfc5217SJeff Kirsher 			udelay(5);
4165adfc5217SJeff Kirsher 
4166e503e066SMichael Chan 			val = BNX2_RD(bp, BNX2_NVM_COMMAND);
4167adfc5217SJeff Kirsher 			if (val & BNX2_NVM_COMMAND_DONE)
4168adfc5217SJeff Kirsher 				break;
4169adfc5217SJeff Kirsher 		}
4170adfc5217SJeff Kirsher 
4171adfc5217SJeff Kirsher 		if (j >= NVRAM_TIMEOUT_COUNT)
4172adfc5217SJeff Kirsher 			return -EBUSY;
4173adfc5217SJeff Kirsher 	}
4174adfc5217SJeff Kirsher 	return 0;
4175adfc5217SJeff Kirsher }
4176adfc5217SJeff Kirsher 
4177adfc5217SJeff Kirsher static void
4178adfc5217SJeff Kirsher bnx2_disable_nvram_write(struct bnx2 *bp)
4179adfc5217SJeff Kirsher {
4180adfc5217SJeff Kirsher 	u32 val;
4181adfc5217SJeff Kirsher 
4182e503e066SMichael Chan 	val = BNX2_RD(bp, BNX2_MISC_CFG);
4183e503e066SMichael Chan 	BNX2_WR(bp, BNX2_MISC_CFG, val & ~BNX2_MISC_CFG_NVM_WR_EN);
4184adfc5217SJeff Kirsher }
4185adfc5217SJeff Kirsher 
4186adfc5217SJeff Kirsher 
4187adfc5217SJeff Kirsher static void
4188adfc5217SJeff Kirsher bnx2_enable_nvram_access(struct bnx2 *bp)
4189adfc5217SJeff Kirsher {
4190adfc5217SJeff Kirsher 	u32 val;
4191adfc5217SJeff Kirsher 
4192e503e066SMichael Chan 	val = BNX2_RD(bp, BNX2_NVM_ACCESS_ENABLE);
4193adfc5217SJeff Kirsher 	/* Enable both bits, even on read. */
4194e503e066SMichael Chan 	BNX2_WR(bp, BNX2_NVM_ACCESS_ENABLE,
4195adfc5217SJeff Kirsher 		val | BNX2_NVM_ACCESS_ENABLE_EN | BNX2_NVM_ACCESS_ENABLE_WR_EN);
4196adfc5217SJeff Kirsher }
4197adfc5217SJeff Kirsher 
4198adfc5217SJeff Kirsher static void
4199adfc5217SJeff Kirsher bnx2_disable_nvram_access(struct bnx2 *bp)
4200adfc5217SJeff Kirsher {
4201adfc5217SJeff Kirsher 	u32 val;
4202adfc5217SJeff Kirsher 
4203e503e066SMichael Chan 	val = BNX2_RD(bp, BNX2_NVM_ACCESS_ENABLE);
4204adfc5217SJeff Kirsher 	/* Disable both bits, even after read. */
4205e503e066SMichael Chan 	BNX2_WR(bp, BNX2_NVM_ACCESS_ENABLE,
4206adfc5217SJeff Kirsher 		val & ~(BNX2_NVM_ACCESS_ENABLE_EN |
4207adfc5217SJeff Kirsher 			BNX2_NVM_ACCESS_ENABLE_WR_EN));
4208adfc5217SJeff Kirsher }
4209adfc5217SJeff Kirsher 
4210adfc5217SJeff Kirsher static int
4211adfc5217SJeff Kirsher bnx2_nvram_erase_page(struct bnx2 *bp, u32 offset)
4212adfc5217SJeff Kirsher {
4213adfc5217SJeff Kirsher 	u32 cmd;
4214adfc5217SJeff Kirsher 	int j;
4215adfc5217SJeff Kirsher 
4216adfc5217SJeff Kirsher 	if (bp->flash_info->flags & BNX2_NV_BUFFERED)
4217adfc5217SJeff Kirsher 		/* Buffered flash, no erase needed */
4218adfc5217SJeff Kirsher 		return 0;
4219adfc5217SJeff Kirsher 
4220adfc5217SJeff Kirsher 	/* Build an erase command */
4221adfc5217SJeff Kirsher 	cmd = BNX2_NVM_COMMAND_ERASE | BNX2_NVM_COMMAND_WR |
4222adfc5217SJeff Kirsher 	      BNX2_NVM_COMMAND_DOIT;
4223adfc5217SJeff Kirsher 
4224adfc5217SJeff Kirsher 	/* Need to clear DONE bit separately. */
4225e503e066SMichael Chan 	BNX2_WR(bp, BNX2_NVM_COMMAND, BNX2_NVM_COMMAND_DONE);
4226adfc5217SJeff Kirsher 
4227adfc5217SJeff Kirsher 	/* Address of the NVRAM to read from. */
4228e503e066SMichael Chan 	BNX2_WR(bp, BNX2_NVM_ADDR, offset & BNX2_NVM_ADDR_NVM_ADDR_VALUE);
4229adfc5217SJeff Kirsher 
4230adfc5217SJeff Kirsher 	/* Issue an erase command. */
4231e503e066SMichael Chan 	BNX2_WR(bp, BNX2_NVM_COMMAND, cmd);
4232adfc5217SJeff Kirsher 
4233adfc5217SJeff Kirsher 	/* Wait for completion. */
4234adfc5217SJeff Kirsher 	for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) {
4235adfc5217SJeff Kirsher 		u32 val;
4236adfc5217SJeff Kirsher 
4237adfc5217SJeff Kirsher 		udelay(5);
4238adfc5217SJeff Kirsher 
4239e503e066SMichael Chan 		val = BNX2_RD(bp, BNX2_NVM_COMMAND);
4240adfc5217SJeff Kirsher 		if (val & BNX2_NVM_COMMAND_DONE)
4241adfc5217SJeff Kirsher 			break;
4242adfc5217SJeff Kirsher 	}
4243adfc5217SJeff Kirsher 
4244adfc5217SJeff Kirsher 	if (j >= NVRAM_TIMEOUT_COUNT)
4245adfc5217SJeff Kirsher 		return -EBUSY;
4246adfc5217SJeff Kirsher 
4247adfc5217SJeff Kirsher 	return 0;
4248adfc5217SJeff Kirsher }
4249adfc5217SJeff Kirsher 
4250adfc5217SJeff Kirsher static int
4251adfc5217SJeff Kirsher bnx2_nvram_read_dword(struct bnx2 *bp, u32 offset, u8 *ret_val, u32 cmd_flags)
4252adfc5217SJeff Kirsher {
4253adfc5217SJeff Kirsher 	u32 cmd;
4254adfc5217SJeff Kirsher 	int j;
4255adfc5217SJeff Kirsher 
4256adfc5217SJeff Kirsher 	/* Build the command word. */
4257adfc5217SJeff Kirsher 	cmd = BNX2_NVM_COMMAND_DOIT | cmd_flags;
4258adfc5217SJeff Kirsher 
4259adfc5217SJeff Kirsher 	/* Calculate an offset of a buffered flash, not needed for 5709. */
4260adfc5217SJeff Kirsher 	if (bp->flash_info->flags & BNX2_NV_TRANSLATE) {
4261adfc5217SJeff Kirsher 		offset = ((offset / bp->flash_info->page_size) <<
4262adfc5217SJeff Kirsher 			   bp->flash_info->page_bits) +
4263adfc5217SJeff Kirsher 			  (offset % bp->flash_info->page_size);
4264adfc5217SJeff Kirsher 	}
4265adfc5217SJeff Kirsher 
4266adfc5217SJeff Kirsher 	/* Need to clear DONE bit separately. */
4267e503e066SMichael Chan 	BNX2_WR(bp, BNX2_NVM_COMMAND, BNX2_NVM_COMMAND_DONE);
4268adfc5217SJeff Kirsher 
4269adfc5217SJeff Kirsher 	/* Address of the NVRAM to read from. */
4270e503e066SMichael Chan 	BNX2_WR(bp, BNX2_NVM_ADDR, offset & BNX2_NVM_ADDR_NVM_ADDR_VALUE);
4271adfc5217SJeff Kirsher 
4272adfc5217SJeff Kirsher 	/* Issue a read command. */
4273e503e066SMichael Chan 	BNX2_WR(bp, BNX2_NVM_COMMAND, cmd);
4274adfc5217SJeff Kirsher 
4275adfc5217SJeff Kirsher 	/* Wait for completion. */
4276adfc5217SJeff Kirsher 	for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) {
4277adfc5217SJeff Kirsher 		u32 val;
4278adfc5217SJeff Kirsher 
4279adfc5217SJeff Kirsher 		udelay(5);
4280adfc5217SJeff Kirsher 
4281e503e066SMichael Chan 		val = BNX2_RD(bp, BNX2_NVM_COMMAND);
4282adfc5217SJeff Kirsher 		if (val & BNX2_NVM_COMMAND_DONE) {
4283e503e066SMichael Chan 			__be32 v = cpu_to_be32(BNX2_RD(bp, BNX2_NVM_READ));
4284adfc5217SJeff Kirsher 			memcpy(ret_val, &v, 4);
4285adfc5217SJeff Kirsher 			break;
4286adfc5217SJeff Kirsher 		}
4287adfc5217SJeff Kirsher 	}
4288adfc5217SJeff Kirsher 	if (j >= NVRAM_TIMEOUT_COUNT)
4289adfc5217SJeff Kirsher 		return -EBUSY;
4290adfc5217SJeff Kirsher 
4291adfc5217SJeff Kirsher 	return 0;
4292adfc5217SJeff Kirsher }
4293adfc5217SJeff Kirsher 
4294adfc5217SJeff Kirsher 
4295adfc5217SJeff Kirsher static int
4296adfc5217SJeff Kirsher bnx2_nvram_write_dword(struct bnx2 *bp, u32 offset, u8 *val, u32 cmd_flags)
4297adfc5217SJeff Kirsher {
4298adfc5217SJeff Kirsher 	u32 cmd;
4299adfc5217SJeff Kirsher 	__be32 val32;
4300adfc5217SJeff Kirsher 	int j;
4301adfc5217SJeff Kirsher 
4302adfc5217SJeff Kirsher 	/* Build the command word. */
4303adfc5217SJeff Kirsher 	cmd = BNX2_NVM_COMMAND_DOIT | BNX2_NVM_COMMAND_WR | cmd_flags;
4304adfc5217SJeff Kirsher 
4305adfc5217SJeff Kirsher 	/* Calculate an offset of a buffered flash, not needed for 5709. */
4306adfc5217SJeff Kirsher 	if (bp->flash_info->flags & BNX2_NV_TRANSLATE) {
4307adfc5217SJeff Kirsher 		offset = ((offset / bp->flash_info->page_size) <<
4308adfc5217SJeff Kirsher 			  bp->flash_info->page_bits) +
4309adfc5217SJeff Kirsher 			 (offset % bp->flash_info->page_size);
4310adfc5217SJeff Kirsher 	}
4311adfc5217SJeff Kirsher 
4312adfc5217SJeff Kirsher 	/* Need to clear DONE bit separately. */
4313e503e066SMichael Chan 	BNX2_WR(bp, BNX2_NVM_COMMAND, BNX2_NVM_COMMAND_DONE);
4314adfc5217SJeff Kirsher 
4315adfc5217SJeff Kirsher 	memcpy(&val32, val, 4);
4316adfc5217SJeff Kirsher 
4317adfc5217SJeff Kirsher 	/* Write the data. */
4318e503e066SMichael Chan 	BNX2_WR(bp, BNX2_NVM_WRITE, be32_to_cpu(val32));
4319adfc5217SJeff Kirsher 
4320adfc5217SJeff Kirsher 	/* Address of the NVRAM to write to. */
4321e503e066SMichael Chan 	BNX2_WR(bp, BNX2_NVM_ADDR, offset & BNX2_NVM_ADDR_NVM_ADDR_VALUE);
4322adfc5217SJeff Kirsher 
4323adfc5217SJeff Kirsher 	/* Issue the write command. */
4324e503e066SMichael Chan 	BNX2_WR(bp, BNX2_NVM_COMMAND, cmd);
4325adfc5217SJeff Kirsher 
4326adfc5217SJeff Kirsher 	/* Wait for completion. */
4327adfc5217SJeff Kirsher 	for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) {
4328adfc5217SJeff Kirsher 		udelay(5);
4329adfc5217SJeff Kirsher 
4330e503e066SMichael Chan 		if (BNX2_RD(bp, BNX2_NVM_COMMAND) & BNX2_NVM_COMMAND_DONE)
4331adfc5217SJeff Kirsher 			break;
4332adfc5217SJeff Kirsher 	}
4333adfc5217SJeff Kirsher 	if (j >= NVRAM_TIMEOUT_COUNT)
4334adfc5217SJeff Kirsher 		return -EBUSY;
4335adfc5217SJeff Kirsher 
4336adfc5217SJeff Kirsher 	return 0;
4337adfc5217SJeff Kirsher }
4338adfc5217SJeff Kirsher 
4339adfc5217SJeff Kirsher static int
4340adfc5217SJeff Kirsher bnx2_init_nvram(struct bnx2 *bp)
4341adfc5217SJeff Kirsher {
4342adfc5217SJeff Kirsher 	u32 val;
4343adfc5217SJeff Kirsher 	int j, entry_count, rc = 0;
4344adfc5217SJeff Kirsher 	const struct flash_spec *flash;
4345adfc5217SJeff Kirsher 
43464ce45e02SMichael Chan 	if (BNX2_CHIP(bp) == BNX2_CHIP_5709) {
4347adfc5217SJeff Kirsher 		bp->flash_info = &flash_5709;
4348adfc5217SJeff Kirsher 		goto get_flash_size;
4349adfc5217SJeff Kirsher 	}
4350adfc5217SJeff Kirsher 
4351adfc5217SJeff Kirsher 	/* Determine the selected interface. */
4352e503e066SMichael Chan 	val = BNX2_RD(bp, BNX2_NVM_CFG1);
4353adfc5217SJeff Kirsher 
4354adfc5217SJeff Kirsher 	entry_count = ARRAY_SIZE(flash_table);
4355adfc5217SJeff Kirsher 
4356adfc5217SJeff Kirsher 	if (val & 0x40000000) {
4357adfc5217SJeff Kirsher 
4358adfc5217SJeff Kirsher 		/* Flash interface has been reconfigured */
4359adfc5217SJeff Kirsher 		for (j = 0, flash = &flash_table[0]; j < entry_count;
4360adfc5217SJeff Kirsher 		     j++, flash++) {
4361adfc5217SJeff Kirsher 			if ((val & FLASH_BACKUP_STRAP_MASK) ==
4362adfc5217SJeff Kirsher 			    (flash->config1 & FLASH_BACKUP_STRAP_MASK)) {
4363adfc5217SJeff Kirsher 				bp->flash_info = flash;
4364adfc5217SJeff Kirsher 				break;
4365adfc5217SJeff Kirsher 			}
4366adfc5217SJeff Kirsher 		}
4367adfc5217SJeff Kirsher 	}
4368adfc5217SJeff Kirsher 	else {
4369adfc5217SJeff Kirsher 		u32 mask;
4370adfc5217SJeff Kirsher 		/* Not yet been reconfigured */
4371adfc5217SJeff Kirsher 
4372adfc5217SJeff Kirsher 		if (val & (1 << 23))
4373adfc5217SJeff Kirsher 			mask = FLASH_BACKUP_STRAP_MASK;
4374adfc5217SJeff Kirsher 		else
4375adfc5217SJeff Kirsher 			mask = FLASH_STRAP_MASK;
4376adfc5217SJeff Kirsher 
4377adfc5217SJeff Kirsher 		for (j = 0, flash = &flash_table[0]; j < entry_count;
4378adfc5217SJeff Kirsher 			j++, flash++) {
4379adfc5217SJeff Kirsher 
4380adfc5217SJeff Kirsher 			if ((val & mask) == (flash->strapping & mask)) {
4381adfc5217SJeff Kirsher 				bp->flash_info = flash;
4382adfc5217SJeff Kirsher 
4383adfc5217SJeff Kirsher 				/* Request access to the flash interface. */
4384adfc5217SJeff Kirsher 				if ((rc = bnx2_acquire_nvram_lock(bp)) != 0)
4385adfc5217SJeff Kirsher 					return rc;
4386adfc5217SJeff Kirsher 
4387adfc5217SJeff Kirsher 				/* Enable access to flash interface */
4388adfc5217SJeff Kirsher 				bnx2_enable_nvram_access(bp);
4389adfc5217SJeff Kirsher 
4390adfc5217SJeff Kirsher 				/* Reconfigure the flash interface */
4391e503e066SMichael Chan 				BNX2_WR(bp, BNX2_NVM_CFG1, flash->config1);
4392e503e066SMichael Chan 				BNX2_WR(bp, BNX2_NVM_CFG2, flash->config2);
4393e503e066SMichael Chan 				BNX2_WR(bp, BNX2_NVM_CFG3, flash->config3);
4394e503e066SMichael Chan 				BNX2_WR(bp, BNX2_NVM_WRITE1, flash->write1);
4395adfc5217SJeff Kirsher 
4396adfc5217SJeff Kirsher 				/* Disable access to flash interface */
4397adfc5217SJeff Kirsher 				bnx2_disable_nvram_access(bp);
4398adfc5217SJeff Kirsher 				bnx2_release_nvram_lock(bp);
4399adfc5217SJeff Kirsher 
4400adfc5217SJeff Kirsher 				break;
4401adfc5217SJeff Kirsher 			}
4402adfc5217SJeff Kirsher 		}
4403adfc5217SJeff Kirsher 	} /* if (val & 0x40000000) */
4404adfc5217SJeff Kirsher 
4405adfc5217SJeff Kirsher 	if (j == entry_count) {
4406adfc5217SJeff Kirsher 		bp->flash_info = NULL;
4407adfc5217SJeff Kirsher 		pr_alert("Unknown flash/EEPROM type\n");
4408adfc5217SJeff Kirsher 		return -ENODEV;
4409adfc5217SJeff Kirsher 	}
4410adfc5217SJeff Kirsher 
4411adfc5217SJeff Kirsher get_flash_size:
4412adfc5217SJeff Kirsher 	val = bnx2_shmem_rd(bp, BNX2_SHARED_HW_CFG_CONFIG2);
4413adfc5217SJeff Kirsher 	val &= BNX2_SHARED_HW_CFG2_NVM_SIZE_MASK;
4414adfc5217SJeff Kirsher 	if (val)
4415adfc5217SJeff Kirsher 		bp->flash_size = val;
4416adfc5217SJeff Kirsher 	else
4417adfc5217SJeff Kirsher 		bp->flash_size = bp->flash_info->total_size;
4418adfc5217SJeff Kirsher 
4419adfc5217SJeff Kirsher 	return rc;
4420adfc5217SJeff Kirsher }
4421adfc5217SJeff Kirsher 
4422adfc5217SJeff Kirsher static int
4423adfc5217SJeff Kirsher bnx2_nvram_read(struct bnx2 *bp, u32 offset, u8 *ret_buf,
4424adfc5217SJeff Kirsher 		int buf_size)
4425adfc5217SJeff Kirsher {
4426adfc5217SJeff Kirsher 	int rc = 0;
4427adfc5217SJeff Kirsher 	u32 cmd_flags, offset32, len32, extra;
4428adfc5217SJeff Kirsher 
4429adfc5217SJeff Kirsher 	if (buf_size == 0)
4430adfc5217SJeff Kirsher 		return 0;
4431adfc5217SJeff Kirsher 
4432adfc5217SJeff Kirsher 	/* Request access to the flash interface. */
4433adfc5217SJeff Kirsher 	if ((rc = bnx2_acquire_nvram_lock(bp)) != 0)
4434adfc5217SJeff Kirsher 		return rc;
4435adfc5217SJeff Kirsher 
4436adfc5217SJeff Kirsher 	/* Enable access to flash interface */
4437adfc5217SJeff Kirsher 	bnx2_enable_nvram_access(bp);
4438adfc5217SJeff Kirsher 
4439adfc5217SJeff Kirsher 	len32 = buf_size;
4440adfc5217SJeff Kirsher 	offset32 = offset;
4441adfc5217SJeff Kirsher 	extra = 0;
4442adfc5217SJeff Kirsher 
4443adfc5217SJeff Kirsher 	cmd_flags = 0;
4444adfc5217SJeff Kirsher 
4445adfc5217SJeff Kirsher 	if (offset32 & 3) {
4446adfc5217SJeff Kirsher 		u8 buf[4];
4447adfc5217SJeff Kirsher 		u32 pre_len;
4448adfc5217SJeff Kirsher 
4449adfc5217SJeff Kirsher 		offset32 &= ~3;
4450adfc5217SJeff Kirsher 		pre_len = 4 - (offset & 3);
4451adfc5217SJeff Kirsher 
4452adfc5217SJeff Kirsher 		if (pre_len >= len32) {
4453adfc5217SJeff Kirsher 			pre_len = len32;
4454adfc5217SJeff Kirsher 			cmd_flags = BNX2_NVM_COMMAND_FIRST |
4455adfc5217SJeff Kirsher 				    BNX2_NVM_COMMAND_LAST;
4456adfc5217SJeff Kirsher 		}
4457adfc5217SJeff Kirsher 		else {
4458adfc5217SJeff Kirsher 			cmd_flags = BNX2_NVM_COMMAND_FIRST;
4459adfc5217SJeff Kirsher 		}
4460adfc5217SJeff Kirsher 
4461adfc5217SJeff Kirsher 		rc = bnx2_nvram_read_dword(bp, offset32, buf, cmd_flags);
4462adfc5217SJeff Kirsher 
4463adfc5217SJeff Kirsher 		if (rc)
4464adfc5217SJeff Kirsher 			return rc;
4465adfc5217SJeff Kirsher 
4466adfc5217SJeff Kirsher 		memcpy(ret_buf, buf + (offset & 3), pre_len);
4467adfc5217SJeff Kirsher 
4468adfc5217SJeff Kirsher 		offset32 += 4;
4469adfc5217SJeff Kirsher 		ret_buf += pre_len;
4470adfc5217SJeff Kirsher 		len32 -= pre_len;
4471adfc5217SJeff Kirsher 	}
4472adfc5217SJeff Kirsher 	if (len32 & 3) {
4473adfc5217SJeff Kirsher 		extra = 4 - (len32 & 3);
4474adfc5217SJeff Kirsher 		len32 = (len32 + 4) & ~3;
4475adfc5217SJeff Kirsher 	}
4476adfc5217SJeff Kirsher 
4477adfc5217SJeff Kirsher 	if (len32 == 4) {
4478adfc5217SJeff Kirsher 		u8 buf[4];
4479adfc5217SJeff Kirsher 
4480adfc5217SJeff Kirsher 		if (cmd_flags)
4481adfc5217SJeff Kirsher 			cmd_flags = BNX2_NVM_COMMAND_LAST;
4482adfc5217SJeff Kirsher 		else
4483adfc5217SJeff Kirsher 			cmd_flags = BNX2_NVM_COMMAND_FIRST |
4484adfc5217SJeff Kirsher 				    BNX2_NVM_COMMAND_LAST;
4485adfc5217SJeff Kirsher 
4486adfc5217SJeff Kirsher 		rc = bnx2_nvram_read_dword(bp, offset32, buf, cmd_flags);
4487adfc5217SJeff Kirsher 
4488adfc5217SJeff Kirsher 		memcpy(ret_buf, buf, 4 - extra);
4489adfc5217SJeff Kirsher 	}
4490adfc5217SJeff Kirsher 	else if (len32 > 0) {
4491adfc5217SJeff Kirsher 		u8 buf[4];
4492adfc5217SJeff Kirsher 
4493adfc5217SJeff Kirsher 		/* Read the first word. */
4494adfc5217SJeff Kirsher 		if (cmd_flags)
4495adfc5217SJeff Kirsher 			cmd_flags = 0;
4496adfc5217SJeff Kirsher 		else
4497adfc5217SJeff Kirsher 			cmd_flags = BNX2_NVM_COMMAND_FIRST;
4498adfc5217SJeff Kirsher 
4499adfc5217SJeff Kirsher 		rc = bnx2_nvram_read_dword(bp, offset32, ret_buf, cmd_flags);
4500adfc5217SJeff Kirsher 
4501adfc5217SJeff Kirsher 		/* Advance to the next dword. */
4502adfc5217SJeff Kirsher 		offset32 += 4;
4503adfc5217SJeff Kirsher 		ret_buf += 4;
4504adfc5217SJeff Kirsher 		len32 -= 4;
4505adfc5217SJeff Kirsher 
4506adfc5217SJeff Kirsher 		while (len32 > 4 && rc == 0) {
4507adfc5217SJeff Kirsher 			rc = bnx2_nvram_read_dword(bp, offset32, ret_buf, 0);
4508adfc5217SJeff Kirsher 
4509adfc5217SJeff Kirsher 			/* Advance to the next dword. */
4510adfc5217SJeff Kirsher 			offset32 += 4;
4511adfc5217SJeff Kirsher 			ret_buf += 4;
4512adfc5217SJeff Kirsher 			len32 -= 4;
4513adfc5217SJeff Kirsher 		}
4514adfc5217SJeff Kirsher 
4515adfc5217SJeff Kirsher 		if (rc)
4516adfc5217SJeff Kirsher 			return rc;
4517adfc5217SJeff Kirsher 
4518adfc5217SJeff Kirsher 		cmd_flags = BNX2_NVM_COMMAND_LAST;
4519adfc5217SJeff Kirsher 		rc = bnx2_nvram_read_dword(bp, offset32, buf, cmd_flags);
4520adfc5217SJeff Kirsher 
4521adfc5217SJeff Kirsher 		memcpy(ret_buf, buf, 4 - extra);
4522adfc5217SJeff Kirsher 	}
4523adfc5217SJeff Kirsher 
4524adfc5217SJeff Kirsher 	/* Disable access to flash interface */
4525adfc5217SJeff Kirsher 	bnx2_disable_nvram_access(bp);
4526adfc5217SJeff Kirsher 
4527adfc5217SJeff Kirsher 	bnx2_release_nvram_lock(bp);
4528adfc5217SJeff Kirsher 
4529adfc5217SJeff Kirsher 	return rc;
4530adfc5217SJeff Kirsher }
4531adfc5217SJeff Kirsher 
4532adfc5217SJeff Kirsher static int
4533adfc5217SJeff Kirsher bnx2_nvram_write(struct bnx2 *bp, u32 offset, u8 *data_buf,
4534adfc5217SJeff Kirsher 		int buf_size)
4535adfc5217SJeff Kirsher {
4536adfc5217SJeff Kirsher 	u32 written, offset32, len32;
4537adfc5217SJeff Kirsher 	u8 *buf, start[4], end[4], *align_buf = NULL, *flash_buffer = NULL;
4538adfc5217SJeff Kirsher 	int rc = 0;
4539adfc5217SJeff Kirsher 	int align_start, align_end;
4540adfc5217SJeff Kirsher 
4541adfc5217SJeff Kirsher 	buf = data_buf;
4542adfc5217SJeff Kirsher 	offset32 = offset;
4543adfc5217SJeff Kirsher 	len32 = buf_size;
4544adfc5217SJeff Kirsher 	align_start = align_end = 0;
4545adfc5217SJeff Kirsher 
4546adfc5217SJeff Kirsher 	if ((align_start = (offset32 & 3))) {
4547adfc5217SJeff Kirsher 		offset32 &= ~3;
4548adfc5217SJeff Kirsher 		len32 += align_start;
4549adfc5217SJeff Kirsher 		if (len32 < 4)
4550adfc5217SJeff Kirsher 			len32 = 4;
4551adfc5217SJeff Kirsher 		if ((rc = bnx2_nvram_read(bp, offset32, start, 4)))
4552adfc5217SJeff Kirsher 			return rc;
4553adfc5217SJeff Kirsher 	}
4554adfc5217SJeff Kirsher 
4555adfc5217SJeff Kirsher 	if (len32 & 3) {
4556adfc5217SJeff Kirsher 		align_end = 4 - (len32 & 3);
4557adfc5217SJeff Kirsher 		len32 += align_end;
4558adfc5217SJeff Kirsher 		if ((rc = bnx2_nvram_read(bp, offset32 + len32 - 4, end, 4)))
4559adfc5217SJeff Kirsher 			return rc;
4560adfc5217SJeff Kirsher 	}
4561adfc5217SJeff Kirsher 
4562adfc5217SJeff Kirsher 	if (align_start || align_end) {
4563adfc5217SJeff Kirsher 		align_buf = kmalloc(len32, GFP_KERNEL);
4564b8aac410SVarsha Rao 		if (!align_buf)
4565adfc5217SJeff Kirsher 			return -ENOMEM;
4566adfc5217SJeff Kirsher 		if (align_start) {
4567adfc5217SJeff Kirsher 			memcpy(align_buf, start, 4);
4568adfc5217SJeff Kirsher 		}
4569adfc5217SJeff Kirsher 		if (align_end) {
4570adfc5217SJeff Kirsher 			memcpy(align_buf + len32 - 4, end, 4);
4571adfc5217SJeff Kirsher 		}
4572adfc5217SJeff Kirsher 		memcpy(align_buf + align_start, data_buf, buf_size);
4573adfc5217SJeff Kirsher 		buf = align_buf;
4574adfc5217SJeff Kirsher 	}
4575adfc5217SJeff Kirsher 
4576adfc5217SJeff Kirsher 	if (!(bp->flash_info->flags & BNX2_NV_BUFFERED)) {
4577adfc5217SJeff Kirsher 		flash_buffer = kmalloc(264, GFP_KERNEL);
4578b8aac410SVarsha Rao 		if (!flash_buffer) {
4579adfc5217SJeff Kirsher 			rc = -ENOMEM;
4580adfc5217SJeff Kirsher 			goto nvram_write_end;
4581adfc5217SJeff Kirsher 		}
4582adfc5217SJeff Kirsher 	}
4583adfc5217SJeff Kirsher 
4584adfc5217SJeff Kirsher 	written = 0;
4585adfc5217SJeff Kirsher 	while ((written < len32) && (rc == 0)) {
4586adfc5217SJeff Kirsher 		u32 page_start, page_end, data_start, data_end;
4587adfc5217SJeff Kirsher 		u32 addr, cmd_flags;
4588adfc5217SJeff Kirsher 		int i;
4589adfc5217SJeff Kirsher 
4590adfc5217SJeff Kirsher 	        /* Find the page_start addr */
4591adfc5217SJeff Kirsher 		page_start = offset32 + written;
4592adfc5217SJeff Kirsher 		page_start -= (page_start % bp->flash_info->page_size);
4593adfc5217SJeff Kirsher 		/* Find the page_end addr */
4594adfc5217SJeff Kirsher 		page_end = page_start + bp->flash_info->page_size;
4595adfc5217SJeff Kirsher 		/* Find the data_start addr */
4596adfc5217SJeff Kirsher 		data_start = (written == 0) ? offset32 : page_start;
4597adfc5217SJeff Kirsher 		/* Find the data_end addr */
4598adfc5217SJeff Kirsher 		data_end = (page_end > offset32 + len32) ?
4599adfc5217SJeff Kirsher 			(offset32 + len32) : page_end;
4600adfc5217SJeff Kirsher 
4601adfc5217SJeff Kirsher 		/* Request access to the flash interface. */
4602adfc5217SJeff Kirsher 		if ((rc = bnx2_acquire_nvram_lock(bp)) != 0)
4603adfc5217SJeff Kirsher 			goto nvram_write_end;
4604adfc5217SJeff Kirsher 
4605adfc5217SJeff Kirsher 		/* Enable access to flash interface */
4606adfc5217SJeff Kirsher 		bnx2_enable_nvram_access(bp);
4607adfc5217SJeff Kirsher 
4608adfc5217SJeff Kirsher 		cmd_flags = BNX2_NVM_COMMAND_FIRST;
4609adfc5217SJeff Kirsher 		if (!(bp->flash_info->flags & BNX2_NV_BUFFERED)) {
4610adfc5217SJeff Kirsher 			int j;
4611adfc5217SJeff Kirsher 
4612adfc5217SJeff Kirsher 			/* Read the whole page into the buffer
4613adfc5217SJeff Kirsher 			 * (non-buffer flash only) */
4614adfc5217SJeff Kirsher 			for (j = 0; j < bp->flash_info->page_size; j += 4) {
4615adfc5217SJeff Kirsher 				if (j == (bp->flash_info->page_size - 4)) {
4616adfc5217SJeff Kirsher 					cmd_flags |= BNX2_NVM_COMMAND_LAST;
4617adfc5217SJeff Kirsher 				}
4618adfc5217SJeff Kirsher 				rc = bnx2_nvram_read_dword(bp,
4619adfc5217SJeff Kirsher 					page_start + j,
4620adfc5217SJeff Kirsher 					&flash_buffer[j],
4621adfc5217SJeff Kirsher 					cmd_flags);
4622adfc5217SJeff Kirsher 
4623adfc5217SJeff Kirsher 				if (rc)
4624adfc5217SJeff Kirsher 					goto nvram_write_end;
4625adfc5217SJeff Kirsher 
4626adfc5217SJeff Kirsher 				cmd_flags = 0;
4627adfc5217SJeff Kirsher 			}
4628adfc5217SJeff Kirsher 		}
4629adfc5217SJeff Kirsher 
4630adfc5217SJeff Kirsher 		/* Enable writes to flash interface (unlock write-protect) */
4631adfc5217SJeff Kirsher 		if ((rc = bnx2_enable_nvram_write(bp)) != 0)
4632adfc5217SJeff Kirsher 			goto nvram_write_end;
4633adfc5217SJeff Kirsher 
4634adfc5217SJeff Kirsher 		/* Loop to write back the buffer data from page_start to
4635adfc5217SJeff Kirsher 		 * data_start */
4636adfc5217SJeff Kirsher 		i = 0;
4637adfc5217SJeff Kirsher 		if (!(bp->flash_info->flags & BNX2_NV_BUFFERED)) {
4638adfc5217SJeff Kirsher 			/* Erase the page */
4639adfc5217SJeff Kirsher 			if ((rc = bnx2_nvram_erase_page(bp, page_start)) != 0)
4640adfc5217SJeff Kirsher 				goto nvram_write_end;
4641adfc5217SJeff Kirsher 
4642adfc5217SJeff Kirsher 			/* Re-enable the write again for the actual write */
4643adfc5217SJeff Kirsher 			bnx2_enable_nvram_write(bp);
4644adfc5217SJeff Kirsher 
4645adfc5217SJeff Kirsher 			for (addr = page_start; addr < data_start;
4646adfc5217SJeff Kirsher 				addr += 4, i += 4) {
4647adfc5217SJeff Kirsher 
4648adfc5217SJeff Kirsher 				rc = bnx2_nvram_write_dword(bp, addr,
4649adfc5217SJeff Kirsher 					&flash_buffer[i], cmd_flags);
4650adfc5217SJeff Kirsher 
4651adfc5217SJeff Kirsher 				if (rc != 0)
4652adfc5217SJeff Kirsher 					goto nvram_write_end;
4653adfc5217SJeff Kirsher 
4654adfc5217SJeff Kirsher 				cmd_flags = 0;
4655adfc5217SJeff Kirsher 			}
4656adfc5217SJeff Kirsher 		}
4657adfc5217SJeff Kirsher 
4658adfc5217SJeff Kirsher 		/* Loop to write the new data from data_start to data_end */
4659adfc5217SJeff Kirsher 		for (addr = data_start; addr < data_end; addr += 4, i += 4) {
4660adfc5217SJeff Kirsher 			if ((addr == page_end - 4) ||
4661adfc5217SJeff Kirsher 				((bp->flash_info->flags & BNX2_NV_BUFFERED) &&
4662adfc5217SJeff Kirsher 				 (addr == data_end - 4))) {
4663adfc5217SJeff Kirsher 
4664adfc5217SJeff Kirsher 				cmd_flags |= BNX2_NVM_COMMAND_LAST;
4665adfc5217SJeff Kirsher 			}
4666adfc5217SJeff Kirsher 			rc = bnx2_nvram_write_dword(bp, addr, buf,
4667adfc5217SJeff Kirsher 				cmd_flags);
4668adfc5217SJeff Kirsher 
4669adfc5217SJeff Kirsher 			if (rc != 0)
4670adfc5217SJeff Kirsher 				goto nvram_write_end;
4671adfc5217SJeff Kirsher 
4672adfc5217SJeff Kirsher 			cmd_flags = 0;
4673adfc5217SJeff Kirsher 			buf += 4;
4674adfc5217SJeff Kirsher 		}
4675adfc5217SJeff Kirsher 
4676adfc5217SJeff Kirsher 		/* Loop to write back the buffer data from data_end
4677adfc5217SJeff Kirsher 		 * to page_end */
4678adfc5217SJeff Kirsher 		if (!(bp->flash_info->flags & BNX2_NV_BUFFERED)) {
4679adfc5217SJeff Kirsher 			for (addr = data_end; addr < page_end;
4680adfc5217SJeff Kirsher 				addr += 4, i += 4) {
4681adfc5217SJeff Kirsher 
4682adfc5217SJeff Kirsher 				if (addr == page_end-4) {
4683adfc5217SJeff Kirsher 					cmd_flags = BNX2_NVM_COMMAND_LAST;
4684adfc5217SJeff Kirsher                 		}
4685adfc5217SJeff Kirsher 				rc = bnx2_nvram_write_dword(bp, addr,
4686adfc5217SJeff Kirsher 					&flash_buffer[i], cmd_flags);
4687adfc5217SJeff Kirsher 
4688adfc5217SJeff Kirsher 				if (rc != 0)
4689adfc5217SJeff Kirsher 					goto nvram_write_end;
4690adfc5217SJeff Kirsher 
4691adfc5217SJeff Kirsher 				cmd_flags = 0;
4692adfc5217SJeff Kirsher 			}
4693adfc5217SJeff Kirsher 		}
4694adfc5217SJeff Kirsher 
4695adfc5217SJeff Kirsher 		/* Disable writes to flash interface (lock write-protect) */
4696adfc5217SJeff Kirsher 		bnx2_disable_nvram_write(bp);
4697adfc5217SJeff Kirsher 
4698adfc5217SJeff Kirsher 		/* Disable access to flash interface */
4699adfc5217SJeff Kirsher 		bnx2_disable_nvram_access(bp);
4700adfc5217SJeff Kirsher 		bnx2_release_nvram_lock(bp);
4701adfc5217SJeff Kirsher 
4702adfc5217SJeff Kirsher 		/* Increment written */
4703adfc5217SJeff Kirsher 		written += data_end - data_start;
4704adfc5217SJeff Kirsher 	}
4705adfc5217SJeff Kirsher 
4706adfc5217SJeff Kirsher nvram_write_end:
4707adfc5217SJeff Kirsher 	kfree(flash_buffer);
4708adfc5217SJeff Kirsher 	kfree(align_buf);
4709adfc5217SJeff Kirsher 	return rc;
4710adfc5217SJeff Kirsher }
4711adfc5217SJeff Kirsher 
4712adfc5217SJeff Kirsher static void
4713adfc5217SJeff Kirsher bnx2_init_fw_cap(struct bnx2 *bp)
4714adfc5217SJeff Kirsher {
4715adfc5217SJeff Kirsher 	u32 val, sig = 0;
4716adfc5217SJeff Kirsher 
4717adfc5217SJeff Kirsher 	bp->phy_flags &= ~BNX2_PHY_FLAG_REMOTE_PHY_CAP;
4718adfc5217SJeff Kirsher 	bp->flags &= ~BNX2_FLAG_CAN_KEEP_VLAN;
4719adfc5217SJeff Kirsher 
4720adfc5217SJeff Kirsher 	if (!(bp->flags & BNX2_FLAG_ASF_ENABLE))
4721adfc5217SJeff Kirsher 		bp->flags |= BNX2_FLAG_CAN_KEEP_VLAN;
4722adfc5217SJeff Kirsher 
4723adfc5217SJeff Kirsher 	val = bnx2_shmem_rd(bp, BNX2_FW_CAP_MB);
4724adfc5217SJeff Kirsher 	if ((val & BNX2_FW_CAP_SIGNATURE_MASK) != BNX2_FW_CAP_SIGNATURE)
4725adfc5217SJeff Kirsher 		return;
4726adfc5217SJeff Kirsher 
4727adfc5217SJeff Kirsher 	if ((val & BNX2_FW_CAP_CAN_KEEP_VLAN) == BNX2_FW_CAP_CAN_KEEP_VLAN) {
4728adfc5217SJeff Kirsher 		bp->flags |= BNX2_FLAG_CAN_KEEP_VLAN;
4729adfc5217SJeff Kirsher 		sig |= BNX2_DRV_ACK_CAP_SIGNATURE | BNX2_FW_CAP_CAN_KEEP_VLAN;
4730adfc5217SJeff Kirsher 	}
4731adfc5217SJeff Kirsher 
4732adfc5217SJeff Kirsher 	if ((bp->phy_flags & BNX2_PHY_FLAG_SERDES) &&
4733adfc5217SJeff Kirsher 	    (val & BNX2_FW_CAP_REMOTE_PHY_CAPABLE)) {
4734adfc5217SJeff Kirsher 		u32 link;
4735adfc5217SJeff Kirsher 
4736adfc5217SJeff Kirsher 		bp->phy_flags |= BNX2_PHY_FLAG_REMOTE_PHY_CAP;
4737adfc5217SJeff Kirsher 
4738adfc5217SJeff Kirsher 		link = bnx2_shmem_rd(bp, BNX2_LINK_STATUS);
4739adfc5217SJeff Kirsher 		if (link & BNX2_LINK_STATUS_SERDES_LINK)
4740adfc5217SJeff Kirsher 			bp->phy_port = PORT_FIBRE;
4741adfc5217SJeff Kirsher 		else
4742adfc5217SJeff Kirsher 			bp->phy_port = PORT_TP;
4743adfc5217SJeff Kirsher 
4744adfc5217SJeff Kirsher 		sig |= BNX2_DRV_ACK_CAP_SIGNATURE |
4745adfc5217SJeff Kirsher 		       BNX2_FW_CAP_REMOTE_PHY_CAPABLE;
4746adfc5217SJeff Kirsher 	}
4747adfc5217SJeff Kirsher 
4748adfc5217SJeff Kirsher 	if (netif_running(bp->dev) && sig)
4749adfc5217SJeff Kirsher 		bnx2_shmem_wr(bp, BNX2_DRV_ACK_CAP_MB, sig);
4750adfc5217SJeff Kirsher }
4751adfc5217SJeff Kirsher 
4752adfc5217SJeff Kirsher static void
4753adfc5217SJeff Kirsher bnx2_setup_msix_tbl(struct bnx2 *bp)
4754adfc5217SJeff Kirsher {
4755e503e066SMichael Chan 	BNX2_WR(bp, BNX2_PCI_GRC_WINDOW_ADDR, BNX2_PCI_GRC_WINDOW_ADDR_SEP_WIN);
4756adfc5217SJeff Kirsher 
4757e503e066SMichael Chan 	BNX2_WR(bp, BNX2_PCI_GRC_WINDOW2_ADDR, BNX2_MSIX_TABLE_ADDR);
4758e503e066SMichael Chan 	BNX2_WR(bp, BNX2_PCI_GRC_WINDOW3_ADDR, BNX2_MSIX_PBA_ADDR);
4759adfc5217SJeff Kirsher }
4760adfc5217SJeff Kirsher 
47616df77862SBaoquan He static void
47626df77862SBaoquan He bnx2_wait_dma_complete(struct bnx2 *bp)
4763adfc5217SJeff Kirsher {
4764adfc5217SJeff Kirsher 	u32 val;
47656df77862SBaoquan He 	int i;
4766adfc5217SJeff Kirsher 
47676df77862SBaoquan He 	/*
47686df77862SBaoquan He 	 * Wait for the current PCI transaction to complete before
47696df77862SBaoquan He 	 * issuing a reset.
47706df77862SBaoquan He 	 */
47714ce45e02SMichael Chan 	if ((BNX2_CHIP(bp) == BNX2_CHIP_5706) ||
47724ce45e02SMichael Chan 	    (BNX2_CHIP(bp) == BNX2_CHIP_5708)) {
4773e503e066SMichael Chan 		BNX2_WR(bp, BNX2_MISC_ENABLE_CLR_BITS,
4774adfc5217SJeff Kirsher 			BNX2_MISC_ENABLE_CLR_BITS_TX_DMA_ENABLE |
4775adfc5217SJeff Kirsher 			BNX2_MISC_ENABLE_CLR_BITS_DMA_ENGINE_ENABLE |
4776adfc5217SJeff Kirsher 			BNX2_MISC_ENABLE_CLR_BITS_RX_DMA_ENABLE |
4777adfc5217SJeff Kirsher 			BNX2_MISC_ENABLE_CLR_BITS_HOST_COALESCE_ENABLE);
4778e503e066SMichael Chan 		val = BNX2_RD(bp, BNX2_MISC_ENABLE_CLR_BITS);
4779adfc5217SJeff Kirsher 		udelay(5);
4780adfc5217SJeff Kirsher 	} else {  /* 5709 */
4781e503e066SMichael Chan 		val = BNX2_RD(bp, BNX2_MISC_NEW_CORE_CTL);
4782adfc5217SJeff Kirsher 		val &= ~BNX2_MISC_NEW_CORE_CTL_DMA_ENABLE;
4783e503e066SMichael Chan 		BNX2_WR(bp, BNX2_MISC_NEW_CORE_CTL, val);
4784e503e066SMichael Chan 		val = BNX2_RD(bp, BNX2_MISC_NEW_CORE_CTL);
4785adfc5217SJeff Kirsher 
4786adfc5217SJeff Kirsher 		for (i = 0; i < 100; i++) {
4787adfc5217SJeff Kirsher 			msleep(1);
4788e503e066SMichael Chan 			val = BNX2_RD(bp, BNX2_PCICFG_DEVICE_CONTROL);
4789adfc5217SJeff Kirsher 			if (!(val & BNX2_PCICFG_DEVICE_STATUS_NO_PEND))
4790adfc5217SJeff Kirsher 				break;
4791adfc5217SJeff Kirsher 		}
4792adfc5217SJeff Kirsher 	}
4793adfc5217SJeff Kirsher 
47946df77862SBaoquan He 	return;
47956df77862SBaoquan He }
47966df77862SBaoquan He 
47976df77862SBaoquan He 
47986df77862SBaoquan He static int
47996df77862SBaoquan He bnx2_reset_chip(struct bnx2 *bp, u32 reset_code)
48006df77862SBaoquan He {
48016df77862SBaoquan He 	u32 val;
48026df77862SBaoquan He 	int i, rc = 0;
48036df77862SBaoquan He 	u8 old_port;
48046df77862SBaoquan He 
48056df77862SBaoquan He 	/* Wait for the current PCI transaction to complete before
48066df77862SBaoquan He 	 * issuing a reset. */
48076df77862SBaoquan He 	bnx2_wait_dma_complete(bp);
48086df77862SBaoquan He 
4809adfc5217SJeff Kirsher 	/* Wait for the firmware to tell us it is ok to issue a reset. */
4810adfc5217SJeff Kirsher 	bnx2_fw_sync(bp, BNX2_DRV_MSG_DATA_WAIT0 | reset_code, 1, 1);
4811adfc5217SJeff Kirsher 
4812adfc5217SJeff Kirsher 	/* Deposit a driver reset signature so the firmware knows that
4813adfc5217SJeff Kirsher 	 * this is a soft reset. */
4814adfc5217SJeff Kirsher 	bnx2_shmem_wr(bp, BNX2_DRV_RESET_SIGNATURE,
4815adfc5217SJeff Kirsher 		      BNX2_DRV_RESET_SIGNATURE_MAGIC);
4816adfc5217SJeff Kirsher 
4817adfc5217SJeff Kirsher 	/* Do a dummy read to force the chip to complete all current transaction
4818adfc5217SJeff Kirsher 	 * before we issue a reset. */
4819e503e066SMichael Chan 	val = BNX2_RD(bp, BNX2_MISC_ID);
4820adfc5217SJeff Kirsher 
48214ce45e02SMichael Chan 	if (BNX2_CHIP(bp) == BNX2_CHIP_5709) {
4822e503e066SMichael Chan 		BNX2_WR(bp, BNX2_MISC_COMMAND, BNX2_MISC_COMMAND_SW_RESET);
4823e503e066SMichael Chan 		BNX2_RD(bp, BNX2_MISC_COMMAND);
4824adfc5217SJeff Kirsher 		udelay(5);
4825adfc5217SJeff Kirsher 
4826adfc5217SJeff Kirsher 		val = BNX2_PCICFG_MISC_CONFIG_REG_WINDOW_ENA |
4827adfc5217SJeff Kirsher 		      BNX2_PCICFG_MISC_CONFIG_TARGET_MB_WORD_SWAP;
4828adfc5217SJeff Kirsher 
4829e503e066SMichael Chan 		BNX2_WR(bp, BNX2_PCICFG_MISC_CONFIG, val);
4830adfc5217SJeff Kirsher 
4831adfc5217SJeff Kirsher 	} else {
4832adfc5217SJeff Kirsher 		val = BNX2_PCICFG_MISC_CONFIG_CORE_RST_REQ |
4833adfc5217SJeff Kirsher 		      BNX2_PCICFG_MISC_CONFIG_REG_WINDOW_ENA |
4834adfc5217SJeff Kirsher 		      BNX2_PCICFG_MISC_CONFIG_TARGET_MB_WORD_SWAP;
4835adfc5217SJeff Kirsher 
4836adfc5217SJeff Kirsher 		/* Chip reset. */
4837e503e066SMichael Chan 		BNX2_WR(bp, BNX2_PCICFG_MISC_CONFIG, val);
4838adfc5217SJeff Kirsher 
4839adfc5217SJeff Kirsher 		/* Reading back any register after chip reset will hang the
4840adfc5217SJeff Kirsher 		 * bus on 5706 A0 and A1.  The msleep below provides plenty
4841adfc5217SJeff Kirsher 		 * of margin for write posting.
4842adfc5217SJeff Kirsher 		 */
48434ce45e02SMichael Chan 		if ((BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5706_A0) ||
48444ce45e02SMichael Chan 		    (BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5706_A1))
4845adfc5217SJeff Kirsher 			msleep(20);
4846adfc5217SJeff Kirsher 
4847adfc5217SJeff Kirsher 		/* Reset takes approximate 30 usec */
4848adfc5217SJeff Kirsher 		for (i = 0; i < 10; i++) {
4849e503e066SMichael Chan 			val = BNX2_RD(bp, BNX2_PCICFG_MISC_CONFIG);
4850adfc5217SJeff Kirsher 			if ((val & (BNX2_PCICFG_MISC_CONFIG_CORE_RST_REQ |
4851adfc5217SJeff Kirsher 				    BNX2_PCICFG_MISC_CONFIG_CORE_RST_BSY)) == 0)
4852adfc5217SJeff Kirsher 				break;
4853adfc5217SJeff Kirsher 			udelay(10);
4854adfc5217SJeff Kirsher 		}
4855adfc5217SJeff Kirsher 
4856adfc5217SJeff Kirsher 		if (val & (BNX2_PCICFG_MISC_CONFIG_CORE_RST_REQ |
4857adfc5217SJeff Kirsher 			   BNX2_PCICFG_MISC_CONFIG_CORE_RST_BSY)) {
4858adfc5217SJeff Kirsher 			pr_err("Chip reset did not complete\n");
4859adfc5217SJeff Kirsher 			return -EBUSY;
4860adfc5217SJeff Kirsher 		}
4861adfc5217SJeff Kirsher 	}
4862adfc5217SJeff Kirsher 
4863adfc5217SJeff Kirsher 	/* Make sure byte swapping is properly configured. */
4864e503e066SMichael Chan 	val = BNX2_RD(bp, BNX2_PCI_SWAP_DIAG0);
4865adfc5217SJeff Kirsher 	if (val != 0x01020304) {
4866adfc5217SJeff Kirsher 		pr_err("Chip not in correct endian mode\n");
4867adfc5217SJeff Kirsher 		return -ENODEV;
4868adfc5217SJeff Kirsher 	}
4869adfc5217SJeff Kirsher 
4870adfc5217SJeff Kirsher 	/* Wait for the firmware to finish its initialization. */
4871adfc5217SJeff Kirsher 	rc = bnx2_fw_sync(bp, BNX2_DRV_MSG_DATA_WAIT1 | reset_code, 1, 0);
4872adfc5217SJeff Kirsher 	if (rc)
4873adfc5217SJeff Kirsher 		return rc;
4874adfc5217SJeff Kirsher 
4875adfc5217SJeff Kirsher 	spin_lock_bh(&bp->phy_lock);
4876adfc5217SJeff Kirsher 	old_port = bp->phy_port;
4877adfc5217SJeff Kirsher 	bnx2_init_fw_cap(bp);
4878adfc5217SJeff Kirsher 	if ((bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP) &&
4879adfc5217SJeff Kirsher 	    old_port != bp->phy_port)
4880adfc5217SJeff Kirsher 		bnx2_set_default_remote_link(bp);
4881adfc5217SJeff Kirsher 	spin_unlock_bh(&bp->phy_lock);
4882adfc5217SJeff Kirsher 
48834ce45e02SMichael Chan 	if (BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5706_A0) {
4884adfc5217SJeff Kirsher 		/* Adjust the voltage regular to two steps lower.  The default
4885adfc5217SJeff Kirsher 		 * of this register is 0x0000000e. */
4886e503e066SMichael Chan 		BNX2_WR(bp, BNX2_MISC_VREG_CONTROL, 0x000000fa);
4887adfc5217SJeff Kirsher 
4888adfc5217SJeff Kirsher 		/* Remove bad rbuf memory from the free pool. */
4889adfc5217SJeff Kirsher 		rc = bnx2_alloc_bad_rbuf(bp);
4890adfc5217SJeff Kirsher 	}
4891adfc5217SJeff Kirsher 
4892adfc5217SJeff Kirsher 	if (bp->flags & BNX2_FLAG_USING_MSIX) {
4893adfc5217SJeff Kirsher 		bnx2_setup_msix_tbl(bp);
4894adfc5217SJeff Kirsher 		/* Prevent MSIX table reads and write from timing out */
4895e503e066SMichael Chan 		BNX2_WR(bp, BNX2_MISC_ECO_HW_CTL,
4896adfc5217SJeff Kirsher 			BNX2_MISC_ECO_HW_CTL_LARGE_GRC_TMOUT_EN);
4897adfc5217SJeff Kirsher 	}
4898adfc5217SJeff Kirsher 
4899adfc5217SJeff Kirsher 	return rc;
4900adfc5217SJeff Kirsher }
4901adfc5217SJeff Kirsher 
4902adfc5217SJeff Kirsher static int
4903adfc5217SJeff Kirsher bnx2_init_chip(struct bnx2 *bp)
4904adfc5217SJeff Kirsher {
4905adfc5217SJeff Kirsher 	u32 val, mtu;
4906adfc5217SJeff Kirsher 	int rc, i;
4907adfc5217SJeff Kirsher 
4908adfc5217SJeff Kirsher 	/* Make sure the interrupt is not active. */
4909e503e066SMichael Chan 	BNX2_WR(bp, BNX2_PCICFG_INT_ACK_CMD, BNX2_PCICFG_INT_ACK_CMD_MASK_INT);
4910adfc5217SJeff Kirsher 
4911adfc5217SJeff Kirsher 	val = BNX2_DMA_CONFIG_DATA_BYTE_SWAP |
4912adfc5217SJeff Kirsher 	      BNX2_DMA_CONFIG_DATA_WORD_SWAP |
4913adfc5217SJeff Kirsher #ifdef __BIG_ENDIAN
4914adfc5217SJeff Kirsher 	      BNX2_DMA_CONFIG_CNTL_BYTE_SWAP |
4915adfc5217SJeff Kirsher #endif
4916adfc5217SJeff Kirsher 	      BNX2_DMA_CONFIG_CNTL_WORD_SWAP |
4917adfc5217SJeff Kirsher 	      DMA_READ_CHANS << 12 |
4918adfc5217SJeff Kirsher 	      DMA_WRITE_CHANS << 16;
4919adfc5217SJeff Kirsher 
4920adfc5217SJeff Kirsher 	val |= (0x2 << 20) | (1 << 11);
4921adfc5217SJeff Kirsher 
4922adfc5217SJeff Kirsher 	if ((bp->flags & BNX2_FLAG_PCIX) && (bp->bus_speed_mhz == 133))
4923adfc5217SJeff Kirsher 		val |= (1 << 23);
4924adfc5217SJeff Kirsher 
49254ce45e02SMichael Chan 	if ((BNX2_CHIP(bp) == BNX2_CHIP_5706) &&
49264ce45e02SMichael Chan 	    (BNX2_CHIP_ID(bp) != BNX2_CHIP_ID_5706_A0) &&
49274ce45e02SMichael Chan 	    !(bp->flags & BNX2_FLAG_PCIX))
4928adfc5217SJeff Kirsher 		val |= BNX2_DMA_CONFIG_CNTL_PING_PONG_DMA;
4929adfc5217SJeff Kirsher 
4930e503e066SMichael Chan 	BNX2_WR(bp, BNX2_DMA_CONFIG, val);
4931adfc5217SJeff Kirsher 
49324ce45e02SMichael Chan 	if (BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5706_A0) {
4933e503e066SMichael Chan 		val = BNX2_RD(bp, BNX2_TDMA_CONFIG);
4934adfc5217SJeff Kirsher 		val |= BNX2_TDMA_CONFIG_ONE_DMA;
4935e503e066SMichael Chan 		BNX2_WR(bp, BNX2_TDMA_CONFIG, val);
4936adfc5217SJeff Kirsher 	}
4937adfc5217SJeff Kirsher 
4938adfc5217SJeff Kirsher 	if (bp->flags & BNX2_FLAG_PCIX) {
4939adfc5217SJeff Kirsher 		u16 val16;
4940adfc5217SJeff Kirsher 
4941adfc5217SJeff Kirsher 		pci_read_config_word(bp->pdev, bp->pcix_cap + PCI_X_CMD,
4942adfc5217SJeff Kirsher 				     &val16);
4943adfc5217SJeff Kirsher 		pci_write_config_word(bp->pdev, bp->pcix_cap + PCI_X_CMD,
4944adfc5217SJeff Kirsher 				      val16 & ~PCI_X_CMD_ERO);
4945adfc5217SJeff Kirsher 	}
4946adfc5217SJeff Kirsher 
4947e503e066SMichael Chan 	BNX2_WR(bp, BNX2_MISC_ENABLE_SET_BITS,
4948adfc5217SJeff Kirsher 		BNX2_MISC_ENABLE_SET_BITS_HOST_COALESCE_ENABLE |
4949adfc5217SJeff Kirsher 		BNX2_MISC_ENABLE_STATUS_BITS_RX_V2P_ENABLE |
4950adfc5217SJeff Kirsher 		BNX2_MISC_ENABLE_STATUS_BITS_CONTEXT_ENABLE);
4951adfc5217SJeff Kirsher 
4952adfc5217SJeff Kirsher 	/* Initialize context mapping and zero out the quick contexts.  The
4953adfc5217SJeff Kirsher 	 * context block must have already been enabled. */
49544ce45e02SMichael Chan 	if (BNX2_CHIP(bp) == BNX2_CHIP_5709) {
4955adfc5217SJeff Kirsher 		rc = bnx2_init_5709_context(bp);
4956adfc5217SJeff Kirsher 		if (rc)
4957adfc5217SJeff Kirsher 			return rc;
4958adfc5217SJeff Kirsher 	} else
4959adfc5217SJeff Kirsher 		bnx2_init_context(bp);
4960adfc5217SJeff Kirsher 
4961adfc5217SJeff Kirsher 	if ((rc = bnx2_init_cpus(bp)) != 0)
4962adfc5217SJeff Kirsher 		return rc;
4963adfc5217SJeff Kirsher 
4964adfc5217SJeff Kirsher 	bnx2_init_nvram(bp);
4965adfc5217SJeff Kirsher 
4966adfc5217SJeff Kirsher 	bnx2_set_mac_addr(bp, bp->dev->dev_addr, 0);
4967adfc5217SJeff Kirsher 
4968e503e066SMichael Chan 	val = BNX2_RD(bp, BNX2_MQ_CONFIG);
4969adfc5217SJeff Kirsher 	val &= ~BNX2_MQ_CONFIG_KNL_BYP_BLK_SIZE;
4970adfc5217SJeff Kirsher 	val |= BNX2_MQ_CONFIG_KNL_BYP_BLK_SIZE_256;
49714ce45e02SMichael Chan 	if (BNX2_CHIP(bp) == BNX2_CHIP_5709) {
4972adfc5217SJeff Kirsher 		val |= BNX2_MQ_CONFIG_BIN_MQ_MODE;
49734ce45e02SMichael Chan 		if (BNX2_CHIP_REV(bp) == BNX2_CHIP_REV_Ax)
4974adfc5217SJeff Kirsher 			val |= BNX2_MQ_CONFIG_HALT_DIS;
4975adfc5217SJeff Kirsher 	}
4976adfc5217SJeff Kirsher 
4977e503e066SMichael Chan 	BNX2_WR(bp, BNX2_MQ_CONFIG, val);
4978adfc5217SJeff Kirsher 
4979adfc5217SJeff Kirsher 	val = 0x10000 + (MAX_CID_CNT * MB_KERNEL_CTX_SIZE);
4980e503e066SMichael Chan 	BNX2_WR(bp, BNX2_MQ_KNL_BYP_WIND_START, val);
4981e503e066SMichael Chan 	BNX2_WR(bp, BNX2_MQ_KNL_WIND_END, val);
4982adfc5217SJeff Kirsher 
49832bc4078eSMichael Chan 	val = (BNX2_PAGE_BITS - 8) << 24;
4984e503e066SMichael Chan 	BNX2_WR(bp, BNX2_RV2P_CONFIG, val);
4985adfc5217SJeff Kirsher 
4986adfc5217SJeff Kirsher 	/* Configure page size. */
4987e503e066SMichael Chan 	val = BNX2_RD(bp, BNX2_TBDR_CONFIG);
4988adfc5217SJeff Kirsher 	val &= ~BNX2_TBDR_CONFIG_PAGE_SIZE;
49892bc4078eSMichael Chan 	val |= (BNX2_PAGE_BITS - 8) << 24 | 0x40;
4990e503e066SMichael Chan 	BNX2_WR(bp, BNX2_TBDR_CONFIG, val);
4991adfc5217SJeff Kirsher 
4992adfc5217SJeff Kirsher 	val = bp->mac_addr[0] +
4993adfc5217SJeff Kirsher 	      (bp->mac_addr[1] << 8) +
4994adfc5217SJeff Kirsher 	      (bp->mac_addr[2] << 16) +
4995adfc5217SJeff Kirsher 	      bp->mac_addr[3] +
4996adfc5217SJeff Kirsher 	      (bp->mac_addr[4] << 8) +
4997adfc5217SJeff Kirsher 	      (bp->mac_addr[5] << 16);
4998e503e066SMichael Chan 	BNX2_WR(bp, BNX2_EMAC_BACKOFF_SEED, val);
4999adfc5217SJeff Kirsher 
5000adfc5217SJeff Kirsher 	/* Program the MTU.  Also include 4 bytes for CRC32. */
5001adfc5217SJeff Kirsher 	mtu = bp->dev->mtu;
5002adfc5217SJeff Kirsher 	val = mtu + ETH_HLEN + ETH_FCS_LEN;
5003e1c6dccaSJarod Wilson 	if (val > (MAX_ETHERNET_PACKET_SIZE + ETH_HLEN + 4))
5004adfc5217SJeff Kirsher 		val |= BNX2_EMAC_RX_MTU_SIZE_JUMBO_ENA;
5005e503e066SMichael Chan 	BNX2_WR(bp, BNX2_EMAC_RX_MTU_SIZE, val);
5006adfc5217SJeff Kirsher 
5007e1c6dccaSJarod Wilson 	if (mtu < ETH_DATA_LEN)
5008e1c6dccaSJarod Wilson 		mtu = ETH_DATA_LEN;
5009adfc5217SJeff Kirsher 
5010adfc5217SJeff Kirsher 	bnx2_reg_wr_ind(bp, BNX2_RBUF_CONFIG, BNX2_RBUF_CONFIG_VAL(mtu));
5011adfc5217SJeff Kirsher 	bnx2_reg_wr_ind(bp, BNX2_RBUF_CONFIG2, BNX2_RBUF_CONFIG2_VAL(mtu));
5012adfc5217SJeff Kirsher 	bnx2_reg_wr_ind(bp, BNX2_RBUF_CONFIG3, BNX2_RBUF_CONFIG3_VAL(mtu));
5013adfc5217SJeff Kirsher 
5014adfc5217SJeff Kirsher 	memset(bp->bnx2_napi[0].status_blk.msi, 0, bp->status_stats_size);
5015adfc5217SJeff Kirsher 	for (i = 0; i < BNX2_MAX_MSIX_VEC; i++)
5016adfc5217SJeff Kirsher 		bp->bnx2_napi[i].last_status_idx = 0;
5017adfc5217SJeff Kirsher 
5018adfc5217SJeff Kirsher 	bp->idle_chk_status_idx = 0xffff;
5019adfc5217SJeff Kirsher 
5020adfc5217SJeff Kirsher 	/* Set up how to generate a link change interrupt. */
5021e503e066SMichael Chan 	BNX2_WR(bp, BNX2_EMAC_ATTENTION_ENA, BNX2_EMAC_ATTENTION_ENA_LINK);
5022adfc5217SJeff Kirsher 
5023e503e066SMichael Chan 	BNX2_WR(bp, BNX2_HC_STATUS_ADDR_L,
5024adfc5217SJeff Kirsher 		(u64) bp->status_blk_mapping & 0xffffffff);
5025e503e066SMichael Chan 	BNX2_WR(bp, BNX2_HC_STATUS_ADDR_H, (u64) bp->status_blk_mapping >> 32);
5026adfc5217SJeff Kirsher 
5027e503e066SMichael Chan 	BNX2_WR(bp, BNX2_HC_STATISTICS_ADDR_L,
5028adfc5217SJeff Kirsher 		(u64) bp->stats_blk_mapping & 0xffffffff);
5029e503e066SMichael Chan 	BNX2_WR(bp, BNX2_HC_STATISTICS_ADDR_H,
5030adfc5217SJeff Kirsher 		(u64) bp->stats_blk_mapping >> 32);
5031adfc5217SJeff Kirsher 
5032e503e066SMichael Chan 	BNX2_WR(bp, BNX2_HC_TX_QUICK_CONS_TRIP,
5033adfc5217SJeff Kirsher 		(bp->tx_quick_cons_trip_int << 16) | bp->tx_quick_cons_trip);
5034adfc5217SJeff Kirsher 
5035e503e066SMichael Chan 	BNX2_WR(bp, BNX2_HC_RX_QUICK_CONS_TRIP,
5036adfc5217SJeff Kirsher 		(bp->rx_quick_cons_trip_int << 16) | bp->rx_quick_cons_trip);
5037adfc5217SJeff Kirsher 
5038e503e066SMichael Chan 	BNX2_WR(bp, BNX2_HC_COMP_PROD_TRIP,
5039adfc5217SJeff Kirsher 		(bp->comp_prod_trip_int << 16) | bp->comp_prod_trip);
5040adfc5217SJeff Kirsher 
5041e503e066SMichael Chan 	BNX2_WR(bp, BNX2_HC_TX_TICKS, (bp->tx_ticks_int << 16) | bp->tx_ticks);
5042adfc5217SJeff Kirsher 
5043e503e066SMichael Chan 	BNX2_WR(bp, BNX2_HC_RX_TICKS, (bp->rx_ticks_int << 16) | bp->rx_ticks);
5044adfc5217SJeff Kirsher 
5045e503e066SMichael Chan 	BNX2_WR(bp, BNX2_HC_COM_TICKS,
5046adfc5217SJeff Kirsher 		(bp->com_ticks_int << 16) | bp->com_ticks);
5047adfc5217SJeff Kirsher 
5048e503e066SMichael Chan 	BNX2_WR(bp, BNX2_HC_CMD_TICKS,
5049adfc5217SJeff Kirsher 		(bp->cmd_ticks_int << 16) | bp->cmd_ticks);
5050adfc5217SJeff Kirsher 
5051adfc5217SJeff Kirsher 	if (bp->flags & BNX2_FLAG_BROKEN_STATS)
5052e503e066SMichael Chan 		BNX2_WR(bp, BNX2_HC_STATS_TICKS, 0);
5053adfc5217SJeff Kirsher 	else
5054e503e066SMichael Chan 		BNX2_WR(bp, BNX2_HC_STATS_TICKS, bp->stats_ticks);
5055e503e066SMichael Chan 	BNX2_WR(bp, BNX2_HC_STAT_COLLECT_TICKS, 0xbb8);  /* 3ms */
5056adfc5217SJeff Kirsher 
50574ce45e02SMichael Chan 	if (BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5706_A1)
5058adfc5217SJeff Kirsher 		val = BNX2_HC_CONFIG_COLLECT_STATS;
5059adfc5217SJeff Kirsher 	else {
5060adfc5217SJeff Kirsher 		val = BNX2_HC_CONFIG_RX_TMR_MODE | BNX2_HC_CONFIG_TX_TMR_MODE |
5061adfc5217SJeff Kirsher 		      BNX2_HC_CONFIG_COLLECT_STATS;
5062adfc5217SJeff Kirsher 	}
5063adfc5217SJeff Kirsher 
5064adfc5217SJeff Kirsher 	if (bp->flags & BNX2_FLAG_USING_MSIX) {
5065e503e066SMichael Chan 		BNX2_WR(bp, BNX2_HC_MSIX_BIT_VECTOR,
5066adfc5217SJeff Kirsher 			BNX2_HC_MSIX_BIT_VECTOR_VAL);
5067adfc5217SJeff Kirsher 
5068adfc5217SJeff Kirsher 		val |= BNX2_HC_CONFIG_SB_ADDR_INC_128B;
5069adfc5217SJeff Kirsher 	}
5070adfc5217SJeff Kirsher 
5071adfc5217SJeff Kirsher 	if (bp->flags & BNX2_FLAG_ONE_SHOT_MSI)
5072adfc5217SJeff Kirsher 		val |= BNX2_HC_CONFIG_ONE_SHOT | BNX2_HC_CONFIG_USE_INT_PARAM;
5073adfc5217SJeff Kirsher 
5074e503e066SMichael Chan 	BNX2_WR(bp, BNX2_HC_CONFIG, val);
5075adfc5217SJeff Kirsher 
5076adfc5217SJeff Kirsher 	if (bp->rx_ticks < 25)
5077adfc5217SJeff Kirsher 		bnx2_reg_wr_ind(bp, BNX2_FW_RX_LOW_LATENCY, 1);
5078adfc5217SJeff Kirsher 	else
5079adfc5217SJeff Kirsher 		bnx2_reg_wr_ind(bp, BNX2_FW_RX_LOW_LATENCY, 0);
5080adfc5217SJeff Kirsher 
5081adfc5217SJeff Kirsher 	for (i = 1; i < bp->irq_nvecs; i++) {
5082adfc5217SJeff Kirsher 		u32 base = ((i - 1) * BNX2_HC_SB_CONFIG_SIZE) +
5083adfc5217SJeff Kirsher 			   BNX2_HC_SB_CONFIG_1;
5084adfc5217SJeff Kirsher 
5085e503e066SMichael Chan 		BNX2_WR(bp, base,
5086adfc5217SJeff Kirsher 			BNX2_HC_SB_CONFIG_1_TX_TMR_MODE |
5087adfc5217SJeff Kirsher 			BNX2_HC_SB_CONFIG_1_RX_TMR_MODE |
5088adfc5217SJeff Kirsher 			BNX2_HC_SB_CONFIG_1_ONE_SHOT);
5089adfc5217SJeff Kirsher 
5090e503e066SMichael Chan 		BNX2_WR(bp, base + BNX2_HC_TX_QUICK_CONS_TRIP_OFF,
5091adfc5217SJeff Kirsher 			(bp->tx_quick_cons_trip_int << 16) |
5092adfc5217SJeff Kirsher 			 bp->tx_quick_cons_trip);
5093adfc5217SJeff Kirsher 
5094e503e066SMichael Chan 		BNX2_WR(bp, base + BNX2_HC_TX_TICKS_OFF,
5095adfc5217SJeff Kirsher 			(bp->tx_ticks_int << 16) | bp->tx_ticks);
5096adfc5217SJeff Kirsher 
5097e503e066SMichael Chan 		BNX2_WR(bp, base + BNX2_HC_RX_QUICK_CONS_TRIP_OFF,
5098adfc5217SJeff Kirsher 			(bp->rx_quick_cons_trip_int << 16) |
5099adfc5217SJeff Kirsher 			bp->rx_quick_cons_trip);
5100adfc5217SJeff Kirsher 
5101e503e066SMichael Chan 		BNX2_WR(bp, base + BNX2_HC_RX_TICKS_OFF,
5102adfc5217SJeff Kirsher 			(bp->rx_ticks_int << 16) | bp->rx_ticks);
5103adfc5217SJeff Kirsher 	}
5104adfc5217SJeff Kirsher 
5105adfc5217SJeff Kirsher 	/* Clear internal stats counters. */
5106e503e066SMichael Chan 	BNX2_WR(bp, BNX2_HC_COMMAND, BNX2_HC_COMMAND_CLR_STAT_NOW);
5107adfc5217SJeff Kirsher 
5108e503e066SMichael Chan 	BNX2_WR(bp, BNX2_HC_ATTN_BITS_ENABLE, STATUS_ATTN_EVENTS);
5109adfc5217SJeff Kirsher 
5110adfc5217SJeff Kirsher 	/* Initialize the receive filter. */
5111adfc5217SJeff Kirsher 	bnx2_set_rx_mode(bp->dev);
5112adfc5217SJeff Kirsher 
51134ce45e02SMichael Chan 	if (BNX2_CHIP(bp) == BNX2_CHIP_5709) {
5114e503e066SMichael Chan 		val = BNX2_RD(bp, BNX2_MISC_NEW_CORE_CTL);
5115adfc5217SJeff Kirsher 		val |= BNX2_MISC_NEW_CORE_CTL_DMA_ENABLE;
5116e503e066SMichael Chan 		BNX2_WR(bp, BNX2_MISC_NEW_CORE_CTL, val);
5117adfc5217SJeff Kirsher 	}
5118adfc5217SJeff Kirsher 	rc = bnx2_fw_sync(bp, BNX2_DRV_MSG_DATA_WAIT2 | BNX2_DRV_MSG_CODE_RESET,
5119adfc5217SJeff Kirsher 			  1, 0);
5120adfc5217SJeff Kirsher 
5121e503e066SMichael Chan 	BNX2_WR(bp, BNX2_MISC_ENABLE_SET_BITS, BNX2_MISC_ENABLE_DEFAULT);
5122e503e066SMichael Chan 	BNX2_RD(bp, BNX2_MISC_ENABLE_SET_BITS);
5123adfc5217SJeff Kirsher 
5124adfc5217SJeff Kirsher 	udelay(20);
5125adfc5217SJeff Kirsher 
5126e503e066SMichael Chan 	bp->hc_cmd = BNX2_RD(bp, BNX2_HC_COMMAND);
5127adfc5217SJeff Kirsher 
5128adfc5217SJeff Kirsher 	return rc;
5129adfc5217SJeff Kirsher }
5130adfc5217SJeff Kirsher 
5131adfc5217SJeff Kirsher static void
5132adfc5217SJeff Kirsher bnx2_clear_ring_states(struct bnx2 *bp)
5133adfc5217SJeff Kirsher {
5134adfc5217SJeff Kirsher 	struct bnx2_napi *bnapi;
5135adfc5217SJeff Kirsher 	struct bnx2_tx_ring_info *txr;
5136adfc5217SJeff Kirsher 	struct bnx2_rx_ring_info *rxr;
5137adfc5217SJeff Kirsher 	int i;
5138adfc5217SJeff Kirsher 
5139adfc5217SJeff Kirsher 	for (i = 0; i < BNX2_MAX_MSIX_VEC; i++) {
5140adfc5217SJeff Kirsher 		bnapi = &bp->bnx2_napi[i];
5141adfc5217SJeff Kirsher 		txr = &bnapi->tx_ring;
5142adfc5217SJeff Kirsher 		rxr = &bnapi->rx_ring;
5143adfc5217SJeff Kirsher 
5144adfc5217SJeff Kirsher 		txr->tx_cons = 0;
5145adfc5217SJeff Kirsher 		txr->hw_tx_cons = 0;
5146adfc5217SJeff Kirsher 		rxr->rx_prod_bseq = 0;
5147adfc5217SJeff Kirsher 		rxr->rx_prod = 0;
5148adfc5217SJeff Kirsher 		rxr->rx_cons = 0;
5149adfc5217SJeff Kirsher 		rxr->rx_pg_prod = 0;
5150adfc5217SJeff Kirsher 		rxr->rx_pg_cons = 0;
5151adfc5217SJeff Kirsher 	}
5152adfc5217SJeff Kirsher }
5153adfc5217SJeff Kirsher 
5154adfc5217SJeff Kirsher static void
5155adfc5217SJeff Kirsher bnx2_init_tx_context(struct bnx2 *bp, u32 cid, struct bnx2_tx_ring_info *txr)
5156adfc5217SJeff Kirsher {
5157adfc5217SJeff Kirsher 	u32 val, offset0, offset1, offset2, offset3;
5158adfc5217SJeff Kirsher 	u32 cid_addr = GET_CID_ADDR(cid);
5159adfc5217SJeff Kirsher 
51604ce45e02SMichael Chan 	if (BNX2_CHIP(bp) == BNX2_CHIP_5709) {
5161adfc5217SJeff Kirsher 		offset0 = BNX2_L2CTX_TYPE_XI;
5162adfc5217SJeff Kirsher 		offset1 = BNX2_L2CTX_CMD_TYPE_XI;
5163adfc5217SJeff Kirsher 		offset2 = BNX2_L2CTX_TBDR_BHADDR_HI_XI;
5164adfc5217SJeff Kirsher 		offset3 = BNX2_L2CTX_TBDR_BHADDR_LO_XI;
5165adfc5217SJeff Kirsher 	} else {
5166adfc5217SJeff Kirsher 		offset0 = BNX2_L2CTX_TYPE;
5167adfc5217SJeff Kirsher 		offset1 = BNX2_L2CTX_CMD_TYPE;
5168adfc5217SJeff Kirsher 		offset2 = BNX2_L2CTX_TBDR_BHADDR_HI;
5169adfc5217SJeff Kirsher 		offset3 = BNX2_L2CTX_TBDR_BHADDR_LO;
5170adfc5217SJeff Kirsher 	}
5171adfc5217SJeff Kirsher 	val = BNX2_L2CTX_TYPE_TYPE_L2 | BNX2_L2CTX_TYPE_SIZE_L2;
5172adfc5217SJeff Kirsher 	bnx2_ctx_wr(bp, cid_addr, offset0, val);
5173adfc5217SJeff Kirsher 
5174adfc5217SJeff Kirsher 	val = BNX2_L2CTX_CMD_TYPE_TYPE_L2 | (8 << 16);
5175adfc5217SJeff Kirsher 	bnx2_ctx_wr(bp, cid_addr, offset1, val);
5176adfc5217SJeff Kirsher 
5177adfc5217SJeff Kirsher 	val = (u64) txr->tx_desc_mapping >> 32;
5178adfc5217SJeff Kirsher 	bnx2_ctx_wr(bp, cid_addr, offset2, val);
5179adfc5217SJeff Kirsher 
5180adfc5217SJeff Kirsher 	val = (u64) txr->tx_desc_mapping & 0xffffffff;
5181adfc5217SJeff Kirsher 	bnx2_ctx_wr(bp, cid_addr, offset3, val);
5182adfc5217SJeff Kirsher }
5183adfc5217SJeff Kirsher 
5184adfc5217SJeff Kirsher static void
5185adfc5217SJeff Kirsher bnx2_init_tx_ring(struct bnx2 *bp, int ring_num)
5186adfc5217SJeff Kirsher {
51872bc4078eSMichael Chan 	struct bnx2_tx_bd *txbd;
5188adfc5217SJeff Kirsher 	u32 cid = TX_CID;
5189adfc5217SJeff Kirsher 	struct bnx2_napi *bnapi;
5190adfc5217SJeff Kirsher 	struct bnx2_tx_ring_info *txr;
5191adfc5217SJeff Kirsher 
5192adfc5217SJeff Kirsher 	bnapi = &bp->bnx2_napi[ring_num];
5193adfc5217SJeff Kirsher 	txr = &bnapi->tx_ring;
5194adfc5217SJeff Kirsher 
5195adfc5217SJeff Kirsher 	if (ring_num == 0)
5196adfc5217SJeff Kirsher 		cid = TX_CID;
5197adfc5217SJeff Kirsher 	else
5198adfc5217SJeff Kirsher 		cid = TX_TSS_CID + ring_num - 1;
5199adfc5217SJeff Kirsher 
5200adfc5217SJeff Kirsher 	bp->tx_wake_thresh = bp->tx_ring_size / 2;
5201adfc5217SJeff Kirsher 
52022bc4078eSMichael Chan 	txbd = &txr->tx_desc_ring[BNX2_MAX_TX_DESC_CNT];
5203adfc5217SJeff Kirsher 
5204adfc5217SJeff Kirsher 	txbd->tx_bd_haddr_hi = (u64) txr->tx_desc_mapping >> 32;
5205adfc5217SJeff Kirsher 	txbd->tx_bd_haddr_lo = (u64) txr->tx_desc_mapping & 0xffffffff;
5206adfc5217SJeff Kirsher 
5207adfc5217SJeff Kirsher 	txr->tx_prod = 0;
5208adfc5217SJeff Kirsher 	txr->tx_prod_bseq = 0;
5209adfc5217SJeff Kirsher 
5210adfc5217SJeff Kirsher 	txr->tx_bidx_addr = MB_GET_CID_ADDR(cid) + BNX2_L2CTX_TX_HOST_BIDX;
5211adfc5217SJeff Kirsher 	txr->tx_bseq_addr = MB_GET_CID_ADDR(cid) + BNX2_L2CTX_TX_HOST_BSEQ;
5212adfc5217SJeff Kirsher 
5213adfc5217SJeff Kirsher 	bnx2_init_tx_context(bp, cid, txr);
5214adfc5217SJeff Kirsher }
5215adfc5217SJeff Kirsher 
5216adfc5217SJeff Kirsher static void
52172bc4078eSMichael Chan bnx2_init_rxbd_rings(struct bnx2_rx_bd *rx_ring[], dma_addr_t dma[],
52182bc4078eSMichael Chan 		     u32 buf_size, int num_rings)
5219adfc5217SJeff Kirsher {
5220adfc5217SJeff Kirsher 	int i;
52212bc4078eSMichael Chan 	struct bnx2_rx_bd *rxbd;
5222adfc5217SJeff Kirsher 
5223adfc5217SJeff Kirsher 	for (i = 0; i < num_rings; i++) {
5224adfc5217SJeff Kirsher 		int j;
5225adfc5217SJeff Kirsher 
5226adfc5217SJeff Kirsher 		rxbd = &rx_ring[i][0];
52272bc4078eSMichael Chan 		for (j = 0; j < BNX2_MAX_RX_DESC_CNT; j++, rxbd++) {
5228adfc5217SJeff Kirsher 			rxbd->rx_bd_len = buf_size;
5229adfc5217SJeff Kirsher 			rxbd->rx_bd_flags = RX_BD_FLAGS_START | RX_BD_FLAGS_END;
5230adfc5217SJeff Kirsher 		}
5231adfc5217SJeff Kirsher 		if (i == (num_rings - 1))
5232adfc5217SJeff Kirsher 			j = 0;
5233adfc5217SJeff Kirsher 		else
5234adfc5217SJeff Kirsher 			j = i + 1;
5235adfc5217SJeff Kirsher 		rxbd->rx_bd_haddr_hi = (u64) dma[j] >> 32;
5236adfc5217SJeff Kirsher 		rxbd->rx_bd_haddr_lo = (u64) dma[j] & 0xffffffff;
5237adfc5217SJeff Kirsher 	}
5238adfc5217SJeff Kirsher }
5239adfc5217SJeff Kirsher 
5240adfc5217SJeff Kirsher static void
5241adfc5217SJeff Kirsher bnx2_init_rx_ring(struct bnx2 *bp, int ring_num)
5242adfc5217SJeff Kirsher {
5243adfc5217SJeff Kirsher 	int i;
5244adfc5217SJeff Kirsher 	u16 prod, ring_prod;
5245adfc5217SJeff Kirsher 	u32 cid, rx_cid_addr, val;
5246adfc5217SJeff Kirsher 	struct bnx2_napi *bnapi = &bp->bnx2_napi[ring_num];
5247adfc5217SJeff Kirsher 	struct bnx2_rx_ring_info *rxr = &bnapi->rx_ring;
5248adfc5217SJeff Kirsher 
5249adfc5217SJeff Kirsher 	if (ring_num == 0)
5250adfc5217SJeff Kirsher 		cid = RX_CID;
5251adfc5217SJeff Kirsher 	else
5252adfc5217SJeff Kirsher 		cid = RX_RSS_CID + ring_num - 1;
5253adfc5217SJeff Kirsher 
5254adfc5217SJeff Kirsher 	rx_cid_addr = GET_CID_ADDR(cid);
5255adfc5217SJeff Kirsher 
5256adfc5217SJeff Kirsher 	bnx2_init_rxbd_rings(rxr->rx_desc_ring, rxr->rx_desc_mapping,
5257adfc5217SJeff Kirsher 			     bp->rx_buf_use_size, bp->rx_max_ring);
5258adfc5217SJeff Kirsher 
5259adfc5217SJeff Kirsher 	bnx2_init_rx_context(bp, cid);
5260adfc5217SJeff Kirsher 
52614ce45e02SMichael Chan 	if (BNX2_CHIP(bp) == BNX2_CHIP_5709) {
5262e503e066SMichael Chan 		val = BNX2_RD(bp, BNX2_MQ_MAP_L2_5);
5263e503e066SMichael Chan 		BNX2_WR(bp, BNX2_MQ_MAP_L2_5, val | BNX2_MQ_MAP_L2_5_ARM);
5264adfc5217SJeff Kirsher 	}
5265adfc5217SJeff Kirsher 
5266adfc5217SJeff Kirsher 	bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_PG_BUF_SIZE, 0);
5267adfc5217SJeff Kirsher 	if (bp->rx_pg_ring_size) {
5268adfc5217SJeff Kirsher 		bnx2_init_rxbd_rings(rxr->rx_pg_desc_ring,
5269adfc5217SJeff Kirsher 				     rxr->rx_pg_desc_mapping,
5270adfc5217SJeff Kirsher 				     PAGE_SIZE, bp->rx_max_pg_ring);
5271adfc5217SJeff Kirsher 		val = (bp->rx_buf_use_size << 16) | PAGE_SIZE;
5272adfc5217SJeff Kirsher 		bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_PG_BUF_SIZE, val);
5273adfc5217SJeff Kirsher 		bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_RBDC_KEY,
5274adfc5217SJeff Kirsher 		       BNX2_L2CTX_RBDC_JUMBO_KEY - ring_num);
5275adfc5217SJeff Kirsher 
5276adfc5217SJeff Kirsher 		val = (u64) rxr->rx_pg_desc_mapping[0] >> 32;
5277adfc5217SJeff Kirsher 		bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_NX_PG_BDHADDR_HI, val);
5278adfc5217SJeff Kirsher 
5279adfc5217SJeff Kirsher 		val = (u64) rxr->rx_pg_desc_mapping[0] & 0xffffffff;
5280adfc5217SJeff Kirsher 		bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_NX_PG_BDHADDR_LO, val);
5281adfc5217SJeff Kirsher 
52824ce45e02SMichael Chan 		if (BNX2_CHIP(bp) == BNX2_CHIP_5709)
5283e503e066SMichael Chan 			BNX2_WR(bp, BNX2_MQ_MAP_L2_3, BNX2_MQ_MAP_L2_3_DEFAULT);
5284adfc5217SJeff Kirsher 	}
5285adfc5217SJeff Kirsher 
5286adfc5217SJeff Kirsher 	val = (u64) rxr->rx_desc_mapping[0] >> 32;
5287adfc5217SJeff Kirsher 	bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_NX_BDHADDR_HI, val);
5288adfc5217SJeff Kirsher 
5289adfc5217SJeff Kirsher 	val = (u64) rxr->rx_desc_mapping[0] & 0xffffffff;
5290adfc5217SJeff Kirsher 	bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_NX_BDHADDR_LO, val);
5291adfc5217SJeff Kirsher 
5292adfc5217SJeff Kirsher 	ring_prod = prod = rxr->rx_pg_prod;
5293adfc5217SJeff Kirsher 	for (i = 0; i < bp->rx_pg_ring_size; i++) {
5294adfc5217SJeff Kirsher 		if (bnx2_alloc_rx_page(bp, rxr, ring_prod, GFP_KERNEL) < 0) {
5295adfc5217SJeff Kirsher 			netdev_warn(bp->dev, "init'ed rx page ring %d with %d/%d pages only\n",
5296adfc5217SJeff Kirsher 				    ring_num, i, bp->rx_pg_ring_size);
5297adfc5217SJeff Kirsher 			break;
5298adfc5217SJeff Kirsher 		}
52992bc4078eSMichael Chan 		prod = BNX2_NEXT_RX_BD(prod);
53002bc4078eSMichael Chan 		ring_prod = BNX2_RX_PG_RING_IDX(prod);
5301adfc5217SJeff Kirsher 	}
5302adfc5217SJeff Kirsher 	rxr->rx_pg_prod = prod;
5303adfc5217SJeff Kirsher 
5304adfc5217SJeff Kirsher 	ring_prod = prod = rxr->rx_prod;
5305adfc5217SJeff Kirsher 	for (i = 0; i < bp->rx_ring_size; i++) {
5306dd2bc8e9SEric Dumazet 		if (bnx2_alloc_rx_data(bp, rxr, ring_prod, GFP_KERNEL) < 0) {
5307adfc5217SJeff Kirsher 			netdev_warn(bp->dev, "init'ed rx ring %d with %d/%d skbs only\n",
5308adfc5217SJeff Kirsher 				    ring_num, i, bp->rx_ring_size);
5309adfc5217SJeff Kirsher 			break;
5310adfc5217SJeff Kirsher 		}
53112bc4078eSMichael Chan 		prod = BNX2_NEXT_RX_BD(prod);
53122bc4078eSMichael Chan 		ring_prod = BNX2_RX_RING_IDX(prod);
5313adfc5217SJeff Kirsher 	}
5314adfc5217SJeff Kirsher 	rxr->rx_prod = prod;
5315adfc5217SJeff Kirsher 
5316adfc5217SJeff Kirsher 	rxr->rx_bidx_addr = MB_GET_CID_ADDR(cid) + BNX2_L2CTX_HOST_BDIDX;
5317adfc5217SJeff Kirsher 	rxr->rx_bseq_addr = MB_GET_CID_ADDR(cid) + BNX2_L2CTX_HOST_BSEQ;
5318adfc5217SJeff Kirsher 	rxr->rx_pg_bidx_addr = MB_GET_CID_ADDR(cid) + BNX2_L2CTX_HOST_PG_BDIDX;
5319adfc5217SJeff Kirsher 
5320e503e066SMichael Chan 	BNX2_WR16(bp, rxr->rx_pg_bidx_addr, rxr->rx_pg_prod);
5321e503e066SMichael Chan 	BNX2_WR16(bp, rxr->rx_bidx_addr, prod);
5322adfc5217SJeff Kirsher 
5323e503e066SMichael Chan 	BNX2_WR(bp, rxr->rx_bseq_addr, rxr->rx_prod_bseq);
5324adfc5217SJeff Kirsher }
5325adfc5217SJeff Kirsher 
5326adfc5217SJeff Kirsher static void
5327adfc5217SJeff Kirsher bnx2_init_all_rings(struct bnx2 *bp)
5328adfc5217SJeff Kirsher {
5329adfc5217SJeff Kirsher 	int i;
5330adfc5217SJeff Kirsher 	u32 val;
5331adfc5217SJeff Kirsher 
5332adfc5217SJeff Kirsher 	bnx2_clear_ring_states(bp);
5333adfc5217SJeff Kirsher 
5334e503e066SMichael Chan 	BNX2_WR(bp, BNX2_TSCH_TSS_CFG, 0);
5335adfc5217SJeff Kirsher 	for (i = 0; i < bp->num_tx_rings; i++)
5336adfc5217SJeff Kirsher 		bnx2_init_tx_ring(bp, i);
5337adfc5217SJeff Kirsher 
5338adfc5217SJeff Kirsher 	if (bp->num_tx_rings > 1)
5339e503e066SMichael Chan 		BNX2_WR(bp, BNX2_TSCH_TSS_CFG, ((bp->num_tx_rings - 1) << 24) |
5340adfc5217SJeff Kirsher 			(TX_TSS_CID << 7));
5341adfc5217SJeff Kirsher 
5342e503e066SMichael Chan 	BNX2_WR(bp, BNX2_RLUP_RSS_CONFIG, 0);
5343adfc5217SJeff Kirsher 	bnx2_reg_wr_ind(bp, BNX2_RXP_SCRATCH_RSS_TBL_SZ, 0);
5344adfc5217SJeff Kirsher 
5345adfc5217SJeff Kirsher 	for (i = 0; i < bp->num_rx_rings; i++)
5346adfc5217SJeff Kirsher 		bnx2_init_rx_ring(bp, i);
5347adfc5217SJeff Kirsher 
5348adfc5217SJeff Kirsher 	if (bp->num_rx_rings > 1) {
5349adfc5217SJeff Kirsher 		u32 tbl_32 = 0;
5350adfc5217SJeff Kirsher 
5351adfc5217SJeff Kirsher 		for (i = 0; i < BNX2_RXP_SCRATCH_RSS_TBL_MAX_ENTRIES; i++) {
5352adfc5217SJeff Kirsher 			int shift = (i % 8) << 2;
5353adfc5217SJeff Kirsher 
5354adfc5217SJeff Kirsher 			tbl_32 |= (i % (bp->num_rx_rings - 1)) << shift;
5355adfc5217SJeff Kirsher 			if ((i % 8) == 7) {
5356e503e066SMichael Chan 				BNX2_WR(bp, BNX2_RLUP_RSS_DATA, tbl_32);
5357e503e066SMichael Chan 				BNX2_WR(bp, BNX2_RLUP_RSS_COMMAND, (i >> 3) |
5358adfc5217SJeff Kirsher 					BNX2_RLUP_RSS_COMMAND_RSS_WRITE_MASK |
5359adfc5217SJeff Kirsher 					BNX2_RLUP_RSS_COMMAND_WRITE |
5360adfc5217SJeff Kirsher 					BNX2_RLUP_RSS_COMMAND_HASH_MASK);
5361adfc5217SJeff Kirsher 				tbl_32 = 0;
5362adfc5217SJeff Kirsher 			}
5363adfc5217SJeff Kirsher 		}
5364adfc5217SJeff Kirsher 
5365adfc5217SJeff Kirsher 		val = BNX2_RLUP_RSS_CONFIG_IPV4_RSS_TYPE_ALL_XI |
5366adfc5217SJeff Kirsher 		      BNX2_RLUP_RSS_CONFIG_IPV6_RSS_TYPE_ALL_XI;
5367adfc5217SJeff Kirsher 
5368e503e066SMichael Chan 		BNX2_WR(bp, BNX2_RLUP_RSS_CONFIG, val);
5369adfc5217SJeff Kirsher 
5370adfc5217SJeff Kirsher 	}
5371adfc5217SJeff Kirsher }
5372adfc5217SJeff Kirsher 
5373adfc5217SJeff Kirsher static u32 bnx2_find_max_ring(u32 ring_size, u32 max_size)
5374adfc5217SJeff Kirsher {
5375adfc5217SJeff Kirsher 	u32 max, num_rings = 1;
5376adfc5217SJeff Kirsher 
53772bc4078eSMichael Chan 	while (ring_size > BNX2_MAX_RX_DESC_CNT) {
53782bc4078eSMichael Chan 		ring_size -= BNX2_MAX_RX_DESC_CNT;
5379adfc5217SJeff Kirsher 		num_rings++;
5380adfc5217SJeff Kirsher 	}
5381adfc5217SJeff Kirsher 	/* round to next power of 2 */
5382adfc5217SJeff Kirsher 	max = max_size;
5383adfc5217SJeff Kirsher 	while ((max & num_rings) == 0)
5384adfc5217SJeff Kirsher 		max >>= 1;
5385adfc5217SJeff Kirsher 
5386adfc5217SJeff Kirsher 	if (num_rings != max)
5387adfc5217SJeff Kirsher 		max <<= 1;
5388adfc5217SJeff Kirsher 
5389adfc5217SJeff Kirsher 	return max;
5390adfc5217SJeff Kirsher }
5391adfc5217SJeff Kirsher 
5392adfc5217SJeff Kirsher static void
5393adfc5217SJeff Kirsher bnx2_set_rx_ring_size(struct bnx2 *bp, u32 size)
5394adfc5217SJeff Kirsher {
5395adfc5217SJeff Kirsher 	u32 rx_size, rx_space, jumbo_size;
5396adfc5217SJeff Kirsher 
5397adfc5217SJeff Kirsher 	/* 8 for CRC and VLAN */
5398adfc5217SJeff Kirsher 	rx_size = bp->dev->mtu + ETH_HLEN + BNX2_RX_OFFSET + 8;
5399adfc5217SJeff Kirsher 
5400adfc5217SJeff Kirsher 	rx_space = SKB_DATA_ALIGN(rx_size + BNX2_RX_ALIGN) + NET_SKB_PAD +
5401dd2bc8e9SEric Dumazet 		SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
5402adfc5217SJeff Kirsher 
5403adfc5217SJeff Kirsher 	bp->rx_copy_thresh = BNX2_RX_COPY_THRESH;
5404adfc5217SJeff Kirsher 	bp->rx_pg_ring_size = 0;
5405adfc5217SJeff Kirsher 	bp->rx_max_pg_ring = 0;
5406adfc5217SJeff Kirsher 	bp->rx_max_pg_ring_idx = 0;
5407adfc5217SJeff Kirsher 	if ((rx_space > PAGE_SIZE) && !(bp->flags & BNX2_FLAG_JUMBO_BROKEN)) {
5408adfc5217SJeff Kirsher 		int pages = PAGE_ALIGN(bp->dev->mtu - 40) >> PAGE_SHIFT;
5409adfc5217SJeff Kirsher 
5410adfc5217SJeff Kirsher 		jumbo_size = size * pages;
54112bc4078eSMichael Chan 		if (jumbo_size > BNX2_MAX_TOTAL_RX_PG_DESC_CNT)
54122bc4078eSMichael Chan 			jumbo_size = BNX2_MAX_TOTAL_RX_PG_DESC_CNT;
5413adfc5217SJeff Kirsher 
5414adfc5217SJeff Kirsher 		bp->rx_pg_ring_size = jumbo_size;
5415adfc5217SJeff Kirsher 		bp->rx_max_pg_ring = bnx2_find_max_ring(jumbo_size,
54162bc4078eSMichael Chan 							BNX2_MAX_RX_PG_RINGS);
54172bc4078eSMichael Chan 		bp->rx_max_pg_ring_idx =
54182bc4078eSMichael Chan 			(bp->rx_max_pg_ring * BNX2_RX_DESC_CNT) - 1;
5419adfc5217SJeff Kirsher 		rx_size = BNX2_RX_COPY_THRESH + BNX2_RX_OFFSET;
5420adfc5217SJeff Kirsher 		bp->rx_copy_thresh = 0;
5421adfc5217SJeff Kirsher 	}
5422adfc5217SJeff Kirsher 
5423adfc5217SJeff Kirsher 	bp->rx_buf_use_size = rx_size;
5424dd2bc8e9SEric Dumazet 	/* hw alignment + build_skb() overhead*/
5425dd2bc8e9SEric Dumazet 	bp->rx_buf_size = SKB_DATA_ALIGN(bp->rx_buf_use_size + BNX2_RX_ALIGN) +
5426dd2bc8e9SEric Dumazet 		NET_SKB_PAD + SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
5427adfc5217SJeff Kirsher 	bp->rx_jumbo_thresh = rx_size - BNX2_RX_OFFSET;
5428adfc5217SJeff Kirsher 	bp->rx_ring_size = size;
54292bc4078eSMichael Chan 	bp->rx_max_ring = bnx2_find_max_ring(size, BNX2_MAX_RX_RINGS);
54302bc4078eSMichael Chan 	bp->rx_max_ring_idx = (bp->rx_max_ring * BNX2_RX_DESC_CNT) - 1;
5431adfc5217SJeff Kirsher }
5432adfc5217SJeff Kirsher 
5433adfc5217SJeff Kirsher static void
5434adfc5217SJeff Kirsher bnx2_free_tx_skbs(struct bnx2 *bp)
5435adfc5217SJeff Kirsher {
5436adfc5217SJeff Kirsher 	int i;
5437adfc5217SJeff Kirsher 
5438adfc5217SJeff Kirsher 	for (i = 0; i < bp->num_tx_rings; i++) {
5439adfc5217SJeff Kirsher 		struct bnx2_napi *bnapi = &bp->bnx2_napi[i];
5440adfc5217SJeff Kirsher 		struct bnx2_tx_ring_info *txr = &bnapi->tx_ring;
5441adfc5217SJeff Kirsher 		int j;
5442adfc5217SJeff Kirsher 
5443b8aac410SVarsha Rao 		if (!txr->tx_buf_ring)
5444adfc5217SJeff Kirsher 			continue;
5445adfc5217SJeff Kirsher 
54462bc4078eSMichael Chan 		for (j = 0; j < BNX2_TX_DESC_CNT; ) {
54472bc4078eSMichael Chan 			struct bnx2_sw_tx_bd *tx_buf = &txr->tx_buf_ring[j];
5448adfc5217SJeff Kirsher 			struct sk_buff *skb = tx_buf->skb;
5449adfc5217SJeff Kirsher 			int k, last;
5450adfc5217SJeff Kirsher 
5451b8aac410SVarsha Rao 			if (!skb) {
54522bc4078eSMichael Chan 				j = BNX2_NEXT_TX_BD(j);
5453adfc5217SJeff Kirsher 				continue;
5454adfc5217SJeff Kirsher 			}
5455adfc5217SJeff Kirsher 
5456adfc5217SJeff Kirsher 			dma_unmap_single(&bp->pdev->dev,
5457adfc5217SJeff Kirsher 					 dma_unmap_addr(tx_buf, mapping),
5458adfc5217SJeff Kirsher 					 skb_headlen(skb),
5459adfc5217SJeff Kirsher 					 PCI_DMA_TODEVICE);
5460adfc5217SJeff Kirsher 
5461adfc5217SJeff Kirsher 			tx_buf->skb = NULL;
5462adfc5217SJeff Kirsher 
5463adfc5217SJeff Kirsher 			last = tx_buf->nr_frags;
54642bc4078eSMichael Chan 			j = BNX2_NEXT_TX_BD(j);
54652bc4078eSMichael Chan 			for (k = 0; k < last; k++, j = BNX2_NEXT_TX_BD(j)) {
54662bc4078eSMichael Chan 				tx_buf = &txr->tx_buf_ring[BNX2_TX_RING_IDX(j)];
5467adfc5217SJeff Kirsher 				dma_unmap_page(&bp->pdev->dev,
5468adfc5217SJeff Kirsher 					dma_unmap_addr(tx_buf, mapping),
54699e903e08SEric Dumazet 					skb_frag_size(&skb_shinfo(skb)->frags[k]),
5470adfc5217SJeff Kirsher 					PCI_DMA_TODEVICE);
5471adfc5217SJeff Kirsher 			}
5472adfc5217SJeff Kirsher 			dev_kfree_skb(skb);
5473adfc5217SJeff Kirsher 		}
5474e9831909SEric Dumazet 		netdev_tx_reset_queue(netdev_get_tx_queue(bp->dev, i));
5475adfc5217SJeff Kirsher 	}
5476adfc5217SJeff Kirsher }
5477adfc5217SJeff Kirsher 
5478adfc5217SJeff Kirsher static void
5479adfc5217SJeff Kirsher bnx2_free_rx_skbs(struct bnx2 *bp)
5480adfc5217SJeff Kirsher {
5481adfc5217SJeff Kirsher 	int i;
5482adfc5217SJeff Kirsher 
5483adfc5217SJeff Kirsher 	for (i = 0; i < bp->num_rx_rings; i++) {
5484adfc5217SJeff Kirsher 		struct bnx2_napi *bnapi = &bp->bnx2_napi[i];
5485adfc5217SJeff Kirsher 		struct bnx2_rx_ring_info *rxr = &bnapi->rx_ring;
5486adfc5217SJeff Kirsher 		int j;
5487adfc5217SJeff Kirsher 
5488b8aac410SVarsha Rao 		if (!rxr->rx_buf_ring)
5489adfc5217SJeff Kirsher 			return;
5490adfc5217SJeff Kirsher 
5491adfc5217SJeff Kirsher 		for (j = 0; j < bp->rx_max_ring_idx; j++) {
54922bc4078eSMichael Chan 			struct bnx2_sw_bd *rx_buf = &rxr->rx_buf_ring[j];
5493dd2bc8e9SEric Dumazet 			u8 *data = rx_buf->data;
5494adfc5217SJeff Kirsher 
5495b8aac410SVarsha Rao 			if (!data)
5496adfc5217SJeff Kirsher 				continue;
5497adfc5217SJeff Kirsher 
5498adfc5217SJeff Kirsher 			dma_unmap_single(&bp->pdev->dev,
5499adfc5217SJeff Kirsher 					 dma_unmap_addr(rx_buf, mapping),
5500adfc5217SJeff Kirsher 					 bp->rx_buf_use_size,
5501adfc5217SJeff Kirsher 					 PCI_DMA_FROMDEVICE);
5502adfc5217SJeff Kirsher 
5503dd2bc8e9SEric Dumazet 			rx_buf->data = NULL;
5504adfc5217SJeff Kirsher 
5505dd2bc8e9SEric Dumazet 			kfree(data);
5506adfc5217SJeff Kirsher 		}
5507adfc5217SJeff Kirsher 		for (j = 0; j < bp->rx_max_pg_ring_idx; j++)
5508adfc5217SJeff Kirsher 			bnx2_free_rx_page(bp, rxr, j);
5509adfc5217SJeff Kirsher 	}
5510adfc5217SJeff Kirsher }
5511adfc5217SJeff Kirsher 
5512adfc5217SJeff Kirsher static void
5513adfc5217SJeff Kirsher bnx2_free_skbs(struct bnx2 *bp)
5514adfc5217SJeff Kirsher {
5515adfc5217SJeff Kirsher 	bnx2_free_tx_skbs(bp);
5516adfc5217SJeff Kirsher 	bnx2_free_rx_skbs(bp);
5517adfc5217SJeff Kirsher }
5518adfc5217SJeff Kirsher 
5519adfc5217SJeff Kirsher static int
5520adfc5217SJeff Kirsher bnx2_reset_nic(struct bnx2 *bp, u32 reset_code)
5521adfc5217SJeff Kirsher {
5522adfc5217SJeff Kirsher 	int rc;
5523adfc5217SJeff Kirsher 
5524adfc5217SJeff Kirsher 	rc = bnx2_reset_chip(bp, reset_code);
5525adfc5217SJeff Kirsher 	bnx2_free_skbs(bp);
5526adfc5217SJeff Kirsher 	if (rc)
5527adfc5217SJeff Kirsher 		return rc;
5528adfc5217SJeff Kirsher 
5529adfc5217SJeff Kirsher 	if ((rc = bnx2_init_chip(bp)) != 0)
5530adfc5217SJeff Kirsher 		return rc;
5531adfc5217SJeff Kirsher 
5532adfc5217SJeff Kirsher 	bnx2_init_all_rings(bp);
5533adfc5217SJeff Kirsher 	return 0;
5534adfc5217SJeff Kirsher }
5535adfc5217SJeff Kirsher 
5536adfc5217SJeff Kirsher static int
5537adfc5217SJeff Kirsher bnx2_init_nic(struct bnx2 *bp, int reset_phy)
5538adfc5217SJeff Kirsher {
5539adfc5217SJeff Kirsher 	int rc;
5540adfc5217SJeff Kirsher 
5541adfc5217SJeff Kirsher 	if ((rc = bnx2_reset_nic(bp, BNX2_DRV_MSG_CODE_RESET)) != 0)
5542adfc5217SJeff Kirsher 		return rc;
5543adfc5217SJeff Kirsher 
5544adfc5217SJeff Kirsher 	spin_lock_bh(&bp->phy_lock);
5545adfc5217SJeff Kirsher 	bnx2_init_phy(bp, reset_phy);
5546adfc5217SJeff Kirsher 	bnx2_set_link(bp);
5547adfc5217SJeff Kirsher 	if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
5548adfc5217SJeff Kirsher 		bnx2_remote_phy_event(bp);
5549adfc5217SJeff Kirsher 	spin_unlock_bh(&bp->phy_lock);
5550adfc5217SJeff Kirsher 	return 0;
5551adfc5217SJeff Kirsher }
5552adfc5217SJeff Kirsher 
5553adfc5217SJeff Kirsher static int
5554adfc5217SJeff Kirsher bnx2_shutdown_chip(struct bnx2 *bp)
5555adfc5217SJeff Kirsher {
5556adfc5217SJeff Kirsher 	u32 reset_code;
5557adfc5217SJeff Kirsher 
5558adfc5217SJeff Kirsher 	if (bp->flags & BNX2_FLAG_NO_WOL)
5559adfc5217SJeff Kirsher 		reset_code = BNX2_DRV_MSG_CODE_UNLOAD_LNK_DN;
5560adfc5217SJeff Kirsher 	else if (bp->wol)
5561adfc5217SJeff Kirsher 		reset_code = BNX2_DRV_MSG_CODE_SUSPEND_WOL;
5562adfc5217SJeff Kirsher 	else
5563adfc5217SJeff Kirsher 		reset_code = BNX2_DRV_MSG_CODE_SUSPEND_NO_WOL;
5564adfc5217SJeff Kirsher 
5565adfc5217SJeff Kirsher 	return bnx2_reset_chip(bp, reset_code);
5566adfc5217SJeff Kirsher }
5567adfc5217SJeff Kirsher 
5568adfc5217SJeff Kirsher static int
5569adfc5217SJeff Kirsher bnx2_test_registers(struct bnx2 *bp)
5570adfc5217SJeff Kirsher {
5571adfc5217SJeff Kirsher 	int ret;
5572adfc5217SJeff Kirsher 	int i, is_5709;
5573adfc5217SJeff Kirsher 	static const struct {
5574adfc5217SJeff Kirsher 		u16   offset;
5575adfc5217SJeff Kirsher 		u16   flags;
5576adfc5217SJeff Kirsher #define BNX2_FL_NOT_5709	1
5577adfc5217SJeff Kirsher 		u32   rw_mask;
5578adfc5217SJeff Kirsher 		u32   ro_mask;
5579adfc5217SJeff Kirsher 	} reg_tbl[] = {
5580adfc5217SJeff Kirsher 		{ 0x006c, 0, 0x00000000, 0x0000003f },
5581adfc5217SJeff Kirsher 		{ 0x0090, 0, 0xffffffff, 0x00000000 },
5582adfc5217SJeff Kirsher 		{ 0x0094, 0, 0x00000000, 0x00000000 },
5583adfc5217SJeff Kirsher 
5584adfc5217SJeff Kirsher 		{ 0x0404, BNX2_FL_NOT_5709, 0x00003f00, 0x00000000 },
5585adfc5217SJeff Kirsher 		{ 0x0418, BNX2_FL_NOT_5709, 0x00000000, 0xffffffff },
5586adfc5217SJeff Kirsher 		{ 0x041c, BNX2_FL_NOT_5709, 0x00000000, 0xffffffff },
5587adfc5217SJeff Kirsher 		{ 0x0420, BNX2_FL_NOT_5709, 0x00000000, 0x80ffffff },
5588adfc5217SJeff Kirsher 		{ 0x0424, BNX2_FL_NOT_5709, 0x00000000, 0x00000000 },
5589adfc5217SJeff Kirsher 		{ 0x0428, BNX2_FL_NOT_5709, 0x00000000, 0x00000001 },
5590adfc5217SJeff Kirsher 		{ 0x0450, BNX2_FL_NOT_5709, 0x00000000, 0x0000ffff },
5591adfc5217SJeff Kirsher 		{ 0x0454, BNX2_FL_NOT_5709, 0x00000000, 0xffffffff },
5592adfc5217SJeff Kirsher 		{ 0x0458, BNX2_FL_NOT_5709, 0x00000000, 0xffffffff },
5593adfc5217SJeff Kirsher 
5594adfc5217SJeff Kirsher 		{ 0x0808, BNX2_FL_NOT_5709, 0x00000000, 0xffffffff },
5595adfc5217SJeff Kirsher 		{ 0x0854, BNX2_FL_NOT_5709, 0x00000000, 0xffffffff },
5596adfc5217SJeff Kirsher 		{ 0x0868, BNX2_FL_NOT_5709, 0x00000000, 0x77777777 },
5597adfc5217SJeff Kirsher 		{ 0x086c, BNX2_FL_NOT_5709, 0x00000000, 0x77777777 },
5598adfc5217SJeff Kirsher 		{ 0x0870, BNX2_FL_NOT_5709, 0x00000000, 0x77777777 },
5599adfc5217SJeff Kirsher 		{ 0x0874, BNX2_FL_NOT_5709, 0x00000000, 0x77777777 },
5600adfc5217SJeff Kirsher 
5601adfc5217SJeff Kirsher 		{ 0x0c00, BNX2_FL_NOT_5709, 0x00000000, 0x00000001 },
5602adfc5217SJeff Kirsher 		{ 0x0c04, BNX2_FL_NOT_5709, 0x00000000, 0x03ff0001 },
5603adfc5217SJeff Kirsher 		{ 0x0c08, BNX2_FL_NOT_5709,  0x0f0ff073, 0x00000000 },
5604adfc5217SJeff Kirsher 
5605adfc5217SJeff Kirsher 		{ 0x1000, 0, 0x00000000, 0x00000001 },
5606adfc5217SJeff Kirsher 		{ 0x1004, BNX2_FL_NOT_5709, 0x00000000, 0x000f0001 },
5607adfc5217SJeff Kirsher 
5608adfc5217SJeff Kirsher 		{ 0x1408, 0, 0x01c00800, 0x00000000 },
5609adfc5217SJeff Kirsher 		{ 0x149c, 0, 0x8000ffff, 0x00000000 },
5610adfc5217SJeff Kirsher 		{ 0x14a8, 0, 0x00000000, 0x000001ff },
5611adfc5217SJeff Kirsher 		{ 0x14ac, 0, 0x0fffffff, 0x10000000 },
5612adfc5217SJeff Kirsher 		{ 0x14b0, 0, 0x00000002, 0x00000001 },
5613adfc5217SJeff Kirsher 		{ 0x14b8, 0, 0x00000000, 0x00000000 },
5614adfc5217SJeff Kirsher 		{ 0x14c0, 0, 0x00000000, 0x00000009 },
5615adfc5217SJeff Kirsher 		{ 0x14c4, 0, 0x00003fff, 0x00000000 },
5616adfc5217SJeff Kirsher 		{ 0x14cc, 0, 0x00000000, 0x00000001 },
5617adfc5217SJeff Kirsher 		{ 0x14d0, 0, 0xffffffff, 0x00000000 },
5618adfc5217SJeff Kirsher 
5619adfc5217SJeff Kirsher 		{ 0x1800, 0, 0x00000000, 0x00000001 },
5620adfc5217SJeff Kirsher 		{ 0x1804, 0, 0x00000000, 0x00000003 },
5621adfc5217SJeff Kirsher 
5622adfc5217SJeff Kirsher 		{ 0x2800, 0, 0x00000000, 0x00000001 },
5623adfc5217SJeff Kirsher 		{ 0x2804, 0, 0x00000000, 0x00003f01 },
5624adfc5217SJeff Kirsher 		{ 0x2808, 0, 0x0f3f3f03, 0x00000000 },
5625adfc5217SJeff Kirsher 		{ 0x2810, 0, 0xffff0000, 0x00000000 },
5626adfc5217SJeff Kirsher 		{ 0x2814, 0, 0xffff0000, 0x00000000 },
5627adfc5217SJeff Kirsher 		{ 0x2818, 0, 0xffff0000, 0x00000000 },
5628adfc5217SJeff Kirsher 		{ 0x281c, 0, 0xffff0000, 0x00000000 },
5629adfc5217SJeff Kirsher 		{ 0x2834, 0, 0xffffffff, 0x00000000 },
5630adfc5217SJeff Kirsher 		{ 0x2840, 0, 0x00000000, 0xffffffff },
5631adfc5217SJeff Kirsher 		{ 0x2844, 0, 0x00000000, 0xffffffff },
5632adfc5217SJeff Kirsher 		{ 0x2848, 0, 0xffffffff, 0x00000000 },
5633adfc5217SJeff Kirsher 		{ 0x284c, 0, 0xf800f800, 0x07ff07ff },
5634adfc5217SJeff Kirsher 
5635adfc5217SJeff Kirsher 		{ 0x2c00, 0, 0x00000000, 0x00000011 },
5636adfc5217SJeff Kirsher 		{ 0x2c04, 0, 0x00000000, 0x00030007 },
5637adfc5217SJeff Kirsher 
5638adfc5217SJeff Kirsher 		{ 0x3c00, 0, 0x00000000, 0x00000001 },
5639adfc5217SJeff Kirsher 		{ 0x3c04, 0, 0x00000000, 0x00070000 },
5640adfc5217SJeff Kirsher 		{ 0x3c08, 0, 0x00007f71, 0x07f00000 },
5641adfc5217SJeff Kirsher 		{ 0x3c0c, 0, 0x1f3ffffc, 0x00000000 },
5642adfc5217SJeff Kirsher 		{ 0x3c10, 0, 0xffffffff, 0x00000000 },
5643adfc5217SJeff Kirsher 		{ 0x3c14, 0, 0x00000000, 0xffffffff },
5644adfc5217SJeff Kirsher 		{ 0x3c18, 0, 0x00000000, 0xffffffff },
5645adfc5217SJeff Kirsher 		{ 0x3c1c, 0, 0xfffff000, 0x00000000 },
5646adfc5217SJeff Kirsher 		{ 0x3c20, 0, 0xffffff00, 0x00000000 },
5647adfc5217SJeff Kirsher 
5648adfc5217SJeff Kirsher 		{ 0x5004, 0, 0x00000000, 0x0000007f },
5649adfc5217SJeff Kirsher 		{ 0x5008, 0, 0x0f0007ff, 0x00000000 },
5650adfc5217SJeff Kirsher 
5651adfc5217SJeff Kirsher 		{ 0x5c00, 0, 0x00000000, 0x00000001 },
5652adfc5217SJeff Kirsher 		{ 0x5c04, 0, 0x00000000, 0x0003000f },
5653adfc5217SJeff Kirsher 		{ 0x5c08, 0, 0x00000003, 0x00000000 },
5654adfc5217SJeff Kirsher 		{ 0x5c0c, 0, 0x0000fff8, 0x00000000 },
5655adfc5217SJeff Kirsher 		{ 0x5c10, 0, 0x00000000, 0xffffffff },
5656adfc5217SJeff Kirsher 		{ 0x5c80, 0, 0x00000000, 0x0f7113f1 },
5657adfc5217SJeff Kirsher 		{ 0x5c84, 0, 0x00000000, 0x0000f333 },
5658adfc5217SJeff Kirsher 		{ 0x5c88, 0, 0x00000000, 0x00077373 },
5659adfc5217SJeff Kirsher 		{ 0x5c8c, 0, 0x00000000, 0x0007f737 },
5660adfc5217SJeff Kirsher 
5661adfc5217SJeff Kirsher 		{ 0x6808, 0, 0x0000ff7f, 0x00000000 },
5662adfc5217SJeff Kirsher 		{ 0x680c, 0, 0xffffffff, 0x00000000 },
5663adfc5217SJeff Kirsher 		{ 0x6810, 0, 0xffffffff, 0x00000000 },
5664adfc5217SJeff Kirsher 		{ 0x6814, 0, 0xffffffff, 0x00000000 },
5665adfc5217SJeff Kirsher 		{ 0x6818, 0, 0xffffffff, 0x00000000 },
5666adfc5217SJeff Kirsher 		{ 0x681c, 0, 0xffffffff, 0x00000000 },
5667adfc5217SJeff Kirsher 		{ 0x6820, 0, 0x00ff00ff, 0x00000000 },
5668adfc5217SJeff Kirsher 		{ 0x6824, 0, 0x00ff00ff, 0x00000000 },
5669adfc5217SJeff Kirsher 		{ 0x6828, 0, 0x00ff00ff, 0x00000000 },
5670adfc5217SJeff Kirsher 		{ 0x682c, 0, 0x03ff03ff, 0x00000000 },
5671adfc5217SJeff Kirsher 		{ 0x6830, 0, 0x03ff03ff, 0x00000000 },
5672adfc5217SJeff Kirsher 		{ 0x6834, 0, 0x03ff03ff, 0x00000000 },
5673adfc5217SJeff Kirsher 		{ 0x6838, 0, 0x03ff03ff, 0x00000000 },
5674adfc5217SJeff Kirsher 		{ 0x683c, 0, 0x0000ffff, 0x00000000 },
5675adfc5217SJeff Kirsher 		{ 0x6840, 0, 0x00000ff0, 0x00000000 },
5676adfc5217SJeff Kirsher 		{ 0x6844, 0, 0x00ffff00, 0x00000000 },
5677adfc5217SJeff Kirsher 		{ 0x684c, 0, 0xffffffff, 0x00000000 },
5678adfc5217SJeff Kirsher 		{ 0x6850, 0, 0x7f7f7f7f, 0x00000000 },
5679adfc5217SJeff Kirsher 		{ 0x6854, 0, 0x7f7f7f7f, 0x00000000 },
5680adfc5217SJeff Kirsher 		{ 0x6858, 0, 0x7f7f7f7f, 0x00000000 },
5681adfc5217SJeff Kirsher 		{ 0x685c, 0, 0x7f7f7f7f, 0x00000000 },
5682adfc5217SJeff Kirsher 		{ 0x6908, 0, 0x00000000, 0x0001ff0f },
5683adfc5217SJeff Kirsher 		{ 0x690c, 0, 0x00000000, 0x0ffe00f0 },
5684adfc5217SJeff Kirsher 
5685adfc5217SJeff Kirsher 		{ 0xffff, 0, 0x00000000, 0x00000000 },
5686adfc5217SJeff Kirsher 	};
5687adfc5217SJeff Kirsher 
5688adfc5217SJeff Kirsher 	ret = 0;
5689adfc5217SJeff Kirsher 	is_5709 = 0;
56904ce45e02SMichael Chan 	if (BNX2_CHIP(bp) == BNX2_CHIP_5709)
5691adfc5217SJeff Kirsher 		is_5709 = 1;
5692adfc5217SJeff Kirsher 
5693adfc5217SJeff Kirsher 	for (i = 0; reg_tbl[i].offset != 0xffff; i++) {
5694adfc5217SJeff Kirsher 		u32 offset, rw_mask, ro_mask, save_val, val;
5695adfc5217SJeff Kirsher 		u16 flags = reg_tbl[i].flags;
5696adfc5217SJeff Kirsher 
5697adfc5217SJeff Kirsher 		if (is_5709 && (flags & BNX2_FL_NOT_5709))
5698adfc5217SJeff Kirsher 			continue;
5699adfc5217SJeff Kirsher 
5700adfc5217SJeff Kirsher 		offset = (u32) reg_tbl[i].offset;
5701adfc5217SJeff Kirsher 		rw_mask = reg_tbl[i].rw_mask;
5702adfc5217SJeff Kirsher 		ro_mask = reg_tbl[i].ro_mask;
5703adfc5217SJeff Kirsher 
5704adfc5217SJeff Kirsher 		save_val = readl(bp->regview + offset);
5705adfc5217SJeff Kirsher 
5706adfc5217SJeff Kirsher 		writel(0, bp->regview + offset);
5707adfc5217SJeff Kirsher 
5708adfc5217SJeff Kirsher 		val = readl(bp->regview + offset);
5709adfc5217SJeff Kirsher 		if ((val & rw_mask) != 0) {
5710adfc5217SJeff Kirsher 			goto reg_test_err;
5711adfc5217SJeff Kirsher 		}
5712adfc5217SJeff Kirsher 
5713adfc5217SJeff Kirsher 		if ((val & ro_mask) != (save_val & ro_mask)) {
5714adfc5217SJeff Kirsher 			goto reg_test_err;
5715adfc5217SJeff Kirsher 		}
5716adfc5217SJeff Kirsher 
5717adfc5217SJeff Kirsher 		writel(0xffffffff, bp->regview + offset);
5718adfc5217SJeff Kirsher 
5719adfc5217SJeff Kirsher 		val = readl(bp->regview + offset);
5720adfc5217SJeff Kirsher 		if ((val & rw_mask) != rw_mask) {
5721adfc5217SJeff Kirsher 			goto reg_test_err;
5722adfc5217SJeff Kirsher 		}
5723adfc5217SJeff Kirsher 
5724adfc5217SJeff Kirsher 		if ((val & ro_mask) != (save_val & ro_mask)) {
5725adfc5217SJeff Kirsher 			goto reg_test_err;
5726adfc5217SJeff Kirsher 		}
5727adfc5217SJeff Kirsher 
5728adfc5217SJeff Kirsher 		writel(save_val, bp->regview + offset);
5729adfc5217SJeff Kirsher 		continue;
5730adfc5217SJeff Kirsher 
5731adfc5217SJeff Kirsher reg_test_err:
5732adfc5217SJeff Kirsher 		writel(save_val, bp->regview + offset);
5733adfc5217SJeff Kirsher 		ret = -ENODEV;
5734adfc5217SJeff Kirsher 		break;
5735adfc5217SJeff Kirsher 	}
5736adfc5217SJeff Kirsher 	return ret;
5737adfc5217SJeff Kirsher }
5738adfc5217SJeff Kirsher 
5739adfc5217SJeff Kirsher static int
5740adfc5217SJeff Kirsher bnx2_do_mem_test(struct bnx2 *bp, u32 start, u32 size)
5741adfc5217SJeff Kirsher {
5742adfc5217SJeff Kirsher 	static const u32 test_pattern[] = { 0x00000000, 0xffffffff, 0x55555555,
5743adfc5217SJeff Kirsher 		0xaaaaaaaa , 0xaa55aa55, 0x55aa55aa };
5744adfc5217SJeff Kirsher 	int i;
5745adfc5217SJeff Kirsher 
5746adfc5217SJeff Kirsher 	for (i = 0; i < sizeof(test_pattern) / 4; i++) {
5747adfc5217SJeff Kirsher 		u32 offset;
5748adfc5217SJeff Kirsher 
5749adfc5217SJeff Kirsher 		for (offset = 0; offset < size; offset += 4) {
5750adfc5217SJeff Kirsher 
5751adfc5217SJeff Kirsher 			bnx2_reg_wr_ind(bp, start + offset, test_pattern[i]);
5752adfc5217SJeff Kirsher 
5753adfc5217SJeff Kirsher 			if (bnx2_reg_rd_ind(bp, start + offset) !=
5754adfc5217SJeff Kirsher 				test_pattern[i]) {
5755adfc5217SJeff Kirsher 				return -ENODEV;
5756adfc5217SJeff Kirsher 			}
5757adfc5217SJeff Kirsher 		}
5758adfc5217SJeff Kirsher 	}
5759adfc5217SJeff Kirsher 	return 0;
5760adfc5217SJeff Kirsher }
5761adfc5217SJeff Kirsher 
5762adfc5217SJeff Kirsher static int
5763adfc5217SJeff Kirsher bnx2_test_memory(struct bnx2 *bp)
5764adfc5217SJeff Kirsher {
5765adfc5217SJeff Kirsher 	int ret = 0;
5766adfc5217SJeff Kirsher 	int i;
5767adfc5217SJeff Kirsher 	static struct mem_entry {
5768adfc5217SJeff Kirsher 		u32   offset;
5769adfc5217SJeff Kirsher 		u32   len;
5770adfc5217SJeff Kirsher 	} mem_tbl_5706[] = {
5771adfc5217SJeff Kirsher 		{ 0x60000,  0x4000 },
5772adfc5217SJeff Kirsher 		{ 0xa0000,  0x3000 },
5773adfc5217SJeff Kirsher 		{ 0xe0000,  0x4000 },
5774adfc5217SJeff Kirsher 		{ 0x120000, 0x4000 },
5775adfc5217SJeff Kirsher 		{ 0x1a0000, 0x4000 },
5776adfc5217SJeff Kirsher 		{ 0x160000, 0x4000 },
5777adfc5217SJeff Kirsher 		{ 0xffffffff, 0    },
5778adfc5217SJeff Kirsher 	},
5779adfc5217SJeff Kirsher 	mem_tbl_5709[] = {
5780adfc5217SJeff Kirsher 		{ 0x60000,  0x4000 },
5781adfc5217SJeff Kirsher 		{ 0xa0000,  0x3000 },
5782adfc5217SJeff Kirsher 		{ 0xe0000,  0x4000 },
5783adfc5217SJeff Kirsher 		{ 0x120000, 0x4000 },
5784adfc5217SJeff Kirsher 		{ 0x1a0000, 0x4000 },
5785adfc5217SJeff Kirsher 		{ 0xffffffff, 0    },
5786adfc5217SJeff Kirsher 	};
5787adfc5217SJeff Kirsher 	struct mem_entry *mem_tbl;
5788adfc5217SJeff Kirsher 
57894ce45e02SMichael Chan 	if (BNX2_CHIP(bp) == BNX2_CHIP_5709)
5790adfc5217SJeff Kirsher 		mem_tbl = mem_tbl_5709;
5791adfc5217SJeff Kirsher 	else
5792adfc5217SJeff Kirsher 		mem_tbl = mem_tbl_5706;
5793adfc5217SJeff Kirsher 
5794adfc5217SJeff Kirsher 	for (i = 0; mem_tbl[i].offset != 0xffffffff; i++) {
5795adfc5217SJeff Kirsher 		if ((ret = bnx2_do_mem_test(bp, mem_tbl[i].offset,
5796adfc5217SJeff Kirsher 			mem_tbl[i].len)) != 0) {
5797adfc5217SJeff Kirsher 			return ret;
5798adfc5217SJeff Kirsher 		}
5799adfc5217SJeff Kirsher 	}
5800adfc5217SJeff Kirsher 
5801adfc5217SJeff Kirsher 	return ret;
5802adfc5217SJeff Kirsher }
5803adfc5217SJeff Kirsher 
5804adfc5217SJeff Kirsher #define BNX2_MAC_LOOPBACK	0
5805adfc5217SJeff Kirsher #define BNX2_PHY_LOOPBACK	1
5806adfc5217SJeff Kirsher 
5807adfc5217SJeff Kirsher static int
5808adfc5217SJeff Kirsher bnx2_run_loopback(struct bnx2 *bp, int loopback_mode)
5809adfc5217SJeff Kirsher {
5810adfc5217SJeff Kirsher 	unsigned int pkt_size, num_pkts, i;
5811dd2bc8e9SEric Dumazet 	struct sk_buff *skb;
5812dd2bc8e9SEric Dumazet 	u8 *data;
5813adfc5217SJeff Kirsher 	unsigned char *packet;
5814adfc5217SJeff Kirsher 	u16 rx_start_idx, rx_idx;
5815adfc5217SJeff Kirsher 	dma_addr_t map;
58162bc4078eSMichael Chan 	struct bnx2_tx_bd *txbd;
58172bc4078eSMichael Chan 	struct bnx2_sw_bd *rx_buf;
5818adfc5217SJeff Kirsher 	struct l2_fhdr *rx_hdr;
5819adfc5217SJeff Kirsher 	int ret = -ENODEV;
5820adfc5217SJeff Kirsher 	struct bnx2_napi *bnapi = &bp->bnx2_napi[0], *tx_napi;
5821196709f4SColin Ian King 	struct bnx2_tx_ring_info *txr;
5822196709f4SColin Ian King 	struct bnx2_rx_ring_info *rxr;
5823adfc5217SJeff Kirsher 
5824adfc5217SJeff Kirsher 	tx_napi = bnapi;
5825adfc5217SJeff Kirsher 
5826adfc5217SJeff Kirsher 	txr = &tx_napi->tx_ring;
5827adfc5217SJeff Kirsher 	rxr = &bnapi->rx_ring;
5828adfc5217SJeff Kirsher 	if (loopback_mode == BNX2_MAC_LOOPBACK) {
5829adfc5217SJeff Kirsher 		bp->loopback = MAC_LOOPBACK;
5830adfc5217SJeff Kirsher 		bnx2_set_mac_loopback(bp);
5831adfc5217SJeff Kirsher 	}
5832adfc5217SJeff Kirsher 	else if (loopback_mode == BNX2_PHY_LOOPBACK) {
5833adfc5217SJeff Kirsher 		if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
5834adfc5217SJeff Kirsher 			return 0;
5835adfc5217SJeff Kirsher 
5836adfc5217SJeff Kirsher 		bp->loopback = PHY_LOOPBACK;
5837adfc5217SJeff Kirsher 		bnx2_set_phy_loopback(bp);
5838adfc5217SJeff Kirsher 	}
5839adfc5217SJeff Kirsher 	else
5840adfc5217SJeff Kirsher 		return -EINVAL;
5841adfc5217SJeff Kirsher 
5842adfc5217SJeff Kirsher 	pkt_size = min(bp->dev->mtu + ETH_HLEN, bp->rx_jumbo_thresh - 4);
5843adfc5217SJeff Kirsher 	skb = netdev_alloc_skb(bp->dev, pkt_size);
5844adfc5217SJeff Kirsher 	if (!skb)
5845adfc5217SJeff Kirsher 		return -ENOMEM;
5846adfc5217SJeff Kirsher 	packet = skb_put(skb, pkt_size);
5847d458cdf7SJoe Perches 	memcpy(packet, bp->dev->dev_addr, ETH_ALEN);
5848d458cdf7SJoe Perches 	memset(packet + ETH_ALEN, 0x0, 8);
5849adfc5217SJeff Kirsher 	for (i = 14; i < pkt_size; i++)
5850adfc5217SJeff Kirsher 		packet[i] = (unsigned char) (i & 0xff);
5851adfc5217SJeff Kirsher 
5852adfc5217SJeff Kirsher 	map = dma_map_single(&bp->pdev->dev, skb->data, pkt_size,
5853adfc5217SJeff Kirsher 			     PCI_DMA_TODEVICE);
5854adfc5217SJeff Kirsher 	if (dma_mapping_error(&bp->pdev->dev, map)) {
5855adfc5217SJeff Kirsher 		dev_kfree_skb(skb);
5856adfc5217SJeff Kirsher 		return -EIO;
5857adfc5217SJeff Kirsher 	}
5858adfc5217SJeff Kirsher 
5859e503e066SMichael Chan 	BNX2_WR(bp, BNX2_HC_COMMAND,
5860adfc5217SJeff Kirsher 		bp->hc_cmd | BNX2_HC_COMMAND_COAL_NOW_WO_INT);
5861adfc5217SJeff Kirsher 
5862e503e066SMichael Chan 	BNX2_RD(bp, BNX2_HC_COMMAND);
5863adfc5217SJeff Kirsher 
5864adfc5217SJeff Kirsher 	udelay(5);
5865adfc5217SJeff Kirsher 	rx_start_idx = bnx2_get_hw_rx_cons(bnapi);
5866adfc5217SJeff Kirsher 
5867adfc5217SJeff Kirsher 	num_pkts = 0;
5868adfc5217SJeff Kirsher 
58692bc4078eSMichael Chan 	txbd = &txr->tx_desc_ring[BNX2_TX_RING_IDX(txr->tx_prod)];
5870adfc5217SJeff Kirsher 
5871adfc5217SJeff Kirsher 	txbd->tx_bd_haddr_hi = (u64) map >> 32;
5872adfc5217SJeff Kirsher 	txbd->tx_bd_haddr_lo = (u64) map & 0xffffffff;
5873adfc5217SJeff Kirsher 	txbd->tx_bd_mss_nbytes = pkt_size;
5874adfc5217SJeff Kirsher 	txbd->tx_bd_vlan_tag_flags = TX_BD_FLAGS_START | TX_BD_FLAGS_END;
5875adfc5217SJeff Kirsher 
5876adfc5217SJeff Kirsher 	num_pkts++;
58772bc4078eSMichael Chan 	txr->tx_prod = BNX2_NEXT_TX_BD(txr->tx_prod);
5878adfc5217SJeff Kirsher 	txr->tx_prod_bseq += pkt_size;
5879adfc5217SJeff Kirsher 
5880e503e066SMichael Chan 	BNX2_WR16(bp, txr->tx_bidx_addr, txr->tx_prod);
5881e503e066SMichael Chan 	BNX2_WR(bp, txr->tx_bseq_addr, txr->tx_prod_bseq);
5882adfc5217SJeff Kirsher 
5883adfc5217SJeff Kirsher 	udelay(100);
5884adfc5217SJeff Kirsher 
5885e503e066SMichael Chan 	BNX2_WR(bp, BNX2_HC_COMMAND,
5886adfc5217SJeff Kirsher 		bp->hc_cmd | BNX2_HC_COMMAND_COAL_NOW_WO_INT);
5887adfc5217SJeff Kirsher 
5888e503e066SMichael Chan 	BNX2_RD(bp, BNX2_HC_COMMAND);
5889adfc5217SJeff Kirsher 
5890adfc5217SJeff Kirsher 	udelay(5);
5891adfc5217SJeff Kirsher 
5892adfc5217SJeff Kirsher 	dma_unmap_single(&bp->pdev->dev, map, pkt_size, PCI_DMA_TODEVICE);
5893adfc5217SJeff Kirsher 	dev_kfree_skb(skb);
5894adfc5217SJeff Kirsher 
5895adfc5217SJeff Kirsher 	if (bnx2_get_hw_tx_cons(tx_napi) != txr->tx_prod)
5896adfc5217SJeff Kirsher 		goto loopback_test_done;
5897adfc5217SJeff Kirsher 
5898adfc5217SJeff Kirsher 	rx_idx = bnx2_get_hw_rx_cons(bnapi);
5899adfc5217SJeff Kirsher 	if (rx_idx != rx_start_idx + num_pkts) {
5900adfc5217SJeff Kirsher 		goto loopback_test_done;
5901adfc5217SJeff Kirsher 	}
5902adfc5217SJeff Kirsher 
5903adfc5217SJeff Kirsher 	rx_buf = &rxr->rx_buf_ring[rx_start_idx];
5904dd2bc8e9SEric Dumazet 	data = rx_buf->data;
5905adfc5217SJeff Kirsher 
5906dd2bc8e9SEric Dumazet 	rx_hdr = get_l2_fhdr(data);
5907dd2bc8e9SEric Dumazet 	data = (u8 *)rx_hdr + BNX2_RX_OFFSET;
5908adfc5217SJeff Kirsher 
5909adfc5217SJeff Kirsher 	dma_sync_single_for_cpu(&bp->pdev->dev,
5910adfc5217SJeff Kirsher 		dma_unmap_addr(rx_buf, mapping),
5911dd2bc8e9SEric Dumazet 		bp->rx_buf_use_size, PCI_DMA_FROMDEVICE);
5912adfc5217SJeff Kirsher 
5913adfc5217SJeff Kirsher 	if (rx_hdr->l2_fhdr_status &
5914adfc5217SJeff Kirsher 		(L2_FHDR_ERRORS_BAD_CRC |
5915adfc5217SJeff Kirsher 		L2_FHDR_ERRORS_PHY_DECODE |
5916adfc5217SJeff Kirsher 		L2_FHDR_ERRORS_ALIGNMENT |
5917adfc5217SJeff Kirsher 		L2_FHDR_ERRORS_TOO_SHORT |
5918adfc5217SJeff Kirsher 		L2_FHDR_ERRORS_GIANT_FRAME)) {
5919adfc5217SJeff Kirsher 
5920adfc5217SJeff Kirsher 		goto loopback_test_done;
5921adfc5217SJeff Kirsher 	}
5922adfc5217SJeff Kirsher 
5923adfc5217SJeff Kirsher 	if ((rx_hdr->l2_fhdr_pkt_len - 4) != pkt_size) {
5924adfc5217SJeff Kirsher 		goto loopback_test_done;
5925adfc5217SJeff Kirsher 	}
5926adfc5217SJeff Kirsher 
5927adfc5217SJeff Kirsher 	for (i = 14; i < pkt_size; i++) {
5928dd2bc8e9SEric Dumazet 		if (*(data + i) != (unsigned char) (i & 0xff)) {
5929adfc5217SJeff Kirsher 			goto loopback_test_done;
5930adfc5217SJeff Kirsher 		}
5931adfc5217SJeff Kirsher 	}
5932adfc5217SJeff Kirsher 
5933adfc5217SJeff Kirsher 	ret = 0;
5934adfc5217SJeff Kirsher 
5935adfc5217SJeff Kirsher loopback_test_done:
5936adfc5217SJeff Kirsher 	bp->loopback = 0;
5937adfc5217SJeff Kirsher 	return ret;
5938adfc5217SJeff Kirsher }
5939adfc5217SJeff Kirsher 
5940adfc5217SJeff Kirsher #define BNX2_MAC_LOOPBACK_FAILED	1
5941adfc5217SJeff Kirsher #define BNX2_PHY_LOOPBACK_FAILED	2
5942adfc5217SJeff Kirsher #define BNX2_LOOPBACK_FAILED		(BNX2_MAC_LOOPBACK_FAILED |	\
5943adfc5217SJeff Kirsher 					 BNX2_PHY_LOOPBACK_FAILED)
5944adfc5217SJeff Kirsher 
5945adfc5217SJeff Kirsher static int
5946adfc5217SJeff Kirsher bnx2_test_loopback(struct bnx2 *bp)
5947adfc5217SJeff Kirsher {
5948adfc5217SJeff Kirsher 	int rc = 0;
5949adfc5217SJeff Kirsher 
5950adfc5217SJeff Kirsher 	if (!netif_running(bp->dev))
5951adfc5217SJeff Kirsher 		return BNX2_LOOPBACK_FAILED;
5952adfc5217SJeff Kirsher 
5953adfc5217SJeff Kirsher 	bnx2_reset_nic(bp, BNX2_DRV_MSG_CODE_RESET);
5954adfc5217SJeff Kirsher 	spin_lock_bh(&bp->phy_lock);
5955adfc5217SJeff Kirsher 	bnx2_init_phy(bp, 1);
5956adfc5217SJeff Kirsher 	spin_unlock_bh(&bp->phy_lock);
5957adfc5217SJeff Kirsher 	if (bnx2_run_loopback(bp, BNX2_MAC_LOOPBACK))
5958adfc5217SJeff Kirsher 		rc |= BNX2_MAC_LOOPBACK_FAILED;
5959adfc5217SJeff Kirsher 	if (bnx2_run_loopback(bp, BNX2_PHY_LOOPBACK))
5960adfc5217SJeff Kirsher 		rc |= BNX2_PHY_LOOPBACK_FAILED;
5961adfc5217SJeff Kirsher 	return rc;
5962adfc5217SJeff Kirsher }
5963adfc5217SJeff Kirsher 
5964adfc5217SJeff Kirsher #define NVRAM_SIZE 0x200
5965adfc5217SJeff Kirsher #define CRC32_RESIDUAL 0xdebb20e3
5966adfc5217SJeff Kirsher 
5967adfc5217SJeff Kirsher static int
5968adfc5217SJeff Kirsher bnx2_test_nvram(struct bnx2 *bp)
5969adfc5217SJeff Kirsher {
5970adfc5217SJeff Kirsher 	__be32 buf[NVRAM_SIZE / 4];
5971adfc5217SJeff Kirsher 	u8 *data = (u8 *) buf;
5972adfc5217SJeff Kirsher 	int rc = 0;
5973adfc5217SJeff Kirsher 	u32 magic, csum;
5974adfc5217SJeff Kirsher 
5975adfc5217SJeff Kirsher 	if ((rc = bnx2_nvram_read(bp, 0, data, 4)) != 0)
5976adfc5217SJeff Kirsher 		goto test_nvram_done;
5977adfc5217SJeff Kirsher 
5978adfc5217SJeff Kirsher         magic = be32_to_cpu(buf[0]);
5979adfc5217SJeff Kirsher 	if (magic != 0x669955aa) {
5980adfc5217SJeff Kirsher 		rc = -ENODEV;
5981adfc5217SJeff Kirsher 		goto test_nvram_done;
5982adfc5217SJeff Kirsher 	}
5983adfc5217SJeff Kirsher 
5984adfc5217SJeff Kirsher 	if ((rc = bnx2_nvram_read(bp, 0x100, data, NVRAM_SIZE)) != 0)
5985adfc5217SJeff Kirsher 		goto test_nvram_done;
5986adfc5217SJeff Kirsher 
5987adfc5217SJeff Kirsher 	csum = ether_crc_le(0x100, data);
5988adfc5217SJeff Kirsher 	if (csum != CRC32_RESIDUAL) {
5989adfc5217SJeff Kirsher 		rc = -ENODEV;
5990adfc5217SJeff Kirsher 		goto test_nvram_done;
5991adfc5217SJeff Kirsher 	}
5992adfc5217SJeff Kirsher 
5993adfc5217SJeff Kirsher 	csum = ether_crc_le(0x100, data + 0x100);
5994adfc5217SJeff Kirsher 	if (csum != CRC32_RESIDUAL) {
5995adfc5217SJeff Kirsher 		rc = -ENODEV;
5996adfc5217SJeff Kirsher 	}
5997adfc5217SJeff Kirsher 
5998adfc5217SJeff Kirsher test_nvram_done:
5999adfc5217SJeff Kirsher 	return rc;
6000adfc5217SJeff Kirsher }
6001adfc5217SJeff Kirsher 
6002adfc5217SJeff Kirsher static int
6003adfc5217SJeff Kirsher bnx2_test_link(struct bnx2 *bp)
6004adfc5217SJeff Kirsher {
6005adfc5217SJeff Kirsher 	u32 bmsr;
6006adfc5217SJeff Kirsher 
6007adfc5217SJeff Kirsher 	if (!netif_running(bp->dev))
6008adfc5217SJeff Kirsher 		return -ENODEV;
6009adfc5217SJeff Kirsher 
6010adfc5217SJeff Kirsher 	if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP) {
6011adfc5217SJeff Kirsher 		if (bp->link_up)
6012adfc5217SJeff Kirsher 			return 0;
6013adfc5217SJeff Kirsher 		return -ENODEV;
6014adfc5217SJeff Kirsher 	}
6015adfc5217SJeff Kirsher 	spin_lock_bh(&bp->phy_lock);
6016adfc5217SJeff Kirsher 	bnx2_enable_bmsr1(bp);
6017adfc5217SJeff Kirsher 	bnx2_read_phy(bp, bp->mii_bmsr1, &bmsr);
6018adfc5217SJeff Kirsher 	bnx2_read_phy(bp, bp->mii_bmsr1, &bmsr);
6019adfc5217SJeff Kirsher 	bnx2_disable_bmsr1(bp);
6020adfc5217SJeff Kirsher 	spin_unlock_bh(&bp->phy_lock);
6021adfc5217SJeff Kirsher 
6022adfc5217SJeff Kirsher 	if (bmsr & BMSR_LSTATUS) {
6023adfc5217SJeff Kirsher 		return 0;
6024adfc5217SJeff Kirsher 	}
6025adfc5217SJeff Kirsher 	return -ENODEV;
6026adfc5217SJeff Kirsher }
6027adfc5217SJeff Kirsher 
6028adfc5217SJeff Kirsher static int
6029adfc5217SJeff Kirsher bnx2_test_intr(struct bnx2 *bp)
6030adfc5217SJeff Kirsher {
6031adfc5217SJeff Kirsher 	int i;
6032adfc5217SJeff Kirsher 	u16 status_idx;
6033adfc5217SJeff Kirsher 
6034adfc5217SJeff Kirsher 	if (!netif_running(bp->dev))
6035adfc5217SJeff Kirsher 		return -ENODEV;
6036adfc5217SJeff Kirsher 
6037e503e066SMichael Chan 	status_idx = BNX2_RD(bp, BNX2_PCICFG_INT_ACK_CMD) & 0xffff;
6038adfc5217SJeff Kirsher 
6039adfc5217SJeff Kirsher 	/* This register is not touched during run-time. */
6040e503e066SMichael Chan 	BNX2_WR(bp, BNX2_HC_COMMAND, bp->hc_cmd | BNX2_HC_COMMAND_COAL_NOW);
6041e503e066SMichael Chan 	BNX2_RD(bp, BNX2_HC_COMMAND);
6042adfc5217SJeff Kirsher 
6043adfc5217SJeff Kirsher 	for (i = 0; i < 10; i++) {
6044e503e066SMichael Chan 		if ((BNX2_RD(bp, BNX2_PCICFG_INT_ACK_CMD) & 0xffff) !=
6045adfc5217SJeff Kirsher 			status_idx) {
6046adfc5217SJeff Kirsher 
6047adfc5217SJeff Kirsher 			break;
6048adfc5217SJeff Kirsher 		}
6049adfc5217SJeff Kirsher 
6050adfc5217SJeff Kirsher 		msleep_interruptible(10);
6051adfc5217SJeff Kirsher 	}
6052adfc5217SJeff Kirsher 	if (i < 10)
6053adfc5217SJeff Kirsher 		return 0;
6054adfc5217SJeff Kirsher 
6055adfc5217SJeff Kirsher 	return -ENODEV;
6056adfc5217SJeff Kirsher }
6057adfc5217SJeff Kirsher 
6058adfc5217SJeff Kirsher /* Determining link for parallel detection. */
6059adfc5217SJeff Kirsher static int
6060adfc5217SJeff Kirsher bnx2_5706_serdes_has_link(struct bnx2 *bp)
6061adfc5217SJeff Kirsher {
6062adfc5217SJeff Kirsher 	u32 mode_ctl, an_dbg, exp;
6063adfc5217SJeff Kirsher 
6064adfc5217SJeff Kirsher 	if (bp->phy_flags & BNX2_PHY_FLAG_NO_PARALLEL)
6065adfc5217SJeff Kirsher 		return 0;
6066adfc5217SJeff Kirsher 
6067adfc5217SJeff Kirsher 	bnx2_write_phy(bp, MII_BNX2_MISC_SHADOW, MISC_SHDW_MODE_CTL);
6068adfc5217SJeff Kirsher 	bnx2_read_phy(bp, MII_BNX2_MISC_SHADOW, &mode_ctl);
6069adfc5217SJeff Kirsher 
6070adfc5217SJeff Kirsher 	if (!(mode_ctl & MISC_SHDW_MODE_CTL_SIG_DET))
6071adfc5217SJeff Kirsher 		return 0;
6072adfc5217SJeff Kirsher 
6073adfc5217SJeff Kirsher 	bnx2_write_phy(bp, MII_BNX2_MISC_SHADOW, MISC_SHDW_AN_DBG);
6074adfc5217SJeff Kirsher 	bnx2_read_phy(bp, MII_BNX2_MISC_SHADOW, &an_dbg);
6075adfc5217SJeff Kirsher 	bnx2_read_phy(bp, MII_BNX2_MISC_SHADOW, &an_dbg);
6076adfc5217SJeff Kirsher 
6077adfc5217SJeff Kirsher 	if (an_dbg & (MISC_SHDW_AN_DBG_NOSYNC | MISC_SHDW_AN_DBG_RUDI_INVALID))
6078adfc5217SJeff Kirsher 		return 0;
6079adfc5217SJeff Kirsher 
6080adfc5217SJeff Kirsher 	bnx2_write_phy(bp, MII_BNX2_DSP_ADDRESS, MII_EXPAND_REG1);
6081adfc5217SJeff Kirsher 	bnx2_read_phy(bp, MII_BNX2_DSP_RW_PORT, &exp);
6082adfc5217SJeff Kirsher 	bnx2_read_phy(bp, MII_BNX2_DSP_RW_PORT, &exp);
6083adfc5217SJeff Kirsher 
6084adfc5217SJeff Kirsher 	if (exp & MII_EXPAND_REG1_RUDI_C)	/* receiving CONFIG */
6085adfc5217SJeff Kirsher 		return 0;
6086adfc5217SJeff Kirsher 
6087adfc5217SJeff Kirsher 	return 1;
6088adfc5217SJeff Kirsher }
6089adfc5217SJeff Kirsher 
6090adfc5217SJeff Kirsher static void
6091adfc5217SJeff Kirsher bnx2_5706_serdes_timer(struct bnx2 *bp)
6092adfc5217SJeff Kirsher {
6093adfc5217SJeff Kirsher 	int check_link = 1;
6094adfc5217SJeff Kirsher 
6095adfc5217SJeff Kirsher 	spin_lock(&bp->phy_lock);
6096adfc5217SJeff Kirsher 	if (bp->serdes_an_pending) {
6097adfc5217SJeff Kirsher 		bp->serdes_an_pending--;
6098adfc5217SJeff Kirsher 		check_link = 0;
6099adfc5217SJeff Kirsher 	} else if ((bp->link_up == 0) && (bp->autoneg & AUTONEG_SPEED)) {
6100adfc5217SJeff Kirsher 		u32 bmcr;
6101adfc5217SJeff Kirsher 
6102adfc5217SJeff Kirsher 		bp->current_interval = BNX2_TIMER_INTERVAL;
6103adfc5217SJeff Kirsher 
6104adfc5217SJeff Kirsher 		bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
6105adfc5217SJeff Kirsher 
6106adfc5217SJeff Kirsher 		if (bmcr & BMCR_ANENABLE) {
6107adfc5217SJeff Kirsher 			if (bnx2_5706_serdes_has_link(bp)) {
6108adfc5217SJeff Kirsher 				bmcr &= ~BMCR_ANENABLE;
6109adfc5217SJeff Kirsher 				bmcr |= BMCR_SPEED1000 | BMCR_FULLDPLX;
6110adfc5217SJeff Kirsher 				bnx2_write_phy(bp, bp->mii_bmcr, bmcr);
6111adfc5217SJeff Kirsher 				bp->phy_flags |= BNX2_PHY_FLAG_PARALLEL_DETECT;
6112adfc5217SJeff Kirsher 			}
6113adfc5217SJeff Kirsher 		}
6114adfc5217SJeff Kirsher 	}
6115adfc5217SJeff Kirsher 	else if ((bp->link_up) && (bp->autoneg & AUTONEG_SPEED) &&
6116adfc5217SJeff Kirsher 		 (bp->phy_flags & BNX2_PHY_FLAG_PARALLEL_DETECT)) {
6117adfc5217SJeff Kirsher 		u32 phy2;
6118adfc5217SJeff Kirsher 
6119adfc5217SJeff Kirsher 		bnx2_write_phy(bp, 0x17, 0x0f01);
6120adfc5217SJeff Kirsher 		bnx2_read_phy(bp, 0x15, &phy2);
6121adfc5217SJeff Kirsher 		if (phy2 & 0x20) {
6122adfc5217SJeff Kirsher 			u32 bmcr;
6123adfc5217SJeff Kirsher 
6124adfc5217SJeff Kirsher 			bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
6125adfc5217SJeff Kirsher 			bmcr |= BMCR_ANENABLE;
6126adfc5217SJeff Kirsher 			bnx2_write_phy(bp, bp->mii_bmcr, bmcr);
6127adfc5217SJeff Kirsher 
6128adfc5217SJeff Kirsher 			bp->phy_flags &= ~BNX2_PHY_FLAG_PARALLEL_DETECT;
6129adfc5217SJeff Kirsher 		}
6130adfc5217SJeff Kirsher 	} else
6131adfc5217SJeff Kirsher 		bp->current_interval = BNX2_TIMER_INTERVAL;
6132adfc5217SJeff Kirsher 
6133adfc5217SJeff Kirsher 	if (check_link) {
6134adfc5217SJeff Kirsher 		u32 val;
6135adfc5217SJeff Kirsher 
6136adfc5217SJeff Kirsher 		bnx2_write_phy(bp, MII_BNX2_MISC_SHADOW, MISC_SHDW_AN_DBG);
6137adfc5217SJeff Kirsher 		bnx2_read_phy(bp, MII_BNX2_MISC_SHADOW, &val);
6138adfc5217SJeff Kirsher 		bnx2_read_phy(bp, MII_BNX2_MISC_SHADOW, &val);
6139adfc5217SJeff Kirsher 
6140adfc5217SJeff Kirsher 		if (bp->link_up && (val & MISC_SHDW_AN_DBG_NOSYNC)) {
6141adfc5217SJeff Kirsher 			if (!(bp->phy_flags & BNX2_PHY_FLAG_FORCED_DOWN)) {
6142adfc5217SJeff Kirsher 				bnx2_5706s_force_link_dn(bp, 1);
6143adfc5217SJeff Kirsher 				bp->phy_flags |= BNX2_PHY_FLAG_FORCED_DOWN;
6144adfc5217SJeff Kirsher 			} else
6145adfc5217SJeff Kirsher 				bnx2_set_link(bp);
6146adfc5217SJeff Kirsher 		} else if (!bp->link_up && !(val & MISC_SHDW_AN_DBG_NOSYNC))
6147adfc5217SJeff Kirsher 			bnx2_set_link(bp);
6148adfc5217SJeff Kirsher 	}
6149adfc5217SJeff Kirsher 	spin_unlock(&bp->phy_lock);
6150adfc5217SJeff Kirsher }
6151adfc5217SJeff Kirsher 
6152adfc5217SJeff Kirsher static void
6153adfc5217SJeff Kirsher bnx2_5708_serdes_timer(struct bnx2 *bp)
6154adfc5217SJeff Kirsher {
6155adfc5217SJeff Kirsher 	if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
6156adfc5217SJeff Kirsher 		return;
6157adfc5217SJeff Kirsher 
6158adfc5217SJeff Kirsher 	if ((bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE) == 0) {
6159adfc5217SJeff Kirsher 		bp->serdes_an_pending = 0;
6160adfc5217SJeff Kirsher 		return;
6161adfc5217SJeff Kirsher 	}
6162adfc5217SJeff Kirsher 
6163adfc5217SJeff Kirsher 	spin_lock(&bp->phy_lock);
6164adfc5217SJeff Kirsher 	if (bp->serdes_an_pending)
6165adfc5217SJeff Kirsher 		bp->serdes_an_pending--;
6166adfc5217SJeff Kirsher 	else if ((bp->link_up == 0) && (bp->autoneg & AUTONEG_SPEED)) {
6167adfc5217SJeff Kirsher 		u32 bmcr;
6168adfc5217SJeff Kirsher 
6169adfc5217SJeff Kirsher 		bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
6170adfc5217SJeff Kirsher 		if (bmcr & BMCR_ANENABLE) {
6171adfc5217SJeff Kirsher 			bnx2_enable_forced_2g5(bp);
6172adfc5217SJeff Kirsher 			bp->current_interval = BNX2_SERDES_FORCED_TIMEOUT;
6173adfc5217SJeff Kirsher 		} else {
6174adfc5217SJeff Kirsher 			bnx2_disable_forced_2g5(bp);
6175adfc5217SJeff Kirsher 			bp->serdes_an_pending = 2;
6176adfc5217SJeff Kirsher 			bp->current_interval = BNX2_TIMER_INTERVAL;
6177adfc5217SJeff Kirsher 		}
6178adfc5217SJeff Kirsher 
6179adfc5217SJeff Kirsher 	} else
6180adfc5217SJeff Kirsher 		bp->current_interval = BNX2_TIMER_INTERVAL;
6181adfc5217SJeff Kirsher 
6182adfc5217SJeff Kirsher 	spin_unlock(&bp->phy_lock);
6183adfc5217SJeff Kirsher }
6184adfc5217SJeff Kirsher 
6185adfc5217SJeff Kirsher static void
6186e99e88a9SKees Cook bnx2_timer(struct timer_list *t)
6187adfc5217SJeff Kirsher {
6188e99e88a9SKees Cook 	struct bnx2 *bp = from_timer(bp, t, timer);
6189adfc5217SJeff Kirsher 
6190adfc5217SJeff Kirsher 	if (!netif_running(bp->dev))
6191adfc5217SJeff Kirsher 		return;
6192adfc5217SJeff Kirsher 
6193adfc5217SJeff Kirsher 	if (atomic_read(&bp->intr_sem) != 0)
6194adfc5217SJeff Kirsher 		goto bnx2_restart_timer;
6195adfc5217SJeff Kirsher 
6196adfc5217SJeff Kirsher 	if ((bp->flags & (BNX2_FLAG_USING_MSI | BNX2_FLAG_ONE_SHOT_MSI)) ==
6197adfc5217SJeff Kirsher 	     BNX2_FLAG_USING_MSI)
6198adfc5217SJeff Kirsher 		bnx2_chk_missed_msi(bp);
6199adfc5217SJeff Kirsher 
6200adfc5217SJeff Kirsher 	bnx2_send_heart_beat(bp);
6201adfc5217SJeff Kirsher 
6202adfc5217SJeff Kirsher 	bp->stats_blk->stat_FwRxDrop =
6203adfc5217SJeff Kirsher 		bnx2_reg_rd_ind(bp, BNX2_FW_RX_DROP_COUNT);
6204adfc5217SJeff Kirsher 
6205adfc5217SJeff Kirsher 	/* workaround occasional corrupted counters */
6206adfc5217SJeff Kirsher 	if ((bp->flags & BNX2_FLAG_BROKEN_STATS) && bp->stats_ticks)
6207e503e066SMichael Chan 		BNX2_WR(bp, BNX2_HC_COMMAND, bp->hc_cmd |
6208adfc5217SJeff Kirsher 			BNX2_HC_COMMAND_STATS_NOW);
6209adfc5217SJeff Kirsher 
6210adfc5217SJeff Kirsher 	if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
62114ce45e02SMichael Chan 		if (BNX2_CHIP(bp) == BNX2_CHIP_5706)
6212adfc5217SJeff Kirsher 			bnx2_5706_serdes_timer(bp);
6213adfc5217SJeff Kirsher 		else
6214adfc5217SJeff Kirsher 			bnx2_5708_serdes_timer(bp);
6215adfc5217SJeff Kirsher 	}
6216adfc5217SJeff Kirsher 
6217adfc5217SJeff Kirsher bnx2_restart_timer:
6218adfc5217SJeff Kirsher 	mod_timer(&bp->timer, jiffies + bp->current_interval);
6219adfc5217SJeff Kirsher }
6220adfc5217SJeff Kirsher 
6221adfc5217SJeff Kirsher static int
6222adfc5217SJeff Kirsher bnx2_request_irq(struct bnx2 *bp)
6223adfc5217SJeff Kirsher {
6224adfc5217SJeff Kirsher 	unsigned long flags;
6225adfc5217SJeff Kirsher 	struct bnx2_irq *irq;
6226adfc5217SJeff Kirsher 	int rc = 0, i;
6227adfc5217SJeff Kirsher 
6228adfc5217SJeff Kirsher 	if (bp->flags & BNX2_FLAG_USING_MSI_OR_MSIX)
6229adfc5217SJeff Kirsher 		flags = 0;
6230adfc5217SJeff Kirsher 	else
6231adfc5217SJeff Kirsher 		flags = IRQF_SHARED;
6232adfc5217SJeff Kirsher 
6233adfc5217SJeff Kirsher 	for (i = 0; i < bp->irq_nvecs; i++) {
6234adfc5217SJeff Kirsher 		irq = &bp->irq_tbl[i];
6235adfc5217SJeff Kirsher 		rc = request_irq(irq->vector, irq->handler, flags, irq->name,
6236adfc5217SJeff Kirsher 				 &bp->bnx2_napi[i]);
6237adfc5217SJeff Kirsher 		if (rc)
6238adfc5217SJeff Kirsher 			break;
6239adfc5217SJeff Kirsher 		irq->requested = 1;
6240adfc5217SJeff Kirsher 	}
6241adfc5217SJeff Kirsher 	return rc;
6242adfc5217SJeff Kirsher }
6243adfc5217SJeff Kirsher 
6244adfc5217SJeff Kirsher static void
6245adfc5217SJeff Kirsher __bnx2_free_irq(struct bnx2 *bp)
6246adfc5217SJeff Kirsher {
6247adfc5217SJeff Kirsher 	struct bnx2_irq *irq;
6248adfc5217SJeff Kirsher 	int i;
6249adfc5217SJeff Kirsher 
6250adfc5217SJeff Kirsher 	for (i = 0; i < bp->irq_nvecs; i++) {
6251adfc5217SJeff Kirsher 		irq = &bp->irq_tbl[i];
6252adfc5217SJeff Kirsher 		if (irq->requested)
6253adfc5217SJeff Kirsher 			free_irq(irq->vector, &bp->bnx2_napi[i]);
6254adfc5217SJeff Kirsher 		irq->requested = 0;
6255adfc5217SJeff Kirsher 	}
6256adfc5217SJeff Kirsher }
6257adfc5217SJeff Kirsher 
6258adfc5217SJeff Kirsher static void
6259adfc5217SJeff Kirsher bnx2_free_irq(struct bnx2 *bp)
6260adfc5217SJeff Kirsher {
6261adfc5217SJeff Kirsher 
6262adfc5217SJeff Kirsher 	__bnx2_free_irq(bp);
6263adfc5217SJeff Kirsher 	if (bp->flags & BNX2_FLAG_USING_MSI)
6264adfc5217SJeff Kirsher 		pci_disable_msi(bp->pdev);
6265adfc5217SJeff Kirsher 	else if (bp->flags & BNX2_FLAG_USING_MSIX)
6266adfc5217SJeff Kirsher 		pci_disable_msix(bp->pdev);
6267adfc5217SJeff Kirsher 
6268adfc5217SJeff Kirsher 	bp->flags &= ~(BNX2_FLAG_USING_MSI_OR_MSIX | BNX2_FLAG_ONE_SHOT_MSI);
6269adfc5217SJeff Kirsher }
6270adfc5217SJeff Kirsher 
6271adfc5217SJeff Kirsher static void
6272adfc5217SJeff Kirsher bnx2_enable_msix(struct bnx2 *bp, int msix_vecs)
6273adfc5217SJeff Kirsher {
6274f2a2dfebSAlexander Gordeev 	int i, total_vecs;
6275adfc5217SJeff Kirsher 	struct msix_entry msix_ent[BNX2_MAX_MSIX_VEC];
6276adfc5217SJeff Kirsher 	struct net_device *dev = bp->dev;
6277adfc5217SJeff Kirsher 	const int len = sizeof(bp->irq_tbl[0].name);
6278adfc5217SJeff Kirsher 
6279adfc5217SJeff Kirsher 	bnx2_setup_msix_tbl(bp);
6280e503e066SMichael Chan 	BNX2_WR(bp, BNX2_PCI_MSIX_CONTROL, BNX2_MAX_MSIX_HW_VEC - 1);
6281e503e066SMichael Chan 	BNX2_WR(bp, BNX2_PCI_MSIX_TBL_OFF_BIR, BNX2_PCI_GRC_WINDOW2_BASE);
6282e503e066SMichael Chan 	BNX2_WR(bp, BNX2_PCI_MSIX_PBA_OFF_BIT, BNX2_PCI_GRC_WINDOW3_BASE);
6283adfc5217SJeff Kirsher 
6284adfc5217SJeff Kirsher 	/*  Need to flush the previous three writes to ensure MSI-X
6285adfc5217SJeff Kirsher 	 *  is setup properly */
6286e503e066SMichael Chan 	BNX2_RD(bp, BNX2_PCI_MSIX_CONTROL);
6287adfc5217SJeff Kirsher 
6288adfc5217SJeff Kirsher 	for (i = 0; i < BNX2_MAX_MSIX_VEC; i++) {
6289adfc5217SJeff Kirsher 		msix_ent[i].entry = i;
6290adfc5217SJeff Kirsher 		msix_ent[i].vector = 0;
6291adfc5217SJeff Kirsher 	}
6292adfc5217SJeff Kirsher 
6293adfc5217SJeff Kirsher 	total_vecs = msix_vecs;
6294adfc5217SJeff Kirsher #ifdef BCM_CNIC
6295adfc5217SJeff Kirsher 	total_vecs++;
6296adfc5217SJeff Kirsher #endif
6297f2a2dfebSAlexander Gordeev 	total_vecs = pci_enable_msix_range(bp->pdev, msix_ent,
6298f2a2dfebSAlexander Gordeev 					   BNX2_MIN_MSIX_VEC, total_vecs);
6299f2a2dfebSAlexander Gordeev 	if (total_vecs < 0)
6300adfc5217SJeff Kirsher 		return;
6301adfc5217SJeff Kirsher 
6302adfc5217SJeff Kirsher 	msix_vecs = total_vecs;
6303adfc5217SJeff Kirsher #ifdef BCM_CNIC
6304adfc5217SJeff Kirsher 	msix_vecs--;
6305adfc5217SJeff Kirsher #endif
6306adfc5217SJeff Kirsher 	bp->irq_nvecs = msix_vecs;
6307adfc5217SJeff Kirsher 	bp->flags |= BNX2_FLAG_USING_MSIX | BNX2_FLAG_ONE_SHOT_MSI;
6308adfc5217SJeff Kirsher 	for (i = 0; i < total_vecs; i++) {
6309adfc5217SJeff Kirsher 		bp->irq_tbl[i].vector = msix_ent[i].vector;
6310adfc5217SJeff Kirsher 		snprintf(bp->irq_tbl[i].name, len, "%s-%d", dev->name, i);
6311adfc5217SJeff Kirsher 		bp->irq_tbl[i].handler = bnx2_msi_1shot;
6312adfc5217SJeff Kirsher 	}
6313adfc5217SJeff Kirsher }
6314adfc5217SJeff Kirsher 
6315adfc5217SJeff Kirsher static int
6316adfc5217SJeff Kirsher bnx2_setup_int_mode(struct bnx2 *bp, int dis_msi)
6317adfc5217SJeff Kirsher {
63180a742128SYuval Mintz 	int cpus = netif_get_num_default_rss_queues();
6319b033281fSMichael Chan 	int msix_vecs;
6320b033281fSMichael Chan 
6321b033281fSMichael Chan 	if (!bp->num_req_rx_rings)
6322b033281fSMichael Chan 		msix_vecs = max(cpus + 1, bp->num_req_tx_rings);
6323b033281fSMichael Chan 	else if (!bp->num_req_tx_rings)
6324b033281fSMichael Chan 		msix_vecs = max(cpus, bp->num_req_rx_rings);
6325b033281fSMichael Chan 	else
6326b033281fSMichael Chan 		msix_vecs = max(bp->num_req_rx_rings, bp->num_req_tx_rings);
6327b033281fSMichael Chan 
6328b033281fSMichael Chan 	msix_vecs = min(msix_vecs, RX_MAX_RINGS);
6329adfc5217SJeff Kirsher 
6330adfc5217SJeff Kirsher 	bp->irq_tbl[0].handler = bnx2_interrupt;
6331adfc5217SJeff Kirsher 	strcpy(bp->irq_tbl[0].name, bp->dev->name);
6332adfc5217SJeff Kirsher 	bp->irq_nvecs = 1;
6333adfc5217SJeff Kirsher 	bp->irq_tbl[0].vector = bp->pdev->irq;
6334adfc5217SJeff Kirsher 
6335adfc5217SJeff Kirsher 	if ((bp->flags & BNX2_FLAG_MSIX_CAP) && !dis_msi)
6336adfc5217SJeff Kirsher 		bnx2_enable_msix(bp, msix_vecs);
6337adfc5217SJeff Kirsher 
6338adfc5217SJeff Kirsher 	if ((bp->flags & BNX2_FLAG_MSI_CAP) && !dis_msi &&
6339adfc5217SJeff Kirsher 	    !(bp->flags & BNX2_FLAG_USING_MSIX)) {
6340adfc5217SJeff Kirsher 		if (pci_enable_msi(bp->pdev) == 0) {
6341adfc5217SJeff Kirsher 			bp->flags |= BNX2_FLAG_USING_MSI;
63424ce45e02SMichael Chan 			if (BNX2_CHIP(bp) == BNX2_CHIP_5709) {
6343adfc5217SJeff Kirsher 				bp->flags |= BNX2_FLAG_ONE_SHOT_MSI;
6344adfc5217SJeff Kirsher 				bp->irq_tbl[0].handler = bnx2_msi_1shot;
6345adfc5217SJeff Kirsher 			} else
6346adfc5217SJeff Kirsher 				bp->irq_tbl[0].handler = bnx2_msi;
6347adfc5217SJeff Kirsher 
6348adfc5217SJeff Kirsher 			bp->irq_tbl[0].vector = bp->pdev->irq;
6349adfc5217SJeff Kirsher 		}
6350adfc5217SJeff Kirsher 	}
6351adfc5217SJeff Kirsher 
6352b033281fSMichael Chan 	if (!bp->num_req_tx_rings)
6353adfc5217SJeff Kirsher 		bp->num_tx_rings = rounddown_pow_of_two(bp->irq_nvecs);
6354b033281fSMichael Chan 	else
6355b033281fSMichael Chan 		bp->num_tx_rings = min(bp->irq_nvecs, bp->num_req_tx_rings);
6356b033281fSMichael Chan 
6357b033281fSMichael Chan 	if (!bp->num_req_rx_rings)
6358b033281fSMichael Chan 		bp->num_rx_rings = bp->irq_nvecs;
6359b033281fSMichael Chan 	else
6360b033281fSMichael Chan 		bp->num_rx_rings = min(bp->irq_nvecs, bp->num_req_rx_rings);
6361b033281fSMichael Chan 
6362adfc5217SJeff Kirsher 	netif_set_real_num_tx_queues(bp->dev, bp->num_tx_rings);
6363adfc5217SJeff Kirsher 
6364adfc5217SJeff Kirsher 	return netif_set_real_num_rx_queues(bp->dev, bp->num_rx_rings);
6365adfc5217SJeff Kirsher }
6366adfc5217SJeff Kirsher 
6367adfc5217SJeff Kirsher /* Called with rtnl_lock */
6368adfc5217SJeff Kirsher static int
6369adfc5217SJeff Kirsher bnx2_open(struct net_device *dev)
6370adfc5217SJeff Kirsher {
6371adfc5217SJeff Kirsher 	struct bnx2 *bp = netdev_priv(dev);
6372adfc5217SJeff Kirsher 	int rc;
6373adfc5217SJeff Kirsher 
63745d0d4b91SBaoquan He 	rc = bnx2_request_firmware(bp);
63755d0d4b91SBaoquan He 	if (rc < 0)
63765d0d4b91SBaoquan He 		goto out;
63775d0d4b91SBaoquan He 
6378adfc5217SJeff Kirsher 	netif_carrier_off(dev);
6379adfc5217SJeff Kirsher 
6380adfc5217SJeff Kirsher 	bnx2_disable_int(bp);
6381adfc5217SJeff Kirsher 
6382adfc5217SJeff Kirsher 	rc = bnx2_setup_int_mode(bp, disable_msi);
6383adfc5217SJeff Kirsher 	if (rc)
6384adfc5217SJeff Kirsher 		goto open_err;
6385adfc5217SJeff Kirsher 	bnx2_init_napi(bp);
6386adfc5217SJeff Kirsher 	bnx2_napi_enable(bp);
6387adfc5217SJeff Kirsher 	rc = bnx2_alloc_mem(bp);
6388adfc5217SJeff Kirsher 	if (rc)
6389adfc5217SJeff Kirsher 		goto open_err;
6390adfc5217SJeff Kirsher 
6391adfc5217SJeff Kirsher 	rc = bnx2_request_irq(bp);
6392adfc5217SJeff Kirsher 	if (rc)
6393adfc5217SJeff Kirsher 		goto open_err;
6394adfc5217SJeff Kirsher 
6395adfc5217SJeff Kirsher 	rc = bnx2_init_nic(bp, 1);
6396adfc5217SJeff Kirsher 	if (rc)
6397adfc5217SJeff Kirsher 		goto open_err;
6398adfc5217SJeff Kirsher 
6399adfc5217SJeff Kirsher 	mod_timer(&bp->timer, jiffies + bp->current_interval);
6400adfc5217SJeff Kirsher 
6401adfc5217SJeff Kirsher 	atomic_set(&bp->intr_sem, 0);
6402adfc5217SJeff Kirsher 
6403adfc5217SJeff Kirsher 	memset(bp->temp_stats_blk, 0, sizeof(struct statistics_block));
6404adfc5217SJeff Kirsher 
6405adfc5217SJeff Kirsher 	bnx2_enable_int(bp);
6406adfc5217SJeff Kirsher 
6407adfc5217SJeff Kirsher 	if (bp->flags & BNX2_FLAG_USING_MSI) {
6408adfc5217SJeff Kirsher 		/* Test MSI to make sure it is working
6409adfc5217SJeff Kirsher 		 * If MSI test fails, go back to INTx mode
6410adfc5217SJeff Kirsher 		 */
6411adfc5217SJeff Kirsher 		if (bnx2_test_intr(bp) != 0) {
6412adfc5217SJeff Kirsher 			netdev_warn(bp->dev, "No interrupt was generated using MSI, switching to INTx mode. Please report this failure to the PCI maintainer and include system chipset information.\n");
6413adfc5217SJeff Kirsher 
6414adfc5217SJeff Kirsher 			bnx2_disable_int(bp);
6415adfc5217SJeff Kirsher 			bnx2_free_irq(bp);
6416adfc5217SJeff Kirsher 
6417adfc5217SJeff Kirsher 			bnx2_setup_int_mode(bp, 1);
6418adfc5217SJeff Kirsher 
6419adfc5217SJeff Kirsher 			rc = bnx2_init_nic(bp, 0);
6420adfc5217SJeff Kirsher 
6421adfc5217SJeff Kirsher 			if (!rc)
6422adfc5217SJeff Kirsher 				rc = bnx2_request_irq(bp);
6423adfc5217SJeff Kirsher 
6424adfc5217SJeff Kirsher 			if (rc) {
6425adfc5217SJeff Kirsher 				del_timer_sync(&bp->timer);
6426adfc5217SJeff Kirsher 				goto open_err;
6427adfc5217SJeff Kirsher 			}
6428adfc5217SJeff Kirsher 			bnx2_enable_int(bp);
6429adfc5217SJeff Kirsher 		}
6430adfc5217SJeff Kirsher 	}
6431adfc5217SJeff Kirsher 	if (bp->flags & BNX2_FLAG_USING_MSI)
6432adfc5217SJeff Kirsher 		netdev_info(dev, "using MSI\n");
6433adfc5217SJeff Kirsher 	else if (bp->flags & BNX2_FLAG_USING_MSIX)
6434adfc5217SJeff Kirsher 		netdev_info(dev, "using MSIX\n");
6435adfc5217SJeff Kirsher 
6436adfc5217SJeff Kirsher 	netif_tx_start_all_queues(dev);
64377880b72eSfrançois romieu out:
64387880b72eSfrançois romieu 	return rc;
6439adfc5217SJeff Kirsher 
6440adfc5217SJeff Kirsher open_err:
6441adfc5217SJeff Kirsher 	bnx2_napi_disable(bp);
6442adfc5217SJeff Kirsher 	bnx2_free_skbs(bp);
6443adfc5217SJeff Kirsher 	bnx2_free_irq(bp);
6444adfc5217SJeff Kirsher 	bnx2_free_mem(bp);
6445adfc5217SJeff Kirsher 	bnx2_del_napi(bp);
64465d0d4b91SBaoquan He 	bnx2_release_firmware(bp);
64477880b72eSfrançois romieu 	goto out;
6448adfc5217SJeff Kirsher }
6449adfc5217SJeff Kirsher 
6450adfc5217SJeff Kirsher static void
6451adfc5217SJeff Kirsher bnx2_reset_task(struct work_struct *work)
6452adfc5217SJeff Kirsher {
6453adfc5217SJeff Kirsher 	struct bnx2 *bp = container_of(work, struct bnx2, reset_task);
6454adfc5217SJeff Kirsher 	int rc;
6455efdfad32SMichael Chan 	u16 pcicmd;
6456adfc5217SJeff Kirsher 
6457adfc5217SJeff Kirsher 	rtnl_lock();
6458adfc5217SJeff Kirsher 	if (!netif_running(bp->dev)) {
6459adfc5217SJeff Kirsher 		rtnl_unlock();
6460adfc5217SJeff Kirsher 		return;
6461adfc5217SJeff Kirsher 	}
6462adfc5217SJeff Kirsher 
6463adfc5217SJeff Kirsher 	bnx2_netif_stop(bp, true);
6464adfc5217SJeff Kirsher 
6465efdfad32SMichael Chan 	pci_read_config_word(bp->pdev, PCI_COMMAND, &pcicmd);
6466efdfad32SMichael Chan 	if (!(pcicmd & PCI_COMMAND_MEMORY)) {
6467efdfad32SMichael Chan 		/* in case PCI block has reset */
6468efdfad32SMichael Chan 		pci_restore_state(bp->pdev);
6469efdfad32SMichael Chan 		pci_save_state(bp->pdev);
6470efdfad32SMichael Chan 	}
6471adfc5217SJeff Kirsher 	rc = bnx2_init_nic(bp, 1);
6472adfc5217SJeff Kirsher 	if (rc) {
6473adfc5217SJeff Kirsher 		netdev_err(bp->dev, "failed to reset NIC, closing\n");
6474adfc5217SJeff Kirsher 		bnx2_napi_enable(bp);
6475adfc5217SJeff Kirsher 		dev_close(bp->dev);
6476adfc5217SJeff Kirsher 		rtnl_unlock();
6477adfc5217SJeff Kirsher 		return;
6478adfc5217SJeff Kirsher 	}
6479adfc5217SJeff Kirsher 
6480adfc5217SJeff Kirsher 	atomic_set(&bp->intr_sem, 1);
6481adfc5217SJeff Kirsher 	bnx2_netif_start(bp, true);
6482adfc5217SJeff Kirsher 	rtnl_unlock();
6483adfc5217SJeff Kirsher }
6484adfc5217SJeff Kirsher 
6485555069daSMichael Chan #define BNX2_FTQ_ENTRY(ftq) { __stringify(ftq##FTQ_CTL), BNX2_##ftq##FTQ_CTL }
6486555069daSMichael Chan 
6487555069daSMichael Chan static void
6488555069daSMichael Chan bnx2_dump_ftq(struct bnx2 *bp)
6489555069daSMichael Chan {
6490555069daSMichael Chan 	int i;
6491555069daSMichael Chan 	u32 reg, bdidx, cid, valid;
6492555069daSMichael Chan 	struct net_device *dev = bp->dev;
6493555069daSMichael Chan 	static const struct ftq_reg {
6494555069daSMichael Chan 		char *name;
6495555069daSMichael Chan 		u32 off;
6496555069daSMichael Chan 	} ftq_arr[] = {
6497555069daSMichael Chan 		BNX2_FTQ_ENTRY(RV2P_P),
6498555069daSMichael Chan 		BNX2_FTQ_ENTRY(RV2P_T),
6499555069daSMichael Chan 		BNX2_FTQ_ENTRY(RV2P_M),
6500555069daSMichael Chan 		BNX2_FTQ_ENTRY(TBDR_),
6501555069daSMichael Chan 		BNX2_FTQ_ENTRY(TDMA_),
6502555069daSMichael Chan 		BNX2_FTQ_ENTRY(TXP_),
6503555069daSMichael Chan 		BNX2_FTQ_ENTRY(TXP_),
6504555069daSMichael Chan 		BNX2_FTQ_ENTRY(TPAT_),
6505555069daSMichael Chan 		BNX2_FTQ_ENTRY(RXP_C),
6506555069daSMichael Chan 		BNX2_FTQ_ENTRY(RXP_),
6507555069daSMichael Chan 		BNX2_FTQ_ENTRY(COM_COMXQ_),
6508555069daSMichael Chan 		BNX2_FTQ_ENTRY(COM_COMTQ_),
6509555069daSMichael Chan 		BNX2_FTQ_ENTRY(COM_COMQ_),
6510555069daSMichael Chan 		BNX2_FTQ_ENTRY(CP_CPQ_),
6511555069daSMichael Chan 	};
6512555069daSMichael Chan 
6513555069daSMichael Chan 	netdev_err(dev, "<--- start FTQ dump --->\n");
6514555069daSMichael Chan 	for (i = 0; i < ARRAY_SIZE(ftq_arr); i++)
6515555069daSMichael Chan 		netdev_err(dev, "%s %08x\n", ftq_arr[i].name,
6516555069daSMichael Chan 			   bnx2_reg_rd_ind(bp, ftq_arr[i].off));
6517555069daSMichael Chan 
6518555069daSMichael Chan 	netdev_err(dev, "CPU states:\n");
6519555069daSMichael Chan 	for (reg = BNX2_TXP_CPU_MODE; reg <= BNX2_CP_CPU_MODE; reg += 0x40000)
6520555069daSMichael Chan 		netdev_err(dev, "%06x mode %x state %x evt_mask %x pc %x pc %x instr %x\n",
6521555069daSMichael Chan 			   reg, bnx2_reg_rd_ind(bp, reg),
6522555069daSMichael Chan 			   bnx2_reg_rd_ind(bp, reg + 4),
6523555069daSMichael Chan 			   bnx2_reg_rd_ind(bp, reg + 8),
6524555069daSMichael Chan 			   bnx2_reg_rd_ind(bp, reg + 0x1c),
6525555069daSMichael Chan 			   bnx2_reg_rd_ind(bp, reg + 0x1c),
6526555069daSMichael Chan 			   bnx2_reg_rd_ind(bp, reg + 0x20));
6527555069daSMichael Chan 
6528555069daSMichael Chan 	netdev_err(dev, "<--- end FTQ dump --->\n");
6529555069daSMichael Chan 	netdev_err(dev, "<--- start TBDC dump --->\n");
6530555069daSMichael Chan 	netdev_err(dev, "TBDC free cnt: %ld\n",
6531e503e066SMichael Chan 		   BNX2_RD(bp, BNX2_TBDC_STATUS) & BNX2_TBDC_STATUS_FREE_CNT);
6532555069daSMichael Chan 	netdev_err(dev, "LINE     CID  BIDX   CMD  VALIDS\n");
6533555069daSMichael Chan 	for (i = 0; i < 0x20; i++) {
6534555069daSMichael Chan 		int j = 0;
6535555069daSMichael Chan 
6536e503e066SMichael Chan 		BNX2_WR(bp, BNX2_TBDC_BD_ADDR, i);
6537e503e066SMichael Chan 		BNX2_WR(bp, BNX2_TBDC_CAM_OPCODE,
6538555069daSMichael Chan 			BNX2_TBDC_CAM_OPCODE_OPCODE_CAM_READ);
6539e503e066SMichael Chan 		BNX2_WR(bp, BNX2_TBDC_COMMAND, BNX2_TBDC_COMMAND_CMD_REG_ARB);
6540e503e066SMichael Chan 		while ((BNX2_RD(bp, BNX2_TBDC_COMMAND) &
6541555069daSMichael Chan 			BNX2_TBDC_COMMAND_CMD_REG_ARB) && j < 100)
6542555069daSMichael Chan 			j++;
6543555069daSMichael Chan 
6544e503e066SMichael Chan 		cid = BNX2_RD(bp, BNX2_TBDC_CID);
6545e503e066SMichael Chan 		bdidx = BNX2_RD(bp, BNX2_TBDC_BIDX);
6546e503e066SMichael Chan 		valid = BNX2_RD(bp, BNX2_TBDC_CAM_OPCODE);
6547555069daSMichael Chan 		netdev_err(dev, "%02x    %06x  %04lx   %02x    [%x]\n",
6548555069daSMichael Chan 			   i, cid, bdidx & BNX2_TBDC_BDIDX_BDIDX,
6549555069daSMichael Chan 			   bdidx >> 24, (valid >> 8) & 0x0ff);
6550555069daSMichael Chan 	}
6551555069daSMichael Chan 	netdev_err(dev, "<--- end TBDC dump --->\n");
6552555069daSMichael Chan }
6553555069daSMichael Chan 
6554adfc5217SJeff Kirsher static void
6555adfc5217SJeff Kirsher bnx2_dump_state(struct bnx2 *bp)
6556adfc5217SJeff Kirsher {
6557adfc5217SJeff Kirsher 	struct net_device *dev = bp->dev;
6558adfc5217SJeff Kirsher 	u32 val1, val2;
6559adfc5217SJeff Kirsher 
6560adfc5217SJeff Kirsher 	pci_read_config_dword(bp->pdev, PCI_COMMAND, &val1);
6561adfc5217SJeff Kirsher 	netdev_err(dev, "DEBUG: intr_sem[%x] PCI_CMD[%08x]\n",
6562adfc5217SJeff Kirsher 		   atomic_read(&bp->intr_sem), val1);
6563adfc5217SJeff Kirsher 	pci_read_config_dword(bp->pdev, bp->pm_cap + PCI_PM_CTRL, &val1);
6564adfc5217SJeff Kirsher 	pci_read_config_dword(bp->pdev, BNX2_PCICFG_MISC_CONFIG, &val2);
6565adfc5217SJeff Kirsher 	netdev_err(dev, "DEBUG: PCI_PM[%08x] PCI_MISC_CFG[%08x]\n", val1, val2);
6566adfc5217SJeff Kirsher 	netdev_err(dev, "DEBUG: EMAC_TX_STATUS[%08x] EMAC_RX_STATUS[%08x]\n",
6567e503e066SMichael Chan 		   BNX2_RD(bp, BNX2_EMAC_TX_STATUS),
6568e503e066SMichael Chan 		   BNX2_RD(bp, BNX2_EMAC_RX_STATUS));
6569adfc5217SJeff Kirsher 	netdev_err(dev, "DEBUG: RPM_MGMT_PKT_CTRL[%08x]\n",
6570e503e066SMichael Chan 		   BNX2_RD(bp, BNX2_RPM_MGMT_PKT_CTRL));
6571adfc5217SJeff Kirsher 	netdev_err(dev, "DEBUG: HC_STATS_INTERRUPT_STATUS[%08x]\n",
6572e503e066SMichael Chan 		   BNX2_RD(bp, BNX2_HC_STATS_INTERRUPT_STATUS));
6573adfc5217SJeff Kirsher 	if (bp->flags & BNX2_FLAG_USING_MSIX)
6574adfc5217SJeff Kirsher 		netdev_err(dev, "DEBUG: PBA[%08x]\n",
6575e503e066SMichael Chan 			   BNX2_RD(bp, BNX2_PCI_GRC_WINDOW3_BASE));
6576adfc5217SJeff Kirsher }
6577adfc5217SJeff Kirsher 
6578adfc5217SJeff Kirsher static void
6579adfc5217SJeff Kirsher bnx2_tx_timeout(struct net_device *dev)
6580adfc5217SJeff Kirsher {
6581adfc5217SJeff Kirsher 	struct bnx2 *bp = netdev_priv(dev);
6582adfc5217SJeff Kirsher 
6583555069daSMichael Chan 	bnx2_dump_ftq(bp);
6584adfc5217SJeff Kirsher 	bnx2_dump_state(bp);
6585adfc5217SJeff Kirsher 	bnx2_dump_mcp_state(bp);
6586adfc5217SJeff Kirsher 
6587adfc5217SJeff Kirsher 	/* This allows the netif to be shutdown gracefully before resetting */
6588adfc5217SJeff Kirsher 	schedule_work(&bp->reset_task);
6589adfc5217SJeff Kirsher }
6590adfc5217SJeff Kirsher 
6591adfc5217SJeff Kirsher /* Called with netif_tx_lock.
6592adfc5217SJeff Kirsher  * bnx2_tx_int() runs without netif_tx_lock unless it needs to call
6593adfc5217SJeff Kirsher  * netif_wake_queue().
6594adfc5217SJeff Kirsher  */
6595adfc5217SJeff Kirsher static netdev_tx_t
6596adfc5217SJeff Kirsher bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev)
6597adfc5217SJeff Kirsher {
6598adfc5217SJeff Kirsher 	struct bnx2 *bp = netdev_priv(dev);
6599adfc5217SJeff Kirsher 	dma_addr_t mapping;
66002bc4078eSMichael Chan 	struct bnx2_tx_bd *txbd;
66012bc4078eSMichael Chan 	struct bnx2_sw_tx_bd *tx_buf;
6602adfc5217SJeff Kirsher 	u32 len, vlan_tag_flags, last_frag, mss;
6603adfc5217SJeff Kirsher 	u16 prod, ring_prod;
6604adfc5217SJeff Kirsher 	int i;
6605adfc5217SJeff Kirsher 	struct bnx2_napi *bnapi;
6606adfc5217SJeff Kirsher 	struct bnx2_tx_ring_info *txr;
6607adfc5217SJeff Kirsher 	struct netdev_queue *txq;
6608adfc5217SJeff Kirsher 
6609adfc5217SJeff Kirsher 	/*  Determine which tx ring we will be placed on */
6610adfc5217SJeff Kirsher 	i = skb_get_queue_mapping(skb);
6611adfc5217SJeff Kirsher 	bnapi = &bp->bnx2_napi[i];
6612adfc5217SJeff Kirsher 	txr = &bnapi->tx_ring;
6613adfc5217SJeff Kirsher 	txq = netdev_get_tx_queue(dev, i);
6614adfc5217SJeff Kirsher 
6615adfc5217SJeff Kirsher 	if (unlikely(bnx2_tx_avail(bp, txr) <
6616adfc5217SJeff Kirsher 	    (skb_shinfo(skb)->nr_frags + 1))) {
6617adfc5217SJeff Kirsher 		netif_tx_stop_queue(txq);
6618adfc5217SJeff Kirsher 		netdev_err(dev, "BUG! Tx ring full when queue awake!\n");
6619adfc5217SJeff Kirsher 
6620adfc5217SJeff Kirsher 		return NETDEV_TX_BUSY;
6621adfc5217SJeff Kirsher 	}
6622adfc5217SJeff Kirsher 	len = skb_headlen(skb);
6623adfc5217SJeff Kirsher 	prod = txr->tx_prod;
66242bc4078eSMichael Chan 	ring_prod = BNX2_TX_RING_IDX(prod);
6625adfc5217SJeff Kirsher 
6626adfc5217SJeff Kirsher 	vlan_tag_flags = 0;
6627adfc5217SJeff Kirsher 	if (skb->ip_summed == CHECKSUM_PARTIAL) {
6628adfc5217SJeff Kirsher 		vlan_tag_flags |= TX_BD_FLAGS_TCP_UDP_CKSUM;
6629adfc5217SJeff Kirsher 	}
6630adfc5217SJeff Kirsher 
6631df8a39deSJiri Pirko 	if (skb_vlan_tag_present(skb)) {
6632adfc5217SJeff Kirsher 		vlan_tag_flags |=
6633df8a39deSJiri Pirko 			(TX_BD_FLAGS_VLAN_TAG | (skb_vlan_tag_get(skb) << 16));
6634adfc5217SJeff Kirsher 	}
6635adfc5217SJeff Kirsher 
6636adfc5217SJeff Kirsher 	if ((mss = skb_shinfo(skb)->gso_size)) {
6637adfc5217SJeff Kirsher 		u32 tcp_opt_len;
6638adfc5217SJeff Kirsher 		struct iphdr *iph;
6639adfc5217SJeff Kirsher 
6640adfc5217SJeff Kirsher 		vlan_tag_flags |= TX_BD_FLAGS_SW_LSO;
6641adfc5217SJeff Kirsher 
6642adfc5217SJeff Kirsher 		tcp_opt_len = tcp_optlen(skb);
6643adfc5217SJeff Kirsher 
6644adfc5217SJeff Kirsher 		if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6) {
6645adfc5217SJeff Kirsher 			u32 tcp_off = skb_transport_offset(skb) -
6646adfc5217SJeff Kirsher 				      sizeof(struct ipv6hdr) - ETH_HLEN;
6647adfc5217SJeff Kirsher 
6648adfc5217SJeff Kirsher 			vlan_tag_flags |= ((tcp_opt_len >> 2) << 8) |
6649adfc5217SJeff Kirsher 					  TX_BD_FLAGS_SW_FLAGS;
6650adfc5217SJeff Kirsher 			if (likely(tcp_off == 0))
6651adfc5217SJeff Kirsher 				vlan_tag_flags &= ~TX_BD_FLAGS_TCP6_OFF0_MSK;
6652adfc5217SJeff Kirsher 			else {
6653adfc5217SJeff Kirsher 				tcp_off >>= 3;
6654adfc5217SJeff Kirsher 				vlan_tag_flags |= ((tcp_off & 0x3) <<
6655adfc5217SJeff Kirsher 						   TX_BD_FLAGS_TCP6_OFF0_SHL) |
6656adfc5217SJeff Kirsher 						  ((tcp_off & 0x10) <<
6657adfc5217SJeff Kirsher 						   TX_BD_FLAGS_TCP6_OFF4_SHL);
6658adfc5217SJeff Kirsher 				mss |= (tcp_off & 0xc) << TX_BD_TCP6_OFF2_SHL;
6659adfc5217SJeff Kirsher 			}
6660adfc5217SJeff Kirsher 		} else {
6661adfc5217SJeff Kirsher 			iph = ip_hdr(skb);
6662adfc5217SJeff Kirsher 			if (tcp_opt_len || (iph->ihl > 5)) {
6663adfc5217SJeff Kirsher 				vlan_tag_flags |= ((iph->ihl - 5) +
6664adfc5217SJeff Kirsher 						   (tcp_opt_len >> 2)) << 8;
6665adfc5217SJeff Kirsher 			}
6666adfc5217SJeff Kirsher 		}
6667adfc5217SJeff Kirsher 	} else
6668adfc5217SJeff Kirsher 		mss = 0;
6669adfc5217SJeff Kirsher 
6670adfc5217SJeff Kirsher 	mapping = dma_map_single(&bp->pdev->dev, skb->data, len, PCI_DMA_TODEVICE);
6671adfc5217SJeff Kirsher 	if (dma_mapping_error(&bp->pdev->dev, mapping)) {
6672f458b2eeSEric W. Biederman 		dev_kfree_skb_any(skb);
6673adfc5217SJeff Kirsher 		return NETDEV_TX_OK;
6674adfc5217SJeff Kirsher 	}
6675adfc5217SJeff Kirsher 
6676adfc5217SJeff Kirsher 	tx_buf = &txr->tx_buf_ring[ring_prod];
6677adfc5217SJeff Kirsher 	tx_buf->skb = skb;
6678adfc5217SJeff Kirsher 	dma_unmap_addr_set(tx_buf, mapping, mapping);
6679adfc5217SJeff Kirsher 
6680adfc5217SJeff Kirsher 	txbd = &txr->tx_desc_ring[ring_prod];
6681adfc5217SJeff Kirsher 
6682adfc5217SJeff Kirsher 	txbd->tx_bd_haddr_hi = (u64) mapping >> 32;
6683adfc5217SJeff Kirsher 	txbd->tx_bd_haddr_lo = (u64) mapping & 0xffffffff;
6684adfc5217SJeff Kirsher 	txbd->tx_bd_mss_nbytes = len | (mss << 16);
6685adfc5217SJeff Kirsher 	txbd->tx_bd_vlan_tag_flags = vlan_tag_flags | TX_BD_FLAGS_START;
6686adfc5217SJeff Kirsher 
6687adfc5217SJeff Kirsher 	last_frag = skb_shinfo(skb)->nr_frags;
6688adfc5217SJeff Kirsher 	tx_buf->nr_frags = last_frag;
6689adfc5217SJeff Kirsher 	tx_buf->is_gso = skb_is_gso(skb);
6690adfc5217SJeff Kirsher 
6691adfc5217SJeff Kirsher 	for (i = 0; i < last_frag; i++) {
66929e903e08SEric Dumazet 		const skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
6693adfc5217SJeff Kirsher 
66942bc4078eSMichael Chan 		prod = BNX2_NEXT_TX_BD(prod);
66952bc4078eSMichael Chan 		ring_prod = BNX2_TX_RING_IDX(prod);
6696adfc5217SJeff Kirsher 		txbd = &txr->tx_desc_ring[ring_prod];
6697adfc5217SJeff Kirsher 
66989e903e08SEric Dumazet 		len = skb_frag_size(frag);
6699b7b6a688SIan Campbell 		mapping = skb_frag_dma_map(&bp->pdev->dev, frag, 0, len,
67005d6bcdfeSIan Campbell 					   DMA_TO_DEVICE);
6701adfc5217SJeff Kirsher 		if (dma_mapping_error(&bp->pdev->dev, mapping))
6702adfc5217SJeff Kirsher 			goto dma_error;
6703adfc5217SJeff Kirsher 		dma_unmap_addr_set(&txr->tx_buf_ring[ring_prod], mapping,
6704adfc5217SJeff Kirsher 				   mapping);
6705adfc5217SJeff Kirsher 
6706adfc5217SJeff Kirsher 		txbd->tx_bd_haddr_hi = (u64) mapping >> 32;
6707adfc5217SJeff Kirsher 		txbd->tx_bd_haddr_lo = (u64) mapping & 0xffffffff;
6708adfc5217SJeff Kirsher 		txbd->tx_bd_mss_nbytes = len | (mss << 16);
6709adfc5217SJeff Kirsher 		txbd->tx_bd_vlan_tag_flags = vlan_tag_flags;
6710adfc5217SJeff Kirsher 
6711adfc5217SJeff Kirsher 	}
6712adfc5217SJeff Kirsher 	txbd->tx_bd_vlan_tag_flags |= TX_BD_FLAGS_END;
6713adfc5217SJeff Kirsher 
671494bf91baSVlad Zolotarov 	/* Sync BD data before updating TX mailbox */
671594bf91baSVlad Zolotarov 	wmb();
671694bf91baSVlad Zolotarov 
6717e9831909SEric Dumazet 	netdev_tx_sent_queue(txq, skb->len);
6718e9831909SEric Dumazet 
67192bc4078eSMichael Chan 	prod = BNX2_NEXT_TX_BD(prod);
6720adfc5217SJeff Kirsher 	txr->tx_prod_bseq += skb->len;
6721adfc5217SJeff Kirsher 
6722e503e066SMichael Chan 	BNX2_WR16(bp, txr->tx_bidx_addr, prod);
6723e503e066SMichael Chan 	BNX2_WR(bp, txr->tx_bseq_addr, txr->tx_prod_bseq);
6724adfc5217SJeff Kirsher 
6725adfc5217SJeff Kirsher 	mmiowb();
6726adfc5217SJeff Kirsher 
6727adfc5217SJeff Kirsher 	txr->tx_prod = prod;
6728adfc5217SJeff Kirsher 
6729adfc5217SJeff Kirsher 	if (unlikely(bnx2_tx_avail(bp, txr) <= MAX_SKB_FRAGS)) {
6730adfc5217SJeff Kirsher 		netif_tx_stop_queue(txq);
6731adfc5217SJeff Kirsher 
6732adfc5217SJeff Kirsher 		/* netif_tx_stop_queue() must be done before checking
6733adfc5217SJeff Kirsher 		 * tx index in bnx2_tx_avail() below, because in
6734adfc5217SJeff Kirsher 		 * bnx2_tx_int(), we update tx index before checking for
6735adfc5217SJeff Kirsher 		 * netif_tx_queue_stopped().
6736adfc5217SJeff Kirsher 		 */
6737adfc5217SJeff Kirsher 		smp_mb();
6738adfc5217SJeff Kirsher 		if (bnx2_tx_avail(bp, txr) > bp->tx_wake_thresh)
6739adfc5217SJeff Kirsher 			netif_tx_wake_queue(txq);
6740adfc5217SJeff Kirsher 	}
6741adfc5217SJeff Kirsher 
6742adfc5217SJeff Kirsher 	return NETDEV_TX_OK;
6743adfc5217SJeff Kirsher dma_error:
6744adfc5217SJeff Kirsher 	/* save value of frag that failed */
6745adfc5217SJeff Kirsher 	last_frag = i;
6746adfc5217SJeff Kirsher 
6747adfc5217SJeff Kirsher 	/* start back at beginning and unmap skb */
6748adfc5217SJeff Kirsher 	prod = txr->tx_prod;
67492bc4078eSMichael Chan 	ring_prod = BNX2_TX_RING_IDX(prod);
6750adfc5217SJeff Kirsher 	tx_buf = &txr->tx_buf_ring[ring_prod];
6751adfc5217SJeff Kirsher 	tx_buf->skb = NULL;
6752adfc5217SJeff Kirsher 	dma_unmap_single(&bp->pdev->dev, dma_unmap_addr(tx_buf, mapping),
6753adfc5217SJeff Kirsher 			 skb_headlen(skb), PCI_DMA_TODEVICE);
6754adfc5217SJeff Kirsher 
6755adfc5217SJeff Kirsher 	/* unmap remaining mapped pages */
6756adfc5217SJeff Kirsher 	for (i = 0; i < last_frag; i++) {
67572bc4078eSMichael Chan 		prod = BNX2_NEXT_TX_BD(prod);
67582bc4078eSMichael Chan 		ring_prod = BNX2_TX_RING_IDX(prod);
6759adfc5217SJeff Kirsher 		tx_buf = &txr->tx_buf_ring[ring_prod];
6760adfc5217SJeff Kirsher 		dma_unmap_page(&bp->pdev->dev, dma_unmap_addr(tx_buf, mapping),
67619e903e08SEric Dumazet 			       skb_frag_size(&skb_shinfo(skb)->frags[i]),
6762adfc5217SJeff Kirsher 			       PCI_DMA_TODEVICE);
6763adfc5217SJeff Kirsher 	}
6764adfc5217SJeff Kirsher 
6765f458b2eeSEric W. Biederman 	dev_kfree_skb_any(skb);
6766adfc5217SJeff Kirsher 	return NETDEV_TX_OK;
6767adfc5217SJeff Kirsher }
6768adfc5217SJeff Kirsher 
6769adfc5217SJeff Kirsher /* Called with rtnl_lock */
6770adfc5217SJeff Kirsher static int
6771adfc5217SJeff Kirsher bnx2_close(struct net_device *dev)
6772adfc5217SJeff Kirsher {
6773adfc5217SJeff Kirsher 	struct bnx2 *bp = netdev_priv(dev);
6774adfc5217SJeff Kirsher 
6775adfc5217SJeff Kirsher 	bnx2_disable_int_sync(bp);
6776adfc5217SJeff Kirsher 	bnx2_napi_disable(bp);
6777d2e553bcSMichael Chan 	netif_tx_disable(dev);
6778adfc5217SJeff Kirsher 	del_timer_sync(&bp->timer);
6779adfc5217SJeff Kirsher 	bnx2_shutdown_chip(bp);
6780adfc5217SJeff Kirsher 	bnx2_free_irq(bp);
6781adfc5217SJeff Kirsher 	bnx2_free_skbs(bp);
6782adfc5217SJeff Kirsher 	bnx2_free_mem(bp);
6783adfc5217SJeff Kirsher 	bnx2_del_napi(bp);
6784adfc5217SJeff Kirsher 	bp->link_up = 0;
6785adfc5217SJeff Kirsher 	netif_carrier_off(bp->dev);
6786adfc5217SJeff Kirsher 	return 0;
6787adfc5217SJeff Kirsher }
6788adfc5217SJeff Kirsher 
6789adfc5217SJeff Kirsher static void
6790adfc5217SJeff Kirsher bnx2_save_stats(struct bnx2 *bp)
6791adfc5217SJeff Kirsher {
6792adfc5217SJeff Kirsher 	u32 *hw_stats = (u32 *) bp->stats_blk;
6793adfc5217SJeff Kirsher 	u32 *temp_stats = (u32 *) bp->temp_stats_blk;
6794adfc5217SJeff Kirsher 	int i;
6795adfc5217SJeff Kirsher 
6796adfc5217SJeff Kirsher 	/* The 1st 10 counters are 64-bit counters */
6797adfc5217SJeff Kirsher 	for (i = 0; i < 20; i += 2) {
6798adfc5217SJeff Kirsher 		u32 hi;
6799adfc5217SJeff Kirsher 		u64 lo;
6800adfc5217SJeff Kirsher 
6801adfc5217SJeff Kirsher 		hi = temp_stats[i] + hw_stats[i];
6802adfc5217SJeff Kirsher 		lo = (u64) temp_stats[i + 1] + (u64) hw_stats[i + 1];
6803adfc5217SJeff Kirsher 		if (lo > 0xffffffff)
6804adfc5217SJeff Kirsher 			hi++;
6805adfc5217SJeff Kirsher 		temp_stats[i] = hi;
6806adfc5217SJeff Kirsher 		temp_stats[i + 1] = lo & 0xffffffff;
6807adfc5217SJeff Kirsher 	}
6808adfc5217SJeff Kirsher 
6809adfc5217SJeff Kirsher 	for ( ; i < sizeof(struct statistics_block) / 4; i++)
6810adfc5217SJeff Kirsher 		temp_stats[i] += hw_stats[i];
6811adfc5217SJeff Kirsher }
6812adfc5217SJeff Kirsher 
6813adfc5217SJeff Kirsher #define GET_64BIT_NET_STATS64(ctr)		\
6814adfc5217SJeff Kirsher 	(((u64) (ctr##_hi) << 32) + (u64) (ctr##_lo))
6815adfc5217SJeff Kirsher 
6816adfc5217SJeff Kirsher #define GET_64BIT_NET_STATS(ctr)				\
6817adfc5217SJeff Kirsher 	GET_64BIT_NET_STATS64(bp->stats_blk->ctr) +		\
6818adfc5217SJeff Kirsher 	GET_64BIT_NET_STATS64(bp->temp_stats_blk->ctr)
6819adfc5217SJeff Kirsher 
6820adfc5217SJeff Kirsher #define GET_32BIT_NET_STATS(ctr)				\
6821adfc5217SJeff Kirsher 	(unsigned long) (bp->stats_blk->ctr +			\
6822adfc5217SJeff Kirsher 			 bp->temp_stats_blk->ctr)
6823adfc5217SJeff Kirsher 
6824bc1f4470Sstephen hemminger static void
6825adfc5217SJeff Kirsher bnx2_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *net_stats)
6826adfc5217SJeff Kirsher {
6827adfc5217SJeff Kirsher 	struct bnx2 *bp = netdev_priv(dev);
6828adfc5217SJeff Kirsher 
6829b8aac410SVarsha Rao 	if (!bp->stats_blk)
6830bc1f4470Sstephen hemminger 		return;
6831adfc5217SJeff Kirsher 
6832adfc5217SJeff Kirsher 	net_stats->rx_packets =
6833adfc5217SJeff Kirsher 		GET_64BIT_NET_STATS(stat_IfHCInUcastPkts) +
6834adfc5217SJeff Kirsher 		GET_64BIT_NET_STATS(stat_IfHCInMulticastPkts) +
6835adfc5217SJeff Kirsher 		GET_64BIT_NET_STATS(stat_IfHCInBroadcastPkts);
6836adfc5217SJeff Kirsher 
6837adfc5217SJeff Kirsher 	net_stats->tx_packets =
6838adfc5217SJeff Kirsher 		GET_64BIT_NET_STATS(stat_IfHCOutUcastPkts) +
6839adfc5217SJeff Kirsher 		GET_64BIT_NET_STATS(stat_IfHCOutMulticastPkts) +
6840adfc5217SJeff Kirsher 		GET_64BIT_NET_STATS(stat_IfHCOutBroadcastPkts);
6841adfc5217SJeff Kirsher 
6842adfc5217SJeff Kirsher 	net_stats->rx_bytes =
6843adfc5217SJeff Kirsher 		GET_64BIT_NET_STATS(stat_IfHCInOctets);
6844adfc5217SJeff Kirsher 
6845adfc5217SJeff Kirsher 	net_stats->tx_bytes =
6846adfc5217SJeff Kirsher 		GET_64BIT_NET_STATS(stat_IfHCOutOctets);
6847adfc5217SJeff Kirsher 
6848adfc5217SJeff Kirsher 	net_stats->multicast =
6849adfc5217SJeff Kirsher 		GET_64BIT_NET_STATS(stat_IfHCInMulticastPkts);
6850adfc5217SJeff Kirsher 
6851adfc5217SJeff Kirsher 	net_stats->collisions =
6852adfc5217SJeff Kirsher 		GET_32BIT_NET_STATS(stat_EtherStatsCollisions);
6853adfc5217SJeff Kirsher 
6854adfc5217SJeff Kirsher 	net_stats->rx_length_errors =
6855adfc5217SJeff Kirsher 		GET_32BIT_NET_STATS(stat_EtherStatsUndersizePkts) +
6856adfc5217SJeff Kirsher 		GET_32BIT_NET_STATS(stat_EtherStatsOverrsizePkts);
6857adfc5217SJeff Kirsher 
6858adfc5217SJeff Kirsher 	net_stats->rx_over_errors =
6859adfc5217SJeff Kirsher 		GET_32BIT_NET_STATS(stat_IfInFTQDiscards) +
6860adfc5217SJeff Kirsher 		GET_32BIT_NET_STATS(stat_IfInMBUFDiscards);
6861adfc5217SJeff Kirsher 
6862adfc5217SJeff Kirsher 	net_stats->rx_frame_errors =
6863adfc5217SJeff Kirsher 		GET_32BIT_NET_STATS(stat_Dot3StatsAlignmentErrors);
6864adfc5217SJeff Kirsher 
6865adfc5217SJeff Kirsher 	net_stats->rx_crc_errors =
6866adfc5217SJeff Kirsher 		GET_32BIT_NET_STATS(stat_Dot3StatsFCSErrors);
6867adfc5217SJeff Kirsher 
6868adfc5217SJeff Kirsher 	net_stats->rx_errors = net_stats->rx_length_errors +
6869adfc5217SJeff Kirsher 		net_stats->rx_over_errors + net_stats->rx_frame_errors +
6870adfc5217SJeff Kirsher 		net_stats->rx_crc_errors;
6871adfc5217SJeff Kirsher 
6872adfc5217SJeff Kirsher 	net_stats->tx_aborted_errors =
6873adfc5217SJeff Kirsher 		GET_32BIT_NET_STATS(stat_Dot3StatsExcessiveCollisions) +
6874adfc5217SJeff Kirsher 		GET_32BIT_NET_STATS(stat_Dot3StatsLateCollisions);
6875adfc5217SJeff Kirsher 
68764ce45e02SMichael Chan 	if ((BNX2_CHIP(bp) == BNX2_CHIP_5706) ||
68774ce45e02SMichael Chan 	    (BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5708_A0))
6878adfc5217SJeff Kirsher 		net_stats->tx_carrier_errors = 0;
6879adfc5217SJeff Kirsher 	else {
6880adfc5217SJeff Kirsher 		net_stats->tx_carrier_errors =
6881adfc5217SJeff Kirsher 			GET_32BIT_NET_STATS(stat_Dot3StatsCarrierSenseErrors);
6882adfc5217SJeff Kirsher 	}
6883adfc5217SJeff Kirsher 
6884adfc5217SJeff Kirsher 	net_stats->tx_errors =
6885adfc5217SJeff Kirsher 		GET_32BIT_NET_STATS(stat_emac_tx_stat_dot3statsinternalmactransmiterrors) +
6886adfc5217SJeff Kirsher 		net_stats->tx_aborted_errors +
6887adfc5217SJeff Kirsher 		net_stats->tx_carrier_errors;
6888adfc5217SJeff Kirsher 
6889adfc5217SJeff Kirsher 	net_stats->rx_missed_errors =
6890adfc5217SJeff Kirsher 		GET_32BIT_NET_STATS(stat_IfInFTQDiscards) +
6891adfc5217SJeff Kirsher 		GET_32BIT_NET_STATS(stat_IfInMBUFDiscards) +
6892adfc5217SJeff Kirsher 		GET_32BIT_NET_STATS(stat_FwRxDrop);
6893adfc5217SJeff Kirsher 
6894adfc5217SJeff Kirsher }
6895adfc5217SJeff Kirsher 
6896adfc5217SJeff Kirsher /* All ethtool functions called with rtnl_lock */
6897adfc5217SJeff Kirsher 
6898adfc5217SJeff Kirsher static int
689908e10d4dSPhilippe Reynes bnx2_get_link_ksettings(struct net_device *dev,
690008e10d4dSPhilippe Reynes 			struct ethtool_link_ksettings *cmd)
6901adfc5217SJeff Kirsher {
6902adfc5217SJeff Kirsher 	struct bnx2 *bp = netdev_priv(dev);
6903adfc5217SJeff Kirsher 	int support_serdes = 0, support_copper = 0;
690408e10d4dSPhilippe Reynes 	u32 supported, advertising;
6905adfc5217SJeff Kirsher 
690608e10d4dSPhilippe Reynes 	supported = SUPPORTED_Autoneg;
6907adfc5217SJeff Kirsher 	if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP) {
6908adfc5217SJeff Kirsher 		support_serdes = 1;
6909adfc5217SJeff Kirsher 		support_copper = 1;
6910adfc5217SJeff Kirsher 	} else if (bp->phy_port == PORT_FIBRE)
6911adfc5217SJeff Kirsher 		support_serdes = 1;
6912adfc5217SJeff Kirsher 	else
6913adfc5217SJeff Kirsher 		support_copper = 1;
6914adfc5217SJeff Kirsher 
6915adfc5217SJeff Kirsher 	if (support_serdes) {
691608e10d4dSPhilippe Reynes 		supported |= SUPPORTED_1000baseT_Full |
6917adfc5217SJeff Kirsher 			SUPPORTED_FIBRE;
6918adfc5217SJeff Kirsher 		if (bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE)
691908e10d4dSPhilippe Reynes 			supported |= SUPPORTED_2500baseX_Full;
6920adfc5217SJeff Kirsher 	}
6921adfc5217SJeff Kirsher 	if (support_copper) {
692208e10d4dSPhilippe Reynes 		supported |= SUPPORTED_10baseT_Half |
6923adfc5217SJeff Kirsher 			SUPPORTED_10baseT_Full |
6924adfc5217SJeff Kirsher 			SUPPORTED_100baseT_Half |
6925adfc5217SJeff Kirsher 			SUPPORTED_100baseT_Full |
6926adfc5217SJeff Kirsher 			SUPPORTED_1000baseT_Full |
6927adfc5217SJeff Kirsher 			SUPPORTED_TP;
6928adfc5217SJeff Kirsher 	}
6929adfc5217SJeff Kirsher 
6930adfc5217SJeff Kirsher 	spin_lock_bh(&bp->phy_lock);
693108e10d4dSPhilippe Reynes 	cmd->base.port = bp->phy_port;
693208e10d4dSPhilippe Reynes 	advertising = bp->advertising;
6933adfc5217SJeff Kirsher 
6934adfc5217SJeff Kirsher 	if (bp->autoneg & AUTONEG_SPEED) {
693508e10d4dSPhilippe Reynes 		cmd->base.autoneg = AUTONEG_ENABLE;
6936adfc5217SJeff Kirsher 	} else {
693708e10d4dSPhilippe Reynes 		cmd->base.autoneg = AUTONEG_DISABLE;
6938adfc5217SJeff Kirsher 	}
6939adfc5217SJeff Kirsher 
6940adfc5217SJeff Kirsher 	if (netif_carrier_ok(dev)) {
694108e10d4dSPhilippe Reynes 		cmd->base.speed = bp->line_speed;
694208e10d4dSPhilippe Reynes 		cmd->base.duplex = bp->duplex;
69434016baddSMichael Chan 		if (!(bp->phy_flags & BNX2_PHY_FLAG_SERDES)) {
69444016baddSMichael Chan 			if (bp->phy_flags & BNX2_PHY_FLAG_MDIX)
694508e10d4dSPhilippe Reynes 				cmd->base.eth_tp_mdix = ETH_TP_MDI_X;
69464016baddSMichael Chan 			else
694708e10d4dSPhilippe Reynes 				cmd->base.eth_tp_mdix = ETH_TP_MDI;
69484016baddSMichael Chan 		}
6949adfc5217SJeff Kirsher 	}
6950adfc5217SJeff Kirsher 	else {
695108e10d4dSPhilippe Reynes 		cmd->base.speed = SPEED_UNKNOWN;
695208e10d4dSPhilippe Reynes 		cmd->base.duplex = DUPLEX_UNKNOWN;
6953adfc5217SJeff Kirsher 	}
6954adfc5217SJeff Kirsher 	spin_unlock_bh(&bp->phy_lock);
6955adfc5217SJeff Kirsher 
695608e10d4dSPhilippe Reynes 	cmd->base.phy_address = bp->phy_addr;
695708e10d4dSPhilippe Reynes 
695808e10d4dSPhilippe Reynes 	ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.supported,
695908e10d4dSPhilippe Reynes 						supported);
696008e10d4dSPhilippe Reynes 	ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.advertising,
696108e10d4dSPhilippe Reynes 						advertising);
6962adfc5217SJeff Kirsher 
6963adfc5217SJeff Kirsher 	return 0;
6964adfc5217SJeff Kirsher }
6965adfc5217SJeff Kirsher 
6966adfc5217SJeff Kirsher static int
696708e10d4dSPhilippe Reynes bnx2_set_link_ksettings(struct net_device *dev,
696808e10d4dSPhilippe Reynes 			const struct ethtool_link_ksettings *cmd)
6969adfc5217SJeff Kirsher {
6970adfc5217SJeff Kirsher 	struct bnx2 *bp = netdev_priv(dev);
6971adfc5217SJeff Kirsher 	u8 autoneg = bp->autoneg;
6972adfc5217SJeff Kirsher 	u8 req_duplex = bp->req_duplex;
6973adfc5217SJeff Kirsher 	u16 req_line_speed = bp->req_line_speed;
6974adfc5217SJeff Kirsher 	u32 advertising = bp->advertising;
6975adfc5217SJeff Kirsher 	int err = -EINVAL;
6976adfc5217SJeff Kirsher 
6977adfc5217SJeff Kirsher 	spin_lock_bh(&bp->phy_lock);
6978adfc5217SJeff Kirsher 
697908e10d4dSPhilippe Reynes 	if (cmd->base.port != PORT_TP && cmd->base.port != PORT_FIBRE)
6980adfc5217SJeff Kirsher 		goto err_out_unlock;
6981adfc5217SJeff Kirsher 
698208e10d4dSPhilippe Reynes 	if (cmd->base.port != bp->phy_port &&
6983adfc5217SJeff Kirsher 	    !(bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP))
6984adfc5217SJeff Kirsher 		goto err_out_unlock;
6985adfc5217SJeff Kirsher 
6986adfc5217SJeff Kirsher 	/* If device is down, we can store the settings only if the user
6987adfc5217SJeff Kirsher 	 * is setting the currently active port.
6988adfc5217SJeff Kirsher 	 */
698908e10d4dSPhilippe Reynes 	if (!netif_running(dev) && cmd->base.port != bp->phy_port)
6990adfc5217SJeff Kirsher 		goto err_out_unlock;
6991adfc5217SJeff Kirsher 
699208e10d4dSPhilippe Reynes 	if (cmd->base.autoneg == AUTONEG_ENABLE) {
6993adfc5217SJeff Kirsher 		autoneg |= AUTONEG_SPEED;
6994adfc5217SJeff Kirsher 
699508e10d4dSPhilippe Reynes 		ethtool_convert_link_mode_to_legacy_u32(
699608e10d4dSPhilippe Reynes 			&advertising, cmd->link_modes.advertising);
699708e10d4dSPhilippe Reynes 
699808e10d4dSPhilippe Reynes 		if (cmd->base.port == PORT_TP) {
6999adfc5217SJeff Kirsher 			advertising &= ETHTOOL_ALL_COPPER_SPEED;
7000adfc5217SJeff Kirsher 			if (!advertising)
7001adfc5217SJeff Kirsher 				advertising = ETHTOOL_ALL_COPPER_SPEED;
7002adfc5217SJeff Kirsher 		} else {
7003adfc5217SJeff Kirsher 			advertising &= ETHTOOL_ALL_FIBRE_SPEED;
7004adfc5217SJeff Kirsher 			if (!advertising)
7005adfc5217SJeff Kirsher 				advertising = ETHTOOL_ALL_FIBRE_SPEED;
7006adfc5217SJeff Kirsher 		}
7007adfc5217SJeff Kirsher 		advertising |= ADVERTISED_Autoneg;
7008adfc5217SJeff Kirsher 	}
7009adfc5217SJeff Kirsher 	else {
701008e10d4dSPhilippe Reynes 		u32 speed = cmd->base.speed;
701108e10d4dSPhilippe Reynes 
701208e10d4dSPhilippe Reynes 		if (cmd->base.port == PORT_FIBRE) {
7013adfc5217SJeff Kirsher 			if ((speed != SPEED_1000 &&
7014adfc5217SJeff Kirsher 			     speed != SPEED_2500) ||
701508e10d4dSPhilippe Reynes 			    (cmd->base.duplex != DUPLEX_FULL))
7016adfc5217SJeff Kirsher 				goto err_out_unlock;
7017adfc5217SJeff Kirsher 
7018adfc5217SJeff Kirsher 			if (speed == SPEED_2500 &&
7019adfc5217SJeff Kirsher 			    !(bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE))
7020adfc5217SJeff Kirsher 				goto err_out_unlock;
7021adfc5217SJeff Kirsher 		} else if (speed == SPEED_1000 || speed == SPEED_2500)
7022adfc5217SJeff Kirsher 			goto err_out_unlock;
7023adfc5217SJeff Kirsher 
7024adfc5217SJeff Kirsher 		autoneg &= ~AUTONEG_SPEED;
7025adfc5217SJeff Kirsher 		req_line_speed = speed;
702608e10d4dSPhilippe Reynes 		req_duplex = cmd->base.duplex;
7027adfc5217SJeff Kirsher 		advertising = 0;
7028adfc5217SJeff Kirsher 	}
7029adfc5217SJeff Kirsher 
7030adfc5217SJeff Kirsher 	bp->autoneg = autoneg;
7031adfc5217SJeff Kirsher 	bp->advertising = advertising;
7032adfc5217SJeff Kirsher 	bp->req_line_speed = req_line_speed;
7033adfc5217SJeff Kirsher 	bp->req_duplex = req_duplex;
7034adfc5217SJeff Kirsher 
7035adfc5217SJeff Kirsher 	err = 0;
7036adfc5217SJeff Kirsher 	/* If device is down, the new settings will be picked up when it is
7037adfc5217SJeff Kirsher 	 * brought up.
7038adfc5217SJeff Kirsher 	 */
7039adfc5217SJeff Kirsher 	if (netif_running(dev))
704008e10d4dSPhilippe Reynes 		err = bnx2_setup_phy(bp, cmd->base.port);
7041adfc5217SJeff Kirsher 
7042adfc5217SJeff Kirsher err_out_unlock:
7043adfc5217SJeff Kirsher 	spin_unlock_bh(&bp->phy_lock);
7044adfc5217SJeff Kirsher 
7045adfc5217SJeff Kirsher 	return err;
7046adfc5217SJeff Kirsher }
7047adfc5217SJeff Kirsher 
7048adfc5217SJeff Kirsher static void
7049adfc5217SJeff Kirsher bnx2_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
7050adfc5217SJeff Kirsher {
7051adfc5217SJeff Kirsher 	struct bnx2 *bp = netdev_priv(dev);
7052adfc5217SJeff Kirsher 
705368aad78cSRick Jones 	strlcpy(info->driver, DRV_MODULE_NAME, sizeof(info->driver));
705468aad78cSRick Jones 	strlcpy(info->version, DRV_MODULE_VERSION, sizeof(info->version));
705568aad78cSRick Jones 	strlcpy(info->bus_info, pci_name(bp->pdev), sizeof(info->bus_info));
705668aad78cSRick Jones 	strlcpy(info->fw_version, bp->fw_version, sizeof(info->fw_version));
7057adfc5217SJeff Kirsher }
7058adfc5217SJeff Kirsher 
7059adfc5217SJeff Kirsher #define BNX2_REGDUMP_LEN		(32 * 1024)
7060adfc5217SJeff Kirsher 
7061adfc5217SJeff Kirsher static int
7062adfc5217SJeff Kirsher bnx2_get_regs_len(struct net_device *dev)
7063adfc5217SJeff Kirsher {
7064adfc5217SJeff Kirsher 	return BNX2_REGDUMP_LEN;
7065adfc5217SJeff Kirsher }
7066adfc5217SJeff Kirsher 
7067adfc5217SJeff Kirsher static void
7068adfc5217SJeff Kirsher bnx2_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *_p)
7069adfc5217SJeff Kirsher {
7070adfc5217SJeff Kirsher 	u32 *p = _p, i, offset;
7071adfc5217SJeff Kirsher 	u8 *orig_p = _p;
7072adfc5217SJeff Kirsher 	struct bnx2 *bp = netdev_priv(dev);
7073adfc5217SJeff Kirsher 	static const u32 reg_boundaries[] = {
7074adfc5217SJeff Kirsher 		0x0000, 0x0098, 0x0400, 0x045c,
7075adfc5217SJeff Kirsher 		0x0800, 0x0880, 0x0c00, 0x0c10,
7076adfc5217SJeff Kirsher 		0x0c30, 0x0d08, 0x1000, 0x101c,
7077adfc5217SJeff Kirsher 		0x1040, 0x1048, 0x1080, 0x10a4,
7078adfc5217SJeff Kirsher 		0x1400, 0x1490, 0x1498, 0x14f0,
7079adfc5217SJeff Kirsher 		0x1500, 0x155c, 0x1580, 0x15dc,
7080adfc5217SJeff Kirsher 		0x1600, 0x1658, 0x1680, 0x16d8,
7081adfc5217SJeff Kirsher 		0x1800, 0x1820, 0x1840, 0x1854,
7082adfc5217SJeff Kirsher 		0x1880, 0x1894, 0x1900, 0x1984,
7083adfc5217SJeff Kirsher 		0x1c00, 0x1c0c, 0x1c40, 0x1c54,
7084adfc5217SJeff Kirsher 		0x1c80, 0x1c94, 0x1d00, 0x1d84,
7085adfc5217SJeff Kirsher 		0x2000, 0x2030, 0x23c0, 0x2400,
7086adfc5217SJeff Kirsher 		0x2800, 0x2820, 0x2830, 0x2850,
7087adfc5217SJeff Kirsher 		0x2b40, 0x2c10, 0x2fc0, 0x3058,
7088adfc5217SJeff Kirsher 		0x3c00, 0x3c94, 0x4000, 0x4010,
7089adfc5217SJeff Kirsher 		0x4080, 0x4090, 0x43c0, 0x4458,
7090adfc5217SJeff Kirsher 		0x4c00, 0x4c18, 0x4c40, 0x4c54,
7091adfc5217SJeff Kirsher 		0x4fc0, 0x5010, 0x53c0, 0x5444,
7092adfc5217SJeff Kirsher 		0x5c00, 0x5c18, 0x5c80, 0x5c90,
7093adfc5217SJeff Kirsher 		0x5fc0, 0x6000, 0x6400, 0x6428,
7094adfc5217SJeff Kirsher 		0x6800, 0x6848, 0x684c, 0x6860,
7095adfc5217SJeff Kirsher 		0x6888, 0x6910, 0x8000
7096adfc5217SJeff Kirsher 	};
7097adfc5217SJeff Kirsher 
7098adfc5217SJeff Kirsher 	regs->version = 0;
7099adfc5217SJeff Kirsher 
7100adfc5217SJeff Kirsher 	memset(p, 0, BNX2_REGDUMP_LEN);
7101adfc5217SJeff Kirsher 
7102adfc5217SJeff Kirsher 	if (!netif_running(bp->dev))
7103adfc5217SJeff Kirsher 		return;
7104adfc5217SJeff Kirsher 
7105adfc5217SJeff Kirsher 	i = 0;
7106adfc5217SJeff Kirsher 	offset = reg_boundaries[0];
7107adfc5217SJeff Kirsher 	p += offset;
7108adfc5217SJeff Kirsher 	while (offset < BNX2_REGDUMP_LEN) {
7109e503e066SMichael Chan 		*p++ = BNX2_RD(bp, offset);
7110adfc5217SJeff Kirsher 		offset += 4;
7111adfc5217SJeff Kirsher 		if (offset == reg_boundaries[i + 1]) {
7112adfc5217SJeff Kirsher 			offset = reg_boundaries[i + 2];
7113adfc5217SJeff Kirsher 			p = (u32 *) (orig_p + offset);
7114adfc5217SJeff Kirsher 			i += 2;
7115adfc5217SJeff Kirsher 		}
7116adfc5217SJeff Kirsher 	}
7117adfc5217SJeff Kirsher }
7118adfc5217SJeff Kirsher 
7119adfc5217SJeff Kirsher static void
7120adfc5217SJeff Kirsher bnx2_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
7121adfc5217SJeff Kirsher {
7122adfc5217SJeff Kirsher 	struct bnx2 *bp = netdev_priv(dev);
7123adfc5217SJeff Kirsher 
7124adfc5217SJeff Kirsher 	if (bp->flags & BNX2_FLAG_NO_WOL) {
7125adfc5217SJeff Kirsher 		wol->supported = 0;
7126adfc5217SJeff Kirsher 		wol->wolopts = 0;
7127adfc5217SJeff Kirsher 	}
7128adfc5217SJeff Kirsher 	else {
7129adfc5217SJeff Kirsher 		wol->supported = WAKE_MAGIC;
7130adfc5217SJeff Kirsher 		if (bp->wol)
7131adfc5217SJeff Kirsher 			wol->wolopts = WAKE_MAGIC;
7132adfc5217SJeff Kirsher 		else
7133adfc5217SJeff Kirsher 			wol->wolopts = 0;
7134adfc5217SJeff Kirsher 	}
7135adfc5217SJeff Kirsher 	memset(&wol->sopass, 0, sizeof(wol->sopass));
7136adfc5217SJeff Kirsher }
7137adfc5217SJeff Kirsher 
7138adfc5217SJeff Kirsher static int
7139adfc5217SJeff Kirsher bnx2_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
7140adfc5217SJeff Kirsher {
7141adfc5217SJeff Kirsher 	struct bnx2 *bp = netdev_priv(dev);
7142adfc5217SJeff Kirsher 
7143adfc5217SJeff Kirsher 	if (wol->wolopts & ~WAKE_MAGIC)
7144adfc5217SJeff Kirsher 		return -EINVAL;
7145adfc5217SJeff Kirsher 
7146adfc5217SJeff Kirsher 	if (wol->wolopts & WAKE_MAGIC) {
7147adfc5217SJeff Kirsher 		if (bp->flags & BNX2_FLAG_NO_WOL)
7148adfc5217SJeff Kirsher 			return -EINVAL;
7149adfc5217SJeff Kirsher 
7150adfc5217SJeff Kirsher 		bp->wol = 1;
7151adfc5217SJeff Kirsher 	}
7152adfc5217SJeff Kirsher 	else {
7153adfc5217SJeff Kirsher 		bp->wol = 0;
7154adfc5217SJeff Kirsher 	}
71556d5e85c7SMichael Chan 
71566d5e85c7SMichael Chan 	device_set_wakeup_enable(&bp->pdev->dev, bp->wol);
71576d5e85c7SMichael Chan 
7158adfc5217SJeff Kirsher 	return 0;
7159adfc5217SJeff Kirsher }
7160adfc5217SJeff Kirsher 
7161adfc5217SJeff Kirsher static int
7162adfc5217SJeff Kirsher bnx2_nway_reset(struct net_device *dev)
7163adfc5217SJeff Kirsher {
7164adfc5217SJeff Kirsher 	struct bnx2 *bp = netdev_priv(dev);
7165adfc5217SJeff Kirsher 	u32 bmcr;
7166adfc5217SJeff Kirsher 
7167adfc5217SJeff Kirsher 	if (!netif_running(dev))
7168adfc5217SJeff Kirsher 		return -EAGAIN;
7169adfc5217SJeff Kirsher 
7170adfc5217SJeff Kirsher 	if (!(bp->autoneg & AUTONEG_SPEED)) {
7171adfc5217SJeff Kirsher 		return -EINVAL;
7172adfc5217SJeff Kirsher 	}
7173adfc5217SJeff Kirsher 
7174adfc5217SJeff Kirsher 	spin_lock_bh(&bp->phy_lock);
7175adfc5217SJeff Kirsher 
7176adfc5217SJeff Kirsher 	if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP) {
7177adfc5217SJeff Kirsher 		int rc;
7178adfc5217SJeff Kirsher 
7179adfc5217SJeff Kirsher 		rc = bnx2_setup_remote_phy(bp, bp->phy_port);
7180adfc5217SJeff Kirsher 		spin_unlock_bh(&bp->phy_lock);
7181adfc5217SJeff Kirsher 		return rc;
7182adfc5217SJeff Kirsher 	}
7183adfc5217SJeff Kirsher 
7184adfc5217SJeff Kirsher 	/* Force a link down visible on the other side */
7185adfc5217SJeff Kirsher 	if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
7186adfc5217SJeff Kirsher 		bnx2_write_phy(bp, bp->mii_bmcr, BMCR_LOOPBACK);
7187adfc5217SJeff Kirsher 		spin_unlock_bh(&bp->phy_lock);
7188adfc5217SJeff Kirsher 
7189adfc5217SJeff Kirsher 		msleep(20);
7190adfc5217SJeff Kirsher 
7191adfc5217SJeff Kirsher 		spin_lock_bh(&bp->phy_lock);
7192adfc5217SJeff Kirsher 
7193adfc5217SJeff Kirsher 		bp->current_interval = BNX2_SERDES_AN_TIMEOUT;
7194adfc5217SJeff Kirsher 		bp->serdes_an_pending = 1;
7195adfc5217SJeff Kirsher 		mod_timer(&bp->timer, jiffies + bp->current_interval);
7196adfc5217SJeff Kirsher 	}
7197adfc5217SJeff Kirsher 
7198adfc5217SJeff Kirsher 	bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
7199adfc5217SJeff Kirsher 	bmcr &= ~BMCR_LOOPBACK;
7200adfc5217SJeff Kirsher 	bnx2_write_phy(bp, bp->mii_bmcr, bmcr | BMCR_ANRESTART | BMCR_ANENABLE);
7201adfc5217SJeff Kirsher 
7202adfc5217SJeff Kirsher 	spin_unlock_bh(&bp->phy_lock);
7203adfc5217SJeff Kirsher 
7204adfc5217SJeff Kirsher 	return 0;
7205adfc5217SJeff Kirsher }
7206adfc5217SJeff Kirsher 
7207adfc5217SJeff Kirsher static u32
7208adfc5217SJeff Kirsher bnx2_get_link(struct net_device *dev)
7209adfc5217SJeff Kirsher {
7210adfc5217SJeff Kirsher 	struct bnx2 *bp = netdev_priv(dev);
7211adfc5217SJeff Kirsher 
7212adfc5217SJeff Kirsher 	return bp->link_up;
7213adfc5217SJeff Kirsher }
7214adfc5217SJeff Kirsher 
7215adfc5217SJeff Kirsher static int
7216adfc5217SJeff Kirsher bnx2_get_eeprom_len(struct net_device *dev)
7217adfc5217SJeff Kirsher {
7218adfc5217SJeff Kirsher 	struct bnx2 *bp = netdev_priv(dev);
7219adfc5217SJeff Kirsher 
7220b8aac410SVarsha Rao 	if (!bp->flash_info)
7221adfc5217SJeff Kirsher 		return 0;
7222adfc5217SJeff Kirsher 
7223adfc5217SJeff Kirsher 	return (int) bp->flash_size;
7224adfc5217SJeff Kirsher }
7225adfc5217SJeff Kirsher 
7226adfc5217SJeff Kirsher static int
7227adfc5217SJeff Kirsher bnx2_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
7228adfc5217SJeff Kirsher 		u8 *eebuf)
7229adfc5217SJeff Kirsher {
7230adfc5217SJeff Kirsher 	struct bnx2 *bp = netdev_priv(dev);
7231adfc5217SJeff Kirsher 	int rc;
7232adfc5217SJeff Kirsher 
7233adfc5217SJeff Kirsher 	/* parameters already validated in ethtool_get_eeprom */
7234adfc5217SJeff Kirsher 
7235adfc5217SJeff Kirsher 	rc = bnx2_nvram_read(bp, eeprom->offset, eebuf, eeprom->len);
7236adfc5217SJeff Kirsher 
7237adfc5217SJeff Kirsher 	return rc;
7238adfc5217SJeff Kirsher }
7239adfc5217SJeff Kirsher 
7240adfc5217SJeff Kirsher static int
7241adfc5217SJeff Kirsher bnx2_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
7242adfc5217SJeff Kirsher 		u8 *eebuf)
7243adfc5217SJeff Kirsher {
7244adfc5217SJeff Kirsher 	struct bnx2 *bp = netdev_priv(dev);
7245adfc5217SJeff Kirsher 	int rc;
7246adfc5217SJeff Kirsher 
7247adfc5217SJeff Kirsher 	/* parameters already validated in ethtool_set_eeprom */
7248adfc5217SJeff Kirsher 
7249adfc5217SJeff Kirsher 	rc = bnx2_nvram_write(bp, eeprom->offset, eebuf, eeprom->len);
7250adfc5217SJeff Kirsher 
7251adfc5217SJeff Kirsher 	return rc;
7252adfc5217SJeff Kirsher }
7253adfc5217SJeff Kirsher 
7254adfc5217SJeff Kirsher static int
7255adfc5217SJeff Kirsher bnx2_get_coalesce(struct net_device *dev, struct ethtool_coalesce *coal)
7256adfc5217SJeff Kirsher {
7257adfc5217SJeff Kirsher 	struct bnx2 *bp = netdev_priv(dev);
7258adfc5217SJeff Kirsher 
7259adfc5217SJeff Kirsher 	memset(coal, 0, sizeof(struct ethtool_coalesce));
7260adfc5217SJeff Kirsher 
7261adfc5217SJeff Kirsher 	coal->rx_coalesce_usecs = bp->rx_ticks;
7262adfc5217SJeff Kirsher 	coal->rx_max_coalesced_frames = bp->rx_quick_cons_trip;
7263adfc5217SJeff Kirsher 	coal->rx_coalesce_usecs_irq = bp->rx_ticks_int;
7264adfc5217SJeff Kirsher 	coal->rx_max_coalesced_frames_irq = bp->rx_quick_cons_trip_int;
7265adfc5217SJeff Kirsher 
7266adfc5217SJeff Kirsher 	coal->tx_coalesce_usecs = bp->tx_ticks;
7267adfc5217SJeff Kirsher 	coal->tx_max_coalesced_frames = bp->tx_quick_cons_trip;
7268adfc5217SJeff Kirsher 	coal->tx_coalesce_usecs_irq = bp->tx_ticks_int;
7269adfc5217SJeff Kirsher 	coal->tx_max_coalesced_frames_irq = bp->tx_quick_cons_trip_int;
7270adfc5217SJeff Kirsher 
7271adfc5217SJeff Kirsher 	coal->stats_block_coalesce_usecs = bp->stats_ticks;
7272adfc5217SJeff Kirsher 
7273adfc5217SJeff Kirsher 	return 0;
7274adfc5217SJeff Kirsher }
7275adfc5217SJeff Kirsher 
7276adfc5217SJeff Kirsher static int
7277adfc5217SJeff Kirsher bnx2_set_coalesce(struct net_device *dev, struct ethtool_coalesce *coal)
7278adfc5217SJeff Kirsher {
7279adfc5217SJeff Kirsher 	struct bnx2 *bp = netdev_priv(dev);
7280adfc5217SJeff Kirsher 
7281adfc5217SJeff Kirsher 	bp->rx_ticks = (u16) coal->rx_coalesce_usecs;
7282adfc5217SJeff Kirsher 	if (bp->rx_ticks > 0x3ff) bp->rx_ticks = 0x3ff;
7283adfc5217SJeff Kirsher 
7284adfc5217SJeff Kirsher 	bp->rx_quick_cons_trip = (u16) coal->rx_max_coalesced_frames;
7285adfc5217SJeff Kirsher 	if (bp->rx_quick_cons_trip > 0xff) bp->rx_quick_cons_trip = 0xff;
7286adfc5217SJeff Kirsher 
7287adfc5217SJeff Kirsher 	bp->rx_ticks_int = (u16) coal->rx_coalesce_usecs_irq;
7288adfc5217SJeff Kirsher 	if (bp->rx_ticks_int > 0x3ff) bp->rx_ticks_int = 0x3ff;
7289adfc5217SJeff Kirsher 
7290adfc5217SJeff Kirsher 	bp->rx_quick_cons_trip_int = (u16) coal->rx_max_coalesced_frames_irq;
7291adfc5217SJeff Kirsher 	if (bp->rx_quick_cons_trip_int > 0xff)
7292adfc5217SJeff Kirsher 		bp->rx_quick_cons_trip_int = 0xff;
7293adfc5217SJeff Kirsher 
7294adfc5217SJeff Kirsher 	bp->tx_ticks = (u16) coal->tx_coalesce_usecs;
7295adfc5217SJeff Kirsher 	if (bp->tx_ticks > 0x3ff) bp->tx_ticks = 0x3ff;
7296adfc5217SJeff Kirsher 
7297adfc5217SJeff Kirsher 	bp->tx_quick_cons_trip = (u16) coal->tx_max_coalesced_frames;
7298adfc5217SJeff Kirsher 	if (bp->tx_quick_cons_trip > 0xff) bp->tx_quick_cons_trip = 0xff;
7299adfc5217SJeff Kirsher 
7300adfc5217SJeff Kirsher 	bp->tx_ticks_int = (u16) coal->tx_coalesce_usecs_irq;
7301adfc5217SJeff Kirsher 	if (bp->tx_ticks_int > 0x3ff) bp->tx_ticks_int = 0x3ff;
7302adfc5217SJeff Kirsher 
7303adfc5217SJeff Kirsher 	bp->tx_quick_cons_trip_int = (u16) coal->tx_max_coalesced_frames_irq;
7304adfc5217SJeff Kirsher 	if (bp->tx_quick_cons_trip_int > 0xff) bp->tx_quick_cons_trip_int =
7305adfc5217SJeff Kirsher 		0xff;
7306adfc5217SJeff Kirsher 
7307adfc5217SJeff Kirsher 	bp->stats_ticks = coal->stats_block_coalesce_usecs;
7308adfc5217SJeff Kirsher 	if (bp->flags & BNX2_FLAG_BROKEN_STATS) {
7309adfc5217SJeff Kirsher 		if (bp->stats_ticks != 0 && bp->stats_ticks != USEC_PER_SEC)
7310adfc5217SJeff Kirsher 			bp->stats_ticks = USEC_PER_SEC;
7311adfc5217SJeff Kirsher 	}
7312adfc5217SJeff Kirsher 	if (bp->stats_ticks > BNX2_HC_STATS_TICKS_HC_STAT_TICKS)
7313adfc5217SJeff Kirsher 		bp->stats_ticks = BNX2_HC_STATS_TICKS_HC_STAT_TICKS;
7314adfc5217SJeff Kirsher 	bp->stats_ticks &= BNX2_HC_STATS_TICKS_HC_STAT_TICKS;
7315adfc5217SJeff Kirsher 
7316adfc5217SJeff Kirsher 	if (netif_running(bp->dev)) {
7317adfc5217SJeff Kirsher 		bnx2_netif_stop(bp, true);
7318adfc5217SJeff Kirsher 		bnx2_init_nic(bp, 0);
7319adfc5217SJeff Kirsher 		bnx2_netif_start(bp, true);
7320adfc5217SJeff Kirsher 	}
7321adfc5217SJeff Kirsher 
7322adfc5217SJeff Kirsher 	return 0;
7323adfc5217SJeff Kirsher }
7324adfc5217SJeff Kirsher 
7325adfc5217SJeff Kirsher static void
7326adfc5217SJeff Kirsher bnx2_get_ringparam(struct net_device *dev, struct ethtool_ringparam *ering)
7327adfc5217SJeff Kirsher {
7328adfc5217SJeff Kirsher 	struct bnx2 *bp = netdev_priv(dev);
7329adfc5217SJeff Kirsher 
73302bc4078eSMichael Chan 	ering->rx_max_pending = BNX2_MAX_TOTAL_RX_DESC_CNT;
73312bc4078eSMichael Chan 	ering->rx_jumbo_max_pending = BNX2_MAX_TOTAL_RX_PG_DESC_CNT;
7332adfc5217SJeff Kirsher 
7333adfc5217SJeff Kirsher 	ering->rx_pending = bp->rx_ring_size;
7334adfc5217SJeff Kirsher 	ering->rx_jumbo_pending = bp->rx_pg_ring_size;
7335adfc5217SJeff Kirsher 
73362bc4078eSMichael Chan 	ering->tx_max_pending = BNX2_MAX_TX_DESC_CNT;
7337adfc5217SJeff Kirsher 	ering->tx_pending = bp->tx_ring_size;
7338adfc5217SJeff Kirsher }
7339adfc5217SJeff Kirsher 
7340adfc5217SJeff Kirsher static int
7341b033281fSMichael Chan bnx2_change_ring_size(struct bnx2 *bp, u32 rx, u32 tx, bool reset_irq)
7342adfc5217SJeff Kirsher {
7343adfc5217SJeff Kirsher 	if (netif_running(bp->dev)) {
7344adfc5217SJeff Kirsher 		/* Reset will erase chipset stats; save them */
7345adfc5217SJeff Kirsher 		bnx2_save_stats(bp);
7346adfc5217SJeff Kirsher 
7347adfc5217SJeff Kirsher 		bnx2_netif_stop(bp, true);
7348adfc5217SJeff Kirsher 		bnx2_reset_chip(bp, BNX2_DRV_MSG_CODE_RESET);
7349b033281fSMichael Chan 		if (reset_irq) {
7350b033281fSMichael Chan 			bnx2_free_irq(bp);
7351b033281fSMichael Chan 			bnx2_del_napi(bp);
7352b033281fSMichael Chan 		} else {
7353adfc5217SJeff Kirsher 			__bnx2_free_irq(bp);
7354b033281fSMichael Chan 		}
7355adfc5217SJeff Kirsher 		bnx2_free_skbs(bp);
7356adfc5217SJeff Kirsher 		bnx2_free_mem(bp);
7357adfc5217SJeff Kirsher 	}
7358adfc5217SJeff Kirsher 
7359adfc5217SJeff Kirsher 	bnx2_set_rx_ring_size(bp, rx);
7360adfc5217SJeff Kirsher 	bp->tx_ring_size = tx;
7361adfc5217SJeff Kirsher 
7362adfc5217SJeff Kirsher 	if (netif_running(bp->dev)) {
7363b033281fSMichael Chan 		int rc = 0;
7364adfc5217SJeff Kirsher 
7365b033281fSMichael Chan 		if (reset_irq) {
7366b033281fSMichael Chan 			rc = bnx2_setup_int_mode(bp, disable_msi);
7367b033281fSMichael Chan 			bnx2_init_napi(bp);
7368b033281fSMichael Chan 		}
7369b033281fSMichael Chan 
7370b033281fSMichael Chan 		if (!rc)
7371adfc5217SJeff Kirsher 			rc = bnx2_alloc_mem(bp);
7372b033281fSMichael Chan 
7373adfc5217SJeff Kirsher 		if (!rc)
7374adfc5217SJeff Kirsher 			rc = bnx2_request_irq(bp);
7375adfc5217SJeff Kirsher 
7376adfc5217SJeff Kirsher 		if (!rc)
7377adfc5217SJeff Kirsher 			rc = bnx2_init_nic(bp, 0);
7378adfc5217SJeff Kirsher 
7379adfc5217SJeff Kirsher 		if (rc) {
7380adfc5217SJeff Kirsher 			bnx2_napi_enable(bp);
7381adfc5217SJeff Kirsher 			dev_close(bp->dev);
7382adfc5217SJeff Kirsher 			return rc;
7383adfc5217SJeff Kirsher 		}
7384adfc5217SJeff Kirsher #ifdef BCM_CNIC
7385adfc5217SJeff Kirsher 		mutex_lock(&bp->cnic_lock);
7386adfc5217SJeff Kirsher 		/* Let cnic know about the new status block. */
7387adfc5217SJeff Kirsher 		if (bp->cnic_eth_dev.drv_state & CNIC_DRV_STATE_REGD)
7388adfc5217SJeff Kirsher 			bnx2_setup_cnic_irq_info(bp);
7389adfc5217SJeff Kirsher 		mutex_unlock(&bp->cnic_lock);
7390adfc5217SJeff Kirsher #endif
7391adfc5217SJeff Kirsher 		bnx2_netif_start(bp, true);
7392adfc5217SJeff Kirsher 	}
7393adfc5217SJeff Kirsher 	return 0;
7394adfc5217SJeff Kirsher }
7395adfc5217SJeff Kirsher 
7396adfc5217SJeff Kirsher static int
7397adfc5217SJeff Kirsher bnx2_set_ringparam(struct net_device *dev, struct ethtool_ringparam *ering)
7398adfc5217SJeff Kirsher {
7399adfc5217SJeff Kirsher 	struct bnx2 *bp = netdev_priv(dev);
7400adfc5217SJeff Kirsher 	int rc;
7401adfc5217SJeff Kirsher 
74022bc4078eSMichael Chan 	if ((ering->rx_pending > BNX2_MAX_TOTAL_RX_DESC_CNT) ||
74032bc4078eSMichael Chan 		(ering->tx_pending > BNX2_MAX_TX_DESC_CNT) ||
7404adfc5217SJeff Kirsher 		(ering->tx_pending <= MAX_SKB_FRAGS)) {
7405adfc5217SJeff Kirsher 
7406adfc5217SJeff Kirsher 		return -EINVAL;
7407adfc5217SJeff Kirsher 	}
7408b033281fSMichael Chan 	rc = bnx2_change_ring_size(bp, ering->rx_pending, ering->tx_pending,
7409b033281fSMichael Chan 				   false);
7410adfc5217SJeff Kirsher 	return rc;
7411adfc5217SJeff Kirsher }
7412adfc5217SJeff Kirsher 
7413adfc5217SJeff Kirsher static void
7414adfc5217SJeff Kirsher bnx2_get_pauseparam(struct net_device *dev, struct ethtool_pauseparam *epause)
7415adfc5217SJeff Kirsher {
7416adfc5217SJeff Kirsher 	struct bnx2 *bp = netdev_priv(dev);
7417adfc5217SJeff Kirsher 
7418adfc5217SJeff Kirsher 	epause->autoneg = ((bp->autoneg & AUTONEG_FLOW_CTRL) != 0);
7419adfc5217SJeff Kirsher 	epause->rx_pause = ((bp->flow_ctrl & FLOW_CTRL_RX) != 0);
7420adfc5217SJeff Kirsher 	epause->tx_pause = ((bp->flow_ctrl & FLOW_CTRL_TX) != 0);
7421adfc5217SJeff Kirsher }
7422adfc5217SJeff Kirsher 
7423adfc5217SJeff Kirsher static int
7424adfc5217SJeff Kirsher bnx2_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam *epause)
7425adfc5217SJeff Kirsher {
7426adfc5217SJeff Kirsher 	struct bnx2 *bp = netdev_priv(dev);
7427adfc5217SJeff Kirsher 
7428adfc5217SJeff Kirsher 	bp->req_flow_ctrl = 0;
7429adfc5217SJeff Kirsher 	if (epause->rx_pause)
7430adfc5217SJeff Kirsher 		bp->req_flow_ctrl |= FLOW_CTRL_RX;
7431adfc5217SJeff Kirsher 	if (epause->tx_pause)
7432adfc5217SJeff Kirsher 		bp->req_flow_ctrl |= FLOW_CTRL_TX;
7433adfc5217SJeff Kirsher 
7434adfc5217SJeff Kirsher 	if (epause->autoneg) {
7435adfc5217SJeff Kirsher 		bp->autoneg |= AUTONEG_FLOW_CTRL;
7436adfc5217SJeff Kirsher 	}
7437adfc5217SJeff Kirsher 	else {
7438adfc5217SJeff Kirsher 		bp->autoneg &= ~AUTONEG_FLOW_CTRL;
7439adfc5217SJeff Kirsher 	}
7440adfc5217SJeff Kirsher 
7441adfc5217SJeff Kirsher 	if (netif_running(dev)) {
7442adfc5217SJeff Kirsher 		spin_lock_bh(&bp->phy_lock);
7443adfc5217SJeff Kirsher 		bnx2_setup_phy(bp, bp->phy_port);
7444adfc5217SJeff Kirsher 		spin_unlock_bh(&bp->phy_lock);
7445adfc5217SJeff Kirsher 	}
7446adfc5217SJeff Kirsher 
7447adfc5217SJeff Kirsher 	return 0;
7448adfc5217SJeff Kirsher }
7449adfc5217SJeff Kirsher 
7450adfc5217SJeff Kirsher static struct {
7451adfc5217SJeff Kirsher 	char string[ETH_GSTRING_LEN];
7452adfc5217SJeff Kirsher } bnx2_stats_str_arr[] = {
7453adfc5217SJeff Kirsher 	{ "rx_bytes" },
7454adfc5217SJeff Kirsher 	{ "rx_error_bytes" },
7455adfc5217SJeff Kirsher 	{ "tx_bytes" },
7456adfc5217SJeff Kirsher 	{ "tx_error_bytes" },
7457adfc5217SJeff Kirsher 	{ "rx_ucast_packets" },
7458adfc5217SJeff Kirsher 	{ "rx_mcast_packets" },
7459adfc5217SJeff Kirsher 	{ "rx_bcast_packets" },
7460adfc5217SJeff Kirsher 	{ "tx_ucast_packets" },
7461adfc5217SJeff Kirsher 	{ "tx_mcast_packets" },
7462adfc5217SJeff Kirsher 	{ "tx_bcast_packets" },
7463adfc5217SJeff Kirsher 	{ "tx_mac_errors" },
7464adfc5217SJeff Kirsher 	{ "tx_carrier_errors" },
7465adfc5217SJeff Kirsher 	{ "rx_crc_errors" },
7466adfc5217SJeff Kirsher 	{ "rx_align_errors" },
7467adfc5217SJeff Kirsher 	{ "tx_single_collisions" },
7468adfc5217SJeff Kirsher 	{ "tx_multi_collisions" },
7469adfc5217SJeff Kirsher 	{ "tx_deferred" },
7470adfc5217SJeff Kirsher 	{ "tx_excess_collisions" },
7471adfc5217SJeff Kirsher 	{ "tx_late_collisions" },
7472adfc5217SJeff Kirsher 	{ "tx_total_collisions" },
7473adfc5217SJeff Kirsher 	{ "rx_fragments" },
7474adfc5217SJeff Kirsher 	{ "rx_jabbers" },
7475adfc5217SJeff Kirsher 	{ "rx_undersize_packets" },
7476adfc5217SJeff Kirsher 	{ "rx_oversize_packets" },
7477adfc5217SJeff Kirsher 	{ "rx_64_byte_packets" },
7478adfc5217SJeff Kirsher 	{ "rx_65_to_127_byte_packets" },
7479adfc5217SJeff Kirsher 	{ "rx_128_to_255_byte_packets" },
7480adfc5217SJeff Kirsher 	{ "rx_256_to_511_byte_packets" },
7481adfc5217SJeff Kirsher 	{ "rx_512_to_1023_byte_packets" },
7482adfc5217SJeff Kirsher 	{ "rx_1024_to_1522_byte_packets" },
7483adfc5217SJeff Kirsher 	{ "rx_1523_to_9022_byte_packets" },
7484adfc5217SJeff Kirsher 	{ "tx_64_byte_packets" },
7485adfc5217SJeff Kirsher 	{ "tx_65_to_127_byte_packets" },
7486adfc5217SJeff Kirsher 	{ "tx_128_to_255_byte_packets" },
7487adfc5217SJeff Kirsher 	{ "tx_256_to_511_byte_packets" },
7488adfc5217SJeff Kirsher 	{ "tx_512_to_1023_byte_packets" },
7489adfc5217SJeff Kirsher 	{ "tx_1024_to_1522_byte_packets" },
7490adfc5217SJeff Kirsher 	{ "tx_1523_to_9022_byte_packets" },
7491adfc5217SJeff Kirsher 	{ "rx_xon_frames" },
7492adfc5217SJeff Kirsher 	{ "rx_xoff_frames" },
7493adfc5217SJeff Kirsher 	{ "tx_xon_frames" },
7494adfc5217SJeff Kirsher 	{ "tx_xoff_frames" },
7495adfc5217SJeff Kirsher 	{ "rx_mac_ctrl_frames" },
7496adfc5217SJeff Kirsher 	{ "rx_filtered_packets" },
7497adfc5217SJeff Kirsher 	{ "rx_ftq_discards" },
7498adfc5217SJeff Kirsher 	{ "rx_discards" },
7499adfc5217SJeff Kirsher 	{ "rx_fw_discards" },
7500adfc5217SJeff Kirsher };
7501adfc5217SJeff Kirsher 
75020db83cd8SJim Cromie #define BNX2_NUM_STATS ARRAY_SIZE(bnx2_stats_str_arr)
7503adfc5217SJeff Kirsher 
7504adfc5217SJeff Kirsher #define STATS_OFFSET32(offset_name) (offsetof(struct statistics_block, offset_name) / 4)
7505adfc5217SJeff Kirsher 
7506adfc5217SJeff Kirsher static const unsigned long bnx2_stats_offset_arr[BNX2_NUM_STATS] = {
7507adfc5217SJeff Kirsher     STATS_OFFSET32(stat_IfHCInOctets_hi),
7508adfc5217SJeff Kirsher     STATS_OFFSET32(stat_IfHCInBadOctets_hi),
7509adfc5217SJeff Kirsher     STATS_OFFSET32(stat_IfHCOutOctets_hi),
7510adfc5217SJeff Kirsher     STATS_OFFSET32(stat_IfHCOutBadOctets_hi),
7511adfc5217SJeff Kirsher     STATS_OFFSET32(stat_IfHCInUcastPkts_hi),
7512adfc5217SJeff Kirsher     STATS_OFFSET32(stat_IfHCInMulticastPkts_hi),
7513adfc5217SJeff Kirsher     STATS_OFFSET32(stat_IfHCInBroadcastPkts_hi),
7514adfc5217SJeff Kirsher     STATS_OFFSET32(stat_IfHCOutUcastPkts_hi),
7515adfc5217SJeff Kirsher     STATS_OFFSET32(stat_IfHCOutMulticastPkts_hi),
7516adfc5217SJeff Kirsher     STATS_OFFSET32(stat_IfHCOutBroadcastPkts_hi),
7517adfc5217SJeff Kirsher     STATS_OFFSET32(stat_emac_tx_stat_dot3statsinternalmactransmiterrors),
7518adfc5217SJeff Kirsher     STATS_OFFSET32(stat_Dot3StatsCarrierSenseErrors),
7519adfc5217SJeff Kirsher     STATS_OFFSET32(stat_Dot3StatsFCSErrors),
7520adfc5217SJeff Kirsher     STATS_OFFSET32(stat_Dot3StatsAlignmentErrors),
7521adfc5217SJeff Kirsher     STATS_OFFSET32(stat_Dot3StatsSingleCollisionFrames),
7522adfc5217SJeff Kirsher     STATS_OFFSET32(stat_Dot3StatsMultipleCollisionFrames),
7523adfc5217SJeff Kirsher     STATS_OFFSET32(stat_Dot3StatsDeferredTransmissions),
7524adfc5217SJeff Kirsher     STATS_OFFSET32(stat_Dot3StatsExcessiveCollisions),
7525adfc5217SJeff Kirsher     STATS_OFFSET32(stat_Dot3StatsLateCollisions),
7526adfc5217SJeff Kirsher     STATS_OFFSET32(stat_EtherStatsCollisions),
7527adfc5217SJeff Kirsher     STATS_OFFSET32(stat_EtherStatsFragments),
7528adfc5217SJeff Kirsher     STATS_OFFSET32(stat_EtherStatsJabbers),
7529adfc5217SJeff Kirsher     STATS_OFFSET32(stat_EtherStatsUndersizePkts),
7530adfc5217SJeff Kirsher     STATS_OFFSET32(stat_EtherStatsOverrsizePkts),
7531adfc5217SJeff Kirsher     STATS_OFFSET32(stat_EtherStatsPktsRx64Octets),
7532adfc5217SJeff Kirsher     STATS_OFFSET32(stat_EtherStatsPktsRx65Octetsto127Octets),
7533adfc5217SJeff Kirsher     STATS_OFFSET32(stat_EtherStatsPktsRx128Octetsto255Octets),
7534adfc5217SJeff Kirsher     STATS_OFFSET32(stat_EtherStatsPktsRx256Octetsto511Octets),
7535adfc5217SJeff Kirsher     STATS_OFFSET32(stat_EtherStatsPktsRx512Octetsto1023Octets),
7536adfc5217SJeff Kirsher     STATS_OFFSET32(stat_EtherStatsPktsRx1024Octetsto1522Octets),
7537adfc5217SJeff Kirsher     STATS_OFFSET32(stat_EtherStatsPktsRx1523Octetsto9022Octets),
7538adfc5217SJeff Kirsher     STATS_OFFSET32(stat_EtherStatsPktsTx64Octets),
7539adfc5217SJeff Kirsher     STATS_OFFSET32(stat_EtherStatsPktsTx65Octetsto127Octets),
7540adfc5217SJeff Kirsher     STATS_OFFSET32(stat_EtherStatsPktsTx128Octetsto255Octets),
7541adfc5217SJeff Kirsher     STATS_OFFSET32(stat_EtherStatsPktsTx256Octetsto511Octets),
7542adfc5217SJeff Kirsher     STATS_OFFSET32(stat_EtherStatsPktsTx512Octetsto1023Octets),
7543adfc5217SJeff Kirsher     STATS_OFFSET32(stat_EtherStatsPktsTx1024Octetsto1522Octets),
7544adfc5217SJeff Kirsher     STATS_OFFSET32(stat_EtherStatsPktsTx1523Octetsto9022Octets),
7545adfc5217SJeff Kirsher     STATS_OFFSET32(stat_XonPauseFramesReceived),
7546adfc5217SJeff Kirsher     STATS_OFFSET32(stat_XoffPauseFramesReceived),
7547adfc5217SJeff Kirsher     STATS_OFFSET32(stat_OutXonSent),
7548adfc5217SJeff Kirsher     STATS_OFFSET32(stat_OutXoffSent),
7549adfc5217SJeff Kirsher     STATS_OFFSET32(stat_MacControlFramesReceived),
7550adfc5217SJeff Kirsher     STATS_OFFSET32(stat_IfInFramesL2FilterDiscards),
7551adfc5217SJeff Kirsher     STATS_OFFSET32(stat_IfInFTQDiscards),
7552adfc5217SJeff Kirsher     STATS_OFFSET32(stat_IfInMBUFDiscards),
7553adfc5217SJeff Kirsher     STATS_OFFSET32(stat_FwRxDrop),
7554adfc5217SJeff Kirsher };
7555adfc5217SJeff Kirsher 
7556adfc5217SJeff Kirsher /* stat_IfHCInBadOctets and stat_Dot3StatsCarrierSenseErrors are
7557adfc5217SJeff Kirsher  * skipped because of errata.
7558adfc5217SJeff Kirsher  */
7559adfc5217SJeff Kirsher static u8 bnx2_5706_stats_len_arr[BNX2_NUM_STATS] = {
7560adfc5217SJeff Kirsher 	8,0,8,8,8,8,8,8,8,8,
7561adfc5217SJeff Kirsher 	4,0,4,4,4,4,4,4,4,4,
7562adfc5217SJeff Kirsher 	4,4,4,4,4,4,4,4,4,4,
7563adfc5217SJeff Kirsher 	4,4,4,4,4,4,4,4,4,4,
7564adfc5217SJeff Kirsher 	4,4,4,4,4,4,4,
7565adfc5217SJeff Kirsher };
7566adfc5217SJeff Kirsher 
7567adfc5217SJeff Kirsher static u8 bnx2_5708_stats_len_arr[BNX2_NUM_STATS] = {
7568adfc5217SJeff Kirsher 	8,0,8,8,8,8,8,8,8,8,
7569adfc5217SJeff Kirsher 	4,4,4,4,4,4,4,4,4,4,
7570adfc5217SJeff Kirsher 	4,4,4,4,4,4,4,4,4,4,
7571adfc5217SJeff Kirsher 	4,4,4,4,4,4,4,4,4,4,
7572adfc5217SJeff Kirsher 	4,4,4,4,4,4,4,
7573adfc5217SJeff Kirsher };
7574adfc5217SJeff Kirsher 
7575adfc5217SJeff Kirsher #define BNX2_NUM_TESTS 6
7576adfc5217SJeff Kirsher 
7577adfc5217SJeff Kirsher static struct {
7578adfc5217SJeff Kirsher 	char string[ETH_GSTRING_LEN];
7579adfc5217SJeff Kirsher } bnx2_tests_str_arr[BNX2_NUM_TESTS] = {
7580adfc5217SJeff Kirsher 	{ "register_test (offline)" },
7581adfc5217SJeff Kirsher 	{ "memory_test (offline)" },
7582adfc5217SJeff Kirsher 	{ "loopback_test (offline)" },
7583adfc5217SJeff Kirsher 	{ "nvram_test (online)" },
7584adfc5217SJeff Kirsher 	{ "interrupt_test (online)" },
7585adfc5217SJeff Kirsher 	{ "link_test (online)" },
7586adfc5217SJeff Kirsher };
7587adfc5217SJeff Kirsher 
7588adfc5217SJeff Kirsher static int
7589adfc5217SJeff Kirsher bnx2_get_sset_count(struct net_device *dev, int sset)
7590adfc5217SJeff Kirsher {
7591adfc5217SJeff Kirsher 	switch (sset) {
7592adfc5217SJeff Kirsher 	case ETH_SS_TEST:
7593adfc5217SJeff Kirsher 		return BNX2_NUM_TESTS;
7594adfc5217SJeff Kirsher 	case ETH_SS_STATS:
7595adfc5217SJeff Kirsher 		return BNX2_NUM_STATS;
7596adfc5217SJeff Kirsher 	default:
7597adfc5217SJeff Kirsher 		return -EOPNOTSUPP;
7598adfc5217SJeff Kirsher 	}
7599adfc5217SJeff Kirsher }
7600adfc5217SJeff Kirsher 
7601adfc5217SJeff Kirsher static void
7602adfc5217SJeff Kirsher bnx2_self_test(struct net_device *dev, struct ethtool_test *etest, u64 *buf)
7603adfc5217SJeff Kirsher {
7604adfc5217SJeff Kirsher 	struct bnx2 *bp = netdev_priv(dev);
7605adfc5217SJeff Kirsher 
7606adfc5217SJeff Kirsher 	memset(buf, 0, sizeof(u64) * BNX2_NUM_TESTS);
7607adfc5217SJeff Kirsher 	if (etest->flags & ETH_TEST_FL_OFFLINE) {
7608adfc5217SJeff Kirsher 		int i;
7609adfc5217SJeff Kirsher 
7610adfc5217SJeff Kirsher 		bnx2_netif_stop(bp, true);
7611adfc5217SJeff Kirsher 		bnx2_reset_chip(bp, BNX2_DRV_MSG_CODE_DIAG);
7612adfc5217SJeff Kirsher 		bnx2_free_skbs(bp);
7613adfc5217SJeff Kirsher 
7614adfc5217SJeff Kirsher 		if (bnx2_test_registers(bp) != 0) {
7615adfc5217SJeff Kirsher 			buf[0] = 1;
7616adfc5217SJeff Kirsher 			etest->flags |= ETH_TEST_FL_FAILED;
7617adfc5217SJeff Kirsher 		}
7618adfc5217SJeff Kirsher 		if (bnx2_test_memory(bp) != 0) {
7619adfc5217SJeff Kirsher 			buf[1] = 1;
7620adfc5217SJeff Kirsher 			etest->flags |= ETH_TEST_FL_FAILED;
7621adfc5217SJeff Kirsher 		}
7622adfc5217SJeff Kirsher 		if ((buf[2] = bnx2_test_loopback(bp)) != 0)
7623adfc5217SJeff Kirsher 			etest->flags |= ETH_TEST_FL_FAILED;
7624adfc5217SJeff Kirsher 
7625adfc5217SJeff Kirsher 		if (!netif_running(bp->dev))
7626adfc5217SJeff Kirsher 			bnx2_shutdown_chip(bp);
7627adfc5217SJeff Kirsher 		else {
7628adfc5217SJeff Kirsher 			bnx2_init_nic(bp, 1);
7629adfc5217SJeff Kirsher 			bnx2_netif_start(bp, true);
7630adfc5217SJeff Kirsher 		}
7631adfc5217SJeff Kirsher 
7632adfc5217SJeff Kirsher 		/* wait for link up */
7633adfc5217SJeff Kirsher 		for (i = 0; i < 7; i++) {
7634adfc5217SJeff Kirsher 			if (bp->link_up)
7635adfc5217SJeff Kirsher 				break;
7636adfc5217SJeff Kirsher 			msleep_interruptible(1000);
7637adfc5217SJeff Kirsher 		}
7638adfc5217SJeff Kirsher 	}
7639adfc5217SJeff Kirsher 
7640adfc5217SJeff Kirsher 	if (bnx2_test_nvram(bp) != 0) {
7641adfc5217SJeff Kirsher 		buf[3] = 1;
7642adfc5217SJeff Kirsher 		etest->flags |= ETH_TEST_FL_FAILED;
7643adfc5217SJeff Kirsher 	}
7644adfc5217SJeff Kirsher 	if (bnx2_test_intr(bp) != 0) {
7645adfc5217SJeff Kirsher 		buf[4] = 1;
7646adfc5217SJeff Kirsher 		etest->flags |= ETH_TEST_FL_FAILED;
7647adfc5217SJeff Kirsher 	}
7648adfc5217SJeff Kirsher 
7649adfc5217SJeff Kirsher 	if (bnx2_test_link(bp) != 0) {
7650adfc5217SJeff Kirsher 		buf[5] = 1;
7651adfc5217SJeff Kirsher 		etest->flags |= ETH_TEST_FL_FAILED;
7652adfc5217SJeff Kirsher 
7653adfc5217SJeff Kirsher 	}
7654adfc5217SJeff Kirsher }
7655adfc5217SJeff Kirsher 
7656adfc5217SJeff Kirsher static void
7657adfc5217SJeff Kirsher bnx2_get_strings(struct net_device *dev, u32 stringset, u8 *buf)
7658adfc5217SJeff Kirsher {
7659adfc5217SJeff Kirsher 	switch (stringset) {
7660adfc5217SJeff Kirsher 	case ETH_SS_STATS:
7661adfc5217SJeff Kirsher 		memcpy(buf, bnx2_stats_str_arr,
7662adfc5217SJeff Kirsher 			sizeof(bnx2_stats_str_arr));
7663adfc5217SJeff Kirsher 		break;
7664adfc5217SJeff Kirsher 	case ETH_SS_TEST:
7665adfc5217SJeff Kirsher 		memcpy(buf, bnx2_tests_str_arr,
7666adfc5217SJeff Kirsher 			sizeof(bnx2_tests_str_arr));
7667adfc5217SJeff Kirsher 		break;
7668adfc5217SJeff Kirsher 	}
7669adfc5217SJeff Kirsher }
7670adfc5217SJeff Kirsher 
7671adfc5217SJeff Kirsher static void
7672adfc5217SJeff Kirsher bnx2_get_ethtool_stats(struct net_device *dev,
7673adfc5217SJeff Kirsher 		struct ethtool_stats *stats, u64 *buf)
7674adfc5217SJeff Kirsher {
7675adfc5217SJeff Kirsher 	struct bnx2 *bp = netdev_priv(dev);
7676adfc5217SJeff Kirsher 	int i;
7677adfc5217SJeff Kirsher 	u32 *hw_stats = (u32 *) bp->stats_blk;
7678adfc5217SJeff Kirsher 	u32 *temp_stats = (u32 *) bp->temp_stats_blk;
7679adfc5217SJeff Kirsher 	u8 *stats_len_arr = NULL;
7680adfc5217SJeff Kirsher 
7681b8aac410SVarsha Rao 	if (!hw_stats) {
7682adfc5217SJeff Kirsher 		memset(buf, 0, sizeof(u64) * BNX2_NUM_STATS);
7683adfc5217SJeff Kirsher 		return;
7684adfc5217SJeff Kirsher 	}
7685adfc5217SJeff Kirsher 
76864ce45e02SMichael Chan 	if ((BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5706_A0) ||
76874ce45e02SMichael Chan 	    (BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5706_A1) ||
76884ce45e02SMichael Chan 	    (BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5706_A2) ||
76894ce45e02SMichael Chan 	    (BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5708_A0))
7690adfc5217SJeff Kirsher 		stats_len_arr = bnx2_5706_stats_len_arr;
7691adfc5217SJeff Kirsher 	else
7692adfc5217SJeff Kirsher 		stats_len_arr = bnx2_5708_stats_len_arr;
7693adfc5217SJeff Kirsher 
7694adfc5217SJeff Kirsher 	for (i = 0; i < BNX2_NUM_STATS; i++) {
7695adfc5217SJeff Kirsher 		unsigned long offset;
7696adfc5217SJeff Kirsher 
7697adfc5217SJeff Kirsher 		if (stats_len_arr[i] == 0) {
7698adfc5217SJeff Kirsher 			/* skip this counter */
7699adfc5217SJeff Kirsher 			buf[i] = 0;
7700adfc5217SJeff Kirsher 			continue;
7701adfc5217SJeff Kirsher 		}
7702adfc5217SJeff Kirsher 
7703adfc5217SJeff Kirsher 		offset = bnx2_stats_offset_arr[i];
7704adfc5217SJeff Kirsher 		if (stats_len_arr[i] == 4) {
7705adfc5217SJeff Kirsher 			/* 4-byte counter */
7706adfc5217SJeff Kirsher 			buf[i] = (u64) *(hw_stats + offset) +
7707adfc5217SJeff Kirsher 				 *(temp_stats + offset);
7708adfc5217SJeff Kirsher 			continue;
7709adfc5217SJeff Kirsher 		}
7710adfc5217SJeff Kirsher 		/* 8-byte counter */
7711adfc5217SJeff Kirsher 		buf[i] = (((u64) *(hw_stats + offset)) << 32) +
7712adfc5217SJeff Kirsher 			 *(hw_stats + offset + 1) +
7713adfc5217SJeff Kirsher 			 (((u64) *(temp_stats + offset)) << 32) +
7714adfc5217SJeff Kirsher 			 *(temp_stats + offset + 1);
7715adfc5217SJeff Kirsher 	}
7716adfc5217SJeff Kirsher }
7717adfc5217SJeff Kirsher 
7718adfc5217SJeff Kirsher static int
7719adfc5217SJeff Kirsher bnx2_set_phys_id(struct net_device *dev, enum ethtool_phys_id_state state)
7720adfc5217SJeff Kirsher {
7721adfc5217SJeff Kirsher 	struct bnx2 *bp = netdev_priv(dev);
7722adfc5217SJeff Kirsher 
7723adfc5217SJeff Kirsher 	switch (state) {
7724adfc5217SJeff Kirsher 	case ETHTOOL_ID_ACTIVE:
7725e503e066SMichael Chan 		bp->leds_save = BNX2_RD(bp, BNX2_MISC_CFG);
7726e503e066SMichael Chan 		BNX2_WR(bp, BNX2_MISC_CFG, BNX2_MISC_CFG_LEDMODE_MAC);
7727adfc5217SJeff Kirsher 		return 1;	/* cycle on/off once per second */
7728adfc5217SJeff Kirsher 
7729adfc5217SJeff Kirsher 	case ETHTOOL_ID_ON:
7730e503e066SMichael Chan 		BNX2_WR(bp, BNX2_EMAC_LED, BNX2_EMAC_LED_OVERRIDE |
7731adfc5217SJeff Kirsher 			BNX2_EMAC_LED_1000MB_OVERRIDE |
7732adfc5217SJeff Kirsher 			BNX2_EMAC_LED_100MB_OVERRIDE |
7733adfc5217SJeff Kirsher 			BNX2_EMAC_LED_10MB_OVERRIDE |
7734adfc5217SJeff Kirsher 			BNX2_EMAC_LED_TRAFFIC_OVERRIDE |
7735adfc5217SJeff Kirsher 			BNX2_EMAC_LED_TRAFFIC);
7736adfc5217SJeff Kirsher 		break;
7737adfc5217SJeff Kirsher 
7738adfc5217SJeff Kirsher 	case ETHTOOL_ID_OFF:
7739e503e066SMichael Chan 		BNX2_WR(bp, BNX2_EMAC_LED, BNX2_EMAC_LED_OVERRIDE);
7740adfc5217SJeff Kirsher 		break;
7741adfc5217SJeff Kirsher 
7742adfc5217SJeff Kirsher 	case ETHTOOL_ID_INACTIVE:
7743e503e066SMichael Chan 		BNX2_WR(bp, BNX2_EMAC_LED, 0);
7744e503e066SMichael Chan 		BNX2_WR(bp, BNX2_MISC_CFG, bp->leds_save);
7745adfc5217SJeff Kirsher 		break;
7746adfc5217SJeff Kirsher 	}
7747adfc5217SJeff Kirsher 
7748adfc5217SJeff Kirsher 	return 0;
7749adfc5217SJeff Kirsher }
7750adfc5217SJeff Kirsher 
7751adfc5217SJeff Kirsher static int
7752c8f44affSMichał Mirosław bnx2_set_features(struct net_device *dev, netdev_features_t features)
7753adfc5217SJeff Kirsher {
7754adfc5217SJeff Kirsher 	struct bnx2 *bp = netdev_priv(dev);
7755adfc5217SJeff Kirsher 
7756adfc5217SJeff Kirsher 	/* TSO with VLAN tag won't work with current firmware */
7757f646968fSPatrick McHardy 	if (features & NETIF_F_HW_VLAN_CTAG_TX)
7758adfc5217SJeff Kirsher 		dev->vlan_features |= (dev->hw_features & NETIF_F_ALL_TSO);
7759adfc5217SJeff Kirsher 	else
7760adfc5217SJeff Kirsher 		dev->vlan_features &= ~NETIF_F_ALL_TSO;
7761adfc5217SJeff Kirsher 
7762f646968fSPatrick McHardy 	if ((!!(features & NETIF_F_HW_VLAN_CTAG_RX) !=
7763adfc5217SJeff Kirsher 	    !!(bp->rx_mode & BNX2_EMAC_RX_MODE_KEEP_VLAN_TAG)) &&
7764adfc5217SJeff Kirsher 	    netif_running(dev)) {
7765adfc5217SJeff Kirsher 		bnx2_netif_stop(bp, false);
7766adfc5217SJeff Kirsher 		dev->features = features;
7767adfc5217SJeff Kirsher 		bnx2_set_rx_mode(dev);
7768adfc5217SJeff Kirsher 		bnx2_fw_sync(bp, BNX2_DRV_MSG_CODE_KEEP_VLAN_UPDATE, 0, 1);
7769adfc5217SJeff Kirsher 		bnx2_netif_start(bp, false);
7770adfc5217SJeff Kirsher 		return 1;
7771adfc5217SJeff Kirsher 	}
7772adfc5217SJeff Kirsher 
7773adfc5217SJeff Kirsher 	return 0;
7774adfc5217SJeff Kirsher }
7775adfc5217SJeff Kirsher 
7776b033281fSMichael Chan static void bnx2_get_channels(struct net_device *dev,
7777b033281fSMichael Chan 			      struct ethtool_channels *channels)
7778b033281fSMichael Chan {
7779b033281fSMichael Chan 	struct bnx2 *bp = netdev_priv(dev);
7780b033281fSMichael Chan 	u32 max_rx_rings = 1;
7781b033281fSMichael Chan 	u32 max_tx_rings = 1;
7782b033281fSMichael Chan 
7783b033281fSMichael Chan 	if ((bp->flags & BNX2_FLAG_MSIX_CAP) && !disable_msi) {
7784b033281fSMichael Chan 		max_rx_rings = RX_MAX_RINGS;
7785b033281fSMichael Chan 		max_tx_rings = TX_MAX_RINGS;
7786b033281fSMichael Chan 	}
7787b033281fSMichael Chan 
7788b033281fSMichael Chan 	channels->max_rx = max_rx_rings;
7789b033281fSMichael Chan 	channels->max_tx = max_tx_rings;
7790b033281fSMichael Chan 	channels->max_other = 0;
7791b033281fSMichael Chan 	channels->max_combined = 0;
7792b033281fSMichael Chan 	channels->rx_count = bp->num_rx_rings;
7793b033281fSMichael Chan 	channels->tx_count = bp->num_tx_rings;
7794b033281fSMichael Chan 	channels->other_count = 0;
7795b033281fSMichael Chan 	channels->combined_count = 0;
7796b033281fSMichael Chan }
7797b033281fSMichael Chan 
7798b033281fSMichael Chan static int bnx2_set_channels(struct net_device *dev,
7799b033281fSMichael Chan 			      struct ethtool_channels *channels)
7800b033281fSMichael Chan {
7801b033281fSMichael Chan 	struct bnx2 *bp = netdev_priv(dev);
7802b033281fSMichael Chan 	u32 max_rx_rings = 1;
7803b033281fSMichael Chan 	u32 max_tx_rings = 1;
7804b033281fSMichael Chan 	int rc = 0;
7805b033281fSMichael Chan 
7806b033281fSMichael Chan 	if ((bp->flags & BNX2_FLAG_MSIX_CAP) && !disable_msi) {
7807b033281fSMichael Chan 		max_rx_rings = RX_MAX_RINGS;
7808b033281fSMichael Chan 		max_tx_rings = TX_MAX_RINGS;
7809b033281fSMichael Chan 	}
7810b033281fSMichael Chan 	if (channels->rx_count > max_rx_rings ||
7811b033281fSMichael Chan 	    channels->tx_count > max_tx_rings)
7812b033281fSMichael Chan 		return -EINVAL;
7813b033281fSMichael Chan 
7814b033281fSMichael Chan 	bp->num_req_rx_rings = channels->rx_count;
7815b033281fSMichael Chan 	bp->num_req_tx_rings = channels->tx_count;
7816b033281fSMichael Chan 
7817b033281fSMichael Chan 	if (netif_running(dev))
7818b033281fSMichael Chan 		rc = bnx2_change_ring_size(bp, bp->rx_ring_size,
7819b033281fSMichael Chan 					   bp->tx_ring_size, true);
7820b033281fSMichael Chan 
7821b033281fSMichael Chan 	return rc;
7822b033281fSMichael Chan }
7823b033281fSMichael Chan 
7824adfc5217SJeff Kirsher static const struct ethtool_ops bnx2_ethtool_ops = {
7825adfc5217SJeff Kirsher 	.get_drvinfo		= bnx2_get_drvinfo,
7826adfc5217SJeff Kirsher 	.get_regs_len		= bnx2_get_regs_len,
7827adfc5217SJeff Kirsher 	.get_regs		= bnx2_get_regs,
7828adfc5217SJeff Kirsher 	.get_wol		= bnx2_get_wol,
7829adfc5217SJeff Kirsher 	.set_wol		= bnx2_set_wol,
7830adfc5217SJeff Kirsher 	.nway_reset		= bnx2_nway_reset,
7831adfc5217SJeff Kirsher 	.get_link		= bnx2_get_link,
7832adfc5217SJeff Kirsher 	.get_eeprom_len		= bnx2_get_eeprom_len,
7833adfc5217SJeff Kirsher 	.get_eeprom		= bnx2_get_eeprom,
7834adfc5217SJeff Kirsher 	.set_eeprom		= bnx2_set_eeprom,
7835adfc5217SJeff Kirsher 	.get_coalesce		= bnx2_get_coalesce,
7836adfc5217SJeff Kirsher 	.set_coalesce		= bnx2_set_coalesce,
7837adfc5217SJeff Kirsher 	.get_ringparam		= bnx2_get_ringparam,
7838adfc5217SJeff Kirsher 	.set_ringparam		= bnx2_set_ringparam,
7839adfc5217SJeff Kirsher 	.get_pauseparam		= bnx2_get_pauseparam,
7840adfc5217SJeff Kirsher 	.set_pauseparam		= bnx2_set_pauseparam,
7841adfc5217SJeff Kirsher 	.self_test		= bnx2_self_test,
7842adfc5217SJeff Kirsher 	.get_strings		= bnx2_get_strings,
7843adfc5217SJeff Kirsher 	.set_phys_id		= bnx2_set_phys_id,
7844adfc5217SJeff Kirsher 	.get_ethtool_stats	= bnx2_get_ethtool_stats,
7845adfc5217SJeff Kirsher 	.get_sset_count		= bnx2_get_sset_count,
7846b033281fSMichael Chan 	.get_channels		= bnx2_get_channels,
7847b033281fSMichael Chan 	.set_channels		= bnx2_set_channels,
784808e10d4dSPhilippe Reynes 	.get_link_ksettings	= bnx2_get_link_ksettings,
784908e10d4dSPhilippe Reynes 	.set_link_ksettings	= bnx2_set_link_ksettings,
7850adfc5217SJeff Kirsher };
7851adfc5217SJeff Kirsher 
7852adfc5217SJeff Kirsher /* Called with rtnl_lock */
7853adfc5217SJeff Kirsher static int
7854adfc5217SJeff Kirsher bnx2_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
7855adfc5217SJeff Kirsher {
7856adfc5217SJeff Kirsher 	struct mii_ioctl_data *data = if_mii(ifr);
7857adfc5217SJeff Kirsher 	struct bnx2 *bp = netdev_priv(dev);
7858adfc5217SJeff Kirsher 	int err;
7859adfc5217SJeff Kirsher 
7860adfc5217SJeff Kirsher 	switch(cmd) {
7861adfc5217SJeff Kirsher 	case SIOCGMIIPHY:
7862adfc5217SJeff Kirsher 		data->phy_id = bp->phy_addr;
7863adfc5217SJeff Kirsher 
7864adfc5217SJeff Kirsher 		/* fallthru */
7865adfc5217SJeff Kirsher 	case SIOCGMIIREG: {
7866adfc5217SJeff Kirsher 		u32 mii_regval;
7867adfc5217SJeff Kirsher 
7868adfc5217SJeff Kirsher 		if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
7869adfc5217SJeff Kirsher 			return -EOPNOTSUPP;
7870adfc5217SJeff Kirsher 
7871adfc5217SJeff Kirsher 		if (!netif_running(dev))
7872adfc5217SJeff Kirsher 			return -EAGAIN;
7873adfc5217SJeff Kirsher 
7874adfc5217SJeff Kirsher 		spin_lock_bh(&bp->phy_lock);
7875adfc5217SJeff Kirsher 		err = bnx2_read_phy(bp, data->reg_num & 0x1f, &mii_regval);
7876adfc5217SJeff Kirsher 		spin_unlock_bh(&bp->phy_lock);
7877adfc5217SJeff Kirsher 
7878adfc5217SJeff Kirsher 		data->val_out = mii_regval;
7879adfc5217SJeff Kirsher 
7880adfc5217SJeff Kirsher 		return err;
7881adfc5217SJeff Kirsher 	}
7882adfc5217SJeff Kirsher 
7883adfc5217SJeff Kirsher 	case SIOCSMIIREG:
7884adfc5217SJeff Kirsher 		if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
7885adfc5217SJeff Kirsher 			return -EOPNOTSUPP;
7886adfc5217SJeff Kirsher 
7887adfc5217SJeff Kirsher 		if (!netif_running(dev))
7888adfc5217SJeff Kirsher 			return -EAGAIN;
7889adfc5217SJeff Kirsher 
7890adfc5217SJeff Kirsher 		spin_lock_bh(&bp->phy_lock);
7891adfc5217SJeff Kirsher 		err = bnx2_write_phy(bp, data->reg_num & 0x1f, data->val_in);
7892adfc5217SJeff Kirsher 		spin_unlock_bh(&bp->phy_lock);
7893adfc5217SJeff Kirsher 
7894adfc5217SJeff Kirsher 		return err;
7895adfc5217SJeff Kirsher 
7896adfc5217SJeff Kirsher 	default:
7897adfc5217SJeff Kirsher 		/* do nothing */
7898adfc5217SJeff Kirsher 		break;
7899adfc5217SJeff Kirsher 	}
7900adfc5217SJeff Kirsher 	return -EOPNOTSUPP;
7901adfc5217SJeff Kirsher }
7902adfc5217SJeff Kirsher 
7903adfc5217SJeff Kirsher /* Called with rtnl_lock */
7904adfc5217SJeff Kirsher static int
7905adfc5217SJeff Kirsher bnx2_change_mac_addr(struct net_device *dev, void *p)
7906adfc5217SJeff Kirsher {
7907adfc5217SJeff Kirsher 	struct sockaddr *addr = p;
7908adfc5217SJeff Kirsher 	struct bnx2 *bp = netdev_priv(dev);
7909adfc5217SJeff Kirsher 
7910adfc5217SJeff Kirsher 	if (!is_valid_ether_addr(addr->sa_data))
7911504f9b5aSDanny Kukawka 		return -EADDRNOTAVAIL;
7912adfc5217SJeff Kirsher 
7913adfc5217SJeff Kirsher 	memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
7914adfc5217SJeff Kirsher 	if (netif_running(dev))
7915adfc5217SJeff Kirsher 		bnx2_set_mac_addr(bp, bp->dev->dev_addr, 0);
7916adfc5217SJeff Kirsher 
7917adfc5217SJeff Kirsher 	return 0;
7918adfc5217SJeff Kirsher }
7919adfc5217SJeff Kirsher 
7920adfc5217SJeff Kirsher /* Called with rtnl_lock */
7921adfc5217SJeff Kirsher static int
7922adfc5217SJeff Kirsher bnx2_change_mtu(struct net_device *dev, int new_mtu)
7923adfc5217SJeff Kirsher {
7924adfc5217SJeff Kirsher 	struct bnx2 *bp = netdev_priv(dev);
7925adfc5217SJeff Kirsher 
7926adfc5217SJeff Kirsher 	dev->mtu = new_mtu;
7927b033281fSMichael Chan 	return bnx2_change_ring_size(bp, bp->rx_ring_size, bp->tx_ring_size,
7928b033281fSMichael Chan 				     false);
7929adfc5217SJeff Kirsher }
7930adfc5217SJeff Kirsher 
7931adfc5217SJeff Kirsher #ifdef CONFIG_NET_POLL_CONTROLLER
7932adfc5217SJeff Kirsher static void
7933adfc5217SJeff Kirsher poll_bnx2(struct net_device *dev)
7934adfc5217SJeff Kirsher {
7935adfc5217SJeff Kirsher 	struct bnx2 *bp = netdev_priv(dev);
7936adfc5217SJeff Kirsher 	int i;
7937adfc5217SJeff Kirsher 
7938adfc5217SJeff Kirsher 	for (i = 0; i < bp->irq_nvecs; i++) {
7939adfc5217SJeff Kirsher 		struct bnx2_irq *irq = &bp->irq_tbl[i];
7940adfc5217SJeff Kirsher 
7941adfc5217SJeff Kirsher 		disable_irq(irq->vector);
7942adfc5217SJeff Kirsher 		irq->handler(irq->vector, &bp->bnx2_napi[i]);
7943adfc5217SJeff Kirsher 		enable_irq(irq->vector);
7944adfc5217SJeff Kirsher 	}
7945adfc5217SJeff Kirsher }
7946adfc5217SJeff Kirsher #endif
7947adfc5217SJeff Kirsher 
7948cfd95a63SBill Pemberton static void
7949adfc5217SJeff Kirsher bnx2_get_5709_media(struct bnx2 *bp)
7950adfc5217SJeff Kirsher {
7951e503e066SMichael Chan 	u32 val = BNX2_RD(bp, BNX2_MISC_DUAL_MEDIA_CTRL);
7952adfc5217SJeff Kirsher 	u32 bond_id = val & BNX2_MISC_DUAL_MEDIA_CTRL_BOND_ID;
7953adfc5217SJeff Kirsher 	u32 strap;
7954adfc5217SJeff Kirsher 
7955adfc5217SJeff Kirsher 	if (bond_id == BNX2_MISC_DUAL_MEDIA_CTRL_BOND_ID_C)
7956adfc5217SJeff Kirsher 		return;
7957adfc5217SJeff Kirsher 	else if (bond_id == BNX2_MISC_DUAL_MEDIA_CTRL_BOND_ID_S) {
7958adfc5217SJeff Kirsher 		bp->phy_flags |= BNX2_PHY_FLAG_SERDES;
7959adfc5217SJeff Kirsher 		return;
7960adfc5217SJeff Kirsher 	}
7961adfc5217SJeff Kirsher 
7962adfc5217SJeff Kirsher 	if (val & BNX2_MISC_DUAL_MEDIA_CTRL_STRAP_OVERRIDE)
7963adfc5217SJeff Kirsher 		strap = (val & BNX2_MISC_DUAL_MEDIA_CTRL_PHY_CTRL) >> 21;
7964adfc5217SJeff Kirsher 	else
7965adfc5217SJeff Kirsher 		strap = (val & BNX2_MISC_DUAL_MEDIA_CTRL_PHY_CTRL_STRAP) >> 8;
7966adfc5217SJeff Kirsher 
7967aefd90e4SMichael Chan 	if (bp->func == 0) {
7968adfc5217SJeff Kirsher 		switch (strap) {
7969adfc5217SJeff Kirsher 		case 0x4:
7970adfc5217SJeff Kirsher 		case 0x5:
7971adfc5217SJeff Kirsher 		case 0x6:
7972adfc5217SJeff Kirsher 			bp->phy_flags |= BNX2_PHY_FLAG_SERDES;
7973adfc5217SJeff Kirsher 			return;
7974adfc5217SJeff Kirsher 		}
7975adfc5217SJeff Kirsher 	} else {
7976adfc5217SJeff Kirsher 		switch (strap) {
7977adfc5217SJeff Kirsher 		case 0x1:
7978adfc5217SJeff Kirsher 		case 0x2:
7979adfc5217SJeff Kirsher 		case 0x4:
7980adfc5217SJeff Kirsher 			bp->phy_flags |= BNX2_PHY_FLAG_SERDES;
7981adfc5217SJeff Kirsher 			return;
7982adfc5217SJeff Kirsher 		}
7983adfc5217SJeff Kirsher 	}
7984adfc5217SJeff Kirsher }
7985adfc5217SJeff Kirsher 
7986cfd95a63SBill Pemberton static void
7987adfc5217SJeff Kirsher bnx2_get_pci_speed(struct bnx2 *bp)
7988adfc5217SJeff Kirsher {
7989adfc5217SJeff Kirsher 	u32 reg;
7990adfc5217SJeff Kirsher 
7991e503e066SMichael Chan 	reg = BNX2_RD(bp, BNX2_PCICFG_MISC_STATUS);
7992adfc5217SJeff Kirsher 	if (reg & BNX2_PCICFG_MISC_STATUS_PCIX_DET) {
7993adfc5217SJeff Kirsher 		u32 clkreg;
7994adfc5217SJeff Kirsher 
7995adfc5217SJeff Kirsher 		bp->flags |= BNX2_FLAG_PCIX;
7996adfc5217SJeff Kirsher 
7997e503e066SMichael Chan 		clkreg = BNX2_RD(bp, BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS);
7998adfc5217SJeff Kirsher 
7999adfc5217SJeff Kirsher 		clkreg &= BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET;
8000adfc5217SJeff Kirsher 		switch (clkreg) {
8001adfc5217SJeff Kirsher 		case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_133MHZ:
8002adfc5217SJeff Kirsher 			bp->bus_speed_mhz = 133;
8003adfc5217SJeff Kirsher 			break;
8004adfc5217SJeff Kirsher 
8005adfc5217SJeff Kirsher 		case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_95MHZ:
8006adfc5217SJeff Kirsher 			bp->bus_speed_mhz = 100;
8007adfc5217SJeff Kirsher 			break;
8008adfc5217SJeff Kirsher 
8009adfc5217SJeff Kirsher 		case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_66MHZ:
8010adfc5217SJeff Kirsher 		case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_80MHZ:
8011adfc5217SJeff Kirsher 			bp->bus_speed_mhz = 66;
8012adfc5217SJeff Kirsher 			break;
8013adfc5217SJeff Kirsher 
8014adfc5217SJeff Kirsher 		case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_48MHZ:
8015adfc5217SJeff Kirsher 		case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_55MHZ:
8016adfc5217SJeff Kirsher 			bp->bus_speed_mhz = 50;
8017adfc5217SJeff Kirsher 			break;
8018adfc5217SJeff Kirsher 
8019adfc5217SJeff Kirsher 		case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_LOW:
8020adfc5217SJeff Kirsher 		case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_32MHZ:
8021adfc5217SJeff Kirsher 		case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_38MHZ:
8022adfc5217SJeff Kirsher 			bp->bus_speed_mhz = 33;
8023adfc5217SJeff Kirsher 			break;
8024adfc5217SJeff Kirsher 		}
8025adfc5217SJeff Kirsher 	}
8026adfc5217SJeff Kirsher 	else {
8027adfc5217SJeff Kirsher 		if (reg & BNX2_PCICFG_MISC_STATUS_M66EN)
8028adfc5217SJeff Kirsher 			bp->bus_speed_mhz = 66;
8029adfc5217SJeff Kirsher 		else
8030adfc5217SJeff Kirsher 			bp->bus_speed_mhz = 33;
8031adfc5217SJeff Kirsher 	}
8032adfc5217SJeff Kirsher 
8033adfc5217SJeff Kirsher 	if (reg & BNX2_PCICFG_MISC_STATUS_32BIT_DET)
8034adfc5217SJeff Kirsher 		bp->flags |= BNX2_FLAG_PCI_32BIT;
8035adfc5217SJeff Kirsher 
8036adfc5217SJeff Kirsher }
8037adfc5217SJeff Kirsher 
8038cfd95a63SBill Pemberton static void
8039adfc5217SJeff Kirsher bnx2_read_vpd_fw_ver(struct bnx2 *bp)
8040adfc5217SJeff Kirsher {
8041adfc5217SJeff Kirsher 	int rc, i, j;
8042adfc5217SJeff Kirsher 	u8 *data;
8043adfc5217SJeff Kirsher 	unsigned int block_end, rosize, len;
8044adfc5217SJeff Kirsher 
8045adfc5217SJeff Kirsher #define BNX2_VPD_NVRAM_OFFSET	0x300
8046adfc5217SJeff Kirsher #define BNX2_VPD_LEN		128
8047adfc5217SJeff Kirsher #define BNX2_MAX_VER_SLEN	30
8048adfc5217SJeff Kirsher 
8049adfc5217SJeff Kirsher 	data = kmalloc(256, GFP_KERNEL);
8050adfc5217SJeff Kirsher 	if (!data)
8051adfc5217SJeff Kirsher 		return;
8052adfc5217SJeff Kirsher 
8053adfc5217SJeff Kirsher 	rc = bnx2_nvram_read(bp, BNX2_VPD_NVRAM_OFFSET, data + BNX2_VPD_LEN,
8054adfc5217SJeff Kirsher 			     BNX2_VPD_LEN);
8055adfc5217SJeff Kirsher 	if (rc)
8056adfc5217SJeff Kirsher 		goto vpd_done;
8057adfc5217SJeff Kirsher 
8058adfc5217SJeff Kirsher 	for (i = 0; i < BNX2_VPD_LEN; i += 4) {
8059adfc5217SJeff Kirsher 		data[i] = data[i + BNX2_VPD_LEN + 3];
8060adfc5217SJeff Kirsher 		data[i + 1] = data[i + BNX2_VPD_LEN + 2];
8061adfc5217SJeff Kirsher 		data[i + 2] = data[i + BNX2_VPD_LEN + 1];
8062adfc5217SJeff Kirsher 		data[i + 3] = data[i + BNX2_VPD_LEN];
8063adfc5217SJeff Kirsher 	}
8064adfc5217SJeff Kirsher 
8065adfc5217SJeff Kirsher 	i = pci_vpd_find_tag(data, 0, BNX2_VPD_LEN, PCI_VPD_LRDT_RO_DATA);
8066adfc5217SJeff Kirsher 	if (i < 0)
8067adfc5217SJeff Kirsher 		goto vpd_done;
8068adfc5217SJeff Kirsher 
8069adfc5217SJeff Kirsher 	rosize = pci_vpd_lrdt_size(&data[i]);
8070adfc5217SJeff Kirsher 	i += PCI_VPD_LRDT_TAG_SIZE;
8071adfc5217SJeff Kirsher 	block_end = i + rosize;
8072adfc5217SJeff Kirsher 
8073adfc5217SJeff Kirsher 	if (block_end > BNX2_VPD_LEN)
8074adfc5217SJeff Kirsher 		goto vpd_done;
8075adfc5217SJeff Kirsher 
8076adfc5217SJeff Kirsher 	j = pci_vpd_find_info_keyword(data, i, rosize,
8077adfc5217SJeff Kirsher 				      PCI_VPD_RO_KEYWORD_MFR_ID);
8078adfc5217SJeff Kirsher 	if (j < 0)
8079adfc5217SJeff Kirsher 		goto vpd_done;
8080adfc5217SJeff Kirsher 
8081adfc5217SJeff Kirsher 	len = pci_vpd_info_field_size(&data[j]);
8082adfc5217SJeff Kirsher 
8083adfc5217SJeff Kirsher 	j += PCI_VPD_INFO_FLD_HDR_SIZE;
8084adfc5217SJeff Kirsher 	if (j + len > block_end || len != 4 ||
8085adfc5217SJeff Kirsher 	    memcmp(&data[j], "1028", 4))
8086adfc5217SJeff Kirsher 		goto vpd_done;
8087adfc5217SJeff Kirsher 
8088adfc5217SJeff Kirsher 	j = pci_vpd_find_info_keyword(data, i, rosize,
8089adfc5217SJeff Kirsher 				      PCI_VPD_RO_KEYWORD_VENDOR0);
8090adfc5217SJeff Kirsher 	if (j < 0)
8091adfc5217SJeff Kirsher 		goto vpd_done;
8092adfc5217SJeff Kirsher 
8093adfc5217SJeff Kirsher 	len = pci_vpd_info_field_size(&data[j]);
8094adfc5217SJeff Kirsher 
8095adfc5217SJeff Kirsher 	j += PCI_VPD_INFO_FLD_HDR_SIZE;
8096adfc5217SJeff Kirsher 	if (j + len > block_end || len > BNX2_MAX_VER_SLEN)
8097adfc5217SJeff Kirsher 		goto vpd_done;
8098adfc5217SJeff Kirsher 
8099adfc5217SJeff Kirsher 	memcpy(bp->fw_version, &data[j], len);
8100adfc5217SJeff Kirsher 	bp->fw_version[len] = ' ';
8101adfc5217SJeff Kirsher 
8102adfc5217SJeff Kirsher vpd_done:
8103adfc5217SJeff Kirsher 	kfree(data);
8104adfc5217SJeff Kirsher }
8105adfc5217SJeff Kirsher 
8106cfd95a63SBill Pemberton static int
8107adfc5217SJeff Kirsher bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
8108adfc5217SJeff Kirsher {
8109adfc5217SJeff Kirsher 	struct bnx2 *bp;
8110adfc5217SJeff Kirsher 	int rc, i, j;
8111adfc5217SJeff Kirsher 	u32 reg;
8112adfc5217SJeff Kirsher 	u64 dma_mask, persist_dma_mask;
8113adfc5217SJeff Kirsher 	int err;
8114adfc5217SJeff Kirsher 
8115adfc5217SJeff Kirsher 	SET_NETDEV_DEV(dev, &pdev->dev);
8116adfc5217SJeff Kirsher 	bp = netdev_priv(dev);
8117adfc5217SJeff Kirsher 
8118adfc5217SJeff Kirsher 	bp->flags = 0;
8119adfc5217SJeff Kirsher 	bp->phy_flags = 0;
8120adfc5217SJeff Kirsher 
8121adfc5217SJeff Kirsher 	bp->temp_stats_blk =
8122adfc5217SJeff Kirsher 		kzalloc(sizeof(struct statistics_block), GFP_KERNEL);
8123adfc5217SJeff Kirsher 
8124b8aac410SVarsha Rao 	if (!bp->temp_stats_blk) {
8125adfc5217SJeff Kirsher 		rc = -ENOMEM;
8126adfc5217SJeff Kirsher 		goto err_out;
8127adfc5217SJeff Kirsher 	}
8128adfc5217SJeff Kirsher 
8129adfc5217SJeff Kirsher 	/* enable device (incl. PCI PM wakeup), and bus-mastering */
8130adfc5217SJeff Kirsher 	rc = pci_enable_device(pdev);
8131adfc5217SJeff Kirsher 	if (rc) {
8132adfc5217SJeff Kirsher 		dev_err(&pdev->dev, "Cannot enable PCI device, aborting\n");
8133adfc5217SJeff Kirsher 		goto err_out;
8134adfc5217SJeff Kirsher 	}
8135adfc5217SJeff Kirsher 
8136adfc5217SJeff Kirsher 	if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) {
8137adfc5217SJeff Kirsher 		dev_err(&pdev->dev,
8138adfc5217SJeff Kirsher 			"Cannot find PCI device base address, aborting\n");
8139adfc5217SJeff Kirsher 		rc = -ENODEV;
8140adfc5217SJeff Kirsher 		goto err_out_disable;
8141adfc5217SJeff Kirsher 	}
8142adfc5217SJeff Kirsher 
8143adfc5217SJeff Kirsher 	rc = pci_request_regions(pdev, DRV_MODULE_NAME);
8144adfc5217SJeff Kirsher 	if (rc) {
8145adfc5217SJeff Kirsher 		dev_err(&pdev->dev, "Cannot obtain PCI resources, aborting\n");
8146adfc5217SJeff Kirsher 		goto err_out_disable;
8147adfc5217SJeff Kirsher 	}
8148adfc5217SJeff Kirsher 
8149adfc5217SJeff Kirsher 	pci_set_master(pdev);
8150adfc5217SJeff Kirsher 
815185768271SYijing Wang 	bp->pm_cap = pdev->pm_cap;
8152adfc5217SJeff Kirsher 	if (bp->pm_cap == 0) {
8153adfc5217SJeff Kirsher 		dev_err(&pdev->dev,
8154adfc5217SJeff Kirsher 			"Cannot find power management capability, aborting\n");
8155adfc5217SJeff Kirsher 		rc = -EIO;
8156adfc5217SJeff Kirsher 		goto err_out_release;
8157adfc5217SJeff Kirsher 	}
8158adfc5217SJeff Kirsher 
8159adfc5217SJeff Kirsher 	bp->dev = dev;
8160adfc5217SJeff Kirsher 	bp->pdev = pdev;
8161adfc5217SJeff Kirsher 
8162adfc5217SJeff Kirsher 	spin_lock_init(&bp->phy_lock);
8163adfc5217SJeff Kirsher 	spin_lock_init(&bp->indirect_lock);
8164adfc5217SJeff Kirsher #ifdef BCM_CNIC
8165adfc5217SJeff Kirsher 	mutex_init(&bp->cnic_lock);
8166adfc5217SJeff Kirsher #endif
8167adfc5217SJeff Kirsher 	INIT_WORK(&bp->reset_task, bnx2_reset_task);
8168adfc5217SJeff Kirsher 
8169c0357e97SFrancois Romieu 	bp->regview = pci_iomap(pdev, 0, MB_GET_CID_ADDR(TX_TSS_CID +
8170c0357e97SFrancois Romieu 							 TX_MAX_TSS_RINGS + 1));
8171adfc5217SJeff Kirsher 	if (!bp->regview) {
8172adfc5217SJeff Kirsher 		dev_err(&pdev->dev, "Cannot map register space, aborting\n");
8173adfc5217SJeff Kirsher 		rc = -ENOMEM;
8174adfc5217SJeff Kirsher 		goto err_out_release;
8175adfc5217SJeff Kirsher 	}
8176adfc5217SJeff Kirsher 
8177adfc5217SJeff Kirsher 	/* Configure byte swap and enable write to the reg_window registers.
8178adfc5217SJeff Kirsher 	 * Rely on CPU to do target byte swapping on big endian systems
8179adfc5217SJeff Kirsher 	 * The chip's target access swapping will not swap all accesses
8180adfc5217SJeff Kirsher 	 */
8181e503e066SMichael Chan 	BNX2_WR(bp, BNX2_PCICFG_MISC_CONFIG,
8182adfc5217SJeff Kirsher 		BNX2_PCICFG_MISC_CONFIG_REG_WINDOW_ENA |
8183adfc5217SJeff Kirsher 		BNX2_PCICFG_MISC_CONFIG_TARGET_MB_WORD_SWAP);
8184adfc5217SJeff Kirsher 
8185e503e066SMichael Chan 	bp->chip_id = BNX2_RD(bp, BNX2_MISC_ID);
8186adfc5217SJeff Kirsher 
81874ce45e02SMichael Chan 	if (BNX2_CHIP(bp) == BNX2_CHIP_5709) {
8188adfc5217SJeff Kirsher 		if (!pci_is_pcie(pdev)) {
8189adfc5217SJeff Kirsher 			dev_err(&pdev->dev, "Not PCIE, aborting\n");
8190adfc5217SJeff Kirsher 			rc = -EIO;
8191adfc5217SJeff Kirsher 			goto err_out_unmap;
8192adfc5217SJeff Kirsher 		}
8193adfc5217SJeff Kirsher 		bp->flags |= BNX2_FLAG_PCIE;
81944ce45e02SMichael Chan 		if (BNX2_CHIP_REV(bp) == BNX2_CHIP_REV_Ax)
8195adfc5217SJeff Kirsher 			bp->flags |= BNX2_FLAG_JUMBO_BROKEN;
8196adfc5217SJeff Kirsher 
8197adfc5217SJeff Kirsher 		/* AER (Advanced Error Reporting) hooks */
8198adfc5217SJeff Kirsher 		err = pci_enable_pcie_error_reporting(pdev);
8199adfc5217SJeff Kirsher 		if (!err)
8200adfc5217SJeff Kirsher 			bp->flags |= BNX2_FLAG_AER_ENABLED;
8201adfc5217SJeff Kirsher 
8202adfc5217SJeff Kirsher 	} else {
8203adfc5217SJeff Kirsher 		bp->pcix_cap = pci_find_capability(pdev, PCI_CAP_ID_PCIX);
8204adfc5217SJeff Kirsher 		if (bp->pcix_cap == 0) {
8205adfc5217SJeff Kirsher 			dev_err(&pdev->dev,
8206adfc5217SJeff Kirsher 				"Cannot find PCIX capability, aborting\n");
8207adfc5217SJeff Kirsher 			rc = -EIO;
8208adfc5217SJeff Kirsher 			goto err_out_unmap;
8209adfc5217SJeff Kirsher 		}
8210adfc5217SJeff Kirsher 		bp->flags |= BNX2_FLAG_BROKEN_STATS;
8211adfc5217SJeff Kirsher 	}
8212adfc5217SJeff Kirsher 
82134ce45e02SMichael Chan 	if (BNX2_CHIP(bp) == BNX2_CHIP_5709 &&
82144ce45e02SMichael Chan 	    BNX2_CHIP_REV(bp) != BNX2_CHIP_REV_Ax) {
8215555a8428SYijing Wang 		if (pdev->msix_cap)
8216adfc5217SJeff Kirsher 			bp->flags |= BNX2_FLAG_MSIX_CAP;
8217adfc5217SJeff Kirsher 	}
8218adfc5217SJeff Kirsher 
82194ce45e02SMichael Chan 	if (BNX2_CHIP_ID(bp) != BNX2_CHIP_ID_5706_A0 &&
82204ce45e02SMichael Chan 	    BNX2_CHIP_ID(bp) != BNX2_CHIP_ID_5706_A1) {
8221555a8428SYijing Wang 		if (pdev->msi_cap)
8222adfc5217SJeff Kirsher 			bp->flags |= BNX2_FLAG_MSI_CAP;
8223adfc5217SJeff Kirsher 	}
8224adfc5217SJeff Kirsher 
8225adfc5217SJeff Kirsher 	/* 5708 cannot support DMA addresses > 40-bit.  */
82264ce45e02SMichael Chan 	if (BNX2_CHIP(bp) == BNX2_CHIP_5708)
8227adfc5217SJeff Kirsher 		persist_dma_mask = dma_mask = DMA_BIT_MASK(40);
8228adfc5217SJeff Kirsher 	else
8229adfc5217SJeff Kirsher 		persist_dma_mask = dma_mask = DMA_BIT_MASK(64);
8230adfc5217SJeff Kirsher 
8231adfc5217SJeff Kirsher 	/* Configure DMA attributes. */
8232adfc5217SJeff Kirsher 	if (pci_set_dma_mask(pdev, dma_mask) == 0) {
8233adfc5217SJeff Kirsher 		dev->features |= NETIF_F_HIGHDMA;
8234adfc5217SJeff Kirsher 		rc = pci_set_consistent_dma_mask(pdev, persist_dma_mask);
8235adfc5217SJeff Kirsher 		if (rc) {
8236adfc5217SJeff Kirsher 			dev_err(&pdev->dev,
8237adfc5217SJeff Kirsher 				"pci_set_consistent_dma_mask failed, aborting\n");
8238adfc5217SJeff Kirsher 			goto err_out_unmap;
8239adfc5217SJeff Kirsher 		}
8240adfc5217SJeff Kirsher 	} else if ((rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) != 0) {
8241adfc5217SJeff Kirsher 		dev_err(&pdev->dev, "System does not support DMA, aborting\n");
8242adfc5217SJeff Kirsher 		goto err_out_unmap;
8243adfc5217SJeff Kirsher 	}
8244adfc5217SJeff Kirsher 
8245adfc5217SJeff Kirsher 	if (!(bp->flags & BNX2_FLAG_PCIE))
8246adfc5217SJeff Kirsher 		bnx2_get_pci_speed(bp);
8247adfc5217SJeff Kirsher 
8248adfc5217SJeff Kirsher 	/* 5706A0 may falsely detect SERR and PERR. */
82494ce45e02SMichael Chan 	if (BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5706_A0) {
8250e503e066SMichael Chan 		reg = BNX2_RD(bp, PCI_COMMAND);
8251adfc5217SJeff Kirsher 		reg &= ~(PCI_COMMAND_SERR | PCI_COMMAND_PARITY);
8252e503e066SMichael Chan 		BNX2_WR(bp, PCI_COMMAND, reg);
82534ce45e02SMichael Chan 	} else if ((BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5706_A1) &&
8254adfc5217SJeff Kirsher 		!(bp->flags & BNX2_FLAG_PCIX)) {
8255adfc5217SJeff Kirsher 
8256adfc5217SJeff Kirsher 		dev_err(&pdev->dev,
8257adfc5217SJeff Kirsher 			"5706 A1 can only be used in a PCIX bus, aborting\n");
8258adfc5217SJeff Kirsher 		goto err_out_unmap;
8259adfc5217SJeff Kirsher 	}
8260adfc5217SJeff Kirsher 
8261adfc5217SJeff Kirsher 	bnx2_init_nvram(bp);
8262adfc5217SJeff Kirsher 
8263adfc5217SJeff Kirsher 	reg = bnx2_reg_rd_ind(bp, BNX2_SHM_HDR_SIGNATURE);
8264adfc5217SJeff Kirsher 
8265aefd90e4SMichael Chan 	if (bnx2_reg_rd_ind(bp, BNX2_MCP_TOE_ID) & BNX2_MCP_TOE_ID_FUNCTION_ID)
8266aefd90e4SMichael Chan 		bp->func = 1;
8267aefd90e4SMichael Chan 
8268adfc5217SJeff Kirsher 	if ((reg & BNX2_SHM_HDR_SIGNATURE_SIG_MASK) ==
8269adfc5217SJeff Kirsher 	    BNX2_SHM_HDR_SIGNATURE_SIG) {
8270aefd90e4SMichael Chan 		u32 off = bp->func << 2;
8271adfc5217SJeff Kirsher 
8272adfc5217SJeff Kirsher 		bp->shmem_base = bnx2_reg_rd_ind(bp, BNX2_SHM_HDR_ADDR_0 + off);
8273adfc5217SJeff Kirsher 	} else
8274adfc5217SJeff Kirsher 		bp->shmem_base = HOST_VIEW_SHMEM_BASE;
8275adfc5217SJeff Kirsher 
8276adfc5217SJeff Kirsher 	/* Get the permanent MAC address.  First we need to make sure the
8277adfc5217SJeff Kirsher 	 * firmware is actually running.
8278adfc5217SJeff Kirsher 	 */
8279adfc5217SJeff Kirsher 	reg = bnx2_shmem_rd(bp, BNX2_DEV_INFO_SIGNATURE);
8280adfc5217SJeff Kirsher 
8281adfc5217SJeff Kirsher 	if ((reg & BNX2_DEV_INFO_SIGNATURE_MAGIC_MASK) !=
8282adfc5217SJeff Kirsher 	    BNX2_DEV_INFO_SIGNATURE_MAGIC) {
8283adfc5217SJeff Kirsher 		dev_err(&pdev->dev, "Firmware not running, aborting\n");
8284adfc5217SJeff Kirsher 		rc = -ENODEV;
8285adfc5217SJeff Kirsher 		goto err_out_unmap;
8286adfc5217SJeff Kirsher 	}
8287adfc5217SJeff Kirsher 
8288adfc5217SJeff Kirsher 	bnx2_read_vpd_fw_ver(bp);
8289adfc5217SJeff Kirsher 
8290adfc5217SJeff Kirsher 	j = strlen(bp->fw_version);
8291adfc5217SJeff Kirsher 	reg = bnx2_shmem_rd(bp, BNX2_DEV_INFO_BC_REV);
8292adfc5217SJeff Kirsher 	for (i = 0; i < 3 && j < 24; i++) {
8293adfc5217SJeff Kirsher 		u8 num, k, skip0;
8294adfc5217SJeff Kirsher 
8295adfc5217SJeff Kirsher 		if (i == 0) {
8296adfc5217SJeff Kirsher 			bp->fw_version[j++] = 'b';
8297adfc5217SJeff Kirsher 			bp->fw_version[j++] = 'c';
8298adfc5217SJeff Kirsher 			bp->fw_version[j++] = ' ';
8299adfc5217SJeff Kirsher 		}
8300adfc5217SJeff Kirsher 		num = (u8) (reg >> (24 - (i * 8)));
8301adfc5217SJeff Kirsher 		for (k = 100, skip0 = 1; k >= 1; num %= k, k /= 10) {
8302adfc5217SJeff Kirsher 			if (num >= k || !skip0 || k == 1) {
8303adfc5217SJeff Kirsher 				bp->fw_version[j++] = (num / k) + '0';
8304adfc5217SJeff Kirsher 				skip0 = 0;
8305adfc5217SJeff Kirsher 			}
8306adfc5217SJeff Kirsher 		}
8307adfc5217SJeff Kirsher 		if (i != 2)
8308adfc5217SJeff Kirsher 			bp->fw_version[j++] = '.';
8309adfc5217SJeff Kirsher 	}
8310adfc5217SJeff Kirsher 	reg = bnx2_shmem_rd(bp, BNX2_PORT_FEATURE);
8311adfc5217SJeff Kirsher 	if (reg & BNX2_PORT_FEATURE_WOL_ENABLED)
8312adfc5217SJeff Kirsher 		bp->wol = 1;
8313adfc5217SJeff Kirsher 
8314adfc5217SJeff Kirsher 	if (reg & BNX2_PORT_FEATURE_ASF_ENABLED) {
8315adfc5217SJeff Kirsher 		bp->flags |= BNX2_FLAG_ASF_ENABLE;
8316adfc5217SJeff Kirsher 
8317adfc5217SJeff Kirsher 		for (i = 0; i < 30; i++) {
8318adfc5217SJeff Kirsher 			reg = bnx2_shmem_rd(bp, BNX2_BC_STATE_CONDITION);
8319adfc5217SJeff Kirsher 			if (reg & BNX2_CONDITION_MFW_RUN_MASK)
8320adfc5217SJeff Kirsher 				break;
8321adfc5217SJeff Kirsher 			msleep(10);
8322adfc5217SJeff Kirsher 		}
8323adfc5217SJeff Kirsher 	}
8324adfc5217SJeff Kirsher 	reg = bnx2_shmem_rd(bp, BNX2_BC_STATE_CONDITION);
8325adfc5217SJeff Kirsher 	reg &= BNX2_CONDITION_MFW_RUN_MASK;
8326adfc5217SJeff Kirsher 	if (reg != BNX2_CONDITION_MFW_RUN_UNKNOWN &&
8327adfc5217SJeff Kirsher 	    reg != BNX2_CONDITION_MFW_RUN_NONE) {
8328adfc5217SJeff Kirsher 		u32 addr = bnx2_shmem_rd(bp, BNX2_MFW_VER_PTR);
8329adfc5217SJeff Kirsher 
8330adfc5217SJeff Kirsher 		if (j < 32)
8331adfc5217SJeff Kirsher 			bp->fw_version[j++] = ' ';
8332adfc5217SJeff Kirsher 		for (i = 0; i < 3 && j < 28; i++) {
8333adfc5217SJeff Kirsher 			reg = bnx2_reg_rd_ind(bp, addr + i * 4);
8334adfc5217SJeff Kirsher 			reg = be32_to_cpu(reg);
8335adfc5217SJeff Kirsher 			memcpy(&bp->fw_version[j], &reg, 4);
8336adfc5217SJeff Kirsher 			j += 4;
8337adfc5217SJeff Kirsher 		}
8338adfc5217SJeff Kirsher 	}
8339adfc5217SJeff Kirsher 
8340adfc5217SJeff Kirsher 	reg = bnx2_shmem_rd(bp, BNX2_PORT_HW_CFG_MAC_UPPER);
8341adfc5217SJeff Kirsher 	bp->mac_addr[0] = (u8) (reg >> 8);
8342adfc5217SJeff Kirsher 	bp->mac_addr[1] = (u8) reg;
8343adfc5217SJeff Kirsher 
8344adfc5217SJeff Kirsher 	reg = bnx2_shmem_rd(bp, BNX2_PORT_HW_CFG_MAC_LOWER);
8345adfc5217SJeff Kirsher 	bp->mac_addr[2] = (u8) (reg >> 24);
8346adfc5217SJeff Kirsher 	bp->mac_addr[3] = (u8) (reg >> 16);
8347adfc5217SJeff Kirsher 	bp->mac_addr[4] = (u8) (reg >> 8);
8348adfc5217SJeff Kirsher 	bp->mac_addr[5] = (u8) reg;
8349adfc5217SJeff Kirsher 
83502bc4078eSMichael Chan 	bp->tx_ring_size = BNX2_MAX_TX_DESC_CNT;
8351adfc5217SJeff Kirsher 	bnx2_set_rx_ring_size(bp, 255);
8352adfc5217SJeff Kirsher 
8353adfc5217SJeff Kirsher 	bp->tx_quick_cons_trip_int = 2;
8354adfc5217SJeff Kirsher 	bp->tx_quick_cons_trip = 20;
8355adfc5217SJeff Kirsher 	bp->tx_ticks_int = 18;
8356adfc5217SJeff Kirsher 	bp->tx_ticks = 80;
8357adfc5217SJeff Kirsher 
8358adfc5217SJeff Kirsher 	bp->rx_quick_cons_trip_int = 2;
8359adfc5217SJeff Kirsher 	bp->rx_quick_cons_trip = 12;
8360adfc5217SJeff Kirsher 	bp->rx_ticks_int = 18;
8361adfc5217SJeff Kirsher 	bp->rx_ticks = 18;
8362adfc5217SJeff Kirsher 
8363adfc5217SJeff Kirsher 	bp->stats_ticks = USEC_PER_SEC & BNX2_HC_STATS_TICKS_HC_STAT_TICKS;
8364adfc5217SJeff Kirsher 
8365adfc5217SJeff Kirsher 	bp->current_interval = BNX2_TIMER_INTERVAL;
8366adfc5217SJeff Kirsher 
8367adfc5217SJeff Kirsher 	bp->phy_addr = 1;
8368adfc5217SJeff Kirsher 
83698fae307cSwangweidong 	/* allocate stats_blk */
83708fae307cSwangweidong 	rc = bnx2_alloc_stats_blk(dev);
83718fae307cSwangweidong 	if (rc)
83728fae307cSwangweidong 		goto err_out_unmap;
83738fae307cSwangweidong 
8374adfc5217SJeff Kirsher 	/* Disable WOL support if we are running on a SERDES chip. */
83754ce45e02SMichael Chan 	if (BNX2_CHIP(bp) == BNX2_CHIP_5709)
8376adfc5217SJeff Kirsher 		bnx2_get_5709_media(bp);
83774ce45e02SMichael Chan 	else if (BNX2_CHIP_BOND(bp) & BNX2_CHIP_BOND_SERDES_BIT)
8378adfc5217SJeff Kirsher 		bp->phy_flags |= BNX2_PHY_FLAG_SERDES;
8379adfc5217SJeff Kirsher 
8380adfc5217SJeff Kirsher 	bp->phy_port = PORT_TP;
8381adfc5217SJeff Kirsher 	if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
8382adfc5217SJeff Kirsher 		bp->phy_port = PORT_FIBRE;
8383adfc5217SJeff Kirsher 		reg = bnx2_shmem_rd(bp, BNX2_SHARED_HW_CFG_CONFIG);
8384adfc5217SJeff Kirsher 		if (!(reg & BNX2_SHARED_HW_CFG_GIG_LINK_ON_VAUX)) {
8385adfc5217SJeff Kirsher 			bp->flags |= BNX2_FLAG_NO_WOL;
8386adfc5217SJeff Kirsher 			bp->wol = 0;
8387adfc5217SJeff Kirsher 		}
83884ce45e02SMichael Chan 		if (BNX2_CHIP(bp) == BNX2_CHIP_5706) {
8389adfc5217SJeff Kirsher 			/* Don't do parallel detect on this board because of
8390adfc5217SJeff Kirsher 			 * some board problems.  The link will not go down
8391adfc5217SJeff Kirsher 			 * if we do parallel detect.
8392adfc5217SJeff Kirsher 			 */
8393adfc5217SJeff Kirsher 			if (pdev->subsystem_vendor == PCI_VENDOR_ID_HP &&
8394adfc5217SJeff Kirsher 			    pdev->subsystem_device == 0x310c)
8395adfc5217SJeff Kirsher 				bp->phy_flags |= BNX2_PHY_FLAG_NO_PARALLEL;
8396adfc5217SJeff Kirsher 		} else {
8397adfc5217SJeff Kirsher 			bp->phy_addr = 2;
8398adfc5217SJeff Kirsher 			if (reg & BNX2_SHARED_HW_CFG_PHY_2_5G)
8399adfc5217SJeff Kirsher 				bp->phy_flags |= BNX2_PHY_FLAG_2_5G_CAPABLE;
8400adfc5217SJeff Kirsher 		}
84014ce45e02SMichael Chan 	} else if (BNX2_CHIP(bp) == BNX2_CHIP_5706 ||
84024ce45e02SMichael Chan 		   BNX2_CHIP(bp) == BNX2_CHIP_5708)
8403adfc5217SJeff Kirsher 		bp->phy_flags |= BNX2_PHY_FLAG_CRC_FIX;
84044ce45e02SMichael Chan 	else if (BNX2_CHIP(bp) == BNX2_CHIP_5709 &&
84054ce45e02SMichael Chan 		 (BNX2_CHIP_REV(bp) == BNX2_CHIP_REV_Ax ||
84064ce45e02SMichael Chan 		  BNX2_CHIP_REV(bp) == BNX2_CHIP_REV_Bx))
8407adfc5217SJeff Kirsher 		bp->phy_flags |= BNX2_PHY_FLAG_DIS_EARLY_DAC;
8408adfc5217SJeff Kirsher 
8409adfc5217SJeff Kirsher 	bnx2_init_fw_cap(bp);
8410adfc5217SJeff Kirsher 
84114ce45e02SMichael Chan 	if ((BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5708_A0) ||
84124ce45e02SMichael Chan 	    (BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5708_B0) ||
84134ce45e02SMichael Chan 	    (BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5708_B1) ||
8414e503e066SMichael Chan 	    !(BNX2_RD(bp, BNX2_PCI_CONFIG_3) & BNX2_PCI_CONFIG_3_VAUX_PRESET)) {
8415adfc5217SJeff Kirsher 		bp->flags |= BNX2_FLAG_NO_WOL;
8416adfc5217SJeff Kirsher 		bp->wol = 0;
8417adfc5217SJeff Kirsher 	}
8418adfc5217SJeff Kirsher 
84196d5e85c7SMichael Chan 	if (bp->flags & BNX2_FLAG_NO_WOL)
84206d5e85c7SMichael Chan 		device_set_wakeup_capable(&bp->pdev->dev, false);
84216d5e85c7SMichael Chan 	else
84226d5e85c7SMichael Chan 		device_set_wakeup_enable(&bp->pdev->dev, bp->wol);
84236d5e85c7SMichael Chan 
84244ce45e02SMichael Chan 	if (BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5706_A0) {
8425adfc5217SJeff Kirsher 		bp->tx_quick_cons_trip_int =
8426adfc5217SJeff Kirsher 			bp->tx_quick_cons_trip;
8427adfc5217SJeff Kirsher 		bp->tx_ticks_int = bp->tx_ticks;
8428adfc5217SJeff Kirsher 		bp->rx_quick_cons_trip_int =
8429adfc5217SJeff Kirsher 			bp->rx_quick_cons_trip;
8430adfc5217SJeff Kirsher 		bp->rx_ticks_int = bp->rx_ticks;
8431adfc5217SJeff Kirsher 		bp->comp_prod_trip_int = bp->comp_prod_trip;
8432adfc5217SJeff Kirsher 		bp->com_ticks_int = bp->com_ticks;
8433adfc5217SJeff Kirsher 		bp->cmd_ticks_int = bp->cmd_ticks;
8434adfc5217SJeff Kirsher 	}
8435adfc5217SJeff Kirsher 
8436adfc5217SJeff Kirsher 	/* Disable MSI on 5706 if AMD 8132 bridge is found.
8437adfc5217SJeff Kirsher 	 *
8438adfc5217SJeff Kirsher 	 * MSI is defined to be 32-bit write.  The 5706 does 64-bit MSI writes
8439adfc5217SJeff Kirsher 	 * with byte enables disabled on the unused 32-bit word.  This is legal
8440adfc5217SJeff Kirsher 	 * but causes problems on the AMD 8132 which will eventually stop
8441adfc5217SJeff Kirsher 	 * responding after a while.
8442adfc5217SJeff Kirsher 	 *
8443adfc5217SJeff Kirsher 	 * AMD believes this incompatibility is unique to the 5706, and
8444adfc5217SJeff Kirsher 	 * prefers to locally disable MSI rather than globally disabling it.
8445adfc5217SJeff Kirsher 	 */
84464ce45e02SMichael Chan 	if (BNX2_CHIP(bp) == BNX2_CHIP_5706 && disable_msi == 0) {
8447adfc5217SJeff Kirsher 		struct pci_dev *amd_8132 = NULL;
8448adfc5217SJeff Kirsher 
8449adfc5217SJeff Kirsher 		while ((amd_8132 = pci_get_device(PCI_VENDOR_ID_AMD,
8450adfc5217SJeff Kirsher 						  PCI_DEVICE_ID_AMD_8132_BRIDGE,
8451adfc5217SJeff Kirsher 						  amd_8132))) {
8452adfc5217SJeff Kirsher 
8453adfc5217SJeff Kirsher 			if (amd_8132->revision >= 0x10 &&
8454adfc5217SJeff Kirsher 			    amd_8132->revision <= 0x13) {
8455adfc5217SJeff Kirsher 				disable_msi = 1;
8456adfc5217SJeff Kirsher 				pci_dev_put(amd_8132);
8457adfc5217SJeff Kirsher 				break;
8458adfc5217SJeff Kirsher 			}
8459adfc5217SJeff Kirsher 		}
8460adfc5217SJeff Kirsher 	}
8461adfc5217SJeff Kirsher 
8462adfc5217SJeff Kirsher 	bnx2_set_default_link(bp);
8463adfc5217SJeff Kirsher 	bp->req_flow_ctrl = FLOW_CTRL_RX | FLOW_CTRL_TX;
8464adfc5217SJeff Kirsher 
8465e99e88a9SKees Cook 	timer_setup(&bp->timer, bnx2_timer, 0);
8466adfc5217SJeff Kirsher 	bp->timer.expires = RUN_AT(BNX2_TIMER_INTERVAL);
8467adfc5217SJeff Kirsher 
8468adfc5217SJeff Kirsher #ifdef BCM_CNIC
8469adfc5217SJeff Kirsher 	if (bnx2_shmem_rd(bp, BNX2_ISCSI_INITIATOR) & BNX2_ISCSI_INITIATOR_EN)
8470adfc5217SJeff Kirsher 		bp->cnic_eth_dev.max_iscsi_conn =
8471adfc5217SJeff Kirsher 			(bnx2_shmem_rd(bp, BNX2_ISCSI_MAX_CONN) &
8472adfc5217SJeff Kirsher 			 BNX2_ISCSI_MAX_CONN_MASK) >> BNX2_ISCSI_MAX_CONN_SHIFT;
84734bd9b0ffSMichael Chan 	bp->cnic_probe = bnx2_cnic_probe;
8474adfc5217SJeff Kirsher #endif
8475adfc5217SJeff Kirsher 	pci_save_state(pdev);
8476adfc5217SJeff Kirsher 
8477adfc5217SJeff Kirsher 	return 0;
8478adfc5217SJeff Kirsher 
8479adfc5217SJeff Kirsher err_out_unmap:
8480adfc5217SJeff Kirsher 	if (bp->flags & BNX2_FLAG_AER_ENABLED) {
8481adfc5217SJeff Kirsher 		pci_disable_pcie_error_reporting(pdev);
8482adfc5217SJeff Kirsher 		bp->flags &= ~BNX2_FLAG_AER_ENABLED;
8483adfc5217SJeff Kirsher 	}
8484adfc5217SJeff Kirsher 
8485c0357e97SFrancois Romieu 	pci_iounmap(pdev, bp->regview);
8486adfc5217SJeff Kirsher 	bp->regview = NULL;
8487adfc5217SJeff Kirsher 
8488adfc5217SJeff Kirsher err_out_release:
8489adfc5217SJeff Kirsher 	pci_release_regions(pdev);
8490adfc5217SJeff Kirsher 
8491adfc5217SJeff Kirsher err_out_disable:
8492adfc5217SJeff Kirsher 	pci_disable_device(pdev);
8493adfc5217SJeff Kirsher 
8494adfc5217SJeff Kirsher err_out:
84953703ebe4Swangweidong 	kfree(bp->temp_stats_blk);
84963703ebe4Swangweidong 
8497adfc5217SJeff Kirsher 	return rc;
8498adfc5217SJeff Kirsher }
8499adfc5217SJeff Kirsher 
8500cfd95a63SBill Pemberton static char *
8501adfc5217SJeff Kirsher bnx2_bus_string(struct bnx2 *bp, char *str)
8502adfc5217SJeff Kirsher {
8503adfc5217SJeff Kirsher 	char *s = str;
8504adfc5217SJeff Kirsher 
8505adfc5217SJeff Kirsher 	if (bp->flags & BNX2_FLAG_PCIE) {
8506adfc5217SJeff Kirsher 		s += sprintf(s, "PCI Express");
8507adfc5217SJeff Kirsher 	} else {
8508adfc5217SJeff Kirsher 		s += sprintf(s, "PCI");
8509adfc5217SJeff Kirsher 		if (bp->flags & BNX2_FLAG_PCIX)
8510adfc5217SJeff Kirsher 			s += sprintf(s, "-X");
8511adfc5217SJeff Kirsher 		if (bp->flags & BNX2_FLAG_PCI_32BIT)
8512adfc5217SJeff Kirsher 			s += sprintf(s, " 32-bit");
8513adfc5217SJeff Kirsher 		else
8514adfc5217SJeff Kirsher 			s += sprintf(s, " 64-bit");
8515adfc5217SJeff Kirsher 		s += sprintf(s, " %dMHz", bp->bus_speed_mhz);
8516adfc5217SJeff Kirsher 	}
8517adfc5217SJeff Kirsher 	return str;
8518adfc5217SJeff Kirsher }
8519adfc5217SJeff Kirsher 
8520adfc5217SJeff Kirsher static void
8521adfc5217SJeff Kirsher bnx2_del_napi(struct bnx2 *bp)
8522adfc5217SJeff Kirsher {
8523adfc5217SJeff Kirsher 	int i;
8524adfc5217SJeff Kirsher 
8525adfc5217SJeff Kirsher 	for (i = 0; i < bp->irq_nvecs; i++)
8526adfc5217SJeff Kirsher 		netif_napi_del(&bp->bnx2_napi[i].napi);
8527adfc5217SJeff Kirsher }
8528adfc5217SJeff Kirsher 
8529adfc5217SJeff Kirsher static void
8530adfc5217SJeff Kirsher bnx2_init_napi(struct bnx2 *bp)
8531adfc5217SJeff Kirsher {
8532adfc5217SJeff Kirsher 	int i;
8533adfc5217SJeff Kirsher 
8534adfc5217SJeff Kirsher 	for (i = 0; i < bp->irq_nvecs; i++) {
8535adfc5217SJeff Kirsher 		struct bnx2_napi *bnapi = &bp->bnx2_napi[i];
8536adfc5217SJeff Kirsher 		int (*poll)(struct napi_struct *, int);
8537adfc5217SJeff Kirsher 
8538adfc5217SJeff Kirsher 		if (i == 0)
8539adfc5217SJeff Kirsher 			poll = bnx2_poll;
8540adfc5217SJeff Kirsher 		else
8541adfc5217SJeff Kirsher 			poll = bnx2_poll_msix;
8542adfc5217SJeff Kirsher 
8543adfc5217SJeff Kirsher 		netif_napi_add(bp->dev, &bp->bnx2_napi[i].napi, poll, 64);
8544adfc5217SJeff Kirsher 		bnapi->bp = bp;
8545adfc5217SJeff Kirsher 	}
8546adfc5217SJeff Kirsher }
8547adfc5217SJeff Kirsher 
8548adfc5217SJeff Kirsher static const struct net_device_ops bnx2_netdev_ops = {
8549adfc5217SJeff Kirsher 	.ndo_open		= bnx2_open,
8550adfc5217SJeff Kirsher 	.ndo_start_xmit		= bnx2_start_xmit,
8551adfc5217SJeff Kirsher 	.ndo_stop		= bnx2_close,
8552adfc5217SJeff Kirsher 	.ndo_get_stats64	= bnx2_get_stats64,
8553adfc5217SJeff Kirsher 	.ndo_set_rx_mode	= bnx2_set_rx_mode,
8554adfc5217SJeff Kirsher 	.ndo_do_ioctl		= bnx2_ioctl,
8555adfc5217SJeff Kirsher 	.ndo_validate_addr	= eth_validate_addr,
8556adfc5217SJeff Kirsher 	.ndo_set_mac_address	= bnx2_change_mac_addr,
8557adfc5217SJeff Kirsher 	.ndo_change_mtu		= bnx2_change_mtu,
8558adfc5217SJeff Kirsher 	.ndo_set_features	= bnx2_set_features,
8559adfc5217SJeff Kirsher 	.ndo_tx_timeout		= bnx2_tx_timeout,
8560adfc5217SJeff Kirsher #ifdef CONFIG_NET_POLL_CONTROLLER
8561adfc5217SJeff Kirsher 	.ndo_poll_controller	= poll_bnx2,
8562adfc5217SJeff Kirsher #endif
8563adfc5217SJeff Kirsher };
8564adfc5217SJeff Kirsher 
8565cfd95a63SBill Pemberton static int
8566adfc5217SJeff Kirsher bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
8567adfc5217SJeff Kirsher {
8568adfc5217SJeff Kirsher 	static int version_printed = 0;
8569c0357e97SFrancois Romieu 	struct net_device *dev;
8570adfc5217SJeff Kirsher 	struct bnx2 *bp;
8571adfc5217SJeff Kirsher 	int rc;
8572adfc5217SJeff Kirsher 	char str[40];
8573adfc5217SJeff Kirsher 
8574adfc5217SJeff Kirsher 	if (version_printed++ == 0)
8575adfc5217SJeff Kirsher 		pr_info("%s", version);
8576adfc5217SJeff Kirsher 
8577adfc5217SJeff Kirsher 	/* dev zeroed in init_etherdev */
8578adfc5217SJeff Kirsher 	dev = alloc_etherdev_mq(sizeof(*bp), TX_MAX_RINGS);
8579adfc5217SJeff Kirsher 	if (!dev)
8580adfc5217SJeff Kirsher 		return -ENOMEM;
8581adfc5217SJeff Kirsher 
8582adfc5217SJeff Kirsher 	rc = bnx2_init_board(pdev, dev);
8583c0357e97SFrancois Romieu 	if (rc < 0)
8584c0357e97SFrancois Romieu 		goto err_free;
8585adfc5217SJeff Kirsher 
8586adfc5217SJeff Kirsher 	dev->netdev_ops = &bnx2_netdev_ops;
8587adfc5217SJeff Kirsher 	dev->watchdog_timeo = TX_TIMEOUT;
8588adfc5217SJeff Kirsher 	dev->ethtool_ops = &bnx2_ethtool_ops;
8589adfc5217SJeff Kirsher 
8590adfc5217SJeff Kirsher 	bp = netdev_priv(dev);
8591adfc5217SJeff Kirsher 
8592adfc5217SJeff Kirsher 	pci_set_drvdata(pdev, dev);
8593adfc5217SJeff Kirsher 
85946df77862SBaoquan He 	/*
85956df77862SBaoquan He 	 * In-flight DMA from 1st kernel could continue going in kdump kernel.
85966df77862SBaoquan He 	 * New io-page table has been created before bnx2 does reset at open stage.
85976df77862SBaoquan He 	 * We have to wait for the in-flight DMA to complete to avoid it look up
85986df77862SBaoquan He 	 * into the newly created io-page table.
85996df77862SBaoquan He 	 */
86006df77862SBaoquan He 	if (is_kdump_kernel())
86016df77862SBaoquan He 		bnx2_wait_dma_complete(bp);
86023e1be7adSBaoquan He 
8603d458cdf7SJoe Perches 	memcpy(dev->dev_addr, bp->mac_addr, ETH_ALEN);
8604adfc5217SJeff Kirsher 
8605adfc5217SJeff Kirsher 	dev->hw_features = NETIF_F_IP_CSUM | NETIF_F_SG |
8606adfc5217SJeff Kirsher 		NETIF_F_TSO | NETIF_F_TSO_ECN |
8607adfc5217SJeff Kirsher 		NETIF_F_RXHASH | NETIF_F_RXCSUM;
8608adfc5217SJeff Kirsher 
86094ce45e02SMichael Chan 	if (BNX2_CHIP(bp) == BNX2_CHIP_5709)
8610adfc5217SJeff Kirsher 		dev->hw_features |= NETIF_F_IPV6_CSUM | NETIF_F_TSO6;
8611adfc5217SJeff Kirsher 
8612adfc5217SJeff Kirsher 	dev->vlan_features = dev->hw_features;
8613f646968fSPatrick McHardy 	dev->hw_features |= NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX;
8614adfc5217SJeff Kirsher 	dev->features |= dev->hw_features;
861501789349SJiri Pirko 	dev->priv_flags |= IFF_UNICAST_FLT;
8616e1c6dccaSJarod Wilson 	dev->min_mtu = MIN_ETHERNET_PACKET_SIZE;
8617e1c6dccaSJarod Wilson 	dev->max_mtu = MAX_ETHERNET_JUMBO_PACKET_SIZE;
8618adfc5217SJeff Kirsher 
861926caa346SIvan Vecera 	if (!(bp->flags & BNX2_FLAG_CAN_KEEP_VLAN))
862026caa346SIvan Vecera 		dev->hw_features &= ~NETIF_F_HW_VLAN_CTAG_RX;
862126caa346SIvan Vecera 
8622adfc5217SJeff Kirsher 	if ((rc = register_netdev(dev))) {
8623adfc5217SJeff Kirsher 		dev_err(&pdev->dev, "Cannot register net device\n");
8624adfc5217SJeff Kirsher 		goto error;
8625adfc5217SJeff Kirsher 	}
8626adfc5217SJeff Kirsher 
8627c0357e97SFrancois Romieu 	netdev_info(dev, "%s (%c%d) %s found at mem %lx, IRQ %d, "
8628c0357e97SFrancois Romieu 		    "node addr %pM\n", board_info[ent->driver_data].name,
86294ce45e02SMichael Chan 		    ((BNX2_CHIP_ID(bp) & 0xf000) >> 12) + 'A',
86304ce45e02SMichael Chan 		    ((BNX2_CHIP_ID(bp) & 0x0ff0) >> 4),
8631c0357e97SFrancois Romieu 		    bnx2_bus_string(bp, str), (long)pci_resource_start(pdev, 0),
8632c0357e97SFrancois Romieu 		    pdev->irq, dev->dev_addr);
8633adfc5217SJeff Kirsher 
8634adfc5217SJeff Kirsher 	return 0;
8635adfc5217SJeff Kirsher 
8636adfc5217SJeff Kirsher error:
8637fda4d85dSMichael Chan 	pci_iounmap(pdev, bp->regview);
8638adfc5217SJeff Kirsher 	pci_release_regions(pdev);
8639adfc5217SJeff Kirsher 	pci_disable_device(pdev);
8640c0357e97SFrancois Romieu err_free:
86418fae307cSwangweidong 	bnx2_free_stats_blk(dev);
8642adfc5217SJeff Kirsher 	free_netdev(dev);
8643adfc5217SJeff Kirsher 	return rc;
8644adfc5217SJeff Kirsher }
8645adfc5217SJeff Kirsher 
8646cfd95a63SBill Pemberton static void
8647adfc5217SJeff Kirsher bnx2_remove_one(struct pci_dev *pdev)
8648adfc5217SJeff Kirsher {
8649adfc5217SJeff Kirsher 	struct net_device *dev = pci_get_drvdata(pdev);
8650adfc5217SJeff Kirsher 	struct bnx2 *bp = netdev_priv(dev);
8651adfc5217SJeff Kirsher 
8652adfc5217SJeff Kirsher 	unregister_netdev(dev);
8653adfc5217SJeff Kirsher 
8654adfc5217SJeff Kirsher 	del_timer_sync(&bp->timer);
8655adfc5217SJeff Kirsher 	cancel_work_sync(&bp->reset_task);
8656adfc5217SJeff Kirsher 
8657c0357e97SFrancois Romieu 	pci_iounmap(bp->pdev, bp->regview);
8658adfc5217SJeff Kirsher 
86598fae307cSwangweidong 	bnx2_free_stats_blk(dev);
8660adfc5217SJeff Kirsher 	kfree(bp->temp_stats_blk);
8661adfc5217SJeff Kirsher 
8662adfc5217SJeff Kirsher 	if (bp->flags & BNX2_FLAG_AER_ENABLED) {
8663adfc5217SJeff Kirsher 		pci_disable_pcie_error_reporting(pdev);
8664adfc5217SJeff Kirsher 		bp->flags &= ~BNX2_FLAG_AER_ENABLED;
8665adfc5217SJeff Kirsher 	}
8666adfc5217SJeff Kirsher 
86677880b72eSfrançois romieu 	bnx2_release_firmware(bp);
86687880b72eSfrançois romieu 
8669adfc5217SJeff Kirsher 	free_netdev(dev);
8670adfc5217SJeff Kirsher 
8671adfc5217SJeff Kirsher 	pci_release_regions(pdev);
8672adfc5217SJeff Kirsher 	pci_disable_device(pdev);
8673adfc5217SJeff Kirsher }
8674adfc5217SJeff Kirsher 
867577d149c4SDaniel J Blueman #ifdef CONFIG_PM_SLEEP
8676adfc5217SJeff Kirsher static int
867728fb4eb4SMichael Chan bnx2_suspend(struct device *device)
8678adfc5217SJeff Kirsher {
867928fb4eb4SMichael Chan 	struct pci_dev *pdev = to_pci_dev(device);
8680adfc5217SJeff Kirsher 	struct net_device *dev = pci_get_drvdata(pdev);
8681adfc5217SJeff Kirsher 	struct bnx2 *bp = netdev_priv(dev);
8682adfc5217SJeff Kirsher 
868328fb4eb4SMichael Chan 	if (netif_running(dev)) {
8684adfc5217SJeff Kirsher 		cancel_work_sync(&bp->reset_task);
8685adfc5217SJeff Kirsher 		bnx2_netif_stop(bp, true);
8686adfc5217SJeff Kirsher 		netif_device_detach(dev);
8687adfc5217SJeff Kirsher 		del_timer_sync(&bp->timer);
8688adfc5217SJeff Kirsher 		bnx2_shutdown_chip(bp);
868928fb4eb4SMichael Chan 		__bnx2_free_irq(bp);
8690adfc5217SJeff Kirsher 		bnx2_free_skbs(bp);
869128fb4eb4SMichael Chan 	}
869228fb4eb4SMichael Chan 	bnx2_setup_wol(bp);
8693adfc5217SJeff Kirsher 	return 0;
8694adfc5217SJeff Kirsher }
8695adfc5217SJeff Kirsher 
8696adfc5217SJeff Kirsher static int
869728fb4eb4SMichael Chan bnx2_resume(struct device *device)
8698adfc5217SJeff Kirsher {
869928fb4eb4SMichael Chan 	struct pci_dev *pdev = to_pci_dev(device);
8700adfc5217SJeff Kirsher 	struct net_device *dev = pci_get_drvdata(pdev);
8701adfc5217SJeff Kirsher 	struct bnx2 *bp = netdev_priv(dev);
8702adfc5217SJeff Kirsher 
8703adfc5217SJeff Kirsher 	if (!netif_running(dev))
8704adfc5217SJeff Kirsher 		return 0;
8705adfc5217SJeff Kirsher 
8706adfc5217SJeff Kirsher 	bnx2_set_power_state(bp, PCI_D0);
8707adfc5217SJeff Kirsher 	netif_device_attach(dev);
870828fb4eb4SMichael Chan 	bnx2_request_irq(bp);
8709adfc5217SJeff Kirsher 	bnx2_init_nic(bp, 1);
8710adfc5217SJeff Kirsher 	bnx2_netif_start(bp, true);
8711adfc5217SJeff Kirsher 	return 0;
8712adfc5217SJeff Kirsher }
8713adfc5217SJeff Kirsher 
871428fb4eb4SMichael Chan static SIMPLE_DEV_PM_OPS(bnx2_pm_ops, bnx2_suspend, bnx2_resume);
871528fb4eb4SMichael Chan #define BNX2_PM_OPS (&bnx2_pm_ops)
871628fb4eb4SMichael Chan 
871728fb4eb4SMichael Chan #else
871828fb4eb4SMichael Chan 
871928fb4eb4SMichael Chan #define BNX2_PM_OPS NULL
872028fb4eb4SMichael Chan 
872128fb4eb4SMichael Chan #endif /* CONFIG_PM_SLEEP */
8722adfc5217SJeff Kirsher /**
8723adfc5217SJeff Kirsher  * bnx2_io_error_detected - called when PCI error is detected
8724adfc5217SJeff Kirsher  * @pdev: Pointer to PCI device
8725adfc5217SJeff Kirsher  * @state: The current pci connection state
8726adfc5217SJeff Kirsher  *
8727adfc5217SJeff Kirsher  * This function is called after a PCI bus error affecting
8728adfc5217SJeff Kirsher  * this device has been detected.
8729adfc5217SJeff Kirsher  */
8730adfc5217SJeff Kirsher static pci_ers_result_t bnx2_io_error_detected(struct pci_dev *pdev,
8731adfc5217SJeff Kirsher 					       pci_channel_state_t state)
8732adfc5217SJeff Kirsher {
8733adfc5217SJeff Kirsher 	struct net_device *dev = pci_get_drvdata(pdev);
8734adfc5217SJeff Kirsher 	struct bnx2 *bp = netdev_priv(dev);
8735adfc5217SJeff Kirsher 
8736adfc5217SJeff Kirsher 	rtnl_lock();
8737adfc5217SJeff Kirsher 	netif_device_detach(dev);
8738adfc5217SJeff Kirsher 
8739adfc5217SJeff Kirsher 	if (state == pci_channel_io_perm_failure) {
8740adfc5217SJeff Kirsher 		rtnl_unlock();
8741adfc5217SJeff Kirsher 		return PCI_ERS_RESULT_DISCONNECT;
8742adfc5217SJeff Kirsher 	}
8743adfc5217SJeff Kirsher 
8744adfc5217SJeff Kirsher 	if (netif_running(dev)) {
8745adfc5217SJeff Kirsher 		bnx2_netif_stop(bp, true);
8746adfc5217SJeff Kirsher 		del_timer_sync(&bp->timer);
8747adfc5217SJeff Kirsher 		bnx2_reset_nic(bp, BNX2_DRV_MSG_CODE_RESET);
8748adfc5217SJeff Kirsher 	}
8749adfc5217SJeff Kirsher 
8750adfc5217SJeff Kirsher 	pci_disable_device(pdev);
8751adfc5217SJeff Kirsher 	rtnl_unlock();
8752adfc5217SJeff Kirsher 
8753adfc5217SJeff Kirsher 	/* Request a slot slot reset. */
8754adfc5217SJeff Kirsher 	return PCI_ERS_RESULT_NEED_RESET;
8755adfc5217SJeff Kirsher }
8756adfc5217SJeff Kirsher 
8757adfc5217SJeff Kirsher /**
8758adfc5217SJeff Kirsher  * bnx2_io_slot_reset - called after the pci bus has been reset.
8759adfc5217SJeff Kirsher  * @pdev: Pointer to PCI device
8760adfc5217SJeff Kirsher  *
8761adfc5217SJeff Kirsher  * Restart the card from scratch, as if from a cold-boot.
8762adfc5217SJeff Kirsher  */
8763adfc5217SJeff Kirsher static pci_ers_result_t bnx2_io_slot_reset(struct pci_dev *pdev)
8764adfc5217SJeff Kirsher {
8765adfc5217SJeff Kirsher 	struct net_device *dev = pci_get_drvdata(pdev);
8766adfc5217SJeff Kirsher 	struct bnx2 *bp = netdev_priv(dev);
876702481bc6SMichael Chan 	pci_ers_result_t result = PCI_ERS_RESULT_DISCONNECT;
876802481bc6SMichael Chan 	int err = 0;
8769adfc5217SJeff Kirsher 
8770adfc5217SJeff Kirsher 	rtnl_lock();
8771adfc5217SJeff Kirsher 	if (pci_enable_device(pdev)) {
8772adfc5217SJeff Kirsher 		dev_err(&pdev->dev,
8773adfc5217SJeff Kirsher 			"Cannot re-enable PCI device after reset\n");
8774adfc5217SJeff Kirsher 	} else {
8775adfc5217SJeff Kirsher 		pci_set_master(pdev);
8776adfc5217SJeff Kirsher 		pci_restore_state(pdev);
8777adfc5217SJeff Kirsher 		pci_save_state(pdev);
8778adfc5217SJeff Kirsher 
877925bfb1ddSMichael Chan 		if (netif_running(dev))
878002481bc6SMichael Chan 			err = bnx2_init_nic(bp, 1);
878125bfb1ddSMichael Chan 
878202481bc6SMichael Chan 		if (!err)
8783adfc5217SJeff Kirsher 			result = PCI_ERS_RESULT_RECOVERED;
8784adfc5217SJeff Kirsher 	}
878502481bc6SMichael Chan 
878602481bc6SMichael Chan 	if (result != PCI_ERS_RESULT_RECOVERED && netif_running(dev)) {
878702481bc6SMichael Chan 		bnx2_napi_enable(bp);
878802481bc6SMichael Chan 		dev_close(dev);
878902481bc6SMichael Chan 	}
8790adfc5217SJeff Kirsher 	rtnl_unlock();
8791adfc5217SJeff Kirsher 
8792adfc5217SJeff Kirsher 	if (!(bp->flags & BNX2_FLAG_AER_ENABLED))
8793adfc5217SJeff Kirsher 		return result;
8794adfc5217SJeff Kirsher 
8795adfc5217SJeff Kirsher 	err = pci_cleanup_aer_uncorrect_error_status(pdev);
8796adfc5217SJeff Kirsher 	if (err) {
8797adfc5217SJeff Kirsher 		dev_err(&pdev->dev,
8798adfc5217SJeff Kirsher 			"pci_cleanup_aer_uncorrect_error_status failed 0x%0x\n",
8799adfc5217SJeff Kirsher 			 err); /* non-fatal, continue */
8800adfc5217SJeff Kirsher 	}
8801adfc5217SJeff Kirsher 
8802adfc5217SJeff Kirsher 	return result;
8803adfc5217SJeff Kirsher }
8804adfc5217SJeff Kirsher 
8805adfc5217SJeff Kirsher /**
8806adfc5217SJeff Kirsher  * bnx2_io_resume - called when traffic can start flowing again.
8807adfc5217SJeff Kirsher  * @pdev: Pointer to PCI device
8808adfc5217SJeff Kirsher  *
8809adfc5217SJeff Kirsher  * This callback is called when the error recovery driver tells us that
8810adfc5217SJeff Kirsher  * its OK to resume normal operation.
8811adfc5217SJeff Kirsher  */
8812adfc5217SJeff Kirsher static void bnx2_io_resume(struct pci_dev *pdev)
8813adfc5217SJeff Kirsher {
8814adfc5217SJeff Kirsher 	struct net_device *dev = pci_get_drvdata(pdev);
8815adfc5217SJeff Kirsher 	struct bnx2 *bp = netdev_priv(dev);
8816adfc5217SJeff Kirsher 
8817adfc5217SJeff Kirsher 	rtnl_lock();
8818adfc5217SJeff Kirsher 	if (netif_running(dev))
8819adfc5217SJeff Kirsher 		bnx2_netif_start(bp, true);
8820adfc5217SJeff Kirsher 
8821adfc5217SJeff Kirsher 	netif_device_attach(dev);
8822adfc5217SJeff Kirsher 	rtnl_unlock();
8823adfc5217SJeff Kirsher }
8824adfc5217SJeff Kirsher 
882525bfb1ddSMichael Chan static void bnx2_shutdown(struct pci_dev *pdev)
882625bfb1ddSMichael Chan {
882725bfb1ddSMichael Chan 	struct net_device *dev = pci_get_drvdata(pdev);
882825bfb1ddSMichael Chan 	struct bnx2 *bp;
882925bfb1ddSMichael Chan 
883025bfb1ddSMichael Chan 	if (!dev)
883125bfb1ddSMichael Chan 		return;
883225bfb1ddSMichael Chan 
883325bfb1ddSMichael Chan 	bp = netdev_priv(dev);
883425bfb1ddSMichael Chan 	if (!bp)
883525bfb1ddSMichael Chan 		return;
883625bfb1ddSMichael Chan 
883725bfb1ddSMichael Chan 	rtnl_lock();
883825bfb1ddSMichael Chan 	if (netif_running(dev))
883925bfb1ddSMichael Chan 		dev_close(bp->dev);
884025bfb1ddSMichael Chan 
884125bfb1ddSMichael Chan 	if (system_state == SYSTEM_POWER_OFF)
884225bfb1ddSMichael Chan 		bnx2_set_power_state(bp, PCI_D3hot);
884325bfb1ddSMichael Chan 
884425bfb1ddSMichael Chan 	rtnl_unlock();
884525bfb1ddSMichael Chan }
884625bfb1ddSMichael Chan 
8847fda4d85dSMichael Chan static const struct pci_error_handlers bnx2_err_handler = {
8848adfc5217SJeff Kirsher 	.error_detected	= bnx2_io_error_detected,
8849adfc5217SJeff Kirsher 	.slot_reset	= bnx2_io_slot_reset,
8850adfc5217SJeff Kirsher 	.resume		= bnx2_io_resume,
8851adfc5217SJeff Kirsher };
8852adfc5217SJeff Kirsher 
8853adfc5217SJeff Kirsher static struct pci_driver bnx2_pci_driver = {
8854adfc5217SJeff Kirsher 	.name		= DRV_MODULE_NAME,
8855adfc5217SJeff Kirsher 	.id_table	= bnx2_pci_tbl,
8856adfc5217SJeff Kirsher 	.probe		= bnx2_init_one,
8857cfd95a63SBill Pemberton 	.remove		= bnx2_remove_one,
885828fb4eb4SMichael Chan 	.driver.pm	= BNX2_PM_OPS,
8859adfc5217SJeff Kirsher 	.err_handler	= &bnx2_err_handler,
886025bfb1ddSMichael Chan 	.shutdown	= bnx2_shutdown,
8861adfc5217SJeff Kirsher };
8862adfc5217SJeff Kirsher 
88635a4123f3SPeter Hüwe module_pci_driver(bnx2_pci_driver);
8864