blob: ecd357dbb1d48ca3d11cd4bcf7644685210226a3 [file] [log] [blame]
Rasesh Mody2e0bf122015-02-17 19:26:18 -05001/* bnx2.c: QLogic bnx2 network driver.
Michael Chanb6016b72005-05-26 13:03:09 -07002 *
Jitendra Kalsaria28c4ec02014-06-23 15:10:33 -04003 * Copyright (c) 2004-2014 Broadcom Corporation
Rasesh Mody2e0bf122015-02-17 19:26:18 -05004 * Copyright (c) 2014-2015 QLogic Corporation
Michael Chanb6016b72005-05-26 13:03:09 -07005 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation.
9 *
10 * Written by: Michael Chan (mchan@broadcom.com)
11 */
12
Joe Perches3a9c6a42010-02-17 15:01:51 +000013#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
Michael Chanf2a4f052006-03-23 01:13:12 -080014
15#include <linux/module.h>
16#include <linux/moduleparam.h>
17
Michael Chan555069d2012-06-16 15:45:41 +000018#include <linux/stringify.h>
Michael Chanf2a4f052006-03-23 01:13:12 -080019#include <linux/kernel.h>
20#include <linux/timer.h>
21#include <linux/errno.h>
22#include <linux/ioport.h>
23#include <linux/slab.h>
24#include <linux/vmalloc.h>
25#include <linux/interrupt.h>
26#include <linux/pci.h>
Michael Chanf2a4f052006-03-23 01:13:12 -080027#include <linux/netdevice.h>
28#include <linux/etherdevice.h>
29#include <linux/skbuff.h>
30#include <linux/dma-mapping.h>
Jiri Slaby1977f032007-10-18 23:40:25 -070031#include <linux/bitops.h>
Michael Chanf2a4f052006-03-23 01:13:12 -080032#include <asm/io.h>
33#include <asm/irq.h>
34#include <linux/delay.h>
35#include <asm/byteorder.h>
Michael Chanc86a31f2006-06-13 15:03:47 -070036#include <asm/page.h>
Michael Chanf2a4f052006-03-23 01:13:12 -080037#include <linux/time.h>
38#include <linux/ethtool.h>
39#include <linux/mii.h>
Jiri Pirko01789342011-08-16 06:29:00 +000040#include <linux/if.h>
Michael Chanf2a4f052006-03-23 01:13:12 -080041#include <linux/if_vlan.h>
Michael Chanf2a4f052006-03-23 01:13:12 -080042#include <net/ip.h>
Linus Torvaldsde081fa2007-07-12 16:40:08 -070043#include <net/tcp.h>
Michael Chanf2a4f052006-03-23 01:13:12 -080044#include <net/checksum.h>
Michael Chanf2a4f052006-03-23 01:13:12 -080045#include <linux/workqueue.h>
46#include <linux/crc32.h>
47#include <linux/prefetch.h>
Michael Chan29b12172006-03-23 01:13:43 -080048#include <linux/cache.h>
Michael Chan57579f72009-04-04 16:51:14 -070049#include <linux/firmware.h>
Benjamin Li706bf242008-07-18 17:55:11 -070050#include <linux/log2.h>
John Feeneycd709aa2010-08-22 17:45:53 +000051#include <linux/aer.h>
Michael Chanf2a4f052006-03-23 01:13:12 -080052
Javier Martinez Canillasda556d62016-09-12 10:03:35 -040053#if IS_ENABLED(CONFIG_CNIC)
Michael Chan4edd4732009-06-08 18:14:42 -070054#define BCM_CNIC 1
55#include "cnic_if.h"
56#endif
Michael Chanb6016b72005-05-26 13:03:09 -070057#include "bnx2.h"
58#include "bnx2_fw.h"
Denys Vlasenkob3448b02007-09-30 17:55:51 -070059
Michael Chanb6016b72005-05-26 13:03:09 -070060#define DRV_MODULE_NAME "bnx2"
Rasesh Mody85fe7cd2015-02-17 19:26:20 -050061#define DRV_MODULE_VERSION "2.2.6"
62#define DRV_MODULE_RELDATE "January 29, 2014"
Michael Chanc2c20ef2011-12-18 18:15:09 +000063#define FW_MIPS_FILE_06 "bnx2/bnx2-mips-06-6.2.3.fw"
Michael Chan22fa1592010-10-11 16:12:00 -070064#define FW_RV2P_FILE_06 "bnx2/bnx2-rv2p-06-6.0.15.fw"
Michael Chanc2c20ef2011-12-18 18:15:09 +000065#define FW_MIPS_FILE_09 "bnx2/bnx2-mips-09-6.2.1b.fw"
Michael Chan22fa1592010-10-11 16:12:00 -070066#define FW_RV2P_FILE_09_Ax "bnx2/bnx2-rv2p-09ax-6.0.17.fw"
67#define FW_RV2P_FILE_09 "bnx2/bnx2-rv2p-09-6.0.17.fw"
Michael Chanb6016b72005-05-26 13:03:09 -070068
69#define RUN_AT(x) (jiffies + (x))
70
71/* Time in jiffies before concluding the transmitter is hung. */
72#define TX_TIMEOUT (5*HZ)
73
Bill Pembertoncfd95a62012-12-03 09:22:58 -050074static char version[] =
Rasesh Mody2e0bf122015-02-17 19:26:18 -050075 "QLogic " DRV_MODULE_NAME " Gigabit Ethernet Driver v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";
Michael Chanb6016b72005-05-26 13:03:09 -070076
77MODULE_AUTHOR("Michael Chan <mchan@broadcom.com>");
Rasesh Mody2e0bf122015-02-17 19:26:18 -050078MODULE_DESCRIPTION("QLogic BCM5706/5708/5709/5716 Driver");
Michael Chanb6016b72005-05-26 13:03:09 -070079MODULE_LICENSE("GPL");
80MODULE_VERSION(DRV_MODULE_VERSION);
Michael Chan57579f72009-04-04 16:51:14 -070081MODULE_FIRMWARE(FW_MIPS_FILE_06);
82MODULE_FIRMWARE(FW_RV2P_FILE_06);
83MODULE_FIRMWARE(FW_MIPS_FILE_09);
84MODULE_FIRMWARE(FW_RV2P_FILE_09);
Michael Chan078b0732009-08-29 00:02:46 -070085MODULE_FIRMWARE(FW_RV2P_FILE_09_Ax);
Michael Chanb6016b72005-05-26 13:03:09 -070086
87static int disable_msi = 0;
88
James M Leddy1c8bb762014-02-04 15:10:59 -050089module_param(disable_msi, int, S_IRUGO);
Michael Chanb6016b72005-05-26 13:03:09 -070090MODULE_PARM_DESC(disable_msi, "Disable Message Signaled Interrupt (MSI)");
91
92typedef enum {
93 BCM5706 = 0,
94 NC370T,
95 NC370I,
96 BCM5706S,
97 NC370F,
Michael Chan5b0c76a2005-11-04 08:45:49 -080098 BCM5708,
99 BCM5708S,
Michael Chanbac0dff2006-11-19 14:15:05 -0800100 BCM5709,
Michael Chan27a005b2007-05-03 13:23:41 -0700101 BCM5709S,
Michael Chan7bb0a042008-07-14 22:37:47 -0700102 BCM5716,
Michael Chan1caacec2008-11-12 16:01:12 -0800103 BCM5716S,
Michael Chanb6016b72005-05-26 13:03:09 -0700104} board_t;
105
106/* indexed by board_t, above */
Andrew Mortonfefa8642008-02-09 23:17:15 -0800107static struct {
Michael Chanb6016b72005-05-26 13:03:09 -0700108 char *name;
Bill Pembertoncfd95a62012-12-03 09:22:58 -0500109} board_info[] = {
Michael Chanb6016b72005-05-26 13:03:09 -0700110 { "Broadcom NetXtreme II BCM5706 1000Base-T" },
111 { "HP NC370T Multifunction Gigabit Server Adapter" },
112 { "HP NC370i Multifunction Gigabit Server Adapter" },
113 { "Broadcom NetXtreme II BCM5706 1000Base-SX" },
114 { "HP NC370F Multifunction Gigabit Server Adapter" },
Michael Chan5b0c76a2005-11-04 08:45:49 -0800115 { "Broadcom NetXtreme II BCM5708 1000Base-T" },
116 { "Broadcom NetXtreme II BCM5708 1000Base-SX" },
Michael Chanbac0dff2006-11-19 14:15:05 -0800117 { "Broadcom NetXtreme II BCM5709 1000Base-T" },
Michael Chan27a005b2007-05-03 13:23:41 -0700118 { "Broadcom NetXtreme II BCM5709 1000Base-SX" },
Michael Chan7bb0a042008-07-14 22:37:47 -0700119 { "Broadcom NetXtreme II BCM5716 1000Base-T" },
Michael Chan1caacec2008-11-12 16:01:12 -0800120 { "Broadcom NetXtreme II BCM5716 1000Base-SX" },
Michael Chanb6016b72005-05-26 13:03:09 -0700121 };
122
Benoit Taine9baa3c32014-08-08 15:56:03 +0200123static const struct pci_device_id bnx2_pci_tbl[] = {
Michael Chanb6016b72005-05-26 13:03:09 -0700124 { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5706,
125 PCI_VENDOR_ID_HP, 0x3101, 0, 0, NC370T },
126 { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5706,
127 PCI_VENDOR_ID_HP, 0x3106, 0, 0, NC370I },
128 { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5706,
129 PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5706 },
Michael Chan5b0c76a2005-11-04 08:45:49 -0800130 { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5708,
131 PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5708 },
Michael Chanb6016b72005-05-26 13:03:09 -0700132 { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5706S,
133 PCI_VENDOR_ID_HP, 0x3102, 0, 0, NC370F },
134 { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5706S,
135 PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5706S },
Michael Chan5b0c76a2005-11-04 08:45:49 -0800136 { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5708S,
137 PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5708S },
Michael Chanbac0dff2006-11-19 14:15:05 -0800138 { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5709,
139 PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5709 },
Michael Chan27a005b2007-05-03 13:23:41 -0700140 { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5709S,
141 PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5709S },
Michael Chan7bb0a042008-07-14 22:37:47 -0700142 { PCI_VENDOR_ID_BROADCOM, 0x163b,
143 PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5716 },
Michael Chan1caacec2008-11-12 16:01:12 -0800144 { PCI_VENDOR_ID_BROADCOM, 0x163c,
Michael Chan1f2435e2008-12-16 20:28:13 -0800145 PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5716S },
Michael Chanb6016b72005-05-26 13:03:09 -0700146 { 0, }
147};
148
Michael Chan0ced9d02009-08-21 16:20:49 +0000149static const struct flash_spec flash_table[] =
Michael Chanb6016b72005-05-26 13:03:09 -0700150{
Michael Chane30372c2007-07-16 18:26:23 -0700151#define BUFFERED_FLAGS (BNX2_NV_BUFFERED | BNX2_NV_TRANSLATE)
152#define NONBUFFERED_FLAGS (BNX2_NV_WREN)
Michael Chanb6016b72005-05-26 13:03:09 -0700153 /* Slow EEPROM */
Michael Chan37137702005-11-04 08:49:17 -0800154 {0x00000000, 0x40830380, 0x009f0081, 0xa184a053, 0xaf000400,
Michael Chane30372c2007-07-16 18:26:23 -0700155 BUFFERED_FLAGS, SEEPROM_PAGE_BITS, SEEPROM_PAGE_SIZE,
Michael Chanb6016b72005-05-26 13:03:09 -0700156 SEEPROM_BYTE_ADDR_MASK, SEEPROM_TOTAL_SIZE,
157 "EEPROM - slow"},
Michael Chan37137702005-11-04 08:49:17 -0800158 /* Expansion entry 0001 */
159 {0x08000002, 0x4b808201, 0x00050081, 0x03840253, 0xaf020406,
Michael Chane30372c2007-07-16 18:26:23 -0700160 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
Michael Chan37137702005-11-04 08:49:17 -0800161 SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
162 "Entry 0001"},
Michael Chanb6016b72005-05-26 13:03:09 -0700163 /* Saifun SA25F010 (non-buffered flash) */
164 /* strap, cfg1, & write1 need updates */
Michael Chan37137702005-11-04 08:49:17 -0800165 {0x04000001, 0x47808201, 0x00050081, 0x03840253, 0xaf020406,
Michael Chane30372c2007-07-16 18:26:23 -0700166 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
Michael Chanb6016b72005-05-26 13:03:09 -0700167 SAIFUN_FLASH_BYTE_ADDR_MASK, SAIFUN_FLASH_BASE_TOTAL_SIZE*2,
168 "Non-buffered flash (128kB)"},
169 /* Saifun SA25F020 (non-buffered flash) */
170 /* strap, cfg1, & write1 need updates */
Michael Chan37137702005-11-04 08:49:17 -0800171 {0x0c000003, 0x4f808201, 0x00050081, 0x03840253, 0xaf020406,
Michael Chane30372c2007-07-16 18:26:23 -0700172 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
Michael Chanb6016b72005-05-26 13:03:09 -0700173 SAIFUN_FLASH_BYTE_ADDR_MASK, SAIFUN_FLASH_BASE_TOTAL_SIZE*4,
174 "Non-buffered flash (256kB)"},
Michael Chan37137702005-11-04 08:49:17 -0800175 /* Expansion entry 0100 */
176 {0x11000000, 0x53808201, 0x00050081, 0x03840253, 0xaf020406,
Michael Chane30372c2007-07-16 18:26:23 -0700177 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
Michael Chan37137702005-11-04 08:49:17 -0800178 SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
179 "Entry 0100"},
180 /* Entry 0101: ST M45PE10 (non-buffered flash, TetonII B0) */
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400181 {0x19000002, 0x5b808201, 0x000500db, 0x03840253, 0xaf020406,
Michael Chane30372c2007-07-16 18:26:23 -0700182 NONBUFFERED_FLAGS, ST_MICRO_FLASH_PAGE_BITS, ST_MICRO_FLASH_PAGE_SIZE,
Michael Chan37137702005-11-04 08:49:17 -0800183 ST_MICRO_FLASH_BYTE_ADDR_MASK, ST_MICRO_FLASH_BASE_TOTAL_SIZE*2,
184 "Entry 0101: ST M45PE10 (128kB non-bufferred)"},
185 /* Entry 0110: ST M45PE20 (non-buffered flash)*/
186 {0x15000001, 0x57808201, 0x000500db, 0x03840253, 0xaf020406,
Michael Chane30372c2007-07-16 18:26:23 -0700187 NONBUFFERED_FLAGS, ST_MICRO_FLASH_PAGE_BITS, ST_MICRO_FLASH_PAGE_SIZE,
Michael Chan37137702005-11-04 08:49:17 -0800188 ST_MICRO_FLASH_BYTE_ADDR_MASK, ST_MICRO_FLASH_BASE_TOTAL_SIZE*4,
189 "Entry 0110: ST M45PE20 (256kB non-bufferred)"},
190 /* Saifun SA25F005 (non-buffered flash) */
191 /* strap, cfg1, & write1 need updates */
192 {0x1d000003, 0x5f808201, 0x00050081, 0x03840253, 0xaf020406,
Michael Chane30372c2007-07-16 18:26:23 -0700193 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
Michael Chan37137702005-11-04 08:49:17 -0800194 SAIFUN_FLASH_BYTE_ADDR_MASK, SAIFUN_FLASH_BASE_TOTAL_SIZE,
195 "Non-buffered flash (64kB)"},
196 /* Fast EEPROM */
197 {0x22000000, 0x62808380, 0x009f0081, 0xa184a053, 0xaf000400,
Michael Chane30372c2007-07-16 18:26:23 -0700198 BUFFERED_FLAGS, SEEPROM_PAGE_BITS, SEEPROM_PAGE_SIZE,
Michael Chan37137702005-11-04 08:49:17 -0800199 SEEPROM_BYTE_ADDR_MASK, SEEPROM_TOTAL_SIZE,
200 "EEPROM - fast"},
201 /* Expansion entry 1001 */
202 {0x2a000002, 0x6b808201, 0x00050081, 0x03840253, 0xaf020406,
Michael Chane30372c2007-07-16 18:26:23 -0700203 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
Michael Chan37137702005-11-04 08:49:17 -0800204 SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
205 "Entry 1001"},
206 /* Expansion entry 1010 */
207 {0x26000001, 0x67808201, 0x00050081, 0x03840253, 0xaf020406,
Michael Chane30372c2007-07-16 18:26:23 -0700208 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
Michael Chan37137702005-11-04 08:49:17 -0800209 SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
210 "Entry 1010"},
211 /* ATMEL AT45DB011B (buffered flash) */
212 {0x2e000003, 0x6e808273, 0x00570081, 0x68848353, 0xaf000400,
Michael Chane30372c2007-07-16 18:26:23 -0700213 BUFFERED_FLAGS, BUFFERED_FLASH_PAGE_BITS, BUFFERED_FLASH_PAGE_SIZE,
Michael Chan37137702005-11-04 08:49:17 -0800214 BUFFERED_FLASH_BYTE_ADDR_MASK, BUFFERED_FLASH_TOTAL_SIZE,
215 "Buffered flash (128kB)"},
216 /* Expansion entry 1100 */
217 {0x33000000, 0x73808201, 0x00050081, 0x03840253, 0xaf020406,
Michael Chane30372c2007-07-16 18:26:23 -0700218 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
Michael Chan37137702005-11-04 08:49:17 -0800219 SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
220 "Entry 1100"},
221 /* Expansion entry 1101 */
222 {0x3b000002, 0x7b808201, 0x00050081, 0x03840253, 0xaf020406,
Michael Chane30372c2007-07-16 18:26:23 -0700223 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
Michael Chan37137702005-11-04 08:49:17 -0800224 SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
225 "Entry 1101"},
226 /* Ateml Expansion entry 1110 */
227 {0x37000001, 0x76808273, 0x00570081, 0x68848353, 0xaf000400,
Michael Chane30372c2007-07-16 18:26:23 -0700228 BUFFERED_FLAGS, BUFFERED_FLASH_PAGE_BITS, BUFFERED_FLASH_PAGE_SIZE,
Michael Chan37137702005-11-04 08:49:17 -0800229 BUFFERED_FLASH_BYTE_ADDR_MASK, 0,
230 "Entry 1110 (Atmel)"},
231 /* ATMEL AT45DB021B (buffered flash) */
232 {0x3f000003, 0x7e808273, 0x00570081, 0x68848353, 0xaf000400,
Michael Chane30372c2007-07-16 18:26:23 -0700233 BUFFERED_FLAGS, BUFFERED_FLASH_PAGE_BITS, BUFFERED_FLASH_PAGE_SIZE,
Michael Chan37137702005-11-04 08:49:17 -0800234 BUFFERED_FLASH_BYTE_ADDR_MASK, BUFFERED_FLASH_TOTAL_SIZE*2,
235 "Buffered flash (256kB)"},
Michael Chanb6016b72005-05-26 13:03:09 -0700236};
237
Michael Chan0ced9d02009-08-21 16:20:49 +0000238static const struct flash_spec flash_5709 = {
Michael Chane30372c2007-07-16 18:26:23 -0700239 .flags = BNX2_NV_BUFFERED,
240 .page_bits = BCM5709_FLASH_PAGE_BITS,
241 .page_size = BCM5709_FLASH_PAGE_SIZE,
242 .addr_mask = BCM5709_FLASH_BYTE_ADDR_MASK,
243 .total_size = BUFFERED_FLASH_TOTAL_SIZE*2,
244 .name = "5709 Buffered flash (256kB)",
245};
246
Michael Chanb6016b72005-05-26 13:03:09 -0700247MODULE_DEVICE_TABLE(pci, bnx2_pci_tbl);
248
Benjamin Li4327ba42010-03-23 13:13:11 +0000249static void bnx2_init_napi(struct bnx2 *bp);
Michael Chanf048fa92010-06-01 15:05:36 +0000250static void bnx2_del_napi(struct bnx2 *bp);
Benjamin Li4327ba42010-03-23 13:13:11 +0000251
Michael Chan35e90102008-06-19 16:37:42 -0700252static inline u32 bnx2_tx_avail(struct bnx2 *bp, struct bnx2_tx_ring_info *txr)
Michael Chane89bbf12005-08-25 15:36:58 -0700253{
Michael Chan2f8af122006-08-15 01:39:10 -0700254 u32 diff;
Michael Chane89bbf12005-08-25 15:36:58 -0700255
Michael Chan11848b962010-07-19 14:15:04 +0000256 /* Tell compiler to fetch tx_prod and tx_cons from memory. */
257 barrier();
Michael Chanfaac9c42006-12-14 15:56:32 -0800258
259 /* The ring uses 256 indices for 255 entries, one of them
260 * needs to be skipped.
261 */
Michael Chan35e90102008-06-19 16:37:42 -0700262 diff = txr->tx_prod - txr->tx_cons;
Michael Chan2bc40782012-12-06 10:33:09 +0000263 if (unlikely(diff >= BNX2_TX_DESC_CNT)) {
Michael Chanfaac9c42006-12-14 15:56:32 -0800264 diff &= 0xffff;
Michael Chan2bc40782012-12-06 10:33:09 +0000265 if (diff == BNX2_TX_DESC_CNT)
266 diff = BNX2_MAX_TX_DESC_CNT;
Michael Chanfaac9c42006-12-14 15:56:32 -0800267 }
Eric Dumazet807540b2010-09-23 05:40:09 +0000268 return bp->tx_ring_size - diff;
Michael Chane89bbf12005-08-25 15:36:58 -0700269}
270
Michael Chanb6016b72005-05-26 13:03:09 -0700271static u32
272bnx2_reg_rd_ind(struct bnx2 *bp, u32 offset)
273{
Michael Chan1b8227c2007-05-03 13:24:05 -0700274 u32 val;
275
276 spin_lock_bh(&bp->indirect_lock);
Michael Chane503e062012-12-06 10:33:08 +0000277 BNX2_WR(bp, BNX2_PCICFG_REG_WINDOW_ADDRESS, offset);
278 val = BNX2_RD(bp, BNX2_PCICFG_REG_WINDOW);
Michael Chan1b8227c2007-05-03 13:24:05 -0700279 spin_unlock_bh(&bp->indirect_lock);
280 return val;
Michael Chanb6016b72005-05-26 13:03:09 -0700281}
282
283static void
284bnx2_reg_wr_ind(struct bnx2 *bp, u32 offset, u32 val)
285{
Michael Chan1b8227c2007-05-03 13:24:05 -0700286 spin_lock_bh(&bp->indirect_lock);
Michael Chane503e062012-12-06 10:33:08 +0000287 BNX2_WR(bp, BNX2_PCICFG_REG_WINDOW_ADDRESS, offset);
288 BNX2_WR(bp, BNX2_PCICFG_REG_WINDOW, val);
Michael Chan1b8227c2007-05-03 13:24:05 -0700289 spin_unlock_bh(&bp->indirect_lock);
Michael Chanb6016b72005-05-26 13:03:09 -0700290}
291
292static void
Michael Chan2726d6e2008-01-29 21:35:05 -0800293bnx2_shmem_wr(struct bnx2 *bp, u32 offset, u32 val)
294{
295 bnx2_reg_wr_ind(bp, bp->shmem_base + offset, val);
296}
297
298static u32
299bnx2_shmem_rd(struct bnx2 *bp, u32 offset)
300{
Eric Dumazet807540b2010-09-23 05:40:09 +0000301 return bnx2_reg_rd_ind(bp, bp->shmem_base + offset);
Michael Chan2726d6e2008-01-29 21:35:05 -0800302}
303
304static void
Michael Chanb6016b72005-05-26 13:03:09 -0700305bnx2_ctx_wr(struct bnx2 *bp, u32 cid_addr, u32 offset, u32 val)
306{
307 offset += cid_addr;
Michael Chan1b8227c2007-05-03 13:24:05 -0700308 spin_lock_bh(&bp->indirect_lock);
Michael Chan4ce45e02012-12-06 10:33:10 +0000309 if (BNX2_CHIP(bp) == BNX2_CHIP_5709) {
Michael Chan59b47d82006-11-19 14:10:45 -0800310 int i;
311
Michael Chane503e062012-12-06 10:33:08 +0000312 BNX2_WR(bp, BNX2_CTX_CTX_DATA, val);
313 BNX2_WR(bp, BNX2_CTX_CTX_CTRL,
314 offset | BNX2_CTX_CTX_CTRL_WRITE_REQ);
Michael Chan59b47d82006-11-19 14:10:45 -0800315 for (i = 0; i < 5; i++) {
Michael Chane503e062012-12-06 10:33:08 +0000316 val = BNX2_RD(bp, BNX2_CTX_CTX_CTRL);
Michael Chan59b47d82006-11-19 14:10:45 -0800317 if ((val & BNX2_CTX_CTX_CTRL_WRITE_REQ) == 0)
318 break;
319 udelay(5);
320 }
321 } else {
Michael Chane503e062012-12-06 10:33:08 +0000322 BNX2_WR(bp, BNX2_CTX_DATA_ADR, offset);
323 BNX2_WR(bp, BNX2_CTX_DATA, val);
Michael Chan59b47d82006-11-19 14:10:45 -0800324 }
Michael Chan1b8227c2007-05-03 13:24:05 -0700325 spin_unlock_bh(&bp->indirect_lock);
Michael Chanb6016b72005-05-26 13:03:09 -0700326}
327
Michael Chan4edd4732009-06-08 18:14:42 -0700328#ifdef BCM_CNIC
329static int
330bnx2_drv_ctl(struct net_device *dev, struct drv_ctl_info *info)
331{
332 struct bnx2 *bp = netdev_priv(dev);
333 struct drv_ctl_io *io = &info->data.io;
334
335 switch (info->cmd) {
336 case DRV_CTL_IO_WR_CMD:
337 bnx2_reg_wr_ind(bp, io->offset, io->data);
338 break;
339 case DRV_CTL_IO_RD_CMD:
340 io->data = bnx2_reg_rd_ind(bp, io->offset);
341 break;
342 case DRV_CTL_CTX_WR_CMD:
343 bnx2_ctx_wr(bp, io->cid_addr, io->offset, io->data);
344 break;
345 default:
346 return -EINVAL;
347 }
348 return 0;
349}
350
351static void bnx2_setup_cnic_irq_info(struct bnx2 *bp)
352{
353 struct cnic_eth_dev *cp = &bp->cnic_eth_dev;
354 struct bnx2_napi *bnapi = &bp->bnx2_napi[0];
355 int sb_id;
356
357 if (bp->flags & BNX2_FLAG_USING_MSIX) {
358 cp->drv_state |= CNIC_DRV_STATE_USING_MSIX;
359 bnapi->cnic_present = 0;
360 sb_id = bp->irq_nvecs;
361 cp->irq_arr[0].irq_flags |= CNIC_IRQ_FL_MSIX;
362 } else {
363 cp->drv_state &= ~CNIC_DRV_STATE_USING_MSIX;
364 bnapi->cnic_tag = bnapi->last_status_idx;
365 bnapi->cnic_present = 1;
366 sb_id = 0;
367 cp->irq_arr[0].irq_flags &= ~CNIC_IRQ_FL_MSIX;
368 }
369
370 cp->irq_arr[0].vector = bp->irq_tbl[sb_id].vector;
371 cp->irq_arr[0].status_blk = (void *)
372 ((unsigned long) bnapi->status_blk.msi +
373 (BNX2_SBLK_MSIX_ALIGN_SIZE * sb_id));
374 cp->irq_arr[0].status_blk_num = sb_id;
375 cp->num_irq = 1;
376}
377
378static int bnx2_register_cnic(struct net_device *dev, struct cnic_ops *ops,
379 void *data)
380{
381 struct bnx2 *bp = netdev_priv(dev);
382 struct cnic_eth_dev *cp = &bp->cnic_eth_dev;
383
384 if (ops == NULL)
385 return -EINVAL;
386
387 if (cp->drv_state & CNIC_DRV_STATE_REGD)
388 return -EBUSY;
389
Michael Chan41c21782011-07-13 17:24:22 +0000390 if (!bnx2_reg_rd_ind(bp, BNX2_FW_MAX_ISCSI_CONN))
391 return -ENODEV;
392
Michael Chan4edd4732009-06-08 18:14:42 -0700393 bp->cnic_data = data;
394 rcu_assign_pointer(bp->cnic_ops, ops);
395
396 cp->num_irq = 0;
397 cp->drv_state = CNIC_DRV_STATE_REGD;
398
399 bnx2_setup_cnic_irq_info(bp);
400
401 return 0;
402}
403
404static int bnx2_unregister_cnic(struct net_device *dev)
405{
406 struct bnx2 *bp = netdev_priv(dev);
407 struct bnx2_napi *bnapi = &bp->bnx2_napi[0];
408 struct cnic_eth_dev *cp = &bp->cnic_eth_dev;
409
Michael Chanc5a88952009-08-14 15:49:45 +0000410 mutex_lock(&bp->cnic_lock);
Michael Chan4edd4732009-06-08 18:14:42 -0700411 cp->drv_state = 0;
412 bnapi->cnic_present = 0;
Eric Dumazet2cfa5a02011-11-23 07:09:32 +0000413 RCU_INIT_POINTER(bp->cnic_ops, NULL);
Michael Chanc5a88952009-08-14 15:49:45 +0000414 mutex_unlock(&bp->cnic_lock);
Michael Chan4edd4732009-06-08 18:14:42 -0700415 synchronize_rcu();
416 return 0;
417}
418
stephen hemminger61c2fc42013-04-10 10:53:40 +0000419static struct cnic_eth_dev *bnx2_cnic_probe(struct net_device *dev)
Michael Chan4edd4732009-06-08 18:14:42 -0700420{
421 struct bnx2 *bp = netdev_priv(dev);
422 struct cnic_eth_dev *cp = &bp->cnic_eth_dev;
423
Michael Chan7625eb22011-06-08 19:29:36 +0000424 if (!cp->max_iscsi_conn)
425 return NULL;
426
Michael Chan4edd4732009-06-08 18:14:42 -0700427 cp->drv_owner = THIS_MODULE;
428 cp->chip_id = bp->chip_id;
429 cp->pdev = bp->pdev;
430 cp->io_base = bp->regview;
431 cp->drv_ctl = bnx2_drv_ctl;
432 cp->drv_register_cnic = bnx2_register_cnic;
433 cp->drv_unregister_cnic = bnx2_unregister_cnic;
434
435 return cp;
436}
Michael Chan4edd4732009-06-08 18:14:42 -0700437
438static void
439bnx2_cnic_stop(struct bnx2 *bp)
440{
441 struct cnic_ops *c_ops;
442 struct cnic_ctl_info info;
443
Michael Chanc5a88952009-08-14 15:49:45 +0000444 mutex_lock(&bp->cnic_lock);
Eric Dumazet13707f92011-01-26 19:28:23 +0000445 c_ops = rcu_dereference_protected(bp->cnic_ops,
446 lockdep_is_held(&bp->cnic_lock));
Michael Chan4edd4732009-06-08 18:14:42 -0700447 if (c_ops) {
448 info.cmd = CNIC_CTL_STOP_CMD;
449 c_ops->cnic_ctl(bp->cnic_data, &info);
450 }
Michael Chanc5a88952009-08-14 15:49:45 +0000451 mutex_unlock(&bp->cnic_lock);
Michael Chan4edd4732009-06-08 18:14:42 -0700452}
453
454static void
455bnx2_cnic_start(struct bnx2 *bp)
456{
457 struct cnic_ops *c_ops;
458 struct cnic_ctl_info info;
459
Michael Chanc5a88952009-08-14 15:49:45 +0000460 mutex_lock(&bp->cnic_lock);
Eric Dumazet13707f92011-01-26 19:28:23 +0000461 c_ops = rcu_dereference_protected(bp->cnic_ops,
462 lockdep_is_held(&bp->cnic_lock));
Michael Chan4edd4732009-06-08 18:14:42 -0700463 if (c_ops) {
464 if (!(bp->flags & BNX2_FLAG_USING_MSIX)) {
465 struct bnx2_napi *bnapi = &bp->bnx2_napi[0];
466
467 bnapi->cnic_tag = bnapi->last_status_idx;
468 }
469 info.cmd = CNIC_CTL_START_CMD;
470 c_ops->cnic_ctl(bp->cnic_data, &info);
471 }
Michael Chanc5a88952009-08-14 15:49:45 +0000472 mutex_unlock(&bp->cnic_lock);
Michael Chan4edd4732009-06-08 18:14:42 -0700473}
474
475#else
476
477static void
478bnx2_cnic_stop(struct bnx2 *bp)
479{
480}
481
482static void
483bnx2_cnic_start(struct bnx2 *bp)
484{
485}
486
487#endif
488
Michael Chanb6016b72005-05-26 13:03:09 -0700489static int
490bnx2_read_phy(struct bnx2 *bp, u32 reg, u32 *val)
491{
492 u32 val1;
493 int i, ret;
494
Michael Chan583c28e2008-01-21 19:51:35 -0800495 if (bp->phy_flags & BNX2_PHY_FLAG_INT_MODE_AUTO_POLLING) {
Michael Chane503e062012-12-06 10:33:08 +0000496 val1 = BNX2_RD(bp, BNX2_EMAC_MDIO_MODE);
Michael Chanb6016b72005-05-26 13:03:09 -0700497 val1 &= ~BNX2_EMAC_MDIO_MODE_AUTO_POLL;
498
Michael Chane503e062012-12-06 10:33:08 +0000499 BNX2_WR(bp, BNX2_EMAC_MDIO_MODE, val1);
500 BNX2_RD(bp, BNX2_EMAC_MDIO_MODE);
Michael Chanb6016b72005-05-26 13:03:09 -0700501
502 udelay(40);
503 }
504
505 val1 = (bp->phy_addr << 21) | (reg << 16) |
506 BNX2_EMAC_MDIO_COMM_COMMAND_READ | BNX2_EMAC_MDIO_COMM_DISEXT |
507 BNX2_EMAC_MDIO_COMM_START_BUSY;
Michael Chane503e062012-12-06 10:33:08 +0000508 BNX2_WR(bp, BNX2_EMAC_MDIO_COMM, val1);
Michael Chanb6016b72005-05-26 13:03:09 -0700509
510 for (i = 0; i < 50; i++) {
511 udelay(10);
512
Michael Chane503e062012-12-06 10:33:08 +0000513 val1 = BNX2_RD(bp, BNX2_EMAC_MDIO_COMM);
Michael Chanb6016b72005-05-26 13:03:09 -0700514 if (!(val1 & BNX2_EMAC_MDIO_COMM_START_BUSY)) {
515 udelay(5);
516
Michael Chane503e062012-12-06 10:33:08 +0000517 val1 = BNX2_RD(bp, BNX2_EMAC_MDIO_COMM);
Michael Chanb6016b72005-05-26 13:03:09 -0700518 val1 &= BNX2_EMAC_MDIO_COMM_DATA;
519
520 break;
521 }
522 }
523
524 if (val1 & BNX2_EMAC_MDIO_COMM_START_BUSY) {
525 *val = 0x0;
526 ret = -EBUSY;
527 }
528 else {
529 *val = val1;
530 ret = 0;
531 }
532
Michael Chan583c28e2008-01-21 19:51:35 -0800533 if (bp->phy_flags & BNX2_PHY_FLAG_INT_MODE_AUTO_POLLING) {
Michael Chane503e062012-12-06 10:33:08 +0000534 val1 = BNX2_RD(bp, BNX2_EMAC_MDIO_MODE);
Michael Chanb6016b72005-05-26 13:03:09 -0700535 val1 |= BNX2_EMAC_MDIO_MODE_AUTO_POLL;
536
Michael Chane503e062012-12-06 10:33:08 +0000537 BNX2_WR(bp, BNX2_EMAC_MDIO_MODE, val1);
538 BNX2_RD(bp, BNX2_EMAC_MDIO_MODE);
Michael Chanb6016b72005-05-26 13:03:09 -0700539
540 udelay(40);
541 }
542
543 return ret;
544}
545
546static int
547bnx2_write_phy(struct bnx2 *bp, u32 reg, u32 val)
548{
549 u32 val1;
550 int i, ret;
551
Michael Chan583c28e2008-01-21 19:51:35 -0800552 if (bp->phy_flags & BNX2_PHY_FLAG_INT_MODE_AUTO_POLLING) {
Michael Chane503e062012-12-06 10:33:08 +0000553 val1 = BNX2_RD(bp, BNX2_EMAC_MDIO_MODE);
Michael Chanb6016b72005-05-26 13:03:09 -0700554 val1 &= ~BNX2_EMAC_MDIO_MODE_AUTO_POLL;
555
Michael Chane503e062012-12-06 10:33:08 +0000556 BNX2_WR(bp, BNX2_EMAC_MDIO_MODE, val1);
557 BNX2_RD(bp, BNX2_EMAC_MDIO_MODE);
Michael Chanb6016b72005-05-26 13:03:09 -0700558
559 udelay(40);
560 }
561
562 val1 = (bp->phy_addr << 21) | (reg << 16) | val |
563 BNX2_EMAC_MDIO_COMM_COMMAND_WRITE |
564 BNX2_EMAC_MDIO_COMM_START_BUSY | BNX2_EMAC_MDIO_COMM_DISEXT;
Michael Chane503e062012-12-06 10:33:08 +0000565 BNX2_WR(bp, BNX2_EMAC_MDIO_COMM, val1);
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400566
Michael Chanb6016b72005-05-26 13:03:09 -0700567 for (i = 0; i < 50; i++) {
568 udelay(10);
569
Michael Chane503e062012-12-06 10:33:08 +0000570 val1 = BNX2_RD(bp, BNX2_EMAC_MDIO_COMM);
Michael Chanb6016b72005-05-26 13:03:09 -0700571 if (!(val1 & BNX2_EMAC_MDIO_COMM_START_BUSY)) {
572 udelay(5);
573 break;
574 }
575 }
576
577 if (val1 & BNX2_EMAC_MDIO_COMM_START_BUSY)
578 ret = -EBUSY;
579 else
580 ret = 0;
581
Michael Chan583c28e2008-01-21 19:51:35 -0800582 if (bp->phy_flags & BNX2_PHY_FLAG_INT_MODE_AUTO_POLLING) {
Michael Chane503e062012-12-06 10:33:08 +0000583 val1 = BNX2_RD(bp, BNX2_EMAC_MDIO_MODE);
Michael Chanb6016b72005-05-26 13:03:09 -0700584 val1 |= BNX2_EMAC_MDIO_MODE_AUTO_POLL;
585
Michael Chane503e062012-12-06 10:33:08 +0000586 BNX2_WR(bp, BNX2_EMAC_MDIO_MODE, val1);
587 BNX2_RD(bp, BNX2_EMAC_MDIO_MODE);
Michael Chanb6016b72005-05-26 13:03:09 -0700588
589 udelay(40);
590 }
591
592 return ret;
593}
594
595static void
596bnx2_disable_int(struct bnx2 *bp)
597{
Michael Chanb4b36042007-12-20 19:59:30 -0800598 int i;
599 struct bnx2_napi *bnapi;
600
601 for (i = 0; i < bp->irq_nvecs; i++) {
602 bnapi = &bp->bnx2_napi[i];
Michael Chane503e062012-12-06 10:33:08 +0000603 BNX2_WR(bp, BNX2_PCICFG_INT_ACK_CMD, bnapi->int_num |
Michael Chanb4b36042007-12-20 19:59:30 -0800604 BNX2_PCICFG_INT_ACK_CMD_MASK_INT);
605 }
Michael Chane503e062012-12-06 10:33:08 +0000606 BNX2_RD(bp, BNX2_PCICFG_INT_ACK_CMD);
Michael Chanb6016b72005-05-26 13:03:09 -0700607}
608
609static void
610bnx2_enable_int(struct bnx2 *bp)
611{
Michael Chanb4b36042007-12-20 19:59:30 -0800612 int i;
613 struct bnx2_napi *bnapi;
Michael Chan1269a8a2006-01-23 16:11:03 -0800614
Michael Chanb4b36042007-12-20 19:59:30 -0800615 for (i = 0; i < bp->irq_nvecs; i++) {
616 bnapi = &bp->bnx2_napi[i];
Michael Chan35efa7c2007-12-20 19:56:37 -0800617
Michael Chane503e062012-12-06 10:33:08 +0000618 BNX2_WR(bp, BNX2_PCICFG_INT_ACK_CMD, bnapi->int_num |
619 BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
620 BNX2_PCICFG_INT_ACK_CMD_MASK_INT |
621 bnapi->last_status_idx);
Michael Chanb6016b72005-05-26 13:03:09 -0700622
Michael Chane503e062012-12-06 10:33:08 +0000623 BNX2_WR(bp, BNX2_PCICFG_INT_ACK_CMD, bnapi->int_num |
624 BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
625 bnapi->last_status_idx);
Michael Chanb4b36042007-12-20 19:59:30 -0800626 }
Michael Chane503e062012-12-06 10:33:08 +0000627 BNX2_WR(bp, BNX2_HC_COMMAND, bp->hc_cmd | BNX2_HC_COMMAND_COAL_NOW);
Michael Chanb6016b72005-05-26 13:03:09 -0700628}
629
630static void
631bnx2_disable_int_sync(struct bnx2 *bp)
632{
Michael Chanb4b36042007-12-20 19:59:30 -0800633 int i;
634
Michael Chanb6016b72005-05-26 13:03:09 -0700635 atomic_inc(&bp->intr_sem);
Michael Chan37675462009-08-21 16:20:44 +0000636 if (!netif_running(bp->dev))
637 return;
638
Michael Chanb6016b72005-05-26 13:03:09 -0700639 bnx2_disable_int(bp);
Michael Chanb4b36042007-12-20 19:59:30 -0800640 for (i = 0; i < bp->irq_nvecs; i++)
641 synchronize_irq(bp->irq_tbl[i].vector);
Michael Chanb6016b72005-05-26 13:03:09 -0700642}
643
644static void
Michael Chan35efa7c2007-12-20 19:56:37 -0800645bnx2_napi_disable(struct bnx2 *bp)
646{
Michael Chanb4b36042007-12-20 19:59:30 -0800647 int i;
648
649 for (i = 0; i < bp->irq_nvecs; i++)
650 napi_disable(&bp->bnx2_napi[i].napi);
Michael Chan35efa7c2007-12-20 19:56:37 -0800651}
652
653static void
654bnx2_napi_enable(struct bnx2 *bp)
655{
Michael Chanb4b36042007-12-20 19:59:30 -0800656 int i;
657
658 for (i = 0; i < bp->irq_nvecs; i++)
659 napi_enable(&bp->bnx2_napi[i].napi);
Michael Chan35efa7c2007-12-20 19:56:37 -0800660}
661
662static void
Michael Chan212f9932010-04-27 11:28:10 +0000663bnx2_netif_stop(struct bnx2 *bp, bool stop_cnic)
Michael Chanb6016b72005-05-26 13:03:09 -0700664{
Michael Chan212f9932010-04-27 11:28:10 +0000665 if (stop_cnic)
666 bnx2_cnic_stop(bp);
Michael Chanb6016b72005-05-26 13:03:09 -0700667 if (netif_running(bp->dev)) {
Michael Chan35efa7c2007-12-20 19:56:37 -0800668 bnx2_napi_disable(bp);
Michael Chanb6016b72005-05-26 13:03:09 -0700669 netif_tx_disable(bp->dev);
Michael Chanb6016b72005-05-26 13:03:09 -0700670 }
Michael Chanb7466562009-12-20 18:40:18 -0800671 bnx2_disable_int_sync(bp);
Michael Chana0ba6762010-05-17 17:34:43 -0700672 netif_carrier_off(bp->dev); /* prevent tx timeout */
Michael Chanb6016b72005-05-26 13:03:09 -0700673}
674
675static void
Michael Chan212f9932010-04-27 11:28:10 +0000676bnx2_netif_start(struct bnx2 *bp, bool start_cnic)
Michael Chanb6016b72005-05-26 13:03:09 -0700677{
678 if (atomic_dec_and_test(&bp->intr_sem)) {
679 if (netif_running(bp->dev)) {
Benjamin Li706bf242008-07-18 17:55:11 -0700680 netif_tx_wake_all_queues(bp->dev);
Michael Chana0ba6762010-05-17 17:34:43 -0700681 spin_lock_bh(&bp->phy_lock);
682 if (bp->link_up)
683 netif_carrier_on(bp->dev);
684 spin_unlock_bh(&bp->phy_lock);
Michael Chan35efa7c2007-12-20 19:56:37 -0800685 bnx2_napi_enable(bp);
Michael Chanb6016b72005-05-26 13:03:09 -0700686 bnx2_enable_int(bp);
Michael Chan212f9932010-04-27 11:28:10 +0000687 if (start_cnic)
688 bnx2_cnic_start(bp);
Michael Chanb6016b72005-05-26 13:03:09 -0700689 }
690 }
691}
692
693static void
Michael Chan35e90102008-06-19 16:37:42 -0700694bnx2_free_tx_mem(struct bnx2 *bp)
695{
696 int i;
697
698 for (i = 0; i < bp->num_tx_rings; i++) {
699 struct bnx2_napi *bnapi = &bp->bnx2_napi[i];
700 struct bnx2_tx_ring_info *txr = &bnapi->tx_ring;
701
702 if (txr->tx_desc_ring) {
Stanislaw Gruszka36227e82010-07-15 04:25:50 +0000703 dma_free_coherent(&bp->pdev->dev, TXBD_RING_SIZE,
704 txr->tx_desc_ring,
705 txr->tx_desc_mapping);
Michael Chan35e90102008-06-19 16:37:42 -0700706 txr->tx_desc_ring = NULL;
707 }
708 kfree(txr->tx_buf_ring);
709 txr->tx_buf_ring = NULL;
710 }
711}
712
Michael Chanbb4f98a2008-06-19 16:38:19 -0700713static void
714bnx2_free_rx_mem(struct bnx2 *bp)
715{
716 int i;
717
718 for (i = 0; i < bp->num_rx_rings; i++) {
719 struct bnx2_napi *bnapi = &bp->bnx2_napi[i];
720 struct bnx2_rx_ring_info *rxr = &bnapi->rx_ring;
721 int j;
722
723 for (j = 0; j < bp->rx_max_ring; j++) {
724 if (rxr->rx_desc_ring[j])
Stanislaw Gruszka36227e82010-07-15 04:25:50 +0000725 dma_free_coherent(&bp->pdev->dev, RXBD_RING_SIZE,
726 rxr->rx_desc_ring[j],
727 rxr->rx_desc_mapping[j]);
Michael Chanbb4f98a2008-06-19 16:38:19 -0700728 rxr->rx_desc_ring[j] = NULL;
729 }
Breno Leitao25b0b992009-06-08 10:30:19 +0000730 vfree(rxr->rx_buf_ring);
Michael Chanbb4f98a2008-06-19 16:38:19 -0700731 rxr->rx_buf_ring = NULL;
732
733 for (j = 0; j < bp->rx_max_pg_ring; j++) {
734 if (rxr->rx_pg_desc_ring[j])
Stanislaw Gruszka36227e82010-07-15 04:25:50 +0000735 dma_free_coherent(&bp->pdev->dev, RXBD_RING_SIZE,
736 rxr->rx_pg_desc_ring[j],
737 rxr->rx_pg_desc_mapping[j]);
Michael Chan3298a732008-12-17 19:06:08 -0800738 rxr->rx_pg_desc_ring[j] = NULL;
Michael Chanbb4f98a2008-06-19 16:38:19 -0700739 }
Breno Leitao25b0b992009-06-08 10:30:19 +0000740 vfree(rxr->rx_pg_ring);
Michael Chanbb4f98a2008-06-19 16:38:19 -0700741 rxr->rx_pg_ring = NULL;
742 }
743}
744
Michael Chan35e90102008-06-19 16:37:42 -0700745static int
746bnx2_alloc_tx_mem(struct bnx2 *bp)
747{
748 int i;
749
750 for (i = 0; i < bp->num_tx_rings; i++) {
751 struct bnx2_napi *bnapi = &bp->bnx2_napi[i];
752 struct bnx2_tx_ring_info *txr = &bnapi->tx_ring;
753
754 txr->tx_buf_ring = kzalloc(SW_TXBD_RING_SIZE, GFP_KERNEL);
755 if (txr->tx_buf_ring == NULL)
756 return -ENOMEM;
757
758 txr->tx_desc_ring =
Stanislaw Gruszka36227e82010-07-15 04:25:50 +0000759 dma_alloc_coherent(&bp->pdev->dev, TXBD_RING_SIZE,
760 &txr->tx_desc_mapping, GFP_KERNEL);
Michael Chan35e90102008-06-19 16:37:42 -0700761 if (txr->tx_desc_ring == NULL)
762 return -ENOMEM;
763 }
764 return 0;
765}
766
Michael Chanbb4f98a2008-06-19 16:38:19 -0700767static int
768bnx2_alloc_rx_mem(struct bnx2 *bp)
769{
770 int i;
771
772 for (i = 0; i < bp->num_rx_rings; i++) {
773 struct bnx2_napi *bnapi = &bp->bnx2_napi[i];
774 struct bnx2_rx_ring_info *rxr = &bnapi->rx_ring;
775 int j;
776
777 rxr->rx_buf_ring =
Eric Dumazet89bf67f2010-11-22 00:15:06 +0000778 vzalloc(SW_RXBD_RING_SIZE * bp->rx_max_ring);
Michael Chanbb4f98a2008-06-19 16:38:19 -0700779 if (rxr->rx_buf_ring == NULL)
780 return -ENOMEM;
781
Michael Chanbb4f98a2008-06-19 16:38:19 -0700782 for (j = 0; j < bp->rx_max_ring; j++) {
783 rxr->rx_desc_ring[j] =
Stanislaw Gruszka36227e82010-07-15 04:25:50 +0000784 dma_alloc_coherent(&bp->pdev->dev,
785 RXBD_RING_SIZE,
786 &rxr->rx_desc_mapping[j],
787 GFP_KERNEL);
Michael Chanbb4f98a2008-06-19 16:38:19 -0700788 if (rxr->rx_desc_ring[j] == NULL)
789 return -ENOMEM;
790
791 }
792
793 if (bp->rx_pg_ring_size) {
Eric Dumazet89bf67f2010-11-22 00:15:06 +0000794 rxr->rx_pg_ring = vzalloc(SW_RXPG_RING_SIZE *
Michael Chanbb4f98a2008-06-19 16:38:19 -0700795 bp->rx_max_pg_ring);
796 if (rxr->rx_pg_ring == NULL)
797 return -ENOMEM;
798
Michael Chanbb4f98a2008-06-19 16:38:19 -0700799 }
800
801 for (j = 0; j < bp->rx_max_pg_ring; j++) {
802 rxr->rx_pg_desc_ring[j] =
Stanislaw Gruszka36227e82010-07-15 04:25:50 +0000803 dma_alloc_coherent(&bp->pdev->dev,
804 RXBD_RING_SIZE,
805 &rxr->rx_pg_desc_mapping[j],
806 GFP_KERNEL);
Michael Chanbb4f98a2008-06-19 16:38:19 -0700807 if (rxr->rx_pg_desc_ring[j] == NULL)
808 return -ENOMEM;
809
810 }
811 }
812 return 0;
813}
814
Michael Chan35e90102008-06-19 16:37:42 -0700815static void
wangweidong8fae3072015-10-08 18:03:47 +0800816bnx2_free_stats_blk(struct net_device *dev)
817{
818 struct bnx2 *bp = netdev_priv(dev);
819
820 if (bp->status_blk) {
821 dma_free_coherent(&bp->pdev->dev, bp->status_stats_size,
822 bp->status_blk,
823 bp->status_blk_mapping);
824 bp->status_blk = NULL;
825 bp->stats_blk = NULL;
826 }
827}
828
829static int
830bnx2_alloc_stats_blk(struct net_device *dev)
831{
832 int status_blk_size;
833 void *status_blk;
834 struct bnx2 *bp = netdev_priv(dev);
835
836 /* Combine status and statistics blocks into one allocation. */
837 status_blk_size = L1_CACHE_ALIGN(sizeof(struct status_block));
838 if (bp->flags & BNX2_FLAG_MSIX_CAP)
839 status_blk_size = L1_CACHE_ALIGN(BNX2_MAX_MSIX_HW_VEC *
840 BNX2_SBLK_MSIX_ALIGN_SIZE);
841 bp->status_stats_size = status_blk_size +
842 sizeof(struct statistics_block);
843 status_blk = dma_zalloc_coherent(&bp->pdev->dev, bp->status_stats_size,
844 &bp->status_blk_mapping, GFP_KERNEL);
845 if (status_blk == NULL)
846 return -ENOMEM;
847
848 bp->status_blk = status_blk;
849 bp->stats_blk = status_blk + status_blk_size;
850 bp->stats_blk_mapping = bp->status_blk_mapping + status_blk_size;
851
852 return 0;
853}
854
855static void
Michael Chanb6016b72005-05-26 13:03:09 -0700856bnx2_free_mem(struct bnx2 *bp)
857{
Michael Chan13daffa2006-03-20 17:49:20 -0800858 int i;
Michael Chan43e80b82008-06-19 16:41:08 -0700859 struct bnx2_napi *bnapi = &bp->bnx2_napi[0];
Michael Chan13daffa2006-03-20 17:49:20 -0800860
Michael Chan35e90102008-06-19 16:37:42 -0700861 bnx2_free_tx_mem(bp);
Michael Chanbb4f98a2008-06-19 16:38:19 -0700862 bnx2_free_rx_mem(bp);
Michael Chan35e90102008-06-19 16:37:42 -0700863
Michael Chan59b47d82006-11-19 14:10:45 -0800864 for (i = 0; i < bp->ctx_pages; i++) {
865 if (bp->ctx_blk[i]) {
Michael Chan2bc40782012-12-06 10:33:09 +0000866 dma_free_coherent(&bp->pdev->dev, BNX2_PAGE_SIZE,
Stanislaw Gruszka36227e82010-07-15 04:25:50 +0000867 bp->ctx_blk[i],
868 bp->ctx_blk_mapping[i]);
Michael Chan59b47d82006-11-19 14:10:45 -0800869 bp->ctx_blk[i] = NULL;
870 }
871 }
wangweidong8fae3072015-10-08 18:03:47 +0800872
873 if (bnapi->status_blk.msi)
Michael Chan43e80b82008-06-19 16:41:08 -0700874 bnapi->status_blk.msi = NULL;
Michael Chanb6016b72005-05-26 13:03:09 -0700875}
876
877static int
878bnx2_alloc_mem(struct bnx2 *bp)
879{
wangweidong8fae3072015-10-08 18:03:47 +0800880 int i, err;
Michael Chan43e80b82008-06-19 16:41:08 -0700881 struct bnx2_napi *bnapi;
Michael Chanb6016b72005-05-26 13:03:09 -0700882
Michael Chan43e80b82008-06-19 16:41:08 -0700883 bnapi = &bp->bnx2_napi[0];
wangweidong8fae3072015-10-08 18:03:47 +0800884 bnapi->status_blk.msi = bp->status_blk;
Michael Chan43e80b82008-06-19 16:41:08 -0700885 bnapi->hw_tx_cons_ptr =
886 &bnapi->status_blk.msi->status_tx_quick_consumer_index0;
887 bnapi->hw_rx_cons_ptr =
888 &bnapi->status_blk.msi->status_rx_quick_consumer_index0;
David S. Millerf86e82f2008-01-21 17:15:40 -0800889 if (bp->flags & BNX2_FLAG_MSIX_CAP) {
Michael Chan379b39a2010-07-19 14:15:03 +0000890 for (i = 1; i < bp->irq_nvecs; i++) {
Michael Chan43e80b82008-06-19 16:41:08 -0700891 struct status_block_msix *sblk;
Michael Chanb4b36042007-12-20 19:59:30 -0800892
Michael Chan43e80b82008-06-19 16:41:08 -0700893 bnapi = &bp->bnx2_napi[i];
894
wangweidong8fae3072015-10-08 18:03:47 +0800895 sblk = (bp->status_blk + BNX2_SBLK_MSIX_ALIGN_SIZE * i);
Michael Chan43e80b82008-06-19 16:41:08 -0700896 bnapi->status_blk.msix = sblk;
897 bnapi->hw_tx_cons_ptr =
898 &sblk->status_tx_quick_consumer_index;
899 bnapi->hw_rx_cons_ptr =
900 &sblk->status_rx_quick_consumer_index;
Michael Chanb4b36042007-12-20 19:59:30 -0800901 bnapi->int_num = i << 24;
902 }
903 }
Michael Chan35efa7c2007-12-20 19:56:37 -0800904
Michael Chan4ce45e02012-12-06 10:33:10 +0000905 if (BNX2_CHIP(bp) == BNX2_CHIP_5709) {
Michael Chan2bc40782012-12-06 10:33:09 +0000906 bp->ctx_pages = 0x2000 / BNX2_PAGE_SIZE;
Michael Chan59b47d82006-11-19 14:10:45 -0800907 if (bp->ctx_pages == 0)
908 bp->ctx_pages = 1;
909 for (i = 0; i < bp->ctx_pages; i++) {
Stanislaw Gruszka36227e82010-07-15 04:25:50 +0000910 bp->ctx_blk[i] = dma_alloc_coherent(&bp->pdev->dev,
Michael Chan2bc40782012-12-06 10:33:09 +0000911 BNX2_PAGE_SIZE,
Stanislaw Gruszka36227e82010-07-15 04:25:50 +0000912 &bp->ctx_blk_mapping[i],
913 GFP_KERNEL);
Michael Chan59b47d82006-11-19 14:10:45 -0800914 if (bp->ctx_blk[i] == NULL)
915 goto alloc_mem_err;
916 }
917 }
Michael Chan35e90102008-06-19 16:37:42 -0700918
Michael Chanbb4f98a2008-06-19 16:38:19 -0700919 err = bnx2_alloc_rx_mem(bp);
920 if (err)
921 goto alloc_mem_err;
922
Michael Chan35e90102008-06-19 16:37:42 -0700923 err = bnx2_alloc_tx_mem(bp);
924 if (err)
925 goto alloc_mem_err;
926
Michael Chanb6016b72005-05-26 13:03:09 -0700927 return 0;
928
929alloc_mem_err:
930 bnx2_free_mem(bp);
931 return -ENOMEM;
932}
933
934static void
Michael Chane3648b32005-11-04 08:51:21 -0800935bnx2_report_fw_link(struct bnx2 *bp)
936{
937 u32 fw_link_status = 0;
938
Michael Chan583c28e2008-01-21 19:51:35 -0800939 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
Michael Chan0d8a6572007-07-07 22:49:43 -0700940 return;
941
Michael Chane3648b32005-11-04 08:51:21 -0800942 if (bp->link_up) {
943 u32 bmsr;
944
945 switch (bp->line_speed) {
946 case SPEED_10:
947 if (bp->duplex == DUPLEX_HALF)
948 fw_link_status = BNX2_LINK_STATUS_10HALF;
949 else
950 fw_link_status = BNX2_LINK_STATUS_10FULL;
951 break;
952 case SPEED_100:
953 if (bp->duplex == DUPLEX_HALF)
954 fw_link_status = BNX2_LINK_STATUS_100HALF;
955 else
956 fw_link_status = BNX2_LINK_STATUS_100FULL;
957 break;
958 case SPEED_1000:
959 if (bp->duplex == DUPLEX_HALF)
960 fw_link_status = BNX2_LINK_STATUS_1000HALF;
961 else
962 fw_link_status = BNX2_LINK_STATUS_1000FULL;
963 break;
964 case SPEED_2500:
965 if (bp->duplex == DUPLEX_HALF)
966 fw_link_status = BNX2_LINK_STATUS_2500HALF;
967 else
968 fw_link_status = BNX2_LINK_STATUS_2500FULL;
969 break;
970 }
971
972 fw_link_status |= BNX2_LINK_STATUS_LINK_UP;
973
974 if (bp->autoneg) {
975 fw_link_status |= BNX2_LINK_STATUS_AN_ENABLED;
976
Michael Chanca58c3a2007-05-03 13:22:52 -0700977 bnx2_read_phy(bp, bp->mii_bmsr, &bmsr);
978 bnx2_read_phy(bp, bp->mii_bmsr, &bmsr);
Michael Chane3648b32005-11-04 08:51:21 -0800979
980 if (!(bmsr & BMSR_ANEGCOMPLETE) ||
Michael Chan583c28e2008-01-21 19:51:35 -0800981 bp->phy_flags & BNX2_PHY_FLAG_PARALLEL_DETECT)
Michael Chane3648b32005-11-04 08:51:21 -0800982 fw_link_status |= BNX2_LINK_STATUS_PARALLEL_DET;
983 else
984 fw_link_status |= BNX2_LINK_STATUS_AN_COMPLETE;
985 }
986 }
987 else
988 fw_link_status = BNX2_LINK_STATUS_LINK_DOWN;
989
Michael Chan2726d6e2008-01-29 21:35:05 -0800990 bnx2_shmem_wr(bp, BNX2_LINK_STATUS, fw_link_status);
Michael Chane3648b32005-11-04 08:51:21 -0800991}
992
Michael Chan9b1084b2007-07-07 22:50:37 -0700993static char *
994bnx2_xceiver_str(struct bnx2 *bp)
995{
Eric Dumazet807540b2010-09-23 05:40:09 +0000996 return (bp->phy_port == PORT_FIBRE) ? "SerDes" :
Michael Chan583c28e2008-01-21 19:51:35 -0800997 ((bp->phy_flags & BNX2_PHY_FLAG_SERDES) ? "Remote Copper" :
Eric Dumazet807540b2010-09-23 05:40:09 +0000998 "Copper");
Michael Chan9b1084b2007-07-07 22:50:37 -0700999}
1000
Michael Chane3648b32005-11-04 08:51:21 -08001001static void
Michael Chanb6016b72005-05-26 13:03:09 -07001002bnx2_report_link(struct bnx2 *bp)
1003{
1004 if (bp->link_up) {
1005 netif_carrier_on(bp->dev);
Joe Perches3a9c6a42010-02-17 15:01:51 +00001006 netdev_info(bp->dev, "NIC %s Link is Up, %d Mbps %s duplex",
1007 bnx2_xceiver_str(bp),
1008 bp->line_speed,
1009 bp->duplex == DUPLEX_FULL ? "full" : "half");
Michael Chanb6016b72005-05-26 13:03:09 -07001010
1011 if (bp->flow_ctrl) {
1012 if (bp->flow_ctrl & FLOW_CTRL_RX) {
Joe Perches3a9c6a42010-02-17 15:01:51 +00001013 pr_cont(", receive ");
Michael Chanb6016b72005-05-26 13:03:09 -07001014 if (bp->flow_ctrl & FLOW_CTRL_TX)
Joe Perches3a9c6a42010-02-17 15:01:51 +00001015 pr_cont("& transmit ");
Michael Chanb6016b72005-05-26 13:03:09 -07001016 }
1017 else {
Joe Perches3a9c6a42010-02-17 15:01:51 +00001018 pr_cont(", transmit ");
Michael Chanb6016b72005-05-26 13:03:09 -07001019 }
Joe Perches3a9c6a42010-02-17 15:01:51 +00001020 pr_cont("flow control ON");
Michael Chanb6016b72005-05-26 13:03:09 -07001021 }
Joe Perches3a9c6a42010-02-17 15:01:51 +00001022 pr_cont("\n");
1023 } else {
Michael Chanb6016b72005-05-26 13:03:09 -07001024 netif_carrier_off(bp->dev);
Joe Perches3a9c6a42010-02-17 15:01:51 +00001025 netdev_err(bp->dev, "NIC %s Link is Down\n",
1026 bnx2_xceiver_str(bp));
Michael Chanb6016b72005-05-26 13:03:09 -07001027 }
Michael Chane3648b32005-11-04 08:51:21 -08001028
1029 bnx2_report_fw_link(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07001030}
1031
1032static void
1033bnx2_resolve_flow_ctrl(struct bnx2 *bp)
1034{
1035 u32 local_adv, remote_adv;
1036
1037 bp->flow_ctrl = 0;
Jeff Garzik6aa20a22006-09-13 13:24:59 -04001038 if ((bp->autoneg & (AUTONEG_SPEED | AUTONEG_FLOW_CTRL)) !=
Michael Chanb6016b72005-05-26 13:03:09 -07001039 (AUTONEG_SPEED | AUTONEG_FLOW_CTRL)) {
1040
1041 if (bp->duplex == DUPLEX_FULL) {
1042 bp->flow_ctrl = bp->req_flow_ctrl;
1043 }
1044 return;
1045 }
1046
1047 if (bp->duplex != DUPLEX_FULL) {
1048 return;
1049 }
1050
Michael Chan583c28e2008-01-21 19:51:35 -08001051 if ((bp->phy_flags & BNX2_PHY_FLAG_SERDES) &&
Michael Chan4ce45e02012-12-06 10:33:10 +00001052 (BNX2_CHIP(bp) == BNX2_CHIP_5708)) {
Michael Chan5b0c76a2005-11-04 08:45:49 -08001053 u32 val;
1054
1055 bnx2_read_phy(bp, BCM5708S_1000X_STAT1, &val);
1056 if (val & BCM5708S_1000X_STAT1_TX_PAUSE)
1057 bp->flow_ctrl |= FLOW_CTRL_TX;
1058 if (val & BCM5708S_1000X_STAT1_RX_PAUSE)
1059 bp->flow_ctrl |= FLOW_CTRL_RX;
1060 return;
1061 }
1062
Michael Chanca58c3a2007-05-03 13:22:52 -07001063 bnx2_read_phy(bp, bp->mii_adv, &local_adv);
1064 bnx2_read_phy(bp, bp->mii_lpa, &remote_adv);
Michael Chanb6016b72005-05-26 13:03:09 -07001065
Michael Chan583c28e2008-01-21 19:51:35 -08001066 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Michael Chanb6016b72005-05-26 13:03:09 -07001067 u32 new_local_adv = 0;
1068 u32 new_remote_adv = 0;
1069
1070 if (local_adv & ADVERTISE_1000XPAUSE)
1071 new_local_adv |= ADVERTISE_PAUSE_CAP;
1072 if (local_adv & ADVERTISE_1000XPSE_ASYM)
1073 new_local_adv |= ADVERTISE_PAUSE_ASYM;
1074 if (remote_adv & ADVERTISE_1000XPAUSE)
1075 new_remote_adv |= ADVERTISE_PAUSE_CAP;
1076 if (remote_adv & ADVERTISE_1000XPSE_ASYM)
1077 new_remote_adv |= ADVERTISE_PAUSE_ASYM;
1078
1079 local_adv = new_local_adv;
1080 remote_adv = new_remote_adv;
1081 }
1082
1083 /* See Table 28B-3 of 802.3ab-1999 spec. */
1084 if (local_adv & ADVERTISE_PAUSE_CAP) {
1085 if(local_adv & ADVERTISE_PAUSE_ASYM) {
1086 if (remote_adv & ADVERTISE_PAUSE_CAP) {
1087 bp->flow_ctrl = FLOW_CTRL_TX | FLOW_CTRL_RX;
1088 }
1089 else if (remote_adv & ADVERTISE_PAUSE_ASYM) {
1090 bp->flow_ctrl = FLOW_CTRL_RX;
1091 }
1092 }
1093 else {
1094 if (remote_adv & ADVERTISE_PAUSE_CAP) {
1095 bp->flow_ctrl = FLOW_CTRL_TX | FLOW_CTRL_RX;
1096 }
1097 }
1098 }
1099 else if (local_adv & ADVERTISE_PAUSE_ASYM) {
1100 if ((remote_adv & ADVERTISE_PAUSE_CAP) &&
1101 (remote_adv & ADVERTISE_PAUSE_ASYM)) {
1102
1103 bp->flow_ctrl = FLOW_CTRL_TX;
1104 }
1105 }
1106}
1107
1108static int
Michael Chan27a005b2007-05-03 13:23:41 -07001109bnx2_5709s_linkup(struct bnx2 *bp)
1110{
1111 u32 val, speed;
1112
1113 bp->link_up = 1;
1114
1115 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_GP_STATUS);
1116 bnx2_read_phy(bp, MII_BNX2_GP_TOP_AN_STATUS1, &val);
1117 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
1118
1119 if ((bp->autoneg & AUTONEG_SPEED) == 0) {
1120 bp->line_speed = bp->req_line_speed;
1121 bp->duplex = bp->req_duplex;
1122 return 0;
1123 }
1124 speed = val & MII_BNX2_GP_TOP_AN_SPEED_MSK;
1125 switch (speed) {
1126 case MII_BNX2_GP_TOP_AN_SPEED_10:
1127 bp->line_speed = SPEED_10;
1128 break;
1129 case MII_BNX2_GP_TOP_AN_SPEED_100:
1130 bp->line_speed = SPEED_100;
1131 break;
1132 case MII_BNX2_GP_TOP_AN_SPEED_1G:
1133 case MII_BNX2_GP_TOP_AN_SPEED_1GKV:
1134 bp->line_speed = SPEED_1000;
1135 break;
1136 case MII_BNX2_GP_TOP_AN_SPEED_2_5G:
1137 bp->line_speed = SPEED_2500;
1138 break;
1139 }
1140 if (val & MII_BNX2_GP_TOP_AN_FD)
1141 bp->duplex = DUPLEX_FULL;
1142 else
1143 bp->duplex = DUPLEX_HALF;
1144 return 0;
1145}
1146
1147static int
Michael Chan5b0c76a2005-11-04 08:45:49 -08001148bnx2_5708s_linkup(struct bnx2 *bp)
1149{
1150 u32 val;
1151
1152 bp->link_up = 1;
1153 bnx2_read_phy(bp, BCM5708S_1000X_STAT1, &val);
1154 switch (val & BCM5708S_1000X_STAT1_SPEED_MASK) {
1155 case BCM5708S_1000X_STAT1_SPEED_10:
1156 bp->line_speed = SPEED_10;
1157 break;
1158 case BCM5708S_1000X_STAT1_SPEED_100:
1159 bp->line_speed = SPEED_100;
1160 break;
1161 case BCM5708S_1000X_STAT1_SPEED_1G:
1162 bp->line_speed = SPEED_1000;
1163 break;
1164 case BCM5708S_1000X_STAT1_SPEED_2G5:
1165 bp->line_speed = SPEED_2500;
1166 break;
1167 }
1168 if (val & BCM5708S_1000X_STAT1_FD)
1169 bp->duplex = DUPLEX_FULL;
1170 else
1171 bp->duplex = DUPLEX_HALF;
1172
1173 return 0;
1174}
1175
1176static int
1177bnx2_5706s_linkup(struct bnx2 *bp)
Michael Chanb6016b72005-05-26 13:03:09 -07001178{
1179 u32 bmcr, local_adv, remote_adv, common;
1180
1181 bp->link_up = 1;
1182 bp->line_speed = SPEED_1000;
1183
Michael Chanca58c3a2007-05-03 13:22:52 -07001184 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chanb6016b72005-05-26 13:03:09 -07001185 if (bmcr & BMCR_FULLDPLX) {
1186 bp->duplex = DUPLEX_FULL;
1187 }
1188 else {
1189 bp->duplex = DUPLEX_HALF;
1190 }
1191
1192 if (!(bmcr & BMCR_ANENABLE)) {
1193 return 0;
1194 }
1195
Michael Chanca58c3a2007-05-03 13:22:52 -07001196 bnx2_read_phy(bp, bp->mii_adv, &local_adv);
1197 bnx2_read_phy(bp, bp->mii_lpa, &remote_adv);
Michael Chanb6016b72005-05-26 13:03:09 -07001198
1199 common = local_adv & remote_adv;
1200 if (common & (ADVERTISE_1000XHALF | ADVERTISE_1000XFULL)) {
1201
1202 if (common & ADVERTISE_1000XFULL) {
1203 bp->duplex = DUPLEX_FULL;
1204 }
1205 else {
1206 bp->duplex = DUPLEX_HALF;
1207 }
1208 }
1209
1210 return 0;
1211}
1212
1213static int
1214bnx2_copper_linkup(struct bnx2 *bp)
1215{
1216 u32 bmcr;
1217
Michael Chan4016bad2013-12-31 23:22:34 -08001218 bp->phy_flags &= ~BNX2_PHY_FLAG_MDIX;
1219
Michael Chanca58c3a2007-05-03 13:22:52 -07001220 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chanb6016b72005-05-26 13:03:09 -07001221 if (bmcr & BMCR_ANENABLE) {
1222 u32 local_adv, remote_adv, common;
1223
1224 bnx2_read_phy(bp, MII_CTRL1000, &local_adv);
1225 bnx2_read_phy(bp, MII_STAT1000, &remote_adv);
1226
1227 common = local_adv & (remote_adv >> 2);
1228 if (common & ADVERTISE_1000FULL) {
1229 bp->line_speed = SPEED_1000;
1230 bp->duplex = DUPLEX_FULL;
1231 }
1232 else if (common & ADVERTISE_1000HALF) {
1233 bp->line_speed = SPEED_1000;
1234 bp->duplex = DUPLEX_HALF;
1235 }
1236 else {
Michael Chanca58c3a2007-05-03 13:22:52 -07001237 bnx2_read_phy(bp, bp->mii_adv, &local_adv);
1238 bnx2_read_phy(bp, bp->mii_lpa, &remote_adv);
Michael Chanb6016b72005-05-26 13:03:09 -07001239
1240 common = local_adv & remote_adv;
1241 if (common & ADVERTISE_100FULL) {
1242 bp->line_speed = SPEED_100;
1243 bp->duplex = DUPLEX_FULL;
1244 }
1245 else if (common & ADVERTISE_100HALF) {
1246 bp->line_speed = SPEED_100;
1247 bp->duplex = DUPLEX_HALF;
1248 }
1249 else if (common & ADVERTISE_10FULL) {
1250 bp->line_speed = SPEED_10;
1251 bp->duplex = DUPLEX_FULL;
1252 }
1253 else if (common & ADVERTISE_10HALF) {
1254 bp->line_speed = SPEED_10;
1255 bp->duplex = DUPLEX_HALF;
1256 }
1257 else {
1258 bp->line_speed = 0;
1259 bp->link_up = 0;
1260 }
1261 }
1262 }
1263 else {
1264 if (bmcr & BMCR_SPEED100) {
1265 bp->line_speed = SPEED_100;
1266 }
1267 else {
1268 bp->line_speed = SPEED_10;
1269 }
1270 if (bmcr & BMCR_FULLDPLX) {
1271 bp->duplex = DUPLEX_FULL;
1272 }
1273 else {
1274 bp->duplex = DUPLEX_HALF;
1275 }
1276 }
1277
Michael Chan4016bad2013-12-31 23:22:34 -08001278 if (bp->link_up) {
1279 u32 ext_status;
1280
1281 bnx2_read_phy(bp, MII_BNX2_EXT_STATUS, &ext_status);
1282 if (ext_status & EXT_STATUS_MDIX)
1283 bp->phy_flags |= BNX2_PHY_FLAG_MDIX;
1284 }
1285
Michael Chanb6016b72005-05-26 13:03:09 -07001286 return 0;
1287}
1288
Michael Chan83e3fc82008-01-29 21:37:17 -08001289static void
Michael Chanbb4f98a2008-06-19 16:38:19 -07001290bnx2_init_rx_context(struct bnx2 *bp, u32 cid)
Michael Chan83e3fc82008-01-29 21:37:17 -08001291{
Michael Chanbb4f98a2008-06-19 16:38:19 -07001292 u32 val, rx_cid_addr = GET_CID_ADDR(cid);
Michael Chan83e3fc82008-01-29 21:37:17 -08001293
1294 val = BNX2_L2CTX_CTX_TYPE_CTX_BD_CHN_TYPE_VALUE;
1295 val |= BNX2_L2CTX_CTX_TYPE_SIZE_L2;
1296 val |= 0x02 << 8;
1297
Michael Chan22fa1592010-10-11 16:12:00 -07001298 if (bp->flow_ctrl & FLOW_CTRL_TX)
1299 val |= BNX2_L2CTX_FLOW_CTRL_ENABLE;
Michael Chan83e3fc82008-01-29 21:37:17 -08001300
Michael Chan83e3fc82008-01-29 21:37:17 -08001301 bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_CTX_TYPE, val);
1302}
1303
Michael Chanbb4f98a2008-06-19 16:38:19 -07001304static void
1305bnx2_init_all_rx_contexts(struct bnx2 *bp)
1306{
1307 int i;
1308 u32 cid;
1309
1310 for (i = 0, cid = RX_CID; i < bp->num_rx_rings; i++, cid++) {
1311 if (i == 1)
1312 cid = RX_RSS_CID;
1313 bnx2_init_rx_context(bp, cid);
1314 }
1315}
1316
Benjamin Li344478d2008-09-18 16:38:24 -07001317static void
Michael Chanb6016b72005-05-26 13:03:09 -07001318bnx2_set_mac_link(struct bnx2 *bp)
1319{
1320 u32 val;
1321
Michael Chane503e062012-12-06 10:33:08 +00001322 BNX2_WR(bp, BNX2_EMAC_TX_LENGTHS, 0x2620);
Michael Chanb6016b72005-05-26 13:03:09 -07001323 if (bp->link_up && (bp->line_speed == SPEED_1000) &&
1324 (bp->duplex == DUPLEX_HALF)) {
Michael Chane503e062012-12-06 10:33:08 +00001325 BNX2_WR(bp, BNX2_EMAC_TX_LENGTHS, 0x26ff);
Michael Chanb6016b72005-05-26 13:03:09 -07001326 }
1327
1328 /* Configure the EMAC mode register. */
Michael Chane503e062012-12-06 10:33:08 +00001329 val = BNX2_RD(bp, BNX2_EMAC_MODE);
Michael Chanb6016b72005-05-26 13:03:09 -07001330
1331 val &= ~(BNX2_EMAC_MODE_PORT | BNX2_EMAC_MODE_HALF_DUPLEX |
Michael Chan5b0c76a2005-11-04 08:45:49 -08001332 BNX2_EMAC_MODE_MAC_LOOP | BNX2_EMAC_MODE_FORCE_LINK |
Michael Chan59b47d82006-11-19 14:10:45 -08001333 BNX2_EMAC_MODE_25G_MODE);
Michael Chanb6016b72005-05-26 13:03:09 -07001334
1335 if (bp->link_up) {
Michael Chan5b0c76a2005-11-04 08:45:49 -08001336 switch (bp->line_speed) {
1337 case SPEED_10:
Michael Chan4ce45e02012-12-06 10:33:10 +00001338 if (BNX2_CHIP(bp) != BNX2_CHIP_5706) {
Michael Chan59b47d82006-11-19 14:10:45 -08001339 val |= BNX2_EMAC_MODE_PORT_MII_10M;
Michael Chan5b0c76a2005-11-04 08:45:49 -08001340 break;
1341 }
1342 /* fall through */
1343 case SPEED_100:
1344 val |= BNX2_EMAC_MODE_PORT_MII;
1345 break;
1346 case SPEED_2500:
Michael Chan59b47d82006-11-19 14:10:45 -08001347 val |= BNX2_EMAC_MODE_25G_MODE;
Michael Chan5b0c76a2005-11-04 08:45:49 -08001348 /* fall through */
1349 case SPEED_1000:
1350 val |= BNX2_EMAC_MODE_PORT_GMII;
1351 break;
1352 }
Michael Chanb6016b72005-05-26 13:03:09 -07001353 }
1354 else {
1355 val |= BNX2_EMAC_MODE_PORT_GMII;
1356 }
1357
1358 /* Set the MAC to operate in the appropriate duplex mode. */
1359 if (bp->duplex == DUPLEX_HALF)
1360 val |= BNX2_EMAC_MODE_HALF_DUPLEX;
Michael Chane503e062012-12-06 10:33:08 +00001361 BNX2_WR(bp, BNX2_EMAC_MODE, val);
Michael Chanb6016b72005-05-26 13:03:09 -07001362
1363 /* Enable/disable rx PAUSE. */
1364 bp->rx_mode &= ~BNX2_EMAC_RX_MODE_FLOW_EN;
1365
1366 if (bp->flow_ctrl & FLOW_CTRL_RX)
1367 bp->rx_mode |= BNX2_EMAC_RX_MODE_FLOW_EN;
Michael Chane503e062012-12-06 10:33:08 +00001368 BNX2_WR(bp, BNX2_EMAC_RX_MODE, bp->rx_mode);
Michael Chanb6016b72005-05-26 13:03:09 -07001369
1370 /* Enable/disable tx PAUSE. */
Michael Chane503e062012-12-06 10:33:08 +00001371 val = BNX2_RD(bp, BNX2_EMAC_TX_MODE);
Michael Chanb6016b72005-05-26 13:03:09 -07001372 val &= ~BNX2_EMAC_TX_MODE_FLOW_EN;
1373
1374 if (bp->flow_ctrl & FLOW_CTRL_TX)
1375 val |= BNX2_EMAC_TX_MODE_FLOW_EN;
Michael Chane503e062012-12-06 10:33:08 +00001376 BNX2_WR(bp, BNX2_EMAC_TX_MODE, val);
Michael Chanb6016b72005-05-26 13:03:09 -07001377
1378 /* Acknowledge the interrupt. */
Michael Chane503e062012-12-06 10:33:08 +00001379 BNX2_WR(bp, BNX2_EMAC_STATUS, BNX2_EMAC_STATUS_LINK_CHANGE);
Michael Chanb6016b72005-05-26 13:03:09 -07001380
Michael Chan22fa1592010-10-11 16:12:00 -07001381 bnx2_init_all_rx_contexts(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07001382}
1383
Michael Chan27a005b2007-05-03 13:23:41 -07001384static void
1385bnx2_enable_bmsr1(struct bnx2 *bp)
1386{
Michael Chan583c28e2008-01-21 19:51:35 -08001387 if ((bp->phy_flags & BNX2_PHY_FLAG_SERDES) &&
Michael Chan4ce45e02012-12-06 10:33:10 +00001388 (BNX2_CHIP(bp) == BNX2_CHIP_5709))
Michael Chan27a005b2007-05-03 13:23:41 -07001389 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
1390 MII_BNX2_BLK_ADDR_GP_STATUS);
1391}
1392
1393static void
1394bnx2_disable_bmsr1(struct bnx2 *bp)
1395{
Michael Chan583c28e2008-01-21 19:51:35 -08001396 if ((bp->phy_flags & BNX2_PHY_FLAG_SERDES) &&
Michael Chan4ce45e02012-12-06 10:33:10 +00001397 (BNX2_CHIP(bp) == BNX2_CHIP_5709))
Michael Chan27a005b2007-05-03 13:23:41 -07001398 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
1399 MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
1400}
1401
Michael Chanb6016b72005-05-26 13:03:09 -07001402static int
Michael Chan605a9e22007-05-03 13:23:13 -07001403bnx2_test_and_enable_2g5(struct bnx2 *bp)
1404{
1405 u32 up1;
1406 int ret = 1;
1407
Michael Chan583c28e2008-01-21 19:51:35 -08001408 if (!(bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE))
Michael Chan605a9e22007-05-03 13:23:13 -07001409 return 0;
1410
1411 if (bp->autoneg & AUTONEG_SPEED)
1412 bp->advertising |= ADVERTISED_2500baseX_Full;
1413
Michael Chan4ce45e02012-12-06 10:33:10 +00001414 if (BNX2_CHIP(bp) == BNX2_CHIP_5709)
Michael Chan27a005b2007-05-03 13:23:41 -07001415 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_OVER1G);
1416
Michael Chan605a9e22007-05-03 13:23:13 -07001417 bnx2_read_phy(bp, bp->mii_up1, &up1);
1418 if (!(up1 & BCM5708S_UP1_2G5)) {
1419 up1 |= BCM5708S_UP1_2G5;
1420 bnx2_write_phy(bp, bp->mii_up1, up1);
1421 ret = 0;
1422 }
1423
Michael Chan4ce45e02012-12-06 10:33:10 +00001424 if (BNX2_CHIP(bp) == BNX2_CHIP_5709)
Michael Chan27a005b2007-05-03 13:23:41 -07001425 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
1426 MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
1427
Michael Chan605a9e22007-05-03 13:23:13 -07001428 return ret;
1429}
1430
1431static int
1432bnx2_test_and_disable_2g5(struct bnx2 *bp)
1433{
1434 u32 up1;
1435 int ret = 0;
1436
Michael Chan583c28e2008-01-21 19:51:35 -08001437 if (!(bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE))
Michael Chan605a9e22007-05-03 13:23:13 -07001438 return 0;
1439
Michael Chan4ce45e02012-12-06 10:33:10 +00001440 if (BNX2_CHIP(bp) == BNX2_CHIP_5709)
Michael Chan27a005b2007-05-03 13:23:41 -07001441 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_OVER1G);
1442
Michael Chan605a9e22007-05-03 13:23:13 -07001443 bnx2_read_phy(bp, bp->mii_up1, &up1);
1444 if (up1 & BCM5708S_UP1_2G5) {
1445 up1 &= ~BCM5708S_UP1_2G5;
1446 bnx2_write_phy(bp, bp->mii_up1, up1);
1447 ret = 1;
1448 }
1449
Michael Chan4ce45e02012-12-06 10:33:10 +00001450 if (BNX2_CHIP(bp) == BNX2_CHIP_5709)
Michael Chan27a005b2007-05-03 13:23:41 -07001451 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
1452 MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
1453
Michael Chan605a9e22007-05-03 13:23:13 -07001454 return ret;
1455}
1456
1457static void
1458bnx2_enable_forced_2g5(struct bnx2 *bp)
1459{
Michael Chancbd68902010-06-08 07:21:30 +00001460 u32 uninitialized_var(bmcr);
1461 int err;
Michael Chan605a9e22007-05-03 13:23:13 -07001462
Michael Chan583c28e2008-01-21 19:51:35 -08001463 if (!(bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE))
Michael Chan605a9e22007-05-03 13:23:13 -07001464 return;
1465
Michael Chan4ce45e02012-12-06 10:33:10 +00001466 if (BNX2_CHIP(bp) == BNX2_CHIP_5709) {
Michael Chan27a005b2007-05-03 13:23:41 -07001467 u32 val;
1468
1469 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
1470 MII_BNX2_BLK_ADDR_SERDES_DIG);
Michael Chancbd68902010-06-08 07:21:30 +00001471 if (!bnx2_read_phy(bp, MII_BNX2_SERDES_DIG_MISC1, &val)) {
1472 val &= ~MII_BNX2_SD_MISC1_FORCE_MSK;
1473 val |= MII_BNX2_SD_MISC1_FORCE |
1474 MII_BNX2_SD_MISC1_FORCE_2_5G;
1475 bnx2_write_phy(bp, MII_BNX2_SERDES_DIG_MISC1, val);
1476 }
Michael Chan27a005b2007-05-03 13:23:41 -07001477
1478 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
1479 MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
Michael Chancbd68902010-06-08 07:21:30 +00001480 err = bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chan27a005b2007-05-03 13:23:41 -07001481
Michael Chan4ce45e02012-12-06 10:33:10 +00001482 } else if (BNX2_CHIP(bp) == BNX2_CHIP_5708) {
Michael Chancbd68902010-06-08 07:21:30 +00001483 err = bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
1484 if (!err)
1485 bmcr |= BCM5708S_BMCR_FORCE_2500;
Eric Dumazetc7079852009-11-02 23:17:42 +00001486 } else {
1487 return;
Michael Chan605a9e22007-05-03 13:23:13 -07001488 }
1489
Michael Chancbd68902010-06-08 07:21:30 +00001490 if (err)
1491 return;
1492
Michael Chan605a9e22007-05-03 13:23:13 -07001493 if (bp->autoneg & AUTONEG_SPEED) {
1494 bmcr &= ~BMCR_ANENABLE;
1495 if (bp->req_duplex == DUPLEX_FULL)
1496 bmcr |= BMCR_FULLDPLX;
1497 }
1498 bnx2_write_phy(bp, bp->mii_bmcr, bmcr);
1499}
1500
1501static void
1502bnx2_disable_forced_2g5(struct bnx2 *bp)
1503{
Michael Chancbd68902010-06-08 07:21:30 +00001504 u32 uninitialized_var(bmcr);
1505 int err;
Michael Chan605a9e22007-05-03 13:23:13 -07001506
Michael Chan583c28e2008-01-21 19:51:35 -08001507 if (!(bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE))
Michael Chan605a9e22007-05-03 13:23:13 -07001508 return;
1509
Michael Chan4ce45e02012-12-06 10:33:10 +00001510 if (BNX2_CHIP(bp) == BNX2_CHIP_5709) {
Michael Chan27a005b2007-05-03 13:23:41 -07001511 u32 val;
1512
1513 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
1514 MII_BNX2_BLK_ADDR_SERDES_DIG);
Michael Chancbd68902010-06-08 07:21:30 +00001515 if (!bnx2_read_phy(bp, MII_BNX2_SERDES_DIG_MISC1, &val)) {
1516 val &= ~MII_BNX2_SD_MISC1_FORCE;
1517 bnx2_write_phy(bp, MII_BNX2_SERDES_DIG_MISC1, val);
1518 }
Michael Chan27a005b2007-05-03 13:23:41 -07001519
1520 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
1521 MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
Michael Chancbd68902010-06-08 07:21:30 +00001522 err = bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chan27a005b2007-05-03 13:23:41 -07001523
Michael Chan4ce45e02012-12-06 10:33:10 +00001524 } else if (BNX2_CHIP(bp) == BNX2_CHIP_5708) {
Michael Chancbd68902010-06-08 07:21:30 +00001525 err = bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
1526 if (!err)
1527 bmcr &= ~BCM5708S_BMCR_FORCE_2500;
Eric Dumazetc7079852009-11-02 23:17:42 +00001528 } else {
1529 return;
Michael Chan605a9e22007-05-03 13:23:13 -07001530 }
1531
Michael Chancbd68902010-06-08 07:21:30 +00001532 if (err)
1533 return;
1534
Michael Chan605a9e22007-05-03 13:23:13 -07001535 if (bp->autoneg & AUTONEG_SPEED)
1536 bmcr |= BMCR_SPEED1000 | BMCR_ANENABLE | BMCR_ANRESTART;
1537 bnx2_write_phy(bp, bp->mii_bmcr, bmcr);
1538}
1539
Michael Chanb2fadea2008-01-21 17:07:06 -08001540static void
1541bnx2_5706s_force_link_dn(struct bnx2 *bp, int start)
1542{
1543 u32 val;
1544
1545 bnx2_write_phy(bp, MII_BNX2_DSP_ADDRESS, MII_EXPAND_SERDES_CTL);
1546 bnx2_read_phy(bp, MII_BNX2_DSP_RW_PORT, &val);
1547 if (start)
1548 bnx2_write_phy(bp, MII_BNX2_DSP_RW_PORT, val & 0xff0f);
1549 else
1550 bnx2_write_phy(bp, MII_BNX2_DSP_RW_PORT, val | 0xc0);
1551}
1552
Michael Chan605a9e22007-05-03 13:23:13 -07001553static int
Michael Chanb6016b72005-05-26 13:03:09 -07001554bnx2_set_link(struct bnx2 *bp)
1555{
1556 u32 bmsr;
1557 u8 link_up;
1558
Michael Chan80be4432006-11-19 14:07:28 -08001559 if (bp->loopback == MAC_LOOPBACK || bp->loopback == PHY_LOOPBACK) {
Michael Chanb6016b72005-05-26 13:03:09 -07001560 bp->link_up = 1;
1561 return 0;
1562 }
1563
Michael Chan583c28e2008-01-21 19:51:35 -08001564 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
Michael Chan0d8a6572007-07-07 22:49:43 -07001565 return 0;
1566
Michael Chanb6016b72005-05-26 13:03:09 -07001567 link_up = bp->link_up;
1568
Michael Chan27a005b2007-05-03 13:23:41 -07001569 bnx2_enable_bmsr1(bp);
1570 bnx2_read_phy(bp, bp->mii_bmsr1, &bmsr);
1571 bnx2_read_phy(bp, bp->mii_bmsr1, &bmsr);
1572 bnx2_disable_bmsr1(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07001573
Michael Chan583c28e2008-01-21 19:51:35 -08001574 if ((bp->phy_flags & BNX2_PHY_FLAG_SERDES) &&
Michael Chan4ce45e02012-12-06 10:33:10 +00001575 (BNX2_CHIP(bp) == BNX2_CHIP_5706)) {
Michael Chana2724e22008-02-23 19:47:44 -08001576 u32 val, an_dbg;
Michael Chanb6016b72005-05-26 13:03:09 -07001577
Michael Chan583c28e2008-01-21 19:51:35 -08001578 if (bp->phy_flags & BNX2_PHY_FLAG_FORCED_DOWN) {
Michael Chanb2fadea2008-01-21 17:07:06 -08001579 bnx2_5706s_force_link_dn(bp, 0);
Michael Chan583c28e2008-01-21 19:51:35 -08001580 bp->phy_flags &= ~BNX2_PHY_FLAG_FORCED_DOWN;
Michael Chanb2fadea2008-01-21 17:07:06 -08001581 }
Michael Chane503e062012-12-06 10:33:08 +00001582 val = BNX2_RD(bp, BNX2_EMAC_STATUS);
Michael Chana2724e22008-02-23 19:47:44 -08001583
1584 bnx2_write_phy(bp, MII_BNX2_MISC_SHADOW, MISC_SHDW_AN_DBG);
1585 bnx2_read_phy(bp, MII_BNX2_MISC_SHADOW, &an_dbg);
1586 bnx2_read_phy(bp, MII_BNX2_MISC_SHADOW, &an_dbg);
1587
1588 if ((val & BNX2_EMAC_STATUS_LINK) &&
1589 !(an_dbg & MISC_SHDW_AN_DBG_NOSYNC))
Michael Chanb6016b72005-05-26 13:03:09 -07001590 bmsr |= BMSR_LSTATUS;
1591 else
1592 bmsr &= ~BMSR_LSTATUS;
1593 }
1594
1595 if (bmsr & BMSR_LSTATUS) {
1596 bp->link_up = 1;
1597
Michael Chan583c28e2008-01-21 19:51:35 -08001598 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Michael Chan4ce45e02012-12-06 10:33:10 +00001599 if (BNX2_CHIP(bp) == BNX2_CHIP_5706)
Michael Chan5b0c76a2005-11-04 08:45:49 -08001600 bnx2_5706s_linkup(bp);
Michael Chan4ce45e02012-12-06 10:33:10 +00001601 else if (BNX2_CHIP(bp) == BNX2_CHIP_5708)
Michael Chan5b0c76a2005-11-04 08:45:49 -08001602 bnx2_5708s_linkup(bp);
Michael Chan4ce45e02012-12-06 10:33:10 +00001603 else if (BNX2_CHIP(bp) == BNX2_CHIP_5709)
Michael Chan27a005b2007-05-03 13:23:41 -07001604 bnx2_5709s_linkup(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07001605 }
1606 else {
1607 bnx2_copper_linkup(bp);
1608 }
1609 bnx2_resolve_flow_ctrl(bp);
1610 }
1611 else {
Michael Chan583c28e2008-01-21 19:51:35 -08001612 if ((bp->phy_flags & BNX2_PHY_FLAG_SERDES) &&
Michael Chan605a9e22007-05-03 13:23:13 -07001613 (bp->autoneg & AUTONEG_SPEED))
1614 bnx2_disable_forced_2g5(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07001615
Michael Chan583c28e2008-01-21 19:51:35 -08001616 if (bp->phy_flags & BNX2_PHY_FLAG_PARALLEL_DETECT) {
Michael Chanb2fadea2008-01-21 17:07:06 -08001617 u32 bmcr;
1618
1619 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
1620 bmcr |= BMCR_ANENABLE;
1621 bnx2_write_phy(bp, bp->mii_bmcr, bmcr);
1622
Michael Chan583c28e2008-01-21 19:51:35 -08001623 bp->phy_flags &= ~BNX2_PHY_FLAG_PARALLEL_DETECT;
Michael Chanb2fadea2008-01-21 17:07:06 -08001624 }
Michael Chanb6016b72005-05-26 13:03:09 -07001625 bp->link_up = 0;
1626 }
1627
1628 if (bp->link_up != link_up) {
1629 bnx2_report_link(bp);
1630 }
1631
1632 bnx2_set_mac_link(bp);
1633
1634 return 0;
1635}
1636
1637static int
1638bnx2_reset_phy(struct bnx2 *bp)
1639{
1640 int i;
1641 u32 reg;
1642
Michael Chanca58c3a2007-05-03 13:22:52 -07001643 bnx2_write_phy(bp, bp->mii_bmcr, BMCR_RESET);
Michael Chanb6016b72005-05-26 13:03:09 -07001644
1645#define PHY_RESET_MAX_WAIT 100
1646 for (i = 0; i < PHY_RESET_MAX_WAIT; i++) {
1647 udelay(10);
1648
Michael Chanca58c3a2007-05-03 13:22:52 -07001649 bnx2_read_phy(bp, bp->mii_bmcr, &reg);
Michael Chanb6016b72005-05-26 13:03:09 -07001650 if (!(reg & BMCR_RESET)) {
1651 udelay(20);
1652 break;
1653 }
1654 }
1655 if (i == PHY_RESET_MAX_WAIT) {
1656 return -EBUSY;
1657 }
1658 return 0;
1659}
1660
1661static u32
1662bnx2_phy_get_pause_adv(struct bnx2 *bp)
1663{
1664 u32 adv = 0;
1665
1666 if ((bp->req_flow_ctrl & (FLOW_CTRL_RX | FLOW_CTRL_TX)) ==
1667 (FLOW_CTRL_RX | FLOW_CTRL_TX)) {
1668
Michael Chan583c28e2008-01-21 19:51:35 -08001669 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Michael Chanb6016b72005-05-26 13:03:09 -07001670 adv = ADVERTISE_1000XPAUSE;
1671 }
1672 else {
1673 adv = ADVERTISE_PAUSE_CAP;
1674 }
1675 }
1676 else if (bp->req_flow_ctrl & FLOW_CTRL_TX) {
Michael Chan583c28e2008-01-21 19:51:35 -08001677 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Michael Chanb6016b72005-05-26 13:03:09 -07001678 adv = ADVERTISE_1000XPSE_ASYM;
1679 }
1680 else {
1681 adv = ADVERTISE_PAUSE_ASYM;
1682 }
1683 }
1684 else if (bp->req_flow_ctrl & FLOW_CTRL_RX) {
Michael Chan583c28e2008-01-21 19:51:35 -08001685 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Michael Chanb6016b72005-05-26 13:03:09 -07001686 adv = ADVERTISE_1000XPAUSE | ADVERTISE_1000XPSE_ASYM;
1687 }
1688 else {
1689 adv = ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM;
1690 }
1691 }
1692 return adv;
1693}
1694
Michael Chana2f13892008-07-14 22:38:23 -07001695static int bnx2_fw_sync(struct bnx2 *, u32, int, int);
Michael Chan0d8a6572007-07-07 22:49:43 -07001696
Michael Chanb6016b72005-05-26 13:03:09 -07001697static int
Michael Chan0d8a6572007-07-07 22:49:43 -07001698bnx2_setup_remote_phy(struct bnx2 *bp, u8 port)
Harvey Harrison52d07b12009-01-19 17:27:06 -08001699__releases(&bp->phy_lock)
1700__acquires(&bp->phy_lock)
Michael Chan0d8a6572007-07-07 22:49:43 -07001701{
1702 u32 speed_arg = 0, pause_adv;
1703
1704 pause_adv = bnx2_phy_get_pause_adv(bp);
1705
1706 if (bp->autoneg & AUTONEG_SPEED) {
1707 speed_arg |= BNX2_NETLINK_SET_LINK_ENABLE_AUTONEG;
1708 if (bp->advertising & ADVERTISED_10baseT_Half)
1709 speed_arg |= BNX2_NETLINK_SET_LINK_SPEED_10HALF;
1710 if (bp->advertising & ADVERTISED_10baseT_Full)
1711 speed_arg |= BNX2_NETLINK_SET_LINK_SPEED_10FULL;
1712 if (bp->advertising & ADVERTISED_100baseT_Half)
1713 speed_arg |= BNX2_NETLINK_SET_LINK_SPEED_100HALF;
1714 if (bp->advertising & ADVERTISED_100baseT_Full)
1715 speed_arg |= BNX2_NETLINK_SET_LINK_SPEED_100FULL;
1716 if (bp->advertising & ADVERTISED_1000baseT_Full)
1717 speed_arg |= BNX2_NETLINK_SET_LINK_SPEED_1GFULL;
1718 if (bp->advertising & ADVERTISED_2500baseX_Full)
1719 speed_arg |= BNX2_NETLINK_SET_LINK_SPEED_2G5FULL;
1720 } else {
1721 if (bp->req_line_speed == SPEED_2500)
1722 speed_arg = BNX2_NETLINK_SET_LINK_SPEED_2G5FULL;
1723 else if (bp->req_line_speed == SPEED_1000)
1724 speed_arg = BNX2_NETLINK_SET_LINK_SPEED_1GFULL;
1725 else if (bp->req_line_speed == SPEED_100) {
1726 if (bp->req_duplex == DUPLEX_FULL)
1727 speed_arg = BNX2_NETLINK_SET_LINK_SPEED_100FULL;
1728 else
1729 speed_arg = BNX2_NETLINK_SET_LINK_SPEED_100HALF;
1730 } else if (bp->req_line_speed == SPEED_10) {
1731 if (bp->req_duplex == DUPLEX_FULL)
1732 speed_arg = BNX2_NETLINK_SET_LINK_SPEED_10FULL;
1733 else
1734 speed_arg = BNX2_NETLINK_SET_LINK_SPEED_10HALF;
1735 }
1736 }
1737
1738 if (pause_adv & (ADVERTISE_1000XPAUSE | ADVERTISE_PAUSE_CAP))
1739 speed_arg |= BNX2_NETLINK_SET_LINK_FC_SYM_PAUSE;
Michael Chanc26736e2008-01-31 17:07:21 -08001740 if (pause_adv & (ADVERTISE_1000XPSE_ASYM | ADVERTISE_PAUSE_ASYM))
Michael Chan0d8a6572007-07-07 22:49:43 -07001741 speed_arg |= BNX2_NETLINK_SET_LINK_FC_ASYM_PAUSE;
1742
1743 if (port == PORT_TP)
1744 speed_arg |= BNX2_NETLINK_SET_LINK_PHY_APP_REMOTE |
1745 BNX2_NETLINK_SET_LINK_ETH_AT_WIRESPEED;
1746
Michael Chan2726d6e2008-01-29 21:35:05 -08001747 bnx2_shmem_wr(bp, BNX2_DRV_MB_ARG0, speed_arg);
Michael Chan0d8a6572007-07-07 22:49:43 -07001748
1749 spin_unlock_bh(&bp->phy_lock);
Michael Chana2f13892008-07-14 22:38:23 -07001750 bnx2_fw_sync(bp, BNX2_DRV_MSG_CODE_CMD_SET_LINK, 1, 0);
Michael Chan0d8a6572007-07-07 22:49:43 -07001751 spin_lock_bh(&bp->phy_lock);
1752
1753 return 0;
1754}
1755
1756static int
1757bnx2_setup_serdes_phy(struct bnx2 *bp, u8 port)
Harvey Harrison52d07b12009-01-19 17:27:06 -08001758__releases(&bp->phy_lock)
1759__acquires(&bp->phy_lock)
Michael Chanb6016b72005-05-26 13:03:09 -07001760{
Michael Chan605a9e22007-05-03 13:23:13 -07001761 u32 adv, bmcr;
Michael Chanb6016b72005-05-26 13:03:09 -07001762 u32 new_adv = 0;
1763
Michael Chan583c28e2008-01-21 19:51:35 -08001764 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
Eric Dumazet807540b2010-09-23 05:40:09 +00001765 return bnx2_setup_remote_phy(bp, port);
Michael Chan0d8a6572007-07-07 22:49:43 -07001766
Michael Chanb6016b72005-05-26 13:03:09 -07001767 if (!(bp->autoneg & AUTONEG_SPEED)) {
1768 u32 new_bmcr;
Michael Chan5b0c76a2005-11-04 08:45:49 -08001769 int force_link_down = 0;
1770
Michael Chan605a9e22007-05-03 13:23:13 -07001771 if (bp->req_line_speed == SPEED_2500) {
1772 if (!bnx2_test_and_enable_2g5(bp))
1773 force_link_down = 1;
1774 } else if (bp->req_line_speed == SPEED_1000) {
1775 if (bnx2_test_and_disable_2g5(bp))
1776 force_link_down = 1;
1777 }
Michael Chanca58c3a2007-05-03 13:22:52 -07001778 bnx2_read_phy(bp, bp->mii_adv, &adv);
Michael Chan80be4432006-11-19 14:07:28 -08001779 adv &= ~(ADVERTISE_1000XFULL | ADVERTISE_1000XHALF);
1780
Michael Chanca58c3a2007-05-03 13:22:52 -07001781 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chan605a9e22007-05-03 13:23:13 -07001782 new_bmcr = bmcr & ~BMCR_ANENABLE;
Michael Chan80be4432006-11-19 14:07:28 -08001783 new_bmcr |= BMCR_SPEED1000;
Michael Chan605a9e22007-05-03 13:23:13 -07001784
Michael Chan4ce45e02012-12-06 10:33:10 +00001785 if (BNX2_CHIP(bp) == BNX2_CHIP_5709) {
Michael Chan27a005b2007-05-03 13:23:41 -07001786 if (bp->req_line_speed == SPEED_2500)
1787 bnx2_enable_forced_2g5(bp);
1788 else if (bp->req_line_speed == SPEED_1000) {
1789 bnx2_disable_forced_2g5(bp);
1790 new_bmcr &= ~0x2000;
1791 }
1792
Michael Chan4ce45e02012-12-06 10:33:10 +00001793 } else if (BNX2_CHIP(bp) == BNX2_CHIP_5708) {
Michael Chan605a9e22007-05-03 13:23:13 -07001794 if (bp->req_line_speed == SPEED_2500)
1795 new_bmcr |= BCM5708S_BMCR_FORCE_2500;
1796 else
1797 new_bmcr = bmcr & ~BCM5708S_BMCR_FORCE_2500;
Michael Chan5b0c76a2005-11-04 08:45:49 -08001798 }
1799
Michael Chanb6016b72005-05-26 13:03:09 -07001800 if (bp->req_duplex == DUPLEX_FULL) {
Michael Chan5b0c76a2005-11-04 08:45:49 -08001801 adv |= ADVERTISE_1000XFULL;
Michael Chanb6016b72005-05-26 13:03:09 -07001802 new_bmcr |= BMCR_FULLDPLX;
1803 }
1804 else {
Michael Chan5b0c76a2005-11-04 08:45:49 -08001805 adv |= ADVERTISE_1000XHALF;
Michael Chanb6016b72005-05-26 13:03:09 -07001806 new_bmcr &= ~BMCR_FULLDPLX;
1807 }
Michael Chan5b0c76a2005-11-04 08:45:49 -08001808 if ((new_bmcr != bmcr) || (force_link_down)) {
Michael Chanb6016b72005-05-26 13:03:09 -07001809 /* Force a link down visible on the other side */
1810 if (bp->link_up) {
Michael Chanca58c3a2007-05-03 13:22:52 -07001811 bnx2_write_phy(bp, bp->mii_adv, adv &
Michael Chan5b0c76a2005-11-04 08:45:49 -08001812 ~(ADVERTISE_1000XFULL |
1813 ADVERTISE_1000XHALF));
Michael Chanca58c3a2007-05-03 13:22:52 -07001814 bnx2_write_phy(bp, bp->mii_bmcr, bmcr |
Michael Chanb6016b72005-05-26 13:03:09 -07001815 BMCR_ANRESTART | BMCR_ANENABLE);
1816
1817 bp->link_up = 0;
1818 netif_carrier_off(bp->dev);
Michael Chanca58c3a2007-05-03 13:22:52 -07001819 bnx2_write_phy(bp, bp->mii_bmcr, new_bmcr);
Michael Chan80be4432006-11-19 14:07:28 -08001820 bnx2_report_link(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07001821 }
Michael Chanca58c3a2007-05-03 13:22:52 -07001822 bnx2_write_phy(bp, bp->mii_adv, adv);
1823 bnx2_write_phy(bp, bp->mii_bmcr, new_bmcr);
Michael Chan605a9e22007-05-03 13:23:13 -07001824 } else {
1825 bnx2_resolve_flow_ctrl(bp);
1826 bnx2_set_mac_link(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07001827 }
1828 return 0;
1829 }
1830
Michael Chan605a9e22007-05-03 13:23:13 -07001831 bnx2_test_and_enable_2g5(bp);
Michael Chan5b0c76a2005-11-04 08:45:49 -08001832
Michael Chanb6016b72005-05-26 13:03:09 -07001833 if (bp->advertising & ADVERTISED_1000baseT_Full)
1834 new_adv |= ADVERTISE_1000XFULL;
1835
1836 new_adv |= bnx2_phy_get_pause_adv(bp);
1837
Michael Chanca58c3a2007-05-03 13:22:52 -07001838 bnx2_read_phy(bp, bp->mii_adv, &adv);
1839 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chanb6016b72005-05-26 13:03:09 -07001840
1841 bp->serdes_an_pending = 0;
1842 if ((adv != new_adv) || ((bmcr & BMCR_ANENABLE) == 0)) {
1843 /* Force a link down visible on the other side */
1844 if (bp->link_up) {
Michael Chanca58c3a2007-05-03 13:22:52 -07001845 bnx2_write_phy(bp, bp->mii_bmcr, BMCR_LOOPBACK);
Michael Chan80be4432006-11-19 14:07:28 -08001846 spin_unlock_bh(&bp->phy_lock);
1847 msleep(20);
1848 spin_lock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07001849 }
1850
Michael Chanca58c3a2007-05-03 13:22:52 -07001851 bnx2_write_phy(bp, bp->mii_adv, new_adv);
1852 bnx2_write_phy(bp, bp->mii_bmcr, bmcr | BMCR_ANRESTART |
Michael Chanb6016b72005-05-26 13:03:09 -07001853 BMCR_ANENABLE);
Michael Chanf8dd0642006-11-19 14:08:29 -08001854 /* Speed up link-up time when the link partner
1855 * does not autonegotiate which is very common
1856 * in blade servers. Some blade servers use
1857 * IPMI for kerboard input and it's important
1858 * to minimize link disruptions. Autoneg. involves
1859 * exchanging base pages plus 3 next pages and
1860 * normally completes in about 120 msec.
1861 */
Michael Chan40105c02008-11-12 16:02:45 -08001862 bp->current_interval = BNX2_SERDES_AN_TIMEOUT;
Michael Chanf8dd0642006-11-19 14:08:29 -08001863 bp->serdes_an_pending = 1;
1864 mod_timer(&bp->timer, jiffies + bp->current_interval);
Michael Chan605a9e22007-05-03 13:23:13 -07001865 } else {
1866 bnx2_resolve_flow_ctrl(bp);
1867 bnx2_set_mac_link(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07001868 }
1869
1870 return 0;
1871}
1872
1873#define ETHTOOL_ALL_FIBRE_SPEED \
Michael Chan583c28e2008-01-21 19:51:35 -08001874 (bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE) ? \
Michael Chandeaf3912007-07-07 22:48:00 -07001875 (ADVERTISED_2500baseX_Full | ADVERTISED_1000baseT_Full) :\
1876 (ADVERTISED_1000baseT_Full)
Michael Chanb6016b72005-05-26 13:03:09 -07001877
1878#define ETHTOOL_ALL_COPPER_SPEED \
1879 (ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full | \
1880 ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full | \
1881 ADVERTISED_1000baseT_Full)
1882
1883#define PHY_ALL_10_100_SPEED (ADVERTISE_10HALF | ADVERTISE_10FULL | \
1884 ADVERTISE_100HALF | ADVERTISE_100FULL | ADVERTISE_CSMA)
Jeff Garzik6aa20a22006-09-13 13:24:59 -04001885
Michael Chanb6016b72005-05-26 13:03:09 -07001886#define PHY_ALL_1000_SPEED (ADVERTISE_1000HALF | ADVERTISE_1000FULL)
1887
Michael Chandeaf3912007-07-07 22:48:00 -07001888static void
Michael Chan0d8a6572007-07-07 22:49:43 -07001889bnx2_set_default_remote_link(struct bnx2 *bp)
1890{
1891 u32 link;
1892
1893 if (bp->phy_port == PORT_TP)
Michael Chan2726d6e2008-01-29 21:35:05 -08001894 link = bnx2_shmem_rd(bp, BNX2_RPHY_COPPER_LINK);
Michael Chan0d8a6572007-07-07 22:49:43 -07001895 else
Michael Chan2726d6e2008-01-29 21:35:05 -08001896 link = bnx2_shmem_rd(bp, BNX2_RPHY_SERDES_LINK);
Michael Chan0d8a6572007-07-07 22:49:43 -07001897
1898 if (link & BNX2_NETLINK_SET_LINK_ENABLE_AUTONEG) {
1899 bp->req_line_speed = 0;
1900 bp->autoneg |= AUTONEG_SPEED;
1901 bp->advertising = ADVERTISED_Autoneg;
1902 if (link & BNX2_NETLINK_SET_LINK_SPEED_10HALF)
1903 bp->advertising |= ADVERTISED_10baseT_Half;
1904 if (link & BNX2_NETLINK_SET_LINK_SPEED_10FULL)
1905 bp->advertising |= ADVERTISED_10baseT_Full;
1906 if (link & BNX2_NETLINK_SET_LINK_SPEED_100HALF)
1907 bp->advertising |= ADVERTISED_100baseT_Half;
1908 if (link & BNX2_NETLINK_SET_LINK_SPEED_100FULL)
1909 bp->advertising |= ADVERTISED_100baseT_Full;
1910 if (link & BNX2_NETLINK_SET_LINK_SPEED_1GFULL)
1911 bp->advertising |= ADVERTISED_1000baseT_Full;
1912 if (link & BNX2_NETLINK_SET_LINK_SPEED_2G5FULL)
1913 bp->advertising |= ADVERTISED_2500baseX_Full;
1914 } else {
1915 bp->autoneg = 0;
1916 bp->advertising = 0;
1917 bp->req_duplex = DUPLEX_FULL;
1918 if (link & BNX2_NETLINK_SET_LINK_SPEED_10) {
1919 bp->req_line_speed = SPEED_10;
1920 if (link & BNX2_NETLINK_SET_LINK_SPEED_10HALF)
1921 bp->req_duplex = DUPLEX_HALF;
1922 }
1923 if (link & BNX2_NETLINK_SET_LINK_SPEED_100) {
1924 bp->req_line_speed = SPEED_100;
1925 if (link & BNX2_NETLINK_SET_LINK_SPEED_100HALF)
1926 bp->req_duplex = DUPLEX_HALF;
1927 }
1928 if (link & BNX2_NETLINK_SET_LINK_SPEED_1GFULL)
1929 bp->req_line_speed = SPEED_1000;
1930 if (link & BNX2_NETLINK_SET_LINK_SPEED_2G5FULL)
1931 bp->req_line_speed = SPEED_2500;
1932 }
1933}
1934
1935static void
Michael Chandeaf3912007-07-07 22:48:00 -07001936bnx2_set_default_link(struct bnx2 *bp)
1937{
Harvey Harrisonab598592008-05-01 02:47:38 -07001938 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP) {
1939 bnx2_set_default_remote_link(bp);
1940 return;
1941 }
Michael Chan0d8a6572007-07-07 22:49:43 -07001942
Michael Chandeaf3912007-07-07 22:48:00 -07001943 bp->autoneg = AUTONEG_SPEED | AUTONEG_FLOW_CTRL;
1944 bp->req_line_speed = 0;
Michael Chan583c28e2008-01-21 19:51:35 -08001945 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Michael Chandeaf3912007-07-07 22:48:00 -07001946 u32 reg;
1947
1948 bp->advertising = ETHTOOL_ALL_FIBRE_SPEED | ADVERTISED_Autoneg;
1949
Michael Chan2726d6e2008-01-29 21:35:05 -08001950 reg = bnx2_shmem_rd(bp, BNX2_PORT_HW_CFG_CONFIG);
Michael Chandeaf3912007-07-07 22:48:00 -07001951 reg &= BNX2_PORT_HW_CFG_CFG_DFLT_LINK_MASK;
1952 if (reg == BNX2_PORT_HW_CFG_CFG_DFLT_LINK_1G) {
1953 bp->autoneg = 0;
1954 bp->req_line_speed = bp->line_speed = SPEED_1000;
1955 bp->req_duplex = DUPLEX_FULL;
1956 }
1957 } else
1958 bp->advertising = ETHTOOL_ALL_COPPER_SPEED | ADVERTISED_Autoneg;
1959}
1960
Michael Chan0d8a6572007-07-07 22:49:43 -07001961static void
Michael Chandf149d72007-07-07 22:51:36 -07001962bnx2_send_heart_beat(struct bnx2 *bp)
1963{
1964 u32 msg;
1965 u32 addr;
1966
1967 spin_lock(&bp->indirect_lock);
1968 msg = (u32) (++bp->fw_drv_pulse_wr_seq & BNX2_DRV_PULSE_SEQ_MASK);
1969 addr = bp->shmem_base + BNX2_DRV_PULSE_MB;
Michael Chane503e062012-12-06 10:33:08 +00001970 BNX2_WR(bp, BNX2_PCICFG_REG_WINDOW_ADDRESS, addr);
1971 BNX2_WR(bp, BNX2_PCICFG_REG_WINDOW, msg);
Michael Chandf149d72007-07-07 22:51:36 -07001972 spin_unlock(&bp->indirect_lock);
1973}
1974
1975static void
Michael Chan0d8a6572007-07-07 22:49:43 -07001976bnx2_remote_phy_event(struct bnx2 *bp)
1977{
1978 u32 msg;
1979 u8 link_up = bp->link_up;
1980 u8 old_port;
1981
Michael Chan2726d6e2008-01-29 21:35:05 -08001982 msg = bnx2_shmem_rd(bp, BNX2_LINK_STATUS);
Michael Chan0d8a6572007-07-07 22:49:43 -07001983
Michael Chandf149d72007-07-07 22:51:36 -07001984 if (msg & BNX2_LINK_STATUS_HEART_BEAT_EXPIRED)
1985 bnx2_send_heart_beat(bp);
1986
1987 msg &= ~BNX2_LINK_STATUS_HEART_BEAT_EXPIRED;
1988
Michael Chan0d8a6572007-07-07 22:49:43 -07001989 if ((msg & BNX2_LINK_STATUS_LINK_UP) == BNX2_LINK_STATUS_LINK_DOWN)
1990 bp->link_up = 0;
1991 else {
1992 u32 speed;
1993
1994 bp->link_up = 1;
1995 speed = msg & BNX2_LINK_STATUS_SPEED_MASK;
1996 bp->duplex = DUPLEX_FULL;
1997 switch (speed) {
1998 case BNX2_LINK_STATUS_10HALF:
1999 bp->duplex = DUPLEX_HALF;
Michael Chan7947c9c2012-06-27 15:08:23 +00002000 /* fall through */
Michael Chan0d8a6572007-07-07 22:49:43 -07002001 case BNX2_LINK_STATUS_10FULL:
2002 bp->line_speed = SPEED_10;
2003 break;
2004 case BNX2_LINK_STATUS_100HALF:
2005 bp->duplex = DUPLEX_HALF;
Michael Chan7947c9c2012-06-27 15:08:23 +00002006 /* fall through */
Michael Chan0d8a6572007-07-07 22:49:43 -07002007 case BNX2_LINK_STATUS_100BASE_T4:
2008 case BNX2_LINK_STATUS_100FULL:
2009 bp->line_speed = SPEED_100;
2010 break;
2011 case BNX2_LINK_STATUS_1000HALF:
2012 bp->duplex = DUPLEX_HALF;
Michael Chan7947c9c2012-06-27 15:08:23 +00002013 /* fall through */
Michael Chan0d8a6572007-07-07 22:49:43 -07002014 case BNX2_LINK_STATUS_1000FULL:
2015 bp->line_speed = SPEED_1000;
2016 break;
2017 case BNX2_LINK_STATUS_2500HALF:
2018 bp->duplex = DUPLEX_HALF;
Michael Chan7947c9c2012-06-27 15:08:23 +00002019 /* fall through */
Michael Chan0d8a6572007-07-07 22:49:43 -07002020 case BNX2_LINK_STATUS_2500FULL:
2021 bp->line_speed = SPEED_2500;
2022 break;
2023 default:
2024 bp->line_speed = 0;
2025 break;
2026 }
2027
Michael Chan0d8a6572007-07-07 22:49:43 -07002028 bp->flow_ctrl = 0;
2029 if ((bp->autoneg & (AUTONEG_SPEED | AUTONEG_FLOW_CTRL)) !=
2030 (AUTONEG_SPEED | AUTONEG_FLOW_CTRL)) {
2031 if (bp->duplex == DUPLEX_FULL)
2032 bp->flow_ctrl = bp->req_flow_ctrl;
2033 } else {
2034 if (msg & BNX2_LINK_STATUS_TX_FC_ENABLED)
2035 bp->flow_ctrl |= FLOW_CTRL_TX;
2036 if (msg & BNX2_LINK_STATUS_RX_FC_ENABLED)
2037 bp->flow_ctrl |= FLOW_CTRL_RX;
2038 }
2039
2040 old_port = bp->phy_port;
2041 if (msg & BNX2_LINK_STATUS_SERDES_LINK)
2042 bp->phy_port = PORT_FIBRE;
2043 else
2044 bp->phy_port = PORT_TP;
2045
2046 if (old_port != bp->phy_port)
2047 bnx2_set_default_link(bp);
2048
Michael Chan0d8a6572007-07-07 22:49:43 -07002049 }
2050 if (bp->link_up != link_up)
2051 bnx2_report_link(bp);
2052
2053 bnx2_set_mac_link(bp);
2054}
2055
2056static int
2057bnx2_set_remote_link(struct bnx2 *bp)
2058{
2059 u32 evt_code;
2060
Michael Chan2726d6e2008-01-29 21:35:05 -08002061 evt_code = bnx2_shmem_rd(bp, BNX2_FW_EVT_CODE_MB);
Michael Chan0d8a6572007-07-07 22:49:43 -07002062 switch (evt_code) {
2063 case BNX2_FW_EVT_CODE_LINK_EVENT:
2064 bnx2_remote_phy_event(bp);
2065 break;
2066 case BNX2_FW_EVT_CODE_SW_TIMER_EXPIRATION_EVENT:
2067 default:
Michael Chandf149d72007-07-07 22:51:36 -07002068 bnx2_send_heart_beat(bp);
Michael Chan0d8a6572007-07-07 22:49:43 -07002069 break;
2070 }
2071 return 0;
2072}
2073
Michael Chanb6016b72005-05-26 13:03:09 -07002074static int
2075bnx2_setup_copper_phy(struct bnx2 *bp)
Harvey Harrison52d07b12009-01-19 17:27:06 -08002076__releases(&bp->phy_lock)
2077__acquires(&bp->phy_lock)
Michael Chanb6016b72005-05-26 13:03:09 -07002078{
Michael Chand17e53b2013-12-31 23:22:32 -08002079 u32 bmcr, adv_reg, new_adv = 0;
Michael Chanb6016b72005-05-26 13:03:09 -07002080 u32 new_bmcr;
2081
Michael Chanca58c3a2007-05-03 13:22:52 -07002082 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chanb6016b72005-05-26 13:03:09 -07002083
Michael Chand17e53b2013-12-31 23:22:32 -08002084 bnx2_read_phy(bp, bp->mii_adv, &adv_reg);
2085 adv_reg &= (PHY_ALL_10_100_SPEED | ADVERTISE_PAUSE_CAP |
2086 ADVERTISE_PAUSE_ASYM);
2087
2088 new_adv = ADVERTISE_CSMA | ethtool_adv_to_mii_adv_t(bp->advertising);
2089
Michael Chanb6016b72005-05-26 13:03:09 -07002090 if (bp->autoneg & AUTONEG_SPEED) {
Michael Chand17e53b2013-12-31 23:22:32 -08002091 u32 adv1000_reg;
Matt Carlson37f07022011-11-17 14:30:55 +00002092 u32 new_adv1000 = 0;
Michael Chanb6016b72005-05-26 13:03:09 -07002093
Michael Chand17e53b2013-12-31 23:22:32 -08002094 new_adv |= bnx2_phy_get_pause_adv(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07002095
2096 bnx2_read_phy(bp, MII_CTRL1000, &adv1000_reg);
2097 adv1000_reg &= PHY_ALL_1000_SPEED;
2098
Matt Carlson37f07022011-11-17 14:30:55 +00002099 new_adv1000 |= ethtool_adv_to_mii_ctrl1000_t(bp->advertising);
Matt Carlson37f07022011-11-17 14:30:55 +00002100 if ((adv1000_reg != new_adv1000) ||
2101 (adv_reg != new_adv) ||
Michael Chanb6016b72005-05-26 13:03:09 -07002102 ((bmcr & BMCR_ANENABLE) == 0)) {
2103
Matt Carlson37f07022011-11-17 14:30:55 +00002104 bnx2_write_phy(bp, bp->mii_adv, new_adv);
2105 bnx2_write_phy(bp, MII_CTRL1000, new_adv1000);
Michael Chanca58c3a2007-05-03 13:22:52 -07002106 bnx2_write_phy(bp, bp->mii_bmcr, BMCR_ANRESTART |
Michael Chanb6016b72005-05-26 13:03:09 -07002107 BMCR_ANENABLE);
2108 }
2109 else if (bp->link_up) {
2110 /* Flow ctrl may have changed from auto to forced */
2111 /* or vice-versa. */
2112
2113 bnx2_resolve_flow_ctrl(bp);
2114 bnx2_set_mac_link(bp);
2115 }
2116 return 0;
2117 }
2118
Michael Chand17e53b2013-12-31 23:22:32 -08002119 /* advertise nothing when forcing speed */
2120 if (adv_reg != new_adv)
2121 bnx2_write_phy(bp, bp->mii_adv, new_adv);
2122
Michael Chanb6016b72005-05-26 13:03:09 -07002123 new_bmcr = 0;
2124 if (bp->req_line_speed == SPEED_100) {
2125 new_bmcr |= BMCR_SPEED100;
2126 }
2127 if (bp->req_duplex == DUPLEX_FULL) {
2128 new_bmcr |= BMCR_FULLDPLX;
2129 }
2130 if (new_bmcr != bmcr) {
2131 u32 bmsr;
Michael Chanb6016b72005-05-26 13:03:09 -07002132
Michael Chanca58c3a2007-05-03 13:22:52 -07002133 bnx2_read_phy(bp, bp->mii_bmsr, &bmsr);
2134 bnx2_read_phy(bp, bp->mii_bmsr, &bmsr);
Jeff Garzik6aa20a22006-09-13 13:24:59 -04002135
Michael Chanb6016b72005-05-26 13:03:09 -07002136 if (bmsr & BMSR_LSTATUS) {
2137 /* Force link down */
Michael Chanca58c3a2007-05-03 13:22:52 -07002138 bnx2_write_phy(bp, bp->mii_bmcr, BMCR_LOOPBACK);
Michael Chana16dda02006-11-19 14:08:56 -08002139 spin_unlock_bh(&bp->phy_lock);
2140 msleep(50);
2141 spin_lock_bh(&bp->phy_lock);
2142
Michael Chanca58c3a2007-05-03 13:22:52 -07002143 bnx2_read_phy(bp, bp->mii_bmsr, &bmsr);
2144 bnx2_read_phy(bp, bp->mii_bmsr, &bmsr);
Michael Chanb6016b72005-05-26 13:03:09 -07002145 }
2146
Michael Chanca58c3a2007-05-03 13:22:52 -07002147 bnx2_write_phy(bp, bp->mii_bmcr, new_bmcr);
Michael Chanb6016b72005-05-26 13:03:09 -07002148
2149 /* Normally, the new speed is setup after the link has
2150 * gone down and up again. In some cases, link will not go
2151 * down so we need to set up the new speed here.
2152 */
2153 if (bmsr & BMSR_LSTATUS) {
2154 bp->line_speed = bp->req_line_speed;
2155 bp->duplex = bp->req_duplex;
2156 bnx2_resolve_flow_ctrl(bp);
2157 bnx2_set_mac_link(bp);
2158 }
Michael Chan27a005b2007-05-03 13:23:41 -07002159 } else {
2160 bnx2_resolve_flow_ctrl(bp);
2161 bnx2_set_mac_link(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07002162 }
2163 return 0;
2164}
2165
2166static int
Michael Chan0d8a6572007-07-07 22:49:43 -07002167bnx2_setup_phy(struct bnx2 *bp, u8 port)
Harvey Harrison52d07b12009-01-19 17:27:06 -08002168__releases(&bp->phy_lock)
2169__acquires(&bp->phy_lock)
Michael Chanb6016b72005-05-26 13:03:09 -07002170{
2171 if (bp->loopback == MAC_LOOPBACK)
2172 return 0;
2173
Michael Chan583c28e2008-01-21 19:51:35 -08002174 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Eric Dumazet807540b2010-09-23 05:40:09 +00002175 return bnx2_setup_serdes_phy(bp, port);
Michael Chanb6016b72005-05-26 13:03:09 -07002176 }
2177 else {
Eric Dumazet807540b2010-09-23 05:40:09 +00002178 return bnx2_setup_copper_phy(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07002179 }
2180}
2181
2182static int
Michael Chan9a120bc2008-05-16 22:17:45 -07002183bnx2_init_5709s_phy(struct bnx2 *bp, int reset_phy)
Michael Chan27a005b2007-05-03 13:23:41 -07002184{
2185 u32 val;
2186
2187 bp->mii_bmcr = MII_BMCR + 0x10;
2188 bp->mii_bmsr = MII_BMSR + 0x10;
2189 bp->mii_bmsr1 = MII_BNX2_GP_TOP_AN_STATUS1;
2190 bp->mii_adv = MII_ADVERTISE + 0x10;
2191 bp->mii_lpa = MII_LPA + 0x10;
2192 bp->mii_up1 = MII_BNX2_OVER1G_UP1;
2193
2194 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_AER);
2195 bnx2_write_phy(bp, MII_BNX2_AER_AER, MII_BNX2_AER_AER_AN_MMD);
2196
2197 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
Michael Chan9a120bc2008-05-16 22:17:45 -07002198 if (reset_phy)
2199 bnx2_reset_phy(bp);
Michael Chan27a005b2007-05-03 13:23:41 -07002200
2201 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_SERDES_DIG);
2202
2203 bnx2_read_phy(bp, MII_BNX2_SERDES_DIG_1000XCTL1, &val);
2204 val &= ~MII_BNX2_SD_1000XCTL1_AUTODET;
2205 val |= MII_BNX2_SD_1000XCTL1_FIBER;
2206 bnx2_write_phy(bp, MII_BNX2_SERDES_DIG_1000XCTL1, val);
2207
2208 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_OVER1G);
2209 bnx2_read_phy(bp, MII_BNX2_OVER1G_UP1, &val);
Michael Chan583c28e2008-01-21 19:51:35 -08002210 if (bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE)
Michael Chan27a005b2007-05-03 13:23:41 -07002211 val |= BCM5708S_UP1_2G5;
2212 else
2213 val &= ~BCM5708S_UP1_2G5;
2214 bnx2_write_phy(bp, MII_BNX2_OVER1G_UP1, val);
2215
2216 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_BAM_NXTPG);
2217 bnx2_read_phy(bp, MII_BNX2_BAM_NXTPG_CTL, &val);
2218 val |= MII_BNX2_NXTPG_CTL_T2 | MII_BNX2_NXTPG_CTL_BAM;
2219 bnx2_write_phy(bp, MII_BNX2_BAM_NXTPG_CTL, val);
2220
2221 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_CL73_USERB0);
2222
2223 val = MII_BNX2_CL73_BAM_EN | MII_BNX2_CL73_BAM_STA_MGR_EN |
2224 MII_BNX2_CL73_BAM_NP_AFT_BP_EN;
2225 bnx2_write_phy(bp, MII_BNX2_CL73_BAM_CTL1, val);
2226
2227 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
2228
2229 return 0;
2230}
2231
2232static int
Michael Chan9a120bc2008-05-16 22:17:45 -07002233bnx2_init_5708s_phy(struct bnx2 *bp, int reset_phy)
Michael Chan5b0c76a2005-11-04 08:45:49 -08002234{
2235 u32 val;
2236
Michael Chan9a120bc2008-05-16 22:17:45 -07002237 if (reset_phy)
2238 bnx2_reset_phy(bp);
Michael Chan27a005b2007-05-03 13:23:41 -07002239
2240 bp->mii_up1 = BCM5708S_UP1;
2241
Michael Chan5b0c76a2005-11-04 08:45:49 -08002242 bnx2_write_phy(bp, BCM5708S_BLK_ADDR, BCM5708S_BLK_ADDR_DIG3);
2243 bnx2_write_phy(bp, BCM5708S_DIG_3_0, BCM5708S_DIG_3_0_USE_IEEE);
2244 bnx2_write_phy(bp, BCM5708S_BLK_ADDR, BCM5708S_BLK_ADDR_DIG);
2245
2246 bnx2_read_phy(bp, BCM5708S_1000X_CTL1, &val);
2247 val |= BCM5708S_1000X_CTL1_FIBER_MODE | BCM5708S_1000X_CTL1_AUTODET_EN;
2248 bnx2_write_phy(bp, BCM5708S_1000X_CTL1, val);
2249
2250 bnx2_read_phy(bp, BCM5708S_1000X_CTL2, &val);
2251 val |= BCM5708S_1000X_CTL2_PLLEL_DET_EN;
2252 bnx2_write_phy(bp, BCM5708S_1000X_CTL2, val);
2253
Michael Chan583c28e2008-01-21 19:51:35 -08002254 if (bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE) {
Michael Chan5b0c76a2005-11-04 08:45:49 -08002255 bnx2_read_phy(bp, BCM5708S_UP1, &val);
2256 val |= BCM5708S_UP1_2G5;
2257 bnx2_write_phy(bp, BCM5708S_UP1, val);
2258 }
2259
Michael Chan4ce45e02012-12-06 10:33:10 +00002260 if ((BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5708_A0) ||
2261 (BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5708_B0) ||
2262 (BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5708_B1)) {
Michael Chan5b0c76a2005-11-04 08:45:49 -08002263 /* increase tx signal amplitude */
2264 bnx2_write_phy(bp, BCM5708S_BLK_ADDR,
2265 BCM5708S_BLK_ADDR_TX_MISC);
2266 bnx2_read_phy(bp, BCM5708S_TX_ACTL1, &val);
2267 val &= ~BCM5708S_TX_ACTL1_DRIVER_VCM;
2268 bnx2_write_phy(bp, BCM5708S_TX_ACTL1, val);
2269 bnx2_write_phy(bp, BCM5708S_BLK_ADDR, BCM5708S_BLK_ADDR_DIG);
2270 }
2271
Michael Chan2726d6e2008-01-29 21:35:05 -08002272 val = bnx2_shmem_rd(bp, BNX2_PORT_HW_CFG_CONFIG) &
Michael Chan5b0c76a2005-11-04 08:45:49 -08002273 BNX2_PORT_HW_CFG_CFG_TXCTL3_MASK;
2274
2275 if (val) {
2276 u32 is_backplane;
2277
Michael Chan2726d6e2008-01-29 21:35:05 -08002278 is_backplane = bnx2_shmem_rd(bp, BNX2_SHARED_HW_CFG_CONFIG);
Michael Chan5b0c76a2005-11-04 08:45:49 -08002279 if (is_backplane & BNX2_SHARED_HW_CFG_PHY_BACKPLANE) {
2280 bnx2_write_phy(bp, BCM5708S_BLK_ADDR,
2281 BCM5708S_BLK_ADDR_TX_MISC);
2282 bnx2_write_phy(bp, BCM5708S_TX_ACTL3, val);
2283 bnx2_write_phy(bp, BCM5708S_BLK_ADDR,
2284 BCM5708S_BLK_ADDR_DIG);
2285 }
2286 }
2287 return 0;
2288}
2289
2290static int
Michael Chan9a120bc2008-05-16 22:17:45 -07002291bnx2_init_5706s_phy(struct bnx2 *bp, int reset_phy)
Michael Chanb6016b72005-05-26 13:03:09 -07002292{
Michael Chan9a120bc2008-05-16 22:17:45 -07002293 if (reset_phy)
2294 bnx2_reset_phy(bp);
Michael Chan27a005b2007-05-03 13:23:41 -07002295
Michael Chan583c28e2008-01-21 19:51:35 -08002296 bp->phy_flags &= ~BNX2_PHY_FLAG_PARALLEL_DETECT;
Michael Chanb6016b72005-05-26 13:03:09 -07002297
Michael Chan4ce45e02012-12-06 10:33:10 +00002298 if (BNX2_CHIP(bp) == BNX2_CHIP_5706)
Michael Chane503e062012-12-06 10:33:08 +00002299 BNX2_WR(bp, BNX2_MISC_GP_HW_CTL0, 0x300);
Michael Chanb6016b72005-05-26 13:03:09 -07002300
2301 if (bp->dev->mtu > 1500) {
2302 u32 val;
2303
2304 /* Set extended packet length bit */
2305 bnx2_write_phy(bp, 0x18, 0x7);
2306 bnx2_read_phy(bp, 0x18, &val);
2307 bnx2_write_phy(bp, 0x18, (val & 0xfff8) | 0x4000);
2308
2309 bnx2_write_phy(bp, 0x1c, 0x6c00);
2310 bnx2_read_phy(bp, 0x1c, &val);
2311 bnx2_write_phy(bp, 0x1c, (val & 0x3ff) | 0xec02);
2312 }
2313 else {
2314 u32 val;
2315
2316 bnx2_write_phy(bp, 0x18, 0x7);
2317 bnx2_read_phy(bp, 0x18, &val);
2318 bnx2_write_phy(bp, 0x18, val & ~0x4007);
2319
2320 bnx2_write_phy(bp, 0x1c, 0x6c00);
2321 bnx2_read_phy(bp, 0x1c, &val);
2322 bnx2_write_phy(bp, 0x1c, (val & 0x3fd) | 0xec00);
2323 }
2324
2325 return 0;
2326}
2327
2328static int
Michael Chan9a120bc2008-05-16 22:17:45 -07002329bnx2_init_copper_phy(struct bnx2 *bp, int reset_phy)
Michael Chanb6016b72005-05-26 13:03:09 -07002330{
Michael Chan5b0c76a2005-11-04 08:45:49 -08002331 u32 val;
2332
Michael Chan9a120bc2008-05-16 22:17:45 -07002333 if (reset_phy)
2334 bnx2_reset_phy(bp);
Michael Chan27a005b2007-05-03 13:23:41 -07002335
Michael Chan583c28e2008-01-21 19:51:35 -08002336 if (bp->phy_flags & BNX2_PHY_FLAG_CRC_FIX) {
Michael Chanb6016b72005-05-26 13:03:09 -07002337 bnx2_write_phy(bp, 0x18, 0x0c00);
2338 bnx2_write_phy(bp, 0x17, 0x000a);
2339 bnx2_write_phy(bp, 0x15, 0x310b);
2340 bnx2_write_phy(bp, 0x17, 0x201f);
2341 bnx2_write_phy(bp, 0x15, 0x9506);
2342 bnx2_write_phy(bp, 0x17, 0x401f);
2343 bnx2_write_phy(bp, 0x15, 0x14e2);
2344 bnx2_write_phy(bp, 0x18, 0x0400);
2345 }
2346
Michael Chan583c28e2008-01-21 19:51:35 -08002347 if (bp->phy_flags & BNX2_PHY_FLAG_DIS_EARLY_DAC) {
Michael Chanb659f442007-02-02 00:46:35 -08002348 bnx2_write_phy(bp, MII_BNX2_DSP_ADDRESS,
2349 MII_BNX2_DSP_EXPAND_REG | 0x8);
2350 bnx2_read_phy(bp, MII_BNX2_DSP_RW_PORT, &val);
2351 val &= ~(1 << 8);
2352 bnx2_write_phy(bp, MII_BNX2_DSP_RW_PORT, val);
2353 }
2354
Michael Chanb6016b72005-05-26 13:03:09 -07002355 if (bp->dev->mtu > 1500) {
Michael Chanb6016b72005-05-26 13:03:09 -07002356 /* Set extended packet length bit */
2357 bnx2_write_phy(bp, 0x18, 0x7);
2358 bnx2_read_phy(bp, 0x18, &val);
2359 bnx2_write_phy(bp, 0x18, val | 0x4000);
2360
2361 bnx2_read_phy(bp, 0x10, &val);
2362 bnx2_write_phy(bp, 0x10, val | 0x1);
2363 }
2364 else {
Michael Chanb6016b72005-05-26 13:03:09 -07002365 bnx2_write_phy(bp, 0x18, 0x7);
2366 bnx2_read_phy(bp, 0x18, &val);
2367 bnx2_write_phy(bp, 0x18, val & ~0x4007);
2368
2369 bnx2_read_phy(bp, 0x10, &val);
2370 bnx2_write_phy(bp, 0x10, val & ~0x1);
2371 }
2372
Michael Chan5b0c76a2005-11-04 08:45:49 -08002373 /* ethernet@wirespeed */
Michael Chan41033b62013-12-31 23:22:33 -08002374 bnx2_write_phy(bp, MII_BNX2_AUX_CTL, AUX_CTL_MISC_CTL);
2375 bnx2_read_phy(bp, MII_BNX2_AUX_CTL, &val);
2376 val |= AUX_CTL_MISC_CTL_WR | AUX_CTL_MISC_CTL_WIRESPEED;
2377
2378 /* auto-mdix */
2379 if (BNX2_CHIP(bp) == BNX2_CHIP_5709)
2380 val |= AUX_CTL_MISC_CTL_AUTOMDIX;
2381
2382 bnx2_write_phy(bp, MII_BNX2_AUX_CTL, val);
Michael Chanb6016b72005-05-26 13:03:09 -07002383 return 0;
2384}
2385
2386
2387static int
Michael Chan9a120bc2008-05-16 22:17:45 -07002388bnx2_init_phy(struct bnx2 *bp, int reset_phy)
Harvey Harrison52d07b12009-01-19 17:27:06 -08002389__releases(&bp->phy_lock)
2390__acquires(&bp->phy_lock)
Michael Chanb6016b72005-05-26 13:03:09 -07002391{
2392 u32 val;
2393 int rc = 0;
2394
Michael Chan583c28e2008-01-21 19:51:35 -08002395 bp->phy_flags &= ~BNX2_PHY_FLAG_INT_MODE_MASK;
2396 bp->phy_flags |= BNX2_PHY_FLAG_INT_MODE_LINK_READY;
Michael Chanb6016b72005-05-26 13:03:09 -07002397
Michael Chanca58c3a2007-05-03 13:22:52 -07002398 bp->mii_bmcr = MII_BMCR;
2399 bp->mii_bmsr = MII_BMSR;
Michael Chan27a005b2007-05-03 13:23:41 -07002400 bp->mii_bmsr1 = MII_BMSR;
Michael Chanca58c3a2007-05-03 13:22:52 -07002401 bp->mii_adv = MII_ADVERTISE;
2402 bp->mii_lpa = MII_LPA;
2403
Michael Chane503e062012-12-06 10:33:08 +00002404 BNX2_WR(bp, BNX2_EMAC_ATTENTION_ENA, BNX2_EMAC_ATTENTION_ENA_LINK);
Michael Chanb6016b72005-05-26 13:03:09 -07002405
Michael Chan583c28e2008-01-21 19:51:35 -08002406 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
Michael Chan0d8a6572007-07-07 22:49:43 -07002407 goto setup_phy;
2408
Michael Chanb6016b72005-05-26 13:03:09 -07002409 bnx2_read_phy(bp, MII_PHYSID1, &val);
2410 bp->phy_id = val << 16;
2411 bnx2_read_phy(bp, MII_PHYSID2, &val);
2412 bp->phy_id |= val & 0xffff;
2413
Michael Chan583c28e2008-01-21 19:51:35 -08002414 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Michael Chan4ce45e02012-12-06 10:33:10 +00002415 if (BNX2_CHIP(bp) == BNX2_CHIP_5706)
Michael Chan9a120bc2008-05-16 22:17:45 -07002416 rc = bnx2_init_5706s_phy(bp, reset_phy);
Michael Chan4ce45e02012-12-06 10:33:10 +00002417 else if (BNX2_CHIP(bp) == BNX2_CHIP_5708)
Michael Chan9a120bc2008-05-16 22:17:45 -07002418 rc = bnx2_init_5708s_phy(bp, reset_phy);
Michael Chan4ce45e02012-12-06 10:33:10 +00002419 else if (BNX2_CHIP(bp) == BNX2_CHIP_5709)
Michael Chan9a120bc2008-05-16 22:17:45 -07002420 rc = bnx2_init_5709s_phy(bp, reset_phy);
Michael Chanb6016b72005-05-26 13:03:09 -07002421 }
2422 else {
Michael Chan9a120bc2008-05-16 22:17:45 -07002423 rc = bnx2_init_copper_phy(bp, reset_phy);
Michael Chanb6016b72005-05-26 13:03:09 -07002424 }
2425
Michael Chan0d8a6572007-07-07 22:49:43 -07002426setup_phy:
2427 if (!rc)
2428 rc = bnx2_setup_phy(bp, bp->phy_port);
Michael Chanb6016b72005-05-26 13:03:09 -07002429
2430 return rc;
2431}
2432
2433static int
2434bnx2_set_mac_loopback(struct bnx2 *bp)
2435{
2436 u32 mac_mode;
2437
Michael Chane503e062012-12-06 10:33:08 +00002438 mac_mode = BNX2_RD(bp, BNX2_EMAC_MODE);
Michael Chanb6016b72005-05-26 13:03:09 -07002439 mac_mode &= ~BNX2_EMAC_MODE_PORT;
2440 mac_mode |= BNX2_EMAC_MODE_MAC_LOOP | BNX2_EMAC_MODE_FORCE_LINK;
Michael Chane503e062012-12-06 10:33:08 +00002441 BNX2_WR(bp, BNX2_EMAC_MODE, mac_mode);
Michael Chanb6016b72005-05-26 13:03:09 -07002442 bp->link_up = 1;
2443 return 0;
2444}
2445
Michael Chanbc5a0692006-01-23 16:13:22 -08002446static int bnx2_test_link(struct bnx2 *);
2447
2448static int
2449bnx2_set_phy_loopback(struct bnx2 *bp)
2450{
2451 u32 mac_mode;
2452 int rc, i;
2453
2454 spin_lock_bh(&bp->phy_lock);
Michael Chanca58c3a2007-05-03 13:22:52 -07002455 rc = bnx2_write_phy(bp, bp->mii_bmcr, BMCR_LOOPBACK | BMCR_FULLDPLX |
Michael Chanbc5a0692006-01-23 16:13:22 -08002456 BMCR_SPEED1000);
2457 spin_unlock_bh(&bp->phy_lock);
2458 if (rc)
2459 return rc;
2460
2461 for (i = 0; i < 10; i++) {
2462 if (bnx2_test_link(bp) == 0)
2463 break;
Michael Chan80be4432006-11-19 14:07:28 -08002464 msleep(100);
Michael Chanbc5a0692006-01-23 16:13:22 -08002465 }
2466
Michael Chane503e062012-12-06 10:33:08 +00002467 mac_mode = BNX2_RD(bp, BNX2_EMAC_MODE);
Michael Chanbc5a0692006-01-23 16:13:22 -08002468 mac_mode &= ~(BNX2_EMAC_MODE_PORT | BNX2_EMAC_MODE_HALF_DUPLEX |
2469 BNX2_EMAC_MODE_MAC_LOOP | BNX2_EMAC_MODE_FORCE_LINK |
Michael Chan59b47d82006-11-19 14:10:45 -08002470 BNX2_EMAC_MODE_25G_MODE);
Michael Chanbc5a0692006-01-23 16:13:22 -08002471
2472 mac_mode |= BNX2_EMAC_MODE_PORT_GMII;
Michael Chane503e062012-12-06 10:33:08 +00002473 BNX2_WR(bp, BNX2_EMAC_MODE, mac_mode);
Michael Chanbc5a0692006-01-23 16:13:22 -08002474 bp->link_up = 1;
2475 return 0;
2476}
2477
Jeffrey Huangecdbf6e2011-07-13 17:24:21 +00002478static void
2479bnx2_dump_mcp_state(struct bnx2 *bp)
2480{
2481 struct net_device *dev = bp->dev;
2482 u32 mcp_p0, mcp_p1;
2483
2484 netdev_err(dev, "<--- start MCP states dump --->\n");
Michael Chan4ce45e02012-12-06 10:33:10 +00002485 if (BNX2_CHIP(bp) == BNX2_CHIP_5709) {
Jeffrey Huangecdbf6e2011-07-13 17:24:21 +00002486 mcp_p0 = BNX2_MCP_STATE_P0;
2487 mcp_p1 = BNX2_MCP_STATE_P1;
2488 } else {
2489 mcp_p0 = BNX2_MCP_STATE_P0_5708;
2490 mcp_p1 = BNX2_MCP_STATE_P1_5708;
2491 }
2492 netdev_err(dev, "DEBUG: MCP_STATE_P0[%08x] MCP_STATE_P1[%08x]\n",
2493 bnx2_reg_rd_ind(bp, mcp_p0), bnx2_reg_rd_ind(bp, mcp_p1));
2494 netdev_err(dev, "DEBUG: MCP mode[%08x] state[%08x] evt_mask[%08x]\n",
2495 bnx2_reg_rd_ind(bp, BNX2_MCP_CPU_MODE),
2496 bnx2_reg_rd_ind(bp, BNX2_MCP_CPU_STATE),
2497 bnx2_reg_rd_ind(bp, BNX2_MCP_CPU_EVENT_MASK));
2498 netdev_err(dev, "DEBUG: pc[%08x] pc[%08x] instr[%08x]\n",
2499 bnx2_reg_rd_ind(bp, BNX2_MCP_CPU_PROGRAM_COUNTER),
2500 bnx2_reg_rd_ind(bp, BNX2_MCP_CPU_PROGRAM_COUNTER),
2501 bnx2_reg_rd_ind(bp, BNX2_MCP_CPU_INSTRUCTION));
2502 netdev_err(dev, "DEBUG: shmem states:\n");
2503 netdev_err(dev, "DEBUG: drv_mb[%08x] fw_mb[%08x] link_status[%08x]",
2504 bnx2_shmem_rd(bp, BNX2_DRV_MB),
2505 bnx2_shmem_rd(bp, BNX2_FW_MB),
2506 bnx2_shmem_rd(bp, BNX2_LINK_STATUS));
2507 pr_cont(" drv_pulse_mb[%08x]\n", bnx2_shmem_rd(bp, BNX2_DRV_PULSE_MB));
2508 netdev_err(dev, "DEBUG: dev_info_signature[%08x] reset_type[%08x]",
2509 bnx2_shmem_rd(bp, BNX2_DEV_INFO_SIGNATURE),
2510 bnx2_shmem_rd(bp, BNX2_BC_STATE_RESET_TYPE));
2511 pr_cont(" condition[%08x]\n",
2512 bnx2_shmem_rd(bp, BNX2_BC_STATE_CONDITION));
Michael Chan13e63512012-06-16 15:45:42 +00002513 DP_SHMEM_LINE(bp, BNX2_BC_RESET_TYPE);
Jeffrey Huangecdbf6e2011-07-13 17:24:21 +00002514 DP_SHMEM_LINE(bp, 0x3cc);
2515 DP_SHMEM_LINE(bp, 0x3dc);
2516 DP_SHMEM_LINE(bp, 0x3ec);
2517 netdev_err(dev, "DEBUG: 0x3fc[%08x]\n", bnx2_shmem_rd(bp, 0x3fc));
2518 netdev_err(dev, "<--- end MCP states dump --->\n");
2519}
2520
Michael Chanb6016b72005-05-26 13:03:09 -07002521static int
Michael Chana2f13892008-07-14 22:38:23 -07002522bnx2_fw_sync(struct bnx2 *bp, u32 msg_data, int ack, int silent)
Michael Chanb6016b72005-05-26 13:03:09 -07002523{
2524 int i;
2525 u32 val;
2526
Michael Chanb6016b72005-05-26 13:03:09 -07002527 bp->fw_wr_seq++;
2528 msg_data |= bp->fw_wr_seq;
Michael Chana8d9bc22014-03-09 15:45:32 -08002529 bp->fw_last_msg = msg_data;
Michael Chanb6016b72005-05-26 13:03:09 -07002530
Michael Chan2726d6e2008-01-29 21:35:05 -08002531 bnx2_shmem_wr(bp, BNX2_DRV_MB, msg_data);
Michael Chanb6016b72005-05-26 13:03:09 -07002532
Michael Chana2f13892008-07-14 22:38:23 -07002533 if (!ack)
2534 return 0;
2535
Michael Chanb6016b72005-05-26 13:03:09 -07002536 /* wait for an acknowledgement. */
Michael Chan40105c02008-11-12 16:02:45 -08002537 for (i = 0; i < (BNX2_FW_ACK_TIME_OUT_MS / 10); i++) {
Michael Chanb090ae22006-01-23 16:07:10 -08002538 msleep(10);
Michael Chanb6016b72005-05-26 13:03:09 -07002539
Michael Chan2726d6e2008-01-29 21:35:05 -08002540 val = bnx2_shmem_rd(bp, BNX2_FW_MB);
Michael Chanb6016b72005-05-26 13:03:09 -07002541
2542 if ((val & BNX2_FW_MSG_ACK) == (msg_data & BNX2_DRV_MSG_SEQ))
2543 break;
2544 }
Michael Chanb090ae22006-01-23 16:07:10 -08002545 if ((msg_data & BNX2_DRV_MSG_DATA) == BNX2_DRV_MSG_DATA_WAIT0)
2546 return 0;
Michael Chanb6016b72005-05-26 13:03:09 -07002547
2548 /* If we timed out, inform the firmware that this is the case. */
Michael Chanb090ae22006-01-23 16:07:10 -08002549 if ((val & BNX2_FW_MSG_ACK) != (msg_data & BNX2_DRV_MSG_SEQ)) {
Michael Chanb6016b72005-05-26 13:03:09 -07002550 msg_data &= ~BNX2_DRV_MSG_CODE;
2551 msg_data |= BNX2_DRV_MSG_CODE_FW_TIMEOUT;
2552
Michael Chan2726d6e2008-01-29 21:35:05 -08002553 bnx2_shmem_wr(bp, BNX2_DRV_MB, msg_data);
Jeffrey Huangecdbf6e2011-07-13 17:24:21 +00002554 if (!silent) {
2555 pr_err("fw sync timeout, reset code = %x\n", msg_data);
2556 bnx2_dump_mcp_state(bp);
2557 }
Michael Chanb6016b72005-05-26 13:03:09 -07002558
Michael Chanb6016b72005-05-26 13:03:09 -07002559 return -EBUSY;
2560 }
2561
Michael Chanb090ae22006-01-23 16:07:10 -08002562 if ((val & BNX2_FW_MSG_STATUS_MASK) != BNX2_FW_MSG_STATUS_OK)
2563 return -EIO;
2564
Michael Chanb6016b72005-05-26 13:03:09 -07002565 return 0;
2566}
2567
Michael Chan59b47d82006-11-19 14:10:45 -08002568static int
2569bnx2_init_5709_context(struct bnx2 *bp)
2570{
2571 int i, ret = 0;
2572 u32 val;
2573
2574 val = BNX2_CTX_COMMAND_ENABLED | BNX2_CTX_COMMAND_MEM_INIT | (1 << 12);
Michael Chan2bc40782012-12-06 10:33:09 +00002575 val |= (BNX2_PAGE_BITS - 8) << 16;
Michael Chane503e062012-12-06 10:33:08 +00002576 BNX2_WR(bp, BNX2_CTX_COMMAND, val);
Michael Chan641bdcd2007-06-04 21:22:24 -07002577 for (i = 0; i < 10; i++) {
Michael Chane503e062012-12-06 10:33:08 +00002578 val = BNX2_RD(bp, BNX2_CTX_COMMAND);
Michael Chan641bdcd2007-06-04 21:22:24 -07002579 if (!(val & BNX2_CTX_COMMAND_MEM_INIT))
2580 break;
2581 udelay(2);
2582 }
2583 if (val & BNX2_CTX_COMMAND_MEM_INIT)
2584 return -EBUSY;
2585
Michael Chan59b47d82006-11-19 14:10:45 -08002586 for (i = 0; i < bp->ctx_pages; i++) {
2587 int j;
2588
Michael Chan352f7682008-05-02 16:57:26 -07002589 if (bp->ctx_blk[i])
Michael Chan2bc40782012-12-06 10:33:09 +00002590 memset(bp->ctx_blk[i], 0, BNX2_PAGE_SIZE);
Michael Chan352f7682008-05-02 16:57:26 -07002591 else
2592 return -ENOMEM;
2593
Michael Chane503e062012-12-06 10:33:08 +00002594 BNX2_WR(bp, BNX2_CTX_HOST_PAGE_TBL_DATA0,
2595 (bp->ctx_blk_mapping[i] & 0xffffffff) |
2596 BNX2_CTX_HOST_PAGE_TBL_DATA0_VALID);
2597 BNX2_WR(bp, BNX2_CTX_HOST_PAGE_TBL_DATA1,
2598 (u64) bp->ctx_blk_mapping[i] >> 32);
2599 BNX2_WR(bp, BNX2_CTX_HOST_PAGE_TBL_CTRL, i |
2600 BNX2_CTX_HOST_PAGE_TBL_CTRL_WRITE_REQ);
Michael Chan59b47d82006-11-19 14:10:45 -08002601 for (j = 0; j < 10; j++) {
2602
Michael Chane503e062012-12-06 10:33:08 +00002603 val = BNX2_RD(bp, BNX2_CTX_HOST_PAGE_TBL_CTRL);
Michael Chan59b47d82006-11-19 14:10:45 -08002604 if (!(val & BNX2_CTX_HOST_PAGE_TBL_CTRL_WRITE_REQ))
2605 break;
2606 udelay(5);
2607 }
2608 if (val & BNX2_CTX_HOST_PAGE_TBL_CTRL_WRITE_REQ) {
2609 ret = -EBUSY;
2610 break;
2611 }
2612 }
2613 return ret;
2614}
2615
Michael Chanb6016b72005-05-26 13:03:09 -07002616static void
2617bnx2_init_context(struct bnx2 *bp)
2618{
2619 u32 vcid;
2620
2621 vcid = 96;
2622 while (vcid) {
2623 u32 vcid_addr, pcid_addr, offset;
Michael Chan7947b202007-06-04 21:17:10 -07002624 int i;
Michael Chanb6016b72005-05-26 13:03:09 -07002625
2626 vcid--;
2627
Michael Chan4ce45e02012-12-06 10:33:10 +00002628 if (BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5706_A0) {
Michael Chanb6016b72005-05-26 13:03:09 -07002629 u32 new_vcid;
2630
2631 vcid_addr = GET_PCID_ADDR(vcid);
2632 if (vcid & 0x8) {
2633 new_vcid = 0x60 + (vcid & 0xf0) + (vcid & 0x7);
2634 }
2635 else {
2636 new_vcid = vcid;
2637 }
2638 pcid_addr = GET_PCID_ADDR(new_vcid);
2639 }
2640 else {
2641 vcid_addr = GET_CID_ADDR(vcid);
2642 pcid_addr = vcid_addr;
2643 }
2644
Michael Chan7947b202007-06-04 21:17:10 -07002645 for (i = 0; i < (CTX_SIZE / PHY_CTX_SIZE); i++) {
2646 vcid_addr += (i << PHY_CTX_SHIFT);
2647 pcid_addr += (i << PHY_CTX_SHIFT);
Michael Chanb6016b72005-05-26 13:03:09 -07002648
Michael Chane503e062012-12-06 10:33:08 +00002649 BNX2_WR(bp, BNX2_CTX_VIRT_ADDR, vcid_addr);
2650 BNX2_WR(bp, BNX2_CTX_PAGE_TBL, pcid_addr);
Michael Chan7947b202007-06-04 21:17:10 -07002651
2652 /* Zero out the context. */
2653 for (offset = 0; offset < PHY_CTX_SIZE; offset += 4)
Michael Chan62a83132008-01-29 21:35:40 -08002654 bnx2_ctx_wr(bp, vcid_addr, offset, 0);
Michael Chanb6016b72005-05-26 13:03:09 -07002655 }
Michael Chanb6016b72005-05-26 13:03:09 -07002656 }
2657}
2658
2659static int
2660bnx2_alloc_bad_rbuf(struct bnx2 *bp)
2661{
2662 u16 *good_mbuf;
2663 u32 good_mbuf_cnt;
2664 u32 val;
2665
2666 good_mbuf = kmalloc(512 * sizeof(u16), GFP_KERNEL);
Joe Perchese404dec2012-01-29 12:56:23 +00002667 if (good_mbuf == NULL)
Michael Chanb6016b72005-05-26 13:03:09 -07002668 return -ENOMEM;
Michael Chanb6016b72005-05-26 13:03:09 -07002669
Michael Chane503e062012-12-06 10:33:08 +00002670 BNX2_WR(bp, BNX2_MISC_ENABLE_SET_BITS,
Michael Chanb6016b72005-05-26 13:03:09 -07002671 BNX2_MISC_ENABLE_SET_BITS_RX_MBUF_ENABLE);
2672
2673 good_mbuf_cnt = 0;
2674
2675 /* Allocate a bunch of mbufs and save the good ones in an array. */
Michael Chan2726d6e2008-01-29 21:35:05 -08002676 val = bnx2_reg_rd_ind(bp, BNX2_RBUF_STATUS1);
Michael Chanb6016b72005-05-26 13:03:09 -07002677 while (val & BNX2_RBUF_STATUS1_FREE_COUNT) {
Michael Chan2726d6e2008-01-29 21:35:05 -08002678 bnx2_reg_wr_ind(bp, BNX2_RBUF_COMMAND,
2679 BNX2_RBUF_COMMAND_ALLOC_REQ);
Michael Chanb6016b72005-05-26 13:03:09 -07002680
Michael Chan2726d6e2008-01-29 21:35:05 -08002681 val = bnx2_reg_rd_ind(bp, BNX2_RBUF_FW_BUF_ALLOC);
Michael Chanb6016b72005-05-26 13:03:09 -07002682
2683 val &= BNX2_RBUF_FW_BUF_ALLOC_VALUE;
2684
2685 /* The addresses with Bit 9 set are bad memory blocks. */
2686 if (!(val & (1 << 9))) {
2687 good_mbuf[good_mbuf_cnt] = (u16) val;
2688 good_mbuf_cnt++;
2689 }
2690
Michael Chan2726d6e2008-01-29 21:35:05 -08002691 val = bnx2_reg_rd_ind(bp, BNX2_RBUF_STATUS1);
Michael Chanb6016b72005-05-26 13:03:09 -07002692 }
2693
2694 /* Free the good ones back to the mbuf pool thus discarding
2695 * all the bad ones. */
2696 while (good_mbuf_cnt) {
2697 good_mbuf_cnt--;
2698
2699 val = good_mbuf[good_mbuf_cnt];
2700 val = (val << 9) | val | 1;
2701
Michael Chan2726d6e2008-01-29 21:35:05 -08002702 bnx2_reg_wr_ind(bp, BNX2_RBUF_FW_BUF_FREE, val);
Michael Chanb6016b72005-05-26 13:03:09 -07002703 }
2704 kfree(good_mbuf);
2705 return 0;
2706}
2707
2708static void
Benjamin Li5fcaed02008-07-14 22:39:52 -07002709bnx2_set_mac_addr(struct bnx2 *bp, u8 *mac_addr, u32 pos)
Michael Chanb6016b72005-05-26 13:03:09 -07002710{
2711 u32 val;
Michael Chanb6016b72005-05-26 13:03:09 -07002712
2713 val = (mac_addr[0] << 8) | mac_addr[1];
2714
Michael Chane503e062012-12-06 10:33:08 +00002715 BNX2_WR(bp, BNX2_EMAC_MAC_MATCH0 + (pos * 8), val);
Michael Chanb6016b72005-05-26 13:03:09 -07002716
Jeff Garzik6aa20a22006-09-13 13:24:59 -04002717 val = (mac_addr[2] << 24) | (mac_addr[3] << 16) |
Michael Chanb6016b72005-05-26 13:03:09 -07002718 (mac_addr[4] << 8) | mac_addr[5];
2719
Michael Chane503e062012-12-06 10:33:08 +00002720 BNX2_WR(bp, BNX2_EMAC_MAC_MATCH1 + (pos * 8), val);
Michael Chanb6016b72005-05-26 13:03:09 -07002721}
2722
2723static inline int
Stanislaw Gruszkaa2df00a2010-07-15 22:55:40 +00002724bnx2_alloc_rx_page(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr, u16 index, gfp_t gfp)
Michael Chan47bf4242007-12-12 11:19:12 -08002725{
2726 dma_addr_t mapping;
Michael Chan2bc40782012-12-06 10:33:09 +00002727 struct bnx2_sw_pg *rx_pg = &rxr->rx_pg_ring[index];
2728 struct bnx2_rx_bd *rxbd =
2729 &rxr->rx_pg_desc_ring[BNX2_RX_RING(index)][BNX2_RX_IDX(index)];
Stanislaw Gruszkaa2df00a2010-07-15 22:55:40 +00002730 struct page *page = alloc_page(gfp);
Michael Chan47bf4242007-12-12 11:19:12 -08002731
2732 if (!page)
2733 return -ENOMEM;
Stanislaw Gruszka36227e82010-07-15 04:25:50 +00002734 mapping = dma_map_page(&bp->pdev->dev, page, 0, PAGE_SIZE,
Michael Chan47bf4242007-12-12 11:19:12 -08002735 PCI_DMA_FROMDEVICE);
Stanislaw Gruszka36227e82010-07-15 04:25:50 +00002736 if (dma_mapping_error(&bp->pdev->dev, mapping)) {
Benjamin Li3d16af82008-10-09 12:26:41 -07002737 __free_page(page);
2738 return -EIO;
2739 }
2740
Michael Chan47bf4242007-12-12 11:19:12 -08002741 rx_pg->page = page;
FUJITA Tomonori1a4ccc22010-04-01 16:56:57 +00002742 dma_unmap_addr_set(rx_pg, mapping, mapping);
Michael Chan47bf4242007-12-12 11:19:12 -08002743 rxbd->rx_bd_haddr_hi = (u64) mapping >> 32;
2744 rxbd->rx_bd_haddr_lo = (u64) mapping & 0xffffffff;
2745 return 0;
2746}
2747
2748static void
Michael Chanbb4f98a2008-06-19 16:38:19 -07002749bnx2_free_rx_page(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr, u16 index)
Michael Chan47bf4242007-12-12 11:19:12 -08002750{
Michael Chan2bc40782012-12-06 10:33:09 +00002751 struct bnx2_sw_pg *rx_pg = &rxr->rx_pg_ring[index];
Michael Chan47bf4242007-12-12 11:19:12 -08002752 struct page *page = rx_pg->page;
2753
2754 if (!page)
2755 return;
2756
Stanislaw Gruszka36227e82010-07-15 04:25:50 +00002757 dma_unmap_page(&bp->pdev->dev, dma_unmap_addr(rx_pg, mapping),
2758 PAGE_SIZE, PCI_DMA_FROMDEVICE);
Michael Chan47bf4242007-12-12 11:19:12 -08002759
2760 __free_page(page);
2761 rx_pg->page = NULL;
2762}
2763
2764static inline int
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00002765bnx2_alloc_rx_data(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr, u16 index, gfp_t gfp)
Michael Chanb6016b72005-05-26 13:03:09 -07002766{
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00002767 u8 *data;
Michael Chan2bc40782012-12-06 10:33:09 +00002768 struct bnx2_sw_bd *rx_buf = &rxr->rx_buf_ring[index];
Michael Chanb6016b72005-05-26 13:03:09 -07002769 dma_addr_t mapping;
Michael Chan2bc40782012-12-06 10:33:09 +00002770 struct bnx2_rx_bd *rxbd =
2771 &rxr->rx_desc_ring[BNX2_RX_RING(index)][BNX2_RX_IDX(index)];
Michael Chanb6016b72005-05-26 13:03:09 -07002772
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00002773 data = kmalloc(bp->rx_buf_size, gfp);
2774 if (!data)
Michael Chanb6016b72005-05-26 13:03:09 -07002775 return -ENOMEM;
Michael Chanb6016b72005-05-26 13:03:09 -07002776
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00002777 mapping = dma_map_single(&bp->pdev->dev,
2778 get_l2_fhdr(data),
2779 bp->rx_buf_use_size,
Stanislaw Gruszka36227e82010-07-15 04:25:50 +00002780 PCI_DMA_FROMDEVICE);
2781 if (dma_mapping_error(&bp->pdev->dev, mapping)) {
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00002782 kfree(data);
Benjamin Li3d16af82008-10-09 12:26:41 -07002783 return -EIO;
2784 }
Michael Chanb6016b72005-05-26 13:03:09 -07002785
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00002786 rx_buf->data = data;
FUJITA Tomonori1a4ccc22010-04-01 16:56:57 +00002787 dma_unmap_addr_set(rx_buf, mapping, mapping);
Michael Chanb6016b72005-05-26 13:03:09 -07002788
2789 rxbd->rx_bd_haddr_hi = (u64) mapping >> 32;
2790 rxbd->rx_bd_haddr_lo = (u64) mapping & 0xffffffff;
2791
Michael Chanbb4f98a2008-06-19 16:38:19 -07002792 rxr->rx_prod_bseq += bp->rx_buf_use_size;
Michael Chanb6016b72005-05-26 13:03:09 -07002793
2794 return 0;
2795}
2796
Michael Chanda3e4fb2007-05-03 13:24:23 -07002797static int
Michael Chan35efa7c2007-12-20 19:56:37 -08002798bnx2_phy_event_is_set(struct bnx2 *bp, struct bnx2_napi *bnapi, u32 event)
Michael Chanda3e4fb2007-05-03 13:24:23 -07002799{
Michael Chan43e80b82008-06-19 16:41:08 -07002800 struct status_block *sblk = bnapi->status_blk.msi;
Michael Chanda3e4fb2007-05-03 13:24:23 -07002801 u32 new_link_state, old_link_state;
2802 int is_set = 1;
2803
2804 new_link_state = sblk->status_attn_bits & event;
2805 old_link_state = sblk->status_attn_bits_ack & event;
2806 if (new_link_state != old_link_state) {
2807 if (new_link_state)
Michael Chane503e062012-12-06 10:33:08 +00002808 BNX2_WR(bp, BNX2_PCICFG_STATUS_BIT_SET_CMD, event);
Michael Chanda3e4fb2007-05-03 13:24:23 -07002809 else
Michael Chane503e062012-12-06 10:33:08 +00002810 BNX2_WR(bp, BNX2_PCICFG_STATUS_BIT_CLEAR_CMD, event);
Michael Chanda3e4fb2007-05-03 13:24:23 -07002811 } else
2812 is_set = 0;
2813
2814 return is_set;
2815}
2816
Michael Chanb6016b72005-05-26 13:03:09 -07002817static void
Michael Chan35efa7c2007-12-20 19:56:37 -08002818bnx2_phy_int(struct bnx2 *bp, struct bnx2_napi *bnapi)
Michael Chanb6016b72005-05-26 13:03:09 -07002819{
Michael Chan74ecc622008-05-02 16:56:16 -07002820 spin_lock(&bp->phy_lock);
2821
2822 if (bnx2_phy_event_is_set(bp, bnapi, STATUS_ATTN_BITS_LINK_STATE))
Michael Chanb6016b72005-05-26 13:03:09 -07002823 bnx2_set_link(bp);
Michael Chan35efa7c2007-12-20 19:56:37 -08002824 if (bnx2_phy_event_is_set(bp, bnapi, STATUS_ATTN_BITS_TIMER_ABORT))
Michael Chan0d8a6572007-07-07 22:49:43 -07002825 bnx2_set_remote_link(bp);
2826
Michael Chan74ecc622008-05-02 16:56:16 -07002827 spin_unlock(&bp->phy_lock);
2828
Michael Chanb6016b72005-05-26 13:03:09 -07002829}
2830
Michael Chanead72702007-12-20 19:55:39 -08002831static inline u16
Michael Chan35efa7c2007-12-20 19:56:37 -08002832bnx2_get_hw_tx_cons(struct bnx2_napi *bnapi)
Michael Chanead72702007-12-20 19:55:39 -08002833{
2834 u16 cons;
2835
Michael Chan43e80b82008-06-19 16:41:08 -07002836 /* Tell compiler that status block fields can change. */
2837 barrier();
2838 cons = *bnapi->hw_tx_cons_ptr;
Michael Chan581daf72009-05-06 16:46:47 -07002839 barrier();
Michael Chan2bc40782012-12-06 10:33:09 +00002840 if (unlikely((cons & BNX2_MAX_TX_DESC_CNT) == BNX2_MAX_TX_DESC_CNT))
Michael Chanead72702007-12-20 19:55:39 -08002841 cons++;
2842 return cons;
2843}
2844
Michael Chan57851d82007-12-20 20:01:44 -08002845static int
2846bnx2_tx_int(struct bnx2 *bp, struct bnx2_napi *bnapi, int budget)
Michael Chanb6016b72005-05-26 13:03:09 -07002847{
Michael Chan35e90102008-06-19 16:37:42 -07002848 struct bnx2_tx_ring_info *txr = &bnapi->tx_ring;
Michael Chanb6016b72005-05-26 13:03:09 -07002849 u16 hw_cons, sw_cons, sw_ring_cons;
Benjamin Li706bf242008-07-18 17:55:11 -07002850 int tx_pkt = 0, index;
Eric Dumazete9831902011-11-29 11:53:05 +00002851 unsigned int tx_bytes = 0;
Benjamin Li706bf242008-07-18 17:55:11 -07002852 struct netdev_queue *txq;
2853
2854 index = (bnapi - bp->bnx2_napi);
2855 txq = netdev_get_tx_queue(bp->dev, index);
Michael Chanb6016b72005-05-26 13:03:09 -07002856
Michael Chan35efa7c2007-12-20 19:56:37 -08002857 hw_cons = bnx2_get_hw_tx_cons(bnapi);
Michael Chan35e90102008-06-19 16:37:42 -07002858 sw_cons = txr->tx_cons;
Michael Chanb6016b72005-05-26 13:03:09 -07002859
2860 while (sw_cons != hw_cons) {
Michael Chan2bc40782012-12-06 10:33:09 +00002861 struct bnx2_sw_tx_bd *tx_buf;
Michael Chanb6016b72005-05-26 13:03:09 -07002862 struct sk_buff *skb;
2863 int i, last;
2864
Michael Chan2bc40782012-12-06 10:33:09 +00002865 sw_ring_cons = BNX2_TX_RING_IDX(sw_cons);
Michael Chanb6016b72005-05-26 13:03:09 -07002866
Michael Chan35e90102008-06-19 16:37:42 -07002867 tx_buf = &txr->tx_buf_ring[sw_ring_cons];
Michael Chanb6016b72005-05-26 13:03:09 -07002868 skb = tx_buf->skb;
Arjan van de Ven1d39ed52006-12-12 14:06:23 +01002869
Eric Dumazetd62fda02009-05-12 20:48:02 +00002870 /* prefetch skb_end_pointer() to speedup skb_shinfo(skb) */
2871 prefetch(&skb->end);
2872
Michael Chanb6016b72005-05-26 13:03:09 -07002873 /* partial BD completions possible with TSO packets */
Eric Dumazetd62fda02009-05-12 20:48:02 +00002874 if (tx_buf->is_gso) {
Michael Chanb6016b72005-05-26 13:03:09 -07002875 u16 last_idx, last_ring_idx;
2876
Eric Dumazetd62fda02009-05-12 20:48:02 +00002877 last_idx = sw_cons + tx_buf->nr_frags + 1;
2878 last_ring_idx = sw_ring_cons + tx_buf->nr_frags + 1;
Michael Chan2bc40782012-12-06 10:33:09 +00002879 if (unlikely(last_ring_idx >= BNX2_MAX_TX_DESC_CNT)) {
Michael Chanb6016b72005-05-26 13:03:09 -07002880 last_idx++;
2881 }
2882 if (((s16) ((s16) last_idx - (s16) hw_cons)) > 0) {
2883 break;
2884 }
2885 }
Arjan van de Ven1d39ed52006-12-12 14:06:23 +01002886
Stanislaw Gruszka36227e82010-07-15 04:25:50 +00002887 dma_unmap_single(&bp->pdev->dev, dma_unmap_addr(tx_buf, mapping),
Alexander Duycke95524a2009-12-02 16:47:57 +00002888 skb_headlen(skb), PCI_DMA_TODEVICE);
Michael Chanb6016b72005-05-26 13:03:09 -07002889
2890 tx_buf->skb = NULL;
Eric Dumazetd62fda02009-05-12 20:48:02 +00002891 last = tx_buf->nr_frags;
Michael Chanb6016b72005-05-26 13:03:09 -07002892
2893 for (i = 0; i < last; i++) {
Michael Chan2bc40782012-12-06 10:33:09 +00002894 struct bnx2_sw_tx_bd *tx_buf;
Alexander Duycke95524a2009-12-02 16:47:57 +00002895
Michael Chan2bc40782012-12-06 10:33:09 +00002896 sw_cons = BNX2_NEXT_TX_BD(sw_cons);
2897
2898 tx_buf = &txr->tx_buf_ring[BNX2_TX_RING_IDX(sw_cons)];
Stanislaw Gruszka36227e82010-07-15 04:25:50 +00002899 dma_unmap_page(&bp->pdev->dev,
Michael Chan2bc40782012-12-06 10:33:09 +00002900 dma_unmap_addr(tx_buf, mapping),
Eric Dumazet9e903e02011-10-18 21:00:24 +00002901 skb_frag_size(&skb_shinfo(skb)->frags[i]),
Alexander Duycke95524a2009-12-02 16:47:57 +00002902 PCI_DMA_TODEVICE);
Michael Chanb6016b72005-05-26 13:03:09 -07002903 }
2904
Michael Chan2bc40782012-12-06 10:33:09 +00002905 sw_cons = BNX2_NEXT_TX_BD(sw_cons);
Michael Chanb6016b72005-05-26 13:03:09 -07002906
Eric Dumazete9831902011-11-29 11:53:05 +00002907 tx_bytes += skb->len;
Eric W. Biedermanf458b2e2014-03-11 14:17:41 -07002908 dev_kfree_skb_any(skb);
Michael Chan57851d82007-12-20 20:01:44 -08002909 tx_pkt++;
2910 if (tx_pkt == budget)
2911 break;
Michael Chanb6016b72005-05-26 13:03:09 -07002912
Eric Dumazetd62fda02009-05-12 20:48:02 +00002913 if (hw_cons == sw_cons)
2914 hw_cons = bnx2_get_hw_tx_cons(bnapi);
Michael Chanb6016b72005-05-26 13:03:09 -07002915 }
2916
Eric Dumazete9831902011-11-29 11:53:05 +00002917 netdev_tx_completed_queue(txq, tx_pkt, tx_bytes);
Michael Chan35e90102008-06-19 16:37:42 -07002918 txr->hw_tx_cons = hw_cons;
2919 txr->tx_cons = sw_cons;
Benjamin Li706bf242008-07-18 17:55:11 -07002920
Michael Chan2f8af122006-08-15 01:39:10 -07002921 /* Need to make the tx_cons update visible to bnx2_start_xmit()
Benjamin Li706bf242008-07-18 17:55:11 -07002922 * before checking for netif_tx_queue_stopped(). Without the
Michael Chan2f8af122006-08-15 01:39:10 -07002923 * memory barrier, there is a small possibility that bnx2_start_xmit()
2924 * will miss it and cause the queue to be stopped forever.
2925 */
2926 smp_mb();
Michael Chanb6016b72005-05-26 13:03:09 -07002927
Benjamin Li706bf242008-07-18 17:55:11 -07002928 if (unlikely(netif_tx_queue_stopped(txq)) &&
Michael Chan35e90102008-06-19 16:37:42 -07002929 (bnx2_tx_avail(bp, txr) > bp->tx_wake_thresh)) {
Benjamin Li706bf242008-07-18 17:55:11 -07002930 __netif_tx_lock(txq, smp_processor_id());
2931 if ((netif_tx_queue_stopped(txq)) &&
Michael Chan35e90102008-06-19 16:37:42 -07002932 (bnx2_tx_avail(bp, txr) > bp->tx_wake_thresh))
Benjamin Li706bf242008-07-18 17:55:11 -07002933 netif_tx_wake_queue(txq);
2934 __netif_tx_unlock(txq);
Michael Chanb6016b72005-05-26 13:03:09 -07002935 }
Benjamin Li706bf242008-07-18 17:55:11 -07002936
Michael Chan57851d82007-12-20 20:01:44 -08002937 return tx_pkt;
Michael Chanb6016b72005-05-26 13:03:09 -07002938}
2939
Michael Chan1db82f22007-12-12 11:19:35 -08002940static void
Michael Chanbb4f98a2008-06-19 16:38:19 -07002941bnx2_reuse_rx_skb_pages(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr,
Michael Chana1f60192007-12-20 19:57:19 -08002942 struct sk_buff *skb, int count)
Michael Chan1db82f22007-12-12 11:19:35 -08002943{
Michael Chan2bc40782012-12-06 10:33:09 +00002944 struct bnx2_sw_pg *cons_rx_pg, *prod_rx_pg;
2945 struct bnx2_rx_bd *cons_bd, *prod_bd;
Michael Chan1db82f22007-12-12 11:19:35 -08002946 int i;
Benjamin Li3d16af82008-10-09 12:26:41 -07002947 u16 hw_prod, prod;
Michael Chanbb4f98a2008-06-19 16:38:19 -07002948 u16 cons = rxr->rx_pg_cons;
Michael Chan1db82f22007-12-12 11:19:35 -08002949
Benjamin Li3d16af82008-10-09 12:26:41 -07002950 cons_rx_pg = &rxr->rx_pg_ring[cons];
2951
2952 /* The caller was unable to allocate a new page to replace the
2953 * last one in the frags array, so we need to recycle that page
2954 * and then free the skb.
2955 */
2956 if (skb) {
2957 struct page *page;
2958 struct skb_shared_info *shinfo;
2959
2960 shinfo = skb_shinfo(skb);
2961 shinfo->nr_frags--;
Ian Campbellb7b6a682011-08-24 22:28:12 +00002962 page = skb_frag_page(&shinfo->frags[shinfo->nr_frags]);
2963 __skb_frag_set_page(&shinfo->frags[shinfo->nr_frags], NULL);
Benjamin Li3d16af82008-10-09 12:26:41 -07002964
2965 cons_rx_pg->page = page;
2966 dev_kfree_skb(skb);
2967 }
2968
2969 hw_prod = rxr->rx_pg_prod;
2970
Michael Chan1db82f22007-12-12 11:19:35 -08002971 for (i = 0; i < count; i++) {
Michael Chan2bc40782012-12-06 10:33:09 +00002972 prod = BNX2_RX_PG_RING_IDX(hw_prod);
Michael Chan1db82f22007-12-12 11:19:35 -08002973
Michael Chanbb4f98a2008-06-19 16:38:19 -07002974 prod_rx_pg = &rxr->rx_pg_ring[prod];
2975 cons_rx_pg = &rxr->rx_pg_ring[cons];
Michael Chan2bc40782012-12-06 10:33:09 +00002976 cons_bd = &rxr->rx_pg_desc_ring[BNX2_RX_RING(cons)]
2977 [BNX2_RX_IDX(cons)];
2978 prod_bd = &rxr->rx_pg_desc_ring[BNX2_RX_RING(prod)]
2979 [BNX2_RX_IDX(prod)];
Michael Chan1db82f22007-12-12 11:19:35 -08002980
Michael Chan1db82f22007-12-12 11:19:35 -08002981 if (prod != cons) {
2982 prod_rx_pg->page = cons_rx_pg->page;
2983 cons_rx_pg->page = NULL;
FUJITA Tomonori1a4ccc22010-04-01 16:56:57 +00002984 dma_unmap_addr_set(prod_rx_pg, mapping,
2985 dma_unmap_addr(cons_rx_pg, mapping));
Michael Chan1db82f22007-12-12 11:19:35 -08002986
2987 prod_bd->rx_bd_haddr_hi = cons_bd->rx_bd_haddr_hi;
2988 prod_bd->rx_bd_haddr_lo = cons_bd->rx_bd_haddr_lo;
2989
2990 }
Michael Chan2bc40782012-12-06 10:33:09 +00002991 cons = BNX2_RX_PG_RING_IDX(BNX2_NEXT_RX_BD(cons));
2992 hw_prod = BNX2_NEXT_RX_BD(hw_prod);
Michael Chan1db82f22007-12-12 11:19:35 -08002993 }
Michael Chanbb4f98a2008-06-19 16:38:19 -07002994 rxr->rx_pg_prod = hw_prod;
2995 rxr->rx_pg_cons = cons;
Michael Chan1db82f22007-12-12 11:19:35 -08002996}
2997
Michael Chanb6016b72005-05-26 13:03:09 -07002998static inline void
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00002999bnx2_reuse_rx_data(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr,
3000 u8 *data, u16 cons, u16 prod)
Michael Chanb6016b72005-05-26 13:03:09 -07003001{
Michael Chan2bc40782012-12-06 10:33:09 +00003002 struct bnx2_sw_bd *cons_rx_buf, *prod_rx_buf;
3003 struct bnx2_rx_bd *cons_bd, *prod_bd;
Michael Chan236b6392006-03-20 17:49:02 -08003004
Michael Chanbb4f98a2008-06-19 16:38:19 -07003005 cons_rx_buf = &rxr->rx_buf_ring[cons];
3006 prod_rx_buf = &rxr->rx_buf_ring[prod];
Michael Chanb6016b72005-05-26 13:03:09 -07003007
Stanislaw Gruszka36227e82010-07-15 04:25:50 +00003008 dma_sync_single_for_device(&bp->pdev->dev,
FUJITA Tomonori1a4ccc22010-04-01 16:56:57 +00003009 dma_unmap_addr(cons_rx_buf, mapping),
Benjamin Li601d3d12008-05-16 22:19:35 -07003010 BNX2_RX_OFFSET + BNX2_RX_COPY_THRESH, PCI_DMA_FROMDEVICE);
Michael Chanb6016b72005-05-26 13:03:09 -07003011
Michael Chanbb4f98a2008-06-19 16:38:19 -07003012 rxr->rx_prod_bseq += bp->rx_buf_use_size;
Michael Chan236b6392006-03-20 17:49:02 -08003013
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00003014 prod_rx_buf->data = data;
Michael Chan236b6392006-03-20 17:49:02 -08003015
3016 if (cons == prod)
3017 return;
3018
FUJITA Tomonori1a4ccc22010-04-01 16:56:57 +00003019 dma_unmap_addr_set(prod_rx_buf, mapping,
3020 dma_unmap_addr(cons_rx_buf, mapping));
Michael Chanb6016b72005-05-26 13:03:09 -07003021
Michael Chan2bc40782012-12-06 10:33:09 +00003022 cons_bd = &rxr->rx_desc_ring[BNX2_RX_RING(cons)][BNX2_RX_IDX(cons)];
3023 prod_bd = &rxr->rx_desc_ring[BNX2_RX_RING(prod)][BNX2_RX_IDX(prod)];
Michael Chan236b6392006-03-20 17:49:02 -08003024 prod_bd->rx_bd_haddr_hi = cons_bd->rx_bd_haddr_hi;
3025 prod_bd->rx_bd_haddr_lo = cons_bd->rx_bd_haddr_lo;
Michael Chanb6016b72005-05-26 13:03:09 -07003026}
3027
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00003028static struct sk_buff *
3029bnx2_rx_skb(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr, u8 *data,
Michael Chana1f60192007-12-20 19:57:19 -08003030 unsigned int len, unsigned int hdr_len, dma_addr_t dma_addr,
3031 u32 ring_idx)
Michael Chan85833c62007-12-12 11:17:01 -08003032{
3033 int err;
3034 u16 prod = ring_idx & 0xffff;
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00003035 struct sk_buff *skb;
Michael Chan85833c62007-12-12 11:17:01 -08003036
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00003037 err = bnx2_alloc_rx_data(bp, rxr, prod, GFP_ATOMIC);
Michael Chan85833c62007-12-12 11:17:01 -08003038 if (unlikely(err)) {
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00003039 bnx2_reuse_rx_data(bp, rxr, data, (u16) (ring_idx >> 16), prod);
3040error:
Michael Chan1db82f22007-12-12 11:19:35 -08003041 if (hdr_len) {
3042 unsigned int raw_len = len + 4;
3043 int pages = PAGE_ALIGN(raw_len - hdr_len) >> PAGE_SHIFT;
3044
Michael Chanbb4f98a2008-06-19 16:38:19 -07003045 bnx2_reuse_rx_skb_pages(bp, rxr, NULL, pages);
Michael Chan1db82f22007-12-12 11:19:35 -08003046 }
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00003047 return NULL;
Michael Chan85833c62007-12-12 11:17:01 -08003048 }
3049
Stanislaw Gruszka36227e82010-07-15 04:25:50 +00003050 dma_unmap_single(&bp->pdev->dev, dma_addr, bp->rx_buf_use_size,
Michael Chan85833c62007-12-12 11:17:01 -08003051 PCI_DMA_FROMDEVICE);
Eric Dumazetd3836f22012-04-27 00:33:38 +00003052 skb = build_skb(data, 0);
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00003053 if (!skb) {
3054 kfree(data);
3055 goto error;
3056 }
3057 skb_reserve(skb, ((u8 *)get_l2_fhdr(data) - data) + BNX2_RX_OFFSET);
Michael Chan1db82f22007-12-12 11:19:35 -08003058 if (hdr_len == 0) {
3059 skb_put(skb, len);
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00003060 return skb;
Michael Chan1db82f22007-12-12 11:19:35 -08003061 } else {
3062 unsigned int i, frag_len, frag_size, pages;
Michael Chan2bc40782012-12-06 10:33:09 +00003063 struct bnx2_sw_pg *rx_pg;
Michael Chanbb4f98a2008-06-19 16:38:19 -07003064 u16 pg_cons = rxr->rx_pg_cons;
3065 u16 pg_prod = rxr->rx_pg_prod;
Michael Chan1db82f22007-12-12 11:19:35 -08003066
3067 frag_size = len + 4 - hdr_len;
3068 pages = PAGE_ALIGN(frag_size) >> PAGE_SHIFT;
3069 skb_put(skb, hdr_len);
3070
3071 for (i = 0; i < pages; i++) {
Benjamin Li3d16af82008-10-09 12:26:41 -07003072 dma_addr_t mapping_old;
3073
Michael Chan1db82f22007-12-12 11:19:35 -08003074 frag_len = min(frag_size, (unsigned int) PAGE_SIZE);
3075 if (unlikely(frag_len <= 4)) {
3076 unsigned int tail = 4 - frag_len;
3077
Michael Chanbb4f98a2008-06-19 16:38:19 -07003078 rxr->rx_pg_cons = pg_cons;
3079 rxr->rx_pg_prod = pg_prod;
3080 bnx2_reuse_rx_skb_pages(bp, rxr, NULL,
Michael Chana1f60192007-12-20 19:57:19 -08003081 pages - i);
Michael Chan1db82f22007-12-12 11:19:35 -08003082 skb->len -= tail;
3083 if (i == 0) {
3084 skb->tail -= tail;
3085 } else {
3086 skb_frag_t *frag =
3087 &skb_shinfo(skb)->frags[i - 1];
Eric Dumazet9e903e02011-10-18 21:00:24 +00003088 skb_frag_size_sub(frag, tail);
Michael Chan1db82f22007-12-12 11:19:35 -08003089 skb->data_len -= tail;
Michael Chan1db82f22007-12-12 11:19:35 -08003090 }
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00003091 return skb;
Michael Chan1db82f22007-12-12 11:19:35 -08003092 }
Michael Chanbb4f98a2008-06-19 16:38:19 -07003093 rx_pg = &rxr->rx_pg_ring[pg_cons];
Michael Chan1db82f22007-12-12 11:19:35 -08003094
Benjamin Li3d16af82008-10-09 12:26:41 -07003095 /* Don't unmap yet. If we're unable to allocate a new
3096 * page, we need to recycle the page and the DMA addr.
3097 */
FUJITA Tomonori1a4ccc22010-04-01 16:56:57 +00003098 mapping_old = dma_unmap_addr(rx_pg, mapping);
Michael Chan1db82f22007-12-12 11:19:35 -08003099 if (i == pages - 1)
3100 frag_len -= 4;
3101
3102 skb_fill_page_desc(skb, i, rx_pg->page, 0, frag_len);
3103 rx_pg->page = NULL;
3104
Michael Chanbb4f98a2008-06-19 16:38:19 -07003105 err = bnx2_alloc_rx_page(bp, rxr,
Michael Chan2bc40782012-12-06 10:33:09 +00003106 BNX2_RX_PG_RING_IDX(pg_prod),
Stanislaw Gruszkaa2df00a2010-07-15 22:55:40 +00003107 GFP_ATOMIC);
Michael Chan1db82f22007-12-12 11:19:35 -08003108 if (unlikely(err)) {
Michael Chanbb4f98a2008-06-19 16:38:19 -07003109 rxr->rx_pg_cons = pg_cons;
3110 rxr->rx_pg_prod = pg_prod;
3111 bnx2_reuse_rx_skb_pages(bp, rxr, skb,
Michael Chana1f60192007-12-20 19:57:19 -08003112 pages - i);
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00003113 return NULL;
Michael Chan1db82f22007-12-12 11:19:35 -08003114 }
3115
Stanislaw Gruszka36227e82010-07-15 04:25:50 +00003116 dma_unmap_page(&bp->pdev->dev, mapping_old,
Benjamin Li3d16af82008-10-09 12:26:41 -07003117 PAGE_SIZE, PCI_DMA_FROMDEVICE);
3118
Michael Chan1db82f22007-12-12 11:19:35 -08003119 frag_size -= frag_len;
3120 skb->data_len += frag_len;
Eric Dumazeta1f4e8b2011-10-13 07:50:19 +00003121 skb->truesize += PAGE_SIZE;
Michael Chan1db82f22007-12-12 11:19:35 -08003122 skb->len += frag_len;
3123
Michael Chan2bc40782012-12-06 10:33:09 +00003124 pg_prod = BNX2_NEXT_RX_BD(pg_prod);
3125 pg_cons = BNX2_RX_PG_RING_IDX(BNX2_NEXT_RX_BD(pg_cons));
Michael Chan1db82f22007-12-12 11:19:35 -08003126 }
Michael Chanbb4f98a2008-06-19 16:38:19 -07003127 rxr->rx_pg_prod = pg_prod;
3128 rxr->rx_pg_cons = pg_cons;
Michael Chan1db82f22007-12-12 11:19:35 -08003129 }
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00003130 return skb;
Michael Chan85833c62007-12-12 11:17:01 -08003131}
3132
Michael Chanc09c2622007-12-10 17:18:37 -08003133static inline u16
Michael Chan35efa7c2007-12-20 19:56:37 -08003134bnx2_get_hw_rx_cons(struct bnx2_napi *bnapi)
Michael Chanc09c2622007-12-10 17:18:37 -08003135{
Michael Chanbb4f98a2008-06-19 16:38:19 -07003136 u16 cons;
3137
Michael Chan43e80b82008-06-19 16:41:08 -07003138 /* Tell compiler that status block fields can change. */
3139 barrier();
3140 cons = *bnapi->hw_rx_cons_ptr;
Michael Chan581daf72009-05-06 16:46:47 -07003141 barrier();
Michael Chan2bc40782012-12-06 10:33:09 +00003142 if (unlikely((cons & BNX2_MAX_RX_DESC_CNT) == BNX2_MAX_RX_DESC_CNT))
Michael Chanc09c2622007-12-10 17:18:37 -08003143 cons++;
3144 return cons;
3145}
3146
Michael Chanb6016b72005-05-26 13:03:09 -07003147static int
Michael Chan35efa7c2007-12-20 19:56:37 -08003148bnx2_rx_int(struct bnx2 *bp, struct bnx2_napi *bnapi, int budget)
Michael Chanb6016b72005-05-26 13:03:09 -07003149{
Michael Chanbb4f98a2008-06-19 16:38:19 -07003150 struct bnx2_rx_ring_info *rxr = &bnapi->rx_ring;
Michael Chanb6016b72005-05-26 13:03:09 -07003151 u16 hw_cons, sw_cons, sw_ring_cons, sw_prod, sw_ring_prod;
3152 struct l2_fhdr *rx_hdr;
Michael Chan1db82f22007-12-12 11:19:35 -08003153 int rx_pkt = 0, pg_ring_used = 0;
Michael Chanb6016b72005-05-26 13:03:09 -07003154
Eric W. Biederman310c4d42014-03-11 14:31:09 -07003155 if (budget <= 0)
3156 return rx_pkt;
3157
Michael Chan35efa7c2007-12-20 19:56:37 -08003158 hw_cons = bnx2_get_hw_rx_cons(bnapi);
Michael Chanbb4f98a2008-06-19 16:38:19 -07003159 sw_cons = rxr->rx_cons;
3160 sw_prod = rxr->rx_prod;
Michael Chanb6016b72005-05-26 13:03:09 -07003161
3162 /* Memory barrier necessary as speculative reads of the rx
3163 * buffer can be ahead of the index in the status block
3164 */
3165 rmb();
3166 while (sw_cons != hw_cons) {
Michael Chan1db82f22007-12-12 11:19:35 -08003167 unsigned int len, hdr_len;
Michael Chanade2bfe2006-01-23 16:09:51 -08003168 u32 status;
Michael Chan2bc40782012-12-06 10:33:09 +00003169 struct bnx2_sw_bd *rx_buf, *next_rx_buf;
Michael Chanb6016b72005-05-26 13:03:09 -07003170 struct sk_buff *skb;
Michael Chan236b6392006-03-20 17:49:02 -08003171 dma_addr_t dma_addr;
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00003172 u8 *data;
Michael Chan2bc40782012-12-06 10:33:09 +00003173 u16 next_ring_idx;
Michael Chanb6016b72005-05-26 13:03:09 -07003174
Michael Chan2bc40782012-12-06 10:33:09 +00003175 sw_ring_cons = BNX2_RX_RING_IDX(sw_cons);
3176 sw_ring_prod = BNX2_RX_RING_IDX(sw_prod);
Michael Chanb6016b72005-05-26 13:03:09 -07003177
Michael Chanbb4f98a2008-06-19 16:38:19 -07003178 rx_buf = &rxr->rx_buf_ring[sw_ring_cons];
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00003179 data = rx_buf->data;
3180 rx_buf->data = NULL;
Michael Chan236b6392006-03-20 17:49:02 -08003181
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00003182 rx_hdr = get_l2_fhdr(data);
3183 prefetch(rx_hdr);
Michael Chan236b6392006-03-20 17:49:02 -08003184
FUJITA Tomonori1a4ccc22010-04-01 16:56:57 +00003185 dma_addr = dma_unmap_addr(rx_buf, mapping);
Michael Chan236b6392006-03-20 17:49:02 -08003186
Stanislaw Gruszka36227e82010-07-15 04:25:50 +00003187 dma_sync_single_for_cpu(&bp->pdev->dev, dma_addr,
Benjamin Li601d3d12008-05-16 22:19:35 -07003188 BNX2_RX_OFFSET + BNX2_RX_COPY_THRESH,
3189 PCI_DMA_FROMDEVICE);
Michael Chanb6016b72005-05-26 13:03:09 -07003190
Michael Chan2bc40782012-12-06 10:33:09 +00003191 next_ring_idx = BNX2_RX_RING_IDX(BNX2_NEXT_RX_BD(sw_cons));
3192 next_rx_buf = &rxr->rx_buf_ring[next_ring_idx];
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00003193 prefetch(get_l2_fhdr(next_rx_buf->data));
3194
Michael Chan1db82f22007-12-12 11:19:35 -08003195 len = rx_hdr->l2_fhdr_pkt_len;
Michael Chan990ec382009-02-12 16:54:13 -08003196 status = rx_hdr->l2_fhdr_status;
Michael Chanb6016b72005-05-26 13:03:09 -07003197
Michael Chan1db82f22007-12-12 11:19:35 -08003198 hdr_len = 0;
3199 if (status & L2_FHDR_STATUS_SPLIT) {
3200 hdr_len = rx_hdr->l2_fhdr_ip_xsum;
3201 pg_ring_used = 1;
3202 } else if (len > bp->rx_jumbo_thresh) {
3203 hdr_len = bp->rx_jumbo_thresh;
3204 pg_ring_used = 1;
3205 }
3206
Michael Chan990ec382009-02-12 16:54:13 -08003207 if (unlikely(status & (L2_FHDR_ERRORS_BAD_CRC |
3208 L2_FHDR_ERRORS_PHY_DECODE |
3209 L2_FHDR_ERRORS_ALIGNMENT |
3210 L2_FHDR_ERRORS_TOO_SHORT |
3211 L2_FHDR_ERRORS_GIANT_FRAME))) {
3212
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00003213 bnx2_reuse_rx_data(bp, rxr, data, sw_ring_cons,
Michael Chan990ec382009-02-12 16:54:13 -08003214 sw_ring_prod);
3215 if (pg_ring_used) {
3216 int pages;
3217
3218 pages = PAGE_ALIGN(len - hdr_len) >> PAGE_SHIFT;
3219
3220 bnx2_reuse_rx_skb_pages(bp, rxr, NULL, pages);
3221 }
3222 goto next_rx;
3223 }
3224
Michael Chan1db82f22007-12-12 11:19:35 -08003225 len -= 4;
Michael Chanb6016b72005-05-26 13:03:09 -07003226
Michael Chan5d5d0012007-12-12 11:17:43 -08003227 if (len <= bp->rx_copy_thresh) {
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00003228 skb = netdev_alloc_skb(bp->dev, len + 6);
3229 if (skb == NULL) {
3230 bnx2_reuse_rx_data(bp, rxr, data, sw_ring_cons,
Michael Chan85833c62007-12-12 11:17:01 -08003231 sw_ring_prod);
3232 goto next_rx;
3233 }
Michael Chanb6016b72005-05-26 13:03:09 -07003234
3235 /* aligned copy */
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00003236 memcpy(skb->data,
3237 (u8 *)rx_hdr + BNX2_RX_OFFSET - 6,
3238 len + 6);
3239 skb_reserve(skb, 6);
3240 skb_put(skb, len);
Michael Chanb6016b72005-05-26 13:03:09 -07003241
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00003242 bnx2_reuse_rx_data(bp, rxr, data,
Michael Chanb6016b72005-05-26 13:03:09 -07003243 sw_ring_cons, sw_ring_prod);
3244
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00003245 } else {
3246 skb = bnx2_rx_skb(bp, rxr, data, len, hdr_len, dma_addr,
3247 (sw_ring_cons << 16) | sw_ring_prod);
3248 if (!skb)
3249 goto next_rx;
3250 }
Michael Chanf22828e2008-08-14 15:30:14 -07003251 if ((status & L2_FHDR_STATUS_L2_VLAN_TAG) &&
Jesse Gross7d0fd212010-10-20 13:56:09 +00003252 !(bp->rx_mode & BNX2_EMAC_RX_MODE_KEEP_VLAN_TAG))
Patrick McHardy86a9bad2013-04-19 02:04:30 +00003253 __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), rx_hdr->l2_fhdr_vlan_tag);
Michael Chanf22828e2008-08-14 15:30:14 -07003254
Michael Chanb6016b72005-05-26 13:03:09 -07003255 skb->protocol = eth_type_trans(skb, bp->dev);
3256
Vlad Yasevich1b0ecb22014-09-30 19:39:37 -04003257 if (len > (bp->dev->mtu + ETH_HLEN) &&
3258 skb->protocol != htons(0x8100) &&
3259 skb->protocol != htons(ETH_P_8021AD)) {
Michael Chanb6016b72005-05-26 13:03:09 -07003260
Michael Chan745720e2006-06-29 12:37:41 -07003261 dev_kfree_skb(skb);
Michael Chanb6016b72005-05-26 13:03:09 -07003262 goto next_rx;
3263
3264 }
3265
Eric Dumazetbc8acf22010-09-02 13:07:41 -07003266 skb_checksum_none_assert(skb);
Michał Mirosław8d7dfc22011-04-10 04:47:46 +00003267 if ((bp->dev->features & NETIF_F_RXCSUM) &&
Michael Chanb6016b72005-05-26 13:03:09 -07003268 (status & (L2_FHDR_STATUS_TCP_SEGMENT |
3269 L2_FHDR_STATUS_UDP_DATAGRAM))) {
3270
Michael Chanade2bfe2006-01-23 16:09:51 -08003271 if (likely((status & (L2_FHDR_ERRORS_TCP_XSUM |
3272 L2_FHDR_ERRORS_UDP_XSUM)) == 0))
Michael Chanb6016b72005-05-26 13:03:09 -07003273 skb->ip_summed = CHECKSUM_UNNECESSARY;
3274 }
Michael Chanfdc85412010-07-03 20:42:16 +00003275 if ((bp->dev->features & NETIF_F_RXHASH) &&
3276 ((status & L2_FHDR_STATUS_USE_RXHASH) ==
3277 L2_FHDR_STATUS_USE_RXHASH))
Tom Herbertcf1bfd62013-12-17 23:22:57 -08003278 skb_set_hash(skb, rx_hdr->l2_fhdr_hash,
3279 PKT_HASH_TYPE_L3);
Michael Chanb6016b72005-05-26 13:03:09 -07003280
David S. Miller0c8dfc82009-01-27 16:22:32 -08003281 skb_record_rx_queue(skb, bnapi - &bp->bnx2_napi[0]);
Jesse Gross7d0fd212010-10-20 13:56:09 +00003282 napi_gro_receive(&bnapi->napi, skb);
Michael Chanb6016b72005-05-26 13:03:09 -07003283 rx_pkt++;
3284
3285next_rx:
Michael Chan2bc40782012-12-06 10:33:09 +00003286 sw_cons = BNX2_NEXT_RX_BD(sw_cons);
3287 sw_prod = BNX2_NEXT_RX_BD(sw_prod);
Michael Chanb6016b72005-05-26 13:03:09 -07003288
3289 if ((rx_pkt == budget))
3290 break;
Michael Chanf4e418f2005-11-04 08:53:48 -08003291
3292 /* Refresh hw_cons to see if there is new work */
3293 if (sw_cons == hw_cons) {
Michael Chan35efa7c2007-12-20 19:56:37 -08003294 hw_cons = bnx2_get_hw_rx_cons(bnapi);
Michael Chanf4e418f2005-11-04 08:53:48 -08003295 rmb();
3296 }
Michael Chanb6016b72005-05-26 13:03:09 -07003297 }
Michael Chanbb4f98a2008-06-19 16:38:19 -07003298 rxr->rx_cons = sw_cons;
3299 rxr->rx_prod = sw_prod;
Michael Chanb6016b72005-05-26 13:03:09 -07003300
Michael Chan1db82f22007-12-12 11:19:35 -08003301 if (pg_ring_used)
Michael Chane503e062012-12-06 10:33:08 +00003302 BNX2_WR16(bp, rxr->rx_pg_bidx_addr, rxr->rx_pg_prod);
Michael Chan1db82f22007-12-12 11:19:35 -08003303
Michael Chane503e062012-12-06 10:33:08 +00003304 BNX2_WR16(bp, rxr->rx_bidx_addr, sw_prod);
Michael Chanb6016b72005-05-26 13:03:09 -07003305
Michael Chane503e062012-12-06 10:33:08 +00003306 BNX2_WR(bp, rxr->rx_bseq_addr, rxr->rx_prod_bseq);
Michael Chanb6016b72005-05-26 13:03:09 -07003307
3308 mmiowb();
3309
3310 return rx_pkt;
3311
3312}
3313
3314/* MSI ISR - The only difference between this and the INTx ISR
3315 * is that the MSI interrupt is always serviced.
3316 */
3317static irqreturn_t
David Howells7d12e782006-10-05 14:55:46 +01003318bnx2_msi(int irq, void *dev_instance)
Michael Chanb6016b72005-05-26 13:03:09 -07003319{
Michael Chanf0ea2e62008-06-19 16:41:57 -07003320 struct bnx2_napi *bnapi = dev_instance;
3321 struct bnx2 *bp = bnapi->bp;
Michael Chanb6016b72005-05-26 13:03:09 -07003322
Michael Chan43e80b82008-06-19 16:41:08 -07003323 prefetch(bnapi->status_blk.msi);
Michael Chane503e062012-12-06 10:33:08 +00003324 BNX2_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
Michael Chanb6016b72005-05-26 13:03:09 -07003325 BNX2_PCICFG_INT_ACK_CMD_USE_INT_HC_PARAM |
3326 BNX2_PCICFG_INT_ACK_CMD_MASK_INT);
3327
3328 /* Return here if interrupt is disabled. */
Michael Chan73eef4c2005-08-25 15:39:15 -07003329 if (unlikely(atomic_read(&bp->intr_sem) != 0))
3330 return IRQ_HANDLED;
Michael Chanb6016b72005-05-26 13:03:09 -07003331
Ben Hutchings288379f2009-01-19 16:43:59 -08003332 napi_schedule(&bnapi->napi);
Michael Chanb6016b72005-05-26 13:03:09 -07003333
Michael Chan73eef4c2005-08-25 15:39:15 -07003334 return IRQ_HANDLED;
Michael Chanb6016b72005-05-26 13:03:09 -07003335}
3336
3337static irqreturn_t
Michael Chan8e6a72c2007-05-03 13:24:48 -07003338bnx2_msi_1shot(int irq, void *dev_instance)
3339{
Michael Chanf0ea2e62008-06-19 16:41:57 -07003340 struct bnx2_napi *bnapi = dev_instance;
3341 struct bnx2 *bp = bnapi->bp;
Michael Chan8e6a72c2007-05-03 13:24:48 -07003342
Michael Chan43e80b82008-06-19 16:41:08 -07003343 prefetch(bnapi->status_blk.msi);
Michael Chan8e6a72c2007-05-03 13:24:48 -07003344
3345 /* Return here if interrupt is disabled. */
3346 if (unlikely(atomic_read(&bp->intr_sem) != 0))
3347 return IRQ_HANDLED;
3348
Ben Hutchings288379f2009-01-19 16:43:59 -08003349 napi_schedule(&bnapi->napi);
Michael Chan8e6a72c2007-05-03 13:24:48 -07003350
3351 return IRQ_HANDLED;
3352}
3353
3354static irqreturn_t
David Howells7d12e782006-10-05 14:55:46 +01003355bnx2_interrupt(int irq, void *dev_instance)
Michael Chanb6016b72005-05-26 13:03:09 -07003356{
Michael Chanf0ea2e62008-06-19 16:41:57 -07003357 struct bnx2_napi *bnapi = dev_instance;
3358 struct bnx2 *bp = bnapi->bp;
Michael Chan43e80b82008-06-19 16:41:08 -07003359 struct status_block *sblk = bnapi->status_blk.msi;
Michael Chanb6016b72005-05-26 13:03:09 -07003360
3361 /* When using INTx, it is possible for the interrupt to arrive
3362 * at the CPU before the status block posted prior to the
3363 * interrupt. Reading a register will flush the status block.
3364 * When using MSI, the MSI message will always complete after
3365 * the status block write.
3366 */
Michael Chan35efa7c2007-12-20 19:56:37 -08003367 if ((sblk->status_idx == bnapi->last_status_idx) &&
Michael Chane503e062012-12-06 10:33:08 +00003368 (BNX2_RD(bp, BNX2_PCICFG_MISC_STATUS) &
Michael Chanb6016b72005-05-26 13:03:09 -07003369 BNX2_PCICFG_MISC_STATUS_INTA_VALUE))
Michael Chan73eef4c2005-08-25 15:39:15 -07003370 return IRQ_NONE;
Michael Chanb6016b72005-05-26 13:03:09 -07003371
Michael Chane503e062012-12-06 10:33:08 +00003372 BNX2_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
Michael Chanb6016b72005-05-26 13:03:09 -07003373 BNX2_PCICFG_INT_ACK_CMD_USE_INT_HC_PARAM |
3374 BNX2_PCICFG_INT_ACK_CMD_MASK_INT);
3375
Michael Chanb8a7ce72007-07-07 22:51:03 -07003376 /* Read back to deassert IRQ immediately to avoid too many
3377 * spurious interrupts.
3378 */
Michael Chane503e062012-12-06 10:33:08 +00003379 BNX2_RD(bp, BNX2_PCICFG_INT_ACK_CMD);
Michael Chanb8a7ce72007-07-07 22:51:03 -07003380
Michael Chanb6016b72005-05-26 13:03:09 -07003381 /* Return here if interrupt is shared and is disabled. */
Michael Chan73eef4c2005-08-25 15:39:15 -07003382 if (unlikely(atomic_read(&bp->intr_sem) != 0))
3383 return IRQ_HANDLED;
Michael Chanb6016b72005-05-26 13:03:09 -07003384
Ben Hutchings288379f2009-01-19 16:43:59 -08003385 if (napi_schedule_prep(&bnapi->napi)) {
Michael Chan35efa7c2007-12-20 19:56:37 -08003386 bnapi->last_status_idx = sblk->status_idx;
Ben Hutchings288379f2009-01-19 16:43:59 -08003387 __napi_schedule(&bnapi->napi);
Michael Chanb8a7ce72007-07-07 22:51:03 -07003388 }
Michael Chanb6016b72005-05-26 13:03:09 -07003389
Michael Chan73eef4c2005-08-25 15:39:15 -07003390 return IRQ_HANDLED;
Michael Chanb6016b72005-05-26 13:03:09 -07003391}
3392
Michael Chan43e80b82008-06-19 16:41:08 -07003393static inline int
3394bnx2_has_fast_work(struct bnx2_napi *bnapi)
3395{
3396 struct bnx2_tx_ring_info *txr = &bnapi->tx_ring;
3397 struct bnx2_rx_ring_info *rxr = &bnapi->rx_ring;
3398
3399 if ((bnx2_get_hw_rx_cons(bnapi) != rxr->rx_cons) ||
3400 (bnx2_get_hw_tx_cons(bnapi) != txr->hw_tx_cons))
3401 return 1;
3402 return 0;
3403}
3404
Michael Chan0d8a6572007-07-07 22:49:43 -07003405#define STATUS_ATTN_EVENTS (STATUS_ATTN_BITS_LINK_STATE | \
3406 STATUS_ATTN_BITS_TIMER_ABORT)
Michael Chanda3e4fb2007-05-03 13:24:23 -07003407
Michael Chanf4e418f2005-11-04 08:53:48 -08003408static inline int
Michael Chan35efa7c2007-12-20 19:56:37 -08003409bnx2_has_work(struct bnx2_napi *bnapi)
Michael Chanf4e418f2005-11-04 08:53:48 -08003410{
Michael Chan43e80b82008-06-19 16:41:08 -07003411 struct status_block *sblk = bnapi->status_blk.msi;
Michael Chanf4e418f2005-11-04 08:53:48 -08003412
Michael Chan43e80b82008-06-19 16:41:08 -07003413 if (bnx2_has_fast_work(bnapi))
Michael Chanf4e418f2005-11-04 08:53:48 -08003414 return 1;
3415
Michael Chan4edd4732009-06-08 18:14:42 -07003416#ifdef BCM_CNIC
3417 if (bnapi->cnic_present && (bnapi->cnic_tag != sblk->status_idx))
3418 return 1;
3419#endif
3420
Michael Chanda3e4fb2007-05-03 13:24:23 -07003421 if ((sblk->status_attn_bits & STATUS_ATTN_EVENTS) !=
3422 (sblk->status_attn_bits_ack & STATUS_ATTN_EVENTS))
Michael Chanf4e418f2005-11-04 08:53:48 -08003423 return 1;
3424
3425 return 0;
3426}
3427
Michael Chanefba0182008-12-03 00:36:15 -08003428static void
3429bnx2_chk_missed_msi(struct bnx2 *bp)
3430{
3431 struct bnx2_napi *bnapi = &bp->bnx2_napi[0];
3432 u32 msi_ctrl;
3433
3434 if (bnx2_has_work(bnapi)) {
Michael Chane503e062012-12-06 10:33:08 +00003435 msi_ctrl = BNX2_RD(bp, BNX2_PCICFG_MSI_CONTROL);
Michael Chanefba0182008-12-03 00:36:15 -08003436 if (!(msi_ctrl & BNX2_PCICFG_MSI_CONTROL_ENABLE))
3437 return;
3438
3439 if (bnapi->last_status_idx == bp->idle_chk_status_idx) {
Michael Chane503e062012-12-06 10:33:08 +00003440 BNX2_WR(bp, BNX2_PCICFG_MSI_CONTROL, msi_ctrl &
3441 ~BNX2_PCICFG_MSI_CONTROL_ENABLE);
3442 BNX2_WR(bp, BNX2_PCICFG_MSI_CONTROL, msi_ctrl);
Michael Chanefba0182008-12-03 00:36:15 -08003443 bnx2_msi(bp->irq_tbl[0].vector, bnapi);
3444 }
3445 }
3446
3447 bp->idle_chk_status_idx = bnapi->last_status_idx;
3448}
3449
Michael Chan4edd4732009-06-08 18:14:42 -07003450#ifdef BCM_CNIC
3451static void bnx2_poll_cnic(struct bnx2 *bp, struct bnx2_napi *bnapi)
3452{
3453 struct cnic_ops *c_ops;
3454
3455 if (!bnapi->cnic_present)
3456 return;
3457
3458 rcu_read_lock();
3459 c_ops = rcu_dereference(bp->cnic_ops);
3460 if (c_ops)
3461 bnapi->cnic_tag = c_ops->cnic_handler(bp->cnic_data,
3462 bnapi->status_blk.msi);
3463 rcu_read_unlock();
3464}
3465#endif
3466
Michael Chan43e80b82008-06-19 16:41:08 -07003467static void bnx2_poll_link(struct bnx2 *bp, struct bnx2_napi *bnapi)
Michael Chanb6016b72005-05-26 13:03:09 -07003468{
Michael Chan43e80b82008-06-19 16:41:08 -07003469 struct status_block *sblk = bnapi->status_blk.msi;
Michael Chanda3e4fb2007-05-03 13:24:23 -07003470 u32 status_attn_bits = sblk->status_attn_bits;
3471 u32 status_attn_bits_ack = sblk->status_attn_bits_ack;
Michael Chanb6016b72005-05-26 13:03:09 -07003472
Michael Chanda3e4fb2007-05-03 13:24:23 -07003473 if ((status_attn_bits & STATUS_ATTN_EVENTS) !=
3474 (status_attn_bits_ack & STATUS_ATTN_EVENTS)) {
Michael Chanb6016b72005-05-26 13:03:09 -07003475
Michael Chan35efa7c2007-12-20 19:56:37 -08003476 bnx2_phy_int(bp, bnapi);
Michael Chanbf5295b2006-03-23 01:11:56 -08003477
3478 /* This is needed to take care of transient status
3479 * during link changes.
3480 */
Michael Chane503e062012-12-06 10:33:08 +00003481 BNX2_WR(bp, BNX2_HC_COMMAND,
3482 bp->hc_cmd | BNX2_HC_COMMAND_COAL_NOW_WO_INT);
3483 BNX2_RD(bp, BNX2_HC_COMMAND);
Michael Chanb6016b72005-05-26 13:03:09 -07003484 }
Michael Chan43e80b82008-06-19 16:41:08 -07003485}
3486
3487static int bnx2_poll_work(struct bnx2 *bp, struct bnx2_napi *bnapi,
3488 int work_done, int budget)
3489{
3490 struct bnx2_tx_ring_info *txr = &bnapi->tx_ring;
3491 struct bnx2_rx_ring_info *rxr = &bnapi->rx_ring;
Michael Chanb6016b72005-05-26 13:03:09 -07003492
Michael Chan35e90102008-06-19 16:37:42 -07003493 if (bnx2_get_hw_tx_cons(bnapi) != txr->hw_tx_cons)
Michael Chan57851d82007-12-20 20:01:44 -08003494 bnx2_tx_int(bp, bnapi, 0);
Michael Chanb6016b72005-05-26 13:03:09 -07003495
Michael Chanbb4f98a2008-06-19 16:38:19 -07003496 if (bnx2_get_hw_rx_cons(bnapi) != rxr->rx_cons)
Michael Chan35efa7c2007-12-20 19:56:37 -08003497 work_done += bnx2_rx_int(bp, bnapi, budget - work_done);
Jeff Garzik6aa20a22006-09-13 13:24:59 -04003498
David S. Miller6f535762007-10-11 18:08:29 -07003499 return work_done;
3500}
Michael Chanf4e418f2005-11-04 08:53:48 -08003501
Michael Chanf0ea2e62008-06-19 16:41:57 -07003502static int bnx2_poll_msix(struct napi_struct *napi, int budget)
3503{
3504 struct bnx2_napi *bnapi = container_of(napi, struct bnx2_napi, napi);
3505 struct bnx2 *bp = bnapi->bp;
3506 int work_done = 0;
3507 struct status_block_msix *sblk = bnapi->status_blk.msix;
3508
3509 while (1) {
3510 work_done = bnx2_poll_work(bp, bnapi, work_done, budget);
3511 if (unlikely(work_done >= budget))
3512 break;
3513
3514 bnapi->last_status_idx = sblk->status_idx;
3515 /* status idx must be read before checking for more work. */
3516 rmb();
3517 if (likely(!bnx2_has_fast_work(bnapi))) {
3518
Ben Hutchings288379f2009-01-19 16:43:59 -08003519 napi_complete(napi);
Michael Chane503e062012-12-06 10:33:08 +00003520 BNX2_WR(bp, BNX2_PCICFG_INT_ACK_CMD, bnapi->int_num |
3521 BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
3522 bnapi->last_status_idx);
Michael Chanf0ea2e62008-06-19 16:41:57 -07003523 break;
3524 }
3525 }
3526 return work_done;
3527}
3528
David S. Miller6f535762007-10-11 18:08:29 -07003529static int bnx2_poll(struct napi_struct *napi, int budget)
3530{
Michael Chan35efa7c2007-12-20 19:56:37 -08003531 struct bnx2_napi *bnapi = container_of(napi, struct bnx2_napi, napi);
3532 struct bnx2 *bp = bnapi->bp;
David S. Miller6f535762007-10-11 18:08:29 -07003533 int work_done = 0;
Michael Chan43e80b82008-06-19 16:41:08 -07003534 struct status_block *sblk = bnapi->status_blk.msi;
David S. Miller6f535762007-10-11 18:08:29 -07003535
3536 while (1) {
Michael Chan43e80b82008-06-19 16:41:08 -07003537 bnx2_poll_link(bp, bnapi);
3538
Michael Chan35efa7c2007-12-20 19:56:37 -08003539 work_done = bnx2_poll_work(bp, bnapi, work_done, budget);
David S. Miller6f535762007-10-11 18:08:29 -07003540
Michael Chan4edd4732009-06-08 18:14:42 -07003541#ifdef BCM_CNIC
3542 bnx2_poll_cnic(bp, bnapi);
3543#endif
3544
Michael Chan35efa7c2007-12-20 19:56:37 -08003545 /* bnapi->last_status_idx is used below to tell the hw how
Michael Chan6dee6422007-10-12 01:40:38 -07003546 * much work has been processed, so we must read it before
3547 * checking for more work.
3548 */
Michael Chan35efa7c2007-12-20 19:56:37 -08003549 bnapi->last_status_idx = sblk->status_idx;
Michael Chanefba0182008-12-03 00:36:15 -08003550
3551 if (unlikely(work_done >= budget))
3552 break;
3553
Michael Chan6dee6422007-10-12 01:40:38 -07003554 rmb();
Michael Chan35efa7c2007-12-20 19:56:37 -08003555 if (likely(!bnx2_has_work(bnapi))) {
Ben Hutchings288379f2009-01-19 16:43:59 -08003556 napi_complete(napi);
David S. Millerf86e82f2008-01-21 17:15:40 -08003557 if (likely(bp->flags & BNX2_FLAG_USING_MSI_OR_MSIX)) {
Michael Chane503e062012-12-06 10:33:08 +00003558 BNX2_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
3559 BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
3560 bnapi->last_status_idx);
Michael Chan6dee6422007-10-12 01:40:38 -07003561 break;
David S. Miller6f535762007-10-11 18:08:29 -07003562 }
Michael Chane503e062012-12-06 10:33:08 +00003563 BNX2_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
3564 BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
3565 BNX2_PCICFG_INT_ACK_CMD_MASK_INT |
3566 bnapi->last_status_idx);
David S. Miller6f535762007-10-11 18:08:29 -07003567
Michael Chane503e062012-12-06 10:33:08 +00003568 BNX2_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
3569 BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
3570 bnapi->last_status_idx);
David S. Miller6f535762007-10-11 18:08:29 -07003571 break;
Michael Chan1269a8a2006-01-23 16:11:03 -08003572 }
Michael Chanb6016b72005-05-26 13:03:09 -07003573 }
3574
Stephen Hemmingerbea33482007-10-03 16:41:36 -07003575 return work_done;
Michael Chanb6016b72005-05-26 13:03:09 -07003576}
3577
Herbert Xu932ff272006-06-09 12:20:56 -07003578/* Called with rtnl_lock from vlan functions and also netif_tx_lock
Michael Chanb6016b72005-05-26 13:03:09 -07003579 * from set_multicast.
3580 */
3581static void
3582bnx2_set_rx_mode(struct net_device *dev)
3583{
Michael Chan972ec0d2006-01-23 16:12:43 -08003584 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07003585 u32 rx_mode, sort_mode;
Jiri Pirkoccffad252009-05-22 23:22:17 +00003586 struct netdev_hw_addr *ha;
Michael Chanb6016b72005-05-26 13:03:09 -07003587 int i;
Michael Chanb6016b72005-05-26 13:03:09 -07003588
Michael Chan9f52b562008-10-09 12:21:46 -07003589 if (!netif_running(dev))
3590 return;
3591
Michael Chanc770a652005-08-25 15:38:39 -07003592 spin_lock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07003593
3594 rx_mode = bp->rx_mode & ~(BNX2_EMAC_RX_MODE_PROMISCUOUS |
3595 BNX2_EMAC_RX_MODE_KEEP_VLAN_TAG);
3596 sort_mode = 1 | BNX2_RPM_SORT_USER0_BC_EN;
Patrick McHardyf6469682013-04-19 02:04:27 +00003597 if (!(dev->features & NETIF_F_HW_VLAN_CTAG_RX) &&
Jesse Gross7d0fd212010-10-20 13:56:09 +00003598 (bp->flags & BNX2_FLAG_CAN_KEEP_VLAN))
Michael Chanb6016b72005-05-26 13:03:09 -07003599 rx_mode |= BNX2_EMAC_RX_MODE_KEEP_VLAN_TAG;
Michael Chanb6016b72005-05-26 13:03:09 -07003600 if (dev->flags & IFF_PROMISC) {
3601 /* Promiscuous mode. */
3602 rx_mode |= BNX2_EMAC_RX_MODE_PROMISCUOUS;
Michael Chan75108732006-11-19 14:06:40 -08003603 sort_mode |= BNX2_RPM_SORT_USER0_PROM_EN |
3604 BNX2_RPM_SORT_USER0_PROM_VLAN;
Michael Chanb6016b72005-05-26 13:03:09 -07003605 }
3606 else if (dev->flags & IFF_ALLMULTI) {
3607 for (i = 0; i < NUM_MC_HASH_REGISTERS; i++) {
Michael Chane503e062012-12-06 10:33:08 +00003608 BNX2_WR(bp, BNX2_EMAC_MULTICAST_HASH0 + (i * 4),
3609 0xffffffff);
Michael Chanb6016b72005-05-26 13:03:09 -07003610 }
3611 sort_mode |= BNX2_RPM_SORT_USER0_MC_EN;
3612 }
3613 else {
3614 /* Accept one or more multicast(s). */
Michael Chanb6016b72005-05-26 13:03:09 -07003615 u32 mc_filter[NUM_MC_HASH_REGISTERS];
3616 u32 regidx;
3617 u32 bit;
3618 u32 crc;
3619
3620 memset(mc_filter, 0, 4 * NUM_MC_HASH_REGISTERS);
3621
Jiri Pirko22bedad32010-04-01 21:22:57 +00003622 netdev_for_each_mc_addr(ha, dev) {
3623 crc = ether_crc_le(ETH_ALEN, ha->addr);
Michael Chanb6016b72005-05-26 13:03:09 -07003624 bit = crc & 0xff;
3625 regidx = (bit & 0xe0) >> 5;
3626 bit &= 0x1f;
3627 mc_filter[regidx] |= (1 << bit);
3628 }
3629
3630 for (i = 0; i < NUM_MC_HASH_REGISTERS; i++) {
Michael Chane503e062012-12-06 10:33:08 +00003631 BNX2_WR(bp, BNX2_EMAC_MULTICAST_HASH0 + (i * 4),
3632 mc_filter[i]);
Michael Chanb6016b72005-05-26 13:03:09 -07003633 }
3634
3635 sort_mode |= BNX2_RPM_SORT_USER0_MC_HSH_EN;
3636 }
3637
Jiri Pirko32e7bfc2010-01-25 13:36:10 -08003638 if (netdev_uc_count(dev) > BNX2_MAX_UNICAST_ADDRESSES) {
Benjamin Li5fcaed02008-07-14 22:39:52 -07003639 rx_mode |= BNX2_EMAC_RX_MODE_PROMISCUOUS;
3640 sort_mode |= BNX2_RPM_SORT_USER0_PROM_EN |
3641 BNX2_RPM_SORT_USER0_PROM_VLAN;
3642 } else if (!(dev->flags & IFF_PROMISC)) {
Benjamin Li5fcaed02008-07-14 22:39:52 -07003643 /* Add all entries into to the match filter list */
Jiri Pirkoccffad252009-05-22 23:22:17 +00003644 i = 0;
Jiri Pirko32e7bfc2010-01-25 13:36:10 -08003645 netdev_for_each_uc_addr(ha, dev) {
Jiri Pirkoccffad252009-05-22 23:22:17 +00003646 bnx2_set_mac_addr(bp, ha->addr,
Benjamin Li5fcaed02008-07-14 22:39:52 -07003647 i + BNX2_START_UNICAST_ADDRESS_INDEX);
3648 sort_mode |= (1 <<
3649 (i + BNX2_START_UNICAST_ADDRESS_INDEX));
Jiri Pirkoccffad252009-05-22 23:22:17 +00003650 i++;
Benjamin Li5fcaed02008-07-14 22:39:52 -07003651 }
3652
3653 }
3654
Michael Chanb6016b72005-05-26 13:03:09 -07003655 if (rx_mode != bp->rx_mode) {
3656 bp->rx_mode = rx_mode;
Michael Chane503e062012-12-06 10:33:08 +00003657 BNX2_WR(bp, BNX2_EMAC_RX_MODE, rx_mode);
Michael Chanb6016b72005-05-26 13:03:09 -07003658 }
3659
Michael Chane503e062012-12-06 10:33:08 +00003660 BNX2_WR(bp, BNX2_RPM_SORT_USER0, 0x0);
3661 BNX2_WR(bp, BNX2_RPM_SORT_USER0, sort_mode);
3662 BNX2_WR(bp, BNX2_RPM_SORT_USER0, sort_mode | BNX2_RPM_SORT_USER0_ENA);
Michael Chanb6016b72005-05-26 13:03:09 -07003663
Michael Chanc770a652005-08-25 15:38:39 -07003664 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07003665}
3666
françois romieu7880b722011-09-30 00:36:52 +00003667static int
Michael Chan57579f72009-04-04 16:51:14 -07003668check_fw_section(const struct firmware *fw,
3669 const struct bnx2_fw_file_section *section,
3670 u32 alignment, bool non_empty)
Michael Chanb6016b72005-05-26 13:03:09 -07003671{
Michael Chan57579f72009-04-04 16:51:14 -07003672 u32 offset = be32_to_cpu(section->offset);
3673 u32 len = be32_to_cpu(section->len);
Michael Chanb6016b72005-05-26 13:03:09 -07003674
Michael Chan57579f72009-04-04 16:51:14 -07003675 if ((offset == 0 && len != 0) || offset >= fw->size || offset & 3)
3676 return -EINVAL;
3677 if ((non_empty && len == 0) || len > fw->size - offset ||
3678 len & (alignment - 1))
3679 return -EINVAL;
3680 return 0;
3681}
3682
françois romieu7880b722011-09-30 00:36:52 +00003683static int
Michael Chan57579f72009-04-04 16:51:14 -07003684check_mips_fw_entry(const struct firmware *fw,
3685 const struct bnx2_mips_fw_file_entry *entry)
3686{
3687 if (check_fw_section(fw, &entry->text, 4, true) ||
3688 check_fw_section(fw, &entry->data, 4, false) ||
3689 check_fw_section(fw, &entry->rodata, 4, false))
3690 return -EINVAL;
3691 return 0;
3692}
3693
françois romieu7880b722011-09-30 00:36:52 +00003694static void bnx2_release_firmware(struct bnx2 *bp)
3695{
3696 if (bp->rv2p_firmware) {
3697 release_firmware(bp->mips_firmware);
3698 release_firmware(bp->rv2p_firmware);
3699 bp->rv2p_firmware = NULL;
3700 }
3701}
3702
3703static int bnx2_request_uncached_firmware(struct bnx2 *bp)
Michael Chan57579f72009-04-04 16:51:14 -07003704{
3705 const char *mips_fw_file, *rv2p_fw_file;
Bastian Blank5ee1c322009-04-08 15:50:07 -07003706 const struct bnx2_mips_fw_file *mips_fw;
3707 const struct bnx2_rv2p_fw_file *rv2p_fw;
Michael Chan57579f72009-04-04 16:51:14 -07003708 int rc;
3709
Michael Chan4ce45e02012-12-06 10:33:10 +00003710 if (BNX2_CHIP(bp) == BNX2_CHIP_5709) {
Michael Chan57579f72009-04-04 16:51:14 -07003711 mips_fw_file = FW_MIPS_FILE_09;
Michael Chan4ce45e02012-12-06 10:33:10 +00003712 if ((BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5709_A0) ||
3713 (BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5709_A1))
Michael Chan078b0732009-08-29 00:02:46 -07003714 rv2p_fw_file = FW_RV2P_FILE_09_Ax;
3715 else
3716 rv2p_fw_file = FW_RV2P_FILE_09;
Michael Chan57579f72009-04-04 16:51:14 -07003717 } else {
3718 mips_fw_file = FW_MIPS_FILE_06;
3719 rv2p_fw_file = FW_RV2P_FILE_06;
3720 }
3721
3722 rc = request_firmware(&bp->mips_firmware, mips_fw_file, &bp->pdev->dev);
3723 if (rc) {
Joe Perches3a9c6a42010-02-17 15:01:51 +00003724 pr_err("Can't load firmware file \"%s\"\n", mips_fw_file);
françois romieu7880b722011-09-30 00:36:52 +00003725 goto out;
Michael Chan57579f72009-04-04 16:51:14 -07003726 }
3727
3728 rc = request_firmware(&bp->rv2p_firmware, rv2p_fw_file, &bp->pdev->dev);
3729 if (rc) {
Joe Perches3a9c6a42010-02-17 15:01:51 +00003730 pr_err("Can't load firmware file \"%s\"\n", rv2p_fw_file);
françois romieu7880b722011-09-30 00:36:52 +00003731 goto err_release_mips_firmware;
Michael Chan57579f72009-04-04 16:51:14 -07003732 }
Bastian Blank5ee1c322009-04-08 15:50:07 -07003733 mips_fw = (const struct bnx2_mips_fw_file *) bp->mips_firmware->data;
3734 rv2p_fw = (const struct bnx2_rv2p_fw_file *) bp->rv2p_firmware->data;
3735 if (bp->mips_firmware->size < sizeof(*mips_fw) ||
3736 check_mips_fw_entry(bp->mips_firmware, &mips_fw->com) ||
3737 check_mips_fw_entry(bp->mips_firmware, &mips_fw->cp) ||
3738 check_mips_fw_entry(bp->mips_firmware, &mips_fw->rxp) ||
3739 check_mips_fw_entry(bp->mips_firmware, &mips_fw->tpat) ||
3740 check_mips_fw_entry(bp->mips_firmware, &mips_fw->txp)) {
Joe Perches3a9c6a42010-02-17 15:01:51 +00003741 pr_err("Firmware file \"%s\" is invalid\n", mips_fw_file);
françois romieu7880b722011-09-30 00:36:52 +00003742 rc = -EINVAL;
3743 goto err_release_firmware;
Michael Chan57579f72009-04-04 16:51:14 -07003744 }
Bastian Blank5ee1c322009-04-08 15:50:07 -07003745 if (bp->rv2p_firmware->size < sizeof(*rv2p_fw) ||
3746 check_fw_section(bp->rv2p_firmware, &rv2p_fw->proc1.rv2p, 8, true) ||
3747 check_fw_section(bp->rv2p_firmware, &rv2p_fw->proc2.rv2p, 8, true)) {
Joe Perches3a9c6a42010-02-17 15:01:51 +00003748 pr_err("Firmware file \"%s\" is invalid\n", rv2p_fw_file);
françois romieu7880b722011-09-30 00:36:52 +00003749 rc = -EINVAL;
3750 goto err_release_firmware;
Michael Chan57579f72009-04-04 16:51:14 -07003751 }
françois romieu7880b722011-09-30 00:36:52 +00003752out:
3753 return rc;
Michael Chan57579f72009-04-04 16:51:14 -07003754
françois romieu7880b722011-09-30 00:36:52 +00003755err_release_firmware:
3756 release_firmware(bp->rv2p_firmware);
3757 bp->rv2p_firmware = NULL;
3758err_release_mips_firmware:
3759 release_firmware(bp->mips_firmware);
3760 goto out;
3761}
3762
3763static int bnx2_request_firmware(struct bnx2 *bp)
3764{
3765 return bp->rv2p_firmware ? 0 : bnx2_request_uncached_firmware(bp);
Michael Chan57579f72009-04-04 16:51:14 -07003766}
3767
3768static u32
3769rv2p_fw_fixup(u32 rv2p_proc, int idx, u32 loc, u32 rv2p_code)
3770{
3771 switch (idx) {
3772 case RV2P_P1_FIXUP_PAGE_SIZE_IDX:
3773 rv2p_code &= ~RV2P_BD_PAGE_SIZE_MSK;
3774 rv2p_code |= RV2P_BD_PAGE_SIZE;
3775 break;
3776 }
3777 return rv2p_code;
3778}
3779
3780static int
3781load_rv2p_fw(struct bnx2 *bp, u32 rv2p_proc,
3782 const struct bnx2_rv2p_fw_file_entry *fw_entry)
3783{
3784 u32 rv2p_code_len, file_offset;
3785 __be32 *rv2p_code;
3786 int i;
3787 u32 val, cmd, addr;
3788
3789 rv2p_code_len = be32_to_cpu(fw_entry->rv2p.len);
3790 file_offset = be32_to_cpu(fw_entry->rv2p.offset);
3791
3792 rv2p_code = (__be32 *)(bp->rv2p_firmware->data + file_offset);
3793
3794 if (rv2p_proc == RV2P_PROC1) {
3795 cmd = BNX2_RV2P_PROC1_ADDR_CMD_RDWR;
3796 addr = BNX2_RV2P_PROC1_ADDR_CMD;
3797 } else {
3798 cmd = BNX2_RV2P_PROC2_ADDR_CMD_RDWR;
3799 addr = BNX2_RV2P_PROC2_ADDR_CMD;
Michael Chand25be1d2008-05-02 16:57:59 -07003800 }
Michael Chanb6016b72005-05-26 13:03:09 -07003801
3802 for (i = 0; i < rv2p_code_len; i += 8) {
Michael Chane503e062012-12-06 10:33:08 +00003803 BNX2_WR(bp, BNX2_RV2P_INSTR_HIGH, be32_to_cpu(*rv2p_code));
Michael Chanb6016b72005-05-26 13:03:09 -07003804 rv2p_code++;
Michael Chane503e062012-12-06 10:33:08 +00003805 BNX2_WR(bp, BNX2_RV2P_INSTR_LOW, be32_to_cpu(*rv2p_code));
Michael Chanb6016b72005-05-26 13:03:09 -07003806 rv2p_code++;
3807
Michael Chan57579f72009-04-04 16:51:14 -07003808 val = (i / 8) | cmd;
Michael Chane503e062012-12-06 10:33:08 +00003809 BNX2_WR(bp, addr, val);
Michael Chan57579f72009-04-04 16:51:14 -07003810 }
3811
3812 rv2p_code = (__be32 *)(bp->rv2p_firmware->data + file_offset);
3813 for (i = 0; i < 8; i++) {
3814 u32 loc, code;
3815
3816 loc = be32_to_cpu(fw_entry->fixup[i]);
3817 if (loc && ((loc * 4) < rv2p_code_len)) {
3818 code = be32_to_cpu(*(rv2p_code + loc - 1));
Michael Chane503e062012-12-06 10:33:08 +00003819 BNX2_WR(bp, BNX2_RV2P_INSTR_HIGH, code);
Michael Chan57579f72009-04-04 16:51:14 -07003820 code = be32_to_cpu(*(rv2p_code + loc));
3821 code = rv2p_fw_fixup(rv2p_proc, i, loc, code);
Michael Chane503e062012-12-06 10:33:08 +00003822 BNX2_WR(bp, BNX2_RV2P_INSTR_LOW, code);
Michael Chan57579f72009-04-04 16:51:14 -07003823
3824 val = (loc / 2) | cmd;
Michael Chane503e062012-12-06 10:33:08 +00003825 BNX2_WR(bp, addr, val);
Michael Chanb6016b72005-05-26 13:03:09 -07003826 }
3827 }
3828
3829 /* Reset the processor, un-stall is done later. */
3830 if (rv2p_proc == RV2P_PROC1) {
Michael Chane503e062012-12-06 10:33:08 +00003831 BNX2_WR(bp, BNX2_RV2P_COMMAND, BNX2_RV2P_COMMAND_PROC1_RESET);
Michael Chanb6016b72005-05-26 13:03:09 -07003832 }
3833 else {
Michael Chane503e062012-12-06 10:33:08 +00003834 BNX2_WR(bp, BNX2_RV2P_COMMAND, BNX2_RV2P_COMMAND_PROC2_RESET);
Michael Chanb6016b72005-05-26 13:03:09 -07003835 }
Michael Chan57579f72009-04-04 16:51:14 -07003836
3837 return 0;
Michael Chanb6016b72005-05-26 13:03:09 -07003838}
3839
Michael Chanaf3ee512006-11-19 14:09:25 -08003840static int
Michael Chan57579f72009-04-04 16:51:14 -07003841load_cpu_fw(struct bnx2 *bp, const struct cpu_reg *cpu_reg,
3842 const struct bnx2_mips_fw_file_entry *fw_entry)
Michael Chanb6016b72005-05-26 13:03:09 -07003843{
Michael Chan57579f72009-04-04 16:51:14 -07003844 u32 addr, len, file_offset;
3845 __be32 *data;
Michael Chanb6016b72005-05-26 13:03:09 -07003846 u32 offset;
3847 u32 val;
3848
3849 /* Halt the CPU. */
Michael Chan2726d6e2008-01-29 21:35:05 -08003850 val = bnx2_reg_rd_ind(bp, cpu_reg->mode);
Michael Chanb6016b72005-05-26 13:03:09 -07003851 val |= cpu_reg->mode_value_halt;
Michael Chan2726d6e2008-01-29 21:35:05 -08003852 bnx2_reg_wr_ind(bp, cpu_reg->mode, val);
3853 bnx2_reg_wr_ind(bp, cpu_reg->state, cpu_reg->state_value_clear);
Michael Chanb6016b72005-05-26 13:03:09 -07003854
3855 /* Load the Text area. */
Michael Chan57579f72009-04-04 16:51:14 -07003856 addr = be32_to_cpu(fw_entry->text.addr);
3857 len = be32_to_cpu(fw_entry->text.len);
3858 file_offset = be32_to_cpu(fw_entry->text.offset);
3859 data = (__be32 *)(bp->mips_firmware->data + file_offset);
3860
3861 offset = cpu_reg->spad_base + (addr - cpu_reg->mips_view_base);
3862 if (len) {
Michael Chanb6016b72005-05-26 13:03:09 -07003863 int j;
3864
Michael Chan57579f72009-04-04 16:51:14 -07003865 for (j = 0; j < (len / 4); j++, offset += 4)
3866 bnx2_reg_wr_ind(bp, offset, be32_to_cpu(data[j]));
Michael Chanb6016b72005-05-26 13:03:09 -07003867 }
3868
3869 /* Load the Data area. */
Michael Chan57579f72009-04-04 16:51:14 -07003870 addr = be32_to_cpu(fw_entry->data.addr);
3871 len = be32_to_cpu(fw_entry->data.len);
3872 file_offset = be32_to_cpu(fw_entry->data.offset);
3873 data = (__be32 *)(bp->mips_firmware->data + file_offset);
3874
3875 offset = cpu_reg->spad_base + (addr - cpu_reg->mips_view_base);
3876 if (len) {
Michael Chanb6016b72005-05-26 13:03:09 -07003877 int j;
3878
Michael Chan57579f72009-04-04 16:51:14 -07003879 for (j = 0; j < (len / 4); j++, offset += 4)
3880 bnx2_reg_wr_ind(bp, offset, be32_to_cpu(data[j]));
Michael Chanb6016b72005-05-26 13:03:09 -07003881 }
3882
3883 /* Load the Read-Only area. */
Michael Chan57579f72009-04-04 16:51:14 -07003884 addr = be32_to_cpu(fw_entry->rodata.addr);
3885 len = be32_to_cpu(fw_entry->rodata.len);
3886 file_offset = be32_to_cpu(fw_entry->rodata.offset);
3887 data = (__be32 *)(bp->mips_firmware->data + file_offset);
3888
3889 offset = cpu_reg->spad_base + (addr - cpu_reg->mips_view_base);
3890 if (len) {
Michael Chanb6016b72005-05-26 13:03:09 -07003891 int j;
3892
Michael Chan57579f72009-04-04 16:51:14 -07003893 for (j = 0; j < (len / 4); j++, offset += 4)
3894 bnx2_reg_wr_ind(bp, offset, be32_to_cpu(data[j]));
Michael Chanb6016b72005-05-26 13:03:09 -07003895 }
3896
3897 /* Clear the pre-fetch instruction. */
Michael Chan2726d6e2008-01-29 21:35:05 -08003898 bnx2_reg_wr_ind(bp, cpu_reg->inst, 0);
Michael Chan57579f72009-04-04 16:51:14 -07003899
3900 val = be32_to_cpu(fw_entry->start_addr);
3901 bnx2_reg_wr_ind(bp, cpu_reg->pc, val);
Michael Chanb6016b72005-05-26 13:03:09 -07003902
3903 /* Start the CPU. */
Michael Chan2726d6e2008-01-29 21:35:05 -08003904 val = bnx2_reg_rd_ind(bp, cpu_reg->mode);
Michael Chanb6016b72005-05-26 13:03:09 -07003905 val &= ~cpu_reg->mode_value_halt;
Michael Chan2726d6e2008-01-29 21:35:05 -08003906 bnx2_reg_wr_ind(bp, cpu_reg->state, cpu_reg->state_value_clear);
3907 bnx2_reg_wr_ind(bp, cpu_reg->mode, val);
Michael Chanaf3ee512006-11-19 14:09:25 -08003908
3909 return 0;
Michael Chanb6016b72005-05-26 13:03:09 -07003910}
3911
Michael Chanfba9fe92006-06-12 22:21:25 -07003912static int
Michael Chanb6016b72005-05-26 13:03:09 -07003913bnx2_init_cpus(struct bnx2 *bp)
3914{
Michael Chan57579f72009-04-04 16:51:14 -07003915 const struct bnx2_mips_fw_file *mips_fw =
3916 (const struct bnx2_mips_fw_file *) bp->mips_firmware->data;
3917 const struct bnx2_rv2p_fw_file *rv2p_fw =
3918 (const struct bnx2_rv2p_fw_file *) bp->rv2p_firmware->data;
3919 int rc;
Michael Chanb6016b72005-05-26 13:03:09 -07003920
3921 /* Initialize the RV2P processor. */
Michael Chan57579f72009-04-04 16:51:14 -07003922 load_rv2p_fw(bp, RV2P_PROC1, &rv2p_fw->proc1);
3923 load_rv2p_fw(bp, RV2P_PROC2, &rv2p_fw->proc2);
Michael Chanb6016b72005-05-26 13:03:09 -07003924
3925 /* Initialize the RX Processor. */
Michael Chan57579f72009-04-04 16:51:14 -07003926 rc = load_cpu_fw(bp, &cpu_reg_rxp, &mips_fw->rxp);
Michael Chanfba9fe92006-06-12 22:21:25 -07003927 if (rc)
3928 goto init_cpu_err;
3929
Michael Chanb6016b72005-05-26 13:03:09 -07003930 /* Initialize the TX Processor. */
Michael Chan57579f72009-04-04 16:51:14 -07003931 rc = load_cpu_fw(bp, &cpu_reg_txp, &mips_fw->txp);
Michael Chanfba9fe92006-06-12 22:21:25 -07003932 if (rc)
3933 goto init_cpu_err;
3934
Michael Chanb6016b72005-05-26 13:03:09 -07003935 /* Initialize the TX Patch-up Processor. */
Michael Chan57579f72009-04-04 16:51:14 -07003936 rc = load_cpu_fw(bp, &cpu_reg_tpat, &mips_fw->tpat);
Michael Chanfba9fe92006-06-12 22:21:25 -07003937 if (rc)
3938 goto init_cpu_err;
3939
Michael Chanb6016b72005-05-26 13:03:09 -07003940 /* Initialize the Completion Processor. */
Michael Chan57579f72009-04-04 16:51:14 -07003941 rc = load_cpu_fw(bp, &cpu_reg_com, &mips_fw->com);
Michael Chanfba9fe92006-06-12 22:21:25 -07003942 if (rc)
3943 goto init_cpu_err;
3944
Michael Chand43584c2006-11-19 14:14:35 -08003945 /* Initialize the Command Processor. */
Michael Chan57579f72009-04-04 16:51:14 -07003946 rc = load_cpu_fw(bp, &cpu_reg_cp, &mips_fw->cp);
Michael Chan110d0ef2007-12-12 11:18:34 -08003947
Michael Chanfba9fe92006-06-12 22:21:25 -07003948init_cpu_err:
Michael Chanfba9fe92006-06-12 22:21:25 -07003949 return rc;
Michael Chanb6016b72005-05-26 13:03:09 -07003950}
3951
Michael Chanb6a23e92013-08-06 15:50:09 -07003952static void
3953bnx2_setup_wol(struct bnx2 *bp)
3954{
3955 int i;
3956 u32 val, wol_msg;
3957
3958 if (bp->wol) {
3959 u32 advertising;
3960 u8 autoneg;
3961
3962 autoneg = bp->autoneg;
3963 advertising = bp->advertising;
3964
3965 if (bp->phy_port == PORT_TP) {
3966 bp->autoneg = AUTONEG_SPEED;
3967 bp->advertising = ADVERTISED_10baseT_Half |
3968 ADVERTISED_10baseT_Full |
3969 ADVERTISED_100baseT_Half |
3970 ADVERTISED_100baseT_Full |
3971 ADVERTISED_Autoneg;
3972 }
3973
3974 spin_lock_bh(&bp->phy_lock);
3975 bnx2_setup_phy(bp, bp->phy_port);
3976 spin_unlock_bh(&bp->phy_lock);
3977
3978 bp->autoneg = autoneg;
3979 bp->advertising = advertising;
3980
3981 bnx2_set_mac_addr(bp, bp->dev->dev_addr, 0);
3982
3983 val = BNX2_RD(bp, BNX2_EMAC_MODE);
3984
3985 /* Enable port mode. */
3986 val &= ~BNX2_EMAC_MODE_PORT;
3987 val |= BNX2_EMAC_MODE_MPKT_RCVD |
3988 BNX2_EMAC_MODE_ACPI_RCVD |
3989 BNX2_EMAC_MODE_MPKT;
3990 if (bp->phy_port == PORT_TP) {
3991 val |= BNX2_EMAC_MODE_PORT_MII;
3992 } else {
3993 val |= BNX2_EMAC_MODE_PORT_GMII;
3994 if (bp->line_speed == SPEED_2500)
3995 val |= BNX2_EMAC_MODE_25G_MODE;
3996 }
3997
3998 BNX2_WR(bp, BNX2_EMAC_MODE, val);
3999
4000 /* receive all multicast */
4001 for (i = 0; i < NUM_MC_HASH_REGISTERS; i++) {
4002 BNX2_WR(bp, BNX2_EMAC_MULTICAST_HASH0 + (i * 4),
4003 0xffffffff);
4004 }
4005 BNX2_WR(bp, BNX2_EMAC_RX_MODE, BNX2_EMAC_RX_MODE_SORT_MODE);
4006
4007 val = 1 | BNX2_RPM_SORT_USER0_BC_EN | BNX2_RPM_SORT_USER0_MC_EN;
4008 BNX2_WR(bp, BNX2_RPM_SORT_USER0, 0x0);
4009 BNX2_WR(bp, BNX2_RPM_SORT_USER0, val);
4010 BNX2_WR(bp, BNX2_RPM_SORT_USER0, val | BNX2_RPM_SORT_USER0_ENA);
4011
4012 /* Need to enable EMAC and RPM for WOL. */
4013 BNX2_WR(bp, BNX2_MISC_ENABLE_SET_BITS,
4014 BNX2_MISC_ENABLE_SET_BITS_RX_PARSER_MAC_ENABLE |
4015 BNX2_MISC_ENABLE_SET_BITS_TX_HEADER_Q_ENABLE |
4016 BNX2_MISC_ENABLE_SET_BITS_EMAC_ENABLE);
4017
4018 val = BNX2_RD(bp, BNX2_RPM_CONFIG);
4019 val &= ~BNX2_RPM_CONFIG_ACPI_ENA;
4020 BNX2_WR(bp, BNX2_RPM_CONFIG, val);
4021
4022 wol_msg = BNX2_DRV_MSG_CODE_SUSPEND_WOL;
4023 } else {
4024 wol_msg = BNX2_DRV_MSG_CODE_SUSPEND_NO_WOL;
4025 }
4026
Michael Chana8d9bc22014-03-09 15:45:32 -08004027 if (!(bp->flags & BNX2_FLAG_NO_WOL)) {
4028 u32 val;
4029
4030 wol_msg |= BNX2_DRV_MSG_DATA_WAIT3;
4031 if (bp->fw_last_msg || BNX2_CHIP(bp) != BNX2_CHIP_5709) {
4032 bnx2_fw_sync(bp, wol_msg, 1, 0);
4033 return;
4034 }
4035 /* Tell firmware not to power down the PHY yet, otherwise
4036 * the chip will take a long time to respond to MMIO reads.
4037 */
4038 val = bnx2_shmem_rd(bp, BNX2_PORT_FEATURE);
4039 bnx2_shmem_wr(bp, BNX2_PORT_FEATURE,
4040 val | BNX2_PORT_FEATURE_ASF_ENABLED);
4041 bnx2_fw_sync(bp, wol_msg, 1, 0);
4042 bnx2_shmem_wr(bp, BNX2_PORT_FEATURE, val);
4043 }
Michael Chanb6a23e92013-08-06 15:50:09 -07004044
4045}
4046
Michael Chanb6016b72005-05-26 13:03:09 -07004047static int
Pavel Machek829ca9a2005-09-03 15:56:56 -07004048bnx2_set_power_state(struct bnx2 *bp, pci_power_t state)
Michael Chanb6016b72005-05-26 13:03:09 -07004049{
Michael Chanb6016b72005-05-26 13:03:09 -07004050 switch (state) {
Pavel Machek829ca9a2005-09-03 15:56:56 -07004051 case PCI_D0: {
Michael Chanb6016b72005-05-26 13:03:09 -07004052 u32 val;
4053
Michael Chan6d5e85c2013-08-06 15:50:08 -07004054 pci_enable_wake(bp->pdev, PCI_D0, false);
4055 pci_set_power_state(bp->pdev, PCI_D0);
Michael Chanb6016b72005-05-26 13:03:09 -07004056
Michael Chane503e062012-12-06 10:33:08 +00004057 val = BNX2_RD(bp, BNX2_EMAC_MODE);
Michael Chanb6016b72005-05-26 13:03:09 -07004058 val |= BNX2_EMAC_MODE_MPKT_RCVD | BNX2_EMAC_MODE_ACPI_RCVD;
4059 val &= ~BNX2_EMAC_MODE_MPKT;
Michael Chane503e062012-12-06 10:33:08 +00004060 BNX2_WR(bp, BNX2_EMAC_MODE, val);
Michael Chanb6016b72005-05-26 13:03:09 -07004061
Michael Chane503e062012-12-06 10:33:08 +00004062 val = BNX2_RD(bp, BNX2_RPM_CONFIG);
Michael Chanb6016b72005-05-26 13:03:09 -07004063 val &= ~BNX2_RPM_CONFIG_ACPI_ENA;
Michael Chane503e062012-12-06 10:33:08 +00004064 BNX2_WR(bp, BNX2_RPM_CONFIG, val);
Michael Chanb6016b72005-05-26 13:03:09 -07004065 break;
4066 }
Pavel Machek829ca9a2005-09-03 15:56:56 -07004067 case PCI_D3hot: {
Michael Chanb6a23e92013-08-06 15:50:09 -07004068 bnx2_setup_wol(bp);
Michael Chan6d5e85c2013-08-06 15:50:08 -07004069 pci_wake_from_d3(bp->pdev, bp->wol);
Michael Chan4ce45e02012-12-06 10:33:10 +00004070 if ((BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5706_A0) ||
4071 (BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5706_A1)) {
Michael Chanb6016b72005-05-26 13:03:09 -07004072
4073 if (bp->wol)
Michael Chan6d5e85c2013-08-06 15:50:08 -07004074 pci_set_power_state(bp->pdev, PCI_D3hot);
Michael Chana8d9bc22014-03-09 15:45:32 -08004075 break;
4076
Michael Chanb6016b72005-05-26 13:03:09 -07004077 }
Michael Chana8d9bc22014-03-09 15:45:32 -08004078 if (!bp->fw_last_msg && BNX2_CHIP(bp) == BNX2_CHIP_5709) {
4079 u32 val;
4080
4081 /* Tell firmware not to power down the PHY yet,
4082 * otherwise the other port may not respond to
4083 * MMIO reads.
4084 */
4085 val = bnx2_shmem_rd(bp, BNX2_BC_STATE_CONDITION);
4086 val &= ~BNX2_CONDITION_PM_STATE_MASK;
4087 val |= BNX2_CONDITION_PM_STATE_UNPREP;
4088 bnx2_shmem_wr(bp, BNX2_BC_STATE_CONDITION, val);
4089 }
4090 pci_set_power_state(bp->pdev, PCI_D3hot);
Michael Chanb6016b72005-05-26 13:03:09 -07004091
4092 /* No more memory access after this point until
4093 * device is brought back to D0.
4094 */
Michael Chanb6016b72005-05-26 13:03:09 -07004095 break;
4096 }
4097 default:
4098 return -EINVAL;
4099 }
4100 return 0;
4101}
4102
4103static int
4104bnx2_acquire_nvram_lock(struct bnx2 *bp)
4105{
4106 u32 val;
4107 int j;
4108
4109 /* Request access to the flash interface. */
Michael Chane503e062012-12-06 10:33:08 +00004110 BNX2_WR(bp, BNX2_NVM_SW_ARB, BNX2_NVM_SW_ARB_ARB_REQ_SET2);
Michael Chanb6016b72005-05-26 13:03:09 -07004111 for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) {
Michael Chane503e062012-12-06 10:33:08 +00004112 val = BNX2_RD(bp, BNX2_NVM_SW_ARB);
Michael Chanb6016b72005-05-26 13:03:09 -07004113 if (val & BNX2_NVM_SW_ARB_ARB_ARB2)
4114 break;
4115
4116 udelay(5);
4117 }
4118
4119 if (j >= NVRAM_TIMEOUT_COUNT)
4120 return -EBUSY;
4121
4122 return 0;
4123}
4124
4125static int
4126bnx2_release_nvram_lock(struct bnx2 *bp)
4127{
4128 int j;
4129 u32 val;
4130
4131 /* Relinquish nvram interface. */
Michael Chane503e062012-12-06 10:33:08 +00004132 BNX2_WR(bp, BNX2_NVM_SW_ARB, BNX2_NVM_SW_ARB_ARB_REQ_CLR2);
Michael Chanb6016b72005-05-26 13:03:09 -07004133
4134 for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) {
Michael Chane503e062012-12-06 10:33:08 +00004135 val = BNX2_RD(bp, BNX2_NVM_SW_ARB);
Michael Chanb6016b72005-05-26 13:03:09 -07004136 if (!(val & BNX2_NVM_SW_ARB_ARB_ARB2))
4137 break;
4138
4139 udelay(5);
4140 }
4141
4142 if (j >= NVRAM_TIMEOUT_COUNT)
4143 return -EBUSY;
4144
4145 return 0;
4146}
4147
4148
4149static int
4150bnx2_enable_nvram_write(struct bnx2 *bp)
4151{
4152 u32 val;
4153
Michael Chane503e062012-12-06 10:33:08 +00004154 val = BNX2_RD(bp, BNX2_MISC_CFG);
4155 BNX2_WR(bp, BNX2_MISC_CFG, val | BNX2_MISC_CFG_NVM_WR_EN_PCI);
Michael Chanb6016b72005-05-26 13:03:09 -07004156
Michael Chane30372c2007-07-16 18:26:23 -07004157 if (bp->flash_info->flags & BNX2_NV_WREN) {
Michael Chanb6016b72005-05-26 13:03:09 -07004158 int j;
4159
Michael Chane503e062012-12-06 10:33:08 +00004160 BNX2_WR(bp, BNX2_NVM_COMMAND, BNX2_NVM_COMMAND_DONE);
4161 BNX2_WR(bp, BNX2_NVM_COMMAND,
4162 BNX2_NVM_COMMAND_WREN | BNX2_NVM_COMMAND_DOIT);
Michael Chanb6016b72005-05-26 13:03:09 -07004163
4164 for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) {
4165 udelay(5);
4166
Michael Chane503e062012-12-06 10:33:08 +00004167 val = BNX2_RD(bp, BNX2_NVM_COMMAND);
Michael Chanb6016b72005-05-26 13:03:09 -07004168 if (val & BNX2_NVM_COMMAND_DONE)
4169 break;
4170 }
4171
4172 if (j >= NVRAM_TIMEOUT_COUNT)
4173 return -EBUSY;
4174 }
4175 return 0;
4176}
4177
4178static void
4179bnx2_disable_nvram_write(struct bnx2 *bp)
4180{
4181 u32 val;
4182
Michael Chane503e062012-12-06 10:33:08 +00004183 val = BNX2_RD(bp, BNX2_MISC_CFG);
4184 BNX2_WR(bp, BNX2_MISC_CFG, val & ~BNX2_MISC_CFG_NVM_WR_EN);
Michael Chanb6016b72005-05-26 13:03:09 -07004185}
4186
4187
4188static void
4189bnx2_enable_nvram_access(struct bnx2 *bp)
4190{
4191 u32 val;
4192
Michael Chane503e062012-12-06 10:33:08 +00004193 val = BNX2_RD(bp, BNX2_NVM_ACCESS_ENABLE);
Michael Chanb6016b72005-05-26 13:03:09 -07004194 /* Enable both bits, even on read. */
Michael Chane503e062012-12-06 10:33:08 +00004195 BNX2_WR(bp, BNX2_NVM_ACCESS_ENABLE,
4196 val | BNX2_NVM_ACCESS_ENABLE_EN | BNX2_NVM_ACCESS_ENABLE_WR_EN);
Michael Chanb6016b72005-05-26 13:03:09 -07004197}
4198
4199static void
4200bnx2_disable_nvram_access(struct bnx2 *bp)
4201{
4202 u32 val;
4203
Michael Chane503e062012-12-06 10:33:08 +00004204 val = BNX2_RD(bp, BNX2_NVM_ACCESS_ENABLE);
Michael Chanb6016b72005-05-26 13:03:09 -07004205 /* Disable both bits, even after read. */
Michael Chane503e062012-12-06 10:33:08 +00004206 BNX2_WR(bp, BNX2_NVM_ACCESS_ENABLE,
Michael Chanb6016b72005-05-26 13:03:09 -07004207 val & ~(BNX2_NVM_ACCESS_ENABLE_EN |
4208 BNX2_NVM_ACCESS_ENABLE_WR_EN));
4209}
4210
4211static int
4212bnx2_nvram_erase_page(struct bnx2 *bp, u32 offset)
4213{
4214 u32 cmd;
4215 int j;
4216
Michael Chane30372c2007-07-16 18:26:23 -07004217 if (bp->flash_info->flags & BNX2_NV_BUFFERED)
Michael Chanb6016b72005-05-26 13:03:09 -07004218 /* Buffered flash, no erase needed */
4219 return 0;
4220
4221 /* Build an erase command */
4222 cmd = BNX2_NVM_COMMAND_ERASE | BNX2_NVM_COMMAND_WR |
4223 BNX2_NVM_COMMAND_DOIT;
4224
4225 /* Need to clear DONE bit separately. */
Michael Chane503e062012-12-06 10:33:08 +00004226 BNX2_WR(bp, BNX2_NVM_COMMAND, BNX2_NVM_COMMAND_DONE);
Michael Chanb6016b72005-05-26 13:03:09 -07004227
4228 /* Address of the NVRAM to read from. */
Michael Chane503e062012-12-06 10:33:08 +00004229 BNX2_WR(bp, BNX2_NVM_ADDR, offset & BNX2_NVM_ADDR_NVM_ADDR_VALUE);
Michael Chanb6016b72005-05-26 13:03:09 -07004230
4231 /* Issue an erase command. */
Michael Chane503e062012-12-06 10:33:08 +00004232 BNX2_WR(bp, BNX2_NVM_COMMAND, cmd);
Michael Chanb6016b72005-05-26 13:03:09 -07004233
4234 /* Wait for completion. */
4235 for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) {
4236 u32 val;
4237
4238 udelay(5);
4239
Michael Chane503e062012-12-06 10:33:08 +00004240 val = BNX2_RD(bp, BNX2_NVM_COMMAND);
Michael Chanb6016b72005-05-26 13:03:09 -07004241 if (val & BNX2_NVM_COMMAND_DONE)
4242 break;
4243 }
4244
4245 if (j >= NVRAM_TIMEOUT_COUNT)
4246 return -EBUSY;
4247
4248 return 0;
4249}
4250
4251static int
4252bnx2_nvram_read_dword(struct bnx2 *bp, u32 offset, u8 *ret_val, u32 cmd_flags)
4253{
4254 u32 cmd;
4255 int j;
4256
4257 /* Build the command word. */
4258 cmd = BNX2_NVM_COMMAND_DOIT | cmd_flags;
4259
Michael Chane30372c2007-07-16 18:26:23 -07004260 /* Calculate an offset of a buffered flash, not needed for 5709. */
4261 if (bp->flash_info->flags & BNX2_NV_TRANSLATE) {
Michael Chanb6016b72005-05-26 13:03:09 -07004262 offset = ((offset / bp->flash_info->page_size) <<
4263 bp->flash_info->page_bits) +
4264 (offset % bp->flash_info->page_size);
4265 }
4266
4267 /* Need to clear DONE bit separately. */
Michael Chane503e062012-12-06 10:33:08 +00004268 BNX2_WR(bp, BNX2_NVM_COMMAND, BNX2_NVM_COMMAND_DONE);
Michael Chanb6016b72005-05-26 13:03:09 -07004269
4270 /* Address of the NVRAM to read from. */
Michael Chane503e062012-12-06 10:33:08 +00004271 BNX2_WR(bp, BNX2_NVM_ADDR, offset & BNX2_NVM_ADDR_NVM_ADDR_VALUE);
Michael Chanb6016b72005-05-26 13:03:09 -07004272
4273 /* Issue a read command. */
Michael Chane503e062012-12-06 10:33:08 +00004274 BNX2_WR(bp, BNX2_NVM_COMMAND, cmd);
Michael Chanb6016b72005-05-26 13:03:09 -07004275
4276 /* Wait for completion. */
4277 for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) {
4278 u32 val;
4279
4280 udelay(5);
4281
Michael Chane503e062012-12-06 10:33:08 +00004282 val = BNX2_RD(bp, BNX2_NVM_COMMAND);
Michael Chanb6016b72005-05-26 13:03:09 -07004283 if (val & BNX2_NVM_COMMAND_DONE) {
Michael Chane503e062012-12-06 10:33:08 +00004284 __be32 v = cpu_to_be32(BNX2_RD(bp, BNX2_NVM_READ));
Al Virob491edd2007-12-22 19:44:51 +00004285 memcpy(ret_val, &v, 4);
Michael Chanb6016b72005-05-26 13:03:09 -07004286 break;
4287 }
4288 }
4289 if (j >= NVRAM_TIMEOUT_COUNT)
4290 return -EBUSY;
4291
4292 return 0;
4293}
4294
4295
4296static int
4297bnx2_nvram_write_dword(struct bnx2 *bp, u32 offset, u8 *val, u32 cmd_flags)
4298{
Al Virob491edd2007-12-22 19:44:51 +00004299 u32 cmd;
4300 __be32 val32;
Michael Chanb6016b72005-05-26 13:03:09 -07004301 int j;
4302
4303 /* Build the command word. */
4304 cmd = BNX2_NVM_COMMAND_DOIT | BNX2_NVM_COMMAND_WR | cmd_flags;
4305
Michael Chane30372c2007-07-16 18:26:23 -07004306 /* Calculate an offset of a buffered flash, not needed for 5709. */
4307 if (bp->flash_info->flags & BNX2_NV_TRANSLATE) {
Michael Chanb6016b72005-05-26 13:03:09 -07004308 offset = ((offset / bp->flash_info->page_size) <<
4309 bp->flash_info->page_bits) +
4310 (offset % bp->flash_info->page_size);
4311 }
4312
4313 /* Need to clear DONE bit separately. */
Michael Chane503e062012-12-06 10:33:08 +00004314 BNX2_WR(bp, BNX2_NVM_COMMAND, BNX2_NVM_COMMAND_DONE);
Michael Chanb6016b72005-05-26 13:03:09 -07004315
4316 memcpy(&val32, val, 4);
Michael Chanb6016b72005-05-26 13:03:09 -07004317
4318 /* Write the data. */
Michael Chane503e062012-12-06 10:33:08 +00004319 BNX2_WR(bp, BNX2_NVM_WRITE, be32_to_cpu(val32));
Michael Chanb6016b72005-05-26 13:03:09 -07004320
4321 /* Address of the NVRAM to write to. */
Michael Chane503e062012-12-06 10:33:08 +00004322 BNX2_WR(bp, BNX2_NVM_ADDR, offset & BNX2_NVM_ADDR_NVM_ADDR_VALUE);
Michael Chanb6016b72005-05-26 13:03:09 -07004323
4324 /* Issue the write command. */
Michael Chane503e062012-12-06 10:33:08 +00004325 BNX2_WR(bp, BNX2_NVM_COMMAND, cmd);
Michael Chanb6016b72005-05-26 13:03:09 -07004326
4327 /* Wait for completion. */
4328 for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) {
4329 udelay(5);
4330
Michael Chane503e062012-12-06 10:33:08 +00004331 if (BNX2_RD(bp, BNX2_NVM_COMMAND) & BNX2_NVM_COMMAND_DONE)
Michael Chanb6016b72005-05-26 13:03:09 -07004332 break;
4333 }
4334 if (j >= NVRAM_TIMEOUT_COUNT)
4335 return -EBUSY;
4336
4337 return 0;
4338}
4339
4340static int
4341bnx2_init_nvram(struct bnx2 *bp)
4342{
4343 u32 val;
Michael Chane30372c2007-07-16 18:26:23 -07004344 int j, entry_count, rc = 0;
Michael Chan0ced9d02009-08-21 16:20:49 +00004345 const struct flash_spec *flash;
Michael Chanb6016b72005-05-26 13:03:09 -07004346
Michael Chan4ce45e02012-12-06 10:33:10 +00004347 if (BNX2_CHIP(bp) == BNX2_CHIP_5709) {
Michael Chane30372c2007-07-16 18:26:23 -07004348 bp->flash_info = &flash_5709;
4349 goto get_flash_size;
4350 }
4351
Michael Chanb6016b72005-05-26 13:03:09 -07004352 /* Determine the selected interface. */
Michael Chane503e062012-12-06 10:33:08 +00004353 val = BNX2_RD(bp, BNX2_NVM_CFG1);
Michael Chanb6016b72005-05-26 13:03:09 -07004354
Denis Chengff8ac602007-09-02 18:30:18 +08004355 entry_count = ARRAY_SIZE(flash_table);
Michael Chanb6016b72005-05-26 13:03:09 -07004356
Michael Chanb6016b72005-05-26 13:03:09 -07004357 if (val & 0x40000000) {
4358
4359 /* Flash interface has been reconfigured */
4360 for (j = 0, flash = &flash_table[0]; j < entry_count;
Michael Chan37137702005-11-04 08:49:17 -08004361 j++, flash++) {
4362 if ((val & FLASH_BACKUP_STRAP_MASK) ==
4363 (flash->config1 & FLASH_BACKUP_STRAP_MASK)) {
Michael Chanb6016b72005-05-26 13:03:09 -07004364 bp->flash_info = flash;
4365 break;
4366 }
4367 }
4368 }
4369 else {
Michael Chan37137702005-11-04 08:49:17 -08004370 u32 mask;
Michael Chanb6016b72005-05-26 13:03:09 -07004371 /* Not yet been reconfigured */
4372
Michael Chan37137702005-11-04 08:49:17 -08004373 if (val & (1 << 23))
4374 mask = FLASH_BACKUP_STRAP_MASK;
4375 else
4376 mask = FLASH_STRAP_MASK;
4377
Michael Chanb6016b72005-05-26 13:03:09 -07004378 for (j = 0, flash = &flash_table[0]; j < entry_count;
4379 j++, flash++) {
4380
Michael Chan37137702005-11-04 08:49:17 -08004381 if ((val & mask) == (flash->strapping & mask)) {
Michael Chanb6016b72005-05-26 13:03:09 -07004382 bp->flash_info = flash;
4383
4384 /* Request access to the flash interface. */
4385 if ((rc = bnx2_acquire_nvram_lock(bp)) != 0)
4386 return rc;
4387
4388 /* Enable access to flash interface */
4389 bnx2_enable_nvram_access(bp);
4390
4391 /* Reconfigure the flash interface */
Michael Chane503e062012-12-06 10:33:08 +00004392 BNX2_WR(bp, BNX2_NVM_CFG1, flash->config1);
4393 BNX2_WR(bp, BNX2_NVM_CFG2, flash->config2);
4394 BNX2_WR(bp, BNX2_NVM_CFG3, flash->config3);
4395 BNX2_WR(bp, BNX2_NVM_WRITE1, flash->write1);
Michael Chanb6016b72005-05-26 13:03:09 -07004396
4397 /* Disable access to flash interface */
4398 bnx2_disable_nvram_access(bp);
4399 bnx2_release_nvram_lock(bp);
4400
4401 break;
4402 }
4403 }
4404 } /* if (val & 0x40000000) */
4405
4406 if (j == entry_count) {
4407 bp->flash_info = NULL;
Joe Perches3a9c6a42010-02-17 15:01:51 +00004408 pr_alert("Unknown flash/EEPROM type\n");
Michael Chan1122db72006-01-23 16:11:42 -08004409 return -ENODEV;
Michael Chanb6016b72005-05-26 13:03:09 -07004410 }
4411
Michael Chane30372c2007-07-16 18:26:23 -07004412get_flash_size:
Michael Chan2726d6e2008-01-29 21:35:05 -08004413 val = bnx2_shmem_rd(bp, BNX2_SHARED_HW_CFG_CONFIG2);
Michael Chan1122db72006-01-23 16:11:42 -08004414 val &= BNX2_SHARED_HW_CFG2_NVM_SIZE_MASK;
4415 if (val)
4416 bp->flash_size = val;
4417 else
4418 bp->flash_size = bp->flash_info->total_size;
4419
Michael Chanb6016b72005-05-26 13:03:09 -07004420 return rc;
4421}
4422
4423static int
4424bnx2_nvram_read(struct bnx2 *bp, u32 offset, u8 *ret_buf,
4425 int buf_size)
4426{
4427 int rc = 0;
4428 u32 cmd_flags, offset32, len32, extra;
4429
4430 if (buf_size == 0)
4431 return 0;
4432
4433 /* Request access to the flash interface. */
4434 if ((rc = bnx2_acquire_nvram_lock(bp)) != 0)
4435 return rc;
4436
4437 /* Enable access to flash interface */
4438 bnx2_enable_nvram_access(bp);
4439
4440 len32 = buf_size;
4441 offset32 = offset;
4442 extra = 0;
4443
4444 cmd_flags = 0;
4445
4446 if (offset32 & 3) {
4447 u8 buf[4];
4448 u32 pre_len;
4449
4450 offset32 &= ~3;
4451 pre_len = 4 - (offset & 3);
4452
4453 if (pre_len >= len32) {
4454 pre_len = len32;
4455 cmd_flags = BNX2_NVM_COMMAND_FIRST |
4456 BNX2_NVM_COMMAND_LAST;
4457 }
4458 else {
4459 cmd_flags = BNX2_NVM_COMMAND_FIRST;
4460 }
4461
4462 rc = bnx2_nvram_read_dword(bp, offset32, buf, cmd_flags);
4463
4464 if (rc)
4465 return rc;
4466
4467 memcpy(ret_buf, buf + (offset & 3), pre_len);
4468
4469 offset32 += 4;
4470 ret_buf += pre_len;
4471 len32 -= pre_len;
4472 }
4473 if (len32 & 3) {
4474 extra = 4 - (len32 & 3);
4475 len32 = (len32 + 4) & ~3;
4476 }
4477
4478 if (len32 == 4) {
4479 u8 buf[4];
4480
4481 if (cmd_flags)
4482 cmd_flags = BNX2_NVM_COMMAND_LAST;
4483 else
4484 cmd_flags = BNX2_NVM_COMMAND_FIRST |
4485 BNX2_NVM_COMMAND_LAST;
4486
4487 rc = bnx2_nvram_read_dword(bp, offset32, buf, cmd_flags);
4488
4489 memcpy(ret_buf, buf, 4 - extra);
4490 }
4491 else if (len32 > 0) {
4492 u8 buf[4];
4493
4494 /* Read the first word. */
4495 if (cmd_flags)
4496 cmd_flags = 0;
4497 else
4498 cmd_flags = BNX2_NVM_COMMAND_FIRST;
4499
4500 rc = bnx2_nvram_read_dword(bp, offset32, ret_buf, cmd_flags);
4501
4502 /* Advance to the next dword. */
4503 offset32 += 4;
4504 ret_buf += 4;
4505 len32 -= 4;
4506
4507 while (len32 > 4 && rc == 0) {
4508 rc = bnx2_nvram_read_dword(bp, offset32, ret_buf, 0);
4509
4510 /* Advance to the next dword. */
4511 offset32 += 4;
4512 ret_buf += 4;
4513 len32 -= 4;
4514 }
4515
4516 if (rc)
4517 return rc;
4518
4519 cmd_flags = BNX2_NVM_COMMAND_LAST;
4520 rc = bnx2_nvram_read_dword(bp, offset32, buf, cmd_flags);
4521
4522 memcpy(ret_buf, buf, 4 - extra);
4523 }
4524
4525 /* Disable access to flash interface */
4526 bnx2_disable_nvram_access(bp);
4527
4528 bnx2_release_nvram_lock(bp);
4529
4530 return rc;
4531}
4532
4533static int
4534bnx2_nvram_write(struct bnx2 *bp, u32 offset, u8 *data_buf,
4535 int buf_size)
4536{
4537 u32 written, offset32, len32;
Michael Chane6be7632007-01-08 19:56:13 -08004538 u8 *buf, start[4], end[4], *align_buf = NULL, *flash_buffer = NULL;
Michael Chanb6016b72005-05-26 13:03:09 -07004539 int rc = 0;
4540 int align_start, align_end;
4541
4542 buf = data_buf;
4543 offset32 = offset;
4544 len32 = buf_size;
4545 align_start = align_end = 0;
4546
4547 if ((align_start = (offset32 & 3))) {
4548 offset32 &= ~3;
Michael Chanc8738792007-03-30 14:53:06 -07004549 len32 += align_start;
4550 if (len32 < 4)
4551 len32 = 4;
Michael Chanb6016b72005-05-26 13:03:09 -07004552 if ((rc = bnx2_nvram_read(bp, offset32, start, 4)))
4553 return rc;
4554 }
4555
4556 if (len32 & 3) {
Michael Chanc8738792007-03-30 14:53:06 -07004557 align_end = 4 - (len32 & 3);
4558 len32 += align_end;
4559 if ((rc = bnx2_nvram_read(bp, offset32 + len32 - 4, end, 4)))
4560 return rc;
Michael Chanb6016b72005-05-26 13:03:09 -07004561 }
4562
4563 if (align_start || align_end) {
Michael Chane6be7632007-01-08 19:56:13 -08004564 align_buf = kmalloc(len32, GFP_KERNEL);
4565 if (align_buf == NULL)
Michael Chanb6016b72005-05-26 13:03:09 -07004566 return -ENOMEM;
4567 if (align_start) {
Michael Chane6be7632007-01-08 19:56:13 -08004568 memcpy(align_buf, start, 4);
Michael Chanb6016b72005-05-26 13:03:09 -07004569 }
4570 if (align_end) {
Michael Chane6be7632007-01-08 19:56:13 -08004571 memcpy(align_buf + len32 - 4, end, 4);
Michael Chanb6016b72005-05-26 13:03:09 -07004572 }
Michael Chane6be7632007-01-08 19:56:13 -08004573 memcpy(align_buf + align_start, data_buf, buf_size);
4574 buf = align_buf;
Michael Chanb6016b72005-05-26 13:03:09 -07004575 }
4576
Michael Chane30372c2007-07-16 18:26:23 -07004577 if (!(bp->flash_info->flags & BNX2_NV_BUFFERED)) {
Michael Chanae181bc2006-05-22 16:39:20 -07004578 flash_buffer = kmalloc(264, GFP_KERNEL);
4579 if (flash_buffer == NULL) {
4580 rc = -ENOMEM;
4581 goto nvram_write_end;
4582 }
4583 }
4584
Michael Chanb6016b72005-05-26 13:03:09 -07004585 written = 0;
4586 while ((written < len32) && (rc == 0)) {
4587 u32 page_start, page_end, data_start, data_end;
4588 u32 addr, cmd_flags;
4589 int i;
Michael Chanb6016b72005-05-26 13:03:09 -07004590
4591 /* Find the page_start addr */
4592 page_start = offset32 + written;
4593 page_start -= (page_start % bp->flash_info->page_size);
4594 /* Find the page_end addr */
4595 page_end = page_start + bp->flash_info->page_size;
4596 /* Find the data_start addr */
4597 data_start = (written == 0) ? offset32 : page_start;
4598 /* Find the data_end addr */
Jeff Garzik6aa20a22006-09-13 13:24:59 -04004599 data_end = (page_end > offset32 + len32) ?
Michael Chanb6016b72005-05-26 13:03:09 -07004600 (offset32 + len32) : page_end;
4601
4602 /* Request access to the flash interface. */
4603 if ((rc = bnx2_acquire_nvram_lock(bp)) != 0)
4604 goto nvram_write_end;
4605
4606 /* Enable access to flash interface */
4607 bnx2_enable_nvram_access(bp);
4608
4609 cmd_flags = BNX2_NVM_COMMAND_FIRST;
Michael Chane30372c2007-07-16 18:26:23 -07004610 if (!(bp->flash_info->flags & BNX2_NV_BUFFERED)) {
Michael Chanb6016b72005-05-26 13:03:09 -07004611 int j;
4612
4613 /* Read the whole page into the buffer
4614 * (non-buffer flash only) */
4615 for (j = 0; j < bp->flash_info->page_size; j += 4) {
4616 if (j == (bp->flash_info->page_size - 4)) {
4617 cmd_flags |= BNX2_NVM_COMMAND_LAST;
4618 }
4619 rc = bnx2_nvram_read_dword(bp,
Jeff Garzik6aa20a22006-09-13 13:24:59 -04004620 page_start + j,
4621 &flash_buffer[j],
Michael Chanb6016b72005-05-26 13:03:09 -07004622 cmd_flags);
4623
4624 if (rc)
4625 goto nvram_write_end;
4626
4627 cmd_flags = 0;
4628 }
4629 }
4630
4631 /* Enable writes to flash interface (unlock write-protect) */
4632 if ((rc = bnx2_enable_nvram_write(bp)) != 0)
4633 goto nvram_write_end;
4634
Michael Chanb6016b72005-05-26 13:03:09 -07004635 /* Loop to write back the buffer data from page_start to
4636 * data_start */
4637 i = 0;
Michael Chane30372c2007-07-16 18:26:23 -07004638 if (!(bp->flash_info->flags & BNX2_NV_BUFFERED)) {
Michael Chanc8738792007-03-30 14:53:06 -07004639 /* Erase the page */
4640 if ((rc = bnx2_nvram_erase_page(bp, page_start)) != 0)
4641 goto nvram_write_end;
4642
4643 /* Re-enable the write again for the actual write */
4644 bnx2_enable_nvram_write(bp);
4645
Michael Chanb6016b72005-05-26 13:03:09 -07004646 for (addr = page_start; addr < data_start;
4647 addr += 4, i += 4) {
Jeff Garzik6aa20a22006-09-13 13:24:59 -04004648
Michael Chanb6016b72005-05-26 13:03:09 -07004649 rc = bnx2_nvram_write_dword(bp, addr,
4650 &flash_buffer[i], cmd_flags);
4651
4652 if (rc != 0)
4653 goto nvram_write_end;
4654
4655 cmd_flags = 0;
4656 }
4657 }
4658
4659 /* Loop to write the new data from data_start to data_end */
Michael Chanbae25762006-05-22 16:38:38 -07004660 for (addr = data_start; addr < data_end; addr += 4, i += 4) {
Michael Chanb6016b72005-05-26 13:03:09 -07004661 if ((addr == page_end - 4) ||
Michael Chane30372c2007-07-16 18:26:23 -07004662 ((bp->flash_info->flags & BNX2_NV_BUFFERED) &&
Michael Chanb6016b72005-05-26 13:03:09 -07004663 (addr == data_end - 4))) {
4664
4665 cmd_flags |= BNX2_NVM_COMMAND_LAST;
4666 }
4667 rc = bnx2_nvram_write_dword(bp, addr, buf,
4668 cmd_flags);
4669
4670 if (rc != 0)
4671 goto nvram_write_end;
4672
4673 cmd_flags = 0;
4674 buf += 4;
4675 }
4676
4677 /* Loop to write back the buffer data from data_end
4678 * to page_end */
Michael Chane30372c2007-07-16 18:26:23 -07004679 if (!(bp->flash_info->flags & BNX2_NV_BUFFERED)) {
Michael Chanb6016b72005-05-26 13:03:09 -07004680 for (addr = data_end; addr < page_end;
4681 addr += 4, i += 4) {
Jeff Garzik6aa20a22006-09-13 13:24:59 -04004682
Michael Chanb6016b72005-05-26 13:03:09 -07004683 if (addr == page_end-4) {
4684 cmd_flags = BNX2_NVM_COMMAND_LAST;
4685 }
4686 rc = bnx2_nvram_write_dword(bp, addr,
4687 &flash_buffer[i], cmd_flags);
4688
4689 if (rc != 0)
4690 goto nvram_write_end;
4691
4692 cmd_flags = 0;
4693 }
4694 }
4695
4696 /* Disable writes to flash interface (lock write-protect) */
4697 bnx2_disable_nvram_write(bp);
4698
4699 /* Disable access to flash interface */
4700 bnx2_disable_nvram_access(bp);
4701 bnx2_release_nvram_lock(bp);
4702
4703 /* Increment written */
4704 written += data_end - data_start;
4705 }
4706
4707nvram_write_end:
Michael Chane6be7632007-01-08 19:56:13 -08004708 kfree(flash_buffer);
4709 kfree(align_buf);
Michael Chanb6016b72005-05-26 13:03:09 -07004710 return rc;
4711}
4712
Michael Chan0d8a6572007-07-07 22:49:43 -07004713static void
Michael Chan7c62e832008-07-14 22:39:03 -07004714bnx2_init_fw_cap(struct bnx2 *bp)
Michael Chan0d8a6572007-07-07 22:49:43 -07004715{
Michael Chan7c62e832008-07-14 22:39:03 -07004716 u32 val, sig = 0;
Michael Chan0d8a6572007-07-07 22:49:43 -07004717
Michael Chan583c28e2008-01-21 19:51:35 -08004718 bp->phy_flags &= ~BNX2_PHY_FLAG_REMOTE_PHY_CAP;
Michael Chan7c62e832008-07-14 22:39:03 -07004719 bp->flags &= ~BNX2_FLAG_CAN_KEEP_VLAN;
4720
4721 if (!(bp->flags & BNX2_FLAG_ASF_ENABLE))
4722 bp->flags |= BNX2_FLAG_CAN_KEEP_VLAN;
Michael Chan0d8a6572007-07-07 22:49:43 -07004723
Michael Chan2726d6e2008-01-29 21:35:05 -08004724 val = bnx2_shmem_rd(bp, BNX2_FW_CAP_MB);
Michael Chan0d8a6572007-07-07 22:49:43 -07004725 if ((val & BNX2_FW_CAP_SIGNATURE_MASK) != BNX2_FW_CAP_SIGNATURE)
4726 return;
4727
Michael Chan7c62e832008-07-14 22:39:03 -07004728 if ((val & BNX2_FW_CAP_CAN_KEEP_VLAN) == BNX2_FW_CAP_CAN_KEEP_VLAN) {
4729 bp->flags |= BNX2_FLAG_CAN_KEEP_VLAN;
4730 sig |= BNX2_DRV_ACK_CAP_SIGNATURE | BNX2_FW_CAP_CAN_KEEP_VLAN;
4731 }
4732
4733 if ((bp->phy_flags & BNX2_PHY_FLAG_SERDES) &&
4734 (val & BNX2_FW_CAP_REMOTE_PHY_CAPABLE)) {
4735 u32 link;
4736
Michael Chan583c28e2008-01-21 19:51:35 -08004737 bp->phy_flags |= BNX2_PHY_FLAG_REMOTE_PHY_CAP;
Michael Chan0d8a6572007-07-07 22:49:43 -07004738
Michael Chan7c62e832008-07-14 22:39:03 -07004739 link = bnx2_shmem_rd(bp, BNX2_LINK_STATUS);
4740 if (link & BNX2_LINK_STATUS_SERDES_LINK)
Michael Chan0d8a6572007-07-07 22:49:43 -07004741 bp->phy_port = PORT_FIBRE;
4742 else
4743 bp->phy_port = PORT_TP;
Michael Chan489310a2007-10-10 16:16:31 -07004744
Michael Chan7c62e832008-07-14 22:39:03 -07004745 sig |= BNX2_DRV_ACK_CAP_SIGNATURE |
4746 BNX2_FW_CAP_REMOTE_PHY_CAPABLE;
Michael Chan0d8a6572007-07-07 22:49:43 -07004747 }
Michael Chan7c62e832008-07-14 22:39:03 -07004748
4749 if (netif_running(bp->dev) && sig)
4750 bnx2_shmem_wr(bp, BNX2_DRV_ACK_CAP_MB, sig);
Michael Chan0d8a6572007-07-07 22:49:43 -07004751}
4752
Michael Chanb4b36042007-12-20 19:59:30 -08004753static void
4754bnx2_setup_msix_tbl(struct bnx2 *bp)
4755{
Michael Chane503e062012-12-06 10:33:08 +00004756 BNX2_WR(bp, BNX2_PCI_GRC_WINDOW_ADDR, BNX2_PCI_GRC_WINDOW_ADDR_SEP_WIN);
Michael Chanb4b36042007-12-20 19:59:30 -08004757
Michael Chane503e062012-12-06 10:33:08 +00004758 BNX2_WR(bp, BNX2_PCI_GRC_WINDOW2_ADDR, BNX2_MSIX_TABLE_ADDR);
4759 BNX2_WR(bp, BNX2_PCI_GRC_WINDOW3_ADDR, BNX2_MSIX_PBA_ADDR);
Michael Chanb4b36042007-12-20 19:59:30 -08004760}
4761
Michael Chanb6016b72005-05-26 13:03:09 -07004762static int
4763bnx2_reset_chip(struct bnx2 *bp, u32 reset_code)
4764{
4765 u32 val;
4766 int i, rc = 0;
Michael Chan489310a2007-10-10 16:16:31 -07004767 u8 old_port;
Michael Chanb6016b72005-05-26 13:03:09 -07004768
4769 /* Wait for the current PCI transaction to complete before
4770 * issuing a reset. */
Michael Chan4ce45e02012-12-06 10:33:10 +00004771 if ((BNX2_CHIP(bp) == BNX2_CHIP_5706) ||
4772 (BNX2_CHIP(bp) == BNX2_CHIP_5708)) {
Michael Chane503e062012-12-06 10:33:08 +00004773 BNX2_WR(bp, BNX2_MISC_ENABLE_CLR_BITS,
4774 BNX2_MISC_ENABLE_CLR_BITS_TX_DMA_ENABLE |
4775 BNX2_MISC_ENABLE_CLR_BITS_DMA_ENGINE_ENABLE |
4776 BNX2_MISC_ENABLE_CLR_BITS_RX_DMA_ENABLE |
4777 BNX2_MISC_ENABLE_CLR_BITS_HOST_COALESCE_ENABLE);
4778 val = BNX2_RD(bp, BNX2_MISC_ENABLE_CLR_BITS);
Eddie Waia5dac102010-11-24 13:48:54 +00004779 udelay(5);
4780 } else { /* 5709 */
Michael Chane503e062012-12-06 10:33:08 +00004781 val = BNX2_RD(bp, BNX2_MISC_NEW_CORE_CTL);
Eddie Waia5dac102010-11-24 13:48:54 +00004782 val &= ~BNX2_MISC_NEW_CORE_CTL_DMA_ENABLE;
Michael Chane503e062012-12-06 10:33:08 +00004783 BNX2_WR(bp, BNX2_MISC_NEW_CORE_CTL, val);
4784 val = BNX2_RD(bp, BNX2_MISC_NEW_CORE_CTL);
Eddie Waia5dac102010-11-24 13:48:54 +00004785
4786 for (i = 0; i < 100; i++) {
4787 msleep(1);
Michael Chane503e062012-12-06 10:33:08 +00004788 val = BNX2_RD(bp, BNX2_PCICFG_DEVICE_CONTROL);
Eddie Waia5dac102010-11-24 13:48:54 +00004789 if (!(val & BNX2_PCICFG_DEVICE_STATUS_NO_PEND))
4790 break;
4791 }
4792 }
Michael Chanb6016b72005-05-26 13:03:09 -07004793
Michael Chanb090ae22006-01-23 16:07:10 -08004794 /* Wait for the firmware to tell us it is ok to issue a reset. */
Michael Chana2f13892008-07-14 22:38:23 -07004795 bnx2_fw_sync(bp, BNX2_DRV_MSG_DATA_WAIT0 | reset_code, 1, 1);
Michael Chanb090ae22006-01-23 16:07:10 -08004796
Michael Chanb6016b72005-05-26 13:03:09 -07004797 /* Deposit a driver reset signature so the firmware knows that
4798 * this is a soft reset. */
Michael Chan2726d6e2008-01-29 21:35:05 -08004799 bnx2_shmem_wr(bp, BNX2_DRV_RESET_SIGNATURE,
4800 BNX2_DRV_RESET_SIGNATURE_MAGIC);
Michael Chanb6016b72005-05-26 13:03:09 -07004801
Michael Chanb6016b72005-05-26 13:03:09 -07004802 /* Do a dummy read to force the chip to complete all current transaction
4803 * before we issue a reset. */
Michael Chane503e062012-12-06 10:33:08 +00004804 val = BNX2_RD(bp, BNX2_MISC_ID);
Michael Chanb6016b72005-05-26 13:03:09 -07004805
Michael Chan4ce45e02012-12-06 10:33:10 +00004806 if (BNX2_CHIP(bp) == BNX2_CHIP_5709) {
Michael Chane503e062012-12-06 10:33:08 +00004807 BNX2_WR(bp, BNX2_MISC_COMMAND, BNX2_MISC_COMMAND_SW_RESET);
4808 BNX2_RD(bp, BNX2_MISC_COMMAND);
Michael Chan234754d2006-11-19 14:11:41 -08004809 udelay(5);
Michael Chanb6016b72005-05-26 13:03:09 -07004810
Michael Chan234754d2006-11-19 14:11:41 -08004811 val = BNX2_PCICFG_MISC_CONFIG_REG_WINDOW_ENA |
4812 BNX2_PCICFG_MISC_CONFIG_TARGET_MB_WORD_SWAP;
Michael Chanb6016b72005-05-26 13:03:09 -07004813
Michael Chane503e062012-12-06 10:33:08 +00004814 BNX2_WR(bp, BNX2_PCICFG_MISC_CONFIG, val);
Michael Chanb6016b72005-05-26 13:03:09 -07004815
Michael Chan234754d2006-11-19 14:11:41 -08004816 } else {
4817 val = BNX2_PCICFG_MISC_CONFIG_CORE_RST_REQ |
4818 BNX2_PCICFG_MISC_CONFIG_REG_WINDOW_ENA |
4819 BNX2_PCICFG_MISC_CONFIG_TARGET_MB_WORD_SWAP;
4820
4821 /* Chip reset. */
Michael Chane503e062012-12-06 10:33:08 +00004822 BNX2_WR(bp, BNX2_PCICFG_MISC_CONFIG, val);
Michael Chan234754d2006-11-19 14:11:41 -08004823
Michael Chan594a9df2007-08-28 15:39:42 -07004824 /* Reading back any register after chip reset will hang the
4825 * bus on 5706 A0 and A1. The msleep below provides plenty
4826 * of margin for write posting.
4827 */
Michael Chan4ce45e02012-12-06 10:33:10 +00004828 if ((BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5706_A0) ||
4829 (BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5706_A1))
Arjan van de Ven8e545882007-08-28 14:34:43 -07004830 msleep(20);
Michael Chanb6016b72005-05-26 13:03:09 -07004831
Michael Chan234754d2006-11-19 14:11:41 -08004832 /* Reset takes approximate 30 usec */
4833 for (i = 0; i < 10; i++) {
Michael Chane503e062012-12-06 10:33:08 +00004834 val = BNX2_RD(bp, BNX2_PCICFG_MISC_CONFIG);
Michael Chan234754d2006-11-19 14:11:41 -08004835 if ((val & (BNX2_PCICFG_MISC_CONFIG_CORE_RST_REQ |
4836 BNX2_PCICFG_MISC_CONFIG_CORE_RST_BSY)) == 0)
4837 break;
4838 udelay(10);
4839 }
4840
4841 if (val & (BNX2_PCICFG_MISC_CONFIG_CORE_RST_REQ |
4842 BNX2_PCICFG_MISC_CONFIG_CORE_RST_BSY)) {
Joe Perches3a9c6a42010-02-17 15:01:51 +00004843 pr_err("Chip reset did not complete\n");
Michael Chan234754d2006-11-19 14:11:41 -08004844 return -EBUSY;
4845 }
Michael Chanb6016b72005-05-26 13:03:09 -07004846 }
4847
4848 /* Make sure byte swapping is properly configured. */
Michael Chane503e062012-12-06 10:33:08 +00004849 val = BNX2_RD(bp, BNX2_PCI_SWAP_DIAG0);
Michael Chanb6016b72005-05-26 13:03:09 -07004850 if (val != 0x01020304) {
Joe Perches3a9c6a42010-02-17 15:01:51 +00004851 pr_err("Chip not in correct endian mode\n");
Michael Chanb6016b72005-05-26 13:03:09 -07004852 return -ENODEV;
4853 }
4854
Michael Chanb6016b72005-05-26 13:03:09 -07004855 /* Wait for the firmware to finish its initialization. */
Michael Chana2f13892008-07-14 22:38:23 -07004856 rc = bnx2_fw_sync(bp, BNX2_DRV_MSG_DATA_WAIT1 | reset_code, 1, 0);
Michael Chanb090ae22006-01-23 16:07:10 -08004857 if (rc)
4858 return rc;
Michael Chanb6016b72005-05-26 13:03:09 -07004859
Michael Chan0d8a6572007-07-07 22:49:43 -07004860 spin_lock_bh(&bp->phy_lock);
Michael Chan489310a2007-10-10 16:16:31 -07004861 old_port = bp->phy_port;
Michael Chan7c62e832008-07-14 22:39:03 -07004862 bnx2_init_fw_cap(bp);
Michael Chan583c28e2008-01-21 19:51:35 -08004863 if ((bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP) &&
4864 old_port != bp->phy_port)
Michael Chan0d8a6572007-07-07 22:49:43 -07004865 bnx2_set_default_remote_link(bp);
4866 spin_unlock_bh(&bp->phy_lock);
4867
Michael Chan4ce45e02012-12-06 10:33:10 +00004868 if (BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5706_A0) {
Michael Chanb6016b72005-05-26 13:03:09 -07004869 /* Adjust the voltage regular to two steps lower. The default
4870 * of this register is 0x0000000e. */
Michael Chane503e062012-12-06 10:33:08 +00004871 BNX2_WR(bp, BNX2_MISC_VREG_CONTROL, 0x000000fa);
Michael Chanb6016b72005-05-26 13:03:09 -07004872
4873 /* Remove bad rbuf memory from the free pool. */
4874 rc = bnx2_alloc_bad_rbuf(bp);
4875 }
4876
Michael Chanc441b8d2010-04-27 11:28:09 +00004877 if (bp->flags & BNX2_FLAG_USING_MSIX) {
Michael Chanb4b36042007-12-20 19:59:30 -08004878 bnx2_setup_msix_tbl(bp);
Michael Chanc441b8d2010-04-27 11:28:09 +00004879 /* Prevent MSIX table reads and write from timing out */
Michael Chane503e062012-12-06 10:33:08 +00004880 BNX2_WR(bp, BNX2_MISC_ECO_HW_CTL,
Michael Chanc441b8d2010-04-27 11:28:09 +00004881 BNX2_MISC_ECO_HW_CTL_LARGE_GRC_TMOUT_EN);
4882 }
Michael Chanb4b36042007-12-20 19:59:30 -08004883
Michael Chanb6016b72005-05-26 13:03:09 -07004884 return rc;
4885}
4886
4887static int
4888bnx2_init_chip(struct bnx2 *bp)
4889{
Michael Chand8026d92008-11-12 16:02:20 -08004890 u32 val, mtu;
Michael Chanb4b36042007-12-20 19:59:30 -08004891 int rc, i;
Michael Chanb6016b72005-05-26 13:03:09 -07004892
4893 /* Make sure the interrupt is not active. */
Michael Chane503e062012-12-06 10:33:08 +00004894 BNX2_WR(bp, BNX2_PCICFG_INT_ACK_CMD, BNX2_PCICFG_INT_ACK_CMD_MASK_INT);
Michael Chanb6016b72005-05-26 13:03:09 -07004895
4896 val = BNX2_DMA_CONFIG_DATA_BYTE_SWAP |
4897 BNX2_DMA_CONFIG_DATA_WORD_SWAP |
4898#ifdef __BIG_ENDIAN
Jeff Garzik6aa20a22006-09-13 13:24:59 -04004899 BNX2_DMA_CONFIG_CNTL_BYTE_SWAP |
Michael Chanb6016b72005-05-26 13:03:09 -07004900#endif
Jeff Garzik6aa20a22006-09-13 13:24:59 -04004901 BNX2_DMA_CONFIG_CNTL_WORD_SWAP |
Michael Chanb6016b72005-05-26 13:03:09 -07004902 DMA_READ_CHANS << 12 |
4903 DMA_WRITE_CHANS << 16;
4904
4905 val |= (0x2 << 20) | (1 << 11);
4906
David S. Millerf86e82f2008-01-21 17:15:40 -08004907 if ((bp->flags & BNX2_FLAG_PCIX) && (bp->bus_speed_mhz == 133))
Michael Chanb6016b72005-05-26 13:03:09 -07004908 val |= (1 << 23);
4909
Michael Chan4ce45e02012-12-06 10:33:10 +00004910 if ((BNX2_CHIP(bp) == BNX2_CHIP_5706) &&
4911 (BNX2_CHIP_ID(bp) != BNX2_CHIP_ID_5706_A0) &&
4912 !(bp->flags & BNX2_FLAG_PCIX))
Michael Chanb6016b72005-05-26 13:03:09 -07004913 val |= BNX2_DMA_CONFIG_CNTL_PING_PONG_DMA;
4914
Michael Chane503e062012-12-06 10:33:08 +00004915 BNX2_WR(bp, BNX2_DMA_CONFIG, val);
Michael Chanb6016b72005-05-26 13:03:09 -07004916
Michael Chan4ce45e02012-12-06 10:33:10 +00004917 if (BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5706_A0) {
Michael Chane503e062012-12-06 10:33:08 +00004918 val = BNX2_RD(bp, BNX2_TDMA_CONFIG);
Michael Chanb6016b72005-05-26 13:03:09 -07004919 val |= BNX2_TDMA_CONFIG_ONE_DMA;
Michael Chane503e062012-12-06 10:33:08 +00004920 BNX2_WR(bp, BNX2_TDMA_CONFIG, val);
Michael Chanb6016b72005-05-26 13:03:09 -07004921 }
4922
David S. Millerf86e82f2008-01-21 17:15:40 -08004923 if (bp->flags & BNX2_FLAG_PCIX) {
Michael Chanb6016b72005-05-26 13:03:09 -07004924 u16 val16;
4925
4926 pci_read_config_word(bp->pdev, bp->pcix_cap + PCI_X_CMD,
4927 &val16);
4928 pci_write_config_word(bp->pdev, bp->pcix_cap + PCI_X_CMD,
4929 val16 & ~PCI_X_CMD_ERO);
4930 }
4931
Michael Chane503e062012-12-06 10:33:08 +00004932 BNX2_WR(bp, BNX2_MISC_ENABLE_SET_BITS,
4933 BNX2_MISC_ENABLE_SET_BITS_HOST_COALESCE_ENABLE |
4934 BNX2_MISC_ENABLE_STATUS_BITS_RX_V2P_ENABLE |
4935 BNX2_MISC_ENABLE_STATUS_BITS_CONTEXT_ENABLE);
Michael Chanb6016b72005-05-26 13:03:09 -07004936
4937 /* Initialize context mapping and zero out the quick contexts. The
4938 * context block must have already been enabled. */
Michael Chan4ce45e02012-12-06 10:33:10 +00004939 if (BNX2_CHIP(bp) == BNX2_CHIP_5709) {
Michael Chan641bdcd2007-06-04 21:22:24 -07004940 rc = bnx2_init_5709_context(bp);
4941 if (rc)
4942 return rc;
4943 } else
Michael Chan59b47d82006-11-19 14:10:45 -08004944 bnx2_init_context(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07004945
Michael Chanfba9fe92006-06-12 22:21:25 -07004946 if ((rc = bnx2_init_cpus(bp)) != 0)
4947 return rc;
4948
Michael Chanb6016b72005-05-26 13:03:09 -07004949 bnx2_init_nvram(bp);
4950
Benjamin Li5fcaed02008-07-14 22:39:52 -07004951 bnx2_set_mac_addr(bp, bp->dev->dev_addr, 0);
Michael Chanb6016b72005-05-26 13:03:09 -07004952
Michael Chane503e062012-12-06 10:33:08 +00004953 val = BNX2_RD(bp, BNX2_MQ_CONFIG);
Michael Chanb6016b72005-05-26 13:03:09 -07004954 val &= ~BNX2_MQ_CONFIG_KNL_BYP_BLK_SIZE;
4955 val |= BNX2_MQ_CONFIG_KNL_BYP_BLK_SIZE_256;
Michael Chan4ce45e02012-12-06 10:33:10 +00004956 if (BNX2_CHIP(bp) == BNX2_CHIP_5709) {
Michael Chan4edd4732009-06-08 18:14:42 -07004957 val |= BNX2_MQ_CONFIG_BIN_MQ_MODE;
Michael Chan4ce45e02012-12-06 10:33:10 +00004958 if (BNX2_CHIP_REV(bp) == BNX2_CHIP_REV_Ax)
Michael Chan4edd4732009-06-08 18:14:42 -07004959 val |= BNX2_MQ_CONFIG_HALT_DIS;
4960 }
Michael Chan68c9f752007-04-24 15:35:53 -07004961
Michael Chane503e062012-12-06 10:33:08 +00004962 BNX2_WR(bp, BNX2_MQ_CONFIG, val);
Michael Chanb6016b72005-05-26 13:03:09 -07004963
4964 val = 0x10000 + (MAX_CID_CNT * MB_KERNEL_CTX_SIZE);
Michael Chane503e062012-12-06 10:33:08 +00004965 BNX2_WR(bp, BNX2_MQ_KNL_BYP_WIND_START, val);
4966 BNX2_WR(bp, BNX2_MQ_KNL_WIND_END, val);
Michael Chanb6016b72005-05-26 13:03:09 -07004967
Michael Chan2bc40782012-12-06 10:33:09 +00004968 val = (BNX2_PAGE_BITS - 8) << 24;
Michael Chane503e062012-12-06 10:33:08 +00004969 BNX2_WR(bp, BNX2_RV2P_CONFIG, val);
Michael Chanb6016b72005-05-26 13:03:09 -07004970
4971 /* Configure page size. */
Michael Chane503e062012-12-06 10:33:08 +00004972 val = BNX2_RD(bp, BNX2_TBDR_CONFIG);
Michael Chanb6016b72005-05-26 13:03:09 -07004973 val &= ~BNX2_TBDR_CONFIG_PAGE_SIZE;
Michael Chan2bc40782012-12-06 10:33:09 +00004974 val |= (BNX2_PAGE_BITS - 8) << 24 | 0x40;
Michael Chane503e062012-12-06 10:33:08 +00004975 BNX2_WR(bp, BNX2_TBDR_CONFIG, val);
Michael Chanb6016b72005-05-26 13:03:09 -07004976
4977 val = bp->mac_addr[0] +
4978 (bp->mac_addr[1] << 8) +
4979 (bp->mac_addr[2] << 16) +
4980 bp->mac_addr[3] +
4981 (bp->mac_addr[4] << 8) +
4982 (bp->mac_addr[5] << 16);
Michael Chane503e062012-12-06 10:33:08 +00004983 BNX2_WR(bp, BNX2_EMAC_BACKOFF_SEED, val);
Michael Chanb6016b72005-05-26 13:03:09 -07004984
4985 /* Program the MTU. Also include 4 bytes for CRC32. */
Michael Chand8026d92008-11-12 16:02:20 -08004986 mtu = bp->dev->mtu;
4987 val = mtu + ETH_HLEN + ETH_FCS_LEN;
Michael Chanb6016b72005-05-26 13:03:09 -07004988 if (val > (MAX_ETHERNET_PACKET_SIZE + 4))
4989 val |= BNX2_EMAC_RX_MTU_SIZE_JUMBO_ENA;
Michael Chane503e062012-12-06 10:33:08 +00004990 BNX2_WR(bp, BNX2_EMAC_RX_MTU_SIZE, val);
Michael Chanb6016b72005-05-26 13:03:09 -07004991
Michael Chand8026d92008-11-12 16:02:20 -08004992 if (mtu < 1500)
4993 mtu = 1500;
4994
4995 bnx2_reg_wr_ind(bp, BNX2_RBUF_CONFIG, BNX2_RBUF_CONFIG_VAL(mtu));
4996 bnx2_reg_wr_ind(bp, BNX2_RBUF_CONFIG2, BNX2_RBUF_CONFIG2_VAL(mtu));
4997 bnx2_reg_wr_ind(bp, BNX2_RBUF_CONFIG3, BNX2_RBUF_CONFIG3_VAL(mtu));
4998
Michael Chan155d5562009-08-21 16:20:43 +00004999 memset(bp->bnx2_napi[0].status_blk.msi, 0, bp->status_stats_size);
Michael Chanb4b36042007-12-20 19:59:30 -08005000 for (i = 0; i < BNX2_MAX_MSIX_VEC; i++)
5001 bp->bnx2_napi[i].last_status_idx = 0;
5002
Michael Chanefba0182008-12-03 00:36:15 -08005003 bp->idle_chk_status_idx = 0xffff;
5004
Michael Chanb6016b72005-05-26 13:03:09 -07005005 /* Set up how to generate a link change interrupt. */
Michael Chane503e062012-12-06 10:33:08 +00005006 BNX2_WR(bp, BNX2_EMAC_ATTENTION_ENA, BNX2_EMAC_ATTENTION_ENA_LINK);
Michael Chanb6016b72005-05-26 13:03:09 -07005007
Michael Chane503e062012-12-06 10:33:08 +00005008 BNX2_WR(bp, BNX2_HC_STATUS_ADDR_L,
5009 (u64) bp->status_blk_mapping & 0xffffffff);
5010 BNX2_WR(bp, BNX2_HC_STATUS_ADDR_H, (u64) bp->status_blk_mapping >> 32);
Michael Chanb6016b72005-05-26 13:03:09 -07005011
Michael Chane503e062012-12-06 10:33:08 +00005012 BNX2_WR(bp, BNX2_HC_STATISTICS_ADDR_L,
5013 (u64) bp->stats_blk_mapping & 0xffffffff);
5014 BNX2_WR(bp, BNX2_HC_STATISTICS_ADDR_H,
5015 (u64) bp->stats_blk_mapping >> 32);
Michael Chanb6016b72005-05-26 13:03:09 -07005016
Michael Chane503e062012-12-06 10:33:08 +00005017 BNX2_WR(bp, BNX2_HC_TX_QUICK_CONS_TRIP,
5018 (bp->tx_quick_cons_trip_int << 16) | bp->tx_quick_cons_trip);
Michael Chanb6016b72005-05-26 13:03:09 -07005019
Michael Chane503e062012-12-06 10:33:08 +00005020 BNX2_WR(bp, BNX2_HC_RX_QUICK_CONS_TRIP,
5021 (bp->rx_quick_cons_trip_int << 16) | bp->rx_quick_cons_trip);
Michael Chanb6016b72005-05-26 13:03:09 -07005022
Michael Chane503e062012-12-06 10:33:08 +00005023 BNX2_WR(bp, BNX2_HC_COMP_PROD_TRIP,
5024 (bp->comp_prod_trip_int << 16) | bp->comp_prod_trip);
Michael Chanb6016b72005-05-26 13:03:09 -07005025
Michael Chane503e062012-12-06 10:33:08 +00005026 BNX2_WR(bp, BNX2_HC_TX_TICKS, (bp->tx_ticks_int << 16) | bp->tx_ticks);
Michael Chanb6016b72005-05-26 13:03:09 -07005027
Michael Chane503e062012-12-06 10:33:08 +00005028 BNX2_WR(bp, BNX2_HC_RX_TICKS, (bp->rx_ticks_int << 16) | bp->rx_ticks);
Michael Chanb6016b72005-05-26 13:03:09 -07005029
Michael Chane503e062012-12-06 10:33:08 +00005030 BNX2_WR(bp, BNX2_HC_COM_TICKS,
5031 (bp->com_ticks_int << 16) | bp->com_ticks);
Michael Chanb6016b72005-05-26 13:03:09 -07005032
Michael Chane503e062012-12-06 10:33:08 +00005033 BNX2_WR(bp, BNX2_HC_CMD_TICKS,
5034 (bp->cmd_ticks_int << 16) | bp->cmd_ticks);
Michael Chanb6016b72005-05-26 13:03:09 -07005035
Michael Chan61d9e3f2009-08-21 16:20:46 +00005036 if (bp->flags & BNX2_FLAG_BROKEN_STATS)
Michael Chane503e062012-12-06 10:33:08 +00005037 BNX2_WR(bp, BNX2_HC_STATS_TICKS, 0);
Michael Chan02537b062007-06-04 21:24:07 -07005038 else
Michael Chane503e062012-12-06 10:33:08 +00005039 BNX2_WR(bp, BNX2_HC_STATS_TICKS, bp->stats_ticks);
5040 BNX2_WR(bp, BNX2_HC_STAT_COLLECT_TICKS, 0xbb8); /* 3ms */
Michael Chanb6016b72005-05-26 13:03:09 -07005041
Michael Chan4ce45e02012-12-06 10:33:10 +00005042 if (BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5706_A1)
Michael Chan8e6a72c2007-05-03 13:24:48 -07005043 val = BNX2_HC_CONFIG_COLLECT_STATS;
Michael Chanb6016b72005-05-26 13:03:09 -07005044 else {
Michael Chan8e6a72c2007-05-03 13:24:48 -07005045 val = BNX2_HC_CONFIG_RX_TMR_MODE | BNX2_HC_CONFIG_TX_TMR_MODE |
5046 BNX2_HC_CONFIG_COLLECT_STATS;
Michael Chanb6016b72005-05-26 13:03:09 -07005047 }
5048
Michael Chanefde73a2010-02-15 19:42:07 +00005049 if (bp->flags & BNX2_FLAG_USING_MSIX) {
Michael Chane503e062012-12-06 10:33:08 +00005050 BNX2_WR(bp, BNX2_HC_MSIX_BIT_VECTOR,
5051 BNX2_HC_MSIX_BIT_VECTOR_VAL);
Michael Chanc76c0472007-12-20 20:01:19 -08005052
Michael Chan5e9ad9e2008-06-19 16:43:17 -07005053 val |= BNX2_HC_CONFIG_SB_ADDR_INC_128B;
5054 }
5055
5056 if (bp->flags & BNX2_FLAG_ONE_SHOT_MSI)
Michael Chancf7474a2009-08-21 16:20:48 +00005057 val |= BNX2_HC_CONFIG_ONE_SHOT | BNX2_HC_CONFIG_USE_INT_PARAM;
Michael Chan5e9ad9e2008-06-19 16:43:17 -07005058
Michael Chane503e062012-12-06 10:33:08 +00005059 BNX2_WR(bp, BNX2_HC_CONFIG, val);
Michael Chan5e9ad9e2008-06-19 16:43:17 -07005060
Michael Chan22fa1592010-10-11 16:12:00 -07005061 if (bp->rx_ticks < 25)
5062 bnx2_reg_wr_ind(bp, BNX2_FW_RX_LOW_LATENCY, 1);
5063 else
5064 bnx2_reg_wr_ind(bp, BNX2_FW_RX_LOW_LATENCY, 0);
5065
Michael Chan5e9ad9e2008-06-19 16:43:17 -07005066 for (i = 1; i < bp->irq_nvecs; i++) {
5067 u32 base = ((i - 1) * BNX2_HC_SB_CONFIG_SIZE) +
5068 BNX2_HC_SB_CONFIG_1;
5069
Michael Chane503e062012-12-06 10:33:08 +00005070 BNX2_WR(bp, base,
Michael Chanc76c0472007-12-20 20:01:19 -08005071 BNX2_HC_SB_CONFIG_1_TX_TMR_MODE |
Michael Chan5e9ad9e2008-06-19 16:43:17 -07005072 BNX2_HC_SB_CONFIG_1_RX_TMR_MODE |
Michael Chanc76c0472007-12-20 20:01:19 -08005073 BNX2_HC_SB_CONFIG_1_ONE_SHOT);
5074
Michael Chane503e062012-12-06 10:33:08 +00005075 BNX2_WR(bp, base + BNX2_HC_TX_QUICK_CONS_TRIP_OFF,
Michael Chanc76c0472007-12-20 20:01:19 -08005076 (bp->tx_quick_cons_trip_int << 16) |
5077 bp->tx_quick_cons_trip);
5078
Michael Chane503e062012-12-06 10:33:08 +00005079 BNX2_WR(bp, base + BNX2_HC_TX_TICKS_OFF,
Michael Chanc76c0472007-12-20 20:01:19 -08005080 (bp->tx_ticks_int << 16) | bp->tx_ticks);
5081
Michael Chane503e062012-12-06 10:33:08 +00005082 BNX2_WR(bp, base + BNX2_HC_RX_QUICK_CONS_TRIP_OFF,
5083 (bp->rx_quick_cons_trip_int << 16) |
Michael Chan5e9ad9e2008-06-19 16:43:17 -07005084 bp->rx_quick_cons_trip);
5085
Michael Chane503e062012-12-06 10:33:08 +00005086 BNX2_WR(bp, base + BNX2_HC_RX_TICKS_OFF,
Michael Chan5e9ad9e2008-06-19 16:43:17 -07005087 (bp->rx_ticks_int << 16) | bp->rx_ticks);
Michael Chanc76c0472007-12-20 20:01:19 -08005088 }
5089
Michael Chanb6016b72005-05-26 13:03:09 -07005090 /* Clear internal stats counters. */
Michael Chane503e062012-12-06 10:33:08 +00005091 BNX2_WR(bp, BNX2_HC_COMMAND, BNX2_HC_COMMAND_CLR_STAT_NOW);
Michael Chanb6016b72005-05-26 13:03:09 -07005092
Michael Chane503e062012-12-06 10:33:08 +00005093 BNX2_WR(bp, BNX2_HC_ATTN_BITS_ENABLE, STATUS_ATTN_EVENTS);
Michael Chanb6016b72005-05-26 13:03:09 -07005094
5095 /* Initialize the receive filter. */
5096 bnx2_set_rx_mode(bp->dev);
5097
Michael Chan4ce45e02012-12-06 10:33:10 +00005098 if (BNX2_CHIP(bp) == BNX2_CHIP_5709) {
Michael Chane503e062012-12-06 10:33:08 +00005099 val = BNX2_RD(bp, BNX2_MISC_NEW_CORE_CTL);
Michael Chan0aa38df2007-06-04 21:23:06 -07005100 val |= BNX2_MISC_NEW_CORE_CTL_DMA_ENABLE;
Michael Chane503e062012-12-06 10:33:08 +00005101 BNX2_WR(bp, BNX2_MISC_NEW_CORE_CTL, val);
Michael Chan0aa38df2007-06-04 21:23:06 -07005102 }
Michael Chanb090ae22006-01-23 16:07:10 -08005103 rc = bnx2_fw_sync(bp, BNX2_DRV_MSG_DATA_WAIT2 | BNX2_DRV_MSG_CODE_RESET,
Michael Chana2f13892008-07-14 22:38:23 -07005104 1, 0);
Michael Chanb6016b72005-05-26 13:03:09 -07005105
Michael Chane503e062012-12-06 10:33:08 +00005106 BNX2_WR(bp, BNX2_MISC_ENABLE_SET_BITS, BNX2_MISC_ENABLE_DEFAULT);
5107 BNX2_RD(bp, BNX2_MISC_ENABLE_SET_BITS);
Michael Chanb6016b72005-05-26 13:03:09 -07005108
5109 udelay(20);
5110
Michael Chane503e062012-12-06 10:33:08 +00005111 bp->hc_cmd = BNX2_RD(bp, BNX2_HC_COMMAND);
Michael Chanbf5295b2006-03-23 01:11:56 -08005112
Michael Chanb090ae22006-01-23 16:07:10 -08005113 return rc;
Michael Chanb6016b72005-05-26 13:03:09 -07005114}
5115
Michael Chan59b47d82006-11-19 14:10:45 -08005116static void
Michael Chanc76c0472007-12-20 20:01:19 -08005117bnx2_clear_ring_states(struct bnx2 *bp)
5118{
5119 struct bnx2_napi *bnapi;
Michael Chan35e90102008-06-19 16:37:42 -07005120 struct bnx2_tx_ring_info *txr;
Michael Chanbb4f98a2008-06-19 16:38:19 -07005121 struct bnx2_rx_ring_info *rxr;
Michael Chanc76c0472007-12-20 20:01:19 -08005122 int i;
5123
5124 for (i = 0; i < BNX2_MAX_MSIX_VEC; i++) {
5125 bnapi = &bp->bnx2_napi[i];
Michael Chan35e90102008-06-19 16:37:42 -07005126 txr = &bnapi->tx_ring;
Michael Chanbb4f98a2008-06-19 16:38:19 -07005127 rxr = &bnapi->rx_ring;
Michael Chanc76c0472007-12-20 20:01:19 -08005128
Michael Chan35e90102008-06-19 16:37:42 -07005129 txr->tx_cons = 0;
5130 txr->hw_tx_cons = 0;
Michael Chanbb4f98a2008-06-19 16:38:19 -07005131 rxr->rx_prod_bseq = 0;
5132 rxr->rx_prod = 0;
5133 rxr->rx_cons = 0;
5134 rxr->rx_pg_prod = 0;
5135 rxr->rx_pg_cons = 0;
Michael Chanc76c0472007-12-20 20:01:19 -08005136 }
5137}
5138
5139static void
Michael Chan35e90102008-06-19 16:37:42 -07005140bnx2_init_tx_context(struct bnx2 *bp, u32 cid, struct bnx2_tx_ring_info *txr)
Michael Chan59b47d82006-11-19 14:10:45 -08005141{
5142 u32 val, offset0, offset1, offset2, offset3;
Michael Chan62a83132008-01-29 21:35:40 -08005143 u32 cid_addr = GET_CID_ADDR(cid);
Michael Chan59b47d82006-11-19 14:10:45 -08005144
Michael Chan4ce45e02012-12-06 10:33:10 +00005145 if (BNX2_CHIP(bp) == BNX2_CHIP_5709) {
Michael Chan59b47d82006-11-19 14:10:45 -08005146 offset0 = BNX2_L2CTX_TYPE_XI;
5147 offset1 = BNX2_L2CTX_CMD_TYPE_XI;
5148 offset2 = BNX2_L2CTX_TBDR_BHADDR_HI_XI;
5149 offset3 = BNX2_L2CTX_TBDR_BHADDR_LO_XI;
5150 } else {
5151 offset0 = BNX2_L2CTX_TYPE;
5152 offset1 = BNX2_L2CTX_CMD_TYPE;
5153 offset2 = BNX2_L2CTX_TBDR_BHADDR_HI;
5154 offset3 = BNX2_L2CTX_TBDR_BHADDR_LO;
5155 }
5156 val = BNX2_L2CTX_TYPE_TYPE_L2 | BNX2_L2CTX_TYPE_SIZE_L2;
Michael Chan62a83132008-01-29 21:35:40 -08005157 bnx2_ctx_wr(bp, cid_addr, offset0, val);
Michael Chan59b47d82006-11-19 14:10:45 -08005158
5159 val = BNX2_L2CTX_CMD_TYPE_TYPE_L2 | (8 << 16);
Michael Chan62a83132008-01-29 21:35:40 -08005160 bnx2_ctx_wr(bp, cid_addr, offset1, val);
Michael Chan59b47d82006-11-19 14:10:45 -08005161
Michael Chan35e90102008-06-19 16:37:42 -07005162 val = (u64) txr->tx_desc_mapping >> 32;
Michael Chan62a83132008-01-29 21:35:40 -08005163 bnx2_ctx_wr(bp, cid_addr, offset2, val);
Michael Chan59b47d82006-11-19 14:10:45 -08005164
Michael Chan35e90102008-06-19 16:37:42 -07005165 val = (u64) txr->tx_desc_mapping & 0xffffffff;
Michael Chan62a83132008-01-29 21:35:40 -08005166 bnx2_ctx_wr(bp, cid_addr, offset3, val);
Michael Chan59b47d82006-11-19 14:10:45 -08005167}
Michael Chanb6016b72005-05-26 13:03:09 -07005168
5169static void
Michael Chan35e90102008-06-19 16:37:42 -07005170bnx2_init_tx_ring(struct bnx2 *bp, int ring_num)
Michael Chanb6016b72005-05-26 13:03:09 -07005171{
Michael Chan2bc40782012-12-06 10:33:09 +00005172 struct bnx2_tx_bd *txbd;
Michael Chanc76c0472007-12-20 20:01:19 -08005173 u32 cid = TX_CID;
5174 struct bnx2_napi *bnapi;
Michael Chan35e90102008-06-19 16:37:42 -07005175 struct bnx2_tx_ring_info *txr;
Michael Chanc76c0472007-12-20 20:01:19 -08005176
Michael Chan35e90102008-06-19 16:37:42 -07005177 bnapi = &bp->bnx2_napi[ring_num];
5178 txr = &bnapi->tx_ring;
5179
5180 if (ring_num == 0)
5181 cid = TX_CID;
5182 else
5183 cid = TX_TSS_CID + ring_num - 1;
Michael Chanb6016b72005-05-26 13:03:09 -07005184
Michael Chan2f8af122006-08-15 01:39:10 -07005185 bp->tx_wake_thresh = bp->tx_ring_size / 2;
5186
Michael Chan2bc40782012-12-06 10:33:09 +00005187 txbd = &txr->tx_desc_ring[BNX2_MAX_TX_DESC_CNT];
Jeff Garzik6aa20a22006-09-13 13:24:59 -04005188
Michael Chan35e90102008-06-19 16:37:42 -07005189 txbd->tx_bd_haddr_hi = (u64) txr->tx_desc_mapping >> 32;
5190 txbd->tx_bd_haddr_lo = (u64) txr->tx_desc_mapping & 0xffffffff;
Michael Chanb6016b72005-05-26 13:03:09 -07005191
Michael Chan35e90102008-06-19 16:37:42 -07005192 txr->tx_prod = 0;
5193 txr->tx_prod_bseq = 0;
Jeff Garzik6aa20a22006-09-13 13:24:59 -04005194
Michael Chan35e90102008-06-19 16:37:42 -07005195 txr->tx_bidx_addr = MB_GET_CID_ADDR(cid) + BNX2_L2CTX_TX_HOST_BIDX;
5196 txr->tx_bseq_addr = MB_GET_CID_ADDR(cid) + BNX2_L2CTX_TX_HOST_BSEQ;
Michael Chanb6016b72005-05-26 13:03:09 -07005197
Michael Chan35e90102008-06-19 16:37:42 -07005198 bnx2_init_tx_context(bp, cid, txr);
Michael Chanb6016b72005-05-26 13:03:09 -07005199}
5200
5201static void
Michael Chan2bc40782012-12-06 10:33:09 +00005202bnx2_init_rxbd_rings(struct bnx2_rx_bd *rx_ring[], dma_addr_t dma[],
5203 u32 buf_size, int num_rings)
Michael Chanb6016b72005-05-26 13:03:09 -07005204{
Michael Chanb6016b72005-05-26 13:03:09 -07005205 int i;
Michael Chan2bc40782012-12-06 10:33:09 +00005206 struct bnx2_rx_bd *rxbd;
Michael Chanb6016b72005-05-26 13:03:09 -07005207
Michael Chan5d5d0012007-12-12 11:17:43 -08005208 for (i = 0; i < num_rings; i++) {
Michael Chan13daffa2006-03-20 17:49:20 -08005209 int j;
Michael Chanb6016b72005-05-26 13:03:09 -07005210
Michael Chan5d5d0012007-12-12 11:17:43 -08005211 rxbd = &rx_ring[i][0];
Michael Chan2bc40782012-12-06 10:33:09 +00005212 for (j = 0; j < BNX2_MAX_RX_DESC_CNT; j++, rxbd++) {
Michael Chan5d5d0012007-12-12 11:17:43 -08005213 rxbd->rx_bd_len = buf_size;
Michael Chan13daffa2006-03-20 17:49:20 -08005214 rxbd->rx_bd_flags = RX_BD_FLAGS_START | RX_BD_FLAGS_END;
5215 }
Michael Chan5d5d0012007-12-12 11:17:43 -08005216 if (i == (num_rings - 1))
Michael Chan13daffa2006-03-20 17:49:20 -08005217 j = 0;
5218 else
5219 j = i + 1;
Michael Chan5d5d0012007-12-12 11:17:43 -08005220 rxbd->rx_bd_haddr_hi = (u64) dma[j] >> 32;
5221 rxbd->rx_bd_haddr_lo = (u64) dma[j] & 0xffffffff;
Michael Chan13daffa2006-03-20 17:49:20 -08005222 }
Michael Chan5d5d0012007-12-12 11:17:43 -08005223}
5224
5225static void
Michael Chanbb4f98a2008-06-19 16:38:19 -07005226bnx2_init_rx_ring(struct bnx2 *bp, int ring_num)
Michael Chan5d5d0012007-12-12 11:17:43 -08005227{
5228 int i;
5229 u16 prod, ring_prod;
Michael Chanbb4f98a2008-06-19 16:38:19 -07005230 u32 cid, rx_cid_addr, val;
5231 struct bnx2_napi *bnapi = &bp->bnx2_napi[ring_num];
5232 struct bnx2_rx_ring_info *rxr = &bnapi->rx_ring;
Michael Chan5d5d0012007-12-12 11:17:43 -08005233
Michael Chanbb4f98a2008-06-19 16:38:19 -07005234 if (ring_num == 0)
5235 cid = RX_CID;
5236 else
5237 cid = RX_RSS_CID + ring_num - 1;
5238
5239 rx_cid_addr = GET_CID_ADDR(cid);
5240
5241 bnx2_init_rxbd_rings(rxr->rx_desc_ring, rxr->rx_desc_mapping,
Michael Chan5d5d0012007-12-12 11:17:43 -08005242 bp->rx_buf_use_size, bp->rx_max_ring);
5243
Michael Chanbb4f98a2008-06-19 16:38:19 -07005244 bnx2_init_rx_context(bp, cid);
Michael Chan83e3fc82008-01-29 21:37:17 -08005245
Michael Chan4ce45e02012-12-06 10:33:10 +00005246 if (BNX2_CHIP(bp) == BNX2_CHIP_5709) {
Michael Chane503e062012-12-06 10:33:08 +00005247 val = BNX2_RD(bp, BNX2_MQ_MAP_L2_5);
5248 BNX2_WR(bp, BNX2_MQ_MAP_L2_5, val | BNX2_MQ_MAP_L2_5_ARM);
Michael Chan83e3fc82008-01-29 21:37:17 -08005249 }
5250
Michael Chan62a83132008-01-29 21:35:40 -08005251 bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_PG_BUF_SIZE, 0);
Michael Chan47bf4242007-12-12 11:19:12 -08005252 if (bp->rx_pg_ring_size) {
Michael Chanbb4f98a2008-06-19 16:38:19 -07005253 bnx2_init_rxbd_rings(rxr->rx_pg_desc_ring,
5254 rxr->rx_pg_desc_mapping,
Michael Chan47bf4242007-12-12 11:19:12 -08005255 PAGE_SIZE, bp->rx_max_pg_ring);
5256 val = (bp->rx_buf_use_size << 16) | PAGE_SIZE;
Michael Chan62a83132008-01-29 21:35:40 -08005257 bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_PG_BUF_SIZE, val);
5258 bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_RBDC_KEY,
Michael Chan5e9ad9e2008-06-19 16:43:17 -07005259 BNX2_L2CTX_RBDC_JUMBO_KEY - ring_num);
Michael Chan47bf4242007-12-12 11:19:12 -08005260
Michael Chanbb4f98a2008-06-19 16:38:19 -07005261 val = (u64) rxr->rx_pg_desc_mapping[0] >> 32;
Michael Chan62a83132008-01-29 21:35:40 -08005262 bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_NX_PG_BDHADDR_HI, val);
Michael Chan47bf4242007-12-12 11:19:12 -08005263
Michael Chanbb4f98a2008-06-19 16:38:19 -07005264 val = (u64) rxr->rx_pg_desc_mapping[0] & 0xffffffff;
Michael Chan62a83132008-01-29 21:35:40 -08005265 bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_NX_PG_BDHADDR_LO, val);
Michael Chan47bf4242007-12-12 11:19:12 -08005266
Michael Chan4ce45e02012-12-06 10:33:10 +00005267 if (BNX2_CHIP(bp) == BNX2_CHIP_5709)
Michael Chane503e062012-12-06 10:33:08 +00005268 BNX2_WR(bp, BNX2_MQ_MAP_L2_3, BNX2_MQ_MAP_L2_3_DEFAULT);
Michael Chan47bf4242007-12-12 11:19:12 -08005269 }
Michael Chanb6016b72005-05-26 13:03:09 -07005270
Michael Chanbb4f98a2008-06-19 16:38:19 -07005271 val = (u64) rxr->rx_desc_mapping[0] >> 32;
Michael Chan62a83132008-01-29 21:35:40 -08005272 bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_NX_BDHADDR_HI, val);
Michael Chanb6016b72005-05-26 13:03:09 -07005273
Michael Chanbb4f98a2008-06-19 16:38:19 -07005274 val = (u64) rxr->rx_desc_mapping[0] & 0xffffffff;
Michael Chan62a83132008-01-29 21:35:40 -08005275 bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_NX_BDHADDR_LO, val);
Michael Chanb6016b72005-05-26 13:03:09 -07005276
Michael Chanbb4f98a2008-06-19 16:38:19 -07005277 ring_prod = prod = rxr->rx_pg_prod;
Michael Chan47bf4242007-12-12 11:19:12 -08005278 for (i = 0; i < bp->rx_pg_ring_size; i++) {
Stanislaw Gruszkaa2df00a2010-07-15 22:55:40 +00005279 if (bnx2_alloc_rx_page(bp, rxr, ring_prod, GFP_KERNEL) < 0) {
Joe Perches3a9c6a42010-02-17 15:01:51 +00005280 netdev_warn(bp->dev, "init'ed rx page ring %d with %d/%d pages only\n",
5281 ring_num, i, bp->rx_pg_ring_size);
Michael Chan47bf4242007-12-12 11:19:12 -08005282 break;
Michael Chanb929e532009-12-03 09:46:33 +00005283 }
Michael Chan2bc40782012-12-06 10:33:09 +00005284 prod = BNX2_NEXT_RX_BD(prod);
5285 ring_prod = BNX2_RX_PG_RING_IDX(prod);
Michael Chan47bf4242007-12-12 11:19:12 -08005286 }
Michael Chanbb4f98a2008-06-19 16:38:19 -07005287 rxr->rx_pg_prod = prod;
Michael Chan47bf4242007-12-12 11:19:12 -08005288
Michael Chanbb4f98a2008-06-19 16:38:19 -07005289 ring_prod = prod = rxr->rx_prod;
Michael Chan236b6392006-03-20 17:49:02 -08005290 for (i = 0; i < bp->rx_ring_size; i++) {
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00005291 if (bnx2_alloc_rx_data(bp, rxr, ring_prod, GFP_KERNEL) < 0) {
Joe Perches3a9c6a42010-02-17 15:01:51 +00005292 netdev_warn(bp->dev, "init'ed rx ring %d with %d/%d skbs only\n",
5293 ring_num, i, bp->rx_ring_size);
Michael Chanb6016b72005-05-26 13:03:09 -07005294 break;
Michael Chanb929e532009-12-03 09:46:33 +00005295 }
Michael Chan2bc40782012-12-06 10:33:09 +00005296 prod = BNX2_NEXT_RX_BD(prod);
5297 ring_prod = BNX2_RX_RING_IDX(prod);
Michael Chanb6016b72005-05-26 13:03:09 -07005298 }
Michael Chanbb4f98a2008-06-19 16:38:19 -07005299 rxr->rx_prod = prod;
Michael Chanb6016b72005-05-26 13:03:09 -07005300
Michael Chanbb4f98a2008-06-19 16:38:19 -07005301 rxr->rx_bidx_addr = MB_GET_CID_ADDR(cid) + BNX2_L2CTX_HOST_BDIDX;
5302 rxr->rx_bseq_addr = MB_GET_CID_ADDR(cid) + BNX2_L2CTX_HOST_BSEQ;
5303 rxr->rx_pg_bidx_addr = MB_GET_CID_ADDR(cid) + BNX2_L2CTX_HOST_PG_BDIDX;
Michael Chanb6016b72005-05-26 13:03:09 -07005304
Michael Chane503e062012-12-06 10:33:08 +00005305 BNX2_WR16(bp, rxr->rx_pg_bidx_addr, rxr->rx_pg_prod);
5306 BNX2_WR16(bp, rxr->rx_bidx_addr, prod);
Michael Chanbb4f98a2008-06-19 16:38:19 -07005307
Michael Chane503e062012-12-06 10:33:08 +00005308 BNX2_WR(bp, rxr->rx_bseq_addr, rxr->rx_prod_bseq);
Michael Chanb6016b72005-05-26 13:03:09 -07005309}
5310
Michael Chan35e90102008-06-19 16:37:42 -07005311static void
5312bnx2_init_all_rings(struct bnx2 *bp)
5313{
5314 int i;
Michael Chan5e9ad9e2008-06-19 16:43:17 -07005315 u32 val;
Michael Chan35e90102008-06-19 16:37:42 -07005316
5317 bnx2_clear_ring_states(bp);
5318
Michael Chane503e062012-12-06 10:33:08 +00005319 BNX2_WR(bp, BNX2_TSCH_TSS_CFG, 0);
Michael Chan35e90102008-06-19 16:37:42 -07005320 for (i = 0; i < bp->num_tx_rings; i++)
5321 bnx2_init_tx_ring(bp, i);
5322
5323 if (bp->num_tx_rings > 1)
Michael Chane503e062012-12-06 10:33:08 +00005324 BNX2_WR(bp, BNX2_TSCH_TSS_CFG, ((bp->num_tx_rings - 1) << 24) |
5325 (TX_TSS_CID << 7));
Michael Chan35e90102008-06-19 16:37:42 -07005326
Michael Chane503e062012-12-06 10:33:08 +00005327 BNX2_WR(bp, BNX2_RLUP_RSS_CONFIG, 0);
Michael Chan5e9ad9e2008-06-19 16:43:17 -07005328 bnx2_reg_wr_ind(bp, BNX2_RXP_SCRATCH_RSS_TBL_SZ, 0);
5329
Michael Chanbb4f98a2008-06-19 16:38:19 -07005330 for (i = 0; i < bp->num_rx_rings; i++)
5331 bnx2_init_rx_ring(bp, i);
Michael Chan5e9ad9e2008-06-19 16:43:17 -07005332
5333 if (bp->num_rx_rings > 1) {
Michael Chan22fa1592010-10-11 16:12:00 -07005334 u32 tbl_32 = 0;
Michael Chan5e9ad9e2008-06-19 16:43:17 -07005335
5336 for (i = 0; i < BNX2_RXP_SCRATCH_RSS_TBL_MAX_ENTRIES; i++) {
Michael Chan22fa1592010-10-11 16:12:00 -07005337 int shift = (i % 8) << 2;
5338
5339 tbl_32 |= (i % (bp->num_rx_rings - 1)) << shift;
5340 if ((i % 8) == 7) {
Michael Chane503e062012-12-06 10:33:08 +00005341 BNX2_WR(bp, BNX2_RLUP_RSS_DATA, tbl_32);
5342 BNX2_WR(bp, BNX2_RLUP_RSS_COMMAND, (i >> 3) |
Michael Chan22fa1592010-10-11 16:12:00 -07005343 BNX2_RLUP_RSS_COMMAND_RSS_WRITE_MASK |
5344 BNX2_RLUP_RSS_COMMAND_WRITE |
5345 BNX2_RLUP_RSS_COMMAND_HASH_MASK);
5346 tbl_32 = 0;
5347 }
Michael Chan5e9ad9e2008-06-19 16:43:17 -07005348 }
5349
5350 val = BNX2_RLUP_RSS_CONFIG_IPV4_RSS_TYPE_ALL_XI |
5351 BNX2_RLUP_RSS_CONFIG_IPV6_RSS_TYPE_ALL_XI;
5352
Michael Chane503e062012-12-06 10:33:08 +00005353 BNX2_WR(bp, BNX2_RLUP_RSS_CONFIG, val);
Michael Chan5e9ad9e2008-06-19 16:43:17 -07005354
5355 }
Michael Chan35e90102008-06-19 16:37:42 -07005356}
5357
Michael Chan5d5d0012007-12-12 11:17:43 -08005358static u32 bnx2_find_max_ring(u32 ring_size, u32 max_size)
Michael Chan13daffa2006-03-20 17:49:20 -08005359{
Michael Chan5d5d0012007-12-12 11:17:43 -08005360 u32 max, num_rings = 1;
Michael Chan13daffa2006-03-20 17:49:20 -08005361
Michael Chan2bc40782012-12-06 10:33:09 +00005362 while (ring_size > BNX2_MAX_RX_DESC_CNT) {
5363 ring_size -= BNX2_MAX_RX_DESC_CNT;
Michael Chan13daffa2006-03-20 17:49:20 -08005364 num_rings++;
5365 }
5366 /* round to next power of 2 */
Michael Chan5d5d0012007-12-12 11:17:43 -08005367 max = max_size;
Michael Chan13daffa2006-03-20 17:49:20 -08005368 while ((max & num_rings) == 0)
5369 max >>= 1;
5370
5371 if (num_rings != max)
5372 max <<= 1;
5373
Michael Chan5d5d0012007-12-12 11:17:43 -08005374 return max;
5375}
5376
5377static void
5378bnx2_set_rx_ring_size(struct bnx2 *bp, u32 size)
5379{
Michael Chan84eaa182007-12-12 11:19:57 -08005380 u32 rx_size, rx_space, jumbo_size;
Michael Chan5d5d0012007-12-12 11:17:43 -08005381
5382 /* 8 for CRC and VLAN */
Benjamin Lid89cb6a2008-05-16 22:18:57 -07005383 rx_size = bp->dev->mtu + ETH_HLEN + BNX2_RX_OFFSET + 8;
Michael Chan5d5d0012007-12-12 11:17:43 -08005384
Michael Chan84eaa182007-12-12 11:19:57 -08005385 rx_space = SKB_DATA_ALIGN(rx_size + BNX2_RX_ALIGN) + NET_SKB_PAD +
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00005386 SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
Michael Chan84eaa182007-12-12 11:19:57 -08005387
Benjamin Li601d3d12008-05-16 22:19:35 -07005388 bp->rx_copy_thresh = BNX2_RX_COPY_THRESH;
Michael Chan47bf4242007-12-12 11:19:12 -08005389 bp->rx_pg_ring_size = 0;
5390 bp->rx_max_pg_ring = 0;
5391 bp->rx_max_pg_ring_idx = 0;
David S. Millerf86e82f2008-01-21 17:15:40 -08005392 if ((rx_space > PAGE_SIZE) && !(bp->flags & BNX2_FLAG_JUMBO_BROKEN)) {
Michael Chan84eaa182007-12-12 11:19:57 -08005393 int pages = PAGE_ALIGN(bp->dev->mtu - 40) >> PAGE_SHIFT;
5394
5395 jumbo_size = size * pages;
Michael Chan2bc40782012-12-06 10:33:09 +00005396 if (jumbo_size > BNX2_MAX_TOTAL_RX_PG_DESC_CNT)
5397 jumbo_size = BNX2_MAX_TOTAL_RX_PG_DESC_CNT;
Michael Chan84eaa182007-12-12 11:19:57 -08005398
5399 bp->rx_pg_ring_size = jumbo_size;
5400 bp->rx_max_pg_ring = bnx2_find_max_ring(jumbo_size,
Michael Chan2bc40782012-12-06 10:33:09 +00005401 BNX2_MAX_RX_PG_RINGS);
5402 bp->rx_max_pg_ring_idx =
5403 (bp->rx_max_pg_ring * BNX2_RX_DESC_CNT) - 1;
Benjamin Li601d3d12008-05-16 22:19:35 -07005404 rx_size = BNX2_RX_COPY_THRESH + BNX2_RX_OFFSET;
Michael Chan84eaa182007-12-12 11:19:57 -08005405 bp->rx_copy_thresh = 0;
5406 }
Michael Chan5d5d0012007-12-12 11:17:43 -08005407
5408 bp->rx_buf_use_size = rx_size;
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00005409 /* hw alignment + build_skb() overhead*/
5410 bp->rx_buf_size = SKB_DATA_ALIGN(bp->rx_buf_use_size + BNX2_RX_ALIGN) +
5411 NET_SKB_PAD + SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
Benjamin Lid89cb6a2008-05-16 22:18:57 -07005412 bp->rx_jumbo_thresh = rx_size - BNX2_RX_OFFSET;
Michael Chan5d5d0012007-12-12 11:17:43 -08005413 bp->rx_ring_size = size;
Michael Chan2bc40782012-12-06 10:33:09 +00005414 bp->rx_max_ring = bnx2_find_max_ring(size, BNX2_MAX_RX_RINGS);
5415 bp->rx_max_ring_idx = (bp->rx_max_ring * BNX2_RX_DESC_CNT) - 1;
Michael Chan13daffa2006-03-20 17:49:20 -08005416}
5417
5418static void
Michael Chanb6016b72005-05-26 13:03:09 -07005419bnx2_free_tx_skbs(struct bnx2 *bp)
5420{
5421 int i;
5422
Michael Chan35e90102008-06-19 16:37:42 -07005423 for (i = 0; i < bp->num_tx_rings; i++) {
5424 struct bnx2_napi *bnapi = &bp->bnx2_napi[i];
5425 struct bnx2_tx_ring_info *txr = &bnapi->tx_ring;
5426 int j;
Michael Chanb6016b72005-05-26 13:03:09 -07005427
Michael Chan35e90102008-06-19 16:37:42 -07005428 if (txr->tx_buf_ring == NULL)
Michael Chanb6016b72005-05-26 13:03:09 -07005429 continue;
Michael Chanb6016b72005-05-26 13:03:09 -07005430
Michael Chan2bc40782012-12-06 10:33:09 +00005431 for (j = 0; j < BNX2_TX_DESC_CNT; ) {
5432 struct bnx2_sw_tx_bd *tx_buf = &txr->tx_buf_ring[j];
Michael Chan35e90102008-06-19 16:37:42 -07005433 struct sk_buff *skb = tx_buf->skb;
Alexander Duycke95524a2009-12-02 16:47:57 +00005434 int k, last;
Michael Chan35e90102008-06-19 16:37:42 -07005435
5436 if (skb == NULL) {
Michael Chan2bc40782012-12-06 10:33:09 +00005437 j = BNX2_NEXT_TX_BD(j);
Michael Chan35e90102008-06-19 16:37:42 -07005438 continue;
5439 }
5440
Stanislaw Gruszka36227e82010-07-15 04:25:50 +00005441 dma_unmap_single(&bp->pdev->dev,
FUJITA Tomonori1a4ccc22010-04-01 16:56:57 +00005442 dma_unmap_addr(tx_buf, mapping),
Alexander Duycke95524a2009-12-02 16:47:57 +00005443 skb_headlen(skb),
5444 PCI_DMA_TODEVICE);
Michael Chanb6016b72005-05-26 13:03:09 -07005445
Michael Chan35e90102008-06-19 16:37:42 -07005446 tx_buf->skb = NULL;
Michael Chanb6016b72005-05-26 13:03:09 -07005447
Alexander Duycke95524a2009-12-02 16:47:57 +00005448 last = tx_buf->nr_frags;
Michael Chan2bc40782012-12-06 10:33:09 +00005449 j = BNX2_NEXT_TX_BD(j);
5450 for (k = 0; k < last; k++, j = BNX2_NEXT_TX_BD(j)) {
5451 tx_buf = &txr->tx_buf_ring[BNX2_TX_RING_IDX(j)];
Stanislaw Gruszka36227e82010-07-15 04:25:50 +00005452 dma_unmap_page(&bp->pdev->dev,
FUJITA Tomonori1a4ccc22010-04-01 16:56:57 +00005453 dma_unmap_addr(tx_buf, mapping),
Eric Dumazet9e903e02011-10-18 21:00:24 +00005454 skb_frag_size(&skb_shinfo(skb)->frags[k]),
Alexander Duycke95524a2009-12-02 16:47:57 +00005455 PCI_DMA_TODEVICE);
5456 }
Michael Chan35e90102008-06-19 16:37:42 -07005457 dev_kfree_skb(skb);
Michael Chanb6016b72005-05-26 13:03:09 -07005458 }
Eric Dumazete9831902011-11-29 11:53:05 +00005459 netdev_tx_reset_queue(netdev_get_tx_queue(bp->dev, i));
Michael Chanb6016b72005-05-26 13:03:09 -07005460 }
Michael Chanb6016b72005-05-26 13:03:09 -07005461}
5462
5463static void
5464bnx2_free_rx_skbs(struct bnx2 *bp)
5465{
5466 int i;
5467
Michael Chanbb4f98a2008-06-19 16:38:19 -07005468 for (i = 0; i < bp->num_rx_rings; i++) {
5469 struct bnx2_napi *bnapi = &bp->bnx2_napi[i];
5470 struct bnx2_rx_ring_info *rxr = &bnapi->rx_ring;
5471 int j;
Michael Chanb6016b72005-05-26 13:03:09 -07005472
Michael Chanbb4f98a2008-06-19 16:38:19 -07005473 if (rxr->rx_buf_ring == NULL)
5474 return;
Michael Chanb6016b72005-05-26 13:03:09 -07005475
Michael Chanbb4f98a2008-06-19 16:38:19 -07005476 for (j = 0; j < bp->rx_max_ring_idx; j++) {
Michael Chan2bc40782012-12-06 10:33:09 +00005477 struct bnx2_sw_bd *rx_buf = &rxr->rx_buf_ring[j];
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00005478 u8 *data = rx_buf->data;
Michael Chanb6016b72005-05-26 13:03:09 -07005479
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00005480 if (data == NULL)
Michael Chanbb4f98a2008-06-19 16:38:19 -07005481 continue;
Michael Chanb6016b72005-05-26 13:03:09 -07005482
Stanislaw Gruszka36227e82010-07-15 04:25:50 +00005483 dma_unmap_single(&bp->pdev->dev,
FUJITA Tomonori1a4ccc22010-04-01 16:56:57 +00005484 dma_unmap_addr(rx_buf, mapping),
Michael Chanbb4f98a2008-06-19 16:38:19 -07005485 bp->rx_buf_use_size,
5486 PCI_DMA_FROMDEVICE);
Michael Chanb6016b72005-05-26 13:03:09 -07005487
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00005488 rx_buf->data = NULL;
Michael Chanbb4f98a2008-06-19 16:38:19 -07005489
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00005490 kfree(data);
Michael Chanbb4f98a2008-06-19 16:38:19 -07005491 }
5492 for (j = 0; j < bp->rx_max_pg_ring_idx; j++)
5493 bnx2_free_rx_page(bp, rxr, j);
Michael Chanb6016b72005-05-26 13:03:09 -07005494 }
5495}
5496
5497static void
5498bnx2_free_skbs(struct bnx2 *bp)
5499{
5500 bnx2_free_tx_skbs(bp);
5501 bnx2_free_rx_skbs(bp);
5502}
5503
5504static int
5505bnx2_reset_nic(struct bnx2 *bp, u32 reset_code)
5506{
5507 int rc;
5508
5509 rc = bnx2_reset_chip(bp, reset_code);
5510 bnx2_free_skbs(bp);
5511 if (rc)
5512 return rc;
5513
Michael Chanfba9fe92006-06-12 22:21:25 -07005514 if ((rc = bnx2_init_chip(bp)) != 0)
5515 return rc;
5516
Michael Chan35e90102008-06-19 16:37:42 -07005517 bnx2_init_all_rings(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07005518 return 0;
5519}
5520
5521static int
Michael Chan9a120bc2008-05-16 22:17:45 -07005522bnx2_init_nic(struct bnx2 *bp, int reset_phy)
Michael Chanb6016b72005-05-26 13:03:09 -07005523{
5524 int rc;
5525
5526 if ((rc = bnx2_reset_nic(bp, BNX2_DRV_MSG_CODE_RESET)) != 0)
5527 return rc;
5528
Michael Chan80be4432006-11-19 14:07:28 -08005529 spin_lock_bh(&bp->phy_lock);
Michael Chan9a120bc2008-05-16 22:17:45 -07005530 bnx2_init_phy(bp, reset_phy);
Michael Chanb6016b72005-05-26 13:03:09 -07005531 bnx2_set_link(bp);
Michael Chan543a8272008-05-02 16:56:44 -07005532 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
5533 bnx2_remote_phy_event(bp);
Michael Chan0d8a6572007-07-07 22:49:43 -07005534 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07005535 return 0;
5536}
5537
5538static int
Michael Chan74bf4ba2008-10-09 12:21:08 -07005539bnx2_shutdown_chip(struct bnx2 *bp)
5540{
5541 u32 reset_code;
5542
5543 if (bp->flags & BNX2_FLAG_NO_WOL)
5544 reset_code = BNX2_DRV_MSG_CODE_UNLOAD_LNK_DN;
5545 else if (bp->wol)
5546 reset_code = BNX2_DRV_MSG_CODE_SUSPEND_WOL;
5547 else
5548 reset_code = BNX2_DRV_MSG_CODE_SUSPEND_NO_WOL;
5549
5550 return bnx2_reset_chip(bp, reset_code);
5551}
5552
5553static int
Michael Chanb6016b72005-05-26 13:03:09 -07005554bnx2_test_registers(struct bnx2 *bp)
5555{
5556 int ret;
Michael Chan5bae30c2007-05-03 13:18:46 -07005557 int i, is_5709;
Arjan van de Venf71e1302006-03-03 21:33:57 -05005558 static const struct {
Michael Chanb6016b72005-05-26 13:03:09 -07005559 u16 offset;
5560 u16 flags;
Michael Chan5bae30c2007-05-03 13:18:46 -07005561#define BNX2_FL_NOT_5709 1
Michael Chanb6016b72005-05-26 13:03:09 -07005562 u32 rw_mask;
5563 u32 ro_mask;
5564 } reg_tbl[] = {
5565 { 0x006c, 0, 0x00000000, 0x0000003f },
5566 { 0x0090, 0, 0xffffffff, 0x00000000 },
5567 { 0x0094, 0, 0x00000000, 0x00000000 },
5568
Michael Chan5bae30c2007-05-03 13:18:46 -07005569 { 0x0404, BNX2_FL_NOT_5709, 0x00003f00, 0x00000000 },
5570 { 0x0418, BNX2_FL_NOT_5709, 0x00000000, 0xffffffff },
5571 { 0x041c, BNX2_FL_NOT_5709, 0x00000000, 0xffffffff },
5572 { 0x0420, BNX2_FL_NOT_5709, 0x00000000, 0x80ffffff },
5573 { 0x0424, BNX2_FL_NOT_5709, 0x00000000, 0x00000000 },
5574 { 0x0428, BNX2_FL_NOT_5709, 0x00000000, 0x00000001 },
5575 { 0x0450, BNX2_FL_NOT_5709, 0x00000000, 0x0000ffff },
5576 { 0x0454, BNX2_FL_NOT_5709, 0x00000000, 0xffffffff },
5577 { 0x0458, BNX2_FL_NOT_5709, 0x00000000, 0xffffffff },
Michael Chanb6016b72005-05-26 13:03:09 -07005578
Michael Chan5bae30c2007-05-03 13:18:46 -07005579 { 0x0808, BNX2_FL_NOT_5709, 0x00000000, 0xffffffff },
5580 { 0x0854, BNX2_FL_NOT_5709, 0x00000000, 0xffffffff },
5581 { 0x0868, BNX2_FL_NOT_5709, 0x00000000, 0x77777777 },
5582 { 0x086c, BNX2_FL_NOT_5709, 0x00000000, 0x77777777 },
5583 { 0x0870, BNX2_FL_NOT_5709, 0x00000000, 0x77777777 },
5584 { 0x0874, BNX2_FL_NOT_5709, 0x00000000, 0x77777777 },
Michael Chanb6016b72005-05-26 13:03:09 -07005585
Michael Chan5bae30c2007-05-03 13:18:46 -07005586 { 0x0c00, BNX2_FL_NOT_5709, 0x00000000, 0x00000001 },
5587 { 0x0c04, BNX2_FL_NOT_5709, 0x00000000, 0x03ff0001 },
5588 { 0x0c08, BNX2_FL_NOT_5709, 0x0f0ff073, 0x00000000 },
Michael Chanb6016b72005-05-26 13:03:09 -07005589
5590 { 0x1000, 0, 0x00000000, 0x00000001 },
Michael Chan15b169c2008-05-02 16:57:08 -07005591 { 0x1004, BNX2_FL_NOT_5709, 0x00000000, 0x000f0001 },
Michael Chanb6016b72005-05-26 13:03:09 -07005592
5593 { 0x1408, 0, 0x01c00800, 0x00000000 },
5594 { 0x149c, 0, 0x8000ffff, 0x00000000 },
5595 { 0x14a8, 0, 0x00000000, 0x000001ff },
Michael Chan5b0c76a2005-11-04 08:45:49 -08005596 { 0x14ac, 0, 0x0fffffff, 0x10000000 },
Michael Chanb6016b72005-05-26 13:03:09 -07005597 { 0x14b0, 0, 0x00000002, 0x00000001 },
5598 { 0x14b8, 0, 0x00000000, 0x00000000 },
5599 { 0x14c0, 0, 0x00000000, 0x00000009 },
5600 { 0x14c4, 0, 0x00003fff, 0x00000000 },
5601 { 0x14cc, 0, 0x00000000, 0x00000001 },
5602 { 0x14d0, 0, 0xffffffff, 0x00000000 },
Michael Chanb6016b72005-05-26 13:03:09 -07005603
5604 { 0x1800, 0, 0x00000000, 0x00000001 },
5605 { 0x1804, 0, 0x00000000, 0x00000003 },
Michael Chanb6016b72005-05-26 13:03:09 -07005606
5607 { 0x2800, 0, 0x00000000, 0x00000001 },
5608 { 0x2804, 0, 0x00000000, 0x00003f01 },
5609 { 0x2808, 0, 0x0f3f3f03, 0x00000000 },
5610 { 0x2810, 0, 0xffff0000, 0x00000000 },
5611 { 0x2814, 0, 0xffff0000, 0x00000000 },
5612 { 0x2818, 0, 0xffff0000, 0x00000000 },
5613 { 0x281c, 0, 0xffff0000, 0x00000000 },
5614 { 0x2834, 0, 0xffffffff, 0x00000000 },
5615 { 0x2840, 0, 0x00000000, 0xffffffff },
5616 { 0x2844, 0, 0x00000000, 0xffffffff },
5617 { 0x2848, 0, 0xffffffff, 0x00000000 },
5618 { 0x284c, 0, 0xf800f800, 0x07ff07ff },
5619
5620 { 0x2c00, 0, 0x00000000, 0x00000011 },
5621 { 0x2c04, 0, 0x00000000, 0x00030007 },
5622
Michael Chanb6016b72005-05-26 13:03:09 -07005623 { 0x3c00, 0, 0x00000000, 0x00000001 },
5624 { 0x3c04, 0, 0x00000000, 0x00070000 },
5625 { 0x3c08, 0, 0x00007f71, 0x07f00000 },
5626 { 0x3c0c, 0, 0x1f3ffffc, 0x00000000 },
5627 { 0x3c10, 0, 0xffffffff, 0x00000000 },
5628 { 0x3c14, 0, 0x00000000, 0xffffffff },
5629 { 0x3c18, 0, 0x00000000, 0xffffffff },
5630 { 0x3c1c, 0, 0xfffff000, 0x00000000 },
5631 { 0x3c20, 0, 0xffffff00, 0x00000000 },
Michael Chanb6016b72005-05-26 13:03:09 -07005632
5633 { 0x5004, 0, 0x00000000, 0x0000007f },
5634 { 0x5008, 0, 0x0f0007ff, 0x00000000 },
Michael Chanb6016b72005-05-26 13:03:09 -07005635
Michael Chanb6016b72005-05-26 13:03:09 -07005636 { 0x5c00, 0, 0x00000000, 0x00000001 },
5637 { 0x5c04, 0, 0x00000000, 0x0003000f },
5638 { 0x5c08, 0, 0x00000003, 0x00000000 },
5639 { 0x5c0c, 0, 0x0000fff8, 0x00000000 },
5640 { 0x5c10, 0, 0x00000000, 0xffffffff },
5641 { 0x5c80, 0, 0x00000000, 0x0f7113f1 },
5642 { 0x5c84, 0, 0x00000000, 0x0000f333 },
5643 { 0x5c88, 0, 0x00000000, 0x00077373 },
5644 { 0x5c8c, 0, 0x00000000, 0x0007f737 },
5645
5646 { 0x6808, 0, 0x0000ff7f, 0x00000000 },
5647 { 0x680c, 0, 0xffffffff, 0x00000000 },
5648 { 0x6810, 0, 0xffffffff, 0x00000000 },
5649 { 0x6814, 0, 0xffffffff, 0x00000000 },
5650 { 0x6818, 0, 0xffffffff, 0x00000000 },
5651 { 0x681c, 0, 0xffffffff, 0x00000000 },
5652 { 0x6820, 0, 0x00ff00ff, 0x00000000 },
5653 { 0x6824, 0, 0x00ff00ff, 0x00000000 },
5654 { 0x6828, 0, 0x00ff00ff, 0x00000000 },
5655 { 0x682c, 0, 0x03ff03ff, 0x00000000 },
5656 { 0x6830, 0, 0x03ff03ff, 0x00000000 },
5657 { 0x6834, 0, 0x03ff03ff, 0x00000000 },
5658 { 0x6838, 0, 0x03ff03ff, 0x00000000 },
5659 { 0x683c, 0, 0x0000ffff, 0x00000000 },
5660 { 0x6840, 0, 0x00000ff0, 0x00000000 },
5661 { 0x6844, 0, 0x00ffff00, 0x00000000 },
5662 { 0x684c, 0, 0xffffffff, 0x00000000 },
5663 { 0x6850, 0, 0x7f7f7f7f, 0x00000000 },
5664 { 0x6854, 0, 0x7f7f7f7f, 0x00000000 },
5665 { 0x6858, 0, 0x7f7f7f7f, 0x00000000 },
5666 { 0x685c, 0, 0x7f7f7f7f, 0x00000000 },
5667 { 0x6908, 0, 0x00000000, 0x0001ff0f },
5668 { 0x690c, 0, 0x00000000, 0x0ffe00f0 },
5669
5670 { 0xffff, 0, 0x00000000, 0x00000000 },
5671 };
5672
5673 ret = 0;
Michael Chan5bae30c2007-05-03 13:18:46 -07005674 is_5709 = 0;
Michael Chan4ce45e02012-12-06 10:33:10 +00005675 if (BNX2_CHIP(bp) == BNX2_CHIP_5709)
Michael Chan5bae30c2007-05-03 13:18:46 -07005676 is_5709 = 1;
5677
Michael Chanb6016b72005-05-26 13:03:09 -07005678 for (i = 0; reg_tbl[i].offset != 0xffff; i++) {
5679 u32 offset, rw_mask, ro_mask, save_val, val;
Michael Chan5bae30c2007-05-03 13:18:46 -07005680 u16 flags = reg_tbl[i].flags;
5681
5682 if (is_5709 && (flags & BNX2_FL_NOT_5709))
5683 continue;
Michael Chanb6016b72005-05-26 13:03:09 -07005684
5685 offset = (u32) reg_tbl[i].offset;
5686 rw_mask = reg_tbl[i].rw_mask;
5687 ro_mask = reg_tbl[i].ro_mask;
5688
Peter Hagervall14ab9b82005-08-10 14:18:16 -07005689 save_val = readl(bp->regview + offset);
Michael Chanb6016b72005-05-26 13:03:09 -07005690
Peter Hagervall14ab9b82005-08-10 14:18:16 -07005691 writel(0, bp->regview + offset);
Michael Chanb6016b72005-05-26 13:03:09 -07005692
Peter Hagervall14ab9b82005-08-10 14:18:16 -07005693 val = readl(bp->regview + offset);
Michael Chanb6016b72005-05-26 13:03:09 -07005694 if ((val & rw_mask) != 0) {
5695 goto reg_test_err;
5696 }
5697
5698 if ((val & ro_mask) != (save_val & ro_mask)) {
5699 goto reg_test_err;
5700 }
5701
Peter Hagervall14ab9b82005-08-10 14:18:16 -07005702 writel(0xffffffff, bp->regview + offset);
Michael Chanb6016b72005-05-26 13:03:09 -07005703
Peter Hagervall14ab9b82005-08-10 14:18:16 -07005704 val = readl(bp->regview + offset);
Michael Chanb6016b72005-05-26 13:03:09 -07005705 if ((val & rw_mask) != rw_mask) {
5706 goto reg_test_err;
5707 }
5708
5709 if ((val & ro_mask) != (save_val & ro_mask)) {
5710 goto reg_test_err;
5711 }
5712
Peter Hagervall14ab9b82005-08-10 14:18:16 -07005713 writel(save_val, bp->regview + offset);
Michael Chanb6016b72005-05-26 13:03:09 -07005714 continue;
5715
5716reg_test_err:
Peter Hagervall14ab9b82005-08-10 14:18:16 -07005717 writel(save_val, bp->regview + offset);
Michael Chanb6016b72005-05-26 13:03:09 -07005718 ret = -ENODEV;
5719 break;
5720 }
5721 return ret;
5722}
5723
5724static int
5725bnx2_do_mem_test(struct bnx2 *bp, u32 start, u32 size)
5726{
Arjan van de Venf71e1302006-03-03 21:33:57 -05005727 static const u32 test_pattern[] = { 0x00000000, 0xffffffff, 0x55555555,
Michael Chanb6016b72005-05-26 13:03:09 -07005728 0xaaaaaaaa , 0xaa55aa55, 0x55aa55aa };
5729 int i;
5730
5731 for (i = 0; i < sizeof(test_pattern) / 4; i++) {
5732 u32 offset;
5733
5734 for (offset = 0; offset < size; offset += 4) {
5735
Michael Chan2726d6e2008-01-29 21:35:05 -08005736 bnx2_reg_wr_ind(bp, start + offset, test_pattern[i]);
Michael Chanb6016b72005-05-26 13:03:09 -07005737
Michael Chan2726d6e2008-01-29 21:35:05 -08005738 if (bnx2_reg_rd_ind(bp, start + offset) !=
Michael Chanb6016b72005-05-26 13:03:09 -07005739 test_pattern[i]) {
5740 return -ENODEV;
5741 }
5742 }
5743 }
5744 return 0;
5745}
5746
5747static int
5748bnx2_test_memory(struct bnx2 *bp)
5749{
5750 int ret = 0;
5751 int i;
Michael Chan5bae30c2007-05-03 13:18:46 -07005752 static struct mem_entry {
Michael Chanb6016b72005-05-26 13:03:09 -07005753 u32 offset;
5754 u32 len;
Michael Chan5bae30c2007-05-03 13:18:46 -07005755 } mem_tbl_5706[] = {
Michael Chanb6016b72005-05-26 13:03:09 -07005756 { 0x60000, 0x4000 },
Michael Chan5b0c76a2005-11-04 08:45:49 -08005757 { 0xa0000, 0x3000 },
Michael Chanb6016b72005-05-26 13:03:09 -07005758 { 0xe0000, 0x4000 },
5759 { 0x120000, 0x4000 },
5760 { 0x1a0000, 0x4000 },
5761 { 0x160000, 0x4000 },
5762 { 0xffffffff, 0 },
Michael Chan5bae30c2007-05-03 13:18:46 -07005763 },
5764 mem_tbl_5709[] = {
5765 { 0x60000, 0x4000 },
5766 { 0xa0000, 0x3000 },
5767 { 0xe0000, 0x4000 },
5768 { 0x120000, 0x4000 },
5769 { 0x1a0000, 0x4000 },
5770 { 0xffffffff, 0 },
Michael Chanb6016b72005-05-26 13:03:09 -07005771 };
Michael Chan5bae30c2007-05-03 13:18:46 -07005772 struct mem_entry *mem_tbl;
5773
Michael Chan4ce45e02012-12-06 10:33:10 +00005774 if (BNX2_CHIP(bp) == BNX2_CHIP_5709)
Michael Chan5bae30c2007-05-03 13:18:46 -07005775 mem_tbl = mem_tbl_5709;
5776 else
5777 mem_tbl = mem_tbl_5706;
Michael Chanb6016b72005-05-26 13:03:09 -07005778
5779 for (i = 0; mem_tbl[i].offset != 0xffffffff; i++) {
5780 if ((ret = bnx2_do_mem_test(bp, mem_tbl[i].offset,
5781 mem_tbl[i].len)) != 0) {
5782 return ret;
5783 }
5784 }
Jeff Garzik6aa20a22006-09-13 13:24:59 -04005785
Michael Chanb6016b72005-05-26 13:03:09 -07005786 return ret;
5787}
5788
Michael Chanbc5a0692006-01-23 16:13:22 -08005789#define BNX2_MAC_LOOPBACK 0
5790#define BNX2_PHY_LOOPBACK 1
5791
Michael Chanb6016b72005-05-26 13:03:09 -07005792static int
Michael Chanbc5a0692006-01-23 16:13:22 -08005793bnx2_run_loopback(struct bnx2 *bp, int loopback_mode)
Michael Chanb6016b72005-05-26 13:03:09 -07005794{
5795 unsigned int pkt_size, num_pkts, i;
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00005796 struct sk_buff *skb;
5797 u8 *data;
Michael Chanb6016b72005-05-26 13:03:09 -07005798 unsigned char *packet;
Michael Chanbc5a0692006-01-23 16:13:22 -08005799 u16 rx_start_idx, rx_idx;
Michael Chanb6016b72005-05-26 13:03:09 -07005800 dma_addr_t map;
Michael Chan2bc40782012-12-06 10:33:09 +00005801 struct bnx2_tx_bd *txbd;
5802 struct bnx2_sw_bd *rx_buf;
Michael Chanb6016b72005-05-26 13:03:09 -07005803 struct l2_fhdr *rx_hdr;
5804 int ret = -ENODEV;
Michael Chanc76c0472007-12-20 20:01:19 -08005805 struct bnx2_napi *bnapi = &bp->bnx2_napi[0], *tx_napi;
Michael Chan35e90102008-06-19 16:37:42 -07005806 struct bnx2_tx_ring_info *txr = &bnapi->tx_ring;
Michael Chanbb4f98a2008-06-19 16:38:19 -07005807 struct bnx2_rx_ring_info *rxr = &bnapi->rx_ring;
Michael Chanc76c0472007-12-20 20:01:19 -08005808
5809 tx_napi = bnapi;
Michael Chanb6016b72005-05-26 13:03:09 -07005810
Michael Chan35e90102008-06-19 16:37:42 -07005811 txr = &tx_napi->tx_ring;
Michael Chanbb4f98a2008-06-19 16:38:19 -07005812 rxr = &bnapi->rx_ring;
Michael Chanbc5a0692006-01-23 16:13:22 -08005813 if (loopback_mode == BNX2_MAC_LOOPBACK) {
5814 bp->loopback = MAC_LOOPBACK;
5815 bnx2_set_mac_loopback(bp);
5816 }
5817 else if (loopback_mode == BNX2_PHY_LOOPBACK) {
Michael Chan583c28e2008-01-21 19:51:35 -08005818 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
Michael Chan489310a2007-10-10 16:16:31 -07005819 return 0;
5820
Michael Chan80be4432006-11-19 14:07:28 -08005821 bp->loopback = PHY_LOOPBACK;
Michael Chanbc5a0692006-01-23 16:13:22 -08005822 bnx2_set_phy_loopback(bp);
5823 }
5824 else
5825 return -EINVAL;
Michael Chanb6016b72005-05-26 13:03:09 -07005826
Michael Chan84eaa182007-12-12 11:19:57 -08005827 pkt_size = min(bp->dev->mtu + ETH_HLEN, bp->rx_jumbo_thresh - 4);
Michael Chan932f3772006-08-15 01:39:36 -07005828 skb = netdev_alloc_skb(bp->dev, pkt_size);
John W. Linvilleb6cbc3b62005-11-10 12:58:00 -08005829 if (!skb)
5830 return -ENOMEM;
Michael Chanb6016b72005-05-26 13:03:09 -07005831 packet = skb_put(skb, pkt_size);
Joe Perchesd458cdf2013-10-01 19:04:40 -07005832 memcpy(packet, bp->dev->dev_addr, ETH_ALEN);
5833 memset(packet + ETH_ALEN, 0x0, 8);
Michael Chanb6016b72005-05-26 13:03:09 -07005834 for (i = 14; i < pkt_size; i++)
5835 packet[i] = (unsigned char) (i & 0xff);
5836
Stanislaw Gruszka36227e82010-07-15 04:25:50 +00005837 map = dma_map_single(&bp->pdev->dev, skb->data, pkt_size,
5838 PCI_DMA_TODEVICE);
5839 if (dma_mapping_error(&bp->pdev->dev, map)) {
Benjamin Li3d16af82008-10-09 12:26:41 -07005840 dev_kfree_skb(skb);
5841 return -EIO;
5842 }
Michael Chanb6016b72005-05-26 13:03:09 -07005843
Michael Chane503e062012-12-06 10:33:08 +00005844 BNX2_WR(bp, BNX2_HC_COMMAND,
5845 bp->hc_cmd | BNX2_HC_COMMAND_COAL_NOW_WO_INT);
Michael Chanbf5295b2006-03-23 01:11:56 -08005846
Michael Chane503e062012-12-06 10:33:08 +00005847 BNX2_RD(bp, BNX2_HC_COMMAND);
Michael Chanb6016b72005-05-26 13:03:09 -07005848
5849 udelay(5);
Michael Chan35efa7c2007-12-20 19:56:37 -08005850 rx_start_idx = bnx2_get_hw_rx_cons(bnapi);
Michael Chanb6016b72005-05-26 13:03:09 -07005851
Michael Chanb6016b72005-05-26 13:03:09 -07005852 num_pkts = 0;
5853
Michael Chan2bc40782012-12-06 10:33:09 +00005854 txbd = &txr->tx_desc_ring[BNX2_TX_RING_IDX(txr->tx_prod)];
Michael Chanb6016b72005-05-26 13:03:09 -07005855
5856 txbd->tx_bd_haddr_hi = (u64) map >> 32;
5857 txbd->tx_bd_haddr_lo = (u64) map & 0xffffffff;
5858 txbd->tx_bd_mss_nbytes = pkt_size;
5859 txbd->tx_bd_vlan_tag_flags = TX_BD_FLAGS_START | TX_BD_FLAGS_END;
5860
5861 num_pkts++;
Michael Chan2bc40782012-12-06 10:33:09 +00005862 txr->tx_prod = BNX2_NEXT_TX_BD(txr->tx_prod);
Michael Chan35e90102008-06-19 16:37:42 -07005863 txr->tx_prod_bseq += pkt_size;
Michael Chanb6016b72005-05-26 13:03:09 -07005864
Michael Chane503e062012-12-06 10:33:08 +00005865 BNX2_WR16(bp, txr->tx_bidx_addr, txr->tx_prod);
5866 BNX2_WR(bp, txr->tx_bseq_addr, txr->tx_prod_bseq);
Michael Chanb6016b72005-05-26 13:03:09 -07005867
5868 udelay(100);
5869
Michael Chane503e062012-12-06 10:33:08 +00005870 BNX2_WR(bp, BNX2_HC_COMMAND,
5871 bp->hc_cmd | BNX2_HC_COMMAND_COAL_NOW_WO_INT);
Michael Chanbf5295b2006-03-23 01:11:56 -08005872
Michael Chane503e062012-12-06 10:33:08 +00005873 BNX2_RD(bp, BNX2_HC_COMMAND);
Michael Chanb6016b72005-05-26 13:03:09 -07005874
5875 udelay(5);
5876
Stanislaw Gruszka36227e82010-07-15 04:25:50 +00005877 dma_unmap_single(&bp->pdev->dev, map, pkt_size, PCI_DMA_TODEVICE);
Michael Chan745720e2006-06-29 12:37:41 -07005878 dev_kfree_skb(skb);
Michael Chanb6016b72005-05-26 13:03:09 -07005879
Michael Chan35e90102008-06-19 16:37:42 -07005880 if (bnx2_get_hw_tx_cons(tx_napi) != txr->tx_prod)
Michael Chanb6016b72005-05-26 13:03:09 -07005881 goto loopback_test_done;
Michael Chanb6016b72005-05-26 13:03:09 -07005882
Michael Chan35efa7c2007-12-20 19:56:37 -08005883 rx_idx = bnx2_get_hw_rx_cons(bnapi);
Michael Chanb6016b72005-05-26 13:03:09 -07005884 if (rx_idx != rx_start_idx + num_pkts) {
5885 goto loopback_test_done;
5886 }
5887
Michael Chanbb4f98a2008-06-19 16:38:19 -07005888 rx_buf = &rxr->rx_buf_ring[rx_start_idx];
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00005889 data = rx_buf->data;
Michael Chanb6016b72005-05-26 13:03:09 -07005890
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00005891 rx_hdr = get_l2_fhdr(data);
5892 data = (u8 *)rx_hdr + BNX2_RX_OFFSET;
Michael Chanb6016b72005-05-26 13:03:09 -07005893
Stanislaw Gruszka36227e82010-07-15 04:25:50 +00005894 dma_sync_single_for_cpu(&bp->pdev->dev,
FUJITA Tomonori1a4ccc22010-04-01 16:56:57 +00005895 dma_unmap_addr(rx_buf, mapping),
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00005896 bp->rx_buf_use_size, PCI_DMA_FROMDEVICE);
Michael Chanb6016b72005-05-26 13:03:09 -07005897
Michael Chanade2bfe2006-01-23 16:09:51 -08005898 if (rx_hdr->l2_fhdr_status &
Michael Chanb6016b72005-05-26 13:03:09 -07005899 (L2_FHDR_ERRORS_BAD_CRC |
5900 L2_FHDR_ERRORS_PHY_DECODE |
5901 L2_FHDR_ERRORS_ALIGNMENT |
5902 L2_FHDR_ERRORS_TOO_SHORT |
5903 L2_FHDR_ERRORS_GIANT_FRAME)) {
5904
5905 goto loopback_test_done;
5906 }
5907
5908 if ((rx_hdr->l2_fhdr_pkt_len - 4) != pkt_size) {
5909 goto loopback_test_done;
5910 }
5911
5912 for (i = 14; i < pkt_size; i++) {
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00005913 if (*(data + i) != (unsigned char) (i & 0xff)) {
Michael Chanb6016b72005-05-26 13:03:09 -07005914 goto loopback_test_done;
5915 }
5916 }
5917
5918 ret = 0;
5919
5920loopback_test_done:
5921 bp->loopback = 0;
5922 return ret;
5923}
5924
Michael Chanbc5a0692006-01-23 16:13:22 -08005925#define BNX2_MAC_LOOPBACK_FAILED 1
5926#define BNX2_PHY_LOOPBACK_FAILED 2
5927#define BNX2_LOOPBACK_FAILED (BNX2_MAC_LOOPBACK_FAILED | \
5928 BNX2_PHY_LOOPBACK_FAILED)
5929
5930static int
5931bnx2_test_loopback(struct bnx2 *bp)
5932{
5933 int rc = 0;
5934
5935 if (!netif_running(bp->dev))
5936 return BNX2_LOOPBACK_FAILED;
5937
5938 bnx2_reset_nic(bp, BNX2_DRV_MSG_CODE_RESET);
5939 spin_lock_bh(&bp->phy_lock);
Michael Chan9a120bc2008-05-16 22:17:45 -07005940 bnx2_init_phy(bp, 1);
Michael Chanbc5a0692006-01-23 16:13:22 -08005941 spin_unlock_bh(&bp->phy_lock);
5942 if (bnx2_run_loopback(bp, BNX2_MAC_LOOPBACK))
5943 rc |= BNX2_MAC_LOOPBACK_FAILED;
5944 if (bnx2_run_loopback(bp, BNX2_PHY_LOOPBACK))
5945 rc |= BNX2_PHY_LOOPBACK_FAILED;
5946 return rc;
5947}
5948
Michael Chanb6016b72005-05-26 13:03:09 -07005949#define NVRAM_SIZE 0x200
5950#define CRC32_RESIDUAL 0xdebb20e3
5951
5952static int
5953bnx2_test_nvram(struct bnx2 *bp)
5954{
Al Virob491edd2007-12-22 19:44:51 +00005955 __be32 buf[NVRAM_SIZE / 4];
Michael Chanb6016b72005-05-26 13:03:09 -07005956 u8 *data = (u8 *) buf;
5957 int rc = 0;
5958 u32 magic, csum;
5959
5960 if ((rc = bnx2_nvram_read(bp, 0, data, 4)) != 0)
5961 goto test_nvram_done;
5962
5963 magic = be32_to_cpu(buf[0]);
5964 if (magic != 0x669955aa) {
5965 rc = -ENODEV;
5966 goto test_nvram_done;
5967 }
5968
5969 if ((rc = bnx2_nvram_read(bp, 0x100, data, NVRAM_SIZE)) != 0)
5970 goto test_nvram_done;
5971
5972 csum = ether_crc_le(0x100, data);
5973 if (csum != CRC32_RESIDUAL) {
5974 rc = -ENODEV;
5975 goto test_nvram_done;
5976 }
5977
5978 csum = ether_crc_le(0x100, data + 0x100);
5979 if (csum != CRC32_RESIDUAL) {
5980 rc = -ENODEV;
5981 }
5982
5983test_nvram_done:
5984 return rc;
5985}
5986
5987static int
5988bnx2_test_link(struct bnx2 *bp)
5989{
5990 u32 bmsr;
5991
Michael Chan9f52b562008-10-09 12:21:46 -07005992 if (!netif_running(bp->dev))
5993 return -ENODEV;
5994
Michael Chan583c28e2008-01-21 19:51:35 -08005995 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP) {
Michael Chan489310a2007-10-10 16:16:31 -07005996 if (bp->link_up)
5997 return 0;
5998 return -ENODEV;
5999 }
Michael Chanc770a652005-08-25 15:38:39 -07006000 spin_lock_bh(&bp->phy_lock);
Michael Chan27a005b2007-05-03 13:23:41 -07006001 bnx2_enable_bmsr1(bp);
6002 bnx2_read_phy(bp, bp->mii_bmsr1, &bmsr);
6003 bnx2_read_phy(bp, bp->mii_bmsr1, &bmsr);
6004 bnx2_disable_bmsr1(bp);
Michael Chanc770a652005-08-25 15:38:39 -07006005 spin_unlock_bh(&bp->phy_lock);
Jeff Garzik6aa20a22006-09-13 13:24:59 -04006006
Michael Chanb6016b72005-05-26 13:03:09 -07006007 if (bmsr & BMSR_LSTATUS) {
6008 return 0;
6009 }
6010 return -ENODEV;
6011}
6012
6013static int
6014bnx2_test_intr(struct bnx2 *bp)
6015{
6016 int i;
Michael Chanb6016b72005-05-26 13:03:09 -07006017 u16 status_idx;
6018
6019 if (!netif_running(bp->dev))
6020 return -ENODEV;
6021
Michael Chane503e062012-12-06 10:33:08 +00006022 status_idx = BNX2_RD(bp, BNX2_PCICFG_INT_ACK_CMD) & 0xffff;
Michael Chanb6016b72005-05-26 13:03:09 -07006023
6024 /* This register is not touched during run-time. */
Michael Chane503e062012-12-06 10:33:08 +00006025 BNX2_WR(bp, BNX2_HC_COMMAND, bp->hc_cmd | BNX2_HC_COMMAND_COAL_NOW);
6026 BNX2_RD(bp, BNX2_HC_COMMAND);
Michael Chanb6016b72005-05-26 13:03:09 -07006027
6028 for (i = 0; i < 10; i++) {
Michael Chane503e062012-12-06 10:33:08 +00006029 if ((BNX2_RD(bp, BNX2_PCICFG_INT_ACK_CMD) & 0xffff) !=
Michael Chanb6016b72005-05-26 13:03:09 -07006030 status_idx) {
6031
6032 break;
6033 }
6034
6035 msleep_interruptible(10);
6036 }
6037 if (i < 10)
6038 return 0;
6039
6040 return -ENODEV;
6041}
6042
Michael Chan38ea3682008-02-23 19:48:57 -08006043/* Determining link for parallel detection. */
Michael Chanb2fadea2008-01-21 17:07:06 -08006044static int
6045bnx2_5706_serdes_has_link(struct bnx2 *bp)
6046{
6047 u32 mode_ctl, an_dbg, exp;
6048
Michael Chan38ea3682008-02-23 19:48:57 -08006049 if (bp->phy_flags & BNX2_PHY_FLAG_NO_PARALLEL)
6050 return 0;
6051
Michael Chanb2fadea2008-01-21 17:07:06 -08006052 bnx2_write_phy(bp, MII_BNX2_MISC_SHADOW, MISC_SHDW_MODE_CTL);
6053 bnx2_read_phy(bp, MII_BNX2_MISC_SHADOW, &mode_ctl);
6054
6055 if (!(mode_ctl & MISC_SHDW_MODE_CTL_SIG_DET))
6056 return 0;
6057
6058 bnx2_write_phy(bp, MII_BNX2_MISC_SHADOW, MISC_SHDW_AN_DBG);
6059 bnx2_read_phy(bp, MII_BNX2_MISC_SHADOW, &an_dbg);
6060 bnx2_read_phy(bp, MII_BNX2_MISC_SHADOW, &an_dbg);
6061
Michael Chanf3014c02008-01-29 21:33:03 -08006062 if (an_dbg & (MISC_SHDW_AN_DBG_NOSYNC | MISC_SHDW_AN_DBG_RUDI_INVALID))
Michael Chanb2fadea2008-01-21 17:07:06 -08006063 return 0;
6064
6065 bnx2_write_phy(bp, MII_BNX2_DSP_ADDRESS, MII_EXPAND_REG1);
6066 bnx2_read_phy(bp, MII_BNX2_DSP_RW_PORT, &exp);
6067 bnx2_read_phy(bp, MII_BNX2_DSP_RW_PORT, &exp);
6068
6069 if (exp & MII_EXPAND_REG1_RUDI_C) /* receiving CONFIG */
6070 return 0;
6071
6072 return 1;
6073}
6074
Michael Chanb6016b72005-05-26 13:03:09 -07006075static void
Michael Chan48b01e22006-11-19 14:08:00 -08006076bnx2_5706_serdes_timer(struct bnx2 *bp)
6077{
Michael Chanb2fadea2008-01-21 17:07:06 -08006078 int check_link = 1;
6079
Michael Chan48b01e22006-11-19 14:08:00 -08006080 spin_lock(&bp->phy_lock);
Michael Chanb2fadea2008-01-21 17:07:06 -08006081 if (bp->serdes_an_pending) {
Michael Chan48b01e22006-11-19 14:08:00 -08006082 bp->serdes_an_pending--;
Michael Chanb2fadea2008-01-21 17:07:06 -08006083 check_link = 0;
6084 } else if ((bp->link_up == 0) && (bp->autoneg & AUTONEG_SPEED)) {
Michael Chan48b01e22006-11-19 14:08:00 -08006085 u32 bmcr;
6086
Benjamin Liac392ab2008-09-18 16:40:49 -07006087 bp->current_interval = BNX2_TIMER_INTERVAL;
Michael Chan48b01e22006-11-19 14:08:00 -08006088
Michael Chanca58c3a2007-05-03 13:22:52 -07006089 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chan48b01e22006-11-19 14:08:00 -08006090
6091 if (bmcr & BMCR_ANENABLE) {
Michael Chanb2fadea2008-01-21 17:07:06 -08006092 if (bnx2_5706_serdes_has_link(bp)) {
Michael Chan48b01e22006-11-19 14:08:00 -08006093 bmcr &= ~BMCR_ANENABLE;
6094 bmcr |= BMCR_SPEED1000 | BMCR_FULLDPLX;
Michael Chanca58c3a2007-05-03 13:22:52 -07006095 bnx2_write_phy(bp, bp->mii_bmcr, bmcr);
Michael Chan583c28e2008-01-21 19:51:35 -08006096 bp->phy_flags |= BNX2_PHY_FLAG_PARALLEL_DETECT;
Michael Chan48b01e22006-11-19 14:08:00 -08006097 }
6098 }
6099 }
6100 else if ((bp->link_up) && (bp->autoneg & AUTONEG_SPEED) &&
Michael Chan583c28e2008-01-21 19:51:35 -08006101 (bp->phy_flags & BNX2_PHY_FLAG_PARALLEL_DETECT)) {
Michael Chan48b01e22006-11-19 14:08:00 -08006102 u32 phy2;
6103
6104 bnx2_write_phy(bp, 0x17, 0x0f01);
6105 bnx2_read_phy(bp, 0x15, &phy2);
6106 if (phy2 & 0x20) {
6107 u32 bmcr;
6108
Michael Chanca58c3a2007-05-03 13:22:52 -07006109 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chan48b01e22006-11-19 14:08:00 -08006110 bmcr |= BMCR_ANENABLE;
Michael Chanca58c3a2007-05-03 13:22:52 -07006111 bnx2_write_phy(bp, bp->mii_bmcr, bmcr);
Michael Chan48b01e22006-11-19 14:08:00 -08006112
Michael Chan583c28e2008-01-21 19:51:35 -08006113 bp->phy_flags &= ~BNX2_PHY_FLAG_PARALLEL_DETECT;
Michael Chan48b01e22006-11-19 14:08:00 -08006114 }
6115 } else
Benjamin Liac392ab2008-09-18 16:40:49 -07006116 bp->current_interval = BNX2_TIMER_INTERVAL;
Michael Chan48b01e22006-11-19 14:08:00 -08006117
Michael Chana2724e22008-02-23 19:47:44 -08006118 if (check_link) {
Michael Chanb2fadea2008-01-21 17:07:06 -08006119 u32 val;
6120
6121 bnx2_write_phy(bp, MII_BNX2_MISC_SHADOW, MISC_SHDW_AN_DBG);
6122 bnx2_read_phy(bp, MII_BNX2_MISC_SHADOW, &val);
6123 bnx2_read_phy(bp, MII_BNX2_MISC_SHADOW, &val);
6124
Michael Chana2724e22008-02-23 19:47:44 -08006125 if (bp->link_up && (val & MISC_SHDW_AN_DBG_NOSYNC)) {
6126 if (!(bp->phy_flags & BNX2_PHY_FLAG_FORCED_DOWN)) {
6127 bnx2_5706s_force_link_dn(bp, 1);
6128 bp->phy_flags |= BNX2_PHY_FLAG_FORCED_DOWN;
6129 } else
6130 bnx2_set_link(bp);
6131 } else if (!bp->link_up && !(val & MISC_SHDW_AN_DBG_NOSYNC))
6132 bnx2_set_link(bp);
Michael Chanb2fadea2008-01-21 17:07:06 -08006133 }
Michael Chan48b01e22006-11-19 14:08:00 -08006134 spin_unlock(&bp->phy_lock);
6135}
6136
6137static void
Michael Chanf8dd0642006-11-19 14:08:29 -08006138bnx2_5708_serdes_timer(struct bnx2 *bp)
6139{
Michael Chan583c28e2008-01-21 19:51:35 -08006140 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
Michael Chan0d8a6572007-07-07 22:49:43 -07006141 return;
6142
Michael Chan583c28e2008-01-21 19:51:35 -08006143 if ((bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE) == 0) {
Michael Chanf8dd0642006-11-19 14:08:29 -08006144 bp->serdes_an_pending = 0;
6145 return;
6146 }
6147
6148 spin_lock(&bp->phy_lock);
6149 if (bp->serdes_an_pending)
6150 bp->serdes_an_pending--;
6151 else if ((bp->link_up == 0) && (bp->autoneg & AUTONEG_SPEED)) {
6152 u32 bmcr;
6153
Michael Chanca58c3a2007-05-03 13:22:52 -07006154 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chanf8dd0642006-11-19 14:08:29 -08006155 if (bmcr & BMCR_ANENABLE) {
Michael Chan605a9e22007-05-03 13:23:13 -07006156 bnx2_enable_forced_2g5(bp);
Michael Chan40105c02008-11-12 16:02:45 -08006157 bp->current_interval = BNX2_SERDES_FORCED_TIMEOUT;
Michael Chanf8dd0642006-11-19 14:08:29 -08006158 } else {
Michael Chan605a9e22007-05-03 13:23:13 -07006159 bnx2_disable_forced_2g5(bp);
Michael Chanf8dd0642006-11-19 14:08:29 -08006160 bp->serdes_an_pending = 2;
Benjamin Liac392ab2008-09-18 16:40:49 -07006161 bp->current_interval = BNX2_TIMER_INTERVAL;
Michael Chanf8dd0642006-11-19 14:08:29 -08006162 }
6163
6164 } else
Benjamin Liac392ab2008-09-18 16:40:49 -07006165 bp->current_interval = BNX2_TIMER_INTERVAL;
Michael Chanf8dd0642006-11-19 14:08:29 -08006166
6167 spin_unlock(&bp->phy_lock);
6168}
6169
6170static void
Michael Chanb6016b72005-05-26 13:03:09 -07006171bnx2_timer(unsigned long data)
6172{
6173 struct bnx2 *bp = (struct bnx2 *) data;
Michael Chanb6016b72005-05-26 13:03:09 -07006174
Michael Chancd339a02005-08-25 15:35:24 -07006175 if (!netif_running(bp->dev))
6176 return;
6177
Michael Chanb6016b72005-05-26 13:03:09 -07006178 if (atomic_read(&bp->intr_sem) != 0)
6179 goto bnx2_restart_timer;
6180
Michael Chanefba0182008-12-03 00:36:15 -08006181 if ((bp->flags & (BNX2_FLAG_USING_MSI | BNX2_FLAG_ONE_SHOT_MSI)) ==
6182 BNX2_FLAG_USING_MSI)
6183 bnx2_chk_missed_msi(bp);
6184
Michael Chandf149d72007-07-07 22:51:36 -07006185 bnx2_send_heart_beat(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07006186
Michael Chan2726d6e2008-01-29 21:35:05 -08006187 bp->stats_blk->stat_FwRxDrop =
6188 bnx2_reg_rd_ind(bp, BNX2_FW_RX_DROP_COUNT);
Michael Chancea94db2006-06-12 22:16:13 -07006189
Michael Chan02537b062007-06-04 21:24:07 -07006190 /* workaround occasional corrupted counters */
Michael Chan61d9e3f2009-08-21 16:20:46 +00006191 if ((bp->flags & BNX2_FLAG_BROKEN_STATS) && bp->stats_ticks)
Michael Chane503e062012-12-06 10:33:08 +00006192 BNX2_WR(bp, BNX2_HC_COMMAND, bp->hc_cmd |
6193 BNX2_HC_COMMAND_STATS_NOW);
Michael Chan02537b062007-06-04 21:24:07 -07006194
Michael Chan583c28e2008-01-21 19:51:35 -08006195 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Michael Chan4ce45e02012-12-06 10:33:10 +00006196 if (BNX2_CHIP(bp) == BNX2_CHIP_5706)
Michael Chanf8dd0642006-11-19 14:08:29 -08006197 bnx2_5706_serdes_timer(bp);
Michael Chan27a005b2007-05-03 13:23:41 -07006198 else
Michael Chanf8dd0642006-11-19 14:08:29 -08006199 bnx2_5708_serdes_timer(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07006200 }
6201
6202bnx2_restart_timer:
Michael Chancd339a02005-08-25 15:35:24 -07006203 mod_timer(&bp->timer, jiffies + bp->current_interval);
Michael Chanb6016b72005-05-26 13:03:09 -07006204}
6205
Michael Chan8e6a72c2007-05-03 13:24:48 -07006206static int
6207bnx2_request_irq(struct bnx2 *bp)
6208{
Michael Chan6d866ff2007-12-20 19:56:09 -08006209 unsigned long flags;
Michael Chanb4b36042007-12-20 19:59:30 -08006210 struct bnx2_irq *irq;
6211 int rc = 0, i;
Michael Chan8e6a72c2007-05-03 13:24:48 -07006212
David S. Millerf86e82f2008-01-21 17:15:40 -08006213 if (bp->flags & BNX2_FLAG_USING_MSI_OR_MSIX)
Michael Chan6d866ff2007-12-20 19:56:09 -08006214 flags = 0;
6215 else
6216 flags = IRQF_SHARED;
Michael Chanb4b36042007-12-20 19:59:30 -08006217
6218 for (i = 0; i < bp->irq_nvecs; i++) {
6219 irq = &bp->irq_tbl[i];
Michael Chanc76c0472007-12-20 20:01:19 -08006220 rc = request_irq(irq->vector, irq->handler, flags, irq->name,
Michael Chanf0ea2e62008-06-19 16:41:57 -07006221 &bp->bnx2_napi[i]);
Michael Chanb4b36042007-12-20 19:59:30 -08006222 if (rc)
6223 break;
6224 irq->requested = 1;
6225 }
Michael Chan8e6a72c2007-05-03 13:24:48 -07006226 return rc;
6227}
6228
6229static void
Michael Chana29ba9d2010-12-31 11:03:14 -08006230__bnx2_free_irq(struct bnx2 *bp)
Michael Chan8e6a72c2007-05-03 13:24:48 -07006231{
Michael Chanb4b36042007-12-20 19:59:30 -08006232 struct bnx2_irq *irq;
6233 int i;
Michael Chan8e6a72c2007-05-03 13:24:48 -07006234
Michael Chanb4b36042007-12-20 19:59:30 -08006235 for (i = 0; i < bp->irq_nvecs; i++) {
6236 irq = &bp->irq_tbl[i];
6237 if (irq->requested)
Michael Chanf0ea2e62008-06-19 16:41:57 -07006238 free_irq(irq->vector, &bp->bnx2_napi[i]);
Michael Chanb4b36042007-12-20 19:59:30 -08006239 irq->requested = 0;
Michael Chan6d866ff2007-12-20 19:56:09 -08006240 }
Michael Chana29ba9d2010-12-31 11:03:14 -08006241}
6242
6243static void
6244bnx2_free_irq(struct bnx2 *bp)
6245{
6246
6247 __bnx2_free_irq(bp);
David S. Millerf86e82f2008-01-21 17:15:40 -08006248 if (bp->flags & BNX2_FLAG_USING_MSI)
Michael Chanb4b36042007-12-20 19:59:30 -08006249 pci_disable_msi(bp->pdev);
David S. Millerf86e82f2008-01-21 17:15:40 -08006250 else if (bp->flags & BNX2_FLAG_USING_MSIX)
Michael Chanb4b36042007-12-20 19:59:30 -08006251 pci_disable_msix(bp->pdev);
6252
David S. Millerf86e82f2008-01-21 17:15:40 -08006253 bp->flags &= ~(BNX2_FLAG_USING_MSI_OR_MSIX | BNX2_FLAG_ONE_SHOT_MSI);
Michael Chanb4b36042007-12-20 19:59:30 -08006254}
6255
6256static void
Michael Chan5e9ad9e2008-06-19 16:43:17 -07006257bnx2_enable_msix(struct bnx2 *bp, int msix_vecs)
Michael Chanb4b36042007-12-20 19:59:30 -08006258{
Alexander Gordeevf2a2dfe2014-02-18 11:07:53 +01006259 int i, total_vecs;
Michael Chan57851d82007-12-20 20:01:44 -08006260 struct msix_entry msix_ent[BNX2_MAX_MSIX_VEC];
Michael Chan4e1d0de2008-12-16 20:27:45 -08006261 struct net_device *dev = bp->dev;
6262 const int len = sizeof(bp->irq_tbl[0].name);
Michael Chan57851d82007-12-20 20:01:44 -08006263
Michael Chanb4b36042007-12-20 19:59:30 -08006264 bnx2_setup_msix_tbl(bp);
Michael Chane503e062012-12-06 10:33:08 +00006265 BNX2_WR(bp, BNX2_PCI_MSIX_CONTROL, BNX2_MAX_MSIX_HW_VEC - 1);
6266 BNX2_WR(bp, BNX2_PCI_MSIX_TBL_OFF_BIR, BNX2_PCI_GRC_WINDOW2_BASE);
6267 BNX2_WR(bp, BNX2_PCI_MSIX_PBA_OFF_BIT, BNX2_PCI_GRC_WINDOW3_BASE);
Michael Chan57851d82007-12-20 20:01:44 -08006268
Benjamin Lie2eb8e32010-01-08 00:51:21 -08006269 /* Need to flush the previous three writes to ensure MSI-X
6270 * is setup properly */
Michael Chane503e062012-12-06 10:33:08 +00006271 BNX2_RD(bp, BNX2_PCI_MSIX_CONTROL);
Benjamin Lie2eb8e32010-01-08 00:51:21 -08006272
Michael Chan57851d82007-12-20 20:01:44 -08006273 for (i = 0; i < BNX2_MAX_MSIX_VEC; i++) {
6274 msix_ent[i].entry = i;
6275 msix_ent[i].vector = 0;
6276 }
6277
Michael Chan379b39a2010-07-19 14:15:03 +00006278 total_vecs = msix_vecs;
6279#ifdef BCM_CNIC
6280 total_vecs++;
6281#endif
Alexander Gordeevf2a2dfe2014-02-18 11:07:53 +01006282 total_vecs = pci_enable_msix_range(bp->pdev, msix_ent,
6283 BNX2_MIN_MSIX_VEC, total_vecs);
6284 if (total_vecs < 0)
Michael Chan57851d82007-12-20 20:01:44 -08006285 return;
6286
Michael Chan379b39a2010-07-19 14:15:03 +00006287 msix_vecs = total_vecs;
6288#ifdef BCM_CNIC
6289 msix_vecs--;
6290#endif
Michael Chan5e9ad9e2008-06-19 16:43:17 -07006291 bp->irq_nvecs = msix_vecs;
David S. Millerf86e82f2008-01-21 17:15:40 -08006292 bp->flags |= BNX2_FLAG_USING_MSIX | BNX2_FLAG_ONE_SHOT_MSI;
Michael Chan379b39a2010-07-19 14:15:03 +00006293 for (i = 0; i < total_vecs; i++) {
Michael Chan57851d82007-12-20 20:01:44 -08006294 bp->irq_tbl[i].vector = msix_ent[i].vector;
Michael Chan69010312009-03-18 18:11:51 -07006295 snprintf(bp->irq_tbl[i].name, len, "%s-%d", dev->name, i);
6296 bp->irq_tbl[i].handler = bnx2_msi_1shot;
6297 }
Michael Chan6d866ff2007-12-20 19:56:09 -08006298}
6299
Ben Hutchings657d92f2010-09-27 08:25:16 +00006300static int
Michael Chan6d866ff2007-12-20 19:56:09 -08006301bnx2_setup_int_mode(struct bnx2 *bp, int dis_msi)
6302{
Yuval Mintz0a742122012-07-01 03:18:58 +00006303 int cpus = netif_get_num_default_rss_queues();
Michael Chanb0332812012-02-05 15:24:38 +00006304 int msix_vecs;
6305
6306 if (!bp->num_req_rx_rings)
6307 msix_vecs = max(cpus + 1, bp->num_req_tx_rings);
6308 else if (!bp->num_req_tx_rings)
6309 msix_vecs = max(cpus, bp->num_req_rx_rings);
6310 else
6311 msix_vecs = max(bp->num_req_rx_rings, bp->num_req_tx_rings);
6312
6313 msix_vecs = min(msix_vecs, RX_MAX_RINGS);
Michael Chan5e9ad9e2008-06-19 16:43:17 -07006314
Michael Chan6d866ff2007-12-20 19:56:09 -08006315 bp->irq_tbl[0].handler = bnx2_interrupt;
6316 strcpy(bp->irq_tbl[0].name, bp->dev->name);
Michael Chanb4b36042007-12-20 19:59:30 -08006317 bp->irq_nvecs = 1;
6318 bp->irq_tbl[0].vector = bp->pdev->irq;
Michael Chan6d866ff2007-12-20 19:56:09 -08006319
Michael Chan3d5f3a72010-07-03 20:42:15 +00006320 if ((bp->flags & BNX2_FLAG_MSIX_CAP) && !dis_msi)
Michael Chan5e9ad9e2008-06-19 16:43:17 -07006321 bnx2_enable_msix(bp, msix_vecs);
Michael Chanb4b36042007-12-20 19:59:30 -08006322
David S. Millerf86e82f2008-01-21 17:15:40 -08006323 if ((bp->flags & BNX2_FLAG_MSI_CAP) && !dis_msi &&
6324 !(bp->flags & BNX2_FLAG_USING_MSIX)) {
Michael Chan6d866ff2007-12-20 19:56:09 -08006325 if (pci_enable_msi(bp->pdev) == 0) {
David S. Millerf86e82f2008-01-21 17:15:40 -08006326 bp->flags |= BNX2_FLAG_USING_MSI;
Michael Chan4ce45e02012-12-06 10:33:10 +00006327 if (BNX2_CHIP(bp) == BNX2_CHIP_5709) {
David S. Millerf86e82f2008-01-21 17:15:40 -08006328 bp->flags |= BNX2_FLAG_ONE_SHOT_MSI;
Michael Chan6d866ff2007-12-20 19:56:09 -08006329 bp->irq_tbl[0].handler = bnx2_msi_1shot;
6330 } else
6331 bp->irq_tbl[0].handler = bnx2_msi;
Michael Chanb4b36042007-12-20 19:59:30 -08006332
6333 bp->irq_tbl[0].vector = bp->pdev->irq;
Michael Chan6d866ff2007-12-20 19:56:09 -08006334 }
6335 }
Benjamin Li706bf242008-07-18 17:55:11 -07006336
Michael Chanb0332812012-02-05 15:24:38 +00006337 if (!bp->num_req_tx_rings)
6338 bp->num_tx_rings = rounddown_pow_of_two(bp->irq_nvecs);
6339 else
6340 bp->num_tx_rings = min(bp->irq_nvecs, bp->num_req_tx_rings);
6341
6342 if (!bp->num_req_rx_rings)
6343 bp->num_rx_rings = bp->irq_nvecs;
6344 else
6345 bp->num_rx_rings = min(bp->irq_nvecs, bp->num_req_rx_rings);
6346
Ben Hutchings657d92f2010-09-27 08:25:16 +00006347 netif_set_real_num_tx_queues(bp->dev, bp->num_tx_rings);
Benjamin Li706bf242008-07-18 17:55:11 -07006348
Ben Hutchings657d92f2010-09-27 08:25:16 +00006349 return netif_set_real_num_rx_queues(bp->dev, bp->num_rx_rings);
Michael Chan8e6a72c2007-05-03 13:24:48 -07006350}
6351
Michael Chanb6016b72005-05-26 13:03:09 -07006352/* Called with rtnl_lock */
6353static int
6354bnx2_open(struct net_device *dev)
6355{
Michael Chan972ec0d2006-01-23 16:12:43 -08006356 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006357 int rc;
6358
françois romieu7880b722011-09-30 00:36:52 +00006359 rc = bnx2_request_firmware(bp);
6360 if (rc < 0)
6361 goto out;
6362
Michael Chan1b2f9222007-05-03 13:20:19 -07006363 netif_carrier_off(dev);
6364
Michael Chanb6016b72005-05-26 13:03:09 -07006365 bnx2_disable_int(bp);
6366
Ben Hutchings657d92f2010-09-27 08:25:16 +00006367 rc = bnx2_setup_int_mode(bp, disable_msi);
6368 if (rc)
6369 goto open_err;
Benjamin Li4327ba42010-03-23 13:13:11 +00006370 bnx2_init_napi(bp);
Michael Chan35efa7c2007-12-20 19:56:37 -08006371 bnx2_napi_enable(bp);
Michael Chan35e90102008-06-19 16:37:42 -07006372 rc = bnx2_alloc_mem(bp);
Michael Chan2739a8b2008-06-19 16:44:10 -07006373 if (rc)
6374 goto open_err;
Michael Chan35e90102008-06-19 16:37:42 -07006375
Michael Chan8e6a72c2007-05-03 13:24:48 -07006376 rc = bnx2_request_irq(bp);
Michael Chan2739a8b2008-06-19 16:44:10 -07006377 if (rc)
6378 goto open_err;
Michael Chanb6016b72005-05-26 13:03:09 -07006379
Michael Chan9a120bc2008-05-16 22:17:45 -07006380 rc = bnx2_init_nic(bp, 1);
Michael Chan2739a8b2008-06-19 16:44:10 -07006381 if (rc)
6382 goto open_err;
Jeff Garzik6aa20a22006-09-13 13:24:59 -04006383
Michael Chancd339a02005-08-25 15:35:24 -07006384 mod_timer(&bp->timer, jiffies + bp->current_interval);
Michael Chanb6016b72005-05-26 13:03:09 -07006385
6386 atomic_set(&bp->intr_sem, 0);
6387
Michael Chan354fcd72010-01-17 07:30:44 +00006388 memset(bp->temp_stats_blk, 0, sizeof(struct statistics_block));
6389
Michael Chanb6016b72005-05-26 13:03:09 -07006390 bnx2_enable_int(bp);
6391
David S. Millerf86e82f2008-01-21 17:15:40 -08006392 if (bp->flags & BNX2_FLAG_USING_MSI) {
Michael Chanb6016b72005-05-26 13:03:09 -07006393 /* Test MSI to make sure it is working
6394 * If MSI test fails, go back to INTx mode
6395 */
6396 if (bnx2_test_intr(bp) != 0) {
Joe Perches3a9c6a42010-02-17 15:01:51 +00006397 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");
Michael Chanb6016b72005-05-26 13:03:09 -07006398
6399 bnx2_disable_int(bp);
Michael Chan8e6a72c2007-05-03 13:24:48 -07006400 bnx2_free_irq(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07006401
Michael Chan6d866ff2007-12-20 19:56:09 -08006402 bnx2_setup_int_mode(bp, 1);
6403
Michael Chan9a120bc2008-05-16 22:17:45 -07006404 rc = bnx2_init_nic(bp, 0);
Michael Chanb6016b72005-05-26 13:03:09 -07006405
Michael Chan8e6a72c2007-05-03 13:24:48 -07006406 if (!rc)
6407 rc = bnx2_request_irq(bp);
6408
Michael Chanb6016b72005-05-26 13:03:09 -07006409 if (rc) {
Michael Chanb6016b72005-05-26 13:03:09 -07006410 del_timer_sync(&bp->timer);
Michael Chan2739a8b2008-06-19 16:44:10 -07006411 goto open_err;
Michael Chanb6016b72005-05-26 13:03:09 -07006412 }
6413 bnx2_enable_int(bp);
6414 }
6415 }
David S. Millerf86e82f2008-01-21 17:15:40 -08006416 if (bp->flags & BNX2_FLAG_USING_MSI)
Joe Perches3a9c6a42010-02-17 15:01:51 +00006417 netdev_info(dev, "using MSI\n");
David S. Millerf86e82f2008-01-21 17:15:40 -08006418 else if (bp->flags & BNX2_FLAG_USING_MSIX)
Joe Perches3a9c6a42010-02-17 15:01:51 +00006419 netdev_info(dev, "using MSIX\n");
Michael Chanb6016b72005-05-26 13:03:09 -07006420
Benjamin Li706bf242008-07-18 17:55:11 -07006421 netif_tx_start_all_queues(dev);
françois romieu7880b722011-09-30 00:36:52 +00006422out:
6423 return rc;
Michael Chan2739a8b2008-06-19 16:44:10 -07006424
6425open_err:
6426 bnx2_napi_disable(bp);
6427 bnx2_free_skbs(bp);
6428 bnx2_free_irq(bp);
6429 bnx2_free_mem(bp);
Michael Chanf048fa92010-06-01 15:05:36 +00006430 bnx2_del_napi(bp);
françois romieu7880b722011-09-30 00:36:52 +00006431 bnx2_release_firmware(bp);
6432 goto out;
Michael Chanb6016b72005-05-26 13:03:09 -07006433}
6434
6435static void
David Howellsc4028952006-11-22 14:57:56 +00006436bnx2_reset_task(struct work_struct *work)
Michael Chanb6016b72005-05-26 13:03:09 -07006437{
David Howellsc4028952006-11-22 14:57:56 +00006438 struct bnx2 *bp = container_of(work, struct bnx2, reset_task);
Michael Chancd634012011-07-15 06:53:58 +00006439 int rc;
Michael Chanefdfad32012-07-16 14:25:56 +00006440 u16 pcicmd;
Michael Chanb6016b72005-05-26 13:03:09 -07006441
Michael Chan51bf6bb2009-12-03 09:46:31 +00006442 rtnl_lock();
6443 if (!netif_running(bp->dev)) {
6444 rtnl_unlock();
Michael Chanafdc08b2005-08-25 15:34:29 -07006445 return;
Michael Chan51bf6bb2009-12-03 09:46:31 +00006446 }
Michael Chanafdc08b2005-08-25 15:34:29 -07006447
Michael Chan212f9932010-04-27 11:28:10 +00006448 bnx2_netif_stop(bp, true);
Michael Chanb6016b72005-05-26 13:03:09 -07006449
Michael Chanefdfad32012-07-16 14:25:56 +00006450 pci_read_config_word(bp->pdev, PCI_COMMAND, &pcicmd);
6451 if (!(pcicmd & PCI_COMMAND_MEMORY)) {
6452 /* in case PCI block has reset */
6453 pci_restore_state(bp->pdev);
6454 pci_save_state(bp->pdev);
6455 }
Michael Chancd634012011-07-15 06:53:58 +00006456 rc = bnx2_init_nic(bp, 1);
6457 if (rc) {
6458 netdev_err(bp->dev, "failed to reset NIC, closing\n");
6459 bnx2_napi_enable(bp);
6460 dev_close(bp->dev);
6461 rtnl_unlock();
6462 return;
6463 }
Michael Chanb6016b72005-05-26 13:03:09 -07006464
6465 atomic_set(&bp->intr_sem, 1);
Michael Chan212f9932010-04-27 11:28:10 +00006466 bnx2_netif_start(bp, true);
Michael Chan51bf6bb2009-12-03 09:46:31 +00006467 rtnl_unlock();
Michael Chanb6016b72005-05-26 13:03:09 -07006468}
6469
Michael Chan555069d2012-06-16 15:45:41 +00006470#define BNX2_FTQ_ENTRY(ftq) { __stringify(ftq##FTQ_CTL), BNX2_##ftq##FTQ_CTL }
6471
6472static void
6473bnx2_dump_ftq(struct bnx2 *bp)
6474{
6475 int i;
6476 u32 reg, bdidx, cid, valid;
6477 struct net_device *dev = bp->dev;
6478 static const struct ftq_reg {
6479 char *name;
6480 u32 off;
6481 } ftq_arr[] = {
6482 BNX2_FTQ_ENTRY(RV2P_P),
6483 BNX2_FTQ_ENTRY(RV2P_T),
6484 BNX2_FTQ_ENTRY(RV2P_M),
6485 BNX2_FTQ_ENTRY(TBDR_),
6486 BNX2_FTQ_ENTRY(TDMA_),
6487 BNX2_FTQ_ENTRY(TXP_),
6488 BNX2_FTQ_ENTRY(TXP_),
6489 BNX2_FTQ_ENTRY(TPAT_),
6490 BNX2_FTQ_ENTRY(RXP_C),
6491 BNX2_FTQ_ENTRY(RXP_),
6492 BNX2_FTQ_ENTRY(COM_COMXQ_),
6493 BNX2_FTQ_ENTRY(COM_COMTQ_),
6494 BNX2_FTQ_ENTRY(COM_COMQ_),
6495 BNX2_FTQ_ENTRY(CP_CPQ_),
6496 };
6497
6498 netdev_err(dev, "<--- start FTQ dump --->\n");
6499 for (i = 0; i < ARRAY_SIZE(ftq_arr); i++)
6500 netdev_err(dev, "%s %08x\n", ftq_arr[i].name,
6501 bnx2_reg_rd_ind(bp, ftq_arr[i].off));
6502
6503 netdev_err(dev, "CPU states:\n");
6504 for (reg = BNX2_TXP_CPU_MODE; reg <= BNX2_CP_CPU_MODE; reg += 0x40000)
6505 netdev_err(dev, "%06x mode %x state %x evt_mask %x pc %x pc %x instr %x\n",
6506 reg, bnx2_reg_rd_ind(bp, reg),
6507 bnx2_reg_rd_ind(bp, reg + 4),
6508 bnx2_reg_rd_ind(bp, reg + 8),
6509 bnx2_reg_rd_ind(bp, reg + 0x1c),
6510 bnx2_reg_rd_ind(bp, reg + 0x1c),
6511 bnx2_reg_rd_ind(bp, reg + 0x20));
6512
6513 netdev_err(dev, "<--- end FTQ dump --->\n");
6514 netdev_err(dev, "<--- start TBDC dump --->\n");
6515 netdev_err(dev, "TBDC free cnt: %ld\n",
Michael Chane503e062012-12-06 10:33:08 +00006516 BNX2_RD(bp, BNX2_TBDC_STATUS) & BNX2_TBDC_STATUS_FREE_CNT);
Michael Chan555069d2012-06-16 15:45:41 +00006517 netdev_err(dev, "LINE CID BIDX CMD VALIDS\n");
6518 for (i = 0; i < 0x20; i++) {
6519 int j = 0;
6520
Michael Chane503e062012-12-06 10:33:08 +00006521 BNX2_WR(bp, BNX2_TBDC_BD_ADDR, i);
6522 BNX2_WR(bp, BNX2_TBDC_CAM_OPCODE,
6523 BNX2_TBDC_CAM_OPCODE_OPCODE_CAM_READ);
6524 BNX2_WR(bp, BNX2_TBDC_COMMAND, BNX2_TBDC_COMMAND_CMD_REG_ARB);
6525 while ((BNX2_RD(bp, BNX2_TBDC_COMMAND) &
Michael Chan555069d2012-06-16 15:45:41 +00006526 BNX2_TBDC_COMMAND_CMD_REG_ARB) && j < 100)
6527 j++;
6528
Michael Chane503e062012-12-06 10:33:08 +00006529 cid = BNX2_RD(bp, BNX2_TBDC_CID);
6530 bdidx = BNX2_RD(bp, BNX2_TBDC_BIDX);
6531 valid = BNX2_RD(bp, BNX2_TBDC_CAM_OPCODE);
Michael Chan555069d2012-06-16 15:45:41 +00006532 netdev_err(dev, "%02x %06x %04lx %02x [%x]\n",
6533 i, cid, bdidx & BNX2_TBDC_BDIDX_BDIDX,
6534 bdidx >> 24, (valid >> 8) & 0x0ff);
6535 }
6536 netdev_err(dev, "<--- end TBDC dump --->\n");
6537}
6538
Michael Chanb6016b72005-05-26 13:03:09 -07006539static void
Michael Chan20175c52009-12-03 09:46:32 +00006540bnx2_dump_state(struct bnx2 *bp)
6541{
6542 struct net_device *dev = bp->dev;
Jeffrey Huangecdbf6e2011-07-13 17:24:21 +00006543 u32 val1, val2;
Michael Chan20175c52009-12-03 09:46:32 +00006544
Michael Chan5804a8f2010-07-03 20:42:17 +00006545 pci_read_config_dword(bp->pdev, PCI_COMMAND, &val1);
6546 netdev_err(dev, "DEBUG: intr_sem[%x] PCI_CMD[%08x]\n",
6547 atomic_read(&bp->intr_sem), val1);
6548 pci_read_config_dword(bp->pdev, bp->pm_cap + PCI_PM_CTRL, &val1);
6549 pci_read_config_dword(bp->pdev, BNX2_PCICFG_MISC_CONFIG, &val2);
6550 netdev_err(dev, "DEBUG: PCI_PM[%08x] PCI_MISC_CFG[%08x]\n", val1, val2);
Eddie Waib98eba52010-05-17 17:32:56 -07006551 netdev_err(dev, "DEBUG: EMAC_TX_STATUS[%08x] EMAC_RX_STATUS[%08x]\n",
Michael Chane503e062012-12-06 10:33:08 +00006552 BNX2_RD(bp, BNX2_EMAC_TX_STATUS),
6553 BNX2_RD(bp, BNX2_EMAC_RX_STATUS));
Eddie Waib98eba52010-05-17 17:32:56 -07006554 netdev_err(dev, "DEBUG: RPM_MGMT_PKT_CTRL[%08x]\n",
Michael Chane503e062012-12-06 10:33:08 +00006555 BNX2_RD(bp, BNX2_RPM_MGMT_PKT_CTRL));
Joe Perches3a9c6a42010-02-17 15:01:51 +00006556 netdev_err(dev, "DEBUG: HC_STATS_INTERRUPT_STATUS[%08x]\n",
Michael Chane503e062012-12-06 10:33:08 +00006557 BNX2_RD(bp, BNX2_HC_STATS_INTERRUPT_STATUS));
Michael Chan20175c52009-12-03 09:46:32 +00006558 if (bp->flags & BNX2_FLAG_USING_MSIX)
Joe Perches3a9c6a42010-02-17 15:01:51 +00006559 netdev_err(dev, "DEBUG: PBA[%08x]\n",
Michael Chane503e062012-12-06 10:33:08 +00006560 BNX2_RD(bp, BNX2_PCI_GRC_WINDOW3_BASE));
Michael Chan20175c52009-12-03 09:46:32 +00006561}
6562
6563static void
Michael Chanb6016b72005-05-26 13:03:09 -07006564bnx2_tx_timeout(struct net_device *dev)
6565{
Michael Chan972ec0d2006-01-23 16:12:43 -08006566 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006567
Michael Chan555069d2012-06-16 15:45:41 +00006568 bnx2_dump_ftq(bp);
Michael Chan20175c52009-12-03 09:46:32 +00006569 bnx2_dump_state(bp);
Jeffrey Huangecdbf6e2011-07-13 17:24:21 +00006570 bnx2_dump_mcp_state(bp);
Michael Chan20175c52009-12-03 09:46:32 +00006571
Michael Chanb6016b72005-05-26 13:03:09 -07006572 /* This allows the netif to be shutdown gracefully before resetting */
6573 schedule_work(&bp->reset_task);
6574}
6575
Herbert Xu932ff272006-06-09 12:20:56 -07006576/* Called with netif_tx_lock.
Michael Chan2f8af122006-08-15 01:39:10 -07006577 * bnx2_tx_int() runs without netif_tx_lock unless it needs to call
6578 * netif_wake_queue().
Michael Chanb6016b72005-05-26 13:03:09 -07006579 */
Stephen Hemminger613573252009-08-31 19:50:58 +00006580static netdev_tx_t
Michael Chanb6016b72005-05-26 13:03:09 -07006581bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev)
6582{
Michael Chan972ec0d2006-01-23 16:12:43 -08006583 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006584 dma_addr_t mapping;
Michael Chan2bc40782012-12-06 10:33:09 +00006585 struct bnx2_tx_bd *txbd;
6586 struct bnx2_sw_tx_bd *tx_buf;
Michael Chanb6016b72005-05-26 13:03:09 -07006587 u32 len, vlan_tag_flags, last_frag, mss;
6588 u16 prod, ring_prod;
6589 int i;
Benjamin Li706bf242008-07-18 17:55:11 -07006590 struct bnx2_napi *bnapi;
6591 struct bnx2_tx_ring_info *txr;
6592 struct netdev_queue *txq;
6593
6594 /* Determine which tx ring we will be placed on */
6595 i = skb_get_queue_mapping(skb);
6596 bnapi = &bp->bnx2_napi[i];
6597 txr = &bnapi->tx_ring;
6598 txq = netdev_get_tx_queue(dev, i);
Michael Chanb6016b72005-05-26 13:03:09 -07006599
Michael Chan35e90102008-06-19 16:37:42 -07006600 if (unlikely(bnx2_tx_avail(bp, txr) <
Michael Chana550c992007-12-20 19:56:59 -08006601 (skb_shinfo(skb)->nr_frags + 1))) {
Benjamin Li706bf242008-07-18 17:55:11 -07006602 netif_tx_stop_queue(txq);
Joe Perches3a9c6a42010-02-17 15:01:51 +00006603 netdev_err(dev, "BUG! Tx ring full when queue awake!\n");
Michael Chanb6016b72005-05-26 13:03:09 -07006604
6605 return NETDEV_TX_BUSY;
6606 }
6607 len = skb_headlen(skb);
Michael Chan35e90102008-06-19 16:37:42 -07006608 prod = txr->tx_prod;
Michael Chan2bc40782012-12-06 10:33:09 +00006609 ring_prod = BNX2_TX_RING_IDX(prod);
Michael Chanb6016b72005-05-26 13:03:09 -07006610
6611 vlan_tag_flags = 0;
Patrick McHardy84fa7932006-08-29 16:44:56 -07006612 if (skb->ip_summed == CHECKSUM_PARTIAL) {
Michael Chanb6016b72005-05-26 13:03:09 -07006613 vlan_tag_flags |= TX_BD_FLAGS_TCP_UDP_CKSUM;
6614 }
6615
Jiri Pirkodf8a39d2015-01-13 17:13:44 +01006616 if (skb_vlan_tag_present(skb)) {
Michael Chanb6016b72005-05-26 13:03:09 -07006617 vlan_tag_flags |=
Jiri Pirkodf8a39d2015-01-13 17:13:44 +01006618 (TX_BD_FLAGS_VLAN_TAG | (skb_vlan_tag_get(skb) << 16));
Michael Chanb6016b72005-05-26 13:03:09 -07006619 }
Jesse Gross7d0fd212010-10-20 13:56:09 +00006620
Michael Chanfde82052007-05-03 17:23:35 -07006621 if ((mss = skb_shinfo(skb)->gso_size)) {
Michael Chana1efb4b2008-10-09 12:24:39 -07006622 u32 tcp_opt_len;
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -07006623 struct iphdr *iph;
Michael Chanb6016b72005-05-26 13:03:09 -07006624
Michael Chanb6016b72005-05-26 13:03:09 -07006625 vlan_tag_flags |= TX_BD_FLAGS_SW_LSO;
6626
Michael Chan4666f872007-05-03 13:22:28 -07006627 tcp_opt_len = tcp_optlen(skb);
Arnaldo Carvalho de Meloab6a5bb2007-03-18 17:43:48 -07006628
Michael Chan4666f872007-05-03 13:22:28 -07006629 if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6) {
6630 u32 tcp_off = skb_transport_offset(skb) -
6631 sizeof(struct ipv6hdr) - ETH_HLEN;
Michael Chanb6016b72005-05-26 13:03:09 -07006632
Michael Chan4666f872007-05-03 13:22:28 -07006633 vlan_tag_flags |= ((tcp_opt_len >> 2) << 8) |
6634 TX_BD_FLAGS_SW_FLAGS;
6635 if (likely(tcp_off == 0))
6636 vlan_tag_flags &= ~TX_BD_FLAGS_TCP6_OFF0_MSK;
6637 else {
6638 tcp_off >>= 3;
6639 vlan_tag_flags |= ((tcp_off & 0x3) <<
6640 TX_BD_FLAGS_TCP6_OFF0_SHL) |
6641 ((tcp_off & 0x10) <<
6642 TX_BD_FLAGS_TCP6_OFF4_SHL);
6643 mss |= (tcp_off & 0xc) << TX_BD_TCP6_OFF2_SHL;
6644 }
6645 } else {
Michael Chan4666f872007-05-03 13:22:28 -07006646 iph = ip_hdr(skb);
Michael Chan4666f872007-05-03 13:22:28 -07006647 if (tcp_opt_len || (iph->ihl > 5)) {
6648 vlan_tag_flags |= ((iph->ihl - 5) +
6649 (tcp_opt_len >> 2)) << 8;
6650 }
Michael Chanb6016b72005-05-26 13:03:09 -07006651 }
Michael Chan4666f872007-05-03 13:22:28 -07006652 } else
Michael Chanb6016b72005-05-26 13:03:09 -07006653 mss = 0;
Michael Chanb6016b72005-05-26 13:03:09 -07006654
Stanislaw Gruszka36227e82010-07-15 04:25:50 +00006655 mapping = dma_map_single(&bp->pdev->dev, skb->data, len, PCI_DMA_TODEVICE);
6656 if (dma_mapping_error(&bp->pdev->dev, mapping)) {
Eric W. Biedermanf458b2e2014-03-11 14:17:41 -07006657 dev_kfree_skb_any(skb);
Benjamin Li3d16af82008-10-09 12:26:41 -07006658 return NETDEV_TX_OK;
6659 }
6660
Michael Chan35e90102008-06-19 16:37:42 -07006661 tx_buf = &txr->tx_buf_ring[ring_prod];
Michael Chanb6016b72005-05-26 13:03:09 -07006662 tx_buf->skb = skb;
FUJITA Tomonori1a4ccc22010-04-01 16:56:57 +00006663 dma_unmap_addr_set(tx_buf, mapping, mapping);
Michael Chanb6016b72005-05-26 13:03:09 -07006664
Michael Chan35e90102008-06-19 16:37:42 -07006665 txbd = &txr->tx_desc_ring[ring_prod];
Michael Chanb6016b72005-05-26 13:03:09 -07006666
6667 txbd->tx_bd_haddr_hi = (u64) mapping >> 32;
6668 txbd->tx_bd_haddr_lo = (u64) mapping & 0xffffffff;
6669 txbd->tx_bd_mss_nbytes = len | (mss << 16);
6670 txbd->tx_bd_vlan_tag_flags = vlan_tag_flags | TX_BD_FLAGS_START;
6671
6672 last_frag = skb_shinfo(skb)->nr_frags;
Eric Dumazetd62fda02009-05-12 20:48:02 +00006673 tx_buf->nr_frags = last_frag;
6674 tx_buf->is_gso = skb_is_gso(skb);
Michael Chanb6016b72005-05-26 13:03:09 -07006675
6676 for (i = 0; i < last_frag; i++) {
Eric Dumazet9e903e02011-10-18 21:00:24 +00006677 const skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
Michael Chanb6016b72005-05-26 13:03:09 -07006678
Michael Chan2bc40782012-12-06 10:33:09 +00006679 prod = BNX2_NEXT_TX_BD(prod);
6680 ring_prod = BNX2_TX_RING_IDX(prod);
Michael Chan35e90102008-06-19 16:37:42 -07006681 txbd = &txr->tx_desc_ring[ring_prod];
Michael Chanb6016b72005-05-26 13:03:09 -07006682
Eric Dumazet9e903e02011-10-18 21:00:24 +00006683 len = skb_frag_size(frag);
Ian Campbellb7b6a682011-08-24 22:28:12 +00006684 mapping = skb_frag_dma_map(&bp->pdev->dev, frag, 0, len,
Ian Campbell5d6bcdf2011-10-06 11:10:48 +01006685 DMA_TO_DEVICE);
Stanislaw Gruszka36227e82010-07-15 04:25:50 +00006686 if (dma_mapping_error(&bp->pdev->dev, mapping))
Alexander Duycke95524a2009-12-02 16:47:57 +00006687 goto dma_error;
FUJITA Tomonori1a4ccc22010-04-01 16:56:57 +00006688 dma_unmap_addr_set(&txr->tx_buf_ring[ring_prod], mapping,
Alexander Duycke95524a2009-12-02 16:47:57 +00006689 mapping);
Michael Chanb6016b72005-05-26 13:03:09 -07006690
6691 txbd->tx_bd_haddr_hi = (u64) mapping >> 32;
6692 txbd->tx_bd_haddr_lo = (u64) mapping & 0xffffffff;
6693 txbd->tx_bd_mss_nbytes = len | (mss << 16);
6694 txbd->tx_bd_vlan_tag_flags = vlan_tag_flags;
6695
6696 }
6697 txbd->tx_bd_vlan_tag_flags |= TX_BD_FLAGS_END;
6698
Vlad Zolotarov94bf91b2012-02-05 15:24:39 +00006699 /* Sync BD data before updating TX mailbox */
6700 wmb();
6701
Eric Dumazete9831902011-11-29 11:53:05 +00006702 netdev_tx_sent_queue(txq, skb->len);
6703
Michael Chan2bc40782012-12-06 10:33:09 +00006704 prod = BNX2_NEXT_TX_BD(prod);
Michael Chan35e90102008-06-19 16:37:42 -07006705 txr->tx_prod_bseq += skb->len;
Michael Chanb6016b72005-05-26 13:03:09 -07006706
Michael Chane503e062012-12-06 10:33:08 +00006707 BNX2_WR16(bp, txr->tx_bidx_addr, prod);
6708 BNX2_WR(bp, txr->tx_bseq_addr, txr->tx_prod_bseq);
Michael Chanb6016b72005-05-26 13:03:09 -07006709
6710 mmiowb();
6711
Michael Chan35e90102008-06-19 16:37:42 -07006712 txr->tx_prod = prod;
Michael Chanb6016b72005-05-26 13:03:09 -07006713
Michael Chan35e90102008-06-19 16:37:42 -07006714 if (unlikely(bnx2_tx_avail(bp, txr) <= MAX_SKB_FRAGS)) {
Benjamin Li706bf242008-07-18 17:55:11 -07006715 netif_tx_stop_queue(txq);
Michael Chan11848b962010-07-19 14:15:04 +00006716
6717 /* netif_tx_stop_queue() must be done before checking
6718 * tx index in bnx2_tx_avail() below, because in
6719 * bnx2_tx_int(), we update tx index before checking for
6720 * netif_tx_queue_stopped().
6721 */
6722 smp_mb();
Michael Chan35e90102008-06-19 16:37:42 -07006723 if (bnx2_tx_avail(bp, txr) > bp->tx_wake_thresh)
Benjamin Li706bf242008-07-18 17:55:11 -07006724 netif_tx_wake_queue(txq);
Michael Chanb6016b72005-05-26 13:03:09 -07006725 }
6726
6727 return NETDEV_TX_OK;
Alexander Duycke95524a2009-12-02 16:47:57 +00006728dma_error:
6729 /* save value of frag that failed */
6730 last_frag = i;
6731
6732 /* start back at beginning and unmap skb */
6733 prod = txr->tx_prod;
Michael Chan2bc40782012-12-06 10:33:09 +00006734 ring_prod = BNX2_TX_RING_IDX(prod);
Alexander Duycke95524a2009-12-02 16:47:57 +00006735 tx_buf = &txr->tx_buf_ring[ring_prod];
6736 tx_buf->skb = NULL;
Stanislaw Gruszka36227e82010-07-15 04:25:50 +00006737 dma_unmap_single(&bp->pdev->dev, dma_unmap_addr(tx_buf, mapping),
Alexander Duycke95524a2009-12-02 16:47:57 +00006738 skb_headlen(skb), PCI_DMA_TODEVICE);
6739
6740 /* unmap remaining mapped pages */
6741 for (i = 0; i < last_frag; i++) {
Michael Chan2bc40782012-12-06 10:33:09 +00006742 prod = BNX2_NEXT_TX_BD(prod);
6743 ring_prod = BNX2_TX_RING_IDX(prod);
Alexander Duycke95524a2009-12-02 16:47:57 +00006744 tx_buf = &txr->tx_buf_ring[ring_prod];
Stanislaw Gruszka36227e82010-07-15 04:25:50 +00006745 dma_unmap_page(&bp->pdev->dev, dma_unmap_addr(tx_buf, mapping),
Eric Dumazet9e903e02011-10-18 21:00:24 +00006746 skb_frag_size(&skb_shinfo(skb)->frags[i]),
Alexander Duycke95524a2009-12-02 16:47:57 +00006747 PCI_DMA_TODEVICE);
6748 }
6749
Eric W. Biedermanf458b2e2014-03-11 14:17:41 -07006750 dev_kfree_skb_any(skb);
Alexander Duycke95524a2009-12-02 16:47:57 +00006751 return NETDEV_TX_OK;
Michael Chanb6016b72005-05-26 13:03:09 -07006752}
6753
6754/* Called with rtnl_lock */
6755static int
6756bnx2_close(struct net_device *dev)
6757{
Michael Chan972ec0d2006-01-23 16:12:43 -08006758 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006759
Stephen Hemmingerbea33482007-10-03 16:41:36 -07006760 bnx2_disable_int_sync(bp);
Michael Chan35efa7c2007-12-20 19:56:37 -08006761 bnx2_napi_disable(bp);
Michael Chand2e553b2012-06-27 15:08:24 +00006762 netif_tx_disable(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006763 del_timer_sync(&bp->timer);
Michael Chan74bf4ba2008-10-09 12:21:08 -07006764 bnx2_shutdown_chip(bp);
Michael Chan8e6a72c2007-05-03 13:24:48 -07006765 bnx2_free_irq(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07006766 bnx2_free_skbs(bp);
6767 bnx2_free_mem(bp);
Michael Chanf048fa92010-06-01 15:05:36 +00006768 bnx2_del_napi(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07006769 bp->link_up = 0;
6770 netif_carrier_off(bp->dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006771 return 0;
6772}
6773
Michael Chan354fcd72010-01-17 07:30:44 +00006774static void
6775bnx2_save_stats(struct bnx2 *bp)
6776{
6777 u32 *hw_stats = (u32 *) bp->stats_blk;
6778 u32 *temp_stats = (u32 *) bp->temp_stats_blk;
6779 int i;
6780
6781 /* The 1st 10 counters are 64-bit counters */
6782 for (i = 0; i < 20; i += 2) {
6783 u32 hi;
6784 u64 lo;
6785
Patrick Rabauc9885fe2010-02-15 19:42:11 +00006786 hi = temp_stats[i] + hw_stats[i];
6787 lo = (u64) temp_stats[i + 1] + (u64) hw_stats[i + 1];
Michael Chan354fcd72010-01-17 07:30:44 +00006788 if (lo > 0xffffffff)
6789 hi++;
Patrick Rabauc9885fe2010-02-15 19:42:11 +00006790 temp_stats[i] = hi;
6791 temp_stats[i + 1] = lo & 0xffffffff;
Michael Chan354fcd72010-01-17 07:30:44 +00006792 }
6793
6794 for ( ; i < sizeof(struct statistics_block) / 4; i++)
Patrick Rabauc9885fe2010-02-15 19:42:11 +00006795 temp_stats[i] += hw_stats[i];
Michael Chan354fcd72010-01-17 07:30:44 +00006796}
6797
Eric Dumazet5d07bf22010-07-08 04:08:43 +00006798#define GET_64BIT_NET_STATS64(ctr) \
6799 (((u64) (ctr##_hi) << 32) + (u64) (ctr##_lo))
Michael Chanb6016b72005-05-26 13:03:09 -07006800
Michael Chana4743052010-01-17 07:30:43 +00006801#define GET_64BIT_NET_STATS(ctr) \
Michael Chan354fcd72010-01-17 07:30:44 +00006802 GET_64BIT_NET_STATS64(bp->stats_blk->ctr) + \
6803 GET_64BIT_NET_STATS64(bp->temp_stats_blk->ctr)
Michael Chanb6016b72005-05-26 13:03:09 -07006804
Michael Chana4743052010-01-17 07:30:43 +00006805#define GET_32BIT_NET_STATS(ctr) \
Michael Chan354fcd72010-01-17 07:30:44 +00006806 (unsigned long) (bp->stats_blk->ctr + \
6807 bp->temp_stats_blk->ctr)
Michael Chana4743052010-01-17 07:30:43 +00006808
Eric Dumazet5d07bf22010-07-08 04:08:43 +00006809static struct rtnl_link_stats64 *
6810bnx2_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *net_stats)
Michael Chanb6016b72005-05-26 13:03:09 -07006811{
Michael Chan972ec0d2006-01-23 16:12:43 -08006812 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006813
Eric Dumazet5d07bf22010-07-08 04:08:43 +00006814 if (bp->stats_blk == NULL)
Michael Chanb6016b72005-05-26 13:03:09 -07006815 return net_stats;
Eric Dumazet5d07bf22010-07-08 04:08:43 +00006816
Michael Chanb6016b72005-05-26 13:03:09 -07006817 net_stats->rx_packets =
Michael Chana4743052010-01-17 07:30:43 +00006818 GET_64BIT_NET_STATS(stat_IfHCInUcastPkts) +
6819 GET_64BIT_NET_STATS(stat_IfHCInMulticastPkts) +
6820 GET_64BIT_NET_STATS(stat_IfHCInBroadcastPkts);
Michael Chanb6016b72005-05-26 13:03:09 -07006821
6822 net_stats->tx_packets =
Michael Chana4743052010-01-17 07:30:43 +00006823 GET_64BIT_NET_STATS(stat_IfHCOutUcastPkts) +
6824 GET_64BIT_NET_STATS(stat_IfHCOutMulticastPkts) +
6825 GET_64BIT_NET_STATS(stat_IfHCOutBroadcastPkts);
Michael Chanb6016b72005-05-26 13:03:09 -07006826
6827 net_stats->rx_bytes =
Michael Chana4743052010-01-17 07:30:43 +00006828 GET_64BIT_NET_STATS(stat_IfHCInOctets);
Michael Chanb6016b72005-05-26 13:03:09 -07006829
6830 net_stats->tx_bytes =
Michael Chana4743052010-01-17 07:30:43 +00006831 GET_64BIT_NET_STATS(stat_IfHCOutOctets);
Michael Chanb6016b72005-05-26 13:03:09 -07006832
Jeff Garzik6aa20a22006-09-13 13:24:59 -04006833 net_stats->multicast =
Michael Chan6fdae992010-07-19 14:15:02 +00006834 GET_64BIT_NET_STATS(stat_IfHCInMulticastPkts);
Michael Chanb6016b72005-05-26 13:03:09 -07006835
Jeff Garzik6aa20a22006-09-13 13:24:59 -04006836 net_stats->collisions =
Michael Chana4743052010-01-17 07:30:43 +00006837 GET_32BIT_NET_STATS(stat_EtherStatsCollisions);
Michael Chanb6016b72005-05-26 13:03:09 -07006838
Jeff Garzik6aa20a22006-09-13 13:24:59 -04006839 net_stats->rx_length_errors =
Michael Chana4743052010-01-17 07:30:43 +00006840 GET_32BIT_NET_STATS(stat_EtherStatsUndersizePkts) +
6841 GET_32BIT_NET_STATS(stat_EtherStatsOverrsizePkts);
Michael Chanb6016b72005-05-26 13:03:09 -07006842
Jeff Garzik6aa20a22006-09-13 13:24:59 -04006843 net_stats->rx_over_errors =
Michael Chana4743052010-01-17 07:30:43 +00006844 GET_32BIT_NET_STATS(stat_IfInFTQDiscards) +
6845 GET_32BIT_NET_STATS(stat_IfInMBUFDiscards);
Michael Chanb6016b72005-05-26 13:03:09 -07006846
Jeff Garzik6aa20a22006-09-13 13:24:59 -04006847 net_stats->rx_frame_errors =
Michael Chana4743052010-01-17 07:30:43 +00006848 GET_32BIT_NET_STATS(stat_Dot3StatsAlignmentErrors);
Michael Chanb6016b72005-05-26 13:03:09 -07006849
Jeff Garzik6aa20a22006-09-13 13:24:59 -04006850 net_stats->rx_crc_errors =
Michael Chana4743052010-01-17 07:30:43 +00006851 GET_32BIT_NET_STATS(stat_Dot3StatsFCSErrors);
Michael Chanb6016b72005-05-26 13:03:09 -07006852
6853 net_stats->rx_errors = net_stats->rx_length_errors +
6854 net_stats->rx_over_errors + net_stats->rx_frame_errors +
6855 net_stats->rx_crc_errors;
6856
6857 net_stats->tx_aborted_errors =
Michael Chana4743052010-01-17 07:30:43 +00006858 GET_32BIT_NET_STATS(stat_Dot3StatsExcessiveCollisions) +
6859 GET_32BIT_NET_STATS(stat_Dot3StatsLateCollisions);
Michael Chanb6016b72005-05-26 13:03:09 -07006860
Michael Chan4ce45e02012-12-06 10:33:10 +00006861 if ((BNX2_CHIP(bp) == BNX2_CHIP_5706) ||
6862 (BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5708_A0))
Michael Chanb6016b72005-05-26 13:03:09 -07006863 net_stats->tx_carrier_errors = 0;
6864 else {
6865 net_stats->tx_carrier_errors =
Michael Chana4743052010-01-17 07:30:43 +00006866 GET_32BIT_NET_STATS(stat_Dot3StatsCarrierSenseErrors);
Michael Chanb6016b72005-05-26 13:03:09 -07006867 }
6868
6869 net_stats->tx_errors =
Michael Chana4743052010-01-17 07:30:43 +00006870 GET_32BIT_NET_STATS(stat_emac_tx_stat_dot3statsinternalmactransmiterrors) +
Michael Chanb6016b72005-05-26 13:03:09 -07006871 net_stats->tx_aborted_errors +
6872 net_stats->tx_carrier_errors;
6873
Michael Chancea94db2006-06-12 22:16:13 -07006874 net_stats->rx_missed_errors =
Michael Chana4743052010-01-17 07:30:43 +00006875 GET_32BIT_NET_STATS(stat_IfInFTQDiscards) +
6876 GET_32BIT_NET_STATS(stat_IfInMBUFDiscards) +
6877 GET_32BIT_NET_STATS(stat_FwRxDrop);
Michael Chancea94db2006-06-12 22:16:13 -07006878
Michael Chanb6016b72005-05-26 13:03:09 -07006879 return net_stats;
6880}
6881
6882/* All ethtool functions called with rtnl_lock */
6883
6884static int
6885bnx2_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
6886{
Michael Chan972ec0d2006-01-23 16:12:43 -08006887 struct bnx2 *bp = netdev_priv(dev);
Michael Chan7b6b8342007-07-07 22:50:15 -07006888 int support_serdes = 0, support_copper = 0;
Michael Chanb6016b72005-05-26 13:03:09 -07006889
6890 cmd->supported = SUPPORTED_Autoneg;
Michael Chan583c28e2008-01-21 19:51:35 -08006891 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP) {
Michael Chan7b6b8342007-07-07 22:50:15 -07006892 support_serdes = 1;
6893 support_copper = 1;
6894 } else if (bp->phy_port == PORT_FIBRE)
6895 support_serdes = 1;
6896 else
6897 support_copper = 1;
6898
6899 if (support_serdes) {
Michael Chanb6016b72005-05-26 13:03:09 -07006900 cmd->supported |= SUPPORTED_1000baseT_Full |
6901 SUPPORTED_FIBRE;
Michael Chan583c28e2008-01-21 19:51:35 -08006902 if (bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE)
Michael Chan605a9e22007-05-03 13:23:13 -07006903 cmd->supported |= SUPPORTED_2500baseX_Full;
Michael Chanb6016b72005-05-26 13:03:09 -07006904
Michael Chanb6016b72005-05-26 13:03:09 -07006905 }
Michael Chan7b6b8342007-07-07 22:50:15 -07006906 if (support_copper) {
Michael Chanb6016b72005-05-26 13:03:09 -07006907 cmd->supported |= SUPPORTED_10baseT_Half |
6908 SUPPORTED_10baseT_Full |
6909 SUPPORTED_100baseT_Half |
6910 SUPPORTED_100baseT_Full |
6911 SUPPORTED_1000baseT_Full |
6912 SUPPORTED_TP;
6913
Michael Chanb6016b72005-05-26 13:03:09 -07006914 }
6915
Michael Chan7b6b8342007-07-07 22:50:15 -07006916 spin_lock_bh(&bp->phy_lock);
6917 cmd->port = bp->phy_port;
Michael Chanb6016b72005-05-26 13:03:09 -07006918 cmd->advertising = bp->advertising;
6919
6920 if (bp->autoneg & AUTONEG_SPEED) {
6921 cmd->autoneg = AUTONEG_ENABLE;
David Decotigny70739492011-04-27 18:32:40 +00006922 } else {
Michael Chanb6016b72005-05-26 13:03:09 -07006923 cmd->autoneg = AUTONEG_DISABLE;
6924 }
6925
6926 if (netif_carrier_ok(dev)) {
David Decotigny70739492011-04-27 18:32:40 +00006927 ethtool_cmd_speed_set(cmd, bp->line_speed);
Michael Chanb6016b72005-05-26 13:03:09 -07006928 cmd->duplex = bp->duplex;
Michael Chan4016bad2013-12-31 23:22:34 -08006929 if (!(bp->phy_flags & BNX2_PHY_FLAG_SERDES)) {
6930 if (bp->phy_flags & BNX2_PHY_FLAG_MDIX)
6931 cmd->eth_tp_mdix = ETH_TP_MDI_X;
6932 else
6933 cmd->eth_tp_mdix = ETH_TP_MDI;
6934 }
Michael Chanb6016b72005-05-26 13:03:09 -07006935 }
6936 else {
Jiri Pirko537fae02014-06-06 14:17:00 +02006937 ethtool_cmd_speed_set(cmd, SPEED_UNKNOWN);
6938 cmd->duplex = DUPLEX_UNKNOWN;
Michael Chanb6016b72005-05-26 13:03:09 -07006939 }
Michael Chan7b6b8342007-07-07 22:50:15 -07006940 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07006941
6942 cmd->transceiver = XCVR_INTERNAL;
6943 cmd->phy_address = bp->phy_addr;
6944
6945 return 0;
6946}
Jeff Garzik6aa20a22006-09-13 13:24:59 -04006947
Michael Chanb6016b72005-05-26 13:03:09 -07006948static int
6949bnx2_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
6950{
Michael Chan972ec0d2006-01-23 16:12:43 -08006951 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006952 u8 autoneg = bp->autoneg;
6953 u8 req_duplex = bp->req_duplex;
6954 u16 req_line_speed = bp->req_line_speed;
6955 u32 advertising = bp->advertising;
Michael Chan7b6b8342007-07-07 22:50:15 -07006956 int err = -EINVAL;
6957
6958 spin_lock_bh(&bp->phy_lock);
6959
6960 if (cmd->port != PORT_TP && cmd->port != PORT_FIBRE)
6961 goto err_out_unlock;
6962
Michael Chan583c28e2008-01-21 19:51:35 -08006963 if (cmd->port != bp->phy_port &&
6964 !(bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP))
Michael Chan7b6b8342007-07-07 22:50:15 -07006965 goto err_out_unlock;
Michael Chanb6016b72005-05-26 13:03:09 -07006966
Michael Chand6b14482008-07-14 22:37:21 -07006967 /* If device is down, we can store the settings only if the user
6968 * is setting the currently active port.
6969 */
6970 if (!netif_running(dev) && cmd->port != bp->phy_port)
6971 goto err_out_unlock;
6972
Michael Chanb6016b72005-05-26 13:03:09 -07006973 if (cmd->autoneg == AUTONEG_ENABLE) {
6974 autoneg |= AUTONEG_SPEED;
6975
Michael Chanbeb499a2010-02-15 19:42:10 +00006976 advertising = cmd->advertising;
6977 if (cmd->port == PORT_TP) {
6978 advertising &= ETHTOOL_ALL_COPPER_SPEED;
6979 if (!advertising)
Michael Chanb6016b72005-05-26 13:03:09 -07006980 advertising = ETHTOOL_ALL_COPPER_SPEED;
Michael Chanbeb499a2010-02-15 19:42:10 +00006981 } else {
6982 advertising &= ETHTOOL_ALL_FIBRE_SPEED;
6983 if (!advertising)
6984 advertising = ETHTOOL_ALL_FIBRE_SPEED;
Michael Chanb6016b72005-05-26 13:03:09 -07006985 }
6986 advertising |= ADVERTISED_Autoneg;
6987 }
6988 else {
David Decotigny25db0332011-04-27 18:32:39 +00006989 u32 speed = ethtool_cmd_speed(cmd);
Michael Chan7b6b8342007-07-07 22:50:15 -07006990 if (cmd->port == PORT_FIBRE) {
David Decotigny25db0332011-04-27 18:32:39 +00006991 if ((speed != SPEED_1000 &&
6992 speed != SPEED_2500) ||
Michael Chan80be4432006-11-19 14:07:28 -08006993 (cmd->duplex != DUPLEX_FULL))
Michael Chan7b6b8342007-07-07 22:50:15 -07006994 goto err_out_unlock;
Michael Chan80be4432006-11-19 14:07:28 -08006995
David Decotigny25db0332011-04-27 18:32:39 +00006996 if (speed == SPEED_2500 &&
Michael Chan583c28e2008-01-21 19:51:35 -08006997 !(bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE))
Michael Chan7b6b8342007-07-07 22:50:15 -07006998 goto err_out_unlock;
David Decotigny25db0332011-04-27 18:32:39 +00006999 } else if (speed == SPEED_1000 || speed == SPEED_2500)
Michael Chan7b6b8342007-07-07 22:50:15 -07007000 goto err_out_unlock;
7001
Michael Chanb6016b72005-05-26 13:03:09 -07007002 autoneg &= ~AUTONEG_SPEED;
David Decotigny25db0332011-04-27 18:32:39 +00007003 req_line_speed = speed;
Michael Chanb6016b72005-05-26 13:03:09 -07007004 req_duplex = cmd->duplex;
7005 advertising = 0;
7006 }
7007
7008 bp->autoneg = autoneg;
7009 bp->advertising = advertising;
7010 bp->req_line_speed = req_line_speed;
7011 bp->req_duplex = req_duplex;
7012
Michael Chand6b14482008-07-14 22:37:21 -07007013 err = 0;
7014 /* If device is down, the new settings will be picked up when it is
7015 * brought up.
7016 */
7017 if (netif_running(dev))
7018 err = bnx2_setup_phy(bp, cmd->port);
Michael Chanb6016b72005-05-26 13:03:09 -07007019
Michael Chan7b6b8342007-07-07 22:50:15 -07007020err_out_unlock:
Michael Chanc770a652005-08-25 15:38:39 -07007021 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07007022
Michael Chan7b6b8342007-07-07 22:50:15 -07007023 return err;
Michael Chanb6016b72005-05-26 13:03:09 -07007024}
7025
7026static void
7027bnx2_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
7028{
Michael Chan972ec0d2006-01-23 16:12:43 -08007029 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007030
Rick Jones68aad782011-11-07 13:29:27 +00007031 strlcpy(info->driver, DRV_MODULE_NAME, sizeof(info->driver));
7032 strlcpy(info->version, DRV_MODULE_VERSION, sizeof(info->version));
7033 strlcpy(info->bus_info, pci_name(bp->pdev), sizeof(info->bus_info));
7034 strlcpy(info->fw_version, bp->fw_version, sizeof(info->fw_version));
Michael Chanb6016b72005-05-26 13:03:09 -07007035}
7036
Michael Chan244ac4f2006-03-20 17:48:46 -08007037#define BNX2_REGDUMP_LEN (32 * 1024)
7038
7039static int
7040bnx2_get_regs_len(struct net_device *dev)
7041{
7042 return BNX2_REGDUMP_LEN;
7043}
7044
7045static void
7046bnx2_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *_p)
7047{
7048 u32 *p = _p, i, offset;
7049 u8 *orig_p = _p;
7050 struct bnx2 *bp = netdev_priv(dev);
Joe Perchesb6bc7652010-12-21 02:16:08 -08007051 static const u32 reg_boundaries[] = {
7052 0x0000, 0x0098, 0x0400, 0x045c,
7053 0x0800, 0x0880, 0x0c00, 0x0c10,
7054 0x0c30, 0x0d08, 0x1000, 0x101c,
7055 0x1040, 0x1048, 0x1080, 0x10a4,
7056 0x1400, 0x1490, 0x1498, 0x14f0,
7057 0x1500, 0x155c, 0x1580, 0x15dc,
7058 0x1600, 0x1658, 0x1680, 0x16d8,
7059 0x1800, 0x1820, 0x1840, 0x1854,
7060 0x1880, 0x1894, 0x1900, 0x1984,
7061 0x1c00, 0x1c0c, 0x1c40, 0x1c54,
7062 0x1c80, 0x1c94, 0x1d00, 0x1d84,
7063 0x2000, 0x2030, 0x23c0, 0x2400,
7064 0x2800, 0x2820, 0x2830, 0x2850,
7065 0x2b40, 0x2c10, 0x2fc0, 0x3058,
7066 0x3c00, 0x3c94, 0x4000, 0x4010,
7067 0x4080, 0x4090, 0x43c0, 0x4458,
7068 0x4c00, 0x4c18, 0x4c40, 0x4c54,
7069 0x4fc0, 0x5010, 0x53c0, 0x5444,
7070 0x5c00, 0x5c18, 0x5c80, 0x5c90,
7071 0x5fc0, 0x6000, 0x6400, 0x6428,
7072 0x6800, 0x6848, 0x684c, 0x6860,
7073 0x6888, 0x6910, 0x8000
7074 };
Michael Chan244ac4f2006-03-20 17:48:46 -08007075
7076 regs->version = 0;
7077
7078 memset(p, 0, BNX2_REGDUMP_LEN);
7079
7080 if (!netif_running(bp->dev))
7081 return;
7082
7083 i = 0;
7084 offset = reg_boundaries[0];
7085 p += offset;
7086 while (offset < BNX2_REGDUMP_LEN) {
Michael Chane503e062012-12-06 10:33:08 +00007087 *p++ = BNX2_RD(bp, offset);
Michael Chan244ac4f2006-03-20 17:48:46 -08007088 offset += 4;
7089 if (offset == reg_boundaries[i + 1]) {
7090 offset = reg_boundaries[i + 2];
7091 p = (u32 *) (orig_p + offset);
7092 i += 2;
7093 }
7094 }
7095}
7096
Michael Chanb6016b72005-05-26 13:03:09 -07007097static void
7098bnx2_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
7099{
Michael Chan972ec0d2006-01-23 16:12:43 -08007100 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007101
David S. Millerf86e82f2008-01-21 17:15:40 -08007102 if (bp->flags & BNX2_FLAG_NO_WOL) {
Michael Chanb6016b72005-05-26 13:03:09 -07007103 wol->supported = 0;
7104 wol->wolopts = 0;
7105 }
7106 else {
7107 wol->supported = WAKE_MAGIC;
7108 if (bp->wol)
7109 wol->wolopts = WAKE_MAGIC;
7110 else
7111 wol->wolopts = 0;
7112 }
7113 memset(&wol->sopass, 0, sizeof(wol->sopass));
7114}
7115
7116static int
7117bnx2_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
7118{
Michael Chan972ec0d2006-01-23 16:12:43 -08007119 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007120
7121 if (wol->wolopts & ~WAKE_MAGIC)
7122 return -EINVAL;
7123
7124 if (wol->wolopts & WAKE_MAGIC) {
David S. Millerf86e82f2008-01-21 17:15:40 -08007125 if (bp->flags & BNX2_FLAG_NO_WOL)
Michael Chanb6016b72005-05-26 13:03:09 -07007126 return -EINVAL;
7127
7128 bp->wol = 1;
7129 }
7130 else {
7131 bp->wol = 0;
7132 }
Michael Chan6d5e85c2013-08-06 15:50:08 -07007133
7134 device_set_wakeup_enable(&bp->pdev->dev, bp->wol);
7135
Michael Chanb6016b72005-05-26 13:03:09 -07007136 return 0;
7137}
7138
7139static int
7140bnx2_nway_reset(struct net_device *dev)
7141{
Michael Chan972ec0d2006-01-23 16:12:43 -08007142 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007143 u32 bmcr;
7144
Michael Chan9f52b562008-10-09 12:21:46 -07007145 if (!netif_running(dev))
7146 return -EAGAIN;
7147
Michael Chanb6016b72005-05-26 13:03:09 -07007148 if (!(bp->autoneg & AUTONEG_SPEED)) {
7149 return -EINVAL;
7150 }
7151
Michael Chanc770a652005-08-25 15:38:39 -07007152 spin_lock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07007153
Michael Chan583c28e2008-01-21 19:51:35 -08007154 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP) {
Michael Chan7b6b8342007-07-07 22:50:15 -07007155 int rc;
7156
7157 rc = bnx2_setup_remote_phy(bp, bp->phy_port);
7158 spin_unlock_bh(&bp->phy_lock);
7159 return rc;
7160 }
7161
Michael Chanb6016b72005-05-26 13:03:09 -07007162 /* Force a link down visible on the other side */
Michael Chan583c28e2008-01-21 19:51:35 -08007163 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Michael Chanca58c3a2007-05-03 13:22:52 -07007164 bnx2_write_phy(bp, bp->mii_bmcr, BMCR_LOOPBACK);
Michael Chanc770a652005-08-25 15:38:39 -07007165 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07007166
7167 msleep(20);
7168
Michael Chanc770a652005-08-25 15:38:39 -07007169 spin_lock_bh(&bp->phy_lock);
Michael Chanf8dd0642006-11-19 14:08:29 -08007170
Michael Chan40105c02008-11-12 16:02:45 -08007171 bp->current_interval = BNX2_SERDES_AN_TIMEOUT;
Michael Chanf8dd0642006-11-19 14:08:29 -08007172 bp->serdes_an_pending = 1;
7173 mod_timer(&bp->timer, jiffies + bp->current_interval);
Michael Chanb6016b72005-05-26 13:03:09 -07007174 }
7175
Michael Chanca58c3a2007-05-03 13:22:52 -07007176 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chanb6016b72005-05-26 13:03:09 -07007177 bmcr &= ~BMCR_LOOPBACK;
Michael Chanca58c3a2007-05-03 13:22:52 -07007178 bnx2_write_phy(bp, bp->mii_bmcr, bmcr | BMCR_ANRESTART | BMCR_ANENABLE);
Michael Chanb6016b72005-05-26 13:03:09 -07007179
Michael Chanc770a652005-08-25 15:38:39 -07007180 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07007181
7182 return 0;
7183}
7184
Ooiwa Naohiro7959ea22009-06-24 00:19:06 -07007185static u32
7186bnx2_get_link(struct net_device *dev)
7187{
7188 struct bnx2 *bp = netdev_priv(dev);
7189
7190 return bp->link_up;
7191}
7192
Michael Chanb6016b72005-05-26 13:03:09 -07007193static int
7194bnx2_get_eeprom_len(struct net_device *dev)
7195{
Michael Chan972ec0d2006-01-23 16:12:43 -08007196 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007197
Michael Chan1122db72006-01-23 16:11:42 -08007198 if (bp->flash_info == NULL)
Michael Chanb6016b72005-05-26 13:03:09 -07007199 return 0;
7200
Michael Chan1122db72006-01-23 16:11:42 -08007201 return (int) bp->flash_size;
Michael Chanb6016b72005-05-26 13:03:09 -07007202}
7203
7204static int
7205bnx2_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
7206 u8 *eebuf)
7207{
Michael Chan972ec0d2006-01-23 16:12:43 -08007208 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007209 int rc;
7210
John W. Linville1064e942005-11-10 12:58:24 -08007211 /* parameters already validated in ethtool_get_eeprom */
Michael Chanb6016b72005-05-26 13:03:09 -07007212
7213 rc = bnx2_nvram_read(bp, eeprom->offset, eebuf, eeprom->len);
7214
7215 return rc;
7216}
7217
7218static int
7219bnx2_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
7220 u8 *eebuf)
7221{
Michael Chan972ec0d2006-01-23 16:12:43 -08007222 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007223 int rc;
7224
John W. Linville1064e942005-11-10 12:58:24 -08007225 /* parameters already validated in ethtool_set_eeprom */
Michael Chanb6016b72005-05-26 13:03:09 -07007226
7227 rc = bnx2_nvram_write(bp, eeprom->offset, eebuf, eeprom->len);
7228
7229 return rc;
7230}
7231
7232static int
7233bnx2_get_coalesce(struct net_device *dev, struct ethtool_coalesce *coal)
7234{
Michael Chan972ec0d2006-01-23 16:12:43 -08007235 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007236
7237 memset(coal, 0, sizeof(struct ethtool_coalesce));
7238
7239 coal->rx_coalesce_usecs = bp->rx_ticks;
7240 coal->rx_max_coalesced_frames = bp->rx_quick_cons_trip;
7241 coal->rx_coalesce_usecs_irq = bp->rx_ticks_int;
7242 coal->rx_max_coalesced_frames_irq = bp->rx_quick_cons_trip_int;
7243
7244 coal->tx_coalesce_usecs = bp->tx_ticks;
7245 coal->tx_max_coalesced_frames = bp->tx_quick_cons_trip;
7246 coal->tx_coalesce_usecs_irq = bp->tx_ticks_int;
7247 coal->tx_max_coalesced_frames_irq = bp->tx_quick_cons_trip_int;
7248
7249 coal->stats_block_coalesce_usecs = bp->stats_ticks;
7250
7251 return 0;
7252}
7253
7254static int
7255bnx2_set_coalesce(struct net_device *dev, struct ethtool_coalesce *coal)
7256{
Michael Chan972ec0d2006-01-23 16:12:43 -08007257 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007258
7259 bp->rx_ticks = (u16) coal->rx_coalesce_usecs;
7260 if (bp->rx_ticks > 0x3ff) bp->rx_ticks = 0x3ff;
7261
Jeff Garzik6aa20a22006-09-13 13:24:59 -04007262 bp->rx_quick_cons_trip = (u16) coal->rx_max_coalesced_frames;
Michael Chanb6016b72005-05-26 13:03:09 -07007263 if (bp->rx_quick_cons_trip > 0xff) bp->rx_quick_cons_trip = 0xff;
7264
7265 bp->rx_ticks_int = (u16) coal->rx_coalesce_usecs_irq;
7266 if (bp->rx_ticks_int > 0x3ff) bp->rx_ticks_int = 0x3ff;
7267
7268 bp->rx_quick_cons_trip_int = (u16) coal->rx_max_coalesced_frames_irq;
7269 if (bp->rx_quick_cons_trip_int > 0xff)
7270 bp->rx_quick_cons_trip_int = 0xff;
7271
7272 bp->tx_ticks = (u16) coal->tx_coalesce_usecs;
7273 if (bp->tx_ticks > 0x3ff) bp->tx_ticks = 0x3ff;
7274
7275 bp->tx_quick_cons_trip = (u16) coal->tx_max_coalesced_frames;
7276 if (bp->tx_quick_cons_trip > 0xff) bp->tx_quick_cons_trip = 0xff;
7277
7278 bp->tx_ticks_int = (u16) coal->tx_coalesce_usecs_irq;
7279 if (bp->tx_ticks_int > 0x3ff) bp->tx_ticks_int = 0x3ff;
7280
7281 bp->tx_quick_cons_trip_int = (u16) coal->tx_max_coalesced_frames_irq;
7282 if (bp->tx_quick_cons_trip_int > 0xff) bp->tx_quick_cons_trip_int =
7283 0xff;
7284
7285 bp->stats_ticks = coal->stats_block_coalesce_usecs;
Michael Chan61d9e3f2009-08-21 16:20:46 +00007286 if (bp->flags & BNX2_FLAG_BROKEN_STATS) {
Michael Chan02537b062007-06-04 21:24:07 -07007287 if (bp->stats_ticks != 0 && bp->stats_ticks != USEC_PER_SEC)
7288 bp->stats_ticks = USEC_PER_SEC;
7289 }
Michael Chan7ea69202007-07-16 18:27:10 -07007290 if (bp->stats_ticks > BNX2_HC_STATS_TICKS_HC_STAT_TICKS)
7291 bp->stats_ticks = BNX2_HC_STATS_TICKS_HC_STAT_TICKS;
7292 bp->stats_ticks &= BNX2_HC_STATS_TICKS_HC_STAT_TICKS;
Michael Chanb6016b72005-05-26 13:03:09 -07007293
7294 if (netif_running(bp->dev)) {
Michael Chan212f9932010-04-27 11:28:10 +00007295 bnx2_netif_stop(bp, true);
Michael Chan9a120bc2008-05-16 22:17:45 -07007296 bnx2_init_nic(bp, 0);
Michael Chan212f9932010-04-27 11:28:10 +00007297 bnx2_netif_start(bp, true);
Michael Chanb6016b72005-05-26 13:03:09 -07007298 }
7299
7300 return 0;
7301}
7302
7303static void
7304bnx2_get_ringparam(struct net_device *dev, struct ethtool_ringparam *ering)
7305{
Michael Chan972ec0d2006-01-23 16:12:43 -08007306 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007307
Michael Chan2bc40782012-12-06 10:33:09 +00007308 ering->rx_max_pending = BNX2_MAX_TOTAL_RX_DESC_CNT;
7309 ering->rx_jumbo_max_pending = BNX2_MAX_TOTAL_RX_PG_DESC_CNT;
Michael Chanb6016b72005-05-26 13:03:09 -07007310
7311 ering->rx_pending = bp->rx_ring_size;
Michael Chan47bf4242007-12-12 11:19:12 -08007312 ering->rx_jumbo_pending = bp->rx_pg_ring_size;
Michael Chanb6016b72005-05-26 13:03:09 -07007313
Michael Chan2bc40782012-12-06 10:33:09 +00007314 ering->tx_max_pending = BNX2_MAX_TX_DESC_CNT;
Michael Chanb6016b72005-05-26 13:03:09 -07007315 ering->tx_pending = bp->tx_ring_size;
7316}
7317
7318static int
Michael Chanb0332812012-02-05 15:24:38 +00007319bnx2_change_ring_size(struct bnx2 *bp, u32 rx, u32 tx, bool reset_irq)
Michael Chanb6016b72005-05-26 13:03:09 -07007320{
Michael Chan13daffa2006-03-20 17:49:20 -08007321 if (netif_running(bp->dev)) {
Michael Chan354fcd72010-01-17 07:30:44 +00007322 /* Reset will erase chipset stats; save them */
7323 bnx2_save_stats(bp);
7324
Michael Chan212f9932010-04-27 11:28:10 +00007325 bnx2_netif_stop(bp, true);
Michael Chan13daffa2006-03-20 17:49:20 -08007326 bnx2_reset_chip(bp, BNX2_DRV_MSG_CODE_RESET);
Michael Chanb0332812012-02-05 15:24:38 +00007327 if (reset_irq) {
7328 bnx2_free_irq(bp);
7329 bnx2_del_napi(bp);
7330 } else {
7331 __bnx2_free_irq(bp);
7332 }
Michael Chan13daffa2006-03-20 17:49:20 -08007333 bnx2_free_skbs(bp);
7334 bnx2_free_mem(bp);
7335 }
7336
Michael Chan5d5d0012007-12-12 11:17:43 -08007337 bnx2_set_rx_ring_size(bp, rx);
7338 bp->tx_ring_size = tx;
Michael Chanb6016b72005-05-26 13:03:09 -07007339
7340 if (netif_running(bp->dev)) {
Michael Chanb0332812012-02-05 15:24:38 +00007341 int rc = 0;
Michael Chan13daffa2006-03-20 17:49:20 -08007342
Michael Chanb0332812012-02-05 15:24:38 +00007343 if (reset_irq) {
7344 rc = bnx2_setup_int_mode(bp, disable_msi);
7345 bnx2_init_napi(bp);
7346 }
7347
7348 if (!rc)
7349 rc = bnx2_alloc_mem(bp);
7350
Michael Chan6fefb65e2009-08-21 16:20:45 +00007351 if (!rc)
Michael Chana29ba9d2010-12-31 11:03:14 -08007352 rc = bnx2_request_irq(bp);
7353
7354 if (!rc)
Michael Chan6fefb65e2009-08-21 16:20:45 +00007355 rc = bnx2_init_nic(bp, 0);
7356
7357 if (rc) {
7358 bnx2_napi_enable(bp);
7359 dev_close(bp->dev);
Michael Chan13daffa2006-03-20 17:49:20 -08007360 return rc;
Michael Chan6fefb65e2009-08-21 16:20:45 +00007361 }
Michael Chane9f26c42010-02-15 19:42:08 +00007362#ifdef BCM_CNIC
7363 mutex_lock(&bp->cnic_lock);
7364 /* Let cnic know about the new status block. */
7365 if (bp->cnic_eth_dev.drv_state & CNIC_DRV_STATE_REGD)
7366 bnx2_setup_cnic_irq_info(bp);
7367 mutex_unlock(&bp->cnic_lock);
7368#endif
Michael Chan212f9932010-04-27 11:28:10 +00007369 bnx2_netif_start(bp, true);
Michael Chanb6016b72005-05-26 13:03:09 -07007370 }
Michael Chanb6016b72005-05-26 13:03:09 -07007371 return 0;
7372}
7373
Michael Chan5d5d0012007-12-12 11:17:43 -08007374static int
7375bnx2_set_ringparam(struct net_device *dev, struct ethtool_ringparam *ering)
7376{
7377 struct bnx2 *bp = netdev_priv(dev);
7378 int rc;
7379
Michael Chan2bc40782012-12-06 10:33:09 +00007380 if ((ering->rx_pending > BNX2_MAX_TOTAL_RX_DESC_CNT) ||
7381 (ering->tx_pending > BNX2_MAX_TX_DESC_CNT) ||
Michael Chan5d5d0012007-12-12 11:17:43 -08007382 (ering->tx_pending <= MAX_SKB_FRAGS)) {
7383
7384 return -EINVAL;
7385 }
Michael Chanb0332812012-02-05 15:24:38 +00007386 rc = bnx2_change_ring_size(bp, ering->rx_pending, ering->tx_pending,
7387 false);
Michael Chan5d5d0012007-12-12 11:17:43 -08007388 return rc;
7389}
7390
Michael Chanb6016b72005-05-26 13:03:09 -07007391static void
7392bnx2_get_pauseparam(struct net_device *dev, struct ethtool_pauseparam *epause)
7393{
Michael Chan972ec0d2006-01-23 16:12:43 -08007394 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007395
7396 epause->autoneg = ((bp->autoneg & AUTONEG_FLOW_CTRL) != 0);
7397 epause->rx_pause = ((bp->flow_ctrl & FLOW_CTRL_RX) != 0);
7398 epause->tx_pause = ((bp->flow_ctrl & FLOW_CTRL_TX) != 0);
7399}
7400
7401static int
7402bnx2_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam *epause)
7403{
Michael Chan972ec0d2006-01-23 16:12:43 -08007404 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007405
7406 bp->req_flow_ctrl = 0;
7407 if (epause->rx_pause)
7408 bp->req_flow_ctrl |= FLOW_CTRL_RX;
7409 if (epause->tx_pause)
7410 bp->req_flow_ctrl |= FLOW_CTRL_TX;
7411
7412 if (epause->autoneg) {
7413 bp->autoneg |= AUTONEG_FLOW_CTRL;
7414 }
7415 else {
7416 bp->autoneg &= ~AUTONEG_FLOW_CTRL;
7417 }
7418
Michael Chan9f52b562008-10-09 12:21:46 -07007419 if (netif_running(dev)) {
7420 spin_lock_bh(&bp->phy_lock);
7421 bnx2_setup_phy(bp, bp->phy_port);
7422 spin_unlock_bh(&bp->phy_lock);
7423 }
Michael Chanb6016b72005-05-26 13:03:09 -07007424
7425 return 0;
7426}
7427
Peter Hagervall14ab9b82005-08-10 14:18:16 -07007428static struct {
Michael Chanb6016b72005-05-26 13:03:09 -07007429 char string[ETH_GSTRING_LEN];
Michael Chan790dab22009-08-21 16:20:47 +00007430} bnx2_stats_str_arr[] = {
Michael Chanb6016b72005-05-26 13:03:09 -07007431 { "rx_bytes" },
7432 { "rx_error_bytes" },
7433 { "tx_bytes" },
7434 { "tx_error_bytes" },
7435 { "rx_ucast_packets" },
7436 { "rx_mcast_packets" },
7437 { "rx_bcast_packets" },
7438 { "tx_ucast_packets" },
7439 { "tx_mcast_packets" },
7440 { "tx_bcast_packets" },
7441 { "tx_mac_errors" },
7442 { "tx_carrier_errors" },
7443 { "rx_crc_errors" },
7444 { "rx_align_errors" },
7445 { "tx_single_collisions" },
7446 { "tx_multi_collisions" },
7447 { "tx_deferred" },
7448 { "tx_excess_collisions" },
7449 { "tx_late_collisions" },
7450 { "tx_total_collisions" },
7451 { "rx_fragments" },
7452 { "rx_jabbers" },
7453 { "rx_undersize_packets" },
7454 { "rx_oversize_packets" },
7455 { "rx_64_byte_packets" },
7456 { "rx_65_to_127_byte_packets" },
7457 { "rx_128_to_255_byte_packets" },
7458 { "rx_256_to_511_byte_packets" },
7459 { "rx_512_to_1023_byte_packets" },
7460 { "rx_1024_to_1522_byte_packets" },
7461 { "rx_1523_to_9022_byte_packets" },
7462 { "tx_64_byte_packets" },
7463 { "tx_65_to_127_byte_packets" },
7464 { "tx_128_to_255_byte_packets" },
7465 { "tx_256_to_511_byte_packets" },
7466 { "tx_512_to_1023_byte_packets" },
7467 { "tx_1024_to_1522_byte_packets" },
7468 { "tx_1523_to_9022_byte_packets" },
7469 { "rx_xon_frames" },
7470 { "rx_xoff_frames" },
7471 { "tx_xon_frames" },
7472 { "tx_xoff_frames" },
7473 { "rx_mac_ctrl_frames" },
7474 { "rx_filtered_packets" },
Michael Chan790dab22009-08-21 16:20:47 +00007475 { "rx_ftq_discards" },
Michael Chanb6016b72005-05-26 13:03:09 -07007476 { "rx_discards" },
Michael Chancea94db2006-06-12 22:16:13 -07007477 { "rx_fw_discards" },
Michael Chanb6016b72005-05-26 13:03:09 -07007478};
7479
Jim Cromie0db83cd2012-04-10 14:56:03 +00007480#define BNX2_NUM_STATS ARRAY_SIZE(bnx2_stats_str_arr)
Michael Chan790dab22009-08-21 16:20:47 +00007481
Michael Chanb6016b72005-05-26 13:03:09 -07007482#define STATS_OFFSET32(offset_name) (offsetof(struct statistics_block, offset_name) / 4)
7483
Arjan van de Venf71e1302006-03-03 21:33:57 -05007484static const unsigned long bnx2_stats_offset_arr[BNX2_NUM_STATS] = {
Michael Chanb6016b72005-05-26 13:03:09 -07007485 STATS_OFFSET32(stat_IfHCInOctets_hi),
7486 STATS_OFFSET32(stat_IfHCInBadOctets_hi),
7487 STATS_OFFSET32(stat_IfHCOutOctets_hi),
7488 STATS_OFFSET32(stat_IfHCOutBadOctets_hi),
7489 STATS_OFFSET32(stat_IfHCInUcastPkts_hi),
7490 STATS_OFFSET32(stat_IfHCInMulticastPkts_hi),
7491 STATS_OFFSET32(stat_IfHCInBroadcastPkts_hi),
7492 STATS_OFFSET32(stat_IfHCOutUcastPkts_hi),
7493 STATS_OFFSET32(stat_IfHCOutMulticastPkts_hi),
7494 STATS_OFFSET32(stat_IfHCOutBroadcastPkts_hi),
7495 STATS_OFFSET32(stat_emac_tx_stat_dot3statsinternalmactransmiterrors),
Jeff Garzik6aa20a22006-09-13 13:24:59 -04007496 STATS_OFFSET32(stat_Dot3StatsCarrierSenseErrors),
7497 STATS_OFFSET32(stat_Dot3StatsFCSErrors),
7498 STATS_OFFSET32(stat_Dot3StatsAlignmentErrors),
7499 STATS_OFFSET32(stat_Dot3StatsSingleCollisionFrames),
7500 STATS_OFFSET32(stat_Dot3StatsMultipleCollisionFrames),
7501 STATS_OFFSET32(stat_Dot3StatsDeferredTransmissions),
7502 STATS_OFFSET32(stat_Dot3StatsExcessiveCollisions),
7503 STATS_OFFSET32(stat_Dot3StatsLateCollisions),
7504 STATS_OFFSET32(stat_EtherStatsCollisions),
7505 STATS_OFFSET32(stat_EtherStatsFragments),
7506 STATS_OFFSET32(stat_EtherStatsJabbers),
7507 STATS_OFFSET32(stat_EtherStatsUndersizePkts),
7508 STATS_OFFSET32(stat_EtherStatsOverrsizePkts),
7509 STATS_OFFSET32(stat_EtherStatsPktsRx64Octets),
7510 STATS_OFFSET32(stat_EtherStatsPktsRx65Octetsto127Octets),
7511 STATS_OFFSET32(stat_EtherStatsPktsRx128Octetsto255Octets),
7512 STATS_OFFSET32(stat_EtherStatsPktsRx256Octetsto511Octets),
7513 STATS_OFFSET32(stat_EtherStatsPktsRx512Octetsto1023Octets),
7514 STATS_OFFSET32(stat_EtherStatsPktsRx1024Octetsto1522Octets),
7515 STATS_OFFSET32(stat_EtherStatsPktsRx1523Octetsto9022Octets),
7516 STATS_OFFSET32(stat_EtherStatsPktsTx64Octets),
7517 STATS_OFFSET32(stat_EtherStatsPktsTx65Octetsto127Octets),
7518 STATS_OFFSET32(stat_EtherStatsPktsTx128Octetsto255Octets),
7519 STATS_OFFSET32(stat_EtherStatsPktsTx256Octetsto511Octets),
7520 STATS_OFFSET32(stat_EtherStatsPktsTx512Octetsto1023Octets),
7521 STATS_OFFSET32(stat_EtherStatsPktsTx1024Octetsto1522Octets),
7522 STATS_OFFSET32(stat_EtherStatsPktsTx1523Octetsto9022Octets),
7523 STATS_OFFSET32(stat_XonPauseFramesReceived),
7524 STATS_OFFSET32(stat_XoffPauseFramesReceived),
7525 STATS_OFFSET32(stat_OutXonSent),
7526 STATS_OFFSET32(stat_OutXoffSent),
7527 STATS_OFFSET32(stat_MacControlFramesReceived),
7528 STATS_OFFSET32(stat_IfInFramesL2FilterDiscards),
Michael Chan790dab22009-08-21 16:20:47 +00007529 STATS_OFFSET32(stat_IfInFTQDiscards),
Jeff Garzik6aa20a22006-09-13 13:24:59 -04007530 STATS_OFFSET32(stat_IfInMBUFDiscards),
Michael Chancea94db2006-06-12 22:16:13 -07007531 STATS_OFFSET32(stat_FwRxDrop),
Michael Chanb6016b72005-05-26 13:03:09 -07007532};
7533
7534/* stat_IfHCInBadOctets and stat_Dot3StatsCarrierSenseErrors are
7535 * skipped because of errata.
Jeff Garzik6aa20a22006-09-13 13:24:59 -04007536 */
Peter Hagervall14ab9b82005-08-10 14:18:16 -07007537static u8 bnx2_5706_stats_len_arr[BNX2_NUM_STATS] = {
Michael Chanb6016b72005-05-26 13:03:09 -07007538 8,0,8,8,8,8,8,8,8,8,
7539 4,0,4,4,4,4,4,4,4,4,
7540 4,4,4,4,4,4,4,4,4,4,
7541 4,4,4,4,4,4,4,4,4,4,
Michael Chan790dab22009-08-21 16:20:47 +00007542 4,4,4,4,4,4,4,
Michael Chanb6016b72005-05-26 13:03:09 -07007543};
7544
Michael Chan5b0c76a2005-11-04 08:45:49 -08007545static u8 bnx2_5708_stats_len_arr[BNX2_NUM_STATS] = {
7546 8,0,8,8,8,8,8,8,8,8,
7547 4,4,4,4,4,4,4,4,4,4,
7548 4,4,4,4,4,4,4,4,4,4,
7549 4,4,4,4,4,4,4,4,4,4,
Michael Chan790dab22009-08-21 16:20:47 +00007550 4,4,4,4,4,4,4,
Michael Chan5b0c76a2005-11-04 08:45:49 -08007551};
7552
Michael Chanb6016b72005-05-26 13:03:09 -07007553#define BNX2_NUM_TESTS 6
7554
Peter Hagervall14ab9b82005-08-10 14:18:16 -07007555static struct {
Michael Chanb6016b72005-05-26 13:03:09 -07007556 char string[ETH_GSTRING_LEN];
7557} bnx2_tests_str_arr[BNX2_NUM_TESTS] = {
7558 { "register_test (offline)" },
7559 { "memory_test (offline)" },
7560 { "loopback_test (offline)" },
7561 { "nvram_test (online)" },
7562 { "interrupt_test (online)" },
7563 { "link_test (online)" },
7564};
7565
7566static int
Jeff Garzikb9f2c042007-10-03 18:07:32 -07007567bnx2_get_sset_count(struct net_device *dev, int sset)
Michael Chanb6016b72005-05-26 13:03:09 -07007568{
Jeff Garzikb9f2c042007-10-03 18:07:32 -07007569 switch (sset) {
7570 case ETH_SS_TEST:
7571 return BNX2_NUM_TESTS;
7572 case ETH_SS_STATS:
7573 return BNX2_NUM_STATS;
7574 default:
7575 return -EOPNOTSUPP;
7576 }
Michael Chanb6016b72005-05-26 13:03:09 -07007577}
7578
7579static void
7580bnx2_self_test(struct net_device *dev, struct ethtool_test *etest, u64 *buf)
7581{
Michael Chan972ec0d2006-01-23 16:12:43 -08007582 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007583
7584 memset(buf, 0, sizeof(u64) * BNX2_NUM_TESTS);
7585 if (etest->flags & ETH_TEST_FL_OFFLINE) {
Michael Chan80be4432006-11-19 14:07:28 -08007586 int i;
7587
Michael Chan212f9932010-04-27 11:28:10 +00007588 bnx2_netif_stop(bp, true);
Michael Chanb6016b72005-05-26 13:03:09 -07007589 bnx2_reset_chip(bp, BNX2_DRV_MSG_CODE_DIAG);
7590 bnx2_free_skbs(bp);
7591
7592 if (bnx2_test_registers(bp) != 0) {
7593 buf[0] = 1;
7594 etest->flags |= ETH_TEST_FL_FAILED;
7595 }
7596 if (bnx2_test_memory(bp) != 0) {
7597 buf[1] = 1;
7598 etest->flags |= ETH_TEST_FL_FAILED;
7599 }
Michael Chanbc5a0692006-01-23 16:13:22 -08007600 if ((buf[2] = bnx2_test_loopback(bp)) != 0)
Michael Chanb6016b72005-05-26 13:03:09 -07007601 etest->flags |= ETH_TEST_FL_FAILED;
Michael Chanb6016b72005-05-26 13:03:09 -07007602
Michael Chan9f52b562008-10-09 12:21:46 -07007603 if (!netif_running(bp->dev))
7604 bnx2_shutdown_chip(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07007605 else {
Michael Chan9a120bc2008-05-16 22:17:45 -07007606 bnx2_init_nic(bp, 1);
Michael Chan212f9932010-04-27 11:28:10 +00007607 bnx2_netif_start(bp, true);
Michael Chanb6016b72005-05-26 13:03:09 -07007608 }
7609
7610 /* wait for link up */
Michael Chan80be4432006-11-19 14:07:28 -08007611 for (i = 0; i < 7; i++) {
7612 if (bp->link_up)
7613 break;
7614 msleep_interruptible(1000);
7615 }
Michael Chanb6016b72005-05-26 13:03:09 -07007616 }
7617
7618 if (bnx2_test_nvram(bp) != 0) {
7619 buf[3] = 1;
7620 etest->flags |= ETH_TEST_FL_FAILED;
7621 }
7622 if (bnx2_test_intr(bp) != 0) {
7623 buf[4] = 1;
7624 etest->flags |= ETH_TEST_FL_FAILED;
7625 }
7626
7627 if (bnx2_test_link(bp) != 0) {
7628 buf[5] = 1;
7629 etest->flags |= ETH_TEST_FL_FAILED;
7630
7631 }
7632}
7633
7634static void
7635bnx2_get_strings(struct net_device *dev, u32 stringset, u8 *buf)
7636{
7637 switch (stringset) {
7638 case ETH_SS_STATS:
7639 memcpy(buf, bnx2_stats_str_arr,
7640 sizeof(bnx2_stats_str_arr));
7641 break;
7642 case ETH_SS_TEST:
7643 memcpy(buf, bnx2_tests_str_arr,
7644 sizeof(bnx2_tests_str_arr));
7645 break;
7646 }
7647}
7648
Michael Chanb6016b72005-05-26 13:03:09 -07007649static void
7650bnx2_get_ethtool_stats(struct net_device *dev,
7651 struct ethtool_stats *stats, u64 *buf)
7652{
Michael Chan972ec0d2006-01-23 16:12:43 -08007653 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007654 int i;
7655 u32 *hw_stats = (u32 *) bp->stats_blk;
Michael Chan354fcd72010-01-17 07:30:44 +00007656 u32 *temp_stats = (u32 *) bp->temp_stats_blk;
Peter Hagervall14ab9b82005-08-10 14:18:16 -07007657 u8 *stats_len_arr = NULL;
Michael Chanb6016b72005-05-26 13:03:09 -07007658
7659 if (hw_stats == NULL) {
7660 memset(buf, 0, sizeof(u64) * BNX2_NUM_STATS);
7661 return;
7662 }
7663
Michael Chan4ce45e02012-12-06 10:33:10 +00007664 if ((BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5706_A0) ||
7665 (BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5706_A1) ||
7666 (BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5706_A2) ||
7667 (BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5708_A0))
Michael Chanb6016b72005-05-26 13:03:09 -07007668 stats_len_arr = bnx2_5706_stats_len_arr;
Michael Chan5b0c76a2005-11-04 08:45:49 -08007669 else
7670 stats_len_arr = bnx2_5708_stats_len_arr;
Michael Chanb6016b72005-05-26 13:03:09 -07007671
7672 for (i = 0; i < BNX2_NUM_STATS; i++) {
Michael Chan354fcd72010-01-17 07:30:44 +00007673 unsigned long offset;
7674
Michael Chanb6016b72005-05-26 13:03:09 -07007675 if (stats_len_arr[i] == 0) {
7676 /* skip this counter */
7677 buf[i] = 0;
7678 continue;
7679 }
Michael Chan354fcd72010-01-17 07:30:44 +00007680
7681 offset = bnx2_stats_offset_arr[i];
Michael Chanb6016b72005-05-26 13:03:09 -07007682 if (stats_len_arr[i] == 4) {
7683 /* 4-byte counter */
Michael Chan354fcd72010-01-17 07:30:44 +00007684 buf[i] = (u64) *(hw_stats + offset) +
7685 *(temp_stats + offset);
Michael Chanb6016b72005-05-26 13:03:09 -07007686 continue;
7687 }
7688 /* 8-byte counter */
Michael Chan354fcd72010-01-17 07:30:44 +00007689 buf[i] = (((u64) *(hw_stats + offset)) << 32) +
7690 *(hw_stats + offset + 1) +
7691 (((u64) *(temp_stats + offset)) << 32) +
7692 *(temp_stats + offset + 1);
Michael Chanb6016b72005-05-26 13:03:09 -07007693 }
7694}
7695
7696static int
stephen hemminger2e17e1a2011-04-04 11:06:36 +00007697bnx2_set_phys_id(struct net_device *dev, enum ethtool_phys_id_state state)
Michael Chanb6016b72005-05-26 13:03:09 -07007698{
Michael Chan972ec0d2006-01-23 16:12:43 -08007699 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007700
stephen hemminger2e17e1a2011-04-04 11:06:36 +00007701 switch (state) {
7702 case ETHTOOL_ID_ACTIVE:
Michael Chane503e062012-12-06 10:33:08 +00007703 bp->leds_save = BNX2_RD(bp, BNX2_MISC_CFG);
7704 BNX2_WR(bp, BNX2_MISC_CFG, BNX2_MISC_CFG_LEDMODE_MAC);
Allan, Bruce Wfce55922011-04-13 13:09:10 +00007705 return 1; /* cycle on/off once per second */
Michael Chanb6016b72005-05-26 13:03:09 -07007706
stephen hemminger2e17e1a2011-04-04 11:06:36 +00007707 case ETHTOOL_ID_ON:
Michael Chane503e062012-12-06 10:33:08 +00007708 BNX2_WR(bp, BNX2_EMAC_LED, BNX2_EMAC_LED_OVERRIDE |
7709 BNX2_EMAC_LED_1000MB_OVERRIDE |
7710 BNX2_EMAC_LED_100MB_OVERRIDE |
7711 BNX2_EMAC_LED_10MB_OVERRIDE |
7712 BNX2_EMAC_LED_TRAFFIC_OVERRIDE |
7713 BNX2_EMAC_LED_TRAFFIC);
stephen hemminger2e17e1a2011-04-04 11:06:36 +00007714 break;
Michael Chanb6016b72005-05-26 13:03:09 -07007715
stephen hemminger2e17e1a2011-04-04 11:06:36 +00007716 case ETHTOOL_ID_OFF:
Michael Chane503e062012-12-06 10:33:08 +00007717 BNX2_WR(bp, BNX2_EMAC_LED, BNX2_EMAC_LED_OVERRIDE);
stephen hemminger2e17e1a2011-04-04 11:06:36 +00007718 break;
7719
7720 case ETHTOOL_ID_INACTIVE:
Michael Chane503e062012-12-06 10:33:08 +00007721 BNX2_WR(bp, BNX2_EMAC_LED, 0);
7722 BNX2_WR(bp, BNX2_MISC_CFG, bp->leds_save);
stephen hemminger2e17e1a2011-04-04 11:06:36 +00007723 break;
Michael Chanb6016b72005-05-26 13:03:09 -07007724 }
Michael Chan9f52b562008-10-09 12:21:46 -07007725
Michael Chanb6016b72005-05-26 13:03:09 -07007726 return 0;
7727}
7728
Michael Chanfdc85412010-07-03 20:42:16 +00007729static int
Michał Mirosławc8f44af2011-11-15 15:29:55 +00007730bnx2_set_features(struct net_device *dev, netdev_features_t features)
Michael Chanfdc85412010-07-03 20:42:16 +00007731{
Jesse Gross7d0fd212010-10-20 13:56:09 +00007732 struct bnx2 *bp = netdev_priv(dev);
Jesse Gross7d0fd212010-10-20 13:56:09 +00007733
Michael Chan7c810472011-01-24 12:59:02 +00007734 /* TSO with VLAN tag won't work with current firmware */
Patrick McHardyf6469682013-04-19 02:04:27 +00007735 if (features & NETIF_F_HW_VLAN_CTAG_TX)
Michał Mirosław8d7dfc22011-04-10 04:47:46 +00007736 dev->vlan_features |= (dev->hw_features & NETIF_F_ALL_TSO);
7737 else
7738 dev->vlan_features &= ~NETIF_F_ALL_TSO;
Michael Chan7c810472011-01-24 12:59:02 +00007739
Patrick McHardyf6469682013-04-19 02:04:27 +00007740 if ((!!(features & NETIF_F_HW_VLAN_CTAG_RX) !=
Jesse Gross7d0fd212010-10-20 13:56:09 +00007741 !!(bp->rx_mode & BNX2_EMAC_RX_MODE_KEEP_VLAN_TAG)) &&
7742 netif_running(dev)) {
7743 bnx2_netif_stop(bp, false);
Michał Mirosław8d7dfc22011-04-10 04:47:46 +00007744 dev->features = features;
Jesse Gross7d0fd212010-10-20 13:56:09 +00007745 bnx2_set_rx_mode(dev);
7746 bnx2_fw_sync(bp, BNX2_DRV_MSG_CODE_KEEP_VLAN_UPDATE, 0, 1);
7747 bnx2_netif_start(bp, false);
Michał Mirosław8d7dfc22011-04-10 04:47:46 +00007748 return 1;
Jesse Gross7d0fd212010-10-20 13:56:09 +00007749 }
7750
7751 return 0;
Michael Chanfdc85412010-07-03 20:42:16 +00007752}
7753
Michael Chanb0332812012-02-05 15:24:38 +00007754static void bnx2_get_channels(struct net_device *dev,
7755 struct ethtool_channels *channels)
7756{
7757 struct bnx2 *bp = netdev_priv(dev);
7758 u32 max_rx_rings = 1;
7759 u32 max_tx_rings = 1;
7760
7761 if ((bp->flags & BNX2_FLAG_MSIX_CAP) && !disable_msi) {
7762 max_rx_rings = RX_MAX_RINGS;
7763 max_tx_rings = TX_MAX_RINGS;
7764 }
7765
7766 channels->max_rx = max_rx_rings;
7767 channels->max_tx = max_tx_rings;
7768 channels->max_other = 0;
7769 channels->max_combined = 0;
7770 channels->rx_count = bp->num_rx_rings;
7771 channels->tx_count = bp->num_tx_rings;
7772 channels->other_count = 0;
7773 channels->combined_count = 0;
7774}
7775
7776static int bnx2_set_channels(struct net_device *dev,
7777 struct ethtool_channels *channels)
7778{
7779 struct bnx2 *bp = netdev_priv(dev);
7780 u32 max_rx_rings = 1;
7781 u32 max_tx_rings = 1;
7782 int rc = 0;
7783
7784 if ((bp->flags & BNX2_FLAG_MSIX_CAP) && !disable_msi) {
7785 max_rx_rings = RX_MAX_RINGS;
7786 max_tx_rings = TX_MAX_RINGS;
7787 }
7788 if (channels->rx_count > max_rx_rings ||
7789 channels->tx_count > max_tx_rings)
7790 return -EINVAL;
7791
7792 bp->num_req_rx_rings = channels->rx_count;
7793 bp->num_req_tx_rings = channels->tx_count;
7794
7795 if (netif_running(dev))
7796 rc = bnx2_change_ring_size(bp, bp->rx_ring_size,
7797 bp->tx_ring_size, true);
7798
7799 return rc;
7800}
7801
Jeff Garzik7282d492006-09-13 14:30:00 -04007802static const struct ethtool_ops bnx2_ethtool_ops = {
Michael Chanb6016b72005-05-26 13:03:09 -07007803 .get_settings = bnx2_get_settings,
7804 .set_settings = bnx2_set_settings,
7805 .get_drvinfo = bnx2_get_drvinfo,
Michael Chan244ac4f2006-03-20 17:48:46 -08007806 .get_regs_len = bnx2_get_regs_len,
7807 .get_regs = bnx2_get_regs,
Michael Chanb6016b72005-05-26 13:03:09 -07007808 .get_wol = bnx2_get_wol,
7809 .set_wol = bnx2_set_wol,
7810 .nway_reset = bnx2_nway_reset,
Ooiwa Naohiro7959ea22009-06-24 00:19:06 -07007811 .get_link = bnx2_get_link,
Michael Chanb6016b72005-05-26 13:03:09 -07007812 .get_eeprom_len = bnx2_get_eeprom_len,
7813 .get_eeprom = bnx2_get_eeprom,
7814 .set_eeprom = bnx2_set_eeprom,
7815 .get_coalesce = bnx2_get_coalesce,
7816 .set_coalesce = bnx2_set_coalesce,
7817 .get_ringparam = bnx2_get_ringparam,
7818 .set_ringparam = bnx2_set_ringparam,
7819 .get_pauseparam = bnx2_get_pauseparam,
7820 .set_pauseparam = bnx2_set_pauseparam,
Michael Chanb6016b72005-05-26 13:03:09 -07007821 .self_test = bnx2_self_test,
7822 .get_strings = bnx2_get_strings,
stephen hemminger2e17e1a2011-04-04 11:06:36 +00007823 .set_phys_id = bnx2_set_phys_id,
Michael Chanb6016b72005-05-26 13:03:09 -07007824 .get_ethtool_stats = bnx2_get_ethtool_stats,
Jeff Garzikb9f2c042007-10-03 18:07:32 -07007825 .get_sset_count = bnx2_get_sset_count,
Michael Chanb0332812012-02-05 15:24:38 +00007826 .get_channels = bnx2_get_channels,
7827 .set_channels = bnx2_set_channels,
Michael Chanb6016b72005-05-26 13:03:09 -07007828};
7829
7830/* Called with rtnl_lock */
7831static int
7832bnx2_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
7833{
Peter Hagervall14ab9b82005-08-10 14:18:16 -07007834 struct mii_ioctl_data *data = if_mii(ifr);
Michael Chan972ec0d2006-01-23 16:12:43 -08007835 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007836 int err;
7837
7838 switch(cmd) {
7839 case SIOCGMIIPHY:
7840 data->phy_id = bp->phy_addr;
7841
7842 /* fallthru */
7843 case SIOCGMIIREG: {
7844 u32 mii_regval;
7845
Michael Chan583c28e2008-01-21 19:51:35 -08007846 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
Michael Chan7b6b8342007-07-07 22:50:15 -07007847 return -EOPNOTSUPP;
7848
Michael Chandad3e452007-05-03 13:18:03 -07007849 if (!netif_running(dev))
7850 return -EAGAIN;
7851
Michael Chanc770a652005-08-25 15:38:39 -07007852 spin_lock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07007853 err = bnx2_read_phy(bp, data->reg_num & 0x1f, &mii_regval);
Michael Chanc770a652005-08-25 15:38:39 -07007854 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07007855
7856 data->val_out = mii_regval;
7857
7858 return err;
7859 }
7860
7861 case SIOCSMIIREG:
Michael Chan583c28e2008-01-21 19:51:35 -08007862 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
Michael Chan7b6b8342007-07-07 22:50:15 -07007863 return -EOPNOTSUPP;
7864
Michael Chandad3e452007-05-03 13:18:03 -07007865 if (!netif_running(dev))
7866 return -EAGAIN;
7867
Michael Chanc770a652005-08-25 15:38:39 -07007868 spin_lock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07007869 err = bnx2_write_phy(bp, data->reg_num & 0x1f, data->val_in);
Michael Chanc770a652005-08-25 15:38:39 -07007870 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07007871
7872 return err;
7873
7874 default:
7875 /* do nothing */
7876 break;
7877 }
7878 return -EOPNOTSUPP;
7879}
7880
7881/* Called with rtnl_lock */
7882static int
7883bnx2_change_mac_addr(struct net_device *dev, void *p)
7884{
7885 struct sockaddr *addr = p;
Michael Chan972ec0d2006-01-23 16:12:43 -08007886 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007887
Michael Chan73eef4c2005-08-25 15:39:15 -07007888 if (!is_valid_ether_addr(addr->sa_data))
Danny Kukawka504f9b52012-02-21 02:07:49 +00007889 return -EADDRNOTAVAIL;
Michael Chan73eef4c2005-08-25 15:39:15 -07007890
Michael Chanb6016b72005-05-26 13:03:09 -07007891 memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
7892 if (netif_running(dev))
Benjamin Li5fcaed02008-07-14 22:39:52 -07007893 bnx2_set_mac_addr(bp, bp->dev->dev_addr, 0);
Michael Chanb6016b72005-05-26 13:03:09 -07007894
7895 return 0;
7896}
7897
7898/* Called with rtnl_lock */
7899static int
7900bnx2_change_mtu(struct net_device *dev, int new_mtu)
7901{
Michael Chan972ec0d2006-01-23 16:12:43 -08007902 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007903
7904 if (((new_mtu + ETH_HLEN) > MAX_ETHERNET_JUMBO_PACKET_SIZE) ||
7905 ((new_mtu + ETH_HLEN) < MIN_ETHERNET_PACKET_SIZE))
7906 return -EINVAL;
7907
7908 dev->mtu = new_mtu;
Michael Chanb0332812012-02-05 15:24:38 +00007909 return bnx2_change_ring_size(bp, bp->rx_ring_size, bp->tx_ring_size,
7910 false);
Michael Chanb6016b72005-05-26 13:03:09 -07007911}
7912
Alexey Dobriyan257ddbd2010-01-27 10:17:41 +00007913#ifdef CONFIG_NET_POLL_CONTROLLER
Michael Chanb6016b72005-05-26 13:03:09 -07007914static void
7915poll_bnx2(struct net_device *dev)
7916{
Michael Chan972ec0d2006-01-23 16:12:43 -08007917 struct bnx2 *bp = netdev_priv(dev);
Neil Hormanb2af2c12008-11-12 16:23:44 -08007918 int i;
Michael Chanb6016b72005-05-26 13:03:09 -07007919
Neil Hormanb2af2c12008-11-12 16:23:44 -08007920 for (i = 0; i < bp->irq_nvecs; i++) {
Michael Chan1bf1e342010-03-23 13:13:12 +00007921 struct bnx2_irq *irq = &bp->irq_tbl[i];
7922
7923 disable_irq(irq->vector);
7924 irq->handler(irq->vector, &bp->bnx2_napi[i]);
7925 enable_irq(irq->vector);
Neil Hormanb2af2c12008-11-12 16:23:44 -08007926 }
Michael Chanb6016b72005-05-26 13:03:09 -07007927}
7928#endif
7929
Bill Pembertoncfd95a62012-12-03 09:22:58 -05007930static void
Michael Chan253c8b72007-01-08 19:56:01 -08007931bnx2_get_5709_media(struct bnx2 *bp)
7932{
Michael Chane503e062012-12-06 10:33:08 +00007933 u32 val = BNX2_RD(bp, BNX2_MISC_DUAL_MEDIA_CTRL);
Michael Chan253c8b72007-01-08 19:56:01 -08007934 u32 bond_id = val & BNX2_MISC_DUAL_MEDIA_CTRL_BOND_ID;
7935 u32 strap;
7936
7937 if (bond_id == BNX2_MISC_DUAL_MEDIA_CTRL_BOND_ID_C)
7938 return;
7939 else if (bond_id == BNX2_MISC_DUAL_MEDIA_CTRL_BOND_ID_S) {
Michael Chan583c28e2008-01-21 19:51:35 -08007940 bp->phy_flags |= BNX2_PHY_FLAG_SERDES;
Michael Chan253c8b72007-01-08 19:56:01 -08007941 return;
7942 }
7943
7944 if (val & BNX2_MISC_DUAL_MEDIA_CTRL_STRAP_OVERRIDE)
7945 strap = (val & BNX2_MISC_DUAL_MEDIA_CTRL_PHY_CTRL) >> 21;
7946 else
7947 strap = (val & BNX2_MISC_DUAL_MEDIA_CTRL_PHY_CTRL_STRAP) >> 8;
7948
Michael Chanaefd90e2012-06-16 15:45:43 +00007949 if (bp->func == 0) {
Michael Chan253c8b72007-01-08 19:56:01 -08007950 switch (strap) {
7951 case 0x4:
7952 case 0x5:
7953 case 0x6:
Michael Chan583c28e2008-01-21 19:51:35 -08007954 bp->phy_flags |= BNX2_PHY_FLAG_SERDES;
Michael Chan253c8b72007-01-08 19:56:01 -08007955 return;
7956 }
7957 } else {
7958 switch (strap) {
7959 case 0x1:
7960 case 0x2:
7961 case 0x4:
Michael Chan583c28e2008-01-21 19:51:35 -08007962 bp->phy_flags |= BNX2_PHY_FLAG_SERDES;
Michael Chan253c8b72007-01-08 19:56:01 -08007963 return;
7964 }
7965 }
7966}
7967
Bill Pembertoncfd95a62012-12-03 09:22:58 -05007968static void
Michael Chan883e5152007-05-03 13:25:11 -07007969bnx2_get_pci_speed(struct bnx2 *bp)
7970{
7971 u32 reg;
7972
Michael Chane503e062012-12-06 10:33:08 +00007973 reg = BNX2_RD(bp, BNX2_PCICFG_MISC_STATUS);
Michael Chan883e5152007-05-03 13:25:11 -07007974 if (reg & BNX2_PCICFG_MISC_STATUS_PCIX_DET) {
7975 u32 clkreg;
7976
David S. Millerf86e82f2008-01-21 17:15:40 -08007977 bp->flags |= BNX2_FLAG_PCIX;
Michael Chan883e5152007-05-03 13:25:11 -07007978
Michael Chane503e062012-12-06 10:33:08 +00007979 clkreg = BNX2_RD(bp, BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS);
Michael Chan883e5152007-05-03 13:25:11 -07007980
7981 clkreg &= BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET;
7982 switch (clkreg) {
7983 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_133MHZ:
7984 bp->bus_speed_mhz = 133;
7985 break;
7986
7987 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_95MHZ:
7988 bp->bus_speed_mhz = 100;
7989 break;
7990
7991 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_66MHZ:
7992 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_80MHZ:
7993 bp->bus_speed_mhz = 66;
7994 break;
7995
7996 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_48MHZ:
7997 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_55MHZ:
7998 bp->bus_speed_mhz = 50;
7999 break;
8000
8001 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_LOW:
8002 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_32MHZ:
8003 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_38MHZ:
8004 bp->bus_speed_mhz = 33;
8005 break;
8006 }
8007 }
8008 else {
8009 if (reg & BNX2_PCICFG_MISC_STATUS_M66EN)
8010 bp->bus_speed_mhz = 66;
8011 else
8012 bp->bus_speed_mhz = 33;
8013 }
8014
8015 if (reg & BNX2_PCICFG_MISC_STATUS_32BIT_DET)
David S. Millerf86e82f2008-01-21 17:15:40 -08008016 bp->flags |= BNX2_FLAG_PCI_32BIT;
Michael Chan883e5152007-05-03 13:25:11 -07008017
8018}
8019
Bill Pembertoncfd95a62012-12-03 09:22:58 -05008020static void
Michael Chan76d99062009-12-03 09:46:34 +00008021bnx2_read_vpd_fw_ver(struct bnx2 *bp)
8022{
Matt Carlsondf25bc32010-02-26 14:04:44 +00008023 int rc, i, j;
Michael Chan76d99062009-12-03 09:46:34 +00008024 u8 *data;
Matt Carlsondf25bc32010-02-26 14:04:44 +00008025 unsigned int block_end, rosize, len;
Michael Chan76d99062009-12-03 09:46:34 +00008026
Michael Chan012093f2009-12-03 15:58:00 -08008027#define BNX2_VPD_NVRAM_OFFSET 0x300
8028#define BNX2_VPD_LEN 128
Michael Chan76d99062009-12-03 09:46:34 +00008029#define BNX2_MAX_VER_SLEN 30
8030
8031 data = kmalloc(256, GFP_KERNEL);
8032 if (!data)
8033 return;
8034
Michael Chan012093f2009-12-03 15:58:00 -08008035 rc = bnx2_nvram_read(bp, BNX2_VPD_NVRAM_OFFSET, data + BNX2_VPD_LEN,
8036 BNX2_VPD_LEN);
Michael Chan76d99062009-12-03 09:46:34 +00008037 if (rc)
8038 goto vpd_done;
8039
Michael Chan012093f2009-12-03 15:58:00 -08008040 for (i = 0; i < BNX2_VPD_LEN; i += 4) {
8041 data[i] = data[i + BNX2_VPD_LEN + 3];
8042 data[i + 1] = data[i + BNX2_VPD_LEN + 2];
8043 data[i + 2] = data[i + BNX2_VPD_LEN + 1];
8044 data[i + 3] = data[i + BNX2_VPD_LEN];
Michael Chan76d99062009-12-03 09:46:34 +00008045 }
8046
Matt Carlsondf25bc32010-02-26 14:04:44 +00008047 i = pci_vpd_find_tag(data, 0, BNX2_VPD_LEN, PCI_VPD_LRDT_RO_DATA);
8048 if (i < 0)
Michael Chan76d99062009-12-03 09:46:34 +00008049 goto vpd_done;
Matt Carlsondf25bc32010-02-26 14:04:44 +00008050
8051 rosize = pci_vpd_lrdt_size(&data[i]);
8052 i += PCI_VPD_LRDT_TAG_SIZE;
8053 block_end = i + rosize;
8054
8055 if (block_end > BNX2_VPD_LEN)
8056 goto vpd_done;
8057
8058 j = pci_vpd_find_info_keyword(data, i, rosize,
8059 PCI_VPD_RO_KEYWORD_MFR_ID);
8060 if (j < 0)
8061 goto vpd_done;
8062
8063 len = pci_vpd_info_field_size(&data[j]);
8064
8065 j += PCI_VPD_INFO_FLD_HDR_SIZE;
8066 if (j + len > block_end || len != 4 ||
8067 memcmp(&data[j], "1028", 4))
8068 goto vpd_done;
8069
8070 j = pci_vpd_find_info_keyword(data, i, rosize,
8071 PCI_VPD_RO_KEYWORD_VENDOR0);
8072 if (j < 0)
8073 goto vpd_done;
8074
8075 len = pci_vpd_info_field_size(&data[j]);
8076
8077 j += PCI_VPD_INFO_FLD_HDR_SIZE;
8078 if (j + len > block_end || len > BNX2_MAX_VER_SLEN)
8079 goto vpd_done;
8080
8081 memcpy(bp->fw_version, &data[j], len);
8082 bp->fw_version[len] = ' ';
Michael Chan76d99062009-12-03 09:46:34 +00008083
8084vpd_done:
8085 kfree(data);
8086}
8087
Bill Pembertoncfd95a62012-12-03 09:22:58 -05008088static int
Michael Chanb6016b72005-05-26 13:03:09 -07008089bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
8090{
8091 struct bnx2 *bp;
Michael Chan58fc2ea2007-07-07 22:52:02 -07008092 int rc, i, j;
Michael Chanb6016b72005-05-26 13:03:09 -07008093 u32 reg;
Michael Chan40453c82007-05-03 13:19:18 -07008094 u64 dma_mask, persist_dma_mask;
John Feeneycd709aa2010-08-22 17:45:53 +00008095 int err;
Michael Chanb6016b72005-05-26 13:03:09 -07008096
Michael Chanb6016b72005-05-26 13:03:09 -07008097 SET_NETDEV_DEV(dev, &pdev->dev);
Michael Chan972ec0d2006-01-23 16:12:43 -08008098 bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07008099
8100 bp->flags = 0;
8101 bp->phy_flags = 0;
8102
Michael Chan354fcd72010-01-17 07:30:44 +00008103 bp->temp_stats_blk =
8104 kzalloc(sizeof(struct statistics_block), GFP_KERNEL);
8105
8106 if (bp->temp_stats_blk == NULL) {
8107 rc = -ENOMEM;
8108 goto err_out;
8109 }
8110
Michael Chanb6016b72005-05-26 13:03:09 -07008111 /* enable device (incl. PCI PM wakeup), and bus-mastering */
8112 rc = pci_enable_device(pdev);
8113 if (rc) {
Joe Perches3a9c6a42010-02-17 15:01:51 +00008114 dev_err(&pdev->dev, "Cannot enable PCI device, aborting\n");
Michael Chanb6016b72005-05-26 13:03:09 -07008115 goto err_out;
8116 }
8117
8118 if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) {
Jeff Garzik9b91cf92006-06-27 11:39:50 -04008119 dev_err(&pdev->dev,
Joe Perches3a9c6a42010-02-17 15:01:51 +00008120 "Cannot find PCI device base address, aborting\n");
Michael Chanb6016b72005-05-26 13:03:09 -07008121 rc = -ENODEV;
8122 goto err_out_disable;
8123 }
8124
8125 rc = pci_request_regions(pdev, DRV_MODULE_NAME);
8126 if (rc) {
Joe Perches3a9c6a42010-02-17 15:01:51 +00008127 dev_err(&pdev->dev, "Cannot obtain PCI resources, aborting\n");
Michael Chanb6016b72005-05-26 13:03:09 -07008128 goto err_out_disable;
8129 }
8130
8131 pci_set_master(pdev);
8132
Yijing Wang85768272013-06-18 16:12:37 +08008133 bp->pm_cap = pdev->pm_cap;
Michael Chanb6016b72005-05-26 13:03:09 -07008134 if (bp->pm_cap == 0) {
Jeff Garzik9b91cf92006-06-27 11:39:50 -04008135 dev_err(&pdev->dev,
Joe Perches3a9c6a42010-02-17 15:01:51 +00008136 "Cannot find power management capability, aborting\n");
Michael Chanb6016b72005-05-26 13:03:09 -07008137 rc = -EIO;
8138 goto err_out_release;
8139 }
8140
Michael Chanb6016b72005-05-26 13:03:09 -07008141 bp->dev = dev;
8142 bp->pdev = pdev;
8143
8144 spin_lock_init(&bp->phy_lock);
Michael Chan1b8227c2007-05-03 13:24:05 -07008145 spin_lock_init(&bp->indirect_lock);
Michael Chanc5a88952009-08-14 15:49:45 +00008146#ifdef BCM_CNIC
8147 mutex_init(&bp->cnic_lock);
8148#endif
David Howellsc4028952006-11-22 14:57:56 +00008149 INIT_WORK(&bp->reset_task, bnx2_reset_task);
Michael Chanb6016b72005-05-26 13:03:09 -07008150
Francois Romieuc0357e92012-03-09 14:51:47 +01008151 bp->regview = pci_iomap(pdev, 0, MB_GET_CID_ADDR(TX_TSS_CID +
8152 TX_MAX_TSS_RINGS + 1));
Michael Chanb6016b72005-05-26 13:03:09 -07008153 if (!bp->regview) {
Joe Perches3a9c6a42010-02-17 15:01:51 +00008154 dev_err(&pdev->dev, "Cannot map register space, aborting\n");
Michael Chanb6016b72005-05-26 13:03:09 -07008155 rc = -ENOMEM;
8156 goto err_out_release;
8157 }
8158
8159 /* Configure byte swap and enable write to the reg_window registers.
8160 * Rely on CPU to do target byte swapping on big endian systems
8161 * The chip's target access swapping will not swap all accesses
8162 */
Michael Chane503e062012-12-06 10:33:08 +00008163 BNX2_WR(bp, BNX2_PCICFG_MISC_CONFIG,
8164 BNX2_PCICFG_MISC_CONFIG_REG_WINDOW_ENA |
8165 BNX2_PCICFG_MISC_CONFIG_TARGET_MB_WORD_SWAP);
Michael Chanb6016b72005-05-26 13:03:09 -07008166
Michael Chane503e062012-12-06 10:33:08 +00008167 bp->chip_id = BNX2_RD(bp, BNX2_MISC_ID);
Michael Chanb6016b72005-05-26 13:03:09 -07008168
Michael Chan4ce45e02012-12-06 10:33:10 +00008169 if (BNX2_CHIP(bp) == BNX2_CHIP_5709) {
Jon Masone82760e2011-06-27 07:44:43 +00008170 if (!pci_is_pcie(pdev)) {
8171 dev_err(&pdev->dev, "Not PCIE, aborting\n");
Michael Chan883e5152007-05-03 13:25:11 -07008172 rc = -EIO;
8173 goto err_out_unmap;
8174 }
David S. Millerf86e82f2008-01-21 17:15:40 -08008175 bp->flags |= BNX2_FLAG_PCIE;
Michael Chan4ce45e02012-12-06 10:33:10 +00008176 if (BNX2_CHIP_REV(bp) == BNX2_CHIP_REV_Ax)
David S. Millerf86e82f2008-01-21 17:15:40 -08008177 bp->flags |= BNX2_FLAG_JUMBO_BROKEN;
Michael Chanc239f272010-10-11 16:12:28 -07008178
8179 /* AER (Advanced Error Reporting) hooks */
8180 err = pci_enable_pcie_error_reporting(pdev);
Michael Chan4bb9ebc2011-01-25 22:14:51 +00008181 if (!err)
8182 bp->flags |= BNX2_FLAG_AER_ENABLED;
Michael Chanc239f272010-10-11 16:12:28 -07008183
Michael Chan883e5152007-05-03 13:25:11 -07008184 } else {
Michael Chan59b47d82006-11-19 14:10:45 -08008185 bp->pcix_cap = pci_find_capability(pdev, PCI_CAP_ID_PCIX);
8186 if (bp->pcix_cap == 0) {
8187 dev_err(&pdev->dev,
Joe Perches3a9c6a42010-02-17 15:01:51 +00008188 "Cannot find PCIX capability, aborting\n");
Michael Chan59b47d82006-11-19 14:10:45 -08008189 rc = -EIO;
8190 goto err_out_unmap;
8191 }
Michael Chan61d9e3f2009-08-21 16:20:46 +00008192 bp->flags |= BNX2_FLAG_BROKEN_STATS;
Michael Chan59b47d82006-11-19 14:10:45 -08008193 }
8194
Michael Chan4ce45e02012-12-06 10:33:10 +00008195 if (BNX2_CHIP(bp) == BNX2_CHIP_5709 &&
8196 BNX2_CHIP_REV(bp) != BNX2_CHIP_REV_Ax) {
Yijing Wang555a8422013-08-08 21:02:22 +08008197 if (pdev->msix_cap)
David S. Millerf86e82f2008-01-21 17:15:40 -08008198 bp->flags |= BNX2_FLAG_MSIX_CAP;
Michael Chanb4b36042007-12-20 19:59:30 -08008199 }
8200
Michael Chan4ce45e02012-12-06 10:33:10 +00008201 if (BNX2_CHIP_ID(bp) != BNX2_CHIP_ID_5706_A0 &&
8202 BNX2_CHIP_ID(bp) != BNX2_CHIP_ID_5706_A1) {
Yijing Wang555a8422013-08-08 21:02:22 +08008203 if (pdev->msi_cap)
David S. Millerf86e82f2008-01-21 17:15:40 -08008204 bp->flags |= BNX2_FLAG_MSI_CAP;
Michael Chan8e6a72c2007-05-03 13:24:48 -07008205 }
8206
Michael Chan40453c82007-05-03 13:19:18 -07008207 /* 5708 cannot support DMA addresses > 40-bit. */
Michael Chan4ce45e02012-12-06 10:33:10 +00008208 if (BNX2_CHIP(bp) == BNX2_CHIP_5708)
Yang Hongyang50cf1562009-04-06 19:01:14 -07008209 persist_dma_mask = dma_mask = DMA_BIT_MASK(40);
Michael Chan40453c82007-05-03 13:19:18 -07008210 else
Yang Hongyang6a355282009-04-06 19:01:13 -07008211 persist_dma_mask = dma_mask = DMA_BIT_MASK(64);
Michael Chan40453c82007-05-03 13:19:18 -07008212
8213 /* Configure DMA attributes. */
8214 if (pci_set_dma_mask(pdev, dma_mask) == 0) {
8215 dev->features |= NETIF_F_HIGHDMA;
8216 rc = pci_set_consistent_dma_mask(pdev, persist_dma_mask);
8217 if (rc) {
8218 dev_err(&pdev->dev,
Joe Perches3a9c6a42010-02-17 15:01:51 +00008219 "pci_set_consistent_dma_mask failed, aborting\n");
Michael Chan40453c82007-05-03 13:19:18 -07008220 goto err_out_unmap;
8221 }
Yang Hongyang284901a2009-04-06 19:01:15 -07008222 } else if ((rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) != 0) {
Joe Perches3a9c6a42010-02-17 15:01:51 +00008223 dev_err(&pdev->dev, "System does not support DMA, aborting\n");
Michael Chan40453c82007-05-03 13:19:18 -07008224 goto err_out_unmap;
8225 }
8226
David S. Millerf86e82f2008-01-21 17:15:40 -08008227 if (!(bp->flags & BNX2_FLAG_PCIE))
Michael Chan883e5152007-05-03 13:25:11 -07008228 bnx2_get_pci_speed(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07008229
8230 /* 5706A0 may falsely detect SERR and PERR. */
Michael Chan4ce45e02012-12-06 10:33:10 +00008231 if (BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5706_A0) {
Michael Chane503e062012-12-06 10:33:08 +00008232 reg = BNX2_RD(bp, PCI_COMMAND);
Michael Chanb6016b72005-05-26 13:03:09 -07008233 reg &= ~(PCI_COMMAND_SERR | PCI_COMMAND_PARITY);
Michael Chane503e062012-12-06 10:33:08 +00008234 BNX2_WR(bp, PCI_COMMAND, reg);
Michael Chan4ce45e02012-12-06 10:33:10 +00008235 } else if ((BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5706_A1) &&
David S. Millerf86e82f2008-01-21 17:15:40 -08008236 !(bp->flags & BNX2_FLAG_PCIX)) {
Michael Chanb6016b72005-05-26 13:03:09 -07008237
Jeff Garzik9b91cf92006-06-27 11:39:50 -04008238 dev_err(&pdev->dev,
Joe Perches3a9c6a42010-02-17 15:01:51 +00008239 "5706 A1 can only be used in a PCIX bus, aborting\n");
Michael Chanb6016b72005-05-26 13:03:09 -07008240 goto err_out_unmap;
8241 }
8242
8243 bnx2_init_nvram(bp);
8244
Michael Chan2726d6e2008-01-29 21:35:05 -08008245 reg = bnx2_reg_rd_ind(bp, BNX2_SHM_HDR_SIGNATURE);
Michael Chane3648b32005-11-04 08:51:21 -08008246
Michael Chanaefd90e2012-06-16 15:45:43 +00008247 if (bnx2_reg_rd_ind(bp, BNX2_MCP_TOE_ID) & BNX2_MCP_TOE_ID_FUNCTION_ID)
8248 bp->func = 1;
8249
Michael Chane3648b32005-11-04 08:51:21 -08008250 if ((reg & BNX2_SHM_HDR_SIGNATURE_SIG_MASK) ==
Michael Chan24cb2302007-01-25 15:49:56 -08008251 BNX2_SHM_HDR_SIGNATURE_SIG) {
Michael Chanaefd90e2012-06-16 15:45:43 +00008252 u32 off = bp->func << 2;
Michael Chan24cb2302007-01-25 15:49:56 -08008253
Michael Chan2726d6e2008-01-29 21:35:05 -08008254 bp->shmem_base = bnx2_reg_rd_ind(bp, BNX2_SHM_HDR_ADDR_0 + off);
Michael Chan24cb2302007-01-25 15:49:56 -08008255 } else
Michael Chane3648b32005-11-04 08:51:21 -08008256 bp->shmem_base = HOST_VIEW_SHMEM_BASE;
8257
Michael Chanb6016b72005-05-26 13:03:09 -07008258 /* Get the permanent MAC address. First we need to make sure the
8259 * firmware is actually running.
8260 */
Michael Chan2726d6e2008-01-29 21:35:05 -08008261 reg = bnx2_shmem_rd(bp, BNX2_DEV_INFO_SIGNATURE);
Michael Chanb6016b72005-05-26 13:03:09 -07008262
8263 if ((reg & BNX2_DEV_INFO_SIGNATURE_MAGIC_MASK) !=
8264 BNX2_DEV_INFO_SIGNATURE_MAGIC) {
Joe Perches3a9c6a42010-02-17 15:01:51 +00008265 dev_err(&pdev->dev, "Firmware not running, aborting\n");
Michael Chanb6016b72005-05-26 13:03:09 -07008266 rc = -ENODEV;
8267 goto err_out_unmap;
8268 }
8269
Michael Chan76d99062009-12-03 09:46:34 +00008270 bnx2_read_vpd_fw_ver(bp);
8271
8272 j = strlen(bp->fw_version);
Michael Chan2726d6e2008-01-29 21:35:05 -08008273 reg = bnx2_shmem_rd(bp, BNX2_DEV_INFO_BC_REV);
Michael Chan76d99062009-12-03 09:46:34 +00008274 for (i = 0; i < 3 && j < 24; i++) {
Michael Chan58fc2ea2007-07-07 22:52:02 -07008275 u8 num, k, skip0;
8276
Michael Chan76d99062009-12-03 09:46:34 +00008277 if (i == 0) {
8278 bp->fw_version[j++] = 'b';
8279 bp->fw_version[j++] = 'c';
8280 bp->fw_version[j++] = ' ';
8281 }
Michael Chan58fc2ea2007-07-07 22:52:02 -07008282 num = (u8) (reg >> (24 - (i * 8)));
8283 for (k = 100, skip0 = 1; k >= 1; num %= k, k /= 10) {
8284 if (num >= k || !skip0 || k == 1) {
8285 bp->fw_version[j++] = (num / k) + '0';
8286 skip0 = 0;
8287 }
8288 }
8289 if (i != 2)
8290 bp->fw_version[j++] = '.';
8291 }
Michael Chan2726d6e2008-01-29 21:35:05 -08008292 reg = bnx2_shmem_rd(bp, BNX2_PORT_FEATURE);
Michael Chan846f5c62007-10-10 16:16:51 -07008293 if (reg & BNX2_PORT_FEATURE_WOL_ENABLED)
8294 bp->wol = 1;
8295
8296 if (reg & BNX2_PORT_FEATURE_ASF_ENABLED) {
David S. Millerf86e82f2008-01-21 17:15:40 -08008297 bp->flags |= BNX2_FLAG_ASF_ENABLE;
Michael Chanc2d3db82007-07-16 18:26:43 -07008298
8299 for (i = 0; i < 30; i++) {
Michael Chan2726d6e2008-01-29 21:35:05 -08008300 reg = bnx2_shmem_rd(bp, BNX2_BC_STATE_CONDITION);
Michael Chanc2d3db82007-07-16 18:26:43 -07008301 if (reg & BNX2_CONDITION_MFW_RUN_MASK)
8302 break;
8303 msleep(10);
8304 }
8305 }
Michael Chan2726d6e2008-01-29 21:35:05 -08008306 reg = bnx2_shmem_rd(bp, BNX2_BC_STATE_CONDITION);
Michael Chan58fc2ea2007-07-07 22:52:02 -07008307 reg &= BNX2_CONDITION_MFW_RUN_MASK;
8308 if (reg != BNX2_CONDITION_MFW_RUN_UNKNOWN &&
8309 reg != BNX2_CONDITION_MFW_RUN_NONE) {
Michael Chan2726d6e2008-01-29 21:35:05 -08008310 u32 addr = bnx2_shmem_rd(bp, BNX2_MFW_VER_PTR);
Michael Chan58fc2ea2007-07-07 22:52:02 -07008311
Michael Chan76d99062009-12-03 09:46:34 +00008312 if (j < 32)
8313 bp->fw_version[j++] = ' ';
8314 for (i = 0; i < 3 && j < 28; i++) {
Michael Chan2726d6e2008-01-29 21:35:05 -08008315 reg = bnx2_reg_rd_ind(bp, addr + i * 4);
Michael Chan3aeb7d22011-07-20 14:55:25 +00008316 reg = be32_to_cpu(reg);
Michael Chan58fc2ea2007-07-07 22:52:02 -07008317 memcpy(&bp->fw_version[j], &reg, 4);
8318 j += 4;
8319 }
8320 }
Michael Chanb6016b72005-05-26 13:03:09 -07008321
Michael Chan2726d6e2008-01-29 21:35:05 -08008322 reg = bnx2_shmem_rd(bp, BNX2_PORT_HW_CFG_MAC_UPPER);
Michael Chanb6016b72005-05-26 13:03:09 -07008323 bp->mac_addr[0] = (u8) (reg >> 8);
8324 bp->mac_addr[1] = (u8) reg;
8325
Michael Chan2726d6e2008-01-29 21:35:05 -08008326 reg = bnx2_shmem_rd(bp, BNX2_PORT_HW_CFG_MAC_LOWER);
Michael Chanb6016b72005-05-26 13:03:09 -07008327 bp->mac_addr[2] = (u8) (reg >> 24);
8328 bp->mac_addr[3] = (u8) (reg >> 16);
8329 bp->mac_addr[4] = (u8) (reg >> 8);
8330 bp->mac_addr[5] = (u8) reg;
8331
Michael Chan2bc40782012-12-06 10:33:09 +00008332 bp->tx_ring_size = BNX2_MAX_TX_DESC_CNT;
Michael Chan932f3772006-08-15 01:39:36 -07008333 bnx2_set_rx_ring_size(bp, 255);
Michael Chanb6016b72005-05-26 13:03:09 -07008334
Michael Chancf7474a2009-08-21 16:20:48 +00008335 bp->tx_quick_cons_trip_int = 2;
Michael Chanb6016b72005-05-26 13:03:09 -07008336 bp->tx_quick_cons_trip = 20;
Michael Chancf7474a2009-08-21 16:20:48 +00008337 bp->tx_ticks_int = 18;
Michael Chanb6016b72005-05-26 13:03:09 -07008338 bp->tx_ticks = 80;
Jeff Garzik6aa20a22006-09-13 13:24:59 -04008339
Michael Chancf7474a2009-08-21 16:20:48 +00008340 bp->rx_quick_cons_trip_int = 2;
8341 bp->rx_quick_cons_trip = 12;
Michael Chanb6016b72005-05-26 13:03:09 -07008342 bp->rx_ticks_int = 18;
8343 bp->rx_ticks = 18;
8344
Michael Chan7ea69202007-07-16 18:27:10 -07008345 bp->stats_ticks = USEC_PER_SEC & BNX2_HC_STATS_TICKS_HC_STAT_TICKS;
Michael Chanb6016b72005-05-26 13:03:09 -07008346
Benjamin Liac392ab2008-09-18 16:40:49 -07008347 bp->current_interval = BNX2_TIMER_INTERVAL;
Michael Chanb6016b72005-05-26 13:03:09 -07008348
Michael Chan5b0c76a2005-11-04 08:45:49 -08008349 bp->phy_addr = 1;
8350
wangweidong8fae3072015-10-08 18:03:47 +08008351 /* allocate stats_blk */
8352 rc = bnx2_alloc_stats_blk(dev);
8353 if (rc)
8354 goto err_out_unmap;
8355
Michael Chanb6016b72005-05-26 13:03:09 -07008356 /* Disable WOL support if we are running on a SERDES chip. */
Michael Chan4ce45e02012-12-06 10:33:10 +00008357 if (BNX2_CHIP(bp) == BNX2_CHIP_5709)
Michael Chan253c8b72007-01-08 19:56:01 -08008358 bnx2_get_5709_media(bp);
Michael Chan4ce45e02012-12-06 10:33:10 +00008359 else if (BNX2_CHIP_BOND(bp) & BNX2_CHIP_BOND_SERDES_BIT)
Michael Chan583c28e2008-01-21 19:51:35 -08008360 bp->phy_flags |= BNX2_PHY_FLAG_SERDES;
Michael Chanbac0dff2006-11-19 14:15:05 -08008361
Michael Chan0d8a6572007-07-07 22:49:43 -07008362 bp->phy_port = PORT_TP;
Michael Chan583c28e2008-01-21 19:51:35 -08008363 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Michael Chan0d8a6572007-07-07 22:49:43 -07008364 bp->phy_port = PORT_FIBRE;
Michael Chan2726d6e2008-01-29 21:35:05 -08008365 reg = bnx2_shmem_rd(bp, BNX2_SHARED_HW_CFG_CONFIG);
Michael Chan846f5c62007-10-10 16:16:51 -07008366 if (!(reg & BNX2_SHARED_HW_CFG_GIG_LINK_ON_VAUX)) {
David S. Millerf86e82f2008-01-21 17:15:40 -08008367 bp->flags |= BNX2_FLAG_NO_WOL;
Michael Chan846f5c62007-10-10 16:16:51 -07008368 bp->wol = 0;
8369 }
Michael Chan4ce45e02012-12-06 10:33:10 +00008370 if (BNX2_CHIP(bp) == BNX2_CHIP_5706) {
Michael Chan38ea3682008-02-23 19:48:57 -08008371 /* Don't do parallel detect on this board because of
8372 * some board problems. The link will not go down
8373 * if we do parallel detect.
8374 */
8375 if (pdev->subsystem_vendor == PCI_VENDOR_ID_HP &&
8376 pdev->subsystem_device == 0x310c)
8377 bp->phy_flags |= BNX2_PHY_FLAG_NO_PARALLEL;
8378 } else {
Michael Chan5b0c76a2005-11-04 08:45:49 -08008379 bp->phy_addr = 2;
Michael Chan5b0c76a2005-11-04 08:45:49 -08008380 if (reg & BNX2_SHARED_HW_CFG_PHY_2_5G)
Michael Chan583c28e2008-01-21 19:51:35 -08008381 bp->phy_flags |= BNX2_PHY_FLAG_2_5G_CAPABLE;
Michael Chan5b0c76a2005-11-04 08:45:49 -08008382 }
Michael Chan4ce45e02012-12-06 10:33:10 +00008383 } else if (BNX2_CHIP(bp) == BNX2_CHIP_5706 ||
8384 BNX2_CHIP(bp) == BNX2_CHIP_5708)
Michael Chan583c28e2008-01-21 19:51:35 -08008385 bp->phy_flags |= BNX2_PHY_FLAG_CRC_FIX;
Michael Chan4ce45e02012-12-06 10:33:10 +00008386 else if (BNX2_CHIP(bp) == BNX2_CHIP_5709 &&
8387 (BNX2_CHIP_REV(bp) == BNX2_CHIP_REV_Ax ||
8388 BNX2_CHIP_REV(bp) == BNX2_CHIP_REV_Bx))
Michael Chan583c28e2008-01-21 19:51:35 -08008389 bp->phy_flags |= BNX2_PHY_FLAG_DIS_EARLY_DAC;
Michael Chanb6016b72005-05-26 13:03:09 -07008390
Michael Chan7c62e832008-07-14 22:39:03 -07008391 bnx2_init_fw_cap(bp);
8392
Michael Chan4ce45e02012-12-06 10:33:10 +00008393 if ((BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5708_A0) ||
8394 (BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5708_B0) ||
8395 (BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5708_B1) ||
Michael Chane503e062012-12-06 10:33:08 +00008396 !(BNX2_RD(bp, BNX2_PCI_CONFIG_3) & BNX2_PCI_CONFIG_3_VAUX_PRESET)) {
David S. Millerf86e82f2008-01-21 17:15:40 -08008397 bp->flags |= BNX2_FLAG_NO_WOL;
Michael Chan846f5c62007-10-10 16:16:51 -07008398 bp->wol = 0;
8399 }
Michael Chandda1e392006-01-23 16:08:14 -08008400
Michael Chan6d5e85c2013-08-06 15:50:08 -07008401 if (bp->flags & BNX2_FLAG_NO_WOL)
8402 device_set_wakeup_capable(&bp->pdev->dev, false);
8403 else
8404 device_set_wakeup_enable(&bp->pdev->dev, bp->wol);
8405
Michael Chan4ce45e02012-12-06 10:33:10 +00008406 if (BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5706_A0) {
Michael Chanb6016b72005-05-26 13:03:09 -07008407 bp->tx_quick_cons_trip_int =
8408 bp->tx_quick_cons_trip;
8409 bp->tx_ticks_int = bp->tx_ticks;
8410 bp->rx_quick_cons_trip_int =
8411 bp->rx_quick_cons_trip;
8412 bp->rx_ticks_int = bp->rx_ticks;
8413 bp->comp_prod_trip_int = bp->comp_prod_trip;
8414 bp->com_ticks_int = bp->com_ticks;
8415 bp->cmd_ticks_int = bp->cmd_ticks;
8416 }
8417
Michael Chanf9317a42006-09-29 17:06:23 -07008418 /* Disable MSI on 5706 if AMD 8132 bridge is found.
8419 *
8420 * MSI is defined to be 32-bit write. The 5706 does 64-bit MSI writes
8421 * with byte enables disabled on the unused 32-bit word. This is legal
8422 * but causes problems on the AMD 8132 which will eventually stop
8423 * responding after a while.
8424 *
8425 * AMD believes this incompatibility is unique to the 5706, and
Michael Ellerman88187df2007-01-25 19:34:07 +11008426 * prefers to locally disable MSI rather than globally disabling it.
Michael Chanf9317a42006-09-29 17:06:23 -07008427 */
Michael Chan4ce45e02012-12-06 10:33:10 +00008428 if (BNX2_CHIP(bp) == BNX2_CHIP_5706 && disable_msi == 0) {
Michael Chanf9317a42006-09-29 17:06:23 -07008429 struct pci_dev *amd_8132 = NULL;
8430
8431 while ((amd_8132 = pci_get_device(PCI_VENDOR_ID_AMD,
8432 PCI_DEVICE_ID_AMD_8132_BRIDGE,
8433 amd_8132))) {
Michael Chanf9317a42006-09-29 17:06:23 -07008434
Auke Kok44c10132007-06-08 15:46:36 -07008435 if (amd_8132->revision >= 0x10 &&
8436 amd_8132->revision <= 0x13) {
Michael Chanf9317a42006-09-29 17:06:23 -07008437 disable_msi = 1;
8438 pci_dev_put(amd_8132);
8439 break;
8440 }
8441 }
8442 }
8443
Michael Chandeaf3912007-07-07 22:48:00 -07008444 bnx2_set_default_link(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07008445 bp->req_flow_ctrl = FLOW_CTRL_RX | FLOW_CTRL_TX;
8446
Michael Chancd339a02005-08-25 15:35:24 -07008447 init_timer(&bp->timer);
Benjamin Liac392ab2008-09-18 16:40:49 -07008448 bp->timer.expires = RUN_AT(BNX2_TIMER_INTERVAL);
Michael Chancd339a02005-08-25 15:35:24 -07008449 bp->timer.data = (unsigned long) bp;
8450 bp->timer.function = bnx2_timer;
8451
Michael Chan7625eb22011-06-08 19:29:36 +00008452#ifdef BCM_CNIC
Michael Chan41c21782011-07-13 17:24:22 +00008453 if (bnx2_shmem_rd(bp, BNX2_ISCSI_INITIATOR) & BNX2_ISCSI_INITIATOR_EN)
8454 bp->cnic_eth_dev.max_iscsi_conn =
8455 (bnx2_shmem_rd(bp, BNX2_ISCSI_MAX_CONN) &
8456 BNX2_ISCSI_MAX_CONN_MASK) >> BNX2_ISCSI_MAX_CONN_SHIFT;
Michael Chan4bd9b0ff2012-12-06 10:33:12 +00008457 bp->cnic_probe = bnx2_cnic_probe;
Michael Chan7625eb22011-06-08 19:29:36 +00008458#endif
Michael Chanc239f272010-10-11 16:12:28 -07008459 pci_save_state(pdev);
8460
Michael Chanb6016b72005-05-26 13:03:09 -07008461 return 0;
8462
8463err_out_unmap:
Michael Chan4bb9ebc2011-01-25 22:14:51 +00008464 if (bp->flags & BNX2_FLAG_AER_ENABLED) {
Michael Chanc239f272010-10-11 16:12:28 -07008465 pci_disable_pcie_error_reporting(pdev);
Michael Chan4bb9ebc2011-01-25 22:14:51 +00008466 bp->flags &= ~BNX2_FLAG_AER_ENABLED;
8467 }
Michael Chanc239f272010-10-11 16:12:28 -07008468
Francois Romieuc0357e92012-03-09 14:51:47 +01008469 pci_iounmap(pdev, bp->regview);
8470 bp->regview = NULL;
Michael Chanb6016b72005-05-26 13:03:09 -07008471
8472err_out_release:
8473 pci_release_regions(pdev);
8474
8475err_out_disable:
8476 pci_disable_device(pdev);
Michael Chanb6016b72005-05-26 13:03:09 -07008477
8478err_out:
wangweidong3703ebe2015-10-13 10:05:19 +08008479 kfree(bp->temp_stats_blk);
8480
Michael Chanb6016b72005-05-26 13:03:09 -07008481 return rc;
8482}
8483
Bill Pembertoncfd95a62012-12-03 09:22:58 -05008484static char *
Michael Chan883e5152007-05-03 13:25:11 -07008485bnx2_bus_string(struct bnx2 *bp, char *str)
8486{
8487 char *s = str;
8488
David S. Millerf86e82f2008-01-21 17:15:40 -08008489 if (bp->flags & BNX2_FLAG_PCIE) {
Michael Chan883e5152007-05-03 13:25:11 -07008490 s += sprintf(s, "PCI Express");
8491 } else {
8492 s += sprintf(s, "PCI");
David S. Millerf86e82f2008-01-21 17:15:40 -08008493 if (bp->flags & BNX2_FLAG_PCIX)
Michael Chan883e5152007-05-03 13:25:11 -07008494 s += sprintf(s, "-X");
David S. Millerf86e82f2008-01-21 17:15:40 -08008495 if (bp->flags & BNX2_FLAG_PCI_32BIT)
Michael Chan883e5152007-05-03 13:25:11 -07008496 s += sprintf(s, " 32-bit");
8497 else
8498 s += sprintf(s, " 64-bit");
8499 s += sprintf(s, " %dMHz", bp->bus_speed_mhz);
8500 }
8501 return str;
8502}
8503
Michael Chanf048fa92010-06-01 15:05:36 +00008504static void
8505bnx2_del_napi(struct bnx2 *bp)
8506{
8507 int i;
8508
8509 for (i = 0; i < bp->irq_nvecs; i++)
8510 netif_napi_del(&bp->bnx2_napi[i].napi);
8511}
8512
8513static void
Michael Chan35efa7c2007-12-20 19:56:37 -08008514bnx2_init_napi(struct bnx2 *bp)
8515{
Michael Chanb4b36042007-12-20 19:59:30 -08008516 int i;
Michael Chan35efa7c2007-12-20 19:56:37 -08008517
Benjamin Li4327ba42010-03-23 13:13:11 +00008518 for (i = 0; i < bp->irq_nvecs; i++) {
Michael Chan35e90102008-06-19 16:37:42 -07008519 struct bnx2_napi *bnapi = &bp->bnx2_napi[i];
8520 int (*poll)(struct napi_struct *, int);
8521
8522 if (i == 0)
8523 poll = bnx2_poll;
8524 else
Michael Chanf0ea2e62008-06-19 16:41:57 -07008525 poll = bnx2_poll_msix;
Michael Chan35e90102008-06-19 16:37:42 -07008526
8527 netif_napi_add(bp->dev, &bp->bnx2_napi[i].napi, poll, 64);
Michael Chanb4b36042007-12-20 19:59:30 -08008528 bnapi->bp = bp;
8529 }
Michael Chan35efa7c2007-12-20 19:56:37 -08008530}
8531
Stephen Hemminger0421eae2008-11-21 17:31:27 -08008532static const struct net_device_ops bnx2_netdev_ops = {
8533 .ndo_open = bnx2_open,
8534 .ndo_start_xmit = bnx2_start_xmit,
8535 .ndo_stop = bnx2_close,
Eric Dumazet5d07bf22010-07-08 04:08:43 +00008536 .ndo_get_stats64 = bnx2_get_stats64,
Stephen Hemminger0421eae2008-11-21 17:31:27 -08008537 .ndo_set_rx_mode = bnx2_set_rx_mode,
8538 .ndo_do_ioctl = bnx2_ioctl,
8539 .ndo_validate_addr = eth_validate_addr,
8540 .ndo_set_mac_address = bnx2_change_mac_addr,
8541 .ndo_change_mtu = bnx2_change_mtu,
Michał Mirosław8d7dfc22011-04-10 04:47:46 +00008542 .ndo_set_features = bnx2_set_features,
Stephen Hemminger0421eae2008-11-21 17:31:27 -08008543 .ndo_tx_timeout = bnx2_tx_timeout,
Alexey Dobriyan257ddbd2010-01-27 10:17:41 +00008544#ifdef CONFIG_NET_POLL_CONTROLLER
Stephen Hemminger0421eae2008-11-21 17:31:27 -08008545 .ndo_poll_controller = poll_bnx2,
8546#endif
8547};
8548
Bill Pembertoncfd95a62012-12-03 09:22:58 -05008549static int
Michael Chanb6016b72005-05-26 13:03:09 -07008550bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
8551{
8552 static int version_printed = 0;
Francois Romieuc0357e92012-03-09 14:51:47 +01008553 struct net_device *dev;
Michael Chanb6016b72005-05-26 13:03:09 -07008554 struct bnx2 *bp;
Joe Perches0795af52007-10-03 17:59:30 -07008555 int rc;
Michael Chan883e5152007-05-03 13:25:11 -07008556 char str[40];
Michael Chanb6016b72005-05-26 13:03:09 -07008557
8558 if (version_printed++ == 0)
Joe Perches3a9c6a42010-02-17 15:01:51 +00008559 pr_info("%s", version);
Michael Chanb6016b72005-05-26 13:03:09 -07008560
8561 /* dev zeroed in init_etherdev */
Benjamin Li706bf242008-07-18 17:55:11 -07008562 dev = alloc_etherdev_mq(sizeof(*bp), TX_MAX_RINGS);
Michael Chanb6016b72005-05-26 13:03:09 -07008563 if (!dev)
8564 return -ENOMEM;
8565
8566 rc = bnx2_init_board(pdev, dev);
Francois Romieuc0357e92012-03-09 14:51:47 +01008567 if (rc < 0)
8568 goto err_free;
Michael Chanb6016b72005-05-26 13:03:09 -07008569
Stephen Hemminger0421eae2008-11-21 17:31:27 -08008570 dev->netdev_ops = &bnx2_netdev_ops;
Michael Chanb6016b72005-05-26 13:03:09 -07008571 dev->watchdog_timeo = TX_TIMEOUT;
Michael Chanb6016b72005-05-26 13:03:09 -07008572 dev->ethtool_ops = &bnx2_ethtool_ops;
Michael Chanb6016b72005-05-26 13:03:09 -07008573
Michael Chan972ec0d2006-01-23 16:12:43 -08008574 bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07008575
Michael Chan1b2f9222007-05-03 13:20:19 -07008576 pci_set_drvdata(pdev, dev);
8577
Joe Perchesd458cdf2013-10-01 19:04:40 -07008578 memcpy(dev->dev_addr, bp->mac_addr, ETH_ALEN);
Michael Chan1b2f9222007-05-03 13:20:19 -07008579
Michał Mirosław8d7dfc22011-04-10 04:47:46 +00008580 dev->hw_features = NETIF_F_IP_CSUM | NETIF_F_SG |
8581 NETIF_F_TSO | NETIF_F_TSO_ECN |
8582 NETIF_F_RXHASH | NETIF_F_RXCSUM;
8583
Michael Chan4ce45e02012-12-06 10:33:10 +00008584 if (BNX2_CHIP(bp) == BNX2_CHIP_5709)
Michał Mirosław8d7dfc22011-04-10 04:47:46 +00008585 dev->hw_features |= NETIF_F_IPV6_CSUM | NETIF_F_TSO6;
8586
8587 dev->vlan_features = dev->hw_features;
Patrick McHardyf6469682013-04-19 02:04:27 +00008588 dev->hw_features |= NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX;
Michał Mirosław8d7dfc22011-04-10 04:47:46 +00008589 dev->features |= dev->hw_features;
Jiri Pirko01789342011-08-16 06:29:00 +00008590 dev->priv_flags |= IFF_UNICAST_FLT;
Michał Mirosław8d7dfc22011-04-10 04:47:46 +00008591
Ivan Vecera26caa342015-02-26 14:48:07 +01008592 if (!(bp->flags & BNX2_FLAG_CAN_KEEP_VLAN))
8593 dev->hw_features &= ~NETIF_F_HW_VLAN_CTAG_RX;
8594
Michael Chanb6016b72005-05-26 13:03:09 -07008595 if ((rc = register_netdev(dev))) {
Jeff Garzik9b91cf92006-06-27 11:39:50 -04008596 dev_err(&pdev->dev, "Cannot register net device\n");
Michael Chan57579f72009-04-04 16:51:14 -07008597 goto error;
Michael Chanb6016b72005-05-26 13:03:09 -07008598 }
8599
Francois Romieuc0357e92012-03-09 14:51:47 +01008600 netdev_info(dev, "%s (%c%d) %s found at mem %lx, IRQ %d, "
8601 "node addr %pM\n", board_info[ent->driver_data].name,
Michael Chan4ce45e02012-12-06 10:33:10 +00008602 ((BNX2_CHIP_ID(bp) & 0xf000) >> 12) + 'A',
8603 ((BNX2_CHIP_ID(bp) & 0x0ff0) >> 4),
Francois Romieuc0357e92012-03-09 14:51:47 +01008604 bnx2_bus_string(bp, str), (long)pci_resource_start(pdev, 0),
8605 pdev->irq, dev->dev_addr);
Michael Chanb6016b72005-05-26 13:03:09 -07008606
Michael Chanb6016b72005-05-26 13:03:09 -07008607 return 0;
Michael Chan57579f72009-04-04 16:51:14 -07008608
8609error:
Michael Chanfda4d852012-12-11 18:24:20 -08008610 pci_iounmap(pdev, bp->regview);
Michael Chan57579f72009-04-04 16:51:14 -07008611 pci_release_regions(pdev);
8612 pci_disable_device(pdev);
Francois Romieuc0357e92012-03-09 14:51:47 +01008613err_free:
wangweidong8fae3072015-10-08 18:03:47 +08008614 bnx2_free_stats_blk(dev);
Michael Chan57579f72009-04-04 16:51:14 -07008615 free_netdev(dev);
8616 return rc;
Michael Chanb6016b72005-05-26 13:03:09 -07008617}
8618
Bill Pembertoncfd95a62012-12-03 09:22:58 -05008619static void
Michael Chanb6016b72005-05-26 13:03:09 -07008620bnx2_remove_one(struct pci_dev *pdev)
8621{
8622 struct net_device *dev = pci_get_drvdata(pdev);
Michael Chan972ec0d2006-01-23 16:12:43 -08008623 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07008624
8625 unregister_netdev(dev);
8626
Neil Horman8333a462011-04-26 10:30:11 +00008627 del_timer_sync(&bp->timer);
Michael Chancd634012011-07-15 06:53:58 +00008628 cancel_work_sync(&bp->reset_task);
Neil Horman8333a462011-04-26 10:30:11 +00008629
Francois Romieuc0357e92012-03-09 14:51:47 +01008630 pci_iounmap(bp->pdev, bp->regview);
Michael Chanb6016b72005-05-26 13:03:09 -07008631
wangweidong8fae3072015-10-08 18:03:47 +08008632 bnx2_free_stats_blk(dev);
Michael Chan354fcd72010-01-17 07:30:44 +00008633 kfree(bp->temp_stats_blk);
8634
Michael Chan4bb9ebc2011-01-25 22:14:51 +00008635 if (bp->flags & BNX2_FLAG_AER_ENABLED) {
Michael Chanc239f272010-10-11 16:12:28 -07008636 pci_disable_pcie_error_reporting(pdev);
Michael Chan4bb9ebc2011-01-25 22:14:51 +00008637 bp->flags &= ~BNX2_FLAG_AER_ENABLED;
8638 }
John Feeneycd709aa2010-08-22 17:45:53 +00008639
françois romieu7880b722011-09-30 00:36:52 +00008640 bnx2_release_firmware(bp);
8641
Michael Chanc239f272010-10-11 16:12:28 -07008642 free_netdev(dev);
John Feeneycd709aa2010-08-22 17:45:53 +00008643
Michael Chanb6016b72005-05-26 13:03:09 -07008644 pci_release_regions(pdev);
8645 pci_disable_device(pdev);
Michael Chanb6016b72005-05-26 13:03:09 -07008646}
8647
Daniel J Blueman77d149c2014-04-11 16:14:26 +08008648#ifdef CONFIG_PM_SLEEP
Michael Chanb6016b72005-05-26 13:03:09 -07008649static int
Michael Chan28fb4eb2013-08-06 15:50:10 -07008650bnx2_suspend(struct device *device)
Michael Chanb6016b72005-05-26 13:03:09 -07008651{
Michael Chan28fb4eb2013-08-06 15:50:10 -07008652 struct pci_dev *pdev = to_pci_dev(device);
Michael Chanb6016b72005-05-26 13:03:09 -07008653 struct net_device *dev = pci_get_drvdata(pdev);
Michael Chan972ec0d2006-01-23 16:12:43 -08008654 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07008655
Michael Chan28fb4eb2013-08-06 15:50:10 -07008656 if (netif_running(dev)) {
8657 cancel_work_sync(&bp->reset_task);
8658 bnx2_netif_stop(bp, true);
8659 netif_device_detach(dev);
8660 del_timer_sync(&bp->timer);
8661 bnx2_shutdown_chip(bp);
8662 __bnx2_free_irq(bp);
8663 bnx2_free_skbs(bp);
8664 }
8665 bnx2_setup_wol(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07008666 return 0;
8667}
8668
8669static int
Michael Chan28fb4eb2013-08-06 15:50:10 -07008670bnx2_resume(struct device *device)
Michael Chanb6016b72005-05-26 13:03:09 -07008671{
Michael Chan28fb4eb2013-08-06 15:50:10 -07008672 struct pci_dev *pdev = to_pci_dev(device);
Michael Chanb6016b72005-05-26 13:03:09 -07008673 struct net_device *dev = pci_get_drvdata(pdev);
Michael Chan972ec0d2006-01-23 16:12:43 -08008674 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07008675
8676 if (!netif_running(dev))
8677 return 0;
8678
Pavel Machek829ca9a2005-09-03 15:56:56 -07008679 bnx2_set_power_state(bp, PCI_D0);
Michael Chanb6016b72005-05-26 13:03:09 -07008680 netif_device_attach(dev);
Michael Chan28fb4eb2013-08-06 15:50:10 -07008681 bnx2_request_irq(bp);
Michael Chan9a120bc2008-05-16 22:17:45 -07008682 bnx2_init_nic(bp, 1);
Michael Chan212f9932010-04-27 11:28:10 +00008683 bnx2_netif_start(bp, true);
Michael Chanb6016b72005-05-26 13:03:09 -07008684 return 0;
8685}
8686
Michael Chan28fb4eb2013-08-06 15:50:10 -07008687static SIMPLE_DEV_PM_OPS(bnx2_pm_ops, bnx2_suspend, bnx2_resume);
8688#define BNX2_PM_OPS (&bnx2_pm_ops)
8689
8690#else
8691
8692#define BNX2_PM_OPS NULL
8693
8694#endif /* CONFIG_PM_SLEEP */
Wendy Xiong6ff2da42008-05-16 22:18:21 -07008695/**
8696 * bnx2_io_error_detected - called when PCI error is detected
8697 * @pdev: Pointer to PCI device
8698 * @state: The current pci connection state
8699 *
8700 * This function is called after a PCI bus error affecting
8701 * this device has been detected.
8702 */
8703static pci_ers_result_t bnx2_io_error_detected(struct pci_dev *pdev,
8704 pci_channel_state_t state)
8705{
8706 struct net_device *dev = pci_get_drvdata(pdev);
8707 struct bnx2 *bp = netdev_priv(dev);
8708
8709 rtnl_lock();
8710 netif_device_detach(dev);
8711
Dean Nelson2ec3de22009-07-31 09:13:18 +00008712 if (state == pci_channel_io_perm_failure) {
8713 rtnl_unlock();
8714 return PCI_ERS_RESULT_DISCONNECT;
8715 }
8716
Wendy Xiong6ff2da42008-05-16 22:18:21 -07008717 if (netif_running(dev)) {
Michael Chan212f9932010-04-27 11:28:10 +00008718 bnx2_netif_stop(bp, true);
Wendy Xiong6ff2da42008-05-16 22:18:21 -07008719 del_timer_sync(&bp->timer);
8720 bnx2_reset_nic(bp, BNX2_DRV_MSG_CODE_RESET);
8721 }
8722
8723 pci_disable_device(pdev);
8724 rtnl_unlock();
8725
8726 /* Request a slot slot reset. */
8727 return PCI_ERS_RESULT_NEED_RESET;
8728}
8729
8730/**
8731 * bnx2_io_slot_reset - called after the pci bus has been reset.
8732 * @pdev: Pointer to PCI device
8733 *
8734 * Restart the card from scratch, as if from a cold-boot.
8735 */
8736static pci_ers_result_t bnx2_io_slot_reset(struct pci_dev *pdev)
8737{
8738 struct net_device *dev = pci_get_drvdata(pdev);
8739 struct bnx2 *bp = netdev_priv(dev);
Michael Chan02481bc2013-08-06 15:50:07 -07008740 pci_ers_result_t result = PCI_ERS_RESULT_DISCONNECT;
8741 int err = 0;
Wendy Xiong6ff2da42008-05-16 22:18:21 -07008742
8743 rtnl_lock();
8744 if (pci_enable_device(pdev)) {
8745 dev_err(&pdev->dev,
Joe Perches3a9c6a42010-02-17 15:01:51 +00008746 "Cannot re-enable PCI device after reset\n");
John Feeneycd709aa2010-08-22 17:45:53 +00008747 } else {
8748 pci_set_master(pdev);
8749 pci_restore_state(pdev);
8750 pci_save_state(pdev);
Wendy Xiong6ff2da42008-05-16 22:18:21 -07008751
Michael Chan25bfb1d2013-08-06 15:50:11 -07008752 if (netif_running(dev))
Michael Chan02481bc2013-08-06 15:50:07 -07008753 err = bnx2_init_nic(bp, 1);
Michael Chan25bfb1d2013-08-06 15:50:11 -07008754
Michael Chan02481bc2013-08-06 15:50:07 -07008755 if (!err)
8756 result = PCI_ERS_RESULT_RECOVERED;
8757 }
8758
8759 if (result != PCI_ERS_RESULT_RECOVERED && netif_running(dev)) {
8760 bnx2_napi_enable(bp);
8761 dev_close(dev);
Wendy Xiong6ff2da42008-05-16 22:18:21 -07008762 }
Wendy Xiong6ff2da42008-05-16 22:18:21 -07008763 rtnl_unlock();
John Feeneycd709aa2010-08-22 17:45:53 +00008764
Michael Chan4bb9ebc2011-01-25 22:14:51 +00008765 if (!(bp->flags & BNX2_FLAG_AER_ENABLED))
Michael Chanc239f272010-10-11 16:12:28 -07008766 return result;
8767
John Feeneycd709aa2010-08-22 17:45:53 +00008768 err = pci_cleanup_aer_uncorrect_error_status(pdev);
8769 if (err) {
8770 dev_err(&pdev->dev,
8771 "pci_cleanup_aer_uncorrect_error_status failed 0x%0x\n",
8772 err); /* non-fatal, continue */
8773 }
8774
8775 return result;
Wendy Xiong6ff2da42008-05-16 22:18:21 -07008776}
8777
8778/**
8779 * bnx2_io_resume - called when traffic can start flowing again.
8780 * @pdev: Pointer to PCI device
8781 *
8782 * This callback is called when the error recovery driver tells us that
8783 * its OK to resume normal operation.
8784 */
8785static void bnx2_io_resume(struct pci_dev *pdev)
8786{
8787 struct net_device *dev = pci_get_drvdata(pdev);
8788 struct bnx2 *bp = netdev_priv(dev);
8789
8790 rtnl_lock();
8791 if (netif_running(dev))
Michael Chan212f9932010-04-27 11:28:10 +00008792 bnx2_netif_start(bp, true);
Wendy Xiong6ff2da42008-05-16 22:18:21 -07008793
8794 netif_device_attach(dev);
8795 rtnl_unlock();
8796}
8797
Michael Chan25bfb1d2013-08-06 15:50:11 -07008798static void bnx2_shutdown(struct pci_dev *pdev)
8799{
8800 struct net_device *dev = pci_get_drvdata(pdev);
8801 struct bnx2 *bp;
8802
8803 if (!dev)
8804 return;
8805
8806 bp = netdev_priv(dev);
8807 if (!bp)
8808 return;
8809
8810 rtnl_lock();
8811 if (netif_running(dev))
8812 dev_close(bp->dev);
8813
8814 if (system_state == SYSTEM_POWER_OFF)
8815 bnx2_set_power_state(bp, PCI_D3hot);
8816
8817 rtnl_unlock();
8818}
8819
Michael Chanfda4d852012-12-11 18:24:20 -08008820static const struct pci_error_handlers bnx2_err_handler = {
Wendy Xiong6ff2da42008-05-16 22:18:21 -07008821 .error_detected = bnx2_io_error_detected,
8822 .slot_reset = bnx2_io_slot_reset,
8823 .resume = bnx2_io_resume,
8824};
8825
Michael Chanb6016b72005-05-26 13:03:09 -07008826static struct pci_driver bnx2_pci_driver = {
Peter Hagervall14ab9b82005-08-10 14:18:16 -07008827 .name = DRV_MODULE_NAME,
8828 .id_table = bnx2_pci_tbl,
8829 .probe = bnx2_init_one,
Bill Pembertoncfd95a62012-12-03 09:22:58 -05008830 .remove = bnx2_remove_one,
Michael Chan28fb4eb2013-08-06 15:50:10 -07008831 .driver.pm = BNX2_PM_OPS,
Wendy Xiong6ff2da42008-05-16 22:18:21 -07008832 .err_handler = &bnx2_err_handler,
Michael Chan25bfb1d2013-08-06 15:50:11 -07008833 .shutdown = bnx2_shutdown,
Michael Chanb6016b72005-05-26 13:03:09 -07008834};
8835
Peter Hüwe5a4123f2013-05-21 12:58:05 +00008836module_pci_driver(bnx2_pci_driver);