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