blob: 1f7034d739b00a02b88beb0ec8ddde875a824882 [file] [log] [blame]
Rasesh Mody2e0bf122015-02-17 19:26:18 -05001/* bnx2.c: QLogic bnx2 network driver.
Michael Chanb6016b72005-05-26 13:03:09 -07002 *
Jitendra Kalsaria28c4ec02014-06-23 15:10:33 -04003 * Copyright (c) 2004-2014 Broadcom Corporation
Rasesh Mody2e0bf122015-02-17 19:26:18 -05004 * Copyright (c) 2014-2015 QLogic Corporation
Michael Chanb6016b72005-05-26 13:03:09 -07005 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation.
9 *
10 * Written by: Michael Chan (mchan@broadcom.com)
11 */
12
Joe Perches3a9c6a42010-02-17 15:01:51 +000013#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
Michael Chanf2a4f052006-03-23 01:13:12 -080014
15#include <linux/module.h>
16#include <linux/moduleparam.h>
17
Michael Chan555069d2012-06-16 15:45:41 +000018#include <linux/stringify.h>
Michael Chanf2a4f052006-03-23 01:13:12 -080019#include <linux/kernel.h>
20#include <linux/timer.h>
21#include <linux/errno.h>
22#include <linux/ioport.h>
23#include <linux/slab.h>
24#include <linux/vmalloc.h>
25#include <linux/interrupt.h>
26#include <linux/pci.h>
Michael Chanf2a4f052006-03-23 01:13:12 -080027#include <linux/netdevice.h>
28#include <linux/etherdevice.h>
29#include <linux/skbuff.h>
30#include <linux/dma-mapping.h>
Jiri Slaby1977f032007-10-18 23:40:25 -070031#include <linux/bitops.h>
Michael Chanf2a4f052006-03-23 01:13:12 -080032#include <asm/io.h>
33#include <asm/irq.h>
34#include <linux/delay.h>
35#include <asm/byteorder.h>
Michael Chanc86a31f2006-06-13 15:03:47 -070036#include <asm/page.h>
Michael Chanf2a4f052006-03-23 01:13:12 -080037#include <linux/time.h>
38#include <linux/ethtool.h>
39#include <linux/mii.h>
Jiri Pirko01789342011-08-16 06:29:00 +000040#include <linux/if.h>
Michael Chanf2a4f052006-03-23 01:13:12 -080041#include <linux/if_vlan.h>
Michael Chanf2a4f052006-03-23 01:13:12 -080042#include <net/ip.h>
Linus Torvaldsde081fa2007-07-12 16:40:08 -070043#include <net/tcp.h>
Michael Chanf2a4f052006-03-23 01:13:12 -080044#include <net/checksum.h>
Michael Chanf2a4f052006-03-23 01:13:12 -080045#include <linux/workqueue.h>
46#include <linux/crc32.h>
47#include <linux/prefetch.h>
Michael Chan29b12172006-03-23 01:13:43 -080048#include <linux/cache.h>
Michael Chan57579f72009-04-04 16:51:14 -070049#include <linux/firmware.h>
Benjamin Li706bf242008-07-18 17:55:11 -070050#include <linux/log2.h>
John Feeneycd709aa2010-08-22 17:45:53 +000051#include <linux/aer.h>
Baoquan He6df77862016-11-13 13:01:33 +080052#include <linux/crash_dump.h>
Michael Chanf2a4f052006-03-23 01:13:12 -080053
Javier Martinez Canillasda556d62016-09-12 10:03:35 -040054#if IS_ENABLED(CONFIG_CNIC)
Michael Chan4edd4732009-06-08 18:14:42 -070055#define BCM_CNIC 1
56#include "cnic_if.h"
57#endif
Michael Chanb6016b72005-05-26 13:03:09 -070058#include "bnx2.h"
59#include "bnx2_fw.h"
Denys Vlasenkob3448b02007-09-30 17:55:51 -070060
Michael Chanb6016b72005-05-26 13:03:09 -070061#define DRV_MODULE_NAME "bnx2"
Rasesh Mody85fe7cd2015-02-17 19:26:20 -050062#define DRV_MODULE_VERSION "2.2.6"
63#define DRV_MODULE_RELDATE "January 29, 2014"
Michael Chanc2c20ef2011-12-18 18:15:09 +000064#define FW_MIPS_FILE_06 "bnx2/bnx2-mips-06-6.2.3.fw"
Michael Chan22fa1592010-10-11 16:12:00 -070065#define FW_RV2P_FILE_06 "bnx2/bnx2-rv2p-06-6.0.15.fw"
Michael Chanc2c20ef2011-12-18 18:15:09 +000066#define FW_MIPS_FILE_09 "bnx2/bnx2-mips-09-6.2.1b.fw"
Michael Chan22fa1592010-10-11 16:12:00 -070067#define FW_RV2P_FILE_09_Ax "bnx2/bnx2-rv2p-09ax-6.0.17.fw"
68#define FW_RV2P_FILE_09 "bnx2/bnx2-rv2p-09-6.0.17.fw"
Michael Chanb6016b72005-05-26 13:03:09 -070069
70#define RUN_AT(x) (jiffies + (x))
71
72/* Time in jiffies before concluding the transmitter is hung. */
73#define TX_TIMEOUT (5*HZ)
74
Bill Pembertoncfd95a62012-12-03 09:22:58 -050075static char version[] =
Rasesh Mody2e0bf122015-02-17 19:26:18 -050076 "QLogic " DRV_MODULE_NAME " Gigabit Ethernet Driver v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";
Michael Chanb6016b72005-05-26 13:03:09 -070077
78MODULE_AUTHOR("Michael Chan <mchan@broadcom.com>");
Rasesh Mody2e0bf122015-02-17 19:26:18 -050079MODULE_DESCRIPTION("QLogic BCM5706/5708/5709/5716 Driver");
Michael Chanb6016b72005-05-26 13:03:09 -070080MODULE_LICENSE("GPL");
81MODULE_VERSION(DRV_MODULE_VERSION);
Michael Chan57579f72009-04-04 16:51:14 -070082MODULE_FIRMWARE(FW_MIPS_FILE_06);
83MODULE_FIRMWARE(FW_RV2P_FILE_06);
84MODULE_FIRMWARE(FW_MIPS_FILE_09);
85MODULE_FIRMWARE(FW_RV2P_FILE_09);
Michael Chan078b0732009-08-29 00:02:46 -070086MODULE_FIRMWARE(FW_RV2P_FILE_09_Ax);
Michael Chanb6016b72005-05-26 13:03:09 -070087
88static int disable_msi = 0;
89
James M Leddy1c8bb762014-02-04 15:10:59 -050090module_param(disable_msi, int, S_IRUGO);
Michael Chanb6016b72005-05-26 13:03:09 -070091MODULE_PARM_DESC(disable_msi, "Disable Message Signaled Interrupt (MSI)");
92
93typedef enum {
94 BCM5706 = 0,
95 NC370T,
96 NC370I,
97 BCM5706S,
98 NC370F,
Michael Chan5b0c76a2005-11-04 08:45:49 -080099 BCM5708,
100 BCM5708S,
Michael Chanbac0dff2006-11-19 14:15:05 -0800101 BCM5709,
Michael Chan27a005b2007-05-03 13:23:41 -0700102 BCM5709S,
Michael Chan7bb0a042008-07-14 22:37:47 -0700103 BCM5716,
Michael Chan1caacec2008-11-12 16:01:12 -0800104 BCM5716S,
Michael Chanb6016b72005-05-26 13:03:09 -0700105} board_t;
106
107/* indexed by board_t, above */
Andrew Mortonfefa8642008-02-09 23:17:15 -0800108static struct {
Michael Chanb6016b72005-05-26 13:03:09 -0700109 char *name;
Bill Pembertoncfd95a62012-12-03 09:22:58 -0500110} board_info[] = {
Michael Chanb6016b72005-05-26 13:03:09 -0700111 { "Broadcom NetXtreme II BCM5706 1000Base-T" },
112 { "HP NC370T Multifunction Gigabit Server Adapter" },
113 { "HP NC370i Multifunction Gigabit Server Adapter" },
114 { "Broadcom NetXtreme II BCM5706 1000Base-SX" },
115 { "HP NC370F Multifunction Gigabit Server Adapter" },
Michael Chan5b0c76a2005-11-04 08:45:49 -0800116 { "Broadcom NetXtreme II BCM5708 1000Base-T" },
117 { "Broadcom NetXtreme II BCM5708 1000Base-SX" },
Michael Chanbac0dff2006-11-19 14:15:05 -0800118 { "Broadcom NetXtreme II BCM5709 1000Base-T" },
Michael Chan27a005b2007-05-03 13:23:41 -0700119 { "Broadcom NetXtreme II BCM5709 1000Base-SX" },
Michael Chan7bb0a042008-07-14 22:37:47 -0700120 { "Broadcom NetXtreme II BCM5716 1000Base-T" },
Michael Chan1caacec2008-11-12 16:01:12 -0800121 { "Broadcom NetXtreme II BCM5716 1000Base-SX" },
Michael Chanb6016b72005-05-26 13:03:09 -0700122 };
123
Benoit Taine9baa3c32014-08-08 15:56:03 +0200124static const struct pci_device_id bnx2_pci_tbl[] = {
Michael Chanb6016b72005-05-26 13:03:09 -0700125 { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5706,
126 PCI_VENDOR_ID_HP, 0x3101, 0, 0, NC370T },
127 { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5706,
128 PCI_VENDOR_ID_HP, 0x3106, 0, 0, NC370I },
129 { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5706,
130 PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5706 },
Michael Chan5b0c76a2005-11-04 08:45:49 -0800131 { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5708,
132 PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5708 },
Michael Chanb6016b72005-05-26 13:03:09 -0700133 { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5706S,
134 PCI_VENDOR_ID_HP, 0x3102, 0, 0, NC370F },
135 { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5706S,
136 PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5706S },
Michael Chan5b0c76a2005-11-04 08:45:49 -0800137 { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5708S,
138 PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5708S },
Michael Chanbac0dff2006-11-19 14:15:05 -0800139 { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5709,
140 PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5709 },
Michael Chan27a005b2007-05-03 13:23:41 -0700141 { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5709S,
142 PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5709S },
Michael Chan7bb0a042008-07-14 22:37:47 -0700143 { PCI_VENDOR_ID_BROADCOM, 0x163b,
144 PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5716 },
Michael Chan1caacec2008-11-12 16:01:12 -0800145 { PCI_VENDOR_ID_BROADCOM, 0x163c,
Michael Chan1f2435e2008-12-16 20:28:13 -0800146 PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5716S },
Michael Chanb6016b72005-05-26 13:03:09 -0700147 { 0, }
148};
149
Michael Chan0ced9d02009-08-21 16:20:49 +0000150static const struct flash_spec flash_table[] =
Michael Chanb6016b72005-05-26 13:03:09 -0700151{
Michael Chane30372c2007-07-16 18:26:23 -0700152#define BUFFERED_FLAGS (BNX2_NV_BUFFERED | BNX2_NV_TRANSLATE)
153#define NONBUFFERED_FLAGS (BNX2_NV_WREN)
Michael Chanb6016b72005-05-26 13:03:09 -0700154 /* Slow EEPROM */
Michael Chan37137702005-11-04 08:49:17 -0800155 {0x00000000, 0x40830380, 0x009f0081, 0xa184a053, 0xaf000400,
Michael Chane30372c2007-07-16 18:26:23 -0700156 BUFFERED_FLAGS, SEEPROM_PAGE_BITS, SEEPROM_PAGE_SIZE,
Michael Chanb6016b72005-05-26 13:03:09 -0700157 SEEPROM_BYTE_ADDR_MASK, SEEPROM_TOTAL_SIZE,
158 "EEPROM - slow"},
Michael Chan37137702005-11-04 08:49:17 -0800159 /* Expansion entry 0001 */
160 {0x08000002, 0x4b808201, 0x00050081, 0x03840253, 0xaf020406,
Michael Chane30372c2007-07-16 18:26:23 -0700161 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
Michael Chan37137702005-11-04 08:49:17 -0800162 SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
163 "Entry 0001"},
Michael Chanb6016b72005-05-26 13:03:09 -0700164 /* Saifun SA25F010 (non-buffered flash) */
165 /* strap, cfg1, & write1 need updates */
Michael Chan37137702005-11-04 08:49:17 -0800166 {0x04000001, 0x47808201, 0x00050081, 0x03840253, 0xaf020406,
Michael Chane30372c2007-07-16 18:26:23 -0700167 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
Michael Chanb6016b72005-05-26 13:03:09 -0700168 SAIFUN_FLASH_BYTE_ADDR_MASK, SAIFUN_FLASH_BASE_TOTAL_SIZE*2,
169 "Non-buffered flash (128kB)"},
170 /* Saifun SA25F020 (non-buffered flash) */
171 /* strap, cfg1, & write1 need updates */
Michael Chan37137702005-11-04 08:49:17 -0800172 {0x0c000003, 0x4f808201, 0x00050081, 0x03840253, 0xaf020406,
Michael Chane30372c2007-07-16 18:26:23 -0700173 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
Michael Chanb6016b72005-05-26 13:03:09 -0700174 SAIFUN_FLASH_BYTE_ADDR_MASK, SAIFUN_FLASH_BASE_TOTAL_SIZE*4,
175 "Non-buffered flash (256kB)"},
Michael Chan37137702005-11-04 08:49:17 -0800176 /* Expansion entry 0100 */
177 {0x11000000, 0x53808201, 0x00050081, 0x03840253, 0xaf020406,
Michael Chane30372c2007-07-16 18:26:23 -0700178 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
Michael Chan37137702005-11-04 08:49:17 -0800179 SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
180 "Entry 0100"},
181 /* Entry 0101: ST M45PE10 (non-buffered flash, TetonII B0) */
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400182 {0x19000002, 0x5b808201, 0x000500db, 0x03840253, 0xaf020406,
Michael Chane30372c2007-07-16 18:26:23 -0700183 NONBUFFERED_FLAGS, ST_MICRO_FLASH_PAGE_BITS, ST_MICRO_FLASH_PAGE_SIZE,
Michael Chan37137702005-11-04 08:49:17 -0800184 ST_MICRO_FLASH_BYTE_ADDR_MASK, ST_MICRO_FLASH_BASE_TOTAL_SIZE*2,
185 "Entry 0101: ST M45PE10 (128kB non-bufferred)"},
186 /* Entry 0110: ST M45PE20 (non-buffered flash)*/
187 {0x15000001, 0x57808201, 0x000500db, 0x03840253, 0xaf020406,
Michael Chane30372c2007-07-16 18:26:23 -0700188 NONBUFFERED_FLAGS, ST_MICRO_FLASH_PAGE_BITS, ST_MICRO_FLASH_PAGE_SIZE,
Michael Chan37137702005-11-04 08:49:17 -0800189 ST_MICRO_FLASH_BYTE_ADDR_MASK, ST_MICRO_FLASH_BASE_TOTAL_SIZE*4,
190 "Entry 0110: ST M45PE20 (256kB non-bufferred)"},
191 /* Saifun SA25F005 (non-buffered flash) */
192 /* strap, cfg1, & write1 need updates */
193 {0x1d000003, 0x5f808201, 0x00050081, 0x03840253, 0xaf020406,
Michael Chane30372c2007-07-16 18:26:23 -0700194 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
Michael Chan37137702005-11-04 08:49:17 -0800195 SAIFUN_FLASH_BYTE_ADDR_MASK, SAIFUN_FLASH_BASE_TOTAL_SIZE,
196 "Non-buffered flash (64kB)"},
197 /* Fast EEPROM */
198 {0x22000000, 0x62808380, 0x009f0081, 0xa184a053, 0xaf000400,
Michael Chane30372c2007-07-16 18:26:23 -0700199 BUFFERED_FLAGS, SEEPROM_PAGE_BITS, SEEPROM_PAGE_SIZE,
Michael Chan37137702005-11-04 08:49:17 -0800200 SEEPROM_BYTE_ADDR_MASK, SEEPROM_TOTAL_SIZE,
201 "EEPROM - fast"},
202 /* Expansion entry 1001 */
203 {0x2a000002, 0x6b808201, 0x00050081, 0x03840253, 0xaf020406,
Michael Chane30372c2007-07-16 18:26:23 -0700204 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
Michael Chan37137702005-11-04 08:49:17 -0800205 SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
206 "Entry 1001"},
207 /* Expansion entry 1010 */
208 {0x26000001, 0x67808201, 0x00050081, 0x03840253, 0xaf020406,
Michael Chane30372c2007-07-16 18:26:23 -0700209 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
Michael Chan37137702005-11-04 08:49:17 -0800210 SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
211 "Entry 1010"},
212 /* ATMEL AT45DB011B (buffered flash) */
213 {0x2e000003, 0x6e808273, 0x00570081, 0x68848353, 0xaf000400,
Michael Chane30372c2007-07-16 18:26:23 -0700214 BUFFERED_FLAGS, BUFFERED_FLASH_PAGE_BITS, BUFFERED_FLASH_PAGE_SIZE,
Michael Chan37137702005-11-04 08:49:17 -0800215 BUFFERED_FLASH_BYTE_ADDR_MASK, BUFFERED_FLASH_TOTAL_SIZE,
216 "Buffered flash (128kB)"},
217 /* Expansion entry 1100 */
218 {0x33000000, 0x73808201, 0x00050081, 0x03840253, 0xaf020406,
Michael Chane30372c2007-07-16 18:26:23 -0700219 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
Michael Chan37137702005-11-04 08:49:17 -0800220 SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
221 "Entry 1100"},
222 /* Expansion entry 1101 */
223 {0x3b000002, 0x7b808201, 0x00050081, 0x03840253, 0xaf020406,
Michael Chane30372c2007-07-16 18:26:23 -0700224 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
Michael Chan37137702005-11-04 08:49:17 -0800225 SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
226 "Entry 1101"},
227 /* Ateml Expansion entry 1110 */
228 {0x37000001, 0x76808273, 0x00570081, 0x68848353, 0xaf000400,
Michael Chane30372c2007-07-16 18:26:23 -0700229 BUFFERED_FLAGS, BUFFERED_FLASH_PAGE_BITS, BUFFERED_FLASH_PAGE_SIZE,
Michael Chan37137702005-11-04 08:49:17 -0800230 BUFFERED_FLASH_BYTE_ADDR_MASK, 0,
231 "Entry 1110 (Atmel)"},
232 /* ATMEL AT45DB021B (buffered flash) */
233 {0x3f000003, 0x7e808273, 0x00570081, 0x68848353, 0xaf000400,
Michael Chane30372c2007-07-16 18:26:23 -0700234 BUFFERED_FLAGS, BUFFERED_FLASH_PAGE_BITS, BUFFERED_FLASH_PAGE_SIZE,
Michael Chan37137702005-11-04 08:49:17 -0800235 BUFFERED_FLASH_BYTE_ADDR_MASK, BUFFERED_FLASH_TOTAL_SIZE*2,
236 "Buffered flash (256kB)"},
Michael Chanb6016b72005-05-26 13:03:09 -0700237};
238
Michael Chan0ced9d02009-08-21 16:20:49 +0000239static const struct flash_spec flash_5709 = {
Michael Chane30372c2007-07-16 18:26:23 -0700240 .flags = BNX2_NV_BUFFERED,
241 .page_bits = BCM5709_FLASH_PAGE_BITS,
242 .page_size = BCM5709_FLASH_PAGE_SIZE,
243 .addr_mask = BCM5709_FLASH_BYTE_ADDR_MASK,
244 .total_size = BUFFERED_FLASH_TOTAL_SIZE*2,
245 .name = "5709 Buffered flash (256kB)",
246};
247
Michael Chanb6016b72005-05-26 13:03:09 -0700248MODULE_DEVICE_TABLE(pci, bnx2_pci_tbl);
249
Benjamin Li4327ba42010-03-23 13:13:11 +0000250static void bnx2_init_napi(struct bnx2 *bp);
Michael Chanf048fa92010-06-01 15:05:36 +0000251static void bnx2_del_napi(struct bnx2 *bp);
Benjamin Li4327ba42010-03-23 13:13:11 +0000252
Michael Chan35e90102008-06-19 16:37:42 -0700253static inline u32 bnx2_tx_avail(struct bnx2 *bp, struct bnx2_tx_ring_info *txr)
Michael Chane89bbf12005-08-25 15:36:58 -0700254{
Michael Chan2f8af122006-08-15 01:39:10 -0700255 u32 diff;
Michael Chane89bbf12005-08-25 15:36:58 -0700256
Michael Chan11848b962010-07-19 14:15:04 +0000257 /* Tell compiler to fetch tx_prod and tx_cons from memory. */
258 barrier();
Michael Chanfaac9c42006-12-14 15:56:32 -0800259
260 /* The ring uses 256 indices for 255 entries, one of them
261 * needs to be skipped.
262 */
Michael Chan35e90102008-06-19 16:37:42 -0700263 diff = txr->tx_prod - txr->tx_cons;
Michael Chan2bc40782012-12-06 10:33:09 +0000264 if (unlikely(diff >= BNX2_TX_DESC_CNT)) {
Michael Chanfaac9c42006-12-14 15:56:32 -0800265 diff &= 0xffff;
Michael Chan2bc40782012-12-06 10:33:09 +0000266 if (diff == BNX2_TX_DESC_CNT)
267 diff = BNX2_MAX_TX_DESC_CNT;
Michael Chanfaac9c42006-12-14 15:56:32 -0800268 }
Eric Dumazet807540b2010-09-23 05:40:09 +0000269 return bp->tx_ring_size - diff;
Michael Chane89bbf12005-08-25 15:36:58 -0700270}
271
Michael Chanb6016b72005-05-26 13:03:09 -0700272static u32
273bnx2_reg_rd_ind(struct bnx2 *bp, u32 offset)
274{
Ivan Vecera6bc80622016-10-18 08:16:03 +0200275 unsigned long flags;
Michael Chan1b8227c2007-05-03 13:24:05 -0700276 u32 val;
277
Ivan Vecera6bc80622016-10-18 08:16:03 +0200278 spin_lock_irqsave(&bp->indirect_lock, flags);
Michael Chane503e062012-12-06 10:33:08 +0000279 BNX2_WR(bp, BNX2_PCICFG_REG_WINDOW_ADDRESS, offset);
280 val = BNX2_RD(bp, BNX2_PCICFG_REG_WINDOW);
Ivan Vecera6bc80622016-10-18 08:16:03 +0200281 spin_unlock_irqrestore(&bp->indirect_lock, flags);
Michael Chan1b8227c2007-05-03 13:24:05 -0700282 return val;
Michael Chanb6016b72005-05-26 13:03:09 -0700283}
284
285static void
286bnx2_reg_wr_ind(struct bnx2 *bp, u32 offset, u32 val)
287{
Ivan Vecera6bc80622016-10-18 08:16:03 +0200288 unsigned long flags;
289
290 spin_lock_irqsave(&bp->indirect_lock, flags);
Michael Chane503e062012-12-06 10:33:08 +0000291 BNX2_WR(bp, BNX2_PCICFG_REG_WINDOW_ADDRESS, offset);
292 BNX2_WR(bp, BNX2_PCICFG_REG_WINDOW, val);
Ivan Vecera6bc80622016-10-18 08:16:03 +0200293 spin_unlock_irqrestore(&bp->indirect_lock, flags);
Michael Chanb6016b72005-05-26 13:03:09 -0700294}
295
296static void
Michael Chan2726d6e2008-01-29 21:35:05 -0800297bnx2_shmem_wr(struct bnx2 *bp, u32 offset, u32 val)
298{
299 bnx2_reg_wr_ind(bp, bp->shmem_base + offset, val);
300}
301
302static u32
303bnx2_shmem_rd(struct bnx2 *bp, u32 offset)
304{
Eric Dumazet807540b2010-09-23 05:40:09 +0000305 return bnx2_reg_rd_ind(bp, bp->shmem_base + offset);
Michael Chan2726d6e2008-01-29 21:35:05 -0800306}
307
308static void
Michael Chanb6016b72005-05-26 13:03:09 -0700309bnx2_ctx_wr(struct bnx2 *bp, u32 cid_addr, u32 offset, u32 val)
310{
Ivan Vecera6bc80622016-10-18 08:16:03 +0200311 unsigned long flags;
312
Michael Chanb6016b72005-05-26 13:03:09 -0700313 offset += cid_addr;
Ivan Vecera6bc80622016-10-18 08:16:03 +0200314 spin_lock_irqsave(&bp->indirect_lock, flags);
Michael Chan4ce45e02012-12-06 10:33:10 +0000315 if (BNX2_CHIP(bp) == BNX2_CHIP_5709) {
Michael Chan59b47d82006-11-19 14:10:45 -0800316 int i;
317
Michael Chane503e062012-12-06 10:33:08 +0000318 BNX2_WR(bp, BNX2_CTX_CTX_DATA, val);
319 BNX2_WR(bp, BNX2_CTX_CTX_CTRL,
320 offset | BNX2_CTX_CTX_CTRL_WRITE_REQ);
Michael Chan59b47d82006-11-19 14:10:45 -0800321 for (i = 0; i < 5; i++) {
Michael Chane503e062012-12-06 10:33:08 +0000322 val = BNX2_RD(bp, BNX2_CTX_CTX_CTRL);
Michael Chan59b47d82006-11-19 14:10:45 -0800323 if ((val & BNX2_CTX_CTX_CTRL_WRITE_REQ) == 0)
324 break;
325 udelay(5);
326 }
327 } else {
Michael Chane503e062012-12-06 10:33:08 +0000328 BNX2_WR(bp, BNX2_CTX_DATA_ADR, offset);
329 BNX2_WR(bp, BNX2_CTX_DATA, val);
Michael Chan59b47d82006-11-19 14:10:45 -0800330 }
Ivan Vecera6bc80622016-10-18 08:16:03 +0200331 spin_unlock_irqrestore(&bp->indirect_lock, flags);
Michael Chanb6016b72005-05-26 13:03:09 -0700332}
333
Michael Chan4edd4732009-06-08 18:14:42 -0700334#ifdef BCM_CNIC
335static int
336bnx2_drv_ctl(struct net_device *dev, struct drv_ctl_info *info)
337{
338 struct bnx2 *bp = netdev_priv(dev);
339 struct drv_ctl_io *io = &info->data.io;
340
341 switch (info->cmd) {
342 case DRV_CTL_IO_WR_CMD:
343 bnx2_reg_wr_ind(bp, io->offset, io->data);
344 break;
345 case DRV_CTL_IO_RD_CMD:
346 io->data = bnx2_reg_rd_ind(bp, io->offset);
347 break;
348 case DRV_CTL_CTX_WR_CMD:
349 bnx2_ctx_wr(bp, io->cid_addr, io->offset, io->data);
350 break;
351 default:
352 return -EINVAL;
353 }
354 return 0;
355}
356
357static void bnx2_setup_cnic_irq_info(struct bnx2 *bp)
358{
359 struct cnic_eth_dev *cp = &bp->cnic_eth_dev;
360 struct bnx2_napi *bnapi = &bp->bnx2_napi[0];
361 int sb_id;
362
363 if (bp->flags & BNX2_FLAG_USING_MSIX) {
364 cp->drv_state |= CNIC_DRV_STATE_USING_MSIX;
365 bnapi->cnic_present = 0;
366 sb_id = bp->irq_nvecs;
367 cp->irq_arr[0].irq_flags |= CNIC_IRQ_FL_MSIX;
368 } else {
369 cp->drv_state &= ~CNIC_DRV_STATE_USING_MSIX;
370 bnapi->cnic_tag = bnapi->last_status_idx;
371 bnapi->cnic_present = 1;
372 sb_id = 0;
373 cp->irq_arr[0].irq_flags &= ~CNIC_IRQ_FL_MSIX;
374 }
375
376 cp->irq_arr[0].vector = bp->irq_tbl[sb_id].vector;
377 cp->irq_arr[0].status_blk = (void *)
378 ((unsigned long) bnapi->status_blk.msi +
379 (BNX2_SBLK_MSIX_ALIGN_SIZE * sb_id));
380 cp->irq_arr[0].status_blk_num = sb_id;
381 cp->num_irq = 1;
382}
383
384static int bnx2_register_cnic(struct net_device *dev, struct cnic_ops *ops,
385 void *data)
386{
387 struct bnx2 *bp = netdev_priv(dev);
388 struct cnic_eth_dev *cp = &bp->cnic_eth_dev;
389
390 if (ops == NULL)
391 return -EINVAL;
392
393 if (cp->drv_state & CNIC_DRV_STATE_REGD)
394 return -EBUSY;
395
Michael Chan41c21782011-07-13 17:24:22 +0000396 if (!bnx2_reg_rd_ind(bp, BNX2_FW_MAX_ISCSI_CONN))
397 return -ENODEV;
398
Michael Chan4edd4732009-06-08 18:14:42 -0700399 bp->cnic_data = data;
400 rcu_assign_pointer(bp->cnic_ops, ops);
401
402 cp->num_irq = 0;
403 cp->drv_state = CNIC_DRV_STATE_REGD;
404
405 bnx2_setup_cnic_irq_info(bp);
406
407 return 0;
408}
409
410static int bnx2_unregister_cnic(struct net_device *dev)
411{
412 struct bnx2 *bp = netdev_priv(dev);
413 struct bnx2_napi *bnapi = &bp->bnx2_napi[0];
414 struct cnic_eth_dev *cp = &bp->cnic_eth_dev;
415
Michael Chanc5a88952009-08-14 15:49:45 +0000416 mutex_lock(&bp->cnic_lock);
Michael Chan4edd4732009-06-08 18:14:42 -0700417 cp->drv_state = 0;
418 bnapi->cnic_present = 0;
Eric Dumazet2cfa5a02011-11-23 07:09:32 +0000419 RCU_INIT_POINTER(bp->cnic_ops, NULL);
Michael Chanc5a88952009-08-14 15:49:45 +0000420 mutex_unlock(&bp->cnic_lock);
Michael Chan4edd4732009-06-08 18:14:42 -0700421 synchronize_rcu();
422 return 0;
423}
424
stephen hemminger61c2fc42013-04-10 10:53:40 +0000425static struct cnic_eth_dev *bnx2_cnic_probe(struct net_device *dev)
Michael Chan4edd4732009-06-08 18:14:42 -0700426{
427 struct bnx2 *bp = netdev_priv(dev);
428 struct cnic_eth_dev *cp = &bp->cnic_eth_dev;
429
Michael Chan7625eb22011-06-08 19:29:36 +0000430 if (!cp->max_iscsi_conn)
431 return NULL;
432
Michael Chan4edd4732009-06-08 18:14:42 -0700433 cp->drv_owner = THIS_MODULE;
434 cp->chip_id = bp->chip_id;
435 cp->pdev = bp->pdev;
436 cp->io_base = bp->regview;
437 cp->drv_ctl = bnx2_drv_ctl;
438 cp->drv_register_cnic = bnx2_register_cnic;
439 cp->drv_unregister_cnic = bnx2_unregister_cnic;
440
441 return cp;
442}
Michael Chan4edd4732009-06-08 18:14:42 -0700443
444static void
445bnx2_cnic_stop(struct bnx2 *bp)
446{
447 struct cnic_ops *c_ops;
448 struct cnic_ctl_info info;
449
Michael Chanc5a88952009-08-14 15:49:45 +0000450 mutex_lock(&bp->cnic_lock);
Eric Dumazet13707f92011-01-26 19:28:23 +0000451 c_ops = rcu_dereference_protected(bp->cnic_ops,
452 lockdep_is_held(&bp->cnic_lock));
Michael Chan4edd4732009-06-08 18:14:42 -0700453 if (c_ops) {
454 info.cmd = CNIC_CTL_STOP_CMD;
455 c_ops->cnic_ctl(bp->cnic_data, &info);
456 }
Michael Chanc5a88952009-08-14 15:49:45 +0000457 mutex_unlock(&bp->cnic_lock);
Michael Chan4edd4732009-06-08 18:14:42 -0700458}
459
460static void
461bnx2_cnic_start(struct bnx2 *bp)
462{
463 struct cnic_ops *c_ops;
464 struct cnic_ctl_info info;
465
Michael Chanc5a88952009-08-14 15:49:45 +0000466 mutex_lock(&bp->cnic_lock);
Eric Dumazet13707f92011-01-26 19:28:23 +0000467 c_ops = rcu_dereference_protected(bp->cnic_ops,
468 lockdep_is_held(&bp->cnic_lock));
Michael Chan4edd4732009-06-08 18:14:42 -0700469 if (c_ops) {
470 if (!(bp->flags & BNX2_FLAG_USING_MSIX)) {
471 struct bnx2_napi *bnapi = &bp->bnx2_napi[0];
472
473 bnapi->cnic_tag = bnapi->last_status_idx;
474 }
475 info.cmd = CNIC_CTL_START_CMD;
476 c_ops->cnic_ctl(bp->cnic_data, &info);
477 }
Michael Chanc5a88952009-08-14 15:49:45 +0000478 mutex_unlock(&bp->cnic_lock);
Michael Chan4edd4732009-06-08 18:14:42 -0700479}
480
481#else
482
483static void
484bnx2_cnic_stop(struct bnx2 *bp)
485{
486}
487
488static void
489bnx2_cnic_start(struct bnx2 *bp)
490{
491}
492
493#endif
494
Michael Chanb6016b72005-05-26 13:03:09 -0700495static int
496bnx2_read_phy(struct bnx2 *bp, u32 reg, u32 *val)
497{
498 u32 val1;
499 int i, ret;
500
Michael Chan583c28e2008-01-21 19:51:35 -0800501 if (bp->phy_flags & BNX2_PHY_FLAG_INT_MODE_AUTO_POLLING) {
Michael Chane503e062012-12-06 10:33:08 +0000502 val1 = BNX2_RD(bp, BNX2_EMAC_MDIO_MODE);
Michael Chanb6016b72005-05-26 13:03:09 -0700503 val1 &= ~BNX2_EMAC_MDIO_MODE_AUTO_POLL;
504
Michael Chane503e062012-12-06 10:33:08 +0000505 BNX2_WR(bp, BNX2_EMAC_MDIO_MODE, val1);
506 BNX2_RD(bp, BNX2_EMAC_MDIO_MODE);
Michael Chanb6016b72005-05-26 13:03:09 -0700507
508 udelay(40);
509 }
510
511 val1 = (bp->phy_addr << 21) | (reg << 16) |
512 BNX2_EMAC_MDIO_COMM_COMMAND_READ | BNX2_EMAC_MDIO_COMM_DISEXT |
513 BNX2_EMAC_MDIO_COMM_START_BUSY;
Michael Chane503e062012-12-06 10:33:08 +0000514 BNX2_WR(bp, BNX2_EMAC_MDIO_COMM, val1);
Michael Chanb6016b72005-05-26 13:03:09 -0700515
516 for (i = 0; i < 50; i++) {
517 udelay(10);
518
Michael Chane503e062012-12-06 10:33:08 +0000519 val1 = BNX2_RD(bp, BNX2_EMAC_MDIO_COMM);
Michael Chanb6016b72005-05-26 13:03:09 -0700520 if (!(val1 & BNX2_EMAC_MDIO_COMM_START_BUSY)) {
521 udelay(5);
522
Michael Chane503e062012-12-06 10:33:08 +0000523 val1 = BNX2_RD(bp, BNX2_EMAC_MDIO_COMM);
Michael Chanb6016b72005-05-26 13:03:09 -0700524 val1 &= BNX2_EMAC_MDIO_COMM_DATA;
525
526 break;
527 }
528 }
529
530 if (val1 & BNX2_EMAC_MDIO_COMM_START_BUSY) {
531 *val = 0x0;
532 ret = -EBUSY;
533 }
534 else {
535 *val = val1;
536 ret = 0;
537 }
538
Michael Chan583c28e2008-01-21 19:51:35 -0800539 if (bp->phy_flags & BNX2_PHY_FLAG_INT_MODE_AUTO_POLLING) {
Michael Chane503e062012-12-06 10:33:08 +0000540 val1 = BNX2_RD(bp, BNX2_EMAC_MDIO_MODE);
Michael Chanb6016b72005-05-26 13:03:09 -0700541 val1 |= BNX2_EMAC_MDIO_MODE_AUTO_POLL;
542
Michael Chane503e062012-12-06 10:33:08 +0000543 BNX2_WR(bp, BNX2_EMAC_MDIO_MODE, val1);
544 BNX2_RD(bp, BNX2_EMAC_MDIO_MODE);
Michael Chanb6016b72005-05-26 13:03:09 -0700545
546 udelay(40);
547 }
548
549 return ret;
550}
551
552static int
553bnx2_write_phy(struct bnx2 *bp, u32 reg, u32 val)
554{
555 u32 val1;
556 int i, ret;
557
Michael Chan583c28e2008-01-21 19:51:35 -0800558 if (bp->phy_flags & BNX2_PHY_FLAG_INT_MODE_AUTO_POLLING) {
Michael Chane503e062012-12-06 10:33:08 +0000559 val1 = BNX2_RD(bp, BNX2_EMAC_MDIO_MODE);
Michael Chanb6016b72005-05-26 13:03:09 -0700560 val1 &= ~BNX2_EMAC_MDIO_MODE_AUTO_POLL;
561
Michael Chane503e062012-12-06 10:33:08 +0000562 BNX2_WR(bp, BNX2_EMAC_MDIO_MODE, val1);
563 BNX2_RD(bp, BNX2_EMAC_MDIO_MODE);
Michael Chanb6016b72005-05-26 13:03:09 -0700564
565 udelay(40);
566 }
567
568 val1 = (bp->phy_addr << 21) | (reg << 16) | val |
569 BNX2_EMAC_MDIO_COMM_COMMAND_WRITE |
570 BNX2_EMAC_MDIO_COMM_START_BUSY | BNX2_EMAC_MDIO_COMM_DISEXT;
Michael Chane503e062012-12-06 10:33:08 +0000571 BNX2_WR(bp, BNX2_EMAC_MDIO_COMM, val1);
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400572
Michael Chanb6016b72005-05-26 13:03:09 -0700573 for (i = 0; i < 50; i++) {
574 udelay(10);
575
Michael Chane503e062012-12-06 10:33:08 +0000576 val1 = BNX2_RD(bp, BNX2_EMAC_MDIO_COMM);
Michael Chanb6016b72005-05-26 13:03:09 -0700577 if (!(val1 & BNX2_EMAC_MDIO_COMM_START_BUSY)) {
578 udelay(5);
579 break;
580 }
581 }
582
583 if (val1 & BNX2_EMAC_MDIO_COMM_START_BUSY)
584 ret = -EBUSY;
585 else
586 ret = 0;
587
Michael Chan583c28e2008-01-21 19:51:35 -0800588 if (bp->phy_flags & BNX2_PHY_FLAG_INT_MODE_AUTO_POLLING) {
Michael Chane503e062012-12-06 10:33:08 +0000589 val1 = BNX2_RD(bp, BNX2_EMAC_MDIO_MODE);
Michael Chanb6016b72005-05-26 13:03:09 -0700590 val1 |= BNX2_EMAC_MDIO_MODE_AUTO_POLL;
591
Michael Chane503e062012-12-06 10:33:08 +0000592 BNX2_WR(bp, BNX2_EMAC_MDIO_MODE, val1);
593 BNX2_RD(bp, BNX2_EMAC_MDIO_MODE);
Michael Chanb6016b72005-05-26 13:03:09 -0700594
595 udelay(40);
596 }
597
598 return ret;
599}
600
601static void
602bnx2_disable_int(struct bnx2 *bp)
603{
Michael Chanb4b36042007-12-20 19:59:30 -0800604 int i;
605 struct bnx2_napi *bnapi;
606
607 for (i = 0; i < bp->irq_nvecs; i++) {
608 bnapi = &bp->bnx2_napi[i];
Michael Chane503e062012-12-06 10:33:08 +0000609 BNX2_WR(bp, BNX2_PCICFG_INT_ACK_CMD, bnapi->int_num |
Michael Chanb4b36042007-12-20 19:59:30 -0800610 BNX2_PCICFG_INT_ACK_CMD_MASK_INT);
611 }
Michael Chane503e062012-12-06 10:33:08 +0000612 BNX2_RD(bp, BNX2_PCICFG_INT_ACK_CMD);
Michael Chanb6016b72005-05-26 13:03:09 -0700613}
614
615static void
616bnx2_enable_int(struct bnx2 *bp)
617{
Michael Chanb4b36042007-12-20 19:59:30 -0800618 int i;
619 struct bnx2_napi *bnapi;
Michael Chan1269a8a2006-01-23 16:11:03 -0800620
Michael Chanb4b36042007-12-20 19:59:30 -0800621 for (i = 0; i < bp->irq_nvecs; i++) {
622 bnapi = &bp->bnx2_napi[i];
Michael Chan35efa7c2007-12-20 19:56:37 -0800623
Michael Chane503e062012-12-06 10:33:08 +0000624 BNX2_WR(bp, BNX2_PCICFG_INT_ACK_CMD, bnapi->int_num |
625 BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
626 BNX2_PCICFG_INT_ACK_CMD_MASK_INT |
627 bnapi->last_status_idx);
Michael Chanb6016b72005-05-26 13:03:09 -0700628
Michael Chane503e062012-12-06 10:33:08 +0000629 BNX2_WR(bp, BNX2_PCICFG_INT_ACK_CMD, bnapi->int_num |
630 BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
631 bnapi->last_status_idx);
Michael Chanb4b36042007-12-20 19:59:30 -0800632 }
Michael Chane503e062012-12-06 10:33:08 +0000633 BNX2_WR(bp, BNX2_HC_COMMAND, bp->hc_cmd | BNX2_HC_COMMAND_COAL_NOW);
Michael Chanb6016b72005-05-26 13:03:09 -0700634}
635
636static void
637bnx2_disable_int_sync(struct bnx2 *bp)
638{
Michael Chanb4b36042007-12-20 19:59:30 -0800639 int i;
640
Michael Chanb6016b72005-05-26 13:03:09 -0700641 atomic_inc(&bp->intr_sem);
Michael Chan37675462009-08-21 16:20:44 +0000642 if (!netif_running(bp->dev))
643 return;
644
Michael Chanb6016b72005-05-26 13:03:09 -0700645 bnx2_disable_int(bp);
Michael Chanb4b36042007-12-20 19:59:30 -0800646 for (i = 0; i < bp->irq_nvecs; i++)
647 synchronize_irq(bp->irq_tbl[i].vector);
Michael Chanb6016b72005-05-26 13:03:09 -0700648}
649
650static void
Michael Chan35efa7c2007-12-20 19:56:37 -0800651bnx2_napi_disable(struct bnx2 *bp)
652{
Michael Chanb4b36042007-12-20 19:59:30 -0800653 int i;
654
655 for (i = 0; i < bp->irq_nvecs; i++)
656 napi_disable(&bp->bnx2_napi[i].napi);
Michael Chan35efa7c2007-12-20 19:56:37 -0800657}
658
659static void
660bnx2_napi_enable(struct bnx2 *bp)
661{
Michael Chanb4b36042007-12-20 19:59:30 -0800662 int i;
663
664 for (i = 0; i < bp->irq_nvecs; i++)
665 napi_enable(&bp->bnx2_napi[i].napi);
Michael Chan35efa7c2007-12-20 19:56:37 -0800666}
667
668static void
Michael Chan212f9932010-04-27 11:28:10 +0000669bnx2_netif_stop(struct bnx2 *bp, bool stop_cnic)
Michael Chanb6016b72005-05-26 13:03:09 -0700670{
Michael Chan212f9932010-04-27 11:28:10 +0000671 if (stop_cnic)
672 bnx2_cnic_stop(bp);
Michael Chanb6016b72005-05-26 13:03:09 -0700673 if (netif_running(bp->dev)) {
Michael Chan35efa7c2007-12-20 19:56:37 -0800674 bnx2_napi_disable(bp);
Michael Chanb6016b72005-05-26 13:03:09 -0700675 netif_tx_disable(bp->dev);
Michael Chanb6016b72005-05-26 13:03:09 -0700676 }
Michael Chanb7466562009-12-20 18:40:18 -0800677 bnx2_disable_int_sync(bp);
Michael Chana0ba6762010-05-17 17:34:43 -0700678 netif_carrier_off(bp->dev); /* prevent tx timeout */
Michael Chanb6016b72005-05-26 13:03:09 -0700679}
680
681static void
Michael Chan212f9932010-04-27 11:28:10 +0000682bnx2_netif_start(struct bnx2 *bp, bool start_cnic)
Michael Chanb6016b72005-05-26 13:03:09 -0700683{
684 if (atomic_dec_and_test(&bp->intr_sem)) {
685 if (netif_running(bp->dev)) {
Benjamin Li706bf242008-07-18 17:55:11 -0700686 netif_tx_wake_all_queues(bp->dev);
Michael Chana0ba6762010-05-17 17:34:43 -0700687 spin_lock_bh(&bp->phy_lock);
688 if (bp->link_up)
689 netif_carrier_on(bp->dev);
690 spin_unlock_bh(&bp->phy_lock);
Michael Chan35efa7c2007-12-20 19:56:37 -0800691 bnx2_napi_enable(bp);
Michael Chanb6016b72005-05-26 13:03:09 -0700692 bnx2_enable_int(bp);
Michael Chan212f9932010-04-27 11:28:10 +0000693 if (start_cnic)
694 bnx2_cnic_start(bp);
Michael Chanb6016b72005-05-26 13:03:09 -0700695 }
696 }
697}
698
699static void
Michael Chan35e90102008-06-19 16:37:42 -0700700bnx2_free_tx_mem(struct bnx2 *bp)
701{
702 int i;
703
704 for (i = 0; i < bp->num_tx_rings; i++) {
705 struct bnx2_napi *bnapi = &bp->bnx2_napi[i];
706 struct bnx2_tx_ring_info *txr = &bnapi->tx_ring;
707
708 if (txr->tx_desc_ring) {
Stanislaw Gruszka36227e82010-07-15 04:25:50 +0000709 dma_free_coherent(&bp->pdev->dev, TXBD_RING_SIZE,
710 txr->tx_desc_ring,
711 txr->tx_desc_mapping);
Michael Chan35e90102008-06-19 16:37:42 -0700712 txr->tx_desc_ring = NULL;
713 }
714 kfree(txr->tx_buf_ring);
715 txr->tx_buf_ring = NULL;
716 }
717}
718
Michael Chanbb4f98a2008-06-19 16:38:19 -0700719static void
720bnx2_free_rx_mem(struct bnx2 *bp)
721{
722 int i;
723
724 for (i = 0; i < bp->num_rx_rings; i++) {
725 struct bnx2_napi *bnapi = &bp->bnx2_napi[i];
726 struct bnx2_rx_ring_info *rxr = &bnapi->rx_ring;
727 int j;
728
729 for (j = 0; j < bp->rx_max_ring; j++) {
730 if (rxr->rx_desc_ring[j])
Stanislaw Gruszka36227e82010-07-15 04:25:50 +0000731 dma_free_coherent(&bp->pdev->dev, RXBD_RING_SIZE,
732 rxr->rx_desc_ring[j],
733 rxr->rx_desc_mapping[j]);
Michael Chanbb4f98a2008-06-19 16:38:19 -0700734 rxr->rx_desc_ring[j] = NULL;
735 }
Breno Leitao25b0b992009-06-08 10:30:19 +0000736 vfree(rxr->rx_buf_ring);
Michael Chanbb4f98a2008-06-19 16:38:19 -0700737 rxr->rx_buf_ring = NULL;
738
739 for (j = 0; j < bp->rx_max_pg_ring; j++) {
740 if (rxr->rx_pg_desc_ring[j])
Stanislaw Gruszka36227e82010-07-15 04:25:50 +0000741 dma_free_coherent(&bp->pdev->dev, RXBD_RING_SIZE,
742 rxr->rx_pg_desc_ring[j],
743 rxr->rx_pg_desc_mapping[j]);
Michael Chan3298a732008-12-17 19:06:08 -0800744 rxr->rx_pg_desc_ring[j] = NULL;
Michael Chanbb4f98a2008-06-19 16:38:19 -0700745 }
Breno Leitao25b0b992009-06-08 10:30:19 +0000746 vfree(rxr->rx_pg_ring);
Michael Chanbb4f98a2008-06-19 16:38:19 -0700747 rxr->rx_pg_ring = NULL;
748 }
749}
750
Michael Chan35e90102008-06-19 16:37:42 -0700751static int
752bnx2_alloc_tx_mem(struct bnx2 *bp)
753{
754 int i;
755
756 for (i = 0; i < bp->num_tx_rings; i++) {
757 struct bnx2_napi *bnapi = &bp->bnx2_napi[i];
758 struct bnx2_tx_ring_info *txr = &bnapi->tx_ring;
759
760 txr->tx_buf_ring = kzalloc(SW_TXBD_RING_SIZE, GFP_KERNEL);
761 if (txr->tx_buf_ring == NULL)
762 return -ENOMEM;
763
764 txr->tx_desc_ring =
Stanislaw Gruszka36227e82010-07-15 04:25:50 +0000765 dma_alloc_coherent(&bp->pdev->dev, TXBD_RING_SIZE,
766 &txr->tx_desc_mapping, GFP_KERNEL);
Michael Chan35e90102008-06-19 16:37:42 -0700767 if (txr->tx_desc_ring == NULL)
768 return -ENOMEM;
769 }
770 return 0;
771}
772
Michael Chanbb4f98a2008-06-19 16:38:19 -0700773static int
774bnx2_alloc_rx_mem(struct bnx2 *bp)
775{
776 int i;
777
778 for (i = 0; i < bp->num_rx_rings; i++) {
779 struct bnx2_napi *bnapi = &bp->bnx2_napi[i];
780 struct bnx2_rx_ring_info *rxr = &bnapi->rx_ring;
781 int j;
782
783 rxr->rx_buf_ring =
Eric Dumazet89bf67f2010-11-22 00:15:06 +0000784 vzalloc(SW_RXBD_RING_SIZE * bp->rx_max_ring);
Michael Chanbb4f98a2008-06-19 16:38:19 -0700785 if (rxr->rx_buf_ring == NULL)
786 return -ENOMEM;
787
Michael Chanbb4f98a2008-06-19 16:38:19 -0700788 for (j = 0; j < bp->rx_max_ring; j++) {
789 rxr->rx_desc_ring[j] =
Stanislaw Gruszka36227e82010-07-15 04:25:50 +0000790 dma_alloc_coherent(&bp->pdev->dev,
791 RXBD_RING_SIZE,
792 &rxr->rx_desc_mapping[j],
793 GFP_KERNEL);
Michael Chanbb4f98a2008-06-19 16:38:19 -0700794 if (rxr->rx_desc_ring[j] == NULL)
795 return -ENOMEM;
796
797 }
798
799 if (bp->rx_pg_ring_size) {
Eric Dumazet89bf67f2010-11-22 00:15:06 +0000800 rxr->rx_pg_ring = vzalloc(SW_RXPG_RING_SIZE *
Michael Chanbb4f98a2008-06-19 16:38:19 -0700801 bp->rx_max_pg_ring);
802 if (rxr->rx_pg_ring == NULL)
803 return -ENOMEM;
804
Michael Chanbb4f98a2008-06-19 16:38:19 -0700805 }
806
807 for (j = 0; j < bp->rx_max_pg_ring; j++) {
808 rxr->rx_pg_desc_ring[j] =
Stanislaw Gruszka36227e82010-07-15 04:25:50 +0000809 dma_alloc_coherent(&bp->pdev->dev,
810 RXBD_RING_SIZE,
811 &rxr->rx_pg_desc_mapping[j],
812 GFP_KERNEL);
Michael Chanbb4f98a2008-06-19 16:38:19 -0700813 if (rxr->rx_pg_desc_ring[j] == NULL)
814 return -ENOMEM;
815
816 }
817 }
818 return 0;
819}
820
Michael Chan35e90102008-06-19 16:37:42 -0700821static void
wangweidong8fae3072015-10-08 18:03:47 +0800822bnx2_free_stats_blk(struct net_device *dev)
823{
824 struct bnx2 *bp = netdev_priv(dev);
825
826 if (bp->status_blk) {
827 dma_free_coherent(&bp->pdev->dev, bp->status_stats_size,
828 bp->status_blk,
829 bp->status_blk_mapping);
830 bp->status_blk = NULL;
831 bp->stats_blk = NULL;
832 }
833}
834
835static int
836bnx2_alloc_stats_blk(struct net_device *dev)
837{
838 int status_blk_size;
839 void *status_blk;
840 struct bnx2 *bp = netdev_priv(dev);
841
842 /* Combine status and statistics blocks into one allocation. */
843 status_blk_size = L1_CACHE_ALIGN(sizeof(struct status_block));
844 if (bp->flags & BNX2_FLAG_MSIX_CAP)
845 status_blk_size = L1_CACHE_ALIGN(BNX2_MAX_MSIX_HW_VEC *
846 BNX2_SBLK_MSIX_ALIGN_SIZE);
847 bp->status_stats_size = status_blk_size +
848 sizeof(struct statistics_block);
849 status_blk = dma_zalloc_coherent(&bp->pdev->dev, bp->status_stats_size,
850 &bp->status_blk_mapping, GFP_KERNEL);
851 if (status_blk == NULL)
852 return -ENOMEM;
853
854 bp->status_blk = status_blk;
855 bp->stats_blk = status_blk + status_blk_size;
856 bp->stats_blk_mapping = bp->status_blk_mapping + status_blk_size;
857
858 return 0;
859}
860
861static void
Michael Chanb6016b72005-05-26 13:03:09 -0700862bnx2_free_mem(struct bnx2 *bp)
863{
Michael Chan13daffa2006-03-20 17:49:20 -0800864 int i;
Michael Chan43e80b82008-06-19 16:41:08 -0700865 struct bnx2_napi *bnapi = &bp->bnx2_napi[0];
Michael Chan13daffa2006-03-20 17:49:20 -0800866
Michael Chan35e90102008-06-19 16:37:42 -0700867 bnx2_free_tx_mem(bp);
Michael Chanbb4f98a2008-06-19 16:38:19 -0700868 bnx2_free_rx_mem(bp);
Michael Chan35e90102008-06-19 16:37:42 -0700869
Michael Chan59b47d82006-11-19 14:10:45 -0800870 for (i = 0; i < bp->ctx_pages; i++) {
871 if (bp->ctx_blk[i]) {
Michael Chan2bc40782012-12-06 10:33:09 +0000872 dma_free_coherent(&bp->pdev->dev, BNX2_PAGE_SIZE,
Stanislaw Gruszka36227e82010-07-15 04:25:50 +0000873 bp->ctx_blk[i],
874 bp->ctx_blk_mapping[i]);
Michael Chan59b47d82006-11-19 14:10:45 -0800875 bp->ctx_blk[i] = NULL;
876 }
877 }
wangweidong8fae3072015-10-08 18:03:47 +0800878
879 if (bnapi->status_blk.msi)
Michael Chan43e80b82008-06-19 16:41:08 -0700880 bnapi->status_blk.msi = NULL;
Michael Chanb6016b72005-05-26 13:03:09 -0700881}
882
883static int
884bnx2_alloc_mem(struct bnx2 *bp)
885{
wangweidong8fae3072015-10-08 18:03:47 +0800886 int i, err;
Michael Chan43e80b82008-06-19 16:41:08 -0700887 struct bnx2_napi *bnapi;
Michael Chanb6016b72005-05-26 13:03:09 -0700888
Michael Chan43e80b82008-06-19 16:41:08 -0700889 bnapi = &bp->bnx2_napi[0];
wangweidong8fae3072015-10-08 18:03:47 +0800890 bnapi->status_blk.msi = bp->status_blk;
Michael Chan43e80b82008-06-19 16:41:08 -0700891 bnapi->hw_tx_cons_ptr =
892 &bnapi->status_blk.msi->status_tx_quick_consumer_index0;
893 bnapi->hw_rx_cons_ptr =
894 &bnapi->status_blk.msi->status_rx_quick_consumer_index0;
David S. Millerf86e82f2008-01-21 17:15:40 -0800895 if (bp->flags & BNX2_FLAG_MSIX_CAP) {
Michael Chan379b39a2010-07-19 14:15:03 +0000896 for (i = 1; i < bp->irq_nvecs; i++) {
Michael Chan43e80b82008-06-19 16:41:08 -0700897 struct status_block_msix *sblk;
Michael Chanb4b36042007-12-20 19:59:30 -0800898
Michael Chan43e80b82008-06-19 16:41:08 -0700899 bnapi = &bp->bnx2_napi[i];
900
wangweidong8fae3072015-10-08 18:03:47 +0800901 sblk = (bp->status_blk + BNX2_SBLK_MSIX_ALIGN_SIZE * i);
Michael Chan43e80b82008-06-19 16:41:08 -0700902 bnapi->status_blk.msix = sblk;
903 bnapi->hw_tx_cons_ptr =
904 &sblk->status_tx_quick_consumer_index;
905 bnapi->hw_rx_cons_ptr =
906 &sblk->status_rx_quick_consumer_index;
Michael Chanb4b36042007-12-20 19:59:30 -0800907 bnapi->int_num = i << 24;
908 }
909 }
Michael Chan35efa7c2007-12-20 19:56:37 -0800910
Michael Chan4ce45e02012-12-06 10:33:10 +0000911 if (BNX2_CHIP(bp) == BNX2_CHIP_5709) {
Michael Chan2bc40782012-12-06 10:33:09 +0000912 bp->ctx_pages = 0x2000 / BNX2_PAGE_SIZE;
Michael Chan59b47d82006-11-19 14:10:45 -0800913 if (bp->ctx_pages == 0)
914 bp->ctx_pages = 1;
915 for (i = 0; i < bp->ctx_pages; i++) {
Stanislaw Gruszka36227e82010-07-15 04:25:50 +0000916 bp->ctx_blk[i] = dma_alloc_coherent(&bp->pdev->dev,
Michael Chan2bc40782012-12-06 10:33:09 +0000917 BNX2_PAGE_SIZE,
Stanislaw Gruszka36227e82010-07-15 04:25:50 +0000918 &bp->ctx_blk_mapping[i],
919 GFP_KERNEL);
Michael Chan59b47d82006-11-19 14:10:45 -0800920 if (bp->ctx_blk[i] == NULL)
921 goto alloc_mem_err;
922 }
923 }
Michael Chan35e90102008-06-19 16:37:42 -0700924
Michael Chanbb4f98a2008-06-19 16:38:19 -0700925 err = bnx2_alloc_rx_mem(bp);
926 if (err)
927 goto alloc_mem_err;
928
Michael Chan35e90102008-06-19 16:37:42 -0700929 err = bnx2_alloc_tx_mem(bp);
930 if (err)
931 goto alloc_mem_err;
932
Michael Chanb6016b72005-05-26 13:03:09 -0700933 return 0;
934
935alloc_mem_err:
936 bnx2_free_mem(bp);
937 return -ENOMEM;
938}
939
940static void
Michael Chane3648b32005-11-04 08:51:21 -0800941bnx2_report_fw_link(struct bnx2 *bp)
942{
943 u32 fw_link_status = 0;
944
Michael Chan583c28e2008-01-21 19:51:35 -0800945 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
Michael Chan0d8a6572007-07-07 22:49:43 -0700946 return;
947
Michael Chane3648b32005-11-04 08:51:21 -0800948 if (bp->link_up) {
949 u32 bmsr;
950
951 switch (bp->line_speed) {
952 case SPEED_10:
953 if (bp->duplex == DUPLEX_HALF)
954 fw_link_status = BNX2_LINK_STATUS_10HALF;
955 else
956 fw_link_status = BNX2_LINK_STATUS_10FULL;
957 break;
958 case SPEED_100:
959 if (bp->duplex == DUPLEX_HALF)
960 fw_link_status = BNX2_LINK_STATUS_100HALF;
961 else
962 fw_link_status = BNX2_LINK_STATUS_100FULL;
963 break;
964 case SPEED_1000:
965 if (bp->duplex == DUPLEX_HALF)
966 fw_link_status = BNX2_LINK_STATUS_1000HALF;
967 else
968 fw_link_status = BNX2_LINK_STATUS_1000FULL;
969 break;
970 case SPEED_2500:
971 if (bp->duplex == DUPLEX_HALF)
972 fw_link_status = BNX2_LINK_STATUS_2500HALF;
973 else
974 fw_link_status = BNX2_LINK_STATUS_2500FULL;
975 break;
976 }
977
978 fw_link_status |= BNX2_LINK_STATUS_LINK_UP;
979
980 if (bp->autoneg) {
981 fw_link_status |= BNX2_LINK_STATUS_AN_ENABLED;
982
Michael Chanca58c3a2007-05-03 13:22:52 -0700983 bnx2_read_phy(bp, bp->mii_bmsr, &bmsr);
984 bnx2_read_phy(bp, bp->mii_bmsr, &bmsr);
Michael Chane3648b32005-11-04 08:51:21 -0800985
986 if (!(bmsr & BMSR_ANEGCOMPLETE) ||
Michael Chan583c28e2008-01-21 19:51:35 -0800987 bp->phy_flags & BNX2_PHY_FLAG_PARALLEL_DETECT)
Michael Chane3648b32005-11-04 08:51:21 -0800988 fw_link_status |= BNX2_LINK_STATUS_PARALLEL_DET;
989 else
990 fw_link_status |= BNX2_LINK_STATUS_AN_COMPLETE;
991 }
992 }
993 else
994 fw_link_status = BNX2_LINK_STATUS_LINK_DOWN;
995
Michael Chan2726d6e2008-01-29 21:35:05 -0800996 bnx2_shmem_wr(bp, BNX2_LINK_STATUS, fw_link_status);
Michael Chane3648b32005-11-04 08:51:21 -0800997}
998
Michael Chan9b1084b2007-07-07 22:50:37 -0700999static char *
1000bnx2_xceiver_str(struct bnx2 *bp)
1001{
Eric Dumazet807540b2010-09-23 05:40:09 +00001002 return (bp->phy_port == PORT_FIBRE) ? "SerDes" :
Michael Chan583c28e2008-01-21 19:51:35 -08001003 ((bp->phy_flags & BNX2_PHY_FLAG_SERDES) ? "Remote Copper" :
Eric Dumazet807540b2010-09-23 05:40:09 +00001004 "Copper");
Michael Chan9b1084b2007-07-07 22:50:37 -07001005}
1006
Michael Chane3648b32005-11-04 08:51:21 -08001007static void
Michael Chanb6016b72005-05-26 13:03:09 -07001008bnx2_report_link(struct bnx2 *bp)
1009{
1010 if (bp->link_up) {
1011 netif_carrier_on(bp->dev);
Joe Perches3a9c6a42010-02-17 15:01:51 +00001012 netdev_info(bp->dev, "NIC %s Link is Up, %d Mbps %s duplex",
1013 bnx2_xceiver_str(bp),
1014 bp->line_speed,
1015 bp->duplex == DUPLEX_FULL ? "full" : "half");
Michael Chanb6016b72005-05-26 13:03:09 -07001016
1017 if (bp->flow_ctrl) {
1018 if (bp->flow_ctrl & FLOW_CTRL_RX) {
Joe Perches3a9c6a42010-02-17 15:01:51 +00001019 pr_cont(", receive ");
Michael Chanb6016b72005-05-26 13:03:09 -07001020 if (bp->flow_ctrl & FLOW_CTRL_TX)
Joe Perches3a9c6a42010-02-17 15:01:51 +00001021 pr_cont("& transmit ");
Michael Chanb6016b72005-05-26 13:03:09 -07001022 }
1023 else {
Joe Perches3a9c6a42010-02-17 15:01:51 +00001024 pr_cont(", transmit ");
Michael Chanb6016b72005-05-26 13:03:09 -07001025 }
Joe Perches3a9c6a42010-02-17 15:01:51 +00001026 pr_cont("flow control ON");
Michael Chanb6016b72005-05-26 13:03:09 -07001027 }
Joe Perches3a9c6a42010-02-17 15:01:51 +00001028 pr_cont("\n");
1029 } else {
Michael Chanb6016b72005-05-26 13:03:09 -07001030 netif_carrier_off(bp->dev);
Joe Perches3a9c6a42010-02-17 15:01:51 +00001031 netdev_err(bp->dev, "NIC %s Link is Down\n",
1032 bnx2_xceiver_str(bp));
Michael Chanb6016b72005-05-26 13:03:09 -07001033 }
Michael Chane3648b32005-11-04 08:51:21 -08001034
1035 bnx2_report_fw_link(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07001036}
1037
1038static void
1039bnx2_resolve_flow_ctrl(struct bnx2 *bp)
1040{
1041 u32 local_adv, remote_adv;
1042
1043 bp->flow_ctrl = 0;
Jeff Garzik6aa20a22006-09-13 13:24:59 -04001044 if ((bp->autoneg & (AUTONEG_SPEED | AUTONEG_FLOW_CTRL)) !=
Michael Chanb6016b72005-05-26 13:03:09 -07001045 (AUTONEG_SPEED | AUTONEG_FLOW_CTRL)) {
1046
1047 if (bp->duplex == DUPLEX_FULL) {
1048 bp->flow_ctrl = bp->req_flow_ctrl;
1049 }
1050 return;
1051 }
1052
1053 if (bp->duplex != DUPLEX_FULL) {
1054 return;
1055 }
1056
Michael Chan583c28e2008-01-21 19:51:35 -08001057 if ((bp->phy_flags & BNX2_PHY_FLAG_SERDES) &&
Michael Chan4ce45e02012-12-06 10:33:10 +00001058 (BNX2_CHIP(bp) == BNX2_CHIP_5708)) {
Michael Chan5b0c76a2005-11-04 08:45:49 -08001059 u32 val;
1060
1061 bnx2_read_phy(bp, BCM5708S_1000X_STAT1, &val);
1062 if (val & BCM5708S_1000X_STAT1_TX_PAUSE)
1063 bp->flow_ctrl |= FLOW_CTRL_TX;
1064 if (val & BCM5708S_1000X_STAT1_RX_PAUSE)
1065 bp->flow_ctrl |= FLOW_CTRL_RX;
1066 return;
1067 }
1068
Michael Chanca58c3a2007-05-03 13:22:52 -07001069 bnx2_read_phy(bp, bp->mii_adv, &local_adv);
1070 bnx2_read_phy(bp, bp->mii_lpa, &remote_adv);
Michael Chanb6016b72005-05-26 13:03:09 -07001071
Michael Chan583c28e2008-01-21 19:51:35 -08001072 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Michael Chanb6016b72005-05-26 13:03:09 -07001073 u32 new_local_adv = 0;
1074 u32 new_remote_adv = 0;
1075
1076 if (local_adv & ADVERTISE_1000XPAUSE)
1077 new_local_adv |= ADVERTISE_PAUSE_CAP;
1078 if (local_adv & ADVERTISE_1000XPSE_ASYM)
1079 new_local_adv |= ADVERTISE_PAUSE_ASYM;
1080 if (remote_adv & ADVERTISE_1000XPAUSE)
1081 new_remote_adv |= ADVERTISE_PAUSE_CAP;
1082 if (remote_adv & ADVERTISE_1000XPSE_ASYM)
1083 new_remote_adv |= ADVERTISE_PAUSE_ASYM;
1084
1085 local_adv = new_local_adv;
1086 remote_adv = new_remote_adv;
1087 }
1088
1089 /* See Table 28B-3 of 802.3ab-1999 spec. */
1090 if (local_adv & ADVERTISE_PAUSE_CAP) {
1091 if(local_adv & ADVERTISE_PAUSE_ASYM) {
1092 if (remote_adv & ADVERTISE_PAUSE_CAP) {
1093 bp->flow_ctrl = FLOW_CTRL_TX | FLOW_CTRL_RX;
1094 }
1095 else if (remote_adv & ADVERTISE_PAUSE_ASYM) {
1096 bp->flow_ctrl = FLOW_CTRL_RX;
1097 }
1098 }
1099 else {
1100 if (remote_adv & ADVERTISE_PAUSE_CAP) {
1101 bp->flow_ctrl = FLOW_CTRL_TX | FLOW_CTRL_RX;
1102 }
1103 }
1104 }
1105 else if (local_adv & ADVERTISE_PAUSE_ASYM) {
1106 if ((remote_adv & ADVERTISE_PAUSE_CAP) &&
1107 (remote_adv & ADVERTISE_PAUSE_ASYM)) {
1108
1109 bp->flow_ctrl = FLOW_CTRL_TX;
1110 }
1111 }
1112}
1113
1114static int
Michael Chan27a005b2007-05-03 13:23:41 -07001115bnx2_5709s_linkup(struct bnx2 *bp)
1116{
1117 u32 val, speed;
1118
1119 bp->link_up = 1;
1120
1121 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_GP_STATUS);
1122 bnx2_read_phy(bp, MII_BNX2_GP_TOP_AN_STATUS1, &val);
1123 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
1124
1125 if ((bp->autoneg & AUTONEG_SPEED) == 0) {
1126 bp->line_speed = bp->req_line_speed;
1127 bp->duplex = bp->req_duplex;
1128 return 0;
1129 }
1130 speed = val & MII_BNX2_GP_TOP_AN_SPEED_MSK;
1131 switch (speed) {
1132 case MII_BNX2_GP_TOP_AN_SPEED_10:
1133 bp->line_speed = SPEED_10;
1134 break;
1135 case MII_BNX2_GP_TOP_AN_SPEED_100:
1136 bp->line_speed = SPEED_100;
1137 break;
1138 case MII_BNX2_GP_TOP_AN_SPEED_1G:
1139 case MII_BNX2_GP_TOP_AN_SPEED_1GKV:
1140 bp->line_speed = SPEED_1000;
1141 break;
1142 case MII_BNX2_GP_TOP_AN_SPEED_2_5G:
1143 bp->line_speed = SPEED_2500;
1144 break;
1145 }
1146 if (val & MII_BNX2_GP_TOP_AN_FD)
1147 bp->duplex = DUPLEX_FULL;
1148 else
1149 bp->duplex = DUPLEX_HALF;
1150 return 0;
1151}
1152
1153static int
Michael Chan5b0c76a2005-11-04 08:45:49 -08001154bnx2_5708s_linkup(struct bnx2 *bp)
1155{
1156 u32 val;
1157
1158 bp->link_up = 1;
1159 bnx2_read_phy(bp, BCM5708S_1000X_STAT1, &val);
1160 switch (val & BCM5708S_1000X_STAT1_SPEED_MASK) {
1161 case BCM5708S_1000X_STAT1_SPEED_10:
1162 bp->line_speed = SPEED_10;
1163 break;
1164 case BCM5708S_1000X_STAT1_SPEED_100:
1165 bp->line_speed = SPEED_100;
1166 break;
1167 case BCM5708S_1000X_STAT1_SPEED_1G:
1168 bp->line_speed = SPEED_1000;
1169 break;
1170 case BCM5708S_1000X_STAT1_SPEED_2G5:
1171 bp->line_speed = SPEED_2500;
1172 break;
1173 }
1174 if (val & BCM5708S_1000X_STAT1_FD)
1175 bp->duplex = DUPLEX_FULL;
1176 else
1177 bp->duplex = DUPLEX_HALF;
1178
1179 return 0;
1180}
1181
1182static int
1183bnx2_5706s_linkup(struct bnx2 *bp)
Michael Chanb6016b72005-05-26 13:03:09 -07001184{
1185 u32 bmcr, local_adv, remote_adv, common;
1186
1187 bp->link_up = 1;
1188 bp->line_speed = SPEED_1000;
1189
Michael Chanca58c3a2007-05-03 13:22:52 -07001190 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chanb6016b72005-05-26 13:03:09 -07001191 if (bmcr & BMCR_FULLDPLX) {
1192 bp->duplex = DUPLEX_FULL;
1193 }
1194 else {
1195 bp->duplex = DUPLEX_HALF;
1196 }
1197
1198 if (!(bmcr & BMCR_ANENABLE)) {
1199 return 0;
1200 }
1201
Michael Chanca58c3a2007-05-03 13:22:52 -07001202 bnx2_read_phy(bp, bp->mii_adv, &local_adv);
1203 bnx2_read_phy(bp, bp->mii_lpa, &remote_adv);
Michael Chanb6016b72005-05-26 13:03:09 -07001204
1205 common = local_adv & remote_adv;
1206 if (common & (ADVERTISE_1000XHALF | ADVERTISE_1000XFULL)) {
1207
1208 if (common & ADVERTISE_1000XFULL) {
1209 bp->duplex = DUPLEX_FULL;
1210 }
1211 else {
1212 bp->duplex = DUPLEX_HALF;
1213 }
1214 }
1215
1216 return 0;
1217}
1218
1219static int
1220bnx2_copper_linkup(struct bnx2 *bp)
1221{
1222 u32 bmcr;
1223
Michael Chan4016bad2013-12-31 23:22:34 -08001224 bp->phy_flags &= ~BNX2_PHY_FLAG_MDIX;
1225
Michael Chanca58c3a2007-05-03 13:22:52 -07001226 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chanb6016b72005-05-26 13:03:09 -07001227 if (bmcr & BMCR_ANENABLE) {
1228 u32 local_adv, remote_adv, common;
1229
1230 bnx2_read_phy(bp, MII_CTRL1000, &local_adv);
1231 bnx2_read_phy(bp, MII_STAT1000, &remote_adv);
1232
1233 common = local_adv & (remote_adv >> 2);
1234 if (common & ADVERTISE_1000FULL) {
1235 bp->line_speed = SPEED_1000;
1236 bp->duplex = DUPLEX_FULL;
1237 }
1238 else if (common & ADVERTISE_1000HALF) {
1239 bp->line_speed = SPEED_1000;
1240 bp->duplex = DUPLEX_HALF;
1241 }
1242 else {
Michael Chanca58c3a2007-05-03 13:22:52 -07001243 bnx2_read_phy(bp, bp->mii_adv, &local_adv);
1244 bnx2_read_phy(bp, bp->mii_lpa, &remote_adv);
Michael Chanb6016b72005-05-26 13:03:09 -07001245
1246 common = local_adv & remote_adv;
1247 if (common & ADVERTISE_100FULL) {
1248 bp->line_speed = SPEED_100;
1249 bp->duplex = DUPLEX_FULL;
1250 }
1251 else if (common & ADVERTISE_100HALF) {
1252 bp->line_speed = SPEED_100;
1253 bp->duplex = DUPLEX_HALF;
1254 }
1255 else if (common & ADVERTISE_10FULL) {
1256 bp->line_speed = SPEED_10;
1257 bp->duplex = DUPLEX_FULL;
1258 }
1259 else if (common & ADVERTISE_10HALF) {
1260 bp->line_speed = SPEED_10;
1261 bp->duplex = DUPLEX_HALF;
1262 }
1263 else {
1264 bp->line_speed = 0;
1265 bp->link_up = 0;
1266 }
1267 }
1268 }
1269 else {
1270 if (bmcr & BMCR_SPEED100) {
1271 bp->line_speed = SPEED_100;
1272 }
1273 else {
1274 bp->line_speed = SPEED_10;
1275 }
1276 if (bmcr & BMCR_FULLDPLX) {
1277 bp->duplex = DUPLEX_FULL;
1278 }
1279 else {
1280 bp->duplex = DUPLEX_HALF;
1281 }
1282 }
1283
Michael Chan4016bad2013-12-31 23:22:34 -08001284 if (bp->link_up) {
1285 u32 ext_status;
1286
1287 bnx2_read_phy(bp, MII_BNX2_EXT_STATUS, &ext_status);
1288 if (ext_status & EXT_STATUS_MDIX)
1289 bp->phy_flags |= BNX2_PHY_FLAG_MDIX;
1290 }
1291
Michael Chanb6016b72005-05-26 13:03:09 -07001292 return 0;
1293}
1294
Michael Chan83e3fc82008-01-29 21:37:17 -08001295static void
Michael Chanbb4f98a2008-06-19 16:38:19 -07001296bnx2_init_rx_context(struct bnx2 *bp, u32 cid)
Michael Chan83e3fc82008-01-29 21:37:17 -08001297{
Michael Chanbb4f98a2008-06-19 16:38:19 -07001298 u32 val, rx_cid_addr = GET_CID_ADDR(cid);
Michael Chan83e3fc82008-01-29 21:37:17 -08001299
1300 val = BNX2_L2CTX_CTX_TYPE_CTX_BD_CHN_TYPE_VALUE;
1301 val |= BNX2_L2CTX_CTX_TYPE_SIZE_L2;
1302 val |= 0x02 << 8;
1303
Michael Chan22fa1592010-10-11 16:12:00 -07001304 if (bp->flow_ctrl & FLOW_CTRL_TX)
1305 val |= BNX2_L2CTX_FLOW_CTRL_ENABLE;
Michael Chan83e3fc82008-01-29 21:37:17 -08001306
Michael Chan83e3fc82008-01-29 21:37:17 -08001307 bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_CTX_TYPE, val);
1308}
1309
Michael Chanbb4f98a2008-06-19 16:38:19 -07001310static void
1311bnx2_init_all_rx_contexts(struct bnx2 *bp)
1312{
1313 int i;
1314 u32 cid;
1315
1316 for (i = 0, cid = RX_CID; i < bp->num_rx_rings; i++, cid++) {
1317 if (i == 1)
1318 cid = RX_RSS_CID;
1319 bnx2_init_rx_context(bp, cid);
1320 }
1321}
1322
Benjamin Li344478d2008-09-18 16:38:24 -07001323static void
Michael Chanb6016b72005-05-26 13:03:09 -07001324bnx2_set_mac_link(struct bnx2 *bp)
1325{
1326 u32 val;
1327
Michael Chane503e062012-12-06 10:33:08 +00001328 BNX2_WR(bp, BNX2_EMAC_TX_LENGTHS, 0x2620);
Michael Chanb6016b72005-05-26 13:03:09 -07001329 if (bp->link_up && (bp->line_speed == SPEED_1000) &&
1330 (bp->duplex == DUPLEX_HALF)) {
Michael Chane503e062012-12-06 10:33:08 +00001331 BNX2_WR(bp, BNX2_EMAC_TX_LENGTHS, 0x26ff);
Michael Chanb6016b72005-05-26 13:03:09 -07001332 }
1333
1334 /* Configure the EMAC mode register. */
Michael Chane503e062012-12-06 10:33:08 +00001335 val = BNX2_RD(bp, BNX2_EMAC_MODE);
Michael Chanb6016b72005-05-26 13:03:09 -07001336
1337 val &= ~(BNX2_EMAC_MODE_PORT | BNX2_EMAC_MODE_HALF_DUPLEX |
Michael Chan5b0c76a2005-11-04 08:45:49 -08001338 BNX2_EMAC_MODE_MAC_LOOP | BNX2_EMAC_MODE_FORCE_LINK |
Michael Chan59b47d82006-11-19 14:10:45 -08001339 BNX2_EMAC_MODE_25G_MODE);
Michael Chanb6016b72005-05-26 13:03:09 -07001340
1341 if (bp->link_up) {
Michael Chan5b0c76a2005-11-04 08:45:49 -08001342 switch (bp->line_speed) {
1343 case SPEED_10:
Michael Chan4ce45e02012-12-06 10:33:10 +00001344 if (BNX2_CHIP(bp) != BNX2_CHIP_5706) {
Michael Chan59b47d82006-11-19 14:10:45 -08001345 val |= BNX2_EMAC_MODE_PORT_MII_10M;
Michael Chan5b0c76a2005-11-04 08:45:49 -08001346 break;
1347 }
1348 /* fall through */
1349 case SPEED_100:
1350 val |= BNX2_EMAC_MODE_PORT_MII;
1351 break;
1352 case SPEED_2500:
Michael Chan59b47d82006-11-19 14:10:45 -08001353 val |= BNX2_EMAC_MODE_25G_MODE;
Michael Chan5b0c76a2005-11-04 08:45:49 -08001354 /* fall through */
1355 case SPEED_1000:
1356 val |= BNX2_EMAC_MODE_PORT_GMII;
1357 break;
1358 }
Michael Chanb6016b72005-05-26 13:03:09 -07001359 }
1360 else {
1361 val |= BNX2_EMAC_MODE_PORT_GMII;
1362 }
1363
1364 /* Set the MAC to operate in the appropriate duplex mode. */
1365 if (bp->duplex == DUPLEX_HALF)
1366 val |= BNX2_EMAC_MODE_HALF_DUPLEX;
Michael Chane503e062012-12-06 10:33:08 +00001367 BNX2_WR(bp, BNX2_EMAC_MODE, val);
Michael Chanb6016b72005-05-26 13:03:09 -07001368
1369 /* Enable/disable rx PAUSE. */
1370 bp->rx_mode &= ~BNX2_EMAC_RX_MODE_FLOW_EN;
1371
1372 if (bp->flow_ctrl & FLOW_CTRL_RX)
1373 bp->rx_mode |= BNX2_EMAC_RX_MODE_FLOW_EN;
Michael Chane503e062012-12-06 10:33:08 +00001374 BNX2_WR(bp, BNX2_EMAC_RX_MODE, bp->rx_mode);
Michael Chanb6016b72005-05-26 13:03:09 -07001375
1376 /* Enable/disable tx PAUSE. */
Michael Chane503e062012-12-06 10:33:08 +00001377 val = BNX2_RD(bp, BNX2_EMAC_TX_MODE);
Michael Chanb6016b72005-05-26 13:03:09 -07001378 val &= ~BNX2_EMAC_TX_MODE_FLOW_EN;
1379
1380 if (bp->flow_ctrl & FLOW_CTRL_TX)
1381 val |= BNX2_EMAC_TX_MODE_FLOW_EN;
Michael Chane503e062012-12-06 10:33:08 +00001382 BNX2_WR(bp, BNX2_EMAC_TX_MODE, val);
Michael Chanb6016b72005-05-26 13:03:09 -07001383
1384 /* Acknowledge the interrupt. */
Michael Chane503e062012-12-06 10:33:08 +00001385 BNX2_WR(bp, BNX2_EMAC_STATUS, BNX2_EMAC_STATUS_LINK_CHANGE);
Michael Chanb6016b72005-05-26 13:03:09 -07001386
Michael Chan22fa1592010-10-11 16:12:00 -07001387 bnx2_init_all_rx_contexts(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07001388}
1389
Michael Chan27a005b2007-05-03 13:23:41 -07001390static void
1391bnx2_enable_bmsr1(struct bnx2 *bp)
1392{
Michael Chan583c28e2008-01-21 19:51:35 -08001393 if ((bp->phy_flags & BNX2_PHY_FLAG_SERDES) &&
Michael Chan4ce45e02012-12-06 10:33:10 +00001394 (BNX2_CHIP(bp) == BNX2_CHIP_5709))
Michael Chan27a005b2007-05-03 13:23:41 -07001395 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
1396 MII_BNX2_BLK_ADDR_GP_STATUS);
1397}
1398
1399static void
1400bnx2_disable_bmsr1(struct bnx2 *bp)
1401{
Michael Chan583c28e2008-01-21 19:51:35 -08001402 if ((bp->phy_flags & BNX2_PHY_FLAG_SERDES) &&
Michael Chan4ce45e02012-12-06 10:33:10 +00001403 (BNX2_CHIP(bp) == BNX2_CHIP_5709))
Michael Chan27a005b2007-05-03 13:23:41 -07001404 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
1405 MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
1406}
1407
Michael Chanb6016b72005-05-26 13:03:09 -07001408static int
Michael Chan605a9e22007-05-03 13:23:13 -07001409bnx2_test_and_enable_2g5(struct bnx2 *bp)
1410{
1411 u32 up1;
1412 int ret = 1;
1413
Michael Chan583c28e2008-01-21 19:51:35 -08001414 if (!(bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE))
Michael Chan605a9e22007-05-03 13:23:13 -07001415 return 0;
1416
1417 if (bp->autoneg & AUTONEG_SPEED)
1418 bp->advertising |= ADVERTISED_2500baseX_Full;
1419
Michael Chan4ce45e02012-12-06 10:33:10 +00001420 if (BNX2_CHIP(bp) == BNX2_CHIP_5709)
Michael Chan27a005b2007-05-03 13:23:41 -07001421 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_OVER1G);
1422
Michael Chan605a9e22007-05-03 13:23:13 -07001423 bnx2_read_phy(bp, bp->mii_up1, &up1);
1424 if (!(up1 & BCM5708S_UP1_2G5)) {
1425 up1 |= BCM5708S_UP1_2G5;
1426 bnx2_write_phy(bp, bp->mii_up1, up1);
1427 ret = 0;
1428 }
1429
Michael Chan4ce45e02012-12-06 10:33:10 +00001430 if (BNX2_CHIP(bp) == BNX2_CHIP_5709)
Michael Chan27a005b2007-05-03 13:23:41 -07001431 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
1432 MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
1433
Michael Chan605a9e22007-05-03 13:23:13 -07001434 return ret;
1435}
1436
1437static int
1438bnx2_test_and_disable_2g5(struct bnx2 *bp)
1439{
1440 u32 up1;
1441 int ret = 0;
1442
Michael Chan583c28e2008-01-21 19:51:35 -08001443 if (!(bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE))
Michael Chan605a9e22007-05-03 13:23:13 -07001444 return 0;
1445
Michael Chan4ce45e02012-12-06 10:33:10 +00001446 if (BNX2_CHIP(bp) == BNX2_CHIP_5709)
Michael Chan27a005b2007-05-03 13:23:41 -07001447 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_OVER1G);
1448
Michael Chan605a9e22007-05-03 13:23:13 -07001449 bnx2_read_phy(bp, bp->mii_up1, &up1);
1450 if (up1 & BCM5708S_UP1_2G5) {
1451 up1 &= ~BCM5708S_UP1_2G5;
1452 bnx2_write_phy(bp, bp->mii_up1, up1);
1453 ret = 1;
1454 }
1455
Michael Chan4ce45e02012-12-06 10:33:10 +00001456 if (BNX2_CHIP(bp) == BNX2_CHIP_5709)
Michael Chan27a005b2007-05-03 13:23:41 -07001457 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
1458 MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
1459
Michael Chan605a9e22007-05-03 13:23:13 -07001460 return ret;
1461}
1462
1463static void
1464bnx2_enable_forced_2g5(struct bnx2 *bp)
1465{
Michael Chancbd68902010-06-08 07:21:30 +00001466 u32 uninitialized_var(bmcr);
1467 int err;
Michael Chan605a9e22007-05-03 13:23:13 -07001468
Michael Chan583c28e2008-01-21 19:51:35 -08001469 if (!(bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE))
Michael Chan605a9e22007-05-03 13:23:13 -07001470 return;
1471
Michael Chan4ce45e02012-12-06 10:33:10 +00001472 if (BNX2_CHIP(bp) == BNX2_CHIP_5709) {
Michael Chan27a005b2007-05-03 13:23:41 -07001473 u32 val;
1474
1475 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
1476 MII_BNX2_BLK_ADDR_SERDES_DIG);
Michael Chancbd68902010-06-08 07:21:30 +00001477 if (!bnx2_read_phy(bp, MII_BNX2_SERDES_DIG_MISC1, &val)) {
1478 val &= ~MII_BNX2_SD_MISC1_FORCE_MSK;
1479 val |= MII_BNX2_SD_MISC1_FORCE |
1480 MII_BNX2_SD_MISC1_FORCE_2_5G;
1481 bnx2_write_phy(bp, MII_BNX2_SERDES_DIG_MISC1, val);
1482 }
Michael Chan27a005b2007-05-03 13:23:41 -07001483
1484 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
1485 MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
Michael Chancbd68902010-06-08 07:21:30 +00001486 err = bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chan27a005b2007-05-03 13:23:41 -07001487
Michael Chan4ce45e02012-12-06 10:33:10 +00001488 } else if (BNX2_CHIP(bp) == BNX2_CHIP_5708) {
Michael Chancbd68902010-06-08 07:21:30 +00001489 err = bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
1490 if (!err)
1491 bmcr |= BCM5708S_BMCR_FORCE_2500;
Eric Dumazetc7079852009-11-02 23:17:42 +00001492 } else {
1493 return;
Michael Chan605a9e22007-05-03 13:23:13 -07001494 }
1495
Michael Chancbd68902010-06-08 07:21:30 +00001496 if (err)
1497 return;
1498
Michael Chan605a9e22007-05-03 13:23:13 -07001499 if (bp->autoneg & AUTONEG_SPEED) {
1500 bmcr &= ~BMCR_ANENABLE;
1501 if (bp->req_duplex == DUPLEX_FULL)
1502 bmcr |= BMCR_FULLDPLX;
1503 }
1504 bnx2_write_phy(bp, bp->mii_bmcr, bmcr);
1505}
1506
1507static void
1508bnx2_disable_forced_2g5(struct bnx2 *bp)
1509{
Michael Chancbd68902010-06-08 07:21:30 +00001510 u32 uninitialized_var(bmcr);
1511 int err;
Michael Chan605a9e22007-05-03 13:23:13 -07001512
Michael Chan583c28e2008-01-21 19:51:35 -08001513 if (!(bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE))
Michael Chan605a9e22007-05-03 13:23:13 -07001514 return;
1515
Michael Chan4ce45e02012-12-06 10:33:10 +00001516 if (BNX2_CHIP(bp) == BNX2_CHIP_5709) {
Michael Chan27a005b2007-05-03 13:23:41 -07001517 u32 val;
1518
1519 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
1520 MII_BNX2_BLK_ADDR_SERDES_DIG);
Michael Chancbd68902010-06-08 07:21:30 +00001521 if (!bnx2_read_phy(bp, MII_BNX2_SERDES_DIG_MISC1, &val)) {
1522 val &= ~MII_BNX2_SD_MISC1_FORCE;
1523 bnx2_write_phy(bp, MII_BNX2_SERDES_DIG_MISC1, val);
1524 }
Michael Chan27a005b2007-05-03 13:23:41 -07001525
1526 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
1527 MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
Michael Chancbd68902010-06-08 07:21:30 +00001528 err = bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chan27a005b2007-05-03 13:23:41 -07001529
Michael Chan4ce45e02012-12-06 10:33:10 +00001530 } else if (BNX2_CHIP(bp) == BNX2_CHIP_5708) {
Michael Chancbd68902010-06-08 07:21:30 +00001531 err = bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
1532 if (!err)
1533 bmcr &= ~BCM5708S_BMCR_FORCE_2500;
Eric Dumazetc7079852009-11-02 23:17:42 +00001534 } else {
1535 return;
Michael Chan605a9e22007-05-03 13:23:13 -07001536 }
1537
Michael Chancbd68902010-06-08 07:21:30 +00001538 if (err)
1539 return;
1540
Michael Chan605a9e22007-05-03 13:23:13 -07001541 if (bp->autoneg & AUTONEG_SPEED)
1542 bmcr |= BMCR_SPEED1000 | BMCR_ANENABLE | BMCR_ANRESTART;
1543 bnx2_write_phy(bp, bp->mii_bmcr, bmcr);
1544}
1545
Michael Chanb2fadea2008-01-21 17:07:06 -08001546static void
1547bnx2_5706s_force_link_dn(struct bnx2 *bp, int start)
1548{
1549 u32 val;
1550
1551 bnx2_write_phy(bp, MII_BNX2_DSP_ADDRESS, MII_EXPAND_SERDES_CTL);
1552 bnx2_read_phy(bp, MII_BNX2_DSP_RW_PORT, &val);
1553 if (start)
1554 bnx2_write_phy(bp, MII_BNX2_DSP_RW_PORT, val & 0xff0f);
1555 else
1556 bnx2_write_phy(bp, MII_BNX2_DSP_RW_PORT, val | 0xc0);
1557}
1558
Michael Chan605a9e22007-05-03 13:23:13 -07001559static int
Michael Chanb6016b72005-05-26 13:03:09 -07001560bnx2_set_link(struct bnx2 *bp)
1561{
1562 u32 bmsr;
1563 u8 link_up;
1564
Michael Chan80be4432006-11-19 14:07:28 -08001565 if (bp->loopback == MAC_LOOPBACK || bp->loopback == PHY_LOOPBACK) {
Michael Chanb6016b72005-05-26 13:03:09 -07001566 bp->link_up = 1;
1567 return 0;
1568 }
1569
Michael Chan583c28e2008-01-21 19:51:35 -08001570 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
Michael Chan0d8a6572007-07-07 22:49:43 -07001571 return 0;
1572
Michael Chanb6016b72005-05-26 13:03:09 -07001573 link_up = bp->link_up;
1574
Michael Chan27a005b2007-05-03 13:23:41 -07001575 bnx2_enable_bmsr1(bp);
1576 bnx2_read_phy(bp, bp->mii_bmsr1, &bmsr);
1577 bnx2_read_phy(bp, bp->mii_bmsr1, &bmsr);
1578 bnx2_disable_bmsr1(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07001579
Michael Chan583c28e2008-01-21 19:51:35 -08001580 if ((bp->phy_flags & BNX2_PHY_FLAG_SERDES) &&
Michael Chan4ce45e02012-12-06 10:33:10 +00001581 (BNX2_CHIP(bp) == BNX2_CHIP_5706)) {
Michael Chana2724e22008-02-23 19:47:44 -08001582 u32 val, an_dbg;
Michael Chanb6016b72005-05-26 13:03:09 -07001583
Michael Chan583c28e2008-01-21 19:51:35 -08001584 if (bp->phy_flags & BNX2_PHY_FLAG_FORCED_DOWN) {
Michael Chanb2fadea2008-01-21 17:07:06 -08001585 bnx2_5706s_force_link_dn(bp, 0);
Michael Chan583c28e2008-01-21 19:51:35 -08001586 bp->phy_flags &= ~BNX2_PHY_FLAG_FORCED_DOWN;
Michael Chanb2fadea2008-01-21 17:07:06 -08001587 }
Michael Chane503e062012-12-06 10:33:08 +00001588 val = BNX2_RD(bp, BNX2_EMAC_STATUS);
Michael Chana2724e22008-02-23 19:47:44 -08001589
1590 bnx2_write_phy(bp, MII_BNX2_MISC_SHADOW, MISC_SHDW_AN_DBG);
1591 bnx2_read_phy(bp, MII_BNX2_MISC_SHADOW, &an_dbg);
1592 bnx2_read_phy(bp, MII_BNX2_MISC_SHADOW, &an_dbg);
1593
1594 if ((val & BNX2_EMAC_STATUS_LINK) &&
1595 !(an_dbg & MISC_SHDW_AN_DBG_NOSYNC))
Michael Chanb6016b72005-05-26 13:03:09 -07001596 bmsr |= BMSR_LSTATUS;
1597 else
1598 bmsr &= ~BMSR_LSTATUS;
1599 }
1600
1601 if (bmsr & BMSR_LSTATUS) {
1602 bp->link_up = 1;
1603
Michael Chan583c28e2008-01-21 19:51:35 -08001604 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Michael Chan4ce45e02012-12-06 10:33:10 +00001605 if (BNX2_CHIP(bp) == BNX2_CHIP_5706)
Michael Chan5b0c76a2005-11-04 08:45:49 -08001606 bnx2_5706s_linkup(bp);
Michael Chan4ce45e02012-12-06 10:33:10 +00001607 else if (BNX2_CHIP(bp) == BNX2_CHIP_5708)
Michael Chan5b0c76a2005-11-04 08:45:49 -08001608 bnx2_5708s_linkup(bp);
Michael Chan4ce45e02012-12-06 10:33:10 +00001609 else if (BNX2_CHIP(bp) == BNX2_CHIP_5709)
Michael Chan27a005b2007-05-03 13:23:41 -07001610 bnx2_5709s_linkup(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07001611 }
1612 else {
1613 bnx2_copper_linkup(bp);
1614 }
1615 bnx2_resolve_flow_ctrl(bp);
1616 }
1617 else {
Michael Chan583c28e2008-01-21 19:51:35 -08001618 if ((bp->phy_flags & BNX2_PHY_FLAG_SERDES) &&
Michael Chan605a9e22007-05-03 13:23:13 -07001619 (bp->autoneg & AUTONEG_SPEED))
1620 bnx2_disable_forced_2g5(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07001621
Michael Chan583c28e2008-01-21 19:51:35 -08001622 if (bp->phy_flags & BNX2_PHY_FLAG_PARALLEL_DETECT) {
Michael Chanb2fadea2008-01-21 17:07:06 -08001623 u32 bmcr;
1624
1625 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
1626 bmcr |= BMCR_ANENABLE;
1627 bnx2_write_phy(bp, bp->mii_bmcr, bmcr);
1628
Michael Chan583c28e2008-01-21 19:51:35 -08001629 bp->phy_flags &= ~BNX2_PHY_FLAG_PARALLEL_DETECT;
Michael Chanb2fadea2008-01-21 17:07:06 -08001630 }
Michael Chanb6016b72005-05-26 13:03:09 -07001631 bp->link_up = 0;
1632 }
1633
1634 if (bp->link_up != link_up) {
1635 bnx2_report_link(bp);
1636 }
1637
1638 bnx2_set_mac_link(bp);
1639
1640 return 0;
1641}
1642
1643static int
1644bnx2_reset_phy(struct bnx2 *bp)
1645{
1646 int i;
1647 u32 reg;
1648
Michael Chanca58c3a2007-05-03 13:22:52 -07001649 bnx2_write_phy(bp, bp->mii_bmcr, BMCR_RESET);
Michael Chanb6016b72005-05-26 13:03:09 -07001650
1651#define PHY_RESET_MAX_WAIT 100
1652 for (i = 0; i < PHY_RESET_MAX_WAIT; i++) {
1653 udelay(10);
1654
Michael Chanca58c3a2007-05-03 13:22:52 -07001655 bnx2_read_phy(bp, bp->mii_bmcr, &reg);
Michael Chanb6016b72005-05-26 13:03:09 -07001656 if (!(reg & BMCR_RESET)) {
1657 udelay(20);
1658 break;
1659 }
1660 }
1661 if (i == PHY_RESET_MAX_WAIT) {
1662 return -EBUSY;
1663 }
1664 return 0;
1665}
1666
1667static u32
1668bnx2_phy_get_pause_adv(struct bnx2 *bp)
1669{
1670 u32 adv = 0;
1671
1672 if ((bp->req_flow_ctrl & (FLOW_CTRL_RX | FLOW_CTRL_TX)) ==
1673 (FLOW_CTRL_RX | FLOW_CTRL_TX)) {
1674
Michael Chan583c28e2008-01-21 19:51:35 -08001675 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Michael Chanb6016b72005-05-26 13:03:09 -07001676 adv = ADVERTISE_1000XPAUSE;
1677 }
1678 else {
1679 adv = ADVERTISE_PAUSE_CAP;
1680 }
1681 }
1682 else if (bp->req_flow_ctrl & FLOW_CTRL_TX) {
Michael Chan583c28e2008-01-21 19:51:35 -08001683 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Michael Chanb6016b72005-05-26 13:03:09 -07001684 adv = ADVERTISE_1000XPSE_ASYM;
1685 }
1686 else {
1687 adv = ADVERTISE_PAUSE_ASYM;
1688 }
1689 }
1690 else if (bp->req_flow_ctrl & FLOW_CTRL_RX) {
Michael Chan583c28e2008-01-21 19:51:35 -08001691 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Michael Chanb6016b72005-05-26 13:03:09 -07001692 adv = ADVERTISE_1000XPAUSE | ADVERTISE_1000XPSE_ASYM;
1693 }
1694 else {
1695 adv = ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM;
1696 }
1697 }
1698 return adv;
1699}
1700
Michael Chana2f13892008-07-14 22:38:23 -07001701static int bnx2_fw_sync(struct bnx2 *, u32, int, int);
Michael Chan0d8a6572007-07-07 22:49:43 -07001702
Michael Chanb6016b72005-05-26 13:03:09 -07001703static int
Michael Chan0d8a6572007-07-07 22:49:43 -07001704bnx2_setup_remote_phy(struct bnx2 *bp, u8 port)
Harvey Harrison52d07b12009-01-19 17:27:06 -08001705__releases(&bp->phy_lock)
1706__acquires(&bp->phy_lock)
Michael Chan0d8a6572007-07-07 22:49:43 -07001707{
1708 u32 speed_arg = 0, pause_adv;
1709
1710 pause_adv = bnx2_phy_get_pause_adv(bp);
1711
1712 if (bp->autoneg & AUTONEG_SPEED) {
1713 speed_arg |= BNX2_NETLINK_SET_LINK_ENABLE_AUTONEG;
1714 if (bp->advertising & ADVERTISED_10baseT_Half)
1715 speed_arg |= BNX2_NETLINK_SET_LINK_SPEED_10HALF;
1716 if (bp->advertising & ADVERTISED_10baseT_Full)
1717 speed_arg |= BNX2_NETLINK_SET_LINK_SPEED_10FULL;
1718 if (bp->advertising & ADVERTISED_100baseT_Half)
1719 speed_arg |= BNX2_NETLINK_SET_LINK_SPEED_100HALF;
1720 if (bp->advertising & ADVERTISED_100baseT_Full)
1721 speed_arg |= BNX2_NETLINK_SET_LINK_SPEED_100FULL;
1722 if (bp->advertising & ADVERTISED_1000baseT_Full)
1723 speed_arg |= BNX2_NETLINK_SET_LINK_SPEED_1GFULL;
1724 if (bp->advertising & ADVERTISED_2500baseX_Full)
1725 speed_arg |= BNX2_NETLINK_SET_LINK_SPEED_2G5FULL;
1726 } else {
1727 if (bp->req_line_speed == SPEED_2500)
1728 speed_arg = BNX2_NETLINK_SET_LINK_SPEED_2G5FULL;
1729 else if (bp->req_line_speed == SPEED_1000)
1730 speed_arg = BNX2_NETLINK_SET_LINK_SPEED_1GFULL;
1731 else if (bp->req_line_speed == SPEED_100) {
1732 if (bp->req_duplex == DUPLEX_FULL)
1733 speed_arg = BNX2_NETLINK_SET_LINK_SPEED_100FULL;
1734 else
1735 speed_arg = BNX2_NETLINK_SET_LINK_SPEED_100HALF;
1736 } else if (bp->req_line_speed == SPEED_10) {
1737 if (bp->req_duplex == DUPLEX_FULL)
1738 speed_arg = BNX2_NETLINK_SET_LINK_SPEED_10FULL;
1739 else
1740 speed_arg = BNX2_NETLINK_SET_LINK_SPEED_10HALF;
1741 }
1742 }
1743
1744 if (pause_adv & (ADVERTISE_1000XPAUSE | ADVERTISE_PAUSE_CAP))
1745 speed_arg |= BNX2_NETLINK_SET_LINK_FC_SYM_PAUSE;
Michael Chanc26736e2008-01-31 17:07:21 -08001746 if (pause_adv & (ADVERTISE_1000XPSE_ASYM | ADVERTISE_PAUSE_ASYM))
Michael Chan0d8a6572007-07-07 22:49:43 -07001747 speed_arg |= BNX2_NETLINK_SET_LINK_FC_ASYM_PAUSE;
1748
1749 if (port == PORT_TP)
1750 speed_arg |= BNX2_NETLINK_SET_LINK_PHY_APP_REMOTE |
1751 BNX2_NETLINK_SET_LINK_ETH_AT_WIRESPEED;
1752
Michael Chan2726d6e2008-01-29 21:35:05 -08001753 bnx2_shmem_wr(bp, BNX2_DRV_MB_ARG0, speed_arg);
Michael Chan0d8a6572007-07-07 22:49:43 -07001754
1755 spin_unlock_bh(&bp->phy_lock);
Michael Chana2f13892008-07-14 22:38:23 -07001756 bnx2_fw_sync(bp, BNX2_DRV_MSG_CODE_CMD_SET_LINK, 1, 0);
Michael Chan0d8a6572007-07-07 22:49:43 -07001757 spin_lock_bh(&bp->phy_lock);
1758
1759 return 0;
1760}
1761
1762static int
1763bnx2_setup_serdes_phy(struct bnx2 *bp, u8 port)
Harvey Harrison52d07b12009-01-19 17:27:06 -08001764__releases(&bp->phy_lock)
1765__acquires(&bp->phy_lock)
Michael Chanb6016b72005-05-26 13:03:09 -07001766{
Michael Chan605a9e22007-05-03 13:23:13 -07001767 u32 adv, bmcr;
Michael Chanb6016b72005-05-26 13:03:09 -07001768 u32 new_adv = 0;
1769
Michael Chan583c28e2008-01-21 19:51:35 -08001770 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
Eric Dumazet807540b2010-09-23 05:40:09 +00001771 return bnx2_setup_remote_phy(bp, port);
Michael Chan0d8a6572007-07-07 22:49:43 -07001772
Michael Chanb6016b72005-05-26 13:03:09 -07001773 if (!(bp->autoneg & AUTONEG_SPEED)) {
1774 u32 new_bmcr;
Michael Chan5b0c76a2005-11-04 08:45:49 -08001775 int force_link_down = 0;
1776
Michael Chan605a9e22007-05-03 13:23:13 -07001777 if (bp->req_line_speed == SPEED_2500) {
1778 if (!bnx2_test_and_enable_2g5(bp))
1779 force_link_down = 1;
1780 } else if (bp->req_line_speed == SPEED_1000) {
1781 if (bnx2_test_and_disable_2g5(bp))
1782 force_link_down = 1;
1783 }
Michael Chanca58c3a2007-05-03 13:22:52 -07001784 bnx2_read_phy(bp, bp->mii_adv, &adv);
Michael Chan80be4432006-11-19 14:07:28 -08001785 adv &= ~(ADVERTISE_1000XFULL | ADVERTISE_1000XHALF);
1786
Michael Chanca58c3a2007-05-03 13:22:52 -07001787 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chan605a9e22007-05-03 13:23:13 -07001788 new_bmcr = bmcr & ~BMCR_ANENABLE;
Michael Chan80be4432006-11-19 14:07:28 -08001789 new_bmcr |= BMCR_SPEED1000;
Michael Chan605a9e22007-05-03 13:23:13 -07001790
Michael Chan4ce45e02012-12-06 10:33:10 +00001791 if (BNX2_CHIP(bp) == BNX2_CHIP_5709) {
Michael Chan27a005b2007-05-03 13:23:41 -07001792 if (bp->req_line_speed == SPEED_2500)
1793 bnx2_enable_forced_2g5(bp);
1794 else if (bp->req_line_speed == SPEED_1000) {
1795 bnx2_disable_forced_2g5(bp);
1796 new_bmcr &= ~0x2000;
1797 }
1798
Michael Chan4ce45e02012-12-06 10:33:10 +00001799 } else if (BNX2_CHIP(bp) == BNX2_CHIP_5708) {
Michael Chan605a9e22007-05-03 13:23:13 -07001800 if (bp->req_line_speed == SPEED_2500)
1801 new_bmcr |= BCM5708S_BMCR_FORCE_2500;
1802 else
1803 new_bmcr = bmcr & ~BCM5708S_BMCR_FORCE_2500;
Michael Chan5b0c76a2005-11-04 08:45:49 -08001804 }
1805
Michael Chanb6016b72005-05-26 13:03:09 -07001806 if (bp->req_duplex == DUPLEX_FULL) {
Michael Chan5b0c76a2005-11-04 08:45:49 -08001807 adv |= ADVERTISE_1000XFULL;
Michael Chanb6016b72005-05-26 13:03:09 -07001808 new_bmcr |= BMCR_FULLDPLX;
1809 }
1810 else {
Michael Chan5b0c76a2005-11-04 08:45:49 -08001811 adv |= ADVERTISE_1000XHALF;
Michael Chanb6016b72005-05-26 13:03:09 -07001812 new_bmcr &= ~BMCR_FULLDPLX;
1813 }
Michael Chan5b0c76a2005-11-04 08:45:49 -08001814 if ((new_bmcr != bmcr) || (force_link_down)) {
Michael Chanb6016b72005-05-26 13:03:09 -07001815 /* 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_adv, adv &
Michael Chan5b0c76a2005-11-04 08:45:49 -08001818 ~(ADVERTISE_1000XFULL |
1819 ADVERTISE_1000XHALF));
Michael Chanca58c3a2007-05-03 13:22:52 -07001820 bnx2_write_phy(bp, bp->mii_bmcr, bmcr |
Michael Chanb6016b72005-05-26 13:03:09 -07001821 BMCR_ANRESTART | BMCR_ANENABLE);
1822
1823 bp->link_up = 0;
1824 netif_carrier_off(bp->dev);
Michael Chanca58c3a2007-05-03 13:22:52 -07001825 bnx2_write_phy(bp, bp->mii_bmcr, new_bmcr);
Michael Chan80be4432006-11-19 14:07:28 -08001826 bnx2_report_link(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07001827 }
Michael Chanca58c3a2007-05-03 13:22:52 -07001828 bnx2_write_phy(bp, bp->mii_adv, adv);
1829 bnx2_write_phy(bp, bp->mii_bmcr, new_bmcr);
Michael Chan605a9e22007-05-03 13:23:13 -07001830 } else {
1831 bnx2_resolve_flow_ctrl(bp);
1832 bnx2_set_mac_link(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07001833 }
1834 return 0;
1835 }
1836
Michael Chan605a9e22007-05-03 13:23:13 -07001837 bnx2_test_and_enable_2g5(bp);
Michael Chan5b0c76a2005-11-04 08:45:49 -08001838
Michael Chanb6016b72005-05-26 13:03:09 -07001839 if (bp->advertising & ADVERTISED_1000baseT_Full)
1840 new_adv |= ADVERTISE_1000XFULL;
1841
1842 new_adv |= bnx2_phy_get_pause_adv(bp);
1843
Michael Chanca58c3a2007-05-03 13:22:52 -07001844 bnx2_read_phy(bp, bp->mii_adv, &adv);
1845 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chanb6016b72005-05-26 13:03:09 -07001846
1847 bp->serdes_an_pending = 0;
1848 if ((adv != new_adv) || ((bmcr & BMCR_ANENABLE) == 0)) {
1849 /* Force a link down visible on the other side */
1850 if (bp->link_up) {
Michael Chanca58c3a2007-05-03 13:22:52 -07001851 bnx2_write_phy(bp, bp->mii_bmcr, BMCR_LOOPBACK);
Michael Chan80be4432006-11-19 14:07:28 -08001852 spin_unlock_bh(&bp->phy_lock);
1853 msleep(20);
1854 spin_lock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07001855 }
1856
Michael Chanca58c3a2007-05-03 13:22:52 -07001857 bnx2_write_phy(bp, bp->mii_adv, new_adv);
1858 bnx2_write_phy(bp, bp->mii_bmcr, bmcr | BMCR_ANRESTART |
Michael Chanb6016b72005-05-26 13:03:09 -07001859 BMCR_ANENABLE);
Michael Chanf8dd0642006-11-19 14:08:29 -08001860 /* Speed up link-up time when the link partner
1861 * does not autonegotiate which is very common
1862 * in blade servers. Some blade servers use
1863 * IPMI for kerboard input and it's important
1864 * to minimize link disruptions. Autoneg. involves
1865 * exchanging base pages plus 3 next pages and
1866 * normally completes in about 120 msec.
1867 */
Michael Chan40105c02008-11-12 16:02:45 -08001868 bp->current_interval = BNX2_SERDES_AN_TIMEOUT;
Michael Chanf8dd0642006-11-19 14:08:29 -08001869 bp->serdes_an_pending = 1;
1870 mod_timer(&bp->timer, jiffies + bp->current_interval);
Michael Chan605a9e22007-05-03 13:23:13 -07001871 } else {
1872 bnx2_resolve_flow_ctrl(bp);
1873 bnx2_set_mac_link(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07001874 }
1875
1876 return 0;
1877}
1878
1879#define ETHTOOL_ALL_FIBRE_SPEED \
Michael Chan583c28e2008-01-21 19:51:35 -08001880 (bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE) ? \
Michael Chandeaf3912007-07-07 22:48:00 -07001881 (ADVERTISED_2500baseX_Full | ADVERTISED_1000baseT_Full) :\
1882 (ADVERTISED_1000baseT_Full)
Michael Chanb6016b72005-05-26 13:03:09 -07001883
1884#define ETHTOOL_ALL_COPPER_SPEED \
1885 (ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full | \
1886 ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full | \
1887 ADVERTISED_1000baseT_Full)
1888
1889#define PHY_ALL_10_100_SPEED (ADVERTISE_10HALF | ADVERTISE_10FULL | \
1890 ADVERTISE_100HALF | ADVERTISE_100FULL | ADVERTISE_CSMA)
Jeff Garzik6aa20a22006-09-13 13:24:59 -04001891
Michael Chanb6016b72005-05-26 13:03:09 -07001892#define PHY_ALL_1000_SPEED (ADVERTISE_1000HALF | ADVERTISE_1000FULL)
1893
Michael Chandeaf3912007-07-07 22:48:00 -07001894static void
Michael Chan0d8a6572007-07-07 22:49:43 -07001895bnx2_set_default_remote_link(struct bnx2 *bp)
1896{
1897 u32 link;
1898
1899 if (bp->phy_port == PORT_TP)
Michael Chan2726d6e2008-01-29 21:35:05 -08001900 link = bnx2_shmem_rd(bp, BNX2_RPHY_COPPER_LINK);
Michael Chan0d8a6572007-07-07 22:49:43 -07001901 else
Michael Chan2726d6e2008-01-29 21:35:05 -08001902 link = bnx2_shmem_rd(bp, BNX2_RPHY_SERDES_LINK);
Michael Chan0d8a6572007-07-07 22:49:43 -07001903
1904 if (link & BNX2_NETLINK_SET_LINK_ENABLE_AUTONEG) {
1905 bp->req_line_speed = 0;
1906 bp->autoneg |= AUTONEG_SPEED;
1907 bp->advertising = ADVERTISED_Autoneg;
1908 if (link & BNX2_NETLINK_SET_LINK_SPEED_10HALF)
1909 bp->advertising |= ADVERTISED_10baseT_Half;
1910 if (link & BNX2_NETLINK_SET_LINK_SPEED_10FULL)
1911 bp->advertising |= ADVERTISED_10baseT_Full;
1912 if (link & BNX2_NETLINK_SET_LINK_SPEED_100HALF)
1913 bp->advertising |= ADVERTISED_100baseT_Half;
1914 if (link & BNX2_NETLINK_SET_LINK_SPEED_100FULL)
1915 bp->advertising |= ADVERTISED_100baseT_Full;
1916 if (link & BNX2_NETLINK_SET_LINK_SPEED_1GFULL)
1917 bp->advertising |= ADVERTISED_1000baseT_Full;
1918 if (link & BNX2_NETLINK_SET_LINK_SPEED_2G5FULL)
1919 bp->advertising |= ADVERTISED_2500baseX_Full;
1920 } else {
1921 bp->autoneg = 0;
1922 bp->advertising = 0;
1923 bp->req_duplex = DUPLEX_FULL;
1924 if (link & BNX2_NETLINK_SET_LINK_SPEED_10) {
1925 bp->req_line_speed = SPEED_10;
1926 if (link & BNX2_NETLINK_SET_LINK_SPEED_10HALF)
1927 bp->req_duplex = DUPLEX_HALF;
1928 }
1929 if (link & BNX2_NETLINK_SET_LINK_SPEED_100) {
1930 bp->req_line_speed = SPEED_100;
1931 if (link & BNX2_NETLINK_SET_LINK_SPEED_100HALF)
1932 bp->req_duplex = DUPLEX_HALF;
1933 }
1934 if (link & BNX2_NETLINK_SET_LINK_SPEED_1GFULL)
1935 bp->req_line_speed = SPEED_1000;
1936 if (link & BNX2_NETLINK_SET_LINK_SPEED_2G5FULL)
1937 bp->req_line_speed = SPEED_2500;
1938 }
1939}
1940
1941static void
Michael Chandeaf3912007-07-07 22:48:00 -07001942bnx2_set_default_link(struct bnx2 *bp)
1943{
Harvey Harrisonab598592008-05-01 02:47:38 -07001944 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP) {
1945 bnx2_set_default_remote_link(bp);
1946 return;
1947 }
Michael Chan0d8a6572007-07-07 22:49:43 -07001948
Michael Chandeaf3912007-07-07 22:48:00 -07001949 bp->autoneg = AUTONEG_SPEED | AUTONEG_FLOW_CTRL;
1950 bp->req_line_speed = 0;
Michael Chan583c28e2008-01-21 19:51:35 -08001951 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Michael Chandeaf3912007-07-07 22:48:00 -07001952 u32 reg;
1953
1954 bp->advertising = ETHTOOL_ALL_FIBRE_SPEED | ADVERTISED_Autoneg;
1955
Michael Chan2726d6e2008-01-29 21:35:05 -08001956 reg = bnx2_shmem_rd(bp, BNX2_PORT_HW_CFG_CONFIG);
Michael Chandeaf3912007-07-07 22:48:00 -07001957 reg &= BNX2_PORT_HW_CFG_CFG_DFLT_LINK_MASK;
1958 if (reg == BNX2_PORT_HW_CFG_CFG_DFLT_LINK_1G) {
1959 bp->autoneg = 0;
1960 bp->req_line_speed = bp->line_speed = SPEED_1000;
1961 bp->req_duplex = DUPLEX_FULL;
1962 }
1963 } else
1964 bp->advertising = ETHTOOL_ALL_COPPER_SPEED | ADVERTISED_Autoneg;
1965}
1966
Michael Chan0d8a6572007-07-07 22:49:43 -07001967static void
Michael Chandf149d72007-07-07 22:51:36 -07001968bnx2_send_heart_beat(struct bnx2 *bp)
1969{
1970 u32 msg;
1971 u32 addr;
1972
1973 spin_lock(&bp->indirect_lock);
1974 msg = (u32) (++bp->fw_drv_pulse_wr_seq & BNX2_DRV_PULSE_SEQ_MASK);
1975 addr = bp->shmem_base + BNX2_DRV_PULSE_MB;
Michael Chane503e062012-12-06 10:33:08 +00001976 BNX2_WR(bp, BNX2_PCICFG_REG_WINDOW_ADDRESS, addr);
1977 BNX2_WR(bp, BNX2_PCICFG_REG_WINDOW, msg);
Michael Chandf149d72007-07-07 22:51:36 -07001978 spin_unlock(&bp->indirect_lock);
1979}
1980
1981static void
Michael Chan0d8a6572007-07-07 22:49:43 -07001982bnx2_remote_phy_event(struct bnx2 *bp)
1983{
1984 u32 msg;
1985 u8 link_up = bp->link_up;
1986 u8 old_port;
1987
Michael Chan2726d6e2008-01-29 21:35:05 -08001988 msg = bnx2_shmem_rd(bp, BNX2_LINK_STATUS);
Michael Chan0d8a6572007-07-07 22:49:43 -07001989
Michael Chandf149d72007-07-07 22:51:36 -07001990 if (msg & BNX2_LINK_STATUS_HEART_BEAT_EXPIRED)
1991 bnx2_send_heart_beat(bp);
1992
1993 msg &= ~BNX2_LINK_STATUS_HEART_BEAT_EXPIRED;
1994
Michael Chan0d8a6572007-07-07 22:49:43 -07001995 if ((msg & BNX2_LINK_STATUS_LINK_UP) == BNX2_LINK_STATUS_LINK_DOWN)
1996 bp->link_up = 0;
1997 else {
1998 u32 speed;
1999
2000 bp->link_up = 1;
2001 speed = msg & BNX2_LINK_STATUS_SPEED_MASK;
2002 bp->duplex = DUPLEX_FULL;
2003 switch (speed) {
2004 case BNX2_LINK_STATUS_10HALF:
2005 bp->duplex = DUPLEX_HALF;
Michael Chan7947c9c2012-06-27 15:08:23 +00002006 /* fall through */
Michael Chan0d8a6572007-07-07 22:49:43 -07002007 case BNX2_LINK_STATUS_10FULL:
2008 bp->line_speed = SPEED_10;
2009 break;
2010 case BNX2_LINK_STATUS_100HALF:
2011 bp->duplex = DUPLEX_HALF;
Michael Chan7947c9c2012-06-27 15:08:23 +00002012 /* fall through */
Michael Chan0d8a6572007-07-07 22:49:43 -07002013 case BNX2_LINK_STATUS_100BASE_T4:
2014 case BNX2_LINK_STATUS_100FULL:
2015 bp->line_speed = SPEED_100;
2016 break;
2017 case BNX2_LINK_STATUS_1000HALF:
2018 bp->duplex = DUPLEX_HALF;
Michael Chan7947c9c2012-06-27 15:08:23 +00002019 /* fall through */
Michael Chan0d8a6572007-07-07 22:49:43 -07002020 case BNX2_LINK_STATUS_1000FULL:
2021 bp->line_speed = SPEED_1000;
2022 break;
2023 case BNX2_LINK_STATUS_2500HALF:
2024 bp->duplex = DUPLEX_HALF;
Michael Chan7947c9c2012-06-27 15:08:23 +00002025 /* fall through */
Michael Chan0d8a6572007-07-07 22:49:43 -07002026 case BNX2_LINK_STATUS_2500FULL:
2027 bp->line_speed = SPEED_2500;
2028 break;
2029 default:
2030 bp->line_speed = 0;
2031 break;
2032 }
2033
Michael Chan0d8a6572007-07-07 22:49:43 -07002034 bp->flow_ctrl = 0;
2035 if ((bp->autoneg & (AUTONEG_SPEED | AUTONEG_FLOW_CTRL)) !=
2036 (AUTONEG_SPEED | AUTONEG_FLOW_CTRL)) {
2037 if (bp->duplex == DUPLEX_FULL)
2038 bp->flow_ctrl = bp->req_flow_ctrl;
2039 } else {
2040 if (msg & BNX2_LINK_STATUS_TX_FC_ENABLED)
2041 bp->flow_ctrl |= FLOW_CTRL_TX;
2042 if (msg & BNX2_LINK_STATUS_RX_FC_ENABLED)
2043 bp->flow_ctrl |= FLOW_CTRL_RX;
2044 }
2045
2046 old_port = bp->phy_port;
2047 if (msg & BNX2_LINK_STATUS_SERDES_LINK)
2048 bp->phy_port = PORT_FIBRE;
2049 else
2050 bp->phy_port = PORT_TP;
2051
2052 if (old_port != bp->phy_port)
2053 bnx2_set_default_link(bp);
2054
Michael Chan0d8a6572007-07-07 22:49:43 -07002055 }
2056 if (bp->link_up != link_up)
2057 bnx2_report_link(bp);
2058
2059 bnx2_set_mac_link(bp);
2060}
2061
2062static int
2063bnx2_set_remote_link(struct bnx2 *bp)
2064{
2065 u32 evt_code;
2066
Michael Chan2726d6e2008-01-29 21:35:05 -08002067 evt_code = bnx2_shmem_rd(bp, BNX2_FW_EVT_CODE_MB);
Michael Chan0d8a6572007-07-07 22:49:43 -07002068 switch (evt_code) {
2069 case BNX2_FW_EVT_CODE_LINK_EVENT:
2070 bnx2_remote_phy_event(bp);
2071 break;
2072 case BNX2_FW_EVT_CODE_SW_TIMER_EXPIRATION_EVENT:
2073 default:
Michael Chandf149d72007-07-07 22:51:36 -07002074 bnx2_send_heart_beat(bp);
Michael Chan0d8a6572007-07-07 22:49:43 -07002075 break;
2076 }
2077 return 0;
2078}
2079
Michael Chanb6016b72005-05-26 13:03:09 -07002080static int
2081bnx2_setup_copper_phy(struct bnx2 *bp)
Harvey Harrison52d07b12009-01-19 17:27:06 -08002082__releases(&bp->phy_lock)
2083__acquires(&bp->phy_lock)
Michael Chanb6016b72005-05-26 13:03:09 -07002084{
Michael Chand17e53b2013-12-31 23:22:32 -08002085 u32 bmcr, adv_reg, new_adv = 0;
Michael Chanb6016b72005-05-26 13:03:09 -07002086 u32 new_bmcr;
2087
Michael Chanca58c3a2007-05-03 13:22:52 -07002088 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chanb6016b72005-05-26 13:03:09 -07002089
Michael Chand17e53b2013-12-31 23:22:32 -08002090 bnx2_read_phy(bp, bp->mii_adv, &adv_reg);
2091 adv_reg &= (PHY_ALL_10_100_SPEED | ADVERTISE_PAUSE_CAP |
2092 ADVERTISE_PAUSE_ASYM);
2093
2094 new_adv = ADVERTISE_CSMA | ethtool_adv_to_mii_adv_t(bp->advertising);
2095
Michael Chanb6016b72005-05-26 13:03:09 -07002096 if (bp->autoneg & AUTONEG_SPEED) {
Michael Chand17e53b2013-12-31 23:22:32 -08002097 u32 adv1000_reg;
Matt Carlson37f07022011-11-17 14:30:55 +00002098 u32 new_adv1000 = 0;
Michael Chanb6016b72005-05-26 13:03:09 -07002099
Michael Chand17e53b2013-12-31 23:22:32 -08002100 new_adv |= bnx2_phy_get_pause_adv(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07002101
2102 bnx2_read_phy(bp, MII_CTRL1000, &adv1000_reg);
2103 adv1000_reg &= PHY_ALL_1000_SPEED;
2104
Matt Carlson37f07022011-11-17 14:30:55 +00002105 new_adv1000 |= ethtool_adv_to_mii_ctrl1000_t(bp->advertising);
Matt Carlson37f07022011-11-17 14:30:55 +00002106 if ((adv1000_reg != new_adv1000) ||
2107 (adv_reg != new_adv) ||
Michael Chanb6016b72005-05-26 13:03:09 -07002108 ((bmcr & BMCR_ANENABLE) == 0)) {
2109
Matt Carlson37f07022011-11-17 14:30:55 +00002110 bnx2_write_phy(bp, bp->mii_adv, new_adv);
2111 bnx2_write_phy(bp, MII_CTRL1000, new_adv1000);
Michael Chanca58c3a2007-05-03 13:22:52 -07002112 bnx2_write_phy(bp, bp->mii_bmcr, BMCR_ANRESTART |
Michael Chanb6016b72005-05-26 13:03:09 -07002113 BMCR_ANENABLE);
2114 }
2115 else if (bp->link_up) {
2116 /* Flow ctrl may have changed from auto to forced */
2117 /* or vice-versa. */
2118
2119 bnx2_resolve_flow_ctrl(bp);
2120 bnx2_set_mac_link(bp);
2121 }
2122 return 0;
2123 }
2124
Michael Chand17e53b2013-12-31 23:22:32 -08002125 /* advertise nothing when forcing speed */
2126 if (adv_reg != new_adv)
2127 bnx2_write_phy(bp, bp->mii_adv, new_adv);
2128
Michael Chanb6016b72005-05-26 13:03:09 -07002129 new_bmcr = 0;
2130 if (bp->req_line_speed == SPEED_100) {
2131 new_bmcr |= BMCR_SPEED100;
2132 }
2133 if (bp->req_duplex == DUPLEX_FULL) {
2134 new_bmcr |= BMCR_FULLDPLX;
2135 }
2136 if (new_bmcr != bmcr) {
2137 u32 bmsr;
Michael Chanb6016b72005-05-26 13:03:09 -07002138
Michael Chanca58c3a2007-05-03 13:22:52 -07002139 bnx2_read_phy(bp, bp->mii_bmsr, &bmsr);
2140 bnx2_read_phy(bp, bp->mii_bmsr, &bmsr);
Jeff Garzik6aa20a22006-09-13 13:24:59 -04002141
Michael Chanb6016b72005-05-26 13:03:09 -07002142 if (bmsr & BMSR_LSTATUS) {
2143 /* Force link down */
Michael Chanca58c3a2007-05-03 13:22:52 -07002144 bnx2_write_phy(bp, bp->mii_bmcr, BMCR_LOOPBACK);
Michael Chana16dda02006-11-19 14:08:56 -08002145 spin_unlock_bh(&bp->phy_lock);
2146 msleep(50);
2147 spin_lock_bh(&bp->phy_lock);
2148
Michael Chanca58c3a2007-05-03 13:22:52 -07002149 bnx2_read_phy(bp, bp->mii_bmsr, &bmsr);
2150 bnx2_read_phy(bp, bp->mii_bmsr, &bmsr);
Michael Chanb6016b72005-05-26 13:03:09 -07002151 }
2152
Michael Chanca58c3a2007-05-03 13:22:52 -07002153 bnx2_write_phy(bp, bp->mii_bmcr, new_bmcr);
Michael Chanb6016b72005-05-26 13:03:09 -07002154
2155 /* Normally, the new speed is setup after the link has
2156 * gone down and up again. In some cases, link will not go
2157 * down so we need to set up the new speed here.
2158 */
2159 if (bmsr & BMSR_LSTATUS) {
2160 bp->line_speed = bp->req_line_speed;
2161 bp->duplex = bp->req_duplex;
2162 bnx2_resolve_flow_ctrl(bp);
2163 bnx2_set_mac_link(bp);
2164 }
Michael Chan27a005b2007-05-03 13:23:41 -07002165 } else {
2166 bnx2_resolve_flow_ctrl(bp);
2167 bnx2_set_mac_link(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07002168 }
2169 return 0;
2170}
2171
2172static int
Michael Chan0d8a6572007-07-07 22:49:43 -07002173bnx2_setup_phy(struct bnx2 *bp, u8 port)
Harvey Harrison52d07b12009-01-19 17:27:06 -08002174__releases(&bp->phy_lock)
2175__acquires(&bp->phy_lock)
Michael Chanb6016b72005-05-26 13:03:09 -07002176{
2177 if (bp->loopback == MAC_LOOPBACK)
2178 return 0;
2179
Michael Chan583c28e2008-01-21 19:51:35 -08002180 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Eric Dumazet807540b2010-09-23 05:40:09 +00002181 return bnx2_setup_serdes_phy(bp, port);
Michael Chanb6016b72005-05-26 13:03:09 -07002182 }
2183 else {
Eric Dumazet807540b2010-09-23 05:40:09 +00002184 return bnx2_setup_copper_phy(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07002185 }
2186}
2187
2188static int
Michael Chan9a120bc2008-05-16 22:17:45 -07002189bnx2_init_5709s_phy(struct bnx2 *bp, int reset_phy)
Michael Chan27a005b2007-05-03 13:23:41 -07002190{
2191 u32 val;
2192
2193 bp->mii_bmcr = MII_BMCR + 0x10;
2194 bp->mii_bmsr = MII_BMSR + 0x10;
2195 bp->mii_bmsr1 = MII_BNX2_GP_TOP_AN_STATUS1;
2196 bp->mii_adv = MII_ADVERTISE + 0x10;
2197 bp->mii_lpa = MII_LPA + 0x10;
2198 bp->mii_up1 = MII_BNX2_OVER1G_UP1;
2199
2200 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_AER);
2201 bnx2_write_phy(bp, MII_BNX2_AER_AER, MII_BNX2_AER_AER_AN_MMD);
2202
2203 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
Michael Chan9a120bc2008-05-16 22:17:45 -07002204 if (reset_phy)
2205 bnx2_reset_phy(bp);
Michael Chan27a005b2007-05-03 13:23:41 -07002206
2207 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_SERDES_DIG);
2208
2209 bnx2_read_phy(bp, MII_BNX2_SERDES_DIG_1000XCTL1, &val);
2210 val &= ~MII_BNX2_SD_1000XCTL1_AUTODET;
2211 val |= MII_BNX2_SD_1000XCTL1_FIBER;
2212 bnx2_write_phy(bp, MII_BNX2_SERDES_DIG_1000XCTL1, val);
2213
2214 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_OVER1G);
2215 bnx2_read_phy(bp, MII_BNX2_OVER1G_UP1, &val);
Michael Chan583c28e2008-01-21 19:51:35 -08002216 if (bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE)
Michael Chan27a005b2007-05-03 13:23:41 -07002217 val |= BCM5708S_UP1_2G5;
2218 else
2219 val &= ~BCM5708S_UP1_2G5;
2220 bnx2_write_phy(bp, MII_BNX2_OVER1G_UP1, val);
2221
2222 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_BAM_NXTPG);
2223 bnx2_read_phy(bp, MII_BNX2_BAM_NXTPG_CTL, &val);
2224 val |= MII_BNX2_NXTPG_CTL_T2 | MII_BNX2_NXTPG_CTL_BAM;
2225 bnx2_write_phy(bp, MII_BNX2_BAM_NXTPG_CTL, val);
2226
2227 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_CL73_USERB0);
2228
2229 val = MII_BNX2_CL73_BAM_EN | MII_BNX2_CL73_BAM_STA_MGR_EN |
2230 MII_BNX2_CL73_BAM_NP_AFT_BP_EN;
2231 bnx2_write_phy(bp, MII_BNX2_CL73_BAM_CTL1, val);
2232
2233 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
2234
2235 return 0;
2236}
2237
2238static int
Michael Chan9a120bc2008-05-16 22:17:45 -07002239bnx2_init_5708s_phy(struct bnx2 *bp, int reset_phy)
Michael Chan5b0c76a2005-11-04 08:45:49 -08002240{
2241 u32 val;
2242
Michael Chan9a120bc2008-05-16 22:17:45 -07002243 if (reset_phy)
2244 bnx2_reset_phy(bp);
Michael Chan27a005b2007-05-03 13:23:41 -07002245
2246 bp->mii_up1 = BCM5708S_UP1;
2247
Michael Chan5b0c76a2005-11-04 08:45:49 -08002248 bnx2_write_phy(bp, BCM5708S_BLK_ADDR, BCM5708S_BLK_ADDR_DIG3);
2249 bnx2_write_phy(bp, BCM5708S_DIG_3_0, BCM5708S_DIG_3_0_USE_IEEE);
2250 bnx2_write_phy(bp, BCM5708S_BLK_ADDR, BCM5708S_BLK_ADDR_DIG);
2251
2252 bnx2_read_phy(bp, BCM5708S_1000X_CTL1, &val);
2253 val |= BCM5708S_1000X_CTL1_FIBER_MODE | BCM5708S_1000X_CTL1_AUTODET_EN;
2254 bnx2_write_phy(bp, BCM5708S_1000X_CTL1, val);
2255
2256 bnx2_read_phy(bp, BCM5708S_1000X_CTL2, &val);
2257 val |= BCM5708S_1000X_CTL2_PLLEL_DET_EN;
2258 bnx2_write_phy(bp, BCM5708S_1000X_CTL2, val);
2259
Michael Chan583c28e2008-01-21 19:51:35 -08002260 if (bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE) {
Michael Chan5b0c76a2005-11-04 08:45:49 -08002261 bnx2_read_phy(bp, BCM5708S_UP1, &val);
2262 val |= BCM5708S_UP1_2G5;
2263 bnx2_write_phy(bp, BCM5708S_UP1, val);
2264 }
2265
Michael Chan4ce45e02012-12-06 10:33:10 +00002266 if ((BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5708_A0) ||
2267 (BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5708_B0) ||
2268 (BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5708_B1)) {
Michael Chan5b0c76a2005-11-04 08:45:49 -08002269 /* increase tx signal amplitude */
2270 bnx2_write_phy(bp, BCM5708S_BLK_ADDR,
2271 BCM5708S_BLK_ADDR_TX_MISC);
2272 bnx2_read_phy(bp, BCM5708S_TX_ACTL1, &val);
2273 val &= ~BCM5708S_TX_ACTL1_DRIVER_VCM;
2274 bnx2_write_phy(bp, BCM5708S_TX_ACTL1, val);
2275 bnx2_write_phy(bp, BCM5708S_BLK_ADDR, BCM5708S_BLK_ADDR_DIG);
2276 }
2277
Michael Chan2726d6e2008-01-29 21:35:05 -08002278 val = bnx2_shmem_rd(bp, BNX2_PORT_HW_CFG_CONFIG) &
Michael Chan5b0c76a2005-11-04 08:45:49 -08002279 BNX2_PORT_HW_CFG_CFG_TXCTL3_MASK;
2280
2281 if (val) {
2282 u32 is_backplane;
2283
Michael Chan2726d6e2008-01-29 21:35:05 -08002284 is_backplane = bnx2_shmem_rd(bp, BNX2_SHARED_HW_CFG_CONFIG);
Michael Chan5b0c76a2005-11-04 08:45:49 -08002285 if (is_backplane & BNX2_SHARED_HW_CFG_PHY_BACKPLANE) {
2286 bnx2_write_phy(bp, BCM5708S_BLK_ADDR,
2287 BCM5708S_BLK_ADDR_TX_MISC);
2288 bnx2_write_phy(bp, BCM5708S_TX_ACTL3, val);
2289 bnx2_write_phy(bp, BCM5708S_BLK_ADDR,
2290 BCM5708S_BLK_ADDR_DIG);
2291 }
2292 }
2293 return 0;
2294}
2295
2296static int
Michael Chan9a120bc2008-05-16 22:17:45 -07002297bnx2_init_5706s_phy(struct bnx2 *bp, int reset_phy)
Michael Chanb6016b72005-05-26 13:03:09 -07002298{
Michael Chan9a120bc2008-05-16 22:17:45 -07002299 if (reset_phy)
2300 bnx2_reset_phy(bp);
Michael Chan27a005b2007-05-03 13:23:41 -07002301
Michael Chan583c28e2008-01-21 19:51:35 -08002302 bp->phy_flags &= ~BNX2_PHY_FLAG_PARALLEL_DETECT;
Michael Chanb6016b72005-05-26 13:03:09 -07002303
Michael Chan4ce45e02012-12-06 10:33:10 +00002304 if (BNX2_CHIP(bp) == BNX2_CHIP_5706)
Michael Chane503e062012-12-06 10:33:08 +00002305 BNX2_WR(bp, BNX2_MISC_GP_HW_CTL0, 0x300);
Michael Chanb6016b72005-05-26 13:03:09 -07002306
2307 if (bp->dev->mtu > 1500) {
2308 u32 val;
2309
2310 /* Set extended packet length bit */
2311 bnx2_write_phy(bp, 0x18, 0x7);
2312 bnx2_read_phy(bp, 0x18, &val);
2313 bnx2_write_phy(bp, 0x18, (val & 0xfff8) | 0x4000);
2314
2315 bnx2_write_phy(bp, 0x1c, 0x6c00);
2316 bnx2_read_phy(bp, 0x1c, &val);
2317 bnx2_write_phy(bp, 0x1c, (val & 0x3ff) | 0xec02);
2318 }
2319 else {
2320 u32 val;
2321
2322 bnx2_write_phy(bp, 0x18, 0x7);
2323 bnx2_read_phy(bp, 0x18, &val);
2324 bnx2_write_phy(bp, 0x18, val & ~0x4007);
2325
2326 bnx2_write_phy(bp, 0x1c, 0x6c00);
2327 bnx2_read_phy(bp, 0x1c, &val);
2328 bnx2_write_phy(bp, 0x1c, (val & 0x3fd) | 0xec00);
2329 }
2330
2331 return 0;
2332}
2333
2334static int
Michael Chan9a120bc2008-05-16 22:17:45 -07002335bnx2_init_copper_phy(struct bnx2 *bp, int reset_phy)
Michael Chanb6016b72005-05-26 13:03:09 -07002336{
Michael Chan5b0c76a2005-11-04 08:45:49 -08002337 u32 val;
2338
Michael Chan9a120bc2008-05-16 22:17:45 -07002339 if (reset_phy)
2340 bnx2_reset_phy(bp);
Michael Chan27a005b2007-05-03 13:23:41 -07002341
Michael Chan583c28e2008-01-21 19:51:35 -08002342 if (bp->phy_flags & BNX2_PHY_FLAG_CRC_FIX) {
Michael Chanb6016b72005-05-26 13:03:09 -07002343 bnx2_write_phy(bp, 0x18, 0x0c00);
2344 bnx2_write_phy(bp, 0x17, 0x000a);
2345 bnx2_write_phy(bp, 0x15, 0x310b);
2346 bnx2_write_phy(bp, 0x17, 0x201f);
2347 bnx2_write_phy(bp, 0x15, 0x9506);
2348 bnx2_write_phy(bp, 0x17, 0x401f);
2349 bnx2_write_phy(bp, 0x15, 0x14e2);
2350 bnx2_write_phy(bp, 0x18, 0x0400);
2351 }
2352
Michael Chan583c28e2008-01-21 19:51:35 -08002353 if (bp->phy_flags & BNX2_PHY_FLAG_DIS_EARLY_DAC) {
Michael Chanb659f442007-02-02 00:46:35 -08002354 bnx2_write_phy(bp, MII_BNX2_DSP_ADDRESS,
2355 MII_BNX2_DSP_EXPAND_REG | 0x8);
2356 bnx2_read_phy(bp, MII_BNX2_DSP_RW_PORT, &val);
2357 val &= ~(1 << 8);
2358 bnx2_write_phy(bp, MII_BNX2_DSP_RW_PORT, val);
2359 }
2360
Michael Chanb6016b72005-05-26 13:03:09 -07002361 if (bp->dev->mtu > 1500) {
Michael Chanb6016b72005-05-26 13:03:09 -07002362 /* Set extended packet length bit */
2363 bnx2_write_phy(bp, 0x18, 0x7);
2364 bnx2_read_phy(bp, 0x18, &val);
2365 bnx2_write_phy(bp, 0x18, val | 0x4000);
2366
2367 bnx2_read_phy(bp, 0x10, &val);
2368 bnx2_write_phy(bp, 0x10, val | 0x1);
2369 }
2370 else {
Michael Chanb6016b72005-05-26 13:03:09 -07002371 bnx2_write_phy(bp, 0x18, 0x7);
2372 bnx2_read_phy(bp, 0x18, &val);
2373 bnx2_write_phy(bp, 0x18, val & ~0x4007);
2374
2375 bnx2_read_phy(bp, 0x10, &val);
2376 bnx2_write_phy(bp, 0x10, val & ~0x1);
2377 }
2378
Michael Chan5b0c76a2005-11-04 08:45:49 -08002379 /* ethernet@wirespeed */
Michael Chan41033b62013-12-31 23:22:33 -08002380 bnx2_write_phy(bp, MII_BNX2_AUX_CTL, AUX_CTL_MISC_CTL);
2381 bnx2_read_phy(bp, MII_BNX2_AUX_CTL, &val);
2382 val |= AUX_CTL_MISC_CTL_WR | AUX_CTL_MISC_CTL_WIRESPEED;
2383
2384 /* auto-mdix */
2385 if (BNX2_CHIP(bp) == BNX2_CHIP_5709)
2386 val |= AUX_CTL_MISC_CTL_AUTOMDIX;
2387
2388 bnx2_write_phy(bp, MII_BNX2_AUX_CTL, val);
Michael Chanb6016b72005-05-26 13:03:09 -07002389 return 0;
2390}
2391
2392
2393static int
Michael Chan9a120bc2008-05-16 22:17:45 -07002394bnx2_init_phy(struct bnx2 *bp, int reset_phy)
Harvey Harrison52d07b12009-01-19 17:27:06 -08002395__releases(&bp->phy_lock)
2396__acquires(&bp->phy_lock)
Michael Chanb6016b72005-05-26 13:03:09 -07002397{
2398 u32 val;
2399 int rc = 0;
2400
Michael Chan583c28e2008-01-21 19:51:35 -08002401 bp->phy_flags &= ~BNX2_PHY_FLAG_INT_MODE_MASK;
2402 bp->phy_flags |= BNX2_PHY_FLAG_INT_MODE_LINK_READY;
Michael Chanb6016b72005-05-26 13:03:09 -07002403
Michael Chanca58c3a2007-05-03 13:22:52 -07002404 bp->mii_bmcr = MII_BMCR;
2405 bp->mii_bmsr = MII_BMSR;
Michael Chan27a005b2007-05-03 13:23:41 -07002406 bp->mii_bmsr1 = MII_BMSR;
Michael Chanca58c3a2007-05-03 13:22:52 -07002407 bp->mii_adv = MII_ADVERTISE;
2408 bp->mii_lpa = MII_LPA;
2409
Michael Chane503e062012-12-06 10:33:08 +00002410 BNX2_WR(bp, BNX2_EMAC_ATTENTION_ENA, BNX2_EMAC_ATTENTION_ENA_LINK);
Michael Chanb6016b72005-05-26 13:03:09 -07002411
Michael Chan583c28e2008-01-21 19:51:35 -08002412 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
Michael Chan0d8a6572007-07-07 22:49:43 -07002413 goto setup_phy;
2414
Michael Chanb6016b72005-05-26 13:03:09 -07002415 bnx2_read_phy(bp, MII_PHYSID1, &val);
2416 bp->phy_id = val << 16;
2417 bnx2_read_phy(bp, MII_PHYSID2, &val);
2418 bp->phy_id |= val & 0xffff;
2419
Michael Chan583c28e2008-01-21 19:51:35 -08002420 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Michael Chan4ce45e02012-12-06 10:33:10 +00002421 if (BNX2_CHIP(bp) == BNX2_CHIP_5706)
Michael Chan9a120bc2008-05-16 22:17:45 -07002422 rc = bnx2_init_5706s_phy(bp, reset_phy);
Michael Chan4ce45e02012-12-06 10:33:10 +00002423 else if (BNX2_CHIP(bp) == BNX2_CHIP_5708)
Michael Chan9a120bc2008-05-16 22:17:45 -07002424 rc = bnx2_init_5708s_phy(bp, reset_phy);
Michael Chan4ce45e02012-12-06 10:33:10 +00002425 else if (BNX2_CHIP(bp) == BNX2_CHIP_5709)
Michael Chan9a120bc2008-05-16 22:17:45 -07002426 rc = bnx2_init_5709s_phy(bp, reset_phy);
Michael Chanb6016b72005-05-26 13:03:09 -07002427 }
2428 else {
Michael Chan9a120bc2008-05-16 22:17:45 -07002429 rc = bnx2_init_copper_phy(bp, reset_phy);
Michael Chanb6016b72005-05-26 13:03:09 -07002430 }
2431
Michael Chan0d8a6572007-07-07 22:49:43 -07002432setup_phy:
2433 if (!rc)
2434 rc = bnx2_setup_phy(bp, bp->phy_port);
Michael Chanb6016b72005-05-26 13:03:09 -07002435
2436 return rc;
2437}
2438
2439static int
2440bnx2_set_mac_loopback(struct bnx2 *bp)
2441{
2442 u32 mac_mode;
2443
Michael Chane503e062012-12-06 10:33:08 +00002444 mac_mode = BNX2_RD(bp, BNX2_EMAC_MODE);
Michael Chanb6016b72005-05-26 13:03:09 -07002445 mac_mode &= ~BNX2_EMAC_MODE_PORT;
2446 mac_mode |= BNX2_EMAC_MODE_MAC_LOOP | BNX2_EMAC_MODE_FORCE_LINK;
Michael Chane503e062012-12-06 10:33:08 +00002447 BNX2_WR(bp, BNX2_EMAC_MODE, mac_mode);
Michael Chanb6016b72005-05-26 13:03:09 -07002448 bp->link_up = 1;
2449 return 0;
2450}
2451
Michael Chanbc5a0692006-01-23 16:13:22 -08002452static int bnx2_test_link(struct bnx2 *);
2453
2454static int
2455bnx2_set_phy_loopback(struct bnx2 *bp)
2456{
2457 u32 mac_mode;
2458 int rc, i;
2459
2460 spin_lock_bh(&bp->phy_lock);
Michael Chanca58c3a2007-05-03 13:22:52 -07002461 rc = bnx2_write_phy(bp, bp->mii_bmcr, BMCR_LOOPBACK | BMCR_FULLDPLX |
Michael Chanbc5a0692006-01-23 16:13:22 -08002462 BMCR_SPEED1000);
2463 spin_unlock_bh(&bp->phy_lock);
2464 if (rc)
2465 return rc;
2466
2467 for (i = 0; i < 10; i++) {
2468 if (bnx2_test_link(bp) == 0)
2469 break;
Michael Chan80be4432006-11-19 14:07:28 -08002470 msleep(100);
Michael Chanbc5a0692006-01-23 16:13:22 -08002471 }
2472
Michael Chane503e062012-12-06 10:33:08 +00002473 mac_mode = BNX2_RD(bp, BNX2_EMAC_MODE);
Michael Chanbc5a0692006-01-23 16:13:22 -08002474 mac_mode &= ~(BNX2_EMAC_MODE_PORT | BNX2_EMAC_MODE_HALF_DUPLEX |
2475 BNX2_EMAC_MODE_MAC_LOOP | BNX2_EMAC_MODE_FORCE_LINK |
Michael Chan59b47d82006-11-19 14:10:45 -08002476 BNX2_EMAC_MODE_25G_MODE);
Michael Chanbc5a0692006-01-23 16:13:22 -08002477
2478 mac_mode |= BNX2_EMAC_MODE_PORT_GMII;
Michael Chane503e062012-12-06 10:33:08 +00002479 BNX2_WR(bp, BNX2_EMAC_MODE, mac_mode);
Michael Chanbc5a0692006-01-23 16:13:22 -08002480 bp->link_up = 1;
2481 return 0;
2482}
2483
Jeffrey Huangecdbf6e2011-07-13 17:24:21 +00002484static void
2485bnx2_dump_mcp_state(struct bnx2 *bp)
2486{
2487 struct net_device *dev = bp->dev;
2488 u32 mcp_p0, mcp_p1;
2489
2490 netdev_err(dev, "<--- start MCP states dump --->\n");
Michael Chan4ce45e02012-12-06 10:33:10 +00002491 if (BNX2_CHIP(bp) == BNX2_CHIP_5709) {
Jeffrey Huangecdbf6e2011-07-13 17:24:21 +00002492 mcp_p0 = BNX2_MCP_STATE_P0;
2493 mcp_p1 = BNX2_MCP_STATE_P1;
2494 } else {
2495 mcp_p0 = BNX2_MCP_STATE_P0_5708;
2496 mcp_p1 = BNX2_MCP_STATE_P1_5708;
2497 }
2498 netdev_err(dev, "DEBUG: MCP_STATE_P0[%08x] MCP_STATE_P1[%08x]\n",
2499 bnx2_reg_rd_ind(bp, mcp_p0), bnx2_reg_rd_ind(bp, mcp_p1));
2500 netdev_err(dev, "DEBUG: MCP mode[%08x] state[%08x] evt_mask[%08x]\n",
2501 bnx2_reg_rd_ind(bp, BNX2_MCP_CPU_MODE),
2502 bnx2_reg_rd_ind(bp, BNX2_MCP_CPU_STATE),
2503 bnx2_reg_rd_ind(bp, BNX2_MCP_CPU_EVENT_MASK));
2504 netdev_err(dev, "DEBUG: pc[%08x] pc[%08x] instr[%08x]\n",
2505 bnx2_reg_rd_ind(bp, BNX2_MCP_CPU_PROGRAM_COUNTER),
2506 bnx2_reg_rd_ind(bp, BNX2_MCP_CPU_PROGRAM_COUNTER),
2507 bnx2_reg_rd_ind(bp, BNX2_MCP_CPU_INSTRUCTION));
2508 netdev_err(dev, "DEBUG: shmem states:\n");
2509 netdev_err(dev, "DEBUG: drv_mb[%08x] fw_mb[%08x] link_status[%08x]",
2510 bnx2_shmem_rd(bp, BNX2_DRV_MB),
2511 bnx2_shmem_rd(bp, BNX2_FW_MB),
2512 bnx2_shmem_rd(bp, BNX2_LINK_STATUS));
2513 pr_cont(" drv_pulse_mb[%08x]\n", bnx2_shmem_rd(bp, BNX2_DRV_PULSE_MB));
2514 netdev_err(dev, "DEBUG: dev_info_signature[%08x] reset_type[%08x]",
2515 bnx2_shmem_rd(bp, BNX2_DEV_INFO_SIGNATURE),
2516 bnx2_shmem_rd(bp, BNX2_BC_STATE_RESET_TYPE));
2517 pr_cont(" condition[%08x]\n",
2518 bnx2_shmem_rd(bp, BNX2_BC_STATE_CONDITION));
Michael Chan13e63512012-06-16 15:45:42 +00002519 DP_SHMEM_LINE(bp, BNX2_BC_RESET_TYPE);
Jeffrey Huangecdbf6e2011-07-13 17:24:21 +00002520 DP_SHMEM_LINE(bp, 0x3cc);
2521 DP_SHMEM_LINE(bp, 0x3dc);
2522 DP_SHMEM_LINE(bp, 0x3ec);
2523 netdev_err(dev, "DEBUG: 0x3fc[%08x]\n", bnx2_shmem_rd(bp, 0x3fc));
2524 netdev_err(dev, "<--- end MCP states dump --->\n");
2525}
2526
Michael Chanb6016b72005-05-26 13:03:09 -07002527static int
Michael Chana2f13892008-07-14 22:38:23 -07002528bnx2_fw_sync(struct bnx2 *bp, u32 msg_data, int ack, int silent)
Michael Chanb6016b72005-05-26 13:03:09 -07002529{
2530 int i;
2531 u32 val;
2532
Michael Chanb6016b72005-05-26 13:03:09 -07002533 bp->fw_wr_seq++;
2534 msg_data |= bp->fw_wr_seq;
Michael Chana8d9bc22014-03-09 15:45:32 -08002535 bp->fw_last_msg = msg_data;
Michael Chanb6016b72005-05-26 13:03:09 -07002536
Michael Chan2726d6e2008-01-29 21:35:05 -08002537 bnx2_shmem_wr(bp, BNX2_DRV_MB, msg_data);
Michael Chanb6016b72005-05-26 13:03:09 -07002538
Michael Chana2f13892008-07-14 22:38:23 -07002539 if (!ack)
2540 return 0;
2541
Michael Chanb6016b72005-05-26 13:03:09 -07002542 /* wait for an acknowledgement. */
Michael Chan40105c02008-11-12 16:02:45 -08002543 for (i = 0; i < (BNX2_FW_ACK_TIME_OUT_MS / 10); i++) {
Michael Chanb090ae22006-01-23 16:07:10 -08002544 msleep(10);
Michael Chanb6016b72005-05-26 13:03:09 -07002545
Michael Chan2726d6e2008-01-29 21:35:05 -08002546 val = bnx2_shmem_rd(bp, BNX2_FW_MB);
Michael Chanb6016b72005-05-26 13:03:09 -07002547
2548 if ((val & BNX2_FW_MSG_ACK) == (msg_data & BNX2_DRV_MSG_SEQ))
2549 break;
2550 }
Michael Chanb090ae22006-01-23 16:07:10 -08002551 if ((msg_data & BNX2_DRV_MSG_DATA) == BNX2_DRV_MSG_DATA_WAIT0)
2552 return 0;
Michael Chanb6016b72005-05-26 13:03:09 -07002553
2554 /* If we timed out, inform the firmware that this is the case. */
Michael Chanb090ae22006-01-23 16:07:10 -08002555 if ((val & BNX2_FW_MSG_ACK) != (msg_data & BNX2_DRV_MSG_SEQ)) {
Michael Chanb6016b72005-05-26 13:03:09 -07002556 msg_data &= ~BNX2_DRV_MSG_CODE;
2557 msg_data |= BNX2_DRV_MSG_CODE_FW_TIMEOUT;
2558
Michael Chan2726d6e2008-01-29 21:35:05 -08002559 bnx2_shmem_wr(bp, BNX2_DRV_MB, msg_data);
Jeffrey Huangecdbf6e2011-07-13 17:24:21 +00002560 if (!silent) {
2561 pr_err("fw sync timeout, reset code = %x\n", msg_data);
2562 bnx2_dump_mcp_state(bp);
2563 }
Michael Chanb6016b72005-05-26 13:03:09 -07002564
Michael Chanb6016b72005-05-26 13:03:09 -07002565 return -EBUSY;
2566 }
2567
Michael Chanb090ae22006-01-23 16:07:10 -08002568 if ((val & BNX2_FW_MSG_STATUS_MASK) != BNX2_FW_MSG_STATUS_OK)
2569 return -EIO;
2570
Michael Chanb6016b72005-05-26 13:03:09 -07002571 return 0;
2572}
2573
Michael Chan59b47d82006-11-19 14:10:45 -08002574static int
2575bnx2_init_5709_context(struct bnx2 *bp)
2576{
2577 int i, ret = 0;
2578 u32 val;
2579
2580 val = BNX2_CTX_COMMAND_ENABLED | BNX2_CTX_COMMAND_MEM_INIT | (1 << 12);
Michael Chan2bc40782012-12-06 10:33:09 +00002581 val |= (BNX2_PAGE_BITS - 8) << 16;
Michael Chane503e062012-12-06 10:33:08 +00002582 BNX2_WR(bp, BNX2_CTX_COMMAND, val);
Michael Chan641bdcd2007-06-04 21:22:24 -07002583 for (i = 0; i < 10; i++) {
Michael Chane503e062012-12-06 10:33:08 +00002584 val = BNX2_RD(bp, BNX2_CTX_COMMAND);
Michael Chan641bdcd2007-06-04 21:22:24 -07002585 if (!(val & BNX2_CTX_COMMAND_MEM_INIT))
2586 break;
2587 udelay(2);
2588 }
2589 if (val & BNX2_CTX_COMMAND_MEM_INIT)
2590 return -EBUSY;
2591
Michael Chan59b47d82006-11-19 14:10:45 -08002592 for (i = 0; i < bp->ctx_pages; i++) {
2593 int j;
2594
Michael Chan352f7682008-05-02 16:57:26 -07002595 if (bp->ctx_blk[i])
Michael Chan2bc40782012-12-06 10:33:09 +00002596 memset(bp->ctx_blk[i], 0, BNX2_PAGE_SIZE);
Michael Chan352f7682008-05-02 16:57:26 -07002597 else
2598 return -ENOMEM;
2599
Michael Chane503e062012-12-06 10:33:08 +00002600 BNX2_WR(bp, BNX2_CTX_HOST_PAGE_TBL_DATA0,
2601 (bp->ctx_blk_mapping[i] & 0xffffffff) |
2602 BNX2_CTX_HOST_PAGE_TBL_DATA0_VALID);
2603 BNX2_WR(bp, BNX2_CTX_HOST_PAGE_TBL_DATA1,
2604 (u64) bp->ctx_blk_mapping[i] >> 32);
2605 BNX2_WR(bp, BNX2_CTX_HOST_PAGE_TBL_CTRL, i |
2606 BNX2_CTX_HOST_PAGE_TBL_CTRL_WRITE_REQ);
Michael Chan59b47d82006-11-19 14:10:45 -08002607 for (j = 0; j < 10; j++) {
2608
Michael Chane503e062012-12-06 10:33:08 +00002609 val = BNX2_RD(bp, BNX2_CTX_HOST_PAGE_TBL_CTRL);
Michael Chan59b47d82006-11-19 14:10:45 -08002610 if (!(val & BNX2_CTX_HOST_PAGE_TBL_CTRL_WRITE_REQ))
2611 break;
2612 udelay(5);
2613 }
2614 if (val & BNX2_CTX_HOST_PAGE_TBL_CTRL_WRITE_REQ) {
2615 ret = -EBUSY;
2616 break;
2617 }
2618 }
2619 return ret;
2620}
2621
Michael Chanb6016b72005-05-26 13:03:09 -07002622static void
2623bnx2_init_context(struct bnx2 *bp)
2624{
2625 u32 vcid;
2626
2627 vcid = 96;
2628 while (vcid) {
2629 u32 vcid_addr, pcid_addr, offset;
Michael Chan7947b202007-06-04 21:17:10 -07002630 int i;
Michael Chanb6016b72005-05-26 13:03:09 -07002631
2632 vcid--;
2633
Michael Chan4ce45e02012-12-06 10:33:10 +00002634 if (BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5706_A0) {
Michael Chanb6016b72005-05-26 13:03:09 -07002635 u32 new_vcid;
2636
2637 vcid_addr = GET_PCID_ADDR(vcid);
2638 if (vcid & 0x8) {
2639 new_vcid = 0x60 + (vcid & 0xf0) + (vcid & 0x7);
2640 }
2641 else {
2642 new_vcid = vcid;
2643 }
2644 pcid_addr = GET_PCID_ADDR(new_vcid);
2645 }
2646 else {
2647 vcid_addr = GET_CID_ADDR(vcid);
2648 pcid_addr = vcid_addr;
2649 }
2650
Michael Chan7947b202007-06-04 21:17:10 -07002651 for (i = 0; i < (CTX_SIZE / PHY_CTX_SIZE); i++) {
2652 vcid_addr += (i << PHY_CTX_SHIFT);
2653 pcid_addr += (i << PHY_CTX_SHIFT);
Michael Chanb6016b72005-05-26 13:03:09 -07002654
Michael Chane503e062012-12-06 10:33:08 +00002655 BNX2_WR(bp, BNX2_CTX_VIRT_ADDR, vcid_addr);
2656 BNX2_WR(bp, BNX2_CTX_PAGE_TBL, pcid_addr);
Michael Chan7947b202007-06-04 21:17:10 -07002657
2658 /* Zero out the context. */
2659 for (offset = 0; offset < PHY_CTX_SIZE; offset += 4)
Michael Chan62a83132008-01-29 21:35:40 -08002660 bnx2_ctx_wr(bp, vcid_addr, offset, 0);
Michael Chanb6016b72005-05-26 13:03:09 -07002661 }
Michael Chanb6016b72005-05-26 13:03:09 -07002662 }
2663}
2664
2665static int
2666bnx2_alloc_bad_rbuf(struct bnx2 *bp)
2667{
2668 u16 *good_mbuf;
2669 u32 good_mbuf_cnt;
2670 u32 val;
2671
2672 good_mbuf = kmalloc(512 * sizeof(u16), GFP_KERNEL);
Joe Perchese404dec2012-01-29 12:56:23 +00002673 if (good_mbuf == NULL)
Michael Chanb6016b72005-05-26 13:03:09 -07002674 return -ENOMEM;
Michael Chanb6016b72005-05-26 13:03:09 -07002675
Michael Chane503e062012-12-06 10:33:08 +00002676 BNX2_WR(bp, BNX2_MISC_ENABLE_SET_BITS,
Michael Chanb6016b72005-05-26 13:03:09 -07002677 BNX2_MISC_ENABLE_SET_BITS_RX_MBUF_ENABLE);
2678
2679 good_mbuf_cnt = 0;
2680
2681 /* Allocate a bunch of mbufs and save the good ones in an array. */
Michael Chan2726d6e2008-01-29 21:35:05 -08002682 val = bnx2_reg_rd_ind(bp, BNX2_RBUF_STATUS1);
Michael Chanb6016b72005-05-26 13:03:09 -07002683 while (val & BNX2_RBUF_STATUS1_FREE_COUNT) {
Michael Chan2726d6e2008-01-29 21:35:05 -08002684 bnx2_reg_wr_ind(bp, BNX2_RBUF_COMMAND,
2685 BNX2_RBUF_COMMAND_ALLOC_REQ);
Michael Chanb6016b72005-05-26 13:03:09 -07002686
Michael Chan2726d6e2008-01-29 21:35:05 -08002687 val = bnx2_reg_rd_ind(bp, BNX2_RBUF_FW_BUF_ALLOC);
Michael Chanb6016b72005-05-26 13:03:09 -07002688
2689 val &= BNX2_RBUF_FW_BUF_ALLOC_VALUE;
2690
2691 /* The addresses with Bit 9 set are bad memory blocks. */
2692 if (!(val & (1 << 9))) {
2693 good_mbuf[good_mbuf_cnt] = (u16) val;
2694 good_mbuf_cnt++;
2695 }
2696
Michael Chan2726d6e2008-01-29 21:35:05 -08002697 val = bnx2_reg_rd_ind(bp, BNX2_RBUF_STATUS1);
Michael Chanb6016b72005-05-26 13:03:09 -07002698 }
2699
2700 /* Free the good ones back to the mbuf pool thus discarding
2701 * all the bad ones. */
2702 while (good_mbuf_cnt) {
2703 good_mbuf_cnt--;
2704
2705 val = good_mbuf[good_mbuf_cnt];
2706 val = (val << 9) | val | 1;
2707
Michael Chan2726d6e2008-01-29 21:35:05 -08002708 bnx2_reg_wr_ind(bp, BNX2_RBUF_FW_BUF_FREE, val);
Michael Chanb6016b72005-05-26 13:03:09 -07002709 }
2710 kfree(good_mbuf);
2711 return 0;
2712}
2713
2714static void
Benjamin Li5fcaed02008-07-14 22:39:52 -07002715bnx2_set_mac_addr(struct bnx2 *bp, u8 *mac_addr, u32 pos)
Michael Chanb6016b72005-05-26 13:03:09 -07002716{
2717 u32 val;
Michael Chanb6016b72005-05-26 13:03:09 -07002718
2719 val = (mac_addr[0] << 8) | mac_addr[1];
2720
Michael Chane503e062012-12-06 10:33:08 +00002721 BNX2_WR(bp, BNX2_EMAC_MAC_MATCH0 + (pos * 8), val);
Michael Chanb6016b72005-05-26 13:03:09 -07002722
Jeff Garzik6aa20a22006-09-13 13:24:59 -04002723 val = (mac_addr[2] << 24) | (mac_addr[3] << 16) |
Michael Chanb6016b72005-05-26 13:03:09 -07002724 (mac_addr[4] << 8) | mac_addr[5];
2725
Michael Chane503e062012-12-06 10:33:08 +00002726 BNX2_WR(bp, BNX2_EMAC_MAC_MATCH1 + (pos * 8), val);
Michael Chanb6016b72005-05-26 13:03:09 -07002727}
2728
2729static inline int
Stanislaw Gruszkaa2df00a2010-07-15 22:55:40 +00002730bnx2_alloc_rx_page(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr, u16 index, gfp_t gfp)
Michael Chan47bf4242007-12-12 11:19:12 -08002731{
2732 dma_addr_t mapping;
Michael Chan2bc40782012-12-06 10:33:09 +00002733 struct bnx2_sw_pg *rx_pg = &rxr->rx_pg_ring[index];
2734 struct bnx2_rx_bd *rxbd =
2735 &rxr->rx_pg_desc_ring[BNX2_RX_RING(index)][BNX2_RX_IDX(index)];
Stanislaw Gruszkaa2df00a2010-07-15 22:55:40 +00002736 struct page *page = alloc_page(gfp);
Michael Chan47bf4242007-12-12 11:19:12 -08002737
2738 if (!page)
2739 return -ENOMEM;
Stanislaw Gruszka36227e82010-07-15 04:25:50 +00002740 mapping = dma_map_page(&bp->pdev->dev, page, 0, PAGE_SIZE,
Michael Chan47bf4242007-12-12 11:19:12 -08002741 PCI_DMA_FROMDEVICE);
Stanislaw Gruszka36227e82010-07-15 04:25:50 +00002742 if (dma_mapping_error(&bp->pdev->dev, mapping)) {
Benjamin Li3d16af82008-10-09 12:26:41 -07002743 __free_page(page);
2744 return -EIO;
2745 }
2746
Michael Chan47bf4242007-12-12 11:19:12 -08002747 rx_pg->page = page;
FUJITA Tomonori1a4ccc22010-04-01 16:56:57 +00002748 dma_unmap_addr_set(rx_pg, mapping, mapping);
Michael Chan47bf4242007-12-12 11:19:12 -08002749 rxbd->rx_bd_haddr_hi = (u64) mapping >> 32;
2750 rxbd->rx_bd_haddr_lo = (u64) mapping & 0xffffffff;
2751 return 0;
2752}
2753
2754static void
Michael Chanbb4f98a2008-06-19 16:38:19 -07002755bnx2_free_rx_page(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr, u16 index)
Michael Chan47bf4242007-12-12 11:19:12 -08002756{
Michael Chan2bc40782012-12-06 10:33:09 +00002757 struct bnx2_sw_pg *rx_pg = &rxr->rx_pg_ring[index];
Michael Chan47bf4242007-12-12 11:19:12 -08002758 struct page *page = rx_pg->page;
2759
2760 if (!page)
2761 return;
2762
Stanislaw Gruszka36227e82010-07-15 04:25:50 +00002763 dma_unmap_page(&bp->pdev->dev, dma_unmap_addr(rx_pg, mapping),
2764 PAGE_SIZE, PCI_DMA_FROMDEVICE);
Michael Chan47bf4242007-12-12 11:19:12 -08002765
2766 __free_page(page);
2767 rx_pg->page = NULL;
2768}
2769
2770static inline int
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00002771bnx2_alloc_rx_data(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr, u16 index, gfp_t gfp)
Michael Chanb6016b72005-05-26 13:03:09 -07002772{
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00002773 u8 *data;
Michael Chan2bc40782012-12-06 10:33:09 +00002774 struct bnx2_sw_bd *rx_buf = &rxr->rx_buf_ring[index];
Michael Chanb6016b72005-05-26 13:03:09 -07002775 dma_addr_t mapping;
Michael Chan2bc40782012-12-06 10:33:09 +00002776 struct bnx2_rx_bd *rxbd =
2777 &rxr->rx_desc_ring[BNX2_RX_RING(index)][BNX2_RX_IDX(index)];
Michael Chanb6016b72005-05-26 13:03:09 -07002778
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00002779 data = kmalloc(bp->rx_buf_size, gfp);
2780 if (!data)
Michael Chanb6016b72005-05-26 13:03:09 -07002781 return -ENOMEM;
Michael Chanb6016b72005-05-26 13:03:09 -07002782
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00002783 mapping = dma_map_single(&bp->pdev->dev,
2784 get_l2_fhdr(data),
2785 bp->rx_buf_use_size,
Stanislaw Gruszka36227e82010-07-15 04:25:50 +00002786 PCI_DMA_FROMDEVICE);
2787 if (dma_mapping_error(&bp->pdev->dev, mapping)) {
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00002788 kfree(data);
Benjamin Li3d16af82008-10-09 12:26:41 -07002789 return -EIO;
2790 }
Michael Chanb6016b72005-05-26 13:03:09 -07002791
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00002792 rx_buf->data = data;
FUJITA Tomonori1a4ccc22010-04-01 16:56:57 +00002793 dma_unmap_addr_set(rx_buf, mapping, mapping);
Michael Chanb6016b72005-05-26 13:03:09 -07002794
2795 rxbd->rx_bd_haddr_hi = (u64) mapping >> 32;
2796 rxbd->rx_bd_haddr_lo = (u64) mapping & 0xffffffff;
2797
Michael Chanbb4f98a2008-06-19 16:38:19 -07002798 rxr->rx_prod_bseq += bp->rx_buf_use_size;
Michael Chanb6016b72005-05-26 13:03:09 -07002799
2800 return 0;
2801}
2802
Michael Chanda3e4fb2007-05-03 13:24:23 -07002803static int
Michael Chan35efa7c2007-12-20 19:56:37 -08002804bnx2_phy_event_is_set(struct bnx2 *bp, struct bnx2_napi *bnapi, u32 event)
Michael Chanda3e4fb2007-05-03 13:24:23 -07002805{
Michael Chan43e80b82008-06-19 16:41:08 -07002806 struct status_block *sblk = bnapi->status_blk.msi;
Michael Chanda3e4fb2007-05-03 13:24:23 -07002807 u32 new_link_state, old_link_state;
2808 int is_set = 1;
2809
2810 new_link_state = sblk->status_attn_bits & event;
2811 old_link_state = sblk->status_attn_bits_ack & event;
2812 if (new_link_state != old_link_state) {
2813 if (new_link_state)
Michael Chane503e062012-12-06 10:33:08 +00002814 BNX2_WR(bp, BNX2_PCICFG_STATUS_BIT_SET_CMD, event);
Michael Chanda3e4fb2007-05-03 13:24:23 -07002815 else
Michael Chane503e062012-12-06 10:33:08 +00002816 BNX2_WR(bp, BNX2_PCICFG_STATUS_BIT_CLEAR_CMD, event);
Michael Chanda3e4fb2007-05-03 13:24:23 -07002817 } else
2818 is_set = 0;
2819
2820 return is_set;
2821}
2822
Michael Chanb6016b72005-05-26 13:03:09 -07002823static void
Michael Chan35efa7c2007-12-20 19:56:37 -08002824bnx2_phy_int(struct bnx2 *bp, struct bnx2_napi *bnapi)
Michael Chanb6016b72005-05-26 13:03:09 -07002825{
Michael Chan74ecc622008-05-02 16:56:16 -07002826 spin_lock(&bp->phy_lock);
2827
2828 if (bnx2_phy_event_is_set(bp, bnapi, STATUS_ATTN_BITS_LINK_STATE))
Michael Chanb6016b72005-05-26 13:03:09 -07002829 bnx2_set_link(bp);
Michael Chan35efa7c2007-12-20 19:56:37 -08002830 if (bnx2_phy_event_is_set(bp, bnapi, STATUS_ATTN_BITS_TIMER_ABORT))
Michael Chan0d8a6572007-07-07 22:49:43 -07002831 bnx2_set_remote_link(bp);
2832
Michael Chan74ecc622008-05-02 16:56:16 -07002833 spin_unlock(&bp->phy_lock);
2834
Michael Chanb6016b72005-05-26 13:03:09 -07002835}
2836
Michael Chanead72702007-12-20 19:55:39 -08002837static inline u16
Michael Chan35efa7c2007-12-20 19:56:37 -08002838bnx2_get_hw_tx_cons(struct bnx2_napi *bnapi)
Michael Chanead72702007-12-20 19:55:39 -08002839{
2840 u16 cons;
2841
Michael Chan43e80b82008-06-19 16:41:08 -07002842 /* Tell compiler that status block fields can change. */
2843 barrier();
2844 cons = *bnapi->hw_tx_cons_ptr;
Michael Chan581daf72009-05-06 16:46:47 -07002845 barrier();
Michael Chan2bc40782012-12-06 10:33:09 +00002846 if (unlikely((cons & BNX2_MAX_TX_DESC_CNT) == BNX2_MAX_TX_DESC_CNT))
Michael Chanead72702007-12-20 19:55:39 -08002847 cons++;
2848 return cons;
2849}
2850
Michael Chan57851d82007-12-20 20:01:44 -08002851static int
2852bnx2_tx_int(struct bnx2 *bp, struct bnx2_napi *bnapi, int budget)
Michael Chanb6016b72005-05-26 13:03:09 -07002853{
Michael Chan35e90102008-06-19 16:37:42 -07002854 struct bnx2_tx_ring_info *txr = &bnapi->tx_ring;
Michael Chanb6016b72005-05-26 13:03:09 -07002855 u16 hw_cons, sw_cons, sw_ring_cons;
Benjamin Li706bf242008-07-18 17:55:11 -07002856 int tx_pkt = 0, index;
Eric Dumazete9831902011-11-29 11:53:05 +00002857 unsigned int tx_bytes = 0;
Benjamin Li706bf242008-07-18 17:55:11 -07002858 struct netdev_queue *txq;
2859
2860 index = (bnapi - bp->bnx2_napi);
2861 txq = netdev_get_tx_queue(bp->dev, index);
Michael Chanb6016b72005-05-26 13:03:09 -07002862
Michael Chan35efa7c2007-12-20 19:56:37 -08002863 hw_cons = bnx2_get_hw_tx_cons(bnapi);
Michael Chan35e90102008-06-19 16:37:42 -07002864 sw_cons = txr->tx_cons;
Michael Chanb6016b72005-05-26 13:03:09 -07002865
2866 while (sw_cons != hw_cons) {
Michael Chan2bc40782012-12-06 10:33:09 +00002867 struct bnx2_sw_tx_bd *tx_buf;
Michael Chanb6016b72005-05-26 13:03:09 -07002868 struct sk_buff *skb;
2869 int i, last;
2870
Michael Chan2bc40782012-12-06 10:33:09 +00002871 sw_ring_cons = BNX2_TX_RING_IDX(sw_cons);
Michael Chanb6016b72005-05-26 13:03:09 -07002872
Michael Chan35e90102008-06-19 16:37:42 -07002873 tx_buf = &txr->tx_buf_ring[sw_ring_cons];
Michael Chanb6016b72005-05-26 13:03:09 -07002874 skb = tx_buf->skb;
Arjan van de Ven1d39ed52006-12-12 14:06:23 +01002875
Eric Dumazetd62fda02009-05-12 20:48:02 +00002876 /* prefetch skb_end_pointer() to speedup skb_shinfo(skb) */
2877 prefetch(&skb->end);
2878
Michael Chanb6016b72005-05-26 13:03:09 -07002879 /* partial BD completions possible with TSO packets */
Eric Dumazetd62fda02009-05-12 20:48:02 +00002880 if (tx_buf->is_gso) {
Michael Chanb6016b72005-05-26 13:03:09 -07002881 u16 last_idx, last_ring_idx;
2882
Eric Dumazetd62fda02009-05-12 20:48:02 +00002883 last_idx = sw_cons + tx_buf->nr_frags + 1;
2884 last_ring_idx = sw_ring_cons + tx_buf->nr_frags + 1;
Michael Chan2bc40782012-12-06 10:33:09 +00002885 if (unlikely(last_ring_idx >= BNX2_MAX_TX_DESC_CNT)) {
Michael Chanb6016b72005-05-26 13:03:09 -07002886 last_idx++;
2887 }
2888 if (((s16) ((s16) last_idx - (s16) hw_cons)) > 0) {
2889 break;
2890 }
2891 }
Arjan van de Ven1d39ed52006-12-12 14:06:23 +01002892
Stanislaw Gruszka36227e82010-07-15 04:25:50 +00002893 dma_unmap_single(&bp->pdev->dev, dma_unmap_addr(tx_buf, mapping),
Alexander Duycke95524a2009-12-02 16:47:57 +00002894 skb_headlen(skb), PCI_DMA_TODEVICE);
Michael Chanb6016b72005-05-26 13:03:09 -07002895
2896 tx_buf->skb = NULL;
Eric Dumazetd62fda02009-05-12 20:48:02 +00002897 last = tx_buf->nr_frags;
Michael Chanb6016b72005-05-26 13:03:09 -07002898
2899 for (i = 0; i < last; i++) {
Michael Chan2bc40782012-12-06 10:33:09 +00002900 struct bnx2_sw_tx_bd *tx_buf;
Alexander Duycke95524a2009-12-02 16:47:57 +00002901
Michael Chan2bc40782012-12-06 10:33:09 +00002902 sw_cons = BNX2_NEXT_TX_BD(sw_cons);
2903
2904 tx_buf = &txr->tx_buf_ring[BNX2_TX_RING_IDX(sw_cons)];
Stanislaw Gruszka36227e82010-07-15 04:25:50 +00002905 dma_unmap_page(&bp->pdev->dev,
Michael Chan2bc40782012-12-06 10:33:09 +00002906 dma_unmap_addr(tx_buf, mapping),
Eric Dumazet9e903e02011-10-18 21:00:24 +00002907 skb_frag_size(&skb_shinfo(skb)->frags[i]),
Alexander Duycke95524a2009-12-02 16:47:57 +00002908 PCI_DMA_TODEVICE);
Michael Chanb6016b72005-05-26 13:03:09 -07002909 }
2910
Michael Chan2bc40782012-12-06 10:33:09 +00002911 sw_cons = BNX2_NEXT_TX_BD(sw_cons);
Michael Chanb6016b72005-05-26 13:03:09 -07002912
Eric Dumazete9831902011-11-29 11:53:05 +00002913 tx_bytes += skb->len;
Eric W. Biedermanf458b2e2014-03-11 14:17:41 -07002914 dev_kfree_skb_any(skb);
Michael Chan57851d82007-12-20 20:01:44 -08002915 tx_pkt++;
2916 if (tx_pkt == budget)
2917 break;
Michael Chanb6016b72005-05-26 13:03:09 -07002918
Eric Dumazetd62fda02009-05-12 20:48:02 +00002919 if (hw_cons == sw_cons)
2920 hw_cons = bnx2_get_hw_tx_cons(bnapi);
Michael Chanb6016b72005-05-26 13:03:09 -07002921 }
2922
Eric Dumazete9831902011-11-29 11:53:05 +00002923 netdev_tx_completed_queue(txq, tx_pkt, tx_bytes);
Michael Chan35e90102008-06-19 16:37:42 -07002924 txr->hw_tx_cons = hw_cons;
2925 txr->tx_cons = sw_cons;
Benjamin Li706bf242008-07-18 17:55:11 -07002926
Michael Chan2f8af122006-08-15 01:39:10 -07002927 /* Need to make the tx_cons update visible to bnx2_start_xmit()
Benjamin Li706bf242008-07-18 17:55:11 -07002928 * before checking for netif_tx_queue_stopped(). Without the
Michael Chan2f8af122006-08-15 01:39:10 -07002929 * memory barrier, there is a small possibility that bnx2_start_xmit()
2930 * will miss it and cause the queue to be stopped forever.
2931 */
2932 smp_mb();
Michael Chanb6016b72005-05-26 13:03:09 -07002933
Benjamin Li706bf242008-07-18 17:55:11 -07002934 if (unlikely(netif_tx_queue_stopped(txq)) &&
Michael Chan35e90102008-06-19 16:37:42 -07002935 (bnx2_tx_avail(bp, txr) > bp->tx_wake_thresh)) {
Benjamin Li706bf242008-07-18 17:55:11 -07002936 __netif_tx_lock(txq, smp_processor_id());
2937 if ((netif_tx_queue_stopped(txq)) &&
Michael Chan35e90102008-06-19 16:37:42 -07002938 (bnx2_tx_avail(bp, txr) > bp->tx_wake_thresh))
Benjamin Li706bf242008-07-18 17:55:11 -07002939 netif_tx_wake_queue(txq);
2940 __netif_tx_unlock(txq);
Michael Chanb6016b72005-05-26 13:03:09 -07002941 }
Benjamin Li706bf242008-07-18 17:55:11 -07002942
Michael Chan57851d82007-12-20 20:01:44 -08002943 return tx_pkt;
Michael Chanb6016b72005-05-26 13:03:09 -07002944}
2945
Michael Chan1db82f22007-12-12 11:19:35 -08002946static void
Michael Chanbb4f98a2008-06-19 16:38:19 -07002947bnx2_reuse_rx_skb_pages(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr,
Michael Chana1f60192007-12-20 19:57:19 -08002948 struct sk_buff *skb, int count)
Michael Chan1db82f22007-12-12 11:19:35 -08002949{
Michael Chan2bc40782012-12-06 10:33:09 +00002950 struct bnx2_sw_pg *cons_rx_pg, *prod_rx_pg;
2951 struct bnx2_rx_bd *cons_bd, *prod_bd;
Michael Chan1db82f22007-12-12 11:19:35 -08002952 int i;
Benjamin Li3d16af82008-10-09 12:26:41 -07002953 u16 hw_prod, prod;
Michael Chanbb4f98a2008-06-19 16:38:19 -07002954 u16 cons = rxr->rx_pg_cons;
Michael Chan1db82f22007-12-12 11:19:35 -08002955
Benjamin Li3d16af82008-10-09 12:26:41 -07002956 cons_rx_pg = &rxr->rx_pg_ring[cons];
2957
2958 /* The caller was unable to allocate a new page to replace the
2959 * last one in the frags array, so we need to recycle that page
2960 * and then free the skb.
2961 */
2962 if (skb) {
2963 struct page *page;
2964 struct skb_shared_info *shinfo;
2965
2966 shinfo = skb_shinfo(skb);
2967 shinfo->nr_frags--;
Ian Campbellb7b6a682011-08-24 22:28:12 +00002968 page = skb_frag_page(&shinfo->frags[shinfo->nr_frags]);
2969 __skb_frag_set_page(&shinfo->frags[shinfo->nr_frags], NULL);
Benjamin Li3d16af82008-10-09 12:26:41 -07002970
2971 cons_rx_pg->page = page;
2972 dev_kfree_skb(skb);
2973 }
2974
2975 hw_prod = rxr->rx_pg_prod;
2976
Michael Chan1db82f22007-12-12 11:19:35 -08002977 for (i = 0; i < count; i++) {
Michael Chan2bc40782012-12-06 10:33:09 +00002978 prod = BNX2_RX_PG_RING_IDX(hw_prod);
Michael Chan1db82f22007-12-12 11:19:35 -08002979
Michael Chanbb4f98a2008-06-19 16:38:19 -07002980 prod_rx_pg = &rxr->rx_pg_ring[prod];
2981 cons_rx_pg = &rxr->rx_pg_ring[cons];
Michael Chan2bc40782012-12-06 10:33:09 +00002982 cons_bd = &rxr->rx_pg_desc_ring[BNX2_RX_RING(cons)]
2983 [BNX2_RX_IDX(cons)];
2984 prod_bd = &rxr->rx_pg_desc_ring[BNX2_RX_RING(prod)]
2985 [BNX2_RX_IDX(prod)];
Michael Chan1db82f22007-12-12 11:19:35 -08002986
Michael Chan1db82f22007-12-12 11:19:35 -08002987 if (prod != cons) {
2988 prod_rx_pg->page = cons_rx_pg->page;
2989 cons_rx_pg->page = NULL;
FUJITA Tomonori1a4ccc22010-04-01 16:56:57 +00002990 dma_unmap_addr_set(prod_rx_pg, mapping,
2991 dma_unmap_addr(cons_rx_pg, mapping));
Michael Chan1db82f22007-12-12 11:19:35 -08002992
2993 prod_bd->rx_bd_haddr_hi = cons_bd->rx_bd_haddr_hi;
2994 prod_bd->rx_bd_haddr_lo = cons_bd->rx_bd_haddr_lo;
2995
2996 }
Michael Chan2bc40782012-12-06 10:33:09 +00002997 cons = BNX2_RX_PG_RING_IDX(BNX2_NEXT_RX_BD(cons));
2998 hw_prod = BNX2_NEXT_RX_BD(hw_prod);
Michael Chan1db82f22007-12-12 11:19:35 -08002999 }
Michael Chanbb4f98a2008-06-19 16:38:19 -07003000 rxr->rx_pg_prod = hw_prod;
3001 rxr->rx_pg_cons = cons;
Michael Chan1db82f22007-12-12 11:19:35 -08003002}
3003
Michael Chanb6016b72005-05-26 13:03:09 -07003004static inline void
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00003005bnx2_reuse_rx_data(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr,
3006 u8 *data, u16 cons, u16 prod)
Michael Chanb6016b72005-05-26 13:03:09 -07003007{
Michael Chan2bc40782012-12-06 10:33:09 +00003008 struct bnx2_sw_bd *cons_rx_buf, *prod_rx_buf;
3009 struct bnx2_rx_bd *cons_bd, *prod_bd;
Michael Chan236b6392006-03-20 17:49:02 -08003010
Michael Chanbb4f98a2008-06-19 16:38:19 -07003011 cons_rx_buf = &rxr->rx_buf_ring[cons];
3012 prod_rx_buf = &rxr->rx_buf_ring[prod];
Michael Chanb6016b72005-05-26 13:03:09 -07003013
Stanislaw Gruszka36227e82010-07-15 04:25:50 +00003014 dma_sync_single_for_device(&bp->pdev->dev,
FUJITA Tomonori1a4ccc22010-04-01 16:56:57 +00003015 dma_unmap_addr(cons_rx_buf, mapping),
Benjamin Li601d3d12008-05-16 22:19:35 -07003016 BNX2_RX_OFFSET + BNX2_RX_COPY_THRESH, PCI_DMA_FROMDEVICE);
Michael Chanb6016b72005-05-26 13:03:09 -07003017
Michael Chanbb4f98a2008-06-19 16:38:19 -07003018 rxr->rx_prod_bseq += bp->rx_buf_use_size;
Michael Chan236b6392006-03-20 17:49:02 -08003019
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00003020 prod_rx_buf->data = data;
Michael Chan236b6392006-03-20 17:49:02 -08003021
3022 if (cons == prod)
3023 return;
3024
FUJITA Tomonori1a4ccc22010-04-01 16:56:57 +00003025 dma_unmap_addr_set(prod_rx_buf, mapping,
3026 dma_unmap_addr(cons_rx_buf, mapping));
Michael Chanb6016b72005-05-26 13:03:09 -07003027
Michael Chan2bc40782012-12-06 10:33:09 +00003028 cons_bd = &rxr->rx_desc_ring[BNX2_RX_RING(cons)][BNX2_RX_IDX(cons)];
3029 prod_bd = &rxr->rx_desc_ring[BNX2_RX_RING(prod)][BNX2_RX_IDX(prod)];
Michael Chan236b6392006-03-20 17:49:02 -08003030 prod_bd->rx_bd_haddr_hi = cons_bd->rx_bd_haddr_hi;
3031 prod_bd->rx_bd_haddr_lo = cons_bd->rx_bd_haddr_lo;
Michael Chanb6016b72005-05-26 13:03:09 -07003032}
3033
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00003034static struct sk_buff *
3035bnx2_rx_skb(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr, u8 *data,
Michael Chana1f60192007-12-20 19:57:19 -08003036 unsigned int len, unsigned int hdr_len, dma_addr_t dma_addr,
3037 u32 ring_idx)
Michael Chan85833c62007-12-12 11:17:01 -08003038{
3039 int err;
3040 u16 prod = ring_idx & 0xffff;
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00003041 struct sk_buff *skb;
Michael Chan85833c62007-12-12 11:17:01 -08003042
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00003043 err = bnx2_alloc_rx_data(bp, rxr, prod, GFP_ATOMIC);
Michael Chan85833c62007-12-12 11:17:01 -08003044 if (unlikely(err)) {
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00003045 bnx2_reuse_rx_data(bp, rxr, data, (u16) (ring_idx >> 16), prod);
3046error:
Michael Chan1db82f22007-12-12 11:19:35 -08003047 if (hdr_len) {
3048 unsigned int raw_len = len + 4;
3049 int pages = PAGE_ALIGN(raw_len - hdr_len) >> PAGE_SHIFT;
3050
Michael Chanbb4f98a2008-06-19 16:38:19 -07003051 bnx2_reuse_rx_skb_pages(bp, rxr, NULL, pages);
Michael Chan1db82f22007-12-12 11:19:35 -08003052 }
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00003053 return NULL;
Michael Chan85833c62007-12-12 11:17:01 -08003054 }
3055
Stanislaw Gruszka36227e82010-07-15 04:25:50 +00003056 dma_unmap_single(&bp->pdev->dev, dma_addr, bp->rx_buf_use_size,
Michael Chan85833c62007-12-12 11:17:01 -08003057 PCI_DMA_FROMDEVICE);
Eric Dumazetd3836f22012-04-27 00:33:38 +00003058 skb = build_skb(data, 0);
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00003059 if (!skb) {
3060 kfree(data);
3061 goto error;
3062 }
3063 skb_reserve(skb, ((u8 *)get_l2_fhdr(data) - data) + BNX2_RX_OFFSET);
Michael Chan1db82f22007-12-12 11:19:35 -08003064 if (hdr_len == 0) {
3065 skb_put(skb, len);
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00003066 return skb;
Michael Chan1db82f22007-12-12 11:19:35 -08003067 } else {
3068 unsigned int i, frag_len, frag_size, pages;
Michael Chan2bc40782012-12-06 10:33:09 +00003069 struct bnx2_sw_pg *rx_pg;
Michael Chanbb4f98a2008-06-19 16:38:19 -07003070 u16 pg_cons = rxr->rx_pg_cons;
3071 u16 pg_prod = rxr->rx_pg_prod;
Michael Chan1db82f22007-12-12 11:19:35 -08003072
3073 frag_size = len + 4 - hdr_len;
3074 pages = PAGE_ALIGN(frag_size) >> PAGE_SHIFT;
3075 skb_put(skb, hdr_len);
3076
3077 for (i = 0; i < pages; i++) {
Benjamin Li3d16af82008-10-09 12:26:41 -07003078 dma_addr_t mapping_old;
3079
Michael Chan1db82f22007-12-12 11:19:35 -08003080 frag_len = min(frag_size, (unsigned int) PAGE_SIZE);
3081 if (unlikely(frag_len <= 4)) {
3082 unsigned int tail = 4 - frag_len;
3083
Michael Chanbb4f98a2008-06-19 16:38:19 -07003084 rxr->rx_pg_cons = pg_cons;
3085 rxr->rx_pg_prod = pg_prod;
3086 bnx2_reuse_rx_skb_pages(bp, rxr, NULL,
Michael Chana1f60192007-12-20 19:57:19 -08003087 pages - i);
Michael Chan1db82f22007-12-12 11:19:35 -08003088 skb->len -= tail;
3089 if (i == 0) {
3090 skb->tail -= tail;
3091 } else {
3092 skb_frag_t *frag =
3093 &skb_shinfo(skb)->frags[i - 1];
Eric Dumazet9e903e02011-10-18 21:00:24 +00003094 skb_frag_size_sub(frag, tail);
Michael Chan1db82f22007-12-12 11:19:35 -08003095 skb->data_len -= tail;
Michael Chan1db82f22007-12-12 11:19:35 -08003096 }
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00003097 return skb;
Michael Chan1db82f22007-12-12 11:19:35 -08003098 }
Michael Chanbb4f98a2008-06-19 16:38:19 -07003099 rx_pg = &rxr->rx_pg_ring[pg_cons];
Michael Chan1db82f22007-12-12 11:19:35 -08003100
Benjamin Li3d16af82008-10-09 12:26:41 -07003101 /* Don't unmap yet. If we're unable to allocate a new
3102 * page, we need to recycle the page and the DMA addr.
3103 */
FUJITA Tomonori1a4ccc22010-04-01 16:56:57 +00003104 mapping_old = dma_unmap_addr(rx_pg, mapping);
Michael Chan1db82f22007-12-12 11:19:35 -08003105 if (i == pages - 1)
3106 frag_len -= 4;
3107
3108 skb_fill_page_desc(skb, i, rx_pg->page, 0, frag_len);
3109 rx_pg->page = NULL;
3110
Michael Chanbb4f98a2008-06-19 16:38:19 -07003111 err = bnx2_alloc_rx_page(bp, rxr,
Michael Chan2bc40782012-12-06 10:33:09 +00003112 BNX2_RX_PG_RING_IDX(pg_prod),
Stanislaw Gruszkaa2df00a2010-07-15 22:55:40 +00003113 GFP_ATOMIC);
Michael Chan1db82f22007-12-12 11:19:35 -08003114 if (unlikely(err)) {
Michael Chanbb4f98a2008-06-19 16:38:19 -07003115 rxr->rx_pg_cons = pg_cons;
3116 rxr->rx_pg_prod = pg_prod;
3117 bnx2_reuse_rx_skb_pages(bp, rxr, skb,
Michael Chana1f60192007-12-20 19:57:19 -08003118 pages - i);
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00003119 return NULL;
Michael Chan1db82f22007-12-12 11:19:35 -08003120 }
3121
Stanislaw Gruszka36227e82010-07-15 04:25:50 +00003122 dma_unmap_page(&bp->pdev->dev, mapping_old,
Benjamin Li3d16af82008-10-09 12:26:41 -07003123 PAGE_SIZE, PCI_DMA_FROMDEVICE);
3124
Michael Chan1db82f22007-12-12 11:19:35 -08003125 frag_size -= frag_len;
3126 skb->data_len += frag_len;
Eric Dumazeta1f4e8b2011-10-13 07:50:19 +00003127 skb->truesize += PAGE_SIZE;
Michael Chan1db82f22007-12-12 11:19:35 -08003128 skb->len += frag_len;
3129
Michael Chan2bc40782012-12-06 10:33:09 +00003130 pg_prod = BNX2_NEXT_RX_BD(pg_prod);
3131 pg_cons = BNX2_RX_PG_RING_IDX(BNX2_NEXT_RX_BD(pg_cons));
Michael Chan1db82f22007-12-12 11:19:35 -08003132 }
Michael Chanbb4f98a2008-06-19 16:38:19 -07003133 rxr->rx_pg_prod = pg_prod;
3134 rxr->rx_pg_cons = pg_cons;
Michael Chan1db82f22007-12-12 11:19:35 -08003135 }
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00003136 return skb;
Michael Chan85833c62007-12-12 11:17:01 -08003137}
3138
Michael Chanc09c2622007-12-10 17:18:37 -08003139static inline u16
Michael Chan35efa7c2007-12-20 19:56:37 -08003140bnx2_get_hw_rx_cons(struct bnx2_napi *bnapi)
Michael Chanc09c2622007-12-10 17:18:37 -08003141{
Michael Chanbb4f98a2008-06-19 16:38:19 -07003142 u16 cons;
3143
Michael Chan43e80b82008-06-19 16:41:08 -07003144 /* Tell compiler that status block fields can change. */
3145 barrier();
3146 cons = *bnapi->hw_rx_cons_ptr;
Michael Chan581daf72009-05-06 16:46:47 -07003147 barrier();
Michael Chan2bc40782012-12-06 10:33:09 +00003148 if (unlikely((cons & BNX2_MAX_RX_DESC_CNT) == BNX2_MAX_RX_DESC_CNT))
Michael Chanc09c2622007-12-10 17:18:37 -08003149 cons++;
3150 return cons;
3151}
3152
Michael Chanb6016b72005-05-26 13:03:09 -07003153static int
Michael Chan35efa7c2007-12-20 19:56:37 -08003154bnx2_rx_int(struct bnx2 *bp, struct bnx2_napi *bnapi, int budget)
Michael Chanb6016b72005-05-26 13:03:09 -07003155{
Michael Chanbb4f98a2008-06-19 16:38:19 -07003156 struct bnx2_rx_ring_info *rxr = &bnapi->rx_ring;
Michael Chanb6016b72005-05-26 13:03:09 -07003157 u16 hw_cons, sw_cons, sw_ring_cons, sw_prod, sw_ring_prod;
3158 struct l2_fhdr *rx_hdr;
Michael Chan1db82f22007-12-12 11:19:35 -08003159 int rx_pkt = 0, pg_ring_used = 0;
Michael Chanb6016b72005-05-26 13:03:09 -07003160
Eric W. Biederman310c4d42014-03-11 14:31:09 -07003161 if (budget <= 0)
3162 return rx_pkt;
3163
Michael Chan35efa7c2007-12-20 19:56:37 -08003164 hw_cons = bnx2_get_hw_rx_cons(bnapi);
Michael Chanbb4f98a2008-06-19 16:38:19 -07003165 sw_cons = rxr->rx_cons;
3166 sw_prod = rxr->rx_prod;
Michael Chanb6016b72005-05-26 13:03:09 -07003167
3168 /* Memory barrier necessary as speculative reads of the rx
3169 * buffer can be ahead of the index in the status block
3170 */
3171 rmb();
3172 while (sw_cons != hw_cons) {
Michael Chan1db82f22007-12-12 11:19:35 -08003173 unsigned int len, hdr_len;
Michael Chanade2bfe2006-01-23 16:09:51 -08003174 u32 status;
Michael Chan2bc40782012-12-06 10:33:09 +00003175 struct bnx2_sw_bd *rx_buf, *next_rx_buf;
Michael Chanb6016b72005-05-26 13:03:09 -07003176 struct sk_buff *skb;
Michael Chan236b6392006-03-20 17:49:02 -08003177 dma_addr_t dma_addr;
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00003178 u8 *data;
Michael Chan2bc40782012-12-06 10:33:09 +00003179 u16 next_ring_idx;
Michael Chanb6016b72005-05-26 13:03:09 -07003180
Michael Chan2bc40782012-12-06 10:33:09 +00003181 sw_ring_cons = BNX2_RX_RING_IDX(sw_cons);
3182 sw_ring_prod = BNX2_RX_RING_IDX(sw_prod);
Michael Chanb6016b72005-05-26 13:03:09 -07003183
Michael Chanbb4f98a2008-06-19 16:38:19 -07003184 rx_buf = &rxr->rx_buf_ring[sw_ring_cons];
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00003185 data = rx_buf->data;
3186 rx_buf->data = NULL;
Michael Chan236b6392006-03-20 17:49:02 -08003187
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00003188 rx_hdr = get_l2_fhdr(data);
3189 prefetch(rx_hdr);
Michael Chan236b6392006-03-20 17:49:02 -08003190
FUJITA Tomonori1a4ccc22010-04-01 16:56:57 +00003191 dma_addr = dma_unmap_addr(rx_buf, mapping);
Michael Chan236b6392006-03-20 17:49:02 -08003192
Stanislaw Gruszka36227e82010-07-15 04:25:50 +00003193 dma_sync_single_for_cpu(&bp->pdev->dev, dma_addr,
Benjamin Li601d3d12008-05-16 22:19:35 -07003194 BNX2_RX_OFFSET + BNX2_RX_COPY_THRESH,
3195 PCI_DMA_FROMDEVICE);
Michael Chanb6016b72005-05-26 13:03:09 -07003196
Michael Chan2bc40782012-12-06 10:33:09 +00003197 next_ring_idx = BNX2_RX_RING_IDX(BNX2_NEXT_RX_BD(sw_cons));
3198 next_rx_buf = &rxr->rx_buf_ring[next_ring_idx];
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00003199 prefetch(get_l2_fhdr(next_rx_buf->data));
3200
Michael Chan1db82f22007-12-12 11:19:35 -08003201 len = rx_hdr->l2_fhdr_pkt_len;
Michael Chan990ec382009-02-12 16:54:13 -08003202 status = rx_hdr->l2_fhdr_status;
Michael Chanb6016b72005-05-26 13:03:09 -07003203
Michael Chan1db82f22007-12-12 11:19:35 -08003204 hdr_len = 0;
3205 if (status & L2_FHDR_STATUS_SPLIT) {
3206 hdr_len = rx_hdr->l2_fhdr_ip_xsum;
3207 pg_ring_used = 1;
3208 } else if (len > bp->rx_jumbo_thresh) {
3209 hdr_len = bp->rx_jumbo_thresh;
3210 pg_ring_used = 1;
3211 }
3212
Michael Chan990ec382009-02-12 16:54:13 -08003213 if (unlikely(status & (L2_FHDR_ERRORS_BAD_CRC |
3214 L2_FHDR_ERRORS_PHY_DECODE |
3215 L2_FHDR_ERRORS_ALIGNMENT |
3216 L2_FHDR_ERRORS_TOO_SHORT |
3217 L2_FHDR_ERRORS_GIANT_FRAME))) {
3218
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00003219 bnx2_reuse_rx_data(bp, rxr, data, sw_ring_cons,
Michael Chan990ec382009-02-12 16:54:13 -08003220 sw_ring_prod);
3221 if (pg_ring_used) {
3222 int pages;
3223
3224 pages = PAGE_ALIGN(len - hdr_len) >> PAGE_SHIFT;
3225
3226 bnx2_reuse_rx_skb_pages(bp, rxr, NULL, pages);
3227 }
3228 goto next_rx;
3229 }
3230
Michael Chan1db82f22007-12-12 11:19:35 -08003231 len -= 4;
Michael Chanb6016b72005-05-26 13:03:09 -07003232
Michael Chan5d5d0012007-12-12 11:17:43 -08003233 if (len <= bp->rx_copy_thresh) {
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00003234 skb = netdev_alloc_skb(bp->dev, len + 6);
3235 if (skb == NULL) {
3236 bnx2_reuse_rx_data(bp, rxr, data, sw_ring_cons,
Michael Chan85833c62007-12-12 11:17:01 -08003237 sw_ring_prod);
3238 goto next_rx;
3239 }
Michael Chanb6016b72005-05-26 13:03:09 -07003240
3241 /* aligned copy */
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00003242 memcpy(skb->data,
3243 (u8 *)rx_hdr + BNX2_RX_OFFSET - 6,
3244 len + 6);
3245 skb_reserve(skb, 6);
3246 skb_put(skb, len);
Michael Chanb6016b72005-05-26 13:03:09 -07003247
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00003248 bnx2_reuse_rx_data(bp, rxr, data,
Michael Chanb6016b72005-05-26 13:03:09 -07003249 sw_ring_cons, sw_ring_prod);
3250
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00003251 } else {
3252 skb = bnx2_rx_skb(bp, rxr, data, len, hdr_len, dma_addr,
3253 (sw_ring_cons << 16) | sw_ring_prod);
3254 if (!skb)
3255 goto next_rx;
3256 }
Michael Chanf22828e2008-08-14 15:30:14 -07003257 if ((status & L2_FHDR_STATUS_L2_VLAN_TAG) &&
Jesse Gross7d0fd212010-10-20 13:56:09 +00003258 !(bp->rx_mode & BNX2_EMAC_RX_MODE_KEEP_VLAN_TAG))
Patrick McHardy86a9bad2013-04-19 02:04:30 +00003259 __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), rx_hdr->l2_fhdr_vlan_tag);
Michael Chanf22828e2008-08-14 15:30:14 -07003260
Michael Chanb6016b72005-05-26 13:03:09 -07003261 skb->protocol = eth_type_trans(skb, bp->dev);
3262
Vlad Yasevich1b0ecb22014-09-30 19:39:37 -04003263 if (len > (bp->dev->mtu + ETH_HLEN) &&
3264 skb->protocol != htons(0x8100) &&
3265 skb->protocol != htons(ETH_P_8021AD)) {
Michael Chanb6016b72005-05-26 13:03:09 -07003266
Michael Chan745720e2006-06-29 12:37:41 -07003267 dev_kfree_skb(skb);
Michael Chanb6016b72005-05-26 13:03:09 -07003268 goto next_rx;
3269
3270 }
3271
Eric Dumazetbc8acf22010-09-02 13:07:41 -07003272 skb_checksum_none_assert(skb);
Michał Mirosław8d7dfc22011-04-10 04:47:46 +00003273 if ((bp->dev->features & NETIF_F_RXCSUM) &&
Michael Chanb6016b72005-05-26 13:03:09 -07003274 (status & (L2_FHDR_STATUS_TCP_SEGMENT |
3275 L2_FHDR_STATUS_UDP_DATAGRAM))) {
3276
Michael Chanade2bfe2006-01-23 16:09:51 -08003277 if (likely((status & (L2_FHDR_ERRORS_TCP_XSUM |
3278 L2_FHDR_ERRORS_UDP_XSUM)) == 0))
Michael Chanb6016b72005-05-26 13:03:09 -07003279 skb->ip_summed = CHECKSUM_UNNECESSARY;
3280 }
Michael Chanfdc85412010-07-03 20:42:16 +00003281 if ((bp->dev->features & NETIF_F_RXHASH) &&
3282 ((status & L2_FHDR_STATUS_USE_RXHASH) ==
3283 L2_FHDR_STATUS_USE_RXHASH))
Tom Herbertcf1bfd62013-12-17 23:22:57 -08003284 skb_set_hash(skb, rx_hdr->l2_fhdr_hash,
3285 PKT_HASH_TYPE_L3);
Michael Chanb6016b72005-05-26 13:03:09 -07003286
David S. Miller0c8dfc82009-01-27 16:22:32 -08003287 skb_record_rx_queue(skb, bnapi - &bp->bnx2_napi[0]);
Jesse Gross7d0fd212010-10-20 13:56:09 +00003288 napi_gro_receive(&bnapi->napi, skb);
Michael Chanb6016b72005-05-26 13:03:09 -07003289 rx_pkt++;
3290
3291next_rx:
Michael Chan2bc40782012-12-06 10:33:09 +00003292 sw_cons = BNX2_NEXT_RX_BD(sw_cons);
3293 sw_prod = BNX2_NEXT_RX_BD(sw_prod);
Michael Chanb6016b72005-05-26 13:03:09 -07003294
3295 if ((rx_pkt == budget))
3296 break;
Michael Chanf4e418f2005-11-04 08:53:48 -08003297
3298 /* Refresh hw_cons to see if there is new work */
3299 if (sw_cons == hw_cons) {
Michael Chan35efa7c2007-12-20 19:56:37 -08003300 hw_cons = bnx2_get_hw_rx_cons(bnapi);
Michael Chanf4e418f2005-11-04 08:53:48 -08003301 rmb();
3302 }
Michael Chanb6016b72005-05-26 13:03:09 -07003303 }
Michael Chanbb4f98a2008-06-19 16:38:19 -07003304 rxr->rx_cons = sw_cons;
3305 rxr->rx_prod = sw_prod;
Michael Chanb6016b72005-05-26 13:03:09 -07003306
Michael Chan1db82f22007-12-12 11:19:35 -08003307 if (pg_ring_used)
Michael Chane503e062012-12-06 10:33:08 +00003308 BNX2_WR16(bp, rxr->rx_pg_bidx_addr, rxr->rx_pg_prod);
Michael Chan1db82f22007-12-12 11:19:35 -08003309
Michael Chane503e062012-12-06 10:33:08 +00003310 BNX2_WR16(bp, rxr->rx_bidx_addr, sw_prod);
Michael Chanb6016b72005-05-26 13:03:09 -07003311
Michael Chane503e062012-12-06 10:33:08 +00003312 BNX2_WR(bp, rxr->rx_bseq_addr, rxr->rx_prod_bseq);
Michael Chanb6016b72005-05-26 13:03:09 -07003313
3314 mmiowb();
3315
3316 return rx_pkt;
3317
3318}
3319
3320/* MSI ISR - The only difference between this and the INTx ISR
3321 * is that the MSI interrupt is always serviced.
3322 */
3323static irqreturn_t
David Howells7d12e782006-10-05 14:55:46 +01003324bnx2_msi(int irq, void *dev_instance)
Michael Chanb6016b72005-05-26 13:03:09 -07003325{
Michael Chanf0ea2e62008-06-19 16:41:57 -07003326 struct bnx2_napi *bnapi = dev_instance;
3327 struct bnx2 *bp = bnapi->bp;
Michael Chanb6016b72005-05-26 13:03:09 -07003328
Michael Chan43e80b82008-06-19 16:41:08 -07003329 prefetch(bnapi->status_blk.msi);
Michael Chane503e062012-12-06 10:33:08 +00003330 BNX2_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
Michael Chanb6016b72005-05-26 13:03:09 -07003331 BNX2_PCICFG_INT_ACK_CMD_USE_INT_HC_PARAM |
3332 BNX2_PCICFG_INT_ACK_CMD_MASK_INT);
3333
3334 /* Return here if interrupt is disabled. */
Michael Chan73eef4c2005-08-25 15:39:15 -07003335 if (unlikely(atomic_read(&bp->intr_sem) != 0))
3336 return IRQ_HANDLED;
Michael Chanb6016b72005-05-26 13:03:09 -07003337
Ben Hutchings288379f2009-01-19 16:43:59 -08003338 napi_schedule(&bnapi->napi);
Michael Chanb6016b72005-05-26 13:03:09 -07003339
Michael Chan73eef4c2005-08-25 15:39:15 -07003340 return IRQ_HANDLED;
Michael Chanb6016b72005-05-26 13:03:09 -07003341}
3342
3343static irqreturn_t
Michael Chan8e6a72c2007-05-03 13:24:48 -07003344bnx2_msi_1shot(int irq, void *dev_instance)
3345{
Michael Chanf0ea2e62008-06-19 16:41:57 -07003346 struct bnx2_napi *bnapi = dev_instance;
3347 struct bnx2 *bp = bnapi->bp;
Michael Chan8e6a72c2007-05-03 13:24:48 -07003348
Michael Chan43e80b82008-06-19 16:41:08 -07003349 prefetch(bnapi->status_blk.msi);
Michael Chan8e6a72c2007-05-03 13:24:48 -07003350
3351 /* Return here if interrupt is disabled. */
3352 if (unlikely(atomic_read(&bp->intr_sem) != 0))
3353 return IRQ_HANDLED;
3354
Ben Hutchings288379f2009-01-19 16:43:59 -08003355 napi_schedule(&bnapi->napi);
Michael Chan8e6a72c2007-05-03 13:24:48 -07003356
3357 return IRQ_HANDLED;
3358}
3359
3360static irqreturn_t
David Howells7d12e782006-10-05 14:55:46 +01003361bnx2_interrupt(int irq, void *dev_instance)
Michael Chanb6016b72005-05-26 13:03:09 -07003362{
Michael Chanf0ea2e62008-06-19 16:41:57 -07003363 struct bnx2_napi *bnapi = dev_instance;
3364 struct bnx2 *bp = bnapi->bp;
Michael Chan43e80b82008-06-19 16:41:08 -07003365 struct status_block *sblk = bnapi->status_blk.msi;
Michael Chanb6016b72005-05-26 13:03:09 -07003366
3367 /* When using INTx, it is possible for the interrupt to arrive
3368 * at the CPU before the status block posted prior to the
3369 * interrupt. Reading a register will flush the status block.
3370 * When using MSI, the MSI message will always complete after
3371 * the status block write.
3372 */
Michael Chan35efa7c2007-12-20 19:56:37 -08003373 if ((sblk->status_idx == bnapi->last_status_idx) &&
Michael Chane503e062012-12-06 10:33:08 +00003374 (BNX2_RD(bp, BNX2_PCICFG_MISC_STATUS) &
Michael Chanb6016b72005-05-26 13:03:09 -07003375 BNX2_PCICFG_MISC_STATUS_INTA_VALUE))
Michael Chan73eef4c2005-08-25 15:39:15 -07003376 return IRQ_NONE;
Michael Chanb6016b72005-05-26 13:03:09 -07003377
Michael Chane503e062012-12-06 10:33:08 +00003378 BNX2_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
Michael Chanb6016b72005-05-26 13:03:09 -07003379 BNX2_PCICFG_INT_ACK_CMD_USE_INT_HC_PARAM |
3380 BNX2_PCICFG_INT_ACK_CMD_MASK_INT);
3381
Michael Chanb8a7ce72007-07-07 22:51:03 -07003382 /* Read back to deassert IRQ immediately to avoid too many
3383 * spurious interrupts.
3384 */
Michael Chane503e062012-12-06 10:33:08 +00003385 BNX2_RD(bp, BNX2_PCICFG_INT_ACK_CMD);
Michael Chanb8a7ce72007-07-07 22:51:03 -07003386
Michael Chanb6016b72005-05-26 13:03:09 -07003387 /* Return here if interrupt is shared and is disabled. */
Michael Chan73eef4c2005-08-25 15:39:15 -07003388 if (unlikely(atomic_read(&bp->intr_sem) != 0))
3389 return IRQ_HANDLED;
Michael Chanb6016b72005-05-26 13:03:09 -07003390
Ben Hutchings288379f2009-01-19 16:43:59 -08003391 if (napi_schedule_prep(&bnapi->napi)) {
Michael Chan35efa7c2007-12-20 19:56:37 -08003392 bnapi->last_status_idx = sblk->status_idx;
Ben Hutchings288379f2009-01-19 16:43:59 -08003393 __napi_schedule(&bnapi->napi);
Michael Chanb8a7ce72007-07-07 22:51:03 -07003394 }
Michael Chanb6016b72005-05-26 13:03:09 -07003395
Michael Chan73eef4c2005-08-25 15:39:15 -07003396 return IRQ_HANDLED;
Michael Chanb6016b72005-05-26 13:03:09 -07003397}
3398
Michael Chan43e80b82008-06-19 16:41:08 -07003399static inline int
3400bnx2_has_fast_work(struct bnx2_napi *bnapi)
3401{
3402 struct bnx2_tx_ring_info *txr = &bnapi->tx_ring;
3403 struct bnx2_rx_ring_info *rxr = &bnapi->rx_ring;
3404
3405 if ((bnx2_get_hw_rx_cons(bnapi) != rxr->rx_cons) ||
3406 (bnx2_get_hw_tx_cons(bnapi) != txr->hw_tx_cons))
3407 return 1;
3408 return 0;
3409}
3410
Michael Chan0d8a6572007-07-07 22:49:43 -07003411#define STATUS_ATTN_EVENTS (STATUS_ATTN_BITS_LINK_STATE | \
3412 STATUS_ATTN_BITS_TIMER_ABORT)
Michael Chanda3e4fb2007-05-03 13:24:23 -07003413
Michael Chanf4e418f2005-11-04 08:53:48 -08003414static inline int
Michael Chan35efa7c2007-12-20 19:56:37 -08003415bnx2_has_work(struct bnx2_napi *bnapi)
Michael Chanf4e418f2005-11-04 08:53:48 -08003416{
Michael Chan43e80b82008-06-19 16:41:08 -07003417 struct status_block *sblk = bnapi->status_blk.msi;
Michael Chanf4e418f2005-11-04 08:53:48 -08003418
Michael Chan43e80b82008-06-19 16:41:08 -07003419 if (bnx2_has_fast_work(bnapi))
Michael Chanf4e418f2005-11-04 08:53:48 -08003420 return 1;
3421
Michael Chan4edd4732009-06-08 18:14:42 -07003422#ifdef BCM_CNIC
3423 if (bnapi->cnic_present && (bnapi->cnic_tag != sblk->status_idx))
3424 return 1;
3425#endif
3426
Michael Chanda3e4fb2007-05-03 13:24:23 -07003427 if ((sblk->status_attn_bits & STATUS_ATTN_EVENTS) !=
3428 (sblk->status_attn_bits_ack & STATUS_ATTN_EVENTS))
Michael Chanf4e418f2005-11-04 08:53:48 -08003429 return 1;
3430
3431 return 0;
3432}
3433
Michael Chanefba0182008-12-03 00:36:15 -08003434static void
3435bnx2_chk_missed_msi(struct bnx2 *bp)
3436{
3437 struct bnx2_napi *bnapi = &bp->bnx2_napi[0];
3438 u32 msi_ctrl;
3439
3440 if (bnx2_has_work(bnapi)) {
Michael Chane503e062012-12-06 10:33:08 +00003441 msi_ctrl = BNX2_RD(bp, BNX2_PCICFG_MSI_CONTROL);
Michael Chanefba0182008-12-03 00:36:15 -08003442 if (!(msi_ctrl & BNX2_PCICFG_MSI_CONTROL_ENABLE))
3443 return;
3444
3445 if (bnapi->last_status_idx == bp->idle_chk_status_idx) {
Michael Chane503e062012-12-06 10:33:08 +00003446 BNX2_WR(bp, BNX2_PCICFG_MSI_CONTROL, msi_ctrl &
3447 ~BNX2_PCICFG_MSI_CONTROL_ENABLE);
3448 BNX2_WR(bp, BNX2_PCICFG_MSI_CONTROL, msi_ctrl);
Michael Chanefba0182008-12-03 00:36:15 -08003449 bnx2_msi(bp->irq_tbl[0].vector, bnapi);
3450 }
3451 }
3452
3453 bp->idle_chk_status_idx = bnapi->last_status_idx;
3454}
3455
Michael Chan4edd4732009-06-08 18:14:42 -07003456#ifdef BCM_CNIC
3457static void bnx2_poll_cnic(struct bnx2 *bp, struct bnx2_napi *bnapi)
3458{
3459 struct cnic_ops *c_ops;
3460
3461 if (!bnapi->cnic_present)
3462 return;
3463
3464 rcu_read_lock();
3465 c_ops = rcu_dereference(bp->cnic_ops);
3466 if (c_ops)
3467 bnapi->cnic_tag = c_ops->cnic_handler(bp->cnic_data,
3468 bnapi->status_blk.msi);
3469 rcu_read_unlock();
3470}
3471#endif
3472
Michael Chan43e80b82008-06-19 16:41:08 -07003473static void bnx2_poll_link(struct bnx2 *bp, struct bnx2_napi *bnapi)
Michael Chanb6016b72005-05-26 13:03:09 -07003474{
Michael Chan43e80b82008-06-19 16:41:08 -07003475 struct status_block *sblk = bnapi->status_blk.msi;
Michael Chanda3e4fb2007-05-03 13:24:23 -07003476 u32 status_attn_bits = sblk->status_attn_bits;
3477 u32 status_attn_bits_ack = sblk->status_attn_bits_ack;
Michael Chanb6016b72005-05-26 13:03:09 -07003478
Michael Chanda3e4fb2007-05-03 13:24:23 -07003479 if ((status_attn_bits & STATUS_ATTN_EVENTS) !=
3480 (status_attn_bits_ack & STATUS_ATTN_EVENTS)) {
Michael Chanb6016b72005-05-26 13:03:09 -07003481
Michael Chan35efa7c2007-12-20 19:56:37 -08003482 bnx2_phy_int(bp, bnapi);
Michael Chanbf5295b2006-03-23 01:11:56 -08003483
3484 /* This is needed to take care of transient status
3485 * during link changes.
3486 */
Michael Chane503e062012-12-06 10:33:08 +00003487 BNX2_WR(bp, BNX2_HC_COMMAND,
3488 bp->hc_cmd | BNX2_HC_COMMAND_COAL_NOW_WO_INT);
3489 BNX2_RD(bp, BNX2_HC_COMMAND);
Michael Chanb6016b72005-05-26 13:03:09 -07003490 }
Michael Chan43e80b82008-06-19 16:41:08 -07003491}
3492
3493static int bnx2_poll_work(struct bnx2 *bp, struct bnx2_napi *bnapi,
3494 int work_done, int budget)
3495{
3496 struct bnx2_tx_ring_info *txr = &bnapi->tx_ring;
3497 struct bnx2_rx_ring_info *rxr = &bnapi->rx_ring;
Michael Chanb6016b72005-05-26 13:03:09 -07003498
Michael Chan35e90102008-06-19 16:37:42 -07003499 if (bnx2_get_hw_tx_cons(bnapi) != txr->hw_tx_cons)
Michael Chan57851d82007-12-20 20:01:44 -08003500 bnx2_tx_int(bp, bnapi, 0);
Michael Chanb6016b72005-05-26 13:03:09 -07003501
Michael Chanbb4f98a2008-06-19 16:38:19 -07003502 if (bnx2_get_hw_rx_cons(bnapi) != rxr->rx_cons)
Michael Chan35efa7c2007-12-20 19:56:37 -08003503 work_done += bnx2_rx_int(bp, bnapi, budget - work_done);
Jeff Garzik6aa20a22006-09-13 13:24:59 -04003504
David S. Miller6f535762007-10-11 18:08:29 -07003505 return work_done;
3506}
Michael Chanf4e418f2005-11-04 08:53:48 -08003507
Michael Chanf0ea2e62008-06-19 16:41:57 -07003508static int bnx2_poll_msix(struct napi_struct *napi, int budget)
3509{
3510 struct bnx2_napi *bnapi = container_of(napi, struct bnx2_napi, napi);
3511 struct bnx2 *bp = bnapi->bp;
3512 int work_done = 0;
3513 struct status_block_msix *sblk = bnapi->status_blk.msix;
3514
3515 while (1) {
3516 work_done = bnx2_poll_work(bp, bnapi, work_done, budget);
3517 if (unlikely(work_done >= budget))
3518 break;
3519
3520 bnapi->last_status_idx = sblk->status_idx;
3521 /* status idx must be read before checking for more work. */
3522 rmb();
3523 if (likely(!bnx2_has_fast_work(bnapi))) {
3524
Ben Hutchings288379f2009-01-19 16:43:59 -08003525 napi_complete(napi);
Michael Chane503e062012-12-06 10:33:08 +00003526 BNX2_WR(bp, BNX2_PCICFG_INT_ACK_CMD, bnapi->int_num |
3527 BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
3528 bnapi->last_status_idx);
Michael Chanf0ea2e62008-06-19 16:41:57 -07003529 break;
3530 }
3531 }
3532 return work_done;
3533}
3534
David S. Miller6f535762007-10-11 18:08:29 -07003535static int bnx2_poll(struct napi_struct *napi, int budget)
3536{
Michael Chan35efa7c2007-12-20 19:56:37 -08003537 struct bnx2_napi *bnapi = container_of(napi, struct bnx2_napi, napi);
3538 struct bnx2 *bp = bnapi->bp;
David S. Miller6f535762007-10-11 18:08:29 -07003539 int work_done = 0;
Michael Chan43e80b82008-06-19 16:41:08 -07003540 struct status_block *sblk = bnapi->status_blk.msi;
David S. Miller6f535762007-10-11 18:08:29 -07003541
3542 while (1) {
Michael Chan43e80b82008-06-19 16:41:08 -07003543 bnx2_poll_link(bp, bnapi);
3544
Michael Chan35efa7c2007-12-20 19:56:37 -08003545 work_done = bnx2_poll_work(bp, bnapi, work_done, budget);
David S. Miller6f535762007-10-11 18:08:29 -07003546
Michael Chan4edd4732009-06-08 18:14:42 -07003547#ifdef BCM_CNIC
3548 bnx2_poll_cnic(bp, bnapi);
3549#endif
3550
Michael Chan35efa7c2007-12-20 19:56:37 -08003551 /* bnapi->last_status_idx is used below to tell the hw how
Michael Chan6dee6422007-10-12 01:40:38 -07003552 * much work has been processed, so we must read it before
3553 * checking for more work.
3554 */
Michael Chan35efa7c2007-12-20 19:56:37 -08003555 bnapi->last_status_idx = sblk->status_idx;
Michael Chanefba0182008-12-03 00:36:15 -08003556
3557 if (unlikely(work_done >= budget))
3558 break;
3559
Michael Chan6dee6422007-10-12 01:40:38 -07003560 rmb();
Michael Chan35efa7c2007-12-20 19:56:37 -08003561 if (likely(!bnx2_has_work(bnapi))) {
Ben Hutchings288379f2009-01-19 16:43:59 -08003562 napi_complete(napi);
David S. Millerf86e82f2008-01-21 17:15:40 -08003563 if (likely(bp->flags & BNX2_FLAG_USING_MSI_OR_MSIX)) {
Michael Chane503e062012-12-06 10:33:08 +00003564 BNX2_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
3565 BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
3566 bnapi->last_status_idx);
Michael Chan6dee6422007-10-12 01:40:38 -07003567 break;
David S. Miller6f535762007-10-11 18:08:29 -07003568 }
Michael Chane503e062012-12-06 10:33:08 +00003569 BNX2_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
3570 BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
3571 BNX2_PCICFG_INT_ACK_CMD_MASK_INT |
3572 bnapi->last_status_idx);
David S. Miller6f535762007-10-11 18:08:29 -07003573
Michael Chane503e062012-12-06 10:33:08 +00003574 BNX2_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
3575 BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
3576 bnapi->last_status_idx);
David S. Miller6f535762007-10-11 18:08:29 -07003577 break;
Michael Chan1269a8a2006-01-23 16:11:03 -08003578 }
Michael Chanb6016b72005-05-26 13:03:09 -07003579 }
3580
Stephen Hemmingerbea33482007-10-03 16:41:36 -07003581 return work_done;
Michael Chanb6016b72005-05-26 13:03:09 -07003582}
3583
Herbert Xu932ff272006-06-09 12:20:56 -07003584/* Called with rtnl_lock from vlan functions and also netif_tx_lock
Michael Chanb6016b72005-05-26 13:03:09 -07003585 * from set_multicast.
3586 */
3587static void
3588bnx2_set_rx_mode(struct net_device *dev)
3589{
Michael Chan972ec0d2006-01-23 16:12:43 -08003590 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07003591 u32 rx_mode, sort_mode;
Jiri Pirkoccffad252009-05-22 23:22:17 +00003592 struct netdev_hw_addr *ha;
Michael Chanb6016b72005-05-26 13:03:09 -07003593 int i;
Michael Chanb6016b72005-05-26 13:03:09 -07003594
Michael Chan9f52b562008-10-09 12:21:46 -07003595 if (!netif_running(dev))
3596 return;
3597
Michael Chanc770a652005-08-25 15:38:39 -07003598 spin_lock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07003599
3600 rx_mode = bp->rx_mode & ~(BNX2_EMAC_RX_MODE_PROMISCUOUS |
3601 BNX2_EMAC_RX_MODE_KEEP_VLAN_TAG);
3602 sort_mode = 1 | BNX2_RPM_SORT_USER0_BC_EN;
Patrick McHardyf6469682013-04-19 02:04:27 +00003603 if (!(dev->features & NETIF_F_HW_VLAN_CTAG_RX) &&
Jesse Gross7d0fd212010-10-20 13:56:09 +00003604 (bp->flags & BNX2_FLAG_CAN_KEEP_VLAN))
Michael Chanb6016b72005-05-26 13:03:09 -07003605 rx_mode |= BNX2_EMAC_RX_MODE_KEEP_VLAN_TAG;
Michael Chanb6016b72005-05-26 13:03:09 -07003606 if (dev->flags & IFF_PROMISC) {
3607 /* Promiscuous mode. */
3608 rx_mode |= BNX2_EMAC_RX_MODE_PROMISCUOUS;
Michael Chan75108732006-11-19 14:06:40 -08003609 sort_mode |= BNX2_RPM_SORT_USER0_PROM_EN |
3610 BNX2_RPM_SORT_USER0_PROM_VLAN;
Michael Chanb6016b72005-05-26 13:03:09 -07003611 }
3612 else if (dev->flags & IFF_ALLMULTI) {
3613 for (i = 0; i < NUM_MC_HASH_REGISTERS; i++) {
Michael Chane503e062012-12-06 10:33:08 +00003614 BNX2_WR(bp, BNX2_EMAC_MULTICAST_HASH0 + (i * 4),
3615 0xffffffff);
Michael Chanb6016b72005-05-26 13:03:09 -07003616 }
3617 sort_mode |= BNX2_RPM_SORT_USER0_MC_EN;
3618 }
3619 else {
3620 /* Accept one or more multicast(s). */
Michael Chanb6016b72005-05-26 13:03:09 -07003621 u32 mc_filter[NUM_MC_HASH_REGISTERS];
3622 u32 regidx;
3623 u32 bit;
3624 u32 crc;
3625
3626 memset(mc_filter, 0, 4 * NUM_MC_HASH_REGISTERS);
3627
Jiri Pirko22bedad32010-04-01 21:22:57 +00003628 netdev_for_each_mc_addr(ha, dev) {
3629 crc = ether_crc_le(ETH_ALEN, ha->addr);
Michael Chanb6016b72005-05-26 13:03:09 -07003630 bit = crc & 0xff;
3631 regidx = (bit & 0xe0) >> 5;
3632 bit &= 0x1f;
3633 mc_filter[regidx] |= (1 << bit);
3634 }
3635
3636 for (i = 0; i < NUM_MC_HASH_REGISTERS; i++) {
Michael Chane503e062012-12-06 10:33:08 +00003637 BNX2_WR(bp, BNX2_EMAC_MULTICAST_HASH0 + (i * 4),
3638 mc_filter[i]);
Michael Chanb6016b72005-05-26 13:03:09 -07003639 }
3640
3641 sort_mode |= BNX2_RPM_SORT_USER0_MC_HSH_EN;
3642 }
3643
Jiri Pirko32e7bfc2010-01-25 13:36:10 -08003644 if (netdev_uc_count(dev) > BNX2_MAX_UNICAST_ADDRESSES) {
Benjamin Li5fcaed02008-07-14 22:39:52 -07003645 rx_mode |= BNX2_EMAC_RX_MODE_PROMISCUOUS;
3646 sort_mode |= BNX2_RPM_SORT_USER0_PROM_EN |
3647 BNX2_RPM_SORT_USER0_PROM_VLAN;
3648 } else if (!(dev->flags & IFF_PROMISC)) {
Benjamin Li5fcaed02008-07-14 22:39:52 -07003649 /* Add all entries into to the match filter list */
Jiri Pirkoccffad252009-05-22 23:22:17 +00003650 i = 0;
Jiri Pirko32e7bfc2010-01-25 13:36:10 -08003651 netdev_for_each_uc_addr(ha, dev) {
Jiri Pirkoccffad252009-05-22 23:22:17 +00003652 bnx2_set_mac_addr(bp, ha->addr,
Benjamin Li5fcaed02008-07-14 22:39:52 -07003653 i + BNX2_START_UNICAST_ADDRESS_INDEX);
3654 sort_mode |= (1 <<
3655 (i + BNX2_START_UNICAST_ADDRESS_INDEX));
Jiri Pirkoccffad252009-05-22 23:22:17 +00003656 i++;
Benjamin Li5fcaed02008-07-14 22:39:52 -07003657 }
3658
3659 }
3660
Michael Chanb6016b72005-05-26 13:03:09 -07003661 if (rx_mode != bp->rx_mode) {
3662 bp->rx_mode = rx_mode;
Michael Chane503e062012-12-06 10:33:08 +00003663 BNX2_WR(bp, BNX2_EMAC_RX_MODE, rx_mode);
Michael Chanb6016b72005-05-26 13:03:09 -07003664 }
3665
Michael Chane503e062012-12-06 10:33:08 +00003666 BNX2_WR(bp, BNX2_RPM_SORT_USER0, 0x0);
3667 BNX2_WR(bp, BNX2_RPM_SORT_USER0, sort_mode);
3668 BNX2_WR(bp, BNX2_RPM_SORT_USER0, sort_mode | BNX2_RPM_SORT_USER0_ENA);
Michael Chanb6016b72005-05-26 13:03:09 -07003669
Michael Chanc770a652005-08-25 15:38:39 -07003670 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07003671}
3672
françois romieu7880b722011-09-30 00:36:52 +00003673static int
Michael Chan57579f72009-04-04 16:51:14 -07003674check_fw_section(const struct firmware *fw,
3675 const struct bnx2_fw_file_section *section,
3676 u32 alignment, bool non_empty)
Michael Chanb6016b72005-05-26 13:03:09 -07003677{
Michael Chan57579f72009-04-04 16:51:14 -07003678 u32 offset = be32_to_cpu(section->offset);
3679 u32 len = be32_to_cpu(section->len);
Michael Chanb6016b72005-05-26 13:03:09 -07003680
Michael Chan57579f72009-04-04 16:51:14 -07003681 if ((offset == 0 && len != 0) || offset >= fw->size || offset & 3)
3682 return -EINVAL;
3683 if ((non_empty && len == 0) || len > fw->size - offset ||
3684 len & (alignment - 1))
3685 return -EINVAL;
3686 return 0;
3687}
3688
françois romieu7880b722011-09-30 00:36:52 +00003689static int
Michael Chan57579f72009-04-04 16:51:14 -07003690check_mips_fw_entry(const struct firmware *fw,
3691 const struct bnx2_mips_fw_file_entry *entry)
3692{
3693 if (check_fw_section(fw, &entry->text, 4, true) ||
3694 check_fw_section(fw, &entry->data, 4, false) ||
3695 check_fw_section(fw, &entry->rodata, 4, false))
3696 return -EINVAL;
3697 return 0;
3698}
3699
françois romieu7880b722011-09-30 00:36:52 +00003700static void bnx2_release_firmware(struct bnx2 *bp)
3701{
3702 if (bp->rv2p_firmware) {
3703 release_firmware(bp->mips_firmware);
3704 release_firmware(bp->rv2p_firmware);
3705 bp->rv2p_firmware = NULL;
3706 }
3707}
3708
3709static int bnx2_request_uncached_firmware(struct bnx2 *bp)
Michael Chan57579f72009-04-04 16:51:14 -07003710{
3711 const char *mips_fw_file, *rv2p_fw_file;
Bastian Blank5ee1c322009-04-08 15:50:07 -07003712 const struct bnx2_mips_fw_file *mips_fw;
3713 const struct bnx2_rv2p_fw_file *rv2p_fw;
Michael Chan57579f72009-04-04 16:51:14 -07003714 int rc;
3715
Michael Chan4ce45e02012-12-06 10:33:10 +00003716 if (BNX2_CHIP(bp) == BNX2_CHIP_5709) {
Michael Chan57579f72009-04-04 16:51:14 -07003717 mips_fw_file = FW_MIPS_FILE_09;
Michael Chan4ce45e02012-12-06 10:33:10 +00003718 if ((BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5709_A0) ||
3719 (BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5709_A1))
Michael Chan078b0732009-08-29 00:02:46 -07003720 rv2p_fw_file = FW_RV2P_FILE_09_Ax;
3721 else
3722 rv2p_fw_file = FW_RV2P_FILE_09;
Michael Chan57579f72009-04-04 16:51:14 -07003723 } else {
3724 mips_fw_file = FW_MIPS_FILE_06;
3725 rv2p_fw_file = FW_RV2P_FILE_06;
3726 }
3727
3728 rc = request_firmware(&bp->mips_firmware, mips_fw_file, &bp->pdev->dev);
3729 if (rc) {
Joe Perches3a9c6a42010-02-17 15:01:51 +00003730 pr_err("Can't load firmware file \"%s\"\n", mips_fw_file);
françois romieu7880b722011-09-30 00:36:52 +00003731 goto out;
Michael Chan57579f72009-04-04 16:51:14 -07003732 }
3733
3734 rc = request_firmware(&bp->rv2p_firmware, rv2p_fw_file, &bp->pdev->dev);
3735 if (rc) {
Joe Perches3a9c6a42010-02-17 15:01:51 +00003736 pr_err("Can't load firmware file \"%s\"\n", rv2p_fw_file);
françois romieu7880b722011-09-30 00:36:52 +00003737 goto err_release_mips_firmware;
Michael Chan57579f72009-04-04 16:51:14 -07003738 }
Bastian Blank5ee1c322009-04-08 15:50:07 -07003739 mips_fw = (const struct bnx2_mips_fw_file *) bp->mips_firmware->data;
3740 rv2p_fw = (const struct bnx2_rv2p_fw_file *) bp->rv2p_firmware->data;
3741 if (bp->mips_firmware->size < sizeof(*mips_fw) ||
3742 check_mips_fw_entry(bp->mips_firmware, &mips_fw->com) ||
3743 check_mips_fw_entry(bp->mips_firmware, &mips_fw->cp) ||
3744 check_mips_fw_entry(bp->mips_firmware, &mips_fw->rxp) ||
3745 check_mips_fw_entry(bp->mips_firmware, &mips_fw->tpat) ||
3746 check_mips_fw_entry(bp->mips_firmware, &mips_fw->txp)) {
Joe Perches3a9c6a42010-02-17 15:01:51 +00003747 pr_err("Firmware file \"%s\" is invalid\n", mips_fw_file);
françois romieu7880b722011-09-30 00:36:52 +00003748 rc = -EINVAL;
3749 goto err_release_firmware;
Michael Chan57579f72009-04-04 16:51:14 -07003750 }
Bastian Blank5ee1c322009-04-08 15:50:07 -07003751 if (bp->rv2p_firmware->size < sizeof(*rv2p_fw) ||
3752 check_fw_section(bp->rv2p_firmware, &rv2p_fw->proc1.rv2p, 8, true) ||
3753 check_fw_section(bp->rv2p_firmware, &rv2p_fw->proc2.rv2p, 8, true)) {
Joe Perches3a9c6a42010-02-17 15:01:51 +00003754 pr_err("Firmware file \"%s\" is invalid\n", rv2p_fw_file);
françois romieu7880b722011-09-30 00:36:52 +00003755 rc = -EINVAL;
3756 goto err_release_firmware;
Michael Chan57579f72009-04-04 16:51:14 -07003757 }
françois romieu7880b722011-09-30 00:36:52 +00003758out:
3759 return rc;
Michael Chan57579f72009-04-04 16:51:14 -07003760
françois romieu7880b722011-09-30 00:36:52 +00003761err_release_firmware:
3762 release_firmware(bp->rv2p_firmware);
3763 bp->rv2p_firmware = NULL;
3764err_release_mips_firmware:
3765 release_firmware(bp->mips_firmware);
3766 goto out;
3767}
3768
3769static int bnx2_request_firmware(struct bnx2 *bp)
3770{
3771 return bp->rv2p_firmware ? 0 : bnx2_request_uncached_firmware(bp);
Michael Chan57579f72009-04-04 16:51:14 -07003772}
3773
3774static u32
3775rv2p_fw_fixup(u32 rv2p_proc, int idx, u32 loc, u32 rv2p_code)
3776{
3777 switch (idx) {
3778 case RV2P_P1_FIXUP_PAGE_SIZE_IDX:
3779 rv2p_code &= ~RV2P_BD_PAGE_SIZE_MSK;
3780 rv2p_code |= RV2P_BD_PAGE_SIZE;
3781 break;
3782 }
3783 return rv2p_code;
3784}
3785
3786static int
3787load_rv2p_fw(struct bnx2 *bp, u32 rv2p_proc,
3788 const struct bnx2_rv2p_fw_file_entry *fw_entry)
3789{
3790 u32 rv2p_code_len, file_offset;
3791 __be32 *rv2p_code;
3792 int i;
3793 u32 val, cmd, addr;
3794
3795 rv2p_code_len = be32_to_cpu(fw_entry->rv2p.len);
3796 file_offset = be32_to_cpu(fw_entry->rv2p.offset);
3797
3798 rv2p_code = (__be32 *)(bp->rv2p_firmware->data + file_offset);
3799
3800 if (rv2p_proc == RV2P_PROC1) {
3801 cmd = BNX2_RV2P_PROC1_ADDR_CMD_RDWR;
3802 addr = BNX2_RV2P_PROC1_ADDR_CMD;
3803 } else {
3804 cmd = BNX2_RV2P_PROC2_ADDR_CMD_RDWR;
3805 addr = BNX2_RV2P_PROC2_ADDR_CMD;
Michael Chand25be1d2008-05-02 16:57:59 -07003806 }
Michael Chanb6016b72005-05-26 13:03:09 -07003807
3808 for (i = 0; i < rv2p_code_len; i += 8) {
Michael Chane503e062012-12-06 10:33:08 +00003809 BNX2_WR(bp, BNX2_RV2P_INSTR_HIGH, be32_to_cpu(*rv2p_code));
Michael Chanb6016b72005-05-26 13:03:09 -07003810 rv2p_code++;
Michael Chane503e062012-12-06 10:33:08 +00003811 BNX2_WR(bp, BNX2_RV2P_INSTR_LOW, be32_to_cpu(*rv2p_code));
Michael Chanb6016b72005-05-26 13:03:09 -07003812 rv2p_code++;
3813
Michael Chan57579f72009-04-04 16:51:14 -07003814 val = (i / 8) | cmd;
Michael Chane503e062012-12-06 10:33:08 +00003815 BNX2_WR(bp, addr, val);
Michael Chan57579f72009-04-04 16:51:14 -07003816 }
3817
3818 rv2p_code = (__be32 *)(bp->rv2p_firmware->data + file_offset);
3819 for (i = 0; i < 8; i++) {
3820 u32 loc, code;
3821
3822 loc = be32_to_cpu(fw_entry->fixup[i]);
3823 if (loc && ((loc * 4) < rv2p_code_len)) {
3824 code = be32_to_cpu(*(rv2p_code + loc - 1));
Michael Chane503e062012-12-06 10:33:08 +00003825 BNX2_WR(bp, BNX2_RV2P_INSTR_HIGH, code);
Michael Chan57579f72009-04-04 16:51:14 -07003826 code = be32_to_cpu(*(rv2p_code + loc));
3827 code = rv2p_fw_fixup(rv2p_proc, i, loc, code);
Michael Chane503e062012-12-06 10:33:08 +00003828 BNX2_WR(bp, BNX2_RV2P_INSTR_LOW, code);
Michael Chan57579f72009-04-04 16:51:14 -07003829
3830 val = (loc / 2) | cmd;
Michael Chane503e062012-12-06 10:33:08 +00003831 BNX2_WR(bp, addr, val);
Michael Chanb6016b72005-05-26 13:03:09 -07003832 }
3833 }
3834
3835 /* Reset the processor, un-stall is done later. */
3836 if (rv2p_proc == RV2P_PROC1) {
Michael Chane503e062012-12-06 10:33:08 +00003837 BNX2_WR(bp, BNX2_RV2P_COMMAND, BNX2_RV2P_COMMAND_PROC1_RESET);
Michael Chanb6016b72005-05-26 13:03:09 -07003838 }
3839 else {
Michael Chane503e062012-12-06 10:33:08 +00003840 BNX2_WR(bp, BNX2_RV2P_COMMAND, BNX2_RV2P_COMMAND_PROC2_RESET);
Michael Chanb6016b72005-05-26 13:03:09 -07003841 }
Michael Chan57579f72009-04-04 16:51:14 -07003842
3843 return 0;
Michael Chanb6016b72005-05-26 13:03:09 -07003844}
3845
Michael Chanaf3ee512006-11-19 14:09:25 -08003846static int
Michael Chan57579f72009-04-04 16:51:14 -07003847load_cpu_fw(struct bnx2 *bp, const struct cpu_reg *cpu_reg,
3848 const struct bnx2_mips_fw_file_entry *fw_entry)
Michael Chanb6016b72005-05-26 13:03:09 -07003849{
Michael Chan57579f72009-04-04 16:51:14 -07003850 u32 addr, len, file_offset;
3851 __be32 *data;
Michael Chanb6016b72005-05-26 13:03:09 -07003852 u32 offset;
3853 u32 val;
3854
3855 /* Halt the CPU. */
Michael Chan2726d6e2008-01-29 21:35:05 -08003856 val = bnx2_reg_rd_ind(bp, cpu_reg->mode);
Michael Chanb6016b72005-05-26 13:03:09 -07003857 val |= cpu_reg->mode_value_halt;
Michael Chan2726d6e2008-01-29 21:35:05 -08003858 bnx2_reg_wr_ind(bp, cpu_reg->mode, val);
3859 bnx2_reg_wr_ind(bp, cpu_reg->state, cpu_reg->state_value_clear);
Michael Chanb6016b72005-05-26 13:03:09 -07003860
3861 /* Load the Text area. */
Michael Chan57579f72009-04-04 16:51:14 -07003862 addr = be32_to_cpu(fw_entry->text.addr);
3863 len = be32_to_cpu(fw_entry->text.len);
3864 file_offset = be32_to_cpu(fw_entry->text.offset);
3865 data = (__be32 *)(bp->mips_firmware->data + file_offset);
3866
3867 offset = cpu_reg->spad_base + (addr - cpu_reg->mips_view_base);
3868 if (len) {
Michael Chanb6016b72005-05-26 13:03:09 -07003869 int j;
3870
Michael Chan57579f72009-04-04 16:51:14 -07003871 for (j = 0; j < (len / 4); j++, offset += 4)
3872 bnx2_reg_wr_ind(bp, offset, be32_to_cpu(data[j]));
Michael Chanb6016b72005-05-26 13:03:09 -07003873 }
3874
3875 /* Load the Data area. */
Michael Chan57579f72009-04-04 16:51:14 -07003876 addr = be32_to_cpu(fw_entry->data.addr);
3877 len = be32_to_cpu(fw_entry->data.len);
3878 file_offset = be32_to_cpu(fw_entry->data.offset);
3879 data = (__be32 *)(bp->mips_firmware->data + file_offset);
3880
3881 offset = cpu_reg->spad_base + (addr - cpu_reg->mips_view_base);
3882 if (len) {
Michael Chanb6016b72005-05-26 13:03:09 -07003883 int j;
3884
Michael Chan57579f72009-04-04 16:51:14 -07003885 for (j = 0; j < (len / 4); j++, offset += 4)
3886 bnx2_reg_wr_ind(bp, offset, be32_to_cpu(data[j]));
Michael Chanb6016b72005-05-26 13:03:09 -07003887 }
3888
3889 /* Load the Read-Only area. */
Michael Chan57579f72009-04-04 16:51:14 -07003890 addr = be32_to_cpu(fw_entry->rodata.addr);
3891 len = be32_to_cpu(fw_entry->rodata.len);
3892 file_offset = be32_to_cpu(fw_entry->rodata.offset);
3893 data = (__be32 *)(bp->mips_firmware->data + file_offset);
3894
3895 offset = cpu_reg->spad_base + (addr - cpu_reg->mips_view_base);
3896 if (len) {
Michael Chanb6016b72005-05-26 13:03:09 -07003897 int j;
3898
Michael Chan57579f72009-04-04 16:51:14 -07003899 for (j = 0; j < (len / 4); j++, offset += 4)
3900 bnx2_reg_wr_ind(bp, offset, be32_to_cpu(data[j]));
Michael Chanb6016b72005-05-26 13:03:09 -07003901 }
3902
3903 /* Clear the pre-fetch instruction. */
Michael Chan2726d6e2008-01-29 21:35:05 -08003904 bnx2_reg_wr_ind(bp, cpu_reg->inst, 0);
Michael Chan57579f72009-04-04 16:51:14 -07003905
3906 val = be32_to_cpu(fw_entry->start_addr);
3907 bnx2_reg_wr_ind(bp, cpu_reg->pc, val);
Michael Chanb6016b72005-05-26 13:03:09 -07003908
3909 /* Start the CPU. */
Michael Chan2726d6e2008-01-29 21:35:05 -08003910 val = bnx2_reg_rd_ind(bp, cpu_reg->mode);
Michael Chanb6016b72005-05-26 13:03:09 -07003911 val &= ~cpu_reg->mode_value_halt;
Michael Chan2726d6e2008-01-29 21:35:05 -08003912 bnx2_reg_wr_ind(bp, cpu_reg->state, cpu_reg->state_value_clear);
3913 bnx2_reg_wr_ind(bp, cpu_reg->mode, val);
Michael Chanaf3ee512006-11-19 14:09:25 -08003914
3915 return 0;
Michael Chanb6016b72005-05-26 13:03:09 -07003916}
3917
Michael Chanfba9fe92006-06-12 22:21:25 -07003918static int
Michael Chanb6016b72005-05-26 13:03:09 -07003919bnx2_init_cpus(struct bnx2 *bp)
3920{
Michael Chan57579f72009-04-04 16:51:14 -07003921 const struct bnx2_mips_fw_file *mips_fw =
3922 (const struct bnx2_mips_fw_file *) bp->mips_firmware->data;
3923 const struct bnx2_rv2p_fw_file *rv2p_fw =
3924 (const struct bnx2_rv2p_fw_file *) bp->rv2p_firmware->data;
3925 int rc;
Michael Chanb6016b72005-05-26 13:03:09 -07003926
3927 /* Initialize the RV2P processor. */
Michael Chan57579f72009-04-04 16:51:14 -07003928 load_rv2p_fw(bp, RV2P_PROC1, &rv2p_fw->proc1);
3929 load_rv2p_fw(bp, RV2P_PROC2, &rv2p_fw->proc2);
Michael Chanb6016b72005-05-26 13:03:09 -07003930
3931 /* Initialize the RX Processor. */
Michael Chan57579f72009-04-04 16:51:14 -07003932 rc = load_cpu_fw(bp, &cpu_reg_rxp, &mips_fw->rxp);
Michael Chanfba9fe92006-06-12 22:21:25 -07003933 if (rc)
3934 goto init_cpu_err;
3935
Michael Chanb6016b72005-05-26 13:03:09 -07003936 /* Initialize the TX Processor. */
Michael Chan57579f72009-04-04 16:51:14 -07003937 rc = load_cpu_fw(bp, &cpu_reg_txp, &mips_fw->txp);
Michael Chanfba9fe92006-06-12 22:21:25 -07003938 if (rc)
3939 goto init_cpu_err;
3940
Michael Chanb6016b72005-05-26 13:03:09 -07003941 /* Initialize the TX Patch-up Processor. */
Michael Chan57579f72009-04-04 16:51:14 -07003942 rc = load_cpu_fw(bp, &cpu_reg_tpat, &mips_fw->tpat);
Michael Chanfba9fe92006-06-12 22:21:25 -07003943 if (rc)
3944 goto init_cpu_err;
3945
Michael Chanb6016b72005-05-26 13:03:09 -07003946 /* Initialize the Completion Processor. */
Michael Chan57579f72009-04-04 16:51:14 -07003947 rc = load_cpu_fw(bp, &cpu_reg_com, &mips_fw->com);
Michael Chanfba9fe92006-06-12 22:21:25 -07003948 if (rc)
3949 goto init_cpu_err;
3950
Michael Chand43584c2006-11-19 14:14:35 -08003951 /* Initialize the Command Processor. */
Michael Chan57579f72009-04-04 16:51:14 -07003952 rc = load_cpu_fw(bp, &cpu_reg_cp, &mips_fw->cp);
Michael Chan110d0ef2007-12-12 11:18:34 -08003953
Michael Chanfba9fe92006-06-12 22:21:25 -07003954init_cpu_err:
Michael Chanfba9fe92006-06-12 22:21:25 -07003955 return rc;
Michael Chanb6016b72005-05-26 13:03:09 -07003956}
3957
Michael Chanb6a23e92013-08-06 15:50:09 -07003958static void
3959bnx2_setup_wol(struct bnx2 *bp)
3960{
3961 int i;
3962 u32 val, wol_msg;
3963
3964 if (bp->wol) {
3965 u32 advertising;
3966 u8 autoneg;
3967
3968 autoneg = bp->autoneg;
3969 advertising = bp->advertising;
3970
3971 if (bp->phy_port == PORT_TP) {
3972 bp->autoneg = AUTONEG_SPEED;
3973 bp->advertising = ADVERTISED_10baseT_Half |
3974 ADVERTISED_10baseT_Full |
3975 ADVERTISED_100baseT_Half |
3976 ADVERTISED_100baseT_Full |
3977 ADVERTISED_Autoneg;
3978 }
3979
3980 spin_lock_bh(&bp->phy_lock);
3981 bnx2_setup_phy(bp, bp->phy_port);
3982 spin_unlock_bh(&bp->phy_lock);
3983
3984 bp->autoneg = autoneg;
3985 bp->advertising = advertising;
3986
3987 bnx2_set_mac_addr(bp, bp->dev->dev_addr, 0);
3988
3989 val = BNX2_RD(bp, BNX2_EMAC_MODE);
3990
3991 /* Enable port mode. */
3992 val &= ~BNX2_EMAC_MODE_PORT;
3993 val |= BNX2_EMAC_MODE_MPKT_RCVD |
3994 BNX2_EMAC_MODE_ACPI_RCVD |
3995 BNX2_EMAC_MODE_MPKT;
3996 if (bp->phy_port == PORT_TP) {
3997 val |= BNX2_EMAC_MODE_PORT_MII;
3998 } else {
3999 val |= BNX2_EMAC_MODE_PORT_GMII;
4000 if (bp->line_speed == SPEED_2500)
4001 val |= BNX2_EMAC_MODE_25G_MODE;
4002 }
4003
4004 BNX2_WR(bp, BNX2_EMAC_MODE, val);
4005
4006 /* receive all multicast */
4007 for (i = 0; i < NUM_MC_HASH_REGISTERS; i++) {
4008 BNX2_WR(bp, BNX2_EMAC_MULTICAST_HASH0 + (i * 4),
4009 0xffffffff);
4010 }
4011 BNX2_WR(bp, BNX2_EMAC_RX_MODE, BNX2_EMAC_RX_MODE_SORT_MODE);
4012
4013 val = 1 | BNX2_RPM_SORT_USER0_BC_EN | BNX2_RPM_SORT_USER0_MC_EN;
4014 BNX2_WR(bp, BNX2_RPM_SORT_USER0, 0x0);
4015 BNX2_WR(bp, BNX2_RPM_SORT_USER0, val);
4016 BNX2_WR(bp, BNX2_RPM_SORT_USER0, val | BNX2_RPM_SORT_USER0_ENA);
4017
4018 /* Need to enable EMAC and RPM for WOL. */
4019 BNX2_WR(bp, BNX2_MISC_ENABLE_SET_BITS,
4020 BNX2_MISC_ENABLE_SET_BITS_RX_PARSER_MAC_ENABLE |
4021 BNX2_MISC_ENABLE_SET_BITS_TX_HEADER_Q_ENABLE |
4022 BNX2_MISC_ENABLE_SET_BITS_EMAC_ENABLE);
4023
4024 val = BNX2_RD(bp, BNX2_RPM_CONFIG);
4025 val &= ~BNX2_RPM_CONFIG_ACPI_ENA;
4026 BNX2_WR(bp, BNX2_RPM_CONFIG, val);
4027
4028 wol_msg = BNX2_DRV_MSG_CODE_SUSPEND_WOL;
4029 } else {
4030 wol_msg = BNX2_DRV_MSG_CODE_SUSPEND_NO_WOL;
4031 }
4032
Michael Chana8d9bc22014-03-09 15:45:32 -08004033 if (!(bp->flags & BNX2_FLAG_NO_WOL)) {
4034 u32 val;
4035
4036 wol_msg |= BNX2_DRV_MSG_DATA_WAIT3;
4037 if (bp->fw_last_msg || BNX2_CHIP(bp) != BNX2_CHIP_5709) {
4038 bnx2_fw_sync(bp, wol_msg, 1, 0);
4039 return;
4040 }
4041 /* Tell firmware not to power down the PHY yet, otherwise
4042 * the chip will take a long time to respond to MMIO reads.
4043 */
4044 val = bnx2_shmem_rd(bp, BNX2_PORT_FEATURE);
4045 bnx2_shmem_wr(bp, BNX2_PORT_FEATURE,
4046 val | BNX2_PORT_FEATURE_ASF_ENABLED);
4047 bnx2_fw_sync(bp, wol_msg, 1, 0);
4048 bnx2_shmem_wr(bp, BNX2_PORT_FEATURE, val);
4049 }
Michael Chanb6a23e92013-08-06 15:50:09 -07004050
4051}
4052
Michael Chanb6016b72005-05-26 13:03:09 -07004053static int
Pavel Machek829ca9a2005-09-03 15:56:56 -07004054bnx2_set_power_state(struct bnx2 *bp, pci_power_t state)
Michael Chanb6016b72005-05-26 13:03:09 -07004055{
Michael Chanb6016b72005-05-26 13:03:09 -07004056 switch (state) {
Pavel Machek829ca9a2005-09-03 15:56:56 -07004057 case PCI_D0: {
Michael Chanb6016b72005-05-26 13:03:09 -07004058 u32 val;
4059
Michael Chan6d5e85c2013-08-06 15:50:08 -07004060 pci_enable_wake(bp->pdev, PCI_D0, false);
4061 pci_set_power_state(bp->pdev, PCI_D0);
Michael Chanb6016b72005-05-26 13:03:09 -07004062
Michael Chane503e062012-12-06 10:33:08 +00004063 val = BNX2_RD(bp, BNX2_EMAC_MODE);
Michael Chanb6016b72005-05-26 13:03:09 -07004064 val |= BNX2_EMAC_MODE_MPKT_RCVD | BNX2_EMAC_MODE_ACPI_RCVD;
4065 val &= ~BNX2_EMAC_MODE_MPKT;
Michael Chane503e062012-12-06 10:33:08 +00004066 BNX2_WR(bp, BNX2_EMAC_MODE, val);
Michael Chanb6016b72005-05-26 13:03:09 -07004067
Michael Chane503e062012-12-06 10:33:08 +00004068 val = BNX2_RD(bp, BNX2_RPM_CONFIG);
Michael Chanb6016b72005-05-26 13:03:09 -07004069 val &= ~BNX2_RPM_CONFIG_ACPI_ENA;
Michael Chane503e062012-12-06 10:33:08 +00004070 BNX2_WR(bp, BNX2_RPM_CONFIG, val);
Michael Chanb6016b72005-05-26 13:03:09 -07004071 break;
4072 }
Pavel Machek829ca9a2005-09-03 15:56:56 -07004073 case PCI_D3hot: {
Michael Chanb6a23e92013-08-06 15:50:09 -07004074 bnx2_setup_wol(bp);
Michael Chan6d5e85c2013-08-06 15:50:08 -07004075 pci_wake_from_d3(bp->pdev, bp->wol);
Michael Chan4ce45e02012-12-06 10:33:10 +00004076 if ((BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5706_A0) ||
4077 (BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5706_A1)) {
Michael Chanb6016b72005-05-26 13:03:09 -07004078
4079 if (bp->wol)
Michael Chan6d5e85c2013-08-06 15:50:08 -07004080 pci_set_power_state(bp->pdev, PCI_D3hot);
Michael Chana8d9bc22014-03-09 15:45:32 -08004081 break;
4082
Michael Chanb6016b72005-05-26 13:03:09 -07004083 }
Michael Chana8d9bc22014-03-09 15:45:32 -08004084 if (!bp->fw_last_msg && BNX2_CHIP(bp) == BNX2_CHIP_5709) {
4085 u32 val;
4086
4087 /* Tell firmware not to power down the PHY yet,
4088 * otherwise the other port may not respond to
4089 * MMIO reads.
4090 */
4091 val = bnx2_shmem_rd(bp, BNX2_BC_STATE_CONDITION);
4092 val &= ~BNX2_CONDITION_PM_STATE_MASK;
4093 val |= BNX2_CONDITION_PM_STATE_UNPREP;
4094 bnx2_shmem_wr(bp, BNX2_BC_STATE_CONDITION, val);
4095 }
4096 pci_set_power_state(bp->pdev, PCI_D3hot);
Michael Chanb6016b72005-05-26 13:03:09 -07004097
4098 /* No more memory access after this point until
4099 * device is brought back to D0.
4100 */
Michael Chanb6016b72005-05-26 13:03:09 -07004101 break;
4102 }
4103 default:
4104 return -EINVAL;
4105 }
4106 return 0;
4107}
4108
4109static int
4110bnx2_acquire_nvram_lock(struct bnx2 *bp)
4111{
4112 u32 val;
4113 int j;
4114
4115 /* Request access to the flash interface. */
Michael Chane503e062012-12-06 10:33:08 +00004116 BNX2_WR(bp, BNX2_NVM_SW_ARB, BNX2_NVM_SW_ARB_ARB_REQ_SET2);
Michael Chanb6016b72005-05-26 13:03:09 -07004117 for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) {
Michael Chane503e062012-12-06 10:33:08 +00004118 val = BNX2_RD(bp, BNX2_NVM_SW_ARB);
Michael Chanb6016b72005-05-26 13:03:09 -07004119 if (val & BNX2_NVM_SW_ARB_ARB_ARB2)
4120 break;
4121
4122 udelay(5);
4123 }
4124
4125 if (j >= NVRAM_TIMEOUT_COUNT)
4126 return -EBUSY;
4127
4128 return 0;
4129}
4130
4131static int
4132bnx2_release_nvram_lock(struct bnx2 *bp)
4133{
4134 int j;
4135 u32 val;
4136
4137 /* Relinquish nvram interface. */
Michael Chane503e062012-12-06 10:33:08 +00004138 BNX2_WR(bp, BNX2_NVM_SW_ARB, BNX2_NVM_SW_ARB_ARB_REQ_CLR2);
Michael Chanb6016b72005-05-26 13:03:09 -07004139
4140 for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) {
Michael Chane503e062012-12-06 10:33:08 +00004141 val = BNX2_RD(bp, BNX2_NVM_SW_ARB);
Michael Chanb6016b72005-05-26 13:03:09 -07004142 if (!(val & BNX2_NVM_SW_ARB_ARB_ARB2))
4143 break;
4144
4145 udelay(5);
4146 }
4147
4148 if (j >= NVRAM_TIMEOUT_COUNT)
4149 return -EBUSY;
4150
4151 return 0;
4152}
4153
4154
4155static int
4156bnx2_enable_nvram_write(struct bnx2 *bp)
4157{
4158 u32 val;
4159
Michael Chane503e062012-12-06 10:33:08 +00004160 val = BNX2_RD(bp, BNX2_MISC_CFG);
4161 BNX2_WR(bp, BNX2_MISC_CFG, val | BNX2_MISC_CFG_NVM_WR_EN_PCI);
Michael Chanb6016b72005-05-26 13:03:09 -07004162
Michael Chane30372c2007-07-16 18:26:23 -07004163 if (bp->flash_info->flags & BNX2_NV_WREN) {
Michael Chanb6016b72005-05-26 13:03:09 -07004164 int j;
4165
Michael Chane503e062012-12-06 10:33:08 +00004166 BNX2_WR(bp, BNX2_NVM_COMMAND, BNX2_NVM_COMMAND_DONE);
4167 BNX2_WR(bp, BNX2_NVM_COMMAND,
4168 BNX2_NVM_COMMAND_WREN | BNX2_NVM_COMMAND_DOIT);
Michael Chanb6016b72005-05-26 13:03:09 -07004169
4170 for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) {
4171 udelay(5);
4172
Michael Chane503e062012-12-06 10:33:08 +00004173 val = BNX2_RD(bp, BNX2_NVM_COMMAND);
Michael Chanb6016b72005-05-26 13:03:09 -07004174 if (val & BNX2_NVM_COMMAND_DONE)
4175 break;
4176 }
4177
4178 if (j >= NVRAM_TIMEOUT_COUNT)
4179 return -EBUSY;
4180 }
4181 return 0;
4182}
4183
4184static void
4185bnx2_disable_nvram_write(struct bnx2 *bp)
4186{
4187 u32 val;
4188
Michael Chane503e062012-12-06 10:33:08 +00004189 val = BNX2_RD(bp, BNX2_MISC_CFG);
4190 BNX2_WR(bp, BNX2_MISC_CFG, val & ~BNX2_MISC_CFG_NVM_WR_EN);
Michael Chanb6016b72005-05-26 13:03:09 -07004191}
4192
4193
4194static void
4195bnx2_enable_nvram_access(struct bnx2 *bp)
4196{
4197 u32 val;
4198
Michael Chane503e062012-12-06 10:33:08 +00004199 val = BNX2_RD(bp, BNX2_NVM_ACCESS_ENABLE);
Michael Chanb6016b72005-05-26 13:03:09 -07004200 /* Enable both bits, even on read. */
Michael Chane503e062012-12-06 10:33:08 +00004201 BNX2_WR(bp, BNX2_NVM_ACCESS_ENABLE,
4202 val | BNX2_NVM_ACCESS_ENABLE_EN | BNX2_NVM_ACCESS_ENABLE_WR_EN);
Michael Chanb6016b72005-05-26 13:03:09 -07004203}
4204
4205static void
4206bnx2_disable_nvram_access(struct bnx2 *bp)
4207{
4208 u32 val;
4209
Michael Chane503e062012-12-06 10:33:08 +00004210 val = BNX2_RD(bp, BNX2_NVM_ACCESS_ENABLE);
Michael Chanb6016b72005-05-26 13:03:09 -07004211 /* Disable both bits, even after read. */
Michael Chane503e062012-12-06 10:33:08 +00004212 BNX2_WR(bp, BNX2_NVM_ACCESS_ENABLE,
Michael Chanb6016b72005-05-26 13:03:09 -07004213 val & ~(BNX2_NVM_ACCESS_ENABLE_EN |
4214 BNX2_NVM_ACCESS_ENABLE_WR_EN));
4215}
4216
4217static int
4218bnx2_nvram_erase_page(struct bnx2 *bp, u32 offset)
4219{
4220 u32 cmd;
4221 int j;
4222
Michael Chane30372c2007-07-16 18:26:23 -07004223 if (bp->flash_info->flags & BNX2_NV_BUFFERED)
Michael Chanb6016b72005-05-26 13:03:09 -07004224 /* Buffered flash, no erase needed */
4225 return 0;
4226
4227 /* Build an erase command */
4228 cmd = BNX2_NVM_COMMAND_ERASE | BNX2_NVM_COMMAND_WR |
4229 BNX2_NVM_COMMAND_DOIT;
4230
4231 /* Need to clear DONE bit separately. */
Michael Chane503e062012-12-06 10:33:08 +00004232 BNX2_WR(bp, BNX2_NVM_COMMAND, BNX2_NVM_COMMAND_DONE);
Michael Chanb6016b72005-05-26 13:03:09 -07004233
4234 /* Address of the NVRAM to read from. */
Michael Chane503e062012-12-06 10:33:08 +00004235 BNX2_WR(bp, BNX2_NVM_ADDR, offset & BNX2_NVM_ADDR_NVM_ADDR_VALUE);
Michael Chanb6016b72005-05-26 13:03:09 -07004236
4237 /* Issue an erase command. */
Michael Chane503e062012-12-06 10:33:08 +00004238 BNX2_WR(bp, BNX2_NVM_COMMAND, cmd);
Michael Chanb6016b72005-05-26 13:03:09 -07004239
4240 /* Wait for completion. */
4241 for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) {
4242 u32 val;
4243
4244 udelay(5);
4245
Michael Chane503e062012-12-06 10:33:08 +00004246 val = BNX2_RD(bp, BNX2_NVM_COMMAND);
Michael Chanb6016b72005-05-26 13:03:09 -07004247 if (val & BNX2_NVM_COMMAND_DONE)
4248 break;
4249 }
4250
4251 if (j >= NVRAM_TIMEOUT_COUNT)
4252 return -EBUSY;
4253
4254 return 0;
4255}
4256
4257static int
4258bnx2_nvram_read_dword(struct bnx2 *bp, u32 offset, u8 *ret_val, u32 cmd_flags)
4259{
4260 u32 cmd;
4261 int j;
4262
4263 /* Build the command word. */
4264 cmd = BNX2_NVM_COMMAND_DOIT | cmd_flags;
4265
Michael Chane30372c2007-07-16 18:26:23 -07004266 /* Calculate an offset of a buffered flash, not needed for 5709. */
4267 if (bp->flash_info->flags & BNX2_NV_TRANSLATE) {
Michael Chanb6016b72005-05-26 13:03:09 -07004268 offset = ((offset / bp->flash_info->page_size) <<
4269 bp->flash_info->page_bits) +
4270 (offset % bp->flash_info->page_size);
4271 }
4272
4273 /* Need to clear DONE bit separately. */
Michael Chane503e062012-12-06 10:33:08 +00004274 BNX2_WR(bp, BNX2_NVM_COMMAND, BNX2_NVM_COMMAND_DONE);
Michael Chanb6016b72005-05-26 13:03:09 -07004275
4276 /* Address of the NVRAM to read from. */
Michael Chane503e062012-12-06 10:33:08 +00004277 BNX2_WR(bp, BNX2_NVM_ADDR, offset & BNX2_NVM_ADDR_NVM_ADDR_VALUE);
Michael Chanb6016b72005-05-26 13:03:09 -07004278
4279 /* Issue a read command. */
Michael Chane503e062012-12-06 10:33:08 +00004280 BNX2_WR(bp, BNX2_NVM_COMMAND, cmd);
Michael Chanb6016b72005-05-26 13:03:09 -07004281
4282 /* Wait for completion. */
4283 for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) {
4284 u32 val;
4285
4286 udelay(5);
4287
Michael Chane503e062012-12-06 10:33:08 +00004288 val = BNX2_RD(bp, BNX2_NVM_COMMAND);
Michael Chanb6016b72005-05-26 13:03:09 -07004289 if (val & BNX2_NVM_COMMAND_DONE) {
Michael Chane503e062012-12-06 10:33:08 +00004290 __be32 v = cpu_to_be32(BNX2_RD(bp, BNX2_NVM_READ));
Al Virob491edd2007-12-22 19:44:51 +00004291 memcpy(ret_val, &v, 4);
Michael Chanb6016b72005-05-26 13:03:09 -07004292 break;
4293 }
4294 }
4295 if (j >= NVRAM_TIMEOUT_COUNT)
4296 return -EBUSY;
4297
4298 return 0;
4299}
4300
4301
4302static int
4303bnx2_nvram_write_dword(struct bnx2 *bp, u32 offset, u8 *val, u32 cmd_flags)
4304{
Al Virob491edd2007-12-22 19:44:51 +00004305 u32 cmd;
4306 __be32 val32;
Michael Chanb6016b72005-05-26 13:03:09 -07004307 int j;
4308
4309 /* Build the command word. */
4310 cmd = BNX2_NVM_COMMAND_DOIT | BNX2_NVM_COMMAND_WR | cmd_flags;
4311
Michael Chane30372c2007-07-16 18:26:23 -07004312 /* Calculate an offset of a buffered flash, not needed for 5709. */
4313 if (bp->flash_info->flags & BNX2_NV_TRANSLATE) {
Michael Chanb6016b72005-05-26 13:03:09 -07004314 offset = ((offset / bp->flash_info->page_size) <<
4315 bp->flash_info->page_bits) +
4316 (offset % bp->flash_info->page_size);
4317 }
4318
4319 /* Need to clear DONE bit separately. */
Michael Chane503e062012-12-06 10:33:08 +00004320 BNX2_WR(bp, BNX2_NVM_COMMAND, BNX2_NVM_COMMAND_DONE);
Michael Chanb6016b72005-05-26 13:03:09 -07004321
4322 memcpy(&val32, val, 4);
Michael Chanb6016b72005-05-26 13:03:09 -07004323
4324 /* Write the data. */
Michael Chane503e062012-12-06 10:33:08 +00004325 BNX2_WR(bp, BNX2_NVM_WRITE, be32_to_cpu(val32));
Michael Chanb6016b72005-05-26 13:03:09 -07004326
4327 /* Address of the NVRAM to write to. */
Michael Chane503e062012-12-06 10:33:08 +00004328 BNX2_WR(bp, BNX2_NVM_ADDR, offset & BNX2_NVM_ADDR_NVM_ADDR_VALUE);
Michael Chanb6016b72005-05-26 13:03:09 -07004329
4330 /* Issue the write command. */
Michael Chane503e062012-12-06 10:33:08 +00004331 BNX2_WR(bp, BNX2_NVM_COMMAND, cmd);
Michael Chanb6016b72005-05-26 13:03:09 -07004332
4333 /* Wait for completion. */
4334 for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) {
4335 udelay(5);
4336
Michael Chane503e062012-12-06 10:33:08 +00004337 if (BNX2_RD(bp, BNX2_NVM_COMMAND) & BNX2_NVM_COMMAND_DONE)
Michael Chanb6016b72005-05-26 13:03:09 -07004338 break;
4339 }
4340 if (j >= NVRAM_TIMEOUT_COUNT)
4341 return -EBUSY;
4342
4343 return 0;
4344}
4345
4346static int
4347bnx2_init_nvram(struct bnx2 *bp)
4348{
4349 u32 val;
Michael Chane30372c2007-07-16 18:26:23 -07004350 int j, entry_count, rc = 0;
Michael Chan0ced9d02009-08-21 16:20:49 +00004351 const struct flash_spec *flash;
Michael Chanb6016b72005-05-26 13:03:09 -07004352
Michael Chan4ce45e02012-12-06 10:33:10 +00004353 if (BNX2_CHIP(bp) == BNX2_CHIP_5709) {
Michael Chane30372c2007-07-16 18:26:23 -07004354 bp->flash_info = &flash_5709;
4355 goto get_flash_size;
4356 }
4357
Michael Chanb6016b72005-05-26 13:03:09 -07004358 /* Determine the selected interface. */
Michael Chane503e062012-12-06 10:33:08 +00004359 val = BNX2_RD(bp, BNX2_NVM_CFG1);
Michael Chanb6016b72005-05-26 13:03:09 -07004360
Denis Chengff8ac602007-09-02 18:30:18 +08004361 entry_count = ARRAY_SIZE(flash_table);
Michael Chanb6016b72005-05-26 13:03:09 -07004362
Michael Chanb6016b72005-05-26 13:03:09 -07004363 if (val & 0x40000000) {
4364
4365 /* Flash interface has been reconfigured */
4366 for (j = 0, flash = &flash_table[0]; j < entry_count;
Michael Chan37137702005-11-04 08:49:17 -08004367 j++, flash++) {
4368 if ((val & FLASH_BACKUP_STRAP_MASK) ==
4369 (flash->config1 & FLASH_BACKUP_STRAP_MASK)) {
Michael Chanb6016b72005-05-26 13:03:09 -07004370 bp->flash_info = flash;
4371 break;
4372 }
4373 }
4374 }
4375 else {
Michael Chan37137702005-11-04 08:49:17 -08004376 u32 mask;
Michael Chanb6016b72005-05-26 13:03:09 -07004377 /* Not yet been reconfigured */
4378
Michael Chan37137702005-11-04 08:49:17 -08004379 if (val & (1 << 23))
4380 mask = FLASH_BACKUP_STRAP_MASK;
4381 else
4382 mask = FLASH_STRAP_MASK;
4383
Michael Chanb6016b72005-05-26 13:03:09 -07004384 for (j = 0, flash = &flash_table[0]; j < entry_count;
4385 j++, flash++) {
4386
Michael Chan37137702005-11-04 08:49:17 -08004387 if ((val & mask) == (flash->strapping & mask)) {
Michael Chanb6016b72005-05-26 13:03:09 -07004388 bp->flash_info = flash;
4389
4390 /* Request access to the flash interface. */
4391 if ((rc = bnx2_acquire_nvram_lock(bp)) != 0)
4392 return rc;
4393
4394 /* Enable access to flash interface */
4395 bnx2_enable_nvram_access(bp);
4396
4397 /* Reconfigure the flash interface */
Michael Chane503e062012-12-06 10:33:08 +00004398 BNX2_WR(bp, BNX2_NVM_CFG1, flash->config1);
4399 BNX2_WR(bp, BNX2_NVM_CFG2, flash->config2);
4400 BNX2_WR(bp, BNX2_NVM_CFG3, flash->config3);
4401 BNX2_WR(bp, BNX2_NVM_WRITE1, flash->write1);
Michael Chanb6016b72005-05-26 13:03:09 -07004402
4403 /* Disable access to flash interface */
4404 bnx2_disable_nvram_access(bp);
4405 bnx2_release_nvram_lock(bp);
4406
4407 break;
4408 }
4409 }
4410 } /* if (val & 0x40000000) */
4411
4412 if (j == entry_count) {
4413 bp->flash_info = NULL;
Joe Perches3a9c6a42010-02-17 15:01:51 +00004414 pr_alert("Unknown flash/EEPROM type\n");
Michael Chan1122db72006-01-23 16:11:42 -08004415 return -ENODEV;
Michael Chanb6016b72005-05-26 13:03:09 -07004416 }
4417
Michael Chane30372c2007-07-16 18:26:23 -07004418get_flash_size:
Michael Chan2726d6e2008-01-29 21:35:05 -08004419 val = bnx2_shmem_rd(bp, BNX2_SHARED_HW_CFG_CONFIG2);
Michael Chan1122db72006-01-23 16:11:42 -08004420 val &= BNX2_SHARED_HW_CFG2_NVM_SIZE_MASK;
4421 if (val)
4422 bp->flash_size = val;
4423 else
4424 bp->flash_size = bp->flash_info->total_size;
4425
Michael Chanb6016b72005-05-26 13:03:09 -07004426 return rc;
4427}
4428
4429static int
4430bnx2_nvram_read(struct bnx2 *bp, u32 offset, u8 *ret_buf,
4431 int buf_size)
4432{
4433 int rc = 0;
4434 u32 cmd_flags, offset32, len32, extra;
4435
4436 if (buf_size == 0)
4437 return 0;
4438
4439 /* Request access to the flash interface. */
4440 if ((rc = bnx2_acquire_nvram_lock(bp)) != 0)
4441 return rc;
4442
4443 /* Enable access to flash interface */
4444 bnx2_enable_nvram_access(bp);
4445
4446 len32 = buf_size;
4447 offset32 = offset;
4448 extra = 0;
4449
4450 cmd_flags = 0;
4451
4452 if (offset32 & 3) {
4453 u8 buf[4];
4454 u32 pre_len;
4455
4456 offset32 &= ~3;
4457 pre_len = 4 - (offset & 3);
4458
4459 if (pre_len >= len32) {
4460 pre_len = len32;
4461 cmd_flags = BNX2_NVM_COMMAND_FIRST |
4462 BNX2_NVM_COMMAND_LAST;
4463 }
4464 else {
4465 cmd_flags = BNX2_NVM_COMMAND_FIRST;
4466 }
4467
4468 rc = bnx2_nvram_read_dword(bp, offset32, buf, cmd_flags);
4469
4470 if (rc)
4471 return rc;
4472
4473 memcpy(ret_buf, buf + (offset & 3), pre_len);
4474
4475 offset32 += 4;
4476 ret_buf += pre_len;
4477 len32 -= pre_len;
4478 }
4479 if (len32 & 3) {
4480 extra = 4 - (len32 & 3);
4481 len32 = (len32 + 4) & ~3;
4482 }
4483
4484 if (len32 == 4) {
4485 u8 buf[4];
4486
4487 if (cmd_flags)
4488 cmd_flags = BNX2_NVM_COMMAND_LAST;
4489 else
4490 cmd_flags = BNX2_NVM_COMMAND_FIRST |
4491 BNX2_NVM_COMMAND_LAST;
4492
4493 rc = bnx2_nvram_read_dword(bp, offset32, buf, cmd_flags);
4494
4495 memcpy(ret_buf, buf, 4 - extra);
4496 }
4497 else if (len32 > 0) {
4498 u8 buf[4];
4499
4500 /* Read the first word. */
4501 if (cmd_flags)
4502 cmd_flags = 0;
4503 else
4504 cmd_flags = BNX2_NVM_COMMAND_FIRST;
4505
4506 rc = bnx2_nvram_read_dword(bp, offset32, ret_buf, cmd_flags);
4507
4508 /* Advance to the next dword. */
4509 offset32 += 4;
4510 ret_buf += 4;
4511 len32 -= 4;
4512
4513 while (len32 > 4 && rc == 0) {
4514 rc = bnx2_nvram_read_dword(bp, offset32, ret_buf, 0);
4515
4516 /* Advance to the next dword. */
4517 offset32 += 4;
4518 ret_buf += 4;
4519 len32 -= 4;
4520 }
4521
4522 if (rc)
4523 return rc;
4524
4525 cmd_flags = BNX2_NVM_COMMAND_LAST;
4526 rc = bnx2_nvram_read_dword(bp, offset32, buf, cmd_flags);
4527
4528 memcpy(ret_buf, buf, 4 - extra);
4529 }
4530
4531 /* Disable access to flash interface */
4532 bnx2_disable_nvram_access(bp);
4533
4534 bnx2_release_nvram_lock(bp);
4535
4536 return rc;
4537}
4538
4539static int
4540bnx2_nvram_write(struct bnx2 *bp, u32 offset, u8 *data_buf,
4541 int buf_size)
4542{
4543 u32 written, offset32, len32;
Michael Chane6be7632007-01-08 19:56:13 -08004544 u8 *buf, start[4], end[4], *align_buf = NULL, *flash_buffer = NULL;
Michael Chanb6016b72005-05-26 13:03:09 -07004545 int rc = 0;
4546 int align_start, align_end;
4547
4548 buf = data_buf;
4549 offset32 = offset;
4550 len32 = buf_size;
4551 align_start = align_end = 0;
4552
4553 if ((align_start = (offset32 & 3))) {
4554 offset32 &= ~3;
Michael Chanc8738792007-03-30 14:53:06 -07004555 len32 += align_start;
4556 if (len32 < 4)
4557 len32 = 4;
Michael Chanb6016b72005-05-26 13:03:09 -07004558 if ((rc = bnx2_nvram_read(bp, offset32, start, 4)))
4559 return rc;
4560 }
4561
4562 if (len32 & 3) {
Michael Chanc8738792007-03-30 14:53:06 -07004563 align_end = 4 - (len32 & 3);
4564 len32 += align_end;
4565 if ((rc = bnx2_nvram_read(bp, offset32 + len32 - 4, end, 4)))
4566 return rc;
Michael Chanb6016b72005-05-26 13:03:09 -07004567 }
4568
4569 if (align_start || align_end) {
Michael Chane6be7632007-01-08 19:56:13 -08004570 align_buf = kmalloc(len32, GFP_KERNEL);
4571 if (align_buf == NULL)
Michael Chanb6016b72005-05-26 13:03:09 -07004572 return -ENOMEM;
4573 if (align_start) {
Michael Chane6be7632007-01-08 19:56:13 -08004574 memcpy(align_buf, start, 4);
Michael Chanb6016b72005-05-26 13:03:09 -07004575 }
4576 if (align_end) {
Michael Chane6be7632007-01-08 19:56:13 -08004577 memcpy(align_buf + len32 - 4, end, 4);
Michael Chanb6016b72005-05-26 13:03:09 -07004578 }
Michael Chane6be7632007-01-08 19:56:13 -08004579 memcpy(align_buf + align_start, data_buf, buf_size);
4580 buf = align_buf;
Michael Chanb6016b72005-05-26 13:03:09 -07004581 }
4582
Michael Chane30372c2007-07-16 18:26:23 -07004583 if (!(bp->flash_info->flags & BNX2_NV_BUFFERED)) {
Michael Chanae181bc2006-05-22 16:39:20 -07004584 flash_buffer = kmalloc(264, GFP_KERNEL);
4585 if (flash_buffer == NULL) {
4586 rc = -ENOMEM;
4587 goto nvram_write_end;
4588 }
4589 }
4590
Michael Chanb6016b72005-05-26 13:03:09 -07004591 written = 0;
4592 while ((written < len32) && (rc == 0)) {
4593 u32 page_start, page_end, data_start, data_end;
4594 u32 addr, cmd_flags;
4595 int i;
Michael Chanb6016b72005-05-26 13:03:09 -07004596
4597 /* Find the page_start addr */
4598 page_start = offset32 + written;
4599 page_start -= (page_start % bp->flash_info->page_size);
4600 /* Find the page_end addr */
4601 page_end = page_start + bp->flash_info->page_size;
4602 /* Find the data_start addr */
4603 data_start = (written == 0) ? offset32 : page_start;
4604 /* Find the data_end addr */
Jeff Garzik6aa20a22006-09-13 13:24:59 -04004605 data_end = (page_end > offset32 + len32) ?
Michael Chanb6016b72005-05-26 13:03:09 -07004606 (offset32 + len32) : page_end;
4607
4608 /* Request access to the flash interface. */
4609 if ((rc = bnx2_acquire_nvram_lock(bp)) != 0)
4610 goto nvram_write_end;
4611
4612 /* Enable access to flash interface */
4613 bnx2_enable_nvram_access(bp);
4614
4615 cmd_flags = BNX2_NVM_COMMAND_FIRST;
Michael Chane30372c2007-07-16 18:26:23 -07004616 if (!(bp->flash_info->flags & BNX2_NV_BUFFERED)) {
Michael Chanb6016b72005-05-26 13:03:09 -07004617 int j;
4618
4619 /* Read the whole page into the buffer
4620 * (non-buffer flash only) */
4621 for (j = 0; j < bp->flash_info->page_size; j += 4) {
4622 if (j == (bp->flash_info->page_size - 4)) {
4623 cmd_flags |= BNX2_NVM_COMMAND_LAST;
4624 }
4625 rc = bnx2_nvram_read_dword(bp,
Jeff Garzik6aa20a22006-09-13 13:24:59 -04004626 page_start + j,
4627 &flash_buffer[j],
Michael Chanb6016b72005-05-26 13:03:09 -07004628 cmd_flags);
4629
4630 if (rc)
4631 goto nvram_write_end;
4632
4633 cmd_flags = 0;
4634 }
4635 }
4636
4637 /* Enable writes to flash interface (unlock write-protect) */
4638 if ((rc = bnx2_enable_nvram_write(bp)) != 0)
4639 goto nvram_write_end;
4640
Michael Chanb6016b72005-05-26 13:03:09 -07004641 /* Loop to write back the buffer data from page_start to
4642 * data_start */
4643 i = 0;
Michael Chane30372c2007-07-16 18:26:23 -07004644 if (!(bp->flash_info->flags & BNX2_NV_BUFFERED)) {
Michael Chanc8738792007-03-30 14:53:06 -07004645 /* Erase the page */
4646 if ((rc = bnx2_nvram_erase_page(bp, page_start)) != 0)
4647 goto nvram_write_end;
4648
4649 /* Re-enable the write again for the actual write */
4650 bnx2_enable_nvram_write(bp);
4651
Michael Chanb6016b72005-05-26 13:03:09 -07004652 for (addr = page_start; addr < data_start;
4653 addr += 4, i += 4) {
Jeff Garzik6aa20a22006-09-13 13:24:59 -04004654
Michael Chanb6016b72005-05-26 13:03:09 -07004655 rc = bnx2_nvram_write_dword(bp, addr,
4656 &flash_buffer[i], cmd_flags);
4657
4658 if (rc != 0)
4659 goto nvram_write_end;
4660
4661 cmd_flags = 0;
4662 }
4663 }
4664
4665 /* Loop to write the new data from data_start to data_end */
Michael Chanbae25762006-05-22 16:38:38 -07004666 for (addr = data_start; addr < data_end; addr += 4, i += 4) {
Michael Chanb6016b72005-05-26 13:03:09 -07004667 if ((addr == page_end - 4) ||
Michael Chane30372c2007-07-16 18:26:23 -07004668 ((bp->flash_info->flags & BNX2_NV_BUFFERED) &&
Michael Chanb6016b72005-05-26 13:03:09 -07004669 (addr == data_end - 4))) {
4670
4671 cmd_flags |= BNX2_NVM_COMMAND_LAST;
4672 }
4673 rc = bnx2_nvram_write_dword(bp, addr, buf,
4674 cmd_flags);
4675
4676 if (rc != 0)
4677 goto nvram_write_end;
4678
4679 cmd_flags = 0;
4680 buf += 4;
4681 }
4682
4683 /* Loop to write back the buffer data from data_end
4684 * to page_end */
Michael Chane30372c2007-07-16 18:26:23 -07004685 if (!(bp->flash_info->flags & BNX2_NV_BUFFERED)) {
Michael Chanb6016b72005-05-26 13:03:09 -07004686 for (addr = data_end; addr < page_end;
4687 addr += 4, i += 4) {
Jeff Garzik6aa20a22006-09-13 13:24:59 -04004688
Michael Chanb6016b72005-05-26 13:03:09 -07004689 if (addr == page_end-4) {
4690 cmd_flags = BNX2_NVM_COMMAND_LAST;
4691 }
4692 rc = bnx2_nvram_write_dword(bp, addr,
4693 &flash_buffer[i], cmd_flags);
4694
4695 if (rc != 0)
4696 goto nvram_write_end;
4697
4698 cmd_flags = 0;
4699 }
4700 }
4701
4702 /* Disable writes to flash interface (lock write-protect) */
4703 bnx2_disable_nvram_write(bp);
4704
4705 /* Disable access to flash interface */
4706 bnx2_disable_nvram_access(bp);
4707 bnx2_release_nvram_lock(bp);
4708
4709 /* Increment written */
4710 written += data_end - data_start;
4711 }
4712
4713nvram_write_end:
Michael Chane6be7632007-01-08 19:56:13 -08004714 kfree(flash_buffer);
4715 kfree(align_buf);
Michael Chanb6016b72005-05-26 13:03:09 -07004716 return rc;
4717}
4718
Michael Chan0d8a6572007-07-07 22:49:43 -07004719static void
Michael Chan7c62e832008-07-14 22:39:03 -07004720bnx2_init_fw_cap(struct bnx2 *bp)
Michael Chan0d8a6572007-07-07 22:49:43 -07004721{
Michael Chan7c62e832008-07-14 22:39:03 -07004722 u32 val, sig = 0;
Michael Chan0d8a6572007-07-07 22:49:43 -07004723
Michael Chan583c28e2008-01-21 19:51:35 -08004724 bp->phy_flags &= ~BNX2_PHY_FLAG_REMOTE_PHY_CAP;
Michael Chan7c62e832008-07-14 22:39:03 -07004725 bp->flags &= ~BNX2_FLAG_CAN_KEEP_VLAN;
4726
4727 if (!(bp->flags & BNX2_FLAG_ASF_ENABLE))
4728 bp->flags |= BNX2_FLAG_CAN_KEEP_VLAN;
Michael Chan0d8a6572007-07-07 22:49:43 -07004729
Michael Chan2726d6e2008-01-29 21:35:05 -08004730 val = bnx2_shmem_rd(bp, BNX2_FW_CAP_MB);
Michael Chan0d8a6572007-07-07 22:49:43 -07004731 if ((val & BNX2_FW_CAP_SIGNATURE_MASK) != BNX2_FW_CAP_SIGNATURE)
4732 return;
4733
Michael Chan7c62e832008-07-14 22:39:03 -07004734 if ((val & BNX2_FW_CAP_CAN_KEEP_VLAN) == BNX2_FW_CAP_CAN_KEEP_VLAN) {
4735 bp->flags |= BNX2_FLAG_CAN_KEEP_VLAN;
4736 sig |= BNX2_DRV_ACK_CAP_SIGNATURE | BNX2_FW_CAP_CAN_KEEP_VLAN;
4737 }
4738
4739 if ((bp->phy_flags & BNX2_PHY_FLAG_SERDES) &&
4740 (val & BNX2_FW_CAP_REMOTE_PHY_CAPABLE)) {
4741 u32 link;
4742
Michael Chan583c28e2008-01-21 19:51:35 -08004743 bp->phy_flags |= BNX2_PHY_FLAG_REMOTE_PHY_CAP;
Michael Chan0d8a6572007-07-07 22:49:43 -07004744
Michael Chan7c62e832008-07-14 22:39:03 -07004745 link = bnx2_shmem_rd(bp, BNX2_LINK_STATUS);
4746 if (link & BNX2_LINK_STATUS_SERDES_LINK)
Michael Chan0d8a6572007-07-07 22:49:43 -07004747 bp->phy_port = PORT_FIBRE;
4748 else
4749 bp->phy_port = PORT_TP;
Michael Chan489310a2007-10-10 16:16:31 -07004750
Michael Chan7c62e832008-07-14 22:39:03 -07004751 sig |= BNX2_DRV_ACK_CAP_SIGNATURE |
4752 BNX2_FW_CAP_REMOTE_PHY_CAPABLE;
Michael Chan0d8a6572007-07-07 22:49:43 -07004753 }
Michael Chan7c62e832008-07-14 22:39:03 -07004754
4755 if (netif_running(bp->dev) && sig)
4756 bnx2_shmem_wr(bp, BNX2_DRV_ACK_CAP_MB, sig);
Michael Chan0d8a6572007-07-07 22:49:43 -07004757}
4758
Michael Chanb4b36042007-12-20 19:59:30 -08004759static void
4760bnx2_setup_msix_tbl(struct bnx2 *bp)
4761{
Michael Chane503e062012-12-06 10:33:08 +00004762 BNX2_WR(bp, BNX2_PCI_GRC_WINDOW_ADDR, BNX2_PCI_GRC_WINDOW_ADDR_SEP_WIN);
Michael Chanb4b36042007-12-20 19:59:30 -08004763
Michael Chane503e062012-12-06 10:33:08 +00004764 BNX2_WR(bp, BNX2_PCI_GRC_WINDOW2_ADDR, BNX2_MSIX_TABLE_ADDR);
4765 BNX2_WR(bp, BNX2_PCI_GRC_WINDOW3_ADDR, BNX2_MSIX_PBA_ADDR);
Michael Chanb4b36042007-12-20 19:59:30 -08004766}
4767
Baoquan He6df77862016-11-13 13:01:33 +08004768static void
4769bnx2_wait_dma_complete(struct bnx2 *bp)
Michael Chanb6016b72005-05-26 13:03:09 -07004770{
4771 u32 val;
Baoquan He6df77862016-11-13 13:01:33 +08004772 int i;
Michael Chanb6016b72005-05-26 13:03:09 -07004773
Baoquan He6df77862016-11-13 13:01:33 +08004774 /*
4775 * Wait for the current PCI transaction to complete before
4776 * issuing a reset.
4777 */
Michael Chan4ce45e02012-12-06 10:33:10 +00004778 if ((BNX2_CHIP(bp) == BNX2_CHIP_5706) ||
4779 (BNX2_CHIP(bp) == BNX2_CHIP_5708)) {
Michael Chane503e062012-12-06 10:33:08 +00004780 BNX2_WR(bp, BNX2_MISC_ENABLE_CLR_BITS,
4781 BNX2_MISC_ENABLE_CLR_BITS_TX_DMA_ENABLE |
4782 BNX2_MISC_ENABLE_CLR_BITS_DMA_ENGINE_ENABLE |
4783 BNX2_MISC_ENABLE_CLR_BITS_RX_DMA_ENABLE |
4784 BNX2_MISC_ENABLE_CLR_BITS_HOST_COALESCE_ENABLE);
4785 val = BNX2_RD(bp, BNX2_MISC_ENABLE_CLR_BITS);
Eddie Waia5dac102010-11-24 13:48:54 +00004786 udelay(5);
4787 } else { /* 5709 */
Michael Chane503e062012-12-06 10:33:08 +00004788 val = BNX2_RD(bp, BNX2_MISC_NEW_CORE_CTL);
Eddie Waia5dac102010-11-24 13:48:54 +00004789 val &= ~BNX2_MISC_NEW_CORE_CTL_DMA_ENABLE;
Michael Chane503e062012-12-06 10:33:08 +00004790 BNX2_WR(bp, BNX2_MISC_NEW_CORE_CTL, val);
4791 val = BNX2_RD(bp, BNX2_MISC_NEW_CORE_CTL);
Eddie Waia5dac102010-11-24 13:48:54 +00004792
4793 for (i = 0; i < 100; i++) {
4794 msleep(1);
Michael Chane503e062012-12-06 10:33:08 +00004795 val = BNX2_RD(bp, BNX2_PCICFG_DEVICE_CONTROL);
Eddie Waia5dac102010-11-24 13:48:54 +00004796 if (!(val & BNX2_PCICFG_DEVICE_STATUS_NO_PEND))
4797 break;
4798 }
4799 }
Michael Chanb6016b72005-05-26 13:03:09 -07004800
Baoquan He6df77862016-11-13 13:01:33 +08004801 return;
4802}
4803
4804
4805static int
4806bnx2_reset_chip(struct bnx2 *bp, u32 reset_code)
4807{
4808 u32 val;
4809 int i, rc = 0;
4810 u8 old_port;
4811
4812 /* Wait for the current PCI transaction to complete before
4813 * issuing a reset. */
4814 bnx2_wait_dma_complete(bp);
4815
Michael Chanb090ae22006-01-23 16:07:10 -08004816 /* Wait for the firmware to tell us it is ok to issue a reset. */
Michael Chana2f13892008-07-14 22:38:23 -07004817 bnx2_fw_sync(bp, BNX2_DRV_MSG_DATA_WAIT0 | reset_code, 1, 1);
Michael Chanb090ae22006-01-23 16:07:10 -08004818
Michael Chanb6016b72005-05-26 13:03:09 -07004819 /* Deposit a driver reset signature so the firmware knows that
4820 * this is a soft reset. */
Michael Chan2726d6e2008-01-29 21:35:05 -08004821 bnx2_shmem_wr(bp, BNX2_DRV_RESET_SIGNATURE,
4822 BNX2_DRV_RESET_SIGNATURE_MAGIC);
Michael Chanb6016b72005-05-26 13:03:09 -07004823
Michael Chanb6016b72005-05-26 13:03:09 -07004824 /* Do a dummy read to force the chip to complete all current transaction
4825 * before we issue a reset. */
Michael Chane503e062012-12-06 10:33:08 +00004826 val = BNX2_RD(bp, BNX2_MISC_ID);
Michael Chanb6016b72005-05-26 13:03:09 -07004827
Michael Chan4ce45e02012-12-06 10:33:10 +00004828 if (BNX2_CHIP(bp) == BNX2_CHIP_5709) {
Michael Chane503e062012-12-06 10:33:08 +00004829 BNX2_WR(bp, BNX2_MISC_COMMAND, BNX2_MISC_COMMAND_SW_RESET);
4830 BNX2_RD(bp, BNX2_MISC_COMMAND);
Michael Chan234754d2006-11-19 14:11:41 -08004831 udelay(5);
Michael Chanb6016b72005-05-26 13:03:09 -07004832
Michael Chan234754d2006-11-19 14:11:41 -08004833 val = BNX2_PCICFG_MISC_CONFIG_REG_WINDOW_ENA |
4834 BNX2_PCICFG_MISC_CONFIG_TARGET_MB_WORD_SWAP;
Michael Chanb6016b72005-05-26 13:03:09 -07004835
Michael Chane503e062012-12-06 10:33:08 +00004836 BNX2_WR(bp, BNX2_PCICFG_MISC_CONFIG, val);
Michael Chanb6016b72005-05-26 13:03:09 -07004837
Michael Chan234754d2006-11-19 14:11:41 -08004838 } else {
4839 val = BNX2_PCICFG_MISC_CONFIG_CORE_RST_REQ |
4840 BNX2_PCICFG_MISC_CONFIG_REG_WINDOW_ENA |
4841 BNX2_PCICFG_MISC_CONFIG_TARGET_MB_WORD_SWAP;
4842
4843 /* Chip reset. */
Michael Chane503e062012-12-06 10:33:08 +00004844 BNX2_WR(bp, BNX2_PCICFG_MISC_CONFIG, val);
Michael Chan234754d2006-11-19 14:11:41 -08004845
Michael Chan594a9df2007-08-28 15:39:42 -07004846 /* Reading back any register after chip reset will hang the
4847 * bus on 5706 A0 and A1. The msleep below provides plenty
4848 * of margin for write posting.
4849 */
Michael Chan4ce45e02012-12-06 10:33:10 +00004850 if ((BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5706_A0) ||
4851 (BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5706_A1))
Arjan van de Ven8e545882007-08-28 14:34:43 -07004852 msleep(20);
Michael Chanb6016b72005-05-26 13:03:09 -07004853
Michael Chan234754d2006-11-19 14:11:41 -08004854 /* Reset takes approximate 30 usec */
4855 for (i = 0; i < 10; i++) {
Michael Chane503e062012-12-06 10:33:08 +00004856 val = BNX2_RD(bp, BNX2_PCICFG_MISC_CONFIG);
Michael Chan234754d2006-11-19 14:11:41 -08004857 if ((val & (BNX2_PCICFG_MISC_CONFIG_CORE_RST_REQ |
4858 BNX2_PCICFG_MISC_CONFIG_CORE_RST_BSY)) == 0)
4859 break;
4860 udelay(10);
4861 }
4862
4863 if (val & (BNX2_PCICFG_MISC_CONFIG_CORE_RST_REQ |
4864 BNX2_PCICFG_MISC_CONFIG_CORE_RST_BSY)) {
Joe Perches3a9c6a42010-02-17 15:01:51 +00004865 pr_err("Chip reset did not complete\n");
Michael Chan234754d2006-11-19 14:11:41 -08004866 return -EBUSY;
4867 }
Michael Chanb6016b72005-05-26 13:03:09 -07004868 }
4869
4870 /* Make sure byte swapping is properly configured. */
Michael Chane503e062012-12-06 10:33:08 +00004871 val = BNX2_RD(bp, BNX2_PCI_SWAP_DIAG0);
Michael Chanb6016b72005-05-26 13:03:09 -07004872 if (val != 0x01020304) {
Joe Perches3a9c6a42010-02-17 15:01:51 +00004873 pr_err("Chip not in correct endian mode\n");
Michael Chanb6016b72005-05-26 13:03:09 -07004874 return -ENODEV;
4875 }
4876
Michael Chanb6016b72005-05-26 13:03:09 -07004877 /* Wait for the firmware to finish its initialization. */
Michael Chana2f13892008-07-14 22:38:23 -07004878 rc = bnx2_fw_sync(bp, BNX2_DRV_MSG_DATA_WAIT1 | reset_code, 1, 0);
Michael Chanb090ae22006-01-23 16:07:10 -08004879 if (rc)
4880 return rc;
Michael Chanb6016b72005-05-26 13:03:09 -07004881
Michael Chan0d8a6572007-07-07 22:49:43 -07004882 spin_lock_bh(&bp->phy_lock);
Michael Chan489310a2007-10-10 16:16:31 -07004883 old_port = bp->phy_port;
Michael Chan7c62e832008-07-14 22:39:03 -07004884 bnx2_init_fw_cap(bp);
Michael Chan583c28e2008-01-21 19:51:35 -08004885 if ((bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP) &&
4886 old_port != bp->phy_port)
Michael Chan0d8a6572007-07-07 22:49:43 -07004887 bnx2_set_default_remote_link(bp);
4888 spin_unlock_bh(&bp->phy_lock);
4889
Michael Chan4ce45e02012-12-06 10:33:10 +00004890 if (BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5706_A0) {
Michael Chanb6016b72005-05-26 13:03:09 -07004891 /* Adjust the voltage regular to two steps lower. The default
4892 * of this register is 0x0000000e. */
Michael Chane503e062012-12-06 10:33:08 +00004893 BNX2_WR(bp, BNX2_MISC_VREG_CONTROL, 0x000000fa);
Michael Chanb6016b72005-05-26 13:03:09 -07004894
4895 /* Remove bad rbuf memory from the free pool. */
4896 rc = bnx2_alloc_bad_rbuf(bp);
4897 }
4898
Michael Chanc441b8d2010-04-27 11:28:09 +00004899 if (bp->flags & BNX2_FLAG_USING_MSIX) {
Michael Chanb4b36042007-12-20 19:59:30 -08004900 bnx2_setup_msix_tbl(bp);
Michael Chanc441b8d2010-04-27 11:28:09 +00004901 /* Prevent MSIX table reads and write from timing out */
Michael Chane503e062012-12-06 10:33:08 +00004902 BNX2_WR(bp, BNX2_MISC_ECO_HW_CTL,
Michael Chanc441b8d2010-04-27 11:28:09 +00004903 BNX2_MISC_ECO_HW_CTL_LARGE_GRC_TMOUT_EN);
4904 }
Michael Chanb4b36042007-12-20 19:59:30 -08004905
Michael Chanb6016b72005-05-26 13:03:09 -07004906 return rc;
4907}
4908
4909static int
4910bnx2_init_chip(struct bnx2 *bp)
4911{
Michael Chand8026d92008-11-12 16:02:20 -08004912 u32 val, mtu;
Michael Chanb4b36042007-12-20 19:59:30 -08004913 int rc, i;
Michael Chanb6016b72005-05-26 13:03:09 -07004914
4915 /* Make sure the interrupt is not active. */
Michael Chane503e062012-12-06 10:33:08 +00004916 BNX2_WR(bp, BNX2_PCICFG_INT_ACK_CMD, BNX2_PCICFG_INT_ACK_CMD_MASK_INT);
Michael Chanb6016b72005-05-26 13:03:09 -07004917
4918 val = BNX2_DMA_CONFIG_DATA_BYTE_SWAP |
4919 BNX2_DMA_CONFIG_DATA_WORD_SWAP |
4920#ifdef __BIG_ENDIAN
Jeff Garzik6aa20a22006-09-13 13:24:59 -04004921 BNX2_DMA_CONFIG_CNTL_BYTE_SWAP |
Michael Chanb6016b72005-05-26 13:03:09 -07004922#endif
Jeff Garzik6aa20a22006-09-13 13:24:59 -04004923 BNX2_DMA_CONFIG_CNTL_WORD_SWAP |
Michael Chanb6016b72005-05-26 13:03:09 -07004924 DMA_READ_CHANS << 12 |
4925 DMA_WRITE_CHANS << 16;
4926
4927 val |= (0x2 << 20) | (1 << 11);
4928
David S. Millerf86e82f2008-01-21 17:15:40 -08004929 if ((bp->flags & BNX2_FLAG_PCIX) && (bp->bus_speed_mhz == 133))
Michael Chanb6016b72005-05-26 13:03:09 -07004930 val |= (1 << 23);
4931
Michael Chan4ce45e02012-12-06 10:33:10 +00004932 if ((BNX2_CHIP(bp) == BNX2_CHIP_5706) &&
4933 (BNX2_CHIP_ID(bp) != BNX2_CHIP_ID_5706_A0) &&
4934 !(bp->flags & BNX2_FLAG_PCIX))
Michael Chanb6016b72005-05-26 13:03:09 -07004935 val |= BNX2_DMA_CONFIG_CNTL_PING_PONG_DMA;
4936
Michael Chane503e062012-12-06 10:33:08 +00004937 BNX2_WR(bp, BNX2_DMA_CONFIG, val);
Michael Chanb6016b72005-05-26 13:03:09 -07004938
Michael Chan4ce45e02012-12-06 10:33:10 +00004939 if (BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5706_A0) {
Michael Chane503e062012-12-06 10:33:08 +00004940 val = BNX2_RD(bp, BNX2_TDMA_CONFIG);
Michael Chanb6016b72005-05-26 13:03:09 -07004941 val |= BNX2_TDMA_CONFIG_ONE_DMA;
Michael Chane503e062012-12-06 10:33:08 +00004942 BNX2_WR(bp, BNX2_TDMA_CONFIG, val);
Michael Chanb6016b72005-05-26 13:03:09 -07004943 }
4944
David S. Millerf86e82f2008-01-21 17:15:40 -08004945 if (bp->flags & BNX2_FLAG_PCIX) {
Michael Chanb6016b72005-05-26 13:03:09 -07004946 u16 val16;
4947
4948 pci_read_config_word(bp->pdev, bp->pcix_cap + PCI_X_CMD,
4949 &val16);
4950 pci_write_config_word(bp->pdev, bp->pcix_cap + PCI_X_CMD,
4951 val16 & ~PCI_X_CMD_ERO);
4952 }
4953
Michael Chane503e062012-12-06 10:33:08 +00004954 BNX2_WR(bp, BNX2_MISC_ENABLE_SET_BITS,
4955 BNX2_MISC_ENABLE_SET_BITS_HOST_COALESCE_ENABLE |
4956 BNX2_MISC_ENABLE_STATUS_BITS_RX_V2P_ENABLE |
4957 BNX2_MISC_ENABLE_STATUS_BITS_CONTEXT_ENABLE);
Michael Chanb6016b72005-05-26 13:03:09 -07004958
4959 /* Initialize context mapping and zero out the quick contexts. The
4960 * context block must have already been enabled. */
Michael Chan4ce45e02012-12-06 10:33:10 +00004961 if (BNX2_CHIP(bp) == BNX2_CHIP_5709) {
Michael Chan641bdcd2007-06-04 21:22:24 -07004962 rc = bnx2_init_5709_context(bp);
4963 if (rc)
4964 return rc;
4965 } else
Michael Chan59b47d82006-11-19 14:10:45 -08004966 bnx2_init_context(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07004967
Michael Chanfba9fe92006-06-12 22:21:25 -07004968 if ((rc = bnx2_init_cpus(bp)) != 0)
4969 return rc;
4970
Michael Chanb6016b72005-05-26 13:03:09 -07004971 bnx2_init_nvram(bp);
4972
Benjamin Li5fcaed02008-07-14 22:39:52 -07004973 bnx2_set_mac_addr(bp, bp->dev->dev_addr, 0);
Michael Chanb6016b72005-05-26 13:03:09 -07004974
Michael Chane503e062012-12-06 10:33:08 +00004975 val = BNX2_RD(bp, BNX2_MQ_CONFIG);
Michael Chanb6016b72005-05-26 13:03:09 -07004976 val &= ~BNX2_MQ_CONFIG_KNL_BYP_BLK_SIZE;
4977 val |= BNX2_MQ_CONFIG_KNL_BYP_BLK_SIZE_256;
Michael Chan4ce45e02012-12-06 10:33:10 +00004978 if (BNX2_CHIP(bp) == BNX2_CHIP_5709) {
Michael Chan4edd4732009-06-08 18:14:42 -07004979 val |= BNX2_MQ_CONFIG_BIN_MQ_MODE;
Michael Chan4ce45e02012-12-06 10:33:10 +00004980 if (BNX2_CHIP_REV(bp) == BNX2_CHIP_REV_Ax)
Michael Chan4edd4732009-06-08 18:14:42 -07004981 val |= BNX2_MQ_CONFIG_HALT_DIS;
4982 }
Michael Chan68c9f752007-04-24 15:35:53 -07004983
Michael Chane503e062012-12-06 10:33:08 +00004984 BNX2_WR(bp, BNX2_MQ_CONFIG, val);
Michael Chanb6016b72005-05-26 13:03:09 -07004985
4986 val = 0x10000 + (MAX_CID_CNT * MB_KERNEL_CTX_SIZE);
Michael Chane503e062012-12-06 10:33:08 +00004987 BNX2_WR(bp, BNX2_MQ_KNL_BYP_WIND_START, val);
4988 BNX2_WR(bp, BNX2_MQ_KNL_WIND_END, val);
Michael Chanb6016b72005-05-26 13:03:09 -07004989
Michael Chan2bc40782012-12-06 10:33:09 +00004990 val = (BNX2_PAGE_BITS - 8) << 24;
Michael Chane503e062012-12-06 10:33:08 +00004991 BNX2_WR(bp, BNX2_RV2P_CONFIG, val);
Michael Chanb6016b72005-05-26 13:03:09 -07004992
4993 /* Configure page size. */
Michael Chane503e062012-12-06 10:33:08 +00004994 val = BNX2_RD(bp, BNX2_TBDR_CONFIG);
Michael Chanb6016b72005-05-26 13:03:09 -07004995 val &= ~BNX2_TBDR_CONFIG_PAGE_SIZE;
Michael Chan2bc40782012-12-06 10:33:09 +00004996 val |= (BNX2_PAGE_BITS - 8) << 24 | 0x40;
Michael Chane503e062012-12-06 10:33:08 +00004997 BNX2_WR(bp, BNX2_TBDR_CONFIG, val);
Michael Chanb6016b72005-05-26 13:03:09 -07004998
4999 val = bp->mac_addr[0] +
5000 (bp->mac_addr[1] << 8) +
5001 (bp->mac_addr[2] << 16) +
5002 bp->mac_addr[3] +
5003 (bp->mac_addr[4] << 8) +
5004 (bp->mac_addr[5] << 16);
Michael Chane503e062012-12-06 10:33:08 +00005005 BNX2_WR(bp, BNX2_EMAC_BACKOFF_SEED, val);
Michael Chanb6016b72005-05-26 13:03:09 -07005006
5007 /* Program the MTU. Also include 4 bytes for CRC32. */
Michael Chand8026d92008-11-12 16:02:20 -08005008 mtu = bp->dev->mtu;
5009 val = mtu + ETH_HLEN + ETH_FCS_LEN;
Michael Chanb6016b72005-05-26 13:03:09 -07005010 if (val > (MAX_ETHERNET_PACKET_SIZE + 4))
5011 val |= BNX2_EMAC_RX_MTU_SIZE_JUMBO_ENA;
Michael Chane503e062012-12-06 10:33:08 +00005012 BNX2_WR(bp, BNX2_EMAC_RX_MTU_SIZE, val);
Michael Chanb6016b72005-05-26 13:03:09 -07005013
Michael Chand8026d92008-11-12 16:02:20 -08005014 if (mtu < 1500)
5015 mtu = 1500;
5016
5017 bnx2_reg_wr_ind(bp, BNX2_RBUF_CONFIG, BNX2_RBUF_CONFIG_VAL(mtu));
5018 bnx2_reg_wr_ind(bp, BNX2_RBUF_CONFIG2, BNX2_RBUF_CONFIG2_VAL(mtu));
5019 bnx2_reg_wr_ind(bp, BNX2_RBUF_CONFIG3, BNX2_RBUF_CONFIG3_VAL(mtu));
5020
Michael Chan155d5562009-08-21 16:20:43 +00005021 memset(bp->bnx2_napi[0].status_blk.msi, 0, bp->status_stats_size);
Michael Chanb4b36042007-12-20 19:59:30 -08005022 for (i = 0; i < BNX2_MAX_MSIX_VEC; i++)
5023 bp->bnx2_napi[i].last_status_idx = 0;
5024
Michael Chanefba0182008-12-03 00:36:15 -08005025 bp->idle_chk_status_idx = 0xffff;
5026
Michael Chanb6016b72005-05-26 13:03:09 -07005027 /* Set up how to generate a link change interrupt. */
Michael Chane503e062012-12-06 10:33:08 +00005028 BNX2_WR(bp, BNX2_EMAC_ATTENTION_ENA, BNX2_EMAC_ATTENTION_ENA_LINK);
Michael Chanb6016b72005-05-26 13:03:09 -07005029
Michael Chane503e062012-12-06 10:33:08 +00005030 BNX2_WR(bp, BNX2_HC_STATUS_ADDR_L,
5031 (u64) bp->status_blk_mapping & 0xffffffff);
5032 BNX2_WR(bp, BNX2_HC_STATUS_ADDR_H, (u64) bp->status_blk_mapping >> 32);
Michael Chanb6016b72005-05-26 13:03:09 -07005033
Michael Chane503e062012-12-06 10:33:08 +00005034 BNX2_WR(bp, BNX2_HC_STATISTICS_ADDR_L,
5035 (u64) bp->stats_blk_mapping & 0xffffffff);
5036 BNX2_WR(bp, BNX2_HC_STATISTICS_ADDR_H,
5037 (u64) bp->stats_blk_mapping >> 32);
Michael Chanb6016b72005-05-26 13:03:09 -07005038
Michael Chane503e062012-12-06 10:33:08 +00005039 BNX2_WR(bp, BNX2_HC_TX_QUICK_CONS_TRIP,
5040 (bp->tx_quick_cons_trip_int << 16) | bp->tx_quick_cons_trip);
Michael Chanb6016b72005-05-26 13:03:09 -07005041
Michael Chane503e062012-12-06 10:33:08 +00005042 BNX2_WR(bp, BNX2_HC_RX_QUICK_CONS_TRIP,
5043 (bp->rx_quick_cons_trip_int << 16) | bp->rx_quick_cons_trip);
Michael Chanb6016b72005-05-26 13:03:09 -07005044
Michael Chane503e062012-12-06 10:33:08 +00005045 BNX2_WR(bp, BNX2_HC_COMP_PROD_TRIP,
5046 (bp->comp_prod_trip_int << 16) | bp->comp_prod_trip);
Michael Chanb6016b72005-05-26 13:03:09 -07005047
Michael Chane503e062012-12-06 10:33:08 +00005048 BNX2_WR(bp, BNX2_HC_TX_TICKS, (bp->tx_ticks_int << 16) | bp->tx_ticks);
Michael Chanb6016b72005-05-26 13:03:09 -07005049
Michael Chane503e062012-12-06 10:33:08 +00005050 BNX2_WR(bp, BNX2_HC_RX_TICKS, (bp->rx_ticks_int << 16) | bp->rx_ticks);
Michael Chanb6016b72005-05-26 13:03:09 -07005051
Michael Chane503e062012-12-06 10:33:08 +00005052 BNX2_WR(bp, BNX2_HC_COM_TICKS,
5053 (bp->com_ticks_int << 16) | bp->com_ticks);
Michael Chanb6016b72005-05-26 13:03:09 -07005054
Michael Chane503e062012-12-06 10:33:08 +00005055 BNX2_WR(bp, BNX2_HC_CMD_TICKS,
5056 (bp->cmd_ticks_int << 16) | bp->cmd_ticks);
Michael Chanb6016b72005-05-26 13:03:09 -07005057
Michael Chan61d9e3f2009-08-21 16:20:46 +00005058 if (bp->flags & BNX2_FLAG_BROKEN_STATS)
Michael Chane503e062012-12-06 10:33:08 +00005059 BNX2_WR(bp, BNX2_HC_STATS_TICKS, 0);
Michael Chan02537b062007-06-04 21:24:07 -07005060 else
Michael Chane503e062012-12-06 10:33:08 +00005061 BNX2_WR(bp, BNX2_HC_STATS_TICKS, bp->stats_ticks);
5062 BNX2_WR(bp, BNX2_HC_STAT_COLLECT_TICKS, 0xbb8); /* 3ms */
Michael Chanb6016b72005-05-26 13:03:09 -07005063
Michael Chan4ce45e02012-12-06 10:33:10 +00005064 if (BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5706_A1)
Michael Chan8e6a72c2007-05-03 13:24:48 -07005065 val = BNX2_HC_CONFIG_COLLECT_STATS;
Michael Chanb6016b72005-05-26 13:03:09 -07005066 else {
Michael Chan8e6a72c2007-05-03 13:24:48 -07005067 val = BNX2_HC_CONFIG_RX_TMR_MODE | BNX2_HC_CONFIG_TX_TMR_MODE |
5068 BNX2_HC_CONFIG_COLLECT_STATS;
Michael Chanb6016b72005-05-26 13:03:09 -07005069 }
5070
Michael Chanefde73a2010-02-15 19:42:07 +00005071 if (bp->flags & BNX2_FLAG_USING_MSIX) {
Michael Chane503e062012-12-06 10:33:08 +00005072 BNX2_WR(bp, BNX2_HC_MSIX_BIT_VECTOR,
5073 BNX2_HC_MSIX_BIT_VECTOR_VAL);
Michael Chanc76c0472007-12-20 20:01:19 -08005074
Michael Chan5e9ad9e2008-06-19 16:43:17 -07005075 val |= BNX2_HC_CONFIG_SB_ADDR_INC_128B;
5076 }
5077
5078 if (bp->flags & BNX2_FLAG_ONE_SHOT_MSI)
Michael Chancf7474a2009-08-21 16:20:48 +00005079 val |= BNX2_HC_CONFIG_ONE_SHOT | BNX2_HC_CONFIG_USE_INT_PARAM;
Michael Chan5e9ad9e2008-06-19 16:43:17 -07005080
Michael Chane503e062012-12-06 10:33:08 +00005081 BNX2_WR(bp, BNX2_HC_CONFIG, val);
Michael Chan5e9ad9e2008-06-19 16:43:17 -07005082
Michael Chan22fa1592010-10-11 16:12:00 -07005083 if (bp->rx_ticks < 25)
5084 bnx2_reg_wr_ind(bp, BNX2_FW_RX_LOW_LATENCY, 1);
5085 else
5086 bnx2_reg_wr_ind(bp, BNX2_FW_RX_LOW_LATENCY, 0);
5087
Michael Chan5e9ad9e2008-06-19 16:43:17 -07005088 for (i = 1; i < bp->irq_nvecs; i++) {
5089 u32 base = ((i - 1) * BNX2_HC_SB_CONFIG_SIZE) +
5090 BNX2_HC_SB_CONFIG_1;
5091
Michael Chane503e062012-12-06 10:33:08 +00005092 BNX2_WR(bp, base,
Michael Chanc76c0472007-12-20 20:01:19 -08005093 BNX2_HC_SB_CONFIG_1_TX_TMR_MODE |
Michael Chan5e9ad9e2008-06-19 16:43:17 -07005094 BNX2_HC_SB_CONFIG_1_RX_TMR_MODE |
Michael Chanc76c0472007-12-20 20:01:19 -08005095 BNX2_HC_SB_CONFIG_1_ONE_SHOT);
5096
Michael Chane503e062012-12-06 10:33:08 +00005097 BNX2_WR(bp, base + BNX2_HC_TX_QUICK_CONS_TRIP_OFF,
Michael Chanc76c0472007-12-20 20:01:19 -08005098 (bp->tx_quick_cons_trip_int << 16) |
5099 bp->tx_quick_cons_trip);
5100
Michael Chane503e062012-12-06 10:33:08 +00005101 BNX2_WR(bp, base + BNX2_HC_TX_TICKS_OFF,
Michael Chanc76c0472007-12-20 20:01:19 -08005102 (bp->tx_ticks_int << 16) | bp->tx_ticks);
5103
Michael Chane503e062012-12-06 10:33:08 +00005104 BNX2_WR(bp, base + BNX2_HC_RX_QUICK_CONS_TRIP_OFF,
5105 (bp->rx_quick_cons_trip_int << 16) |
Michael Chan5e9ad9e2008-06-19 16:43:17 -07005106 bp->rx_quick_cons_trip);
5107
Michael Chane503e062012-12-06 10:33:08 +00005108 BNX2_WR(bp, base + BNX2_HC_RX_TICKS_OFF,
Michael Chan5e9ad9e2008-06-19 16:43:17 -07005109 (bp->rx_ticks_int << 16) | bp->rx_ticks);
Michael Chanc76c0472007-12-20 20:01:19 -08005110 }
5111
Michael Chanb6016b72005-05-26 13:03:09 -07005112 /* Clear internal stats counters. */
Michael Chane503e062012-12-06 10:33:08 +00005113 BNX2_WR(bp, BNX2_HC_COMMAND, BNX2_HC_COMMAND_CLR_STAT_NOW);
Michael Chanb6016b72005-05-26 13:03:09 -07005114
Michael Chane503e062012-12-06 10:33:08 +00005115 BNX2_WR(bp, BNX2_HC_ATTN_BITS_ENABLE, STATUS_ATTN_EVENTS);
Michael Chanb6016b72005-05-26 13:03:09 -07005116
5117 /* Initialize the receive filter. */
5118 bnx2_set_rx_mode(bp->dev);
5119
Michael Chan4ce45e02012-12-06 10:33:10 +00005120 if (BNX2_CHIP(bp) == BNX2_CHIP_5709) {
Michael Chane503e062012-12-06 10:33:08 +00005121 val = BNX2_RD(bp, BNX2_MISC_NEW_CORE_CTL);
Michael Chan0aa38df2007-06-04 21:23:06 -07005122 val |= BNX2_MISC_NEW_CORE_CTL_DMA_ENABLE;
Michael Chane503e062012-12-06 10:33:08 +00005123 BNX2_WR(bp, BNX2_MISC_NEW_CORE_CTL, val);
Michael Chan0aa38df2007-06-04 21:23:06 -07005124 }
Michael Chanb090ae22006-01-23 16:07:10 -08005125 rc = bnx2_fw_sync(bp, BNX2_DRV_MSG_DATA_WAIT2 | BNX2_DRV_MSG_CODE_RESET,
Michael Chana2f13892008-07-14 22:38:23 -07005126 1, 0);
Michael Chanb6016b72005-05-26 13:03:09 -07005127
Michael Chane503e062012-12-06 10:33:08 +00005128 BNX2_WR(bp, BNX2_MISC_ENABLE_SET_BITS, BNX2_MISC_ENABLE_DEFAULT);
5129 BNX2_RD(bp, BNX2_MISC_ENABLE_SET_BITS);
Michael Chanb6016b72005-05-26 13:03:09 -07005130
5131 udelay(20);
5132
Michael Chane503e062012-12-06 10:33:08 +00005133 bp->hc_cmd = BNX2_RD(bp, BNX2_HC_COMMAND);
Michael Chanbf5295b2006-03-23 01:11:56 -08005134
Michael Chanb090ae22006-01-23 16:07:10 -08005135 return rc;
Michael Chanb6016b72005-05-26 13:03:09 -07005136}
5137
Michael Chan59b47d82006-11-19 14:10:45 -08005138static void
Michael Chanc76c0472007-12-20 20:01:19 -08005139bnx2_clear_ring_states(struct bnx2 *bp)
5140{
5141 struct bnx2_napi *bnapi;
Michael Chan35e90102008-06-19 16:37:42 -07005142 struct bnx2_tx_ring_info *txr;
Michael Chanbb4f98a2008-06-19 16:38:19 -07005143 struct bnx2_rx_ring_info *rxr;
Michael Chanc76c0472007-12-20 20:01:19 -08005144 int i;
5145
5146 for (i = 0; i < BNX2_MAX_MSIX_VEC; i++) {
5147 bnapi = &bp->bnx2_napi[i];
Michael Chan35e90102008-06-19 16:37:42 -07005148 txr = &bnapi->tx_ring;
Michael Chanbb4f98a2008-06-19 16:38:19 -07005149 rxr = &bnapi->rx_ring;
Michael Chanc76c0472007-12-20 20:01:19 -08005150
Michael Chan35e90102008-06-19 16:37:42 -07005151 txr->tx_cons = 0;
5152 txr->hw_tx_cons = 0;
Michael Chanbb4f98a2008-06-19 16:38:19 -07005153 rxr->rx_prod_bseq = 0;
5154 rxr->rx_prod = 0;
5155 rxr->rx_cons = 0;
5156 rxr->rx_pg_prod = 0;
5157 rxr->rx_pg_cons = 0;
Michael Chanc76c0472007-12-20 20:01:19 -08005158 }
5159}
5160
5161static void
Michael Chan35e90102008-06-19 16:37:42 -07005162bnx2_init_tx_context(struct bnx2 *bp, u32 cid, struct bnx2_tx_ring_info *txr)
Michael Chan59b47d82006-11-19 14:10:45 -08005163{
5164 u32 val, offset0, offset1, offset2, offset3;
Michael Chan62a83132008-01-29 21:35:40 -08005165 u32 cid_addr = GET_CID_ADDR(cid);
Michael Chan59b47d82006-11-19 14:10:45 -08005166
Michael Chan4ce45e02012-12-06 10:33:10 +00005167 if (BNX2_CHIP(bp) == BNX2_CHIP_5709) {
Michael Chan59b47d82006-11-19 14:10:45 -08005168 offset0 = BNX2_L2CTX_TYPE_XI;
5169 offset1 = BNX2_L2CTX_CMD_TYPE_XI;
5170 offset2 = BNX2_L2CTX_TBDR_BHADDR_HI_XI;
5171 offset3 = BNX2_L2CTX_TBDR_BHADDR_LO_XI;
5172 } else {
5173 offset0 = BNX2_L2CTX_TYPE;
5174 offset1 = BNX2_L2CTX_CMD_TYPE;
5175 offset2 = BNX2_L2CTX_TBDR_BHADDR_HI;
5176 offset3 = BNX2_L2CTX_TBDR_BHADDR_LO;
5177 }
5178 val = BNX2_L2CTX_TYPE_TYPE_L2 | BNX2_L2CTX_TYPE_SIZE_L2;
Michael Chan62a83132008-01-29 21:35:40 -08005179 bnx2_ctx_wr(bp, cid_addr, offset0, val);
Michael Chan59b47d82006-11-19 14:10:45 -08005180
5181 val = BNX2_L2CTX_CMD_TYPE_TYPE_L2 | (8 << 16);
Michael Chan62a83132008-01-29 21:35:40 -08005182 bnx2_ctx_wr(bp, cid_addr, offset1, val);
Michael Chan59b47d82006-11-19 14:10:45 -08005183
Michael Chan35e90102008-06-19 16:37:42 -07005184 val = (u64) txr->tx_desc_mapping >> 32;
Michael Chan62a83132008-01-29 21:35:40 -08005185 bnx2_ctx_wr(bp, cid_addr, offset2, val);
Michael Chan59b47d82006-11-19 14:10:45 -08005186
Michael Chan35e90102008-06-19 16:37:42 -07005187 val = (u64) txr->tx_desc_mapping & 0xffffffff;
Michael Chan62a83132008-01-29 21:35:40 -08005188 bnx2_ctx_wr(bp, cid_addr, offset3, val);
Michael Chan59b47d82006-11-19 14:10:45 -08005189}
Michael Chanb6016b72005-05-26 13:03:09 -07005190
5191static void
Michael Chan35e90102008-06-19 16:37:42 -07005192bnx2_init_tx_ring(struct bnx2 *bp, int ring_num)
Michael Chanb6016b72005-05-26 13:03:09 -07005193{
Michael Chan2bc40782012-12-06 10:33:09 +00005194 struct bnx2_tx_bd *txbd;
Michael Chanc76c0472007-12-20 20:01:19 -08005195 u32 cid = TX_CID;
5196 struct bnx2_napi *bnapi;
Michael Chan35e90102008-06-19 16:37:42 -07005197 struct bnx2_tx_ring_info *txr;
Michael Chanc76c0472007-12-20 20:01:19 -08005198
Michael Chan35e90102008-06-19 16:37:42 -07005199 bnapi = &bp->bnx2_napi[ring_num];
5200 txr = &bnapi->tx_ring;
5201
5202 if (ring_num == 0)
5203 cid = TX_CID;
5204 else
5205 cid = TX_TSS_CID + ring_num - 1;
Michael Chanb6016b72005-05-26 13:03:09 -07005206
Michael Chan2f8af122006-08-15 01:39:10 -07005207 bp->tx_wake_thresh = bp->tx_ring_size / 2;
5208
Michael Chan2bc40782012-12-06 10:33:09 +00005209 txbd = &txr->tx_desc_ring[BNX2_MAX_TX_DESC_CNT];
Jeff Garzik6aa20a22006-09-13 13:24:59 -04005210
Michael Chan35e90102008-06-19 16:37:42 -07005211 txbd->tx_bd_haddr_hi = (u64) txr->tx_desc_mapping >> 32;
5212 txbd->tx_bd_haddr_lo = (u64) txr->tx_desc_mapping & 0xffffffff;
Michael Chanb6016b72005-05-26 13:03:09 -07005213
Michael Chan35e90102008-06-19 16:37:42 -07005214 txr->tx_prod = 0;
5215 txr->tx_prod_bseq = 0;
Jeff Garzik6aa20a22006-09-13 13:24:59 -04005216
Michael Chan35e90102008-06-19 16:37:42 -07005217 txr->tx_bidx_addr = MB_GET_CID_ADDR(cid) + BNX2_L2CTX_TX_HOST_BIDX;
5218 txr->tx_bseq_addr = MB_GET_CID_ADDR(cid) + BNX2_L2CTX_TX_HOST_BSEQ;
Michael Chanb6016b72005-05-26 13:03:09 -07005219
Michael Chan35e90102008-06-19 16:37:42 -07005220 bnx2_init_tx_context(bp, cid, txr);
Michael Chanb6016b72005-05-26 13:03:09 -07005221}
5222
5223static void
Michael Chan2bc40782012-12-06 10:33:09 +00005224bnx2_init_rxbd_rings(struct bnx2_rx_bd *rx_ring[], dma_addr_t dma[],
5225 u32 buf_size, int num_rings)
Michael Chanb6016b72005-05-26 13:03:09 -07005226{
Michael Chanb6016b72005-05-26 13:03:09 -07005227 int i;
Michael Chan2bc40782012-12-06 10:33:09 +00005228 struct bnx2_rx_bd *rxbd;
Michael Chanb6016b72005-05-26 13:03:09 -07005229
Michael Chan5d5d0012007-12-12 11:17:43 -08005230 for (i = 0; i < num_rings; i++) {
Michael Chan13daffa2006-03-20 17:49:20 -08005231 int j;
Michael Chanb6016b72005-05-26 13:03:09 -07005232
Michael Chan5d5d0012007-12-12 11:17:43 -08005233 rxbd = &rx_ring[i][0];
Michael Chan2bc40782012-12-06 10:33:09 +00005234 for (j = 0; j < BNX2_MAX_RX_DESC_CNT; j++, rxbd++) {
Michael Chan5d5d0012007-12-12 11:17:43 -08005235 rxbd->rx_bd_len = buf_size;
Michael Chan13daffa2006-03-20 17:49:20 -08005236 rxbd->rx_bd_flags = RX_BD_FLAGS_START | RX_BD_FLAGS_END;
5237 }
Michael Chan5d5d0012007-12-12 11:17:43 -08005238 if (i == (num_rings - 1))
Michael Chan13daffa2006-03-20 17:49:20 -08005239 j = 0;
5240 else
5241 j = i + 1;
Michael Chan5d5d0012007-12-12 11:17:43 -08005242 rxbd->rx_bd_haddr_hi = (u64) dma[j] >> 32;
5243 rxbd->rx_bd_haddr_lo = (u64) dma[j] & 0xffffffff;
Michael Chan13daffa2006-03-20 17:49:20 -08005244 }
Michael Chan5d5d0012007-12-12 11:17:43 -08005245}
5246
5247static void
Michael Chanbb4f98a2008-06-19 16:38:19 -07005248bnx2_init_rx_ring(struct bnx2 *bp, int ring_num)
Michael Chan5d5d0012007-12-12 11:17:43 -08005249{
5250 int i;
5251 u16 prod, ring_prod;
Michael Chanbb4f98a2008-06-19 16:38:19 -07005252 u32 cid, rx_cid_addr, val;
5253 struct bnx2_napi *bnapi = &bp->bnx2_napi[ring_num];
5254 struct bnx2_rx_ring_info *rxr = &bnapi->rx_ring;
Michael Chan5d5d0012007-12-12 11:17:43 -08005255
Michael Chanbb4f98a2008-06-19 16:38:19 -07005256 if (ring_num == 0)
5257 cid = RX_CID;
5258 else
5259 cid = RX_RSS_CID + ring_num - 1;
5260
5261 rx_cid_addr = GET_CID_ADDR(cid);
5262
5263 bnx2_init_rxbd_rings(rxr->rx_desc_ring, rxr->rx_desc_mapping,
Michael Chan5d5d0012007-12-12 11:17:43 -08005264 bp->rx_buf_use_size, bp->rx_max_ring);
5265
Michael Chanbb4f98a2008-06-19 16:38:19 -07005266 bnx2_init_rx_context(bp, cid);
Michael Chan83e3fc82008-01-29 21:37:17 -08005267
Michael Chan4ce45e02012-12-06 10:33:10 +00005268 if (BNX2_CHIP(bp) == BNX2_CHIP_5709) {
Michael Chane503e062012-12-06 10:33:08 +00005269 val = BNX2_RD(bp, BNX2_MQ_MAP_L2_5);
5270 BNX2_WR(bp, BNX2_MQ_MAP_L2_5, val | BNX2_MQ_MAP_L2_5_ARM);
Michael Chan83e3fc82008-01-29 21:37:17 -08005271 }
5272
Michael Chan62a83132008-01-29 21:35:40 -08005273 bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_PG_BUF_SIZE, 0);
Michael Chan47bf4242007-12-12 11:19:12 -08005274 if (bp->rx_pg_ring_size) {
Michael Chanbb4f98a2008-06-19 16:38:19 -07005275 bnx2_init_rxbd_rings(rxr->rx_pg_desc_ring,
5276 rxr->rx_pg_desc_mapping,
Michael Chan47bf4242007-12-12 11:19:12 -08005277 PAGE_SIZE, bp->rx_max_pg_ring);
5278 val = (bp->rx_buf_use_size << 16) | PAGE_SIZE;
Michael Chan62a83132008-01-29 21:35:40 -08005279 bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_PG_BUF_SIZE, val);
5280 bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_RBDC_KEY,
Michael Chan5e9ad9e2008-06-19 16:43:17 -07005281 BNX2_L2CTX_RBDC_JUMBO_KEY - ring_num);
Michael Chan47bf4242007-12-12 11:19:12 -08005282
Michael Chanbb4f98a2008-06-19 16:38:19 -07005283 val = (u64) rxr->rx_pg_desc_mapping[0] >> 32;
Michael Chan62a83132008-01-29 21:35:40 -08005284 bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_NX_PG_BDHADDR_HI, val);
Michael Chan47bf4242007-12-12 11:19:12 -08005285
Michael Chanbb4f98a2008-06-19 16:38:19 -07005286 val = (u64) rxr->rx_pg_desc_mapping[0] & 0xffffffff;
Michael Chan62a83132008-01-29 21:35:40 -08005287 bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_NX_PG_BDHADDR_LO, val);
Michael Chan47bf4242007-12-12 11:19:12 -08005288
Michael Chan4ce45e02012-12-06 10:33:10 +00005289 if (BNX2_CHIP(bp) == BNX2_CHIP_5709)
Michael Chane503e062012-12-06 10:33:08 +00005290 BNX2_WR(bp, BNX2_MQ_MAP_L2_3, BNX2_MQ_MAP_L2_3_DEFAULT);
Michael Chan47bf4242007-12-12 11:19:12 -08005291 }
Michael Chanb6016b72005-05-26 13:03:09 -07005292
Michael Chanbb4f98a2008-06-19 16:38:19 -07005293 val = (u64) rxr->rx_desc_mapping[0] >> 32;
Michael Chan62a83132008-01-29 21:35:40 -08005294 bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_NX_BDHADDR_HI, val);
Michael Chanb6016b72005-05-26 13:03:09 -07005295
Michael Chanbb4f98a2008-06-19 16:38:19 -07005296 val = (u64) rxr->rx_desc_mapping[0] & 0xffffffff;
Michael Chan62a83132008-01-29 21:35:40 -08005297 bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_NX_BDHADDR_LO, val);
Michael Chanb6016b72005-05-26 13:03:09 -07005298
Michael Chanbb4f98a2008-06-19 16:38:19 -07005299 ring_prod = prod = rxr->rx_pg_prod;
Michael Chan47bf4242007-12-12 11:19:12 -08005300 for (i = 0; i < bp->rx_pg_ring_size; i++) {
Stanislaw Gruszkaa2df00a2010-07-15 22:55:40 +00005301 if (bnx2_alloc_rx_page(bp, rxr, ring_prod, GFP_KERNEL) < 0) {
Joe Perches3a9c6a42010-02-17 15:01:51 +00005302 netdev_warn(bp->dev, "init'ed rx page ring %d with %d/%d pages only\n",
5303 ring_num, i, bp->rx_pg_ring_size);
Michael Chan47bf4242007-12-12 11:19:12 -08005304 break;
Michael Chanb929e532009-12-03 09:46:33 +00005305 }
Michael Chan2bc40782012-12-06 10:33:09 +00005306 prod = BNX2_NEXT_RX_BD(prod);
5307 ring_prod = BNX2_RX_PG_RING_IDX(prod);
Michael Chan47bf4242007-12-12 11:19:12 -08005308 }
Michael Chanbb4f98a2008-06-19 16:38:19 -07005309 rxr->rx_pg_prod = prod;
Michael Chan47bf4242007-12-12 11:19:12 -08005310
Michael Chanbb4f98a2008-06-19 16:38:19 -07005311 ring_prod = prod = rxr->rx_prod;
Michael Chan236b6392006-03-20 17:49:02 -08005312 for (i = 0; i < bp->rx_ring_size; i++) {
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00005313 if (bnx2_alloc_rx_data(bp, rxr, ring_prod, GFP_KERNEL) < 0) {
Joe Perches3a9c6a42010-02-17 15:01:51 +00005314 netdev_warn(bp->dev, "init'ed rx ring %d with %d/%d skbs only\n",
5315 ring_num, i, bp->rx_ring_size);
Michael Chanb6016b72005-05-26 13:03:09 -07005316 break;
Michael Chanb929e532009-12-03 09:46:33 +00005317 }
Michael Chan2bc40782012-12-06 10:33:09 +00005318 prod = BNX2_NEXT_RX_BD(prod);
5319 ring_prod = BNX2_RX_RING_IDX(prod);
Michael Chanb6016b72005-05-26 13:03:09 -07005320 }
Michael Chanbb4f98a2008-06-19 16:38:19 -07005321 rxr->rx_prod = prod;
Michael Chanb6016b72005-05-26 13:03:09 -07005322
Michael Chanbb4f98a2008-06-19 16:38:19 -07005323 rxr->rx_bidx_addr = MB_GET_CID_ADDR(cid) + BNX2_L2CTX_HOST_BDIDX;
5324 rxr->rx_bseq_addr = MB_GET_CID_ADDR(cid) + BNX2_L2CTX_HOST_BSEQ;
5325 rxr->rx_pg_bidx_addr = MB_GET_CID_ADDR(cid) + BNX2_L2CTX_HOST_PG_BDIDX;
Michael Chanb6016b72005-05-26 13:03:09 -07005326
Michael Chane503e062012-12-06 10:33:08 +00005327 BNX2_WR16(bp, rxr->rx_pg_bidx_addr, rxr->rx_pg_prod);
5328 BNX2_WR16(bp, rxr->rx_bidx_addr, prod);
Michael Chanbb4f98a2008-06-19 16:38:19 -07005329
Michael Chane503e062012-12-06 10:33:08 +00005330 BNX2_WR(bp, rxr->rx_bseq_addr, rxr->rx_prod_bseq);
Michael Chanb6016b72005-05-26 13:03:09 -07005331}
5332
Michael Chan35e90102008-06-19 16:37:42 -07005333static void
5334bnx2_init_all_rings(struct bnx2 *bp)
5335{
5336 int i;
Michael Chan5e9ad9e2008-06-19 16:43:17 -07005337 u32 val;
Michael Chan35e90102008-06-19 16:37:42 -07005338
5339 bnx2_clear_ring_states(bp);
5340
Michael Chane503e062012-12-06 10:33:08 +00005341 BNX2_WR(bp, BNX2_TSCH_TSS_CFG, 0);
Michael Chan35e90102008-06-19 16:37:42 -07005342 for (i = 0; i < bp->num_tx_rings; i++)
5343 bnx2_init_tx_ring(bp, i);
5344
5345 if (bp->num_tx_rings > 1)
Michael Chane503e062012-12-06 10:33:08 +00005346 BNX2_WR(bp, BNX2_TSCH_TSS_CFG, ((bp->num_tx_rings - 1) << 24) |
5347 (TX_TSS_CID << 7));
Michael Chan35e90102008-06-19 16:37:42 -07005348
Michael Chane503e062012-12-06 10:33:08 +00005349 BNX2_WR(bp, BNX2_RLUP_RSS_CONFIG, 0);
Michael Chan5e9ad9e2008-06-19 16:43:17 -07005350 bnx2_reg_wr_ind(bp, BNX2_RXP_SCRATCH_RSS_TBL_SZ, 0);
5351
Michael Chanbb4f98a2008-06-19 16:38:19 -07005352 for (i = 0; i < bp->num_rx_rings; i++)
5353 bnx2_init_rx_ring(bp, i);
Michael Chan5e9ad9e2008-06-19 16:43:17 -07005354
5355 if (bp->num_rx_rings > 1) {
Michael Chan22fa1592010-10-11 16:12:00 -07005356 u32 tbl_32 = 0;
Michael Chan5e9ad9e2008-06-19 16:43:17 -07005357
5358 for (i = 0; i < BNX2_RXP_SCRATCH_RSS_TBL_MAX_ENTRIES; i++) {
Michael Chan22fa1592010-10-11 16:12:00 -07005359 int shift = (i % 8) << 2;
5360
5361 tbl_32 |= (i % (bp->num_rx_rings - 1)) << shift;
5362 if ((i % 8) == 7) {
Michael Chane503e062012-12-06 10:33:08 +00005363 BNX2_WR(bp, BNX2_RLUP_RSS_DATA, tbl_32);
5364 BNX2_WR(bp, BNX2_RLUP_RSS_COMMAND, (i >> 3) |
Michael Chan22fa1592010-10-11 16:12:00 -07005365 BNX2_RLUP_RSS_COMMAND_RSS_WRITE_MASK |
5366 BNX2_RLUP_RSS_COMMAND_WRITE |
5367 BNX2_RLUP_RSS_COMMAND_HASH_MASK);
5368 tbl_32 = 0;
5369 }
Michael Chan5e9ad9e2008-06-19 16:43:17 -07005370 }
5371
5372 val = BNX2_RLUP_RSS_CONFIG_IPV4_RSS_TYPE_ALL_XI |
5373 BNX2_RLUP_RSS_CONFIG_IPV6_RSS_TYPE_ALL_XI;
5374
Michael Chane503e062012-12-06 10:33:08 +00005375 BNX2_WR(bp, BNX2_RLUP_RSS_CONFIG, val);
Michael Chan5e9ad9e2008-06-19 16:43:17 -07005376
5377 }
Michael Chan35e90102008-06-19 16:37:42 -07005378}
5379
Michael Chan5d5d0012007-12-12 11:17:43 -08005380static u32 bnx2_find_max_ring(u32 ring_size, u32 max_size)
Michael Chan13daffa2006-03-20 17:49:20 -08005381{
Michael Chan5d5d0012007-12-12 11:17:43 -08005382 u32 max, num_rings = 1;
Michael Chan13daffa2006-03-20 17:49:20 -08005383
Michael Chan2bc40782012-12-06 10:33:09 +00005384 while (ring_size > BNX2_MAX_RX_DESC_CNT) {
5385 ring_size -= BNX2_MAX_RX_DESC_CNT;
Michael Chan13daffa2006-03-20 17:49:20 -08005386 num_rings++;
5387 }
5388 /* round to next power of 2 */
Michael Chan5d5d0012007-12-12 11:17:43 -08005389 max = max_size;
Michael Chan13daffa2006-03-20 17:49:20 -08005390 while ((max & num_rings) == 0)
5391 max >>= 1;
5392
5393 if (num_rings != max)
5394 max <<= 1;
5395
Michael Chan5d5d0012007-12-12 11:17:43 -08005396 return max;
5397}
5398
5399static void
5400bnx2_set_rx_ring_size(struct bnx2 *bp, u32 size)
5401{
Michael Chan84eaa182007-12-12 11:19:57 -08005402 u32 rx_size, rx_space, jumbo_size;
Michael Chan5d5d0012007-12-12 11:17:43 -08005403
5404 /* 8 for CRC and VLAN */
Benjamin Lid89cb6a2008-05-16 22:18:57 -07005405 rx_size = bp->dev->mtu + ETH_HLEN + BNX2_RX_OFFSET + 8;
Michael Chan5d5d0012007-12-12 11:17:43 -08005406
Michael Chan84eaa182007-12-12 11:19:57 -08005407 rx_space = SKB_DATA_ALIGN(rx_size + BNX2_RX_ALIGN) + NET_SKB_PAD +
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00005408 SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
Michael Chan84eaa182007-12-12 11:19:57 -08005409
Benjamin Li601d3d12008-05-16 22:19:35 -07005410 bp->rx_copy_thresh = BNX2_RX_COPY_THRESH;
Michael Chan47bf4242007-12-12 11:19:12 -08005411 bp->rx_pg_ring_size = 0;
5412 bp->rx_max_pg_ring = 0;
5413 bp->rx_max_pg_ring_idx = 0;
David S. Millerf86e82f2008-01-21 17:15:40 -08005414 if ((rx_space > PAGE_SIZE) && !(bp->flags & BNX2_FLAG_JUMBO_BROKEN)) {
Michael Chan84eaa182007-12-12 11:19:57 -08005415 int pages = PAGE_ALIGN(bp->dev->mtu - 40) >> PAGE_SHIFT;
5416
5417 jumbo_size = size * pages;
Michael Chan2bc40782012-12-06 10:33:09 +00005418 if (jumbo_size > BNX2_MAX_TOTAL_RX_PG_DESC_CNT)
5419 jumbo_size = BNX2_MAX_TOTAL_RX_PG_DESC_CNT;
Michael Chan84eaa182007-12-12 11:19:57 -08005420
5421 bp->rx_pg_ring_size = jumbo_size;
5422 bp->rx_max_pg_ring = bnx2_find_max_ring(jumbo_size,
Michael Chan2bc40782012-12-06 10:33:09 +00005423 BNX2_MAX_RX_PG_RINGS);
5424 bp->rx_max_pg_ring_idx =
5425 (bp->rx_max_pg_ring * BNX2_RX_DESC_CNT) - 1;
Benjamin Li601d3d12008-05-16 22:19:35 -07005426 rx_size = BNX2_RX_COPY_THRESH + BNX2_RX_OFFSET;
Michael Chan84eaa182007-12-12 11:19:57 -08005427 bp->rx_copy_thresh = 0;
5428 }
Michael Chan5d5d0012007-12-12 11:17:43 -08005429
5430 bp->rx_buf_use_size = rx_size;
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00005431 /* hw alignment + build_skb() overhead*/
5432 bp->rx_buf_size = SKB_DATA_ALIGN(bp->rx_buf_use_size + BNX2_RX_ALIGN) +
5433 NET_SKB_PAD + SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
Benjamin Lid89cb6a2008-05-16 22:18:57 -07005434 bp->rx_jumbo_thresh = rx_size - BNX2_RX_OFFSET;
Michael Chan5d5d0012007-12-12 11:17:43 -08005435 bp->rx_ring_size = size;
Michael Chan2bc40782012-12-06 10:33:09 +00005436 bp->rx_max_ring = bnx2_find_max_ring(size, BNX2_MAX_RX_RINGS);
5437 bp->rx_max_ring_idx = (bp->rx_max_ring * BNX2_RX_DESC_CNT) - 1;
Michael Chan13daffa2006-03-20 17:49:20 -08005438}
5439
5440static void
Michael Chanb6016b72005-05-26 13:03:09 -07005441bnx2_free_tx_skbs(struct bnx2 *bp)
5442{
5443 int i;
5444
Michael Chan35e90102008-06-19 16:37:42 -07005445 for (i = 0; i < bp->num_tx_rings; i++) {
5446 struct bnx2_napi *bnapi = &bp->bnx2_napi[i];
5447 struct bnx2_tx_ring_info *txr = &bnapi->tx_ring;
5448 int j;
Michael Chanb6016b72005-05-26 13:03:09 -07005449
Michael Chan35e90102008-06-19 16:37:42 -07005450 if (txr->tx_buf_ring == NULL)
Michael Chanb6016b72005-05-26 13:03:09 -07005451 continue;
Michael Chanb6016b72005-05-26 13:03:09 -07005452
Michael Chan2bc40782012-12-06 10:33:09 +00005453 for (j = 0; j < BNX2_TX_DESC_CNT; ) {
5454 struct bnx2_sw_tx_bd *tx_buf = &txr->tx_buf_ring[j];
Michael Chan35e90102008-06-19 16:37:42 -07005455 struct sk_buff *skb = tx_buf->skb;
Alexander Duycke95524a2009-12-02 16:47:57 +00005456 int k, last;
Michael Chan35e90102008-06-19 16:37:42 -07005457
5458 if (skb == NULL) {
Michael Chan2bc40782012-12-06 10:33:09 +00005459 j = BNX2_NEXT_TX_BD(j);
Michael Chan35e90102008-06-19 16:37:42 -07005460 continue;
5461 }
5462
Stanislaw Gruszka36227e82010-07-15 04:25:50 +00005463 dma_unmap_single(&bp->pdev->dev,
FUJITA Tomonori1a4ccc22010-04-01 16:56:57 +00005464 dma_unmap_addr(tx_buf, mapping),
Alexander Duycke95524a2009-12-02 16:47:57 +00005465 skb_headlen(skb),
5466 PCI_DMA_TODEVICE);
Michael Chanb6016b72005-05-26 13:03:09 -07005467
Michael Chan35e90102008-06-19 16:37:42 -07005468 tx_buf->skb = NULL;
Michael Chanb6016b72005-05-26 13:03:09 -07005469
Alexander Duycke95524a2009-12-02 16:47:57 +00005470 last = tx_buf->nr_frags;
Michael Chan2bc40782012-12-06 10:33:09 +00005471 j = BNX2_NEXT_TX_BD(j);
5472 for (k = 0; k < last; k++, j = BNX2_NEXT_TX_BD(j)) {
5473 tx_buf = &txr->tx_buf_ring[BNX2_TX_RING_IDX(j)];
Stanislaw Gruszka36227e82010-07-15 04:25:50 +00005474 dma_unmap_page(&bp->pdev->dev,
FUJITA Tomonori1a4ccc22010-04-01 16:56:57 +00005475 dma_unmap_addr(tx_buf, mapping),
Eric Dumazet9e903e02011-10-18 21:00:24 +00005476 skb_frag_size(&skb_shinfo(skb)->frags[k]),
Alexander Duycke95524a2009-12-02 16:47:57 +00005477 PCI_DMA_TODEVICE);
5478 }
Michael Chan35e90102008-06-19 16:37:42 -07005479 dev_kfree_skb(skb);
Michael Chanb6016b72005-05-26 13:03:09 -07005480 }
Eric Dumazete9831902011-11-29 11:53:05 +00005481 netdev_tx_reset_queue(netdev_get_tx_queue(bp->dev, i));
Michael Chanb6016b72005-05-26 13:03:09 -07005482 }
Michael Chanb6016b72005-05-26 13:03:09 -07005483}
5484
5485static void
5486bnx2_free_rx_skbs(struct bnx2 *bp)
5487{
5488 int i;
5489
Michael Chanbb4f98a2008-06-19 16:38:19 -07005490 for (i = 0; i < bp->num_rx_rings; i++) {
5491 struct bnx2_napi *bnapi = &bp->bnx2_napi[i];
5492 struct bnx2_rx_ring_info *rxr = &bnapi->rx_ring;
5493 int j;
Michael Chanb6016b72005-05-26 13:03:09 -07005494
Michael Chanbb4f98a2008-06-19 16:38:19 -07005495 if (rxr->rx_buf_ring == NULL)
5496 return;
Michael Chanb6016b72005-05-26 13:03:09 -07005497
Michael Chanbb4f98a2008-06-19 16:38:19 -07005498 for (j = 0; j < bp->rx_max_ring_idx; j++) {
Michael Chan2bc40782012-12-06 10:33:09 +00005499 struct bnx2_sw_bd *rx_buf = &rxr->rx_buf_ring[j];
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00005500 u8 *data = rx_buf->data;
Michael Chanb6016b72005-05-26 13:03:09 -07005501
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00005502 if (data == NULL)
Michael Chanbb4f98a2008-06-19 16:38:19 -07005503 continue;
Michael Chanb6016b72005-05-26 13:03:09 -07005504
Stanislaw Gruszka36227e82010-07-15 04:25:50 +00005505 dma_unmap_single(&bp->pdev->dev,
FUJITA Tomonori1a4ccc22010-04-01 16:56:57 +00005506 dma_unmap_addr(rx_buf, mapping),
Michael Chanbb4f98a2008-06-19 16:38:19 -07005507 bp->rx_buf_use_size,
5508 PCI_DMA_FROMDEVICE);
Michael Chanb6016b72005-05-26 13:03:09 -07005509
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00005510 rx_buf->data = NULL;
Michael Chanbb4f98a2008-06-19 16:38:19 -07005511
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00005512 kfree(data);
Michael Chanbb4f98a2008-06-19 16:38:19 -07005513 }
5514 for (j = 0; j < bp->rx_max_pg_ring_idx; j++)
5515 bnx2_free_rx_page(bp, rxr, j);
Michael Chanb6016b72005-05-26 13:03:09 -07005516 }
5517}
5518
5519static void
5520bnx2_free_skbs(struct bnx2 *bp)
5521{
5522 bnx2_free_tx_skbs(bp);
5523 bnx2_free_rx_skbs(bp);
5524}
5525
5526static int
5527bnx2_reset_nic(struct bnx2 *bp, u32 reset_code)
5528{
5529 int rc;
5530
5531 rc = bnx2_reset_chip(bp, reset_code);
5532 bnx2_free_skbs(bp);
5533 if (rc)
5534 return rc;
5535
Michael Chanfba9fe92006-06-12 22:21:25 -07005536 if ((rc = bnx2_init_chip(bp)) != 0)
5537 return rc;
5538
Michael Chan35e90102008-06-19 16:37:42 -07005539 bnx2_init_all_rings(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07005540 return 0;
5541}
5542
5543static int
Michael Chan9a120bc2008-05-16 22:17:45 -07005544bnx2_init_nic(struct bnx2 *bp, int reset_phy)
Michael Chanb6016b72005-05-26 13:03:09 -07005545{
5546 int rc;
5547
5548 if ((rc = bnx2_reset_nic(bp, BNX2_DRV_MSG_CODE_RESET)) != 0)
5549 return rc;
5550
Michael Chan80be4432006-11-19 14:07:28 -08005551 spin_lock_bh(&bp->phy_lock);
Michael Chan9a120bc2008-05-16 22:17:45 -07005552 bnx2_init_phy(bp, reset_phy);
Michael Chanb6016b72005-05-26 13:03:09 -07005553 bnx2_set_link(bp);
Michael Chan543a8272008-05-02 16:56:44 -07005554 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
5555 bnx2_remote_phy_event(bp);
Michael Chan0d8a6572007-07-07 22:49:43 -07005556 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07005557 return 0;
5558}
5559
5560static int
Michael Chan74bf4ba2008-10-09 12:21:08 -07005561bnx2_shutdown_chip(struct bnx2 *bp)
5562{
5563 u32 reset_code;
5564
5565 if (bp->flags & BNX2_FLAG_NO_WOL)
5566 reset_code = BNX2_DRV_MSG_CODE_UNLOAD_LNK_DN;
5567 else if (bp->wol)
5568 reset_code = BNX2_DRV_MSG_CODE_SUSPEND_WOL;
5569 else
5570 reset_code = BNX2_DRV_MSG_CODE_SUSPEND_NO_WOL;
5571
5572 return bnx2_reset_chip(bp, reset_code);
5573}
5574
5575static int
Michael Chanb6016b72005-05-26 13:03:09 -07005576bnx2_test_registers(struct bnx2 *bp)
5577{
5578 int ret;
Michael Chan5bae30c2007-05-03 13:18:46 -07005579 int i, is_5709;
Arjan van de Venf71e1302006-03-03 21:33:57 -05005580 static const struct {
Michael Chanb6016b72005-05-26 13:03:09 -07005581 u16 offset;
5582 u16 flags;
Michael Chan5bae30c2007-05-03 13:18:46 -07005583#define BNX2_FL_NOT_5709 1
Michael Chanb6016b72005-05-26 13:03:09 -07005584 u32 rw_mask;
5585 u32 ro_mask;
5586 } reg_tbl[] = {
5587 { 0x006c, 0, 0x00000000, 0x0000003f },
5588 { 0x0090, 0, 0xffffffff, 0x00000000 },
5589 { 0x0094, 0, 0x00000000, 0x00000000 },
5590
Michael Chan5bae30c2007-05-03 13:18:46 -07005591 { 0x0404, BNX2_FL_NOT_5709, 0x00003f00, 0x00000000 },
5592 { 0x0418, BNX2_FL_NOT_5709, 0x00000000, 0xffffffff },
5593 { 0x041c, BNX2_FL_NOT_5709, 0x00000000, 0xffffffff },
5594 { 0x0420, BNX2_FL_NOT_5709, 0x00000000, 0x80ffffff },
5595 { 0x0424, BNX2_FL_NOT_5709, 0x00000000, 0x00000000 },
5596 { 0x0428, BNX2_FL_NOT_5709, 0x00000000, 0x00000001 },
5597 { 0x0450, BNX2_FL_NOT_5709, 0x00000000, 0x0000ffff },
5598 { 0x0454, BNX2_FL_NOT_5709, 0x00000000, 0xffffffff },
5599 { 0x0458, BNX2_FL_NOT_5709, 0x00000000, 0xffffffff },
Michael Chanb6016b72005-05-26 13:03:09 -07005600
Michael Chan5bae30c2007-05-03 13:18:46 -07005601 { 0x0808, BNX2_FL_NOT_5709, 0x00000000, 0xffffffff },
5602 { 0x0854, BNX2_FL_NOT_5709, 0x00000000, 0xffffffff },
5603 { 0x0868, BNX2_FL_NOT_5709, 0x00000000, 0x77777777 },
5604 { 0x086c, BNX2_FL_NOT_5709, 0x00000000, 0x77777777 },
5605 { 0x0870, BNX2_FL_NOT_5709, 0x00000000, 0x77777777 },
5606 { 0x0874, BNX2_FL_NOT_5709, 0x00000000, 0x77777777 },
Michael Chanb6016b72005-05-26 13:03:09 -07005607
Michael Chan5bae30c2007-05-03 13:18:46 -07005608 { 0x0c00, BNX2_FL_NOT_5709, 0x00000000, 0x00000001 },
5609 { 0x0c04, BNX2_FL_NOT_5709, 0x00000000, 0x03ff0001 },
5610 { 0x0c08, BNX2_FL_NOT_5709, 0x0f0ff073, 0x00000000 },
Michael Chanb6016b72005-05-26 13:03:09 -07005611
5612 { 0x1000, 0, 0x00000000, 0x00000001 },
Michael Chan15b169c2008-05-02 16:57:08 -07005613 { 0x1004, BNX2_FL_NOT_5709, 0x00000000, 0x000f0001 },
Michael Chanb6016b72005-05-26 13:03:09 -07005614
5615 { 0x1408, 0, 0x01c00800, 0x00000000 },
5616 { 0x149c, 0, 0x8000ffff, 0x00000000 },
5617 { 0x14a8, 0, 0x00000000, 0x000001ff },
Michael Chan5b0c76a2005-11-04 08:45:49 -08005618 { 0x14ac, 0, 0x0fffffff, 0x10000000 },
Michael Chanb6016b72005-05-26 13:03:09 -07005619 { 0x14b0, 0, 0x00000002, 0x00000001 },
5620 { 0x14b8, 0, 0x00000000, 0x00000000 },
5621 { 0x14c0, 0, 0x00000000, 0x00000009 },
5622 { 0x14c4, 0, 0x00003fff, 0x00000000 },
5623 { 0x14cc, 0, 0x00000000, 0x00000001 },
5624 { 0x14d0, 0, 0xffffffff, 0x00000000 },
Michael Chanb6016b72005-05-26 13:03:09 -07005625
5626 { 0x1800, 0, 0x00000000, 0x00000001 },
5627 { 0x1804, 0, 0x00000000, 0x00000003 },
Michael Chanb6016b72005-05-26 13:03:09 -07005628
5629 { 0x2800, 0, 0x00000000, 0x00000001 },
5630 { 0x2804, 0, 0x00000000, 0x00003f01 },
5631 { 0x2808, 0, 0x0f3f3f03, 0x00000000 },
5632 { 0x2810, 0, 0xffff0000, 0x00000000 },
5633 { 0x2814, 0, 0xffff0000, 0x00000000 },
5634 { 0x2818, 0, 0xffff0000, 0x00000000 },
5635 { 0x281c, 0, 0xffff0000, 0x00000000 },
5636 { 0x2834, 0, 0xffffffff, 0x00000000 },
5637 { 0x2840, 0, 0x00000000, 0xffffffff },
5638 { 0x2844, 0, 0x00000000, 0xffffffff },
5639 { 0x2848, 0, 0xffffffff, 0x00000000 },
5640 { 0x284c, 0, 0xf800f800, 0x07ff07ff },
5641
5642 { 0x2c00, 0, 0x00000000, 0x00000011 },
5643 { 0x2c04, 0, 0x00000000, 0x00030007 },
5644
Michael Chanb6016b72005-05-26 13:03:09 -07005645 { 0x3c00, 0, 0x00000000, 0x00000001 },
5646 { 0x3c04, 0, 0x00000000, 0x00070000 },
5647 { 0x3c08, 0, 0x00007f71, 0x07f00000 },
5648 { 0x3c0c, 0, 0x1f3ffffc, 0x00000000 },
5649 { 0x3c10, 0, 0xffffffff, 0x00000000 },
5650 { 0x3c14, 0, 0x00000000, 0xffffffff },
5651 { 0x3c18, 0, 0x00000000, 0xffffffff },
5652 { 0x3c1c, 0, 0xfffff000, 0x00000000 },
5653 { 0x3c20, 0, 0xffffff00, 0x00000000 },
Michael Chanb6016b72005-05-26 13:03:09 -07005654
5655 { 0x5004, 0, 0x00000000, 0x0000007f },
5656 { 0x5008, 0, 0x0f0007ff, 0x00000000 },
Michael Chanb6016b72005-05-26 13:03:09 -07005657
Michael Chanb6016b72005-05-26 13:03:09 -07005658 { 0x5c00, 0, 0x00000000, 0x00000001 },
5659 { 0x5c04, 0, 0x00000000, 0x0003000f },
5660 { 0x5c08, 0, 0x00000003, 0x00000000 },
5661 { 0x5c0c, 0, 0x0000fff8, 0x00000000 },
5662 { 0x5c10, 0, 0x00000000, 0xffffffff },
5663 { 0x5c80, 0, 0x00000000, 0x0f7113f1 },
5664 { 0x5c84, 0, 0x00000000, 0x0000f333 },
5665 { 0x5c88, 0, 0x00000000, 0x00077373 },
5666 { 0x5c8c, 0, 0x00000000, 0x0007f737 },
5667
5668 { 0x6808, 0, 0x0000ff7f, 0x00000000 },
5669 { 0x680c, 0, 0xffffffff, 0x00000000 },
5670 { 0x6810, 0, 0xffffffff, 0x00000000 },
5671 { 0x6814, 0, 0xffffffff, 0x00000000 },
5672 { 0x6818, 0, 0xffffffff, 0x00000000 },
5673 { 0x681c, 0, 0xffffffff, 0x00000000 },
5674 { 0x6820, 0, 0x00ff00ff, 0x00000000 },
5675 { 0x6824, 0, 0x00ff00ff, 0x00000000 },
5676 { 0x6828, 0, 0x00ff00ff, 0x00000000 },
5677 { 0x682c, 0, 0x03ff03ff, 0x00000000 },
5678 { 0x6830, 0, 0x03ff03ff, 0x00000000 },
5679 { 0x6834, 0, 0x03ff03ff, 0x00000000 },
5680 { 0x6838, 0, 0x03ff03ff, 0x00000000 },
5681 { 0x683c, 0, 0x0000ffff, 0x00000000 },
5682 { 0x6840, 0, 0x00000ff0, 0x00000000 },
5683 { 0x6844, 0, 0x00ffff00, 0x00000000 },
5684 { 0x684c, 0, 0xffffffff, 0x00000000 },
5685 { 0x6850, 0, 0x7f7f7f7f, 0x00000000 },
5686 { 0x6854, 0, 0x7f7f7f7f, 0x00000000 },
5687 { 0x6858, 0, 0x7f7f7f7f, 0x00000000 },
5688 { 0x685c, 0, 0x7f7f7f7f, 0x00000000 },
5689 { 0x6908, 0, 0x00000000, 0x0001ff0f },
5690 { 0x690c, 0, 0x00000000, 0x0ffe00f0 },
5691
5692 { 0xffff, 0, 0x00000000, 0x00000000 },
5693 };
5694
5695 ret = 0;
Michael Chan5bae30c2007-05-03 13:18:46 -07005696 is_5709 = 0;
Michael Chan4ce45e02012-12-06 10:33:10 +00005697 if (BNX2_CHIP(bp) == BNX2_CHIP_5709)
Michael Chan5bae30c2007-05-03 13:18:46 -07005698 is_5709 = 1;
5699
Michael Chanb6016b72005-05-26 13:03:09 -07005700 for (i = 0; reg_tbl[i].offset != 0xffff; i++) {
5701 u32 offset, rw_mask, ro_mask, save_val, val;
Michael Chan5bae30c2007-05-03 13:18:46 -07005702 u16 flags = reg_tbl[i].flags;
5703
5704 if (is_5709 && (flags & BNX2_FL_NOT_5709))
5705 continue;
Michael Chanb6016b72005-05-26 13:03:09 -07005706
5707 offset = (u32) reg_tbl[i].offset;
5708 rw_mask = reg_tbl[i].rw_mask;
5709 ro_mask = reg_tbl[i].ro_mask;
5710
Peter Hagervall14ab9b82005-08-10 14:18:16 -07005711 save_val = readl(bp->regview + offset);
Michael Chanb6016b72005-05-26 13:03:09 -07005712
Peter Hagervall14ab9b82005-08-10 14:18:16 -07005713 writel(0, bp->regview + offset);
Michael Chanb6016b72005-05-26 13:03:09 -07005714
Peter Hagervall14ab9b82005-08-10 14:18:16 -07005715 val = readl(bp->regview + offset);
Michael Chanb6016b72005-05-26 13:03:09 -07005716 if ((val & rw_mask) != 0) {
5717 goto reg_test_err;
5718 }
5719
5720 if ((val & ro_mask) != (save_val & ro_mask)) {
5721 goto reg_test_err;
5722 }
5723
Peter Hagervall14ab9b82005-08-10 14:18:16 -07005724 writel(0xffffffff, bp->regview + offset);
Michael Chanb6016b72005-05-26 13:03:09 -07005725
Peter Hagervall14ab9b82005-08-10 14:18:16 -07005726 val = readl(bp->regview + offset);
Michael Chanb6016b72005-05-26 13:03:09 -07005727 if ((val & rw_mask) != rw_mask) {
5728 goto reg_test_err;
5729 }
5730
5731 if ((val & ro_mask) != (save_val & ro_mask)) {
5732 goto reg_test_err;
5733 }
5734
Peter Hagervall14ab9b82005-08-10 14:18:16 -07005735 writel(save_val, bp->regview + offset);
Michael Chanb6016b72005-05-26 13:03:09 -07005736 continue;
5737
5738reg_test_err:
Peter Hagervall14ab9b82005-08-10 14:18:16 -07005739 writel(save_val, bp->regview + offset);
Michael Chanb6016b72005-05-26 13:03:09 -07005740 ret = -ENODEV;
5741 break;
5742 }
5743 return ret;
5744}
5745
5746static int
5747bnx2_do_mem_test(struct bnx2 *bp, u32 start, u32 size)
5748{
Arjan van de Venf71e1302006-03-03 21:33:57 -05005749 static const u32 test_pattern[] = { 0x00000000, 0xffffffff, 0x55555555,
Michael Chanb6016b72005-05-26 13:03:09 -07005750 0xaaaaaaaa , 0xaa55aa55, 0x55aa55aa };
5751 int i;
5752
5753 for (i = 0; i < sizeof(test_pattern) / 4; i++) {
5754 u32 offset;
5755
5756 for (offset = 0; offset < size; offset += 4) {
5757
Michael Chan2726d6e2008-01-29 21:35:05 -08005758 bnx2_reg_wr_ind(bp, start + offset, test_pattern[i]);
Michael Chanb6016b72005-05-26 13:03:09 -07005759
Michael Chan2726d6e2008-01-29 21:35:05 -08005760 if (bnx2_reg_rd_ind(bp, start + offset) !=
Michael Chanb6016b72005-05-26 13:03:09 -07005761 test_pattern[i]) {
5762 return -ENODEV;
5763 }
5764 }
5765 }
5766 return 0;
5767}
5768
5769static int
5770bnx2_test_memory(struct bnx2 *bp)
5771{
5772 int ret = 0;
5773 int i;
Michael Chan5bae30c2007-05-03 13:18:46 -07005774 static struct mem_entry {
Michael Chanb6016b72005-05-26 13:03:09 -07005775 u32 offset;
5776 u32 len;
Michael Chan5bae30c2007-05-03 13:18:46 -07005777 } mem_tbl_5706[] = {
Michael Chanb6016b72005-05-26 13:03:09 -07005778 { 0x60000, 0x4000 },
Michael Chan5b0c76a2005-11-04 08:45:49 -08005779 { 0xa0000, 0x3000 },
Michael Chanb6016b72005-05-26 13:03:09 -07005780 { 0xe0000, 0x4000 },
5781 { 0x120000, 0x4000 },
5782 { 0x1a0000, 0x4000 },
5783 { 0x160000, 0x4000 },
5784 { 0xffffffff, 0 },
Michael Chan5bae30c2007-05-03 13:18:46 -07005785 },
5786 mem_tbl_5709[] = {
5787 { 0x60000, 0x4000 },
5788 { 0xa0000, 0x3000 },
5789 { 0xe0000, 0x4000 },
5790 { 0x120000, 0x4000 },
5791 { 0x1a0000, 0x4000 },
5792 { 0xffffffff, 0 },
Michael Chanb6016b72005-05-26 13:03:09 -07005793 };
Michael Chan5bae30c2007-05-03 13:18:46 -07005794 struct mem_entry *mem_tbl;
5795
Michael Chan4ce45e02012-12-06 10:33:10 +00005796 if (BNX2_CHIP(bp) == BNX2_CHIP_5709)
Michael Chan5bae30c2007-05-03 13:18:46 -07005797 mem_tbl = mem_tbl_5709;
5798 else
5799 mem_tbl = mem_tbl_5706;
Michael Chanb6016b72005-05-26 13:03:09 -07005800
5801 for (i = 0; mem_tbl[i].offset != 0xffffffff; i++) {
5802 if ((ret = bnx2_do_mem_test(bp, mem_tbl[i].offset,
5803 mem_tbl[i].len)) != 0) {
5804 return ret;
5805 }
5806 }
Jeff Garzik6aa20a22006-09-13 13:24:59 -04005807
Michael Chanb6016b72005-05-26 13:03:09 -07005808 return ret;
5809}
5810
Michael Chanbc5a0692006-01-23 16:13:22 -08005811#define BNX2_MAC_LOOPBACK 0
5812#define BNX2_PHY_LOOPBACK 1
5813
Michael Chanb6016b72005-05-26 13:03:09 -07005814static int
Michael Chanbc5a0692006-01-23 16:13:22 -08005815bnx2_run_loopback(struct bnx2 *bp, int loopback_mode)
Michael Chanb6016b72005-05-26 13:03:09 -07005816{
5817 unsigned int pkt_size, num_pkts, i;
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00005818 struct sk_buff *skb;
5819 u8 *data;
Michael Chanb6016b72005-05-26 13:03:09 -07005820 unsigned char *packet;
Michael Chanbc5a0692006-01-23 16:13:22 -08005821 u16 rx_start_idx, rx_idx;
Michael Chanb6016b72005-05-26 13:03:09 -07005822 dma_addr_t map;
Michael Chan2bc40782012-12-06 10:33:09 +00005823 struct bnx2_tx_bd *txbd;
5824 struct bnx2_sw_bd *rx_buf;
Michael Chanb6016b72005-05-26 13:03:09 -07005825 struct l2_fhdr *rx_hdr;
5826 int ret = -ENODEV;
Michael Chanc76c0472007-12-20 20:01:19 -08005827 struct bnx2_napi *bnapi = &bp->bnx2_napi[0], *tx_napi;
Michael Chan35e90102008-06-19 16:37:42 -07005828 struct bnx2_tx_ring_info *txr = &bnapi->tx_ring;
Michael Chanbb4f98a2008-06-19 16:38:19 -07005829 struct bnx2_rx_ring_info *rxr = &bnapi->rx_ring;
Michael Chanc76c0472007-12-20 20:01:19 -08005830
5831 tx_napi = bnapi;
Michael Chanb6016b72005-05-26 13:03:09 -07005832
Michael Chan35e90102008-06-19 16:37:42 -07005833 txr = &tx_napi->tx_ring;
Michael Chanbb4f98a2008-06-19 16:38:19 -07005834 rxr = &bnapi->rx_ring;
Michael Chanbc5a0692006-01-23 16:13:22 -08005835 if (loopback_mode == BNX2_MAC_LOOPBACK) {
5836 bp->loopback = MAC_LOOPBACK;
5837 bnx2_set_mac_loopback(bp);
5838 }
5839 else if (loopback_mode == BNX2_PHY_LOOPBACK) {
Michael Chan583c28e2008-01-21 19:51:35 -08005840 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
Michael Chan489310a2007-10-10 16:16:31 -07005841 return 0;
5842
Michael Chan80be4432006-11-19 14:07:28 -08005843 bp->loopback = PHY_LOOPBACK;
Michael Chanbc5a0692006-01-23 16:13:22 -08005844 bnx2_set_phy_loopback(bp);
5845 }
5846 else
5847 return -EINVAL;
Michael Chanb6016b72005-05-26 13:03:09 -07005848
Michael Chan84eaa182007-12-12 11:19:57 -08005849 pkt_size = min(bp->dev->mtu + ETH_HLEN, bp->rx_jumbo_thresh - 4);
Michael Chan932f3772006-08-15 01:39:36 -07005850 skb = netdev_alloc_skb(bp->dev, pkt_size);
John W. Linvilleb6cbc3b62005-11-10 12:58:00 -08005851 if (!skb)
5852 return -ENOMEM;
Michael Chanb6016b72005-05-26 13:03:09 -07005853 packet = skb_put(skb, pkt_size);
Joe Perchesd458cdf2013-10-01 19:04:40 -07005854 memcpy(packet, bp->dev->dev_addr, ETH_ALEN);
5855 memset(packet + ETH_ALEN, 0x0, 8);
Michael Chanb6016b72005-05-26 13:03:09 -07005856 for (i = 14; i < pkt_size; i++)
5857 packet[i] = (unsigned char) (i & 0xff);
5858
Stanislaw Gruszka36227e82010-07-15 04:25:50 +00005859 map = dma_map_single(&bp->pdev->dev, skb->data, pkt_size,
5860 PCI_DMA_TODEVICE);
5861 if (dma_mapping_error(&bp->pdev->dev, map)) {
Benjamin Li3d16af82008-10-09 12:26:41 -07005862 dev_kfree_skb(skb);
5863 return -EIO;
5864 }
Michael Chanb6016b72005-05-26 13:03:09 -07005865
Michael Chane503e062012-12-06 10:33:08 +00005866 BNX2_WR(bp, BNX2_HC_COMMAND,
5867 bp->hc_cmd | BNX2_HC_COMMAND_COAL_NOW_WO_INT);
Michael Chanbf5295b2006-03-23 01:11:56 -08005868
Michael Chane503e062012-12-06 10:33:08 +00005869 BNX2_RD(bp, BNX2_HC_COMMAND);
Michael Chanb6016b72005-05-26 13:03:09 -07005870
5871 udelay(5);
Michael Chan35efa7c2007-12-20 19:56:37 -08005872 rx_start_idx = bnx2_get_hw_rx_cons(bnapi);
Michael Chanb6016b72005-05-26 13:03:09 -07005873
Michael Chanb6016b72005-05-26 13:03:09 -07005874 num_pkts = 0;
5875
Michael Chan2bc40782012-12-06 10:33:09 +00005876 txbd = &txr->tx_desc_ring[BNX2_TX_RING_IDX(txr->tx_prod)];
Michael Chanb6016b72005-05-26 13:03:09 -07005877
5878 txbd->tx_bd_haddr_hi = (u64) map >> 32;
5879 txbd->tx_bd_haddr_lo = (u64) map & 0xffffffff;
5880 txbd->tx_bd_mss_nbytes = pkt_size;
5881 txbd->tx_bd_vlan_tag_flags = TX_BD_FLAGS_START | TX_BD_FLAGS_END;
5882
5883 num_pkts++;
Michael Chan2bc40782012-12-06 10:33:09 +00005884 txr->tx_prod = BNX2_NEXT_TX_BD(txr->tx_prod);
Michael Chan35e90102008-06-19 16:37:42 -07005885 txr->tx_prod_bseq += pkt_size;
Michael Chanb6016b72005-05-26 13:03:09 -07005886
Michael Chane503e062012-12-06 10:33:08 +00005887 BNX2_WR16(bp, txr->tx_bidx_addr, txr->tx_prod);
5888 BNX2_WR(bp, txr->tx_bseq_addr, txr->tx_prod_bseq);
Michael Chanb6016b72005-05-26 13:03:09 -07005889
5890 udelay(100);
5891
Michael Chane503e062012-12-06 10:33:08 +00005892 BNX2_WR(bp, BNX2_HC_COMMAND,
5893 bp->hc_cmd | BNX2_HC_COMMAND_COAL_NOW_WO_INT);
Michael Chanbf5295b2006-03-23 01:11:56 -08005894
Michael Chane503e062012-12-06 10:33:08 +00005895 BNX2_RD(bp, BNX2_HC_COMMAND);
Michael Chanb6016b72005-05-26 13:03:09 -07005896
5897 udelay(5);
5898
Stanislaw Gruszka36227e82010-07-15 04:25:50 +00005899 dma_unmap_single(&bp->pdev->dev, map, pkt_size, PCI_DMA_TODEVICE);
Michael Chan745720e2006-06-29 12:37:41 -07005900 dev_kfree_skb(skb);
Michael Chanb6016b72005-05-26 13:03:09 -07005901
Michael Chan35e90102008-06-19 16:37:42 -07005902 if (bnx2_get_hw_tx_cons(tx_napi) != txr->tx_prod)
Michael Chanb6016b72005-05-26 13:03:09 -07005903 goto loopback_test_done;
Michael Chanb6016b72005-05-26 13:03:09 -07005904
Michael Chan35efa7c2007-12-20 19:56:37 -08005905 rx_idx = bnx2_get_hw_rx_cons(bnapi);
Michael Chanb6016b72005-05-26 13:03:09 -07005906 if (rx_idx != rx_start_idx + num_pkts) {
5907 goto loopback_test_done;
5908 }
5909
Michael Chanbb4f98a2008-06-19 16:38:19 -07005910 rx_buf = &rxr->rx_buf_ring[rx_start_idx];
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00005911 data = rx_buf->data;
Michael Chanb6016b72005-05-26 13:03:09 -07005912
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00005913 rx_hdr = get_l2_fhdr(data);
5914 data = (u8 *)rx_hdr + BNX2_RX_OFFSET;
Michael Chanb6016b72005-05-26 13:03:09 -07005915
Stanislaw Gruszka36227e82010-07-15 04:25:50 +00005916 dma_sync_single_for_cpu(&bp->pdev->dev,
FUJITA Tomonori1a4ccc22010-04-01 16:56:57 +00005917 dma_unmap_addr(rx_buf, mapping),
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00005918 bp->rx_buf_use_size, PCI_DMA_FROMDEVICE);
Michael Chanb6016b72005-05-26 13:03:09 -07005919
Michael Chanade2bfe2006-01-23 16:09:51 -08005920 if (rx_hdr->l2_fhdr_status &
Michael Chanb6016b72005-05-26 13:03:09 -07005921 (L2_FHDR_ERRORS_BAD_CRC |
5922 L2_FHDR_ERRORS_PHY_DECODE |
5923 L2_FHDR_ERRORS_ALIGNMENT |
5924 L2_FHDR_ERRORS_TOO_SHORT |
5925 L2_FHDR_ERRORS_GIANT_FRAME)) {
5926
5927 goto loopback_test_done;
5928 }
5929
5930 if ((rx_hdr->l2_fhdr_pkt_len - 4) != pkt_size) {
5931 goto loopback_test_done;
5932 }
5933
5934 for (i = 14; i < pkt_size; i++) {
Eric Dumazetdd2bc8e2011-11-15 07:30:05 +00005935 if (*(data + i) != (unsigned char) (i & 0xff)) {
Michael Chanb6016b72005-05-26 13:03:09 -07005936 goto loopback_test_done;
5937 }
5938 }
5939
5940 ret = 0;
5941
5942loopback_test_done:
5943 bp->loopback = 0;
5944 return ret;
5945}
5946
Michael Chanbc5a0692006-01-23 16:13:22 -08005947#define BNX2_MAC_LOOPBACK_FAILED 1
5948#define BNX2_PHY_LOOPBACK_FAILED 2
5949#define BNX2_LOOPBACK_FAILED (BNX2_MAC_LOOPBACK_FAILED | \
5950 BNX2_PHY_LOOPBACK_FAILED)
5951
5952static int
5953bnx2_test_loopback(struct bnx2 *bp)
5954{
5955 int rc = 0;
5956
5957 if (!netif_running(bp->dev))
5958 return BNX2_LOOPBACK_FAILED;
5959
5960 bnx2_reset_nic(bp, BNX2_DRV_MSG_CODE_RESET);
5961 spin_lock_bh(&bp->phy_lock);
Michael Chan9a120bc2008-05-16 22:17:45 -07005962 bnx2_init_phy(bp, 1);
Michael Chanbc5a0692006-01-23 16:13:22 -08005963 spin_unlock_bh(&bp->phy_lock);
5964 if (bnx2_run_loopback(bp, BNX2_MAC_LOOPBACK))
5965 rc |= BNX2_MAC_LOOPBACK_FAILED;
5966 if (bnx2_run_loopback(bp, BNX2_PHY_LOOPBACK))
5967 rc |= BNX2_PHY_LOOPBACK_FAILED;
5968 return rc;
5969}
5970
Michael Chanb6016b72005-05-26 13:03:09 -07005971#define NVRAM_SIZE 0x200
5972#define CRC32_RESIDUAL 0xdebb20e3
5973
5974static int
5975bnx2_test_nvram(struct bnx2 *bp)
5976{
Al Virob491edd2007-12-22 19:44:51 +00005977 __be32 buf[NVRAM_SIZE / 4];
Michael Chanb6016b72005-05-26 13:03:09 -07005978 u8 *data = (u8 *) buf;
5979 int rc = 0;
5980 u32 magic, csum;
5981
5982 if ((rc = bnx2_nvram_read(bp, 0, data, 4)) != 0)
5983 goto test_nvram_done;
5984
5985 magic = be32_to_cpu(buf[0]);
5986 if (magic != 0x669955aa) {
5987 rc = -ENODEV;
5988 goto test_nvram_done;
5989 }
5990
5991 if ((rc = bnx2_nvram_read(bp, 0x100, data, NVRAM_SIZE)) != 0)
5992 goto test_nvram_done;
5993
5994 csum = ether_crc_le(0x100, data);
5995 if (csum != CRC32_RESIDUAL) {
5996 rc = -ENODEV;
5997 goto test_nvram_done;
5998 }
5999
6000 csum = ether_crc_le(0x100, data + 0x100);
6001 if (csum != CRC32_RESIDUAL) {
6002 rc = -ENODEV;
6003 }
6004
6005test_nvram_done:
6006 return rc;
6007}
6008
6009static int
6010bnx2_test_link(struct bnx2 *bp)
6011{
6012 u32 bmsr;
6013
Michael Chan9f52b562008-10-09 12:21:46 -07006014 if (!netif_running(bp->dev))
6015 return -ENODEV;
6016
Michael Chan583c28e2008-01-21 19:51:35 -08006017 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP) {
Michael Chan489310a2007-10-10 16:16:31 -07006018 if (bp->link_up)
6019 return 0;
6020 return -ENODEV;
6021 }
Michael Chanc770a652005-08-25 15:38:39 -07006022 spin_lock_bh(&bp->phy_lock);
Michael Chan27a005b2007-05-03 13:23:41 -07006023 bnx2_enable_bmsr1(bp);
6024 bnx2_read_phy(bp, bp->mii_bmsr1, &bmsr);
6025 bnx2_read_phy(bp, bp->mii_bmsr1, &bmsr);
6026 bnx2_disable_bmsr1(bp);
Michael Chanc770a652005-08-25 15:38:39 -07006027 spin_unlock_bh(&bp->phy_lock);
Jeff Garzik6aa20a22006-09-13 13:24:59 -04006028
Michael Chanb6016b72005-05-26 13:03:09 -07006029 if (bmsr & BMSR_LSTATUS) {
6030 return 0;
6031 }
6032 return -ENODEV;
6033}
6034
6035static int
6036bnx2_test_intr(struct bnx2 *bp)
6037{
6038 int i;
Michael Chanb6016b72005-05-26 13:03:09 -07006039 u16 status_idx;
6040
6041 if (!netif_running(bp->dev))
6042 return -ENODEV;
6043
Michael Chane503e062012-12-06 10:33:08 +00006044 status_idx = BNX2_RD(bp, BNX2_PCICFG_INT_ACK_CMD) & 0xffff;
Michael Chanb6016b72005-05-26 13:03:09 -07006045
6046 /* This register is not touched during run-time. */
Michael Chane503e062012-12-06 10:33:08 +00006047 BNX2_WR(bp, BNX2_HC_COMMAND, bp->hc_cmd | BNX2_HC_COMMAND_COAL_NOW);
6048 BNX2_RD(bp, BNX2_HC_COMMAND);
Michael Chanb6016b72005-05-26 13:03:09 -07006049
6050 for (i = 0; i < 10; i++) {
Michael Chane503e062012-12-06 10:33:08 +00006051 if ((BNX2_RD(bp, BNX2_PCICFG_INT_ACK_CMD) & 0xffff) !=
Michael Chanb6016b72005-05-26 13:03:09 -07006052 status_idx) {
6053
6054 break;
6055 }
6056
6057 msleep_interruptible(10);
6058 }
6059 if (i < 10)
6060 return 0;
6061
6062 return -ENODEV;
6063}
6064
Michael Chan38ea3682008-02-23 19:48:57 -08006065/* Determining link for parallel detection. */
Michael Chanb2fadea2008-01-21 17:07:06 -08006066static int
6067bnx2_5706_serdes_has_link(struct bnx2 *bp)
6068{
6069 u32 mode_ctl, an_dbg, exp;
6070
Michael Chan38ea3682008-02-23 19:48:57 -08006071 if (bp->phy_flags & BNX2_PHY_FLAG_NO_PARALLEL)
6072 return 0;
6073
Michael Chanb2fadea2008-01-21 17:07:06 -08006074 bnx2_write_phy(bp, MII_BNX2_MISC_SHADOW, MISC_SHDW_MODE_CTL);
6075 bnx2_read_phy(bp, MII_BNX2_MISC_SHADOW, &mode_ctl);
6076
6077 if (!(mode_ctl & MISC_SHDW_MODE_CTL_SIG_DET))
6078 return 0;
6079
6080 bnx2_write_phy(bp, MII_BNX2_MISC_SHADOW, MISC_SHDW_AN_DBG);
6081 bnx2_read_phy(bp, MII_BNX2_MISC_SHADOW, &an_dbg);
6082 bnx2_read_phy(bp, MII_BNX2_MISC_SHADOW, &an_dbg);
6083
Michael Chanf3014c02008-01-29 21:33:03 -08006084 if (an_dbg & (MISC_SHDW_AN_DBG_NOSYNC | MISC_SHDW_AN_DBG_RUDI_INVALID))
Michael Chanb2fadea2008-01-21 17:07:06 -08006085 return 0;
6086
6087 bnx2_write_phy(bp, MII_BNX2_DSP_ADDRESS, MII_EXPAND_REG1);
6088 bnx2_read_phy(bp, MII_BNX2_DSP_RW_PORT, &exp);
6089 bnx2_read_phy(bp, MII_BNX2_DSP_RW_PORT, &exp);
6090
6091 if (exp & MII_EXPAND_REG1_RUDI_C) /* receiving CONFIG */
6092 return 0;
6093
6094 return 1;
6095}
6096
Michael Chanb6016b72005-05-26 13:03:09 -07006097static void
Michael Chan48b01e22006-11-19 14:08:00 -08006098bnx2_5706_serdes_timer(struct bnx2 *bp)
6099{
Michael Chanb2fadea2008-01-21 17:07:06 -08006100 int check_link = 1;
6101
Michael Chan48b01e22006-11-19 14:08:00 -08006102 spin_lock(&bp->phy_lock);
Michael Chanb2fadea2008-01-21 17:07:06 -08006103 if (bp->serdes_an_pending) {
Michael Chan48b01e22006-11-19 14:08:00 -08006104 bp->serdes_an_pending--;
Michael Chanb2fadea2008-01-21 17:07:06 -08006105 check_link = 0;
6106 } else if ((bp->link_up == 0) && (bp->autoneg & AUTONEG_SPEED)) {
Michael Chan48b01e22006-11-19 14:08:00 -08006107 u32 bmcr;
6108
Benjamin Liac392ab2008-09-18 16:40:49 -07006109 bp->current_interval = BNX2_TIMER_INTERVAL;
Michael Chan48b01e22006-11-19 14:08:00 -08006110
Michael Chanca58c3a2007-05-03 13:22:52 -07006111 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chan48b01e22006-11-19 14:08:00 -08006112
6113 if (bmcr & BMCR_ANENABLE) {
Michael Chanb2fadea2008-01-21 17:07:06 -08006114 if (bnx2_5706_serdes_has_link(bp)) {
Michael Chan48b01e22006-11-19 14:08:00 -08006115 bmcr &= ~BMCR_ANENABLE;
6116 bmcr |= BMCR_SPEED1000 | BMCR_FULLDPLX;
Michael Chanca58c3a2007-05-03 13:22:52 -07006117 bnx2_write_phy(bp, bp->mii_bmcr, bmcr);
Michael Chan583c28e2008-01-21 19:51:35 -08006118 bp->phy_flags |= BNX2_PHY_FLAG_PARALLEL_DETECT;
Michael Chan48b01e22006-11-19 14:08:00 -08006119 }
6120 }
6121 }
6122 else if ((bp->link_up) && (bp->autoneg & AUTONEG_SPEED) &&
Michael Chan583c28e2008-01-21 19:51:35 -08006123 (bp->phy_flags & BNX2_PHY_FLAG_PARALLEL_DETECT)) {
Michael Chan48b01e22006-11-19 14:08:00 -08006124 u32 phy2;
6125
6126 bnx2_write_phy(bp, 0x17, 0x0f01);
6127 bnx2_read_phy(bp, 0x15, &phy2);
6128 if (phy2 & 0x20) {
6129 u32 bmcr;
6130
Michael Chanca58c3a2007-05-03 13:22:52 -07006131 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chan48b01e22006-11-19 14:08:00 -08006132 bmcr |= BMCR_ANENABLE;
Michael Chanca58c3a2007-05-03 13:22:52 -07006133 bnx2_write_phy(bp, bp->mii_bmcr, bmcr);
Michael Chan48b01e22006-11-19 14:08:00 -08006134
Michael Chan583c28e2008-01-21 19:51:35 -08006135 bp->phy_flags &= ~BNX2_PHY_FLAG_PARALLEL_DETECT;
Michael Chan48b01e22006-11-19 14:08:00 -08006136 }
6137 } else
Benjamin Liac392ab2008-09-18 16:40:49 -07006138 bp->current_interval = BNX2_TIMER_INTERVAL;
Michael Chan48b01e22006-11-19 14:08:00 -08006139
Michael Chana2724e22008-02-23 19:47:44 -08006140 if (check_link) {
Michael Chanb2fadea2008-01-21 17:07:06 -08006141 u32 val;
6142
6143 bnx2_write_phy(bp, MII_BNX2_MISC_SHADOW, MISC_SHDW_AN_DBG);
6144 bnx2_read_phy(bp, MII_BNX2_MISC_SHADOW, &val);
6145 bnx2_read_phy(bp, MII_BNX2_MISC_SHADOW, &val);
6146
Michael Chana2724e22008-02-23 19:47:44 -08006147 if (bp->link_up && (val & MISC_SHDW_AN_DBG_NOSYNC)) {
6148 if (!(bp->phy_flags & BNX2_PHY_FLAG_FORCED_DOWN)) {
6149 bnx2_5706s_force_link_dn(bp, 1);
6150 bp->phy_flags |= BNX2_PHY_FLAG_FORCED_DOWN;
6151 } else
6152 bnx2_set_link(bp);
6153 } else if (!bp->link_up && !(val & MISC_SHDW_AN_DBG_NOSYNC))
6154 bnx2_set_link(bp);
Michael Chanb2fadea2008-01-21 17:07:06 -08006155 }
Michael Chan48b01e22006-11-19 14:08:00 -08006156 spin_unlock(&bp->phy_lock);
6157}
6158
6159static void
Michael Chanf8dd0642006-11-19 14:08:29 -08006160bnx2_5708_serdes_timer(struct bnx2 *bp)
6161{
Michael Chan583c28e2008-01-21 19:51:35 -08006162 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
Michael Chan0d8a6572007-07-07 22:49:43 -07006163 return;
6164
Michael Chan583c28e2008-01-21 19:51:35 -08006165 if ((bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE) == 0) {
Michael Chanf8dd0642006-11-19 14:08:29 -08006166 bp->serdes_an_pending = 0;
6167 return;
6168 }
6169
6170 spin_lock(&bp->phy_lock);
6171 if (bp->serdes_an_pending)
6172 bp->serdes_an_pending--;
6173 else if ((bp->link_up == 0) && (bp->autoneg & AUTONEG_SPEED)) {
6174 u32 bmcr;
6175
Michael Chanca58c3a2007-05-03 13:22:52 -07006176 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chanf8dd0642006-11-19 14:08:29 -08006177 if (bmcr & BMCR_ANENABLE) {
Michael Chan605a9e22007-05-03 13:23:13 -07006178 bnx2_enable_forced_2g5(bp);
Michael Chan40105c02008-11-12 16:02:45 -08006179 bp->current_interval = BNX2_SERDES_FORCED_TIMEOUT;
Michael Chanf8dd0642006-11-19 14:08:29 -08006180 } else {
Michael Chan605a9e22007-05-03 13:23:13 -07006181 bnx2_disable_forced_2g5(bp);
Michael Chanf8dd0642006-11-19 14:08:29 -08006182 bp->serdes_an_pending = 2;
Benjamin Liac392ab2008-09-18 16:40:49 -07006183 bp->current_interval = BNX2_TIMER_INTERVAL;
Michael Chanf8dd0642006-11-19 14:08:29 -08006184 }
6185
6186 } else
Benjamin Liac392ab2008-09-18 16:40:49 -07006187 bp->current_interval = BNX2_TIMER_INTERVAL;
Michael Chanf8dd0642006-11-19 14:08:29 -08006188
6189 spin_unlock(&bp->phy_lock);
6190}
6191
6192static void
Michael Chanb6016b72005-05-26 13:03:09 -07006193bnx2_timer(unsigned long data)
6194{
6195 struct bnx2 *bp = (struct bnx2 *) data;
Michael Chanb6016b72005-05-26 13:03:09 -07006196
Michael Chancd339a02005-08-25 15:35:24 -07006197 if (!netif_running(bp->dev))
6198 return;
6199
Michael Chanb6016b72005-05-26 13:03:09 -07006200 if (atomic_read(&bp->intr_sem) != 0)
6201 goto bnx2_restart_timer;
6202
Michael Chanefba0182008-12-03 00:36:15 -08006203 if ((bp->flags & (BNX2_FLAG_USING_MSI | BNX2_FLAG_ONE_SHOT_MSI)) ==
6204 BNX2_FLAG_USING_MSI)
6205 bnx2_chk_missed_msi(bp);
6206
Michael Chandf149d72007-07-07 22:51:36 -07006207 bnx2_send_heart_beat(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07006208
Michael Chan2726d6e2008-01-29 21:35:05 -08006209 bp->stats_blk->stat_FwRxDrop =
6210 bnx2_reg_rd_ind(bp, BNX2_FW_RX_DROP_COUNT);
Michael Chancea94db2006-06-12 22:16:13 -07006211
Michael Chan02537b062007-06-04 21:24:07 -07006212 /* workaround occasional corrupted counters */
Michael Chan61d9e3f2009-08-21 16:20:46 +00006213 if ((bp->flags & BNX2_FLAG_BROKEN_STATS) && bp->stats_ticks)
Michael Chane503e062012-12-06 10:33:08 +00006214 BNX2_WR(bp, BNX2_HC_COMMAND, bp->hc_cmd |
6215 BNX2_HC_COMMAND_STATS_NOW);
Michael Chan02537b062007-06-04 21:24:07 -07006216
Michael Chan583c28e2008-01-21 19:51:35 -08006217 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Michael Chan4ce45e02012-12-06 10:33:10 +00006218 if (BNX2_CHIP(bp) == BNX2_CHIP_5706)
Michael Chanf8dd0642006-11-19 14:08:29 -08006219 bnx2_5706_serdes_timer(bp);
Michael Chan27a005b2007-05-03 13:23:41 -07006220 else
Michael Chanf8dd0642006-11-19 14:08:29 -08006221 bnx2_5708_serdes_timer(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07006222 }
6223
6224bnx2_restart_timer:
Michael Chancd339a02005-08-25 15:35:24 -07006225 mod_timer(&bp->timer, jiffies + bp->current_interval);
Michael Chanb6016b72005-05-26 13:03:09 -07006226}
6227
Michael Chan8e6a72c2007-05-03 13:24:48 -07006228static int
6229bnx2_request_irq(struct bnx2 *bp)
6230{
Michael Chan6d866ff2007-12-20 19:56:09 -08006231 unsigned long flags;
Michael Chanb4b36042007-12-20 19:59:30 -08006232 struct bnx2_irq *irq;
6233 int rc = 0, i;
Michael Chan8e6a72c2007-05-03 13:24:48 -07006234
David S. Millerf86e82f2008-01-21 17:15:40 -08006235 if (bp->flags & BNX2_FLAG_USING_MSI_OR_MSIX)
Michael Chan6d866ff2007-12-20 19:56:09 -08006236 flags = 0;
6237 else
6238 flags = IRQF_SHARED;
Michael Chanb4b36042007-12-20 19:59:30 -08006239
6240 for (i = 0; i < bp->irq_nvecs; i++) {
6241 irq = &bp->irq_tbl[i];
Michael Chanc76c0472007-12-20 20:01:19 -08006242 rc = request_irq(irq->vector, irq->handler, flags, irq->name,
Michael Chanf0ea2e62008-06-19 16:41:57 -07006243 &bp->bnx2_napi[i]);
Michael Chanb4b36042007-12-20 19:59:30 -08006244 if (rc)
6245 break;
6246 irq->requested = 1;
6247 }
Michael Chan8e6a72c2007-05-03 13:24:48 -07006248 return rc;
6249}
6250
6251static void
Michael Chana29ba9d2010-12-31 11:03:14 -08006252__bnx2_free_irq(struct bnx2 *bp)
Michael Chan8e6a72c2007-05-03 13:24:48 -07006253{
Michael Chanb4b36042007-12-20 19:59:30 -08006254 struct bnx2_irq *irq;
6255 int i;
Michael Chan8e6a72c2007-05-03 13:24:48 -07006256
Michael Chanb4b36042007-12-20 19:59:30 -08006257 for (i = 0; i < bp->irq_nvecs; i++) {
6258 irq = &bp->irq_tbl[i];
6259 if (irq->requested)
Michael Chanf0ea2e62008-06-19 16:41:57 -07006260 free_irq(irq->vector, &bp->bnx2_napi[i]);
Michael Chanb4b36042007-12-20 19:59:30 -08006261 irq->requested = 0;
Michael Chan6d866ff2007-12-20 19:56:09 -08006262 }
Michael Chana29ba9d2010-12-31 11:03:14 -08006263}
6264
6265static void
6266bnx2_free_irq(struct bnx2 *bp)
6267{
6268
6269 __bnx2_free_irq(bp);
David S. Millerf86e82f2008-01-21 17:15:40 -08006270 if (bp->flags & BNX2_FLAG_USING_MSI)
Michael Chanb4b36042007-12-20 19:59:30 -08006271 pci_disable_msi(bp->pdev);
David S. Millerf86e82f2008-01-21 17:15:40 -08006272 else if (bp->flags & BNX2_FLAG_USING_MSIX)
Michael Chanb4b36042007-12-20 19:59:30 -08006273 pci_disable_msix(bp->pdev);
6274
David S. Millerf86e82f2008-01-21 17:15:40 -08006275 bp->flags &= ~(BNX2_FLAG_USING_MSI_OR_MSIX | BNX2_FLAG_ONE_SHOT_MSI);
Michael Chanb4b36042007-12-20 19:59:30 -08006276}
6277
6278static void
Michael Chan5e9ad9e2008-06-19 16:43:17 -07006279bnx2_enable_msix(struct bnx2 *bp, int msix_vecs)
Michael Chanb4b36042007-12-20 19:59:30 -08006280{
Alexander Gordeevf2a2dfe2014-02-18 11:07:53 +01006281 int i, total_vecs;
Michael Chan57851d82007-12-20 20:01:44 -08006282 struct msix_entry msix_ent[BNX2_MAX_MSIX_VEC];
Michael Chan4e1d0de2008-12-16 20:27:45 -08006283 struct net_device *dev = bp->dev;
6284 const int len = sizeof(bp->irq_tbl[0].name);
Michael Chan57851d82007-12-20 20:01:44 -08006285
Michael Chanb4b36042007-12-20 19:59:30 -08006286 bnx2_setup_msix_tbl(bp);
Michael Chane503e062012-12-06 10:33:08 +00006287 BNX2_WR(bp, BNX2_PCI_MSIX_CONTROL, BNX2_MAX_MSIX_HW_VEC - 1);
6288 BNX2_WR(bp, BNX2_PCI_MSIX_TBL_OFF_BIR, BNX2_PCI_GRC_WINDOW2_BASE);
6289 BNX2_WR(bp, BNX2_PCI_MSIX_PBA_OFF_BIT, BNX2_PCI_GRC_WINDOW3_BASE);
Michael Chan57851d82007-12-20 20:01:44 -08006290
Benjamin Lie2eb8e32010-01-08 00:51:21 -08006291 /* Need to flush the previous three writes to ensure MSI-X
6292 * is setup properly */
Michael Chane503e062012-12-06 10:33:08 +00006293 BNX2_RD(bp, BNX2_PCI_MSIX_CONTROL);
Benjamin Lie2eb8e32010-01-08 00:51:21 -08006294
Michael Chan57851d82007-12-20 20:01:44 -08006295 for (i = 0; i < BNX2_MAX_MSIX_VEC; i++) {
6296 msix_ent[i].entry = i;
6297 msix_ent[i].vector = 0;
6298 }
6299
Michael Chan379b39a2010-07-19 14:15:03 +00006300 total_vecs = msix_vecs;
6301#ifdef BCM_CNIC
6302 total_vecs++;
6303#endif
Alexander Gordeevf2a2dfe2014-02-18 11:07:53 +01006304 total_vecs = pci_enable_msix_range(bp->pdev, msix_ent,
6305 BNX2_MIN_MSIX_VEC, total_vecs);
6306 if (total_vecs < 0)
Michael Chan57851d82007-12-20 20:01:44 -08006307 return;
6308
Michael Chan379b39a2010-07-19 14:15:03 +00006309 msix_vecs = total_vecs;
6310#ifdef BCM_CNIC
6311 msix_vecs--;
6312#endif
Michael Chan5e9ad9e2008-06-19 16:43:17 -07006313 bp->irq_nvecs = msix_vecs;
David S. Millerf86e82f2008-01-21 17:15:40 -08006314 bp->flags |= BNX2_FLAG_USING_MSIX | BNX2_FLAG_ONE_SHOT_MSI;
Michael Chan379b39a2010-07-19 14:15:03 +00006315 for (i = 0; i < total_vecs; i++) {
Michael Chan57851d82007-12-20 20:01:44 -08006316 bp->irq_tbl[i].vector = msix_ent[i].vector;
Michael Chan69010312009-03-18 18:11:51 -07006317 snprintf(bp->irq_tbl[i].name, len, "%s-%d", dev->name, i);
6318 bp->irq_tbl[i].handler = bnx2_msi_1shot;
6319 }
Michael Chan6d866ff2007-12-20 19:56:09 -08006320}
6321
Ben Hutchings657d92f2010-09-27 08:25:16 +00006322static int
Michael Chan6d866ff2007-12-20 19:56:09 -08006323bnx2_setup_int_mode(struct bnx2 *bp, int dis_msi)
6324{
Yuval Mintz0a742122012-07-01 03:18:58 +00006325 int cpus = netif_get_num_default_rss_queues();
Michael Chanb0332812012-02-05 15:24:38 +00006326 int msix_vecs;
6327
6328 if (!bp->num_req_rx_rings)
6329 msix_vecs = max(cpus + 1, bp->num_req_tx_rings);
6330 else if (!bp->num_req_tx_rings)
6331 msix_vecs = max(cpus, bp->num_req_rx_rings);
6332 else
6333 msix_vecs = max(bp->num_req_rx_rings, bp->num_req_tx_rings);
6334
6335 msix_vecs = min(msix_vecs, RX_MAX_RINGS);
Michael Chan5e9ad9e2008-06-19 16:43:17 -07006336
Michael Chan6d866ff2007-12-20 19:56:09 -08006337 bp->irq_tbl[0].handler = bnx2_interrupt;
6338 strcpy(bp->irq_tbl[0].name, bp->dev->name);
Michael Chanb4b36042007-12-20 19:59:30 -08006339 bp->irq_nvecs = 1;
6340 bp->irq_tbl[0].vector = bp->pdev->irq;
Michael Chan6d866ff2007-12-20 19:56:09 -08006341
Michael Chan3d5f3a72010-07-03 20:42:15 +00006342 if ((bp->flags & BNX2_FLAG_MSIX_CAP) && !dis_msi)
Michael Chan5e9ad9e2008-06-19 16:43:17 -07006343 bnx2_enable_msix(bp, msix_vecs);
Michael Chanb4b36042007-12-20 19:59:30 -08006344
David S. Millerf86e82f2008-01-21 17:15:40 -08006345 if ((bp->flags & BNX2_FLAG_MSI_CAP) && !dis_msi &&
6346 !(bp->flags & BNX2_FLAG_USING_MSIX)) {
Michael Chan6d866ff2007-12-20 19:56:09 -08006347 if (pci_enable_msi(bp->pdev) == 0) {
David S. Millerf86e82f2008-01-21 17:15:40 -08006348 bp->flags |= BNX2_FLAG_USING_MSI;
Michael Chan4ce45e02012-12-06 10:33:10 +00006349 if (BNX2_CHIP(bp) == BNX2_CHIP_5709) {
David S. Millerf86e82f2008-01-21 17:15:40 -08006350 bp->flags |= BNX2_FLAG_ONE_SHOT_MSI;
Michael Chan6d866ff2007-12-20 19:56:09 -08006351 bp->irq_tbl[0].handler = bnx2_msi_1shot;
6352 } else
6353 bp->irq_tbl[0].handler = bnx2_msi;
Michael Chanb4b36042007-12-20 19:59:30 -08006354
6355 bp->irq_tbl[0].vector = bp->pdev->irq;
Michael Chan6d866ff2007-12-20 19:56:09 -08006356 }
6357 }
Benjamin Li706bf242008-07-18 17:55:11 -07006358
Michael Chanb0332812012-02-05 15:24:38 +00006359 if (!bp->num_req_tx_rings)
6360 bp->num_tx_rings = rounddown_pow_of_two(bp->irq_nvecs);
6361 else
6362 bp->num_tx_rings = min(bp->irq_nvecs, bp->num_req_tx_rings);
6363
6364 if (!bp->num_req_rx_rings)
6365 bp->num_rx_rings = bp->irq_nvecs;
6366 else
6367 bp->num_rx_rings = min(bp->irq_nvecs, bp->num_req_rx_rings);
6368
Ben Hutchings657d92f2010-09-27 08:25:16 +00006369 netif_set_real_num_tx_queues(bp->dev, bp->num_tx_rings);
Benjamin Li706bf242008-07-18 17:55:11 -07006370
Ben Hutchings657d92f2010-09-27 08:25:16 +00006371 return netif_set_real_num_rx_queues(bp->dev, bp->num_rx_rings);
Michael Chan8e6a72c2007-05-03 13:24:48 -07006372}
6373
Michael Chanb6016b72005-05-26 13:03:09 -07006374/* Called with rtnl_lock */
6375static int
6376bnx2_open(struct net_device *dev)
6377{
Michael Chan972ec0d2006-01-23 16:12:43 -08006378 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006379 int rc;
6380
Baoquan He5d0d4b92016-11-13 13:01:32 +08006381 rc = bnx2_request_firmware(bp);
6382 if (rc < 0)
6383 goto out;
6384
Michael Chan1b2f9222007-05-03 13:20:19 -07006385 netif_carrier_off(dev);
6386
Michael Chanb6016b72005-05-26 13:03:09 -07006387 bnx2_disable_int(bp);
6388
Ben Hutchings657d92f2010-09-27 08:25:16 +00006389 rc = bnx2_setup_int_mode(bp, disable_msi);
6390 if (rc)
6391 goto open_err;
Benjamin Li4327ba42010-03-23 13:13:11 +00006392 bnx2_init_napi(bp);
Michael Chan35efa7c2007-12-20 19:56:37 -08006393 bnx2_napi_enable(bp);
Michael Chan35e90102008-06-19 16:37:42 -07006394 rc = bnx2_alloc_mem(bp);
Michael Chan2739a8b2008-06-19 16:44:10 -07006395 if (rc)
6396 goto open_err;
Michael Chan35e90102008-06-19 16:37:42 -07006397
Michael Chan8e6a72c2007-05-03 13:24:48 -07006398 rc = bnx2_request_irq(bp);
Michael Chan2739a8b2008-06-19 16:44:10 -07006399 if (rc)
6400 goto open_err;
Michael Chanb6016b72005-05-26 13:03:09 -07006401
Michael Chan9a120bc2008-05-16 22:17:45 -07006402 rc = bnx2_init_nic(bp, 1);
Michael Chan2739a8b2008-06-19 16:44:10 -07006403 if (rc)
6404 goto open_err;
Jeff Garzik6aa20a22006-09-13 13:24:59 -04006405
Michael Chancd339a02005-08-25 15:35:24 -07006406 mod_timer(&bp->timer, jiffies + bp->current_interval);
Michael Chanb6016b72005-05-26 13:03:09 -07006407
6408 atomic_set(&bp->intr_sem, 0);
6409
Michael Chan354fcd72010-01-17 07:30:44 +00006410 memset(bp->temp_stats_blk, 0, sizeof(struct statistics_block));
6411
Michael Chanb6016b72005-05-26 13:03:09 -07006412 bnx2_enable_int(bp);
6413
David S. Millerf86e82f2008-01-21 17:15:40 -08006414 if (bp->flags & BNX2_FLAG_USING_MSI) {
Michael Chanb6016b72005-05-26 13:03:09 -07006415 /* Test MSI to make sure it is working
6416 * If MSI test fails, go back to INTx mode
6417 */
6418 if (bnx2_test_intr(bp) != 0) {
Joe Perches3a9c6a42010-02-17 15:01:51 +00006419 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 -07006420
6421 bnx2_disable_int(bp);
Michael Chan8e6a72c2007-05-03 13:24:48 -07006422 bnx2_free_irq(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07006423
Michael Chan6d866ff2007-12-20 19:56:09 -08006424 bnx2_setup_int_mode(bp, 1);
6425
Michael Chan9a120bc2008-05-16 22:17:45 -07006426 rc = bnx2_init_nic(bp, 0);
Michael Chanb6016b72005-05-26 13:03:09 -07006427
Michael Chan8e6a72c2007-05-03 13:24:48 -07006428 if (!rc)
6429 rc = bnx2_request_irq(bp);
6430
Michael Chanb6016b72005-05-26 13:03:09 -07006431 if (rc) {
Michael Chanb6016b72005-05-26 13:03:09 -07006432 del_timer_sync(&bp->timer);
Michael Chan2739a8b2008-06-19 16:44:10 -07006433 goto open_err;
Michael Chanb6016b72005-05-26 13:03:09 -07006434 }
6435 bnx2_enable_int(bp);
6436 }
6437 }
David S. Millerf86e82f2008-01-21 17:15:40 -08006438 if (bp->flags & BNX2_FLAG_USING_MSI)
Joe Perches3a9c6a42010-02-17 15:01:51 +00006439 netdev_info(dev, "using MSI\n");
David S. Millerf86e82f2008-01-21 17:15:40 -08006440 else if (bp->flags & BNX2_FLAG_USING_MSIX)
Joe Perches3a9c6a42010-02-17 15:01:51 +00006441 netdev_info(dev, "using MSIX\n");
Michael Chanb6016b72005-05-26 13:03:09 -07006442
Benjamin Li706bf242008-07-18 17:55:11 -07006443 netif_tx_start_all_queues(dev);
françois romieu7880b722011-09-30 00:36:52 +00006444out:
6445 return rc;
Michael Chan2739a8b2008-06-19 16:44:10 -07006446
6447open_err:
6448 bnx2_napi_disable(bp);
6449 bnx2_free_skbs(bp);
6450 bnx2_free_irq(bp);
6451 bnx2_free_mem(bp);
Michael Chanf048fa92010-06-01 15:05:36 +00006452 bnx2_del_napi(bp);
Baoquan He5d0d4b92016-11-13 13:01:32 +08006453 bnx2_release_firmware(bp);
françois romieu7880b722011-09-30 00:36:52 +00006454 goto out;
Michael Chanb6016b72005-05-26 13:03:09 -07006455}
6456
6457static void
David Howellsc4028952006-11-22 14:57:56 +00006458bnx2_reset_task(struct work_struct *work)
Michael Chanb6016b72005-05-26 13:03:09 -07006459{
David Howellsc4028952006-11-22 14:57:56 +00006460 struct bnx2 *bp = container_of(work, struct bnx2, reset_task);
Michael Chancd634012011-07-15 06:53:58 +00006461 int rc;
Michael Chanefdfad32012-07-16 14:25:56 +00006462 u16 pcicmd;
Michael Chanb6016b72005-05-26 13:03:09 -07006463
Michael Chan51bf6bb2009-12-03 09:46:31 +00006464 rtnl_lock();
6465 if (!netif_running(bp->dev)) {
6466 rtnl_unlock();
Michael Chanafdc08b2005-08-25 15:34:29 -07006467 return;
Michael Chan51bf6bb2009-12-03 09:46:31 +00006468 }
Michael Chanafdc08b2005-08-25 15:34:29 -07006469
Michael Chan212f9932010-04-27 11:28:10 +00006470 bnx2_netif_stop(bp, true);
Michael Chanb6016b72005-05-26 13:03:09 -07006471
Michael Chanefdfad32012-07-16 14:25:56 +00006472 pci_read_config_word(bp->pdev, PCI_COMMAND, &pcicmd);
6473 if (!(pcicmd & PCI_COMMAND_MEMORY)) {
6474 /* in case PCI block has reset */
6475 pci_restore_state(bp->pdev);
6476 pci_save_state(bp->pdev);
6477 }
Michael Chancd634012011-07-15 06:53:58 +00006478 rc = bnx2_init_nic(bp, 1);
6479 if (rc) {
6480 netdev_err(bp->dev, "failed to reset NIC, closing\n");
6481 bnx2_napi_enable(bp);
6482 dev_close(bp->dev);
6483 rtnl_unlock();
6484 return;
6485 }
Michael Chanb6016b72005-05-26 13:03:09 -07006486
6487 atomic_set(&bp->intr_sem, 1);
Michael Chan212f9932010-04-27 11:28:10 +00006488 bnx2_netif_start(bp, true);
Michael Chan51bf6bb2009-12-03 09:46:31 +00006489 rtnl_unlock();
Michael Chanb6016b72005-05-26 13:03:09 -07006490}
6491
Michael Chan555069d2012-06-16 15:45:41 +00006492#define BNX2_FTQ_ENTRY(ftq) { __stringify(ftq##FTQ_CTL), BNX2_##ftq##FTQ_CTL }
6493
6494static void
6495bnx2_dump_ftq(struct bnx2 *bp)
6496{
6497 int i;
6498 u32 reg, bdidx, cid, valid;
6499 struct net_device *dev = bp->dev;
6500 static const struct ftq_reg {
6501 char *name;
6502 u32 off;
6503 } ftq_arr[] = {
6504 BNX2_FTQ_ENTRY(RV2P_P),
6505 BNX2_FTQ_ENTRY(RV2P_T),
6506 BNX2_FTQ_ENTRY(RV2P_M),
6507 BNX2_FTQ_ENTRY(TBDR_),
6508 BNX2_FTQ_ENTRY(TDMA_),
6509 BNX2_FTQ_ENTRY(TXP_),
6510 BNX2_FTQ_ENTRY(TXP_),
6511 BNX2_FTQ_ENTRY(TPAT_),
6512 BNX2_FTQ_ENTRY(RXP_C),
6513 BNX2_FTQ_ENTRY(RXP_),
6514 BNX2_FTQ_ENTRY(COM_COMXQ_),
6515 BNX2_FTQ_ENTRY(COM_COMTQ_),
6516 BNX2_FTQ_ENTRY(COM_COMQ_),
6517 BNX2_FTQ_ENTRY(CP_CPQ_),
6518 };
6519
6520 netdev_err(dev, "<--- start FTQ dump --->\n");
6521 for (i = 0; i < ARRAY_SIZE(ftq_arr); i++)
6522 netdev_err(dev, "%s %08x\n", ftq_arr[i].name,
6523 bnx2_reg_rd_ind(bp, ftq_arr[i].off));
6524
6525 netdev_err(dev, "CPU states:\n");
6526 for (reg = BNX2_TXP_CPU_MODE; reg <= BNX2_CP_CPU_MODE; reg += 0x40000)
6527 netdev_err(dev, "%06x mode %x state %x evt_mask %x pc %x pc %x instr %x\n",
6528 reg, bnx2_reg_rd_ind(bp, reg),
6529 bnx2_reg_rd_ind(bp, reg + 4),
6530 bnx2_reg_rd_ind(bp, reg + 8),
6531 bnx2_reg_rd_ind(bp, reg + 0x1c),
6532 bnx2_reg_rd_ind(bp, reg + 0x1c),
6533 bnx2_reg_rd_ind(bp, reg + 0x20));
6534
6535 netdev_err(dev, "<--- end FTQ dump --->\n");
6536 netdev_err(dev, "<--- start TBDC dump --->\n");
6537 netdev_err(dev, "TBDC free cnt: %ld\n",
Michael Chane503e062012-12-06 10:33:08 +00006538 BNX2_RD(bp, BNX2_TBDC_STATUS) & BNX2_TBDC_STATUS_FREE_CNT);
Michael Chan555069d2012-06-16 15:45:41 +00006539 netdev_err(dev, "LINE CID BIDX CMD VALIDS\n");
6540 for (i = 0; i < 0x20; i++) {
6541 int j = 0;
6542
Michael Chane503e062012-12-06 10:33:08 +00006543 BNX2_WR(bp, BNX2_TBDC_BD_ADDR, i);
6544 BNX2_WR(bp, BNX2_TBDC_CAM_OPCODE,
6545 BNX2_TBDC_CAM_OPCODE_OPCODE_CAM_READ);
6546 BNX2_WR(bp, BNX2_TBDC_COMMAND, BNX2_TBDC_COMMAND_CMD_REG_ARB);
6547 while ((BNX2_RD(bp, BNX2_TBDC_COMMAND) &
Michael Chan555069d2012-06-16 15:45:41 +00006548 BNX2_TBDC_COMMAND_CMD_REG_ARB) && j < 100)
6549 j++;
6550
Michael Chane503e062012-12-06 10:33:08 +00006551 cid = BNX2_RD(bp, BNX2_TBDC_CID);
6552 bdidx = BNX2_RD(bp, BNX2_TBDC_BIDX);
6553 valid = BNX2_RD(bp, BNX2_TBDC_CAM_OPCODE);
Michael Chan555069d2012-06-16 15:45:41 +00006554 netdev_err(dev, "%02x %06x %04lx %02x [%x]\n",
6555 i, cid, bdidx & BNX2_TBDC_BDIDX_BDIDX,
6556 bdidx >> 24, (valid >> 8) & 0x0ff);
6557 }
6558 netdev_err(dev, "<--- end TBDC dump --->\n");
6559}
6560
Michael Chanb6016b72005-05-26 13:03:09 -07006561static void
Michael Chan20175c52009-12-03 09:46:32 +00006562bnx2_dump_state(struct bnx2 *bp)
6563{
6564 struct net_device *dev = bp->dev;
Jeffrey Huangecdbf6e2011-07-13 17:24:21 +00006565 u32 val1, val2;
Michael Chan20175c52009-12-03 09:46:32 +00006566
Michael Chan5804a8f2010-07-03 20:42:17 +00006567 pci_read_config_dword(bp->pdev, PCI_COMMAND, &val1);
6568 netdev_err(dev, "DEBUG: intr_sem[%x] PCI_CMD[%08x]\n",
6569 atomic_read(&bp->intr_sem), val1);
6570 pci_read_config_dword(bp->pdev, bp->pm_cap + PCI_PM_CTRL, &val1);
6571 pci_read_config_dword(bp->pdev, BNX2_PCICFG_MISC_CONFIG, &val2);
6572 netdev_err(dev, "DEBUG: PCI_PM[%08x] PCI_MISC_CFG[%08x]\n", val1, val2);
Eddie Waib98eba52010-05-17 17:32:56 -07006573 netdev_err(dev, "DEBUG: EMAC_TX_STATUS[%08x] EMAC_RX_STATUS[%08x]\n",
Michael Chane503e062012-12-06 10:33:08 +00006574 BNX2_RD(bp, BNX2_EMAC_TX_STATUS),
6575 BNX2_RD(bp, BNX2_EMAC_RX_STATUS));
Eddie Waib98eba52010-05-17 17:32:56 -07006576 netdev_err(dev, "DEBUG: RPM_MGMT_PKT_CTRL[%08x]\n",
Michael Chane503e062012-12-06 10:33:08 +00006577 BNX2_RD(bp, BNX2_RPM_MGMT_PKT_CTRL));
Joe Perches3a9c6a42010-02-17 15:01:51 +00006578 netdev_err(dev, "DEBUG: HC_STATS_INTERRUPT_STATUS[%08x]\n",
Michael Chane503e062012-12-06 10:33:08 +00006579 BNX2_RD(bp, BNX2_HC_STATS_INTERRUPT_STATUS));
Michael Chan20175c52009-12-03 09:46:32 +00006580 if (bp->flags & BNX2_FLAG_USING_MSIX)
Joe Perches3a9c6a42010-02-17 15:01:51 +00006581 netdev_err(dev, "DEBUG: PBA[%08x]\n",
Michael Chane503e062012-12-06 10:33:08 +00006582 BNX2_RD(bp, BNX2_PCI_GRC_WINDOW3_BASE));
Michael Chan20175c52009-12-03 09:46:32 +00006583}
6584
6585static void
Michael Chanb6016b72005-05-26 13:03:09 -07006586bnx2_tx_timeout(struct net_device *dev)
6587{
Michael Chan972ec0d2006-01-23 16:12:43 -08006588 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006589
Michael Chan555069d2012-06-16 15:45:41 +00006590 bnx2_dump_ftq(bp);
Michael Chan20175c52009-12-03 09:46:32 +00006591 bnx2_dump_state(bp);
Jeffrey Huangecdbf6e2011-07-13 17:24:21 +00006592 bnx2_dump_mcp_state(bp);
Michael Chan20175c52009-12-03 09:46:32 +00006593
Michael Chanb6016b72005-05-26 13:03:09 -07006594 /* This allows the netif to be shutdown gracefully before resetting */
6595 schedule_work(&bp->reset_task);
6596}
6597
Herbert Xu932ff272006-06-09 12:20:56 -07006598/* Called with netif_tx_lock.
Michael Chan2f8af122006-08-15 01:39:10 -07006599 * bnx2_tx_int() runs without netif_tx_lock unless it needs to call
6600 * netif_wake_queue().
Michael Chanb6016b72005-05-26 13:03:09 -07006601 */
Stephen Hemminger613573252009-08-31 19:50:58 +00006602static netdev_tx_t
Michael Chanb6016b72005-05-26 13:03:09 -07006603bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev)
6604{
Michael Chan972ec0d2006-01-23 16:12:43 -08006605 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006606 dma_addr_t mapping;
Michael Chan2bc40782012-12-06 10:33:09 +00006607 struct bnx2_tx_bd *txbd;
6608 struct bnx2_sw_tx_bd *tx_buf;
Michael Chanb6016b72005-05-26 13:03:09 -07006609 u32 len, vlan_tag_flags, last_frag, mss;
6610 u16 prod, ring_prod;
6611 int i;
Benjamin Li706bf242008-07-18 17:55:11 -07006612 struct bnx2_napi *bnapi;
6613 struct bnx2_tx_ring_info *txr;
6614 struct netdev_queue *txq;
6615
6616 /* Determine which tx ring we will be placed on */
6617 i = skb_get_queue_mapping(skb);
6618 bnapi = &bp->bnx2_napi[i];
6619 txr = &bnapi->tx_ring;
6620 txq = netdev_get_tx_queue(dev, i);
Michael Chanb6016b72005-05-26 13:03:09 -07006621
Michael Chan35e90102008-06-19 16:37:42 -07006622 if (unlikely(bnx2_tx_avail(bp, txr) <
Michael Chana550c992007-12-20 19:56:59 -08006623 (skb_shinfo(skb)->nr_frags + 1))) {
Benjamin Li706bf242008-07-18 17:55:11 -07006624 netif_tx_stop_queue(txq);
Joe Perches3a9c6a42010-02-17 15:01:51 +00006625 netdev_err(dev, "BUG! Tx ring full when queue awake!\n");
Michael Chanb6016b72005-05-26 13:03:09 -07006626
6627 return NETDEV_TX_BUSY;
6628 }
6629 len = skb_headlen(skb);
Michael Chan35e90102008-06-19 16:37:42 -07006630 prod = txr->tx_prod;
Michael Chan2bc40782012-12-06 10:33:09 +00006631 ring_prod = BNX2_TX_RING_IDX(prod);
Michael Chanb6016b72005-05-26 13:03:09 -07006632
6633 vlan_tag_flags = 0;
Patrick McHardy84fa7932006-08-29 16:44:56 -07006634 if (skb->ip_summed == CHECKSUM_PARTIAL) {
Michael Chanb6016b72005-05-26 13:03:09 -07006635 vlan_tag_flags |= TX_BD_FLAGS_TCP_UDP_CKSUM;
6636 }
6637
Jiri Pirkodf8a39d2015-01-13 17:13:44 +01006638 if (skb_vlan_tag_present(skb)) {
Michael Chanb6016b72005-05-26 13:03:09 -07006639 vlan_tag_flags |=
Jiri Pirkodf8a39d2015-01-13 17:13:44 +01006640 (TX_BD_FLAGS_VLAN_TAG | (skb_vlan_tag_get(skb) << 16));
Michael Chanb6016b72005-05-26 13:03:09 -07006641 }
Jesse Gross7d0fd212010-10-20 13:56:09 +00006642
Michael Chanfde82052007-05-03 17:23:35 -07006643 if ((mss = skb_shinfo(skb)->gso_size)) {
Michael Chana1efb4b2008-10-09 12:24:39 -07006644 u32 tcp_opt_len;
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -07006645 struct iphdr *iph;
Michael Chanb6016b72005-05-26 13:03:09 -07006646
Michael Chanb6016b72005-05-26 13:03:09 -07006647 vlan_tag_flags |= TX_BD_FLAGS_SW_LSO;
6648
Michael Chan4666f872007-05-03 13:22:28 -07006649 tcp_opt_len = tcp_optlen(skb);
Arnaldo Carvalho de Meloab6a5bb2007-03-18 17:43:48 -07006650
Michael Chan4666f872007-05-03 13:22:28 -07006651 if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6) {
6652 u32 tcp_off = skb_transport_offset(skb) -
6653 sizeof(struct ipv6hdr) - ETH_HLEN;
Michael Chanb6016b72005-05-26 13:03:09 -07006654
Michael Chan4666f872007-05-03 13:22:28 -07006655 vlan_tag_flags |= ((tcp_opt_len >> 2) << 8) |
6656 TX_BD_FLAGS_SW_FLAGS;
6657 if (likely(tcp_off == 0))
6658 vlan_tag_flags &= ~TX_BD_FLAGS_TCP6_OFF0_MSK;
6659 else {
6660 tcp_off >>= 3;
6661 vlan_tag_flags |= ((tcp_off & 0x3) <<
6662 TX_BD_FLAGS_TCP6_OFF0_SHL) |
6663 ((tcp_off & 0x10) <<
6664 TX_BD_FLAGS_TCP6_OFF4_SHL);
6665 mss |= (tcp_off & 0xc) << TX_BD_TCP6_OFF2_SHL;
6666 }
6667 } else {
Michael Chan4666f872007-05-03 13:22:28 -07006668 iph = ip_hdr(skb);
Michael Chan4666f872007-05-03 13:22:28 -07006669 if (tcp_opt_len || (iph->ihl > 5)) {
6670 vlan_tag_flags |= ((iph->ihl - 5) +
6671 (tcp_opt_len >> 2)) << 8;
6672 }
Michael Chanb6016b72005-05-26 13:03:09 -07006673 }
Michael Chan4666f872007-05-03 13:22:28 -07006674 } else
Michael Chanb6016b72005-05-26 13:03:09 -07006675 mss = 0;
Michael Chanb6016b72005-05-26 13:03:09 -07006676
Stanislaw Gruszka36227e82010-07-15 04:25:50 +00006677 mapping = dma_map_single(&bp->pdev->dev, skb->data, len, PCI_DMA_TODEVICE);
6678 if (dma_mapping_error(&bp->pdev->dev, mapping)) {
Eric W. Biedermanf458b2e2014-03-11 14:17:41 -07006679 dev_kfree_skb_any(skb);
Benjamin Li3d16af82008-10-09 12:26:41 -07006680 return NETDEV_TX_OK;
6681 }
6682
Michael Chan35e90102008-06-19 16:37:42 -07006683 tx_buf = &txr->tx_buf_ring[ring_prod];
Michael Chanb6016b72005-05-26 13:03:09 -07006684 tx_buf->skb = skb;
FUJITA Tomonori1a4ccc22010-04-01 16:56:57 +00006685 dma_unmap_addr_set(tx_buf, mapping, mapping);
Michael Chanb6016b72005-05-26 13:03:09 -07006686
Michael Chan35e90102008-06-19 16:37:42 -07006687 txbd = &txr->tx_desc_ring[ring_prod];
Michael Chanb6016b72005-05-26 13:03:09 -07006688
6689 txbd->tx_bd_haddr_hi = (u64) mapping >> 32;
6690 txbd->tx_bd_haddr_lo = (u64) mapping & 0xffffffff;
6691 txbd->tx_bd_mss_nbytes = len | (mss << 16);
6692 txbd->tx_bd_vlan_tag_flags = vlan_tag_flags | TX_BD_FLAGS_START;
6693
6694 last_frag = skb_shinfo(skb)->nr_frags;
Eric Dumazetd62fda02009-05-12 20:48:02 +00006695 tx_buf->nr_frags = last_frag;
6696 tx_buf->is_gso = skb_is_gso(skb);
Michael Chanb6016b72005-05-26 13:03:09 -07006697
6698 for (i = 0; i < last_frag; i++) {
Eric Dumazet9e903e02011-10-18 21:00:24 +00006699 const skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
Michael Chanb6016b72005-05-26 13:03:09 -07006700
Michael Chan2bc40782012-12-06 10:33:09 +00006701 prod = BNX2_NEXT_TX_BD(prod);
6702 ring_prod = BNX2_TX_RING_IDX(prod);
Michael Chan35e90102008-06-19 16:37:42 -07006703 txbd = &txr->tx_desc_ring[ring_prod];
Michael Chanb6016b72005-05-26 13:03:09 -07006704
Eric Dumazet9e903e02011-10-18 21:00:24 +00006705 len = skb_frag_size(frag);
Ian Campbellb7b6a682011-08-24 22:28:12 +00006706 mapping = skb_frag_dma_map(&bp->pdev->dev, frag, 0, len,
Ian Campbell5d6bcdf2011-10-06 11:10:48 +01006707 DMA_TO_DEVICE);
Stanislaw Gruszka36227e82010-07-15 04:25:50 +00006708 if (dma_mapping_error(&bp->pdev->dev, mapping))
Alexander Duycke95524a2009-12-02 16:47:57 +00006709 goto dma_error;
FUJITA Tomonori1a4ccc22010-04-01 16:56:57 +00006710 dma_unmap_addr_set(&txr->tx_buf_ring[ring_prod], mapping,
Alexander Duycke95524a2009-12-02 16:47:57 +00006711 mapping);
Michael Chanb6016b72005-05-26 13:03:09 -07006712
6713 txbd->tx_bd_haddr_hi = (u64) mapping >> 32;
6714 txbd->tx_bd_haddr_lo = (u64) mapping & 0xffffffff;
6715 txbd->tx_bd_mss_nbytes = len | (mss << 16);
6716 txbd->tx_bd_vlan_tag_flags = vlan_tag_flags;
6717
6718 }
6719 txbd->tx_bd_vlan_tag_flags |= TX_BD_FLAGS_END;
6720
Vlad Zolotarov94bf91b2012-02-05 15:24:39 +00006721 /* Sync BD data before updating TX mailbox */
6722 wmb();
6723
Eric Dumazete9831902011-11-29 11:53:05 +00006724 netdev_tx_sent_queue(txq, skb->len);
6725
Michael Chan2bc40782012-12-06 10:33:09 +00006726 prod = BNX2_NEXT_TX_BD(prod);
Michael Chan35e90102008-06-19 16:37:42 -07006727 txr->tx_prod_bseq += skb->len;
Michael Chanb6016b72005-05-26 13:03:09 -07006728
Michael Chane503e062012-12-06 10:33:08 +00006729 BNX2_WR16(bp, txr->tx_bidx_addr, prod);
6730 BNX2_WR(bp, txr->tx_bseq_addr, txr->tx_prod_bseq);
Michael Chanb6016b72005-05-26 13:03:09 -07006731
6732 mmiowb();
6733
Michael Chan35e90102008-06-19 16:37:42 -07006734 txr->tx_prod = prod;
Michael Chanb6016b72005-05-26 13:03:09 -07006735
Michael Chan35e90102008-06-19 16:37:42 -07006736 if (unlikely(bnx2_tx_avail(bp, txr) <= MAX_SKB_FRAGS)) {
Benjamin Li706bf242008-07-18 17:55:11 -07006737 netif_tx_stop_queue(txq);
Michael Chan11848b962010-07-19 14:15:04 +00006738
6739 /* netif_tx_stop_queue() must be done before checking
6740 * tx index in bnx2_tx_avail() below, because in
6741 * bnx2_tx_int(), we update tx index before checking for
6742 * netif_tx_queue_stopped().
6743 */
6744 smp_mb();
Michael Chan35e90102008-06-19 16:37:42 -07006745 if (bnx2_tx_avail(bp, txr) > bp->tx_wake_thresh)
Benjamin Li706bf242008-07-18 17:55:11 -07006746 netif_tx_wake_queue(txq);
Michael Chanb6016b72005-05-26 13:03:09 -07006747 }
6748
6749 return NETDEV_TX_OK;
Alexander Duycke95524a2009-12-02 16:47:57 +00006750dma_error:
6751 /* save value of frag that failed */
6752 last_frag = i;
6753
6754 /* start back at beginning and unmap skb */
6755 prod = txr->tx_prod;
Michael Chan2bc40782012-12-06 10:33:09 +00006756 ring_prod = BNX2_TX_RING_IDX(prod);
Alexander Duycke95524a2009-12-02 16:47:57 +00006757 tx_buf = &txr->tx_buf_ring[ring_prod];
6758 tx_buf->skb = NULL;
Stanislaw Gruszka36227e82010-07-15 04:25:50 +00006759 dma_unmap_single(&bp->pdev->dev, dma_unmap_addr(tx_buf, mapping),
Alexander Duycke95524a2009-12-02 16:47:57 +00006760 skb_headlen(skb), PCI_DMA_TODEVICE);
6761
6762 /* unmap remaining mapped pages */
6763 for (i = 0; i < last_frag; i++) {
Michael Chan2bc40782012-12-06 10:33:09 +00006764 prod = BNX2_NEXT_TX_BD(prod);
6765 ring_prod = BNX2_TX_RING_IDX(prod);
Alexander Duycke95524a2009-12-02 16:47:57 +00006766 tx_buf = &txr->tx_buf_ring[ring_prod];
Stanislaw Gruszka36227e82010-07-15 04:25:50 +00006767 dma_unmap_page(&bp->pdev->dev, dma_unmap_addr(tx_buf, mapping),
Eric Dumazet9e903e02011-10-18 21:00:24 +00006768 skb_frag_size(&skb_shinfo(skb)->frags[i]),
Alexander Duycke95524a2009-12-02 16:47:57 +00006769 PCI_DMA_TODEVICE);
6770 }
6771
Eric W. Biedermanf458b2e2014-03-11 14:17:41 -07006772 dev_kfree_skb_any(skb);
Alexander Duycke95524a2009-12-02 16:47:57 +00006773 return NETDEV_TX_OK;
Michael Chanb6016b72005-05-26 13:03:09 -07006774}
6775
6776/* Called with rtnl_lock */
6777static int
6778bnx2_close(struct net_device *dev)
6779{
Michael Chan972ec0d2006-01-23 16:12:43 -08006780 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006781
Stephen Hemmingerbea33482007-10-03 16:41:36 -07006782 bnx2_disable_int_sync(bp);
Michael Chan35efa7c2007-12-20 19:56:37 -08006783 bnx2_napi_disable(bp);
Michael Chand2e553b2012-06-27 15:08:24 +00006784 netif_tx_disable(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006785 del_timer_sync(&bp->timer);
Michael Chan74bf4ba2008-10-09 12:21:08 -07006786 bnx2_shutdown_chip(bp);
Michael Chan8e6a72c2007-05-03 13:24:48 -07006787 bnx2_free_irq(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07006788 bnx2_free_skbs(bp);
6789 bnx2_free_mem(bp);
Michael Chanf048fa92010-06-01 15:05:36 +00006790 bnx2_del_napi(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07006791 bp->link_up = 0;
6792 netif_carrier_off(bp->dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006793 return 0;
6794}
6795
Michael Chan354fcd72010-01-17 07:30:44 +00006796static void
6797bnx2_save_stats(struct bnx2 *bp)
6798{
6799 u32 *hw_stats = (u32 *) bp->stats_blk;
6800 u32 *temp_stats = (u32 *) bp->temp_stats_blk;
6801 int i;
6802
6803 /* The 1st 10 counters are 64-bit counters */
6804 for (i = 0; i < 20; i += 2) {
6805 u32 hi;
6806 u64 lo;
6807
Patrick Rabauc9885fe2010-02-15 19:42:11 +00006808 hi = temp_stats[i] + hw_stats[i];
6809 lo = (u64) temp_stats[i + 1] + (u64) hw_stats[i + 1];
Michael Chan354fcd72010-01-17 07:30:44 +00006810 if (lo > 0xffffffff)
6811 hi++;
Patrick Rabauc9885fe2010-02-15 19:42:11 +00006812 temp_stats[i] = hi;
6813 temp_stats[i + 1] = lo & 0xffffffff;
Michael Chan354fcd72010-01-17 07:30:44 +00006814 }
6815
6816 for ( ; i < sizeof(struct statistics_block) / 4; i++)
Patrick Rabauc9885fe2010-02-15 19:42:11 +00006817 temp_stats[i] += hw_stats[i];
Michael Chan354fcd72010-01-17 07:30:44 +00006818}
6819
Eric Dumazet5d07bf22010-07-08 04:08:43 +00006820#define GET_64BIT_NET_STATS64(ctr) \
6821 (((u64) (ctr##_hi) << 32) + (u64) (ctr##_lo))
Michael Chanb6016b72005-05-26 13:03:09 -07006822
Michael Chana4743052010-01-17 07:30:43 +00006823#define GET_64BIT_NET_STATS(ctr) \
Michael Chan354fcd72010-01-17 07:30:44 +00006824 GET_64BIT_NET_STATS64(bp->stats_blk->ctr) + \
6825 GET_64BIT_NET_STATS64(bp->temp_stats_blk->ctr)
Michael Chanb6016b72005-05-26 13:03:09 -07006826
Michael Chana4743052010-01-17 07:30:43 +00006827#define GET_32BIT_NET_STATS(ctr) \
Michael Chan354fcd72010-01-17 07:30:44 +00006828 (unsigned long) (bp->stats_blk->ctr + \
6829 bp->temp_stats_blk->ctr)
Michael Chana4743052010-01-17 07:30:43 +00006830
Eric Dumazet5d07bf22010-07-08 04:08:43 +00006831static struct rtnl_link_stats64 *
6832bnx2_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *net_stats)
Michael Chanb6016b72005-05-26 13:03:09 -07006833{
Michael Chan972ec0d2006-01-23 16:12:43 -08006834 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006835
Eric Dumazet5d07bf22010-07-08 04:08:43 +00006836 if (bp->stats_blk == NULL)
Michael Chanb6016b72005-05-26 13:03:09 -07006837 return net_stats;
Eric Dumazet5d07bf22010-07-08 04:08:43 +00006838
Michael Chanb6016b72005-05-26 13:03:09 -07006839 net_stats->rx_packets =
Michael Chana4743052010-01-17 07:30:43 +00006840 GET_64BIT_NET_STATS(stat_IfHCInUcastPkts) +
6841 GET_64BIT_NET_STATS(stat_IfHCInMulticastPkts) +
6842 GET_64BIT_NET_STATS(stat_IfHCInBroadcastPkts);
Michael Chanb6016b72005-05-26 13:03:09 -07006843
6844 net_stats->tx_packets =
Michael Chana4743052010-01-17 07:30:43 +00006845 GET_64BIT_NET_STATS(stat_IfHCOutUcastPkts) +
6846 GET_64BIT_NET_STATS(stat_IfHCOutMulticastPkts) +
6847 GET_64BIT_NET_STATS(stat_IfHCOutBroadcastPkts);
Michael Chanb6016b72005-05-26 13:03:09 -07006848
6849 net_stats->rx_bytes =
Michael Chana4743052010-01-17 07:30:43 +00006850 GET_64BIT_NET_STATS(stat_IfHCInOctets);
Michael Chanb6016b72005-05-26 13:03:09 -07006851
6852 net_stats->tx_bytes =
Michael Chana4743052010-01-17 07:30:43 +00006853 GET_64BIT_NET_STATS(stat_IfHCOutOctets);
Michael Chanb6016b72005-05-26 13:03:09 -07006854
Jeff Garzik6aa20a22006-09-13 13:24:59 -04006855 net_stats->multicast =
Michael Chan6fdae992010-07-19 14:15:02 +00006856 GET_64BIT_NET_STATS(stat_IfHCInMulticastPkts);
Michael Chanb6016b72005-05-26 13:03:09 -07006857
Jeff Garzik6aa20a22006-09-13 13:24:59 -04006858 net_stats->collisions =
Michael Chana4743052010-01-17 07:30:43 +00006859 GET_32BIT_NET_STATS(stat_EtherStatsCollisions);
Michael Chanb6016b72005-05-26 13:03:09 -07006860
Jeff Garzik6aa20a22006-09-13 13:24:59 -04006861 net_stats->rx_length_errors =
Michael Chana4743052010-01-17 07:30:43 +00006862 GET_32BIT_NET_STATS(stat_EtherStatsUndersizePkts) +
6863 GET_32BIT_NET_STATS(stat_EtherStatsOverrsizePkts);
Michael Chanb6016b72005-05-26 13:03:09 -07006864
Jeff Garzik6aa20a22006-09-13 13:24:59 -04006865 net_stats->rx_over_errors =
Michael Chana4743052010-01-17 07:30:43 +00006866 GET_32BIT_NET_STATS(stat_IfInFTQDiscards) +
6867 GET_32BIT_NET_STATS(stat_IfInMBUFDiscards);
Michael Chanb6016b72005-05-26 13:03:09 -07006868
Jeff Garzik6aa20a22006-09-13 13:24:59 -04006869 net_stats->rx_frame_errors =
Michael Chana4743052010-01-17 07:30:43 +00006870 GET_32BIT_NET_STATS(stat_Dot3StatsAlignmentErrors);
Michael Chanb6016b72005-05-26 13:03:09 -07006871
Jeff Garzik6aa20a22006-09-13 13:24:59 -04006872 net_stats->rx_crc_errors =
Michael Chana4743052010-01-17 07:30:43 +00006873 GET_32BIT_NET_STATS(stat_Dot3StatsFCSErrors);
Michael Chanb6016b72005-05-26 13:03:09 -07006874
6875 net_stats->rx_errors = net_stats->rx_length_errors +
6876 net_stats->rx_over_errors + net_stats->rx_frame_errors +
6877 net_stats->rx_crc_errors;
6878
6879 net_stats->tx_aborted_errors =
Michael Chana4743052010-01-17 07:30:43 +00006880 GET_32BIT_NET_STATS(stat_Dot3StatsExcessiveCollisions) +
6881 GET_32BIT_NET_STATS(stat_Dot3StatsLateCollisions);
Michael Chanb6016b72005-05-26 13:03:09 -07006882
Michael Chan4ce45e02012-12-06 10:33:10 +00006883 if ((BNX2_CHIP(bp) == BNX2_CHIP_5706) ||
6884 (BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5708_A0))
Michael Chanb6016b72005-05-26 13:03:09 -07006885 net_stats->tx_carrier_errors = 0;
6886 else {
6887 net_stats->tx_carrier_errors =
Michael Chana4743052010-01-17 07:30:43 +00006888 GET_32BIT_NET_STATS(stat_Dot3StatsCarrierSenseErrors);
Michael Chanb6016b72005-05-26 13:03:09 -07006889 }
6890
6891 net_stats->tx_errors =
Michael Chana4743052010-01-17 07:30:43 +00006892 GET_32BIT_NET_STATS(stat_emac_tx_stat_dot3statsinternalmactransmiterrors) +
Michael Chanb6016b72005-05-26 13:03:09 -07006893 net_stats->tx_aborted_errors +
6894 net_stats->tx_carrier_errors;
6895
Michael Chancea94db2006-06-12 22:16:13 -07006896 net_stats->rx_missed_errors =
Michael Chana4743052010-01-17 07:30:43 +00006897 GET_32BIT_NET_STATS(stat_IfInFTQDiscards) +
6898 GET_32BIT_NET_STATS(stat_IfInMBUFDiscards) +
6899 GET_32BIT_NET_STATS(stat_FwRxDrop);
Michael Chancea94db2006-06-12 22:16:13 -07006900
Michael Chanb6016b72005-05-26 13:03:09 -07006901 return net_stats;
6902}
6903
6904/* All ethtool functions called with rtnl_lock */
6905
6906static int
6907bnx2_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
6908{
Michael Chan972ec0d2006-01-23 16:12:43 -08006909 struct bnx2 *bp = netdev_priv(dev);
Michael Chan7b6b8342007-07-07 22:50:15 -07006910 int support_serdes = 0, support_copper = 0;
Michael Chanb6016b72005-05-26 13:03:09 -07006911
6912 cmd->supported = SUPPORTED_Autoneg;
Michael Chan583c28e2008-01-21 19:51:35 -08006913 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP) {
Michael Chan7b6b8342007-07-07 22:50:15 -07006914 support_serdes = 1;
6915 support_copper = 1;
6916 } else if (bp->phy_port == PORT_FIBRE)
6917 support_serdes = 1;
6918 else
6919 support_copper = 1;
6920
6921 if (support_serdes) {
Michael Chanb6016b72005-05-26 13:03:09 -07006922 cmd->supported |= SUPPORTED_1000baseT_Full |
6923 SUPPORTED_FIBRE;
Michael Chan583c28e2008-01-21 19:51:35 -08006924 if (bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE)
Michael Chan605a9e22007-05-03 13:23:13 -07006925 cmd->supported |= SUPPORTED_2500baseX_Full;
Michael Chanb6016b72005-05-26 13:03:09 -07006926
Michael Chanb6016b72005-05-26 13:03:09 -07006927 }
Michael Chan7b6b8342007-07-07 22:50:15 -07006928 if (support_copper) {
Michael Chanb6016b72005-05-26 13:03:09 -07006929 cmd->supported |= SUPPORTED_10baseT_Half |
6930 SUPPORTED_10baseT_Full |
6931 SUPPORTED_100baseT_Half |
6932 SUPPORTED_100baseT_Full |
6933 SUPPORTED_1000baseT_Full |
6934 SUPPORTED_TP;
6935
Michael Chanb6016b72005-05-26 13:03:09 -07006936 }
6937
Michael Chan7b6b8342007-07-07 22:50:15 -07006938 spin_lock_bh(&bp->phy_lock);
6939 cmd->port = bp->phy_port;
Michael Chanb6016b72005-05-26 13:03:09 -07006940 cmd->advertising = bp->advertising;
6941
6942 if (bp->autoneg & AUTONEG_SPEED) {
6943 cmd->autoneg = AUTONEG_ENABLE;
David Decotigny70739492011-04-27 18:32:40 +00006944 } else {
Michael Chanb6016b72005-05-26 13:03:09 -07006945 cmd->autoneg = AUTONEG_DISABLE;
6946 }
6947
6948 if (netif_carrier_ok(dev)) {
David Decotigny70739492011-04-27 18:32:40 +00006949 ethtool_cmd_speed_set(cmd, bp->line_speed);
Michael Chanb6016b72005-05-26 13:03:09 -07006950 cmd->duplex = bp->duplex;
Michael Chan4016bad2013-12-31 23:22:34 -08006951 if (!(bp->phy_flags & BNX2_PHY_FLAG_SERDES)) {
6952 if (bp->phy_flags & BNX2_PHY_FLAG_MDIX)
6953 cmd->eth_tp_mdix = ETH_TP_MDI_X;
6954 else
6955 cmd->eth_tp_mdix = ETH_TP_MDI;
6956 }
Michael Chanb6016b72005-05-26 13:03:09 -07006957 }
6958 else {
Jiri Pirko537fae02014-06-06 14:17:00 +02006959 ethtool_cmd_speed_set(cmd, SPEED_UNKNOWN);
6960 cmd->duplex = DUPLEX_UNKNOWN;
Michael Chanb6016b72005-05-26 13:03:09 -07006961 }
Michael Chan7b6b8342007-07-07 22:50:15 -07006962 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07006963
6964 cmd->transceiver = XCVR_INTERNAL;
6965 cmd->phy_address = bp->phy_addr;
6966
6967 return 0;
6968}
Jeff Garzik6aa20a22006-09-13 13:24:59 -04006969
Michael Chanb6016b72005-05-26 13:03:09 -07006970static int
6971bnx2_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
6972{
Michael Chan972ec0d2006-01-23 16:12:43 -08006973 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006974 u8 autoneg = bp->autoneg;
6975 u8 req_duplex = bp->req_duplex;
6976 u16 req_line_speed = bp->req_line_speed;
6977 u32 advertising = bp->advertising;
Michael Chan7b6b8342007-07-07 22:50:15 -07006978 int err = -EINVAL;
6979
6980 spin_lock_bh(&bp->phy_lock);
6981
6982 if (cmd->port != PORT_TP && cmd->port != PORT_FIBRE)
6983 goto err_out_unlock;
6984
Michael Chan583c28e2008-01-21 19:51:35 -08006985 if (cmd->port != bp->phy_port &&
6986 !(bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP))
Michael Chan7b6b8342007-07-07 22:50:15 -07006987 goto err_out_unlock;
Michael Chanb6016b72005-05-26 13:03:09 -07006988
Michael Chand6b14482008-07-14 22:37:21 -07006989 /* If device is down, we can store the settings only if the user
6990 * is setting the currently active port.
6991 */
6992 if (!netif_running(dev) && cmd->port != bp->phy_port)
6993 goto err_out_unlock;
6994
Michael Chanb6016b72005-05-26 13:03:09 -07006995 if (cmd->autoneg == AUTONEG_ENABLE) {
6996 autoneg |= AUTONEG_SPEED;
6997
Michael Chanbeb499a2010-02-15 19:42:10 +00006998 advertising = cmd->advertising;
6999 if (cmd->port == PORT_TP) {
7000 advertising &= ETHTOOL_ALL_COPPER_SPEED;
7001 if (!advertising)
Michael Chanb6016b72005-05-26 13:03:09 -07007002 advertising = ETHTOOL_ALL_COPPER_SPEED;
Michael Chanbeb499a2010-02-15 19:42:10 +00007003 } else {
7004 advertising &= ETHTOOL_ALL_FIBRE_SPEED;
7005 if (!advertising)
7006 advertising = ETHTOOL_ALL_FIBRE_SPEED;
Michael Chanb6016b72005-05-26 13:03:09 -07007007 }
7008 advertising |= ADVERTISED_Autoneg;
7009 }
7010 else {
David Decotigny25db0332011-04-27 18:32:39 +00007011 u32 speed = ethtool_cmd_speed(cmd);
Michael Chan7b6b8342007-07-07 22:50:15 -07007012 if (cmd->port == PORT_FIBRE) {
David Decotigny25db0332011-04-27 18:32:39 +00007013 if ((speed != SPEED_1000 &&
7014 speed != SPEED_2500) ||
Michael Chan80be4432006-11-19 14:07:28 -08007015 (cmd->duplex != DUPLEX_FULL))
Michael Chan7b6b8342007-07-07 22:50:15 -07007016 goto err_out_unlock;
Michael Chan80be4432006-11-19 14:07:28 -08007017
David Decotigny25db0332011-04-27 18:32:39 +00007018 if (speed == SPEED_2500 &&
Michael Chan583c28e2008-01-21 19:51:35 -08007019 !(bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE))
Michael Chan7b6b8342007-07-07 22:50:15 -07007020 goto err_out_unlock;
David Decotigny25db0332011-04-27 18:32:39 +00007021 } else if (speed == SPEED_1000 || speed == SPEED_2500)
Michael Chan7b6b8342007-07-07 22:50:15 -07007022 goto err_out_unlock;
7023
Michael Chanb6016b72005-05-26 13:03:09 -07007024 autoneg &= ~AUTONEG_SPEED;
David Decotigny25db0332011-04-27 18:32:39 +00007025 req_line_speed = speed;
Michael Chanb6016b72005-05-26 13:03:09 -07007026 req_duplex = cmd->duplex;
7027 advertising = 0;
7028 }
7029
7030 bp->autoneg = autoneg;
7031 bp->advertising = advertising;
7032 bp->req_line_speed = req_line_speed;
7033 bp->req_duplex = req_duplex;
7034
Michael Chand6b14482008-07-14 22:37:21 -07007035 err = 0;
7036 /* If device is down, the new settings will be picked up when it is
7037 * brought up.
7038 */
7039 if (netif_running(dev))
7040 err = bnx2_setup_phy(bp, cmd->port);
Michael Chanb6016b72005-05-26 13:03:09 -07007041
Michael Chan7b6b8342007-07-07 22:50:15 -07007042err_out_unlock:
Michael Chanc770a652005-08-25 15:38:39 -07007043 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07007044
Michael Chan7b6b8342007-07-07 22:50:15 -07007045 return err;
Michael Chanb6016b72005-05-26 13:03:09 -07007046}
7047
7048static void
7049bnx2_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
7050{
Michael Chan972ec0d2006-01-23 16:12:43 -08007051 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007052
Rick Jones68aad782011-11-07 13:29:27 +00007053 strlcpy(info->driver, DRV_MODULE_NAME, sizeof(info->driver));
7054 strlcpy(info->version, DRV_MODULE_VERSION, sizeof(info->version));
7055 strlcpy(info->bus_info, pci_name(bp->pdev), sizeof(info->bus_info));
7056 strlcpy(info->fw_version, bp->fw_version, sizeof(info->fw_version));
Michael Chanb6016b72005-05-26 13:03:09 -07007057}
7058
Michael Chan244ac4f2006-03-20 17:48:46 -08007059#define BNX2_REGDUMP_LEN (32 * 1024)
7060
7061static int
7062bnx2_get_regs_len(struct net_device *dev)
7063{
7064 return BNX2_REGDUMP_LEN;
7065}
7066
7067static void
7068bnx2_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *_p)
7069{
7070 u32 *p = _p, i, offset;
7071 u8 *orig_p = _p;
7072 struct bnx2 *bp = netdev_priv(dev);
Joe Perchesb6bc7652010-12-21 02:16:08 -08007073 static const u32 reg_boundaries[] = {
7074 0x0000, 0x0098, 0x0400, 0x045c,
7075 0x0800, 0x0880, 0x0c00, 0x0c10,
7076 0x0c30, 0x0d08, 0x1000, 0x101c,
7077 0x1040, 0x1048, 0x1080, 0x10a4,
7078 0x1400, 0x1490, 0x1498, 0x14f0,
7079 0x1500, 0x155c, 0x1580, 0x15dc,
7080 0x1600, 0x1658, 0x1680, 0x16d8,
7081 0x1800, 0x1820, 0x1840, 0x1854,
7082 0x1880, 0x1894, 0x1900, 0x1984,
7083 0x1c00, 0x1c0c, 0x1c40, 0x1c54,
7084 0x1c80, 0x1c94, 0x1d00, 0x1d84,
7085 0x2000, 0x2030, 0x23c0, 0x2400,
7086 0x2800, 0x2820, 0x2830, 0x2850,
7087 0x2b40, 0x2c10, 0x2fc0, 0x3058,
7088 0x3c00, 0x3c94, 0x4000, 0x4010,
7089 0x4080, 0x4090, 0x43c0, 0x4458,
7090 0x4c00, 0x4c18, 0x4c40, 0x4c54,
7091 0x4fc0, 0x5010, 0x53c0, 0x5444,
7092 0x5c00, 0x5c18, 0x5c80, 0x5c90,
7093 0x5fc0, 0x6000, 0x6400, 0x6428,
7094 0x6800, 0x6848, 0x684c, 0x6860,
7095 0x6888, 0x6910, 0x8000
7096 };
Michael Chan244ac4f2006-03-20 17:48:46 -08007097
7098 regs->version = 0;
7099
7100 memset(p, 0, BNX2_REGDUMP_LEN);
7101
7102 if (!netif_running(bp->dev))
7103 return;
7104
7105 i = 0;
7106 offset = reg_boundaries[0];
7107 p += offset;
7108 while (offset < BNX2_REGDUMP_LEN) {
Michael Chane503e062012-12-06 10:33:08 +00007109 *p++ = BNX2_RD(bp, offset);
Michael Chan244ac4f2006-03-20 17:48:46 -08007110 offset += 4;
7111 if (offset == reg_boundaries[i + 1]) {
7112 offset = reg_boundaries[i + 2];
7113 p = (u32 *) (orig_p + offset);
7114 i += 2;
7115 }
7116 }
7117}
7118
Michael Chanb6016b72005-05-26 13:03:09 -07007119static void
7120bnx2_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
7121{
Michael Chan972ec0d2006-01-23 16:12:43 -08007122 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007123
David S. Millerf86e82f2008-01-21 17:15:40 -08007124 if (bp->flags & BNX2_FLAG_NO_WOL) {
Michael Chanb6016b72005-05-26 13:03:09 -07007125 wol->supported = 0;
7126 wol->wolopts = 0;
7127 }
7128 else {
7129 wol->supported = WAKE_MAGIC;
7130 if (bp->wol)
7131 wol->wolopts = WAKE_MAGIC;
7132 else
7133 wol->wolopts = 0;
7134 }
7135 memset(&wol->sopass, 0, sizeof(wol->sopass));
7136}
7137
7138static int
7139bnx2_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
7140{
Michael Chan972ec0d2006-01-23 16:12:43 -08007141 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007142
7143 if (wol->wolopts & ~WAKE_MAGIC)
7144 return -EINVAL;
7145
7146 if (wol->wolopts & WAKE_MAGIC) {
David S. Millerf86e82f2008-01-21 17:15:40 -08007147 if (bp->flags & BNX2_FLAG_NO_WOL)
Michael Chanb6016b72005-05-26 13:03:09 -07007148 return -EINVAL;
7149
7150 bp->wol = 1;
7151 }
7152 else {
7153 bp->wol = 0;
7154 }
Michael Chan6d5e85c2013-08-06 15:50:08 -07007155
7156 device_set_wakeup_enable(&bp->pdev->dev, bp->wol);
7157
Michael Chanb6016b72005-05-26 13:03:09 -07007158 return 0;
7159}
7160
7161static int
7162bnx2_nway_reset(struct net_device *dev)
7163{
Michael Chan972ec0d2006-01-23 16:12:43 -08007164 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007165 u32 bmcr;
7166
Michael Chan9f52b562008-10-09 12:21:46 -07007167 if (!netif_running(dev))
7168 return -EAGAIN;
7169
Michael Chanb6016b72005-05-26 13:03:09 -07007170 if (!(bp->autoneg & AUTONEG_SPEED)) {
7171 return -EINVAL;
7172 }
7173
Michael Chanc770a652005-08-25 15:38:39 -07007174 spin_lock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07007175
Michael Chan583c28e2008-01-21 19:51:35 -08007176 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP) {
Michael Chan7b6b8342007-07-07 22:50:15 -07007177 int rc;
7178
7179 rc = bnx2_setup_remote_phy(bp, bp->phy_port);
7180 spin_unlock_bh(&bp->phy_lock);
7181 return rc;
7182 }
7183
Michael Chanb6016b72005-05-26 13:03:09 -07007184 /* Force a link down visible on the other side */
Michael Chan583c28e2008-01-21 19:51:35 -08007185 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Michael Chanca58c3a2007-05-03 13:22:52 -07007186 bnx2_write_phy(bp, bp->mii_bmcr, BMCR_LOOPBACK);
Michael Chanc770a652005-08-25 15:38:39 -07007187 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07007188
7189 msleep(20);
7190
Michael Chanc770a652005-08-25 15:38:39 -07007191 spin_lock_bh(&bp->phy_lock);
Michael Chanf8dd0642006-11-19 14:08:29 -08007192
Michael Chan40105c02008-11-12 16:02:45 -08007193 bp->current_interval = BNX2_SERDES_AN_TIMEOUT;
Michael Chanf8dd0642006-11-19 14:08:29 -08007194 bp->serdes_an_pending = 1;
7195 mod_timer(&bp->timer, jiffies + bp->current_interval);
Michael Chanb6016b72005-05-26 13:03:09 -07007196 }
7197
Michael Chanca58c3a2007-05-03 13:22:52 -07007198 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chanb6016b72005-05-26 13:03:09 -07007199 bmcr &= ~BMCR_LOOPBACK;
Michael Chanca58c3a2007-05-03 13:22:52 -07007200 bnx2_write_phy(bp, bp->mii_bmcr, bmcr | BMCR_ANRESTART | BMCR_ANENABLE);
Michael Chanb6016b72005-05-26 13:03:09 -07007201
Michael Chanc770a652005-08-25 15:38:39 -07007202 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07007203
7204 return 0;
7205}
7206
Ooiwa Naohiro7959ea22009-06-24 00:19:06 -07007207static u32
7208bnx2_get_link(struct net_device *dev)
7209{
7210 struct bnx2 *bp = netdev_priv(dev);
7211
7212 return bp->link_up;
7213}
7214
Michael Chanb6016b72005-05-26 13:03:09 -07007215static int
7216bnx2_get_eeprom_len(struct net_device *dev)
7217{
Michael Chan972ec0d2006-01-23 16:12:43 -08007218 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007219
Michael Chan1122db72006-01-23 16:11:42 -08007220 if (bp->flash_info == NULL)
Michael Chanb6016b72005-05-26 13:03:09 -07007221 return 0;
7222
Michael Chan1122db72006-01-23 16:11:42 -08007223 return (int) bp->flash_size;
Michael Chanb6016b72005-05-26 13:03:09 -07007224}
7225
7226static int
7227bnx2_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
7228 u8 *eebuf)
7229{
Michael Chan972ec0d2006-01-23 16:12:43 -08007230 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007231 int rc;
7232
John W. Linville1064e942005-11-10 12:58:24 -08007233 /* parameters already validated in ethtool_get_eeprom */
Michael Chanb6016b72005-05-26 13:03:09 -07007234
7235 rc = bnx2_nvram_read(bp, eeprom->offset, eebuf, eeprom->len);
7236
7237 return rc;
7238}
7239
7240static int
7241bnx2_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
7242 u8 *eebuf)
7243{
Michael Chan972ec0d2006-01-23 16:12:43 -08007244 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007245 int rc;
7246
John W. Linville1064e942005-11-10 12:58:24 -08007247 /* parameters already validated in ethtool_set_eeprom */
Michael Chanb6016b72005-05-26 13:03:09 -07007248
7249 rc = bnx2_nvram_write(bp, eeprom->offset, eebuf, eeprom->len);
7250
7251 return rc;
7252}
7253
7254static int
7255bnx2_get_coalesce(struct net_device *dev, struct ethtool_coalesce *coal)
7256{
Michael Chan972ec0d2006-01-23 16:12:43 -08007257 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007258
7259 memset(coal, 0, sizeof(struct ethtool_coalesce));
7260
7261 coal->rx_coalesce_usecs = bp->rx_ticks;
7262 coal->rx_max_coalesced_frames = bp->rx_quick_cons_trip;
7263 coal->rx_coalesce_usecs_irq = bp->rx_ticks_int;
7264 coal->rx_max_coalesced_frames_irq = bp->rx_quick_cons_trip_int;
7265
7266 coal->tx_coalesce_usecs = bp->tx_ticks;
7267 coal->tx_max_coalesced_frames = bp->tx_quick_cons_trip;
7268 coal->tx_coalesce_usecs_irq = bp->tx_ticks_int;
7269 coal->tx_max_coalesced_frames_irq = bp->tx_quick_cons_trip_int;
7270
7271 coal->stats_block_coalesce_usecs = bp->stats_ticks;
7272
7273 return 0;
7274}
7275
7276static int
7277bnx2_set_coalesce(struct net_device *dev, struct ethtool_coalesce *coal)
7278{
Michael Chan972ec0d2006-01-23 16:12:43 -08007279 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007280
7281 bp->rx_ticks = (u16) coal->rx_coalesce_usecs;
7282 if (bp->rx_ticks > 0x3ff) bp->rx_ticks = 0x3ff;
7283
Jeff Garzik6aa20a22006-09-13 13:24:59 -04007284 bp->rx_quick_cons_trip = (u16) coal->rx_max_coalesced_frames;
Michael Chanb6016b72005-05-26 13:03:09 -07007285 if (bp->rx_quick_cons_trip > 0xff) bp->rx_quick_cons_trip = 0xff;
7286
7287 bp->rx_ticks_int = (u16) coal->rx_coalesce_usecs_irq;
7288 if (bp->rx_ticks_int > 0x3ff) bp->rx_ticks_int = 0x3ff;
7289
7290 bp->rx_quick_cons_trip_int = (u16) coal->rx_max_coalesced_frames_irq;
7291 if (bp->rx_quick_cons_trip_int > 0xff)
7292 bp->rx_quick_cons_trip_int = 0xff;
7293
7294 bp->tx_ticks = (u16) coal->tx_coalesce_usecs;
7295 if (bp->tx_ticks > 0x3ff) bp->tx_ticks = 0x3ff;
7296
7297 bp->tx_quick_cons_trip = (u16) coal->tx_max_coalesced_frames;
7298 if (bp->tx_quick_cons_trip > 0xff) bp->tx_quick_cons_trip = 0xff;
7299
7300 bp->tx_ticks_int = (u16) coal->tx_coalesce_usecs_irq;
7301 if (bp->tx_ticks_int > 0x3ff) bp->tx_ticks_int = 0x3ff;
7302
7303 bp->tx_quick_cons_trip_int = (u16) coal->tx_max_coalesced_frames_irq;
7304 if (bp->tx_quick_cons_trip_int > 0xff) bp->tx_quick_cons_trip_int =
7305 0xff;
7306
7307 bp->stats_ticks = coal->stats_block_coalesce_usecs;
Michael Chan61d9e3f2009-08-21 16:20:46 +00007308 if (bp->flags & BNX2_FLAG_BROKEN_STATS) {
Michael Chan02537b062007-06-04 21:24:07 -07007309 if (bp->stats_ticks != 0 && bp->stats_ticks != USEC_PER_SEC)
7310 bp->stats_ticks = USEC_PER_SEC;
7311 }
Michael Chan7ea69202007-07-16 18:27:10 -07007312 if (bp->stats_ticks > BNX2_HC_STATS_TICKS_HC_STAT_TICKS)
7313 bp->stats_ticks = BNX2_HC_STATS_TICKS_HC_STAT_TICKS;
7314 bp->stats_ticks &= BNX2_HC_STATS_TICKS_HC_STAT_TICKS;
Michael Chanb6016b72005-05-26 13:03:09 -07007315
7316 if (netif_running(bp->dev)) {
Michael Chan212f9932010-04-27 11:28:10 +00007317 bnx2_netif_stop(bp, true);
Michael Chan9a120bc2008-05-16 22:17:45 -07007318 bnx2_init_nic(bp, 0);
Michael Chan212f9932010-04-27 11:28:10 +00007319 bnx2_netif_start(bp, true);
Michael Chanb6016b72005-05-26 13:03:09 -07007320 }
7321
7322 return 0;
7323}
7324
7325static void
7326bnx2_get_ringparam(struct net_device *dev, struct ethtool_ringparam *ering)
7327{
Michael Chan972ec0d2006-01-23 16:12:43 -08007328 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007329
Michael Chan2bc40782012-12-06 10:33:09 +00007330 ering->rx_max_pending = BNX2_MAX_TOTAL_RX_DESC_CNT;
7331 ering->rx_jumbo_max_pending = BNX2_MAX_TOTAL_RX_PG_DESC_CNT;
Michael Chanb6016b72005-05-26 13:03:09 -07007332
7333 ering->rx_pending = bp->rx_ring_size;
Michael Chan47bf4242007-12-12 11:19:12 -08007334 ering->rx_jumbo_pending = bp->rx_pg_ring_size;
Michael Chanb6016b72005-05-26 13:03:09 -07007335
Michael Chan2bc40782012-12-06 10:33:09 +00007336 ering->tx_max_pending = BNX2_MAX_TX_DESC_CNT;
Michael Chanb6016b72005-05-26 13:03:09 -07007337 ering->tx_pending = bp->tx_ring_size;
7338}
7339
7340static int
Michael Chanb0332812012-02-05 15:24:38 +00007341bnx2_change_ring_size(struct bnx2 *bp, u32 rx, u32 tx, bool reset_irq)
Michael Chanb6016b72005-05-26 13:03:09 -07007342{
Michael Chan13daffa2006-03-20 17:49:20 -08007343 if (netif_running(bp->dev)) {
Michael Chan354fcd72010-01-17 07:30:44 +00007344 /* Reset will erase chipset stats; save them */
7345 bnx2_save_stats(bp);
7346
Michael Chan212f9932010-04-27 11:28:10 +00007347 bnx2_netif_stop(bp, true);
Michael Chan13daffa2006-03-20 17:49:20 -08007348 bnx2_reset_chip(bp, BNX2_DRV_MSG_CODE_RESET);
Michael Chanb0332812012-02-05 15:24:38 +00007349 if (reset_irq) {
7350 bnx2_free_irq(bp);
7351 bnx2_del_napi(bp);
7352 } else {
7353 __bnx2_free_irq(bp);
7354 }
Michael Chan13daffa2006-03-20 17:49:20 -08007355 bnx2_free_skbs(bp);
7356 bnx2_free_mem(bp);
7357 }
7358
Michael Chan5d5d0012007-12-12 11:17:43 -08007359 bnx2_set_rx_ring_size(bp, rx);
7360 bp->tx_ring_size = tx;
Michael Chanb6016b72005-05-26 13:03:09 -07007361
7362 if (netif_running(bp->dev)) {
Michael Chanb0332812012-02-05 15:24:38 +00007363 int rc = 0;
Michael Chan13daffa2006-03-20 17:49:20 -08007364
Michael Chanb0332812012-02-05 15:24:38 +00007365 if (reset_irq) {
7366 rc = bnx2_setup_int_mode(bp, disable_msi);
7367 bnx2_init_napi(bp);
7368 }
7369
7370 if (!rc)
7371 rc = bnx2_alloc_mem(bp);
7372
Michael Chan6fefb65e2009-08-21 16:20:45 +00007373 if (!rc)
Michael Chana29ba9d2010-12-31 11:03:14 -08007374 rc = bnx2_request_irq(bp);
7375
7376 if (!rc)
Michael Chan6fefb65e2009-08-21 16:20:45 +00007377 rc = bnx2_init_nic(bp, 0);
7378
7379 if (rc) {
7380 bnx2_napi_enable(bp);
7381 dev_close(bp->dev);
Michael Chan13daffa2006-03-20 17:49:20 -08007382 return rc;
Michael Chan6fefb65e2009-08-21 16:20:45 +00007383 }
Michael Chane9f26c42010-02-15 19:42:08 +00007384#ifdef BCM_CNIC
7385 mutex_lock(&bp->cnic_lock);
7386 /* Let cnic know about the new status block. */
7387 if (bp->cnic_eth_dev.drv_state & CNIC_DRV_STATE_REGD)
7388 bnx2_setup_cnic_irq_info(bp);
7389 mutex_unlock(&bp->cnic_lock);
7390#endif
Michael Chan212f9932010-04-27 11:28:10 +00007391 bnx2_netif_start(bp, true);
Michael Chanb6016b72005-05-26 13:03:09 -07007392 }
Michael Chanb6016b72005-05-26 13:03:09 -07007393 return 0;
7394}
7395
Michael Chan5d5d0012007-12-12 11:17:43 -08007396static int
7397bnx2_set_ringparam(struct net_device *dev, struct ethtool_ringparam *ering)
7398{
7399 struct bnx2 *bp = netdev_priv(dev);
7400 int rc;
7401
Michael Chan2bc40782012-12-06 10:33:09 +00007402 if ((ering->rx_pending > BNX2_MAX_TOTAL_RX_DESC_CNT) ||
7403 (ering->tx_pending > BNX2_MAX_TX_DESC_CNT) ||
Michael Chan5d5d0012007-12-12 11:17:43 -08007404 (ering->tx_pending <= MAX_SKB_FRAGS)) {
7405
7406 return -EINVAL;
7407 }
Michael Chanb0332812012-02-05 15:24:38 +00007408 rc = bnx2_change_ring_size(bp, ering->rx_pending, ering->tx_pending,
7409 false);
Michael Chan5d5d0012007-12-12 11:17:43 -08007410 return rc;
7411}
7412
Michael Chanb6016b72005-05-26 13:03:09 -07007413static void
7414bnx2_get_pauseparam(struct net_device *dev, struct ethtool_pauseparam *epause)
7415{
Michael Chan972ec0d2006-01-23 16:12:43 -08007416 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007417
7418 epause->autoneg = ((bp->autoneg & AUTONEG_FLOW_CTRL) != 0);
7419 epause->rx_pause = ((bp->flow_ctrl & FLOW_CTRL_RX) != 0);
7420 epause->tx_pause = ((bp->flow_ctrl & FLOW_CTRL_TX) != 0);
7421}
7422
7423static int
7424bnx2_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam *epause)
7425{
Michael Chan972ec0d2006-01-23 16:12:43 -08007426 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007427
7428 bp->req_flow_ctrl = 0;
7429 if (epause->rx_pause)
7430 bp->req_flow_ctrl |= FLOW_CTRL_RX;
7431 if (epause->tx_pause)
7432 bp->req_flow_ctrl |= FLOW_CTRL_TX;
7433
7434 if (epause->autoneg) {
7435 bp->autoneg |= AUTONEG_FLOW_CTRL;
7436 }
7437 else {
7438 bp->autoneg &= ~AUTONEG_FLOW_CTRL;
7439 }
7440
Michael Chan9f52b562008-10-09 12:21:46 -07007441 if (netif_running(dev)) {
7442 spin_lock_bh(&bp->phy_lock);
7443 bnx2_setup_phy(bp, bp->phy_port);
7444 spin_unlock_bh(&bp->phy_lock);
7445 }
Michael Chanb6016b72005-05-26 13:03:09 -07007446
7447 return 0;
7448}
7449
Peter Hagervall14ab9b82005-08-10 14:18:16 -07007450static struct {
Michael Chanb6016b72005-05-26 13:03:09 -07007451 char string[ETH_GSTRING_LEN];
Michael Chan790dab22009-08-21 16:20:47 +00007452} bnx2_stats_str_arr[] = {
Michael Chanb6016b72005-05-26 13:03:09 -07007453 { "rx_bytes" },
7454 { "rx_error_bytes" },
7455 { "tx_bytes" },
7456 { "tx_error_bytes" },
7457 { "rx_ucast_packets" },
7458 { "rx_mcast_packets" },
7459 { "rx_bcast_packets" },
7460 { "tx_ucast_packets" },
7461 { "tx_mcast_packets" },
7462 { "tx_bcast_packets" },
7463 { "tx_mac_errors" },
7464 { "tx_carrier_errors" },
7465 { "rx_crc_errors" },
7466 { "rx_align_errors" },
7467 { "tx_single_collisions" },
7468 { "tx_multi_collisions" },
7469 { "tx_deferred" },
7470 { "tx_excess_collisions" },
7471 { "tx_late_collisions" },
7472 { "tx_total_collisions" },
7473 { "rx_fragments" },
7474 { "rx_jabbers" },
7475 { "rx_undersize_packets" },
7476 { "rx_oversize_packets" },
7477 { "rx_64_byte_packets" },
7478 { "rx_65_to_127_byte_packets" },
7479 { "rx_128_to_255_byte_packets" },
7480 { "rx_256_to_511_byte_packets" },
7481 { "rx_512_to_1023_byte_packets" },
7482 { "rx_1024_to_1522_byte_packets" },
7483 { "rx_1523_to_9022_byte_packets" },
7484 { "tx_64_byte_packets" },
7485 { "tx_65_to_127_byte_packets" },
7486 { "tx_128_to_255_byte_packets" },
7487 { "tx_256_to_511_byte_packets" },
7488 { "tx_512_to_1023_byte_packets" },
7489 { "tx_1024_to_1522_byte_packets" },
7490 { "tx_1523_to_9022_byte_packets" },
7491 { "rx_xon_frames" },
7492 { "rx_xoff_frames" },
7493 { "tx_xon_frames" },
7494 { "tx_xoff_frames" },
7495 { "rx_mac_ctrl_frames" },
7496 { "rx_filtered_packets" },
Michael Chan790dab22009-08-21 16:20:47 +00007497 { "rx_ftq_discards" },
Michael Chanb6016b72005-05-26 13:03:09 -07007498 { "rx_discards" },
Michael Chancea94db2006-06-12 22:16:13 -07007499 { "rx_fw_discards" },
Michael Chanb6016b72005-05-26 13:03:09 -07007500};
7501
Jim Cromie0db83cd2012-04-10 14:56:03 +00007502#define BNX2_NUM_STATS ARRAY_SIZE(bnx2_stats_str_arr)
Michael Chan790dab22009-08-21 16:20:47 +00007503
Michael Chanb6016b72005-05-26 13:03:09 -07007504#define STATS_OFFSET32(offset_name) (offsetof(struct statistics_block, offset_name) / 4)
7505
Arjan van de Venf71e1302006-03-03 21:33:57 -05007506static const unsigned long bnx2_stats_offset_arr[BNX2_NUM_STATS] = {
Michael Chanb6016b72005-05-26 13:03:09 -07007507 STATS_OFFSET32(stat_IfHCInOctets_hi),
7508 STATS_OFFSET32(stat_IfHCInBadOctets_hi),
7509 STATS_OFFSET32(stat_IfHCOutOctets_hi),
7510 STATS_OFFSET32(stat_IfHCOutBadOctets_hi),
7511 STATS_OFFSET32(stat_IfHCInUcastPkts_hi),
7512 STATS_OFFSET32(stat_IfHCInMulticastPkts_hi),
7513 STATS_OFFSET32(stat_IfHCInBroadcastPkts_hi),
7514 STATS_OFFSET32(stat_IfHCOutUcastPkts_hi),
7515 STATS_OFFSET32(stat_IfHCOutMulticastPkts_hi),
7516 STATS_OFFSET32(stat_IfHCOutBroadcastPkts_hi),
7517 STATS_OFFSET32(stat_emac_tx_stat_dot3statsinternalmactransmiterrors),
Jeff Garzik6aa20a22006-09-13 13:24:59 -04007518 STATS_OFFSET32(stat_Dot3StatsCarrierSenseErrors),
7519 STATS_OFFSET32(stat_Dot3StatsFCSErrors),
7520 STATS_OFFSET32(stat_Dot3StatsAlignmentErrors),
7521 STATS_OFFSET32(stat_Dot3StatsSingleCollisionFrames),
7522 STATS_OFFSET32(stat_Dot3StatsMultipleCollisionFrames),
7523 STATS_OFFSET32(stat_Dot3StatsDeferredTransmissions),
7524 STATS_OFFSET32(stat_Dot3StatsExcessiveCollisions),
7525 STATS_OFFSET32(stat_Dot3StatsLateCollisions),
7526 STATS_OFFSET32(stat_EtherStatsCollisions),
7527 STATS_OFFSET32(stat_EtherStatsFragments),
7528 STATS_OFFSET32(stat_EtherStatsJabbers),
7529 STATS_OFFSET32(stat_EtherStatsUndersizePkts),
7530 STATS_OFFSET32(stat_EtherStatsOverrsizePkts),
7531 STATS_OFFSET32(stat_EtherStatsPktsRx64Octets),
7532 STATS_OFFSET32(stat_EtherStatsPktsRx65Octetsto127Octets),
7533 STATS_OFFSET32(stat_EtherStatsPktsRx128Octetsto255Octets),
7534 STATS_OFFSET32(stat_EtherStatsPktsRx256Octetsto511Octets),
7535 STATS_OFFSET32(stat_EtherStatsPktsRx512Octetsto1023Octets),
7536 STATS_OFFSET32(stat_EtherStatsPktsRx1024Octetsto1522Octets),
7537 STATS_OFFSET32(stat_EtherStatsPktsRx1523Octetsto9022Octets),
7538 STATS_OFFSET32(stat_EtherStatsPktsTx64Octets),
7539 STATS_OFFSET32(stat_EtherStatsPktsTx65Octetsto127Octets),
7540 STATS_OFFSET32(stat_EtherStatsPktsTx128Octetsto255Octets),
7541 STATS_OFFSET32(stat_EtherStatsPktsTx256Octetsto511Octets),
7542 STATS_OFFSET32(stat_EtherStatsPktsTx512Octetsto1023Octets),
7543 STATS_OFFSET32(stat_EtherStatsPktsTx1024Octetsto1522Octets),
7544 STATS_OFFSET32(stat_EtherStatsPktsTx1523Octetsto9022Octets),
7545 STATS_OFFSET32(stat_XonPauseFramesReceived),
7546 STATS_OFFSET32(stat_XoffPauseFramesReceived),
7547 STATS_OFFSET32(stat_OutXonSent),
7548 STATS_OFFSET32(stat_OutXoffSent),
7549 STATS_OFFSET32(stat_MacControlFramesReceived),
7550 STATS_OFFSET32(stat_IfInFramesL2FilterDiscards),
Michael Chan790dab22009-08-21 16:20:47 +00007551 STATS_OFFSET32(stat_IfInFTQDiscards),
Jeff Garzik6aa20a22006-09-13 13:24:59 -04007552 STATS_OFFSET32(stat_IfInMBUFDiscards),
Michael Chancea94db2006-06-12 22:16:13 -07007553 STATS_OFFSET32(stat_FwRxDrop),
Michael Chanb6016b72005-05-26 13:03:09 -07007554};
7555
7556/* stat_IfHCInBadOctets and stat_Dot3StatsCarrierSenseErrors are
7557 * skipped because of errata.
Jeff Garzik6aa20a22006-09-13 13:24:59 -04007558 */
Peter Hagervall14ab9b82005-08-10 14:18:16 -07007559static u8 bnx2_5706_stats_len_arr[BNX2_NUM_STATS] = {
Michael Chanb6016b72005-05-26 13:03:09 -07007560 8,0,8,8,8,8,8,8,8,8,
7561 4,0,4,4,4,4,4,4,4,4,
7562 4,4,4,4,4,4,4,4,4,4,
7563 4,4,4,4,4,4,4,4,4,4,
Michael Chan790dab22009-08-21 16:20:47 +00007564 4,4,4,4,4,4,4,
Michael Chanb6016b72005-05-26 13:03:09 -07007565};
7566
Michael Chan5b0c76a2005-11-04 08:45:49 -08007567static u8 bnx2_5708_stats_len_arr[BNX2_NUM_STATS] = {
7568 8,0,8,8,8,8,8,8,8,8,
7569 4,4,4,4,4,4,4,4,4,4,
7570 4,4,4,4,4,4,4,4,4,4,
7571 4,4,4,4,4,4,4,4,4,4,
Michael Chan790dab22009-08-21 16:20:47 +00007572 4,4,4,4,4,4,4,
Michael Chan5b0c76a2005-11-04 08:45:49 -08007573};
7574
Michael Chanb6016b72005-05-26 13:03:09 -07007575#define BNX2_NUM_TESTS 6
7576
Peter Hagervall14ab9b82005-08-10 14:18:16 -07007577static struct {
Michael Chanb6016b72005-05-26 13:03:09 -07007578 char string[ETH_GSTRING_LEN];
7579} bnx2_tests_str_arr[BNX2_NUM_TESTS] = {
7580 { "register_test (offline)" },
7581 { "memory_test (offline)" },
7582 { "loopback_test (offline)" },
7583 { "nvram_test (online)" },
7584 { "interrupt_test (online)" },
7585 { "link_test (online)" },
7586};
7587
7588static int
Jeff Garzikb9f2c042007-10-03 18:07:32 -07007589bnx2_get_sset_count(struct net_device *dev, int sset)
Michael Chanb6016b72005-05-26 13:03:09 -07007590{
Jeff Garzikb9f2c042007-10-03 18:07:32 -07007591 switch (sset) {
7592 case ETH_SS_TEST:
7593 return BNX2_NUM_TESTS;
7594 case ETH_SS_STATS:
7595 return BNX2_NUM_STATS;
7596 default:
7597 return -EOPNOTSUPP;
7598 }
Michael Chanb6016b72005-05-26 13:03:09 -07007599}
7600
7601static void
7602bnx2_self_test(struct net_device *dev, struct ethtool_test *etest, u64 *buf)
7603{
Michael Chan972ec0d2006-01-23 16:12:43 -08007604 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007605
7606 memset(buf, 0, sizeof(u64) * BNX2_NUM_TESTS);
7607 if (etest->flags & ETH_TEST_FL_OFFLINE) {
Michael Chan80be4432006-11-19 14:07:28 -08007608 int i;
7609
Michael Chan212f9932010-04-27 11:28:10 +00007610 bnx2_netif_stop(bp, true);
Michael Chanb6016b72005-05-26 13:03:09 -07007611 bnx2_reset_chip(bp, BNX2_DRV_MSG_CODE_DIAG);
7612 bnx2_free_skbs(bp);
7613
7614 if (bnx2_test_registers(bp) != 0) {
7615 buf[0] = 1;
7616 etest->flags |= ETH_TEST_FL_FAILED;
7617 }
7618 if (bnx2_test_memory(bp) != 0) {
7619 buf[1] = 1;
7620 etest->flags |= ETH_TEST_FL_FAILED;
7621 }
Michael Chanbc5a0692006-01-23 16:13:22 -08007622 if ((buf[2] = bnx2_test_loopback(bp)) != 0)
Michael Chanb6016b72005-05-26 13:03:09 -07007623 etest->flags |= ETH_TEST_FL_FAILED;
Michael Chanb6016b72005-05-26 13:03:09 -07007624
Michael Chan9f52b562008-10-09 12:21:46 -07007625 if (!netif_running(bp->dev))
7626 bnx2_shutdown_chip(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07007627 else {
Michael Chan9a120bc2008-05-16 22:17:45 -07007628 bnx2_init_nic(bp, 1);
Michael Chan212f9932010-04-27 11:28:10 +00007629 bnx2_netif_start(bp, true);
Michael Chanb6016b72005-05-26 13:03:09 -07007630 }
7631
7632 /* wait for link up */
Michael Chan80be4432006-11-19 14:07:28 -08007633 for (i = 0; i < 7; i++) {
7634 if (bp->link_up)
7635 break;
7636 msleep_interruptible(1000);
7637 }
Michael Chanb6016b72005-05-26 13:03:09 -07007638 }
7639
7640 if (bnx2_test_nvram(bp) != 0) {
7641 buf[3] = 1;
7642 etest->flags |= ETH_TEST_FL_FAILED;
7643 }
7644 if (bnx2_test_intr(bp) != 0) {
7645 buf[4] = 1;
7646 etest->flags |= ETH_TEST_FL_FAILED;
7647 }
7648
7649 if (bnx2_test_link(bp) != 0) {
7650 buf[5] = 1;
7651 etest->flags |= ETH_TEST_FL_FAILED;
7652
7653 }
7654}
7655
7656static void
7657bnx2_get_strings(struct net_device *dev, u32 stringset, u8 *buf)
7658{
7659 switch (stringset) {
7660 case ETH_SS_STATS:
7661 memcpy(buf, bnx2_stats_str_arr,
7662 sizeof(bnx2_stats_str_arr));
7663 break;
7664 case ETH_SS_TEST:
7665 memcpy(buf, bnx2_tests_str_arr,
7666 sizeof(bnx2_tests_str_arr));
7667 break;
7668 }
7669}
7670
Michael Chanb6016b72005-05-26 13:03:09 -07007671static void
7672bnx2_get_ethtool_stats(struct net_device *dev,
7673 struct ethtool_stats *stats, u64 *buf)
7674{
Michael Chan972ec0d2006-01-23 16:12:43 -08007675 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007676 int i;
7677 u32 *hw_stats = (u32 *) bp->stats_blk;
Michael Chan354fcd72010-01-17 07:30:44 +00007678 u32 *temp_stats = (u32 *) bp->temp_stats_blk;
Peter Hagervall14ab9b82005-08-10 14:18:16 -07007679 u8 *stats_len_arr = NULL;
Michael Chanb6016b72005-05-26 13:03:09 -07007680
7681 if (hw_stats == NULL) {
7682 memset(buf, 0, sizeof(u64) * BNX2_NUM_STATS);
7683 return;
7684 }
7685
Michael Chan4ce45e02012-12-06 10:33:10 +00007686 if ((BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5706_A0) ||
7687 (BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5706_A1) ||
7688 (BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5706_A2) ||
7689 (BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5708_A0))
Michael Chanb6016b72005-05-26 13:03:09 -07007690 stats_len_arr = bnx2_5706_stats_len_arr;
Michael Chan5b0c76a2005-11-04 08:45:49 -08007691 else
7692 stats_len_arr = bnx2_5708_stats_len_arr;
Michael Chanb6016b72005-05-26 13:03:09 -07007693
7694 for (i = 0; i < BNX2_NUM_STATS; i++) {
Michael Chan354fcd72010-01-17 07:30:44 +00007695 unsigned long offset;
7696
Michael Chanb6016b72005-05-26 13:03:09 -07007697 if (stats_len_arr[i] == 0) {
7698 /* skip this counter */
7699 buf[i] = 0;
7700 continue;
7701 }
Michael Chan354fcd72010-01-17 07:30:44 +00007702
7703 offset = bnx2_stats_offset_arr[i];
Michael Chanb6016b72005-05-26 13:03:09 -07007704 if (stats_len_arr[i] == 4) {
7705 /* 4-byte counter */
Michael Chan354fcd72010-01-17 07:30:44 +00007706 buf[i] = (u64) *(hw_stats + offset) +
7707 *(temp_stats + offset);
Michael Chanb6016b72005-05-26 13:03:09 -07007708 continue;
7709 }
7710 /* 8-byte counter */
Michael Chan354fcd72010-01-17 07:30:44 +00007711 buf[i] = (((u64) *(hw_stats + offset)) << 32) +
7712 *(hw_stats + offset + 1) +
7713 (((u64) *(temp_stats + offset)) << 32) +
7714 *(temp_stats + offset + 1);
Michael Chanb6016b72005-05-26 13:03:09 -07007715 }
7716}
7717
7718static int
stephen hemminger2e17e1a2011-04-04 11:06:36 +00007719bnx2_set_phys_id(struct net_device *dev, enum ethtool_phys_id_state state)
Michael Chanb6016b72005-05-26 13:03:09 -07007720{
Michael Chan972ec0d2006-01-23 16:12:43 -08007721 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007722
stephen hemminger2e17e1a2011-04-04 11:06:36 +00007723 switch (state) {
7724 case ETHTOOL_ID_ACTIVE:
Michael Chane503e062012-12-06 10:33:08 +00007725 bp->leds_save = BNX2_RD(bp, BNX2_MISC_CFG);
7726 BNX2_WR(bp, BNX2_MISC_CFG, BNX2_MISC_CFG_LEDMODE_MAC);
Allan, Bruce Wfce55922011-04-13 13:09:10 +00007727 return 1; /* cycle on/off once per second */
Michael Chanb6016b72005-05-26 13:03:09 -07007728
stephen hemminger2e17e1a2011-04-04 11:06:36 +00007729 case ETHTOOL_ID_ON:
Michael Chane503e062012-12-06 10:33:08 +00007730 BNX2_WR(bp, BNX2_EMAC_LED, BNX2_EMAC_LED_OVERRIDE |
7731 BNX2_EMAC_LED_1000MB_OVERRIDE |
7732 BNX2_EMAC_LED_100MB_OVERRIDE |
7733 BNX2_EMAC_LED_10MB_OVERRIDE |
7734 BNX2_EMAC_LED_TRAFFIC_OVERRIDE |
7735 BNX2_EMAC_LED_TRAFFIC);
stephen hemminger2e17e1a2011-04-04 11:06:36 +00007736 break;
Michael Chanb6016b72005-05-26 13:03:09 -07007737
stephen hemminger2e17e1a2011-04-04 11:06:36 +00007738 case ETHTOOL_ID_OFF:
Michael Chane503e062012-12-06 10:33:08 +00007739 BNX2_WR(bp, BNX2_EMAC_LED, BNX2_EMAC_LED_OVERRIDE);
stephen hemminger2e17e1a2011-04-04 11:06:36 +00007740 break;
7741
7742 case ETHTOOL_ID_INACTIVE:
Michael Chane503e062012-12-06 10:33:08 +00007743 BNX2_WR(bp, BNX2_EMAC_LED, 0);
7744 BNX2_WR(bp, BNX2_MISC_CFG, bp->leds_save);
stephen hemminger2e17e1a2011-04-04 11:06:36 +00007745 break;
Michael Chanb6016b72005-05-26 13:03:09 -07007746 }
Michael Chan9f52b562008-10-09 12:21:46 -07007747
Michael Chanb6016b72005-05-26 13:03:09 -07007748 return 0;
7749}
7750
Michael Chanfdc85412010-07-03 20:42:16 +00007751static int
Michał Mirosławc8f44af2011-11-15 15:29:55 +00007752bnx2_set_features(struct net_device *dev, netdev_features_t features)
Michael Chanfdc85412010-07-03 20:42:16 +00007753{
Jesse Gross7d0fd212010-10-20 13:56:09 +00007754 struct bnx2 *bp = netdev_priv(dev);
Jesse Gross7d0fd212010-10-20 13:56:09 +00007755
Michael Chan7c810472011-01-24 12:59:02 +00007756 /* TSO with VLAN tag won't work with current firmware */
Patrick McHardyf6469682013-04-19 02:04:27 +00007757 if (features & NETIF_F_HW_VLAN_CTAG_TX)
Michał Mirosław8d7dfc22011-04-10 04:47:46 +00007758 dev->vlan_features |= (dev->hw_features & NETIF_F_ALL_TSO);
7759 else
7760 dev->vlan_features &= ~NETIF_F_ALL_TSO;
Michael Chan7c810472011-01-24 12:59:02 +00007761
Patrick McHardyf6469682013-04-19 02:04:27 +00007762 if ((!!(features & NETIF_F_HW_VLAN_CTAG_RX) !=
Jesse Gross7d0fd212010-10-20 13:56:09 +00007763 !!(bp->rx_mode & BNX2_EMAC_RX_MODE_KEEP_VLAN_TAG)) &&
7764 netif_running(dev)) {
7765 bnx2_netif_stop(bp, false);
Michał Mirosław8d7dfc22011-04-10 04:47:46 +00007766 dev->features = features;
Jesse Gross7d0fd212010-10-20 13:56:09 +00007767 bnx2_set_rx_mode(dev);
7768 bnx2_fw_sync(bp, BNX2_DRV_MSG_CODE_KEEP_VLAN_UPDATE, 0, 1);
7769 bnx2_netif_start(bp, false);
Michał Mirosław8d7dfc22011-04-10 04:47:46 +00007770 return 1;
Jesse Gross7d0fd212010-10-20 13:56:09 +00007771 }
7772
7773 return 0;
Michael Chanfdc85412010-07-03 20:42:16 +00007774}
7775
Michael Chanb0332812012-02-05 15:24:38 +00007776static void bnx2_get_channels(struct net_device *dev,
7777 struct ethtool_channels *channels)
7778{
7779 struct bnx2 *bp = netdev_priv(dev);
7780 u32 max_rx_rings = 1;
7781 u32 max_tx_rings = 1;
7782
7783 if ((bp->flags & BNX2_FLAG_MSIX_CAP) && !disable_msi) {
7784 max_rx_rings = RX_MAX_RINGS;
7785 max_tx_rings = TX_MAX_RINGS;
7786 }
7787
7788 channels->max_rx = max_rx_rings;
7789 channels->max_tx = max_tx_rings;
7790 channels->max_other = 0;
7791 channels->max_combined = 0;
7792 channels->rx_count = bp->num_rx_rings;
7793 channels->tx_count = bp->num_tx_rings;
7794 channels->other_count = 0;
7795 channels->combined_count = 0;
7796}
7797
7798static int bnx2_set_channels(struct net_device *dev,
7799 struct ethtool_channels *channels)
7800{
7801 struct bnx2 *bp = netdev_priv(dev);
7802 u32 max_rx_rings = 1;
7803 u32 max_tx_rings = 1;
7804 int rc = 0;
7805
7806 if ((bp->flags & BNX2_FLAG_MSIX_CAP) && !disable_msi) {
7807 max_rx_rings = RX_MAX_RINGS;
7808 max_tx_rings = TX_MAX_RINGS;
7809 }
7810 if (channels->rx_count > max_rx_rings ||
7811 channels->tx_count > max_tx_rings)
7812 return -EINVAL;
7813
7814 bp->num_req_rx_rings = channels->rx_count;
7815 bp->num_req_tx_rings = channels->tx_count;
7816
7817 if (netif_running(dev))
7818 rc = bnx2_change_ring_size(bp, bp->rx_ring_size,
7819 bp->tx_ring_size, true);
7820
7821 return rc;
7822}
7823
Jeff Garzik7282d492006-09-13 14:30:00 -04007824static const struct ethtool_ops bnx2_ethtool_ops = {
Michael Chanb6016b72005-05-26 13:03:09 -07007825 .get_settings = bnx2_get_settings,
7826 .set_settings = bnx2_set_settings,
7827 .get_drvinfo = bnx2_get_drvinfo,
Michael Chan244ac4f2006-03-20 17:48:46 -08007828 .get_regs_len = bnx2_get_regs_len,
7829 .get_regs = bnx2_get_regs,
Michael Chanb6016b72005-05-26 13:03:09 -07007830 .get_wol = bnx2_get_wol,
7831 .set_wol = bnx2_set_wol,
7832 .nway_reset = bnx2_nway_reset,
Ooiwa Naohiro7959ea22009-06-24 00:19:06 -07007833 .get_link = bnx2_get_link,
Michael Chanb6016b72005-05-26 13:03:09 -07007834 .get_eeprom_len = bnx2_get_eeprom_len,
7835 .get_eeprom = bnx2_get_eeprom,
7836 .set_eeprom = bnx2_set_eeprom,
7837 .get_coalesce = bnx2_get_coalesce,
7838 .set_coalesce = bnx2_set_coalesce,
7839 .get_ringparam = bnx2_get_ringparam,
7840 .set_ringparam = bnx2_set_ringparam,
7841 .get_pauseparam = bnx2_get_pauseparam,
7842 .set_pauseparam = bnx2_set_pauseparam,
Michael Chanb6016b72005-05-26 13:03:09 -07007843 .self_test = bnx2_self_test,
7844 .get_strings = bnx2_get_strings,
stephen hemminger2e17e1a2011-04-04 11:06:36 +00007845 .set_phys_id = bnx2_set_phys_id,
Michael Chanb6016b72005-05-26 13:03:09 -07007846 .get_ethtool_stats = bnx2_get_ethtool_stats,
Jeff Garzikb9f2c042007-10-03 18:07:32 -07007847 .get_sset_count = bnx2_get_sset_count,
Michael Chanb0332812012-02-05 15:24:38 +00007848 .get_channels = bnx2_get_channels,
7849 .set_channels = bnx2_set_channels,
Michael Chanb6016b72005-05-26 13:03:09 -07007850};
7851
7852/* Called with rtnl_lock */
7853static int
7854bnx2_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
7855{
Peter Hagervall14ab9b82005-08-10 14:18:16 -07007856 struct mii_ioctl_data *data = if_mii(ifr);
Michael Chan972ec0d2006-01-23 16:12:43 -08007857 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007858 int err;
7859
7860 switch(cmd) {
7861 case SIOCGMIIPHY:
7862 data->phy_id = bp->phy_addr;
7863
7864 /* fallthru */
7865 case SIOCGMIIREG: {
7866 u32 mii_regval;
7867
Michael Chan583c28e2008-01-21 19:51:35 -08007868 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
Michael Chan7b6b8342007-07-07 22:50:15 -07007869 return -EOPNOTSUPP;
7870
Michael Chandad3e452007-05-03 13:18:03 -07007871 if (!netif_running(dev))
7872 return -EAGAIN;
7873
Michael Chanc770a652005-08-25 15:38:39 -07007874 spin_lock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07007875 err = bnx2_read_phy(bp, data->reg_num & 0x1f, &mii_regval);
Michael Chanc770a652005-08-25 15:38:39 -07007876 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07007877
7878 data->val_out = mii_regval;
7879
7880 return err;
7881 }
7882
7883 case SIOCSMIIREG:
Michael Chan583c28e2008-01-21 19:51:35 -08007884 if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
Michael Chan7b6b8342007-07-07 22:50:15 -07007885 return -EOPNOTSUPP;
7886
Michael Chandad3e452007-05-03 13:18:03 -07007887 if (!netif_running(dev))
7888 return -EAGAIN;
7889
Michael Chanc770a652005-08-25 15:38:39 -07007890 spin_lock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07007891 err = bnx2_write_phy(bp, data->reg_num & 0x1f, data->val_in);
Michael Chanc770a652005-08-25 15:38:39 -07007892 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07007893
7894 return err;
7895
7896 default:
7897 /* do nothing */
7898 break;
7899 }
7900 return -EOPNOTSUPP;
7901}
7902
7903/* Called with rtnl_lock */
7904static int
7905bnx2_change_mac_addr(struct net_device *dev, void *p)
7906{
7907 struct sockaddr *addr = p;
Michael Chan972ec0d2006-01-23 16:12:43 -08007908 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007909
Michael Chan73eef4c2005-08-25 15:39:15 -07007910 if (!is_valid_ether_addr(addr->sa_data))
Danny Kukawka504f9b52012-02-21 02:07:49 +00007911 return -EADDRNOTAVAIL;
Michael Chan73eef4c2005-08-25 15:39:15 -07007912
Michael Chanb6016b72005-05-26 13:03:09 -07007913 memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
7914 if (netif_running(dev))
Benjamin Li5fcaed02008-07-14 22:39:52 -07007915 bnx2_set_mac_addr(bp, bp->dev->dev_addr, 0);
Michael Chanb6016b72005-05-26 13:03:09 -07007916
7917 return 0;
7918}
7919
7920/* Called with rtnl_lock */
7921static int
7922bnx2_change_mtu(struct net_device *dev, int new_mtu)
7923{
Michael Chan972ec0d2006-01-23 16:12:43 -08007924 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07007925
7926 if (((new_mtu + ETH_HLEN) > MAX_ETHERNET_JUMBO_PACKET_SIZE) ||
7927 ((new_mtu + ETH_HLEN) < MIN_ETHERNET_PACKET_SIZE))
7928 return -EINVAL;
7929
7930 dev->mtu = new_mtu;
Michael Chanb0332812012-02-05 15:24:38 +00007931 return bnx2_change_ring_size(bp, bp->rx_ring_size, bp->tx_ring_size,
7932 false);
Michael Chanb6016b72005-05-26 13:03:09 -07007933}
7934
Alexey Dobriyan257ddbd2010-01-27 10:17:41 +00007935#ifdef CONFIG_NET_POLL_CONTROLLER
Michael Chanb6016b72005-05-26 13:03:09 -07007936static void
7937poll_bnx2(struct net_device *dev)
7938{
Michael Chan972ec0d2006-01-23 16:12:43 -08007939 struct bnx2 *bp = netdev_priv(dev);
Neil Hormanb2af2c12008-11-12 16:23:44 -08007940 int i;
Michael Chanb6016b72005-05-26 13:03:09 -07007941
Neil Hormanb2af2c12008-11-12 16:23:44 -08007942 for (i = 0; i < bp->irq_nvecs; i++) {
Michael Chan1bf1e342010-03-23 13:13:12 +00007943 struct bnx2_irq *irq = &bp->irq_tbl[i];
7944
7945 disable_irq(irq->vector);
7946 irq->handler(irq->vector, &bp->bnx2_napi[i]);
7947 enable_irq(irq->vector);
Neil Hormanb2af2c12008-11-12 16:23:44 -08007948 }
Michael Chanb6016b72005-05-26 13:03:09 -07007949}
7950#endif
7951
Bill Pembertoncfd95a62012-12-03 09:22:58 -05007952static void
Michael Chan253c8b72007-01-08 19:56:01 -08007953bnx2_get_5709_media(struct bnx2 *bp)
7954{
Michael Chane503e062012-12-06 10:33:08 +00007955 u32 val = BNX2_RD(bp, BNX2_MISC_DUAL_MEDIA_CTRL);
Michael Chan253c8b72007-01-08 19:56:01 -08007956 u32 bond_id = val & BNX2_MISC_DUAL_MEDIA_CTRL_BOND_ID;
7957 u32 strap;
7958
7959 if (bond_id == BNX2_MISC_DUAL_MEDIA_CTRL_BOND_ID_C)
7960 return;
7961 else if (bond_id == BNX2_MISC_DUAL_MEDIA_CTRL_BOND_ID_S) {
Michael Chan583c28e2008-01-21 19:51:35 -08007962 bp->phy_flags |= BNX2_PHY_FLAG_SERDES;
Michael Chan253c8b72007-01-08 19:56:01 -08007963 return;
7964 }
7965
7966 if (val & BNX2_MISC_DUAL_MEDIA_CTRL_STRAP_OVERRIDE)
7967 strap = (val & BNX2_MISC_DUAL_MEDIA_CTRL_PHY_CTRL) >> 21;
7968 else
7969 strap = (val & BNX2_MISC_DUAL_MEDIA_CTRL_PHY_CTRL_STRAP) >> 8;
7970
Michael Chanaefd90e2012-06-16 15:45:43 +00007971 if (bp->func == 0) {
Michael Chan253c8b72007-01-08 19:56:01 -08007972 switch (strap) {
7973 case 0x4:
7974 case 0x5:
7975 case 0x6:
Michael Chan583c28e2008-01-21 19:51:35 -08007976 bp->phy_flags |= BNX2_PHY_FLAG_SERDES;
Michael Chan253c8b72007-01-08 19:56:01 -08007977 return;
7978 }
7979 } else {
7980 switch (strap) {
7981 case 0x1:
7982 case 0x2:
7983 case 0x4:
Michael Chan583c28e2008-01-21 19:51:35 -08007984 bp->phy_flags |= BNX2_PHY_FLAG_SERDES;
Michael Chan253c8b72007-01-08 19:56:01 -08007985 return;
7986 }
7987 }
7988}
7989
Bill Pembertoncfd95a62012-12-03 09:22:58 -05007990static void
Michael Chan883e5152007-05-03 13:25:11 -07007991bnx2_get_pci_speed(struct bnx2 *bp)
7992{
7993 u32 reg;
7994
Michael Chane503e062012-12-06 10:33:08 +00007995 reg = BNX2_RD(bp, BNX2_PCICFG_MISC_STATUS);
Michael Chan883e5152007-05-03 13:25:11 -07007996 if (reg & BNX2_PCICFG_MISC_STATUS_PCIX_DET) {
7997 u32 clkreg;
7998
David S. Millerf86e82f2008-01-21 17:15:40 -08007999 bp->flags |= BNX2_FLAG_PCIX;
Michael Chan883e5152007-05-03 13:25:11 -07008000
Michael Chane503e062012-12-06 10:33:08 +00008001 clkreg = BNX2_RD(bp, BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS);
Michael Chan883e5152007-05-03 13:25:11 -07008002
8003 clkreg &= BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET;
8004 switch (clkreg) {
8005 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_133MHZ:
8006 bp->bus_speed_mhz = 133;
8007 break;
8008
8009 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_95MHZ:
8010 bp->bus_speed_mhz = 100;
8011 break;
8012
8013 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_66MHZ:
8014 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_80MHZ:
8015 bp->bus_speed_mhz = 66;
8016 break;
8017
8018 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_48MHZ:
8019 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_55MHZ:
8020 bp->bus_speed_mhz = 50;
8021 break;
8022
8023 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_LOW:
8024 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_32MHZ:
8025 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_38MHZ:
8026 bp->bus_speed_mhz = 33;
8027 break;
8028 }
8029 }
8030 else {
8031 if (reg & BNX2_PCICFG_MISC_STATUS_M66EN)
8032 bp->bus_speed_mhz = 66;
8033 else
8034 bp->bus_speed_mhz = 33;
8035 }
8036
8037 if (reg & BNX2_PCICFG_MISC_STATUS_32BIT_DET)
David S. Millerf86e82f2008-01-21 17:15:40 -08008038 bp->flags |= BNX2_FLAG_PCI_32BIT;
Michael Chan883e5152007-05-03 13:25:11 -07008039
8040}
8041
Bill Pembertoncfd95a62012-12-03 09:22:58 -05008042static void
Michael Chan76d99062009-12-03 09:46:34 +00008043bnx2_read_vpd_fw_ver(struct bnx2 *bp)
8044{
Matt Carlsondf25bc32010-02-26 14:04:44 +00008045 int rc, i, j;
Michael Chan76d99062009-12-03 09:46:34 +00008046 u8 *data;
Matt Carlsondf25bc32010-02-26 14:04:44 +00008047 unsigned int block_end, rosize, len;
Michael Chan76d99062009-12-03 09:46:34 +00008048
Michael Chan012093f2009-12-03 15:58:00 -08008049#define BNX2_VPD_NVRAM_OFFSET 0x300
8050#define BNX2_VPD_LEN 128
Michael Chan76d99062009-12-03 09:46:34 +00008051#define BNX2_MAX_VER_SLEN 30
8052
8053 data = kmalloc(256, GFP_KERNEL);
8054 if (!data)
8055 return;
8056
Michael Chan012093f2009-12-03 15:58:00 -08008057 rc = bnx2_nvram_read(bp, BNX2_VPD_NVRAM_OFFSET, data + BNX2_VPD_LEN,
8058 BNX2_VPD_LEN);
Michael Chan76d99062009-12-03 09:46:34 +00008059 if (rc)
8060 goto vpd_done;
8061
Michael Chan012093f2009-12-03 15:58:00 -08008062 for (i = 0; i < BNX2_VPD_LEN; i += 4) {
8063 data[i] = data[i + BNX2_VPD_LEN + 3];
8064 data[i + 1] = data[i + BNX2_VPD_LEN + 2];
8065 data[i + 2] = data[i + BNX2_VPD_LEN + 1];
8066 data[i + 3] = data[i + BNX2_VPD_LEN];
Michael Chan76d99062009-12-03 09:46:34 +00008067 }
8068
Matt Carlsondf25bc32010-02-26 14:04:44 +00008069 i = pci_vpd_find_tag(data, 0, BNX2_VPD_LEN, PCI_VPD_LRDT_RO_DATA);
8070 if (i < 0)
Michael Chan76d99062009-12-03 09:46:34 +00008071 goto vpd_done;
Matt Carlsondf25bc32010-02-26 14:04:44 +00008072
8073 rosize = pci_vpd_lrdt_size(&data[i]);
8074 i += PCI_VPD_LRDT_TAG_SIZE;
8075 block_end = i + rosize;
8076
8077 if (block_end > BNX2_VPD_LEN)
8078 goto vpd_done;
8079
8080 j = pci_vpd_find_info_keyword(data, i, rosize,
8081 PCI_VPD_RO_KEYWORD_MFR_ID);
8082 if (j < 0)
8083 goto vpd_done;
8084
8085 len = pci_vpd_info_field_size(&data[j]);
8086
8087 j += PCI_VPD_INFO_FLD_HDR_SIZE;
8088 if (j + len > block_end || len != 4 ||
8089 memcmp(&data[j], "1028", 4))
8090 goto vpd_done;
8091
8092 j = pci_vpd_find_info_keyword(data, i, rosize,
8093 PCI_VPD_RO_KEYWORD_VENDOR0);
8094 if (j < 0)
8095 goto vpd_done;
8096
8097 len = pci_vpd_info_field_size(&data[j]);
8098
8099 j += PCI_VPD_INFO_FLD_HDR_SIZE;
8100 if (j + len > block_end || len > BNX2_MAX_VER_SLEN)
8101 goto vpd_done;
8102
8103 memcpy(bp->fw_version, &data[j], len);
8104 bp->fw_version[len] = ' ';
Michael Chan76d99062009-12-03 09:46:34 +00008105
8106vpd_done:
8107 kfree(data);
8108}
8109
Bill Pembertoncfd95a62012-12-03 09:22:58 -05008110static int
Michael Chanb6016b72005-05-26 13:03:09 -07008111bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
8112{
8113 struct bnx2 *bp;
Michael Chan58fc2ea2007-07-07 22:52:02 -07008114 int rc, i, j;
Michael Chanb6016b72005-05-26 13:03:09 -07008115 u32 reg;
Michael Chan40453c82007-05-03 13:19:18 -07008116 u64 dma_mask, persist_dma_mask;
John Feeneycd709aa2010-08-22 17:45:53 +00008117 int err;
Michael Chanb6016b72005-05-26 13:03:09 -07008118
Michael Chanb6016b72005-05-26 13:03:09 -07008119 SET_NETDEV_DEV(dev, &pdev->dev);
Michael Chan972ec0d2006-01-23 16:12:43 -08008120 bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07008121
8122 bp->flags = 0;
8123 bp->phy_flags = 0;
8124
Michael Chan354fcd72010-01-17 07:30:44 +00008125 bp->temp_stats_blk =
8126 kzalloc(sizeof(struct statistics_block), GFP_KERNEL);
8127
8128 if (bp->temp_stats_blk == NULL) {
8129 rc = -ENOMEM;
8130 goto err_out;
8131 }
8132
Michael Chanb6016b72005-05-26 13:03:09 -07008133 /* enable device (incl. PCI PM wakeup), and bus-mastering */
8134 rc = pci_enable_device(pdev);
8135 if (rc) {
Joe Perches3a9c6a42010-02-17 15:01:51 +00008136 dev_err(&pdev->dev, "Cannot enable PCI device, aborting\n");
Michael Chanb6016b72005-05-26 13:03:09 -07008137 goto err_out;
8138 }
8139
8140 if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) {
Jeff Garzik9b91cf92006-06-27 11:39:50 -04008141 dev_err(&pdev->dev,
Joe Perches3a9c6a42010-02-17 15:01:51 +00008142 "Cannot find PCI device base address, aborting\n");
Michael Chanb6016b72005-05-26 13:03:09 -07008143 rc = -ENODEV;
8144 goto err_out_disable;
8145 }
8146
8147 rc = pci_request_regions(pdev, DRV_MODULE_NAME);
8148 if (rc) {
Joe Perches3a9c6a42010-02-17 15:01:51 +00008149 dev_err(&pdev->dev, "Cannot obtain PCI resources, aborting\n");
Michael Chanb6016b72005-05-26 13:03:09 -07008150 goto err_out_disable;
8151 }
8152
8153 pci_set_master(pdev);
8154
Yijing Wang85768272013-06-18 16:12:37 +08008155 bp->pm_cap = pdev->pm_cap;
Michael Chanb6016b72005-05-26 13:03:09 -07008156 if (bp->pm_cap == 0) {
Jeff Garzik9b91cf92006-06-27 11:39:50 -04008157 dev_err(&pdev->dev,
Joe Perches3a9c6a42010-02-17 15:01:51 +00008158 "Cannot find power management capability, aborting\n");
Michael Chanb6016b72005-05-26 13:03:09 -07008159 rc = -EIO;
8160 goto err_out_release;
8161 }
8162
Michael Chanb6016b72005-05-26 13:03:09 -07008163 bp->dev = dev;
8164 bp->pdev = pdev;
8165
8166 spin_lock_init(&bp->phy_lock);
Michael Chan1b8227c2007-05-03 13:24:05 -07008167 spin_lock_init(&bp->indirect_lock);
Michael Chanc5a88952009-08-14 15:49:45 +00008168#ifdef BCM_CNIC
8169 mutex_init(&bp->cnic_lock);
8170#endif
David Howellsc4028952006-11-22 14:57:56 +00008171 INIT_WORK(&bp->reset_task, bnx2_reset_task);
Michael Chanb6016b72005-05-26 13:03:09 -07008172
Francois Romieuc0357e92012-03-09 14:51:47 +01008173 bp->regview = pci_iomap(pdev, 0, MB_GET_CID_ADDR(TX_TSS_CID +
8174 TX_MAX_TSS_RINGS + 1));
Michael Chanb6016b72005-05-26 13:03:09 -07008175 if (!bp->regview) {
Joe Perches3a9c6a42010-02-17 15:01:51 +00008176 dev_err(&pdev->dev, "Cannot map register space, aborting\n");
Michael Chanb6016b72005-05-26 13:03:09 -07008177 rc = -ENOMEM;
8178 goto err_out_release;
8179 }
8180
8181 /* Configure byte swap and enable write to the reg_window registers.
8182 * Rely on CPU to do target byte swapping on big endian systems
8183 * The chip's target access swapping will not swap all accesses
8184 */
Michael Chane503e062012-12-06 10:33:08 +00008185 BNX2_WR(bp, BNX2_PCICFG_MISC_CONFIG,
8186 BNX2_PCICFG_MISC_CONFIG_REG_WINDOW_ENA |
8187 BNX2_PCICFG_MISC_CONFIG_TARGET_MB_WORD_SWAP);
Michael Chanb6016b72005-05-26 13:03:09 -07008188
Michael Chane503e062012-12-06 10:33:08 +00008189 bp->chip_id = BNX2_RD(bp, BNX2_MISC_ID);
Michael Chanb6016b72005-05-26 13:03:09 -07008190
Michael Chan4ce45e02012-12-06 10:33:10 +00008191 if (BNX2_CHIP(bp) == BNX2_CHIP_5709) {
Jon Masone82760e2011-06-27 07:44:43 +00008192 if (!pci_is_pcie(pdev)) {
8193 dev_err(&pdev->dev, "Not PCIE, aborting\n");
Michael Chan883e5152007-05-03 13:25:11 -07008194 rc = -EIO;
8195 goto err_out_unmap;
8196 }
David S. Millerf86e82f2008-01-21 17:15:40 -08008197 bp->flags |= BNX2_FLAG_PCIE;
Michael Chan4ce45e02012-12-06 10:33:10 +00008198 if (BNX2_CHIP_REV(bp) == BNX2_CHIP_REV_Ax)
David S. Millerf86e82f2008-01-21 17:15:40 -08008199 bp->flags |= BNX2_FLAG_JUMBO_BROKEN;
Michael Chanc239f272010-10-11 16:12:28 -07008200
8201 /* AER (Advanced Error Reporting) hooks */
8202 err = pci_enable_pcie_error_reporting(pdev);
Michael Chan4bb9ebc2011-01-25 22:14:51 +00008203 if (!err)
8204 bp->flags |= BNX2_FLAG_AER_ENABLED;
Michael Chanc239f272010-10-11 16:12:28 -07008205
Michael Chan883e5152007-05-03 13:25:11 -07008206 } else {
Michael Chan59b47d82006-11-19 14:10:45 -08008207 bp->pcix_cap = pci_find_capability(pdev, PCI_CAP_ID_PCIX);
8208 if (bp->pcix_cap == 0) {
8209 dev_err(&pdev->dev,
Joe Perches3a9c6a42010-02-17 15:01:51 +00008210 "Cannot find PCIX capability, aborting\n");
Michael Chan59b47d82006-11-19 14:10:45 -08008211 rc = -EIO;
8212 goto err_out_unmap;
8213 }
Michael Chan61d9e3f2009-08-21 16:20:46 +00008214 bp->flags |= BNX2_FLAG_BROKEN_STATS;
Michael Chan59b47d82006-11-19 14:10:45 -08008215 }
8216
Michael Chan4ce45e02012-12-06 10:33:10 +00008217 if (BNX2_CHIP(bp) == BNX2_CHIP_5709 &&
8218 BNX2_CHIP_REV(bp) != BNX2_CHIP_REV_Ax) {
Yijing Wang555a8422013-08-08 21:02:22 +08008219 if (pdev->msix_cap)
David S. Millerf86e82f2008-01-21 17:15:40 -08008220 bp->flags |= BNX2_FLAG_MSIX_CAP;
Michael Chanb4b36042007-12-20 19:59:30 -08008221 }
8222
Michael Chan4ce45e02012-12-06 10:33:10 +00008223 if (BNX2_CHIP_ID(bp) != BNX2_CHIP_ID_5706_A0 &&
8224 BNX2_CHIP_ID(bp) != BNX2_CHIP_ID_5706_A1) {
Yijing Wang555a8422013-08-08 21:02:22 +08008225 if (pdev->msi_cap)
David S. Millerf86e82f2008-01-21 17:15:40 -08008226 bp->flags |= BNX2_FLAG_MSI_CAP;
Michael Chan8e6a72c2007-05-03 13:24:48 -07008227 }
8228
Michael Chan40453c82007-05-03 13:19:18 -07008229 /* 5708 cannot support DMA addresses > 40-bit. */
Michael Chan4ce45e02012-12-06 10:33:10 +00008230 if (BNX2_CHIP(bp) == BNX2_CHIP_5708)
Yang Hongyang50cf1562009-04-06 19:01:14 -07008231 persist_dma_mask = dma_mask = DMA_BIT_MASK(40);
Michael Chan40453c82007-05-03 13:19:18 -07008232 else
Yang Hongyang6a355282009-04-06 19:01:13 -07008233 persist_dma_mask = dma_mask = DMA_BIT_MASK(64);
Michael Chan40453c82007-05-03 13:19:18 -07008234
8235 /* Configure DMA attributes. */
8236 if (pci_set_dma_mask(pdev, dma_mask) == 0) {
8237 dev->features |= NETIF_F_HIGHDMA;
8238 rc = pci_set_consistent_dma_mask(pdev, persist_dma_mask);
8239 if (rc) {
8240 dev_err(&pdev->dev,
Joe Perches3a9c6a42010-02-17 15:01:51 +00008241 "pci_set_consistent_dma_mask failed, aborting\n");
Michael Chan40453c82007-05-03 13:19:18 -07008242 goto err_out_unmap;
8243 }
Yang Hongyang284901a2009-04-06 19:01:15 -07008244 } else if ((rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) != 0) {
Joe Perches3a9c6a42010-02-17 15:01:51 +00008245 dev_err(&pdev->dev, "System does not support DMA, aborting\n");
Michael Chan40453c82007-05-03 13:19:18 -07008246 goto err_out_unmap;
8247 }
8248
David S. Millerf86e82f2008-01-21 17:15:40 -08008249 if (!(bp->flags & BNX2_FLAG_PCIE))
Michael Chan883e5152007-05-03 13:25:11 -07008250 bnx2_get_pci_speed(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07008251
8252 /* 5706A0 may falsely detect SERR and PERR. */
Michael Chan4ce45e02012-12-06 10:33:10 +00008253 if (BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5706_A0) {
Michael Chane503e062012-12-06 10:33:08 +00008254 reg = BNX2_RD(bp, PCI_COMMAND);
Michael Chanb6016b72005-05-26 13:03:09 -07008255 reg &= ~(PCI_COMMAND_SERR | PCI_COMMAND_PARITY);
Michael Chane503e062012-12-06 10:33:08 +00008256 BNX2_WR(bp, PCI_COMMAND, reg);
Michael Chan4ce45e02012-12-06 10:33:10 +00008257 } else if ((BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5706_A1) &&
David S. Millerf86e82f2008-01-21 17:15:40 -08008258 !(bp->flags & BNX2_FLAG_PCIX)) {
Michael Chanb6016b72005-05-26 13:03:09 -07008259
Jeff Garzik9b91cf92006-06-27 11:39:50 -04008260 dev_err(&pdev->dev,
Joe Perches3a9c6a42010-02-17 15:01:51 +00008261 "5706 A1 can only be used in a PCIX bus, aborting\n");
Michael Chanb6016b72005-05-26 13:03:09 -07008262 goto err_out_unmap;
8263 }
8264
8265 bnx2_init_nvram(bp);
8266
Michael Chan2726d6e2008-01-29 21:35:05 -08008267 reg = bnx2_reg_rd_ind(bp, BNX2_SHM_HDR_SIGNATURE);
Michael Chane3648b32005-11-04 08:51:21 -08008268
Michael Chanaefd90e2012-06-16 15:45:43 +00008269 if (bnx2_reg_rd_ind(bp, BNX2_MCP_TOE_ID) & BNX2_MCP_TOE_ID_FUNCTION_ID)
8270 bp->func = 1;
8271
Michael Chane3648b32005-11-04 08:51:21 -08008272 if ((reg & BNX2_SHM_HDR_SIGNATURE_SIG_MASK) ==
Michael Chan24cb2302007-01-25 15:49:56 -08008273 BNX2_SHM_HDR_SIGNATURE_SIG) {
Michael Chanaefd90e2012-06-16 15:45:43 +00008274 u32 off = bp->func << 2;
Michael Chan24cb2302007-01-25 15:49:56 -08008275
Michael Chan2726d6e2008-01-29 21:35:05 -08008276 bp->shmem_base = bnx2_reg_rd_ind(bp, BNX2_SHM_HDR_ADDR_0 + off);
Michael Chan24cb2302007-01-25 15:49:56 -08008277 } else
Michael Chane3648b32005-11-04 08:51:21 -08008278 bp->shmem_base = HOST_VIEW_SHMEM_BASE;
8279
Michael Chanb6016b72005-05-26 13:03:09 -07008280 /* Get the permanent MAC address. First we need to make sure the
8281 * firmware is actually running.
8282 */
Michael Chan2726d6e2008-01-29 21:35:05 -08008283 reg = bnx2_shmem_rd(bp, BNX2_DEV_INFO_SIGNATURE);
Michael Chanb6016b72005-05-26 13:03:09 -07008284
8285 if ((reg & BNX2_DEV_INFO_SIGNATURE_MAGIC_MASK) !=
8286 BNX2_DEV_INFO_SIGNATURE_MAGIC) {
Joe Perches3a9c6a42010-02-17 15:01:51 +00008287 dev_err(&pdev->dev, "Firmware not running, aborting\n");
Michael Chanb6016b72005-05-26 13:03:09 -07008288 rc = -ENODEV;
8289 goto err_out_unmap;
8290 }
8291
Michael Chan76d99062009-12-03 09:46:34 +00008292 bnx2_read_vpd_fw_ver(bp);
8293
8294 j = strlen(bp->fw_version);
Michael Chan2726d6e2008-01-29 21:35:05 -08008295 reg = bnx2_shmem_rd(bp, BNX2_DEV_INFO_BC_REV);
Michael Chan76d99062009-12-03 09:46:34 +00008296 for (i = 0; i < 3 && j < 24; i++) {
Michael Chan58fc2ea2007-07-07 22:52:02 -07008297 u8 num, k, skip0;
8298
Michael Chan76d99062009-12-03 09:46:34 +00008299 if (i == 0) {
8300 bp->fw_version[j++] = 'b';
8301 bp->fw_version[j++] = 'c';
8302 bp->fw_version[j++] = ' ';
8303 }
Michael Chan58fc2ea2007-07-07 22:52:02 -07008304 num = (u8) (reg >> (24 - (i * 8)));
8305 for (k = 100, skip0 = 1; k >= 1; num %= k, k /= 10) {
8306 if (num >= k || !skip0 || k == 1) {
8307 bp->fw_version[j++] = (num / k) + '0';
8308 skip0 = 0;
8309 }
8310 }
8311 if (i != 2)
8312 bp->fw_version[j++] = '.';
8313 }
Michael Chan2726d6e2008-01-29 21:35:05 -08008314 reg = bnx2_shmem_rd(bp, BNX2_PORT_FEATURE);
Michael Chan846f5c62007-10-10 16:16:51 -07008315 if (reg & BNX2_PORT_FEATURE_WOL_ENABLED)
8316 bp->wol = 1;
8317
8318 if (reg & BNX2_PORT_FEATURE_ASF_ENABLED) {
David S. Millerf86e82f2008-01-21 17:15:40 -08008319 bp->flags |= BNX2_FLAG_ASF_ENABLE;
Michael Chanc2d3db82007-07-16 18:26:43 -07008320
8321 for (i = 0; i < 30; i++) {
Michael Chan2726d6e2008-01-29 21:35:05 -08008322 reg = bnx2_shmem_rd(bp, BNX2_BC_STATE_CONDITION);
Michael Chanc2d3db82007-07-16 18:26:43 -07008323 if (reg & BNX2_CONDITION_MFW_RUN_MASK)
8324 break;
8325 msleep(10);
8326 }
8327 }
Michael Chan2726d6e2008-01-29 21:35:05 -08008328 reg = bnx2_shmem_rd(bp, BNX2_BC_STATE_CONDITION);
Michael Chan58fc2ea2007-07-07 22:52:02 -07008329 reg &= BNX2_CONDITION_MFW_RUN_MASK;
8330 if (reg != BNX2_CONDITION_MFW_RUN_UNKNOWN &&
8331 reg != BNX2_CONDITION_MFW_RUN_NONE) {
Michael Chan2726d6e2008-01-29 21:35:05 -08008332 u32 addr = bnx2_shmem_rd(bp, BNX2_MFW_VER_PTR);
Michael Chan58fc2ea2007-07-07 22:52:02 -07008333
Michael Chan76d99062009-12-03 09:46:34 +00008334 if (j < 32)
8335 bp->fw_version[j++] = ' ';
8336 for (i = 0; i < 3 && j < 28; i++) {
Michael Chan2726d6e2008-01-29 21:35:05 -08008337 reg = bnx2_reg_rd_ind(bp, addr + i * 4);
Michael Chan3aeb7d22011-07-20 14:55:25 +00008338 reg = be32_to_cpu(reg);
Michael Chan58fc2ea2007-07-07 22:52:02 -07008339 memcpy(&bp->fw_version[j], &reg, 4);
8340 j += 4;
8341 }
8342 }
Michael Chanb6016b72005-05-26 13:03:09 -07008343
Michael Chan2726d6e2008-01-29 21:35:05 -08008344 reg = bnx2_shmem_rd(bp, BNX2_PORT_HW_CFG_MAC_UPPER);
Michael Chanb6016b72005-05-26 13:03:09 -07008345 bp->mac_addr[0] = (u8) (reg >> 8);
8346 bp->mac_addr[1] = (u8) reg;
8347
Michael Chan2726d6e2008-01-29 21:35:05 -08008348 reg = bnx2_shmem_rd(bp, BNX2_PORT_HW_CFG_MAC_LOWER);
Michael Chanb6016b72005-05-26 13:03:09 -07008349 bp->mac_addr[2] = (u8) (reg >> 24);
8350 bp->mac_addr[3] = (u8) (reg >> 16);
8351 bp->mac_addr[4] = (u8) (reg >> 8);
8352 bp->mac_addr[5] = (u8) reg;
8353
Michael Chan2bc40782012-12-06 10:33:09 +00008354 bp->tx_ring_size = BNX2_MAX_TX_DESC_CNT;
Michael Chan932f3772006-08-15 01:39:36 -07008355 bnx2_set_rx_ring_size(bp, 255);
Michael Chanb6016b72005-05-26 13:03:09 -07008356
Michael Chancf7474a2009-08-21 16:20:48 +00008357 bp->tx_quick_cons_trip_int = 2;
Michael Chanb6016b72005-05-26 13:03:09 -07008358 bp->tx_quick_cons_trip = 20;
Michael Chancf7474a2009-08-21 16:20:48 +00008359 bp->tx_ticks_int = 18;
Michael Chanb6016b72005-05-26 13:03:09 -07008360 bp->tx_ticks = 80;
Jeff Garzik6aa20a22006-09-13 13:24:59 -04008361
Michael Chancf7474a2009-08-21 16:20:48 +00008362 bp->rx_quick_cons_trip_int = 2;
8363 bp->rx_quick_cons_trip = 12;
Michael Chanb6016b72005-05-26 13:03:09 -07008364 bp->rx_ticks_int = 18;
8365 bp->rx_ticks = 18;
8366
Michael Chan7ea69202007-07-16 18:27:10 -07008367 bp->stats_ticks = USEC_PER_SEC & BNX2_HC_STATS_TICKS_HC_STAT_TICKS;
Michael Chanb6016b72005-05-26 13:03:09 -07008368
Benjamin Liac392ab2008-09-18 16:40:49 -07008369 bp->current_interval = BNX2_TIMER_INTERVAL;
Michael Chanb6016b72005-05-26 13:03:09 -07008370
Michael Chan5b0c76a2005-11-04 08:45:49 -08008371 bp->phy_addr = 1;
8372
wangweidong8fae3072015-10-08 18:03:47 +08008373 /* allocate stats_blk */
8374 rc = bnx2_alloc_stats_blk(dev);
8375 if (rc)
8376 goto err_out_unmap;
8377
Michael Chanb6016b72005-05-26 13:03:09 -07008378 /* Disable WOL support if we are running on a SERDES chip. */
Michael Chan4ce45e02012-12-06 10:33:10 +00008379 if (BNX2_CHIP(bp) == BNX2_CHIP_5709)
Michael Chan253c8b72007-01-08 19:56:01 -08008380 bnx2_get_5709_media(bp);
Michael Chan4ce45e02012-12-06 10:33:10 +00008381 else if (BNX2_CHIP_BOND(bp) & BNX2_CHIP_BOND_SERDES_BIT)
Michael Chan583c28e2008-01-21 19:51:35 -08008382 bp->phy_flags |= BNX2_PHY_FLAG_SERDES;
Michael Chanbac0dff2006-11-19 14:15:05 -08008383
Michael Chan0d8a6572007-07-07 22:49:43 -07008384 bp->phy_port = PORT_TP;
Michael Chan583c28e2008-01-21 19:51:35 -08008385 if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
Michael Chan0d8a6572007-07-07 22:49:43 -07008386 bp->phy_port = PORT_FIBRE;
Michael Chan2726d6e2008-01-29 21:35:05 -08008387 reg = bnx2_shmem_rd(bp, BNX2_SHARED_HW_CFG_CONFIG);
Michael Chan846f5c62007-10-10 16:16:51 -07008388 if (!(reg & BNX2_SHARED_HW_CFG_GIG_LINK_ON_VAUX)) {
David S. Millerf86e82f2008-01-21 17:15:40 -08008389 bp->flags |= BNX2_FLAG_NO_WOL;
Michael Chan846f5c62007-10-10 16:16:51 -07008390 bp->wol = 0;
8391 }
Michael Chan4ce45e02012-12-06 10:33:10 +00008392 if (BNX2_CHIP(bp) == BNX2_CHIP_5706) {
Michael Chan38ea3682008-02-23 19:48:57 -08008393 /* Don't do parallel detect on this board because of
8394 * some board problems. The link will not go down
8395 * if we do parallel detect.
8396 */
8397 if (pdev->subsystem_vendor == PCI_VENDOR_ID_HP &&
8398 pdev->subsystem_device == 0x310c)
8399 bp->phy_flags |= BNX2_PHY_FLAG_NO_PARALLEL;
8400 } else {
Michael Chan5b0c76a2005-11-04 08:45:49 -08008401 bp->phy_addr = 2;
Michael Chan5b0c76a2005-11-04 08:45:49 -08008402 if (reg & BNX2_SHARED_HW_CFG_PHY_2_5G)
Michael Chan583c28e2008-01-21 19:51:35 -08008403 bp->phy_flags |= BNX2_PHY_FLAG_2_5G_CAPABLE;
Michael Chan5b0c76a2005-11-04 08:45:49 -08008404 }
Michael Chan4ce45e02012-12-06 10:33:10 +00008405 } else if (BNX2_CHIP(bp) == BNX2_CHIP_5706 ||
8406 BNX2_CHIP(bp) == BNX2_CHIP_5708)
Michael Chan583c28e2008-01-21 19:51:35 -08008407 bp->phy_flags |= BNX2_PHY_FLAG_CRC_FIX;
Michael Chan4ce45e02012-12-06 10:33:10 +00008408 else if (BNX2_CHIP(bp) == BNX2_CHIP_5709 &&
8409 (BNX2_CHIP_REV(bp) == BNX2_CHIP_REV_Ax ||
8410 BNX2_CHIP_REV(bp) == BNX2_CHIP_REV_Bx))
Michael Chan583c28e2008-01-21 19:51:35 -08008411 bp->phy_flags |= BNX2_PHY_FLAG_DIS_EARLY_DAC;
Michael Chanb6016b72005-05-26 13:03:09 -07008412
Michael Chan7c62e832008-07-14 22:39:03 -07008413 bnx2_init_fw_cap(bp);
8414
Michael Chan4ce45e02012-12-06 10:33:10 +00008415 if ((BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5708_A0) ||
8416 (BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5708_B0) ||
8417 (BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5708_B1) ||
Michael Chane503e062012-12-06 10:33:08 +00008418 !(BNX2_RD(bp, BNX2_PCI_CONFIG_3) & BNX2_PCI_CONFIG_3_VAUX_PRESET)) {
David S. Millerf86e82f2008-01-21 17:15:40 -08008419 bp->flags |= BNX2_FLAG_NO_WOL;
Michael Chan846f5c62007-10-10 16:16:51 -07008420 bp->wol = 0;
8421 }
Michael Chandda1e392006-01-23 16:08:14 -08008422
Michael Chan6d5e85c2013-08-06 15:50:08 -07008423 if (bp->flags & BNX2_FLAG_NO_WOL)
8424 device_set_wakeup_capable(&bp->pdev->dev, false);
8425 else
8426 device_set_wakeup_enable(&bp->pdev->dev, bp->wol);
8427
Michael Chan4ce45e02012-12-06 10:33:10 +00008428 if (BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5706_A0) {
Michael Chanb6016b72005-05-26 13:03:09 -07008429 bp->tx_quick_cons_trip_int =
8430 bp->tx_quick_cons_trip;
8431 bp->tx_ticks_int = bp->tx_ticks;
8432 bp->rx_quick_cons_trip_int =
8433 bp->rx_quick_cons_trip;
8434 bp->rx_ticks_int = bp->rx_ticks;
8435 bp->comp_prod_trip_int = bp->comp_prod_trip;
8436 bp->com_ticks_int = bp->com_ticks;
8437 bp->cmd_ticks_int = bp->cmd_ticks;
8438 }
8439
Michael Chanf9317a42006-09-29 17:06:23 -07008440 /* Disable MSI on 5706 if AMD 8132 bridge is found.
8441 *
8442 * MSI is defined to be 32-bit write. The 5706 does 64-bit MSI writes
8443 * with byte enables disabled on the unused 32-bit word. This is legal
8444 * but causes problems on the AMD 8132 which will eventually stop
8445 * responding after a while.
8446 *
8447 * AMD believes this incompatibility is unique to the 5706, and
Michael Ellerman88187df2007-01-25 19:34:07 +11008448 * prefers to locally disable MSI rather than globally disabling it.
Michael Chanf9317a42006-09-29 17:06:23 -07008449 */
Michael Chan4ce45e02012-12-06 10:33:10 +00008450 if (BNX2_CHIP(bp) == BNX2_CHIP_5706 && disable_msi == 0) {
Michael Chanf9317a42006-09-29 17:06:23 -07008451 struct pci_dev *amd_8132 = NULL;
8452
8453 while ((amd_8132 = pci_get_device(PCI_VENDOR_ID_AMD,
8454 PCI_DEVICE_ID_AMD_8132_BRIDGE,
8455 amd_8132))) {
Michael Chanf9317a42006-09-29 17:06:23 -07008456
Auke Kok44c10132007-06-08 15:46:36 -07008457 if (amd_8132->revision >= 0x10 &&
8458 amd_8132->revision <= 0x13) {
Michael Chanf9317a42006-09-29 17:06:23 -07008459 disable_msi = 1;
8460 pci_dev_put(amd_8132);
8461 break;
8462 }
8463 }
8464 }
8465
Michael Chandeaf3912007-07-07 22:48:00 -07008466 bnx2_set_default_link(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07008467 bp->req_flow_ctrl = FLOW_CTRL_RX | FLOW_CTRL_TX;
8468
Michael Chancd339a02005-08-25 15:35:24 -07008469 init_timer(&bp->timer);
Benjamin Liac392ab2008-09-18 16:40:49 -07008470 bp->timer.expires = RUN_AT(BNX2_TIMER_INTERVAL);
Michael Chancd339a02005-08-25 15:35:24 -07008471 bp->timer.data = (unsigned long) bp;
8472 bp->timer.function = bnx2_timer;
8473
Michael Chan7625eb22011-06-08 19:29:36 +00008474#ifdef BCM_CNIC
Michael Chan41c21782011-07-13 17:24:22 +00008475 if (bnx2_shmem_rd(bp, BNX2_ISCSI_INITIATOR) & BNX2_ISCSI_INITIATOR_EN)
8476 bp->cnic_eth_dev.max_iscsi_conn =
8477 (bnx2_shmem_rd(bp, BNX2_ISCSI_MAX_CONN) &
8478 BNX2_ISCSI_MAX_CONN_MASK) >> BNX2_ISCSI_MAX_CONN_SHIFT;
Michael Chan4bd9b0ff2012-12-06 10:33:12 +00008479 bp->cnic_probe = bnx2_cnic_probe;
Michael Chan7625eb22011-06-08 19:29:36 +00008480#endif
Michael Chanc239f272010-10-11 16:12:28 -07008481 pci_save_state(pdev);
8482
Michael Chanb6016b72005-05-26 13:03:09 -07008483 return 0;
8484
8485err_out_unmap:
Michael Chan4bb9ebc2011-01-25 22:14:51 +00008486 if (bp->flags & BNX2_FLAG_AER_ENABLED) {
Michael Chanc239f272010-10-11 16:12:28 -07008487 pci_disable_pcie_error_reporting(pdev);
Michael Chan4bb9ebc2011-01-25 22:14:51 +00008488 bp->flags &= ~BNX2_FLAG_AER_ENABLED;
8489 }
Michael Chanc239f272010-10-11 16:12:28 -07008490
Francois Romieuc0357e92012-03-09 14:51:47 +01008491 pci_iounmap(pdev, bp->regview);
8492 bp->regview = NULL;
Michael Chanb6016b72005-05-26 13:03:09 -07008493
8494err_out_release:
8495 pci_release_regions(pdev);
8496
8497err_out_disable:
8498 pci_disable_device(pdev);
Michael Chanb6016b72005-05-26 13:03:09 -07008499
8500err_out:
wangweidong3703ebe2015-10-13 10:05:19 +08008501 kfree(bp->temp_stats_blk);
8502
Michael Chanb6016b72005-05-26 13:03:09 -07008503 return rc;
8504}
8505
Bill Pembertoncfd95a62012-12-03 09:22:58 -05008506static char *
Michael Chan883e5152007-05-03 13:25:11 -07008507bnx2_bus_string(struct bnx2 *bp, char *str)
8508{
8509 char *s = str;
8510
David S. Millerf86e82f2008-01-21 17:15:40 -08008511 if (bp->flags & BNX2_FLAG_PCIE) {
Michael Chan883e5152007-05-03 13:25:11 -07008512 s += sprintf(s, "PCI Express");
8513 } else {
8514 s += sprintf(s, "PCI");
David S. Millerf86e82f2008-01-21 17:15:40 -08008515 if (bp->flags & BNX2_FLAG_PCIX)
Michael Chan883e5152007-05-03 13:25:11 -07008516 s += sprintf(s, "-X");
David S. Millerf86e82f2008-01-21 17:15:40 -08008517 if (bp->flags & BNX2_FLAG_PCI_32BIT)
Michael Chan883e5152007-05-03 13:25:11 -07008518 s += sprintf(s, " 32-bit");
8519 else
8520 s += sprintf(s, " 64-bit");
8521 s += sprintf(s, " %dMHz", bp->bus_speed_mhz);
8522 }
8523 return str;
8524}
8525
Michael Chanf048fa92010-06-01 15:05:36 +00008526static void
8527bnx2_del_napi(struct bnx2 *bp)
8528{
8529 int i;
8530
8531 for (i = 0; i < bp->irq_nvecs; i++)
8532 netif_napi_del(&bp->bnx2_napi[i].napi);
8533}
8534
8535static void
Michael Chan35efa7c2007-12-20 19:56:37 -08008536bnx2_init_napi(struct bnx2 *bp)
8537{
Michael Chanb4b36042007-12-20 19:59:30 -08008538 int i;
Michael Chan35efa7c2007-12-20 19:56:37 -08008539
Benjamin Li4327ba42010-03-23 13:13:11 +00008540 for (i = 0; i < bp->irq_nvecs; i++) {
Michael Chan35e90102008-06-19 16:37:42 -07008541 struct bnx2_napi *bnapi = &bp->bnx2_napi[i];
8542 int (*poll)(struct napi_struct *, int);
8543
8544 if (i == 0)
8545 poll = bnx2_poll;
8546 else
Michael Chanf0ea2e62008-06-19 16:41:57 -07008547 poll = bnx2_poll_msix;
Michael Chan35e90102008-06-19 16:37:42 -07008548
8549 netif_napi_add(bp->dev, &bp->bnx2_napi[i].napi, poll, 64);
Michael Chanb4b36042007-12-20 19:59:30 -08008550 bnapi->bp = bp;
8551 }
Michael Chan35efa7c2007-12-20 19:56:37 -08008552}
8553
Stephen Hemminger0421eae2008-11-21 17:31:27 -08008554static const struct net_device_ops bnx2_netdev_ops = {
8555 .ndo_open = bnx2_open,
8556 .ndo_start_xmit = bnx2_start_xmit,
8557 .ndo_stop = bnx2_close,
Eric Dumazet5d07bf22010-07-08 04:08:43 +00008558 .ndo_get_stats64 = bnx2_get_stats64,
Stephen Hemminger0421eae2008-11-21 17:31:27 -08008559 .ndo_set_rx_mode = bnx2_set_rx_mode,
8560 .ndo_do_ioctl = bnx2_ioctl,
8561 .ndo_validate_addr = eth_validate_addr,
8562 .ndo_set_mac_address = bnx2_change_mac_addr,
8563 .ndo_change_mtu = bnx2_change_mtu,
Michał Mirosław8d7dfc22011-04-10 04:47:46 +00008564 .ndo_set_features = bnx2_set_features,
Stephen Hemminger0421eae2008-11-21 17:31:27 -08008565 .ndo_tx_timeout = bnx2_tx_timeout,
Alexey Dobriyan257ddbd2010-01-27 10:17:41 +00008566#ifdef CONFIG_NET_POLL_CONTROLLER
Stephen Hemminger0421eae2008-11-21 17:31:27 -08008567 .ndo_poll_controller = poll_bnx2,
8568#endif
8569};
8570
Bill Pembertoncfd95a62012-12-03 09:22:58 -05008571static int
Michael Chanb6016b72005-05-26 13:03:09 -07008572bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
8573{
8574 static int version_printed = 0;
Francois Romieuc0357e92012-03-09 14:51:47 +01008575 struct net_device *dev;
Michael Chanb6016b72005-05-26 13:03:09 -07008576 struct bnx2 *bp;
Joe Perches0795af52007-10-03 17:59:30 -07008577 int rc;
Michael Chan883e5152007-05-03 13:25:11 -07008578 char str[40];
Michael Chanb6016b72005-05-26 13:03:09 -07008579
8580 if (version_printed++ == 0)
Joe Perches3a9c6a42010-02-17 15:01:51 +00008581 pr_info("%s", version);
Michael Chanb6016b72005-05-26 13:03:09 -07008582
8583 /* dev zeroed in init_etherdev */
Benjamin Li706bf242008-07-18 17:55:11 -07008584 dev = alloc_etherdev_mq(sizeof(*bp), TX_MAX_RINGS);
Michael Chanb6016b72005-05-26 13:03:09 -07008585 if (!dev)
8586 return -ENOMEM;
8587
8588 rc = bnx2_init_board(pdev, dev);
Francois Romieuc0357e92012-03-09 14:51:47 +01008589 if (rc < 0)
8590 goto err_free;
Michael Chanb6016b72005-05-26 13:03:09 -07008591
Stephen Hemminger0421eae2008-11-21 17:31:27 -08008592 dev->netdev_ops = &bnx2_netdev_ops;
Michael Chanb6016b72005-05-26 13:03:09 -07008593 dev->watchdog_timeo = TX_TIMEOUT;
Michael Chanb6016b72005-05-26 13:03:09 -07008594 dev->ethtool_ops = &bnx2_ethtool_ops;
Michael Chanb6016b72005-05-26 13:03:09 -07008595
Michael Chan972ec0d2006-01-23 16:12:43 -08008596 bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07008597
Michael Chan1b2f9222007-05-03 13:20:19 -07008598 pci_set_drvdata(pdev, dev);
8599
Baoquan He6df77862016-11-13 13:01:33 +08008600 /*
8601 * In-flight DMA from 1st kernel could continue going in kdump kernel.
8602 * New io-page table has been created before bnx2 does reset at open stage.
8603 * We have to wait for the in-flight DMA to complete to avoid it look up
8604 * into the newly created io-page table.
8605 */
8606 if (is_kdump_kernel())
8607 bnx2_wait_dma_complete(bp);
8608
Joe Perchesd458cdf2013-10-01 19:04:40 -07008609 memcpy(dev->dev_addr, bp->mac_addr, ETH_ALEN);
Michael Chan1b2f9222007-05-03 13:20:19 -07008610
Michał Mirosław8d7dfc22011-04-10 04:47:46 +00008611 dev->hw_features = NETIF_F_IP_CSUM | NETIF_F_SG |
8612 NETIF_F_TSO | NETIF_F_TSO_ECN |
8613 NETIF_F_RXHASH | NETIF_F_RXCSUM;
8614
Michael Chan4ce45e02012-12-06 10:33:10 +00008615 if (BNX2_CHIP(bp) == BNX2_CHIP_5709)
Michał Mirosław8d7dfc22011-04-10 04:47:46 +00008616 dev->hw_features |= NETIF_F_IPV6_CSUM | NETIF_F_TSO6;
8617
8618 dev->vlan_features = dev->hw_features;
Patrick McHardyf6469682013-04-19 02:04:27 +00008619 dev->hw_features |= NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX;
Michał Mirosław8d7dfc22011-04-10 04:47:46 +00008620 dev->features |= dev->hw_features;
Jiri Pirko01789342011-08-16 06:29:00 +00008621 dev->priv_flags |= IFF_UNICAST_FLT;
Michał Mirosław8d7dfc22011-04-10 04:47:46 +00008622
Ivan Vecera26caa342015-02-26 14:48:07 +01008623 if (!(bp->flags & BNX2_FLAG_CAN_KEEP_VLAN))
8624 dev->hw_features &= ~NETIF_F_HW_VLAN_CTAG_RX;
8625
Michael Chanb6016b72005-05-26 13:03:09 -07008626 if ((rc = register_netdev(dev))) {
Jeff Garzik9b91cf92006-06-27 11:39:50 -04008627 dev_err(&pdev->dev, "Cannot register net device\n");
Michael Chan57579f72009-04-04 16:51:14 -07008628 goto error;
Michael Chanb6016b72005-05-26 13:03:09 -07008629 }
8630
Francois Romieuc0357e92012-03-09 14:51:47 +01008631 netdev_info(dev, "%s (%c%d) %s found at mem %lx, IRQ %d, "
8632 "node addr %pM\n", board_info[ent->driver_data].name,
Michael Chan4ce45e02012-12-06 10:33:10 +00008633 ((BNX2_CHIP_ID(bp) & 0xf000) >> 12) + 'A',
8634 ((BNX2_CHIP_ID(bp) & 0x0ff0) >> 4),
Francois Romieuc0357e92012-03-09 14:51:47 +01008635 bnx2_bus_string(bp, str), (long)pci_resource_start(pdev, 0),
8636 pdev->irq, dev->dev_addr);
Michael Chanb6016b72005-05-26 13:03:09 -07008637
Michael Chanb6016b72005-05-26 13:03:09 -07008638 return 0;
Michael Chan57579f72009-04-04 16:51:14 -07008639
8640error:
Michael Chanfda4d852012-12-11 18:24:20 -08008641 pci_iounmap(pdev, bp->regview);
Michael Chan57579f72009-04-04 16:51:14 -07008642 pci_release_regions(pdev);
8643 pci_disable_device(pdev);
Francois Romieuc0357e92012-03-09 14:51:47 +01008644err_free:
wangweidong8fae3072015-10-08 18:03:47 +08008645 bnx2_free_stats_blk(dev);
Michael Chan57579f72009-04-04 16:51:14 -07008646 free_netdev(dev);
8647 return rc;
Michael Chanb6016b72005-05-26 13:03:09 -07008648}
8649
Bill Pembertoncfd95a62012-12-03 09:22:58 -05008650static void
Michael Chanb6016b72005-05-26 13:03:09 -07008651bnx2_remove_one(struct pci_dev *pdev)
8652{
8653 struct net_device *dev = pci_get_drvdata(pdev);
Michael Chan972ec0d2006-01-23 16:12:43 -08008654 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07008655
8656 unregister_netdev(dev);
8657
Neil Horman8333a462011-04-26 10:30:11 +00008658 del_timer_sync(&bp->timer);
Michael Chancd634012011-07-15 06:53:58 +00008659 cancel_work_sync(&bp->reset_task);
Neil Horman8333a462011-04-26 10:30:11 +00008660
Francois Romieuc0357e92012-03-09 14:51:47 +01008661 pci_iounmap(bp->pdev, bp->regview);
Michael Chanb6016b72005-05-26 13:03:09 -07008662
wangweidong8fae3072015-10-08 18:03:47 +08008663 bnx2_free_stats_blk(dev);
Michael Chan354fcd72010-01-17 07:30:44 +00008664 kfree(bp->temp_stats_blk);
8665
Michael Chan4bb9ebc2011-01-25 22:14:51 +00008666 if (bp->flags & BNX2_FLAG_AER_ENABLED) {
Michael Chanc239f272010-10-11 16:12:28 -07008667 pci_disable_pcie_error_reporting(pdev);
Michael Chan4bb9ebc2011-01-25 22:14:51 +00008668 bp->flags &= ~BNX2_FLAG_AER_ENABLED;
8669 }
John Feeneycd709aa2010-08-22 17:45:53 +00008670
françois romieu7880b722011-09-30 00:36:52 +00008671 bnx2_release_firmware(bp);
8672
Michael Chanc239f272010-10-11 16:12:28 -07008673 free_netdev(dev);
John Feeneycd709aa2010-08-22 17:45:53 +00008674
Michael Chanb6016b72005-05-26 13:03:09 -07008675 pci_release_regions(pdev);
8676 pci_disable_device(pdev);
Michael Chanb6016b72005-05-26 13:03:09 -07008677}
8678
Daniel J Blueman77d149c2014-04-11 16:14:26 +08008679#ifdef CONFIG_PM_SLEEP
Michael Chanb6016b72005-05-26 13:03:09 -07008680static int
Michael Chan28fb4eb2013-08-06 15:50:10 -07008681bnx2_suspend(struct device *device)
Michael Chanb6016b72005-05-26 13:03:09 -07008682{
Michael Chan28fb4eb2013-08-06 15:50:10 -07008683 struct pci_dev *pdev = to_pci_dev(device);
Michael Chanb6016b72005-05-26 13:03:09 -07008684 struct net_device *dev = pci_get_drvdata(pdev);
Michael Chan972ec0d2006-01-23 16:12:43 -08008685 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07008686
Michael Chan28fb4eb2013-08-06 15:50:10 -07008687 if (netif_running(dev)) {
8688 cancel_work_sync(&bp->reset_task);
8689 bnx2_netif_stop(bp, true);
8690 netif_device_detach(dev);
8691 del_timer_sync(&bp->timer);
8692 bnx2_shutdown_chip(bp);
8693 __bnx2_free_irq(bp);
8694 bnx2_free_skbs(bp);
8695 }
8696 bnx2_setup_wol(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07008697 return 0;
8698}
8699
8700static int
Michael Chan28fb4eb2013-08-06 15:50:10 -07008701bnx2_resume(struct device *device)
Michael Chanb6016b72005-05-26 13:03:09 -07008702{
Michael Chan28fb4eb2013-08-06 15:50:10 -07008703 struct pci_dev *pdev = to_pci_dev(device);
Michael Chanb6016b72005-05-26 13:03:09 -07008704 struct net_device *dev = pci_get_drvdata(pdev);
Michael Chan972ec0d2006-01-23 16:12:43 -08008705 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07008706
8707 if (!netif_running(dev))
8708 return 0;
8709
Pavel Machek829ca9a2005-09-03 15:56:56 -07008710 bnx2_set_power_state(bp, PCI_D0);
Michael Chanb6016b72005-05-26 13:03:09 -07008711 netif_device_attach(dev);
Michael Chan28fb4eb2013-08-06 15:50:10 -07008712 bnx2_request_irq(bp);
Michael Chan9a120bc2008-05-16 22:17:45 -07008713 bnx2_init_nic(bp, 1);
Michael Chan212f9932010-04-27 11:28:10 +00008714 bnx2_netif_start(bp, true);
Michael Chanb6016b72005-05-26 13:03:09 -07008715 return 0;
8716}
8717
Michael Chan28fb4eb2013-08-06 15:50:10 -07008718static SIMPLE_DEV_PM_OPS(bnx2_pm_ops, bnx2_suspend, bnx2_resume);
8719#define BNX2_PM_OPS (&bnx2_pm_ops)
8720
8721#else
8722
8723#define BNX2_PM_OPS NULL
8724
8725#endif /* CONFIG_PM_SLEEP */
Wendy Xiong6ff2da42008-05-16 22:18:21 -07008726/**
8727 * bnx2_io_error_detected - called when PCI error is detected
8728 * @pdev: Pointer to PCI device
8729 * @state: The current pci connection state
8730 *
8731 * This function is called after a PCI bus error affecting
8732 * this device has been detected.
8733 */
8734static pci_ers_result_t bnx2_io_error_detected(struct pci_dev *pdev,
8735 pci_channel_state_t state)
8736{
8737 struct net_device *dev = pci_get_drvdata(pdev);
8738 struct bnx2 *bp = netdev_priv(dev);
8739
8740 rtnl_lock();
8741 netif_device_detach(dev);
8742
Dean Nelson2ec3de22009-07-31 09:13:18 +00008743 if (state == pci_channel_io_perm_failure) {
8744 rtnl_unlock();
8745 return PCI_ERS_RESULT_DISCONNECT;
8746 }
8747
Wendy Xiong6ff2da42008-05-16 22:18:21 -07008748 if (netif_running(dev)) {
Michael Chan212f9932010-04-27 11:28:10 +00008749 bnx2_netif_stop(bp, true);
Wendy Xiong6ff2da42008-05-16 22:18:21 -07008750 del_timer_sync(&bp->timer);
8751 bnx2_reset_nic(bp, BNX2_DRV_MSG_CODE_RESET);
8752 }
8753
8754 pci_disable_device(pdev);
8755 rtnl_unlock();
8756
8757 /* Request a slot slot reset. */
8758 return PCI_ERS_RESULT_NEED_RESET;
8759}
8760
8761/**
8762 * bnx2_io_slot_reset - called after the pci bus has been reset.
8763 * @pdev: Pointer to PCI device
8764 *
8765 * Restart the card from scratch, as if from a cold-boot.
8766 */
8767static pci_ers_result_t bnx2_io_slot_reset(struct pci_dev *pdev)
8768{
8769 struct net_device *dev = pci_get_drvdata(pdev);
8770 struct bnx2 *bp = netdev_priv(dev);
Michael Chan02481bc2013-08-06 15:50:07 -07008771 pci_ers_result_t result = PCI_ERS_RESULT_DISCONNECT;
8772 int err = 0;
Wendy Xiong6ff2da42008-05-16 22:18:21 -07008773
8774 rtnl_lock();
8775 if (pci_enable_device(pdev)) {
8776 dev_err(&pdev->dev,
Joe Perches3a9c6a42010-02-17 15:01:51 +00008777 "Cannot re-enable PCI device after reset\n");
John Feeneycd709aa2010-08-22 17:45:53 +00008778 } else {
8779 pci_set_master(pdev);
8780 pci_restore_state(pdev);
8781 pci_save_state(pdev);
Wendy Xiong6ff2da42008-05-16 22:18:21 -07008782
Michael Chan25bfb1d2013-08-06 15:50:11 -07008783 if (netif_running(dev))
Michael Chan02481bc2013-08-06 15:50:07 -07008784 err = bnx2_init_nic(bp, 1);
Michael Chan25bfb1d2013-08-06 15:50:11 -07008785
Michael Chan02481bc2013-08-06 15:50:07 -07008786 if (!err)
8787 result = PCI_ERS_RESULT_RECOVERED;
8788 }
8789
8790 if (result != PCI_ERS_RESULT_RECOVERED && netif_running(dev)) {
8791 bnx2_napi_enable(bp);
8792 dev_close(dev);
Wendy Xiong6ff2da42008-05-16 22:18:21 -07008793 }
Wendy Xiong6ff2da42008-05-16 22:18:21 -07008794 rtnl_unlock();
John Feeneycd709aa2010-08-22 17:45:53 +00008795
Michael Chan4bb9ebc2011-01-25 22:14:51 +00008796 if (!(bp->flags & BNX2_FLAG_AER_ENABLED))
Michael Chanc239f272010-10-11 16:12:28 -07008797 return result;
8798
John Feeneycd709aa2010-08-22 17:45:53 +00008799 err = pci_cleanup_aer_uncorrect_error_status(pdev);
8800 if (err) {
8801 dev_err(&pdev->dev,
8802 "pci_cleanup_aer_uncorrect_error_status failed 0x%0x\n",
8803 err); /* non-fatal, continue */
8804 }
8805
8806 return result;
Wendy Xiong6ff2da42008-05-16 22:18:21 -07008807}
8808
8809/**
8810 * bnx2_io_resume - called when traffic can start flowing again.
8811 * @pdev: Pointer to PCI device
8812 *
8813 * This callback is called when the error recovery driver tells us that
8814 * its OK to resume normal operation.
8815 */
8816static void bnx2_io_resume(struct pci_dev *pdev)
8817{
8818 struct net_device *dev = pci_get_drvdata(pdev);
8819 struct bnx2 *bp = netdev_priv(dev);
8820
8821 rtnl_lock();
8822 if (netif_running(dev))
Michael Chan212f9932010-04-27 11:28:10 +00008823 bnx2_netif_start(bp, true);
Wendy Xiong6ff2da42008-05-16 22:18:21 -07008824
8825 netif_device_attach(dev);
8826 rtnl_unlock();
8827}
8828
Michael Chan25bfb1d2013-08-06 15:50:11 -07008829static void bnx2_shutdown(struct pci_dev *pdev)
8830{
8831 struct net_device *dev = pci_get_drvdata(pdev);
8832 struct bnx2 *bp;
8833
8834 if (!dev)
8835 return;
8836
8837 bp = netdev_priv(dev);
8838 if (!bp)
8839 return;
8840
8841 rtnl_lock();
8842 if (netif_running(dev))
8843 dev_close(bp->dev);
8844
8845 if (system_state == SYSTEM_POWER_OFF)
8846 bnx2_set_power_state(bp, PCI_D3hot);
8847
8848 rtnl_unlock();
8849}
8850
Michael Chanfda4d852012-12-11 18:24:20 -08008851static const struct pci_error_handlers bnx2_err_handler = {
Wendy Xiong6ff2da42008-05-16 22:18:21 -07008852 .error_detected = bnx2_io_error_detected,
8853 .slot_reset = bnx2_io_slot_reset,
8854 .resume = bnx2_io_resume,
8855};
8856
Michael Chanb6016b72005-05-26 13:03:09 -07008857static struct pci_driver bnx2_pci_driver = {
Peter Hagervall14ab9b82005-08-10 14:18:16 -07008858 .name = DRV_MODULE_NAME,
8859 .id_table = bnx2_pci_tbl,
8860 .probe = bnx2_init_one,
Bill Pembertoncfd95a62012-12-03 09:22:58 -05008861 .remove = bnx2_remove_one,
Michael Chan28fb4eb2013-08-06 15:50:10 -07008862 .driver.pm = BNX2_PM_OPS,
Wendy Xiong6ff2da42008-05-16 22:18:21 -07008863 .err_handler = &bnx2_err_handler,
Michael Chan25bfb1d2013-08-06 15:50:11 -07008864 .shutdown = bnx2_shutdown,
Michael Chanb6016b72005-05-26 13:03:09 -07008865};
8866
Peter Hüwe5a4123f2013-05-21 12:58:05 +00008867module_pci_driver(bnx2_pci_driver);