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