blob: b380c69d57a557088e416532521803b76abc8416 [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 Chanca58c3a2007-05-03 13:22:52 -07001200 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chanb6016b72005-05-26 13:03:09 -07001201 if (bmcr & BMCR_ANENABLE) {
1202 u32 local_adv, remote_adv, common;
1203
1204 bnx2_read_phy(bp, MII_CTRL1000, &local_adv);
1205 bnx2_read_phy(bp, MII_STAT1000, &remote_adv);
1206
1207 common = local_adv & (remote_adv >> 2);
1208 if (common & ADVERTISE_1000FULL) {
1209 bp->line_speed = SPEED_1000;
1210 bp->duplex = DUPLEX_FULL;
1211 }
1212 else if (common & ADVERTISE_1000HALF) {
1213 bp->line_speed = SPEED_1000;
1214 bp->duplex = DUPLEX_HALF;
1215 }
1216 else {
Michael Chanca58c3a2007-05-03 13:22:52 -07001217 bnx2_read_phy(bp, bp->mii_adv, &local_adv);
1218 bnx2_read_phy(bp, bp->mii_lpa, &remote_adv);
Michael Chanb6016b72005-05-26 13:03:09 -07001219
1220 common = local_adv & remote_adv;
1221 if (common & ADVERTISE_100FULL) {
1222 bp->line_speed = SPEED_100;
1223 bp->duplex = DUPLEX_FULL;
1224 }
1225 else if (common & ADVERTISE_100HALF) {
1226 bp->line_speed = SPEED_100;
1227 bp->duplex = DUPLEX_HALF;
1228 }
1229 else if (common & ADVERTISE_10FULL) {
1230 bp->line_speed = SPEED_10;
1231 bp->duplex = DUPLEX_FULL;
1232 }
1233 else if (common & ADVERTISE_10HALF) {
1234 bp->line_speed = SPEED_10;
1235 bp->duplex = DUPLEX_HALF;
1236 }
1237 else {
1238 bp->line_speed = 0;
1239 bp->link_up = 0;
1240 }
1241 }
1242 }
1243 else {
1244 if (bmcr & BMCR_SPEED100) {
1245 bp->line_speed = SPEED_100;
1246 }
1247 else {
1248 bp->line_speed = SPEED_10;
1249 }
1250 if (bmcr & BMCR_FULLDPLX) {
1251 bp->duplex = DUPLEX_FULL;
1252 }
1253 else {
1254 bp->duplex = DUPLEX_HALF;
1255 }
1256 }
1257
1258 return 0;
1259}
1260
Michael Chan83e3fc82008-01-29 21:37:17 -08001261static void
Michael Chanbb4f98a2008-06-19 16:38:19 -07001262bnx2_init_rx_context(struct bnx2 *bp, u32 cid)
Michael Chan83e3fc82008-01-29 21:37:17 -08001263{
Michael Chanbb4f98a2008-06-19 16:38:19 -07001264 u32 val, rx_cid_addr = GET_CID_ADDR(cid);
Michael Chan83e3fc82008-01-29 21:37:17 -08001265
1266 val = BNX2_L2CTX_CTX_TYPE_CTX_BD_CHN_TYPE_VALUE;
1267 val |= BNX2_L2CTX_CTX_TYPE_SIZE_L2;
1268 val |= 0x02 << 8;
1269
Michael Chan22fa1592010-10-11 16:12:00 -07001270 if (bp->flow_ctrl & FLOW_CTRL_TX)
1271 val |= BNX2_L2CTX_FLOW_CTRL_ENABLE;
Michael Chan83e3fc82008-01-29 21:37:17 -08001272
Michael Chan83e3fc82008-01-29 21:37:17 -08001273 bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_CTX_TYPE, val);
1274}
1275
Michael Chanbb4f98a2008-06-19 16:38:19 -07001276static void
1277bnx2_init_all_rx_contexts(struct bnx2 *bp)
1278{
1279 int i;
1280 u32 cid;
1281
1282 for (i = 0, cid = RX_CID; i < bp->num_rx_rings; i++, cid++) {
1283 if (i == 1)
1284 cid = RX_RSS_CID;
1285 bnx2_init_rx_context(bp, cid);
1286 }
1287}
1288
Benjamin Li344478d2008-09-18 16:38:24 -07001289static void
Michael Chanb6016b72005-05-26 13:03:09 -07001290bnx2_set_mac_link(struct bnx2 *bp)
1291{
1292 u32 val;
1293
Michael Chane503e062012-12-06 10:33:08 +00001294 BNX2_WR(bp, BNX2_EMAC_TX_LENGTHS, 0x2620);
Michael Chanb6016b72005-05-26 13:03:09 -07001295 if (bp->link_up && (bp->line_speed == SPEED_1000) &&
1296 (bp->duplex == DUPLEX_HALF)) {
Michael Chane503e062012-12-06 10:33:08 +00001297 BNX2_WR(bp, BNX2_EMAC_TX_LENGTHS, 0x26ff);
Michael Chanb6016b72005-05-26 13:03:09 -07001298 }
1299
1300 /* Configure the EMAC mode register. */
Michael Chane503e062012-12-06 10:33:08 +00001301 val = BNX2_RD(bp, BNX2_EMAC_MODE);
Michael Chanb6016b72005-05-26 13:03:09 -07001302
1303 val &= ~(BNX2_EMAC_MODE_PORT | BNX2_EMAC_MODE_HALF_DUPLEX |
Michael Chan5b0c76a2005-11-04 08:45:49 -08001304 BNX2_EMAC_MODE_MAC_LOOP | BNX2_EMAC_MODE_FORCE_LINK |
Michael Chan59b47d82006-11-19 14:10:45 -08001305 BNX2_EMAC_MODE_25G_MODE);
Michael Chanb6016b72005-05-26 13:03:09 -07001306
1307 if (bp->link_up) {
Michael Chan5b0c76a2005-11-04 08:45:49 -08001308 switch (bp->line_speed) {
1309 case SPEED_10:
Michael Chan4ce45e02012-12-06 10:33:10 +00001310 if (BNX2_CHIP(bp) != BNX2_CHIP_5706) {
Michael Chan59b47d82006-11-19 14:10:45 -08001311 val |= BNX2_EMAC_MODE_PORT_MII_10M;
Michael Chan5b0c76a2005-11-04 08:45:49 -08001312 break;
1313 }
1314 /* fall through */
1315 case SPEED_100:
1316 val |= BNX2_EMAC_MODE_PORT_MII;
1317 break;
1318 case SPEED_2500:
Michael Chan59b47d82006-11-19 14:10:45 -08001319 val |= BNX2_EMAC_MODE_25G_MODE;
Michael Chan5b0c76a2005-11-04 08:45:49 -08001320 /* fall through */
1321 case SPEED_1000:
1322 val |= BNX2_EMAC_MODE_PORT_GMII;
1323 break;
1324 }
Michael Chanb6016b72005-05-26 13:03:09 -07001325 }
1326 else {
1327 val |= BNX2_EMAC_MODE_PORT_GMII;
1328 }
1329
1330 /* Set the MAC to operate in the appropriate duplex mode. */
1331 if (bp->duplex == DUPLEX_HALF)
1332 val |= BNX2_EMAC_MODE_HALF_DUPLEX;
Michael Chane503e062012-12-06 10:33:08 +00001333 BNX2_WR(bp, BNX2_EMAC_MODE, val);
Michael Chanb6016b72005-05-26 13:03:09 -07001334
1335 /* Enable/disable rx PAUSE. */
1336 bp->rx_mode &= ~BNX2_EMAC_RX_MODE_FLOW_EN;
1337
1338 if (bp->flow_ctrl & FLOW_CTRL_RX)
1339 bp->rx_mode |= BNX2_EMAC_RX_MODE_FLOW_EN;
Michael Chane503e062012-12-06 10:33:08 +00001340 BNX2_WR(bp, BNX2_EMAC_RX_MODE, bp->rx_mode);
Michael Chanb6016b72005-05-26 13:03:09 -07001341
1342 /* Enable/disable tx PAUSE. */
Michael Chane503e062012-12-06 10:33:08 +00001343 val = BNX2_RD(bp, BNX2_EMAC_TX_MODE);
Michael Chanb6016b72005-05-26 13:03:09 -07001344 val &= ~BNX2_EMAC_TX_MODE_FLOW_EN;
1345
1346 if (bp->flow_ctrl & FLOW_CTRL_TX)
1347 val |= BNX2_EMAC_TX_MODE_FLOW_EN;
Michael Chane503e062012-12-06 10:33:08 +00001348 BNX2_WR(bp, BNX2_EMAC_TX_MODE, val);
Michael Chanb6016b72005-05-26 13:03:09 -07001349
1350 /* Acknowledge the interrupt. */
Michael Chane503e062012-12-06 10:33:08 +00001351 BNX2_WR(bp, BNX2_EMAC_STATUS, BNX2_EMAC_STATUS_LINK_CHANGE);
Michael Chanb6016b72005-05-26 13:03:09 -07001352
Michael Chan22fa1592010-10-11 16:12:00 -07001353 bnx2_init_all_rx_contexts(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07001354}
1355
Michael Chan27a005b2007-05-03 13:23:41 -07001356static void
1357bnx2_enable_bmsr1(struct bnx2 *bp)
1358{
Michael Chan583c28e2008-01-21 19:51:35 -08001359 if ((bp->phy_flags & BNX2_PHY_FLAG_SERDES) &&
Michael Chan4ce45e02012-12-06 10:33:10 +00001360 (BNX2_CHIP(bp) == BNX2_CHIP_5709))
Michael Chan27a005b2007-05-03 13:23:41 -07001361 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
1362 MII_BNX2_BLK_ADDR_GP_STATUS);
1363}
1364
1365static void
1366bnx2_disable_bmsr1(struct bnx2 *bp)
1367{
Michael Chan583c28e2008-01-21 19:51:35 -08001368 if ((bp->phy_flags & BNX2_PHY_FLAG_SERDES) &&
Michael Chan4ce45e02012-12-06 10:33:10 +00001369 (BNX2_CHIP(bp) == BNX2_CHIP_5709))
Michael Chan27a005b2007-05-03 13:23:41 -07001370 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
1371 MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
1372}
1373
Michael Chanb6016b72005-05-26 13:03:09 -07001374static int
Michael Chan605a9e22007-05-03 13:23:13 -07001375bnx2_test_and_enable_2g5(struct bnx2 *bp)
1376{
1377 u32 up1;
1378 int ret = 1;
1379
Michael Chan583c28e2008-01-21 19:51:35 -08001380 if (!(bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE))
Michael Chan605a9e22007-05-03 13:23:13 -07001381 return 0;
1382
1383 if (bp->autoneg & AUTONEG_SPEED)
1384 bp->advertising |= ADVERTISED_2500baseX_Full;
1385
Michael Chan4ce45e02012-12-06 10:33:10 +00001386 if (BNX2_CHIP(bp) == BNX2_CHIP_5709)
Michael Chan27a005b2007-05-03 13:23:41 -07001387 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_OVER1G);
1388
Michael Chan605a9e22007-05-03 13:23:13 -07001389 bnx2_read_phy(bp, bp->mii_up1, &up1);
1390 if (!(up1 & BCM5708S_UP1_2G5)) {
1391 up1 |= BCM5708S_UP1_2G5;
1392 bnx2_write_phy(bp, bp->mii_up1, up1);
1393 ret = 0;
1394 }
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,
1398 MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
1399
Michael Chan605a9e22007-05-03 13:23:13 -07001400 return ret;
1401}
1402
1403static int
1404bnx2_test_and_disable_2g5(struct bnx2 *bp)
1405{
1406 u32 up1;
1407 int ret = 0;
1408
Michael Chan583c28e2008-01-21 19:51:35 -08001409 if (!(bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE))
Michael Chan605a9e22007-05-03 13:23:13 -07001410 return 0;
1411
Michael Chan4ce45e02012-12-06 10:33:10 +00001412 if (BNX2_CHIP(bp) == BNX2_CHIP_5709)
Michael Chan27a005b2007-05-03 13:23:41 -07001413 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_OVER1G);
1414
Michael Chan605a9e22007-05-03 13:23:13 -07001415 bnx2_read_phy(bp, bp->mii_up1, &up1);
1416 if (up1 & BCM5708S_UP1_2G5) {
1417 up1 &= ~BCM5708S_UP1_2G5;
1418 bnx2_write_phy(bp, bp->mii_up1, up1);
1419 ret = 1;
1420 }
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,
1424 MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
1425
Michael Chan605a9e22007-05-03 13:23:13 -07001426 return ret;
1427}
1428
1429static void
1430bnx2_enable_forced_2g5(struct bnx2 *bp)
1431{
Michael Chancbd68902010-06-08 07:21:30 +00001432 u32 uninitialized_var(bmcr);
1433 int err;
Michael Chan605a9e22007-05-03 13:23:13 -07001434
Michael Chan583c28e2008-01-21 19:51:35 -08001435 if (!(bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE))
Michael Chan605a9e22007-05-03 13:23:13 -07001436 return;
1437
Michael Chan4ce45e02012-12-06 10:33:10 +00001438 if (BNX2_CHIP(bp) == BNX2_CHIP_5709) {
Michael Chan27a005b2007-05-03 13:23:41 -07001439 u32 val;
1440
1441 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
1442 MII_BNX2_BLK_ADDR_SERDES_DIG);
Michael Chancbd68902010-06-08 07:21:30 +00001443 if (!bnx2_read_phy(bp, MII_BNX2_SERDES_DIG_MISC1, &val)) {
1444 val &= ~MII_BNX2_SD_MISC1_FORCE_MSK;
1445 val |= MII_BNX2_SD_MISC1_FORCE |
1446 MII_BNX2_SD_MISC1_FORCE_2_5G;
1447 bnx2_write_phy(bp, MII_BNX2_SERDES_DIG_MISC1, val);
1448 }
Michael Chan27a005b2007-05-03 13:23:41 -07001449
1450 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
1451 MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
Michael Chancbd68902010-06-08 07:21:30 +00001452 err = bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chan27a005b2007-05-03 13:23:41 -07001453
Michael Chan4ce45e02012-12-06 10:33:10 +00001454 } else if (BNX2_CHIP(bp) == BNX2_CHIP_5708) {
Michael Chancbd68902010-06-08 07:21:30 +00001455 err = bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
1456 if (!err)
1457 bmcr |= BCM5708S_BMCR_FORCE_2500;
Eric Dumazetc70798572009-11-02 23:17:42 +00001458 } else {
1459 return;
Michael Chan605a9e22007-05-03 13:23:13 -07001460 }
1461
Michael Chancbd68902010-06-08 07:21:30 +00001462 if (err)
1463 return;
1464
Michael Chan605a9e22007-05-03 13:23:13 -07001465 if (bp->autoneg & AUTONEG_SPEED) {
1466 bmcr &= ~BMCR_ANENABLE;
1467 if (bp->req_duplex == DUPLEX_FULL)
1468 bmcr |= BMCR_FULLDPLX;
1469 }
1470 bnx2_write_phy(bp, bp->mii_bmcr, bmcr);
1471}
1472
1473static void
1474bnx2_disable_forced_2g5(struct bnx2 *bp)
1475{
Michael Chancbd68902010-06-08 07:21:30 +00001476 u32 uninitialized_var(bmcr);
1477 int err;
Michael Chan605a9e22007-05-03 13:23:13 -07001478
Michael Chan583c28e2008-01-21 19:51:35 -08001479 if (!(bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE))
Michael Chan605a9e22007-05-03 13:23:13 -07001480 return;
1481
Michael Chan4ce45e02012-12-06 10:33:10 +00001482 if (BNX2_CHIP(bp) == BNX2_CHIP_5709) {
Michael Chan27a005b2007-05-03 13:23:41 -07001483 u32 val;
1484
1485 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
1486 MII_BNX2_BLK_ADDR_SERDES_DIG);
Michael Chancbd68902010-06-08 07:21:30 +00001487 if (!bnx2_read_phy(bp, MII_BNX2_SERDES_DIG_MISC1, &val)) {
1488 val &= ~MII_BNX2_SD_MISC1_FORCE;
1489 bnx2_write_phy(bp, MII_BNX2_SERDES_DIG_MISC1, val);
1490 }
Michael Chan27a005b2007-05-03 13:23:41 -07001491
1492 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
1493 MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
Michael Chancbd68902010-06-08 07:21:30 +00001494 err = bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chan27a005b2007-05-03 13:23:41 -07001495
Michael Chan4ce45e02012-12-06 10:33:10 +00001496 } else if (BNX2_CHIP(bp) == BNX2_CHIP_5708) {
Michael Chancbd68902010-06-08 07:21:30 +00001497 err = bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
1498 if (!err)
1499 bmcr &= ~BCM5708S_BMCR_FORCE_2500;
Eric Dumazetc70798572009-11-02 23:17:42 +00001500 } else {
1501 return;
Michael Chan605a9e22007-05-03 13:23:13 -07001502 }
1503
Michael Chancbd68902010-06-08 07:21:30 +00001504 if (err)
1505 return;
1506
Michael Chan605a9e22007-05-03 13:23:13 -07001507 if (bp->autoneg & AUTONEG_SPEED)
1508 bmcr |= BMCR_SPEED1000 | BMCR_ANENABLE | BMCR_ANRESTART;
1509 bnx2_write_phy(bp, bp->mii_bmcr, bmcr);
1510}
1511
Michael Chanb2fadea2008-01-21 17:07:06 -08001512static void
1513bnx2_5706s_force_link_dn(struct bnx2 *bp, int start)
1514{
1515 u32 val;
1516
1517 bnx2_write_phy(bp, MII_BNX2_DSP_ADDRESS, MII_EXPAND_SERDES_CTL);
1518 bnx2_read_phy(bp, MII_BNX2_DSP_RW_PORT, &val);
1519 if (start)
1520 bnx2_write_phy(bp, MII_BNX2_DSP_RW_PORT, val & 0xff0f);
1521 else
1522 bnx2_write_phy(bp, MII_BNX2_DSP_RW_PORT, val | 0xc0);
1523}
1524
Michael Chan605a9e22007-05-03 13:23:13 -07001525static int
Michael Chanb6016b72005-05-26 13:03:09 -07001526bnx2_set_link(struct bnx2 *bp)
1527{
1528 u32 bmsr;
1529 u8 link_up;
1530
Michael Chan80be4432006-11-19 14:07:28 -08001531 if (bp->loopback == MAC_LOOPBACK || bp->loopback == PHY_LOOPBACK) {
Michael Chanb6016b72005-05-26 13:03:09 -07001532 bp->link_up = 1;
1533 return 0;
1534 }
1535
Michael Chan583c28e2008-01-21 19:51:35 -08001536 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
Michael Chan0d8a6572007-07-07 22:49:43 -07001537 return 0;
1538
Michael Chanb6016b72005-05-26 13:03:09 -07001539 link_up = bp->link_up;
1540
Michael Chan27a005b2007-05-03 13:23:41 -07001541 bnx2_enable_bmsr1(bp);
1542 bnx2_read_phy(bp, bp->mii_bmsr1, &bmsr);
1543 bnx2_read_phy(bp, bp->mii_bmsr1, &bmsr);
1544 bnx2_disable_bmsr1(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07001545
Michael Chan583c28e2008-01-21 19:51:35 -08001546 if ((bp->phy_flags & BNX2_PHY_FLAG_SERDES) &&
Michael Chan4ce45e02012-12-06 10:33:10 +00001547 (BNX2_CHIP(bp) == BNX2_CHIP_5706)) {
Michael Chana2724e22008-02-23 19:47:44 -08001548 u32 val, an_dbg;
Michael Chanb6016b72005-05-26 13:03:09 -07001549
Michael Chan583c28e2008-01-21 19:51:35 -08001550 if (bp->phy_flags & BNX2_PHY_FLAG_FORCED_DOWN) {
Michael Chanb2fadea2008-01-21 17:07:06 -08001551 bnx2_5706s_force_link_dn(bp, 0);
Michael Chan583c28e2008-01-21 19:51:35 -08001552 bp->phy_flags &= ~BNX2_PHY_FLAG_FORCED_DOWN;
Michael Chanb2fadea2008-01-21 17:07:06 -08001553 }
Michael Chane503e062012-12-06 10:33:08 +00001554 val = BNX2_RD(bp, BNX2_EMAC_STATUS);
Michael Chana2724e22008-02-23 19:47:44 -08001555
1556 bnx2_write_phy(bp, MII_BNX2_MISC_SHADOW, MISC_SHDW_AN_DBG);
1557 bnx2_read_phy(bp, MII_BNX2_MISC_SHADOW, &an_dbg);
1558 bnx2_read_phy(bp, MII_BNX2_MISC_SHADOW, &an_dbg);
1559
1560 if ((val & BNX2_EMAC_STATUS_LINK) &&
1561 !(an_dbg & MISC_SHDW_AN_DBG_NOSYNC))
Michael Chanb6016b72005-05-26 13:03:09 -07001562 bmsr |= BMSR_LSTATUS;
1563 else
1564 bmsr &= ~BMSR_LSTATUS;
1565 }
1566
1567 if (bmsr & BMSR_LSTATUS) {
1568 bp->link_up = 1;
1569
Michael Chan583c28e2008-01-21 19:51:35 -08001570 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Michael Chan4ce45e02012-12-06 10:33:10 +00001571 if (BNX2_CHIP(bp) == BNX2_CHIP_5706)
Michael Chan5b0c76a2005-11-04 08:45:49 -08001572 bnx2_5706s_linkup(bp);
Michael Chan4ce45e02012-12-06 10:33:10 +00001573 else if (BNX2_CHIP(bp) == BNX2_CHIP_5708)
Michael Chan5b0c76a2005-11-04 08:45:49 -08001574 bnx2_5708s_linkup(bp);
Michael Chan4ce45e02012-12-06 10:33:10 +00001575 else if (BNX2_CHIP(bp) == BNX2_CHIP_5709)
Michael Chan27a005b2007-05-03 13:23:41 -07001576 bnx2_5709s_linkup(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07001577 }
1578 else {
1579 bnx2_copper_linkup(bp);
1580 }
1581 bnx2_resolve_flow_ctrl(bp);
1582 }
1583 else {
Michael Chan583c28e2008-01-21 19:51:35 -08001584 if ((bp->phy_flags & BNX2_PHY_FLAG_SERDES) &&
Michael Chan605a9e22007-05-03 13:23:13 -07001585 (bp->autoneg & AUTONEG_SPEED))
1586 bnx2_disable_forced_2g5(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07001587
Michael Chan583c28e2008-01-21 19:51:35 -08001588 if (bp->phy_flags & BNX2_PHY_FLAG_PARALLEL_DETECT) {
Michael Chanb2fadea2008-01-21 17:07:06 -08001589 u32 bmcr;
1590
1591 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
1592 bmcr |= BMCR_ANENABLE;
1593 bnx2_write_phy(bp, bp->mii_bmcr, bmcr);
1594
Michael Chan583c28e2008-01-21 19:51:35 -08001595 bp->phy_flags &= ~BNX2_PHY_FLAG_PARALLEL_DETECT;
Michael Chanb2fadea2008-01-21 17:07:06 -08001596 }
Michael Chanb6016b72005-05-26 13:03:09 -07001597 bp->link_up = 0;
1598 }
1599
1600 if (bp->link_up != link_up) {
1601 bnx2_report_link(bp);
1602 }
1603
1604 bnx2_set_mac_link(bp);
1605
1606 return 0;
1607}
1608
1609static int
1610bnx2_reset_phy(struct bnx2 *bp)
1611{
1612 int i;
1613 u32 reg;
1614
Michael Chanca58c3a2007-05-03 13:22:52 -07001615 bnx2_write_phy(bp, bp->mii_bmcr, BMCR_RESET);
Michael Chanb6016b72005-05-26 13:03:09 -07001616
1617#define PHY_RESET_MAX_WAIT 100
1618 for (i = 0; i < PHY_RESET_MAX_WAIT; i++) {
1619 udelay(10);
1620
Michael Chanca58c3a2007-05-03 13:22:52 -07001621 bnx2_read_phy(bp, bp->mii_bmcr, &reg);
Michael Chanb6016b72005-05-26 13:03:09 -07001622 if (!(reg & BMCR_RESET)) {
1623 udelay(20);
1624 break;
1625 }
1626 }
1627 if (i == PHY_RESET_MAX_WAIT) {
1628 return -EBUSY;
1629 }
1630 return 0;
1631}
1632
1633static u32
1634bnx2_phy_get_pause_adv(struct bnx2 *bp)
1635{
1636 u32 adv = 0;
1637
1638 if ((bp->req_flow_ctrl & (FLOW_CTRL_RX | FLOW_CTRL_TX)) ==
1639 (FLOW_CTRL_RX | FLOW_CTRL_TX)) {
1640
Michael Chan583c28e2008-01-21 19:51:35 -08001641 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Michael Chanb6016b72005-05-26 13:03:09 -07001642 adv = ADVERTISE_1000XPAUSE;
1643 }
1644 else {
1645 adv = ADVERTISE_PAUSE_CAP;
1646 }
1647 }
1648 else if (bp->req_flow_ctrl & FLOW_CTRL_TX) {
Michael Chan583c28e2008-01-21 19:51:35 -08001649 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Michael Chanb6016b72005-05-26 13:03:09 -07001650 adv = ADVERTISE_1000XPSE_ASYM;
1651 }
1652 else {
1653 adv = ADVERTISE_PAUSE_ASYM;
1654 }
1655 }
1656 else if (bp->req_flow_ctrl & FLOW_CTRL_RX) {
Michael Chan583c28e2008-01-21 19:51:35 -08001657 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Michael Chanb6016b72005-05-26 13:03:09 -07001658 adv = ADVERTISE_1000XPAUSE | ADVERTISE_1000XPSE_ASYM;
1659 }
1660 else {
1661 adv = ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM;
1662 }
1663 }
1664 return adv;
1665}
1666
Michael Chana2f13892008-07-14 22:38:23 -07001667static int bnx2_fw_sync(struct bnx2 *, u32, int, int);
Michael Chan0d8a6572007-07-07 22:49:43 -07001668
Michael Chanb6016b72005-05-26 13:03:09 -07001669static int
Michael Chan0d8a6572007-07-07 22:49:43 -07001670bnx2_setup_remote_phy(struct bnx2 *bp, u8 port)
Harvey Harrison52d07b12009-01-19 17:27:06 -08001671__releases(&bp->phy_lock)
1672__acquires(&bp->phy_lock)
Michael Chan0d8a6572007-07-07 22:49:43 -07001673{
1674 u32 speed_arg = 0, pause_adv;
1675
1676 pause_adv = bnx2_phy_get_pause_adv(bp);
1677
1678 if (bp->autoneg & AUTONEG_SPEED) {
1679 speed_arg |= BNX2_NETLINK_SET_LINK_ENABLE_AUTONEG;
1680 if (bp->advertising & ADVERTISED_10baseT_Half)
1681 speed_arg |= BNX2_NETLINK_SET_LINK_SPEED_10HALF;
1682 if (bp->advertising & ADVERTISED_10baseT_Full)
1683 speed_arg |= BNX2_NETLINK_SET_LINK_SPEED_10FULL;
1684 if (bp->advertising & ADVERTISED_100baseT_Half)
1685 speed_arg |= BNX2_NETLINK_SET_LINK_SPEED_100HALF;
1686 if (bp->advertising & ADVERTISED_100baseT_Full)
1687 speed_arg |= BNX2_NETLINK_SET_LINK_SPEED_100FULL;
1688 if (bp->advertising & ADVERTISED_1000baseT_Full)
1689 speed_arg |= BNX2_NETLINK_SET_LINK_SPEED_1GFULL;
1690 if (bp->advertising & ADVERTISED_2500baseX_Full)
1691 speed_arg |= BNX2_NETLINK_SET_LINK_SPEED_2G5FULL;
1692 } else {
1693 if (bp->req_line_speed == SPEED_2500)
1694 speed_arg = BNX2_NETLINK_SET_LINK_SPEED_2G5FULL;
1695 else if (bp->req_line_speed == SPEED_1000)
1696 speed_arg = BNX2_NETLINK_SET_LINK_SPEED_1GFULL;
1697 else if (bp->req_line_speed == SPEED_100) {
1698 if (bp->req_duplex == DUPLEX_FULL)
1699 speed_arg = BNX2_NETLINK_SET_LINK_SPEED_100FULL;
1700 else
1701 speed_arg = BNX2_NETLINK_SET_LINK_SPEED_100HALF;
1702 } else if (bp->req_line_speed == SPEED_10) {
1703 if (bp->req_duplex == DUPLEX_FULL)
1704 speed_arg = BNX2_NETLINK_SET_LINK_SPEED_10FULL;
1705 else
1706 speed_arg = BNX2_NETLINK_SET_LINK_SPEED_10HALF;
1707 }
1708 }
1709
1710 if (pause_adv & (ADVERTISE_1000XPAUSE | ADVERTISE_PAUSE_CAP))
1711 speed_arg |= BNX2_NETLINK_SET_LINK_FC_SYM_PAUSE;
Michael Chanc26736e2008-01-31 17:07:21 -08001712 if (pause_adv & (ADVERTISE_1000XPSE_ASYM | ADVERTISE_PAUSE_ASYM))
Michael Chan0d8a6572007-07-07 22:49:43 -07001713 speed_arg |= BNX2_NETLINK_SET_LINK_FC_ASYM_PAUSE;
1714
1715 if (port == PORT_TP)
1716 speed_arg |= BNX2_NETLINK_SET_LINK_PHY_APP_REMOTE |
1717 BNX2_NETLINK_SET_LINK_ETH_AT_WIRESPEED;
1718
Michael Chan2726d6e2008-01-29 21:35:05 -08001719 bnx2_shmem_wr(bp, BNX2_DRV_MB_ARG0, speed_arg);
Michael Chan0d8a6572007-07-07 22:49:43 -07001720
1721 spin_unlock_bh(&bp->phy_lock);
Michael Chana2f13892008-07-14 22:38:23 -07001722 bnx2_fw_sync(bp, BNX2_DRV_MSG_CODE_CMD_SET_LINK, 1, 0);
Michael Chan0d8a6572007-07-07 22:49:43 -07001723 spin_lock_bh(&bp->phy_lock);
1724
1725 return 0;
1726}
1727
1728static int
1729bnx2_setup_serdes_phy(struct bnx2 *bp, u8 port)
Harvey Harrison52d07b12009-01-19 17:27:06 -08001730__releases(&bp->phy_lock)
1731__acquires(&bp->phy_lock)
Michael Chanb6016b72005-05-26 13:03:09 -07001732{
Michael Chan605a9e22007-05-03 13:23:13 -07001733 u32 adv, bmcr;
Michael Chanb6016b72005-05-26 13:03:09 -07001734 u32 new_adv = 0;
1735
Michael Chan583c28e2008-01-21 19:51:35 -08001736 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
Eric Dumazet807540b2010-09-23 05:40:09 +00001737 return bnx2_setup_remote_phy(bp, port);
Michael Chan0d8a6572007-07-07 22:49:43 -07001738
Michael Chanb6016b72005-05-26 13:03:09 -07001739 if (!(bp->autoneg & AUTONEG_SPEED)) {
1740 u32 new_bmcr;
Michael Chan5b0c76a2005-11-04 08:45:49 -08001741 int force_link_down = 0;
1742
Michael Chan605a9e22007-05-03 13:23:13 -07001743 if (bp->req_line_speed == SPEED_2500) {
1744 if (!bnx2_test_and_enable_2g5(bp))
1745 force_link_down = 1;
1746 } else if (bp->req_line_speed == SPEED_1000) {
1747 if (bnx2_test_and_disable_2g5(bp))
1748 force_link_down = 1;
1749 }
Michael Chanca58c3a2007-05-03 13:22:52 -07001750 bnx2_read_phy(bp, bp->mii_adv, &adv);
Michael Chan80be4432006-11-19 14:07:28 -08001751 adv &= ~(ADVERTISE_1000XFULL | ADVERTISE_1000XHALF);
1752
Michael Chanca58c3a2007-05-03 13:22:52 -07001753 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chan605a9e22007-05-03 13:23:13 -07001754 new_bmcr = bmcr & ~BMCR_ANENABLE;
Michael Chan80be4432006-11-19 14:07:28 -08001755 new_bmcr |= BMCR_SPEED1000;
Michael Chan605a9e22007-05-03 13:23:13 -07001756
Michael Chan4ce45e02012-12-06 10:33:10 +00001757 if (BNX2_CHIP(bp) == BNX2_CHIP_5709) {
Michael Chan27a005b2007-05-03 13:23:41 -07001758 if (bp->req_line_speed == SPEED_2500)
1759 bnx2_enable_forced_2g5(bp);
1760 else if (bp->req_line_speed == SPEED_1000) {
1761 bnx2_disable_forced_2g5(bp);
1762 new_bmcr &= ~0x2000;
1763 }
1764
Michael Chan4ce45e02012-12-06 10:33:10 +00001765 } else if (BNX2_CHIP(bp) == BNX2_CHIP_5708) {
Michael Chan605a9e22007-05-03 13:23:13 -07001766 if (bp->req_line_speed == SPEED_2500)
1767 new_bmcr |= BCM5708S_BMCR_FORCE_2500;
1768 else
1769 new_bmcr = bmcr & ~BCM5708S_BMCR_FORCE_2500;
Michael Chan5b0c76a2005-11-04 08:45:49 -08001770 }
1771
Michael Chanb6016b72005-05-26 13:03:09 -07001772 if (bp->req_duplex == DUPLEX_FULL) {
Michael Chan5b0c76a2005-11-04 08:45:49 -08001773 adv |= ADVERTISE_1000XFULL;
Michael Chanb6016b72005-05-26 13:03:09 -07001774 new_bmcr |= BMCR_FULLDPLX;
1775 }
1776 else {
Michael Chan5b0c76a2005-11-04 08:45:49 -08001777 adv |= ADVERTISE_1000XHALF;
Michael Chanb6016b72005-05-26 13:03:09 -07001778 new_bmcr &= ~BMCR_FULLDPLX;
1779 }
Michael Chan5b0c76a2005-11-04 08:45:49 -08001780 if ((new_bmcr != bmcr) || (force_link_down)) {
Michael Chanb6016b72005-05-26 13:03:09 -07001781 /* Force a link down visible on the other side */
1782 if (bp->link_up) {
Michael Chanca58c3a2007-05-03 13:22:52 -07001783 bnx2_write_phy(bp, bp->mii_adv, adv &
Michael Chan5b0c76a2005-11-04 08:45:49 -08001784 ~(ADVERTISE_1000XFULL |
1785 ADVERTISE_1000XHALF));
Michael Chanca58c3a2007-05-03 13:22:52 -07001786 bnx2_write_phy(bp, bp->mii_bmcr, bmcr |
Michael Chanb6016b72005-05-26 13:03:09 -07001787 BMCR_ANRESTART | BMCR_ANENABLE);
1788
1789 bp->link_up = 0;
1790 netif_carrier_off(bp->dev);
Michael Chanca58c3a2007-05-03 13:22:52 -07001791 bnx2_write_phy(bp, bp->mii_bmcr, new_bmcr);
Michael Chan80be4432006-11-19 14:07:28 -08001792 bnx2_report_link(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07001793 }
Michael Chanca58c3a2007-05-03 13:22:52 -07001794 bnx2_write_phy(bp, bp->mii_adv, adv);
1795 bnx2_write_phy(bp, bp->mii_bmcr, new_bmcr);
Michael Chan605a9e22007-05-03 13:23:13 -07001796 } else {
1797 bnx2_resolve_flow_ctrl(bp);
1798 bnx2_set_mac_link(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07001799 }
1800 return 0;
1801 }
1802
Michael Chan605a9e22007-05-03 13:23:13 -07001803 bnx2_test_and_enable_2g5(bp);
Michael Chan5b0c76a2005-11-04 08:45:49 -08001804
Michael Chanb6016b72005-05-26 13:03:09 -07001805 if (bp->advertising & ADVERTISED_1000baseT_Full)
1806 new_adv |= ADVERTISE_1000XFULL;
1807
1808 new_adv |= bnx2_phy_get_pause_adv(bp);
1809
Michael Chanca58c3a2007-05-03 13:22:52 -07001810 bnx2_read_phy(bp, bp->mii_adv, &adv);
1811 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chanb6016b72005-05-26 13:03:09 -07001812
1813 bp->serdes_an_pending = 0;
1814 if ((adv != new_adv) || ((bmcr & BMCR_ANENABLE) == 0)) {
1815 /* Force a link down visible on the other side */
1816 if (bp->link_up) {
Michael Chanca58c3a2007-05-03 13:22:52 -07001817 bnx2_write_phy(bp, bp->mii_bmcr, BMCR_LOOPBACK);
Michael Chan80be4432006-11-19 14:07:28 -08001818 spin_unlock_bh(&bp->phy_lock);
1819 msleep(20);
1820 spin_lock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07001821 }
1822
Michael Chanca58c3a2007-05-03 13:22:52 -07001823 bnx2_write_phy(bp, bp->mii_adv, new_adv);
1824 bnx2_write_phy(bp, bp->mii_bmcr, bmcr | BMCR_ANRESTART |
Michael Chanb6016b72005-05-26 13:03:09 -07001825 BMCR_ANENABLE);
Michael Chanf8dd0642006-11-19 14:08:29 -08001826 /* Speed up link-up time when the link partner
1827 * does not autonegotiate which is very common
1828 * in blade servers. Some blade servers use
1829 * IPMI for kerboard input and it's important
1830 * to minimize link disruptions. Autoneg. involves
1831 * exchanging base pages plus 3 next pages and
1832 * normally completes in about 120 msec.
1833 */
Michael Chan40105c02008-11-12 16:02:45 -08001834 bp->current_interval = BNX2_SERDES_AN_TIMEOUT;
Michael Chanf8dd0642006-11-19 14:08:29 -08001835 bp->serdes_an_pending = 1;
1836 mod_timer(&bp->timer, jiffies + bp->current_interval);
Michael Chan605a9e22007-05-03 13:23:13 -07001837 } else {
1838 bnx2_resolve_flow_ctrl(bp);
1839 bnx2_set_mac_link(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07001840 }
1841
1842 return 0;
1843}
1844
1845#define ETHTOOL_ALL_FIBRE_SPEED \
Michael Chan583c28e2008-01-21 19:51:35 -08001846 (bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE) ? \
Michael Chandeaf3912007-07-07 22:48:00 -07001847 (ADVERTISED_2500baseX_Full | ADVERTISED_1000baseT_Full) :\
1848 (ADVERTISED_1000baseT_Full)
Michael Chanb6016b72005-05-26 13:03:09 -07001849
1850#define ETHTOOL_ALL_COPPER_SPEED \
1851 (ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full | \
1852 ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full | \
1853 ADVERTISED_1000baseT_Full)
1854
1855#define PHY_ALL_10_100_SPEED (ADVERTISE_10HALF | ADVERTISE_10FULL | \
1856 ADVERTISE_100HALF | ADVERTISE_100FULL | ADVERTISE_CSMA)
Jeff Garzik6aa20a22006-09-13 13:24:59 -04001857
Michael Chanb6016b72005-05-26 13:03:09 -07001858#define PHY_ALL_1000_SPEED (ADVERTISE_1000HALF | ADVERTISE_1000FULL)
1859
Michael Chandeaf3912007-07-07 22:48:00 -07001860static void
Michael Chan0d8a6572007-07-07 22:49:43 -07001861bnx2_set_default_remote_link(struct bnx2 *bp)
1862{
1863 u32 link;
1864
1865 if (bp->phy_port == PORT_TP)
Michael Chan2726d6e2008-01-29 21:35:05 -08001866 link = bnx2_shmem_rd(bp, BNX2_RPHY_COPPER_LINK);
Michael Chan0d8a6572007-07-07 22:49:43 -07001867 else
Michael Chan2726d6e2008-01-29 21:35:05 -08001868 link = bnx2_shmem_rd(bp, BNX2_RPHY_SERDES_LINK);
Michael Chan0d8a6572007-07-07 22:49:43 -07001869
1870 if (link & BNX2_NETLINK_SET_LINK_ENABLE_AUTONEG) {
1871 bp->req_line_speed = 0;
1872 bp->autoneg |= AUTONEG_SPEED;
1873 bp->advertising = ADVERTISED_Autoneg;
1874 if (link & BNX2_NETLINK_SET_LINK_SPEED_10HALF)
1875 bp->advertising |= ADVERTISED_10baseT_Half;
1876 if (link & BNX2_NETLINK_SET_LINK_SPEED_10FULL)
1877 bp->advertising |= ADVERTISED_10baseT_Full;
1878 if (link & BNX2_NETLINK_SET_LINK_SPEED_100HALF)
1879 bp->advertising |= ADVERTISED_100baseT_Half;
1880 if (link & BNX2_NETLINK_SET_LINK_SPEED_100FULL)
1881 bp->advertising |= ADVERTISED_100baseT_Full;
1882 if (link & BNX2_NETLINK_SET_LINK_SPEED_1GFULL)
1883 bp->advertising |= ADVERTISED_1000baseT_Full;
1884 if (link & BNX2_NETLINK_SET_LINK_SPEED_2G5FULL)
1885 bp->advertising |= ADVERTISED_2500baseX_Full;
1886 } else {
1887 bp->autoneg = 0;
1888 bp->advertising = 0;
1889 bp->req_duplex = DUPLEX_FULL;
1890 if (link & BNX2_NETLINK_SET_LINK_SPEED_10) {
1891 bp->req_line_speed = SPEED_10;
1892 if (link & BNX2_NETLINK_SET_LINK_SPEED_10HALF)
1893 bp->req_duplex = DUPLEX_HALF;
1894 }
1895 if (link & BNX2_NETLINK_SET_LINK_SPEED_100) {
1896 bp->req_line_speed = SPEED_100;
1897 if (link & BNX2_NETLINK_SET_LINK_SPEED_100HALF)
1898 bp->req_duplex = DUPLEX_HALF;
1899 }
1900 if (link & BNX2_NETLINK_SET_LINK_SPEED_1GFULL)
1901 bp->req_line_speed = SPEED_1000;
1902 if (link & BNX2_NETLINK_SET_LINK_SPEED_2G5FULL)
1903 bp->req_line_speed = SPEED_2500;
1904 }
1905}
1906
1907static void
Michael Chandeaf3912007-07-07 22:48:00 -07001908bnx2_set_default_link(struct bnx2 *bp)
1909{
Harvey Harrisonab598592008-05-01 02:47:38 -07001910 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP) {
1911 bnx2_set_default_remote_link(bp);
1912 return;
1913 }
Michael Chan0d8a6572007-07-07 22:49:43 -07001914
Michael Chandeaf3912007-07-07 22:48:00 -07001915 bp->autoneg = AUTONEG_SPEED | AUTONEG_FLOW_CTRL;
1916 bp->req_line_speed = 0;
Michael Chan583c28e2008-01-21 19:51:35 -08001917 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Michael Chandeaf3912007-07-07 22:48:00 -07001918 u32 reg;
1919
1920 bp->advertising = ETHTOOL_ALL_FIBRE_SPEED | ADVERTISED_Autoneg;
1921
Michael Chan2726d6e2008-01-29 21:35:05 -08001922 reg = bnx2_shmem_rd(bp, BNX2_PORT_HW_CFG_CONFIG);
Michael Chandeaf3912007-07-07 22:48:00 -07001923 reg &= BNX2_PORT_HW_CFG_CFG_DFLT_LINK_MASK;
1924 if (reg == BNX2_PORT_HW_CFG_CFG_DFLT_LINK_1G) {
1925 bp->autoneg = 0;
1926 bp->req_line_speed = bp->line_speed = SPEED_1000;
1927 bp->req_duplex = DUPLEX_FULL;
1928 }
1929 } else
1930 bp->advertising = ETHTOOL_ALL_COPPER_SPEED | ADVERTISED_Autoneg;
1931}
1932
Michael Chan0d8a6572007-07-07 22:49:43 -07001933static void
Michael Chandf149d72007-07-07 22:51:36 -07001934bnx2_send_heart_beat(struct bnx2 *bp)
1935{
1936 u32 msg;
1937 u32 addr;
1938
1939 spin_lock(&bp->indirect_lock);
1940 msg = (u32) (++bp->fw_drv_pulse_wr_seq & BNX2_DRV_PULSE_SEQ_MASK);
1941 addr = bp->shmem_base + BNX2_DRV_PULSE_MB;
Michael Chane503e062012-12-06 10:33:08 +00001942 BNX2_WR(bp, BNX2_PCICFG_REG_WINDOW_ADDRESS, addr);
1943 BNX2_WR(bp, BNX2_PCICFG_REG_WINDOW, msg);
Michael Chandf149d72007-07-07 22:51:36 -07001944 spin_unlock(&bp->indirect_lock);
1945}
1946
1947static void
Michael Chan0d8a6572007-07-07 22:49:43 -07001948bnx2_remote_phy_event(struct bnx2 *bp)
1949{
1950 u32 msg;
1951 u8 link_up = bp->link_up;
1952 u8 old_port;
1953
Michael Chan2726d6e2008-01-29 21:35:05 -08001954 msg = bnx2_shmem_rd(bp, BNX2_LINK_STATUS);
Michael Chan0d8a6572007-07-07 22:49:43 -07001955
Michael Chandf149d72007-07-07 22:51:36 -07001956 if (msg & BNX2_LINK_STATUS_HEART_BEAT_EXPIRED)
1957 bnx2_send_heart_beat(bp);
1958
1959 msg &= ~BNX2_LINK_STATUS_HEART_BEAT_EXPIRED;
1960
Michael Chan0d8a6572007-07-07 22:49:43 -07001961 if ((msg & BNX2_LINK_STATUS_LINK_UP) == BNX2_LINK_STATUS_LINK_DOWN)
1962 bp->link_up = 0;
1963 else {
1964 u32 speed;
1965
1966 bp->link_up = 1;
1967 speed = msg & BNX2_LINK_STATUS_SPEED_MASK;
1968 bp->duplex = DUPLEX_FULL;
1969 switch (speed) {
1970 case BNX2_LINK_STATUS_10HALF:
1971 bp->duplex = DUPLEX_HALF;
Michael Chan7947c9c2012-06-27 15:08:23 +00001972 /* fall through */
Michael Chan0d8a6572007-07-07 22:49:43 -07001973 case BNX2_LINK_STATUS_10FULL:
1974 bp->line_speed = SPEED_10;
1975 break;
1976 case BNX2_LINK_STATUS_100HALF:
1977 bp->duplex = DUPLEX_HALF;
Michael Chan7947c9c2012-06-27 15:08:23 +00001978 /* fall through */
Michael Chan0d8a6572007-07-07 22:49:43 -07001979 case BNX2_LINK_STATUS_100BASE_T4:
1980 case BNX2_LINK_STATUS_100FULL:
1981 bp->line_speed = SPEED_100;
1982 break;
1983 case BNX2_LINK_STATUS_1000HALF:
1984 bp->duplex = DUPLEX_HALF;
Michael Chan7947c9c2012-06-27 15:08:23 +00001985 /* fall through */
Michael Chan0d8a6572007-07-07 22:49:43 -07001986 case BNX2_LINK_STATUS_1000FULL:
1987 bp->line_speed = SPEED_1000;
1988 break;
1989 case BNX2_LINK_STATUS_2500HALF:
1990 bp->duplex = DUPLEX_HALF;
Michael Chan7947c9c2012-06-27 15:08:23 +00001991 /* fall through */
Michael Chan0d8a6572007-07-07 22:49:43 -07001992 case BNX2_LINK_STATUS_2500FULL:
1993 bp->line_speed = SPEED_2500;
1994 break;
1995 default:
1996 bp->line_speed = 0;
1997 break;
1998 }
1999
Michael Chan0d8a6572007-07-07 22:49:43 -07002000 bp->flow_ctrl = 0;
2001 if ((bp->autoneg & (AUTONEG_SPEED | AUTONEG_FLOW_CTRL)) !=
2002 (AUTONEG_SPEED | AUTONEG_FLOW_CTRL)) {
2003 if (bp->duplex == DUPLEX_FULL)
2004 bp->flow_ctrl = bp->req_flow_ctrl;
2005 } else {
2006 if (msg & BNX2_LINK_STATUS_TX_FC_ENABLED)
2007 bp->flow_ctrl |= FLOW_CTRL_TX;
2008 if (msg & BNX2_LINK_STATUS_RX_FC_ENABLED)
2009 bp->flow_ctrl |= FLOW_CTRL_RX;
2010 }
2011
2012 old_port = bp->phy_port;
2013 if (msg & BNX2_LINK_STATUS_SERDES_LINK)
2014 bp->phy_port = PORT_FIBRE;
2015 else
2016 bp->phy_port = PORT_TP;
2017
2018 if (old_port != bp->phy_port)
2019 bnx2_set_default_link(bp);
2020
Michael Chan0d8a6572007-07-07 22:49:43 -07002021 }
2022 if (bp->link_up != link_up)
2023 bnx2_report_link(bp);
2024
2025 bnx2_set_mac_link(bp);
2026}
2027
2028static int
2029bnx2_set_remote_link(struct bnx2 *bp)
2030{
2031 u32 evt_code;
2032
Michael Chan2726d6e2008-01-29 21:35:05 -08002033 evt_code = bnx2_shmem_rd(bp, BNX2_FW_EVT_CODE_MB);
Michael Chan0d8a6572007-07-07 22:49:43 -07002034 switch (evt_code) {
2035 case BNX2_FW_EVT_CODE_LINK_EVENT:
2036 bnx2_remote_phy_event(bp);
2037 break;
2038 case BNX2_FW_EVT_CODE_SW_TIMER_EXPIRATION_EVENT:
2039 default:
Michael Chandf149d72007-07-07 22:51:36 -07002040 bnx2_send_heart_beat(bp);
Michael Chan0d8a6572007-07-07 22:49:43 -07002041 break;
2042 }
2043 return 0;
2044}
2045
Michael Chanb6016b72005-05-26 13:03:09 -07002046static int
2047bnx2_setup_copper_phy(struct bnx2 *bp)
Harvey Harrison52d07b12009-01-19 17:27:06 -08002048__releases(&bp->phy_lock)
2049__acquires(&bp->phy_lock)
Michael Chanb6016b72005-05-26 13:03:09 -07002050{
Michael Chand17e53b2013-12-31 23:22:32 -08002051 u32 bmcr, adv_reg, new_adv = 0;
Michael Chanb6016b72005-05-26 13:03:09 -07002052 u32 new_bmcr;
2053
Michael Chanca58c3a2007-05-03 13:22:52 -07002054 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chanb6016b72005-05-26 13:03:09 -07002055
Michael Chand17e53b2013-12-31 23:22:32 -08002056 bnx2_read_phy(bp, bp->mii_adv, &adv_reg);
2057 adv_reg &= (PHY_ALL_10_100_SPEED | ADVERTISE_PAUSE_CAP |
2058 ADVERTISE_PAUSE_ASYM);
2059
2060 new_adv = ADVERTISE_CSMA | ethtool_adv_to_mii_adv_t(bp->advertising);
2061
Michael Chanb6016b72005-05-26 13:03:09 -07002062 if (bp->autoneg & AUTONEG_SPEED) {
Michael Chand17e53b2013-12-31 23:22:32 -08002063 u32 adv1000_reg;
Matt Carlson37f07022011-11-17 14:30:55 +00002064 u32 new_adv1000 = 0;
Michael Chanb6016b72005-05-26 13:03:09 -07002065
Michael Chand17e53b2013-12-31 23:22:32 -08002066 new_adv |= bnx2_phy_get_pause_adv(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07002067
2068 bnx2_read_phy(bp, MII_CTRL1000, &adv1000_reg);
2069 adv1000_reg &= PHY_ALL_1000_SPEED;
2070
Matt Carlson37f07022011-11-17 14:30:55 +00002071 new_adv1000 |= ethtool_adv_to_mii_ctrl1000_t(bp->advertising);
Matt Carlson37f07022011-11-17 14:30:55 +00002072 if ((adv1000_reg != new_adv1000) ||
2073 (adv_reg != new_adv) ||
Michael Chanb6016b72005-05-26 13:03:09 -07002074 ((bmcr & BMCR_ANENABLE) == 0)) {
2075
Matt Carlson37f07022011-11-17 14:30:55 +00002076 bnx2_write_phy(bp, bp->mii_adv, new_adv);
2077 bnx2_write_phy(bp, MII_CTRL1000, new_adv1000);
Michael Chanca58c3a2007-05-03 13:22:52 -07002078 bnx2_write_phy(bp, bp->mii_bmcr, BMCR_ANRESTART |
Michael Chanb6016b72005-05-26 13:03:09 -07002079 BMCR_ANENABLE);
2080 }
2081 else if (bp->link_up) {
2082 /* Flow ctrl may have changed from auto to forced */
2083 /* or vice-versa. */
2084
2085 bnx2_resolve_flow_ctrl(bp);
2086 bnx2_set_mac_link(bp);
2087 }
2088 return 0;
2089 }
2090
Michael Chand17e53b2013-12-31 23:22:32 -08002091 /* advertise nothing when forcing speed */
2092 if (adv_reg != new_adv)
2093 bnx2_write_phy(bp, bp->mii_adv, new_adv);
2094
Michael Chanb6016b72005-05-26 13:03:09 -07002095 new_bmcr = 0;
2096 if (bp->req_line_speed == SPEED_100) {
2097 new_bmcr |= BMCR_SPEED100;
2098 }
2099 if (bp->req_duplex == DUPLEX_FULL) {
2100 new_bmcr |= BMCR_FULLDPLX;
2101 }
2102 if (new_bmcr != bmcr) {
2103 u32 bmsr;
Michael Chanb6016b72005-05-26 13:03:09 -07002104
Michael Chanca58c3a2007-05-03 13:22:52 -07002105 bnx2_read_phy(bp, bp->mii_bmsr, &bmsr);
2106 bnx2_read_phy(bp, bp->mii_bmsr, &bmsr);
Jeff Garzik6aa20a22006-09-13 13:24:59 -04002107
Michael Chanb6016b72005-05-26 13:03:09 -07002108 if (bmsr & BMSR_LSTATUS) {
2109 /* Force link down */
Michael Chanca58c3a2007-05-03 13:22:52 -07002110 bnx2_write_phy(bp, bp->mii_bmcr, BMCR_LOOPBACK);
Michael Chana16dda02006-11-19 14:08:56 -08002111 spin_unlock_bh(&bp->phy_lock);
2112 msleep(50);
2113 spin_lock_bh(&bp->phy_lock);
2114
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);
Michael Chanb6016b72005-05-26 13:03:09 -07002117 }
2118
Michael Chanca58c3a2007-05-03 13:22:52 -07002119 bnx2_write_phy(bp, bp->mii_bmcr, new_bmcr);
Michael Chanb6016b72005-05-26 13:03:09 -07002120
2121 /* Normally, the new speed is setup after the link has
2122 * gone down and up again. In some cases, link will not go
2123 * down so we need to set up the new speed here.
2124 */
2125 if (bmsr & BMSR_LSTATUS) {
2126 bp->line_speed = bp->req_line_speed;
2127 bp->duplex = bp->req_duplex;
2128 bnx2_resolve_flow_ctrl(bp);
2129 bnx2_set_mac_link(bp);
2130 }
Michael Chan27a005b2007-05-03 13:23:41 -07002131 } else {
2132 bnx2_resolve_flow_ctrl(bp);
2133 bnx2_set_mac_link(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07002134 }
2135 return 0;
2136}
2137
2138static int
Michael Chan0d8a6572007-07-07 22:49:43 -07002139bnx2_setup_phy(struct bnx2 *bp, u8 port)
Harvey Harrison52d07b12009-01-19 17:27:06 -08002140__releases(&bp->phy_lock)
2141__acquires(&bp->phy_lock)
Michael Chanb6016b72005-05-26 13:03:09 -07002142{
2143 if (bp->loopback == MAC_LOOPBACK)
2144 return 0;
2145
Michael Chan583c28e2008-01-21 19:51:35 -08002146 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Eric Dumazet807540b2010-09-23 05:40:09 +00002147 return bnx2_setup_serdes_phy(bp, port);
Michael Chanb6016b72005-05-26 13:03:09 -07002148 }
2149 else {
Eric Dumazet807540b2010-09-23 05:40:09 +00002150 return bnx2_setup_copper_phy(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07002151 }
2152}
2153
2154static int
Michael Chan9a120bc2008-05-16 22:17:45 -07002155bnx2_init_5709s_phy(struct bnx2 *bp, int reset_phy)
Michael Chan27a005b2007-05-03 13:23:41 -07002156{
2157 u32 val;
2158
2159 bp->mii_bmcr = MII_BMCR + 0x10;
2160 bp->mii_bmsr = MII_BMSR + 0x10;
2161 bp->mii_bmsr1 = MII_BNX2_GP_TOP_AN_STATUS1;
2162 bp->mii_adv = MII_ADVERTISE + 0x10;
2163 bp->mii_lpa = MII_LPA + 0x10;
2164 bp->mii_up1 = MII_BNX2_OVER1G_UP1;
2165
2166 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_AER);
2167 bnx2_write_phy(bp, MII_BNX2_AER_AER, MII_BNX2_AER_AER_AN_MMD);
2168
2169 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
Michael Chan9a120bc2008-05-16 22:17:45 -07002170 if (reset_phy)
2171 bnx2_reset_phy(bp);
Michael Chan27a005b2007-05-03 13:23:41 -07002172
2173 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_SERDES_DIG);
2174
2175 bnx2_read_phy(bp, MII_BNX2_SERDES_DIG_1000XCTL1, &val);
2176 val &= ~MII_BNX2_SD_1000XCTL1_AUTODET;
2177 val |= MII_BNX2_SD_1000XCTL1_FIBER;
2178 bnx2_write_phy(bp, MII_BNX2_SERDES_DIG_1000XCTL1, val);
2179
2180 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_OVER1G);
2181 bnx2_read_phy(bp, MII_BNX2_OVER1G_UP1, &val);
Michael Chan583c28e2008-01-21 19:51:35 -08002182 if (bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE)
Michael Chan27a005b2007-05-03 13:23:41 -07002183 val |= BCM5708S_UP1_2G5;
2184 else
2185 val &= ~BCM5708S_UP1_2G5;
2186 bnx2_write_phy(bp, MII_BNX2_OVER1G_UP1, val);
2187
2188 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_BAM_NXTPG);
2189 bnx2_read_phy(bp, MII_BNX2_BAM_NXTPG_CTL, &val);
2190 val |= MII_BNX2_NXTPG_CTL_T2 | MII_BNX2_NXTPG_CTL_BAM;
2191 bnx2_write_phy(bp, MII_BNX2_BAM_NXTPG_CTL, val);
2192
2193 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_CL73_USERB0);
2194
2195 val = MII_BNX2_CL73_BAM_EN | MII_BNX2_CL73_BAM_STA_MGR_EN |
2196 MII_BNX2_CL73_BAM_NP_AFT_BP_EN;
2197 bnx2_write_phy(bp, MII_BNX2_CL73_BAM_CTL1, val);
2198
2199 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
2200
2201 return 0;
2202}
2203
2204static int
Michael Chan9a120bc2008-05-16 22:17:45 -07002205bnx2_init_5708s_phy(struct bnx2 *bp, int reset_phy)
Michael Chan5b0c76a2005-11-04 08:45:49 -08002206{
2207 u32 val;
2208
Michael Chan9a120bc2008-05-16 22:17:45 -07002209 if (reset_phy)
2210 bnx2_reset_phy(bp);
Michael Chan27a005b2007-05-03 13:23:41 -07002211
2212 bp->mii_up1 = BCM5708S_UP1;
2213
Michael Chan5b0c76a2005-11-04 08:45:49 -08002214 bnx2_write_phy(bp, BCM5708S_BLK_ADDR, BCM5708S_BLK_ADDR_DIG3);
2215 bnx2_write_phy(bp, BCM5708S_DIG_3_0, BCM5708S_DIG_3_0_USE_IEEE);
2216 bnx2_write_phy(bp, BCM5708S_BLK_ADDR, BCM5708S_BLK_ADDR_DIG);
2217
2218 bnx2_read_phy(bp, BCM5708S_1000X_CTL1, &val);
2219 val |= BCM5708S_1000X_CTL1_FIBER_MODE | BCM5708S_1000X_CTL1_AUTODET_EN;
2220 bnx2_write_phy(bp, BCM5708S_1000X_CTL1, val);
2221
2222 bnx2_read_phy(bp, BCM5708S_1000X_CTL2, &val);
2223 val |= BCM5708S_1000X_CTL2_PLLEL_DET_EN;
2224 bnx2_write_phy(bp, BCM5708S_1000X_CTL2, val);
2225
Michael Chan583c28e2008-01-21 19:51:35 -08002226 if (bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE) {
Michael Chan5b0c76a2005-11-04 08:45:49 -08002227 bnx2_read_phy(bp, BCM5708S_UP1, &val);
2228 val |= BCM5708S_UP1_2G5;
2229 bnx2_write_phy(bp, BCM5708S_UP1, val);
2230 }
2231
Michael Chan4ce45e02012-12-06 10:33:10 +00002232 if ((BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5708_A0) ||
2233 (BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5708_B0) ||
2234 (BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5708_B1)) {
Michael Chan5b0c76a2005-11-04 08:45:49 -08002235 /* increase tx signal amplitude */
2236 bnx2_write_phy(bp, BCM5708S_BLK_ADDR,
2237 BCM5708S_BLK_ADDR_TX_MISC);
2238 bnx2_read_phy(bp, BCM5708S_TX_ACTL1, &val);
2239 val &= ~BCM5708S_TX_ACTL1_DRIVER_VCM;
2240 bnx2_write_phy(bp, BCM5708S_TX_ACTL1, val);
2241 bnx2_write_phy(bp, BCM5708S_BLK_ADDR, BCM5708S_BLK_ADDR_DIG);
2242 }
2243
Michael Chan2726d6e2008-01-29 21:35:05 -08002244 val = bnx2_shmem_rd(bp, BNX2_PORT_HW_CFG_CONFIG) &
Michael Chan5b0c76a2005-11-04 08:45:49 -08002245 BNX2_PORT_HW_CFG_CFG_TXCTL3_MASK;
2246
2247 if (val) {
2248 u32 is_backplane;
2249
Michael Chan2726d6e2008-01-29 21:35:05 -08002250 is_backplane = bnx2_shmem_rd(bp, BNX2_SHARED_HW_CFG_CONFIG);
Michael Chan5b0c76a2005-11-04 08:45:49 -08002251 if (is_backplane & BNX2_SHARED_HW_CFG_PHY_BACKPLANE) {
2252 bnx2_write_phy(bp, BCM5708S_BLK_ADDR,
2253 BCM5708S_BLK_ADDR_TX_MISC);
2254 bnx2_write_phy(bp, BCM5708S_TX_ACTL3, val);
2255 bnx2_write_phy(bp, BCM5708S_BLK_ADDR,
2256 BCM5708S_BLK_ADDR_DIG);
2257 }
2258 }
2259 return 0;
2260}
2261
2262static int
Michael Chan9a120bc2008-05-16 22:17:45 -07002263bnx2_init_5706s_phy(struct bnx2 *bp, int reset_phy)
Michael Chanb6016b72005-05-26 13:03:09 -07002264{
Michael Chan9a120bc2008-05-16 22:17:45 -07002265 if (reset_phy)
2266 bnx2_reset_phy(bp);
Michael Chan27a005b2007-05-03 13:23:41 -07002267
Michael Chan583c28e2008-01-21 19:51:35 -08002268 bp->phy_flags &= ~BNX2_PHY_FLAG_PARALLEL_DETECT;
Michael Chanb6016b72005-05-26 13:03:09 -07002269
Michael Chan4ce45e02012-12-06 10:33:10 +00002270 if (BNX2_CHIP(bp) == BNX2_CHIP_5706)
Michael Chane503e062012-12-06 10:33:08 +00002271 BNX2_WR(bp, BNX2_MISC_GP_HW_CTL0, 0x300);
Michael Chanb6016b72005-05-26 13:03:09 -07002272
2273 if (bp->dev->mtu > 1500) {
2274 u32 val;
2275
2276 /* Set extended packet length bit */
2277 bnx2_write_phy(bp, 0x18, 0x7);
2278 bnx2_read_phy(bp, 0x18, &val);
2279 bnx2_write_phy(bp, 0x18, (val & 0xfff8) | 0x4000);
2280
2281 bnx2_write_phy(bp, 0x1c, 0x6c00);
2282 bnx2_read_phy(bp, 0x1c, &val);
2283 bnx2_write_phy(bp, 0x1c, (val & 0x3ff) | 0xec02);
2284 }
2285 else {
2286 u32 val;
2287
2288 bnx2_write_phy(bp, 0x18, 0x7);
2289 bnx2_read_phy(bp, 0x18, &val);
2290 bnx2_write_phy(bp, 0x18, val & ~0x4007);
2291
2292 bnx2_write_phy(bp, 0x1c, 0x6c00);
2293 bnx2_read_phy(bp, 0x1c, &val);
2294 bnx2_write_phy(bp, 0x1c, (val & 0x3fd) | 0xec00);
2295 }
2296
2297 return 0;
2298}
2299
2300static int
Michael Chan9a120bc2008-05-16 22:17:45 -07002301bnx2_init_copper_phy(struct bnx2 *bp, int reset_phy)
Michael Chanb6016b72005-05-26 13:03:09 -07002302{
Michael Chan5b0c76a2005-11-04 08:45:49 -08002303 u32 val;
2304
Michael Chan9a120bc2008-05-16 22:17:45 -07002305 if (reset_phy)
2306 bnx2_reset_phy(bp);
Michael Chan27a005b2007-05-03 13:23:41 -07002307
Michael Chan583c28e2008-01-21 19:51:35 -08002308 if (bp->phy_flags & BNX2_PHY_FLAG_CRC_FIX) {
Michael Chanb6016b72005-05-26 13:03:09 -07002309 bnx2_write_phy(bp, 0x18, 0x0c00);
2310 bnx2_write_phy(bp, 0x17, 0x000a);
2311 bnx2_write_phy(bp, 0x15, 0x310b);
2312 bnx2_write_phy(bp, 0x17, 0x201f);
2313 bnx2_write_phy(bp, 0x15, 0x9506);
2314 bnx2_write_phy(bp, 0x17, 0x401f);
2315 bnx2_write_phy(bp, 0x15, 0x14e2);
2316 bnx2_write_phy(bp, 0x18, 0x0400);
2317 }
2318
Michael Chan583c28e2008-01-21 19:51:35 -08002319 if (bp->phy_flags & BNX2_PHY_FLAG_DIS_EARLY_DAC) {
Michael Chanb659f442007-02-02 00:46:35 -08002320 bnx2_write_phy(bp, MII_BNX2_DSP_ADDRESS,
2321 MII_BNX2_DSP_EXPAND_REG | 0x8);
2322 bnx2_read_phy(bp, MII_BNX2_DSP_RW_PORT, &val);
2323 val &= ~(1 << 8);
2324 bnx2_write_phy(bp, MII_BNX2_DSP_RW_PORT, val);
2325 }
2326
Michael Chanb6016b72005-05-26 13:03:09 -07002327 if (bp->dev->mtu > 1500) {
Michael Chanb6016b72005-05-26 13:03:09 -07002328 /* Set extended packet length bit */
2329 bnx2_write_phy(bp, 0x18, 0x7);
2330 bnx2_read_phy(bp, 0x18, &val);
2331 bnx2_write_phy(bp, 0x18, val | 0x4000);
2332
2333 bnx2_read_phy(bp, 0x10, &val);
2334 bnx2_write_phy(bp, 0x10, val | 0x1);
2335 }
2336 else {
Michael Chanb6016b72005-05-26 13:03:09 -07002337 bnx2_write_phy(bp, 0x18, 0x7);
2338 bnx2_read_phy(bp, 0x18, &val);
2339 bnx2_write_phy(bp, 0x18, val & ~0x4007);
2340
2341 bnx2_read_phy(bp, 0x10, &val);
2342 bnx2_write_phy(bp, 0x10, val & ~0x1);
2343 }
2344
Michael Chan5b0c76a2005-11-04 08:45:49 -08002345 /* ethernet@wirespeed */
Michael Chan41033b62013-12-31 23:22:33 -08002346 bnx2_write_phy(bp, MII_BNX2_AUX_CTL, AUX_CTL_MISC_CTL);
2347 bnx2_read_phy(bp, MII_BNX2_AUX_CTL, &val);
2348 val |= AUX_CTL_MISC_CTL_WR | AUX_CTL_MISC_CTL_WIRESPEED;
2349
2350 /* auto-mdix */
2351 if (BNX2_CHIP(bp) == BNX2_CHIP_5709)
2352 val |= AUX_CTL_MISC_CTL_AUTOMDIX;
2353
2354 bnx2_write_phy(bp, MII_BNX2_AUX_CTL, val);
Michael Chanb6016b72005-05-26 13:03:09 -07002355 return 0;
2356}
2357
2358
2359static int
Michael Chan9a120bc2008-05-16 22:17:45 -07002360bnx2_init_phy(struct bnx2 *bp, int reset_phy)
Harvey Harrison52d07b12009-01-19 17:27:06 -08002361__releases(&bp->phy_lock)
2362__acquires(&bp->phy_lock)
Michael Chanb6016b72005-05-26 13:03:09 -07002363{
2364 u32 val;
2365 int rc = 0;
2366
Michael Chan583c28e2008-01-21 19:51:35 -08002367 bp->phy_flags &= ~BNX2_PHY_FLAG_INT_MODE_MASK;
2368 bp->phy_flags |= BNX2_PHY_FLAG_INT_MODE_LINK_READY;
Michael Chanb6016b72005-05-26 13:03:09 -07002369
Michael Chanca58c3a2007-05-03 13:22:52 -07002370 bp->mii_bmcr = MII_BMCR;
2371 bp->mii_bmsr = MII_BMSR;
Michael Chan27a005b2007-05-03 13:23:41 -07002372 bp->mii_bmsr1 = MII_BMSR;
Michael Chanca58c3a2007-05-03 13:22:52 -07002373 bp->mii_adv = MII_ADVERTISE;
2374 bp->mii_lpa = MII_LPA;
2375
Michael Chane503e062012-12-06 10:33:08 +00002376 BNX2_WR(bp, BNX2_EMAC_ATTENTION_ENA, BNX2_EMAC_ATTENTION_ENA_LINK);
Michael Chanb6016b72005-05-26 13:03:09 -07002377
Michael Chan583c28e2008-01-21 19:51:35 -08002378 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
Michael Chan0d8a6572007-07-07 22:49:43 -07002379 goto setup_phy;
2380
Michael Chanb6016b72005-05-26 13:03:09 -07002381 bnx2_read_phy(bp, MII_PHYSID1, &val);
2382 bp->phy_id = val << 16;
2383 bnx2_read_phy(bp, MII_PHYSID2, &val);
2384 bp->phy_id |= val & 0xffff;
2385
Michael Chan583c28e2008-01-21 19:51:35 -08002386 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Michael Chan4ce45e02012-12-06 10:33:10 +00002387 if (BNX2_CHIP(bp) == BNX2_CHIP_5706)
Michael Chan9a120bc2008-05-16 22:17:45 -07002388 rc = bnx2_init_5706s_phy(bp, reset_phy);
Michael Chan4ce45e02012-12-06 10:33:10 +00002389 else if (BNX2_CHIP(bp) == BNX2_CHIP_5708)
Michael Chan9a120bc2008-05-16 22:17:45 -07002390 rc = bnx2_init_5708s_phy(bp, reset_phy);
Michael Chan4ce45e02012-12-06 10:33:10 +00002391 else if (BNX2_CHIP(bp) == BNX2_CHIP_5709)
Michael Chan9a120bc2008-05-16 22:17:45 -07002392 rc = bnx2_init_5709s_phy(bp, reset_phy);
Michael Chanb6016b72005-05-26 13:03:09 -07002393 }
2394 else {
Michael Chan9a120bc2008-05-16 22:17:45 -07002395 rc = bnx2_init_copper_phy(bp, reset_phy);
Michael Chanb6016b72005-05-26 13:03:09 -07002396 }
2397
Michael Chan0d8a6572007-07-07 22:49:43 -07002398setup_phy:
2399 if (!rc)
2400 rc = bnx2_setup_phy(bp, bp->phy_port);
Michael Chanb6016b72005-05-26 13:03:09 -07002401
2402 return rc;
2403}
2404
2405static int
2406bnx2_set_mac_loopback(struct bnx2 *bp)
2407{
2408 u32 mac_mode;
2409
Michael Chane503e062012-12-06 10:33:08 +00002410 mac_mode = BNX2_RD(bp, BNX2_EMAC_MODE);
Michael Chanb6016b72005-05-26 13:03:09 -07002411 mac_mode &= ~BNX2_EMAC_MODE_PORT;
2412 mac_mode |= BNX2_EMAC_MODE_MAC_LOOP | BNX2_EMAC_MODE_FORCE_LINK;
Michael Chane503e062012-12-06 10:33:08 +00002413 BNX2_WR(bp, BNX2_EMAC_MODE, mac_mode);
Michael Chanb6016b72005-05-26 13:03:09 -07002414 bp->link_up = 1;
2415 return 0;
2416}
2417
Michael Chanbc5a0692006-01-23 16:13:22 -08002418static int bnx2_test_link(struct bnx2 *);
2419
2420static int
2421bnx2_set_phy_loopback(struct bnx2 *bp)
2422{
2423 u32 mac_mode;
2424 int rc, i;
2425
2426 spin_lock_bh(&bp->phy_lock);
Michael Chanca58c3a2007-05-03 13:22:52 -07002427 rc = bnx2_write_phy(bp, bp->mii_bmcr, BMCR_LOOPBACK | BMCR_FULLDPLX |
Michael Chanbc5a0692006-01-23 16:13:22 -08002428 BMCR_SPEED1000);
2429 spin_unlock_bh(&bp->phy_lock);
2430 if (rc)
2431 return rc;
2432
2433 for (i = 0; i < 10; i++) {
2434 if (bnx2_test_link(bp) == 0)
2435 break;
Michael Chan80be4432006-11-19 14:07:28 -08002436 msleep(100);
Michael Chanbc5a0692006-01-23 16:13:22 -08002437 }
2438
Michael Chane503e062012-12-06 10:33:08 +00002439 mac_mode = BNX2_RD(bp, BNX2_EMAC_MODE);
Michael Chanbc5a0692006-01-23 16:13:22 -08002440 mac_mode &= ~(BNX2_EMAC_MODE_PORT | BNX2_EMAC_MODE_HALF_DUPLEX |
2441 BNX2_EMAC_MODE_MAC_LOOP | BNX2_EMAC_MODE_FORCE_LINK |
Michael Chan59b47d82006-11-19 14:10:45 -08002442 BNX2_EMAC_MODE_25G_MODE);
Michael Chanbc5a0692006-01-23 16:13:22 -08002443
2444 mac_mode |= BNX2_EMAC_MODE_PORT_GMII;
Michael Chane503e062012-12-06 10:33:08 +00002445 BNX2_WR(bp, BNX2_EMAC_MODE, mac_mode);
Michael Chanbc5a0692006-01-23 16:13:22 -08002446 bp->link_up = 1;
2447 return 0;
2448}
2449
Jeffrey Huangecdbf6e2011-07-13 17:24:21 +00002450static void
2451bnx2_dump_mcp_state(struct bnx2 *bp)
2452{
2453 struct net_device *dev = bp->dev;
2454 u32 mcp_p0, mcp_p1;
2455
2456 netdev_err(dev, "<--- start MCP states dump --->\n");
Michael Chan4ce45e02012-12-06 10:33:10 +00002457 if (BNX2_CHIP(bp) == BNX2_CHIP_5709) {
Jeffrey Huangecdbf6e2011-07-13 17:24:21 +00002458 mcp_p0 = BNX2_MCP_STATE_P0;
2459 mcp_p1 = BNX2_MCP_STATE_P1;
2460 } else {
2461 mcp_p0 = BNX2_MCP_STATE_P0_5708;
2462 mcp_p1 = BNX2_MCP_STATE_P1_5708;
2463 }
2464 netdev_err(dev, "DEBUG: MCP_STATE_P0[%08x] MCP_STATE_P1[%08x]\n",
2465 bnx2_reg_rd_ind(bp, mcp_p0), bnx2_reg_rd_ind(bp, mcp_p1));
2466 netdev_err(dev, "DEBUG: MCP mode[%08x] state[%08x] evt_mask[%08x]\n",
2467 bnx2_reg_rd_ind(bp, BNX2_MCP_CPU_MODE),
2468 bnx2_reg_rd_ind(bp, BNX2_MCP_CPU_STATE),
2469 bnx2_reg_rd_ind(bp, BNX2_MCP_CPU_EVENT_MASK));
2470 netdev_err(dev, "DEBUG: pc[%08x] pc[%08x] instr[%08x]\n",
2471 bnx2_reg_rd_ind(bp, BNX2_MCP_CPU_PROGRAM_COUNTER),
2472 bnx2_reg_rd_ind(bp, BNX2_MCP_CPU_PROGRAM_COUNTER),
2473 bnx2_reg_rd_ind(bp, BNX2_MCP_CPU_INSTRUCTION));
2474 netdev_err(dev, "DEBUG: shmem states:\n");
2475 netdev_err(dev, "DEBUG: drv_mb[%08x] fw_mb[%08x] link_status[%08x]",
2476 bnx2_shmem_rd(bp, BNX2_DRV_MB),
2477 bnx2_shmem_rd(bp, BNX2_FW_MB),
2478 bnx2_shmem_rd(bp, BNX2_LINK_STATUS));
2479 pr_cont(" drv_pulse_mb[%08x]\n", bnx2_shmem_rd(bp, BNX2_DRV_PULSE_MB));
2480 netdev_err(dev, "DEBUG: dev_info_signature[%08x] reset_type[%08x]",
2481 bnx2_shmem_rd(bp, BNX2_DEV_INFO_SIGNATURE),
2482 bnx2_shmem_rd(bp, BNX2_BC_STATE_RESET_TYPE));
2483 pr_cont(" condition[%08x]\n",
2484 bnx2_shmem_rd(bp, BNX2_BC_STATE_CONDITION));
Michael Chan13e63512012-06-16 15:45:42 +00002485 DP_SHMEM_LINE(bp, BNX2_BC_RESET_TYPE);
Jeffrey Huangecdbf6e2011-07-13 17:24:21 +00002486 DP_SHMEM_LINE(bp, 0x3cc);
2487 DP_SHMEM_LINE(bp, 0x3dc);
2488 DP_SHMEM_LINE(bp, 0x3ec);
2489 netdev_err(dev, "DEBUG: 0x3fc[%08x]\n", bnx2_shmem_rd(bp, 0x3fc));
2490 netdev_err(dev, "<--- end MCP states dump --->\n");
2491}
2492
Michael Chanb6016b72005-05-26 13:03:09 -07002493static int
Michael Chana2f13892008-07-14 22:38:23 -07002494bnx2_fw_sync(struct bnx2 *bp, u32 msg_data, int ack, int silent)
Michael Chanb6016b72005-05-26 13:03:09 -07002495{
2496 int i;
2497 u32 val;
2498
Michael Chanb6016b72005-05-26 13:03:09 -07002499 bp->fw_wr_seq++;
2500 msg_data |= bp->fw_wr_seq;
2501
Michael Chan2726d6e2008-01-29 21:35:05 -08002502 bnx2_shmem_wr(bp, BNX2_DRV_MB, msg_data);
Michael Chanb6016b72005-05-26 13:03:09 -07002503
Michael Chana2f13892008-07-14 22:38:23 -07002504 if (!ack)
2505 return 0;
2506
Michael Chanb6016b72005-05-26 13:03:09 -07002507 /* wait for an acknowledgement. */
Michael Chan40105c02008-11-12 16:02:45 -08002508 for (i = 0; i < (BNX2_FW_ACK_TIME_OUT_MS / 10); i++) {
Michael Chanb090ae22006-01-23 16:07:10 -08002509 msleep(10);
Michael Chanb6016b72005-05-26 13:03:09 -07002510
Michael Chan2726d6e2008-01-29 21:35:05 -08002511 val = bnx2_shmem_rd(bp, BNX2_FW_MB);
Michael Chanb6016b72005-05-26 13:03:09 -07002512
2513 if ((val & BNX2_FW_MSG_ACK) == (msg_data & BNX2_DRV_MSG_SEQ))
2514 break;
2515 }
Michael Chanb090ae22006-01-23 16:07:10 -08002516 if ((msg_data & BNX2_DRV_MSG_DATA) == BNX2_DRV_MSG_DATA_WAIT0)
2517 return 0;
Michael Chanb6016b72005-05-26 13:03:09 -07002518
2519 /* If we timed out, inform the firmware that this is the case. */
Michael Chanb090ae22006-01-23 16:07:10 -08002520 if ((val & BNX2_FW_MSG_ACK) != (msg_data & BNX2_DRV_MSG_SEQ)) {
Michael Chanb6016b72005-05-26 13:03:09 -07002521 msg_data &= ~BNX2_DRV_MSG_CODE;
2522 msg_data |= BNX2_DRV_MSG_CODE_FW_TIMEOUT;
2523
Michael Chan2726d6e2008-01-29 21:35:05 -08002524 bnx2_shmem_wr(bp, BNX2_DRV_MB, msg_data);
Jeffrey Huangecdbf6e2011-07-13 17:24:21 +00002525 if (!silent) {
2526 pr_err("fw sync timeout, reset code = %x\n", msg_data);
2527 bnx2_dump_mcp_state(bp);
2528 }
Michael Chanb6016b72005-05-26 13:03:09 -07002529
Michael Chanb6016b72005-05-26 13:03:09 -07002530 return -EBUSY;
2531 }
2532
Michael Chanb090ae22006-01-23 16:07:10 -08002533 if ((val & BNX2_FW_MSG_STATUS_MASK) != BNX2_FW_MSG_STATUS_OK)
2534 return -EIO;
2535
Michael Chanb6016b72005-05-26 13:03:09 -07002536 return 0;
2537}
2538
Michael Chan59b47d82006-11-19 14:10:45 -08002539static int
2540bnx2_init_5709_context(struct bnx2 *bp)
2541{
2542 int i, ret = 0;
2543 u32 val;
2544
2545 val = BNX2_CTX_COMMAND_ENABLED | BNX2_CTX_COMMAND_MEM_INIT | (1 << 12);
Michael Chan2bc40782012-12-06 10:33:09 +00002546 val |= (BNX2_PAGE_BITS - 8) << 16;
Michael Chane503e062012-12-06 10:33:08 +00002547 BNX2_WR(bp, BNX2_CTX_COMMAND, val);
Michael Chan641bdcd2007-06-04 21:22:24 -07002548 for (i = 0; i < 10; i++) {
Michael Chane503e062012-12-06 10:33:08 +00002549 val = BNX2_RD(bp, BNX2_CTX_COMMAND);
Michael Chan641bdcd2007-06-04 21:22:24 -07002550 if (!(val & BNX2_CTX_COMMAND_MEM_INIT))
2551 break;
2552 udelay(2);
2553 }
2554 if (val & BNX2_CTX_COMMAND_MEM_INIT)
2555 return -EBUSY;
2556
Michael Chan59b47d82006-11-19 14:10:45 -08002557 for (i = 0; i < bp->ctx_pages; i++) {
2558 int j;
2559
Michael Chan352f7682008-05-02 16:57:26 -07002560 if (bp->ctx_blk[i])
Michael Chan2bc40782012-12-06 10:33:09 +00002561 memset(bp->ctx_blk[i], 0, BNX2_PAGE_SIZE);
Michael Chan352f7682008-05-02 16:57:26 -07002562 else
2563 return -ENOMEM;
2564
Michael Chane503e062012-12-06 10:33:08 +00002565 BNX2_WR(bp, BNX2_CTX_HOST_PAGE_TBL_DATA0,
2566 (bp->ctx_blk_mapping[i] & 0xffffffff) |
2567 BNX2_CTX_HOST_PAGE_TBL_DATA0_VALID);
2568 BNX2_WR(bp, BNX2_CTX_HOST_PAGE_TBL_DATA1,
2569 (u64) bp->ctx_blk_mapping[i] >> 32);
2570 BNX2_WR(bp, BNX2_CTX_HOST_PAGE_TBL_CTRL, i |
2571 BNX2_CTX_HOST_PAGE_TBL_CTRL_WRITE_REQ);
Michael Chan59b47d82006-11-19 14:10:45 -08002572 for (j = 0; j < 10; j++) {
2573
Michael Chane503e062012-12-06 10:33:08 +00002574 val = BNX2_RD(bp, BNX2_CTX_HOST_PAGE_TBL_CTRL);
Michael Chan59b47d82006-11-19 14:10:45 -08002575 if (!(val & BNX2_CTX_HOST_PAGE_TBL_CTRL_WRITE_REQ))
2576 break;
2577 udelay(5);
2578 }
2579 if (val & BNX2_CTX_HOST_PAGE_TBL_CTRL_WRITE_REQ) {
2580 ret = -EBUSY;
2581 break;
2582 }
2583 }
2584 return ret;
2585}
2586
Michael Chanb6016b72005-05-26 13:03:09 -07002587static void
2588bnx2_init_context(struct bnx2 *bp)
2589{
2590 u32 vcid;
2591
2592 vcid = 96;
2593 while (vcid) {
2594 u32 vcid_addr, pcid_addr, offset;
Michael Chan7947b202007-06-04 21:17:10 -07002595 int i;
Michael Chanb6016b72005-05-26 13:03:09 -07002596
2597 vcid--;
2598
Michael Chan4ce45e02012-12-06 10:33:10 +00002599 if (BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5706_A0) {
Michael Chanb6016b72005-05-26 13:03:09 -07002600 u32 new_vcid;
2601
2602 vcid_addr = GET_PCID_ADDR(vcid);
2603 if (vcid & 0x8) {
2604 new_vcid = 0x60 + (vcid & 0xf0) + (vcid & 0x7);
2605 }
2606 else {
2607 new_vcid = vcid;
2608 }
2609 pcid_addr = GET_PCID_ADDR(new_vcid);
2610 }
2611 else {
2612 vcid_addr = GET_CID_ADDR(vcid);
2613 pcid_addr = vcid_addr;
2614 }
2615
Michael Chan7947b202007-06-04 21:17:10 -07002616 for (i = 0; i < (CTX_SIZE / PHY_CTX_SIZE); i++) {
2617 vcid_addr += (i << PHY_CTX_SHIFT);
2618 pcid_addr += (i << PHY_CTX_SHIFT);
Michael Chanb6016b72005-05-26 13:03:09 -07002619
Michael Chane503e062012-12-06 10:33:08 +00002620 BNX2_WR(bp, BNX2_CTX_VIRT_ADDR, vcid_addr);
2621 BNX2_WR(bp, BNX2_CTX_PAGE_TBL, pcid_addr);
Michael Chan7947b202007-06-04 21:17:10 -07002622
2623 /* Zero out the context. */
2624 for (offset = 0; offset < PHY_CTX_SIZE; offset += 4)
Michael Chan62a83132008-01-29 21:35:40 -08002625 bnx2_ctx_wr(bp, vcid_addr, offset, 0);
Michael Chanb6016b72005-05-26 13:03:09 -07002626 }
Michael Chanb6016b72005-05-26 13:03:09 -07002627 }
2628}
2629
2630static int
2631bnx2_alloc_bad_rbuf(struct bnx2 *bp)
2632{
2633 u16 *good_mbuf;
2634 u32 good_mbuf_cnt;
2635 u32 val;
2636
2637 good_mbuf = kmalloc(512 * sizeof(u16), GFP_KERNEL);
Joe Perchese404dec2012-01-29 12:56:23 +00002638 if (good_mbuf == NULL)
Michael Chanb6016b72005-05-26 13:03:09 -07002639 return -ENOMEM;
Michael Chanb6016b72005-05-26 13:03:09 -07002640
Michael Chane503e062012-12-06 10:33:08 +00002641 BNX2_WR(bp, BNX2_MISC_ENABLE_SET_BITS,
Michael Chanb6016b72005-05-26 13:03:09 -07002642 BNX2_MISC_ENABLE_SET_BITS_RX_MBUF_ENABLE);
2643
2644 good_mbuf_cnt = 0;
2645
2646 /* Allocate a bunch of mbufs and save the good ones in an array. */
Michael Chan2726d6e2008-01-29 21:35:05 -08002647 val = bnx2_reg_rd_ind(bp, BNX2_RBUF_STATUS1);
Michael Chanb6016b72005-05-26 13:03:09 -07002648 while (val & BNX2_RBUF_STATUS1_FREE_COUNT) {
Michael Chan2726d6e2008-01-29 21:35:05 -08002649 bnx2_reg_wr_ind(bp, BNX2_RBUF_COMMAND,
2650 BNX2_RBUF_COMMAND_ALLOC_REQ);
Michael Chanb6016b72005-05-26 13:03:09 -07002651
Michael Chan2726d6e2008-01-29 21:35:05 -08002652 val = bnx2_reg_rd_ind(bp, BNX2_RBUF_FW_BUF_ALLOC);
Michael Chanb6016b72005-05-26 13:03:09 -07002653
2654 val &= BNX2_RBUF_FW_BUF_ALLOC_VALUE;
2655
2656 /* The addresses with Bit 9 set are bad memory blocks. */
2657 if (!(val & (1 << 9))) {
2658 good_mbuf[good_mbuf_cnt] = (u16) val;
2659 good_mbuf_cnt++;
2660 }
2661
Michael Chan2726d6e2008-01-29 21:35:05 -08002662 val = bnx2_reg_rd_ind(bp, BNX2_RBUF_STATUS1);
Michael Chanb6016b72005-05-26 13:03:09 -07002663 }
2664
2665 /* Free the good ones back to the mbuf pool thus discarding
2666 * all the bad ones. */
2667 while (good_mbuf_cnt) {
2668 good_mbuf_cnt--;
2669
2670 val = good_mbuf[good_mbuf_cnt];
2671 val = (val << 9) | val | 1;
2672
Michael Chan2726d6e2008-01-29 21:35:05 -08002673 bnx2_reg_wr_ind(bp, BNX2_RBUF_FW_BUF_FREE, val);
Michael Chanb6016b72005-05-26 13:03:09 -07002674 }
2675 kfree(good_mbuf);
2676 return 0;
2677}
2678
2679static void
Benjamin Li5fcaed02008-07-14 22:39:52 -07002680bnx2_set_mac_addr(struct bnx2 *bp, u8 *mac_addr, u32 pos)
Michael Chanb6016b72005-05-26 13:03:09 -07002681{
2682 u32 val;
Michael Chanb6016b72005-05-26 13:03:09 -07002683
2684 val = (mac_addr[0] << 8) | mac_addr[1];
2685
Michael Chane503e062012-12-06 10:33:08 +00002686 BNX2_WR(bp, BNX2_EMAC_MAC_MATCH0 + (pos * 8), val);
Michael Chanb6016b72005-05-26 13:03:09 -07002687
Jeff Garzik6aa20a22006-09-13 13:24:59 -04002688 val = (mac_addr[2] << 24) | (mac_addr[3] << 16) |
Michael Chanb6016b72005-05-26 13:03:09 -07002689 (mac_addr[4] << 8) | mac_addr[5];
2690
Michael Chane503e062012-12-06 10:33:08 +00002691 BNX2_WR(bp, BNX2_EMAC_MAC_MATCH1 + (pos * 8), val);
Michael Chanb6016b72005-05-26 13:03:09 -07002692}
2693
2694static inline int
Stanislaw Gruszkaa2df00a2010-07-15 22:55:40 +00002695bnx2_alloc_rx_page(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr, u16 index, gfp_t gfp)
Michael Chan47bf4242007-12-12 11:19:12 -08002696{
2697 dma_addr_t mapping;
Michael Chan2bc40782012-12-06 10:33:09 +00002698 struct bnx2_sw_pg *rx_pg = &rxr->rx_pg_ring[index];
2699 struct bnx2_rx_bd *rxbd =
2700 &rxr->rx_pg_desc_ring[BNX2_RX_RING(index)][BNX2_RX_IDX(index)];
Stanislaw Gruszkaa2df00a2010-07-15 22:55:40 +00002701 struct page *page = alloc_page(gfp);
Michael Chan47bf4242007-12-12 11:19:12 -08002702
2703 if (!page)
2704 return -ENOMEM;
Stanislaw Gruszka36227e82010-07-15 04:25:50 +00002705 mapping = dma_map_page(&bp->pdev->dev, page, 0, PAGE_SIZE,
Michael Chan47bf4242007-12-12 11:19:12 -08002706 PCI_DMA_FROMDEVICE);
Stanislaw Gruszka36227e82010-07-15 04:25:50 +00002707 if (dma_mapping_error(&bp->pdev->dev, mapping)) {
Benjamin Li3d16af82008-10-09 12:26:41 -07002708 __free_page(page);
2709 return -EIO;
2710 }
2711
Michael Chan47bf4242007-12-12 11:19:12 -08002712 rx_pg->page = page;
FUJITA Tomonori1a4ccc22010-04-01 16:56:57 +00002713 dma_unmap_addr_set(rx_pg, mapping, mapping);
Michael Chan47bf4242007-12-12 11:19:12 -08002714 rxbd->rx_bd_haddr_hi = (u64) mapping >> 32;
2715 rxbd->rx_bd_haddr_lo = (u64) mapping & 0xffffffff;
2716 return 0;
2717}
2718
2719static void
Michael Chanbb4f98a2008-06-19 16:38:19 -07002720bnx2_free_rx_page(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr, u16 index)
Michael Chan47bf4242007-12-12 11:19:12 -08002721{
Michael Chan2bc40782012-12-06 10:33:09 +00002722 struct bnx2_sw_pg *rx_pg = &rxr->rx_pg_ring[index];
Michael Chan47bf4242007-12-12 11:19:12 -08002723 struct page *page = rx_pg->page;
2724
2725 if (!page)
2726 return;
2727
Stanislaw Gruszka36227e82010-07-15 04:25:50 +00002728 dma_unmap_page(&bp->pdev->dev, dma_unmap_addr(rx_pg, mapping),
2729 PAGE_SIZE, PCI_DMA_FROMDEVICE);
Michael Chan47bf4242007-12-12 11:19:12 -08002730
2731 __free_page(page);
2732 rx_pg->page = NULL;
2733}
2734
2735static inline int
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00002736bnx2_alloc_rx_data(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr, u16 index, gfp_t gfp)
Michael Chanb6016b72005-05-26 13:03:09 -07002737{
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00002738 u8 *data;
Michael Chan2bc40782012-12-06 10:33:09 +00002739 struct bnx2_sw_bd *rx_buf = &rxr->rx_buf_ring[index];
Michael Chanb6016b72005-05-26 13:03:09 -07002740 dma_addr_t mapping;
Michael Chan2bc40782012-12-06 10:33:09 +00002741 struct bnx2_rx_bd *rxbd =
2742 &rxr->rx_desc_ring[BNX2_RX_RING(index)][BNX2_RX_IDX(index)];
Michael Chanb6016b72005-05-26 13:03:09 -07002743
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00002744 data = kmalloc(bp->rx_buf_size, gfp);
2745 if (!data)
Michael Chanb6016b72005-05-26 13:03:09 -07002746 return -ENOMEM;
Michael Chanb6016b72005-05-26 13:03:09 -07002747
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00002748 mapping = dma_map_single(&bp->pdev->dev,
2749 get_l2_fhdr(data),
2750 bp->rx_buf_use_size,
Stanislaw Gruszka36227e82010-07-15 04:25:50 +00002751 PCI_DMA_FROMDEVICE);
2752 if (dma_mapping_error(&bp->pdev->dev, mapping)) {
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00002753 kfree(data);
Benjamin Li3d16af82008-10-09 12:26:41 -07002754 return -EIO;
2755 }
Michael Chanb6016b72005-05-26 13:03:09 -07002756
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00002757 rx_buf->data = data;
FUJITA Tomonori1a4ccc22010-04-01 16:56:57 +00002758 dma_unmap_addr_set(rx_buf, mapping, mapping);
Michael Chanb6016b72005-05-26 13:03:09 -07002759
2760 rxbd->rx_bd_haddr_hi = (u64) mapping >> 32;
2761 rxbd->rx_bd_haddr_lo = (u64) mapping & 0xffffffff;
2762
Michael Chanbb4f98a2008-06-19 16:38:19 -07002763 rxr->rx_prod_bseq += bp->rx_buf_use_size;
Michael Chanb6016b72005-05-26 13:03:09 -07002764
2765 return 0;
2766}
2767
Michael Chanda3e4fb2007-05-03 13:24:23 -07002768static int
Michael Chan35efa7c2007-12-20 19:56:37 -08002769bnx2_phy_event_is_set(struct bnx2 *bp, struct bnx2_napi *bnapi, u32 event)
Michael Chanda3e4fb2007-05-03 13:24:23 -07002770{
Michael Chan43e80b82008-06-19 16:41:08 -07002771 struct status_block *sblk = bnapi->status_blk.msi;
Michael Chanda3e4fb2007-05-03 13:24:23 -07002772 u32 new_link_state, old_link_state;
2773 int is_set = 1;
2774
2775 new_link_state = sblk->status_attn_bits & event;
2776 old_link_state = sblk->status_attn_bits_ack & event;
2777 if (new_link_state != old_link_state) {
2778 if (new_link_state)
Michael Chane503e062012-12-06 10:33:08 +00002779 BNX2_WR(bp, BNX2_PCICFG_STATUS_BIT_SET_CMD, event);
Michael Chanda3e4fb2007-05-03 13:24:23 -07002780 else
Michael Chane503e062012-12-06 10:33:08 +00002781 BNX2_WR(bp, BNX2_PCICFG_STATUS_BIT_CLEAR_CMD, event);
Michael Chanda3e4fb2007-05-03 13:24:23 -07002782 } else
2783 is_set = 0;
2784
2785 return is_set;
2786}
2787
Michael Chanb6016b72005-05-26 13:03:09 -07002788static void
Michael Chan35efa7c2007-12-20 19:56:37 -08002789bnx2_phy_int(struct bnx2 *bp, struct bnx2_napi *bnapi)
Michael Chanb6016b72005-05-26 13:03:09 -07002790{
Michael Chan74ecc622008-05-02 16:56:16 -07002791 spin_lock(&bp->phy_lock);
2792
2793 if (bnx2_phy_event_is_set(bp, bnapi, STATUS_ATTN_BITS_LINK_STATE))
Michael Chanb6016b72005-05-26 13:03:09 -07002794 bnx2_set_link(bp);
Michael Chan35efa7c2007-12-20 19:56:37 -08002795 if (bnx2_phy_event_is_set(bp, bnapi, STATUS_ATTN_BITS_TIMER_ABORT))
Michael Chan0d8a6572007-07-07 22:49:43 -07002796 bnx2_set_remote_link(bp);
2797
Michael Chan74ecc622008-05-02 16:56:16 -07002798 spin_unlock(&bp->phy_lock);
2799
Michael Chanb6016b72005-05-26 13:03:09 -07002800}
2801
Michael Chanead72702007-12-20 19:55:39 -08002802static inline u16
Michael Chan35efa7c2007-12-20 19:56:37 -08002803bnx2_get_hw_tx_cons(struct bnx2_napi *bnapi)
Michael Chanead72702007-12-20 19:55:39 -08002804{
2805 u16 cons;
2806
Michael Chan43e80b82008-06-19 16:41:08 -07002807 /* Tell compiler that status block fields can change. */
2808 barrier();
2809 cons = *bnapi->hw_tx_cons_ptr;
Michael Chan581daf72009-05-06 16:46:47 -07002810 barrier();
Michael Chan2bc40782012-12-06 10:33:09 +00002811 if (unlikely((cons & BNX2_MAX_TX_DESC_CNT) == BNX2_MAX_TX_DESC_CNT))
Michael Chanead72702007-12-20 19:55:39 -08002812 cons++;
2813 return cons;
2814}
2815
Michael Chan57851d82007-12-20 20:01:44 -08002816static int
2817bnx2_tx_int(struct bnx2 *bp, struct bnx2_napi *bnapi, int budget)
Michael Chanb6016b72005-05-26 13:03:09 -07002818{
Michael Chan35e90102008-06-19 16:37:42 -07002819 struct bnx2_tx_ring_info *txr = &bnapi->tx_ring;
Michael Chanb6016b72005-05-26 13:03:09 -07002820 u16 hw_cons, sw_cons, sw_ring_cons;
Benjamin Li706bf242008-07-18 17:55:11 -07002821 int tx_pkt = 0, index;
Eric Dumazete9831902011-11-29 11:53:05 +00002822 unsigned int tx_bytes = 0;
Benjamin Li706bf242008-07-18 17:55:11 -07002823 struct netdev_queue *txq;
2824
2825 index = (bnapi - bp->bnx2_napi);
2826 txq = netdev_get_tx_queue(bp->dev, index);
Michael Chanb6016b72005-05-26 13:03:09 -07002827
Michael Chan35efa7c2007-12-20 19:56:37 -08002828 hw_cons = bnx2_get_hw_tx_cons(bnapi);
Michael Chan35e90102008-06-19 16:37:42 -07002829 sw_cons = txr->tx_cons;
Michael Chanb6016b72005-05-26 13:03:09 -07002830
2831 while (sw_cons != hw_cons) {
Michael Chan2bc40782012-12-06 10:33:09 +00002832 struct bnx2_sw_tx_bd *tx_buf;
Michael Chanb6016b72005-05-26 13:03:09 -07002833 struct sk_buff *skb;
2834 int i, last;
2835
Michael Chan2bc40782012-12-06 10:33:09 +00002836 sw_ring_cons = BNX2_TX_RING_IDX(sw_cons);
Michael Chanb6016b72005-05-26 13:03:09 -07002837
Michael Chan35e90102008-06-19 16:37:42 -07002838 tx_buf = &txr->tx_buf_ring[sw_ring_cons];
Michael Chanb6016b72005-05-26 13:03:09 -07002839 skb = tx_buf->skb;
Arjan van de Ven1d39ed52006-12-12 14:06:23 +01002840
Eric Dumazetd62fda02009-05-12 20:48:02 +00002841 /* prefetch skb_end_pointer() to speedup skb_shinfo(skb) */
2842 prefetch(&skb->end);
2843
Michael Chanb6016b72005-05-26 13:03:09 -07002844 /* partial BD completions possible with TSO packets */
Eric Dumazetd62fda02009-05-12 20:48:02 +00002845 if (tx_buf->is_gso) {
Michael Chanb6016b72005-05-26 13:03:09 -07002846 u16 last_idx, last_ring_idx;
2847
Eric Dumazetd62fda02009-05-12 20:48:02 +00002848 last_idx = sw_cons + tx_buf->nr_frags + 1;
2849 last_ring_idx = sw_ring_cons + tx_buf->nr_frags + 1;
Michael Chan2bc40782012-12-06 10:33:09 +00002850 if (unlikely(last_ring_idx >= BNX2_MAX_TX_DESC_CNT)) {
Michael Chanb6016b72005-05-26 13:03:09 -07002851 last_idx++;
2852 }
2853 if (((s16) ((s16) last_idx - (s16) hw_cons)) > 0) {
2854 break;
2855 }
2856 }
Arjan van de Ven1d39ed52006-12-12 14:06:23 +01002857
Stanislaw Gruszka36227e82010-07-15 04:25:50 +00002858 dma_unmap_single(&bp->pdev->dev, dma_unmap_addr(tx_buf, mapping),
Alexander Duycke95524a2009-12-02 16:47:57 +00002859 skb_headlen(skb), PCI_DMA_TODEVICE);
Michael Chanb6016b72005-05-26 13:03:09 -07002860
2861 tx_buf->skb = NULL;
Eric Dumazetd62fda02009-05-12 20:48:02 +00002862 last = tx_buf->nr_frags;
Michael Chanb6016b72005-05-26 13:03:09 -07002863
2864 for (i = 0; i < last; i++) {
Michael Chan2bc40782012-12-06 10:33:09 +00002865 struct bnx2_sw_tx_bd *tx_buf;
Alexander Duycke95524a2009-12-02 16:47:57 +00002866
Michael Chan2bc40782012-12-06 10:33:09 +00002867 sw_cons = BNX2_NEXT_TX_BD(sw_cons);
2868
2869 tx_buf = &txr->tx_buf_ring[BNX2_TX_RING_IDX(sw_cons)];
Stanislaw Gruszka36227e82010-07-15 04:25:50 +00002870 dma_unmap_page(&bp->pdev->dev,
Michael Chan2bc40782012-12-06 10:33:09 +00002871 dma_unmap_addr(tx_buf, mapping),
Eric Dumazet9e903e02011-10-18 21:00:24 +00002872 skb_frag_size(&skb_shinfo(skb)->frags[i]),
Alexander Duycke95524a2009-12-02 16:47:57 +00002873 PCI_DMA_TODEVICE);
Michael Chanb6016b72005-05-26 13:03:09 -07002874 }
2875
Michael Chan2bc40782012-12-06 10:33:09 +00002876 sw_cons = BNX2_NEXT_TX_BD(sw_cons);
Michael Chanb6016b72005-05-26 13:03:09 -07002877
Eric Dumazete9831902011-11-29 11:53:05 +00002878 tx_bytes += skb->len;
Michael Chan745720e2006-06-29 12:37:41 -07002879 dev_kfree_skb(skb);
Michael Chan57851d82007-12-20 20:01:44 -08002880 tx_pkt++;
2881 if (tx_pkt == budget)
2882 break;
Michael Chanb6016b72005-05-26 13:03:09 -07002883
Eric Dumazetd62fda02009-05-12 20:48:02 +00002884 if (hw_cons == sw_cons)
2885 hw_cons = bnx2_get_hw_tx_cons(bnapi);
Michael Chanb6016b72005-05-26 13:03:09 -07002886 }
2887
Eric Dumazete9831902011-11-29 11:53:05 +00002888 netdev_tx_completed_queue(txq, tx_pkt, tx_bytes);
Michael Chan35e90102008-06-19 16:37:42 -07002889 txr->hw_tx_cons = hw_cons;
2890 txr->tx_cons = sw_cons;
Benjamin Li706bf242008-07-18 17:55:11 -07002891
Michael Chan2f8af122006-08-15 01:39:10 -07002892 /* Need to make the tx_cons update visible to bnx2_start_xmit()
Benjamin Li706bf242008-07-18 17:55:11 -07002893 * before checking for netif_tx_queue_stopped(). Without the
Michael Chan2f8af122006-08-15 01:39:10 -07002894 * memory barrier, there is a small possibility that bnx2_start_xmit()
2895 * will miss it and cause the queue to be stopped forever.
2896 */
2897 smp_mb();
Michael Chanb6016b72005-05-26 13:03:09 -07002898
Benjamin Li706bf242008-07-18 17:55:11 -07002899 if (unlikely(netif_tx_queue_stopped(txq)) &&
Michael Chan35e90102008-06-19 16:37:42 -07002900 (bnx2_tx_avail(bp, txr) > bp->tx_wake_thresh)) {
Benjamin Li706bf242008-07-18 17:55:11 -07002901 __netif_tx_lock(txq, smp_processor_id());
2902 if ((netif_tx_queue_stopped(txq)) &&
Michael Chan35e90102008-06-19 16:37:42 -07002903 (bnx2_tx_avail(bp, txr) > bp->tx_wake_thresh))
Benjamin Li706bf242008-07-18 17:55:11 -07002904 netif_tx_wake_queue(txq);
2905 __netif_tx_unlock(txq);
Michael Chanb6016b72005-05-26 13:03:09 -07002906 }
Benjamin Li706bf242008-07-18 17:55:11 -07002907
Michael Chan57851d82007-12-20 20:01:44 -08002908 return tx_pkt;
Michael Chanb6016b72005-05-26 13:03:09 -07002909}
2910
Michael Chan1db82f22007-12-12 11:19:35 -08002911static void
Michael Chanbb4f98a2008-06-19 16:38:19 -07002912bnx2_reuse_rx_skb_pages(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr,
Michael Chana1f60192007-12-20 19:57:19 -08002913 struct sk_buff *skb, int count)
Michael Chan1db82f22007-12-12 11:19:35 -08002914{
Michael Chan2bc40782012-12-06 10:33:09 +00002915 struct bnx2_sw_pg *cons_rx_pg, *prod_rx_pg;
2916 struct bnx2_rx_bd *cons_bd, *prod_bd;
Michael Chan1db82f22007-12-12 11:19:35 -08002917 int i;
Benjamin Li3d16af82008-10-09 12:26:41 -07002918 u16 hw_prod, prod;
Michael Chanbb4f98a2008-06-19 16:38:19 -07002919 u16 cons = rxr->rx_pg_cons;
Michael Chan1db82f22007-12-12 11:19:35 -08002920
Benjamin Li3d16af82008-10-09 12:26:41 -07002921 cons_rx_pg = &rxr->rx_pg_ring[cons];
2922
2923 /* The caller was unable to allocate a new page to replace the
2924 * last one in the frags array, so we need to recycle that page
2925 * and then free the skb.
2926 */
2927 if (skb) {
2928 struct page *page;
2929 struct skb_shared_info *shinfo;
2930
2931 shinfo = skb_shinfo(skb);
2932 shinfo->nr_frags--;
Ian Campbellb7b6a682011-08-24 22:28:12 +00002933 page = skb_frag_page(&shinfo->frags[shinfo->nr_frags]);
2934 __skb_frag_set_page(&shinfo->frags[shinfo->nr_frags], NULL);
Benjamin Li3d16af82008-10-09 12:26:41 -07002935
2936 cons_rx_pg->page = page;
2937 dev_kfree_skb(skb);
2938 }
2939
2940 hw_prod = rxr->rx_pg_prod;
2941
Michael Chan1db82f22007-12-12 11:19:35 -08002942 for (i = 0; i < count; i++) {
Michael Chan2bc40782012-12-06 10:33:09 +00002943 prod = BNX2_RX_PG_RING_IDX(hw_prod);
Michael Chan1db82f22007-12-12 11:19:35 -08002944
Michael Chanbb4f98a2008-06-19 16:38:19 -07002945 prod_rx_pg = &rxr->rx_pg_ring[prod];
2946 cons_rx_pg = &rxr->rx_pg_ring[cons];
Michael Chan2bc40782012-12-06 10:33:09 +00002947 cons_bd = &rxr->rx_pg_desc_ring[BNX2_RX_RING(cons)]
2948 [BNX2_RX_IDX(cons)];
2949 prod_bd = &rxr->rx_pg_desc_ring[BNX2_RX_RING(prod)]
2950 [BNX2_RX_IDX(prod)];
Michael Chan1db82f22007-12-12 11:19:35 -08002951
Michael Chan1db82f22007-12-12 11:19:35 -08002952 if (prod != cons) {
2953 prod_rx_pg->page = cons_rx_pg->page;
2954 cons_rx_pg->page = NULL;
FUJITA Tomonori1a4ccc22010-04-01 16:56:57 +00002955 dma_unmap_addr_set(prod_rx_pg, mapping,
2956 dma_unmap_addr(cons_rx_pg, mapping));
Michael Chan1db82f22007-12-12 11:19:35 -08002957
2958 prod_bd->rx_bd_haddr_hi = cons_bd->rx_bd_haddr_hi;
2959 prod_bd->rx_bd_haddr_lo = cons_bd->rx_bd_haddr_lo;
2960
2961 }
Michael Chan2bc40782012-12-06 10:33:09 +00002962 cons = BNX2_RX_PG_RING_IDX(BNX2_NEXT_RX_BD(cons));
2963 hw_prod = BNX2_NEXT_RX_BD(hw_prod);
Michael Chan1db82f22007-12-12 11:19:35 -08002964 }
Michael Chanbb4f98a2008-06-19 16:38:19 -07002965 rxr->rx_pg_prod = hw_prod;
2966 rxr->rx_pg_cons = cons;
Michael Chan1db82f22007-12-12 11:19:35 -08002967}
2968
Michael Chanb6016b72005-05-26 13:03:09 -07002969static inline void
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00002970bnx2_reuse_rx_data(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr,
2971 u8 *data, u16 cons, u16 prod)
Michael Chanb6016b72005-05-26 13:03:09 -07002972{
Michael Chan2bc40782012-12-06 10:33:09 +00002973 struct bnx2_sw_bd *cons_rx_buf, *prod_rx_buf;
2974 struct bnx2_rx_bd *cons_bd, *prod_bd;
Michael Chan236b6392006-03-20 17:49:02 -08002975
Michael Chanbb4f98a2008-06-19 16:38:19 -07002976 cons_rx_buf = &rxr->rx_buf_ring[cons];
2977 prod_rx_buf = &rxr->rx_buf_ring[prod];
Michael Chanb6016b72005-05-26 13:03:09 -07002978
Stanislaw Gruszka36227e82010-07-15 04:25:50 +00002979 dma_sync_single_for_device(&bp->pdev->dev,
FUJITA Tomonori1a4ccc22010-04-01 16:56:57 +00002980 dma_unmap_addr(cons_rx_buf, mapping),
Benjamin Li601d3d12008-05-16 22:19:35 -07002981 BNX2_RX_OFFSET + BNX2_RX_COPY_THRESH, PCI_DMA_FROMDEVICE);
Michael Chanb6016b72005-05-26 13:03:09 -07002982
Michael Chanbb4f98a2008-06-19 16:38:19 -07002983 rxr->rx_prod_bseq += bp->rx_buf_use_size;
Michael Chan236b6392006-03-20 17:49:02 -08002984
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00002985 prod_rx_buf->data = data;
Michael Chan236b6392006-03-20 17:49:02 -08002986
2987 if (cons == prod)
2988 return;
2989
FUJITA Tomonori1a4ccc22010-04-01 16:56:57 +00002990 dma_unmap_addr_set(prod_rx_buf, mapping,
2991 dma_unmap_addr(cons_rx_buf, mapping));
Michael Chanb6016b72005-05-26 13:03:09 -07002992
Michael Chan2bc40782012-12-06 10:33:09 +00002993 cons_bd = &rxr->rx_desc_ring[BNX2_RX_RING(cons)][BNX2_RX_IDX(cons)];
2994 prod_bd = &rxr->rx_desc_ring[BNX2_RX_RING(prod)][BNX2_RX_IDX(prod)];
Michael Chan236b6392006-03-20 17:49:02 -08002995 prod_bd->rx_bd_haddr_hi = cons_bd->rx_bd_haddr_hi;
2996 prod_bd->rx_bd_haddr_lo = cons_bd->rx_bd_haddr_lo;
Michael Chanb6016b72005-05-26 13:03:09 -07002997}
2998
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00002999static struct sk_buff *
3000bnx2_rx_skb(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr, u8 *data,
Michael Chana1f60192007-12-20 19:57:19 -08003001 unsigned int len, unsigned int hdr_len, dma_addr_t dma_addr,
3002 u32 ring_idx)
Michael Chan85833c62007-12-12 11:17:01 -08003003{
3004 int err;
3005 u16 prod = ring_idx & 0xffff;
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00003006 struct sk_buff *skb;
Michael Chan85833c62007-12-12 11:17:01 -08003007
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00003008 err = bnx2_alloc_rx_data(bp, rxr, prod, GFP_ATOMIC);
Michael Chan85833c62007-12-12 11:17:01 -08003009 if (unlikely(err)) {
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00003010 bnx2_reuse_rx_data(bp, rxr, data, (u16) (ring_idx >> 16), prod);
3011error:
Michael Chan1db82f22007-12-12 11:19:35 -08003012 if (hdr_len) {
3013 unsigned int raw_len = len + 4;
3014 int pages = PAGE_ALIGN(raw_len - hdr_len) >> PAGE_SHIFT;
3015
Michael Chanbb4f98a2008-06-19 16:38:19 -07003016 bnx2_reuse_rx_skb_pages(bp, rxr, NULL, pages);
Michael Chan1db82f22007-12-12 11:19:35 -08003017 }
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00003018 return NULL;
Michael Chan85833c62007-12-12 11:17:01 -08003019 }
3020
Stanislaw Gruszka36227e82010-07-15 04:25:50 +00003021 dma_unmap_single(&bp->pdev->dev, dma_addr, bp->rx_buf_use_size,
Michael Chan85833c62007-12-12 11:17:01 -08003022 PCI_DMA_FROMDEVICE);
Eric Dumazetd3836f22012-04-27 00:33:38 +00003023 skb = build_skb(data, 0);
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00003024 if (!skb) {
3025 kfree(data);
3026 goto error;
3027 }
3028 skb_reserve(skb, ((u8 *)get_l2_fhdr(data) - data) + BNX2_RX_OFFSET);
Michael Chan1db82f22007-12-12 11:19:35 -08003029 if (hdr_len == 0) {
3030 skb_put(skb, len);
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00003031 return skb;
Michael Chan1db82f22007-12-12 11:19:35 -08003032 } else {
3033 unsigned int i, frag_len, frag_size, pages;
Michael Chan2bc40782012-12-06 10:33:09 +00003034 struct bnx2_sw_pg *rx_pg;
Michael Chanbb4f98a2008-06-19 16:38:19 -07003035 u16 pg_cons = rxr->rx_pg_cons;
3036 u16 pg_prod = rxr->rx_pg_prod;
Michael Chan1db82f22007-12-12 11:19:35 -08003037
3038 frag_size = len + 4 - hdr_len;
3039 pages = PAGE_ALIGN(frag_size) >> PAGE_SHIFT;
3040 skb_put(skb, hdr_len);
3041
3042 for (i = 0; i < pages; i++) {
Benjamin Li3d16af82008-10-09 12:26:41 -07003043 dma_addr_t mapping_old;
3044
Michael Chan1db82f22007-12-12 11:19:35 -08003045 frag_len = min(frag_size, (unsigned int) PAGE_SIZE);
3046 if (unlikely(frag_len <= 4)) {
3047 unsigned int tail = 4 - frag_len;
3048
Michael Chanbb4f98a2008-06-19 16:38:19 -07003049 rxr->rx_pg_cons = pg_cons;
3050 rxr->rx_pg_prod = pg_prod;
3051 bnx2_reuse_rx_skb_pages(bp, rxr, NULL,
Michael Chana1f60192007-12-20 19:57:19 -08003052 pages - i);
Michael Chan1db82f22007-12-12 11:19:35 -08003053 skb->len -= tail;
3054 if (i == 0) {
3055 skb->tail -= tail;
3056 } else {
3057 skb_frag_t *frag =
3058 &skb_shinfo(skb)->frags[i - 1];
Eric Dumazet9e903e02011-10-18 21:00:24 +00003059 skb_frag_size_sub(frag, tail);
Michael Chan1db82f22007-12-12 11:19:35 -08003060 skb->data_len -= tail;
Michael Chan1db82f22007-12-12 11:19:35 -08003061 }
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00003062 return skb;
Michael Chan1db82f22007-12-12 11:19:35 -08003063 }
Michael Chanbb4f98a2008-06-19 16:38:19 -07003064 rx_pg = &rxr->rx_pg_ring[pg_cons];
Michael Chan1db82f22007-12-12 11:19:35 -08003065
Benjamin Li3d16af82008-10-09 12:26:41 -07003066 /* Don't unmap yet. If we're unable to allocate a new
3067 * page, we need to recycle the page and the DMA addr.
3068 */
FUJITA Tomonori1a4ccc22010-04-01 16:56:57 +00003069 mapping_old = dma_unmap_addr(rx_pg, mapping);
Michael Chan1db82f22007-12-12 11:19:35 -08003070 if (i == pages - 1)
3071 frag_len -= 4;
3072
3073 skb_fill_page_desc(skb, i, rx_pg->page, 0, frag_len);
3074 rx_pg->page = NULL;
3075
Michael Chanbb4f98a2008-06-19 16:38:19 -07003076 err = bnx2_alloc_rx_page(bp, rxr,
Michael Chan2bc40782012-12-06 10:33:09 +00003077 BNX2_RX_PG_RING_IDX(pg_prod),
Stanislaw Gruszkaa2df00a2010-07-15 22:55:40 +00003078 GFP_ATOMIC);
Michael Chan1db82f22007-12-12 11:19:35 -08003079 if (unlikely(err)) {
Michael Chanbb4f98a2008-06-19 16:38:19 -07003080 rxr->rx_pg_cons = pg_cons;
3081 rxr->rx_pg_prod = pg_prod;
3082 bnx2_reuse_rx_skb_pages(bp, rxr, skb,
Michael Chana1f60192007-12-20 19:57:19 -08003083 pages - i);
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00003084 return NULL;
Michael Chan1db82f22007-12-12 11:19:35 -08003085 }
3086
Stanislaw Gruszka36227e82010-07-15 04:25:50 +00003087 dma_unmap_page(&bp->pdev->dev, mapping_old,
Benjamin Li3d16af82008-10-09 12:26:41 -07003088 PAGE_SIZE, PCI_DMA_FROMDEVICE);
3089
Michael Chan1db82f22007-12-12 11:19:35 -08003090 frag_size -= frag_len;
3091 skb->data_len += frag_len;
Eric Dumazeta1f4e8b2011-10-13 07:50:19 +00003092 skb->truesize += PAGE_SIZE;
Michael Chan1db82f22007-12-12 11:19:35 -08003093 skb->len += frag_len;
3094
Michael Chan2bc40782012-12-06 10:33:09 +00003095 pg_prod = BNX2_NEXT_RX_BD(pg_prod);
3096 pg_cons = BNX2_RX_PG_RING_IDX(BNX2_NEXT_RX_BD(pg_cons));
Michael Chan1db82f22007-12-12 11:19:35 -08003097 }
Michael Chanbb4f98a2008-06-19 16:38:19 -07003098 rxr->rx_pg_prod = pg_prod;
3099 rxr->rx_pg_cons = pg_cons;
Michael Chan1db82f22007-12-12 11:19:35 -08003100 }
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00003101 return skb;
Michael Chan85833c62007-12-12 11:17:01 -08003102}
3103
Michael Chanc09c2622007-12-10 17:18:37 -08003104static inline u16
Michael Chan35efa7c2007-12-20 19:56:37 -08003105bnx2_get_hw_rx_cons(struct bnx2_napi *bnapi)
Michael Chanc09c2622007-12-10 17:18:37 -08003106{
Michael Chanbb4f98a2008-06-19 16:38:19 -07003107 u16 cons;
3108
Michael Chan43e80b82008-06-19 16:41:08 -07003109 /* Tell compiler that status block fields can change. */
3110 barrier();
3111 cons = *bnapi->hw_rx_cons_ptr;
Michael Chan581daf72009-05-06 16:46:47 -07003112 barrier();
Michael Chan2bc40782012-12-06 10:33:09 +00003113 if (unlikely((cons & BNX2_MAX_RX_DESC_CNT) == BNX2_MAX_RX_DESC_CNT))
Michael Chanc09c2622007-12-10 17:18:37 -08003114 cons++;
3115 return cons;
3116}
3117
Michael Chanb6016b72005-05-26 13:03:09 -07003118static int
Michael Chan35efa7c2007-12-20 19:56:37 -08003119bnx2_rx_int(struct bnx2 *bp, struct bnx2_napi *bnapi, int budget)
Michael Chanb6016b72005-05-26 13:03:09 -07003120{
Michael Chanbb4f98a2008-06-19 16:38:19 -07003121 struct bnx2_rx_ring_info *rxr = &bnapi->rx_ring;
Michael Chanb6016b72005-05-26 13:03:09 -07003122 u16 hw_cons, sw_cons, sw_ring_cons, sw_prod, sw_ring_prod;
3123 struct l2_fhdr *rx_hdr;
Michael Chan1db82f22007-12-12 11:19:35 -08003124 int rx_pkt = 0, pg_ring_used = 0;
Michael Chanb6016b72005-05-26 13:03:09 -07003125
Michael Chan35efa7c2007-12-20 19:56:37 -08003126 hw_cons = bnx2_get_hw_rx_cons(bnapi);
Michael Chanbb4f98a2008-06-19 16:38:19 -07003127 sw_cons = rxr->rx_cons;
3128 sw_prod = rxr->rx_prod;
Michael Chanb6016b72005-05-26 13:03:09 -07003129
3130 /* Memory barrier necessary as speculative reads of the rx
3131 * buffer can be ahead of the index in the status block
3132 */
3133 rmb();
3134 while (sw_cons != hw_cons) {
Michael Chan1db82f22007-12-12 11:19:35 -08003135 unsigned int len, hdr_len;
Michael Chanade2bfe2006-01-23 16:09:51 -08003136 u32 status;
Michael Chan2bc40782012-12-06 10:33:09 +00003137 struct bnx2_sw_bd *rx_buf, *next_rx_buf;
Michael Chanb6016b72005-05-26 13:03:09 -07003138 struct sk_buff *skb;
Michael Chan236b6392006-03-20 17:49:02 -08003139 dma_addr_t dma_addr;
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00003140 u8 *data;
Michael Chan2bc40782012-12-06 10:33:09 +00003141 u16 next_ring_idx;
Michael Chanb6016b72005-05-26 13:03:09 -07003142
Michael Chan2bc40782012-12-06 10:33:09 +00003143 sw_ring_cons = BNX2_RX_RING_IDX(sw_cons);
3144 sw_ring_prod = BNX2_RX_RING_IDX(sw_prod);
Michael Chanb6016b72005-05-26 13:03:09 -07003145
Michael Chanbb4f98a2008-06-19 16:38:19 -07003146 rx_buf = &rxr->rx_buf_ring[sw_ring_cons];
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00003147 data = rx_buf->data;
3148 rx_buf->data = NULL;
Michael Chan236b6392006-03-20 17:49:02 -08003149
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00003150 rx_hdr = get_l2_fhdr(data);
3151 prefetch(rx_hdr);
Michael Chan236b6392006-03-20 17:49:02 -08003152
FUJITA Tomonori1a4ccc22010-04-01 16:56:57 +00003153 dma_addr = dma_unmap_addr(rx_buf, mapping);
Michael Chan236b6392006-03-20 17:49:02 -08003154
Stanislaw Gruszka36227e82010-07-15 04:25:50 +00003155 dma_sync_single_for_cpu(&bp->pdev->dev, dma_addr,
Benjamin Li601d3d12008-05-16 22:19:35 -07003156 BNX2_RX_OFFSET + BNX2_RX_COPY_THRESH,
3157 PCI_DMA_FROMDEVICE);
Michael Chanb6016b72005-05-26 13:03:09 -07003158
Michael Chan2bc40782012-12-06 10:33:09 +00003159 next_ring_idx = BNX2_RX_RING_IDX(BNX2_NEXT_RX_BD(sw_cons));
3160 next_rx_buf = &rxr->rx_buf_ring[next_ring_idx];
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00003161 prefetch(get_l2_fhdr(next_rx_buf->data));
3162
Michael Chan1db82f22007-12-12 11:19:35 -08003163 len = rx_hdr->l2_fhdr_pkt_len;
Michael Chan990ec382009-02-12 16:54:13 -08003164 status = rx_hdr->l2_fhdr_status;
Michael Chanb6016b72005-05-26 13:03:09 -07003165
Michael Chan1db82f22007-12-12 11:19:35 -08003166 hdr_len = 0;
3167 if (status & L2_FHDR_STATUS_SPLIT) {
3168 hdr_len = rx_hdr->l2_fhdr_ip_xsum;
3169 pg_ring_used = 1;
3170 } else if (len > bp->rx_jumbo_thresh) {
3171 hdr_len = bp->rx_jumbo_thresh;
3172 pg_ring_used = 1;
3173 }
3174
Michael Chan990ec382009-02-12 16:54:13 -08003175 if (unlikely(status & (L2_FHDR_ERRORS_BAD_CRC |
3176 L2_FHDR_ERRORS_PHY_DECODE |
3177 L2_FHDR_ERRORS_ALIGNMENT |
3178 L2_FHDR_ERRORS_TOO_SHORT |
3179 L2_FHDR_ERRORS_GIANT_FRAME))) {
3180
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00003181 bnx2_reuse_rx_data(bp, rxr, data, sw_ring_cons,
Michael Chan990ec382009-02-12 16:54:13 -08003182 sw_ring_prod);
3183 if (pg_ring_used) {
3184 int pages;
3185
3186 pages = PAGE_ALIGN(len - hdr_len) >> PAGE_SHIFT;
3187
3188 bnx2_reuse_rx_skb_pages(bp, rxr, NULL, pages);
3189 }
3190 goto next_rx;
3191 }
3192
Michael Chan1db82f22007-12-12 11:19:35 -08003193 len -= 4;
Michael Chanb6016b72005-05-26 13:03:09 -07003194
Michael Chan5d5d0012007-12-12 11:17:43 -08003195 if (len <= bp->rx_copy_thresh) {
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00003196 skb = netdev_alloc_skb(bp->dev, len + 6);
3197 if (skb == NULL) {
3198 bnx2_reuse_rx_data(bp, rxr, data, sw_ring_cons,
Michael Chan85833c62007-12-12 11:17:01 -08003199 sw_ring_prod);
3200 goto next_rx;
3201 }
Michael Chanb6016b72005-05-26 13:03:09 -07003202
3203 /* aligned copy */
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00003204 memcpy(skb->data,
3205 (u8 *)rx_hdr + BNX2_RX_OFFSET - 6,
3206 len + 6);
3207 skb_reserve(skb, 6);
3208 skb_put(skb, len);
Michael Chanb6016b72005-05-26 13:03:09 -07003209
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00003210 bnx2_reuse_rx_data(bp, rxr, data,
Michael Chanb6016b72005-05-26 13:03:09 -07003211 sw_ring_cons, sw_ring_prod);
3212
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00003213 } else {
3214 skb = bnx2_rx_skb(bp, rxr, data, len, hdr_len, dma_addr,
3215 (sw_ring_cons << 16) | sw_ring_prod);
3216 if (!skb)
3217 goto next_rx;
3218 }
Michael Chanf22828e2008-08-14 15:30:14 -07003219 if ((status & L2_FHDR_STATUS_L2_VLAN_TAG) &&
Jesse Gross7d0fd212010-10-20 13:56:09 +00003220 !(bp->rx_mode & BNX2_EMAC_RX_MODE_KEEP_VLAN_TAG))
Patrick McHardy86a9bad2013-04-19 02:04:30 +00003221 __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), rx_hdr->l2_fhdr_vlan_tag);
Michael Chanf22828e2008-08-14 15:30:14 -07003222
Michael Chanb6016b72005-05-26 13:03:09 -07003223 skb->protocol = eth_type_trans(skb, bp->dev);
3224
3225 if ((len > (bp->dev->mtu + ETH_HLEN)) &&
Alexey Dobriyand1e100b2006-06-11 20:57:17 -07003226 (ntohs(skb->protocol) != 0x8100)) {
Michael Chanb6016b72005-05-26 13:03:09 -07003227
Michael Chan745720e2006-06-29 12:37:41 -07003228 dev_kfree_skb(skb);
Michael Chanb6016b72005-05-26 13:03:09 -07003229 goto next_rx;
3230
3231 }
3232
Eric Dumazetbc8acf22010-09-02 13:07:41 -07003233 skb_checksum_none_assert(skb);
Michał Mirosław8d7dfc22011-04-10 04:47:46 +00003234 if ((bp->dev->features & NETIF_F_RXCSUM) &&
Michael Chanb6016b72005-05-26 13:03:09 -07003235 (status & (L2_FHDR_STATUS_TCP_SEGMENT |
3236 L2_FHDR_STATUS_UDP_DATAGRAM))) {
3237
Michael Chanade2bfe2006-01-23 16:09:51 -08003238 if (likely((status & (L2_FHDR_ERRORS_TCP_XSUM |
3239 L2_FHDR_ERRORS_UDP_XSUM)) == 0))
Michael Chanb6016b72005-05-26 13:03:09 -07003240 skb->ip_summed = CHECKSUM_UNNECESSARY;
3241 }
Michael Chanfdc85412010-07-03 20:42:16 +00003242 if ((bp->dev->features & NETIF_F_RXHASH) &&
3243 ((status & L2_FHDR_STATUS_USE_RXHASH) ==
3244 L2_FHDR_STATUS_USE_RXHASH))
Tom Herbertcf1bfd62013-12-17 23:22:57 -08003245 skb_set_hash(skb, rx_hdr->l2_fhdr_hash,
3246 PKT_HASH_TYPE_L3);
Michael Chanb6016b72005-05-26 13:03:09 -07003247
David S. Miller0c8dfc82009-01-27 16:22:32 -08003248 skb_record_rx_queue(skb, bnapi - &bp->bnx2_napi[0]);
Jesse Gross7d0fd212010-10-20 13:56:09 +00003249 napi_gro_receive(&bnapi->napi, skb);
Michael Chanb6016b72005-05-26 13:03:09 -07003250 rx_pkt++;
3251
3252next_rx:
Michael Chan2bc40782012-12-06 10:33:09 +00003253 sw_cons = BNX2_NEXT_RX_BD(sw_cons);
3254 sw_prod = BNX2_NEXT_RX_BD(sw_prod);
Michael Chanb6016b72005-05-26 13:03:09 -07003255
3256 if ((rx_pkt == budget))
3257 break;
Michael Chanf4e418f2005-11-04 08:53:48 -08003258
3259 /* Refresh hw_cons to see if there is new work */
3260 if (sw_cons == hw_cons) {
Michael Chan35efa7c2007-12-20 19:56:37 -08003261 hw_cons = bnx2_get_hw_rx_cons(bnapi);
Michael Chanf4e418f2005-11-04 08:53:48 -08003262 rmb();
3263 }
Michael Chanb6016b72005-05-26 13:03:09 -07003264 }
Michael Chanbb4f98a2008-06-19 16:38:19 -07003265 rxr->rx_cons = sw_cons;
3266 rxr->rx_prod = sw_prod;
Michael Chanb6016b72005-05-26 13:03:09 -07003267
Michael Chan1db82f22007-12-12 11:19:35 -08003268 if (pg_ring_used)
Michael Chane503e062012-12-06 10:33:08 +00003269 BNX2_WR16(bp, rxr->rx_pg_bidx_addr, rxr->rx_pg_prod);
Michael Chan1db82f22007-12-12 11:19:35 -08003270
Michael Chane503e062012-12-06 10:33:08 +00003271 BNX2_WR16(bp, rxr->rx_bidx_addr, sw_prod);
Michael Chanb6016b72005-05-26 13:03:09 -07003272
Michael Chane503e062012-12-06 10:33:08 +00003273 BNX2_WR(bp, rxr->rx_bseq_addr, rxr->rx_prod_bseq);
Michael Chanb6016b72005-05-26 13:03:09 -07003274
3275 mmiowb();
3276
3277 return rx_pkt;
3278
3279}
3280
3281/* MSI ISR - The only difference between this and the INTx ISR
3282 * is that the MSI interrupt is always serviced.
3283 */
3284static irqreturn_t
David Howells7d12e782006-10-05 14:55:46 +01003285bnx2_msi(int irq, void *dev_instance)
Michael Chanb6016b72005-05-26 13:03:09 -07003286{
Michael Chanf0ea2e62008-06-19 16:41:57 -07003287 struct bnx2_napi *bnapi = dev_instance;
3288 struct bnx2 *bp = bnapi->bp;
Michael Chanb6016b72005-05-26 13:03:09 -07003289
Michael Chan43e80b82008-06-19 16:41:08 -07003290 prefetch(bnapi->status_blk.msi);
Michael Chane503e062012-12-06 10:33:08 +00003291 BNX2_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
Michael Chanb6016b72005-05-26 13:03:09 -07003292 BNX2_PCICFG_INT_ACK_CMD_USE_INT_HC_PARAM |
3293 BNX2_PCICFG_INT_ACK_CMD_MASK_INT);
3294
3295 /* Return here if interrupt is disabled. */
Michael Chan73eef4c2005-08-25 15:39:15 -07003296 if (unlikely(atomic_read(&bp->intr_sem) != 0))
3297 return IRQ_HANDLED;
Michael Chanb6016b72005-05-26 13:03:09 -07003298
Ben Hutchings288379f2009-01-19 16:43:59 -08003299 napi_schedule(&bnapi->napi);
Michael Chanb6016b72005-05-26 13:03:09 -07003300
Michael Chan73eef4c2005-08-25 15:39:15 -07003301 return IRQ_HANDLED;
Michael Chanb6016b72005-05-26 13:03:09 -07003302}
3303
3304static irqreturn_t
Michael Chan8e6a72c2007-05-03 13:24:48 -07003305bnx2_msi_1shot(int irq, void *dev_instance)
3306{
Michael Chanf0ea2e62008-06-19 16:41:57 -07003307 struct bnx2_napi *bnapi = dev_instance;
3308 struct bnx2 *bp = bnapi->bp;
Michael Chan8e6a72c2007-05-03 13:24:48 -07003309
Michael Chan43e80b82008-06-19 16:41:08 -07003310 prefetch(bnapi->status_blk.msi);
Michael Chan8e6a72c2007-05-03 13:24:48 -07003311
3312 /* Return here if interrupt is disabled. */
3313 if (unlikely(atomic_read(&bp->intr_sem) != 0))
3314 return IRQ_HANDLED;
3315
Ben Hutchings288379f2009-01-19 16:43:59 -08003316 napi_schedule(&bnapi->napi);
Michael Chan8e6a72c2007-05-03 13:24:48 -07003317
3318 return IRQ_HANDLED;
3319}
3320
3321static irqreturn_t
David Howells7d12e782006-10-05 14:55:46 +01003322bnx2_interrupt(int irq, void *dev_instance)
Michael Chanb6016b72005-05-26 13:03:09 -07003323{
Michael Chanf0ea2e62008-06-19 16:41:57 -07003324 struct bnx2_napi *bnapi = dev_instance;
3325 struct bnx2 *bp = bnapi->bp;
Michael Chan43e80b82008-06-19 16:41:08 -07003326 struct status_block *sblk = bnapi->status_blk.msi;
Michael Chanb6016b72005-05-26 13:03:09 -07003327
3328 /* When using INTx, it is possible for the interrupt to arrive
3329 * at the CPU before the status block posted prior to the
3330 * interrupt. Reading a register will flush the status block.
3331 * When using MSI, the MSI message will always complete after
3332 * the status block write.
3333 */
Michael Chan35efa7c2007-12-20 19:56:37 -08003334 if ((sblk->status_idx == bnapi->last_status_idx) &&
Michael Chane503e062012-12-06 10:33:08 +00003335 (BNX2_RD(bp, BNX2_PCICFG_MISC_STATUS) &
Michael Chanb6016b72005-05-26 13:03:09 -07003336 BNX2_PCICFG_MISC_STATUS_INTA_VALUE))
Michael Chan73eef4c2005-08-25 15:39:15 -07003337 return IRQ_NONE;
Michael Chanb6016b72005-05-26 13:03:09 -07003338
Michael Chane503e062012-12-06 10:33:08 +00003339 BNX2_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
Michael Chanb6016b72005-05-26 13:03:09 -07003340 BNX2_PCICFG_INT_ACK_CMD_USE_INT_HC_PARAM |
3341 BNX2_PCICFG_INT_ACK_CMD_MASK_INT);
3342
Michael Chanb8a7ce72007-07-07 22:51:03 -07003343 /* Read back to deassert IRQ immediately to avoid too many
3344 * spurious interrupts.
3345 */
Michael Chane503e062012-12-06 10:33:08 +00003346 BNX2_RD(bp, BNX2_PCICFG_INT_ACK_CMD);
Michael Chanb8a7ce72007-07-07 22:51:03 -07003347
Michael Chanb6016b72005-05-26 13:03:09 -07003348 /* Return here if interrupt is shared and is disabled. */
Michael Chan73eef4c2005-08-25 15:39:15 -07003349 if (unlikely(atomic_read(&bp->intr_sem) != 0))
3350 return IRQ_HANDLED;
Michael Chanb6016b72005-05-26 13:03:09 -07003351
Ben Hutchings288379f2009-01-19 16:43:59 -08003352 if (napi_schedule_prep(&bnapi->napi)) {
Michael Chan35efa7c2007-12-20 19:56:37 -08003353 bnapi->last_status_idx = sblk->status_idx;
Ben Hutchings288379f2009-01-19 16:43:59 -08003354 __napi_schedule(&bnapi->napi);
Michael Chanb8a7ce72007-07-07 22:51:03 -07003355 }
Michael Chanb6016b72005-05-26 13:03:09 -07003356
Michael Chan73eef4c2005-08-25 15:39:15 -07003357 return IRQ_HANDLED;
Michael Chanb6016b72005-05-26 13:03:09 -07003358}
3359
Michael Chan43e80b82008-06-19 16:41:08 -07003360static inline int
3361bnx2_has_fast_work(struct bnx2_napi *bnapi)
3362{
3363 struct bnx2_tx_ring_info *txr = &bnapi->tx_ring;
3364 struct bnx2_rx_ring_info *rxr = &bnapi->rx_ring;
3365
3366 if ((bnx2_get_hw_rx_cons(bnapi) != rxr->rx_cons) ||
3367 (bnx2_get_hw_tx_cons(bnapi) != txr->hw_tx_cons))
3368 return 1;
3369 return 0;
3370}
3371
Michael Chan0d8a6572007-07-07 22:49:43 -07003372#define STATUS_ATTN_EVENTS (STATUS_ATTN_BITS_LINK_STATE | \
3373 STATUS_ATTN_BITS_TIMER_ABORT)
Michael Chanda3e4fb2007-05-03 13:24:23 -07003374
Michael Chanf4e418f2005-11-04 08:53:48 -08003375static inline int
Michael Chan35efa7c2007-12-20 19:56:37 -08003376bnx2_has_work(struct bnx2_napi *bnapi)
Michael Chanf4e418f2005-11-04 08:53:48 -08003377{
Michael Chan43e80b82008-06-19 16:41:08 -07003378 struct status_block *sblk = bnapi->status_blk.msi;
Michael Chanf4e418f2005-11-04 08:53:48 -08003379
Michael Chan43e80b82008-06-19 16:41:08 -07003380 if (bnx2_has_fast_work(bnapi))
Michael Chanf4e418f2005-11-04 08:53:48 -08003381 return 1;
3382
Michael Chan4edd4732009-06-08 18:14:42 -07003383#ifdef BCM_CNIC
3384 if (bnapi->cnic_present && (bnapi->cnic_tag != sblk->status_idx))
3385 return 1;
3386#endif
3387
Michael Chanda3e4fb2007-05-03 13:24:23 -07003388 if ((sblk->status_attn_bits & STATUS_ATTN_EVENTS) !=
3389 (sblk->status_attn_bits_ack & STATUS_ATTN_EVENTS))
Michael Chanf4e418f2005-11-04 08:53:48 -08003390 return 1;
3391
3392 return 0;
3393}
3394
Michael Chanefba0182008-12-03 00:36:15 -08003395static void
3396bnx2_chk_missed_msi(struct bnx2 *bp)
3397{
3398 struct bnx2_napi *bnapi = &bp->bnx2_napi[0];
3399 u32 msi_ctrl;
3400
3401 if (bnx2_has_work(bnapi)) {
Michael Chane503e062012-12-06 10:33:08 +00003402 msi_ctrl = BNX2_RD(bp, BNX2_PCICFG_MSI_CONTROL);
Michael Chanefba0182008-12-03 00:36:15 -08003403 if (!(msi_ctrl & BNX2_PCICFG_MSI_CONTROL_ENABLE))
3404 return;
3405
3406 if (bnapi->last_status_idx == bp->idle_chk_status_idx) {
Michael Chane503e062012-12-06 10:33:08 +00003407 BNX2_WR(bp, BNX2_PCICFG_MSI_CONTROL, msi_ctrl &
3408 ~BNX2_PCICFG_MSI_CONTROL_ENABLE);
3409 BNX2_WR(bp, BNX2_PCICFG_MSI_CONTROL, msi_ctrl);
Michael Chanefba0182008-12-03 00:36:15 -08003410 bnx2_msi(bp->irq_tbl[0].vector, bnapi);
3411 }
3412 }
3413
3414 bp->idle_chk_status_idx = bnapi->last_status_idx;
3415}
3416
Michael Chan4edd4732009-06-08 18:14:42 -07003417#ifdef BCM_CNIC
3418static void bnx2_poll_cnic(struct bnx2 *bp, struct bnx2_napi *bnapi)
3419{
3420 struct cnic_ops *c_ops;
3421
3422 if (!bnapi->cnic_present)
3423 return;
3424
3425 rcu_read_lock();
3426 c_ops = rcu_dereference(bp->cnic_ops);
3427 if (c_ops)
3428 bnapi->cnic_tag = c_ops->cnic_handler(bp->cnic_data,
3429 bnapi->status_blk.msi);
3430 rcu_read_unlock();
3431}
3432#endif
3433
Michael Chan43e80b82008-06-19 16:41:08 -07003434static void bnx2_poll_link(struct bnx2 *bp, struct bnx2_napi *bnapi)
Michael Chanb6016b72005-05-26 13:03:09 -07003435{
Michael Chan43e80b82008-06-19 16:41:08 -07003436 struct status_block *sblk = bnapi->status_blk.msi;
Michael Chanda3e4fb2007-05-03 13:24:23 -07003437 u32 status_attn_bits = sblk->status_attn_bits;
3438 u32 status_attn_bits_ack = sblk->status_attn_bits_ack;
Michael Chanb6016b72005-05-26 13:03:09 -07003439
Michael Chanda3e4fb2007-05-03 13:24:23 -07003440 if ((status_attn_bits & STATUS_ATTN_EVENTS) !=
3441 (status_attn_bits_ack & STATUS_ATTN_EVENTS)) {
Michael Chanb6016b72005-05-26 13:03:09 -07003442
Michael Chan35efa7c2007-12-20 19:56:37 -08003443 bnx2_phy_int(bp, bnapi);
Michael Chanbf5295b2006-03-23 01:11:56 -08003444
3445 /* This is needed to take care of transient status
3446 * during link changes.
3447 */
Michael Chane503e062012-12-06 10:33:08 +00003448 BNX2_WR(bp, BNX2_HC_COMMAND,
3449 bp->hc_cmd | BNX2_HC_COMMAND_COAL_NOW_WO_INT);
3450 BNX2_RD(bp, BNX2_HC_COMMAND);
Michael Chanb6016b72005-05-26 13:03:09 -07003451 }
Michael Chan43e80b82008-06-19 16:41:08 -07003452}
3453
3454static int bnx2_poll_work(struct bnx2 *bp, struct bnx2_napi *bnapi,
3455 int work_done, int budget)
3456{
3457 struct bnx2_tx_ring_info *txr = &bnapi->tx_ring;
3458 struct bnx2_rx_ring_info *rxr = &bnapi->rx_ring;
Michael Chanb6016b72005-05-26 13:03:09 -07003459
Michael Chan35e90102008-06-19 16:37:42 -07003460 if (bnx2_get_hw_tx_cons(bnapi) != txr->hw_tx_cons)
Michael Chan57851d82007-12-20 20:01:44 -08003461 bnx2_tx_int(bp, bnapi, 0);
Michael Chanb6016b72005-05-26 13:03:09 -07003462
Michael Chanbb4f98a2008-06-19 16:38:19 -07003463 if (bnx2_get_hw_rx_cons(bnapi) != rxr->rx_cons)
Michael Chan35efa7c2007-12-20 19:56:37 -08003464 work_done += bnx2_rx_int(bp, bnapi, budget - work_done);
Jeff Garzik6aa20a22006-09-13 13:24:59 -04003465
David S. Miller6f535762007-10-11 18:08:29 -07003466 return work_done;
3467}
Michael Chanf4e418f2005-11-04 08:53:48 -08003468
Michael Chanf0ea2e62008-06-19 16:41:57 -07003469static int bnx2_poll_msix(struct napi_struct *napi, int budget)
3470{
3471 struct bnx2_napi *bnapi = container_of(napi, struct bnx2_napi, napi);
3472 struct bnx2 *bp = bnapi->bp;
3473 int work_done = 0;
3474 struct status_block_msix *sblk = bnapi->status_blk.msix;
3475
3476 while (1) {
3477 work_done = bnx2_poll_work(bp, bnapi, work_done, budget);
3478 if (unlikely(work_done >= budget))
3479 break;
3480
3481 bnapi->last_status_idx = sblk->status_idx;
3482 /* status idx must be read before checking for more work. */
3483 rmb();
3484 if (likely(!bnx2_has_fast_work(bnapi))) {
3485
Ben Hutchings288379f2009-01-19 16:43:59 -08003486 napi_complete(napi);
Michael Chane503e062012-12-06 10:33:08 +00003487 BNX2_WR(bp, BNX2_PCICFG_INT_ACK_CMD, bnapi->int_num |
3488 BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
3489 bnapi->last_status_idx);
Michael Chanf0ea2e62008-06-19 16:41:57 -07003490 break;
3491 }
3492 }
3493 return work_done;
3494}
3495
David S. Miller6f535762007-10-11 18:08:29 -07003496static int bnx2_poll(struct napi_struct *napi, int budget)
3497{
Michael Chan35efa7c2007-12-20 19:56:37 -08003498 struct bnx2_napi *bnapi = container_of(napi, struct bnx2_napi, napi);
3499 struct bnx2 *bp = bnapi->bp;
David S. Miller6f535762007-10-11 18:08:29 -07003500 int work_done = 0;
Michael Chan43e80b82008-06-19 16:41:08 -07003501 struct status_block *sblk = bnapi->status_blk.msi;
David S. Miller6f535762007-10-11 18:08:29 -07003502
3503 while (1) {
Michael Chan43e80b82008-06-19 16:41:08 -07003504 bnx2_poll_link(bp, bnapi);
3505
Michael Chan35efa7c2007-12-20 19:56:37 -08003506 work_done = bnx2_poll_work(bp, bnapi, work_done, budget);
David S. Miller6f535762007-10-11 18:08:29 -07003507
Michael Chan4edd4732009-06-08 18:14:42 -07003508#ifdef BCM_CNIC
3509 bnx2_poll_cnic(bp, bnapi);
3510#endif
3511
Michael Chan35efa7c2007-12-20 19:56:37 -08003512 /* bnapi->last_status_idx is used below to tell the hw how
Michael Chan6dee6422007-10-12 01:40:38 -07003513 * much work has been processed, so we must read it before
3514 * checking for more work.
3515 */
Michael Chan35efa7c2007-12-20 19:56:37 -08003516 bnapi->last_status_idx = sblk->status_idx;
Michael Chanefba0182008-12-03 00:36:15 -08003517
3518 if (unlikely(work_done >= budget))
3519 break;
3520
Michael Chan6dee6422007-10-12 01:40:38 -07003521 rmb();
Michael Chan35efa7c2007-12-20 19:56:37 -08003522 if (likely(!bnx2_has_work(bnapi))) {
Ben Hutchings288379f2009-01-19 16:43:59 -08003523 napi_complete(napi);
David S. Millerf86e82f2008-01-21 17:15:40 -08003524 if (likely(bp->flags & BNX2_FLAG_USING_MSI_OR_MSIX)) {
Michael Chane503e062012-12-06 10:33:08 +00003525 BNX2_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
3526 BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
3527 bnapi->last_status_idx);
Michael Chan6dee6422007-10-12 01:40:38 -07003528 break;
David S. Miller6f535762007-10-11 18:08:29 -07003529 }
Michael Chane503e062012-12-06 10:33:08 +00003530 BNX2_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
3531 BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
3532 BNX2_PCICFG_INT_ACK_CMD_MASK_INT |
3533 bnapi->last_status_idx);
David S. Miller6f535762007-10-11 18:08:29 -07003534
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);
David S. Miller6f535762007-10-11 18:08:29 -07003538 break;
Michael Chan1269a8a2006-01-23 16:11:03 -08003539 }
Michael Chanb6016b72005-05-26 13:03:09 -07003540 }
3541
Stephen Hemmingerbea33482007-10-03 16:41:36 -07003542 return work_done;
Michael Chanb6016b72005-05-26 13:03:09 -07003543}
3544
Herbert Xu932ff272006-06-09 12:20:56 -07003545/* Called with rtnl_lock from vlan functions and also netif_tx_lock
Michael Chanb6016b72005-05-26 13:03:09 -07003546 * from set_multicast.
3547 */
3548static void
3549bnx2_set_rx_mode(struct net_device *dev)
3550{
Michael Chan972ec0d2006-01-23 16:12:43 -08003551 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07003552 u32 rx_mode, sort_mode;
Jiri Pirkoccffad252009-05-22 23:22:17 +00003553 struct netdev_hw_addr *ha;
Michael Chanb6016b72005-05-26 13:03:09 -07003554 int i;
Michael Chanb6016b72005-05-26 13:03:09 -07003555
Michael Chan9f52b562008-10-09 12:21:46 -07003556 if (!netif_running(dev))
3557 return;
3558
Michael Chanc770a652005-08-25 15:38:39 -07003559 spin_lock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07003560
3561 rx_mode = bp->rx_mode & ~(BNX2_EMAC_RX_MODE_PROMISCUOUS |
3562 BNX2_EMAC_RX_MODE_KEEP_VLAN_TAG);
3563 sort_mode = 1 | BNX2_RPM_SORT_USER0_BC_EN;
Patrick McHardyf6469682013-04-19 02:04:27 +00003564 if (!(dev->features & NETIF_F_HW_VLAN_CTAG_RX) &&
Jesse Gross7d0fd212010-10-20 13:56:09 +00003565 (bp->flags & BNX2_FLAG_CAN_KEEP_VLAN))
Michael Chanb6016b72005-05-26 13:03:09 -07003566 rx_mode |= BNX2_EMAC_RX_MODE_KEEP_VLAN_TAG;
Michael Chanb6016b72005-05-26 13:03:09 -07003567 if (dev->flags & IFF_PROMISC) {
3568 /* Promiscuous mode. */
3569 rx_mode |= BNX2_EMAC_RX_MODE_PROMISCUOUS;
Michael Chan75108732006-11-19 14:06:40 -08003570 sort_mode |= BNX2_RPM_SORT_USER0_PROM_EN |
3571 BNX2_RPM_SORT_USER0_PROM_VLAN;
Michael Chanb6016b72005-05-26 13:03:09 -07003572 }
3573 else if (dev->flags & IFF_ALLMULTI) {
3574 for (i = 0; i < NUM_MC_HASH_REGISTERS; i++) {
Michael Chane503e062012-12-06 10:33:08 +00003575 BNX2_WR(bp, BNX2_EMAC_MULTICAST_HASH0 + (i * 4),
3576 0xffffffff);
Michael Chanb6016b72005-05-26 13:03:09 -07003577 }
3578 sort_mode |= BNX2_RPM_SORT_USER0_MC_EN;
3579 }
3580 else {
3581 /* Accept one or more multicast(s). */
Michael Chanb6016b72005-05-26 13:03:09 -07003582 u32 mc_filter[NUM_MC_HASH_REGISTERS];
3583 u32 regidx;
3584 u32 bit;
3585 u32 crc;
3586
3587 memset(mc_filter, 0, 4 * NUM_MC_HASH_REGISTERS);
3588
Jiri Pirko22bedad32010-04-01 21:22:57 +00003589 netdev_for_each_mc_addr(ha, dev) {
3590 crc = ether_crc_le(ETH_ALEN, ha->addr);
Michael Chanb6016b72005-05-26 13:03:09 -07003591 bit = crc & 0xff;
3592 regidx = (bit & 0xe0) >> 5;
3593 bit &= 0x1f;
3594 mc_filter[regidx] |= (1 << bit);
3595 }
3596
3597 for (i = 0; i < NUM_MC_HASH_REGISTERS; i++) {
Michael Chane503e062012-12-06 10:33:08 +00003598 BNX2_WR(bp, BNX2_EMAC_MULTICAST_HASH0 + (i * 4),
3599 mc_filter[i]);
Michael Chanb6016b72005-05-26 13:03:09 -07003600 }
3601
3602 sort_mode |= BNX2_RPM_SORT_USER0_MC_HSH_EN;
3603 }
3604
Jiri Pirko32e7bfc2010-01-25 13:36:10 -08003605 if (netdev_uc_count(dev) > BNX2_MAX_UNICAST_ADDRESSES) {
Benjamin Li5fcaed02008-07-14 22:39:52 -07003606 rx_mode |= BNX2_EMAC_RX_MODE_PROMISCUOUS;
3607 sort_mode |= BNX2_RPM_SORT_USER0_PROM_EN |
3608 BNX2_RPM_SORT_USER0_PROM_VLAN;
3609 } else if (!(dev->flags & IFF_PROMISC)) {
Benjamin Li5fcaed02008-07-14 22:39:52 -07003610 /* Add all entries into to the match filter list */
Jiri Pirkoccffad252009-05-22 23:22:17 +00003611 i = 0;
Jiri Pirko32e7bfc2010-01-25 13:36:10 -08003612 netdev_for_each_uc_addr(ha, dev) {
Jiri Pirkoccffad252009-05-22 23:22:17 +00003613 bnx2_set_mac_addr(bp, ha->addr,
Benjamin Li5fcaed02008-07-14 22:39:52 -07003614 i + BNX2_START_UNICAST_ADDRESS_INDEX);
3615 sort_mode |= (1 <<
3616 (i + BNX2_START_UNICAST_ADDRESS_INDEX));
Jiri Pirkoccffad252009-05-22 23:22:17 +00003617 i++;
Benjamin Li5fcaed02008-07-14 22:39:52 -07003618 }
3619
3620 }
3621
Michael Chanb6016b72005-05-26 13:03:09 -07003622 if (rx_mode != bp->rx_mode) {
3623 bp->rx_mode = rx_mode;
Michael Chane503e062012-12-06 10:33:08 +00003624 BNX2_WR(bp, BNX2_EMAC_RX_MODE, rx_mode);
Michael Chanb6016b72005-05-26 13:03:09 -07003625 }
3626
Michael Chane503e062012-12-06 10:33:08 +00003627 BNX2_WR(bp, BNX2_RPM_SORT_USER0, 0x0);
3628 BNX2_WR(bp, BNX2_RPM_SORT_USER0, sort_mode);
3629 BNX2_WR(bp, BNX2_RPM_SORT_USER0, sort_mode | BNX2_RPM_SORT_USER0_ENA);
Michael Chanb6016b72005-05-26 13:03:09 -07003630
Michael Chanc770a652005-08-25 15:38:39 -07003631 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07003632}
3633
françois romieu7880b722011-09-30 00:36:52 +00003634static int
Michael Chan57579f72009-04-04 16:51:14 -07003635check_fw_section(const struct firmware *fw,
3636 const struct bnx2_fw_file_section *section,
3637 u32 alignment, bool non_empty)
Michael Chanb6016b72005-05-26 13:03:09 -07003638{
Michael Chan57579f72009-04-04 16:51:14 -07003639 u32 offset = be32_to_cpu(section->offset);
3640 u32 len = be32_to_cpu(section->len);
Michael Chanb6016b72005-05-26 13:03:09 -07003641
Michael Chan57579f72009-04-04 16:51:14 -07003642 if ((offset == 0 && len != 0) || offset >= fw->size || offset & 3)
3643 return -EINVAL;
3644 if ((non_empty && len == 0) || len > fw->size - offset ||
3645 len & (alignment - 1))
3646 return -EINVAL;
3647 return 0;
3648}
3649
françois romieu7880b722011-09-30 00:36:52 +00003650static int
Michael Chan57579f72009-04-04 16:51:14 -07003651check_mips_fw_entry(const struct firmware *fw,
3652 const struct bnx2_mips_fw_file_entry *entry)
3653{
3654 if (check_fw_section(fw, &entry->text, 4, true) ||
3655 check_fw_section(fw, &entry->data, 4, false) ||
3656 check_fw_section(fw, &entry->rodata, 4, false))
3657 return -EINVAL;
3658 return 0;
3659}
3660
françois romieu7880b722011-09-30 00:36:52 +00003661static void bnx2_release_firmware(struct bnx2 *bp)
3662{
3663 if (bp->rv2p_firmware) {
3664 release_firmware(bp->mips_firmware);
3665 release_firmware(bp->rv2p_firmware);
3666 bp->rv2p_firmware = NULL;
3667 }
3668}
3669
3670static int bnx2_request_uncached_firmware(struct bnx2 *bp)
Michael Chan57579f72009-04-04 16:51:14 -07003671{
3672 const char *mips_fw_file, *rv2p_fw_file;
Bastian Blank5ee1c322009-04-08 15:50:07 -07003673 const struct bnx2_mips_fw_file *mips_fw;
3674 const struct bnx2_rv2p_fw_file *rv2p_fw;
Michael Chan57579f72009-04-04 16:51:14 -07003675 int rc;
3676
Michael Chan4ce45e02012-12-06 10:33:10 +00003677 if (BNX2_CHIP(bp) == BNX2_CHIP_5709) {
Michael Chan57579f72009-04-04 16:51:14 -07003678 mips_fw_file = FW_MIPS_FILE_09;
Michael Chan4ce45e02012-12-06 10:33:10 +00003679 if ((BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5709_A0) ||
3680 (BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5709_A1))
Michael Chan078b0732009-08-29 00:02:46 -07003681 rv2p_fw_file = FW_RV2P_FILE_09_Ax;
3682 else
3683 rv2p_fw_file = FW_RV2P_FILE_09;
Michael Chan57579f72009-04-04 16:51:14 -07003684 } else {
3685 mips_fw_file = FW_MIPS_FILE_06;
3686 rv2p_fw_file = FW_RV2P_FILE_06;
3687 }
3688
3689 rc = request_firmware(&bp->mips_firmware, mips_fw_file, &bp->pdev->dev);
3690 if (rc) {
Joe Perches3a9c6a42010-02-17 15:01:51 +00003691 pr_err("Can't load firmware file \"%s\"\n", mips_fw_file);
françois romieu7880b722011-09-30 00:36:52 +00003692 goto out;
Michael Chan57579f72009-04-04 16:51:14 -07003693 }
3694
3695 rc = request_firmware(&bp->rv2p_firmware, rv2p_fw_file, &bp->pdev->dev);
3696 if (rc) {
Joe Perches3a9c6a42010-02-17 15:01:51 +00003697 pr_err("Can't load firmware file \"%s\"\n", rv2p_fw_file);
françois romieu7880b722011-09-30 00:36:52 +00003698 goto err_release_mips_firmware;
Michael Chan57579f72009-04-04 16:51:14 -07003699 }
Bastian Blank5ee1c322009-04-08 15:50:07 -07003700 mips_fw = (const struct bnx2_mips_fw_file *) bp->mips_firmware->data;
3701 rv2p_fw = (const struct bnx2_rv2p_fw_file *) bp->rv2p_firmware->data;
3702 if (bp->mips_firmware->size < sizeof(*mips_fw) ||
3703 check_mips_fw_entry(bp->mips_firmware, &mips_fw->com) ||
3704 check_mips_fw_entry(bp->mips_firmware, &mips_fw->cp) ||
3705 check_mips_fw_entry(bp->mips_firmware, &mips_fw->rxp) ||
3706 check_mips_fw_entry(bp->mips_firmware, &mips_fw->tpat) ||
3707 check_mips_fw_entry(bp->mips_firmware, &mips_fw->txp)) {
Joe Perches3a9c6a42010-02-17 15:01:51 +00003708 pr_err("Firmware file \"%s\" is invalid\n", mips_fw_file);
françois romieu7880b722011-09-30 00:36:52 +00003709 rc = -EINVAL;
3710 goto err_release_firmware;
Michael Chan57579f72009-04-04 16:51:14 -07003711 }
Bastian Blank5ee1c322009-04-08 15:50:07 -07003712 if (bp->rv2p_firmware->size < sizeof(*rv2p_fw) ||
3713 check_fw_section(bp->rv2p_firmware, &rv2p_fw->proc1.rv2p, 8, true) ||
3714 check_fw_section(bp->rv2p_firmware, &rv2p_fw->proc2.rv2p, 8, true)) {
Joe Perches3a9c6a42010-02-17 15:01:51 +00003715 pr_err("Firmware file \"%s\" is invalid\n", rv2p_fw_file);
françois romieu7880b722011-09-30 00:36:52 +00003716 rc = -EINVAL;
3717 goto err_release_firmware;
Michael Chan57579f72009-04-04 16:51:14 -07003718 }
françois romieu7880b722011-09-30 00:36:52 +00003719out:
3720 return rc;
Michael Chan57579f72009-04-04 16:51:14 -07003721
françois romieu7880b722011-09-30 00:36:52 +00003722err_release_firmware:
3723 release_firmware(bp->rv2p_firmware);
3724 bp->rv2p_firmware = NULL;
3725err_release_mips_firmware:
3726 release_firmware(bp->mips_firmware);
3727 goto out;
3728}
3729
3730static int bnx2_request_firmware(struct bnx2 *bp)
3731{
3732 return bp->rv2p_firmware ? 0 : bnx2_request_uncached_firmware(bp);
Michael Chan57579f72009-04-04 16:51:14 -07003733}
3734
3735static u32
3736rv2p_fw_fixup(u32 rv2p_proc, int idx, u32 loc, u32 rv2p_code)
3737{
3738 switch (idx) {
3739 case RV2P_P1_FIXUP_PAGE_SIZE_IDX:
3740 rv2p_code &= ~RV2P_BD_PAGE_SIZE_MSK;
3741 rv2p_code |= RV2P_BD_PAGE_SIZE;
3742 break;
3743 }
3744 return rv2p_code;
3745}
3746
3747static int
3748load_rv2p_fw(struct bnx2 *bp, u32 rv2p_proc,
3749 const struct bnx2_rv2p_fw_file_entry *fw_entry)
3750{
3751 u32 rv2p_code_len, file_offset;
3752 __be32 *rv2p_code;
3753 int i;
3754 u32 val, cmd, addr;
3755
3756 rv2p_code_len = be32_to_cpu(fw_entry->rv2p.len);
3757 file_offset = be32_to_cpu(fw_entry->rv2p.offset);
3758
3759 rv2p_code = (__be32 *)(bp->rv2p_firmware->data + file_offset);
3760
3761 if (rv2p_proc == RV2P_PROC1) {
3762 cmd = BNX2_RV2P_PROC1_ADDR_CMD_RDWR;
3763 addr = BNX2_RV2P_PROC1_ADDR_CMD;
3764 } else {
3765 cmd = BNX2_RV2P_PROC2_ADDR_CMD_RDWR;
3766 addr = BNX2_RV2P_PROC2_ADDR_CMD;
Michael Chand25be1d2008-05-02 16:57:59 -07003767 }
Michael Chanb6016b72005-05-26 13:03:09 -07003768
3769 for (i = 0; i < rv2p_code_len; i += 8) {
Michael Chane503e062012-12-06 10:33:08 +00003770 BNX2_WR(bp, BNX2_RV2P_INSTR_HIGH, be32_to_cpu(*rv2p_code));
Michael Chanb6016b72005-05-26 13:03:09 -07003771 rv2p_code++;
Michael Chane503e062012-12-06 10:33:08 +00003772 BNX2_WR(bp, BNX2_RV2P_INSTR_LOW, be32_to_cpu(*rv2p_code));
Michael Chanb6016b72005-05-26 13:03:09 -07003773 rv2p_code++;
3774
Michael Chan57579f72009-04-04 16:51:14 -07003775 val = (i / 8) | cmd;
Michael Chane503e062012-12-06 10:33:08 +00003776 BNX2_WR(bp, addr, val);
Michael Chan57579f72009-04-04 16:51:14 -07003777 }
3778
3779 rv2p_code = (__be32 *)(bp->rv2p_firmware->data + file_offset);
3780 for (i = 0; i < 8; i++) {
3781 u32 loc, code;
3782
3783 loc = be32_to_cpu(fw_entry->fixup[i]);
3784 if (loc && ((loc * 4) < rv2p_code_len)) {
3785 code = be32_to_cpu(*(rv2p_code + loc - 1));
Michael Chane503e062012-12-06 10:33:08 +00003786 BNX2_WR(bp, BNX2_RV2P_INSTR_HIGH, code);
Michael Chan57579f72009-04-04 16:51:14 -07003787 code = be32_to_cpu(*(rv2p_code + loc));
3788 code = rv2p_fw_fixup(rv2p_proc, i, loc, code);
Michael Chane503e062012-12-06 10:33:08 +00003789 BNX2_WR(bp, BNX2_RV2P_INSTR_LOW, code);
Michael Chan57579f72009-04-04 16:51:14 -07003790
3791 val = (loc / 2) | cmd;
Michael Chane503e062012-12-06 10:33:08 +00003792 BNX2_WR(bp, addr, val);
Michael Chanb6016b72005-05-26 13:03:09 -07003793 }
3794 }
3795
3796 /* Reset the processor, un-stall is done later. */
3797 if (rv2p_proc == RV2P_PROC1) {
Michael Chane503e062012-12-06 10:33:08 +00003798 BNX2_WR(bp, BNX2_RV2P_COMMAND, BNX2_RV2P_COMMAND_PROC1_RESET);
Michael Chanb6016b72005-05-26 13:03:09 -07003799 }
3800 else {
Michael Chane503e062012-12-06 10:33:08 +00003801 BNX2_WR(bp, BNX2_RV2P_COMMAND, BNX2_RV2P_COMMAND_PROC2_RESET);
Michael Chanb6016b72005-05-26 13:03:09 -07003802 }
Michael Chan57579f72009-04-04 16:51:14 -07003803
3804 return 0;
Michael Chanb6016b72005-05-26 13:03:09 -07003805}
3806
Michael Chanaf3ee512006-11-19 14:09:25 -08003807static int
Michael Chan57579f72009-04-04 16:51:14 -07003808load_cpu_fw(struct bnx2 *bp, const struct cpu_reg *cpu_reg,
3809 const struct bnx2_mips_fw_file_entry *fw_entry)
Michael Chanb6016b72005-05-26 13:03:09 -07003810{
Michael Chan57579f72009-04-04 16:51:14 -07003811 u32 addr, len, file_offset;
3812 __be32 *data;
Michael Chanb6016b72005-05-26 13:03:09 -07003813 u32 offset;
3814 u32 val;
3815
3816 /* Halt the CPU. */
Michael Chan2726d6e2008-01-29 21:35:05 -08003817 val = bnx2_reg_rd_ind(bp, cpu_reg->mode);
Michael Chanb6016b72005-05-26 13:03:09 -07003818 val |= cpu_reg->mode_value_halt;
Michael Chan2726d6e2008-01-29 21:35:05 -08003819 bnx2_reg_wr_ind(bp, cpu_reg->mode, val);
3820 bnx2_reg_wr_ind(bp, cpu_reg->state, cpu_reg->state_value_clear);
Michael Chanb6016b72005-05-26 13:03:09 -07003821
3822 /* Load the Text area. */
Michael Chan57579f72009-04-04 16:51:14 -07003823 addr = be32_to_cpu(fw_entry->text.addr);
3824 len = be32_to_cpu(fw_entry->text.len);
3825 file_offset = be32_to_cpu(fw_entry->text.offset);
3826 data = (__be32 *)(bp->mips_firmware->data + file_offset);
3827
3828 offset = cpu_reg->spad_base + (addr - cpu_reg->mips_view_base);
3829 if (len) {
Michael Chanb6016b72005-05-26 13:03:09 -07003830 int j;
3831
Michael Chan57579f72009-04-04 16:51:14 -07003832 for (j = 0; j < (len / 4); j++, offset += 4)
3833 bnx2_reg_wr_ind(bp, offset, be32_to_cpu(data[j]));
Michael Chanb6016b72005-05-26 13:03:09 -07003834 }
3835
3836 /* Load the Data area. */
Michael Chan57579f72009-04-04 16:51:14 -07003837 addr = be32_to_cpu(fw_entry->data.addr);
3838 len = be32_to_cpu(fw_entry->data.len);
3839 file_offset = be32_to_cpu(fw_entry->data.offset);
3840 data = (__be32 *)(bp->mips_firmware->data + file_offset);
3841
3842 offset = cpu_reg->spad_base + (addr - cpu_reg->mips_view_base);
3843 if (len) {
Michael Chanb6016b72005-05-26 13:03:09 -07003844 int j;
3845
Michael Chan57579f72009-04-04 16:51:14 -07003846 for (j = 0; j < (len / 4); j++, offset += 4)
3847 bnx2_reg_wr_ind(bp, offset, be32_to_cpu(data[j]));
Michael Chanb6016b72005-05-26 13:03:09 -07003848 }
3849
3850 /* Load the Read-Only area. */
Michael Chan57579f72009-04-04 16:51:14 -07003851 addr = be32_to_cpu(fw_entry->rodata.addr);
3852 len = be32_to_cpu(fw_entry->rodata.len);
3853 file_offset = be32_to_cpu(fw_entry->rodata.offset);
3854 data = (__be32 *)(bp->mips_firmware->data + file_offset);
3855
3856 offset = cpu_reg->spad_base + (addr - cpu_reg->mips_view_base);
3857 if (len) {
Michael Chanb6016b72005-05-26 13:03:09 -07003858 int j;
3859
Michael Chan57579f72009-04-04 16:51:14 -07003860 for (j = 0; j < (len / 4); j++, offset += 4)
3861 bnx2_reg_wr_ind(bp, offset, be32_to_cpu(data[j]));
Michael Chanb6016b72005-05-26 13:03:09 -07003862 }
3863
3864 /* Clear the pre-fetch instruction. */
Michael Chan2726d6e2008-01-29 21:35:05 -08003865 bnx2_reg_wr_ind(bp, cpu_reg->inst, 0);
Michael Chan57579f72009-04-04 16:51:14 -07003866
3867 val = be32_to_cpu(fw_entry->start_addr);
3868 bnx2_reg_wr_ind(bp, cpu_reg->pc, val);
Michael Chanb6016b72005-05-26 13:03:09 -07003869
3870 /* Start the CPU. */
Michael Chan2726d6e2008-01-29 21:35:05 -08003871 val = bnx2_reg_rd_ind(bp, cpu_reg->mode);
Michael Chanb6016b72005-05-26 13:03:09 -07003872 val &= ~cpu_reg->mode_value_halt;
Michael Chan2726d6e2008-01-29 21:35:05 -08003873 bnx2_reg_wr_ind(bp, cpu_reg->state, cpu_reg->state_value_clear);
3874 bnx2_reg_wr_ind(bp, cpu_reg->mode, val);
Michael Chanaf3ee512006-11-19 14:09:25 -08003875
3876 return 0;
Michael Chanb6016b72005-05-26 13:03:09 -07003877}
3878
Michael Chanfba9fe92006-06-12 22:21:25 -07003879static int
Michael Chanb6016b72005-05-26 13:03:09 -07003880bnx2_init_cpus(struct bnx2 *bp)
3881{
Michael Chan57579f72009-04-04 16:51:14 -07003882 const struct bnx2_mips_fw_file *mips_fw =
3883 (const struct bnx2_mips_fw_file *) bp->mips_firmware->data;
3884 const struct bnx2_rv2p_fw_file *rv2p_fw =
3885 (const struct bnx2_rv2p_fw_file *) bp->rv2p_firmware->data;
3886 int rc;
Michael Chanb6016b72005-05-26 13:03:09 -07003887
3888 /* Initialize the RV2P processor. */
Michael Chan57579f72009-04-04 16:51:14 -07003889 load_rv2p_fw(bp, RV2P_PROC1, &rv2p_fw->proc1);
3890 load_rv2p_fw(bp, RV2P_PROC2, &rv2p_fw->proc2);
Michael Chanb6016b72005-05-26 13:03:09 -07003891
3892 /* Initialize the RX Processor. */
Michael Chan57579f72009-04-04 16:51:14 -07003893 rc = load_cpu_fw(bp, &cpu_reg_rxp, &mips_fw->rxp);
Michael Chanfba9fe92006-06-12 22:21:25 -07003894 if (rc)
3895 goto init_cpu_err;
3896
Michael Chanb6016b72005-05-26 13:03:09 -07003897 /* Initialize the TX Processor. */
Michael Chan57579f72009-04-04 16:51:14 -07003898 rc = load_cpu_fw(bp, &cpu_reg_txp, &mips_fw->txp);
Michael Chanfba9fe92006-06-12 22:21:25 -07003899 if (rc)
3900 goto init_cpu_err;
3901
Michael Chanb6016b72005-05-26 13:03:09 -07003902 /* Initialize the TX Patch-up Processor. */
Michael Chan57579f72009-04-04 16:51:14 -07003903 rc = load_cpu_fw(bp, &cpu_reg_tpat, &mips_fw->tpat);
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 Completion Processor. */
Michael Chan57579f72009-04-04 16:51:14 -07003908 rc = load_cpu_fw(bp, &cpu_reg_com, &mips_fw->com);
Michael Chanfba9fe92006-06-12 22:21:25 -07003909 if (rc)
3910 goto init_cpu_err;
3911
Michael Chand43584c2006-11-19 14:14:35 -08003912 /* Initialize the Command Processor. */
Michael Chan57579f72009-04-04 16:51:14 -07003913 rc = load_cpu_fw(bp, &cpu_reg_cp, &mips_fw->cp);
Michael Chan110d0ef2007-12-12 11:18:34 -08003914
Michael Chanfba9fe92006-06-12 22:21:25 -07003915init_cpu_err:
Michael Chanfba9fe92006-06-12 22:21:25 -07003916 return rc;
Michael Chanb6016b72005-05-26 13:03:09 -07003917}
3918
Michael Chanb6a23e92013-08-06 15:50:09 -07003919static void
3920bnx2_setup_wol(struct bnx2 *bp)
3921{
3922 int i;
3923 u32 val, wol_msg;
3924
3925 if (bp->wol) {
3926 u32 advertising;
3927 u8 autoneg;
3928
3929 autoneg = bp->autoneg;
3930 advertising = bp->advertising;
3931
3932 if (bp->phy_port == PORT_TP) {
3933 bp->autoneg = AUTONEG_SPEED;
3934 bp->advertising = ADVERTISED_10baseT_Half |
3935 ADVERTISED_10baseT_Full |
3936 ADVERTISED_100baseT_Half |
3937 ADVERTISED_100baseT_Full |
3938 ADVERTISED_Autoneg;
3939 }
3940
3941 spin_lock_bh(&bp->phy_lock);
3942 bnx2_setup_phy(bp, bp->phy_port);
3943 spin_unlock_bh(&bp->phy_lock);
3944
3945 bp->autoneg = autoneg;
3946 bp->advertising = advertising;
3947
3948 bnx2_set_mac_addr(bp, bp->dev->dev_addr, 0);
3949
3950 val = BNX2_RD(bp, BNX2_EMAC_MODE);
3951
3952 /* Enable port mode. */
3953 val &= ~BNX2_EMAC_MODE_PORT;
3954 val |= BNX2_EMAC_MODE_MPKT_RCVD |
3955 BNX2_EMAC_MODE_ACPI_RCVD |
3956 BNX2_EMAC_MODE_MPKT;
3957 if (bp->phy_port == PORT_TP) {
3958 val |= BNX2_EMAC_MODE_PORT_MII;
3959 } else {
3960 val |= BNX2_EMAC_MODE_PORT_GMII;
3961 if (bp->line_speed == SPEED_2500)
3962 val |= BNX2_EMAC_MODE_25G_MODE;
3963 }
3964
3965 BNX2_WR(bp, BNX2_EMAC_MODE, val);
3966
3967 /* receive all multicast */
3968 for (i = 0; i < NUM_MC_HASH_REGISTERS; i++) {
3969 BNX2_WR(bp, BNX2_EMAC_MULTICAST_HASH0 + (i * 4),
3970 0xffffffff);
3971 }
3972 BNX2_WR(bp, BNX2_EMAC_RX_MODE, BNX2_EMAC_RX_MODE_SORT_MODE);
3973
3974 val = 1 | BNX2_RPM_SORT_USER0_BC_EN | BNX2_RPM_SORT_USER0_MC_EN;
3975 BNX2_WR(bp, BNX2_RPM_SORT_USER0, 0x0);
3976 BNX2_WR(bp, BNX2_RPM_SORT_USER0, val);
3977 BNX2_WR(bp, BNX2_RPM_SORT_USER0, val | BNX2_RPM_SORT_USER0_ENA);
3978
3979 /* Need to enable EMAC and RPM for WOL. */
3980 BNX2_WR(bp, BNX2_MISC_ENABLE_SET_BITS,
3981 BNX2_MISC_ENABLE_SET_BITS_RX_PARSER_MAC_ENABLE |
3982 BNX2_MISC_ENABLE_SET_BITS_TX_HEADER_Q_ENABLE |
3983 BNX2_MISC_ENABLE_SET_BITS_EMAC_ENABLE);
3984
3985 val = BNX2_RD(bp, BNX2_RPM_CONFIG);
3986 val &= ~BNX2_RPM_CONFIG_ACPI_ENA;
3987 BNX2_WR(bp, BNX2_RPM_CONFIG, val);
3988
3989 wol_msg = BNX2_DRV_MSG_CODE_SUSPEND_WOL;
3990 } else {
3991 wol_msg = BNX2_DRV_MSG_CODE_SUSPEND_NO_WOL;
3992 }
3993
3994 if (!(bp->flags & BNX2_FLAG_NO_WOL))
3995 bnx2_fw_sync(bp, BNX2_DRV_MSG_DATA_WAIT3 | wol_msg, 1, 0);
3996
3997}
3998
Michael Chanb6016b72005-05-26 13:03:09 -07003999static int
Pavel Machek829ca9a2005-09-03 15:56:56 -07004000bnx2_set_power_state(struct bnx2 *bp, pci_power_t state)
Michael Chanb6016b72005-05-26 13:03:09 -07004001{
Michael Chanb6016b72005-05-26 13:03:09 -07004002 switch (state) {
Pavel Machek829ca9a2005-09-03 15:56:56 -07004003 case PCI_D0: {
Michael Chanb6016b72005-05-26 13:03:09 -07004004 u32 val;
4005
Michael Chan6d5e85c2013-08-06 15:50:08 -07004006 pci_enable_wake(bp->pdev, PCI_D0, false);
4007 pci_set_power_state(bp->pdev, PCI_D0);
Michael Chanb6016b72005-05-26 13:03:09 -07004008
Michael Chane503e062012-12-06 10:33:08 +00004009 val = BNX2_RD(bp, BNX2_EMAC_MODE);
Michael Chanb6016b72005-05-26 13:03:09 -07004010 val |= BNX2_EMAC_MODE_MPKT_RCVD | BNX2_EMAC_MODE_ACPI_RCVD;
4011 val &= ~BNX2_EMAC_MODE_MPKT;
Michael Chane503e062012-12-06 10:33:08 +00004012 BNX2_WR(bp, BNX2_EMAC_MODE, val);
Michael Chanb6016b72005-05-26 13:03:09 -07004013
Michael Chane503e062012-12-06 10:33:08 +00004014 val = BNX2_RD(bp, BNX2_RPM_CONFIG);
Michael Chanb6016b72005-05-26 13:03:09 -07004015 val &= ~BNX2_RPM_CONFIG_ACPI_ENA;
Michael Chane503e062012-12-06 10:33:08 +00004016 BNX2_WR(bp, BNX2_RPM_CONFIG, val);
Michael Chanb6016b72005-05-26 13:03:09 -07004017 break;
4018 }
Pavel Machek829ca9a2005-09-03 15:56:56 -07004019 case PCI_D3hot: {
Michael Chanb6a23e92013-08-06 15:50:09 -07004020 bnx2_setup_wol(bp);
Michael Chan6d5e85c2013-08-06 15:50:08 -07004021 pci_wake_from_d3(bp->pdev, bp->wol);
Michael Chan4ce45e02012-12-06 10:33:10 +00004022 if ((BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5706_A0) ||
4023 (BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5706_A1)) {
Michael Chanb6016b72005-05-26 13:03:09 -07004024
4025 if (bp->wol)
Michael Chan6d5e85c2013-08-06 15:50:08 -07004026 pci_set_power_state(bp->pdev, PCI_D3hot);
4027 } else {
4028 pci_set_power_state(bp->pdev, PCI_D3hot);
Michael Chanb6016b72005-05-26 13:03:09 -07004029 }
Michael Chanb6016b72005-05-26 13:03:09 -07004030
4031 /* No more memory access after this point until
4032 * device is brought back to D0.
4033 */
Michael Chanb6016b72005-05-26 13:03:09 -07004034 break;
4035 }
4036 default:
4037 return -EINVAL;
4038 }
4039 return 0;
4040}
4041
4042static int
4043bnx2_acquire_nvram_lock(struct bnx2 *bp)
4044{
4045 u32 val;
4046 int j;
4047
4048 /* Request access to the flash interface. */
Michael Chane503e062012-12-06 10:33:08 +00004049 BNX2_WR(bp, BNX2_NVM_SW_ARB, BNX2_NVM_SW_ARB_ARB_REQ_SET2);
Michael Chanb6016b72005-05-26 13:03:09 -07004050 for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) {
Michael Chane503e062012-12-06 10:33:08 +00004051 val = BNX2_RD(bp, BNX2_NVM_SW_ARB);
Michael Chanb6016b72005-05-26 13:03:09 -07004052 if (val & BNX2_NVM_SW_ARB_ARB_ARB2)
4053 break;
4054
4055 udelay(5);
4056 }
4057
4058 if (j >= NVRAM_TIMEOUT_COUNT)
4059 return -EBUSY;
4060
4061 return 0;
4062}
4063
4064static int
4065bnx2_release_nvram_lock(struct bnx2 *bp)
4066{
4067 int j;
4068 u32 val;
4069
4070 /* Relinquish nvram interface. */
Michael Chane503e062012-12-06 10:33:08 +00004071 BNX2_WR(bp, BNX2_NVM_SW_ARB, BNX2_NVM_SW_ARB_ARB_REQ_CLR2);
Michael Chanb6016b72005-05-26 13:03:09 -07004072
4073 for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) {
Michael Chane503e062012-12-06 10:33:08 +00004074 val = BNX2_RD(bp, BNX2_NVM_SW_ARB);
Michael Chanb6016b72005-05-26 13:03:09 -07004075 if (!(val & BNX2_NVM_SW_ARB_ARB_ARB2))
4076 break;
4077
4078 udelay(5);
4079 }
4080
4081 if (j >= NVRAM_TIMEOUT_COUNT)
4082 return -EBUSY;
4083
4084 return 0;
4085}
4086
4087
4088static int
4089bnx2_enable_nvram_write(struct bnx2 *bp)
4090{
4091 u32 val;
4092
Michael Chane503e062012-12-06 10:33:08 +00004093 val = BNX2_RD(bp, BNX2_MISC_CFG);
4094 BNX2_WR(bp, BNX2_MISC_CFG, val | BNX2_MISC_CFG_NVM_WR_EN_PCI);
Michael Chanb6016b72005-05-26 13:03:09 -07004095
Michael Chane30372c2007-07-16 18:26:23 -07004096 if (bp->flash_info->flags & BNX2_NV_WREN) {
Michael Chanb6016b72005-05-26 13:03:09 -07004097 int j;
4098
Michael Chane503e062012-12-06 10:33:08 +00004099 BNX2_WR(bp, BNX2_NVM_COMMAND, BNX2_NVM_COMMAND_DONE);
4100 BNX2_WR(bp, BNX2_NVM_COMMAND,
4101 BNX2_NVM_COMMAND_WREN | BNX2_NVM_COMMAND_DOIT);
Michael Chanb6016b72005-05-26 13:03:09 -07004102
4103 for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) {
4104 udelay(5);
4105
Michael Chane503e062012-12-06 10:33:08 +00004106 val = BNX2_RD(bp, BNX2_NVM_COMMAND);
Michael Chanb6016b72005-05-26 13:03:09 -07004107 if (val & BNX2_NVM_COMMAND_DONE)
4108 break;
4109 }
4110
4111 if (j >= NVRAM_TIMEOUT_COUNT)
4112 return -EBUSY;
4113 }
4114 return 0;
4115}
4116
4117static void
4118bnx2_disable_nvram_write(struct bnx2 *bp)
4119{
4120 u32 val;
4121
Michael Chane503e062012-12-06 10:33:08 +00004122 val = BNX2_RD(bp, BNX2_MISC_CFG);
4123 BNX2_WR(bp, BNX2_MISC_CFG, val & ~BNX2_MISC_CFG_NVM_WR_EN);
Michael Chanb6016b72005-05-26 13:03:09 -07004124}
4125
4126
4127static void
4128bnx2_enable_nvram_access(struct bnx2 *bp)
4129{
4130 u32 val;
4131
Michael Chane503e062012-12-06 10:33:08 +00004132 val = BNX2_RD(bp, BNX2_NVM_ACCESS_ENABLE);
Michael Chanb6016b72005-05-26 13:03:09 -07004133 /* Enable both bits, even on read. */
Michael Chane503e062012-12-06 10:33:08 +00004134 BNX2_WR(bp, BNX2_NVM_ACCESS_ENABLE,
4135 val | BNX2_NVM_ACCESS_ENABLE_EN | BNX2_NVM_ACCESS_ENABLE_WR_EN);
Michael Chanb6016b72005-05-26 13:03:09 -07004136}
4137
4138static void
4139bnx2_disable_nvram_access(struct bnx2 *bp)
4140{
4141 u32 val;
4142
Michael Chane503e062012-12-06 10:33:08 +00004143 val = BNX2_RD(bp, BNX2_NVM_ACCESS_ENABLE);
Michael Chanb6016b72005-05-26 13:03:09 -07004144 /* Disable both bits, even after read. */
Michael Chane503e062012-12-06 10:33:08 +00004145 BNX2_WR(bp, BNX2_NVM_ACCESS_ENABLE,
Michael Chanb6016b72005-05-26 13:03:09 -07004146 val & ~(BNX2_NVM_ACCESS_ENABLE_EN |
4147 BNX2_NVM_ACCESS_ENABLE_WR_EN));
4148}
4149
4150static int
4151bnx2_nvram_erase_page(struct bnx2 *bp, u32 offset)
4152{
4153 u32 cmd;
4154 int j;
4155
Michael Chane30372c2007-07-16 18:26:23 -07004156 if (bp->flash_info->flags & BNX2_NV_BUFFERED)
Michael Chanb6016b72005-05-26 13:03:09 -07004157 /* Buffered flash, no erase needed */
4158 return 0;
4159
4160 /* Build an erase command */
4161 cmd = BNX2_NVM_COMMAND_ERASE | BNX2_NVM_COMMAND_WR |
4162 BNX2_NVM_COMMAND_DOIT;
4163
4164 /* Need to clear DONE bit separately. */
Michael Chane503e062012-12-06 10:33:08 +00004165 BNX2_WR(bp, BNX2_NVM_COMMAND, BNX2_NVM_COMMAND_DONE);
Michael Chanb6016b72005-05-26 13:03:09 -07004166
4167 /* Address of the NVRAM to read from. */
Michael Chane503e062012-12-06 10:33:08 +00004168 BNX2_WR(bp, BNX2_NVM_ADDR, offset & BNX2_NVM_ADDR_NVM_ADDR_VALUE);
Michael Chanb6016b72005-05-26 13:03:09 -07004169
4170 /* Issue an erase command. */
Michael Chane503e062012-12-06 10:33:08 +00004171 BNX2_WR(bp, BNX2_NVM_COMMAND, cmd);
Michael Chanb6016b72005-05-26 13:03:09 -07004172
4173 /* Wait for completion. */
4174 for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) {
4175 u32 val;
4176
4177 udelay(5);
4178
Michael Chane503e062012-12-06 10:33:08 +00004179 val = BNX2_RD(bp, BNX2_NVM_COMMAND);
Michael Chanb6016b72005-05-26 13:03:09 -07004180 if (val & BNX2_NVM_COMMAND_DONE)
4181 break;
4182 }
4183
4184 if (j >= NVRAM_TIMEOUT_COUNT)
4185 return -EBUSY;
4186
4187 return 0;
4188}
4189
4190static int
4191bnx2_nvram_read_dword(struct bnx2 *bp, u32 offset, u8 *ret_val, u32 cmd_flags)
4192{
4193 u32 cmd;
4194 int j;
4195
4196 /* Build the command word. */
4197 cmd = BNX2_NVM_COMMAND_DOIT | cmd_flags;
4198
Michael Chane30372c2007-07-16 18:26:23 -07004199 /* Calculate an offset of a buffered flash, not needed for 5709. */
4200 if (bp->flash_info->flags & BNX2_NV_TRANSLATE) {
Michael Chanb6016b72005-05-26 13:03:09 -07004201 offset = ((offset / bp->flash_info->page_size) <<
4202 bp->flash_info->page_bits) +
4203 (offset % bp->flash_info->page_size);
4204 }
4205
4206 /* Need to clear DONE bit separately. */
Michael Chane503e062012-12-06 10:33:08 +00004207 BNX2_WR(bp, BNX2_NVM_COMMAND, BNX2_NVM_COMMAND_DONE);
Michael Chanb6016b72005-05-26 13:03:09 -07004208
4209 /* Address of the NVRAM to read from. */
Michael Chane503e062012-12-06 10:33:08 +00004210 BNX2_WR(bp, BNX2_NVM_ADDR, offset & BNX2_NVM_ADDR_NVM_ADDR_VALUE);
Michael Chanb6016b72005-05-26 13:03:09 -07004211
4212 /* Issue a read command. */
Michael Chane503e062012-12-06 10:33:08 +00004213 BNX2_WR(bp, BNX2_NVM_COMMAND, cmd);
Michael Chanb6016b72005-05-26 13:03:09 -07004214
4215 /* Wait for completion. */
4216 for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) {
4217 u32 val;
4218
4219 udelay(5);
4220
Michael Chane503e062012-12-06 10:33:08 +00004221 val = BNX2_RD(bp, BNX2_NVM_COMMAND);
Michael Chanb6016b72005-05-26 13:03:09 -07004222 if (val & BNX2_NVM_COMMAND_DONE) {
Michael Chane503e062012-12-06 10:33:08 +00004223 __be32 v = cpu_to_be32(BNX2_RD(bp, BNX2_NVM_READ));
Al Virob491edd2007-12-22 19:44:51 +00004224 memcpy(ret_val, &v, 4);
Michael Chanb6016b72005-05-26 13:03:09 -07004225 break;
4226 }
4227 }
4228 if (j >= NVRAM_TIMEOUT_COUNT)
4229 return -EBUSY;
4230
4231 return 0;
4232}
4233
4234
4235static int
4236bnx2_nvram_write_dword(struct bnx2 *bp, u32 offset, u8 *val, u32 cmd_flags)
4237{
Al Virob491edd2007-12-22 19:44:51 +00004238 u32 cmd;
4239 __be32 val32;
Michael Chanb6016b72005-05-26 13:03:09 -07004240 int j;
4241
4242 /* Build the command word. */
4243 cmd = BNX2_NVM_COMMAND_DOIT | BNX2_NVM_COMMAND_WR | cmd_flags;
4244
Michael Chane30372c2007-07-16 18:26:23 -07004245 /* Calculate an offset of a buffered flash, not needed for 5709. */
4246 if (bp->flash_info->flags & BNX2_NV_TRANSLATE) {
Michael Chanb6016b72005-05-26 13:03:09 -07004247 offset = ((offset / bp->flash_info->page_size) <<
4248 bp->flash_info->page_bits) +
4249 (offset % bp->flash_info->page_size);
4250 }
4251
4252 /* Need to clear DONE bit separately. */
Michael Chane503e062012-12-06 10:33:08 +00004253 BNX2_WR(bp, BNX2_NVM_COMMAND, BNX2_NVM_COMMAND_DONE);
Michael Chanb6016b72005-05-26 13:03:09 -07004254
4255 memcpy(&val32, val, 4);
Michael Chanb6016b72005-05-26 13:03:09 -07004256
4257 /* Write the data. */
Michael Chane503e062012-12-06 10:33:08 +00004258 BNX2_WR(bp, BNX2_NVM_WRITE, be32_to_cpu(val32));
Michael Chanb6016b72005-05-26 13:03:09 -07004259
4260 /* Address of the NVRAM to write to. */
Michael Chane503e062012-12-06 10:33:08 +00004261 BNX2_WR(bp, BNX2_NVM_ADDR, offset & BNX2_NVM_ADDR_NVM_ADDR_VALUE);
Michael Chanb6016b72005-05-26 13:03:09 -07004262
4263 /* Issue the write command. */
Michael Chane503e062012-12-06 10:33:08 +00004264 BNX2_WR(bp, BNX2_NVM_COMMAND, cmd);
Michael Chanb6016b72005-05-26 13:03:09 -07004265
4266 /* Wait for completion. */
4267 for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) {
4268 udelay(5);
4269
Michael Chane503e062012-12-06 10:33:08 +00004270 if (BNX2_RD(bp, BNX2_NVM_COMMAND) & BNX2_NVM_COMMAND_DONE)
Michael Chanb6016b72005-05-26 13:03:09 -07004271 break;
4272 }
4273 if (j >= NVRAM_TIMEOUT_COUNT)
4274 return -EBUSY;
4275
4276 return 0;
4277}
4278
4279static int
4280bnx2_init_nvram(struct bnx2 *bp)
4281{
4282 u32 val;
Michael Chane30372c2007-07-16 18:26:23 -07004283 int j, entry_count, rc = 0;
Michael Chan0ced9d02009-08-21 16:20:49 +00004284 const struct flash_spec *flash;
Michael Chanb6016b72005-05-26 13:03:09 -07004285
Michael Chan4ce45e02012-12-06 10:33:10 +00004286 if (BNX2_CHIP(bp) == BNX2_CHIP_5709) {
Michael Chane30372c2007-07-16 18:26:23 -07004287 bp->flash_info = &flash_5709;
4288 goto get_flash_size;
4289 }
4290
Michael Chanb6016b72005-05-26 13:03:09 -07004291 /* Determine the selected interface. */
Michael Chane503e062012-12-06 10:33:08 +00004292 val = BNX2_RD(bp, BNX2_NVM_CFG1);
Michael Chanb6016b72005-05-26 13:03:09 -07004293
Denis Chengff8ac602007-09-02 18:30:18 +08004294 entry_count = ARRAY_SIZE(flash_table);
Michael Chanb6016b72005-05-26 13:03:09 -07004295
Michael Chanb6016b72005-05-26 13:03:09 -07004296 if (val & 0x40000000) {
4297
4298 /* Flash interface has been reconfigured */
4299 for (j = 0, flash = &flash_table[0]; j < entry_count;
Michael Chan37137702005-11-04 08:49:17 -08004300 j++, flash++) {
4301 if ((val & FLASH_BACKUP_STRAP_MASK) ==
4302 (flash->config1 & FLASH_BACKUP_STRAP_MASK)) {
Michael Chanb6016b72005-05-26 13:03:09 -07004303 bp->flash_info = flash;
4304 break;
4305 }
4306 }
4307 }
4308 else {
Michael Chan37137702005-11-04 08:49:17 -08004309 u32 mask;
Michael Chanb6016b72005-05-26 13:03:09 -07004310 /* Not yet been reconfigured */
4311
Michael Chan37137702005-11-04 08:49:17 -08004312 if (val & (1 << 23))
4313 mask = FLASH_BACKUP_STRAP_MASK;
4314 else
4315 mask = FLASH_STRAP_MASK;
4316
Michael Chanb6016b72005-05-26 13:03:09 -07004317 for (j = 0, flash = &flash_table[0]; j < entry_count;
4318 j++, flash++) {
4319
Michael Chan37137702005-11-04 08:49:17 -08004320 if ((val & mask) == (flash->strapping & mask)) {
Michael Chanb6016b72005-05-26 13:03:09 -07004321 bp->flash_info = flash;
4322
4323 /* Request access to the flash interface. */
4324 if ((rc = bnx2_acquire_nvram_lock(bp)) != 0)
4325 return rc;
4326
4327 /* Enable access to flash interface */
4328 bnx2_enable_nvram_access(bp);
4329
4330 /* Reconfigure the flash interface */
Michael Chane503e062012-12-06 10:33:08 +00004331 BNX2_WR(bp, BNX2_NVM_CFG1, flash->config1);
4332 BNX2_WR(bp, BNX2_NVM_CFG2, flash->config2);
4333 BNX2_WR(bp, BNX2_NVM_CFG3, flash->config3);
4334 BNX2_WR(bp, BNX2_NVM_WRITE1, flash->write1);
Michael Chanb6016b72005-05-26 13:03:09 -07004335
4336 /* Disable access to flash interface */
4337 bnx2_disable_nvram_access(bp);
4338 bnx2_release_nvram_lock(bp);
4339
4340 break;
4341 }
4342 }
4343 } /* if (val & 0x40000000) */
4344
4345 if (j == entry_count) {
4346 bp->flash_info = NULL;
Joe Perches3a9c6a42010-02-17 15:01:51 +00004347 pr_alert("Unknown flash/EEPROM type\n");
Michael Chan1122db72006-01-23 16:11:42 -08004348 return -ENODEV;
Michael Chanb6016b72005-05-26 13:03:09 -07004349 }
4350
Michael Chane30372c2007-07-16 18:26:23 -07004351get_flash_size:
Michael Chan2726d6e2008-01-29 21:35:05 -08004352 val = bnx2_shmem_rd(bp, BNX2_SHARED_HW_CFG_CONFIG2);
Michael Chan1122db72006-01-23 16:11:42 -08004353 val &= BNX2_SHARED_HW_CFG2_NVM_SIZE_MASK;
4354 if (val)
4355 bp->flash_size = val;
4356 else
4357 bp->flash_size = bp->flash_info->total_size;
4358
Michael Chanb6016b72005-05-26 13:03:09 -07004359 return rc;
4360}
4361
4362static int
4363bnx2_nvram_read(struct bnx2 *bp, u32 offset, u8 *ret_buf,
4364 int buf_size)
4365{
4366 int rc = 0;
4367 u32 cmd_flags, offset32, len32, extra;
4368
4369 if (buf_size == 0)
4370 return 0;
4371
4372 /* Request access to the flash interface. */
4373 if ((rc = bnx2_acquire_nvram_lock(bp)) != 0)
4374 return rc;
4375
4376 /* Enable access to flash interface */
4377 bnx2_enable_nvram_access(bp);
4378
4379 len32 = buf_size;
4380 offset32 = offset;
4381 extra = 0;
4382
4383 cmd_flags = 0;
4384
4385 if (offset32 & 3) {
4386 u8 buf[4];
4387 u32 pre_len;
4388
4389 offset32 &= ~3;
4390 pre_len = 4 - (offset & 3);
4391
4392 if (pre_len >= len32) {
4393 pre_len = len32;
4394 cmd_flags = BNX2_NVM_COMMAND_FIRST |
4395 BNX2_NVM_COMMAND_LAST;
4396 }
4397 else {
4398 cmd_flags = BNX2_NVM_COMMAND_FIRST;
4399 }
4400
4401 rc = bnx2_nvram_read_dword(bp, offset32, buf, cmd_flags);
4402
4403 if (rc)
4404 return rc;
4405
4406 memcpy(ret_buf, buf + (offset & 3), pre_len);
4407
4408 offset32 += 4;
4409 ret_buf += pre_len;
4410 len32 -= pre_len;
4411 }
4412 if (len32 & 3) {
4413 extra = 4 - (len32 & 3);
4414 len32 = (len32 + 4) & ~3;
4415 }
4416
4417 if (len32 == 4) {
4418 u8 buf[4];
4419
4420 if (cmd_flags)
4421 cmd_flags = BNX2_NVM_COMMAND_LAST;
4422 else
4423 cmd_flags = BNX2_NVM_COMMAND_FIRST |
4424 BNX2_NVM_COMMAND_LAST;
4425
4426 rc = bnx2_nvram_read_dword(bp, offset32, buf, cmd_flags);
4427
4428 memcpy(ret_buf, buf, 4 - extra);
4429 }
4430 else if (len32 > 0) {
4431 u8 buf[4];
4432
4433 /* Read the first word. */
4434 if (cmd_flags)
4435 cmd_flags = 0;
4436 else
4437 cmd_flags = BNX2_NVM_COMMAND_FIRST;
4438
4439 rc = bnx2_nvram_read_dword(bp, offset32, ret_buf, cmd_flags);
4440
4441 /* Advance to the next dword. */
4442 offset32 += 4;
4443 ret_buf += 4;
4444 len32 -= 4;
4445
4446 while (len32 > 4 && rc == 0) {
4447 rc = bnx2_nvram_read_dword(bp, offset32, ret_buf, 0);
4448
4449 /* Advance to the next dword. */
4450 offset32 += 4;
4451 ret_buf += 4;
4452 len32 -= 4;
4453 }
4454
4455 if (rc)
4456 return rc;
4457
4458 cmd_flags = BNX2_NVM_COMMAND_LAST;
4459 rc = bnx2_nvram_read_dword(bp, offset32, buf, cmd_flags);
4460
4461 memcpy(ret_buf, buf, 4 - extra);
4462 }
4463
4464 /* Disable access to flash interface */
4465 bnx2_disable_nvram_access(bp);
4466
4467 bnx2_release_nvram_lock(bp);
4468
4469 return rc;
4470}
4471
4472static int
4473bnx2_nvram_write(struct bnx2 *bp, u32 offset, u8 *data_buf,
4474 int buf_size)
4475{
4476 u32 written, offset32, len32;
Michael Chane6be7632007-01-08 19:56:13 -08004477 u8 *buf, start[4], end[4], *align_buf = NULL, *flash_buffer = NULL;
Michael Chanb6016b72005-05-26 13:03:09 -07004478 int rc = 0;
4479 int align_start, align_end;
4480
4481 buf = data_buf;
4482 offset32 = offset;
4483 len32 = buf_size;
4484 align_start = align_end = 0;
4485
4486 if ((align_start = (offset32 & 3))) {
4487 offset32 &= ~3;
Michael Chanc8738792007-03-30 14:53:06 -07004488 len32 += align_start;
4489 if (len32 < 4)
4490 len32 = 4;
Michael Chanb6016b72005-05-26 13:03:09 -07004491 if ((rc = bnx2_nvram_read(bp, offset32, start, 4)))
4492 return rc;
4493 }
4494
4495 if (len32 & 3) {
Michael Chanc8738792007-03-30 14:53:06 -07004496 align_end = 4 - (len32 & 3);
4497 len32 += align_end;
4498 if ((rc = bnx2_nvram_read(bp, offset32 + len32 - 4, end, 4)))
4499 return rc;
Michael Chanb6016b72005-05-26 13:03:09 -07004500 }
4501
4502 if (align_start || align_end) {
Michael Chane6be7632007-01-08 19:56:13 -08004503 align_buf = kmalloc(len32, GFP_KERNEL);
4504 if (align_buf == NULL)
Michael Chanb6016b72005-05-26 13:03:09 -07004505 return -ENOMEM;
4506 if (align_start) {
Michael Chane6be7632007-01-08 19:56:13 -08004507 memcpy(align_buf, start, 4);
Michael Chanb6016b72005-05-26 13:03:09 -07004508 }
4509 if (align_end) {
Michael Chane6be7632007-01-08 19:56:13 -08004510 memcpy(align_buf + len32 - 4, end, 4);
Michael Chanb6016b72005-05-26 13:03:09 -07004511 }
Michael Chane6be7632007-01-08 19:56:13 -08004512 memcpy(align_buf + align_start, data_buf, buf_size);
4513 buf = align_buf;
Michael Chanb6016b72005-05-26 13:03:09 -07004514 }
4515
Michael Chane30372c2007-07-16 18:26:23 -07004516 if (!(bp->flash_info->flags & BNX2_NV_BUFFERED)) {
Michael Chanae181bc2006-05-22 16:39:20 -07004517 flash_buffer = kmalloc(264, GFP_KERNEL);
4518 if (flash_buffer == NULL) {
4519 rc = -ENOMEM;
4520 goto nvram_write_end;
4521 }
4522 }
4523
Michael Chanb6016b72005-05-26 13:03:09 -07004524 written = 0;
4525 while ((written < len32) && (rc == 0)) {
4526 u32 page_start, page_end, data_start, data_end;
4527 u32 addr, cmd_flags;
4528 int i;
Michael Chanb6016b72005-05-26 13:03:09 -07004529
4530 /* Find the page_start addr */
4531 page_start = offset32 + written;
4532 page_start -= (page_start % bp->flash_info->page_size);
4533 /* Find the page_end addr */
4534 page_end = page_start + bp->flash_info->page_size;
4535 /* Find the data_start addr */
4536 data_start = (written == 0) ? offset32 : page_start;
4537 /* Find the data_end addr */
Jeff Garzik6aa20a22006-09-13 13:24:59 -04004538 data_end = (page_end > offset32 + len32) ?
Michael Chanb6016b72005-05-26 13:03:09 -07004539 (offset32 + len32) : page_end;
4540
4541 /* Request access to the flash interface. */
4542 if ((rc = bnx2_acquire_nvram_lock(bp)) != 0)
4543 goto nvram_write_end;
4544
4545 /* Enable access to flash interface */
4546 bnx2_enable_nvram_access(bp);
4547
4548 cmd_flags = BNX2_NVM_COMMAND_FIRST;
Michael Chane30372c2007-07-16 18:26:23 -07004549 if (!(bp->flash_info->flags & BNX2_NV_BUFFERED)) {
Michael Chanb6016b72005-05-26 13:03:09 -07004550 int j;
4551
4552 /* Read the whole page into the buffer
4553 * (non-buffer flash only) */
4554 for (j = 0; j < bp->flash_info->page_size; j += 4) {
4555 if (j == (bp->flash_info->page_size - 4)) {
4556 cmd_flags |= BNX2_NVM_COMMAND_LAST;
4557 }
4558 rc = bnx2_nvram_read_dword(bp,
Jeff Garzik6aa20a22006-09-13 13:24:59 -04004559 page_start + j,
4560 &flash_buffer[j],
Michael Chanb6016b72005-05-26 13:03:09 -07004561 cmd_flags);
4562
4563 if (rc)
4564 goto nvram_write_end;
4565
4566 cmd_flags = 0;
4567 }
4568 }
4569
4570 /* Enable writes to flash interface (unlock write-protect) */
4571 if ((rc = bnx2_enable_nvram_write(bp)) != 0)
4572 goto nvram_write_end;
4573
Michael Chanb6016b72005-05-26 13:03:09 -07004574 /* Loop to write back the buffer data from page_start to
4575 * data_start */
4576 i = 0;
Michael Chane30372c2007-07-16 18:26:23 -07004577 if (!(bp->flash_info->flags & BNX2_NV_BUFFERED)) {
Michael Chanc8738792007-03-30 14:53:06 -07004578 /* Erase the page */
4579 if ((rc = bnx2_nvram_erase_page(bp, page_start)) != 0)
4580 goto nvram_write_end;
4581
4582 /* Re-enable the write again for the actual write */
4583 bnx2_enable_nvram_write(bp);
4584
Michael Chanb6016b72005-05-26 13:03:09 -07004585 for (addr = page_start; addr < data_start;
4586 addr += 4, i += 4) {
Jeff Garzik6aa20a22006-09-13 13:24:59 -04004587
Michael Chanb6016b72005-05-26 13:03:09 -07004588 rc = bnx2_nvram_write_dword(bp, addr,
4589 &flash_buffer[i], cmd_flags);
4590
4591 if (rc != 0)
4592 goto nvram_write_end;
4593
4594 cmd_flags = 0;
4595 }
4596 }
4597
4598 /* Loop to write the new data from data_start to data_end */
Michael Chanbae25762006-05-22 16:38:38 -07004599 for (addr = data_start; addr < data_end; addr += 4, i += 4) {
Michael Chanb6016b72005-05-26 13:03:09 -07004600 if ((addr == page_end - 4) ||
Michael Chane30372c2007-07-16 18:26:23 -07004601 ((bp->flash_info->flags & BNX2_NV_BUFFERED) &&
Michael Chanb6016b72005-05-26 13:03:09 -07004602 (addr == data_end - 4))) {
4603
4604 cmd_flags |= BNX2_NVM_COMMAND_LAST;
4605 }
4606 rc = bnx2_nvram_write_dword(bp, addr, buf,
4607 cmd_flags);
4608
4609 if (rc != 0)
4610 goto nvram_write_end;
4611
4612 cmd_flags = 0;
4613 buf += 4;
4614 }
4615
4616 /* Loop to write back the buffer data from data_end
4617 * to page_end */
Michael Chane30372c2007-07-16 18:26:23 -07004618 if (!(bp->flash_info->flags & BNX2_NV_BUFFERED)) {
Michael Chanb6016b72005-05-26 13:03:09 -07004619 for (addr = data_end; addr < page_end;
4620 addr += 4, i += 4) {
Jeff Garzik6aa20a22006-09-13 13:24:59 -04004621
Michael Chanb6016b72005-05-26 13:03:09 -07004622 if (addr == page_end-4) {
4623 cmd_flags = BNX2_NVM_COMMAND_LAST;
4624 }
4625 rc = bnx2_nvram_write_dword(bp, addr,
4626 &flash_buffer[i], cmd_flags);
4627
4628 if (rc != 0)
4629 goto nvram_write_end;
4630
4631 cmd_flags = 0;
4632 }
4633 }
4634
4635 /* Disable writes to flash interface (lock write-protect) */
4636 bnx2_disable_nvram_write(bp);
4637
4638 /* Disable access to flash interface */
4639 bnx2_disable_nvram_access(bp);
4640 bnx2_release_nvram_lock(bp);
4641
4642 /* Increment written */
4643 written += data_end - data_start;
4644 }
4645
4646nvram_write_end:
Michael Chane6be7632007-01-08 19:56:13 -08004647 kfree(flash_buffer);
4648 kfree(align_buf);
Michael Chanb6016b72005-05-26 13:03:09 -07004649 return rc;
4650}
4651
Michael Chan0d8a6572007-07-07 22:49:43 -07004652static void
Michael Chan7c62e832008-07-14 22:39:03 -07004653bnx2_init_fw_cap(struct bnx2 *bp)
Michael Chan0d8a6572007-07-07 22:49:43 -07004654{
Michael Chan7c62e832008-07-14 22:39:03 -07004655 u32 val, sig = 0;
Michael Chan0d8a6572007-07-07 22:49:43 -07004656
Michael Chan583c28e2008-01-21 19:51:35 -08004657 bp->phy_flags &= ~BNX2_PHY_FLAG_REMOTE_PHY_CAP;
Michael Chan7c62e832008-07-14 22:39:03 -07004658 bp->flags &= ~BNX2_FLAG_CAN_KEEP_VLAN;
4659
4660 if (!(bp->flags & BNX2_FLAG_ASF_ENABLE))
4661 bp->flags |= BNX2_FLAG_CAN_KEEP_VLAN;
Michael Chan0d8a6572007-07-07 22:49:43 -07004662
Michael Chan2726d6e2008-01-29 21:35:05 -08004663 val = bnx2_shmem_rd(bp, BNX2_FW_CAP_MB);
Michael Chan0d8a6572007-07-07 22:49:43 -07004664 if ((val & BNX2_FW_CAP_SIGNATURE_MASK) != BNX2_FW_CAP_SIGNATURE)
4665 return;
4666
Michael Chan7c62e832008-07-14 22:39:03 -07004667 if ((val & BNX2_FW_CAP_CAN_KEEP_VLAN) == BNX2_FW_CAP_CAN_KEEP_VLAN) {
4668 bp->flags |= BNX2_FLAG_CAN_KEEP_VLAN;
4669 sig |= BNX2_DRV_ACK_CAP_SIGNATURE | BNX2_FW_CAP_CAN_KEEP_VLAN;
4670 }
4671
4672 if ((bp->phy_flags & BNX2_PHY_FLAG_SERDES) &&
4673 (val & BNX2_FW_CAP_REMOTE_PHY_CAPABLE)) {
4674 u32 link;
4675
Michael Chan583c28e2008-01-21 19:51:35 -08004676 bp->phy_flags |= BNX2_PHY_FLAG_REMOTE_PHY_CAP;
Michael Chan0d8a6572007-07-07 22:49:43 -07004677
Michael Chan7c62e832008-07-14 22:39:03 -07004678 link = bnx2_shmem_rd(bp, BNX2_LINK_STATUS);
4679 if (link & BNX2_LINK_STATUS_SERDES_LINK)
Michael Chan0d8a6572007-07-07 22:49:43 -07004680 bp->phy_port = PORT_FIBRE;
4681 else
4682 bp->phy_port = PORT_TP;
Michael Chan489310a2007-10-10 16:16:31 -07004683
Michael Chan7c62e832008-07-14 22:39:03 -07004684 sig |= BNX2_DRV_ACK_CAP_SIGNATURE |
4685 BNX2_FW_CAP_REMOTE_PHY_CAPABLE;
Michael Chan0d8a6572007-07-07 22:49:43 -07004686 }
Michael Chan7c62e832008-07-14 22:39:03 -07004687
4688 if (netif_running(bp->dev) && sig)
4689 bnx2_shmem_wr(bp, BNX2_DRV_ACK_CAP_MB, sig);
Michael Chan0d8a6572007-07-07 22:49:43 -07004690}
4691
Michael Chanb4b36042007-12-20 19:59:30 -08004692static void
4693bnx2_setup_msix_tbl(struct bnx2 *bp)
4694{
Michael Chane503e062012-12-06 10:33:08 +00004695 BNX2_WR(bp, BNX2_PCI_GRC_WINDOW_ADDR, BNX2_PCI_GRC_WINDOW_ADDR_SEP_WIN);
Michael Chanb4b36042007-12-20 19:59:30 -08004696
Michael Chane503e062012-12-06 10:33:08 +00004697 BNX2_WR(bp, BNX2_PCI_GRC_WINDOW2_ADDR, BNX2_MSIX_TABLE_ADDR);
4698 BNX2_WR(bp, BNX2_PCI_GRC_WINDOW3_ADDR, BNX2_MSIX_PBA_ADDR);
Michael Chanb4b36042007-12-20 19:59:30 -08004699}
4700
Michael Chanb6016b72005-05-26 13:03:09 -07004701static int
4702bnx2_reset_chip(struct bnx2 *bp, u32 reset_code)
4703{
4704 u32 val;
4705 int i, rc = 0;
Michael Chan489310a2007-10-10 16:16:31 -07004706 u8 old_port;
Michael Chanb6016b72005-05-26 13:03:09 -07004707
4708 /* Wait for the current PCI transaction to complete before
4709 * issuing a reset. */
Michael Chan4ce45e02012-12-06 10:33:10 +00004710 if ((BNX2_CHIP(bp) == BNX2_CHIP_5706) ||
4711 (BNX2_CHIP(bp) == BNX2_CHIP_5708)) {
Michael Chane503e062012-12-06 10:33:08 +00004712 BNX2_WR(bp, BNX2_MISC_ENABLE_CLR_BITS,
4713 BNX2_MISC_ENABLE_CLR_BITS_TX_DMA_ENABLE |
4714 BNX2_MISC_ENABLE_CLR_BITS_DMA_ENGINE_ENABLE |
4715 BNX2_MISC_ENABLE_CLR_BITS_RX_DMA_ENABLE |
4716 BNX2_MISC_ENABLE_CLR_BITS_HOST_COALESCE_ENABLE);
4717 val = BNX2_RD(bp, BNX2_MISC_ENABLE_CLR_BITS);
Eddie Waia5dac102010-11-24 13:48:54 +00004718 udelay(5);
4719 } else { /* 5709 */
Michael Chane503e062012-12-06 10:33:08 +00004720 val = BNX2_RD(bp, BNX2_MISC_NEW_CORE_CTL);
Eddie Waia5dac102010-11-24 13:48:54 +00004721 val &= ~BNX2_MISC_NEW_CORE_CTL_DMA_ENABLE;
Michael Chane503e062012-12-06 10:33:08 +00004722 BNX2_WR(bp, BNX2_MISC_NEW_CORE_CTL, val);
4723 val = BNX2_RD(bp, BNX2_MISC_NEW_CORE_CTL);
Eddie Waia5dac102010-11-24 13:48:54 +00004724
4725 for (i = 0; i < 100; i++) {
4726 msleep(1);
Michael Chane503e062012-12-06 10:33:08 +00004727 val = BNX2_RD(bp, BNX2_PCICFG_DEVICE_CONTROL);
Eddie Waia5dac102010-11-24 13:48:54 +00004728 if (!(val & BNX2_PCICFG_DEVICE_STATUS_NO_PEND))
4729 break;
4730 }
4731 }
Michael Chanb6016b72005-05-26 13:03:09 -07004732
Michael Chanb090ae22006-01-23 16:07:10 -08004733 /* Wait for the firmware to tell us it is ok to issue a reset. */
Michael Chana2f13892008-07-14 22:38:23 -07004734 bnx2_fw_sync(bp, BNX2_DRV_MSG_DATA_WAIT0 | reset_code, 1, 1);
Michael Chanb090ae22006-01-23 16:07:10 -08004735
Michael Chanb6016b72005-05-26 13:03:09 -07004736 /* Deposit a driver reset signature so the firmware knows that
4737 * this is a soft reset. */
Michael Chan2726d6e2008-01-29 21:35:05 -08004738 bnx2_shmem_wr(bp, BNX2_DRV_RESET_SIGNATURE,
4739 BNX2_DRV_RESET_SIGNATURE_MAGIC);
Michael Chanb6016b72005-05-26 13:03:09 -07004740
Michael Chanb6016b72005-05-26 13:03:09 -07004741 /* Do a dummy read to force the chip to complete all current transaction
4742 * before we issue a reset. */
Michael Chane503e062012-12-06 10:33:08 +00004743 val = BNX2_RD(bp, BNX2_MISC_ID);
Michael Chanb6016b72005-05-26 13:03:09 -07004744
Michael Chan4ce45e02012-12-06 10:33:10 +00004745 if (BNX2_CHIP(bp) == BNX2_CHIP_5709) {
Michael Chane503e062012-12-06 10:33:08 +00004746 BNX2_WR(bp, BNX2_MISC_COMMAND, BNX2_MISC_COMMAND_SW_RESET);
4747 BNX2_RD(bp, BNX2_MISC_COMMAND);
Michael Chan234754d2006-11-19 14:11:41 -08004748 udelay(5);
Michael Chanb6016b72005-05-26 13:03:09 -07004749
Michael Chan234754d2006-11-19 14:11:41 -08004750 val = BNX2_PCICFG_MISC_CONFIG_REG_WINDOW_ENA |
4751 BNX2_PCICFG_MISC_CONFIG_TARGET_MB_WORD_SWAP;
Michael Chanb6016b72005-05-26 13:03:09 -07004752
Michael Chane503e062012-12-06 10:33:08 +00004753 BNX2_WR(bp, BNX2_PCICFG_MISC_CONFIG, val);
Michael Chanb6016b72005-05-26 13:03:09 -07004754
Michael Chan234754d2006-11-19 14:11:41 -08004755 } else {
4756 val = BNX2_PCICFG_MISC_CONFIG_CORE_RST_REQ |
4757 BNX2_PCICFG_MISC_CONFIG_REG_WINDOW_ENA |
4758 BNX2_PCICFG_MISC_CONFIG_TARGET_MB_WORD_SWAP;
4759
4760 /* Chip reset. */
Michael Chane503e062012-12-06 10:33:08 +00004761 BNX2_WR(bp, BNX2_PCICFG_MISC_CONFIG, val);
Michael Chan234754d2006-11-19 14:11:41 -08004762
Michael Chan594a9df2007-08-28 15:39:42 -07004763 /* Reading back any register after chip reset will hang the
4764 * bus on 5706 A0 and A1. The msleep below provides plenty
4765 * of margin for write posting.
4766 */
Michael Chan4ce45e02012-12-06 10:33:10 +00004767 if ((BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5706_A0) ||
4768 (BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5706_A1))
Arjan van de Ven8e545882007-08-28 14:34:43 -07004769 msleep(20);
Michael Chanb6016b72005-05-26 13:03:09 -07004770
Michael Chan234754d2006-11-19 14:11:41 -08004771 /* Reset takes approximate 30 usec */
4772 for (i = 0; i < 10; i++) {
Michael Chane503e062012-12-06 10:33:08 +00004773 val = BNX2_RD(bp, BNX2_PCICFG_MISC_CONFIG);
Michael Chan234754d2006-11-19 14:11:41 -08004774 if ((val & (BNX2_PCICFG_MISC_CONFIG_CORE_RST_REQ |
4775 BNX2_PCICFG_MISC_CONFIG_CORE_RST_BSY)) == 0)
4776 break;
4777 udelay(10);
4778 }
4779
4780 if (val & (BNX2_PCICFG_MISC_CONFIG_CORE_RST_REQ |
4781 BNX2_PCICFG_MISC_CONFIG_CORE_RST_BSY)) {
Joe Perches3a9c6a42010-02-17 15:01:51 +00004782 pr_err("Chip reset did not complete\n");
Michael Chan234754d2006-11-19 14:11:41 -08004783 return -EBUSY;
4784 }
Michael Chanb6016b72005-05-26 13:03:09 -07004785 }
4786
4787 /* Make sure byte swapping is properly configured. */
Michael Chane503e062012-12-06 10:33:08 +00004788 val = BNX2_RD(bp, BNX2_PCI_SWAP_DIAG0);
Michael Chanb6016b72005-05-26 13:03:09 -07004789 if (val != 0x01020304) {
Joe Perches3a9c6a42010-02-17 15:01:51 +00004790 pr_err("Chip not in correct endian mode\n");
Michael Chanb6016b72005-05-26 13:03:09 -07004791 return -ENODEV;
4792 }
4793
Michael Chanb6016b72005-05-26 13:03:09 -07004794 /* Wait for the firmware to finish its initialization. */
Michael Chana2f13892008-07-14 22:38:23 -07004795 rc = bnx2_fw_sync(bp, BNX2_DRV_MSG_DATA_WAIT1 | reset_code, 1, 0);
Michael Chanb090ae22006-01-23 16:07:10 -08004796 if (rc)
4797 return rc;
Michael Chanb6016b72005-05-26 13:03:09 -07004798
Michael Chan0d8a6572007-07-07 22:49:43 -07004799 spin_lock_bh(&bp->phy_lock);
Michael Chan489310a2007-10-10 16:16:31 -07004800 old_port = bp->phy_port;
Michael Chan7c62e832008-07-14 22:39:03 -07004801 bnx2_init_fw_cap(bp);
Michael Chan583c28e2008-01-21 19:51:35 -08004802 if ((bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP) &&
4803 old_port != bp->phy_port)
Michael Chan0d8a6572007-07-07 22:49:43 -07004804 bnx2_set_default_remote_link(bp);
4805 spin_unlock_bh(&bp->phy_lock);
4806
Michael Chan4ce45e02012-12-06 10:33:10 +00004807 if (BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5706_A0) {
Michael Chanb6016b72005-05-26 13:03:09 -07004808 /* Adjust the voltage regular to two steps lower. The default
4809 * of this register is 0x0000000e. */
Michael Chane503e062012-12-06 10:33:08 +00004810 BNX2_WR(bp, BNX2_MISC_VREG_CONTROL, 0x000000fa);
Michael Chanb6016b72005-05-26 13:03:09 -07004811
4812 /* Remove bad rbuf memory from the free pool. */
4813 rc = bnx2_alloc_bad_rbuf(bp);
4814 }
4815
Michael Chanc441b8d2010-04-27 11:28:09 +00004816 if (bp->flags & BNX2_FLAG_USING_MSIX) {
Michael Chanb4b36042007-12-20 19:59:30 -08004817 bnx2_setup_msix_tbl(bp);
Michael Chanc441b8d2010-04-27 11:28:09 +00004818 /* Prevent MSIX table reads and write from timing out */
Michael Chane503e062012-12-06 10:33:08 +00004819 BNX2_WR(bp, BNX2_MISC_ECO_HW_CTL,
Michael Chanc441b8d2010-04-27 11:28:09 +00004820 BNX2_MISC_ECO_HW_CTL_LARGE_GRC_TMOUT_EN);
4821 }
Michael Chanb4b36042007-12-20 19:59:30 -08004822
Michael Chanb6016b72005-05-26 13:03:09 -07004823 return rc;
4824}
4825
4826static int
4827bnx2_init_chip(struct bnx2 *bp)
4828{
Michael Chand8026d92008-11-12 16:02:20 -08004829 u32 val, mtu;
Michael Chanb4b36042007-12-20 19:59:30 -08004830 int rc, i;
Michael Chanb6016b72005-05-26 13:03:09 -07004831
4832 /* Make sure the interrupt is not active. */
Michael Chane503e062012-12-06 10:33:08 +00004833 BNX2_WR(bp, BNX2_PCICFG_INT_ACK_CMD, BNX2_PCICFG_INT_ACK_CMD_MASK_INT);
Michael Chanb6016b72005-05-26 13:03:09 -07004834
4835 val = BNX2_DMA_CONFIG_DATA_BYTE_SWAP |
4836 BNX2_DMA_CONFIG_DATA_WORD_SWAP |
4837#ifdef __BIG_ENDIAN
Jeff Garzik6aa20a22006-09-13 13:24:59 -04004838 BNX2_DMA_CONFIG_CNTL_BYTE_SWAP |
Michael Chanb6016b72005-05-26 13:03:09 -07004839#endif
Jeff Garzik6aa20a22006-09-13 13:24:59 -04004840 BNX2_DMA_CONFIG_CNTL_WORD_SWAP |
Michael Chanb6016b72005-05-26 13:03:09 -07004841 DMA_READ_CHANS << 12 |
4842 DMA_WRITE_CHANS << 16;
4843
4844 val |= (0x2 << 20) | (1 << 11);
4845
David S. Millerf86e82f2008-01-21 17:15:40 -08004846 if ((bp->flags & BNX2_FLAG_PCIX) && (bp->bus_speed_mhz == 133))
Michael Chanb6016b72005-05-26 13:03:09 -07004847 val |= (1 << 23);
4848
Michael Chan4ce45e02012-12-06 10:33:10 +00004849 if ((BNX2_CHIP(bp) == BNX2_CHIP_5706) &&
4850 (BNX2_CHIP_ID(bp) != BNX2_CHIP_ID_5706_A0) &&
4851 !(bp->flags & BNX2_FLAG_PCIX))
Michael Chanb6016b72005-05-26 13:03:09 -07004852 val |= BNX2_DMA_CONFIG_CNTL_PING_PONG_DMA;
4853
Michael Chane503e062012-12-06 10:33:08 +00004854 BNX2_WR(bp, BNX2_DMA_CONFIG, val);
Michael Chanb6016b72005-05-26 13:03:09 -07004855
Michael Chan4ce45e02012-12-06 10:33:10 +00004856 if (BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5706_A0) {
Michael Chane503e062012-12-06 10:33:08 +00004857 val = BNX2_RD(bp, BNX2_TDMA_CONFIG);
Michael Chanb6016b72005-05-26 13:03:09 -07004858 val |= BNX2_TDMA_CONFIG_ONE_DMA;
Michael Chane503e062012-12-06 10:33:08 +00004859 BNX2_WR(bp, BNX2_TDMA_CONFIG, val);
Michael Chanb6016b72005-05-26 13:03:09 -07004860 }
4861
David S. Millerf86e82f2008-01-21 17:15:40 -08004862 if (bp->flags & BNX2_FLAG_PCIX) {
Michael Chanb6016b72005-05-26 13:03:09 -07004863 u16 val16;
4864
4865 pci_read_config_word(bp->pdev, bp->pcix_cap + PCI_X_CMD,
4866 &val16);
4867 pci_write_config_word(bp->pdev, bp->pcix_cap + PCI_X_CMD,
4868 val16 & ~PCI_X_CMD_ERO);
4869 }
4870
Michael Chane503e062012-12-06 10:33:08 +00004871 BNX2_WR(bp, BNX2_MISC_ENABLE_SET_BITS,
4872 BNX2_MISC_ENABLE_SET_BITS_HOST_COALESCE_ENABLE |
4873 BNX2_MISC_ENABLE_STATUS_BITS_RX_V2P_ENABLE |
4874 BNX2_MISC_ENABLE_STATUS_BITS_CONTEXT_ENABLE);
Michael Chanb6016b72005-05-26 13:03:09 -07004875
4876 /* Initialize context mapping and zero out the quick contexts. The
4877 * context block must have already been enabled. */
Michael Chan4ce45e02012-12-06 10:33:10 +00004878 if (BNX2_CHIP(bp) == BNX2_CHIP_5709) {
Michael Chan641bdcd2007-06-04 21:22:24 -07004879 rc = bnx2_init_5709_context(bp);
4880 if (rc)
4881 return rc;
4882 } else
Michael Chan59b47d82006-11-19 14:10:45 -08004883 bnx2_init_context(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07004884
Michael Chanfba9fe92006-06-12 22:21:25 -07004885 if ((rc = bnx2_init_cpus(bp)) != 0)
4886 return rc;
4887
Michael Chanb6016b72005-05-26 13:03:09 -07004888 bnx2_init_nvram(bp);
4889
Benjamin Li5fcaed02008-07-14 22:39:52 -07004890 bnx2_set_mac_addr(bp, bp->dev->dev_addr, 0);
Michael Chanb6016b72005-05-26 13:03:09 -07004891
Michael Chane503e062012-12-06 10:33:08 +00004892 val = BNX2_RD(bp, BNX2_MQ_CONFIG);
Michael Chanb6016b72005-05-26 13:03:09 -07004893 val &= ~BNX2_MQ_CONFIG_KNL_BYP_BLK_SIZE;
4894 val |= BNX2_MQ_CONFIG_KNL_BYP_BLK_SIZE_256;
Michael Chan4ce45e02012-12-06 10:33:10 +00004895 if (BNX2_CHIP(bp) == BNX2_CHIP_5709) {
Michael Chan4edd4732009-06-08 18:14:42 -07004896 val |= BNX2_MQ_CONFIG_BIN_MQ_MODE;
Michael Chan4ce45e02012-12-06 10:33:10 +00004897 if (BNX2_CHIP_REV(bp) == BNX2_CHIP_REV_Ax)
Michael Chan4edd4732009-06-08 18:14:42 -07004898 val |= BNX2_MQ_CONFIG_HALT_DIS;
4899 }
Michael Chan68c9f752007-04-24 15:35:53 -07004900
Michael Chane503e062012-12-06 10:33:08 +00004901 BNX2_WR(bp, BNX2_MQ_CONFIG, val);
Michael Chanb6016b72005-05-26 13:03:09 -07004902
4903 val = 0x10000 + (MAX_CID_CNT * MB_KERNEL_CTX_SIZE);
Michael Chane503e062012-12-06 10:33:08 +00004904 BNX2_WR(bp, BNX2_MQ_KNL_BYP_WIND_START, val);
4905 BNX2_WR(bp, BNX2_MQ_KNL_WIND_END, val);
Michael Chanb6016b72005-05-26 13:03:09 -07004906
Michael Chan2bc40782012-12-06 10:33:09 +00004907 val = (BNX2_PAGE_BITS - 8) << 24;
Michael Chane503e062012-12-06 10:33:08 +00004908 BNX2_WR(bp, BNX2_RV2P_CONFIG, val);
Michael Chanb6016b72005-05-26 13:03:09 -07004909
4910 /* Configure page size. */
Michael Chane503e062012-12-06 10:33:08 +00004911 val = BNX2_RD(bp, BNX2_TBDR_CONFIG);
Michael Chanb6016b72005-05-26 13:03:09 -07004912 val &= ~BNX2_TBDR_CONFIG_PAGE_SIZE;
Michael Chan2bc40782012-12-06 10:33:09 +00004913 val |= (BNX2_PAGE_BITS - 8) << 24 | 0x40;
Michael Chane503e062012-12-06 10:33:08 +00004914 BNX2_WR(bp, BNX2_TBDR_CONFIG, val);
Michael Chanb6016b72005-05-26 13:03:09 -07004915
4916 val = bp->mac_addr[0] +
4917 (bp->mac_addr[1] << 8) +
4918 (bp->mac_addr[2] << 16) +
4919 bp->mac_addr[3] +
4920 (bp->mac_addr[4] << 8) +
4921 (bp->mac_addr[5] << 16);
Michael Chane503e062012-12-06 10:33:08 +00004922 BNX2_WR(bp, BNX2_EMAC_BACKOFF_SEED, val);
Michael Chanb6016b72005-05-26 13:03:09 -07004923
4924 /* Program the MTU. Also include 4 bytes for CRC32. */
Michael Chand8026d92008-11-12 16:02:20 -08004925 mtu = bp->dev->mtu;
4926 val = mtu + ETH_HLEN + ETH_FCS_LEN;
Michael Chanb6016b72005-05-26 13:03:09 -07004927 if (val > (MAX_ETHERNET_PACKET_SIZE + 4))
4928 val |= BNX2_EMAC_RX_MTU_SIZE_JUMBO_ENA;
Michael Chane503e062012-12-06 10:33:08 +00004929 BNX2_WR(bp, BNX2_EMAC_RX_MTU_SIZE, val);
Michael Chanb6016b72005-05-26 13:03:09 -07004930
Michael Chand8026d92008-11-12 16:02:20 -08004931 if (mtu < 1500)
4932 mtu = 1500;
4933
4934 bnx2_reg_wr_ind(bp, BNX2_RBUF_CONFIG, BNX2_RBUF_CONFIG_VAL(mtu));
4935 bnx2_reg_wr_ind(bp, BNX2_RBUF_CONFIG2, BNX2_RBUF_CONFIG2_VAL(mtu));
4936 bnx2_reg_wr_ind(bp, BNX2_RBUF_CONFIG3, BNX2_RBUF_CONFIG3_VAL(mtu));
4937
Michael Chan155d5562009-08-21 16:20:43 +00004938 memset(bp->bnx2_napi[0].status_blk.msi, 0, bp->status_stats_size);
Michael Chanb4b36042007-12-20 19:59:30 -08004939 for (i = 0; i < BNX2_MAX_MSIX_VEC; i++)
4940 bp->bnx2_napi[i].last_status_idx = 0;
4941
Michael Chanefba0182008-12-03 00:36:15 -08004942 bp->idle_chk_status_idx = 0xffff;
4943
Michael Chanb6016b72005-05-26 13:03:09 -07004944 bp->rx_mode = BNX2_EMAC_RX_MODE_SORT_MODE;
4945
4946 /* Set up how to generate a link change interrupt. */
Michael Chane503e062012-12-06 10:33:08 +00004947 BNX2_WR(bp, BNX2_EMAC_ATTENTION_ENA, BNX2_EMAC_ATTENTION_ENA_LINK);
Michael Chanb6016b72005-05-26 13:03:09 -07004948
Michael Chane503e062012-12-06 10:33:08 +00004949 BNX2_WR(bp, BNX2_HC_STATUS_ADDR_L,
4950 (u64) bp->status_blk_mapping & 0xffffffff);
4951 BNX2_WR(bp, BNX2_HC_STATUS_ADDR_H, (u64) bp->status_blk_mapping >> 32);
Michael Chanb6016b72005-05-26 13:03:09 -07004952
Michael Chane503e062012-12-06 10:33:08 +00004953 BNX2_WR(bp, BNX2_HC_STATISTICS_ADDR_L,
4954 (u64) bp->stats_blk_mapping & 0xffffffff);
4955 BNX2_WR(bp, BNX2_HC_STATISTICS_ADDR_H,
4956 (u64) bp->stats_blk_mapping >> 32);
Michael Chanb6016b72005-05-26 13:03:09 -07004957
Michael Chane503e062012-12-06 10:33:08 +00004958 BNX2_WR(bp, BNX2_HC_TX_QUICK_CONS_TRIP,
4959 (bp->tx_quick_cons_trip_int << 16) | bp->tx_quick_cons_trip);
Michael Chanb6016b72005-05-26 13:03:09 -07004960
Michael Chane503e062012-12-06 10:33:08 +00004961 BNX2_WR(bp, BNX2_HC_RX_QUICK_CONS_TRIP,
4962 (bp->rx_quick_cons_trip_int << 16) | bp->rx_quick_cons_trip);
Michael Chanb6016b72005-05-26 13:03:09 -07004963
Michael Chane503e062012-12-06 10:33:08 +00004964 BNX2_WR(bp, BNX2_HC_COMP_PROD_TRIP,
4965 (bp->comp_prod_trip_int << 16) | bp->comp_prod_trip);
Michael Chanb6016b72005-05-26 13:03:09 -07004966
Michael Chane503e062012-12-06 10:33:08 +00004967 BNX2_WR(bp, BNX2_HC_TX_TICKS, (bp->tx_ticks_int << 16) | bp->tx_ticks);
Michael Chanb6016b72005-05-26 13:03:09 -07004968
Michael Chane503e062012-12-06 10:33:08 +00004969 BNX2_WR(bp, BNX2_HC_RX_TICKS, (bp->rx_ticks_int << 16) | bp->rx_ticks);
Michael Chanb6016b72005-05-26 13:03:09 -07004970
Michael Chane503e062012-12-06 10:33:08 +00004971 BNX2_WR(bp, BNX2_HC_COM_TICKS,
4972 (bp->com_ticks_int << 16) | bp->com_ticks);
Michael Chanb6016b72005-05-26 13:03:09 -07004973
Michael Chane503e062012-12-06 10:33:08 +00004974 BNX2_WR(bp, BNX2_HC_CMD_TICKS,
4975 (bp->cmd_ticks_int << 16) | bp->cmd_ticks);
Michael Chanb6016b72005-05-26 13:03:09 -07004976
Michael Chan61d9e3f2009-08-21 16:20:46 +00004977 if (bp->flags & BNX2_FLAG_BROKEN_STATS)
Michael Chane503e062012-12-06 10:33:08 +00004978 BNX2_WR(bp, BNX2_HC_STATS_TICKS, 0);
Michael Chan02537b062007-06-04 21:24:07 -07004979 else
Michael Chane503e062012-12-06 10:33:08 +00004980 BNX2_WR(bp, BNX2_HC_STATS_TICKS, bp->stats_ticks);
4981 BNX2_WR(bp, BNX2_HC_STAT_COLLECT_TICKS, 0xbb8); /* 3ms */
Michael Chanb6016b72005-05-26 13:03:09 -07004982
Michael Chan4ce45e02012-12-06 10:33:10 +00004983 if (BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5706_A1)
Michael Chan8e6a72c2007-05-03 13:24:48 -07004984 val = BNX2_HC_CONFIG_COLLECT_STATS;
Michael Chanb6016b72005-05-26 13:03:09 -07004985 else {
Michael Chan8e6a72c2007-05-03 13:24:48 -07004986 val = BNX2_HC_CONFIG_RX_TMR_MODE | BNX2_HC_CONFIG_TX_TMR_MODE |
4987 BNX2_HC_CONFIG_COLLECT_STATS;
Michael Chanb6016b72005-05-26 13:03:09 -07004988 }
4989
Michael Chanefde73a2010-02-15 19:42:07 +00004990 if (bp->flags & BNX2_FLAG_USING_MSIX) {
Michael Chane503e062012-12-06 10:33:08 +00004991 BNX2_WR(bp, BNX2_HC_MSIX_BIT_VECTOR,
4992 BNX2_HC_MSIX_BIT_VECTOR_VAL);
Michael Chanc76c0472007-12-20 20:01:19 -08004993
Michael Chan5e9ad9e2008-06-19 16:43:17 -07004994 val |= BNX2_HC_CONFIG_SB_ADDR_INC_128B;
4995 }
4996
4997 if (bp->flags & BNX2_FLAG_ONE_SHOT_MSI)
Michael Chancf7474a2009-08-21 16:20:48 +00004998 val |= BNX2_HC_CONFIG_ONE_SHOT | BNX2_HC_CONFIG_USE_INT_PARAM;
Michael Chan5e9ad9e2008-06-19 16:43:17 -07004999
Michael Chane503e062012-12-06 10:33:08 +00005000 BNX2_WR(bp, BNX2_HC_CONFIG, val);
Michael Chan5e9ad9e2008-06-19 16:43:17 -07005001
Michael Chan22fa1592010-10-11 16:12:00 -07005002 if (bp->rx_ticks < 25)
5003 bnx2_reg_wr_ind(bp, BNX2_FW_RX_LOW_LATENCY, 1);
5004 else
5005 bnx2_reg_wr_ind(bp, BNX2_FW_RX_LOW_LATENCY, 0);
5006
Michael Chan5e9ad9e2008-06-19 16:43:17 -07005007 for (i = 1; i < bp->irq_nvecs; i++) {
5008 u32 base = ((i - 1) * BNX2_HC_SB_CONFIG_SIZE) +
5009 BNX2_HC_SB_CONFIG_1;
5010
Michael Chane503e062012-12-06 10:33:08 +00005011 BNX2_WR(bp, base,
Michael Chanc76c0472007-12-20 20:01:19 -08005012 BNX2_HC_SB_CONFIG_1_TX_TMR_MODE |
Michael Chan5e9ad9e2008-06-19 16:43:17 -07005013 BNX2_HC_SB_CONFIG_1_RX_TMR_MODE |
Michael Chanc76c0472007-12-20 20:01:19 -08005014 BNX2_HC_SB_CONFIG_1_ONE_SHOT);
5015
Michael Chane503e062012-12-06 10:33:08 +00005016 BNX2_WR(bp, base + BNX2_HC_TX_QUICK_CONS_TRIP_OFF,
Michael Chanc76c0472007-12-20 20:01:19 -08005017 (bp->tx_quick_cons_trip_int << 16) |
5018 bp->tx_quick_cons_trip);
5019
Michael Chane503e062012-12-06 10:33:08 +00005020 BNX2_WR(bp, base + BNX2_HC_TX_TICKS_OFF,
Michael Chanc76c0472007-12-20 20:01:19 -08005021 (bp->tx_ticks_int << 16) | bp->tx_ticks);
5022
Michael Chane503e062012-12-06 10:33:08 +00005023 BNX2_WR(bp, base + BNX2_HC_RX_QUICK_CONS_TRIP_OFF,
5024 (bp->rx_quick_cons_trip_int << 16) |
Michael Chan5e9ad9e2008-06-19 16:43:17 -07005025 bp->rx_quick_cons_trip);
5026
Michael Chane503e062012-12-06 10:33:08 +00005027 BNX2_WR(bp, base + BNX2_HC_RX_TICKS_OFF,
Michael Chan5e9ad9e2008-06-19 16:43:17 -07005028 (bp->rx_ticks_int << 16) | bp->rx_ticks);
Michael Chanc76c0472007-12-20 20:01:19 -08005029 }
5030
Michael Chanb6016b72005-05-26 13:03:09 -07005031 /* Clear internal stats counters. */
Michael Chane503e062012-12-06 10:33:08 +00005032 BNX2_WR(bp, BNX2_HC_COMMAND, BNX2_HC_COMMAND_CLR_STAT_NOW);
Michael Chanb6016b72005-05-26 13:03:09 -07005033
Michael Chane503e062012-12-06 10:33:08 +00005034 BNX2_WR(bp, BNX2_HC_ATTN_BITS_ENABLE, STATUS_ATTN_EVENTS);
Michael Chanb6016b72005-05-26 13:03:09 -07005035
5036 /* Initialize the receive filter. */
5037 bnx2_set_rx_mode(bp->dev);
5038
Michael Chan4ce45e02012-12-06 10:33:10 +00005039 if (BNX2_CHIP(bp) == BNX2_CHIP_5709) {
Michael Chane503e062012-12-06 10:33:08 +00005040 val = BNX2_RD(bp, BNX2_MISC_NEW_CORE_CTL);
Michael Chan0aa38df2007-06-04 21:23:06 -07005041 val |= BNX2_MISC_NEW_CORE_CTL_DMA_ENABLE;
Michael Chane503e062012-12-06 10:33:08 +00005042 BNX2_WR(bp, BNX2_MISC_NEW_CORE_CTL, val);
Michael Chan0aa38df2007-06-04 21:23:06 -07005043 }
Michael Chanb090ae22006-01-23 16:07:10 -08005044 rc = bnx2_fw_sync(bp, BNX2_DRV_MSG_DATA_WAIT2 | BNX2_DRV_MSG_CODE_RESET,
Michael Chana2f13892008-07-14 22:38:23 -07005045 1, 0);
Michael Chanb6016b72005-05-26 13:03:09 -07005046
Michael Chane503e062012-12-06 10:33:08 +00005047 BNX2_WR(bp, BNX2_MISC_ENABLE_SET_BITS, BNX2_MISC_ENABLE_DEFAULT);
5048 BNX2_RD(bp, BNX2_MISC_ENABLE_SET_BITS);
Michael Chanb6016b72005-05-26 13:03:09 -07005049
5050 udelay(20);
5051
Michael Chane503e062012-12-06 10:33:08 +00005052 bp->hc_cmd = BNX2_RD(bp, BNX2_HC_COMMAND);
Michael Chanbf5295b2006-03-23 01:11:56 -08005053
Michael Chanb090ae22006-01-23 16:07:10 -08005054 return rc;
Michael Chanb6016b72005-05-26 13:03:09 -07005055}
5056
Michael Chan59b47d82006-11-19 14:10:45 -08005057static void
Michael Chanc76c0472007-12-20 20:01:19 -08005058bnx2_clear_ring_states(struct bnx2 *bp)
5059{
5060 struct bnx2_napi *bnapi;
Michael Chan35e90102008-06-19 16:37:42 -07005061 struct bnx2_tx_ring_info *txr;
Michael Chanbb4f98a2008-06-19 16:38:19 -07005062 struct bnx2_rx_ring_info *rxr;
Michael Chanc76c0472007-12-20 20:01:19 -08005063 int i;
5064
5065 for (i = 0; i < BNX2_MAX_MSIX_VEC; i++) {
5066 bnapi = &bp->bnx2_napi[i];
Michael Chan35e90102008-06-19 16:37:42 -07005067 txr = &bnapi->tx_ring;
Michael Chanbb4f98a2008-06-19 16:38:19 -07005068 rxr = &bnapi->rx_ring;
Michael Chanc76c0472007-12-20 20:01:19 -08005069
Michael Chan35e90102008-06-19 16:37:42 -07005070 txr->tx_cons = 0;
5071 txr->hw_tx_cons = 0;
Michael Chanbb4f98a2008-06-19 16:38:19 -07005072 rxr->rx_prod_bseq = 0;
5073 rxr->rx_prod = 0;
5074 rxr->rx_cons = 0;
5075 rxr->rx_pg_prod = 0;
5076 rxr->rx_pg_cons = 0;
Michael Chanc76c0472007-12-20 20:01:19 -08005077 }
5078}
5079
5080static void
Michael Chan35e90102008-06-19 16:37:42 -07005081bnx2_init_tx_context(struct bnx2 *bp, u32 cid, struct bnx2_tx_ring_info *txr)
Michael Chan59b47d82006-11-19 14:10:45 -08005082{
5083 u32 val, offset0, offset1, offset2, offset3;
Michael Chan62a83132008-01-29 21:35:40 -08005084 u32 cid_addr = GET_CID_ADDR(cid);
Michael Chan59b47d82006-11-19 14:10:45 -08005085
Michael Chan4ce45e02012-12-06 10:33:10 +00005086 if (BNX2_CHIP(bp) == BNX2_CHIP_5709) {
Michael Chan59b47d82006-11-19 14:10:45 -08005087 offset0 = BNX2_L2CTX_TYPE_XI;
5088 offset1 = BNX2_L2CTX_CMD_TYPE_XI;
5089 offset2 = BNX2_L2CTX_TBDR_BHADDR_HI_XI;
5090 offset3 = BNX2_L2CTX_TBDR_BHADDR_LO_XI;
5091 } else {
5092 offset0 = BNX2_L2CTX_TYPE;
5093 offset1 = BNX2_L2CTX_CMD_TYPE;
5094 offset2 = BNX2_L2CTX_TBDR_BHADDR_HI;
5095 offset3 = BNX2_L2CTX_TBDR_BHADDR_LO;
5096 }
5097 val = BNX2_L2CTX_TYPE_TYPE_L2 | BNX2_L2CTX_TYPE_SIZE_L2;
Michael Chan62a83132008-01-29 21:35:40 -08005098 bnx2_ctx_wr(bp, cid_addr, offset0, val);
Michael Chan59b47d82006-11-19 14:10:45 -08005099
5100 val = BNX2_L2CTX_CMD_TYPE_TYPE_L2 | (8 << 16);
Michael Chan62a83132008-01-29 21:35:40 -08005101 bnx2_ctx_wr(bp, cid_addr, offset1, val);
Michael Chan59b47d82006-11-19 14:10:45 -08005102
Michael Chan35e90102008-06-19 16:37:42 -07005103 val = (u64) txr->tx_desc_mapping >> 32;
Michael Chan62a83132008-01-29 21:35:40 -08005104 bnx2_ctx_wr(bp, cid_addr, offset2, val);
Michael Chan59b47d82006-11-19 14:10:45 -08005105
Michael Chan35e90102008-06-19 16:37:42 -07005106 val = (u64) txr->tx_desc_mapping & 0xffffffff;
Michael Chan62a83132008-01-29 21:35:40 -08005107 bnx2_ctx_wr(bp, cid_addr, offset3, val);
Michael Chan59b47d82006-11-19 14:10:45 -08005108}
Michael Chanb6016b72005-05-26 13:03:09 -07005109
5110static void
Michael Chan35e90102008-06-19 16:37:42 -07005111bnx2_init_tx_ring(struct bnx2 *bp, int ring_num)
Michael Chanb6016b72005-05-26 13:03:09 -07005112{
Michael Chan2bc40782012-12-06 10:33:09 +00005113 struct bnx2_tx_bd *txbd;
Michael Chanc76c0472007-12-20 20:01:19 -08005114 u32 cid = TX_CID;
5115 struct bnx2_napi *bnapi;
Michael Chan35e90102008-06-19 16:37:42 -07005116 struct bnx2_tx_ring_info *txr;
Michael Chanc76c0472007-12-20 20:01:19 -08005117
Michael Chan35e90102008-06-19 16:37:42 -07005118 bnapi = &bp->bnx2_napi[ring_num];
5119 txr = &bnapi->tx_ring;
5120
5121 if (ring_num == 0)
5122 cid = TX_CID;
5123 else
5124 cid = TX_TSS_CID + ring_num - 1;
Michael Chanb6016b72005-05-26 13:03:09 -07005125
Michael Chan2f8af122006-08-15 01:39:10 -07005126 bp->tx_wake_thresh = bp->tx_ring_size / 2;
5127
Michael Chan2bc40782012-12-06 10:33:09 +00005128 txbd = &txr->tx_desc_ring[BNX2_MAX_TX_DESC_CNT];
Jeff Garzik6aa20a22006-09-13 13:24:59 -04005129
Michael Chan35e90102008-06-19 16:37:42 -07005130 txbd->tx_bd_haddr_hi = (u64) txr->tx_desc_mapping >> 32;
5131 txbd->tx_bd_haddr_lo = (u64) txr->tx_desc_mapping & 0xffffffff;
Michael Chanb6016b72005-05-26 13:03:09 -07005132
Michael Chan35e90102008-06-19 16:37:42 -07005133 txr->tx_prod = 0;
5134 txr->tx_prod_bseq = 0;
Jeff Garzik6aa20a22006-09-13 13:24:59 -04005135
Michael Chan35e90102008-06-19 16:37:42 -07005136 txr->tx_bidx_addr = MB_GET_CID_ADDR(cid) + BNX2_L2CTX_TX_HOST_BIDX;
5137 txr->tx_bseq_addr = MB_GET_CID_ADDR(cid) + BNX2_L2CTX_TX_HOST_BSEQ;
Michael Chanb6016b72005-05-26 13:03:09 -07005138
Michael Chan35e90102008-06-19 16:37:42 -07005139 bnx2_init_tx_context(bp, cid, txr);
Michael Chanb6016b72005-05-26 13:03:09 -07005140}
5141
5142static void
Michael Chan2bc40782012-12-06 10:33:09 +00005143bnx2_init_rxbd_rings(struct bnx2_rx_bd *rx_ring[], dma_addr_t dma[],
5144 u32 buf_size, int num_rings)
Michael Chanb6016b72005-05-26 13:03:09 -07005145{
Michael Chanb6016b72005-05-26 13:03:09 -07005146 int i;
Michael Chan2bc40782012-12-06 10:33:09 +00005147 struct bnx2_rx_bd *rxbd;
Michael Chanb6016b72005-05-26 13:03:09 -07005148
Michael Chan5d5d0012007-12-12 11:17:43 -08005149 for (i = 0; i < num_rings; i++) {
Michael Chan13daffa2006-03-20 17:49:20 -08005150 int j;
Michael Chanb6016b72005-05-26 13:03:09 -07005151
Michael Chan5d5d0012007-12-12 11:17:43 -08005152 rxbd = &rx_ring[i][0];
Michael Chan2bc40782012-12-06 10:33:09 +00005153 for (j = 0; j < BNX2_MAX_RX_DESC_CNT; j++, rxbd++) {
Michael Chan5d5d0012007-12-12 11:17:43 -08005154 rxbd->rx_bd_len = buf_size;
Michael Chan13daffa2006-03-20 17:49:20 -08005155 rxbd->rx_bd_flags = RX_BD_FLAGS_START | RX_BD_FLAGS_END;
5156 }
Michael Chan5d5d0012007-12-12 11:17:43 -08005157 if (i == (num_rings - 1))
Michael Chan13daffa2006-03-20 17:49:20 -08005158 j = 0;
5159 else
5160 j = i + 1;
Michael Chan5d5d0012007-12-12 11:17:43 -08005161 rxbd->rx_bd_haddr_hi = (u64) dma[j] >> 32;
5162 rxbd->rx_bd_haddr_lo = (u64) dma[j] & 0xffffffff;
Michael Chan13daffa2006-03-20 17:49:20 -08005163 }
Michael Chan5d5d0012007-12-12 11:17:43 -08005164}
5165
5166static void
Michael Chanbb4f98a2008-06-19 16:38:19 -07005167bnx2_init_rx_ring(struct bnx2 *bp, int ring_num)
Michael Chan5d5d0012007-12-12 11:17:43 -08005168{
5169 int i;
5170 u16 prod, ring_prod;
Michael Chanbb4f98a2008-06-19 16:38:19 -07005171 u32 cid, rx_cid_addr, val;
5172 struct bnx2_napi *bnapi = &bp->bnx2_napi[ring_num];
5173 struct bnx2_rx_ring_info *rxr = &bnapi->rx_ring;
Michael Chan5d5d0012007-12-12 11:17:43 -08005174
Michael Chanbb4f98a2008-06-19 16:38:19 -07005175 if (ring_num == 0)
5176 cid = RX_CID;
5177 else
5178 cid = RX_RSS_CID + ring_num - 1;
5179
5180 rx_cid_addr = GET_CID_ADDR(cid);
5181
5182 bnx2_init_rxbd_rings(rxr->rx_desc_ring, rxr->rx_desc_mapping,
Michael Chan5d5d0012007-12-12 11:17:43 -08005183 bp->rx_buf_use_size, bp->rx_max_ring);
5184
Michael Chanbb4f98a2008-06-19 16:38:19 -07005185 bnx2_init_rx_context(bp, cid);
Michael Chan83e3fc82008-01-29 21:37:17 -08005186
Michael Chan4ce45e02012-12-06 10:33:10 +00005187 if (BNX2_CHIP(bp) == BNX2_CHIP_5709) {
Michael Chane503e062012-12-06 10:33:08 +00005188 val = BNX2_RD(bp, BNX2_MQ_MAP_L2_5);
5189 BNX2_WR(bp, BNX2_MQ_MAP_L2_5, val | BNX2_MQ_MAP_L2_5_ARM);
Michael Chan83e3fc82008-01-29 21:37:17 -08005190 }
5191
Michael Chan62a83132008-01-29 21:35:40 -08005192 bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_PG_BUF_SIZE, 0);
Michael Chan47bf4242007-12-12 11:19:12 -08005193 if (bp->rx_pg_ring_size) {
Michael Chanbb4f98a2008-06-19 16:38:19 -07005194 bnx2_init_rxbd_rings(rxr->rx_pg_desc_ring,
5195 rxr->rx_pg_desc_mapping,
Michael Chan47bf4242007-12-12 11:19:12 -08005196 PAGE_SIZE, bp->rx_max_pg_ring);
5197 val = (bp->rx_buf_use_size << 16) | PAGE_SIZE;
Michael Chan62a83132008-01-29 21:35:40 -08005198 bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_PG_BUF_SIZE, val);
5199 bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_RBDC_KEY,
Michael Chan5e9ad9e2008-06-19 16:43:17 -07005200 BNX2_L2CTX_RBDC_JUMBO_KEY - ring_num);
Michael Chan47bf4242007-12-12 11:19:12 -08005201
Michael Chanbb4f98a2008-06-19 16:38:19 -07005202 val = (u64) rxr->rx_pg_desc_mapping[0] >> 32;
Michael Chan62a83132008-01-29 21:35:40 -08005203 bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_NX_PG_BDHADDR_HI, val);
Michael Chan47bf4242007-12-12 11:19:12 -08005204
Michael Chanbb4f98a2008-06-19 16:38:19 -07005205 val = (u64) rxr->rx_pg_desc_mapping[0] & 0xffffffff;
Michael Chan62a83132008-01-29 21:35:40 -08005206 bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_NX_PG_BDHADDR_LO, val);
Michael Chan47bf4242007-12-12 11:19:12 -08005207
Michael Chan4ce45e02012-12-06 10:33:10 +00005208 if (BNX2_CHIP(bp) == BNX2_CHIP_5709)
Michael Chane503e062012-12-06 10:33:08 +00005209 BNX2_WR(bp, BNX2_MQ_MAP_L2_3, BNX2_MQ_MAP_L2_3_DEFAULT);
Michael Chan47bf4242007-12-12 11:19:12 -08005210 }
Michael Chanb6016b72005-05-26 13:03:09 -07005211
Michael Chanbb4f98a2008-06-19 16:38:19 -07005212 val = (u64) rxr->rx_desc_mapping[0] >> 32;
Michael Chan62a83132008-01-29 21:35:40 -08005213 bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_NX_BDHADDR_HI, val);
Michael Chanb6016b72005-05-26 13:03:09 -07005214
Michael Chanbb4f98a2008-06-19 16:38:19 -07005215 val = (u64) rxr->rx_desc_mapping[0] & 0xffffffff;
Michael Chan62a83132008-01-29 21:35:40 -08005216 bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_NX_BDHADDR_LO, val);
Michael Chanb6016b72005-05-26 13:03:09 -07005217
Michael Chanbb4f98a2008-06-19 16:38:19 -07005218 ring_prod = prod = rxr->rx_pg_prod;
Michael Chan47bf4242007-12-12 11:19:12 -08005219 for (i = 0; i < bp->rx_pg_ring_size; i++) {
Stanislaw Gruszkaa2df00a2010-07-15 22:55:40 +00005220 if (bnx2_alloc_rx_page(bp, rxr, ring_prod, GFP_KERNEL) < 0) {
Joe Perches3a9c6a42010-02-17 15:01:51 +00005221 netdev_warn(bp->dev, "init'ed rx page ring %d with %d/%d pages only\n",
5222 ring_num, i, bp->rx_pg_ring_size);
Michael Chan47bf4242007-12-12 11:19:12 -08005223 break;
Michael Chanb929e532009-12-03 09:46:33 +00005224 }
Michael Chan2bc40782012-12-06 10:33:09 +00005225 prod = BNX2_NEXT_RX_BD(prod);
5226 ring_prod = BNX2_RX_PG_RING_IDX(prod);
Michael Chan47bf4242007-12-12 11:19:12 -08005227 }
Michael Chanbb4f98a2008-06-19 16:38:19 -07005228 rxr->rx_pg_prod = prod;
Michael Chan47bf4242007-12-12 11:19:12 -08005229
Michael Chanbb4f98a2008-06-19 16:38:19 -07005230 ring_prod = prod = rxr->rx_prod;
Michael Chan236b6392006-03-20 17:49:02 -08005231 for (i = 0; i < bp->rx_ring_size; i++) {
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00005232 if (bnx2_alloc_rx_data(bp, rxr, ring_prod, GFP_KERNEL) < 0) {
Joe Perches3a9c6a42010-02-17 15:01:51 +00005233 netdev_warn(bp->dev, "init'ed rx ring %d with %d/%d skbs only\n",
5234 ring_num, i, bp->rx_ring_size);
Michael Chanb6016b72005-05-26 13:03:09 -07005235 break;
Michael Chanb929e532009-12-03 09:46:33 +00005236 }
Michael Chan2bc40782012-12-06 10:33:09 +00005237 prod = BNX2_NEXT_RX_BD(prod);
5238 ring_prod = BNX2_RX_RING_IDX(prod);
Michael Chanb6016b72005-05-26 13:03:09 -07005239 }
Michael Chanbb4f98a2008-06-19 16:38:19 -07005240 rxr->rx_prod = prod;
Michael Chanb6016b72005-05-26 13:03:09 -07005241
Michael Chanbb4f98a2008-06-19 16:38:19 -07005242 rxr->rx_bidx_addr = MB_GET_CID_ADDR(cid) + BNX2_L2CTX_HOST_BDIDX;
5243 rxr->rx_bseq_addr = MB_GET_CID_ADDR(cid) + BNX2_L2CTX_HOST_BSEQ;
5244 rxr->rx_pg_bidx_addr = MB_GET_CID_ADDR(cid) + BNX2_L2CTX_HOST_PG_BDIDX;
Michael Chanb6016b72005-05-26 13:03:09 -07005245
Michael Chane503e062012-12-06 10:33:08 +00005246 BNX2_WR16(bp, rxr->rx_pg_bidx_addr, rxr->rx_pg_prod);
5247 BNX2_WR16(bp, rxr->rx_bidx_addr, prod);
Michael Chanbb4f98a2008-06-19 16:38:19 -07005248
Michael Chane503e062012-12-06 10:33:08 +00005249 BNX2_WR(bp, rxr->rx_bseq_addr, rxr->rx_prod_bseq);
Michael Chanb6016b72005-05-26 13:03:09 -07005250}
5251
Michael Chan35e90102008-06-19 16:37:42 -07005252static void
5253bnx2_init_all_rings(struct bnx2 *bp)
5254{
5255 int i;
Michael Chan5e9ad9e2008-06-19 16:43:17 -07005256 u32 val;
Michael Chan35e90102008-06-19 16:37:42 -07005257
5258 bnx2_clear_ring_states(bp);
5259
Michael Chane503e062012-12-06 10:33:08 +00005260 BNX2_WR(bp, BNX2_TSCH_TSS_CFG, 0);
Michael Chan35e90102008-06-19 16:37:42 -07005261 for (i = 0; i < bp->num_tx_rings; i++)
5262 bnx2_init_tx_ring(bp, i);
5263
5264 if (bp->num_tx_rings > 1)
Michael Chane503e062012-12-06 10:33:08 +00005265 BNX2_WR(bp, BNX2_TSCH_TSS_CFG, ((bp->num_tx_rings - 1) << 24) |
5266 (TX_TSS_CID << 7));
Michael Chan35e90102008-06-19 16:37:42 -07005267
Michael Chane503e062012-12-06 10:33:08 +00005268 BNX2_WR(bp, BNX2_RLUP_RSS_CONFIG, 0);
Michael Chan5e9ad9e2008-06-19 16:43:17 -07005269 bnx2_reg_wr_ind(bp, BNX2_RXP_SCRATCH_RSS_TBL_SZ, 0);
5270
Michael Chanbb4f98a2008-06-19 16:38:19 -07005271 for (i = 0; i < bp->num_rx_rings; i++)
5272 bnx2_init_rx_ring(bp, i);
Michael Chan5e9ad9e2008-06-19 16:43:17 -07005273
5274 if (bp->num_rx_rings > 1) {
Michael Chan22fa1592010-10-11 16:12:00 -07005275 u32 tbl_32 = 0;
Michael Chan5e9ad9e2008-06-19 16:43:17 -07005276
5277 for (i = 0; i < BNX2_RXP_SCRATCH_RSS_TBL_MAX_ENTRIES; i++) {
Michael Chan22fa1592010-10-11 16:12:00 -07005278 int shift = (i % 8) << 2;
5279
5280 tbl_32 |= (i % (bp->num_rx_rings - 1)) << shift;
5281 if ((i % 8) == 7) {
Michael Chane503e062012-12-06 10:33:08 +00005282 BNX2_WR(bp, BNX2_RLUP_RSS_DATA, tbl_32);
5283 BNX2_WR(bp, BNX2_RLUP_RSS_COMMAND, (i >> 3) |
Michael Chan22fa1592010-10-11 16:12:00 -07005284 BNX2_RLUP_RSS_COMMAND_RSS_WRITE_MASK |
5285 BNX2_RLUP_RSS_COMMAND_WRITE |
5286 BNX2_RLUP_RSS_COMMAND_HASH_MASK);
5287 tbl_32 = 0;
5288 }
Michael Chan5e9ad9e2008-06-19 16:43:17 -07005289 }
5290
5291 val = BNX2_RLUP_RSS_CONFIG_IPV4_RSS_TYPE_ALL_XI |
5292 BNX2_RLUP_RSS_CONFIG_IPV6_RSS_TYPE_ALL_XI;
5293
Michael Chane503e062012-12-06 10:33:08 +00005294 BNX2_WR(bp, BNX2_RLUP_RSS_CONFIG, val);
Michael Chan5e9ad9e2008-06-19 16:43:17 -07005295
5296 }
Michael Chan35e90102008-06-19 16:37:42 -07005297}
5298
Michael Chan5d5d0012007-12-12 11:17:43 -08005299static u32 bnx2_find_max_ring(u32 ring_size, u32 max_size)
Michael Chan13daffa2006-03-20 17:49:20 -08005300{
Michael Chan5d5d0012007-12-12 11:17:43 -08005301 u32 max, num_rings = 1;
Michael Chan13daffa2006-03-20 17:49:20 -08005302
Michael Chan2bc40782012-12-06 10:33:09 +00005303 while (ring_size > BNX2_MAX_RX_DESC_CNT) {
5304 ring_size -= BNX2_MAX_RX_DESC_CNT;
Michael Chan13daffa2006-03-20 17:49:20 -08005305 num_rings++;
5306 }
5307 /* round to next power of 2 */
Michael Chan5d5d0012007-12-12 11:17:43 -08005308 max = max_size;
Michael Chan13daffa2006-03-20 17:49:20 -08005309 while ((max & num_rings) == 0)
5310 max >>= 1;
5311
5312 if (num_rings != max)
5313 max <<= 1;
5314
Michael Chan5d5d0012007-12-12 11:17:43 -08005315 return max;
5316}
5317
5318static void
5319bnx2_set_rx_ring_size(struct bnx2 *bp, u32 size)
5320{
Michael Chan84eaa182007-12-12 11:19:57 -08005321 u32 rx_size, rx_space, jumbo_size;
Michael Chan5d5d0012007-12-12 11:17:43 -08005322
5323 /* 8 for CRC and VLAN */
Benjamin Lid89cb6a2008-05-16 22:18:57 -07005324 rx_size = bp->dev->mtu + ETH_HLEN + BNX2_RX_OFFSET + 8;
Michael Chan5d5d0012007-12-12 11:17:43 -08005325
Michael Chan84eaa182007-12-12 11:19:57 -08005326 rx_space = SKB_DATA_ALIGN(rx_size + BNX2_RX_ALIGN) + NET_SKB_PAD +
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00005327 SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
Michael Chan84eaa182007-12-12 11:19:57 -08005328
Benjamin Li601d3d12008-05-16 22:19:35 -07005329 bp->rx_copy_thresh = BNX2_RX_COPY_THRESH;
Michael Chan47bf4242007-12-12 11:19:12 -08005330 bp->rx_pg_ring_size = 0;
5331 bp->rx_max_pg_ring = 0;
5332 bp->rx_max_pg_ring_idx = 0;
David S. Millerf86e82f2008-01-21 17:15:40 -08005333 if ((rx_space > PAGE_SIZE) && !(bp->flags & BNX2_FLAG_JUMBO_BROKEN)) {
Michael Chan84eaa182007-12-12 11:19:57 -08005334 int pages = PAGE_ALIGN(bp->dev->mtu - 40) >> PAGE_SHIFT;
5335
5336 jumbo_size = size * pages;
Michael Chan2bc40782012-12-06 10:33:09 +00005337 if (jumbo_size > BNX2_MAX_TOTAL_RX_PG_DESC_CNT)
5338 jumbo_size = BNX2_MAX_TOTAL_RX_PG_DESC_CNT;
Michael Chan84eaa182007-12-12 11:19:57 -08005339
5340 bp->rx_pg_ring_size = jumbo_size;
5341 bp->rx_max_pg_ring = bnx2_find_max_ring(jumbo_size,
Michael Chan2bc40782012-12-06 10:33:09 +00005342 BNX2_MAX_RX_PG_RINGS);
5343 bp->rx_max_pg_ring_idx =
5344 (bp->rx_max_pg_ring * BNX2_RX_DESC_CNT) - 1;
Benjamin Li601d3d12008-05-16 22:19:35 -07005345 rx_size = BNX2_RX_COPY_THRESH + BNX2_RX_OFFSET;
Michael Chan84eaa182007-12-12 11:19:57 -08005346 bp->rx_copy_thresh = 0;
5347 }
Michael Chan5d5d0012007-12-12 11:17:43 -08005348
5349 bp->rx_buf_use_size = rx_size;
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00005350 /* hw alignment + build_skb() overhead*/
5351 bp->rx_buf_size = SKB_DATA_ALIGN(bp->rx_buf_use_size + BNX2_RX_ALIGN) +
5352 NET_SKB_PAD + SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
Benjamin Lid89cb6a2008-05-16 22:18:57 -07005353 bp->rx_jumbo_thresh = rx_size - BNX2_RX_OFFSET;
Michael Chan5d5d0012007-12-12 11:17:43 -08005354 bp->rx_ring_size = size;
Michael Chan2bc40782012-12-06 10:33:09 +00005355 bp->rx_max_ring = bnx2_find_max_ring(size, BNX2_MAX_RX_RINGS);
5356 bp->rx_max_ring_idx = (bp->rx_max_ring * BNX2_RX_DESC_CNT) - 1;
Michael Chan13daffa2006-03-20 17:49:20 -08005357}
5358
5359static void
Michael Chanb6016b72005-05-26 13:03:09 -07005360bnx2_free_tx_skbs(struct bnx2 *bp)
5361{
5362 int i;
5363
Michael Chan35e90102008-06-19 16:37:42 -07005364 for (i = 0; i < bp->num_tx_rings; i++) {
5365 struct bnx2_napi *bnapi = &bp->bnx2_napi[i];
5366 struct bnx2_tx_ring_info *txr = &bnapi->tx_ring;
5367 int j;
Michael Chanb6016b72005-05-26 13:03:09 -07005368
Michael Chan35e90102008-06-19 16:37:42 -07005369 if (txr->tx_buf_ring == NULL)
Michael Chanb6016b72005-05-26 13:03:09 -07005370 continue;
Michael Chanb6016b72005-05-26 13:03:09 -07005371
Michael Chan2bc40782012-12-06 10:33:09 +00005372 for (j = 0; j < BNX2_TX_DESC_CNT; ) {
5373 struct bnx2_sw_tx_bd *tx_buf = &txr->tx_buf_ring[j];
Michael Chan35e90102008-06-19 16:37:42 -07005374 struct sk_buff *skb = tx_buf->skb;
Alexander Duycke95524a2009-12-02 16:47:57 +00005375 int k, last;
Michael Chan35e90102008-06-19 16:37:42 -07005376
5377 if (skb == NULL) {
Michael Chan2bc40782012-12-06 10:33:09 +00005378 j = BNX2_NEXT_TX_BD(j);
Michael Chan35e90102008-06-19 16:37:42 -07005379 continue;
5380 }
5381
Stanislaw Gruszka36227e82010-07-15 04:25:50 +00005382 dma_unmap_single(&bp->pdev->dev,
FUJITA Tomonori1a4ccc22010-04-01 16:56:57 +00005383 dma_unmap_addr(tx_buf, mapping),
Alexander Duycke95524a2009-12-02 16:47:57 +00005384 skb_headlen(skb),
5385 PCI_DMA_TODEVICE);
Michael Chanb6016b72005-05-26 13:03:09 -07005386
Michael Chan35e90102008-06-19 16:37:42 -07005387 tx_buf->skb = NULL;
Michael Chanb6016b72005-05-26 13:03:09 -07005388
Alexander Duycke95524a2009-12-02 16:47:57 +00005389 last = tx_buf->nr_frags;
Michael Chan2bc40782012-12-06 10:33:09 +00005390 j = BNX2_NEXT_TX_BD(j);
5391 for (k = 0; k < last; k++, j = BNX2_NEXT_TX_BD(j)) {
5392 tx_buf = &txr->tx_buf_ring[BNX2_TX_RING_IDX(j)];
Stanislaw Gruszka36227e82010-07-15 04:25:50 +00005393 dma_unmap_page(&bp->pdev->dev,
FUJITA Tomonori1a4ccc22010-04-01 16:56:57 +00005394 dma_unmap_addr(tx_buf, mapping),
Eric Dumazet9e903e02011-10-18 21:00:24 +00005395 skb_frag_size(&skb_shinfo(skb)->frags[k]),
Alexander Duycke95524a2009-12-02 16:47:57 +00005396 PCI_DMA_TODEVICE);
5397 }
Michael Chan35e90102008-06-19 16:37:42 -07005398 dev_kfree_skb(skb);
Michael Chanb6016b72005-05-26 13:03:09 -07005399 }
Eric Dumazete9831902011-11-29 11:53:05 +00005400 netdev_tx_reset_queue(netdev_get_tx_queue(bp->dev, i));
Michael Chanb6016b72005-05-26 13:03:09 -07005401 }
Michael Chanb6016b72005-05-26 13:03:09 -07005402}
5403
5404static void
5405bnx2_free_rx_skbs(struct bnx2 *bp)
5406{
5407 int i;
5408
Michael Chanbb4f98a2008-06-19 16:38:19 -07005409 for (i = 0; i < bp->num_rx_rings; i++) {
5410 struct bnx2_napi *bnapi = &bp->bnx2_napi[i];
5411 struct bnx2_rx_ring_info *rxr = &bnapi->rx_ring;
5412 int j;
Michael Chanb6016b72005-05-26 13:03:09 -07005413
Michael Chanbb4f98a2008-06-19 16:38:19 -07005414 if (rxr->rx_buf_ring == NULL)
5415 return;
Michael Chanb6016b72005-05-26 13:03:09 -07005416
Michael Chanbb4f98a2008-06-19 16:38:19 -07005417 for (j = 0; j < bp->rx_max_ring_idx; j++) {
Michael Chan2bc40782012-12-06 10:33:09 +00005418 struct bnx2_sw_bd *rx_buf = &rxr->rx_buf_ring[j];
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00005419 u8 *data = rx_buf->data;
Michael Chanb6016b72005-05-26 13:03:09 -07005420
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00005421 if (data == NULL)
Michael Chanbb4f98a2008-06-19 16:38:19 -07005422 continue;
Michael Chanb6016b72005-05-26 13:03:09 -07005423
Stanislaw Gruszka36227e82010-07-15 04:25:50 +00005424 dma_unmap_single(&bp->pdev->dev,
FUJITA Tomonori1a4ccc22010-04-01 16:56:57 +00005425 dma_unmap_addr(rx_buf, mapping),
Michael Chanbb4f98a2008-06-19 16:38:19 -07005426 bp->rx_buf_use_size,
5427 PCI_DMA_FROMDEVICE);
Michael Chanb6016b72005-05-26 13:03:09 -07005428
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00005429 rx_buf->data = NULL;
Michael Chanbb4f98a2008-06-19 16:38:19 -07005430
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00005431 kfree(data);
Michael Chanbb4f98a2008-06-19 16:38:19 -07005432 }
5433 for (j = 0; j < bp->rx_max_pg_ring_idx; j++)
5434 bnx2_free_rx_page(bp, rxr, j);
Michael Chanb6016b72005-05-26 13:03:09 -07005435 }
5436}
5437
5438static void
5439bnx2_free_skbs(struct bnx2 *bp)
5440{
5441 bnx2_free_tx_skbs(bp);
5442 bnx2_free_rx_skbs(bp);
5443}
5444
5445static int
5446bnx2_reset_nic(struct bnx2 *bp, u32 reset_code)
5447{
5448 int rc;
5449
5450 rc = bnx2_reset_chip(bp, reset_code);
5451 bnx2_free_skbs(bp);
5452 if (rc)
5453 return rc;
5454
Michael Chanfba9fe92006-06-12 22:21:25 -07005455 if ((rc = bnx2_init_chip(bp)) != 0)
5456 return rc;
5457
Michael Chan35e90102008-06-19 16:37:42 -07005458 bnx2_init_all_rings(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07005459 return 0;
5460}
5461
5462static int
Michael Chan9a120bc2008-05-16 22:17:45 -07005463bnx2_init_nic(struct bnx2 *bp, int reset_phy)
Michael Chanb6016b72005-05-26 13:03:09 -07005464{
5465 int rc;
5466
5467 if ((rc = bnx2_reset_nic(bp, BNX2_DRV_MSG_CODE_RESET)) != 0)
5468 return rc;
5469
Michael Chan80be4432006-11-19 14:07:28 -08005470 spin_lock_bh(&bp->phy_lock);
Michael Chan9a120bc2008-05-16 22:17:45 -07005471 bnx2_init_phy(bp, reset_phy);
Michael Chanb6016b72005-05-26 13:03:09 -07005472 bnx2_set_link(bp);
Michael Chan543a8272008-05-02 16:56:44 -07005473 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
5474 bnx2_remote_phy_event(bp);
Michael Chan0d8a6572007-07-07 22:49:43 -07005475 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07005476 return 0;
5477}
5478
5479static int
Michael Chan74bf4ba2008-10-09 12:21:08 -07005480bnx2_shutdown_chip(struct bnx2 *bp)
5481{
5482 u32 reset_code;
5483
5484 if (bp->flags & BNX2_FLAG_NO_WOL)
5485 reset_code = BNX2_DRV_MSG_CODE_UNLOAD_LNK_DN;
5486 else if (bp->wol)
5487 reset_code = BNX2_DRV_MSG_CODE_SUSPEND_WOL;
5488 else
5489 reset_code = BNX2_DRV_MSG_CODE_SUSPEND_NO_WOL;
5490
5491 return bnx2_reset_chip(bp, reset_code);
5492}
5493
5494static int
Michael Chanb6016b72005-05-26 13:03:09 -07005495bnx2_test_registers(struct bnx2 *bp)
5496{
5497 int ret;
Michael Chan5bae30c2007-05-03 13:18:46 -07005498 int i, is_5709;
Arjan van de Venf71e1302006-03-03 21:33:57 -05005499 static const struct {
Michael Chanb6016b72005-05-26 13:03:09 -07005500 u16 offset;
5501 u16 flags;
Michael Chan5bae30c2007-05-03 13:18:46 -07005502#define BNX2_FL_NOT_5709 1
Michael Chanb6016b72005-05-26 13:03:09 -07005503 u32 rw_mask;
5504 u32 ro_mask;
5505 } reg_tbl[] = {
5506 { 0x006c, 0, 0x00000000, 0x0000003f },
5507 { 0x0090, 0, 0xffffffff, 0x00000000 },
5508 { 0x0094, 0, 0x00000000, 0x00000000 },
5509
Michael Chan5bae30c2007-05-03 13:18:46 -07005510 { 0x0404, BNX2_FL_NOT_5709, 0x00003f00, 0x00000000 },
5511 { 0x0418, BNX2_FL_NOT_5709, 0x00000000, 0xffffffff },
5512 { 0x041c, BNX2_FL_NOT_5709, 0x00000000, 0xffffffff },
5513 { 0x0420, BNX2_FL_NOT_5709, 0x00000000, 0x80ffffff },
5514 { 0x0424, BNX2_FL_NOT_5709, 0x00000000, 0x00000000 },
5515 { 0x0428, BNX2_FL_NOT_5709, 0x00000000, 0x00000001 },
5516 { 0x0450, BNX2_FL_NOT_5709, 0x00000000, 0x0000ffff },
5517 { 0x0454, BNX2_FL_NOT_5709, 0x00000000, 0xffffffff },
5518 { 0x0458, BNX2_FL_NOT_5709, 0x00000000, 0xffffffff },
Michael Chanb6016b72005-05-26 13:03:09 -07005519
Michael Chan5bae30c2007-05-03 13:18:46 -07005520 { 0x0808, BNX2_FL_NOT_5709, 0x00000000, 0xffffffff },
5521 { 0x0854, BNX2_FL_NOT_5709, 0x00000000, 0xffffffff },
5522 { 0x0868, BNX2_FL_NOT_5709, 0x00000000, 0x77777777 },
5523 { 0x086c, BNX2_FL_NOT_5709, 0x00000000, 0x77777777 },
5524 { 0x0870, BNX2_FL_NOT_5709, 0x00000000, 0x77777777 },
5525 { 0x0874, BNX2_FL_NOT_5709, 0x00000000, 0x77777777 },
Michael Chanb6016b72005-05-26 13:03:09 -07005526
Michael Chan5bae30c2007-05-03 13:18:46 -07005527 { 0x0c00, BNX2_FL_NOT_5709, 0x00000000, 0x00000001 },
5528 { 0x0c04, BNX2_FL_NOT_5709, 0x00000000, 0x03ff0001 },
5529 { 0x0c08, BNX2_FL_NOT_5709, 0x0f0ff073, 0x00000000 },
Michael Chanb6016b72005-05-26 13:03:09 -07005530
5531 { 0x1000, 0, 0x00000000, 0x00000001 },
Michael Chan15b169c2008-05-02 16:57:08 -07005532 { 0x1004, BNX2_FL_NOT_5709, 0x00000000, 0x000f0001 },
Michael Chanb6016b72005-05-26 13:03:09 -07005533
5534 { 0x1408, 0, 0x01c00800, 0x00000000 },
5535 { 0x149c, 0, 0x8000ffff, 0x00000000 },
5536 { 0x14a8, 0, 0x00000000, 0x000001ff },
Michael Chan5b0c76a2005-11-04 08:45:49 -08005537 { 0x14ac, 0, 0x0fffffff, 0x10000000 },
Michael Chanb6016b72005-05-26 13:03:09 -07005538 { 0x14b0, 0, 0x00000002, 0x00000001 },
5539 { 0x14b8, 0, 0x00000000, 0x00000000 },
5540 { 0x14c0, 0, 0x00000000, 0x00000009 },
5541 { 0x14c4, 0, 0x00003fff, 0x00000000 },
5542 { 0x14cc, 0, 0x00000000, 0x00000001 },
5543 { 0x14d0, 0, 0xffffffff, 0x00000000 },
Michael Chanb6016b72005-05-26 13:03:09 -07005544
5545 { 0x1800, 0, 0x00000000, 0x00000001 },
5546 { 0x1804, 0, 0x00000000, 0x00000003 },
Michael Chanb6016b72005-05-26 13:03:09 -07005547
5548 { 0x2800, 0, 0x00000000, 0x00000001 },
5549 { 0x2804, 0, 0x00000000, 0x00003f01 },
5550 { 0x2808, 0, 0x0f3f3f03, 0x00000000 },
5551 { 0x2810, 0, 0xffff0000, 0x00000000 },
5552 { 0x2814, 0, 0xffff0000, 0x00000000 },
5553 { 0x2818, 0, 0xffff0000, 0x00000000 },
5554 { 0x281c, 0, 0xffff0000, 0x00000000 },
5555 { 0x2834, 0, 0xffffffff, 0x00000000 },
5556 { 0x2840, 0, 0x00000000, 0xffffffff },
5557 { 0x2844, 0, 0x00000000, 0xffffffff },
5558 { 0x2848, 0, 0xffffffff, 0x00000000 },
5559 { 0x284c, 0, 0xf800f800, 0x07ff07ff },
5560
5561 { 0x2c00, 0, 0x00000000, 0x00000011 },
5562 { 0x2c04, 0, 0x00000000, 0x00030007 },
5563
Michael Chanb6016b72005-05-26 13:03:09 -07005564 { 0x3c00, 0, 0x00000000, 0x00000001 },
5565 { 0x3c04, 0, 0x00000000, 0x00070000 },
5566 { 0x3c08, 0, 0x00007f71, 0x07f00000 },
5567 { 0x3c0c, 0, 0x1f3ffffc, 0x00000000 },
5568 { 0x3c10, 0, 0xffffffff, 0x00000000 },
5569 { 0x3c14, 0, 0x00000000, 0xffffffff },
5570 { 0x3c18, 0, 0x00000000, 0xffffffff },
5571 { 0x3c1c, 0, 0xfffff000, 0x00000000 },
5572 { 0x3c20, 0, 0xffffff00, 0x00000000 },
Michael Chanb6016b72005-05-26 13:03:09 -07005573
5574 { 0x5004, 0, 0x00000000, 0x0000007f },
5575 { 0x5008, 0, 0x0f0007ff, 0x00000000 },
Michael Chanb6016b72005-05-26 13:03:09 -07005576
Michael Chanb6016b72005-05-26 13:03:09 -07005577 { 0x5c00, 0, 0x00000000, 0x00000001 },
5578 { 0x5c04, 0, 0x00000000, 0x0003000f },
5579 { 0x5c08, 0, 0x00000003, 0x00000000 },
5580 { 0x5c0c, 0, 0x0000fff8, 0x00000000 },
5581 { 0x5c10, 0, 0x00000000, 0xffffffff },
5582 { 0x5c80, 0, 0x00000000, 0x0f7113f1 },
5583 { 0x5c84, 0, 0x00000000, 0x0000f333 },
5584 { 0x5c88, 0, 0x00000000, 0x00077373 },
5585 { 0x5c8c, 0, 0x00000000, 0x0007f737 },
5586
5587 { 0x6808, 0, 0x0000ff7f, 0x00000000 },
5588 { 0x680c, 0, 0xffffffff, 0x00000000 },
5589 { 0x6810, 0, 0xffffffff, 0x00000000 },
5590 { 0x6814, 0, 0xffffffff, 0x00000000 },
5591 { 0x6818, 0, 0xffffffff, 0x00000000 },
5592 { 0x681c, 0, 0xffffffff, 0x00000000 },
5593 { 0x6820, 0, 0x00ff00ff, 0x00000000 },
5594 { 0x6824, 0, 0x00ff00ff, 0x00000000 },
5595 { 0x6828, 0, 0x00ff00ff, 0x00000000 },
5596 { 0x682c, 0, 0x03ff03ff, 0x00000000 },
5597 { 0x6830, 0, 0x03ff03ff, 0x00000000 },
5598 { 0x6834, 0, 0x03ff03ff, 0x00000000 },
5599 { 0x6838, 0, 0x03ff03ff, 0x00000000 },
5600 { 0x683c, 0, 0x0000ffff, 0x00000000 },
5601 { 0x6840, 0, 0x00000ff0, 0x00000000 },
5602 { 0x6844, 0, 0x00ffff00, 0x00000000 },
5603 { 0x684c, 0, 0xffffffff, 0x00000000 },
5604 { 0x6850, 0, 0x7f7f7f7f, 0x00000000 },
5605 { 0x6854, 0, 0x7f7f7f7f, 0x00000000 },
5606 { 0x6858, 0, 0x7f7f7f7f, 0x00000000 },
5607 { 0x685c, 0, 0x7f7f7f7f, 0x00000000 },
5608 { 0x6908, 0, 0x00000000, 0x0001ff0f },
5609 { 0x690c, 0, 0x00000000, 0x0ffe00f0 },
5610
5611 { 0xffff, 0, 0x00000000, 0x00000000 },
5612 };
5613
5614 ret = 0;
Michael Chan5bae30c2007-05-03 13:18:46 -07005615 is_5709 = 0;
Michael Chan4ce45e02012-12-06 10:33:10 +00005616 if (BNX2_CHIP(bp) == BNX2_CHIP_5709)
Michael Chan5bae30c2007-05-03 13:18:46 -07005617 is_5709 = 1;
5618
Michael Chanb6016b72005-05-26 13:03:09 -07005619 for (i = 0; reg_tbl[i].offset != 0xffff; i++) {
5620 u32 offset, rw_mask, ro_mask, save_val, val;
Michael Chan5bae30c2007-05-03 13:18:46 -07005621 u16 flags = reg_tbl[i].flags;
5622
5623 if (is_5709 && (flags & BNX2_FL_NOT_5709))
5624 continue;
Michael Chanb6016b72005-05-26 13:03:09 -07005625
5626 offset = (u32) reg_tbl[i].offset;
5627 rw_mask = reg_tbl[i].rw_mask;
5628 ro_mask = reg_tbl[i].ro_mask;
5629
Peter Hagervall14ab9b82005-08-10 14:18:16 -07005630 save_val = readl(bp->regview + offset);
Michael Chanb6016b72005-05-26 13:03:09 -07005631
Peter Hagervall14ab9b82005-08-10 14:18:16 -07005632 writel(0, bp->regview + offset);
Michael Chanb6016b72005-05-26 13:03:09 -07005633
Peter Hagervall14ab9b82005-08-10 14:18:16 -07005634 val = readl(bp->regview + offset);
Michael Chanb6016b72005-05-26 13:03:09 -07005635 if ((val & rw_mask) != 0) {
5636 goto reg_test_err;
5637 }
5638
5639 if ((val & ro_mask) != (save_val & ro_mask)) {
5640 goto reg_test_err;
5641 }
5642
Peter Hagervall14ab9b82005-08-10 14:18:16 -07005643 writel(0xffffffff, bp->regview + offset);
Michael Chanb6016b72005-05-26 13:03:09 -07005644
Peter Hagervall14ab9b82005-08-10 14:18:16 -07005645 val = readl(bp->regview + offset);
Michael Chanb6016b72005-05-26 13:03:09 -07005646 if ((val & rw_mask) != rw_mask) {
5647 goto reg_test_err;
5648 }
5649
5650 if ((val & ro_mask) != (save_val & ro_mask)) {
5651 goto reg_test_err;
5652 }
5653
Peter Hagervall14ab9b82005-08-10 14:18:16 -07005654 writel(save_val, bp->regview + offset);
Michael Chanb6016b72005-05-26 13:03:09 -07005655 continue;
5656
5657reg_test_err:
Peter Hagervall14ab9b82005-08-10 14:18:16 -07005658 writel(save_val, bp->regview + offset);
Michael Chanb6016b72005-05-26 13:03:09 -07005659 ret = -ENODEV;
5660 break;
5661 }
5662 return ret;
5663}
5664
5665static int
5666bnx2_do_mem_test(struct bnx2 *bp, u32 start, u32 size)
5667{
Arjan van de Venf71e1302006-03-03 21:33:57 -05005668 static const u32 test_pattern[] = { 0x00000000, 0xffffffff, 0x55555555,
Michael Chanb6016b72005-05-26 13:03:09 -07005669 0xaaaaaaaa , 0xaa55aa55, 0x55aa55aa };
5670 int i;
5671
5672 for (i = 0; i < sizeof(test_pattern) / 4; i++) {
5673 u32 offset;
5674
5675 for (offset = 0; offset < size; offset += 4) {
5676
Michael Chan2726d6e2008-01-29 21:35:05 -08005677 bnx2_reg_wr_ind(bp, start + offset, test_pattern[i]);
Michael Chanb6016b72005-05-26 13:03:09 -07005678
Michael Chan2726d6e2008-01-29 21:35:05 -08005679 if (bnx2_reg_rd_ind(bp, start + offset) !=
Michael Chanb6016b72005-05-26 13:03:09 -07005680 test_pattern[i]) {
5681 return -ENODEV;
5682 }
5683 }
5684 }
5685 return 0;
5686}
5687
5688static int
5689bnx2_test_memory(struct bnx2 *bp)
5690{
5691 int ret = 0;
5692 int i;
Michael Chan5bae30c2007-05-03 13:18:46 -07005693 static struct mem_entry {
Michael Chanb6016b72005-05-26 13:03:09 -07005694 u32 offset;
5695 u32 len;
Michael Chan5bae30c2007-05-03 13:18:46 -07005696 } mem_tbl_5706[] = {
Michael Chanb6016b72005-05-26 13:03:09 -07005697 { 0x60000, 0x4000 },
Michael Chan5b0c76a2005-11-04 08:45:49 -08005698 { 0xa0000, 0x3000 },
Michael Chanb6016b72005-05-26 13:03:09 -07005699 { 0xe0000, 0x4000 },
5700 { 0x120000, 0x4000 },
5701 { 0x1a0000, 0x4000 },
5702 { 0x160000, 0x4000 },
5703 { 0xffffffff, 0 },
Michael Chan5bae30c2007-05-03 13:18:46 -07005704 },
5705 mem_tbl_5709[] = {
5706 { 0x60000, 0x4000 },
5707 { 0xa0000, 0x3000 },
5708 { 0xe0000, 0x4000 },
5709 { 0x120000, 0x4000 },
5710 { 0x1a0000, 0x4000 },
5711 { 0xffffffff, 0 },
Michael Chanb6016b72005-05-26 13:03:09 -07005712 };
Michael Chan5bae30c2007-05-03 13:18:46 -07005713 struct mem_entry *mem_tbl;
5714
Michael Chan4ce45e02012-12-06 10:33:10 +00005715 if (BNX2_CHIP(bp) == BNX2_CHIP_5709)
Michael Chan5bae30c2007-05-03 13:18:46 -07005716 mem_tbl = mem_tbl_5709;
5717 else
5718 mem_tbl = mem_tbl_5706;
Michael Chanb6016b72005-05-26 13:03:09 -07005719
5720 for (i = 0; mem_tbl[i].offset != 0xffffffff; i++) {
5721 if ((ret = bnx2_do_mem_test(bp, mem_tbl[i].offset,
5722 mem_tbl[i].len)) != 0) {
5723 return ret;
5724 }
5725 }
Jeff Garzik6aa20a22006-09-13 13:24:59 -04005726
Michael Chanb6016b72005-05-26 13:03:09 -07005727 return ret;
5728}
5729
Michael Chanbc5a0692006-01-23 16:13:22 -08005730#define BNX2_MAC_LOOPBACK 0
5731#define BNX2_PHY_LOOPBACK 1
5732
Michael Chanb6016b72005-05-26 13:03:09 -07005733static int
Michael Chanbc5a0692006-01-23 16:13:22 -08005734bnx2_run_loopback(struct bnx2 *bp, int loopback_mode)
Michael Chanb6016b72005-05-26 13:03:09 -07005735{
5736 unsigned int pkt_size, num_pkts, i;
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00005737 struct sk_buff *skb;
5738 u8 *data;
Michael Chanb6016b72005-05-26 13:03:09 -07005739 unsigned char *packet;
Michael Chanbc5a0692006-01-23 16:13:22 -08005740 u16 rx_start_idx, rx_idx;
Michael Chanb6016b72005-05-26 13:03:09 -07005741 dma_addr_t map;
Michael Chan2bc40782012-12-06 10:33:09 +00005742 struct bnx2_tx_bd *txbd;
5743 struct bnx2_sw_bd *rx_buf;
Michael Chanb6016b72005-05-26 13:03:09 -07005744 struct l2_fhdr *rx_hdr;
5745 int ret = -ENODEV;
Michael Chanc76c0472007-12-20 20:01:19 -08005746 struct bnx2_napi *bnapi = &bp->bnx2_napi[0], *tx_napi;
Michael Chan35e90102008-06-19 16:37:42 -07005747 struct bnx2_tx_ring_info *txr = &bnapi->tx_ring;
Michael Chanbb4f98a2008-06-19 16:38:19 -07005748 struct bnx2_rx_ring_info *rxr = &bnapi->rx_ring;
Michael Chanc76c0472007-12-20 20:01:19 -08005749
5750 tx_napi = bnapi;
Michael Chanb6016b72005-05-26 13:03:09 -07005751
Michael Chan35e90102008-06-19 16:37:42 -07005752 txr = &tx_napi->tx_ring;
Michael Chanbb4f98a2008-06-19 16:38:19 -07005753 rxr = &bnapi->rx_ring;
Michael Chanbc5a0692006-01-23 16:13:22 -08005754 if (loopback_mode == BNX2_MAC_LOOPBACK) {
5755 bp->loopback = MAC_LOOPBACK;
5756 bnx2_set_mac_loopback(bp);
5757 }
5758 else if (loopback_mode == BNX2_PHY_LOOPBACK) {
Michael Chan583c28e2008-01-21 19:51:35 -08005759 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
Michael Chan489310a2007-10-10 16:16:31 -07005760 return 0;
5761
Michael Chan80be4432006-11-19 14:07:28 -08005762 bp->loopback = PHY_LOOPBACK;
Michael Chanbc5a0692006-01-23 16:13:22 -08005763 bnx2_set_phy_loopback(bp);
5764 }
5765 else
5766 return -EINVAL;
Michael Chanb6016b72005-05-26 13:03:09 -07005767
Michael Chan84eaa182007-12-12 11:19:57 -08005768 pkt_size = min(bp->dev->mtu + ETH_HLEN, bp->rx_jumbo_thresh - 4);
Michael Chan932f3772006-08-15 01:39:36 -07005769 skb = netdev_alloc_skb(bp->dev, pkt_size);
John W. Linvilleb6cbc3b62005-11-10 12:58:00 -08005770 if (!skb)
5771 return -ENOMEM;
Michael Chanb6016b72005-05-26 13:03:09 -07005772 packet = skb_put(skb, pkt_size);
Joe Perchesd458cdf2013-10-01 19:04:40 -07005773 memcpy(packet, bp->dev->dev_addr, ETH_ALEN);
5774 memset(packet + ETH_ALEN, 0x0, 8);
Michael Chanb6016b72005-05-26 13:03:09 -07005775 for (i = 14; i < pkt_size; i++)
5776 packet[i] = (unsigned char) (i & 0xff);
5777
Stanislaw Gruszka36227e82010-07-15 04:25:50 +00005778 map = dma_map_single(&bp->pdev->dev, skb->data, pkt_size,
5779 PCI_DMA_TODEVICE);
5780 if (dma_mapping_error(&bp->pdev->dev, map)) {
Benjamin Li3d16af82008-10-09 12:26:41 -07005781 dev_kfree_skb(skb);
5782 return -EIO;
5783 }
Michael Chanb6016b72005-05-26 13:03:09 -07005784
Michael Chane503e062012-12-06 10:33:08 +00005785 BNX2_WR(bp, BNX2_HC_COMMAND,
5786 bp->hc_cmd | BNX2_HC_COMMAND_COAL_NOW_WO_INT);
Michael Chanbf5295b2006-03-23 01:11:56 -08005787
Michael Chane503e062012-12-06 10:33:08 +00005788 BNX2_RD(bp, BNX2_HC_COMMAND);
Michael Chanb6016b72005-05-26 13:03:09 -07005789
5790 udelay(5);
Michael Chan35efa7c2007-12-20 19:56:37 -08005791 rx_start_idx = bnx2_get_hw_rx_cons(bnapi);
Michael Chanb6016b72005-05-26 13:03:09 -07005792
Michael Chanb6016b72005-05-26 13:03:09 -07005793 num_pkts = 0;
5794
Michael Chan2bc40782012-12-06 10:33:09 +00005795 txbd = &txr->tx_desc_ring[BNX2_TX_RING_IDX(txr->tx_prod)];
Michael Chanb6016b72005-05-26 13:03:09 -07005796
5797 txbd->tx_bd_haddr_hi = (u64) map >> 32;
5798 txbd->tx_bd_haddr_lo = (u64) map & 0xffffffff;
5799 txbd->tx_bd_mss_nbytes = pkt_size;
5800 txbd->tx_bd_vlan_tag_flags = TX_BD_FLAGS_START | TX_BD_FLAGS_END;
5801
5802 num_pkts++;
Michael Chan2bc40782012-12-06 10:33:09 +00005803 txr->tx_prod = BNX2_NEXT_TX_BD(txr->tx_prod);
Michael Chan35e90102008-06-19 16:37:42 -07005804 txr->tx_prod_bseq += pkt_size;
Michael Chanb6016b72005-05-26 13:03:09 -07005805
Michael Chane503e062012-12-06 10:33:08 +00005806 BNX2_WR16(bp, txr->tx_bidx_addr, txr->tx_prod);
5807 BNX2_WR(bp, txr->tx_bseq_addr, txr->tx_prod_bseq);
Michael Chanb6016b72005-05-26 13:03:09 -07005808
5809 udelay(100);
5810
Michael Chane503e062012-12-06 10:33:08 +00005811 BNX2_WR(bp, BNX2_HC_COMMAND,
5812 bp->hc_cmd | BNX2_HC_COMMAND_COAL_NOW_WO_INT);
Michael Chanbf5295b2006-03-23 01:11:56 -08005813
Michael Chane503e062012-12-06 10:33:08 +00005814 BNX2_RD(bp, BNX2_HC_COMMAND);
Michael Chanb6016b72005-05-26 13:03:09 -07005815
5816 udelay(5);
5817
Stanislaw Gruszka36227e82010-07-15 04:25:50 +00005818 dma_unmap_single(&bp->pdev->dev, map, pkt_size, PCI_DMA_TODEVICE);
Michael Chan745720e2006-06-29 12:37:41 -07005819 dev_kfree_skb(skb);
Michael Chanb6016b72005-05-26 13:03:09 -07005820
Michael Chan35e90102008-06-19 16:37:42 -07005821 if (bnx2_get_hw_tx_cons(tx_napi) != txr->tx_prod)
Michael Chanb6016b72005-05-26 13:03:09 -07005822 goto loopback_test_done;
Michael Chanb6016b72005-05-26 13:03:09 -07005823
Michael Chan35efa7c2007-12-20 19:56:37 -08005824 rx_idx = bnx2_get_hw_rx_cons(bnapi);
Michael Chanb6016b72005-05-26 13:03:09 -07005825 if (rx_idx != rx_start_idx + num_pkts) {
5826 goto loopback_test_done;
5827 }
5828
Michael Chanbb4f98a2008-06-19 16:38:19 -07005829 rx_buf = &rxr->rx_buf_ring[rx_start_idx];
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00005830 data = rx_buf->data;
Michael Chanb6016b72005-05-26 13:03:09 -07005831
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00005832 rx_hdr = get_l2_fhdr(data);
5833 data = (u8 *)rx_hdr + BNX2_RX_OFFSET;
Michael Chanb6016b72005-05-26 13:03:09 -07005834
Stanislaw Gruszka36227e82010-07-15 04:25:50 +00005835 dma_sync_single_for_cpu(&bp->pdev->dev,
FUJITA Tomonori1a4ccc22010-04-01 16:56:57 +00005836 dma_unmap_addr(rx_buf, mapping),
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00005837 bp->rx_buf_use_size, PCI_DMA_FROMDEVICE);
Michael Chanb6016b72005-05-26 13:03:09 -07005838
Michael Chanade2bfe2006-01-23 16:09:51 -08005839 if (rx_hdr->l2_fhdr_status &
Michael Chanb6016b72005-05-26 13:03:09 -07005840 (L2_FHDR_ERRORS_BAD_CRC |
5841 L2_FHDR_ERRORS_PHY_DECODE |
5842 L2_FHDR_ERRORS_ALIGNMENT |
5843 L2_FHDR_ERRORS_TOO_SHORT |
5844 L2_FHDR_ERRORS_GIANT_FRAME)) {
5845
5846 goto loopback_test_done;
5847 }
5848
5849 if ((rx_hdr->l2_fhdr_pkt_len - 4) != pkt_size) {
5850 goto loopback_test_done;
5851 }
5852
5853 for (i = 14; i < pkt_size; i++) {
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00005854 if (*(data + i) != (unsigned char) (i & 0xff)) {
Michael Chanb6016b72005-05-26 13:03:09 -07005855 goto loopback_test_done;
5856 }
5857 }
5858
5859 ret = 0;
5860
5861loopback_test_done:
5862 bp->loopback = 0;
5863 return ret;
5864}
5865
Michael Chanbc5a0692006-01-23 16:13:22 -08005866#define BNX2_MAC_LOOPBACK_FAILED 1
5867#define BNX2_PHY_LOOPBACK_FAILED 2
5868#define BNX2_LOOPBACK_FAILED (BNX2_MAC_LOOPBACK_FAILED | \
5869 BNX2_PHY_LOOPBACK_FAILED)
5870
5871static int
5872bnx2_test_loopback(struct bnx2 *bp)
5873{
5874 int rc = 0;
5875
5876 if (!netif_running(bp->dev))
5877 return BNX2_LOOPBACK_FAILED;
5878
5879 bnx2_reset_nic(bp, BNX2_DRV_MSG_CODE_RESET);
5880 spin_lock_bh(&bp->phy_lock);
Michael Chan9a120bc2008-05-16 22:17:45 -07005881 bnx2_init_phy(bp, 1);
Michael Chanbc5a0692006-01-23 16:13:22 -08005882 spin_unlock_bh(&bp->phy_lock);
5883 if (bnx2_run_loopback(bp, BNX2_MAC_LOOPBACK))
5884 rc |= BNX2_MAC_LOOPBACK_FAILED;
5885 if (bnx2_run_loopback(bp, BNX2_PHY_LOOPBACK))
5886 rc |= BNX2_PHY_LOOPBACK_FAILED;
5887 return rc;
5888}
5889
Michael Chanb6016b72005-05-26 13:03:09 -07005890#define NVRAM_SIZE 0x200
5891#define CRC32_RESIDUAL 0xdebb20e3
5892
5893static int
5894bnx2_test_nvram(struct bnx2 *bp)
5895{
Al Virob491edd2007-12-22 19:44:51 +00005896 __be32 buf[NVRAM_SIZE / 4];
Michael Chanb6016b72005-05-26 13:03:09 -07005897 u8 *data = (u8 *) buf;
5898 int rc = 0;
5899 u32 magic, csum;
5900
5901 if ((rc = bnx2_nvram_read(bp, 0, data, 4)) != 0)
5902 goto test_nvram_done;
5903
5904 magic = be32_to_cpu(buf[0]);
5905 if (magic != 0x669955aa) {
5906 rc = -ENODEV;
5907 goto test_nvram_done;
5908 }
5909
5910 if ((rc = bnx2_nvram_read(bp, 0x100, data, NVRAM_SIZE)) != 0)
5911 goto test_nvram_done;
5912
5913 csum = ether_crc_le(0x100, data);
5914 if (csum != CRC32_RESIDUAL) {
5915 rc = -ENODEV;
5916 goto test_nvram_done;
5917 }
5918
5919 csum = ether_crc_le(0x100, data + 0x100);
5920 if (csum != CRC32_RESIDUAL) {
5921 rc = -ENODEV;
5922 }
5923
5924test_nvram_done:
5925 return rc;
5926}
5927
5928static int
5929bnx2_test_link(struct bnx2 *bp)
5930{
5931 u32 bmsr;
5932
Michael Chan9f52b562008-10-09 12:21:46 -07005933 if (!netif_running(bp->dev))
5934 return -ENODEV;
5935
Michael Chan583c28e2008-01-21 19:51:35 -08005936 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP) {
Michael Chan489310a2007-10-10 16:16:31 -07005937 if (bp->link_up)
5938 return 0;
5939 return -ENODEV;
5940 }
Michael Chanc770a652005-08-25 15:38:39 -07005941 spin_lock_bh(&bp->phy_lock);
Michael Chan27a005b2007-05-03 13:23:41 -07005942 bnx2_enable_bmsr1(bp);
5943 bnx2_read_phy(bp, bp->mii_bmsr1, &bmsr);
5944 bnx2_read_phy(bp, bp->mii_bmsr1, &bmsr);
5945 bnx2_disable_bmsr1(bp);
Michael Chanc770a652005-08-25 15:38:39 -07005946 spin_unlock_bh(&bp->phy_lock);
Jeff Garzik6aa20a22006-09-13 13:24:59 -04005947
Michael Chanb6016b72005-05-26 13:03:09 -07005948 if (bmsr & BMSR_LSTATUS) {
5949 return 0;
5950 }
5951 return -ENODEV;
5952}
5953
5954static int
5955bnx2_test_intr(struct bnx2 *bp)
5956{
5957 int i;
Michael Chanb6016b72005-05-26 13:03:09 -07005958 u16 status_idx;
5959
5960 if (!netif_running(bp->dev))
5961 return -ENODEV;
5962
Michael Chane503e062012-12-06 10:33:08 +00005963 status_idx = BNX2_RD(bp, BNX2_PCICFG_INT_ACK_CMD) & 0xffff;
Michael Chanb6016b72005-05-26 13:03:09 -07005964
5965 /* This register is not touched during run-time. */
Michael Chane503e062012-12-06 10:33:08 +00005966 BNX2_WR(bp, BNX2_HC_COMMAND, bp->hc_cmd | BNX2_HC_COMMAND_COAL_NOW);
5967 BNX2_RD(bp, BNX2_HC_COMMAND);
Michael Chanb6016b72005-05-26 13:03:09 -07005968
5969 for (i = 0; i < 10; i++) {
Michael Chane503e062012-12-06 10:33:08 +00005970 if ((BNX2_RD(bp, BNX2_PCICFG_INT_ACK_CMD) & 0xffff) !=
Michael Chanb6016b72005-05-26 13:03:09 -07005971 status_idx) {
5972
5973 break;
5974 }
5975
5976 msleep_interruptible(10);
5977 }
5978 if (i < 10)
5979 return 0;
5980
5981 return -ENODEV;
5982}
5983
Michael Chan38ea3682008-02-23 19:48:57 -08005984/* Determining link for parallel detection. */
Michael Chanb2fadea2008-01-21 17:07:06 -08005985static int
5986bnx2_5706_serdes_has_link(struct bnx2 *bp)
5987{
5988 u32 mode_ctl, an_dbg, exp;
5989
Michael Chan38ea3682008-02-23 19:48:57 -08005990 if (bp->phy_flags & BNX2_PHY_FLAG_NO_PARALLEL)
5991 return 0;
5992
Michael Chanb2fadea2008-01-21 17:07:06 -08005993 bnx2_write_phy(bp, MII_BNX2_MISC_SHADOW, MISC_SHDW_MODE_CTL);
5994 bnx2_read_phy(bp, MII_BNX2_MISC_SHADOW, &mode_ctl);
5995
5996 if (!(mode_ctl & MISC_SHDW_MODE_CTL_SIG_DET))
5997 return 0;
5998
5999 bnx2_write_phy(bp, MII_BNX2_MISC_SHADOW, MISC_SHDW_AN_DBG);
6000 bnx2_read_phy(bp, MII_BNX2_MISC_SHADOW, &an_dbg);
6001 bnx2_read_phy(bp, MII_BNX2_MISC_SHADOW, &an_dbg);
6002
Michael Chanf3014c0c2008-01-29 21:33:03 -08006003 if (an_dbg & (MISC_SHDW_AN_DBG_NOSYNC | MISC_SHDW_AN_DBG_RUDI_INVALID))
Michael Chanb2fadea2008-01-21 17:07:06 -08006004 return 0;
6005
6006 bnx2_write_phy(bp, MII_BNX2_DSP_ADDRESS, MII_EXPAND_REG1);
6007 bnx2_read_phy(bp, MII_BNX2_DSP_RW_PORT, &exp);
6008 bnx2_read_phy(bp, MII_BNX2_DSP_RW_PORT, &exp);
6009
6010 if (exp & MII_EXPAND_REG1_RUDI_C) /* receiving CONFIG */
6011 return 0;
6012
6013 return 1;
6014}
6015
Michael Chanb6016b72005-05-26 13:03:09 -07006016static void
Michael Chan48b01e22006-11-19 14:08:00 -08006017bnx2_5706_serdes_timer(struct bnx2 *bp)
6018{
Michael Chanb2fadea2008-01-21 17:07:06 -08006019 int check_link = 1;
6020
Michael Chan48b01e22006-11-19 14:08:00 -08006021 spin_lock(&bp->phy_lock);
Michael Chanb2fadea2008-01-21 17:07:06 -08006022 if (bp->serdes_an_pending) {
Michael Chan48b01e22006-11-19 14:08:00 -08006023 bp->serdes_an_pending--;
Michael Chanb2fadea2008-01-21 17:07:06 -08006024 check_link = 0;
6025 } else if ((bp->link_up == 0) && (bp->autoneg & AUTONEG_SPEED)) {
Michael Chan48b01e22006-11-19 14:08:00 -08006026 u32 bmcr;
6027
Benjamin Liac392ab2008-09-18 16:40:49 -07006028 bp->current_interval = BNX2_TIMER_INTERVAL;
Michael Chan48b01e22006-11-19 14:08:00 -08006029
Michael Chanca58c3a2007-05-03 13:22:52 -07006030 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chan48b01e22006-11-19 14:08:00 -08006031
6032 if (bmcr & BMCR_ANENABLE) {
Michael Chanb2fadea2008-01-21 17:07:06 -08006033 if (bnx2_5706_serdes_has_link(bp)) {
Michael Chan48b01e22006-11-19 14:08:00 -08006034 bmcr &= ~BMCR_ANENABLE;
6035 bmcr |= BMCR_SPEED1000 | BMCR_FULLDPLX;
Michael Chanca58c3a2007-05-03 13:22:52 -07006036 bnx2_write_phy(bp, bp->mii_bmcr, bmcr);
Michael Chan583c28e2008-01-21 19:51:35 -08006037 bp->phy_flags |= BNX2_PHY_FLAG_PARALLEL_DETECT;
Michael Chan48b01e22006-11-19 14:08:00 -08006038 }
6039 }
6040 }
6041 else if ((bp->link_up) && (bp->autoneg & AUTONEG_SPEED) &&
Michael Chan583c28e2008-01-21 19:51:35 -08006042 (bp->phy_flags & BNX2_PHY_FLAG_PARALLEL_DETECT)) {
Michael Chan48b01e22006-11-19 14:08:00 -08006043 u32 phy2;
6044
6045 bnx2_write_phy(bp, 0x17, 0x0f01);
6046 bnx2_read_phy(bp, 0x15, &phy2);
6047 if (phy2 & 0x20) {
6048 u32 bmcr;
6049
Michael Chanca58c3a2007-05-03 13:22:52 -07006050 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chan48b01e22006-11-19 14:08:00 -08006051 bmcr |= BMCR_ANENABLE;
Michael Chanca58c3a2007-05-03 13:22:52 -07006052 bnx2_write_phy(bp, bp->mii_bmcr, bmcr);
Michael Chan48b01e22006-11-19 14:08:00 -08006053
Michael Chan583c28e2008-01-21 19:51:35 -08006054 bp->phy_flags &= ~BNX2_PHY_FLAG_PARALLEL_DETECT;
Michael Chan48b01e22006-11-19 14:08:00 -08006055 }
6056 } else
Benjamin Liac392ab2008-09-18 16:40:49 -07006057 bp->current_interval = BNX2_TIMER_INTERVAL;
Michael Chan48b01e22006-11-19 14:08:00 -08006058
Michael Chana2724e22008-02-23 19:47:44 -08006059 if (check_link) {
Michael Chanb2fadea2008-01-21 17:07:06 -08006060 u32 val;
6061
6062 bnx2_write_phy(bp, MII_BNX2_MISC_SHADOW, MISC_SHDW_AN_DBG);
6063 bnx2_read_phy(bp, MII_BNX2_MISC_SHADOW, &val);
6064 bnx2_read_phy(bp, MII_BNX2_MISC_SHADOW, &val);
6065
Michael Chana2724e22008-02-23 19:47:44 -08006066 if (bp->link_up && (val & MISC_SHDW_AN_DBG_NOSYNC)) {
6067 if (!(bp->phy_flags & BNX2_PHY_FLAG_FORCED_DOWN)) {
6068 bnx2_5706s_force_link_dn(bp, 1);
6069 bp->phy_flags |= BNX2_PHY_FLAG_FORCED_DOWN;
6070 } else
6071 bnx2_set_link(bp);
6072 } else if (!bp->link_up && !(val & MISC_SHDW_AN_DBG_NOSYNC))
6073 bnx2_set_link(bp);
Michael Chanb2fadea2008-01-21 17:07:06 -08006074 }
Michael Chan48b01e22006-11-19 14:08:00 -08006075 spin_unlock(&bp->phy_lock);
6076}
6077
6078static void
Michael Chanf8dd0642006-11-19 14:08:29 -08006079bnx2_5708_serdes_timer(struct bnx2 *bp)
6080{
Michael Chan583c28e2008-01-21 19:51:35 -08006081 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
Michael Chan0d8a6572007-07-07 22:49:43 -07006082 return;
6083
Michael Chan583c28e2008-01-21 19:51:35 -08006084 if ((bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE) == 0) {
Michael Chanf8dd0642006-11-19 14:08:29 -08006085 bp->serdes_an_pending = 0;
6086 return;
6087 }
6088
6089 spin_lock(&bp->phy_lock);
6090 if (bp->serdes_an_pending)
6091 bp->serdes_an_pending--;
6092 else if ((bp->link_up == 0) && (bp->autoneg & AUTONEG_SPEED)) {
6093 u32 bmcr;
6094
Michael Chanca58c3a2007-05-03 13:22:52 -07006095 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chanf8dd0642006-11-19 14:08:29 -08006096 if (bmcr & BMCR_ANENABLE) {
Michael Chan605a9e22007-05-03 13:23:13 -07006097 bnx2_enable_forced_2g5(bp);
Michael Chan40105c02008-11-12 16:02:45 -08006098 bp->current_interval = BNX2_SERDES_FORCED_TIMEOUT;
Michael Chanf8dd0642006-11-19 14:08:29 -08006099 } else {
Michael Chan605a9e22007-05-03 13:23:13 -07006100 bnx2_disable_forced_2g5(bp);
Michael Chanf8dd0642006-11-19 14:08:29 -08006101 bp->serdes_an_pending = 2;
Benjamin Liac392ab2008-09-18 16:40:49 -07006102 bp->current_interval = BNX2_TIMER_INTERVAL;
Michael Chanf8dd0642006-11-19 14:08:29 -08006103 }
6104
6105 } else
Benjamin Liac392ab2008-09-18 16:40:49 -07006106 bp->current_interval = BNX2_TIMER_INTERVAL;
Michael Chanf8dd0642006-11-19 14:08:29 -08006107
6108 spin_unlock(&bp->phy_lock);
6109}
6110
6111static void
Michael Chanb6016b72005-05-26 13:03:09 -07006112bnx2_timer(unsigned long data)
6113{
6114 struct bnx2 *bp = (struct bnx2 *) data;
Michael Chanb6016b72005-05-26 13:03:09 -07006115
Michael Chancd339a02005-08-25 15:35:24 -07006116 if (!netif_running(bp->dev))
6117 return;
6118
Michael Chanb6016b72005-05-26 13:03:09 -07006119 if (atomic_read(&bp->intr_sem) != 0)
6120 goto bnx2_restart_timer;
6121
Michael Chanefba0182008-12-03 00:36:15 -08006122 if ((bp->flags & (BNX2_FLAG_USING_MSI | BNX2_FLAG_ONE_SHOT_MSI)) ==
6123 BNX2_FLAG_USING_MSI)
6124 bnx2_chk_missed_msi(bp);
6125
Michael Chandf149d72007-07-07 22:51:36 -07006126 bnx2_send_heart_beat(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07006127
Michael Chan2726d6e2008-01-29 21:35:05 -08006128 bp->stats_blk->stat_FwRxDrop =
6129 bnx2_reg_rd_ind(bp, BNX2_FW_RX_DROP_COUNT);
Michael Chancea94db2006-06-12 22:16:13 -07006130
Michael Chan02537b062007-06-04 21:24:07 -07006131 /* workaround occasional corrupted counters */
Michael Chan61d9e3f2009-08-21 16:20:46 +00006132 if ((bp->flags & BNX2_FLAG_BROKEN_STATS) && bp->stats_ticks)
Michael Chane503e062012-12-06 10:33:08 +00006133 BNX2_WR(bp, BNX2_HC_COMMAND, bp->hc_cmd |
6134 BNX2_HC_COMMAND_STATS_NOW);
Michael Chan02537b062007-06-04 21:24:07 -07006135
Michael Chan583c28e2008-01-21 19:51:35 -08006136 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Michael Chan4ce45e02012-12-06 10:33:10 +00006137 if (BNX2_CHIP(bp) == BNX2_CHIP_5706)
Michael Chanf8dd0642006-11-19 14:08:29 -08006138 bnx2_5706_serdes_timer(bp);
Michael Chan27a005b2007-05-03 13:23:41 -07006139 else
Michael Chanf8dd0642006-11-19 14:08:29 -08006140 bnx2_5708_serdes_timer(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07006141 }
6142
6143bnx2_restart_timer:
Michael Chancd339a02005-08-25 15:35:24 -07006144 mod_timer(&bp->timer, jiffies + bp->current_interval);
Michael Chanb6016b72005-05-26 13:03:09 -07006145}
6146
Michael Chan8e6a72c2007-05-03 13:24:48 -07006147static int
6148bnx2_request_irq(struct bnx2 *bp)
6149{
Michael Chan6d866ff2007-12-20 19:56:09 -08006150 unsigned long flags;
Michael Chanb4b36042007-12-20 19:59:30 -08006151 struct bnx2_irq *irq;
6152 int rc = 0, i;
Michael Chan8e6a72c2007-05-03 13:24:48 -07006153
David S. Millerf86e82f2008-01-21 17:15:40 -08006154 if (bp->flags & BNX2_FLAG_USING_MSI_OR_MSIX)
Michael Chan6d866ff2007-12-20 19:56:09 -08006155 flags = 0;
6156 else
6157 flags = IRQF_SHARED;
Michael Chanb4b36042007-12-20 19:59:30 -08006158
6159 for (i = 0; i < bp->irq_nvecs; i++) {
6160 irq = &bp->irq_tbl[i];
Michael Chanc76c0472007-12-20 20:01:19 -08006161 rc = request_irq(irq->vector, irq->handler, flags, irq->name,
Michael Chanf0ea2e62008-06-19 16:41:57 -07006162 &bp->bnx2_napi[i]);
Michael Chanb4b36042007-12-20 19:59:30 -08006163 if (rc)
6164 break;
6165 irq->requested = 1;
6166 }
Michael Chan8e6a72c2007-05-03 13:24:48 -07006167 return rc;
6168}
6169
6170static void
Michael Chana29ba9d2010-12-31 11:03:14 -08006171__bnx2_free_irq(struct bnx2 *bp)
Michael Chan8e6a72c2007-05-03 13:24:48 -07006172{
Michael Chanb4b36042007-12-20 19:59:30 -08006173 struct bnx2_irq *irq;
6174 int i;
Michael Chan8e6a72c2007-05-03 13:24:48 -07006175
Michael Chanb4b36042007-12-20 19:59:30 -08006176 for (i = 0; i < bp->irq_nvecs; i++) {
6177 irq = &bp->irq_tbl[i];
6178 if (irq->requested)
Michael Chanf0ea2e62008-06-19 16:41:57 -07006179 free_irq(irq->vector, &bp->bnx2_napi[i]);
Michael Chanb4b36042007-12-20 19:59:30 -08006180 irq->requested = 0;
Michael Chan6d866ff2007-12-20 19:56:09 -08006181 }
Michael Chana29ba9d2010-12-31 11:03:14 -08006182}
6183
6184static void
6185bnx2_free_irq(struct bnx2 *bp)
6186{
6187
6188 __bnx2_free_irq(bp);
David S. Millerf86e82f2008-01-21 17:15:40 -08006189 if (bp->flags & BNX2_FLAG_USING_MSI)
Michael Chanb4b36042007-12-20 19:59:30 -08006190 pci_disable_msi(bp->pdev);
David S. Millerf86e82f2008-01-21 17:15:40 -08006191 else if (bp->flags & BNX2_FLAG_USING_MSIX)
Michael Chanb4b36042007-12-20 19:59:30 -08006192 pci_disable_msix(bp->pdev);
6193
David S. Millerf86e82f2008-01-21 17:15:40 -08006194 bp->flags &= ~(BNX2_FLAG_USING_MSI_OR_MSIX | BNX2_FLAG_ONE_SHOT_MSI);
Michael Chanb4b36042007-12-20 19:59:30 -08006195}
6196
6197static void
Michael Chan5e9ad9e2008-06-19 16:43:17 -07006198bnx2_enable_msix(struct bnx2 *bp, int msix_vecs)
Michael Chanb4b36042007-12-20 19:59:30 -08006199{
Michael Chan379b39a2010-07-19 14:15:03 +00006200 int i, total_vecs, rc;
Michael Chan57851d82007-12-20 20:01:44 -08006201 struct msix_entry msix_ent[BNX2_MAX_MSIX_VEC];
Michael Chan4e1d0de2008-12-16 20:27:45 -08006202 struct net_device *dev = bp->dev;
6203 const int len = sizeof(bp->irq_tbl[0].name);
Michael Chan57851d82007-12-20 20:01:44 -08006204
Michael Chanb4b36042007-12-20 19:59:30 -08006205 bnx2_setup_msix_tbl(bp);
Michael Chane503e062012-12-06 10:33:08 +00006206 BNX2_WR(bp, BNX2_PCI_MSIX_CONTROL, BNX2_MAX_MSIX_HW_VEC - 1);
6207 BNX2_WR(bp, BNX2_PCI_MSIX_TBL_OFF_BIR, BNX2_PCI_GRC_WINDOW2_BASE);
6208 BNX2_WR(bp, BNX2_PCI_MSIX_PBA_OFF_BIT, BNX2_PCI_GRC_WINDOW3_BASE);
Michael Chan57851d82007-12-20 20:01:44 -08006209
Benjamin Lie2eb8e32010-01-08 00:51:21 -08006210 /* Need to flush the previous three writes to ensure MSI-X
6211 * is setup properly */
Michael Chane503e062012-12-06 10:33:08 +00006212 BNX2_RD(bp, BNX2_PCI_MSIX_CONTROL);
Benjamin Lie2eb8e32010-01-08 00:51:21 -08006213
Michael Chan57851d82007-12-20 20:01:44 -08006214 for (i = 0; i < BNX2_MAX_MSIX_VEC; i++) {
6215 msix_ent[i].entry = i;
6216 msix_ent[i].vector = 0;
6217 }
6218
Michael Chan379b39a2010-07-19 14:15:03 +00006219 total_vecs = msix_vecs;
6220#ifdef BCM_CNIC
6221 total_vecs++;
6222#endif
6223 rc = -ENOSPC;
6224 while (total_vecs >= BNX2_MIN_MSIX_VEC) {
6225 rc = pci_enable_msix(bp->pdev, msix_ent, total_vecs);
6226 if (rc <= 0)
6227 break;
6228 if (rc > 0)
6229 total_vecs = rc;
6230 }
6231
Michael Chan57851d82007-12-20 20:01:44 -08006232 if (rc != 0)
6233 return;
6234
Michael Chan379b39a2010-07-19 14:15:03 +00006235 msix_vecs = total_vecs;
6236#ifdef BCM_CNIC
6237 msix_vecs--;
6238#endif
Michael Chan5e9ad9e2008-06-19 16:43:17 -07006239 bp->irq_nvecs = msix_vecs;
David S. Millerf86e82f2008-01-21 17:15:40 -08006240 bp->flags |= BNX2_FLAG_USING_MSIX | BNX2_FLAG_ONE_SHOT_MSI;
Michael Chan379b39a2010-07-19 14:15:03 +00006241 for (i = 0; i < total_vecs; i++) {
Michael Chan57851d82007-12-20 20:01:44 -08006242 bp->irq_tbl[i].vector = msix_ent[i].vector;
Michael Chan69010312009-03-18 18:11:51 -07006243 snprintf(bp->irq_tbl[i].name, len, "%s-%d", dev->name, i);
6244 bp->irq_tbl[i].handler = bnx2_msi_1shot;
6245 }
Michael Chan6d866ff2007-12-20 19:56:09 -08006246}
6247
Ben Hutchings657d92f2010-09-27 08:25:16 +00006248static int
Michael Chan6d866ff2007-12-20 19:56:09 -08006249bnx2_setup_int_mode(struct bnx2 *bp, int dis_msi)
6250{
Yuval Mintz0a742122012-07-01 03:18:58 +00006251 int cpus = netif_get_num_default_rss_queues();
Michael Chanb0332812012-02-05 15:24:38 +00006252 int msix_vecs;
6253
6254 if (!bp->num_req_rx_rings)
6255 msix_vecs = max(cpus + 1, bp->num_req_tx_rings);
6256 else if (!bp->num_req_tx_rings)
6257 msix_vecs = max(cpus, bp->num_req_rx_rings);
6258 else
6259 msix_vecs = max(bp->num_req_rx_rings, bp->num_req_tx_rings);
6260
6261 msix_vecs = min(msix_vecs, RX_MAX_RINGS);
Michael Chan5e9ad9e2008-06-19 16:43:17 -07006262
Michael Chan6d866ff2007-12-20 19:56:09 -08006263 bp->irq_tbl[0].handler = bnx2_interrupt;
6264 strcpy(bp->irq_tbl[0].name, bp->dev->name);
Michael Chanb4b36042007-12-20 19:59:30 -08006265 bp->irq_nvecs = 1;
6266 bp->irq_tbl[0].vector = bp->pdev->irq;
Michael Chan6d866ff2007-12-20 19:56:09 -08006267
Michael Chan3d5f3a72010-07-03 20:42:15 +00006268 if ((bp->flags & BNX2_FLAG_MSIX_CAP) && !dis_msi)
Michael Chan5e9ad9e2008-06-19 16:43:17 -07006269 bnx2_enable_msix(bp, msix_vecs);
Michael Chanb4b36042007-12-20 19:59:30 -08006270
David S. Millerf86e82f2008-01-21 17:15:40 -08006271 if ((bp->flags & BNX2_FLAG_MSI_CAP) && !dis_msi &&
6272 !(bp->flags & BNX2_FLAG_USING_MSIX)) {
Michael Chan6d866ff2007-12-20 19:56:09 -08006273 if (pci_enable_msi(bp->pdev) == 0) {
David S. Millerf86e82f2008-01-21 17:15:40 -08006274 bp->flags |= BNX2_FLAG_USING_MSI;
Michael Chan4ce45e02012-12-06 10:33:10 +00006275 if (BNX2_CHIP(bp) == BNX2_CHIP_5709) {
David S. Millerf86e82f2008-01-21 17:15:40 -08006276 bp->flags |= BNX2_FLAG_ONE_SHOT_MSI;
Michael Chan6d866ff2007-12-20 19:56:09 -08006277 bp->irq_tbl[0].handler = bnx2_msi_1shot;
6278 } else
6279 bp->irq_tbl[0].handler = bnx2_msi;
Michael Chanb4b36042007-12-20 19:59:30 -08006280
6281 bp->irq_tbl[0].vector = bp->pdev->irq;
Michael Chan6d866ff2007-12-20 19:56:09 -08006282 }
6283 }
Benjamin Li706bf242008-07-18 17:55:11 -07006284
Michael Chanb0332812012-02-05 15:24:38 +00006285 if (!bp->num_req_tx_rings)
6286 bp->num_tx_rings = rounddown_pow_of_two(bp->irq_nvecs);
6287 else
6288 bp->num_tx_rings = min(bp->irq_nvecs, bp->num_req_tx_rings);
6289
6290 if (!bp->num_req_rx_rings)
6291 bp->num_rx_rings = bp->irq_nvecs;
6292 else
6293 bp->num_rx_rings = min(bp->irq_nvecs, bp->num_req_rx_rings);
6294
Ben Hutchings657d92f2010-09-27 08:25:16 +00006295 netif_set_real_num_tx_queues(bp->dev, bp->num_tx_rings);
Benjamin Li706bf242008-07-18 17:55:11 -07006296
Ben Hutchings657d92f2010-09-27 08:25:16 +00006297 return netif_set_real_num_rx_queues(bp->dev, bp->num_rx_rings);
Michael Chan8e6a72c2007-05-03 13:24:48 -07006298}
6299
Michael Chanb6016b72005-05-26 13:03:09 -07006300/* Called with rtnl_lock */
6301static int
6302bnx2_open(struct net_device *dev)
6303{
Michael Chan972ec0d2006-01-23 16:12:43 -08006304 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006305 int rc;
6306
françois romieu7880b722011-09-30 00:36:52 +00006307 rc = bnx2_request_firmware(bp);
6308 if (rc < 0)
6309 goto out;
6310
Michael Chan1b2f9222007-05-03 13:20:19 -07006311 netif_carrier_off(dev);
6312
Michael Chanb6016b72005-05-26 13:03:09 -07006313 bnx2_disable_int(bp);
6314
Ben Hutchings657d92f2010-09-27 08:25:16 +00006315 rc = bnx2_setup_int_mode(bp, disable_msi);
6316 if (rc)
6317 goto open_err;
Benjamin Li4327ba42010-03-23 13:13:11 +00006318 bnx2_init_napi(bp);
Michael Chan35efa7c2007-12-20 19:56:37 -08006319 bnx2_napi_enable(bp);
Michael Chan35e90102008-06-19 16:37:42 -07006320 rc = bnx2_alloc_mem(bp);
Michael Chan2739a8b2008-06-19 16:44:10 -07006321 if (rc)
6322 goto open_err;
Michael Chan35e90102008-06-19 16:37:42 -07006323
Michael Chan8e6a72c2007-05-03 13:24:48 -07006324 rc = bnx2_request_irq(bp);
Michael Chan2739a8b2008-06-19 16:44:10 -07006325 if (rc)
6326 goto open_err;
Michael Chanb6016b72005-05-26 13:03:09 -07006327
Michael Chan9a120bc2008-05-16 22:17:45 -07006328 rc = bnx2_init_nic(bp, 1);
Michael Chan2739a8b2008-06-19 16:44:10 -07006329 if (rc)
6330 goto open_err;
Jeff Garzik6aa20a22006-09-13 13:24:59 -04006331
Michael Chancd339a02005-08-25 15:35:24 -07006332 mod_timer(&bp->timer, jiffies + bp->current_interval);
Michael Chanb6016b72005-05-26 13:03:09 -07006333
6334 atomic_set(&bp->intr_sem, 0);
6335
Michael Chan354fcd72010-01-17 07:30:44 +00006336 memset(bp->temp_stats_blk, 0, sizeof(struct statistics_block));
6337
Michael Chanb6016b72005-05-26 13:03:09 -07006338 bnx2_enable_int(bp);
6339
David S. Millerf86e82f2008-01-21 17:15:40 -08006340 if (bp->flags & BNX2_FLAG_USING_MSI) {
Michael Chanb6016b72005-05-26 13:03:09 -07006341 /* Test MSI to make sure it is working
6342 * If MSI test fails, go back to INTx mode
6343 */
6344 if (bnx2_test_intr(bp) != 0) {
Joe Perches3a9c6a42010-02-17 15:01:51 +00006345 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 -07006346
6347 bnx2_disable_int(bp);
Michael Chan8e6a72c2007-05-03 13:24:48 -07006348 bnx2_free_irq(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07006349
Michael Chan6d866ff2007-12-20 19:56:09 -08006350 bnx2_setup_int_mode(bp, 1);
6351
Michael Chan9a120bc2008-05-16 22:17:45 -07006352 rc = bnx2_init_nic(bp, 0);
Michael Chanb6016b72005-05-26 13:03:09 -07006353
Michael Chan8e6a72c2007-05-03 13:24:48 -07006354 if (!rc)
6355 rc = bnx2_request_irq(bp);
6356
Michael Chanb6016b72005-05-26 13:03:09 -07006357 if (rc) {
Michael Chanb6016b72005-05-26 13:03:09 -07006358 del_timer_sync(&bp->timer);
Michael Chan2739a8b2008-06-19 16:44:10 -07006359 goto open_err;
Michael Chanb6016b72005-05-26 13:03:09 -07006360 }
6361 bnx2_enable_int(bp);
6362 }
6363 }
David S. Millerf86e82f2008-01-21 17:15:40 -08006364 if (bp->flags & BNX2_FLAG_USING_MSI)
Joe Perches3a9c6a42010-02-17 15:01:51 +00006365 netdev_info(dev, "using MSI\n");
David S. Millerf86e82f2008-01-21 17:15:40 -08006366 else if (bp->flags & BNX2_FLAG_USING_MSIX)
Joe Perches3a9c6a42010-02-17 15:01:51 +00006367 netdev_info(dev, "using MSIX\n");
Michael Chanb6016b72005-05-26 13:03:09 -07006368
Benjamin Li706bf242008-07-18 17:55:11 -07006369 netif_tx_start_all_queues(dev);
françois romieu7880b722011-09-30 00:36:52 +00006370out:
6371 return rc;
Michael Chan2739a8b2008-06-19 16:44:10 -07006372
6373open_err:
6374 bnx2_napi_disable(bp);
6375 bnx2_free_skbs(bp);
6376 bnx2_free_irq(bp);
6377 bnx2_free_mem(bp);
Michael Chanf048fa92010-06-01 15:05:36 +00006378 bnx2_del_napi(bp);
françois romieu7880b722011-09-30 00:36:52 +00006379 bnx2_release_firmware(bp);
6380 goto out;
Michael Chanb6016b72005-05-26 13:03:09 -07006381}
6382
6383static void
David Howellsc4028952006-11-22 14:57:56 +00006384bnx2_reset_task(struct work_struct *work)
Michael Chanb6016b72005-05-26 13:03:09 -07006385{
David Howellsc4028952006-11-22 14:57:56 +00006386 struct bnx2 *bp = container_of(work, struct bnx2, reset_task);
Michael Chancd634012011-07-15 06:53:58 +00006387 int rc;
Michael Chanefdfad32012-07-16 14:25:56 +00006388 u16 pcicmd;
Michael Chanb6016b72005-05-26 13:03:09 -07006389
Michael Chan51bf6bb2009-12-03 09:46:31 +00006390 rtnl_lock();
6391 if (!netif_running(bp->dev)) {
6392 rtnl_unlock();
Michael Chanafdc08b2005-08-25 15:34:29 -07006393 return;
Michael Chan51bf6bb2009-12-03 09:46:31 +00006394 }
Michael Chanafdc08b2005-08-25 15:34:29 -07006395
Michael Chan212f9932010-04-27 11:28:10 +00006396 bnx2_netif_stop(bp, true);
Michael Chanb6016b72005-05-26 13:03:09 -07006397
Michael Chanefdfad32012-07-16 14:25:56 +00006398 pci_read_config_word(bp->pdev, PCI_COMMAND, &pcicmd);
6399 if (!(pcicmd & PCI_COMMAND_MEMORY)) {
6400 /* in case PCI block has reset */
6401 pci_restore_state(bp->pdev);
6402 pci_save_state(bp->pdev);
6403 }
Michael Chancd634012011-07-15 06:53:58 +00006404 rc = bnx2_init_nic(bp, 1);
6405 if (rc) {
6406 netdev_err(bp->dev, "failed to reset NIC, closing\n");
6407 bnx2_napi_enable(bp);
6408 dev_close(bp->dev);
6409 rtnl_unlock();
6410 return;
6411 }
Michael Chanb6016b72005-05-26 13:03:09 -07006412
6413 atomic_set(&bp->intr_sem, 1);
Michael Chan212f9932010-04-27 11:28:10 +00006414 bnx2_netif_start(bp, true);
Michael Chan51bf6bb2009-12-03 09:46:31 +00006415 rtnl_unlock();
Michael Chanb6016b72005-05-26 13:03:09 -07006416}
6417
Michael Chan555069d2012-06-16 15:45:41 +00006418#define BNX2_FTQ_ENTRY(ftq) { __stringify(ftq##FTQ_CTL), BNX2_##ftq##FTQ_CTL }
6419
6420static void
6421bnx2_dump_ftq(struct bnx2 *bp)
6422{
6423 int i;
6424 u32 reg, bdidx, cid, valid;
6425 struct net_device *dev = bp->dev;
6426 static const struct ftq_reg {
6427 char *name;
6428 u32 off;
6429 } ftq_arr[] = {
6430 BNX2_FTQ_ENTRY(RV2P_P),
6431 BNX2_FTQ_ENTRY(RV2P_T),
6432 BNX2_FTQ_ENTRY(RV2P_M),
6433 BNX2_FTQ_ENTRY(TBDR_),
6434 BNX2_FTQ_ENTRY(TDMA_),
6435 BNX2_FTQ_ENTRY(TXP_),
6436 BNX2_FTQ_ENTRY(TXP_),
6437 BNX2_FTQ_ENTRY(TPAT_),
6438 BNX2_FTQ_ENTRY(RXP_C),
6439 BNX2_FTQ_ENTRY(RXP_),
6440 BNX2_FTQ_ENTRY(COM_COMXQ_),
6441 BNX2_FTQ_ENTRY(COM_COMTQ_),
6442 BNX2_FTQ_ENTRY(COM_COMQ_),
6443 BNX2_FTQ_ENTRY(CP_CPQ_),
6444 };
6445
6446 netdev_err(dev, "<--- start FTQ dump --->\n");
6447 for (i = 0; i < ARRAY_SIZE(ftq_arr); i++)
6448 netdev_err(dev, "%s %08x\n", ftq_arr[i].name,
6449 bnx2_reg_rd_ind(bp, ftq_arr[i].off));
6450
6451 netdev_err(dev, "CPU states:\n");
6452 for (reg = BNX2_TXP_CPU_MODE; reg <= BNX2_CP_CPU_MODE; reg += 0x40000)
6453 netdev_err(dev, "%06x mode %x state %x evt_mask %x pc %x pc %x instr %x\n",
6454 reg, bnx2_reg_rd_ind(bp, reg),
6455 bnx2_reg_rd_ind(bp, reg + 4),
6456 bnx2_reg_rd_ind(bp, reg + 8),
6457 bnx2_reg_rd_ind(bp, reg + 0x1c),
6458 bnx2_reg_rd_ind(bp, reg + 0x1c),
6459 bnx2_reg_rd_ind(bp, reg + 0x20));
6460
6461 netdev_err(dev, "<--- end FTQ dump --->\n");
6462 netdev_err(dev, "<--- start TBDC dump --->\n");
6463 netdev_err(dev, "TBDC free cnt: %ld\n",
Michael Chane503e062012-12-06 10:33:08 +00006464 BNX2_RD(bp, BNX2_TBDC_STATUS) & BNX2_TBDC_STATUS_FREE_CNT);
Michael Chan555069d2012-06-16 15:45:41 +00006465 netdev_err(dev, "LINE CID BIDX CMD VALIDS\n");
6466 for (i = 0; i < 0x20; i++) {
6467 int j = 0;
6468
Michael Chane503e062012-12-06 10:33:08 +00006469 BNX2_WR(bp, BNX2_TBDC_BD_ADDR, i);
6470 BNX2_WR(bp, BNX2_TBDC_CAM_OPCODE,
6471 BNX2_TBDC_CAM_OPCODE_OPCODE_CAM_READ);
6472 BNX2_WR(bp, BNX2_TBDC_COMMAND, BNX2_TBDC_COMMAND_CMD_REG_ARB);
6473 while ((BNX2_RD(bp, BNX2_TBDC_COMMAND) &
Michael Chan555069d2012-06-16 15:45:41 +00006474 BNX2_TBDC_COMMAND_CMD_REG_ARB) && j < 100)
6475 j++;
6476
Michael Chane503e062012-12-06 10:33:08 +00006477 cid = BNX2_RD(bp, BNX2_TBDC_CID);
6478 bdidx = BNX2_RD(bp, BNX2_TBDC_BIDX);
6479 valid = BNX2_RD(bp, BNX2_TBDC_CAM_OPCODE);
Michael Chan555069d2012-06-16 15:45:41 +00006480 netdev_err(dev, "%02x %06x %04lx %02x [%x]\n",
6481 i, cid, bdidx & BNX2_TBDC_BDIDX_BDIDX,
6482 bdidx >> 24, (valid >> 8) & 0x0ff);
6483 }
6484 netdev_err(dev, "<--- end TBDC dump --->\n");
6485}
6486
Michael Chanb6016b72005-05-26 13:03:09 -07006487static void
Michael Chan20175c52009-12-03 09:46:32 +00006488bnx2_dump_state(struct bnx2 *bp)
6489{
6490 struct net_device *dev = bp->dev;
Jeffrey Huangecdbf6e2011-07-13 17:24:21 +00006491 u32 val1, val2;
Michael Chan20175c52009-12-03 09:46:32 +00006492
Michael Chan5804a8f2010-07-03 20:42:17 +00006493 pci_read_config_dword(bp->pdev, PCI_COMMAND, &val1);
6494 netdev_err(dev, "DEBUG: intr_sem[%x] PCI_CMD[%08x]\n",
6495 atomic_read(&bp->intr_sem), val1);
6496 pci_read_config_dword(bp->pdev, bp->pm_cap + PCI_PM_CTRL, &val1);
6497 pci_read_config_dword(bp->pdev, BNX2_PCICFG_MISC_CONFIG, &val2);
6498 netdev_err(dev, "DEBUG: PCI_PM[%08x] PCI_MISC_CFG[%08x]\n", val1, val2);
Eddie Waib98eba52010-05-17 17:32:56 -07006499 netdev_err(dev, "DEBUG: EMAC_TX_STATUS[%08x] EMAC_RX_STATUS[%08x]\n",
Michael Chane503e062012-12-06 10:33:08 +00006500 BNX2_RD(bp, BNX2_EMAC_TX_STATUS),
6501 BNX2_RD(bp, BNX2_EMAC_RX_STATUS));
Eddie Waib98eba52010-05-17 17:32:56 -07006502 netdev_err(dev, "DEBUG: RPM_MGMT_PKT_CTRL[%08x]\n",
Michael Chane503e062012-12-06 10:33:08 +00006503 BNX2_RD(bp, BNX2_RPM_MGMT_PKT_CTRL));
Joe Perches3a9c6a42010-02-17 15:01:51 +00006504 netdev_err(dev, "DEBUG: HC_STATS_INTERRUPT_STATUS[%08x]\n",
Michael Chane503e062012-12-06 10:33:08 +00006505 BNX2_RD(bp, BNX2_HC_STATS_INTERRUPT_STATUS));
Michael Chan20175c52009-12-03 09:46:32 +00006506 if (bp->flags & BNX2_FLAG_USING_MSIX)
Joe Perches3a9c6a42010-02-17 15:01:51 +00006507 netdev_err(dev, "DEBUG: PBA[%08x]\n",
Michael Chane503e062012-12-06 10:33:08 +00006508 BNX2_RD(bp, BNX2_PCI_GRC_WINDOW3_BASE));
Michael Chan20175c52009-12-03 09:46:32 +00006509}
6510
6511static void
Michael Chanb6016b72005-05-26 13:03:09 -07006512bnx2_tx_timeout(struct net_device *dev)
6513{
Michael Chan972ec0d2006-01-23 16:12:43 -08006514 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006515
Michael Chan555069d2012-06-16 15:45:41 +00006516 bnx2_dump_ftq(bp);
Michael Chan20175c52009-12-03 09:46:32 +00006517 bnx2_dump_state(bp);
Jeffrey Huangecdbf6e2011-07-13 17:24:21 +00006518 bnx2_dump_mcp_state(bp);
Michael Chan20175c52009-12-03 09:46:32 +00006519
Michael Chanb6016b72005-05-26 13:03:09 -07006520 /* This allows the netif to be shutdown gracefully before resetting */
6521 schedule_work(&bp->reset_task);
6522}
6523
Herbert Xu932ff272006-06-09 12:20:56 -07006524/* Called with netif_tx_lock.
Michael Chan2f8af122006-08-15 01:39:10 -07006525 * bnx2_tx_int() runs without netif_tx_lock unless it needs to call
6526 * netif_wake_queue().
Michael Chanb6016b72005-05-26 13:03:09 -07006527 */
Stephen Hemminger613573252009-08-31 19:50:58 +00006528static netdev_tx_t
Michael Chanb6016b72005-05-26 13:03:09 -07006529bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev)
6530{
Michael Chan972ec0d2006-01-23 16:12:43 -08006531 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006532 dma_addr_t mapping;
Michael Chan2bc40782012-12-06 10:33:09 +00006533 struct bnx2_tx_bd *txbd;
6534 struct bnx2_sw_tx_bd *tx_buf;
Michael Chanb6016b72005-05-26 13:03:09 -07006535 u32 len, vlan_tag_flags, last_frag, mss;
6536 u16 prod, ring_prod;
6537 int i;
Benjamin Li706bf242008-07-18 17:55:11 -07006538 struct bnx2_napi *bnapi;
6539 struct bnx2_tx_ring_info *txr;
6540 struct netdev_queue *txq;
6541
6542 /* Determine which tx ring we will be placed on */
6543 i = skb_get_queue_mapping(skb);
6544 bnapi = &bp->bnx2_napi[i];
6545 txr = &bnapi->tx_ring;
6546 txq = netdev_get_tx_queue(dev, i);
Michael Chanb6016b72005-05-26 13:03:09 -07006547
Michael Chan35e90102008-06-19 16:37:42 -07006548 if (unlikely(bnx2_tx_avail(bp, txr) <
Michael Chana550c992007-12-20 19:56:59 -08006549 (skb_shinfo(skb)->nr_frags + 1))) {
Benjamin Li706bf242008-07-18 17:55:11 -07006550 netif_tx_stop_queue(txq);
Joe Perches3a9c6a42010-02-17 15:01:51 +00006551 netdev_err(dev, "BUG! Tx ring full when queue awake!\n");
Michael Chanb6016b72005-05-26 13:03:09 -07006552
6553 return NETDEV_TX_BUSY;
6554 }
6555 len = skb_headlen(skb);
Michael Chan35e90102008-06-19 16:37:42 -07006556 prod = txr->tx_prod;
Michael Chan2bc40782012-12-06 10:33:09 +00006557 ring_prod = BNX2_TX_RING_IDX(prod);
Michael Chanb6016b72005-05-26 13:03:09 -07006558
6559 vlan_tag_flags = 0;
Patrick McHardy84fa7932006-08-29 16:44:56 -07006560 if (skb->ip_summed == CHECKSUM_PARTIAL) {
Michael Chanb6016b72005-05-26 13:03:09 -07006561 vlan_tag_flags |= TX_BD_FLAGS_TCP_UDP_CKSUM;
6562 }
6563
Jesse Grosseab6d182010-10-20 13:56:03 +00006564 if (vlan_tx_tag_present(skb)) {
Michael Chanb6016b72005-05-26 13:03:09 -07006565 vlan_tag_flags |=
6566 (TX_BD_FLAGS_VLAN_TAG | (vlan_tx_tag_get(skb) << 16));
6567 }
Jesse Gross7d0fd212010-10-20 13:56:09 +00006568
Michael Chanfde82052007-05-03 17:23:35 -07006569 if ((mss = skb_shinfo(skb)->gso_size)) {
Michael Chana1efb4b2008-10-09 12:24:39 -07006570 u32 tcp_opt_len;
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -07006571 struct iphdr *iph;
Michael Chanb6016b72005-05-26 13:03:09 -07006572
Michael Chanb6016b72005-05-26 13:03:09 -07006573 vlan_tag_flags |= TX_BD_FLAGS_SW_LSO;
6574
Michael Chan4666f872007-05-03 13:22:28 -07006575 tcp_opt_len = tcp_optlen(skb);
Arnaldo Carvalho de Meloab6a5bb2007-03-18 17:43:48 -07006576
Michael Chan4666f872007-05-03 13:22:28 -07006577 if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6) {
6578 u32 tcp_off = skb_transport_offset(skb) -
6579 sizeof(struct ipv6hdr) - ETH_HLEN;
Michael Chanb6016b72005-05-26 13:03:09 -07006580
Michael Chan4666f872007-05-03 13:22:28 -07006581 vlan_tag_flags |= ((tcp_opt_len >> 2) << 8) |
6582 TX_BD_FLAGS_SW_FLAGS;
6583 if (likely(tcp_off == 0))
6584 vlan_tag_flags &= ~TX_BD_FLAGS_TCP6_OFF0_MSK;
6585 else {
6586 tcp_off >>= 3;
6587 vlan_tag_flags |= ((tcp_off & 0x3) <<
6588 TX_BD_FLAGS_TCP6_OFF0_SHL) |
6589 ((tcp_off & 0x10) <<
6590 TX_BD_FLAGS_TCP6_OFF4_SHL);
6591 mss |= (tcp_off & 0xc) << TX_BD_TCP6_OFF2_SHL;
6592 }
6593 } else {
Michael Chan4666f872007-05-03 13:22:28 -07006594 iph = ip_hdr(skb);
Michael Chan4666f872007-05-03 13:22:28 -07006595 if (tcp_opt_len || (iph->ihl > 5)) {
6596 vlan_tag_flags |= ((iph->ihl - 5) +
6597 (tcp_opt_len >> 2)) << 8;
6598 }
Michael Chanb6016b72005-05-26 13:03:09 -07006599 }
Michael Chan4666f872007-05-03 13:22:28 -07006600 } else
Michael Chanb6016b72005-05-26 13:03:09 -07006601 mss = 0;
Michael Chanb6016b72005-05-26 13:03:09 -07006602
Stanislaw Gruszka36227e82010-07-15 04:25:50 +00006603 mapping = dma_map_single(&bp->pdev->dev, skb->data, len, PCI_DMA_TODEVICE);
6604 if (dma_mapping_error(&bp->pdev->dev, mapping)) {
Benjamin Li3d16af82008-10-09 12:26:41 -07006605 dev_kfree_skb(skb);
6606 return NETDEV_TX_OK;
6607 }
6608
Michael Chan35e90102008-06-19 16:37:42 -07006609 tx_buf = &txr->tx_buf_ring[ring_prod];
Michael Chanb6016b72005-05-26 13:03:09 -07006610 tx_buf->skb = skb;
FUJITA Tomonori1a4ccc22010-04-01 16:56:57 +00006611 dma_unmap_addr_set(tx_buf, mapping, mapping);
Michael Chanb6016b72005-05-26 13:03:09 -07006612
Michael Chan35e90102008-06-19 16:37:42 -07006613 txbd = &txr->tx_desc_ring[ring_prod];
Michael Chanb6016b72005-05-26 13:03:09 -07006614
6615 txbd->tx_bd_haddr_hi = (u64) mapping >> 32;
6616 txbd->tx_bd_haddr_lo = (u64) mapping & 0xffffffff;
6617 txbd->tx_bd_mss_nbytes = len | (mss << 16);
6618 txbd->tx_bd_vlan_tag_flags = vlan_tag_flags | TX_BD_FLAGS_START;
6619
6620 last_frag = skb_shinfo(skb)->nr_frags;
Eric Dumazetd62fda02009-05-12 20:48:02 +00006621 tx_buf->nr_frags = last_frag;
6622 tx_buf->is_gso = skb_is_gso(skb);
Michael Chanb6016b72005-05-26 13:03:09 -07006623
6624 for (i = 0; i < last_frag; i++) {
Eric Dumazet9e903e02011-10-18 21:00:24 +00006625 const skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
Michael Chanb6016b72005-05-26 13:03:09 -07006626
Michael Chan2bc40782012-12-06 10:33:09 +00006627 prod = BNX2_NEXT_TX_BD(prod);
6628 ring_prod = BNX2_TX_RING_IDX(prod);
Michael Chan35e90102008-06-19 16:37:42 -07006629 txbd = &txr->tx_desc_ring[ring_prod];
Michael Chanb6016b72005-05-26 13:03:09 -07006630
Eric Dumazet9e903e02011-10-18 21:00:24 +00006631 len = skb_frag_size(frag);
Ian Campbellb7b6a682011-08-24 22:28:12 +00006632 mapping = skb_frag_dma_map(&bp->pdev->dev, frag, 0, len,
Ian Campbell5d6bcdf2011-10-06 11:10:48 +01006633 DMA_TO_DEVICE);
Stanislaw Gruszka36227e82010-07-15 04:25:50 +00006634 if (dma_mapping_error(&bp->pdev->dev, mapping))
Alexander Duycke95524a2009-12-02 16:47:57 +00006635 goto dma_error;
FUJITA Tomonori1a4ccc22010-04-01 16:56:57 +00006636 dma_unmap_addr_set(&txr->tx_buf_ring[ring_prod], mapping,
Alexander Duycke95524a2009-12-02 16:47:57 +00006637 mapping);
Michael Chanb6016b72005-05-26 13:03:09 -07006638
6639 txbd->tx_bd_haddr_hi = (u64) mapping >> 32;
6640 txbd->tx_bd_haddr_lo = (u64) mapping & 0xffffffff;
6641 txbd->tx_bd_mss_nbytes = len | (mss << 16);
6642 txbd->tx_bd_vlan_tag_flags = vlan_tag_flags;
6643
6644 }
6645 txbd->tx_bd_vlan_tag_flags |= TX_BD_FLAGS_END;
6646
Vlad Zolotarov94bf91b2012-02-05 15:24:39 +00006647 /* Sync BD data before updating TX mailbox */
6648 wmb();
6649
Eric Dumazete9831902011-11-29 11:53:05 +00006650 netdev_tx_sent_queue(txq, skb->len);
6651
Michael Chan2bc40782012-12-06 10:33:09 +00006652 prod = BNX2_NEXT_TX_BD(prod);
Michael Chan35e90102008-06-19 16:37:42 -07006653 txr->tx_prod_bseq += skb->len;
Michael Chanb6016b72005-05-26 13:03:09 -07006654
Michael Chane503e062012-12-06 10:33:08 +00006655 BNX2_WR16(bp, txr->tx_bidx_addr, prod);
6656 BNX2_WR(bp, txr->tx_bseq_addr, txr->tx_prod_bseq);
Michael Chanb6016b72005-05-26 13:03:09 -07006657
6658 mmiowb();
6659
Michael Chan35e90102008-06-19 16:37:42 -07006660 txr->tx_prod = prod;
Michael Chanb6016b72005-05-26 13:03:09 -07006661
Michael Chan35e90102008-06-19 16:37:42 -07006662 if (unlikely(bnx2_tx_avail(bp, txr) <= MAX_SKB_FRAGS)) {
Benjamin Li706bf242008-07-18 17:55:11 -07006663 netif_tx_stop_queue(txq);
Michael Chan11848b962010-07-19 14:15:04 +00006664
6665 /* netif_tx_stop_queue() must be done before checking
6666 * tx index in bnx2_tx_avail() below, because in
6667 * bnx2_tx_int(), we update tx index before checking for
6668 * netif_tx_queue_stopped().
6669 */
6670 smp_mb();
Michael Chan35e90102008-06-19 16:37:42 -07006671 if (bnx2_tx_avail(bp, txr) > bp->tx_wake_thresh)
Benjamin Li706bf242008-07-18 17:55:11 -07006672 netif_tx_wake_queue(txq);
Michael Chanb6016b72005-05-26 13:03:09 -07006673 }
6674
6675 return NETDEV_TX_OK;
Alexander Duycke95524a2009-12-02 16:47:57 +00006676dma_error:
6677 /* save value of frag that failed */
6678 last_frag = i;
6679
6680 /* start back at beginning and unmap skb */
6681 prod = txr->tx_prod;
Michael Chan2bc40782012-12-06 10:33:09 +00006682 ring_prod = BNX2_TX_RING_IDX(prod);
Alexander Duycke95524a2009-12-02 16:47:57 +00006683 tx_buf = &txr->tx_buf_ring[ring_prod];
6684 tx_buf->skb = NULL;
Stanislaw Gruszka36227e82010-07-15 04:25:50 +00006685 dma_unmap_single(&bp->pdev->dev, dma_unmap_addr(tx_buf, mapping),
Alexander Duycke95524a2009-12-02 16:47:57 +00006686 skb_headlen(skb), PCI_DMA_TODEVICE);
6687
6688 /* unmap remaining mapped pages */
6689 for (i = 0; i < last_frag; i++) {
Michael Chan2bc40782012-12-06 10:33:09 +00006690 prod = BNX2_NEXT_TX_BD(prod);
6691 ring_prod = BNX2_TX_RING_IDX(prod);
Alexander Duycke95524a2009-12-02 16:47:57 +00006692 tx_buf = &txr->tx_buf_ring[ring_prod];
Stanislaw Gruszka36227e82010-07-15 04:25:50 +00006693 dma_unmap_page(&bp->pdev->dev, dma_unmap_addr(tx_buf, mapping),
Eric Dumazet9e903e02011-10-18 21:00:24 +00006694 skb_frag_size(&skb_shinfo(skb)->frags[i]),
Alexander Duycke95524a2009-12-02 16:47:57 +00006695 PCI_DMA_TODEVICE);
6696 }
6697
6698 dev_kfree_skb(skb);
6699 return NETDEV_TX_OK;
Michael Chanb6016b72005-05-26 13:03:09 -07006700}
6701
6702/* Called with rtnl_lock */
6703static int
6704bnx2_close(struct net_device *dev)
6705{
Michael Chan972ec0d2006-01-23 16:12:43 -08006706 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006707
Stephen Hemmingerbea33482007-10-03 16:41:36 -07006708 bnx2_disable_int_sync(bp);
Michael Chan35efa7c2007-12-20 19:56:37 -08006709 bnx2_napi_disable(bp);
Michael Chand2e553b2012-06-27 15:08:24 +00006710 netif_tx_disable(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006711 del_timer_sync(&bp->timer);
Michael Chan74bf4ba2008-10-09 12:21:08 -07006712 bnx2_shutdown_chip(bp);
Michael Chan8e6a72c2007-05-03 13:24:48 -07006713 bnx2_free_irq(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07006714 bnx2_free_skbs(bp);
6715 bnx2_free_mem(bp);
Michael Chanf048fa92010-06-01 15:05:36 +00006716 bnx2_del_napi(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07006717 bp->link_up = 0;
6718 netif_carrier_off(bp->dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006719 return 0;
6720}
6721
Michael Chan354fcd72010-01-17 07:30:44 +00006722static void
6723bnx2_save_stats(struct bnx2 *bp)
6724{
6725 u32 *hw_stats = (u32 *) bp->stats_blk;
6726 u32 *temp_stats = (u32 *) bp->temp_stats_blk;
6727 int i;
6728
6729 /* The 1st 10 counters are 64-bit counters */
6730 for (i = 0; i < 20; i += 2) {
6731 u32 hi;
6732 u64 lo;
6733
Patrick Rabauc9885fe2010-02-15 19:42:11 +00006734 hi = temp_stats[i] + hw_stats[i];
6735 lo = (u64) temp_stats[i + 1] + (u64) hw_stats[i + 1];
Michael Chan354fcd72010-01-17 07:30:44 +00006736 if (lo > 0xffffffff)
6737 hi++;
Patrick Rabauc9885fe2010-02-15 19:42:11 +00006738 temp_stats[i] = hi;
6739 temp_stats[i + 1] = lo & 0xffffffff;
Michael Chan354fcd72010-01-17 07:30:44 +00006740 }
6741
6742 for ( ; i < sizeof(struct statistics_block) / 4; i++)
Patrick Rabauc9885fe2010-02-15 19:42:11 +00006743 temp_stats[i] += hw_stats[i];
Michael Chan354fcd72010-01-17 07:30:44 +00006744}
6745
Eric Dumazet5d07bf22010-07-08 04:08:43 +00006746#define GET_64BIT_NET_STATS64(ctr) \
6747 (((u64) (ctr##_hi) << 32) + (u64) (ctr##_lo))
Michael Chanb6016b72005-05-26 13:03:09 -07006748
Michael Chana4743052010-01-17 07:30:43 +00006749#define GET_64BIT_NET_STATS(ctr) \
Michael Chan354fcd72010-01-17 07:30:44 +00006750 GET_64BIT_NET_STATS64(bp->stats_blk->ctr) + \
6751 GET_64BIT_NET_STATS64(bp->temp_stats_blk->ctr)
Michael Chanb6016b72005-05-26 13:03:09 -07006752
Michael Chana4743052010-01-17 07:30:43 +00006753#define GET_32BIT_NET_STATS(ctr) \
Michael Chan354fcd72010-01-17 07:30:44 +00006754 (unsigned long) (bp->stats_blk->ctr + \
6755 bp->temp_stats_blk->ctr)
Michael Chana4743052010-01-17 07:30:43 +00006756
Eric Dumazet5d07bf22010-07-08 04:08:43 +00006757static struct rtnl_link_stats64 *
6758bnx2_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *net_stats)
Michael Chanb6016b72005-05-26 13:03:09 -07006759{
Michael Chan972ec0d2006-01-23 16:12:43 -08006760 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006761
Eric Dumazet5d07bf22010-07-08 04:08:43 +00006762 if (bp->stats_blk == NULL)
Michael Chanb6016b72005-05-26 13:03:09 -07006763 return net_stats;
Eric Dumazet5d07bf22010-07-08 04:08:43 +00006764
Michael Chanb6016b72005-05-26 13:03:09 -07006765 net_stats->rx_packets =
Michael Chana4743052010-01-17 07:30:43 +00006766 GET_64BIT_NET_STATS(stat_IfHCInUcastPkts) +
6767 GET_64BIT_NET_STATS(stat_IfHCInMulticastPkts) +
6768 GET_64BIT_NET_STATS(stat_IfHCInBroadcastPkts);
Michael Chanb6016b72005-05-26 13:03:09 -07006769
6770 net_stats->tx_packets =
Michael Chana4743052010-01-17 07:30:43 +00006771 GET_64BIT_NET_STATS(stat_IfHCOutUcastPkts) +
6772 GET_64BIT_NET_STATS(stat_IfHCOutMulticastPkts) +
6773 GET_64BIT_NET_STATS(stat_IfHCOutBroadcastPkts);
Michael Chanb6016b72005-05-26 13:03:09 -07006774
6775 net_stats->rx_bytes =
Michael Chana4743052010-01-17 07:30:43 +00006776 GET_64BIT_NET_STATS(stat_IfHCInOctets);
Michael Chanb6016b72005-05-26 13:03:09 -07006777
6778 net_stats->tx_bytes =
Michael Chana4743052010-01-17 07:30:43 +00006779 GET_64BIT_NET_STATS(stat_IfHCOutOctets);
Michael Chanb6016b72005-05-26 13:03:09 -07006780
Jeff Garzik6aa20a22006-09-13 13:24:59 -04006781 net_stats->multicast =
Michael Chan6fdae992010-07-19 14:15:02 +00006782 GET_64BIT_NET_STATS(stat_IfHCInMulticastPkts);
Michael Chanb6016b72005-05-26 13:03:09 -07006783
Jeff Garzik6aa20a22006-09-13 13:24:59 -04006784 net_stats->collisions =
Michael Chana4743052010-01-17 07:30:43 +00006785 GET_32BIT_NET_STATS(stat_EtherStatsCollisions);
Michael Chanb6016b72005-05-26 13:03:09 -07006786
Jeff Garzik6aa20a22006-09-13 13:24:59 -04006787 net_stats->rx_length_errors =
Michael Chana4743052010-01-17 07:30:43 +00006788 GET_32BIT_NET_STATS(stat_EtherStatsUndersizePkts) +
6789 GET_32BIT_NET_STATS(stat_EtherStatsOverrsizePkts);
Michael Chanb6016b72005-05-26 13:03:09 -07006790
Jeff Garzik6aa20a22006-09-13 13:24:59 -04006791 net_stats->rx_over_errors =
Michael Chana4743052010-01-17 07:30:43 +00006792 GET_32BIT_NET_STATS(stat_IfInFTQDiscards) +
6793 GET_32BIT_NET_STATS(stat_IfInMBUFDiscards);
Michael Chanb6016b72005-05-26 13:03:09 -07006794
Jeff Garzik6aa20a22006-09-13 13:24:59 -04006795 net_stats->rx_frame_errors =
Michael Chana4743052010-01-17 07:30:43 +00006796 GET_32BIT_NET_STATS(stat_Dot3StatsAlignmentErrors);
Michael Chanb6016b72005-05-26 13:03:09 -07006797
Jeff Garzik6aa20a22006-09-13 13:24:59 -04006798 net_stats->rx_crc_errors =
Michael Chana4743052010-01-17 07:30:43 +00006799 GET_32BIT_NET_STATS(stat_Dot3StatsFCSErrors);
Michael Chanb6016b72005-05-26 13:03:09 -07006800
6801 net_stats->rx_errors = net_stats->rx_length_errors +
6802 net_stats->rx_over_errors + net_stats->rx_frame_errors +
6803 net_stats->rx_crc_errors;
6804
6805 net_stats->tx_aborted_errors =
Michael Chana4743052010-01-17 07:30:43 +00006806 GET_32BIT_NET_STATS(stat_Dot3StatsExcessiveCollisions) +
6807 GET_32BIT_NET_STATS(stat_Dot3StatsLateCollisions);
Michael Chanb6016b72005-05-26 13:03:09 -07006808
Michael Chan4ce45e02012-12-06 10:33:10 +00006809 if ((BNX2_CHIP(bp) == BNX2_CHIP_5706) ||
6810 (BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5708_A0))
Michael Chanb6016b72005-05-26 13:03:09 -07006811 net_stats->tx_carrier_errors = 0;
6812 else {
6813 net_stats->tx_carrier_errors =
Michael Chana4743052010-01-17 07:30:43 +00006814 GET_32BIT_NET_STATS(stat_Dot3StatsCarrierSenseErrors);
Michael Chanb6016b72005-05-26 13:03:09 -07006815 }
6816
6817 net_stats->tx_errors =
Michael Chana4743052010-01-17 07:30:43 +00006818 GET_32BIT_NET_STATS(stat_emac_tx_stat_dot3statsinternalmactransmiterrors) +
Michael Chanb6016b72005-05-26 13:03:09 -07006819 net_stats->tx_aborted_errors +
6820 net_stats->tx_carrier_errors;
6821
Michael Chancea94db2006-06-12 22:16:13 -07006822 net_stats->rx_missed_errors =
Michael Chana4743052010-01-17 07:30:43 +00006823 GET_32BIT_NET_STATS(stat_IfInFTQDiscards) +
6824 GET_32BIT_NET_STATS(stat_IfInMBUFDiscards) +
6825 GET_32BIT_NET_STATS(stat_FwRxDrop);
Michael Chancea94db2006-06-12 22:16:13 -07006826
Michael Chanb6016b72005-05-26 13:03:09 -07006827 return net_stats;
6828}
6829
6830/* All ethtool functions called with rtnl_lock */
6831
6832static int
6833bnx2_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
6834{
Michael Chan972ec0d2006-01-23 16:12:43 -08006835 struct bnx2 *bp = netdev_priv(dev);
Michael Chan7b6b8342007-07-07 22:50:15 -07006836 int support_serdes = 0, support_copper = 0;
Michael Chanb6016b72005-05-26 13:03:09 -07006837
6838 cmd->supported = SUPPORTED_Autoneg;
Michael Chan583c28e2008-01-21 19:51:35 -08006839 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP) {
Michael Chan7b6b8342007-07-07 22:50:15 -07006840 support_serdes = 1;
6841 support_copper = 1;
6842 } else if (bp->phy_port == PORT_FIBRE)
6843 support_serdes = 1;
6844 else
6845 support_copper = 1;
6846
6847 if (support_serdes) {
Michael Chanb6016b72005-05-26 13:03:09 -07006848 cmd->supported |= SUPPORTED_1000baseT_Full |
6849 SUPPORTED_FIBRE;
Michael Chan583c28e2008-01-21 19:51:35 -08006850 if (bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE)
Michael Chan605a9e22007-05-03 13:23:13 -07006851 cmd->supported |= SUPPORTED_2500baseX_Full;
Michael Chanb6016b72005-05-26 13:03:09 -07006852
Michael Chanb6016b72005-05-26 13:03:09 -07006853 }
Michael Chan7b6b8342007-07-07 22:50:15 -07006854 if (support_copper) {
Michael Chanb6016b72005-05-26 13:03:09 -07006855 cmd->supported |= SUPPORTED_10baseT_Half |
6856 SUPPORTED_10baseT_Full |
6857 SUPPORTED_100baseT_Half |
6858 SUPPORTED_100baseT_Full |
6859 SUPPORTED_1000baseT_Full |
6860 SUPPORTED_TP;
6861
Michael Chanb6016b72005-05-26 13:03:09 -07006862 }
6863
Michael Chan7b6b8342007-07-07 22:50:15 -07006864 spin_lock_bh(&bp->phy_lock);
6865 cmd->port = bp->phy_port;
Michael Chanb6016b72005-05-26 13:03:09 -07006866 cmd->advertising = bp->advertising;
6867
6868 if (bp->autoneg & AUTONEG_SPEED) {
6869 cmd->autoneg = AUTONEG_ENABLE;
David Decotigny70739492011-04-27 18:32:40 +00006870 } else {
Michael Chanb6016b72005-05-26 13:03:09 -07006871 cmd->autoneg = AUTONEG_DISABLE;
6872 }
6873
6874 if (netif_carrier_ok(dev)) {
David Decotigny70739492011-04-27 18:32:40 +00006875 ethtool_cmd_speed_set(cmd, bp->line_speed);
Michael Chanb6016b72005-05-26 13:03:09 -07006876 cmd->duplex = bp->duplex;
6877 }
6878 else {
David Decotigny70739492011-04-27 18:32:40 +00006879 ethtool_cmd_speed_set(cmd, -1);
Michael Chanb6016b72005-05-26 13:03:09 -07006880 cmd->duplex = -1;
6881 }
Michael Chan7b6b8342007-07-07 22:50:15 -07006882 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07006883
6884 cmd->transceiver = XCVR_INTERNAL;
6885 cmd->phy_address = bp->phy_addr;
6886
6887 return 0;
6888}
Jeff Garzik6aa20a22006-09-13 13:24:59 -04006889
Michael Chanb6016b72005-05-26 13:03:09 -07006890static int
6891bnx2_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
6892{
Michael Chan972ec0d2006-01-23 16:12:43 -08006893 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006894 u8 autoneg = bp->autoneg;
6895 u8 req_duplex = bp->req_duplex;
6896 u16 req_line_speed = bp->req_line_speed;
6897 u32 advertising = bp->advertising;
Michael Chan7b6b8342007-07-07 22:50:15 -07006898 int err = -EINVAL;
6899
6900 spin_lock_bh(&bp->phy_lock);
6901
6902 if (cmd->port != PORT_TP && cmd->port != PORT_FIBRE)
6903 goto err_out_unlock;
6904
Michael Chan583c28e2008-01-21 19:51:35 -08006905 if (cmd->port != bp->phy_port &&
6906 !(bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP))
Michael Chan7b6b8342007-07-07 22:50:15 -07006907 goto err_out_unlock;
Michael Chanb6016b72005-05-26 13:03:09 -07006908
Michael Chand6b14482008-07-14 22:37:21 -07006909 /* If device is down, we can store the settings only if the user
6910 * is setting the currently active port.
6911 */
6912 if (!netif_running(dev) && cmd->port != bp->phy_port)
6913 goto err_out_unlock;
6914
Michael Chanb6016b72005-05-26 13:03:09 -07006915 if (cmd->autoneg == AUTONEG_ENABLE) {
6916 autoneg |= AUTONEG_SPEED;
6917
Michael Chanbeb499a2010-02-15 19:42:10 +00006918 advertising = cmd->advertising;
6919 if (cmd->port == PORT_TP) {
6920 advertising &= ETHTOOL_ALL_COPPER_SPEED;
6921 if (!advertising)
Michael Chanb6016b72005-05-26 13:03:09 -07006922 advertising = ETHTOOL_ALL_COPPER_SPEED;
Michael Chanbeb499a2010-02-15 19:42:10 +00006923 } else {
6924 advertising &= ETHTOOL_ALL_FIBRE_SPEED;
6925 if (!advertising)
6926 advertising = ETHTOOL_ALL_FIBRE_SPEED;
Michael Chanb6016b72005-05-26 13:03:09 -07006927 }
6928 advertising |= ADVERTISED_Autoneg;
6929 }
6930 else {
David Decotigny25db0332011-04-27 18:32:39 +00006931 u32 speed = ethtool_cmd_speed(cmd);
Michael Chan7b6b8342007-07-07 22:50:15 -07006932 if (cmd->port == PORT_FIBRE) {
David Decotigny25db0332011-04-27 18:32:39 +00006933 if ((speed != SPEED_1000 &&
6934 speed != SPEED_2500) ||
Michael Chan80be4432006-11-19 14:07:28 -08006935 (cmd->duplex != DUPLEX_FULL))
Michael Chan7b6b8342007-07-07 22:50:15 -07006936 goto err_out_unlock;
Michael Chan80be4432006-11-19 14:07:28 -08006937
David Decotigny25db0332011-04-27 18:32:39 +00006938 if (speed == SPEED_2500 &&
Michael Chan583c28e2008-01-21 19:51:35 -08006939 !(bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE))
Michael Chan7b6b8342007-07-07 22:50:15 -07006940 goto err_out_unlock;
David Decotigny25db0332011-04-27 18:32:39 +00006941 } else if (speed == SPEED_1000 || speed == SPEED_2500)
Michael Chan7b6b8342007-07-07 22:50:15 -07006942 goto err_out_unlock;
6943
Michael Chanb6016b72005-05-26 13:03:09 -07006944 autoneg &= ~AUTONEG_SPEED;
David Decotigny25db0332011-04-27 18:32:39 +00006945 req_line_speed = speed;
Michael Chanb6016b72005-05-26 13:03:09 -07006946 req_duplex = cmd->duplex;
6947 advertising = 0;
6948 }
6949
6950 bp->autoneg = autoneg;
6951 bp->advertising = advertising;
6952 bp->req_line_speed = req_line_speed;
6953 bp->req_duplex = req_duplex;
6954
Michael Chand6b14482008-07-14 22:37:21 -07006955 err = 0;
6956 /* If device is down, the new settings will be picked up when it is
6957 * brought up.
6958 */
6959 if (netif_running(dev))
6960 err = bnx2_setup_phy(bp, cmd->port);
Michael Chanb6016b72005-05-26 13:03:09 -07006961
Michael Chan7b6b8342007-07-07 22:50:15 -07006962err_out_unlock:
Michael Chanc770a652005-08-25 15:38:39 -07006963 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07006964
Michael Chan7b6b8342007-07-07 22:50:15 -07006965 return err;
Michael Chanb6016b72005-05-26 13:03:09 -07006966}
6967
6968static void
6969bnx2_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
6970{
Michael Chan972ec0d2006-01-23 16:12:43 -08006971 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006972
Rick Jones68aad782011-11-07 13:29:27 +00006973 strlcpy(info->driver, DRV_MODULE_NAME, sizeof(info->driver));
6974 strlcpy(info->version, DRV_MODULE_VERSION, sizeof(info->version));
6975 strlcpy(info->bus_info, pci_name(bp->pdev), sizeof(info->bus_info));
6976 strlcpy(info->fw_version, bp->fw_version, sizeof(info->fw_version));
Michael Chanb6016b72005-05-26 13:03:09 -07006977}
6978
Michael Chan244ac4f2006-03-20 17:48:46 -08006979#define BNX2_REGDUMP_LEN (32 * 1024)
6980
6981static int
6982bnx2_get_regs_len(struct net_device *dev)
6983{
6984 return BNX2_REGDUMP_LEN;
6985}
6986
6987static void
6988bnx2_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *_p)
6989{
6990 u32 *p = _p, i, offset;
6991 u8 *orig_p = _p;
6992 struct bnx2 *bp = netdev_priv(dev);
Joe Perchesb6bc7652010-12-21 02:16:08 -08006993 static const u32 reg_boundaries[] = {
6994 0x0000, 0x0098, 0x0400, 0x045c,
6995 0x0800, 0x0880, 0x0c00, 0x0c10,
6996 0x0c30, 0x0d08, 0x1000, 0x101c,
6997 0x1040, 0x1048, 0x1080, 0x10a4,
6998 0x1400, 0x1490, 0x1498, 0x14f0,
6999 0x1500, 0x155c, 0x1580, 0x15dc,
7000 0x1600, 0x1658, 0x1680, 0x16d8,
7001 0x1800, 0x1820, 0x1840, 0x1854,
7002 0x1880, 0x1894, 0x1900, 0x1984,
7003 0x1c00, 0x1c0c, 0x1c40, 0x1c54,
7004 0x1c80, 0x1c94, 0x1d00, 0x1d84,
7005 0x2000, 0x2030, 0x23c0, 0x2400,
7006 0x2800, 0x2820, 0x2830, 0x2850,
7007 0x2b40, 0x2c10, 0x2fc0, 0x3058,
7008 0x3c00, 0x3c94, 0x4000, 0x4010,
7009 0x4080, 0x4090, 0x43c0, 0x4458,
7010 0x4c00, 0x4c18, 0x4c40, 0x4c54,
7011 0x4fc0, 0x5010, 0x53c0, 0x5444,
7012 0x5c00, 0x5c18, 0x5c80, 0x5c90,
7013 0x5fc0, 0x6000, 0x6400, 0x6428,
7014 0x6800, 0x6848, 0x684c, 0x6860,
7015 0x6888, 0x6910, 0x8000
7016 };
Michael Chan244ac4f2006-03-20 17:48:46 -08007017
7018 regs->version = 0;
7019
7020 memset(p, 0, BNX2_REGDUMP_LEN);
7021
7022 if (!netif_running(bp->dev))
7023 return;
7024
7025 i = 0;
7026 offset = reg_boundaries[0];
7027 p += offset;
7028 while (offset < BNX2_REGDUMP_LEN) {
Michael Chane503e062012-12-06 10:33:08 +00007029 *p++ = BNX2_RD(bp, offset);
Michael Chan244ac4f2006-03-20 17:48:46 -08007030 offset += 4;
7031 if (offset == reg_boundaries[i + 1]) {
7032 offset = reg_boundaries[i + 2];
7033 p = (u32 *) (orig_p + offset);
7034 i += 2;
7035 }
7036 }
7037}
7038
Michael Chanb6016b72005-05-26 13:03:09 -07007039static void
7040bnx2_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
7041{
Michael Chan972ec0d2006-01-23 16:12:43 -08007042 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007043
David S. Millerf86e82f2008-01-21 17:15:40 -08007044 if (bp->flags & BNX2_FLAG_NO_WOL) {
Michael Chanb6016b72005-05-26 13:03:09 -07007045 wol->supported = 0;
7046 wol->wolopts = 0;
7047 }
7048 else {
7049 wol->supported = WAKE_MAGIC;
7050 if (bp->wol)
7051 wol->wolopts = WAKE_MAGIC;
7052 else
7053 wol->wolopts = 0;
7054 }
7055 memset(&wol->sopass, 0, sizeof(wol->sopass));
7056}
7057
7058static int
7059bnx2_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
7060{
Michael Chan972ec0d2006-01-23 16:12:43 -08007061 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007062
7063 if (wol->wolopts & ~WAKE_MAGIC)
7064 return -EINVAL;
7065
7066 if (wol->wolopts & WAKE_MAGIC) {
David S. Millerf86e82f2008-01-21 17:15:40 -08007067 if (bp->flags & BNX2_FLAG_NO_WOL)
Michael Chanb6016b72005-05-26 13:03:09 -07007068 return -EINVAL;
7069
7070 bp->wol = 1;
7071 }
7072 else {
7073 bp->wol = 0;
7074 }
Michael Chan6d5e85c2013-08-06 15:50:08 -07007075
7076 device_set_wakeup_enable(&bp->pdev->dev, bp->wol);
7077
Michael Chanb6016b72005-05-26 13:03:09 -07007078 return 0;
7079}
7080
7081static int
7082bnx2_nway_reset(struct net_device *dev)
7083{
Michael Chan972ec0d2006-01-23 16:12:43 -08007084 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007085 u32 bmcr;
7086
Michael Chan9f52b562008-10-09 12:21:46 -07007087 if (!netif_running(dev))
7088 return -EAGAIN;
7089
Michael Chanb6016b72005-05-26 13:03:09 -07007090 if (!(bp->autoneg & AUTONEG_SPEED)) {
7091 return -EINVAL;
7092 }
7093
Michael Chanc770a652005-08-25 15:38:39 -07007094 spin_lock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07007095
Michael Chan583c28e2008-01-21 19:51:35 -08007096 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP) {
Michael Chan7b6b8342007-07-07 22:50:15 -07007097 int rc;
7098
7099 rc = bnx2_setup_remote_phy(bp, bp->phy_port);
7100 spin_unlock_bh(&bp->phy_lock);
7101 return rc;
7102 }
7103
Michael Chanb6016b72005-05-26 13:03:09 -07007104 /* Force a link down visible on the other side */
Michael Chan583c28e2008-01-21 19:51:35 -08007105 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Michael Chanca58c3a2007-05-03 13:22:52 -07007106 bnx2_write_phy(bp, bp->mii_bmcr, BMCR_LOOPBACK);
Michael Chanc770a652005-08-25 15:38:39 -07007107 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07007108
7109 msleep(20);
7110
Michael Chanc770a652005-08-25 15:38:39 -07007111 spin_lock_bh(&bp->phy_lock);
Michael Chanf8dd0642006-11-19 14:08:29 -08007112
Michael Chan40105c02008-11-12 16:02:45 -08007113 bp->current_interval = BNX2_SERDES_AN_TIMEOUT;
Michael Chanf8dd0642006-11-19 14:08:29 -08007114 bp->serdes_an_pending = 1;
7115 mod_timer(&bp->timer, jiffies + bp->current_interval);
Michael Chanb6016b72005-05-26 13:03:09 -07007116 }
7117
Michael Chanca58c3a2007-05-03 13:22:52 -07007118 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chanb6016b72005-05-26 13:03:09 -07007119 bmcr &= ~BMCR_LOOPBACK;
Michael Chanca58c3a2007-05-03 13:22:52 -07007120 bnx2_write_phy(bp, bp->mii_bmcr, bmcr | BMCR_ANRESTART | BMCR_ANENABLE);
Michael Chanb6016b72005-05-26 13:03:09 -07007121
Michael Chanc770a652005-08-25 15:38:39 -07007122 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07007123
7124 return 0;
7125}
7126
Ooiwa Naohiro7959ea22009-06-24 00:19:06 -07007127static u32
7128bnx2_get_link(struct net_device *dev)
7129{
7130 struct bnx2 *bp = netdev_priv(dev);
7131
7132 return bp->link_up;
7133}
7134
Michael Chanb6016b72005-05-26 13:03:09 -07007135static int
7136bnx2_get_eeprom_len(struct net_device *dev)
7137{
Michael Chan972ec0d2006-01-23 16:12:43 -08007138 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007139
Michael Chan1122db72006-01-23 16:11:42 -08007140 if (bp->flash_info == NULL)
Michael Chanb6016b72005-05-26 13:03:09 -07007141 return 0;
7142
Michael Chan1122db72006-01-23 16:11:42 -08007143 return (int) bp->flash_size;
Michael Chanb6016b72005-05-26 13:03:09 -07007144}
7145
7146static int
7147bnx2_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
7148 u8 *eebuf)
7149{
Michael Chan972ec0d2006-01-23 16:12:43 -08007150 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007151 int rc;
7152
John W. Linville1064e942005-11-10 12:58:24 -08007153 /* parameters already validated in ethtool_get_eeprom */
Michael Chanb6016b72005-05-26 13:03:09 -07007154
7155 rc = bnx2_nvram_read(bp, eeprom->offset, eebuf, eeprom->len);
7156
7157 return rc;
7158}
7159
7160static int
7161bnx2_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
7162 u8 *eebuf)
7163{
Michael Chan972ec0d2006-01-23 16:12:43 -08007164 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007165 int rc;
7166
John W. Linville1064e942005-11-10 12:58:24 -08007167 /* parameters already validated in ethtool_set_eeprom */
Michael Chanb6016b72005-05-26 13:03:09 -07007168
7169 rc = bnx2_nvram_write(bp, eeprom->offset, eebuf, eeprom->len);
7170
7171 return rc;
7172}
7173
7174static int
7175bnx2_get_coalesce(struct net_device *dev, struct ethtool_coalesce *coal)
7176{
Michael Chan972ec0d2006-01-23 16:12:43 -08007177 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007178
7179 memset(coal, 0, sizeof(struct ethtool_coalesce));
7180
7181 coal->rx_coalesce_usecs = bp->rx_ticks;
7182 coal->rx_max_coalesced_frames = bp->rx_quick_cons_trip;
7183 coal->rx_coalesce_usecs_irq = bp->rx_ticks_int;
7184 coal->rx_max_coalesced_frames_irq = bp->rx_quick_cons_trip_int;
7185
7186 coal->tx_coalesce_usecs = bp->tx_ticks;
7187 coal->tx_max_coalesced_frames = bp->tx_quick_cons_trip;
7188 coal->tx_coalesce_usecs_irq = bp->tx_ticks_int;
7189 coal->tx_max_coalesced_frames_irq = bp->tx_quick_cons_trip_int;
7190
7191 coal->stats_block_coalesce_usecs = bp->stats_ticks;
7192
7193 return 0;
7194}
7195
7196static int
7197bnx2_set_coalesce(struct net_device *dev, struct ethtool_coalesce *coal)
7198{
Michael Chan972ec0d2006-01-23 16:12:43 -08007199 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007200
7201 bp->rx_ticks = (u16) coal->rx_coalesce_usecs;
7202 if (bp->rx_ticks > 0x3ff) bp->rx_ticks = 0x3ff;
7203
Jeff Garzik6aa20a22006-09-13 13:24:59 -04007204 bp->rx_quick_cons_trip = (u16) coal->rx_max_coalesced_frames;
Michael Chanb6016b72005-05-26 13:03:09 -07007205 if (bp->rx_quick_cons_trip > 0xff) bp->rx_quick_cons_trip = 0xff;
7206
7207 bp->rx_ticks_int = (u16) coal->rx_coalesce_usecs_irq;
7208 if (bp->rx_ticks_int > 0x3ff) bp->rx_ticks_int = 0x3ff;
7209
7210 bp->rx_quick_cons_trip_int = (u16) coal->rx_max_coalesced_frames_irq;
7211 if (bp->rx_quick_cons_trip_int > 0xff)
7212 bp->rx_quick_cons_trip_int = 0xff;
7213
7214 bp->tx_ticks = (u16) coal->tx_coalesce_usecs;
7215 if (bp->tx_ticks > 0x3ff) bp->tx_ticks = 0x3ff;
7216
7217 bp->tx_quick_cons_trip = (u16) coal->tx_max_coalesced_frames;
7218 if (bp->tx_quick_cons_trip > 0xff) bp->tx_quick_cons_trip = 0xff;
7219
7220 bp->tx_ticks_int = (u16) coal->tx_coalesce_usecs_irq;
7221 if (bp->tx_ticks_int > 0x3ff) bp->tx_ticks_int = 0x3ff;
7222
7223 bp->tx_quick_cons_trip_int = (u16) coal->tx_max_coalesced_frames_irq;
7224 if (bp->tx_quick_cons_trip_int > 0xff) bp->tx_quick_cons_trip_int =
7225 0xff;
7226
7227 bp->stats_ticks = coal->stats_block_coalesce_usecs;
Michael Chan61d9e3f2009-08-21 16:20:46 +00007228 if (bp->flags & BNX2_FLAG_BROKEN_STATS) {
Michael Chan02537b062007-06-04 21:24:07 -07007229 if (bp->stats_ticks != 0 && bp->stats_ticks != USEC_PER_SEC)
7230 bp->stats_ticks = USEC_PER_SEC;
7231 }
Michael Chan7ea69202007-07-16 18:27:10 -07007232 if (bp->stats_ticks > BNX2_HC_STATS_TICKS_HC_STAT_TICKS)
7233 bp->stats_ticks = BNX2_HC_STATS_TICKS_HC_STAT_TICKS;
7234 bp->stats_ticks &= BNX2_HC_STATS_TICKS_HC_STAT_TICKS;
Michael Chanb6016b72005-05-26 13:03:09 -07007235
7236 if (netif_running(bp->dev)) {
Michael Chan212f9932010-04-27 11:28:10 +00007237 bnx2_netif_stop(bp, true);
Michael Chan9a120bc2008-05-16 22:17:45 -07007238 bnx2_init_nic(bp, 0);
Michael Chan212f9932010-04-27 11:28:10 +00007239 bnx2_netif_start(bp, true);
Michael Chanb6016b72005-05-26 13:03:09 -07007240 }
7241
7242 return 0;
7243}
7244
7245static void
7246bnx2_get_ringparam(struct net_device *dev, struct ethtool_ringparam *ering)
7247{
Michael Chan972ec0d2006-01-23 16:12:43 -08007248 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007249
Michael Chan2bc40782012-12-06 10:33:09 +00007250 ering->rx_max_pending = BNX2_MAX_TOTAL_RX_DESC_CNT;
7251 ering->rx_jumbo_max_pending = BNX2_MAX_TOTAL_RX_PG_DESC_CNT;
Michael Chanb6016b72005-05-26 13:03:09 -07007252
7253 ering->rx_pending = bp->rx_ring_size;
Michael Chan47bf4242007-12-12 11:19:12 -08007254 ering->rx_jumbo_pending = bp->rx_pg_ring_size;
Michael Chanb6016b72005-05-26 13:03:09 -07007255
Michael Chan2bc40782012-12-06 10:33:09 +00007256 ering->tx_max_pending = BNX2_MAX_TX_DESC_CNT;
Michael Chanb6016b72005-05-26 13:03:09 -07007257 ering->tx_pending = bp->tx_ring_size;
7258}
7259
7260static int
Michael Chanb0332812012-02-05 15:24:38 +00007261bnx2_change_ring_size(struct bnx2 *bp, u32 rx, u32 tx, bool reset_irq)
Michael Chanb6016b72005-05-26 13:03:09 -07007262{
Michael Chan13daffa2006-03-20 17:49:20 -08007263 if (netif_running(bp->dev)) {
Michael Chan354fcd72010-01-17 07:30:44 +00007264 /* Reset will erase chipset stats; save them */
7265 bnx2_save_stats(bp);
7266
Michael Chan212f9932010-04-27 11:28:10 +00007267 bnx2_netif_stop(bp, true);
Michael Chan13daffa2006-03-20 17:49:20 -08007268 bnx2_reset_chip(bp, BNX2_DRV_MSG_CODE_RESET);
Michael Chanb0332812012-02-05 15:24:38 +00007269 if (reset_irq) {
7270 bnx2_free_irq(bp);
7271 bnx2_del_napi(bp);
7272 } else {
7273 __bnx2_free_irq(bp);
7274 }
Michael Chan13daffa2006-03-20 17:49:20 -08007275 bnx2_free_skbs(bp);
7276 bnx2_free_mem(bp);
7277 }
7278
Michael Chan5d5d0012007-12-12 11:17:43 -08007279 bnx2_set_rx_ring_size(bp, rx);
7280 bp->tx_ring_size = tx;
Michael Chanb6016b72005-05-26 13:03:09 -07007281
7282 if (netif_running(bp->dev)) {
Michael Chanb0332812012-02-05 15:24:38 +00007283 int rc = 0;
Michael Chan13daffa2006-03-20 17:49:20 -08007284
Michael Chanb0332812012-02-05 15:24:38 +00007285 if (reset_irq) {
7286 rc = bnx2_setup_int_mode(bp, disable_msi);
7287 bnx2_init_napi(bp);
7288 }
7289
7290 if (!rc)
7291 rc = bnx2_alloc_mem(bp);
7292
Michael Chan6fefb652009-08-21 16:20:45 +00007293 if (!rc)
Michael Chana29ba9d2010-12-31 11:03:14 -08007294 rc = bnx2_request_irq(bp);
7295
7296 if (!rc)
Michael Chan6fefb652009-08-21 16:20:45 +00007297 rc = bnx2_init_nic(bp, 0);
7298
7299 if (rc) {
7300 bnx2_napi_enable(bp);
7301 dev_close(bp->dev);
Michael Chan13daffa2006-03-20 17:49:20 -08007302 return rc;
Michael Chan6fefb652009-08-21 16:20:45 +00007303 }
Michael Chane9f26c42010-02-15 19:42:08 +00007304#ifdef BCM_CNIC
7305 mutex_lock(&bp->cnic_lock);
7306 /* Let cnic know about the new status block. */
7307 if (bp->cnic_eth_dev.drv_state & CNIC_DRV_STATE_REGD)
7308 bnx2_setup_cnic_irq_info(bp);
7309 mutex_unlock(&bp->cnic_lock);
7310#endif
Michael Chan212f9932010-04-27 11:28:10 +00007311 bnx2_netif_start(bp, true);
Michael Chanb6016b72005-05-26 13:03:09 -07007312 }
Michael Chanb6016b72005-05-26 13:03:09 -07007313 return 0;
7314}
7315
Michael Chan5d5d0012007-12-12 11:17:43 -08007316static int
7317bnx2_set_ringparam(struct net_device *dev, struct ethtool_ringparam *ering)
7318{
7319 struct bnx2 *bp = netdev_priv(dev);
7320 int rc;
7321
Michael Chan2bc40782012-12-06 10:33:09 +00007322 if ((ering->rx_pending > BNX2_MAX_TOTAL_RX_DESC_CNT) ||
7323 (ering->tx_pending > BNX2_MAX_TX_DESC_CNT) ||
Michael Chan5d5d0012007-12-12 11:17:43 -08007324 (ering->tx_pending <= MAX_SKB_FRAGS)) {
7325
7326 return -EINVAL;
7327 }
Michael Chanb0332812012-02-05 15:24:38 +00007328 rc = bnx2_change_ring_size(bp, ering->rx_pending, ering->tx_pending,
7329 false);
Michael Chan5d5d0012007-12-12 11:17:43 -08007330 return rc;
7331}
7332
Michael Chanb6016b72005-05-26 13:03:09 -07007333static void
7334bnx2_get_pauseparam(struct net_device *dev, struct ethtool_pauseparam *epause)
7335{
Michael Chan972ec0d2006-01-23 16:12:43 -08007336 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007337
7338 epause->autoneg = ((bp->autoneg & AUTONEG_FLOW_CTRL) != 0);
7339 epause->rx_pause = ((bp->flow_ctrl & FLOW_CTRL_RX) != 0);
7340 epause->tx_pause = ((bp->flow_ctrl & FLOW_CTRL_TX) != 0);
7341}
7342
7343static int
7344bnx2_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam *epause)
7345{
Michael Chan972ec0d2006-01-23 16:12:43 -08007346 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007347
7348 bp->req_flow_ctrl = 0;
7349 if (epause->rx_pause)
7350 bp->req_flow_ctrl |= FLOW_CTRL_RX;
7351 if (epause->tx_pause)
7352 bp->req_flow_ctrl |= FLOW_CTRL_TX;
7353
7354 if (epause->autoneg) {
7355 bp->autoneg |= AUTONEG_FLOW_CTRL;
7356 }
7357 else {
7358 bp->autoneg &= ~AUTONEG_FLOW_CTRL;
7359 }
7360
Michael Chan9f52b562008-10-09 12:21:46 -07007361 if (netif_running(dev)) {
7362 spin_lock_bh(&bp->phy_lock);
7363 bnx2_setup_phy(bp, bp->phy_port);
7364 spin_unlock_bh(&bp->phy_lock);
7365 }
Michael Chanb6016b72005-05-26 13:03:09 -07007366
7367 return 0;
7368}
7369
Peter Hagervall14ab9b82005-08-10 14:18:16 -07007370static struct {
Michael Chanb6016b72005-05-26 13:03:09 -07007371 char string[ETH_GSTRING_LEN];
Michael Chan790dab22009-08-21 16:20:47 +00007372} bnx2_stats_str_arr[] = {
Michael Chanb6016b72005-05-26 13:03:09 -07007373 { "rx_bytes" },
7374 { "rx_error_bytes" },
7375 { "tx_bytes" },
7376 { "tx_error_bytes" },
7377 { "rx_ucast_packets" },
7378 { "rx_mcast_packets" },
7379 { "rx_bcast_packets" },
7380 { "tx_ucast_packets" },
7381 { "tx_mcast_packets" },
7382 { "tx_bcast_packets" },
7383 { "tx_mac_errors" },
7384 { "tx_carrier_errors" },
7385 { "rx_crc_errors" },
7386 { "rx_align_errors" },
7387 { "tx_single_collisions" },
7388 { "tx_multi_collisions" },
7389 { "tx_deferred" },
7390 { "tx_excess_collisions" },
7391 { "tx_late_collisions" },
7392 { "tx_total_collisions" },
7393 { "rx_fragments" },
7394 { "rx_jabbers" },
7395 { "rx_undersize_packets" },
7396 { "rx_oversize_packets" },
7397 { "rx_64_byte_packets" },
7398 { "rx_65_to_127_byte_packets" },
7399 { "rx_128_to_255_byte_packets" },
7400 { "rx_256_to_511_byte_packets" },
7401 { "rx_512_to_1023_byte_packets" },
7402 { "rx_1024_to_1522_byte_packets" },
7403 { "rx_1523_to_9022_byte_packets" },
7404 { "tx_64_byte_packets" },
7405 { "tx_65_to_127_byte_packets" },
7406 { "tx_128_to_255_byte_packets" },
7407 { "tx_256_to_511_byte_packets" },
7408 { "tx_512_to_1023_byte_packets" },
7409 { "tx_1024_to_1522_byte_packets" },
7410 { "tx_1523_to_9022_byte_packets" },
7411 { "rx_xon_frames" },
7412 { "rx_xoff_frames" },
7413 { "tx_xon_frames" },
7414 { "tx_xoff_frames" },
7415 { "rx_mac_ctrl_frames" },
7416 { "rx_filtered_packets" },
Michael Chan790dab22009-08-21 16:20:47 +00007417 { "rx_ftq_discards" },
Michael Chanb6016b72005-05-26 13:03:09 -07007418 { "rx_discards" },
Michael Chancea94db2006-06-12 22:16:13 -07007419 { "rx_fw_discards" },
Michael Chanb6016b72005-05-26 13:03:09 -07007420};
7421
Jim Cromie0db83cd2012-04-10 14:56:03 +00007422#define BNX2_NUM_STATS ARRAY_SIZE(bnx2_stats_str_arr)
Michael Chan790dab22009-08-21 16:20:47 +00007423
Michael Chanb6016b72005-05-26 13:03:09 -07007424#define STATS_OFFSET32(offset_name) (offsetof(struct statistics_block, offset_name) / 4)
7425
Arjan van de Venf71e1302006-03-03 21:33:57 -05007426static const unsigned long bnx2_stats_offset_arr[BNX2_NUM_STATS] = {
Michael Chanb6016b72005-05-26 13:03:09 -07007427 STATS_OFFSET32(stat_IfHCInOctets_hi),
7428 STATS_OFFSET32(stat_IfHCInBadOctets_hi),
7429 STATS_OFFSET32(stat_IfHCOutOctets_hi),
7430 STATS_OFFSET32(stat_IfHCOutBadOctets_hi),
7431 STATS_OFFSET32(stat_IfHCInUcastPkts_hi),
7432 STATS_OFFSET32(stat_IfHCInMulticastPkts_hi),
7433 STATS_OFFSET32(stat_IfHCInBroadcastPkts_hi),
7434 STATS_OFFSET32(stat_IfHCOutUcastPkts_hi),
7435 STATS_OFFSET32(stat_IfHCOutMulticastPkts_hi),
7436 STATS_OFFSET32(stat_IfHCOutBroadcastPkts_hi),
7437 STATS_OFFSET32(stat_emac_tx_stat_dot3statsinternalmactransmiterrors),
Jeff Garzik6aa20a22006-09-13 13:24:59 -04007438 STATS_OFFSET32(stat_Dot3StatsCarrierSenseErrors),
7439 STATS_OFFSET32(stat_Dot3StatsFCSErrors),
7440 STATS_OFFSET32(stat_Dot3StatsAlignmentErrors),
7441 STATS_OFFSET32(stat_Dot3StatsSingleCollisionFrames),
7442 STATS_OFFSET32(stat_Dot3StatsMultipleCollisionFrames),
7443 STATS_OFFSET32(stat_Dot3StatsDeferredTransmissions),
7444 STATS_OFFSET32(stat_Dot3StatsExcessiveCollisions),
7445 STATS_OFFSET32(stat_Dot3StatsLateCollisions),
7446 STATS_OFFSET32(stat_EtherStatsCollisions),
7447 STATS_OFFSET32(stat_EtherStatsFragments),
7448 STATS_OFFSET32(stat_EtherStatsJabbers),
7449 STATS_OFFSET32(stat_EtherStatsUndersizePkts),
7450 STATS_OFFSET32(stat_EtherStatsOverrsizePkts),
7451 STATS_OFFSET32(stat_EtherStatsPktsRx64Octets),
7452 STATS_OFFSET32(stat_EtherStatsPktsRx65Octetsto127Octets),
7453 STATS_OFFSET32(stat_EtherStatsPktsRx128Octetsto255Octets),
7454 STATS_OFFSET32(stat_EtherStatsPktsRx256Octetsto511Octets),
7455 STATS_OFFSET32(stat_EtherStatsPktsRx512Octetsto1023Octets),
7456 STATS_OFFSET32(stat_EtherStatsPktsRx1024Octetsto1522Octets),
7457 STATS_OFFSET32(stat_EtherStatsPktsRx1523Octetsto9022Octets),
7458 STATS_OFFSET32(stat_EtherStatsPktsTx64Octets),
7459 STATS_OFFSET32(stat_EtherStatsPktsTx65Octetsto127Octets),
7460 STATS_OFFSET32(stat_EtherStatsPktsTx128Octetsto255Octets),
7461 STATS_OFFSET32(stat_EtherStatsPktsTx256Octetsto511Octets),
7462 STATS_OFFSET32(stat_EtherStatsPktsTx512Octetsto1023Octets),
7463 STATS_OFFSET32(stat_EtherStatsPktsTx1024Octetsto1522Octets),
7464 STATS_OFFSET32(stat_EtherStatsPktsTx1523Octetsto9022Octets),
7465 STATS_OFFSET32(stat_XonPauseFramesReceived),
7466 STATS_OFFSET32(stat_XoffPauseFramesReceived),
7467 STATS_OFFSET32(stat_OutXonSent),
7468 STATS_OFFSET32(stat_OutXoffSent),
7469 STATS_OFFSET32(stat_MacControlFramesReceived),
7470 STATS_OFFSET32(stat_IfInFramesL2FilterDiscards),
Michael Chan790dab22009-08-21 16:20:47 +00007471 STATS_OFFSET32(stat_IfInFTQDiscards),
Jeff Garzik6aa20a22006-09-13 13:24:59 -04007472 STATS_OFFSET32(stat_IfInMBUFDiscards),
Michael Chancea94db2006-06-12 22:16:13 -07007473 STATS_OFFSET32(stat_FwRxDrop),
Michael Chanb6016b72005-05-26 13:03:09 -07007474};
7475
7476/* stat_IfHCInBadOctets and stat_Dot3StatsCarrierSenseErrors are
7477 * skipped because of errata.
Jeff Garzik6aa20a22006-09-13 13:24:59 -04007478 */
Peter Hagervall14ab9b82005-08-10 14:18:16 -07007479static u8 bnx2_5706_stats_len_arr[BNX2_NUM_STATS] = {
Michael Chanb6016b72005-05-26 13:03:09 -07007480 8,0,8,8,8,8,8,8,8,8,
7481 4,0,4,4,4,4,4,4,4,4,
7482 4,4,4,4,4,4,4,4,4,4,
7483 4,4,4,4,4,4,4,4,4,4,
Michael Chan790dab22009-08-21 16:20:47 +00007484 4,4,4,4,4,4,4,
Michael Chanb6016b72005-05-26 13:03:09 -07007485};
7486
Michael Chan5b0c76a2005-11-04 08:45:49 -08007487static u8 bnx2_5708_stats_len_arr[BNX2_NUM_STATS] = {
7488 8,0,8,8,8,8,8,8,8,8,
7489 4,4,4,4,4,4,4,4,4,4,
7490 4,4,4,4,4,4,4,4,4,4,
7491 4,4,4,4,4,4,4,4,4,4,
Michael Chan790dab22009-08-21 16:20:47 +00007492 4,4,4,4,4,4,4,
Michael Chan5b0c76a2005-11-04 08:45:49 -08007493};
7494
Michael Chanb6016b72005-05-26 13:03:09 -07007495#define BNX2_NUM_TESTS 6
7496
Peter Hagervall14ab9b82005-08-10 14:18:16 -07007497static struct {
Michael Chanb6016b72005-05-26 13:03:09 -07007498 char string[ETH_GSTRING_LEN];
7499} bnx2_tests_str_arr[BNX2_NUM_TESTS] = {
7500 { "register_test (offline)" },
7501 { "memory_test (offline)" },
7502 { "loopback_test (offline)" },
7503 { "nvram_test (online)" },
7504 { "interrupt_test (online)" },
7505 { "link_test (online)" },
7506};
7507
7508static int
Jeff Garzikb9f2c042007-10-03 18:07:32 -07007509bnx2_get_sset_count(struct net_device *dev, int sset)
Michael Chanb6016b72005-05-26 13:03:09 -07007510{
Jeff Garzikb9f2c042007-10-03 18:07:32 -07007511 switch (sset) {
7512 case ETH_SS_TEST:
7513 return BNX2_NUM_TESTS;
7514 case ETH_SS_STATS:
7515 return BNX2_NUM_STATS;
7516 default:
7517 return -EOPNOTSUPP;
7518 }
Michael Chanb6016b72005-05-26 13:03:09 -07007519}
7520
7521static void
7522bnx2_self_test(struct net_device *dev, struct ethtool_test *etest, u64 *buf)
7523{
Michael Chan972ec0d2006-01-23 16:12:43 -08007524 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007525
7526 memset(buf, 0, sizeof(u64) * BNX2_NUM_TESTS);
7527 if (etest->flags & ETH_TEST_FL_OFFLINE) {
Michael Chan80be4432006-11-19 14:07:28 -08007528 int i;
7529
Michael Chan212f9932010-04-27 11:28:10 +00007530 bnx2_netif_stop(bp, true);
Michael Chanb6016b72005-05-26 13:03:09 -07007531 bnx2_reset_chip(bp, BNX2_DRV_MSG_CODE_DIAG);
7532 bnx2_free_skbs(bp);
7533
7534 if (bnx2_test_registers(bp) != 0) {
7535 buf[0] = 1;
7536 etest->flags |= ETH_TEST_FL_FAILED;
7537 }
7538 if (bnx2_test_memory(bp) != 0) {
7539 buf[1] = 1;
7540 etest->flags |= ETH_TEST_FL_FAILED;
7541 }
Michael Chanbc5a0692006-01-23 16:13:22 -08007542 if ((buf[2] = bnx2_test_loopback(bp)) != 0)
Michael Chanb6016b72005-05-26 13:03:09 -07007543 etest->flags |= ETH_TEST_FL_FAILED;
Michael Chanb6016b72005-05-26 13:03:09 -07007544
Michael Chan9f52b562008-10-09 12:21:46 -07007545 if (!netif_running(bp->dev))
7546 bnx2_shutdown_chip(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07007547 else {
Michael Chan9a120bc2008-05-16 22:17:45 -07007548 bnx2_init_nic(bp, 1);
Michael Chan212f9932010-04-27 11:28:10 +00007549 bnx2_netif_start(bp, true);
Michael Chanb6016b72005-05-26 13:03:09 -07007550 }
7551
7552 /* wait for link up */
Michael Chan80be4432006-11-19 14:07:28 -08007553 for (i = 0; i < 7; i++) {
7554 if (bp->link_up)
7555 break;
7556 msleep_interruptible(1000);
7557 }
Michael Chanb6016b72005-05-26 13:03:09 -07007558 }
7559
7560 if (bnx2_test_nvram(bp) != 0) {
7561 buf[3] = 1;
7562 etest->flags |= ETH_TEST_FL_FAILED;
7563 }
7564 if (bnx2_test_intr(bp) != 0) {
7565 buf[4] = 1;
7566 etest->flags |= ETH_TEST_FL_FAILED;
7567 }
7568
7569 if (bnx2_test_link(bp) != 0) {
7570 buf[5] = 1;
7571 etest->flags |= ETH_TEST_FL_FAILED;
7572
7573 }
7574}
7575
7576static void
7577bnx2_get_strings(struct net_device *dev, u32 stringset, u8 *buf)
7578{
7579 switch (stringset) {
7580 case ETH_SS_STATS:
7581 memcpy(buf, bnx2_stats_str_arr,
7582 sizeof(bnx2_stats_str_arr));
7583 break;
7584 case ETH_SS_TEST:
7585 memcpy(buf, bnx2_tests_str_arr,
7586 sizeof(bnx2_tests_str_arr));
7587 break;
7588 }
7589}
7590
Michael Chanb6016b72005-05-26 13:03:09 -07007591static void
7592bnx2_get_ethtool_stats(struct net_device *dev,
7593 struct ethtool_stats *stats, u64 *buf)
7594{
Michael Chan972ec0d2006-01-23 16:12:43 -08007595 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007596 int i;
7597 u32 *hw_stats = (u32 *) bp->stats_blk;
Michael Chan354fcd72010-01-17 07:30:44 +00007598 u32 *temp_stats = (u32 *) bp->temp_stats_blk;
Peter Hagervall14ab9b82005-08-10 14:18:16 -07007599 u8 *stats_len_arr = NULL;
Michael Chanb6016b72005-05-26 13:03:09 -07007600
7601 if (hw_stats == NULL) {
7602 memset(buf, 0, sizeof(u64) * BNX2_NUM_STATS);
7603 return;
7604 }
7605
Michael Chan4ce45e02012-12-06 10:33:10 +00007606 if ((BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5706_A0) ||
7607 (BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5706_A1) ||
7608 (BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5706_A2) ||
7609 (BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5708_A0))
Michael Chanb6016b72005-05-26 13:03:09 -07007610 stats_len_arr = bnx2_5706_stats_len_arr;
Michael Chan5b0c76a2005-11-04 08:45:49 -08007611 else
7612 stats_len_arr = bnx2_5708_stats_len_arr;
Michael Chanb6016b72005-05-26 13:03:09 -07007613
7614 for (i = 0; i < BNX2_NUM_STATS; i++) {
Michael Chan354fcd72010-01-17 07:30:44 +00007615 unsigned long offset;
7616
Michael Chanb6016b72005-05-26 13:03:09 -07007617 if (stats_len_arr[i] == 0) {
7618 /* skip this counter */
7619 buf[i] = 0;
7620 continue;
7621 }
Michael Chan354fcd72010-01-17 07:30:44 +00007622
7623 offset = bnx2_stats_offset_arr[i];
Michael Chanb6016b72005-05-26 13:03:09 -07007624 if (stats_len_arr[i] == 4) {
7625 /* 4-byte counter */
Michael Chan354fcd72010-01-17 07:30:44 +00007626 buf[i] = (u64) *(hw_stats + offset) +
7627 *(temp_stats + offset);
Michael Chanb6016b72005-05-26 13:03:09 -07007628 continue;
7629 }
7630 /* 8-byte counter */
Michael Chan354fcd72010-01-17 07:30:44 +00007631 buf[i] = (((u64) *(hw_stats + offset)) << 32) +
7632 *(hw_stats + offset + 1) +
7633 (((u64) *(temp_stats + offset)) << 32) +
7634 *(temp_stats + offset + 1);
Michael Chanb6016b72005-05-26 13:03:09 -07007635 }
7636}
7637
7638static int
stephen hemminger2e17e1a2011-04-04 11:06:36 +00007639bnx2_set_phys_id(struct net_device *dev, enum ethtool_phys_id_state state)
Michael Chanb6016b72005-05-26 13:03:09 -07007640{
Michael Chan972ec0d2006-01-23 16:12:43 -08007641 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007642
stephen hemminger2e17e1a2011-04-04 11:06:36 +00007643 switch (state) {
7644 case ETHTOOL_ID_ACTIVE:
Michael Chane503e062012-12-06 10:33:08 +00007645 bp->leds_save = BNX2_RD(bp, BNX2_MISC_CFG);
7646 BNX2_WR(bp, BNX2_MISC_CFG, BNX2_MISC_CFG_LEDMODE_MAC);
Allan, Bruce Wfce55922011-04-13 13:09:10 +00007647 return 1; /* cycle on/off once per second */
Michael Chanb6016b72005-05-26 13:03:09 -07007648
stephen hemminger2e17e1a2011-04-04 11:06:36 +00007649 case ETHTOOL_ID_ON:
Michael Chane503e062012-12-06 10:33:08 +00007650 BNX2_WR(bp, BNX2_EMAC_LED, BNX2_EMAC_LED_OVERRIDE |
7651 BNX2_EMAC_LED_1000MB_OVERRIDE |
7652 BNX2_EMAC_LED_100MB_OVERRIDE |
7653 BNX2_EMAC_LED_10MB_OVERRIDE |
7654 BNX2_EMAC_LED_TRAFFIC_OVERRIDE |
7655 BNX2_EMAC_LED_TRAFFIC);
stephen hemminger2e17e1a2011-04-04 11:06:36 +00007656 break;
Michael Chanb6016b72005-05-26 13:03:09 -07007657
stephen hemminger2e17e1a2011-04-04 11:06:36 +00007658 case ETHTOOL_ID_OFF:
Michael Chane503e062012-12-06 10:33:08 +00007659 BNX2_WR(bp, BNX2_EMAC_LED, BNX2_EMAC_LED_OVERRIDE);
stephen hemminger2e17e1a2011-04-04 11:06:36 +00007660 break;
7661
7662 case ETHTOOL_ID_INACTIVE:
Michael Chane503e062012-12-06 10:33:08 +00007663 BNX2_WR(bp, BNX2_EMAC_LED, 0);
7664 BNX2_WR(bp, BNX2_MISC_CFG, bp->leds_save);
stephen hemminger2e17e1a2011-04-04 11:06:36 +00007665 break;
Michael Chanb6016b72005-05-26 13:03:09 -07007666 }
Michael Chan9f52b562008-10-09 12:21:46 -07007667
Michael Chanb6016b72005-05-26 13:03:09 -07007668 return 0;
7669}
7670
Michał Mirosławc8f44af2011-11-15 15:29:55 +00007671static netdev_features_t
7672bnx2_fix_features(struct net_device *dev, netdev_features_t features)
Michael Chan4666f872007-05-03 13:22:28 -07007673{
7674 struct bnx2 *bp = netdev_priv(dev);
7675
Michał Mirosław8d7dfc22011-04-10 04:47:46 +00007676 if (!(bp->flags & BNX2_FLAG_CAN_KEEP_VLAN))
Patrick McHardyf6469682013-04-19 02:04:27 +00007677 features |= NETIF_F_HW_VLAN_CTAG_RX;
Michał Mirosław8d7dfc22011-04-10 04:47:46 +00007678
7679 return features;
Michael Chan4666f872007-05-03 13:22:28 -07007680}
7681
Michael Chanfdc85412010-07-03 20:42:16 +00007682static int
Michał Mirosławc8f44af2011-11-15 15:29:55 +00007683bnx2_set_features(struct net_device *dev, netdev_features_t features)
Michael Chanfdc85412010-07-03 20:42:16 +00007684{
Jesse Gross7d0fd212010-10-20 13:56:09 +00007685 struct bnx2 *bp = netdev_priv(dev);
Jesse Gross7d0fd212010-10-20 13:56:09 +00007686
Michael Chan7c810472011-01-24 12:59:02 +00007687 /* TSO with VLAN tag won't work with current firmware */
Patrick McHardyf6469682013-04-19 02:04:27 +00007688 if (features & NETIF_F_HW_VLAN_CTAG_TX)
Michał Mirosław8d7dfc22011-04-10 04:47:46 +00007689 dev->vlan_features |= (dev->hw_features & NETIF_F_ALL_TSO);
7690 else
7691 dev->vlan_features &= ~NETIF_F_ALL_TSO;
Michael Chan7c810472011-01-24 12:59:02 +00007692
Patrick McHardyf6469682013-04-19 02:04:27 +00007693 if ((!!(features & NETIF_F_HW_VLAN_CTAG_RX) !=
Jesse Gross7d0fd212010-10-20 13:56:09 +00007694 !!(bp->rx_mode & BNX2_EMAC_RX_MODE_KEEP_VLAN_TAG)) &&
7695 netif_running(dev)) {
7696 bnx2_netif_stop(bp, false);
Michał Mirosław8d7dfc22011-04-10 04:47:46 +00007697 dev->features = features;
Jesse Gross7d0fd212010-10-20 13:56:09 +00007698 bnx2_set_rx_mode(dev);
7699 bnx2_fw_sync(bp, BNX2_DRV_MSG_CODE_KEEP_VLAN_UPDATE, 0, 1);
7700 bnx2_netif_start(bp, false);
Michał Mirosław8d7dfc22011-04-10 04:47:46 +00007701 return 1;
Jesse Gross7d0fd212010-10-20 13:56:09 +00007702 }
7703
7704 return 0;
Michael Chanfdc85412010-07-03 20:42:16 +00007705}
7706
Michael Chanb0332812012-02-05 15:24:38 +00007707static void bnx2_get_channels(struct net_device *dev,
7708 struct ethtool_channels *channels)
7709{
7710 struct bnx2 *bp = netdev_priv(dev);
7711 u32 max_rx_rings = 1;
7712 u32 max_tx_rings = 1;
7713
7714 if ((bp->flags & BNX2_FLAG_MSIX_CAP) && !disable_msi) {
7715 max_rx_rings = RX_MAX_RINGS;
7716 max_tx_rings = TX_MAX_RINGS;
7717 }
7718
7719 channels->max_rx = max_rx_rings;
7720 channels->max_tx = max_tx_rings;
7721 channels->max_other = 0;
7722 channels->max_combined = 0;
7723 channels->rx_count = bp->num_rx_rings;
7724 channels->tx_count = bp->num_tx_rings;
7725 channels->other_count = 0;
7726 channels->combined_count = 0;
7727}
7728
7729static int bnx2_set_channels(struct net_device *dev,
7730 struct ethtool_channels *channels)
7731{
7732 struct bnx2 *bp = netdev_priv(dev);
7733 u32 max_rx_rings = 1;
7734 u32 max_tx_rings = 1;
7735 int rc = 0;
7736
7737 if ((bp->flags & BNX2_FLAG_MSIX_CAP) && !disable_msi) {
7738 max_rx_rings = RX_MAX_RINGS;
7739 max_tx_rings = TX_MAX_RINGS;
7740 }
7741 if (channels->rx_count > max_rx_rings ||
7742 channels->tx_count > max_tx_rings)
7743 return -EINVAL;
7744
7745 bp->num_req_rx_rings = channels->rx_count;
7746 bp->num_req_tx_rings = channels->tx_count;
7747
7748 if (netif_running(dev))
7749 rc = bnx2_change_ring_size(bp, bp->rx_ring_size,
7750 bp->tx_ring_size, true);
7751
7752 return rc;
7753}
7754
Jeff Garzik7282d492006-09-13 14:30:00 -04007755static const struct ethtool_ops bnx2_ethtool_ops = {
Michael Chanb6016b72005-05-26 13:03:09 -07007756 .get_settings = bnx2_get_settings,
7757 .set_settings = bnx2_set_settings,
7758 .get_drvinfo = bnx2_get_drvinfo,
Michael Chan244ac4f2006-03-20 17:48:46 -08007759 .get_regs_len = bnx2_get_regs_len,
7760 .get_regs = bnx2_get_regs,
Michael Chanb6016b72005-05-26 13:03:09 -07007761 .get_wol = bnx2_get_wol,
7762 .set_wol = bnx2_set_wol,
7763 .nway_reset = bnx2_nway_reset,
Ooiwa Naohiro7959ea22009-06-24 00:19:06 -07007764 .get_link = bnx2_get_link,
Michael Chanb6016b72005-05-26 13:03:09 -07007765 .get_eeprom_len = bnx2_get_eeprom_len,
7766 .get_eeprom = bnx2_get_eeprom,
7767 .set_eeprom = bnx2_set_eeprom,
7768 .get_coalesce = bnx2_get_coalesce,
7769 .set_coalesce = bnx2_set_coalesce,
7770 .get_ringparam = bnx2_get_ringparam,
7771 .set_ringparam = bnx2_set_ringparam,
7772 .get_pauseparam = bnx2_get_pauseparam,
7773 .set_pauseparam = bnx2_set_pauseparam,
Michael Chanb6016b72005-05-26 13:03:09 -07007774 .self_test = bnx2_self_test,
7775 .get_strings = bnx2_get_strings,
stephen hemminger2e17e1a2011-04-04 11:06:36 +00007776 .set_phys_id = bnx2_set_phys_id,
Michael Chanb6016b72005-05-26 13:03:09 -07007777 .get_ethtool_stats = bnx2_get_ethtool_stats,
Jeff Garzikb9f2c042007-10-03 18:07:32 -07007778 .get_sset_count = bnx2_get_sset_count,
Michael Chanb0332812012-02-05 15:24:38 +00007779 .get_channels = bnx2_get_channels,
7780 .set_channels = bnx2_set_channels,
Michael Chanb6016b72005-05-26 13:03:09 -07007781};
7782
7783/* Called with rtnl_lock */
7784static int
7785bnx2_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
7786{
Peter Hagervall14ab9b82005-08-10 14:18:16 -07007787 struct mii_ioctl_data *data = if_mii(ifr);
Michael Chan972ec0d2006-01-23 16:12:43 -08007788 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007789 int err;
7790
7791 switch(cmd) {
7792 case SIOCGMIIPHY:
7793 data->phy_id = bp->phy_addr;
7794
7795 /* fallthru */
7796 case SIOCGMIIREG: {
7797 u32 mii_regval;
7798
Michael Chan583c28e2008-01-21 19:51:35 -08007799 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
Michael Chan7b6b8342007-07-07 22:50:15 -07007800 return -EOPNOTSUPP;
7801
Michael Chandad3e452007-05-03 13:18:03 -07007802 if (!netif_running(dev))
7803 return -EAGAIN;
7804
Michael Chanc770a652005-08-25 15:38:39 -07007805 spin_lock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07007806 err = bnx2_read_phy(bp, data->reg_num & 0x1f, &mii_regval);
Michael Chanc770a652005-08-25 15:38:39 -07007807 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07007808
7809 data->val_out = mii_regval;
7810
7811 return err;
7812 }
7813
7814 case SIOCSMIIREG:
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_write_phy(bp, data->reg_num & 0x1f, data->val_in);
Michael Chanc770a652005-08-25 15:38:39 -07007823 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07007824
7825 return err;
7826
7827 default:
7828 /* do nothing */
7829 break;
7830 }
7831 return -EOPNOTSUPP;
7832}
7833
7834/* Called with rtnl_lock */
7835static int
7836bnx2_change_mac_addr(struct net_device *dev, void *p)
7837{
7838 struct sockaddr *addr = p;
Michael Chan972ec0d2006-01-23 16:12:43 -08007839 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007840
Michael Chan73eef4c2005-08-25 15:39:15 -07007841 if (!is_valid_ether_addr(addr->sa_data))
Danny Kukawka504f9b52012-02-21 02:07:49 +00007842 return -EADDRNOTAVAIL;
Michael Chan73eef4c2005-08-25 15:39:15 -07007843
Michael Chanb6016b72005-05-26 13:03:09 -07007844 memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
7845 if (netif_running(dev))
Benjamin Li5fcaed02008-07-14 22:39:52 -07007846 bnx2_set_mac_addr(bp, bp->dev->dev_addr, 0);
Michael Chanb6016b72005-05-26 13:03:09 -07007847
7848 return 0;
7849}
7850
7851/* Called with rtnl_lock */
7852static int
7853bnx2_change_mtu(struct net_device *dev, int new_mtu)
7854{
Michael Chan972ec0d2006-01-23 16:12:43 -08007855 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007856
7857 if (((new_mtu + ETH_HLEN) > MAX_ETHERNET_JUMBO_PACKET_SIZE) ||
7858 ((new_mtu + ETH_HLEN) < MIN_ETHERNET_PACKET_SIZE))
7859 return -EINVAL;
7860
7861 dev->mtu = new_mtu;
Michael Chanb0332812012-02-05 15:24:38 +00007862 return bnx2_change_ring_size(bp, bp->rx_ring_size, bp->tx_ring_size,
7863 false);
Michael Chanb6016b72005-05-26 13:03:09 -07007864}
7865
Alexey Dobriyan257ddbd2010-01-27 10:17:41 +00007866#ifdef CONFIG_NET_POLL_CONTROLLER
Michael Chanb6016b72005-05-26 13:03:09 -07007867static void
7868poll_bnx2(struct net_device *dev)
7869{
Michael Chan972ec0d2006-01-23 16:12:43 -08007870 struct bnx2 *bp = netdev_priv(dev);
Neil Hormanb2af2c12008-11-12 16:23:44 -08007871 int i;
Michael Chanb6016b72005-05-26 13:03:09 -07007872
Neil Hormanb2af2c12008-11-12 16:23:44 -08007873 for (i = 0; i < bp->irq_nvecs; i++) {
Michael Chan1bf1e342010-03-23 13:13:12 +00007874 struct bnx2_irq *irq = &bp->irq_tbl[i];
7875
7876 disable_irq(irq->vector);
7877 irq->handler(irq->vector, &bp->bnx2_napi[i]);
7878 enable_irq(irq->vector);
Neil Hormanb2af2c12008-11-12 16:23:44 -08007879 }
Michael Chanb6016b72005-05-26 13:03:09 -07007880}
7881#endif
7882
Bill Pembertoncfd95a62012-12-03 09:22:58 -05007883static void
Michael Chan253c8b72007-01-08 19:56:01 -08007884bnx2_get_5709_media(struct bnx2 *bp)
7885{
Michael Chane503e062012-12-06 10:33:08 +00007886 u32 val = BNX2_RD(bp, BNX2_MISC_DUAL_MEDIA_CTRL);
Michael Chan253c8b72007-01-08 19:56:01 -08007887 u32 bond_id = val & BNX2_MISC_DUAL_MEDIA_CTRL_BOND_ID;
7888 u32 strap;
7889
7890 if (bond_id == BNX2_MISC_DUAL_MEDIA_CTRL_BOND_ID_C)
7891 return;
7892 else if (bond_id == BNX2_MISC_DUAL_MEDIA_CTRL_BOND_ID_S) {
Michael Chan583c28e2008-01-21 19:51:35 -08007893 bp->phy_flags |= BNX2_PHY_FLAG_SERDES;
Michael Chan253c8b72007-01-08 19:56:01 -08007894 return;
7895 }
7896
7897 if (val & BNX2_MISC_DUAL_MEDIA_CTRL_STRAP_OVERRIDE)
7898 strap = (val & BNX2_MISC_DUAL_MEDIA_CTRL_PHY_CTRL) >> 21;
7899 else
7900 strap = (val & BNX2_MISC_DUAL_MEDIA_CTRL_PHY_CTRL_STRAP) >> 8;
7901
Michael Chanaefd90e2012-06-16 15:45:43 +00007902 if (bp->func == 0) {
Michael Chan253c8b72007-01-08 19:56:01 -08007903 switch (strap) {
7904 case 0x4:
7905 case 0x5:
7906 case 0x6:
Michael Chan583c28e2008-01-21 19:51:35 -08007907 bp->phy_flags |= BNX2_PHY_FLAG_SERDES;
Michael Chan253c8b72007-01-08 19:56:01 -08007908 return;
7909 }
7910 } else {
7911 switch (strap) {
7912 case 0x1:
7913 case 0x2:
7914 case 0x4:
Michael Chan583c28e2008-01-21 19:51:35 -08007915 bp->phy_flags |= BNX2_PHY_FLAG_SERDES;
Michael Chan253c8b72007-01-08 19:56:01 -08007916 return;
7917 }
7918 }
7919}
7920
Bill Pembertoncfd95a62012-12-03 09:22:58 -05007921static void
Michael Chan883e5152007-05-03 13:25:11 -07007922bnx2_get_pci_speed(struct bnx2 *bp)
7923{
7924 u32 reg;
7925
Michael Chane503e062012-12-06 10:33:08 +00007926 reg = BNX2_RD(bp, BNX2_PCICFG_MISC_STATUS);
Michael Chan883e5152007-05-03 13:25:11 -07007927 if (reg & BNX2_PCICFG_MISC_STATUS_PCIX_DET) {
7928 u32 clkreg;
7929
David S. Millerf86e82f2008-01-21 17:15:40 -08007930 bp->flags |= BNX2_FLAG_PCIX;
Michael Chan883e5152007-05-03 13:25:11 -07007931
Michael Chane503e062012-12-06 10:33:08 +00007932 clkreg = BNX2_RD(bp, BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS);
Michael Chan883e5152007-05-03 13:25:11 -07007933
7934 clkreg &= BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET;
7935 switch (clkreg) {
7936 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_133MHZ:
7937 bp->bus_speed_mhz = 133;
7938 break;
7939
7940 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_95MHZ:
7941 bp->bus_speed_mhz = 100;
7942 break;
7943
7944 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_66MHZ:
7945 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_80MHZ:
7946 bp->bus_speed_mhz = 66;
7947 break;
7948
7949 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_48MHZ:
7950 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_55MHZ:
7951 bp->bus_speed_mhz = 50;
7952 break;
7953
7954 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_LOW:
7955 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_32MHZ:
7956 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_38MHZ:
7957 bp->bus_speed_mhz = 33;
7958 break;
7959 }
7960 }
7961 else {
7962 if (reg & BNX2_PCICFG_MISC_STATUS_M66EN)
7963 bp->bus_speed_mhz = 66;
7964 else
7965 bp->bus_speed_mhz = 33;
7966 }
7967
7968 if (reg & BNX2_PCICFG_MISC_STATUS_32BIT_DET)
David S. Millerf86e82f2008-01-21 17:15:40 -08007969 bp->flags |= BNX2_FLAG_PCI_32BIT;
Michael Chan883e5152007-05-03 13:25:11 -07007970
7971}
7972
Bill Pembertoncfd95a62012-12-03 09:22:58 -05007973static void
Michael Chan76d99062009-12-03 09:46:34 +00007974bnx2_read_vpd_fw_ver(struct bnx2 *bp)
7975{
Matt Carlsondf25bc32010-02-26 14:04:44 +00007976 int rc, i, j;
Michael Chan76d99062009-12-03 09:46:34 +00007977 u8 *data;
Matt Carlsondf25bc32010-02-26 14:04:44 +00007978 unsigned int block_end, rosize, len;
Michael Chan76d99062009-12-03 09:46:34 +00007979
Michael Chan012093f2009-12-03 15:58:00 -08007980#define BNX2_VPD_NVRAM_OFFSET 0x300
7981#define BNX2_VPD_LEN 128
Michael Chan76d99062009-12-03 09:46:34 +00007982#define BNX2_MAX_VER_SLEN 30
7983
7984 data = kmalloc(256, GFP_KERNEL);
7985 if (!data)
7986 return;
7987
Michael Chan012093f2009-12-03 15:58:00 -08007988 rc = bnx2_nvram_read(bp, BNX2_VPD_NVRAM_OFFSET, data + BNX2_VPD_LEN,
7989 BNX2_VPD_LEN);
Michael Chan76d99062009-12-03 09:46:34 +00007990 if (rc)
7991 goto vpd_done;
7992
Michael Chan012093f2009-12-03 15:58:00 -08007993 for (i = 0; i < BNX2_VPD_LEN; i += 4) {
7994 data[i] = data[i + BNX2_VPD_LEN + 3];
7995 data[i + 1] = data[i + BNX2_VPD_LEN + 2];
7996 data[i + 2] = data[i + BNX2_VPD_LEN + 1];
7997 data[i + 3] = data[i + BNX2_VPD_LEN];
Michael Chan76d99062009-12-03 09:46:34 +00007998 }
7999
Matt Carlsondf25bc32010-02-26 14:04:44 +00008000 i = pci_vpd_find_tag(data, 0, BNX2_VPD_LEN, PCI_VPD_LRDT_RO_DATA);
8001 if (i < 0)
Michael Chan76d99062009-12-03 09:46:34 +00008002 goto vpd_done;
Matt Carlsondf25bc32010-02-26 14:04:44 +00008003
8004 rosize = pci_vpd_lrdt_size(&data[i]);
8005 i += PCI_VPD_LRDT_TAG_SIZE;
8006 block_end = i + rosize;
8007
8008 if (block_end > BNX2_VPD_LEN)
8009 goto vpd_done;
8010
8011 j = pci_vpd_find_info_keyword(data, i, rosize,
8012 PCI_VPD_RO_KEYWORD_MFR_ID);
8013 if (j < 0)
8014 goto vpd_done;
8015
8016 len = pci_vpd_info_field_size(&data[j]);
8017
8018 j += PCI_VPD_INFO_FLD_HDR_SIZE;
8019 if (j + len > block_end || len != 4 ||
8020 memcmp(&data[j], "1028", 4))
8021 goto vpd_done;
8022
8023 j = pci_vpd_find_info_keyword(data, i, rosize,
8024 PCI_VPD_RO_KEYWORD_VENDOR0);
8025 if (j < 0)
8026 goto vpd_done;
8027
8028 len = pci_vpd_info_field_size(&data[j]);
8029
8030 j += PCI_VPD_INFO_FLD_HDR_SIZE;
8031 if (j + len > block_end || len > BNX2_MAX_VER_SLEN)
8032 goto vpd_done;
8033
8034 memcpy(bp->fw_version, &data[j], len);
8035 bp->fw_version[len] = ' ';
Michael Chan76d99062009-12-03 09:46:34 +00008036
8037vpd_done:
8038 kfree(data);
8039}
8040
Bill Pembertoncfd95a62012-12-03 09:22:58 -05008041static int
Michael Chanb6016b72005-05-26 13:03:09 -07008042bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
8043{
8044 struct bnx2 *bp;
Michael Chan58fc2ea2007-07-07 22:52:02 -07008045 int rc, i, j;
Michael Chanb6016b72005-05-26 13:03:09 -07008046 u32 reg;
Michael Chan40453c82007-05-03 13:19:18 -07008047 u64 dma_mask, persist_dma_mask;
John Feeneycd709aa2010-08-22 17:45:53 +00008048 int err;
Michael Chanb6016b72005-05-26 13:03:09 -07008049
Michael Chanb6016b72005-05-26 13:03:09 -07008050 SET_NETDEV_DEV(dev, &pdev->dev);
Michael Chan972ec0d2006-01-23 16:12:43 -08008051 bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07008052
8053 bp->flags = 0;
8054 bp->phy_flags = 0;
8055
Michael Chan354fcd72010-01-17 07:30:44 +00008056 bp->temp_stats_blk =
8057 kzalloc(sizeof(struct statistics_block), GFP_KERNEL);
8058
8059 if (bp->temp_stats_blk == NULL) {
8060 rc = -ENOMEM;
8061 goto err_out;
8062 }
8063
Michael Chanb6016b72005-05-26 13:03:09 -07008064 /* enable device (incl. PCI PM wakeup), and bus-mastering */
8065 rc = pci_enable_device(pdev);
8066 if (rc) {
Joe Perches3a9c6a42010-02-17 15:01:51 +00008067 dev_err(&pdev->dev, "Cannot enable PCI device, aborting\n");
Michael Chanb6016b72005-05-26 13:03:09 -07008068 goto err_out;
8069 }
8070
8071 if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) {
Jeff Garzik9b91cf92006-06-27 11:39:50 -04008072 dev_err(&pdev->dev,
Joe Perches3a9c6a42010-02-17 15:01:51 +00008073 "Cannot find PCI device base address, aborting\n");
Michael Chanb6016b72005-05-26 13:03:09 -07008074 rc = -ENODEV;
8075 goto err_out_disable;
8076 }
8077
8078 rc = pci_request_regions(pdev, DRV_MODULE_NAME);
8079 if (rc) {
Joe Perches3a9c6a42010-02-17 15:01:51 +00008080 dev_err(&pdev->dev, "Cannot obtain PCI resources, aborting\n");
Michael Chanb6016b72005-05-26 13:03:09 -07008081 goto err_out_disable;
8082 }
8083
8084 pci_set_master(pdev);
8085
Yijing Wang85768272013-06-18 16:12:37 +08008086 bp->pm_cap = pdev->pm_cap;
Michael Chanb6016b72005-05-26 13:03:09 -07008087 if (bp->pm_cap == 0) {
Jeff Garzik9b91cf92006-06-27 11:39:50 -04008088 dev_err(&pdev->dev,
Joe Perches3a9c6a42010-02-17 15:01:51 +00008089 "Cannot find power management capability, aborting\n");
Michael Chanb6016b72005-05-26 13:03:09 -07008090 rc = -EIO;
8091 goto err_out_release;
8092 }
8093
Michael Chanb6016b72005-05-26 13:03:09 -07008094 bp->dev = dev;
8095 bp->pdev = pdev;
8096
8097 spin_lock_init(&bp->phy_lock);
Michael Chan1b8227c2007-05-03 13:24:05 -07008098 spin_lock_init(&bp->indirect_lock);
Michael Chanc5a88952009-08-14 15:49:45 +00008099#ifdef BCM_CNIC
8100 mutex_init(&bp->cnic_lock);
8101#endif
David Howellsc4028952006-11-22 14:57:56 +00008102 INIT_WORK(&bp->reset_task, bnx2_reset_task);
Michael Chanb6016b72005-05-26 13:03:09 -07008103
Francois Romieuc0357e92012-03-09 14:51:47 +01008104 bp->regview = pci_iomap(pdev, 0, MB_GET_CID_ADDR(TX_TSS_CID +
8105 TX_MAX_TSS_RINGS + 1));
Michael Chanb6016b72005-05-26 13:03:09 -07008106 if (!bp->regview) {
Joe Perches3a9c6a42010-02-17 15:01:51 +00008107 dev_err(&pdev->dev, "Cannot map register space, aborting\n");
Michael Chanb6016b72005-05-26 13:03:09 -07008108 rc = -ENOMEM;
8109 goto err_out_release;
8110 }
8111
8112 /* Configure byte swap and enable write to the reg_window registers.
8113 * Rely on CPU to do target byte swapping on big endian systems
8114 * The chip's target access swapping will not swap all accesses
8115 */
Michael Chane503e062012-12-06 10:33:08 +00008116 BNX2_WR(bp, BNX2_PCICFG_MISC_CONFIG,
8117 BNX2_PCICFG_MISC_CONFIG_REG_WINDOW_ENA |
8118 BNX2_PCICFG_MISC_CONFIG_TARGET_MB_WORD_SWAP);
Michael Chanb6016b72005-05-26 13:03:09 -07008119
Michael Chane503e062012-12-06 10:33:08 +00008120 bp->chip_id = BNX2_RD(bp, BNX2_MISC_ID);
Michael Chanb6016b72005-05-26 13:03:09 -07008121
Michael Chan4ce45e02012-12-06 10:33:10 +00008122 if (BNX2_CHIP(bp) == BNX2_CHIP_5709) {
Jon Masone82760e2011-06-27 07:44:43 +00008123 if (!pci_is_pcie(pdev)) {
8124 dev_err(&pdev->dev, "Not PCIE, aborting\n");
Michael Chan883e5152007-05-03 13:25:11 -07008125 rc = -EIO;
8126 goto err_out_unmap;
8127 }
David S. Millerf86e82f2008-01-21 17:15:40 -08008128 bp->flags |= BNX2_FLAG_PCIE;
Michael Chan4ce45e02012-12-06 10:33:10 +00008129 if (BNX2_CHIP_REV(bp) == BNX2_CHIP_REV_Ax)
David S. Millerf86e82f2008-01-21 17:15:40 -08008130 bp->flags |= BNX2_FLAG_JUMBO_BROKEN;
Michael Chanc239f272010-10-11 16:12:28 -07008131
8132 /* AER (Advanced Error Reporting) hooks */
8133 err = pci_enable_pcie_error_reporting(pdev);
Michael Chan4bb9ebc2011-01-25 22:14:51 +00008134 if (!err)
8135 bp->flags |= BNX2_FLAG_AER_ENABLED;
Michael Chanc239f272010-10-11 16:12:28 -07008136
Michael Chan883e5152007-05-03 13:25:11 -07008137 } else {
Michael Chan59b47d82006-11-19 14:10:45 -08008138 bp->pcix_cap = pci_find_capability(pdev, PCI_CAP_ID_PCIX);
8139 if (bp->pcix_cap == 0) {
8140 dev_err(&pdev->dev,
Joe Perches3a9c6a42010-02-17 15:01:51 +00008141 "Cannot find PCIX capability, aborting\n");
Michael Chan59b47d82006-11-19 14:10:45 -08008142 rc = -EIO;
8143 goto err_out_unmap;
8144 }
Michael Chan61d9e3f2009-08-21 16:20:46 +00008145 bp->flags |= BNX2_FLAG_BROKEN_STATS;
Michael Chan59b47d82006-11-19 14:10:45 -08008146 }
8147
Michael Chan4ce45e02012-12-06 10:33:10 +00008148 if (BNX2_CHIP(bp) == BNX2_CHIP_5709 &&
8149 BNX2_CHIP_REV(bp) != BNX2_CHIP_REV_Ax) {
Yijing Wang555a8422013-08-08 21:02:22 +08008150 if (pdev->msix_cap)
David S. Millerf86e82f2008-01-21 17:15:40 -08008151 bp->flags |= BNX2_FLAG_MSIX_CAP;
Michael Chanb4b36042007-12-20 19:59:30 -08008152 }
8153
Michael Chan4ce45e02012-12-06 10:33:10 +00008154 if (BNX2_CHIP_ID(bp) != BNX2_CHIP_ID_5706_A0 &&
8155 BNX2_CHIP_ID(bp) != BNX2_CHIP_ID_5706_A1) {
Yijing Wang555a8422013-08-08 21:02:22 +08008156 if (pdev->msi_cap)
David S. Millerf86e82f2008-01-21 17:15:40 -08008157 bp->flags |= BNX2_FLAG_MSI_CAP;
Michael Chan8e6a72c2007-05-03 13:24:48 -07008158 }
8159
Michael Chan40453c82007-05-03 13:19:18 -07008160 /* 5708 cannot support DMA addresses > 40-bit. */
Michael Chan4ce45e02012-12-06 10:33:10 +00008161 if (BNX2_CHIP(bp) == BNX2_CHIP_5708)
Yang Hongyang50cf1562009-04-06 19:01:14 -07008162 persist_dma_mask = dma_mask = DMA_BIT_MASK(40);
Michael Chan40453c82007-05-03 13:19:18 -07008163 else
Yang Hongyang6a355282009-04-06 19:01:13 -07008164 persist_dma_mask = dma_mask = DMA_BIT_MASK(64);
Michael Chan40453c82007-05-03 13:19:18 -07008165
8166 /* Configure DMA attributes. */
8167 if (pci_set_dma_mask(pdev, dma_mask) == 0) {
8168 dev->features |= NETIF_F_HIGHDMA;
8169 rc = pci_set_consistent_dma_mask(pdev, persist_dma_mask);
8170 if (rc) {
8171 dev_err(&pdev->dev,
Joe Perches3a9c6a42010-02-17 15:01:51 +00008172 "pci_set_consistent_dma_mask failed, aborting\n");
Michael Chan40453c82007-05-03 13:19:18 -07008173 goto err_out_unmap;
8174 }
Yang Hongyang284901a2009-04-06 19:01:15 -07008175 } else if ((rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) != 0) {
Joe Perches3a9c6a42010-02-17 15:01:51 +00008176 dev_err(&pdev->dev, "System does not support DMA, aborting\n");
Michael Chan40453c82007-05-03 13:19:18 -07008177 goto err_out_unmap;
8178 }
8179
David S. Millerf86e82f2008-01-21 17:15:40 -08008180 if (!(bp->flags & BNX2_FLAG_PCIE))
Michael Chan883e5152007-05-03 13:25:11 -07008181 bnx2_get_pci_speed(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07008182
8183 /* 5706A0 may falsely detect SERR and PERR. */
Michael Chan4ce45e02012-12-06 10:33:10 +00008184 if (BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5706_A0) {
Michael Chane503e062012-12-06 10:33:08 +00008185 reg = BNX2_RD(bp, PCI_COMMAND);
Michael Chanb6016b72005-05-26 13:03:09 -07008186 reg &= ~(PCI_COMMAND_SERR | PCI_COMMAND_PARITY);
Michael Chane503e062012-12-06 10:33:08 +00008187 BNX2_WR(bp, PCI_COMMAND, reg);
Michael Chan4ce45e02012-12-06 10:33:10 +00008188 } else if ((BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5706_A1) &&
David S. Millerf86e82f2008-01-21 17:15:40 -08008189 !(bp->flags & BNX2_FLAG_PCIX)) {
Michael Chanb6016b72005-05-26 13:03:09 -07008190
Jeff Garzik9b91cf92006-06-27 11:39:50 -04008191 dev_err(&pdev->dev,
Joe Perches3a9c6a42010-02-17 15:01:51 +00008192 "5706 A1 can only be used in a PCIX bus, aborting\n");
Michael Chanb6016b72005-05-26 13:03:09 -07008193 goto err_out_unmap;
8194 }
8195
8196 bnx2_init_nvram(bp);
8197
Michael Chan2726d6e2008-01-29 21:35:05 -08008198 reg = bnx2_reg_rd_ind(bp, BNX2_SHM_HDR_SIGNATURE);
Michael Chane3648b32005-11-04 08:51:21 -08008199
Michael Chanaefd90e2012-06-16 15:45:43 +00008200 if (bnx2_reg_rd_ind(bp, BNX2_MCP_TOE_ID) & BNX2_MCP_TOE_ID_FUNCTION_ID)
8201 bp->func = 1;
8202
Michael Chane3648b32005-11-04 08:51:21 -08008203 if ((reg & BNX2_SHM_HDR_SIGNATURE_SIG_MASK) ==
Michael Chan24cb2302007-01-25 15:49:56 -08008204 BNX2_SHM_HDR_SIGNATURE_SIG) {
Michael Chanaefd90e2012-06-16 15:45:43 +00008205 u32 off = bp->func << 2;
Michael Chan24cb2302007-01-25 15:49:56 -08008206
Michael Chan2726d6e2008-01-29 21:35:05 -08008207 bp->shmem_base = bnx2_reg_rd_ind(bp, BNX2_SHM_HDR_ADDR_0 + off);
Michael Chan24cb2302007-01-25 15:49:56 -08008208 } else
Michael Chane3648b32005-11-04 08:51:21 -08008209 bp->shmem_base = HOST_VIEW_SHMEM_BASE;
8210
Michael Chanb6016b72005-05-26 13:03:09 -07008211 /* Get the permanent MAC address. First we need to make sure the
8212 * firmware is actually running.
8213 */
Michael Chan2726d6e2008-01-29 21:35:05 -08008214 reg = bnx2_shmem_rd(bp, BNX2_DEV_INFO_SIGNATURE);
Michael Chanb6016b72005-05-26 13:03:09 -07008215
8216 if ((reg & BNX2_DEV_INFO_SIGNATURE_MAGIC_MASK) !=
8217 BNX2_DEV_INFO_SIGNATURE_MAGIC) {
Joe Perches3a9c6a42010-02-17 15:01:51 +00008218 dev_err(&pdev->dev, "Firmware not running, aborting\n");
Michael Chanb6016b72005-05-26 13:03:09 -07008219 rc = -ENODEV;
8220 goto err_out_unmap;
8221 }
8222
Michael Chan76d99062009-12-03 09:46:34 +00008223 bnx2_read_vpd_fw_ver(bp);
8224
8225 j = strlen(bp->fw_version);
Michael Chan2726d6e2008-01-29 21:35:05 -08008226 reg = bnx2_shmem_rd(bp, BNX2_DEV_INFO_BC_REV);
Michael Chan76d99062009-12-03 09:46:34 +00008227 for (i = 0; i < 3 && j < 24; i++) {
Michael Chan58fc2ea2007-07-07 22:52:02 -07008228 u8 num, k, skip0;
8229
Michael Chan76d99062009-12-03 09:46:34 +00008230 if (i == 0) {
8231 bp->fw_version[j++] = 'b';
8232 bp->fw_version[j++] = 'c';
8233 bp->fw_version[j++] = ' ';
8234 }
Michael Chan58fc2ea2007-07-07 22:52:02 -07008235 num = (u8) (reg >> (24 - (i * 8)));
8236 for (k = 100, skip0 = 1; k >= 1; num %= k, k /= 10) {
8237 if (num >= k || !skip0 || k == 1) {
8238 bp->fw_version[j++] = (num / k) + '0';
8239 skip0 = 0;
8240 }
8241 }
8242 if (i != 2)
8243 bp->fw_version[j++] = '.';
8244 }
Michael Chan2726d6e2008-01-29 21:35:05 -08008245 reg = bnx2_shmem_rd(bp, BNX2_PORT_FEATURE);
Michael Chan846f5c62007-10-10 16:16:51 -07008246 if (reg & BNX2_PORT_FEATURE_WOL_ENABLED)
8247 bp->wol = 1;
8248
8249 if (reg & BNX2_PORT_FEATURE_ASF_ENABLED) {
David S. Millerf86e82f2008-01-21 17:15:40 -08008250 bp->flags |= BNX2_FLAG_ASF_ENABLE;
Michael Chanc2d3db82007-07-16 18:26:43 -07008251
8252 for (i = 0; i < 30; i++) {
Michael Chan2726d6e2008-01-29 21:35:05 -08008253 reg = bnx2_shmem_rd(bp, BNX2_BC_STATE_CONDITION);
Michael Chanc2d3db82007-07-16 18:26:43 -07008254 if (reg & BNX2_CONDITION_MFW_RUN_MASK)
8255 break;
8256 msleep(10);
8257 }
8258 }
Michael Chan2726d6e2008-01-29 21:35:05 -08008259 reg = bnx2_shmem_rd(bp, BNX2_BC_STATE_CONDITION);
Michael Chan58fc2ea2007-07-07 22:52:02 -07008260 reg &= BNX2_CONDITION_MFW_RUN_MASK;
8261 if (reg != BNX2_CONDITION_MFW_RUN_UNKNOWN &&
8262 reg != BNX2_CONDITION_MFW_RUN_NONE) {
Michael Chan2726d6e2008-01-29 21:35:05 -08008263 u32 addr = bnx2_shmem_rd(bp, BNX2_MFW_VER_PTR);
Michael Chan58fc2ea2007-07-07 22:52:02 -07008264
Michael Chan76d99062009-12-03 09:46:34 +00008265 if (j < 32)
8266 bp->fw_version[j++] = ' ';
8267 for (i = 0; i < 3 && j < 28; i++) {
Michael Chan2726d6e2008-01-29 21:35:05 -08008268 reg = bnx2_reg_rd_ind(bp, addr + i * 4);
Michael Chan3aeb7d22011-07-20 14:55:25 +00008269 reg = be32_to_cpu(reg);
Michael Chan58fc2ea2007-07-07 22:52:02 -07008270 memcpy(&bp->fw_version[j], &reg, 4);
8271 j += 4;
8272 }
8273 }
Michael Chanb6016b72005-05-26 13:03:09 -07008274
Michael Chan2726d6e2008-01-29 21:35:05 -08008275 reg = bnx2_shmem_rd(bp, BNX2_PORT_HW_CFG_MAC_UPPER);
Michael Chanb6016b72005-05-26 13:03:09 -07008276 bp->mac_addr[0] = (u8) (reg >> 8);
8277 bp->mac_addr[1] = (u8) reg;
8278
Michael Chan2726d6e2008-01-29 21:35:05 -08008279 reg = bnx2_shmem_rd(bp, BNX2_PORT_HW_CFG_MAC_LOWER);
Michael Chanb6016b72005-05-26 13:03:09 -07008280 bp->mac_addr[2] = (u8) (reg >> 24);
8281 bp->mac_addr[3] = (u8) (reg >> 16);
8282 bp->mac_addr[4] = (u8) (reg >> 8);
8283 bp->mac_addr[5] = (u8) reg;
8284
Michael Chan2bc40782012-12-06 10:33:09 +00008285 bp->tx_ring_size = BNX2_MAX_TX_DESC_CNT;
Michael Chan932f3772006-08-15 01:39:36 -07008286 bnx2_set_rx_ring_size(bp, 255);
Michael Chanb6016b72005-05-26 13:03:09 -07008287
Michael Chancf7474a2009-08-21 16:20:48 +00008288 bp->tx_quick_cons_trip_int = 2;
Michael Chanb6016b72005-05-26 13:03:09 -07008289 bp->tx_quick_cons_trip = 20;
Michael Chancf7474a2009-08-21 16:20:48 +00008290 bp->tx_ticks_int = 18;
Michael Chanb6016b72005-05-26 13:03:09 -07008291 bp->tx_ticks = 80;
Jeff Garzik6aa20a22006-09-13 13:24:59 -04008292
Michael Chancf7474a2009-08-21 16:20:48 +00008293 bp->rx_quick_cons_trip_int = 2;
8294 bp->rx_quick_cons_trip = 12;
Michael Chanb6016b72005-05-26 13:03:09 -07008295 bp->rx_ticks_int = 18;
8296 bp->rx_ticks = 18;
8297
Michael Chan7ea69202007-07-16 18:27:10 -07008298 bp->stats_ticks = USEC_PER_SEC & BNX2_HC_STATS_TICKS_HC_STAT_TICKS;
Michael Chanb6016b72005-05-26 13:03:09 -07008299
Benjamin Liac392ab2008-09-18 16:40:49 -07008300 bp->current_interval = BNX2_TIMER_INTERVAL;
Michael Chanb6016b72005-05-26 13:03:09 -07008301
Michael Chan5b0c76a2005-11-04 08:45:49 -08008302 bp->phy_addr = 1;
8303
Michael Chanb6016b72005-05-26 13:03:09 -07008304 /* Disable WOL support if we are running on a SERDES chip. */
Michael Chan4ce45e02012-12-06 10:33:10 +00008305 if (BNX2_CHIP(bp) == BNX2_CHIP_5709)
Michael Chan253c8b72007-01-08 19:56:01 -08008306 bnx2_get_5709_media(bp);
Michael Chan4ce45e02012-12-06 10:33:10 +00008307 else if (BNX2_CHIP_BOND(bp) & BNX2_CHIP_BOND_SERDES_BIT)
Michael Chan583c28e2008-01-21 19:51:35 -08008308 bp->phy_flags |= BNX2_PHY_FLAG_SERDES;
Michael Chanbac0dff2006-11-19 14:15:05 -08008309
Michael Chan0d8a6572007-07-07 22:49:43 -07008310 bp->phy_port = PORT_TP;
Michael Chan583c28e2008-01-21 19:51:35 -08008311 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Michael Chan0d8a6572007-07-07 22:49:43 -07008312 bp->phy_port = PORT_FIBRE;
Michael Chan2726d6e2008-01-29 21:35:05 -08008313 reg = bnx2_shmem_rd(bp, BNX2_SHARED_HW_CFG_CONFIG);
Michael Chan846f5c62007-10-10 16:16:51 -07008314 if (!(reg & BNX2_SHARED_HW_CFG_GIG_LINK_ON_VAUX)) {
David S. Millerf86e82f2008-01-21 17:15:40 -08008315 bp->flags |= BNX2_FLAG_NO_WOL;
Michael Chan846f5c62007-10-10 16:16:51 -07008316 bp->wol = 0;
8317 }
Michael Chan4ce45e02012-12-06 10:33:10 +00008318 if (BNX2_CHIP(bp) == BNX2_CHIP_5706) {
Michael Chan38ea3682008-02-23 19:48:57 -08008319 /* Don't do parallel detect on this board because of
8320 * some board problems. The link will not go down
8321 * if we do parallel detect.
8322 */
8323 if (pdev->subsystem_vendor == PCI_VENDOR_ID_HP &&
8324 pdev->subsystem_device == 0x310c)
8325 bp->phy_flags |= BNX2_PHY_FLAG_NO_PARALLEL;
8326 } else {
Michael Chan5b0c76a2005-11-04 08:45:49 -08008327 bp->phy_addr = 2;
Michael Chan5b0c76a2005-11-04 08:45:49 -08008328 if (reg & BNX2_SHARED_HW_CFG_PHY_2_5G)
Michael Chan583c28e2008-01-21 19:51:35 -08008329 bp->phy_flags |= BNX2_PHY_FLAG_2_5G_CAPABLE;
Michael Chan5b0c76a2005-11-04 08:45:49 -08008330 }
Michael Chan4ce45e02012-12-06 10:33:10 +00008331 } else if (BNX2_CHIP(bp) == BNX2_CHIP_5706 ||
8332 BNX2_CHIP(bp) == BNX2_CHIP_5708)
Michael Chan583c28e2008-01-21 19:51:35 -08008333 bp->phy_flags |= BNX2_PHY_FLAG_CRC_FIX;
Michael Chan4ce45e02012-12-06 10:33:10 +00008334 else if (BNX2_CHIP(bp) == BNX2_CHIP_5709 &&
8335 (BNX2_CHIP_REV(bp) == BNX2_CHIP_REV_Ax ||
8336 BNX2_CHIP_REV(bp) == BNX2_CHIP_REV_Bx))
Michael Chan583c28e2008-01-21 19:51:35 -08008337 bp->phy_flags |= BNX2_PHY_FLAG_DIS_EARLY_DAC;
Michael Chanb6016b72005-05-26 13:03:09 -07008338
Michael Chan7c62e832008-07-14 22:39:03 -07008339 bnx2_init_fw_cap(bp);
8340
Michael Chan4ce45e02012-12-06 10:33:10 +00008341 if ((BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5708_A0) ||
8342 (BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5708_B0) ||
8343 (BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5708_B1) ||
Michael Chane503e062012-12-06 10:33:08 +00008344 !(BNX2_RD(bp, BNX2_PCI_CONFIG_3) & BNX2_PCI_CONFIG_3_VAUX_PRESET)) {
David S. Millerf86e82f2008-01-21 17:15:40 -08008345 bp->flags |= BNX2_FLAG_NO_WOL;
Michael Chan846f5c62007-10-10 16:16:51 -07008346 bp->wol = 0;
8347 }
Michael Chandda1e392006-01-23 16:08:14 -08008348
Michael Chan6d5e85c2013-08-06 15:50:08 -07008349 if (bp->flags & BNX2_FLAG_NO_WOL)
8350 device_set_wakeup_capable(&bp->pdev->dev, false);
8351 else
8352 device_set_wakeup_enable(&bp->pdev->dev, bp->wol);
8353
Michael Chan4ce45e02012-12-06 10:33:10 +00008354 if (BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5706_A0) {
Michael Chanb6016b72005-05-26 13:03:09 -07008355 bp->tx_quick_cons_trip_int =
8356 bp->tx_quick_cons_trip;
8357 bp->tx_ticks_int = bp->tx_ticks;
8358 bp->rx_quick_cons_trip_int =
8359 bp->rx_quick_cons_trip;
8360 bp->rx_ticks_int = bp->rx_ticks;
8361 bp->comp_prod_trip_int = bp->comp_prod_trip;
8362 bp->com_ticks_int = bp->com_ticks;
8363 bp->cmd_ticks_int = bp->cmd_ticks;
8364 }
8365
Michael Chanf9317a42006-09-29 17:06:23 -07008366 /* Disable MSI on 5706 if AMD 8132 bridge is found.
8367 *
8368 * MSI is defined to be 32-bit write. The 5706 does 64-bit MSI writes
8369 * with byte enables disabled on the unused 32-bit word. This is legal
8370 * but causes problems on the AMD 8132 which will eventually stop
8371 * responding after a while.
8372 *
8373 * AMD believes this incompatibility is unique to the 5706, and
Michael Ellerman88187df2007-01-25 19:34:07 +11008374 * prefers to locally disable MSI rather than globally disabling it.
Michael Chanf9317a42006-09-29 17:06:23 -07008375 */
Michael Chan4ce45e02012-12-06 10:33:10 +00008376 if (BNX2_CHIP(bp) == BNX2_CHIP_5706 && disable_msi == 0) {
Michael Chanf9317a42006-09-29 17:06:23 -07008377 struct pci_dev *amd_8132 = NULL;
8378
8379 while ((amd_8132 = pci_get_device(PCI_VENDOR_ID_AMD,
8380 PCI_DEVICE_ID_AMD_8132_BRIDGE,
8381 amd_8132))) {
Michael Chanf9317a42006-09-29 17:06:23 -07008382
Auke Kok44c10132007-06-08 15:46:36 -07008383 if (amd_8132->revision >= 0x10 &&
8384 amd_8132->revision <= 0x13) {
Michael Chanf9317a42006-09-29 17:06:23 -07008385 disable_msi = 1;
8386 pci_dev_put(amd_8132);
8387 break;
8388 }
8389 }
8390 }
8391
Michael Chandeaf3912007-07-07 22:48:00 -07008392 bnx2_set_default_link(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07008393 bp->req_flow_ctrl = FLOW_CTRL_RX | FLOW_CTRL_TX;
8394
Michael Chancd339a02005-08-25 15:35:24 -07008395 init_timer(&bp->timer);
Benjamin Liac392ab2008-09-18 16:40:49 -07008396 bp->timer.expires = RUN_AT(BNX2_TIMER_INTERVAL);
Michael Chancd339a02005-08-25 15:35:24 -07008397 bp->timer.data = (unsigned long) bp;
8398 bp->timer.function = bnx2_timer;
8399
Michael Chan7625eb22011-06-08 19:29:36 +00008400#ifdef BCM_CNIC
Michael Chan41c21782011-07-13 17:24:22 +00008401 if (bnx2_shmem_rd(bp, BNX2_ISCSI_INITIATOR) & BNX2_ISCSI_INITIATOR_EN)
8402 bp->cnic_eth_dev.max_iscsi_conn =
8403 (bnx2_shmem_rd(bp, BNX2_ISCSI_MAX_CONN) &
8404 BNX2_ISCSI_MAX_CONN_MASK) >> BNX2_ISCSI_MAX_CONN_SHIFT;
Michael Chan4bd9b0ff2012-12-06 10:33:12 +00008405 bp->cnic_probe = bnx2_cnic_probe;
Michael Chan7625eb22011-06-08 19:29:36 +00008406#endif
Michael Chanc239f272010-10-11 16:12:28 -07008407 pci_save_state(pdev);
8408
Michael Chanb6016b72005-05-26 13:03:09 -07008409 return 0;
8410
8411err_out_unmap:
Michael Chan4bb9ebc2011-01-25 22:14:51 +00008412 if (bp->flags & BNX2_FLAG_AER_ENABLED) {
Michael Chanc239f272010-10-11 16:12:28 -07008413 pci_disable_pcie_error_reporting(pdev);
Michael Chan4bb9ebc2011-01-25 22:14:51 +00008414 bp->flags &= ~BNX2_FLAG_AER_ENABLED;
8415 }
Michael Chanc239f272010-10-11 16:12:28 -07008416
Francois Romieuc0357e92012-03-09 14:51:47 +01008417 pci_iounmap(pdev, bp->regview);
8418 bp->regview = NULL;
Michael Chanb6016b72005-05-26 13:03:09 -07008419
8420err_out_release:
8421 pci_release_regions(pdev);
8422
8423err_out_disable:
8424 pci_disable_device(pdev);
Michael Chanb6016b72005-05-26 13:03:09 -07008425
8426err_out:
8427 return rc;
8428}
8429
Bill Pembertoncfd95a62012-12-03 09:22:58 -05008430static char *
Michael Chan883e5152007-05-03 13:25:11 -07008431bnx2_bus_string(struct bnx2 *bp, char *str)
8432{
8433 char *s = str;
8434
David S. Millerf86e82f2008-01-21 17:15:40 -08008435 if (bp->flags & BNX2_FLAG_PCIE) {
Michael Chan883e5152007-05-03 13:25:11 -07008436 s += sprintf(s, "PCI Express");
8437 } else {
8438 s += sprintf(s, "PCI");
David S. Millerf86e82f2008-01-21 17:15:40 -08008439 if (bp->flags & BNX2_FLAG_PCIX)
Michael Chan883e5152007-05-03 13:25:11 -07008440 s += sprintf(s, "-X");
David S. Millerf86e82f2008-01-21 17:15:40 -08008441 if (bp->flags & BNX2_FLAG_PCI_32BIT)
Michael Chan883e5152007-05-03 13:25:11 -07008442 s += sprintf(s, " 32-bit");
8443 else
8444 s += sprintf(s, " 64-bit");
8445 s += sprintf(s, " %dMHz", bp->bus_speed_mhz);
8446 }
8447 return str;
8448}
8449
Michael Chanf048fa92010-06-01 15:05:36 +00008450static void
8451bnx2_del_napi(struct bnx2 *bp)
8452{
8453 int i;
8454
8455 for (i = 0; i < bp->irq_nvecs; i++)
8456 netif_napi_del(&bp->bnx2_napi[i].napi);
8457}
8458
8459static void
Michael Chan35efa7c2007-12-20 19:56:37 -08008460bnx2_init_napi(struct bnx2 *bp)
8461{
Michael Chanb4b36042007-12-20 19:59:30 -08008462 int i;
Michael Chan35efa7c2007-12-20 19:56:37 -08008463
Benjamin Li4327ba42010-03-23 13:13:11 +00008464 for (i = 0; i < bp->irq_nvecs; i++) {
Michael Chan35e90102008-06-19 16:37:42 -07008465 struct bnx2_napi *bnapi = &bp->bnx2_napi[i];
8466 int (*poll)(struct napi_struct *, int);
8467
8468 if (i == 0)
8469 poll = bnx2_poll;
8470 else
Michael Chanf0ea2e62008-06-19 16:41:57 -07008471 poll = bnx2_poll_msix;
Michael Chan35e90102008-06-19 16:37:42 -07008472
8473 netif_napi_add(bp->dev, &bp->bnx2_napi[i].napi, poll, 64);
Michael Chanb4b36042007-12-20 19:59:30 -08008474 bnapi->bp = bp;
8475 }
Michael Chan35efa7c2007-12-20 19:56:37 -08008476}
8477
Stephen Hemminger0421eae2008-11-21 17:31:27 -08008478static const struct net_device_ops bnx2_netdev_ops = {
8479 .ndo_open = bnx2_open,
8480 .ndo_start_xmit = bnx2_start_xmit,
8481 .ndo_stop = bnx2_close,
Eric Dumazet5d07bf22010-07-08 04:08:43 +00008482 .ndo_get_stats64 = bnx2_get_stats64,
Stephen Hemminger0421eae2008-11-21 17:31:27 -08008483 .ndo_set_rx_mode = bnx2_set_rx_mode,
8484 .ndo_do_ioctl = bnx2_ioctl,
8485 .ndo_validate_addr = eth_validate_addr,
8486 .ndo_set_mac_address = bnx2_change_mac_addr,
8487 .ndo_change_mtu = bnx2_change_mtu,
Michał Mirosław8d7dfc22011-04-10 04:47:46 +00008488 .ndo_fix_features = bnx2_fix_features,
8489 .ndo_set_features = bnx2_set_features,
Stephen Hemminger0421eae2008-11-21 17:31:27 -08008490 .ndo_tx_timeout = bnx2_tx_timeout,
Alexey Dobriyan257ddbd2010-01-27 10:17:41 +00008491#ifdef CONFIG_NET_POLL_CONTROLLER
Stephen Hemminger0421eae2008-11-21 17:31:27 -08008492 .ndo_poll_controller = poll_bnx2,
8493#endif
8494};
8495
Bill Pembertoncfd95a62012-12-03 09:22:58 -05008496static int
Michael Chanb6016b72005-05-26 13:03:09 -07008497bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
8498{
8499 static int version_printed = 0;
Francois Romieuc0357e92012-03-09 14:51:47 +01008500 struct net_device *dev;
Michael Chanb6016b72005-05-26 13:03:09 -07008501 struct bnx2 *bp;
Joe Perches0795af52007-10-03 17:59:30 -07008502 int rc;
Michael Chan883e5152007-05-03 13:25:11 -07008503 char str[40];
Michael Chanb6016b72005-05-26 13:03:09 -07008504
8505 if (version_printed++ == 0)
Joe Perches3a9c6a42010-02-17 15:01:51 +00008506 pr_info("%s", version);
Michael Chanb6016b72005-05-26 13:03:09 -07008507
8508 /* dev zeroed in init_etherdev */
Benjamin Li706bf242008-07-18 17:55:11 -07008509 dev = alloc_etherdev_mq(sizeof(*bp), TX_MAX_RINGS);
Michael Chanb6016b72005-05-26 13:03:09 -07008510 if (!dev)
8511 return -ENOMEM;
8512
8513 rc = bnx2_init_board(pdev, dev);
Francois Romieuc0357e92012-03-09 14:51:47 +01008514 if (rc < 0)
8515 goto err_free;
Michael Chanb6016b72005-05-26 13:03:09 -07008516
Stephen Hemminger0421eae2008-11-21 17:31:27 -08008517 dev->netdev_ops = &bnx2_netdev_ops;
Michael Chanb6016b72005-05-26 13:03:09 -07008518 dev->watchdog_timeo = TX_TIMEOUT;
Michael Chanb6016b72005-05-26 13:03:09 -07008519 dev->ethtool_ops = &bnx2_ethtool_ops;
Michael Chanb6016b72005-05-26 13:03:09 -07008520
Michael Chan972ec0d2006-01-23 16:12:43 -08008521 bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07008522
Michael Chan1b2f9222007-05-03 13:20:19 -07008523 pci_set_drvdata(pdev, dev);
8524
Joe Perchesd458cdf2013-10-01 19:04:40 -07008525 memcpy(dev->dev_addr, bp->mac_addr, ETH_ALEN);
Michael Chan1b2f9222007-05-03 13:20:19 -07008526
Michał Mirosław8d7dfc22011-04-10 04:47:46 +00008527 dev->hw_features = NETIF_F_IP_CSUM | NETIF_F_SG |
8528 NETIF_F_TSO | NETIF_F_TSO_ECN |
8529 NETIF_F_RXHASH | NETIF_F_RXCSUM;
8530
Michael Chan4ce45e02012-12-06 10:33:10 +00008531 if (BNX2_CHIP(bp) == BNX2_CHIP_5709)
Michał Mirosław8d7dfc22011-04-10 04:47:46 +00008532 dev->hw_features |= NETIF_F_IPV6_CSUM | NETIF_F_TSO6;
8533
8534 dev->vlan_features = dev->hw_features;
Patrick McHardyf6469682013-04-19 02:04:27 +00008535 dev->hw_features |= NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX;
Michał Mirosław8d7dfc22011-04-10 04:47:46 +00008536 dev->features |= dev->hw_features;
Jiri Pirko01789342011-08-16 06:29:00 +00008537 dev->priv_flags |= IFF_UNICAST_FLT;
Michał Mirosław8d7dfc22011-04-10 04:47:46 +00008538
Michael Chanb6016b72005-05-26 13:03:09 -07008539 if ((rc = register_netdev(dev))) {
Jeff Garzik9b91cf92006-06-27 11:39:50 -04008540 dev_err(&pdev->dev, "Cannot register net device\n");
Michael Chan57579f72009-04-04 16:51:14 -07008541 goto error;
Michael Chanb6016b72005-05-26 13:03:09 -07008542 }
8543
Francois Romieuc0357e92012-03-09 14:51:47 +01008544 netdev_info(dev, "%s (%c%d) %s found at mem %lx, IRQ %d, "
8545 "node addr %pM\n", board_info[ent->driver_data].name,
Michael Chan4ce45e02012-12-06 10:33:10 +00008546 ((BNX2_CHIP_ID(bp) & 0xf000) >> 12) + 'A',
8547 ((BNX2_CHIP_ID(bp) & 0x0ff0) >> 4),
Francois Romieuc0357e92012-03-09 14:51:47 +01008548 bnx2_bus_string(bp, str), (long)pci_resource_start(pdev, 0),
8549 pdev->irq, dev->dev_addr);
Michael Chanb6016b72005-05-26 13:03:09 -07008550
Michael Chanb6016b72005-05-26 13:03:09 -07008551 return 0;
Michael Chan57579f72009-04-04 16:51:14 -07008552
8553error:
Michael Chanfda4d852012-12-11 18:24:20 -08008554 pci_iounmap(pdev, bp->regview);
Michael Chan57579f72009-04-04 16:51:14 -07008555 pci_release_regions(pdev);
8556 pci_disable_device(pdev);
Francois Romieuc0357e92012-03-09 14:51:47 +01008557err_free:
Michael Chan57579f72009-04-04 16:51:14 -07008558 free_netdev(dev);
8559 return rc;
Michael Chanb6016b72005-05-26 13:03:09 -07008560}
8561
Bill Pembertoncfd95a62012-12-03 09:22:58 -05008562static void
Michael Chanb6016b72005-05-26 13:03:09 -07008563bnx2_remove_one(struct pci_dev *pdev)
8564{
8565 struct net_device *dev = pci_get_drvdata(pdev);
Michael Chan972ec0d2006-01-23 16:12:43 -08008566 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07008567
8568 unregister_netdev(dev);
8569
Neil Horman8333a462011-04-26 10:30:11 +00008570 del_timer_sync(&bp->timer);
Michael Chancd634012011-07-15 06:53:58 +00008571 cancel_work_sync(&bp->reset_task);
Neil Horman8333a462011-04-26 10:30:11 +00008572
Francois Romieuc0357e92012-03-09 14:51:47 +01008573 pci_iounmap(bp->pdev, bp->regview);
Michael Chanb6016b72005-05-26 13:03:09 -07008574
Michael Chan354fcd72010-01-17 07:30:44 +00008575 kfree(bp->temp_stats_blk);
8576
Michael Chan4bb9ebc2011-01-25 22:14:51 +00008577 if (bp->flags & BNX2_FLAG_AER_ENABLED) {
Michael Chanc239f272010-10-11 16:12:28 -07008578 pci_disable_pcie_error_reporting(pdev);
Michael Chan4bb9ebc2011-01-25 22:14:51 +00008579 bp->flags &= ~BNX2_FLAG_AER_ENABLED;
8580 }
John Feeneycd709aa2010-08-22 17:45:53 +00008581
françois romieu7880b722011-09-30 00:36:52 +00008582 bnx2_release_firmware(bp);
8583
Michael Chanc239f272010-10-11 16:12:28 -07008584 free_netdev(dev);
John Feeneycd709aa2010-08-22 17:45:53 +00008585
Michael Chanb6016b72005-05-26 13:03:09 -07008586 pci_release_regions(pdev);
8587 pci_disable_device(pdev);
Michael Chanb6016b72005-05-26 13:03:09 -07008588}
8589
8590static int
Michael Chan28fb4eb2013-08-06 15:50:10 -07008591bnx2_suspend(struct device *device)
Michael Chanb6016b72005-05-26 13:03:09 -07008592{
Michael Chan28fb4eb2013-08-06 15:50:10 -07008593 struct pci_dev *pdev = to_pci_dev(device);
Michael Chanb6016b72005-05-26 13:03:09 -07008594 struct net_device *dev = pci_get_drvdata(pdev);
Michael Chan972ec0d2006-01-23 16:12:43 -08008595 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07008596
Michael Chan28fb4eb2013-08-06 15:50:10 -07008597 if (netif_running(dev)) {
8598 cancel_work_sync(&bp->reset_task);
8599 bnx2_netif_stop(bp, true);
8600 netif_device_detach(dev);
8601 del_timer_sync(&bp->timer);
8602 bnx2_shutdown_chip(bp);
8603 __bnx2_free_irq(bp);
8604 bnx2_free_skbs(bp);
8605 }
8606 bnx2_setup_wol(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07008607 return 0;
8608}
8609
8610static int
Michael Chan28fb4eb2013-08-06 15:50:10 -07008611bnx2_resume(struct device *device)
Michael Chanb6016b72005-05-26 13:03:09 -07008612{
Michael Chan28fb4eb2013-08-06 15:50:10 -07008613 struct pci_dev *pdev = to_pci_dev(device);
Michael Chanb6016b72005-05-26 13:03:09 -07008614 struct net_device *dev = pci_get_drvdata(pdev);
Michael Chan972ec0d2006-01-23 16:12:43 -08008615 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07008616
8617 if (!netif_running(dev))
8618 return 0;
8619
Pavel Machek829ca9a2005-09-03 15:56:56 -07008620 bnx2_set_power_state(bp, PCI_D0);
Michael Chanb6016b72005-05-26 13:03:09 -07008621 netif_device_attach(dev);
Michael Chan28fb4eb2013-08-06 15:50:10 -07008622 bnx2_request_irq(bp);
Michael Chan9a120bc2008-05-16 22:17:45 -07008623 bnx2_init_nic(bp, 1);
Michael Chan212f9932010-04-27 11:28:10 +00008624 bnx2_netif_start(bp, true);
Michael Chanb6016b72005-05-26 13:03:09 -07008625 return 0;
8626}
8627
Michael Chan28fb4eb2013-08-06 15:50:10 -07008628#ifdef CONFIG_PM_SLEEP
8629static SIMPLE_DEV_PM_OPS(bnx2_pm_ops, bnx2_suspend, bnx2_resume);
8630#define BNX2_PM_OPS (&bnx2_pm_ops)
8631
8632#else
8633
8634#define BNX2_PM_OPS NULL
8635
8636#endif /* CONFIG_PM_SLEEP */
Wendy Xiong6ff2da42008-05-16 22:18:21 -07008637/**
8638 * bnx2_io_error_detected - called when PCI error is detected
8639 * @pdev: Pointer to PCI device
8640 * @state: The current pci connection state
8641 *
8642 * This function is called after a PCI bus error affecting
8643 * this device has been detected.
8644 */
8645static pci_ers_result_t bnx2_io_error_detected(struct pci_dev *pdev,
8646 pci_channel_state_t state)
8647{
8648 struct net_device *dev = pci_get_drvdata(pdev);
8649 struct bnx2 *bp = netdev_priv(dev);
8650
8651 rtnl_lock();
8652 netif_device_detach(dev);
8653
Dean Nelson2ec3de22009-07-31 09:13:18 +00008654 if (state == pci_channel_io_perm_failure) {
8655 rtnl_unlock();
8656 return PCI_ERS_RESULT_DISCONNECT;
8657 }
8658
Wendy Xiong6ff2da42008-05-16 22:18:21 -07008659 if (netif_running(dev)) {
Michael Chan212f9932010-04-27 11:28:10 +00008660 bnx2_netif_stop(bp, true);
Wendy Xiong6ff2da42008-05-16 22:18:21 -07008661 del_timer_sync(&bp->timer);
8662 bnx2_reset_nic(bp, BNX2_DRV_MSG_CODE_RESET);
8663 }
8664
8665 pci_disable_device(pdev);
8666 rtnl_unlock();
8667
8668 /* Request a slot slot reset. */
8669 return PCI_ERS_RESULT_NEED_RESET;
8670}
8671
8672/**
8673 * bnx2_io_slot_reset - called after the pci bus has been reset.
8674 * @pdev: Pointer to PCI device
8675 *
8676 * Restart the card from scratch, as if from a cold-boot.
8677 */
8678static pci_ers_result_t bnx2_io_slot_reset(struct pci_dev *pdev)
8679{
8680 struct net_device *dev = pci_get_drvdata(pdev);
8681 struct bnx2 *bp = netdev_priv(dev);
Michael Chan02481bc2013-08-06 15:50:07 -07008682 pci_ers_result_t result = PCI_ERS_RESULT_DISCONNECT;
8683 int err = 0;
Wendy Xiong6ff2da42008-05-16 22:18:21 -07008684
8685 rtnl_lock();
8686 if (pci_enable_device(pdev)) {
8687 dev_err(&pdev->dev,
Joe Perches3a9c6a42010-02-17 15:01:51 +00008688 "Cannot re-enable PCI device after reset\n");
John Feeneycd709aa2010-08-22 17:45:53 +00008689 } else {
8690 pci_set_master(pdev);
8691 pci_restore_state(pdev);
8692 pci_save_state(pdev);
Wendy Xiong6ff2da42008-05-16 22:18:21 -07008693
Michael Chan25bfb1d2013-08-06 15:50:11 -07008694 if (netif_running(dev))
Michael Chan02481bc2013-08-06 15:50:07 -07008695 err = bnx2_init_nic(bp, 1);
Michael Chan25bfb1d2013-08-06 15:50:11 -07008696
Michael Chan02481bc2013-08-06 15:50:07 -07008697 if (!err)
8698 result = PCI_ERS_RESULT_RECOVERED;
8699 }
8700
8701 if (result != PCI_ERS_RESULT_RECOVERED && netif_running(dev)) {
8702 bnx2_napi_enable(bp);
8703 dev_close(dev);
Wendy Xiong6ff2da42008-05-16 22:18:21 -07008704 }
Wendy Xiong6ff2da42008-05-16 22:18:21 -07008705 rtnl_unlock();
John Feeneycd709aa2010-08-22 17:45:53 +00008706
Michael Chan4bb9ebc2011-01-25 22:14:51 +00008707 if (!(bp->flags & BNX2_FLAG_AER_ENABLED))
Michael Chanc239f272010-10-11 16:12:28 -07008708 return result;
8709
John Feeneycd709aa2010-08-22 17:45:53 +00008710 err = pci_cleanup_aer_uncorrect_error_status(pdev);
8711 if (err) {
8712 dev_err(&pdev->dev,
8713 "pci_cleanup_aer_uncorrect_error_status failed 0x%0x\n",
8714 err); /* non-fatal, continue */
8715 }
8716
8717 return result;
Wendy Xiong6ff2da42008-05-16 22:18:21 -07008718}
8719
8720/**
8721 * bnx2_io_resume - called when traffic can start flowing again.
8722 * @pdev: Pointer to PCI device
8723 *
8724 * This callback is called when the error recovery driver tells us that
8725 * its OK to resume normal operation.
8726 */
8727static void bnx2_io_resume(struct pci_dev *pdev)
8728{
8729 struct net_device *dev = pci_get_drvdata(pdev);
8730 struct bnx2 *bp = netdev_priv(dev);
8731
8732 rtnl_lock();
8733 if (netif_running(dev))
Michael Chan212f9932010-04-27 11:28:10 +00008734 bnx2_netif_start(bp, true);
Wendy Xiong6ff2da42008-05-16 22:18:21 -07008735
8736 netif_device_attach(dev);
8737 rtnl_unlock();
8738}
8739
Michael Chan25bfb1d2013-08-06 15:50:11 -07008740static void bnx2_shutdown(struct pci_dev *pdev)
8741{
8742 struct net_device *dev = pci_get_drvdata(pdev);
8743 struct bnx2 *bp;
8744
8745 if (!dev)
8746 return;
8747
8748 bp = netdev_priv(dev);
8749 if (!bp)
8750 return;
8751
8752 rtnl_lock();
8753 if (netif_running(dev))
8754 dev_close(bp->dev);
8755
8756 if (system_state == SYSTEM_POWER_OFF)
8757 bnx2_set_power_state(bp, PCI_D3hot);
8758
8759 rtnl_unlock();
8760}
8761
Michael Chanfda4d852012-12-11 18:24:20 -08008762static const struct pci_error_handlers bnx2_err_handler = {
Wendy Xiong6ff2da42008-05-16 22:18:21 -07008763 .error_detected = bnx2_io_error_detected,
8764 .slot_reset = bnx2_io_slot_reset,
8765 .resume = bnx2_io_resume,
8766};
8767
Michael Chanb6016b72005-05-26 13:03:09 -07008768static struct pci_driver bnx2_pci_driver = {
Peter Hagervall14ab9b82005-08-10 14:18:16 -07008769 .name = DRV_MODULE_NAME,
8770 .id_table = bnx2_pci_tbl,
8771 .probe = bnx2_init_one,
Bill Pembertoncfd95a62012-12-03 09:22:58 -05008772 .remove = bnx2_remove_one,
Michael Chan28fb4eb2013-08-06 15:50:10 -07008773 .driver.pm = BNX2_PM_OPS,
Wendy Xiong6ff2da42008-05-16 22:18:21 -07008774 .err_handler = &bnx2_err_handler,
Michael Chan25bfb1d2013-08-06 15:50:11 -07008775 .shutdown = bnx2_shutdown,
Michael Chanb6016b72005-05-26 13:03:09 -07008776};
8777
Peter Hüwe5a4123f2013-05-21 12:58:05 +00008778module_pci_driver(bnx2_pci_driver);