blob: c55797291b5750418d336e4f8695a77c05075237 [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{
Ivan Vecera6bc80622016-10-18 08:16:03 +0200274 unsigned long flags;
Michael Chan1b8227c2007-05-03 13:24:05 -0700275 u32 val;
276
Ivan Vecera6bc80622016-10-18 08:16:03 +0200277 spin_lock_irqsave(&bp->indirect_lock, flags);
Michael Chane503e062012-12-06 10:33:08 +0000278 BNX2_WR(bp, BNX2_PCICFG_REG_WINDOW_ADDRESS, offset);
279 val = BNX2_RD(bp, BNX2_PCICFG_REG_WINDOW);
Ivan Vecera6bc80622016-10-18 08:16:03 +0200280 spin_unlock_irqrestore(&bp->indirect_lock, flags);
Michael Chan1b8227c2007-05-03 13:24:05 -0700281 return val;
Michael Chanb6016b72005-05-26 13:03:09 -0700282}
283
284static void
285bnx2_reg_wr_ind(struct bnx2 *bp, u32 offset, u32 val)
286{
Ivan Vecera6bc80622016-10-18 08:16:03 +0200287 unsigned long flags;
288
289 spin_lock_irqsave(&bp->indirect_lock, flags);
Michael Chane503e062012-12-06 10:33:08 +0000290 BNX2_WR(bp, BNX2_PCICFG_REG_WINDOW_ADDRESS, offset);
291 BNX2_WR(bp, BNX2_PCICFG_REG_WINDOW, val);
Ivan Vecera6bc80622016-10-18 08:16:03 +0200292 spin_unlock_irqrestore(&bp->indirect_lock, flags);
Michael Chanb6016b72005-05-26 13:03:09 -0700293}
294
295static void
Michael Chan2726d6e2008-01-29 21:35:05 -0800296bnx2_shmem_wr(struct bnx2 *bp, u32 offset, u32 val)
297{
298 bnx2_reg_wr_ind(bp, bp->shmem_base + offset, val);
299}
300
301static u32
302bnx2_shmem_rd(struct bnx2 *bp, u32 offset)
303{
Eric Dumazet807540b2010-09-23 05:40:09 +0000304 return bnx2_reg_rd_ind(bp, bp->shmem_base + offset);
Michael Chan2726d6e2008-01-29 21:35:05 -0800305}
306
307static void
Michael Chanb6016b72005-05-26 13:03:09 -0700308bnx2_ctx_wr(struct bnx2 *bp, u32 cid_addr, u32 offset, u32 val)
309{
Ivan Vecera6bc80622016-10-18 08:16:03 +0200310 unsigned long flags;
311
Michael Chanb6016b72005-05-26 13:03:09 -0700312 offset += cid_addr;
Ivan Vecera6bc80622016-10-18 08:16:03 +0200313 spin_lock_irqsave(&bp->indirect_lock, flags);
Michael Chan4ce45e02012-12-06 10:33:10 +0000314 if (BNX2_CHIP(bp) == BNX2_CHIP_5709) {
Michael Chan59b47d82006-11-19 14:10:45 -0800315 int i;
316
Michael Chane503e062012-12-06 10:33:08 +0000317 BNX2_WR(bp, BNX2_CTX_CTX_DATA, val);
318 BNX2_WR(bp, BNX2_CTX_CTX_CTRL,
319 offset | BNX2_CTX_CTX_CTRL_WRITE_REQ);
Michael Chan59b47d82006-11-19 14:10:45 -0800320 for (i = 0; i < 5; i++) {
Michael Chane503e062012-12-06 10:33:08 +0000321 val = BNX2_RD(bp, BNX2_CTX_CTX_CTRL);
Michael Chan59b47d82006-11-19 14:10:45 -0800322 if ((val & BNX2_CTX_CTX_CTRL_WRITE_REQ) == 0)
323 break;
324 udelay(5);
325 }
326 } else {
Michael Chane503e062012-12-06 10:33:08 +0000327 BNX2_WR(bp, BNX2_CTX_DATA_ADR, offset);
328 BNX2_WR(bp, BNX2_CTX_DATA, val);
Michael Chan59b47d82006-11-19 14:10:45 -0800329 }
Ivan Vecera6bc80622016-10-18 08:16:03 +0200330 spin_unlock_irqrestore(&bp->indirect_lock, flags);
Michael Chanb6016b72005-05-26 13:03:09 -0700331}
332
Michael Chan4edd4732009-06-08 18:14:42 -0700333#ifdef BCM_CNIC
334static int
335bnx2_drv_ctl(struct net_device *dev, struct drv_ctl_info *info)
336{
337 struct bnx2 *bp = netdev_priv(dev);
338 struct drv_ctl_io *io = &info->data.io;
339
340 switch (info->cmd) {
341 case DRV_CTL_IO_WR_CMD:
342 bnx2_reg_wr_ind(bp, io->offset, io->data);
343 break;
344 case DRV_CTL_IO_RD_CMD:
345 io->data = bnx2_reg_rd_ind(bp, io->offset);
346 break;
347 case DRV_CTL_CTX_WR_CMD:
348 bnx2_ctx_wr(bp, io->cid_addr, io->offset, io->data);
349 break;
350 default:
351 return -EINVAL;
352 }
353 return 0;
354}
355
356static void bnx2_setup_cnic_irq_info(struct bnx2 *bp)
357{
358 struct cnic_eth_dev *cp = &bp->cnic_eth_dev;
359 struct bnx2_napi *bnapi = &bp->bnx2_napi[0];
360 int sb_id;
361
362 if (bp->flags & BNX2_FLAG_USING_MSIX) {
363 cp->drv_state |= CNIC_DRV_STATE_USING_MSIX;
364 bnapi->cnic_present = 0;
365 sb_id = bp->irq_nvecs;
366 cp->irq_arr[0].irq_flags |= CNIC_IRQ_FL_MSIX;
367 } else {
368 cp->drv_state &= ~CNIC_DRV_STATE_USING_MSIX;
369 bnapi->cnic_tag = bnapi->last_status_idx;
370 bnapi->cnic_present = 1;
371 sb_id = 0;
372 cp->irq_arr[0].irq_flags &= ~CNIC_IRQ_FL_MSIX;
373 }
374
375 cp->irq_arr[0].vector = bp->irq_tbl[sb_id].vector;
376 cp->irq_arr[0].status_blk = (void *)
377 ((unsigned long) bnapi->status_blk.msi +
378 (BNX2_SBLK_MSIX_ALIGN_SIZE * sb_id));
379 cp->irq_arr[0].status_blk_num = sb_id;
380 cp->num_irq = 1;
381}
382
383static int bnx2_register_cnic(struct net_device *dev, struct cnic_ops *ops,
384 void *data)
385{
386 struct bnx2 *bp = netdev_priv(dev);
387 struct cnic_eth_dev *cp = &bp->cnic_eth_dev;
388
389 if (ops == NULL)
390 return -EINVAL;
391
392 if (cp->drv_state & CNIC_DRV_STATE_REGD)
393 return -EBUSY;
394
Michael Chan41c21782011-07-13 17:24:22 +0000395 if (!bnx2_reg_rd_ind(bp, BNX2_FW_MAX_ISCSI_CONN))
396 return -ENODEV;
397
Michael Chan4edd4732009-06-08 18:14:42 -0700398 bp->cnic_data = data;
399 rcu_assign_pointer(bp->cnic_ops, ops);
400
401 cp->num_irq = 0;
402 cp->drv_state = CNIC_DRV_STATE_REGD;
403
404 bnx2_setup_cnic_irq_info(bp);
405
406 return 0;
407}
408
409static int bnx2_unregister_cnic(struct net_device *dev)
410{
411 struct bnx2 *bp = netdev_priv(dev);
412 struct bnx2_napi *bnapi = &bp->bnx2_napi[0];
413 struct cnic_eth_dev *cp = &bp->cnic_eth_dev;
414
Michael Chanc5a88952009-08-14 15:49:45 +0000415 mutex_lock(&bp->cnic_lock);
Michael Chan4edd4732009-06-08 18:14:42 -0700416 cp->drv_state = 0;
417 bnapi->cnic_present = 0;
Eric Dumazet2cfa5a02011-11-23 07:09:32 +0000418 RCU_INIT_POINTER(bp->cnic_ops, NULL);
Michael Chanc5a88952009-08-14 15:49:45 +0000419 mutex_unlock(&bp->cnic_lock);
Michael Chan4edd4732009-06-08 18:14:42 -0700420 synchronize_rcu();
421 return 0;
422}
423
stephen hemminger61c2fc42013-04-10 10:53:40 +0000424static struct cnic_eth_dev *bnx2_cnic_probe(struct net_device *dev)
Michael Chan4edd4732009-06-08 18:14:42 -0700425{
426 struct bnx2 *bp = netdev_priv(dev);
427 struct cnic_eth_dev *cp = &bp->cnic_eth_dev;
428
Michael Chan7625eb22011-06-08 19:29:36 +0000429 if (!cp->max_iscsi_conn)
430 return NULL;
431
Michael Chan4edd4732009-06-08 18:14:42 -0700432 cp->drv_owner = THIS_MODULE;
433 cp->chip_id = bp->chip_id;
434 cp->pdev = bp->pdev;
435 cp->io_base = bp->regview;
436 cp->drv_ctl = bnx2_drv_ctl;
437 cp->drv_register_cnic = bnx2_register_cnic;
438 cp->drv_unregister_cnic = bnx2_unregister_cnic;
439
440 return cp;
441}
Michael Chan4edd4732009-06-08 18:14:42 -0700442
443static void
444bnx2_cnic_stop(struct bnx2 *bp)
445{
446 struct cnic_ops *c_ops;
447 struct cnic_ctl_info info;
448
Michael Chanc5a88952009-08-14 15:49:45 +0000449 mutex_lock(&bp->cnic_lock);
Eric Dumazet13707f92011-01-26 19:28:23 +0000450 c_ops = rcu_dereference_protected(bp->cnic_ops,
451 lockdep_is_held(&bp->cnic_lock));
Michael Chan4edd4732009-06-08 18:14:42 -0700452 if (c_ops) {
453 info.cmd = CNIC_CTL_STOP_CMD;
454 c_ops->cnic_ctl(bp->cnic_data, &info);
455 }
Michael Chanc5a88952009-08-14 15:49:45 +0000456 mutex_unlock(&bp->cnic_lock);
Michael Chan4edd4732009-06-08 18:14:42 -0700457}
458
459static void
460bnx2_cnic_start(struct bnx2 *bp)
461{
462 struct cnic_ops *c_ops;
463 struct cnic_ctl_info info;
464
Michael Chanc5a88952009-08-14 15:49:45 +0000465 mutex_lock(&bp->cnic_lock);
Eric Dumazet13707f92011-01-26 19:28:23 +0000466 c_ops = rcu_dereference_protected(bp->cnic_ops,
467 lockdep_is_held(&bp->cnic_lock));
Michael Chan4edd4732009-06-08 18:14:42 -0700468 if (c_ops) {
469 if (!(bp->flags & BNX2_FLAG_USING_MSIX)) {
470 struct bnx2_napi *bnapi = &bp->bnx2_napi[0];
471
472 bnapi->cnic_tag = bnapi->last_status_idx;
473 }
474 info.cmd = CNIC_CTL_START_CMD;
475 c_ops->cnic_ctl(bp->cnic_data, &info);
476 }
Michael Chanc5a88952009-08-14 15:49:45 +0000477 mutex_unlock(&bp->cnic_lock);
Michael Chan4edd4732009-06-08 18:14:42 -0700478}
479
480#else
481
482static void
483bnx2_cnic_stop(struct bnx2 *bp)
484{
485}
486
487static void
488bnx2_cnic_start(struct bnx2 *bp)
489{
490}
491
492#endif
493
Michael Chanb6016b72005-05-26 13:03:09 -0700494static int
495bnx2_read_phy(struct bnx2 *bp, u32 reg, u32 *val)
496{
497 u32 val1;
498 int i, ret;
499
Michael Chan583c28e2008-01-21 19:51:35 -0800500 if (bp->phy_flags & BNX2_PHY_FLAG_INT_MODE_AUTO_POLLING) {
Michael Chane503e062012-12-06 10:33:08 +0000501 val1 = BNX2_RD(bp, BNX2_EMAC_MDIO_MODE);
Michael Chanb6016b72005-05-26 13:03:09 -0700502 val1 &= ~BNX2_EMAC_MDIO_MODE_AUTO_POLL;
503
Michael Chane503e062012-12-06 10:33:08 +0000504 BNX2_WR(bp, BNX2_EMAC_MDIO_MODE, val1);
505 BNX2_RD(bp, BNX2_EMAC_MDIO_MODE);
Michael Chanb6016b72005-05-26 13:03:09 -0700506
507 udelay(40);
508 }
509
510 val1 = (bp->phy_addr << 21) | (reg << 16) |
511 BNX2_EMAC_MDIO_COMM_COMMAND_READ | BNX2_EMAC_MDIO_COMM_DISEXT |
512 BNX2_EMAC_MDIO_COMM_START_BUSY;
Michael Chane503e062012-12-06 10:33:08 +0000513 BNX2_WR(bp, BNX2_EMAC_MDIO_COMM, val1);
Michael Chanb6016b72005-05-26 13:03:09 -0700514
515 for (i = 0; i < 50; i++) {
516 udelay(10);
517
Michael Chane503e062012-12-06 10:33:08 +0000518 val1 = BNX2_RD(bp, BNX2_EMAC_MDIO_COMM);
Michael Chanb6016b72005-05-26 13:03:09 -0700519 if (!(val1 & BNX2_EMAC_MDIO_COMM_START_BUSY)) {
520 udelay(5);
521
Michael Chane503e062012-12-06 10:33:08 +0000522 val1 = BNX2_RD(bp, BNX2_EMAC_MDIO_COMM);
Michael Chanb6016b72005-05-26 13:03:09 -0700523 val1 &= BNX2_EMAC_MDIO_COMM_DATA;
524
525 break;
526 }
527 }
528
529 if (val1 & BNX2_EMAC_MDIO_COMM_START_BUSY) {
530 *val = 0x0;
531 ret = -EBUSY;
532 }
533 else {
534 *val = val1;
535 ret = 0;
536 }
537
Michael Chan583c28e2008-01-21 19:51:35 -0800538 if (bp->phy_flags & BNX2_PHY_FLAG_INT_MODE_AUTO_POLLING) {
Michael Chane503e062012-12-06 10:33:08 +0000539 val1 = BNX2_RD(bp, BNX2_EMAC_MDIO_MODE);
Michael Chanb6016b72005-05-26 13:03:09 -0700540 val1 |= BNX2_EMAC_MDIO_MODE_AUTO_POLL;
541
Michael Chane503e062012-12-06 10:33:08 +0000542 BNX2_WR(bp, BNX2_EMAC_MDIO_MODE, val1);
543 BNX2_RD(bp, BNX2_EMAC_MDIO_MODE);
Michael Chanb6016b72005-05-26 13:03:09 -0700544
545 udelay(40);
546 }
547
548 return ret;
549}
550
551static int
552bnx2_write_phy(struct bnx2 *bp, u32 reg, u32 val)
553{
554 u32 val1;
555 int i, ret;
556
Michael Chan583c28e2008-01-21 19:51:35 -0800557 if (bp->phy_flags & BNX2_PHY_FLAG_INT_MODE_AUTO_POLLING) {
Michael Chane503e062012-12-06 10:33:08 +0000558 val1 = BNX2_RD(bp, BNX2_EMAC_MDIO_MODE);
Michael Chanb6016b72005-05-26 13:03:09 -0700559 val1 &= ~BNX2_EMAC_MDIO_MODE_AUTO_POLL;
560
Michael Chane503e062012-12-06 10:33:08 +0000561 BNX2_WR(bp, BNX2_EMAC_MDIO_MODE, val1);
562 BNX2_RD(bp, BNX2_EMAC_MDIO_MODE);
Michael Chanb6016b72005-05-26 13:03:09 -0700563
564 udelay(40);
565 }
566
567 val1 = (bp->phy_addr << 21) | (reg << 16) | val |
568 BNX2_EMAC_MDIO_COMM_COMMAND_WRITE |
569 BNX2_EMAC_MDIO_COMM_START_BUSY | BNX2_EMAC_MDIO_COMM_DISEXT;
Michael Chane503e062012-12-06 10:33:08 +0000570 BNX2_WR(bp, BNX2_EMAC_MDIO_COMM, val1);
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400571
Michael Chanb6016b72005-05-26 13:03:09 -0700572 for (i = 0; i < 50; i++) {
573 udelay(10);
574
Michael Chane503e062012-12-06 10:33:08 +0000575 val1 = BNX2_RD(bp, BNX2_EMAC_MDIO_COMM);
Michael Chanb6016b72005-05-26 13:03:09 -0700576 if (!(val1 & BNX2_EMAC_MDIO_COMM_START_BUSY)) {
577 udelay(5);
578 break;
579 }
580 }
581
582 if (val1 & BNX2_EMAC_MDIO_COMM_START_BUSY)
583 ret = -EBUSY;
584 else
585 ret = 0;
586
Michael Chan583c28e2008-01-21 19:51:35 -0800587 if (bp->phy_flags & BNX2_PHY_FLAG_INT_MODE_AUTO_POLLING) {
Michael Chane503e062012-12-06 10:33:08 +0000588 val1 = BNX2_RD(bp, BNX2_EMAC_MDIO_MODE);
Michael Chanb6016b72005-05-26 13:03:09 -0700589 val1 |= BNX2_EMAC_MDIO_MODE_AUTO_POLL;
590
Michael Chane503e062012-12-06 10:33:08 +0000591 BNX2_WR(bp, BNX2_EMAC_MDIO_MODE, val1);
592 BNX2_RD(bp, BNX2_EMAC_MDIO_MODE);
Michael Chanb6016b72005-05-26 13:03:09 -0700593
594 udelay(40);
595 }
596
597 return ret;
598}
599
600static void
601bnx2_disable_int(struct bnx2 *bp)
602{
Michael Chanb4b36042007-12-20 19:59:30 -0800603 int i;
604 struct bnx2_napi *bnapi;
605
606 for (i = 0; i < bp->irq_nvecs; i++) {
607 bnapi = &bp->bnx2_napi[i];
Michael Chane503e062012-12-06 10:33:08 +0000608 BNX2_WR(bp, BNX2_PCICFG_INT_ACK_CMD, bnapi->int_num |
Michael Chanb4b36042007-12-20 19:59:30 -0800609 BNX2_PCICFG_INT_ACK_CMD_MASK_INT);
610 }
Michael Chane503e062012-12-06 10:33:08 +0000611 BNX2_RD(bp, BNX2_PCICFG_INT_ACK_CMD);
Michael Chanb6016b72005-05-26 13:03:09 -0700612}
613
614static void
615bnx2_enable_int(struct bnx2 *bp)
616{
Michael Chanb4b36042007-12-20 19:59:30 -0800617 int i;
618 struct bnx2_napi *bnapi;
Michael Chan1269a8a2006-01-23 16:11:03 -0800619
Michael Chanb4b36042007-12-20 19:59:30 -0800620 for (i = 0; i < bp->irq_nvecs; i++) {
621 bnapi = &bp->bnx2_napi[i];
Michael Chan35efa7c2007-12-20 19:56:37 -0800622
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 BNX2_PCICFG_INT_ACK_CMD_MASK_INT |
626 bnapi->last_status_idx);
Michael Chanb6016b72005-05-26 13:03:09 -0700627
Michael Chane503e062012-12-06 10:33:08 +0000628 BNX2_WR(bp, BNX2_PCICFG_INT_ACK_CMD, bnapi->int_num |
629 BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
630 bnapi->last_status_idx);
Michael Chanb4b36042007-12-20 19:59:30 -0800631 }
Michael Chane503e062012-12-06 10:33:08 +0000632 BNX2_WR(bp, BNX2_HC_COMMAND, bp->hc_cmd | BNX2_HC_COMMAND_COAL_NOW);
Michael Chanb6016b72005-05-26 13:03:09 -0700633}
634
635static void
636bnx2_disable_int_sync(struct bnx2 *bp)
637{
Michael Chanb4b36042007-12-20 19:59:30 -0800638 int i;
639
Michael Chanb6016b72005-05-26 13:03:09 -0700640 atomic_inc(&bp->intr_sem);
Michael Chan37675462009-08-21 16:20:44 +0000641 if (!netif_running(bp->dev))
642 return;
643
Michael Chanb6016b72005-05-26 13:03:09 -0700644 bnx2_disable_int(bp);
Michael Chanb4b36042007-12-20 19:59:30 -0800645 for (i = 0; i < bp->irq_nvecs; i++)
646 synchronize_irq(bp->irq_tbl[i].vector);
Michael Chanb6016b72005-05-26 13:03:09 -0700647}
648
649static void
Michael Chan35efa7c2007-12-20 19:56:37 -0800650bnx2_napi_disable(struct bnx2 *bp)
651{
Michael Chanb4b36042007-12-20 19:59:30 -0800652 int i;
653
654 for (i = 0; i < bp->irq_nvecs; i++)
655 napi_disable(&bp->bnx2_napi[i].napi);
Michael Chan35efa7c2007-12-20 19:56:37 -0800656}
657
658static void
659bnx2_napi_enable(struct bnx2 *bp)
660{
Michael Chanb4b36042007-12-20 19:59:30 -0800661 int i;
662
663 for (i = 0; i < bp->irq_nvecs; i++)
664 napi_enable(&bp->bnx2_napi[i].napi);
Michael Chan35efa7c2007-12-20 19:56:37 -0800665}
666
667static void
Michael Chan212f9932010-04-27 11:28:10 +0000668bnx2_netif_stop(struct bnx2 *bp, bool stop_cnic)
Michael Chanb6016b72005-05-26 13:03:09 -0700669{
Michael Chan212f9932010-04-27 11:28:10 +0000670 if (stop_cnic)
671 bnx2_cnic_stop(bp);
Michael Chanb6016b72005-05-26 13:03:09 -0700672 if (netif_running(bp->dev)) {
Michael Chan35efa7c2007-12-20 19:56:37 -0800673 bnx2_napi_disable(bp);
Michael Chanb6016b72005-05-26 13:03:09 -0700674 netif_tx_disable(bp->dev);
Michael Chanb6016b72005-05-26 13:03:09 -0700675 }
Michael Chanb7466562009-12-20 18:40:18 -0800676 bnx2_disable_int_sync(bp);
Michael Chana0ba6762010-05-17 17:34:43 -0700677 netif_carrier_off(bp->dev); /* prevent tx timeout */
Michael Chanb6016b72005-05-26 13:03:09 -0700678}
679
680static void
Michael Chan212f9932010-04-27 11:28:10 +0000681bnx2_netif_start(struct bnx2 *bp, bool start_cnic)
Michael Chanb6016b72005-05-26 13:03:09 -0700682{
683 if (atomic_dec_and_test(&bp->intr_sem)) {
684 if (netif_running(bp->dev)) {
Benjamin Li706bf242008-07-18 17:55:11 -0700685 netif_tx_wake_all_queues(bp->dev);
Michael Chana0ba6762010-05-17 17:34:43 -0700686 spin_lock_bh(&bp->phy_lock);
687 if (bp->link_up)
688 netif_carrier_on(bp->dev);
689 spin_unlock_bh(&bp->phy_lock);
Michael Chan35efa7c2007-12-20 19:56:37 -0800690 bnx2_napi_enable(bp);
Michael Chanb6016b72005-05-26 13:03:09 -0700691 bnx2_enable_int(bp);
Michael Chan212f9932010-04-27 11:28:10 +0000692 if (start_cnic)
693 bnx2_cnic_start(bp);
Michael Chanb6016b72005-05-26 13:03:09 -0700694 }
695 }
696}
697
698static void
Michael Chan35e90102008-06-19 16:37:42 -0700699bnx2_free_tx_mem(struct bnx2 *bp)
700{
701 int i;
702
703 for (i = 0; i < bp->num_tx_rings; i++) {
704 struct bnx2_napi *bnapi = &bp->bnx2_napi[i];
705 struct bnx2_tx_ring_info *txr = &bnapi->tx_ring;
706
707 if (txr->tx_desc_ring) {
Stanislaw Gruszka36227e82010-07-15 04:25:50 +0000708 dma_free_coherent(&bp->pdev->dev, TXBD_RING_SIZE,
709 txr->tx_desc_ring,
710 txr->tx_desc_mapping);
Michael Chan35e90102008-06-19 16:37:42 -0700711 txr->tx_desc_ring = NULL;
712 }
713 kfree(txr->tx_buf_ring);
714 txr->tx_buf_ring = NULL;
715 }
716}
717
Michael Chanbb4f98a2008-06-19 16:38:19 -0700718static void
719bnx2_free_rx_mem(struct bnx2 *bp)
720{
721 int i;
722
723 for (i = 0; i < bp->num_rx_rings; i++) {
724 struct bnx2_napi *bnapi = &bp->bnx2_napi[i];
725 struct bnx2_rx_ring_info *rxr = &bnapi->rx_ring;
726 int j;
727
728 for (j = 0; j < bp->rx_max_ring; j++) {
729 if (rxr->rx_desc_ring[j])
Stanislaw Gruszka36227e82010-07-15 04:25:50 +0000730 dma_free_coherent(&bp->pdev->dev, RXBD_RING_SIZE,
731 rxr->rx_desc_ring[j],
732 rxr->rx_desc_mapping[j]);
Michael Chanbb4f98a2008-06-19 16:38:19 -0700733 rxr->rx_desc_ring[j] = NULL;
734 }
Breno Leitao25b0b992009-06-08 10:30:19 +0000735 vfree(rxr->rx_buf_ring);
Michael Chanbb4f98a2008-06-19 16:38:19 -0700736 rxr->rx_buf_ring = NULL;
737
738 for (j = 0; j < bp->rx_max_pg_ring; j++) {
739 if (rxr->rx_pg_desc_ring[j])
Stanislaw Gruszka36227e82010-07-15 04:25:50 +0000740 dma_free_coherent(&bp->pdev->dev, RXBD_RING_SIZE,
741 rxr->rx_pg_desc_ring[j],
742 rxr->rx_pg_desc_mapping[j]);
Michael Chan3298a732008-12-17 19:06:08 -0800743 rxr->rx_pg_desc_ring[j] = NULL;
Michael Chanbb4f98a2008-06-19 16:38:19 -0700744 }
Breno Leitao25b0b992009-06-08 10:30:19 +0000745 vfree(rxr->rx_pg_ring);
Michael Chanbb4f98a2008-06-19 16:38:19 -0700746 rxr->rx_pg_ring = NULL;
747 }
748}
749
Michael Chan35e90102008-06-19 16:37:42 -0700750static int
751bnx2_alloc_tx_mem(struct bnx2 *bp)
752{
753 int i;
754
755 for (i = 0; i < bp->num_tx_rings; i++) {
756 struct bnx2_napi *bnapi = &bp->bnx2_napi[i];
757 struct bnx2_tx_ring_info *txr = &bnapi->tx_ring;
758
759 txr->tx_buf_ring = kzalloc(SW_TXBD_RING_SIZE, GFP_KERNEL);
760 if (txr->tx_buf_ring == NULL)
761 return -ENOMEM;
762
763 txr->tx_desc_ring =
Stanislaw Gruszka36227e82010-07-15 04:25:50 +0000764 dma_alloc_coherent(&bp->pdev->dev, TXBD_RING_SIZE,
765 &txr->tx_desc_mapping, GFP_KERNEL);
Michael Chan35e90102008-06-19 16:37:42 -0700766 if (txr->tx_desc_ring == NULL)
767 return -ENOMEM;
768 }
769 return 0;
770}
771
Michael Chanbb4f98a2008-06-19 16:38:19 -0700772static int
773bnx2_alloc_rx_mem(struct bnx2 *bp)
774{
775 int i;
776
777 for (i = 0; i < bp->num_rx_rings; i++) {
778 struct bnx2_napi *bnapi = &bp->bnx2_napi[i];
779 struct bnx2_rx_ring_info *rxr = &bnapi->rx_ring;
780 int j;
781
782 rxr->rx_buf_ring =
Eric Dumazet89bf67f2010-11-22 00:15:06 +0000783 vzalloc(SW_RXBD_RING_SIZE * bp->rx_max_ring);
Michael Chanbb4f98a2008-06-19 16:38:19 -0700784 if (rxr->rx_buf_ring == NULL)
785 return -ENOMEM;
786
Michael Chanbb4f98a2008-06-19 16:38:19 -0700787 for (j = 0; j < bp->rx_max_ring; j++) {
788 rxr->rx_desc_ring[j] =
Stanislaw Gruszka36227e82010-07-15 04:25:50 +0000789 dma_alloc_coherent(&bp->pdev->dev,
790 RXBD_RING_SIZE,
791 &rxr->rx_desc_mapping[j],
792 GFP_KERNEL);
Michael Chanbb4f98a2008-06-19 16:38:19 -0700793 if (rxr->rx_desc_ring[j] == NULL)
794 return -ENOMEM;
795
796 }
797
798 if (bp->rx_pg_ring_size) {
Eric Dumazet89bf67f2010-11-22 00:15:06 +0000799 rxr->rx_pg_ring = vzalloc(SW_RXPG_RING_SIZE *
Michael Chanbb4f98a2008-06-19 16:38:19 -0700800 bp->rx_max_pg_ring);
801 if (rxr->rx_pg_ring == NULL)
802 return -ENOMEM;
803
Michael Chanbb4f98a2008-06-19 16:38:19 -0700804 }
805
806 for (j = 0; j < bp->rx_max_pg_ring; j++) {
807 rxr->rx_pg_desc_ring[j] =
Stanislaw Gruszka36227e82010-07-15 04:25:50 +0000808 dma_alloc_coherent(&bp->pdev->dev,
809 RXBD_RING_SIZE,
810 &rxr->rx_pg_desc_mapping[j],
811 GFP_KERNEL);
Michael Chanbb4f98a2008-06-19 16:38:19 -0700812 if (rxr->rx_pg_desc_ring[j] == NULL)
813 return -ENOMEM;
814
815 }
816 }
817 return 0;
818}
819
Michael Chan35e90102008-06-19 16:37:42 -0700820static void
wangweidong8fae3072015-10-08 18:03:47 +0800821bnx2_free_stats_blk(struct net_device *dev)
822{
823 struct bnx2 *bp = netdev_priv(dev);
824
825 if (bp->status_blk) {
826 dma_free_coherent(&bp->pdev->dev, bp->status_stats_size,
827 bp->status_blk,
828 bp->status_blk_mapping);
829 bp->status_blk = NULL;
830 bp->stats_blk = NULL;
831 }
832}
833
834static int
835bnx2_alloc_stats_blk(struct net_device *dev)
836{
837 int status_blk_size;
838 void *status_blk;
839 struct bnx2 *bp = netdev_priv(dev);
840
841 /* Combine status and statistics blocks into one allocation. */
842 status_blk_size = L1_CACHE_ALIGN(sizeof(struct status_block));
843 if (bp->flags & BNX2_FLAG_MSIX_CAP)
844 status_blk_size = L1_CACHE_ALIGN(BNX2_MAX_MSIX_HW_VEC *
845 BNX2_SBLK_MSIX_ALIGN_SIZE);
846 bp->status_stats_size = status_blk_size +
847 sizeof(struct statistics_block);
848 status_blk = dma_zalloc_coherent(&bp->pdev->dev, bp->status_stats_size,
849 &bp->status_blk_mapping, GFP_KERNEL);
850 if (status_blk == NULL)
851 return -ENOMEM;
852
853 bp->status_blk = status_blk;
854 bp->stats_blk = status_blk + status_blk_size;
855 bp->stats_blk_mapping = bp->status_blk_mapping + status_blk_size;
856
857 return 0;
858}
859
860static void
Michael Chanb6016b72005-05-26 13:03:09 -0700861bnx2_free_mem(struct bnx2 *bp)
862{
Michael Chan13daffa2006-03-20 17:49:20 -0800863 int i;
Michael Chan43e80b82008-06-19 16:41:08 -0700864 struct bnx2_napi *bnapi = &bp->bnx2_napi[0];
Michael Chan13daffa2006-03-20 17:49:20 -0800865
Michael Chan35e90102008-06-19 16:37:42 -0700866 bnx2_free_tx_mem(bp);
Michael Chanbb4f98a2008-06-19 16:38:19 -0700867 bnx2_free_rx_mem(bp);
Michael Chan35e90102008-06-19 16:37:42 -0700868
Michael Chan59b47d82006-11-19 14:10:45 -0800869 for (i = 0; i < bp->ctx_pages; i++) {
870 if (bp->ctx_blk[i]) {
Michael Chan2bc40782012-12-06 10:33:09 +0000871 dma_free_coherent(&bp->pdev->dev, BNX2_PAGE_SIZE,
Stanislaw Gruszka36227e82010-07-15 04:25:50 +0000872 bp->ctx_blk[i],
873 bp->ctx_blk_mapping[i]);
Michael Chan59b47d82006-11-19 14:10:45 -0800874 bp->ctx_blk[i] = NULL;
875 }
876 }
wangweidong8fae3072015-10-08 18:03:47 +0800877
878 if (bnapi->status_blk.msi)
Michael Chan43e80b82008-06-19 16:41:08 -0700879 bnapi->status_blk.msi = NULL;
Michael Chanb6016b72005-05-26 13:03:09 -0700880}
881
882static int
883bnx2_alloc_mem(struct bnx2 *bp)
884{
wangweidong8fae3072015-10-08 18:03:47 +0800885 int i, err;
Michael Chan43e80b82008-06-19 16:41:08 -0700886 struct bnx2_napi *bnapi;
Michael Chanb6016b72005-05-26 13:03:09 -0700887
Michael Chan43e80b82008-06-19 16:41:08 -0700888 bnapi = &bp->bnx2_napi[0];
wangweidong8fae3072015-10-08 18:03:47 +0800889 bnapi->status_blk.msi = bp->status_blk;
Michael Chan43e80b82008-06-19 16:41:08 -0700890 bnapi->hw_tx_cons_ptr =
891 &bnapi->status_blk.msi->status_tx_quick_consumer_index0;
892 bnapi->hw_rx_cons_ptr =
893 &bnapi->status_blk.msi->status_rx_quick_consumer_index0;
David S. Millerf86e82f2008-01-21 17:15:40 -0800894 if (bp->flags & BNX2_FLAG_MSIX_CAP) {
Michael Chan379b39a2010-07-19 14:15:03 +0000895 for (i = 1; i < bp->irq_nvecs; i++) {
Michael Chan43e80b82008-06-19 16:41:08 -0700896 struct status_block_msix *sblk;
Michael Chanb4b36042007-12-20 19:59:30 -0800897
Michael Chan43e80b82008-06-19 16:41:08 -0700898 bnapi = &bp->bnx2_napi[i];
899
wangweidong8fae3072015-10-08 18:03:47 +0800900 sblk = (bp->status_blk + BNX2_SBLK_MSIX_ALIGN_SIZE * i);
Michael Chan43e80b82008-06-19 16:41:08 -0700901 bnapi->status_blk.msix = sblk;
902 bnapi->hw_tx_cons_ptr =
903 &sblk->status_tx_quick_consumer_index;
904 bnapi->hw_rx_cons_ptr =
905 &sblk->status_rx_quick_consumer_index;
Michael Chanb4b36042007-12-20 19:59:30 -0800906 bnapi->int_num = i << 24;
907 }
908 }
Michael Chan35efa7c2007-12-20 19:56:37 -0800909
Michael Chan4ce45e02012-12-06 10:33:10 +0000910 if (BNX2_CHIP(bp) == BNX2_CHIP_5709) {
Michael Chan2bc40782012-12-06 10:33:09 +0000911 bp->ctx_pages = 0x2000 / BNX2_PAGE_SIZE;
Michael Chan59b47d82006-11-19 14:10:45 -0800912 if (bp->ctx_pages == 0)
913 bp->ctx_pages = 1;
914 for (i = 0; i < bp->ctx_pages; i++) {
Stanislaw Gruszka36227e82010-07-15 04:25:50 +0000915 bp->ctx_blk[i] = dma_alloc_coherent(&bp->pdev->dev,
Michael Chan2bc40782012-12-06 10:33:09 +0000916 BNX2_PAGE_SIZE,
Stanislaw Gruszka36227e82010-07-15 04:25:50 +0000917 &bp->ctx_blk_mapping[i],
918 GFP_KERNEL);
Michael Chan59b47d82006-11-19 14:10:45 -0800919 if (bp->ctx_blk[i] == NULL)
920 goto alloc_mem_err;
921 }
922 }
Michael Chan35e90102008-06-19 16:37:42 -0700923
Michael Chanbb4f98a2008-06-19 16:38:19 -0700924 err = bnx2_alloc_rx_mem(bp);
925 if (err)
926 goto alloc_mem_err;
927
Michael Chan35e90102008-06-19 16:37:42 -0700928 err = bnx2_alloc_tx_mem(bp);
929 if (err)
930 goto alloc_mem_err;
931
Michael Chanb6016b72005-05-26 13:03:09 -0700932 return 0;
933
934alloc_mem_err:
935 bnx2_free_mem(bp);
936 return -ENOMEM;
937}
938
939static void
Michael Chane3648b32005-11-04 08:51:21 -0800940bnx2_report_fw_link(struct bnx2 *bp)
941{
942 u32 fw_link_status = 0;
943
Michael Chan583c28e2008-01-21 19:51:35 -0800944 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
Michael Chan0d8a6572007-07-07 22:49:43 -0700945 return;
946
Michael Chane3648b32005-11-04 08:51:21 -0800947 if (bp->link_up) {
948 u32 bmsr;
949
950 switch (bp->line_speed) {
951 case SPEED_10:
952 if (bp->duplex == DUPLEX_HALF)
953 fw_link_status = BNX2_LINK_STATUS_10HALF;
954 else
955 fw_link_status = BNX2_LINK_STATUS_10FULL;
956 break;
957 case SPEED_100:
958 if (bp->duplex == DUPLEX_HALF)
959 fw_link_status = BNX2_LINK_STATUS_100HALF;
960 else
961 fw_link_status = BNX2_LINK_STATUS_100FULL;
962 break;
963 case SPEED_1000:
964 if (bp->duplex == DUPLEX_HALF)
965 fw_link_status = BNX2_LINK_STATUS_1000HALF;
966 else
967 fw_link_status = BNX2_LINK_STATUS_1000FULL;
968 break;
969 case SPEED_2500:
970 if (bp->duplex == DUPLEX_HALF)
971 fw_link_status = BNX2_LINK_STATUS_2500HALF;
972 else
973 fw_link_status = BNX2_LINK_STATUS_2500FULL;
974 break;
975 }
976
977 fw_link_status |= BNX2_LINK_STATUS_LINK_UP;
978
979 if (bp->autoneg) {
980 fw_link_status |= BNX2_LINK_STATUS_AN_ENABLED;
981
Michael Chanca58c3a2007-05-03 13:22:52 -0700982 bnx2_read_phy(bp, bp->mii_bmsr, &bmsr);
983 bnx2_read_phy(bp, bp->mii_bmsr, &bmsr);
Michael Chane3648b32005-11-04 08:51:21 -0800984
985 if (!(bmsr & BMSR_ANEGCOMPLETE) ||
Michael Chan583c28e2008-01-21 19:51:35 -0800986 bp->phy_flags & BNX2_PHY_FLAG_PARALLEL_DETECT)
Michael Chane3648b32005-11-04 08:51:21 -0800987 fw_link_status |= BNX2_LINK_STATUS_PARALLEL_DET;
988 else
989 fw_link_status |= BNX2_LINK_STATUS_AN_COMPLETE;
990 }
991 }
992 else
993 fw_link_status = BNX2_LINK_STATUS_LINK_DOWN;
994
Michael Chan2726d6e2008-01-29 21:35:05 -0800995 bnx2_shmem_wr(bp, BNX2_LINK_STATUS, fw_link_status);
Michael Chane3648b32005-11-04 08:51:21 -0800996}
997
Michael Chan9b1084b2007-07-07 22:50:37 -0700998static char *
999bnx2_xceiver_str(struct bnx2 *bp)
1000{
Eric Dumazet807540b2010-09-23 05:40:09 +00001001 return (bp->phy_port == PORT_FIBRE) ? "SerDes" :
Michael Chan583c28e2008-01-21 19:51:35 -08001002 ((bp->phy_flags & BNX2_PHY_FLAG_SERDES) ? "Remote Copper" :
Eric Dumazet807540b2010-09-23 05:40:09 +00001003 "Copper");
Michael Chan9b1084b2007-07-07 22:50:37 -07001004}
1005
Michael Chane3648b32005-11-04 08:51:21 -08001006static void
Michael Chanb6016b72005-05-26 13:03:09 -07001007bnx2_report_link(struct bnx2 *bp)
1008{
1009 if (bp->link_up) {
1010 netif_carrier_on(bp->dev);
Joe Perches3a9c6a42010-02-17 15:01:51 +00001011 netdev_info(bp->dev, "NIC %s Link is Up, %d Mbps %s duplex",
1012 bnx2_xceiver_str(bp),
1013 bp->line_speed,
1014 bp->duplex == DUPLEX_FULL ? "full" : "half");
Michael Chanb6016b72005-05-26 13:03:09 -07001015
1016 if (bp->flow_ctrl) {
1017 if (bp->flow_ctrl & FLOW_CTRL_RX) {
Joe Perches3a9c6a42010-02-17 15:01:51 +00001018 pr_cont(", receive ");
Michael Chanb6016b72005-05-26 13:03:09 -07001019 if (bp->flow_ctrl & FLOW_CTRL_TX)
Joe Perches3a9c6a42010-02-17 15:01:51 +00001020 pr_cont("& transmit ");
Michael Chanb6016b72005-05-26 13:03:09 -07001021 }
1022 else {
Joe Perches3a9c6a42010-02-17 15:01:51 +00001023 pr_cont(", transmit ");
Michael Chanb6016b72005-05-26 13:03:09 -07001024 }
Joe Perches3a9c6a42010-02-17 15:01:51 +00001025 pr_cont("flow control ON");
Michael Chanb6016b72005-05-26 13:03:09 -07001026 }
Joe Perches3a9c6a42010-02-17 15:01:51 +00001027 pr_cont("\n");
1028 } else {
Michael Chanb6016b72005-05-26 13:03:09 -07001029 netif_carrier_off(bp->dev);
Joe Perches3a9c6a42010-02-17 15:01:51 +00001030 netdev_err(bp->dev, "NIC %s Link is Down\n",
1031 bnx2_xceiver_str(bp));
Michael Chanb6016b72005-05-26 13:03:09 -07001032 }
Michael Chane3648b32005-11-04 08:51:21 -08001033
1034 bnx2_report_fw_link(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07001035}
1036
1037static void
1038bnx2_resolve_flow_ctrl(struct bnx2 *bp)
1039{
1040 u32 local_adv, remote_adv;
1041
1042 bp->flow_ctrl = 0;
Jeff Garzik6aa20a22006-09-13 13:24:59 -04001043 if ((bp->autoneg & (AUTONEG_SPEED | AUTONEG_FLOW_CTRL)) !=
Michael Chanb6016b72005-05-26 13:03:09 -07001044 (AUTONEG_SPEED | AUTONEG_FLOW_CTRL)) {
1045
1046 if (bp->duplex == DUPLEX_FULL) {
1047 bp->flow_ctrl = bp->req_flow_ctrl;
1048 }
1049 return;
1050 }
1051
1052 if (bp->duplex != DUPLEX_FULL) {
1053 return;
1054 }
1055
Michael Chan583c28e2008-01-21 19:51:35 -08001056 if ((bp->phy_flags & BNX2_PHY_FLAG_SERDES) &&
Michael Chan4ce45e02012-12-06 10:33:10 +00001057 (BNX2_CHIP(bp) == BNX2_CHIP_5708)) {
Michael Chan5b0c76a2005-11-04 08:45:49 -08001058 u32 val;
1059
1060 bnx2_read_phy(bp, BCM5708S_1000X_STAT1, &val);
1061 if (val & BCM5708S_1000X_STAT1_TX_PAUSE)
1062 bp->flow_ctrl |= FLOW_CTRL_TX;
1063 if (val & BCM5708S_1000X_STAT1_RX_PAUSE)
1064 bp->flow_ctrl |= FLOW_CTRL_RX;
1065 return;
1066 }
1067
Michael Chanca58c3a2007-05-03 13:22:52 -07001068 bnx2_read_phy(bp, bp->mii_adv, &local_adv);
1069 bnx2_read_phy(bp, bp->mii_lpa, &remote_adv);
Michael Chanb6016b72005-05-26 13:03:09 -07001070
Michael Chan583c28e2008-01-21 19:51:35 -08001071 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Michael Chanb6016b72005-05-26 13:03:09 -07001072 u32 new_local_adv = 0;
1073 u32 new_remote_adv = 0;
1074
1075 if (local_adv & ADVERTISE_1000XPAUSE)
1076 new_local_adv |= ADVERTISE_PAUSE_CAP;
1077 if (local_adv & ADVERTISE_1000XPSE_ASYM)
1078 new_local_adv |= ADVERTISE_PAUSE_ASYM;
1079 if (remote_adv & ADVERTISE_1000XPAUSE)
1080 new_remote_adv |= ADVERTISE_PAUSE_CAP;
1081 if (remote_adv & ADVERTISE_1000XPSE_ASYM)
1082 new_remote_adv |= ADVERTISE_PAUSE_ASYM;
1083
1084 local_adv = new_local_adv;
1085 remote_adv = new_remote_adv;
1086 }
1087
1088 /* See Table 28B-3 of 802.3ab-1999 spec. */
1089 if (local_adv & ADVERTISE_PAUSE_CAP) {
1090 if(local_adv & ADVERTISE_PAUSE_ASYM) {
1091 if (remote_adv & ADVERTISE_PAUSE_CAP) {
1092 bp->flow_ctrl = FLOW_CTRL_TX | FLOW_CTRL_RX;
1093 }
1094 else if (remote_adv & ADVERTISE_PAUSE_ASYM) {
1095 bp->flow_ctrl = FLOW_CTRL_RX;
1096 }
1097 }
1098 else {
1099 if (remote_adv & ADVERTISE_PAUSE_CAP) {
1100 bp->flow_ctrl = FLOW_CTRL_TX | FLOW_CTRL_RX;
1101 }
1102 }
1103 }
1104 else if (local_adv & ADVERTISE_PAUSE_ASYM) {
1105 if ((remote_adv & ADVERTISE_PAUSE_CAP) &&
1106 (remote_adv & ADVERTISE_PAUSE_ASYM)) {
1107
1108 bp->flow_ctrl = FLOW_CTRL_TX;
1109 }
1110 }
1111}
1112
1113static int
Michael Chan27a005b2007-05-03 13:23:41 -07001114bnx2_5709s_linkup(struct bnx2 *bp)
1115{
1116 u32 val, speed;
1117
1118 bp->link_up = 1;
1119
1120 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_GP_STATUS);
1121 bnx2_read_phy(bp, MII_BNX2_GP_TOP_AN_STATUS1, &val);
1122 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
1123
1124 if ((bp->autoneg & AUTONEG_SPEED) == 0) {
1125 bp->line_speed = bp->req_line_speed;
1126 bp->duplex = bp->req_duplex;
1127 return 0;
1128 }
1129 speed = val & MII_BNX2_GP_TOP_AN_SPEED_MSK;
1130 switch (speed) {
1131 case MII_BNX2_GP_TOP_AN_SPEED_10:
1132 bp->line_speed = SPEED_10;
1133 break;
1134 case MII_BNX2_GP_TOP_AN_SPEED_100:
1135 bp->line_speed = SPEED_100;
1136 break;
1137 case MII_BNX2_GP_TOP_AN_SPEED_1G:
1138 case MII_BNX2_GP_TOP_AN_SPEED_1GKV:
1139 bp->line_speed = SPEED_1000;
1140 break;
1141 case MII_BNX2_GP_TOP_AN_SPEED_2_5G:
1142 bp->line_speed = SPEED_2500;
1143 break;
1144 }
1145 if (val & MII_BNX2_GP_TOP_AN_FD)
1146 bp->duplex = DUPLEX_FULL;
1147 else
1148 bp->duplex = DUPLEX_HALF;
1149 return 0;
1150}
1151
1152static int
Michael Chan5b0c76a2005-11-04 08:45:49 -08001153bnx2_5708s_linkup(struct bnx2 *bp)
1154{
1155 u32 val;
1156
1157 bp->link_up = 1;
1158 bnx2_read_phy(bp, BCM5708S_1000X_STAT1, &val);
1159 switch (val & BCM5708S_1000X_STAT1_SPEED_MASK) {
1160 case BCM5708S_1000X_STAT1_SPEED_10:
1161 bp->line_speed = SPEED_10;
1162 break;
1163 case BCM5708S_1000X_STAT1_SPEED_100:
1164 bp->line_speed = SPEED_100;
1165 break;
1166 case BCM5708S_1000X_STAT1_SPEED_1G:
1167 bp->line_speed = SPEED_1000;
1168 break;
1169 case BCM5708S_1000X_STAT1_SPEED_2G5:
1170 bp->line_speed = SPEED_2500;
1171 break;
1172 }
1173 if (val & BCM5708S_1000X_STAT1_FD)
1174 bp->duplex = DUPLEX_FULL;
1175 else
1176 bp->duplex = DUPLEX_HALF;
1177
1178 return 0;
1179}
1180
1181static int
1182bnx2_5706s_linkup(struct bnx2 *bp)
Michael Chanb6016b72005-05-26 13:03:09 -07001183{
1184 u32 bmcr, local_adv, remote_adv, common;
1185
1186 bp->link_up = 1;
1187 bp->line_speed = SPEED_1000;
1188
Michael Chanca58c3a2007-05-03 13:22:52 -07001189 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chanb6016b72005-05-26 13:03:09 -07001190 if (bmcr & BMCR_FULLDPLX) {
1191 bp->duplex = DUPLEX_FULL;
1192 }
1193 else {
1194 bp->duplex = DUPLEX_HALF;
1195 }
1196
1197 if (!(bmcr & BMCR_ANENABLE)) {
1198 return 0;
1199 }
1200
Michael Chanca58c3a2007-05-03 13:22:52 -07001201 bnx2_read_phy(bp, bp->mii_adv, &local_adv);
1202 bnx2_read_phy(bp, bp->mii_lpa, &remote_adv);
Michael Chanb6016b72005-05-26 13:03:09 -07001203
1204 common = local_adv & remote_adv;
1205 if (common & (ADVERTISE_1000XHALF | ADVERTISE_1000XFULL)) {
1206
1207 if (common & ADVERTISE_1000XFULL) {
1208 bp->duplex = DUPLEX_FULL;
1209 }
1210 else {
1211 bp->duplex = DUPLEX_HALF;
1212 }
1213 }
1214
1215 return 0;
1216}
1217
1218static int
1219bnx2_copper_linkup(struct bnx2 *bp)
1220{
1221 u32 bmcr;
1222
Michael Chan4016bad2013-12-31 23:22:34 -08001223 bp->phy_flags &= ~BNX2_PHY_FLAG_MDIX;
1224
Michael Chanca58c3a2007-05-03 13:22:52 -07001225 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chanb6016b72005-05-26 13:03:09 -07001226 if (bmcr & BMCR_ANENABLE) {
1227 u32 local_adv, remote_adv, common;
1228
1229 bnx2_read_phy(bp, MII_CTRL1000, &local_adv);
1230 bnx2_read_phy(bp, MII_STAT1000, &remote_adv);
1231
1232 common = local_adv & (remote_adv >> 2);
1233 if (common & ADVERTISE_1000FULL) {
1234 bp->line_speed = SPEED_1000;
1235 bp->duplex = DUPLEX_FULL;
1236 }
1237 else if (common & ADVERTISE_1000HALF) {
1238 bp->line_speed = SPEED_1000;
1239 bp->duplex = DUPLEX_HALF;
1240 }
1241 else {
Michael Chanca58c3a2007-05-03 13:22:52 -07001242 bnx2_read_phy(bp, bp->mii_adv, &local_adv);
1243 bnx2_read_phy(bp, bp->mii_lpa, &remote_adv);
Michael Chanb6016b72005-05-26 13:03:09 -07001244
1245 common = local_adv & remote_adv;
1246 if (common & ADVERTISE_100FULL) {
1247 bp->line_speed = SPEED_100;
1248 bp->duplex = DUPLEX_FULL;
1249 }
1250 else if (common & ADVERTISE_100HALF) {
1251 bp->line_speed = SPEED_100;
1252 bp->duplex = DUPLEX_HALF;
1253 }
1254 else if (common & ADVERTISE_10FULL) {
1255 bp->line_speed = SPEED_10;
1256 bp->duplex = DUPLEX_FULL;
1257 }
1258 else if (common & ADVERTISE_10HALF) {
1259 bp->line_speed = SPEED_10;
1260 bp->duplex = DUPLEX_HALF;
1261 }
1262 else {
1263 bp->line_speed = 0;
1264 bp->link_up = 0;
1265 }
1266 }
1267 }
1268 else {
1269 if (bmcr & BMCR_SPEED100) {
1270 bp->line_speed = SPEED_100;
1271 }
1272 else {
1273 bp->line_speed = SPEED_10;
1274 }
1275 if (bmcr & BMCR_FULLDPLX) {
1276 bp->duplex = DUPLEX_FULL;
1277 }
1278 else {
1279 bp->duplex = DUPLEX_HALF;
1280 }
1281 }
1282
Michael Chan4016bad2013-12-31 23:22:34 -08001283 if (bp->link_up) {
1284 u32 ext_status;
1285
1286 bnx2_read_phy(bp, MII_BNX2_EXT_STATUS, &ext_status);
1287 if (ext_status & EXT_STATUS_MDIX)
1288 bp->phy_flags |= BNX2_PHY_FLAG_MDIX;
1289 }
1290
Michael Chanb6016b72005-05-26 13:03:09 -07001291 return 0;
1292}
1293
Michael Chan83e3fc82008-01-29 21:37:17 -08001294static void
Michael Chanbb4f98a2008-06-19 16:38:19 -07001295bnx2_init_rx_context(struct bnx2 *bp, u32 cid)
Michael Chan83e3fc82008-01-29 21:37:17 -08001296{
Michael Chanbb4f98a2008-06-19 16:38:19 -07001297 u32 val, rx_cid_addr = GET_CID_ADDR(cid);
Michael Chan83e3fc82008-01-29 21:37:17 -08001298
1299 val = BNX2_L2CTX_CTX_TYPE_CTX_BD_CHN_TYPE_VALUE;
1300 val |= BNX2_L2CTX_CTX_TYPE_SIZE_L2;
1301 val |= 0x02 << 8;
1302
Michael Chan22fa1592010-10-11 16:12:00 -07001303 if (bp->flow_ctrl & FLOW_CTRL_TX)
1304 val |= BNX2_L2CTX_FLOW_CTRL_ENABLE;
Michael Chan83e3fc82008-01-29 21:37:17 -08001305
Michael Chan83e3fc82008-01-29 21:37:17 -08001306 bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_CTX_TYPE, val);
1307}
1308
Michael Chanbb4f98a2008-06-19 16:38:19 -07001309static void
1310bnx2_init_all_rx_contexts(struct bnx2 *bp)
1311{
1312 int i;
1313 u32 cid;
1314
1315 for (i = 0, cid = RX_CID; i < bp->num_rx_rings; i++, cid++) {
1316 if (i == 1)
1317 cid = RX_RSS_CID;
1318 bnx2_init_rx_context(bp, cid);
1319 }
1320}
1321
Benjamin Li344478d2008-09-18 16:38:24 -07001322static void
Michael Chanb6016b72005-05-26 13:03:09 -07001323bnx2_set_mac_link(struct bnx2 *bp)
1324{
1325 u32 val;
1326
Michael Chane503e062012-12-06 10:33:08 +00001327 BNX2_WR(bp, BNX2_EMAC_TX_LENGTHS, 0x2620);
Michael Chanb6016b72005-05-26 13:03:09 -07001328 if (bp->link_up && (bp->line_speed == SPEED_1000) &&
1329 (bp->duplex == DUPLEX_HALF)) {
Michael Chane503e062012-12-06 10:33:08 +00001330 BNX2_WR(bp, BNX2_EMAC_TX_LENGTHS, 0x26ff);
Michael Chanb6016b72005-05-26 13:03:09 -07001331 }
1332
1333 /* Configure the EMAC mode register. */
Michael Chane503e062012-12-06 10:33:08 +00001334 val = BNX2_RD(bp, BNX2_EMAC_MODE);
Michael Chanb6016b72005-05-26 13:03:09 -07001335
1336 val &= ~(BNX2_EMAC_MODE_PORT | BNX2_EMAC_MODE_HALF_DUPLEX |
Michael Chan5b0c76a2005-11-04 08:45:49 -08001337 BNX2_EMAC_MODE_MAC_LOOP | BNX2_EMAC_MODE_FORCE_LINK |
Michael Chan59b47d82006-11-19 14:10:45 -08001338 BNX2_EMAC_MODE_25G_MODE);
Michael Chanb6016b72005-05-26 13:03:09 -07001339
1340 if (bp->link_up) {
Michael Chan5b0c76a2005-11-04 08:45:49 -08001341 switch (bp->line_speed) {
1342 case SPEED_10:
Michael Chan4ce45e02012-12-06 10:33:10 +00001343 if (BNX2_CHIP(bp) != BNX2_CHIP_5706) {
Michael Chan59b47d82006-11-19 14:10:45 -08001344 val |= BNX2_EMAC_MODE_PORT_MII_10M;
Michael Chan5b0c76a2005-11-04 08:45:49 -08001345 break;
1346 }
1347 /* fall through */
1348 case SPEED_100:
1349 val |= BNX2_EMAC_MODE_PORT_MII;
1350 break;
1351 case SPEED_2500:
Michael Chan59b47d82006-11-19 14:10:45 -08001352 val |= BNX2_EMAC_MODE_25G_MODE;
Michael Chan5b0c76a2005-11-04 08:45:49 -08001353 /* fall through */
1354 case SPEED_1000:
1355 val |= BNX2_EMAC_MODE_PORT_GMII;
1356 break;
1357 }
Michael Chanb6016b72005-05-26 13:03:09 -07001358 }
1359 else {
1360 val |= BNX2_EMAC_MODE_PORT_GMII;
1361 }
1362
1363 /* Set the MAC to operate in the appropriate duplex mode. */
1364 if (bp->duplex == DUPLEX_HALF)
1365 val |= BNX2_EMAC_MODE_HALF_DUPLEX;
Michael Chane503e062012-12-06 10:33:08 +00001366 BNX2_WR(bp, BNX2_EMAC_MODE, val);
Michael Chanb6016b72005-05-26 13:03:09 -07001367
1368 /* Enable/disable rx PAUSE. */
1369 bp->rx_mode &= ~BNX2_EMAC_RX_MODE_FLOW_EN;
1370
1371 if (bp->flow_ctrl & FLOW_CTRL_RX)
1372 bp->rx_mode |= BNX2_EMAC_RX_MODE_FLOW_EN;
Michael Chane503e062012-12-06 10:33:08 +00001373 BNX2_WR(bp, BNX2_EMAC_RX_MODE, bp->rx_mode);
Michael Chanb6016b72005-05-26 13:03:09 -07001374
1375 /* Enable/disable tx PAUSE. */
Michael Chane503e062012-12-06 10:33:08 +00001376 val = BNX2_RD(bp, BNX2_EMAC_TX_MODE);
Michael Chanb6016b72005-05-26 13:03:09 -07001377 val &= ~BNX2_EMAC_TX_MODE_FLOW_EN;
1378
1379 if (bp->flow_ctrl & FLOW_CTRL_TX)
1380 val |= BNX2_EMAC_TX_MODE_FLOW_EN;
Michael Chane503e062012-12-06 10:33:08 +00001381 BNX2_WR(bp, BNX2_EMAC_TX_MODE, val);
Michael Chanb6016b72005-05-26 13:03:09 -07001382
1383 /* Acknowledge the interrupt. */
Michael Chane503e062012-12-06 10:33:08 +00001384 BNX2_WR(bp, BNX2_EMAC_STATUS, BNX2_EMAC_STATUS_LINK_CHANGE);
Michael Chanb6016b72005-05-26 13:03:09 -07001385
Michael Chan22fa1592010-10-11 16:12:00 -07001386 bnx2_init_all_rx_contexts(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07001387}
1388
Michael Chan27a005b2007-05-03 13:23:41 -07001389static void
1390bnx2_enable_bmsr1(struct bnx2 *bp)
1391{
Michael Chan583c28e2008-01-21 19:51:35 -08001392 if ((bp->phy_flags & BNX2_PHY_FLAG_SERDES) &&
Michael Chan4ce45e02012-12-06 10:33:10 +00001393 (BNX2_CHIP(bp) == BNX2_CHIP_5709))
Michael Chan27a005b2007-05-03 13:23:41 -07001394 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
1395 MII_BNX2_BLK_ADDR_GP_STATUS);
1396}
1397
1398static void
1399bnx2_disable_bmsr1(struct bnx2 *bp)
1400{
Michael Chan583c28e2008-01-21 19:51:35 -08001401 if ((bp->phy_flags & BNX2_PHY_FLAG_SERDES) &&
Michael Chan4ce45e02012-12-06 10:33:10 +00001402 (BNX2_CHIP(bp) == BNX2_CHIP_5709))
Michael Chan27a005b2007-05-03 13:23:41 -07001403 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
1404 MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
1405}
1406
Michael Chanb6016b72005-05-26 13:03:09 -07001407static int
Michael Chan605a9e22007-05-03 13:23:13 -07001408bnx2_test_and_enable_2g5(struct bnx2 *bp)
1409{
1410 u32 up1;
1411 int ret = 1;
1412
Michael Chan583c28e2008-01-21 19:51:35 -08001413 if (!(bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE))
Michael Chan605a9e22007-05-03 13:23:13 -07001414 return 0;
1415
1416 if (bp->autoneg & AUTONEG_SPEED)
1417 bp->advertising |= ADVERTISED_2500baseX_Full;
1418
Michael Chan4ce45e02012-12-06 10:33:10 +00001419 if (BNX2_CHIP(bp) == BNX2_CHIP_5709)
Michael Chan27a005b2007-05-03 13:23:41 -07001420 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_OVER1G);
1421
Michael Chan605a9e22007-05-03 13:23:13 -07001422 bnx2_read_phy(bp, bp->mii_up1, &up1);
1423 if (!(up1 & BCM5708S_UP1_2G5)) {
1424 up1 |= BCM5708S_UP1_2G5;
1425 bnx2_write_phy(bp, bp->mii_up1, up1);
1426 ret = 0;
1427 }
1428
Michael Chan4ce45e02012-12-06 10:33:10 +00001429 if (BNX2_CHIP(bp) == BNX2_CHIP_5709)
Michael Chan27a005b2007-05-03 13:23:41 -07001430 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
1431 MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
1432
Michael Chan605a9e22007-05-03 13:23:13 -07001433 return ret;
1434}
1435
1436static int
1437bnx2_test_and_disable_2g5(struct bnx2 *bp)
1438{
1439 u32 up1;
1440 int ret = 0;
1441
Michael Chan583c28e2008-01-21 19:51:35 -08001442 if (!(bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE))
Michael Chan605a9e22007-05-03 13:23:13 -07001443 return 0;
1444
Michael Chan4ce45e02012-12-06 10:33:10 +00001445 if (BNX2_CHIP(bp) == BNX2_CHIP_5709)
Michael Chan27a005b2007-05-03 13:23:41 -07001446 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_OVER1G);
1447
Michael Chan605a9e22007-05-03 13:23:13 -07001448 bnx2_read_phy(bp, bp->mii_up1, &up1);
1449 if (up1 & BCM5708S_UP1_2G5) {
1450 up1 &= ~BCM5708S_UP1_2G5;
1451 bnx2_write_phy(bp, bp->mii_up1, up1);
1452 ret = 1;
1453 }
1454
Michael Chan4ce45e02012-12-06 10:33:10 +00001455 if (BNX2_CHIP(bp) == BNX2_CHIP_5709)
Michael Chan27a005b2007-05-03 13:23:41 -07001456 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
1457 MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
1458
Michael Chan605a9e22007-05-03 13:23:13 -07001459 return ret;
1460}
1461
1462static void
1463bnx2_enable_forced_2g5(struct bnx2 *bp)
1464{
Michael Chancbd68902010-06-08 07:21:30 +00001465 u32 uninitialized_var(bmcr);
1466 int err;
Michael Chan605a9e22007-05-03 13:23:13 -07001467
Michael Chan583c28e2008-01-21 19:51:35 -08001468 if (!(bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE))
Michael Chan605a9e22007-05-03 13:23:13 -07001469 return;
1470
Michael Chan4ce45e02012-12-06 10:33:10 +00001471 if (BNX2_CHIP(bp) == BNX2_CHIP_5709) {
Michael Chan27a005b2007-05-03 13:23:41 -07001472 u32 val;
1473
1474 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
1475 MII_BNX2_BLK_ADDR_SERDES_DIG);
Michael Chancbd68902010-06-08 07:21:30 +00001476 if (!bnx2_read_phy(bp, MII_BNX2_SERDES_DIG_MISC1, &val)) {
1477 val &= ~MII_BNX2_SD_MISC1_FORCE_MSK;
1478 val |= MII_BNX2_SD_MISC1_FORCE |
1479 MII_BNX2_SD_MISC1_FORCE_2_5G;
1480 bnx2_write_phy(bp, MII_BNX2_SERDES_DIG_MISC1, val);
1481 }
Michael Chan27a005b2007-05-03 13:23:41 -07001482
1483 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
1484 MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
Michael Chancbd68902010-06-08 07:21:30 +00001485 err = bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chan27a005b2007-05-03 13:23:41 -07001486
Michael Chan4ce45e02012-12-06 10:33:10 +00001487 } else if (BNX2_CHIP(bp) == BNX2_CHIP_5708) {
Michael Chancbd68902010-06-08 07:21:30 +00001488 err = bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
1489 if (!err)
1490 bmcr |= BCM5708S_BMCR_FORCE_2500;
Eric Dumazetc70798572009-11-02 23:17:42 +00001491 } else {
1492 return;
Michael Chan605a9e22007-05-03 13:23:13 -07001493 }
1494
Michael Chancbd68902010-06-08 07:21:30 +00001495 if (err)
1496 return;
1497
Michael Chan605a9e22007-05-03 13:23:13 -07001498 if (bp->autoneg & AUTONEG_SPEED) {
1499 bmcr &= ~BMCR_ANENABLE;
1500 if (bp->req_duplex == DUPLEX_FULL)
1501 bmcr |= BMCR_FULLDPLX;
1502 }
1503 bnx2_write_phy(bp, bp->mii_bmcr, bmcr);
1504}
1505
1506static void
1507bnx2_disable_forced_2g5(struct bnx2 *bp)
1508{
Michael Chancbd68902010-06-08 07:21:30 +00001509 u32 uninitialized_var(bmcr);
1510 int err;
Michael Chan605a9e22007-05-03 13:23:13 -07001511
Michael Chan583c28e2008-01-21 19:51:35 -08001512 if (!(bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE))
Michael Chan605a9e22007-05-03 13:23:13 -07001513 return;
1514
Michael Chan4ce45e02012-12-06 10:33:10 +00001515 if (BNX2_CHIP(bp) == BNX2_CHIP_5709) {
Michael Chan27a005b2007-05-03 13:23:41 -07001516 u32 val;
1517
1518 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
1519 MII_BNX2_BLK_ADDR_SERDES_DIG);
Michael Chancbd68902010-06-08 07:21:30 +00001520 if (!bnx2_read_phy(bp, MII_BNX2_SERDES_DIG_MISC1, &val)) {
1521 val &= ~MII_BNX2_SD_MISC1_FORCE;
1522 bnx2_write_phy(bp, MII_BNX2_SERDES_DIG_MISC1, val);
1523 }
Michael Chan27a005b2007-05-03 13:23:41 -07001524
1525 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
1526 MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
Michael Chancbd68902010-06-08 07:21:30 +00001527 err = bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chan27a005b2007-05-03 13:23:41 -07001528
Michael Chan4ce45e02012-12-06 10:33:10 +00001529 } else if (BNX2_CHIP(bp) == BNX2_CHIP_5708) {
Michael Chancbd68902010-06-08 07:21:30 +00001530 err = bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
1531 if (!err)
1532 bmcr &= ~BCM5708S_BMCR_FORCE_2500;
Eric Dumazetc70798572009-11-02 23:17:42 +00001533 } else {
1534 return;
Michael Chan605a9e22007-05-03 13:23:13 -07001535 }
1536
Michael Chancbd68902010-06-08 07:21:30 +00001537 if (err)
1538 return;
1539
Michael Chan605a9e22007-05-03 13:23:13 -07001540 if (bp->autoneg & AUTONEG_SPEED)
1541 bmcr |= BMCR_SPEED1000 | BMCR_ANENABLE | BMCR_ANRESTART;
1542 bnx2_write_phy(bp, bp->mii_bmcr, bmcr);
1543}
1544
Michael Chanb2fadea2008-01-21 17:07:06 -08001545static void
1546bnx2_5706s_force_link_dn(struct bnx2 *bp, int start)
1547{
1548 u32 val;
1549
1550 bnx2_write_phy(bp, MII_BNX2_DSP_ADDRESS, MII_EXPAND_SERDES_CTL);
1551 bnx2_read_phy(bp, MII_BNX2_DSP_RW_PORT, &val);
1552 if (start)
1553 bnx2_write_phy(bp, MII_BNX2_DSP_RW_PORT, val & 0xff0f);
1554 else
1555 bnx2_write_phy(bp, MII_BNX2_DSP_RW_PORT, val | 0xc0);
1556}
1557
Michael Chan605a9e22007-05-03 13:23:13 -07001558static int
Michael Chanb6016b72005-05-26 13:03:09 -07001559bnx2_set_link(struct bnx2 *bp)
1560{
1561 u32 bmsr;
1562 u8 link_up;
1563
Michael Chan80be4432006-11-19 14:07:28 -08001564 if (bp->loopback == MAC_LOOPBACK || bp->loopback == PHY_LOOPBACK) {
Michael Chanb6016b72005-05-26 13:03:09 -07001565 bp->link_up = 1;
1566 return 0;
1567 }
1568
Michael Chan583c28e2008-01-21 19:51:35 -08001569 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
Michael Chan0d8a6572007-07-07 22:49:43 -07001570 return 0;
1571
Michael Chanb6016b72005-05-26 13:03:09 -07001572 link_up = bp->link_up;
1573
Michael Chan27a005b2007-05-03 13:23:41 -07001574 bnx2_enable_bmsr1(bp);
1575 bnx2_read_phy(bp, bp->mii_bmsr1, &bmsr);
1576 bnx2_read_phy(bp, bp->mii_bmsr1, &bmsr);
1577 bnx2_disable_bmsr1(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07001578
Michael Chan583c28e2008-01-21 19:51:35 -08001579 if ((bp->phy_flags & BNX2_PHY_FLAG_SERDES) &&
Michael Chan4ce45e02012-12-06 10:33:10 +00001580 (BNX2_CHIP(bp) == BNX2_CHIP_5706)) {
Michael Chana2724e22008-02-23 19:47:44 -08001581 u32 val, an_dbg;
Michael Chanb6016b72005-05-26 13:03:09 -07001582
Michael Chan583c28e2008-01-21 19:51:35 -08001583 if (bp->phy_flags & BNX2_PHY_FLAG_FORCED_DOWN) {
Michael Chanb2fadea2008-01-21 17:07:06 -08001584 bnx2_5706s_force_link_dn(bp, 0);
Michael Chan583c28e2008-01-21 19:51:35 -08001585 bp->phy_flags &= ~BNX2_PHY_FLAG_FORCED_DOWN;
Michael Chanb2fadea2008-01-21 17:07:06 -08001586 }
Michael Chane503e062012-12-06 10:33:08 +00001587 val = BNX2_RD(bp, BNX2_EMAC_STATUS);
Michael Chana2724e22008-02-23 19:47:44 -08001588
1589 bnx2_write_phy(bp, MII_BNX2_MISC_SHADOW, MISC_SHDW_AN_DBG);
1590 bnx2_read_phy(bp, MII_BNX2_MISC_SHADOW, &an_dbg);
1591 bnx2_read_phy(bp, MII_BNX2_MISC_SHADOW, &an_dbg);
1592
1593 if ((val & BNX2_EMAC_STATUS_LINK) &&
1594 !(an_dbg & MISC_SHDW_AN_DBG_NOSYNC))
Michael Chanb6016b72005-05-26 13:03:09 -07001595 bmsr |= BMSR_LSTATUS;
1596 else
1597 bmsr &= ~BMSR_LSTATUS;
1598 }
1599
1600 if (bmsr & BMSR_LSTATUS) {
1601 bp->link_up = 1;
1602
Michael Chan583c28e2008-01-21 19:51:35 -08001603 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Michael Chan4ce45e02012-12-06 10:33:10 +00001604 if (BNX2_CHIP(bp) == BNX2_CHIP_5706)
Michael Chan5b0c76a2005-11-04 08:45:49 -08001605 bnx2_5706s_linkup(bp);
Michael Chan4ce45e02012-12-06 10:33:10 +00001606 else if (BNX2_CHIP(bp) == BNX2_CHIP_5708)
Michael Chan5b0c76a2005-11-04 08:45:49 -08001607 bnx2_5708s_linkup(bp);
Michael Chan4ce45e02012-12-06 10:33:10 +00001608 else if (BNX2_CHIP(bp) == BNX2_CHIP_5709)
Michael Chan27a005b2007-05-03 13:23:41 -07001609 bnx2_5709s_linkup(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07001610 }
1611 else {
1612 bnx2_copper_linkup(bp);
1613 }
1614 bnx2_resolve_flow_ctrl(bp);
1615 }
1616 else {
Michael Chan583c28e2008-01-21 19:51:35 -08001617 if ((bp->phy_flags & BNX2_PHY_FLAG_SERDES) &&
Michael Chan605a9e22007-05-03 13:23:13 -07001618 (bp->autoneg & AUTONEG_SPEED))
1619 bnx2_disable_forced_2g5(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07001620
Michael Chan583c28e2008-01-21 19:51:35 -08001621 if (bp->phy_flags & BNX2_PHY_FLAG_PARALLEL_DETECT) {
Michael Chanb2fadea2008-01-21 17:07:06 -08001622 u32 bmcr;
1623
1624 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
1625 bmcr |= BMCR_ANENABLE;
1626 bnx2_write_phy(bp, bp->mii_bmcr, bmcr);
1627
Michael Chan583c28e2008-01-21 19:51:35 -08001628 bp->phy_flags &= ~BNX2_PHY_FLAG_PARALLEL_DETECT;
Michael Chanb2fadea2008-01-21 17:07:06 -08001629 }
Michael Chanb6016b72005-05-26 13:03:09 -07001630 bp->link_up = 0;
1631 }
1632
1633 if (bp->link_up != link_up) {
1634 bnx2_report_link(bp);
1635 }
1636
1637 bnx2_set_mac_link(bp);
1638
1639 return 0;
1640}
1641
1642static int
1643bnx2_reset_phy(struct bnx2 *bp)
1644{
1645 int i;
1646 u32 reg;
1647
Michael Chanca58c3a2007-05-03 13:22:52 -07001648 bnx2_write_phy(bp, bp->mii_bmcr, BMCR_RESET);
Michael Chanb6016b72005-05-26 13:03:09 -07001649
1650#define PHY_RESET_MAX_WAIT 100
1651 for (i = 0; i < PHY_RESET_MAX_WAIT; i++) {
1652 udelay(10);
1653
Michael Chanca58c3a2007-05-03 13:22:52 -07001654 bnx2_read_phy(bp, bp->mii_bmcr, &reg);
Michael Chanb6016b72005-05-26 13:03:09 -07001655 if (!(reg & BMCR_RESET)) {
1656 udelay(20);
1657 break;
1658 }
1659 }
1660 if (i == PHY_RESET_MAX_WAIT) {
1661 return -EBUSY;
1662 }
1663 return 0;
1664}
1665
1666static u32
1667bnx2_phy_get_pause_adv(struct bnx2 *bp)
1668{
1669 u32 adv = 0;
1670
1671 if ((bp->req_flow_ctrl & (FLOW_CTRL_RX | FLOW_CTRL_TX)) ==
1672 (FLOW_CTRL_RX | FLOW_CTRL_TX)) {
1673
Michael Chan583c28e2008-01-21 19:51:35 -08001674 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Michael Chanb6016b72005-05-26 13:03:09 -07001675 adv = ADVERTISE_1000XPAUSE;
1676 }
1677 else {
1678 adv = ADVERTISE_PAUSE_CAP;
1679 }
1680 }
1681 else if (bp->req_flow_ctrl & FLOW_CTRL_TX) {
Michael Chan583c28e2008-01-21 19:51:35 -08001682 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Michael Chanb6016b72005-05-26 13:03:09 -07001683 adv = ADVERTISE_1000XPSE_ASYM;
1684 }
1685 else {
1686 adv = ADVERTISE_PAUSE_ASYM;
1687 }
1688 }
1689 else if (bp->req_flow_ctrl & FLOW_CTRL_RX) {
Michael Chan583c28e2008-01-21 19:51:35 -08001690 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Michael Chanb6016b72005-05-26 13:03:09 -07001691 adv = ADVERTISE_1000XPAUSE | ADVERTISE_1000XPSE_ASYM;
1692 }
1693 else {
1694 adv = ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM;
1695 }
1696 }
1697 return adv;
1698}
1699
Michael Chana2f13892008-07-14 22:38:23 -07001700static int bnx2_fw_sync(struct bnx2 *, u32, int, int);
Michael Chan0d8a6572007-07-07 22:49:43 -07001701
Michael Chanb6016b72005-05-26 13:03:09 -07001702static int
Michael Chan0d8a6572007-07-07 22:49:43 -07001703bnx2_setup_remote_phy(struct bnx2 *bp, u8 port)
Harvey Harrison52d07b12009-01-19 17:27:06 -08001704__releases(&bp->phy_lock)
1705__acquires(&bp->phy_lock)
Michael Chan0d8a6572007-07-07 22:49:43 -07001706{
1707 u32 speed_arg = 0, pause_adv;
1708
1709 pause_adv = bnx2_phy_get_pause_adv(bp);
1710
1711 if (bp->autoneg & AUTONEG_SPEED) {
1712 speed_arg |= BNX2_NETLINK_SET_LINK_ENABLE_AUTONEG;
1713 if (bp->advertising & ADVERTISED_10baseT_Half)
1714 speed_arg |= BNX2_NETLINK_SET_LINK_SPEED_10HALF;
1715 if (bp->advertising & ADVERTISED_10baseT_Full)
1716 speed_arg |= BNX2_NETLINK_SET_LINK_SPEED_10FULL;
1717 if (bp->advertising & ADVERTISED_100baseT_Half)
1718 speed_arg |= BNX2_NETLINK_SET_LINK_SPEED_100HALF;
1719 if (bp->advertising & ADVERTISED_100baseT_Full)
1720 speed_arg |= BNX2_NETLINK_SET_LINK_SPEED_100FULL;
1721 if (bp->advertising & ADVERTISED_1000baseT_Full)
1722 speed_arg |= BNX2_NETLINK_SET_LINK_SPEED_1GFULL;
1723 if (bp->advertising & ADVERTISED_2500baseX_Full)
1724 speed_arg |= BNX2_NETLINK_SET_LINK_SPEED_2G5FULL;
1725 } else {
1726 if (bp->req_line_speed == SPEED_2500)
1727 speed_arg = BNX2_NETLINK_SET_LINK_SPEED_2G5FULL;
1728 else if (bp->req_line_speed == SPEED_1000)
1729 speed_arg = BNX2_NETLINK_SET_LINK_SPEED_1GFULL;
1730 else if (bp->req_line_speed == SPEED_100) {
1731 if (bp->req_duplex == DUPLEX_FULL)
1732 speed_arg = BNX2_NETLINK_SET_LINK_SPEED_100FULL;
1733 else
1734 speed_arg = BNX2_NETLINK_SET_LINK_SPEED_100HALF;
1735 } else if (bp->req_line_speed == SPEED_10) {
1736 if (bp->req_duplex == DUPLEX_FULL)
1737 speed_arg = BNX2_NETLINK_SET_LINK_SPEED_10FULL;
1738 else
1739 speed_arg = BNX2_NETLINK_SET_LINK_SPEED_10HALF;
1740 }
1741 }
1742
1743 if (pause_adv & (ADVERTISE_1000XPAUSE | ADVERTISE_PAUSE_CAP))
1744 speed_arg |= BNX2_NETLINK_SET_LINK_FC_SYM_PAUSE;
Michael Chanc26736e2008-01-31 17:07:21 -08001745 if (pause_adv & (ADVERTISE_1000XPSE_ASYM | ADVERTISE_PAUSE_ASYM))
Michael Chan0d8a6572007-07-07 22:49:43 -07001746 speed_arg |= BNX2_NETLINK_SET_LINK_FC_ASYM_PAUSE;
1747
1748 if (port == PORT_TP)
1749 speed_arg |= BNX2_NETLINK_SET_LINK_PHY_APP_REMOTE |
1750 BNX2_NETLINK_SET_LINK_ETH_AT_WIRESPEED;
1751
Michael Chan2726d6e2008-01-29 21:35:05 -08001752 bnx2_shmem_wr(bp, BNX2_DRV_MB_ARG0, speed_arg);
Michael Chan0d8a6572007-07-07 22:49:43 -07001753
1754 spin_unlock_bh(&bp->phy_lock);
Michael Chana2f13892008-07-14 22:38:23 -07001755 bnx2_fw_sync(bp, BNX2_DRV_MSG_CODE_CMD_SET_LINK, 1, 0);
Michael Chan0d8a6572007-07-07 22:49:43 -07001756 spin_lock_bh(&bp->phy_lock);
1757
1758 return 0;
1759}
1760
1761static int
1762bnx2_setup_serdes_phy(struct bnx2 *bp, u8 port)
Harvey Harrison52d07b12009-01-19 17:27:06 -08001763__releases(&bp->phy_lock)
1764__acquires(&bp->phy_lock)
Michael Chanb6016b72005-05-26 13:03:09 -07001765{
Michael Chan605a9e22007-05-03 13:23:13 -07001766 u32 adv, bmcr;
Michael Chanb6016b72005-05-26 13:03:09 -07001767 u32 new_adv = 0;
1768
Michael Chan583c28e2008-01-21 19:51:35 -08001769 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
Eric Dumazet807540b2010-09-23 05:40:09 +00001770 return bnx2_setup_remote_phy(bp, port);
Michael Chan0d8a6572007-07-07 22:49:43 -07001771
Michael Chanb6016b72005-05-26 13:03:09 -07001772 if (!(bp->autoneg & AUTONEG_SPEED)) {
1773 u32 new_bmcr;
Michael Chan5b0c76a2005-11-04 08:45:49 -08001774 int force_link_down = 0;
1775
Michael Chan605a9e22007-05-03 13:23:13 -07001776 if (bp->req_line_speed == SPEED_2500) {
1777 if (!bnx2_test_and_enable_2g5(bp))
1778 force_link_down = 1;
1779 } else if (bp->req_line_speed == SPEED_1000) {
1780 if (bnx2_test_and_disable_2g5(bp))
1781 force_link_down = 1;
1782 }
Michael Chanca58c3a2007-05-03 13:22:52 -07001783 bnx2_read_phy(bp, bp->mii_adv, &adv);
Michael Chan80be4432006-11-19 14:07:28 -08001784 adv &= ~(ADVERTISE_1000XFULL | ADVERTISE_1000XHALF);
1785
Michael Chanca58c3a2007-05-03 13:22:52 -07001786 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chan605a9e22007-05-03 13:23:13 -07001787 new_bmcr = bmcr & ~BMCR_ANENABLE;
Michael Chan80be4432006-11-19 14:07:28 -08001788 new_bmcr |= BMCR_SPEED1000;
Michael Chan605a9e22007-05-03 13:23:13 -07001789
Michael Chan4ce45e02012-12-06 10:33:10 +00001790 if (BNX2_CHIP(bp) == BNX2_CHIP_5709) {
Michael Chan27a005b2007-05-03 13:23:41 -07001791 if (bp->req_line_speed == SPEED_2500)
1792 bnx2_enable_forced_2g5(bp);
1793 else if (bp->req_line_speed == SPEED_1000) {
1794 bnx2_disable_forced_2g5(bp);
1795 new_bmcr &= ~0x2000;
1796 }
1797
Michael Chan4ce45e02012-12-06 10:33:10 +00001798 } else if (BNX2_CHIP(bp) == BNX2_CHIP_5708) {
Michael Chan605a9e22007-05-03 13:23:13 -07001799 if (bp->req_line_speed == SPEED_2500)
1800 new_bmcr |= BCM5708S_BMCR_FORCE_2500;
1801 else
1802 new_bmcr = bmcr & ~BCM5708S_BMCR_FORCE_2500;
Michael Chan5b0c76a2005-11-04 08:45:49 -08001803 }
1804
Michael Chanb6016b72005-05-26 13:03:09 -07001805 if (bp->req_duplex == DUPLEX_FULL) {
Michael Chan5b0c76a2005-11-04 08:45:49 -08001806 adv |= ADVERTISE_1000XFULL;
Michael Chanb6016b72005-05-26 13:03:09 -07001807 new_bmcr |= BMCR_FULLDPLX;
1808 }
1809 else {
Michael Chan5b0c76a2005-11-04 08:45:49 -08001810 adv |= ADVERTISE_1000XHALF;
Michael Chanb6016b72005-05-26 13:03:09 -07001811 new_bmcr &= ~BMCR_FULLDPLX;
1812 }
Michael Chan5b0c76a2005-11-04 08:45:49 -08001813 if ((new_bmcr != bmcr) || (force_link_down)) {
Michael Chanb6016b72005-05-26 13:03:09 -07001814 /* Force a link down visible on the other side */
1815 if (bp->link_up) {
Michael Chanca58c3a2007-05-03 13:22:52 -07001816 bnx2_write_phy(bp, bp->mii_adv, adv &
Michael Chan5b0c76a2005-11-04 08:45:49 -08001817 ~(ADVERTISE_1000XFULL |
1818 ADVERTISE_1000XHALF));
Michael Chanca58c3a2007-05-03 13:22:52 -07001819 bnx2_write_phy(bp, bp->mii_bmcr, bmcr |
Michael Chanb6016b72005-05-26 13:03:09 -07001820 BMCR_ANRESTART | BMCR_ANENABLE);
1821
1822 bp->link_up = 0;
1823 netif_carrier_off(bp->dev);
Michael Chanca58c3a2007-05-03 13:22:52 -07001824 bnx2_write_phy(bp, bp->mii_bmcr, new_bmcr);
Michael Chan80be4432006-11-19 14:07:28 -08001825 bnx2_report_link(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07001826 }
Michael Chanca58c3a2007-05-03 13:22:52 -07001827 bnx2_write_phy(bp, bp->mii_adv, adv);
1828 bnx2_write_phy(bp, bp->mii_bmcr, new_bmcr);
Michael Chan605a9e22007-05-03 13:23:13 -07001829 } else {
1830 bnx2_resolve_flow_ctrl(bp);
1831 bnx2_set_mac_link(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07001832 }
1833 return 0;
1834 }
1835
Michael Chan605a9e22007-05-03 13:23:13 -07001836 bnx2_test_and_enable_2g5(bp);
Michael Chan5b0c76a2005-11-04 08:45:49 -08001837
Michael Chanb6016b72005-05-26 13:03:09 -07001838 if (bp->advertising & ADVERTISED_1000baseT_Full)
1839 new_adv |= ADVERTISE_1000XFULL;
1840
1841 new_adv |= bnx2_phy_get_pause_adv(bp);
1842
Michael Chanca58c3a2007-05-03 13:22:52 -07001843 bnx2_read_phy(bp, bp->mii_adv, &adv);
1844 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chanb6016b72005-05-26 13:03:09 -07001845
1846 bp->serdes_an_pending = 0;
1847 if ((adv != new_adv) || ((bmcr & BMCR_ANENABLE) == 0)) {
1848 /* Force a link down visible on the other side */
1849 if (bp->link_up) {
Michael Chanca58c3a2007-05-03 13:22:52 -07001850 bnx2_write_phy(bp, bp->mii_bmcr, BMCR_LOOPBACK);
Michael Chan80be4432006-11-19 14:07:28 -08001851 spin_unlock_bh(&bp->phy_lock);
1852 msleep(20);
1853 spin_lock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07001854 }
1855
Michael Chanca58c3a2007-05-03 13:22:52 -07001856 bnx2_write_phy(bp, bp->mii_adv, new_adv);
1857 bnx2_write_phy(bp, bp->mii_bmcr, bmcr | BMCR_ANRESTART |
Michael Chanb6016b72005-05-26 13:03:09 -07001858 BMCR_ANENABLE);
Michael Chanf8dd0642006-11-19 14:08:29 -08001859 /* Speed up link-up time when the link partner
1860 * does not autonegotiate which is very common
1861 * in blade servers. Some blade servers use
1862 * IPMI for kerboard input and it's important
1863 * to minimize link disruptions. Autoneg. involves
1864 * exchanging base pages plus 3 next pages and
1865 * normally completes in about 120 msec.
1866 */
Michael Chan40105c02008-11-12 16:02:45 -08001867 bp->current_interval = BNX2_SERDES_AN_TIMEOUT;
Michael Chanf8dd0642006-11-19 14:08:29 -08001868 bp->serdes_an_pending = 1;
1869 mod_timer(&bp->timer, jiffies + bp->current_interval);
Michael Chan605a9e22007-05-03 13:23:13 -07001870 } else {
1871 bnx2_resolve_flow_ctrl(bp);
1872 bnx2_set_mac_link(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07001873 }
1874
1875 return 0;
1876}
1877
1878#define ETHTOOL_ALL_FIBRE_SPEED \
Michael Chan583c28e2008-01-21 19:51:35 -08001879 (bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE) ? \
Michael Chandeaf3912007-07-07 22:48:00 -07001880 (ADVERTISED_2500baseX_Full | ADVERTISED_1000baseT_Full) :\
1881 (ADVERTISED_1000baseT_Full)
Michael Chanb6016b72005-05-26 13:03:09 -07001882
1883#define ETHTOOL_ALL_COPPER_SPEED \
1884 (ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full | \
1885 ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full | \
1886 ADVERTISED_1000baseT_Full)
1887
1888#define PHY_ALL_10_100_SPEED (ADVERTISE_10HALF | ADVERTISE_10FULL | \
1889 ADVERTISE_100HALF | ADVERTISE_100FULL | ADVERTISE_CSMA)
Jeff Garzik6aa20a22006-09-13 13:24:59 -04001890
Michael Chanb6016b72005-05-26 13:03:09 -07001891#define PHY_ALL_1000_SPEED (ADVERTISE_1000HALF | ADVERTISE_1000FULL)
1892
Michael Chandeaf3912007-07-07 22:48:00 -07001893static void
Michael Chan0d8a6572007-07-07 22:49:43 -07001894bnx2_set_default_remote_link(struct bnx2 *bp)
1895{
1896 u32 link;
1897
1898 if (bp->phy_port == PORT_TP)
Michael Chan2726d6e2008-01-29 21:35:05 -08001899 link = bnx2_shmem_rd(bp, BNX2_RPHY_COPPER_LINK);
Michael Chan0d8a6572007-07-07 22:49:43 -07001900 else
Michael Chan2726d6e2008-01-29 21:35:05 -08001901 link = bnx2_shmem_rd(bp, BNX2_RPHY_SERDES_LINK);
Michael Chan0d8a6572007-07-07 22:49:43 -07001902
1903 if (link & BNX2_NETLINK_SET_LINK_ENABLE_AUTONEG) {
1904 bp->req_line_speed = 0;
1905 bp->autoneg |= AUTONEG_SPEED;
1906 bp->advertising = ADVERTISED_Autoneg;
1907 if (link & BNX2_NETLINK_SET_LINK_SPEED_10HALF)
1908 bp->advertising |= ADVERTISED_10baseT_Half;
1909 if (link & BNX2_NETLINK_SET_LINK_SPEED_10FULL)
1910 bp->advertising |= ADVERTISED_10baseT_Full;
1911 if (link & BNX2_NETLINK_SET_LINK_SPEED_100HALF)
1912 bp->advertising |= ADVERTISED_100baseT_Half;
1913 if (link & BNX2_NETLINK_SET_LINK_SPEED_100FULL)
1914 bp->advertising |= ADVERTISED_100baseT_Full;
1915 if (link & BNX2_NETLINK_SET_LINK_SPEED_1GFULL)
1916 bp->advertising |= ADVERTISED_1000baseT_Full;
1917 if (link & BNX2_NETLINK_SET_LINK_SPEED_2G5FULL)
1918 bp->advertising |= ADVERTISED_2500baseX_Full;
1919 } else {
1920 bp->autoneg = 0;
1921 bp->advertising = 0;
1922 bp->req_duplex = DUPLEX_FULL;
1923 if (link & BNX2_NETLINK_SET_LINK_SPEED_10) {
1924 bp->req_line_speed = SPEED_10;
1925 if (link & BNX2_NETLINK_SET_LINK_SPEED_10HALF)
1926 bp->req_duplex = DUPLEX_HALF;
1927 }
1928 if (link & BNX2_NETLINK_SET_LINK_SPEED_100) {
1929 bp->req_line_speed = SPEED_100;
1930 if (link & BNX2_NETLINK_SET_LINK_SPEED_100HALF)
1931 bp->req_duplex = DUPLEX_HALF;
1932 }
1933 if (link & BNX2_NETLINK_SET_LINK_SPEED_1GFULL)
1934 bp->req_line_speed = SPEED_1000;
1935 if (link & BNX2_NETLINK_SET_LINK_SPEED_2G5FULL)
1936 bp->req_line_speed = SPEED_2500;
1937 }
1938}
1939
1940static void
Michael Chandeaf3912007-07-07 22:48:00 -07001941bnx2_set_default_link(struct bnx2 *bp)
1942{
Harvey Harrisonab598592008-05-01 02:47:38 -07001943 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP) {
1944 bnx2_set_default_remote_link(bp);
1945 return;
1946 }
Michael Chan0d8a6572007-07-07 22:49:43 -07001947
Michael Chandeaf3912007-07-07 22:48:00 -07001948 bp->autoneg = AUTONEG_SPEED | AUTONEG_FLOW_CTRL;
1949 bp->req_line_speed = 0;
Michael Chan583c28e2008-01-21 19:51:35 -08001950 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Michael Chandeaf3912007-07-07 22:48:00 -07001951 u32 reg;
1952
1953 bp->advertising = ETHTOOL_ALL_FIBRE_SPEED | ADVERTISED_Autoneg;
1954
Michael Chan2726d6e2008-01-29 21:35:05 -08001955 reg = bnx2_shmem_rd(bp, BNX2_PORT_HW_CFG_CONFIG);
Michael Chandeaf3912007-07-07 22:48:00 -07001956 reg &= BNX2_PORT_HW_CFG_CFG_DFLT_LINK_MASK;
1957 if (reg == BNX2_PORT_HW_CFG_CFG_DFLT_LINK_1G) {
1958 bp->autoneg = 0;
1959 bp->req_line_speed = bp->line_speed = SPEED_1000;
1960 bp->req_duplex = DUPLEX_FULL;
1961 }
1962 } else
1963 bp->advertising = ETHTOOL_ALL_COPPER_SPEED | ADVERTISED_Autoneg;
1964}
1965
Michael Chan0d8a6572007-07-07 22:49:43 -07001966static void
Michael Chandf149d72007-07-07 22:51:36 -07001967bnx2_send_heart_beat(struct bnx2 *bp)
1968{
1969 u32 msg;
1970 u32 addr;
1971
1972 spin_lock(&bp->indirect_lock);
1973 msg = (u32) (++bp->fw_drv_pulse_wr_seq & BNX2_DRV_PULSE_SEQ_MASK);
1974 addr = bp->shmem_base + BNX2_DRV_PULSE_MB;
Michael Chane503e062012-12-06 10:33:08 +00001975 BNX2_WR(bp, BNX2_PCICFG_REG_WINDOW_ADDRESS, addr);
1976 BNX2_WR(bp, BNX2_PCICFG_REG_WINDOW, msg);
Michael Chandf149d72007-07-07 22:51:36 -07001977 spin_unlock(&bp->indirect_lock);
1978}
1979
1980static void
Michael Chan0d8a6572007-07-07 22:49:43 -07001981bnx2_remote_phy_event(struct bnx2 *bp)
1982{
1983 u32 msg;
1984 u8 link_up = bp->link_up;
1985 u8 old_port;
1986
Michael Chan2726d6e2008-01-29 21:35:05 -08001987 msg = bnx2_shmem_rd(bp, BNX2_LINK_STATUS);
Michael Chan0d8a6572007-07-07 22:49:43 -07001988
Michael Chandf149d72007-07-07 22:51:36 -07001989 if (msg & BNX2_LINK_STATUS_HEART_BEAT_EXPIRED)
1990 bnx2_send_heart_beat(bp);
1991
1992 msg &= ~BNX2_LINK_STATUS_HEART_BEAT_EXPIRED;
1993
Michael Chan0d8a6572007-07-07 22:49:43 -07001994 if ((msg & BNX2_LINK_STATUS_LINK_UP) == BNX2_LINK_STATUS_LINK_DOWN)
1995 bp->link_up = 0;
1996 else {
1997 u32 speed;
1998
1999 bp->link_up = 1;
2000 speed = msg & BNX2_LINK_STATUS_SPEED_MASK;
2001 bp->duplex = DUPLEX_FULL;
2002 switch (speed) {
2003 case BNX2_LINK_STATUS_10HALF:
2004 bp->duplex = DUPLEX_HALF;
Michael Chan7947c9c2012-06-27 15:08:23 +00002005 /* fall through */
Michael Chan0d8a6572007-07-07 22:49:43 -07002006 case BNX2_LINK_STATUS_10FULL:
2007 bp->line_speed = SPEED_10;
2008 break;
2009 case BNX2_LINK_STATUS_100HALF:
2010 bp->duplex = DUPLEX_HALF;
Michael Chan7947c9c2012-06-27 15:08:23 +00002011 /* fall through */
Michael Chan0d8a6572007-07-07 22:49:43 -07002012 case BNX2_LINK_STATUS_100BASE_T4:
2013 case BNX2_LINK_STATUS_100FULL:
2014 bp->line_speed = SPEED_100;
2015 break;
2016 case BNX2_LINK_STATUS_1000HALF:
2017 bp->duplex = DUPLEX_HALF;
Michael Chan7947c9c2012-06-27 15:08:23 +00002018 /* fall through */
Michael Chan0d8a6572007-07-07 22:49:43 -07002019 case BNX2_LINK_STATUS_1000FULL:
2020 bp->line_speed = SPEED_1000;
2021 break;
2022 case BNX2_LINK_STATUS_2500HALF:
2023 bp->duplex = DUPLEX_HALF;
Michael Chan7947c9c2012-06-27 15:08:23 +00002024 /* fall through */
Michael Chan0d8a6572007-07-07 22:49:43 -07002025 case BNX2_LINK_STATUS_2500FULL:
2026 bp->line_speed = SPEED_2500;
2027 break;
2028 default:
2029 bp->line_speed = 0;
2030 break;
2031 }
2032
Michael Chan0d8a6572007-07-07 22:49:43 -07002033 bp->flow_ctrl = 0;
2034 if ((bp->autoneg & (AUTONEG_SPEED | AUTONEG_FLOW_CTRL)) !=
2035 (AUTONEG_SPEED | AUTONEG_FLOW_CTRL)) {
2036 if (bp->duplex == DUPLEX_FULL)
2037 bp->flow_ctrl = bp->req_flow_ctrl;
2038 } else {
2039 if (msg & BNX2_LINK_STATUS_TX_FC_ENABLED)
2040 bp->flow_ctrl |= FLOW_CTRL_TX;
2041 if (msg & BNX2_LINK_STATUS_RX_FC_ENABLED)
2042 bp->flow_ctrl |= FLOW_CTRL_RX;
2043 }
2044
2045 old_port = bp->phy_port;
2046 if (msg & BNX2_LINK_STATUS_SERDES_LINK)
2047 bp->phy_port = PORT_FIBRE;
2048 else
2049 bp->phy_port = PORT_TP;
2050
2051 if (old_port != bp->phy_port)
2052 bnx2_set_default_link(bp);
2053
Michael Chan0d8a6572007-07-07 22:49:43 -07002054 }
2055 if (bp->link_up != link_up)
2056 bnx2_report_link(bp);
2057
2058 bnx2_set_mac_link(bp);
2059}
2060
2061static int
2062bnx2_set_remote_link(struct bnx2 *bp)
2063{
2064 u32 evt_code;
2065
Michael Chan2726d6e2008-01-29 21:35:05 -08002066 evt_code = bnx2_shmem_rd(bp, BNX2_FW_EVT_CODE_MB);
Michael Chan0d8a6572007-07-07 22:49:43 -07002067 switch (evt_code) {
2068 case BNX2_FW_EVT_CODE_LINK_EVENT:
2069 bnx2_remote_phy_event(bp);
2070 break;
2071 case BNX2_FW_EVT_CODE_SW_TIMER_EXPIRATION_EVENT:
2072 default:
Michael Chandf149d72007-07-07 22:51:36 -07002073 bnx2_send_heart_beat(bp);
Michael Chan0d8a6572007-07-07 22:49:43 -07002074 break;
2075 }
2076 return 0;
2077}
2078
Michael Chanb6016b72005-05-26 13:03:09 -07002079static int
2080bnx2_setup_copper_phy(struct bnx2 *bp)
Harvey Harrison52d07b12009-01-19 17:27:06 -08002081__releases(&bp->phy_lock)
2082__acquires(&bp->phy_lock)
Michael Chanb6016b72005-05-26 13:03:09 -07002083{
Michael Chand17e53b2013-12-31 23:22:32 -08002084 u32 bmcr, adv_reg, new_adv = 0;
Michael Chanb6016b72005-05-26 13:03:09 -07002085 u32 new_bmcr;
2086
Michael Chanca58c3a2007-05-03 13:22:52 -07002087 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chanb6016b72005-05-26 13:03:09 -07002088
Michael Chand17e53b2013-12-31 23:22:32 -08002089 bnx2_read_phy(bp, bp->mii_adv, &adv_reg);
2090 adv_reg &= (PHY_ALL_10_100_SPEED | ADVERTISE_PAUSE_CAP |
2091 ADVERTISE_PAUSE_ASYM);
2092
2093 new_adv = ADVERTISE_CSMA | ethtool_adv_to_mii_adv_t(bp->advertising);
2094
Michael Chanb6016b72005-05-26 13:03:09 -07002095 if (bp->autoneg & AUTONEG_SPEED) {
Michael Chand17e53b2013-12-31 23:22:32 -08002096 u32 adv1000_reg;
Matt Carlson37f07022011-11-17 14:30:55 +00002097 u32 new_adv1000 = 0;
Michael Chanb6016b72005-05-26 13:03:09 -07002098
Michael Chand17e53b2013-12-31 23:22:32 -08002099 new_adv |= bnx2_phy_get_pause_adv(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07002100
2101 bnx2_read_phy(bp, MII_CTRL1000, &adv1000_reg);
2102 adv1000_reg &= PHY_ALL_1000_SPEED;
2103
Matt Carlson37f07022011-11-17 14:30:55 +00002104 new_adv1000 |= ethtool_adv_to_mii_ctrl1000_t(bp->advertising);
Matt Carlson37f07022011-11-17 14:30:55 +00002105 if ((adv1000_reg != new_adv1000) ||
2106 (adv_reg != new_adv) ||
Michael Chanb6016b72005-05-26 13:03:09 -07002107 ((bmcr & BMCR_ANENABLE) == 0)) {
2108
Matt Carlson37f07022011-11-17 14:30:55 +00002109 bnx2_write_phy(bp, bp->mii_adv, new_adv);
2110 bnx2_write_phy(bp, MII_CTRL1000, new_adv1000);
Michael Chanca58c3a2007-05-03 13:22:52 -07002111 bnx2_write_phy(bp, bp->mii_bmcr, BMCR_ANRESTART |
Michael Chanb6016b72005-05-26 13:03:09 -07002112 BMCR_ANENABLE);
2113 }
2114 else if (bp->link_up) {
2115 /* Flow ctrl may have changed from auto to forced */
2116 /* or vice-versa. */
2117
2118 bnx2_resolve_flow_ctrl(bp);
2119 bnx2_set_mac_link(bp);
2120 }
2121 return 0;
2122 }
2123
Michael Chand17e53b2013-12-31 23:22:32 -08002124 /* advertise nothing when forcing speed */
2125 if (adv_reg != new_adv)
2126 bnx2_write_phy(bp, bp->mii_adv, new_adv);
2127
Michael Chanb6016b72005-05-26 13:03:09 -07002128 new_bmcr = 0;
2129 if (bp->req_line_speed == SPEED_100) {
2130 new_bmcr |= BMCR_SPEED100;
2131 }
2132 if (bp->req_duplex == DUPLEX_FULL) {
2133 new_bmcr |= BMCR_FULLDPLX;
2134 }
2135 if (new_bmcr != bmcr) {
2136 u32 bmsr;
Michael Chanb6016b72005-05-26 13:03:09 -07002137
Michael Chanca58c3a2007-05-03 13:22:52 -07002138 bnx2_read_phy(bp, bp->mii_bmsr, &bmsr);
2139 bnx2_read_phy(bp, bp->mii_bmsr, &bmsr);
Jeff Garzik6aa20a22006-09-13 13:24:59 -04002140
Michael Chanb6016b72005-05-26 13:03:09 -07002141 if (bmsr & BMSR_LSTATUS) {
2142 /* Force link down */
Michael Chanca58c3a2007-05-03 13:22:52 -07002143 bnx2_write_phy(bp, bp->mii_bmcr, BMCR_LOOPBACK);
Michael Chana16dda02006-11-19 14:08:56 -08002144 spin_unlock_bh(&bp->phy_lock);
2145 msleep(50);
2146 spin_lock_bh(&bp->phy_lock);
2147
Michael Chanca58c3a2007-05-03 13:22:52 -07002148 bnx2_read_phy(bp, bp->mii_bmsr, &bmsr);
2149 bnx2_read_phy(bp, bp->mii_bmsr, &bmsr);
Michael Chanb6016b72005-05-26 13:03:09 -07002150 }
2151
Michael Chanca58c3a2007-05-03 13:22:52 -07002152 bnx2_write_phy(bp, bp->mii_bmcr, new_bmcr);
Michael Chanb6016b72005-05-26 13:03:09 -07002153
2154 /* Normally, the new speed is setup after the link has
2155 * gone down and up again. In some cases, link will not go
2156 * down so we need to set up the new speed here.
2157 */
2158 if (bmsr & BMSR_LSTATUS) {
2159 bp->line_speed = bp->req_line_speed;
2160 bp->duplex = bp->req_duplex;
2161 bnx2_resolve_flow_ctrl(bp);
2162 bnx2_set_mac_link(bp);
2163 }
Michael Chan27a005b2007-05-03 13:23:41 -07002164 } else {
2165 bnx2_resolve_flow_ctrl(bp);
2166 bnx2_set_mac_link(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07002167 }
2168 return 0;
2169}
2170
2171static int
Michael Chan0d8a6572007-07-07 22:49:43 -07002172bnx2_setup_phy(struct bnx2 *bp, u8 port)
Harvey Harrison52d07b12009-01-19 17:27:06 -08002173__releases(&bp->phy_lock)
2174__acquires(&bp->phy_lock)
Michael Chanb6016b72005-05-26 13:03:09 -07002175{
2176 if (bp->loopback == MAC_LOOPBACK)
2177 return 0;
2178
Michael Chan583c28e2008-01-21 19:51:35 -08002179 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Eric Dumazet807540b2010-09-23 05:40:09 +00002180 return bnx2_setup_serdes_phy(bp, port);
Michael Chanb6016b72005-05-26 13:03:09 -07002181 }
2182 else {
Eric Dumazet807540b2010-09-23 05:40:09 +00002183 return bnx2_setup_copper_phy(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07002184 }
2185}
2186
2187static int
Michael Chan9a120bc2008-05-16 22:17:45 -07002188bnx2_init_5709s_phy(struct bnx2 *bp, int reset_phy)
Michael Chan27a005b2007-05-03 13:23:41 -07002189{
2190 u32 val;
2191
2192 bp->mii_bmcr = MII_BMCR + 0x10;
2193 bp->mii_bmsr = MII_BMSR + 0x10;
2194 bp->mii_bmsr1 = MII_BNX2_GP_TOP_AN_STATUS1;
2195 bp->mii_adv = MII_ADVERTISE + 0x10;
2196 bp->mii_lpa = MII_LPA + 0x10;
2197 bp->mii_up1 = MII_BNX2_OVER1G_UP1;
2198
2199 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_AER);
2200 bnx2_write_phy(bp, MII_BNX2_AER_AER, MII_BNX2_AER_AER_AN_MMD);
2201
2202 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
Michael Chan9a120bc2008-05-16 22:17:45 -07002203 if (reset_phy)
2204 bnx2_reset_phy(bp);
Michael Chan27a005b2007-05-03 13:23:41 -07002205
2206 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_SERDES_DIG);
2207
2208 bnx2_read_phy(bp, MII_BNX2_SERDES_DIG_1000XCTL1, &val);
2209 val &= ~MII_BNX2_SD_1000XCTL1_AUTODET;
2210 val |= MII_BNX2_SD_1000XCTL1_FIBER;
2211 bnx2_write_phy(bp, MII_BNX2_SERDES_DIG_1000XCTL1, val);
2212
2213 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_OVER1G);
2214 bnx2_read_phy(bp, MII_BNX2_OVER1G_UP1, &val);
Michael Chan583c28e2008-01-21 19:51:35 -08002215 if (bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE)
Michael Chan27a005b2007-05-03 13:23:41 -07002216 val |= BCM5708S_UP1_2G5;
2217 else
2218 val &= ~BCM5708S_UP1_2G5;
2219 bnx2_write_phy(bp, MII_BNX2_OVER1G_UP1, val);
2220
2221 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_BAM_NXTPG);
2222 bnx2_read_phy(bp, MII_BNX2_BAM_NXTPG_CTL, &val);
2223 val |= MII_BNX2_NXTPG_CTL_T2 | MII_BNX2_NXTPG_CTL_BAM;
2224 bnx2_write_phy(bp, MII_BNX2_BAM_NXTPG_CTL, val);
2225
2226 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_CL73_USERB0);
2227
2228 val = MII_BNX2_CL73_BAM_EN | MII_BNX2_CL73_BAM_STA_MGR_EN |
2229 MII_BNX2_CL73_BAM_NP_AFT_BP_EN;
2230 bnx2_write_phy(bp, MII_BNX2_CL73_BAM_CTL1, val);
2231
2232 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
2233
2234 return 0;
2235}
2236
2237static int
Michael Chan9a120bc2008-05-16 22:17:45 -07002238bnx2_init_5708s_phy(struct bnx2 *bp, int reset_phy)
Michael Chan5b0c76a2005-11-04 08:45:49 -08002239{
2240 u32 val;
2241
Michael Chan9a120bc2008-05-16 22:17:45 -07002242 if (reset_phy)
2243 bnx2_reset_phy(bp);
Michael Chan27a005b2007-05-03 13:23:41 -07002244
2245 bp->mii_up1 = BCM5708S_UP1;
2246
Michael Chan5b0c76a2005-11-04 08:45:49 -08002247 bnx2_write_phy(bp, BCM5708S_BLK_ADDR, BCM5708S_BLK_ADDR_DIG3);
2248 bnx2_write_phy(bp, BCM5708S_DIG_3_0, BCM5708S_DIG_3_0_USE_IEEE);
2249 bnx2_write_phy(bp, BCM5708S_BLK_ADDR, BCM5708S_BLK_ADDR_DIG);
2250
2251 bnx2_read_phy(bp, BCM5708S_1000X_CTL1, &val);
2252 val |= BCM5708S_1000X_CTL1_FIBER_MODE | BCM5708S_1000X_CTL1_AUTODET_EN;
2253 bnx2_write_phy(bp, BCM5708S_1000X_CTL1, val);
2254
2255 bnx2_read_phy(bp, BCM5708S_1000X_CTL2, &val);
2256 val |= BCM5708S_1000X_CTL2_PLLEL_DET_EN;
2257 bnx2_write_phy(bp, BCM5708S_1000X_CTL2, val);
2258
Michael Chan583c28e2008-01-21 19:51:35 -08002259 if (bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE) {
Michael Chan5b0c76a2005-11-04 08:45:49 -08002260 bnx2_read_phy(bp, BCM5708S_UP1, &val);
2261 val |= BCM5708S_UP1_2G5;
2262 bnx2_write_phy(bp, BCM5708S_UP1, val);
2263 }
2264
Michael Chan4ce45e02012-12-06 10:33:10 +00002265 if ((BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5708_A0) ||
2266 (BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5708_B0) ||
2267 (BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5708_B1)) {
Michael Chan5b0c76a2005-11-04 08:45:49 -08002268 /* increase tx signal amplitude */
2269 bnx2_write_phy(bp, BCM5708S_BLK_ADDR,
2270 BCM5708S_BLK_ADDR_TX_MISC);
2271 bnx2_read_phy(bp, BCM5708S_TX_ACTL1, &val);
2272 val &= ~BCM5708S_TX_ACTL1_DRIVER_VCM;
2273 bnx2_write_phy(bp, BCM5708S_TX_ACTL1, val);
2274 bnx2_write_phy(bp, BCM5708S_BLK_ADDR, BCM5708S_BLK_ADDR_DIG);
2275 }
2276
Michael Chan2726d6e2008-01-29 21:35:05 -08002277 val = bnx2_shmem_rd(bp, BNX2_PORT_HW_CFG_CONFIG) &
Michael Chan5b0c76a2005-11-04 08:45:49 -08002278 BNX2_PORT_HW_CFG_CFG_TXCTL3_MASK;
2279
2280 if (val) {
2281 u32 is_backplane;
2282
Michael Chan2726d6e2008-01-29 21:35:05 -08002283 is_backplane = bnx2_shmem_rd(bp, BNX2_SHARED_HW_CFG_CONFIG);
Michael Chan5b0c76a2005-11-04 08:45:49 -08002284 if (is_backplane & BNX2_SHARED_HW_CFG_PHY_BACKPLANE) {
2285 bnx2_write_phy(bp, BCM5708S_BLK_ADDR,
2286 BCM5708S_BLK_ADDR_TX_MISC);
2287 bnx2_write_phy(bp, BCM5708S_TX_ACTL3, val);
2288 bnx2_write_phy(bp, BCM5708S_BLK_ADDR,
2289 BCM5708S_BLK_ADDR_DIG);
2290 }
2291 }
2292 return 0;
2293}
2294
2295static int
Michael Chan9a120bc2008-05-16 22:17:45 -07002296bnx2_init_5706s_phy(struct bnx2 *bp, int reset_phy)
Michael Chanb6016b72005-05-26 13:03:09 -07002297{
Michael Chan9a120bc2008-05-16 22:17:45 -07002298 if (reset_phy)
2299 bnx2_reset_phy(bp);
Michael Chan27a005b2007-05-03 13:23:41 -07002300
Michael Chan583c28e2008-01-21 19:51:35 -08002301 bp->phy_flags &= ~BNX2_PHY_FLAG_PARALLEL_DETECT;
Michael Chanb6016b72005-05-26 13:03:09 -07002302
Michael Chan4ce45e02012-12-06 10:33:10 +00002303 if (BNX2_CHIP(bp) == BNX2_CHIP_5706)
Michael Chane503e062012-12-06 10:33:08 +00002304 BNX2_WR(bp, BNX2_MISC_GP_HW_CTL0, 0x300);
Michael Chanb6016b72005-05-26 13:03:09 -07002305
2306 if (bp->dev->mtu > 1500) {
2307 u32 val;
2308
2309 /* Set extended packet length bit */
2310 bnx2_write_phy(bp, 0x18, 0x7);
2311 bnx2_read_phy(bp, 0x18, &val);
2312 bnx2_write_phy(bp, 0x18, (val & 0xfff8) | 0x4000);
2313
2314 bnx2_write_phy(bp, 0x1c, 0x6c00);
2315 bnx2_read_phy(bp, 0x1c, &val);
2316 bnx2_write_phy(bp, 0x1c, (val & 0x3ff) | 0xec02);
2317 }
2318 else {
2319 u32 val;
2320
2321 bnx2_write_phy(bp, 0x18, 0x7);
2322 bnx2_read_phy(bp, 0x18, &val);
2323 bnx2_write_phy(bp, 0x18, val & ~0x4007);
2324
2325 bnx2_write_phy(bp, 0x1c, 0x6c00);
2326 bnx2_read_phy(bp, 0x1c, &val);
2327 bnx2_write_phy(bp, 0x1c, (val & 0x3fd) | 0xec00);
2328 }
2329
2330 return 0;
2331}
2332
2333static int
Michael Chan9a120bc2008-05-16 22:17:45 -07002334bnx2_init_copper_phy(struct bnx2 *bp, int reset_phy)
Michael Chanb6016b72005-05-26 13:03:09 -07002335{
Michael Chan5b0c76a2005-11-04 08:45:49 -08002336 u32 val;
2337
Michael Chan9a120bc2008-05-16 22:17:45 -07002338 if (reset_phy)
2339 bnx2_reset_phy(bp);
Michael Chan27a005b2007-05-03 13:23:41 -07002340
Michael Chan583c28e2008-01-21 19:51:35 -08002341 if (bp->phy_flags & BNX2_PHY_FLAG_CRC_FIX) {
Michael Chanb6016b72005-05-26 13:03:09 -07002342 bnx2_write_phy(bp, 0x18, 0x0c00);
2343 bnx2_write_phy(bp, 0x17, 0x000a);
2344 bnx2_write_phy(bp, 0x15, 0x310b);
2345 bnx2_write_phy(bp, 0x17, 0x201f);
2346 bnx2_write_phy(bp, 0x15, 0x9506);
2347 bnx2_write_phy(bp, 0x17, 0x401f);
2348 bnx2_write_phy(bp, 0x15, 0x14e2);
2349 bnx2_write_phy(bp, 0x18, 0x0400);
2350 }
2351
Michael Chan583c28e2008-01-21 19:51:35 -08002352 if (bp->phy_flags & BNX2_PHY_FLAG_DIS_EARLY_DAC) {
Michael Chanb659f442007-02-02 00:46:35 -08002353 bnx2_write_phy(bp, MII_BNX2_DSP_ADDRESS,
2354 MII_BNX2_DSP_EXPAND_REG | 0x8);
2355 bnx2_read_phy(bp, MII_BNX2_DSP_RW_PORT, &val);
2356 val &= ~(1 << 8);
2357 bnx2_write_phy(bp, MII_BNX2_DSP_RW_PORT, val);
2358 }
2359
Michael Chanb6016b72005-05-26 13:03:09 -07002360 if (bp->dev->mtu > 1500) {
Michael Chanb6016b72005-05-26 13:03:09 -07002361 /* Set extended packet length bit */
2362 bnx2_write_phy(bp, 0x18, 0x7);
2363 bnx2_read_phy(bp, 0x18, &val);
2364 bnx2_write_phy(bp, 0x18, val | 0x4000);
2365
2366 bnx2_read_phy(bp, 0x10, &val);
2367 bnx2_write_phy(bp, 0x10, val | 0x1);
2368 }
2369 else {
Michael Chanb6016b72005-05-26 13:03:09 -07002370 bnx2_write_phy(bp, 0x18, 0x7);
2371 bnx2_read_phy(bp, 0x18, &val);
2372 bnx2_write_phy(bp, 0x18, val & ~0x4007);
2373
2374 bnx2_read_phy(bp, 0x10, &val);
2375 bnx2_write_phy(bp, 0x10, val & ~0x1);
2376 }
2377
Michael Chan5b0c76a2005-11-04 08:45:49 -08002378 /* ethernet@wirespeed */
Michael Chan41033b62013-12-31 23:22:33 -08002379 bnx2_write_phy(bp, MII_BNX2_AUX_CTL, AUX_CTL_MISC_CTL);
2380 bnx2_read_phy(bp, MII_BNX2_AUX_CTL, &val);
2381 val |= AUX_CTL_MISC_CTL_WR | AUX_CTL_MISC_CTL_WIRESPEED;
2382
2383 /* auto-mdix */
2384 if (BNX2_CHIP(bp) == BNX2_CHIP_5709)
2385 val |= AUX_CTL_MISC_CTL_AUTOMDIX;
2386
2387 bnx2_write_phy(bp, MII_BNX2_AUX_CTL, val);
Michael Chanb6016b72005-05-26 13:03:09 -07002388 return 0;
2389}
2390
2391
2392static int
Michael Chan9a120bc2008-05-16 22:17:45 -07002393bnx2_init_phy(struct bnx2 *bp, int reset_phy)
Harvey Harrison52d07b12009-01-19 17:27:06 -08002394__releases(&bp->phy_lock)
2395__acquires(&bp->phy_lock)
Michael Chanb6016b72005-05-26 13:03:09 -07002396{
2397 u32 val;
2398 int rc = 0;
2399
Michael Chan583c28e2008-01-21 19:51:35 -08002400 bp->phy_flags &= ~BNX2_PHY_FLAG_INT_MODE_MASK;
2401 bp->phy_flags |= BNX2_PHY_FLAG_INT_MODE_LINK_READY;
Michael Chanb6016b72005-05-26 13:03:09 -07002402
Michael Chanca58c3a2007-05-03 13:22:52 -07002403 bp->mii_bmcr = MII_BMCR;
2404 bp->mii_bmsr = MII_BMSR;
Michael Chan27a005b2007-05-03 13:23:41 -07002405 bp->mii_bmsr1 = MII_BMSR;
Michael Chanca58c3a2007-05-03 13:22:52 -07002406 bp->mii_adv = MII_ADVERTISE;
2407 bp->mii_lpa = MII_LPA;
2408
Michael Chane503e062012-12-06 10:33:08 +00002409 BNX2_WR(bp, BNX2_EMAC_ATTENTION_ENA, BNX2_EMAC_ATTENTION_ENA_LINK);
Michael Chanb6016b72005-05-26 13:03:09 -07002410
Michael Chan583c28e2008-01-21 19:51:35 -08002411 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
Michael Chan0d8a6572007-07-07 22:49:43 -07002412 goto setup_phy;
2413
Michael Chanb6016b72005-05-26 13:03:09 -07002414 bnx2_read_phy(bp, MII_PHYSID1, &val);
2415 bp->phy_id = val << 16;
2416 bnx2_read_phy(bp, MII_PHYSID2, &val);
2417 bp->phy_id |= val & 0xffff;
2418
Michael Chan583c28e2008-01-21 19:51:35 -08002419 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Michael Chan4ce45e02012-12-06 10:33:10 +00002420 if (BNX2_CHIP(bp) == BNX2_CHIP_5706)
Michael Chan9a120bc2008-05-16 22:17:45 -07002421 rc = bnx2_init_5706s_phy(bp, reset_phy);
Michael Chan4ce45e02012-12-06 10:33:10 +00002422 else if (BNX2_CHIP(bp) == BNX2_CHIP_5708)
Michael Chan9a120bc2008-05-16 22:17:45 -07002423 rc = bnx2_init_5708s_phy(bp, reset_phy);
Michael Chan4ce45e02012-12-06 10:33:10 +00002424 else if (BNX2_CHIP(bp) == BNX2_CHIP_5709)
Michael Chan9a120bc2008-05-16 22:17:45 -07002425 rc = bnx2_init_5709s_phy(bp, reset_phy);
Michael Chanb6016b72005-05-26 13:03:09 -07002426 }
2427 else {
Michael Chan9a120bc2008-05-16 22:17:45 -07002428 rc = bnx2_init_copper_phy(bp, reset_phy);
Michael Chanb6016b72005-05-26 13:03:09 -07002429 }
2430
Michael Chan0d8a6572007-07-07 22:49:43 -07002431setup_phy:
2432 if (!rc)
2433 rc = bnx2_setup_phy(bp, bp->phy_port);
Michael Chanb6016b72005-05-26 13:03:09 -07002434
2435 return rc;
2436}
2437
2438static int
2439bnx2_set_mac_loopback(struct bnx2 *bp)
2440{
2441 u32 mac_mode;
2442
Michael Chane503e062012-12-06 10:33:08 +00002443 mac_mode = BNX2_RD(bp, BNX2_EMAC_MODE);
Michael Chanb6016b72005-05-26 13:03:09 -07002444 mac_mode &= ~BNX2_EMAC_MODE_PORT;
2445 mac_mode |= BNX2_EMAC_MODE_MAC_LOOP | BNX2_EMAC_MODE_FORCE_LINK;
Michael Chane503e062012-12-06 10:33:08 +00002446 BNX2_WR(bp, BNX2_EMAC_MODE, mac_mode);
Michael Chanb6016b72005-05-26 13:03:09 -07002447 bp->link_up = 1;
2448 return 0;
2449}
2450
Michael Chanbc5a0692006-01-23 16:13:22 -08002451static int bnx2_test_link(struct bnx2 *);
2452
2453static int
2454bnx2_set_phy_loopback(struct bnx2 *bp)
2455{
2456 u32 mac_mode;
2457 int rc, i;
2458
2459 spin_lock_bh(&bp->phy_lock);
Michael Chanca58c3a2007-05-03 13:22:52 -07002460 rc = bnx2_write_phy(bp, bp->mii_bmcr, BMCR_LOOPBACK | BMCR_FULLDPLX |
Michael Chanbc5a0692006-01-23 16:13:22 -08002461 BMCR_SPEED1000);
2462 spin_unlock_bh(&bp->phy_lock);
2463 if (rc)
2464 return rc;
2465
2466 for (i = 0; i < 10; i++) {
2467 if (bnx2_test_link(bp) == 0)
2468 break;
Michael Chan80be4432006-11-19 14:07:28 -08002469 msleep(100);
Michael Chanbc5a0692006-01-23 16:13:22 -08002470 }
2471
Michael Chane503e062012-12-06 10:33:08 +00002472 mac_mode = BNX2_RD(bp, BNX2_EMAC_MODE);
Michael Chanbc5a0692006-01-23 16:13:22 -08002473 mac_mode &= ~(BNX2_EMAC_MODE_PORT | BNX2_EMAC_MODE_HALF_DUPLEX |
2474 BNX2_EMAC_MODE_MAC_LOOP | BNX2_EMAC_MODE_FORCE_LINK |
Michael Chan59b47d82006-11-19 14:10:45 -08002475 BNX2_EMAC_MODE_25G_MODE);
Michael Chanbc5a0692006-01-23 16:13:22 -08002476
2477 mac_mode |= BNX2_EMAC_MODE_PORT_GMII;
Michael Chane503e062012-12-06 10:33:08 +00002478 BNX2_WR(bp, BNX2_EMAC_MODE, mac_mode);
Michael Chanbc5a0692006-01-23 16:13:22 -08002479 bp->link_up = 1;
2480 return 0;
2481}
2482
Jeffrey Huangecdbf6e2011-07-13 17:24:21 +00002483static void
2484bnx2_dump_mcp_state(struct bnx2 *bp)
2485{
2486 struct net_device *dev = bp->dev;
2487 u32 mcp_p0, mcp_p1;
2488
2489 netdev_err(dev, "<--- start MCP states dump --->\n");
Michael Chan4ce45e02012-12-06 10:33:10 +00002490 if (BNX2_CHIP(bp) == BNX2_CHIP_5709) {
Jeffrey Huangecdbf6e2011-07-13 17:24:21 +00002491 mcp_p0 = BNX2_MCP_STATE_P0;
2492 mcp_p1 = BNX2_MCP_STATE_P1;
2493 } else {
2494 mcp_p0 = BNX2_MCP_STATE_P0_5708;
2495 mcp_p1 = BNX2_MCP_STATE_P1_5708;
2496 }
2497 netdev_err(dev, "DEBUG: MCP_STATE_P0[%08x] MCP_STATE_P1[%08x]\n",
2498 bnx2_reg_rd_ind(bp, mcp_p0), bnx2_reg_rd_ind(bp, mcp_p1));
2499 netdev_err(dev, "DEBUG: MCP mode[%08x] state[%08x] evt_mask[%08x]\n",
2500 bnx2_reg_rd_ind(bp, BNX2_MCP_CPU_MODE),
2501 bnx2_reg_rd_ind(bp, BNX2_MCP_CPU_STATE),
2502 bnx2_reg_rd_ind(bp, BNX2_MCP_CPU_EVENT_MASK));
2503 netdev_err(dev, "DEBUG: pc[%08x] pc[%08x] instr[%08x]\n",
2504 bnx2_reg_rd_ind(bp, BNX2_MCP_CPU_PROGRAM_COUNTER),
2505 bnx2_reg_rd_ind(bp, BNX2_MCP_CPU_PROGRAM_COUNTER),
2506 bnx2_reg_rd_ind(bp, BNX2_MCP_CPU_INSTRUCTION));
2507 netdev_err(dev, "DEBUG: shmem states:\n");
2508 netdev_err(dev, "DEBUG: drv_mb[%08x] fw_mb[%08x] link_status[%08x]",
2509 bnx2_shmem_rd(bp, BNX2_DRV_MB),
2510 bnx2_shmem_rd(bp, BNX2_FW_MB),
2511 bnx2_shmem_rd(bp, BNX2_LINK_STATUS));
2512 pr_cont(" drv_pulse_mb[%08x]\n", bnx2_shmem_rd(bp, BNX2_DRV_PULSE_MB));
2513 netdev_err(dev, "DEBUG: dev_info_signature[%08x] reset_type[%08x]",
2514 bnx2_shmem_rd(bp, BNX2_DEV_INFO_SIGNATURE),
2515 bnx2_shmem_rd(bp, BNX2_BC_STATE_RESET_TYPE));
2516 pr_cont(" condition[%08x]\n",
2517 bnx2_shmem_rd(bp, BNX2_BC_STATE_CONDITION));
Michael Chan13e63512012-06-16 15:45:42 +00002518 DP_SHMEM_LINE(bp, BNX2_BC_RESET_TYPE);
Jeffrey Huangecdbf6e2011-07-13 17:24:21 +00002519 DP_SHMEM_LINE(bp, 0x3cc);
2520 DP_SHMEM_LINE(bp, 0x3dc);
2521 DP_SHMEM_LINE(bp, 0x3ec);
2522 netdev_err(dev, "DEBUG: 0x3fc[%08x]\n", bnx2_shmem_rd(bp, 0x3fc));
2523 netdev_err(dev, "<--- end MCP states dump --->\n");
2524}
2525
Michael Chanb6016b72005-05-26 13:03:09 -07002526static int
Michael Chana2f13892008-07-14 22:38:23 -07002527bnx2_fw_sync(struct bnx2 *bp, u32 msg_data, int ack, int silent)
Michael Chanb6016b72005-05-26 13:03:09 -07002528{
2529 int i;
2530 u32 val;
2531
Michael Chanb6016b72005-05-26 13:03:09 -07002532 bp->fw_wr_seq++;
2533 msg_data |= bp->fw_wr_seq;
Michael Chana8d9bc22014-03-09 15:45:32 -08002534 bp->fw_last_msg = msg_data;
Michael Chanb6016b72005-05-26 13:03:09 -07002535
Michael Chan2726d6e2008-01-29 21:35:05 -08002536 bnx2_shmem_wr(bp, BNX2_DRV_MB, msg_data);
Michael Chanb6016b72005-05-26 13:03:09 -07002537
Michael Chana2f13892008-07-14 22:38:23 -07002538 if (!ack)
2539 return 0;
2540
Michael Chanb6016b72005-05-26 13:03:09 -07002541 /* wait for an acknowledgement. */
Michael Chan40105c02008-11-12 16:02:45 -08002542 for (i = 0; i < (BNX2_FW_ACK_TIME_OUT_MS / 10); i++) {
Michael Chanb090ae22006-01-23 16:07:10 -08002543 msleep(10);
Michael Chanb6016b72005-05-26 13:03:09 -07002544
Michael Chan2726d6e2008-01-29 21:35:05 -08002545 val = bnx2_shmem_rd(bp, BNX2_FW_MB);
Michael Chanb6016b72005-05-26 13:03:09 -07002546
2547 if ((val & BNX2_FW_MSG_ACK) == (msg_data & BNX2_DRV_MSG_SEQ))
2548 break;
2549 }
Michael Chanb090ae22006-01-23 16:07:10 -08002550 if ((msg_data & BNX2_DRV_MSG_DATA) == BNX2_DRV_MSG_DATA_WAIT0)
2551 return 0;
Michael Chanb6016b72005-05-26 13:03:09 -07002552
2553 /* If we timed out, inform the firmware that this is the case. */
Michael Chanb090ae22006-01-23 16:07:10 -08002554 if ((val & BNX2_FW_MSG_ACK) != (msg_data & BNX2_DRV_MSG_SEQ)) {
Michael Chanb6016b72005-05-26 13:03:09 -07002555 msg_data &= ~BNX2_DRV_MSG_CODE;
2556 msg_data |= BNX2_DRV_MSG_CODE_FW_TIMEOUT;
2557
Michael Chan2726d6e2008-01-29 21:35:05 -08002558 bnx2_shmem_wr(bp, BNX2_DRV_MB, msg_data);
Jeffrey Huangecdbf6e2011-07-13 17:24:21 +00002559 if (!silent) {
2560 pr_err("fw sync timeout, reset code = %x\n", msg_data);
2561 bnx2_dump_mcp_state(bp);
2562 }
Michael Chanb6016b72005-05-26 13:03:09 -07002563
Michael Chanb6016b72005-05-26 13:03:09 -07002564 return -EBUSY;
2565 }
2566
Michael Chanb090ae22006-01-23 16:07:10 -08002567 if ((val & BNX2_FW_MSG_STATUS_MASK) != BNX2_FW_MSG_STATUS_OK)
2568 return -EIO;
2569
Michael Chanb6016b72005-05-26 13:03:09 -07002570 return 0;
2571}
2572
Michael Chan59b47d82006-11-19 14:10:45 -08002573static int
2574bnx2_init_5709_context(struct bnx2 *bp)
2575{
2576 int i, ret = 0;
2577 u32 val;
2578
2579 val = BNX2_CTX_COMMAND_ENABLED | BNX2_CTX_COMMAND_MEM_INIT | (1 << 12);
Michael Chan2bc40782012-12-06 10:33:09 +00002580 val |= (BNX2_PAGE_BITS - 8) << 16;
Michael Chane503e062012-12-06 10:33:08 +00002581 BNX2_WR(bp, BNX2_CTX_COMMAND, val);
Michael Chan641bdcd2007-06-04 21:22:24 -07002582 for (i = 0; i < 10; i++) {
Michael Chane503e062012-12-06 10:33:08 +00002583 val = BNX2_RD(bp, BNX2_CTX_COMMAND);
Michael Chan641bdcd2007-06-04 21:22:24 -07002584 if (!(val & BNX2_CTX_COMMAND_MEM_INIT))
2585 break;
2586 udelay(2);
2587 }
2588 if (val & BNX2_CTX_COMMAND_MEM_INIT)
2589 return -EBUSY;
2590
Michael Chan59b47d82006-11-19 14:10:45 -08002591 for (i = 0; i < bp->ctx_pages; i++) {
2592 int j;
2593
Michael Chan352f7682008-05-02 16:57:26 -07002594 if (bp->ctx_blk[i])
Michael Chan2bc40782012-12-06 10:33:09 +00002595 memset(bp->ctx_blk[i], 0, BNX2_PAGE_SIZE);
Michael Chan352f7682008-05-02 16:57:26 -07002596 else
2597 return -ENOMEM;
2598
Michael Chane503e062012-12-06 10:33:08 +00002599 BNX2_WR(bp, BNX2_CTX_HOST_PAGE_TBL_DATA0,
2600 (bp->ctx_blk_mapping[i] & 0xffffffff) |
2601 BNX2_CTX_HOST_PAGE_TBL_DATA0_VALID);
2602 BNX2_WR(bp, BNX2_CTX_HOST_PAGE_TBL_DATA1,
2603 (u64) bp->ctx_blk_mapping[i] >> 32);
2604 BNX2_WR(bp, BNX2_CTX_HOST_PAGE_TBL_CTRL, i |
2605 BNX2_CTX_HOST_PAGE_TBL_CTRL_WRITE_REQ);
Michael Chan59b47d82006-11-19 14:10:45 -08002606 for (j = 0; j < 10; j++) {
2607
Michael Chane503e062012-12-06 10:33:08 +00002608 val = BNX2_RD(bp, BNX2_CTX_HOST_PAGE_TBL_CTRL);
Michael Chan59b47d82006-11-19 14:10:45 -08002609 if (!(val & BNX2_CTX_HOST_PAGE_TBL_CTRL_WRITE_REQ))
2610 break;
2611 udelay(5);
2612 }
2613 if (val & BNX2_CTX_HOST_PAGE_TBL_CTRL_WRITE_REQ) {
2614 ret = -EBUSY;
2615 break;
2616 }
2617 }
2618 return ret;
2619}
2620
Michael Chanb6016b72005-05-26 13:03:09 -07002621static void
2622bnx2_init_context(struct bnx2 *bp)
2623{
2624 u32 vcid;
2625
2626 vcid = 96;
2627 while (vcid) {
2628 u32 vcid_addr, pcid_addr, offset;
Michael Chan7947b202007-06-04 21:17:10 -07002629 int i;
Michael Chanb6016b72005-05-26 13:03:09 -07002630
2631 vcid--;
2632
Michael Chan4ce45e02012-12-06 10:33:10 +00002633 if (BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5706_A0) {
Michael Chanb6016b72005-05-26 13:03:09 -07002634 u32 new_vcid;
2635
2636 vcid_addr = GET_PCID_ADDR(vcid);
2637 if (vcid & 0x8) {
2638 new_vcid = 0x60 + (vcid & 0xf0) + (vcid & 0x7);
2639 }
2640 else {
2641 new_vcid = vcid;
2642 }
2643 pcid_addr = GET_PCID_ADDR(new_vcid);
2644 }
2645 else {
2646 vcid_addr = GET_CID_ADDR(vcid);
2647 pcid_addr = vcid_addr;
2648 }
2649
Michael Chan7947b202007-06-04 21:17:10 -07002650 for (i = 0; i < (CTX_SIZE / PHY_CTX_SIZE); i++) {
2651 vcid_addr += (i << PHY_CTX_SHIFT);
2652 pcid_addr += (i << PHY_CTX_SHIFT);
Michael Chanb6016b72005-05-26 13:03:09 -07002653
Michael Chane503e062012-12-06 10:33:08 +00002654 BNX2_WR(bp, BNX2_CTX_VIRT_ADDR, vcid_addr);
2655 BNX2_WR(bp, BNX2_CTX_PAGE_TBL, pcid_addr);
Michael Chan7947b202007-06-04 21:17:10 -07002656
2657 /* Zero out the context. */
2658 for (offset = 0; offset < PHY_CTX_SIZE; offset += 4)
Michael Chan62a83132008-01-29 21:35:40 -08002659 bnx2_ctx_wr(bp, vcid_addr, offset, 0);
Michael Chanb6016b72005-05-26 13:03:09 -07002660 }
Michael Chanb6016b72005-05-26 13:03:09 -07002661 }
2662}
2663
2664static int
2665bnx2_alloc_bad_rbuf(struct bnx2 *bp)
2666{
2667 u16 *good_mbuf;
2668 u32 good_mbuf_cnt;
2669 u32 val;
2670
2671 good_mbuf = kmalloc(512 * sizeof(u16), GFP_KERNEL);
Joe Perchese404dec2012-01-29 12:56:23 +00002672 if (good_mbuf == NULL)
Michael Chanb6016b72005-05-26 13:03:09 -07002673 return -ENOMEM;
Michael Chanb6016b72005-05-26 13:03:09 -07002674
Michael Chane503e062012-12-06 10:33:08 +00002675 BNX2_WR(bp, BNX2_MISC_ENABLE_SET_BITS,
Michael Chanb6016b72005-05-26 13:03:09 -07002676 BNX2_MISC_ENABLE_SET_BITS_RX_MBUF_ENABLE);
2677
2678 good_mbuf_cnt = 0;
2679
2680 /* Allocate a bunch of mbufs and save the good ones in an array. */
Michael Chan2726d6e2008-01-29 21:35:05 -08002681 val = bnx2_reg_rd_ind(bp, BNX2_RBUF_STATUS1);
Michael Chanb6016b72005-05-26 13:03:09 -07002682 while (val & BNX2_RBUF_STATUS1_FREE_COUNT) {
Michael Chan2726d6e2008-01-29 21:35:05 -08002683 bnx2_reg_wr_ind(bp, BNX2_RBUF_COMMAND,
2684 BNX2_RBUF_COMMAND_ALLOC_REQ);
Michael Chanb6016b72005-05-26 13:03:09 -07002685
Michael Chan2726d6e2008-01-29 21:35:05 -08002686 val = bnx2_reg_rd_ind(bp, BNX2_RBUF_FW_BUF_ALLOC);
Michael Chanb6016b72005-05-26 13:03:09 -07002687
2688 val &= BNX2_RBUF_FW_BUF_ALLOC_VALUE;
2689
2690 /* The addresses with Bit 9 set are bad memory blocks. */
2691 if (!(val & (1 << 9))) {
2692 good_mbuf[good_mbuf_cnt] = (u16) val;
2693 good_mbuf_cnt++;
2694 }
2695
Michael Chan2726d6e2008-01-29 21:35:05 -08002696 val = bnx2_reg_rd_ind(bp, BNX2_RBUF_STATUS1);
Michael Chanb6016b72005-05-26 13:03:09 -07002697 }
2698
2699 /* Free the good ones back to the mbuf pool thus discarding
2700 * all the bad ones. */
2701 while (good_mbuf_cnt) {
2702 good_mbuf_cnt--;
2703
2704 val = good_mbuf[good_mbuf_cnt];
2705 val = (val << 9) | val | 1;
2706
Michael Chan2726d6e2008-01-29 21:35:05 -08002707 bnx2_reg_wr_ind(bp, BNX2_RBUF_FW_BUF_FREE, val);
Michael Chanb6016b72005-05-26 13:03:09 -07002708 }
2709 kfree(good_mbuf);
2710 return 0;
2711}
2712
2713static void
Benjamin Li5fcaed02008-07-14 22:39:52 -07002714bnx2_set_mac_addr(struct bnx2 *bp, u8 *mac_addr, u32 pos)
Michael Chanb6016b72005-05-26 13:03:09 -07002715{
2716 u32 val;
Michael Chanb6016b72005-05-26 13:03:09 -07002717
2718 val = (mac_addr[0] << 8) | mac_addr[1];
2719
Michael Chane503e062012-12-06 10:33:08 +00002720 BNX2_WR(bp, BNX2_EMAC_MAC_MATCH0 + (pos * 8), val);
Michael Chanb6016b72005-05-26 13:03:09 -07002721
Jeff Garzik6aa20a22006-09-13 13:24:59 -04002722 val = (mac_addr[2] << 24) | (mac_addr[3] << 16) |
Michael Chanb6016b72005-05-26 13:03:09 -07002723 (mac_addr[4] << 8) | mac_addr[5];
2724
Michael Chane503e062012-12-06 10:33:08 +00002725 BNX2_WR(bp, BNX2_EMAC_MAC_MATCH1 + (pos * 8), val);
Michael Chanb6016b72005-05-26 13:03:09 -07002726}
2727
2728static inline int
Stanislaw Gruszkaa2df00a2010-07-15 22:55:40 +00002729bnx2_alloc_rx_page(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr, u16 index, gfp_t gfp)
Michael Chan47bf4242007-12-12 11:19:12 -08002730{
2731 dma_addr_t mapping;
Michael Chan2bc40782012-12-06 10:33:09 +00002732 struct bnx2_sw_pg *rx_pg = &rxr->rx_pg_ring[index];
2733 struct bnx2_rx_bd *rxbd =
2734 &rxr->rx_pg_desc_ring[BNX2_RX_RING(index)][BNX2_RX_IDX(index)];
Stanislaw Gruszkaa2df00a2010-07-15 22:55:40 +00002735 struct page *page = alloc_page(gfp);
Michael Chan47bf4242007-12-12 11:19:12 -08002736
2737 if (!page)
2738 return -ENOMEM;
Stanislaw Gruszka36227e82010-07-15 04:25:50 +00002739 mapping = dma_map_page(&bp->pdev->dev, page, 0, PAGE_SIZE,
Michael Chan47bf4242007-12-12 11:19:12 -08002740 PCI_DMA_FROMDEVICE);
Stanislaw Gruszka36227e82010-07-15 04:25:50 +00002741 if (dma_mapping_error(&bp->pdev->dev, mapping)) {
Benjamin Li3d16af82008-10-09 12:26:41 -07002742 __free_page(page);
2743 return -EIO;
2744 }
2745
Michael Chan47bf4242007-12-12 11:19:12 -08002746 rx_pg->page = page;
FUJITA Tomonori1a4ccc22010-04-01 16:56:57 +00002747 dma_unmap_addr_set(rx_pg, mapping, mapping);
Michael Chan47bf4242007-12-12 11:19:12 -08002748 rxbd->rx_bd_haddr_hi = (u64) mapping >> 32;
2749 rxbd->rx_bd_haddr_lo = (u64) mapping & 0xffffffff;
2750 return 0;
2751}
2752
2753static void
Michael Chanbb4f98a2008-06-19 16:38:19 -07002754bnx2_free_rx_page(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr, u16 index)
Michael Chan47bf4242007-12-12 11:19:12 -08002755{
Michael Chan2bc40782012-12-06 10:33:09 +00002756 struct bnx2_sw_pg *rx_pg = &rxr->rx_pg_ring[index];
Michael Chan47bf4242007-12-12 11:19:12 -08002757 struct page *page = rx_pg->page;
2758
2759 if (!page)
2760 return;
2761
Stanislaw Gruszka36227e82010-07-15 04:25:50 +00002762 dma_unmap_page(&bp->pdev->dev, dma_unmap_addr(rx_pg, mapping),
2763 PAGE_SIZE, PCI_DMA_FROMDEVICE);
Michael Chan47bf4242007-12-12 11:19:12 -08002764
2765 __free_page(page);
2766 rx_pg->page = NULL;
2767}
2768
2769static inline int
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00002770bnx2_alloc_rx_data(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr, u16 index, gfp_t gfp)
Michael Chanb6016b72005-05-26 13:03:09 -07002771{
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00002772 u8 *data;
Michael Chan2bc40782012-12-06 10:33:09 +00002773 struct bnx2_sw_bd *rx_buf = &rxr->rx_buf_ring[index];
Michael Chanb6016b72005-05-26 13:03:09 -07002774 dma_addr_t mapping;
Michael Chan2bc40782012-12-06 10:33:09 +00002775 struct bnx2_rx_bd *rxbd =
2776 &rxr->rx_desc_ring[BNX2_RX_RING(index)][BNX2_RX_IDX(index)];
Michael Chanb6016b72005-05-26 13:03:09 -07002777
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00002778 data = kmalloc(bp->rx_buf_size, gfp);
2779 if (!data)
Michael Chanb6016b72005-05-26 13:03:09 -07002780 return -ENOMEM;
Michael Chanb6016b72005-05-26 13:03:09 -07002781
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00002782 mapping = dma_map_single(&bp->pdev->dev,
2783 get_l2_fhdr(data),
2784 bp->rx_buf_use_size,
Stanislaw Gruszka36227e82010-07-15 04:25:50 +00002785 PCI_DMA_FROMDEVICE);
2786 if (dma_mapping_error(&bp->pdev->dev, mapping)) {
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00002787 kfree(data);
Benjamin Li3d16af82008-10-09 12:26:41 -07002788 return -EIO;
2789 }
Michael Chanb6016b72005-05-26 13:03:09 -07002790
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00002791 rx_buf->data = data;
FUJITA Tomonori1a4ccc22010-04-01 16:56:57 +00002792 dma_unmap_addr_set(rx_buf, mapping, mapping);
Michael Chanb6016b72005-05-26 13:03:09 -07002793
2794 rxbd->rx_bd_haddr_hi = (u64) mapping >> 32;
2795 rxbd->rx_bd_haddr_lo = (u64) mapping & 0xffffffff;
2796
Michael Chanbb4f98a2008-06-19 16:38:19 -07002797 rxr->rx_prod_bseq += bp->rx_buf_use_size;
Michael Chanb6016b72005-05-26 13:03:09 -07002798
2799 return 0;
2800}
2801
Michael Chanda3e4fb2007-05-03 13:24:23 -07002802static int
Michael Chan35efa7c2007-12-20 19:56:37 -08002803bnx2_phy_event_is_set(struct bnx2 *bp, struct bnx2_napi *bnapi, u32 event)
Michael Chanda3e4fb2007-05-03 13:24:23 -07002804{
Michael Chan43e80b82008-06-19 16:41:08 -07002805 struct status_block *sblk = bnapi->status_blk.msi;
Michael Chanda3e4fb2007-05-03 13:24:23 -07002806 u32 new_link_state, old_link_state;
2807 int is_set = 1;
2808
2809 new_link_state = sblk->status_attn_bits & event;
2810 old_link_state = sblk->status_attn_bits_ack & event;
2811 if (new_link_state != old_link_state) {
2812 if (new_link_state)
Michael Chane503e062012-12-06 10:33:08 +00002813 BNX2_WR(bp, BNX2_PCICFG_STATUS_BIT_SET_CMD, event);
Michael Chanda3e4fb2007-05-03 13:24:23 -07002814 else
Michael Chane503e062012-12-06 10:33:08 +00002815 BNX2_WR(bp, BNX2_PCICFG_STATUS_BIT_CLEAR_CMD, event);
Michael Chanda3e4fb2007-05-03 13:24:23 -07002816 } else
2817 is_set = 0;
2818
2819 return is_set;
2820}
2821
Michael Chanb6016b72005-05-26 13:03:09 -07002822static void
Michael Chan35efa7c2007-12-20 19:56:37 -08002823bnx2_phy_int(struct bnx2 *bp, struct bnx2_napi *bnapi)
Michael Chanb6016b72005-05-26 13:03:09 -07002824{
Michael Chan74ecc622008-05-02 16:56:16 -07002825 spin_lock(&bp->phy_lock);
2826
2827 if (bnx2_phy_event_is_set(bp, bnapi, STATUS_ATTN_BITS_LINK_STATE))
Michael Chanb6016b72005-05-26 13:03:09 -07002828 bnx2_set_link(bp);
Michael Chan35efa7c2007-12-20 19:56:37 -08002829 if (bnx2_phy_event_is_set(bp, bnapi, STATUS_ATTN_BITS_TIMER_ABORT))
Michael Chan0d8a6572007-07-07 22:49:43 -07002830 bnx2_set_remote_link(bp);
2831
Michael Chan74ecc622008-05-02 16:56:16 -07002832 spin_unlock(&bp->phy_lock);
2833
Michael Chanb6016b72005-05-26 13:03:09 -07002834}
2835
Michael Chanead72702007-12-20 19:55:39 -08002836static inline u16
Michael Chan35efa7c2007-12-20 19:56:37 -08002837bnx2_get_hw_tx_cons(struct bnx2_napi *bnapi)
Michael Chanead72702007-12-20 19:55:39 -08002838{
2839 u16 cons;
2840
Michael Chan43e80b82008-06-19 16:41:08 -07002841 /* Tell compiler that status block fields can change. */
2842 barrier();
2843 cons = *bnapi->hw_tx_cons_ptr;
Michael Chan581daf72009-05-06 16:46:47 -07002844 barrier();
Michael Chan2bc40782012-12-06 10:33:09 +00002845 if (unlikely((cons & BNX2_MAX_TX_DESC_CNT) == BNX2_MAX_TX_DESC_CNT))
Michael Chanead72702007-12-20 19:55:39 -08002846 cons++;
2847 return cons;
2848}
2849
Michael Chan57851d82007-12-20 20:01:44 -08002850static int
2851bnx2_tx_int(struct bnx2 *bp, struct bnx2_napi *bnapi, int budget)
Michael Chanb6016b72005-05-26 13:03:09 -07002852{
Michael Chan35e90102008-06-19 16:37:42 -07002853 struct bnx2_tx_ring_info *txr = &bnapi->tx_ring;
Michael Chanb6016b72005-05-26 13:03:09 -07002854 u16 hw_cons, sw_cons, sw_ring_cons;
Benjamin Li706bf242008-07-18 17:55:11 -07002855 int tx_pkt = 0, index;
Eric Dumazete9831902011-11-29 11:53:05 +00002856 unsigned int tx_bytes = 0;
Benjamin Li706bf242008-07-18 17:55:11 -07002857 struct netdev_queue *txq;
2858
2859 index = (bnapi - bp->bnx2_napi);
2860 txq = netdev_get_tx_queue(bp->dev, index);
Michael Chanb6016b72005-05-26 13:03:09 -07002861
Michael Chan35efa7c2007-12-20 19:56:37 -08002862 hw_cons = bnx2_get_hw_tx_cons(bnapi);
Michael Chan35e90102008-06-19 16:37:42 -07002863 sw_cons = txr->tx_cons;
Michael Chanb6016b72005-05-26 13:03:09 -07002864
2865 while (sw_cons != hw_cons) {
Michael Chan2bc40782012-12-06 10:33:09 +00002866 struct bnx2_sw_tx_bd *tx_buf;
Michael Chanb6016b72005-05-26 13:03:09 -07002867 struct sk_buff *skb;
2868 int i, last;
2869
Michael Chan2bc40782012-12-06 10:33:09 +00002870 sw_ring_cons = BNX2_TX_RING_IDX(sw_cons);
Michael Chanb6016b72005-05-26 13:03:09 -07002871
Michael Chan35e90102008-06-19 16:37:42 -07002872 tx_buf = &txr->tx_buf_ring[sw_ring_cons];
Michael Chanb6016b72005-05-26 13:03:09 -07002873 skb = tx_buf->skb;
Arjan van de Ven1d39ed52006-12-12 14:06:23 +01002874
Eric Dumazetd62fda02009-05-12 20:48:02 +00002875 /* prefetch skb_end_pointer() to speedup skb_shinfo(skb) */
2876 prefetch(&skb->end);
2877
Michael Chanb6016b72005-05-26 13:03:09 -07002878 /* partial BD completions possible with TSO packets */
Eric Dumazetd62fda02009-05-12 20:48:02 +00002879 if (tx_buf->is_gso) {
Michael Chanb6016b72005-05-26 13:03:09 -07002880 u16 last_idx, last_ring_idx;
2881
Eric Dumazetd62fda02009-05-12 20:48:02 +00002882 last_idx = sw_cons + tx_buf->nr_frags + 1;
2883 last_ring_idx = sw_ring_cons + tx_buf->nr_frags + 1;
Michael Chan2bc40782012-12-06 10:33:09 +00002884 if (unlikely(last_ring_idx >= BNX2_MAX_TX_DESC_CNT)) {
Michael Chanb6016b72005-05-26 13:03:09 -07002885 last_idx++;
2886 }
2887 if (((s16) ((s16) last_idx - (s16) hw_cons)) > 0) {
2888 break;
2889 }
2890 }
Arjan van de Ven1d39ed52006-12-12 14:06:23 +01002891
Stanislaw Gruszka36227e82010-07-15 04:25:50 +00002892 dma_unmap_single(&bp->pdev->dev, dma_unmap_addr(tx_buf, mapping),
Alexander Duycke95524a2009-12-02 16:47:57 +00002893 skb_headlen(skb), PCI_DMA_TODEVICE);
Michael Chanb6016b72005-05-26 13:03:09 -07002894
2895 tx_buf->skb = NULL;
Eric Dumazetd62fda02009-05-12 20:48:02 +00002896 last = tx_buf->nr_frags;
Michael Chanb6016b72005-05-26 13:03:09 -07002897
2898 for (i = 0; i < last; i++) {
Michael Chan2bc40782012-12-06 10:33:09 +00002899 struct bnx2_sw_tx_bd *tx_buf;
Alexander Duycke95524a2009-12-02 16:47:57 +00002900
Michael Chan2bc40782012-12-06 10:33:09 +00002901 sw_cons = BNX2_NEXT_TX_BD(sw_cons);
2902
2903 tx_buf = &txr->tx_buf_ring[BNX2_TX_RING_IDX(sw_cons)];
Stanislaw Gruszka36227e82010-07-15 04:25:50 +00002904 dma_unmap_page(&bp->pdev->dev,
Michael Chan2bc40782012-12-06 10:33:09 +00002905 dma_unmap_addr(tx_buf, mapping),
Eric Dumazet9e903e02011-10-18 21:00:24 +00002906 skb_frag_size(&skb_shinfo(skb)->frags[i]),
Alexander Duycke95524a2009-12-02 16:47:57 +00002907 PCI_DMA_TODEVICE);
Michael Chanb6016b72005-05-26 13:03:09 -07002908 }
2909
Michael Chan2bc40782012-12-06 10:33:09 +00002910 sw_cons = BNX2_NEXT_TX_BD(sw_cons);
Michael Chanb6016b72005-05-26 13:03:09 -07002911
Eric Dumazete9831902011-11-29 11:53:05 +00002912 tx_bytes += skb->len;
Eric W. Biedermanf458b2e2014-03-11 14:17:41 -07002913 dev_kfree_skb_any(skb);
Michael Chan57851d82007-12-20 20:01:44 -08002914 tx_pkt++;
2915 if (tx_pkt == budget)
2916 break;
Michael Chanb6016b72005-05-26 13:03:09 -07002917
Eric Dumazetd62fda02009-05-12 20:48:02 +00002918 if (hw_cons == sw_cons)
2919 hw_cons = bnx2_get_hw_tx_cons(bnapi);
Michael Chanb6016b72005-05-26 13:03:09 -07002920 }
2921
Eric Dumazete9831902011-11-29 11:53:05 +00002922 netdev_tx_completed_queue(txq, tx_pkt, tx_bytes);
Michael Chan35e90102008-06-19 16:37:42 -07002923 txr->hw_tx_cons = hw_cons;
2924 txr->tx_cons = sw_cons;
Benjamin Li706bf242008-07-18 17:55:11 -07002925
Michael Chan2f8af122006-08-15 01:39:10 -07002926 /* Need to make the tx_cons update visible to bnx2_start_xmit()
Benjamin Li706bf242008-07-18 17:55:11 -07002927 * before checking for netif_tx_queue_stopped(). Without the
Michael Chan2f8af122006-08-15 01:39:10 -07002928 * memory barrier, there is a small possibility that bnx2_start_xmit()
2929 * will miss it and cause the queue to be stopped forever.
2930 */
2931 smp_mb();
Michael Chanb6016b72005-05-26 13:03:09 -07002932
Benjamin Li706bf242008-07-18 17:55:11 -07002933 if (unlikely(netif_tx_queue_stopped(txq)) &&
Michael Chan35e90102008-06-19 16:37:42 -07002934 (bnx2_tx_avail(bp, txr) > bp->tx_wake_thresh)) {
Benjamin Li706bf242008-07-18 17:55:11 -07002935 __netif_tx_lock(txq, smp_processor_id());
2936 if ((netif_tx_queue_stopped(txq)) &&
Michael Chan35e90102008-06-19 16:37:42 -07002937 (bnx2_tx_avail(bp, txr) > bp->tx_wake_thresh))
Benjamin Li706bf242008-07-18 17:55:11 -07002938 netif_tx_wake_queue(txq);
2939 __netif_tx_unlock(txq);
Michael Chanb6016b72005-05-26 13:03:09 -07002940 }
Benjamin Li706bf242008-07-18 17:55:11 -07002941
Michael Chan57851d82007-12-20 20:01:44 -08002942 return tx_pkt;
Michael Chanb6016b72005-05-26 13:03:09 -07002943}
2944
Michael Chan1db82f22007-12-12 11:19:35 -08002945static void
Michael Chanbb4f98a2008-06-19 16:38:19 -07002946bnx2_reuse_rx_skb_pages(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr,
Michael Chana1f60192007-12-20 19:57:19 -08002947 struct sk_buff *skb, int count)
Michael Chan1db82f22007-12-12 11:19:35 -08002948{
Michael Chan2bc40782012-12-06 10:33:09 +00002949 struct bnx2_sw_pg *cons_rx_pg, *prod_rx_pg;
2950 struct bnx2_rx_bd *cons_bd, *prod_bd;
Michael Chan1db82f22007-12-12 11:19:35 -08002951 int i;
Benjamin Li3d16af82008-10-09 12:26:41 -07002952 u16 hw_prod, prod;
Michael Chanbb4f98a2008-06-19 16:38:19 -07002953 u16 cons = rxr->rx_pg_cons;
Michael Chan1db82f22007-12-12 11:19:35 -08002954
Benjamin Li3d16af82008-10-09 12:26:41 -07002955 cons_rx_pg = &rxr->rx_pg_ring[cons];
2956
2957 /* The caller was unable to allocate a new page to replace the
2958 * last one in the frags array, so we need to recycle that page
2959 * and then free the skb.
2960 */
2961 if (skb) {
2962 struct page *page;
2963 struct skb_shared_info *shinfo;
2964
2965 shinfo = skb_shinfo(skb);
2966 shinfo->nr_frags--;
Ian Campbellb7b6a682011-08-24 22:28:12 +00002967 page = skb_frag_page(&shinfo->frags[shinfo->nr_frags]);
2968 __skb_frag_set_page(&shinfo->frags[shinfo->nr_frags], NULL);
Benjamin Li3d16af82008-10-09 12:26:41 -07002969
2970 cons_rx_pg->page = page;
2971 dev_kfree_skb(skb);
2972 }
2973
2974 hw_prod = rxr->rx_pg_prod;
2975
Michael Chan1db82f22007-12-12 11:19:35 -08002976 for (i = 0; i < count; i++) {
Michael Chan2bc40782012-12-06 10:33:09 +00002977 prod = BNX2_RX_PG_RING_IDX(hw_prod);
Michael Chan1db82f22007-12-12 11:19:35 -08002978
Michael Chanbb4f98a2008-06-19 16:38:19 -07002979 prod_rx_pg = &rxr->rx_pg_ring[prod];
2980 cons_rx_pg = &rxr->rx_pg_ring[cons];
Michael Chan2bc40782012-12-06 10:33:09 +00002981 cons_bd = &rxr->rx_pg_desc_ring[BNX2_RX_RING(cons)]
2982 [BNX2_RX_IDX(cons)];
2983 prod_bd = &rxr->rx_pg_desc_ring[BNX2_RX_RING(prod)]
2984 [BNX2_RX_IDX(prod)];
Michael Chan1db82f22007-12-12 11:19:35 -08002985
Michael Chan1db82f22007-12-12 11:19:35 -08002986 if (prod != cons) {
2987 prod_rx_pg->page = cons_rx_pg->page;
2988 cons_rx_pg->page = NULL;
FUJITA Tomonori1a4ccc22010-04-01 16:56:57 +00002989 dma_unmap_addr_set(prod_rx_pg, mapping,
2990 dma_unmap_addr(cons_rx_pg, mapping));
Michael Chan1db82f22007-12-12 11:19:35 -08002991
2992 prod_bd->rx_bd_haddr_hi = cons_bd->rx_bd_haddr_hi;
2993 prod_bd->rx_bd_haddr_lo = cons_bd->rx_bd_haddr_lo;
2994
2995 }
Michael Chan2bc40782012-12-06 10:33:09 +00002996 cons = BNX2_RX_PG_RING_IDX(BNX2_NEXT_RX_BD(cons));
2997 hw_prod = BNX2_NEXT_RX_BD(hw_prod);
Michael Chan1db82f22007-12-12 11:19:35 -08002998 }
Michael Chanbb4f98a2008-06-19 16:38:19 -07002999 rxr->rx_pg_prod = hw_prod;
3000 rxr->rx_pg_cons = cons;
Michael Chan1db82f22007-12-12 11:19:35 -08003001}
3002
Michael Chanb6016b72005-05-26 13:03:09 -07003003static inline void
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00003004bnx2_reuse_rx_data(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr,
3005 u8 *data, u16 cons, u16 prod)
Michael Chanb6016b72005-05-26 13:03:09 -07003006{
Michael Chan2bc40782012-12-06 10:33:09 +00003007 struct bnx2_sw_bd *cons_rx_buf, *prod_rx_buf;
3008 struct bnx2_rx_bd *cons_bd, *prod_bd;
Michael Chan236b6392006-03-20 17:49:02 -08003009
Michael Chanbb4f98a2008-06-19 16:38:19 -07003010 cons_rx_buf = &rxr->rx_buf_ring[cons];
3011 prod_rx_buf = &rxr->rx_buf_ring[prod];
Michael Chanb6016b72005-05-26 13:03:09 -07003012
Stanislaw Gruszka36227e82010-07-15 04:25:50 +00003013 dma_sync_single_for_device(&bp->pdev->dev,
FUJITA Tomonori1a4ccc22010-04-01 16:56:57 +00003014 dma_unmap_addr(cons_rx_buf, mapping),
Benjamin Li601d3d12008-05-16 22:19:35 -07003015 BNX2_RX_OFFSET + BNX2_RX_COPY_THRESH, PCI_DMA_FROMDEVICE);
Michael Chanb6016b72005-05-26 13:03:09 -07003016
Michael Chanbb4f98a2008-06-19 16:38:19 -07003017 rxr->rx_prod_bseq += bp->rx_buf_use_size;
Michael Chan236b6392006-03-20 17:49:02 -08003018
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00003019 prod_rx_buf->data = data;
Michael Chan236b6392006-03-20 17:49:02 -08003020
3021 if (cons == prod)
3022 return;
3023
FUJITA Tomonori1a4ccc22010-04-01 16:56:57 +00003024 dma_unmap_addr_set(prod_rx_buf, mapping,
3025 dma_unmap_addr(cons_rx_buf, mapping));
Michael Chanb6016b72005-05-26 13:03:09 -07003026
Michael Chan2bc40782012-12-06 10:33:09 +00003027 cons_bd = &rxr->rx_desc_ring[BNX2_RX_RING(cons)][BNX2_RX_IDX(cons)];
3028 prod_bd = &rxr->rx_desc_ring[BNX2_RX_RING(prod)][BNX2_RX_IDX(prod)];
Michael Chan236b6392006-03-20 17:49:02 -08003029 prod_bd->rx_bd_haddr_hi = cons_bd->rx_bd_haddr_hi;
3030 prod_bd->rx_bd_haddr_lo = cons_bd->rx_bd_haddr_lo;
Michael Chanb6016b72005-05-26 13:03:09 -07003031}
3032
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00003033static struct sk_buff *
3034bnx2_rx_skb(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr, u8 *data,
Michael Chana1f60192007-12-20 19:57:19 -08003035 unsigned int len, unsigned int hdr_len, dma_addr_t dma_addr,
3036 u32 ring_idx)
Michael Chan85833c62007-12-12 11:17:01 -08003037{
3038 int err;
3039 u16 prod = ring_idx & 0xffff;
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00003040 struct sk_buff *skb;
Michael Chan85833c62007-12-12 11:17:01 -08003041
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00003042 err = bnx2_alloc_rx_data(bp, rxr, prod, GFP_ATOMIC);
Michael Chan85833c62007-12-12 11:17:01 -08003043 if (unlikely(err)) {
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00003044 bnx2_reuse_rx_data(bp, rxr, data, (u16) (ring_idx >> 16), prod);
3045error:
Michael Chan1db82f22007-12-12 11:19:35 -08003046 if (hdr_len) {
3047 unsigned int raw_len = len + 4;
3048 int pages = PAGE_ALIGN(raw_len - hdr_len) >> PAGE_SHIFT;
3049
Michael Chanbb4f98a2008-06-19 16:38:19 -07003050 bnx2_reuse_rx_skb_pages(bp, rxr, NULL, pages);
Michael Chan1db82f22007-12-12 11:19:35 -08003051 }
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00003052 return NULL;
Michael Chan85833c62007-12-12 11:17:01 -08003053 }
3054
Stanislaw Gruszka36227e82010-07-15 04:25:50 +00003055 dma_unmap_single(&bp->pdev->dev, dma_addr, bp->rx_buf_use_size,
Michael Chan85833c62007-12-12 11:17:01 -08003056 PCI_DMA_FROMDEVICE);
Eric Dumazetd3836f22012-04-27 00:33:38 +00003057 skb = build_skb(data, 0);
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00003058 if (!skb) {
3059 kfree(data);
3060 goto error;
3061 }
3062 skb_reserve(skb, ((u8 *)get_l2_fhdr(data) - data) + BNX2_RX_OFFSET);
Michael Chan1db82f22007-12-12 11:19:35 -08003063 if (hdr_len == 0) {
3064 skb_put(skb, len);
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00003065 return skb;
Michael Chan1db82f22007-12-12 11:19:35 -08003066 } else {
3067 unsigned int i, frag_len, frag_size, pages;
Michael Chan2bc40782012-12-06 10:33:09 +00003068 struct bnx2_sw_pg *rx_pg;
Michael Chanbb4f98a2008-06-19 16:38:19 -07003069 u16 pg_cons = rxr->rx_pg_cons;
3070 u16 pg_prod = rxr->rx_pg_prod;
Michael Chan1db82f22007-12-12 11:19:35 -08003071
3072 frag_size = len + 4 - hdr_len;
3073 pages = PAGE_ALIGN(frag_size) >> PAGE_SHIFT;
3074 skb_put(skb, hdr_len);
3075
3076 for (i = 0; i < pages; i++) {
Benjamin Li3d16af82008-10-09 12:26:41 -07003077 dma_addr_t mapping_old;
3078
Michael Chan1db82f22007-12-12 11:19:35 -08003079 frag_len = min(frag_size, (unsigned int) PAGE_SIZE);
3080 if (unlikely(frag_len <= 4)) {
3081 unsigned int tail = 4 - frag_len;
3082
Michael Chanbb4f98a2008-06-19 16:38:19 -07003083 rxr->rx_pg_cons = pg_cons;
3084 rxr->rx_pg_prod = pg_prod;
3085 bnx2_reuse_rx_skb_pages(bp, rxr, NULL,
Michael Chana1f60192007-12-20 19:57:19 -08003086 pages - i);
Michael Chan1db82f22007-12-12 11:19:35 -08003087 skb->len -= tail;
3088 if (i == 0) {
3089 skb->tail -= tail;
3090 } else {
3091 skb_frag_t *frag =
3092 &skb_shinfo(skb)->frags[i - 1];
Eric Dumazet9e903e02011-10-18 21:00:24 +00003093 skb_frag_size_sub(frag, tail);
Michael Chan1db82f22007-12-12 11:19:35 -08003094 skb->data_len -= tail;
Michael Chan1db82f22007-12-12 11:19:35 -08003095 }
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00003096 return skb;
Michael Chan1db82f22007-12-12 11:19:35 -08003097 }
Michael Chanbb4f98a2008-06-19 16:38:19 -07003098 rx_pg = &rxr->rx_pg_ring[pg_cons];
Michael Chan1db82f22007-12-12 11:19:35 -08003099
Benjamin Li3d16af82008-10-09 12:26:41 -07003100 /* Don't unmap yet. If we're unable to allocate a new
3101 * page, we need to recycle the page and the DMA addr.
3102 */
FUJITA Tomonori1a4ccc22010-04-01 16:56:57 +00003103 mapping_old = dma_unmap_addr(rx_pg, mapping);
Michael Chan1db82f22007-12-12 11:19:35 -08003104 if (i == pages - 1)
3105 frag_len -= 4;
3106
3107 skb_fill_page_desc(skb, i, rx_pg->page, 0, frag_len);
3108 rx_pg->page = NULL;
3109
Michael Chanbb4f98a2008-06-19 16:38:19 -07003110 err = bnx2_alloc_rx_page(bp, rxr,
Michael Chan2bc40782012-12-06 10:33:09 +00003111 BNX2_RX_PG_RING_IDX(pg_prod),
Stanislaw Gruszkaa2df00a2010-07-15 22:55:40 +00003112 GFP_ATOMIC);
Michael Chan1db82f22007-12-12 11:19:35 -08003113 if (unlikely(err)) {
Michael Chanbb4f98a2008-06-19 16:38:19 -07003114 rxr->rx_pg_cons = pg_cons;
3115 rxr->rx_pg_prod = pg_prod;
3116 bnx2_reuse_rx_skb_pages(bp, rxr, skb,
Michael Chana1f60192007-12-20 19:57:19 -08003117 pages - i);
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00003118 return NULL;
Michael Chan1db82f22007-12-12 11:19:35 -08003119 }
3120
Stanislaw Gruszka36227e82010-07-15 04:25:50 +00003121 dma_unmap_page(&bp->pdev->dev, mapping_old,
Benjamin Li3d16af82008-10-09 12:26:41 -07003122 PAGE_SIZE, PCI_DMA_FROMDEVICE);
3123
Michael Chan1db82f22007-12-12 11:19:35 -08003124 frag_size -= frag_len;
3125 skb->data_len += frag_len;
Eric Dumazeta1f4e8b2011-10-13 07:50:19 +00003126 skb->truesize += PAGE_SIZE;
Michael Chan1db82f22007-12-12 11:19:35 -08003127 skb->len += frag_len;
3128
Michael Chan2bc40782012-12-06 10:33:09 +00003129 pg_prod = BNX2_NEXT_RX_BD(pg_prod);
3130 pg_cons = BNX2_RX_PG_RING_IDX(BNX2_NEXT_RX_BD(pg_cons));
Michael Chan1db82f22007-12-12 11:19:35 -08003131 }
Michael Chanbb4f98a2008-06-19 16:38:19 -07003132 rxr->rx_pg_prod = pg_prod;
3133 rxr->rx_pg_cons = pg_cons;
Michael Chan1db82f22007-12-12 11:19:35 -08003134 }
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00003135 return skb;
Michael Chan85833c62007-12-12 11:17:01 -08003136}
3137
Michael Chanc09c2622007-12-10 17:18:37 -08003138static inline u16
Michael Chan35efa7c2007-12-20 19:56:37 -08003139bnx2_get_hw_rx_cons(struct bnx2_napi *bnapi)
Michael Chanc09c2622007-12-10 17:18:37 -08003140{
Michael Chanbb4f98a2008-06-19 16:38:19 -07003141 u16 cons;
3142
Michael Chan43e80b82008-06-19 16:41:08 -07003143 /* Tell compiler that status block fields can change. */
3144 barrier();
3145 cons = *bnapi->hw_rx_cons_ptr;
Michael Chan581daf72009-05-06 16:46:47 -07003146 barrier();
Michael Chan2bc40782012-12-06 10:33:09 +00003147 if (unlikely((cons & BNX2_MAX_RX_DESC_CNT) == BNX2_MAX_RX_DESC_CNT))
Michael Chanc09c2622007-12-10 17:18:37 -08003148 cons++;
3149 return cons;
3150}
3151
Michael Chanb6016b72005-05-26 13:03:09 -07003152static int
Michael Chan35efa7c2007-12-20 19:56:37 -08003153bnx2_rx_int(struct bnx2 *bp, struct bnx2_napi *bnapi, int budget)
Michael Chanb6016b72005-05-26 13:03:09 -07003154{
Michael Chanbb4f98a2008-06-19 16:38:19 -07003155 struct bnx2_rx_ring_info *rxr = &bnapi->rx_ring;
Michael Chanb6016b72005-05-26 13:03:09 -07003156 u16 hw_cons, sw_cons, sw_ring_cons, sw_prod, sw_ring_prod;
3157 struct l2_fhdr *rx_hdr;
Michael Chan1db82f22007-12-12 11:19:35 -08003158 int rx_pkt = 0, pg_ring_used = 0;
Michael Chanb6016b72005-05-26 13:03:09 -07003159
Eric W. Biederman310c4d42014-03-11 14:31:09 -07003160 if (budget <= 0)
3161 return rx_pkt;
3162
Michael Chan35efa7c2007-12-20 19:56:37 -08003163 hw_cons = bnx2_get_hw_rx_cons(bnapi);
Michael Chanbb4f98a2008-06-19 16:38:19 -07003164 sw_cons = rxr->rx_cons;
3165 sw_prod = rxr->rx_prod;
Michael Chanb6016b72005-05-26 13:03:09 -07003166
3167 /* Memory barrier necessary as speculative reads of the rx
3168 * buffer can be ahead of the index in the status block
3169 */
3170 rmb();
3171 while (sw_cons != hw_cons) {
Michael Chan1db82f22007-12-12 11:19:35 -08003172 unsigned int len, hdr_len;
Michael Chanade2bfe2006-01-23 16:09:51 -08003173 u32 status;
Michael Chan2bc40782012-12-06 10:33:09 +00003174 struct bnx2_sw_bd *rx_buf, *next_rx_buf;
Michael Chanb6016b72005-05-26 13:03:09 -07003175 struct sk_buff *skb;
Michael Chan236b6392006-03-20 17:49:02 -08003176 dma_addr_t dma_addr;
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00003177 u8 *data;
Michael Chan2bc40782012-12-06 10:33:09 +00003178 u16 next_ring_idx;
Michael Chanb6016b72005-05-26 13:03:09 -07003179
Michael Chan2bc40782012-12-06 10:33:09 +00003180 sw_ring_cons = BNX2_RX_RING_IDX(sw_cons);
3181 sw_ring_prod = BNX2_RX_RING_IDX(sw_prod);
Michael Chanb6016b72005-05-26 13:03:09 -07003182
Michael Chanbb4f98a2008-06-19 16:38:19 -07003183 rx_buf = &rxr->rx_buf_ring[sw_ring_cons];
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00003184 data = rx_buf->data;
3185 rx_buf->data = NULL;
Michael Chan236b6392006-03-20 17:49:02 -08003186
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00003187 rx_hdr = get_l2_fhdr(data);
3188 prefetch(rx_hdr);
Michael Chan236b6392006-03-20 17:49:02 -08003189
FUJITA Tomonori1a4ccc22010-04-01 16:56:57 +00003190 dma_addr = dma_unmap_addr(rx_buf, mapping);
Michael Chan236b6392006-03-20 17:49:02 -08003191
Stanislaw Gruszka36227e82010-07-15 04:25:50 +00003192 dma_sync_single_for_cpu(&bp->pdev->dev, dma_addr,
Benjamin Li601d3d12008-05-16 22:19:35 -07003193 BNX2_RX_OFFSET + BNX2_RX_COPY_THRESH,
3194 PCI_DMA_FROMDEVICE);
Michael Chanb6016b72005-05-26 13:03:09 -07003195
Michael Chan2bc40782012-12-06 10:33:09 +00003196 next_ring_idx = BNX2_RX_RING_IDX(BNX2_NEXT_RX_BD(sw_cons));
3197 next_rx_buf = &rxr->rx_buf_ring[next_ring_idx];
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00003198 prefetch(get_l2_fhdr(next_rx_buf->data));
3199
Michael Chan1db82f22007-12-12 11:19:35 -08003200 len = rx_hdr->l2_fhdr_pkt_len;
Michael Chan990ec382009-02-12 16:54:13 -08003201 status = rx_hdr->l2_fhdr_status;
Michael Chanb6016b72005-05-26 13:03:09 -07003202
Michael Chan1db82f22007-12-12 11:19:35 -08003203 hdr_len = 0;
3204 if (status & L2_FHDR_STATUS_SPLIT) {
3205 hdr_len = rx_hdr->l2_fhdr_ip_xsum;
3206 pg_ring_used = 1;
3207 } else if (len > bp->rx_jumbo_thresh) {
3208 hdr_len = bp->rx_jumbo_thresh;
3209 pg_ring_used = 1;
3210 }
3211
Michael Chan990ec382009-02-12 16:54:13 -08003212 if (unlikely(status & (L2_FHDR_ERRORS_BAD_CRC |
3213 L2_FHDR_ERRORS_PHY_DECODE |
3214 L2_FHDR_ERRORS_ALIGNMENT |
3215 L2_FHDR_ERRORS_TOO_SHORT |
3216 L2_FHDR_ERRORS_GIANT_FRAME))) {
3217
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00003218 bnx2_reuse_rx_data(bp, rxr, data, sw_ring_cons,
Michael Chan990ec382009-02-12 16:54:13 -08003219 sw_ring_prod);
3220 if (pg_ring_used) {
3221 int pages;
3222
3223 pages = PAGE_ALIGN(len - hdr_len) >> PAGE_SHIFT;
3224
3225 bnx2_reuse_rx_skb_pages(bp, rxr, NULL, pages);
3226 }
3227 goto next_rx;
3228 }
3229
Michael Chan1db82f22007-12-12 11:19:35 -08003230 len -= 4;
Michael Chanb6016b72005-05-26 13:03:09 -07003231
Michael Chan5d5d0012007-12-12 11:17:43 -08003232 if (len <= bp->rx_copy_thresh) {
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00003233 skb = netdev_alloc_skb(bp->dev, len + 6);
3234 if (skb == NULL) {
3235 bnx2_reuse_rx_data(bp, rxr, data, sw_ring_cons,
Michael Chan85833c62007-12-12 11:17:01 -08003236 sw_ring_prod);
3237 goto next_rx;
3238 }
Michael Chanb6016b72005-05-26 13:03:09 -07003239
3240 /* aligned copy */
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00003241 memcpy(skb->data,
3242 (u8 *)rx_hdr + BNX2_RX_OFFSET - 6,
3243 len + 6);
3244 skb_reserve(skb, 6);
3245 skb_put(skb, len);
Michael Chanb6016b72005-05-26 13:03:09 -07003246
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00003247 bnx2_reuse_rx_data(bp, rxr, data,
Michael Chanb6016b72005-05-26 13:03:09 -07003248 sw_ring_cons, sw_ring_prod);
3249
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00003250 } else {
3251 skb = bnx2_rx_skb(bp, rxr, data, len, hdr_len, dma_addr,
3252 (sw_ring_cons << 16) | sw_ring_prod);
3253 if (!skb)
3254 goto next_rx;
3255 }
Michael Chanf22828e2008-08-14 15:30:14 -07003256 if ((status & L2_FHDR_STATUS_L2_VLAN_TAG) &&
Jesse Gross7d0fd212010-10-20 13:56:09 +00003257 !(bp->rx_mode & BNX2_EMAC_RX_MODE_KEEP_VLAN_TAG))
Patrick McHardy86a9bad2013-04-19 02:04:30 +00003258 __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), rx_hdr->l2_fhdr_vlan_tag);
Michael Chanf22828e2008-08-14 15:30:14 -07003259
Michael Chanb6016b72005-05-26 13:03:09 -07003260 skb->protocol = eth_type_trans(skb, bp->dev);
3261
Vlad Yasevich1b0ecb22014-09-30 19:39:37 -04003262 if (len > (bp->dev->mtu + ETH_HLEN) &&
3263 skb->protocol != htons(0x8100) &&
3264 skb->protocol != htons(ETH_P_8021AD)) {
Michael Chanb6016b72005-05-26 13:03:09 -07003265
Michael Chan745720e2006-06-29 12:37:41 -07003266 dev_kfree_skb(skb);
Michael Chanb6016b72005-05-26 13:03:09 -07003267 goto next_rx;
3268
3269 }
3270
Eric Dumazetbc8acf22010-09-02 13:07:41 -07003271 skb_checksum_none_assert(skb);
Michał Mirosław8d7dfc22011-04-10 04:47:46 +00003272 if ((bp->dev->features & NETIF_F_RXCSUM) &&
Michael Chanb6016b72005-05-26 13:03:09 -07003273 (status & (L2_FHDR_STATUS_TCP_SEGMENT |
3274 L2_FHDR_STATUS_UDP_DATAGRAM))) {
3275
Michael Chanade2bfe2006-01-23 16:09:51 -08003276 if (likely((status & (L2_FHDR_ERRORS_TCP_XSUM |
3277 L2_FHDR_ERRORS_UDP_XSUM)) == 0))
Michael Chanb6016b72005-05-26 13:03:09 -07003278 skb->ip_summed = CHECKSUM_UNNECESSARY;
3279 }
Michael Chanfdc85412010-07-03 20:42:16 +00003280 if ((bp->dev->features & NETIF_F_RXHASH) &&
3281 ((status & L2_FHDR_STATUS_USE_RXHASH) ==
3282 L2_FHDR_STATUS_USE_RXHASH))
Tom Herbertcf1bfd62013-12-17 23:22:57 -08003283 skb_set_hash(skb, rx_hdr->l2_fhdr_hash,
3284 PKT_HASH_TYPE_L3);
Michael Chanb6016b72005-05-26 13:03:09 -07003285
David S. Miller0c8dfc82009-01-27 16:22:32 -08003286 skb_record_rx_queue(skb, bnapi - &bp->bnx2_napi[0]);
Jesse Gross7d0fd212010-10-20 13:56:09 +00003287 napi_gro_receive(&bnapi->napi, skb);
Michael Chanb6016b72005-05-26 13:03:09 -07003288 rx_pkt++;
3289
3290next_rx:
Michael Chan2bc40782012-12-06 10:33:09 +00003291 sw_cons = BNX2_NEXT_RX_BD(sw_cons);
3292 sw_prod = BNX2_NEXT_RX_BD(sw_prod);
Michael Chanb6016b72005-05-26 13:03:09 -07003293
3294 if ((rx_pkt == budget))
3295 break;
Michael Chanf4e418f2005-11-04 08:53:48 -08003296
3297 /* Refresh hw_cons to see if there is new work */
3298 if (sw_cons == hw_cons) {
Michael Chan35efa7c2007-12-20 19:56:37 -08003299 hw_cons = bnx2_get_hw_rx_cons(bnapi);
Michael Chanf4e418f2005-11-04 08:53:48 -08003300 rmb();
3301 }
Michael Chanb6016b72005-05-26 13:03:09 -07003302 }
Michael Chanbb4f98a2008-06-19 16:38:19 -07003303 rxr->rx_cons = sw_cons;
3304 rxr->rx_prod = sw_prod;
Michael Chanb6016b72005-05-26 13:03:09 -07003305
Michael Chan1db82f22007-12-12 11:19:35 -08003306 if (pg_ring_used)
Michael Chane503e062012-12-06 10:33:08 +00003307 BNX2_WR16(bp, rxr->rx_pg_bidx_addr, rxr->rx_pg_prod);
Michael Chan1db82f22007-12-12 11:19:35 -08003308
Michael Chane503e062012-12-06 10:33:08 +00003309 BNX2_WR16(bp, rxr->rx_bidx_addr, sw_prod);
Michael Chanb6016b72005-05-26 13:03:09 -07003310
Michael Chane503e062012-12-06 10:33:08 +00003311 BNX2_WR(bp, rxr->rx_bseq_addr, rxr->rx_prod_bseq);
Michael Chanb6016b72005-05-26 13:03:09 -07003312
3313 mmiowb();
3314
3315 return rx_pkt;
3316
3317}
3318
3319/* MSI ISR - The only difference between this and the INTx ISR
3320 * is that the MSI interrupt is always serviced.
3321 */
3322static irqreturn_t
David Howells7d12e782006-10-05 14:55:46 +01003323bnx2_msi(int irq, void *dev_instance)
Michael Chanb6016b72005-05-26 13:03:09 -07003324{
Michael Chanf0ea2e62008-06-19 16:41:57 -07003325 struct bnx2_napi *bnapi = dev_instance;
3326 struct bnx2 *bp = bnapi->bp;
Michael Chanb6016b72005-05-26 13:03:09 -07003327
Michael Chan43e80b82008-06-19 16:41:08 -07003328 prefetch(bnapi->status_blk.msi);
Michael Chane503e062012-12-06 10:33:08 +00003329 BNX2_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
Michael Chanb6016b72005-05-26 13:03:09 -07003330 BNX2_PCICFG_INT_ACK_CMD_USE_INT_HC_PARAM |
3331 BNX2_PCICFG_INT_ACK_CMD_MASK_INT);
3332
3333 /* Return here if interrupt is disabled. */
Michael Chan73eef4c2005-08-25 15:39:15 -07003334 if (unlikely(atomic_read(&bp->intr_sem) != 0))
3335 return IRQ_HANDLED;
Michael Chanb6016b72005-05-26 13:03:09 -07003336
Ben Hutchings288379f2009-01-19 16:43:59 -08003337 napi_schedule(&bnapi->napi);
Michael Chanb6016b72005-05-26 13:03:09 -07003338
Michael Chan73eef4c2005-08-25 15:39:15 -07003339 return IRQ_HANDLED;
Michael Chanb6016b72005-05-26 13:03:09 -07003340}
3341
3342static irqreturn_t
Michael Chan8e6a72c2007-05-03 13:24:48 -07003343bnx2_msi_1shot(int irq, void *dev_instance)
3344{
Michael Chanf0ea2e62008-06-19 16:41:57 -07003345 struct bnx2_napi *bnapi = dev_instance;
3346 struct bnx2 *bp = bnapi->bp;
Michael Chan8e6a72c2007-05-03 13:24:48 -07003347
Michael Chan43e80b82008-06-19 16:41:08 -07003348 prefetch(bnapi->status_blk.msi);
Michael Chan8e6a72c2007-05-03 13:24:48 -07003349
3350 /* Return here if interrupt is disabled. */
3351 if (unlikely(atomic_read(&bp->intr_sem) != 0))
3352 return IRQ_HANDLED;
3353
Ben Hutchings288379f2009-01-19 16:43:59 -08003354 napi_schedule(&bnapi->napi);
Michael Chan8e6a72c2007-05-03 13:24:48 -07003355
3356 return IRQ_HANDLED;
3357}
3358
3359static irqreturn_t
David Howells7d12e782006-10-05 14:55:46 +01003360bnx2_interrupt(int irq, void *dev_instance)
Michael Chanb6016b72005-05-26 13:03:09 -07003361{
Michael Chanf0ea2e62008-06-19 16:41:57 -07003362 struct bnx2_napi *bnapi = dev_instance;
3363 struct bnx2 *bp = bnapi->bp;
Michael Chan43e80b82008-06-19 16:41:08 -07003364 struct status_block *sblk = bnapi->status_blk.msi;
Michael Chanb6016b72005-05-26 13:03:09 -07003365
3366 /* When using INTx, it is possible for the interrupt to arrive
3367 * at the CPU before the status block posted prior to the
3368 * interrupt. Reading a register will flush the status block.
3369 * When using MSI, the MSI message will always complete after
3370 * the status block write.
3371 */
Michael Chan35efa7c2007-12-20 19:56:37 -08003372 if ((sblk->status_idx == bnapi->last_status_idx) &&
Michael Chane503e062012-12-06 10:33:08 +00003373 (BNX2_RD(bp, BNX2_PCICFG_MISC_STATUS) &
Michael Chanb6016b72005-05-26 13:03:09 -07003374 BNX2_PCICFG_MISC_STATUS_INTA_VALUE))
Michael Chan73eef4c2005-08-25 15:39:15 -07003375 return IRQ_NONE;
Michael Chanb6016b72005-05-26 13:03:09 -07003376
Michael Chane503e062012-12-06 10:33:08 +00003377 BNX2_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
Michael Chanb6016b72005-05-26 13:03:09 -07003378 BNX2_PCICFG_INT_ACK_CMD_USE_INT_HC_PARAM |
3379 BNX2_PCICFG_INT_ACK_CMD_MASK_INT);
3380
Michael Chanb8a7ce72007-07-07 22:51:03 -07003381 /* Read back to deassert IRQ immediately to avoid too many
3382 * spurious interrupts.
3383 */
Michael Chane503e062012-12-06 10:33:08 +00003384 BNX2_RD(bp, BNX2_PCICFG_INT_ACK_CMD);
Michael Chanb8a7ce72007-07-07 22:51:03 -07003385
Michael Chanb6016b72005-05-26 13:03:09 -07003386 /* Return here if interrupt is shared and is disabled. */
Michael Chan73eef4c2005-08-25 15:39:15 -07003387 if (unlikely(atomic_read(&bp->intr_sem) != 0))
3388 return IRQ_HANDLED;
Michael Chanb6016b72005-05-26 13:03:09 -07003389
Ben Hutchings288379f2009-01-19 16:43:59 -08003390 if (napi_schedule_prep(&bnapi->napi)) {
Michael Chan35efa7c2007-12-20 19:56:37 -08003391 bnapi->last_status_idx = sblk->status_idx;
Ben Hutchings288379f2009-01-19 16:43:59 -08003392 __napi_schedule(&bnapi->napi);
Michael Chanb8a7ce72007-07-07 22:51:03 -07003393 }
Michael Chanb6016b72005-05-26 13:03:09 -07003394
Michael Chan73eef4c2005-08-25 15:39:15 -07003395 return IRQ_HANDLED;
Michael Chanb6016b72005-05-26 13:03:09 -07003396}
3397
Michael Chan43e80b82008-06-19 16:41:08 -07003398static inline int
3399bnx2_has_fast_work(struct bnx2_napi *bnapi)
3400{
3401 struct bnx2_tx_ring_info *txr = &bnapi->tx_ring;
3402 struct bnx2_rx_ring_info *rxr = &bnapi->rx_ring;
3403
3404 if ((bnx2_get_hw_rx_cons(bnapi) != rxr->rx_cons) ||
3405 (bnx2_get_hw_tx_cons(bnapi) != txr->hw_tx_cons))
3406 return 1;
3407 return 0;
3408}
3409
Michael Chan0d8a6572007-07-07 22:49:43 -07003410#define STATUS_ATTN_EVENTS (STATUS_ATTN_BITS_LINK_STATE | \
3411 STATUS_ATTN_BITS_TIMER_ABORT)
Michael Chanda3e4fb2007-05-03 13:24:23 -07003412
Michael Chanf4e418f2005-11-04 08:53:48 -08003413static inline int
Michael Chan35efa7c2007-12-20 19:56:37 -08003414bnx2_has_work(struct bnx2_napi *bnapi)
Michael Chanf4e418f2005-11-04 08:53:48 -08003415{
Michael Chan43e80b82008-06-19 16:41:08 -07003416 struct status_block *sblk = bnapi->status_blk.msi;
Michael Chanf4e418f2005-11-04 08:53:48 -08003417
Michael Chan43e80b82008-06-19 16:41:08 -07003418 if (bnx2_has_fast_work(bnapi))
Michael Chanf4e418f2005-11-04 08:53:48 -08003419 return 1;
3420
Michael Chan4edd4732009-06-08 18:14:42 -07003421#ifdef BCM_CNIC
3422 if (bnapi->cnic_present && (bnapi->cnic_tag != sblk->status_idx))
3423 return 1;
3424#endif
3425
Michael Chanda3e4fb2007-05-03 13:24:23 -07003426 if ((sblk->status_attn_bits & STATUS_ATTN_EVENTS) !=
3427 (sblk->status_attn_bits_ack & STATUS_ATTN_EVENTS))
Michael Chanf4e418f2005-11-04 08:53:48 -08003428 return 1;
3429
3430 return 0;
3431}
3432
Michael Chanefba0182008-12-03 00:36:15 -08003433static void
3434bnx2_chk_missed_msi(struct bnx2 *bp)
3435{
3436 struct bnx2_napi *bnapi = &bp->bnx2_napi[0];
3437 u32 msi_ctrl;
3438
3439 if (bnx2_has_work(bnapi)) {
Michael Chane503e062012-12-06 10:33:08 +00003440 msi_ctrl = BNX2_RD(bp, BNX2_PCICFG_MSI_CONTROL);
Michael Chanefba0182008-12-03 00:36:15 -08003441 if (!(msi_ctrl & BNX2_PCICFG_MSI_CONTROL_ENABLE))
3442 return;
3443
3444 if (bnapi->last_status_idx == bp->idle_chk_status_idx) {
Michael Chane503e062012-12-06 10:33:08 +00003445 BNX2_WR(bp, BNX2_PCICFG_MSI_CONTROL, msi_ctrl &
3446 ~BNX2_PCICFG_MSI_CONTROL_ENABLE);
3447 BNX2_WR(bp, BNX2_PCICFG_MSI_CONTROL, msi_ctrl);
Michael Chanefba0182008-12-03 00:36:15 -08003448 bnx2_msi(bp->irq_tbl[0].vector, bnapi);
3449 }
3450 }
3451
3452 bp->idle_chk_status_idx = bnapi->last_status_idx;
3453}
3454
Michael Chan4edd4732009-06-08 18:14:42 -07003455#ifdef BCM_CNIC
3456static void bnx2_poll_cnic(struct bnx2 *bp, struct bnx2_napi *bnapi)
3457{
3458 struct cnic_ops *c_ops;
3459
3460 if (!bnapi->cnic_present)
3461 return;
3462
3463 rcu_read_lock();
3464 c_ops = rcu_dereference(bp->cnic_ops);
3465 if (c_ops)
3466 bnapi->cnic_tag = c_ops->cnic_handler(bp->cnic_data,
3467 bnapi->status_blk.msi);
3468 rcu_read_unlock();
3469}
3470#endif
3471
Michael Chan43e80b82008-06-19 16:41:08 -07003472static void bnx2_poll_link(struct bnx2 *bp, struct bnx2_napi *bnapi)
Michael Chanb6016b72005-05-26 13:03:09 -07003473{
Michael Chan43e80b82008-06-19 16:41:08 -07003474 struct status_block *sblk = bnapi->status_blk.msi;
Michael Chanda3e4fb2007-05-03 13:24:23 -07003475 u32 status_attn_bits = sblk->status_attn_bits;
3476 u32 status_attn_bits_ack = sblk->status_attn_bits_ack;
Michael Chanb6016b72005-05-26 13:03:09 -07003477
Michael Chanda3e4fb2007-05-03 13:24:23 -07003478 if ((status_attn_bits & STATUS_ATTN_EVENTS) !=
3479 (status_attn_bits_ack & STATUS_ATTN_EVENTS)) {
Michael Chanb6016b72005-05-26 13:03:09 -07003480
Michael Chan35efa7c2007-12-20 19:56:37 -08003481 bnx2_phy_int(bp, bnapi);
Michael Chanbf5295b2006-03-23 01:11:56 -08003482
3483 /* This is needed to take care of transient status
3484 * during link changes.
3485 */
Michael Chane503e062012-12-06 10:33:08 +00003486 BNX2_WR(bp, BNX2_HC_COMMAND,
3487 bp->hc_cmd | BNX2_HC_COMMAND_COAL_NOW_WO_INT);
3488 BNX2_RD(bp, BNX2_HC_COMMAND);
Michael Chanb6016b72005-05-26 13:03:09 -07003489 }
Michael Chan43e80b82008-06-19 16:41:08 -07003490}
3491
3492static int bnx2_poll_work(struct bnx2 *bp, struct bnx2_napi *bnapi,
3493 int work_done, int budget)
3494{
3495 struct bnx2_tx_ring_info *txr = &bnapi->tx_ring;
3496 struct bnx2_rx_ring_info *rxr = &bnapi->rx_ring;
Michael Chanb6016b72005-05-26 13:03:09 -07003497
Michael Chan35e90102008-06-19 16:37:42 -07003498 if (bnx2_get_hw_tx_cons(bnapi) != txr->hw_tx_cons)
Michael Chan57851d82007-12-20 20:01:44 -08003499 bnx2_tx_int(bp, bnapi, 0);
Michael Chanb6016b72005-05-26 13:03:09 -07003500
Michael Chanbb4f98a2008-06-19 16:38:19 -07003501 if (bnx2_get_hw_rx_cons(bnapi) != rxr->rx_cons)
Michael Chan35efa7c2007-12-20 19:56:37 -08003502 work_done += bnx2_rx_int(bp, bnapi, budget - work_done);
Jeff Garzik6aa20a22006-09-13 13:24:59 -04003503
David S. Miller6f535762007-10-11 18:08:29 -07003504 return work_done;
3505}
Michael Chanf4e418f2005-11-04 08:53:48 -08003506
Michael Chanf0ea2e62008-06-19 16:41:57 -07003507static int bnx2_poll_msix(struct napi_struct *napi, int budget)
3508{
3509 struct bnx2_napi *bnapi = container_of(napi, struct bnx2_napi, napi);
3510 struct bnx2 *bp = bnapi->bp;
3511 int work_done = 0;
3512 struct status_block_msix *sblk = bnapi->status_blk.msix;
3513
3514 while (1) {
3515 work_done = bnx2_poll_work(bp, bnapi, work_done, budget);
3516 if (unlikely(work_done >= budget))
3517 break;
3518
3519 bnapi->last_status_idx = sblk->status_idx;
3520 /* status idx must be read before checking for more work. */
3521 rmb();
3522 if (likely(!bnx2_has_fast_work(bnapi))) {
3523
Ben Hutchings288379f2009-01-19 16:43:59 -08003524 napi_complete(napi);
Michael Chane503e062012-12-06 10:33:08 +00003525 BNX2_WR(bp, BNX2_PCICFG_INT_ACK_CMD, bnapi->int_num |
3526 BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
3527 bnapi->last_status_idx);
Michael Chanf0ea2e62008-06-19 16:41:57 -07003528 break;
3529 }
3530 }
3531 return work_done;
3532}
3533
David S. Miller6f535762007-10-11 18:08:29 -07003534static int bnx2_poll(struct napi_struct *napi, int budget)
3535{
Michael Chan35efa7c2007-12-20 19:56:37 -08003536 struct bnx2_napi *bnapi = container_of(napi, struct bnx2_napi, napi);
3537 struct bnx2 *bp = bnapi->bp;
David S. Miller6f535762007-10-11 18:08:29 -07003538 int work_done = 0;
Michael Chan43e80b82008-06-19 16:41:08 -07003539 struct status_block *sblk = bnapi->status_blk.msi;
David S. Miller6f535762007-10-11 18:08:29 -07003540
3541 while (1) {
Michael Chan43e80b82008-06-19 16:41:08 -07003542 bnx2_poll_link(bp, bnapi);
3543
Michael Chan35efa7c2007-12-20 19:56:37 -08003544 work_done = bnx2_poll_work(bp, bnapi, work_done, budget);
David S. Miller6f535762007-10-11 18:08:29 -07003545
Michael Chan4edd4732009-06-08 18:14:42 -07003546#ifdef BCM_CNIC
3547 bnx2_poll_cnic(bp, bnapi);
3548#endif
3549
Michael Chan35efa7c2007-12-20 19:56:37 -08003550 /* bnapi->last_status_idx is used below to tell the hw how
Michael Chan6dee6422007-10-12 01:40:38 -07003551 * much work has been processed, so we must read it before
3552 * checking for more work.
3553 */
Michael Chan35efa7c2007-12-20 19:56:37 -08003554 bnapi->last_status_idx = sblk->status_idx;
Michael Chanefba0182008-12-03 00:36:15 -08003555
3556 if (unlikely(work_done >= budget))
3557 break;
3558
Michael Chan6dee6422007-10-12 01:40:38 -07003559 rmb();
Michael Chan35efa7c2007-12-20 19:56:37 -08003560 if (likely(!bnx2_has_work(bnapi))) {
Ben Hutchings288379f2009-01-19 16:43:59 -08003561 napi_complete(napi);
David S. Millerf86e82f2008-01-21 17:15:40 -08003562 if (likely(bp->flags & BNX2_FLAG_USING_MSI_OR_MSIX)) {
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 bnapi->last_status_idx);
Michael Chan6dee6422007-10-12 01:40:38 -07003566 break;
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 BNX2_PCICFG_INT_ACK_CMD_MASK_INT |
3571 bnapi->last_status_idx);
David S. Miller6f535762007-10-11 18:08:29 -07003572
Michael Chane503e062012-12-06 10:33:08 +00003573 BNX2_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
3574 BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
3575 bnapi->last_status_idx);
David S. Miller6f535762007-10-11 18:08:29 -07003576 break;
Michael Chan1269a8a2006-01-23 16:11:03 -08003577 }
Michael Chanb6016b72005-05-26 13:03:09 -07003578 }
3579
Stephen Hemmingerbea33482007-10-03 16:41:36 -07003580 return work_done;
Michael Chanb6016b72005-05-26 13:03:09 -07003581}
3582
Herbert Xu932ff272006-06-09 12:20:56 -07003583/* Called with rtnl_lock from vlan functions and also netif_tx_lock
Michael Chanb6016b72005-05-26 13:03:09 -07003584 * from set_multicast.
3585 */
3586static void
3587bnx2_set_rx_mode(struct net_device *dev)
3588{
Michael Chan972ec0d2006-01-23 16:12:43 -08003589 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07003590 u32 rx_mode, sort_mode;
Jiri Pirkoccffad252009-05-22 23:22:17 +00003591 struct netdev_hw_addr *ha;
Michael Chanb6016b72005-05-26 13:03:09 -07003592 int i;
Michael Chanb6016b72005-05-26 13:03:09 -07003593
Michael Chan9f52b562008-10-09 12:21:46 -07003594 if (!netif_running(dev))
3595 return;
3596
Michael Chanc770a652005-08-25 15:38:39 -07003597 spin_lock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07003598
3599 rx_mode = bp->rx_mode & ~(BNX2_EMAC_RX_MODE_PROMISCUOUS |
3600 BNX2_EMAC_RX_MODE_KEEP_VLAN_TAG);
3601 sort_mode = 1 | BNX2_RPM_SORT_USER0_BC_EN;
Patrick McHardyf6469682013-04-19 02:04:27 +00003602 if (!(dev->features & NETIF_F_HW_VLAN_CTAG_RX) &&
Jesse Gross7d0fd212010-10-20 13:56:09 +00003603 (bp->flags & BNX2_FLAG_CAN_KEEP_VLAN))
Michael Chanb6016b72005-05-26 13:03:09 -07003604 rx_mode |= BNX2_EMAC_RX_MODE_KEEP_VLAN_TAG;
Michael Chanb6016b72005-05-26 13:03:09 -07003605 if (dev->flags & IFF_PROMISC) {
3606 /* Promiscuous mode. */
3607 rx_mode |= BNX2_EMAC_RX_MODE_PROMISCUOUS;
Michael Chan75108732006-11-19 14:06:40 -08003608 sort_mode |= BNX2_RPM_SORT_USER0_PROM_EN |
3609 BNX2_RPM_SORT_USER0_PROM_VLAN;
Michael Chanb6016b72005-05-26 13:03:09 -07003610 }
3611 else if (dev->flags & IFF_ALLMULTI) {
3612 for (i = 0; i < NUM_MC_HASH_REGISTERS; i++) {
Michael Chane503e062012-12-06 10:33:08 +00003613 BNX2_WR(bp, BNX2_EMAC_MULTICAST_HASH0 + (i * 4),
3614 0xffffffff);
Michael Chanb6016b72005-05-26 13:03:09 -07003615 }
3616 sort_mode |= BNX2_RPM_SORT_USER0_MC_EN;
3617 }
3618 else {
3619 /* Accept one or more multicast(s). */
Michael Chanb6016b72005-05-26 13:03:09 -07003620 u32 mc_filter[NUM_MC_HASH_REGISTERS];
3621 u32 regidx;
3622 u32 bit;
3623 u32 crc;
3624
3625 memset(mc_filter, 0, 4 * NUM_MC_HASH_REGISTERS);
3626
Jiri Pirko22bedad32010-04-01 21:22:57 +00003627 netdev_for_each_mc_addr(ha, dev) {
3628 crc = ether_crc_le(ETH_ALEN, ha->addr);
Michael Chanb6016b72005-05-26 13:03:09 -07003629 bit = crc & 0xff;
3630 regidx = (bit & 0xe0) >> 5;
3631 bit &= 0x1f;
3632 mc_filter[regidx] |= (1 << bit);
3633 }
3634
3635 for (i = 0; i < NUM_MC_HASH_REGISTERS; i++) {
Michael Chane503e062012-12-06 10:33:08 +00003636 BNX2_WR(bp, BNX2_EMAC_MULTICAST_HASH0 + (i * 4),
3637 mc_filter[i]);
Michael Chanb6016b72005-05-26 13:03:09 -07003638 }
3639
3640 sort_mode |= BNX2_RPM_SORT_USER0_MC_HSH_EN;
3641 }
3642
Jiri Pirko32e7bfc2010-01-25 13:36:10 -08003643 if (netdev_uc_count(dev) > BNX2_MAX_UNICAST_ADDRESSES) {
Benjamin Li5fcaed02008-07-14 22:39:52 -07003644 rx_mode |= BNX2_EMAC_RX_MODE_PROMISCUOUS;
3645 sort_mode |= BNX2_RPM_SORT_USER0_PROM_EN |
3646 BNX2_RPM_SORT_USER0_PROM_VLAN;
3647 } else if (!(dev->flags & IFF_PROMISC)) {
Benjamin Li5fcaed02008-07-14 22:39:52 -07003648 /* Add all entries into to the match filter list */
Jiri Pirkoccffad252009-05-22 23:22:17 +00003649 i = 0;
Jiri Pirko32e7bfc2010-01-25 13:36:10 -08003650 netdev_for_each_uc_addr(ha, dev) {
Jiri Pirkoccffad252009-05-22 23:22:17 +00003651 bnx2_set_mac_addr(bp, ha->addr,
Benjamin Li5fcaed02008-07-14 22:39:52 -07003652 i + BNX2_START_UNICAST_ADDRESS_INDEX);
3653 sort_mode |= (1 <<
3654 (i + BNX2_START_UNICAST_ADDRESS_INDEX));
Jiri Pirkoccffad252009-05-22 23:22:17 +00003655 i++;
Benjamin Li5fcaed02008-07-14 22:39:52 -07003656 }
3657
3658 }
3659
Michael Chanb6016b72005-05-26 13:03:09 -07003660 if (rx_mode != bp->rx_mode) {
3661 bp->rx_mode = rx_mode;
Michael Chane503e062012-12-06 10:33:08 +00003662 BNX2_WR(bp, BNX2_EMAC_RX_MODE, rx_mode);
Michael Chanb6016b72005-05-26 13:03:09 -07003663 }
3664
Michael Chane503e062012-12-06 10:33:08 +00003665 BNX2_WR(bp, BNX2_RPM_SORT_USER0, 0x0);
3666 BNX2_WR(bp, BNX2_RPM_SORT_USER0, sort_mode);
3667 BNX2_WR(bp, BNX2_RPM_SORT_USER0, sort_mode | BNX2_RPM_SORT_USER0_ENA);
Michael Chanb6016b72005-05-26 13:03:09 -07003668
Michael Chanc770a652005-08-25 15:38:39 -07003669 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07003670}
3671
françois romieu7880b722011-09-30 00:36:52 +00003672static int
Michael Chan57579f72009-04-04 16:51:14 -07003673check_fw_section(const struct firmware *fw,
3674 const struct bnx2_fw_file_section *section,
3675 u32 alignment, bool non_empty)
Michael Chanb6016b72005-05-26 13:03:09 -07003676{
Michael Chan57579f72009-04-04 16:51:14 -07003677 u32 offset = be32_to_cpu(section->offset);
3678 u32 len = be32_to_cpu(section->len);
Michael Chanb6016b72005-05-26 13:03:09 -07003679
Michael Chan57579f72009-04-04 16:51:14 -07003680 if ((offset == 0 && len != 0) || offset >= fw->size || offset & 3)
3681 return -EINVAL;
3682 if ((non_empty && len == 0) || len > fw->size - offset ||
3683 len & (alignment - 1))
3684 return -EINVAL;
3685 return 0;
3686}
3687
françois romieu7880b722011-09-30 00:36:52 +00003688static int
Michael Chan57579f72009-04-04 16:51:14 -07003689check_mips_fw_entry(const struct firmware *fw,
3690 const struct bnx2_mips_fw_file_entry *entry)
3691{
3692 if (check_fw_section(fw, &entry->text, 4, true) ||
3693 check_fw_section(fw, &entry->data, 4, false) ||
3694 check_fw_section(fw, &entry->rodata, 4, false))
3695 return -EINVAL;
3696 return 0;
3697}
3698
françois romieu7880b722011-09-30 00:36:52 +00003699static void bnx2_release_firmware(struct bnx2 *bp)
3700{
3701 if (bp->rv2p_firmware) {
3702 release_firmware(bp->mips_firmware);
3703 release_firmware(bp->rv2p_firmware);
3704 bp->rv2p_firmware = NULL;
3705 }
3706}
3707
3708static int bnx2_request_uncached_firmware(struct bnx2 *bp)
Michael Chan57579f72009-04-04 16:51:14 -07003709{
3710 const char *mips_fw_file, *rv2p_fw_file;
Bastian Blank5ee1c322009-04-08 15:50:07 -07003711 const struct bnx2_mips_fw_file *mips_fw;
3712 const struct bnx2_rv2p_fw_file *rv2p_fw;
Michael Chan57579f72009-04-04 16:51:14 -07003713 int rc;
3714
Michael Chan4ce45e02012-12-06 10:33:10 +00003715 if (BNX2_CHIP(bp) == BNX2_CHIP_5709) {
Michael Chan57579f72009-04-04 16:51:14 -07003716 mips_fw_file = FW_MIPS_FILE_09;
Michael Chan4ce45e02012-12-06 10:33:10 +00003717 if ((BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5709_A0) ||
3718 (BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5709_A1))
Michael Chan078b0732009-08-29 00:02:46 -07003719 rv2p_fw_file = FW_RV2P_FILE_09_Ax;
3720 else
3721 rv2p_fw_file = FW_RV2P_FILE_09;
Michael Chan57579f72009-04-04 16:51:14 -07003722 } else {
3723 mips_fw_file = FW_MIPS_FILE_06;
3724 rv2p_fw_file = FW_RV2P_FILE_06;
3725 }
3726
3727 rc = request_firmware(&bp->mips_firmware, mips_fw_file, &bp->pdev->dev);
3728 if (rc) {
Joe Perches3a9c6a42010-02-17 15:01:51 +00003729 pr_err("Can't load firmware file \"%s\"\n", mips_fw_file);
françois romieu7880b722011-09-30 00:36:52 +00003730 goto out;
Michael Chan57579f72009-04-04 16:51:14 -07003731 }
3732
3733 rc = request_firmware(&bp->rv2p_firmware, rv2p_fw_file, &bp->pdev->dev);
3734 if (rc) {
Joe Perches3a9c6a42010-02-17 15:01:51 +00003735 pr_err("Can't load firmware file \"%s\"\n", rv2p_fw_file);
françois romieu7880b722011-09-30 00:36:52 +00003736 goto err_release_mips_firmware;
Michael Chan57579f72009-04-04 16:51:14 -07003737 }
Bastian Blank5ee1c322009-04-08 15:50:07 -07003738 mips_fw = (const struct bnx2_mips_fw_file *) bp->mips_firmware->data;
3739 rv2p_fw = (const struct bnx2_rv2p_fw_file *) bp->rv2p_firmware->data;
3740 if (bp->mips_firmware->size < sizeof(*mips_fw) ||
3741 check_mips_fw_entry(bp->mips_firmware, &mips_fw->com) ||
3742 check_mips_fw_entry(bp->mips_firmware, &mips_fw->cp) ||
3743 check_mips_fw_entry(bp->mips_firmware, &mips_fw->rxp) ||
3744 check_mips_fw_entry(bp->mips_firmware, &mips_fw->tpat) ||
3745 check_mips_fw_entry(bp->mips_firmware, &mips_fw->txp)) {
Joe Perches3a9c6a42010-02-17 15:01:51 +00003746 pr_err("Firmware file \"%s\" is invalid\n", mips_fw_file);
françois romieu7880b722011-09-30 00:36:52 +00003747 rc = -EINVAL;
3748 goto err_release_firmware;
Michael Chan57579f72009-04-04 16:51:14 -07003749 }
Bastian Blank5ee1c322009-04-08 15:50:07 -07003750 if (bp->rv2p_firmware->size < sizeof(*rv2p_fw) ||
3751 check_fw_section(bp->rv2p_firmware, &rv2p_fw->proc1.rv2p, 8, true) ||
3752 check_fw_section(bp->rv2p_firmware, &rv2p_fw->proc2.rv2p, 8, true)) {
Joe Perches3a9c6a42010-02-17 15:01:51 +00003753 pr_err("Firmware file \"%s\" is invalid\n", rv2p_fw_file);
françois romieu7880b722011-09-30 00:36:52 +00003754 rc = -EINVAL;
3755 goto err_release_firmware;
Michael Chan57579f72009-04-04 16:51:14 -07003756 }
françois romieu7880b722011-09-30 00:36:52 +00003757out:
3758 return rc;
Michael Chan57579f72009-04-04 16:51:14 -07003759
françois romieu7880b722011-09-30 00:36:52 +00003760err_release_firmware:
3761 release_firmware(bp->rv2p_firmware);
3762 bp->rv2p_firmware = NULL;
3763err_release_mips_firmware:
3764 release_firmware(bp->mips_firmware);
3765 goto out;
3766}
3767
3768static int bnx2_request_firmware(struct bnx2 *bp)
3769{
3770 return bp->rv2p_firmware ? 0 : bnx2_request_uncached_firmware(bp);
Michael Chan57579f72009-04-04 16:51:14 -07003771}
3772
3773static u32
3774rv2p_fw_fixup(u32 rv2p_proc, int idx, u32 loc, u32 rv2p_code)
3775{
3776 switch (idx) {
3777 case RV2P_P1_FIXUP_PAGE_SIZE_IDX:
3778 rv2p_code &= ~RV2P_BD_PAGE_SIZE_MSK;
3779 rv2p_code |= RV2P_BD_PAGE_SIZE;
3780 break;
3781 }
3782 return rv2p_code;
3783}
3784
3785static int
3786load_rv2p_fw(struct bnx2 *bp, u32 rv2p_proc,
3787 const struct bnx2_rv2p_fw_file_entry *fw_entry)
3788{
3789 u32 rv2p_code_len, file_offset;
3790 __be32 *rv2p_code;
3791 int i;
3792 u32 val, cmd, addr;
3793
3794 rv2p_code_len = be32_to_cpu(fw_entry->rv2p.len);
3795 file_offset = be32_to_cpu(fw_entry->rv2p.offset);
3796
3797 rv2p_code = (__be32 *)(bp->rv2p_firmware->data + file_offset);
3798
3799 if (rv2p_proc == RV2P_PROC1) {
3800 cmd = BNX2_RV2P_PROC1_ADDR_CMD_RDWR;
3801 addr = BNX2_RV2P_PROC1_ADDR_CMD;
3802 } else {
3803 cmd = BNX2_RV2P_PROC2_ADDR_CMD_RDWR;
3804 addr = BNX2_RV2P_PROC2_ADDR_CMD;
Michael Chand25be1d2008-05-02 16:57:59 -07003805 }
Michael Chanb6016b72005-05-26 13:03:09 -07003806
3807 for (i = 0; i < rv2p_code_len; i += 8) {
Michael Chane503e062012-12-06 10:33:08 +00003808 BNX2_WR(bp, BNX2_RV2P_INSTR_HIGH, be32_to_cpu(*rv2p_code));
Michael Chanb6016b72005-05-26 13:03:09 -07003809 rv2p_code++;
Michael Chane503e062012-12-06 10:33:08 +00003810 BNX2_WR(bp, BNX2_RV2P_INSTR_LOW, be32_to_cpu(*rv2p_code));
Michael Chanb6016b72005-05-26 13:03:09 -07003811 rv2p_code++;
3812
Michael Chan57579f72009-04-04 16:51:14 -07003813 val = (i / 8) | cmd;
Michael Chane503e062012-12-06 10:33:08 +00003814 BNX2_WR(bp, addr, val);
Michael Chan57579f72009-04-04 16:51:14 -07003815 }
3816
3817 rv2p_code = (__be32 *)(bp->rv2p_firmware->data + file_offset);
3818 for (i = 0; i < 8; i++) {
3819 u32 loc, code;
3820
3821 loc = be32_to_cpu(fw_entry->fixup[i]);
3822 if (loc && ((loc * 4) < rv2p_code_len)) {
3823 code = be32_to_cpu(*(rv2p_code + loc - 1));
Michael Chane503e062012-12-06 10:33:08 +00003824 BNX2_WR(bp, BNX2_RV2P_INSTR_HIGH, code);
Michael Chan57579f72009-04-04 16:51:14 -07003825 code = be32_to_cpu(*(rv2p_code + loc));
3826 code = rv2p_fw_fixup(rv2p_proc, i, loc, code);
Michael Chane503e062012-12-06 10:33:08 +00003827 BNX2_WR(bp, BNX2_RV2P_INSTR_LOW, code);
Michael Chan57579f72009-04-04 16:51:14 -07003828
3829 val = (loc / 2) | cmd;
Michael Chane503e062012-12-06 10:33:08 +00003830 BNX2_WR(bp, addr, val);
Michael Chanb6016b72005-05-26 13:03:09 -07003831 }
3832 }
3833
3834 /* Reset the processor, un-stall is done later. */
3835 if (rv2p_proc == RV2P_PROC1) {
Michael Chane503e062012-12-06 10:33:08 +00003836 BNX2_WR(bp, BNX2_RV2P_COMMAND, BNX2_RV2P_COMMAND_PROC1_RESET);
Michael Chanb6016b72005-05-26 13:03:09 -07003837 }
3838 else {
Michael Chane503e062012-12-06 10:33:08 +00003839 BNX2_WR(bp, BNX2_RV2P_COMMAND, BNX2_RV2P_COMMAND_PROC2_RESET);
Michael Chanb6016b72005-05-26 13:03:09 -07003840 }
Michael Chan57579f72009-04-04 16:51:14 -07003841
3842 return 0;
Michael Chanb6016b72005-05-26 13:03:09 -07003843}
3844
Michael Chanaf3ee512006-11-19 14:09:25 -08003845static int
Michael Chan57579f72009-04-04 16:51:14 -07003846load_cpu_fw(struct bnx2 *bp, const struct cpu_reg *cpu_reg,
3847 const struct bnx2_mips_fw_file_entry *fw_entry)
Michael Chanb6016b72005-05-26 13:03:09 -07003848{
Michael Chan57579f72009-04-04 16:51:14 -07003849 u32 addr, len, file_offset;
3850 __be32 *data;
Michael Chanb6016b72005-05-26 13:03:09 -07003851 u32 offset;
3852 u32 val;
3853
3854 /* Halt the CPU. */
Michael Chan2726d6e2008-01-29 21:35:05 -08003855 val = bnx2_reg_rd_ind(bp, cpu_reg->mode);
Michael Chanb6016b72005-05-26 13:03:09 -07003856 val |= cpu_reg->mode_value_halt;
Michael Chan2726d6e2008-01-29 21:35:05 -08003857 bnx2_reg_wr_ind(bp, cpu_reg->mode, val);
3858 bnx2_reg_wr_ind(bp, cpu_reg->state, cpu_reg->state_value_clear);
Michael Chanb6016b72005-05-26 13:03:09 -07003859
3860 /* Load the Text area. */
Michael Chan57579f72009-04-04 16:51:14 -07003861 addr = be32_to_cpu(fw_entry->text.addr);
3862 len = be32_to_cpu(fw_entry->text.len);
3863 file_offset = be32_to_cpu(fw_entry->text.offset);
3864 data = (__be32 *)(bp->mips_firmware->data + file_offset);
3865
3866 offset = cpu_reg->spad_base + (addr - cpu_reg->mips_view_base);
3867 if (len) {
Michael Chanb6016b72005-05-26 13:03:09 -07003868 int j;
3869
Michael Chan57579f72009-04-04 16:51:14 -07003870 for (j = 0; j < (len / 4); j++, offset += 4)
3871 bnx2_reg_wr_ind(bp, offset, be32_to_cpu(data[j]));
Michael Chanb6016b72005-05-26 13:03:09 -07003872 }
3873
3874 /* Load the Data area. */
Michael Chan57579f72009-04-04 16:51:14 -07003875 addr = be32_to_cpu(fw_entry->data.addr);
3876 len = be32_to_cpu(fw_entry->data.len);
3877 file_offset = be32_to_cpu(fw_entry->data.offset);
3878 data = (__be32 *)(bp->mips_firmware->data + file_offset);
3879
3880 offset = cpu_reg->spad_base + (addr - cpu_reg->mips_view_base);
3881 if (len) {
Michael Chanb6016b72005-05-26 13:03:09 -07003882 int j;
3883
Michael Chan57579f72009-04-04 16:51:14 -07003884 for (j = 0; j < (len / 4); j++, offset += 4)
3885 bnx2_reg_wr_ind(bp, offset, be32_to_cpu(data[j]));
Michael Chanb6016b72005-05-26 13:03:09 -07003886 }
3887
3888 /* Load the Read-Only area. */
Michael Chan57579f72009-04-04 16:51:14 -07003889 addr = be32_to_cpu(fw_entry->rodata.addr);
3890 len = be32_to_cpu(fw_entry->rodata.len);
3891 file_offset = be32_to_cpu(fw_entry->rodata.offset);
3892 data = (__be32 *)(bp->mips_firmware->data + file_offset);
3893
3894 offset = cpu_reg->spad_base + (addr - cpu_reg->mips_view_base);
3895 if (len) {
Michael Chanb6016b72005-05-26 13:03:09 -07003896 int j;
3897
Michael Chan57579f72009-04-04 16:51:14 -07003898 for (j = 0; j < (len / 4); j++, offset += 4)
3899 bnx2_reg_wr_ind(bp, offset, be32_to_cpu(data[j]));
Michael Chanb6016b72005-05-26 13:03:09 -07003900 }
3901
3902 /* Clear the pre-fetch instruction. */
Michael Chan2726d6e2008-01-29 21:35:05 -08003903 bnx2_reg_wr_ind(bp, cpu_reg->inst, 0);
Michael Chan57579f72009-04-04 16:51:14 -07003904
3905 val = be32_to_cpu(fw_entry->start_addr);
3906 bnx2_reg_wr_ind(bp, cpu_reg->pc, val);
Michael Chanb6016b72005-05-26 13:03:09 -07003907
3908 /* Start the CPU. */
Michael Chan2726d6e2008-01-29 21:35:05 -08003909 val = bnx2_reg_rd_ind(bp, cpu_reg->mode);
Michael Chanb6016b72005-05-26 13:03:09 -07003910 val &= ~cpu_reg->mode_value_halt;
Michael Chan2726d6e2008-01-29 21:35:05 -08003911 bnx2_reg_wr_ind(bp, cpu_reg->state, cpu_reg->state_value_clear);
3912 bnx2_reg_wr_ind(bp, cpu_reg->mode, val);
Michael Chanaf3ee512006-11-19 14:09:25 -08003913
3914 return 0;
Michael Chanb6016b72005-05-26 13:03:09 -07003915}
3916
Michael Chanfba9fe92006-06-12 22:21:25 -07003917static int
Michael Chanb6016b72005-05-26 13:03:09 -07003918bnx2_init_cpus(struct bnx2 *bp)
3919{
Michael Chan57579f72009-04-04 16:51:14 -07003920 const struct bnx2_mips_fw_file *mips_fw =
3921 (const struct bnx2_mips_fw_file *) bp->mips_firmware->data;
3922 const struct bnx2_rv2p_fw_file *rv2p_fw =
3923 (const struct bnx2_rv2p_fw_file *) bp->rv2p_firmware->data;
3924 int rc;
Michael Chanb6016b72005-05-26 13:03:09 -07003925
3926 /* Initialize the RV2P processor. */
Michael Chan57579f72009-04-04 16:51:14 -07003927 load_rv2p_fw(bp, RV2P_PROC1, &rv2p_fw->proc1);
3928 load_rv2p_fw(bp, RV2P_PROC2, &rv2p_fw->proc2);
Michael Chanb6016b72005-05-26 13:03:09 -07003929
3930 /* Initialize the RX Processor. */
Michael Chan57579f72009-04-04 16:51:14 -07003931 rc = load_cpu_fw(bp, &cpu_reg_rxp, &mips_fw->rxp);
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 Processor. */
Michael Chan57579f72009-04-04 16:51:14 -07003936 rc = load_cpu_fw(bp, &cpu_reg_txp, &mips_fw->txp);
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 TX Patch-up Processor. */
Michael Chan57579f72009-04-04 16:51:14 -07003941 rc = load_cpu_fw(bp, &cpu_reg_tpat, &mips_fw->tpat);
Michael Chanfba9fe92006-06-12 22:21:25 -07003942 if (rc)
3943 goto init_cpu_err;
3944
Michael Chanb6016b72005-05-26 13:03:09 -07003945 /* Initialize the Completion Processor. */
Michael Chan57579f72009-04-04 16:51:14 -07003946 rc = load_cpu_fw(bp, &cpu_reg_com, &mips_fw->com);
Michael Chanfba9fe92006-06-12 22:21:25 -07003947 if (rc)
3948 goto init_cpu_err;
3949
Michael Chand43584c2006-11-19 14:14:35 -08003950 /* Initialize the Command Processor. */
Michael Chan57579f72009-04-04 16:51:14 -07003951 rc = load_cpu_fw(bp, &cpu_reg_cp, &mips_fw->cp);
Michael Chan110d0ef2007-12-12 11:18:34 -08003952
Michael Chanfba9fe92006-06-12 22:21:25 -07003953init_cpu_err:
Michael Chanfba9fe92006-06-12 22:21:25 -07003954 return rc;
Michael Chanb6016b72005-05-26 13:03:09 -07003955}
3956
Michael Chanb6a23e92013-08-06 15:50:09 -07003957static void
3958bnx2_setup_wol(struct bnx2 *bp)
3959{
3960 int i;
3961 u32 val, wol_msg;
3962
3963 if (bp->wol) {
3964 u32 advertising;
3965 u8 autoneg;
3966
3967 autoneg = bp->autoneg;
3968 advertising = bp->advertising;
3969
3970 if (bp->phy_port == PORT_TP) {
3971 bp->autoneg = AUTONEG_SPEED;
3972 bp->advertising = ADVERTISED_10baseT_Half |
3973 ADVERTISED_10baseT_Full |
3974 ADVERTISED_100baseT_Half |
3975 ADVERTISED_100baseT_Full |
3976 ADVERTISED_Autoneg;
3977 }
3978
3979 spin_lock_bh(&bp->phy_lock);
3980 bnx2_setup_phy(bp, bp->phy_port);
3981 spin_unlock_bh(&bp->phy_lock);
3982
3983 bp->autoneg = autoneg;
3984 bp->advertising = advertising;
3985
3986 bnx2_set_mac_addr(bp, bp->dev->dev_addr, 0);
3987
3988 val = BNX2_RD(bp, BNX2_EMAC_MODE);
3989
3990 /* Enable port mode. */
3991 val &= ~BNX2_EMAC_MODE_PORT;
3992 val |= BNX2_EMAC_MODE_MPKT_RCVD |
3993 BNX2_EMAC_MODE_ACPI_RCVD |
3994 BNX2_EMAC_MODE_MPKT;
3995 if (bp->phy_port == PORT_TP) {
3996 val |= BNX2_EMAC_MODE_PORT_MII;
3997 } else {
3998 val |= BNX2_EMAC_MODE_PORT_GMII;
3999 if (bp->line_speed == SPEED_2500)
4000 val |= BNX2_EMAC_MODE_25G_MODE;
4001 }
4002
4003 BNX2_WR(bp, BNX2_EMAC_MODE, val);
4004
4005 /* receive all multicast */
4006 for (i = 0; i < NUM_MC_HASH_REGISTERS; i++) {
4007 BNX2_WR(bp, BNX2_EMAC_MULTICAST_HASH0 + (i * 4),
4008 0xffffffff);
4009 }
4010 BNX2_WR(bp, BNX2_EMAC_RX_MODE, BNX2_EMAC_RX_MODE_SORT_MODE);
4011
4012 val = 1 | BNX2_RPM_SORT_USER0_BC_EN | BNX2_RPM_SORT_USER0_MC_EN;
4013 BNX2_WR(bp, BNX2_RPM_SORT_USER0, 0x0);
4014 BNX2_WR(bp, BNX2_RPM_SORT_USER0, val);
4015 BNX2_WR(bp, BNX2_RPM_SORT_USER0, val | BNX2_RPM_SORT_USER0_ENA);
4016
4017 /* Need to enable EMAC and RPM for WOL. */
4018 BNX2_WR(bp, BNX2_MISC_ENABLE_SET_BITS,
4019 BNX2_MISC_ENABLE_SET_BITS_RX_PARSER_MAC_ENABLE |
4020 BNX2_MISC_ENABLE_SET_BITS_TX_HEADER_Q_ENABLE |
4021 BNX2_MISC_ENABLE_SET_BITS_EMAC_ENABLE);
4022
4023 val = BNX2_RD(bp, BNX2_RPM_CONFIG);
4024 val &= ~BNX2_RPM_CONFIG_ACPI_ENA;
4025 BNX2_WR(bp, BNX2_RPM_CONFIG, val);
4026
4027 wol_msg = BNX2_DRV_MSG_CODE_SUSPEND_WOL;
4028 } else {
4029 wol_msg = BNX2_DRV_MSG_CODE_SUSPEND_NO_WOL;
4030 }
4031
Michael Chana8d9bc22014-03-09 15:45:32 -08004032 if (!(bp->flags & BNX2_FLAG_NO_WOL)) {
4033 u32 val;
4034
4035 wol_msg |= BNX2_DRV_MSG_DATA_WAIT3;
4036 if (bp->fw_last_msg || BNX2_CHIP(bp) != BNX2_CHIP_5709) {
4037 bnx2_fw_sync(bp, wol_msg, 1, 0);
4038 return;
4039 }
4040 /* Tell firmware not to power down the PHY yet, otherwise
4041 * the chip will take a long time to respond to MMIO reads.
4042 */
4043 val = bnx2_shmem_rd(bp, BNX2_PORT_FEATURE);
4044 bnx2_shmem_wr(bp, BNX2_PORT_FEATURE,
4045 val | BNX2_PORT_FEATURE_ASF_ENABLED);
4046 bnx2_fw_sync(bp, wol_msg, 1, 0);
4047 bnx2_shmem_wr(bp, BNX2_PORT_FEATURE, val);
4048 }
Michael Chanb6a23e92013-08-06 15:50:09 -07004049
4050}
4051
Michael Chanb6016b72005-05-26 13:03:09 -07004052static int
Pavel Machek829ca9a2005-09-03 15:56:56 -07004053bnx2_set_power_state(struct bnx2 *bp, pci_power_t state)
Michael Chanb6016b72005-05-26 13:03:09 -07004054{
Michael Chanb6016b72005-05-26 13:03:09 -07004055 switch (state) {
Pavel Machek829ca9a2005-09-03 15:56:56 -07004056 case PCI_D0: {
Michael Chanb6016b72005-05-26 13:03:09 -07004057 u32 val;
4058
Michael Chan6d5e85c2013-08-06 15:50:08 -07004059 pci_enable_wake(bp->pdev, PCI_D0, false);
4060 pci_set_power_state(bp->pdev, PCI_D0);
Michael Chanb6016b72005-05-26 13:03:09 -07004061
Michael Chane503e062012-12-06 10:33:08 +00004062 val = BNX2_RD(bp, BNX2_EMAC_MODE);
Michael Chanb6016b72005-05-26 13:03:09 -07004063 val |= BNX2_EMAC_MODE_MPKT_RCVD | BNX2_EMAC_MODE_ACPI_RCVD;
4064 val &= ~BNX2_EMAC_MODE_MPKT;
Michael Chane503e062012-12-06 10:33:08 +00004065 BNX2_WR(bp, BNX2_EMAC_MODE, val);
Michael Chanb6016b72005-05-26 13:03:09 -07004066
Michael Chane503e062012-12-06 10:33:08 +00004067 val = BNX2_RD(bp, BNX2_RPM_CONFIG);
Michael Chanb6016b72005-05-26 13:03:09 -07004068 val &= ~BNX2_RPM_CONFIG_ACPI_ENA;
Michael Chane503e062012-12-06 10:33:08 +00004069 BNX2_WR(bp, BNX2_RPM_CONFIG, val);
Michael Chanb6016b72005-05-26 13:03:09 -07004070 break;
4071 }
Pavel Machek829ca9a2005-09-03 15:56:56 -07004072 case PCI_D3hot: {
Michael Chanb6a23e92013-08-06 15:50:09 -07004073 bnx2_setup_wol(bp);
Michael Chan6d5e85c2013-08-06 15:50:08 -07004074 pci_wake_from_d3(bp->pdev, bp->wol);
Michael Chan4ce45e02012-12-06 10:33:10 +00004075 if ((BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5706_A0) ||
4076 (BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5706_A1)) {
Michael Chanb6016b72005-05-26 13:03:09 -07004077
4078 if (bp->wol)
Michael Chan6d5e85c2013-08-06 15:50:08 -07004079 pci_set_power_state(bp->pdev, PCI_D3hot);
Michael Chana8d9bc22014-03-09 15:45:32 -08004080 break;
4081
Michael Chanb6016b72005-05-26 13:03:09 -07004082 }
Michael Chana8d9bc22014-03-09 15:45:32 -08004083 if (!bp->fw_last_msg && BNX2_CHIP(bp) == BNX2_CHIP_5709) {
4084 u32 val;
4085
4086 /* Tell firmware not to power down the PHY yet,
4087 * otherwise the other port may not respond to
4088 * MMIO reads.
4089 */
4090 val = bnx2_shmem_rd(bp, BNX2_BC_STATE_CONDITION);
4091 val &= ~BNX2_CONDITION_PM_STATE_MASK;
4092 val |= BNX2_CONDITION_PM_STATE_UNPREP;
4093 bnx2_shmem_wr(bp, BNX2_BC_STATE_CONDITION, val);
4094 }
4095 pci_set_power_state(bp->pdev, PCI_D3hot);
Michael Chanb6016b72005-05-26 13:03:09 -07004096
4097 /* No more memory access after this point until
4098 * device is brought back to D0.
4099 */
Michael Chanb6016b72005-05-26 13:03:09 -07004100 break;
4101 }
4102 default:
4103 return -EINVAL;
4104 }
4105 return 0;
4106}
4107
4108static int
4109bnx2_acquire_nvram_lock(struct bnx2 *bp)
4110{
4111 u32 val;
4112 int j;
4113
4114 /* Request access to the flash interface. */
Michael Chane503e062012-12-06 10:33:08 +00004115 BNX2_WR(bp, BNX2_NVM_SW_ARB, BNX2_NVM_SW_ARB_ARB_REQ_SET2);
Michael Chanb6016b72005-05-26 13:03:09 -07004116 for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) {
Michael Chane503e062012-12-06 10:33:08 +00004117 val = BNX2_RD(bp, BNX2_NVM_SW_ARB);
Michael Chanb6016b72005-05-26 13:03:09 -07004118 if (val & BNX2_NVM_SW_ARB_ARB_ARB2)
4119 break;
4120
4121 udelay(5);
4122 }
4123
4124 if (j >= NVRAM_TIMEOUT_COUNT)
4125 return -EBUSY;
4126
4127 return 0;
4128}
4129
4130static int
4131bnx2_release_nvram_lock(struct bnx2 *bp)
4132{
4133 int j;
4134 u32 val;
4135
4136 /* Relinquish nvram interface. */
Michael Chane503e062012-12-06 10:33:08 +00004137 BNX2_WR(bp, BNX2_NVM_SW_ARB, BNX2_NVM_SW_ARB_ARB_REQ_CLR2);
Michael Chanb6016b72005-05-26 13:03:09 -07004138
4139 for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) {
Michael Chane503e062012-12-06 10:33:08 +00004140 val = BNX2_RD(bp, BNX2_NVM_SW_ARB);
Michael Chanb6016b72005-05-26 13:03:09 -07004141 if (!(val & BNX2_NVM_SW_ARB_ARB_ARB2))
4142 break;
4143
4144 udelay(5);
4145 }
4146
4147 if (j >= NVRAM_TIMEOUT_COUNT)
4148 return -EBUSY;
4149
4150 return 0;
4151}
4152
4153
4154static int
4155bnx2_enable_nvram_write(struct bnx2 *bp)
4156{
4157 u32 val;
4158
Michael Chane503e062012-12-06 10:33:08 +00004159 val = BNX2_RD(bp, BNX2_MISC_CFG);
4160 BNX2_WR(bp, BNX2_MISC_CFG, val | BNX2_MISC_CFG_NVM_WR_EN_PCI);
Michael Chanb6016b72005-05-26 13:03:09 -07004161
Michael Chane30372c2007-07-16 18:26:23 -07004162 if (bp->flash_info->flags & BNX2_NV_WREN) {
Michael Chanb6016b72005-05-26 13:03:09 -07004163 int j;
4164
Michael Chane503e062012-12-06 10:33:08 +00004165 BNX2_WR(bp, BNX2_NVM_COMMAND, BNX2_NVM_COMMAND_DONE);
4166 BNX2_WR(bp, BNX2_NVM_COMMAND,
4167 BNX2_NVM_COMMAND_WREN | BNX2_NVM_COMMAND_DOIT);
Michael Chanb6016b72005-05-26 13:03:09 -07004168
4169 for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) {
4170 udelay(5);
4171
Michael Chane503e062012-12-06 10:33:08 +00004172 val = BNX2_RD(bp, BNX2_NVM_COMMAND);
Michael Chanb6016b72005-05-26 13:03:09 -07004173 if (val & BNX2_NVM_COMMAND_DONE)
4174 break;
4175 }
4176
4177 if (j >= NVRAM_TIMEOUT_COUNT)
4178 return -EBUSY;
4179 }
4180 return 0;
4181}
4182
4183static void
4184bnx2_disable_nvram_write(struct bnx2 *bp)
4185{
4186 u32 val;
4187
Michael Chane503e062012-12-06 10:33:08 +00004188 val = BNX2_RD(bp, BNX2_MISC_CFG);
4189 BNX2_WR(bp, BNX2_MISC_CFG, val & ~BNX2_MISC_CFG_NVM_WR_EN);
Michael Chanb6016b72005-05-26 13:03:09 -07004190}
4191
4192
4193static void
4194bnx2_enable_nvram_access(struct bnx2 *bp)
4195{
4196 u32 val;
4197
Michael Chane503e062012-12-06 10:33:08 +00004198 val = BNX2_RD(bp, BNX2_NVM_ACCESS_ENABLE);
Michael Chanb6016b72005-05-26 13:03:09 -07004199 /* Enable both bits, even on read. */
Michael Chane503e062012-12-06 10:33:08 +00004200 BNX2_WR(bp, BNX2_NVM_ACCESS_ENABLE,
4201 val | BNX2_NVM_ACCESS_ENABLE_EN | BNX2_NVM_ACCESS_ENABLE_WR_EN);
Michael Chanb6016b72005-05-26 13:03:09 -07004202}
4203
4204static void
4205bnx2_disable_nvram_access(struct bnx2 *bp)
4206{
4207 u32 val;
4208
Michael Chane503e062012-12-06 10:33:08 +00004209 val = BNX2_RD(bp, BNX2_NVM_ACCESS_ENABLE);
Michael Chanb6016b72005-05-26 13:03:09 -07004210 /* Disable both bits, even after read. */
Michael Chane503e062012-12-06 10:33:08 +00004211 BNX2_WR(bp, BNX2_NVM_ACCESS_ENABLE,
Michael Chanb6016b72005-05-26 13:03:09 -07004212 val & ~(BNX2_NVM_ACCESS_ENABLE_EN |
4213 BNX2_NVM_ACCESS_ENABLE_WR_EN));
4214}
4215
4216static int
4217bnx2_nvram_erase_page(struct bnx2 *bp, u32 offset)
4218{
4219 u32 cmd;
4220 int j;
4221
Michael Chane30372c2007-07-16 18:26:23 -07004222 if (bp->flash_info->flags & BNX2_NV_BUFFERED)
Michael Chanb6016b72005-05-26 13:03:09 -07004223 /* Buffered flash, no erase needed */
4224 return 0;
4225
4226 /* Build an erase command */
4227 cmd = BNX2_NVM_COMMAND_ERASE | BNX2_NVM_COMMAND_WR |
4228 BNX2_NVM_COMMAND_DOIT;
4229
4230 /* Need to clear DONE bit separately. */
Michael Chane503e062012-12-06 10:33:08 +00004231 BNX2_WR(bp, BNX2_NVM_COMMAND, BNX2_NVM_COMMAND_DONE);
Michael Chanb6016b72005-05-26 13:03:09 -07004232
4233 /* Address of the NVRAM to read from. */
Michael Chane503e062012-12-06 10:33:08 +00004234 BNX2_WR(bp, BNX2_NVM_ADDR, offset & BNX2_NVM_ADDR_NVM_ADDR_VALUE);
Michael Chanb6016b72005-05-26 13:03:09 -07004235
4236 /* Issue an erase command. */
Michael Chane503e062012-12-06 10:33:08 +00004237 BNX2_WR(bp, BNX2_NVM_COMMAND, cmd);
Michael Chanb6016b72005-05-26 13:03:09 -07004238
4239 /* Wait for completion. */
4240 for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) {
4241 u32 val;
4242
4243 udelay(5);
4244
Michael Chane503e062012-12-06 10:33:08 +00004245 val = BNX2_RD(bp, BNX2_NVM_COMMAND);
Michael Chanb6016b72005-05-26 13:03:09 -07004246 if (val & BNX2_NVM_COMMAND_DONE)
4247 break;
4248 }
4249
4250 if (j >= NVRAM_TIMEOUT_COUNT)
4251 return -EBUSY;
4252
4253 return 0;
4254}
4255
4256static int
4257bnx2_nvram_read_dword(struct bnx2 *bp, u32 offset, u8 *ret_val, u32 cmd_flags)
4258{
4259 u32 cmd;
4260 int j;
4261
4262 /* Build the command word. */
4263 cmd = BNX2_NVM_COMMAND_DOIT | cmd_flags;
4264
Michael Chane30372c2007-07-16 18:26:23 -07004265 /* Calculate an offset of a buffered flash, not needed for 5709. */
4266 if (bp->flash_info->flags & BNX2_NV_TRANSLATE) {
Michael Chanb6016b72005-05-26 13:03:09 -07004267 offset = ((offset / bp->flash_info->page_size) <<
4268 bp->flash_info->page_bits) +
4269 (offset % bp->flash_info->page_size);
4270 }
4271
4272 /* Need to clear DONE bit separately. */
Michael Chane503e062012-12-06 10:33:08 +00004273 BNX2_WR(bp, BNX2_NVM_COMMAND, BNX2_NVM_COMMAND_DONE);
Michael Chanb6016b72005-05-26 13:03:09 -07004274
4275 /* Address of the NVRAM to read from. */
Michael Chane503e062012-12-06 10:33:08 +00004276 BNX2_WR(bp, BNX2_NVM_ADDR, offset & BNX2_NVM_ADDR_NVM_ADDR_VALUE);
Michael Chanb6016b72005-05-26 13:03:09 -07004277
4278 /* Issue a read command. */
Michael Chane503e062012-12-06 10:33:08 +00004279 BNX2_WR(bp, BNX2_NVM_COMMAND, cmd);
Michael Chanb6016b72005-05-26 13:03:09 -07004280
4281 /* Wait for completion. */
4282 for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) {
4283 u32 val;
4284
4285 udelay(5);
4286
Michael Chane503e062012-12-06 10:33:08 +00004287 val = BNX2_RD(bp, BNX2_NVM_COMMAND);
Michael Chanb6016b72005-05-26 13:03:09 -07004288 if (val & BNX2_NVM_COMMAND_DONE) {
Michael Chane503e062012-12-06 10:33:08 +00004289 __be32 v = cpu_to_be32(BNX2_RD(bp, BNX2_NVM_READ));
Al Virob491edd2007-12-22 19:44:51 +00004290 memcpy(ret_val, &v, 4);
Michael Chanb6016b72005-05-26 13:03:09 -07004291 break;
4292 }
4293 }
4294 if (j >= NVRAM_TIMEOUT_COUNT)
4295 return -EBUSY;
4296
4297 return 0;
4298}
4299
4300
4301static int
4302bnx2_nvram_write_dword(struct bnx2 *bp, u32 offset, u8 *val, u32 cmd_flags)
4303{
Al Virob491edd2007-12-22 19:44:51 +00004304 u32 cmd;
4305 __be32 val32;
Michael Chanb6016b72005-05-26 13:03:09 -07004306 int j;
4307
4308 /* Build the command word. */
4309 cmd = BNX2_NVM_COMMAND_DOIT | BNX2_NVM_COMMAND_WR | cmd_flags;
4310
Michael Chane30372c2007-07-16 18:26:23 -07004311 /* Calculate an offset of a buffered flash, not needed for 5709. */
4312 if (bp->flash_info->flags & BNX2_NV_TRANSLATE) {
Michael Chanb6016b72005-05-26 13:03:09 -07004313 offset = ((offset / bp->flash_info->page_size) <<
4314 bp->flash_info->page_bits) +
4315 (offset % bp->flash_info->page_size);
4316 }
4317
4318 /* Need to clear DONE bit separately. */
Michael Chane503e062012-12-06 10:33:08 +00004319 BNX2_WR(bp, BNX2_NVM_COMMAND, BNX2_NVM_COMMAND_DONE);
Michael Chanb6016b72005-05-26 13:03:09 -07004320
4321 memcpy(&val32, val, 4);
Michael Chanb6016b72005-05-26 13:03:09 -07004322
4323 /* Write the data. */
Michael Chane503e062012-12-06 10:33:08 +00004324 BNX2_WR(bp, BNX2_NVM_WRITE, be32_to_cpu(val32));
Michael Chanb6016b72005-05-26 13:03:09 -07004325
4326 /* Address of the NVRAM to write to. */
Michael Chane503e062012-12-06 10:33:08 +00004327 BNX2_WR(bp, BNX2_NVM_ADDR, offset & BNX2_NVM_ADDR_NVM_ADDR_VALUE);
Michael Chanb6016b72005-05-26 13:03:09 -07004328
4329 /* Issue the write command. */
Michael Chane503e062012-12-06 10:33:08 +00004330 BNX2_WR(bp, BNX2_NVM_COMMAND, cmd);
Michael Chanb6016b72005-05-26 13:03:09 -07004331
4332 /* Wait for completion. */
4333 for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) {
4334 udelay(5);
4335
Michael Chane503e062012-12-06 10:33:08 +00004336 if (BNX2_RD(bp, BNX2_NVM_COMMAND) & BNX2_NVM_COMMAND_DONE)
Michael Chanb6016b72005-05-26 13:03:09 -07004337 break;
4338 }
4339 if (j >= NVRAM_TIMEOUT_COUNT)
4340 return -EBUSY;
4341
4342 return 0;
4343}
4344
4345static int
4346bnx2_init_nvram(struct bnx2 *bp)
4347{
4348 u32 val;
Michael Chane30372c2007-07-16 18:26:23 -07004349 int j, entry_count, rc = 0;
Michael Chan0ced9d02009-08-21 16:20:49 +00004350 const struct flash_spec *flash;
Michael Chanb6016b72005-05-26 13:03:09 -07004351
Michael Chan4ce45e02012-12-06 10:33:10 +00004352 if (BNX2_CHIP(bp) == BNX2_CHIP_5709) {
Michael Chane30372c2007-07-16 18:26:23 -07004353 bp->flash_info = &flash_5709;
4354 goto get_flash_size;
4355 }
4356
Michael Chanb6016b72005-05-26 13:03:09 -07004357 /* Determine the selected interface. */
Michael Chane503e062012-12-06 10:33:08 +00004358 val = BNX2_RD(bp, BNX2_NVM_CFG1);
Michael Chanb6016b72005-05-26 13:03:09 -07004359
Denis Chengff8ac602007-09-02 18:30:18 +08004360 entry_count = ARRAY_SIZE(flash_table);
Michael Chanb6016b72005-05-26 13:03:09 -07004361
Michael Chanb6016b72005-05-26 13:03:09 -07004362 if (val & 0x40000000) {
4363
4364 /* Flash interface has been reconfigured */
4365 for (j = 0, flash = &flash_table[0]; j < entry_count;
Michael Chan37137702005-11-04 08:49:17 -08004366 j++, flash++) {
4367 if ((val & FLASH_BACKUP_STRAP_MASK) ==
4368 (flash->config1 & FLASH_BACKUP_STRAP_MASK)) {
Michael Chanb6016b72005-05-26 13:03:09 -07004369 bp->flash_info = flash;
4370 break;
4371 }
4372 }
4373 }
4374 else {
Michael Chan37137702005-11-04 08:49:17 -08004375 u32 mask;
Michael Chanb6016b72005-05-26 13:03:09 -07004376 /* Not yet been reconfigured */
4377
Michael Chan37137702005-11-04 08:49:17 -08004378 if (val & (1 << 23))
4379 mask = FLASH_BACKUP_STRAP_MASK;
4380 else
4381 mask = FLASH_STRAP_MASK;
4382
Michael Chanb6016b72005-05-26 13:03:09 -07004383 for (j = 0, flash = &flash_table[0]; j < entry_count;
4384 j++, flash++) {
4385
Michael Chan37137702005-11-04 08:49:17 -08004386 if ((val & mask) == (flash->strapping & mask)) {
Michael Chanb6016b72005-05-26 13:03:09 -07004387 bp->flash_info = flash;
4388
4389 /* Request access to the flash interface. */
4390 if ((rc = bnx2_acquire_nvram_lock(bp)) != 0)
4391 return rc;
4392
4393 /* Enable access to flash interface */
4394 bnx2_enable_nvram_access(bp);
4395
4396 /* Reconfigure the flash interface */
Michael Chane503e062012-12-06 10:33:08 +00004397 BNX2_WR(bp, BNX2_NVM_CFG1, flash->config1);
4398 BNX2_WR(bp, BNX2_NVM_CFG2, flash->config2);
4399 BNX2_WR(bp, BNX2_NVM_CFG3, flash->config3);
4400 BNX2_WR(bp, BNX2_NVM_WRITE1, flash->write1);
Michael Chanb6016b72005-05-26 13:03:09 -07004401
4402 /* Disable access to flash interface */
4403 bnx2_disable_nvram_access(bp);
4404 bnx2_release_nvram_lock(bp);
4405
4406 break;
4407 }
4408 }
4409 } /* if (val & 0x40000000) */
4410
4411 if (j == entry_count) {
4412 bp->flash_info = NULL;
Joe Perches3a9c6a42010-02-17 15:01:51 +00004413 pr_alert("Unknown flash/EEPROM type\n");
Michael Chan1122db72006-01-23 16:11:42 -08004414 return -ENODEV;
Michael Chanb6016b72005-05-26 13:03:09 -07004415 }
4416
Michael Chane30372c2007-07-16 18:26:23 -07004417get_flash_size:
Michael Chan2726d6e2008-01-29 21:35:05 -08004418 val = bnx2_shmem_rd(bp, BNX2_SHARED_HW_CFG_CONFIG2);
Michael Chan1122db72006-01-23 16:11:42 -08004419 val &= BNX2_SHARED_HW_CFG2_NVM_SIZE_MASK;
4420 if (val)
4421 bp->flash_size = val;
4422 else
4423 bp->flash_size = bp->flash_info->total_size;
4424
Michael Chanb6016b72005-05-26 13:03:09 -07004425 return rc;
4426}
4427
4428static int
4429bnx2_nvram_read(struct bnx2 *bp, u32 offset, u8 *ret_buf,
4430 int buf_size)
4431{
4432 int rc = 0;
4433 u32 cmd_flags, offset32, len32, extra;
4434
4435 if (buf_size == 0)
4436 return 0;
4437
4438 /* Request access to the flash interface. */
4439 if ((rc = bnx2_acquire_nvram_lock(bp)) != 0)
4440 return rc;
4441
4442 /* Enable access to flash interface */
4443 bnx2_enable_nvram_access(bp);
4444
4445 len32 = buf_size;
4446 offset32 = offset;
4447 extra = 0;
4448
4449 cmd_flags = 0;
4450
4451 if (offset32 & 3) {
4452 u8 buf[4];
4453 u32 pre_len;
4454
4455 offset32 &= ~3;
4456 pre_len = 4 - (offset & 3);
4457
4458 if (pre_len >= len32) {
4459 pre_len = len32;
4460 cmd_flags = BNX2_NVM_COMMAND_FIRST |
4461 BNX2_NVM_COMMAND_LAST;
4462 }
4463 else {
4464 cmd_flags = BNX2_NVM_COMMAND_FIRST;
4465 }
4466
4467 rc = bnx2_nvram_read_dword(bp, offset32, buf, cmd_flags);
4468
4469 if (rc)
4470 return rc;
4471
4472 memcpy(ret_buf, buf + (offset & 3), pre_len);
4473
4474 offset32 += 4;
4475 ret_buf += pre_len;
4476 len32 -= pre_len;
4477 }
4478 if (len32 & 3) {
4479 extra = 4 - (len32 & 3);
4480 len32 = (len32 + 4) & ~3;
4481 }
4482
4483 if (len32 == 4) {
4484 u8 buf[4];
4485
4486 if (cmd_flags)
4487 cmd_flags = BNX2_NVM_COMMAND_LAST;
4488 else
4489 cmd_flags = BNX2_NVM_COMMAND_FIRST |
4490 BNX2_NVM_COMMAND_LAST;
4491
4492 rc = bnx2_nvram_read_dword(bp, offset32, buf, cmd_flags);
4493
4494 memcpy(ret_buf, buf, 4 - extra);
4495 }
4496 else if (len32 > 0) {
4497 u8 buf[4];
4498
4499 /* Read the first word. */
4500 if (cmd_flags)
4501 cmd_flags = 0;
4502 else
4503 cmd_flags = BNX2_NVM_COMMAND_FIRST;
4504
4505 rc = bnx2_nvram_read_dword(bp, offset32, ret_buf, cmd_flags);
4506
4507 /* Advance to the next dword. */
4508 offset32 += 4;
4509 ret_buf += 4;
4510 len32 -= 4;
4511
4512 while (len32 > 4 && rc == 0) {
4513 rc = bnx2_nvram_read_dword(bp, offset32, ret_buf, 0);
4514
4515 /* Advance to the next dword. */
4516 offset32 += 4;
4517 ret_buf += 4;
4518 len32 -= 4;
4519 }
4520
4521 if (rc)
4522 return rc;
4523
4524 cmd_flags = BNX2_NVM_COMMAND_LAST;
4525 rc = bnx2_nvram_read_dword(bp, offset32, buf, cmd_flags);
4526
4527 memcpy(ret_buf, buf, 4 - extra);
4528 }
4529
4530 /* Disable access to flash interface */
4531 bnx2_disable_nvram_access(bp);
4532
4533 bnx2_release_nvram_lock(bp);
4534
4535 return rc;
4536}
4537
4538static int
4539bnx2_nvram_write(struct bnx2 *bp, u32 offset, u8 *data_buf,
4540 int buf_size)
4541{
4542 u32 written, offset32, len32;
Michael Chane6be7632007-01-08 19:56:13 -08004543 u8 *buf, start[4], end[4], *align_buf = NULL, *flash_buffer = NULL;
Michael Chanb6016b72005-05-26 13:03:09 -07004544 int rc = 0;
4545 int align_start, align_end;
4546
4547 buf = data_buf;
4548 offset32 = offset;
4549 len32 = buf_size;
4550 align_start = align_end = 0;
4551
4552 if ((align_start = (offset32 & 3))) {
4553 offset32 &= ~3;
Michael Chanc8738792007-03-30 14:53:06 -07004554 len32 += align_start;
4555 if (len32 < 4)
4556 len32 = 4;
Michael Chanb6016b72005-05-26 13:03:09 -07004557 if ((rc = bnx2_nvram_read(bp, offset32, start, 4)))
4558 return rc;
4559 }
4560
4561 if (len32 & 3) {
Michael Chanc8738792007-03-30 14:53:06 -07004562 align_end = 4 - (len32 & 3);
4563 len32 += align_end;
4564 if ((rc = bnx2_nvram_read(bp, offset32 + len32 - 4, end, 4)))
4565 return rc;
Michael Chanb6016b72005-05-26 13:03:09 -07004566 }
4567
4568 if (align_start || align_end) {
Michael Chane6be7632007-01-08 19:56:13 -08004569 align_buf = kmalloc(len32, GFP_KERNEL);
4570 if (align_buf == NULL)
Michael Chanb6016b72005-05-26 13:03:09 -07004571 return -ENOMEM;
4572 if (align_start) {
Michael Chane6be7632007-01-08 19:56:13 -08004573 memcpy(align_buf, start, 4);
Michael Chanb6016b72005-05-26 13:03:09 -07004574 }
4575 if (align_end) {
Michael Chane6be7632007-01-08 19:56:13 -08004576 memcpy(align_buf + len32 - 4, end, 4);
Michael Chanb6016b72005-05-26 13:03:09 -07004577 }
Michael Chane6be7632007-01-08 19:56:13 -08004578 memcpy(align_buf + align_start, data_buf, buf_size);
4579 buf = align_buf;
Michael Chanb6016b72005-05-26 13:03:09 -07004580 }
4581
Michael Chane30372c2007-07-16 18:26:23 -07004582 if (!(bp->flash_info->flags & BNX2_NV_BUFFERED)) {
Michael Chanae181bc2006-05-22 16:39:20 -07004583 flash_buffer = kmalloc(264, GFP_KERNEL);
4584 if (flash_buffer == NULL) {
4585 rc = -ENOMEM;
4586 goto nvram_write_end;
4587 }
4588 }
4589
Michael Chanb6016b72005-05-26 13:03:09 -07004590 written = 0;
4591 while ((written < len32) && (rc == 0)) {
4592 u32 page_start, page_end, data_start, data_end;
4593 u32 addr, cmd_flags;
4594 int i;
Michael Chanb6016b72005-05-26 13:03:09 -07004595
4596 /* Find the page_start addr */
4597 page_start = offset32 + written;
4598 page_start -= (page_start % bp->flash_info->page_size);
4599 /* Find the page_end addr */
4600 page_end = page_start + bp->flash_info->page_size;
4601 /* Find the data_start addr */
4602 data_start = (written == 0) ? offset32 : page_start;
4603 /* Find the data_end addr */
Jeff Garzik6aa20a22006-09-13 13:24:59 -04004604 data_end = (page_end > offset32 + len32) ?
Michael Chanb6016b72005-05-26 13:03:09 -07004605 (offset32 + len32) : page_end;
4606
4607 /* Request access to the flash interface. */
4608 if ((rc = bnx2_acquire_nvram_lock(bp)) != 0)
4609 goto nvram_write_end;
4610
4611 /* Enable access to flash interface */
4612 bnx2_enable_nvram_access(bp);
4613
4614 cmd_flags = BNX2_NVM_COMMAND_FIRST;
Michael Chane30372c2007-07-16 18:26:23 -07004615 if (!(bp->flash_info->flags & BNX2_NV_BUFFERED)) {
Michael Chanb6016b72005-05-26 13:03:09 -07004616 int j;
4617
4618 /* Read the whole page into the buffer
4619 * (non-buffer flash only) */
4620 for (j = 0; j < bp->flash_info->page_size; j += 4) {
4621 if (j == (bp->flash_info->page_size - 4)) {
4622 cmd_flags |= BNX2_NVM_COMMAND_LAST;
4623 }
4624 rc = bnx2_nvram_read_dword(bp,
Jeff Garzik6aa20a22006-09-13 13:24:59 -04004625 page_start + j,
4626 &flash_buffer[j],
Michael Chanb6016b72005-05-26 13:03:09 -07004627 cmd_flags);
4628
4629 if (rc)
4630 goto nvram_write_end;
4631
4632 cmd_flags = 0;
4633 }
4634 }
4635
4636 /* Enable writes to flash interface (unlock write-protect) */
4637 if ((rc = bnx2_enable_nvram_write(bp)) != 0)
4638 goto nvram_write_end;
4639
Michael Chanb6016b72005-05-26 13:03:09 -07004640 /* Loop to write back the buffer data from page_start to
4641 * data_start */
4642 i = 0;
Michael Chane30372c2007-07-16 18:26:23 -07004643 if (!(bp->flash_info->flags & BNX2_NV_BUFFERED)) {
Michael Chanc8738792007-03-30 14:53:06 -07004644 /* Erase the page */
4645 if ((rc = bnx2_nvram_erase_page(bp, page_start)) != 0)
4646 goto nvram_write_end;
4647
4648 /* Re-enable the write again for the actual write */
4649 bnx2_enable_nvram_write(bp);
4650
Michael Chanb6016b72005-05-26 13:03:09 -07004651 for (addr = page_start; addr < data_start;
4652 addr += 4, i += 4) {
Jeff Garzik6aa20a22006-09-13 13:24:59 -04004653
Michael Chanb6016b72005-05-26 13:03:09 -07004654 rc = bnx2_nvram_write_dword(bp, addr,
4655 &flash_buffer[i], cmd_flags);
4656
4657 if (rc != 0)
4658 goto nvram_write_end;
4659
4660 cmd_flags = 0;
4661 }
4662 }
4663
4664 /* Loop to write the new data from data_start to data_end */
Michael Chanbae25762006-05-22 16:38:38 -07004665 for (addr = data_start; addr < data_end; addr += 4, i += 4) {
Michael Chanb6016b72005-05-26 13:03:09 -07004666 if ((addr == page_end - 4) ||
Michael Chane30372c2007-07-16 18:26:23 -07004667 ((bp->flash_info->flags & BNX2_NV_BUFFERED) &&
Michael Chanb6016b72005-05-26 13:03:09 -07004668 (addr == data_end - 4))) {
4669
4670 cmd_flags |= BNX2_NVM_COMMAND_LAST;
4671 }
4672 rc = bnx2_nvram_write_dword(bp, addr, buf,
4673 cmd_flags);
4674
4675 if (rc != 0)
4676 goto nvram_write_end;
4677
4678 cmd_flags = 0;
4679 buf += 4;
4680 }
4681
4682 /* Loop to write back the buffer data from data_end
4683 * to page_end */
Michael Chane30372c2007-07-16 18:26:23 -07004684 if (!(bp->flash_info->flags & BNX2_NV_BUFFERED)) {
Michael Chanb6016b72005-05-26 13:03:09 -07004685 for (addr = data_end; addr < page_end;
4686 addr += 4, i += 4) {
Jeff Garzik6aa20a22006-09-13 13:24:59 -04004687
Michael Chanb6016b72005-05-26 13:03:09 -07004688 if (addr == page_end-4) {
4689 cmd_flags = BNX2_NVM_COMMAND_LAST;
4690 }
4691 rc = bnx2_nvram_write_dword(bp, addr,
4692 &flash_buffer[i], cmd_flags);
4693
4694 if (rc != 0)
4695 goto nvram_write_end;
4696
4697 cmd_flags = 0;
4698 }
4699 }
4700
4701 /* Disable writes to flash interface (lock write-protect) */
4702 bnx2_disable_nvram_write(bp);
4703
4704 /* Disable access to flash interface */
4705 bnx2_disable_nvram_access(bp);
4706 bnx2_release_nvram_lock(bp);
4707
4708 /* Increment written */
4709 written += data_end - data_start;
4710 }
4711
4712nvram_write_end:
Michael Chane6be7632007-01-08 19:56:13 -08004713 kfree(flash_buffer);
4714 kfree(align_buf);
Michael Chanb6016b72005-05-26 13:03:09 -07004715 return rc;
4716}
4717
Michael Chan0d8a6572007-07-07 22:49:43 -07004718static void
Michael Chan7c62e832008-07-14 22:39:03 -07004719bnx2_init_fw_cap(struct bnx2 *bp)
Michael Chan0d8a6572007-07-07 22:49:43 -07004720{
Michael Chan7c62e832008-07-14 22:39:03 -07004721 u32 val, sig = 0;
Michael Chan0d8a6572007-07-07 22:49:43 -07004722
Michael Chan583c28e2008-01-21 19:51:35 -08004723 bp->phy_flags &= ~BNX2_PHY_FLAG_REMOTE_PHY_CAP;
Michael Chan7c62e832008-07-14 22:39:03 -07004724 bp->flags &= ~BNX2_FLAG_CAN_KEEP_VLAN;
4725
4726 if (!(bp->flags & BNX2_FLAG_ASF_ENABLE))
4727 bp->flags |= BNX2_FLAG_CAN_KEEP_VLAN;
Michael Chan0d8a6572007-07-07 22:49:43 -07004728
Michael Chan2726d6e2008-01-29 21:35:05 -08004729 val = bnx2_shmem_rd(bp, BNX2_FW_CAP_MB);
Michael Chan0d8a6572007-07-07 22:49:43 -07004730 if ((val & BNX2_FW_CAP_SIGNATURE_MASK) != BNX2_FW_CAP_SIGNATURE)
4731 return;
4732
Michael Chan7c62e832008-07-14 22:39:03 -07004733 if ((val & BNX2_FW_CAP_CAN_KEEP_VLAN) == BNX2_FW_CAP_CAN_KEEP_VLAN) {
4734 bp->flags |= BNX2_FLAG_CAN_KEEP_VLAN;
4735 sig |= BNX2_DRV_ACK_CAP_SIGNATURE | BNX2_FW_CAP_CAN_KEEP_VLAN;
4736 }
4737
4738 if ((bp->phy_flags & BNX2_PHY_FLAG_SERDES) &&
4739 (val & BNX2_FW_CAP_REMOTE_PHY_CAPABLE)) {
4740 u32 link;
4741
Michael Chan583c28e2008-01-21 19:51:35 -08004742 bp->phy_flags |= BNX2_PHY_FLAG_REMOTE_PHY_CAP;
Michael Chan0d8a6572007-07-07 22:49:43 -07004743
Michael Chan7c62e832008-07-14 22:39:03 -07004744 link = bnx2_shmem_rd(bp, BNX2_LINK_STATUS);
4745 if (link & BNX2_LINK_STATUS_SERDES_LINK)
Michael Chan0d8a6572007-07-07 22:49:43 -07004746 bp->phy_port = PORT_FIBRE;
4747 else
4748 bp->phy_port = PORT_TP;
Michael Chan489310a2007-10-10 16:16:31 -07004749
Michael Chan7c62e832008-07-14 22:39:03 -07004750 sig |= BNX2_DRV_ACK_CAP_SIGNATURE |
4751 BNX2_FW_CAP_REMOTE_PHY_CAPABLE;
Michael Chan0d8a6572007-07-07 22:49:43 -07004752 }
Michael Chan7c62e832008-07-14 22:39:03 -07004753
4754 if (netif_running(bp->dev) && sig)
4755 bnx2_shmem_wr(bp, BNX2_DRV_ACK_CAP_MB, sig);
Michael Chan0d8a6572007-07-07 22:49:43 -07004756}
4757
Michael Chanb4b36042007-12-20 19:59:30 -08004758static void
4759bnx2_setup_msix_tbl(struct bnx2 *bp)
4760{
Michael Chane503e062012-12-06 10:33:08 +00004761 BNX2_WR(bp, BNX2_PCI_GRC_WINDOW_ADDR, BNX2_PCI_GRC_WINDOW_ADDR_SEP_WIN);
Michael Chanb4b36042007-12-20 19:59:30 -08004762
Michael Chane503e062012-12-06 10:33:08 +00004763 BNX2_WR(bp, BNX2_PCI_GRC_WINDOW2_ADDR, BNX2_MSIX_TABLE_ADDR);
4764 BNX2_WR(bp, BNX2_PCI_GRC_WINDOW3_ADDR, BNX2_MSIX_PBA_ADDR);
Michael Chanb4b36042007-12-20 19:59:30 -08004765}
4766
Michael Chanb6016b72005-05-26 13:03:09 -07004767static int
4768bnx2_reset_chip(struct bnx2 *bp, u32 reset_code)
4769{
4770 u32 val;
4771 int i, rc = 0;
Michael Chan489310a2007-10-10 16:16:31 -07004772 u8 old_port;
Michael Chanb6016b72005-05-26 13:03:09 -07004773
4774 /* Wait for the current PCI transaction to complete before
4775 * issuing a reset. */
Michael Chan4ce45e02012-12-06 10:33:10 +00004776 if ((BNX2_CHIP(bp) == BNX2_CHIP_5706) ||
4777 (BNX2_CHIP(bp) == BNX2_CHIP_5708)) {
Michael Chane503e062012-12-06 10:33:08 +00004778 BNX2_WR(bp, BNX2_MISC_ENABLE_CLR_BITS,
4779 BNX2_MISC_ENABLE_CLR_BITS_TX_DMA_ENABLE |
4780 BNX2_MISC_ENABLE_CLR_BITS_DMA_ENGINE_ENABLE |
4781 BNX2_MISC_ENABLE_CLR_BITS_RX_DMA_ENABLE |
4782 BNX2_MISC_ENABLE_CLR_BITS_HOST_COALESCE_ENABLE);
4783 val = BNX2_RD(bp, BNX2_MISC_ENABLE_CLR_BITS);
Eddie Waia5dac102010-11-24 13:48:54 +00004784 udelay(5);
4785 } else { /* 5709 */
Michael Chane503e062012-12-06 10:33:08 +00004786 val = BNX2_RD(bp, BNX2_MISC_NEW_CORE_CTL);
Eddie Waia5dac102010-11-24 13:48:54 +00004787 val &= ~BNX2_MISC_NEW_CORE_CTL_DMA_ENABLE;
Michael Chane503e062012-12-06 10:33:08 +00004788 BNX2_WR(bp, BNX2_MISC_NEW_CORE_CTL, val);
4789 val = BNX2_RD(bp, BNX2_MISC_NEW_CORE_CTL);
Eddie Waia5dac102010-11-24 13:48:54 +00004790
4791 for (i = 0; i < 100; i++) {
4792 msleep(1);
Michael Chane503e062012-12-06 10:33:08 +00004793 val = BNX2_RD(bp, BNX2_PCICFG_DEVICE_CONTROL);
Eddie Waia5dac102010-11-24 13:48:54 +00004794 if (!(val & BNX2_PCICFG_DEVICE_STATUS_NO_PEND))
4795 break;
4796 }
4797 }
Michael Chanb6016b72005-05-26 13:03:09 -07004798
Michael Chanb090ae22006-01-23 16:07:10 -08004799 /* Wait for the firmware to tell us it is ok to issue a reset. */
Michael Chana2f13892008-07-14 22:38:23 -07004800 bnx2_fw_sync(bp, BNX2_DRV_MSG_DATA_WAIT0 | reset_code, 1, 1);
Michael Chanb090ae22006-01-23 16:07:10 -08004801
Michael Chanb6016b72005-05-26 13:03:09 -07004802 /* Deposit a driver reset signature so the firmware knows that
4803 * this is a soft reset. */
Michael Chan2726d6e2008-01-29 21:35:05 -08004804 bnx2_shmem_wr(bp, BNX2_DRV_RESET_SIGNATURE,
4805 BNX2_DRV_RESET_SIGNATURE_MAGIC);
Michael Chanb6016b72005-05-26 13:03:09 -07004806
Michael Chanb6016b72005-05-26 13:03:09 -07004807 /* Do a dummy read to force the chip to complete all current transaction
4808 * before we issue a reset. */
Michael Chane503e062012-12-06 10:33:08 +00004809 val = BNX2_RD(bp, BNX2_MISC_ID);
Michael Chanb6016b72005-05-26 13:03:09 -07004810
Michael Chan4ce45e02012-12-06 10:33:10 +00004811 if (BNX2_CHIP(bp) == BNX2_CHIP_5709) {
Michael Chane503e062012-12-06 10:33:08 +00004812 BNX2_WR(bp, BNX2_MISC_COMMAND, BNX2_MISC_COMMAND_SW_RESET);
4813 BNX2_RD(bp, BNX2_MISC_COMMAND);
Michael Chan234754d2006-11-19 14:11:41 -08004814 udelay(5);
Michael Chanb6016b72005-05-26 13:03:09 -07004815
Michael Chan234754d2006-11-19 14:11:41 -08004816 val = BNX2_PCICFG_MISC_CONFIG_REG_WINDOW_ENA |
4817 BNX2_PCICFG_MISC_CONFIG_TARGET_MB_WORD_SWAP;
Michael Chanb6016b72005-05-26 13:03:09 -07004818
Michael Chane503e062012-12-06 10:33:08 +00004819 BNX2_WR(bp, BNX2_PCICFG_MISC_CONFIG, val);
Michael Chanb6016b72005-05-26 13:03:09 -07004820
Michael Chan234754d2006-11-19 14:11:41 -08004821 } else {
4822 val = BNX2_PCICFG_MISC_CONFIG_CORE_RST_REQ |
4823 BNX2_PCICFG_MISC_CONFIG_REG_WINDOW_ENA |
4824 BNX2_PCICFG_MISC_CONFIG_TARGET_MB_WORD_SWAP;
4825
4826 /* Chip reset. */
Michael Chane503e062012-12-06 10:33:08 +00004827 BNX2_WR(bp, BNX2_PCICFG_MISC_CONFIG, val);
Michael Chan234754d2006-11-19 14:11:41 -08004828
Michael Chan594a9df2007-08-28 15:39:42 -07004829 /* Reading back any register after chip reset will hang the
4830 * bus on 5706 A0 and A1. The msleep below provides plenty
4831 * of margin for write posting.
4832 */
Michael Chan4ce45e02012-12-06 10:33:10 +00004833 if ((BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5706_A0) ||
4834 (BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5706_A1))
Arjan van de Ven8e545882007-08-28 14:34:43 -07004835 msleep(20);
Michael Chanb6016b72005-05-26 13:03:09 -07004836
Michael Chan234754d2006-11-19 14:11:41 -08004837 /* Reset takes approximate 30 usec */
4838 for (i = 0; i < 10; i++) {
Michael Chane503e062012-12-06 10:33:08 +00004839 val = BNX2_RD(bp, BNX2_PCICFG_MISC_CONFIG);
Michael Chan234754d2006-11-19 14:11:41 -08004840 if ((val & (BNX2_PCICFG_MISC_CONFIG_CORE_RST_REQ |
4841 BNX2_PCICFG_MISC_CONFIG_CORE_RST_BSY)) == 0)
4842 break;
4843 udelay(10);
4844 }
4845
4846 if (val & (BNX2_PCICFG_MISC_CONFIG_CORE_RST_REQ |
4847 BNX2_PCICFG_MISC_CONFIG_CORE_RST_BSY)) {
Joe Perches3a9c6a42010-02-17 15:01:51 +00004848 pr_err("Chip reset did not complete\n");
Michael Chan234754d2006-11-19 14:11:41 -08004849 return -EBUSY;
4850 }
Michael Chanb6016b72005-05-26 13:03:09 -07004851 }
4852
4853 /* Make sure byte swapping is properly configured. */
Michael Chane503e062012-12-06 10:33:08 +00004854 val = BNX2_RD(bp, BNX2_PCI_SWAP_DIAG0);
Michael Chanb6016b72005-05-26 13:03:09 -07004855 if (val != 0x01020304) {
Joe Perches3a9c6a42010-02-17 15:01:51 +00004856 pr_err("Chip not in correct endian mode\n");
Michael Chanb6016b72005-05-26 13:03:09 -07004857 return -ENODEV;
4858 }
4859
Michael Chanb6016b72005-05-26 13:03:09 -07004860 /* Wait for the firmware to finish its initialization. */
Michael Chana2f13892008-07-14 22:38:23 -07004861 rc = bnx2_fw_sync(bp, BNX2_DRV_MSG_DATA_WAIT1 | reset_code, 1, 0);
Michael Chanb090ae22006-01-23 16:07:10 -08004862 if (rc)
4863 return rc;
Michael Chanb6016b72005-05-26 13:03:09 -07004864
Michael Chan0d8a6572007-07-07 22:49:43 -07004865 spin_lock_bh(&bp->phy_lock);
Michael Chan489310a2007-10-10 16:16:31 -07004866 old_port = bp->phy_port;
Michael Chan7c62e832008-07-14 22:39:03 -07004867 bnx2_init_fw_cap(bp);
Michael Chan583c28e2008-01-21 19:51:35 -08004868 if ((bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP) &&
4869 old_port != bp->phy_port)
Michael Chan0d8a6572007-07-07 22:49:43 -07004870 bnx2_set_default_remote_link(bp);
4871 spin_unlock_bh(&bp->phy_lock);
4872
Michael Chan4ce45e02012-12-06 10:33:10 +00004873 if (BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5706_A0) {
Michael Chanb6016b72005-05-26 13:03:09 -07004874 /* Adjust the voltage regular to two steps lower. The default
4875 * of this register is 0x0000000e. */
Michael Chane503e062012-12-06 10:33:08 +00004876 BNX2_WR(bp, BNX2_MISC_VREG_CONTROL, 0x000000fa);
Michael Chanb6016b72005-05-26 13:03:09 -07004877
4878 /* Remove bad rbuf memory from the free pool. */
4879 rc = bnx2_alloc_bad_rbuf(bp);
4880 }
4881
Michael Chanc441b8d2010-04-27 11:28:09 +00004882 if (bp->flags & BNX2_FLAG_USING_MSIX) {
Michael Chanb4b36042007-12-20 19:59:30 -08004883 bnx2_setup_msix_tbl(bp);
Michael Chanc441b8d2010-04-27 11:28:09 +00004884 /* Prevent MSIX table reads and write from timing out */
Michael Chane503e062012-12-06 10:33:08 +00004885 BNX2_WR(bp, BNX2_MISC_ECO_HW_CTL,
Michael Chanc441b8d2010-04-27 11:28:09 +00004886 BNX2_MISC_ECO_HW_CTL_LARGE_GRC_TMOUT_EN);
4887 }
Michael Chanb4b36042007-12-20 19:59:30 -08004888
Michael Chanb6016b72005-05-26 13:03:09 -07004889 return rc;
4890}
4891
4892static int
4893bnx2_init_chip(struct bnx2 *bp)
4894{
Michael Chand8026d92008-11-12 16:02:20 -08004895 u32 val, mtu;
Michael Chanb4b36042007-12-20 19:59:30 -08004896 int rc, i;
Michael Chanb6016b72005-05-26 13:03:09 -07004897
4898 /* Make sure the interrupt is not active. */
Michael Chane503e062012-12-06 10:33:08 +00004899 BNX2_WR(bp, BNX2_PCICFG_INT_ACK_CMD, BNX2_PCICFG_INT_ACK_CMD_MASK_INT);
Michael Chanb6016b72005-05-26 13:03:09 -07004900
4901 val = BNX2_DMA_CONFIG_DATA_BYTE_SWAP |
4902 BNX2_DMA_CONFIG_DATA_WORD_SWAP |
4903#ifdef __BIG_ENDIAN
Jeff Garzik6aa20a22006-09-13 13:24:59 -04004904 BNX2_DMA_CONFIG_CNTL_BYTE_SWAP |
Michael Chanb6016b72005-05-26 13:03:09 -07004905#endif
Jeff Garzik6aa20a22006-09-13 13:24:59 -04004906 BNX2_DMA_CONFIG_CNTL_WORD_SWAP |
Michael Chanb6016b72005-05-26 13:03:09 -07004907 DMA_READ_CHANS << 12 |
4908 DMA_WRITE_CHANS << 16;
4909
4910 val |= (0x2 << 20) | (1 << 11);
4911
David S. Millerf86e82f2008-01-21 17:15:40 -08004912 if ((bp->flags & BNX2_FLAG_PCIX) && (bp->bus_speed_mhz == 133))
Michael Chanb6016b72005-05-26 13:03:09 -07004913 val |= (1 << 23);
4914
Michael Chan4ce45e02012-12-06 10:33:10 +00004915 if ((BNX2_CHIP(bp) == BNX2_CHIP_5706) &&
4916 (BNX2_CHIP_ID(bp) != BNX2_CHIP_ID_5706_A0) &&
4917 !(bp->flags & BNX2_FLAG_PCIX))
Michael Chanb6016b72005-05-26 13:03:09 -07004918 val |= BNX2_DMA_CONFIG_CNTL_PING_PONG_DMA;
4919
Michael Chane503e062012-12-06 10:33:08 +00004920 BNX2_WR(bp, BNX2_DMA_CONFIG, val);
Michael Chanb6016b72005-05-26 13:03:09 -07004921
Michael Chan4ce45e02012-12-06 10:33:10 +00004922 if (BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5706_A0) {
Michael Chane503e062012-12-06 10:33:08 +00004923 val = BNX2_RD(bp, BNX2_TDMA_CONFIG);
Michael Chanb6016b72005-05-26 13:03:09 -07004924 val |= BNX2_TDMA_CONFIG_ONE_DMA;
Michael Chane503e062012-12-06 10:33:08 +00004925 BNX2_WR(bp, BNX2_TDMA_CONFIG, val);
Michael Chanb6016b72005-05-26 13:03:09 -07004926 }
4927
David S. Millerf86e82f2008-01-21 17:15:40 -08004928 if (bp->flags & BNX2_FLAG_PCIX) {
Michael Chanb6016b72005-05-26 13:03:09 -07004929 u16 val16;
4930
4931 pci_read_config_word(bp->pdev, bp->pcix_cap + PCI_X_CMD,
4932 &val16);
4933 pci_write_config_word(bp->pdev, bp->pcix_cap + PCI_X_CMD,
4934 val16 & ~PCI_X_CMD_ERO);
4935 }
4936
Michael Chane503e062012-12-06 10:33:08 +00004937 BNX2_WR(bp, BNX2_MISC_ENABLE_SET_BITS,
4938 BNX2_MISC_ENABLE_SET_BITS_HOST_COALESCE_ENABLE |
4939 BNX2_MISC_ENABLE_STATUS_BITS_RX_V2P_ENABLE |
4940 BNX2_MISC_ENABLE_STATUS_BITS_CONTEXT_ENABLE);
Michael Chanb6016b72005-05-26 13:03:09 -07004941
4942 /* Initialize context mapping and zero out the quick contexts. The
4943 * context block must have already been enabled. */
Michael Chan4ce45e02012-12-06 10:33:10 +00004944 if (BNX2_CHIP(bp) == BNX2_CHIP_5709) {
Michael Chan641bdcd2007-06-04 21:22:24 -07004945 rc = bnx2_init_5709_context(bp);
4946 if (rc)
4947 return rc;
4948 } else
Michael Chan59b47d82006-11-19 14:10:45 -08004949 bnx2_init_context(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07004950
Michael Chanfba9fe92006-06-12 22:21:25 -07004951 if ((rc = bnx2_init_cpus(bp)) != 0)
4952 return rc;
4953
Michael Chanb6016b72005-05-26 13:03:09 -07004954 bnx2_init_nvram(bp);
4955
Benjamin Li5fcaed02008-07-14 22:39:52 -07004956 bnx2_set_mac_addr(bp, bp->dev->dev_addr, 0);
Michael Chanb6016b72005-05-26 13:03:09 -07004957
Michael Chane503e062012-12-06 10:33:08 +00004958 val = BNX2_RD(bp, BNX2_MQ_CONFIG);
Michael Chanb6016b72005-05-26 13:03:09 -07004959 val &= ~BNX2_MQ_CONFIG_KNL_BYP_BLK_SIZE;
4960 val |= BNX2_MQ_CONFIG_KNL_BYP_BLK_SIZE_256;
Michael Chan4ce45e02012-12-06 10:33:10 +00004961 if (BNX2_CHIP(bp) == BNX2_CHIP_5709) {
Michael Chan4edd4732009-06-08 18:14:42 -07004962 val |= BNX2_MQ_CONFIG_BIN_MQ_MODE;
Michael Chan4ce45e02012-12-06 10:33:10 +00004963 if (BNX2_CHIP_REV(bp) == BNX2_CHIP_REV_Ax)
Michael Chan4edd4732009-06-08 18:14:42 -07004964 val |= BNX2_MQ_CONFIG_HALT_DIS;
4965 }
Michael Chan68c9f752007-04-24 15:35:53 -07004966
Michael Chane503e062012-12-06 10:33:08 +00004967 BNX2_WR(bp, BNX2_MQ_CONFIG, val);
Michael Chanb6016b72005-05-26 13:03:09 -07004968
4969 val = 0x10000 + (MAX_CID_CNT * MB_KERNEL_CTX_SIZE);
Michael Chane503e062012-12-06 10:33:08 +00004970 BNX2_WR(bp, BNX2_MQ_KNL_BYP_WIND_START, val);
4971 BNX2_WR(bp, BNX2_MQ_KNL_WIND_END, val);
Michael Chanb6016b72005-05-26 13:03:09 -07004972
Michael Chan2bc40782012-12-06 10:33:09 +00004973 val = (BNX2_PAGE_BITS - 8) << 24;
Michael Chane503e062012-12-06 10:33:08 +00004974 BNX2_WR(bp, BNX2_RV2P_CONFIG, val);
Michael Chanb6016b72005-05-26 13:03:09 -07004975
4976 /* Configure page size. */
Michael Chane503e062012-12-06 10:33:08 +00004977 val = BNX2_RD(bp, BNX2_TBDR_CONFIG);
Michael Chanb6016b72005-05-26 13:03:09 -07004978 val &= ~BNX2_TBDR_CONFIG_PAGE_SIZE;
Michael Chan2bc40782012-12-06 10:33:09 +00004979 val |= (BNX2_PAGE_BITS - 8) << 24 | 0x40;
Michael Chane503e062012-12-06 10:33:08 +00004980 BNX2_WR(bp, BNX2_TBDR_CONFIG, val);
Michael Chanb6016b72005-05-26 13:03:09 -07004981
4982 val = bp->mac_addr[0] +
4983 (bp->mac_addr[1] << 8) +
4984 (bp->mac_addr[2] << 16) +
4985 bp->mac_addr[3] +
4986 (bp->mac_addr[4] << 8) +
4987 (bp->mac_addr[5] << 16);
Michael Chane503e062012-12-06 10:33:08 +00004988 BNX2_WR(bp, BNX2_EMAC_BACKOFF_SEED, val);
Michael Chanb6016b72005-05-26 13:03:09 -07004989
4990 /* Program the MTU. Also include 4 bytes for CRC32. */
Michael Chand8026d92008-11-12 16:02:20 -08004991 mtu = bp->dev->mtu;
4992 val = mtu + ETH_HLEN + ETH_FCS_LEN;
Michael Chanb6016b72005-05-26 13:03:09 -07004993 if (val > (MAX_ETHERNET_PACKET_SIZE + 4))
4994 val |= BNX2_EMAC_RX_MTU_SIZE_JUMBO_ENA;
Michael Chane503e062012-12-06 10:33:08 +00004995 BNX2_WR(bp, BNX2_EMAC_RX_MTU_SIZE, val);
Michael Chanb6016b72005-05-26 13:03:09 -07004996
Michael Chand8026d92008-11-12 16:02:20 -08004997 if (mtu < 1500)
4998 mtu = 1500;
4999
5000 bnx2_reg_wr_ind(bp, BNX2_RBUF_CONFIG, BNX2_RBUF_CONFIG_VAL(mtu));
5001 bnx2_reg_wr_ind(bp, BNX2_RBUF_CONFIG2, BNX2_RBUF_CONFIG2_VAL(mtu));
5002 bnx2_reg_wr_ind(bp, BNX2_RBUF_CONFIG3, BNX2_RBUF_CONFIG3_VAL(mtu));
5003
Michael Chan155d5562009-08-21 16:20:43 +00005004 memset(bp->bnx2_napi[0].status_blk.msi, 0, bp->status_stats_size);
Michael Chanb4b36042007-12-20 19:59:30 -08005005 for (i = 0; i < BNX2_MAX_MSIX_VEC; i++)
5006 bp->bnx2_napi[i].last_status_idx = 0;
5007
Michael Chanefba0182008-12-03 00:36:15 -08005008 bp->idle_chk_status_idx = 0xffff;
5009
Michael Chanb6016b72005-05-26 13:03:09 -07005010 /* Set up how to generate a link change interrupt. */
Michael Chane503e062012-12-06 10:33:08 +00005011 BNX2_WR(bp, BNX2_EMAC_ATTENTION_ENA, BNX2_EMAC_ATTENTION_ENA_LINK);
Michael Chanb6016b72005-05-26 13:03:09 -07005012
Michael Chane503e062012-12-06 10:33:08 +00005013 BNX2_WR(bp, BNX2_HC_STATUS_ADDR_L,
5014 (u64) bp->status_blk_mapping & 0xffffffff);
5015 BNX2_WR(bp, BNX2_HC_STATUS_ADDR_H, (u64) bp->status_blk_mapping >> 32);
Michael Chanb6016b72005-05-26 13:03:09 -07005016
Michael Chane503e062012-12-06 10:33:08 +00005017 BNX2_WR(bp, BNX2_HC_STATISTICS_ADDR_L,
5018 (u64) bp->stats_blk_mapping & 0xffffffff);
5019 BNX2_WR(bp, BNX2_HC_STATISTICS_ADDR_H,
5020 (u64) bp->stats_blk_mapping >> 32);
Michael Chanb6016b72005-05-26 13:03:09 -07005021
Michael Chane503e062012-12-06 10:33:08 +00005022 BNX2_WR(bp, BNX2_HC_TX_QUICK_CONS_TRIP,
5023 (bp->tx_quick_cons_trip_int << 16) | bp->tx_quick_cons_trip);
Michael Chanb6016b72005-05-26 13:03:09 -07005024
Michael Chane503e062012-12-06 10:33:08 +00005025 BNX2_WR(bp, BNX2_HC_RX_QUICK_CONS_TRIP,
5026 (bp->rx_quick_cons_trip_int << 16) | bp->rx_quick_cons_trip);
Michael Chanb6016b72005-05-26 13:03:09 -07005027
Michael Chane503e062012-12-06 10:33:08 +00005028 BNX2_WR(bp, BNX2_HC_COMP_PROD_TRIP,
5029 (bp->comp_prod_trip_int << 16) | bp->comp_prod_trip);
Michael Chanb6016b72005-05-26 13:03:09 -07005030
Michael Chane503e062012-12-06 10:33:08 +00005031 BNX2_WR(bp, BNX2_HC_TX_TICKS, (bp->tx_ticks_int << 16) | bp->tx_ticks);
Michael Chanb6016b72005-05-26 13:03:09 -07005032
Michael Chane503e062012-12-06 10:33:08 +00005033 BNX2_WR(bp, BNX2_HC_RX_TICKS, (bp->rx_ticks_int << 16) | bp->rx_ticks);
Michael Chanb6016b72005-05-26 13:03:09 -07005034
Michael Chane503e062012-12-06 10:33:08 +00005035 BNX2_WR(bp, BNX2_HC_COM_TICKS,
5036 (bp->com_ticks_int << 16) | bp->com_ticks);
Michael Chanb6016b72005-05-26 13:03:09 -07005037
Michael Chane503e062012-12-06 10:33:08 +00005038 BNX2_WR(bp, BNX2_HC_CMD_TICKS,
5039 (bp->cmd_ticks_int << 16) | bp->cmd_ticks);
Michael Chanb6016b72005-05-26 13:03:09 -07005040
Michael Chan61d9e3f2009-08-21 16:20:46 +00005041 if (bp->flags & BNX2_FLAG_BROKEN_STATS)
Michael Chane503e062012-12-06 10:33:08 +00005042 BNX2_WR(bp, BNX2_HC_STATS_TICKS, 0);
Michael Chan02537b062007-06-04 21:24:07 -07005043 else
Michael Chane503e062012-12-06 10:33:08 +00005044 BNX2_WR(bp, BNX2_HC_STATS_TICKS, bp->stats_ticks);
5045 BNX2_WR(bp, BNX2_HC_STAT_COLLECT_TICKS, 0xbb8); /* 3ms */
Michael Chanb6016b72005-05-26 13:03:09 -07005046
Michael Chan4ce45e02012-12-06 10:33:10 +00005047 if (BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5706_A1)
Michael Chan8e6a72c2007-05-03 13:24:48 -07005048 val = BNX2_HC_CONFIG_COLLECT_STATS;
Michael Chanb6016b72005-05-26 13:03:09 -07005049 else {
Michael Chan8e6a72c2007-05-03 13:24:48 -07005050 val = BNX2_HC_CONFIG_RX_TMR_MODE | BNX2_HC_CONFIG_TX_TMR_MODE |
5051 BNX2_HC_CONFIG_COLLECT_STATS;
Michael Chanb6016b72005-05-26 13:03:09 -07005052 }
5053
Michael Chanefde73a2010-02-15 19:42:07 +00005054 if (bp->flags & BNX2_FLAG_USING_MSIX) {
Michael Chane503e062012-12-06 10:33:08 +00005055 BNX2_WR(bp, BNX2_HC_MSIX_BIT_VECTOR,
5056 BNX2_HC_MSIX_BIT_VECTOR_VAL);
Michael Chanc76c0472007-12-20 20:01:19 -08005057
Michael Chan5e9ad9e2008-06-19 16:43:17 -07005058 val |= BNX2_HC_CONFIG_SB_ADDR_INC_128B;
5059 }
5060
5061 if (bp->flags & BNX2_FLAG_ONE_SHOT_MSI)
Michael Chancf7474a2009-08-21 16:20:48 +00005062 val |= BNX2_HC_CONFIG_ONE_SHOT | BNX2_HC_CONFIG_USE_INT_PARAM;
Michael Chan5e9ad9e2008-06-19 16:43:17 -07005063
Michael Chane503e062012-12-06 10:33:08 +00005064 BNX2_WR(bp, BNX2_HC_CONFIG, val);
Michael Chan5e9ad9e2008-06-19 16:43:17 -07005065
Michael Chan22fa1592010-10-11 16:12:00 -07005066 if (bp->rx_ticks < 25)
5067 bnx2_reg_wr_ind(bp, BNX2_FW_RX_LOW_LATENCY, 1);
5068 else
5069 bnx2_reg_wr_ind(bp, BNX2_FW_RX_LOW_LATENCY, 0);
5070
Michael Chan5e9ad9e2008-06-19 16:43:17 -07005071 for (i = 1; i < bp->irq_nvecs; i++) {
5072 u32 base = ((i - 1) * BNX2_HC_SB_CONFIG_SIZE) +
5073 BNX2_HC_SB_CONFIG_1;
5074
Michael Chane503e062012-12-06 10:33:08 +00005075 BNX2_WR(bp, base,
Michael Chanc76c0472007-12-20 20:01:19 -08005076 BNX2_HC_SB_CONFIG_1_TX_TMR_MODE |
Michael Chan5e9ad9e2008-06-19 16:43:17 -07005077 BNX2_HC_SB_CONFIG_1_RX_TMR_MODE |
Michael Chanc76c0472007-12-20 20:01:19 -08005078 BNX2_HC_SB_CONFIG_1_ONE_SHOT);
5079
Michael Chane503e062012-12-06 10:33:08 +00005080 BNX2_WR(bp, base + BNX2_HC_TX_QUICK_CONS_TRIP_OFF,
Michael Chanc76c0472007-12-20 20:01:19 -08005081 (bp->tx_quick_cons_trip_int << 16) |
5082 bp->tx_quick_cons_trip);
5083
Michael Chane503e062012-12-06 10:33:08 +00005084 BNX2_WR(bp, base + BNX2_HC_TX_TICKS_OFF,
Michael Chanc76c0472007-12-20 20:01:19 -08005085 (bp->tx_ticks_int << 16) | bp->tx_ticks);
5086
Michael Chane503e062012-12-06 10:33:08 +00005087 BNX2_WR(bp, base + BNX2_HC_RX_QUICK_CONS_TRIP_OFF,
5088 (bp->rx_quick_cons_trip_int << 16) |
Michael Chan5e9ad9e2008-06-19 16:43:17 -07005089 bp->rx_quick_cons_trip);
5090
Michael Chane503e062012-12-06 10:33:08 +00005091 BNX2_WR(bp, base + BNX2_HC_RX_TICKS_OFF,
Michael Chan5e9ad9e2008-06-19 16:43:17 -07005092 (bp->rx_ticks_int << 16) | bp->rx_ticks);
Michael Chanc76c0472007-12-20 20:01:19 -08005093 }
5094
Michael Chanb6016b72005-05-26 13:03:09 -07005095 /* Clear internal stats counters. */
Michael Chane503e062012-12-06 10:33:08 +00005096 BNX2_WR(bp, BNX2_HC_COMMAND, BNX2_HC_COMMAND_CLR_STAT_NOW);
Michael Chanb6016b72005-05-26 13:03:09 -07005097
Michael Chane503e062012-12-06 10:33:08 +00005098 BNX2_WR(bp, BNX2_HC_ATTN_BITS_ENABLE, STATUS_ATTN_EVENTS);
Michael Chanb6016b72005-05-26 13:03:09 -07005099
5100 /* Initialize the receive filter. */
5101 bnx2_set_rx_mode(bp->dev);
5102
Michael Chan4ce45e02012-12-06 10:33:10 +00005103 if (BNX2_CHIP(bp) == BNX2_CHIP_5709) {
Michael Chane503e062012-12-06 10:33:08 +00005104 val = BNX2_RD(bp, BNX2_MISC_NEW_CORE_CTL);
Michael Chan0aa38df2007-06-04 21:23:06 -07005105 val |= BNX2_MISC_NEW_CORE_CTL_DMA_ENABLE;
Michael Chane503e062012-12-06 10:33:08 +00005106 BNX2_WR(bp, BNX2_MISC_NEW_CORE_CTL, val);
Michael Chan0aa38df2007-06-04 21:23:06 -07005107 }
Michael Chanb090ae22006-01-23 16:07:10 -08005108 rc = bnx2_fw_sync(bp, BNX2_DRV_MSG_DATA_WAIT2 | BNX2_DRV_MSG_CODE_RESET,
Michael Chana2f13892008-07-14 22:38:23 -07005109 1, 0);
Michael Chanb6016b72005-05-26 13:03:09 -07005110
Michael Chane503e062012-12-06 10:33:08 +00005111 BNX2_WR(bp, BNX2_MISC_ENABLE_SET_BITS, BNX2_MISC_ENABLE_DEFAULT);
5112 BNX2_RD(bp, BNX2_MISC_ENABLE_SET_BITS);
Michael Chanb6016b72005-05-26 13:03:09 -07005113
5114 udelay(20);
5115
Michael Chane503e062012-12-06 10:33:08 +00005116 bp->hc_cmd = BNX2_RD(bp, BNX2_HC_COMMAND);
Michael Chanbf5295b2006-03-23 01:11:56 -08005117
Michael Chanb090ae22006-01-23 16:07:10 -08005118 return rc;
Michael Chanb6016b72005-05-26 13:03:09 -07005119}
5120
Michael Chan59b47d82006-11-19 14:10:45 -08005121static void
Michael Chanc76c0472007-12-20 20:01:19 -08005122bnx2_clear_ring_states(struct bnx2 *bp)
5123{
5124 struct bnx2_napi *bnapi;
Michael Chan35e90102008-06-19 16:37:42 -07005125 struct bnx2_tx_ring_info *txr;
Michael Chanbb4f98a2008-06-19 16:38:19 -07005126 struct bnx2_rx_ring_info *rxr;
Michael Chanc76c0472007-12-20 20:01:19 -08005127 int i;
5128
5129 for (i = 0; i < BNX2_MAX_MSIX_VEC; i++) {
5130 bnapi = &bp->bnx2_napi[i];
Michael Chan35e90102008-06-19 16:37:42 -07005131 txr = &bnapi->tx_ring;
Michael Chanbb4f98a2008-06-19 16:38:19 -07005132 rxr = &bnapi->rx_ring;
Michael Chanc76c0472007-12-20 20:01:19 -08005133
Michael Chan35e90102008-06-19 16:37:42 -07005134 txr->tx_cons = 0;
5135 txr->hw_tx_cons = 0;
Michael Chanbb4f98a2008-06-19 16:38:19 -07005136 rxr->rx_prod_bseq = 0;
5137 rxr->rx_prod = 0;
5138 rxr->rx_cons = 0;
5139 rxr->rx_pg_prod = 0;
5140 rxr->rx_pg_cons = 0;
Michael Chanc76c0472007-12-20 20:01:19 -08005141 }
5142}
5143
5144static void
Michael Chan35e90102008-06-19 16:37:42 -07005145bnx2_init_tx_context(struct bnx2 *bp, u32 cid, struct bnx2_tx_ring_info *txr)
Michael Chan59b47d82006-11-19 14:10:45 -08005146{
5147 u32 val, offset0, offset1, offset2, offset3;
Michael Chan62a83132008-01-29 21:35:40 -08005148 u32 cid_addr = GET_CID_ADDR(cid);
Michael Chan59b47d82006-11-19 14:10:45 -08005149
Michael Chan4ce45e02012-12-06 10:33:10 +00005150 if (BNX2_CHIP(bp) == BNX2_CHIP_5709) {
Michael Chan59b47d82006-11-19 14:10:45 -08005151 offset0 = BNX2_L2CTX_TYPE_XI;
5152 offset1 = BNX2_L2CTX_CMD_TYPE_XI;
5153 offset2 = BNX2_L2CTX_TBDR_BHADDR_HI_XI;
5154 offset3 = BNX2_L2CTX_TBDR_BHADDR_LO_XI;
5155 } else {
5156 offset0 = BNX2_L2CTX_TYPE;
5157 offset1 = BNX2_L2CTX_CMD_TYPE;
5158 offset2 = BNX2_L2CTX_TBDR_BHADDR_HI;
5159 offset3 = BNX2_L2CTX_TBDR_BHADDR_LO;
5160 }
5161 val = BNX2_L2CTX_TYPE_TYPE_L2 | BNX2_L2CTX_TYPE_SIZE_L2;
Michael Chan62a83132008-01-29 21:35:40 -08005162 bnx2_ctx_wr(bp, cid_addr, offset0, val);
Michael Chan59b47d82006-11-19 14:10:45 -08005163
5164 val = BNX2_L2CTX_CMD_TYPE_TYPE_L2 | (8 << 16);
Michael Chan62a83132008-01-29 21:35:40 -08005165 bnx2_ctx_wr(bp, cid_addr, offset1, val);
Michael Chan59b47d82006-11-19 14:10:45 -08005166
Michael Chan35e90102008-06-19 16:37:42 -07005167 val = (u64) txr->tx_desc_mapping >> 32;
Michael Chan62a83132008-01-29 21:35:40 -08005168 bnx2_ctx_wr(bp, cid_addr, offset2, val);
Michael Chan59b47d82006-11-19 14:10:45 -08005169
Michael Chan35e90102008-06-19 16:37:42 -07005170 val = (u64) txr->tx_desc_mapping & 0xffffffff;
Michael Chan62a83132008-01-29 21:35:40 -08005171 bnx2_ctx_wr(bp, cid_addr, offset3, val);
Michael Chan59b47d82006-11-19 14:10:45 -08005172}
Michael Chanb6016b72005-05-26 13:03:09 -07005173
5174static void
Michael Chan35e90102008-06-19 16:37:42 -07005175bnx2_init_tx_ring(struct bnx2 *bp, int ring_num)
Michael Chanb6016b72005-05-26 13:03:09 -07005176{
Michael Chan2bc40782012-12-06 10:33:09 +00005177 struct bnx2_tx_bd *txbd;
Michael Chanc76c0472007-12-20 20:01:19 -08005178 u32 cid = TX_CID;
5179 struct bnx2_napi *bnapi;
Michael Chan35e90102008-06-19 16:37:42 -07005180 struct bnx2_tx_ring_info *txr;
Michael Chanc76c0472007-12-20 20:01:19 -08005181
Michael Chan35e90102008-06-19 16:37:42 -07005182 bnapi = &bp->bnx2_napi[ring_num];
5183 txr = &bnapi->tx_ring;
5184
5185 if (ring_num == 0)
5186 cid = TX_CID;
5187 else
5188 cid = TX_TSS_CID + ring_num - 1;
Michael Chanb6016b72005-05-26 13:03:09 -07005189
Michael Chan2f8af122006-08-15 01:39:10 -07005190 bp->tx_wake_thresh = bp->tx_ring_size / 2;
5191
Michael Chan2bc40782012-12-06 10:33:09 +00005192 txbd = &txr->tx_desc_ring[BNX2_MAX_TX_DESC_CNT];
Jeff Garzik6aa20a22006-09-13 13:24:59 -04005193
Michael Chan35e90102008-06-19 16:37:42 -07005194 txbd->tx_bd_haddr_hi = (u64) txr->tx_desc_mapping >> 32;
5195 txbd->tx_bd_haddr_lo = (u64) txr->tx_desc_mapping & 0xffffffff;
Michael Chanb6016b72005-05-26 13:03:09 -07005196
Michael Chan35e90102008-06-19 16:37:42 -07005197 txr->tx_prod = 0;
5198 txr->tx_prod_bseq = 0;
Jeff Garzik6aa20a22006-09-13 13:24:59 -04005199
Michael Chan35e90102008-06-19 16:37:42 -07005200 txr->tx_bidx_addr = MB_GET_CID_ADDR(cid) + BNX2_L2CTX_TX_HOST_BIDX;
5201 txr->tx_bseq_addr = MB_GET_CID_ADDR(cid) + BNX2_L2CTX_TX_HOST_BSEQ;
Michael Chanb6016b72005-05-26 13:03:09 -07005202
Michael Chan35e90102008-06-19 16:37:42 -07005203 bnx2_init_tx_context(bp, cid, txr);
Michael Chanb6016b72005-05-26 13:03:09 -07005204}
5205
5206static void
Michael Chan2bc40782012-12-06 10:33:09 +00005207bnx2_init_rxbd_rings(struct bnx2_rx_bd *rx_ring[], dma_addr_t dma[],
5208 u32 buf_size, int num_rings)
Michael Chanb6016b72005-05-26 13:03:09 -07005209{
Michael Chanb6016b72005-05-26 13:03:09 -07005210 int i;
Michael Chan2bc40782012-12-06 10:33:09 +00005211 struct bnx2_rx_bd *rxbd;
Michael Chanb6016b72005-05-26 13:03:09 -07005212
Michael Chan5d5d0012007-12-12 11:17:43 -08005213 for (i = 0; i < num_rings; i++) {
Michael Chan13daffa2006-03-20 17:49:20 -08005214 int j;
Michael Chanb6016b72005-05-26 13:03:09 -07005215
Michael Chan5d5d0012007-12-12 11:17:43 -08005216 rxbd = &rx_ring[i][0];
Michael Chan2bc40782012-12-06 10:33:09 +00005217 for (j = 0; j < BNX2_MAX_RX_DESC_CNT; j++, rxbd++) {
Michael Chan5d5d0012007-12-12 11:17:43 -08005218 rxbd->rx_bd_len = buf_size;
Michael Chan13daffa2006-03-20 17:49:20 -08005219 rxbd->rx_bd_flags = RX_BD_FLAGS_START | RX_BD_FLAGS_END;
5220 }
Michael Chan5d5d0012007-12-12 11:17:43 -08005221 if (i == (num_rings - 1))
Michael Chan13daffa2006-03-20 17:49:20 -08005222 j = 0;
5223 else
5224 j = i + 1;
Michael Chan5d5d0012007-12-12 11:17:43 -08005225 rxbd->rx_bd_haddr_hi = (u64) dma[j] >> 32;
5226 rxbd->rx_bd_haddr_lo = (u64) dma[j] & 0xffffffff;
Michael Chan13daffa2006-03-20 17:49:20 -08005227 }
Michael Chan5d5d0012007-12-12 11:17:43 -08005228}
5229
5230static void
Michael Chanbb4f98a2008-06-19 16:38:19 -07005231bnx2_init_rx_ring(struct bnx2 *bp, int ring_num)
Michael Chan5d5d0012007-12-12 11:17:43 -08005232{
5233 int i;
5234 u16 prod, ring_prod;
Michael Chanbb4f98a2008-06-19 16:38:19 -07005235 u32 cid, rx_cid_addr, val;
5236 struct bnx2_napi *bnapi = &bp->bnx2_napi[ring_num];
5237 struct bnx2_rx_ring_info *rxr = &bnapi->rx_ring;
Michael Chan5d5d0012007-12-12 11:17:43 -08005238
Michael Chanbb4f98a2008-06-19 16:38:19 -07005239 if (ring_num == 0)
5240 cid = RX_CID;
5241 else
5242 cid = RX_RSS_CID + ring_num - 1;
5243
5244 rx_cid_addr = GET_CID_ADDR(cid);
5245
5246 bnx2_init_rxbd_rings(rxr->rx_desc_ring, rxr->rx_desc_mapping,
Michael Chan5d5d0012007-12-12 11:17:43 -08005247 bp->rx_buf_use_size, bp->rx_max_ring);
5248
Michael Chanbb4f98a2008-06-19 16:38:19 -07005249 bnx2_init_rx_context(bp, cid);
Michael Chan83e3fc82008-01-29 21:37:17 -08005250
Michael Chan4ce45e02012-12-06 10:33:10 +00005251 if (BNX2_CHIP(bp) == BNX2_CHIP_5709) {
Michael Chane503e062012-12-06 10:33:08 +00005252 val = BNX2_RD(bp, BNX2_MQ_MAP_L2_5);
5253 BNX2_WR(bp, BNX2_MQ_MAP_L2_5, val | BNX2_MQ_MAP_L2_5_ARM);
Michael Chan83e3fc82008-01-29 21:37:17 -08005254 }
5255
Michael Chan62a83132008-01-29 21:35:40 -08005256 bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_PG_BUF_SIZE, 0);
Michael Chan47bf4242007-12-12 11:19:12 -08005257 if (bp->rx_pg_ring_size) {
Michael Chanbb4f98a2008-06-19 16:38:19 -07005258 bnx2_init_rxbd_rings(rxr->rx_pg_desc_ring,
5259 rxr->rx_pg_desc_mapping,
Michael Chan47bf4242007-12-12 11:19:12 -08005260 PAGE_SIZE, bp->rx_max_pg_ring);
5261 val = (bp->rx_buf_use_size << 16) | PAGE_SIZE;
Michael Chan62a83132008-01-29 21:35:40 -08005262 bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_PG_BUF_SIZE, val);
5263 bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_RBDC_KEY,
Michael Chan5e9ad9e2008-06-19 16:43:17 -07005264 BNX2_L2CTX_RBDC_JUMBO_KEY - ring_num);
Michael Chan47bf4242007-12-12 11:19:12 -08005265
Michael Chanbb4f98a2008-06-19 16:38:19 -07005266 val = (u64) rxr->rx_pg_desc_mapping[0] >> 32;
Michael Chan62a83132008-01-29 21:35:40 -08005267 bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_NX_PG_BDHADDR_HI, val);
Michael Chan47bf4242007-12-12 11:19:12 -08005268
Michael Chanbb4f98a2008-06-19 16:38:19 -07005269 val = (u64) rxr->rx_pg_desc_mapping[0] & 0xffffffff;
Michael Chan62a83132008-01-29 21:35:40 -08005270 bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_NX_PG_BDHADDR_LO, val);
Michael Chan47bf4242007-12-12 11:19:12 -08005271
Michael Chan4ce45e02012-12-06 10:33:10 +00005272 if (BNX2_CHIP(bp) == BNX2_CHIP_5709)
Michael Chane503e062012-12-06 10:33:08 +00005273 BNX2_WR(bp, BNX2_MQ_MAP_L2_3, BNX2_MQ_MAP_L2_3_DEFAULT);
Michael Chan47bf4242007-12-12 11:19:12 -08005274 }
Michael Chanb6016b72005-05-26 13:03:09 -07005275
Michael Chanbb4f98a2008-06-19 16:38:19 -07005276 val = (u64) rxr->rx_desc_mapping[0] >> 32;
Michael Chan62a83132008-01-29 21:35:40 -08005277 bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_NX_BDHADDR_HI, val);
Michael Chanb6016b72005-05-26 13:03:09 -07005278
Michael Chanbb4f98a2008-06-19 16:38:19 -07005279 val = (u64) rxr->rx_desc_mapping[0] & 0xffffffff;
Michael Chan62a83132008-01-29 21:35:40 -08005280 bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_NX_BDHADDR_LO, val);
Michael Chanb6016b72005-05-26 13:03:09 -07005281
Michael Chanbb4f98a2008-06-19 16:38:19 -07005282 ring_prod = prod = rxr->rx_pg_prod;
Michael Chan47bf4242007-12-12 11:19:12 -08005283 for (i = 0; i < bp->rx_pg_ring_size; i++) {
Stanislaw Gruszkaa2df00a2010-07-15 22:55:40 +00005284 if (bnx2_alloc_rx_page(bp, rxr, ring_prod, GFP_KERNEL) < 0) {
Joe Perches3a9c6a42010-02-17 15:01:51 +00005285 netdev_warn(bp->dev, "init'ed rx page ring %d with %d/%d pages only\n",
5286 ring_num, i, bp->rx_pg_ring_size);
Michael Chan47bf4242007-12-12 11:19:12 -08005287 break;
Michael Chanb929e532009-12-03 09:46:33 +00005288 }
Michael Chan2bc40782012-12-06 10:33:09 +00005289 prod = BNX2_NEXT_RX_BD(prod);
5290 ring_prod = BNX2_RX_PG_RING_IDX(prod);
Michael Chan47bf4242007-12-12 11:19:12 -08005291 }
Michael Chanbb4f98a2008-06-19 16:38:19 -07005292 rxr->rx_pg_prod = prod;
Michael Chan47bf4242007-12-12 11:19:12 -08005293
Michael Chanbb4f98a2008-06-19 16:38:19 -07005294 ring_prod = prod = rxr->rx_prod;
Michael Chan236b6392006-03-20 17:49:02 -08005295 for (i = 0; i < bp->rx_ring_size; i++) {
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00005296 if (bnx2_alloc_rx_data(bp, rxr, ring_prod, GFP_KERNEL) < 0) {
Joe Perches3a9c6a42010-02-17 15:01:51 +00005297 netdev_warn(bp->dev, "init'ed rx ring %d with %d/%d skbs only\n",
5298 ring_num, i, bp->rx_ring_size);
Michael Chanb6016b72005-05-26 13:03:09 -07005299 break;
Michael Chanb929e532009-12-03 09:46:33 +00005300 }
Michael Chan2bc40782012-12-06 10:33:09 +00005301 prod = BNX2_NEXT_RX_BD(prod);
5302 ring_prod = BNX2_RX_RING_IDX(prod);
Michael Chanb6016b72005-05-26 13:03:09 -07005303 }
Michael Chanbb4f98a2008-06-19 16:38:19 -07005304 rxr->rx_prod = prod;
Michael Chanb6016b72005-05-26 13:03:09 -07005305
Michael Chanbb4f98a2008-06-19 16:38:19 -07005306 rxr->rx_bidx_addr = MB_GET_CID_ADDR(cid) + BNX2_L2CTX_HOST_BDIDX;
5307 rxr->rx_bseq_addr = MB_GET_CID_ADDR(cid) + BNX2_L2CTX_HOST_BSEQ;
5308 rxr->rx_pg_bidx_addr = MB_GET_CID_ADDR(cid) + BNX2_L2CTX_HOST_PG_BDIDX;
Michael Chanb6016b72005-05-26 13:03:09 -07005309
Michael Chane503e062012-12-06 10:33:08 +00005310 BNX2_WR16(bp, rxr->rx_pg_bidx_addr, rxr->rx_pg_prod);
5311 BNX2_WR16(bp, rxr->rx_bidx_addr, prod);
Michael Chanbb4f98a2008-06-19 16:38:19 -07005312
Michael Chane503e062012-12-06 10:33:08 +00005313 BNX2_WR(bp, rxr->rx_bseq_addr, rxr->rx_prod_bseq);
Michael Chanb6016b72005-05-26 13:03:09 -07005314}
5315
Michael Chan35e90102008-06-19 16:37:42 -07005316static void
5317bnx2_init_all_rings(struct bnx2 *bp)
5318{
5319 int i;
Michael Chan5e9ad9e2008-06-19 16:43:17 -07005320 u32 val;
Michael Chan35e90102008-06-19 16:37:42 -07005321
5322 bnx2_clear_ring_states(bp);
5323
Michael Chane503e062012-12-06 10:33:08 +00005324 BNX2_WR(bp, BNX2_TSCH_TSS_CFG, 0);
Michael Chan35e90102008-06-19 16:37:42 -07005325 for (i = 0; i < bp->num_tx_rings; i++)
5326 bnx2_init_tx_ring(bp, i);
5327
5328 if (bp->num_tx_rings > 1)
Michael Chane503e062012-12-06 10:33:08 +00005329 BNX2_WR(bp, BNX2_TSCH_TSS_CFG, ((bp->num_tx_rings - 1) << 24) |
5330 (TX_TSS_CID << 7));
Michael Chan35e90102008-06-19 16:37:42 -07005331
Michael Chane503e062012-12-06 10:33:08 +00005332 BNX2_WR(bp, BNX2_RLUP_RSS_CONFIG, 0);
Michael Chan5e9ad9e2008-06-19 16:43:17 -07005333 bnx2_reg_wr_ind(bp, BNX2_RXP_SCRATCH_RSS_TBL_SZ, 0);
5334
Michael Chanbb4f98a2008-06-19 16:38:19 -07005335 for (i = 0; i < bp->num_rx_rings; i++)
5336 bnx2_init_rx_ring(bp, i);
Michael Chan5e9ad9e2008-06-19 16:43:17 -07005337
5338 if (bp->num_rx_rings > 1) {
Michael Chan22fa1592010-10-11 16:12:00 -07005339 u32 tbl_32 = 0;
Michael Chan5e9ad9e2008-06-19 16:43:17 -07005340
5341 for (i = 0; i < BNX2_RXP_SCRATCH_RSS_TBL_MAX_ENTRIES; i++) {
Michael Chan22fa1592010-10-11 16:12:00 -07005342 int shift = (i % 8) << 2;
5343
5344 tbl_32 |= (i % (bp->num_rx_rings - 1)) << shift;
5345 if ((i % 8) == 7) {
Michael Chane503e062012-12-06 10:33:08 +00005346 BNX2_WR(bp, BNX2_RLUP_RSS_DATA, tbl_32);
5347 BNX2_WR(bp, BNX2_RLUP_RSS_COMMAND, (i >> 3) |
Michael Chan22fa1592010-10-11 16:12:00 -07005348 BNX2_RLUP_RSS_COMMAND_RSS_WRITE_MASK |
5349 BNX2_RLUP_RSS_COMMAND_WRITE |
5350 BNX2_RLUP_RSS_COMMAND_HASH_MASK);
5351 tbl_32 = 0;
5352 }
Michael Chan5e9ad9e2008-06-19 16:43:17 -07005353 }
5354
5355 val = BNX2_RLUP_RSS_CONFIG_IPV4_RSS_TYPE_ALL_XI |
5356 BNX2_RLUP_RSS_CONFIG_IPV6_RSS_TYPE_ALL_XI;
5357
Michael Chane503e062012-12-06 10:33:08 +00005358 BNX2_WR(bp, BNX2_RLUP_RSS_CONFIG, val);
Michael Chan5e9ad9e2008-06-19 16:43:17 -07005359
5360 }
Michael Chan35e90102008-06-19 16:37:42 -07005361}
5362
Michael Chan5d5d0012007-12-12 11:17:43 -08005363static u32 bnx2_find_max_ring(u32 ring_size, u32 max_size)
Michael Chan13daffa2006-03-20 17:49:20 -08005364{
Michael Chan5d5d0012007-12-12 11:17:43 -08005365 u32 max, num_rings = 1;
Michael Chan13daffa2006-03-20 17:49:20 -08005366
Michael Chan2bc40782012-12-06 10:33:09 +00005367 while (ring_size > BNX2_MAX_RX_DESC_CNT) {
5368 ring_size -= BNX2_MAX_RX_DESC_CNT;
Michael Chan13daffa2006-03-20 17:49:20 -08005369 num_rings++;
5370 }
5371 /* round to next power of 2 */
Michael Chan5d5d0012007-12-12 11:17:43 -08005372 max = max_size;
Michael Chan13daffa2006-03-20 17:49:20 -08005373 while ((max & num_rings) == 0)
5374 max >>= 1;
5375
5376 if (num_rings != max)
5377 max <<= 1;
5378
Michael Chan5d5d0012007-12-12 11:17:43 -08005379 return max;
5380}
5381
5382static void
5383bnx2_set_rx_ring_size(struct bnx2 *bp, u32 size)
5384{
Michael Chan84eaa182007-12-12 11:19:57 -08005385 u32 rx_size, rx_space, jumbo_size;
Michael Chan5d5d0012007-12-12 11:17:43 -08005386
5387 /* 8 for CRC and VLAN */
Benjamin Lid89cb6a2008-05-16 22:18:57 -07005388 rx_size = bp->dev->mtu + ETH_HLEN + BNX2_RX_OFFSET + 8;
Michael Chan5d5d0012007-12-12 11:17:43 -08005389
Michael Chan84eaa182007-12-12 11:19:57 -08005390 rx_space = SKB_DATA_ALIGN(rx_size + BNX2_RX_ALIGN) + NET_SKB_PAD +
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00005391 SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
Michael Chan84eaa182007-12-12 11:19:57 -08005392
Benjamin Li601d3d12008-05-16 22:19:35 -07005393 bp->rx_copy_thresh = BNX2_RX_COPY_THRESH;
Michael Chan47bf4242007-12-12 11:19:12 -08005394 bp->rx_pg_ring_size = 0;
5395 bp->rx_max_pg_ring = 0;
5396 bp->rx_max_pg_ring_idx = 0;
David S. Millerf86e82f2008-01-21 17:15:40 -08005397 if ((rx_space > PAGE_SIZE) && !(bp->flags & BNX2_FLAG_JUMBO_BROKEN)) {
Michael Chan84eaa182007-12-12 11:19:57 -08005398 int pages = PAGE_ALIGN(bp->dev->mtu - 40) >> PAGE_SHIFT;
5399
5400 jumbo_size = size * pages;
Michael Chan2bc40782012-12-06 10:33:09 +00005401 if (jumbo_size > BNX2_MAX_TOTAL_RX_PG_DESC_CNT)
5402 jumbo_size = BNX2_MAX_TOTAL_RX_PG_DESC_CNT;
Michael Chan84eaa182007-12-12 11:19:57 -08005403
5404 bp->rx_pg_ring_size = jumbo_size;
5405 bp->rx_max_pg_ring = bnx2_find_max_ring(jumbo_size,
Michael Chan2bc40782012-12-06 10:33:09 +00005406 BNX2_MAX_RX_PG_RINGS);
5407 bp->rx_max_pg_ring_idx =
5408 (bp->rx_max_pg_ring * BNX2_RX_DESC_CNT) - 1;
Benjamin Li601d3d12008-05-16 22:19:35 -07005409 rx_size = BNX2_RX_COPY_THRESH + BNX2_RX_OFFSET;
Michael Chan84eaa182007-12-12 11:19:57 -08005410 bp->rx_copy_thresh = 0;
5411 }
Michael Chan5d5d0012007-12-12 11:17:43 -08005412
5413 bp->rx_buf_use_size = rx_size;
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00005414 /* hw alignment + build_skb() overhead*/
5415 bp->rx_buf_size = SKB_DATA_ALIGN(bp->rx_buf_use_size + BNX2_RX_ALIGN) +
5416 NET_SKB_PAD + SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
Benjamin Lid89cb6a2008-05-16 22:18:57 -07005417 bp->rx_jumbo_thresh = rx_size - BNX2_RX_OFFSET;
Michael Chan5d5d0012007-12-12 11:17:43 -08005418 bp->rx_ring_size = size;
Michael Chan2bc40782012-12-06 10:33:09 +00005419 bp->rx_max_ring = bnx2_find_max_ring(size, BNX2_MAX_RX_RINGS);
5420 bp->rx_max_ring_idx = (bp->rx_max_ring * BNX2_RX_DESC_CNT) - 1;
Michael Chan13daffa2006-03-20 17:49:20 -08005421}
5422
5423static void
Michael Chanb6016b72005-05-26 13:03:09 -07005424bnx2_free_tx_skbs(struct bnx2 *bp)
5425{
5426 int i;
5427
Michael Chan35e90102008-06-19 16:37:42 -07005428 for (i = 0; i < bp->num_tx_rings; i++) {
5429 struct bnx2_napi *bnapi = &bp->bnx2_napi[i];
5430 struct bnx2_tx_ring_info *txr = &bnapi->tx_ring;
5431 int j;
Michael Chanb6016b72005-05-26 13:03:09 -07005432
Michael Chan35e90102008-06-19 16:37:42 -07005433 if (txr->tx_buf_ring == NULL)
Michael Chanb6016b72005-05-26 13:03:09 -07005434 continue;
Michael Chanb6016b72005-05-26 13:03:09 -07005435
Michael Chan2bc40782012-12-06 10:33:09 +00005436 for (j = 0; j < BNX2_TX_DESC_CNT; ) {
5437 struct bnx2_sw_tx_bd *tx_buf = &txr->tx_buf_ring[j];
Michael Chan35e90102008-06-19 16:37:42 -07005438 struct sk_buff *skb = tx_buf->skb;
Alexander Duycke95524a2009-12-02 16:47:57 +00005439 int k, last;
Michael Chan35e90102008-06-19 16:37:42 -07005440
5441 if (skb == NULL) {
Michael Chan2bc40782012-12-06 10:33:09 +00005442 j = BNX2_NEXT_TX_BD(j);
Michael Chan35e90102008-06-19 16:37:42 -07005443 continue;
5444 }
5445
Stanislaw Gruszka36227e82010-07-15 04:25:50 +00005446 dma_unmap_single(&bp->pdev->dev,
FUJITA Tomonori1a4ccc22010-04-01 16:56:57 +00005447 dma_unmap_addr(tx_buf, mapping),
Alexander Duycke95524a2009-12-02 16:47:57 +00005448 skb_headlen(skb),
5449 PCI_DMA_TODEVICE);
Michael Chanb6016b72005-05-26 13:03:09 -07005450
Michael Chan35e90102008-06-19 16:37:42 -07005451 tx_buf->skb = NULL;
Michael Chanb6016b72005-05-26 13:03:09 -07005452
Alexander Duycke95524a2009-12-02 16:47:57 +00005453 last = tx_buf->nr_frags;
Michael Chan2bc40782012-12-06 10:33:09 +00005454 j = BNX2_NEXT_TX_BD(j);
5455 for (k = 0; k < last; k++, j = BNX2_NEXT_TX_BD(j)) {
5456 tx_buf = &txr->tx_buf_ring[BNX2_TX_RING_IDX(j)];
Stanislaw Gruszka36227e82010-07-15 04:25:50 +00005457 dma_unmap_page(&bp->pdev->dev,
FUJITA Tomonori1a4ccc22010-04-01 16:56:57 +00005458 dma_unmap_addr(tx_buf, mapping),
Eric Dumazet9e903e02011-10-18 21:00:24 +00005459 skb_frag_size(&skb_shinfo(skb)->frags[k]),
Alexander Duycke95524a2009-12-02 16:47:57 +00005460 PCI_DMA_TODEVICE);
5461 }
Michael Chan35e90102008-06-19 16:37:42 -07005462 dev_kfree_skb(skb);
Michael Chanb6016b72005-05-26 13:03:09 -07005463 }
Eric Dumazete9831902011-11-29 11:53:05 +00005464 netdev_tx_reset_queue(netdev_get_tx_queue(bp->dev, i));
Michael Chanb6016b72005-05-26 13:03:09 -07005465 }
Michael Chanb6016b72005-05-26 13:03:09 -07005466}
5467
5468static void
5469bnx2_free_rx_skbs(struct bnx2 *bp)
5470{
5471 int i;
5472
Michael Chanbb4f98a2008-06-19 16:38:19 -07005473 for (i = 0; i < bp->num_rx_rings; i++) {
5474 struct bnx2_napi *bnapi = &bp->bnx2_napi[i];
5475 struct bnx2_rx_ring_info *rxr = &bnapi->rx_ring;
5476 int j;
Michael Chanb6016b72005-05-26 13:03:09 -07005477
Michael Chanbb4f98a2008-06-19 16:38:19 -07005478 if (rxr->rx_buf_ring == NULL)
5479 return;
Michael Chanb6016b72005-05-26 13:03:09 -07005480
Michael Chanbb4f98a2008-06-19 16:38:19 -07005481 for (j = 0; j < bp->rx_max_ring_idx; j++) {
Michael Chan2bc40782012-12-06 10:33:09 +00005482 struct bnx2_sw_bd *rx_buf = &rxr->rx_buf_ring[j];
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00005483 u8 *data = rx_buf->data;
Michael Chanb6016b72005-05-26 13:03:09 -07005484
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00005485 if (data == NULL)
Michael Chanbb4f98a2008-06-19 16:38:19 -07005486 continue;
Michael Chanb6016b72005-05-26 13:03:09 -07005487
Stanislaw Gruszka36227e82010-07-15 04:25:50 +00005488 dma_unmap_single(&bp->pdev->dev,
FUJITA Tomonori1a4ccc22010-04-01 16:56:57 +00005489 dma_unmap_addr(rx_buf, mapping),
Michael Chanbb4f98a2008-06-19 16:38:19 -07005490 bp->rx_buf_use_size,
5491 PCI_DMA_FROMDEVICE);
Michael Chanb6016b72005-05-26 13:03:09 -07005492
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00005493 rx_buf->data = NULL;
Michael Chanbb4f98a2008-06-19 16:38:19 -07005494
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00005495 kfree(data);
Michael Chanbb4f98a2008-06-19 16:38:19 -07005496 }
5497 for (j = 0; j < bp->rx_max_pg_ring_idx; j++)
5498 bnx2_free_rx_page(bp, rxr, j);
Michael Chanb6016b72005-05-26 13:03:09 -07005499 }
5500}
5501
5502static void
5503bnx2_free_skbs(struct bnx2 *bp)
5504{
5505 bnx2_free_tx_skbs(bp);
5506 bnx2_free_rx_skbs(bp);
5507}
5508
5509static int
5510bnx2_reset_nic(struct bnx2 *bp, u32 reset_code)
5511{
5512 int rc;
5513
5514 rc = bnx2_reset_chip(bp, reset_code);
5515 bnx2_free_skbs(bp);
5516 if (rc)
5517 return rc;
5518
Michael Chanfba9fe92006-06-12 22:21:25 -07005519 if ((rc = bnx2_init_chip(bp)) != 0)
5520 return rc;
5521
Michael Chan35e90102008-06-19 16:37:42 -07005522 bnx2_init_all_rings(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07005523 return 0;
5524}
5525
5526static int
Michael Chan9a120bc2008-05-16 22:17:45 -07005527bnx2_init_nic(struct bnx2 *bp, int reset_phy)
Michael Chanb6016b72005-05-26 13:03:09 -07005528{
5529 int rc;
5530
5531 if ((rc = bnx2_reset_nic(bp, BNX2_DRV_MSG_CODE_RESET)) != 0)
5532 return rc;
5533
Michael Chan80be4432006-11-19 14:07:28 -08005534 spin_lock_bh(&bp->phy_lock);
Michael Chan9a120bc2008-05-16 22:17:45 -07005535 bnx2_init_phy(bp, reset_phy);
Michael Chanb6016b72005-05-26 13:03:09 -07005536 bnx2_set_link(bp);
Michael Chan543a8272008-05-02 16:56:44 -07005537 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
5538 bnx2_remote_phy_event(bp);
Michael Chan0d8a6572007-07-07 22:49:43 -07005539 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07005540 return 0;
5541}
5542
5543static int
Michael Chan74bf4ba2008-10-09 12:21:08 -07005544bnx2_shutdown_chip(struct bnx2 *bp)
5545{
5546 u32 reset_code;
5547
5548 if (bp->flags & BNX2_FLAG_NO_WOL)
5549 reset_code = BNX2_DRV_MSG_CODE_UNLOAD_LNK_DN;
5550 else if (bp->wol)
5551 reset_code = BNX2_DRV_MSG_CODE_SUSPEND_WOL;
5552 else
5553 reset_code = BNX2_DRV_MSG_CODE_SUSPEND_NO_WOL;
5554
5555 return bnx2_reset_chip(bp, reset_code);
5556}
5557
5558static int
Michael Chanb6016b72005-05-26 13:03:09 -07005559bnx2_test_registers(struct bnx2 *bp)
5560{
5561 int ret;
Michael Chan5bae30c2007-05-03 13:18:46 -07005562 int i, is_5709;
Arjan van de Venf71e1302006-03-03 21:33:57 -05005563 static const struct {
Michael Chanb6016b72005-05-26 13:03:09 -07005564 u16 offset;
5565 u16 flags;
Michael Chan5bae30c2007-05-03 13:18:46 -07005566#define BNX2_FL_NOT_5709 1
Michael Chanb6016b72005-05-26 13:03:09 -07005567 u32 rw_mask;
5568 u32 ro_mask;
5569 } reg_tbl[] = {
5570 { 0x006c, 0, 0x00000000, 0x0000003f },
5571 { 0x0090, 0, 0xffffffff, 0x00000000 },
5572 { 0x0094, 0, 0x00000000, 0x00000000 },
5573
Michael Chan5bae30c2007-05-03 13:18:46 -07005574 { 0x0404, BNX2_FL_NOT_5709, 0x00003f00, 0x00000000 },
5575 { 0x0418, BNX2_FL_NOT_5709, 0x00000000, 0xffffffff },
5576 { 0x041c, BNX2_FL_NOT_5709, 0x00000000, 0xffffffff },
5577 { 0x0420, BNX2_FL_NOT_5709, 0x00000000, 0x80ffffff },
5578 { 0x0424, BNX2_FL_NOT_5709, 0x00000000, 0x00000000 },
5579 { 0x0428, BNX2_FL_NOT_5709, 0x00000000, 0x00000001 },
5580 { 0x0450, BNX2_FL_NOT_5709, 0x00000000, 0x0000ffff },
5581 { 0x0454, BNX2_FL_NOT_5709, 0x00000000, 0xffffffff },
5582 { 0x0458, BNX2_FL_NOT_5709, 0x00000000, 0xffffffff },
Michael Chanb6016b72005-05-26 13:03:09 -07005583
Michael Chan5bae30c2007-05-03 13:18:46 -07005584 { 0x0808, BNX2_FL_NOT_5709, 0x00000000, 0xffffffff },
5585 { 0x0854, BNX2_FL_NOT_5709, 0x00000000, 0xffffffff },
5586 { 0x0868, BNX2_FL_NOT_5709, 0x00000000, 0x77777777 },
5587 { 0x086c, BNX2_FL_NOT_5709, 0x00000000, 0x77777777 },
5588 { 0x0870, BNX2_FL_NOT_5709, 0x00000000, 0x77777777 },
5589 { 0x0874, BNX2_FL_NOT_5709, 0x00000000, 0x77777777 },
Michael Chanb6016b72005-05-26 13:03:09 -07005590
Michael Chan5bae30c2007-05-03 13:18:46 -07005591 { 0x0c00, BNX2_FL_NOT_5709, 0x00000000, 0x00000001 },
5592 { 0x0c04, BNX2_FL_NOT_5709, 0x00000000, 0x03ff0001 },
5593 { 0x0c08, BNX2_FL_NOT_5709, 0x0f0ff073, 0x00000000 },
Michael Chanb6016b72005-05-26 13:03:09 -07005594
5595 { 0x1000, 0, 0x00000000, 0x00000001 },
Michael Chan15b169c2008-05-02 16:57:08 -07005596 { 0x1004, BNX2_FL_NOT_5709, 0x00000000, 0x000f0001 },
Michael Chanb6016b72005-05-26 13:03:09 -07005597
5598 { 0x1408, 0, 0x01c00800, 0x00000000 },
5599 { 0x149c, 0, 0x8000ffff, 0x00000000 },
5600 { 0x14a8, 0, 0x00000000, 0x000001ff },
Michael Chan5b0c76a2005-11-04 08:45:49 -08005601 { 0x14ac, 0, 0x0fffffff, 0x10000000 },
Michael Chanb6016b72005-05-26 13:03:09 -07005602 { 0x14b0, 0, 0x00000002, 0x00000001 },
5603 { 0x14b8, 0, 0x00000000, 0x00000000 },
5604 { 0x14c0, 0, 0x00000000, 0x00000009 },
5605 { 0x14c4, 0, 0x00003fff, 0x00000000 },
5606 { 0x14cc, 0, 0x00000000, 0x00000001 },
5607 { 0x14d0, 0, 0xffffffff, 0x00000000 },
Michael Chanb6016b72005-05-26 13:03:09 -07005608
5609 { 0x1800, 0, 0x00000000, 0x00000001 },
5610 { 0x1804, 0, 0x00000000, 0x00000003 },
Michael Chanb6016b72005-05-26 13:03:09 -07005611
5612 { 0x2800, 0, 0x00000000, 0x00000001 },
5613 { 0x2804, 0, 0x00000000, 0x00003f01 },
5614 { 0x2808, 0, 0x0f3f3f03, 0x00000000 },
5615 { 0x2810, 0, 0xffff0000, 0x00000000 },
5616 { 0x2814, 0, 0xffff0000, 0x00000000 },
5617 { 0x2818, 0, 0xffff0000, 0x00000000 },
5618 { 0x281c, 0, 0xffff0000, 0x00000000 },
5619 { 0x2834, 0, 0xffffffff, 0x00000000 },
5620 { 0x2840, 0, 0x00000000, 0xffffffff },
5621 { 0x2844, 0, 0x00000000, 0xffffffff },
5622 { 0x2848, 0, 0xffffffff, 0x00000000 },
5623 { 0x284c, 0, 0xf800f800, 0x07ff07ff },
5624
5625 { 0x2c00, 0, 0x00000000, 0x00000011 },
5626 { 0x2c04, 0, 0x00000000, 0x00030007 },
5627
Michael Chanb6016b72005-05-26 13:03:09 -07005628 { 0x3c00, 0, 0x00000000, 0x00000001 },
5629 { 0x3c04, 0, 0x00000000, 0x00070000 },
5630 { 0x3c08, 0, 0x00007f71, 0x07f00000 },
5631 { 0x3c0c, 0, 0x1f3ffffc, 0x00000000 },
5632 { 0x3c10, 0, 0xffffffff, 0x00000000 },
5633 { 0x3c14, 0, 0x00000000, 0xffffffff },
5634 { 0x3c18, 0, 0x00000000, 0xffffffff },
5635 { 0x3c1c, 0, 0xfffff000, 0x00000000 },
5636 { 0x3c20, 0, 0xffffff00, 0x00000000 },
Michael Chanb6016b72005-05-26 13:03:09 -07005637
5638 { 0x5004, 0, 0x00000000, 0x0000007f },
5639 { 0x5008, 0, 0x0f0007ff, 0x00000000 },
Michael Chanb6016b72005-05-26 13:03:09 -07005640
Michael Chanb6016b72005-05-26 13:03:09 -07005641 { 0x5c00, 0, 0x00000000, 0x00000001 },
5642 { 0x5c04, 0, 0x00000000, 0x0003000f },
5643 { 0x5c08, 0, 0x00000003, 0x00000000 },
5644 { 0x5c0c, 0, 0x0000fff8, 0x00000000 },
5645 { 0x5c10, 0, 0x00000000, 0xffffffff },
5646 { 0x5c80, 0, 0x00000000, 0x0f7113f1 },
5647 { 0x5c84, 0, 0x00000000, 0x0000f333 },
5648 { 0x5c88, 0, 0x00000000, 0x00077373 },
5649 { 0x5c8c, 0, 0x00000000, 0x0007f737 },
5650
5651 { 0x6808, 0, 0x0000ff7f, 0x00000000 },
5652 { 0x680c, 0, 0xffffffff, 0x00000000 },
5653 { 0x6810, 0, 0xffffffff, 0x00000000 },
5654 { 0x6814, 0, 0xffffffff, 0x00000000 },
5655 { 0x6818, 0, 0xffffffff, 0x00000000 },
5656 { 0x681c, 0, 0xffffffff, 0x00000000 },
5657 { 0x6820, 0, 0x00ff00ff, 0x00000000 },
5658 { 0x6824, 0, 0x00ff00ff, 0x00000000 },
5659 { 0x6828, 0, 0x00ff00ff, 0x00000000 },
5660 { 0x682c, 0, 0x03ff03ff, 0x00000000 },
5661 { 0x6830, 0, 0x03ff03ff, 0x00000000 },
5662 { 0x6834, 0, 0x03ff03ff, 0x00000000 },
5663 { 0x6838, 0, 0x03ff03ff, 0x00000000 },
5664 { 0x683c, 0, 0x0000ffff, 0x00000000 },
5665 { 0x6840, 0, 0x00000ff0, 0x00000000 },
5666 { 0x6844, 0, 0x00ffff00, 0x00000000 },
5667 { 0x684c, 0, 0xffffffff, 0x00000000 },
5668 { 0x6850, 0, 0x7f7f7f7f, 0x00000000 },
5669 { 0x6854, 0, 0x7f7f7f7f, 0x00000000 },
5670 { 0x6858, 0, 0x7f7f7f7f, 0x00000000 },
5671 { 0x685c, 0, 0x7f7f7f7f, 0x00000000 },
5672 { 0x6908, 0, 0x00000000, 0x0001ff0f },
5673 { 0x690c, 0, 0x00000000, 0x0ffe00f0 },
5674
5675 { 0xffff, 0, 0x00000000, 0x00000000 },
5676 };
5677
5678 ret = 0;
Michael Chan5bae30c2007-05-03 13:18:46 -07005679 is_5709 = 0;
Michael Chan4ce45e02012-12-06 10:33:10 +00005680 if (BNX2_CHIP(bp) == BNX2_CHIP_5709)
Michael Chan5bae30c2007-05-03 13:18:46 -07005681 is_5709 = 1;
5682
Michael Chanb6016b72005-05-26 13:03:09 -07005683 for (i = 0; reg_tbl[i].offset != 0xffff; i++) {
5684 u32 offset, rw_mask, ro_mask, save_val, val;
Michael Chan5bae30c2007-05-03 13:18:46 -07005685 u16 flags = reg_tbl[i].flags;
5686
5687 if (is_5709 && (flags & BNX2_FL_NOT_5709))
5688 continue;
Michael Chanb6016b72005-05-26 13:03:09 -07005689
5690 offset = (u32) reg_tbl[i].offset;
5691 rw_mask = reg_tbl[i].rw_mask;
5692 ro_mask = reg_tbl[i].ro_mask;
5693
Peter Hagervall14ab9b82005-08-10 14:18:16 -07005694 save_val = readl(bp->regview + offset);
Michael Chanb6016b72005-05-26 13:03:09 -07005695
Peter Hagervall14ab9b82005-08-10 14:18:16 -07005696 writel(0, bp->regview + offset);
Michael Chanb6016b72005-05-26 13:03:09 -07005697
Peter Hagervall14ab9b82005-08-10 14:18:16 -07005698 val = readl(bp->regview + offset);
Michael Chanb6016b72005-05-26 13:03:09 -07005699 if ((val & rw_mask) != 0) {
5700 goto reg_test_err;
5701 }
5702
5703 if ((val & ro_mask) != (save_val & ro_mask)) {
5704 goto reg_test_err;
5705 }
5706
Peter Hagervall14ab9b82005-08-10 14:18:16 -07005707 writel(0xffffffff, bp->regview + offset);
Michael Chanb6016b72005-05-26 13:03:09 -07005708
Peter Hagervall14ab9b82005-08-10 14:18:16 -07005709 val = readl(bp->regview + offset);
Michael Chanb6016b72005-05-26 13:03:09 -07005710 if ((val & rw_mask) != rw_mask) {
5711 goto reg_test_err;
5712 }
5713
5714 if ((val & ro_mask) != (save_val & ro_mask)) {
5715 goto reg_test_err;
5716 }
5717
Peter Hagervall14ab9b82005-08-10 14:18:16 -07005718 writel(save_val, bp->regview + offset);
Michael Chanb6016b72005-05-26 13:03:09 -07005719 continue;
5720
5721reg_test_err:
Peter Hagervall14ab9b82005-08-10 14:18:16 -07005722 writel(save_val, bp->regview + offset);
Michael Chanb6016b72005-05-26 13:03:09 -07005723 ret = -ENODEV;
5724 break;
5725 }
5726 return ret;
5727}
5728
5729static int
5730bnx2_do_mem_test(struct bnx2 *bp, u32 start, u32 size)
5731{
Arjan van de Venf71e1302006-03-03 21:33:57 -05005732 static const u32 test_pattern[] = { 0x00000000, 0xffffffff, 0x55555555,
Michael Chanb6016b72005-05-26 13:03:09 -07005733 0xaaaaaaaa , 0xaa55aa55, 0x55aa55aa };
5734 int i;
5735
5736 for (i = 0; i < sizeof(test_pattern) / 4; i++) {
5737 u32 offset;
5738
5739 for (offset = 0; offset < size; offset += 4) {
5740
Michael Chan2726d6e2008-01-29 21:35:05 -08005741 bnx2_reg_wr_ind(bp, start + offset, test_pattern[i]);
Michael Chanb6016b72005-05-26 13:03:09 -07005742
Michael Chan2726d6e2008-01-29 21:35:05 -08005743 if (bnx2_reg_rd_ind(bp, start + offset) !=
Michael Chanb6016b72005-05-26 13:03:09 -07005744 test_pattern[i]) {
5745 return -ENODEV;
5746 }
5747 }
5748 }
5749 return 0;
5750}
5751
5752static int
5753bnx2_test_memory(struct bnx2 *bp)
5754{
5755 int ret = 0;
5756 int i;
Michael Chan5bae30c2007-05-03 13:18:46 -07005757 static struct mem_entry {
Michael Chanb6016b72005-05-26 13:03:09 -07005758 u32 offset;
5759 u32 len;
Michael Chan5bae30c2007-05-03 13:18:46 -07005760 } mem_tbl_5706[] = {
Michael Chanb6016b72005-05-26 13:03:09 -07005761 { 0x60000, 0x4000 },
Michael Chan5b0c76a2005-11-04 08:45:49 -08005762 { 0xa0000, 0x3000 },
Michael Chanb6016b72005-05-26 13:03:09 -07005763 { 0xe0000, 0x4000 },
5764 { 0x120000, 0x4000 },
5765 { 0x1a0000, 0x4000 },
5766 { 0x160000, 0x4000 },
5767 { 0xffffffff, 0 },
Michael Chan5bae30c2007-05-03 13:18:46 -07005768 },
5769 mem_tbl_5709[] = {
5770 { 0x60000, 0x4000 },
5771 { 0xa0000, 0x3000 },
5772 { 0xe0000, 0x4000 },
5773 { 0x120000, 0x4000 },
5774 { 0x1a0000, 0x4000 },
5775 { 0xffffffff, 0 },
Michael Chanb6016b72005-05-26 13:03:09 -07005776 };
Michael Chan5bae30c2007-05-03 13:18:46 -07005777 struct mem_entry *mem_tbl;
5778
Michael Chan4ce45e02012-12-06 10:33:10 +00005779 if (BNX2_CHIP(bp) == BNX2_CHIP_5709)
Michael Chan5bae30c2007-05-03 13:18:46 -07005780 mem_tbl = mem_tbl_5709;
5781 else
5782 mem_tbl = mem_tbl_5706;
Michael Chanb6016b72005-05-26 13:03:09 -07005783
5784 for (i = 0; mem_tbl[i].offset != 0xffffffff; i++) {
5785 if ((ret = bnx2_do_mem_test(bp, mem_tbl[i].offset,
5786 mem_tbl[i].len)) != 0) {
5787 return ret;
5788 }
5789 }
Jeff Garzik6aa20a22006-09-13 13:24:59 -04005790
Michael Chanb6016b72005-05-26 13:03:09 -07005791 return ret;
5792}
5793
Michael Chanbc5a0692006-01-23 16:13:22 -08005794#define BNX2_MAC_LOOPBACK 0
5795#define BNX2_PHY_LOOPBACK 1
5796
Michael Chanb6016b72005-05-26 13:03:09 -07005797static int
Michael Chanbc5a0692006-01-23 16:13:22 -08005798bnx2_run_loopback(struct bnx2 *bp, int loopback_mode)
Michael Chanb6016b72005-05-26 13:03:09 -07005799{
5800 unsigned int pkt_size, num_pkts, i;
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00005801 struct sk_buff *skb;
5802 u8 *data;
Michael Chanb6016b72005-05-26 13:03:09 -07005803 unsigned char *packet;
Michael Chanbc5a0692006-01-23 16:13:22 -08005804 u16 rx_start_idx, rx_idx;
Michael Chanb6016b72005-05-26 13:03:09 -07005805 dma_addr_t map;
Michael Chan2bc40782012-12-06 10:33:09 +00005806 struct bnx2_tx_bd *txbd;
5807 struct bnx2_sw_bd *rx_buf;
Michael Chanb6016b72005-05-26 13:03:09 -07005808 struct l2_fhdr *rx_hdr;
5809 int ret = -ENODEV;
Michael Chanc76c0472007-12-20 20:01:19 -08005810 struct bnx2_napi *bnapi = &bp->bnx2_napi[0], *tx_napi;
Michael Chan35e90102008-06-19 16:37:42 -07005811 struct bnx2_tx_ring_info *txr = &bnapi->tx_ring;
Michael Chanbb4f98a2008-06-19 16:38:19 -07005812 struct bnx2_rx_ring_info *rxr = &bnapi->rx_ring;
Michael Chanc76c0472007-12-20 20:01:19 -08005813
5814 tx_napi = bnapi;
Michael Chanb6016b72005-05-26 13:03:09 -07005815
Michael Chan35e90102008-06-19 16:37:42 -07005816 txr = &tx_napi->tx_ring;
Michael Chanbb4f98a2008-06-19 16:38:19 -07005817 rxr = &bnapi->rx_ring;
Michael Chanbc5a0692006-01-23 16:13:22 -08005818 if (loopback_mode == BNX2_MAC_LOOPBACK) {
5819 bp->loopback = MAC_LOOPBACK;
5820 bnx2_set_mac_loopback(bp);
5821 }
5822 else if (loopback_mode == BNX2_PHY_LOOPBACK) {
Michael Chan583c28e2008-01-21 19:51:35 -08005823 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
Michael Chan489310a2007-10-10 16:16:31 -07005824 return 0;
5825
Michael Chan80be4432006-11-19 14:07:28 -08005826 bp->loopback = PHY_LOOPBACK;
Michael Chanbc5a0692006-01-23 16:13:22 -08005827 bnx2_set_phy_loopback(bp);
5828 }
5829 else
5830 return -EINVAL;
Michael Chanb6016b72005-05-26 13:03:09 -07005831
Michael Chan84eaa182007-12-12 11:19:57 -08005832 pkt_size = min(bp->dev->mtu + ETH_HLEN, bp->rx_jumbo_thresh - 4);
Michael Chan932f3772006-08-15 01:39:36 -07005833 skb = netdev_alloc_skb(bp->dev, pkt_size);
John W. Linvilleb6cbc3b62005-11-10 12:58:00 -08005834 if (!skb)
5835 return -ENOMEM;
Michael Chanb6016b72005-05-26 13:03:09 -07005836 packet = skb_put(skb, pkt_size);
Joe Perchesd458cdf2013-10-01 19:04:40 -07005837 memcpy(packet, bp->dev->dev_addr, ETH_ALEN);
5838 memset(packet + ETH_ALEN, 0x0, 8);
Michael Chanb6016b72005-05-26 13:03:09 -07005839 for (i = 14; i < pkt_size; i++)
5840 packet[i] = (unsigned char) (i & 0xff);
5841
Stanislaw Gruszka36227e82010-07-15 04:25:50 +00005842 map = dma_map_single(&bp->pdev->dev, skb->data, pkt_size,
5843 PCI_DMA_TODEVICE);
5844 if (dma_mapping_error(&bp->pdev->dev, map)) {
Benjamin Li3d16af82008-10-09 12:26:41 -07005845 dev_kfree_skb(skb);
5846 return -EIO;
5847 }
Michael Chanb6016b72005-05-26 13:03:09 -07005848
Michael Chane503e062012-12-06 10:33:08 +00005849 BNX2_WR(bp, BNX2_HC_COMMAND,
5850 bp->hc_cmd | BNX2_HC_COMMAND_COAL_NOW_WO_INT);
Michael Chanbf5295b2006-03-23 01:11:56 -08005851
Michael Chane503e062012-12-06 10:33:08 +00005852 BNX2_RD(bp, BNX2_HC_COMMAND);
Michael Chanb6016b72005-05-26 13:03:09 -07005853
5854 udelay(5);
Michael Chan35efa7c2007-12-20 19:56:37 -08005855 rx_start_idx = bnx2_get_hw_rx_cons(bnapi);
Michael Chanb6016b72005-05-26 13:03:09 -07005856
Michael Chanb6016b72005-05-26 13:03:09 -07005857 num_pkts = 0;
5858
Michael Chan2bc40782012-12-06 10:33:09 +00005859 txbd = &txr->tx_desc_ring[BNX2_TX_RING_IDX(txr->tx_prod)];
Michael Chanb6016b72005-05-26 13:03:09 -07005860
5861 txbd->tx_bd_haddr_hi = (u64) map >> 32;
5862 txbd->tx_bd_haddr_lo = (u64) map & 0xffffffff;
5863 txbd->tx_bd_mss_nbytes = pkt_size;
5864 txbd->tx_bd_vlan_tag_flags = TX_BD_FLAGS_START | TX_BD_FLAGS_END;
5865
5866 num_pkts++;
Michael Chan2bc40782012-12-06 10:33:09 +00005867 txr->tx_prod = BNX2_NEXT_TX_BD(txr->tx_prod);
Michael Chan35e90102008-06-19 16:37:42 -07005868 txr->tx_prod_bseq += pkt_size;
Michael Chanb6016b72005-05-26 13:03:09 -07005869
Michael Chane503e062012-12-06 10:33:08 +00005870 BNX2_WR16(bp, txr->tx_bidx_addr, txr->tx_prod);
5871 BNX2_WR(bp, txr->tx_bseq_addr, txr->tx_prod_bseq);
Michael Chanb6016b72005-05-26 13:03:09 -07005872
5873 udelay(100);
5874
Michael Chane503e062012-12-06 10:33:08 +00005875 BNX2_WR(bp, BNX2_HC_COMMAND,
5876 bp->hc_cmd | BNX2_HC_COMMAND_COAL_NOW_WO_INT);
Michael Chanbf5295b2006-03-23 01:11:56 -08005877
Michael Chane503e062012-12-06 10:33:08 +00005878 BNX2_RD(bp, BNX2_HC_COMMAND);
Michael Chanb6016b72005-05-26 13:03:09 -07005879
5880 udelay(5);
5881
Stanislaw Gruszka36227e82010-07-15 04:25:50 +00005882 dma_unmap_single(&bp->pdev->dev, map, pkt_size, PCI_DMA_TODEVICE);
Michael Chan745720e2006-06-29 12:37:41 -07005883 dev_kfree_skb(skb);
Michael Chanb6016b72005-05-26 13:03:09 -07005884
Michael Chan35e90102008-06-19 16:37:42 -07005885 if (bnx2_get_hw_tx_cons(tx_napi) != txr->tx_prod)
Michael Chanb6016b72005-05-26 13:03:09 -07005886 goto loopback_test_done;
Michael Chanb6016b72005-05-26 13:03:09 -07005887
Michael Chan35efa7c2007-12-20 19:56:37 -08005888 rx_idx = bnx2_get_hw_rx_cons(bnapi);
Michael Chanb6016b72005-05-26 13:03:09 -07005889 if (rx_idx != rx_start_idx + num_pkts) {
5890 goto loopback_test_done;
5891 }
5892
Michael Chanbb4f98a2008-06-19 16:38:19 -07005893 rx_buf = &rxr->rx_buf_ring[rx_start_idx];
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00005894 data = rx_buf->data;
Michael Chanb6016b72005-05-26 13:03:09 -07005895
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00005896 rx_hdr = get_l2_fhdr(data);
5897 data = (u8 *)rx_hdr + BNX2_RX_OFFSET;
Michael Chanb6016b72005-05-26 13:03:09 -07005898
Stanislaw Gruszka36227e82010-07-15 04:25:50 +00005899 dma_sync_single_for_cpu(&bp->pdev->dev,
FUJITA Tomonori1a4ccc22010-04-01 16:56:57 +00005900 dma_unmap_addr(rx_buf, mapping),
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00005901 bp->rx_buf_use_size, PCI_DMA_FROMDEVICE);
Michael Chanb6016b72005-05-26 13:03:09 -07005902
Michael Chanade2bfe2006-01-23 16:09:51 -08005903 if (rx_hdr->l2_fhdr_status &
Michael Chanb6016b72005-05-26 13:03:09 -07005904 (L2_FHDR_ERRORS_BAD_CRC |
5905 L2_FHDR_ERRORS_PHY_DECODE |
5906 L2_FHDR_ERRORS_ALIGNMENT |
5907 L2_FHDR_ERRORS_TOO_SHORT |
5908 L2_FHDR_ERRORS_GIANT_FRAME)) {
5909
5910 goto loopback_test_done;
5911 }
5912
5913 if ((rx_hdr->l2_fhdr_pkt_len - 4) != pkt_size) {
5914 goto loopback_test_done;
5915 }
5916
5917 for (i = 14; i < pkt_size; i++) {
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00005918 if (*(data + i) != (unsigned char) (i & 0xff)) {
Michael Chanb6016b72005-05-26 13:03:09 -07005919 goto loopback_test_done;
5920 }
5921 }
5922
5923 ret = 0;
5924
5925loopback_test_done:
5926 bp->loopback = 0;
5927 return ret;
5928}
5929
Michael Chanbc5a0692006-01-23 16:13:22 -08005930#define BNX2_MAC_LOOPBACK_FAILED 1
5931#define BNX2_PHY_LOOPBACK_FAILED 2
5932#define BNX2_LOOPBACK_FAILED (BNX2_MAC_LOOPBACK_FAILED | \
5933 BNX2_PHY_LOOPBACK_FAILED)
5934
5935static int
5936bnx2_test_loopback(struct bnx2 *bp)
5937{
5938 int rc = 0;
5939
5940 if (!netif_running(bp->dev))
5941 return BNX2_LOOPBACK_FAILED;
5942
5943 bnx2_reset_nic(bp, BNX2_DRV_MSG_CODE_RESET);
5944 spin_lock_bh(&bp->phy_lock);
Michael Chan9a120bc2008-05-16 22:17:45 -07005945 bnx2_init_phy(bp, 1);
Michael Chanbc5a0692006-01-23 16:13:22 -08005946 spin_unlock_bh(&bp->phy_lock);
5947 if (bnx2_run_loopback(bp, BNX2_MAC_LOOPBACK))
5948 rc |= BNX2_MAC_LOOPBACK_FAILED;
5949 if (bnx2_run_loopback(bp, BNX2_PHY_LOOPBACK))
5950 rc |= BNX2_PHY_LOOPBACK_FAILED;
5951 return rc;
5952}
5953
Michael Chanb6016b72005-05-26 13:03:09 -07005954#define NVRAM_SIZE 0x200
5955#define CRC32_RESIDUAL 0xdebb20e3
5956
5957static int
5958bnx2_test_nvram(struct bnx2 *bp)
5959{
Al Virob491edd2007-12-22 19:44:51 +00005960 __be32 buf[NVRAM_SIZE / 4];
Michael Chanb6016b72005-05-26 13:03:09 -07005961 u8 *data = (u8 *) buf;
5962 int rc = 0;
5963 u32 magic, csum;
5964
5965 if ((rc = bnx2_nvram_read(bp, 0, data, 4)) != 0)
5966 goto test_nvram_done;
5967
5968 magic = be32_to_cpu(buf[0]);
5969 if (magic != 0x669955aa) {
5970 rc = -ENODEV;
5971 goto test_nvram_done;
5972 }
5973
5974 if ((rc = bnx2_nvram_read(bp, 0x100, data, NVRAM_SIZE)) != 0)
5975 goto test_nvram_done;
5976
5977 csum = ether_crc_le(0x100, data);
5978 if (csum != CRC32_RESIDUAL) {
5979 rc = -ENODEV;
5980 goto test_nvram_done;
5981 }
5982
5983 csum = ether_crc_le(0x100, data + 0x100);
5984 if (csum != CRC32_RESIDUAL) {
5985 rc = -ENODEV;
5986 }
5987
5988test_nvram_done:
5989 return rc;
5990}
5991
5992static int
5993bnx2_test_link(struct bnx2 *bp)
5994{
5995 u32 bmsr;
5996
Michael Chan9f52b562008-10-09 12:21:46 -07005997 if (!netif_running(bp->dev))
5998 return -ENODEV;
5999
Michael Chan583c28e2008-01-21 19:51:35 -08006000 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP) {
Michael Chan489310a2007-10-10 16:16:31 -07006001 if (bp->link_up)
6002 return 0;
6003 return -ENODEV;
6004 }
Michael Chanc770a652005-08-25 15:38:39 -07006005 spin_lock_bh(&bp->phy_lock);
Michael Chan27a005b2007-05-03 13:23:41 -07006006 bnx2_enable_bmsr1(bp);
6007 bnx2_read_phy(bp, bp->mii_bmsr1, &bmsr);
6008 bnx2_read_phy(bp, bp->mii_bmsr1, &bmsr);
6009 bnx2_disable_bmsr1(bp);
Michael Chanc770a652005-08-25 15:38:39 -07006010 spin_unlock_bh(&bp->phy_lock);
Jeff Garzik6aa20a22006-09-13 13:24:59 -04006011
Michael Chanb6016b72005-05-26 13:03:09 -07006012 if (bmsr & BMSR_LSTATUS) {
6013 return 0;
6014 }
6015 return -ENODEV;
6016}
6017
6018static int
6019bnx2_test_intr(struct bnx2 *bp)
6020{
6021 int i;
Michael Chanb6016b72005-05-26 13:03:09 -07006022 u16 status_idx;
6023
6024 if (!netif_running(bp->dev))
6025 return -ENODEV;
6026
Michael Chane503e062012-12-06 10:33:08 +00006027 status_idx = BNX2_RD(bp, BNX2_PCICFG_INT_ACK_CMD) & 0xffff;
Michael Chanb6016b72005-05-26 13:03:09 -07006028
6029 /* This register is not touched during run-time. */
Michael Chane503e062012-12-06 10:33:08 +00006030 BNX2_WR(bp, BNX2_HC_COMMAND, bp->hc_cmd | BNX2_HC_COMMAND_COAL_NOW);
6031 BNX2_RD(bp, BNX2_HC_COMMAND);
Michael Chanb6016b72005-05-26 13:03:09 -07006032
6033 for (i = 0; i < 10; i++) {
Michael Chane503e062012-12-06 10:33:08 +00006034 if ((BNX2_RD(bp, BNX2_PCICFG_INT_ACK_CMD) & 0xffff) !=
Michael Chanb6016b72005-05-26 13:03:09 -07006035 status_idx) {
6036
6037 break;
6038 }
6039
6040 msleep_interruptible(10);
6041 }
6042 if (i < 10)
6043 return 0;
6044
6045 return -ENODEV;
6046}
6047
Michael Chan38ea3682008-02-23 19:48:57 -08006048/* Determining link for parallel detection. */
Michael Chanb2fadea2008-01-21 17:07:06 -08006049static int
6050bnx2_5706_serdes_has_link(struct bnx2 *bp)
6051{
6052 u32 mode_ctl, an_dbg, exp;
6053
Michael Chan38ea3682008-02-23 19:48:57 -08006054 if (bp->phy_flags & BNX2_PHY_FLAG_NO_PARALLEL)
6055 return 0;
6056
Michael Chanb2fadea2008-01-21 17:07:06 -08006057 bnx2_write_phy(bp, MII_BNX2_MISC_SHADOW, MISC_SHDW_MODE_CTL);
6058 bnx2_read_phy(bp, MII_BNX2_MISC_SHADOW, &mode_ctl);
6059
6060 if (!(mode_ctl & MISC_SHDW_MODE_CTL_SIG_DET))
6061 return 0;
6062
6063 bnx2_write_phy(bp, MII_BNX2_MISC_SHADOW, MISC_SHDW_AN_DBG);
6064 bnx2_read_phy(bp, MII_BNX2_MISC_SHADOW, &an_dbg);
6065 bnx2_read_phy(bp, MII_BNX2_MISC_SHADOW, &an_dbg);
6066
Michael Chanf3014c0c2008-01-29 21:33:03 -08006067 if (an_dbg & (MISC_SHDW_AN_DBG_NOSYNC | MISC_SHDW_AN_DBG_RUDI_INVALID))
Michael Chanb2fadea2008-01-21 17:07:06 -08006068 return 0;
6069
6070 bnx2_write_phy(bp, MII_BNX2_DSP_ADDRESS, MII_EXPAND_REG1);
6071 bnx2_read_phy(bp, MII_BNX2_DSP_RW_PORT, &exp);
6072 bnx2_read_phy(bp, MII_BNX2_DSP_RW_PORT, &exp);
6073
6074 if (exp & MII_EXPAND_REG1_RUDI_C) /* receiving CONFIG */
6075 return 0;
6076
6077 return 1;
6078}
6079
Michael Chanb6016b72005-05-26 13:03:09 -07006080static void
Michael Chan48b01e22006-11-19 14:08:00 -08006081bnx2_5706_serdes_timer(struct bnx2 *bp)
6082{
Michael Chanb2fadea2008-01-21 17:07:06 -08006083 int check_link = 1;
6084
Michael Chan48b01e22006-11-19 14:08:00 -08006085 spin_lock(&bp->phy_lock);
Michael Chanb2fadea2008-01-21 17:07:06 -08006086 if (bp->serdes_an_pending) {
Michael Chan48b01e22006-11-19 14:08:00 -08006087 bp->serdes_an_pending--;
Michael Chanb2fadea2008-01-21 17:07:06 -08006088 check_link = 0;
6089 } else if ((bp->link_up == 0) && (bp->autoneg & AUTONEG_SPEED)) {
Michael Chan48b01e22006-11-19 14:08:00 -08006090 u32 bmcr;
6091
Benjamin Liac392ab2008-09-18 16:40:49 -07006092 bp->current_interval = BNX2_TIMER_INTERVAL;
Michael Chan48b01e22006-11-19 14:08:00 -08006093
Michael Chanca58c3a2007-05-03 13:22:52 -07006094 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chan48b01e22006-11-19 14:08:00 -08006095
6096 if (bmcr & BMCR_ANENABLE) {
Michael Chanb2fadea2008-01-21 17:07:06 -08006097 if (bnx2_5706_serdes_has_link(bp)) {
Michael Chan48b01e22006-11-19 14:08:00 -08006098 bmcr &= ~BMCR_ANENABLE;
6099 bmcr |= BMCR_SPEED1000 | BMCR_FULLDPLX;
Michael Chanca58c3a2007-05-03 13:22:52 -07006100 bnx2_write_phy(bp, bp->mii_bmcr, bmcr);
Michael Chan583c28e2008-01-21 19:51:35 -08006101 bp->phy_flags |= BNX2_PHY_FLAG_PARALLEL_DETECT;
Michael Chan48b01e22006-11-19 14:08:00 -08006102 }
6103 }
6104 }
6105 else if ((bp->link_up) && (bp->autoneg & AUTONEG_SPEED) &&
Michael Chan583c28e2008-01-21 19:51:35 -08006106 (bp->phy_flags & BNX2_PHY_FLAG_PARALLEL_DETECT)) {
Michael Chan48b01e22006-11-19 14:08:00 -08006107 u32 phy2;
6108
6109 bnx2_write_phy(bp, 0x17, 0x0f01);
6110 bnx2_read_phy(bp, 0x15, &phy2);
6111 if (phy2 & 0x20) {
6112 u32 bmcr;
6113
Michael Chanca58c3a2007-05-03 13:22:52 -07006114 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chan48b01e22006-11-19 14:08:00 -08006115 bmcr |= BMCR_ANENABLE;
Michael Chanca58c3a2007-05-03 13:22:52 -07006116 bnx2_write_phy(bp, bp->mii_bmcr, bmcr);
Michael Chan48b01e22006-11-19 14:08:00 -08006117
Michael Chan583c28e2008-01-21 19:51:35 -08006118 bp->phy_flags &= ~BNX2_PHY_FLAG_PARALLEL_DETECT;
Michael Chan48b01e22006-11-19 14:08:00 -08006119 }
6120 } else
Benjamin Liac392ab2008-09-18 16:40:49 -07006121 bp->current_interval = BNX2_TIMER_INTERVAL;
Michael Chan48b01e22006-11-19 14:08:00 -08006122
Michael Chana2724e22008-02-23 19:47:44 -08006123 if (check_link) {
Michael Chanb2fadea2008-01-21 17:07:06 -08006124 u32 val;
6125
6126 bnx2_write_phy(bp, MII_BNX2_MISC_SHADOW, MISC_SHDW_AN_DBG);
6127 bnx2_read_phy(bp, MII_BNX2_MISC_SHADOW, &val);
6128 bnx2_read_phy(bp, MII_BNX2_MISC_SHADOW, &val);
6129
Michael Chana2724e22008-02-23 19:47:44 -08006130 if (bp->link_up && (val & MISC_SHDW_AN_DBG_NOSYNC)) {
6131 if (!(bp->phy_flags & BNX2_PHY_FLAG_FORCED_DOWN)) {
6132 bnx2_5706s_force_link_dn(bp, 1);
6133 bp->phy_flags |= BNX2_PHY_FLAG_FORCED_DOWN;
6134 } else
6135 bnx2_set_link(bp);
6136 } else if (!bp->link_up && !(val & MISC_SHDW_AN_DBG_NOSYNC))
6137 bnx2_set_link(bp);
Michael Chanb2fadea2008-01-21 17:07:06 -08006138 }
Michael Chan48b01e22006-11-19 14:08:00 -08006139 spin_unlock(&bp->phy_lock);
6140}
6141
6142static void
Michael Chanf8dd0642006-11-19 14:08:29 -08006143bnx2_5708_serdes_timer(struct bnx2 *bp)
6144{
Michael Chan583c28e2008-01-21 19:51:35 -08006145 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
Michael Chan0d8a6572007-07-07 22:49:43 -07006146 return;
6147
Michael Chan583c28e2008-01-21 19:51:35 -08006148 if ((bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE) == 0) {
Michael Chanf8dd0642006-11-19 14:08:29 -08006149 bp->serdes_an_pending = 0;
6150 return;
6151 }
6152
6153 spin_lock(&bp->phy_lock);
6154 if (bp->serdes_an_pending)
6155 bp->serdes_an_pending--;
6156 else if ((bp->link_up == 0) && (bp->autoneg & AUTONEG_SPEED)) {
6157 u32 bmcr;
6158
Michael Chanca58c3a2007-05-03 13:22:52 -07006159 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chanf8dd0642006-11-19 14:08:29 -08006160 if (bmcr & BMCR_ANENABLE) {
Michael Chan605a9e22007-05-03 13:23:13 -07006161 bnx2_enable_forced_2g5(bp);
Michael Chan40105c02008-11-12 16:02:45 -08006162 bp->current_interval = BNX2_SERDES_FORCED_TIMEOUT;
Michael Chanf8dd0642006-11-19 14:08:29 -08006163 } else {
Michael Chan605a9e22007-05-03 13:23:13 -07006164 bnx2_disable_forced_2g5(bp);
Michael Chanf8dd0642006-11-19 14:08:29 -08006165 bp->serdes_an_pending = 2;
Benjamin Liac392ab2008-09-18 16:40:49 -07006166 bp->current_interval = BNX2_TIMER_INTERVAL;
Michael Chanf8dd0642006-11-19 14:08:29 -08006167 }
6168
6169 } else
Benjamin Liac392ab2008-09-18 16:40:49 -07006170 bp->current_interval = BNX2_TIMER_INTERVAL;
Michael Chanf8dd0642006-11-19 14:08:29 -08006171
6172 spin_unlock(&bp->phy_lock);
6173}
6174
6175static void
Michael Chanb6016b72005-05-26 13:03:09 -07006176bnx2_timer(unsigned long data)
6177{
6178 struct bnx2 *bp = (struct bnx2 *) data;
Michael Chanb6016b72005-05-26 13:03:09 -07006179
Michael Chancd339a02005-08-25 15:35:24 -07006180 if (!netif_running(bp->dev))
6181 return;
6182
Michael Chanb6016b72005-05-26 13:03:09 -07006183 if (atomic_read(&bp->intr_sem) != 0)
6184 goto bnx2_restart_timer;
6185
Michael Chanefba0182008-12-03 00:36:15 -08006186 if ((bp->flags & (BNX2_FLAG_USING_MSI | BNX2_FLAG_ONE_SHOT_MSI)) ==
6187 BNX2_FLAG_USING_MSI)
6188 bnx2_chk_missed_msi(bp);
6189
Michael Chandf149d72007-07-07 22:51:36 -07006190 bnx2_send_heart_beat(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07006191
Michael Chan2726d6e2008-01-29 21:35:05 -08006192 bp->stats_blk->stat_FwRxDrop =
6193 bnx2_reg_rd_ind(bp, BNX2_FW_RX_DROP_COUNT);
Michael Chancea94db2006-06-12 22:16:13 -07006194
Michael Chan02537b062007-06-04 21:24:07 -07006195 /* workaround occasional corrupted counters */
Michael Chan61d9e3f2009-08-21 16:20:46 +00006196 if ((bp->flags & BNX2_FLAG_BROKEN_STATS) && bp->stats_ticks)
Michael Chane503e062012-12-06 10:33:08 +00006197 BNX2_WR(bp, BNX2_HC_COMMAND, bp->hc_cmd |
6198 BNX2_HC_COMMAND_STATS_NOW);
Michael Chan02537b062007-06-04 21:24:07 -07006199
Michael Chan583c28e2008-01-21 19:51:35 -08006200 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Michael Chan4ce45e02012-12-06 10:33:10 +00006201 if (BNX2_CHIP(bp) == BNX2_CHIP_5706)
Michael Chanf8dd0642006-11-19 14:08:29 -08006202 bnx2_5706_serdes_timer(bp);
Michael Chan27a005b2007-05-03 13:23:41 -07006203 else
Michael Chanf8dd0642006-11-19 14:08:29 -08006204 bnx2_5708_serdes_timer(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07006205 }
6206
6207bnx2_restart_timer:
Michael Chancd339a02005-08-25 15:35:24 -07006208 mod_timer(&bp->timer, jiffies + bp->current_interval);
Michael Chanb6016b72005-05-26 13:03:09 -07006209}
6210
Michael Chan8e6a72c2007-05-03 13:24:48 -07006211static int
6212bnx2_request_irq(struct bnx2 *bp)
6213{
Michael Chan6d866ff2007-12-20 19:56:09 -08006214 unsigned long flags;
Michael Chanb4b36042007-12-20 19:59:30 -08006215 struct bnx2_irq *irq;
6216 int rc = 0, i;
Michael Chan8e6a72c2007-05-03 13:24:48 -07006217
David S. Millerf86e82f2008-01-21 17:15:40 -08006218 if (bp->flags & BNX2_FLAG_USING_MSI_OR_MSIX)
Michael Chan6d866ff2007-12-20 19:56:09 -08006219 flags = 0;
6220 else
6221 flags = IRQF_SHARED;
Michael Chanb4b36042007-12-20 19:59:30 -08006222
6223 for (i = 0; i < bp->irq_nvecs; i++) {
6224 irq = &bp->irq_tbl[i];
Michael Chanc76c0472007-12-20 20:01:19 -08006225 rc = request_irq(irq->vector, irq->handler, flags, irq->name,
Michael Chanf0ea2e62008-06-19 16:41:57 -07006226 &bp->bnx2_napi[i]);
Michael Chanb4b36042007-12-20 19:59:30 -08006227 if (rc)
6228 break;
6229 irq->requested = 1;
6230 }
Michael Chan8e6a72c2007-05-03 13:24:48 -07006231 return rc;
6232}
6233
6234static void
Michael Chana29ba9d2010-12-31 11:03:14 -08006235__bnx2_free_irq(struct bnx2 *bp)
Michael Chan8e6a72c2007-05-03 13:24:48 -07006236{
Michael Chanb4b36042007-12-20 19:59:30 -08006237 struct bnx2_irq *irq;
6238 int i;
Michael Chan8e6a72c2007-05-03 13:24:48 -07006239
Michael Chanb4b36042007-12-20 19:59:30 -08006240 for (i = 0; i < bp->irq_nvecs; i++) {
6241 irq = &bp->irq_tbl[i];
6242 if (irq->requested)
Michael Chanf0ea2e62008-06-19 16:41:57 -07006243 free_irq(irq->vector, &bp->bnx2_napi[i]);
Michael Chanb4b36042007-12-20 19:59:30 -08006244 irq->requested = 0;
Michael Chan6d866ff2007-12-20 19:56:09 -08006245 }
Michael Chana29ba9d2010-12-31 11:03:14 -08006246}
6247
6248static void
6249bnx2_free_irq(struct bnx2 *bp)
6250{
6251
6252 __bnx2_free_irq(bp);
David S. Millerf86e82f2008-01-21 17:15:40 -08006253 if (bp->flags & BNX2_FLAG_USING_MSI)
Michael Chanb4b36042007-12-20 19:59:30 -08006254 pci_disable_msi(bp->pdev);
David S. Millerf86e82f2008-01-21 17:15:40 -08006255 else if (bp->flags & BNX2_FLAG_USING_MSIX)
Michael Chanb4b36042007-12-20 19:59:30 -08006256 pci_disable_msix(bp->pdev);
6257
David S. Millerf86e82f2008-01-21 17:15:40 -08006258 bp->flags &= ~(BNX2_FLAG_USING_MSI_OR_MSIX | BNX2_FLAG_ONE_SHOT_MSI);
Michael Chanb4b36042007-12-20 19:59:30 -08006259}
6260
6261static void
Michael Chan5e9ad9e2008-06-19 16:43:17 -07006262bnx2_enable_msix(struct bnx2 *bp, int msix_vecs)
Michael Chanb4b36042007-12-20 19:59:30 -08006263{
Alexander Gordeevf2a2dfe2014-02-18 11:07:53 +01006264 int i, total_vecs;
Michael Chan57851d82007-12-20 20:01:44 -08006265 struct msix_entry msix_ent[BNX2_MAX_MSIX_VEC];
Michael Chan4e1d0de2008-12-16 20:27:45 -08006266 struct net_device *dev = bp->dev;
6267 const int len = sizeof(bp->irq_tbl[0].name);
Michael Chan57851d82007-12-20 20:01:44 -08006268
Michael Chanb4b36042007-12-20 19:59:30 -08006269 bnx2_setup_msix_tbl(bp);
Michael Chane503e062012-12-06 10:33:08 +00006270 BNX2_WR(bp, BNX2_PCI_MSIX_CONTROL, BNX2_MAX_MSIX_HW_VEC - 1);
6271 BNX2_WR(bp, BNX2_PCI_MSIX_TBL_OFF_BIR, BNX2_PCI_GRC_WINDOW2_BASE);
6272 BNX2_WR(bp, BNX2_PCI_MSIX_PBA_OFF_BIT, BNX2_PCI_GRC_WINDOW3_BASE);
Michael Chan57851d82007-12-20 20:01:44 -08006273
Benjamin Lie2eb8e32010-01-08 00:51:21 -08006274 /* Need to flush the previous three writes to ensure MSI-X
6275 * is setup properly */
Michael Chane503e062012-12-06 10:33:08 +00006276 BNX2_RD(bp, BNX2_PCI_MSIX_CONTROL);
Benjamin Lie2eb8e32010-01-08 00:51:21 -08006277
Michael Chan57851d82007-12-20 20:01:44 -08006278 for (i = 0; i < BNX2_MAX_MSIX_VEC; i++) {
6279 msix_ent[i].entry = i;
6280 msix_ent[i].vector = 0;
6281 }
6282
Michael Chan379b39a2010-07-19 14:15:03 +00006283 total_vecs = msix_vecs;
6284#ifdef BCM_CNIC
6285 total_vecs++;
6286#endif
Alexander Gordeevf2a2dfe2014-02-18 11:07:53 +01006287 total_vecs = pci_enable_msix_range(bp->pdev, msix_ent,
6288 BNX2_MIN_MSIX_VEC, total_vecs);
6289 if (total_vecs < 0)
Michael Chan57851d82007-12-20 20:01:44 -08006290 return;
6291
Michael Chan379b39a2010-07-19 14:15:03 +00006292 msix_vecs = total_vecs;
6293#ifdef BCM_CNIC
6294 msix_vecs--;
6295#endif
Michael Chan5e9ad9e2008-06-19 16:43:17 -07006296 bp->irq_nvecs = msix_vecs;
David S. Millerf86e82f2008-01-21 17:15:40 -08006297 bp->flags |= BNX2_FLAG_USING_MSIX | BNX2_FLAG_ONE_SHOT_MSI;
Michael Chan379b39a2010-07-19 14:15:03 +00006298 for (i = 0; i < total_vecs; i++) {
Michael Chan57851d82007-12-20 20:01:44 -08006299 bp->irq_tbl[i].vector = msix_ent[i].vector;
Michael Chan69010312009-03-18 18:11:51 -07006300 snprintf(bp->irq_tbl[i].name, len, "%s-%d", dev->name, i);
6301 bp->irq_tbl[i].handler = bnx2_msi_1shot;
6302 }
Michael Chan6d866ff2007-12-20 19:56:09 -08006303}
6304
Ben Hutchings657d92f2010-09-27 08:25:16 +00006305static int
Michael Chan6d866ff2007-12-20 19:56:09 -08006306bnx2_setup_int_mode(struct bnx2 *bp, int dis_msi)
6307{
Yuval Mintz0a742122012-07-01 03:18:58 +00006308 int cpus = netif_get_num_default_rss_queues();
Michael Chanb0332812012-02-05 15:24:38 +00006309 int msix_vecs;
6310
6311 if (!bp->num_req_rx_rings)
6312 msix_vecs = max(cpus + 1, bp->num_req_tx_rings);
6313 else if (!bp->num_req_tx_rings)
6314 msix_vecs = max(cpus, bp->num_req_rx_rings);
6315 else
6316 msix_vecs = max(bp->num_req_rx_rings, bp->num_req_tx_rings);
6317
6318 msix_vecs = min(msix_vecs, RX_MAX_RINGS);
Michael Chan5e9ad9e2008-06-19 16:43:17 -07006319
Michael Chan6d866ff2007-12-20 19:56:09 -08006320 bp->irq_tbl[0].handler = bnx2_interrupt;
6321 strcpy(bp->irq_tbl[0].name, bp->dev->name);
Michael Chanb4b36042007-12-20 19:59:30 -08006322 bp->irq_nvecs = 1;
6323 bp->irq_tbl[0].vector = bp->pdev->irq;
Michael Chan6d866ff2007-12-20 19:56:09 -08006324
Michael Chan3d5f3a72010-07-03 20:42:15 +00006325 if ((bp->flags & BNX2_FLAG_MSIX_CAP) && !dis_msi)
Michael Chan5e9ad9e2008-06-19 16:43:17 -07006326 bnx2_enable_msix(bp, msix_vecs);
Michael Chanb4b36042007-12-20 19:59:30 -08006327
David S. Millerf86e82f2008-01-21 17:15:40 -08006328 if ((bp->flags & BNX2_FLAG_MSI_CAP) && !dis_msi &&
6329 !(bp->flags & BNX2_FLAG_USING_MSIX)) {
Michael Chan6d866ff2007-12-20 19:56:09 -08006330 if (pci_enable_msi(bp->pdev) == 0) {
David S. Millerf86e82f2008-01-21 17:15:40 -08006331 bp->flags |= BNX2_FLAG_USING_MSI;
Michael Chan4ce45e02012-12-06 10:33:10 +00006332 if (BNX2_CHIP(bp) == BNX2_CHIP_5709) {
David S. Millerf86e82f2008-01-21 17:15:40 -08006333 bp->flags |= BNX2_FLAG_ONE_SHOT_MSI;
Michael Chan6d866ff2007-12-20 19:56:09 -08006334 bp->irq_tbl[0].handler = bnx2_msi_1shot;
6335 } else
6336 bp->irq_tbl[0].handler = bnx2_msi;
Michael Chanb4b36042007-12-20 19:59:30 -08006337
6338 bp->irq_tbl[0].vector = bp->pdev->irq;
Michael Chan6d866ff2007-12-20 19:56:09 -08006339 }
6340 }
Benjamin Li706bf242008-07-18 17:55:11 -07006341
Michael Chanb0332812012-02-05 15:24:38 +00006342 if (!bp->num_req_tx_rings)
6343 bp->num_tx_rings = rounddown_pow_of_two(bp->irq_nvecs);
6344 else
6345 bp->num_tx_rings = min(bp->irq_nvecs, bp->num_req_tx_rings);
6346
6347 if (!bp->num_req_rx_rings)
6348 bp->num_rx_rings = bp->irq_nvecs;
6349 else
6350 bp->num_rx_rings = min(bp->irq_nvecs, bp->num_req_rx_rings);
6351
Ben Hutchings657d92f2010-09-27 08:25:16 +00006352 netif_set_real_num_tx_queues(bp->dev, bp->num_tx_rings);
Benjamin Li706bf242008-07-18 17:55:11 -07006353
Ben Hutchings657d92f2010-09-27 08:25:16 +00006354 return netif_set_real_num_rx_queues(bp->dev, bp->num_rx_rings);
Michael Chan8e6a72c2007-05-03 13:24:48 -07006355}
6356
Michael Chanb6016b72005-05-26 13:03:09 -07006357/* Called with rtnl_lock */
6358static int
6359bnx2_open(struct net_device *dev)
6360{
Michael Chan972ec0d2006-01-23 16:12:43 -08006361 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006362 int rc;
6363
Baoquan He5d0d4b92016-11-13 13:01:32 +08006364 rc = bnx2_request_firmware(bp);
6365 if (rc < 0)
6366 goto out;
6367
Michael Chan1b2f9222007-05-03 13:20:19 -07006368 netif_carrier_off(dev);
6369
Michael Chanb6016b72005-05-26 13:03:09 -07006370 bnx2_disable_int(bp);
6371
Ben Hutchings657d92f2010-09-27 08:25:16 +00006372 rc = bnx2_setup_int_mode(bp, disable_msi);
6373 if (rc)
6374 goto open_err;
Benjamin Li4327ba42010-03-23 13:13:11 +00006375 bnx2_init_napi(bp);
Michael Chan35efa7c2007-12-20 19:56:37 -08006376 bnx2_napi_enable(bp);
Michael Chan35e90102008-06-19 16:37:42 -07006377 rc = bnx2_alloc_mem(bp);
Michael Chan2739a8b2008-06-19 16:44:10 -07006378 if (rc)
6379 goto open_err;
Michael Chan35e90102008-06-19 16:37:42 -07006380
Michael Chan8e6a72c2007-05-03 13:24:48 -07006381 rc = bnx2_request_irq(bp);
Michael Chan2739a8b2008-06-19 16:44:10 -07006382 if (rc)
6383 goto open_err;
Michael Chanb6016b72005-05-26 13:03:09 -07006384
Michael Chan9a120bc2008-05-16 22:17:45 -07006385 rc = bnx2_init_nic(bp, 1);
Michael Chan2739a8b2008-06-19 16:44:10 -07006386 if (rc)
6387 goto open_err;
Jeff Garzik6aa20a22006-09-13 13:24:59 -04006388
Michael Chancd339a02005-08-25 15:35:24 -07006389 mod_timer(&bp->timer, jiffies + bp->current_interval);
Michael Chanb6016b72005-05-26 13:03:09 -07006390
6391 atomic_set(&bp->intr_sem, 0);
6392
Michael Chan354fcd72010-01-17 07:30:44 +00006393 memset(bp->temp_stats_blk, 0, sizeof(struct statistics_block));
6394
Michael Chanb6016b72005-05-26 13:03:09 -07006395 bnx2_enable_int(bp);
6396
David S. Millerf86e82f2008-01-21 17:15:40 -08006397 if (bp->flags & BNX2_FLAG_USING_MSI) {
Michael Chanb6016b72005-05-26 13:03:09 -07006398 /* Test MSI to make sure it is working
6399 * If MSI test fails, go back to INTx mode
6400 */
6401 if (bnx2_test_intr(bp) != 0) {
Joe Perches3a9c6a42010-02-17 15:01:51 +00006402 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 -07006403
6404 bnx2_disable_int(bp);
Michael Chan8e6a72c2007-05-03 13:24:48 -07006405 bnx2_free_irq(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07006406
Michael Chan6d866ff2007-12-20 19:56:09 -08006407 bnx2_setup_int_mode(bp, 1);
6408
Michael Chan9a120bc2008-05-16 22:17:45 -07006409 rc = bnx2_init_nic(bp, 0);
Michael Chanb6016b72005-05-26 13:03:09 -07006410
Michael Chan8e6a72c2007-05-03 13:24:48 -07006411 if (!rc)
6412 rc = bnx2_request_irq(bp);
6413
Michael Chanb6016b72005-05-26 13:03:09 -07006414 if (rc) {
Michael Chanb6016b72005-05-26 13:03:09 -07006415 del_timer_sync(&bp->timer);
Michael Chan2739a8b2008-06-19 16:44:10 -07006416 goto open_err;
Michael Chanb6016b72005-05-26 13:03:09 -07006417 }
6418 bnx2_enable_int(bp);
6419 }
6420 }
David S. Millerf86e82f2008-01-21 17:15:40 -08006421 if (bp->flags & BNX2_FLAG_USING_MSI)
Joe Perches3a9c6a42010-02-17 15:01:51 +00006422 netdev_info(dev, "using MSI\n");
David S. Millerf86e82f2008-01-21 17:15:40 -08006423 else if (bp->flags & BNX2_FLAG_USING_MSIX)
Joe Perches3a9c6a42010-02-17 15:01:51 +00006424 netdev_info(dev, "using MSIX\n");
Michael Chanb6016b72005-05-26 13:03:09 -07006425
Benjamin Li706bf242008-07-18 17:55:11 -07006426 netif_tx_start_all_queues(dev);
françois romieu7880b722011-09-30 00:36:52 +00006427out:
6428 return rc;
Michael Chan2739a8b2008-06-19 16:44:10 -07006429
6430open_err:
6431 bnx2_napi_disable(bp);
6432 bnx2_free_skbs(bp);
6433 bnx2_free_irq(bp);
6434 bnx2_free_mem(bp);
Michael Chanf048fa92010-06-01 15:05:36 +00006435 bnx2_del_napi(bp);
Baoquan He5d0d4b92016-11-13 13:01:32 +08006436 bnx2_release_firmware(bp);
françois romieu7880b722011-09-30 00:36:52 +00006437 goto out;
Michael Chanb6016b72005-05-26 13:03:09 -07006438}
6439
6440static void
David Howellsc4028952006-11-22 14:57:56 +00006441bnx2_reset_task(struct work_struct *work)
Michael Chanb6016b72005-05-26 13:03:09 -07006442{
David Howellsc4028952006-11-22 14:57:56 +00006443 struct bnx2 *bp = container_of(work, struct bnx2, reset_task);
Michael Chancd634012011-07-15 06:53:58 +00006444 int rc;
Michael Chanefdfad32012-07-16 14:25:56 +00006445 u16 pcicmd;
Michael Chanb6016b72005-05-26 13:03:09 -07006446
Michael Chan51bf6bb2009-12-03 09:46:31 +00006447 rtnl_lock();
6448 if (!netif_running(bp->dev)) {
6449 rtnl_unlock();
Michael Chanafdc08b2005-08-25 15:34:29 -07006450 return;
Michael Chan51bf6bb2009-12-03 09:46:31 +00006451 }
Michael Chanafdc08b2005-08-25 15:34:29 -07006452
Michael Chan212f9932010-04-27 11:28:10 +00006453 bnx2_netif_stop(bp, true);
Michael Chanb6016b72005-05-26 13:03:09 -07006454
Michael Chanefdfad32012-07-16 14:25:56 +00006455 pci_read_config_word(bp->pdev, PCI_COMMAND, &pcicmd);
6456 if (!(pcicmd & PCI_COMMAND_MEMORY)) {
6457 /* in case PCI block has reset */
6458 pci_restore_state(bp->pdev);
6459 pci_save_state(bp->pdev);
6460 }
Michael Chancd634012011-07-15 06:53:58 +00006461 rc = bnx2_init_nic(bp, 1);
6462 if (rc) {
6463 netdev_err(bp->dev, "failed to reset NIC, closing\n");
6464 bnx2_napi_enable(bp);
6465 dev_close(bp->dev);
6466 rtnl_unlock();
6467 return;
6468 }
Michael Chanb6016b72005-05-26 13:03:09 -07006469
6470 atomic_set(&bp->intr_sem, 1);
Michael Chan212f9932010-04-27 11:28:10 +00006471 bnx2_netif_start(bp, true);
Michael Chan51bf6bb2009-12-03 09:46:31 +00006472 rtnl_unlock();
Michael Chanb6016b72005-05-26 13:03:09 -07006473}
6474
Michael Chan555069d2012-06-16 15:45:41 +00006475#define BNX2_FTQ_ENTRY(ftq) { __stringify(ftq##FTQ_CTL), BNX2_##ftq##FTQ_CTL }
6476
6477static void
6478bnx2_dump_ftq(struct bnx2 *bp)
6479{
6480 int i;
6481 u32 reg, bdidx, cid, valid;
6482 struct net_device *dev = bp->dev;
6483 static const struct ftq_reg {
6484 char *name;
6485 u32 off;
6486 } ftq_arr[] = {
6487 BNX2_FTQ_ENTRY(RV2P_P),
6488 BNX2_FTQ_ENTRY(RV2P_T),
6489 BNX2_FTQ_ENTRY(RV2P_M),
6490 BNX2_FTQ_ENTRY(TBDR_),
6491 BNX2_FTQ_ENTRY(TDMA_),
6492 BNX2_FTQ_ENTRY(TXP_),
6493 BNX2_FTQ_ENTRY(TXP_),
6494 BNX2_FTQ_ENTRY(TPAT_),
6495 BNX2_FTQ_ENTRY(RXP_C),
6496 BNX2_FTQ_ENTRY(RXP_),
6497 BNX2_FTQ_ENTRY(COM_COMXQ_),
6498 BNX2_FTQ_ENTRY(COM_COMTQ_),
6499 BNX2_FTQ_ENTRY(COM_COMQ_),
6500 BNX2_FTQ_ENTRY(CP_CPQ_),
6501 };
6502
6503 netdev_err(dev, "<--- start FTQ dump --->\n");
6504 for (i = 0; i < ARRAY_SIZE(ftq_arr); i++)
6505 netdev_err(dev, "%s %08x\n", ftq_arr[i].name,
6506 bnx2_reg_rd_ind(bp, ftq_arr[i].off));
6507
6508 netdev_err(dev, "CPU states:\n");
6509 for (reg = BNX2_TXP_CPU_MODE; reg <= BNX2_CP_CPU_MODE; reg += 0x40000)
6510 netdev_err(dev, "%06x mode %x state %x evt_mask %x pc %x pc %x instr %x\n",
6511 reg, bnx2_reg_rd_ind(bp, reg),
6512 bnx2_reg_rd_ind(bp, reg + 4),
6513 bnx2_reg_rd_ind(bp, reg + 8),
6514 bnx2_reg_rd_ind(bp, reg + 0x1c),
6515 bnx2_reg_rd_ind(bp, reg + 0x1c),
6516 bnx2_reg_rd_ind(bp, reg + 0x20));
6517
6518 netdev_err(dev, "<--- end FTQ dump --->\n");
6519 netdev_err(dev, "<--- start TBDC dump --->\n");
6520 netdev_err(dev, "TBDC free cnt: %ld\n",
Michael Chane503e062012-12-06 10:33:08 +00006521 BNX2_RD(bp, BNX2_TBDC_STATUS) & BNX2_TBDC_STATUS_FREE_CNT);
Michael Chan555069d2012-06-16 15:45:41 +00006522 netdev_err(dev, "LINE CID BIDX CMD VALIDS\n");
6523 for (i = 0; i < 0x20; i++) {
6524 int j = 0;
6525
Michael Chane503e062012-12-06 10:33:08 +00006526 BNX2_WR(bp, BNX2_TBDC_BD_ADDR, i);
6527 BNX2_WR(bp, BNX2_TBDC_CAM_OPCODE,
6528 BNX2_TBDC_CAM_OPCODE_OPCODE_CAM_READ);
6529 BNX2_WR(bp, BNX2_TBDC_COMMAND, BNX2_TBDC_COMMAND_CMD_REG_ARB);
6530 while ((BNX2_RD(bp, BNX2_TBDC_COMMAND) &
Michael Chan555069d2012-06-16 15:45:41 +00006531 BNX2_TBDC_COMMAND_CMD_REG_ARB) && j < 100)
6532 j++;
6533
Michael Chane503e062012-12-06 10:33:08 +00006534 cid = BNX2_RD(bp, BNX2_TBDC_CID);
6535 bdidx = BNX2_RD(bp, BNX2_TBDC_BIDX);
6536 valid = BNX2_RD(bp, BNX2_TBDC_CAM_OPCODE);
Michael Chan555069d2012-06-16 15:45:41 +00006537 netdev_err(dev, "%02x %06x %04lx %02x [%x]\n",
6538 i, cid, bdidx & BNX2_TBDC_BDIDX_BDIDX,
6539 bdidx >> 24, (valid >> 8) & 0x0ff);
6540 }
6541 netdev_err(dev, "<--- end TBDC dump --->\n");
6542}
6543
Michael Chanb6016b72005-05-26 13:03:09 -07006544static void
Michael Chan20175c52009-12-03 09:46:32 +00006545bnx2_dump_state(struct bnx2 *bp)
6546{
6547 struct net_device *dev = bp->dev;
Jeffrey Huangecdbf6e2011-07-13 17:24:21 +00006548 u32 val1, val2;
Michael Chan20175c52009-12-03 09:46:32 +00006549
Michael Chan5804a8f2010-07-03 20:42:17 +00006550 pci_read_config_dword(bp->pdev, PCI_COMMAND, &val1);
6551 netdev_err(dev, "DEBUG: intr_sem[%x] PCI_CMD[%08x]\n",
6552 atomic_read(&bp->intr_sem), val1);
6553 pci_read_config_dword(bp->pdev, bp->pm_cap + PCI_PM_CTRL, &val1);
6554 pci_read_config_dword(bp->pdev, BNX2_PCICFG_MISC_CONFIG, &val2);
6555 netdev_err(dev, "DEBUG: PCI_PM[%08x] PCI_MISC_CFG[%08x]\n", val1, val2);
Eddie Waib98eba52010-05-17 17:32:56 -07006556 netdev_err(dev, "DEBUG: EMAC_TX_STATUS[%08x] EMAC_RX_STATUS[%08x]\n",
Michael Chane503e062012-12-06 10:33:08 +00006557 BNX2_RD(bp, BNX2_EMAC_TX_STATUS),
6558 BNX2_RD(bp, BNX2_EMAC_RX_STATUS));
Eddie Waib98eba52010-05-17 17:32:56 -07006559 netdev_err(dev, "DEBUG: RPM_MGMT_PKT_CTRL[%08x]\n",
Michael Chane503e062012-12-06 10:33:08 +00006560 BNX2_RD(bp, BNX2_RPM_MGMT_PKT_CTRL));
Joe Perches3a9c6a42010-02-17 15:01:51 +00006561 netdev_err(dev, "DEBUG: HC_STATS_INTERRUPT_STATUS[%08x]\n",
Michael Chane503e062012-12-06 10:33:08 +00006562 BNX2_RD(bp, BNX2_HC_STATS_INTERRUPT_STATUS));
Michael Chan20175c52009-12-03 09:46:32 +00006563 if (bp->flags & BNX2_FLAG_USING_MSIX)
Joe Perches3a9c6a42010-02-17 15:01:51 +00006564 netdev_err(dev, "DEBUG: PBA[%08x]\n",
Michael Chane503e062012-12-06 10:33:08 +00006565 BNX2_RD(bp, BNX2_PCI_GRC_WINDOW3_BASE));
Michael Chan20175c52009-12-03 09:46:32 +00006566}
6567
6568static void
Michael Chanb6016b72005-05-26 13:03:09 -07006569bnx2_tx_timeout(struct net_device *dev)
6570{
Michael Chan972ec0d2006-01-23 16:12:43 -08006571 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006572
Michael Chan555069d2012-06-16 15:45:41 +00006573 bnx2_dump_ftq(bp);
Michael Chan20175c52009-12-03 09:46:32 +00006574 bnx2_dump_state(bp);
Jeffrey Huangecdbf6e2011-07-13 17:24:21 +00006575 bnx2_dump_mcp_state(bp);
Michael Chan20175c52009-12-03 09:46:32 +00006576
Michael Chanb6016b72005-05-26 13:03:09 -07006577 /* This allows the netif to be shutdown gracefully before resetting */
6578 schedule_work(&bp->reset_task);
6579}
6580
Herbert Xu932ff272006-06-09 12:20:56 -07006581/* Called with netif_tx_lock.
Michael Chan2f8af122006-08-15 01:39:10 -07006582 * bnx2_tx_int() runs without netif_tx_lock unless it needs to call
6583 * netif_wake_queue().
Michael Chanb6016b72005-05-26 13:03:09 -07006584 */
Stephen Hemminger613573252009-08-31 19:50:58 +00006585static netdev_tx_t
Michael Chanb6016b72005-05-26 13:03:09 -07006586bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev)
6587{
Michael Chan972ec0d2006-01-23 16:12:43 -08006588 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006589 dma_addr_t mapping;
Michael Chan2bc40782012-12-06 10:33:09 +00006590 struct bnx2_tx_bd *txbd;
6591 struct bnx2_sw_tx_bd *tx_buf;
Michael Chanb6016b72005-05-26 13:03:09 -07006592 u32 len, vlan_tag_flags, last_frag, mss;
6593 u16 prod, ring_prod;
6594 int i;
Benjamin Li706bf242008-07-18 17:55:11 -07006595 struct bnx2_napi *bnapi;
6596 struct bnx2_tx_ring_info *txr;
6597 struct netdev_queue *txq;
6598
6599 /* Determine which tx ring we will be placed on */
6600 i = skb_get_queue_mapping(skb);
6601 bnapi = &bp->bnx2_napi[i];
6602 txr = &bnapi->tx_ring;
6603 txq = netdev_get_tx_queue(dev, i);
Michael Chanb6016b72005-05-26 13:03:09 -07006604
Michael Chan35e90102008-06-19 16:37:42 -07006605 if (unlikely(bnx2_tx_avail(bp, txr) <
Michael Chana550c992007-12-20 19:56:59 -08006606 (skb_shinfo(skb)->nr_frags + 1))) {
Benjamin Li706bf242008-07-18 17:55:11 -07006607 netif_tx_stop_queue(txq);
Joe Perches3a9c6a42010-02-17 15:01:51 +00006608 netdev_err(dev, "BUG! Tx ring full when queue awake!\n");
Michael Chanb6016b72005-05-26 13:03:09 -07006609
6610 return NETDEV_TX_BUSY;
6611 }
6612 len = skb_headlen(skb);
Michael Chan35e90102008-06-19 16:37:42 -07006613 prod = txr->tx_prod;
Michael Chan2bc40782012-12-06 10:33:09 +00006614 ring_prod = BNX2_TX_RING_IDX(prod);
Michael Chanb6016b72005-05-26 13:03:09 -07006615
6616 vlan_tag_flags = 0;
Patrick McHardy84fa7932006-08-29 16:44:56 -07006617 if (skb->ip_summed == CHECKSUM_PARTIAL) {
Michael Chanb6016b72005-05-26 13:03:09 -07006618 vlan_tag_flags |= TX_BD_FLAGS_TCP_UDP_CKSUM;
6619 }
6620
Jiri Pirkodf8a39d2015-01-13 17:13:44 +01006621 if (skb_vlan_tag_present(skb)) {
Michael Chanb6016b72005-05-26 13:03:09 -07006622 vlan_tag_flags |=
Jiri Pirkodf8a39d2015-01-13 17:13:44 +01006623 (TX_BD_FLAGS_VLAN_TAG | (skb_vlan_tag_get(skb) << 16));
Michael Chanb6016b72005-05-26 13:03:09 -07006624 }
Jesse Gross7d0fd212010-10-20 13:56:09 +00006625
Michael Chanfde82052007-05-03 17:23:35 -07006626 if ((mss = skb_shinfo(skb)->gso_size)) {
Michael Chana1efb4b2008-10-09 12:24:39 -07006627 u32 tcp_opt_len;
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -07006628 struct iphdr *iph;
Michael Chanb6016b72005-05-26 13:03:09 -07006629
Michael Chanb6016b72005-05-26 13:03:09 -07006630 vlan_tag_flags |= TX_BD_FLAGS_SW_LSO;
6631
Michael Chan4666f872007-05-03 13:22:28 -07006632 tcp_opt_len = tcp_optlen(skb);
Arnaldo Carvalho de Meloab6a5bb2007-03-18 17:43:48 -07006633
Michael Chan4666f872007-05-03 13:22:28 -07006634 if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6) {
6635 u32 tcp_off = skb_transport_offset(skb) -
6636 sizeof(struct ipv6hdr) - ETH_HLEN;
Michael Chanb6016b72005-05-26 13:03:09 -07006637
Michael Chan4666f872007-05-03 13:22:28 -07006638 vlan_tag_flags |= ((tcp_opt_len >> 2) << 8) |
6639 TX_BD_FLAGS_SW_FLAGS;
6640 if (likely(tcp_off == 0))
6641 vlan_tag_flags &= ~TX_BD_FLAGS_TCP6_OFF0_MSK;
6642 else {
6643 tcp_off >>= 3;
6644 vlan_tag_flags |= ((tcp_off & 0x3) <<
6645 TX_BD_FLAGS_TCP6_OFF0_SHL) |
6646 ((tcp_off & 0x10) <<
6647 TX_BD_FLAGS_TCP6_OFF4_SHL);
6648 mss |= (tcp_off & 0xc) << TX_BD_TCP6_OFF2_SHL;
6649 }
6650 } else {
Michael Chan4666f872007-05-03 13:22:28 -07006651 iph = ip_hdr(skb);
Michael Chan4666f872007-05-03 13:22:28 -07006652 if (tcp_opt_len || (iph->ihl > 5)) {
6653 vlan_tag_flags |= ((iph->ihl - 5) +
6654 (tcp_opt_len >> 2)) << 8;
6655 }
Michael Chanb6016b72005-05-26 13:03:09 -07006656 }
Michael Chan4666f872007-05-03 13:22:28 -07006657 } else
Michael Chanb6016b72005-05-26 13:03:09 -07006658 mss = 0;
Michael Chanb6016b72005-05-26 13:03:09 -07006659
Stanislaw Gruszka36227e82010-07-15 04:25:50 +00006660 mapping = dma_map_single(&bp->pdev->dev, skb->data, len, PCI_DMA_TODEVICE);
6661 if (dma_mapping_error(&bp->pdev->dev, mapping)) {
Eric W. Biedermanf458b2e2014-03-11 14:17:41 -07006662 dev_kfree_skb_any(skb);
Benjamin Li3d16af82008-10-09 12:26:41 -07006663 return NETDEV_TX_OK;
6664 }
6665
Michael Chan35e90102008-06-19 16:37:42 -07006666 tx_buf = &txr->tx_buf_ring[ring_prod];
Michael Chanb6016b72005-05-26 13:03:09 -07006667 tx_buf->skb = skb;
FUJITA Tomonori1a4ccc22010-04-01 16:56:57 +00006668 dma_unmap_addr_set(tx_buf, mapping, mapping);
Michael Chanb6016b72005-05-26 13:03:09 -07006669
Michael Chan35e90102008-06-19 16:37:42 -07006670 txbd = &txr->tx_desc_ring[ring_prod];
Michael Chanb6016b72005-05-26 13:03:09 -07006671
6672 txbd->tx_bd_haddr_hi = (u64) mapping >> 32;
6673 txbd->tx_bd_haddr_lo = (u64) mapping & 0xffffffff;
6674 txbd->tx_bd_mss_nbytes = len | (mss << 16);
6675 txbd->tx_bd_vlan_tag_flags = vlan_tag_flags | TX_BD_FLAGS_START;
6676
6677 last_frag = skb_shinfo(skb)->nr_frags;
Eric Dumazetd62fda02009-05-12 20:48:02 +00006678 tx_buf->nr_frags = last_frag;
6679 tx_buf->is_gso = skb_is_gso(skb);
Michael Chanb6016b72005-05-26 13:03:09 -07006680
6681 for (i = 0; i < last_frag; i++) {
Eric Dumazet9e903e02011-10-18 21:00:24 +00006682 const skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
Michael Chanb6016b72005-05-26 13:03:09 -07006683
Michael Chan2bc40782012-12-06 10:33:09 +00006684 prod = BNX2_NEXT_TX_BD(prod);
6685 ring_prod = BNX2_TX_RING_IDX(prod);
Michael Chan35e90102008-06-19 16:37:42 -07006686 txbd = &txr->tx_desc_ring[ring_prod];
Michael Chanb6016b72005-05-26 13:03:09 -07006687
Eric Dumazet9e903e02011-10-18 21:00:24 +00006688 len = skb_frag_size(frag);
Ian Campbellb7b6a682011-08-24 22:28:12 +00006689 mapping = skb_frag_dma_map(&bp->pdev->dev, frag, 0, len,
Ian Campbell5d6bcdf2011-10-06 11:10:48 +01006690 DMA_TO_DEVICE);
Stanislaw Gruszka36227e82010-07-15 04:25:50 +00006691 if (dma_mapping_error(&bp->pdev->dev, mapping))
Alexander Duycke95524a2009-12-02 16:47:57 +00006692 goto dma_error;
FUJITA Tomonori1a4ccc22010-04-01 16:56:57 +00006693 dma_unmap_addr_set(&txr->tx_buf_ring[ring_prod], mapping,
Alexander Duycke95524a2009-12-02 16:47:57 +00006694 mapping);
Michael Chanb6016b72005-05-26 13:03:09 -07006695
6696 txbd->tx_bd_haddr_hi = (u64) mapping >> 32;
6697 txbd->tx_bd_haddr_lo = (u64) mapping & 0xffffffff;
6698 txbd->tx_bd_mss_nbytes = len | (mss << 16);
6699 txbd->tx_bd_vlan_tag_flags = vlan_tag_flags;
6700
6701 }
6702 txbd->tx_bd_vlan_tag_flags |= TX_BD_FLAGS_END;
6703
Vlad Zolotarov94bf91b2012-02-05 15:24:39 +00006704 /* Sync BD data before updating TX mailbox */
6705 wmb();
6706
Eric Dumazete9831902011-11-29 11:53:05 +00006707 netdev_tx_sent_queue(txq, skb->len);
6708
Michael Chan2bc40782012-12-06 10:33:09 +00006709 prod = BNX2_NEXT_TX_BD(prod);
Michael Chan35e90102008-06-19 16:37:42 -07006710 txr->tx_prod_bseq += skb->len;
Michael Chanb6016b72005-05-26 13:03:09 -07006711
Michael Chane503e062012-12-06 10:33:08 +00006712 BNX2_WR16(bp, txr->tx_bidx_addr, prod);
6713 BNX2_WR(bp, txr->tx_bseq_addr, txr->tx_prod_bseq);
Michael Chanb6016b72005-05-26 13:03:09 -07006714
6715 mmiowb();
6716
Michael Chan35e90102008-06-19 16:37:42 -07006717 txr->tx_prod = prod;
Michael Chanb6016b72005-05-26 13:03:09 -07006718
Michael Chan35e90102008-06-19 16:37:42 -07006719 if (unlikely(bnx2_tx_avail(bp, txr) <= MAX_SKB_FRAGS)) {
Benjamin Li706bf242008-07-18 17:55:11 -07006720 netif_tx_stop_queue(txq);
Michael Chan11848b962010-07-19 14:15:04 +00006721
6722 /* netif_tx_stop_queue() must be done before checking
6723 * tx index in bnx2_tx_avail() below, because in
6724 * bnx2_tx_int(), we update tx index before checking for
6725 * netif_tx_queue_stopped().
6726 */
6727 smp_mb();
Michael Chan35e90102008-06-19 16:37:42 -07006728 if (bnx2_tx_avail(bp, txr) > bp->tx_wake_thresh)
Benjamin Li706bf242008-07-18 17:55:11 -07006729 netif_tx_wake_queue(txq);
Michael Chanb6016b72005-05-26 13:03:09 -07006730 }
6731
6732 return NETDEV_TX_OK;
Alexander Duycke95524a2009-12-02 16:47:57 +00006733dma_error:
6734 /* save value of frag that failed */
6735 last_frag = i;
6736
6737 /* start back at beginning and unmap skb */
6738 prod = txr->tx_prod;
Michael Chan2bc40782012-12-06 10:33:09 +00006739 ring_prod = BNX2_TX_RING_IDX(prod);
Alexander Duycke95524a2009-12-02 16:47:57 +00006740 tx_buf = &txr->tx_buf_ring[ring_prod];
6741 tx_buf->skb = NULL;
Stanislaw Gruszka36227e82010-07-15 04:25:50 +00006742 dma_unmap_single(&bp->pdev->dev, dma_unmap_addr(tx_buf, mapping),
Alexander Duycke95524a2009-12-02 16:47:57 +00006743 skb_headlen(skb), PCI_DMA_TODEVICE);
6744
6745 /* unmap remaining mapped pages */
6746 for (i = 0; i < last_frag; i++) {
Michael Chan2bc40782012-12-06 10:33:09 +00006747 prod = BNX2_NEXT_TX_BD(prod);
6748 ring_prod = BNX2_TX_RING_IDX(prod);
Alexander Duycke95524a2009-12-02 16:47:57 +00006749 tx_buf = &txr->tx_buf_ring[ring_prod];
Stanislaw Gruszka36227e82010-07-15 04:25:50 +00006750 dma_unmap_page(&bp->pdev->dev, dma_unmap_addr(tx_buf, mapping),
Eric Dumazet9e903e02011-10-18 21:00:24 +00006751 skb_frag_size(&skb_shinfo(skb)->frags[i]),
Alexander Duycke95524a2009-12-02 16:47:57 +00006752 PCI_DMA_TODEVICE);
6753 }
6754
Eric W. Biedermanf458b2e2014-03-11 14:17:41 -07006755 dev_kfree_skb_any(skb);
Alexander Duycke95524a2009-12-02 16:47:57 +00006756 return NETDEV_TX_OK;
Michael Chanb6016b72005-05-26 13:03:09 -07006757}
6758
6759/* Called with rtnl_lock */
6760static int
6761bnx2_close(struct net_device *dev)
6762{
Michael Chan972ec0d2006-01-23 16:12:43 -08006763 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006764
Stephen Hemmingerbea33482007-10-03 16:41:36 -07006765 bnx2_disable_int_sync(bp);
Michael Chan35efa7c2007-12-20 19:56:37 -08006766 bnx2_napi_disable(bp);
Michael Chand2e553b2012-06-27 15:08:24 +00006767 netif_tx_disable(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006768 del_timer_sync(&bp->timer);
Michael Chan74bf4ba2008-10-09 12:21:08 -07006769 bnx2_shutdown_chip(bp);
Michael Chan8e6a72c2007-05-03 13:24:48 -07006770 bnx2_free_irq(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07006771 bnx2_free_skbs(bp);
6772 bnx2_free_mem(bp);
Michael Chanf048fa92010-06-01 15:05:36 +00006773 bnx2_del_napi(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07006774 bp->link_up = 0;
6775 netif_carrier_off(bp->dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006776 return 0;
6777}
6778
Michael Chan354fcd72010-01-17 07:30:44 +00006779static void
6780bnx2_save_stats(struct bnx2 *bp)
6781{
6782 u32 *hw_stats = (u32 *) bp->stats_blk;
6783 u32 *temp_stats = (u32 *) bp->temp_stats_blk;
6784 int i;
6785
6786 /* The 1st 10 counters are 64-bit counters */
6787 for (i = 0; i < 20; i += 2) {
6788 u32 hi;
6789 u64 lo;
6790
Patrick Rabauc9885fe2010-02-15 19:42:11 +00006791 hi = temp_stats[i] + hw_stats[i];
6792 lo = (u64) temp_stats[i + 1] + (u64) hw_stats[i + 1];
Michael Chan354fcd72010-01-17 07:30:44 +00006793 if (lo > 0xffffffff)
6794 hi++;
Patrick Rabauc9885fe2010-02-15 19:42:11 +00006795 temp_stats[i] = hi;
6796 temp_stats[i + 1] = lo & 0xffffffff;
Michael Chan354fcd72010-01-17 07:30:44 +00006797 }
6798
6799 for ( ; i < sizeof(struct statistics_block) / 4; i++)
Patrick Rabauc9885fe2010-02-15 19:42:11 +00006800 temp_stats[i] += hw_stats[i];
Michael Chan354fcd72010-01-17 07:30:44 +00006801}
6802
Eric Dumazet5d07bf22010-07-08 04:08:43 +00006803#define GET_64BIT_NET_STATS64(ctr) \
6804 (((u64) (ctr##_hi) << 32) + (u64) (ctr##_lo))
Michael Chanb6016b72005-05-26 13:03:09 -07006805
Michael Chana4743052010-01-17 07:30:43 +00006806#define GET_64BIT_NET_STATS(ctr) \
Michael Chan354fcd72010-01-17 07:30:44 +00006807 GET_64BIT_NET_STATS64(bp->stats_blk->ctr) + \
6808 GET_64BIT_NET_STATS64(bp->temp_stats_blk->ctr)
Michael Chanb6016b72005-05-26 13:03:09 -07006809
Michael Chana4743052010-01-17 07:30:43 +00006810#define GET_32BIT_NET_STATS(ctr) \
Michael Chan354fcd72010-01-17 07:30:44 +00006811 (unsigned long) (bp->stats_blk->ctr + \
6812 bp->temp_stats_blk->ctr)
Michael Chana4743052010-01-17 07:30:43 +00006813
Eric Dumazet5d07bf22010-07-08 04:08:43 +00006814static struct rtnl_link_stats64 *
6815bnx2_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *net_stats)
Michael Chanb6016b72005-05-26 13:03:09 -07006816{
Michael Chan972ec0d2006-01-23 16:12:43 -08006817 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006818
Eric Dumazet5d07bf22010-07-08 04:08:43 +00006819 if (bp->stats_blk == NULL)
Michael Chanb6016b72005-05-26 13:03:09 -07006820 return net_stats;
Eric Dumazet5d07bf22010-07-08 04:08:43 +00006821
Michael Chanb6016b72005-05-26 13:03:09 -07006822 net_stats->rx_packets =
Michael Chana4743052010-01-17 07:30:43 +00006823 GET_64BIT_NET_STATS(stat_IfHCInUcastPkts) +
6824 GET_64BIT_NET_STATS(stat_IfHCInMulticastPkts) +
6825 GET_64BIT_NET_STATS(stat_IfHCInBroadcastPkts);
Michael Chanb6016b72005-05-26 13:03:09 -07006826
6827 net_stats->tx_packets =
Michael Chana4743052010-01-17 07:30:43 +00006828 GET_64BIT_NET_STATS(stat_IfHCOutUcastPkts) +
6829 GET_64BIT_NET_STATS(stat_IfHCOutMulticastPkts) +
6830 GET_64BIT_NET_STATS(stat_IfHCOutBroadcastPkts);
Michael Chanb6016b72005-05-26 13:03:09 -07006831
6832 net_stats->rx_bytes =
Michael Chana4743052010-01-17 07:30:43 +00006833 GET_64BIT_NET_STATS(stat_IfHCInOctets);
Michael Chanb6016b72005-05-26 13:03:09 -07006834
6835 net_stats->tx_bytes =
Michael Chana4743052010-01-17 07:30:43 +00006836 GET_64BIT_NET_STATS(stat_IfHCOutOctets);
Michael Chanb6016b72005-05-26 13:03:09 -07006837
Jeff Garzik6aa20a22006-09-13 13:24:59 -04006838 net_stats->multicast =
Michael Chan6fdae992010-07-19 14:15:02 +00006839 GET_64BIT_NET_STATS(stat_IfHCInMulticastPkts);
Michael Chanb6016b72005-05-26 13:03:09 -07006840
Jeff Garzik6aa20a22006-09-13 13:24:59 -04006841 net_stats->collisions =
Michael Chana4743052010-01-17 07:30:43 +00006842 GET_32BIT_NET_STATS(stat_EtherStatsCollisions);
Michael Chanb6016b72005-05-26 13:03:09 -07006843
Jeff Garzik6aa20a22006-09-13 13:24:59 -04006844 net_stats->rx_length_errors =
Michael Chana4743052010-01-17 07:30:43 +00006845 GET_32BIT_NET_STATS(stat_EtherStatsUndersizePkts) +
6846 GET_32BIT_NET_STATS(stat_EtherStatsOverrsizePkts);
Michael Chanb6016b72005-05-26 13:03:09 -07006847
Jeff Garzik6aa20a22006-09-13 13:24:59 -04006848 net_stats->rx_over_errors =
Michael Chana4743052010-01-17 07:30:43 +00006849 GET_32BIT_NET_STATS(stat_IfInFTQDiscards) +
6850 GET_32BIT_NET_STATS(stat_IfInMBUFDiscards);
Michael Chanb6016b72005-05-26 13:03:09 -07006851
Jeff Garzik6aa20a22006-09-13 13:24:59 -04006852 net_stats->rx_frame_errors =
Michael Chana4743052010-01-17 07:30:43 +00006853 GET_32BIT_NET_STATS(stat_Dot3StatsAlignmentErrors);
Michael Chanb6016b72005-05-26 13:03:09 -07006854
Jeff Garzik6aa20a22006-09-13 13:24:59 -04006855 net_stats->rx_crc_errors =
Michael Chana4743052010-01-17 07:30:43 +00006856 GET_32BIT_NET_STATS(stat_Dot3StatsFCSErrors);
Michael Chanb6016b72005-05-26 13:03:09 -07006857
6858 net_stats->rx_errors = net_stats->rx_length_errors +
6859 net_stats->rx_over_errors + net_stats->rx_frame_errors +
6860 net_stats->rx_crc_errors;
6861
6862 net_stats->tx_aborted_errors =
Michael Chana4743052010-01-17 07:30:43 +00006863 GET_32BIT_NET_STATS(stat_Dot3StatsExcessiveCollisions) +
6864 GET_32BIT_NET_STATS(stat_Dot3StatsLateCollisions);
Michael Chanb6016b72005-05-26 13:03:09 -07006865
Michael Chan4ce45e02012-12-06 10:33:10 +00006866 if ((BNX2_CHIP(bp) == BNX2_CHIP_5706) ||
6867 (BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5708_A0))
Michael Chanb6016b72005-05-26 13:03:09 -07006868 net_stats->tx_carrier_errors = 0;
6869 else {
6870 net_stats->tx_carrier_errors =
Michael Chana4743052010-01-17 07:30:43 +00006871 GET_32BIT_NET_STATS(stat_Dot3StatsCarrierSenseErrors);
Michael Chanb6016b72005-05-26 13:03:09 -07006872 }
6873
6874 net_stats->tx_errors =
Michael Chana4743052010-01-17 07:30:43 +00006875 GET_32BIT_NET_STATS(stat_emac_tx_stat_dot3statsinternalmactransmiterrors) +
Michael Chanb6016b72005-05-26 13:03:09 -07006876 net_stats->tx_aborted_errors +
6877 net_stats->tx_carrier_errors;
6878
Michael Chancea94db2006-06-12 22:16:13 -07006879 net_stats->rx_missed_errors =
Michael Chana4743052010-01-17 07:30:43 +00006880 GET_32BIT_NET_STATS(stat_IfInFTQDiscards) +
6881 GET_32BIT_NET_STATS(stat_IfInMBUFDiscards) +
6882 GET_32BIT_NET_STATS(stat_FwRxDrop);
Michael Chancea94db2006-06-12 22:16:13 -07006883
Michael Chanb6016b72005-05-26 13:03:09 -07006884 return net_stats;
6885}
6886
6887/* All ethtool functions called with rtnl_lock */
6888
6889static int
6890bnx2_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
6891{
Michael Chan972ec0d2006-01-23 16:12:43 -08006892 struct bnx2 *bp = netdev_priv(dev);
Michael Chan7b6b8342007-07-07 22:50:15 -07006893 int support_serdes = 0, support_copper = 0;
Michael Chanb6016b72005-05-26 13:03:09 -07006894
6895 cmd->supported = SUPPORTED_Autoneg;
Michael Chan583c28e2008-01-21 19:51:35 -08006896 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP) {
Michael Chan7b6b8342007-07-07 22:50:15 -07006897 support_serdes = 1;
6898 support_copper = 1;
6899 } else if (bp->phy_port == PORT_FIBRE)
6900 support_serdes = 1;
6901 else
6902 support_copper = 1;
6903
6904 if (support_serdes) {
Michael Chanb6016b72005-05-26 13:03:09 -07006905 cmd->supported |= SUPPORTED_1000baseT_Full |
6906 SUPPORTED_FIBRE;
Michael Chan583c28e2008-01-21 19:51:35 -08006907 if (bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE)
Michael Chan605a9e22007-05-03 13:23:13 -07006908 cmd->supported |= SUPPORTED_2500baseX_Full;
Michael Chanb6016b72005-05-26 13:03:09 -07006909
Michael Chanb6016b72005-05-26 13:03:09 -07006910 }
Michael Chan7b6b8342007-07-07 22:50:15 -07006911 if (support_copper) {
Michael Chanb6016b72005-05-26 13:03:09 -07006912 cmd->supported |= SUPPORTED_10baseT_Half |
6913 SUPPORTED_10baseT_Full |
6914 SUPPORTED_100baseT_Half |
6915 SUPPORTED_100baseT_Full |
6916 SUPPORTED_1000baseT_Full |
6917 SUPPORTED_TP;
6918
Michael Chanb6016b72005-05-26 13:03:09 -07006919 }
6920
Michael Chan7b6b8342007-07-07 22:50:15 -07006921 spin_lock_bh(&bp->phy_lock);
6922 cmd->port = bp->phy_port;
Michael Chanb6016b72005-05-26 13:03:09 -07006923 cmd->advertising = bp->advertising;
6924
6925 if (bp->autoneg & AUTONEG_SPEED) {
6926 cmd->autoneg = AUTONEG_ENABLE;
David Decotigny70739492011-04-27 18:32:40 +00006927 } else {
Michael Chanb6016b72005-05-26 13:03:09 -07006928 cmd->autoneg = AUTONEG_DISABLE;
6929 }
6930
6931 if (netif_carrier_ok(dev)) {
David Decotigny70739492011-04-27 18:32:40 +00006932 ethtool_cmd_speed_set(cmd, bp->line_speed);
Michael Chanb6016b72005-05-26 13:03:09 -07006933 cmd->duplex = bp->duplex;
Michael Chan4016bad2013-12-31 23:22:34 -08006934 if (!(bp->phy_flags & BNX2_PHY_FLAG_SERDES)) {
6935 if (bp->phy_flags & BNX2_PHY_FLAG_MDIX)
6936 cmd->eth_tp_mdix = ETH_TP_MDI_X;
6937 else
6938 cmd->eth_tp_mdix = ETH_TP_MDI;
6939 }
Michael Chanb6016b72005-05-26 13:03:09 -07006940 }
6941 else {
Jiri Pirko537fae02014-06-06 14:17:00 +02006942 ethtool_cmd_speed_set(cmd, SPEED_UNKNOWN);
6943 cmd->duplex = DUPLEX_UNKNOWN;
Michael Chanb6016b72005-05-26 13:03:09 -07006944 }
Michael Chan7b6b8342007-07-07 22:50:15 -07006945 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07006946
6947 cmd->transceiver = XCVR_INTERNAL;
6948 cmd->phy_address = bp->phy_addr;
6949
6950 return 0;
6951}
Jeff Garzik6aa20a22006-09-13 13:24:59 -04006952
Michael Chanb6016b72005-05-26 13:03:09 -07006953static int
6954bnx2_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
6955{
Michael Chan972ec0d2006-01-23 16:12:43 -08006956 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006957 u8 autoneg = bp->autoneg;
6958 u8 req_duplex = bp->req_duplex;
6959 u16 req_line_speed = bp->req_line_speed;
6960 u32 advertising = bp->advertising;
Michael Chan7b6b8342007-07-07 22:50:15 -07006961 int err = -EINVAL;
6962
6963 spin_lock_bh(&bp->phy_lock);
6964
6965 if (cmd->port != PORT_TP && cmd->port != PORT_FIBRE)
6966 goto err_out_unlock;
6967
Michael Chan583c28e2008-01-21 19:51:35 -08006968 if (cmd->port != bp->phy_port &&
6969 !(bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP))
Michael Chan7b6b8342007-07-07 22:50:15 -07006970 goto err_out_unlock;
Michael Chanb6016b72005-05-26 13:03:09 -07006971
Michael Chand6b14482008-07-14 22:37:21 -07006972 /* If device is down, we can store the settings only if the user
6973 * is setting the currently active port.
6974 */
6975 if (!netif_running(dev) && cmd->port != bp->phy_port)
6976 goto err_out_unlock;
6977
Michael Chanb6016b72005-05-26 13:03:09 -07006978 if (cmd->autoneg == AUTONEG_ENABLE) {
6979 autoneg |= AUTONEG_SPEED;
6980
Michael Chanbeb499a2010-02-15 19:42:10 +00006981 advertising = cmd->advertising;
6982 if (cmd->port == PORT_TP) {
6983 advertising &= ETHTOOL_ALL_COPPER_SPEED;
6984 if (!advertising)
Michael Chanb6016b72005-05-26 13:03:09 -07006985 advertising = ETHTOOL_ALL_COPPER_SPEED;
Michael Chanbeb499a2010-02-15 19:42:10 +00006986 } else {
6987 advertising &= ETHTOOL_ALL_FIBRE_SPEED;
6988 if (!advertising)
6989 advertising = ETHTOOL_ALL_FIBRE_SPEED;
Michael Chanb6016b72005-05-26 13:03:09 -07006990 }
6991 advertising |= ADVERTISED_Autoneg;
6992 }
6993 else {
David Decotigny25db0332011-04-27 18:32:39 +00006994 u32 speed = ethtool_cmd_speed(cmd);
Michael Chan7b6b8342007-07-07 22:50:15 -07006995 if (cmd->port == PORT_FIBRE) {
David Decotigny25db0332011-04-27 18:32:39 +00006996 if ((speed != SPEED_1000 &&
6997 speed != SPEED_2500) ||
Michael Chan80be4432006-11-19 14:07:28 -08006998 (cmd->duplex != DUPLEX_FULL))
Michael Chan7b6b8342007-07-07 22:50:15 -07006999 goto err_out_unlock;
Michael Chan80be4432006-11-19 14:07:28 -08007000
David Decotigny25db0332011-04-27 18:32:39 +00007001 if (speed == SPEED_2500 &&
Michael Chan583c28e2008-01-21 19:51:35 -08007002 !(bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE))
Michael Chan7b6b8342007-07-07 22:50:15 -07007003 goto err_out_unlock;
David Decotigny25db0332011-04-27 18:32:39 +00007004 } else if (speed == SPEED_1000 || speed == SPEED_2500)
Michael Chan7b6b8342007-07-07 22:50:15 -07007005 goto err_out_unlock;
7006
Michael Chanb6016b72005-05-26 13:03:09 -07007007 autoneg &= ~AUTONEG_SPEED;
David Decotigny25db0332011-04-27 18:32:39 +00007008 req_line_speed = speed;
Michael Chanb6016b72005-05-26 13:03:09 -07007009 req_duplex = cmd->duplex;
7010 advertising = 0;
7011 }
7012
7013 bp->autoneg = autoneg;
7014 bp->advertising = advertising;
7015 bp->req_line_speed = req_line_speed;
7016 bp->req_duplex = req_duplex;
7017
Michael Chand6b14482008-07-14 22:37:21 -07007018 err = 0;
7019 /* If device is down, the new settings will be picked up when it is
7020 * brought up.
7021 */
7022 if (netif_running(dev))
7023 err = bnx2_setup_phy(bp, cmd->port);
Michael Chanb6016b72005-05-26 13:03:09 -07007024
Michael Chan7b6b8342007-07-07 22:50:15 -07007025err_out_unlock:
Michael Chanc770a652005-08-25 15:38:39 -07007026 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07007027
Michael Chan7b6b8342007-07-07 22:50:15 -07007028 return err;
Michael Chanb6016b72005-05-26 13:03:09 -07007029}
7030
7031static void
7032bnx2_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
7033{
Michael Chan972ec0d2006-01-23 16:12:43 -08007034 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007035
Rick Jones68aad782011-11-07 13:29:27 +00007036 strlcpy(info->driver, DRV_MODULE_NAME, sizeof(info->driver));
7037 strlcpy(info->version, DRV_MODULE_VERSION, sizeof(info->version));
7038 strlcpy(info->bus_info, pci_name(bp->pdev), sizeof(info->bus_info));
7039 strlcpy(info->fw_version, bp->fw_version, sizeof(info->fw_version));
Michael Chanb6016b72005-05-26 13:03:09 -07007040}
7041
Michael Chan244ac4f2006-03-20 17:48:46 -08007042#define BNX2_REGDUMP_LEN (32 * 1024)
7043
7044static int
7045bnx2_get_regs_len(struct net_device *dev)
7046{
7047 return BNX2_REGDUMP_LEN;
7048}
7049
7050static void
7051bnx2_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *_p)
7052{
7053 u32 *p = _p, i, offset;
7054 u8 *orig_p = _p;
7055 struct bnx2 *bp = netdev_priv(dev);
Joe Perchesb6bc7652010-12-21 02:16:08 -08007056 static const u32 reg_boundaries[] = {
7057 0x0000, 0x0098, 0x0400, 0x045c,
7058 0x0800, 0x0880, 0x0c00, 0x0c10,
7059 0x0c30, 0x0d08, 0x1000, 0x101c,
7060 0x1040, 0x1048, 0x1080, 0x10a4,
7061 0x1400, 0x1490, 0x1498, 0x14f0,
7062 0x1500, 0x155c, 0x1580, 0x15dc,
7063 0x1600, 0x1658, 0x1680, 0x16d8,
7064 0x1800, 0x1820, 0x1840, 0x1854,
7065 0x1880, 0x1894, 0x1900, 0x1984,
7066 0x1c00, 0x1c0c, 0x1c40, 0x1c54,
7067 0x1c80, 0x1c94, 0x1d00, 0x1d84,
7068 0x2000, 0x2030, 0x23c0, 0x2400,
7069 0x2800, 0x2820, 0x2830, 0x2850,
7070 0x2b40, 0x2c10, 0x2fc0, 0x3058,
7071 0x3c00, 0x3c94, 0x4000, 0x4010,
7072 0x4080, 0x4090, 0x43c0, 0x4458,
7073 0x4c00, 0x4c18, 0x4c40, 0x4c54,
7074 0x4fc0, 0x5010, 0x53c0, 0x5444,
7075 0x5c00, 0x5c18, 0x5c80, 0x5c90,
7076 0x5fc0, 0x6000, 0x6400, 0x6428,
7077 0x6800, 0x6848, 0x684c, 0x6860,
7078 0x6888, 0x6910, 0x8000
7079 };
Michael Chan244ac4f2006-03-20 17:48:46 -08007080
7081 regs->version = 0;
7082
7083 memset(p, 0, BNX2_REGDUMP_LEN);
7084
7085 if (!netif_running(bp->dev))
7086 return;
7087
7088 i = 0;
7089 offset = reg_boundaries[0];
7090 p += offset;
7091 while (offset < BNX2_REGDUMP_LEN) {
Michael Chane503e062012-12-06 10:33:08 +00007092 *p++ = BNX2_RD(bp, offset);
Michael Chan244ac4f2006-03-20 17:48:46 -08007093 offset += 4;
7094 if (offset == reg_boundaries[i + 1]) {
7095 offset = reg_boundaries[i + 2];
7096 p = (u32 *) (orig_p + offset);
7097 i += 2;
7098 }
7099 }
7100}
7101
Michael Chanb6016b72005-05-26 13:03:09 -07007102static void
7103bnx2_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
7104{
Michael Chan972ec0d2006-01-23 16:12:43 -08007105 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007106
David S. Millerf86e82f2008-01-21 17:15:40 -08007107 if (bp->flags & BNX2_FLAG_NO_WOL) {
Michael Chanb6016b72005-05-26 13:03:09 -07007108 wol->supported = 0;
7109 wol->wolopts = 0;
7110 }
7111 else {
7112 wol->supported = WAKE_MAGIC;
7113 if (bp->wol)
7114 wol->wolopts = WAKE_MAGIC;
7115 else
7116 wol->wolopts = 0;
7117 }
7118 memset(&wol->sopass, 0, sizeof(wol->sopass));
7119}
7120
7121static int
7122bnx2_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
7123{
Michael Chan972ec0d2006-01-23 16:12:43 -08007124 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007125
7126 if (wol->wolopts & ~WAKE_MAGIC)
7127 return -EINVAL;
7128
7129 if (wol->wolopts & WAKE_MAGIC) {
David S. Millerf86e82f2008-01-21 17:15:40 -08007130 if (bp->flags & BNX2_FLAG_NO_WOL)
Michael Chanb6016b72005-05-26 13:03:09 -07007131 return -EINVAL;
7132
7133 bp->wol = 1;
7134 }
7135 else {
7136 bp->wol = 0;
7137 }
Michael Chan6d5e85c2013-08-06 15:50:08 -07007138
7139 device_set_wakeup_enable(&bp->pdev->dev, bp->wol);
7140
Michael Chanb6016b72005-05-26 13:03:09 -07007141 return 0;
7142}
7143
7144static int
7145bnx2_nway_reset(struct net_device *dev)
7146{
Michael Chan972ec0d2006-01-23 16:12:43 -08007147 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007148 u32 bmcr;
7149
Michael Chan9f52b562008-10-09 12:21:46 -07007150 if (!netif_running(dev))
7151 return -EAGAIN;
7152
Michael Chanb6016b72005-05-26 13:03:09 -07007153 if (!(bp->autoneg & AUTONEG_SPEED)) {
7154 return -EINVAL;
7155 }
7156
Michael Chanc770a652005-08-25 15:38:39 -07007157 spin_lock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07007158
Michael Chan583c28e2008-01-21 19:51:35 -08007159 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP) {
Michael Chan7b6b8342007-07-07 22:50:15 -07007160 int rc;
7161
7162 rc = bnx2_setup_remote_phy(bp, bp->phy_port);
7163 spin_unlock_bh(&bp->phy_lock);
7164 return rc;
7165 }
7166
Michael Chanb6016b72005-05-26 13:03:09 -07007167 /* Force a link down visible on the other side */
Michael Chan583c28e2008-01-21 19:51:35 -08007168 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Michael Chanca58c3a2007-05-03 13:22:52 -07007169 bnx2_write_phy(bp, bp->mii_bmcr, BMCR_LOOPBACK);
Michael Chanc770a652005-08-25 15:38:39 -07007170 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07007171
7172 msleep(20);
7173
Michael Chanc770a652005-08-25 15:38:39 -07007174 spin_lock_bh(&bp->phy_lock);
Michael Chanf8dd0642006-11-19 14:08:29 -08007175
Michael Chan40105c02008-11-12 16:02:45 -08007176 bp->current_interval = BNX2_SERDES_AN_TIMEOUT;
Michael Chanf8dd0642006-11-19 14:08:29 -08007177 bp->serdes_an_pending = 1;
7178 mod_timer(&bp->timer, jiffies + bp->current_interval);
Michael Chanb6016b72005-05-26 13:03:09 -07007179 }
7180
Michael Chanca58c3a2007-05-03 13:22:52 -07007181 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chanb6016b72005-05-26 13:03:09 -07007182 bmcr &= ~BMCR_LOOPBACK;
Michael Chanca58c3a2007-05-03 13:22:52 -07007183 bnx2_write_phy(bp, bp->mii_bmcr, bmcr | BMCR_ANRESTART | BMCR_ANENABLE);
Michael Chanb6016b72005-05-26 13:03:09 -07007184
Michael Chanc770a652005-08-25 15:38:39 -07007185 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07007186
7187 return 0;
7188}
7189
Ooiwa Naohiro7959ea22009-06-24 00:19:06 -07007190static u32
7191bnx2_get_link(struct net_device *dev)
7192{
7193 struct bnx2 *bp = netdev_priv(dev);
7194
7195 return bp->link_up;
7196}
7197
Michael Chanb6016b72005-05-26 13:03:09 -07007198static int
7199bnx2_get_eeprom_len(struct net_device *dev)
7200{
Michael Chan972ec0d2006-01-23 16:12:43 -08007201 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007202
Michael Chan1122db72006-01-23 16:11:42 -08007203 if (bp->flash_info == NULL)
Michael Chanb6016b72005-05-26 13:03:09 -07007204 return 0;
7205
Michael Chan1122db72006-01-23 16:11:42 -08007206 return (int) bp->flash_size;
Michael Chanb6016b72005-05-26 13:03:09 -07007207}
7208
7209static int
7210bnx2_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
7211 u8 *eebuf)
7212{
Michael Chan972ec0d2006-01-23 16:12:43 -08007213 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007214 int rc;
7215
John W. Linville1064e942005-11-10 12:58:24 -08007216 /* parameters already validated in ethtool_get_eeprom */
Michael Chanb6016b72005-05-26 13:03:09 -07007217
7218 rc = bnx2_nvram_read(bp, eeprom->offset, eebuf, eeprom->len);
7219
7220 return rc;
7221}
7222
7223static int
7224bnx2_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
7225 u8 *eebuf)
7226{
Michael Chan972ec0d2006-01-23 16:12:43 -08007227 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007228 int rc;
7229
John W. Linville1064e942005-11-10 12:58:24 -08007230 /* parameters already validated in ethtool_set_eeprom */
Michael Chanb6016b72005-05-26 13:03:09 -07007231
7232 rc = bnx2_nvram_write(bp, eeprom->offset, eebuf, eeprom->len);
7233
7234 return rc;
7235}
7236
7237static int
7238bnx2_get_coalesce(struct net_device *dev, struct ethtool_coalesce *coal)
7239{
Michael Chan972ec0d2006-01-23 16:12:43 -08007240 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007241
7242 memset(coal, 0, sizeof(struct ethtool_coalesce));
7243
7244 coal->rx_coalesce_usecs = bp->rx_ticks;
7245 coal->rx_max_coalesced_frames = bp->rx_quick_cons_trip;
7246 coal->rx_coalesce_usecs_irq = bp->rx_ticks_int;
7247 coal->rx_max_coalesced_frames_irq = bp->rx_quick_cons_trip_int;
7248
7249 coal->tx_coalesce_usecs = bp->tx_ticks;
7250 coal->tx_max_coalesced_frames = bp->tx_quick_cons_trip;
7251 coal->tx_coalesce_usecs_irq = bp->tx_ticks_int;
7252 coal->tx_max_coalesced_frames_irq = bp->tx_quick_cons_trip_int;
7253
7254 coal->stats_block_coalesce_usecs = bp->stats_ticks;
7255
7256 return 0;
7257}
7258
7259static int
7260bnx2_set_coalesce(struct net_device *dev, struct ethtool_coalesce *coal)
7261{
Michael Chan972ec0d2006-01-23 16:12:43 -08007262 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007263
7264 bp->rx_ticks = (u16) coal->rx_coalesce_usecs;
7265 if (bp->rx_ticks > 0x3ff) bp->rx_ticks = 0x3ff;
7266
Jeff Garzik6aa20a22006-09-13 13:24:59 -04007267 bp->rx_quick_cons_trip = (u16) coal->rx_max_coalesced_frames;
Michael Chanb6016b72005-05-26 13:03:09 -07007268 if (bp->rx_quick_cons_trip > 0xff) bp->rx_quick_cons_trip = 0xff;
7269
7270 bp->rx_ticks_int = (u16) coal->rx_coalesce_usecs_irq;
7271 if (bp->rx_ticks_int > 0x3ff) bp->rx_ticks_int = 0x3ff;
7272
7273 bp->rx_quick_cons_trip_int = (u16) coal->rx_max_coalesced_frames_irq;
7274 if (bp->rx_quick_cons_trip_int > 0xff)
7275 bp->rx_quick_cons_trip_int = 0xff;
7276
7277 bp->tx_ticks = (u16) coal->tx_coalesce_usecs;
7278 if (bp->tx_ticks > 0x3ff) bp->tx_ticks = 0x3ff;
7279
7280 bp->tx_quick_cons_trip = (u16) coal->tx_max_coalesced_frames;
7281 if (bp->tx_quick_cons_trip > 0xff) bp->tx_quick_cons_trip = 0xff;
7282
7283 bp->tx_ticks_int = (u16) coal->tx_coalesce_usecs_irq;
7284 if (bp->tx_ticks_int > 0x3ff) bp->tx_ticks_int = 0x3ff;
7285
7286 bp->tx_quick_cons_trip_int = (u16) coal->tx_max_coalesced_frames_irq;
7287 if (bp->tx_quick_cons_trip_int > 0xff) bp->tx_quick_cons_trip_int =
7288 0xff;
7289
7290 bp->stats_ticks = coal->stats_block_coalesce_usecs;
Michael Chan61d9e3f2009-08-21 16:20:46 +00007291 if (bp->flags & BNX2_FLAG_BROKEN_STATS) {
Michael Chan02537b062007-06-04 21:24:07 -07007292 if (bp->stats_ticks != 0 && bp->stats_ticks != USEC_PER_SEC)
7293 bp->stats_ticks = USEC_PER_SEC;
7294 }
Michael Chan7ea69202007-07-16 18:27:10 -07007295 if (bp->stats_ticks > BNX2_HC_STATS_TICKS_HC_STAT_TICKS)
7296 bp->stats_ticks = BNX2_HC_STATS_TICKS_HC_STAT_TICKS;
7297 bp->stats_ticks &= BNX2_HC_STATS_TICKS_HC_STAT_TICKS;
Michael Chanb6016b72005-05-26 13:03:09 -07007298
7299 if (netif_running(bp->dev)) {
Michael Chan212f9932010-04-27 11:28:10 +00007300 bnx2_netif_stop(bp, true);
Michael Chan9a120bc2008-05-16 22:17:45 -07007301 bnx2_init_nic(bp, 0);
Michael Chan212f9932010-04-27 11:28:10 +00007302 bnx2_netif_start(bp, true);
Michael Chanb6016b72005-05-26 13:03:09 -07007303 }
7304
7305 return 0;
7306}
7307
7308static void
7309bnx2_get_ringparam(struct net_device *dev, struct ethtool_ringparam *ering)
7310{
Michael Chan972ec0d2006-01-23 16:12:43 -08007311 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007312
Michael Chan2bc40782012-12-06 10:33:09 +00007313 ering->rx_max_pending = BNX2_MAX_TOTAL_RX_DESC_CNT;
7314 ering->rx_jumbo_max_pending = BNX2_MAX_TOTAL_RX_PG_DESC_CNT;
Michael Chanb6016b72005-05-26 13:03:09 -07007315
7316 ering->rx_pending = bp->rx_ring_size;
Michael Chan47bf4242007-12-12 11:19:12 -08007317 ering->rx_jumbo_pending = bp->rx_pg_ring_size;
Michael Chanb6016b72005-05-26 13:03:09 -07007318
Michael Chan2bc40782012-12-06 10:33:09 +00007319 ering->tx_max_pending = BNX2_MAX_TX_DESC_CNT;
Michael Chanb6016b72005-05-26 13:03:09 -07007320 ering->tx_pending = bp->tx_ring_size;
7321}
7322
7323static int
Michael Chanb0332812012-02-05 15:24:38 +00007324bnx2_change_ring_size(struct bnx2 *bp, u32 rx, u32 tx, bool reset_irq)
Michael Chanb6016b72005-05-26 13:03:09 -07007325{
Michael Chan13daffa2006-03-20 17:49:20 -08007326 if (netif_running(bp->dev)) {
Michael Chan354fcd72010-01-17 07:30:44 +00007327 /* Reset will erase chipset stats; save them */
7328 bnx2_save_stats(bp);
7329
Michael Chan212f9932010-04-27 11:28:10 +00007330 bnx2_netif_stop(bp, true);
Michael Chan13daffa2006-03-20 17:49:20 -08007331 bnx2_reset_chip(bp, BNX2_DRV_MSG_CODE_RESET);
Michael Chanb0332812012-02-05 15:24:38 +00007332 if (reset_irq) {
7333 bnx2_free_irq(bp);
7334 bnx2_del_napi(bp);
7335 } else {
7336 __bnx2_free_irq(bp);
7337 }
Michael Chan13daffa2006-03-20 17:49:20 -08007338 bnx2_free_skbs(bp);
7339 bnx2_free_mem(bp);
7340 }
7341
Michael Chan5d5d0012007-12-12 11:17:43 -08007342 bnx2_set_rx_ring_size(bp, rx);
7343 bp->tx_ring_size = tx;
Michael Chanb6016b72005-05-26 13:03:09 -07007344
7345 if (netif_running(bp->dev)) {
Michael Chanb0332812012-02-05 15:24:38 +00007346 int rc = 0;
Michael Chan13daffa2006-03-20 17:49:20 -08007347
Michael Chanb0332812012-02-05 15:24:38 +00007348 if (reset_irq) {
7349 rc = bnx2_setup_int_mode(bp, disable_msi);
7350 bnx2_init_napi(bp);
7351 }
7352
7353 if (!rc)
7354 rc = bnx2_alloc_mem(bp);
7355
Michael Chan6fefb652009-08-21 16:20:45 +00007356 if (!rc)
Michael Chana29ba9d2010-12-31 11:03:14 -08007357 rc = bnx2_request_irq(bp);
7358
7359 if (!rc)
Michael Chan6fefb652009-08-21 16:20:45 +00007360 rc = bnx2_init_nic(bp, 0);
7361
7362 if (rc) {
7363 bnx2_napi_enable(bp);
7364 dev_close(bp->dev);
Michael Chan13daffa2006-03-20 17:49:20 -08007365 return rc;
Michael Chan6fefb652009-08-21 16:20:45 +00007366 }
Michael Chane9f26c42010-02-15 19:42:08 +00007367#ifdef BCM_CNIC
7368 mutex_lock(&bp->cnic_lock);
7369 /* Let cnic know about the new status block. */
7370 if (bp->cnic_eth_dev.drv_state & CNIC_DRV_STATE_REGD)
7371 bnx2_setup_cnic_irq_info(bp);
7372 mutex_unlock(&bp->cnic_lock);
7373#endif
Michael Chan212f9932010-04-27 11:28:10 +00007374 bnx2_netif_start(bp, true);
Michael Chanb6016b72005-05-26 13:03:09 -07007375 }
Michael Chanb6016b72005-05-26 13:03:09 -07007376 return 0;
7377}
7378
Michael Chan5d5d0012007-12-12 11:17:43 -08007379static int
7380bnx2_set_ringparam(struct net_device *dev, struct ethtool_ringparam *ering)
7381{
7382 struct bnx2 *bp = netdev_priv(dev);
7383 int rc;
7384
Michael Chan2bc40782012-12-06 10:33:09 +00007385 if ((ering->rx_pending > BNX2_MAX_TOTAL_RX_DESC_CNT) ||
7386 (ering->tx_pending > BNX2_MAX_TX_DESC_CNT) ||
Michael Chan5d5d0012007-12-12 11:17:43 -08007387 (ering->tx_pending <= MAX_SKB_FRAGS)) {
7388
7389 return -EINVAL;
7390 }
Michael Chanb0332812012-02-05 15:24:38 +00007391 rc = bnx2_change_ring_size(bp, ering->rx_pending, ering->tx_pending,
7392 false);
Michael Chan5d5d0012007-12-12 11:17:43 -08007393 return rc;
7394}
7395
Michael Chanb6016b72005-05-26 13:03:09 -07007396static void
7397bnx2_get_pauseparam(struct net_device *dev, struct ethtool_pauseparam *epause)
7398{
Michael Chan972ec0d2006-01-23 16:12:43 -08007399 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007400
7401 epause->autoneg = ((bp->autoneg & AUTONEG_FLOW_CTRL) != 0);
7402 epause->rx_pause = ((bp->flow_ctrl & FLOW_CTRL_RX) != 0);
7403 epause->tx_pause = ((bp->flow_ctrl & FLOW_CTRL_TX) != 0);
7404}
7405
7406static int
7407bnx2_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam *epause)
7408{
Michael Chan972ec0d2006-01-23 16:12:43 -08007409 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007410
7411 bp->req_flow_ctrl = 0;
7412 if (epause->rx_pause)
7413 bp->req_flow_ctrl |= FLOW_CTRL_RX;
7414 if (epause->tx_pause)
7415 bp->req_flow_ctrl |= FLOW_CTRL_TX;
7416
7417 if (epause->autoneg) {
7418 bp->autoneg |= AUTONEG_FLOW_CTRL;
7419 }
7420 else {
7421 bp->autoneg &= ~AUTONEG_FLOW_CTRL;
7422 }
7423
Michael Chan9f52b562008-10-09 12:21:46 -07007424 if (netif_running(dev)) {
7425 spin_lock_bh(&bp->phy_lock);
7426 bnx2_setup_phy(bp, bp->phy_port);
7427 spin_unlock_bh(&bp->phy_lock);
7428 }
Michael Chanb6016b72005-05-26 13:03:09 -07007429
7430 return 0;
7431}
7432
Peter Hagervall14ab9b82005-08-10 14:18:16 -07007433static struct {
Michael Chanb6016b72005-05-26 13:03:09 -07007434 char string[ETH_GSTRING_LEN];
Michael Chan790dab22009-08-21 16:20:47 +00007435} bnx2_stats_str_arr[] = {
Michael Chanb6016b72005-05-26 13:03:09 -07007436 { "rx_bytes" },
7437 { "rx_error_bytes" },
7438 { "tx_bytes" },
7439 { "tx_error_bytes" },
7440 { "rx_ucast_packets" },
7441 { "rx_mcast_packets" },
7442 { "rx_bcast_packets" },
7443 { "tx_ucast_packets" },
7444 { "tx_mcast_packets" },
7445 { "tx_bcast_packets" },
7446 { "tx_mac_errors" },
7447 { "tx_carrier_errors" },
7448 { "rx_crc_errors" },
7449 { "rx_align_errors" },
7450 { "tx_single_collisions" },
7451 { "tx_multi_collisions" },
7452 { "tx_deferred" },
7453 { "tx_excess_collisions" },
7454 { "tx_late_collisions" },
7455 { "tx_total_collisions" },
7456 { "rx_fragments" },
7457 { "rx_jabbers" },
7458 { "rx_undersize_packets" },
7459 { "rx_oversize_packets" },
7460 { "rx_64_byte_packets" },
7461 { "rx_65_to_127_byte_packets" },
7462 { "rx_128_to_255_byte_packets" },
7463 { "rx_256_to_511_byte_packets" },
7464 { "rx_512_to_1023_byte_packets" },
7465 { "rx_1024_to_1522_byte_packets" },
7466 { "rx_1523_to_9022_byte_packets" },
7467 { "tx_64_byte_packets" },
7468 { "tx_65_to_127_byte_packets" },
7469 { "tx_128_to_255_byte_packets" },
7470 { "tx_256_to_511_byte_packets" },
7471 { "tx_512_to_1023_byte_packets" },
7472 { "tx_1024_to_1522_byte_packets" },
7473 { "tx_1523_to_9022_byte_packets" },
7474 { "rx_xon_frames" },
7475 { "rx_xoff_frames" },
7476 { "tx_xon_frames" },
7477 { "tx_xoff_frames" },
7478 { "rx_mac_ctrl_frames" },
7479 { "rx_filtered_packets" },
Michael Chan790dab22009-08-21 16:20:47 +00007480 { "rx_ftq_discards" },
Michael Chanb6016b72005-05-26 13:03:09 -07007481 { "rx_discards" },
Michael Chancea94db2006-06-12 22:16:13 -07007482 { "rx_fw_discards" },
Michael Chanb6016b72005-05-26 13:03:09 -07007483};
7484
Jim Cromie0db83cd2012-04-10 14:56:03 +00007485#define BNX2_NUM_STATS ARRAY_SIZE(bnx2_stats_str_arr)
Michael Chan790dab22009-08-21 16:20:47 +00007486
Michael Chanb6016b72005-05-26 13:03:09 -07007487#define STATS_OFFSET32(offset_name) (offsetof(struct statistics_block, offset_name) / 4)
7488
Arjan van de Venf71e1302006-03-03 21:33:57 -05007489static const unsigned long bnx2_stats_offset_arr[BNX2_NUM_STATS] = {
Michael Chanb6016b72005-05-26 13:03:09 -07007490 STATS_OFFSET32(stat_IfHCInOctets_hi),
7491 STATS_OFFSET32(stat_IfHCInBadOctets_hi),
7492 STATS_OFFSET32(stat_IfHCOutOctets_hi),
7493 STATS_OFFSET32(stat_IfHCOutBadOctets_hi),
7494 STATS_OFFSET32(stat_IfHCInUcastPkts_hi),
7495 STATS_OFFSET32(stat_IfHCInMulticastPkts_hi),
7496 STATS_OFFSET32(stat_IfHCInBroadcastPkts_hi),
7497 STATS_OFFSET32(stat_IfHCOutUcastPkts_hi),
7498 STATS_OFFSET32(stat_IfHCOutMulticastPkts_hi),
7499 STATS_OFFSET32(stat_IfHCOutBroadcastPkts_hi),
7500 STATS_OFFSET32(stat_emac_tx_stat_dot3statsinternalmactransmiterrors),
Jeff Garzik6aa20a22006-09-13 13:24:59 -04007501 STATS_OFFSET32(stat_Dot3StatsCarrierSenseErrors),
7502 STATS_OFFSET32(stat_Dot3StatsFCSErrors),
7503 STATS_OFFSET32(stat_Dot3StatsAlignmentErrors),
7504 STATS_OFFSET32(stat_Dot3StatsSingleCollisionFrames),
7505 STATS_OFFSET32(stat_Dot3StatsMultipleCollisionFrames),
7506 STATS_OFFSET32(stat_Dot3StatsDeferredTransmissions),
7507 STATS_OFFSET32(stat_Dot3StatsExcessiveCollisions),
7508 STATS_OFFSET32(stat_Dot3StatsLateCollisions),
7509 STATS_OFFSET32(stat_EtherStatsCollisions),
7510 STATS_OFFSET32(stat_EtherStatsFragments),
7511 STATS_OFFSET32(stat_EtherStatsJabbers),
7512 STATS_OFFSET32(stat_EtherStatsUndersizePkts),
7513 STATS_OFFSET32(stat_EtherStatsOverrsizePkts),
7514 STATS_OFFSET32(stat_EtherStatsPktsRx64Octets),
7515 STATS_OFFSET32(stat_EtherStatsPktsRx65Octetsto127Octets),
7516 STATS_OFFSET32(stat_EtherStatsPktsRx128Octetsto255Octets),
7517 STATS_OFFSET32(stat_EtherStatsPktsRx256Octetsto511Octets),
7518 STATS_OFFSET32(stat_EtherStatsPktsRx512Octetsto1023Octets),
7519 STATS_OFFSET32(stat_EtherStatsPktsRx1024Octetsto1522Octets),
7520 STATS_OFFSET32(stat_EtherStatsPktsRx1523Octetsto9022Octets),
7521 STATS_OFFSET32(stat_EtherStatsPktsTx64Octets),
7522 STATS_OFFSET32(stat_EtherStatsPktsTx65Octetsto127Octets),
7523 STATS_OFFSET32(stat_EtherStatsPktsTx128Octetsto255Octets),
7524 STATS_OFFSET32(stat_EtherStatsPktsTx256Octetsto511Octets),
7525 STATS_OFFSET32(stat_EtherStatsPktsTx512Octetsto1023Octets),
7526 STATS_OFFSET32(stat_EtherStatsPktsTx1024Octetsto1522Octets),
7527 STATS_OFFSET32(stat_EtherStatsPktsTx1523Octetsto9022Octets),
7528 STATS_OFFSET32(stat_XonPauseFramesReceived),
7529 STATS_OFFSET32(stat_XoffPauseFramesReceived),
7530 STATS_OFFSET32(stat_OutXonSent),
7531 STATS_OFFSET32(stat_OutXoffSent),
7532 STATS_OFFSET32(stat_MacControlFramesReceived),
7533 STATS_OFFSET32(stat_IfInFramesL2FilterDiscards),
Michael Chan790dab22009-08-21 16:20:47 +00007534 STATS_OFFSET32(stat_IfInFTQDiscards),
Jeff Garzik6aa20a22006-09-13 13:24:59 -04007535 STATS_OFFSET32(stat_IfInMBUFDiscards),
Michael Chancea94db2006-06-12 22:16:13 -07007536 STATS_OFFSET32(stat_FwRxDrop),
Michael Chanb6016b72005-05-26 13:03:09 -07007537};
7538
7539/* stat_IfHCInBadOctets and stat_Dot3StatsCarrierSenseErrors are
7540 * skipped because of errata.
Jeff Garzik6aa20a22006-09-13 13:24:59 -04007541 */
Peter Hagervall14ab9b82005-08-10 14:18:16 -07007542static u8 bnx2_5706_stats_len_arr[BNX2_NUM_STATS] = {
Michael Chanb6016b72005-05-26 13:03:09 -07007543 8,0,8,8,8,8,8,8,8,8,
7544 4,0,4,4,4,4,4,4,4,4,
7545 4,4,4,4,4,4,4,4,4,4,
7546 4,4,4,4,4,4,4,4,4,4,
Michael Chan790dab22009-08-21 16:20:47 +00007547 4,4,4,4,4,4,4,
Michael Chanb6016b72005-05-26 13:03:09 -07007548};
7549
Michael Chan5b0c76a2005-11-04 08:45:49 -08007550static u8 bnx2_5708_stats_len_arr[BNX2_NUM_STATS] = {
7551 8,0,8,8,8,8,8,8,8,8,
7552 4,4,4,4,4,4,4,4,4,4,
7553 4,4,4,4,4,4,4,4,4,4,
7554 4,4,4,4,4,4,4,4,4,4,
Michael Chan790dab22009-08-21 16:20:47 +00007555 4,4,4,4,4,4,4,
Michael Chan5b0c76a2005-11-04 08:45:49 -08007556};
7557
Michael Chanb6016b72005-05-26 13:03:09 -07007558#define BNX2_NUM_TESTS 6
7559
Peter Hagervall14ab9b82005-08-10 14:18:16 -07007560static struct {
Michael Chanb6016b72005-05-26 13:03:09 -07007561 char string[ETH_GSTRING_LEN];
7562} bnx2_tests_str_arr[BNX2_NUM_TESTS] = {
7563 { "register_test (offline)" },
7564 { "memory_test (offline)" },
7565 { "loopback_test (offline)" },
7566 { "nvram_test (online)" },
7567 { "interrupt_test (online)" },
7568 { "link_test (online)" },
7569};
7570
7571static int
Jeff Garzikb9f2c042007-10-03 18:07:32 -07007572bnx2_get_sset_count(struct net_device *dev, int sset)
Michael Chanb6016b72005-05-26 13:03:09 -07007573{
Jeff Garzikb9f2c042007-10-03 18:07:32 -07007574 switch (sset) {
7575 case ETH_SS_TEST:
7576 return BNX2_NUM_TESTS;
7577 case ETH_SS_STATS:
7578 return BNX2_NUM_STATS;
7579 default:
7580 return -EOPNOTSUPP;
7581 }
Michael Chanb6016b72005-05-26 13:03:09 -07007582}
7583
7584static void
7585bnx2_self_test(struct net_device *dev, struct ethtool_test *etest, u64 *buf)
7586{
Michael Chan972ec0d2006-01-23 16:12:43 -08007587 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007588
7589 memset(buf, 0, sizeof(u64) * BNX2_NUM_TESTS);
7590 if (etest->flags & ETH_TEST_FL_OFFLINE) {
Michael Chan80be4432006-11-19 14:07:28 -08007591 int i;
7592
Michael Chan212f9932010-04-27 11:28:10 +00007593 bnx2_netif_stop(bp, true);
Michael Chanb6016b72005-05-26 13:03:09 -07007594 bnx2_reset_chip(bp, BNX2_DRV_MSG_CODE_DIAG);
7595 bnx2_free_skbs(bp);
7596
7597 if (bnx2_test_registers(bp) != 0) {
7598 buf[0] = 1;
7599 etest->flags |= ETH_TEST_FL_FAILED;
7600 }
7601 if (bnx2_test_memory(bp) != 0) {
7602 buf[1] = 1;
7603 etest->flags |= ETH_TEST_FL_FAILED;
7604 }
Michael Chanbc5a0692006-01-23 16:13:22 -08007605 if ((buf[2] = bnx2_test_loopback(bp)) != 0)
Michael Chanb6016b72005-05-26 13:03:09 -07007606 etest->flags |= ETH_TEST_FL_FAILED;
Michael Chanb6016b72005-05-26 13:03:09 -07007607
Michael Chan9f52b562008-10-09 12:21:46 -07007608 if (!netif_running(bp->dev))
7609 bnx2_shutdown_chip(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07007610 else {
Michael Chan9a120bc2008-05-16 22:17:45 -07007611 bnx2_init_nic(bp, 1);
Michael Chan212f9932010-04-27 11:28:10 +00007612 bnx2_netif_start(bp, true);
Michael Chanb6016b72005-05-26 13:03:09 -07007613 }
7614
7615 /* wait for link up */
Michael Chan80be4432006-11-19 14:07:28 -08007616 for (i = 0; i < 7; i++) {
7617 if (bp->link_up)
7618 break;
7619 msleep_interruptible(1000);
7620 }
Michael Chanb6016b72005-05-26 13:03:09 -07007621 }
7622
7623 if (bnx2_test_nvram(bp) != 0) {
7624 buf[3] = 1;
7625 etest->flags |= ETH_TEST_FL_FAILED;
7626 }
7627 if (bnx2_test_intr(bp) != 0) {
7628 buf[4] = 1;
7629 etest->flags |= ETH_TEST_FL_FAILED;
7630 }
7631
7632 if (bnx2_test_link(bp) != 0) {
7633 buf[5] = 1;
7634 etest->flags |= ETH_TEST_FL_FAILED;
7635
7636 }
7637}
7638
7639static void
7640bnx2_get_strings(struct net_device *dev, u32 stringset, u8 *buf)
7641{
7642 switch (stringset) {
7643 case ETH_SS_STATS:
7644 memcpy(buf, bnx2_stats_str_arr,
7645 sizeof(bnx2_stats_str_arr));
7646 break;
7647 case ETH_SS_TEST:
7648 memcpy(buf, bnx2_tests_str_arr,
7649 sizeof(bnx2_tests_str_arr));
7650 break;
7651 }
7652}
7653
Michael Chanb6016b72005-05-26 13:03:09 -07007654static void
7655bnx2_get_ethtool_stats(struct net_device *dev,
7656 struct ethtool_stats *stats, u64 *buf)
7657{
Michael Chan972ec0d2006-01-23 16:12:43 -08007658 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007659 int i;
7660 u32 *hw_stats = (u32 *) bp->stats_blk;
Michael Chan354fcd72010-01-17 07:30:44 +00007661 u32 *temp_stats = (u32 *) bp->temp_stats_blk;
Peter Hagervall14ab9b82005-08-10 14:18:16 -07007662 u8 *stats_len_arr = NULL;
Michael Chanb6016b72005-05-26 13:03:09 -07007663
7664 if (hw_stats == NULL) {
7665 memset(buf, 0, sizeof(u64) * BNX2_NUM_STATS);
7666 return;
7667 }
7668
Michael Chan4ce45e02012-12-06 10:33:10 +00007669 if ((BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5706_A0) ||
7670 (BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5706_A1) ||
7671 (BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5706_A2) ||
7672 (BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5708_A0))
Michael Chanb6016b72005-05-26 13:03:09 -07007673 stats_len_arr = bnx2_5706_stats_len_arr;
Michael Chan5b0c76a2005-11-04 08:45:49 -08007674 else
7675 stats_len_arr = bnx2_5708_stats_len_arr;
Michael Chanb6016b72005-05-26 13:03:09 -07007676
7677 for (i = 0; i < BNX2_NUM_STATS; i++) {
Michael Chan354fcd72010-01-17 07:30:44 +00007678 unsigned long offset;
7679
Michael Chanb6016b72005-05-26 13:03:09 -07007680 if (stats_len_arr[i] == 0) {
7681 /* skip this counter */
7682 buf[i] = 0;
7683 continue;
7684 }
Michael Chan354fcd72010-01-17 07:30:44 +00007685
7686 offset = bnx2_stats_offset_arr[i];
Michael Chanb6016b72005-05-26 13:03:09 -07007687 if (stats_len_arr[i] == 4) {
7688 /* 4-byte counter */
Michael Chan354fcd72010-01-17 07:30:44 +00007689 buf[i] = (u64) *(hw_stats + offset) +
7690 *(temp_stats + offset);
Michael Chanb6016b72005-05-26 13:03:09 -07007691 continue;
7692 }
7693 /* 8-byte counter */
Michael Chan354fcd72010-01-17 07:30:44 +00007694 buf[i] = (((u64) *(hw_stats + offset)) << 32) +
7695 *(hw_stats + offset + 1) +
7696 (((u64) *(temp_stats + offset)) << 32) +
7697 *(temp_stats + offset + 1);
Michael Chanb6016b72005-05-26 13:03:09 -07007698 }
7699}
7700
7701static int
stephen hemminger2e17e1a2011-04-04 11:06:36 +00007702bnx2_set_phys_id(struct net_device *dev, enum ethtool_phys_id_state state)
Michael Chanb6016b72005-05-26 13:03:09 -07007703{
Michael Chan972ec0d2006-01-23 16:12:43 -08007704 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007705
stephen hemminger2e17e1a2011-04-04 11:06:36 +00007706 switch (state) {
7707 case ETHTOOL_ID_ACTIVE:
Michael Chane503e062012-12-06 10:33:08 +00007708 bp->leds_save = BNX2_RD(bp, BNX2_MISC_CFG);
7709 BNX2_WR(bp, BNX2_MISC_CFG, BNX2_MISC_CFG_LEDMODE_MAC);
Allan, Bruce Wfce55922011-04-13 13:09:10 +00007710 return 1; /* cycle on/off once per second */
Michael Chanb6016b72005-05-26 13:03:09 -07007711
stephen hemminger2e17e1a2011-04-04 11:06:36 +00007712 case ETHTOOL_ID_ON:
Michael Chane503e062012-12-06 10:33:08 +00007713 BNX2_WR(bp, BNX2_EMAC_LED, BNX2_EMAC_LED_OVERRIDE |
7714 BNX2_EMAC_LED_1000MB_OVERRIDE |
7715 BNX2_EMAC_LED_100MB_OVERRIDE |
7716 BNX2_EMAC_LED_10MB_OVERRIDE |
7717 BNX2_EMAC_LED_TRAFFIC_OVERRIDE |
7718 BNX2_EMAC_LED_TRAFFIC);
stephen hemminger2e17e1a2011-04-04 11:06:36 +00007719 break;
Michael Chanb6016b72005-05-26 13:03:09 -07007720
stephen hemminger2e17e1a2011-04-04 11:06:36 +00007721 case ETHTOOL_ID_OFF:
Michael Chane503e062012-12-06 10:33:08 +00007722 BNX2_WR(bp, BNX2_EMAC_LED, BNX2_EMAC_LED_OVERRIDE);
stephen hemminger2e17e1a2011-04-04 11:06:36 +00007723 break;
7724
7725 case ETHTOOL_ID_INACTIVE:
Michael Chane503e062012-12-06 10:33:08 +00007726 BNX2_WR(bp, BNX2_EMAC_LED, 0);
7727 BNX2_WR(bp, BNX2_MISC_CFG, bp->leds_save);
stephen hemminger2e17e1a2011-04-04 11:06:36 +00007728 break;
Michael Chanb6016b72005-05-26 13:03:09 -07007729 }
Michael Chan9f52b562008-10-09 12:21:46 -07007730
Michael Chanb6016b72005-05-26 13:03:09 -07007731 return 0;
7732}
7733
Michael Chanfdc85412010-07-03 20:42:16 +00007734static int
Michał Mirosławc8f44af2011-11-15 15:29:55 +00007735bnx2_set_features(struct net_device *dev, netdev_features_t features)
Michael Chanfdc85412010-07-03 20:42:16 +00007736{
Jesse Gross7d0fd212010-10-20 13:56:09 +00007737 struct bnx2 *bp = netdev_priv(dev);
Jesse Gross7d0fd212010-10-20 13:56:09 +00007738
Michael Chan7c810472011-01-24 12:59:02 +00007739 /* TSO with VLAN tag won't work with current firmware */
Patrick McHardyf6469682013-04-19 02:04:27 +00007740 if (features & NETIF_F_HW_VLAN_CTAG_TX)
Michał Mirosław8d7dfc22011-04-10 04:47:46 +00007741 dev->vlan_features |= (dev->hw_features & NETIF_F_ALL_TSO);
7742 else
7743 dev->vlan_features &= ~NETIF_F_ALL_TSO;
Michael Chan7c810472011-01-24 12:59:02 +00007744
Patrick McHardyf6469682013-04-19 02:04:27 +00007745 if ((!!(features & NETIF_F_HW_VLAN_CTAG_RX) !=
Jesse Gross7d0fd212010-10-20 13:56:09 +00007746 !!(bp->rx_mode & BNX2_EMAC_RX_MODE_KEEP_VLAN_TAG)) &&
7747 netif_running(dev)) {
7748 bnx2_netif_stop(bp, false);
Michał Mirosław8d7dfc22011-04-10 04:47:46 +00007749 dev->features = features;
Jesse Gross7d0fd212010-10-20 13:56:09 +00007750 bnx2_set_rx_mode(dev);
7751 bnx2_fw_sync(bp, BNX2_DRV_MSG_CODE_KEEP_VLAN_UPDATE, 0, 1);
7752 bnx2_netif_start(bp, false);
Michał Mirosław8d7dfc22011-04-10 04:47:46 +00007753 return 1;
Jesse Gross7d0fd212010-10-20 13:56:09 +00007754 }
7755
7756 return 0;
Michael Chanfdc85412010-07-03 20:42:16 +00007757}
7758
Michael Chanb0332812012-02-05 15:24:38 +00007759static void bnx2_get_channels(struct net_device *dev,
7760 struct ethtool_channels *channels)
7761{
7762 struct bnx2 *bp = netdev_priv(dev);
7763 u32 max_rx_rings = 1;
7764 u32 max_tx_rings = 1;
7765
7766 if ((bp->flags & BNX2_FLAG_MSIX_CAP) && !disable_msi) {
7767 max_rx_rings = RX_MAX_RINGS;
7768 max_tx_rings = TX_MAX_RINGS;
7769 }
7770
7771 channels->max_rx = max_rx_rings;
7772 channels->max_tx = max_tx_rings;
7773 channels->max_other = 0;
7774 channels->max_combined = 0;
7775 channels->rx_count = bp->num_rx_rings;
7776 channels->tx_count = bp->num_tx_rings;
7777 channels->other_count = 0;
7778 channels->combined_count = 0;
7779}
7780
7781static int bnx2_set_channels(struct net_device *dev,
7782 struct ethtool_channels *channels)
7783{
7784 struct bnx2 *bp = netdev_priv(dev);
7785 u32 max_rx_rings = 1;
7786 u32 max_tx_rings = 1;
7787 int rc = 0;
7788
7789 if ((bp->flags & BNX2_FLAG_MSIX_CAP) && !disable_msi) {
7790 max_rx_rings = RX_MAX_RINGS;
7791 max_tx_rings = TX_MAX_RINGS;
7792 }
7793 if (channels->rx_count > max_rx_rings ||
7794 channels->tx_count > max_tx_rings)
7795 return -EINVAL;
7796
7797 bp->num_req_rx_rings = channels->rx_count;
7798 bp->num_req_tx_rings = channels->tx_count;
7799
7800 if (netif_running(dev))
7801 rc = bnx2_change_ring_size(bp, bp->rx_ring_size,
7802 bp->tx_ring_size, true);
7803
7804 return rc;
7805}
7806
Jeff Garzik7282d492006-09-13 14:30:00 -04007807static const struct ethtool_ops bnx2_ethtool_ops = {
Michael Chanb6016b72005-05-26 13:03:09 -07007808 .get_settings = bnx2_get_settings,
7809 .set_settings = bnx2_set_settings,
7810 .get_drvinfo = bnx2_get_drvinfo,
Michael Chan244ac4f2006-03-20 17:48:46 -08007811 .get_regs_len = bnx2_get_regs_len,
7812 .get_regs = bnx2_get_regs,
Michael Chanb6016b72005-05-26 13:03:09 -07007813 .get_wol = bnx2_get_wol,
7814 .set_wol = bnx2_set_wol,
7815 .nway_reset = bnx2_nway_reset,
Ooiwa Naohiro7959ea22009-06-24 00:19:06 -07007816 .get_link = bnx2_get_link,
Michael Chanb6016b72005-05-26 13:03:09 -07007817 .get_eeprom_len = bnx2_get_eeprom_len,
7818 .get_eeprom = bnx2_get_eeprom,
7819 .set_eeprom = bnx2_set_eeprom,
7820 .get_coalesce = bnx2_get_coalesce,
7821 .set_coalesce = bnx2_set_coalesce,
7822 .get_ringparam = bnx2_get_ringparam,
7823 .set_ringparam = bnx2_set_ringparam,
7824 .get_pauseparam = bnx2_get_pauseparam,
7825 .set_pauseparam = bnx2_set_pauseparam,
Michael Chanb6016b72005-05-26 13:03:09 -07007826 .self_test = bnx2_self_test,
7827 .get_strings = bnx2_get_strings,
stephen hemminger2e17e1a2011-04-04 11:06:36 +00007828 .set_phys_id = bnx2_set_phys_id,
Michael Chanb6016b72005-05-26 13:03:09 -07007829 .get_ethtool_stats = bnx2_get_ethtool_stats,
Jeff Garzikb9f2c042007-10-03 18:07:32 -07007830 .get_sset_count = bnx2_get_sset_count,
Michael Chanb0332812012-02-05 15:24:38 +00007831 .get_channels = bnx2_get_channels,
7832 .set_channels = bnx2_set_channels,
Michael Chanb6016b72005-05-26 13:03:09 -07007833};
7834
7835/* Called with rtnl_lock */
7836static int
7837bnx2_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
7838{
Peter Hagervall14ab9b82005-08-10 14:18:16 -07007839 struct mii_ioctl_data *data = if_mii(ifr);
Michael Chan972ec0d2006-01-23 16:12:43 -08007840 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007841 int err;
7842
7843 switch(cmd) {
7844 case SIOCGMIIPHY:
7845 data->phy_id = bp->phy_addr;
7846
7847 /* fallthru */
7848 case SIOCGMIIREG: {
7849 u32 mii_regval;
7850
Michael Chan583c28e2008-01-21 19:51:35 -08007851 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
Michael Chan7b6b8342007-07-07 22:50:15 -07007852 return -EOPNOTSUPP;
7853
Michael Chandad3e452007-05-03 13:18:03 -07007854 if (!netif_running(dev))
7855 return -EAGAIN;
7856
Michael Chanc770a652005-08-25 15:38:39 -07007857 spin_lock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07007858 err = bnx2_read_phy(bp, data->reg_num & 0x1f, &mii_regval);
Michael Chanc770a652005-08-25 15:38:39 -07007859 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07007860
7861 data->val_out = mii_regval;
7862
7863 return err;
7864 }
7865
7866 case SIOCSMIIREG:
Michael Chan583c28e2008-01-21 19:51:35 -08007867 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
Michael Chan7b6b8342007-07-07 22:50:15 -07007868 return -EOPNOTSUPP;
7869
Michael Chandad3e452007-05-03 13:18:03 -07007870 if (!netif_running(dev))
7871 return -EAGAIN;
7872
Michael Chanc770a652005-08-25 15:38:39 -07007873 spin_lock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07007874 err = bnx2_write_phy(bp, data->reg_num & 0x1f, data->val_in);
Michael Chanc770a652005-08-25 15:38:39 -07007875 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07007876
7877 return err;
7878
7879 default:
7880 /* do nothing */
7881 break;
7882 }
7883 return -EOPNOTSUPP;
7884}
7885
7886/* Called with rtnl_lock */
7887static int
7888bnx2_change_mac_addr(struct net_device *dev, void *p)
7889{
7890 struct sockaddr *addr = p;
Michael Chan972ec0d2006-01-23 16:12:43 -08007891 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007892
Michael Chan73eef4c2005-08-25 15:39:15 -07007893 if (!is_valid_ether_addr(addr->sa_data))
Danny Kukawka504f9b52012-02-21 02:07:49 +00007894 return -EADDRNOTAVAIL;
Michael Chan73eef4c2005-08-25 15:39:15 -07007895
Michael Chanb6016b72005-05-26 13:03:09 -07007896 memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
7897 if (netif_running(dev))
Benjamin Li5fcaed02008-07-14 22:39:52 -07007898 bnx2_set_mac_addr(bp, bp->dev->dev_addr, 0);
Michael Chanb6016b72005-05-26 13:03:09 -07007899
7900 return 0;
7901}
7902
7903/* Called with rtnl_lock */
7904static int
7905bnx2_change_mtu(struct net_device *dev, int new_mtu)
7906{
Michael Chan972ec0d2006-01-23 16:12:43 -08007907 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007908
7909 if (((new_mtu + ETH_HLEN) > MAX_ETHERNET_JUMBO_PACKET_SIZE) ||
7910 ((new_mtu + ETH_HLEN) < MIN_ETHERNET_PACKET_SIZE))
7911 return -EINVAL;
7912
7913 dev->mtu = new_mtu;
Michael Chanb0332812012-02-05 15:24:38 +00007914 return bnx2_change_ring_size(bp, bp->rx_ring_size, bp->tx_ring_size,
7915 false);
Michael Chanb6016b72005-05-26 13:03:09 -07007916}
7917
Alexey Dobriyan257ddbd2010-01-27 10:17:41 +00007918#ifdef CONFIG_NET_POLL_CONTROLLER
Michael Chanb6016b72005-05-26 13:03:09 -07007919static void
7920poll_bnx2(struct net_device *dev)
7921{
Michael Chan972ec0d2006-01-23 16:12:43 -08007922 struct bnx2 *bp = netdev_priv(dev);
Neil Hormanb2af2c12008-11-12 16:23:44 -08007923 int i;
Michael Chanb6016b72005-05-26 13:03:09 -07007924
Neil Hormanb2af2c12008-11-12 16:23:44 -08007925 for (i = 0; i < bp->irq_nvecs; i++) {
Michael Chan1bf1e342010-03-23 13:13:12 +00007926 struct bnx2_irq *irq = &bp->irq_tbl[i];
7927
7928 disable_irq(irq->vector);
7929 irq->handler(irq->vector, &bp->bnx2_napi[i]);
7930 enable_irq(irq->vector);
Neil Hormanb2af2c12008-11-12 16:23:44 -08007931 }
Michael Chanb6016b72005-05-26 13:03:09 -07007932}
7933#endif
7934
Bill Pembertoncfd95a62012-12-03 09:22:58 -05007935static void
Michael Chan253c8b72007-01-08 19:56:01 -08007936bnx2_get_5709_media(struct bnx2 *bp)
7937{
Michael Chane503e062012-12-06 10:33:08 +00007938 u32 val = BNX2_RD(bp, BNX2_MISC_DUAL_MEDIA_CTRL);
Michael Chan253c8b72007-01-08 19:56:01 -08007939 u32 bond_id = val & BNX2_MISC_DUAL_MEDIA_CTRL_BOND_ID;
7940 u32 strap;
7941
7942 if (bond_id == BNX2_MISC_DUAL_MEDIA_CTRL_BOND_ID_C)
7943 return;
7944 else if (bond_id == BNX2_MISC_DUAL_MEDIA_CTRL_BOND_ID_S) {
Michael Chan583c28e2008-01-21 19:51:35 -08007945 bp->phy_flags |= BNX2_PHY_FLAG_SERDES;
Michael Chan253c8b72007-01-08 19:56:01 -08007946 return;
7947 }
7948
7949 if (val & BNX2_MISC_DUAL_MEDIA_CTRL_STRAP_OVERRIDE)
7950 strap = (val & BNX2_MISC_DUAL_MEDIA_CTRL_PHY_CTRL) >> 21;
7951 else
7952 strap = (val & BNX2_MISC_DUAL_MEDIA_CTRL_PHY_CTRL_STRAP) >> 8;
7953
Michael Chanaefd90e2012-06-16 15:45:43 +00007954 if (bp->func == 0) {
Michael Chan253c8b72007-01-08 19:56:01 -08007955 switch (strap) {
7956 case 0x4:
7957 case 0x5:
7958 case 0x6:
Michael Chan583c28e2008-01-21 19:51:35 -08007959 bp->phy_flags |= BNX2_PHY_FLAG_SERDES;
Michael Chan253c8b72007-01-08 19:56:01 -08007960 return;
7961 }
7962 } else {
7963 switch (strap) {
7964 case 0x1:
7965 case 0x2:
7966 case 0x4:
Michael Chan583c28e2008-01-21 19:51:35 -08007967 bp->phy_flags |= BNX2_PHY_FLAG_SERDES;
Michael Chan253c8b72007-01-08 19:56:01 -08007968 return;
7969 }
7970 }
7971}
7972
Bill Pembertoncfd95a62012-12-03 09:22:58 -05007973static void
Michael Chan883e5152007-05-03 13:25:11 -07007974bnx2_get_pci_speed(struct bnx2 *bp)
7975{
7976 u32 reg;
7977
Michael Chane503e062012-12-06 10:33:08 +00007978 reg = BNX2_RD(bp, BNX2_PCICFG_MISC_STATUS);
Michael Chan883e5152007-05-03 13:25:11 -07007979 if (reg & BNX2_PCICFG_MISC_STATUS_PCIX_DET) {
7980 u32 clkreg;
7981
David S. Millerf86e82f2008-01-21 17:15:40 -08007982 bp->flags |= BNX2_FLAG_PCIX;
Michael Chan883e5152007-05-03 13:25:11 -07007983
Michael Chane503e062012-12-06 10:33:08 +00007984 clkreg = BNX2_RD(bp, BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS);
Michael Chan883e5152007-05-03 13:25:11 -07007985
7986 clkreg &= BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET;
7987 switch (clkreg) {
7988 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_133MHZ:
7989 bp->bus_speed_mhz = 133;
7990 break;
7991
7992 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_95MHZ:
7993 bp->bus_speed_mhz = 100;
7994 break;
7995
7996 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_66MHZ:
7997 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_80MHZ:
7998 bp->bus_speed_mhz = 66;
7999 break;
8000
8001 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_48MHZ:
8002 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_55MHZ:
8003 bp->bus_speed_mhz = 50;
8004 break;
8005
8006 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_LOW:
8007 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_32MHZ:
8008 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_38MHZ:
8009 bp->bus_speed_mhz = 33;
8010 break;
8011 }
8012 }
8013 else {
8014 if (reg & BNX2_PCICFG_MISC_STATUS_M66EN)
8015 bp->bus_speed_mhz = 66;
8016 else
8017 bp->bus_speed_mhz = 33;
8018 }
8019
8020 if (reg & BNX2_PCICFG_MISC_STATUS_32BIT_DET)
David S. Millerf86e82f2008-01-21 17:15:40 -08008021 bp->flags |= BNX2_FLAG_PCI_32BIT;
Michael Chan883e5152007-05-03 13:25:11 -07008022
8023}
8024
Bill Pembertoncfd95a62012-12-03 09:22:58 -05008025static void
Michael Chan76d99062009-12-03 09:46:34 +00008026bnx2_read_vpd_fw_ver(struct bnx2 *bp)
8027{
Matt Carlsondf25bc32010-02-26 14:04:44 +00008028 int rc, i, j;
Michael Chan76d99062009-12-03 09:46:34 +00008029 u8 *data;
Matt Carlsondf25bc32010-02-26 14:04:44 +00008030 unsigned int block_end, rosize, len;
Michael Chan76d99062009-12-03 09:46:34 +00008031
Michael Chan012093f2009-12-03 15:58:00 -08008032#define BNX2_VPD_NVRAM_OFFSET 0x300
8033#define BNX2_VPD_LEN 128
Michael Chan76d99062009-12-03 09:46:34 +00008034#define BNX2_MAX_VER_SLEN 30
8035
8036 data = kmalloc(256, GFP_KERNEL);
8037 if (!data)
8038 return;
8039
Michael Chan012093f2009-12-03 15:58:00 -08008040 rc = bnx2_nvram_read(bp, BNX2_VPD_NVRAM_OFFSET, data + BNX2_VPD_LEN,
8041 BNX2_VPD_LEN);
Michael Chan76d99062009-12-03 09:46:34 +00008042 if (rc)
8043 goto vpd_done;
8044
Michael Chan012093f2009-12-03 15:58:00 -08008045 for (i = 0; i < BNX2_VPD_LEN; i += 4) {
8046 data[i] = data[i + BNX2_VPD_LEN + 3];
8047 data[i + 1] = data[i + BNX2_VPD_LEN + 2];
8048 data[i + 2] = data[i + BNX2_VPD_LEN + 1];
8049 data[i + 3] = data[i + BNX2_VPD_LEN];
Michael Chan76d99062009-12-03 09:46:34 +00008050 }
8051
Matt Carlsondf25bc32010-02-26 14:04:44 +00008052 i = pci_vpd_find_tag(data, 0, BNX2_VPD_LEN, PCI_VPD_LRDT_RO_DATA);
8053 if (i < 0)
Michael Chan76d99062009-12-03 09:46:34 +00008054 goto vpd_done;
Matt Carlsondf25bc32010-02-26 14:04:44 +00008055
8056 rosize = pci_vpd_lrdt_size(&data[i]);
8057 i += PCI_VPD_LRDT_TAG_SIZE;
8058 block_end = i + rosize;
8059
8060 if (block_end > BNX2_VPD_LEN)
8061 goto vpd_done;
8062
8063 j = pci_vpd_find_info_keyword(data, i, rosize,
8064 PCI_VPD_RO_KEYWORD_MFR_ID);
8065 if (j < 0)
8066 goto vpd_done;
8067
8068 len = pci_vpd_info_field_size(&data[j]);
8069
8070 j += PCI_VPD_INFO_FLD_HDR_SIZE;
8071 if (j + len > block_end || len != 4 ||
8072 memcmp(&data[j], "1028", 4))
8073 goto vpd_done;
8074
8075 j = pci_vpd_find_info_keyword(data, i, rosize,
8076 PCI_VPD_RO_KEYWORD_VENDOR0);
8077 if (j < 0)
8078 goto vpd_done;
8079
8080 len = pci_vpd_info_field_size(&data[j]);
8081
8082 j += PCI_VPD_INFO_FLD_HDR_SIZE;
8083 if (j + len > block_end || len > BNX2_MAX_VER_SLEN)
8084 goto vpd_done;
8085
8086 memcpy(bp->fw_version, &data[j], len);
8087 bp->fw_version[len] = ' ';
Michael Chan76d99062009-12-03 09:46:34 +00008088
8089vpd_done:
8090 kfree(data);
8091}
8092
Bill Pembertoncfd95a62012-12-03 09:22:58 -05008093static int
Michael Chanb6016b72005-05-26 13:03:09 -07008094bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
8095{
8096 struct bnx2 *bp;
Michael Chan58fc2ea2007-07-07 22:52:02 -07008097 int rc, i, j;
Michael Chanb6016b72005-05-26 13:03:09 -07008098 u32 reg;
Michael Chan40453c82007-05-03 13:19:18 -07008099 u64 dma_mask, persist_dma_mask;
John Feeneycd709aa2010-08-22 17:45:53 +00008100 int err;
Michael Chanb6016b72005-05-26 13:03:09 -07008101
Michael Chanb6016b72005-05-26 13:03:09 -07008102 SET_NETDEV_DEV(dev, &pdev->dev);
Michael Chan972ec0d2006-01-23 16:12:43 -08008103 bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07008104
8105 bp->flags = 0;
8106 bp->phy_flags = 0;
8107
Michael Chan354fcd72010-01-17 07:30:44 +00008108 bp->temp_stats_blk =
8109 kzalloc(sizeof(struct statistics_block), GFP_KERNEL);
8110
8111 if (bp->temp_stats_blk == NULL) {
8112 rc = -ENOMEM;
8113 goto err_out;
8114 }
8115
Michael Chanb6016b72005-05-26 13:03:09 -07008116 /* enable device (incl. PCI PM wakeup), and bus-mastering */
8117 rc = pci_enable_device(pdev);
8118 if (rc) {
Joe Perches3a9c6a42010-02-17 15:01:51 +00008119 dev_err(&pdev->dev, "Cannot enable PCI device, aborting\n");
Michael Chanb6016b72005-05-26 13:03:09 -07008120 goto err_out;
8121 }
8122
8123 if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) {
Jeff Garzik9b91cf92006-06-27 11:39:50 -04008124 dev_err(&pdev->dev,
Joe Perches3a9c6a42010-02-17 15:01:51 +00008125 "Cannot find PCI device base address, aborting\n");
Michael Chanb6016b72005-05-26 13:03:09 -07008126 rc = -ENODEV;
8127 goto err_out_disable;
8128 }
8129
8130 rc = pci_request_regions(pdev, DRV_MODULE_NAME);
8131 if (rc) {
Joe Perches3a9c6a42010-02-17 15:01:51 +00008132 dev_err(&pdev->dev, "Cannot obtain PCI resources, aborting\n");
Michael Chanb6016b72005-05-26 13:03:09 -07008133 goto err_out_disable;
8134 }
8135
8136 pci_set_master(pdev);
8137
Yijing Wang85768272013-06-18 16:12:37 +08008138 bp->pm_cap = pdev->pm_cap;
Michael Chanb6016b72005-05-26 13:03:09 -07008139 if (bp->pm_cap == 0) {
Jeff Garzik9b91cf92006-06-27 11:39:50 -04008140 dev_err(&pdev->dev,
Joe Perches3a9c6a42010-02-17 15:01:51 +00008141 "Cannot find power management capability, aborting\n");
Michael Chanb6016b72005-05-26 13:03:09 -07008142 rc = -EIO;
8143 goto err_out_release;
8144 }
8145
Michael Chanb6016b72005-05-26 13:03:09 -07008146 bp->dev = dev;
8147 bp->pdev = pdev;
8148
8149 spin_lock_init(&bp->phy_lock);
Michael Chan1b8227c2007-05-03 13:24:05 -07008150 spin_lock_init(&bp->indirect_lock);
Michael Chanc5a88952009-08-14 15:49:45 +00008151#ifdef BCM_CNIC
8152 mutex_init(&bp->cnic_lock);
8153#endif
David Howellsc4028952006-11-22 14:57:56 +00008154 INIT_WORK(&bp->reset_task, bnx2_reset_task);
Michael Chanb6016b72005-05-26 13:03:09 -07008155
Francois Romieuc0357e92012-03-09 14:51:47 +01008156 bp->regview = pci_iomap(pdev, 0, MB_GET_CID_ADDR(TX_TSS_CID +
8157 TX_MAX_TSS_RINGS + 1));
Michael Chanb6016b72005-05-26 13:03:09 -07008158 if (!bp->regview) {
Joe Perches3a9c6a42010-02-17 15:01:51 +00008159 dev_err(&pdev->dev, "Cannot map register space, aborting\n");
Michael Chanb6016b72005-05-26 13:03:09 -07008160 rc = -ENOMEM;
8161 goto err_out_release;
8162 }
8163
8164 /* Configure byte swap and enable write to the reg_window registers.
8165 * Rely on CPU to do target byte swapping on big endian systems
8166 * The chip's target access swapping will not swap all accesses
8167 */
Michael Chane503e062012-12-06 10:33:08 +00008168 BNX2_WR(bp, BNX2_PCICFG_MISC_CONFIG,
8169 BNX2_PCICFG_MISC_CONFIG_REG_WINDOW_ENA |
8170 BNX2_PCICFG_MISC_CONFIG_TARGET_MB_WORD_SWAP);
Michael Chanb6016b72005-05-26 13:03:09 -07008171
Michael Chane503e062012-12-06 10:33:08 +00008172 bp->chip_id = BNX2_RD(bp, BNX2_MISC_ID);
Michael Chanb6016b72005-05-26 13:03:09 -07008173
Michael Chan4ce45e02012-12-06 10:33:10 +00008174 if (BNX2_CHIP(bp) == BNX2_CHIP_5709) {
Jon Masone82760e2011-06-27 07:44:43 +00008175 if (!pci_is_pcie(pdev)) {
8176 dev_err(&pdev->dev, "Not PCIE, aborting\n");
Michael Chan883e5152007-05-03 13:25:11 -07008177 rc = -EIO;
8178 goto err_out_unmap;
8179 }
David S. Millerf86e82f2008-01-21 17:15:40 -08008180 bp->flags |= BNX2_FLAG_PCIE;
Michael Chan4ce45e02012-12-06 10:33:10 +00008181 if (BNX2_CHIP_REV(bp) == BNX2_CHIP_REV_Ax)
David S. Millerf86e82f2008-01-21 17:15:40 -08008182 bp->flags |= BNX2_FLAG_JUMBO_BROKEN;
Michael Chanc239f272010-10-11 16:12:28 -07008183
8184 /* AER (Advanced Error Reporting) hooks */
8185 err = pci_enable_pcie_error_reporting(pdev);
Michael Chan4bb9ebc2011-01-25 22:14:51 +00008186 if (!err)
8187 bp->flags |= BNX2_FLAG_AER_ENABLED;
Michael Chanc239f272010-10-11 16:12:28 -07008188
Michael Chan883e5152007-05-03 13:25:11 -07008189 } else {
Michael Chan59b47d82006-11-19 14:10:45 -08008190 bp->pcix_cap = pci_find_capability(pdev, PCI_CAP_ID_PCIX);
8191 if (bp->pcix_cap == 0) {
8192 dev_err(&pdev->dev,
Joe Perches3a9c6a42010-02-17 15:01:51 +00008193 "Cannot find PCIX capability, aborting\n");
Michael Chan59b47d82006-11-19 14:10:45 -08008194 rc = -EIO;
8195 goto err_out_unmap;
8196 }
Michael Chan61d9e3f2009-08-21 16:20:46 +00008197 bp->flags |= BNX2_FLAG_BROKEN_STATS;
Michael Chan59b47d82006-11-19 14:10:45 -08008198 }
8199
Michael Chan4ce45e02012-12-06 10:33:10 +00008200 if (BNX2_CHIP(bp) == BNX2_CHIP_5709 &&
8201 BNX2_CHIP_REV(bp) != BNX2_CHIP_REV_Ax) {
Yijing Wang555a8422013-08-08 21:02:22 +08008202 if (pdev->msix_cap)
David S. Millerf86e82f2008-01-21 17:15:40 -08008203 bp->flags |= BNX2_FLAG_MSIX_CAP;
Michael Chanb4b36042007-12-20 19:59:30 -08008204 }
8205
Michael Chan4ce45e02012-12-06 10:33:10 +00008206 if (BNX2_CHIP_ID(bp) != BNX2_CHIP_ID_5706_A0 &&
8207 BNX2_CHIP_ID(bp) != BNX2_CHIP_ID_5706_A1) {
Yijing Wang555a8422013-08-08 21:02:22 +08008208 if (pdev->msi_cap)
David S. Millerf86e82f2008-01-21 17:15:40 -08008209 bp->flags |= BNX2_FLAG_MSI_CAP;
Michael Chan8e6a72c2007-05-03 13:24:48 -07008210 }
8211
Michael Chan40453c82007-05-03 13:19:18 -07008212 /* 5708 cannot support DMA addresses > 40-bit. */
Michael Chan4ce45e02012-12-06 10:33:10 +00008213 if (BNX2_CHIP(bp) == BNX2_CHIP_5708)
Yang Hongyang50cf1562009-04-06 19:01:14 -07008214 persist_dma_mask = dma_mask = DMA_BIT_MASK(40);
Michael Chan40453c82007-05-03 13:19:18 -07008215 else
Yang Hongyang6a355282009-04-06 19:01:13 -07008216 persist_dma_mask = dma_mask = DMA_BIT_MASK(64);
Michael Chan40453c82007-05-03 13:19:18 -07008217
8218 /* Configure DMA attributes. */
8219 if (pci_set_dma_mask(pdev, dma_mask) == 0) {
8220 dev->features |= NETIF_F_HIGHDMA;
8221 rc = pci_set_consistent_dma_mask(pdev, persist_dma_mask);
8222 if (rc) {
8223 dev_err(&pdev->dev,
Joe Perches3a9c6a42010-02-17 15:01:51 +00008224 "pci_set_consistent_dma_mask failed, aborting\n");
Michael Chan40453c82007-05-03 13:19:18 -07008225 goto err_out_unmap;
8226 }
Yang Hongyang284901a2009-04-06 19:01:15 -07008227 } else if ((rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) != 0) {
Joe Perches3a9c6a42010-02-17 15:01:51 +00008228 dev_err(&pdev->dev, "System does not support DMA, aborting\n");
Michael Chan40453c82007-05-03 13:19:18 -07008229 goto err_out_unmap;
8230 }
8231
David S. Millerf86e82f2008-01-21 17:15:40 -08008232 if (!(bp->flags & BNX2_FLAG_PCIE))
Michael Chan883e5152007-05-03 13:25:11 -07008233 bnx2_get_pci_speed(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07008234
8235 /* 5706A0 may falsely detect SERR and PERR. */
Michael Chan4ce45e02012-12-06 10:33:10 +00008236 if (BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5706_A0) {
Michael Chane503e062012-12-06 10:33:08 +00008237 reg = BNX2_RD(bp, PCI_COMMAND);
Michael Chanb6016b72005-05-26 13:03:09 -07008238 reg &= ~(PCI_COMMAND_SERR | PCI_COMMAND_PARITY);
Michael Chane503e062012-12-06 10:33:08 +00008239 BNX2_WR(bp, PCI_COMMAND, reg);
Michael Chan4ce45e02012-12-06 10:33:10 +00008240 } else if ((BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5706_A1) &&
David S. Millerf86e82f2008-01-21 17:15:40 -08008241 !(bp->flags & BNX2_FLAG_PCIX)) {
Michael Chanb6016b72005-05-26 13:03:09 -07008242
Jeff Garzik9b91cf92006-06-27 11:39:50 -04008243 dev_err(&pdev->dev,
Joe Perches3a9c6a42010-02-17 15:01:51 +00008244 "5706 A1 can only be used in a PCIX bus, aborting\n");
Michael Chanb6016b72005-05-26 13:03:09 -07008245 goto err_out_unmap;
8246 }
8247
8248 bnx2_init_nvram(bp);
8249
Michael Chan2726d6e2008-01-29 21:35:05 -08008250 reg = bnx2_reg_rd_ind(bp, BNX2_SHM_HDR_SIGNATURE);
Michael Chane3648b32005-11-04 08:51:21 -08008251
Michael Chanaefd90e2012-06-16 15:45:43 +00008252 if (bnx2_reg_rd_ind(bp, BNX2_MCP_TOE_ID) & BNX2_MCP_TOE_ID_FUNCTION_ID)
8253 bp->func = 1;
8254
Michael Chane3648b32005-11-04 08:51:21 -08008255 if ((reg & BNX2_SHM_HDR_SIGNATURE_SIG_MASK) ==
Michael Chan24cb2302007-01-25 15:49:56 -08008256 BNX2_SHM_HDR_SIGNATURE_SIG) {
Michael Chanaefd90e2012-06-16 15:45:43 +00008257 u32 off = bp->func << 2;
Michael Chan24cb2302007-01-25 15:49:56 -08008258
Michael Chan2726d6e2008-01-29 21:35:05 -08008259 bp->shmem_base = bnx2_reg_rd_ind(bp, BNX2_SHM_HDR_ADDR_0 + off);
Michael Chan24cb2302007-01-25 15:49:56 -08008260 } else
Michael Chane3648b32005-11-04 08:51:21 -08008261 bp->shmem_base = HOST_VIEW_SHMEM_BASE;
8262
Michael Chanb6016b72005-05-26 13:03:09 -07008263 /* Get the permanent MAC address. First we need to make sure the
8264 * firmware is actually running.
8265 */
Michael Chan2726d6e2008-01-29 21:35:05 -08008266 reg = bnx2_shmem_rd(bp, BNX2_DEV_INFO_SIGNATURE);
Michael Chanb6016b72005-05-26 13:03:09 -07008267
8268 if ((reg & BNX2_DEV_INFO_SIGNATURE_MAGIC_MASK) !=
8269 BNX2_DEV_INFO_SIGNATURE_MAGIC) {
Joe Perches3a9c6a42010-02-17 15:01:51 +00008270 dev_err(&pdev->dev, "Firmware not running, aborting\n");
Michael Chanb6016b72005-05-26 13:03:09 -07008271 rc = -ENODEV;
8272 goto err_out_unmap;
8273 }
8274
Michael Chan76d99062009-12-03 09:46:34 +00008275 bnx2_read_vpd_fw_ver(bp);
8276
8277 j = strlen(bp->fw_version);
Michael Chan2726d6e2008-01-29 21:35:05 -08008278 reg = bnx2_shmem_rd(bp, BNX2_DEV_INFO_BC_REV);
Michael Chan76d99062009-12-03 09:46:34 +00008279 for (i = 0; i < 3 && j < 24; i++) {
Michael Chan58fc2ea2007-07-07 22:52:02 -07008280 u8 num, k, skip0;
8281
Michael Chan76d99062009-12-03 09:46:34 +00008282 if (i == 0) {
8283 bp->fw_version[j++] = 'b';
8284 bp->fw_version[j++] = 'c';
8285 bp->fw_version[j++] = ' ';
8286 }
Michael Chan58fc2ea2007-07-07 22:52:02 -07008287 num = (u8) (reg >> (24 - (i * 8)));
8288 for (k = 100, skip0 = 1; k >= 1; num %= k, k /= 10) {
8289 if (num >= k || !skip0 || k == 1) {
8290 bp->fw_version[j++] = (num / k) + '0';
8291 skip0 = 0;
8292 }
8293 }
8294 if (i != 2)
8295 bp->fw_version[j++] = '.';
8296 }
Michael Chan2726d6e2008-01-29 21:35:05 -08008297 reg = bnx2_shmem_rd(bp, BNX2_PORT_FEATURE);
Michael Chan846f5c62007-10-10 16:16:51 -07008298 if (reg & BNX2_PORT_FEATURE_WOL_ENABLED)
8299 bp->wol = 1;
8300
8301 if (reg & BNX2_PORT_FEATURE_ASF_ENABLED) {
David S. Millerf86e82f2008-01-21 17:15:40 -08008302 bp->flags |= BNX2_FLAG_ASF_ENABLE;
Michael Chanc2d3db82007-07-16 18:26:43 -07008303
8304 for (i = 0; i < 30; i++) {
Michael Chan2726d6e2008-01-29 21:35:05 -08008305 reg = bnx2_shmem_rd(bp, BNX2_BC_STATE_CONDITION);
Michael Chanc2d3db82007-07-16 18:26:43 -07008306 if (reg & BNX2_CONDITION_MFW_RUN_MASK)
8307 break;
8308 msleep(10);
8309 }
8310 }
Michael Chan2726d6e2008-01-29 21:35:05 -08008311 reg = bnx2_shmem_rd(bp, BNX2_BC_STATE_CONDITION);
Michael Chan58fc2ea2007-07-07 22:52:02 -07008312 reg &= BNX2_CONDITION_MFW_RUN_MASK;
8313 if (reg != BNX2_CONDITION_MFW_RUN_UNKNOWN &&
8314 reg != BNX2_CONDITION_MFW_RUN_NONE) {
Michael Chan2726d6e2008-01-29 21:35:05 -08008315 u32 addr = bnx2_shmem_rd(bp, BNX2_MFW_VER_PTR);
Michael Chan58fc2ea2007-07-07 22:52:02 -07008316
Michael Chan76d99062009-12-03 09:46:34 +00008317 if (j < 32)
8318 bp->fw_version[j++] = ' ';
8319 for (i = 0; i < 3 && j < 28; i++) {
Michael Chan2726d6e2008-01-29 21:35:05 -08008320 reg = bnx2_reg_rd_ind(bp, addr + i * 4);
Michael Chan3aeb7d22011-07-20 14:55:25 +00008321 reg = be32_to_cpu(reg);
Michael Chan58fc2ea2007-07-07 22:52:02 -07008322 memcpy(&bp->fw_version[j], &reg, 4);
8323 j += 4;
8324 }
8325 }
Michael Chanb6016b72005-05-26 13:03:09 -07008326
Michael Chan2726d6e2008-01-29 21:35:05 -08008327 reg = bnx2_shmem_rd(bp, BNX2_PORT_HW_CFG_MAC_UPPER);
Michael Chanb6016b72005-05-26 13:03:09 -07008328 bp->mac_addr[0] = (u8) (reg >> 8);
8329 bp->mac_addr[1] = (u8) reg;
8330
Michael Chan2726d6e2008-01-29 21:35:05 -08008331 reg = bnx2_shmem_rd(bp, BNX2_PORT_HW_CFG_MAC_LOWER);
Michael Chanb6016b72005-05-26 13:03:09 -07008332 bp->mac_addr[2] = (u8) (reg >> 24);
8333 bp->mac_addr[3] = (u8) (reg >> 16);
8334 bp->mac_addr[4] = (u8) (reg >> 8);
8335 bp->mac_addr[5] = (u8) reg;
8336
Michael Chan2bc40782012-12-06 10:33:09 +00008337 bp->tx_ring_size = BNX2_MAX_TX_DESC_CNT;
Michael Chan932f3772006-08-15 01:39:36 -07008338 bnx2_set_rx_ring_size(bp, 255);
Michael Chanb6016b72005-05-26 13:03:09 -07008339
Michael Chancf7474a2009-08-21 16:20:48 +00008340 bp->tx_quick_cons_trip_int = 2;
Michael Chanb6016b72005-05-26 13:03:09 -07008341 bp->tx_quick_cons_trip = 20;
Michael Chancf7474a2009-08-21 16:20:48 +00008342 bp->tx_ticks_int = 18;
Michael Chanb6016b72005-05-26 13:03:09 -07008343 bp->tx_ticks = 80;
Jeff Garzik6aa20a22006-09-13 13:24:59 -04008344
Michael Chancf7474a2009-08-21 16:20:48 +00008345 bp->rx_quick_cons_trip_int = 2;
8346 bp->rx_quick_cons_trip = 12;
Michael Chanb6016b72005-05-26 13:03:09 -07008347 bp->rx_ticks_int = 18;
8348 bp->rx_ticks = 18;
8349
Michael Chan7ea69202007-07-16 18:27:10 -07008350 bp->stats_ticks = USEC_PER_SEC & BNX2_HC_STATS_TICKS_HC_STAT_TICKS;
Michael Chanb6016b72005-05-26 13:03:09 -07008351
Benjamin Liac392ab2008-09-18 16:40:49 -07008352 bp->current_interval = BNX2_TIMER_INTERVAL;
Michael Chanb6016b72005-05-26 13:03:09 -07008353
Michael Chan5b0c76a2005-11-04 08:45:49 -08008354 bp->phy_addr = 1;
8355
wangweidong8fae3072015-10-08 18:03:47 +08008356 /* allocate stats_blk */
8357 rc = bnx2_alloc_stats_blk(dev);
8358 if (rc)
8359 goto err_out_unmap;
8360
Michael Chanb6016b72005-05-26 13:03:09 -07008361 /* Disable WOL support if we are running on a SERDES chip. */
Michael Chan4ce45e02012-12-06 10:33:10 +00008362 if (BNX2_CHIP(bp) == BNX2_CHIP_5709)
Michael Chan253c8b72007-01-08 19:56:01 -08008363 bnx2_get_5709_media(bp);
Michael Chan4ce45e02012-12-06 10:33:10 +00008364 else if (BNX2_CHIP_BOND(bp) & BNX2_CHIP_BOND_SERDES_BIT)
Michael Chan583c28e2008-01-21 19:51:35 -08008365 bp->phy_flags |= BNX2_PHY_FLAG_SERDES;
Michael Chanbac0dff2006-11-19 14:15:05 -08008366
Michael Chan0d8a6572007-07-07 22:49:43 -07008367 bp->phy_port = PORT_TP;
Michael Chan583c28e2008-01-21 19:51:35 -08008368 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Michael Chan0d8a6572007-07-07 22:49:43 -07008369 bp->phy_port = PORT_FIBRE;
Michael Chan2726d6e2008-01-29 21:35:05 -08008370 reg = bnx2_shmem_rd(bp, BNX2_SHARED_HW_CFG_CONFIG);
Michael Chan846f5c62007-10-10 16:16:51 -07008371 if (!(reg & BNX2_SHARED_HW_CFG_GIG_LINK_ON_VAUX)) {
David S. Millerf86e82f2008-01-21 17:15:40 -08008372 bp->flags |= BNX2_FLAG_NO_WOL;
Michael Chan846f5c62007-10-10 16:16:51 -07008373 bp->wol = 0;
8374 }
Michael Chan4ce45e02012-12-06 10:33:10 +00008375 if (BNX2_CHIP(bp) == BNX2_CHIP_5706) {
Michael Chan38ea3682008-02-23 19:48:57 -08008376 /* Don't do parallel detect on this board because of
8377 * some board problems. The link will not go down
8378 * if we do parallel detect.
8379 */
8380 if (pdev->subsystem_vendor == PCI_VENDOR_ID_HP &&
8381 pdev->subsystem_device == 0x310c)
8382 bp->phy_flags |= BNX2_PHY_FLAG_NO_PARALLEL;
8383 } else {
Michael Chan5b0c76a2005-11-04 08:45:49 -08008384 bp->phy_addr = 2;
Michael Chan5b0c76a2005-11-04 08:45:49 -08008385 if (reg & BNX2_SHARED_HW_CFG_PHY_2_5G)
Michael Chan583c28e2008-01-21 19:51:35 -08008386 bp->phy_flags |= BNX2_PHY_FLAG_2_5G_CAPABLE;
Michael Chan5b0c76a2005-11-04 08:45:49 -08008387 }
Michael Chan4ce45e02012-12-06 10:33:10 +00008388 } else if (BNX2_CHIP(bp) == BNX2_CHIP_5706 ||
8389 BNX2_CHIP(bp) == BNX2_CHIP_5708)
Michael Chan583c28e2008-01-21 19:51:35 -08008390 bp->phy_flags |= BNX2_PHY_FLAG_CRC_FIX;
Michael Chan4ce45e02012-12-06 10:33:10 +00008391 else if (BNX2_CHIP(bp) == BNX2_CHIP_5709 &&
8392 (BNX2_CHIP_REV(bp) == BNX2_CHIP_REV_Ax ||
8393 BNX2_CHIP_REV(bp) == BNX2_CHIP_REV_Bx))
Michael Chan583c28e2008-01-21 19:51:35 -08008394 bp->phy_flags |= BNX2_PHY_FLAG_DIS_EARLY_DAC;
Michael Chanb6016b72005-05-26 13:03:09 -07008395
Michael Chan7c62e832008-07-14 22:39:03 -07008396 bnx2_init_fw_cap(bp);
8397
Michael Chan4ce45e02012-12-06 10:33:10 +00008398 if ((BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5708_A0) ||
8399 (BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5708_B0) ||
8400 (BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5708_B1) ||
Michael Chane503e062012-12-06 10:33:08 +00008401 !(BNX2_RD(bp, BNX2_PCI_CONFIG_3) & BNX2_PCI_CONFIG_3_VAUX_PRESET)) {
David S. Millerf86e82f2008-01-21 17:15:40 -08008402 bp->flags |= BNX2_FLAG_NO_WOL;
Michael Chan846f5c62007-10-10 16:16:51 -07008403 bp->wol = 0;
8404 }
Michael Chandda1e392006-01-23 16:08:14 -08008405
Michael Chan6d5e85c2013-08-06 15:50:08 -07008406 if (bp->flags & BNX2_FLAG_NO_WOL)
8407 device_set_wakeup_capable(&bp->pdev->dev, false);
8408 else
8409 device_set_wakeup_enable(&bp->pdev->dev, bp->wol);
8410
Michael Chan4ce45e02012-12-06 10:33:10 +00008411 if (BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5706_A0) {
Michael Chanb6016b72005-05-26 13:03:09 -07008412 bp->tx_quick_cons_trip_int =
8413 bp->tx_quick_cons_trip;
8414 bp->tx_ticks_int = bp->tx_ticks;
8415 bp->rx_quick_cons_trip_int =
8416 bp->rx_quick_cons_trip;
8417 bp->rx_ticks_int = bp->rx_ticks;
8418 bp->comp_prod_trip_int = bp->comp_prod_trip;
8419 bp->com_ticks_int = bp->com_ticks;
8420 bp->cmd_ticks_int = bp->cmd_ticks;
8421 }
8422
Michael Chanf9317a42006-09-29 17:06:23 -07008423 /* Disable MSI on 5706 if AMD 8132 bridge is found.
8424 *
8425 * MSI is defined to be 32-bit write. The 5706 does 64-bit MSI writes
8426 * with byte enables disabled on the unused 32-bit word. This is legal
8427 * but causes problems on the AMD 8132 which will eventually stop
8428 * responding after a while.
8429 *
8430 * AMD believes this incompatibility is unique to the 5706, and
Michael Ellerman88187df2007-01-25 19:34:07 +11008431 * prefers to locally disable MSI rather than globally disabling it.
Michael Chanf9317a42006-09-29 17:06:23 -07008432 */
Michael Chan4ce45e02012-12-06 10:33:10 +00008433 if (BNX2_CHIP(bp) == BNX2_CHIP_5706 && disable_msi == 0) {
Michael Chanf9317a42006-09-29 17:06:23 -07008434 struct pci_dev *amd_8132 = NULL;
8435
8436 while ((amd_8132 = pci_get_device(PCI_VENDOR_ID_AMD,
8437 PCI_DEVICE_ID_AMD_8132_BRIDGE,
8438 amd_8132))) {
Michael Chanf9317a42006-09-29 17:06:23 -07008439
Auke Kok44c10132007-06-08 15:46:36 -07008440 if (amd_8132->revision >= 0x10 &&
8441 amd_8132->revision <= 0x13) {
Michael Chanf9317a42006-09-29 17:06:23 -07008442 disable_msi = 1;
8443 pci_dev_put(amd_8132);
8444 break;
8445 }
8446 }
8447 }
8448
Michael Chandeaf3912007-07-07 22:48:00 -07008449 bnx2_set_default_link(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07008450 bp->req_flow_ctrl = FLOW_CTRL_RX | FLOW_CTRL_TX;
8451
Michael Chancd339a02005-08-25 15:35:24 -07008452 init_timer(&bp->timer);
Benjamin Liac392ab2008-09-18 16:40:49 -07008453 bp->timer.expires = RUN_AT(BNX2_TIMER_INTERVAL);
Michael Chancd339a02005-08-25 15:35:24 -07008454 bp->timer.data = (unsigned long) bp;
8455 bp->timer.function = bnx2_timer;
8456
Michael Chan7625eb22011-06-08 19:29:36 +00008457#ifdef BCM_CNIC
Michael Chan41c21782011-07-13 17:24:22 +00008458 if (bnx2_shmem_rd(bp, BNX2_ISCSI_INITIATOR) & BNX2_ISCSI_INITIATOR_EN)
8459 bp->cnic_eth_dev.max_iscsi_conn =
8460 (bnx2_shmem_rd(bp, BNX2_ISCSI_MAX_CONN) &
8461 BNX2_ISCSI_MAX_CONN_MASK) >> BNX2_ISCSI_MAX_CONN_SHIFT;
Michael Chan4bd9b0ff2012-12-06 10:33:12 +00008462 bp->cnic_probe = bnx2_cnic_probe;
Michael Chan7625eb22011-06-08 19:29:36 +00008463#endif
Michael Chanc239f272010-10-11 16:12:28 -07008464 pci_save_state(pdev);
8465
Michael Chanb6016b72005-05-26 13:03:09 -07008466 return 0;
8467
8468err_out_unmap:
Michael Chan4bb9ebc2011-01-25 22:14:51 +00008469 if (bp->flags & BNX2_FLAG_AER_ENABLED) {
Michael Chanc239f272010-10-11 16:12:28 -07008470 pci_disable_pcie_error_reporting(pdev);
Michael Chan4bb9ebc2011-01-25 22:14:51 +00008471 bp->flags &= ~BNX2_FLAG_AER_ENABLED;
8472 }
Michael Chanc239f272010-10-11 16:12:28 -07008473
Francois Romieuc0357e92012-03-09 14:51:47 +01008474 pci_iounmap(pdev, bp->regview);
8475 bp->regview = NULL;
Michael Chanb6016b72005-05-26 13:03:09 -07008476
8477err_out_release:
8478 pci_release_regions(pdev);
8479
8480err_out_disable:
8481 pci_disable_device(pdev);
Michael Chanb6016b72005-05-26 13:03:09 -07008482
8483err_out:
wangweidong3703ebe2015-10-13 10:05:19 +08008484 kfree(bp->temp_stats_blk);
8485
Michael Chanb6016b72005-05-26 13:03:09 -07008486 return rc;
8487}
8488
Bill Pembertoncfd95a62012-12-03 09:22:58 -05008489static char *
Michael Chan883e5152007-05-03 13:25:11 -07008490bnx2_bus_string(struct bnx2 *bp, char *str)
8491{
8492 char *s = str;
8493
David S. Millerf86e82f2008-01-21 17:15:40 -08008494 if (bp->flags & BNX2_FLAG_PCIE) {
Michael Chan883e5152007-05-03 13:25:11 -07008495 s += sprintf(s, "PCI Express");
8496 } else {
8497 s += sprintf(s, "PCI");
David S. Millerf86e82f2008-01-21 17:15:40 -08008498 if (bp->flags & BNX2_FLAG_PCIX)
Michael Chan883e5152007-05-03 13:25:11 -07008499 s += sprintf(s, "-X");
David S. Millerf86e82f2008-01-21 17:15:40 -08008500 if (bp->flags & BNX2_FLAG_PCI_32BIT)
Michael Chan883e5152007-05-03 13:25:11 -07008501 s += sprintf(s, " 32-bit");
8502 else
8503 s += sprintf(s, " 64-bit");
8504 s += sprintf(s, " %dMHz", bp->bus_speed_mhz);
8505 }
8506 return str;
8507}
8508
Michael Chanf048fa92010-06-01 15:05:36 +00008509static void
8510bnx2_del_napi(struct bnx2 *bp)
8511{
8512 int i;
8513
8514 for (i = 0; i < bp->irq_nvecs; i++)
8515 netif_napi_del(&bp->bnx2_napi[i].napi);
8516}
8517
8518static void
Michael Chan35efa7c2007-12-20 19:56:37 -08008519bnx2_init_napi(struct bnx2 *bp)
8520{
Michael Chanb4b36042007-12-20 19:59:30 -08008521 int i;
Michael Chan35efa7c2007-12-20 19:56:37 -08008522
Benjamin Li4327ba42010-03-23 13:13:11 +00008523 for (i = 0; i < bp->irq_nvecs; i++) {
Michael Chan35e90102008-06-19 16:37:42 -07008524 struct bnx2_napi *bnapi = &bp->bnx2_napi[i];
8525 int (*poll)(struct napi_struct *, int);
8526
8527 if (i == 0)
8528 poll = bnx2_poll;
8529 else
Michael Chanf0ea2e62008-06-19 16:41:57 -07008530 poll = bnx2_poll_msix;
Michael Chan35e90102008-06-19 16:37:42 -07008531
8532 netif_napi_add(bp->dev, &bp->bnx2_napi[i].napi, poll, 64);
Michael Chanb4b36042007-12-20 19:59:30 -08008533 bnapi->bp = bp;
8534 }
Michael Chan35efa7c2007-12-20 19:56:37 -08008535}
8536
Stephen Hemminger0421eae2008-11-21 17:31:27 -08008537static const struct net_device_ops bnx2_netdev_ops = {
8538 .ndo_open = bnx2_open,
8539 .ndo_start_xmit = bnx2_start_xmit,
8540 .ndo_stop = bnx2_close,
Eric Dumazet5d07bf22010-07-08 04:08:43 +00008541 .ndo_get_stats64 = bnx2_get_stats64,
Stephen Hemminger0421eae2008-11-21 17:31:27 -08008542 .ndo_set_rx_mode = bnx2_set_rx_mode,
8543 .ndo_do_ioctl = bnx2_ioctl,
8544 .ndo_validate_addr = eth_validate_addr,
8545 .ndo_set_mac_address = bnx2_change_mac_addr,
8546 .ndo_change_mtu = bnx2_change_mtu,
Michał Mirosław8d7dfc22011-04-10 04:47:46 +00008547 .ndo_set_features = bnx2_set_features,
Stephen Hemminger0421eae2008-11-21 17:31:27 -08008548 .ndo_tx_timeout = bnx2_tx_timeout,
Alexey Dobriyan257ddbd2010-01-27 10:17:41 +00008549#ifdef CONFIG_NET_POLL_CONTROLLER
Stephen Hemminger0421eae2008-11-21 17:31:27 -08008550 .ndo_poll_controller = poll_bnx2,
8551#endif
8552};
8553
Bill Pembertoncfd95a62012-12-03 09:22:58 -05008554static int
Michael Chanb6016b72005-05-26 13:03:09 -07008555bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
8556{
8557 static int version_printed = 0;
Francois Romieuc0357e92012-03-09 14:51:47 +01008558 struct net_device *dev;
Michael Chanb6016b72005-05-26 13:03:09 -07008559 struct bnx2 *bp;
Joe Perches0795af52007-10-03 17:59:30 -07008560 int rc;
Michael Chan883e5152007-05-03 13:25:11 -07008561 char str[40];
Michael Chanb6016b72005-05-26 13:03:09 -07008562
8563 if (version_printed++ == 0)
Joe Perches3a9c6a42010-02-17 15:01:51 +00008564 pr_info("%s", version);
Michael Chanb6016b72005-05-26 13:03:09 -07008565
8566 /* dev zeroed in init_etherdev */
Benjamin Li706bf242008-07-18 17:55:11 -07008567 dev = alloc_etherdev_mq(sizeof(*bp), TX_MAX_RINGS);
Michael Chanb6016b72005-05-26 13:03:09 -07008568 if (!dev)
8569 return -ENOMEM;
8570
8571 rc = bnx2_init_board(pdev, dev);
Francois Romieuc0357e92012-03-09 14:51:47 +01008572 if (rc < 0)
8573 goto err_free;
Michael Chanb6016b72005-05-26 13:03:09 -07008574
Stephen Hemminger0421eae2008-11-21 17:31:27 -08008575 dev->netdev_ops = &bnx2_netdev_ops;
Michael Chanb6016b72005-05-26 13:03:09 -07008576 dev->watchdog_timeo = TX_TIMEOUT;
Michael Chanb6016b72005-05-26 13:03:09 -07008577 dev->ethtool_ops = &bnx2_ethtool_ops;
Michael Chanb6016b72005-05-26 13:03:09 -07008578
Michael Chan972ec0d2006-01-23 16:12:43 -08008579 bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07008580
Michael Chan1b2f9222007-05-03 13:20:19 -07008581 pci_set_drvdata(pdev, dev);
8582
Joe Perchesd458cdf2013-10-01 19:04:40 -07008583 memcpy(dev->dev_addr, bp->mac_addr, ETH_ALEN);
Michael Chan1b2f9222007-05-03 13:20:19 -07008584
Michał Mirosław8d7dfc22011-04-10 04:47:46 +00008585 dev->hw_features = NETIF_F_IP_CSUM | NETIF_F_SG |
8586 NETIF_F_TSO | NETIF_F_TSO_ECN |
8587 NETIF_F_RXHASH | NETIF_F_RXCSUM;
8588
Michael Chan4ce45e02012-12-06 10:33:10 +00008589 if (BNX2_CHIP(bp) == BNX2_CHIP_5709)
Michał Mirosław8d7dfc22011-04-10 04:47:46 +00008590 dev->hw_features |= NETIF_F_IPV6_CSUM | NETIF_F_TSO6;
8591
8592 dev->vlan_features = dev->hw_features;
Patrick McHardyf6469682013-04-19 02:04:27 +00008593 dev->hw_features |= NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX;
Michał Mirosław8d7dfc22011-04-10 04:47:46 +00008594 dev->features |= dev->hw_features;
Jiri Pirko01789342011-08-16 06:29:00 +00008595 dev->priv_flags |= IFF_UNICAST_FLT;
Michał Mirosław8d7dfc22011-04-10 04:47:46 +00008596
Ivan Vecera26caa342015-02-26 14:48:07 +01008597 if (!(bp->flags & BNX2_FLAG_CAN_KEEP_VLAN))
8598 dev->hw_features &= ~NETIF_F_HW_VLAN_CTAG_RX;
8599
Michael Chanb6016b72005-05-26 13:03:09 -07008600 if ((rc = register_netdev(dev))) {
Jeff Garzik9b91cf92006-06-27 11:39:50 -04008601 dev_err(&pdev->dev, "Cannot register net device\n");
Michael Chan57579f72009-04-04 16:51:14 -07008602 goto error;
Michael Chanb6016b72005-05-26 13:03:09 -07008603 }
8604
Francois Romieuc0357e92012-03-09 14:51:47 +01008605 netdev_info(dev, "%s (%c%d) %s found at mem %lx, IRQ %d, "
8606 "node addr %pM\n", board_info[ent->driver_data].name,
Michael Chan4ce45e02012-12-06 10:33:10 +00008607 ((BNX2_CHIP_ID(bp) & 0xf000) >> 12) + 'A',
8608 ((BNX2_CHIP_ID(bp) & 0x0ff0) >> 4),
Francois Romieuc0357e92012-03-09 14:51:47 +01008609 bnx2_bus_string(bp, str), (long)pci_resource_start(pdev, 0),
8610 pdev->irq, dev->dev_addr);
Michael Chanb6016b72005-05-26 13:03:09 -07008611
Michael Chanb6016b72005-05-26 13:03:09 -07008612 return 0;
Michael Chan57579f72009-04-04 16:51:14 -07008613
8614error:
Michael Chanfda4d852012-12-11 18:24:20 -08008615 pci_iounmap(pdev, bp->regview);
Michael Chan57579f72009-04-04 16:51:14 -07008616 pci_release_regions(pdev);
8617 pci_disable_device(pdev);
Francois Romieuc0357e92012-03-09 14:51:47 +01008618err_free:
wangweidong8fae3072015-10-08 18:03:47 +08008619 bnx2_free_stats_blk(dev);
Michael Chan57579f72009-04-04 16:51:14 -07008620 free_netdev(dev);
8621 return rc;
Michael Chanb6016b72005-05-26 13:03:09 -07008622}
8623
Bill Pembertoncfd95a62012-12-03 09:22:58 -05008624static void
Michael Chanb6016b72005-05-26 13:03:09 -07008625bnx2_remove_one(struct pci_dev *pdev)
8626{
8627 struct net_device *dev = pci_get_drvdata(pdev);
Michael Chan972ec0d2006-01-23 16:12:43 -08008628 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07008629
8630 unregister_netdev(dev);
8631
Neil Horman8333a462011-04-26 10:30:11 +00008632 del_timer_sync(&bp->timer);
Michael Chancd634012011-07-15 06:53:58 +00008633 cancel_work_sync(&bp->reset_task);
Neil Horman8333a462011-04-26 10:30:11 +00008634
Francois Romieuc0357e92012-03-09 14:51:47 +01008635 pci_iounmap(bp->pdev, bp->regview);
Michael Chanb6016b72005-05-26 13:03:09 -07008636
wangweidong8fae3072015-10-08 18:03:47 +08008637 bnx2_free_stats_blk(dev);
Michael Chan354fcd72010-01-17 07:30:44 +00008638 kfree(bp->temp_stats_blk);
8639
Michael Chan4bb9ebc2011-01-25 22:14:51 +00008640 if (bp->flags & BNX2_FLAG_AER_ENABLED) {
Michael Chanc239f272010-10-11 16:12:28 -07008641 pci_disable_pcie_error_reporting(pdev);
Michael Chan4bb9ebc2011-01-25 22:14:51 +00008642 bp->flags &= ~BNX2_FLAG_AER_ENABLED;
8643 }
John Feeneycd709aa2010-08-22 17:45:53 +00008644
françois romieu7880b722011-09-30 00:36:52 +00008645 bnx2_release_firmware(bp);
8646
Michael Chanc239f272010-10-11 16:12:28 -07008647 free_netdev(dev);
John Feeneycd709aa2010-08-22 17:45:53 +00008648
Michael Chanb6016b72005-05-26 13:03:09 -07008649 pci_release_regions(pdev);
8650 pci_disable_device(pdev);
Michael Chanb6016b72005-05-26 13:03:09 -07008651}
8652
Daniel J Blueman77d149c2014-04-11 16:14:26 +08008653#ifdef CONFIG_PM_SLEEP
Michael Chanb6016b72005-05-26 13:03:09 -07008654static int
Michael Chan28fb4eb2013-08-06 15:50:10 -07008655bnx2_suspend(struct device *device)
Michael Chanb6016b72005-05-26 13:03:09 -07008656{
Michael Chan28fb4eb2013-08-06 15:50:10 -07008657 struct pci_dev *pdev = to_pci_dev(device);
Michael Chanb6016b72005-05-26 13:03:09 -07008658 struct net_device *dev = pci_get_drvdata(pdev);
Michael Chan972ec0d2006-01-23 16:12:43 -08008659 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07008660
Michael Chan28fb4eb2013-08-06 15:50:10 -07008661 if (netif_running(dev)) {
8662 cancel_work_sync(&bp->reset_task);
8663 bnx2_netif_stop(bp, true);
8664 netif_device_detach(dev);
8665 del_timer_sync(&bp->timer);
8666 bnx2_shutdown_chip(bp);
8667 __bnx2_free_irq(bp);
8668 bnx2_free_skbs(bp);
8669 }
8670 bnx2_setup_wol(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07008671 return 0;
8672}
8673
8674static int
Michael Chan28fb4eb2013-08-06 15:50:10 -07008675bnx2_resume(struct device *device)
Michael Chanb6016b72005-05-26 13:03:09 -07008676{
Michael Chan28fb4eb2013-08-06 15:50:10 -07008677 struct pci_dev *pdev = to_pci_dev(device);
Michael Chanb6016b72005-05-26 13:03:09 -07008678 struct net_device *dev = pci_get_drvdata(pdev);
Michael Chan972ec0d2006-01-23 16:12:43 -08008679 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07008680
8681 if (!netif_running(dev))
8682 return 0;
8683
Pavel Machek829ca9a2005-09-03 15:56:56 -07008684 bnx2_set_power_state(bp, PCI_D0);
Michael Chanb6016b72005-05-26 13:03:09 -07008685 netif_device_attach(dev);
Michael Chan28fb4eb2013-08-06 15:50:10 -07008686 bnx2_request_irq(bp);
Michael Chan9a120bc2008-05-16 22:17:45 -07008687 bnx2_init_nic(bp, 1);
Michael Chan212f9932010-04-27 11:28:10 +00008688 bnx2_netif_start(bp, true);
Michael Chanb6016b72005-05-26 13:03:09 -07008689 return 0;
8690}
8691
Michael Chan28fb4eb2013-08-06 15:50:10 -07008692static SIMPLE_DEV_PM_OPS(bnx2_pm_ops, bnx2_suspend, bnx2_resume);
8693#define BNX2_PM_OPS (&bnx2_pm_ops)
8694
8695#else
8696
8697#define BNX2_PM_OPS NULL
8698
8699#endif /* CONFIG_PM_SLEEP */
Wendy Xiong6ff2da42008-05-16 22:18:21 -07008700/**
8701 * bnx2_io_error_detected - called when PCI error is detected
8702 * @pdev: Pointer to PCI device
8703 * @state: The current pci connection state
8704 *
8705 * This function is called after a PCI bus error affecting
8706 * this device has been detected.
8707 */
8708static pci_ers_result_t bnx2_io_error_detected(struct pci_dev *pdev,
8709 pci_channel_state_t state)
8710{
8711 struct net_device *dev = pci_get_drvdata(pdev);
8712 struct bnx2 *bp = netdev_priv(dev);
8713
8714 rtnl_lock();
8715 netif_device_detach(dev);
8716
Dean Nelson2ec3de22009-07-31 09:13:18 +00008717 if (state == pci_channel_io_perm_failure) {
8718 rtnl_unlock();
8719 return PCI_ERS_RESULT_DISCONNECT;
8720 }
8721
Wendy Xiong6ff2da42008-05-16 22:18:21 -07008722 if (netif_running(dev)) {
Michael Chan212f9932010-04-27 11:28:10 +00008723 bnx2_netif_stop(bp, true);
Wendy Xiong6ff2da42008-05-16 22:18:21 -07008724 del_timer_sync(&bp->timer);
8725 bnx2_reset_nic(bp, BNX2_DRV_MSG_CODE_RESET);
8726 }
8727
8728 pci_disable_device(pdev);
8729 rtnl_unlock();
8730
8731 /* Request a slot slot reset. */
8732 return PCI_ERS_RESULT_NEED_RESET;
8733}
8734
8735/**
8736 * bnx2_io_slot_reset - called after the pci bus has been reset.
8737 * @pdev: Pointer to PCI device
8738 *
8739 * Restart the card from scratch, as if from a cold-boot.
8740 */
8741static pci_ers_result_t bnx2_io_slot_reset(struct pci_dev *pdev)
8742{
8743 struct net_device *dev = pci_get_drvdata(pdev);
8744 struct bnx2 *bp = netdev_priv(dev);
Michael Chan02481bc2013-08-06 15:50:07 -07008745 pci_ers_result_t result = PCI_ERS_RESULT_DISCONNECT;
8746 int err = 0;
Wendy Xiong6ff2da42008-05-16 22:18:21 -07008747
8748 rtnl_lock();
8749 if (pci_enable_device(pdev)) {
8750 dev_err(&pdev->dev,
Joe Perches3a9c6a42010-02-17 15:01:51 +00008751 "Cannot re-enable PCI device after reset\n");
John Feeneycd709aa2010-08-22 17:45:53 +00008752 } else {
8753 pci_set_master(pdev);
8754 pci_restore_state(pdev);
8755 pci_save_state(pdev);
Wendy Xiong6ff2da42008-05-16 22:18:21 -07008756
Michael Chan25bfb1d2013-08-06 15:50:11 -07008757 if (netif_running(dev))
Michael Chan02481bc2013-08-06 15:50:07 -07008758 err = bnx2_init_nic(bp, 1);
Michael Chan25bfb1d2013-08-06 15:50:11 -07008759
Michael Chan02481bc2013-08-06 15:50:07 -07008760 if (!err)
8761 result = PCI_ERS_RESULT_RECOVERED;
8762 }
8763
8764 if (result != PCI_ERS_RESULT_RECOVERED && netif_running(dev)) {
8765 bnx2_napi_enable(bp);
8766 dev_close(dev);
Wendy Xiong6ff2da42008-05-16 22:18:21 -07008767 }
Wendy Xiong6ff2da42008-05-16 22:18:21 -07008768 rtnl_unlock();
John Feeneycd709aa2010-08-22 17:45:53 +00008769
Michael Chan4bb9ebc2011-01-25 22:14:51 +00008770 if (!(bp->flags & BNX2_FLAG_AER_ENABLED))
Michael Chanc239f272010-10-11 16:12:28 -07008771 return result;
8772
John Feeneycd709aa2010-08-22 17:45:53 +00008773 err = pci_cleanup_aer_uncorrect_error_status(pdev);
8774 if (err) {
8775 dev_err(&pdev->dev,
8776 "pci_cleanup_aer_uncorrect_error_status failed 0x%0x\n",
8777 err); /* non-fatal, continue */
8778 }
8779
8780 return result;
Wendy Xiong6ff2da42008-05-16 22:18:21 -07008781}
8782
8783/**
8784 * bnx2_io_resume - called when traffic can start flowing again.
8785 * @pdev: Pointer to PCI device
8786 *
8787 * This callback is called when the error recovery driver tells us that
8788 * its OK to resume normal operation.
8789 */
8790static void bnx2_io_resume(struct pci_dev *pdev)
8791{
8792 struct net_device *dev = pci_get_drvdata(pdev);
8793 struct bnx2 *bp = netdev_priv(dev);
8794
8795 rtnl_lock();
8796 if (netif_running(dev))
Michael Chan212f9932010-04-27 11:28:10 +00008797 bnx2_netif_start(bp, true);
Wendy Xiong6ff2da42008-05-16 22:18:21 -07008798
8799 netif_device_attach(dev);
8800 rtnl_unlock();
8801}
8802
Michael Chan25bfb1d2013-08-06 15:50:11 -07008803static void bnx2_shutdown(struct pci_dev *pdev)
8804{
8805 struct net_device *dev = pci_get_drvdata(pdev);
8806 struct bnx2 *bp;
8807
8808 if (!dev)
8809 return;
8810
8811 bp = netdev_priv(dev);
8812 if (!bp)
8813 return;
8814
8815 rtnl_lock();
8816 if (netif_running(dev))
8817 dev_close(bp->dev);
8818
8819 if (system_state == SYSTEM_POWER_OFF)
8820 bnx2_set_power_state(bp, PCI_D3hot);
8821
8822 rtnl_unlock();
8823}
8824
Michael Chanfda4d852012-12-11 18:24:20 -08008825static const struct pci_error_handlers bnx2_err_handler = {
Wendy Xiong6ff2da42008-05-16 22:18:21 -07008826 .error_detected = bnx2_io_error_detected,
8827 .slot_reset = bnx2_io_slot_reset,
8828 .resume = bnx2_io_resume,
8829};
8830
Michael Chanb6016b72005-05-26 13:03:09 -07008831static struct pci_driver bnx2_pci_driver = {
Peter Hagervall14ab9b82005-08-10 14:18:16 -07008832 .name = DRV_MODULE_NAME,
8833 .id_table = bnx2_pci_tbl,
8834 .probe = bnx2_init_one,
Bill Pembertoncfd95a62012-12-03 09:22:58 -05008835 .remove = bnx2_remove_one,
Michael Chan28fb4eb2013-08-06 15:50:10 -07008836 .driver.pm = BNX2_PM_OPS,
Wendy Xiong6ff2da42008-05-16 22:18:21 -07008837 .err_handler = &bnx2_err_handler,
Michael Chan25bfb1d2013-08-06 15:50:11 -07008838 .shutdown = bnx2_shutdown,
Michael Chanb6016b72005-05-26 13:03:09 -07008839};
8840
Peter Hüwe5a4123f2013-05-21 12:58:05 +00008841module_pci_driver(bnx2_pci_driver);