blob: 3fcabd9e4b7e1a41397ff8dcee1a690c79a4b509 [file] [log] [blame]
Michael Chanb6016b72005-05-26 13:03:09 -07001/* bnx2.c: Broadcom NX2 network driver.
2 *
Michael Chan8a56d242013-08-06 15:50:12 -07003 * Copyright (c) 2004-2013 Broadcom Corporation
Michael Chanb6016b72005-05-26 13:03:09 -07004 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation.
8 *
9 * Written by: Michael Chan (mchan@broadcom.com)
10 */
11
Joe Perches3a9c6a42010-02-17 15:01:51 +000012#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
Michael Chanf2a4f052006-03-23 01:13:12 -080013
14#include <linux/module.h>
15#include <linux/moduleparam.h>
16
Michael Chan555069d2012-06-16 15:45:41 +000017#include <linux/stringify.h>
Michael Chanf2a4f052006-03-23 01:13:12 -080018#include <linux/kernel.h>
19#include <linux/timer.h>
20#include <linux/errno.h>
21#include <linux/ioport.h>
22#include <linux/slab.h>
23#include <linux/vmalloc.h>
24#include <linux/interrupt.h>
25#include <linux/pci.h>
26#include <linux/init.h>
27#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
Michael Chan4edd4732009-06-08 18:14:42 -070053#if defined(CONFIG_CNIC) || defined(CONFIG_CNIC_MODULE)
54#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"
Michael Chan8a56d242013-08-06 15:50:12 -070061#define DRV_MODULE_VERSION "2.2.4"
62#define DRV_MODULE_RELDATE "Aug 05, 2013"
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[] =
Michael Chanb6016b72005-05-26 13:03:09 -070075 "Broadcom NetXtreme II Gigabit Ethernet Driver " DRV_MODULE_NAME " v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";
76
77MODULE_AUTHOR("Michael Chan <mchan@broadcom.com>");
Benjamin Li453a9c62008-09-18 16:39:16 -070078MODULE_DESCRIPTION("Broadcom NetXtreme II 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
89module_param(disable_msi, int, 0);
90MODULE_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
Michael Chan7bb0a042008-07-14 22:37:47 -0700123static DEFINE_PCI_DEVICE_TABLE(bnx2_pci_tbl) = {
Michael Chanb6016b72005-05-26 13:03:09 -0700124 { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5706,
125 PCI_VENDOR_ID_HP, 0x3101, 0, 0, NC370T },
126 { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5706,
127 PCI_VENDOR_ID_HP, 0x3106, 0, 0, NC370I },
128 { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5706,
129 PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5706 },
Michael Chan5b0c76a2005-11-04 08:45:49 -0800130 { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5708,
131 PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5708 },
Michael Chanb6016b72005-05-26 13:03:09 -0700132 { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5706S,
133 PCI_VENDOR_ID_HP, 0x3102, 0, 0, NC370F },
134 { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5706S,
135 PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5706S },
Michael Chan5b0c76a2005-11-04 08:45:49 -0800136 { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5708S,
137 PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5708S },
Michael Chanbac0dff2006-11-19 14:15:05 -0800138 { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5709,
139 PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5709 },
Michael Chan27a005b2007-05-03 13:23:41 -0700140 { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5709S,
141 PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5709S },
Michael Chan7bb0a042008-07-14 22:37:47 -0700142 { PCI_VENDOR_ID_BROADCOM, 0x163b,
143 PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5716 },
Michael Chan1caacec2008-11-12 16:01:12 -0800144 { PCI_VENDOR_ID_BROADCOM, 0x163c,
Michael Chan1f2435e2008-12-16 20:28:13 -0800145 PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5716S },
Michael Chanb6016b72005-05-26 13:03:09 -0700146 { 0, }
147};
148
Michael Chan0ced9d02009-08-21 16:20:49 +0000149static const struct flash_spec flash_table[] =
Michael Chanb6016b72005-05-26 13:03:09 -0700150{
Michael Chane30372c2007-07-16 18:26:23 -0700151#define BUFFERED_FLAGS (BNX2_NV_BUFFERED | BNX2_NV_TRANSLATE)
152#define NONBUFFERED_FLAGS (BNX2_NV_WREN)
Michael Chanb6016b72005-05-26 13:03:09 -0700153 /* Slow EEPROM */
Michael Chan37137702005-11-04 08:49:17 -0800154 {0x00000000, 0x40830380, 0x009f0081, 0xa184a053, 0xaf000400,
Michael Chane30372c2007-07-16 18:26:23 -0700155 BUFFERED_FLAGS, SEEPROM_PAGE_BITS, SEEPROM_PAGE_SIZE,
Michael Chanb6016b72005-05-26 13:03:09 -0700156 SEEPROM_BYTE_ADDR_MASK, SEEPROM_TOTAL_SIZE,
157 "EEPROM - slow"},
Michael Chan37137702005-11-04 08:49:17 -0800158 /* Expansion entry 0001 */
159 {0x08000002, 0x4b808201, 0x00050081, 0x03840253, 0xaf020406,
Michael Chane30372c2007-07-16 18:26:23 -0700160 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
Michael Chan37137702005-11-04 08:49:17 -0800161 SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
162 "Entry 0001"},
Michael Chanb6016b72005-05-26 13:03:09 -0700163 /* Saifun SA25F010 (non-buffered flash) */
164 /* strap, cfg1, & write1 need updates */
Michael Chan37137702005-11-04 08:49:17 -0800165 {0x04000001, 0x47808201, 0x00050081, 0x03840253, 0xaf020406,
Michael Chane30372c2007-07-16 18:26:23 -0700166 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
Michael Chanb6016b72005-05-26 13:03:09 -0700167 SAIFUN_FLASH_BYTE_ADDR_MASK, SAIFUN_FLASH_BASE_TOTAL_SIZE*2,
168 "Non-buffered flash (128kB)"},
169 /* Saifun SA25F020 (non-buffered flash) */
170 /* strap, cfg1, & write1 need updates */
Michael Chan37137702005-11-04 08:49:17 -0800171 {0x0c000003, 0x4f808201, 0x00050081, 0x03840253, 0xaf020406,
Michael Chane30372c2007-07-16 18:26:23 -0700172 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
Michael Chanb6016b72005-05-26 13:03:09 -0700173 SAIFUN_FLASH_BYTE_ADDR_MASK, SAIFUN_FLASH_BASE_TOTAL_SIZE*4,
174 "Non-buffered flash (256kB)"},
Michael Chan37137702005-11-04 08:49:17 -0800175 /* Expansion entry 0100 */
176 {0x11000000, 0x53808201, 0x00050081, 0x03840253, 0xaf020406,
Michael Chane30372c2007-07-16 18:26:23 -0700177 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
Michael Chan37137702005-11-04 08:49:17 -0800178 SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
179 "Entry 0100"},
180 /* Entry 0101: ST M45PE10 (non-buffered flash, TetonII B0) */
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400181 {0x19000002, 0x5b808201, 0x000500db, 0x03840253, 0xaf020406,
Michael Chane30372c2007-07-16 18:26:23 -0700182 NONBUFFERED_FLAGS, ST_MICRO_FLASH_PAGE_BITS, ST_MICRO_FLASH_PAGE_SIZE,
Michael Chan37137702005-11-04 08:49:17 -0800183 ST_MICRO_FLASH_BYTE_ADDR_MASK, ST_MICRO_FLASH_BASE_TOTAL_SIZE*2,
184 "Entry 0101: ST M45PE10 (128kB non-bufferred)"},
185 /* Entry 0110: ST M45PE20 (non-buffered flash)*/
186 {0x15000001, 0x57808201, 0x000500db, 0x03840253, 0xaf020406,
Michael Chane30372c2007-07-16 18:26:23 -0700187 NONBUFFERED_FLAGS, ST_MICRO_FLASH_PAGE_BITS, ST_MICRO_FLASH_PAGE_SIZE,
Michael Chan37137702005-11-04 08:49:17 -0800188 ST_MICRO_FLASH_BYTE_ADDR_MASK, ST_MICRO_FLASH_BASE_TOTAL_SIZE*4,
189 "Entry 0110: ST M45PE20 (256kB non-bufferred)"},
190 /* Saifun SA25F005 (non-buffered flash) */
191 /* strap, cfg1, & write1 need updates */
192 {0x1d000003, 0x5f808201, 0x00050081, 0x03840253, 0xaf020406,
Michael Chane30372c2007-07-16 18:26:23 -0700193 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
Michael Chan37137702005-11-04 08:49:17 -0800194 SAIFUN_FLASH_BYTE_ADDR_MASK, SAIFUN_FLASH_BASE_TOTAL_SIZE,
195 "Non-buffered flash (64kB)"},
196 /* Fast EEPROM */
197 {0x22000000, 0x62808380, 0x009f0081, 0xa184a053, 0xaf000400,
Michael Chane30372c2007-07-16 18:26:23 -0700198 BUFFERED_FLAGS, SEEPROM_PAGE_BITS, SEEPROM_PAGE_SIZE,
Michael Chan37137702005-11-04 08:49:17 -0800199 SEEPROM_BYTE_ADDR_MASK, SEEPROM_TOTAL_SIZE,
200 "EEPROM - fast"},
201 /* Expansion entry 1001 */
202 {0x2a000002, 0x6b808201, 0x00050081, 0x03840253, 0xaf020406,
Michael Chane30372c2007-07-16 18:26:23 -0700203 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
Michael Chan37137702005-11-04 08:49:17 -0800204 SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
205 "Entry 1001"},
206 /* Expansion entry 1010 */
207 {0x26000001, 0x67808201, 0x00050081, 0x03840253, 0xaf020406,
Michael Chane30372c2007-07-16 18:26:23 -0700208 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
Michael Chan37137702005-11-04 08:49:17 -0800209 SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
210 "Entry 1010"},
211 /* ATMEL AT45DB011B (buffered flash) */
212 {0x2e000003, 0x6e808273, 0x00570081, 0x68848353, 0xaf000400,
Michael Chane30372c2007-07-16 18:26:23 -0700213 BUFFERED_FLAGS, BUFFERED_FLASH_PAGE_BITS, BUFFERED_FLASH_PAGE_SIZE,
Michael Chan37137702005-11-04 08:49:17 -0800214 BUFFERED_FLASH_BYTE_ADDR_MASK, BUFFERED_FLASH_TOTAL_SIZE,
215 "Buffered flash (128kB)"},
216 /* Expansion entry 1100 */
217 {0x33000000, 0x73808201, 0x00050081, 0x03840253, 0xaf020406,
Michael Chane30372c2007-07-16 18:26:23 -0700218 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
Michael Chan37137702005-11-04 08:49:17 -0800219 SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
220 "Entry 1100"},
221 /* Expansion entry 1101 */
222 {0x3b000002, 0x7b808201, 0x00050081, 0x03840253, 0xaf020406,
Michael Chane30372c2007-07-16 18:26:23 -0700223 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
Michael Chan37137702005-11-04 08:49:17 -0800224 SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
225 "Entry 1101"},
226 /* Ateml Expansion entry 1110 */
227 {0x37000001, 0x76808273, 0x00570081, 0x68848353, 0xaf000400,
Michael Chane30372c2007-07-16 18:26:23 -0700228 BUFFERED_FLAGS, BUFFERED_FLASH_PAGE_BITS, BUFFERED_FLASH_PAGE_SIZE,
Michael Chan37137702005-11-04 08:49:17 -0800229 BUFFERED_FLASH_BYTE_ADDR_MASK, 0,
230 "Entry 1110 (Atmel)"},
231 /* ATMEL AT45DB021B (buffered flash) */
232 {0x3f000003, 0x7e808273, 0x00570081, 0x68848353, 0xaf000400,
Michael Chane30372c2007-07-16 18:26:23 -0700233 BUFFERED_FLAGS, BUFFERED_FLASH_PAGE_BITS, BUFFERED_FLASH_PAGE_SIZE,
Michael Chan37137702005-11-04 08:49:17 -0800234 BUFFERED_FLASH_BYTE_ADDR_MASK, BUFFERED_FLASH_TOTAL_SIZE*2,
235 "Buffered flash (256kB)"},
Michael Chanb6016b72005-05-26 13:03:09 -0700236};
237
Michael Chan0ced9d02009-08-21 16:20:49 +0000238static const struct flash_spec flash_5709 = {
Michael Chane30372c2007-07-16 18:26:23 -0700239 .flags = BNX2_NV_BUFFERED,
240 .page_bits = BCM5709_FLASH_PAGE_BITS,
241 .page_size = BCM5709_FLASH_PAGE_SIZE,
242 .addr_mask = BCM5709_FLASH_BYTE_ADDR_MASK,
243 .total_size = BUFFERED_FLASH_TOTAL_SIZE*2,
244 .name = "5709 Buffered flash (256kB)",
245};
246
Michael Chanb6016b72005-05-26 13:03:09 -0700247MODULE_DEVICE_TABLE(pci, bnx2_pci_tbl);
248
Benjamin Li4327ba42010-03-23 13:13:11 +0000249static void bnx2_init_napi(struct bnx2 *bp);
Michael Chanf048fa92010-06-01 15:05:36 +0000250static void bnx2_del_napi(struct bnx2 *bp);
Benjamin Li4327ba42010-03-23 13:13:11 +0000251
Michael Chan35e90102008-06-19 16:37:42 -0700252static inline u32 bnx2_tx_avail(struct bnx2 *bp, struct bnx2_tx_ring_info *txr)
Michael Chane89bbf12005-08-25 15:36:58 -0700253{
Michael Chan2f8af122006-08-15 01:39:10 -0700254 u32 diff;
Michael Chane89bbf12005-08-25 15:36:58 -0700255
Michael Chan11848b962010-07-19 14:15:04 +0000256 /* Tell compiler to fetch tx_prod and tx_cons from memory. */
257 barrier();
Michael Chanfaac9c42006-12-14 15:56:32 -0800258
259 /* The ring uses 256 indices for 255 entries, one of them
260 * needs to be skipped.
261 */
Michael Chan35e90102008-06-19 16:37:42 -0700262 diff = txr->tx_prod - txr->tx_cons;
Michael Chan2bc40782012-12-06 10:33:09 +0000263 if (unlikely(diff >= BNX2_TX_DESC_CNT)) {
Michael Chanfaac9c42006-12-14 15:56:32 -0800264 diff &= 0xffff;
Michael Chan2bc40782012-12-06 10:33:09 +0000265 if (diff == BNX2_TX_DESC_CNT)
266 diff = BNX2_MAX_TX_DESC_CNT;
Michael Chanfaac9c42006-12-14 15:56:32 -0800267 }
Eric Dumazet807540b2010-09-23 05:40:09 +0000268 return bp->tx_ring_size - diff;
Michael Chane89bbf12005-08-25 15:36:58 -0700269}
270
Michael Chanb6016b72005-05-26 13:03:09 -0700271static u32
272bnx2_reg_rd_ind(struct bnx2 *bp, u32 offset)
273{
Michael Chan1b8227c2007-05-03 13:24:05 -0700274 u32 val;
275
276 spin_lock_bh(&bp->indirect_lock);
Michael Chane503e062012-12-06 10:33:08 +0000277 BNX2_WR(bp, BNX2_PCICFG_REG_WINDOW_ADDRESS, offset);
278 val = BNX2_RD(bp, BNX2_PCICFG_REG_WINDOW);
Michael Chan1b8227c2007-05-03 13:24:05 -0700279 spin_unlock_bh(&bp->indirect_lock);
280 return val;
Michael Chanb6016b72005-05-26 13:03:09 -0700281}
282
283static void
284bnx2_reg_wr_ind(struct bnx2 *bp, u32 offset, u32 val)
285{
Michael Chan1b8227c2007-05-03 13:24:05 -0700286 spin_lock_bh(&bp->indirect_lock);
Michael Chane503e062012-12-06 10:33:08 +0000287 BNX2_WR(bp, BNX2_PCICFG_REG_WINDOW_ADDRESS, offset);
288 BNX2_WR(bp, BNX2_PCICFG_REG_WINDOW, val);
Michael Chan1b8227c2007-05-03 13:24:05 -0700289 spin_unlock_bh(&bp->indirect_lock);
Michael Chanb6016b72005-05-26 13:03:09 -0700290}
291
292static void
Michael Chan2726d6e2008-01-29 21:35:05 -0800293bnx2_shmem_wr(struct bnx2 *bp, u32 offset, u32 val)
294{
295 bnx2_reg_wr_ind(bp, bp->shmem_base + offset, val);
296}
297
298static u32
299bnx2_shmem_rd(struct bnx2 *bp, u32 offset)
300{
Eric Dumazet807540b2010-09-23 05:40:09 +0000301 return bnx2_reg_rd_ind(bp, bp->shmem_base + offset);
Michael Chan2726d6e2008-01-29 21:35:05 -0800302}
303
304static void
Michael Chanb6016b72005-05-26 13:03:09 -0700305bnx2_ctx_wr(struct bnx2 *bp, u32 cid_addr, u32 offset, u32 val)
306{
307 offset += cid_addr;
Michael Chan1b8227c2007-05-03 13:24:05 -0700308 spin_lock_bh(&bp->indirect_lock);
Michael Chan4ce45e02012-12-06 10:33:10 +0000309 if (BNX2_CHIP(bp) == BNX2_CHIP_5709) {
Michael Chan59b47d82006-11-19 14:10:45 -0800310 int i;
311
Michael Chane503e062012-12-06 10:33:08 +0000312 BNX2_WR(bp, BNX2_CTX_CTX_DATA, val);
313 BNX2_WR(bp, BNX2_CTX_CTX_CTRL,
314 offset | BNX2_CTX_CTX_CTRL_WRITE_REQ);
Michael Chan59b47d82006-11-19 14:10:45 -0800315 for (i = 0; i < 5; i++) {
Michael Chane503e062012-12-06 10:33:08 +0000316 val = BNX2_RD(bp, BNX2_CTX_CTX_CTRL);
Michael Chan59b47d82006-11-19 14:10:45 -0800317 if ((val & BNX2_CTX_CTX_CTRL_WRITE_REQ) == 0)
318 break;
319 udelay(5);
320 }
321 } else {
Michael Chane503e062012-12-06 10:33:08 +0000322 BNX2_WR(bp, BNX2_CTX_DATA_ADR, offset);
323 BNX2_WR(bp, BNX2_CTX_DATA, val);
Michael Chan59b47d82006-11-19 14:10:45 -0800324 }
Michael Chan1b8227c2007-05-03 13:24:05 -0700325 spin_unlock_bh(&bp->indirect_lock);
Michael Chanb6016b72005-05-26 13:03:09 -0700326}
327
Michael Chan4edd4732009-06-08 18:14:42 -0700328#ifdef BCM_CNIC
329static int
330bnx2_drv_ctl(struct net_device *dev, struct drv_ctl_info *info)
331{
332 struct bnx2 *bp = netdev_priv(dev);
333 struct drv_ctl_io *io = &info->data.io;
334
335 switch (info->cmd) {
336 case DRV_CTL_IO_WR_CMD:
337 bnx2_reg_wr_ind(bp, io->offset, io->data);
338 break;
339 case DRV_CTL_IO_RD_CMD:
340 io->data = bnx2_reg_rd_ind(bp, io->offset);
341 break;
342 case DRV_CTL_CTX_WR_CMD:
343 bnx2_ctx_wr(bp, io->cid_addr, io->offset, io->data);
344 break;
345 default:
346 return -EINVAL;
347 }
348 return 0;
349}
350
351static void bnx2_setup_cnic_irq_info(struct bnx2 *bp)
352{
353 struct cnic_eth_dev *cp = &bp->cnic_eth_dev;
354 struct bnx2_napi *bnapi = &bp->bnx2_napi[0];
355 int sb_id;
356
357 if (bp->flags & BNX2_FLAG_USING_MSIX) {
358 cp->drv_state |= CNIC_DRV_STATE_USING_MSIX;
359 bnapi->cnic_present = 0;
360 sb_id = bp->irq_nvecs;
361 cp->irq_arr[0].irq_flags |= CNIC_IRQ_FL_MSIX;
362 } else {
363 cp->drv_state &= ~CNIC_DRV_STATE_USING_MSIX;
364 bnapi->cnic_tag = bnapi->last_status_idx;
365 bnapi->cnic_present = 1;
366 sb_id = 0;
367 cp->irq_arr[0].irq_flags &= ~CNIC_IRQ_FL_MSIX;
368 }
369
370 cp->irq_arr[0].vector = bp->irq_tbl[sb_id].vector;
371 cp->irq_arr[0].status_blk = (void *)
372 ((unsigned long) bnapi->status_blk.msi +
373 (BNX2_SBLK_MSIX_ALIGN_SIZE * sb_id));
374 cp->irq_arr[0].status_blk_num = sb_id;
375 cp->num_irq = 1;
376}
377
378static int bnx2_register_cnic(struct net_device *dev, struct cnic_ops *ops,
379 void *data)
380{
381 struct bnx2 *bp = netdev_priv(dev);
382 struct cnic_eth_dev *cp = &bp->cnic_eth_dev;
383
384 if (ops == NULL)
385 return -EINVAL;
386
387 if (cp->drv_state & CNIC_DRV_STATE_REGD)
388 return -EBUSY;
389
Michael Chan41c21782011-07-13 17:24:22 +0000390 if (!bnx2_reg_rd_ind(bp, BNX2_FW_MAX_ISCSI_CONN))
391 return -ENODEV;
392
Michael Chan4edd4732009-06-08 18:14:42 -0700393 bp->cnic_data = data;
394 rcu_assign_pointer(bp->cnic_ops, ops);
395
396 cp->num_irq = 0;
397 cp->drv_state = CNIC_DRV_STATE_REGD;
398
399 bnx2_setup_cnic_irq_info(bp);
400
401 return 0;
402}
403
404static int bnx2_unregister_cnic(struct net_device *dev)
405{
406 struct bnx2 *bp = netdev_priv(dev);
407 struct bnx2_napi *bnapi = &bp->bnx2_napi[0];
408 struct cnic_eth_dev *cp = &bp->cnic_eth_dev;
409
Michael Chanc5a88952009-08-14 15:49:45 +0000410 mutex_lock(&bp->cnic_lock);
Michael Chan4edd4732009-06-08 18:14:42 -0700411 cp->drv_state = 0;
412 bnapi->cnic_present = 0;
Eric Dumazet2cfa5a02011-11-23 07:09:32 +0000413 RCU_INIT_POINTER(bp->cnic_ops, NULL);
Michael Chanc5a88952009-08-14 15:49:45 +0000414 mutex_unlock(&bp->cnic_lock);
Michael Chan4edd4732009-06-08 18:14:42 -0700415 synchronize_rcu();
416 return 0;
417}
418
stephen hemminger61c2fc42013-04-10 10:53:40 +0000419static struct cnic_eth_dev *bnx2_cnic_probe(struct net_device *dev)
Michael Chan4edd4732009-06-08 18:14:42 -0700420{
421 struct bnx2 *bp = netdev_priv(dev);
422 struct cnic_eth_dev *cp = &bp->cnic_eth_dev;
423
Michael Chan7625eb22011-06-08 19:29:36 +0000424 if (!cp->max_iscsi_conn)
425 return NULL;
426
Michael Chan4edd4732009-06-08 18:14:42 -0700427 cp->drv_owner = THIS_MODULE;
428 cp->chip_id = bp->chip_id;
429 cp->pdev = bp->pdev;
430 cp->io_base = bp->regview;
431 cp->drv_ctl = bnx2_drv_ctl;
432 cp->drv_register_cnic = bnx2_register_cnic;
433 cp->drv_unregister_cnic = bnx2_unregister_cnic;
434
435 return cp;
436}
Michael Chan4edd4732009-06-08 18:14:42 -0700437
438static void
439bnx2_cnic_stop(struct bnx2 *bp)
440{
441 struct cnic_ops *c_ops;
442 struct cnic_ctl_info info;
443
Michael Chanc5a88952009-08-14 15:49:45 +0000444 mutex_lock(&bp->cnic_lock);
Eric Dumazet13707f92011-01-26 19:28:23 +0000445 c_ops = rcu_dereference_protected(bp->cnic_ops,
446 lockdep_is_held(&bp->cnic_lock));
Michael Chan4edd4732009-06-08 18:14:42 -0700447 if (c_ops) {
448 info.cmd = CNIC_CTL_STOP_CMD;
449 c_ops->cnic_ctl(bp->cnic_data, &info);
450 }
Michael Chanc5a88952009-08-14 15:49:45 +0000451 mutex_unlock(&bp->cnic_lock);
Michael Chan4edd4732009-06-08 18:14:42 -0700452}
453
454static void
455bnx2_cnic_start(struct bnx2 *bp)
456{
457 struct cnic_ops *c_ops;
458 struct cnic_ctl_info info;
459
Michael Chanc5a88952009-08-14 15:49:45 +0000460 mutex_lock(&bp->cnic_lock);
Eric Dumazet13707f92011-01-26 19:28:23 +0000461 c_ops = rcu_dereference_protected(bp->cnic_ops,
462 lockdep_is_held(&bp->cnic_lock));
Michael Chan4edd4732009-06-08 18:14:42 -0700463 if (c_ops) {
464 if (!(bp->flags & BNX2_FLAG_USING_MSIX)) {
465 struct bnx2_napi *bnapi = &bp->bnx2_napi[0];
466
467 bnapi->cnic_tag = bnapi->last_status_idx;
468 }
469 info.cmd = CNIC_CTL_START_CMD;
470 c_ops->cnic_ctl(bp->cnic_data, &info);
471 }
Michael Chanc5a88952009-08-14 15:49:45 +0000472 mutex_unlock(&bp->cnic_lock);
Michael Chan4edd4732009-06-08 18:14:42 -0700473}
474
475#else
476
477static void
478bnx2_cnic_stop(struct bnx2 *bp)
479{
480}
481
482static void
483bnx2_cnic_start(struct bnx2 *bp)
484{
485}
486
487#endif
488
Michael Chanb6016b72005-05-26 13:03:09 -0700489static int
490bnx2_read_phy(struct bnx2 *bp, u32 reg, u32 *val)
491{
492 u32 val1;
493 int i, ret;
494
Michael Chan583c28e2008-01-21 19:51:35 -0800495 if (bp->phy_flags & BNX2_PHY_FLAG_INT_MODE_AUTO_POLLING) {
Michael Chane503e062012-12-06 10:33:08 +0000496 val1 = BNX2_RD(bp, BNX2_EMAC_MDIO_MODE);
Michael Chanb6016b72005-05-26 13:03:09 -0700497 val1 &= ~BNX2_EMAC_MDIO_MODE_AUTO_POLL;
498
Michael Chane503e062012-12-06 10:33:08 +0000499 BNX2_WR(bp, BNX2_EMAC_MDIO_MODE, val1);
500 BNX2_RD(bp, BNX2_EMAC_MDIO_MODE);
Michael Chanb6016b72005-05-26 13:03:09 -0700501
502 udelay(40);
503 }
504
505 val1 = (bp->phy_addr << 21) | (reg << 16) |
506 BNX2_EMAC_MDIO_COMM_COMMAND_READ | BNX2_EMAC_MDIO_COMM_DISEXT |
507 BNX2_EMAC_MDIO_COMM_START_BUSY;
Michael Chane503e062012-12-06 10:33:08 +0000508 BNX2_WR(bp, BNX2_EMAC_MDIO_COMM, val1);
Michael Chanb6016b72005-05-26 13:03:09 -0700509
510 for (i = 0; i < 50; i++) {
511 udelay(10);
512
Michael Chane503e062012-12-06 10:33:08 +0000513 val1 = BNX2_RD(bp, BNX2_EMAC_MDIO_COMM);
Michael Chanb6016b72005-05-26 13:03:09 -0700514 if (!(val1 & BNX2_EMAC_MDIO_COMM_START_BUSY)) {
515 udelay(5);
516
Michael Chane503e062012-12-06 10:33:08 +0000517 val1 = BNX2_RD(bp, BNX2_EMAC_MDIO_COMM);
Michael Chanb6016b72005-05-26 13:03:09 -0700518 val1 &= BNX2_EMAC_MDIO_COMM_DATA;
519
520 break;
521 }
522 }
523
524 if (val1 & BNX2_EMAC_MDIO_COMM_START_BUSY) {
525 *val = 0x0;
526 ret = -EBUSY;
527 }
528 else {
529 *val = val1;
530 ret = 0;
531 }
532
Michael Chan583c28e2008-01-21 19:51:35 -0800533 if (bp->phy_flags & BNX2_PHY_FLAG_INT_MODE_AUTO_POLLING) {
Michael Chane503e062012-12-06 10:33:08 +0000534 val1 = BNX2_RD(bp, BNX2_EMAC_MDIO_MODE);
Michael Chanb6016b72005-05-26 13:03:09 -0700535 val1 |= BNX2_EMAC_MDIO_MODE_AUTO_POLL;
536
Michael Chane503e062012-12-06 10:33:08 +0000537 BNX2_WR(bp, BNX2_EMAC_MDIO_MODE, val1);
538 BNX2_RD(bp, BNX2_EMAC_MDIO_MODE);
Michael Chanb6016b72005-05-26 13:03:09 -0700539
540 udelay(40);
541 }
542
543 return ret;
544}
545
546static int
547bnx2_write_phy(struct bnx2 *bp, u32 reg, u32 val)
548{
549 u32 val1;
550 int i, ret;
551
Michael Chan583c28e2008-01-21 19:51:35 -0800552 if (bp->phy_flags & BNX2_PHY_FLAG_INT_MODE_AUTO_POLLING) {
Michael Chane503e062012-12-06 10:33:08 +0000553 val1 = BNX2_RD(bp, BNX2_EMAC_MDIO_MODE);
Michael Chanb6016b72005-05-26 13:03:09 -0700554 val1 &= ~BNX2_EMAC_MDIO_MODE_AUTO_POLL;
555
Michael Chane503e062012-12-06 10:33:08 +0000556 BNX2_WR(bp, BNX2_EMAC_MDIO_MODE, val1);
557 BNX2_RD(bp, BNX2_EMAC_MDIO_MODE);
Michael Chanb6016b72005-05-26 13:03:09 -0700558
559 udelay(40);
560 }
561
562 val1 = (bp->phy_addr << 21) | (reg << 16) | val |
563 BNX2_EMAC_MDIO_COMM_COMMAND_WRITE |
564 BNX2_EMAC_MDIO_COMM_START_BUSY | BNX2_EMAC_MDIO_COMM_DISEXT;
Michael Chane503e062012-12-06 10:33:08 +0000565 BNX2_WR(bp, BNX2_EMAC_MDIO_COMM, val1);
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400566
Michael Chanb6016b72005-05-26 13:03:09 -0700567 for (i = 0; i < 50; i++) {
568 udelay(10);
569
Michael Chane503e062012-12-06 10:33:08 +0000570 val1 = BNX2_RD(bp, BNX2_EMAC_MDIO_COMM);
Michael Chanb6016b72005-05-26 13:03:09 -0700571 if (!(val1 & BNX2_EMAC_MDIO_COMM_START_BUSY)) {
572 udelay(5);
573 break;
574 }
575 }
576
577 if (val1 & BNX2_EMAC_MDIO_COMM_START_BUSY)
578 ret = -EBUSY;
579 else
580 ret = 0;
581
Michael Chan583c28e2008-01-21 19:51:35 -0800582 if (bp->phy_flags & BNX2_PHY_FLAG_INT_MODE_AUTO_POLLING) {
Michael Chane503e062012-12-06 10:33:08 +0000583 val1 = BNX2_RD(bp, BNX2_EMAC_MDIO_MODE);
Michael Chanb6016b72005-05-26 13:03:09 -0700584 val1 |= BNX2_EMAC_MDIO_MODE_AUTO_POLL;
585
Michael Chane503e062012-12-06 10:33:08 +0000586 BNX2_WR(bp, BNX2_EMAC_MDIO_MODE, val1);
587 BNX2_RD(bp, BNX2_EMAC_MDIO_MODE);
Michael Chanb6016b72005-05-26 13:03:09 -0700588
589 udelay(40);
590 }
591
592 return ret;
593}
594
595static void
596bnx2_disable_int(struct bnx2 *bp)
597{
Michael Chanb4b36042007-12-20 19:59:30 -0800598 int i;
599 struct bnx2_napi *bnapi;
600
601 for (i = 0; i < bp->irq_nvecs; i++) {
602 bnapi = &bp->bnx2_napi[i];
Michael Chane503e062012-12-06 10:33:08 +0000603 BNX2_WR(bp, BNX2_PCICFG_INT_ACK_CMD, bnapi->int_num |
Michael Chanb4b36042007-12-20 19:59:30 -0800604 BNX2_PCICFG_INT_ACK_CMD_MASK_INT);
605 }
Michael Chane503e062012-12-06 10:33:08 +0000606 BNX2_RD(bp, BNX2_PCICFG_INT_ACK_CMD);
Michael Chanb6016b72005-05-26 13:03:09 -0700607}
608
609static void
610bnx2_enable_int(struct bnx2 *bp)
611{
Michael Chanb4b36042007-12-20 19:59:30 -0800612 int i;
613 struct bnx2_napi *bnapi;
Michael Chan1269a8a2006-01-23 16:11:03 -0800614
Michael Chanb4b36042007-12-20 19:59:30 -0800615 for (i = 0; i < bp->irq_nvecs; i++) {
616 bnapi = &bp->bnx2_napi[i];
Michael Chan35efa7c2007-12-20 19:56:37 -0800617
Michael Chane503e062012-12-06 10:33:08 +0000618 BNX2_WR(bp, BNX2_PCICFG_INT_ACK_CMD, bnapi->int_num |
619 BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
620 BNX2_PCICFG_INT_ACK_CMD_MASK_INT |
621 bnapi->last_status_idx);
Michael Chanb6016b72005-05-26 13:03:09 -0700622
Michael Chane503e062012-12-06 10:33:08 +0000623 BNX2_WR(bp, BNX2_PCICFG_INT_ACK_CMD, bnapi->int_num |
624 BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
625 bnapi->last_status_idx);
Michael Chanb4b36042007-12-20 19:59:30 -0800626 }
Michael Chane503e062012-12-06 10:33:08 +0000627 BNX2_WR(bp, BNX2_HC_COMMAND, bp->hc_cmd | BNX2_HC_COMMAND_COAL_NOW);
Michael Chanb6016b72005-05-26 13:03:09 -0700628}
629
630static void
631bnx2_disable_int_sync(struct bnx2 *bp)
632{
Michael Chanb4b36042007-12-20 19:59:30 -0800633 int i;
634
Michael Chanb6016b72005-05-26 13:03:09 -0700635 atomic_inc(&bp->intr_sem);
Michael Chan37675462009-08-21 16:20:44 +0000636 if (!netif_running(bp->dev))
637 return;
638
Michael Chanb6016b72005-05-26 13:03:09 -0700639 bnx2_disable_int(bp);
Michael Chanb4b36042007-12-20 19:59:30 -0800640 for (i = 0; i < bp->irq_nvecs; i++)
641 synchronize_irq(bp->irq_tbl[i].vector);
Michael Chanb6016b72005-05-26 13:03:09 -0700642}
643
644static void
Michael Chan35efa7c2007-12-20 19:56:37 -0800645bnx2_napi_disable(struct bnx2 *bp)
646{
Michael Chanb4b36042007-12-20 19:59:30 -0800647 int i;
648
649 for (i = 0; i < bp->irq_nvecs; i++)
650 napi_disable(&bp->bnx2_napi[i].napi);
Michael Chan35efa7c2007-12-20 19:56:37 -0800651}
652
653static void
654bnx2_napi_enable(struct bnx2 *bp)
655{
Michael Chanb4b36042007-12-20 19:59:30 -0800656 int i;
657
658 for (i = 0; i < bp->irq_nvecs; i++)
659 napi_enable(&bp->bnx2_napi[i].napi);
Michael Chan35efa7c2007-12-20 19:56:37 -0800660}
661
662static void
Michael Chan212f9932010-04-27 11:28:10 +0000663bnx2_netif_stop(struct bnx2 *bp, bool stop_cnic)
Michael Chanb6016b72005-05-26 13:03:09 -0700664{
Michael Chan212f9932010-04-27 11:28:10 +0000665 if (stop_cnic)
666 bnx2_cnic_stop(bp);
Michael Chanb6016b72005-05-26 13:03:09 -0700667 if (netif_running(bp->dev)) {
Michael Chan35efa7c2007-12-20 19:56:37 -0800668 bnx2_napi_disable(bp);
Michael Chanb6016b72005-05-26 13:03:09 -0700669 netif_tx_disable(bp->dev);
Michael Chanb6016b72005-05-26 13:03:09 -0700670 }
Michael Chanb7466562009-12-20 18:40:18 -0800671 bnx2_disable_int_sync(bp);
Michael Chana0ba6762010-05-17 17:34:43 -0700672 netif_carrier_off(bp->dev); /* prevent tx timeout */
Michael Chanb6016b72005-05-26 13:03:09 -0700673}
674
675static void
Michael Chan212f9932010-04-27 11:28:10 +0000676bnx2_netif_start(struct bnx2 *bp, bool start_cnic)
Michael Chanb6016b72005-05-26 13:03:09 -0700677{
678 if (atomic_dec_and_test(&bp->intr_sem)) {
679 if (netif_running(bp->dev)) {
Benjamin Li706bf242008-07-18 17:55:11 -0700680 netif_tx_wake_all_queues(bp->dev);
Michael Chana0ba6762010-05-17 17:34:43 -0700681 spin_lock_bh(&bp->phy_lock);
682 if (bp->link_up)
683 netif_carrier_on(bp->dev);
684 spin_unlock_bh(&bp->phy_lock);
Michael Chan35efa7c2007-12-20 19:56:37 -0800685 bnx2_napi_enable(bp);
Michael Chanb6016b72005-05-26 13:03:09 -0700686 bnx2_enable_int(bp);
Michael Chan212f9932010-04-27 11:28:10 +0000687 if (start_cnic)
688 bnx2_cnic_start(bp);
Michael Chanb6016b72005-05-26 13:03:09 -0700689 }
690 }
691}
692
693static void
Michael Chan35e90102008-06-19 16:37:42 -0700694bnx2_free_tx_mem(struct bnx2 *bp)
695{
696 int i;
697
698 for (i = 0; i < bp->num_tx_rings; i++) {
699 struct bnx2_napi *bnapi = &bp->bnx2_napi[i];
700 struct bnx2_tx_ring_info *txr = &bnapi->tx_ring;
701
702 if (txr->tx_desc_ring) {
Stanislaw Gruszka36227e82010-07-15 04:25:50 +0000703 dma_free_coherent(&bp->pdev->dev, TXBD_RING_SIZE,
704 txr->tx_desc_ring,
705 txr->tx_desc_mapping);
Michael Chan35e90102008-06-19 16:37:42 -0700706 txr->tx_desc_ring = NULL;
707 }
708 kfree(txr->tx_buf_ring);
709 txr->tx_buf_ring = NULL;
710 }
711}
712
Michael Chanbb4f98a2008-06-19 16:38:19 -0700713static void
714bnx2_free_rx_mem(struct bnx2 *bp)
715{
716 int i;
717
718 for (i = 0; i < bp->num_rx_rings; i++) {
719 struct bnx2_napi *bnapi = &bp->bnx2_napi[i];
720 struct bnx2_rx_ring_info *rxr = &bnapi->rx_ring;
721 int j;
722
723 for (j = 0; j < bp->rx_max_ring; j++) {
724 if (rxr->rx_desc_ring[j])
Stanislaw Gruszka36227e82010-07-15 04:25:50 +0000725 dma_free_coherent(&bp->pdev->dev, RXBD_RING_SIZE,
726 rxr->rx_desc_ring[j],
727 rxr->rx_desc_mapping[j]);
Michael Chanbb4f98a2008-06-19 16:38:19 -0700728 rxr->rx_desc_ring[j] = NULL;
729 }
Breno Leitao25b0b992009-06-08 10:30:19 +0000730 vfree(rxr->rx_buf_ring);
Michael Chanbb4f98a2008-06-19 16:38:19 -0700731 rxr->rx_buf_ring = NULL;
732
733 for (j = 0; j < bp->rx_max_pg_ring; j++) {
734 if (rxr->rx_pg_desc_ring[j])
Stanislaw Gruszka36227e82010-07-15 04:25:50 +0000735 dma_free_coherent(&bp->pdev->dev, RXBD_RING_SIZE,
736 rxr->rx_pg_desc_ring[j],
737 rxr->rx_pg_desc_mapping[j]);
Michael Chan3298a732008-12-17 19:06:08 -0800738 rxr->rx_pg_desc_ring[j] = NULL;
Michael Chanbb4f98a2008-06-19 16:38:19 -0700739 }
Breno Leitao25b0b992009-06-08 10:30:19 +0000740 vfree(rxr->rx_pg_ring);
Michael Chanbb4f98a2008-06-19 16:38:19 -0700741 rxr->rx_pg_ring = NULL;
742 }
743}
744
Michael Chan35e90102008-06-19 16:37:42 -0700745static int
746bnx2_alloc_tx_mem(struct bnx2 *bp)
747{
748 int i;
749
750 for (i = 0; i < bp->num_tx_rings; i++) {
751 struct bnx2_napi *bnapi = &bp->bnx2_napi[i];
752 struct bnx2_tx_ring_info *txr = &bnapi->tx_ring;
753
754 txr->tx_buf_ring = kzalloc(SW_TXBD_RING_SIZE, GFP_KERNEL);
755 if (txr->tx_buf_ring == NULL)
756 return -ENOMEM;
757
758 txr->tx_desc_ring =
Stanislaw Gruszka36227e82010-07-15 04:25:50 +0000759 dma_alloc_coherent(&bp->pdev->dev, TXBD_RING_SIZE,
760 &txr->tx_desc_mapping, GFP_KERNEL);
Michael Chan35e90102008-06-19 16:37:42 -0700761 if (txr->tx_desc_ring == NULL)
762 return -ENOMEM;
763 }
764 return 0;
765}
766
Michael Chanbb4f98a2008-06-19 16:38:19 -0700767static int
768bnx2_alloc_rx_mem(struct bnx2 *bp)
769{
770 int i;
771
772 for (i = 0; i < bp->num_rx_rings; i++) {
773 struct bnx2_napi *bnapi = &bp->bnx2_napi[i];
774 struct bnx2_rx_ring_info *rxr = &bnapi->rx_ring;
775 int j;
776
777 rxr->rx_buf_ring =
Eric Dumazet89bf67f2010-11-22 00:15:06 +0000778 vzalloc(SW_RXBD_RING_SIZE * bp->rx_max_ring);
Michael Chanbb4f98a2008-06-19 16:38:19 -0700779 if (rxr->rx_buf_ring == NULL)
780 return -ENOMEM;
781
Michael Chanbb4f98a2008-06-19 16:38:19 -0700782 for (j = 0; j < bp->rx_max_ring; j++) {
783 rxr->rx_desc_ring[j] =
Stanislaw Gruszka36227e82010-07-15 04:25:50 +0000784 dma_alloc_coherent(&bp->pdev->dev,
785 RXBD_RING_SIZE,
786 &rxr->rx_desc_mapping[j],
787 GFP_KERNEL);
Michael Chanbb4f98a2008-06-19 16:38:19 -0700788 if (rxr->rx_desc_ring[j] == NULL)
789 return -ENOMEM;
790
791 }
792
793 if (bp->rx_pg_ring_size) {
Eric Dumazet89bf67f2010-11-22 00:15:06 +0000794 rxr->rx_pg_ring = vzalloc(SW_RXPG_RING_SIZE *
Michael Chanbb4f98a2008-06-19 16:38:19 -0700795 bp->rx_max_pg_ring);
796 if (rxr->rx_pg_ring == NULL)
797 return -ENOMEM;
798
Michael Chanbb4f98a2008-06-19 16:38:19 -0700799 }
800
801 for (j = 0; j < bp->rx_max_pg_ring; j++) {
802 rxr->rx_pg_desc_ring[j] =
Stanislaw Gruszka36227e82010-07-15 04:25:50 +0000803 dma_alloc_coherent(&bp->pdev->dev,
804 RXBD_RING_SIZE,
805 &rxr->rx_pg_desc_mapping[j],
806 GFP_KERNEL);
Michael Chanbb4f98a2008-06-19 16:38:19 -0700807 if (rxr->rx_pg_desc_ring[j] == NULL)
808 return -ENOMEM;
809
810 }
811 }
812 return 0;
813}
814
Michael Chan35e90102008-06-19 16:37:42 -0700815static void
Michael Chanb6016b72005-05-26 13:03:09 -0700816bnx2_free_mem(struct bnx2 *bp)
817{
Michael Chan13daffa2006-03-20 17:49:20 -0800818 int i;
Michael Chan43e80b82008-06-19 16:41:08 -0700819 struct bnx2_napi *bnapi = &bp->bnx2_napi[0];
Michael Chan13daffa2006-03-20 17:49:20 -0800820
Michael Chan35e90102008-06-19 16:37:42 -0700821 bnx2_free_tx_mem(bp);
Michael Chanbb4f98a2008-06-19 16:38:19 -0700822 bnx2_free_rx_mem(bp);
Michael Chan35e90102008-06-19 16:37:42 -0700823
Michael Chan59b47d82006-11-19 14:10:45 -0800824 for (i = 0; i < bp->ctx_pages; i++) {
825 if (bp->ctx_blk[i]) {
Michael Chan2bc40782012-12-06 10:33:09 +0000826 dma_free_coherent(&bp->pdev->dev, BNX2_PAGE_SIZE,
Stanislaw Gruszka36227e82010-07-15 04:25:50 +0000827 bp->ctx_blk[i],
828 bp->ctx_blk_mapping[i]);
Michael Chan59b47d82006-11-19 14:10:45 -0800829 bp->ctx_blk[i] = NULL;
830 }
831 }
Michael Chan43e80b82008-06-19 16:41:08 -0700832 if (bnapi->status_blk.msi) {
Stanislaw Gruszka36227e82010-07-15 04:25:50 +0000833 dma_free_coherent(&bp->pdev->dev, bp->status_stats_size,
834 bnapi->status_blk.msi,
835 bp->status_blk_mapping);
Michael Chan43e80b82008-06-19 16:41:08 -0700836 bnapi->status_blk.msi = NULL;
Michael Chan0f31f992006-03-23 01:12:38 -0800837 bp->stats_blk = NULL;
Michael Chanb6016b72005-05-26 13:03:09 -0700838 }
Michael Chanb6016b72005-05-26 13:03:09 -0700839}
840
841static int
842bnx2_alloc_mem(struct bnx2 *bp)
843{
Michael Chan35e90102008-06-19 16:37:42 -0700844 int i, status_blk_size, err;
Michael Chan43e80b82008-06-19 16:41:08 -0700845 struct bnx2_napi *bnapi;
846 void *status_blk;
Michael Chanb6016b72005-05-26 13:03:09 -0700847
Michael Chan0f31f992006-03-23 01:12:38 -0800848 /* Combine status and statistics blocks into one allocation. */
849 status_blk_size = L1_CACHE_ALIGN(sizeof(struct status_block));
David S. Millerf86e82f2008-01-21 17:15:40 -0800850 if (bp->flags & BNX2_FLAG_MSIX_CAP)
Michael Chanb4b36042007-12-20 19:59:30 -0800851 status_blk_size = L1_CACHE_ALIGN(BNX2_MAX_MSIX_HW_VEC *
852 BNX2_SBLK_MSIX_ALIGN_SIZE);
Michael Chan0f31f992006-03-23 01:12:38 -0800853 bp->status_stats_size = status_blk_size +
854 sizeof(struct statistics_block);
855
Joe Perchesede23fa2013-08-26 22:45:23 -0700856 status_blk = dma_zalloc_coherent(&bp->pdev->dev, bp->status_stats_size,
857 &bp->status_blk_mapping, GFP_KERNEL);
Michael Chan43e80b82008-06-19 16:41:08 -0700858 if (status_blk == NULL)
Michael Chanb6016b72005-05-26 13:03:09 -0700859 goto alloc_mem_err;
860
Michael Chan43e80b82008-06-19 16:41:08 -0700861 bnapi = &bp->bnx2_napi[0];
862 bnapi->status_blk.msi = status_blk;
863 bnapi->hw_tx_cons_ptr =
864 &bnapi->status_blk.msi->status_tx_quick_consumer_index0;
865 bnapi->hw_rx_cons_ptr =
866 &bnapi->status_blk.msi->status_rx_quick_consumer_index0;
David S. Millerf86e82f2008-01-21 17:15:40 -0800867 if (bp->flags & BNX2_FLAG_MSIX_CAP) {
Michael Chan379b39a2010-07-19 14:15:03 +0000868 for (i = 1; i < bp->irq_nvecs; i++) {
Michael Chan43e80b82008-06-19 16:41:08 -0700869 struct status_block_msix *sblk;
Michael Chanb4b36042007-12-20 19:59:30 -0800870
Michael Chan43e80b82008-06-19 16:41:08 -0700871 bnapi = &bp->bnx2_napi[i];
872
Joe Perches64699332012-06-04 12:44:16 +0000873 sblk = (status_blk + BNX2_SBLK_MSIX_ALIGN_SIZE * i);
Michael Chan43e80b82008-06-19 16:41:08 -0700874 bnapi->status_blk.msix = sblk;
875 bnapi->hw_tx_cons_ptr =
876 &sblk->status_tx_quick_consumer_index;
877 bnapi->hw_rx_cons_ptr =
878 &sblk->status_rx_quick_consumer_index;
Michael Chanb4b36042007-12-20 19:59:30 -0800879 bnapi->int_num = i << 24;
880 }
881 }
Michael Chan35efa7c2007-12-20 19:56:37 -0800882
Michael Chan43e80b82008-06-19 16:41:08 -0700883 bp->stats_blk = status_blk + status_blk_size;
Michael Chanb6016b72005-05-26 13:03:09 -0700884
Michael Chan0f31f992006-03-23 01:12:38 -0800885 bp->stats_blk_mapping = bp->status_blk_mapping + status_blk_size;
Michael Chanb6016b72005-05-26 13:03:09 -0700886
Michael Chan4ce45e02012-12-06 10:33:10 +0000887 if (BNX2_CHIP(bp) == BNX2_CHIP_5709) {
Michael Chan2bc40782012-12-06 10:33:09 +0000888 bp->ctx_pages = 0x2000 / BNX2_PAGE_SIZE;
Michael Chan59b47d82006-11-19 14:10:45 -0800889 if (bp->ctx_pages == 0)
890 bp->ctx_pages = 1;
891 for (i = 0; i < bp->ctx_pages; i++) {
Stanislaw Gruszka36227e82010-07-15 04:25:50 +0000892 bp->ctx_blk[i] = dma_alloc_coherent(&bp->pdev->dev,
Michael Chan2bc40782012-12-06 10:33:09 +0000893 BNX2_PAGE_SIZE,
Stanislaw Gruszka36227e82010-07-15 04:25:50 +0000894 &bp->ctx_blk_mapping[i],
895 GFP_KERNEL);
Michael Chan59b47d82006-11-19 14:10:45 -0800896 if (bp->ctx_blk[i] == NULL)
897 goto alloc_mem_err;
898 }
899 }
Michael Chan35e90102008-06-19 16:37:42 -0700900
Michael Chanbb4f98a2008-06-19 16:38:19 -0700901 err = bnx2_alloc_rx_mem(bp);
902 if (err)
903 goto alloc_mem_err;
904
Michael Chan35e90102008-06-19 16:37:42 -0700905 err = bnx2_alloc_tx_mem(bp);
906 if (err)
907 goto alloc_mem_err;
908
Michael Chanb6016b72005-05-26 13:03:09 -0700909 return 0;
910
911alloc_mem_err:
912 bnx2_free_mem(bp);
913 return -ENOMEM;
914}
915
916static void
Michael Chane3648b32005-11-04 08:51:21 -0800917bnx2_report_fw_link(struct bnx2 *bp)
918{
919 u32 fw_link_status = 0;
920
Michael Chan583c28e2008-01-21 19:51:35 -0800921 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
Michael Chan0d8a6572007-07-07 22:49:43 -0700922 return;
923
Michael Chane3648b32005-11-04 08:51:21 -0800924 if (bp->link_up) {
925 u32 bmsr;
926
927 switch (bp->line_speed) {
928 case SPEED_10:
929 if (bp->duplex == DUPLEX_HALF)
930 fw_link_status = BNX2_LINK_STATUS_10HALF;
931 else
932 fw_link_status = BNX2_LINK_STATUS_10FULL;
933 break;
934 case SPEED_100:
935 if (bp->duplex == DUPLEX_HALF)
936 fw_link_status = BNX2_LINK_STATUS_100HALF;
937 else
938 fw_link_status = BNX2_LINK_STATUS_100FULL;
939 break;
940 case SPEED_1000:
941 if (bp->duplex == DUPLEX_HALF)
942 fw_link_status = BNX2_LINK_STATUS_1000HALF;
943 else
944 fw_link_status = BNX2_LINK_STATUS_1000FULL;
945 break;
946 case SPEED_2500:
947 if (bp->duplex == DUPLEX_HALF)
948 fw_link_status = BNX2_LINK_STATUS_2500HALF;
949 else
950 fw_link_status = BNX2_LINK_STATUS_2500FULL;
951 break;
952 }
953
954 fw_link_status |= BNX2_LINK_STATUS_LINK_UP;
955
956 if (bp->autoneg) {
957 fw_link_status |= BNX2_LINK_STATUS_AN_ENABLED;
958
Michael Chanca58c3a2007-05-03 13:22:52 -0700959 bnx2_read_phy(bp, bp->mii_bmsr, &bmsr);
960 bnx2_read_phy(bp, bp->mii_bmsr, &bmsr);
Michael Chane3648b32005-11-04 08:51:21 -0800961
962 if (!(bmsr & BMSR_ANEGCOMPLETE) ||
Michael Chan583c28e2008-01-21 19:51:35 -0800963 bp->phy_flags & BNX2_PHY_FLAG_PARALLEL_DETECT)
Michael Chane3648b32005-11-04 08:51:21 -0800964 fw_link_status |= BNX2_LINK_STATUS_PARALLEL_DET;
965 else
966 fw_link_status |= BNX2_LINK_STATUS_AN_COMPLETE;
967 }
968 }
969 else
970 fw_link_status = BNX2_LINK_STATUS_LINK_DOWN;
971
Michael Chan2726d6e2008-01-29 21:35:05 -0800972 bnx2_shmem_wr(bp, BNX2_LINK_STATUS, fw_link_status);
Michael Chane3648b32005-11-04 08:51:21 -0800973}
974
Michael Chan9b1084b2007-07-07 22:50:37 -0700975static char *
976bnx2_xceiver_str(struct bnx2 *bp)
977{
Eric Dumazet807540b2010-09-23 05:40:09 +0000978 return (bp->phy_port == PORT_FIBRE) ? "SerDes" :
Michael Chan583c28e2008-01-21 19:51:35 -0800979 ((bp->phy_flags & BNX2_PHY_FLAG_SERDES) ? "Remote Copper" :
Eric Dumazet807540b2010-09-23 05:40:09 +0000980 "Copper");
Michael Chan9b1084b2007-07-07 22:50:37 -0700981}
982
Michael Chane3648b32005-11-04 08:51:21 -0800983static void
Michael Chanb6016b72005-05-26 13:03:09 -0700984bnx2_report_link(struct bnx2 *bp)
985{
986 if (bp->link_up) {
987 netif_carrier_on(bp->dev);
Joe Perches3a9c6a42010-02-17 15:01:51 +0000988 netdev_info(bp->dev, "NIC %s Link is Up, %d Mbps %s duplex",
989 bnx2_xceiver_str(bp),
990 bp->line_speed,
991 bp->duplex == DUPLEX_FULL ? "full" : "half");
Michael Chanb6016b72005-05-26 13:03:09 -0700992
993 if (bp->flow_ctrl) {
994 if (bp->flow_ctrl & FLOW_CTRL_RX) {
Joe Perches3a9c6a42010-02-17 15:01:51 +0000995 pr_cont(", receive ");
Michael Chanb6016b72005-05-26 13:03:09 -0700996 if (bp->flow_ctrl & FLOW_CTRL_TX)
Joe Perches3a9c6a42010-02-17 15:01:51 +0000997 pr_cont("& transmit ");
Michael Chanb6016b72005-05-26 13:03:09 -0700998 }
999 else {
Joe Perches3a9c6a42010-02-17 15:01:51 +00001000 pr_cont(", transmit ");
Michael Chanb6016b72005-05-26 13:03:09 -07001001 }
Joe Perches3a9c6a42010-02-17 15:01:51 +00001002 pr_cont("flow control ON");
Michael Chanb6016b72005-05-26 13:03:09 -07001003 }
Joe Perches3a9c6a42010-02-17 15:01:51 +00001004 pr_cont("\n");
1005 } else {
Michael Chanb6016b72005-05-26 13:03:09 -07001006 netif_carrier_off(bp->dev);
Joe Perches3a9c6a42010-02-17 15:01:51 +00001007 netdev_err(bp->dev, "NIC %s Link is Down\n",
1008 bnx2_xceiver_str(bp));
Michael Chanb6016b72005-05-26 13:03:09 -07001009 }
Michael Chane3648b32005-11-04 08:51:21 -08001010
1011 bnx2_report_fw_link(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07001012}
1013
1014static void
1015bnx2_resolve_flow_ctrl(struct bnx2 *bp)
1016{
1017 u32 local_adv, remote_adv;
1018
1019 bp->flow_ctrl = 0;
Jeff Garzik6aa20a22006-09-13 13:24:59 -04001020 if ((bp->autoneg & (AUTONEG_SPEED | AUTONEG_FLOW_CTRL)) !=
Michael Chanb6016b72005-05-26 13:03:09 -07001021 (AUTONEG_SPEED | AUTONEG_FLOW_CTRL)) {
1022
1023 if (bp->duplex == DUPLEX_FULL) {
1024 bp->flow_ctrl = bp->req_flow_ctrl;
1025 }
1026 return;
1027 }
1028
1029 if (bp->duplex != DUPLEX_FULL) {
1030 return;
1031 }
1032
Michael Chan583c28e2008-01-21 19:51:35 -08001033 if ((bp->phy_flags & BNX2_PHY_FLAG_SERDES) &&
Michael Chan4ce45e02012-12-06 10:33:10 +00001034 (BNX2_CHIP(bp) == BNX2_CHIP_5708)) {
Michael Chan5b0c76a2005-11-04 08:45:49 -08001035 u32 val;
1036
1037 bnx2_read_phy(bp, BCM5708S_1000X_STAT1, &val);
1038 if (val & BCM5708S_1000X_STAT1_TX_PAUSE)
1039 bp->flow_ctrl |= FLOW_CTRL_TX;
1040 if (val & BCM5708S_1000X_STAT1_RX_PAUSE)
1041 bp->flow_ctrl |= FLOW_CTRL_RX;
1042 return;
1043 }
1044
Michael Chanca58c3a2007-05-03 13:22:52 -07001045 bnx2_read_phy(bp, bp->mii_adv, &local_adv);
1046 bnx2_read_phy(bp, bp->mii_lpa, &remote_adv);
Michael Chanb6016b72005-05-26 13:03:09 -07001047
Michael Chan583c28e2008-01-21 19:51:35 -08001048 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Michael Chanb6016b72005-05-26 13:03:09 -07001049 u32 new_local_adv = 0;
1050 u32 new_remote_adv = 0;
1051
1052 if (local_adv & ADVERTISE_1000XPAUSE)
1053 new_local_adv |= ADVERTISE_PAUSE_CAP;
1054 if (local_adv & ADVERTISE_1000XPSE_ASYM)
1055 new_local_adv |= ADVERTISE_PAUSE_ASYM;
1056 if (remote_adv & ADVERTISE_1000XPAUSE)
1057 new_remote_adv |= ADVERTISE_PAUSE_CAP;
1058 if (remote_adv & ADVERTISE_1000XPSE_ASYM)
1059 new_remote_adv |= ADVERTISE_PAUSE_ASYM;
1060
1061 local_adv = new_local_adv;
1062 remote_adv = new_remote_adv;
1063 }
1064
1065 /* See Table 28B-3 of 802.3ab-1999 spec. */
1066 if (local_adv & ADVERTISE_PAUSE_CAP) {
1067 if(local_adv & ADVERTISE_PAUSE_ASYM) {
1068 if (remote_adv & ADVERTISE_PAUSE_CAP) {
1069 bp->flow_ctrl = FLOW_CTRL_TX | FLOW_CTRL_RX;
1070 }
1071 else if (remote_adv & ADVERTISE_PAUSE_ASYM) {
1072 bp->flow_ctrl = FLOW_CTRL_RX;
1073 }
1074 }
1075 else {
1076 if (remote_adv & ADVERTISE_PAUSE_CAP) {
1077 bp->flow_ctrl = FLOW_CTRL_TX | FLOW_CTRL_RX;
1078 }
1079 }
1080 }
1081 else if (local_adv & ADVERTISE_PAUSE_ASYM) {
1082 if ((remote_adv & ADVERTISE_PAUSE_CAP) &&
1083 (remote_adv & ADVERTISE_PAUSE_ASYM)) {
1084
1085 bp->flow_ctrl = FLOW_CTRL_TX;
1086 }
1087 }
1088}
1089
1090static int
Michael Chan27a005b2007-05-03 13:23:41 -07001091bnx2_5709s_linkup(struct bnx2 *bp)
1092{
1093 u32 val, speed;
1094
1095 bp->link_up = 1;
1096
1097 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_GP_STATUS);
1098 bnx2_read_phy(bp, MII_BNX2_GP_TOP_AN_STATUS1, &val);
1099 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
1100
1101 if ((bp->autoneg & AUTONEG_SPEED) == 0) {
1102 bp->line_speed = bp->req_line_speed;
1103 bp->duplex = bp->req_duplex;
1104 return 0;
1105 }
1106 speed = val & MII_BNX2_GP_TOP_AN_SPEED_MSK;
1107 switch (speed) {
1108 case MII_BNX2_GP_TOP_AN_SPEED_10:
1109 bp->line_speed = SPEED_10;
1110 break;
1111 case MII_BNX2_GP_TOP_AN_SPEED_100:
1112 bp->line_speed = SPEED_100;
1113 break;
1114 case MII_BNX2_GP_TOP_AN_SPEED_1G:
1115 case MII_BNX2_GP_TOP_AN_SPEED_1GKV:
1116 bp->line_speed = SPEED_1000;
1117 break;
1118 case MII_BNX2_GP_TOP_AN_SPEED_2_5G:
1119 bp->line_speed = SPEED_2500;
1120 break;
1121 }
1122 if (val & MII_BNX2_GP_TOP_AN_FD)
1123 bp->duplex = DUPLEX_FULL;
1124 else
1125 bp->duplex = DUPLEX_HALF;
1126 return 0;
1127}
1128
1129static int
Michael Chan5b0c76a2005-11-04 08:45:49 -08001130bnx2_5708s_linkup(struct bnx2 *bp)
1131{
1132 u32 val;
1133
1134 bp->link_up = 1;
1135 bnx2_read_phy(bp, BCM5708S_1000X_STAT1, &val);
1136 switch (val & BCM5708S_1000X_STAT1_SPEED_MASK) {
1137 case BCM5708S_1000X_STAT1_SPEED_10:
1138 bp->line_speed = SPEED_10;
1139 break;
1140 case BCM5708S_1000X_STAT1_SPEED_100:
1141 bp->line_speed = SPEED_100;
1142 break;
1143 case BCM5708S_1000X_STAT1_SPEED_1G:
1144 bp->line_speed = SPEED_1000;
1145 break;
1146 case BCM5708S_1000X_STAT1_SPEED_2G5:
1147 bp->line_speed = SPEED_2500;
1148 break;
1149 }
1150 if (val & BCM5708S_1000X_STAT1_FD)
1151 bp->duplex = DUPLEX_FULL;
1152 else
1153 bp->duplex = DUPLEX_HALF;
1154
1155 return 0;
1156}
1157
1158static int
1159bnx2_5706s_linkup(struct bnx2 *bp)
Michael Chanb6016b72005-05-26 13:03:09 -07001160{
1161 u32 bmcr, local_adv, remote_adv, common;
1162
1163 bp->link_up = 1;
1164 bp->line_speed = SPEED_1000;
1165
Michael Chanca58c3a2007-05-03 13:22:52 -07001166 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chanb6016b72005-05-26 13:03:09 -07001167 if (bmcr & BMCR_FULLDPLX) {
1168 bp->duplex = DUPLEX_FULL;
1169 }
1170 else {
1171 bp->duplex = DUPLEX_HALF;
1172 }
1173
1174 if (!(bmcr & BMCR_ANENABLE)) {
1175 return 0;
1176 }
1177
Michael Chanca58c3a2007-05-03 13:22:52 -07001178 bnx2_read_phy(bp, bp->mii_adv, &local_adv);
1179 bnx2_read_phy(bp, bp->mii_lpa, &remote_adv);
Michael Chanb6016b72005-05-26 13:03:09 -07001180
1181 common = local_adv & remote_adv;
1182 if (common & (ADVERTISE_1000XHALF | ADVERTISE_1000XFULL)) {
1183
1184 if (common & ADVERTISE_1000XFULL) {
1185 bp->duplex = DUPLEX_FULL;
1186 }
1187 else {
1188 bp->duplex = DUPLEX_HALF;
1189 }
1190 }
1191
1192 return 0;
1193}
1194
1195static int
1196bnx2_copper_linkup(struct bnx2 *bp)
1197{
1198 u32 bmcr;
1199
Michael Chan4016bad2013-12-31 23:22:34 -08001200 bp->phy_flags &= ~BNX2_PHY_FLAG_MDIX;
1201
Michael Chanca58c3a2007-05-03 13:22:52 -07001202 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chanb6016b72005-05-26 13:03:09 -07001203 if (bmcr & BMCR_ANENABLE) {
1204 u32 local_adv, remote_adv, common;
1205
1206 bnx2_read_phy(bp, MII_CTRL1000, &local_adv);
1207 bnx2_read_phy(bp, MII_STAT1000, &remote_adv);
1208
1209 common = local_adv & (remote_adv >> 2);
1210 if (common & ADVERTISE_1000FULL) {
1211 bp->line_speed = SPEED_1000;
1212 bp->duplex = DUPLEX_FULL;
1213 }
1214 else if (common & ADVERTISE_1000HALF) {
1215 bp->line_speed = SPEED_1000;
1216 bp->duplex = DUPLEX_HALF;
1217 }
1218 else {
Michael Chanca58c3a2007-05-03 13:22:52 -07001219 bnx2_read_phy(bp, bp->mii_adv, &local_adv);
1220 bnx2_read_phy(bp, bp->mii_lpa, &remote_adv);
Michael Chanb6016b72005-05-26 13:03:09 -07001221
1222 common = local_adv & remote_adv;
1223 if (common & ADVERTISE_100FULL) {
1224 bp->line_speed = SPEED_100;
1225 bp->duplex = DUPLEX_FULL;
1226 }
1227 else if (common & ADVERTISE_100HALF) {
1228 bp->line_speed = SPEED_100;
1229 bp->duplex = DUPLEX_HALF;
1230 }
1231 else if (common & ADVERTISE_10FULL) {
1232 bp->line_speed = SPEED_10;
1233 bp->duplex = DUPLEX_FULL;
1234 }
1235 else if (common & ADVERTISE_10HALF) {
1236 bp->line_speed = SPEED_10;
1237 bp->duplex = DUPLEX_HALF;
1238 }
1239 else {
1240 bp->line_speed = 0;
1241 bp->link_up = 0;
1242 }
1243 }
1244 }
1245 else {
1246 if (bmcr & BMCR_SPEED100) {
1247 bp->line_speed = SPEED_100;
1248 }
1249 else {
1250 bp->line_speed = SPEED_10;
1251 }
1252 if (bmcr & BMCR_FULLDPLX) {
1253 bp->duplex = DUPLEX_FULL;
1254 }
1255 else {
1256 bp->duplex = DUPLEX_HALF;
1257 }
1258 }
1259
Michael Chan4016bad2013-12-31 23:22:34 -08001260 if (bp->link_up) {
1261 u32 ext_status;
1262
1263 bnx2_read_phy(bp, MII_BNX2_EXT_STATUS, &ext_status);
1264 if (ext_status & EXT_STATUS_MDIX)
1265 bp->phy_flags |= BNX2_PHY_FLAG_MDIX;
1266 }
1267
Michael Chanb6016b72005-05-26 13:03:09 -07001268 return 0;
1269}
1270
Michael Chan83e3fc82008-01-29 21:37:17 -08001271static void
Michael Chanbb4f98a2008-06-19 16:38:19 -07001272bnx2_init_rx_context(struct bnx2 *bp, u32 cid)
Michael Chan83e3fc82008-01-29 21:37:17 -08001273{
Michael Chanbb4f98a2008-06-19 16:38:19 -07001274 u32 val, rx_cid_addr = GET_CID_ADDR(cid);
Michael Chan83e3fc82008-01-29 21:37:17 -08001275
1276 val = BNX2_L2CTX_CTX_TYPE_CTX_BD_CHN_TYPE_VALUE;
1277 val |= BNX2_L2CTX_CTX_TYPE_SIZE_L2;
1278 val |= 0x02 << 8;
1279
Michael Chan22fa1592010-10-11 16:12:00 -07001280 if (bp->flow_ctrl & FLOW_CTRL_TX)
1281 val |= BNX2_L2CTX_FLOW_CTRL_ENABLE;
Michael Chan83e3fc82008-01-29 21:37:17 -08001282
Michael Chan83e3fc82008-01-29 21:37:17 -08001283 bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_CTX_TYPE, val);
1284}
1285
Michael Chanbb4f98a2008-06-19 16:38:19 -07001286static void
1287bnx2_init_all_rx_contexts(struct bnx2 *bp)
1288{
1289 int i;
1290 u32 cid;
1291
1292 for (i = 0, cid = RX_CID; i < bp->num_rx_rings; i++, cid++) {
1293 if (i == 1)
1294 cid = RX_RSS_CID;
1295 bnx2_init_rx_context(bp, cid);
1296 }
1297}
1298
Benjamin Li344478d2008-09-18 16:38:24 -07001299static void
Michael Chanb6016b72005-05-26 13:03:09 -07001300bnx2_set_mac_link(struct bnx2 *bp)
1301{
1302 u32 val;
1303
Michael Chane503e062012-12-06 10:33:08 +00001304 BNX2_WR(bp, BNX2_EMAC_TX_LENGTHS, 0x2620);
Michael Chanb6016b72005-05-26 13:03:09 -07001305 if (bp->link_up && (bp->line_speed == SPEED_1000) &&
1306 (bp->duplex == DUPLEX_HALF)) {
Michael Chane503e062012-12-06 10:33:08 +00001307 BNX2_WR(bp, BNX2_EMAC_TX_LENGTHS, 0x26ff);
Michael Chanb6016b72005-05-26 13:03:09 -07001308 }
1309
1310 /* Configure the EMAC mode register. */
Michael Chane503e062012-12-06 10:33:08 +00001311 val = BNX2_RD(bp, BNX2_EMAC_MODE);
Michael Chanb6016b72005-05-26 13:03:09 -07001312
1313 val &= ~(BNX2_EMAC_MODE_PORT | BNX2_EMAC_MODE_HALF_DUPLEX |
Michael Chan5b0c76a2005-11-04 08:45:49 -08001314 BNX2_EMAC_MODE_MAC_LOOP | BNX2_EMAC_MODE_FORCE_LINK |
Michael Chan59b47d82006-11-19 14:10:45 -08001315 BNX2_EMAC_MODE_25G_MODE);
Michael Chanb6016b72005-05-26 13:03:09 -07001316
1317 if (bp->link_up) {
Michael Chan5b0c76a2005-11-04 08:45:49 -08001318 switch (bp->line_speed) {
1319 case SPEED_10:
Michael Chan4ce45e02012-12-06 10:33:10 +00001320 if (BNX2_CHIP(bp) != BNX2_CHIP_5706) {
Michael Chan59b47d82006-11-19 14:10:45 -08001321 val |= BNX2_EMAC_MODE_PORT_MII_10M;
Michael Chan5b0c76a2005-11-04 08:45:49 -08001322 break;
1323 }
1324 /* fall through */
1325 case SPEED_100:
1326 val |= BNX2_EMAC_MODE_PORT_MII;
1327 break;
1328 case SPEED_2500:
Michael Chan59b47d82006-11-19 14:10:45 -08001329 val |= BNX2_EMAC_MODE_25G_MODE;
Michael Chan5b0c76a2005-11-04 08:45:49 -08001330 /* fall through */
1331 case SPEED_1000:
1332 val |= BNX2_EMAC_MODE_PORT_GMII;
1333 break;
1334 }
Michael Chanb6016b72005-05-26 13:03:09 -07001335 }
1336 else {
1337 val |= BNX2_EMAC_MODE_PORT_GMII;
1338 }
1339
1340 /* Set the MAC to operate in the appropriate duplex mode. */
1341 if (bp->duplex == DUPLEX_HALF)
1342 val |= BNX2_EMAC_MODE_HALF_DUPLEX;
Michael Chane503e062012-12-06 10:33:08 +00001343 BNX2_WR(bp, BNX2_EMAC_MODE, val);
Michael Chanb6016b72005-05-26 13:03:09 -07001344
1345 /* Enable/disable rx PAUSE. */
1346 bp->rx_mode &= ~BNX2_EMAC_RX_MODE_FLOW_EN;
1347
1348 if (bp->flow_ctrl & FLOW_CTRL_RX)
1349 bp->rx_mode |= BNX2_EMAC_RX_MODE_FLOW_EN;
Michael Chane503e062012-12-06 10:33:08 +00001350 BNX2_WR(bp, BNX2_EMAC_RX_MODE, bp->rx_mode);
Michael Chanb6016b72005-05-26 13:03:09 -07001351
1352 /* Enable/disable tx PAUSE. */
Michael Chane503e062012-12-06 10:33:08 +00001353 val = BNX2_RD(bp, BNX2_EMAC_TX_MODE);
Michael Chanb6016b72005-05-26 13:03:09 -07001354 val &= ~BNX2_EMAC_TX_MODE_FLOW_EN;
1355
1356 if (bp->flow_ctrl & FLOW_CTRL_TX)
1357 val |= BNX2_EMAC_TX_MODE_FLOW_EN;
Michael Chane503e062012-12-06 10:33:08 +00001358 BNX2_WR(bp, BNX2_EMAC_TX_MODE, val);
Michael Chanb6016b72005-05-26 13:03:09 -07001359
1360 /* Acknowledge the interrupt. */
Michael Chane503e062012-12-06 10:33:08 +00001361 BNX2_WR(bp, BNX2_EMAC_STATUS, BNX2_EMAC_STATUS_LINK_CHANGE);
Michael Chanb6016b72005-05-26 13:03:09 -07001362
Michael Chan22fa1592010-10-11 16:12:00 -07001363 bnx2_init_all_rx_contexts(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07001364}
1365
Michael Chan27a005b2007-05-03 13:23:41 -07001366static void
1367bnx2_enable_bmsr1(struct bnx2 *bp)
1368{
Michael Chan583c28e2008-01-21 19:51:35 -08001369 if ((bp->phy_flags & BNX2_PHY_FLAG_SERDES) &&
Michael Chan4ce45e02012-12-06 10:33:10 +00001370 (BNX2_CHIP(bp) == BNX2_CHIP_5709))
Michael Chan27a005b2007-05-03 13:23:41 -07001371 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
1372 MII_BNX2_BLK_ADDR_GP_STATUS);
1373}
1374
1375static void
1376bnx2_disable_bmsr1(struct bnx2 *bp)
1377{
Michael Chan583c28e2008-01-21 19:51:35 -08001378 if ((bp->phy_flags & BNX2_PHY_FLAG_SERDES) &&
Michael Chan4ce45e02012-12-06 10:33:10 +00001379 (BNX2_CHIP(bp) == BNX2_CHIP_5709))
Michael Chan27a005b2007-05-03 13:23:41 -07001380 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
1381 MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
1382}
1383
Michael Chanb6016b72005-05-26 13:03:09 -07001384static int
Michael Chan605a9e22007-05-03 13:23:13 -07001385bnx2_test_and_enable_2g5(struct bnx2 *bp)
1386{
1387 u32 up1;
1388 int ret = 1;
1389
Michael Chan583c28e2008-01-21 19:51:35 -08001390 if (!(bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE))
Michael Chan605a9e22007-05-03 13:23:13 -07001391 return 0;
1392
1393 if (bp->autoneg & AUTONEG_SPEED)
1394 bp->advertising |= ADVERTISED_2500baseX_Full;
1395
Michael Chan4ce45e02012-12-06 10:33:10 +00001396 if (BNX2_CHIP(bp) == BNX2_CHIP_5709)
Michael Chan27a005b2007-05-03 13:23:41 -07001397 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_OVER1G);
1398
Michael Chan605a9e22007-05-03 13:23:13 -07001399 bnx2_read_phy(bp, bp->mii_up1, &up1);
1400 if (!(up1 & BCM5708S_UP1_2G5)) {
1401 up1 |= BCM5708S_UP1_2G5;
1402 bnx2_write_phy(bp, bp->mii_up1, up1);
1403 ret = 0;
1404 }
1405
Michael Chan4ce45e02012-12-06 10:33:10 +00001406 if (BNX2_CHIP(bp) == BNX2_CHIP_5709)
Michael Chan27a005b2007-05-03 13:23:41 -07001407 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
1408 MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
1409
Michael Chan605a9e22007-05-03 13:23:13 -07001410 return ret;
1411}
1412
1413static int
1414bnx2_test_and_disable_2g5(struct bnx2 *bp)
1415{
1416 u32 up1;
1417 int ret = 0;
1418
Michael Chan583c28e2008-01-21 19:51:35 -08001419 if (!(bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE))
Michael Chan605a9e22007-05-03 13:23:13 -07001420 return 0;
1421
Michael Chan4ce45e02012-12-06 10:33:10 +00001422 if (BNX2_CHIP(bp) == BNX2_CHIP_5709)
Michael Chan27a005b2007-05-03 13:23:41 -07001423 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_OVER1G);
1424
Michael Chan605a9e22007-05-03 13:23:13 -07001425 bnx2_read_phy(bp, bp->mii_up1, &up1);
1426 if (up1 & BCM5708S_UP1_2G5) {
1427 up1 &= ~BCM5708S_UP1_2G5;
1428 bnx2_write_phy(bp, bp->mii_up1, up1);
1429 ret = 1;
1430 }
1431
Michael Chan4ce45e02012-12-06 10:33:10 +00001432 if (BNX2_CHIP(bp) == BNX2_CHIP_5709)
Michael Chan27a005b2007-05-03 13:23:41 -07001433 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
1434 MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
1435
Michael Chan605a9e22007-05-03 13:23:13 -07001436 return ret;
1437}
1438
1439static void
1440bnx2_enable_forced_2g5(struct bnx2 *bp)
1441{
Michael Chancbd68902010-06-08 07:21:30 +00001442 u32 uninitialized_var(bmcr);
1443 int err;
Michael Chan605a9e22007-05-03 13:23:13 -07001444
Michael Chan583c28e2008-01-21 19:51:35 -08001445 if (!(bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE))
Michael Chan605a9e22007-05-03 13:23:13 -07001446 return;
1447
Michael Chan4ce45e02012-12-06 10:33:10 +00001448 if (BNX2_CHIP(bp) == BNX2_CHIP_5709) {
Michael Chan27a005b2007-05-03 13:23:41 -07001449 u32 val;
1450
1451 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
1452 MII_BNX2_BLK_ADDR_SERDES_DIG);
Michael Chancbd68902010-06-08 07:21:30 +00001453 if (!bnx2_read_phy(bp, MII_BNX2_SERDES_DIG_MISC1, &val)) {
1454 val &= ~MII_BNX2_SD_MISC1_FORCE_MSK;
1455 val |= MII_BNX2_SD_MISC1_FORCE |
1456 MII_BNX2_SD_MISC1_FORCE_2_5G;
1457 bnx2_write_phy(bp, MII_BNX2_SERDES_DIG_MISC1, val);
1458 }
Michael Chan27a005b2007-05-03 13:23:41 -07001459
1460 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
1461 MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
Michael Chancbd68902010-06-08 07:21:30 +00001462 err = bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chan27a005b2007-05-03 13:23:41 -07001463
Michael Chan4ce45e02012-12-06 10:33:10 +00001464 } else if (BNX2_CHIP(bp) == BNX2_CHIP_5708) {
Michael Chancbd68902010-06-08 07:21:30 +00001465 err = bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
1466 if (!err)
1467 bmcr |= BCM5708S_BMCR_FORCE_2500;
Eric Dumazetc70798572009-11-02 23:17:42 +00001468 } else {
1469 return;
Michael Chan605a9e22007-05-03 13:23:13 -07001470 }
1471
Michael Chancbd68902010-06-08 07:21:30 +00001472 if (err)
1473 return;
1474
Michael Chan605a9e22007-05-03 13:23:13 -07001475 if (bp->autoneg & AUTONEG_SPEED) {
1476 bmcr &= ~BMCR_ANENABLE;
1477 if (bp->req_duplex == DUPLEX_FULL)
1478 bmcr |= BMCR_FULLDPLX;
1479 }
1480 bnx2_write_phy(bp, bp->mii_bmcr, bmcr);
1481}
1482
1483static void
1484bnx2_disable_forced_2g5(struct bnx2 *bp)
1485{
Michael Chancbd68902010-06-08 07:21:30 +00001486 u32 uninitialized_var(bmcr);
1487 int err;
Michael Chan605a9e22007-05-03 13:23:13 -07001488
Michael Chan583c28e2008-01-21 19:51:35 -08001489 if (!(bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE))
Michael Chan605a9e22007-05-03 13:23:13 -07001490 return;
1491
Michael Chan4ce45e02012-12-06 10:33:10 +00001492 if (BNX2_CHIP(bp) == BNX2_CHIP_5709) {
Michael Chan27a005b2007-05-03 13:23:41 -07001493 u32 val;
1494
1495 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
1496 MII_BNX2_BLK_ADDR_SERDES_DIG);
Michael Chancbd68902010-06-08 07:21:30 +00001497 if (!bnx2_read_phy(bp, MII_BNX2_SERDES_DIG_MISC1, &val)) {
1498 val &= ~MII_BNX2_SD_MISC1_FORCE;
1499 bnx2_write_phy(bp, MII_BNX2_SERDES_DIG_MISC1, val);
1500 }
Michael Chan27a005b2007-05-03 13:23:41 -07001501
1502 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
1503 MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
Michael Chancbd68902010-06-08 07:21:30 +00001504 err = bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chan27a005b2007-05-03 13:23:41 -07001505
Michael Chan4ce45e02012-12-06 10:33:10 +00001506 } else if (BNX2_CHIP(bp) == BNX2_CHIP_5708) {
Michael Chancbd68902010-06-08 07:21:30 +00001507 err = bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
1508 if (!err)
1509 bmcr &= ~BCM5708S_BMCR_FORCE_2500;
Eric Dumazetc70798572009-11-02 23:17:42 +00001510 } else {
1511 return;
Michael Chan605a9e22007-05-03 13:23:13 -07001512 }
1513
Michael Chancbd68902010-06-08 07:21:30 +00001514 if (err)
1515 return;
1516
Michael Chan605a9e22007-05-03 13:23:13 -07001517 if (bp->autoneg & AUTONEG_SPEED)
1518 bmcr |= BMCR_SPEED1000 | BMCR_ANENABLE | BMCR_ANRESTART;
1519 bnx2_write_phy(bp, bp->mii_bmcr, bmcr);
1520}
1521
Michael Chanb2fadea2008-01-21 17:07:06 -08001522static void
1523bnx2_5706s_force_link_dn(struct bnx2 *bp, int start)
1524{
1525 u32 val;
1526
1527 bnx2_write_phy(bp, MII_BNX2_DSP_ADDRESS, MII_EXPAND_SERDES_CTL);
1528 bnx2_read_phy(bp, MII_BNX2_DSP_RW_PORT, &val);
1529 if (start)
1530 bnx2_write_phy(bp, MII_BNX2_DSP_RW_PORT, val & 0xff0f);
1531 else
1532 bnx2_write_phy(bp, MII_BNX2_DSP_RW_PORT, val | 0xc0);
1533}
1534
Michael Chan605a9e22007-05-03 13:23:13 -07001535static int
Michael Chanb6016b72005-05-26 13:03:09 -07001536bnx2_set_link(struct bnx2 *bp)
1537{
1538 u32 bmsr;
1539 u8 link_up;
1540
Michael Chan80be4432006-11-19 14:07:28 -08001541 if (bp->loopback == MAC_LOOPBACK || bp->loopback == PHY_LOOPBACK) {
Michael Chanb6016b72005-05-26 13:03:09 -07001542 bp->link_up = 1;
1543 return 0;
1544 }
1545
Michael Chan583c28e2008-01-21 19:51:35 -08001546 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
Michael Chan0d8a6572007-07-07 22:49:43 -07001547 return 0;
1548
Michael Chanb6016b72005-05-26 13:03:09 -07001549 link_up = bp->link_up;
1550
Michael Chan27a005b2007-05-03 13:23:41 -07001551 bnx2_enable_bmsr1(bp);
1552 bnx2_read_phy(bp, bp->mii_bmsr1, &bmsr);
1553 bnx2_read_phy(bp, bp->mii_bmsr1, &bmsr);
1554 bnx2_disable_bmsr1(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07001555
Michael Chan583c28e2008-01-21 19:51:35 -08001556 if ((bp->phy_flags & BNX2_PHY_FLAG_SERDES) &&
Michael Chan4ce45e02012-12-06 10:33:10 +00001557 (BNX2_CHIP(bp) == BNX2_CHIP_5706)) {
Michael Chana2724e22008-02-23 19:47:44 -08001558 u32 val, an_dbg;
Michael Chanb6016b72005-05-26 13:03:09 -07001559
Michael Chan583c28e2008-01-21 19:51:35 -08001560 if (bp->phy_flags & BNX2_PHY_FLAG_FORCED_DOWN) {
Michael Chanb2fadea2008-01-21 17:07:06 -08001561 bnx2_5706s_force_link_dn(bp, 0);
Michael Chan583c28e2008-01-21 19:51:35 -08001562 bp->phy_flags &= ~BNX2_PHY_FLAG_FORCED_DOWN;
Michael Chanb2fadea2008-01-21 17:07:06 -08001563 }
Michael Chane503e062012-12-06 10:33:08 +00001564 val = BNX2_RD(bp, BNX2_EMAC_STATUS);
Michael Chana2724e22008-02-23 19:47:44 -08001565
1566 bnx2_write_phy(bp, MII_BNX2_MISC_SHADOW, MISC_SHDW_AN_DBG);
1567 bnx2_read_phy(bp, MII_BNX2_MISC_SHADOW, &an_dbg);
1568 bnx2_read_phy(bp, MII_BNX2_MISC_SHADOW, &an_dbg);
1569
1570 if ((val & BNX2_EMAC_STATUS_LINK) &&
1571 !(an_dbg & MISC_SHDW_AN_DBG_NOSYNC))
Michael Chanb6016b72005-05-26 13:03:09 -07001572 bmsr |= BMSR_LSTATUS;
1573 else
1574 bmsr &= ~BMSR_LSTATUS;
1575 }
1576
1577 if (bmsr & BMSR_LSTATUS) {
1578 bp->link_up = 1;
1579
Michael Chan583c28e2008-01-21 19:51:35 -08001580 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Michael Chan4ce45e02012-12-06 10:33:10 +00001581 if (BNX2_CHIP(bp) == BNX2_CHIP_5706)
Michael Chan5b0c76a2005-11-04 08:45:49 -08001582 bnx2_5706s_linkup(bp);
Michael Chan4ce45e02012-12-06 10:33:10 +00001583 else if (BNX2_CHIP(bp) == BNX2_CHIP_5708)
Michael Chan5b0c76a2005-11-04 08:45:49 -08001584 bnx2_5708s_linkup(bp);
Michael Chan4ce45e02012-12-06 10:33:10 +00001585 else if (BNX2_CHIP(bp) == BNX2_CHIP_5709)
Michael Chan27a005b2007-05-03 13:23:41 -07001586 bnx2_5709s_linkup(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07001587 }
1588 else {
1589 bnx2_copper_linkup(bp);
1590 }
1591 bnx2_resolve_flow_ctrl(bp);
1592 }
1593 else {
Michael Chan583c28e2008-01-21 19:51:35 -08001594 if ((bp->phy_flags & BNX2_PHY_FLAG_SERDES) &&
Michael Chan605a9e22007-05-03 13:23:13 -07001595 (bp->autoneg & AUTONEG_SPEED))
1596 bnx2_disable_forced_2g5(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07001597
Michael Chan583c28e2008-01-21 19:51:35 -08001598 if (bp->phy_flags & BNX2_PHY_FLAG_PARALLEL_DETECT) {
Michael Chanb2fadea2008-01-21 17:07:06 -08001599 u32 bmcr;
1600
1601 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
1602 bmcr |= BMCR_ANENABLE;
1603 bnx2_write_phy(bp, bp->mii_bmcr, bmcr);
1604
Michael Chan583c28e2008-01-21 19:51:35 -08001605 bp->phy_flags &= ~BNX2_PHY_FLAG_PARALLEL_DETECT;
Michael Chanb2fadea2008-01-21 17:07:06 -08001606 }
Michael Chanb6016b72005-05-26 13:03:09 -07001607 bp->link_up = 0;
1608 }
1609
1610 if (bp->link_up != link_up) {
1611 bnx2_report_link(bp);
1612 }
1613
1614 bnx2_set_mac_link(bp);
1615
1616 return 0;
1617}
1618
1619static int
1620bnx2_reset_phy(struct bnx2 *bp)
1621{
1622 int i;
1623 u32 reg;
1624
Michael Chanca58c3a2007-05-03 13:22:52 -07001625 bnx2_write_phy(bp, bp->mii_bmcr, BMCR_RESET);
Michael Chanb6016b72005-05-26 13:03:09 -07001626
1627#define PHY_RESET_MAX_WAIT 100
1628 for (i = 0; i < PHY_RESET_MAX_WAIT; i++) {
1629 udelay(10);
1630
Michael Chanca58c3a2007-05-03 13:22:52 -07001631 bnx2_read_phy(bp, bp->mii_bmcr, &reg);
Michael Chanb6016b72005-05-26 13:03:09 -07001632 if (!(reg & BMCR_RESET)) {
1633 udelay(20);
1634 break;
1635 }
1636 }
1637 if (i == PHY_RESET_MAX_WAIT) {
1638 return -EBUSY;
1639 }
1640 return 0;
1641}
1642
1643static u32
1644bnx2_phy_get_pause_adv(struct bnx2 *bp)
1645{
1646 u32 adv = 0;
1647
1648 if ((bp->req_flow_ctrl & (FLOW_CTRL_RX | FLOW_CTRL_TX)) ==
1649 (FLOW_CTRL_RX | FLOW_CTRL_TX)) {
1650
Michael Chan583c28e2008-01-21 19:51:35 -08001651 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Michael Chanb6016b72005-05-26 13:03:09 -07001652 adv = ADVERTISE_1000XPAUSE;
1653 }
1654 else {
1655 adv = ADVERTISE_PAUSE_CAP;
1656 }
1657 }
1658 else if (bp->req_flow_ctrl & FLOW_CTRL_TX) {
Michael Chan583c28e2008-01-21 19:51:35 -08001659 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Michael Chanb6016b72005-05-26 13:03:09 -07001660 adv = ADVERTISE_1000XPSE_ASYM;
1661 }
1662 else {
1663 adv = ADVERTISE_PAUSE_ASYM;
1664 }
1665 }
1666 else if (bp->req_flow_ctrl & FLOW_CTRL_RX) {
Michael Chan583c28e2008-01-21 19:51:35 -08001667 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Michael Chanb6016b72005-05-26 13:03:09 -07001668 adv = ADVERTISE_1000XPAUSE | ADVERTISE_1000XPSE_ASYM;
1669 }
1670 else {
1671 adv = ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM;
1672 }
1673 }
1674 return adv;
1675}
1676
Michael Chana2f13892008-07-14 22:38:23 -07001677static int bnx2_fw_sync(struct bnx2 *, u32, int, int);
Michael Chan0d8a6572007-07-07 22:49:43 -07001678
Michael Chanb6016b72005-05-26 13:03:09 -07001679static int
Michael Chan0d8a6572007-07-07 22:49:43 -07001680bnx2_setup_remote_phy(struct bnx2 *bp, u8 port)
Harvey Harrison52d07b12009-01-19 17:27:06 -08001681__releases(&bp->phy_lock)
1682__acquires(&bp->phy_lock)
Michael Chan0d8a6572007-07-07 22:49:43 -07001683{
1684 u32 speed_arg = 0, pause_adv;
1685
1686 pause_adv = bnx2_phy_get_pause_adv(bp);
1687
1688 if (bp->autoneg & AUTONEG_SPEED) {
1689 speed_arg |= BNX2_NETLINK_SET_LINK_ENABLE_AUTONEG;
1690 if (bp->advertising & ADVERTISED_10baseT_Half)
1691 speed_arg |= BNX2_NETLINK_SET_LINK_SPEED_10HALF;
1692 if (bp->advertising & ADVERTISED_10baseT_Full)
1693 speed_arg |= BNX2_NETLINK_SET_LINK_SPEED_10FULL;
1694 if (bp->advertising & ADVERTISED_100baseT_Half)
1695 speed_arg |= BNX2_NETLINK_SET_LINK_SPEED_100HALF;
1696 if (bp->advertising & ADVERTISED_100baseT_Full)
1697 speed_arg |= BNX2_NETLINK_SET_LINK_SPEED_100FULL;
1698 if (bp->advertising & ADVERTISED_1000baseT_Full)
1699 speed_arg |= BNX2_NETLINK_SET_LINK_SPEED_1GFULL;
1700 if (bp->advertising & ADVERTISED_2500baseX_Full)
1701 speed_arg |= BNX2_NETLINK_SET_LINK_SPEED_2G5FULL;
1702 } else {
1703 if (bp->req_line_speed == SPEED_2500)
1704 speed_arg = BNX2_NETLINK_SET_LINK_SPEED_2G5FULL;
1705 else if (bp->req_line_speed == SPEED_1000)
1706 speed_arg = BNX2_NETLINK_SET_LINK_SPEED_1GFULL;
1707 else if (bp->req_line_speed == SPEED_100) {
1708 if (bp->req_duplex == DUPLEX_FULL)
1709 speed_arg = BNX2_NETLINK_SET_LINK_SPEED_100FULL;
1710 else
1711 speed_arg = BNX2_NETLINK_SET_LINK_SPEED_100HALF;
1712 } else if (bp->req_line_speed == SPEED_10) {
1713 if (bp->req_duplex == DUPLEX_FULL)
1714 speed_arg = BNX2_NETLINK_SET_LINK_SPEED_10FULL;
1715 else
1716 speed_arg = BNX2_NETLINK_SET_LINK_SPEED_10HALF;
1717 }
1718 }
1719
1720 if (pause_adv & (ADVERTISE_1000XPAUSE | ADVERTISE_PAUSE_CAP))
1721 speed_arg |= BNX2_NETLINK_SET_LINK_FC_SYM_PAUSE;
Michael Chanc26736e2008-01-31 17:07:21 -08001722 if (pause_adv & (ADVERTISE_1000XPSE_ASYM | ADVERTISE_PAUSE_ASYM))
Michael Chan0d8a6572007-07-07 22:49:43 -07001723 speed_arg |= BNX2_NETLINK_SET_LINK_FC_ASYM_PAUSE;
1724
1725 if (port == PORT_TP)
1726 speed_arg |= BNX2_NETLINK_SET_LINK_PHY_APP_REMOTE |
1727 BNX2_NETLINK_SET_LINK_ETH_AT_WIRESPEED;
1728
Michael Chan2726d6e2008-01-29 21:35:05 -08001729 bnx2_shmem_wr(bp, BNX2_DRV_MB_ARG0, speed_arg);
Michael Chan0d8a6572007-07-07 22:49:43 -07001730
1731 spin_unlock_bh(&bp->phy_lock);
Michael Chana2f13892008-07-14 22:38:23 -07001732 bnx2_fw_sync(bp, BNX2_DRV_MSG_CODE_CMD_SET_LINK, 1, 0);
Michael Chan0d8a6572007-07-07 22:49:43 -07001733 spin_lock_bh(&bp->phy_lock);
1734
1735 return 0;
1736}
1737
1738static int
1739bnx2_setup_serdes_phy(struct bnx2 *bp, u8 port)
Harvey Harrison52d07b12009-01-19 17:27:06 -08001740__releases(&bp->phy_lock)
1741__acquires(&bp->phy_lock)
Michael Chanb6016b72005-05-26 13:03:09 -07001742{
Michael Chan605a9e22007-05-03 13:23:13 -07001743 u32 adv, bmcr;
Michael Chanb6016b72005-05-26 13:03:09 -07001744 u32 new_adv = 0;
1745
Michael Chan583c28e2008-01-21 19:51:35 -08001746 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
Eric Dumazet807540b2010-09-23 05:40:09 +00001747 return bnx2_setup_remote_phy(bp, port);
Michael Chan0d8a6572007-07-07 22:49:43 -07001748
Michael Chanb6016b72005-05-26 13:03:09 -07001749 if (!(bp->autoneg & AUTONEG_SPEED)) {
1750 u32 new_bmcr;
Michael Chan5b0c76a2005-11-04 08:45:49 -08001751 int force_link_down = 0;
1752
Michael Chan605a9e22007-05-03 13:23:13 -07001753 if (bp->req_line_speed == SPEED_2500) {
1754 if (!bnx2_test_and_enable_2g5(bp))
1755 force_link_down = 1;
1756 } else if (bp->req_line_speed == SPEED_1000) {
1757 if (bnx2_test_and_disable_2g5(bp))
1758 force_link_down = 1;
1759 }
Michael Chanca58c3a2007-05-03 13:22:52 -07001760 bnx2_read_phy(bp, bp->mii_adv, &adv);
Michael Chan80be4432006-11-19 14:07:28 -08001761 adv &= ~(ADVERTISE_1000XFULL | ADVERTISE_1000XHALF);
1762
Michael Chanca58c3a2007-05-03 13:22:52 -07001763 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chan605a9e22007-05-03 13:23:13 -07001764 new_bmcr = bmcr & ~BMCR_ANENABLE;
Michael Chan80be4432006-11-19 14:07:28 -08001765 new_bmcr |= BMCR_SPEED1000;
Michael Chan605a9e22007-05-03 13:23:13 -07001766
Michael Chan4ce45e02012-12-06 10:33:10 +00001767 if (BNX2_CHIP(bp) == BNX2_CHIP_5709) {
Michael Chan27a005b2007-05-03 13:23:41 -07001768 if (bp->req_line_speed == SPEED_2500)
1769 bnx2_enable_forced_2g5(bp);
1770 else if (bp->req_line_speed == SPEED_1000) {
1771 bnx2_disable_forced_2g5(bp);
1772 new_bmcr &= ~0x2000;
1773 }
1774
Michael Chan4ce45e02012-12-06 10:33:10 +00001775 } else if (BNX2_CHIP(bp) == BNX2_CHIP_5708) {
Michael Chan605a9e22007-05-03 13:23:13 -07001776 if (bp->req_line_speed == SPEED_2500)
1777 new_bmcr |= BCM5708S_BMCR_FORCE_2500;
1778 else
1779 new_bmcr = bmcr & ~BCM5708S_BMCR_FORCE_2500;
Michael Chan5b0c76a2005-11-04 08:45:49 -08001780 }
1781
Michael Chanb6016b72005-05-26 13:03:09 -07001782 if (bp->req_duplex == DUPLEX_FULL) {
Michael Chan5b0c76a2005-11-04 08:45:49 -08001783 adv |= ADVERTISE_1000XFULL;
Michael Chanb6016b72005-05-26 13:03:09 -07001784 new_bmcr |= BMCR_FULLDPLX;
1785 }
1786 else {
Michael Chan5b0c76a2005-11-04 08:45:49 -08001787 adv |= ADVERTISE_1000XHALF;
Michael Chanb6016b72005-05-26 13:03:09 -07001788 new_bmcr &= ~BMCR_FULLDPLX;
1789 }
Michael Chan5b0c76a2005-11-04 08:45:49 -08001790 if ((new_bmcr != bmcr) || (force_link_down)) {
Michael Chanb6016b72005-05-26 13:03:09 -07001791 /* Force a link down visible on the other side */
1792 if (bp->link_up) {
Michael Chanca58c3a2007-05-03 13:22:52 -07001793 bnx2_write_phy(bp, bp->mii_adv, adv &
Michael Chan5b0c76a2005-11-04 08:45:49 -08001794 ~(ADVERTISE_1000XFULL |
1795 ADVERTISE_1000XHALF));
Michael Chanca58c3a2007-05-03 13:22:52 -07001796 bnx2_write_phy(bp, bp->mii_bmcr, bmcr |
Michael Chanb6016b72005-05-26 13:03:09 -07001797 BMCR_ANRESTART | BMCR_ANENABLE);
1798
1799 bp->link_up = 0;
1800 netif_carrier_off(bp->dev);
Michael Chanca58c3a2007-05-03 13:22:52 -07001801 bnx2_write_phy(bp, bp->mii_bmcr, new_bmcr);
Michael Chan80be4432006-11-19 14:07:28 -08001802 bnx2_report_link(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07001803 }
Michael Chanca58c3a2007-05-03 13:22:52 -07001804 bnx2_write_phy(bp, bp->mii_adv, adv);
1805 bnx2_write_phy(bp, bp->mii_bmcr, new_bmcr);
Michael Chan605a9e22007-05-03 13:23:13 -07001806 } else {
1807 bnx2_resolve_flow_ctrl(bp);
1808 bnx2_set_mac_link(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07001809 }
1810 return 0;
1811 }
1812
Michael Chan605a9e22007-05-03 13:23:13 -07001813 bnx2_test_and_enable_2g5(bp);
Michael Chan5b0c76a2005-11-04 08:45:49 -08001814
Michael Chanb6016b72005-05-26 13:03:09 -07001815 if (bp->advertising & ADVERTISED_1000baseT_Full)
1816 new_adv |= ADVERTISE_1000XFULL;
1817
1818 new_adv |= bnx2_phy_get_pause_adv(bp);
1819
Michael Chanca58c3a2007-05-03 13:22:52 -07001820 bnx2_read_phy(bp, bp->mii_adv, &adv);
1821 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chanb6016b72005-05-26 13:03:09 -07001822
1823 bp->serdes_an_pending = 0;
1824 if ((adv != new_adv) || ((bmcr & BMCR_ANENABLE) == 0)) {
1825 /* Force a link down visible on the other side */
1826 if (bp->link_up) {
Michael Chanca58c3a2007-05-03 13:22:52 -07001827 bnx2_write_phy(bp, bp->mii_bmcr, BMCR_LOOPBACK);
Michael Chan80be4432006-11-19 14:07:28 -08001828 spin_unlock_bh(&bp->phy_lock);
1829 msleep(20);
1830 spin_lock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07001831 }
1832
Michael Chanca58c3a2007-05-03 13:22:52 -07001833 bnx2_write_phy(bp, bp->mii_adv, new_adv);
1834 bnx2_write_phy(bp, bp->mii_bmcr, bmcr | BMCR_ANRESTART |
Michael Chanb6016b72005-05-26 13:03:09 -07001835 BMCR_ANENABLE);
Michael Chanf8dd0642006-11-19 14:08:29 -08001836 /* Speed up link-up time when the link partner
1837 * does not autonegotiate which is very common
1838 * in blade servers. Some blade servers use
1839 * IPMI for kerboard input and it's important
1840 * to minimize link disruptions. Autoneg. involves
1841 * exchanging base pages plus 3 next pages and
1842 * normally completes in about 120 msec.
1843 */
Michael Chan40105c02008-11-12 16:02:45 -08001844 bp->current_interval = BNX2_SERDES_AN_TIMEOUT;
Michael Chanf8dd0642006-11-19 14:08:29 -08001845 bp->serdes_an_pending = 1;
1846 mod_timer(&bp->timer, jiffies + bp->current_interval);
Michael Chan605a9e22007-05-03 13:23:13 -07001847 } else {
1848 bnx2_resolve_flow_ctrl(bp);
1849 bnx2_set_mac_link(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07001850 }
1851
1852 return 0;
1853}
1854
1855#define ETHTOOL_ALL_FIBRE_SPEED \
Michael Chan583c28e2008-01-21 19:51:35 -08001856 (bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE) ? \
Michael Chandeaf3912007-07-07 22:48:00 -07001857 (ADVERTISED_2500baseX_Full | ADVERTISED_1000baseT_Full) :\
1858 (ADVERTISED_1000baseT_Full)
Michael Chanb6016b72005-05-26 13:03:09 -07001859
1860#define ETHTOOL_ALL_COPPER_SPEED \
1861 (ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full | \
1862 ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full | \
1863 ADVERTISED_1000baseT_Full)
1864
1865#define PHY_ALL_10_100_SPEED (ADVERTISE_10HALF | ADVERTISE_10FULL | \
1866 ADVERTISE_100HALF | ADVERTISE_100FULL | ADVERTISE_CSMA)
Jeff Garzik6aa20a22006-09-13 13:24:59 -04001867
Michael Chanb6016b72005-05-26 13:03:09 -07001868#define PHY_ALL_1000_SPEED (ADVERTISE_1000HALF | ADVERTISE_1000FULL)
1869
Michael Chandeaf3912007-07-07 22:48:00 -07001870static void
Michael Chan0d8a6572007-07-07 22:49:43 -07001871bnx2_set_default_remote_link(struct bnx2 *bp)
1872{
1873 u32 link;
1874
1875 if (bp->phy_port == PORT_TP)
Michael Chan2726d6e2008-01-29 21:35:05 -08001876 link = bnx2_shmem_rd(bp, BNX2_RPHY_COPPER_LINK);
Michael Chan0d8a6572007-07-07 22:49:43 -07001877 else
Michael Chan2726d6e2008-01-29 21:35:05 -08001878 link = bnx2_shmem_rd(bp, BNX2_RPHY_SERDES_LINK);
Michael Chan0d8a6572007-07-07 22:49:43 -07001879
1880 if (link & BNX2_NETLINK_SET_LINK_ENABLE_AUTONEG) {
1881 bp->req_line_speed = 0;
1882 bp->autoneg |= AUTONEG_SPEED;
1883 bp->advertising = ADVERTISED_Autoneg;
1884 if (link & BNX2_NETLINK_SET_LINK_SPEED_10HALF)
1885 bp->advertising |= ADVERTISED_10baseT_Half;
1886 if (link & BNX2_NETLINK_SET_LINK_SPEED_10FULL)
1887 bp->advertising |= ADVERTISED_10baseT_Full;
1888 if (link & BNX2_NETLINK_SET_LINK_SPEED_100HALF)
1889 bp->advertising |= ADVERTISED_100baseT_Half;
1890 if (link & BNX2_NETLINK_SET_LINK_SPEED_100FULL)
1891 bp->advertising |= ADVERTISED_100baseT_Full;
1892 if (link & BNX2_NETLINK_SET_LINK_SPEED_1GFULL)
1893 bp->advertising |= ADVERTISED_1000baseT_Full;
1894 if (link & BNX2_NETLINK_SET_LINK_SPEED_2G5FULL)
1895 bp->advertising |= ADVERTISED_2500baseX_Full;
1896 } else {
1897 bp->autoneg = 0;
1898 bp->advertising = 0;
1899 bp->req_duplex = DUPLEX_FULL;
1900 if (link & BNX2_NETLINK_SET_LINK_SPEED_10) {
1901 bp->req_line_speed = SPEED_10;
1902 if (link & BNX2_NETLINK_SET_LINK_SPEED_10HALF)
1903 bp->req_duplex = DUPLEX_HALF;
1904 }
1905 if (link & BNX2_NETLINK_SET_LINK_SPEED_100) {
1906 bp->req_line_speed = SPEED_100;
1907 if (link & BNX2_NETLINK_SET_LINK_SPEED_100HALF)
1908 bp->req_duplex = DUPLEX_HALF;
1909 }
1910 if (link & BNX2_NETLINK_SET_LINK_SPEED_1GFULL)
1911 bp->req_line_speed = SPEED_1000;
1912 if (link & BNX2_NETLINK_SET_LINK_SPEED_2G5FULL)
1913 bp->req_line_speed = SPEED_2500;
1914 }
1915}
1916
1917static void
Michael Chandeaf3912007-07-07 22:48:00 -07001918bnx2_set_default_link(struct bnx2 *bp)
1919{
Harvey Harrisonab598592008-05-01 02:47:38 -07001920 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP) {
1921 bnx2_set_default_remote_link(bp);
1922 return;
1923 }
Michael Chan0d8a6572007-07-07 22:49:43 -07001924
Michael Chandeaf3912007-07-07 22:48:00 -07001925 bp->autoneg = AUTONEG_SPEED | AUTONEG_FLOW_CTRL;
1926 bp->req_line_speed = 0;
Michael Chan583c28e2008-01-21 19:51:35 -08001927 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Michael Chandeaf3912007-07-07 22:48:00 -07001928 u32 reg;
1929
1930 bp->advertising = ETHTOOL_ALL_FIBRE_SPEED | ADVERTISED_Autoneg;
1931
Michael Chan2726d6e2008-01-29 21:35:05 -08001932 reg = bnx2_shmem_rd(bp, BNX2_PORT_HW_CFG_CONFIG);
Michael Chandeaf3912007-07-07 22:48:00 -07001933 reg &= BNX2_PORT_HW_CFG_CFG_DFLT_LINK_MASK;
1934 if (reg == BNX2_PORT_HW_CFG_CFG_DFLT_LINK_1G) {
1935 bp->autoneg = 0;
1936 bp->req_line_speed = bp->line_speed = SPEED_1000;
1937 bp->req_duplex = DUPLEX_FULL;
1938 }
1939 } else
1940 bp->advertising = ETHTOOL_ALL_COPPER_SPEED | ADVERTISED_Autoneg;
1941}
1942
Michael Chan0d8a6572007-07-07 22:49:43 -07001943static void
Michael Chandf149d72007-07-07 22:51:36 -07001944bnx2_send_heart_beat(struct bnx2 *bp)
1945{
1946 u32 msg;
1947 u32 addr;
1948
1949 spin_lock(&bp->indirect_lock);
1950 msg = (u32) (++bp->fw_drv_pulse_wr_seq & BNX2_DRV_PULSE_SEQ_MASK);
1951 addr = bp->shmem_base + BNX2_DRV_PULSE_MB;
Michael Chane503e062012-12-06 10:33:08 +00001952 BNX2_WR(bp, BNX2_PCICFG_REG_WINDOW_ADDRESS, addr);
1953 BNX2_WR(bp, BNX2_PCICFG_REG_WINDOW, msg);
Michael Chandf149d72007-07-07 22:51:36 -07001954 spin_unlock(&bp->indirect_lock);
1955}
1956
1957static void
Michael Chan0d8a6572007-07-07 22:49:43 -07001958bnx2_remote_phy_event(struct bnx2 *bp)
1959{
1960 u32 msg;
1961 u8 link_up = bp->link_up;
1962 u8 old_port;
1963
Michael Chan2726d6e2008-01-29 21:35:05 -08001964 msg = bnx2_shmem_rd(bp, BNX2_LINK_STATUS);
Michael Chan0d8a6572007-07-07 22:49:43 -07001965
Michael Chandf149d72007-07-07 22:51:36 -07001966 if (msg & BNX2_LINK_STATUS_HEART_BEAT_EXPIRED)
1967 bnx2_send_heart_beat(bp);
1968
1969 msg &= ~BNX2_LINK_STATUS_HEART_BEAT_EXPIRED;
1970
Michael Chan0d8a6572007-07-07 22:49:43 -07001971 if ((msg & BNX2_LINK_STATUS_LINK_UP) == BNX2_LINK_STATUS_LINK_DOWN)
1972 bp->link_up = 0;
1973 else {
1974 u32 speed;
1975
1976 bp->link_up = 1;
1977 speed = msg & BNX2_LINK_STATUS_SPEED_MASK;
1978 bp->duplex = DUPLEX_FULL;
1979 switch (speed) {
1980 case BNX2_LINK_STATUS_10HALF:
1981 bp->duplex = DUPLEX_HALF;
Michael Chan7947c9c2012-06-27 15:08:23 +00001982 /* fall through */
Michael Chan0d8a6572007-07-07 22:49:43 -07001983 case BNX2_LINK_STATUS_10FULL:
1984 bp->line_speed = SPEED_10;
1985 break;
1986 case BNX2_LINK_STATUS_100HALF:
1987 bp->duplex = DUPLEX_HALF;
Michael Chan7947c9c2012-06-27 15:08:23 +00001988 /* fall through */
Michael Chan0d8a6572007-07-07 22:49:43 -07001989 case BNX2_LINK_STATUS_100BASE_T4:
1990 case BNX2_LINK_STATUS_100FULL:
1991 bp->line_speed = SPEED_100;
1992 break;
1993 case BNX2_LINK_STATUS_1000HALF:
1994 bp->duplex = DUPLEX_HALF;
Michael Chan7947c9c2012-06-27 15:08:23 +00001995 /* fall through */
Michael Chan0d8a6572007-07-07 22:49:43 -07001996 case BNX2_LINK_STATUS_1000FULL:
1997 bp->line_speed = SPEED_1000;
1998 break;
1999 case BNX2_LINK_STATUS_2500HALF:
2000 bp->duplex = DUPLEX_HALF;
Michael Chan7947c9c2012-06-27 15:08:23 +00002001 /* fall through */
Michael Chan0d8a6572007-07-07 22:49:43 -07002002 case BNX2_LINK_STATUS_2500FULL:
2003 bp->line_speed = SPEED_2500;
2004 break;
2005 default:
2006 bp->line_speed = 0;
2007 break;
2008 }
2009
Michael Chan0d8a6572007-07-07 22:49:43 -07002010 bp->flow_ctrl = 0;
2011 if ((bp->autoneg & (AUTONEG_SPEED | AUTONEG_FLOW_CTRL)) !=
2012 (AUTONEG_SPEED | AUTONEG_FLOW_CTRL)) {
2013 if (bp->duplex == DUPLEX_FULL)
2014 bp->flow_ctrl = bp->req_flow_ctrl;
2015 } else {
2016 if (msg & BNX2_LINK_STATUS_TX_FC_ENABLED)
2017 bp->flow_ctrl |= FLOW_CTRL_TX;
2018 if (msg & BNX2_LINK_STATUS_RX_FC_ENABLED)
2019 bp->flow_ctrl |= FLOW_CTRL_RX;
2020 }
2021
2022 old_port = bp->phy_port;
2023 if (msg & BNX2_LINK_STATUS_SERDES_LINK)
2024 bp->phy_port = PORT_FIBRE;
2025 else
2026 bp->phy_port = PORT_TP;
2027
2028 if (old_port != bp->phy_port)
2029 bnx2_set_default_link(bp);
2030
Michael Chan0d8a6572007-07-07 22:49:43 -07002031 }
2032 if (bp->link_up != link_up)
2033 bnx2_report_link(bp);
2034
2035 bnx2_set_mac_link(bp);
2036}
2037
2038static int
2039bnx2_set_remote_link(struct bnx2 *bp)
2040{
2041 u32 evt_code;
2042
Michael Chan2726d6e2008-01-29 21:35:05 -08002043 evt_code = bnx2_shmem_rd(bp, BNX2_FW_EVT_CODE_MB);
Michael Chan0d8a6572007-07-07 22:49:43 -07002044 switch (evt_code) {
2045 case BNX2_FW_EVT_CODE_LINK_EVENT:
2046 bnx2_remote_phy_event(bp);
2047 break;
2048 case BNX2_FW_EVT_CODE_SW_TIMER_EXPIRATION_EVENT:
2049 default:
Michael Chandf149d72007-07-07 22:51:36 -07002050 bnx2_send_heart_beat(bp);
Michael Chan0d8a6572007-07-07 22:49:43 -07002051 break;
2052 }
2053 return 0;
2054}
2055
Michael Chanb6016b72005-05-26 13:03:09 -07002056static int
2057bnx2_setup_copper_phy(struct bnx2 *bp)
Harvey Harrison52d07b12009-01-19 17:27:06 -08002058__releases(&bp->phy_lock)
2059__acquires(&bp->phy_lock)
Michael Chanb6016b72005-05-26 13:03:09 -07002060{
Michael Chand17e53b2013-12-31 23:22:32 -08002061 u32 bmcr, adv_reg, new_adv = 0;
Michael Chanb6016b72005-05-26 13:03:09 -07002062 u32 new_bmcr;
2063
Michael Chanca58c3a2007-05-03 13:22:52 -07002064 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chanb6016b72005-05-26 13:03:09 -07002065
Michael Chand17e53b2013-12-31 23:22:32 -08002066 bnx2_read_phy(bp, bp->mii_adv, &adv_reg);
2067 adv_reg &= (PHY_ALL_10_100_SPEED | ADVERTISE_PAUSE_CAP |
2068 ADVERTISE_PAUSE_ASYM);
2069
2070 new_adv = ADVERTISE_CSMA | ethtool_adv_to_mii_adv_t(bp->advertising);
2071
Michael Chanb6016b72005-05-26 13:03:09 -07002072 if (bp->autoneg & AUTONEG_SPEED) {
Michael Chand17e53b2013-12-31 23:22:32 -08002073 u32 adv1000_reg;
Matt Carlson37f07022011-11-17 14:30:55 +00002074 u32 new_adv1000 = 0;
Michael Chanb6016b72005-05-26 13:03:09 -07002075
Michael Chand17e53b2013-12-31 23:22:32 -08002076 new_adv |= bnx2_phy_get_pause_adv(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07002077
2078 bnx2_read_phy(bp, MII_CTRL1000, &adv1000_reg);
2079 adv1000_reg &= PHY_ALL_1000_SPEED;
2080
Matt Carlson37f07022011-11-17 14:30:55 +00002081 new_adv1000 |= ethtool_adv_to_mii_ctrl1000_t(bp->advertising);
Matt Carlson37f07022011-11-17 14:30:55 +00002082 if ((adv1000_reg != new_adv1000) ||
2083 (adv_reg != new_adv) ||
Michael Chanb6016b72005-05-26 13:03:09 -07002084 ((bmcr & BMCR_ANENABLE) == 0)) {
2085
Matt Carlson37f07022011-11-17 14:30:55 +00002086 bnx2_write_phy(bp, bp->mii_adv, new_adv);
2087 bnx2_write_phy(bp, MII_CTRL1000, new_adv1000);
Michael Chanca58c3a2007-05-03 13:22:52 -07002088 bnx2_write_phy(bp, bp->mii_bmcr, BMCR_ANRESTART |
Michael Chanb6016b72005-05-26 13:03:09 -07002089 BMCR_ANENABLE);
2090 }
2091 else if (bp->link_up) {
2092 /* Flow ctrl may have changed from auto to forced */
2093 /* or vice-versa. */
2094
2095 bnx2_resolve_flow_ctrl(bp);
2096 bnx2_set_mac_link(bp);
2097 }
2098 return 0;
2099 }
2100
Michael Chand17e53b2013-12-31 23:22:32 -08002101 /* advertise nothing when forcing speed */
2102 if (adv_reg != new_adv)
2103 bnx2_write_phy(bp, bp->mii_adv, new_adv);
2104
Michael Chanb6016b72005-05-26 13:03:09 -07002105 new_bmcr = 0;
2106 if (bp->req_line_speed == SPEED_100) {
2107 new_bmcr |= BMCR_SPEED100;
2108 }
2109 if (bp->req_duplex == DUPLEX_FULL) {
2110 new_bmcr |= BMCR_FULLDPLX;
2111 }
2112 if (new_bmcr != bmcr) {
2113 u32 bmsr;
Michael Chanb6016b72005-05-26 13:03:09 -07002114
Michael Chanca58c3a2007-05-03 13:22:52 -07002115 bnx2_read_phy(bp, bp->mii_bmsr, &bmsr);
2116 bnx2_read_phy(bp, bp->mii_bmsr, &bmsr);
Jeff Garzik6aa20a22006-09-13 13:24:59 -04002117
Michael Chanb6016b72005-05-26 13:03:09 -07002118 if (bmsr & BMSR_LSTATUS) {
2119 /* Force link down */
Michael Chanca58c3a2007-05-03 13:22:52 -07002120 bnx2_write_phy(bp, bp->mii_bmcr, BMCR_LOOPBACK);
Michael Chana16dda02006-11-19 14:08:56 -08002121 spin_unlock_bh(&bp->phy_lock);
2122 msleep(50);
2123 spin_lock_bh(&bp->phy_lock);
2124
Michael Chanca58c3a2007-05-03 13:22:52 -07002125 bnx2_read_phy(bp, bp->mii_bmsr, &bmsr);
2126 bnx2_read_phy(bp, bp->mii_bmsr, &bmsr);
Michael Chanb6016b72005-05-26 13:03:09 -07002127 }
2128
Michael Chanca58c3a2007-05-03 13:22:52 -07002129 bnx2_write_phy(bp, bp->mii_bmcr, new_bmcr);
Michael Chanb6016b72005-05-26 13:03:09 -07002130
2131 /* Normally, the new speed is setup after the link has
2132 * gone down and up again. In some cases, link will not go
2133 * down so we need to set up the new speed here.
2134 */
2135 if (bmsr & BMSR_LSTATUS) {
2136 bp->line_speed = bp->req_line_speed;
2137 bp->duplex = bp->req_duplex;
2138 bnx2_resolve_flow_ctrl(bp);
2139 bnx2_set_mac_link(bp);
2140 }
Michael Chan27a005b2007-05-03 13:23:41 -07002141 } else {
2142 bnx2_resolve_flow_ctrl(bp);
2143 bnx2_set_mac_link(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07002144 }
2145 return 0;
2146}
2147
2148static int
Michael Chan0d8a6572007-07-07 22:49:43 -07002149bnx2_setup_phy(struct bnx2 *bp, u8 port)
Harvey Harrison52d07b12009-01-19 17:27:06 -08002150__releases(&bp->phy_lock)
2151__acquires(&bp->phy_lock)
Michael Chanb6016b72005-05-26 13:03:09 -07002152{
2153 if (bp->loopback == MAC_LOOPBACK)
2154 return 0;
2155
Michael Chan583c28e2008-01-21 19:51:35 -08002156 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Eric Dumazet807540b2010-09-23 05:40:09 +00002157 return bnx2_setup_serdes_phy(bp, port);
Michael Chanb6016b72005-05-26 13:03:09 -07002158 }
2159 else {
Eric Dumazet807540b2010-09-23 05:40:09 +00002160 return bnx2_setup_copper_phy(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07002161 }
2162}
2163
2164static int
Michael Chan9a120bc2008-05-16 22:17:45 -07002165bnx2_init_5709s_phy(struct bnx2 *bp, int reset_phy)
Michael Chan27a005b2007-05-03 13:23:41 -07002166{
2167 u32 val;
2168
2169 bp->mii_bmcr = MII_BMCR + 0x10;
2170 bp->mii_bmsr = MII_BMSR + 0x10;
2171 bp->mii_bmsr1 = MII_BNX2_GP_TOP_AN_STATUS1;
2172 bp->mii_adv = MII_ADVERTISE + 0x10;
2173 bp->mii_lpa = MII_LPA + 0x10;
2174 bp->mii_up1 = MII_BNX2_OVER1G_UP1;
2175
2176 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_AER);
2177 bnx2_write_phy(bp, MII_BNX2_AER_AER, MII_BNX2_AER_AER_AN_MMD);
2178
2179 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
Michael Chan9a120bc2008-05-16 22:17:45 -07002180 if (reset_phy)
2181 bnx2_reset_phy(bp);
Michael Chan27a005b2007-05-03 13:23:41 -07002182
2183 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_SERDES_DIG);
2184
2185 bnx2_read_phy(bp, MII_BNX2_SERDES_DIG_1000XCTL1, &val);
2186 val &= ~MII_BNX2_SD_1000XCTL1_AUTODET;
2187 val |= MII_BNX2_SD_1000XCTL1_FIBER;
2188 bnx2_write_phy(bp, MII_BNX2_SERDES_DIG_1000XCTL1, val);
2189
2190 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_OVER1G);
2191 bnx2_read_phy(bp, MII_BNX2_OVER1G_UP1, &val);
Michael Chan583c28e2008-01-21 19:51:35 -08002192 if (bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE)
Michael Chan27a005b2007-05-03 13:23:41 -07002193 val |= BCM5708S_UP1_2G5;
2194 else
2195 val &= ~BCM5708S_UP1_2G5;
2196 bnx2_write_phy(bp, MII_BNX2_OVER1G_UP1, val);
2197
2198 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_BAM_NXTPG);
2199 bnx2_read_phy(bp, MII_BNX2_BAM_NXTPG_CTL, &val);
2200 val |= MII_BNX2_NXTPG_CTL_T2 | MII_BNX2_NXTPG_CTL_BAM;
2201 bnx2_write_phy(bp, MII_BNX2_BAM_NXTPG_CTL, val);
2202
2203 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_CL73_USERB0);
2204
2205 val = MII_BNX2_CL73_BAM_EN | MII_BNX2_CL73_BAM_STA_MGR_EN |
2206 MII_BNX2_CL73_BAM_NP_AFT_BP_EN;
2207 bnx2_write_phy(bp, MII_BNX2_CL73_BAM_CTL1, val);
2208
2209 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
2210
2211 return 0;
2212}
2213
2214static int
Michael Chan9a120bc2008-05-16 22:17:45 -07002215bnx2_init_5708s_phy(struct bnx2 *bp, int reset_phy)
Michael Chan5b0c76a2005-11-04 08:45:49 -08002216{
2217 u32 val;
2218
Michael Chan9a120bc2008-05-16 22:17:45 -07002219 if (reset_phy)
2220 bnx2_reset_phy(bp);
Michael Chan27a005b2007-05-03 13:23:41 -07002221
2222 bp->mii_up1 = BCM5708S_UP1;
2223
Michael Chan5b0c76a2005-11-04 08:45:49 -08002224 bnx2_write_phy(bp, BCM5708S_BLK_ADDR, BCM5708S_BLK_ADDR_DIG3);
2225 bnx2_write_phy(bp, BCM5708S_DIG_3_0, BCM5708S_DIG_3_0_USE_IEEE);
2226 bnx2_write_phy(bp, BCM5708S_BLK_ADDR, BCM5708S_BLK_ADDR_DIG);
2227
2228 bnx2_read_phy(bp, BCM5708S_1000X_CTL1, &val);
2229 val |= BCM5708S_1000X_CTL1_FIBER_MODE | BCM5708S_1000X_CTL1_AUTODET_EN;
2230 bnx2_write_phy(bp, BCM5708S_1000X_CTL1, val);
2231
2232 bnx2_read_phy(bp, BCM5708S_1000X_CTL2, &val);
2233 val |= BCM5708S_1000X_CTL2_PLLEL_DET_EN;
2234 bnx2_write_phy(bp, BCM5708S_1000X_CTL2, val);
2235
Michael Chan583c28e2008-01-21 19:51:35 -08002236 if (bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE) {
Michael Chan5b0c76a2005-11-04 08:45:49 -08002237 bnx2_read_phy(bp, BCM5708S_UP1, &val);
2238 val |= BCM5708S_UP1_2G5;
2239 bnx2_write_phy(bp, BCM5708S_UP1, val);
2240 }
2241
Michael Chan4ce45e02012-12-06 10:33:10 +00002242 if ((BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5708_A0) ||
2243 (BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5708_B0) ||
2244 (BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5708_B1)) {
Michael Chan5b0c76a2005-11-04 08:45:49 -08002245 /* increase tx signal amplitude */
2246 bnx2_write_phy(bp, BCM5708S_BLK_ADDR,
2247 BCM5708S_BLK_ADDR_TX_MISC);
2248 bnx2_read_phy(bp, BCM5708S_TX_ACTL1, &val);
2249 val &= ~BCM5708S_TX_ACTL1_DRIVER_VCM;
2250 bnx2_write_phy(bp, BCM5708S_TX_ACTL1, val);
2251 bnx2_write_phy(bp, BCM5708S_BLK_ADDR, BCM5708S_BLK_ADDR_DIG);
2252 }
2253
Michael Chan2726d6e2008-01-29 21:35:05 -08002254 val = bnx2_shmem_rd(bp, BNX2_PORT_HW_CFG_CONFIG) &
Michael Chan5b0c76a2005-11-04 08:45:49 -08002255 BNX2_PORT_HW_CFG_CFG_TXCTL3_MASK;
2256
2257 if (val) {
2258 u32 is_backplane;
2259
Michael Chan2726d6e2008-01-29 21:35:05 -08002260 is_backplane = bnx2_shmem_rd(bp, BNX2_SHARED_HW_CFG_CONFIG);
Michael Chan5b0c76a2005-11-04 08:45:49 -08002261 if (is_backplane & BNX2_SHARED_HW_CFG_PHY_BACKPLANE) {
2262 bnx2_write_phy(bp, BCM5708S_BLK_ADDR,
2263 BCM5708S_BLK_ADDR_TX_MISC);
2264 bnx2_write_phy(bp, BCM5708S_TX_ACTL3, val);
2265 bnx2_write_phy(bp, BCM5708S_BLK_ADDR,
2266 BCM5708S_BLK_ADDR_DIG);
2267 }
2268 }
2269 return 0;
2270}
2271
2272static int
Michael Chan9a120bc2008-05-16 22:17:45 -07002273bnx2_init_5706s_phy(struct bnx2 *bp, int reset_phy)
Michael Chanb6016b72005-05-26 13:03:09 -07002274{
Michael Chan9a120bc2008-05-16 22:17:45 -07002275 if (reset_phy)
2276 bnx2_reset_phy(bp);
Michael Chan27a005b2007-05-03 13:23:41 -07002277
Michael Chan583c28e2008-01-21 19:51:35 -08002278 bp->phy_flags &= ~BNX2_PHY_FLAG_PARALLEL_DETECT;
Michael Chanb6016b72005-05-26 13:03:09 -07002279
Michael Chan4ce45e02012-12-06 10:33:10 +00002280 if (BNX2_CHIP(bp) == BNX2_CHIP_5706)
Michael Chane503e062012-12-06 10:33:08 +00002281 BNX2_WR(bp, BNX2_MISC_GP_HW_CTL0, 0x300);
Michael Chanb6016b72005-05-26 13:03:09 -07002282
2283 if (bp->dev->mtu > 1500) {
2284 u32 val;
2285
2286 /* Set extended packet length bit */
2287 bnx2_write_phy(bp, 0x18, 0x7);
2288 bnx2_read_phy(bp, 0x18, &val);
2289 bnx2_write_phy(bp, 0x18, (val & 0xfff8) | 0x4000);
2290
2291 bnx2_write_phy(bp, 0x1c, 0x6c00);
2292 bnx2_read_phy(bp, 0x1c, &val);
2293 bnx2_write_phy(bp, 0x1c, (val & 0x3ff) | 0xec02);
2294 }
2295 else {
2296 u32 val;
2297
2298 bnx2_write_phy(bp, 0x18, 0x7);
2299 bnx2_read_phy(bp, 0x18, &val);
2300 bnx2_write_phy(bp, 0x18, val & ~0x4007);
2301
2302 bnx2_write_phy(bp, 0x1c, 0x6c00);
2303 bnx2_read_phy(bp, 0x1c, &val);
2304 bnx2_write_phy(bp, 0x1c, (val & 0x3fd) | 0xec00);
2305 }
2306
2307 return 0;
2308}
2309
2310static int
Michael Chan9a120bc2008-05-16 22:17:45 -07002311bnx2_init_copper_phy(struct bnx2 *bp, int reset_phy)
Michael Chanb6016b72005-05-26 13:03:09 -07002312{
Michael Chan5b0c76a2005-11-04 08:45:49 -08002313 u32 val;
2314
Michael Chan9a120bc2008-05-16 22:17:45 -07002315 if (reset_phy)
2316 bnx2_reset_phy(bp);
Michael Chan27a005b2007-05-03 13:23:41 -07002317
Michael Chan583c28e2008-01-21 19:51:35 -08002318 if (bp->phy_flags & BNX2_PHY_FLAG_CRC_FIX) {
Michael Chanb6016b72005-05-26 13:03:09 -07002319 bnx2_write_phy(bp, 0x18, 0x0c00);
2320 bnx2_write_phy(bp, 0x17, 0x000a);
2321 bnx2_write_phy(bp, 0x15, 0x310b);
2322 bnx2_write_phy(bp, 0x17, 0x201f);
2323 bnx2_write_phy(bp, 0x15, 0x9506);
2324 bnx2_write_phy(bp, 0x17, 0x401f);
2325 bnx2_write_phy(bp, 0x15, 0x14e2);
2326 bnx2_write_phy(bp, 0x18, 0x0400);
2327 }
2328
Michael Chan583c28e2008-01-21 19:51:35 -08002329 if (bp->phy_flags & BNX2_PHY_FLAG_DIS_EARLY_DAC) {
Michael Chanb659f442007-02-02 00:46:35 -08002330 bnx2_write_phy(bp, MII_BNX2_DSP_ADDRESS,
2331 MII_BNX2_DSP_EXPAND_REG | 0x8);
2332 bnx2_read_phy(bp, MII_BNX2_DSP_RW_PORT, &val);
2333 val &= ~(1 << 8);
2334 bnx2_write_phy(bp, MII_BNX2_DSP_RW_PORT, val);
2335 }
2336
Michael Chanb6016b72005-05-26 13:03:09 -07002337 if (bp->dev->mtu > 1500) {
Michael Chanb6016b72005-05-26 13:03:09 -07002338 /* Set extended packet length bit */
2339 bnx2_write_phy(bp, 0x18, 0x7);
2340 bnx2_read_phy(bp, 0x18, &val);
2341 bnx2_write_phy(bp, 0x18, val | 0x4000);
2342
2343 bnx2_read_phy(bp, 0x10, &val);
2344 bnx2_write_phy(bp, 0x10, val | 0x1);
2345 }
2346 else {
Michael Chanb6016b72005-05-26 13:03:09 -07002347 bnx2_write_phy(bp, 0x18, 0x7);
2348 bnx2_read_phy(bp, 0x18, &val);
2349 bnx2_write_phy(bp, 0x18, val & ~0x4007);
2350
2351 bnx2_read_phy(bp, 0x10, &val);
2352 bnx2_write_phy(bp, 0x10, val & ~0x1);
2353 }
2354
Michael Chan5b0c76a2005-11-04 08:45:49 -08002355 /* ethernet@wirespeed */
Michael Chan41033b62013-12-31 23:22:33 -08002356 bnx2_write_phy(bp, MII_BNX2_AUX_CTL, AUX_CTL_MISC_CTL);
2357 bnx2_read_phy(bp, MII_BNX2_AUX_CTL, &val);
2358 val |= AUX_CTL_MISC_CTL_WR | AUX_CTL_MISC_CTL_WIRESPEED;
2359
2360 /* auto-mdix */
2361 if (BNX2_CHIP(bp) == BNX2_CHIP_5709)
2362 val |= AUX_CTL_MISC_CTL_AUTOMDIX;
2363
2364 bnx2_write_phy(bp, MII_BNX2_AUX_CTL, val);
Michael Chanb6016b72005-05-26 13:03:09 -07002365 return 0;
2366}
2367
2368
2369static int
Michael Chan9a120bc2008-05-16 22:17:45 -07002370bnx2_init_phy(struct bnx2 *bp, int reset_phy)
Harvey Harrison52d07b12009-01-19 17:27:06 -08002371__releases(&bp->phy_lock)
2372__acquires(&bp->phy_lock)
Michael Chanb6016b72005-05-26 13:03:09 -07002373{
2374 u32 val;
2375 int rc = 0;
2376
Michael Chan583c28e2008-01-21 19:51:35 -08002377 bp->phy_flags &= ~BNX2_PHY_FLAG_INT_MODE_MASK;
2378 bp->phy_flags |= BNX2_PHY_FLAG_INT_MODE_LINK_READY;
Michael Chanb6016b72005-05-26 13:03:09 -07002379
Michael Chanca58c3a2007-05-03 13:22:52 -07002380 bp->mii_bmcr = MII_BMCR;
2381 bp->mii_bmsr = MII_BMSR;
Michael Chan27a005b2007-05-03 13:23:41 -07002382 bp->mii_bmsr1 = MII_BMSR;
Michael Chanca58c3a2007-05-03 13:22:52 -07002383 bp->mii_adv = MII_ADVERTISE;
2384 bp->mii_lpa = MII_LPA;
2385
Michael Chane503e062012-12-06 10:33:08 +00002386 BNX2_WR(bp, BNX2_EMAC_ATTENTION_ENA, BNX2_EMAC_ATTENTION_ENA_LINK);
Michael Chanb6016b72005-05-26 13:03:09 -07002387
Michael Chan583c28e2008-01-21 19:51:35 -08002388 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
Michael Chan0d8a6572007-07-07 22:49:43 -07002389 goto setup_phy;
2390
Michael Chanb6016b72005-05-26 13:03:09 -07002391 bnx2_read_phy(bp, MII_PHYSID1, &val);
2392 bp->phy_id = val << 16;
2393 bnx2_read_phy(bp, MII_PHYSID2, &val);
2394 bp->phy_id |= val & 0xffff;
2395
Michael Chan583c28e2008-01-21 19:51:35 -08002396 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Michael Chan4ce45e02012-12-06 10:33:10 +00002397 if (BNX2_CHIP(bp) == BNX2_CHIP_5706)
Michael Chan9a120bc2008-05-16 22:17:45 -07002398 rc = bnx2_init_5706s_phy(bp, reset_phy);
Michael Chan4ce45e02012-12-06 10:33:10 +00002399 else if (BNX2_CHIP(bp) == BNX2_CHIP_5708)
Michael Chan9a120bc2008-05-16 22:17:45 -07002400 rc = bnx2_init_5708s_phy(bp, reset_phy);
Michael Chan4ce45e02012-12-06 10:33:10 +00002401 else if (BNX2_CHIP(bp) == BNX2_CHIP_5709)
Michael Chan9a120bc2008-05-16 22:17:45 -07002402 rc = bnx2_init_5709s_phy(bp, reset_phy);
Michael Chanb6016b72005-05-26 13:03:09 -07002403 }
2404 else {
Michael Chan9a120bc2008-05-16 22:17:45 -07002405 rc = bnx2_init_copper_phy(bp, reset_phy);
Michael Chanb6016b72005-05-26 13:03:09 -07002406 }
2407
Michael Chan0d8a6572007-07-07 22:49:43 -07002408setup_phy:
2409 if (!rc)
2410 rc = bnx2_setup_phy(bp, bp->phy_port);
Michael Chanb6016b72005-05-26 13:03:09 -07002411
2412 return rc;
2413}
2414
2415static int
2416bnx2_set_mac_loopback(struct bnx2 *bp)
2417{
2418 u32 mac_mode;
2419
Michael Chane503e062012-12-06 10:33:08 +00002420 mac_mode = BNX2_RD(bp, BNX2_EMAC_MODE);
Michael Chanb6016b72005-05-26 13:03:09 -07002421 mac_mode &= ~BNX2_EMAC_MODE_PORT;
2422 mac_mode |= BNX2_EMAC_MODE_MAC_LOOP | BNX2_EMAC_MODE_FORCE_LINK;
Michael Chane503e062012-12-06 10:33:08 +00002423 BNX2_WR(bp, BNX2_EMAC_MODE, mac_mode);
Michael Chanb6016b72005-05-26 13:03:09 -07002424 bp->link_up = 1;
2425 return 0;
2426}
2427
Michael Chanbc5a0692006-01-23 16:13:22 -08002428static int bnx2_test_link(struct bnx2 *);
2429
2430static int
2431bnx2_set_phy_loopback(struct bnx2 *bp)
2432{
2433 u32 mac_mode;
2434 int rc, i;
2435
2436 spin_lock_bh(&bp->phy_lock);
Michael Chanca58c3a2007-05-03 13:22:52 -07002437 rc = bnx2_write_phy(bp, bp->mii_bmcr, BMCR_LOOPBACK | BMCR_FULLDPLX |
Michael Chanbc5a0692006-01-23 16:13:22 -08002438 BMCR_SPEED1000);
2439 spin_unlock_bh(&bp->phy_lock);
2440 if (rc)
2441 return rc;
2442
2443 for (i = 0; i < 10; i++) {
2444 if (bnx2_test_link(bp) == 0)
2445 break;
Michael Chan80be4432006-11-19 14:07:28 -08002446 msleep(100);
Michael Chanbc5a0692006-01-23 16:13:22 -08002447 }
2448
Michael Chane503e062012-12-06 10:33:08 +00002449 mac_mode = BNX2_RD(bp, BNX2_EMAC_MODE);
Michael Chanbc5a0692006-01-23 16:13:22 -08002450 mac_mode &= ~(BNX2_EMAC_MODE_PORT | BNX2_EMAC_MODE_HALF_DUPLEX |
2451 BNX2_EMAC_MODE_MAC_LOOP | BNX2_EMAC_MODE_FORCE_LINK |
Michael Chan59b47d82006-11-19 14:10:45 -08002452 BNX2_EMAC_MODE_25G_MODE);
Michael Chanbc5a0692006-01-23 16:13:22 -08002453
2454 mac_mode |= BNX2_EMAC_MODE_PORT_GMII;
Michael Chane503e062012-12-06 10:33:08 +00002455 BNX2_WR(bp, BNX2_EMAC_MODE, mac_mode);
Michael Chanbc5a0692006-01-23 16:13:22 -08002456 bp->link_up = 1;
2457 return 0;
2458}
2459
Jeffrey Huangecdbf6e2011-07-13 17:24:21 +00002460static void
2461bnx2_dump_mcp_state(struct bnx2 *bp)
2462{
2463 struct net_device *dev = bp->dev;
2464 u32 mcp_p0, mcp_p1;
2465
2466 netdev_err(dev, "<--- start MCP states dump --->\n");
Michael Chan4ce45e02012-12-06 10:33:10 +00002467 if (BNX2_CHIP(bp) == BNX2_CHIP_5709) {
Jeffrey Huangecdbf6e2011-07-13 17:24:21 +00002468 mcp_p0 = BNX2_MCP_STATE_P0;
2469 mcp_p1 = BNX2_MCP_STATE_P1;
2470 } else {
2471 mcp_p0 = BNX2_MCP_STATE_P0_5708;
2472 mcp_p1 = BNX2_MCP_STATE_P1_5708;
2473 }
2474 netdev_err(dev, "DEBUG: MCP_STATE_P0[%08x] MCP_STATE_P1[%08x]\n",
2475 bnx2_reg_rd_ind(bp, mcp_p0), bnx2_reg_rd_ind(bp, mcp_p1));
2476 netdev_err(dev, "DEBUG: MCP mode[%08x] state[%08x] evt_mask[%08x]\n",
2477 bnx2_reg_rd_ind(bp, BNX2_MCP_CPU_MODE),
2478 bnx2_reg_rd_ind(bp, BNX2_MCP_CPU_STATE),
2479 bnx2_reg_rd_ind(bp, BNX2_MCP_CPU_EVENT_MASK));
2480 netdev_err(dev, "DEBUG: pc[%08x] pc[%08x] instr[%08x]\n",
2481 bnx2_reg_rd_ind(bp, BNX2_MCP_CPU_PROGRAM_COUNTER),
2482 bnx2_reg_rd_ind(bp, BNX2_MCP_CPU_PROGRAM_COUNTER),
2483 bnx2_reg_rd_ind(bp, BNX2_MCP_CPU_INSTRUCTION));
2484 netdev_err(dev, "DEBUG: shmem states:\n");
2485 netdev_err(dev, "DEBUG: drv_mb[%08x] fw_mb[%08x] link_status[%08x]",
2486 bnx2_shmem_rd(bp, BNX2_DRV_MB),
2487 bnx2_shmem_rd(bp, BNX2_FW_MB),
2488 bnx2_shmem_rd(bp, BNX2_LINK_STATUS));
2489 pr_cont(" drv_pulse_mb[%08x]\n", bnx2_shmem_rd(bp, BNX2_DRV_PULSE_MB));
2490 netdev_err(dev, "DEBUG: dev_info_signature[%08x] reset_type[%08x]",
2491 bnx2_shmem_rd(bp, BNX2_DEV_INFO_SIGNATURE),
2492 bnx2_shmem_rd(bp, BNX2_BC_STATE_RESET_TYPE));
2493 pr_cont(" condition[%08x]\n",
2494 bnx2_shmem_rd(bp, BNX2_BC_STATE_CONDITION));
Michael Chan13e63512012-06-16 15:45:42 +00002495 DP_SHMEM_LINE(bp, BNX2_BC_RESET_TYPE);
Jeffrey Huangecdbf6e2011-07-13 17:24:21 +00002496 DP_SHMEM_LINE(bp, 0x3cc);
2497 DP_SHMEM_LINE(bp, 0x3dc);
2498 DP_SHMEM_LINE(bp, 0x3ec);
2499 netdev_err(dev, "DEBUG: 0x3fc[%08x]\n", bnx2_shmem_rd(bp, 0x3fc));
2500 netdev_err(dev, "<--- end MCP states dump --->\n");
2501}
2502
Michael Chanb6016b72005-05-26 13:03:09 -07002503static int
Michael Chana2f13892008-07-14 22:38:23 -07002504bnx2_fw_sync(struct bnx2 *bp, u32 msg_data, int ack, int silent)
Michael Chanb6016b72005-05-26 13:03:09 -07002505{
2506 int i;
2507 u32 val;
2508
Michael Chanb6016b72005-05-26 13:03:09 -07002509 bp->fw_wr_seq++;
2510 msg_data |= bp->fw_wr_seq;
2511
Michael Chan2726d6e2008-01-29 21:35:05 -08002512 bnx2_shmem_wr(bp, BNX2_DRV_MB, msg_data);
Michael Chanb6016b72005-05-26 13:03:09 -07002513
Michael Chana2f13892008-07-14 22:38:23 -07002514 if (!ack)
2515 return 0;
2516
Michael Chanb6016b72005-05-26 13:03:09 -07002517 /* wait for an acknowledgement. */
Michael Chan40105c02008-11-12 16:02:45 -08002518 for (i = 0; i < (BNX2_FW_ACK_TIME_OUT_MS / 10); i++) {
Michael Chanb090ae22006-01-23 16:07:10 -08002519 msleep(10);
Michael Chanb6016b72005-05-26 13:03:09 -07002520
Michael Chan2726d6e2008-01-29 21:35:05 -08002521 val = bnx2_shmem_rd(bp, BNX2_FW_MB);
Michael Chanb6016b72005-05-26 13:03:09 -07002522
2523 if ((val & BNX2_FW_MSG_ACK) == (msg_data & BNX2_DRV_MSG_SEQ))
2524 break;
2525 }
Michael Chanb090ae22006-01-23 16:07:10 -08002526 if ((msg_data & BNX2_DRV_MSG_DATA) == BNX2_DRV_MSG_DATA_WAIT0)
2527 return 0;
Michael Chanb6016b72005-05-26 13:03:09 -07002528
2529 /* If we timed out, inform the firmware that this is the case. */
Michael Chanb090ae22006-01-23 16:07:10 -08002530 if ((val & BNX2_FW_MSG_ACK) != (msg_data & BNX2_DRV_MSG_SEQ)) {
Michael Chanb6016b72005-05-26 13:03:09 -07002531 msg_data &= ~BNX2_DRV_MSG_CODE;
2532 msg_data |= BNX2_DRV_MSG_CODE_FW_TIMEOUT;
2533
Michael Chan2726d6e2008-01-29 21:35:05 -08002534 bnx2_shmem_wr(bp, BNX2_DRV_MB, msg_data);
Jeffrey Huangecdbf6e2011-07-13 17:24:21 +00002535 if (!silent) {
2536 pr_err("fw sync timeout, reset code = %x\n", msg_data);
2537 bnx2_dump_mcp_state(bp);
2538 }
Michael Chanb6016b72005-05-26 13:03:09 -07002539
Michael Chanb6016b72005-05-26 13:03:09 -07002540 return -EBUSY;
2541 }
2542
Michael Chanb090ae22006-01-23 16:07:10 -08002543 if ((val & BNX2_FW_MSG_STATUS_MASK) != BNX2_FW_MSG_STATUS_OK)
2544 return -EIO;
2545
Michael Chanb6016b72005-05-26 13:03:09 -07002546 return 0;
2547}
2548
Michael Chan59b47d82006-11-19 14:10:45 -08002549static int
2550bnx2_init_5709_context(struct bnx2 *bp)
2551{
2552 int i, ret = 0;
2553 u32 val;
2554
2555 val = BNX2_CTX_COMMAND_ENABLED | BNX2_CTX_COMMAND_MEM_INIT | (1 << 12);
Michael Chan2bc40782012-12-06 10:33:09 +00002556 val |= (BNX2_PAGE_BITS - 8) << 16;
Michael Chane503e062012-12-06 10:33:08 +00002557 BNX2_WR(bp, BNX2_CTX_COMMAND, val);
Michael Chan641bdcd2007-06-04 21:22:24 -07002558 for (i = 0; i < 10; i++) {
Michael Chane503e062012-12-06 10:33:08 +00002559 val = BNX2_RD(bp, BNX2_CTX_COMMAND);
Michael Chan641bdcd2007-06-04 21:22:24 -07002560 if (!(val & BNX2_CTX_COMMAND_MEM_INIT))
2561 break;
2562 udelay(2);
2563 }
2564 if (val & BNX2_CTX_COMMAND_MEM_INIT)
2565 return -EBUSY;
2566
Michael Chan59b47d82006-11-19 14:10:45 -08002567 for (i = 0; i < bp->ctx_pages; i++) {
2568 int j;
2569
Michael Chan352f7682008-05-02 16:57:26 -07002570 if (bp->ctx_blk[i])
Michael Chan2bc40782012-12-06 10:33:09 +00002571 memset(bp->ctx_blk[i], 0, BNX2_PAGE_SIZE);
Michael Chan352f7682008-05-02 16:57:26 -07002572 else
2573 return -ENOMEM;
2574
Michael Chane503e062012-12-06 10:33:08 +00002575 BNX2_WR(bp, BNX2_CTX_HOST_PAGE_TBL_DATA0,
2576 (bp->ctx_blk_mapping[i] & 0xffffffff) |
2577 BNX2_CTX_HOST_PAGE_TBL_DATA0_VALID);
2578 BNX2_WR(bp, BNX2_CTX_HOST_PAGE_TBL_DATA1,
2579 (u64) bp->ctx_blk_mapping[i] >> 32);
2580 BNX2_WR(bp, BNX2_CTX_HOST_PAGE_TBL_CTRL, i |
2581 BNX2_CTX_HOST_PAGE_TBL_CTRL_WRITE_REQ);
Michael Chan59b47d82006-11-19 14:10:45 -08002582 for (j = 0; j < 10; j++) {
2583
Michael Chane503e062012-12-06 10:33:08 +00002584 val = BNX2_RD(bp, BNX2_CTX_HOST_PAGE_TBL_CTRL);
Michael Chan59b47d82006-11-19 14:10:45 -08002585 if (!(val & BNX2_CTX_HOST_PAGE_TBL_CTRL_WRITE_REQ))
2586 break;
2587 udelay(5);
2588 }
2589 if (val & BNX2_CTX_HOST_PAGE_TBL_CTRL_WRITE_REQ) {
2590 ret = -EBUSY;
2591 break;
2592 }
2593 }
2594 return ret;
2595}
2596
Michael Chanb6016b72005-05-26 13:03:09 -07002597static void
2598bnx2_init_context(struct bnx2 *bp)
2599{
2600 u32 vcid;
2601
2602 vcid = 96;
2603 while (vcid) {
2604 u32 vcid_addr, pcid_addr, offset;
Michael Chan7947b202007-06-04 21:17:10 -07002605 int i;
Michael Chanb6016b72005-05-26 13:03:09 -07002606
2607 vcid--;
2608
Michael Chan4ce45e02012-12-06 10:33:10 +00002609 if (BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5706_A0) {
Michael Chanb6016b72005-05-26 13:03:09 -07002610 u32 new_vcid;
2611
2612 vcid_addr = GET_PCID_ADDR(vcid);
2613 if (vcid & 0x8) {
2614 new_vcid = 0x60 + (vcid & 0xf0) + (vcid & 0x7);
2615 }
2616 else {
2617 new_vcid = vcid;
2618 }
2619 pcid_addr = GET_PCID_ADDR(new_vcid);
2620 }
2621 else {
2622 vcid_addr = GET_CID_ADDR(vcid);
2623 pcid_addr = vcid_addr;
2624 }
2625
Michael Chan7947b202007-06-04 21:17:10 -07002626 for (i = 0; i < (CTX_SIZE / PHY_CTX_SIZE); i++) {
2627 vcid_addr += (i << PHY_CTX_SHIFT);
2628 pcid_addr += (i << PHY_CTX_SHIFT);
Michael Chanb6016b72005-05-26 13:03:09 -07002629
Michael Chane503e062012-12-06 10:33:08 +00002630 BNX2_WR(bp, BNX2_CTX_VIRT_ADDR, vcid_addr);
2631 BNX2_WR(bp, BNX2_CTX_PAGE_TBL, pcid_addr);
Michael Chan7947b202007-06-04 21:17:10 -07002632
2633 /* Zero out the context. */
2634 for (offset = 0; offset < PHY_CTX_SIZE; offset += 4)
Michael Chan62a83132008-01-29 21:35:40 -08002635 bnx2_ctx_wr(bp, vcid_addr, offset, 0);
Michael Chanb6016b72005-05-26 13:03:09 -07002636 }
Michael Chanb6016b72005-05-26 13:03:09 -07002637 }
2638}
2639
2640static int
2641bnx2_alloc_bad_rbuf(struct bnx2 *bp)
2642{
2643 u16 *good_mbuf;
2644 u32 good_mbuf_cnt;
2645 u32 val;
2646
2647 good_mbuf = kmalloc(512 * sizeof(u16), GFP_KERNEL);
Joe Perchese404dec2012-01-29 12:56:23 +00002648 if (good_mbuf == NULL)
Michael Chanb6016b72005-05-26 13:03:09 -07002649 return -ENOMEM;
Michael Chanb6016b72005-05-26 13:03:09 -07002650
Michael Chane503e062012-12-06 10:33:08 +00002651 BNX2_WR(bp, BNX2_MISC_ENABLE_SET_BITS,
Michael Chanb6016b72005-05-26 13:03:09 -07002652 BNX2_MISC_ENABLE_SET_BITS_RX_MBUF_ENABLE);
2653
2654 good_mbuf_cnt = 0;
2655
2656 /* Allocate a bunch of mbufs and save the good ones in an array. */
Michael Chan2726d6e2008-01-29 21:35:05 -08002657 val = bnx2_reg_rd_ind(bp, BNX2_RBUF_STATUS1);
Michael Chanb6016b72005-05-26 13:03:09 -07002658 while (val & BNX2_RBUF_STATUS1_FREE_COUNT) {
Michael Chan2726d6e2008-01-29 21:35:05 -08002659 bnx2_reg_wr_ind(bp, BNX2_RBUF_COMMAND,
2660 BNX2_RBUF_COMMAND_ALLOC_REQ);
Michael Chanb6016b72005-05-26 13:03:09 -07002661
Michael Chan2726d6e2008-01-29 21:35:05 -08002662 val = bnx2_reg_rd_ind(bp, BNX2_RBUF_FW_BUF_ALLOC);
Michael Chanb6016b72005-05-26 13:03:09 -07002663
2664 val &= BNX2_RBUF_FW_BUF_ALLOC_VALUE;
2665
2666 /* The addresses with Bit 9 set are bad memory blocks. */
2667 if (!(val & (1 << 9))) {
2668 good_mbuf[good_mbuf_cnt] = (u16) val;
2669 good_mbuf_cnt++;
2670 }
2671
Michael Chan2726d6e2008-01-29 21:35:05 -08002672 val = bnx2_reg_rd_ind(bp, BNX2_RBUF_STATUS1);
Michael Chanb6016b72005-05-26 13:03:09 -07002673 }
2674
2675 /* Free the good ones back to the mbuf pool thus discarding
2676 * all the bad ones. */
2677 while (good_mbuf_cnt) {
2678 good_mbuf_cnt--;
2679
2680 val = good_mbuf[good_mbuf_cnt];
2681 val = (val << 9) | val | 1;
2682
Michael Chan2726d6e2008-01-29 21:35:05 -08002683 bnx2_reg_wr_ind(bp, BNX2_RBUF_FW_BUF_FREE, val);
Michael Chanb6016b72005-05-26 13:03:09 -07002684 }
2685 kfree(good_mbuf);
2686 return 0;
2687}
2688
2689static void
Benjamin Li5fcaed02008-07-14 22:39:52 -07002690bnx2_set_mac_addr(struct bnx2 *bp, u8 *mac_addr, u32 pos)
Michael Chanb6016b72005-05-26 13:03:09 -07002691{
2692 u32 val;
Michael Chanb6016b72005-05-26 13:03:09 -07002693
2694 val = (mac_addr[0] << 8) | mac_addr[1];
2695
Michael Chane503e062012-12-06 10:33:08 +00002696 BNX2_WR(bp, BNX2_EMAC_MAC_MATCH0 + (pos * 8), val);
Michael Chanb6016b72005-05-26 13:03:09 -07002697
Jeff Garzik6aa20a22006-09-13 13:24:59 -04002698 val = (mac_addr[2] << 24) | (mac_addr[3] << 16) |
Michael Chanb6016b72005-05-26 13:03:09 -07002699 (mac_addr[4] << 8) | mac_addr[5];
2700
Michael Chane503e062012-12-06 10:33:08 +00002701 BNX2_WR(bp, BNX2_EMAC_MAC_MATCH1 + (pos * 8), val);
Michael Chanb6016b72005-05-26 13:03:09 -07002702}
2703
2704static inline int
Stanislaw Gruszkaa2df00a2010-07-15 22:55:40 +00002705bnx2_alloc_rx_page(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr, u16 index, gfp_t gfp)
Michael Chan47bf4242007-12-12 11:19:12 -08002706{
2707 dma_addr_t mapping;
Michael Chan2bc40782012-12-06 10:33:09 +00002708 struct bnx2_sw_pg *rx_pg = &rxr->rx_pg_ring[index];
2709 struct bnx2_rx_bd *rxbd =
2710 &rxr->rx_pg_desc_ring[BNX2_RX_RING(index)][BNX2_RX_IDX(index)];
Stanislaw Gruszkaa2df00a2010-07-15 22:55:40 +00002711 struct page *page = alloc_page(gfp);
Michael Chan47bf4242007-12-12 11:19:12 -08002712
2713 if (!page)
2714 return -ENOMEM;
Stanislaw Gruszka36227e82010-07-15 04:25:50 +00002715 mapping = dma_map_page(&bp->pdev->dev, page, 0, PAGE_SIZE,
Michael Chan47bf4242007-12-12 11:19:12 -08002716 PCI_DMA_FROMDEVICE);
Stanislaw Gruszka36227e82010-07-15 04:25:50 +00002717 if (dma_mapping_error(&bp->pdev->dev, mapping)) {
Benjamin Li3d16af82008-10-09 12:26:41 -07002718 __free_page(page);
2719 return -EIO;
2720 }
2721
Michael Chan47bf4242007-12-12 11:19:12 -08002722 rx_pg->page = page;
FUJITA Tomonori1a4ccc22010-04-01 16:56:57 +00002723 dma_unmap_addr_set(rx_pg, mapping, mapping);
Michael Chan47bf4242007-12-12 11:19:12 -08002724 rxbd->rx_bd_haddr_hi = (u64) mapping >> 32;
2725 rxbd->rx_bd_haddr_lo = (u64) mapping & 0xffffffff;
2726 return 0;
2727}
2728
2729static void
Michael Chanbb4f98a2008-06-19 16:38:19 -07002730bnx2_free_rx_page(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr, u16 index)
Michael Chan47bf4242007-12-12 11:19:12 -08002731{
Michael Chan2bc40782012-12-06 10:33:09 +00002732 struct bnx2_sw_pg *rx_pg = &rxr->rx_pg_ring[index];
Michael Chan47bf4242007-12-12 11:19:12 -08002733 struct page *page = rx_pg->page;
2734
2735 if (!page)
2736 return;
2737
Stanislaw Gruszka36227e82010-07-15 04:25:50 +00002738 dma_unmap_page(&bp->pdev->dev, dma_unmap_addr(rx_pg, mapping),
2739 PAGE_SIZE, PCI_DMA_FROMDEVICE);
Michael Chan47bf4242007-12-12 11:19:12 -08002740
2741 __free_page(page);
2742 rx_pg->page = NULL;
2743}
2744
2745static inline int
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00002746bnx2_alloc_rx_data(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr, u16 index, gfp_t gfp)
Michael Chanb6016b72005-05-26 13:03:09 -07002747{
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00002748 u8 *data;
Michael Chan2bc40782012-12-06 10:33:09 +00002749 struct bnx2_sw_bd *rx_buf = &rxr->rx_buf_ring[index];
Michael Chanb6016b72005-05-26 13:03:09 -07002750 dma_addr_t mapping;
Michael Chan2bc40782012-12-06 10:33:09 +00002751 struct bnx2_rx_bd *rxbd =
2752 &rxr->rx_desc_ring[BNX2_RX_RING(index)][BNX2_RX_IDX(index)];
Michael Chanb6016b72005-05-26 13:03:09 -07002753
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00002754 data = kmalloc(bp->rx_buf_size, gfp);
2755 if (!data)
Michael Chanb6016b72005-05-26 13:03:09 -07002756 return -ENOMEM;
Michael Chanb6016b72005-05-26 13:03:09 -07002757
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00002758 mapping = dma_map_single(&bp->pdev->dev,
2759 get_l2_fhdr(data),
2760 bp->rx_buf_use_size,
Stanislaw Gruszka36227e82010-07-15 04:25:50 +00002761 PCI_DMA_FROMDEVICE);
2762 if (dma_mapping_error(&bp->pdev->dev, mapping)) {
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00002763 kfree(data);
Benjamin Li3d16af82008-10-09 12:26:41 -07002764 return -EIO;
2765 }
Michael Chanb6016b72005-05-26 13:03:09 -07002766
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00002767 rx_buf->data = data;
FUJITA Tomonori1a4ccc22010-04-01 16:56:57 +00002768 dma_unmap_addr_set(rx_buf, mapping, mapping);
Michael Chanb6016b72005-05-26 13:03:09 -07002769
2770 rxbd->rx_bd_haddr_hi = (u64) mapping >> 32;
2771 rxbd->rx_bd_haddr_lo = (u64) mapping & 0xffffffff;
2772
Michael Chanbb4f98a2008-06-19 16:38:19 -07002773 rxr->rx_prod_bseq += bp->rx_buf_use_size;
Michael Chanb6016b72005-05-26 13:03:09 -07002774
2775 return 0;
2776}
2777
Michael Chanda3e4fb2007-05-03 13:24:23 -07002778static int
Michael Chan35efa7c2007-12-20 19:56:37 -08002779bnx2_phy_event_is_set(struct bnx2 *bp, struct bnx2_napi *bnapi, u32 event)
Michael Chanda3e4fb2007-05-03 13:24:23 -07002780{
Michael Chan43e80b82008-06-19 16:41:08 -07002781 struct status_block *sblk = bnapi->status_blk.msi;
Michael Chanda3e4fb2007-05-03 13:24:23 -07002782 u32 new_link_state, old_link_state;
2783 int is_set = 1;
2784
2785 new_link_state = sblk->status_attn_bits & event;
2786 old_link_state = sblk->status_attn_bits_ack & event;
2787 if (new_link_state != old_link_state) {
2788 if (new_link_state)
Michael Chane503e062012-12-06 10:33:08 +00002789 BNX2_WR(bp, BNX2_PCICFG_STATUS_BIT_SET_CMD, event);
Michael Chanda3e4fb2007-05-03 13:24:23 -07002790 else
Michael Chane503e062012-12-06 10:33:08 +00002791 BNX2_WR(bp, BNX2_PCICFG_STATUS_BIT_CLEAR_CMD, event);
Michael Chanda3e4fb2007-05-03 13:24:23 -07002792 } else
2793 is_set = 0;
2794
2795 return is_set;
2796}
2797
Michael Chanb6016b72005-05-26 13:03:09 -07002798static void
Michael Chan35efa7c2007-12-20 19:56:37 -08002799bnx2_phy_int(struct bnx2 *bp, struct bnx2_napi *bnapi)
Michael Chanb6016b72005-05-26 13:03:09 -07002800{
Michael Chan74ecc622008-05-02 16:56:16 -07002801 spin_lock(&bp->phy_lock);
2802
2803 if (bnx2_phy_event_is_set(bp, bnapi, STATUS_ATTN_BITS_LINK_STATE))
Michael Chanb6016b72005-05-26 13:03:09 -07002804 bnx2_set_link(bp);
Michael Chan35efa7c2007-12-20 19:56:37 -08002805 if (bnx2_phy_event_is_set(bp, bnapi, STATUS_ATTN_BITS_TIMER_ABORT))
Michael Chan0d8a6572007-07-07 22:49:43 -07002806 bnx2_set_remote_link(bp);
2807
Michael Chan74ecc622008-05-02 16:56:16 -07002808 spin_unlock(&bp->phy_lock);
2809
Michael Chanb6016b72005-05-26 13:03:09 -07002810}
2811
Michael Chanead72702007-12-20 19:55:39 -08002812static inline u16
Michael Chan35efa7c2007-12-20 19:56:37 -08002813bnx2_get_hw_tx_cons(struct bnx2_napi *bnapi)
Michael Chanead72702007-12-20 19:55:39 -08002814{
2815 u16 cons;
2816
Michael Chan43e80b82008-06-19 16:41:08 -07002817 /* Tell compiler that status block fields can change. */
2818 barrier();
2819 cons = *bnapi->hw_tx_cons_ptr;
Michael Chan581daf72009-05-06 16:46:47 -07002820 barrier();
Michael Chan2bc40782012-12-06 10:33:09 +00002821 if (unlikely((cons & BNX2_MAX_TX_DESC_CNT) == BNX2_MAX_TX_DESC_CNT))
Michael Chanead72702007-12-20 19:55:39 -08002822 cons++;
2823 return cons;
2824}
2825
Michael Chan57851d82007-12-20 20:01:44 -08002826static int
2827bnx2_tx_int(struct bnx2 *bp, struct bnx2_napi *bnapi, int budget)
Michael Chanb6016b72005-05-26 13:03:09 -07002828{
Michael Chan35e90102008-06-19 16:37:42 -07002829 struct bnx2_tx_ring_info *txr = &bnapi->tx_ring;
Michael Chanb6016b72005-05-26 13:03:09 -07002830 u16 hw_cons, sw_cons, sw_ring_cons;
Benjamin Li706bf242008-07-18 17:55:11 -07002831 int tx_pkt = 0, index;
Eric Dumazete9831902011-11-29 11:53:05 +00002832 unsigned int tx_bytes = 0;
Benjamin Li706bf242008-07-18 17:55:11 -07002833 struct netdev_queue *txq;
2834
2835 index = (bnapi - bp->bnx2_napi);
2836 txq = netdev_get_tx_queue(bp->dev, index);
Michael Chanb6016b72005-05-26 13:03:09 -07002837
Michael Chan35efa7c2007-12-20 19:56:37 -08002838 hw_cons = bnx2_get_hw_tx_cons(bnapi);
Michael Chan35e90102008-06-19 16:37:42 -07002839 sw_cons = txr->tx_cons;
Michael Chanb6016b72005-05-26 13:03:09 -07002840
2841 while (sw_cons != hw_cons) {
Michael Chan2bc40782012-12-06 10:33:09 +00002842 struct bnx2_sw_tx_bd *tx_buf;
Michael Chanb6016b72005-05-26 13:03:09 -07002843 struct sk_buff *skb;
2844 int i, last;
2845
Michael Chan2bc40782012-12-06 10:33:09 +00002846 sw_ring_cons = BNX2_TX_RING_IDX(sw_cons);
Michael Chanb6016b72005-05-26 13:03:09 -07002847
Michael Chan35e90102008-06-19 16:37:42 -07002848 tx_buf = &txr->tx_buf_ring[sw_ring_cons];
Michael Chanb6016b72005-05-26 13:03:09 -07002849 skb = tx_buf->skb;
Arjan van de Ven1d39ed52006-12-12 14:06:23 +01002850
Eric Dumazetd62fda02009-05-12 20:48:02 +00002851 /* prefetch skb_end_pointer() to speedup skb_shinfo(skb) */
2852 prefetch(&skb->end);
2853
Michael Chanb6016b72005-05-26 13:03:09 -07002854 /* partial BD completions possible with TSO packets */
Eric Dumazetd62fda02009-05-12 20:48:02 +00002855 if (tx_buf->is_gso) {
Michael Chanb6016b72005-05-26 13:03:09 -07002856 u16 last_idx, last_ring_idx;
2857
Eric Dumazetd62fda02009-05-12 20:48:02 +00002858 last_idx = sw_cons + tx_buf->nr_frags + 1;
2859 last_ring_idx = sw_ring_cons + tx_buf->nr_frags + 1;
Michael Chan2bc40782012-12-06 10:33:09 +00002860 if (unlikely(last_ring_idx >= BNX2_MAX_TX_DESC_CNT)) {
Michael Chanb6016b72005-05-26 13:03:09 -07002861 last_idx++;
2862 }
2863 if (((s16) ((s16) last_idx - (s16) hw_cons)) > 0) {
2864 break;
2865 }
2866 }
Arjan van de Ven1d39ed52006-12-12 14:06:23 +01002867
Stanislaw Gruszka36227e82010-07-15 04:25:50 +00002868 dma_unmap_single(&bp->pdev->dev, dma_unmap_addr(tx_buf, mapping),
Alexander Duycke95524a2009-12-02 16:47:57 +00002869 skb_headlen(skb), PCI_DMA_TODEVICE);
Michael Chanb6016b72005-05-26 13:03:09 -07002870
2871 tx_buf->skb = NULL;
Eric Dumazetd62fda02009-05-12 20:48:02 +00002872 last = tx_buf->nr_frags;
Michael Chanb6016b72005-05-26 13:03:09 -07002873
2874 for (i = 0; i < last; i++) {
Michael Chan2bc40782012-12-06 10:33:09 +00002875 struct bnx2_sw_tx_bd *tx_buf;
Alexander Duycke95524a2009-12-02 16:47:57 +00002876
Michael Chan2bc40782012-12-06 10:33:09 +00002877 sw_cons = BNX2_NEXT_TX_BD(sw_cons);
2878
2879 tx_buf = &txr->tx_buf_ring[BNX2_TX_RING_IDX(sw_cons)];
Stanislaw Gruszka36227e82010-07-15 04:25:50 +00002880 dma_unmap_page(&bp->pdev->dev,
Michael Chan2bc40782012-12-06 10:33:09 +00002881 dma_unmap_addr(tx_buf, mapping),
Eric Dumazet9e903e02011-10-18 21:00:24 +00002882 skb_frag_size(&skb_shinfo(skb)->frags[i]),
Alexander Duycke95524a2009-12-02 16:47:57 +00002883 PCI_DMA_TODEVICE);
Michael Chanb6016b72005-05-26 13:03:09 -07002884 }
2885
Michael Chan2bc40782012-12-06 10:33:09 +00002886 sw_cons = BNX2_NEXT_TX_BD(sw_cons);
Michael Chanb6016b72005-05-26 13:03:09 -07002887
Eric Dumazete9831902011-11-29 11:53:05 +00002888 tx_bytes += skb->len;
Michael Chan745720e2006-06-29 12:37:41 -07002889 dev_kfree_skb(skb);
Michael Chan57851d82007-12-20 20:01:44 -08002890 tx_pkt++;
2891 if (tx_pkt == budget)
2892 break;
Michael Chanb6016b72005-05-26 13:03:09 -07002893
Eric Dumazetd62fda02009-05-12 20:48:02 +00002894 if (hw_cons == sw_cons)
2895 hw_cons = bnx2_get_hw_tx_cons(bnapi);
Michael Chanb6016b72005-05-26 13:03:09 -07002896 }
2897
Eric Dumazete9831902011-11-29 11:53:05 +00002898 netdev_tx_completed_queue(txq, tx_pkt, tx_bytes);
Michael Chan35e90102008-06-19 16:37:42 -07002899 txr->hw_tx_cons = hw_cons;
2900 txr->tx_cons = sw_cons;
Benjamin Li706bf242008-07-18 17:55:11 -07002901
Michael Chan2f8af122006-08-15 01:39:10 -07002902 /* Need to make the tx_cons update visible to bnx2_start_xmit()
Benjamin Li706bf242008-07-18 17:55:11 -07002903 * before checking for netif_tx_queue_stopped(). Without the
Michael Chan2f8af122006-08-15 01:39:10 -07002904 * memory barrier, there is a small possibility that bnx2_start_xmit()
2905 * will miss it and cause the queue to be stopped forever.
2906 */
2907 smp_mb();
Michael Chanb6016b72005-05-26 13:03:09 -07002908
Benjamin Li706bf242008-07-18 17:55:11 -07002909 if (unlikely(netif_tx_queue_stopped(txq)) &&
Michael Chan35e90102008-06-19 16:37:42 -07002910 (bnx2_tx_avail(bp, txr) > bp->tx_wake_thresh)) {
Benjamin Li706bf242008-07-18 17:55:11 -07002911 __netif_tx_lock(txq, smp_processor_id());
2912 if ((netif_tx_queue_stopped(txq)) &&
Michael Chan35e90102008-06-19 16:37:42 -07002913 (bnx2_tx_avail(bp, txr) > bp->tx_wake_thresh))
Benjamin Li706bf242008-07-18 17:55:11 -07002914 netif_tx_wake_queue(txq);
2915 __netif_tx_unlock(txq);
Michael Chanb6016b72005-05-26 13:03:09 -07002916 }
Benjamin Li706bf242008-07-18 17:55:11 -07002917
Michael Chan57851d82007-12-20 20:01:44 -08002918 return tx_pkt;
Michael Chanb6016b72005-05-26 13:03:09 -07002919}
2920
Michael Chan1db82f22007-12-12 11:19:35 -08002921static void
Michael Chanbb4f98a2008-06-19 16:38:19 -07002922bnx2_reuse_rx_skb_pages(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr,
Michael Chana1f60192007-12-20 19:57:19 -08002923 struct sk_buff *skb, int count)
Michael Chan1db82f22007-12-12 11:19:35 -08002924{
Michael Chan2bc40782012-12-06 10:33:09 +00002925 struct bnx2_sw_pg *cons_rx_pg, *prod_rx_pg;
2926 struct bnx2_rx_bd *cons_bd, *prod_bd;
Michael Chan1db82f22007-12-12 11:19:35 -08002927 int i;
Benjamin Li3d16af82008-10-09 12:26:41 -07002928 u16 hw_prod, prod;
Michael Chanbb4f98a2008-06-19 16:38:19 -07002929 u16 cons = rxr->rx_pg_cons;
Michael Chan1db82f22007-12-12 11:19:35 -08002930
Benjamin Li3d16af82008-10-09 12:26:41 -07002931 cons_rx_pg = &rxr->rx_pg_ring[cons];
2932
2933 /* The caller was unable to allocate a new page to replace the
2934 * last one in the frags array, so we need to recycle that page
2935 * and then free the skb.
2936 */
2937 if (skb) {
2938 struct page *page;
2939 struct skb_shared_info *shinfo;
2940
2941 shinfo = skb_shinfo(skb);
2942 shinfo->nr_frags--;
Ian Campbellb7b6a682011-08-24 22:28:12 +00002943 page = skb_frag_page(&shinfo->frags[shinfo->nr_frags]);
2944 __skb_frag_set_page(&shinfo->frags[shinfo->nr_frags], NULL);
Benjamin Li3d16af82008-10-09 12:26:41 -07002945
2946 cons_rx_pg->page = page;
2947 dev_kfree_skb(skb);
2948 }
2949
2950 hw_prod = rxr->rx_pg_prod;
2951
Michael Chan1db82f22007-12-12 11:19:35 -08002952 for (i = 0; i < count; i++) {
Michael Chan2bc40782012-12-06 10:33:09 +00002953 prod = BNX2_RX_PG_RING_IDX(hw_prod);
Michael Chan1db82f22007-12-12 11:19:35 -08002954
Michael Chanbb4f98a2008-06-19 16:38:19 -07002955 prod_rx_pg = &rxr->rx_pg_ring[prod];
2956 cons_rx_pg = &rxr->rx_pg_ring[cons];
Michael Chan2bc40782012-12-06 10:33:09 +00002957 cons_bd = &rxr->rx_pg_desc_ring[BNX2_RX_RING(cons)]
2958 [BNX2_RX_IDX(cons)];
2959 prod_bd = &rxr->rx_pg_desc_ring[BNX2_RX_RING(prod)]
2960 [BNX2_RX_IDX(prod)];
Michael Chan1db82f22007-12-12 11:19:35 -08002961
Michael Chan1db82f22007-12-12 11:19:35 -08002962 if (prod != cons) {
2963 prod_rx_pg->page = cons_rx_pg->page;
2964 cons_rx_pg->page = NULL;
FUJITA Tomonori1a4ccc22010-04-01 16:56:57 +00002965 dma_unmap_addr_set(prod_rx_pg, mapping,
2966 dma_unmap_addr(cons_rx_pg, mapping));
Michael Chan1db82f22007-12-12 11:19:35 -08002967
2968 prod_bd->rx_bd_haddr_hi = cons_bd->rx_bd_haddr_hi;
2969 prod_bd->rx_bd_haddr_lo = cons_bd->rx_bd_haddr_lo;
2970
2971 }
Michael Chan2bc40782012-12-06 10:33:09 +00002972 cons = BNX2_RX_PG_RING_IDX(BNX2_NEXT_RX_BD(cons));
2973 hw_prod = BNX2_NEXT_RX_BD(hw_prod);
Michael Chan1db82f22007-12-12 11:19:35 -08002974 }
Michael Chanbb4f98a2008-06-19 16:38:19 -07002975 rxr->rx_pg_prod = hw_prod;
2976 rxr->rx_pg_cons = cons;
Michael Chan1db82f22007-12-12 11:19:35 -08002977}
2978
Michael Chanb6016b72005-05-26 13:03:09 -07002979static inline void
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00002980bnx2_reuse_rx_data(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr,
2981 u8 *data, u16 cons, u16 prod)
Michael Chanb6016b72005-05-26 13:03:09 -07002982{
Michael Chan2bc40782012-12-06 10:33:09 +00002983 struct bnx2_sw_bd *cons_rx_buf, *prod_rx_buf;
2984 struct bnx2_rx_bd *cons_bd, *prod_bd;
Michael Chan236b6392006-03-20 17:49:02 -08002985
Michael Chanbb4f98a2008-06-19 16:38:19 -07002986 cons_rx_buf = &rxr->rx_buf_ring[cons];
2987 prod_rx_buf = &rxr->rx_buf_ring[prod];
Michael Chanb6016b72005-05-26 13:03:09 -07002988
Stanislaw Gruszka36227e82010-07-15 04:25:50 +00002989 dma_sync_single_for_device(&bp->pdev->dev,
FUJITA Tomonori1a4ccc22010-04-01 16:56:57 +00002990 dma_unmap_addr(cons_rx_buf, mapping),
Benjamin Li601d3d12008-05-16 22:19:35 -07002991 BNX2_RX_OFFSET + BNX2_RX_COPY_THRESH, PCI_DMA_FROMDEVICE);
Michael Chanb6016b72005-05-26 13:03:09 -07002992
Michael Chanbb4f98a2008-06-19 16:38:19 -07002993 rxr->rx_prod_bseq += bp->rx_buf_use_size;
Michael Chan236b6392006-03-20 17:49:02 -08002994
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00002995 prod_rx_buf->data = data;
Michael Chan236b6392006-03-20 17:49:02 -08002996
2997 if (cons == prod)
2998 return;
2999
FUJITA Tomonori1a4ccc22010-04-01 16:56:57 +00003000 dma_unmap_addr_set(prod_rx_buf, mapping,
3001 dma_unmap_addr(cons_rx_buf, mapping));
Michael Chanb6016b72005-05-26 13:03:09 -07003002
Michael Chan2bc40782012-12-06 10:33:09 +00003003 cons_bd = &rxr->rx_desc_ring[BNX2_RX_RING(cons)][BNX2_RX_IDX(cons)];
3004 prod_bd = &rxr->rx_desc_ring[BNX2_RX_RING(prod)][BNX2_RX_IDX(prod)];
Michael Chan236b6392006-03-20 17:49:02 -08003005 prod_bd->rx_bd_haddr_hi = cons_bd->rx_bd_haddr_hi;
3006 prod_bd->rx_bd_haddr_lo = cons_bd->rx_bd_haddr_lo;
Michael Chanb6016b72005-05-26 13:03:09 -07003007}
3008
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00003009static struct sk_buff *
3010bnx2_rx_skb(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr, u8 *data,
Michael Chana1f60192007-12-20 19:57:19 -08003011 unsigned int len, unsigned int hdr_len, dma_addr_t dma_addr,
3012 u32 ring_idx)
Michael Chan85833c62007-12-12 11:17:01 -08003013{
3014 int err;
3015 u16 prod = ring_idx & 0xffff;
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00003016 struct sk_buff *skb;
Michael Chan85833c62007-12-12 11:17:01 -08003017
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00003018 err = bnx2_alloc_rx_data(bp, rxr, prod, GFP_ATOMIC);
Michael Chan85833c62007-12-12 11:17:01 -08003019 if (unlikely(err)) {
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00003020 bnx2_reuse_rx_data(bp, rxr, data, (u16) (ring_idx >> 16), prod);
3021error:
Michael Chan1db82f22007-12-12 11:19:35 -08003022 if (hdr_len) {
3023 unsigned int raw_len = len + 4;
3024 int pages = PAGE_ALIGN(raw_len - hdr_len) >> PAGE_SHIFT;
3025
Michael Chanbb4f98a2008-06-19 16:38:19 -07003026 bnx2_reuse_rx_skb_pages(bp, rxr, NULL, pages);
Michael Chan1db82f22007-12-12 11:19:35 -08003027 }
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00003028 return NULL;
Michael Chan85833c62007-12-12 11:17:01 -08003029 }
3030
Stanislaw Gruszka36227e82010-07-15 04:25:50 +00003031 dma_unmap_single(&bp->pdev->dev, dma_addr, bp->rx_buf_use_size,
Michael Chan85833c62007-12-12 11:17:01 -08003032 PCI_DMA_FROMDEVICE);
Eric Dumazetd3836f22012-04-27 00:33:38 +00003033 skb = build_skb(data, 0);
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00003034 if (!skb) {
3035 kfree(data);
3036 goto error;
3037 }
3038 skb_reserve(skb, ((u8 *)get_l2_fhdr(data) - data) + BNX2_RX_OFFSET);
Michael Chan1db82f22007-12-12 11:19:35 -08003039 if (hdr_len == 0) {
3040 skb_put(skb, len);
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00003041 return skb;
Michael Chan1db82f22007-12-12 11:19:35 -08003042 } else {
3043 unsigned int i, frag_len, frag_size, pages;
Michael Chan2bc40782012-12-06 10:33:09 +00003044 struct bnx2_sw_pg *rx_pg;
Michael Chanbb4f98a2008-06-19 16:38:19 -07003045 u16 pg_cons = rxr->rx_pg_cons;
3046 u16 pg_prod = rxr->rx_pg_prod;
Michael Chan1db82f22007-12-12 11:19:35 -08003047
3048 frag_size = len + 4 - hdr_len;
3049 pages = PAGE_ALIGN(frag_size) >> PAGE_SHIFT;
3050 skb_put(skb, hdr_len);
3051
3052 for (i = 0; i < pages; i++) {
Benjamin Li3d16af82008-10-09 12:26:41 -07003053 dma_addr_t mapping_old;
3054
Michael Chan1db82f22007-12-12 11:19:35 -08003055 frag_len = min(frag_size, (unsigned int) PAGE_SIZE);
3056 if (unlikely(frag_len <= 4)) {
3057 unsigned int tail = 4 - frag_len;
3058
Michael Chanbb4f98a2008-06-19 16:38:19 -07003059 rxr->rx_pg_cons = pg_cons;
3060 rxr->rx_pg_prod = pg_prod;
3061 bnx2_reuse_rx_skb_pages(bp, rxr, NULL,
Michael Chana1f60192007-12-20 19:57:19 -08003062 pages - i);
Michael Chan1db82f22007-12-12 11:19:35 -08003063 skb->len -= tail;
3064 if (i == 0) {
3065 skb->tail -= tail;
3066 } else {
3067 skb_frag_t *frag =
3068 &skb_shinfo(skb)->frags[i - 1];
Eric Dumazet9e903e02011-10-18 21:00:24 +00003069 skb_frag_size_sub(frag, tail);
Michael Chan1db82f22007-12-12 11:19:35 -08003070 skb->data_len -= tail;
Michael Chan1db82f22007-12-12 11:19:35 -08003071 }
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00003072 return skb;
Michael Chan1db82f22007-12-12 11:19:35 -08003073 }
Michael Chanbb4f98a2008-06-19 16:38:19 -07003074 rx_pg = &rxr->rx_pg_ring[pg_cons];
Michael Chan1db82f22007-12-12 11:19:35 -08003075
Benjamin Li3d16af82008-10-09 12:26:41 -07003076 /* Don't unmap yet. If we're unable to allocate a new
3077 * page, we need to recycle the page and the DMA addr.
3078 */
FUJITA Tomonori1a4ccc22010-04-01 16:56:57 +00003079 mapping_old = dma_unmap_addr(rx_pg, mapping);
Michael Chan1db82f22007-12-12 11:19:35 -08003080 if (i == pages - 1)
3081 frag_len -= 4;
3082
3083 skb_fill_page_desc(skb, i, rx_pg->page, 0, frag_len);
3084 rx_pg->page = NULL;
3085
Michael Chanbb4f98a2008-06-19 16:38:19 -07003086 err = bnx2_alloc_rx_page(bp, rxr,
Michael Chan2bc40782012-12-06 10:33:09 +00003087 BNX2_RX_PG_RING_IDX(pg_prod),
Stanislaw Gruszkaa2df00a2010-07-15 22:55:40 +00003088 GFP_ATOMIC);
Michael Chan1db82f22007-12-12 11:19:35 -08003089 if (unlikely(err)) {
Michael Chanbb4f98a2008-06-19 16:38:19 -07003090 rxr->rx_pg_cons = pg_cons;
3091 rxr->rx_pg_prod = pg_prod;
3092 bnx2_reuse_rx_skb_pages(bp, rxr, skb,
Michael Chana1f60192007-12-20 19:57:19 -08003093 pages - i);
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00003094 return NULL;
Michael Chan1db82f22007-12-12 11:19:35 -08003095 }
3096
Stanislaw Gruszka36227e82010-07-15 04:25:50 +00003097 dma_unmap_page(&bp->pdev->dev, mapping_old,
Benjamin Li3d16af82008-10-09 12:26:41 -07003098 PAGE_SIZE, PCI_DMA_FROMDEVICE);
3099
Michael Chan1db82f22007-12-12 11:19:35 -08003100 frag_size -= frag_len;
3101 skb->data_len += frag_len;
Eric Dumazeta1f4e8b2011-10-13 07:50:19 +00003102 skb->truesize += PAGE_SIZE;
Michael Chan1db82f22007-12-12 11:19:35 -08003103 skb->len += frag_len;
3104
Michael Chan2bc40782012-12-06 10:33:09 +00003105 pg_prod = BNX2_NEXT_RX_BD(pg_prod);
3106 pg_cons = BNX2_RX_PG_RING_IDX(BNX2_NEXT_RX_BD(pg_cons));
Michael Chan1db82f22007-12-12 11:19:35 -08003107 }
Michael Chanbb4f98a2008-06-19 16:38:19 -07003108 rxr->rx_pg_prod = pg_prod;
3109 rxr->rx_pg_cons = pg_cons;
Michael Chan1db82f22007-12-12 11:19:35 -08003110 }
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00003111 return skb;
Michael Chan85833c62007-12-12 11:17:01 -08003112}
3113
Michael Chanc09c2622007-12-10 17:18:37 -08003114static inline u16
Michael Chan35efa7c2007-12-20 19:56:37 -08003115bnx2_get_hw_rx_cons(struct bnx2_napi *bnapi)
Michael Chanc09c2622007-12-10 17:18:37 -08003116{
Michael Chanbb4f98a2008-06-19 16:38:19 -07003117 u16 cons;
3118
Michael Chan43e80b82008-06-19 16:41:08 -07003119 /* Tell compiler that status block fields can change. */
3120 barrier();
3121 cons = *bnapi->hw_rx_cons_ptr;
Michael Chan581daf72009-05-06 16:46:47 -07003122 barrier();
Michael Chan2bc40782012-12-06 10:33:09 +00003123 if (unlikely((cons & BNX2_MAX_RX_DESC_CNT) == BNX2_MAX_RX_DESC_CNT))
Michael Chanc09c2622007-12-10 17:18:37 -08003124 cons++;
3125 return cons;
3126}
3127
Michael Chanb6016b72005-05-26 13:03:09 -07003128static int
Michael Chan35efa7c2007-12-20 19:56:37 -08003129bnx2_rx_int(struct bnx2 *bp, struct bnx2_napi *bnapi, int budget)
Michael Chanb6016b72005-05-26 13:03:09 -07003130{
Michael Chanbb4f98a2008-06-19 16:38:19 -07003131 struct bnx2_rx_ring_info *rxr = &bnapi->rx_ring;
Michael Chanb6016b72005-05-26 13:03:09 -07003132 u16 hw_cons, sw_cons, sw_ring_cons, sw_prod, sw_ring_prod;
3133 struct l2_fhdr *rx_hdr;
Michael Chan1db82f22007-12-12 11:19:35 -08003134 int rx_pkt = 0, pg_ring_used = 0;
Michael Chanb6016b72005-05-26 13:03:09 -07003135
Michael Chan35efa7c2007-12-20 19:56:37 -08003136 hw_cons = bnx2_get_hw_rx_cons(bnapi);
Michael Chanbb4f98a2008-06-19 16:38:19 -07003137 sw_cons = rxr->rx_cons;
3138 sw_prod = rxr->rx_prod;
Michael Chanb6016b72005-05-26 13:03:09 -07003139
3140 /* Memory barrier necessary as speculative reads of the rx
3141 * buffer can be ahead of the index in the status block
3142 */
3143 rmb();
3144 while (sw_cons != hw_cons) {
Michael Chan1db82f22007-12-12 11:19:35 -08003145 unsigned int len, hdr_len;
Michael Chanade2bfe2006-01-23 16:09:51 -08003146 u32 status;
Michael Chan2bc40782012-12-06 10:33:09 +00003147 struct bnx2_sw_bd *rx_buf, *next_rx_buf;
Michael Chanb6016b72005-05-26 13:03:09 -07003148 struct sk_buff *skb;
Michael Chan236b6392006-03-20 17:49:02 -08003149 dma_addr_t dma_addr;
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00003150 u8 *data;
Michael Chan2bc40782012-12-06 10:33:09 +00003151 u16 next_ring_idx;
Michael Chanb6016b72005-05-26 13:03:09 -07003152
Michael Chan2bc40782012-12-06 10:33:09 +00003153 sw_ring_cons = BNX2_RX_RING_IDX(sw_cons);
3154 sw_ring_prod = BNX2_RX_RING_IDX(sw_prod);
Michael Chanb6016b72005-05-26 13:03:09 -07003155
Michael Chanbb4f98a2008-06-19 16:38:19 -07003156 rx_buf = &rxr->rx_buf_ring[sw_ring_cons];
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00003157 data = rx_buf->data;
3158 rx_buf->data = NULL;
Michael Chan236b6392006-03-20 17:49:02 -08003159
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00003160 rx_hdr = get_l2_fhdr(data);
3161 prefetch(rx_hdr);
Michael Chan236b6392006-03-20 17:49:02 -08003162
FUJITA Tomonori1a4ccc22010-04-01 16:56:57 +00003163 dma_addr = dma_unmap_addr(rx_buf, mapping);
Michael Chan236b6392006-03-20 17:49:02 -08003164
Stanislaw Gruszka36227e82010-07-15 04:25:50 +00003165 dma_sync_single_for_cpu(&bp->pdev->dev, dma_addr,
Benjamin Li601d3d12008-05-16 22:19:35 -07003166 BNX2_RX_OFFSET + BNX2_RX_COPY_THRESH,
3167 PCI_DMA_FROMDEVICE);
Michael Chanb6016b72005-05-26 13:03:09 -07003168
Michael Chan2bc40782012-12-06 10:33:09 +00003169 next_ring_idx = BNX2_RX_RING_IDX(BNX2_NEXT_RX_BD(sw_cons));
3170 next_rx_buf = &rxr->rx_buf_ring[next_ring_idx];
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00003171 prefetch(get_l2_fhdr(next_rx_buf->data));
3172
Michael Chan1db82f22007-12-12 11:19:35 -08003173 len = rx_hdr->l2_fhdr_pkt_len;
Michael Chan990ec382009-02-12 16:54:13 -08003174 status = rx_hdr->l2_fhdr_status;
Michael Chanb6016b72005-05-26 13:03:09 -07003175
Michael Chan1db82f22007-12-12 11:19:35 -08003176 hdr_len = 0;
3177 if (status & L2_FHDR_STATUS_SPLIT) {
3178 hdr_len = rx_hdr->l2_fhdr_ip_xsum;
3179 pg_ring_used = 1;
3180 } else if (len > bp->rx_jumbo_thresh) {
3181 hdr_len = bp->rx_jumbo_thresh;
3182 pg_ring_used = 1;
3183 }
3184
Michael Chan990ec382009-02-12 16:54:13 -08003185 if (unlikely(status & (L2_FHDR_ERRORS_BAD_CRC |
3186 L2_FHDR_ERRORS_PHY_DECODE |
3187 L2_FHDR_ERRORS_ALIGNMENT |
3188 L2_FHDR_ERRORS_TOO_SHORT |
3189 L2_FHDR_ERRORS_GIANT_FRAME))) {
3190
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00003191 bnx2_reuse_rx_data(bp, rxr, data, sw_ring_cons,
Michael Chan990ec382009-02-12 16:54:13 -08003192 sw_ring_prod);
3193 if (pg_ring_used) {
3194 int pages;
3195
3196 pages = PAGE_ALIGN(len - hdr_len) >> PAGE_SHIFT;
3197
3198 bnx2_reuse_rx_skb_pages(bp, rxr, NULL, pages);
3199 }
3200 goto next_rx;
3201 }
3202
Michael Chan1db82f22007-12-12 11:19:35 -08003203 len -= 4;
Michael Chanb6016b72005-05-26 13:03:09 -07003204
Michael Chan5d5d0012007-12-12 11:17:43 -08003205 if (len <= bp->rx_copy_thresh) {
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00003206 skb = netdev_alloc_skb(bp->dev, len + 6);
3207 if (skb == NULL) {
3208 bnx2_reuse_rx_data(bp, rxr, data, sw_ring_cons,
Michael Chan85833c62007-12-12 11:17:01 -08003209 sw_ring_prod);
3210 goto next_rx;
3211 }
Michael Chanb6016b72005-05-26 13:03:09 -07003212
3213 /* aligned copy */
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00003214 memcpy(skb->data,
3215 (u8 *)rx_hdr + BNX2_RX_OFFSET - 6,
3216 len + 6);
3217 skb_reserve(skb, 6);
3218 skb_put(skb, len);
Michael Chanb6016b72005-05-26 13:03:09 -07003219
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00003220 bnx2_reuse_rx_data(bp, rxr, data,
Michael Chanb6016b72005-05-26 13:03:09 -07003221 sw_ring_cons, sw_ring_prod);
3222
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00003223 } else {
3224 skb = bnx2_rx_skb(bp, rxr, data, len, hdr_len, dma_addr,
3225 (sw_ring_cons << 16) | sw_ring_prod);
3226 if (!skb)
3227 goto next_rx;
3228 }
Michael Chanf22828e2008-08-14 15:30:14 -07003229 if ((status & L2_FHDR_STATUS_L2_VLAN_TAG) &&
Jesse Gross7d0fd212010-10-20 13:56:09 +00003230 !(bp->rx_mode & BNX2_EMAC_RX_MODE_KEEP_VLAN_TAG))
Patrick McHardy86a9bad2013-04-19 02:04:30 +00003231 __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), rx_hdr->l2_fhdr_vlan_tag);
Michael Chanf22828e2008-08-14 15:30:14 -07003232
Michael Chanb6016b72005-05-26 13:03:09 -07003233 skb->protocol = eth_type_trans(skb, bp->dev);
3234
3235 if ((len > (bp->dev->mtu + ETH_HLEN)) &&
Alexey Dobriyand1e100b2006-06-11 20:57:17 -07003236 (ntohs(skb->protocol) != 0x8100)) {
Michael Chanb6016b72005-05-26 13:03:09 -07003237
Michael Chan745720e2006-06-29 12:37:41 -07003238 dev_kfree_skb(skb);
Michael Chanb6016b72005-05-26 13:03:09 -07003239 goto next_rx;
3240
3241 }
3242
Eric Dumazetbc8acf22010-09-02 13:07:41 -07003243 skb_checksum_none_assert(skb);
Michał Mirosław8d7dfc22011-04-10 04:47:46 +00003244 if ((bp->dev->features & NETIF_F_RXCSUM) &&
Michael Chanb6016b72005-05-26 13:03:09 -07003245 (status & (L2_FHDR_STATUS_TCP_SEGMENT |
3246 L2_FHDR_STATUS_UDP_DATAGRAM))) {
3247
Michael Chanade2bfe2006-01-23 16:09:51 -08003248 if (likely((status & (L2_FHDR_ERRORS_TCP_XSUM |
3249 L2_FHDR_ERRORS_UDP_XSUM)) == 0))
Michael Chanb6016b72005-05-26 13:03:09 -07003250 skb->ip_summed = CHECKSUM_UNNECESSARY;
3251 }
Michael Chanfdc85412010-07-03 20:42:16 +00003252 if ((bp->dev->features & NETIF_F_RXHASH) &&
3253 ((status & L2_FHDR_STATUS_USE_RXHASH) ==
3254 L2_FHDR_STATUS_USE_RXHASH))
Tom Herbertcf1bfd62013-12-17 23:22:57 -08003255 skb_set_hash(skb, rx_hdr->l2_fhdr_hash,
3256 PKT_HASH_TYPE_L3);
Michael Chanb6016b72005-05-26 13:03:09 -07003257
David S. Miller0c8dfc82009-01-27 16:22:32 -08003258 skb_record_rx_queue(skb, bnapi - &bp->bnx2_napi[0]);
Jesse Gross7d0fd212010-10-20 13:56:09 +00003259 napi_gro_receive(&bnapi->napi, skb);
Michael Chanb6016b72005-05-26 13:03:09 -07003260 rx_pkt++;
3261
3262next_rx:
Michael Chan2bc40782012-12-06 10:33:09 +00003263 sw_cons = BNX2_NEXT_RX_BD(sw_cons);
3264 sw_prod = BNX2_NEXT_RX_BD(sw_prod);
Michael Chanb6016b72005-05-26 13:03:09 -07003265
3266 if ((rx_pkt == budget))
3267 break;
Michael Chanf4e418f2005-11-04 08:53:48 -08003268
3269 /* Refresh hw_cons to see if there is new work */
3270 if (sw_cons == hw_cons) {
Michael Chan35efa7c2007-12-20 19:56:37 -08003271 hw_cons = bnx2_get_hw_rx_cons(bnapi);
Michael Chanf4e418f2005-11-04 08:53:48 -08003272 rmb();
3273 }
Michael Chanb6016b72005-05-26 13:03:09 -07003274 }
Michael Chanbb4f98a2008-06-19 16:38:19 -07003275 rxr->rx_cons = sw_cons;
3276 rxr->rx_prod = sw_prod;
Michael Chanb6016b72005-05-26 13:03:09 -07003277
Michael Chan1db82f22007-12-12 11:19:35 -08003278 if (pg_ring_used)
Michael Chane503e062012-12-06 10:33:08 +00003279 BNX2_WR16(bp, rxr->rx_pg_bidx_addr, rxr->rx_pg_prod);
Michael Chan1db82f22007-12-12 11:19:35 -08003280
Michael Chane503e062012-12-06 10:33:08 +00003281 BNX2_WR16(bp, rxr->rx_bidx_addr, sw_prod);
Michael Chanb6016b72005-05-26 13:03:09 -07003282
Michael Chane503e062012-12-06 10:33:08 +00003283 BNX2_WR(bp, rxr->rx_bseq_addr, rxr->rx_prod_bseq);
Michael Chanb6016b72005-05-26 13:03:09 -07003284
3285 mmiowb();
3286
3287 return rx_pkt;
3288
3289}
3290
3291/* MSI ISR - The only difference between this and the INTx ISR
3292 * is that the MSI interrupt is always serviced.
3293 */
3294static irqreturn_t
David Howells7d12e782006-10-05 14:55:46 +01003295bnx2_msi(int irq, void *dev_instance)
Michael Chanb6016b72005-05-26 13:03:09 -07003296{
Michael Chanf0ea2e62008-06-19 16:41:57 -07003297 struct bnx2_napi *bnapi = dev_instance;
3298 struct bnx2 *bp = bnapi->bp;
Michael Chanb6016b72005-05-26 13:03:09 -07003299
Michael Chan43e80b82008-06-19 16:41:08 -07003300 prefetch(bnapi->status_blk.msi);
Michael Chane503e062012-12-06 10:33:08 +00003301 BNX2_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
Michael Chanb6016b72005-05-26 13:03:09 -07003302 BNX2_PCICFG_INT_ACK_CMD_USE_INT_HC_PARAM |
3303 BNX2_PCICFG_INT_ACK_CMD_MASK_INT);
3304
3305 /* Return here if interrupt is disabled. */
Michael Chan73eef4c2005-08-25 15:39:15 -07003306 if (unlikely(atomic_read(&bp->intr_sem) != 0))
3307 return IRQ_HANDLED;
Michael Chanb6016b72005-05-26 13:03:09 -07003308
Ben Hutchings288379f2009-01-19 16:43:59 -08003309 napi_schedule(&bnapi->napi);
Michael Chanb6016b72005-05-26 13:03:09 -07003310
Michael Chan73eef4c2005-08-25 15:39:15 -07003311 return IRQ_HANDLED;
Michael Chanb6016b72005-05-26 13:03:09 -07003312}
3313
3314static irqreturn_t
Michael Chan8e6a72c2007-05-03 13:24:48 -07003315bnx2_msi_1shot(int irq, void *dev_instance)
3316{
Michael Chanf0ea2e62008-06-19 16:41:57 -07003317 struct bnx2_napi *bnapi = dev_instance;
3318 struct bnx2 *bp = bnapi->bp;
Michael Chan8e6a72c2007-05-03 13:24:48 -07003319
Michael Chan43e80b82008-06-19 16:41:08 -07003320 prefetch(bnapi->status_blk.msi);
Michael Chan8e6a72c2007-05-03 13:24:48 -07003321
3322 /* Return here if interrupt is disabled. */
3323 if (unlikely(atomic_read(&bp->intr_sem) != 0))
3324 return IRQ_HANDLED;
3325
Ben Hutchings288379f2009-01-19 16:43:59 -08003326 napi_schedule(&bnapi->napi);
Michael Chan8e6a72c2007-05-03 13:24:48 -07003327
3328 return IRQ_HANDLED;
3329}
3330
3331static irqreturn_t
David Howells7d12e782006-10-05 14:55:46 +01003332bnx2_interrupt(int irq, void *dev_instance)
Michael Chanb6016b72005-05-26 13:03:09 -07003333{
Michael Chanf0ea2e62008-06-19 16:41:57 -07003334 struct bnx2_napi *bnapi = dev_instance;
3335 struct bnx2 *bp = bnapi->bp;
Michael Chan43e80b82008-06-19 16:41:08 -07003336 struct status_block *sblk = bnapi->status_blk.msi;
Michael Chanb6016b72005-05-26 13:03:09 -07003337
3338 /* When using INTx, it is possible for the interrupt to arrive
3339 * at the CPU before the status block posted prior to the
3340 * interrupt. Reading a register will flush the status block.
3341 * When using MSI, the MSI message will always complete after
3342 * the status block write.
3343 */
Michael Chan35efa7c2007-12-20 19:56:37 -08003344 if ((sblk->status_idx == bnapi->last_status_idx) &&
Michael Chane503e062012-12-06 10:33:08 +00003345 (BNX2_RD(bp, BNX2_PCICFG_MISC_STATUS) &
Michael Chanb6016b72005-05-26 13:03:09 -07003346 BNX2_PCICFG_MISC_STATUS_INTA_VALUE))
Michael Chan73eef4c2005-08-25 15:39:15 -07003347 return IRQ_NONE;
Michael Chanb6016b72005-05-26 13:03:09 -07003348
Michael Chane503e062012-12-06 10:33:08 +00003349 BNX2_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
Michael Chanb6016b72005-05-26 13:03:09 -07003350 BNX2_PCICFG_INT_ACK_CMD_USE_INT_HC_PARAM |
3351 BNX2_PCICFG_INT_ACK_CMD_MASK_INT);
3352
Michael Chanb8a7ce72007-07-07 22:51:03 -07003353 /* Read back to deassert IRQ immediately to avoid too many
3354 * spurious interrupts.
3355 */
Michael Chane503e062012-12-06 10:33:08 +00003356 BNX2_RD(bp, BNX2_PCICFG_INT_ACK_CMD);
Michael Chanb8a7ce72007-07-07 22:51:03 -07003357
Michael Chanb6016b72005-05-26 13:03:09 -07003358 /* Return here if interrupt is shared and is disabled. */
Michael Chan73eef4c2005-08-25 15:39:15 -07003359 if (unlikely(atomic_read(&bp->intr_sem) != 0))
3360 return IRQ_HANDLED;
Michael Chanb6016b72005-05-26 13:03:09 -07003361
Ben Hutchings288379f2009-01-19 16:43:59 -08003362 if (napi_schedule_prep(&bnapi->napi)) {
Michael Chan35efa7c2007-12-20 19:56:37 -08003363 bnapi->last_status_idx = sblk->status_idx;
Ben Hutchings288379f2009-01-19 16:43:59 -08003364 __napi_schedule(&bnapi->napi);
Michael Chanb8a7ce72007-07-07 22:51:03 -07003365 }
Michael Chanb6016b72005-05-26 13:03:09 -07003366
Michael Chan73eef4c2005-08-25 15:39:15 -07003367 return IRQ_HANDLED;
Michael Chanb6016b72005-05-26 13:03:09 -07003368}
3369
Michael Chan43e80b82008-06-19 16:41:08 -07003370static inline int
3371bnx2_has_fast_work(struct bnx2_napi *bnapi)
3372{
3373 struct bnx2_tx_ring_info *txr = &bnapi->tx_ring;
3374 struct bnx2_rx_ring_info *rxr = &bnapi->rx_ring;
3375
3376 if ((bnx2_get_hw_rx_cons(bnapi) != rxr->rx_cons) ||
3377 (bnx2_get_hw_tx_cons(bnapi) != txr->hw_tx_cons))
3378 return 1;
3379 return 0;
3380}
3381
Michael Chan0d8a6572007-07-07 22:49:43 -07003382#define STATUS_ATTN_EVENTS (STATUS_ATTN_BITS_LINK_STATE | \
3383 STATUS_ATTN_BITS_TIMER_ABORT)
Michael Chanda3e4fb2007-05-03 13:24:23 -07003384
Michael Chanf4e418f2005-11-04 08:53:48 -08003385static inline int
Michael Chan35efa7c2007-12-20 19:56:37 -08003386bnx2_has_work(struct bnx2_napi *bnapi)
Michael Chanf4e418f2005-11-04 08:53:48 -08003387{
Michael Chan43e80b82008-06-19 16:41:08 -07003388 struct status_block *sblk = bnapi->status_blk.msi;
Michael Chanf4e418f2005-11-04 08:53:48 -08003389
Michael Chan43e80b82008-06-19 16:41:08 -07003390 if (bnx2_has_fast_work(bnapi))
Michael Chanf4e418f2005-11-04 08:53:48 -08003391 return 1;
3392
Michael Chan4edd4732009-06-08 18:14:42 -07003393#ifdef BCM_CNIC
3394 if (bnapi->cnic_present && (bnapi->cnic_tag != sblk->status_idx))
3395 return 1;
3396#endif
3397
Michael Chanda3e4fb2007-05-03 13:24:23 -07003398 if ((sblk->status_attn_bits & STATUS_ATTN_EVENTS) !=
3399 (sblk->status_attn_bits_ack & STATUS_ATTN_EVENTS))
Michael Chanf4e418f2005-11-04 08:53:48 -08003400 return 1;
3401
3402 return 0;
3403}
3404
Michael Chanefba0182008-12-03 00:36:15 -08003405static void
3406bnx2_chk_missed_msi(struct bnx2 *bp)
3407{
3408 struct bnx2_napi *bnapi = &bp->bnx2_napi[0];
3409 u32 msi_ctrl;
3410
3411 if (bnx2_has_work(bnapi)) {
Michael Chane503e062012-12-06 10:33:08 +00003412 msi_ctrl = BNX2_RD(bp, BNX2_PCICFG_MSI_CONTROL);
Michael Chanefba0182008-12-03 00:36:15 -08003413 if (!(msi_ctrl & BNX2_PCICFG_MSI_CONTROL_ENABLE))
3414 return;
3415
3416 if (bnapi->last_status_idx == bp->idle_chk_status_idx) {
Michael Chane503e062012-12-06 10:33:08 +00003417 BNX2_WR(bp, BNX2_PCICFG_MSI_CONTROL, msi_ctrl &
3418 ~BNX2_PCICFG_MSI_CONTROL_ENABLE);
3419 BNX2_WR(bp, BNX2_PCICFG_MSI_CONTROL, msi_ctrl);
Michael Chanefba0182008-12-03 00:36:15 -08003420 bnx2_msi(bp->irq_tbl[0].vector, bnapi);
3421 }
3422 }
3423
3424 bp->idle_chk_status_idx = bnapi->last_status_idx;
3425}
3426
Michael Chan4edd4732009-06-08 18:14:42 -07003427#ifdef BCM_CNIC
3428static void bnx2_poll_cnic(struct bnx2 *bp, struct bnx2_napi *bnapi)
3429{
3430 struct cnic_ops *c_ops;
3431
3432 if (!bnapi->cnic_present)
3433 return;
3434
3435 rcu_read_lock();
3436 c_ops = rcu_dereference(bp->cnic_ops);
3437 if (c_ops)
3438 bnapi->cnic_tag = c_ops->cnic_handler(bp->cnic_data,
3439 bnapi->status_blk.msi);
3440 rcu_read_unlock();
3441}
3442#endif
3443
Michael Chan43e80b82008-06-19 16:41:08 -07003444static void bnx2_poll_link(struct bnx2 *bp, struct bnx2_napi *bnapi)
Michael Chanb6016b72005-05-26 13:03:09 -07003445{
Michael Chan43e80b82008-06-19 16:41:08 -07003446 struct status_block *sblk = bnapi->status_blk.msi;
Michael Chanda3e4fb2007-05-03 13:24:23 -07003447 u32 status_attn_bits = sblk->status_attn_bits;
3448 u32 status_attn_bits_ack = sblk->status_attn_bits_ack;
Michael Chanb6016b72005-05-26 13:03:09 -07003449
Michael Chanda3e4fb2007-05-03 13:24:23 -07003450 if ((status_attn_bits & STATUS_ATTN_EVENTS) !=
3451 (status_attn_bits_ack & STATUS_ATTN_EVENTS)) {
Michael Chanb6016b72005-05-26 13:03:09 -07003452
Michael Chan35efa7c2007-12-20 19:56:37 -08003453 bnx2_phy_int(bp, bnapi);
Michael Chanbf5295b2006-03-23 01:11:56 -08003454
3455 /* This is needed to take care of transient status
3456 * during link changes.
3457 */
Michael Chane503e062012-12-06 10:33:08 +00003458 BNX2_WR(bp, BNX2_HC_COMMAND,
3459 bp->hc_cmd | BNX2_HC_COMMAND_COAL_NOW_WO_INT);
3460 BNX2_RD(bp, BNX2_HC_COMMAND);
Michael Chanb6016b72005-05-26 13:03:09 -07003461 }
Michael Chan43e80b82008-06-19 16:41:08 -07003462}
3463
3464static int bnx2_poll_work(struct bnx2 *bp, struct bnx2_napi *bnapi,
3465 int work_done, int budget)
3466{
3467 struct bnx2_tx_ring_info *txr = &bnapi->tx_ring;
3468 struct bnx2_rx_ring_info *rxr = &bnapi->rx_ring;
Michael Chanb6016b72005-05-26 13:03:09 -07003469
Michael Chan35e90102008-06-19 16:37:42 -07003470 if (bnx2_get_hw_tx_cons(bnapi) != txr->hw_tx_cons)
Michael Chan57851d82007-12-20 20:01:44 -08003471 bnx2_tx_int(bp, bnapi, 0);
Michael Chanb6016b72005-05-26 13:03:09 -07003472
Michael Chanbb4f98a2008-06-19 16:38:19 -07003473 if (bnx2_get_hw_rx_cons(bnapi) != rxr->rx_cons)
Michael Chan35efa7c2007-12-20 19:56:37 -08003474 work_done += bnx2_rx_int(bp, bnapi, budget - work_done);
Jeff Garzik6aa20a22006-09-13 13:24:59 -04003475
David S. Miller6f535762007-10-11 18:08:29 -07003476 return work_done;
3477}
Michael Chanf4e418f2005-11-04 08:53:48 -08003478
Michael Chanf0ea2e62008-06-19 16:41:57 -07003479static int bnx2_poll_msix(struct napi_struct *napi, int budget)
3480{
3481 struct bnx2_napi *bnapi = container_of(napi, struct bnx2_napi, napi);
3482 struct bnx2 *bp = bnapi->bp;
3483 int work_done = 0;
3484 struct status_block_msix *sblk = bnapi->status_blk.msix;
3485
3486 while (1) {
3487 work_done = bnx2_poll_work(bp, bnapi, work_done, budget);
3488 if (unlikely(work_done >= budget))
3489 break;
3490
3491 bnapi->last_status_idx = sblk->status_idx;
3492 /* status idx must be read before checking for more work. */
3493 rmb();
3494 if (likely(!bnx2_has_fast_work(bnapi))) {
3495
Ben Hutchings288379f2009-01-19 16:43:59 -08003496 napi_complete(napi);
Michael Chane503e062012-12-06 10:33:08 +00003497 BNX2_WR(bp, BNX2_PCICFG_INT_ACK_CMD, bnapi->int_num |
3498 BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
3499 bnapi->last_status_idx);
Michael Chanf0ea2e62008-06-19 16:41:57 -07003500 break;
3501 }
3502 }
3503 return work_done;
3504}
3505
David S. Miller6f535762007-10-11 18:08:29 -07003506static int bnx2_poll(struct napi_struct *napi, int budget)
3507{
Michael Chan35efa7c2007-12-20 19:56:37 -08003508 struct bnx2_napi *bnapi = container_of(napi, struct bnx2_napi, napi);
3509 struct bnx2 *bp = bnapi->bp;
David S. Miller6f535762007-10-11 18:08:29 -07003510 int work_done = 0;
Michael Chan43e80b82008-06-19 16:41:08 -07003511 struct status_block *sblk = bnapi->status_blk.msi;
David S. Miller6f535762007-10-11 18:08:29 -07003512
3513 while (1) {
Michael Chan43e80b82008-06-19 16:41:08 -07003514 bnx2_poll_link(bp, bnapi);
3515
Michael Chan35efa7c2007-12-20 19:56:37 -08003516 work_done = bnx2_poll_work(bp, bnapi, work_done, budget);
David S. Miller6f535762007-10-11 18:08:29 -07003517
Michael Chan4edd4732009-06-08 18:14:42 -07003518#ifdef BCM_CNIC
3519 bnx2_poll_cnic(bp, bnapi);
3520#endif
3521
Michael Chan35efa7c2007-12-20 19:56:37 -08003522 /* bnapi->last_status_idx is used below to tell the hw how
Michael Chan6dee6422007-10-12 01:40:38 -07003523 * much work has been processed, so we must read it before
3524 * checking for more work.
3525 */
Michael Chan35efa7c2007-12-20 19:56:37 -08003526 bnapi->last_status_idx = sblk->status_idx;
Michael Chanefba0182008-12-03 00:36:15 -08003527
3528 if (unlikely(work_done >= budget))
3529 break;
3530
Michael Chan6dee6422007-10-12 01:40:38 -07003531 rmb();
Michael Chan35efa7c2007-12-20 19:56:37 -08003532 if (likely(!bnx2_has_work(bnapi))) {
Ben Hutchings288379f2009-01-19 16:43:59 -08003533 napi_complete(napi);
David S. Millerf86e82f2008-01-21 17:15:40 -08003534 if (likely(bp->flags & BNX2_FLAG_USING_MSI_OR_MSIX)) {
Michael Chane503e062012-12-06 10:33:08 +00003535 BNX2_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
3536 BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
3537 bnapi->last_status_idx);
Michael Chan6dee6422007-10-12 01:40:38 -07003538 break;
David S. Miller6f535762007-10-11 18:08:29 -07003539 }
Michael Chane503e062012-12-06 10:33:08 +00003540 BNX2_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
3541 BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
3542 BNX2_PCICFG_INT_ACK_CMD_MASK_INT |
3543 bnapi->last_status_idx);
David S. Miller6f535762007-10-11 18:08:29 -07003544
Michael Chane503e062012-12-06 10:33:08 +00003545 BNX2_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
3546 BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
3547 bnapi->last_status_idx);
David S. Miller6f535762007-10-11 18:08:29 -07003548 break;
Michael Chan1269a8a2006-01-23 16:11:03 -08003549 }
Michael Chanb6016b72005-05-26 13:03:09 -07003550 }
3551
Stephen Hemmingerbea33482007-10-03 16:41:36 -07003552 return work_done;
Michael Chanb6016b72005-05-26 13:03:09 -07003553}
3554
Herbert Xu932ff272006-06-09 12:20:56 -07003555/* Called with rtnl_lock from vlan functions and also netif_tx_lock
Michael Chanb6016b72005-05-26 13:03:09 -07003556 * from set_multicast.
3557 */
3558static void
3559bnx2_set_rx_mode(struct net_device *dev)
3560{
Michael Chan972ec0d2006-01-23 16:12:43 -08003561 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07003562 u32 rx_mode, sort_mode;
Jiri Pirkoccffad252009-05-22 23:22:17 +00003563 struct netdev_hw_addr *ha;
Michael Chanb6016b72005-05-26 13:03:09 -07003564 int i;
Michael Chanb6016b72005-05-26 13:03:09 -07003565
Michael Chan9f52b562008-10-09 12:21:46 -07003566 if (!netif_running(dev))
3567 return;
3568
Michael Chanc770a652005-08-25 15:38:39 -07003569 spin_lock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07003570
3571 rx_mode = bp->rx_mode & ~(BNX2_EMAC_RX_MODE_PROMISCUOUS |
3572 BNX2_EMAC_RX_MODE_KEEP_VLAN_TAG);
3573 sort_mode = 1 | BNX2_RPM_SORT_USER0_BC_EN;
Patrick McHardyf6469682013-04-19 02:04:27 +00003574 if (!(dev->features & NETIF_F_HW_VLAN_CTAG_RX) &&
Jesse Gross7d0fd212010-10-20 13:56:09 +00003575 (bp->flags & BNX2_FLAG_CAN_KEEP_VLAN))
Michael Chanb6016b72005-05-26 13:03:09 -07003576 rx_mode |= BNX2_EMAC_RX_MODE_KEEP_VLAN_TAG;
Michael Chanb6016b72005-05-26 13:03:09 -07003577 if (dev->flags & IFF_PROMISC) {
3578 /* Promiscuous mode. */
3579 rx_mode |= BNX2_EMAC_RX_MODE_PROMISCUOUS;
Michael Chan75108732006-11-19 14:06:40 -08003580 sort_mode |= BNX2_RPM_SORT_USER0_PROM_EN |
3581 BNX2_RPM_SORT_USER0_PROM_VLAN;
Michael Chanb6016b72005-05-26 13:03:09 -07003582 }
3583 else if (dev->flags & IFF_ALLMULTI) {
3584 for (i = 0; i < NUM_MC_HASH_REGISTERS; i++) {
Michael Chane503e062012-12-06 10:33:08 +00003585 BNX2_WR(bp, BNX2_EMAC_MULTICAST_HASH0 + (i * 4),
3586 0xffffffff);
Michael Chanb6016b72005-05-26 13:03:09 -07003587 }
3588 sort_mode |= BNX2_RPM_SORT_USER0_MC_EN;
3589 }
3590 else {
3591 /* Accept one or more multicast(s). */
Michael Chanb6016b72005-05-26 13:03:09 -07003592 u32 mc_filter[NUM_MC_HASH_REGISTERS];
3593 u32 regidx;
3594 u32 bit;
3595 u32 crc;
3596
3597 memset(mc_filter, 0, 4 * NUM_MC_HASH_REGISTERS);
3598
Jiri Pirko22bedad32010-04-01 21:22:57 +00003599 netdev_for_each_mc_addr(ha, dev) {
3600 crc = ether_crc_le(ETH_ALEN, ha->addr);
Michael Chanb6016b72005-05-26 13:03:09 -07003601 bit = crc & 0xff;
3602 regidx = (bit & 0xe0) >> 5;
3603 bit &= 0x1f;
3604 mc_filter[regidx] |= (1 << bit);
3605 }
3606
3607 for (i = 0; i < NUM_MC_HASH_REGISTERS; i++) {
Michael Chane503e062012-12-06 10:33:08 +00003608 BNX2_WR(bp, BNX2_EMAC_MULTICAST_HASH0 + (i * 4),
3609 mc_filter[i]);
Michael Chanb6016b72005-05-26 13:03:09 -07003610 }
3611
3612 sort_mode |= BNX2_RPM_SORT_USER0_MC_HSH_EN;
3613 }
3614
Jiri Pirko32e7bfc2010-01-25 13:36:10 -08003615 if (netdev_uc_count(dev) > BNX2_MAX_UNICAST_ADDRESSES) {
Benjamin Li5fcaed02008-07-14 22:39:52 -07003616 rx_mode |= BNX2_EMAC_RX_MODE_PROMISCUOUS;
3617 sort_mode |= BNX2_RPM_SORT_USER0_PROM_EN |
3618 BNX2_RPM_SORT_USER0_PROM_VLAN;
3619 } else if (!(dev->flags & IFF_PROMISC)) {
Benjamin Li5fcaed02008-07-14 22:39:52 -07003620 /* Add all entries into to the match filter list */
Jiri Pirkoccffad252009-05-22 23:22:17 +00003621 i = 0;
Jiri Pirko32e7bfc2010-01-25 13:36:10 -08003622 netdev_for_each_uc_addr(ha, dev) {
Jiri Pirkoccffad252009-05-22 23:22:17 +00003623 bnx2_set_mac_addr(bp, ha->addr,
Benjamin Li5fcaed02008-07-14 22:39:52 -07003624 i + BNX2_START_UNICAST_ADDRESS_INDEX);
3625 sort_mode |= (1 <<
3626 (i + BNX2_START_UNICAST_ADDRESS_INDEX));
Jiri Pirkoccffad252009-05-22 23:22:17 +00003627 i++;
Benjamin Li5fcaed02008-07-14 22:39:52 -07003628 }
3629
3630 }
3631
Michael Chanb6016b72005-05-26 13:03:09 -07003632 if (rx_mode != bp->rx_mode) {
3633 bp->rx_mode = rx_mode;
Michael Chane503e062012-12-06 10:33:08 +00003634 BNX2_WR(bp, BNX2_EMAC_RX_MODE, rx_mode);
Michael Chanb6016b72005-05-26 13:03:09 -07003635 }
3636
Michael Chane503e062012-12-06 10:33:08 +00003637 BNX2_WR(bp, BNX2_RPM_SORT_USER0, 0x0);
3638 BNX2_WR(bp, BNX2_RPM_SORT_USER0, sort_mode);
3639 BNX2_WR(bp, BNX2_RPM_SORT_USER0, sort_mode | BNX2_RPM_SORT_USER0_ENA);
Michael Chanb6016b72005-05-26 13:03:09 -07003640
Michael Chanc770a652005-08-25 15:38:39 -07003641 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07003642}
3643
françois romieu7880b722011-09-30 00:36:52 +00003644static int
Michael Chan57579f72009-04-04 16:51:14 -07003645check_fw_section(const struct firmware *fw,
3646 const struct bnx2_fw_file_section *section,
3647 u32 alignment, bool non_empty)
Michael Chanb6016b72005-05-26 13:03:09 -07003648{
Michael Chan57579f72009-04-04 16:51:14 -07003649 u32 offset = be32_to_cpu(section->offset);
3650 u32 len = be32_to_cpu(section->len);
Michael Chanb6016b72005-05-26 13:03:09 -07003651
Michael Chan57579f72009-04-04 16:51:14 -07003652 if ((offset == 0 && len != 0) || offset >= fw->size || offset & 3)
3653 return -EINVAL;
3654 if ((non_empty && len == 0) || len > fw->size - offset ||
3655 len & (alignment - 1))
3656 return -EINVAL;
3657 return 0;
3658}
3659
françois romieu7880b722011-09-30 00:36:52 +00003660static int
Michael Chan57579f72009-04-04 16:51:14 -07003661check_mips_fw_entry(const struct firmware *fw,
3662 const struct bnx2_mips_fw_file_entry *entry)
3663{
3664 if (check_fw_section(fw, &entry->text, 4, true) ||
3665 check_fw_section(fw, &entry->data, 4, false) ||
3666 check_fw_section(fw, &entry->rodata, 4, false))
3667 return -EINVAL;
3668 return 0;
3669}
3670
françois romieu7880b722011-09-30 00:36:52 +00003671static void bnx2_release_firmware(struct bnx2 *bp)
3672{
3673 if (bp->rv2p_firmware) {
3674 release_firmware(bp->mips_firmware);
3675 release_firmware(bp->rv2p_firmware);
3676 bp->rv2p_firmware = NULL;
3677 }
3678}
3679
3680static int bnx2_request_uncached_firmware(struct bnx2 *bp)
Michael Chan57579f72009-04-04 16:51:14 -07003681{
3682 const char *mips_fw_file, *rv2p_fw_file;
Bastian Blank5ee1c322009-04-08 15:50:07 -07003683 const struct bnx2_mips_fw_file *mips_fw;
3684 const struct bnx2_rv2p_fw_file *rv2p_fw;
Michael Chan57579f72009-04-04 16:51:14 -07003685 int rc;
3686
Michael Chan4ce45e02012-12-06 10:33:10 +00003687 if (BNX2_CHIP(bp) == BNX2_CHIP_5709) {
Michael Chan57579f72009-04-04 16:51:14 -07003688 mips_fw_file = FW_MIPS_FILE_09;
Michael Chan4ce45e02012-12-06 10:33:10 +00003689 if ((BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5709_A0) ||
3690 (BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5709_A1))
Michael Chan078b0732009-08-29 00:02:46 -07003691 rv2p_fw_file = FW_RV2P_FILE_09_Ax;
3692 else
3693 rv2p_fw_file = FW_RV2P_FILE_09;
Michael Chan57579f72009-04-04 16:51:14 -07003694 } else {
3695 mips_fw_file = FW_MIPS_FILE_06;
3696 rv2p_fw_file = FW_RV2P_FILE_06;
3697 }
3698
3699 rc = request_firmware(&bp->mips_firmware, mips_fw_file, &bp->pdev->dev);
3700 if (rc) {
Joe Perches3a9c6a42010-02-17 15:01:51 +00003701 pr_err("Can't load firmware file \"%s\"\n", mips_fw_file);
françois romieu7880b722011-09-30 00:36:52 +00003702 goto out;
Michael Chan57579f72009-04-04 16:51:14 -07003703 }
3704
3705 rc = request_firmware(&bp->rv2p_firmware, rv2p_fw_file, &bp->pdev->dev);
3706 if (rc) {
Joe Perches3a9c6a42010-02-17 15:01:51 +00003707 pr_err("Can't load firmware file \"%s\"\n", rv2p_fw_file);
françois romieu7880b722011-09-30 00:36:52 +00003708 goto err_release_mips_firmware;
Michael Chan57579f72009-04-04 16:51:14 -07003709 }
Bastian Blank5ee1c322009-04-08 15:50:07 -07003710 mips_fw = (const struct bnx2_mips_fw_file *) bp->mips_firmware->data;
3711 rv2p_fw = (const struct bnx2_rv2p_fw_file *) bp->rv2p_firmware->data;
3712 if (bp->mips_firmware->size < sizeof(*mips_fw) ||
3713 check_mips_fw_entry(bp->mips_firmware, &mips_fw->com) ||
3714 check_mips_fw_entry(bp->mips_firmware, &mips_fw->cp) ||
3715 check_mips_fw_entry(bp->mips_firmware, &mips_fw->rxp) ||
3716 check_mips_fw_entry(bp->mips_firmware, &mips_fw->tpat) ||
3717 check_mips_fw_entry(bp->mips_firmware, &mips_fw->txp)) {
Joe Perches3a9c6a42010-02-17 15:01:51 +00003718 pr_err("Firmware file \"%s\" is invalid\n", mips_fw_file);
françois romieu7880b722011-09-30 00:36:52 +00003719 rc = -EINVAL;
3720 goto err_release_firmware;
Michael Chan57579f72009-04-04 16:51:14 -07003721 }
Bastian Blank5ee1c322009-04-08 15:50:07 -07003722 if (bp->rv2p_firmware->size < sizeof(*rv2p_fw) ||
3723 check_fw_section(bp->rv2p_firmware, &rv2p_fw->proc1.rv2p, 8, true) ||
3724 check_fw_section(bp->rv2p_firmware, &rv2p_fw->proc2.rv2p, 8, true)) {
Joe Perches3a9c6a42010-02-17 15:01:51 +00003725 pr_err("Firmware file \"%s\" is invalid\n", rv2p_fw_file);
françois romieu7880b722011-09-30 00:36:52 +00003726 rc = -EINVAL;
3727 goto err_release_firmware;
Michael Chan57579f72009-04-04 16:51:14 -07003728 }
françois romieu7880b722011-09-30 00:36:52 +00003729out:
3730 return rc;
Michael Chan57579f72009-04-04 16:51:14 -07003731
françois romieu7880b722011-09-30 00:36:52 +00003732err_release_firmware:
3733 release_firmware(bp->rv2p_firmware);
3734 bp->rv2p_firmware = NULL;
3735err_release_mips_firmware:
3736 release_firmware(bp->mips_firmware);
3737 goto out;
3738}
3739
3740static int bnx2_request_firmware(struct bnx2 *bp)
3741{
3742 return bp->rv2p_firmware ? 0 : bnx2_request_uncached_firmware(bp);
Michael Chan57579f72009-04-04 16:51:14 -07003743}
3744
3745static u32
3746rv2p_fw_fixup(u32 rv2p_proc, int idx, u32 loc, u32 rv2p_code)
3747{
3748 switch (idx) {
3749 case RV2P_P1_FIXUP_PAGE_SIZE_IDX:
3750 rv2p_code &= ~RV2P_BD_PAGE_SIZE_MSK;
3751 rv2p_code |= RV2P_BD_PAGE_SIZE;
3752 break;
3753 }
3754 return rv2p_code;
3755}
3756
3757static int
3758load_rv2p_fw(struct bnx2 *bp, u32 rv2p_proc,
3759 const struct bnx2_rv2p_fw_file_entry *fw_entry)
3760{
3761 u32 rv2p_code_len, file_offset;
3762 __be32 *rv2p_code;
3763 int i;
3764 u32 val, cmd, addr;
3765
3766 rv2p_code_len = be32_to_cpu(fw_entry->rv2p.len);
3767 file_offset = be32_to_cpu(fw_entry->rv2p.offset);
3768
3769 rv2p_code = (__be32 *)(bp->rv2p_firmware->data + file_offset);
3770
3771 if (rv2p_proc == RV2P_PROC1) {
3772 cmd = BNX2_RV2P_PROC1_ADDR_CMD_RDWR;
3773 addr = BNX2_RV2P_PROC1_ADDR_CMD;
3774 } else {
3775 cmd = BNX2_RV2P_PROC2_ADDR_CMD_RDWR;
3776 addr = BNX2_RV2P_PROC2_ADDR_CMD;
Michael Chand25be1d2008-05-02 16:57:59 -07003777 }
Michael Chanb6016b72005-05-26 13:03:09 -07003778
3779 for (i = 0; i < rv2p_code_len; i += 8) {
Michael Chane503e062012-12-06 10:33:08 +00003780 BNX2_WR(bp, BNX2_RV2P_INSTR_HIGH, be32_to_cpu(*rv2p_code));
Michael Chanb6016b72005-05-26 13:03:09 -07003781 rv2p_code++;
Michael Chane503e062012-12-06 10:33:08 +00003782 BNX2_WR(bp, BNX2_RV2P_INSTR_LOW, be32_to_cpu(*rv2p_code));
Michael Chanb6016b72005-05-26 13:03:09 -07003783 rv2p_code++;
3784
Michael Chan57579f72009-04-04 16:51:14 -07003785 val = (i / 8) | cmd;
Michael Chane503e062012-12-06 10:33:08 +00003786 BNX2_WR(bp, addr, val);
Michael Chan57579f72009-04-04 16:51:14 -07003787 }
3788
3789 rv2p_code = (__be32 *)(bp->rv2p_firmware->data + file_offset);
3790 for (i = 0; i < 8; i++) {
3791 u32 loc, code;
3792
3793 loc = be32_to_cpu(fw_entry->fixup[i]);
3794 if (loc && ((loc * 4) < rv2p_code_len)) {
3795 code = be32_to_cpu(*(rv2p_code + loc - 1));
Michael Chane503e062012-12-06 10:33:08 +00003796 BNX2_WR(bp, BNX2_RV2P_INSTR_HIGH, code);
Michael Chan57579f72009-04-04 16:51:14 -07003797 code = be32_to_cpu(*(rv2p_code + loc));
3798 code = rv2p_fw_fixup(rv2p_proc, i, loc, code);
Michael Chane503e062012-12-06 10:33:08 +00003799 BNX2_WR(bp, BNX2_RV2P_INSTR_LOW, code);
Michael Chan57579f72009-04-04 16:51:14 -07003800
3801 val = (loc / 2) | cmd;
Michael Chane503e062012-12-06 10:33:08 +00003802 BNX2_WR(bp, addr, val);
Michael Chanb6016b72005-05-26 13:03:09 -07003803 }
3804 }
3805
3806 /* Reset the processor, un-stall is done later. */
3807 if (rv2p_proc == RV2P_PROC1) {
Michael Chane503e062012-12-06 10:33:08 +00003808 BNX2_WR(bp, BNX2_RV2P_COMMAND, BNX2_RV2P_COMMAND_PROC1_RESET);
Michael Chanb6016b72005-05-26 13:03:09 -07003809 }
3810 else {
Michael Chane503e062012-12-06 10:33:08 +00003811 BNX2_WR(bp, BNX2_RV2P_COMMAND, BNX2_RV2P_COMMAND_PROC2_RESET);
Michael Chanb6016b72005-05-26 13:03:09 -07003812 }
Michael Chan57579f72009-04-04 16:51:14 -07003813
3814 return 0;
Michael Chanb6016b72005-05-26 13:03:09 -07003815}
3816
Michael Chanaf3ee512006-11-19 14:09:25 -08003817static int
Michael Chan57579f72009-04-04 16:51:14 -07003818load_cpu_fw(struct bnx2 *bp, const struct cpu_reg *cpu_reg,
3819 const struct bnx2_mips_fw_file_entry *fw_entry)
Michael Chanb6016b72005-05-26 13:03:09 -07003820{
Michael Chan57579f72009-04-04 16:51:14 -07003821 u32 addr, len, file_offset;
3822 __be32 *data;
Michael Chanb6016b72005-05-26 13:03:09 -07003823 u32 offset;
3824 u32 val;
3825
3826 /* Halt the CPU. */
Michael Chan2726d6e2008-01-29 21:35:05 -08003827 val = bnx2_reg_rd_ind(bp, cpu_reg->mode);
Michael Chanb6016b72005-05-26 13:03:09 -07003828 val |= cpu_reg->mode_value_halt;
Michael Chan2726d6e2008-01-29 21:35:05 -08003829 bnx2_reg_wr_ind(bp, cpu_reg->mode, val);
3830 bnx2_reg_wr_ind(bp, cpu_reg->state, cpu_reg->state_value_clear);
Michael Chanb6016b72005-05-26 13:03:09 -07003831
3832 /* Load the Text area. */
Michael Chan57579f72009-04-04 16:51:14 -07003833 addr = be32_to_cpu(fw_entry->text.addr);
3834 len = be32_to_cpu(fw_entry->text.len);
3835 file_offset = be32_to_cpu(fw_entry->text.offset);
3836 data = (__be32 *)(bp->mips_firmware->data + file_offset);
3837
3838 offset = cpu_reg->spad_base + (addr - cpu_reg->mips_view_base);
3839 if (len) {
Michael Chanb6016b72005-05-26 13:03:09 -07003840 int j;
3841
Michael Chan57579f72009-04-04 16:51:14 -07003842 for (j = 0; j < (len / 4); j++, offset += 4)
3843 bnx2_reg_wr_ind(bp, offset, be32_to_cpu(data[j]));
Michael Chanb6016b72005-05-26 13:03:09 -07003844 }
3845
3846 /* Load the Data area. */
Michael Chan57579f72009-04-04 16:51:14 -07003847 addr = be32_to_cpu(fw_entry->data.addr);
3848 len = be32_to_cpu(fw_entry->data.len);
3849 file_offset = be32_to_cpu(fw_entry->data.offset);
3850 data = (__be32 *)(bp->mips_firmware->data + file_offset);
3851
3852 offset = cpu_reg->spad_base + (addr - cpu_reg->mips_view_base);
3853 if (len) {
Michael Chanb6016b72005-05-26 13:03:09 -07003854 int j;
3855
Michael Chan57579f72009-04-04 16:51:14 -07003856 for (j = 0; j < (len / 4); j++, offset += 4)
3857 bnx2_reg_wr_ind(bp, offset, be32_to_cpu(data[j]));
Michael Chanb6016b72005-05-26 13:03:09 -07003858 }
3859
3860 /* Load the Read-Only area. */
Michael Chan57579f72009-04-04 16:51:14 -07003861 addr = be32_to_cpu(fw_entry->rodata.addr);
3862 len = be32_to_cpu(fw_entry->rodata.len);
3863 file_offset = be32_to_cpu(fw_entry->rodata.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 /* Clear the pre-fetch instruction. */
Michael Chan2726d6e2008-01-29 21:35:05 -08003875 bnx2_reg_wr_ind(bp, cpu_reg->inst, 0);
Michael Chan57579f72009-04-04 16:51:14 -07003876
3877 val = be32_to_cpu(fw_entry->start_addr);
3878 bnx2_reg_wr_ind(bp, cpu_reg->pc, val);
Michael Chanb6016b72005-05-26 13:03:09 -07003879
3880 /* Start the CPU. */
Michael Chan2726d6e2008-01-29 21:35:05 -08003881 val = bnx2_reg_rd_ind(bp, cpu_reg->mode);
Michael Chanb6016b72005-05-26 13:03:09 -07003882 val &= ~cpu_reg->mode_value_halt;
Michael Chan2726d6e2008-01-29 21:35:05 -08003883 bnx2_reg_wr_ind(bp, cpu_reg->state, cpu_reg->state_value_clear);
3884 bnx2_reg_wr_ind(bp, cpu_reg->mode, val);
Michael Chanaf3ee512006-11-19 14:09:25 -08003885
3886 return 0;
Michael Chanb6016b72005-05-26 13:03:09 -07003887}
3888
Michael Chanfba9fe92006-06-12 22:21:25 -07003889static int
Michael Chanb6016b72005-05-26 13:03:09 -07003890bnx2_init_cpus(struct bnx2 *bp)
3891{
Michael Chan57579f72009-04-04 16:51:14 -07003892 const struct bnx2_mips_fw_file *mips_fw =
3893 (const struct bnx2_mips_fw_file *) bp->mips_firmware->data;
3894 const struct bnx2_rv2p_fw_file *rv2p_fw =
3895 (const struct bnx2_rv2p_fw_file *) bp->rv2p_firmware->data;
3896 int rc;
Michael Chanb6016b72005-05-26 13:03:09 -07003897
3898 /* Initialize the RV2P processor. */
Michael Chan57579f72009-04-04 16:51:14 -07003899 load_rv2p_fw(bp, RV2P_PROC1, &rv2p_fw->proc1);
3900 load_rv2p_fw(bp, RV2P_PROC2, &rv2p_fw->proc2);
Michael Chanb6016b72005-05-26 13:03:09 -07003901
3902 /* Initialize the RX Processor. */
Michael Chan57579f72009-04-04 16:51:14 -07003903 rc = load_cpu_fw(bp, &cpu_reg_rxp, &mips_fw->rxp);
Michael Chanfba9fe92006-06-12 22:21:25 -07003904 if (rc)
3905 goto init_cpu_err;
3906
Michael Chanb6016b72005-05-26 13:03:09 -07003907 /* Initialize the TX Processor. */
Michael Chan57579f72009-04-04 16:51:14 -07003908 rc = load_cpu_fw(bp, &cpu_reg_txp, &mips_fw->txp);
Michael Chanfba9fe92006-06-12 22:21:25 -07003909 if (rc)
3910 goto init_cpu_err;
3911
Michael Chanb6016b72005-05-26 13:03:09 -07003912 /* Initialize the TX Patch-up Processor. */
Michael Chan57579f72009-04-04 16:51:14 -07003913 rc = load_cpu_fw(bp, &cpu_reg_tpat, &mips_fw->tpat);
Michael Chanfba9fe92006-06-12 22:21:25 -07003914 if (rc)
3915 goto init_cpu_err;
3916
Michael Chanb6016b72005-05-26 13:03:09 -07003917 /* Initialize the Completion Processor. */
Michael Chan57579f72009-04-04 16:51:14 -07003918 rc = load_cpu_fw(bp, &cpu_reg_com, &mips_fw->com);
Michael Chanfba9fe92006-06-12 22:21:25 -07003919 if (rc)
3920 goto init_cpu_err;
3921
Michael Chand43584c2006-11-19 14:14:35 -08003922 /* Initialize the Command Processor. */
Michael Chan57579f72009-04-04 16:51:14 -07003923 rc = load_cpu_fw(bp, &cpu_reg_cp, &mips_fw->cp);
Michael Chan110d0ef2007-12-12 11:18:34 -08003924
Michael Chanfba9fe92006-06-12 22:21:25 -07003925init_cpu_err:
Michael Chanfba9fe92006-06-12 22:21:25 -07003926 return rc;
Michael Chanb6016b72005-05-26 13:03:09 -07003927}
3928
Michael Chanb6a23e92013-08-06 15:50:09 -07003929static void
3930bnx2_setup_wol(struct bnx2 *bp)
3931{
3932 int i;
3933 u32 val, wol_msg;
3934
3935 if (bp->wol) {
3936 u32 advertising;
3937 u8 autoneg;
3938
3939 autoneg = bp->autoneg;
3940 advertising = bp->advertising;
3941
3942 if (bp->phy_port == PORT_TP) {
3943 bp->autoneg = AUTONEG_SPEED;
3944 bp->advertising = ADVERTISED_10baseT_Half |
3945 ADVERTISED_10baseT_Full |
3946 ADVERTISED_100baseT_Half |
3947 ADVERTISED_100baseT_Full |
3948 ADVERTISED_Autoneg;
3949 }
3950
3951 spin_lock_bh(&bp->phy_lock);
3952 bnx2_setup_phy(bp, bp->phy_port);
3953 spin_unlock_bh(&bp->phy_lock);
3954
3955 bp->autoneg = autoneg;
3956 bp->advertising = advertising;
3957
3958 bnx2_set_mac_addr(bp, bp->dev->dev_addr, 0);
3959
3960 val = BNX2_RD(bp, BNX2_EMAC_MODE);
3961
3962 /* Enable port mode. */
3963 val &= ~BNX2_EMAC_MODE_PORT;
3964 val |= BNX2_EMAC_MODE_MPKT_RCVD |
3965 BNX2_EMAC_MODE_ACPI_RCVD |
3966 BNX2_EMAC_MODE_MPKT;
3967 if (bp->phy_port == PORT_TP) {
3968 val |= BNX2_EMAC_MODE_PORT_MII;
3969 } else {
3970 val |= BNX2_EMAC_MODE_PORT_GMII;
3971 if (bp->line_speed == SPEED_2500)
3972 val |= BNX2_EMAC_MODE_25G_MODE;
3973 }
3974
3975 BNX2_WR(bp, BNX2_EMAC_MODE, val);
3976
3977 /* receive all multicast */
3978 for (i = 0; i < NUM_MC_HASH_REGISTERS; i++) {
3979 BNX2_WR(bp, BNX2_EMAC_MULTICAST_HASH0 + (i * 4),
3980 0xffffffff);
3981 }
3982 BNX2_WR(bp, BNX2_EMAC_RX_MODE, BNX2_EMAC_RX_MODE_SORT_MODE);
3983
3984 val = 1 | BNX2_RPM_SORT_USER0_BC_EN | BNX2_RPM_SORT_USER0_MC_EN;
3985 BNX2_WR(bp, BNX2_RPM_SORT_USER0, 0x0);
3986 BNX2_WR(bp, BNX2_RPM_SORT_USER0, val);
3987 BNX2_WR(bp, BNX2_RPM_SORT_USER0, val | BNX2_RPM_SORT_USER0_ENA);
3988
3989 /* Need to enable EMAC and RPM for WOL. */
3990 BNX2_WR(bp, BNX2_MISC_ENABLE_SET_BITS,
3991 BNX2_MISC_ENABLE_SET_BITS_RX_PARSER_MAC_ENABLE |
3992 BNX2_MISC_ENABLE_SET_BITS_TX_HEADER_Q_ENABLE |
3993 BNX2_MISC_ENABLE_SET_BITS_EMAC_ENABLE);
3994
3995 val = BNX2_RD(bp, BNX2_RPM_CONFIG);
3996 val &= ~BNX2_RPM_CONFIG_ACPI_ENA;
3997 BNX2_WR(bp, BNX2_RPM_CONFIG, val);
3998
3999 wol_msg = BNX2_DRV_MSG_CODE_SUSPEND_WOL;
4000 } else {
4001 wol_msg = BNX2_DRV_MSG_CODE_SUSPEND_NO_WOL;
4002 }
4003
4004 if (!(bp->flags & BNX2_FLAG_NO_WOL))
4005 bnx2_fw_sync(bp, BNX2_DRV_MSG_DATA_WAIT3 | wol_msg, 1, 0);
4006
4007}
4008
Michael Chanb6016b72005-05-26 13:03:09 -07004009static int
Pavel Machek829ca9a2005-09-03 15:56:56 -07004010bnx2_set_power_state(struct bnx2 *bp, pci_power_t state)
Michael Chanb6016b72005-05-26 13:03:09 -07004011{
Michael Chanb6016b72005-05-26 13:03:09 -07004012 switch (state) {
Pavel Machek829ca9a2005-09-03 15:56:56 -07004013 case PCI_D0: {
Michael Chanb6016b72005-05-26 13:03:09 -07004014 u32 val;
4015
Michael Chan6d5e85c2013-08-06 15:50:08 -07004016 pci_enable_wake(bp->pdev, PCI_D0, false);
4017 pci_set_power_state(bp->pdev, PCI_D0);
Michael Chanb6016b72005-05-26 13:03:09 -07004018
Michael Chane503e062012-12-06 10:33:08 +00004019 val = BNX2_RD(bp, BNX2_EMAC_MODE);
Michael Chanb6016b72005-05-26 13:03:09 -07004020 val |= BNX2_EMAC_MODE_MPKT_RCVD | BNX2_EMAC_MODE_ACPI_RCVD;
4021 val &= ~BNX2_EMAC_MODE_MPKT;
Michael Chane503e062012-12-06 10:33:08 +00004022 BNX2_WR(bp, BNX2_EMAC_MODE, val);
Michael Chanb6016b72005-05-26 13:03:09 -07004023
Michael Chane503e062012-12-06 10:33:08 +00004024 val = BNX2_RD(bp, BNX2_RPM_CONFIG);
Michael Chanb6016b72005-05-26 13:03:09 -07004025 val &= ~BNX2_RPM_CONFIG_ACPI_ENA;
Michael Chane503e062012-12-06 10:33:08 +00004026 BNX2_WR(bp, BNX2_RPM_CONFIG, val);
Michael Chanb6016b72005-05-26 13:03:09 -07004027 break;
4028 }
Pavel Machek829ca9a2005-09-03 15:56:56 -07004029 case PCI_D3hot: {
Michael Chanb6a23e92013-08-06 15:50:09 -07004030 bnx2_setup_wol(bp);
Michael Chan6d5e85c2013-08-06 15:50:08 -07004031 pci_wake_from_d3(bp->pdev, bp->wol);
Michael Chan4ce45e02012-12-06 10:33:10 +00004032 if ((BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5706_A0) ||
4033 (BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5706_A1)) {
Michael Chanb6016b72005-05-26 13:03:09 -07004034
4035 if (bp->wol)
Michael Chan6d5e85c2013-08-06 15:50:08 -07004036 pci_set_power_state(bp->pdev, PCI_D3hot);
4037 } else {
4038 pci_set_power_state(bp->pdev, PCI_D3hot);
Michael Chanb6016b72005-05-26 13:03:09 -07004039 }
Michael Chanb6016b72005-05-26 13:03:09 -07004040
4041 /* No more memory access after this point until
4042 * device is brought back to D0.
4043 */
Michael Chanb6016b72005-05-26 13:03:09 -07004044 break;
4045 }
4046 default:
4047 return -EINVAL;
4048 }
4049 return 0;
4050}
4051
4052static int
4053bnx2_acquire_nvram_lock(struct bnx2 *bp)
4054{
4055 u32 val;
4056 int j;
4057
4058 /* Request access to the flash interface. */
Michael Chane503e062012-12-06 10:33:08 +00004059 BNX2_WR(bp, BNX2_NVM_SW_ARB, BNX2_NVM_SW_ARB_ARB_REQ_SET2);
Michael Chanb6016b72005-05-26 13:03:09 -07004060 for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) {
Michael Chane503e062012-12-06 10:33:08 +00004061 val = BNX2_RD(bp, BNX2_NVM_SW_ARB);
Michael Chanb6016b72005-05-26 13:03:09 -07004062 if (val & BNX2_NVM_SW_ARB_ARB_ARB2)
4063 break;
4064
4065 udelay(5);
4066 }
4067
4068 if (j >= NVRAM_TIMEOUT_COUNT)
4069 return -EBUSY;
4070
4071 return 0;
4072}
4073
4074static int
4075bnx2_release_nvram_lock(struct bnx2 *bp)
4076{
4077 int j;
4078 u32 val;
4079
4080 /* Relinquish nvram interface. */
Michael Chane503e062012-12-06 10:33:08 +00004081 BNX2_WR(bp, BNX2_NVM_SW_ARB, BNX2_NVM_SW_ARB_ARB_REQ_CLR2);
Michael Chanb6016b72005-05-26 13:03:09 -07004082
4083 for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) {
Michael Chane503e062012-12-06 10:33:08 +00004084 val = BNX2_RD(bp, BNX2_NVM_SW_ARB);
Michael Chanb6016b72005-05-26 13:03:09 -07004085 if (!(val & BNX2_NVM_SW_ARB_ARB_ARB2))
4086 break;
4087
4088 udelay(5);
4089 }
4090
4091 if (j >= NVRAM_TIMEOUT_COUNT)
4092 return -EBUSY;
4093
4094 return 0;
4095}
4096
4097
4098static int
4099bnx2_enable_nvram_write(struct bnx2 *bp)
4100{
4101 u32 val;
4102
Michael Chane503e062012-12-06 10:33:08 +00004103 val = BNX2_RD(bp, BNX2_MISC_CFG);
4104 BNX2_WR(bp, BNX2_MISC_CFG, val | BNX2_MISC_CFG_NVM_WR_EN_PCI);
Michael Chanb6016b72005-05-26 13:03:09 -07004105
Michael Chane30372c2007-07-16 18:26:23 -07004106 if (bp->flash_info->flags & BNX2_NV_WREN) {
Michael Chanb6016b72005-05-26 13:03:09 -07004107 int j;
4108
Michael Chane503e062012-12-06 10:33:08 +00004109 BNX2_WR(bp, BNX2_NVM_COMMAND, BNX2_NVM_COMMAND_DONE);
4110 BNX2_WR(bp, BNX2_NVM_COMMAND,
4111 BNX2_NVM_COMMAND_WREN | BNX2_NVM_COMMAND_DOIT);
Michael Chanb6016b72005-05-26 13:03:09 -07004112
4113 for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) {
4114 udelay(5);
4115
Michael Chane503e062012-12-06 10:33:08 +00004116 val = BNX2_RD(bp, BNX2_NVM_COMMAND);
Michael Chanb6016b72005-05-26 13:03:09 -07004117 if (val & BNX2_NVM_COMMAND_DONE)
4118 break;
4119 }
4120
4121 if (j >= NVRAM_TIMEOUT_COUNT)
4122 return -EBUSY;
4123 }
4124 return 0;
4125}
4126
4127static void
4128bnx2_disable_nvram_write(struct bnx2 *bp)
4129{
4130 u32 val;
4131
Michael Chane503e062012-12-06 10:33:08 +00004132 val = BNX2_RD(bp, BNX2_MISC_CFG);
4133 BNX2_WR(bp, BNX2_MISC_CFG, val & ~BNX2_MISC_CFG_NVM_WR_EN);
Michael Chanb6016b72005-05-26 13:03:09 -07004134}
4135
4136
4137static void
4138bnx2_enable_nvram_access(struct bnx2 *bp)
4139{
4140 u32 val;
4141
Michael Chane503e062012-12-06 10:33:08 +00004142 val = BNX2_RD(bp, BNX2_NVM_ACCESS_ENABLE);
Michael Chanb6016b72005-05-26 13:03:09 -07004143 /* Enable both bits, even on read. */
Michael Chane503e062012-12-06 10:33:08 +00004144 BNX2_WR(bp, BNX2_NVM_ACCESS_ENABLE,
4145 val | BNX2_NVM_ACCESS_ENABLE_EN | BNX2_NVM_ACCESS_ENABLE_WR_EN);
Michael Chanb6016b72005-05-26 13:03:09 -07004146}
4147
4148static void
4149bnx2_disable_nvram_access(struct bnx2 *bp)
4150{
4151 u32 val;
4152
Michael Chane503e062012-12-06 10:33:08 +00004153 val = BNX2_RD(bp, BNX2_NVM_ACCESS_ENABLE);
Michael Chanb6016b72005-05-26 13:03:09 -07004154 /* Disable both bits, even after read. */
Michael Chane503e062012-12-06 10:33:08 +00004155 BNX2_WR(bp, BNX2_NVM_ACCESS_ENABLE,
Michael Chanb6016b72005-05-26 13:03:09 -07004156 val & ~(BNX2_NVM_ACCESS_ENABLE_EN |
4157 BNX2_NVM_ACCESS_ENABLE_WR_EN));
4158}
4159
4160static int
4161bnx2_nvram_erase_page(struct bnx2 *bp, u32 offset)
4162{
4163 u32 cmd;
4164 int j;
4165
Michael Chane30372c2007-07-16 18:26:23 -07004166 if (bp->flash_info->flags & BNX2_NV_BUFFERED)
Michael Chanb6016b72005-05-26 13:03:09 -07004167 /* Buffered flash, no erase needed */
4168 return 0;
4169
4170 /* Build an erase command */
4171 cmd = BNX2_NVM_COMMAND_ERASE | BNX2_NVM_COMMAND_WR |
4172 BNX2_NVM_COMMAND_DOIT;
4173
4174 /* Need to clear DONE bit separately. */
Michael Chane503e062012-12-06 10:33:08 +00004175 BNX2_WR(bp, BNX2_NVM_COMMAND, BNX2_NVM_COMMAND_DONE);
Michael Chanb6016b72005-05-26 13:03:09 -07004176
4177 /* Address of the NVRAM to read from. */
Michael Chane503e062012-12-06 10:33:08 +00004178 BNX2_WR(bp, BNX2_NVM_ADDR, offset & BNX2_NVM_ADDR_NVM_ADDR_VALUE);
Michael Chanb6016b72005-05-26 13:03:09 -07004179
4180 /* Issue an erase command. */
Michael Chane503e062012-12-06 10:33:08 +00004181 BNX2_WR(bp, BNX2_NVM_COMMAND, cmd);
Michael Chanb6016b72005-05-26 13:03:09 -07004182
4183 /* Wait for completion. */
4184 for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) {
4185 u32 val;
4186
4187 udelay(5);
4188
Michael Chane503e062012-12-06 10:33:08 +00004189 val = BNX2_RD(bp, BNX2_NVM_COMMAND);
Michael Chanb6016b72005-05-26 13:03:09 -07004190 if (val & BNX2_NVM_COMMAND_DONE)
4191 break;
4192 }
4193
4194 if (j >= NVRAM_TIMEOUT_COUNT)
4195 return -EBUSY;
4196
4197 return 0;
4198}
4199
4200static int
4201bnx2_nvram_read_dword(struct bnx2 *bp, u32 offset, u8 *ret_val, u32 cmd_flags)
4202{
4203 u32 cmd;
4204 int j;
4205
4206 /* Build the command word. */
4207 cmd = BNX2_NVM_COMMAND_DOIT | cmd_flags;
4208
Michael Chane30372c2007-07-16 18:26:23 -07004209 /* Calculate an offset of a buffered flash, not needed for 5709. */
4210 if (bp->flash_info->flags & BNX2_NV_TRANSLATE) {
Michael Chanb6016b72005-05-26 13:03:09 -07004211 offset = ((offset / bp->flash_info->page_size) <<
4212 bp->flash_info->page_bits) +
4213 (offset % bp->flash_info->page_size);
4214 }
4215
4216 /* Need to clear DONE bit separately. */
Michael Chane503e062012-12-06 10:33:08 +00004217 BNX2_WR(bp, BNX2_NVM_COMMAND, BNX2_NVM_COMMAND_DONE);
Michael Chanb6016b72005-05-26 13:03:09 -07004218
4219 /* Address of the NVRAM to read from. */
Michael Chane503e062012-12-06 10:33:08 +00004220 BNX2_WR(bp, BNX2_NVM_ADDR, offset & BNX2_NVM_ADDR_NVM_ADDR_VALUE);
Michael Chanb6016b72005-05-26 13:03:09 -07004221
4222 /* Issue a read command. */
Michael Chane503e062012-12-06 10:33:08 +00004223 BNX2_WR(bp, BNX2_NVM_COMMAND, cmd);
Michael Chanb6016b72005-05-26 13:03:09 -07004224
4225 /* Wait for completion. */
4226 for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) {
4227 u32 val;
4228
4229 udelay(5);
4230
Michael Chane503e062012-12-06 10:33:08 +00004231 val = BNX2_RD(bp, BNX2_NVM_COMMAND);
Michael Chanb6016b72005-05-26 13:03:09 -07004232 if (val & BNX2_NVM_COMMAND_DONE) {
Michael Chane503e062012-12-06 10:33:08 +00004233 __be32 v = cpu_to_be32(BNX2_RD(bp, BNX2_NVM_READ));
Al Virob491edd2007-12-22 19:44:51 +00004234 memcpy(ret_val, &v, 4);
Michael Chanb6016b72005-05-26 13:03:09 -07004235 break;
4236 }
4237 }
4238 if (j >= NVRAM_TIMEOUT_COUNT)
4239 return -EBUSY;
4240
4241 return 0;
4242}
4243
4244
4245static int
4246bnx2_nvram_write_dword(struct bnx2 *bp, u32 offset, u8 *val, u32 cmd_flags)
4247{
Al Virob491edd2007-12-22 19:44:51 +00004248 u32 cmd;
4249 __be32 val32;
Michael Chanb6016b72005-05-26 13:03:09 -07004250 int j;
4251
4252 /* Build the command word. */
4253 cmd = BNX2_NVM_COMMAND_DOIT | BNX2_NVM_COMMAND_WR | cmd_flags;
4254
Michael Chane30372c2007-07-16 18:26:23 -07004255 /* Calculate an offset of a buffered flash, not needed for 5709. */
4256 if (bp->flash_info->flags & BNX2_NV_TRANSLATE) {
Michael Chanb6016b72005-05-26 13:03:09 -07004257 offset = ((offset / bp->flash_info->page_size) <<
4258 bp->flash_info->page_bits) +
4259 (offset % bp->flash_info->page_size);
4260 }
4261
4262 /* Need to clear DONE bit separately. */
Michael Chane503e062012-12-06 10:33:08 +00004263 BNX2_WR(bp, BNX2_NVM_COMMAND, BNX2_NVM_COMMAND_DONE);
Michael Chanb6016b72005-05-26 13:03:09 -07004264
4265 memcpy(&val32, val, 4);
Michael Chanb6016b72005-05-26 13:03:09 -07004266
4267 /* Write the data. */
Michael Chane503e062012-12-06 10:33:08 +00004268 BNX2_WR(bp, BNX2_NVM_WRITE, be32_to_cpu(val32));
Michael Chanb6016b72005-05-26 13:03:09 -07004269
4270 /* Address of the NVRAM to write to. */
Michael Chane503e062012-12-06 10:33:08 +00004271 BNX2_WR(bp, BNX2_NVM_ADDR, offset & BNX2_NVM_ADDR_NVM_ADDR_VALUE);
Michael Chanb6016b72005-05-26 13:03:09 -07004272
4273 /* Issue the write command. */
Michael Chane503e062012-12-06 10:33:08 +00004274 BNX2_WR(bp, BNX2_NVM_COMMAND, cmd);
Michael Chanb6016b72005-05-26 13:03:09 -07004275
4276 /* Wait for completion. */
4277 for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) {
4278 udelay(5);
4279
Michael Chane503e062012-12-06 10:33:08 +00004280 if (BNX2_RD(bp, BNX2_NVM_COMMAND) & BNX2_NVM_COMMAND_DONE)
Michael Chanb6016b72005-05-26 13:03:09 -07004281 break;
4282 }
4283 if (j >= NVRAM_TIMEOUT_COUNT)
4284 return -EBUSY;
4285
4286 return 0;
4287}
4288
4289static int
4290bnx2_init_nvram(struct bnx2 *bp)
4291{
4292 u32 val;
Michael Chane30372c2007-07-16 18:26:23 -07004293 int j, entry_count, rc = 0;
Michael Chan0ced9d02009-08-21 16:20:49 +00004294 const struct flash_spec *flash;
Michael Chanb6016b72005-05-26 13:03:09 -07004295
Michael Chan4ce45e02012-12-06 10:33:10 +00004296 if (BNX2_CHIP(bp) == BNX2_CHIP_5709) {
Michael Chane30372c2007-07-16 18:26:23 -07004297 bp->flash_info = &flash_5709;
4298 goto get_flash_size;
4299 }
4300
Michael Chanb6016b72005-05-26 13:03:09 -07004301 /* Determine the selected interface. */
Michael Chane503e062012-12-06 10:33:08 +00004302 val = BNX2_RD(bp, BNX2_NVM_CFG1);
Michael Chanb6016b72005-05-26 13:03:09 -07004303
Denis Chengff8ac602007-09-02 18:30:18 +08004304 entry_count = ARRAY_SIZE(flash_table);
Michael Chanb6016b72005-05-26 13:03:09 -07004305
Michael Chanb6016b72005-05-26 13:03:09 -07004306 if (val & 0x40000000) {
4307
4308 /* Flash interface has been reconfigured */
4309 for (j = 0, flash = &flash_table[0]; j < entry_count;
Michael Chan37137702005-11-04 08:49:17 -08004310 j++, flash++) {
4311 if ((val & FLASH_BACKUP_STRAP_MASK) ==
4312 (flash->config1 & FLASH_BACKUP_STRAP_MASK)) {
Michael Chanb6016b72005-05-26 13:03:09 -07004313 bp->flash_info = flash;
4314 break;
4315 }
4316 }
4317 }
4318 else {
Michael Chan37137702005-11-04 08:49:17 -08004319 u32 mask;
Michael Chanb6016b72005-05-26 13:03:09 -07004320 /* Not yet been reconfigured */
4321
Michael Chan37137702005-11-04 08:49:17 -08004322 if (val & (1 << 23))
4323 mask = FLASH_BACKUP_STRAP_MASK;
4324 else
4325 mask = FLASH_STRAP_MASK;
4326
Michael Chanb6016b72005-05-26 13:03:09 -07004327 for (j = 0, flash = &flash_table[0]; j < entry_count;
4328 j++, flash++) {
4329
Michael Chan37137702005-11-04 08:49:17 -08004330 if ((val & mask) == (flash->strapping & mask)) {
Michael Chanb6016b72005-05-26 13:03:09 -07004331 bp->flash_info = flash;
4332
4333 /* Request access to the flash interface. */
4334 if ((rc = bnx2_acquire_nvram_lock(bp)) != 0)
4335 return rc;
4336
4337 /* Enable access to flash interface */
4338 bnx2_enable_nvram_access(bp);
4339
4340 /* Reconfigure the flash interface */
Michael Chane503e062012-12-06 10:33:08 +00004341 BNX2_WR(bp, BNX2_NVM_CFG1, flash->config1);
4342 BNX2_WR(bp, BNX2_NVM_CFG2, flash->config2);
4343 BNX2_WR(bp, BNX2_NVM_CFG3, flash->config3);
4344 BNX2_WR(bp, BNX2_NVM_WRITE1, flash->write1);
Michael Chanb6016b72005-05-26 13:03:09 -07004345
4346 /* Disable access to flash interface */
4347 bnx2_disable_nvram_access(bp);
4348 bnx2_release_nvram_lock(bp);
4349
4350 break;
4351 }
4352 }
4353 } /* if (val & 0x40000000) */
4354
4355 if (j == entry_count) {
4356 bp->flash_info = NULL;
Joe Perches3a9c6a42010-02-17 15:01:51 +00004357 pr_alert("Unknown flash/EEPROM type\n");
Michael Chan1122db72006-01-23 16:11:42 -08004358 return -ENODEV;
Michael Chanb6016b72005-05-26 13:03:09 -07004359 }
4360
Michael Chane30372c2007-07-16 18:26:23 -07004361get_flash_size:
Michael Chan2726d6e2008-01-29 21:35:05 -08004362 val = bnx2_shmem_rd(bp, BNX2_SHARED_HW_CFG_CONFIG2);
Michael Chan1122db72006-01-23 16:11:42 -08004363 val &= BNX2_SHARED_HW_CFG2_NVM_SIZE_MASK;
4364 if (val)
4365 bp->flash_size = val;
4366 else
4367 bp->flash_size = bp->flash_info->total_size;
4368
Michael Chanb6016b72005-05-26 13:03:09 -07004369 return rc;
4370}
4371
4372static int
4373bnx2_nvram_read(struct bnx2 *bp, u32 offset, u8 *ret_buf,
4374 int buf_size)
4375{
4376 int rc = 0;
4377 u32 cmd_flags, offset32, len32, extra;
4378
4379 if (buf_size == 0)
4380 return 0;
4381
4382 /* Request access to the flash interface. */
4383 if ((rc = bnx2_acquire_nvram_lock(bp)) != 0)
4384 return rc;
4385
4386 /* Enable access to flash interface */
4387 bnx2_enable_nvram_access(bp);
4388
4389 len32 = buf_size;
4390 offset32 = offset;
4391 extra = 0;
4392
4393 cmd_flags = 0;
4394
4395 if (offset32 & 3) {
4396 u8 buf[4];
4397 u32 pre_len;
4398
4399 offset32 &= ~3;
4400 pre_len = 4 - (offset & 3);
4401
4402 if (pre_len >= len32) {
4403 pre_len = len32;
4404 cmd_flags = BNX2_NVM_COMMAND_FIRST |
4405 BNX2_NVM_COMMAND_LAST;
4406 }
4407 else {
4408 cmd_flags = BNX2_NVM_COMMAND_FIRST;
4409 }
4410
4411 rc = bnx2_nvram_read_dword(bp, offset32, buf, cmd_flags);
4412
4413 if (rc)
4414 return rc;
4415
4416 memcpy(ret_buf, buf + (offset & 3), pre_len);
4417
4418 offset32 += 4;
4419 ret_buf += pre_len;
4420 len32 -= pre_len;
4421 }
4422 if (len32 & 3) {
4423 extra = 4 - (len32 & 3);
4424 len32 = (len32 + 4) & ~3;
4425 }
4426
4427 if (len32 == 4) {
4428 u8 buf[4];
4429
4430 if (cmd_flags)
4431 cmd_flags = BNX2_NVM_COMMAND_LAST;
4432 else
4433 cmd_flags = BNX2_NVM_COMMAND_FIRST |
4434 BNX2_NVM_COMMAND_LAST;
4435
4436 rc = bnx2_nvram_read_dword(bp, offset32, buf, cmd_flags);
4437
4438 memcpy(ret_buf, buf, 4 - extra);
4439 }
4440 else if (len32 > 0) {
4441 u8 buf[4];
4442
4443 /* Read the first word. */
4444 if (cmd_flags)
4445 cmd_flags = 0;
4446 else
4447 cmd_flags = BNX2_NVM_COMMAND_FIRST;
4448
4449 rc = bnx2_nvram_read_dword(bp, offset32, ret_buf, cmd_flags);
4450
4451 /* Advance to the next dword. */
4452 offset32 += 4;
4453 ret_buf += 4;
4454 len32 -= 4;
4455
4456 while (len32 > 4 && rc == 0) {
4457 rc = bnx2_nvram_read_dword(bp, offset32, ret_buf, 0);
4458
4459 /* Advance to the next dword. */
4460 offset32 += 4;
4461 ret_buf += 4;
4462 len32 -= 4;
4463 }
4464
4465 if (rc)
4466 return rc;
4467
4468 cmd_flags = BNX2_NVM_COMMAND_LAST;
4469 rc = bnx2_nvram_read_dword(bp, offset32, buf, cmd_flags);
4470
4471 memcpy(ret_buf, buf, 4 - extra);
4472 }
4473
4474 /* Disable access to flash interface */
4475 bnx2_disable_nvram_access(bp);
4476
4477 bnx2_release_nvram_lock(bp);
4478
4479 return rc;
4480}
4481
4482static int
4483bnx2_nvram_write(struct bnx2 *bp, u32 offset, u8 *data_buf,
4484 int buf_size)
4485{
4486 u32 written, offset32, len32;
Michael Chane6be7632007-01-08 19:56:13 -08004487 u8 *buf, start[4], end[4], *align_buf = NULL, *flash_buffer = NULL;
Michael Chanb6016b72005-05-26 13:03:09 -07004488 int rc = 0;
4489 int align_start, align_end;
4490
4491 buf = data_buf;
4492 offset32 = offset;
4493 len32 = buf_size;
4494 align_start = align_end = 0;
4495
4496 if ((align_start = (offset32 & 3))) {
4497 offset32 &= ~3;
Michael Chanc8738792007-03-30 14:53:06 -07004498 len32 += align_start;
4499 if (len32 < 4)
4500 len32 = 4;
Michael Chanb6016b72005-05-26 13:03:09 -07004501 if ((rc = bnx2_nvram_read(bp, offset32, start, 4)))
4502 return rc;
4503 }
4504
4505 if (len32 & 3) {
Michael Chanc8738792007-03-30 14:53:06 -07004506 align_end = 4 - (len32 & 3);
4507 len32 += align_end;
4508 if ((rc = bnx2_nvram_read(bp, offset32 + len32 - 4, end, 4)))
4509 return rc;
Michael Chanb6016b72005-05-26 13:03:09 -07004510 }
4511
4512 if (align_start || align_end) {
Michael Chane6be7632007-01-08 19:56:13 -08004513 align_buf = kmalloc(len32, GFP_KERNEL);
4514 if (align_buf == NULL)
Michael Chanb6016b72005-05-26 13:03:09 -07004515 return -ENOMEM;
4516 if (align_start) {
Michael Chane6be7632007-01-08 19:56:13 -08004517 memcpy(align_buf, start, 4);
Michael Chanb6016b72005-05-26 13:03:09 -07004518 }
4519 if (align_end) {
Michael Chane6be7632007-01-08 19:56:13 -08004520 memcpy(align_buf + len32 - 4, end, 4);
Michael Chanb6016b72005-05-26 13:03:09 -07004521 }
Michael Chane6be7632007-01-08 19:56:13 -08004522 memcpy(align_buf + align_start, data_buf, buf_size);
4523 buf = align_buf;
Michael Chanb6016b72005-05-26 13:03:09 -07004524 }
4525
Michael Chane30372c2007-07-16 18:26:23 -07004526 if (!(bp->flash_info->flags & BNX2_NV_BUFFERED)) {
Michael Chanae181bc2006-05-22 16:39:20 -07004527 flash_buffer = kmalloc(264, GFP_KERNEL);
4528 if (flash_buffer == NULL) {
4529 rc = -ENOMEM;
4530 goto nvram_write_end;
4531 }
4532 }
4533
Michael Chanb6016b72005-05-26 13:03:09 -07004534 written = 0;
4535 while ((written < len32) && (rc == 0)) {
4536 u32 page_start, page_end, data_start, data_end;
4537 u32 addr, cmd_flags;
4538 int i;
Michael Chanb6016b72005-05-26 13:03:09 -07004539
4540 /* Find the page_start addr */
4541 page_start = offset32 + written;
4542 page_start -= (page_start % bp->flash_info->page_size);
4543 /* Find the page_end addr */
4544 page_end = page_start + bp->flash_info->page_size;
4545 /* Find the data_start addr */
4546 data_start = (written == 0) ? offset32 : page_start;
4547 /* Find the data_end addr */
Jeff Garzik6aa20a22006-09-13 13:24:59 -04004548 data_end = (page_end > offset32 + len32) ?
Michael Chanb6016b72005-05-26 13:03:09 -07004549 (offset32 + len32) : page_end;
4550
4551 /* Request access to the flash interface. */
4552 if ((rc = bnx2_acquire_nvram_lock(bp)) != 0)
4553 goto nvram_write_end;
4554
4555 /* Enable access to flash interface */
4556 bnx2_enable_nvram_access(bp);
4557
4558 cmd_flags = BNX2_NVM_COMMAND_FIRST;
Michael Chane30372c2007-07-16 18:26:23 -07004559 if (!(bp->flash_info->flags & BNX2_NV_BUFFERED)) {
Michael Chanb6016b72005-05-26 13:03:09 -07004560 int j;
4561
4562 /* Read the whole page into the buffer
4563 * (non-buffer flash only) */
4564 for (j = 0; j < bp->flash_info->page_size; j += 4) {
4565 if (j == (bp->flash_info->page_size - 4)) {
4566 cmd_flags |= BNX2_NVM_COMMAND_LAST;
4567 }
4568 rc = bnx2_nvram_read_dword(bp,
Jeff Garzik6aa20a22006-09-13 13:24:59 -04004569 page_start + j,
4570 &flash_buffer[j],
Michael Chanb6016b72005-05-26 13:03:09 -07004571 cmd_flags);
4572
4573 if (rc)
4574 goto nvram_write_end;
4575
4576 cmd_flags = 0;
4577 }
4578 }
4579
4580 /* Enable writes to flash interface (unlock write-protect) */
4581 if ((rc = bnx2_enable_nvram_write(bp)) != 0)
4582 goto nvram_write_end;
4583
Michael Chanb6016b72005-05-26 13:03:09 -07004584 /* Loop to write back the buffer data from page_start to
4585 * data_start */
4586 i = 0;
Michael Chane30372c2007-07-16 18:26:23 -07004587 if (!(bp->flash_info->flags & BNX2_NV_BUFFERED)) {
Michael Chanc8738792007-03-30 14:53:06 -07004588 /* Erase the page */
4589 if ((rc = bnx2_nvram_erase_page(bp, page_start)) != 0)
4590 goto nvram_write_end;
4591
4592 /* Re-enable the write again for the actual write */
4593 bnx2_enable_nvram_write(bp);
4594
Michael Chanb6016b72005-05-26 13:03:09 -07004595 for (addr = page_start; addr < data_start;
4596 addr += 4, i += 4) {
Jeff Garzik6aa20a22006-09-13 13:24:59 -04004597
Michael Chanb6016b72005-05-26 13:03:09 -07004598 rc = bnx2_nvram_write_dword(bp, addr,
4599 &flash_buffer[i], cmd_flags);
4600
4601 if (rc != 0)
4602 goto nvram_write_end;
4603
4604 cmd_flags = 0;
4605 }
4606 }
4607
4608 /* Loop to write the new data from data_start to data_end */
Michael Chanbae25762006-05-22 16:38:38 -07004609 for (addr = data_start; addr < data_end; addr += 4, i += 4) {
Michael Chanb6016b72005-05-26 13:03:09 -07004610 if ((addr == page_end - 4) ||
Michael Chane30372c2007-07-16 18:26:23 -07004611 ((bp->flash_info->flags & BNX2_NV_BUFFERED) &&
Michael Chanb6016b72005-05-26 13:03:09 -07004612 (addr == data_end - 4))) {
4613
4614 cmd_flags |= BNX2_NVM_COMMAND_LAST;
4615 }
4616 rc = bnx2_nvram_write_dword(bp, addr, buf,
4617 cmd_flags);
4618
4619 if (rc != 0)
4620 goto nvram_write_end;
4621
4622 cmd_flags = 0;
4623 buf += 4;
4624 }
4625
4626 /* Loop to write back the buffer data from data_end
4627 * to page_end */
Michael Chane30372c2007-07-16 18:26:23 -07004628 if (!(bp->flash_info->flags & BNX2_NV_BUFFERED)) {
Michael Chanb6016b72005-05-26 13:03:09 -07004629 for (addr = data_end; addr < page_end;
4630 addr += 4, i += 4) {
Jeff Garzik6aa20a22006-09-13 13:24:59 -04004631
Michael Chanb6016b72005-05-26 13:03:09 -07004632 if (addr == page_end-4) {
4633 cmd_flags = BNX2_NVM_COMMAND_LAST;
4634 }
4635 rc = bnx2_nvram_write_dword(bp, addr,
4636 &flash_buffer[i], cmd_flags);
4637
4638 if (rc != 0)
4639 goto nvram_write_end;
4640
4641 cmd_flags = 0;
4642 }
4643 }
4644
4645 /* Disable writes to flash interface (lock write-protect) */
4646 bnx2_disable_nvram_write(bp);
4647
4648 /* Disable access to flash interface */
4649 bnx2_disable_nvram_access(bp);
4650 bnx2_release_nvram_lock(bp);
4651
4652 /* Increment written */
4653 written += data_end - data_start;
4654 }
4655
4656nvram_write_end:
Michael Chane6be7632007-01-08 19:56:13 -08004657 kfree(flash_buffer);
4658 kfree(align_buf);
Michael Chanb6016b72005-05-26 13:03:09 -07004659 return rc;
4660}
4661
Michael Chan0d8a6572007-07-07 22:49:43 -07004662static void
Michael Chan7c62e832008-07-14 22:39:03 -07004663bnx2_init_fw_cap(struct bnx2 *bp)
Michael Chan0d8a6572007-07-07 22:49:43 -07004664{
Michael Chan7c62e832008-07-14 22:39:03 -07004665 u32 val, sig = 0;
Michael Chan0d8a6572007-07-07 22:49:43 -07004666
Michael Chan583c28e2008-01-21 19:51:35 -08004667 bp->phy_flags &= ~BNX2_PHY_FLAG_REMOTE_PHY_CAP;
Michael Chan7c62e832008-07-14 22:39:03 -07004668 bp->flags &= ~BNX2_FLAG_CAN_KEEP_VLAN;
4669
4670 if (!(bp->flags & BNX2_FLAG_ASF_ENABLE))
4671 bp->flags |= BNX2_FLAG_CAN_KEEP_VLAN;
Michael Chan0d8a6572007-07-07 22:49:43 -07004672
Michael Chan2726d6e2008-01-29 21:35:05 -08004673 val = bnx2_shmem_rd(bp, BNX2_FW_CAP_MB);
Michael Chan0d8a6572007-07-07 22:49:43 -07004674 if ((val & BNX2_FW_CAP_SIGNATURE_MASK) != BNX2_FW_CAP_SIGNATURE)
4675 return;
4676
Michael Chan7c62e832008-07-14 22:39:03 -07004677 if ((val & BNX2_FW_CAP_CAN_KEEP_VLAN) == BNX2_FW_CAP_CAN_KEEP_VLAN) {
4678 bp->flags |= BNX2_FLAG_CAN_KEEP_VLAN;
4679 sig |= BNX2_DRV_ACK_CAP_SIGNATURE | BNX2_FW_CAP_CAN_KEEP_VLAN;
4680 }
4681
4682 if ((bp->phy_flags & BNX2_PHY_FLAG_SERDES) &&
4683 (val & BNX2_FW_CAP_REMOTE_PHY_CAPABLE)) {
4684 u32 link;
4685
Michael Chan583c28e2008-01-21 19:51:35 -08004686 bp->phy_flags |= BNX2_PHY_FLAG_REMOTE_PHY_CAP;
Michael Chan0d8a6572007-07-07 22:49:43 -07004687
Michael Chan7c62e832008-07-14 22:39:03 -07004688 link = bnx2_shmem_rd(bp, BNX2_LINK_STATUS);
4689 if (link & BNX2_LINK_STATUS_SERDES_LINK)
Michael Chan0d8a6572007-07-07 22:49:43 -07004690 bp->phy_port = PORT_FIBRE;
4691 else
4692 bp->phy_port = PORT_TP;
Michael Chan489310a2007-10-10 16:16:31 -07004693
Michael Chan7c62e832008-07-14 22:39:03 -07004694 sig |= BNX2_DRV_ACK_CAP_SIGNATURE |
4695 BNX2_FW_CAP_REMOTE_PHY_CAPABLE;
Michael Chan0d8a6572007-07-07 22:49:43 -07004696 }
Michael Chan7c62e832008-07-14 22:39:03 -07004697
4698 if (netif_running(bp->dev) && sig)
4699 bnx2_shmem_wr(bp, BNX2_DRV_ACK_CAP_MB, sig);
Michael Chan0d8a6572007-07-07 22:49:43 -07004700}
4701
Michael Chanb4b36042007-12-20 19:59:30 -08004702static void
4703bnx2_setup_msix_tbl(struct bnx2 *bp)
4704{
Michael Chane503e062012-12-06 10:33:08 +00004705 BNX2_WR(bp, BNX2_PCI_GRC_WINDOW_ADDR, BNX2_PCI_GRC_WINDOW_ADDR_SEP_WIN);
Michael Chanb4b36042007-12-20 19:59:30 -08004706
Michael Chane503e062012-12-06 10:33:08 +00004707 BNX2_WR(bp, BNX2_PCI_GRC_WINDOW2_ADDR, BNX2_MSIX_TABLE_ADDR);
4708 BNX2_WR(bp, BNX2_PCI_GRC_WINDOW3_ADDR, BNX2_MSIX_PBA_ADDR);
Michael Chanb4b36042007-12-20 19:59:30 -08004709}
4710
Michael Chanb6016b72005-05-26 13:03:09 -07004711static int
4712bnx2_reset_chip(struct bnx2 *bp, u32 reset_code)
4713{
4714 u32 val;
4715 int i, rc = 0;
Michael Chan489310a2007-10-10 16:16:31 -07004716 u8 old_port;
Michael Chanb6016b72005-05-26 13:03:09 -07004717
4718 /* Wait for the current PCI transaction to complete before
4719 * issuing a reset. */
Michael Chan4ce45e02012-12-06 10:33:10 +00004720 if ((BNX2_CHIP(bp) == BNX2_CHIP_5706) ||
4721 (BNX2_CHIP(bp) == BNX2_CHIP_5708)) {
Michael Chane503e062012-12-06 10:33:08 +00004722 BNX2_WR(bp, BNX2_MISC_ENABLE_CLR_BITS,
4723 BNX2_MISC_ENABLE_CLR_BITS_TX_DMA_ENABLE |
4724 BNX2_MISC_ENABLE_CLR_BITS_DMA_ENGINE_ENABLE |
4725 BNX2_MISC_ENABLE_CLR_BITS_RX_DMA_ENABLE |
4726 BNX2_MISC_ENABLE_CLR_BITS_HOST_COALESCE_ENABLE);
4727 val = BNX2_RD(bp, BNX2_MISC_ENABLE_CLR_BITS);
Eddie Waia5dac102010-11-24 13:48:54 +00004728 udelay(5);
4729 } else { /* 5709 */
Michael Chane503e062012-12-06 10:33:08 +00004730 val = BNX2_RD(bp, BNX2_MISC_NEW_CORE_CTL);
Eddie Waia5dac102010-11-24 13:48:54 +00004731 val &= ~BNX2_MISC_NEW_CORE_CTL_DMA_ENABLE;
Michael Chane503e062012-12-06 10:33:08 +00004732 BNX2_WR(bp, BNX2_MISC_NEW_CORE_CTL, val);
4733 val = BNX2_RD(bp, BNX2_MISC_NEW_CORE_CTL);
Eddie Waia5dac102010-11-24 13:48:54 +00004734
4735 for (i = 0; i < 100; i++) {
4736 msleep(1);
Michael Chane503e062012-12-06 10:33:08 +00004737 val = BNX2_RD(bp, BNX2_PCICFG_DEVICE_CONTROL);
Eddie Waia5dac102010-11-24 13:48:54 +00004738 if (!(val & BNX2_PCICFG_DEVICE_STATUS_NO_PEND))
4739 break;
4740 }
4741 }
Michael Chanb6016b72005-05-26 13:03:09 -07004742
Michael Chanb090ae22006-01-23 16:07:10 -08004743 /* Wait for the firmware to tell us it is ok to issue a reset. */
Michael Chana2f13892008-07-14 22:38:23 -07004744 bnx2_fw_sync(bp, BNX2_DRV_MSG_DATA_WAIT0 | reset_code, 1, 1);
Michael Chanb090ae22006-01-23 16:07:10 -08004745
Michael Chanb6016b72005-05-26 13:03:09 -07004746 /* Deposit a driver reset signature so the firmware knows that
4747 * this is a soft reset. */
Michael Chan2726d6e2008-01-29 21:35:05 -08004748 bnx2_shmem_wr(bp, BNX2_DRV_RESET_SIGNATURE,
4749 BNX2_DRV_RESET_SIGNATURE_MAGIC);
Michael Chanb6016b72005-05-26 13:03:09 -07004750
Michael Chanb6016b72005-05-26 13:03:09 -07004751 /* Do a dummy read to force the chip to complete all current transaction
4752 * before we issue a reset. */
Michael Chane503e062012-12-06 10:33:08 +00004753 val = BNX2_RD(bp, BNX2_MISC_ID);
Michael Chanb6016b72005-05-26 13:03:09 -07004754
Michael Chan4ce45e02012-12-06 10:33:10 +00004755 if (BNX2_CHIP(bp) == BNX2_CHIP_5709) {
Michael Chane503e062012-12-06 10:33:08 +00004756 BNX2_WR(bp, BNX2_MISC_COMMAND, BNX2_MISC_COMMAND_SW_RESET);
4757 BNX2_RD(bp, BNX2_MISC_COMMAND);
Michael Chan234754d2006-11-19 14:11:41 -08004758 udelay(5);
Michael Chanb6016b72005-05-26 13:03:09 -07004759
Michael Chan234754d2006-11-19 14:11:41 -08004760 val = BNX2_PCICFG_MISC_CONFIG_REG_WINDOW_ENA |
4761 BNX2_PCICFG_MISC_CONFIG_TARGET_MB_WORD_SWAP;
Michael Chanb6016b72005-05-26 13:03:09 -07004762
Michael Chane503e062012-12-06 10:33:08 +00004763 BNX2_WR(bp, BNX2_PCICFG_MISC_CONFIG, val);
Michael Chanb6016b72005-05-26 13:03:09 -07004764
Michael Chan234754d2006-11-19 14:11:41 -08004765 } else {
4766 val = BNX2_PCICFG_MISC_CONFIG_CORE_RST_REQ |
4767 BNX2_PCICFG_MISC_CONFIG_REG_WINDOW_ENA |
4768 BNX2_PCICFG_MISC_CONFIG_TARGET_MB_WORD_SWAP;
4769
4770 /* Chip reset. */
Michael Chane503e062012-12-06 10:33:08 +00004771 BNX2_WR(bp, BNX2_PCICFG_MISC_CONFIG, val);
Michael Chan234754d2006-11-19 14:11:41 -08004772
Michael Chan594a9df2007-08-28 15:39:42 -07004773 /* Reading back any register after chip reset will hang the
4774 * bus on 5706 A0 and A1. The msleep below provides plenty
4775 * of margin for write posting.
4776 */
Michael Chan4ce45e02012-12-06 10:33:10 +00004777 if ((BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5706_A0) ||
4778 (BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5706_A1))
Arjan van de Ven8e545882007-08-28 14:34:43 -07004779 msleep(20);
Michael Chanb6016b72005-05-26 13:03:09 -07004780
Michael Chan234754d2006-11-19 14:11:41 -08004781 /* Reset takes approximate 30 usec */
4782 for (i = 0; i < 10; i++) {
Michael Chane503e062012-12-06 10:33:08 +00004783 val = BNX2_RD(bp, BNX2_PCICFG_MISC_CONFIG);
Michael Chan234754d2006-11-19 14:11:41 -08004784 if ((val & (BNX2_PCICFG_MISC_CONFIG_CORE_RST_REQ |
4785 BNX2_PCICFG_MISC_CONFIG_CORE_RST_BSY)) == 0)
4786 break;
4787 udelay(10);
4788 }
4789
4790 if (val & (BNX2_PCICFG_MISC_CONFIG_CORE_RST_REQ |
4791 BNX2_PCICFG_MISC_CONFIG_CORE_RST_BSY)) {
Joe Perches3a9c6a42010-02-17 15:01:51 +00004792 pr_err("Chip reset did not complete\n");
Michael Chan234754d2006-11-19 14:11:41 -08004793 return -EBUSY;
4794 }
Michael Chanb6016b72005-05-26 13:03:09 -07004795 }
4796
4797 /* Make sure byte swapping is properly configured. */
Michael Chane503e062012-12-06 10:33:08 +00004798 val = BNX2_RD(bp, BNX2_PCI_SWAP_DIAG0);
Michael Chanb6016b72005-05-26 13:03:09 -07004799 if (val != 0x01020304) {
Joe Perches3a9c6a42010-02-17 15:01:51 +00004800 pr_err("Chip not in correct endian mode\n");
Michael Chanb6016b72005-05-26 13:03:09 -07004801 return -ENODEV;
4802 }
4803
Michael Chanb6016b72005-05-26 13:03:09 -07004804 /* Wait for the firmware to finish its initialization. */
Michael Chana2f13892008-07-14 22:38:23 -07004805 rc = bnx2_fw_sync(bp, BNX2_DRV_MSG_DATA_WAIT1 | reset_code, 1, 0);
Michael Chanb090ae22006-01-23 16:07:10 -08004806 if (rc)
4807 return rc;
Michael Chanb6016b72005-05-26 13:03:09 -07004808
Michael Chan0d8a6572007-07-07 22:49:43 -07004809 spin_lock_bh(&bp->phy_lock);
Michael Chan489310a2007-10-10 16:16:31 -07004810 old_port = bp->phy_port;
Michael Chan7c62e832008-07-14 22:39:03 -07004811 bnx2_init_fw_cap(bp);
Michael Chan583c28e2008-01-21 19:51:35 -08004812 if ((bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP) &&
4813 old_port != bp->phy_port)
Michael Chan0d8a6572007-07-07 22:49:43 -07004814 bnx2_set_default_remote_link(bp);
4815 spin_unlock_bh(&bp->phy_lock);
4816
Michael Chan4ce45e02012-12-06 10:33:10 +00004817 if (BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5706_A0) {
Michael Chanb6016b72005-05-26 13:03:09 -07004818 /* Adjust the voltage regular to two steps lower. The default
4819 * of this register is 0x0000000e. */
Michael Chane503e062012-12-06 10:33:08 +00004820 BNX2_WR(bp, BNX2_MISC_VREG_CONTROL, 0x000000fa);
Michael Chanb6016b72005-05-26 13:03:09 -07004821
4822 /* Remove bad rbuf memory from the free pool. */
4823 rc = bnx2_alloc_bad_rbuf(bp);
4824 }
4825
Michael Chanc441b8d2010-04-27 11:28:09 +00004826 if (bp->flags & BNX2_FLAG_USING_MSIX) {
Michael Chanb4b36042007-12-20 19:59:30 -08004827 bnx2_setup_msix_tbl(bp);
Michael Chanc441b8d2010-04-27 11:28:09 +00004828 /* Prevent MSIX table reads and write from timing out */
Michael Chane503e062012-12-06 10:33:08 +00004829 BNX2_WR(bp, BNX2_MISC_ECO_HW_CTL,
Michael Chanc441b8d2010-04-27 11:28:09 +00004830 BNX2_MISC_ECO_HW_CTL_LARGE_GRC_TMOUT_EN);
4831 }
Michael Chanb4b36042007-12-20 19:59:30 -08004832
Michael Chanb6016b72005-05-26 13:03:09 -07004833 return rc;
4834}
4835
4836static int
4837bnx2_init_chip(struct bnx2 *bp)
4838{
Michael Chand8026d92008-11-12 16:02:20 -08004839 u32 val, mtu;
Michael Chanb4b36042007-12-20 19:59:30 -08004840 int rc, i;
Michael Chanb6016b72005-05-26 13:03:09 -07004841
4842 /* Make sure the interrupt is not active. */
Michael Chane503e062012-12-06 10:33:08 +00004843 BNX2_WR(bp, BNX2_PCICFG_INT_ACK_CMD, BNX2_PCICFG_INT_ACK_CMD_MASK_INT);
Michael Chanb6016b72005-05-26 13:03:09 -07004844
4845 val = BNX2_DMA_CONFIG_DATA_BYTE_SWAP |
4846 BNX2_DMA_CONFIG_DATA_WORD_SWAP |
4847#ifdef __BIG_ENDIAN
Jeff Garzik6aa20a22006-09-13 13:24:59 -04004848 BNX2_DMA_CONFIG_CNTL_BYTE_SWAP |
Michael Chanb6016b72005-05-26 13:03:09 -07004849#endif
Jeff Garzik6aa20a22006-09-13 13:24:59 -04004850 BNX2_DMA_CONFIG_CNTL_WORD_SWAP |
Michael Chanb6016b72005-05-26 13:03:09 -07004851 DMA_READ_CHANS << 12 |
4852 DMA_WRITE_CHANS << 16;
4853
4854 val |= (0x2 << 20) | (1 << 11);
4855
David S. Millerf86e82f2008-01-21 17:15:40 -08004856 if ((bp->flags & BNX2_FLAG_PCIX) && (bp->bus_speed_mhz == 133))
Michael Chanb6016b72005-05-26 13:03:09 -07004857 val |= (1 << 23);
4858
Michael Chan4ce45e02012-12-06 10:33:10 +00004859 if ((BNX2_CHIP(bp) == BNX2_CHIP_5706) &&
4860 (BNX2_CHIP_ID(bp) != BNX2_CHIP_ID_5706_A0) &&
4861 !(bp->flags & BNX2_FLAG_PCIX))
Michael Chanb6016b72005-05-26 13:03:09 -07004862 val |= BNX2_DMA_CONFIG_CNTL_PING_PONG_DMA;
4863
Michael Chane503e062012-12-06 10:33:08 +00004864 BNX2_WR(bp, BNX2_DMA_CONFIG, val);
Michael Chanb6016b72005-05-26 13:03:09 -07004865
Michael Chan4ce45e02012-12-06 10:33:10 +00004866 if (BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5706_A0) {
Michael Chane503e062012-12-06 10:33:08 +00004867 val = BNX2_RD(bp, BNX2_TDMA_CONFIG);
Michael Chanb6016b72005-05-26 13:03:09 -07004868 val |= BNX2_TDMA_CONFIG_ONE_DMA;
Michael Chane503e062012-12-06 10:33:08 +00004869 BNX2_WR(bp, BNX2_TDMA_CONFIG, val);
Michael Chanb6016b72005-05-26 13:03:09 -07004870 }
4871
David S. Millerf86e82f2008-01-21 17:15:40 -08004872 if (bp->flags & BNX2_FLAG_PCIX) {
Michael Chanb6016b72005-05-26 13:03:09 -07004873 u16 val16;
4874
4875 pci_read_config_word(bp->pdev, bp->pcix_cap + PCI_X_CMD,
4876 &val16);
4877 pci_write_config_word(bp->pdev, bp->pcix_cap + PCI_X_CMD,
4878 val16 & ~PCI_X_CMD_ERO);
4879 }
4880
Michael Chane503e062012-12-06 10:33:08 +00004881 BNX2_WR(bp, BNX2_MISC_ENABLE_SET_BITS,
4882 BNX2_MISC_ENABLE_SET_BITS_HOST_COALESCE_ENABLE |
4883 BNX2_MISC_ENABLE_STATUS_BITS_RX_V2P_ENABLE |
4884 BNX2_MISC_ENABLE_STATUS_BITS_CONTEXT_ENABLE);
Michael Chanb6016b72005-05-26 13:03:09 -07004885
4886 /* Initialize context mapping and zero out the quick contexts. The
4887 * context block must have already been enabled. */
Michael Chan4ce45e02012-12-06 10:33:10 +00004888 if (BNX2_CHIP(bp) == BNX2_CHIP_5709) {
Michael Chan641bdcd2007-06-04 21:22:24 -07004889 rc = bnx2_init_5709_context(bp);
4890 if (rc)
4891 return rc;
4892 } else
Michael Chan59b47d82006-11-19 14:10:45 -08004893 bnx2_init_context(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07004894
Michael Chanfba9fe92006-06-12 22:21:25 -07004895 if ((rc = bnx2_init_cpus(bp)) != 0)
4896 return rc;
4897
Michael Chanb6016b72005-05-26 13:03:09 -07004898 bnx2_init_nvram(bp);
4899
Benjamin Li5fcaed02008-07-14 22:39:52 -07004900 bnx2_set_mac_addr(bp, bp->dev->dev_addr, 0);
Michael Chanb6016b72005-05-26 13:03:09 -07004901
Michael Chane503e062012-12-06 10:33:08 +00004902 val = BNX2_RD(bp, BNX2_MQ_CONFIG);
Michael Chanb6016b72005-05-26 13:03:09 -07004903 val &= ~BNX2_MQ_CONFIG_KNL_BYP_BLK_SIZE;
4904 val |= BNX2_MQ_CONFIG_KNL_BYP_BLK_SIZE_256;
Michael Chan4ce45e02012-12-06 10:33:10 +00004905 if (BNX2_CHIP(bp) == BNX2_CHIP_5709) {
Michael Chan4edd4732009-06-08 18:14:42 -07004906 val |= BNX2_MQ_CONFIG_BIN_MQ_MODE;
Michael Chan4ce45e02012-12-06 10:33:10 +00004907 if (BNX2_CHIP_REV(bp) == BNX2_CHIP_REV_Ax)
Michael Chan4edd4732009-06-08 18:14:42 -07004908 val |= BNX2_MQ_CONFIG_HALT_DIS;
4909 }
Michael Chan68c9f752007-04-24 15:35:53 -07004910
Michael Chane503e062012-12-06 10:33:08 +00004911 BNX2_WR(bp, BNX2_MQ_CONFIG, val);
Michael Chanb6016b72005-05-26 13:03:09 -07004912
4913 val = 0x10000 + (MAX_CID_CNT * MB_KERNEL_CTX_SIZE);
Michael Chane503e062012-12-06 10:33:08 +00004914 BNX2_WR(bp, BNX2_MQ_KNL_BYP_WIND_START, val);
4915 BNX2_WR(bp, BNX2_MQ_KNL_WIND_END, val);
Michael Chanb6016b72005-05-26 13:03:09 -07004916
Michael Chan2bc40782012-12-06 10:33:09 +00004917 val = (BNX2_PAGE_BITS - 8) << 24;
Michael Chane503e062012-12-06 10:33:08 +00004918 BNX2_WR(bp, BNX2_RV2P_CONFIG, val);
Michael Chanb6016b72005-05-26 13:03:09 -07004919
4920 /* Configure page size. */
Michael Chane503e062012-12-06 10:33:08 +00004921 val = BNX2_RD(bp, BNX2_TBDR_CONFIG);
Michael Chanb6016b72005-05-26 13:03:09 -07004922 val &= ~BNX2_TBDR_CONFIG_PAGE_SIZE;
Michael Chan2bc40782012-12-06 10:33:09 +00004923 val |= (BNX2_PAGE_BITS - 8) << 24 | 0x40;
Michael Chane503e062012-12-06 10:33:08 +00004924 BNX2_WR(bp, BNX2_TBDR_CONFIG, val);
Michael Chanb6016b72005-05-26 13:03:09 -07004925
4926 val = bp->mac_addr[0] +
4927 (bp->mac_addr[1] << 8) +
4928 (bp->mac_addr[2] << 16) +
4929 bp->mac_addr[3] +
4930 (bp->mac_addr[4] << 8) +
4931 (bp->mac_addr[5] << 16);
Michael Chane503e062012-12-06 10:33:08 +00004932 BNX2_WR(bp, BNX2_EMAC_BACKOFF_SEED, val);
Michael Chanb6016b72005-05-26 13:03:09 -07004933
4934 /* Program the MTU. Also include 4 bytes for CRC32. */
Michael Chand8026d92008-11-12 16:02:20 -08004935 mtu = bp->dev->mtu;
4936 val = mtu + ETH_HLEN + ETH_FCS_LEN;
Michael Chanb6016b72005-05-26 13:03:09 -07004937 if (val > (MAX_ETHERNET_PACKET_SIZE + 4))
4938 val |= BNX2_EMAC_RX_MTU_SIZE_JUMBO_ENA;
Michael Chane503e062012-12-06 10:33:08 +00004939 BNX2_WR(bp, BNX2_EMAC_RX_MTU_SIZE, val);
Michael Chanb6016b72005-05-26 13:03:09 -07004940
Michael Chand8026d92008-11-12 16:02:20 -08004941 if (mtu < 1500)
4942 mtu = 1500;
4943
4944 bnx2_reg_wr_ind(bp, BNX2_RBUF_CONFIG, BNX2_RBUF_CONFIG_VAL(mtu));
4945 bnx2_reg_wr_ind(bp, BNX2_RBUF_CONFIG2, BNX2_RBUF_CONFIG2_VAL(mtu));
4946 bnx2_reg_wr_ind(bp, BNX2_RBUF_CONFIG3, BNX2_RBUF_CONFIG3_VAL(mtu));
4947
Michael Chan155d5562009-08-21 16:20:43 +00004948 memset(bp->bnx2_napi[0].status_blk.msi, 0, bp->status_stats_size);
Michael Chanb4b36042007-12-20 19:59:30 -08004949 for (i = 0; i < BNX2_MAX_MSIX_VEC; i++)
4950 bp->bnx2_napi[i].last_status_idx = 0;
4951
Michael Chanefba0182008-12-03 00:36:15 -08004952 bp->idle_chk_status_idx = 0xffff;
4953
Michael Chanb6016b72005-05-26 13:03:09 -07004954 bp->rx_mode = BNX2_EMAC_RX_MODE_SORT_MODE;
4955
4956 /* Set up how to generate a link change interrupt. */
Michael Chane503e062012-12-06 10:33:08 +00004957 BNX2_WR(bp, BNX2_EMAC_ATTENTION_ENA, BNX2_EMAC_ATTENTION_ENA_LINK);
Michael Chanb6016b72005-05-26 13:03:09 -07004958
Michael Chane503e062012-12-06 10:33:08 +00004959 BNX2_WR(bp, BNX2_HC_STATUS_ADDR_L,
4960 (u64) bp->status_blk_mapping & 0xffffffff);
4961 BNX2_WR(bp, BNX2_HC_STATUS_ADDR_H, (u64) bp->status_blk_mapping >> 32);
Michael Chanb6016b72005-05-26 13:03:09 -07004962
Michael Chane503e062012-12-06 10:33:08 +00004963 BNX2_WR(bp, BNX2_HC_STATISTICS_ADDR_L,
4964 (u64) bp->stats_blk_mapping & 0xffffffff);
4965 BNX2_WR(bp, BNX2_HC_STATISTICS_ADDR_H,
4966 (u64) bp->stats_blk_mapping >> 32);
Michael Chanb6016b72005-05-26 13:03:09 -07004967
Michael Chane503e062012-12-06 10:33:08 +00004968 BNX2_WR(bp, BNX2_HC_TX_QUICK_CONS_TRIP,
4969 (bp->tx_quick_cons_trip_int << 16) | bp->tx_quick_cons_trip);
Michael Chanb6016b72005-05-26 13:03:09 -07004970
Michael Chane503e062012-12-06 10:33:08 +00004971 BNX2_WR(bp, BNX2_HC_RX_QUICK_CONS_TRIP,
4972 (bp->rx_quick_cons_trip_int << 16) | bp->rx_quick_cons_trip);
Michael Chanb6016b72005-05-26 13:03:09 -07004973
Michael Chane503e062012-12-06 10:33:08 +00004974 BNX2_WR(bp, BNX2_HC_COMP_PROD_TRIP,
4975 (bp->comp_prod_trip_int << 16) | bp->comp_prod_trip);
Michael Chanb6016b72005-05-26 13:03:09 -07004976
Michael Chane503e062012-12-06 10:33:08 +00004977 BNX2_WR(bp, BNX2_HC_TX_TICKS, (bp->tx_ticks_int << 16) | bp->tx_ticks);
Michael Chanb6016b72005-05-26 13:03:09 -07004978
Michael Chane503e062012-12-06 10:33:08 +00004979 BNX2_WR(bp, BNX2_HC_RX_TICKS, (bp->rx_ticks_int << 16) | bp->rx_ticks);
Michael Chanb6016b72005-05-26 13:03:09 -07004980
Michael Chane503e062012-12-06 10:33:08 +00004981 BNX2_WR(bp, BNX2_HC_COM_TICKS,
4982 (bp->com_ticks_int << 16) | bp->com_ticks);
Michael Chanb6016b72005-05-26 13:03:09 -07004983
Michael Chane503e062012-12-06 10:33:08 +00004984 BNX2_WR(bp, BNX2_HC_CMD_TICKS,
4985 (bp->cmd_ticks_int << 16) | bp->cmd_ticks);
Michael Chanb6016b72005-05-26 13:03:09 -07004986
Michael Chan61d9e3f2009-08-21 16:20:46 +00004987 if (bp->flags & BNX2_FLAG_BROKEN_STATS)
Michael Chane503e062012-12-06 10:33:08 +00004988 BNX2_WR(bp, BNX2_HC_STATS_TICKS, 0);
Michael Chan02537b062007-06-04 21:24:07 -07004989 else
Michael Chane503e062012-12-06 10:33:08 +00004990 BNX2_WR(bp, BNX2_HC_STATS_TICKS, bp->stats_ticks);
4991 BNX2_WR(bp, BNX2_HC_STAT_COLLECT_TICKS, 0xbb8); /* 3ms */
Michael Chanb6016b72005-05-26 13:03:09 -07004992
Michael Chan4ce45e02012-12-06 10:33:10 +00004993 if (BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5706_A1)
Michael Chan8e6a72c2007-05-03 13:24:48 -07004994 val = BNX2_HC_CONFIG_COLLECT_STATS;
Michael Chanb6016b72005-05-26 13:03:09 -07004995 else {
Michael Chan8e6a72c2007-05-03 13:24:48 -07004996 val = BNX2_HC_CONFIG_RX_TMR_MODE | BNX2_HC_CONFIG_TX_TMR_MODE |
4997 BNX2_HC_CONFIG_COLLECT_STATS;
Michael Chanb6016b72005-05-26 13:03:09 -07004998 }
4999
Michael Chanefde73a2010-02-15 19:42:07 +00005000 if (bp->flags & BNX2_FLAG_USING_MSIX) {
Michael Chane503e062012-12-06 10:33:08 +00005001 BNX2_WR(bp, BNX2_HC_MSIX_BIT_VECTOR,
5002 BNX2_HC_MSIX_BIT_VECTOR_VAL);
Michael Chanc76c0472007-12-20 20:01:19 -08005003
Michael Chan5e9ad9e2008-06-19 16:43:17 -07005004 val |= BNX2_HC_CONFIG_SB_ADDR_INC_128B;
5005 }
5006
5007 if (bp->flags & BNX2_FLAG_ONE_SHOT_MSI)
Michael Chancf7474a2009-08-21 16:20:48 +00005008 val |= BNX2_HC_CONFIG_ONE_SHOT | BNX2_HC_CONFIG_USE_INT_PARAM;
Michael Chan5e9ad9e2008-06-19 16:43:17 -07005009
Michael Chane503e062012-12-06 10:33:08 +00005010 BNX2_WR(bp, BNX2_HC_CONFIG, val);
Michael Chan5e9ad9e2008-06-19 16:43:17 -07005011
Michael Chan22fa1592010-10-11 16:12:00 -07005012 if (bp->rx_ticks < 25)
5013 bnx2_reg_wr_ind(bp, BNX2_FW_RX_LOW_LATENCY, 1);
5014 else
5015 bnx2_reg_wr_ind(bp, BNX2_FW_RX_LOW_LATENCY, 0);
5016
Michael Chan5e9ad9e2008-06-19 16:43:17 -07005017 for (i = 1; i < bp->irq_nvecs; i++) {
5018 u32 base = ((i - 1) * BNX2_HC_SB_CONFIG_SIZE) +
5019 BNX2_HC_SB_CONFIG_1;
5020
Michael Chane503e062012-12-06 10:33:08 +00005021 BNX2_WR(bp, base,
Michael Chanc76c0472007-12-20 20:01:19 -08005022 BNX2_HC_SB_CONFIG_1_TX_TMR_MODE |
Michael Chan5e9ad9e2008-06-19 16:43:17 -07005023 BNX2_HC_SB_CONFIG_1_RX_TMR_MODE |
Michael Chanc76c0472007-12-20 20:01:19 -08005024 BNX2_HC_SB_CONFIG_1_ONE_SHOT);
5025
Michael Chane503e062012-12-06 10:33:08 +00005026 BNX2_WR(bp, base + BNX2_HC_TX_QUICK_CONS_TRIP_OFF,
Michael Chanc76c0472007-12-20 20:01:19 -08005027 (bp->tx_quick_cons_trip_int << 16) |
5028 bp->tx_quick_cons_trip);
5029
Michael Chane503e062012-12-06 10:33:08 +00005030 BNX2_WR(bp, base + BNX2_HC_TX_TICKS_OFF,
Michael Chanc76c0472007-12-20 20:01:19 -08005031 (bp->tx_ticks_int << 16) | bp->tx_ticks);
5032
Michael Chane503e062012-12-06 10:33:08 +00005033 BNX2_WR(bp, base + BNX2_HC_RX_QUICK_CONS_TRIP_OFF,
5034 (bp->rx_quick_cons_trip_int << 16) |
Michael Chan5e9ad9e2008-06-19 16:43:17 -07005035 bp->rx_quick_cons_trip);
5036
Michael Chane503e062012-12-06 10:33:08 +00005037 BNX2_WR(bp, base + BNX2_HC_RX_TICKS_OFF,
Michael Chan5e9ad9e2008-06-19 16:43:17 -07005038 (bp->rx_ticks_int << 16) | bp->rx_ticks);
Michael Chanc76c0472007-12-20 20:01:19 -08005039 }
5040
Michael Chanb6016b72005-05-26 13:03:09 -07005041 /* Clear internal stats counters. */
Michael Chane503e062012-12-06 10:33:08 +00005042 BNX2_WR(bp, BNX2_HC_COMMAND, BNX2_HC_COMMAND_CLR_STAT_NOW);
Michael Chanb6016b72005-05-26 13:03:09 -07005043
Michael Chane503e062012-12-06 10:33:08 +00005044 BNX2_WR(bp, BNX2_HC_ATTN_BITS_ENABLE, STATUS_ATTN_EVENTS);
Michael Chanb6016b72005-05-26 13:03:09 -07005045
5046 /* Initialize the receive filter. */
5047 bnx2_set_rx_mode(bp->dev);
5048
Michael Chan4ce45e02012-12-06 10:33:10 +00005049 if (BNX2_CHIP(bp) == BNX2_CHIP_5709) {
Michael Chane503e062012-12-06 10:33:08 +00005050 val = BNX2_RD(bp, BNX2_MISC_NEW_CORE_CTL);
Michael Chan0aa38df2007-06-04 21:23:06 -07005051 val |= BNX2_MISC_NEW_CORE_CTL_DMA_ENABLE;
Michael Chane503e062012-12-06 10:33:08 +00005052 BNX2_WR(bp, BNX2_MISC_NEW_CORE_CTL, val);
Michael Chan0aa38df2007-06-04 21:23:06 -07005053 }
Michael Chanb090ae22006-01-23 16:07:10 -08005054 rc = bnx2_fw_sync(bp, BNX2_DRV_MSG_DATA_WAIT2 | BNX2_DRV_MSG_CODE_RESET,
Michael Chana2f13892008-07-14 22:38:23 -07005055 1, 0);
Michael Chanb6016b72005-05-26 13:03:09 -07005056
Michael Chane503e062012-12-06 10:33:08 +00005057 BNX2_WR(bp, BNX2_MISC_ENABLE_SET_BITS, BNX2_MISC_ENABLE_DEFAULT);
5058 BNX2_RD(bp, BNX2_MISC_ENABLE_SET_BITS);
Michael Chanb6016b72005-05-26 13:03:09 -07005059
5060 udelay(20);
5061
Michael Chane503e062012-12-06 10:33:08 +00005062 bp->hc_cmd = BNX2_RD(bp, BNX2_HC_COMMAND);
Michael Chanbf5295b2006-03-23 01:11:56 -08005063
Michael Chanb090ae22006-01-23 16:07:10 -08005064 return rc;
Michael Chanb6016b72005-05-26 13:03:09 -07005065}
5066
Michael Chan59b47d82006-11-19 14:10:45 -08005067static void
Michael Chanc76c0472007-12-20 20:01:19 -08005068bnx2_clear_ring_states(struct bnx2 *bp)
5069{
5070 struct bnx2_napi *bnapi;
Michael Chan35e90102008-06-19 16:37:42 -07005071 struct bnx2_tx_ring_info *txr;
Michael Chanbb4f98a2008-06-19 16:38:19 -07005072 struct bnx2_rx_ring_info *rxr;
Michael Chanc76c0472007-12-20 20:01:19 -08005073 int i;
5074
5075 for (i = 0; i < BNX2_MAX_MSIX_VEC; i++) {
5076 bnapi = &bp->bnx2_napi[i];
Michael Chan35e90102008-06-19 16:37:42 -07005077 txr = &bnapi->tx_ring;
Michael Chanbb4f98a2008-06-19 16:38:19 -07005078 rxr = &bnapi->rx_ring;
Michael Chanc76c0472007-12-20 20:01:19 -08005079
Michael Chan35e90102008-06-19 16:37:42 -07005080 txr->tx_cons = 0;
5081 txr->hw_tx_cons = 0;
Michael Chanbb4f98a2008-06-19 16:38:19 -07005082 rxr->rx_prod_bseq = 0;
5083 rxr->rx_prod = 0;
5084 rxr->rx_cons = 0;
5085 rxr->rx_pg_prod = 0;
5086 rxr->rx_pg_cons = 0;
Michael Chanc76c0472007-12-20 20:01:19 -08005087 }
5088}
5089
5090static void
Michael Chan35e90102008-06-19 16:37:42 -07005091bnx2_init_tx_context(struct bnx2 *bp, u32 cid, struct bnx2_tx_ring_info *txr)
Michael Chan59b47d82006-11-19 14:10:45 -08005092{
5093 u32 val, offset0, offset1, offset2, offset3;
Michael Chan62a83132008-01-29 21:35:40 -08005094 u32 cid_addr = GET_CID_ADDR(cid);
Michael Chan59b47d82006-11-19 14:10:45 -08005095
Michael Chan4ce45e02012-12-06 10:33:10 +00005096 if (BNX2_CHIP(bp) == BNX2_CHIP_5709) {
Michael Chan59b47d82006-11-19 14:10:45 -08005097 offset0 = BNX2_L2CTX_TYPE_XI;
5098 offset1 = BNX2_L2CTX_CMD_TYPE_XI;
5099 offset2 = BNX2_L2CTX_TBDR_BHADDR_HI_XI;
5100 offset3 = BNX2_L2CTX_TBDR_BHADDR_LO_XI;
5101 } else {
5102 offset0 = BNX2_L2CTX_TYPE;
5103 offset1 = BNX2_L2CTX_CMD_TYPE;
5104 offset2 = BNX2_L2CTX_TBDR_BHADDR_HI;
5105 offset3 = BNX2_L2CTX_TBDR_BHADDR_LO;
5106 }
5107 val = BNX2_L2CTX_TYPE_TYPE_L2 | BNX2_L2CTX_TYPE_SIZE_L2;
Michael Chan62a83132008-01-29 21:35:40 -08005108 bnx2_ctx_wr(bp, cid_addr, offset0, val);
Michael Chan59b47d82006-11-19 14:10:45 -08005109
5110 val = BNX2_L2CTX_CMD_TYPE_TYPE_L2 | (8 << 16);
Michael Chan62a83132008-01-29 21:35:40 -08005111 bnx2_ctx_wr(bp, cid_addr, offset1, val);
Michael Chan59b47d82006-11-19 14:10:45 -08005112
Michael Chan35e90102008-06-19 16:37:42 -07005113 val = (u64) txr->tx_desc_mapping >> 32;
Michael Chan62a83132008-01-29 21:35:40 -08005114 bnx2_ctx_wr(bp, cid_addr, offset2, val);
Michael Chan59b47d82006-11-19 14:10:45 -08005115
Michael Chan35e90102008-06-19 16:37:42 -07005116 val = (u64) txr->tx_desc_mapping & 0xffffffff;
Michael Chan62a83132008-01-29 21:35:40 -08005117 bnx2_ctx_wr(bp, cid_addr, offset3, val);
Michael Chan59b47d82006-11-19 14:10:45 -08005118}
Michael Chanb6016b72005-05-26 13:03:09 -07005119
5120static void
Michael Chan35e90102008-06-19 16:37:42 -07005121bnx2_init_tx_ring(struct bnx2 *bp, int ring_num)
Michael Chanb6016b72005-05-26 13:03:09 -07005122{
Michael Chan2bc40782012-12-06 10:33:09 +00005123 struct bnx2_tx_bd *txbd;
Michael Chanc76c0472007-12-20 20:01:19 -08005124 u32 cid = TX_CID;
5125 struct bnx2_napi *bnapi;
Michael Chan35e90102008-06-19 16:37:42 -07005126 struct bnx2_tx_ring_info *txr;
Michael Chanc76c0472007-12-20 20:01:19 -08005127
Michael Chan35e90102008-06-19 16:37:42 -07005128 bnapi = &bp->bnx2_napi[ring_num];
5129 txr = &bnapi->tx_ring;
5130
5131 if (ring_num == 0)
5132 cid = TX_CID;
5133 else
5134 cid = TX_TSS_CID + ring_num - 1;
Michael Chanb6016b72005-05-26 13:03:09 -07005135
Michael Chan2f8af122006-08-15 01:39:10 -07005136 bp->tx_wake_thresh = bp->tx_ring_size / 2;
5137
Michael Chan2bc40782012-12-06 10:33:09 +00005138 txbd = &txr->tx_desc_ring[BNX2_MAX_TX_DESC_CNT];
Jeff Garzik6aa20a22006-09-13 13:24:59 -04005139
Michael Chan35e90102008-06-19 16:37:42 -07005140 txbd->tx_bd_haddr_hi = (u64) txr->tx_desc_mapping >> 32;
5141 txbd->tx_bd_haddr_lo = (u64) txr->tx_desc_mapping & 0xffffffff;
Michael Chanb6016b72005-05-26 13:03:09 -07005142
Michael Chan35e90102008-06-19 16:37:42 -07005143 txr->tx_prod = 0;
5144 txr->tx_prod_bseq = 0;
Jeff Garzik6aa20a22006-09-13 13:24:59 -04005145
Michael Chan35e90102008-06-19 16:37:42 -07005146 txr->tx_bidx_addr = MB_GET_CID_ADDR(cid) + BNX2_L2CTX_TX_HOST_BIDX;
5147 txr->tx_bseq_addr = MB_GET_CID_ADDR(cid) + BNX2_L2CTX_TX_HOST_BSEQ;
Michael Chanb6016b72005-05-26 13:03:09 -07005148
Michael Chan35e90102008-06-19 16:37:42 -07005149 bnx2_init_tx_context(bp, cid, txr);
Michael Chanb6016b72005-05-26 13:03:09 -07005150}
5151
5152static void
Michael Chan2bc40782012-12-06 10:33:09 +00005153bnx2_init_rxbd_rings(struct bnx2_rx_bd *rx_ring[], dma_addr_t dma[],
5154 u32 buf_size, int num_rings)
Michael Chanb6016b72005-05-26 13:03:09 -07005155{
Michael Chanb6016b72005-05-26 13:03:09 -07005156 int i;
Michael Chan2bc40782012-12-06 10:33:09 +00005157 struct bnx2_rx_bd *rxbd;
Michael Chanb6016b72005-05-26 13:03:09 -07005158
Michael Chan5d5d0012007-12-12 11:17:43 -08005159 for (i = 0; i < num_rings; i++) {
Michael Chan13daffa2006-03-20 17:49:20 -08005160 int j;
Michael Chanb6016b72005-05-26 13:03:09 -07005161
Michael Chan5d5d0012007-12-12 11:17:43 -08005162 rxbd = &rx_ring[i][0];
Michael Chan2bc40782012-12-06 10:33:09 +00005163 for (j = 0; j < BNX2_MAX_RX_DESC_CNT; j++, rxbd++) {
Michael Chan5d5d0012007-12-12 11:17:43 -08005164 rxbd->rx_bd_len = buf_size;
Michael Chan13daffa2006-03-20 17:49:20 -08005165 rxbd->rx_bd_flags = RX_BD_FLAGS_START | RX_BD_FLAGS_END;
5166 }
Michael Chan5d5d0012007-12-12 11:17:43 -08005167 if (i == (num_rings - 1))
Michael Chan13daffa2006-03-20 17:49:20 -08005168 j = 0;
5169 else
5170 j = i + 1;
Michael Chan5d5d0012007-12-12 11:17:43 -08005171 rxbd->rx_bd_haddr_hi = (u64) dma[j] >> 32;
5172 rxbd->rx_bd_haddr_lo = (u64) dma[j] & 0xffffffff;
Michael Chan13daffa2006-03-20 17:49:20 -08005173 }
Michael Chan5d5d0012007-12-12 11:17:43 -08005174}
5175
5176static void
Michael Chanbb4f98a2008-06-19 16:38:19 -07005177bnx2_init_rx_ring(struct bnx2 *bp, int ring_num)
Michael Chan5d5d0012007-12-12 11:17:43 -08005178{
5179 int i;
5180 u16 prod, ring_prod;
Michael Chanbb4f98a2008-06-19 16:38:19 -07005181 u32 cid, rx_cid_addr, val;
5182 struct bnx2_napi *bnapi = &bp->bnx2_napi[ring_num];
5183 struct bnx2_rx_ring_info *rxr = &bnapi->rx_ring;
Michael Chan5d5d0012007-12-12 11:17:43 -08005184
Michael Chanbb4f98a2008-06-19 16:38:19 -07005185 if (ring_num == 0)
5186 cid = RX_CID;
5187 else
5188 cid = RX_RSS_CID + ring_num - 1;
5189
5190 rx_cid_addr = GET_CID_ADDR(cid);
5191
5192 bnx2_init_rxbd_rings(rxr->rx_desc_ring, rxr->rx_desc_mapping,
Michael Chan5d5d0012007-12-12 11:17:43 -08005193 bp->rx_buf_use_size, bp->rx_max_ring);
5194
Michael Chanbb4f98a2008-06-19 16:38:19 -07005195 bnx2_init_rx_context(bp, cid);
Michael Chan83e3fc82008-01-29 21:37:17 -08005196
Michael Chan4ce45e02012-12-06 10:33:10 +00005197 if (BNX2_CHIP(bp) == BNX2_CHIP_5709) {
Michael Chane503e062012-12-06 10:33:08 +00005198 val = BNX2_RD(bp, BNX2_MQ_MAP_L2_5);
5199 BNX2_WR(bp, BNX2_MQ_MAP_L2_5, val | BNX2_MQ_MAP_L2_5_ARM);
Michael Chan83e3fc82008-01-29 21:37:17 -08005200 }
5201
Michael Chan62a83132008-01-29 21:35:40 -08005202 bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_PG_BUF_SIZE, 0);
Michael Chan47bf4242007-12-12 11:19:12 -08005203 if (bp->rx_pg_ring_size) {
Michael Chanbb4f98a2008-06-19 16:38:19 -07005204 bnx2_init_rxbd_rings(rxr->rx_pg_desc_ring,
5205 rxr->rx_pg_desc_mapping,
Michael Chan47bf4242007-12-12 11:19:12 -08005206 PAGE_SIZE, bp->rx_max_pg_ring);
5207 val = (bp->rx_buf_use_size << 16) | PAGE_SIZE;
Michael Chan62a83132008-01-29 21:35:40 -08005208 bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_PG_BUF_SIZE, val);
5209 bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_RBDC_KEY,
Michael Chan5e9ad9e2008-06-19 16:43:17 -07005210 BNX2_L2CTX_RBDC_JUMBO_KEY - ring_num);
Michael Chan47bf4242007-12-12 11:19:12 -08005211
Michael Chanbb4f98a2008-06-19 16:38:19 -07005212 val = (u64) rxr->rx_pg_desc_mapping[0] >> 32;
Michael Chan62a83132008-01-29 21:35:40 -08005213 bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_NX_PG_BDHADDR_HI, val);
Michael Chan47bf4242007-12-12 11:19:12 -08005214
Michael Chanbb4f98a2008-06-19 16:38:19 -07005215 val = (u64) rxr->rx_pg_desc_mapping[0] & 0xffffffff;
Michael Chan62a83132008-01-29 21:35:40 -08005216 bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_NX_PG_BDHADDR_LO, val);
Michael Chan47bf4242007-12-12 11:19:12 -08005217
Michael Chan4ce45e02012-12-06 10:33:10 +00005218 if (BNX2_CHIP(bp) == BNX2_CHIP_5709)
Michael Chane503e062012-12-06 10:33:08 +00005219 BNX2_WR(bp, BNX2_MQ_MAP_L2_3, BNX2_MQ_MAP_L2_3_DEFAULT);
Michael Chan47bf4242007-12-12 11:19:12 -08005220 }
Michael Chanb6016b72005-05-26 13:03:09 -07005221
Michael Chanbb4f98a2008-06-19 16:38:19 -07005222 val = (u64) rxr->rx_desc_mapping[0] >> 32;
Michael Chan62a83132008-01-29 21:35:40 -08005223 bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_NX_BDHADDR_HI, val);
Michael Chanb6016b72005-05-26 13:03:09 -07005224
Michael Chanbb4f98a2008-06-19 16:38:19 -07005225 val = (u64) rxr->rx_desc_mapping[0] & 0xffffffff;
Michael Chan62a83132008-01-29 21:35:40 -08005226 bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_NX_BDHADDR_LO, val);
Michael Chanb6016b72005-05-26 13:03:09 -07005227
Michael Chanbb4f98a2008-06-19 16:38:19 -07005228 ring_prod = prod = rxr->rx_pg_prod;
Michael Chan47bf4242007-12-12 11:19:12 -08005229 for (i = 0; i < bp->rx_pg_ring_size; i++) {
Stanislaw Gruszkaa2df00a2010-07-15 22:55:40 +00005230 if (bnx2_alloc_rx_page(bp, rxr, ring_prod, GFP_KERNEL) < 0) {
Joe Perches3a9c6a42010-02-17 15:01:51 +00005231 netdev_warn(bp->dev, "init'ed rx page ring %d with %d/%d pages only\n",
5232 ring_num, i, bp->rx_pg_ring_size);
Michael Chan47bf4242007-12-12 11:19:12 -08005233 break;
Michael Chanb929e532009-12-03 09:46:33 +00005234 }
Michael Chan2bc40782012-12-06 10:33:09 +00005235 prod = BNX2_NEXT_RX_BD(prod);
5236 ring_prod = BNX2_RX_PG_RING_IDX(prod);
Michael Chan47bf4242007-12-12 11:19:12 -08005237 }
Michael Chanbb4f98a2008-06-19 16:38:19 -07005238 rxr->rx_pg_prod = prod;
Michael Chan47bf4242007-12-12 11:19:12 -08005239
Michael Chanbb4f98a2008-06-19 16:38:19 -07005240 ring_prod = prod = rxr->rx_prod;
Michael Chan236b6392006-03-20 17:49:02 -08005241 for (i = 0; i < bp->rx_ring_size; i++) {
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00005242 if (bnx2_alloc_rx_data(bp, rxr, ring_prod, GFP_KERNEL) < 0) {
Joe Perches3a9c6a42010-02-17 15:01:51 +00005243 netdev_warn(bp->dev, "init'ed rx ring %d with %d/%d skbs only\n",
5244 ring_num, i, bp->rx_ring_size);
Michael Chanb6016b72005-05-26 13:03:09 -07005245 break;
Michael Chanb929e532009-12-03 09:46:33 +00005246 }
Michael Chan2bc40782012-12-06 10:33:09 +00005247 prod = BNX2_NEXT_RX_BD(prod);
5248 ring_prod = BNX2_RX_RING_IDX(prod);
Michael Chanb6016b72005-05-26 13:03:09 -07005249 }
Michael Chanbb4f98a2008-06-19 16:38:19 -07005250 rxr->rx_prod = prod;
Michael Chanb6016b72005-05-26 13:03:09 -07005251
Michael Chanbb4f98a2008-06-19 16:38:19 -07005252 rxr->rx_bidx_addr = MB_GET_CID_ADDR(cid) + BNX2_L2CTX_HOST_BDIDX;
5253 rxr->rx_bseq_addr = MB_GET_CID_ADDR(cid) + BNX2_L2CTX_HOST_BSEQ;
5254 rxr->rx_pg_bidx_addr = MB_GET_CID_ADDR(cid) + BNX2_L2CTX_HOST_PG_BDIDX;
Michael Chanb6016b72005-05-26 13:03:09 -07005255
Michael Chane503e062012-12-06 10:33:08 +00005256 BNX2_WR16(bp, rxr->rx_pg_bidx_addr, rxr->rx_pg_prod);
5257 BNX2_WR16(bp, rxr->rx_bidx_addr, prod);
Michael Chanbb4f98a2008-06-19 16:38:19 -07005258
Michael Chane503e062012-12-06 10:33:08 +00005259 BNX2_WR(bp, rxr->rx_bseq_addr, rxr->rx_prod_bseq);
Michael Chanb6016b72005-05-26 13:03:09 -07005260}
5261
Michael Chan35e90102008-06-19 16:37:42 -07005262static void
5263bnx2_init_all_rings(struct bnx2 *bp)
5264{
5265 int i;
Michael Chan5e9ad9e2008-06-19 16:43:17 -07005266 u32 val;
Michael Chan35e90102008-06-19 16:37:42 -07005267
5268 bnx2_clear_ring_states(bp);
5269
Michael Chane503e062012-12-06 10:33:08 +00005270 BNX2_WR(bp, BNX2_TSCH_TSS_CFG, 0);
Michael Chan35e90102008-06-19 16:37:42 -07005271 for (i = 0; i < bp->num_tx_rings; i++)
5272 bnx2_init_tx_ring(bp, i);
5273
5274 if (bp->num_tx_rings > 1)
Michael Chane503e062012-12-06 10:33:08 +00005275 BNX2_WR(bp, BNX2_TSCH_TSS_CFG, ((bp->num_tx_rings - 1) << 24) |
5276 (TX_TSS_CID << 7));
Michael Chan35e90102008-06-19 16:37:42 -07005277
Michael Chane503e062012-12-06 10:33:08 +00005278 BNX2_WR(bp, BNX2_RLUP_RSS_CONFIG, 0);
Michael Chan5e9ad9e2008-06-19 16:43:17 -07005279 bnx2_reg_wr_ind(bp, BNX2_RXP_SCRATCH_RSS_TBL_SZ, 0);
5280
Michael Chanbb4f98a2008-06-19 16:38:19 -07005281 for (i = 0; i < bp->num_rx_rings; i++)
5282 bnx2_init_rx_ring(bp, i);
Michael Chan5e9ad9e2008-06-19 16:43:17 -07005283
5284 if (bp->num_rx_rings > 1) {
Michael Chan22fa1592010-10-11 16:12:00 -07005285 u32 tbl_32 = 0;
Michael Chan5e9ad9e2008-06-19 16:43:17 -07005286
5287 for (i = 0; i < BNX2_RXP_SCRATCH_RSS_TBL_MAX_ENTRIES; i++) {
Michael Chan22fa1592010-10-11 16:12:00 -07005288 int shift = (i % 8) << 2;
5289
5290 tbl_32 |= (i % (bp->num_rx_rings - 1)) << shift;
5291 if ((i % 8) == 7) {
Michael Chane503e062012-12-06 10:33:08 +00005292 BNX2_WR(bp, BNX2_RLUP_RSS_DATA, tbl_32);
5293 BNX2_WR(bp, BNX2_RLUP_RSS_COMMAND, (i >> 3) |
Michael Chan22fa1592010-10-11 16:12:00 -07005294 BNX2_RLUP_RSS_COMMAND_RSS_WRITE_MASK |
5295 BNX2_RLUP_RSS_COMMAND_WRITE |
5296 BNX2_RLUP_RSS_COMMAND_HASH_MASK);
5297 tbl_32 = 0;
5298 }
Michael Chan5e9ad9e2008-06-19 16:43:17 -07005299 }
5300
5301 val = BNX2_RLUP_RSS_CONFIG_IPV4_RSS_TYPE_ALL_XI |
5302 BNX2_RLUP_RSS_CONFIG_IPV6_RSS_TYPE_ALL_XI;
5303
Michael Chane503e062012-12-06 10:33:08 +00005304 BNX2_WR(bp, BNX2_RLUP_RSS_CONFIG, val);
Michael Chan5e9ad9e2008-06-19 16:43:17 -07005305
5306 }
Michael Chan35e90102008-06-19 16:37:42 -07005307}
5308
Michael Chan5d5d0012007-12-12 11:17:43 -08005309static u32 bnx2_find_max_ring(u32 ring_size, u32 max_size)
Michael Chan13daffa2006-03-20 17:49:20 -08005310{
Michael Chan5d5d0012007-12-12 11:17:43 -08005311 u32 max, num_rings = 1;
Michael Chan13daffa2006-03-20 17:49:20 -08005312
Michael Chan2bc40782012-12-06 10:33:09 +00005313 while (ring_size > BNX2_MAX_RX_DESC_CNT) {
5314 ring_size -= BNX2_MAX_RX_DESC_CNT;
Michael Chan13daffa2006-03-20 17:49:20 -08005315 num_rings++;
5316 }
5317 /* round to next power of 2 */
Michael Chan5d5d0012007-12-12 11:17:43 -08005318 max = max_size;
Michael Chan13daffa2006-03-20 17:49:20 -08005319 while ((max & num_rings) == 0)
5320 max >>= 1;
5321
5322 if (num_rings != max)
5323 max <<= 1;
5324
Michael Chan5d5d0012007-12-12 11:17:43 -08005325 return max;
5326}
5327
5328static void
5329bnx2_set_rx_ring_size(struct bnx2 *bp, u32 size)
5330{
Michael Chan84eaa182007-12-12 11:19:57 -08005331 u32 rx_size, rx_space, jumbo_size;
Michael Chan5d5d0012007-12-12 11:17:43 -08005332
5333 /* 8 for CRC and VLAN */
Benjamin Lid89cb6a2008-05-16 22:18:57 -07005334 rx_size = bp->dev->mtu + ETH_HLEN + BNX2_RX_OFFSET + 8;
Michael Chan5d5d0012007-12-12 11:17:43 -08005335
Michael Chan84eaa182007-12-12 11:19:57 -08005336 rx_space = SKB_DATA_ALIGN(rx_size + BNX2_RX_ALIGN) + NET_SKB_PAD +
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00005337 SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
Michael Chan84eaa182007-12-12 11:19:57 -08005338
Benjamin Li601d3d12008-05-16 22:19:35 -07005339 bp->rx_copy_thresh = BNX2_RX_COPY_THRESH;
Michael Chan47bf4242007-12-12 11:19:12 -08005340 bp->rx_pg_ring_size = 0;
5341 bp->rx_max_pg_ring = 0;
5342 bp->rx_max_pg_ring_idx = 0;
David S. Millerf86e82f2008-01-21 17:15:40 -08005343 if ((rx_space > PAGE_SIZE) && !(bp->flags & BNX2_FLAG_JUMBO_BROKEN)) {
Michael Chan84eaa182007-12-12 11:19:57 -08005344 int pages = PAGE_ALIGN(bp->dev->mtu - 40) >> PAGE_SHIFT;
5345
5346 jumbo_size = size * pages;
Michael Chan2bc40782012-12-06 10:33:09 +00005347 if (jumbo_size > BNX2_MAX_TOTAL_RX_PG_DESC_CNT)
5348 jumbo_size = BNX2_MAX_TOTAL_RX_PG_DESC_CNT;
Michael Chan84eaa182007-12-12 11:19:57 -08005349
5350 bp->rx_pg_ring_size = jumbo_size;
5351 bp->rx_max_pg_ring = bnx2_find_max_ring(jumbo_size,
Michael Chan2bc40782012-12-06 10:33:09 +00005352 BNX2_MAX_RX_PG_RINGS);
5353 bp->rx_max_pg_ring_idx =
5354 (bp->rx_max_pg_ring * BNX2_RX_DESC_CNT) - 1;
Benjamin Li601d3d12008-05-16 22:19:35 -07005355 rx_size = BNX2_RX_COPY_THRESH + BNX2_RX_OFFSET;
Michael Chan84eaa182007-12-12 11:19:57 -08005356 bp->rx_copy_thresh = 0;
5357 }
Michael Chan5d5d0012007-12-12 11:17:43 -08005358
5359 bp->rx_buf_use_size = rx_size;
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00005360 /* hw alignment + build_skb() overhead*/
5361 bp->rx_buf_size = SKB_DATA_ALIGN(bp->rx_buf_use_size + BNX2_RX_ALIGN) +
5362 NET_SKB_PAD + SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
Benjamin Lid89cb6a2008-05-16 22:18:57 -07005363 bp->rx_jumbo_thresh = rx_size - BNX2_RX_OFFSET;
Michael Chan5d5d0012007-12-12 11:17:43 -08005364 bp->rx_ring_size = size;
Michael Chan2bc40782012-12-06 10:33:09 +00005365 bp->rx_max_ring = bnx2_find_max_ring(size, BNX2_MAX_RX_RINGS);
5366 bp->rx_max_ring_idx = (bp->rx_max_ring * BNX2_RX_DESC_CNT) - 1;
Michael Chan13daffa2006-03-20 17:49:20 -08005367}
5368
5369static void
Michael Chanb6016b72005-05-26 13:03:09 -07005370bnx2_free_tx_skbs(struct bnx2 *bp)
5371{
5372 int i;
5373
Michael Chan35e90102008-06-19 16:37:42 -07005374 for (i = 0; i < bp->num_tx_rings; i++) {
5375 struct bnx2_napi *bnapi = &bp->bnx2_napi[i];
5376 struct bnx2_tx_ring_info *txr = &bnapi->tx_ring;
5377 int j;
Michael Chanb6016b72005-05-26 13:03:09 -07005378
Michael Chan35e90102008-06-19 16:37:42 -07005379 if (txr->tx_buf_ring == NULL)
Michael Chanb6016b72005-05-26 13:03:09 -07005380 continue;
Michael Chanb6016b72005-05-26 13:03:09 -07005381
Michael Chan2bc40782012-12-06 10:33:09 +00005382 for (j = 0; j < BNX2_TX_DESC_CNT; ) {
5383 struct bnx2_sw_tx_bd *tx_buf = &txr->tx_buf_ring[j];
Michael Chan35e90102008-06-19 16:37:42 -07005384 struct sk_buff *skb = tx_buf->skb;
Alexander Duycke95524a2009-12-02 16:47:57 +00005385 int k, last;
Michael Chan35e90102008-06-19 16:37:42 -07005386
5387 if (skb == NULL) {
Michael Chan2bc40782012-12-06 10:33:09 +00005388 j = BNX2_NEXT_TX_BD(j);
Michael Chan35e90102008-06-19 16:37:42 -07005389 continue;
5390 }
5391
Stanislaw Gruszka36227e82010-07-15 04:25:50 +00005392 dma_unmap_single(&bp->pdev->dev,
FUJITA Tomonori1a4ccc22010-04-01 16:56:57 +00005393 dma_unmap_addr(tx_buf, mapping),
Alexander Duycke95524a2009-12-02 16:47:57 +00005394 skb_headlen(skb),
5395 PCI_DMA_TODEVICE);
Michael Chanb6016b72005-05-26 13:03:09 -07005396
Michael Chan35e90102008-06-19 16:37:42 -07005397 tx_buf->skb = NULL;
Michael Chanb6016b72005-05-26 13:03:09 -07005398
Alexander Duycke95524a2009-12-02 16:47:57 +00005399 last = tx_buf->nr_frags;
Michael Chan2bc40782012-12-06 10:33:09 +00005400 j = BNX2_NEXT_TX_BD(j);
5401 for (k = 0; k < last; k++, j = BNX2_NEXT_TX_BD(j)) {
5402 tx_buf = &txr->tx_buf_ring[BNX2_TX_RING_IDX(j)];
Stanislaw Gruszka36227e82010-07-15 04:25:50 +00005403 dma_unmap_page(&bp->pdev->dev,
FUJITA Tomonori1a4ccc22010-04-01 16:56:57 +00005404 dma_unmap_addr(tx_buf, mapping),
Eric Dumazet9e903e02011-10-18 21:00:24 +00005405 skb_frag_size(&skb_shinfo(skb)->frags[k]),
Alexander Duycke95524a2009-12-02 16:47:57 +00005406 PCI_DMA_TODEVICE);
5407 }
Michael Chan35e90102008-06-19 16:37:42 -07005408 dev_kfree_skb(skb);
Michael Chanb6016b72005-05-26 13:03:09 -07005409 }
Eric Dumazete9831902011-11-29 11:53:05 +00005410 netdev_tx_reset_queue(netdev_get_tx_queue(bp->dev, i));
Michael Chanb6016b72005-05-26 13:03:09 -07005411 }
Michael Chanb6016b72005-05-26 13:03:09 -07005412}
5413
5414static void
5415bnx2_free_rx_skbs(struct bnx2 *bp)
5416{
5417 int i;
5418
Michael Chanbb4f98a2008-06-19 16:38:19 -07005419 for (i = 0; i < bp->num_rx_rings; i++) {
5420 struct bnx2_napi *bnapi = &bp->bnx2_napi[i];
5421 struct bnx2_rx_ring_info *rxr = &bnapi->rx_ring;
5422 int j;
Michael Chanb6016b72005-05-26 13:03:09 -07005423
Michael Chanbb4f98a2008-06-19 16:38:19 -07005424 if (rxr->rx_buf_ring == NULL)
5425 return;
Michael Chanb6016b72005-05-26 13:03:09 -07005426
Michael Chanbb4f98a2008-06-19 16:38:19 -07005427 for (j = 0; j < bp->rx_max_ring_idx; j++) {
Michael Chan2bc40782012-12-06 10:33:09 +00005428 struct bnx2_sw_bd *rx_buf = &rxr->rx_buf_ring[j];
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00005429 u8 *data = rx_buf->data;
Michael Chanb6016b72005-05-26 13:03:09 -07005430
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00005431 if (data == NULL)
Michael Chanbb4f98a2008-06-19 16:38:19 -07005432 continue;
Michael Chanb6016b72005-05-26 13:03:09 -07005433
Stanislaw Gruszka36227e82010-07-15 04:25:50 +00005434 dma_unmap_single(&bp->pdev->dev,
FUJITA Tomonori1a4ccc22010-04-01 16:56:57 +00005435 dma_unmap_addr(rx_buf, mapping),
Michael Chanbb4f98a2008-06-19 16:38:19 -07005436 bp->rx_buf_use_size,
5437 PCI_DMA_FROMDEVICE);
Michael Chanb6016b72005-05-26 13:03:09 -07005438
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00005439 rx_buf->data = NULL;
Michael Chanbb4f98a2008-06-19 16:38:19 -07005440
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00005441 kfree(data);
Michael Chanbb4f98a2008-06-19 16:38:19 -07005442 }
5443 for (j = 0; j < bp->rx_max_pg_ring_idx; j++)
5444 bnx2_free_rx_page(bp, rxr, j);
Michael Chanb6016b72005-05-26 13:03:09 -07005445 }
5446}
5447
5448static void
5449bnx2_free_skbs(struct bnx2 *bp)
5450{
5451 bnx2_free_tx_skbs(bp);
5452 bnx2_free_rx_skbs(bp);
5453}
5454
5455static int
5456bnx2_reset_nic(struct bnx2 *bp, u32 reset_code)
5457{
5458 int rc;
5459
5460 rc = bnx2_reset_chip(bp, reset_code);
5461 bnx2_free_skbs(bp);
5462 if (rc)
5463 return rc;
5464
Michael Chanfba9fe92006-06-12 22:21:25 -07005465 if ((rc = bnx2_init_chip(bp)) != 0)
5466 return rc;
5467
Michael Chan35e90102008-06-19 16:37:42 -07005468 bnx2_init_all_rings(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07005469 return 0;
5470}
5471
5472static int
Michael Chan9a120bc2008-05-16 22:17:45 -07005473bnx2_init_nic(struct bnx2 *bp, int reset_phy)
Michael Chanb6016b72005-05-26 13:03:09 -07005474{
5475 int rc;
5476
5477 if ((rc = bnx2_reset_nic(bp, BNX2_DRV_MSG_CODE_RESET)) != 0)
5478 return rc;
5479
Michael Chan80be4432006-11-19 14:07:28 -08005480 spin_lock_bh(&bp->phy_lock);
Michael Chan9a120bc2008-05-16 22:17:45 -07005481 bnx2_init_phy(bp, reset_phy);
Michael Chanb6016b72005-05-26 13:03:09 -07005482 bnx2_set_link(bp);
Michael Chan543a8272008-05-02 16:56:44 -07005483 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
5484 bnx2_remote_phy_event(bp);
Michael Chan0d8a6572007-07-07 22:49:43 -07005485 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07005486 return 0;
5487}
5488
5489static int
Michael Chan74bf4ba2008-10-09 12:21:08 -07005490bnx2_shutdown_chip(struct bnx2 *bp)
5491{
5492 u32 reset_code;
5493
5494 if (bp->flags & BNX2_FLAG_NO_WOL)
5495 reset_code = BNX2_DRV_MSG_CODE_UNLOAD_LNK_DN;
5496 else if (bp->wol)
5497 reset_code = BNX2_DRV_MSG_CODE_SUSPEND_WOL;
5498 else
5499 reset_code = BNX2_DRV_MSG_CODE_SUSPEND_NO_WOL;
5500
5501 return bnx2_reset_chip(bp, reset_code);
5502}
5503
5504static int
Michael Chanb6016b72005-05-26 13:03:09 -07005505bnx2_test_registers(struct bnx2 *bp)
5506{
5507 int ret;
Michael Chan5bae30c2007-05-03 13:18:46 -07005508 int i, is_5709;
Arjan van de Venf71e1302006-03-03 21:33:57 -05005509 static const struct {
Michael Chanb6016b72005-05-26 13:03:09 -07005510 u16 offset;
5511 u16 flags;
Michael Chan5bae30c2007-05-03 13:18:46 -07005512#define BNX2_FL_NOT_5709 1
Michael Chanb6016b72005-05-26 13:03:09 -07005513 u32 rw_mask;
5514 u32 ro_mask;
5515 } reg_tbl[] = {
5516 { 0x006c, 0, 0x00000000, 0x0000003f },
5517 { 0x0090, 0, 0xffffffff, 0x00000000 },
5518 { 0x0094, 0, 0x00000000, 0x00000000 },
5519
Michael Chan5bae30c2007-05-03 13:18:46 -07005520 { 0x0404, BNX2_FL_NOT_5709, 0x00003f00, 0x00000000 },
5521 { 0x0418, BNX2_FL_NOT_5709, 0x00000000, 0xffffffff },
5522 { 0x041c, BNX2_FL_NOT_5709, 0x00000000, 0xffffffff },
5523 { 0x0420, BNX2_FL_NOT_5709, 0x00000000, 0x80ffffff },
5524 { 0x0424, BNX2_FL_NOT_5709, 0x00000000, 0x00000000 },
5525 { 0x0428, BNX2_FL_NOT_5709, 0x00000000, 0x00000001 },
5526 { 0x0450, BNX2_FL_NOT_5709, 0x00000000, 0x0000ffff },
5527 { 0x0454, BNX2_FL_NOT_5709, 0x00000000, 0xffffffff },
5528 { 0x0458, BNX2_FL_NOT_5709, 0x00000000, 0xffffffff },
Michael Chanb6016b72005-05-26 13:03:09 -07005529
Michael Chan5bae30c2007-05-03 13:18:46 -07005530 { 0x0808, BNX2_FL_NOT_5709, 0x00000000, 0xffffffff },
5531 { 0x0854, BNX2_FL_NOT_5709, 0x00000000, 0xffffffff },
5532 { 0x0868, BNX2_FL_NOT_5709, 0x00000000, 0x77777777 },
5533 { 0x086c, BNX2_FL_NOT_5709, 0x00000000, 0x77777777 },
5534 { 0x0870, BNX2_FL_NOT_5709, 0x00000000, 0x77777777 },
5535 { 0x0874, BNX2_FL_NOT_5709, 0x00000000, 0x77777777 },
Michael Chanb6016b72005-05-26 13:03:09 -07005536
Michael Chan5bae30c2007-05-03 13:18:46 -07005537 { 0x0c00, BNX2_FL_NOT_5709, 0x00000000, 0x00000001 },
5538 { 0x0c04, BNX2_FL_NOT_5709, 0x00000000, 0x03ff0001 },
5539 { 0x0c08, BNX2_FL_NOT_5709, 0x0f0ff073, 0x00000000 },
Michael Chanb6016b72005-05-26 13:03:09 -07005540
5541 { 0x1000, 0, 0x00000000, 0x00000001 },
Michael Chan15b169c2008-05-02 16:57:08 -07005542 { 0x1004, BNX2_FL_NOT_5709, 0x00000000, 0x000f0001 },
Michael Chanb6016b72005-05-26 13:03:09 -07005543
5544 { 0x1408, 0, 0x01c00800, 0x00000000 },
5545 { 0x149c, 0, 0x8000ffff, 0x00000000 },
5546 { 0x14a8, 0, 0x00000000, 0x000001ff },
Michael Chan5b0c76a2005-11-04 08:45:49 -08005547 { 0x14ac, 0, 0x0fffffff, 0x10000000 },
Michael Chanb6016b72005-05-26 13:03:09 -07005548 { 0x14b0, 0, 0x00000002, 0x00000001 },
5549 { 0x14b8, 0, 0x00000000, 0x00000000 },
5550 { 0x14c0, 0, 0x00000000, 0x00000009 },
5551 { 0x14c4, 0, 0x00003fff, 0x00000000 },
5552 { 0x14cc, 0, 0x00000000, 0x00000001 },
5553 { 0x14d0, 0, 0xffffffff, 0x00000000 },
Michael Chanb6016b72005-05-26 13:03:09 -07005554
5555 { 0x1800, 0, 0x00000000, 0x00000001 },
5556 { 0x1804, 0, 0x00000000, 0x00000003 },
Michael Chanb6016b72005-05-26 13:03:09 -07005557
5558 { 0x2800, 0, 0x00000000, 0x00000001 },
5559 { 0x2804, 0, 0x00000000, 0x00003f01 },
5560 { 0x2808, 0, 0x0f3f3f03, 0x00000000 },
5561 { 0x2810, 0, 0xffff0000, 0x00000000 },
5562 { 0x2814, 0, 0xffff0000, 0x00000000 },
5563 { 0x2818, 0, 0xffff0000, 0x00000000 },
5564 { 0x281c, 0, 0xffff0000, 0x00000000 },
5565 { 0x2834, 0, 0xffffffff, 0x00000000 },
5566 { 0x2840, 0, 0x00000000, 0xffffffff },
5567 { 0x2844, 0, 0x00000000, 0xffffffff },
5568 { 0x2848, 0, 0xffffffff, 0x00000000 },
5569 { 0x284c, 0, 0xf800f800, 0x07ff07ff },
5570
5571 { 0x2c00, 0, 0x00000000, 0x00000011 },
5572 { 0x2c04, 0, 0x00000000, 0x00030007 },
5573
Michael Chanb6016b72005-05-26 13:03:09 -07005574 { 0x3c00, 0, 0x00000000, 0x00000001 },
5575 { 0x3c04, 0, 0x00000000, 0x00070000 },
5576 { 0x3c08, 0, 0x00007f71, 0x07f00000 },
5577 { 0x3c0c, 0, 0x1f3ffffc, 0x00000000 },
5578 { 0x3c10, 0, 0xffffffff, 0x00000000 },
5579 { 0x3c14, 0, 0x00000000, 0xffffffff },
5580 { 0x3c18, 0, 0x00000000, 0xffffffff },
5581 { 0x3c1c, 0, 0xfffff000, 0x00000000 },
5582 { 0x3c20, 0, 0xffffff00, 0x00000000 },
Michael Chanb6016b72005-05-26 13:03:09 -07005583
5584 { 0x5004, 0, 0x00000000, 0x0000007f },
5585 { 0x5008, 0, 0x0f0007ff, 0x00000000 },
Michael Chanb6016b72005-05-26 13:03:09 -07005586
Michael Chanb6016b72005-05-26 13:03:09 -07005587 { 0x5c00, 0, 0x00000000, 0x00000001 },
5588 { 0x5c04, 0, 0x00000000, 0x0003000f },
5589 { 0x5c08, 0, 0x00000003, 0x00000000 },
5590 { 0x5c0c, 0, 0x0000fff8, 0x00000000 },
5591 { 0x5c10, 0, 0x00000000, 0xffffffff },
5592 { 0x5c80, 0, 0x00000000, 0x0f7113f1 },
5593 { 0x5c84, 0, 0x00000000, 0x0000f333 },
5594 { 0x5c88, 0, 0x00000000, 0x00077373 },
5595 { 0x5c8c, 0, 0x00000000, 0x0007f737 },
5596
5597 { 0x6808, 0, 0x0000ff7f, 0x00000000 },
5598 { 0x680c, 0, 0xffffffff, 0x00000000 },
5599 { 0x6810, 0, 0xffffffff, 0x00000000 },
5600 { 0x6814, 0, 0xffffffff, 0x00000000 },
5601 { 0x6818, 0, 0xffffffff, 0x00000000 },
5602 { 0x681c, 0, 0xffffffff, 0x00000000 },
5603 { 0x6820, 0, 0x00ff00ff, 0x00000000 },
5604 { 0x6824, 0, 0x00ff00ff, 0x00000000 },
5605 { 0x6828, 0, 0x00ff00ff, 0x00000000 },
5606 { 0x682c, 0, 0x03ff03ff, 0x00000000 },
5607 { 0x6830, 0, 0x03ff03ff, 0x00000000 },
5608 { 0x6834, 0, 0x03ff03ff, 0x00000000 },
5609 { 0x6838, 0, 0x03ff03ff, 0x00000000 },
5610 { 0x683c, 0, 0x0000ffff, 0x00000000 },
5611 { 0x6840, 0, 0x00000ff0, 0x00000000 },
5612 { 0x6844, 0, 0x00ffff00, 0x00000000 },
5613 { 0x684c, 0, 0xffffffff, 0x00000000 },
5614 { 0x6850, 0, 0x7f7f7f7f, 0x00000000 },
5615 { 0x6854, 0, 0x7f7f7f7f, 0x00000000 },
5616 { 0x6858, 0, 0x7f7f7f7f, 0x00000000 },
5617 { 0x685c, 0, 0x7f7f7f7f, 0x00000000 },
5618 { 0x6908, 0, 0x00000000, 0x0001ff0f },
5619 { 0x690c, 0, 0x00000000, 0x0ffe00f0 },
5620
5621 { 0xffff, 0, 0x00000000, 0x00000000 },
5622 };
5623
5624 ret = 0;
Michael Chan5bae30c2007-05-03 13:18:46 -07005625 is_5709 = 0;
Michael Chan4ce45e02012-12-06 10:33:10 +00005626 if (BNX2_CHIP(bp) == BNX2_CHIP_5709)
Michael Chan5bae30c2007-05-03 13:18:46 -07005627 is_5709 = 1;
5628
Michael Chanb6016b72005-05-26 13:03:09 -07005629 for (i = 0; reg_tbl[i].offset != 0xffff; i++) {
5630 u32 offset, rw_mask, ro_mask, save_val, val;
Michael Chan5bae30c2007-05-03 13:18:46 -07005631 u16 flags = reg_tbl[i].flags;
5632
5633 if (is_5709 && (flags & BNX2_FL_NOT_5709))
5634 continue;
Michael Chanb6016b72005-05-26 13:03:09 -07005635
5636 offset = (u32) reg_tbl[i].offset;
5637 rw_mask = reg_tbl[i].rw_mask;
5638 ro_mask = reg_tbl[i].ro_mask;
5639
Peter Hagervall14ab9b82005-08-10 14:18:16 -07005640 save_val = readl(bp->regview + offset);
Michael Chanb6016b72005-05-26 13:03:09 -07005641
Peter Hagervall14ab9b82005-08-10 14:18:16 -07005642 writel(0, bp->regview + offset);
Michael Chanb6016b72005-05-26 13:03:09 -07005643
Peter Hagervall14ab9b82005-08-10 14:18:16 -07005644 val = readl(bp->regview + offset);
Michael Chanb6016b72005-05-26 13:03:09 -07005645 if ((val & rw_mask) != 0) {
5646 goto reg_test_err;
5647 }
5648
5649 if ((val & ro_mask) != (save_val & ro_mask)) {
5650 goto reg_test_err;
5651 }
5652
Peter Hagervall14ab9b82005-08-10 14:18:16 -07005653 writel(0xffffffff, bp->regview + offset);
Michael Chanb6016b72005-05-26 13:03:09 -07005654
Peter Hagervall14ab9b82005-08-10 14:18:16 -07005655 val = readl(bp->regview + offset);
Michael Chanb6016b72005-05-26 13:03:09 -07005656 if ((val & rw_mask) != rw_mask) {
5657 goto reg_test_err;
5658 }
5659
5660 if ((val & ro_mask) != (save_val & ro_mask)) {
5661 goto reg_test_err;
5662 }
5663
Peter Hagervall14ab9b82005-08-10 14:18:16 -07005664 writel(save_val, bp->regview + offset);
Michael Chanb6016b72005-05-26 13:03:09 -07005665 continue;
5666
5667reg_test_err:
Peter Hagervall14ab9b82005-08-10 14:18:16 -07005668 writel(save_val, bp->regview + offset);
Michael Chanb6016b72005-05-26 13:03:09 -07005669 ret = -ENODEV;
5670 break;
5671 }
5672 return ret;
5673}
5674
5675static int
5676bnx2_do_mem_test(struct bnx2 *bp, u32 start, u32 size)
5677{
Arjan van de Venf71e1302006-03-03 21:33:57 -05005678 static const u32 test_pattern[] = { 0x00000000, 0xffffffff, 0x55555555,
Michael Chanb6016b72005-05-26 13:03:09 -07005679 0xaaaaaaaa , 0xaa55aa55, 0x55aa55aa };
5680 int i;
5681
5682 for (i = 0; i < sizeof(test_pattern) / 4; i++) {
5683 u32 offset;
5684
5685 for (offset = 0; offset < size; offset += 4) {
5686
Michael Chan2726d6e2008-01-29 21:35:05 -08005687 bnx2_reg_wr_ind(bp, start + offset, test_pattern[i]);
Michael Chanb6016b72005-05-26 13:03:09 -07005688
Michael Chan2726d6e2008-01-29 21:35:05 -08005689 if (bnx2_reg_rd_ind(bp, start + offset) !=
Michael Chanb6016b72005-05-26 13:03:09 -07005690 test_pattern[i]) {
5691 return -ENODEV;
5692 }
5693 }
5694 }
5695 return 0;
5696}
5697
5698static int
5699bnx2_test_memory(struct bnx2 *bp)
5700{
5701 int ret = 0;
5702 int i;
Michael Chan5bae30c2007-05-03 13:18:46 -07005703 static struct mem_entry {
Michael Chanb6016b72005-05-26 13:03:09 -07005704 u32 offset;
5705 u32 len;
Michael Chan5bae30c2007-05-03 13:18:46 -07005706 } mem_tbl_5706[] = {
Michael Chanb6016b72005-05-26 13:03:09 -07005707 { 0x60000, 0x4000 },
Michael Chan5b0c76a2005-11-04 08:45:49 -08005708 { 0xa0000, 0x3000 },
Michael Chanb6016b72005-05-26 13:03:09 -07005709 { 0xe0000, 0x4000 },
5710 { 0x120000, 0x4000 },
5711 { 0x1a0000, 0x4000 },
5712 { 0x160000, 0x4000 },
5713 { 0xffffffff, 0 },
Michael Chan5bae30c2007-05-03 13:18:46 -07005714 },
5715 mem_tbl_5709[] = {
5716 { 0x60000, 0x4000 },
5717 { 0xa0000, 0x3000 },
5718 { 0xe0000, 0x4000 },
5719 { 0x120000, 0x4000 },
5720 { 0x1a0000, 0x4000 },
5721 { 0xffffffff, 0 },
Michael Chanb6016b72005-05-26 13:03:09 -07005722 };
Michael Chan5bae30c2007-05-03 13:18:46 -07005723 struct mem_entry *mem_tbl;
5724
Michael Chan4ce45e02012-12-06 10:33:10 +00005725 if (BNX2_CHIP(bp) == BNX2_CHIP_5709)
Michael Chan5bae30c2007-05-03 13:18:46 -07005726 mem_tbl = mem_tbl_5709;
5727 else
5728 mem_tbl = mem_tbl_5706;
Michael Chanb6016b72005-05-26 13:03:09 -07005729
5730 for (i = 0; mem_tbl[i].offset != 0xffffffff; i++) {
5731 if ((ret = bnx2_do_mem_test(bp, mem_tbl[i].offset,
5732 mem_tbl[i].len)) != 0) {
5733 return ret;
5734 }
5735 }
Jeff Garzik6aa20a22006-09-13 13:24:59 -04005736
Michael Chanb6016b72005-05-26 13:03:09 -07005737 return ret;
5738}
5739
Michael Chanbc5a0692006-01-23 16:13:22 -08005740#define BNX2_MAC_LOOPBACK 0
5741#define BNX2_PHY_LOOPBACK 1
5742
Michael Chanb6016b72005-05-26 13:03:09 -07005743static int
Michael Chanbc5a0692006-01-23 16:13:22 -08005744bnx2_run_loopback(struct bnx2 *bp, int loopback_mode)
Michael Chanb6016b72005-05-26 13:03:09 -07005745{
5746 unsigned int pkt_size, num_pkts, i;
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00005747 struct sk_buff *skb;
5748 u8 *data;
Michael Chanb6016b72005-05-26 13:03:09 -07005749 unsigned char *packet;
Michael Chanbc5a0692006-01-23 16:13:22 -08005750 u16 rx_start_idx, rx_idx;
Michael Chanb6016b72005-05-26 13:03:09 -07005751 dma_addr_t map;
Michael Chan2bc40782012-12-06 10:33:09 +00005752 struct bnx2_tx_bd *txbd;
5753 struct bnx2_sw_bd *rx_buf;
Michael Chanb6016b72005-05-26 13:03:09 -07005754 struct l2_fhdr *rx_hdr;
5755 int ret = -ENODEV;
Michael Chanc76c0472007-12-20 20:01:19 -08005756 struct bnx2_napi *bnapi = &bp->bnx2_napi[0], *tx_napi;
Michael Chan35e90102008-06-19 16:37:42 -07005757 struct bnx2_tx_ring_info *txr = &bnapi->tx_ring;
Michael Chanbb4f98a2008-06-19 16:38:19 -07005758 struct bnx2_rx_ring_info *rxr = &bnapi->rx_ring;
Michael Chanc76c0472007-12-20 20:01:19 -08005759
5760 tx_napi = bnapi;
Michael Chanb6016b72005-05-26 13:03:09 -07005761
Michael Chan35e90102008-06-19 16:37:42 -07005762 txr = &tx_napi->tx_ring;
Michael Chanbb4f98a2008-06-19 16:38:19 -07005763 rxr = &bnapi->rx_ring;
Michael Chanbc5a0692006-01-23 16:13:22 -08005764 if (loopback_mode == BNX2_MAC_LOOPBACK) {
5765 bp->loopback = MAC_LOOPBACK;
5766 bnx2_set_mac_loopback(bp);
5767 }
5768 else if (loopback_mode == BNX2_PHY_LOOPBACK) {
Michael Chan583c28e2008-01-21 19:51:35 -08005769 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
Michael Chan489310a2007-10-10 16:16:31 -07005770 return 0;
5771
Michael Chan80be4432006-11-19 14:07:28 -08005772 bp->loopback = PHY_LOOPBACK;
Michael Chanbc5a0692006-01-23 16:13:22 -08005773 bnx2_set_phy_loopback(bp);
5774 }
5775 else
5776 return -EINVAL;
Michael Chanb6016b72005-05-26 13:03:09 -07005777
Michael Chan84eaa182007-12-12 11:19:57 -08005778 pkt_size = min(bp->dev->mtu + ETH_HLEN, bp->rx_jumbo_thresh - 4);
Michael Chan932f3772006-08-15 01:39:36 -07005779 skb = netdev_alloc_skb(bp->dev, pkt_size);
John W. Linvilleb6cbc3b62005-11-10 12:58:00 -08005780 if (!skb)
5781 return -ENOMEM;
Michael Chanb6016b72005-05-26 13:03:09 -07005782 packet = skb_put(skb, pkt_size);
Joe Perchesd458cdf2013-10-01 19:04:40 -07005783 memcpy(packet, bp->dev->dev_addr, ETH_ALEN);
5784 memset(packet + ETH_ALEN, 0x0, 8);
Michael Chanb6016b72005-05-26 13:03:09 -07005785 for (i = 14; i < pkt_size; i++)
5786 packet[i] = (unsigned char) (i & 0xff);
5787
Stanislaw Gruszka36227e82010-07-15 04:25:50 +00005788 map = dma_map_single(&bp->pdev->dev, skb->data, pkt_size,
5789 PCI_DMA_TODEVICE);
5790 if (dma_mapping_error(&bp->pdev->dev, map)) {
Benjamin Li3d16af82008-10-09 12:26:41 -07005791 dev_kfree_skb(skb);
5792 return -EIO;
5793 }
Michael Chanb6016b72005-05-26 13:03:09 -07005794
Michael Chane503e062012-12-06 10:33:08 +00005795 BNX2_WR(bp, BNX2_HC_COMMAND,
5796 bp->hc_cmd | BNX2_HC_COMMAND_COAL_NOW_WO_INT);
Michael Chanbf5295b2006-03-23 01:11:56 -08005797
Michael Chane503e062012-12-06 10:33:08 +00005798 BNX2_RD(bp, BNX2_HC_COMMAND);
Michael Chanb6016b72005-05-26 13:03:09 -07005799
5800 udelay(5);
Michael Chan35efa7c2007-12-20 19:56:37 -08005801 rx_start_idx = bnx2_get_hw_rx_cons(bnapi);
Michael Chanb6016b72005-05-26 13:03:09 -07005802
Michael Chanb6016b72005-05-26 13:03:09 -07005803 num_pkts = 0;
5804
Michael Chan2bc40782012-12-06 10:33:09 +00005805 txbd = &txr->tx_desc_ring[BNX2_TX_RING_IDX(txr->tx_prod)];
Michael Chanb6016b72005-05-26 13:03:09 -07005806
5807 txbd->tx_bd_haddr_hi = (u64) map >> 32;
5808 txbd->tx_bd_haddr_lo = (u64) map & 0xffffffff;
5809 txbd->tx_bd_mss_nbytes = pkt_size;
5810 txbd->tx_bd_vlan_tag_flags = TX_BD_FLAGS_START | TX_BD_FLAGS_END;
5811
5812 num_pkts++;
Michael Chan2bc40782012-12-06 10:33:09 +00005813 txr->tx_prod = BNX2_NEXT_TX_BD(txr->tx_prod);
Michael Chan35e90102008-06-19 16:37:42 -07005814 txr->tx_prod_bseq += pkt_size;
Michael Chanb6016b72005-05-26 13:03:09 -07005815
Michael Chane503e062012-12-06 10:33:08 +00005816 BNX2_WR16(bp, txr->tx_bidx_addr, txr->tx_prod);
5817 BNX2_WR(bp, txr->tx_bseq_addr, txr->tx_prod_bseq);
Michael Chanb6016b72005-05-26 13:03:09 -07005818
5819 udelay(100);
5820
Michael Chane503e062012-12-06 10:33:08 +00005821 BNX2_WR(bp, BNX2_HC_COMMAND,
5822 bp->hc_cmd | BNX2_HC_COMMAND_COAL_NOW_WO_INT);
Michael Chanbf5295b2006-03-23 01:11:56 -08005823
Michael Chane503e062012-12-06 10:33:08 +00005824 BNX2_RD(bp, BNX2_HC_COMMAND);
Michael Chanb6016b72005-05-26 13:03:09 -07005825
5826 udelay(5);
5827
Stanislaw Gruszka36227e82010-07-15 04:25:50 +00005828 dma_unmap_single(&bp->pdev->dev, map, pkt_size, PCI_DMA_TODEVICE);
Michael Chan745720e2006-06-29 12:37:41 -07005829 dev_kfree_skb(skb);
Michael Chanb6016b72005-05-26 13:03:09 -07005830
Michael Chan35e90102008-06-19 16:37:42 -07005831 if (bnx2_get_hw_tx_cons(tx_napi) != txr->tx_prod)
Michael Chanb6016b72005-05-26 13:03:09 -07005832 goto loopback_test_done;
Michael Chanb6016b72005-05-26 13:03:09 -07005833
Michael Chan35efa7c2007-12-20 19:56:37 -08005834 rx_idx = bnx2_get_hw_rx_cons(bnapi);
Michael Chanb6016b72005-05-26 13:03:09 -07005835 if (rx_idx != rx_start_idx + num_pkts) {
5836 goto loopback_test_done;
5837 }
5838
Michael Chanbb4f98a2008-06-19 16:38:19 -07005839 rx_buf = &rxr->rx_buf_ring[rx_start_idx];
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00005840 data = rx_buf->data;
Michael Chanb6016b72005-05-26 13:03:09 -07005841
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00005842 rx_hdr = get_l2_fhdr(data);
5843 data = (u8 *)rx_hdr + BNX2_RX_OFFSET;
Michael Chanb6016b72005-05-26 13:03:09 -07005844
Stanislaw Gruszka36227e82010-07-15 04:25:50 +00005845 dma_sync_single_for_cpu(&bp->pdev->dev,
FUJITA Tomonori1a4ccc22010-04-01 16:56:57 +00005846 dma_unmap_addr(rx_buf, mapping),
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00005847 bp->rx_buf_use_size, PCI_DMA_FROMDEVICE);
Michael Chanb6016b72005-05-26 13:03:09 -07005848
Michael Chanade2bfe2006-01-23 16:09:51 -08005849 if (rx_hdr->l2_fhdr_status &
Michael Chanb6016b72005-05-26 13:03:09 -07005850 (L2_FHDR_ERRORS_BAD_CRC |
5851 L2_FHDR_ERRORS_PHY_DECODE |
5852 L2_FHDR_ERRORS_ALIGNMENT |
5853 L2_FHDR_ERRORS_TOO_SHORT |
5854 L2_FHDR_ERRORS_GIANT_FRAME)) {
5855
5856 goto loopback_test_done;
5857 }
5858
5859 if ((rx_hdr->l2_fhdr_pkt_len - 4) != pkt_size) {
5860 goto loopback_test_done;
5861 }
5862
5863 for (i = 14; i < pkt_size; i++) {
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00005864 if (*(data + i) != (unsigned char) (i & 0xff)) {
Michael Chanb6016b72005-05-26 13:03:09 -07005865 goto loopback_test_done;
5866 }
5867 }
5868
5869 ret = 0;
5870
5871loopback_test_done:
5872 bp->loopback = 0;
5873 return ret;
5874}
5875
Michael Chanbc5a0692006-01-23 16:13:22 -08005876#define BNX2_MAC_LOOPBACK_FAILED 1
5877#define BNX2_PHY_LOOPBACK_FAILED 2
5878#define BNX2_LOOPBACK_FAILED (BNX2_MAC_LOOPBACK_FAILED | \
5879 BNX2_PHY_LOOPBACK_FAILED)
5880
5881static int
5882bnx2_test_loopback(struct bnx2 *bp)
5883{
5884 int rc = 0;
5885
5886 if (!netif_running(bp->dev))
5887 return BNX2_LOOPBACK_FAILED;
5888
5889 bnx2_reset_nic(bp, BNX2_DRV_MSG_CODE_RESET);
5890 spin_lock_bh(&bp->phy_lock);
Michael Chan9a120bc2008-05-16 22:17:45 -07005891 bnx2_init_phy(bp, 1);
Michael Chanbc5a0692006-01-23 16:13:22 -08005892 spin_unlock_bh(&bp->phy_lock);
5893 if (bnx2_run_loopback(bp, BNX2_MAC_LOOPBACK))
5894 rc |= BNX2_MAC_LOOPBACK_FAILED;
5895 if (bnx2_run_loopback(bp, BNX2_PHY_LOOPBACK))
5896 rc |= BNX2_PHY_LOOPBACK_FAILED;
5897 return rc;
5898}
5899
Michael Chanb6016b72005-05-26 13:03:09 -07005900#define NVRAM_SIZE 0x200
5901#define CRC32_RESIDUAL 0xdebb20e3
5902
5903static int
5904bnx2_test_nvram(struct bnx2 *bp)
5905{
Al Virob491edd2007-12-22 19:44:51 +00005906 __be32 buf[NVRAM_SIZE / 4];
Michael Chanb6016b72005-05-26 13:03:09 -07005907 u8 *data = (u8 *) buf;
5908 int rc = 0;
5909 u32 magic, csum;
5910
5911 if ((rc = bnx2_nvram_read(bp, 0, data, 4)) != 0)
5912 goto test_nvram_done;
5913
5914 magic = be32_to_cpu(buf[0]);
5915 if (magic != 0x669955aa) {
5916 rc = -ENODEV;
5917 goto test_nvram_done;
5918 }
5919
5920 if ((rc = bnx2_nvram_read(bp, 0x100, data, NVRAM_SIZE)) != 0)
5921 goto test_nvram_done;
5922
5923 csum = ether_crc_le(0x100, data);
5924 if (csum != CRC32_RESIDUAL) {
5925 rc = -ENODEV;
5926 goto test_nvram_done;
5927 }
5928
5929 csum = ether_crc_le(0x100, data + 0x100);
5930 if (csum != CRC32_RESIDUAL) {
5931 rc = -ENODEV;
5932 }
5933
5934test_nvram_done:
5935 return rc;
5936}
5937
5938static int
5939bnx2_test_link(struct bnx2 *bp)
5940{
5941 u32 bmsr;
5942
Michael Chan9f52b562008-10-09 12:21:46 -07005943 if (!netif_running(bp->dev))
5944 return -ENODEV;
5945
Michael Chan583c28e2008-01-21 19:51:35 -08005946 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP) {
Michael Chan489310a2007-10-10 16:16:31 -07005947 if (bp->link_up)
5948 return 0;
5949 return -ENODEV;
5950 }
Michael Chanc770a652005-08-25 15:38:39 -07005951 spin_lock_bh(&bp->phy_lock);
Michael Chan27a005b2007-05-03 13:23:41 -07005952 bnx2_enable_bmsr1(bp);
5953 bnx2_read_phy(bp, bp->mii_bmsr1, &bmsr);
5954 bnx2_read_phy(bp, bp->mii_bmsr1, &bmsr);
5955 bnx2_disable_bmsr1(bp);
Michael Chanc770a652005-08-25 15:38:39 -07005956 spin_unlock_bh(&bp->phy_lock);
Jeff Garzik6aa20a22006-09-13 13:24:59 -04005957
Michael Chanb6016b72005-05-26 13:03:09 -07005958 if (bmsr & BMSR_LSTATUS) {
5959 return 0;
5960 }
5961 return -ENODEV;
5962}
5963
5964static int
5965bnx2_test_intr(struct bnx2 *bp)
5966{
5967 int i;
Michael Chanb6016b72005-05-26 13:03:09 -07005968 u16 status_idx;
5969
5970 if (!netif_running(bp->dev))
5971 return -ENODEV;
5972
Michael Chane503e062012-12-06 10:33:08 +00005973 status_idx = BNX2_RD(bp, BNX2_PCICFG_INT_ACK_CMD) & 0xffff;
Michael Chanb6016b72005-05-26 13:03:09 -07005974
5975 /* This register is not touched during run-time. */
Michael Chane503e062012-12-06 10:33:08 +00005976 BNX2_WR(bp, BNX2_HC_COMMAND, bp->hc_cmd | BNX2_HC_COMMAND_COAL_NOW);
5977 BNX2_RD(bp, BNX2_HC_COMMAND);
Michael Chanb6016b72005-05-26 13:03:09 -07005978
5979 for (i = 0; i < 10; i++) {
Michael Chane503e062012-12-06 10:33:08 +00005980 if ((BNX2_RD(bp, BNX2_PCICFG_INT_ACK_CMD) & 0xffff) !=
Michael Chanb6016b72005-05-26 13:03:09 -07005981 status_idx) {
5982
5983 break;
5984 }
5985
5986 msleep_interruptible(10);
5987 }
5988 if (i < 10)
5989 return 0;
5990
5991 return -ENODEV;
5992}
5993
Michael Chan38ea3682008-02-23 19:48:57 -08005994/* Determining link for parallel detection. */
Michael Chanb2fadea2008-01-21 17:07:06 -08005995static int
5996bnx2_5706_serdes_has_link(struct bnx2 *bp)
5997{
5998 u32 mode_ctl, an_dbg, exp;
5999
Michael Chan38ea3682008-02-23 19:48:57 -08006000 if (bp->phy_flags & BNX2_PHY_FLAG_NO_PARALLEL)
6001 return 0;
6002
Michael Chanb2fadea2008-01-21 17:07:06 -08006003 bnx2_write_phy(bp, MII_BNX2_MISC_SHADOW, MISC_SHDW_MODE_CTL);
6004 bnx2_read_phy(bp, MII_BNX2_MISC_SHADOW, &mode_ctl);
6005
6006 if (!(mode_ctl & MISC_SHDW_MODE_CTL_SIG_DET))
6007 return 0;
6008
6009 bnx2_write_phy(bp, MII_BNX2_MISC_SHADOW, MISC_SHDW_AN_DBG);
6010 bnx2_read_phy(bp, MII_BNX2_MISC_SHADOW, &an_dbg);
6011 bnx2_read_phy(bp, MII_BNX2_MISC_SHADOW, &an_dbg);
6012
Michael Chanf3014c0c2008-01-29 21:33:03 -08006013 if (an_dbg & (MISC_SHDW_AN_DBG_NOSYNC | MISC_SHDW_AN_DBG_RUDI_INVALID))
Michael Chanb2fadea2008-01-21 17:07:06 -08006014 return 0;
6015
6016 bnx2_write_phy(bp, MII_BNX2_DSP_ADDRESS, MII_EXPAND_REG1);
6017 bnx2_read_phy(bp, MII_BNX2_DSP_RW_PORT, &exp);
6018 bnx2_read_phy(bp, MII_BNX2_DSP_RW_PORT, &exp);
6019
6020 if (exp & MII_EXPAND_REG1_RUDI_C) /* receiving CONFIG */
6021 return 0;
6022
6023 return 1;
6024}
6025
Michael Chanb6016b72005-05-26 13:03:09 -07006026static void
Michael Chan48b01e22006-11-19 14:08:00 -08006027bnx2_5706_serdes_timer(struct bnx2 *bp)
6028{
Michael Chanb2fadea2008-01-21 17:07:06 -08006029 int check_link = 1;
6030
Michael Chan48b01e22006-11-19 14:08:00 -08006031 spin_lock(&bp->phy_lock);
Michael Chanb2fadea2008-01-21 17:07:06 -08006032 if (bp->serdes_an_pending) {
Michael Chan48b01e22006-11-19 14:08:00 -08006033 bp->serdes_an_pending--;
Michael Chanb2fadea2008-01-21 17:07:06 -08006034 check_link = 0;
6035 } else if ((bp->link_up == 0) && (bp->autoneg & AUTONEG_SPEED)) {
Michael Chan48b01e22006-11-19 14:08:00 -08006036 u32 bmcr;
6037
Benjamin Liac392ab2008-09-18 16:40:49 -07006038 bp->current_interval = BNX2_TIMER_INTERVAL;
Michael Chan48b01e22006-11-19 14:08:00 -08006039
Michael Chanca58c3a2007-05-03 13:22:52 -07006040 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chan48b01e22006-11-19 14:08:00 -08006041
6042 if (bmcr & BMCR_ANENABLE) {
Michael Chanb2fadea2008-01-21 17:07:06 -08006043 if (bnx2_5706_serdes_has_link(bp)) {
Michael Chan48b01e22006-11-19 14:08:00 -08006044 bmcr &= ~BMCR_ANENABLE;
6045 bmcr |= BMCR_SPEED1000 | BMCR_FULLDPLX;
Michael Chanca58c3a2007-05-03 13:22:52 -07006046 bnx2_write_phy(bp, bp->mii_bmcr, bmcr);
Michael Chan583c28e2008-01-21 19:51:35 -08006047 bp->phy_flags |= BNX2_PHY_FLAG_PARALLEL_DETECT;
Michael Chan48b01e22006-11-19 14:08:00 -08006048 }
6049 }
6050 }
6051 else if ((bp->link_up) && (bp->autoneg & AUTONEG_SPEED) &&
Michael Chan583c28e2008-01-21 19:51:35 -08006052 (bp->phy_flags & BNX2_PHY_FLAG_PARALLEL_DETECT)) {
Michael Chan48b01e22006-11-19 14:08:00 -08006053 u32 phy2;
6054
6055 bnx2_write_phy(bp, 0x17, 0x0f01);
6056 bnx2_read_phy(bp, 0x15, &phy2);
6057 if (phy2 & 0x20) {
6058 u32 bmcr;
6059
Michael Chanca58c3a2007-05-03 13:22:52 -07006060 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chan48b01e22006-11-19 14:08:00 -08006061 bmcr |= BMCR_ANENABLE;
Michael Chanca58c3a2007-05-03 13:22:52 -07006062 bnx2_write_phy(bp, bp->mii_bmcr, bmcr);
Michael Chan48b01e22006-11-19 14:08:00 -08006063
Michael Chan583c28e2008-01-21 19:51:35 -08006064 bp->phy_flags &= ~BNX2_PHY_FLAG_PARALLEL_DETECT;
Michael Chan48b01e22006-11-19 14:08:00 -08006065 }
6066 } else
Benjamin Liac392ab2008-09-18 16:40:49 -07006067 bp->current_interval = BNX2_TIMER_INTERVAL;
Michael Chan48b01e22006-11-19 14:08:00 -08006068
Michael Chana2724e22008-02-23 19:47:44 -08006069 if (check_link) {
Michael Chanb2fadea2008-01-21 17:07:06 -08006070 u32 val;
6071
6072 bnx2_write_phy(bp, MII_BNX2_MISC_SHADOW, MISC_SHDW_AN_DBG);
6073 bnx2_read_phy(bp, MII_BNX2_MISC_SHADOW, &val);
6074 bnx2_read_phy(bp, MII_BNX2_MISC_SHADOW, &val);
6075
Michael Chana2724e22008-02-23 19:47:44 -08006076 if (bp->link_up && (val & MISC_SHDW_AN_DBG_NOSYNC)) {
6077 if (!(bp->phy_flags & BNX2_PHY_FLAG_FORCED_DOWN)) {
6078 bnx2_5706s_force_link_dn(bp, 1);
6079 bp->phy_flags |= BNX2_PHY_FLAG_FORCED_DOWN;
6080 } else
6081 bnx2_set_link(bp);
6082 } else if (!bp->link_up && !(val & MISC_SHDW_AN_DBG_NOSYNC))
6083 bnx2_set_link(bp);
Michael Chanb2fadea2008-01-21 17:07:06 -08006084 }
Michael Chan48b01e22006-11-19 14:08:00 -08006085 spin_unlock(&bp->phy_lock);
6086}
6087
6088static void
Michael Chanf8dd0642006-11-19 14:08:29 -08006089bnx2_5708_serdes_timer(struct bnx2 *bp)
6090{
Michael Chan583c28e2008-01-21 19:51:35 -08006091 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
Michael Chan0d8a6572007-07-07 22:49:43 -07006092 return;
6093
Michael Chan583c28e2008-01-21 19:51:35 -08006094 if ((bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE) == 0) {
Michael Chanf8dd0642006-11-19 14:08:29 -08006095 bp->serdes_an_pending = 0;
6096 return;
6097 }
6098
6099 spin_lock(&bp->phy_lock);
6100 if (bp->serdes_an_pending)
6101 bp->serdes_an_pending--;
6102 else if ((bp->link_up == 0) && (bp->autoneg & AUTONEG_SPEED)) {
6103 u32 bmcr;
6104
Michael Chanca58c3a2007-05-03 13:22:52 -07006105 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chanf8dd0642006-11-19 14:08:29 -08006106 if (bmcr & BMCR_ANENABLE) {
Michael Chan605a9e22007-05-03 13:23:13 -07006107 bnx2_enable_forced_2g5(bp);
Michael Chan40105c02008-11-12 16:02:45 -08006108 bp->current_interval = BNX2_SERDES_FORCED_TIMEOUT;
Michael Chanf8dd0642006-11-19 14:08:29 -08006109 } else {
Michael Chan605a9e22007-05-03 13:23:13 -07006110 bnx2_disable_forced_2g5(bp);
Michael Chanf8dd0642006-11-19 14:08:29 -08006111 bp->serdes_an_pending = 2;
Benjamin Liac392ab2008-09-18 16:40:49 -07006112 bp->current_interval = BNX2_TIMER_INTERVAL;
Michael Chanf8dd0642006-11-19 14:08:29 -08006113 }
6114
6115 } else
Benjamin Liac392ab2008-09-18 16:40:49 -07006116 bp->current_interval = BNX2_TIMER_INTERVAL;
Michael Chanf8dd0642006-11-19 14:08:29 -08006117
6118 spin_unlock(&bp->phy_lock);
6119}
6120
6121static void
Michael Chanb6016b72005-05-26 13:03:09 -07006122bnx2_timer(unsigned long data)
6123{
6124 struct bnx2 *bp = (struct bnx2 *) data;
Michael Chanb6016b72005-05-26 13:03:09 -07006125
Michael Chancd339a02005-08-25 15:35:24 -07006126 if (!netif_running(bp->dev))
6127 return;
6128
Michael Chanb6016b72005-05-26 13:03:09 -07006129 if (atomic_read(&bp->intr_sem) != 0)
6130 goto bnx2_restart_timer;
6131
Michael Chanefba0182008-12-03 00:36:15 -08006132 if ((bp->flags & (BNX2_FLAG_USING_MSI | BNX2_FLAG_ONE_SHOT_MSI)) ==
6133 BNX2_FLAG_USING_MSI)
6134 bnx2_chk_missed_msi(bp);
6135
Michael Chandf149d72007-07-07 22:51:36 -07006136 bnx2_send_heart_beat(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07006137
Michael Chan2726d6e2008-01-29 21:35:05 -08006138 bp->stats_blk->stat_FwRxDrop =
6139 bnx2_reg_rd_ind(bp, BNX2_FW_RX_DROP_COUNT);
Michael Chancea94db2006-06-12 22:16:13 -07006140
Michael Chan02537b062007-06-04 21:24:07 -07006141 /* workaround occasional corrupted counters */
Michael Chan61d9e3f2009-08-21 16:20:46 +00006142 if ((bp->flags & BNX2_FLAG_BROKEN_STATS) && bp->stats_ticks)
Michael Chane503e062012-12-06 10:33:08 +00006143 BNX2_WR(bp, BNX2_HC_COMMAND, bp->hc_cmd |
6144 BNX2_HC_COMMAND_STATS_NOW);
Michael Chan02537b062007-06-04 21:24:07 -07006145
Michael Chan583c28e2008-01-21 19:51:35 -08006146 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Michael Chan4ce45e02012-12-06 10:33:10 +00006147 if (BNX2_CHIP(bp) == BNX2_CHIP_5706)
Michael Chanf8dd0642006-11-19 14:08:29 -08006148 bnx2_5706_serdes_timer(bp);
Michael Chan27a005b2007-05-03 13:23:41 -07006149 else
Michael Chanf8dd0642006-11-19 14:08:29 -08006150 bnx2_5708_serdes_timer(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07006151 }
6152
6153bnx2_restart_timer:
Michael Chancd339a02005-08-25 15:35:24 -07006154 mod_timer(&bp->timer, jiffies + bp->current_interval);
Michael Chanb6016b72005-05-26 13:03:09 -07006155}
6156
Michael Chan8e6a72c2007-05-03 13:24:48 -07006157static int
6158bnx2_request_irq(struct bnx2 *bp)
6159{
Michael Chan6d866ff2007-12-20 19:56:09 -08006160 unsigned long flags;
Michael Chanb4b36042007-12-20 19:59:30 -08006161 struct bnx2_irq *irq;
6162 int rc = 0, i;
Michael Chan8e6a72c2007-05-03 13:24:48 -07006163
David S. Millerf86e82f2008-01-21 17:15:40 -08006164 if (bp->flags & BNX2_FLAG_USING_MSI_OR_MSIX)
Michael Chan6d866ff2007-12-20 19:56:09 -08006165 flags = 0;
6166 else
6167 flags = IRQF_SHARED;
Michael Chanb4b36042007-12-20 19:59:30 -08006168
6169 for (i = 0; i < bp->irq_nvecs; i++) {
6170 irq = &bp->irq_tbl[i];
Michael Chanc76c0472007-12-20 20:01:19 -08006171 rc = request_irq(irq->vector, irq->handler, flags, irq->name,
Michael Chanf0ea2e62008-06-19 16:41:57 -07006172 &bp->bnx2_napi[i]);
Michael Chanb4b36042007-12-20 19:59:30 -08006173 if (rc)
6174 break;
6175 irq->requested = 1;
6176 }
Michael Chan8e6a72c2007-05-03 13:24:48 -07006177 return rc;
6178}
6179
6180static void
Michael Chana29ba9d2010-12-31 11:03:14 -08006181__bnx2_free_irq(struct bnx2 *bp)
Michael Chan8e6a72c2007-05-03 13:24:48 -07006182{
Michael Chanb4b36042007-12-20 19:59:30 -08006183 struct bnx2_irq *irq;
6184 int i;
Michael Chan8e6a72c2007-05-03 13:24:48 -07006185
Michael Chanb4b36042007-12-20 19:59:30 -08006186 for (i = 0; i < bp->irq_nvecs; i++) {
6187 irq = &bp->irq_tbl[i];
6188 if (irq->requested)
Michael Chanf0ea2e62008-06-19 16:41:57 -07006189 free_irq(irq->vector, &bp->bnx2_napi[i]);
Michael Chanb4b36042007-12-20 19:59:30 -08006190 irq->requested = 0;
Michael Chan6d866ff2007-12-20 19:56:09 -08006191 }
Michael Chana29ba9d2010-12-31 11:03:14 -08006192}
6193
6194static void
6195bnx2_free_irq(struct bnx2 *bp)
6196{
6197
6198 __bnx2_free_irq(bp);
David S. Millerf86e82f2008-01-21 17:15:40 -08006199 if (bp->flags & BNX2_FLAG_USING_MSI)
Michael Chanb4b36042007-12-20 19:59:30 -08006200 pci_disable_msi(bp->pdev);
David S. Millerf86e82f2008-01-21 17:15:40 -08006201 else if (bp->flags & BNX2_FLAG_USING_MSIX)
Michael Chanb4b36042007-12-20 19:59:30 -08006202 pci_disable_msix(bp->pdev);
6203
David S. Millerf86e82f2008-01-21 17:15:40 -08006204 bp->flags &= ~(BNX2_FLAG_USING_MSI_OR_MSIX | BNX2_FLAG_ONE_SHOT_MSI);
Michael Chanb4b36042007-12-20 19:59:30 -08006205}
6206
6207static void
Michael Chan5e9ad9e2008-06-19 16:43:17 -07006208bnx2_enable_msix(struct bnx2 *bp, int msix_vecs)
Michael Chanb4b36042007-12-20 19:59:30 -08006209{
Michael Chan379b39a2010-07-19 14:15:03 +00006210 int i, total_vecs, rc;
Michael Chan57851d82007-12-20 20:01:44 -08006211 struct msix_entry msix_ent[BNX2_MAX_MSIX_VEC];
Michael Chan4e1d0de2008-12-16 20:27:45 -08006212 struct net_device *dev = bp->dev;
6213 const int len = sizeof(bp->irq_tbl[0].name);
Michael Chan57851d82007-12-20 20:01:44 -08006214
Michael Chanb4b36042007-12-20 19:59:30 -08006215 bnx2_setup_msix_tbl(bp);
Michael Chane503e062012-12-06 10:33:08 +00006216 BNX2_WR(bp, BNX2_PCI_MSIX_CONTROL, BNX2_MAX_MSIX_HW_VEC - 1);
6217 BNX2_WR(bp, BNX2_PCI_MSIX_TBL_OFF_BIR, BNX2_PCI_GRC_WINDOW2_BASE);
6218 BNX2_WR(bp, BNX2_PCI_MSIX_PBA_OFF_BIT, BNX2_PCI_GRC_WINDOW3_BASE);
Michael Chan57851d82007-12-20 20:01:44 -08006219
Benjamin Lie2eb8e32010-01-08 00:51:21 -08006220 /* Need to flush the previous three writes to ensure MSI-X
6221 * is setup properly */
Michael Chane503e062012-12-06 10:33:08 +00006222 BNX2_RD(bp, BNX2_PCI_MSIX_CONTROL);
Benjamin Lie2eb8e32010-01-08 00:51:21 -08006223
Michael Chan57851d82007-12-20 20:01:44 -08006224 for (i = 0; i < BNX2_MAX_MSIX_VEC; i++) {
6225 msix_ent[i].entry = i;
6226 msix_ent[i].vector = 0;
6227 }
6228
Michael Chan379b39a2010-07-19 14:15:03 +00006229 total_vecs = msix_vecs;
6230#ifdef BCM_CNIC
6231 total_vecs++;
6232#endif
6233 rc = -ENOSPC;
6234 while (total_vecs >= BNX2_MIN_MSIX_VEC) {
6235 rc = pci_enable_msix(bp->pdev, msix_ent, total_vecs);
6236 if (rc <= 0)
6237 break;
6238 if (rc > 0)
6239 total_vecs = rc;
6240 }
6241
Michael Chan57851d82007-12-20 20:01:44 -08006242 if (rc != 0)
6243 return;
6244
Michael Chan379b39a2010-07-19 14:15:03 +00006245 msix_vecs = total_vecs;
6246#ifdef BCM_CNIC
6247 msix_vecs--;
6248#endif
Michael Chan5e9ad9e2008-06-19 16:43:17 -07006249 bp->irq_nvecs = msix_vecs;
David S. Millerf86e82f2008-01-21 17:15:40 -08006250 bp->flags |= BNX2_FLAG_USING_MSIX | BNX2_FLAG_ONE_SHOT_MSI;
Michael Chan379b39a2010-07-19 14:15:03 +00006251 for (i = 0; i < total_vecs; i++) {
Michael Chan57851d82007-12-20 20:01:44 -08006252 bp->irq_tbl[i].vector = msix_ent[i].vector;
Michael Chan69010312009-03-18 18:11:51 -07006253 snprintf(bp->irq_tbl[i].name, len, "%s-%d", dev->name, i);
6254 bp->irq_tbl[i].handler = bnx2_msi_1shot;
6255 }
Michael Chan6d866ff2007-12-20 19:56:09 -08006256}
6257
Ben Hutchings657d92f2010-09-27 08:25:16 +00006258static int
Michael Chan6d866ff2007-12-20 19:56:09 -08006259bnx2_setup_int_mode(struct bnx2 *bp, int dis_msi)
6260{
Yuval Mintz0a742122012-07-01 03:18:58 +00006261 int cpus = netif_get_num_default_rss_queues();
Michael Chanb0332812012-02-05 15:24:38 +00006262 int msix_vecs;
6263
6264 if (!bp->num_req_rx_rings)
6265 msix_vecs = max(cpus + 1, bp->num_req_tx_rings);
6266 else if (!bp->num_req_tx_rings)
6267 msix_vecs = max(cpus, bp->num_req_rx_rings);
6268 else
6269 msix_vecs = max(bp->num_req_rx_rings, bp->num_req_tx_rings);
6270
6271 msix_vecs = min(msix_vecs, RX_MAX_RINGS);
Michael Chan5e9ad9e2008-06-19 16:43:17 -07006272
Michael Chan6d866ff2007-12-20 19:56:09 -08006273 bp->irq_tbl[0].handler = bnx2_interrupt;
6274 strcpy(bp->irq_tbl[0].name, bp->dev->name);
Michael Chanb4b36042007-12-20 19:59:30 -08006275 bp->irq_nvecs = 1;
6276 bp->irq_tbl[0].vector = bp->pdev->irq;
Michael Chan6d866ff2007-12-20 19:56:09 -08006277
Michael Chan3d5f3a72010-07-03 20:42:15 +00006278 if ((bp->flags & BNX2_FLAG_MSIX_CAP) && !dis_msi)
Michael Chan5e9ad9e2008-06-19 16:43:17 -07006279 bnx2_enable_msix(bp, msix_vecs);
Michael Chanb4b36042007-12-20 19:59:30 -08006280
David S. Millerf86e82f2008-01-21 17:15:40 -08006281 if ((bp->flags & BNX2_FLAG_MSI_CAP) && !dis_msi &&
6282 !(bp->flags & BNX2_FLAG_USING_MSIX)) {
Michael Chan6d866ff2007-12-20 19:56:09 -08006283 if (pci_enable_msi(bp->pdev) == 0) {
David S. Millerf86e82f2008-01-21 17:15:40 -08006284 bp->flags |= BNX2_FLAG_USING_MSI;
Michael Chan4ce45e02012-12-06 10:33:10 +00006285 if (BNX2_CHIP(bp) == BNX2_CHIP_5709) {
David S. Millerf86e82f2008-01-21 17:15:40 -08006286 bp->flags |= BNX2_FLAG_ONE_SHOT_MSI;
Michael Chan6d866ff2007-12-20 19:56:09 -08006287 bp->irq_tbl[0].handler = bnx2_msi_1shot;
6288 } else
6289 bp->irq_tbl[0].handler = bnx2_msi;
Michael Chanb4b36042007-12-20 19:59:30 -08006290
6291 bp->irq_tbl[0].vector = bp->pdev->irq;
Michael Chan6d866ff2007-12-20 19:56:09 -08006292 }
6293 }
Benjamin Li706bf242008-07-18 17:55:11 -07006294
Michael Chanb0332812012-02-05 15:24:38 +00006295 if (!bp->num_req_tx_rings)
6296 bp->num_tx_rings = rounddown_pow_of_two(bp->irq_nvecs);
6297 else
6298 bp->num_tx_rings = min(bp->irq_nvecs, bp->num_req_tx_rings);
6299
6300 if (!bp->num_req_rx_rings)
6301 bp->num_rx_rings = bp->irq_nvecs;
6302 else
6303 bp->num_rx_rings = min(bp->irq_nvecs, bp->num_req_rx_rings);
6304
Ben Hutchings657d92f2010-09-27 08:25:16 +00006305 netif_set_real_num_tx_queues(bp->dev, bp->num_tx_rings);
Benjamin Li706bf242008-07-18 17:55:11 -07006306
Ben Hutchings657d92f2010-09-27 08:25:16 +00006307 return netif_set_real_num_rx_queues(bp->dev, bp->num_rx_rings);
Michael Chan8e6a72c2007-05-03 13:24:48 -07006308}
6309
Michael Chanb6016b72005-05-26 13:03:09 -07006310/* Called with rtnl_lock */
6311static int
6312bnx2_open(struct net_device *dev)
6313{
Michael Chan972ec0d2006-01-23 16:12:43 -08006314 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006315 int rc;
6316
françois romieu7880b722011-09-30 00:36:52 +00006317 rc = bnx2_request_firmware(bp);
6318 if (rc < 0)
6319 goto out;
6320
Michael Chan1b2f9222007-05-03 13:20:19 -07006321 netif_carrier_off(dev);
6322
Michael Chanb6016b72005-05-26 13:03:09 -07006323 bnx2_disable_int(bp);
6324
Ben Hutchings657d92f2010-09-27 08:25:16 +00006325 rc = bnx2_setup_int_mode(bp, disable_msi);
6326 if (rc)
6327 goto open_err;
Benjamin Li4327ba42010-03-23 13:13:11 +00006328 bnx2_init_napi(bp);
Michael Chan35efa7c2007-12-20 19:56:37 -08006329 bnx2_napi_enable(bp);
Michael Chan35e90102008-06-19 16:37:42 -07006330 rc = bnx2_alloc_mem(bp);
Michael Chan2739a8b2008-06-19 16:44:10 -07006331 if (rc)
6332 goto open_err;
Michael Chan35e90102008-06-19 16:37:42 -07006333
Michael Chan8e6a72c2007-05-03 13:24:48 -07006334 rc = bnx2_request_irq(bp);
Michael Chan2739a8b2008-06-19 16:44:10 -07006335 if (rc)
6336 goto open_err;
Michael Chanb6016b72005-05-26 13:03:09 -07006337
Michael Chan9a120bc2008-05-16 22:17:45 -07006338 rc = bnx2_init_nic(bp, 1);
Michael Chan2739a8b2008-06-19 16:44:10 -07006339 if (rc)
6340 goto open_err;
Jeff Garzik6aa20a22006-09-13 13:24:59 -04006341
Michael Chancd339a02005-08-25 15:35:24 -07006342 mod_timer(&bp->timer, jiffies + bp->current_interval);
Michael Chanb6016b72005-05-26 13:03:09 -07006343
6344 atomic_set(&bp->intr_sem, 0);
6345
Michael Chan354fcd72010-01-17 07:30:44 +00006346 memset(bp->temp_stats_blk, 0, sizeof(struct statistics_block));
6347
Michael Chanb6016b72005-05-26 13:03:09 -07006348 bnx2_enable_int(bp);
6349
David S. Millerf86e82f2008-01-21 17:15:40 -08006350 if (bp->flags & BNX2_FLAG_USING_MSI) {
Michael Chanb6016b72005-05-26 13:03:09 -07006351 /* Test MSI to make sure it is working
6352 * If MSI test fails, go back to INTx mode
6353 */
6354 if (bnx2_test_intr(bp) != 0) {
Joe Perches3a9c6a42010-02-17 15:01:51 +00006355 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 -07006356
6357 bnx2_disable_int(bp);
Michael Chan8e6a72c2007-05-03 13:24:48 -07006358 bnx2_free_irq(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07006359
Michael Chan6d866ff2007-12-20 19:56:09 -08006360 bnx2_setup_int_mode(bp, 1);
6361
Michael Chan9a120bc2008-05-16 22:17:45 -07006362 rc = bnx2_init_nic(bp, 0);
Michael Chanb6016b72005-05-26 13:03:09 -07006363
Michael Chan8e6a72c2007-05-03 13:24:48 -07006364 if (!rc)
6365 rc = bnx2_request_irq(bp);
6366
Michael Chanb6016b72005-05-26 13:03:09 -07006367 if (rc) {
Michael Chanb6016b72005-05-26 13:03:09 -07006368 del_timer_sync(&bp->timer);
Michael Chan2739a8b2008-06-19 16:44:10 -07006369 goto open_err;
Michael Chanb6016b72005-05-26 13:03:09 -07006370 }
6371 bnx2_enable_int(bp);
6372 }
6373 }
David S. Millerf86e82f2008-01-21 17:15:40 -08006374 if (bp->flags & BNX2_FLAG_USING_MSI)
Joe Perches3a9c6a42010-02-17 15:01:51 +00006375 netdev_info(dev, "using MSI\n");
David S. Millerf86e82f2008-01-21 17:15:40 -08006376 else if (bp->flags & BNX2_FLAG_USING_MSIX)
Joe Perches3a9c6a42010-02-17 15:01:51 +00006377 netdev_info(dev, "using MSIX\n");
Michael Chanb6016b72005-05-26 13:03:09 -07006378
Benjamin Li706bf242008-07-18 17:55:11 -07006379 netif_tx_start_all_queues(dev);
françois romieu7880b722011-09-30 00:36:52 +00006380out:
6381 return rc;
Michael Chan2739a8b2008-06-19 16:44:10 -07006382
6383open_err:
6384 bnx2_napi_disable(bp);
6385 bnx2_free_skbs(bp);
6386 bnx2_free_irq(bp);
6387 bnx2_free_mem(bp);
Michael Chanf048fa92010-06-01 15:05:36 +00006388 bnx2_del_napi(bp);
françois romieu7880b722011-09-30 00:36:52 +00006389 bnx2_release_firmware(bp);
6390 goto out;
Michael Chanb6016b72005-05-26 13:03:09 -07006391}
6392
6393static void
David Howellsc4028952006-11-22 14:57:56 +00006394bnx2_reset_task(struct work_struct *work)
Michael Chanb6016b72005-05-26 13:03:09 -07006395{
David Howellsc4028952006-11-22 14:57:56 +00006396 struct bnx2 *bp = container_of(work, struct bnx2, reset_task);
Michael Chancd634012011-07-15 06:53:58 +00006397 int rc;
Michael Chanefdfad32012-07-16 14:25:56 +00006398 u16 pcicmd;
Michael Chanb6016b72005-05-26 13:03:09 -07006399
Michael Chan51bf6bb2009-12-03 09:46:31 +00006400 rtnl_lock();
6401 if (!netif_running(bp->dev)) {
6402 rtnl_unlock();
Michael Chanafdc08b2005-08-25 15:34:29 -07006403 return;
Michael Chan51bf6bb2009-12-03 09:46:31 +00006404 }
Michael Chanafdc08b2005-08-25 15:34:29 -07006405
Michael Chan212f9932010-04-27 11:28:10 +00006406 bnx2_netif_stop(bp, true);
Michael Chanb6016b72005-05-26 13:03:09 -07006407
Michael Chanefdfad32012-07-16 14:25:56 +00006408 pci_read_config_word(bp->pdev, PCI_COMMAND, &pcicmd);
6409 if (!(pcicmd & PCI_COMMAND_MEMORY)) {
6410 /* in case PCI block has reset */
6411 pci_restore_state(bp->pdev);
6412 pci_save_state(bp->pdev);
6413 }
Michael Chancd634012011-07-15 06:53:58 +00006414 rc = bnx2_init_nic(bp, 1);
6415 if (rc) {
6416 netdev_err(bp->dev, "failed to reset NIC, closing\n");
6417 bnx2_napi_enable(bp);
6418 dev_close(bp->dev);
6419 rtnl_unlock();
6420 return;
6421 }
Michael Chanb6016b72005-05-26 13:03:09 -07006422
6423 atomic_set(&bp->intr_sem, 1);
Michael Chan212f9932010-04-27 11:28:10 +00006424 bnx2_netif_start(bp, true);
Michael Chan51bf6bb2009-12-03 09:46:31 +00006425 rtnl_unlock();
Michael Chanb6016b72005-05-26 13:03:09 -07006426}
6427
Michael Chan555069d2012-06-16 15:45:41 +00006428#define BNX2_FTQ_ENTRY(ftq) { __stringify(ftq##FTQ_CTL), BNX2_##ftq##FTQ_CTL }
6429
6430static void
6431bnx2_dump_ftq(struct bnx2 *bp)
6432{
6433 int i;
6434 u32 reg, bdidx, cid, valid;
6435 struct net_device *dev = bp->dev;
6436 static const struct ftq_reg {
6437 char *name;
6438 u32 off;
6439 } ftq_arr[] = {
6440 BNX2_FTQ_ENTRY(RV2P_P),
6441 BNX2_FTQ_ENTRY(RV2P_T),
6442 BNX2_FTQ_ENTRY(RV2P_M),
6443 BNX2_FTQ_ENTRY(TBDR_),
6444 BNX2_FTQ_ENTRY(TDMA_),
6445 BNX2_FTQ_ENTRY(TXP_),
6446 BNX2_FTQ_ENTRY(TXP_),
6447 BNX2_FTQ_ENTRY(TPAT_),
6448 BNX2_FTQ_ENTRY(RXP_C),
6449 BNX2_FTQ_ENTRY(RXP_),
6450 BNX2_FTQ_ENTRY(COM_COMXQ_),
6451 BNX2_FTQ_ENTRY(COM_COMTQ_),
6452 BNX2_FTQ_ENTRY(COM_COMQ_),
6453 BNX2_FTQ_ENTRY(CP_CPQ_),
6454 };
6455
6456 netdev_err(dev, "<--- start FTQ dump --->\n");
6457 for (i = 0; i < ARRAY_SIZE(ftq_arr); i++)
6458 netdev_err(dev, "%s %08x\n", ftq_arr[i].name,
6459 bnx2_reg_rd_ind(bp, ftq_arr[i].off));
6460
6461 netdev_err(dev, "CPU states:\n");
6462 for (reg = BNX2_TXP_CPU_MODE; reg <= BNX2_CP_CPU_MODE; reg += 0x40000)
6463 netdev_err(dev, "%06x mode %x state %x evt_mask %x pc %x pc %x instr %x\n",
6464 reg, bnx2_reg_rd_ind(bp, reg),
6465 bnx2_reg_rd_ind(bp, reg + 4),
6466 bnx2_reg_rd_ind(bp, reg + 8),
6467 bnx2_reg_rd_ind(bp, reg + 0x1c),
6468 bnx2_reg_rd_ind(bp, reg + 0x1c),
6469 bnx2_reg_rd_ind(bp, reg + 0x20));
6470
6471 netdev_err(dev, "<--- end FTQ dump --->\n");
6472 netdev_err(dev, "<--- start TBDC dump --->\n");
6473 netdev_err(dev, "TBDC free cnt: %ld\n",
Michael Chane503e062012-12-06 10:33:08 +00006474 BNX2_RD(bp, BNX2_TBDC_STATUS) & BNX2_TBDC_STATUS_FREE_CNT);
Michael Chan555069d2012-06-16 15:45:41 +00006475 netdev_err(dev, "LINE CID BIDX CMD VALIDS\n");
6476 for (i = 0; i < 0x20; i++) {
6477 int j = 0;
6478
Michael Chane503e062012-12-06 10:33:08 +00006479 BNX2_WR(bp, BNX2_TBDC_BD_ADDR, i);
6480 BNX2_WR(bp, BNX2_TBDC_CAM_OPCODE,
6481 BNX2_TBDC_CAM_OPCODE_OPCODE_CAM_READ);
6482 BNX2_WR(bp, BNX2_TBDC_COMMAND, BNX2_TBDC_COMMAND_CMD_REG_ARB);
6483 while ((BNX2_RD(bp, BNX2_TBDC_COMMAND) &
Michael Chan555069d2012-06-16 15:45:41 +00006484 BNX2_TBDC_COMMAND_CMD_REG_ARB) && j < 100)
6485 j++;
6486
Michael Chane503e062012-12-06 10:33:08 +00006487 cid = BNX2_RD(bp, BNX2_TBDC_CID);
6488 bdidx = BNX2_RD(bp, BNX2_TBDC_BIDX);
6489 valid = BNX2_RD(bp, BNX2_TBDC_CAM_OPCODE);
Michael Chan555069d2012-06-16 15:45:41 +00006490 netdev_err(dev, "%02x %06x %04lx %02x [%x]\n",
6491 i, cid, bdidx & BNX2_TBDC_BDIDX_BDIDX,
6492 bdidx >> 24, (valid >> 8) & 0x0ff);
6493 }
6494 netdev_err(dev, "<--- end TBDC dump --->\n");
6495}
6496
Michael Chanb6016b72005-05-26 13:03:09 -07006497static void
Michael Chan20175c52009-12-03 09:46:32 +00006498bnx2_dump_state(struct bnx2 *bp)
6499{
6500 struct net_device *dev = bp->dev;
Jeffrey Huangecdbf6e2011-07-13 17:24:21 +00006501 u32 val1, val2;
Michael Chan20175c52009-12-03 09:46:32 +00006502
Michael Chan5804a8f2010-07-03 20:42:17 +00006503 pci_read_config_dword(bp->pdev, PCI_COMMAND, &val1);
6504 netdev_err(dev, "DEBUG: intr_sem[%x] PCI_CMD[%08x]\n",
6505 atomic_read(&bp->intr_sem), val1);
6506 pci_read_config_dword(bp->pdev, bp->pm_cap + PCI_PM_CTRL, &val1);
6507 pci_read_config_dword(bp->pdev, BNX2_PCICFG_MISC_CONFIG, &val2);
6508 netdev_err(dev, "DEBUG: PCI_PM[%08x] PCI_MISC_CFG[%08x]\n", val1, val2);
Eddie Waib98eba52010-05-17 17:32:56 -07006509 netdev_err(dev, "DEBUG: EMAC_TX_STATUS[%08x] EMAC_RX_STATUS[%08x]\n",
Michael Chane503e062012-12-06 10:33:08 +00006510 BNX2_RD(bp, BNX2_EMAC_TX_STATUS),
6511 BNX2_RD(bp, BNX2_EMAC_RX_STATUS));
Eddie Waib98eba52010-05-17 17:32:56 -07006512 netdev_err(dev, "DEBUG: RPM_MGMT_PKT_CTRL[%08x]\n",
Michael Chane503e062012-12-06 10:33:08 +00006513 BNX2_RD(bp, BNX2_RPM_MGMT_PKT_CTRL));
Joe Perches3a9c6a42010-02-17 15:01:51 +00006514 netdev_err(dev, "DEBUG: HC_STATS_INTERRUPT_STATUS[%08x]\n",
Michael Chane503e062012-12-06 10:33:08 +00006515 BNX2_RD(bp, BNX2_HC_STATS_INTERRUPT_STATUS));
Michael Chan20175c52009-12-03 09:46:32 +00006516 if (bp->flags & BNX2_FLAG_USING_MSIX)
Joe Perches3a9c6a42010-02-17 15:01:51 +00006517 netdev_err(dev, "DEBUG: PBA[%08x]\n",
Michael Chane503e062012-12-06 10:33:08 +00006518 BNX2_RD(bp, BNX2_PCI_GRC_WINDOW3_BASE));
Michael Chan20175c52009-12-03 09:46:32 +00006519}
6520
6521static void
Michael Chanb6016b72005-05-26 13:03:09 -07006522bnx2_tx_timeout(struct net_device *dev)
6523{
Michael Chan972ec0d2006-01-23 16:12:43 -08006524 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006525
Michael Chan555069d2012-06-16 15:45:41 +00006526 bnx2_dump_ftq(bp);
Michael Chan20175c52009-12-03 09:46:32 +00006527 bnx2_dump_state(bp);
Jeffrey Huangecdbf6e2011-07-13 17:24:21 +00006528 bnx2_dump_mcp_state(bp);
Michael Chan20175c52009-12-03 09:46:32 +00006529
Michael Chanb6016b72005-05-26 13:03:09 -07006530 /* This allows the netif to be shutdown gracefully before resetting */
6531 schedule_work(&bp->reset_task);
6532}
6533
Herbert Xu932ff272006-06-09 12:20:56 -07006534/* Called with netif_tx_lock.
Michael Chan2f8af122006-08-15 01:39:10 -07006535 * bnx2_tx_int() runs without netif_tx_lock unless it needs to call
6536 * netif_wake_queue().
Michael Chanb6016b72005-05-26 13:03:09 -07006537 */
Stephen Hemminger613573252009-08-31 19:50:58 +00006538static netdev_tx_t
Michael Chanb6016b72005-05-26 13:03:09 -07006539bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev)
6540{
Michael Chan972ec0d2006-01-23 16:12:43 -08006541 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006542 dma_addr_t mapping;
Michael Chan2bc40782012-12-06 10:33:09 +00006543 struct bnx2_tx_bd *txbd;
6544 struct bnx2_sw_tx_bd *tx_buf;
Michael Chanb6016b72005-05-26 13:03:09 -07006545 u32 len, vlan_tag_flags, last_frag, mss;
6546 u16 prod, ring_prod;
6547 int i;
Benjamin Li706bf242008-07-18 17:55:11 -07006548 struct bnx2_napi *bnapi;
6549 struct bnx2_tx_ring_info *txr;
6550 struct netdev_queue *txq;
6551
6552 /* Determine which tx ring we will be placed on */
6553 i = skb_get_queue_mapping(skb);
6554 bnapi = &bp->bnx2_napi[i];
6555 txr = &bnapi->tx_ring;
6556 txq = netdev_get_tx_queue(dev, i);
Michael Chanb6016b72005-05-26 13:03:09 -07006557
Michael Chan35e90102008-06-19 16:37:42 -07006558 if (unlikely(bnx2_tx_avail(bp, txr) <
Michael Chana550c992007-12-20 19:56:59 -08006559 (skb_shinfo(skb)->nr_frags + 1))) {
Benjamin Li706bf242008-07-18 17:55:11 -07006560 netif_tx_stop_queue(txq);
Joe Perches3a9c6a42010-02-17 15:01:51 +00006561 netdev_err(dev, "BUG! Tx ring full when queue awake!\n");
Michael Chanb6016b72005-05-26 13:03:09 -07006562
6563 return NETDEV_TX_BUSY;
6564 }
6565 len = skb_headlen(skb);
Michael Chan35e90102008-06-19 16:37:42 -07006566 prod = txr->tx_prod;
Michael Chan2bc40782012-12-06 10:33:09 +00006567 ring_prod = BNX2_TX_RING_IDX(prod);
Michael Chanb6016b72005-05-26 13:03:09 -07006568
6569 vlan_tag_flags = 0;
Patrick McHardy84fa7932006-08-29 16:44:56 -07006570 if (skb->ip_summed == CHECKSUM_PARTIAL) {
Michael Chanb6016b72005-05-26 13:03:09 -07006571 vlan_tag_flags |= TX_BD_FLAGS_TCP_UDP_CKSUM;
6572 }
6573
Jesse Grosseab6d182010-10-20 13:56:03 +00006574 if (vlan_tx_tag_present(skb)) {
Michael Chanb6016b72005-05-26 13:03:09 -07006575 vlan_tag_flags |=
6576 (TX_BD_FLAGS_VLAN_TAG | (vlan_tx_tag_get(skb) << 16));
6577 }
Jesse Gross7d0fd212010-10-20 13:56:09 +00006578
Michael Chanfde82052007-05-03 17:23:35 -07006579 if ((mss = skb_shinfo(skb)->gso_size)) {
Michael Chana1efb4b2008-10-09 12:24:39 -07006580 u32 tcp_opt_len;
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -07006581 struct iphdr *iph;
Michael Chanb6016b72005-05-26 13:03:09 -07006582
Michael Chanb6016b72005-05-26 13:03:09 -07006583 vlan_tag_flags |= TX_BD_FLAGS_SW_LSO;
6584
Michael Chan4666f872007-05-03 13:22:28 -07006585 tcp_opt_len = tcp_optlen(skb);
Arnaldo Carvalho de Meloab6a5bb2007-03-18 17:43:48 -07006586
Michael Chan4666f872007-05-03 13:22:28 -07006587 if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6) {
6588 u32 tcp_off = skb_transport_offset(skb) -
6589 sizeof(struct ipv6hdr) - ETH_HLEN;
Michael Chanb6016b72005-05-26 13:03:09 -07006590
Michael Chan4666f872007-05-03 13:22:28 -07006591 vlan_tag_flags |= ((tcp_opt_len >> 2) << 8) |
6592 TX_BD_FLAGS_SW_FLAGS;
6593 if (likely(tcp_off == 0))
6594 vlan_tag_flags &= ~TX_BD_FLAGS_TCP6_OFF0_MSK;
6595 else {
6596 tcp_off >>= 3;
6597 vlan_tag_flags |= ((tcp_off & 0x3) <<
6598 TX_BD_FLAGS_TCP6_OFF0_SHL) |
6599 ((tcp_off & 0x10) <<
6600 TX_BD_FLAGS_TCP6_OFF4_SHL);
6601 mss |= (tcp_off & 0xc) << TX_BD_TCP6_OFF2_SHL;
6602 }
6603 } else {
Michael Chan4666f872007-05-03 13:22:28 -07006604 iph = ip_hdr(skb);
Michael Chan4666f872007-05-03 13:22:28 -07006605 if (tcp_opt_len || (iph->ihl > 5)) {
6606 vlan_tag_flags |= ((iph->ihl - 5) +
6607 (tcp_opt_len >> 2)) << 8;
6608 }
Michael Chanb6016b72005-05-26 13:03:09 -07006609 }
Michael Chan4666f872007-05-03 13:22:28 -07006610 } else
Michael Chanb6016b72005-05-26 13:03:09 -07006611 mss = 0;
Michael Chanb6016b72005-05-26 13:03:09 -07006612
Stanislaw Gruszka36227e82010-07-15 04:25:50 +00006613 mapping = dma_map_single(&bp->pdev->dev, skb->data, len, PCI_DMA_TODEVICE);
6614 if (dma_mapping_error(&bp->pdev->dev, mapping)) {
Benjamin Li3d16af82008-10-09 12:26:41 -07006615 dev_kfree_skb(skb);
6616 return NETDEV_TX_OK;
6617 }
6618
Michael Chan35e90102008-06-19 16:37:42 -07006619 tx_buf = &txr->tx_buf_ring[ring_prod];
Michael Chanb6016b72005-05-26 13:03:09 -07006620 tx_buf->skb = skb;
FUJITA Tomonori1a4ccc22010-04-01 16:56:57 +00006621 dma_unmap_addr_set(tx_buf, mapping, mapping);
Michael Chanb6016b72005-05-26 13:03:09 -07006622
Michael Chan35e90102008-06-19 16:37:42 -07006623 txbd = &txr->tx_desc_ring[ring_prod];
Michael Chanb6016b72005-05-26 13:03:09 -07006624
6625 txbd->tx_bd_haddr_hi = (u64) mapping >> 32;
6626 txbd->tx_bd_haddr_lo = (u64) mapping & 0xffffffff;
6627 txbd->tx_bd_mss_nbytes = len | (mss << 16);
6628 txbd->tx_bd_vlan_tag_flags = vlan_tag_flags | TX_BD_FLAGS_START;
6629
6630 last_frag = skb_shinfo(skb)->nr_frags;
Eric Dumazetd62fda02009-05-12 20:48:02 +00006631 tx_buf->nr_frags = last_frag;
6632 tx_buf->is_gso = skb_is_gso(skb);
Michael Chanb6016b72005-05-26 13:03:09 -07006633
6634 for (i = 0; i < last_frag; i++) {
Eric Dumazet9e903e02011-10-18 21:00:24 +00006635 const skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
Michael Chanb6016b72005-05-26 13:03:09 -07006636
Michael Chan2bc40782012-12-06 10:33:09 +00006637 prod = BNX2_NEXT_TX_BD(prod);
6638 ring_prod = BNX2_TX_RING_IDX(prod);
Michael Chan35e90102008-06-19 16:37:42 -07006639 txbd = &txr->tx_desc_ring[ring_prod];
Michael Chanb6016b72005-05-26 13:03:09 -07006640
Eric Dumazet9e903e02011-10-18 21:00:24 +00006641 len = skb_frag_size(frag);
Ian Campbellb7b6a682011-08-24 22:28:12 +00006642 mapping = skb_frag_dma_map(&bp->pdev->dev, frag, 0, len,
Ian Campbell5d6bcdf2011-10-06 11:10:48 +01006643 DMA_TO_DEVICE);
Stanislaw Gruszka36227e82010-07-15 04:25:50 +00006644 if (dma_mapping_error(&bp->pdev->dev, mapping))
Alexander Duycke95524a2009-12-02 16:47:57 +00006645 goto dma_error;
FUJITA Tomonori1a4ccc22010-04-01 16:56:57 +00006646 dma_unmap_addr_set(&txr->tx_buf_ring[ring_prod], mapping,
Alexander Duycke95524a2009-12-02 16:47:57 +00006647 mapping);
Michael Chanb6016b72005-05-26 13:03:09 -07006648
6649 txbd->tx_bd_haddr_hi = (u64) mapping >> 32;
6650 txbd->tx_bd_haddr_lo = (u64) mapping & 0xffffffff;
6651 txbd->tx_bd_mss_nbytes = len | (mss << 16);
6652 txbd->tx_bd_vlan_tag_flags = vlan_tag_flags;
6653
6654 }
6655 txbd->tx_bd_vlan_tag_flags |= TX_BD_FLAGS_END;
6656
Vlad Zolotarov94bf91b2012-02-05 15:24:39 +00006657 /* Sync BD data before updating TX mailbox */
6658 wmb();
6659
Eric Dumazete9831902011-11-29 11:53:05 +00006660 netdev_tx_sent_queue(txq, skb->len);
6661
Michael Chan2bc40782012-12-06 10:33:09 +00006662 prod = BNX2_NEXT_TX_BD(prod);
Michael Chan35e90102008-06-19 16:37:42 -07006663 txr->tx_prod_bseq += skb->len;
Michael Chanb6016b72005-05-26 13:03:09 -07006664
Michael Chane503e062012-12-06 10:33:08 +00006665 BNX2_WR16(bp, txr->tx_bidx_addr, prod);
6666 BNX2_WR(bp, txr->tx_bseq_addr, txr->tx_prod_bseq);
Michael Chanb6016b72005-05-26 13:03:09 -07006667
6668 mmiowb();
6669
Michael Chan35e90102008-06-19 16:37:42 -07006670 txr->tx_prod = prod;
Michael Chanb6016b72005-05-26 13:03:09 -07006671
Michael Chan35e90102008-06-19 16:37:42 -07006672 if (unlikely(bnx2_tx_avail(bp, txr) <= MAX_SKB_FRAGS)) {
Benjamin Li706bf242008-07-18 17:55:11 -07006673 netif_tx_stop_queue(txq);
Michael Chan11848b962010-07-19 14:15:04 +00006674
6675 /* netif_tx_stop_queue() must be done before checking
6676 * tx index in bnx2_tx_avail() below, because in
6677 * bnx2_tx_int(), we update tx index before checking for
6678 * netif_tx_queue_stopped().
6679 */
6680 smp_mb();
Michael Chan35e90102008-06-19 16:37:42 -07006681 if (bnx2_tx_avail(bp, txr) > bp->tx_wake_thresh)
Benjamin Li706bf242008-07-18 17:55:11 -07006682 netif_tx_wake_queue(txq);
Michael Chanb6016b72005-05-26 13:03:09 -07006683 }
6684
6685 return NETDEV_TX_OK;
Alexander Duycke95524a2009-12-02 16:47:57 +00006686dma_error:
6687 /* save value of frag that failed */
6688 last_frag = i;
6689
6690 /* start back at beginning and unmap skb */
6691 prod = txr->tx_prod;
Michael Chan2bc40782012-12-06 10:33:09 +00006692 ring_prod = BNX2_TX_RING_IDX(prod);
Alexander Duycke95524a2009-12-02 16:47:57 +00006693 tx_buf = &txr->tx_buf_ring[ring_prod];
6694 tx_buf->skb = NULL;
Stanislaw Gruszka36227e82010-07-15 04:25:50 +00006695 dma_unmap_single(&bp->pdev->dev, dma_unmap_addr(tx_buf, mapping),
Alexander Duycke95524a2009-12-02 16:47:57 +00006696 skb_headlen(skb), PCI_DMA_TODEVICE);
6697
6698 /* unmap remaining mapped pages */
6699 for (i = 0; i < last_frag; i++) {
Michael Chan2bc40782012-12-06 10:33:09 +00006700 prod = BNX2_NEXT_TX_BD(prod);
6701 ring_prod = BNX2_TX_RING_IDX(prod);
Alexander Duycke95524a2009-12-02 16:47:57 +00006702 tx_buf = &txr->tx_buf_ring[ring_prod];
Stanislaw Gruszka36227e82010-07-15 04:25:50 +00006703 dma_unmap_page(&bp->pdev->dev, dma_unmap_addr(tx_buf, mapping),
Eric Dumazet9e903e02011-10-18 21:00:24 +00006704 skb_frag_size(&skb_shinfo(skb)->frags[i]),
Alexander Duycke95524a2009-12-02 16:47:57 +00006705 PCI_DMA_TODEVICE);
6706 }
6707
6708 dev_kfree_skb(skb);
6709 return NETDEV_TX_OK;
Michael Chanb6016b72005-05-26 13:03:09 -07006710}
6711
6712/* Called with rtnl_lock */
6713static int
6714bnx2_close(struct net_device *dev)
6715{
Michael Chan972ec0d2006-01-23 16:12:43 -08006716 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006717
Stephen Hemmingerbea33482007-10-03 16:41:36 -07006718 bnx2_disable_int_sync(bp);
Michael Chan35efa7c2007-12-20 19:56:37 -08006719 bnx2_napi_disable(bp);
Michael Chand2e553b2012-06-27 15:08:24 +00006720 netif_tx_disable(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006721 del_timer_sync(&bp->timer);
Michael Chan74bf4ba2008-10-09 12:21:08 -07006722 bnx2_shutdown_chip(bp);
Michael Chan8e6a72c2007-05-03 13:24:48 -07006723 bnx2_free_irq(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07006724 bnx2_free_skbs(bp);
6725 bnx2_free_mem(bp);
Michael Chanf048fa92010-06-01 15:05:36 +00006726 bnx2_del_napi(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07006727 bp->link_up = 0;
6728 netif_carrier_off(bp->dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006729 return 0;
6730}
6731
Michael Chan354fcd72010-01-17 07:30:44 +00006732static void
6733bnx2_save_stats(struct bnx2 *bp)
6734{
6735 u32 *hw_stats = (u32 *) bp->stats_blk;
6736 u32 *temp_stats = (u32 *) bp->temp_stats_blk;
6737 int i;
6738
6739 /* The 1st 10 counters are 64-bit counters */
6740 for (i = 0; i < 20; i += 2) {
6741 u32 hi;
6742 u64 lo;
6743
Patrick Rabauc9885fe2010-02-15 19:42:11 +00006744 hi = temp_stats[i] + hw_stats[i];
6745 lo = (u64) temp_stats[i + 1] + (u64) hw_stats[i + 1];
Michael Chan354fcd72010-01-17 07:30:44 +00006746 if (lo > 0xffffffff)
6747 hi++;
Patrick Rabauc9885fe2010-02-15 19:42:11 +00006748 temp_stats[i] = hi;
6749 temp_stats[i + 1] = lo & 0xffffffff;
Michael Chan354fcd72010-01-17 07:30:44 +00006750 }
6751
6752 for ( ; i < sizeof(struct statistics_block) / 4; i++)
Patrick Rabauc9885fe2010-02-15 19:42:11 +00006753 temp_stats[i] += hw_stats[i];
Michael Chan354fcd72010-01-17 07:30:44 +00006754}
6755
Eric Dumazet5d07bf22010-07-08 04:08:43 +00006756#define GET_64BIT_NET_STATS64(ctr) \
6757 (((u64) (ctr##_hi) << 32) + (u64) (ctr##_lo))
Michael Chanb6016b72005-05-26 13:03:09 -07006758
Michael Chana4743052010-01-17 07:30:43 +00006759#define GET_64BIT_NET_STATS(ctr) \
Michael Chan354fcd72010-01-17 07:30:44 +00006760 GET_64BIT_NET_STATS64(bp->stats_blk->ctr) + \
6761 GET_64BIT_NET_STATS64(bp->temp_stats_blk->ctr)
Michael Chanb6016b72005-05-26 13:03:09 -07006762
Michael Chana4743052010-01-17 07:30:43 +00006763#define GET_32BIT_NET_STATS(ctr) \
Michael Chan354fcd72010-01-17 07:30:44 +00006764 (unsigned long) (bp->stats_blk->ctr + \
6765 bp->temp_stats_blk->ctr)
Michael Chana4743052010-01-17 07:30:43 +00006766
Eric Dumazet5d07bf22010-07-08 04:08:43 +00006767static struct rtnl_link_stats64 *
6768bnx2_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *net_stats)
Michael Chanb6016b72005-05-26 13:03:09 -07006769{
Michael Chan972ec0d2006-01-23 16:12:43 -08006770 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006771
Eric Dumazet5d07bf22010-07-08 04:08:43 +00006772 if (bp->stats_blk == NULL)
Michael Chanb6016b72005-05-26 13:03:09 -07006773 return net_stats;
Eric Dumazet5d07bf22010-07-08 04:08:43 +00006774
Michael Chanb6016b72005-05-26 13:03:09 -07006775 net_stats->rx_packets =
Michael Chana4743052010-01-17 07:30:43 +00006776 GET_64BIT_NET_STATS(stat_IfHCInUcastPkts) +
6777 GET_64BIT_NET_STATS(stat_IfHCInMulticastPkts) +
6778 GET_64BIT_NET_STATS(stat_IfHCInBroadcastPkts);
Michael Chanb6016b72005-05-26 13:03:09 -07006779
6780 net_stats->tx_packets =
Michael Chana4743052010-01-17 07:30:43 +00006781 GET_64BIT_NET_STATS(stat_IfHCOutUcastPkts) +
6782 GET_64BIT_NET_STATS(stat_IfHCOutMulticastPkts) +
6783 GET_64BIT_NET_STATS(stat_IfHCOutBroadcastPkts);
Michael Chanb6016b72005-05-26 13:03:09 -07006784
6785 net_stats->rx_bytes =
Michael Chana4743052010-01-17 07:30:43 +00006786 GET_64BIT_NET_STATS(stat_IfHCInOctets);
Michael Chanb6016b72005-05-26 13:03:09 -07006787
6788 net_stats->tx_bytes =
Michael Chana4743052010-01-17 07:30:43 +00006789 GET_64BIT_NET_STATS(stat_IfHCOutOctets);
Michael Chanb6016b72005-05-26 13:03:09 -07006790
Jeff Garzik6aa20a22006-09-13 13:24:59 -04006791 net_stats->multicast =
Michael Chan6fdae992010-07-19 14:15:02 +00006792 GET_64BIT_NET_STATS(stat_IfHCInMulticastPkts);
Michael Chanb6016b72005-05-26 13:03:09 -07006793
Jeff Garzik6aa20a22006-09-13 13:24:59 -04006794 net_stats->collisions =
Michael Chana4743052010-01-17 07:30:43 +00006795 GET_32BIT_NET_STATS(stat_EtherStatsCollisions);
Michael Chanb6016b72005-05-26 13:03:09 -07006796
Jeff Garzik6aa20a22006-09-13 13:24:59 -04006797 net_stats->rx_length_errors =
Michael Chana4743052010-01-17 07:30:43 +00006798 GET_32BIT_NET_STATS(stat_EtherStatsUndersizePkts) +
6799 GET_32BIT_NET_STATS(stat_EtherStatsOverrsizePkts);
Michael Chanb6016b72005-05-26 13:03:09 -07006800
Jeff Garzik6aa20a22006-09-13 13:24:59 -04006801 net_stats->rx_over_errors =
Michael Chana4743052010-01-17 07:30:43 +00006802 GET_32BIT_NET_STATS(stat_IfInFTQDiscards) +
6803 GET_32BIT_NET_STATS(stat_IfInMBUFDiscards);
Michael Chanb6016b72005-05-26 13:03:09 -07006804
Jeff Garzik6aa20a22006-09-13 13:24:59 -04006805 net_stats->rx_frame_errors =
Michael Chana4743052010-01-17 07:30:43 +00006806 GET_32BIT_NET_STATS(stat_Dot3StatsAlignmentErrors);
Michael Chanb6016b72005-05-26 13:03:09 -07006807
Jeff Garzik6aa20a22006-09-13 13:24:59 -04006808 net_stats->rx_crc_errors =
Michael Chana4743052010-01-17 07:30:43 +00006809 GET_32BIT_NET_STATS(stat_Dot3StatsFCSErrors);
Michael Chanb6016b72005-05-26 13:03:09 -07006810
6811 net_stats->rx_errors = net_stats->rx_length_errors +
6812 net_stats->rx_over_errors + net_stats->rx_frame_errors +
6813 net_stats->rx_crc_errors;
6814
6815 net_stats->tx_aborted_errors =
Michael Chana4743052010-01-17 07:30:43 +00006816 GET_32BIT_NET_STATS(stat_Dot3StatsExcessiveCollisions) +
6817 GET_32BIT_NET_STATS(stat_Dot3StatsLateCollisions);
Michael Chanb6016b72005-05-26 13:03:09 -07006818
Michael Chan4ce45e02012-12-06 10:33:10 +00006819 if ((BNX2_CHIP(bp) == BNX2_CHIP_5706) ||
6820 (BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5708_A0))
Michael Chanb6016b72005-05-26 13:03:09 -07006821 net_stats->tx_carrier_errors = 0;
6822 else {
6823 net_stats->tx_carrier_errors =
Michael Chana4743052010-01-17 07:30:43 +00006824 GET_32BIT_NET_STATS(stat_Dot3StatsCarrierSenseErrors);
Michael Chanb6016b72005-05-26 13:03:09 -07006825 }
6826
6827 net_stats->tx_errors =
Michael Chana4743052010-01-17 07:30:43 +00006828 GET_32BIT_NET_STATS(stat_emac_tx_stat_dot3statsinternalmactransmiterrors) +
Michael Chanb6016b72005-05-26 13:03:09 -07006829 net_stats->tx_aborted_errors +
6830 net_stats->tx_carrier_errors;
6831
Michael Chancea94db2006-06-12 22:16:13 -07006832 net_stats->rx_missed_errors =
Michael Chana4743052010-01-17 07:30:43 +00006833 GET_32BIT_NET_STATS(stat_IfInFTQDiscards) +
6834 GET_32BIT_NET_STATS(stat_IfInMBUFDiscards) +
6835 GET_32BIT_NET_STATS(stat_FwRxDrop);
Michael Chancea94db2006-06-12 22:16:13 -07006836
Michael Chanb6016b72005-05-26 13:03:09 -07006837 return net_stats;
6838}
6839
6840/* All ethtool functions called with rtnl_lock */
6841
6842static int
6843bnx2_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
6844{
Michael Chan972ec0d2006-01-23 16:12:43 -08006845 struct bnx2 *bp = netdev_priv(dev);
Michael Chan7b6b8342007-07-07 22:50:15 -07006846 int support_serdes = 0, support_copper = 0;
Michael Chanb6016b72005-05-26 13:03:09 -07006847
6848 cmd->supported = SUPPORTED_Autoneg;
Michael Chan583c28e2008-01-21 19:51:35 -08006849 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP) {
Michael Chan7b6b8342007-07-07 22:50:15 -07006850 support_serdes = 1;
6851 support_copper = 1;
6852 } else if (bp->phy_port == PORT_FIBRE)
6853 support_serdes = 1;
6854 else
6855 support_copper = 1;
6856
6857 if (support_serdes) {
Michael Chanb6016b72005-05-26 13:03:09 -07006858 cmd->supported |= SUPPORTED_1000baseT_Full |
6859 SUPPORTED_FIBRE;
Michael Chan583c28e2008-01-21 19:51:35 -08006860 if (bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE)
Michael Chan605a9e22007-05-03 13:23:13 -07006861 cmd->supported |= SUPPORTED_2500baseX_Full;
Michael Chanb6016b72005-05-26 13:03:09 -07006862
Michael Chanb6016b72005-05-26 13:03:09 -07006863 }
Michael Chan7b6b8342007-07-07 22:50:15 -07006864 if (support_copper) {
Michael Chanb6016b72005-05-26 13:03:09 -07006865 cmd->supported |= SUPPORTED_10baseT_Half |
6866 SUPPORTED_10baseT_Full |
6867 SUPPORTED_100baseT_Half |
6868 SUPPORTED_100baseT_Full |
6869 SUPPORTED_1000baseT_Full |
6870 SUPPORTED_TP;
6871
Michael Chanb6016b72005-05-26 13:03:09 -07006872 }
6873
Michael Chan7b6b8342007-07-07 22:50:15 -07006874 spin_lock_bh(&bp->phy_lock);
6875 cmd->port = bp->phy_port;
Michael Chanb6016b72005-05-26 13:03:09 -07006876 cmd->advertising = bp->advertising;
6877
6878 if (bp->autoneg & AUTONEG_SPEED) {
6879 cmd->autoneg = AUTONEG_ENABLE;
David Decotigny70739492011-04-27 18:32:40 +00006880 } else {
Michael Chanb6016b72005-05-26 13:03:09 -07006881 cmd->autoneg = AUTONEG_DISABLE;
6882 }
6883
6884 if (netif_carrier_ok(dev)) {
David Decotigny70739492011-04-27 18:32:40 +00006885 ethtool_cmd_speed_set(cmd, bp->line_speed);
Michael Chanb6016b72005-05-26 13:03:09 -07006886 cmd->duplex = bp->duplex;
Michael Chan4016bad2013-12-31 23:22:34 -08006887 if (!(bp->phy_flags & BNX2_PHY_FLAG_SERDES)) {
6888 if (bp->phy_flags & BNX2_PHY_FLAG_MDIX)
6889 cmd->eth_tp_mdix = ETH_TP_MDI_X;
6890 else
6891 cmd->eth_tp_mdix = ETH_TP_MDI;
6892 }
Michael Chanb6016b72005-05-26 13:03:09 -07006893 }
6894 else {
David Decotigny70739492011-04-27 18:32:40 +00006895 ethtool_cmd_speed_set(cmd, -1);
Michael Chanb6016b72005-05-26 13:03:09 -07006896 cmd->duplex = -1;
6897 }
Michael Chan7b6b8342007-07-07 22:50:15 -07006898 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07006899
6900 cmd->transceiver = XCVR_INTERNAL;
6901 cmd->phy_address = bp->phy_addr;
6902
6903 return 0;
6904}
Jeff Garzik6aa20a22006-09-13 13:24:59 -04006905
Michael Chanb6016b72005-05-26 13:03:09 -07006906static int
6907bnx2_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
6908{
Michael Chan972ec0d2006-01-23 16:12:43 -08006909 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006910 u8 autoneg = bp->autoneg;
6911 u8 req_duplex = bp->req_duplex;
6912 u16 req_line_speed = bp->req_line_speed;
6913 u32 advertising = bp->advertising;
Michael Chan7b6b8342007-07-07 22:50:15 -07006914 int err = -EINVAL;
6915
6916 spin_lock_bh(&bp->phy_lock);
6917
6918 if (cmd->port != PORT_TP && cmd->port != PORT_FIBRE)
6919 goto err_out_unlock;
6920
Michael Chan583c28e2008-01-21 19:51:35 -08006921 if (cmd->port != bp->phy_port &&
6922 !(bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP))
Michael Chan7b6b8342007-07-07 22:50:15 -07006923 goto err_out_unlock;
Michael Chanb6016b72005-05-26 13:03:09 -07006924
Michael Chand6b14482008-07-14 22:37:21 -07006925 /* If device is down, we can store the settings only if the user
6926 * is setting the currently active port.
6927 */
6928 if (!netif_running(dev) && cmd->port != bp->phy_port)
6929 goto err_out_unlock;
6930
Michael Chanb6016b72005-05-26 13:03:09 -07006931 if (cmd->autoneg == AUTONEG_ENABLE) {
6932 autoneg |= AUTONEG_SPEED;
6933
Michael Chanbeb499a2010-02-15 19:42:10 +00006934 advertising = cmd->advertising;
6935 if (cmd->port == PORT_TP) {
6936 advertising &= ETHTOOL_ALL_COPPER_SPEED;
6937 if (!advertising)
Michael Chanb6016b72005-05-26 13:03:09 -07006938 advertising = ETHTOOL_ALL_COPPER_SPEED;
Michael Chanbeb499a2010-02-15 19:42:10 +00006939 } else {
6940 advertising &= ETHTOOL_ALL_FIBRE_SPEED;
6941 if (!advertising)
6942 advertising = ETHTOOL_ALL_FIBRE_SPEED;
Michael Chanb6016b72005-05-26 13:03:09 -07006943 }
6944 advertising |= ADVERTISED_Autoneg;
6945 }
6946 else {
David Decotigny25db0332011-04-27 18:32:39 +00006947 u32 speed = ethtool_cmd_speed(cmd);
Michael Chan7b6b8342007-07-07 22:50:15 -07006948 if (cmd->port == PORT_FIBRE) {
David Decotigny25db0332011-04-27 18:32:39 +00006949 if ((speed != SPEED_1000 &&
6950 speed != SPEED_2500) ||
Michael Chan80be4432006-11-19 14:07:28 -08006951 (cmd->duplex != DUPLEX_FULL))
Michael Chan7b6b8342007-07-07 22:50:15 -07006952 goto err_out_unlock;
Michael Chan80be4432006-11-19 14:07:28 -08006953
David Decotigny25db0332011-04-27 18:32:39 +00006954 if (speed == SPEED_2500 &&
Michael Chan583c28e2008-01-21 19:51:35 -08006955 !(bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE))
Michael Chan7b6b8342007-07-07 22:50:15 -07006956 goto err_out_unlock;
David Decotigny25db0332011-04-27 18:32:39 +00006957 } else if (speed == SPEED_1000 || speed == SPEED_2500)
Michael Chan7b6b8342007-07-07 22:50:15 -07006958 goto err_out_unlock;
6959
Michael Chanb6016b72005-05-26 13:03:09 -07006960 autoneg &= ~AUTONEG_SPEED;
David Decotigny25db0332011-04-27 18:32:39 +00006961 req_line_speed = speed;
Michael Chanb6016b72005-05-26 13:03:09 -07006962 req_duplex = cmd->duplex;
6963 advertising = 0;
6964 }
6965
6966 bp->autoneg = autoneg;
6967 bp->advertising = advertising;
6968 bp->req_line_speed = req_line_speed;
6969 bp->req_duplex = req_duplex;
6970
Michael Chand6b14482008-07-14 22:37:21 -07006971 err = 0;
6972 /* If device is down, the new settings will be picked up when it is
6973 * brought up.
6974 */
6975 if (netif_running(dev))
6976 err = bnx2_setup_phy(bp, cmd->port);
Michael Chanb6016b72005-05-26 13:03:09 -07006977
Michael Chan7b6b8342007-07-07 22:50:15 -07006978err_out_unlock:
Michael Chanc770a652005-08-25 15:38:39 -07006979 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07006980
Michael Chan7b6b8342007-07-07 22:50:15 -07006981 return err;
Michael Chanb6016b72005-05-26 13:03:09 -07006982}
6983
6984static void
6985bnx2_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
6986{
Michael Chan972ec0d2006-01-23 16:12:43 -08006987 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006988
Rick Jones68aad782011-11-07 13:29:27 +00006989 strlcpy(info->driver, DRV_MODULE_NAME, sizeof(info->driver));
6990 strlcpy(info->version, DRV_MODULE_VERSION, sizeof(info->version));
6991 strlcpy(info->bus_info, pci_name(bp->pdev), sizeof(info->bus_info));
6992 strlcpy(info->fw_version, bp->fw_version, sizeof(info->fw_version));
Michael Chanb6016b72005-05-26 13:03:09 -07006993}
6994
Michael Chan244ac4f2006-03-20 17:48:46 -08006995#define BNX2_REGDUMP_LEN (32 * 1024)
6996
6997static int
6998bnx2_get_regs_len(struct net_device *dev)
6999{
7000 return BNX2_REGDUMP_LEN;
7001}
7002
7003static void
7004bnx2_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *_p)
7005{
7006 u32 *p = _p, i, offset;
7007 u8 *orig_p = _p;
7008 struct bnx2 *bp = netdev_priv(dev);
Joe Perchesb6bc7652010-12-21 02:16:08 -08007009 static const u32 reg_boundaries[] = {
7010 0x0000, 0x0098, 0x0400, 0x045c,
7011 0x0800, 0x0880, 0x0c00, 0x0c10,
7012 0x0c30, 0x0d08, 0x1000, 0x101c,
7013 0x1040, 0x1048, 0x1080, 0x10a4,
7014 0x1400, 0x1490, 0x1498, 0x14f0,
7015 0x1500, 0x155c, 0x1580, 0x15dc,
7016 0x1600, 0x1658, 0x1680, 0x16d8,
7017 0x1800, 0x1820, 0x1840, 0x1854,
7018 0x1880, 0x1894, 0x1900, 0x1984,
7019 0x1c00, 0x1c0c, 0x1c40, 0x1c54,
7020 0x1c80, 0x1c94, 0x1d00, 0x1d84,
7021 0x2000, 0x2030, 0x23c0, 0x2400,
7022 0x2800, 0x2820, 0x2830, 0x2850,
7023 0x2b40, 0x2c10, 0x2fc0, 0x3058,
7024 0x3c00, 0x3c94, 0x4000, 0x4010,
7025 0x4080, 0x4090, 0x43c0, 0x4458,
7026 0x4c00, 0x4c18, 0x4c40, 0x4c54,
7027 0x4fc0, 0x5010, 0x53c0, 0x5444,
7028 0x5c00, 0x5c18, 0x5c80, 0x5c90,
7029 0x5fc0, 0x6000, 0x6400, 0x6428,
7030 0x6800, 0x6848, 0x684c, 0x6860,
7031 0x6888, 0x6910, 0x8000
7032 };
Michael Chan244ac4f2006-03-20 17:48:46 -08007033
7034 regs->version = 0;
7035
7036 memset(p, 0, BNX2_REGDUMP_LEN);
7037
7038 if (!netif_running(bp->dev))
7039 return;
7040
7041 i = 0;
7042 offset = reg_boundaries[0];
7043 p += offset;
7044 while (offset < BNX2_REGDUMP_LEN) {
Michael Chane503e062012-12-06 10:33:08 +00007045 *p++ = BNX2_RD(bp, offset);
Michael Chan244ac4f2006-03-20 17:48:46 -08007046 offset += 4;
7047 if (offset == reg_boundaries[i + 1]) {
7048 offset = reg_boundaries[i + 2];
7049 p = (u32 *) (orig_p + offset);
7050 i += 2;
7051 }
7052 }
7053}
7054
Michael Chanb6016b72005-05-26 13:03:09 -07007055static void
7056bnx2_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
7057{
Michael Chan972ec0d2006-01-23 16:12:43 -08007058 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007059
David S. Millerf86e82f2008-01-21 17:15:40 -08007060 if (bp->flags & BNX2_FLAG_NO_WOL) {
Michael Chanb6016b72005-05-26 13:03:09 -07007061 wol->supported = 0;
7062 wol->wolopts = 0;
7063 }
7064 else {
7065 wol->supported = WAKE_MAGIC;
7066 if (bp->wol)
7067 wol->wolopts = WAKE_MAGIC;
7068 else
7069 wol->wolopts = 0;
7070 }
7071 memset(&wol->sopass, 0, sizeof(wol->sopass));
7072}
7073
7074static int
7075bnx2_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
7076{
Michael Chan972ec0d2006-01-23 16:12:43 -08007077 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007078
7079 if (wol->wolopts & ~WAKE_MAGIC)
7080 return -EINVAL;
7081
7082 if (wol->wolopts & WAKE_MAGIC) {
David S. Millerf86e82f2008-01-21 17:15:40 -08007083 if (bp->flags & BNX2_FLAG_NO_WOL)
Michael Chanb6016b72005-05-26 13:03:09 -07007084 return -EINVAL;
7085
7086 bp->wol = 1;
7087 }
7088 else {
7089 bp->wol = 0;
7090 }
Michael Chan6d5e85c2013-08-06 15:50:08 -07007091
7092 device_set_wakeup_enable(&bp->pdev->dev, bp->wol);
7093
Michael Chanb6016b72005-05-26 13:03:09 -07007094 return 0;
7095}
7096
7097static int
7098bnx2_nway_reset(struct net_device *dev)
7099{
Michael Chan972ec0d2006-01-23 16:12:43 -08007100 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007101 u32 bmcr;
7102
Michael Chan9f52b562008-10-09 12:21:46 -07007103 if (!netif_running(dev))
7104 return -EAGAIN;
7105
Michael Chanb6016b72005-05-26 13:03:09 -07007106 if (!(bp->autoneg & AUTONEG_SPEED)) {
7107 return -EINVAL;
7108 }
7109
Michael Chanc770a652005-08-25 15:38:39 -07007110 spin_lock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07007111
Michael Chan583c28e2008-01-21 19:51:35 -08007112 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP) {
Michael Chan7b6b8342007-07-07 22:50:15 -07007113 int rc;
7114
7115 rc = bnx2_setup_remote_phy(bp, bp->phy_port);
7116 spin_unlock_bh(&bp->phy_lock);
7117 return rc;
7118 }
7119
Michael Chanb6016b72005-05-26 13:03:09 -07007120 /* Force a link down visible on the other side */
Michael Chan583c28e2008-01-21 19:51:35 -08007121 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Michael Chanca58c3a2007-05-03 13:22:52 -07007122 bnx2_write_phy(bp, bp->mii_bmcr, BMCR_LOOPBACK);
Michael Chanc770a652005-08-25 15:38:39 -07007123 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07007124
7125 msleep(20);
7126
Michael Chanc770a652005-08-25 15:38:39 -07007127 spin_lock_bh(&bp->phy_lock);
Michael Chanf8dd0642006-11-19 14:08:29 -08007128
Michael Chan40105c02008-11-12 16:02:45 -08007129 bp->current_interval = BNX2_SERDES_AN_TIMEOUT;
Michael Chanf8dd0642006-11-19 14:08:29 -08007130 bp->serdes_an_pending = 1;
7131 mod_timer(&bp->timer, jiffies + bp->current_interval);
Michael Chanb6016b72005-05-26 13:03:09 -07007132 }
7133
Michael Chanca58c3a2007-05-03 13:22:52 -07007134 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chanb6016b72005-05-26 13:03:09 -07007135 bmcr &= ~BMCR_LOOPBACK;
Michael Chanca58c3a2007-05-03 13:22:52 -07007136 bnx2_write_phy(bp, bp->mii_bmcr, bmcr | BMCR_ANRESTART | BMCR_ANENABLE);
Michael Chanb6016b72005-05-26 13:03:09 -07007137
Michael Chanc770a652005-08-25 15:38:39 -07007138 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07007139
7140 return 0;
7141}
7142
Ooiwa Naohiro7959ea22009-06-24 00:19:06 -07007143static u32
7144bnx2_get_link(struct net_device *dev)
7145{
7146 struct bnx2 *bp = netdev_priv(dev);
7147
7148 return bp->link_up;
7149}
7150
Michael Chanb6016b72005-05-26 13:03:09 -07007151static int
7152bnx2_get_eeprom_len(struct net_device *dev)
7153{
Michael Chan972ec0d2006-01-23 16:12:43 -08007154 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007155
Michael Chan1122db72006-01-23 16:11:42 -08007156 if (bp->flash_info == NULL)
Michael Chanb6016b72005-05-26 13:03:09 -07007157 return 0;
7158
Michael Chan1122db72006-01-23 16:11:42 -08007159 return (int) bp->flash_size;
Michael Chanb6016b72005-05-26 13:03:09 -07007160}
7161
7162static int
7163bnx2_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
7164 u8 *eebuf)
7165{
Michael Chan972ec0d2006-01-23 16:12:43 -08007166 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007167 int rc;
7168
John W. Linville1064e942005-11-10 12:58:24 -08007169 /* parameters already validated in ethtool_get_eeprom */
Michael Chanb6016b72005-05-26 13:03:09 -07007170
7171 rc = bnx2_nvram_read(bp, eeprom->offset, eebuf, eeprom->len);
7172
7173 return rc;
7174}
7175
7176static int
7177bnx2_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
7178 u8 *eebuf)
7179{
Michael Chan972ec0d2006-01-23 16:12:43 -08007180 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007181 int rc;
7182
John W. Linville1064e942005-11-10 12:58:24 -08007183 /* parameters already validated in ethtool_set_eeprom */
Michael Chanb6016b72005-05-26 13:03:09 -07007184
7185 rc = bnx2_nvram_write(bp, eeprom->offset, eebuf, eeprom->len);
7186
7187 return rc;
7188}
7189
7190static int
7191bnx2_get_coalesce(struct net_device *dev, struct ethtool_coalesce *coal)
7192{
Michael Chan972ec0d2006-01-23 16:12:43 -08007193 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007194
7195 memset(coal, 0, sizeof(struct ethtool_coalesce));
7196
7197 coal->rx_coalesce_usecs = bp->rx_ticks;
7198 coal->rx_max_coalesced_frames = bp->rx_quick_cons_trip;
7199 coal->rx_coalesce_usecs_irq = bp->rx_ticks_int;
7200 coal->rx_max_coalesced_frames_irq = bp->rx_quick_cons_trip_int;
7201
7202 coal->tx_coalesce_usecs = bp->tx_ticks;
7203 coal->tx_max_coalesced_frames = bp->tx_quick_cons_trip;
7204 coal->tx_coalesce_usecs_irq = bp->tx_ticks_int;
7205 coal->tx_max_coalesced_frames_irq = bp->tx_quick_cons_trip_int;
7206
7207 coal->stats_block_coalesce_usecs = bp->stats_ticks;
7208
7209 return 0;
7210}
7211
7212static int
7213bnx2_set_coalesce(struct net_device *dev, struct ethtool_coalesce *coal)
7214{
Michael Chan972ec0d2006-01-23 16:12:43 -08007215 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007216
7217 bp->rx_ticks = (u16) coal->rx_coalesce_usecs;
7218 if (bp->rx_ticks > 0x3ff) bp->rx_ticks = 0x3ff;
7219
Jeff Garzik6aa20a22006-09-13 13:24:59 -04007220 bp->rx_quick_cons_trip = (u16) coal->rx_max_coalesced_frames;
Michael Chanb6016b72005-05-26 13:03:09 -07007221 if (bp->rx_quick_cons_trip > 0xff) bp->rx_quick_cons_trip = 0xff;
7222
7223 bp->rx_ticks_int = (u16) coal->rx_coalesce_usecs_irq;
7224 if (bp->rx_ticks_int > 0x3ff) bp->rx_ticks_int = 0x3ff;
7225
7226 bp->rx_quick_cons_trip_int = (u16) coal->rx_max_coalesced_frames_irq;
7227 if (bp->rx_quick_cons_trip_int > 0xff)
7228 bp->rx_quick_cons_trip_int = 0xff;
7229
7230 bp->tx_ticks = (u16) coal->tx_coalesce_usecs;
7231 if (bp->tx_ticks > 0x3ff) bp->tx_ticks = 0x3ff;
7232
7233 bp->tx_quick_cons_trip = (u16) coal->tx_max_coalesced_frames;
7234 if (bp->tx_quick_cons_trip > 0xff) bp->tx_quick_cons_trip = 0xff;
7235
7236 bp->tx_ticks_int = (u16) coal->tx_coalesce_usecs_irq;
7237 if (bp->tx_ticks_int > 0x3ff) bp->tx_ticks_int = 0x3ff;
7238
7239 bp->tx_quick_cons_trip_int = (u16) coal->tx_max_coalesced_frames_irq;
7240 if (bp->tx_quick_cons_trip_int > 0xff) bp->tx_quick_cons_trip_int =
7241 0xff;
7242
7243 bp->stats_ticks = coal->stats_block_coalesce_usecs;
Michael Chan61d9e3f2009-08-21 16:20:46 +00007244 if (bp->flags & BNX2_FLAG_BROKEN_STATS) {
Michael Chan02537b062007-06-04 21:24:07 -07007245 if (bp->stats_ticks != 0 && bp->stats_ticks != USEC_PER_SEC)
7246 bp->stats_ticks = USEC_PER_SEC;
7247 }
Michael Chan7ea69202007-07-16 18:27:10 -07007248 if (bp->stats_ticks > BNX2_HC_STATS_TICKS_HC_STAT_TICKS)
7249 bp->stats_ticks = BNX2_HC_STATS_TICKS_HC_STAT_TICKS;
7250 bp->stats_ticks &= BNX2_HC_STATS_TICKS_HC_STAT_TICKS;
Michael Chanb6016b72005-05-26 13:03:09 -07007251
7252 if (netif_running(bp->dev)) {
Michael Chan212f9932010-04-27 11:28:10 +00007253 bnx2_netif_stop(bp, true);
Michael Chan9a120bc2008-05-16 22:17:45 -07007254 bnx2_init_nic(bp, 0);
Michael Chan212f9932010-04-27 11:28:10 +00007255 bnx2_netif_start(bp, true);
Michael Chanb6016b72005-05-26 13:03:09 -07007256 }
7257
7258 return 0;
7259}
7260
7261static void
7262bnx2_get_ringparam(struct net_device *dev, struct ethtool_ringparam *ering)
7263{
Michael Chan972ec0d2006-01-23 16:12:43 -08007264 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007265
Michael Chan2bc40782012-12-06 10:33:09 +00007266 ering->rx_max_pending = BNX2_MAX_TOTAL_RX_DESC_CNT;
7267 ering->rx_jumbo_max_pending = BNX2_MAX_TOTAL_RX_PG_DESC_CNT;
Michael Chanb6016b72005-05-26 13:03:09 -07007268
7269 ering->rx_pending = bp->rx_ring_size;
Michael Chan47bf4242007-12-12 11:19:12 -08007270 ering->rx_jumbo_pending = bp->rx_pg_ring_size;
Michael Chanb6016b72005-05-26 13:03:09 -07007271
Michael Chan2bc40782012-12-06 10:33:09 +00007272 ering->tx_max_pending = BNX2_MAX_TX_DESC_CNT;
Michael Chanb6016b72005-05-26 13:03:09 -07007273 ering->tx_pending = bp->tx_ring_size;
7274}
7275
7276static int
Michael Chanb0332812012-02-05 15:24:38 +00007277bnx2_change_ring_size(struct bnx2 *bp, u32 rx, u32 tx, bool reset_irq)
Michael Chanb6016b72005-05-26 13:03:09 -07007278{
Michael Chan13daffa2006-03-20 17:49:20 -08007279 if (netif_running(bp->dev)) {
Michael Chan354fcd72010-01-17 07:30:44 +00007280 /* Reset will erase chipset stats; save them */
7281 bnx2_save_stats(bp);
7282
Michael Chan212f9932010-04-27 11:28:10 +00007283 bnx2_netif_stop(bp, true);
Michael Chan13daffa2006-03-20 17:49:20 -08007284 bnx2_reset_chip(bp, BNX2_DRV_MSG_CODE_RESET);
Michael Chanb0332812012-02-05 15:24:38 +00007285 if (reset_irq) {
7286 bnx2_free_irq(bp);
7287 bnx2_del_napi(bp);
7288 } else {
7289 __bnx2_free_irq(bp);
7290 }
Michael Chan13daffa2006-03-20 17:49:20 -08007291 bnx2_free_skbs(bp);
7292 bnx2_free_mem(bp);
7293 }
7294
Michael Chan5d5d0012007-12-12 11:17:43 -08007295 bnx2_set_rx_ring_size(bp, rx);
7296 bp->tx_ring_size = tx;
Michael Chanb6016b72005-05-26 13:03:09 -07007297
7298 if (netif_running(bp->dev)) {
Michael Chanb0332812012-02-05 15:24:38 +00007299 int rc = 0;
Michael Chan13daffa2006-03-20 17:49:20 -08007300
Michael Chanb0332812012-02-05 15:24:38 +00007301 if (reset_irq) {
7302 rc = bnx2_setup_int_mode(bp, disable_msi);
7303 bnx2_init_napi(bp);
7304 }
7305
7306 if (!rc)
7307 rc = bnx2_alloc_mem(bp);
7308
Michael Chan6fefb652009-08-21 16:20:45 +00007309 if (!rc)
Michael Chana29ba9d2010-12-31 11:03:14 -08007310 rc = bnx2_request_irq(bp);
7311
7312 if (!rc)
Michael Chan6fefb652009-08-21 16:20:45 +00007313 rc = bnx2_init_nic(bp, 0);
7314
7315 if (rc) {
7316 bnx2_napi_enable(bp);
7317 dev_close(bp->dev);
Michael Chan13daffa2006-03-20 17:49:20 -08007318 return rc;
Michael Chan6fefb652009-08-21 16:20:45 +00007319 }
Michael Chane9f26c42010-02-15 19:42:08 +00007320#ifdef BCM_CNIC
7321 mutex_lock(&bp->cnic_lock);
7322 /* Let cnic know about the new status block. */
7323 if (bp->cnic_eth_dev.drv_state & CNIC_DRV_STATE_REGD)
7324 bnx2_setup_cnic_irq_info(bp);
7325 mutex_unlock(&bp->cnic_lock);
7326#endif
Michael Chan212f9932010-04-27 11:28:10 +00007327 bnx2_netif_start(bp, true);
Michael Chanb6016b72005-05-26 13:03:09 -07007328 }
Michael Chanb6016b72005-05-26 13:03:09 -07007329 return 0;
7330}
7331
Michael Chan5d5d0012007-12-12 11:17:43 -08007332static int
7333bnx2_set_ringparam(struct net_device *dev, struct ethtool_ringparam *ering)
7334{
7335 struct bnx2 *bp = netdev_priv(dev);
7336 int rc;
7337
Michael Chan2bc40782012-12-06 10:33:09 +00007338 if ((ering->rx_pending > BNX2_MAX_TOTAL_RX_DESC_CNT) ||
7339 (ering->tx_pending > BNX2_MAX_TX_DESC_CNT) ||
Michael Chan5d5d0012007-12-12 11:17:43 -08007340 (ering->tx_pending <= MAX_SKB_FRAGS)) {
7341
7342 return -EINVAL;
7343 }
Michael Chanb0332812012-02-05 15:24:38 +00007344 rc = bnx2_change_ring_size(bp, ering->rx_pending, ering->tx_pending,
7345 false);
Michael Chan5d5d0012007-12-12 11:17:43 -08007346 return rc;
7347}
7348
Michael Chanb6016b72005-05-26 13:03:09 -07007349static void
7350bnx2_get_pauseparam(struct net_device *dev, struct ethtool_pauseparam *epause)
7351{
Michael Chan972ec0d2006-01-23 16:12:43 -08007352 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007353
7354 epause->autoneg = ((bp->autoneg & AUTONEG_FLOW_CTRL) != 0);
7355 epause->rx_pause = ((bp->flow_ctrl & FLOW_CTRL_RX) != 0);
7356 epause->tx_pause = ((bp->flow_ctrl & FLOW_CTRL_TX) != 0);
7357}
7358
7359static int
7360bnx2_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam *epause)
7361{
Michael Chan972ec0d2006-01-23 16:12:43 -08007362 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007363
7364 bp->req_flow_ctrl = 0;
7365 if (epause->rx_pause)
7366 bp->req_flow_ctrl |= FLOW_CTRL_RX;
7367 if (epause->tx_pause)
7368 bp->req_flow_ctrl |= FLOW_CTRL_TX;
7369
7370 if (epause->autoneg) {
7371 bp->autoneg |= AUTONEG_FLOW_CTRL;
7372 }
7373 else {
7374 bp->autoneg &= ~AUTONEG_FLOW_CTRL;
7375 }
7376
Michael Chan9f52b562008-10-09 12:21:46 -07007377 if (netif_running(dev)) {
7378 spin_lock_bh(&bp->phy_lock);
7379 bnx2_setup_phy(bp, bp->phy_port);
7380 spin_unlock_bh(&bp->phy_lock);
7381 }
Michael Chanb6016b72005-05-26 13:03:09 -07007382
7383 return 0;
7384}
7385
Peter Hagervall14ab9b82005-08-10 14:18:16 -07007386static struct {
Michael Chanb6016b72005-05-26 13:03:09 -07007387 char string[ETH_GSTRING_LEN];
Michael Chan790dab22009-08-21 16:20:47 +00007388} bnx2_stats_str_arr[] = {
Michael Chanb6016b72005-05-26 13:03:09 -07007389 { "rx_bytes" },
7390 { "rx_error_bytes" },
7391 { "tx_bytes" },
7392 { "tx_error_bytes" },
7393 { "rx_ucast_packets" },
7394 { "rx_mcast_packets" },
7395 { "rx_bcast_packets" },
7396 { "tx_ucast_packets" },
7397 { "tx_mcast_packets" },
7398 { "tx_bcast_packets" },
7399 { "tx_mac_errors" },
7400 { "tx_carrier_errors" },
7401 { "rx_crc_errors" },
7402 { "rx_align_errors" },
7403 { "tx_single_collisions" },
7404 { "tx_multi_collisions" },
7405 { "tx_deferred" },
7406 { "tx_excess_collisions" },
7407 { "tx_late_collisions" },
7408 { "tx_total_collisions" },
7409 { "rx_fragments" },
7410 { "rx_jabbers" },
7411 { "rx_undersize_packets" },
7412 { "rx_oversize_packets" },
7413 { "rx_64_byte_packets" },
7414 { "rx_65_to_127_byte_packets" },
7415 { "rx_128_to_255_byte_packets" },
7416 { "rx_256_to_511_byte_packets" },
7417 { "rx_512_to_1023_byte_packets" },
7418 { "rx_1024_to_1522_byte_packets" },
7419 { "rx_1523_to_9022_byte_packets" },
7420 { "tx_64_byte_packets" },
7421 { "tx_65_to_127_byte_packets" },
7422 { "tx_128_to_255_byte_packets" },
7423 { "tx_256_to_511_byte_packets" },
7424 { "tx_512_to_1023_byte_packets" },
7425 { "tx_1024_to_1522_byte_packets" },
7426 { "tx_1523_to_9022_byte_packets" },
7427 { "rx_xon_frames" },
7428 { "rx_xoff_frames" },
7429 { "tx_xon_frames" },
7430 { "tx_xoff_frames" },
7431 { "rx_mac_ctrl_frames" },
7432 { "rx_filtered_packets" },
Michael Chan790dab22009-08-21 16:20:47 +00007433 { "rx_ftq_discards" },
Michael Chanb6016b72005-05-26 13:03:09 -07007434 { "rx_discards" },
Michael Chancea94db2006-06-12 22:16:13 -07007435 { "rx_fw_discards" },
Michael Chanb6016b72005-05-26 13:03:09 -07007436};
7437
Jim Cromie0db83cd2012-04-10 14:56:03 +00007438#define BNX2_NUM_STATS ARRAY_SIZE(bnx2_stats_str_arr)
Michael Chan790dab22009-08-21 16:20:47 +00007439
Michael Chanb6016b72005-05-26 13:03:09 -07007440#define STATS_OFFSET32(offset_name) (offsetof(struct statistics_block, offset_name) / 4)
7441
Arjan van de Venf71e1302006-03-03 21:33:57 -05007442static const unsigned long bnx2_stats_offset_arr[BNX2_NUM_STATS] = {
Michael Chanb6016b72005-05-26 13:03:09 -07007443 STATS_OFFSET32(stat_IfHCInOctets_hi),
7444 STATS_OFFSET32(stat_IfHCInBadOctets_hi),
7445 STATS_OFFSET32(stat_IfHCOutOctets_hi),
7446 STATS_OFFSET32(stat_IfHCOutBadOctets_hi),
7447 STATS_OFFSET32(stat_IfHCInUcastPkts_hi),
7448 STATS_OFFSET32(stat_IfHCInMulticastPkts_hi),
7449 STATS_OFFSET32(stat_IfHCInBroadcastPkts_hi),
7450 STATS_OFFSET32(stat_IfHCOutUcastPkts_hi),
7451 STATS_OFFSET32(stat_IfHCOutMulticastPkts_hi),
7452 STATS_OFFSET32(stat_IfHCOutBroadcastPkts_hi),
7453 STATS_OFFSET32(stat_emac_tx_stat_dot3statsinternalmactransmiterrors),
Jeff Garzik6aa20a22006-09-13 13:24:59 -04007454 STATS_OFFSET32(stat_Dot3StatsCarrierSenseErrors),
7455 STATS_OFFSET32(stat_Dot3StatsFCSErrors),
7456 STATS_OFFSET32(stat_Dot3StatsAlignmentErrors),
7457 STATS_OFFSET32(stat_Dot3StatsSingleCollisionFrames),
7458 STATS_OFFSET32(stat_Dot3StatsMultipleCollisionFrames),
7459 STATS_OFFSET32(stat_Dot3StatsDeferredTransmissions),
7460 STATS_OFFSET32(stat_Dot3StatsExcessiveCollisions),
7461 STATS_OFFSET32(stat_Dot3StatsLateCollisions),
7462 STATS_OFFSET32(stat_EtherStatsCollisions),
7463 STATS_OFFSET32(stat_EtherStatsFragments),
7464 STATS_OFFSET32(stat_EtherStatsJabbers),
7465 STATS_OFFSET32(stat_EtherStatsUndersizePkts),
7466 STATS_OFFSET32(stat_EtherStatsOverrsizePkts),
7467 STATS_OFFSET32(stat_EtherStatsPktsRx64Octets),
7468 STATS_OFFSET32(stat_EtherStatsPktsRx65Octetsto127Octets),
7469 STATS_OFFSET32(stat_EtherStatsPktsRx128Octetsto255Octets),
7470 STATS_OFFSET32(stat_EtherStatsPktsRx256Octetsto511Octets),
7471 STATS_OFFSET32(stat_EtherStatsPktsRx512Octetsto1023Octets),
7472 STATS_OFFSET32(stat_EtherStatsPktsRx1024Octetsto1522Octets),
7473 STATS_OFFSET32(stat_EtherStatsPktsRx1523Octetsto9022Octets),
7474 STATS_OFFSET32(stat_EtherStatsPktsTx64Octets),
7475 STATS_OFFSET32(stat_EtherStatsPktsTx65Octetsto127Octets),
7476 STATS_OFFSET32(stat_EtherStatsPktsTx128Octetsto255Octets),
7477 STATS_OFFSET32(stat_EtherStatsPktsTx256Octetsto511Octets),
7478 STATS_OFFSET32(stat_EtherStatsPktsTx512Octetsto1023Octets),
7479 STATS_OFFSET32(stat_EtherStatsPktsTx1024Octetsto1522Octets),
7480 STATS_OFFSET32(stat_EtherStatsPktsTx1523Octetsto9022Octets),
7481 STATS_OFFSET32(stat_XonPauseFramesReceived),
7482 STATS_OFFSET32(stat_XoffPauseFramesReceived),
7483 STATS_OFFSET32(stat_OutXonSent),
7484 STATS_OFFSET32(stat_OutXoffSent),
7485 STATS_OFFSET32(stat_MacControlFramesReceived),
7486 STATS_OFFSET32(stat_IfInFramesL2FilterDiscards),
Michael Chan790dab22009-08-21 16:20:47 +00007487 STATS_OFFSET32(stat_IfInFTQDiscards),
Jeff Garzik6aa20a22006-09-13 13:24:59 -04007488 STATS_OFFSET32(stat_IfInMBUFDiscards),
Michael Chancea94db2006-06-12 22:16:13 -07007489 STATS_OFFSET32(stat_FwRxDrop),
Michael Chanb6016b72005-05-26 13:03:09 -07007490};
7491
7492/* stat_IfHCInBadOctets and stat_Dot3StatsCarrierSenseErrors are
7493 * skipped because of errata.
Jeff Garzik6aa20a22006-09-13 13:24:59 -04007494 */
Peter Hagervall14ab9b82005-08-10 14:18:16 -07007495static u8 bnx2_5706_stats_len_arr[BNX2_NUM_STATS] = {
Michael Chanb6016b72005-05-26 13:03:09 -07007496 8,0,8,8,8,8,8,8,8,8,
7497 4,0,4,4,4,4,4,4,4,4,
7498 4,4,4,4,4,4,4,4,4,4,
7499 4,4,4,4,4,4,4,4,4,4,
Michael Chan790dab22009-08-21 16:20:47 +00007500 4,4,4,4,4,4,4,
Michael Chanb6016b72005-05-26 13:03:09 -07007501};
7502
Michael Chan5b0c76a2005-11-04 08:45:49 -08007503static u8 bnx2_5708_stats_len_arr[BNX2_NUM_STATS] = {
7504 8,0,8,8,8,8,8,8,8,8,
7505 4,4,4,4,4,4,4,4,4,4,
7506 4,4,4,4,4,4,4,4,4,4,
7507 4,4,4,4,4,4,4,4,4,4,
Michael Chan790dab22009-08-21 16:20:47 +00007508 4,4,4,4,4,4,4,
Michael Chan5b0c76a2005-11-04 08:45:49 -08007509};
7510
Michael Chanb6016b72005-05-26 13:03:09 -07007511#define BNX2_NUM_TESTS 6
7512
Peter Hagervall14ab9b82005-08-10 14:18:16 -07007513static struct {
Michael Chanb6016b72005-05-26 13:03:09 -07007514 char string[ETH_GSTRING_LEN];
7515} bnx2_tests_str_arr[BNX2_NUM_TESTS] = {
7516 { "register_test (offline)" },
7517 { "memory_test (offline)" },
7518 { "loopback_test (offline)" },
7519 { "nvram_test (online)" },
7520 { "interrupt_test (online)" },
7521 { "link_test (online)" },
7522};
7523
7524static int
Jeff Garzikb9f2c042007-10-03 18:07:32 -07007525bnx2_get_sset_count(struct net_device *dev, int sset)
Michael Chanb6016b72005-05-26 13:03:09 -07007526{
Jeff Garzikb9f2c042007-10-03 18:07:32 -07007527 switch (sset) {
7528 case ETH_SS_TEST:
7529 return BNX2_NUM_TESTS;
7530 case ETH_SS_STATS:
7531 return BNX2_NUM_STATS;
7532 default:
7533 return -EOPNOTSUPP;
7534 }
Michael Chanb6016b72005-05-26 13:03:09 -07007535}
7536
7537static void
7538bnx2_self_test(struct net_device *dev, struct ethtool_test *etest, u64 *buf)
7539{
Michael Chan972ec0d2006-01-23 16:12:43 -08007540 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007541
7542 memset(buf, 0, sizeof(u64) * BNX2_NUM_TESTS);
7543 if (etest->flags & ETH_TEST_FL_OFFLINE) {
Michael Chan80be4432006-11-19 14:07:28 -08007544 int i;
7545
Michael Chan212f9932010-04-27 11:28:10 +00007546 bnx2_netif_stop(bp, true);
Michael Chanb6016b72005-05-26 13:03:09 -07007547 bnx2_reset_chip(bp, BNX2_DRV_MSG_CODE_DIAG);
7548 bnx2_free_skbs(bp);
7549
7550 if (bnx2_test_registers(bp) != 0) {
7551 buf[0] = 1;
7552 etest->flags |= ETH_TEST_FL_FAILED;
7553 }
7554 if (bnx2_test_memory(bp) != 0) {
7555 buf[1] = 1;
7556 etest->flags |= ETH_TEST_FL_FAILED;
7557 }
Michael Chanbc5a0692006-01-23 16:13:22 -08007558 if ((buf[2] = bnx2_test_loopback(bp)) != 0)
Michael Chanb6016b72005-05-26 13:03:09 -07007559 etest->flags |= ETH_TEST_FL_FAILED;
Michael Chanb6016b72005-05-26 13:03:09 -07007560
Michael Chan9f52b562008-10-09 12:21:46 -07007561 if (!netif_running(bp->dev))
7562 bnx2_shutdown_chip(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07007563 else {
Michael Chan9a120bc2008-05-16 22:17:45 -07007564 bnx2_init_nic(bp, 1);
Michael Chan212f9932010-04-27 11:28:10 +00007565 bnx2_netif_start(bp, true);
Michael Chanb6016b72005-05-26 13:03:09 -07007566 }
7567
7568 /* wait for link up */
Michael Chan80be4432006-11-19 14:07:28 -08007569 for (i = 0; i < 7; i++) {
7570 if (bp->link_up)
7571 break;
7572 msleep_interruptible(1000);
7573 }
Michael Chanb6016b72005-05-26 13:03:09 -07007574 }
7575
7576 if (bnx2_test_nvram(bp) != 0) {
7577 buf[3] = 1;
7578 etest->flags |= ETH_TEST_FL_FAILED;
7579 }
7580 if (bnx2_test_intr(bp) != 0) {
7581 buf[4] = 1;
7582 etest->flags |= ETH_TEST_FL_FAILED;
7583 }
7584
7585 if (bnx2_test_link(bp) != 0) {
7586 buf[5] = 1;
7587 etest->flags |= ETH_TEST_FL_FAILED;
7588
7589 }
7590}
7591
7592static void
7593bnx2_get_strings(struct net_device *dev, u32 stringset, u8 *buf)
7594{
7595 switch (stringset) {
7596 case ETH_SS_STATS:
7597 memcpy(buf, bnx2_stats_str_arr,
7598 sizeof(bnx2_stats_str_arr));
7599 break;
7600 case ETH_SS_TEST:
7601 memcpy(buf, bnx2_tests_str_arr,
7602 sizeof(bnx2_tests_str_arr));
7603 break;
7604 }
7605}
7606
Michael Chanb6016b72005-05-26 13:03:09 -07007607static void
7608bnx2_get_ethtool_stats(struct net_device *dev,
7609 struct ethtool_stats *stats, u64 *buf)
7610{
Michael Chan972ec0d2006-01-23 16:12:43 -08007611 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007612 int i;
7613 u32 *hw_stats = (u32 *) bp->stats_blk;
Michael Chan354fcd72010-01-17 07:30:44 +00007614 u32 *temp_stats = (u32 *) bp->temp_stats_blk;
Peter Hagervall14ab9b82005-08-10 14:18:16 -07007615 u8 *stats_len_arr = NULL;
Michael Chanb6016b72005-05-26 13:03:09 -07007616
7617 if (hw_stats == NULL) {
7618 memset(buf, 0, sizeof(u64) * BNX2_NUM_STATS);
7619 return;
7620 }
7621
Michael Chan4ce45e02012-12-06 10:33:10 +00007622 if ((BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5706_A0) ||
7623 (BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5706_A1) ||
7624 (BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5706_A2) ||
7625 (BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5708_A0))
Michael Chanb6016b72005-05-26 13:03:09 -07007626 stats_len_arr = bnx2_5706_stats_len_arr;
Michael Chan5b0c76a2005-11-04 08:45:49 -08007627 else
7628 stats_len_arr = bnx2_5708_stats_len_arr;
Michael Chanb6016b72005-05-26 13:03:09 -07007629
7630 for (i = 0; i < BNX2_NUM_STATS; i++) {
Michael Chan354fcd72010-01-17 07:30:44 +00007631 unsigned long offset;
7632
Michael Chanb6016b72005-05-26 13:03:09 -07007633 if (stats_len_arr[i] == 0) {
7634 /* skip this counter */
7635 buf[i] = 0;
7636 continue;
7637 }
Michael Chan354fcd72010-01-17 07:30:44 +00007638
7639 offset = bnx2_stats_offset_arr[i];
Michael Chanb6016b72005-05-26 13:03:09 -07007640 if (stats_len_arr[i] == 4) {
7641 /* 4-byte counter */
Michael Chan354fcd72010-01-17 07:30:44 +00007642 buf[i] = (u64) *(hw_stats + offset) +
7643 *(temp_stats + offset);
Michael Chanb6016b72005-05-26 13:03:09 -07007644 continue;
7645 }
7646 /* 8-byte counter */
Michael Chan354fcd72010-01-17 07:30:44 +00007647 buf[i] = (((u64) *(hw_stats + offset)) << 32) +
7648 *(hw_stats + offset + 1) +
7649 (((u64) *(temp_stats + offset)) << 32) +
7650 *(temp_stats + offset + 1);
Michael Chanb6016b72005-05-26 13:03:09 -07007651 }
7652}
7653
7654static int
stephen hemminger2e17e1a2011-04-04 11:06:36 +00007655bnx2_set_phys_id(struct net_device *dev, enum ethtool_phys_id_state state)
Michael Chanb6016b72005-05-26 13:03:09 -07007656{
Michael Chan972ec0d2006-01-23 16:12:43 -08007657 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007658
stephen hemminger2e17e1a2011-04-04 11:06:36 +00007659 switch (state) {
7660 case ETHTOOL_ID_ACTIVE:
Michael Chane503e062012-12-06 10:33:08 +00007661 bp->leds_save = BNX2_RD(bp, BNX2_MISC_CFG);
7662 BNX2_WR(bp, BNX2_MISC_CFG, BNX2_MISC_CFG_LEDMODE_MAC);
Allan, Bruce Wfce55922011-04-13 13:09:10 +00007663 return 1; /* cycle on/off once per second */
Michael Chanb6016b72005-05-26 13:03:09 -07007664
stephen hemminger2e17e1a2011-04-04 11:06:36 +00007665 case ETHTOOL_ID_ON:
Michael Chane503e062012-12-06 10:33:08 +00007666 BNX2_WR(bp, BNX2_EMAC_LED, BNX2_EMAC_LED_OVERRIDE |
7667 BNX2_EMAC_LED_1000MB_OVERRIDE |
7668 BNX2_EMAC_LED_100MB_OVERRIDE |
7669 BNX2_EMAC_LED_10MB_OVERRIDE |
7670 BNX2_EMAC_LED_TRAFFIC_OVERRIDE |
7671 BNX2_EMAC_LED_TRAFFIC);
stephen hemminger2e17e1a2011-04-04 11:06:36 +00007672 break;
Michael Chanb6016b72005-05-26 13:03:09 -07007673
stephen hemminger2e17e1a2011-04-04 11:06:36 +00007674 case ETHTOOL_ID_OFF:
Michael Chane503e062012-12-06 10:33:08 +00007675 BNX2_WR(bp, BNX2_EMAC_LED, BNX2_EMAC_LED_OVERRIDE);
stephen hemminger2e17e1a2011-04-04 11:06:36 +00007676 break;
7677
7678 case ETHTOOL_ID_INACTIVE:
Michael Chane503e062012-12-06 10:33:08 +00007679 BNX2_WR(bp, BNX2_EMAC_LED, 0);
7680 BNX2_WR(bp, BNX2_MISC_CFG, bp->leds_save);
stephen hemminger2e17e1a2011-04-04 11:06:36 +00007681 break;
Michael Chanb6016b72005-05-26 13:03:09 -07007682 }
Michael Chan9f52b562008-10-09 12:21:46 -07007683
Michael Chanb6016b72005-05-26 13:03:09 -07007684 return 0;
7685}
7686
Michał Mirosławc8f44af2011-11-15 15:29:55 +00007687static netdev_features_t
7688bnx2_fix_features(struct net_device *dev, netdev_features_t features)
Michael Chan4666f872007-05-03 13:22:28 -07007689{
7690 struct bnx2 *bp = netdev_priv(dev);
7691
Michał Mirosław8d7dfc22011-04-10 04:47:46 +00007692 if (!(bp->flags & BNX2_FLAG_CAN_KEEP_VLAN))
Patrick McHardyf6469682013-04-19 02:04:27 +00007693 features |= NETIF_F_HW_VLAN_CTAG_RX;
Michał Mirosław8d7dfc22011-04-10 04:47:46 +00007694
7695 return features;
Michael Chan4666f872007-05-03 13:22:28 -07007696}
7697
Michael Chanfdc85412010-07-03 20:42:16 +00007698static int
Michał Mirosławc8f44af2011-11-15 15:29:55 +00007699bnx2_set_features(struct net_device *dev, netdev_features_t features)
Michael Chanfdc85412010-07-03 20:42:16 +00007700{
Jesse Gross7d0fd212010-10-20 13:56:09 +00007701 struct bnx2 *bp = netdev_priv(dev);
Jesse Gross7d0fd212010-10-20 13:56:09 +00007702
Michael Chan7c810472011-01-24 12:59:02 +00007703 /* TSO with VLAN tag won't work with current firmware */
Patrick McHardyf6469682013-04-19 02:04:27 +00007704 if (features & NETIF_F_HW_VLAN_CTAG_TX)
Michał Mirosław8d7dfc22011-04-10 04:47:46 +00007705 dev->vlan_features |= (dev->hw_features & NETIF_F_ALL_TSO);
7706 else
7707 dev->vlan_features &= ~NETIF_F_ALL_TSO;
Michael Chan7c810472011-01-24 12:59:02 +00007708
Patrick McHardyf6469682013-04-19 02:04:27 +00007709 if ((!!(features & NETIF_F_HW_VLAN_CTAG_RX) !=
Jesse Gross7d0fd212010-10-20 13:56:09 +00007710 !!(bp->rx_mode & BNX2_EMAC_RX_MODE_KEEP_VLAN_TAG)) &&
7711 netif_running(dev)) {
7712 bnx2_netif_stop(bp, false);
Michał Mirosław8d7dfc22011-04-10 04:47:46 +00007713 dev->features = features;
Jesse Gross7d0fd212010-10-20 13:56:09 +00007714 bnx2_set_rx_mode(dev);
7715 bnx2_fw_sync(bp, BNX2_DRV_MSG_CODE_KEEP_VLAN_UPDATE, 0, 1);
7716 bnx2_netif_start(bp, false);
Michał Mirosław8d7dfc22011-04-10 04:47:46 +00007717 return 1;
Jesse Gross7d0fd212010-10-20 13:56:09 +00007718 }
7719
7720 return 0;
Michael Chanfdc85412010-07-03 20:42:16 +00007721}
7722
Michael Chanb0332812012-02-05 15:24:38 +00007723static void bnx2_get_channels(struct net_device *dev,
7724 struct ethtool_channels *channels)
7725{
7726 struct bnx2 *bp = netdev_priv(dev);
7727 u32 max_rx_rings = 1;
7728 u32 max_tx_rings = 1;
7729
7730 if ((bp->flags & BNX2_FLAG_MSIX_CAP) && !disable_msi) {
7731 max_rx_rings = RX_MAX_RINGS;
7732 max_tx_rings = TX_MAX_RINGS;
7733 }
7734
7735 channels->max_rx = max_rx_rings;
7736 channels->max_tx = max_tx_rings;
7737 channels->max_other = 0;
7738 channels->max_combined = 0;
7739 channels->rx_count = bp->num_rx_rings;
7740 channels->tx_count = bp->num_tx_rings;
7741 channels->other_count = 0;
7742 channels->combined_count = 0;
7743}
7744
7745static int bnx2_set_channels(struct net_device *dev,
7746 struct ethtool_channels *channels)
7747{
7748 struct bnx2 *bp = netdev_priv(dev);
7749 u32 max_rx_rings = 1;
7750 u32 max_tx_rings = 1;
7751 int rc = 0;
7752
7753 if ((bp->flags & BNX2_FLAG_MSIX_CAP) && !disable_msi) {
7754 max_rx_rings = RX_MAX_RINGS;
7755 max_tx_rings = TX_MAX_RINGS;
7756 }
7757 if (channels->rx_count > max_rx_rings ||
7758 channels->tx_count > max_tx_rings)
7759 return -EINVAL;
7760
7761 bp->num_req_rx_rings = channels->rx_count;
7762 bp->num_req_tx_rings = channels->tx_count;
7763
7764 if (netif_running(dev))
7765 rc = bnx2_change_ring_size(bp, bp->rx_ring_size,
7766 bp->tx_ring_size, true);
7767
7768 return rc;
7769}
7770
Jeff Garzik7282d492006-09-13 14:30:00 -04007771static const struct ethtool_ops bnx2_ethtool_ops = {
Michael Chanb6016b72005-05-26 13:03:09 -07007772 .get_settings = bnx2_get_settings,
7773 .set_settings = bnx2_set_settings,
7774 .get_drvinfo = bnx2_get_drvinfo,
Michael Chan244ac4f2006-03-20 17:48:46 -08007775 .get_regs_len = bnx2_get_regs_len,
7776 .get_regs = bnx2_get_regs,
Michael Chanb6016b72005-05-26 13:03:09 -07007777 .get_wol = bnx2_get_wol,
7778 .set_wol = bnx2_set_wol,
7779 .nway_reset = bnx2_nway_reset,
Ooiwa Naohiro7959ea22009-06-24 00:19:06 -07007780 .get_link = bnx2_get_link,
Michael Chanb6016b72005-05-26 13:03:09 -07007781 .get_eeprom_len = bnx2_get_eeprom_len,
7782 .get_eeprom = bnx2_get_eeprom,
7783 .set_eeprom = bnx2_set_eeprom,
7784 .get_coalesce = bnx2_get_coalesce,
7785 .set_coalesce = bnx2_set_coalesce,
7786 .get_ringparam = bnx2_get_ringparam,
7787 .set_ringparam = bnx2_set_ringparam,
7788 .get_pauseparam = bnx2_get_pauseparam,
7789 .set_pauseparam = bnx2_set_pauseparam,
Michael Chanb6016b72005-05-26 13:03:09 -07007790 .self_test = bnx2_self_test,
7791 .get_strings = bnx2_get_strings,
stephen hemminger2e17e1a2011-04-04 11:06:36 +00007792 .set_phys_id = bnx2_set_phys_id,
Michael Chanb6016b72005-05-26 13:03:09 -07007793 .get_ethtool_stats = bnx2_get_ethtool_stats,
Jeff Garzikb9f2c042007-10-03 18:07:32 -07007794 .get_sset_count = bnx2_get_sset_count,
Michael Chanb0332812012-02-05 15:24:38 +00007795 .get_channels = bnx2_get_channels,
7796 .set_channels = bnx2_set_channels,
Michael Chanb6016b72005-05-26 13:03:09 -07007797};
7798
7799/* Called with rtnl_lock */
7800static int
7801bnx2_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
7802{
Peter Hagervall14ab9b82005-08-10 14:18:16 -07007803 struct mii_ioctl_data *data = if_mii(ifr);
Michael Chan972ec0d2006-01-23 16:12:43 -08007804 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007805 int err;
7806
7807 switch(cmd) {
7808 case SIOCGMIIPHY:
7809 data->phy_id = bp->phy_addr;
7810
7811 /* fallthru */
7812 case SIOCGMIIREG: {
7813 u32 mii_regval;
7814
Michael Chan583c28e2008-01-21 19:51:35 -08007815 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
Michael Chan7b6b8342007-07-07 22:50:15 -07007816 return -EOPNOTSUPP;
7817
Michael Chandad3e452007-05-03 13:18:03 -07007818 if (!netif_running(dev))
7819 return -EAGAIN;
7820
Michael Chanc770a652005-08-25 15:38:39 -07007821 spin_lock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07007822 err = bnx2_read_phy(bp, data->reg_num & 0x1f, &mii_regval);
Michael Chanc770a652005-08-25 15:38:39 -07007823 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07007824
7825 data->val_out = mii_regval;
7826
7827 return err;
7828 }
7829
7830 case SIOCSMIIREG:
Michael Chan583c28e2008-01-21 19:51:35 -08007831 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
Michael Chan7b6b8342007-07-07 22:50:15 -07007832 return -EOPNOTSUPP;
7833
Michael Chandad3e452007-05-03 13:18:03 -07007834 if (!netif_running(dev))
7835 return -EAGAIN;
7836
Michael Chanc770a652005-08-25 15:38:39 -07007837 spin_lock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07007838 err = bnx2_write_phy(bp, data->reg_num & 0x1f, data->val_in);
Michael Chanc770a652005-08-25 15:38:39 -07007839 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07007840
7841 return err;
7842
7843 default:
7844 /* do nothing */
7845 break;
7846 }
7847 return -EOPNOTSUPP;
7848}
7849
7850/* Called with rtnl_lock */
7851static int
7852bnx2_change_mac_addr(struct net_device *dev, void *p)
7853{
7854 struct sockaddr *addr = p;
Michael Chan972ec0d2006-01-23 16:12:43 -08007855 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007856
Michael Chan73eef4c2005-08-25 15:39:15 -07007857 if (!is_valid_ether_addr(addr->sa_data))
Danny Kukawka504f9b52012-02-21 02:07:49 +00007858 return -EADDRNOTAVAIL;
Michael Chan73eef4c2005-08-25 15:39:15 -07007859
Michael Chanb6016b72005-05-26 13:03:09 -07007860 memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
7861 if (netif_running(dev))
Benjamin Li5fcaed02008-07-14 22:39:52 -07007862 bnx2_set_mac_addr(bp, bp->dev->dev_addr, 0);
Michael Chanb6016b72005-05-26 13:03:09 -07007863
7864 return 0;
7865}
7866
7867/* Called with rtnl_lock */
7868static int
7869bnx2_change_mtu(struct net_device *dev, int new_mtu)
7870{
Michael Chan972ec0d2006-01-23 16:12:43 -08007871 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007872
7873 if (((new_mtu + ETH_HLEN) > MAX_ETHERNET_JUMBO_PACKET_SIZE) ||
7874 ((new_mtu + ETH_HLEN) < MIN_ETHERNET_PACKET_SIZE))
7875 return -EINVAL;
7876
7877 dev->mtu = new_mtu;
Michael Chanb0332812012-02-05 15:24:38 +00007878 return bnx2_change_ring_size(bp, bp->rx_ring_size, bp->tx_ring_size,
7879 false);
Michael Chanb6016b72005-05-26 13:03:09 -07007880}
7881
Alexey Dobriyan257ddbd2010-01-27 10:17:41 +00007882#ifdef CONFIG_NET_POLL_CONTROLLER
Michael Chanb6016b72005-05-26 13:03:09 -07007883static void
7884poll_bnx2(struct net_device *dev)
7885{
Michael Chan972ec0d2006-01-23 16:12:43 -08007886 struct bnx2 *bp = netdev_priv(dev);
Neil Hormanb2af2c12008-11-12 16:23:44 -08007887 int i;
Michael Chanb6016b72005-05-26 13:03:09 -07007888
Neil Hormanb2af2c12008-11-12 16:23:44 -08007889 for (i = 0; i < bp->irq_nvecs; i++) {
Michael Chan1bf1e342010-03-23 13:13:12 +00007890 struct bnx2_irq *irq = &bp->irq_tbl[i];
7891
7892 disable_irq(irq->vector);
7893 irq->handler(irq->vector, &bp->bnx2_napi[i]);
7894 enable_irq(irq->vector);
Neil Hormanb2af2c12008-11-12 16:23:44 -08007895 }
Michael Chanb6016b72005-05-26 13:03:09 -07007896}
7897#endif
7898
Bill Pembertoncfd95a62012-12-03 09:22:58 -05007899static void
Michael Chan253c8b72007-01-08 19:56:01 -08007900bnx2_get_5709_media(struct bnx2 *bp)
7901{
Michael Chane503e062012-12-06 10:33:08 +00007902 u32 val = BNX2_RD(bp, BNX2_MISC_DUAL_MEDIA_CTRL);
Michael Chan253c8b72007-01-08 19:56:01 -08007903 u32 bond_id = val & BNX2_MISC_DUAL_MEDIA_CTRL_BOND_ID;
7904 u32 strap;
7905
7906 if (bond_id == BNX2_MISC_DUAL_MEDIA_CTRL_BOND_ID_C)
7907 return;
7908 else if (bond_id == BNX2_MISC_DUAL_MEDIA_CTRL_BOND_ID_S) {
Michael Chan583c28e2008-01-21 19:51:35 -08007909 bp->phy_flags |= BNX2_PHY_FLAG_SERDES;
Michael Chan253c8b72007-01-08 19:56:01 -08007910 return;
7911 }
7912
7913 if (val & BNX2_MISC_DUAL_MEDIA_CTRL_STRAP_OVERRIDE)
7914 strap = (val & BNX2_MISC_DUAL_MEDIA_CTRL_PHY_CTRL) >> 21;
7915 else
7916 strap = (val & BNX2_MISC_DUAL_MEDIA_CTRL_PHY_CTRL_STRAP) >> 8;
7917
Michael Chanaefd90e2012-06-16 15:45:43 +00007918 if (bp->func == 0) {
Michael Chan253c8b72007-01-08 19:56:01 -08007919 switch (strap) {
7920 case 0x4:
7921 case 0x5:
7922 case 0x6:
Michael Chan583c28e2008-01-21 19:51:35 -08007923 bp->phy_flags |= BNX2_PHY_FLAG_SERDES;
Michael Chan253c8b72007-01-08 19:56:01 -08007924 return;
7925 }
7926 } else {
7927 switch (strap) {
7928 case 0x1:
7929 case 0x2:
7930 case 0x4:
Michael Chan583c28e2008-01-21 19:51:35 -08007931 bp->phy_flags |= BNX2_PHY_FLAG_SERDES;
Michael Chan253c8b72007-01-08 19:56:01 -08007932 return;
7933 }
7934 }
7935}
7936
Bill Pembertoncfd95a62012-12-03 09:22:58 -05007937static void
Michael Chan883e5152007-05-03 13:25:11 -07007938bnx2_get_pci_speed(struct bnx2 *bp)
7939{
7940 u32 reg;
7941
Michael Chane503e062012-12-06 10:33:08 +00007942 reg = BNX2_RD(bp, BNX2_PCICFG_MISC_STATUS);
Michael Chan883e5152007-05-03 13:25:11 -07007943 if (reg & BNX2_PCICFG_MISC_STATUS_PCIX_DET) {
7944 u32 clkreg;
7945
David S. Millerf86e82f2008-01-21 17:15:40 -08007946 bp->flags |= BNX2_FLAG_PCIX;
Michael Chan883e5152007-05-03 13:25:11 -07007947
Michael Chane503e062012-12-06 10:33:08 +00007948 clkreg = BNX2_RD(bp, BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS);
Michael Chan883e5152007-05-03 13:25:11 -07007949
7950 clkreg &= BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET;
7951 switch (clkreg) {
7952 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_133MHZ:
7953 bp->bus_speed_mhz = 133;
7954 break;
7955
7956 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_95MHZ:
7957 bp->bus_speed_mhz = 100;
7958 break;
7959
7960 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_66MHZ:
7961 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_80MHZ:
7962 bp->bus_speed_mhz = 66;
7963 break;
7964
7965 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_48MHZ:
7966 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_55MHZ:
7967 bp->bus_speed_mhz = 50;
7968 break;
7969
7970 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_LOW:
7971 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_32MHZ:
7972 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_38MHZ:
7973 bp->bus_speed_mhz = 33;
7974 break;
7975 }
7976 }
7977 else {
7978 if (reg & BNX2_PCICFG_MISC_STATUS_M66EN)
7979 bp->bus_speed_mhz = 66;
7980 else
7981 bp->bus_speed_mhz = 33;
7982 }
7983
7984 if (reg & BNX2_PCICFG_MISC_STATUS_32BIT_DET)
David S. Millerf86e82f2008-01-21 17:15:40 -08007985 bp->flags |= BNX2_FLAG_PCI_32BIT;
Michael Chan883e5152007-05-03 13:25:11 -07007986
7987}
7988
Bill Pembertoncfd95a62012-12-03 09:22:58 -05007989static void
Michael Chan76d99062009-12-03 09:46:34 +00007990bnx2_read_vpd_fw_ver(struct bnx2 *bp)
7991{
Matt Carlsondf25bc32010-02-26 14:04:44 +00007992 int rc, i, j;
Michael Chan76d99062009-12-03 09:46:34 +00007993 u8 *data;
Matt Carlsondf25bc32010-02-26 14:04:44 +00007994 unsigned int block_end, rosize, len;
Michael Chan76d99062009-12-03 09:46:34 +00007995
Michael Chan012093f2009-12-03 15:58:00 -08007996#define BNX2_VPD_NVRAM_OFFSET 0x300
7997#define BNX2_VPD_LEN 128
Michael Chan76d99062009-12-03 09:46:34 +00007998#define BNX2_MAX_VER_SLEN 30
7999
8000 data = kmalloc(256, GFP_KERNEL);
8001 if (!data)
8002 return;
8003
Michael Chan012093f2009-12-03 15:58:00 -08008004 rc = bnx2_nvram_read(bp, BNX2_VPD_NVRAM_OFFSET, data + BNX2_VPD_LEN,
8005 BNX2_VPD_LEN);
Michael Chan76d99062009-12-03 09:46:34 +00008006 if (rc)
8007 goto vpd_done;
8008
Michael Chan012093f2009-12-03 15:58:00 -08008009 for (i = 0; i < BNX2_VPD_LEN; i += 4) {
8010 data[i] = data[i + BNX2_VPD_LEN + 3];
8011 data[i + 1] = data[i + BNX2_VPD_LEN + 2];
8012 data[i + 2] = data[i + BNX2_VPD_LEN + 1];
8013 data[i + 3] = data[i + BNX2_VPD_LEN];
Michael Chan76d99062009-12-03 09:46:34 +00008014 }
8015
Matt Carlsondf25bc32010-02-26 14:04:44 +00008016 i = pci_vpd_find_tag(data, 0, BNX2_VPD_LEN, PCI_VPD_LRDT_RO_DATA);
8017 if (i < 0)
Michael Chan76d99062009-12-03 09:46:34 +00008018 goto vpd_done;
Matt Carlsondf25bc32010-02-26 14:04:44 +00008019
8020 rosize = pci_vpd_lrdt_size(&data[i]);
8021 i += PCI_VPD_LRDT_TAG_SIZE;
8022 block_end = i + rosize;
8023
8024 if (block_end > BNX2_VPD_LEN)
8025 goto vpd_done;
8026
8027 j = pci_vpd_find_info_keyword(data, i, rosize,
8028 PCI_VPD_RO_KEYWORD_MFR_ID);
8029 if (j < 0)
8030 goto vpd_done;
8031
8032 len = pci_vpd_info_field_size(&data[j]);
8033
8034 j += PCI_VPD_INFO_FLD_HDR_SIZE;
8035 if (j + len > block_end || len != 4 ||
8036 memcmp(&data[j], "1028", 4))
8037 goto vpd_done;
8038
8039 j = pci_vpd_find_info_keyword(data, i, rosize,
8040 PCI_VPD_RO_KEYWORD_VENDOR0);
8041 if (j < 0)
8042 goto vpd_done;
8043
8044 len = pci_vpd_info_field_size(&data[j]);
8045
8046 j += PCI_VPD_INFO_FLD_HDR_SIZE;
8047 if (j + len > block_end || len > BNX2_MAX_VER_SLEN)
8048 goto vpd_done;
8049
8050 memcpy(bp->fw_version, &data[j], len);
8051 bp->fw_version[len] = ' ';
Michael Chan76d99062009-12-03 09:46:34 +00008052
8053vpd_done:
8054 kfree(data);
8055}
8056
Bill Pembertoncfd95a62012-12-03 09:22:58 -05008057static int
Michael Chanb6016b72005-05-26 13:03:09 -07008058bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
8059{
8060 struct bnx2 *bp;
Michael Chan58fc2ea2007-07-07 22:52:02 -07008061 int rc, i, j;
Michael Chanb6016b72005-05-26 13:03:09 -07008062 u32 reg;
Michael Chan40453c82007-05-03 13:19:18 -07008063 u64 dma_mask, persist_dma_mask;
John Feeneycd709aa2010-08-22 17:45:53 +00008064 int err;
Michael Chanb6016b72005-05-26 13:03:09 -07008065
Michael Chanb6016b72005-05-26 13:03:09 -07008066 SET_NETDEV_DEV(dev, &pdev->dev);
Michael Chan972ec0d2006-01-23 16:12:43 -08008067 bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07008068
8069 bp->flags = 0;
8070 bp->phy_flags = 0;
8071
Michael Chan354fcd72010-01-17 07:30:44 +00008072 bp->temp_stats_blk =
8073 kzalloc(sizeof(struct statistics_block), GFP_KERNEL);
8074
8075 if (bp->temp_stats_blk == NULL) {
8076 rc = -ENOMEM;
8077 goto err_out;
8078 }
8079
Michael Chanb6016b72005-05-26 13:03:09 -07008080 /* enable device (incl. PCI PM wakeup), and bus-mastering */
8081 rc = pci_enable_device(pdev);
8082 if (rc) {
Joe Perches3a9c6a42010-02-17 15:01:51 +00008083 dev_err(&pdev->dev, "Cannot enable PCI device, aborting\n");
Michael Chanb6016b72005-05-26 13:03:09 -07008084 goto err_out;
8085 }
8086
8087 if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) {
Jeff Garzik9b91cf92006-06-27 11:39:50 -04008088 dev_err(&pdev->dev,
Joe Perches3a9c6a42010-02-17 15:01:51 +00008089 "Cannot find PCI device base address, aborting\n");
Michael Chanb6016b72005-05-26 13:03:09 -07008090 rc = -ENODEV;
8091 goto err_out_disable;
8092 }
8093
8094 rc = pci_request_regions(pdev, DRV_MODULE_NAME);
8095 if (rc) {
Joe Perches3a9c6a42010-02-17 15:01:51 +00008096 dev_err(&pdev->dev, "Cannot obtain PCI resources, aborting\n");
Michael Chanb6016b72005-05-26 13:03:09 -07008097 goto err_out_disable;
8098 }
8099
8100 pci_set_master(pdev);
8101
Yijing Wang85768272013-06-18 16:12:37 +08008102 bp->pm_cap = pdev->pm_cap;
Michael Chanb6016b72005-05-26 13:03:09 -07008103 if (bp->pm_cap == 0) {
Jeff Garzik9b91cf92006-06-27 11:39:50 -04008104 dev_err(&pdev->dev,
Joe Perches3a9c6a42010-02-17 15:01:51 +00008105 "Cannot find power management capability, aborting\n");
Michael Chanb6016b72005-05-26 13:03:09 -07008106 rc = -EIO;
8107 goto err_out_release;
8108 }
8109
Michael Chanb6016b72005-05-26 13:03:09 -07008110 bp->dev = dev;
8111 bp->pdev = pdev;
8112
8113 spin_lock_init(&bp->phy_lock);
Michael Chan1b8227c2007-05-03 13:24:05 -07008114 spin_lock_init(&bp->indirect_lock);
Michael Chanc5a88952009-08-14 15:49:45 +00008115#ifdef BCM_CNIC
8116 mutex_init(&bp->cnic_lock);
8117#endif
David Howellsc4028952006-11-22 14:57:56 +00008118 INIT_WORK(&bp->reset_task, bnx2_reset_task);
Michael Chanb6016b72005-05-26 13:03:09 -07008119
Francois Romieuc0357e92012-03-09 14:51:47 +01008120 bp->regview = pci_iomap(pdev, 0, MB_GET_CID_ADDR(TX_TSS_CID +
8121 TX_MAX_TSS_RINGS + 1));
Michael Chanb6016b72005-05-26 13:03:09 -07008122 if (!bp->regview) {
Joe Perches3a9c6a42010-02-17 15:01:51 +00008123 dev_err(&pdev->dev, "Cannot map register space, aborting\n");
Michael Chanb6016b72005-05-26 13:03:09 -07008124 rc = -ENOMEM;
8125 goto err_out_release;
8126 }
8127
8128 /* Configure byte swap and enable write to the reg_window registers.
8129 * Rely on CPU to do target byte swapping on big endian systems
8130 * The chip's target access swapping will not swap all accesses
8131 */
Michael Chane503e062012-12-06 10:33:08 +00008132 BNX2_WR(bp, BNX2_PCICFG_MISC_CONFIG,
8133 BNX2_PCICFG_MISC_CONFIG_REG_WINDOW_ENA |
8134 BNX2_PCICFG_MISC_CONFIG_TARGET_MB_WORD_SWAP);
Michael Chanb6016b72005-05-26 13:03:09 -07008135
Michael Chane503e062012-12-06 10:33:08 +00008136 bp->chip_id = BNX2_RD(bp, BNX2_MISC_ID);
Michael Chanb6016b72005-05-26 13:03:09 -07008137
Michael Chan4ce45e02012-12-06 10:33:10 +00008138 if (BNX2_CHIP(bp) == BNX2_CHIP_5709) {
Jon Masone82760e2011-06-27 07:44:43 +00008139 if (!pci_is_pcie(pdev)) {
8140 dev_err(&pdev->dev, "Not PCIE, aborting\n");
Michael Chan883e5152007-05-03 13:25:11 -07008141 rc = -EIO;
8142 goto err_out_unmap;
8143 }
David S. Millerf86e82f2008-01-21 17:15:40 -08008144 bp->flags |= BNX2_FLAG_PCIE;
Michael Chan4ce45e02012-12-06 10:33:10 +00008145 if (BNX2_CHIP_REV(bp) == BNX2_CHIP_REV_Ax)
David S. Millerf86e82f2008-01-21 17:15:40 -08008146 bp->flags |= BNX2_FLAG_JUMBO_BROKEN;
Michael Chanc239f272010-10-11 16:12:28 -07008147
8148 /* AER (Advanced Error Reporting) hooks */
8149 err = pci_enable_pcie_error_reporting(pdev);
Michael Chan4bb9ebc2011-01-25 22:14:51 +00008150 if (!err)
8151 bp->flags |= BNX2_FLAG_AER_ENABLED;
Michael Chanc239f272010-10-11 16:12:28 -07008152
Michael Chan883e5152007-05-03 13:25:11 -07008153 } else {
Michael Chan59b47d82006-11-19 14:10:45 -08008154 bp->pcix_cap = pci_find_capability(pdev, PCI_CAP_ID_PCIX);
8155 if (bp->pcix_cap == 0) {
8156 dev_err(&pdev->dev,
Joe Perches3a9c6a42010-02-17 15:01:51 +00008157 "Cannot find PCIX capability, aborting\n");
Michael Chan59b47d82006-11-19 14:10:45 -08008158 rc = -EIO;
8159 goto err_out_unmap;
8160 }
Michael Chan61d9e3f2009-08-21 16:20:46 +00008161 bp->flags |= BNX2_FLAG_BROKEN_STATS;
Michael Chan59b47d82006-11-19 14:10:45 -08008162 }
8163
Michael Chan4ce45e02012-12-06 10:33:10 +00008164 if (BNX2_CHIP(bp) == BNX2_CHIP_5709 &&
8165 BNX2_CHIP_REV(bp) != BNX2_CHIP_REV_Ax) {
Yijing Wang555a8422013-08-08 21:02:22 +08008166 if (pdev->msix_cap)
David S. Millerf86e82f2008-01-21 17:15:40 -08008167 bp->flags |= BNX2_FLAG_MSIX_CAP;
Michael Chanb4b36042007-12-20 19:59:30 -08008168 }
8169
Michael Chan4ce45e02012-12-06 10:33:10 +00008170 if (BNX2_CHIP_ID(bp) != BNX2_CHIP_ID_5706_A0 &&
8171 BNX2_CHIP_ID(bp) != BNX2_CHIP_ID_5706_A1) {
Yijing Wang555a8422013-08-08 21:02:22 +08008172 if (pdev->msi_cap)
David S. Millerf86e82f2008-01-21 17:15:40 -08008173 bp->flags |= BNX2_FLAG_MSI_CAP;
Michael Chan8e6a72c2007-05-03 13:24:48 -07008174 }
8175
Michael Chan40453c82007-05-03 13:19:18 -07008176 /* 5708 cannot support DMA addresses > 40-bit. */
Michael Chan4ce45e02012-12-06 10:33:10 +00008177 if (BNX2_CHIP(bp) == BNX2_CHIP_5708)
Yang Hongyang50cf1562009-04-06 19:01:14 -07008178 persist_dma_mask = dma_mask = DMA_BIT_MASK(40);
Michael Chan40453c82007-05-03 13:19:18 -07008179 else
Yang Hongyang6a355282009-04-06 19:01:13 -07008180 persist_dma_mask = dma_mask = DMA_BIT_MASK(64);
Michael Chan40453c82007-05-03 13:19:18 -07008181
8182 /* Configure DMA attributes. */
8183 if (pci_set_dma_mask(pdev, dma_mask) == 0) {
8184 dev->features |= NETIF_F_HIGHDMA;
8185 rc = pci_set_consistent_dma_mask(pdev, persist_dma_mask);
8186 if (rc) {
8187 dev_err(&pdev->dev,
Joe Perches3a9c6a42010-02-17 15:01:51 +00008188 "pci_set_consistent_dma_mask failed, aborting\n");
Michael Chan40453c82007-05-03 13:19:18 -07008189 goto err_out_unmap;
8190 }
Yang Hongyang284901a2009-04-06 19:01:15 -07008191 } else if ((rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) != 0) {
Joe Perches3a9c6a42010-02-17 15:01:51 +00008192 dev_err(&pdev->dev, "System does not support DMA, aborting\n");
Michael Chan40453c82007-05-03 13:19:18 -07008193 goto err_out_unmap;
8194 }
8195
David S. Millerf86e82f2008-01-21 17:15:40 -08008196 if (!(bp->flags & BNX2_FLAG_PCIE))
Michael Chan883e5152007-05-03 13:25:11 -07008197 bnx2_get_pci_speed(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07008198
8199 /* 5706A0 may falsely detect SERR and PERR. */
Michael Chan4ce45e02012-12-06 10:33:10 +00008200 if (BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5706_A0) {
Michael Chane503e062012-12-06 10:33:08 +00008201 reg = BNX2_RD(bp, PCI_COMMAND);
Michael Chanb6016b72005-05-26 13:03:09 -07008202 reg &= ~(PCI_COMMAND_SERR | PCI_COMMAND_PARITY);
Michael Chane503e062012-12-06 10:33:08 +00008203 BNX2_WR(bp, PCI_COMMAND, reg);
Michael Chan4ce45e02012-12-06 10:33:10 +00008204 } else if ((BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5706_A1) &&
David S. Millerf86e82f2008-01-21 17:15:40 -08008205 !(bp->flags & BNX2_FLAG_PCIX)) {
Michael Chanb6016b72005-05-26 13:03:09 -07008206
Jeff Garzik9b91cf92006-06-27 11:39:50 -04008207 dev_err(&pdev->dev,
Joe Perches3a9c6a42010-02-17 15:01:51 +00008208 "5706 A1 can only be used in a PCIX bus, aborting\n");
Michael Chanb6016b72005-05-26 13:03:09 -07008209 goto err_out_unmap;
8210 }
8211
8212 bnx2_init_nvram(bp);
8213
Michael Chan2726d6e2008-01-29 21:35:05 -08008214 reg = bnx2_reg_rd_ind(bp, BNX2_SHM_HDR_SIGNATURE);
Michael Chane3648b32005-11-04 08:51:21 -08008215
Michael Chanaefd90e2012-06-16 15:45:43 +00008216 if (bnx2_reg_rd_ind(bp, BNX2_MCP_TOE_ID) & BNX2_MCP_TOE_ID_FUNCTION_ID)
8217 bp->func = 1;
8218
Michael Chane3648b32005-11-04 08:51:21 -08008219 if ((reg & BNX2_SHM_HDR_SIGNATURE_SIG_MASK) ==
Michael Chan24cb2302007-01-25 15:49:56 -08008220 BNX2_SHM_HDR_SIGNATURE_SIG) {
Michael Chanaefd90e2012-06-16 15:45:43 +00008221 u32 off = bp->func << 2;
Michael Chan24cb2302007-01-25 15:49:56 -08008222
Michael Chan2726d6e2008-01-29 21:35:05 -08008223 bp->shmem_base = bnx2_reg_rd_ind(bp, BNX2_SHM_HDR_ADDR_0 + off);
Michael Chan24cb2302007-01-25 15:49:56 -08008224 } else
Michael Chane3648b32005-11-04 08:51:21 -08008225 bp->shmem_base = HOST_VIEW_SHMEM_BASE;
8226
Michael Chanb6016b72005-05-26 13:03:09 -07008227 /* Get the permanent MAC address. First we need to make sure the
8228 * firmware is actually running.
8229 */
Michael Chan2726d6e2008-01-29 21:35:05 -08008230 reg = bnx2_shmem_rd(bp, BNX2_DEV_INFO_SIGNATURE);
Michael Chanb6016b72005-05-26 13:03:09 -07008231
8232 if ((reg & BNX2_DEV_INFO_SIGNATURE_MAGIC_MASK) !=
8233 BNX2_DEV_INFO_SIGNATURE_MAGIC) {
Joe Perches3a9c6a42010-02-17 15:01:51 +00008234 dev_err(&pdev->dev, "Firmware not running, aborting\n");
Michael Chanb6016b72005-05-26 13:03:09 -07008235 rc = -ENODEV;
8236 goto err_out_unmap;
8237 }
8238
Michael Chan76d99062009-12-03 09:46:34 +00008239 bnx2_read_vpd_fw_ver(bp);
8240
8241 j = strlen(bp->fw_version);
Michael Chan2726d6e2008-01-29 21:35:05 -08008242 reg = bnx2_shmem_rd(bp, BNX2_DEV_INFO_BC_REV);
Michael Chan76d99062009-12-03 09:46:34 +00008243 for (i = 0; i < 3 && j < 24; i++) {
Michael Chan58fc2ea2007-07-07 22:52:02 -07008244 u8 num, k, skip0;
8245
Michael Chan76d99062009-12-03 09:46:34 +00008246 if (i == 0) {
8247 bp->fw_version[j++] = 'b';
8248 bp->fw_version[j++] = 'c';
8249 bp->fw_version[j++] = ' ';
8250 }
Michael Chan58fc2ea2007-07-07 22:52:02 -07008251 num = (u8) (reg >> (24 - (i * 8)));
8252 for (k = 100, skip0 = 1; k >= 1; num %= k, k /= 10) {
8253 if (num >= k || !skip0 || k == 1) {
8254 bp->fw_version[j++] = (num / k) + '0';
8255 skip0 = 0;
8256 }
8257 }
8258 if (i != 2)
8259 bp->fw_version[j++] = '.';
8260 }
Michael Chan2726d6e2008-01-29 21:35:05 -08008261 reg = bnx2_shmem_rd(bp, BNX2_PORT_FEATURE);
Michael Chan846f5c62007-10-10 16:16:51 -07008262 if (reg & BNX2_PORT_FEATURE_WOL_ENABLED)
8263 bp->wol = 1;
8264
8265 if (reg & BNX2_PORT_FEATURE_ASF_ENABLED) {
David S. Millerf86e82f2008-01-21 17:15:40 -08008266 bp->flags |= BNX2_FLAG_ASF_ENABLE;
Michael Chanc2d3db82007-07-16 18:26:43 -07008267
8268 for (i = 0; i < 30; i++) {
Michael Chan2726d6e2008-01-29 21:35:05 -08008269 reg = bnx2_shmem_rd(bp, BNX2_BC_STATE_CONDITION);
Michael Chanc2d3db82007-07-16 18:26:43 -07008270 if (reg & BNX2_CONDITION_MFW_RUN_MASK)
8271 break;
8272 msleep(10);
8273 }
8274 }
Michael Chan2726d6e2008-01-29 21:35:05 -08008275 reg = bnx2_shmem_rd(bp, BNX2_BC_STATE_CONDITION);
Michael Chan58fc2ea2007-07-07 22:52:02 -07008276 reg &= BNX2_CONDITION_MFW_RUN_MASK;
8277 if (reg != BNX2_CONDITION_MFW_RUN_UNKNOWN &&
8278 reg != BNX2_CONDITION_MFW_RUN_NONE) {
Michael Chan2726d6e2008-01-29 21:35:05 -08008279 u32 addr = bnx2_shmem_rd(bp, BNX2_MFW_VER_PTR);
Michael Chan58fc2ea2007-07-07 22:52:02 -07008280
Michael Chan76d99062009-12-03 09:46:34 +00008281 if (j < 32)
8282 bp->fw_version[j++] = ' ';
8283 for (i = 0; i < 3 && j < 28; i++) {
Michael Chan2726d6e2008-01-29 21:35:05 -08008284 reg = bnx2_reg_rd_ind(bp, addr + i * 4);
Michael Chan3aeb7d22011-07-20 14:55:25 +00008285 reg = be32_to_cpu(reg);
Michael Chan58fc2ea2007-07-07 22:52:02 -07008286 memcpy(&bp->fw_version[j], &reg, 4);
8287 j += 4;
8288 }
8289 }
Michael Chanb6016b72005-05-26 13:03:09 -07008290
Michael Chan2726d6e2008-01-29 21:35:05 -08008291 reg = bnx2_shmem_rd(bp, BNX2_PORT_HW_CFG_MAC_UPPER);
Michael Chanb6016b72005-05-26 13:03:09 -07008292 bp->mac_addr[0] = (u8) (reg >> 8);
8293 bp->mac_addr[1] = (u8) reg;
8294
Michael Chan2726d6e2008-01-29 21:35:05 -08008295 reg = bnx2_shmem_rd(bp, BNX2_PORT_HW_CFG_MAC_LOWER);
Michael Chanb6016b72005-05-26 13:03:09 -07008296 bp->mac_addr[2] = (u8) (reg >> 24);
8297 bp->mac_addr[3] = (u8) (reg >> 16);
8298 bp->mac_addr[4] = (u8) (reg >> 8);
8299 bp->mac_addr[5] = (u8) reg;
8300
Michael Chan2bc40782012-12-06 10:33:09 +00008301 bp->tx_ring_size = BNX2_MAX_TX_DESC_CNT;
Michael Chan932f3772006-08-15 01:39:36 -07008302 bnx2_set_rx_ring_size(bp, 255);
Michael Chanb6016b72005-05-26 13:03:09 -07008303
Michael Chancf7474a2009-08-21 16:20:48 +00008304 bp->tx_quick_cons_trip_int = 2;
Michael Chanb6016b72005-05-26 13:03:09 -07008305 bp->tx_quick_cons_trip = 20;
Michael Chancf7474a2009-08-21 16:20:48 +00008306 bp->tx_ticks_int = 18;
Michael Chanb6016b72005-05-26 13:03:09 -07008307 bp->tx_ticks = 80;
Jeff Garzik6aa20a22006-09-13 13:24:59 -04008308
Michael Chancf7474a2009-08-21 16:20:48 +00008309 bp->rx_quick_cons_trip_int = 2;
8310 bp->rx_quick_cons_trip = 12;
Michael Chanb6016b72005-05-26 13:03:09 -07008311 bp->rx_ticks_int = 18;
8312 bp->rx_ticks = 18;
8313
Michael Chan7ea69202007-07-16 18:27:10 -07008314 bp->stats_ticks = USEC_PER_SEC & BNX2_HC_STATS_TICKS_HC_STAT_TICKS;
Michael Chanb6016b72005-05-26 13:03:09 -07008315
Benjamin Liac392ab2008-09-18 16:40:49 -07008316 bp->current_interval = BNX2_TIMER_INTERVAL;
Michael Chanb6016b72005-05-26 13:03:09 -07008317
Michael Chan5b0c76a2005-11-04 08:45:49 -08008318 bp->phy_addr = 1;
8319
Michael Chanb6016b72005-05-26 13:03:09 -07008320 /* Disable WOL support if we are running on a SERDES chip. */
Michael Chan4ce45e02012-12-06 10:33:10 +00008321 if (BNX2_CHIP(bp) == BNX2_CHIP_5709)
Michael Chan253c8b72007-01-08 19:56:01 -08008322 bnx2_get_5709_media(bp);
Michael Chan4ce45e02012-12-06 10:33:10 +00008323 else if (BNX2_CHIP_BOND(bp) & BNX2_CHIP_BOND_SERDES_BIT)
Michael Chan583c28e2008-01-21 19:51:35 -08008324 bp->phy_flags |= BNX2_PHY_FLAG_SERDES;
Michael Chanbac0dff2006-11-19 14:15:05 -08008325
Michael Chan0d8a6572007-07-07 22:49:43 -07008326 bp->phy_port = PORT_TP;
Michael Chan583c28e2008-01-21 19:51:35 -08008327 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Michael Chan0d8a6572007-07-07 22:49:43 -07008328 bp->phy_port = PORT_FIBRE;
Michael Chan2726d6e2008-01-29 21:35:05 -08008329 reg = bnx2_shmem_rd(bp, BNX2_SHARED_HW_CFG_CONFIG);
Michael Chan846f5c62007-10-10 16:16:51 -07008330 if (!(reg & BNX2_SHARED_HW_CFG_GIG_LINK_ON_VAUX)) {
David S. Millerf86e82f2008-01-21 17:15:40 -08008331 bp->flags |= BNX2_FLAG_NO_WOL;
Michael Chan846f5c62007-10-10 16:16:51 -07008332 bp->wol = 0;
8333 }
Michael Chan4ce45e02012-12-06 10:33:10 +00008334 if (BNX2_CHIP(bp) == BNX2_CHIP_5706) {
Michael Chan38ea3682008-02-23 19:48:57 -08008335 /* Don't do parallel detect on this board because of
8336 * some board problems. The link will not go down
8337 * if we do parallel detect.
8338 */
8339 if (pdev->subsystem_vendor == PCI_VENDOR_ID_HP &&
8340 pdev->subsystem_device == 0x310c)
8341 bp->phy_flags |= BNX2_PHY_FLAG_NO_PARALLEL;
8342 } else {
Michael Chan5b0c76a2005-11-04 08:45:49 -08008343 bp->phy_addr = 2;
Michael Chan5b0c76a2005-11-04 08:45:49 -08008344 if (reg & BNX2_SHARED_HW_CFG_PHY_2_5G)
Michael Chan583c28e2008-01-21 19:51:35 -08008345 bp->phy_flags |= BNX2_PHY_FLAG_2_5G_CAPABLE;
Michael Chan5b0c76a2005-11-04 08:45:49 -08008346 }
Michael Chan4ce45e02012-12-06 10:33:10 +00008347 } else if (BNX2_CHIP(bp) == BNX2_CHIP_5706 ||
8348 BNX2_CHIP(bp) == BNX2_CHIP_5708)
Michael Chan583c28e2008-01-21 19:51:35 -08008349 bp->phy_flags |= BNX2_PHY_FLAG_CRC_FIX;
Michael Chan4ce45e02012-12-06 10:33:10 +00008350 else if (BNX2_CHIP(bp) == BNX2_CHIP_5709 &&
8351 (BNX2_CHIP_REV(bp) == BNX2_CHIP_REV_Ax ||
8352 BNX2_CHIP_REV(bp) == BNX2_CHIP_REV_Bx))
Michael Chan583c28e2008-01-21 19:51:35 -08008353 bp->phy_flags |= BNX2_PHY_FLAG_DIS_EARLY_DAC;
Michael Chanb6016b72005-05-26 13:03:09 -07008354
Michael Chan7c62e832008-07-14 22:39:03 -07008355 bnx2_init_fw_cap(bp);
8356
Michael Chan4ce45e02012-12-06 10:33:10 +00008357 if ((BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5708_A0) ||
8358 (BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5708_B0) ||
8359 (BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5708_B1) ||
Michael Chane503e062012-12-06 10:33:08 +00008360 !(BNX2_RD(bp, BNX2_PCI_CONFIG_3) & BNX2_PCI_CONFIG_3_VAUX_PRESET)) {
David S. Millerf86e82f2008-01-21 17:15:40 -08008361 bp->flags |= BNX2_FLAG_NO_WOL;
Michael Chan846f5c62007-10-10 16:16:51 -07008362 bp->wol = 0;
8363 }
Michael Chandda1e392006-01-23 16:08:14 -08008364
Michael Chan6d5e85c2013-08-06 15:50:08 -07008365 if (bp->flags & BNX2_FLAG_NO_WOL)
8366 device_set_wakeup_capable(&bp->pdev->dev, false);
8367 else
8368 device_set_wakeup_enable(&bp->pdev->dev, bp->wol);
8369
Michael Chan4ce45e02012-12-06 10:33:10 +00008370 if (BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5706_A0) {
Michael Chanb6016b72005-05-26 13:03:09 -07008371 bp->tx_quick_cons_trip_int =
8372 bp->tx_quick_cons_trip;
8373 bp->tx_ticks_int = bp->tx_ticks;
8374 bp->rx_quick_cons_trip_int =
8375 bp->rx_quick_cons_trip;
8376 bp->rx_ticks_int = bp->rx_ticks;
8377 bp->comp_prod_trip_int = bp->comp_prod_trip;
8378 bp->com_ticks_int = bp->com_ticks;
8379 bp->cmd_ticks_int = bp->cmd_ticks;
8380 }
8381
Michael Chanf9317a42006-09-29 17:06:23 -07008382 /* Disable MSI on 5706 if AMD 8132 bridge is found.
8383 *
8384 * MSI is defined to be 32-bit write. The 5706 does 64-bit MSI writes
8385 * with byte enables disabled on the unused 32-bit word. This is legal
8386 * but causes problems on the AMD 8132 which will eventually stop
8387 * responding after a while.
8388 *
8389 * AMD believes this incompatibility is unique to the 5706, and
Michael Ellerman88187df2007-01-25 19:34:07 +11008390 * prefers to locally disable MSI rather than globally disabling it.
Michael Chanf9317a42006-09-29 17:06:23 -07008391 */
Michael Chan4ce45e02012-12-06 10:33:10 +00008392 if (BNX2_CHIP(bp) == BNX2_CHIP_5706 && disable_msi == 0) {
Michael Chanf9317a42006-09-29 17:06:23 -07008393 struct pci_dev *amd_8132 = NULL;
8394
8395 while ((amd_8132 = pci_get_device(PCI_VENDOR_ID_AMD,
8396 PCI_DEVICE_ID_AMD_8132_BRIDGE,
8397 amd_8132))) {
Michael Chanf9317a42006-09-29 17:06:23 -07008398
Auke Kok44c10132007-06-08 15:46:36 -07008399 if (amd_8132->revision >= 0x10 &&
8400 amd_8132->revision <= 0x13) {
Michael Chanf9317a42006-09-29 17:06:23 -07008401 disable_msi = 1;
8402 pci_dev_put(amd_8132);
8403 break;
8404 }
8405 }
8406 }
8407
Michael Chandeaf3912007-07-07 22:48:00 -07008408 bnx2_set_default_link(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07008409 bp->req_flow_ctrl = FLOW_CTRL_RX | FLOW_CTRL_TX;
8410
Michael Chancd339a02005-08-25 15:35:24 -07008411 init_timer(&bp->timer);
Benjamin Liac392ab2008-09-18 16:40:49 -07008412 bp->timer.expires = RUN_AT(BNX2_TIMER_INTERVAL);
Michael Chancd339a02005-08-25 15:35:24 -07008413 bp->timer.data = (unsigned long) bp;
8414 bp->timer.function = bnx2_timer;
8415
Michael Chan7625eb22011-06-08 19:29:36 +00008416#ifdef BCM_CNIC
Michael Chan41c21782011-07-13 17:24:22 +00008417 if (bnx2_shmem_rd(bp, BNX2_ISCSI_INITIATOR) & BNX2_ISCSI_INITIATOR_EN)
8418 bp->cnic_eth_dev.max_iscsi_conn =
8419 (bnx2_shmem_rd(bp, BNX2_ISCSI_MAX_CONN) &
8420 BNX2_ISCSI_MAX_CONN_MASK) >> BNX2_ISCSI_MAX_CONN_SHIFT;
Michael Chan4bd9b0ff2012-12-06 10:33:12 +00008421 bp->cnic_probe = bnx2_cnic_probe;
Michael Chan7625eb22011-06-08 19:29:36 +00008422#endif
Michael Chanc239f272010-10-11 16:12:28 -07008423 pci_save_state(pdev);
8424
Michael Chanb6016b72005-05-26 13:03:09 -07008425 return 0;
8426
8427err_out_unmap:
Michael Chan4bb9ebc2011-01-25 22:14:51 +00008428 if (bp->flags & BNX2_FLAG_AER_ENABLED) {
Michael Chanc239f272010-10-11 16:12:28 -07008429 pci_disable_pcie_error_reporting(pdev);
Michael Chan4bb9ebc2011-01-25 22:14:51 +00008430 bp->flags &= ~BNX2_FLAG_AER_ENABLED;
8431 }
Michael Chanc239f272010-10-11 16:12:28 -07008432
Francois Romieuc0357e92012-03-09 14:51:47 +01008433 pci_iounmap(pdev, bp->regview);
8434 bp->regview = NULL;
Michael Chanb6016b72005-05-26 13:03:09 -07008435
8436err_out_release:
8437 pci_release_regions(pdev);
8438
8439err_out_disable:
8440 pci_disable_device(pdev);
Michael Chanb6016b72005-05-26 13:03:09 -07008441
8442err_out:
8443 return rc;
8444}
8445
Bill Pembertoncfd95a62012-12-03 09:22:58 -05008446static char *
Michael Chan883e5152007-05-03 13:25:11 -07008447bnx2_bus_string(struct bnx2 *bp, char *str)
8448{
8449 char *s = str;
8450
David S. Millerf86e82f2008-01-21 17:15:40 -08008451 if (bp->flags & BNX2_FLAG_PCIE) {
Michael Chan883e5152007-05-03 13:25:11 -07008452 s += sprintf(s, "PCI Express");
8453 } else {
8454 s += sprintf(s, "PCI");
David S. Millerf86e82f2008-01-21 17:15:40 -08008455 if (bp->flags & BNX2_FLAG_PCIX)
Michael Chan883e5152007-05-03 13:25:11 -07008456 s += sprintf(s, "-X");
David S. Millerf86e82f2008-01-21 17:15:40 -08008457 if (bp->flags & BNX2_FLAG_PCI_32BIT)
Michael Chan883e5152007-05-03 13:25:11 -07008458 s += sprintf(s, " 32-bit");
8459 else
8460 s += sprintf(s, " 64-bit");
8461 s += sprintf(s, " %dMHz", bp->bus_speed_mhz);
8462 }
8463 return str;
8464}
8465
Michael Chanf048fa92010-06-01 15:05:36 +00008466static void
8467bnx2_del_napi(struct bnx2 *bp)
8468{
8469 int i;
8470
8471 for (i = 0; i < bp->irq_nvecs; i++)
8472 netif_napi_del(&bp->bnx2_napi[i].napi);
8473}
8474
8475static void
Michael Chan35efa7c2007-12-20 19:56:37 -08008476bnx2_init_napi(struct bnx2 *bp)
8477{
Michael Chanb4b36042007-12-20 19:59:30 -08008478 int i;
Michael Chan35efa7c2007-12-20 19:56:37 -08008479
Benjamin Li4327ba42010-03-23 13:13:11 +00008480 for (i = 0; i < bp->irq_nvecs; i++) {
Michael Chan35e90102008-06-19 16:37:42 -07008481 struct bnx2_napi *bnapi = &bp->bnx2_napi[i];
8482 int (*poll)(struct napi_struct *, int);
8483
8484 if (i == 0)
8485 poll = bnx2_poll;
8486 else
Michael Chanf0ea2e62008-06-19 16:41:57 -07008487 poll = bnx2_poll_msix;
Michael Chan35e90102008-06-19 16:37:42 -07008488
8489 netif_napi_add(bp->dev, &bp->bnx2_napi[i].napi, poll, 64);
Michael Chanb4b36042007-12-20 19:59:30 -08008490 bnapi->bp = bp;
8491 }
Michael Chan35efa7c2007-12-20 19:56:37 -08008492}
8493
Stephen Hemminger0421eae2008-11-21 17:31:27 -08008494static const struct net_device_ops bnx2_netdev_ops = {
8495 .ndo_open = bnx2_open,
8496 .ndo_start_xmit = bnx2_start_xmit,
8497 .ndo_stop = bnx2_close,
Eric Dumazet5d07bf22010-07-08 04:08:43 +00008498 .ndo_get_stats64 = bnx2_get_stats64,
Stephen Hemminger0421eae2008-11-21 17:31:27 -08008499 .ndo_set_rx_mode = bnx2_set_rx_mode,
8500 .ndo_do_ioctl = bnx2_ioctl,
8501 .ndo_validate_addr = eth_validate_addr,
8502 .ndo_set_mac_address = bnx2_change_mac_addr,
8503 .ndo_change_mtu = bnx2_change_mtu,
Michał Mirosław8d7dfc22011-04-10 04:47:46 +00008504 .ndo_fix_features = bnx2_fix_features,
8505 .ndo_set_features = bnx2_set_features,
Stephen Hemminger0421eae2008-11-21 17:31:27 -08008506 .ndo_tx_timeout = bnx2_tx_timeout,
Alexey Dobriyan257ddbd2010-01-27 10:17:41 +00008507#ifdef CONFIG_NET_POLL_CONTROLLER
Stephen Hemminger0421eae2008-11-21 17:31:27 -08008508 .ndo_poll_controller = poll_bnx2,
8509#endif
8510};
8511
Bill Pembertoncfd95a62012-12-03 09:22:58 -05008512static int
Michael Chanb6016b72005-05-26 13:03:09 -07008513bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
8514{
8515 static int version_printed = 0;
Francois Romieuc0357e92012-03-09 14:51:47 +01008516 struct net_device *dev;
Michael Chanb6016b72005-05-26 13:03:09 -07008517 struct bnx2 *bp;
Joe Perches0795af52007-10-03 17:59:30 -07008518 int rc;
Michael Chan883e5152007-05-03 13:25:11 -07008519 char str[40];
Michael Chanb6016b72005-05-26 13:03:09 -07008520
8521 if (version_printed++ == 0)
Joe Perches3a9c6a42010-02-17 15:01:51 +00008522 pr_info("%s", version);
Michael Chanb6016b72005-05-26 13:03:09 -07008523
8524 /* dev zeroed in init_etherdev */
Benjamin Li706bf242008-07-18 17:55:11 -07008525 dev = alloc_etherdev_mq(sizeof(*bp), TX_MAX_RINGS);
Michael Chanb6016b72005-05-26 13:03:09 -07008526 if (!dev)
8527 return -ENOMEM;
8528
8529 rc = bnx2_init_board(pdev, dev);
Francois Romieuc0357e92012-03-09 14:51:47 +01008530 if (rc < 0)
8531 goto err_free;
Michael Chanb6016b72005-05-26 13:03:09 -07008532
Stephen Hemminger0421eae2008-11-21 17:31:27 -08008533 dev->netdev_ops = &bnx2_netdev_ops;
Michael Chanb6016b72005-05-26 13:03:09 -07008534 dev->watchdog_timeo = TX_TIMEOUT;
Michael Chanb6016b72005-05-26 13:03:09 -07008535 dev->ethtool_ops = &bnx2_ethtool_ops;
Michael Chanb6016b72005-05-26 13:03:09 -07008536
Michael Chan972ec0d2006-01-23 16:12:43 -08008537 bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07008538
Michael Chan1b2f9222007-05-03 13:20:19 -07008539 pci_set_drvdata(pdev, dev);
8540
Joe Perchesd458cdf2013-10-01 19:04:40 -07008541 memcpy(dev->dev_addr, bp->mac_addr, ETH_ALEN);
Michael Chan1b2f9222007-05-03 13:20:19 -07008542
Michał Mirosław8d7dfc22011-04-10 04:47:46 +00008543 dev->hw_features = NETIF_F_IP_CSUM | NETIF_F_SG |
8544 NETIF_F_TSO | NETIF_F_TSO_ECN |
8545 NETIF_F_RXHASH | NETIF_F_RXCSUM;
8546
Michael Chan4ce45e02012-12-06 10:33:10 +00008547 if (BNX2_CHIP(bp) == BNX2_CHIP_5709)
Michał Mirosław8d7dfc22011-04-10 04:47:46 +00008548 dev->hw_features |= NETIF_F_IPV6_CSUM | NETIF_F_TSO6;
8549
8550 dev->vlan_features = dev->hw_features;
Patrick McHardyf6469682013-04-19 02:04:27 +00008551 dev->hw_features |= NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX;
Michał Mirosław8d7dfc22011-04-10 04:47:46 +00008552 dev->features |= dev->hw_features;
Jiri Pirko01789342011-08-16 06:29:00 +00008553 dev->priv_flags |= IFF_UNICAST_FLT;
Michał Mirosław8d7dfc22011-04-10 04:47:46 +00008554
Michael Chanb6016b72005-05-26 13:03:09 -07008555 if ((rc = register_netdev(dev))) {
Jeff Garzik9b91cf92006-06-27 11:39:50 -04008556 dev_err(&pdev->dev, "Cannot register net device\n");
Michael Chan57579f72009-04-04 16:51:14 -07008557 goto error;
Michael Chanb6016b72005-05-26 13:03:09 -07008558 }
8559
Francois Romieuc0357e92012-03-09 14:51:47 +01008560 netdev_info(dev, "%s (%c%d) %s found at mem %lx, IRQ %d, "
8561 "node addr %pM\n", board_info[ent->driver_data].name,
Michael Chan4ce45e02012-12-06 10:33:10 +00008562 ((BNX2_CHIP_ID(bp) & 0xf000) >> 12) + 'A',
8563 ((BNX2_CHIP_ID(bp) & 0x0ff0) >> 4),
Francois Romieuc0357e92012-03-09 14:51:47 +01008564 bnx2_bus_string(bp, str), (long)pci_resource_start(pdev, 0),
8565 pdev->irq, dev->dev_addr);
Michael Chanb6016b72005-05-26 13:03:09 -07008566
Michael Chanb6016b72005-05-26 13:03:09 -07008567 return 0;
Michael Chan57579f72009-04-04 16:51:14 -07008568
8569error:
Michael Chanfda4d852012-12-11 18:24:20 -08008570 pci_iounmap(pdev, bp->regview);
Michael Chan57579f72009-04-04 16:51:14 -07008571 pci_release_regions(pdev);
8572 pci_disable_device(pdev);
Francois Romieuc0357e92012-03-09 14:51:47 +01008573err_free:
Michael Chan57579f72009-04-04 16:51:14 -07008574 free_netdev(dev);
8575 return rc;
Michael Chanb6016b72005-05-26 13:03:09 -07008576}
8577
Bill Pembertoncfd95a62012-12-03 09:22:58 -05008578static void
Michael Chanb6016b72005-05-26 13:03:09 -07008579bnx2_remove_one(struct pci_dev *pdev)
8580{
8581 struct net_device *dev = pci_get_drvdata(pdev);
Michael Chan972ec0d2006-01-23 16:12:43 -08008582 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07008583
8584 unregister_netdev(dev);
8585
Neil Horman8333a462011-04-26 10:30:11 +00008586 del_timer_sync(&bp->timer);
Michael Chancd634012011-07-15 06:53:58 +00008587 cancel_work_sync(&bp->reset_task);
Neil Horman8333a462011-04-26 10:30:11 +00008588
Francois Romieuc0357e92012-03-09 14:51:47 +01008589 pci_iounmap(bp->pdev, bp->regview);
Michael Chanb6016b72005-05-26 13:03:09 -07008590
Michael Chan354fcd72010-01-17 07:30:44 +00008591 kfree(bp->temp_stats_blk);
8592
Michael Chan4bb9ebc2011-01-25 22:14:51 +00008593 if (bp->flags & BNX2_FLAG_AER_ENABLED) {
Michael Chanc239f272010-10-11 16:12:28 -07008594 pci_disable_pcie_error_reporting(pdev);
Michael Chan4bb9ebc2011-01-25 22:14:51 +00008595 bp->flags &= ~BNX2_FLAG_AER_ENABLED;
8596 }
John Feeneycd709aa2010-08-22 17:45:53 +00008597
françois romieu7880b722011-09-30 00:36:52 +00008598 bnx2_release_firmware(bp);
8599
Michael Chanc239f272010-10-11 16:12:28 -07008600 free_netdev(dev);
John Feeneycd709aa2010-08-22 17:45:53 +00008601
Michael Chanb6016b72005-05-26 13:03:09 -07008602 pci_release_regions(pdev);
8603 pci_disable_device(pdev);
Michael Chanb6016b72005-05-26 13:03:09 -07008604}
8605
8606static int
Michael Chan28fb4eb2013-08-06 15:50:10 -07008607bnx2_suspend(struct device *device)
Michael Chanb6016b72005-05-26 13:03:09 -07008608{
Michael Chan28fb4eb2013-08-06 15:50:10 -07008609 struct pci_dev *pdev = to_pci_dev(device);
Michael Chanb6016b72005-05-26 13:03:09 -07008610 struct net_device *dev = pci_get_drvdata(pdev);
Michael Chan972ec0d2006-01-23 16:12:43 -08008611 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07008612
Michael Chan28fb4eb2013-08-06 15:50:10 -07008613 if (netif_running(dev)) {
8614 cancel_work_sync(&bp->reset_task);
8615 bnx2_netif_stop(bp, true);
8616 netif_device_detach(dev);
8617 del_timer_sync(&bp->timer);
8618 bnx2_shutdown_chip(bp);
8619 __bnx2_free_irq(bp);
8620 bnx2_free_skbs(bp);
8621 }
8622 bnx2_setup_wol(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07008623 return 0;
8624}
8625
8626static int
Michael Chan28fb4eb2013-08-06 15:50:10 -07008627bnx2_resume(struct device *device)
Michael Chanb6016b72005-05-26 13:03:09 -07008628{
Michael Chan28fb4eb2013-08-06 15:50:10 -07008629 struct pci_dev *pdev = to_pci_dev(device);
Michael Chanb6016b72005-05-26 13:03:09 -07008630 struct net_device *dev = pci_get_drvdata(pdev);
Michael Chan972ec0d2006-01-23 16:12:43 -08008631 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07008632
8633 if (!netif_running(dev))
8634 return 0;
8635
Pavel Machek829ca9a2005-09-03 15:56:56 -07008636 bnx2_set_power_state(bp, PCI_D0);
Michael Chanb6016b72005-05-26 13:03:09 -07008637 netif_device_attach(dev);
Michael Chan28fb4eb2013-08-06 15:50:10 -07008638 bnx2_request_irq(bp);
Michael Chan9a120bc2008-05-16 22:17:45 -07008639 bnx2_init_nic(bp, 1);
Michael Chan212f9932010-04-27 11:28:10 +00008640 bnx2_netif_start(bp, true);
Michael Chanb6016b72005-05-26 13:03:09 -07008641 return 0;
8642}
8643
Michael Chan28fb4eb2013-08-06 15:50:10 -07008644#ifdef CONFIG_PM_SLEEP
8645static SIMPLE_DEV_PM_OPS(bnx2_pm_ops, bnx2_suspend, bnx2_resume);
8646#define BNX2_PM_OPS (&bnx2_pm_ops)
8647
8648#else
8649
8650#define BNX2_PM_OPS NULL
8651
8652#endif /* CONFIG_PM_SLEEP */
Wendy Xiong6ff2da42008-05-16 22:18:21 -07008653/**
8654 * bnx2_io_error_detected - called when PCI error is detected
8655 * @pdev: Pointer to PCI device
8656 * @state: The current pci connection state
8657 *
8658 * This function is called after a PCI bus error affecting
8659 * this device has been detected.
8660 */
8661static pci_ers_result_t bnx2_io_error_detected(struct pci_dev *pdev,
8662 pci_channel_state_t state)
8663{
8664 struct net_device *dev = pci_get_drvdata(pdev);
8665 struct bnx2 *bp = netdev_priv(dev);
8666
8667 rtnl_lock();
8668 netif_device_detach(dev);
8669
Dean Nelson2ec3de22009-07-31 09:13:18 +00008670 if (state == pci_channel_io_perm_failure) {
8671 rtnl_unlock();
8672 return PCI_ERS_RESULT_DISCONNECT;
8673 }
8674
Wendy Xiong6ff2da42008-05-16 22:18:21 -07008675 if (netif_running(dev)) {
Michael Chan212f9932010-04-27 11:28:10 +00008676 bnx2_netif_stop(bp, true);
Wendy Xiong6ff2da42008-05-16 22:18:21 -07008677 del_timer_sync(&bp->timer);
8678 bnx2_reset_nic(bp, BNX2_DRV_MSG_CODE_RESET);
8679 }
8680
8681 pci_disable_device(pdev);
8682 rtnl_unlock();
8683
8684 /* Request a slot slot reset. */
8685 return PCI_ERS_RESULT_NEED_RESET;
8686}
8687
8688/**
8689 * bnx2_io_slot_reset - called after the pci bus has been reset.
8690 * @pdev: Pointer to PCI device
8691 *
8692 * Restart the card from scratch, as if from a cold-boot.
8693 */
8694static pci_ers_result_t bnx2_io_slot_reset(struct pci_dev *pdev)
8695{
8696 struct net_device *dev = pci_get_drvdata(pdev);
8697 struct bnx2 *bp = netdev_priv(dev);
Michael Chan02481bc2013-08-06 15:50:07 -07008698 pci_ers_result_t result = PCI_ERS_RESULT_DISCONNECT;
8699 int err = 0;
Wendy Xiong6ff2da42008-05-16 22:18:21 -07008700
8701 rtnl_lock();
8702 if (pci_enable_device(pdev)) {
8703 dev_err(&pdev->dev,
Joe Perches3a9c6a42010-02-17 15:01:51 +00008704 "Cannot re-enable PCI device after reset\n");
John Feeneycd709aa2010-08-22 17:45:53 +00008705 } else {
8706 pci_set_master(pdev);
8707 pci_restore_state(pdev);
8708 pci_save_state(pdev);
Wendy Xiong6ff2da42008-05-16 22:18:21 -07008709
Michael Chan25bfb1d2013-08-06 15:50:11 -07008710 if (netif_running(dev))
Michael Chan02481bc2013-08-06 15:50:07 -07008711 err = bnx2_init_nic(bp, 1);
Michael Chan25bfb1d2013-08-06 15:50:11 -07008712
Michael Chan02481bc2013-08-06 15:50:07 -07008713 if (!err)
8714 result = PCI_ERS_RESULT_RECOVERED;
8715 }
8716
8717 if (result != PCI_ERS_RESULT_RECOVERED && netif_running(dev)) {
8718 bnx2_napi_enable(bp);
8719 dev_close(dev);
Wendy Xiong6ff2da42008-05-16 22:18:21 -07008720 }
Wendy Xiong6ff2da42008-05-16 22:18:21 -07008721 rtnl_unlock();
John Feeneycd709aa2010-08-22 17:45:53 +00008722
Michael Chan4bb9ebc2011-01-25 22:14:51 +00008723 if (!(bp->flags & BNX2_FLAG_AER_ENABLED))
Michael Chanc239f272010-10-11 16:12:28 -07008724 return result;
8725
John Feeneycd709aa2010-08-22 17:45:53 +00008726 err = pci_cleanup_aer_uncorrect_error_status(pdev);
8727 if (err) {
8728 dev_err(&pdev->dev,
8729 "pci_cleanup_aer_uncorrect_error_status failed 0x%0x\n",
8730 err); /* non-fatal, continue */
8731 }
8732
8733 return result;
Wendy Xiong6ff2da42008-05-16 22:18:21 -07008734}
8735
8736/**
8737 * bnx2_io_resume - called when traffic can start flowing again.
8738 * @pdev: Pointer to PCI device
8739 *
8740 * This callback is called when the error recovery driver tells us that
8741 * its OK to resume normal operation.
8742 */
8743static void bnx2_io_resume(struct pci_dev *pdev)
8744{
8745 struct net_device *dev = pci_get_drvdata(pdev);
8746 struct bnx2 *bp = netdev_priv(dev);
8747
8748 rtnl_lock();
8749 if (netif_running(dev))
Michael Chan212f9932010-04-27 11:28:10 +00008750 bnx2_netif_start(bp, true);
Wendy Xiong6ff2da42008-05-16 22:18:21 -07008751
8752 netif_device_attach(dev);
8753 rtnl_unlock();
8754}
8755
Michael Chan25bfb1d2013-08-06 15:50:11 -07008756static void bnx2_shutdown(struct pci_dev *pdev)
8757{
8758 struct net_device *dev = pci_get_drvdata(pdev);
8759 struct bnx2 *bp;
8760
8761 if (!dev)
8762 return;
8763
8764 bp = netdev_priv(dev);
8765 if (!bp)
8766 return;
8767
8768 rtnl_lock();
8769 if (netif_running(dev))
8770 dev_close(bp->dev);
8771
8772 if (system_state == SYSTEM_POWER_OFF)
8773 bnx2_set_power_state(bp, PCI_D3hot);
8774
8775 rtnl_unlock();
8776}
8777
Michael Chanfda4d852012-12-11 18:24:20 -08008778static const struct pci_error_handlers bnx2_err_handler = {
Wendy Xiong6ff2da42008-05-16 22:18:21 -07008779 .error_detected = bnx2_io_error_detected,
8780 .slot_reset = bnx2_io_slot_reset,
8781 .resume = bnx2_io_resume,
8782};
8783
Michael Chanb6016b72005-05-26 13:03:09 -07008784static struct pci_driver bnx2_pci_driver = {
Peter Hagervall14ab9b82005-08-10 14:18:16 -07008785 .name = DRV_MODULE_NAME,
8786 .id_table = bnx2_pci_tbl,
8787 .probe = bnx2_init_one,
Bill Pembertoncfd95a62012-12-03 09:22:58 -05008788 .remove = bnx2_remove_one,
Michael Chan28fb4eb2013-08-06 15:50:10 -07008789 .driver.pm = BNX2_PM_OPS,
Wendy Xiong6ff2da42008-05-16 22:18:21 -07008790 .err_handler = &bnx2_err_handler,
Michael Chan25bfb1d2013-08-06 15:50:11 -07008791 .shutdown = bnx2_shutdown,
Michael Chanb6016b72005-05-26 13:03:09 -07008792};
8793
Peter Hüwe5a4123f2013-05-21 12:58:05 +00008794module_pci_driver(bnx2_pci_driver);