if_bce.c revision 204371
1157642Sps/*-
2189117Sdavidch * Copyright (c) 2006-2009 Broadcom Corporation
3157642Sps *	David Christensen <davidch@broadcom.com>.  All rights reserved.
4157642Sps *
5157642Sps * Redistribution and use in source and binary forms, with or without
6157642Sps * modification, are permitted provided that the following conditions
7157642Sps * are met:
8157642Sps *
9157642Sps * 1. Redistributions of source code must retain the above copyright
10157642Sps *    notice, this list of conditions and the following disclaimer.
11157642Sps * 2. Redistributions in binary form must reproduce the above copyright
12157642Sps *    notice, this list of conditions and the following disclaimer in the
13157642Sps *    documentation and/or other materials provided with the distribution.
14157642Sps * 3. Neither the name of Broadcom Corporation nor the name of its contributors
15157642Sps *    may be used to endorse or promote products derived from this software
16157642Sps *    without specific prior written consent.
17157642Sps *
18157642Sps * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS'
19157642Sps * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20157642Sps * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21157642Sps * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
22157642Sps * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23157642Sps * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24157642Sps * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25157642Sps * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26157642Sps * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27157642Sps * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
28157642Sps * THE POSSIBILITY OF SUCH DAMAGE.
29157642Sps */
30157642Sps
31157642Sps#include <sys/cdefs.h>
32157642Sps__FBSDID("$FreeBSD: head/sys/dev/bce/if_bce.c 204371 2010-02-26 20:39:07Z yongari $");
33157642Sps
34157642Sps/*
35157642Sps * The following controllers are supported by this driver:
36157642Sps *   BCM5706C A2, A3
37176448Sdavidch *   BCM5706S A2, A3
38169271Sdavidch *   BCM5708C B1, B2
39176448Sdavidch *   BCM5708S B1, B2
40182293Sdavidch *   BCM5709C A1, C0
41189325Sdavidch * 	 BCM5716C C0
42157642Sps *
43157642Sps * The following controllers are not supported by this driver:
44176448Sdavidch *   BCM5706C A0, A1 (pre-production)
45176448Sdavidch *   BCM5706S A0, A1 (pre-production)
46176448Sdavidch *   BCM5708C A0, B0 (pre-production)
47176448Sdavidch *   BCM5708S A0, B0 (pre-production)
48179771Sdavidch *   BCM5709C A0  B0, B1, B2 (pre-production)
49179771Sdavidch *   BCM5709S A0, A1, B0, B1, B2, C0 (pre-production)
50157642Sps */
51157642Sps
52157643Sps#include "opt_bce.h"
53157643Sps
54157642Sps#include <dev/bce/if_bcereg.h>
55157642Sps#include <dev/bce/if_bcefw.h>
56157642Sps
57157642Sps/****************************************************************************/
58157642Sps/* BCE Debug Options                                                        */
59157642Sps/****************************************************************************/
60157642Sps#ifdef BCE_DEBUG
61157642Sps	u32 bce_debug = BCE_WARN;
62157642Sps
63157642Sps	/*          0 = Never              */
64157642Sps	/*          1 = 1 in 2,147,483,648 */
65157642Sps	/*        256 = 1 in     8,388,608 */
66157642Sps	/*       2048 = 1 in     1,048,576 */
67157642Sps	/*      65536 = 1 in        32,768 */
68157642Sps	/*    1048576 = 1 in         2,048 */
69157642Sps	/*  268435456 =	1 in             8 */
70157642Sps	/*  536870912 = 1 in             4 */
71157642Sps	/* 1073741824 = 1 in             2 */
72157642Sps
73157642Sps	/* Controls how often the l2_fhdr frame error check will fail. */
74189325Sdavidch	int l2fhdr_error_sim_control = 0;
75157642Sps
76157642Sps	/* Controls how often the unexpected attention check will fail. */
77189325Sdavidch	int unexpected_attention_sim_control = 0;
78157642Sps
79157642Sps	/* Controls how often to simulate an mbuf allocation failure. */
80189325Sdavidch	int mbuf_alloc_failed_sim_control = 0;
81157642Sps
82157642Sps	/* Controls how often to simulate a DMA mapping failure. */
83189325Sdavidch	int dma_map_addr_failed_sim_control = 0;
84157642Sps
85157642Sps	/* Controls how often to simulate a bootcode failure. */
86189325Sdavidch	int bootcode_running_failure_sim_control = 0;
87157642Sps#endif
88178132Sdavidch
89179695Sdavidch/****************************************************************************/
90179695Sdavidch/* BCE Build Time Options                                                   */
91179695Sdavidch/****************************************************************************/
92179695Sdavidch/* #define BCE_NVRAM_WRITE_SUPPORT 1 */
93178132Sdavidch
94182293Sdavidch
95157642Sps/****************************************************************************/
96157642Sps/* PCI Device ID Table                                                      */
97157642Sps/*                                                                          */
98157642Sps/* Used by bce_probe() to identify the devices supported by this driver.    */
99157642Sps/****************************************************************************/
100157642Sps#define BCE_DEVDESC_MAX		64
101157642Sps
102157642Spsstatic struct bce_type bce_devs[] = {
103157642Sps	/* BCM5706C Controllers and OEM boards. */
104157642Sps	{ BRCM_VENDORID, BRCM_DEVICEID_BCM5706,  HP_VENDORID, 0x3101,
105157642Sps		"HP NC370T Multifunction Gigabit Server Adapter" },
106157642Sps	{ BRCM_VENDORID, BRCM_DEVICEID_BCM5706,  HP_VENDORID, 0x3106,
107157642Sps		"HP NC370i Multifunction Gigabit Server Adapter" },
108187133Sdelphij	{ BRCM_VENDORID, BRCM_DEVICEID_BCM5706,  HP_VENDORID, 0x3070,
109187317Sdelphij		"HP NC380T PCIe DP Multifunc Gig Server Adapter" },
110187317Sdelphij	{ BRCM_VENDORID, BRCM_DEVICEID_BCM5706,  HP_VENDORID, 0x1709,
111187317Sdelphij		"HP NC371i Multifunction Gigabit Server Adapter" },
112157642Sps	{ BRCM_VENDORID, BRCM_DEVICEID_BCM5706,  PCI_ANY_ID,  PCI_ANY_ID,
113157642Sps		"Broadcom NetXtreme II BCM5706 1000Base-T" },
114157642Sps
115157642Sps	/* BCM5706S controllers and OEM boards. */
116157642Sps	{ BRCM_VENDORID, BRCM_DEVICEID_BCM5706S, HP_VENDORID, 0x3102,
117157642Sps		"HP NC370F Multifunction Gigabit Server Adapter" },
118157642Sps	{ BRCM_VENDORID, BRCM_DEVICEID_BCM5706S, PCI_ANY_ID,  PCI_ANY_ID,
119157642Sps		"Broadcom NetXtreme II BCM5706 1000Base-SX" },
120157642Sps
121157642Sps	/* BCM5708C controllers and OEM boards. */
122187133Sdelphij	{ BRCM_VENDORID, BRCM_DEVICEID_BCM5708,  HP_VENDORID, 0x7037,
123187317Sdelphij		"HP NC373T PCIe Multifunction Gig Server Adapter" },
124187133Sdelphij	{ BRCM_VENDORID, BRCM_DEVICEID_BCM5708,  HP_VENDORID, 0x7038,
125187317Sdelphij		"HP NC373i Multifunction Gigabit Server Adapter" },
126187317Sdelphij	{ BRCM_VENDORID, BRCM_DEVICEID_BCM5708,  HP_VENDORID, 0x7045,
127187317Sdelphij		"HP NC374m PCIe Multifunction Adapter" },
128157642Sps	{ BRCM_VENDORID, BRCM_DEVICEID_BCM5708,  PCI_ANY_ID,  PCI_ANY_ID,
129157642Sps		"Broadcom NetXtreme II BCM5708 1000Base-T" },
130157642Sps
131157642Sps	/* BCM5708S controllers and OEM boards. */
132187133Sdelphij	{ BRCM_VENDORID, BRCM_DEVICEID_BCM5708S,  HP_VENDORID, 0x1706,
133187317Sdelphij		"HP NC373m Multifunction Gigabit Server Adapter" },
134187133Sdelphij	{ BRCM_VENDORID, BRCM_DEVICEID_BCM5708S,  HP_VENDORID, 0x703b,
135187317Sdelphij		"HP NC373i Multifunction Gigabit Server Adapter" },
136187133Sdelphij	{ BRCM_VENDORID, BRCM_DEVICEID_BCM5708S,  HP_VENDORID, 0x703d,
137187317Sdelphij		"HP NC373F PCIe Multifunc Giga Server Adapter" },
138163814Sscottl	{ BRCM_VENDORID, BRCM_DEVICEID_BCM5708S,  PCI_ANY_ID,  PCI_ANY_ID,
139170392Sdavidch		"Broadcom NetXtreme II BCM5708 1000Base-SX" },
140179771Sdavidch
141179771Sdavidch	/* BCM5709C controllers and OEM boards. */
142187133Sdelphij	{ BRCM_VENDORID, BRCM_DEVICEID_BCM5709,  HP_VENDORID, 0x7055,
143187317Sdelphij		"HP NC382i DP Multifunction Gigabit Server Adapter" },
144187133Sdelphij	{ BRCM_VENDORID, BRCM_DEVICEID_BCM5709,  HP_VENDORID, 0x7059,
145187317Sdelphij		"HP NC382T PCIe DP Multifunction Gigabit Server Adapter" },
146179771Sdavidch	{ BRCM_VENDORID, BRCM_DEVICEID_BCM5709,  PCI_ANY_ID,  PCI_ANY_ID,
147179771Sdavidch		"Broadcom NetXtreme II BCM5709 1000Base-T" },
148179771Sdavidch
149179771Sdavidch	/* BCM5709S controllers and OEM boards. */
150187133Sdelphij	{ BRCM_VENDORID, BRCM_DEVICEID_BCM5709S,  HP_VENDORID, 0x171d,
151187317Sdelphij		"HP NC382m DP 1GbE Multifunction BL-c Adapter" },
152187133Sdelphij	{ BRCM_VENDORID, BRCM_DEVICEID_BCM5709S,  HP_VENDORID, 0x7056,
153187317Sdelphij		"HP NC382i DP Multifunction Gigabit Server Adapter" },
154179771Sdavidch	{ BRCM_VENDORID, BRCM_DEVICEID_BCM5709S,  PCI_ANY_ID,  PCI_ANY_ID,
155179771Sdavidch		"Broadcom NetXtreme II BCM5709 1000Base-SX" },
156179771Sdavidch
157179771Sdavidch	/* BCM5716 controllers and OEM boards. */
158179771Sdavidch	{ BRCM_VENDORID, BRCM_DEVICEID_BCM5716,  PCI_ANY_ID,  PCI_ANY_ID,
159179771Sdavidch		"Broadcom NetXtreme II BCM5716 1000Base-T" },
160179771Sdavidch
161157642Sps	{ 0, 0, 0, 0, NULL }
162157642Sps};
163157642Sps
164157642Sps
165157642Sps/****************************************************************************/
166157642Sps/* Supported Flash NVRAM device data.                                       */
167157642Sps/****************************************************************************/
168157642Spsstatic struct flash_spec flash_table[] =
169157642Sps{
170179771Sdavidch#define BUFFERED_FLAGS		(BCE_NV_BUFFERED | BCE_NV_TRANSLATE)
171179771Sdavidch#define NONBUFFERED_FLAGS	(BCE_NV_WREN)
172179771Sdavidch
173157642Sps	/* Slow EEPROM */
174157642Sps	{0x00000000, 0x40830380, 0x009f0081, 0xa184a053, 0xaf000400,
175179771Sdavidch	 BUFFERED_FLAGS, SEEPROM_PAGE_BITS, SEEPROM_PAGE_SIZE,
176157642Sps	 SEEPROM_BYTE_ADDR_MASK, SEEPROM_TOTAL_SIZE,
177157642Sps	 "EEPROM - slow"},
178157642Sps	/* Expansion entry 0001 */
179157642Sps	{0x08000002, 0x4b808201, 0x00050081, 0x03840253, 0xaf020406,
180179771Sdavidch	 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
181157642Sps	 SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
182157642Sps	 "Entry 0001"},
183157642Sps	/* Saifun SA25F010 (non-buffered flash) */
184157642Sps	/* strap, cfg1, & write1 need updates */
185157642Sps	{0x04000001, 0x47808201, 0x00050081, 0x03840253, 0xaf020406,
186179771Sdavidch	 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
187157642Sps	 SAIFUN_FLASH_BYTE_ADDR_MASK, SAIFUN_FLASH_BASE_TOTAL_SIZE*2,
188157642Sps	 "Non-buffered flash (128kB)"},
189157642Sps	/* Saifun SA25F020 (non-buffered flash) */
190157642Sps	/* strap, cfg1, & write1 need updates */
191157642Sps	{0x0c000003, 0x4f808201, 0x00050081, 0x03840253, 0xaf020406,
192179771Sdavidch	 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
193157642Sps	 SAIFUN_FLASH_BYTE_ADDR_MASK, SAIFUN_FLASH_BASE_TOTAL_SIZE*4,
194157642Sps	 "Non-buffered flash (256kB)"},
195157642Sps	/* Expansion entry 0100 */
196157642Sps	{0x11000000, 0x53808201, 0x00050081, 0x03840253, 0xaf020406,
197179771Sdavidch	 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
198157642Sps	 SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
199157642Sps	 "Entry 0100"},
200157642Sps	/* Entry 0101: ST M45PE10 (non-buffered flash, TetonII B0) */
201157642Sps	{0x19000002, 0x5b808201, 0x000500db, 0x03840253, 0xaf020406,
202179771Sdavidch	 NONBUFFERED_FLAGS, ST_MICRO_FLASH_PAGE_BITS, ST_MICRO_FLASH_PAGE_SIZE,
203157642Sps	 ST_MICRO_FLASH_BYTE_ADDR_MASK, ST_MICRO_FLASH_BASE_TOTAL_SIZE*2,
204157642Sps	 "Entry 0101: ST M45PE10 (128kB non-bufferred)"},
205157642Sps	/* Entry 0110: ST M45PE20 (non-buffered flash)*/
206157642Sps	{0x15000001, 0x57808201, 0x000500db, 0x03840253, 0xaf020406,
207179771Sdavidch	 NONBUFFERED_FLAGS, ST_MICRO_FLASH_PAGE_BITS, ST_MICRO_FLASH_PAGE_SIZE,
208157642Sps	 ST_MICRO_FLASH_BYTE_ADDR_MASK, ST_MICRO_FLASH_BASE_TOTAL_SIZE*4,
209157642Sps	 "Entry 0110: ST M45PE20 (256kB non-bufferred)"},
210157642Sps	/* Saifun SA25F005 (non-buffered flash) */
211157642Sps	/* strap, cfg1, & write1 need updates */
212157642Sps	{0x1d000003, 0x5f808201, 0x00050081, 0x03840253, 0xaf020406,
213179771Sdavidch	 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
214157642Sps	 SAIFUN_FLASH_BYTE_ADDR_MASK, SAIFUN_FLASH_BASE_TOTAL_SIZE,
215157642Sps	 "Non-buffered flash (64kB)"},
216157642Sps	/* Fast EEPROM */
217157642Sps	{0x22000000, 0x62808380, 0x009f0081, 0xa184a053, 0xaf000400,
218179771Sdavidch	 BUFFERED_FLAGS, SEEPROM_PAGE_BITS, SEEPROM_PAGE_SIZE,
219157642Sps	 SEEPROM_BYTE_ADDR_MASK, SEEPROM_TOTAL_SIZE,
220157642Sps	 "EEPROM - fast"},
221157642Sps	/* Expansion entry 1001 */
222157642Sps	{0x2a000002, 0x6b808201, 0x00050081, 0x03840253, 0xaf020406,
223179771Sdavidch	 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
224157642Sps	 SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
225157642Sps	 "Entry 1001"},
226157642Sps	/* Expansion entry 1010 */
227157642Sps	{0x26000001, 0x67808201, 0x00050081, 0x03840253, 0xaf020406,
228179771Sdavidch	 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
229157642Sps	 SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
230157642Sps	 "Entry 1010"},
231157642Sps	/* ATMEL AT45DB011B (buffered flash) */
232157642Sps	{0x2e000003, 0x6e808273, 0x00570081, 0x68848353, 0xaf000400,
233179771Sdavidch	 BUFFERED_FLAGS, BUFFERED_FLASH_PAGE_BITS, BUFFERED_FLASH_PAGE_SIZE,
234157642Sps	 BUFFERED_FLASH_BYTE_ADDR_MASK, BUFFERED_FLASH_TOTAL_SIZE,
235157642Sps	 "Buffered flash (128kB)"},
236157642Sps	/* Expansion entry 1100 */
237157642Sps	{0x33000000, 0x73808201, 0x00050081, 0x03840253, 0xaf020406,
238179771Sdavidch	 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
239157642Sps	 SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
240157642Sps	 "Entry 1100"},
241157642Sps	/* Expansion entry 1101 */
242157642Sps	{0x3b000002, 0x7b808201, 0x00050081, 0x03840253, 0xaf020406,
243179771Sdavidch	 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
244157642Sps	 SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
245157642Sps	 "Entry 1101"},
246157642Sps	/* Ateml Expansion entry 1110 */
247157642Sps	{0x37000001, 0x76808273, 0x00570081, 0x68848353, 0xaf000400,
248179771Sdavidch	 BUFFERED_FLAGS, BUFFERED_FLASH_PAGE_BITS, BUFFERED_FLASH_PAGE_SIZE,
249157642Sps	 BUFFERED_FLASH_BYTE_ADDR_MASK, 0,
250157642Sps	 "Entry 1110 (Atmel)"},
251157642Sps	/* ATMEL AT45DB021B (buffered flash) */
252157642Sps	{0x3f000003, 0x7e808273, 0x00570081, 0x68848353, 0xaf000400,
253179771Sdavidch	 BUFFERED_FLAGS, BUFFERED_FLASH_PAGE_BITS, BUFFERED_FLASH_PAGE_SIZE,
254157642Sps	 BUFFERED_FLASH_BYTE_ADDR_MASK, BUFFERED_FLASH_TOTAL_SIZE*2,
255157642Sps	 "Buffered flash (256kB)"},
256157642Sps};
257157642Sps
258179771Sdavidch/*
259179771Sdavidch * The BCM5709 controllers transparently handle the
260179771Sdavidch * differences between Atmel 264 byte pages and all
261179771Sdavidch * flash devices which use 256 byte pages, so no
262179771Sdavidch * logical-to-physical mapping is required in the
263179771Sdavidch * driver.
264179771Sdavidch */
265179771Sdavidchstatic struct flash_spec flash_5709 = {
266179771Sdavidch	.flags		= BCE_NV_BUFFERED,
267179771Sdavidch	.page_bits	= BCM5709_FLASH_PAGE_BITS,
268179771Sdavidch	.page_size	= BCM5709_FLASH_PAGE_SIZE,
269179771Sdavidch	.addr_mask	= BCM5709_FLASH_BYTE_ADDR_MASK,
270179771Sdavidch	.total_size	= BUFFERED_FLASH_TOTAL_SIZE * 2,
271182293Sdavidch	.name		= "5709/5716 buffered flash (256kB)",
272179771Sdavidch};
273157642Sps
274179771Sdavidch
275157642Sps/****************************************************************************/
276157642Sps/* FreeBSD device entry points.                                             */
277157642Sps/****************************************************************************/
278157642Spsstatic int  bce_probe				(device_t);
279157642Spsstatic int  bce_attach				(device_t);
280157642Spsstatic int  bce_detach				(device_t);
281173839Syongaristatic int  bce_shutdown			(device_t);
282157642Sps
283157642Sps
284157642Sps/****************************************************************************/
285157642Sps/* BCE Debug Data Structure Dump Routines                                   */
286157642Sps/****************************************************************************/
287157642Sps#ifdef BCE_DEBUG
288179771Sdavidchstatic u32	bce_reg_rd				(struct bce_softc *, u32);
289179771Sdavidchstatic void	bce_reg_wr				(struct bce_softc *, u32, u32);
290179771Sdavidchstatic void	bce_reg_wr16			(struct bce_softc *, u32, u16);
291176448Sdavidchstatic u32  bce_ctx_rd				(struct bce_softc *, u32, u32);
292182293Sdavidchstatic void bce_dump_enet           (struct bce_softc *, struct mbuf *);
293157642Spsstatic void bce_dump_mbuf 			(struct bce_softc *, struct mbuf *);
294176448Sdavidchstatic void bce_dump_tx_mbuf_chain	(struct bce_softc *, u16, int);
295176448Sdavidchstatic void bce_dump_rx_mbuf_chain	(struct bce_softc *, u16, int);
296198320Sstas#ifdef BCE_JUMBO_HDRSPLIT
297179771Sdavidchstatic void bce_dump_pg_mbuf_chain	(struct bce_softc *, u16, int);
298179695Sdavidch#endif
299157642Spsstatic void bce_dump_txbd			(struct bce_softc *, int, struct tx_bd *);
300157642Spsstatic void bce_dump_rxbd			(struct bce_softc *, int, struct rx_bd *);
301198320Sstas#ifdef BCE_JUMBO_HDRSPLIT
302179771Sdavidchstatic void bce_dump_pgbd			(struct bce_softc *, int, struct rx_bd *);
303179695Sdavidch#endif
304157642Spsstatic void bce_dump_l2fhdr			(struct bce_softc *, int, struct l2_fhdr *);
305176448Sdavidchstatic void bce_dump_ctx			(struct bce_softc *, u16);
306176448Sdavidchstatic void bce_dump_ftqs			(struct bce_softc *);
307176448Sdavidchstatic void bce_dump_tx_chain		(struct bce_softc *, u16, int);
308176448Sdavidchstatic void bce_dump_rx_chain		(struct bce_softc *, u16, int);
309198320Sstas#ifdef BCE_JUMBO_HDRSPLIT
310179771Sdavidchstatic void bce_dump_pg_chain		(struct bce_softc *, u16, int);
311179695Sdavidch#endif
312157642Spsstatic void bce_dump_status_block	(struct bce_softc *);
313157642Spsstatic void bce_dump_stats_block	(struct bce_softc *);
314157642Spsstatic void bce_dump_driver_state	(struct bce_softc *);
315157642Spsstatic void bce_dump_hw_state		(struct bce_softc *);
316179771Sdavidchstatic void bce_dump_mq_regs        (struct bce_softc *);
317170810Sdavidchstatic void bce_dump_bc_state		(struct bce_softc *);
318179771Sdavidchstatic void bce_dump_txp_state		(struct bce_softc *, int);
319179771Sdavidchstatic void bce_dump_rxp_state		(struct bce_softc *, int);
320179771Sdavidchstatic void bce_dump_tpat_state		(struct bce_softc *, int);
321179771Sdavidchstatic void bce_dump_cp_state		(struct bce_softc *, int);
322179771Sdavidchstatic void bce_dump_com_state		(struct bce_softc *, int);
323157642Spsstatic void bce_breakpoint			(struct bce_softc *);
324157642Sps#endif
325157642Sps
326157642Sps
327157642Sps/****************************************************************************/
328157642Sps/* BCE Register/Memory Access Routines                                      */
329157642Sps/****************************************************************************/
330157642Spsstatic u32  bce_reg_rd_ind			(struct bce_softc *, u32);
331157642Spsstatic void bce_reg_wr_ind			(struct bce_softc *, u32, u32);
332194781Sdavidchstatic void bce_shmem_wr            (struct bce_softc *, u32, u32);
333194781Sdavidchstatic u32  bce_shmem_rd            (struct bce_softc *, u32);
334157642Spsstatic void bce_ctx_wr				(struct bce_softc *, u32, u32, u32);
335157642Spsstatic int  bce_miibus_read_reg		(device_t, int, int);
336157642Spsstatic int  bce_miibus_write_reg	(device_t, int, int, int);
337157642Spsstatic void bce_miibus_statchg		(device_t);
338157642Sps
339157642Sps
340157642Sps/****************************************************************************/
341157642Sps/* BCE NVRAM Access Routines                                                */
342157642Sps/****************************************************************************/
343157642Spsstatic int  bce_acquire_nvram_lock	(struct bce_softc *);
344157642Spsstatic int  bce_release_nvram_lock	(struct bce_softc *);
345157642Spsstatic void bce_enable_nvram_access	(struct bce_softc *);
346157642Spsstatic void	bce_disable_nvram_access(struct bce_softc *);
347157642Spsstatic int  bce_nvram_read_dword	(struct bce_softc *, u32, u8 *, u32);
348157642Spsstatic int  bce_init_nvram			(struct bce_softc *);
349157642Spsstatic int  bce_nvram_read			(struct bce_softc *, u32, u8 *, int);
350157642Spsstatic int  bce_nvram_test			(struct bce_softc *);
351157642Sps#ifdef BCE_NVRAM_WRITE_SUPPORT
352157642Spsstatic int  bce_enable_nvram_write	(struct bce_softc *);
353157642Spsstatic void bce_disable_nvram_write	(struct bce_softc *);
354157642Spsstatic int  bce_nvram_erase_page	(struct bce_softc *, u32);
355157642Spsstatic int  bce_nvram_write_dword	(struct bce_softc *, u32, u8 *, u32);
356157642Spsstatic int  bce_nvram_write			(struct bce_softc *, u32, u8 *, int);
357157642Sps#endif
358157642Sps
359157642Sps/****************************************************************************/
360157642Sps/*                                                                          */
361157642Sps/****************************************************************************/
362179771Sdavidchstatic void bce_get_media			(struct bce_softc *);
363157642Spsstatic void bce_dma_map_addr		(void *, bus_dma_segment_t *, int, int);
364157642Spsstatic int  bce_dma_alloc			(device_t);
365157642Spsstatic void bce_dma_free			(struct bce_softc *);
366157642Spsstatic void bce_release_resources	(struct bce_softc *);
367157642Sps
368157642Sps/****************************************************************************/
369157642Sps/* BCE Firmware Synchronization and Load                                    */
370157642Sps/****************************************************************************/
371157642Spsstatic int  bce_fw_sync				(struct bce_softc *, u32);
372157642Spsstatic void bce_load_rv2p_fw		(struct bce_softc *, u32 *, u32, u32);
373157642Spsstatic void bce_load_cpu_fw			(struct bce_softc *, struct cpu_reg *, struct fw_info *);
374202717Sdavidchstatic void bce_start_cpu           (struct bce_softc *, struct cpu_reg *);
375202717Sdavidchstatic void bce_halt_cpu            (struct bce_softc *, struct cpu_reg *);
376202717Sdavidchstatic void bce_start_rxp_cpu       (struct bce_softc *);
377179771Sdavidchstatic void bce_init_rxp_cpu		(struct bce_softc *);
378179771Sdavidchstatic void bce_init_txp_cpu 		(struct bce_softc *);
379179771Sdavidchstatic void bce_init_tpat_cpu		(struct bce_softc *);
380179771Sdavidchstatic void bce_init_cp_cpu		  	(struct bce_softc *);
381179771Sdavidchstatic void bce_init_com_cpu	  	(struct bce_softc *);
382157642Spsstatic void bce_init_cpus			(struct bce_softc *);
383157642Sps
384179771Sdavidchstatic void	bce_print_adapter_info	(struct bce_softc *);
385179771Sdavidchstatic void bce_probe_pci_caps		(device_t, struct bce_softc *);
386157642Spsstatic void bce_stop				(struct bce_softc *);
387157642Spsstatic int  bce_reset				(struct bce_softc *, u32);
388157642Spsstatic int  bce_chipinit 			(struct bce_softc *);
389157642Spsstatic int  bce_blockinit 			(struct bce_softc *);
390157642Sps
391157642Spsstatic int  bce_init_tx_chain		(struct bce_softc *);
392176448Sdavidchstatic void bce_free_tx_chain		(struct bce_softc *);
393176448Sdavidch
394179771Sdavidchstatic int  bce_get_rx_buf			(struct bce_softc *, struct mbuf *, u16 *, u16 *, u32 *);
395176448Sdavidchstatic int  bce_init_rx_chain		(struct bce_softc *);
396171667Sdavidchstatic void bce_fill_rx_chain		(struct bce_softc *);
397157642Spsstatic void bce_free_rx_chain		(struct bce_softc *);
398179771Sdavidch
399198320Sstas#ifdef BCE_JUMBO_HDRSPLIT
400179771Sdavidchstatic int  bce_get_pg_buf			(struct bce_softc *, struct mbuf *, u16 *, u16 *);
401176448Sdavidchstatic int  bce_init_pg_chain		(struct bce_softc *);
402176448Sdavidchstatic void bce_fill_pg_chain		(struct bce_softc *);
403179771Sdavidchstatic void bce_free_pg_chain		(struct bce_softc *);
404179695Sdavidch#endif
405176448Sdavidch
406171667Sdavidchstatic int  bce_tx_encap			(struct bce_softc *, struct mbuf **);
407157642Spsstatic void bce_start_locked		(struct ifnet *);
408157642Spsstatic void bce_start				(struct ifnet *);
409157642Spsstatic int  bce_ioctl				(struct ifnet *, u_long, caddr_t);
410165933Sdelphijstatic void bce_watchdog			(struct bce_softc *);
411157642Spsstatic int  bce_ifmedia_upd			(struct ifnet *);
412171667Sdavidchstatic void bce_ifmedia_upd_locked	(struct ifnet *);
413157642Spsstatic void bce_ifmedia_sts			(struct ifnet *, struct ifmediareq *);
414157642Spsstatic void bce_init_locked			(struct bce_softc *);
415157642Spsstatic void bce_init				(void *);
416171667Sdavidchstatic void bce_mgmt_init_locked	(struct bce_softc *sc);
417157642Sps
418176448Sdavidchstatic void bce_init_ctx			(struct bce_softc *);
419157642Spsstatic void bce_get_mac_addr		(struct bce_softc *);
420157642Spsstatic void bce_set_mac_addr		(struct bce_softc *);
421157642Spsstatic void bce_phy_intr			(struct bce_softc *);
422176448Sdavidchstatic inline u16 bce_get_hw_rx_cons(struct bce_softc *);
423157642Spsstatic void bce_rx_intr				(struct bce_softc *);
424157642Spsstatic void bce_tx_intr				(struct bce_softc *);
425157642Spsstatic void bce_disable_intr		(struct bce_softc *);
426179771Sdavidchstatic void bce_enable_intr			(struct bce_softc *, int);
427179771Sdavidch
428157642Spsstatic void bce_intr				(void *);
429157642Spsstatic void bce_set_rx_mode			(struct bce_softc *);
430157642Spsstatic void bce_stats_update		(struct bce_softc *);
431157642Spsstatic void bce_tick				(void *);
432170810Sdavidchstatic void bce_pulse				(void *);
433157642Spsstatic void bce_add_sysctls			(struct bce_softc *);
434157642Sps
435157642Sps
436157642Sps/****************************************************************************/
437157642Sps/* FreeBSD device dispatch table.                                           */
438157642Sps/****************************************************************************/
439157642Spsstatic device_method_t bce_methods[] = {
440176448Sdavidch	/* Device interface (device_if.h) */
441157642Sps	DEVMETHOD(device_probe,		bce_probe),
442157642Sps	DEVMETHOD(device_attach,	bce_attach),
443157642Sps	DEVMETHOD(device_detach,	bce_detach),
444157642Sps	DEVMETHOD(device_shutdown,	bce_shutdown),
445178132Sdavidch/* Supported by device interface but not used here. */
446176448Sdavidch/*	DEVMETHOD(device_identify,	bce_identify),      */
447176448Sdavidch/*	DEVMETHOD(device_suspend,	bce_suspend),       */
448176448Sdavidch/*	DEVMETHOD(device_resume,	bce_resume),        */
449176448Sdavidch/*	DEVMETHOD(device_quiesce,	bce_quiesce),       */
450157642Sps
451176448Sdavidch	/* Bus interface (bus_if.h) */
452157642Sps	DEVMETHOD(bus_print_child,	bus_generic_print_child),
453157642Sps	DEVMETHOD(bus_driver_added,	bus_generic_driver_added),
454157642Sps
455176448Sdavidch	/* MII interface (miibus_if.h) */
456157642Sps	DEVMETHOD(miibus_readreg,	bce_miibus_read_reg),
457157642Sps	DEVMETHOD(miibus_writereg,	bce_miibus_write_reg),
458157642Sps	DEVMETHOD(miibus_statchg,	bce_miibus_statchg),
459178132Sdavidch/* Supported by MII interface but not used here.       */
460176448Sdavidch/*	DEVMETHOD(miibus_linkchg,	bce_miibus_linkchg),   */
461176448Sdavidch/*	DEVMETHOD(miibus_mediainit,	bce_miibus_mediainit), */
462157642Sps
463157642Sps	{ 0, 0 }
464157642Sps};
465157642Sps
466157642Spsstatic driver_t bce_driver = {
467157642Sps	"bce",
468157642Sps	bce_methods,
469157642Sps	sizeof(struct bce_softc)
470157642Sps};
471157642Sps
472157642Spsstatic devclass_t bce_devclass;
473157642Sps
474157642SpsMODULE_DEPEND(bce, pci, 1, 1, 1);
475157642SpsMODULE_DEPEND(bce, ether, 1, 1, 1);
476157642SpsMODULE_DEPEND(bce, miibus, 1, 1, 1);
477157642Sps
478157642SpsDRIVER_MODULE(bce, pci, bce_driver, bce_devclass, 0, 0);
479157642SpsDRIVER_MODULE(miibus, bce, miibus_driver, miibus_devclass, 0, 0);
480170392Sdavidch
481170392Sdavidch
482169632Sdavidch/****************************************************************************/
483169632Sdavidch/* Tunable device values                                                    */
484169632Sdavidch/****************************************************************************/
485176448SdavidchSYSCTL_NODE(_hw, OID_AUTO, bce, CTLFLAG_RD, 0, "bce driver parameters");
486176448Sdavidch
487170392Sdavidch/* Allowable values are TRUE or FALSE */
488179771Sdavidchstatic int bce_tso_enable = TRUE;
489170392SdavidchTUNABLE_INT("hw.bce.tso_enable", &bce_tso_enable);
490176448SdavidchSYSCTL_UINT(_hw_bce, OID_AUTO, tso_enable, CTLFLAG_RDTUN, &bce_tso_enable, 0,
491176448Sdavidch"TSO Enable/Disable");
492176448Sdavidch
493179771Sdavidch/* Allowable values are 0 (IRQ), 1 (MSI/IRQ), and 2 (MSI-X/MSI/IRQ) */
494179771Sdavidch/* ToDo: Add MSI-X support. */
495179771Sdavidchstatic int bce_msi_enable = 1;
496169632SdavidchTUNABLE_INT("hw.bce.msi_enable", &bce_msi_enable);
497170392SdavidchSYSCTL_UINT(_hw_bce, OID_AUTO, msi_enable, CTLFLAG_RDTUN, &bce_msi_enable, 0,
498179771Sdavidch"MSI-X|MSI|INTx selector");
499178132Sdavidch
500178132Sdavidch/* ToDo: Add tunable to enable/disable strict MTU handling. */
501178132Sdavidch/* Currently allows "loose" RX MTU checking (i.e. sets the  */
502182293Sdavidch/* H/W RX MTU to the size of the largest receive buffer, or */
503189325Sdavidch/* 2048 bytes). This will cause a UNH failure but is more   */
504189325Sdavidch/* desireable from a functional perspective.                */
505170392Sdavidch
506182293Sdavidch
507157642Sps/****************************************************************************/
508157642Sps/* Device probe function.                                                   */
509157642Sps/*                                                                          */
510157642Sps/* Compares the device to the driver's list of supported devices and        */
511157642Sps/* reports back to the OS whether this is the right driver for the device.  */
512157642Sps/*                                                                          */
513157642Sps/* Returns:                                                                 */
514157642Sps/*   BUS_PROBE_DEFAULT on success, positive value on failure.               */
515157642Sps/****************************************************************************/
516157642Spsstatic int
517157642Spsbce_probe(device_t dev)
518157642Sps{
519157642Sps	struct bce_type *t;
520157642Sps	struct bce_softc *sc;
521157642Sps	char *descbuf;
522157642Sps	u16 vid = 0, did = 0, svid = 0, sdid = 0;
523157642Sps
524157642Sps	t = bce_devs;
525157642Sps
526157642Sps	sc = device_get_softc(dev);
527157642Sps	bzero(sc, sizeof(struct bce_softc));
528157642Sps	sc->bce_unit = device_get_unit(dev);
529157642Sps	sc->bce_dev = dev;
530157642Sps
531157642Sps	/* Get the data for the device to be probed. */
532157642Sps	vid  = pci_get_vendor(dev);
533157642Sps	did  = pci_get_device(dev);
534157642Sps	svid = pci_get_subvendor(dev);
535157642Sps	sdid = pci_get_subdevice(dev);
536157642Sps
537179771Sdavidch	DBPRINT(sc, BCE_EXTREME_LOAD,
538157642Sps		"%s(); VID = 0x%04X, DID = 0x%04X, SVID = 0x%04X, "
539157642Sps		"SDID = 0x%04X\n", __FUNCTION__, vid, did, svid, sdid);
540157642Sps
541157642Sps	/* Look through the list of known devices for a match. */
542157642Sps	while(t->bce_name != NULL) {
543157642Sps
544179771Sdavidch		if ((vid == t->bce_vid) && (did == t->bce_did) &&
545157642Sps			((svid == t->bce_svid) || (t->bce_svid == PCI_ANY_ID)) &&
546157642Sps			((sdid == t->bce_sdid) || (t->bce_sdid == PCI_ANY_ID))) {
547157642Sps
548157642Sps			descbuf = malloc(BCE_DEVDESC_MAX, M_TEMP, M_NOWAIT);
549157642Sps
550157642Sps			if (descbuf == NULL)
551157642Sps				return(ENOMEM);
552157642Sps
553157642Sps			/* Print out the device identity. */
554179771Sdavidch			snprintf(descbuf, BCE_DEVDESC_MAX, "%s (%c%d)",
555157642Sps				t->bce_name,
556157642Sps			    (((pci_read_config(dev, PCIR_REVID, 4) & 0xf0) >> 4) + 'A'),
557169271Sdavidch			    (pci_read_config(dev, PCIR_REVID, 4) & 0xf));
558157642Sps
559157642Sps			device_set_desc_copy(dev, descbuf);
560157642Sps			free(descbuf, M_TEMP);
561157642Sps			return(BUS_PROBE_DEFAULT);
562157642Sps		}
563157642Sps		t++;
564157642Sps	}
565157642Sps
566157642Sps	return(ENXIO);
567157642Sps}
568157642Sps
569157642Sps
570157642Sps/****************************************************************************/
571179771Sdavidch/* PCI Capabilities Probe Function.                                         */
572179771Sdavidch/*                                                                          */
573179771Sdavidch/* Walks the PCI capabiites list for the device to find what features are   */
574179771Sdavidch/* supported.                                                               */
575179771Sdavidch/*                                                                          */
576179771Sdavidch/* Returns:                                                                 */
577179771Sdavidch/*   None.                                                                  */
578179771Sdavidch/****************************************************************************/
579179771Sdavidchstatic void
580179771Sdavidchbce_print_adapter_info(struct bce_softc *sc)
581179771Sdavidch{
582194781Sdavidch    int i = 0;
583194781Sdavidch
584179771Sdavidch	DBENTER(BCE_VERBOSE_LOAD);
585179771Sdavidch
586179771Sdavidch	BCE_PRINTF("ASIC (0x%08X); ", sc->bce_chipid);
587179771Sdavidch	printf("Rev (%c%d); ", ((BCE_CHIP_ID(sc) & 0xf000) >> 12) + 'A',
588179771Sdavidch		((BCE_CHIP_ID(sc) & 0x0ff0) >> 4));
589179771Sdavidch
590179771Sdavidch	/* Bus info. */
591179771Sdavidch	if (sc->bce_flags & BCE_PCIE_FLAG) {
592179771Sdavidch		printf("Bus (PCIe x%d, ", sc->link_width);
593179771Sdavidch		switch (sc->link_speed) {
594179771Sdavidch			case 1: printf("2.5Gbps); "); break;
595179771Sdavidch			case 2:	printf("5Gbps); "); break;
596179771Sdavidch			default: printf("Unknown link speed); ");
597179771Sdavidch		}
598179771Sdavidch	} else {
599179771Sdavidch		printf("Bus (PCI%s, %s, %dMHz); ",
600179771Sdavidch			((sc->bce_flags & BCE_PCIX_FLAG) ? "-X" : ""),
601179771Sdavidch			((sc->bce_flags & BCE_PCI_32BIT_FLAG) ? "32-bit" : "64-bit"),
602179771Sdavidch			sc->bus_speed_mhz);
603179771Sdavidch	}
604179771Sdavidch
605179771Sdavidch	/* Firmware version and device features. */
606194781Sdavidch	printf("B/C (%s); Flags (", sc->bce_bc_ver);
607194781Sdavidch
608198320Sstas#ifdef BCE_JUMBO_HDRSPLIT
609202717Sdavidch	printf("SPLT");
610194781Sdavidch    i++;
611179771Sdavidch#endif
612202717Sdavidch
613194781Sdavidch    if (sc->bce_flags & BCE_USING_MSI_FLAG) {
614194781Sdavidch        if (i > 0) printf("|");
615196970Sphk		printf("MSI"); i++;
616194781Sdavidch    }
617179771Sdavidch
618194781Sdavidch    if (sc->bce_flags & BCE_USING_MSIX_FLAG) {
619194781Sdavidch        if (i > 0) printf("|");
620202717Sdavidch		printf("MSI-X"); i++;
621194781Sdavidch    }
622194781Sdavidch
623194781Sdavidch    if (sc->bce_phy_flags & BCE_PHY_2_5G_CAPABLE_FLAG) {
624194781Sdavidch        if (i > 0) printf("|");
625196970Sphk		printf("2.5G"); i++;
626194781Sdavidch    }
627194781Sdavidch
628194781Sdavidch    if (sc->bce_flags & BCE_MFW_ENABLE_FLAG) {
629194781Sdavidch        if (i > 0) printf("|");
630194781Sdavidch        printf("MFW); MFW (%s)\n", sc->bce_mfw_ver);
631194781Sdavidch    } else {
632194781Sdavidch        printf(")\n");
633194781Sdavidch    }
634194781Sdavidch
635196970Sphk	DBEXIT(BCE_VERBOSE_LOAD);
636179771Sdavidch}
637179771Sdavidch
638179771Sdavidch
639179771Sdavidch/****************************************************************************/
640179771Sdavidch/* PCI Capabilities Probe Function.                                         */
641179771Sdavidch/*                                                                          */
642179771Sdavidch/* Walks the PCI capabiites list for the device to find what features are   */
643179771Sdavidch/* supported.                                                               */
644179771Sdavidch/*                                                                          */
645179771Sdavidch/* Returns:                                                                 */
646179771Sdavidch/*   None.                                                                  */
647179771Sdavidch/****************************************************************************/
648179771Sdavidchstatic void
649179771Sdavidchbce_probe_pci_caps(device_t dev, struct bce_softc *sc)
650179771Sdavidch{
651179771Sdavidch	u32 reg;
652179771Sdavidch
653179771Sdavidch	DBENTER(BCE_VERBOSE_LOAD);
654179771Sdavidch
655179771Sdavidch	/* Check if PCI-X capability is enabled. */
656179771Sdavidch	if (pci_find_extcap(dev, PCIY_PCIX, &reg) == 0) {
657179771Sdavidch		if (reg != 0)
658179771Sdavidch			sc->bce_cap_flags |= BCE_PCIX_CAPABLE_FLAG;
659179771Sdavidch	}
660179771Sdavidch
661179771Sdavidch	/* Check if PCIe capability is enabled. */
662179771Sdavidch	if (pci_find_extcap(dev, PCIY_EXPRESS, &reg) == 0) {
663179771Sdavidch		if (reg != 0) {
664179771Sdavidch			u16 link_status = pci_read_config(dev, reg + 0x12, 2);
665179771Sdavidch			DBPRINT(sc, BCE_INFO_LOAD, "PCIe link_status = 0x%08X\n",
666179771Sdavidch				link_status);
667179771Sdavidch			sc->link_speed = link_status & 0xf;
668179771Sdavidch			sc->link_width = (link_status >> 4) & 0x3f;
669179771Sdavidch			sc->bce_cap_flags |= BCE_PCIE_CAPABLE_FLAG;
670179771Sdavidch			sc->bce_flags |= BCE_PCIE_FLAG;
671179771Sdavidch		}
672179771Sdavidch	}
673179771Sdavidch
674179771Sdavidch	/* Check if MSI capability is enabled. */
675179771Sdavidch	if (pci_find_extcap(dev, PCIY_MSI, &reg) == 0) {
676179771Sdavidch		if (reg != 0)
677179771Sdavidch			sc->bce_cap_flags |= BCE_MSI_CAPABLE_FLAG;
678179771Sdavidch	}
679179771Sdavidch
680179771Sdavidch	/* Check if MSI-X capability is enabled. */
681179771Sdavidch	if (pci_find_extcap(dev, PCIY_MSIX, &reg) == 0) {
682179771Sdavidch		if (reg != 0)
683179771Sdavidch			sc->bce_cap_flags |= BCE_MSIX_CAPABLE_FLAG;
684179771Sdavidch	}
685179771Sdavidch
686179771Sdavidch	DBEXIT(BCE_VERBOSE_LOAD);
687179771Sdavidch}
688179771Sdavidch
689179771Sdavidch
690179771Sdavidch/****************************************************************************/
691157642Sps/* Device attach function.                                                  */
692157642Sps/*                                                                          */
693157642Sps/* Allocates device resources, performs secondary chip identification,      */
694157642Sps/* resets and initializes the hardware, and initializes driver instance     */
695157642Sps/* variables.                                                               */
696157642Sps/*                                                                          */
697157642Sps/* Returns:                                                                 */
698157642Sps/*   0 on success, positive value on failure.                               */
699157642Sps/****************************************************************************/
700157642Spsstatic int
701157642Spsbce_attach(device_t dev)
702157642Sps{
703157642Sps	struct bce_softc *sc;
704157642Sps	struct ifnet *ifp;
705157642Sps	u32 val;
706179771Sdavidch	int error, rid, rc = 0;
707157642Sps
708157642Sps	sc = device_get_softc(dev);
709157642Sps	sc->bce_dev = dev;
710157642Sps
711179771Sdavidch	DBENTER(BCE_VERBOSE_LOAD | BCE_VERBOSE_RESET);
712157642Sps
713176448Sdavidch	sc->bce_unit = device_get_unit(dev);
714170392Sdavidch
715169632Sdavidch	/* Set initial device and PHY flags */
716169632Sdavidch	sc->bce_flags = 0;
717169632Sdavidch	sc->bce_phy_flags = 0;
718169632Sdavidch
719157642Sps	pci_enable_busmaster(dev);
720157642Sps
721157642Sps	/* Allocate PCI memory resources. */
722157642Sps	rid = PCIR_BAR(0);
723169632Sdavidch	sc->bce_res_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
724178588Smarius		&rid, RF_ACTIVE);
725157642Sps
726169632Sdavidch	if (sc->bce_res_mem == NULL) {
727179771Sdavidch		BCE_PRINTF("%s(%d): PCI memory allocation failed\n",
728157642Sps			__FILE__, __LINE__);
729157642Sps		rc = ENXIO;
730157642Sps		goto bce_attach_fail;
731157642Sps	}
732157642Sps
733157642Sps	/* Get various resource handles. */
734169632Sdavidch	sc->bce_btag    = rman_get_bustag(sc->bce_res_mem);
735169632Sdavidch	sc->bce_bhandle = rman_get_bushandle(sc->bce_res_mem);
736169632Sdavidch	sc->bce_vhandle = (vm_offset_t) rman_get_virtual(sc->bce_res_mem);
737157642Sps
738179771Sdavidch	bce_probe_pci_caps(dev, sc);
739170392Sdavidch
740179771Sdavidch	rid = 1;
741179771Sdavidch#if 0
742179771Sdavidch	/* Try allocating MSI-X interrupts. */
743179771Sdavidch	if ((sc->bce_cap_flags & BCE_MSIX_CAPABLE_FLAG) &&
744179771Sdavidch		(bce_msi_enable >= 2) &&
745179771Sdavidch		((sc->bce_res_irq = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
746179771Sdavidch		&rid, RF_ACTIVE)) != NULL)) {
747179771Sdavidch
748179771Sdavidch		msi_needed = sc->bce_msi_count = 1;
749179771Sdavidch
750179771Sdavidch		if (((error = pci_alloc_msix(dev, &sc->bce_msi_count)) != 0) ||
751179771Sdavidch			(sc->bce_msi_count != msi_needed)) {
752179771Sdavidch			BCE_PRINTF("%s(%d): MSI-X allocation failed! Requested = %d,"
753179771Sdavidch				"Received = %d, error = %d\n", __FILE__, __LINE__,
754179771Sdavidch				msi_needed, sc->bce_msi_count, error);
755179771Sdavidch			sc->bce_msi_count = 0;
756179771Sdavidch			pci_release_msi(dev);
757179771Sdavidch			bus_release_resource(dev, SYS_RES_MEMORY, rid,
758179771Sdavidch				sc->bce_res_irq);
759179771Sdavidch			sc->bce_res_irq = NULL;
760179771Sdavidch		} else {
761179771Sdavidch			DBPRINT(sc, BCE_INFO_LOAD, "%s(): Using MSI-X interrupt.\n",
762179771Sdavidch				__FUNCTION__);
763179771Sdavidch			sc->bce_flags |= BCE_USING_MSIX_FLAG;
764179771Sdavidch			sc->bce_intr = bce_intr;
765179771Sdavidch		}
766179771Sdavidch	}
767179771Sdavidch#endif
768179771Sdavidch
769179771Sdavidch	/* Try allocating a MSI interrupt. */
770179771Sdavidch	if ((sc->bce_cap_flags & BCE_MSI_CAPABLE_FLAG) &&
771179771Sdavidch		(bce_msi_enable >= 1) && (sc->bce_msi_count == 0)) {
772179771Sdavidch		sc->bce_msi_count = 1;
773179771Sdavidch		if ((error = pci_alloc_msi(dev, &sc->bce_msi_count)) != 0) {
774179771Sdavidch			BCE_PRINTF("%s(%d): MSI allocation failed! error = %d\n",
775179771Sdavidch				__FILE__, __LINE__, error);
776179771Sdavidch			sc->bce_msi_count = 0;
777179771Sdavidch			pci_release_msi(dev);
778179771Sdavidch		} else {
779179771Sdavidch			DBPRINT(sc, BCE_INFO_LOAD, "%s(): Using MSI interrupt.\n",
780179771Sdavidch				__FUNCTION__);
781179771Sdavidch			sc->bce_flags |= BCE_USING_MSI_FLAG;
782182293Sdavidch			if ((BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5709) ||
783182293Sdavidch				(BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5716))
784179771Sdavidch				sc->bce_flags |= BCE_ONE_SHOT_MSI_FLAG;
785179771Sdavidch			sc->bce_irq_rid = 1;
786179771Sdavidch			sc->bce_intr = bce_intr;
787179771Sdavidch		}
788179771Sdavidch	}
789179771Sdavidch
790179771Sdavidch	/* Try allocating a legacy interrupt. */
791179771Sdavidch	if (sc->bce_msi_count == 0) {
792179771Sdavidch		DBPRINT(sc, BCE_INFO_LOAD, "%s(): Using INTx interrupt.\n",
793179771Sdavidch			__FUNCTION__);
794170392Sdavidch		rid = 0;
795179771Sdavidch		sc->bce_intr = bce_intr;
796169632Sdavidch	}
797170392Sdavidch
798179771Sdavidch	sc->bce_res_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ,
799179771Sdavidch		&rid, RF_SHAREABLE | RF_ACTIVE);
800157642Sps
801179771Sdavidch	sc->bce_irq_rid = rid;
802179771Sdavidch
803179771Sdavidch	/* Report any IRQ allocation errors. */
804169632Sdavidch	if (sc->bce_res_irq == NULL) {
805179771Sdavidch		BCE_PRINTF("%s(%d): PCI map interrupt failed!\n",
806157642Sps			__FILE__, __LINE__);
807157642Sps		rc = ENXIO;
808157642Sps		goto bce_attach_fail;
809157642Sps	}
810157642Sps
811157642Sps	/* Initialize mutex for the current device instance. */
812157642Sps	BCE_LOCK_INIT(sc, device_get_nameunit(dev));
813157642Sps
814157642Sps	/*
815157642Sps	 * Configure byte swap and enable indirect register access.
816157642Sps	 * Rely on CPU to do target byte swapping on big endian systems.
817157642Sps	 * Access to registers outside of PCI configurtion space are not
818157642Sps	 * valid until this is done.
819157642Sps	 */
820157642Sps	pci_write_config(dev, BCE_PCICFG_MISC_CONFIG,
821157642Sps			       BCE_PCICFG_MISC_CONFIG_REG_WINDOW_ENA |
822157642Sps			       BCE_PCICFG_MISC_CONFIG_TARGET_MB_WORD_SWAP, 4);
823157642Sps
824157642Sps	/* Save ASIC revsion info. */
825157642Sps	sc->bce_chipid =  REG_RD(sc, BCE_MISC_ID);
826157642Sps
827157642Sps	/* Weed out any non-production controller revisions. */
828157642Sps	switch(BCE_CHIP_ID(sc)) {
829157642Sps		case BCE_CHIP_ID_5706_A0:
830157642Sps		case BCE_CHIP_ID_5706_A1:
831157642Sps		case BCE_CHIP_ID_5708_A0:
832157642Sps		case BCE_CHIP_ID_5708_B0:
833179771Sdavidch		case BCE_CHIP_ID_5709_A0:
834179771Sdavidch		case BCE_CHIP_ID_5709_B0:
835179771Sdavidch		case BCE_CHIP_ID_5709_B1:
836179771Sdavidch		case BCE_CHIP_ID_5709_B2:
837169271Sdavidch			BCE_PRINTF("%s(%d): Unsupported controller revision (%c%d)!\n",
838179771Sdavidch				__FILE__, __LINE__,
839157642Sps				(((pci_read_config(dev, PCIR_REVID, 4) & 0xf0) >> 4) + 'A'),
840157642Sps			    (pci_read_config(dev, PCIR_REVID, 4) & 0xf));
841157642Sps			rc = ENODEV;
842157642Sps			goto bce_attach_fail;
843157642Sps	}
844157642Sps
845179771Sdavidch	/*
846179771Sdavidch	 * The embedded PCIe to PCI-X bridge (EPB)
847179771Sdavidch	 * in the 5708 cannot address memory above
848179771Sdavidch	 * 40 bits (E7_5708CB1_23043 & E6_5708SB1_23043).
849157642Sps	 */
850157642Sps	if (BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5708)
851157642Sps		sc->max_bus_addr = BCE_BUS_SPACE_MAXADDR;
852157642Sps	else
853157642Sps		sc->max_bus_addr = BUS_SPACE_MAXADDR;
854157642Sps
855157642Sps	/*
856157642Sps	 * Find the base address for shared memory access.
857157642Sps	 * Newer versions of bootcode use a signature and offset
858157642Sps	 * while older versions use a fixed address.
859157642Sps	 */
860157642Sps	val = REG_RD_IND(sc, BCE_SHM_HDR_SIGNATURE);
861157642Sps	if ((val & BCE_SHM_HDR_SIGNATURE_SIG_MASK) == BCE_SHM_HDR_SIGNATURE_SIG)
862179771Sdavidch		/* Multi-port devices use different offsets in shared memory. */
863179771Sdavidch		sc->bce_shmem_base = REG_RD_IND(sc, BCE_SHM_HDR_ADDR_0 +
864179771Sdavidch			(pci_get_function(sc->bce_dev) << 2));
865157642Sps	else
866157642Sps		sc->bce_shmem_base = HOST_VIEW_SHMEM_BASE;
867157642Sps
868179771Sdavidch	DBPRINT(sc, BCE_VERBOSE_FIRMWARE, "%s(): bce_shmem_base = 0x%08X\n",
869170810Sdavidch		__FUNCTION__, sc->bce_shmem_base);
870157642Sps
871178132Sdavidch	/* Fetch the bootcode revision. */
872194781Sdavidch    val = bce_shmem_rd(sc, BCE_DEV_INFO_BC_REV);
873194781Sdavidch    for (int i = 0, j = 0; i < 3; i++) {
874194781Sdavidch        u8 num;
875170810Sdavidch
876194781Sdavidch        num = (u8) (val >> (24 - (i * 8)));
877194781Sdavidch        for (int k = 100, skip0 = 1; k >= 1; num %= k, k /= 10) {
878194781Sdavidch            if (num >= k || !skip0 || k == 1) {
879194781Sdavidch                sc->bce_bc_ver[j++] = (num / k) + '0';
880194781Sdavidch                skip0 = 0;
881194781Sdavidch            }
882194781Sdavidch        }
883194781Sdavidch        if (i != 2)
884194781Sdavidch            sc->bce_bc_ver[j++] = '.';
885194781Sdavidch    }
886170810Sdavidch
887194781Sdavidch    /* Check if any management firwmare is running. */
888194781Sdavidch    val = bce_shmem_rd(sc, BCE_PORT_FEATURE);
889194781Sdavidch    if (val & BCE_PORT_FEATURE_ASF_ENABLED) {
890194781Sdavidch        sc->bce_flags |= BCE_MFW_ENABLE_FLAG;
891194781Sdavidch
892194781Sdavidch        /* Allow time for firmware to enter the running state. */
893194781Sdavidch        for (int i = 0; i < 30; i++) {
894194781Sdavidch            val = bce_shmem_rd(sc, BCE_BC_STATE_CONDITION);
895194781Sdavidch            if (val & BCE_CONDITION_MFW_RUN_MASK)
896194781Sdavidch                break;
897194781Sdavidch            DELAY(10000);
898194781Sdavidch        }
899194781Sdavidch    }
900194781Sdavidch
901194781Sdavidch    /* Check the current bootcode state. */
902194781Sdavidch    val = bce_shmem_rd(sc, BCE_BC_STATE_CONDITION);
903194781Sdavidch    val &= BCE_CONDITION_MFW_RUN_MASK;
904194781Sdavidch    if (val != BCE_CONDITION_MFW_RUN_UNKNOWN &&
905194781Sdavidch        val != BCE_CONDITION_MFW_RUN_NONE) {
906194781Sdavidch        u32 addr = bce_shmem_rd(sc, BCE_MFW_VER_PTR);
907194781Sdavidch        int i = 0;
908194781Sdavidch
909194781Sdavidch        for (int j = 0; j < 3; j++) {
910194781Sdavidch            val = bce_reg_rd_ind(sc, addr + j * 4);
911194781Sdavidch            val = bswap32(val);
912194781Sdavidch            memcpy(&sc->bce_mfw_ver[i], &val, 4);
913194781Sdavidch            i += 4;
914194781Sdavidch        }
915194781Sdavidch    }
916194781Sdavidch
917157642Sps	/* Get PCI bus information (speed and type). */
918157642Sps	val = REG_RD(sc, BCE_PCICFG_MISC_STATUS);
919157642Sps	if (val & BCE_PCICFG_MISC_STATUS_PCIX_DET) {
920157642Sps		u32 clkreg;
921157642Sps
922157642Sps		sc->bce_flags |= BCE_PCIX_FLAG;
923157642Sps
924157642Sps		clkreg = REG_RD(sc, BCE_PCICFG_PCI_CLOCK_CONTROL_BITS);
925157642Sps
926157642Sps		clkreg &= BCE_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET;
927157642Sps		switch (clkreg) {
928157642Sps		case BCE_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_133MHZ:
929157642Sps			sc->bus_speed_mhz = 133;
930157642Sps			break;
931157642Sps
932157642Sps		case BCE_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_95MHZ:
933157642Sps			sc->bus_speed_mhz = 100;
934157642Sps			break;
935157642Sps
936157642Sps		case BCE_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_66MHZ:
937157642Sps		case BCE_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_80MHZ:
938157642Sps			sc->bus_speed_mhz = 66;
939157642Sps			break;
940157642Sps
941157642Sps		case BCE_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_48MHZ:
942157642Sps		case BCE_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_55MHZ:
943157642Sps			sc->bus_speed_mhz = 50;
944157642Sps			break;
945157642Sps
946157642Sps		case BCE_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_LOW:
947157642Sps		case BCE_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_32MHZ:
948157642Sps		case BCE_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_38MHZ:
949157642Sps			sc->bus_speed_mhz = 33;
950157642Sps			break;
951157642Sps		}
952157642Sps	} else {
953157642Sps		if (val & BCE_PCICFG_MISC_STATUS_M66EN)
954157642Sps			sc->bus_speed_mhz = 66;
955157642Sps		else
956157642Sps			sc->bus_speed_mhz = 33;
957157642Sps	}
958157642Sps
959157642Sps	if (val & BCE_PCICFG_MISC_STATUS_32BIT_DET)
960157642Sps		sc->bce_flags |= BCE_PCI_32BIT_FLAG;
961157642Sps
962171667Sdavidch	/* Reset the controller and announce to bootcode that driver is present. */
963157642Sps	if (bce_reset(sc, BCE_DRV_MSG_CODE_RESET)) {
964179771Sdavidch		BCE_PRINTF("%s(%d): Controller reset failed!\n",
965170810Sdavidch			__FILE__, __LINE__);
966157642Sps		rc = ENXIO;
967157642Sps		goto bce_attach_fail;
968157642Sps	}
969157642Sps
970157642Sps	/* Initialize the controller. */
971157642Sps	if (bce_chipinit(sc)) {
972169271Sdavidch		BCE_PRINTF("%s(%d): Controller initialization failed!\n",
973170392Sdavidch			__FILE__, __LINE__);
974157642Sps		rc = ENXIO;
975157642Sps		goto bce_attach_fail;
976157642Sps	}
977157642Sps
978157642Sps	/* Perform NVRAM test. */
979157642Sps	if (bce_nvram_test(sc)) {
980169271Sdavidch		BCE_PRINTF("%s(%d): NVRAM test failed!\n",
981157642Sps			__FILE__, __LINE__);
982157642Sps		rc = ENXIO;
983157642Sps		goto bce_attach_fail;
984157642Sps	}
985157642Sps
986157642Sps	/* Fetch the permanent Ethernet MAC address. */
987157642Sps	bce_get_mac_addr(sc);
988157642Sps
989157642Sps	/*
990157642Sps	 * Trip points control how many BDs
991157642Sps	 * should be ready before generating an
992157642Sps	 * interrupt while ticks control how long
993157642Sps	 * a BD can sit in the chain before
994179771Sdavidch	 * generating an interrupt.  Set the default
995170810Sdavidch	 * values for the RX and TX chains.
996157642Sps	 */
997157642Sps
998170810Sdavidch#ifdef BCE_DEBUG
999157642Sps	/* Force more frequent interrupts. */
1000157642Sps	sc->bce_tx_quick_cons_trip_int = 1;
1001157642Sps	sc->bce_tx_quick_cons_trip     = 1;
1002157642Sps	sc->bce_tx_ticks_int           = 0;
1003157642Sps	sc->bce_tx_ticks               = 0;
1004157642Sps
1005157642Sps	sc->bce_rx_quick_cons_trip_int = 1;
1006157642Sps	sc->bce_rx_quick_cons_trip     = 1;
1007157642Sps	sc->bce_rx_ticks_int           = 0;
1008157642Sps	sc->bce_rx_ticks               = 0;
1009157642Sps#else
1010170810Sdavidch	/* Improve throughput at the expense of increased latency. */
1011157642Sps	sc->bce_tx_quick_cons_trip_int = 20;
1012157642Sps	sc->bce_tx_quick_cons_trip     = 20;
1013157642Sps	sc->bce_tx_ticks_int           = 80;
1014157642Sps	sc->bce_tx_ticks               = 80;
1015157642Sps
1016157642Sps	sc->bce_rx_quick_cons_trip_int = 6;
1017157642Sps	sc->bce_rx_quick_cons_trip     = 6;
1018157642Sps	sc->bce_rx_ticks_int           = 18;
1019157642Sps	sc->bce_rx_ticks               = 18;
1020157642Sps#endif
1021157642Sps
1022157642Sps	/* Update statistics once every second. */
1023157642Sps	sc->bce_stats_ticks = 1000000 & 0xffff00;
1024157642Sps
1025179771Sdavidch	/* Find the media type for the adapter. */
1026179771Sdavidch	bce_get_media(sc);
1027157642Sps
1028170810Sdavidch	/* Store data needed by PHY driver for backplane applications */
1029194781Sdavidch	sc->bce_shared_hw_cfg = bce_shmem_rd(sc, BCE_SHARED_HW_CFG_CONFIG);
1030194781Sdavidch	sc->bce_port_hw_cfg   = bce_shmem_rd(sc, BCE_PORT_HW_CFG_CONFIG);
1031170392Sdavidch
1032157642Sps	/* Allocate DMA memory resources. */
1033157642Sps	if (bce_dma_alloc(dev)) {
1034169271Sdavidch		BCE_PRINTF("%s(%d): DMA resource allocation failed!\n",
1035157642Sps		    __FILE__, __LINE__);
1036157642Sps		rc = ENXIO;
1037157642Sps		goto bce_attach_fail;
1038157642Sps	}
1039157642Sps
1040157642Sps	/* Allocate an ifnet structure. */
1041157642Sps	ifp = sc->bce_ifp = if_alloc(IFT_ETHER);
1042157642Sps	if (ifp == NULL) {
1043179771Sdavidch		BCE_PRINTF("%s(%d): Interface allocation failed!\n",
1044157642Sps			__FILE__, __LINE__);
1045157642Sps		rc = ENXIO;
1046157642Sps		goto bce_attach_fail;
1047157642Sps	}
1048157642Sps
1049157642Sps	/* Initialize the ifnet interface. */
1050157642Sps	ifp->if_softc        = sc;
1051157642Sps	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
1052157642Sps	ifp->if_flags        = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
1053157642Sps	ifp->if_ioctl        = bce_ioctl;
1054157642Sps	ifp->if_start        = bce_start;
1055157642Sps	ifp->if_init         = bce_init;
1056157642Sps	ifp->if_mtu          = ETHERMTU;
1057170392Sdavidch
1058170392Sdavidch	if (bce_tso_enable) {
1059170392Sdavidch		ifp->if_hwassist = BCE_IF_HWASSIST | CSUM_TSO;
1060169632Sdavidch		ifp->if_capabilities = BCE_IF_CAPABILITIES | IFCAP_TSO4;
1061170392Sdavidch	} else {
1062170392Sdavidch		ifp->if_hwassist = BCE_IF_HWASSIST;
1063170392Sdavidch		ifp->if_capabilities = BCE_IF_CAPABILITIES;
1064170392Sdavidch	}
1065169632Sdavidch
1066157642Sps	ifp->if_capenable    = ifp->if_capabilities;
1067157642Sps
1068182293Sdavidch	/*
1069182293Sdavidch	 * Assume standard mbuf sizes for buffer allocation.
1070182293Sdavidch	 * This may change later if the MTU size is set to
1071182293Sdavidch	 * something other than 1500.
1072179771Sdavidch	 */
1073198320Sstas#ifdef BCE_JUMBO_HDRSPLIT
1074176448Sdavidch	sc->rx_bd_mbuf_alloc_size = MHLEN;
1075179771Sdavidch	/* Make sure offset is 16 byte aligned for hardware. */
1076179771Sdavidch	sc->rx_bd_mbuf_align_pad  = roundup2((MSIZE - MHLEN), 16) -
1077179695Sdavidch		(MSIZE - MHLEN);
1078179771Sdavidch	sc->rx_bd_mbuf_data_len   = sc->rx_bd_mbuf_alloc_size -
1079179695Sdavidch		sc->rx_bd_mbuf_align_pad;
1080179771Sdavidch	sc->pg_bd_mbuf_alloc_size = MCLBYTES;
1081178853Sscottl#else
1082179436Sjhb	sc->rx_bd_mbuf_alloc_size = MCLBYTES;
1083179695Sdavidch	sc->rx_bd_mbuf_align_pad  = roundup2(MCLBYTES, 16) - MCLBYTES;
1084179771Sdavidch	sc->rx_bd_mbuf_data_len   = sc->rx_bd_mbuf_alloc_size -
1085179695Sdavidch		sc->rx_bd_mbuf_align_pad;
1086179771Sdavidch#endif
1087176448Sdavidch
1088157642Sps	ifp->if_snd.ifq_drv_maxlen = USABLE_TX_BD;
1089170810Sdavidch	IFQ_SET_MAXLEN(&ifp->if_snd, ifp->if_snd.ifq_drv_maxlen);
1090170810Sdavidch	IFQ_SET_READY(&ifp->if_snd);
1091170810Sdavidch
1092157642Sps	if (sc->bce_phy_flags & BCE_PHY_2_5G_CAPABLE_FLAG)
1093170392Sdavidch		ifp->if_baudrate = IF_Mbps(2500ULL);
1094157642Sps	else
1095170392Sdavidch		ifp->if_baudrate = IF_Mbps(1000);
1096157642Sps
1097170810Sdavidch	/* Check for an MII child bus by probing the PHY. */
1098166261Sdwhite	if (mii_phy_probe(dev, &sc->bce_miibus, bce_ifmedia_upd,
1099166261Sdwhite		bce_ifmedia_sts)) {
1100179771Sdavidch		BCE_PRINTF("%s(%d): No PHY found on child MII bus!\n",
1101157642Sps			__FILE__, __LINE__);
1102166261Sdwhite		rc = ENXIO;
1103157642Sps		goto bce_attach_fail;
1104157642Sps	}
1105157642Sps
1106157642Sps	/* Attach to the Ethernet interface list. */
1107157642Sps	ether_ifattach(ifp, sc->eaddr);
1108157642Sps
1109157642Sps#if __FreeBSD_version < 500000
1110170810Sdavidch	callout_init(&sc->bce_tick_callout);
1111170810Sdavidch	callout_init(&sc->bce_pulse_callout);
1112157642Sps#else
1113170810Sdavidch	callout_init_mtx(&sc->bce_tick_callout, &sc->bce_mtx, 0);
1114170810Sdavidch	callout_init_mtx(&sc->bce_pulse_callout, &sc->bce_mtx, 0);
1115157642Sps#endif
1116157642Sps
1117157642Sps	/* Hookup IRQ last. */
1118179771Sdavidch	rc = bus_setup_intr(dev, sc->bce_res_irq, INTR_TYPE_NET | INTR_MPSAFE,
1119179771Sdavidch		NULL, bce_intr, sc, &sc->bce_intrhand);
1120157642Sps
1121157642Sps	if (rc) {
1122179771Sdavidch		BCE_PRINTF("%s(%d): Failed to setup IRQ!\n",
1123157642Sps			__FILE__, __LINE__);
1124157642Sps		bce_detach(dev);
1125157642Sps		goto bce_attach_exit;
1126157642Sps	}
1127157642Sps
1128179771Sdavidch	/*
1129179771Sdavidch	 * At this point we've acquired all the resources
1130170810Sdavidch	 * we need to run so there's no turning back, we're
1131170810Sdavidch	 * cleared for launch.
1132170810Sdavidch	 */
1133170810Sdavidch
1134157642Sps	/* Print some important debugging info. */
1135176448Sdavidch	DBRUNMSG(BCE_INFO, bce_dump_driver_state(sc));
1136157642Sps
1137157642Sps	/* Add the supported sysctls to the kernel. */
1138157642Sps	bce_add_sysctls(sc);
1139157642Sps
1140170810Sdavidch	BCE_LOCK(sc);
1141182293Sdavidch
1142179771Sdavidch	/*
1143170810Sdavidch	 * The chip reset earlier notified the bootcode that
1144170810Sdavidch	 * a driver is present.  We now need to start our pulse
1145170810Sdavidch	 * routine so that the bootcode is reminded that we're
1146170810Sdavidch	 * still running.
1147170810Sdavidch	 */
1148170810Sdavidch	bce_pulse(sc);
1149170810Sdavidch
1150162474Sambrisko	bce_mgmt_init_locked(sc);
1151170392Sdavidch	BCE_UNLOCK(sc);
1152162474Sambrisko
1153170810Sdavidch	/* Finally, print some useful adapter info */
1154179771Sdavidch	bce_print_adapter_info(sc);
1155176448Sdavidch	DBPRINT(sc, BCE_FATAL, "%s(): sc = %p\n",
1156176448Sdavidch		__FUNCTION__, sc);
1157170810Sdavidch
1158157642Sps	goto bce_attach_exit;
1159157642Sps
1160157642Spsbce_attach_fail:
1161157642Sps	bce_release_resources(sc);
1162157642Sps
1163157642Spsbce_attach_exit:
1164157642Sps
1165179771Sdavidch	DBEXIT(BCE_VERBOSE_LOAD | BCE_VERBOSE_RESET);
1166157642Sps
1167157642Sps	return(rc);
1168157642Sps}
1169157642Sps
1170157642Sps
1171157642Sps/****************************************************************************/
1172157642Sps/* Device detach function.                                                  */
1173157642Sps/*                                                                          */
1174157642Sps/* Stops the controller, resets the controller, and releases resources.     */
1175157642Sps/*                                                                          */
1176157642Sps/* Returns:                                                                 */
1177157642Sps/*   0 on success, positive value on failure.                               */
1178157642Sps/****************************************************************************/
1179157642Spsstatic int
1180157642Spsbce_detach(device_t dev)
1181157642Sps{
1182170810Sdavidch	struct bce_softc *sc = device_get_softc(dev);
1183157642Sps	struct ifnet *ifp;
1184170810Sdavidch	u32 msg;
1185157642Sps
1186179771Sdavidch	DBENTER(BCE_VERBOSE_UNLOAD | BCE_VERBOSE_RESET);
1187157642Sps
1188157642Sps	ifp = sc->bce_ifp;
1189157642Sps
1190176448Sdavidch	/* Stop and reset the controller. */
1191176448Sdavidch	BCE_LOCK(sc);
1192176448Sdavidch
1193170810Sdavidch	/* Stop the pulse so the bootcode can go to driver absent state. */
1194170810Sdavidch	callout_stop(&sc->bce_pulse_callout);
1195170810Sdavidch
1196157642Sps	bce_stop(sc);
1197170810Sdavidch	if (sc->bce_flags & BCE_NO_WOL_FLAG)
1198170810Sdavidch		msg = BCE_DRV_MSG_CODE_UNLOAD_LNK_DN;
1199170810Sdavidch	else
1200170810Sdavidch		msg = BCE_DRV_MSG_CODE_UNLOAD;
1201170810Sdavidch	bce_reset(sc, msg);
1202176448Sdavidch
1203157642Sps	BCE_UNLOCK(sc);
1204157642Sps
1205157642Sps	ether_ifdetach(ifp);
1206157642Sps
1207157642Sps	/* If we have a child device on the MII bus remove it too. */
1208166261Sdwhite	bus_generic_detach(dev);
1209166261Sdwhite	device_delete_child(dev, sc->bce_miibus);
1210157642Sps
1211157642Sps	/* Release all remaining resources. */
1212157642Sps	bce_release_resources(sc);
1213157642Sps
1214179771Sdavidch	DBEXIT(BCE_VERBOSE_UNLOAD | BCE_VERBOSE_RESET);
1215157642Sps
1216157642Sps	return(0);
1217157642Sps}
1218157642Sps
1219157642Sps
1220157642Sps/****************************************************************************/
1221157642Sps/* Device shutdown function.                                                */
1222157642Sps/*                                                                          */
1223157642Sps/* Stops and resets the controller.                                         */
1224157642Sps/*                                                                          */
1225157642Sps/* Returns:                                                                 */
1226173839Syongari/*   0 on success, positive value on failure.                               */
1227157642Sps/****************************************************************************/
1228173839Syongaristatic int
1229157642Spsbce_shutdown(device_t dev)
1230157642Sps{
1231157642Sps	struct bce_softc *sc = device_get_softc(dev);
1232170810Sdavidch	u32 msg;
1233157642Sps
1234179771Sdavidch	DBENTER(BCE_VERBOSE);
1235170810Sdavidch
1236157642Sps	BCE_LOCK(sc);
1237157642Sps	bce_stop(sc);
1238170810Sdavidch	if (sc->bce_flags & BCE_NO_WOL_FLAG)
1239170810Sdavidch		msg = BCE_DRV_MSG_CODE_UNLOAD_LNK_DN;
1240170810Sdavidch	else
1241170810Sdavidch		msg = BCE_DRV_MSG_CODE_UNLOAD;
1242170810Sdavidch	bce_reset(sc, msg);
1243157642Sps	BCE_UNLOCK(sc);
1244173839Syongari
1245179771Sdavidch	DBEXIT(BCE_VERBOSE);
1246179771Sdavidch
1247173839Syongari	return (0);
1248157642Sps}
1249157642Sps
1250157642Sps
1251179771Sdavidch#ifdef BCE_DEBUG
1252157642Sps/****************************************************************************/
1253179771Sdavidch/* Register read.                                                           */
1254179771Sdavidch/*                                                                          */
1255179771Sdavidch/* Returns:                                                                 */
1256179771Sdavidch/*   The value of the register.                                             */
1257179771Sdavidch/****************************************************************************/
1258179771Sdavidchstatic u32
1259179771Sdavidchbce_reg_rd(struct bce_softc *sc, u32 offset)
1260179771Sdavidch{
1261179771Sdavidch	u32 val = bus_space_read_4(sc->bce_btag, sc->bce_bhandle, offset);
1262179771Sdavidch	DBPRINT(sc, BCE_INSANE_REG, "%s(); offset = 0x%08X, val = 0x%08X\n",
1263179771Sdavidch		__FUNCTION__, offset, val);
1264179771Sdavidch	return val;
1265179771Sdavidch}
1266179771Sdavidch
1267179771Sdavidch
1268179771Sdavidch/****************************************************************************/
1269179771Sdavidch/* Register write (16 bit).                                                 */
1270179771Sdavidch/*                                                                          */
1271179771Sdavidch/* Returns:                                                                 */
1272179771Sdavidch/*   Nothing.                                                               */
1273179771Sdavidch/****************************************************************************/
1274179771Sdavidchstatic void
1275179771Sdavidchbce_reg_wr16(struct bce_softc *sc, u32 offset, u16 val)
1276179771Sdavidch{
1277179771Sdavidch	DBPRINT(sc, BCE_INSANE_REG, "%s(); offset = 0x%08X, val = 0x%04X\n",
1278179771Sdavidch		__FUNCTION__, offset, val);
1279179771Sdavidch	bus_space_write_2(sc->bce_btag, sc->bce_bhandle, offset, val);
1280179771Sdavidch}
1281179771Sdavidch
1282179771Sdavidch
1283179771Sdavidch/****************************************************************************/
1284179771Sdavidch/* Register write.                                                          */
1285179771Sdavidch/*                                                                          */
1286179771Sdavidch/* Returns:                                                                 */
1287179771Sdavidch/*   Nothing.                                                               */
1288179771Sdavidch/****************************************************************************/
1289179771Sdavidchstatic void
1290179771Sdavidchbce_reg_wr(struct bce_softc *sc, u32 offset, u32 val)
1291179771Sdavidch{
1292179771Sdavidch	DBPRINT(sc, BCE_INSANE_REG, "%s(); offset = 0x%08X, val = 0x%08X\n",
1293179771Sdavidch		__FUNCTION__, offset, val);
1294179771Sdavidch	bus_space_write_4(sc->bce_btag, sc->bce_bhandle, offset, val);
1295179771Sdavidch}
1296179771Sdavidch#endif
1297179771Sdavidch
1298179771Sdavidch/****************************************************************************/
1299157642Sps/* Indirect register read.                                                  */
1300157642Sps/*                                                                          */
1301157642Sps/* Reads NetXtreme II registers using an index/data register pair in PCI    */
1302157642Sps/* configuration space.  Using this mechanism avoids issues with posted     */
1303157642Sps/* reads but is much slower than memory-mapped I/O.                         */
1304157642Sps/*                                                                          */
1305157642Sps/* Returns:                                                                 */
1306157642Sps/*   The value of the register.                                             */
1307157642Sps/****************************************************************************/
1308157642Spsstatic u32
1309157642Spsbce_reg_rd_ind(struct bce_softc *sc, u32 offset)
1310157642Sps{
1311157642Sps	device_t dev;
1312157642Sps	dev = sc->bce_dev;
1313157642Sps
1314157642Sps	pci_write_config(dev, BCE_PCICFG_REG_WINDOW_ADDRESS, offset, 4);
1315157642Sps#ifdef BCE_DEBUG
1316157642Sps	{
1317157642Sps		u32 val;
1318157642Sps		val = pci_read_config(dev, BCE_PCICFG_REG_WINDOW, 4);
1319179771Sdavidch		DBPRINT(sc, BCE_INSANE_REG, "%s(); offset = 0x%08X, val = 0x%08X\n",
1320157642Sps			__FUNCTION__, offset, val);
1321157642Sps		return val;
1322157642Sps	}
1323157642Sps#else
1324157642Sps	return pci_read_config(dev, BCE_PCICFG_REG_WINDOW, 4);
1325157642Sps#endif
1326157642Sps}
1327157642Sps
1328157642Sps
1329157642Sps/****************************************************************************/
1330157642Sps/* Indirect register write.                                                 */
1331157642Sps/*                                                                          */
1332157642Sps/* Writes NetXtreme II registers using an index/data register pair in PCI   */
1333157642Sps/* configuration space.  Using this mechanism avoids issues with posted     */
1334157642Sps/* writes but is muchh slower than memory-mapped I/O.                       */
1335157642Sps/*                                                                          */
1336157642Sps/* Returns:                                                                 */
1337157642Sps/*   Nothing.                                                               */
1338157642Sps/****************************************************************************/
1339157642Spsstatic void
1340157642Spsbce_reg_wr_ind(struct bce_softc *sc, u32 offset, u32 val)
1341157642Sps{
1342157642Sps	device_t dev;
1343157642Sps	dev = sc->bce_dev;
1344157642Sps
1345179771Sdavidch	DBPRINT(sc, BCE_INSANE_REG, "%s(); offset = 0x%08X, val = 0x%08X\n",
1346157642Sps		__FUNCTION__, offset, val);
1347157642Sps
1348157642Sps	pci_write_config(dev, BCE_PCICFG_REG_WINDOW_ADDRESS, offset, 4);
1349157642Sps	pci_write_config(dev, BCE_PCICFG_REG_WINDOW, val, 4);
1350157642Sps}
1351157642Sps
1352178132Sdavidch
1353194781Sdavidch/****************************************************************************/
1354194781Sdavidch/* Shared memory write.                                                     */
1355194781Sdavidch/*                                                                          */
1356194781Sdavidch/* Writes NetXtreme II shared memory region.                                */
1357194781Sdavidch/*                                                                          */
1358194781Sdavidch/* Returns:                                                                 */
1359194781Sdavidch/*   Nothing.                                                               */
1360194781Sdavidch/****************************************************************************/
1361194781Sdavidchstatic void
1362194781Sdavidchbce_shmem_wr(struct bce_softc *sc, u32 offset, u32 val)
1363194781Sdavidch{
1364194781Sdavidch	bce_reg_wr_ind(sc, sc->bce_shmem_base + offset, val);
1365194781Sdavidch}
1366194781Sdavidch
1367194781Sdavidch
1368194781Sdavidch/****************************************************************************/
1369194781Sdavidch/* Shared memory read.                                                      */
1370194781Sdavidch/*                                                                          */
1371194781Sdavidch/* Reads NetXtreme II shared memory region.                                 */
1372194781Sdavidch/*                                                                          */
1373194781Sdavidch/* Returns:                                                                 */
1374194781Sdavidch/*   The 32 bit value read.                                                 */
1375194781Sdavidch/****************************************************************************/
1376194781Sdavidchstatic u32
1377194781Sdavidchbce_shmem_rd(struct bce_softc *sc, u32 offset)
1378194781Sdavidch{
1379194781Sdavidch	return (bce_reg_rd_ind(sc, sc->bce_shmem_base + offset));
1380194781Sdavidch}
1381194781Sdavidch
1382194781Sdavidch
1383176448Sdavidch#ifdef BCE_DEBUG
1384176448Sdavidch/****************************************************************************/
1385176448Sdavidch/* Context memory read.                                                     */
1386176448Sdavidch/*                                                                          */
1387176448Sdavidch/* The NetXtreme II controller uses context memory to track connection      */
1388176448Sdavidch/* information for L2 and higher network protocols.                         */
1389176448Sdavidch/*                                                                          */
1390176448Sdavidch/* Returns:                                                                 */
1391176448Sdavidch/*   The requested 32 bit value of context memory.                          */
1392176448Sdavidch/****************************************************************************/
1393176448Sdavidchstatic u32
1394179771Sdavidchbce_ctx_rd(struct bce_softc *sc, u32 cid_addr, u32 ctx_offset)
1395176448Sdavidch{
1396179771Sdavidch	u32 idx, offset, retry_cnt = 5, val;
1397157642Sps
1398179771Sdavidch	DBRUNIF((cid_addr > MAX_CID_ADDR || ctx_offset & 0x3 || cid_addr & CTX_MASK),
1399179771Sdavidch		BCE_PRINTF("%s(): Invalid CID address: 0x%08X.\n",
1400179771Sdavidch			__FUNCTION__, cid_addr));
1401176448Sdavidch
1402179771Sdavidch	offset = ctx_offset + cid_addr;
1403176448Sdavidch
1404182293Sdavidch	if ((BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5709) ||
1405182293Sdavidch		(BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5716)) {
1406179771Sdavidch
1407179771Sdavidch		REG_WR(sc, BCE_CTX_CTX_CTRL, (offset | BCE_CTX_CTX_CTRL_READ_REQ));
1408179771Sdavidch
1409179771Sdavidch		for (idx = 0; idx < retry_cnt; idx++) {
1410179771Sdavidch			val = REG_RD(sc, BCE_CTX_CTX_CTRL);
1411179771Sdavidch			if ((val & BCE_CTX_CTX_CTRL_READ_REQ) == 0)
1412179771Sdavidch				break;
1413179771Sdavidch			DELAY(5);
1414179771Sdavidch		}
1415179771Sdavidch
1416179771Sdavidch		if (val & BCE_CTX_CTX_CTRL_READ_REQ)
1417179771Sdavidch			BCE_PRINTF("%s(%d); Unable to read CTX memory: "
1418179771Sdavidch				"cid_addr = 0x%08X, offset = 0x%08X!\n",
1419179771Sdavidch				__FILE__, __LINE__, cid_addr, ctx_offset);
1420179771Sdavidch
1421179771Sdavidch		val = REG_RD(sc, BCE_CTX_CTX_DATA);
1422179771Sdavidch	} else {
1423179771Sdavidch		REG_WR(sc, BCE_CTX_DATA_ADR, offset);
1424179771Sdavidch		val = REG_RD(sc, BCE_CTX_DATA);
1425179771Sdavidch	}
1426179771Sdavidch
1427179771Sdavidch	DBPRINT(sc, BCE_EXTREME_CTX, "%s(); cid_addr = 0x%08X, offset = 0x%08X, "
1428179771Sdavidch		"val = 0x%08X\n", __FUNCTION__, cid_addr, ctx_offset, val);
1429179771Sdavidch
1430176448Sdavidch	return(val);
1431176448Sdavidch}
1432176448Sdavidch#endif
1433176448Sdavidch
1434178132Sdavidch
1435157642Sps/****************************************************************************/
1436157642Sps/* Context memory write.                                                    */
1437157642Sps/*                                                                          */
1438157642Sps/* The NetXtreme II controller uses context memory to track connection      */
1439157642Sps/* information for L2 and higher network protocols.                         */
1440157642Sps/*                                                                          */
1441157642Sps/* Returns:                                                                 */
1442157642Sps/*   Nothing.                                                               */
1443157642Sps/****************************************************************************/
1444157642Spsstatic void
1445179771Sdavidchbce_ctx_wr(struct bce_softc *sc, u32 cid_addr, u32 ctx_offset, u32 ctx_val)
1446157642Sps{
1447179771Sdavidch	u32 idx, offset = ctx_offset + cid_addr;
1448179771Sdavidch	u32 val, retry_cnt = 5;
1449157642Sps
1450179771Sdavidch	DBPRINT(sc, BCE_EXTREME_CTX, "%s(); cid_addr = 0x%08X, offset = 0x%08X, "
1451179771Sdavidch		"val = 0x%08X\n", __FUNCTION__, cid_addr, ctx_offset, ctx_val);
1452157642Sps
1453179771Sdavidch	DBRUNIF((cid_addr > MAX_CID_ADDR || ctx_offset & 0x3 || cid_addr & CTX_MASK),
1454179771Sdavidch		BCE_PRINTF("%s(): Invalid CID address: 0x%08X.\n",
1455179771Sdavidch			__FUNCTION__, cid_addr));
1456179771Sdavidch
1457182293Sdavidch	if ((BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5709) ||
1458182293Sdavidch		(BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5716)) {
1459179771Sdavidch
1460179771Sdavidch		REG_WR(sc, BCE_CTX_CTX_DATA, ctx_val);
1461179771Sdavidch		REG_WR(sc, BCE_CTX_CTX_CTRL, (offset | BCE_CTX_CTX_CTRL_WRITE_REQ));
1462179771Sdavidch
1463179771Sdavidch		for (idx = 0; idx < retry_cnt; idx++) {
1464179771Sdavidch			val = REG_RD(sc, BCE_CTX_CTX_CTRL);
1465179771Sdavidch			if ((val & BCE_CTX_CTX_CTRL_WRITE_REQ) == 0)
1466179771Sdavidch				break;
1467179771Sdavidch			DELAY(5);
1468179771Sdavidch		}
1469179771Sdavidch
1470179771Sdavidch		if (val & BCE_CTX_CTX_CTRL_WRITE_REQ)
1471179771Sdavidch			BCE_PRINTF("%s(%d); Unable to write CTX memory: "
1472179771Sdavidch				"cid_addr = 0x%08X, offset = 0x%08X!\n",
1473179771Sdavidch				__FILE__, __LINE__, cid_addr, ctx_offset);
1474179771Sdavidch
1475179771Sdavidch	} else {
1476179771Sdavidch		REG_WR(sc, BCE_CTX_DATA_ADR, offset);
1477179771Sdavidch		REG_WR(sc, BCE_CTX_DATA, ctx_val);
1478179771Sdavidch	}
1479157642Sps}
1480157642Sps
1481157642Sps
1482157642Sps/****************************************************************************/
1483157642Sps/* PHY register read.                                                       */
1484157642Sps/*                                                                          */
1485157642Sps/* Implements register reads on the MII bus.                                */
1486157642Sps/*                                                                          */
1487157642Sps/* Returns:                                                                 */
1488157642Sps/*   The value of the register.                                             */
1489157642Sps/****************************************************************************/
1490157642Spsstatic int
1491157642Spsbce_miibus_read_reg(device_t dev, int phy, int reg)
1492157642Sps{
1493157642Sps	struct bce_softc *sc;
1494157642Sps	u32 val;
1495157642Sps	int i;
1496157642Sps
1497157642Sps	sc = device_get_softc(dev);
1498157642Sps
1499157642Sps	/* Make sure we are accessing the correct PHY address. */
1500157642Sps	if (phy != sc->bce_phy_addr) {
1501179771Sdavidch		DBPRINT(sc, BCE_INSANE_PHY, "Invalid PHY address %d for PHY read!\n", phy);
1502157642Sps		return(0);
1503157642Sps	}
1504157642Sps
1505157642Sps	if (sc->bce_phy_flags & BCE_PHY_INT_MODE_AUTO_POLLING_FLAG) {
1506157642Sps		val = REG_RD(sc, BCE_EMAC_MDIO_MODE);
1507157642Sps		val &= ~BCE_EMAC_MDIO_MODE_AUTO_POLL;
1508157642Sps
1509157642Sps		REG_WR(sc, BCE_EMAC_MDIO_MODE, val);
1510157642Sps		REG_RD(sc, BCE_EMAC_MDIO_MODE);
1511157642Sps
1512157642Sps		DELAY(40);
1513157642Sps	}
1514157642Sps
1515179771Sdavidch
1516157642Sps	val = BCE_MIPHY(phy) | BCE_MIREG(reg) |
1517157642Sps		BCE_EMAC_MDIO_COMM_COMMAND_READ | BCE_EMAC_MDIO_COMM_DISEXT |
1518157642Sps		BCE_EMAC_MDIO_COMM_START_BUSY;
1519157642Sps	REG_WR(sc, BCE_EMAC_MDIO_COMM, val);
1520157642Sps
1521157642Sps	for (i = 0; i < BCE_PHY_TIMEOUT; i++) {
1522157642Sps		DELAY(10);
1523157642Sps
1524157642Sps		val = REG_RD(sc, BCE_EMAC_MDIO_COMM);
1525157642Sps		if (!(val & BCE_EMAC_MDIO_COMM_START_BUSY)) {
1526157642Sps			DELAY(5);
1527157642Sps
1528157642Sps			val = REG_RD(sc, BCE_EMAC_MDIO_COMM);
1529157642Sps			val &= BCE_EMAC_MDIO_COMM_DATA;
1530157642Sps
1531157642Sps			break;
1532157642Sps		}
1533157642Sps	}
1534157642Sps
1535157642Sps	if (val & BCE_EMAC_MDIO_COMM_START_BUSY) {
1536169271Sdavidch		BCE_PRINTF("%s(%d): Error: PHY read timeout! phy = %d, reg = 0x%04X\n",
1537157642Sps			__FILE__, __LINE__, phy, reg);
1538157642Sps		val = 0x0;
1539157642Sps	} else {
1540157642Sps		val = REG_RD(sc, BCE_EMAC_MDIO_COMM);
1541157642Sps	}
1542157642Sps
1543157642Sps
1544157642Sps	if (sc->bce_phy_flags & BCE_PHY_INT_MODE_AUTO_POLLING_FLAG) {
1545157642Sps		val = REG_RD(sc, BCE_EMAC_MDIO_MODE);
1546157642Sps		val |= BCE_EMAC_MDIO_MODE_AUTO_POLL;
1547157642Sps
1548157642Sps		REG_WR(sc, BCE_EMAC_MDIO_MODE, val);
1549157642Sps		REG_RD(sc, BCE_EMAC_MDIO_MODE);
1550157642Sps
1551157642Sps		DELAY(40);
1552157642Sps	}
1553157642Sps
1554179771Sdavidch	DB_PRINT_PHY_REG(reg, val);
1555157642Sps	return (val & 0xffff);
1556157642Sps
1557157642Sps}
1558157642Sps
1559157642Sps
1560157642Sps/****************************************************************************/
1561157642Sps/* PHY register write.                                                      */
1562157642Sps/*                                                                          */
1563157642Sps/* Implements register writes on the MII bus.                               */
1564157642Sps/*                                                                          */
1565157642Sps/* Returns:                                                                 */
1566157642Sps/*   The value of the register.                                             */
1567157642Sps/****************************************************************************/
1568157642Spsstatic int
1569157642Spsbce_miibus_write_reg(device_t dev, int phy, int reg, int val)
1570157642Sps{
1571157642Sps	struct bce_softc *sc;
1572157642Sps	u32 val1;
1573157642Sps	int i;
1574157642Sps
1575157642Sps	sc = device_get_softc(dev);
1576157642Sps
1577157642Sps	/* Make sure we are accessing the correct PHY address. */
1578157642Sps	if (phy != sc->bce_phy_addr) {
1579179771Sdavidch		DBPRINT(sc, BCE_INSANE_PHY, "Invalid PHY address %d for PHY write!\n", phy);
1580157642Sps		return(0);
1581157642Sps	}
1582157642Sps
1583179771Sdavidch	DB_PRINT_PHY_REG(reg, val);
1584157642Sps
1585157642Sps	if (sc->bce_phy_flags & BCE_PHY_INT_MODE_AUTO_POLLING_FLAG) {
1586157642Sps		val1 = REG_RD(sc, BCE_EMAC_MDIO_MODE);
1587157642Sps		val1 &= ~BCE_EMAC_MDIO_MODE_AUTO_POLL;
1588157642Sps
1589157642Sps		REG_WR(sc, BCE_EMAC_MDIO_MODE, val1);
1590157642Sps		REG_RD(sc, BCE_EMAC_MDIO_MODE);
1591157642Sps
1592157642Sps		DELAY(40);
1593157642Sps	}
1594157642Sps
1595157642Sps	val1 = BCE_MIPHY(phy) | BCE_MIREG(reg) | val |
1596157642Sps		BCE_EMAC_MDIO_COMM_COMMAND_WRITE |
1597157642Sps		BCE_EMAC_MDIO_COMM_START_BUSY | BCE_EMAC_MDIO_COMM_DISEXT;
1598157642Sps	REG_WR(sc, BCE_EMAC_MDIO_COMM, val1);
1599157642Sps
1600157642Sps	for (i = 0; i < BCE_PHY_TIMEOUT; i++) {
1601157642Sps		DELAY(10);
1602157642Sps
1603157642Sps		val1 = REG_RD(sc, BCE_EMAC_MDIO_COMM);
1604157642Sps		if (!(val1 & BCE_EMAC_MDIO_COMM_START_BUSY)) {
1605157642Sps			DELAY(5);
1606157642Sps			break;
1607157642Sps		}
1608157642Sps	}
1609157642Sps
1610157642Sps	if (val1 & BCE_EMAC_MDIO_COMM_START_BUSY)
1611179771Sdavidch		BCE_PRINTF("%s(%d): PHY write timeout!\n",
1612157642Sps			__FILE__, __LINE__);
1613157642Sps
1614157642Sps	if (sc->bce_phy_flags & BCE_PHY_INT_MODE_AUTO_POLLING_FLAG) {
1615157642Sps		val1 = REG_RD(sc, BCE_EMAC_MDIO_MODE);
1616157642Sps		val1 |= BCE_EMAC_MDIO_MODE_AUTO_POLL;
1617157642Sps
1618157642Sps		REG_WR(sc, BCE_EMAC_MDIO_MODE, val1);
1619157642Sps		REG_RD(sc, BCE_EMAC_MDIO_MODE);
1620157642Sps
1621157642Sps		DELAY(40);
1622157642Sps	}
1623157642Sps
1624157642Sps	return 0;
1625157642Sps}
1626157642Sps
1627157642Sps
1628157642Sps/****************************************************************************/
1629157642Sps/* MII bus status change.                                                   */
1630157642Sps/*                                                                          */
1631157642Sps/* Called by the MII bus driver when the PHY establishes link to set the    */
1632157642Sps/* MAC interface registers.                                                 */
1633157642Sps/*                                                                          */
1634157642Sps/* Returns:                                                                 */
1635157642Sps/*   Nothing.                                                               */
1636157642Sps/****************************************************************************/
1637157642Spsstatic void
1638157642Spsbce_miibus_statchg(device_t dev)
1639157642Sps{
1640157642Sps	struct bce_softc *sc;
1641157642Sps	struct mii_data *mii;
1642170392Sdavidch	int val;
1643157642Sps
1644157642Sps	sc = device_get_softc(dev);
1645157642Sps
1646179771Sdavidch	DBENTER(BCE_VERBOSE_PHY);
1647179771Sdavidch
1648157642Sps	mii = device_get_softc(sc->bce_miibus);
1649157642Sps
1650170392Sdavidch	val = REG_RD(sc, BCE_EMAC_MODE);
1651179771Sdavidch	val &= ~(BCE_EMAC_MODE_PORT | BCE_EMAC_MODE_HALF_DUPLEX |
1652179771Sdavidch		BCE_EMAC_MODE_MAC_LOOP | BCE_EMAC_MODE_FORCE_LINK |
1653170392Sdavidch		BCE_EMAC_MODE_25G);
1654157642Sps
1655169632Sdavidch	/* Set MII or GMII interface based on the speed negotiated by the PHY. */
1656170392Sdavidch	switch (IFM_SUBTYPE(mii->mii_media_active)) {
1657170392Sdavidch	case IFM_10_T:
1658170392Sdavidch		if (BCE_CHIP_NUM(sc) != BCE_CHIP_NUM_5706) {
1659170392Sdavidch			DBPRINT(sc, BCE_INFO, "Enabling 10Mb interface.\n");
1660170392Sdavidch			val |= BCE_EMAC_MODE_PORT_MII_10;
1661170392Sdavidch			break;
1662170392Sdavidch		}
1663170392Sdavidch		/* fall-through */
1664170392Sdavidch	case IFM_100_TX:
1665170392Sdavidch		DBPRINT(sc, BCE_INFO, "Enabling MII interface.\n");
1666170392Sdavidch		val |= BCE_EMAC_MODE_PORT_MII;
1667170392Sdavidch		break;
1668170392Sdavidch	case IFM_2500_SX:
1669170392Sdavidch		DBPRINT(sc, BCE_INFO, "Enabling 2.5G MAC mode.\n");
1670170392Sdavidch		val |= BCE_EMAC_MODE_25G;
1671170392Sdavidch		/* fall-through */
1672170392Sdavidch	case IFM_1000_T:
1673170392Sdavidch	case IFM_1000_SX:
1674170810Sdavidch		DBPRINT(sc, BCE_INFO, "Enabling GMII interface.\n");
1675170392Sdavidch		val |= BCE_EMAC_MODE_PORT_GMII;
1676170392Sdavidch		break;
1677170392Sdavidch	default:
1678178132Sdavidch		DBPRINT(sc, BCE_INFO, "Unknown speed, enabling default GMII "
1679176448Sdavidch			"interface.\n");
1680170392Sdavidch		val |= BCE_EMAC_MODE_PORT_GMII;
1681157642Sps	}
1682157642Sps
1683157642Sps	/* Set half or full duplex based on the duplicity negotiated by the PHY. */
1684170392Sdavidch	if ((mii->mii_media_active & IFM_GMASK) == IFM_HDX) {
1685170392Sdavidch		DBPRINT(sc, BCE_INFO, "Setting Half-Duplex interface.\n");
1686170392Sdavidch		val |= BCE_EMAC_MODE_HALF_DUPLEX;
1687170392Sdavidch	} else
1688157642Sps		DBPRINT(sc, BCE_INFO, "Setting Full-Duplex interface.\n");
1689170392Sdavidch
1690170392Sdavidch	REG_WR(sc, BCE_EMAC_MODE, val);
1691170392Sdavidch
1692170392Sdavidch#if 0
1693176448Sdavidch	/* ToDo: Enable flow control support in brgphy and bge. */
1694170392Sdavidch	/* FLAG0 is set if RX is enabled and FLAG1 if TX is enabled */
1695170392Sdavidch	if (mii->mii_media_active & IFM_FLAG0)
1696170392Sdavidch		BCE_SETBIT(sc, BCE_EMAC_RX_MODE, BCE_EMAC_RX_MODE_FLOW_EN);
1697170392Sdavidch	if (mii->mii_media_active & IFM_FLAG1)
1698170392Sdavidch		BCE_SETBIT(sc, BCE_EMAC_RX_MODE, BCE_EMAC_TX_MODE_FLOW_EN);
1699170392Sdavidch#endif
1700170392Sdavidch
1701179771Sdavidch	DBEXIT(BCE_VERBOSE_PHY);
1702157642Sps}
1703157642Sps
1704157642Sps
1705157642Sps/****************************************************************************/
1706157642Sps/* Acquire NVRAM lock.                                                      */
1707157642Sps/*                                                                          */
1708157642Sps/* Before the NVRAM can be accessed the caller must acquire an NVRAM lock.  */
1709157642Sps/* Locks 0 and 2 are reserved, lock 1 is used by firmware and lock 2 is     */
1710157642Sps/* for use by the driver.                                                   */
1711157642Sps/*                                                                          */
1712157642Sps/* Returns:                                                                 */
1713157642Sps/*   0 on success, positive value on failure.                               */
1714157642Sps/****************************************************************************/
1715157642Spsstatic int
1716157642Spsbce_acquire_nvram_lock(struct bce_softc *sc)
1717157642Sps{
1718157642Sps	u32 val;
1719179771Sdavidch	int j, rc = 0;
1720157642Sps
1721179771Sdavidch	DBENTER(BCE_VERBOSE_NVRAM);
1722157642Sps
1723157642Sps	/* Request access to the flash interface. */
1724157642Sps	REG_WR(sc, BCE_NVM_SW_ARB, BCE_NVM_SW_ARB_ARB_REQ_SET2);
1725157642Sps	for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) {
1726157642Sps		val = REG_RD(sc, BCE_NVM_SW_ARB);
1727157642Sps		if (val & BCE_NVM_SW_ARB_ARB_ARB2)
1728157642Sps			break;
1729157642Sps
1730157642Sps		DELAY(5);
1731157642Sps	}
1732157642Sps
1733157642Sps	if (j >= NVRAM_TIMEOUT_COUNT) {
1734157642Sps		DBPRINT(sc, BCE_WARN, "Timeout acquiring NVRAM lock!\n");
1735179771Sdavidch		rc = EBUSY;
1736157642Sps	}
1737157642Sps
1738179771Sdavidch	DBEXIT(BCE_VERBOSE_NVRAM);
1739179771Sdavidch	return (rc);
1740157642Sps}
1741157642Sps
1742157642Sps
1743157642Sps/****************************************************************************/
1744157642Sps/* Release NVRAM lock.                                                      */
1745157642Sps/*                                                                          */
1746157642Sps/* When the caller is finished accessing NVRAM the lock must be released.   */
1747157642Sps/* Locks 0 and 2 are reserved, lock 1 is used by firmware and lock 2 is     */
1748157642Sps/* for use by the driver.                                                   */
1749157642Sps/*                                                                          */
1750157642Sps/* Returns:                                                                 */
1751157642Sps/*   0 on success, positive value on failure.                               */
1752157642Sps/****************************************************************************/
1753157642Spsstatic int
1754157642Spsbce_release_nvram_lock(struct bce_softc *sc)
1755157642Sps{
1756157642Sps	u32 val;
1757179771Sdavidch	int j, rc = 0;
1758157642Sps
1759179771Sdavidch	DBENTER(BCE_VERBOSE_NVRAM);
1760157642Sps
1761157642Sps	/*
1762157642Sps	 * Relinquish nvram interface.
1763157642Sps	 */
1764157642Sps	REG_WR(sc, BCE_NVM_SW_ARB, BCE_NVM_SW_ARB_ARB_REQ_CLR2);
1765157642Sps
1766157642Sps	for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) {
1767157642Sps		val = REG_RD(sc, BCE_NVM_SW_ARB);
1768157642Sps		if (!(val & BCE_NVM_SW_ARB_ARB_ARB2))
1769157642Sps			break;
1770157642Sps
1771157642Sps		DELAY(5);
1772157642Sps	}
1773157642Sps
1774157642Sps	if (j >= NVRAM_TIMEOUT_COUNT) {
1775179771Sdavidch		DBPRINT(sc, BCE_WARN, "Timeout releasing NVRAM lock!\n");
1776179771Sdavidch		rc = EBUSY;
1777157642Sps	}
1778157642Sps
1779179771Sdavidch	DBEXIT(BCE_VERBOSE_NVRAM);
1780179771Sdavidch	return (rc);
1781157642Sps}
1782157642Sps
1783157642Sps
1784157642Sps#ifdef BCE_NVRAM_WRITE_SUPPORT
1785157642Sps/****************************************************************************/
1786157642Sps/* Enable NVRAM write access.                                               */
1787157642Sps/*                                                                          */
1788157642Sps/* Before writing to NVRAM the caller must enable NVRAM writes.             */
1789157642Sps/*                                                                          */
1790157642Sps/* Returns:                                                                 */
1791157642Sps/*   0 on success, positive value on failure.                               */
1792157642Sps/****************************************************************************/
1793157642Spsstatic int
1794157642Spsbce_enable_nvram_write(struct bce_softc *sc)
1795157642Sps{
1796157642Sps	u32 val;
1797179771Sdavidch	int rc = 0;
1798157642Sps
1799179771Sdavidch	DBENTER(BCE_VERBOSE_NVRAM);
1800157642Sps
1801157642Sps	val = REG_RD(sc, BCE_MISC_CFG);
1802157642Sps	REG_WR(sc, BCE_MISC_CFG, val | BCE_MISC_CFG_NVM_WR_EN_PCI);
1803157642Sps
1804179771Sdavidch	if (!(sc->bce_flash_info->flags & BCE_NV_BUFFERED)) {
1805157642Sps		int j;
1806157642Sps
1807157642Sps		REG_WR(sc, BCE_NVM_COMMAND, BCE_NVM_COMMAND_DONE);
1808157642Sps		REG_WR(sc, BCE_NVM_COMMAND,	BCE_NVM_COMMAND_WREN | BCE_NVM_COMMAND_DOIT);
1809157642Sps
1810157642Sps		for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) {
1811157642Sps			DELAY(5);
1812157642Sps
1813157642Sps			val = REG_RD(sc, BCE_NVM_COMMAND);
1814157642Sps			if (val & BCE_NVM_COMMAND_DONE)
1815157642Sps				break;
1816157642Sps		}
1817157642Sps
1818157642Sps		if (j >= NVRAM_TIMEOUT_COUNT) {
1819157642Sps			DBPRINT(sc, BCE_WARN, "Timeout writing NVRAM!\n");
1820179771Sdavidch			rc = EBUSY;
1821157642Sps		}
1822157642Sps	}
1823179771Sdavidch
1824179771Sdavidch	DBENTER(BCE_VERBOSE_NVRAM);
1825179771Sdavidch	return (rc);
1826157642Sps}
1827157642Sps
1828157642Sps
1829157642Sps/****************************************************************************/
1830157642Sps/* Disable NVRAM write access.                                              */
1831157642Sps/*                                                                          */
1832157642Sps/* When the caller is finished writing to NVRAM write access must be        */
1833157642Sps/* disabled.                                                                */
1834157642Sps/*                                                                          */
1835157642Sps/* Returns:                                                                 */
1836157642Sps/*   Nothing.                                                               */
1837157642Sps/****************************************************************************/
1838157642Spsstatic void
1839157642Spsbce_disable_nvram_write(struct bce_softc *sc)
1840157642Sps{
1841157642Sps	u32 val;
1842157642Sps
1843179771Sdavidch	DBENTER(BCE_VERBOSE_NVRAM);
1844157642Sps
1845157642Sps	val = REG_RD(sc, BCE_MISC_CFG);
1846157642Sps	REG_WR(sc, BCE_MISC_CFG, val & ~BCE_MISC_CFG_NVM_WR_EN);
1847179771Sdavidch
1848179771Sdavidch	DBEXIT(BCE_VERBOSE_NVRAM);
1849179771Sdavidch
1850157642Sps}
1851157642Sps#endif
1852157642Sps
1853157642Sps
1854157642Sps/****************************************************************************/
1855157642Sps/* Enable NVRAM access.                                                     */
1856157642Sps/*                                                                          */
1857157642Sps/* Before accessing NVRAM for read or write operations the caller must      */
1858157642Sps/* enabled NVRAM access.                                                    */
1859157642Sps/*                                                                          */
1860157642Sps/* Returns:                                                                 */
1861157642Sps/*   Nothing.                                                               */
1862157642Sps/****************************************************************************/
1863157642Spsstatic void
1864157642Spsbce_enable_nvram_access(struct bce_softc *sc)
1865157642Sps{
1866157642Sps	u32 val;
1867157642Sps
1868179771Sdavidch	DBENTER(BCE_VERBOSE_NVRAM);
1869157642Sps
1870157642Sps	val = REG_RD(sc, BCE_NVM_ACCESS_ENABLE);
1871157642Sps	/* Enable both bits, even on read. */
1872157642Sps	REG_WR(sc, BCE_NVM_ACCESS_ENABLE,
1873157642Sps	       val | BCE_NVM_ACCESS_ENABLE_EN | BCE_NVM_ACCESS_ENABLE_WR_EN);
1874179771Sdavidch
1875179771Sdavidch	DBEXIT(BCE_VERBOSE_NVRAM);
1876157642Sps}
1877157642Sps
1878157642Sps
1879157642Sps/****************************************************************************/
1880157642Sps/* Disable NVRAM access.                                                    */
1881157642Sps/*                                                                          */
1882157642Sps/* When the caller is finished accessing NVRAM access must be disabled.     */
1883157642Sps/*                                                                          */
1884157642Sps/* Returns:                                                                 */
1885157642Sps/*   Nothing.                                                               */
1886157642Sps/****************************************************************************/
1887157642Spsstatic void
1888157642Spsbce_disable_nvram_access(struct bce_softc *sc)
1889157642Sps{
1890157642Sps	u32 val;
1891157642Sps
1892179771Sdavidch	DBENTER(BCE_VERBOSE_NVRAM);
1893157642Sps
1894157642Sps	val = REG_RD(sc, BCE_NVM_ACCESS_ENABLE);
1895157642Sps
1896157642Sps	/* Disable both bits, even after read. */
1897157642Sps	REG_WR(sc, BCE_NVM_ACCESS_ENABLE,
1898157642Sps		val & ~(BCE_NVM_ACCESS_ENABLE_EN |
1899157642Sps			BCE_NVM_ACCESS_ENABLE_WR_EN));
1900179771Sdavidch
1901179771Sdavidch	DBEXIT(BCE_VERBOSE_NVRAM);
1902157642Sps}
1903157642Sps
1904157642Sps
1905157642Sps#ifdef BCE_NVRAM_WRITE_SUPPORT
1906157642Sps/****************************************************************************/
1907157642Sps/* Erase NVRAM page before writing.                                         */
1908157642Sps/*                                                                          */
1909157642Sps/* Non-buffered flash parts require that a page be erased before it is      */
1910157642Sps/* written.                                                                 */
1911157642Sps/*                                                                          */
1912157642Sps/* Returns:                                                                 */
1913157642Sps/*   0 on success, positive value on failure.                               */
1914157642Sps/****************************************************************************/
1915157642Spsstatic int
1916157642Spsbce_nvram_erase_page(struct bce_softc *sc, u32 offset)
1917157642Sps{
1918157642Sps	u32 cmd;
1919179771Sdavidch	int j, rc = 0;
1920157642Sps
1921179771Sdavidch	DBENTER(BCE_VERBOSE_NVRAM);
1922179771Sdavidch
1923157642Sps	/* Buffered flash doesn't require an erase. */
1924179771Sdavidch	if (sc->bce_flash_info->flags & BCE_NV_BUFFERED)
1925179771Sdavidch		goto bce_nvram_erase_page_exit;
1926157642Sps
1927157642Sps	/* Build an erase command. */
1928157642Sps	cmd = BCE_NVM_COMMAND_ERASE | BCE_NVM_COMMAND_WR |
1929157642Sps	      BCE_NVM_COMMAND_DOIT;
1930157642Sps
1931157642Sps	/*
1932157642Sps	 * Clear the DONE bit separately, set the NVRAM adress to erase,
1933157642Sps	 * and issue the erase command.
1934157642Sps	 */
1935157642Sps	REG_WR(sc, BCE_NVM_COMMAND, BCE_NVM_COMMAND_DONE);
1936157642Sps	REG_WR(sc, BCE_NVM_ADDR, offset & BCE_NVM_ADDR_NVM_ADDR_VALUE);
1937157642Sps	REG_WR(sc, BCE_NVM_COMMAND, cmd);
1938157642Sps
1939157642Sps	/* Wait for completion. */
1940157642Sps	for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) {
1941157642Sps		u32 val;
1942157642Sps
1943157642Sps		DELAY(5);
1944157642Sps
1945157642Sps		val = REG_RD(sc, BCE_NVM_COMMAND);
1946157642Sps		if (val & BCE_NVM_COMMAND_DONE)
1947157642Sps			break;
1948157642Sps	}
1949157642Sps
1950157642Sps	if (j >= NVRAM_TIMEOUT_COUNT) {
1951157642Sps		DBPRINT(sc, BCE_WARN, "Timeout erasing NVRAM.\n");
1952179771Sdavidch		rc = EBUSY;
1953157642Sps	}
1954157642Sps
1955179771Sdavidchbce_nvram_erase_page_exit:
1956179771Sdavidch	DBEXIT(BCE_VERBOSE_NVRAM);
1957179771Sdavidch	return (rc);
1958157642Sps}
1959157642Sps#endif /* BCE_NVRAM_WRITE_SUPPORT */
1960157642Sps
1961157642Sps
1962157642Sps/****************************************************************************/
1963157642Sps/* Read a dword (32 bits) from NVRAM.                                       */
1964157642Sps/*                                                                          */
1965157642Sps/* Read a 32 bit word from NVRAM.  The caller is assumed to have already    */
1966157642Sps/* obtained the NVRAM lock and enabled the controller for NVRAM access.     */
1967157642Sps/*                                                                          */
1968157642Sps/* Returns:                                                                 */
1969157642Sps/*   0 on success and the 32 bit value read, positive value on failure.     */
1970157642Sps/****************************************************************************/
1971157642Spsstatic int
1972157642Spsbce_nvram_read_dword(struct bce_softc *sc, u32 offset, u8 *ret_val,
1973157642Sps							u32 cmd_flags)
1974157642Sps{
1975157642Sps	u32 cmd;
1976157642Sps	int i, rc = 0;
1977157642Sps
1978179771Sdavidch	DBENTER(BCE_EXTREME_NVRAM);
1979179771Sdavidch
1980157642Sps	/* Build the command word. */
1981157642Sps	cmd = BCE_NVM_COMMAND_DOIT | cmd_flags;
1982157642Sps
1983179771Sdavidch	/* Calculate the offset for buffered flash if translation is used. */
1984179771Sdavidch	if (sc->bce_flash_info->flags & BCE_NV_TRANSLATE) {
1985157642Sps		offset = ((offset / sc->bce_flash_info->page_size) <<
1986157642Sps			   sc->bce_flash_info->page_bits) +
1987157642Sps			  (offset % sc->bce_flash_info->page_size);
1988157642Sps	}
1989157642Sps
1990157642Sps	/*
1991157642Sps	 * Clear the DONE bit separately, set the address to read,
1992157642Sps	 * and issue the read.
1993157642Sps	 */
1994157642Sps	REG_WR(sc, BCE_NVM_COMMAND, BCE_NVM_COMMAND_DONE);
1995157642Sps	REG_WR(sc, BCE_NVM_ADDR, offset & BCE_NVM_ADDR_NVM_ADDR_VALUE);
1996157642Sps	REG_WR(sc, BCE_NVM_COMMAND, cmd);
1997157642Sps
1998157642Sps	/* Wait for completion. */
1999157642Sps	for (i = 0; i < NVRAM_TIMEOUT_COUNT; i++) {
2000157642Sps		u32 val;
2001157642Sps
2002157642Sps		DELAY(5);
2003157642Sps
2004157642Sps		val = REG_RD(sc, BCE_NVM_COMMAND);
2005157642Sps		if (val & BCE_NVM_COMMAND_DONE) {
2006157642Sps			val = REG_RD(sc, BCE_NVM_READ);
2007157642Sps
2008157642Sps			val = bce_be32toh(val);
2009157642Sps			memcpy(ret_val, &val, 4);
2010157642Sps			break;
2011157642Sps		}
2012157642Sps	}
2013157642Sps
2014157642Sps	/* Check for errors. */
2015157642Sps	if (i >= NVRAM_TIMEOUT_COUNT) {
2016169271Sdavidch		BCE_PRINTF("%s(%d): Timeout error reading NVRAM at offset 0x%08X!\n",
2017157642Sps			__FILE__, __LINE__, offset);
2018157642Sps		rc = EBUSY;
2019157642Sps	}
2020157642Sps
2021179771Sdavidch	DBEXIT(BCE_EXTREME_NVRAM);
2022157642Sps	return(rc);
2023157642Sps}
2024157642Sps
2025157642Sps
2026157642Sps#ifdef BCE_NVRAM_WRITE_SUPPORT
2027157642Sps/****************************************************************************/
2028157642Sps/* Write a dword (32 bits) to NVRAM.                                        */
2029157642Sps/*                                                                          */
2030157642Sps/* Write a 32 bit word to NVRAM.  The caller is assumed to have already     */
2031157642Sps/* obtained the NVRAM lock, enabled the controller for NVRAM access, and    */
2032157642Sps/* enabled NVRAM write access.                                              */
2033157642Sps/*                                                                          */
2034157642Sps/* Returns:                                                                 */
2035157642Sps/*   0 on success, positive value on failure.                               */
2036157642Sps/****************************************************************************/
2037157642Spsstatic int
2038157642Spsbce_nvram_write_dword(struct bce_softc *sc, u32 offset, u8 *val,
2039157642Sps	u32 cmd_flags)
2040157642Sps{
2041157642Sps	u32 cmd, val32;
2042179771Sdavidch	int j, rc = 0;
2043157642Sps
2044179771Sdavidch	DBENTER(BCE_VERBOSE_NVRAM);
2045179771Sdavidch
2046157642Sps	/* Build the command word. */
2047157642Sps	cmd = BCE_NVM_COMMAND_DOIT | BCE_NVM_COMMAND_WR | cmd_flags;
2048157642Sps
2049179771Sdavidch	/* Calculate the offset for buffered flash if translation is used. */
2050179771Sdavidch	if (sc->bce_flash_info->flags & BCE_NV_TRANSLATE) {
2051157642Sps		offset = ((offset / sc->bce_flash_info->page_size) <<
2052157642Sps			  sc->bce_flash_info->page_bits) +
2053157642Sps			 (offset % sc->bce_flash_info->page_size);
2054157642Sps	}
2055157642Sps
2056157642Sps	/*
2057157642Sps	 * Clear the DONE bit separately, convert NVRAM data to big-endian,
2058157642Sps	 * set the NVRAM address to write, and issue the write command
2059157642Sps	 */
2060157642Sps	REG_WR(sc, BCE_NVM_COMMAND, BCE_NVM_COMMAND_DONE);
2061157642Sps	memcpy(&val32, val, 4);
2062157642Sps	val32 = htobe32(val32);
2063157642Sps	REG_WR(sc, BCE_NVM_WRITE, val32);
2064157642Sps	REG_WR(sc, BCE_NVM_ADDR, offset & BCE_NVM_ADDR_NVM_ADDR_VALUE);
2065157642Sps	REG_WR(sc, BCE_NVM_COMMAND, cmd);
2066157642Sps
2067157642Sps	/* Wait for completion. */
2068157642Sps	for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) {
2069157642Sps		DELAY(5);
2070157642Sps
2071157642Sps		if (REG_RD(sc, BCE_NVM_COMMAND) & BCE_NVM_COMMAND_DONE)
2072157642Sps			break;
2073157642Sps	}
2074157642Sps	if (j >= NVRAM_TIMEOUT_COUNT) {
2075169271Sdavidch		BCE_PRINTF("%s(%d): Timeout error writing NVRAM at offset 0x%08X\n",
2076157642Sps			__FILE__, __LINE__, offset);
2077179771Sdavidch		rc = EBUSY;
2078157642Sps	}
2079157642Sps
2080179771Sdavidch	DBEXIT(BCE_VERBOSE_NVRAM);
2081179771Sdavidch	return (rc);
2082157642Sps}
2083157642Sps#endif /* BCE_NVRAM_WRITE_SUPPORT */
2084157642Sps
2085157642Sps
2086157642Sps/****************************************************************************/
2087157642Sps/* Initialize NVRAM access.                                                 */
2088157642Sps/*                                                                          */
2089157642Sps/* Identify the NVRAM device in use and prepare the NVRAM interface to      */
2090157642Sps/* access that device.                                                      */
2091157642Sps/*                                                                          */
2092157642Sps/* Returns:                                                                 */
2093157642Sps/*   0 on success, positive value on failure.                               */
2094157642Sps/****************************************************************************/
2095157642Spsstatic int
2096157642Spsbce_init_nvram(struct bce_softc *sc)
2097157642Sps{
2098157642Sps	u32 val;
2099179771Sdavidch	int j, entry_count, rc = 0;
2100157642Sps	struct flash_spec *flash;
2101157642Sps
2102179771Sdavidch	DBENTER(BCE_VERBOSE_NVRAM);
2103157642Sps
2104182293Sdavidch	if ((BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5709) ||
2105182293Sdavidch		(BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5716)) {
2106179771Sdavidch		sc->bce_flash_info = &flash_5709;
2107179771Sdavidch		goto bce_init_nvram_get_flash_size;
2108179771Sdavidch	}
2109179771Sdavidch
2110157642Sps	/* Determine the selected interface. */
2111157642Sps	val = REG_RD(sc, BCE_NVM_CFG1);
2112157642Sps
2113157642Sps	entry_count = sizeof(flash_table) / sizeof(struct flash_spec);
2114157642Sps
2115157642Sps	/*
2116157642Sps	 * Flash reconfiguration is required to support additional
2117157642Sps	 * NVRAM devices not directly supported in hardware.
2118157642Sps	 * Check if the flash interface was reconfigured
2119157642Sps	 * by the bootcode.
2120157642Sps	 */
2121157642Sps
2122157642Sps	if (val & 0x40000000) {
2123157642Sps		/* Flash interface reconfigured by bootcode. */
2124157642Sps
2125179771Sdavidch		DBPRINT(sc,BCE_INFO_LOAD,
2126157642Sps			"bce_init_nvram(): Flash WAS reconfigured.\n");
2127157642Sps
2128157642Sps		for (j = 0, flash = &flash_table[0]; j < entry_count;
2129157642Sps		     j++, flash++) {
2130157642Sps			if ((val & FLASH_BACKUP_STRAP_MASK) ==
2131157642Sps			    (flash->config1 & FLASH_BACKUP_STRAP_MASK)) {
2132157642Sps				sc->bce_flash_info = flash;
2133157642Sps				break;
2134157642Sps			}
2135157642Sps		}
2136157642Sps	} else {
2137157642Sps		/* Flash interface not yet reconfigured. */
2138157642Sps		u32 mask;
2139157642Sps
2140179771Sdavidch		DBPRINT(sc, BCE_INFO_LOAD, "%s(): Flash was NOT reconfigured.\n",
2141179771Sdavidch			__FUNCTION__);
2142157642Sps
2143157642Sps		if (val & (1 << 23))
2144157642Sps			mask = FLASH_BACKUP_STRAP_MASK;
2145157642Sps		else
2146157642Sps			mask = FLASH_STRAP_MASK;
2147157642Sps
2148157642Sps		/* Look for the matching NVRAM device configuration data. */
2149157642Sps		for (j = 0, flash = &flash_table[0]; j < entry_count; j++, flash++) {
2150157642Sps
2151157642Sps			/* Check if the device matches any of the known devices. */
2152157642Sps			if ((val & mask) == (flash->strapping & mask)) {
2153157642Sps				/* Found a device match. */
2154157642Sps				sc->bce_flash_info = flash;
2155157642Sps
2156157642Sps				/* Request access to the flash interface. */
2157157642Sps				if ((rc = bce_acquire_nvram_lock(sc)) != 0)
2158157642Sps					return rc;
2159157642Sps
2160157642Sps				/* Reconfigure the flash interface. */
2161157642Sps				bce_enable_nvram_access(sc);
2162157642Sps				REG_WR(sc, BCE_NVM_CFG1, flash->config1);
2163157642Sps				REG_WR(sc, BCE_NVM_CFG2, flash->config2);
2164157642Sps				REG_WR(sc, BCE_NVM_CFG3, flash->config3);
2165157642Sps				REG_WR(sc, BCE_NVM_WRITE1, flash->write1);
2166157642Sps				bce_disable_nvram_access(sc);
2167157642Sps				bce_release_nvram_lock(sc);
2168157642Sps
2169157642Sps				break;
2170157642Sps			}
2171157642Sps		}
2172157642Sps	}
2173157642Sps
2174157642Sps	/* Check if a matching device was found. */
2175157642Sps	if (j == entry_count) {
2176157642Sps		sc->bce_flash_info = NULL;
2177179771Sdavidch		BCE_PRINTF("%s(%d): Unknown Flash NVRAM found!\n",
2178157642Sps			__FILE__, __LINE__);
2179157642Sps		rc = ENODEV;
2180157642Sps	}
2181157642Sps
2182179771Sdavidchbce_init_nvram_get_flash_size:
2183157642Sps	/* Write the flash config data to the shared memory interface. */
2184194781Sdavidch	val = bce_shmem_rd(sc, BCE_SHARED_HW_CFG_CONFIG2);
2185157642Sps	val &= BCE_SHARED_HW_CFG2_NVM_SIZE_MASK;
2186157642Sps	if (val)
2187157642Sps		sc->bce_flash_size = val;
2188157642Sps	else
2189157642Sps		sc->bce_flash_size = sc->bce_flash_info->total_size;
2190157642Sps
2191179771Sdavidch	DBPRINT(sc, BCE_INFO_LOAD, "%s(): Found %s, size = 0x%08X\n",
2192179771Sdavidch		__FUNCTION__, sc->bce_flash_info->name,
2193157642Sps		sc->bce_flash_info->total_size);
2194157642Sps
2195179771Sdavidch	DBEXIT(BCE_VERBOSE_NVRAM);
2196157642Sps	return rc;
2197157642Sps}
2198157642Sps
2199157642Sps
2200157642Sps/****************************************************************************/
2201157642Sps/* Read an arbitrary range of data from NVRAM.                              */
2202157642Sps/*                                                                          */
2203157642Sps/* Prepares the NVRAM interface for access and reads the requested data     */
2204157642Sps/* into the supplied buffer.                                                */
2205157642Sps/*                                                                          */
2206157642Sps/* Returns:                                                                 */
2207157642Sps/*   0 on success and the data read, positive value on failure.             */
2208157642Sps/****************************************************************************/
2209157642Spsstatic int
2210157642Spsbce_nvram_read(struct bce_softc *sc, u32 offset, u8 *ret_buf,
2211157642Sps	int buf_size)
2212157642Sps{
2213157642Sps	int rc = 0;
2214157642Sps	u32 cmd_flags, offset32, len32, extra;
2215157642Sps
2216179771Sdavidch	DBENTER(BCE_VERBOSE_NVRAM);
2217179771Sdavidch
2218157642Sps	if (buf_size == 0)
2219179771Sdavidch		goto bce_nvram_read_exit;
2220157642Sps
2221157642Sps	/* Request access to the flash interface. */
2222157642Sps	if ((rc = bce_acquire_nvram_lock(sc)) != 0)
2223179771Sdavidch		goto bce_nvram_read_exit;
2224157642Sps
2225157642Sps	/* Enable access to flash interface */
2226157642Sps	bce_enable_nvram_access(sc);
2227157642Sps
2228157642Sps	len32 = buf_size;
2229157642Sps	offset32 = offset;
2230157642Sps	extra = 0;
2231157642Sps
2232157642Sps	cmd_flags = 0;
2233157642Sps
2234157642Sps	if (offset32 & 3) {
2235157642Sps		u8 buf[4];
2236157642Sps		u32 pre_len;
2237157642Sps
2238157642Sps		offset32 &= ~3;
2239157642Sps		pre_len = 4 - (offset & 3);
2240157642Sps
2241157642Sps		if (pre_len >= len32) {
2242157642Sps			pre_len = len32;
2243157642Sps			cmd_flags = BCE_NVM_COMMAND_FIRST | BCE_NVM_COMMAND_LAST;
2244157642Sps		}
2245157642Sps		else {
2246157642Sps			cmd_flags = BCE_NVM_COMMAND_FIRST;
2247157642Sps		}
2248157642Sps
2249157642Sps		rc = bce_nvram_read_dword(sc, offset32, buf, cmd_flags);
2250157642Sps
2251157642Sps		if (rc)
2252157642Sps			return rc;
2253157642Sps
2254157642Sps		memcpy(ret_buf, buf + (offset & 3), pre_len);
2255157642Sps
2256157642Sps		offset32 += 4;
2257157642Sps		ret_buf += pre_len;
2258157642Sps		len32 -= pre_len;
2259157642Sps	}
2260157642Sps
2261157642Sps	if (len32 & 3) {
2262157642Sps		extra = 4 - (len32 & 3);
2263157642Sps		len32 = (len32 + 4) & ~3;
2264157642Sps	}
2265157642Sps
2266157642Sps	if (len32 == 4) {
2267157642Sps		u8 buf[4];
2268157642Sps
2269157642Sps		if (cmd_flags)
2270157642Sps			cmd_flags = BCE_NVM_COMMAND_LAST;
2271157642Sps		else
2272157642Sps			cmd_flags = BCE_NVM_COMMAND_FIRST |
2273157642Sps				    BCE_NVM_COMMAND_LAST;
2274157642Sps
2275157642Sps		rc = bce_nvram_read_dword(sc, offset32, buf, cmd_flags);
2276157642Sps
2277157642Sps		memcpy(ret_buf, buf, 4 - extra);
2278157642Sps	}
2279157642Sps	else if (len32 > 0) {
2280157642Sps		u8 buf[4];
2281157642Sps
2282157642Sps		/* Read the first word. */
2283157642Sps		if (cmd_flags)
2284157642Sps			cmd_flags = 0;
2285157642Sps		else
2286157642Sps			cmd_flags = BCE_NVM_COMMAND_FIRST;
2287157642Sps
2288157642Sps		rc = bce_nvram_read_dword(sc, offset32, ret_buf, cmd_flags);
2289157642Sps
2290157642Sps		/* Advance to the next dword. */
2291157642Sps		offset32 += 4;
2292157642Sps		ret_buf += 4;
2293157642Sps		len32 -= 4;
2294157642Sps
2295157642Sps		while (len32 > 4 && rc == 0) {
2296157642Sps			rc = bce_nvram_read_dword(sc, offset32, ret_buf, 0);
2297157642Sps
2298157642Sps			/* Advance to the next dword. */
2299157642Sps			offset32 += 4;
2300157642Sps			ret_buf += 4;
2301157642Sps			len32 -= 4;
2302157642Sps		}
2303157642Sps
2304157642Sps		if (rc)
2305179771Sdavidch			goto bce_nvram_read_locked_exit;
2306157642Sps
2307157642Sps		cmd_flags = BCE_NVM_COMMAND_LAST;
2308157642Sps		rc = bce_nvram_read_dword(sc, offset32, buf, cmd_flags);
2309157642Sps
2310157642Sps		memcpy(ret_buf, buf, 4 - extra);
2311157642Sps	}
2312157642Sps
2313179771Sdavidchbce_nvram_read_locked_exit:
2314157642Sps	/* Disable access to flash interface and release the lock. */
2315157642Sps	bce_disable_nvram_access(sc);
2316157642Sps	bce_release_nvram_lock(sc);
2317157642Sps
2318179771Sdavidchbce_nvram_read_exit:
2319179771Sdavidch	DBEXIT(BCE_VERBOSE_NVRAM);
2320157642Sps	return rc;
2321157642Sps}
2322157642Sps
2323157642Sps
2324157642Sps#ifdef BCE_NVRAM_WRITE_SUPPORT
2325157642Sps/****************************************************************************/
2326157642Sps/* Write an arbitrary range of data from NVRAM.                             */
2327157642Sps/*                                                                          */
2328157642Sps/* Prepares the NVRAM interface for write access and writes the requested   */
2329157642Sps/* data from the supplied buffer.  The caller is responsible for            */
2330157642Sps/* calculating any appropriate CRCs.                                        */
2331157642Sps/*                                                                          */
2332157642Sps/* Returns:                                                                 */
2333157642Sps/*   0 on success, positive value on failure.                               */
2334157642Sps/****************************************************************************/
2335157642Spsstatic int
2336157642Spsbce_nvram_write(struct bce_softc *sc, u32 offset, u8 *data_buf,
2337157642Sps	int buf_size)
2338157642Sps{
2339157642Sps	u32 written, offset32, len32;
2340157642Sps	u8 *buf, start[4], end[4];
2341157642Sps	int rc = 0;
2342157642Sps	int align_start, align_end;
2343157642Sps
2344179771Sdavidch	DBENTER(BCE_VERBOSE_NVRAM);
2345179771Sdavidch
2346157642Sps	buf = data_buf;
2347157642Sps	offset32 = offset;
2348157642Sps	len32 = buf_size;
2349157642Sps	align_start = align_end = 0;
2350157642Sps
2351157642Sps	if ((align_start = (offset32 & 3))) {
2352157642Sps		offset32 &= ~3;
2353157642Sps		len32 += align_start;
2354157642Sps		if ((rc = bce_nvram_read(sc, offset32, start, 4)))
2355179771Sdavidch			goto bce_nvram_write_exit;
2356157642Sps	}
2357157642Sps
2358157642Sps	if (len32 & 3) {
2359157642Sps	       	if ((len32 > 4) || !align_start) {
2360157642Sps			align_end = 4 - (len32 & 3);
2361157642Sps			len32 += align_end;
2362157642Sps			if ((rc = bce_nvram_read(sc, offset32 + len32 - 4,
2363157642Sps				end, 4))) {
2364179771Sdavidch				goto bce_nvram_write_exit;
2365157642Sps			}
2366157642Sps		}
2367157642Sps	}
2368157642Sps
2369157642Sps	if (align_start || align_end) {
2370157642Sps		buf = malloc(len32, M_DEVBUF, M_NOWAIT);
2371179771Sdavidch		if (buf == 0) {
2372179771Sdavidch			rc = ENOMEM;
2373179771Sdavidch			goto bce_nvram_write_exit;
2374179771Sdavidch		}
2375179771Sdavidch
2376157642Sps		if (align_start) {
2377157642Sps			memcpy(buf, start, 4);
2378157642Sps		}
2379179771Sdavidch
2380157642Sps		if (align_end) {
2381157642Sps			memcpy(buf + len32 - 4, end, 4);
2382157642Sps		}
2383157642Sps		memcpy(buf + align_start, data_buf, buf_size);
2384157642Sps	}
2385157642Sps
2386157642Sps	written = 0;
2387157642Sps	while ((written < len32) && (rc == 0)) {
2388157642Sps		u32 page_start, page_end, data_start, data_end;
2389157642Sps		u32 addr, cmd_flags;
2390157642Sps		int i;
2391157642Sps		u8 flash_buffer[264];
2392157642Sps
2393157642Sps	    /* Find the page_start addr */
2394157642Sps		page_start = offset32 + written;
2395157642Sps		page_start -= (page_start % sc->bce_flash_info->page_size);
2396157642Sps		/* Find the page_end addr */
2397157642Sps		page_end = page_start + sc->bce_flash_info->page_size;
2398157642Sps		/* Find the data_start addr */
2399157642Sps		data_start = (written == 0) ? offset32 : page_start;
2400157642Sps		/* Find the data_end addr */
2401157642Sps		data_end = (page_end > offset32 + len32) ?
2402157642Sps			(offset32 + len32) : page_end;
2403157642Sps
2404157642Sps		/* Request access to the flash interface. */
2405157642Sps		if ((rc = bce_acquire_nvram_lock(sc)) != 0)
2406179771Sdavidch			goto bce_nvram_write_exit;
2407157642Sps
2408157642Sps		/* Enable access to flash interface */
2409157642Sps		bce_enable_nvram_access(sc);
2410157642Sps
2411157642Sps		cmd_flags = BCE_NVM_COMMAND_FIRST;
2412179771Sdavidch		if (!(sc->bce_flash_info->flags & BCE_NV_BUFFERED)) {
2413157642Sps			int j;
2414157642Sps
2415157642Sps			/* Read the whole page into the buffer
2416157642Sps			 * (non-buffer flash only) */
2417157642Sps			for (j = 0; j < sc->bce_flash_info->page_size; j += 4) {
2418157642Sps				if (j == (sc->bce_flash_info->page_size - 4)) {
2419157642Sps					cmd_flags |= BCE_NVM_COMMAND_LAST;
2420157642Sps				}
2421157642Sps				rc = bce_nvram_read_dword(sc,
2422157642Sps					page_start + j,
2423157642Sps					&flash_buffer[j],
2424157642Sps					cmd_flags);
2425157642Sps
2426157642Sps				if (rc)
2427179771Sdavidch					goto bce_nvram_write_locked_exit;
2428157642Sps
2429157642Sps				cmd_flags = 0;
2430157642Sps			}
2431157642Sps		}
2432157642Sps
2433157642Sps		/* Enable writes to flash interface (unlock write-protect) */
2434157642Sps		if ((rc = bce_enable_nvram_write(sc)) != 0)
2435179771Sdavidch			goto bce_nvram_write_locked_exit;
2436157642Sps
2437157642Sps		/* Erase the page */
2438157642Sps		if ((rc = bce_nvram_erase_page(sc, page_start)) != 0)
2439179771Sdavidch			goto bce_nvram_write_locked_exit;
2440157642Sps
2441157642Sps		/* Re-enable the write again for the actual write */
2442157642Sps		bce_enable_nvram_write(sc);
2443157642Sps
2444157642Sps		/* Loop to write back the buffer data from page_start to
2445157642Sps		 * data_start */
2446157642Sps		i = 0;
2447179771Sdavidch		if (!(sc->bce_flash_info->flags & BCE_NV_BUFFERED)) {
2448157642Sps			for (addr = page_start; addr < data_start;
2449157642Sps				addr += 4, i += 4) {
2450157642Sps
2451157642Sps				rc = bce_nvram_write_dword(sc, addr,
2452157642Sps					&flash_buffer[i], cmd_flags);
2453157642Sps
2454157642Sps				if (rc != 0)
2455179771Sdavidch					goto bce_nvram_write_locked_exit;
2456157642Sps
2457157642Sps				cmd_flags = 0;
2458157642Sps			}
2459157642Sps		}
2460157642Sps
2461157642Sps		/* Loop to write the new data from data_start to data_end */
2462157642Sps		for (addr = data_start; addr < data_end; addr += 4, i++) {
2463157642Sps			if ((addr == page_end - 4) ||
2464179771Sdavidch				((sc->bce_flash_info->flags & BCE_NV_BUFFERED) &&
2465179771Sdavidch				(addr == data_end - 4))) {
2466157642Sps
2467157642Sps				cmd_flags |= BCE_NVM_COMMAND_LAST;
2468157642Sps			}
2469157642Sps			rc = bce_nvram_write_dword(sc, addr, buf,
2470157642Sps				cmd_flags);
2471157642Sps
2472157642Sps			if (rc != 0)
2473179771Sdavidch				goto bce_nvram_write_locked_exit;
2474157642Sps
2475157642Sps			cmd_flags = 0;
2476157642Sps			buf += 4;
2477157642Sps		}
2478157642Sps
2479157642Sps		/* Loop to write back the buffer data from data_end
2480157642Sps		 * to page_end */
2481179771Sdavidch		if (!(sc->bce_flash_info->flags & BCE_NV_BUFFERED)) {
2482157642Sps			for (addr = data_end; addr < page_end;
2483157642Sps				addr += 4, i += 4) {
2484157642Sps
2485157642Sps				if (addr == page_end-4) {
2486157642Sps					cmd_flags = BCE_NVM_COMMAND_LAST;
2487157642Sps                		}
2488157642Sps				rc = bce_nvram_write_dword(sc, addr,
2489157642Sps					&flash_buffer[i], cmd_flags);
2490157642Sps
2491157642Sps				if (rc != 0)
2492179771Sdavidch					goto bce_nvram_write_locked_exit;
2493157642Sps
2494157642Sps				cmd_flags = 0;
2495157642Sps			}
2496157642Sps		}
2497157642Sps
2498157642Sps		/* Disable writes to flash interface (lock write-protect) */
2499157642Sps		bce_disable_nvram_write(sc);
2500157642Sps
2501157642Sps		/* Disable access to flash interface */
2502157642Sps		bce_disable_nvram_access(sc);
2503157642Sps		bce_release_nvram_lock(sc);
2504157642Sps
2505157642Sps		/* Increment written */
2506157642Sps		written += data_end - data_start;
2507157642Sps	}
2508157642Sps
2509179771Sdavidch	goto bce_nvram_write_exit;
2510179771Sdavidch
2511179771Sdavidchbce_nvram_write_locked_exit:
2512179771Sdavidch		bce_disable_nvram_write(sc);
2513179771Sdavidch		bce_disable_nvram_access(sc);
2514179771Sdavidch		bce_release_nvram_lock(sc);
2515179771Sdavidch
2516179771Sdavidchbce_nvram_write_exit:
2517157642Sps	if (align_start || align_end)
2518157642Sps		free(buf, M_DEVBUF);
2519157642Sps
2520179771Sdavidch	DBEXIT(BCE_VERBOSE_NVRAM);
2521179771Sdavidch	return (rc);
2522157642Sps}
2523157642Sps#endif /* BCE_NVRAM_WRITE_SUPPORT */
2524157642Sps
2525157642Sps
2526157642Sps/****************************************************************************/
2527157642Sps/* Verifies that NVRAM is accessible and contains valid data.               */
2528157642Sps/*                                                                          */
2529157642Sps/* Reads the configuration data from NVRAM and verifies that the CRC is     */
2530157642Sps/* correct.                                                                 */
2531157642Sps/*                                                                          */
2532157642Sps/* Returns:                                                                 */
2533157642Sps/*   0 on success, positive value on failure.                               */
2534157642Sps/****************************************************************************/
2535157642Spsstatic int
2536157642Spsbce_nvram_test(struct bce_softc *sc)
2537157642Sps{
2538157642Sps	u32 buf[BCE_NVRAM_SIZE / 4];
2539157642Sps	u8 *data = (u8 *) buf;
2540157642Sps	int rc = 0;
2541157642Sps	u32 magic, csum;
2542157642Sps
2543179771Sdavidch	DBENTER(BCE_VERBOSE_NVRAM | BCE_VERBOSE_LOAD | BCE_VERBOSE_RESET);
2544157642Sps
2545157642Sps	/*
2546157642Sps	 * Check that the device NVRAM is valid by reading
2547157642Sps	 * the magic value at offset 0.
2548157642Sps	 */
2549179771Sdavidch	if ((rc = bce_nvram_read(sc, 0, data, 4)) != 0) {
2550179771Sdavidch		BCE_PRINTF("%s(%d): Unable to read NVRAM!\n", __FILE__, __LINE__);
2551179771Sdavidch		goto bce_nvram_test_exit;
2552179771Sdavidch	}
2553157642Sps
2554179771Sdavidch	/*
2555179771Sdavidch	 * Verify that offset 0 of the NVRAM contains
2556179771Sdavidch	 * a valid magic number.
2557179771Sdavidch	 */
2558157642Sps    magic = bce_be32toh(buf[0]);
2559157642Sps	if (magic != BCE_NVRAM_MAGIC) {
2560157642Sps		rc = ENODEV;
2561169271Sdavidch		BCE_PRINTF("%s(%d): Invalid NVRAM magic value! Expected: 0x%08X, "
2562157642Sps			"Found: 0x%08X\n",
2563157642Sps			__FILE__, __LINE__, BCE_NVRAM_MAGIC, magic);
2564179771Sdavidch		goto bce_nvram_test_exit;
2565157642Sps	}
2566157642Sps
2567157642Sps	/*
2568157642Sps	 * Verify that the device NVRAM includes valid
2569157642Sps	 * configuration data.
2570157642Sps	 */
2571179771Sdavidch	if ((rc = bce_nvram_read(sc, 0x100, data, BCE_NVRAM_SIZE)) != 0) {
2572179771Sdavidch		BCE_PRINTF("%s(%d): Unable to read Manufacturing Information from "
2573179771Sdavidch			"NVRAM!\n", __FILE__, __LINE__);
2574179771Sdavidch		goto bce_nvram_test_exit;
2575179771Sdavidch	}
2576157642Sps
2577157642Sps	csum = ether_crc32_le(data, 0x100);
2578157642Sps	if (csum != BCE_CRC32_RESIDUAL) {
2579157642Sps		rc = ENODEV;
2580169271Sdavidch		BCE_PRINTF("%s(%d): Invalid Manufacturing Information NVRAM CRC! "
2581157642Sps			"Expected: 0x%08X, Found: 0x%08X\n",
2582157642Sps			__FILE__, __LINE__, BCE_CRC32_RESIDUAL, csum);
2583179771Sdavidch		goto bce_nvram_test_exit;
2584157642Sps	}
2585157642Sps
2586157642Sps	csum = ether_crc32_le(data + 0x100, 0x100);
2587157642Sps	if (csum != BCE_CRC32_RESIDUAL) {
2588179771Sdavidch		rc = ENODEV;
2589169271Sdavidch		BCE_PRINTF("%s(%d): Invalid Feature Configuration Information "
2590157642Sps			"NVRAM CRC! Expected: 0x%08X, Found: 08%08X\n",
2591157642Sps			__FILE__, __LINE__, BCE_CRC32_RESIDUAL, csum);
2592157642Sps	}
2593157642Sps
2594179771Sdavidchbce_nvram_test_exit:
2595179771Sdavidch	DBEXIT(BCE_VERBOSE_NVRAM | BCE_VERBOSE_LOAD | BCE_VERBOSE_RESET);
2596157642Sps	return rc;
2597157642Sps}
2598157642Sps
2599157642Sps
2600157642Sps/****************************************************************************/
2601179771Sdavidch/* Identifies the current media type of the controller and sets the PHY     */
2602179771Sdavidch/* address.                                                                 */
2603179771Sdavidch/*                                                                          */
2604179771Sdavidch/* Returns:                                                                 */
2605179771Sdavidch/*   Nothing.                                                               */
2606179771Sdavidch/****************************************************************************/
2607179771Sdavidchstatic void
2608179771Sdavidchbce_get_media(struct bce_softc *sc)
2609179771Sdavidch{
2610179771Sdavidch	u32 val;
2611179771Sdavidch
2612179771Sdavidch	DBENTER(BCE_VERBOSE);
2613179771Sdavidch
2614182293Sdavidch	/* Assume PHY address for copper controllers. */
2615179771Sdavidch	sc->bce_phy_addr = 1;
2616179771Sdavidch
2617179771Sdavidch	if (BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5709) {
2618179771Sdavidch 		u32 val = REG_RD(sc, BCE_MISC_DUAL_MEDIA_CTRL);
2619179771Sdavidch		u32 bond_id = val & BCE_MISC_DUAL_MEDIA_CTRL_BOND_ID;
2620179771Sdavidch		u32 strap;
2621179771Sdavidch
2622179771Sdavidch		/*
2623179771Sdavidch		 * The BCM5709S is software configurable
2624179771Sdavidch		 * for Copper or SerDes operation.
2625179771Sdavidch		 */
2626179771Sdavidch		if (bond_id == BCE_MISC_DUAL_MEDIA_CTRL_BOND_ID_C) {
2627179771Sdavidch			DBPRINT(sc, BCE_INFO_LOAD, "5709 bonded for copper.\n");
2628179771Sdavidch			goto bce_get_media_exit;
2629179771Sdavidch		} else if (bond_id == BCE_MISC_DUAL_MEDIA_CTRL_BOND_ID_S) {
2630179771Sdavidch			DBPRINT(sc, BCE_INFO_LOAD, "5709 bonded for dual media.\n");
2631179771Sdavidch			sc->bce_phy_flags |= BCE_PHY_SERDES_FLAG;
2632179771Sdavidch			goto bce_get_media_exit;
2633179771Sdavidch		}
2634179771Sdavidch
2635179771Sdavidch		if (val & BCE_MISC_DUAL_MEDIA_CTRL_STRAP_OVERRIDE)
2636179771Sdavidch			strap = (val & BCE_MISC_DUAL_MEDIA_CTRL_PHY_CTRL) >> 21;
2637179771Sdavidch		else
2638179771Sdavidch			strap = (val & BCE_MISC_DUAL_MEDIA_CTRL_PHY_CTRL_STRAP) >> 8;
2639179771Sdavidch
2640179771Sdavidch		if (pci_get_function(sc->bce_dev) == 0) {
2641179771Sdavidch			switch (strap) {
2642179771Sdavidch			case 0x4:
2643179771Sdavidch			case 0x5:
2644179771Sdavidch			case 0x6:
2645182293Sdavidch				DBPRINT(sc, BCE_INFO_LOAD,
2646179771Sdavidch					"BCM5709 s/w configured for SerDes.\n");
2647179771Sdavidch				sc->bce_phy_flags |= BCE_PHY_SERDES_FLAG;
2648179771Sdavidch			default:
2649182293Sdavidch				DBPRINT(sc, BCE_INFO_LOAD,
2650179771Sdavidch					"BCM5709 s/w configured for Copper.\n");
2651179771Sdavidch			}
2652179771Sdavidch		} else {
2653179771Sdavidch			switch (strap) {
2654179771Sdavidch			case 0x1:
2655179771Sdavidch			case 0x2:
2656179771Sdavidch			case 0x4:
2657182293Sdavidch				DBPRINT(sc, BCE_INFO_LOAD,
2658179771Sdavidch					"BCM5709 s/w configured for SerDes.\n");
2659179771Sdavidch				sc->bce_phy_flags |= BCE_PHY_SERDES_FLAG;
2660179771Sdavidch			default:
2661182293Sdavidch				DBPRINT(sc, BCE_INFO_LOAD,
2662179771Sdavidch					"BCM5709 s/w configured for Copper.\n");
2663179771Sdavidch			}
2664179771Sdavidch		}
2665179771Sdavidch
2666179771Sdavidch	} else if (BCE_CHIP_BOND_ID(sc) & BCE_CHIP_BOND_ID_SERDES_BIT)
2667179771Sdavidch		sc->bce_phy_flags |= BCE_PHY_SERDES_FLAG;
2668179771Sdavidch
2669185082Sdelphij	if (sc->bce_phy_flags & BCE_PHY_SERDES_FLAG) {
2670179771Sdavidch		sc->bce_flags |= BCE_NO_WOL_FLAG;
2671179771Sdavidch		if (BCE_CHIP_NUM(sc) != BCE_CHIP_NUM_5706) {
2672179771Sdavidch			sc->bce_phy_addr = 2;
2673194781Sdavidch			val = bce_shmem_rd(sc, BCE_SHARED_HW_CFG_CONFIG);
2674179771Sdavidch			if (val & BCE_SHARED_HW_CFG_PHY_2_5G) {
2675179771Sdavidch				sc->bce_phy_flags |= BCE_PHY_2_5G_CAPABLE_FLAG;
2676179771Sdavidch				DBPRINT(sc, BCE_INFO_LOAD, "Found 2.5Gb capable adapter\n");
2677179771Sdavidch			}
2678179771Sdavidch		}
2679179771Sdavidch	} else if ((BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5706) ||
2680179771Sdavidch		   (BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5708))
2681179771Sdavidch		sc->bce_phy_flags |= BCE_PHY_CRC_FIX_FLAG;
2682179771Sdavidch
2683179771Sdavidchbce_get_media_exit:
2684182293Sdavidch	DBPRINT(sc, (BCE_INFO_LOAD | BCE_INFO_PHY),
2685179771Sdavidch		"Using PHY address %d.\n", sc->bce_phy_addr);
2686182293Sdavidch
2687179771Sdavidch	DBEXIT(BCE_VERBOSE);
2688179771Sdavidch}
2689179771Sdavidch
2690179771Sdavidch
2691179771Sdavidch/****************************************************************************/
2692157642Sps/* Free any DMA memory owned by the driver.                                 */
2693157642Sps/*                                                                          */
2694157642Sps/* Scans through each data structre that requires DMA memory and frees      */
2695157642Sps/* the memory if allocated.                                                 */
2696157642Sps/*                                                                          */
2697157642Sps/* Returns:                                                                 */
2698157642Sps/*   Nothing.                                                               */
2699157642Sps/****************************************************************************/
2700157642Spsstatic void
2701157642Spsbce_dma_free(struct bce_softc *sc)
2702157642Sps{
2703157642Sps	int i;
2704157642Sps
2705179771Sdavidch	DBENTER(BCE_VERBOSE_RESET | BCE_VERBOSE_UNLOAD | BCE_VERBOSE_CTX);
2706157642Sps
2707179771Sdavidch	/* Free, unmap, and destroy the status block. */
2708176448Sdavidch	if (sc->status_block != NULL) {
2709157642Sps		bus_dmamem_free(
2710157642Sps			sc->status_tag,
2711157642Sps		    sc->status_block,
2712157642Sps		    sc->status_map);
2713176448Sdavidch		sc->status_block = NULL;
2714176448Sdavidch	}
2715157642Sps
2716157642Sps	if (sc->status_map != NULL) {
2717157642Sps		bus_dmamap_unload(
2718157642Sps			sc->status_tag,
2719157642Sps		    sc->status_map);
2720157642Sps		bus_dmamap_destroy(sc->status_tag,
2721157642Sps		    sc->status_map);
2722176448Sdavidch		sc->status_map = NULL;
2723157642Sps	}
2724157642Sps
2725176448Sdavidch	if (sc->status_tag != NULL) {
2726157642Sps		bus_dma_tag_destroy(sc->status_tag);
2727176448Sdavidch		sc->status_tag = NULL;
2728176448Sdavidch	}
2729157642Sps
2730157642Sps
2731179771Sdavidch	/* Free, unmap, and destroy the statistics block. */
2732176448Sdavidch	if (sc->stats_block != NULL) {
2733157642Sps		bus_dmamem_free(
2734157642Sps			sc->stats_tag,
2735157642Sps		    sc->stats_block,
2736157642Sps		    sc->stats_map);
2737176448Sdavidch		sc->stats_block = NULL;
2738176448Sdavidch	}
2739157642Sps
2740157642Sps	if (sc->stats_map != NULL) {
2741157642Sps		bus_dmamap_unload(
2742157642Sps			sc->stats_tag,
2743157642Sps		    sc->stats_map);
2744157642Sps		bus_dmamap_destroy(sc->stats_tag,
2745157642Sps		    sc->stats_map);
2746176448Sdavidch		sc->stats_map = NULL;
2747157642Sps	}
2748157642Sps
2749176448Sdavidch	if (sc->stats_tag != NULL) {
2750157642Sps		bus_dma_tag_destroy(sc->stats_tag);
2751176448Sdavidch		sc->stats_tag = NULL;
2752176448Sdavidch	}
2753157642Sps
2754157642Sps
2755179771Sdavidch	/* Free, unmap and destroy all context memory pages. */
2756182293Sdavidch	if ((BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5709) ||
2757182293Sdavidch		(BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5716)) {
2758179771Sdavidch		for (i = 0; i < sc->ctx_pages; i++ ) {
2759179771Sdavidch			if (sc->ctx_block[i] != NULL) {
2760179771Sdavidch				bus_dmamem_free(
2761179771Sdavidch					sc->ctx_tag,
2762179771Sdavidch				    sc->ctx_block[i],
2763179771Sdavidch				    sc->ctx_map[i]);
2764179771Sdavidch				sc->ctx_block[i] = NULL;
2765179771Sdavidch			}
2766179771Sdavidch
2767179771Sdavidch			if (sc->ctx_map[i] != NULL) {
2768179771Sdavidch				bus_dmamap_unload(
2769179771Sdavidch					sc->ctx_tag,
2770179771Sdavidch		    		sc->ctx_map[i]);
2771179771Sdavidch				bus_dmamap_destroy(
2772179771Sdavidch					sc->ctx_tag,
2773179771Sdavidch				    sc->ctx_map[i]);
2774179771Sdavidch				sc->ctx_map[i] = NULL;
2775179771Sdavidch			}
2776179771Sdavidch		}
2777179771Sdavidch
2778179771Sdavidch		/* Destroy the context memory tag. */
2779179771Sdavidch		if (sc->ctx_tag != NULL) {
2780179771Sdavidch			bus_dma_tag_destroy(sc->ctx_tag);
2781179771Sdavidch			sc->ctx_tag = NULL;
2782179771Sdavidch		}
2783179771Sdavidch	}
2784179771Sdavidch
2785179771Sdavidch
2786157642Sps	/* Free, unmap and destroy all TX buffer descriptor chain pages. */
2787157642Sps	for (i = 0; i < TX_PAGES; i++ ) {
2788176448Sdavidch		if (sc->tx_bd_chain[i] != NULL) {
2789157642Sps			bus_dmamem_free(
2790157642Sps				sc->tx_bd_chain_tag,
2791157642Sps			    sc->tx_bd_chain[i],
2792157642Sps			    sc->tx_bd_chain_map[i]);
2793176448Sdavidch			sc->tx_bd_chain[i] = NULL;
2794176448Sdavidch		}
2795157642Sps
2796157642Sps		if (sc->tx_bd_chain_map[i] != NULL) {
2797157642Sps			bus_dmamap_unload(
2798157642Sps				sc->tx_bd_chain_tag,
2799157642Sps		    	sc->tx_bd_chain_map[i]);
2800157642Sps			bus_dmamap_destroy(
2801157642Sps				sc->tx_bd_chain_tag,
2802157642Sps			    sc->tx_bd_chain_map[i]);
2803176448Sdavidch			sc->tx_bd_chain_map[i] = NULL;
2804157642Sps		}
2805157642Sps	}
2806157642Sps
2807157642Sps	/* Destroy the TX buffer descriptor tag. */
2808176448Sdavidch	if (sc->tx_bd_chain_tag != NULL) {
2809157642Sps		bus_dma_tag_destroy(sc->tx_bd_chain_tag);
2810176448Sdavidch		sc->tx_bd_chain_tag = NULL;
2811176448Sdavidch	}
2812157642Sps
2813157642Sps
2814157642Sps	/* Free, unmap and destroy all RX buffer descriptor chain pages. */
2815157642Sps	for (i = 0; i < RX_PAGES; i++ ) {
2816176448Sdavidch		if (sc->rx_bd_chain[i] != NULL) {
2817157642Sps			bus_dmamem_free(
2818157642Sps				sc->rx_bd_chain_tag,
2819157642Sps			    sc->rx_bd_chain[i],
2820157642Sps			    sc->rx_bd_chain_map[i]);
2821176448Sdavidch			sc->rx_bd_chain[i] = NULL;
2822176448Sdavidch		}
2823157642Sps
2824157642Sps		if (sc->rx_bd_chain_map[i] != NULL) {
2825157642Sps			bus_dmamap_unload(
2826157642Sps				sc->rx_bd_chain_tag,
2827157642Sps		    	sc->rx_bd_chain_map[i]);
2828157642Sps			bus_dmamap_destroy(
2829157642Sps				sc->rx_bd_chain_tag,
2830157642Sps			    sc->rx_bd_chain_map[i]);
2831176448Sdavidch			sc->rx_bd_chain_map[i] = NULL;
2832157642Sps		}
2833157642Sps	}
2834157642Sps
2835157642Sps	/* Destroy the RX buffer descriptor tag. */
2836176448Sdavidch	if (sc->rx_bd_chain_tag != NULL) {
2837157642Sps		bus_dma_tag_destroy(sc->rx_bd_chain_tag);
2838176448Sdavidch		sc->rx_bd_chain_tag = NULL;
2839176448Sdavidch	}
2840157642Sps
2841157642Sps
2842198320Sstas#ifdef BCE_JUMBO_HDRSPLIT
2843176448Sdavidch	/* Free, unmap and destroy all page buffer descriptor chain pages. */
2844176448Sdavidch	for (i = 0; i < PG_PAGES; i++ ) {
2845176448Sdavidch		if (sc->pg_bd_chain[i] != NULL) {
2846176448Sdavidch			bus_dmamem_free(
2847176448Sdavidch				sc->pg_bd_chain_tag,
2848176448Sdavidch			    sc->pg_bd_chain[i],
2849176448Sdavidch			    sc->pg_bd_chain_map[i]);
2850176448Sdavidch			sc->pg_bd_chain[i] = NULL;
2851176448Sdavidch		}
2852176448Sdavidch
2853176448Sdavidch		if (sc->pg_bd_chain_map[i] != NULL) {
2854176448Sdavidch			bus_dmamap_unload(
2855176448Sdavidch				sc->pg_bd_chain_tag,
2856176448Sdavidch		    	sc->pg_bd_chain_map[i]);
2857176448Sdavidch			bus_dmamap_destroy(
2858176448Sdavidch				sc->pg_bd_chain_tag,
2859176448Sdavidch			    sc->pg_bd_chain_map[i]);
2860176448Sdavidch			sc->pg_bd_chain_map[i] = NULL;
2861176448Sdavidch		}
2862176448Sdavidch	}
2863176448Sdavidch
2864176448Sdavidch	/* Destroy the page buffer descriptor tag. */
2865176448Sdavidch	if (sc->pg_bd_chain_tag != NULL) {
2866176448Sdavidch		bus_dma_tag_destroy(sc->pg_bd_chain_tag);
2867176448Sdavidch		sc->pg_bd_chain_tag = NULL;
2868176448Sdavidch	}
2869179771Sdavidch#endif
2870176448Sdavidch
2871176448Sdavidch
2872157642Sps	/* Unload and destroy the TX mbuf maps. */
2873157642Sps	for (i = 0; i < TOTAL_TX_BD; i++) {
2874157642Sps		if (sc->tx_mbuf_map[i] != NULL) {
2875179771Sdavidch			bus_dmamap_unload(sc->tx_mbuf_tag,
2876157642Sps				sc->tx_mbuf_map[i]);
2877179771Sdavidch			bus_dmamap_destroy(sc->tx_mbuf_tag,
2878157642Sps	 			sc->tx_mbuf_map[i]);
2879176448Sdavidch			sc->tx_mbuf_map[i] = NULL;
2880157642Sps		}
2881157642Sps	}
2882157642Sps
2883157642Sps	/* Destroy the TX mbuf tag. */
2884176448Sdavidch	if (sc->tx_mbuf_tag != NULL) {
2885157642Sps		bus_dma_tag_destroy(sc->tx_mbuf_tag);
2886176448Sdavidch		sc->tx_mbuf_tag = NULL;
2887176448Sdavidch	}
2888157642Sps
2889157642Sps	/* Unload and destroy the RX mbuf maps. */
2890157642Sps	for (i = 0; i < TOTAL_RX_BD; i++) {
2891157642Sps		if (sc->rx_mbuf_map[i] != NULL) {
2892179771Sdavidch			bus_dmamap_unload(sc->rx_mbuf_tag,
2893157642Sps				sc->rx_mbuf_map[i]);
2894179771Sdavidch			bus_dmamap_destroy(sc->rx_mbuf_tag,
2895157642Sps	 			sc->rx_mbuf_map[i]);
2896176448Sdavidch			sc->rx_mbuf_map[i] = NULL;
2897157642Sps		}
2898157642Sps	}
2899157642Sps
2900157642Sps	/* Destroy the RX mbuf tag. */
2901176448Sdavidch	if (sc->rx_mbuf_tag != NULL) {
2902157642Sps		bus_dma_tag_destroy(sc->rx_mbuf_tag);
2903176448Sdavidch		sc->rx_mbuf_tag = NULL;
2904176448Sdavidch	}
2905157642Sps
2906198320Sstas#ifdef BCE_JUMBO_HDRSPLIT
2907176448Sdavidch	/* Unload and destroy the page mbuf maps. */
2908176448Sdavidch	for (i = 0; i < TOTAL_PG_BD; i++) {
2909176448Sdavidch		if (sc->pg_mbuf_map[i] != NULL) {
2910179771Sdavidch			bus_dmamap_unload(sc->pg_mbuf_tag,
2911176448Sdavidch				sc->pg_mbuf_map[i]);
2912179771Sdavidch			bus_dmamap_destroy(sc->pg_mbuf_tag,
2913176448Sdavidch	 			sc->pg_mbuf_map[i]);
2914176448Sdavidch			sc->pg_mbuf_map[i] = NULL;
2915176448Sdavidch		}
2916176448Sdavidch	}
2917157642Sps
2918176448Sdavidch	/* Destroy the page mbuf tag. */
2919176448Sdavidch	if (sc->pg_mbuf_tag != NULL) {
2920176448Sdavidch		bus_dma_tag_destroy(sc->pg_mbuf_tag);
2921176448Sdavidch		sc->pg_mbuf_tag = NULL;
2922176448Sdavidch	}
2923179771Sdavidch#endif
2924176448Sdavidch
2925157642Sps	/* Destroy the parent tag */
2926176448Sdavidch	if (sc->parent_tag != NULL) {
2927157642Sps		bus_dma_tag_destroy(sc->parent_tag);
2928176448Sdavidch		sc->parent_tag = NULL;
2929176448Sdavidch	}
2930157642Sps
2931179771Sdavidch	DBEXIT(BCE_VERBOSE_RESET | BCE_VERBOSE_UNLOAD | BCE_VERBOSE_CTX);
2932157642Sps}
2933157642Sps
2934157642Sps
2935157642Sps/****************************************************************************/
2936157642Sps/* Get DMA memory from the OS.                                              */
2937157642Sps/*                                                                          */
2938157642Sps/* Validates that the OS has provided DMA buffers in response to a          */
2939157642Sps/* bus_dmamap_load() call and saves the physical address of those buffers.  */
2940157642Sps/* When the callback is used the OS will return 0 for the mapping function  */
2941157642Sps/* (bus_dmamap_load()) so we use the value of map_arg->maxsegs to pass any  */
2942157642Sps/* failures back to the caller.                                             */
2943157642Sps/*                                                                          */
2944157642Sps/* Returns:                                                                 */
2945157642Sps/*   Nothing.                                                               */
2946157642Sps/****************************************************************************/
2947157642Spsstatic void
2948157642Spsbce_dma_map_addr(void *arg, bus_dma_segment_t *segs, int nseg, int error)
2949157642Sps{
2950163393Sscottl	bus_addr_t *busaddr = arg;
2951157642Sps
2952157642Sps	/* Simulate a mapping failure. */
2953189325Sdavidch	DBRUNIF(DB_RANDOMTRUE(dma_map_addr_failed_sim_control),
2954157642Sps		error = ENOMEM);
2955179771Sdavidch
2956157642Sps	/* Check for an error and signal the caller that an error occurred. */
2957157642Sps	if (error) {
2958163393Sscottl		*busaddr = 0;
2959189325Sdavidch	} else {
2960189325Sdavidch		*busaddr = segs->ds_addr;
2961157642Sps	}
2962157642Sps
2963163393Sscottl	return;
2964157642Sps}
2965157642Sps
2966157642Sps
2967157642Sps/****************************************************************************/
2968157642Sps/* Allocate any DMA memory needed by the driver.                            */
2969157642Sps/*                                                                          */
2970157642Sps/* Allocates DMA memory needed for the various global structures needed by  */
2971182293Sdavidch/* hardware.                                                                */
2972157642Sps/*                                                                          */
2973182293Sdavidch/* Memory alignment requirements:                                           */
2974182293Sdavidch/* +-----------------+----------+----------+----------+----------+          */
2975182293Sdavidch/* |                 |   5706   |   5708   |   5709   |   5716   |          */
2976182293Sdavidch/* +-----------------+----------+----------+----------+----------+          */
2977182293Sdavidch/* |Status Block     | 8 bytes  | 8 bytes  | 16 bytes | 16 bytes |          */
2978182293Sdavidch/* |Statistics Block | 8 bytes  | 8 bytes  | 16 bytes | 16 bytes |          */
2979182293Sdavidch/* |RX Buffers       | 16 bytes | 16 bytes | 16 bytes | 16 bytes |          */
2980182293Sdavidch/* |PG Buffers       |   none   |   none   |   none   |   none   |          */
2981182293Sdavidch/* |TX Buffers       |   none   |   none   |   none   |   none   |          */
2982182293Sdavidch/* |Chain Pages(1)   |   4KiB   |   4KiB   |   4KiB   |   4KiB   |          */
2983202717Sdavidch/* |Context Memory   |          |          |          |          |          */
2984182293Sdavidch/* +-----------------+----------+----------+----------+----------+          */
2985182293Sdavidch/*                                                                          */
2986182293Sdavidch/* (1) Must align with CPU page size (BCM_PAGE_SZIE).                       */
2987182293Sdavidch/*                                                                          */
2988157642Sps/* Returns:                                                                 */
2989157642Sps/*   0 for success, positive value for failure.                             */
2990157642Sps/****************************************************************************/
2991157642Spsstatic int
2992157642Spsbce_dma_alloc(device_t dev)
2993157642Sps{
2994157642Sps	struct bce_softc *sc;
2995157642Sps	int i, error, rc = 0;
2996170392Sdavidch	bus_size_t max_size, max_seg_size;
2997170392Sdavidch	int max_segments;
2998157642Sps
2999157642Sps	sc = device_get_softc(dev);
3000157642Sps
3001179771Sdavidch	DBENTER(BCE_VERBOSE_RESET | BCE_VERBOSE_CTX);
3002179771Sdavidch
3003157642Sps	/*
3004157642Sps	 * Allocate the parent bus DMA tag appropriate for PCI.
3005157642Sps	 */
3006169632Sdavidch	if (bus_dma_tag_create(NULL,
3007169632Sdavidch			1,
3008169632Sdavidch			BCE_DMA_BOUNDARY,
3009169632Sdavidch			sc->max_bus_addr,
3010169632Sdavidch			BUS_SPACE_MAXADDR,
3011169632Sdavidch			NULL, NULL,
3012169632Sdavidch			MAXBSIZE,
3013169632Sdavidch			BUS_SPACE_UNRESTRICTED,
3014169632Sdavidch			BUS_SPACE_MAXSIZE_32BIT,
3015169632Sdavidch			0,
3016169632Sdavidch			NULL, NULL,
3017157642Sps			&sc->parent_tag)) {
3018169271Sdavidch		BCE_PRINTF("%s(%d): Could not allocate parent DMA tag!\n",
3019157642Sps			__FILE__, __LINE__);
3020157642Sps		rc = ENOMEM;
3021157642Sps		goto bce_dma_alloc_exit;
3022157642Sps	}
3023157642Sps
3024157642Sps	/*
3025157642Sps	 * Create a DMA tag for the status block, allocate and clear the
3026179771Sdavidch	 * memory, map the memory into DMA space, and fetch the physical
3027157642Sps	 * address of the block.
3028157642Sps	 */
3029169632Sdavidch	if (bus_dma_tag_create(sc->parent_tag,
3030169632Sdavidch	    	BCE_DMA_ALIGN,
3031169632Sdavidch	    	BCE_DMA_BOUNDARY,
3032169632Sdavidch	    	sc->max_bus_addr,
3033169632Sdavidch	    	BUS_SPACE_MAXADDR,
3034169632Sdavidch	    	NULL, NULL,
3035169632Sdavidch	    	BCE_STATUS_BLK_SZ,
3036169632Sdavidch	    	1,
3037169632Sdavidch	    	BCE_STATUS_BLK_SZ,
3038169632Sdavidch	    	0,
3039169632Sdavidch	    	NULL, NULL,
3040157642Sps	    	&sc->status_tag)) {
3041169271Sdavidch		BCE_PRINTF("%s(%d): Could not allocate status block DMA tag!\n",
3042157642Sps			__FILE__, __LINE__);
3043157642Sps		rc = ENOMEM;
3044157642Sps		goto bce_dma_alloc_exit;
3045157642Sps	}
3046157642Sps
3047169632Sdavidch	if(bus_dmamem_alloc(sc->status_tag,
3048169632Sdavidch	    	(void **)&sc->status_block,
3049169632Sdavidch	    	BUS_DMA_NOWAIT,
3050157642Sps	    	&sc->status_map)) {
3051169271Sdavidch		BCE_PRINTF("%s(%d): Could not allocate status block DMA memory!\n",
3052157642Sps			__FILE__, __LINE__);
3053157642Sps		rc = ENOMEM;
3054157642Sps		goto bce_dma_alloc_exit;
3055157642Sps	}
3056157642Sps
3057157642Sps	bzero((char *)sc->status_block, BCE_STATUS_BLK_SZ);
3058157642Sps
3059169632Sdavidch	error = bus_dmamap_load(sc->status_tag,
3060169632Sdavidch	    	sc->status_map,
3061169632Sdavidch	    	sc->status_block,
3062169632Sdavidch	    	BCE_STATUS_BLK_SZ,
3063169632Sdavidch	    	bce_dma_map_addr,
3064187204Sdelphij	    	&sc->status_block_paddr,
3065169632Sdavidch	    	BUS_DMA_NOWAIT);
3066179771Sdavidch
3067163393Sscottl	if (error) {
3068169271Sdavidch		BCE_PRINTF("%s(%d): Could not map status block DMA memory!\n",
3069157642Sps			__FILE__, __LINE__);
3070157642Sps		rc = ENOMEM;
3071157642Sps		goto bce_dma_alloc_exit;
3072157642Sps	}
3073157642Sps
3074182293Sdavidch	DBPRINT(sc, BCE_INFO, "%s(): status_block_paddr = 0x%jX\n",
3075182293Sdavidch		__FUNCTION__, (uintmax_t) sc->status_block_paddr);
3076157642Sps
3077157642Sps	/*
3078157642Sps	 * Create a DMA tag for the statistics block, allocate and clear the
3079179771Sdavidch	 * memory, map the memory into DMA space, and fetch the physical
3080157642Sps	 * address of the block.
3081157642Sps	 */
3082169632Sdavidch	if (bus_dma_tag_create(sc->parent_tag,
3083169632Sdavidch	    	BCE_DMA_ALIGN,
3084169632Sdavidch	    	BCE_DMA_BOUNDARY,
3085169632Sdavidch	    	sc->max_bus_addr,
3086169632Sdavidch	    	BUS_SPACE_MAXADDR,
3087169632Sdavidch	    	NULL, NULL,
3088169632Sdavidch	    	BCE_STATS_BLK_SZ,
3089169632Sdavidch	    	1,
3090169632Sdavidch	    	BCE_STATS_BLK_SZ,
3091169632Sdavidch	    	0,
3092169632Sdavidch	    	NULL, NULL,
3093157642Sps	    	&sc->stats_tag)) {
3094169271Sdavidch		BCE_PRINTF("%s(%d): Could not allocate statistics block DMA tag!\n",
3095157642Sps			__FILE__, __LINE__);
3096157642Sps		rc = ENOMEM;
3097157642Sps		goto bce_dma_alloc_exit;
3098157642Sps	}
3099157642Sps
3100169632Sdavidch	if (bus_dmamem_alloc(sc->stats_tag,
3101169632Sdavidch	    	(void **)&sc->stats_block,
3102169632Sdavidch	    	BUS_DMA_NOWAIT,
3103157642Sps	    	&sc->stats_map)) {
3104169271Sdavidch		BCE_PRINTF("%s(%d): Could not allocate statistics block DMA memory!\n",
3105157642Sps			__FILE__, __LINE__);
3106157642Sps		rc = ENOMEM;
3107157642Sps		goto bce_dma_alloc_exit;
3108157642Sps	}
3109157642Sps
3110157642Sps	bzero((char *)sc->stats_block, BCE_STATS_BLK_SZ);
3111157642Sps
3112169632Sdavidch	error = bus_dmamap_load(sc->stats_tag,
3113169632Sdavidch	    	sc->stats_map,
3114169632Sdavidch	    	sc->stats_block,
3115169632Sdavidch	    	BCE_STATS_BLK_SZ,
3116169632Sdavidch	    	bce_dma_map_addr,
3117187204Sdelphij	    	&sc->stats_block_paddr,
3118169632Sdavidch	    	BUS_DMA_NOWAIT);
3119157642Sps
3120163393Sscottl	if(error) {
3121169271Sdavidch		BCE_PRINTF("%s(%d): Could not map statistics block DMA memory!\n",
3122157642Sps			__FILE__, __LINE__);
3123157642Sps		rc = ENOMEM;
3124157642Sps		goto bce_dma_alloc_exit;
3125157642Sps	}
3126157642Sps
3127182293Sdavidch	DBPRINT(sc, BCE_INFO, "%s(): stats_block_paddr = 0x%jX\n",
3128182293Sdavidch		__FUNCTION__, (uintmax_t) sc->stats_block_paddr);
3129157642Sps
3130179771Sdavidch	/* BCM5709 uses host memory as cache for context memory. */
3131182293Sdavidch	if ((BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5709) ||
3132182293Sdavidch		(BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5716)) {
3133179771Sdavidch		sc->ctx_pages = 0x2000 / BCM_PAGE_SIZE;
3134179771Sdavidch		if (sc->ctx_pages == 0)
3135179771Sdavidch			sc->ctx_pages = 1;
3136179771Sdavidch
3137179771Sdavidch		DBRUNIF((sc->ctx_pages > 512),
3138179771Sdavidch			BCE_PRINTF("%s(%d): Too many CTX pages! %d > 512\n",
3139179771Sdavidch				__FILE__, __LINE__, sc->ctx_pages));
3140179771Sdavidch
3141179771Sdavidch		/*
3142179771Sdavidch		 * Create a DMA tag for the context pages,
3143179771Sdavidch		 * allocate and clear the memory, map the
3144179771Sdavidch		 * memory into DMA space, and fetch the
3145179771Sdavidch		 * physical address of the block.
3146179771Sdavidch		 */
3147179771Sdavidch		if(bus_dma_tag_create(sc->parent_tag,
3148179771Sdavidch			BCM_PAGE_SIZE,
3149179771Sdavidch		    BCE_DMA_BOUNDARY,
3150179771Sdavidch			sc->max_bus_addr,
3151179771Sdavidch			BUS_SPACE_MAXADDR,
3152179771Sdavidch			NULL, NULL,
3153179771Sdavidch			BCM_PAGE_SIZE,
3154179771Sdavidch			1,
3155179771Sdavidch			BCM_PAGE_SIZE,
3156179771Sdavidch			0,
3157179771Sdavidch			NULL, NULL,
3158179771Sdavidch			&sc->ctx_tag)) {
3159179771Sdavidch			BCE_PRINTF("%s(%d): Could not allocate CTX DMA tag!\n",
3160179771Sdavidch				__FILE__, __LINE__);
3161179771Sdavidch			rc = ENOMEM;
3162179771Sdavidch			goto bce_dma_alloc_exit;
3163179771Sdavidch		}
3164179771Sdavidch
3165179771Sdavidch		for (i = 0; i < sc->ctx_pages; i++) {
3166179771Sdavidch
3167179771Sdavidch			if(bus_dmamem_alloc(sc->ctx_tag,
3168179771Sdavidch		    		(void **)&sc->ctx_block[i],
3169179771Sdavidch	    		BUS_DMA_NOWAIT,
3170179771Sdavidch		    	&sc->ctx_map[i])) {
3171179771Sdavidch				BCE_PRINTF("%s(%d): Could not allocate CTX "
3172179771Sdavidch					"DMA memory!\n", __FILE__, __LINE__);
3173179771Sdavidch				rc = ENOMEM;
3174179771Sdavidch				goto bce_dma_alloc_exit;
3175179771Sdavidch			}
3176179771Sdavidch
3177179771Sdavidch			bzero((char *)sc->ctx_block[i], BCM_PAGE_SIZE);
3178179771Sdavidch
3179179771Sdavidch			error = bus_dmamap_load(sc->ctx_tag,
3180179771Sdavidch	    		sc->ctx_map[i],
3181179771Sdavidch	    		sc->ctx_block[i],
3182179771Sdavidch		    	BCM_PAGE_SIZE,
3183179771Sdavidch		    	bce_dma_map_addr,
3184187204Sdelphij	    		&sc->ctx_paddr[i],
3185179771Sdavidch	    		BUS_DMA_NOWAIT);
3186179771Sdavidch
3187179771Sdavidch			if (error) {
3188179771Sdavidch				BCE_PRINTF("%s(%d): Could not map CTX DMA memory!\n",
3189179771Sdavidch					__FILE__, __LINE__);
3190179771Sdavidch				rc = ENOMEM;
3191179771Sdavidch				goto bce_dma_alloc_exit;
3192179771Sdavidch			}
3193179771Sdavidch
3194182293Sdavidch			DBPRINT(sc, BCE_INFO, "%s(): ctx_paddr[%d] = 0x%jX\n",
3195182293Sdavidch				__FUNCTION__, i, (uintmax_t) sc->ctx_paddr[i]);
3196179771Sdavidch		}
3197179771Sdavidch	}
3198179771Sdavidch
3199157642Sps	/*
3200157642Sps	 * Create a DMA tag for the TX buffer descriptor chain,
3201157642Sps	 * allocate and clear the  memory, and fetch the
3202157642Sps	 * physical address of the block.
3203157642Sps	 */
3204169632Sdavidch	if(bus_dma_tag_create(sc->parent_tag,
3205169632Sdavidch			BCM_PAGE_SIZE,
3206169632Sdavidch		    BCE_DMA_BOUNDARY,
3207169632Sdavidch			sc->max_bus_addr,
3208179771Sdavidch			BUS_SPACE_MAXADDR,
3209169632Sdavidch			NULL, NULL,
3210169632Sdavidch			BCE_TX_CHAIN_PAGE_SZ,
3211169632Sdavidch			1,
3212169632Sdavidch			BCE_TX_CHAIN_PAGE_SZ,
3213169632Sdavidch			0,
3214169632Sdavidch			NULL, NULL,
3215157642Sps			&sc->tx_bd_chain_tag)) {
3216169271Sdavidch		BCE_PRINTF("%s(%d): Could not allocate TX descriptor chain DMA tag!\n",
3217157642Sps			__FILE__, __LINE__);
3218157642Sps		rc = ENOMEM;
3219157642Sps		goto bce_dma_alloc_exit;
3220157642Sps	}
3221157642Sps
3222157642Sps	for (i = 0; i < TX_PAGES; i++) {
3223157642Sps
3224169632Sdavidch		if(bus_dmamem_alloc(sc->tx_bd_chain_tag,
3225169632Sdavidch	    		(void **)&sc->tx_bd_chain[i],
3226169632Sdavidch	    		BUS_DMA_NOWAIT,
3227157642Sps		    	&sc->tx_bd_chain_map[i])) {
3228169271Sdavidch			BCE_PRINTF("%s(%d): Could not allocate TX descriptor "
3229157642Sps				"chain DMA memory!\n", __FILE__, __LINE__);
3230157642Sps			rc = ENOMEM;
3231157642Sps			goto bce_dma_alloc_exit;
3232157642Sps		}
3233157642Sps
3234169632Sdavidch		error = bus_dmamap_load(sc->tx_bd_chain_tag,
3235169632Sdavidch	    		sc->tx_bd_chain_map[i],
3236169632Sdavidch	    		sc->tx_bd_chain[i],
3237169632Sdavidch		    	BCE_TX_CHAIN_PAGE_SZ,
3238169632Sdavidch		    	bce_dma_map_addr,
3239187204Sdelphij	    		&sc->tx_bd_chain_paddr[i],
3240169632Sdavidch	    		BUS_DMA_NOWAIT);
3241157642Sps
3242163393Sscottl		if (error) {
3243169271Sdavidch			BCE_PRINTF("%s(%d): Could not map TX descriptor chain DMA memory!\n",
3244157642Sps				__FILE__, __LINE__);
3245157642Sps			rc = ENOMEM;
3246157642Sps			goto bce_dma_alloc_exit;
3247157642Sps		}
3248157642Sps
3249182293Sdavidch		DBPRINT(sc, BCE_INFO, "%s(): tx_bd_chain_paddr[%d] = 0x%jX\n",
3250182293Sdavidch			__FUNCTION__, i, (uintmax_t) sc->tx_bd_chain_paddr[i]);
3251157642Sps	}
3252170392Sdavidch
3253170392Sdavidch	/* Check the required size before mapping to conserve resources. */
3254170392Sdavidch	if (bce_tso_enable) {
3255170392Sdavidch		max_size     = BCE_TSO_MAX_SIZE;
3256170392Sdavidch		max_segments = BCE_MAX_SEGMENTS;
3257170392Sdavidch		max_seg_size = BCE_TSO_MAX_SEG_SIZE;
3258170392Sdavidch	} else {
3259170392Sdavidch		max_size     = MCLBYTES * BCE_MAX_SEGMENTS;
3260170392Sdavidch		max_segments = BCE_MAX_SEGMENTS;
3261170392Sdavidch		max_seg_size = MCLBYTES;
3262170392Sdavidch	}
3263179771Sdavidch
3264157642Sps	/* Create a DMA tag for TX mbufs. */
3265169632Sdavidch	if (bus_dma_tag_create(sc->parent_tag,
3266169632Sdavidch			1,
3267169632Sdavidch			BCE_DMA_BOUNDARY,
3268169632Sdavidch			sc->max_bus_addr,
3269169632Sdavidch			BUS_SPACE_MAXADDR,
3270169632Sdavidch			NULL, NULL,
3271169632Sdavidch			max_size,
3272169632Sdavidch			max_segments,
3273170392Sdavidch			max_seg_size,
3274169632Sdavidch			0,
3275169632Sdavidch			NULL, NULL,
3276163287Sscottl			&sc->tx_mbuf_tag)) {
3277169271Sdavidch		BCE_PRINTF("%s(%d): Could not allocate TX mbuf DMA tag!\n",
3278157642Sps			__FILE__, __LINE__);
3279157642Sps		rc = ENOMEM;
3280157642Sps		goto bce_dma_alloc_exit;
3281157642Sps	}
3282157642Sps
3283157642Sps	/* Create DMA maps for the TX mbufs clusters. */
3284157642Sps	for (i = 0; i < TOTAL_TX_BD; i++) {
3285179771Sdavidch		if (bus_dmamap_create(sc->tx_mbuf_tag, BUS_DMA_NOWAIT,
3286157642Sps			&sc->tx_mbuf_map[i])) {
3287169271Sdavidch			BCE_PRINTF("%s(%d): Unable to create TX mbuf DMA map!\n",
3288157642Sps				__FILE__, __LINE__);
3289157642Sps			rc = ENOMEM;
3290157642Sps			goto bce_dma_alloc_exit;
3291157642Sps		}
3292157642Sps	}
3293157642Sps
3294157642Sps	/*
3295157642Sps	 * Create a DMA tag for the RX buffer descriptor chain,
3296176448Sdavidch	 * allocate and clear the memory, and fetch the physical
3297157642Sps	 * address of the blocks.
3298157642Sps	 */
3299169632Sdavidch	if (bus_dma_tag_create(sc->parent_tag,
3300169632Sdavidch			BCM_PAGE_SIZE,
3301169632Sdavidch			BCE_DMA_BOUNDARY,
3302169632Sdavidch			BUS_SPACE_MAXADDR,
3303169632Sdavidch			sc->max_bus_addr,
3304169632Sdavidch			NULL, NULL,
3305169632Sdavidch			BCE_RX_CHAIN_PAGE_SZ,
3306169632Sdavidch			1,
3307169632Sdavidch			BCE_RX_CHAIN_PAGE_SZ,
3308169632Sdavidch			0,
3309169632Sdavidch			NULL, NULL,
3310157642Sps			&sc->rx_bd_chain_tag)) {
3311169271Sdavidch		BCE_PRINTF("%s(%d): Could not allocate RX descriptor chain DMA tag!\n",
3312157642Sps			__FILE__, __LINE__);
3313157642Sps		rc = ENOMEM;
3314157642Sps		goto bce_dma_alloc_exit;
3315157642Sps	}
3316157642Sps
3317157642Sps	for (i = 0; i < RX_PAGES; i++) {
3318157642Sps
3319169632Sdavidch		if (bus_dmamem_alloc(sc->rx_bd_chain_tag,
3320169632Sdavidch	    		(void **)&sc->rx_bd_chain[i],
3321169632Sdavidch	    		BUS_DMA_NOWAIT,
3322157642Sps		    	&sc->rx_bd_chain_map[i])) {
3323169271Sdavidch			BCE_PRINTF("%s(%d): Could not allocate RX descriptor chain "
3324157642Sps				"DMA memory!\n", __FILE__, __LINE__);
3325157642Sps			rc = ENOMEM;
3326157642Sps			goto bce_dma_alloc_exit;
3327157642Sps		}
3328157642Sps
3329157642Sps		bzero((char *)sc->rx_bd_chain[i], BCE_RX_CHAIN_PAGE_SZ);
3330157642Sps
3331169632Sdavidch		error = bus_dmamap_load(sc->rx_bd_chain_tag,
3332169632Sdavidch	    		sc->rx_bd_chain_map[i],
3333169632Sdavidch	    		sc->rx_bd_chain[i],
3334169632Sdavidch		    	BCE_RX_CHAIN_PAGE_SZ,
3335169632Sdavidch		    	bce_dma_map_addr,
3336187204Sdelphij	    		&sc->rx_bd_chain_paddr[i],
3337169632Sdavidch	    		BUS_DMA_NOWAIT);
3338157642Sps
3339163393Sscottl		if (error) {
3340169271Sdavidch			BCE_PRINTF("%s(%d): Could not map RX descriptor chain DMA memory!\n",
3341157642Sps				__FILE__, __LINE__);
3342157642Sps			rc = ENOMEM;
3343157642Sps			goto bce_dma_alloc_exit;
3344157642Sps		}
3345157642Sps
3346182293Sdavidch		DBPRINT(sc, BCE_INFO, "%s(): rx_bd_chain_paddr[%d] = 0x%jX\n",
3347182293Sdavidch			__FUNCTION__, i, (uintmax_t) sc->rx_bd_chain_paddr[i]);
3348157642Sps	}
3349157642Sps
3350157642Sps	/*
3351157642Sps	 * Create a DMA tag for RX mbufs.
3352178132Sdavidch	 */
3353198320Sstas#ifdef BCE_JUMBO_HDRSPLIT
3354182293Sdavidch	max_size = max_seg_size = ((sc->rx_bd_mbuf_alloc_size < MCLBYTES) ?
3355179771Sdavidch		MCLBYTES : sc->rx_bd_mbuf_alloc_size);
3356179771Sdavidch#else
3357179771Sdavidch	max_size = max_seg_size = MJUM9BYTES;
3358179771Sdavidch#endif
3359189325Sdavidch	max_segments = 1;
3360176448Sdavidch
3361189325Sdavidch	DBPRINT(sc, BCE_INFO, "%s(): Creating rx_mbuf_tag (max size = 0x%jX "
3362189325Sdavidch		"max segments = %d, max segment size = 0x%jX)\n", __FUNCTION__,
3363189325Sdavidch		(uintmax_t) max_size, max_segments, (uintmax_t) max_seg_size);
3364189325Sdavidch
3365169632Sdavidch	if (bus_dma_tag_create(sc->parent_tag,
3366169632Sdavidch			1,
3367169632Sdavidch			BCE_DMA_BOUNDARY,
3368169632Sdavidch			sc->max_bus_addr,
3369169632Sdavidch			BUS_SPACE_MAXADDR,
3370169632Sdavidch			NULL, NULL,
3371176448Sdavidch			max_size,
3372189325Sdavidch			max_segments,
3373176448Sdavidch			max_seg_size,
3374169632Sdavidch			0,
3375169632Sdavidch			NULL, NULL,
3376157642Sps	    	&sc->rx_mbuf_tag)) {
3377169271Sdavidch		BCE_PRINTF("%s(%d): Could not allocate RX mbuf DMA tag!\n",
3378157642Sps			__FILE__, __LINE__);
3379157642Sps		rc = ENOMEM;
3380157642Sps		goto bce_dma_alloc_exit;
3381157642Sps	}
3382157642Sps
3383157642Sps	/* Create DMA maps for the RX mbuf clusters. */
3384157642Sps	for (i = 0; i < TOTAL_RX_BD; i++) {
3385157642Sps		if (bus_dmamap_create(sc->rx_mbuf_tag, BUS_DMA_NOWAIT,
3386157642Sps				&sc->rx_mbuf_map[i])) {
3387169271Sdavidch			BCE_PRINTF("%s(%d): Unable to create RX mbuf DMA map!\n",
3388157642Sps				__FILE__, __LINE__);
3389157642Sps			rc = ENOMEM;
3390157642Sps			goto bce_dma_alloc_exit;
3391157642Sps		}
3392157642Sps	}
3393157642Sps
3394198320Sstas#ifdef BCE_JUMBO_HDRSPLIT
3395176448Sdavidch	/*
3396176448Sdavidch	 * Create a DMA tag for the page buffer descriptor chain,
3397176448Sdavidch	 * allocate and clear the memory, and fetch the physical
3398176448Sdavidch	 * address of the blocks.
3399176448Sdavidch	 */
3400176448Sdavidch	if (bus_dma_tag_create(sc->parent_tag,
3401176448Sdavidch			BCM_PAGE_SIZE,
3402176448Sdavidch			BCE_DMA_BOUNDARY,
3403176448Sdavidch			BUS_SPACE_MAXADDR,
3404176448Sdavidch			sc->max_bus_addr,
3405176448Sdavidch			NULL, NULL,
3406176448Sdavidch			BCE_PG_CHAIN_PAGE_SZ,
3407176448Sdavidch			1,
3408176448Sdavidch			BCE_PG_CHAIN_PAGE_SZ,
3409176448Sdavidch			0,
3410176448Sdavidch			NULL, NULL,
3411176448Sdavidch			&sc->pg_bd_chain_tag)) {
3412176448Sdavidch		BCE_PRINTF("%s(%d): Could not allocate page descriptor chain DMA tag!\n",
3413176448Sdavidch			__FILE__, __LINE__);
3414176448Sdavidch		rc = ENOMEM;
3415176448Sdavidch		goto bce_dma_alloc_exit;
3416176448Sdavidch	}
3417176448Sdavidch
3418176448Sdavidch	for (i = 0; i < PG_PAGES; i++) {
3419176448Sdavidch
3420176448Sdavidch		if (bus_dmamem_alloc(sc->pg_bd_chain_tag,
3421176448Sdavidch	    		(void **)&sc->pg_bd_chain[i],
3422176448Sdavidch	    		BUS_DMA_NOWAIT,
3423176448Sdavidch		    	&sc->pg_bd_chain_map[i])) {
3424176448Sdavidch			BCE_PRINTF("%s(%d): Could not allocate page descriptor chain "
3425176448Sdavidch				"DMA memory!\n", __FILE__, __LINE__);
3426176448Sdavidch			rc = ENOMEM;
3427176448Sdavidch			goto bce_dma_alloc_exit;
3428176448Sdavidch		}
3429176448Sdavidch
3430176448Sdavidch		bzero((char *)sc->pg_bd_chain[i], BCE_PG_CHAIN_PAGE_SZ);
3431176448Sdavidch
3432176448Sdavidch		error = bus_dmamap_load(sc->pg_bd_chain_tag,
3433176448Sdavidch	    		sc->pg_bd_chain_map[i],
3434176448Sdavidch	    		sc->pg_bd_chain[i],
3435176448Sdavidch		    	BCE_PG_CHAIN_PAGE_SZ,
3436176448Sdavidch		    	bce_dma_map_addr,
3437187204Sdelphij	    		&sc->pg_bd_chain_paddr[i],
3438176448Sdavidch	    		BUS_DMA_NOWAIT);
3439176448Sdavidch
3440176448Sdavidch		if (error) {
3441176448Sdavidch			BCE_PRINTF("%s(%d): Could not map page descriptor chain DMA memory!\n",
3442176448Sdavidch				__FILE__, __LINE__);
3443176448Sdavidch			rc = ENOMEM;
3444176448Sdavidch			goto bce_dma_alloc_exit;
3445176448Sdavidch		}
3446176448Sdavidch
3447182293Sdavidch		DBPRINT(sc, BCE_INFO, "%s(): pg_bd_chain_paddr[%d] = 0x%jX\n",
3448182293Sdavidch			__FUNCTION__, i, (uintmax_t) sc->pg_bd_chain_paddr[i]);
3449176448Sdavidch	}
3450176448Sdavidch
3451176448Sdavidch	/*
3452176448Sdavidch	 * Create a DMA tag for page mbufs.
3453176448Sdavidch	 */
3454179771Sdavidch	max_size = max_seg_size = ((sc->pg_bd_mbuf_alloc_size < MCLBYTES) ?
3455179695Sdavidch		MCLBYTES : sc->pg_bd_mbuf_alloc_size);
3456176448Sdavidch
3457176448Sdavidch	if (bus_dma_tag_create(sc->parent_tag,
3458176448Sdavidch			1,
3459176448Sdavidch			BCE_DMA_BOUNDARY,
3460176448Sdavidch			sc->max_bus_addr,
3461176448Sdavidch			BUS_SPACE_MAXADDR,
3462176448Sdavidch			NULL, NULL,
3463176448Sdavidch			max_size,
3464176448Sdavidch			1,
3465176448Sdavidch			max_seg_size,
3466176448Sdavidch			0,
3467176448Sdavidch			NULL, NULL,
3468176448Sdavidch	    	&sc->pg_mbuf_tag)) {
3469176448Sdavidch		BCE_PRINTF("%s(%d): Could not allocate page mbuf DMA tag!\n",
3470176448Sdavidch			__FILE__, __LINE__);
3471176448Sdavidch		rc = ENOMEM;
3472176448Sdavidch		goto bce_dma_alloc_exit;
3473176448Sdavidch	}
3474176448Sdavidch
3475176448Sdavidch	/* Create DMA maps for the page mbuf clusters. */
3476176448Sdavidch	for (i = 0; i < TOTAL_PG_BD; i++) {
3477176448Sdavidch		if (bus_dmamap_create(sc->pg_mbuf_tag, BUS_DMA_NOWAIT,
3478176448Sdavidch				&sc->pg_mbuf_map[i])) {
3479176448Sdavidch			BCE_PRINTF("%s(%d): Unable to create page mbuf DMA map!\n",
3480176448Sdavidch				__FILE__, __LINE__);
3481176448Sdavidch			rc = ENOMEM;
3482176448Sdavidch			goto bce_dma_alloc_exit;
3483176448Sdavidch		}
3484176448Sdavidch	}
3485179771Sdavidch#endif
3486176448Sdavidch
3487157642Spsbce_dma_alloc_exit:
3488179771Sdavidch	DBEXIT(BCE_VERBOSE_RESET | BCE_VERBOSE_CTX);
3489157642Sps	return(rc);
3490157642Sps}
3491157642Sps
3492157642Sps
3493157642Sps/****************************************************************************/
3494157642Sps/* Release all resources used by the driver.                                */
3495157642Sps/*                                                                          */
3496157642Sps/* Releases all resources acquired by the driver including interrupts,      */
3497157642Sps/* interrupt handler, interfaces, mutexes, and DMA memory.                  */
3498157642Sps/*                                                                          */
3499157642Sps/* Returns:                                                                 */
3500157642Sps/*   Nothing.                                                               */
3501157642Sps/****************************************************************************/
3502157642Spsstatic void
3503157642Spsbce_release_resources(struct bce_softc *sc)
3504157642Sps{
3505157642Sps	device_t dev;
3506157642Sps
3507179771Sdavidch	DBENTER(BCE_VERBOSE_RESET);
3508157642Sps
3509157642Sps	dev = sc->bce_dev;
3510157642Sps
3511157642Sps	bce_dma_free(sc);
3512170392Sdavidch
3513170392Sdavidch	if (sc->bce_intrhand != NULL) {
3514169632Sdavidch		DBPRINT(sc, BCE_INFO_RESET, "Removing interrupt handler.\n");
3515170392Sdavidch		bus_teardown_intr(dev, sc->bce_res_irq, sc->bce_intrhand);
3516169632Sdavidch	}
3517157642Sps
3518170392Sdavidch	if (sc->bce_res_irq != NULL) {
3519169632Sdavidch		DBPRINT(sc, BCE_INFO_RESET, "Releasing IRQ.\n");
3520179771Sdavidch		bus_release_resource(dev, SYS_RES_IRQ, sc->bce_irq_rid,
3521169632Sdavidch			sc->bce_res_irq);
3522169632Sdavidch	}
3523170392Sdavidch
3524179771Sdavidch	if (sc->bce_flags & (BCE_USING_MSI_FLAG | BCE_USING_MSIX_FLAG)) {
3525179771Sdavidch		DBPRINT(sc, BCE_INFO_RESET, "Releasing MSI/MSI-X vector.\n");
3526170392Sdavidch		pci_release_msi(dev);
3527170392Sdavidch	}
3528157642Sps
3529170392Sdavidch	if (sc->bce_res_mem != NULL) {
3530169632Sdavidch		DBPRINT(sc, BCE_INFO_RESET, "Releasing PCI memory.\n");
3531170392Sdavidch		bus_release_resource(dev, SYS_RES_MEMORY, PCIR_BAR(0), sc->bce_res_mem);
3532169632Sdavidch	}
3533157642Sps
3534170392Sdavidch	if (sc->bce_ifp != NULL) {
3535169632Sdavidch		DBPRINT(sc, BCE_INFO_RESET, "Releasing IF.\n");
3536170392Sdavidch		if_free(sc->bce_ifp);
3537169632Sdavidch	}
3538164305Sjhb
3539157642Sps	if (mtx_initialized(&sc->bce_mtx))
3540157642Sps		BCE_LOCK_DESTROY(sc);
3541157642Sps
3542179771Sdavidch	DBEXIT(BCE_VERBOSE_RESET);
3543157642Sps}
3544157642Sps
3545157642Sps
3546157642Sps/****************************************************************************/
3547157642Sps/* Firmware synchronization.                                                */
3548157642Sps/*                                                                          */
3549157642Sps/* Before performing certain events such as a chip reset, synchronize with  */
3550157642Sps/* the firmware first.                                                      */
3551157642Sps/*                                                                          */
3552157642Sps/* Returns:                                                                 */
3553157642Sps/*   0 for success, positive value for failure.                             */
3554157642Sps/****************************************************************************/
3555157642Spsstatic int
3556157642Spsbce_fw_sync(struct bce_softc *sc, u32 msg_data)
3557157642Sps{
3558157642Sps	int i, rc = 0;
3559157642Sps	u32 val;
3560157642Sps
3561179771Sdavidch	DBENTER(BCE_VERBOSE_RESET);
3562179771Sdavidch
3563157642Sps	/* Don't waste any time if we've timed out before. */
3564157642Sps	if (sc->bce_fw_timed_out) {
3565157642Sps		rc = EBUSY;
3566157642Sps		goto bce_fw_sync_exit;
3567157642Sps	}
3568157642Sps
3569157642Sps	/* Increment the message sequence number. */
3570157642Sps	sc->bce_fw_wr_seq++;
3571157642Sps	msg_data |= sc->bce_fw_wr_seq;
3572157642Sps
3573179771Sdavidch 	DBPRINT(sc, BCE_VERBOSE_FIRMWARE, "bce_fw_sync(): msg_data = 0x%08X\n",
3574179771Sdavidch 		msg_data);
3575157642Sps
3576157642Sps	/* Send the message to the bootcode driver mailbox. */
3577194781Sdavidch	bce_shmem_wr(sc, BCE_DRV_MB, msg_data);
3578157642Sps
3579157642Sps	/* Wait for the bootcode to acknowledge the message. */
3580157642Sps	for (i = 0; i < FW_ACK_TIME_OUT_MS; i++) {
3581157642Sps		/* Check for a response in the bootcode firmware mailbox. */
3582194781Sdavidch		val = bce_shmem_rd(sc, BCE_FW_MB);
3583157642Sps		if ((val & BCE_FW_MSG_ACK) == (msg_data & BCE_DRV_MSG_SEQ))
3584157642Sps			break;
3585157642Sps		DELAY(1000);
3586157642Sps	}
3587157642Sps
3588157642Sps	/* If we've timed out, tell the bootcode that we've stopped waiting. */
3589157642Sps	if (((val & BCE_FW_MSG_ACK) != (msg_data & BCE_DRV_MSG_SEQ)) &&
3590157642Sps		((msg_data & BCE_DRV_MSG_DATA) != BCE_DRV_MSG_DATA_WAIT0)) {
3591157642Sps
3592169271Sdavidch		BCE_PRINTF("%s(%d): Firmware synchronization timeout! "
3593157642Sps			"msg_data = 0x%08X\n",
3594157642Sps			__FILE__, __LINE__, msg_data);
3595157642Sps
3596157642Sps		msg_data &= ~BCE_DRV_MSG_CODE;
3597157642Sps		msg_data |= BCE_DRV_MSG_CODE_FW_TIMEOUT;
3598157642Sps
3599194781Sdavidch		bce_shmem_wr(sc, BCE_DRV_MB, msg_data);
3600157642Sps
3601157642Sps		sc->bce_fw_timed_out = 1;
3602157642Sps		rc = EBUSY;
3603157642Sps	}
3604157642Sps
3605157642Spsbce_fw_sync_exit:
3606179771Sdavidch	DBEXIT(BCE_VERBOSE_RESET);
3607157642Sps	return (rc);
3608157642Sps}
3609157642Sps
3610157642Sps
3611157642Sps/****************************************************************************/
3612157642Sps/* Load Receive Virtual 2 Physical (RV2P) processor firmware.               */
3613157642Sps/*                                                                          */
3614157642Sps/* Returns:                                                                 */
3615157642Sps/*   Nothing.                                                               */
3616157642Sps/****************************************************************************/
3617157642Spsstatic void
3618179771Sdavidchbce_load_rv2p_fw(struct bce_softc *sc, u32 *rv2p_code,
3619157642Sps	u32 rv2p_code_len, u32 rv2p_proc)
3620157642Sps{
3621157642Sps	int i;
3622157642Sps	u32 val;
3623178132Sdavidch
3624179771Sdavidch	DBENTER(BCE_VERBOSE_RESET);
3625179771Sdavidch
3626176448Sdavidch	/* Set the page size used by RV2P. */
3627176448Sdavidch	if (rv2p_proc == RV2P_PROC2) {
3628178132Sdavidch		BCE_RV2P_PROC2_CHG_MAX_BD_PAGE(USABLE_RX_BD_PER_PAGE);
3629176448Sdavidch	}
3630178132Sdavidch
3631157642Sps	for (i = 0; i < rv2p_code_len; i += 8) {
3632157642Sps		REG_WR(sc, BCE_RV2P_INSTR_HIGH, *rv2p_code);
3633157642Sps		rv2p_code++;
3634157642Sps		REG_WR(sc, BCE_RV2P_INSTR_LOW, *rv2p_code);
3635157642Sps		rv2p_code++;
3636157642Sps
3637157642Sps		if (rv2p_proc == RV2P_PROC1) {
3638157642Sps			val = (i / 8) | BCE_RV2P_PROC1_ADDR_CMD_RDWR;
3639157642Sps			REG_WR(sc, BCE_RV2P_PROC1_ADDR_CMD, val);
3640157642Sps		}
3641157642Sps		else {
3642157642Sps			val = (i / 8) | BCE_RV2P_PROC2_ADDR_CMD_RDWR;
3643157642Sps			REG_WR(sc, BCE_RV2P_PROC2_ADDR_CMD, val);
3644157642Sps		}
3645157642Sps	}
3646157642Sps
3647157642Sps	/* Reset the processor, un-stall is done later. */
3648157642Sps	if (rv2p_proc == RV2P_PROC1) {
3649157642Sps		REG_WR(sc, BCE_RV2P_COMMAND, BCE_RV2P_COMMAND_PROC1_RESET);
3650157642Sps	}
3651157642Sps	else {
3652157642Sps		REG_WR(sc, BCE_RV2P_COMMAND, BCE_RV2P_COMMAND_PROC2_RESET);
3653157642Sps	}
3654179771Sdavidch
3655179771Sdavidch	DBEXIT(BCE_VERBOSE_RESET);
3656157642Sps}
3657157642Sps
3658157642Sps
3659157642Sps/****************************************************************************/
3660157642Sps/* Load RISC processor firmware.                                            */
3661157642Sps/*                                                                          */
3662157642Sps/* Loads firmware from the file if_bcefw.h into the scratchpad memory       */
3663157642Sps/* associated with a particular processor.                                  */
3664157642Sps/*                                                                          */
3665157642Sps/* Returns:                                                                 */
3666157642Sps/*   Nothing.                                                               */
3667157642Sps/****************************************************************************/
3668157642Spsstatic void
3669157642Spsbce_load_cpu_fw(struct bce_softc *sc, struct cpu_reg *cpu_reg,
3670157642Sps	struct fw_info *fw)
3671157642Sps{
3672157642Sps	u32 offset;
3673157642Sps
3674179771Sdavidch	DBENTER(BCE_VERBOSE_RESET);
3675179771Sdavidch
3676202717Sdavidch    bce_halt_cpu(sc, cpu_reg);
3677157642Sps
3678157642Sps	/* Load the Text area. */
3679157642Sps	offset = cpu_reg->spad_base + (fw->text_addr - cpu_reg->mips_view_base);
3680157642Sps	if (fw->text) {
3681157642Sps		int j;
3682157642Sps
3683157642Sps		for (j = 0; j < (fw->text_len / 4); j++, offset += 4) {
3684157642Sps			REG_WR_IND(sc, offset, fw->text[j]);
3685157642Sps	        }
3686157642Sps	}
3687157642Sps
3688157642Sps	/* Load the Data area. */
3689157642Sps	offset = cpu_reg->spad_base + (fw->data_addr - cpu_reg->mips_view_base);
3690157642Sps	if (fw->data) {
3691157642Sps		int j;
3692157642Sps
3693157642Sps		for (j = 0; j < (fw->data_len / 4); j++, offset += 4) {
3694157642Sps			REG_WR_IND(sc, offset, fw->data[j]);
3695157642Sps		}
3696157642Sps	}
3697157642Sps
3698157642Sps	/* Load the SBSS area. */
3699157642Sps	offset = cpu_reg->spad_base + (fw->sbss_addr - cpu_reg->mips_view_base);
3700157642Sps	if (fw->sbss) {
3701157642Sps		int j;
3702157642Sps
3703157642Sps		for (j = 0; j < (fw->sbss_len / 4); j++, offset += 4) {
3704157642Sps			REG_WR_IND(sc, offset, fw->sbss[j]);
3705157642Sps		}
3706157642Sps	}
3707157642Sps
3708157642Sps	/* Load the BSS area. */
3709157642Sps	offset = cpu_reg->spad_base + (fw->bss_addr - cpu_reg->mips_view_base);
3710157642Sps	if (fw->bss) {
3711157642Sps		int j;
3712157642Sps
3713157642Sps		for (j = 0; j < (fw->bss_len/4); j++, offset += 4) {
3714157642Sps			REG_WR_IND(sc, offset, fw->bss[j]);
3715157642Sps		}
3716157642Sps	}
3717157642Sps
3718157642Sps	/* Load the Read-Only area. */
3719157642Sps	offset = cpu_reg->spad_base +
3720157642Sps		(fw->rodata_addr - cpu_reg->mips_view_base);
3721157642Sps	if (fw->rodata) {
3722157642Sps		int j;
3723157642Sps
3724157642Sps		for (j = 0; j < (fw->rodata_len / 4); j++, offset += 4) {
3725157642Sps			REG_WR_IND(sc, offset, fw->rodata[j]);
3726157642Sps		}
3727157642Sps	}
3728157642Sps
3729202717Sdavidch    /* Clear the pre-fetch instruction and set the FW start address. */
3730202717Sdavidch    REG_WR_IND(sc, cpu_reg->inst, 0);
3731202717Sdavidch    REG_WR_IND(sc, cpu_reg->pc, fw->start_addr);
3732157642Sps
3733202717Sdavidch	DBEXIT(BCE_VERBOSE_RESET);
3734202717Sdavidch}
3735202717Sdavidch
3736202717Sdavidch
3737202717Sdavidch/****************************************************************************/
3738202717Sdavidch/* Starts the RISC processor.                                               */
3739202717Sdavidch/*                                                                          */
3740202717Sdavidch/* Assumes the CPU starting address has already been set.                   */
3741202717Sdavidch/*                                                                          */
3742202717Sdavidch/* Returns:                                                                 */
3743202717Sdavidch/*   Nothing.                                                               */
3744202717Sdavidch/****************************************************************************/
3745202717Sdavidchstatic void
3746202717Sdavidchbce_start_cpu(struct bce_softc *sc, struct cpu_reg *cpu_reg)
3747202717Sdavidch{
3748202717Sdavidch	u32 val;
3749202717Sdavidch
3750202717Sdavidch	DBENTER(BCE_VERBOSE_RESET);
3751202717Sdavidch
3752157642Sps	/* Start the CPU. */
3753157642Sps	val = REG_RD_IND(sc, cpu_reg->mode);
3754157642Sps	val &= ~cpu_reg->mode_value_halt;
3755157642Sps	REG_WR_IND(sc, cpu_reg->state, cpu_reg->state_value_clear);
3756157642Sps	REG_WR_IND(sc, cpu_reg->mode, val);
3757179771Sdavidch
3758179771Sdavidch	DBEXIT(BCE_VERBOSE_RESET);
3759157642Sps}
3760157642Sps
3761157642Sps
3762157642Sps/****************************************************************************/
3763202717Sdavidch/* Halts the RISC processor.                                                */
3764202717Sdavidch/*                                                                          */
3765202717Sdavidch/* Returns:                                                                 */
3766202717Sdavidch/*   Nothing.                                                               */
3767202717Sdavidch/****************************************************************************/
3768202717Sdavidchstatic void
3769202717Sdavidchbce_halt_cpu(struct bce_softc *sc, struct cpu_reg *cpu_reg)
3770202717Sdavidch{
3771202717Sdavidch	u32 val;
3772202717Sdavidch
3773202717Sdavidch	DBENTER(BCE_VERBOSE_RESET);
3774202717Sdavidch
3775202717Sdavidch    /* Halt the CPU. */
3776202717Sdavidch    val = REG_RD_IND(sc, cpu_reg->mode);
3777202717Sdavidch    val |= cpu_reg->mode_value_halt;
3778202717Sdavidch    REG_WR_IND(sc, cpu_reg->mode, val);
3779202717Sdavidch    REG_WR_IND(sc, cpu_reg->state, cpu_reg->state_value_clear);
3780202717Sdavidch
3781202717Sdavidch	DBEXIT(BCE_VERBOSE_RESET);
3782202717Sdavidch}
3783202717Sdavidch
3784202717Sdavidch
3785202717Sdavidch/****************************************************************************/
3786179771Sdavidch/* Initialize the RX CPU.                                                   */
3787157642Sps/*                                                                          */
3788157642Sps/* Returns:                                                                 */
3789157642Sps/*   Nothing.                                                               */
3790157642Sps/****************************************************************************/
3791157642Spsstatic void
3792202717Sdavidchbce_start_rxp_cpu(struct bce_softc *sc)
3793202717Sdavidch{
3794202717Sdavidch	struct cpu_reg cpu_reg;
3795202717Sdavidch
3796202717Sdavidch	DBENTER(BCE_VERBOSE_RESET);
3797202717Sdavidch
3798202717Sdavidch	cpu_reg.mode = BCE_RXP_CPU_MODE;
3799202717Sdavidch	cpu_reg.mode_value_halt = BCE_RXP_CPU_MODE_SOFT_HALT;
3800202717Sdavidch	cpu_reg.mode_value_sstep = BCE_RXP_CPU_MODE_STEP_ENA;
3801202717Sdavidch	cpu_reg.state = BCE_RXP_CPU_STATE;
3802202717Sdavidch	cpu_reg.state_value_clear = 0xffffff;
3803202717Sdavidch	cpu_reg.gpr0 = BCE_RXP_CPU_REG_FILE;
3804202717Sdavidch	cpu_reg.evmask = BCE_RXP_CPU_EVENT_MASK;
3805202717Sdavidch	cpu_reg.pc = BCE_RXP_CPU_PROGRAM_COUNTER;
3806202717Sdavidch	cpu_reg.inst = BCE_RXP_CPU_INSTRUCTION;
3807202717Sdavidch	cpu_reg.bp = BCE_RXP_CPU_HW_BREAKPOINT;
3808202717Sdavidch	cpu_reg.spad_base = BCE_RXP_SCRATCH;
3809202717Sdavidch	cpu_reg.mips_view_base = 0x8000000;
3810202717Sdavidch
3811202717Sdavidch	DBPRINT(sc, BCE_INFO_RESET, "Starting RX firmware.\n");
3812202717Sdavidch	bce_start_cpu(sc, &cpu_reg);
3813202717Sdavidch
3814202717Sdavidch	DBEXIT(BCE_VERBOSE_RESET);
3815202717Sdavidch}
3816202717Sdavidch
3817202717Sdavidch
3818202717Sdavidch/****************************************************************************/
3819202717Sdavidch/* Initialize the RX CPU.                                                   */
3820202717Sdavidch/*                                                                          */
3821202717Sdavidch/* Returns:                                                                 */
3822202717Sdavidch/*   Nothing.                                                               */
3823202717Sdavidch/****************************************************************************/
3824202717Sdavidchstatic void
3825179771Sdavidchbce_init_rxp_cpu(struct bce_softc *sc)
3826157642Sps{
3827157642Sps	struct cpu_reg cpu_reg;
3828157642Sps	struct fw_info fw;
3829157642Sps
3830179771Sdavidch	DBENTER(BCE_VERBOSE_RESET);
3831157642Sps
3832157642Sps	cpu_reg.mode = BCE_RXP_CPU_MODE;
3833157642Sps	cpu_reg.mode_value_halt = BCE_RXP_CPU_MODE_SOFT_HALT;
3834157642Sps	cpu_reg.mode_value_sstep = BCE_RXP_CPU_MODE_STEP_ENA;
3835157642Sps	cpu_reg.state = BCE_RXP_CPU_STATE;
3836157642Sps	cpu_reg.state_value_clear = 0xffffff;
3837157642Sps	cpu_reg.gpr0 = BCE_RXP_CPU_REG_FILE;
3838157642Sps	cpu_reg.evmask = BCE_RXP_CPU_EVENT_MASK;
3839157642Sps	cpu_reg.pc = BCE_RXP_CPU_PROGRAM_COUNTER;
3840157642Sps	cpu_reg.inst = BCE_RXP_CPU_INSTRUCTION;
3841157642Sps	cpu_reg.bp = BCE_RXP_CPU_HW_BREAKPOINT;
3842157642Sps	cpu_reg.spad_base = BCE_RXP_SCRATCH;
3843157642Sps	cpu_reg.mips_view_base = 0x8000000;
3844157642Sps
3845182293Sdavidch	if ((BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5709) ||
3846182293Sdavidch		(BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5716)) {
3847179771Sdavidch 		fw.ver_major = bce_RXP_b09FwReleaseMajor;
3848179771Sdavidch		fw.ver_minor = bce_RXP_b09FwReleaseMinor;
3849179771Sdavidch		fw.ver_fix = bce_RXP_b09FwReleaseFix;
3850179771Sdavidch		fw.start_addr = bce_RXP_b09FwStartAddr;
3851157642Sps
3852179771Sdavidch		fw.text_addr = bce_RXP_b09FwTextAddr;
3853179771Sdavidch		fw.text_len = bce_RXP_b09FwTextLen;
3854179771Sdavidch		fw.text_index = 0;
3855179771Sdavidch		fw.text = bce_RXP_b09FwText;
3856157642Sps
3857179771Sdavidch		fw.data_addr = bce_RXP_b09FwDataAddr;
3858179771Sdavidch		fw.data_len = bce_RXP_b09FwDataLen;
3859179771Sdavidch		fw.data_index = 0;
3860179771Sdavidch		fw.data = bce_RXP_b09FwData;
3861157642Sps
3862179771Sdavidch		fw.sbss_addr = bce_RXP_b09FwSbssAddr;
3863179771Sdavidch		fw.sbss_len = bce_RXP_b09FwSbssLen;
3864179771Sdavidch		fw.sbss_index = 0;
3865179771Sdavidch		fw.sbss = bce_RXP_b09FwSbss;
3866157642Sps
3867179771Sdavidch		fw.bss_addr = bce_RXP_b09FwBssAddr;
3868179771Sdavidch		fw.bss_len = bce_RXP_b09FwBssLen;
3869179771Sdavidch		fw.bss_index = 0;
3870179771Sdavidch		fw.bss = bce_RXP_b09FwBss;
3871157642Sps
3872179771Sdavidch		fw.rodata_addr = bce_RXP_b09FwRodataAddr;
3873179771Sdavidch		fw.rodata_len = bce_RXP_b09FwRodataLen;
3874179771Sdavidch		fw.rodata_index = 0;
3875179771Sdavidch		fw.rodata = bce_RXP_b09FwRodata;
3876179771Sdavidch	} else {
3877179771Sdavidch		fw.ver_major = bce_RXP_b06FwReleaseMajor;
3878179771Sdavidch		fw.ver_minor = bce_RXP_b06FwReleaseMinor;
3879179771Sdavidch		fw.ver_fix = bce_RXP_b06FwReleaseFix;
3880179771Sdavidch		fw.start_addr = bce_RXP_b06FwStartAddr;
3881157642Sps
3882179771Sdavidch		fw.text_addr = bce_RXP_b06FwTextAddr;
3883179771Sdavidch		fw.text_len = bce_RXP_b06FwTextLen;
3884179771Sdavidch		fw.text_index = 0;
3885179771Sdavidch		fw.text = bce_RXP_b06FwText;
3886179771Sdavidch
3887179771Sdavidch		fw.data_addr = bce_RXP_b06FwDataAddr;
3888179771Sdavidch		fw.data_len = bce_RXP_b06FwDataLen;
3889179771Sdavidch		fw.data_index = 0;
3890179771Sdavidch		fw.data = bce_RXP_b06FwData;
3891179771Sdavidch
3892179771Sdavidch		fw.sbss_addr = bce_RXP_b06FwSbssAddr;
3893179771Sdavidch		fw.sbss_len = bce_RXP_b06FwSbssLen;
3894179771Sdavidch		fw.sbss_index = 0;
3895179771Sdavidch		fw.sbss = bce_RXP_b06FwSbss;
3896179771Sdavidch
3897179771Sdavidch		fw.bss_addr = bce_RXP_b06FwBssAddr;
3898179771Sdavidch		fw.bss_len = bce_RXP_b06FwBssLen;
3899179771Sdavidch		fw.bss_index = 0;
3900179771Sdavidch		fw.bss = bce_RXP_b06FwBss;
3901179771Sdavidch
3902179771Sdavidch		fw.rodata_addr = bce_RXP_b06FwRodataAddr;
3903179771Sdavidch		fw.rodata_len = bce_RXP_b06FwRodataLen;
3904179771Sdavidch		fw.rodata_index = 0;
3905179771Sdavidch		fw.rodata = bce_RXP_b06FwRodata;
3906179771Sdavidch	}
3907179771Sdavidch
3908157642Sps	DBPRINT(sc, BCE_INFO_RESET, "Loading RX firmware.\n");
3909157642Sps	bce_load_cpu_fw(sc, &cpu_reg, &fw);
3910157642Sps
3911202717Sdavidch    /* Delay RXP start until initialization is complete. */
3912202717Sdavidch
3913179771Sdavidch	DBEXIT(BCE_VERBOSE_RESET);
3914179771Sdavidch}
3915179771Sdavidch
3916179771Sdavidch
3917179771Sdavidch/****************************************************************************/
3918179771Sdavidch/* Initialize the TX CPU.                                                   */
3919179771Sdavidch/*                                                                          */
3920179771Sdavidch/* Returns:                                                                 */
3921179771Sdavidch/*   Nothing.                                                               */
3922179771Sdavidch/****************************************************************************/
3923179771Sdavidchstatic void
3924179771Sdavidchbce_init_txp_cpu(struct bce_softc *sc)
3925179771Sdavidch{
3926179771Sdavidch	struct cpu_reg cpu_reg;
3927179771Sdavidch	struct fw_info fw;
3928179771Sdavidch
3929179771Sdavidch	DBENTER(BCE_VERBOSE_RESET);
3930179771Sdavidch
3931157642Sps	cpu_reg.mode = BCE_TXP_CPU_MODE;
3932157642Sps	cpu_reg.mode_value_halt = BCE_TXP_CPU_MODE_SOFT_HALT;
3933157642Sps	cpu_reg.mode_value_sstep = BCE_TXP_CPU_MODE_STEP_ENA;
3934157642Sps	cpu_reg.state = BCE_TXP_CPU_STATE;
3935157642Sps	cpu_reg.state_value_clear = 0xffffff;
3936157642Sps	cpu_reg.gpr0 = BCE_TXP_CPU_REG_FILE;
3937157642Sps	cpu_reg.evmask = BCE_TXP_CPU_EVENT_MASK;
3938157642Sps	cpu_reg.pc = BCE_TXP_CPU_PROGRAM_COUNTER;
3939157642Sps	cpu_reg.inst = BCE_TXP_CPU_INSTRUCTION;
3940157642Sps	cpu_reg.bp = BCE_TXP_CPU_HW_BREAKPOINT;
3941157642Sps	cpu_reg.spad_base = BCE_TXP_SCRATCH;
3942157642Sps	cpu_reg.mips_view_base = 0x8000000;
3943157642Sps
3944182293Sdavidch	if ((BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5709) ||
3945182293Sdavidch		(BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5716)) {
3946179771Sdavidch		fw.ver_major = bce_TXP_b09FwReleaseMajor;
3947179771Sdavidch		fw.ver_minor = bce_TXP_b09FwReleaseMinor;
3948179771Sdavidch		fw.ver_fix = bce_TXP_b09FwReleaseFix;
3949179771Sdavidch		fw.start_addr = bce_TXP_b09FwStartAddr;
3950157642Sps
3951179771Sdavidch		fw.text_addr = bce_TXP_b09FwTextAddr;
3952179771Sdavidch		fw.text_len = bce_TXP_b09FwTextLen;
3953179771Sdavidch		fw.text_index = 0;
3954179771Sdavidch		fw.text = bce_TXP_b09FwText;
3955157642Sps
3956179771Sdavidch		fw.data_addr = bce_TXP_b09FwDataAddr;
3957179771Sdavidch		fw.data_len = bce_TXP_b09FwDataLen;
3958179771Sdavidch		fw.data_index = 0;
3959179771Sdavidch		fw.data = bce_TXP_b09FwData;
3960157642Sps
3961179771Sdavidch		fw.sbss_addr = bce_TXP_b09FwSbssAddr;
3962179771Sdavidch		fw.sbss_len = bce_TXP_b09FwSbssLen;
3963179771Sdavidch		fw.sbss_index = 0;
3964179771Sdavidch		fw.sbss = bce_TXP_b09FwSbss;
3965157642Sps
3966179771Sdavidch		fw.bss_addr = bce_TXP_b09FwBssAddr;
3967179771Sdavidch		fw.bss_len = bce_TXP_b09FwBssLen;
3968179771Sdavidch		fw.bss_index = 0;
3969179771Sdavidch		fw.bss = bce_TXP_b09FwBss;
3970157642Sps
3971179771Sdavidch		fw.rodata_addr = bce_TXP_b09FwRodataAddr;
3972179771Sdavidch		fw.rodata_len = bce_TXP_b09FwRodataLen;
3973179771Sdavidch		fw.rodata_index = 0;
3974179771Sdavidch		fw.rodata = bce_TXP_b09FwRodata;
3975179771Sdavidch	} else {
3976179771Sdavidch		fw.ver_major = bce_TXP_b06FwReleaseMajor;
3977179771Sdavidch		fw.ver_minor = bce_TXP_b06FwReleaseMinor;
3978179771Sdavidch		fw.ver_fix = bce_TXP_b06FwReleaseFix;
3979179771Sdavidch		fw.start_addr = bce_TXP_b06FwStartAddr;
3980157642Sps
3981179771Sdavidch		fw.text_addr = bce_TXP_b06FwTextAddr;
3982179771Sdavidch		fw.text_len = bce_TXP_b06FwTextLen;
3983179771Sdavidch		fw.text_index = 0;
3984179771Sdavidch		fw.text = bce_TXP_b06FwText;
3985179771Sdavidch
3986179771Sdavidch		fw.data_addr = bce_TXP_b06FwDataAddr;
3987179771Sdavidch		fw.data_len = bce_TXP_b06FwDataLen;
3988179771Sdavidch		fw.data_index = 0;
3989179771Sdavidch		fw.data = bce_TXP_b06FwData;
3990179771Sdavidch
3991179771Sdavidch		fw.sbss_addr = bce_TXP_b06FwSbssAddr;
3992179771Sdavidch		fw.sbss_len = bce_TXP_b06FwSbssLen;
3993179771Sdavidch		fw.sbss_index = 0;
3994179771Sdavidch		fw.sbss = bce_TXP_b06FwSbss;
3995179771Sdavidch
3996179771Sdavidch		fw.bss_addr = bce_TXP_b06FwBssAddr;
3997179771Sdavidch		fw.bss_len = bce_TXP_b06FwBssLen;
3998179771Sdavidch		fw.bss_index = 0;
3999179771Sdavidch		fw.bss = bce_TXP_b06FwBss;
4000179771Sdavidch
4001179771Sdavidch		fw.rodata_addr = bce_TXP_b06FwRodataAddr;
4002179771Sdavidch		fw.rodata_len = bce_TXP_b06FwRodataLen;
4003179771Sdavidch		fw.rodata_index = 0;
4004179771Sdavidch		fw.rodata = bce_TXP_b06FwRodata;
4005179771Sdavidch	}
4006179771Sdavidch
4007157642Sps	DBPRINT(sc, BCE_INFO_RESET, "Loading TX firmware.\n");
4008157642Sps	bce_load_cpu_fw(sc, &cpu_reg, &fw);
4009202717Sdavidch    bce_start_cpu(sc, &cpu_reg);
4010157642Sps
4011179771Sdavidch	DBEXIT(BCE_VERBOSE_RESET);
4012179771Sdavidch}
4013179771Sdavidch
4014179771Sdavidch
4015179771Sdavidch/****************************************************************************/
4016179771Sdavidch/* Initialize the TPAT CPU.                                                 */
4017179771Sdavidch/*                                                                          */
4018179771Sdavidch/* Returns:                                                                 */
4019179771Sdavidch/*   Nothing.                                                               */
4020179771Sdavidch/****************************************************************************/
4021179771Sdavidchstatic void
4022179771Sdavidchbce_init_tpat_cpu(struct bce_softc *sc)
4023179771Sdavidch{
4024179771Sdavidch	struct cpu_reg cpu_reg;
4025179771Sdavidch	struct fw_info fw;
4026179771Sdavidch
4027179771Sdavidch	DBENTER(BCE_VERBOSE_RESET);
4028179771Sdavidch
4029157642Sps	cpu_reg.mode = BCE_TPAT_CPU_MODE;
4030157642Sps	cpu_reg.mode_value_halt = BCE_TPAT_CPU_MODE_SOFT_HALT;
4031157642Sps	cpu_reg.mode_value_sstep = BCE_TPAT_CPU_MODE_STEP_ENA;
4032157642Sps	cpu_reg.state = BCE_TPAT_CPU_STATE;
4033157642Sps	cpu_reg.state_value_clear = 0xffffff;
4034157642Sps	cpu_reg.gpr0 = BCE_TPAT_CPU_REG_FILE;
4035157642Sps	cpu_reg.evmask = BCE_TPAT_CPU_EVENT_MASK;
4036157642Sps	cpu_reg.pc = BCE_TPAT_CPU_PROGRAM_COUNTER;
4037157642Sps	cpu_reg.inst = BCE_TPAT_CPU_INSTRUCTION;
4038157642Sps	cpu_reg.bp = BCE_TPAT_CPU_HW_BREAKPOINT;
4039157642Sps	cpu_reg.spad_base = BCE_TPAT_SCRATCH;
4040157642Sps	cpu_reg.mips_view_base = 0x8000000;
4041157642Sps
4042182293Sdavidch	if ((BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5709) ||
4043182293Sdavidch		(BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5716)) {
4044179771Sdavidch		fw.ver_major = bce_TPAT_b09FwReleaseMajor;
4045179771Sdavidch		fw.ver_minor = bce_TPAT_b09FwReleaseMinor;
4046179771Sdavidch		fw.ver_fix = bce_TPAT_b09FwReleaseFix;
4047179771Sdavidch		fw.start_addr = bce_TPAT_b09FwStartAddr;
4048157642Sps
4049179771Sdavidch		fw.text_addr = bce_TPAT_b09FwTextAddr;
4050179771Sdavidch		fw.text_len = bce_TPAT_b09FwTextLen;
4051179771Sdavidch		fw.text_index = 0;
4052179771Sdavidch		fw.text = bce_TPAT_b09FwText;
4053157642Sps
4054179771Sdavidch		fw.data_addr = bce_TPAT_b09FwDataAddr;
4055179771Sdavidch		fw.data_len = bce_TPAT_b09FwDataLen;
4056179771Sdavidch		fw.data_index = 0;
4057179771Sdavidch		fw.data = bce_TPAT_b09FwData;
4058157642Sps
4059179771Sdavidch		fw.sbss_addr = bce_TPAT_b09FwSbssAddr;
4060179771Sdavidch		fw.sbss_len = bce_TPAT_b09FwSbssLen;
4061179771Sdavidch		fw.sbss_index = 0;
4062179771Sdavidch		fw.sbss = bce_TPAT_b09FwSbss;
4063157642Sps
4064179771Sdavidch		fw.bss_addr = bce_TPAT_b09FwBssAddr;
4065179771Sdavidch		fw.bss_len = bce_TPAT_b09FwBssLen;
4066179771Sdavidch		fw.bss_index = 0;
4067179771Sdavidch		fw.bss = bce_TPAT_b09FwBss;
4068157642Sps
4069179771Sdavidch		fw.rodata_addr = bce_TPAT_b09FwRodataAddr;
4070179771Sdavidch		fw.rodata_len = bce_TPAT_b09FwRodataLen;
4071179771Sdavidch		fw.rodata_index = 0;
4072179771Sdavidch		fw.rodata = bce_TPAT_b09FwRodata;
4073179771Sdavidch	} else {
4074179771Sdavidch		fw.ver_major = bce_TPAT_b06FwReleaseMajor;
4075179771Sdavidch		fw.ver_minor = bce_TPAT_b06FwReleaseMinor;
4076179771Sdavidch		fw.ver_fix = bce_TPAT_b06FwReleaseFix;
4077179771Sdavidch		fw.start_addr = bce_TPAT_b06FwStartAddr;
4078157642Sps
4079179771Sdavidch		fw.text_addr = bce_TPAT_b06FwTextAddr;
4080179771Sdavidch		fw.text_len = bce_TPAT_b06FwTextLen;
4081179771Sdavidch		fw.text_index = 0;
4082179771Sdavidch		fw.text = bce_TPAT_b06FwText;
4083157642Sps
4084179771Sdavidch		fw.data_addr = bce_TPAT_b06FwDataAddr;
4085179771Sdavidch		fw.data_len = bce_TPAT_b06FwDataLen;
4086179771Sdavidch		fw.data_index = 0;
4087179771Sdavidch		fw.data = bce_TPAT_b06FwData;
4088157642Sps
4089179771Sdavidch		fw.sbss_addr = bce_TPAT_b06FwSbssAddr;
4090179771Sdavidch		fw.sbss_len = bce_TPAT_b06FwSbssLen;
4091179771Sdavidch		fw.sbss_index = 0;
4092179771Sdavidch		fw.sbss = bce_TPAT_b06FwSbss;
4093157642Sps
4094179771Sdavidch		fw.bss_addr = bce_TPAT_b06FwBssAddr;
4095179771Sdavidch		fw.bss_len = bce_TPAT_b06FwBssLen;
4096179771Sdavidch		fw.bss_index = 0;
4097179771Sdavidch		fw.bss = bce_TPAT_b06FwBss;
4098157642Sps
4099179771Sdavidch		fw.rodata_addr = bce_TPAT_b06FwRodataAddr;
4100179771Sdavidch		fw.rodata_len = bce_TPAT_b06FwRodataLen;
4101179771Sdavidch		fw.rodata_index = 0;
4102179771Sdavidch		fw.rodata = bce_TPAT_b06FwRodata;
4103179771Sdavidch	}
4104157642Sps
4105179771Sdavidch	DBPRINT(sc, BCE_INFO_RESET, "Loading TPAT firmware.\n");
4106179771Sdavidch	bce_load_cpu_fw(sc, &cpu_reg, &fw);
4107202717Sdavidch    bce_start_cpu(sc, &cpu_reg);
4108157642Sps
4109179771Sdavidch	DBEXIT(BCE_VERBOSE_RESET);
4110179771Sdavidch}
4111157642Sps
4112157642Sps
4113179771Sdavidch/****************************************************************************/
4114179771Sdavidch/* Initialize the CP CPU.                                                   */
4115179771Sdavidch/*                                                                          */
4116179771Sdavidch/* Returns:                                                                 */
4117179771Sdavidch/*   Nothing.                                                               */
4118179771Sdavidch/****************************************************************************/
4119179771Sdavidchstatic void
4120179771Sdavidchbce_init_cp_cpu(struct bce_softc *sc)
4121179771Sdavidch{
4122179771Sdavidch	struct cpu_reg cpu_reg;
4123179771Sdavidch	struct fw_info fw;
4124176448Sdavidch
4125179771Sdavidch	DBENTER(BCE_VERBOSE_RESET);
4126179771Sdavidch
4127176448Sdavidch	cpu_reg.mode = BCE_CP_CPU_MODE;
4128176448Sdavidch	cpu_reg.mode_value_halt = BCE_CP_CPU_MODE_SOFT_HALT;
4129176448Sdavidch	cpu_reg.mode_value_sstep = BCE_CP_CPU_MODE_STEP_ENA;
4130176448Sdavidch	cpu_reg.state = BCE_CP_CPU_STATE;
4131176448Sdavidch	cpu_reg.state_value_clear = 0xffffff;
4132176448Sdavidch	cpu_reg.gpr0 = BCE_CP_CPU_REG_FILE;
4133176448Sdavidch	cpu_reg.evmask = BCE_CP_CPU_EVENT_MASK;
4134176448Sdavidch	cpu_reg.pc = BCE_CP_CPU_PROGRAM_COUNTER;
4135176448Sdavidch	cpu_reg.inst = BCE_CP_CPU_INSTRUCTION;
4136176448Sdavidch	cpu_reg.bp = BCE_CP_CPU_HW_BREAKPOINT;
4137176448Sdavidch	cpu_reg.spad_base = BCE_CP_SCRATCH;
4138176448Sdavidch	cpu_reg.mips_view_base = 0x8000000;
4139176448Sdavidch
4140182293Sdavidch	if ((BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5709) ||
4141182293Sdavidch		(BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5716)) {
4142179771Sdavidch		fw.ver_major = bce_CP_b09FwReleaseMajor;
4143179771Sdavidch		fw.ver_minor = bce_CP_b09FwReleaseMinor;
4144179771Sdavidch		fw.ver_fix = bce_CP_b09FwReleaseFix;
4145179771Sdavidch		fw.start_addr = bce_CP_b09FwStartAddr;
4146176448Sdavidch
4147179771Sdavidch		fw.text_addr = bce_CP_b09FwTextAddr;
4148179771Sdavidch		fw.text_len = bce_CP_b09FwTextLen;
4149179771Sdavidch		fw.text_index = 0;
4150179771Sdavidch		fw.text = bce_CP_b09FwText;
4151176448Sdavidch
4152179771Sdavidch		fw.data_addr = bce_CP_b09FwDataAddr;
4153179771Sdavidch		fw.data_len = bce_CP_b09FwDataLen;
4154179771Sdavidch		fw.data_index = 0;
4155179771Sdavidch		fw.data = bce_CP_b09FwData;
4156176448Sdavidch
4157179771Sdavidch		fw.sbss_addr = bce_CP_b09FwSbssAddr;
4158179771Sdavidch		fw.sbss_len = bce_CP_b09FwSbssLen;
4159179771Sdavidch		fw.sbss_index = 0;
4160179771Sdavidch		fw.sbss = bce_CP_b09FwSbss;
4161176448Sdavidch
4162179771Sdavidch		fw.bss_addr = bce_CP_b09FwBssAddr;
4163179771Sdavidch		fw.bss_len = bce_CP_b09FwBssLen;
4164179771Sdavidch		fw.bss_index = 0;
4165179771Sdavidch		fw.bss = bce_CP_b09FwBss;
4166176448Sdavidch
4167179771Sdavidch		fw.rodata_addr = bce_CP_b09FwRodataAddr;
4168179771Sdavidch		fw.rodata_len = bce_CP_b09FwRodataLen;
4169179771Sdavidch		fw.rodata_index = 0;
4170179771Sdavidch		fw.rodata = bce_CP_b09FwRodata;
4171179771Sdavidch	} else {
4172179771Sdavidch		fw.ver_major = bce_CP_b06FwReleaseMajor;
4173179771Sdavidch		fw.ver_minor = bce_CP_b06FwReleaseMinor;
4174179771Sdavidch		fw.ver_fix = bce_CP_b06FwReleaseFix;
4175179771Sdavidch		fw.start_addr = bce_CP_b06FwStartAddr;
4176176448Sdavidch
4177179771Sdavidch		fw.text_addr = bce_CP_b06FwTextAddr;
4178179771Sdavidch		fw.text_len = bce_CP_b06FwTextLen;
4179179771Sdavidch		fw.text_index = 0;
4180179771Sdavidch		fw.text = bce_CP_b06FwText;
4181179771Sdavidch
4182179771Sdavidch		fw.data_addr = bce_CP_b06FwDataAddr;
4183179771Sdavidch		fw.data_len = bce_CP_b06FwDataLen;
4184179771Sdavidch		fw.data_index = 0;
4185179771Sdavidch		fw.data = bce_CP_b06FwData;
4186179771Sdavidch
4187179771Sdavidch		fw.sbss_addr = bce_CP_b06FwSbssAddr;
4188179771Sdavidch		fw.sbss_len = bce_CP_b06FwSbssLen;
4189179771Sdavidch		fw.sbss_index = 0;
4190179771Sdavidch		fw.sbss = bce_CP_b06FwSbss;
4191179771Sdavidch
4192179771Sdavidch		fw.bss_addr = bce_CP_b06FwBssAddr;
4193179771Sdavidch		fw.bss_len = bce_CP_b06FwBssLen;
4194179771Sdavidch		fw.bss_index = 0;
4195179771Sdavidch		fw.bss = bce_CP_b06FwBss;
4196179771Sdavidch
4197179771Sdavidch		fw.rodata_addr = bce_CP_b06FwRodataAddr;
4198179771Sdavidch		fw.rodata_len = bce_CP_b06FwRodataLen;
4199179771Sdavidch		fw.rodata_index = 0;
4200179771Sdavidch		fw.rodata = bce_CP_b06FwRodata;
4201179771Sdavidch	}
4202179771Sdavidch
4203176448Sdavidch	DBPRINT(sc, BCE_INFO_RESET, "Loading CP firmware.\n");
4204176448Sdavidch	bce_load_cpu_fw(sc, &cpu_reg, &fw);
4205202717Sdavidch    bce_start_cpu(sc, &cpu_reg);
4206179771Sdavidch
4207179771Sdavidch	DBEXIT(BCE_VERBOSE_RESET);
4208157642Sps}
4209157642Sps
4210157642Sps
4211157642Sps/****************************************************************************/
4212179771Sdavidch/* Initialize the COM CPU.                                                 */
4213179771Sdavidch/*                                                                          */
4214179771Sdavidch/* Returns:                                                                 */
4215179771Sdavidch/*   Nothing.                                                               */
4216179771Sdavidch/****************************************************************************/
4217179771Sdavidchstatic void
4218179771Sdavidchbce_init_com_cpu(struct bce_softc *sc)
4219179771Sdavidch{
4220179771Sdavidch	struct cpu_reg cpu_reg;
4221179771Sdavidch	struct fw_info fw;
4222179771Sdavidch
4223179771Sdavidch	DBENTER(BCE_VERBOSE_RESET);
4224179771Sdavidch
4225179771Sdavidch	cpu_reg.mode = BCE_COM_CPU_MODE;
4226179771Sdavidch	cpu_reg.mode_value_halt = BCE_COM_CPU_MODE_SOFT_HALT;
4227179771Sdavidch	cpu_reg.mode_value_sstep = BCE_COM_CPU_MODE_STEP_ENA;
4228179771Sdavidch	cpu_reg.state = BCE_COM_CPU_STATE;
4229179771Sdavidch	cpu_reg.state_value_clear = 0xffffff;
4230179771Sdavidch	cpu_reg.gpr0 = BCE_COM_CPU_REG_FILE;
4231179771Sdavidch	cpu_reg.evmask = BCE_COM_CPU_EVENT_MASK;
4232179771Sdavidch	cpu_reg.pc = BCE_COM_CPU_PROGRAM_COUNTER;
4233179771Sdavidch	cpu_reg.inst = BCE_COM_CPU_INSTRUCTION;
4234179771Sdavidch	cpu_reg.bp = BCE_COM_CPU_HW_BREAKPOINT;
4235179771Sdavidch	cpu_reg.spad_base = BCE_COM_SCRATCH;
4236179771Sdavidch	cpu_reg.mips_view_base = 0x8000000;
4237179771Sdavidch
4238182293Sdavidch	if ((BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5709) ||
4239182293Sdavidch		(BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5716)) {
4240179771Sdavidch		fw.ver_major = bce_COM_b09FwReleaseMajor;
4241179771Sdavidch		fw.ver_minor = bce_COM_b09FwReleaseMinor;
4242179771Sdavidch		fw.ver_fix = bce_COM_b09FwReleaseFix;
4243179771Sdavidch		fw.start_addr = bce_COM_b09FwStartAddr;
4244179771Sdavidch
4245179771Sdavidch		fw.text_addr = bce_COM_b09FwTextAddr;
4246179771Sdavidch		fw.text_len = bce_COM_b09FwTextLen;
4247179771Sdavidch		fw.text_index = 0;
4248179771Sdavidch		fw.text = bce_COM_b09FwText;
4249179771Sdavidch
4250179771Sdavidch		fw.data_addr = bce_COM_b09FwDataAddr;
4251179771Sdavidch		fw.data_len = bce_COM_b09FwDataLen;
4252179771Sdavidch		fw.data_index = 0;
4253179771Sdavidch		fw.data = bce_COM_b09FwData;
4254179771Sdavidch
4255179771Sdavidch		fw.sbss_addr = bce_COM_b09FwSbssAddr;
4256179771Sdavidch		fw.sbss_len = bce_COM_b09FwSbssLen;
4257179771Sdavidch		fw.sbss_index = 0;
4258179771Sdavidch		fw.sbss = bce_COM_b09FwSbss;
4259179771Sdavidch
4260179771Sdavidch		fw.bss_addr = bce_COM_b09FwBssAddr;
4261179771Sdavidch		fw.bss_len = bce_COM_b09FwBssLen;
4262179771Sdavidch		fw.bss_index = 0;
4263179771Sdavidch		fw.bss = bce_COM_b09FwBss;
4264179771Sdavidch
4265179771Sdavidch		fw.rodata_addr = bce_COM_b09FwRodataAddr;
4266179771Sdavidch		fw.rodata_len = bce_COM_b09FwRodataLen;
4267179771Sdavidch		fw.rodata_index = 0;
4268179771Sdavidch		fw.rodata = bce_COM_b09FwRodata;
4269179771Sdavidch	} else {
4270179771Sdavidch		fw.ver_major = bce_COM_b06FwReleaseMajor;
4271179771Sdavidch		fw.ver_minor = bce_COM_b06FwReleaseMinor;
4272179771Sdavidch		fw.ver_fix = bce_COM_b06FwReleaseFix;
4273179771Sdavidch		fw.start_addr = bce_COM_b06FwStartAddr;
4274179771Sdavidch
4275179771Sdavidch		fw.text_addr = bce_COM_b06FwTextAddr;
4276179771Sdavidch		fw.text_len = bce_COM_b06FwTextLen;
4277179771Sdavidch		fw.text_index = 0;
4278179771Sdavidch		fw.text = bce_COM_b06FwText;
4279179771Sdavidch
4280179771Sdavidch		fw.data_addr = bce_COM_b06FwDataAddr;
4281179771Sdavidch		fw.data_len = bce_COM_b06FwDataLen;
4282179771Sdavidch		fw.data_index = 0;
4283179771Sdavidch		fw.data = bce_COM_b06FwData;
4284179771Sdavidch
4285179771Sdavidch		fw.sbss_addr = bce_COM_b06FwSbssAddr;
4286179771Sdavidch		fw.sbss_len = bce_COM_b06FwSbssLen;
4287179771Sdavidch		fw.sbss_index = 0;
4288179771Sdavidch		fw.sbss = bce_COM_b06FwSbss;
4289179771Sdavidch
4290179771Sdavidch		fw.bss_addr = bce_COM_b06FwBssAddr;
4291179771Sdavidch		fw.bss_len = bce_COM_b06FwBssLen;
4292179771Sdavidch		fw.bss_index = 0;
4293179771Sdavidch		fw.bss = bce_COM_b06FwBss;
4294179771Sdavidch
4295179771Sdavidch		fw.rodata_addr = bce_COM_b06FwRodataAddr;
4296179771Sdavidch		fw.rodata_len = bce_COM_b06FwRodataLen;
4297179771Sdavidch		fw.rodata_index = 0;
4298179771Sdavidch		fw.rodata = bce_COM_b06FwRodata;
4299179771Sdavidch	}
4300179771Sdavidch
4301179771Sdavidch	DBPRINT(sc, BCE_INFO_RESET, "Loading COM firmware.\n");
4302179771Sdavidch	bce_load_cpu_fw(sc, &cpu_reg, &fw);
4303202717Sdavidch    bce_start_cpu(sc, &cpu_reg);
4304179771Sdavidch
4305179771Sdavidch	DBEXIT(BCE_VERBOSE_RESET);
4306179771Sdavidch}
4307179771Sdavidch
4308179771Sdavidch
4309179771Sdavidch/****************************************************************************/
4310179771Sdavidch/* Initialize the RV2P, RX, TX, TPAT, COM, and CP CPUs.                     */
4311179771Sdavidch/*                                                                          */
4312179771Sdavidch/* Loads the firmware for each CPU and starts the CPU.                      */
4313179771Sdavidch/*                                                                          */
4314179771Sdavidch/* Returns:                                                                 */
4315179771Sdavidch/*   Nothing.                                                               */
4316179771Sdavidch/****************************************************************************/
4317179771Sdavidchstatic void
4318179771Sdavidchbce_init_cpus(struct bce_softc *sc)
4319179771Sdavidch{
4320179771Sdavidch	DBENTER(BCE_VERBOSE_RESET);
4321179771Sdavidch
4322182293Sdavidch	if ((BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5709) ||
4323182293Sdavidch		(BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5716)) {
4324189325Sdavidch
4325189325Sdavidch		if ((BCE_CHIP_REV(sc) == BCE_CHIP_REV_Ax)) {
4326189325Sdavidch			bce_load_rv2p_fw(sc, bce_xi90_rv2p_proc1,
4327189325Sdavidch				sizeof(bce_xi90_rv2p_proc1), RV2P_PROC1);
4328189325Sdavidch			bce_load_rv2p_fw(sc, bce_xi90_rv2p_proc2,
4329189325Sdavidch				sizeof(bce_xi90_rv2p_proc2), RV2P_PROC2);
4330189325Sdavidch		} else {
4331189325Sdavidch			bce_load_rv2p_fw(sc, bce_xi_rv2p_proc1,
4332189325Sdavidch				sizeof(bce_xi_rv2p_proc1), RV2P_PROC1);
4333189325Sdavidch			bce_load_rv2p_fw(sc, bce_xi_rv2p_proc2,
4334189325Sdavidch				sizeof(bce_xi_rv2p_proc2), RV2P_PROC2);
4335189325Sdavidch		}
4336189325Sdavidch
4337179771Sdavidch	} else {
4338189325Sdavidch		bce_load_rv2p_fw(sc, bce_rv2p_proc1,
4339189325Sdavidch			sizeof(bce_rv2p_proc1),	RV2P_PROC1);
4340189325Sdavidch		bce_load_rv2p_fw(sc, bce_rv2p_proc2,
4341189325Sdavidch			sizeof(bce_rv2p_proc2),	RV2P_PROC2);
4342179771Sdavidch	}
4343179771Sdavidch
4344179771Sdavidch	bce_init_rxp_cpu(sc);
4345179771Sdavidch	bce_init_txp_cpu(sc);
4346179771Sdavidch	bce_init_tpat_cpu(sc);
4347179771Sdavidch	bce_init_com_cpu(sc);
4348179771Sdavidch	bce_init_cp_cpu(sc);
4349179771Sdavidch
4350179771Sdavidch	DBEXIT(BCE_VERBOSE_RESET);
4351179771Sdavidch}
4352179771Sdavidch
4353179771Sdavidch
4354179771Sdavidch/****************************************************************************/
4355157642Sps/* Initialize context memory.                                               */
4356157642Sps/*                                                                          */
4357157642Sps/* Clears the memory associated with each Context ID (CID).                 */
4358157642Sps/*                                                                          */
4359157642Sps/* Returns:                                                                 */
4360157642Sps/*   Nothing.                                                               */
4361157642Sps/****************************************************************************/
4362157642Spsstatic void
4363176448Sdavidchbce_init_ctx(struct bce_softc *sc)
4364157642Sps{
4365157642Sps
4366179771Sdavidch	DBENTER(BCE_VERBOSE_RESET | BCE_VERBOSE_CTX);
4367157642Sps
4368182293Sdavidch	if ((BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5709) ||
4369182293Sdavidch		(BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5716)) {
4370191923Sdavidch		int i, retry_cnt = CTX_INIT_RETRY_COUNT;
4371179771Sdavidch		u32 val;
4372157642Sps
4373179771Sdavidch		DBPRINT(sc, BCE_INFO_CTX, "Initializing 5709 context.\n");
4374157642Sps
4375179771Sdavidch		/*
4376179771Sdavidch		 * BCM5709 context memory may be cached
4377179771Sdavidch		 * in host memory so prepare the host memory
4378179771Sdavidch		 * for access.
4379179771Sdavidch		 */
4380179771Sdavidch		val = BCE_CTX_COMMAND_ENABLED | BCE_CTX_COMMAND_MEM_INIT | (1 << 12);
4381179771Sdavidch		val |= (BCM_PAGE_BITS - 8) << 16;
4382179771Sdavidch		REG_WR(sc, BCE_CTX_COMMAND, val);
4383157642Sps
4384179771Sdavidch		/* Wait for mem init command to complete. */
4385179771Sdavidch		for (i = 0; i < retry_cnt; i++) {
4386179771Sdavidch			val = REG_RD(sc, BCE_CTX_COMMAND);
4387179771Sdavidch			if (!(val & BCE_CTX_COMMAND_MEM_INIT))
4388179771Sdavidch				break;
4389179771Sdavidch			DELAY(2);
4390179771Sdavidch		}
4391182293Sdavidch
4392179771Sdavidch		/* ToDo: Consider returning an error here. */
4393179771Sdavidch		DBRUNIF((val & BCE_CTX_COMMAND_MEM_INIT),
4394179771Sdavidch			BCE_PRINTF("%s(): Context memory initialization failed!\n",
4395179771Sdavidch			__FUNCTION__));
4396179771Sdavidch
4397179771Sdavidch		for (i = 0; i < sc->ctx_pages; i++) {
4398179771Sdavidch			int j;
4399179771Sdavidch
4400179771Sdavidch			/* Set the physical address of the context memory cache. */
4401179771Sdavidch			REG_WR(sc, BCE_CTX_HOST_PAGE_TBL_DATA0,
4402182293Sdavidch				BCE_ADDR_LO(sc->ctx_paddr[i] & 0xfffffff0) |
4403179771Sdavidch				BCE_CTX_HOST_PAGE_TBL_DATA0_VALID);
4404179771Sdavidch			REG_WR(sc, BCE_CTX_HOST_PAGE_TBL_DATA1,
4405179771Sdavidch				BCE_ADDR_HI(sc->ctx_paddr[i]));
4406179771Sdavidch			REG_WR(sc, BCE_CTX_HOST_PAGE_TBL_CTRL, i |
4407179771Sdavidch				BCE_CTX_HOST_PAGE_TBL_CTRL_WRITE_REQ);
4408179771Sdavidch
4409179771Sdavidch			/* Verify that the context memory write was successful. */
4410179771Sdavidch			for (j = 0; j < retry_cnt; j++) {
4411179771Sdavidch				val = REG_RD(sc, BCE_CTX_HOST_PAGE_TBL_CTRL);
4412179771Sdavidch				if ((val & BCE_CTX_HOST_PAGE_TBL_CTRL_WRITE_REQ) == 0)
4413179771Sdavidch					break;
4414179771Sdavidch				DELAY(5);
4415179771Sdavidch			}
4416179771Sdavidch
4417179771Sdavidch			/* ToDo: Consider returning an error here. */
4418179771Sdavidch			DBRUNIF((val & BCE_CTX_HOST_PAGE_TBL_CTRL_WRITE_REQ),
4419182293Sdavidch				BCE_PRINTF("%s(): Failed to initialize context page %d!\n",
4420179771Sdavidch				__FUNCTION__, i));
4421179771Sdavidch		}
4422179771Sdavidch	} else {
4423179771Sdavidch		u32 vcid_addr, offset;
4424179771Sdavidch
4425179771Sdavidch		DBPRINT(sc, BCE_INFO, "Initializing 5706/5708 context.\n");
4426179771Sdavidch
4427179771Sdavidch		/*
4428179771Sdavidch		 * For the 5706/5708, context memory is local to
4429179771Sdavidch		 * the controller, so initialize the controller
4430179771Sdavidch		 * context memory.
4431179771Sdavidch		 */
4432179771Sdavidch
4433179771Sdavidch		vcid_addr = GET_CID_ADDR(96);
4434179771Sdavidch		while (vcid_addr) {
4435179771Sdavidch
4436179771Sdavidch			vcid_addr -= PHY_CTX_SIZE;
4437179771Sdavidch
4438179771Sdavidch			REG_WR(sc, BCE_CTX_VIRT_ADDR, 0);
4439179771Sdavidch			REG_WR(sc, BCE_CTX_PAGE_TBL, vcid_addr);
4440179771Sdavidch
4441179771Sdavidch            for(offset = 0; offset < PHY_CTX_SIZE; offset += 4) {
4442179771Sdavidch                CTX_WR(sc, 0x00, offset, 0);
4443179771Sdavidch            }
4444179771Sdavidch
4445176448Sdavidch			REG_WR(sc, BCE_CTX_VIRT_ADDR, vcid_addr);
4446179771Sdavidch			REG_WR(sc, BCE_CTX_PAGE_TBL, vcid_addr);
4447179771Sdavidch		}
4448176448Sdavidch
4449157642Sps	}
4450179771Sdavidch	DBEXIT(BCE_VERBOSE_RESET | BCE_VERBOSE_CTX);
4451157642Sps}
4452157642Sps
4453182293Sdavidch
4454157642Sps/****************************************************************************/
4455157642Sps/* Fetch the permanent MAC address of the controller.                       */
4456157642Sps/*                                                                          */
4457157642Sps/* Returns:                                                                 */
4458157642Sps/*   Nothing.                                                               */
4459157642Sps/****************************************************************************/
4460157642Spsstatic void
4461157642Spsbce_get_mac_addr(struct bce_softc *sc)
4462157642Sps{
4463157642Sps	u32 mac_lo = 0, mac_hi = 0;
4464157642Sps
4465179771Sdavidch	DBENTER(BCE_VERBOSE_RESET);
4466157642Sps	/*
4467157642Sps	 * The NetXtreme II bootcode populates various NIC
4468157642Sps	 * power-on and runtime configuration items in a
4469157642Sps	 * shared memory area.  The factory configured MAC
4470157642Sps	 * address is available from both NVRAM and the
4471157642Sps	 * shared memory area so we'll read the value from
4472157642Sps	 * shared memory for speed.
4473157642Sps	 */
4474157642Sps
4475194781Sdavidch	mac_hi = bce_shmem_rd(sc, BCE_PORT_HW_CFG_MAC_UPPER);
4476194781Sdavidch	mac_lo = bce_shmem_rd(sc, BCE_PORT_HW_CFG_MAC_LOWER);
4477157642Sps
4478157642Sps	if ((mac_lo == 0) && (mac_hi == 0)) {
4479179771Sdavidch		BCE_PRINTF("%s(%d): Invalid Ethernet address!\n",
4480157642Sps			__FILE__, __LINE__);
4481157642Sps	} else {
4482157642Sps		sc->eaddr[0] = (u_char)(mac_hi >> 8);
4483157642Sps		sc->eaddr[1] = (u_char)(mac_hi >> 0);
4484157642Sps		sc->eaddr[2] = (u_char)(mac_lo >> 24);
4485157642Sps		sc->eaddr[3] = (u_char)(mac_lo >> 16);
4486157642Sps		sc->eaddr[4] = (u_char)(mac_lo >> 8);
4487157642Sps		sc->eaddr[5] = (u_char)(mac_lo >> 0);
4488157642Sps	}
4489157642Sps
4490170810Sdavidch	DBPRINT(sc, BCE_INFO_MISC, "Permanent Ethernet address = %6D\n", sc->eaddr, ":");
4491179771Sdavidch	DBEXIT(BCE_VERBOSE_RESET);
4492157642Sps}
4493157642Sps
4494157642Sps
4495157642Sps/****************************************************************************/
4496157642Sps/* Program the MAC address.                                                 */
4497157642Sps/*                                                                          */
4498157642Sps/* Returns:                                                                 */
4499157642Sps/*   Nothing.                                                               */
4500157642Sps/****************************************************************************/
4501157642Spsstatic void
4502157642Spsbce_set_mac_addr(struct bce_softc *sc)
4503157642Sps{
4504157642Sps	u32 val;
4505157642Sps	u8 *mac_addr = sc->eaddr;
4506157642Sps
4507179771Sdavidch	/* ToDo: Add support for setting multiple MAC addresses. */
4508179771Sdavidch
4509179771Sdavidch	DBENTER(BCE_VERBOSE_RESET);
4510170810Sdavidch	DBPRINT(sc, BCE_INFO_MISC, "Setting Ethernet address = %6D\n", sc->eaddr, ":");
4511157642Sps
4512157642Sps	val = (mac_addr[0] << 8) | mac_addr[1];
4513157642Sps
4514157642Sps	REG_WR(sc, BCE_EMAC_MAC_MATCH0, val);
4515157642Sps
4516157642Sps	val = (mac_addr[2] << 24) | (mac_addr[3] << 16) |
4517157642Sps		(mac_addr[4] << 8) | mac_addr[5];
4518157642Sps
4519157642Sps	REG_WR(sc, BCE_EMAC_MAC_MATCH1, val);
4520179771Sdavidch
4521179771Sdavidch	DBEXIT(BCE_VERBOSE_RESET);
4522157642Sps}
4523157642Sps
4524157642Sps
4525157642Sps/****************************************************************************/
4526157642Sps/* Stop the controller.                                                     */
4527157642Sps/*                                                                          */
4528157642Sps/* Returns:                                                                 */
4529157642Sps/*   Nothing.                                                               */
4530157642Sps/****************************************************************************/
4531157642Spsstatic void
4532157642Spsbce_stop(struct bce_softc *sc)
4533157642Sps{
4534157642Sps	struct ifnet *ifp;
4535157642Sps	struct ifmedia_entry *ifm;
4536157642Sps	struct mii_data *mii = NULL;
4537157642Sps	int mtmp, itmp;
4538157642Sps
4539179771Sdavidch	DBENTER(BCE_VERBOSE_RESET);
4540157642Sps
4541157642Sps	BCE_LOCK_ASSERT(sc);
4542157642Sps
4543157642Sps	ifp = sc->bce_ifp;
4544157642Sps
4545157642Sps	mii = device_get_softc(sc->bce_miibus);
4546157642Sps
4547170810Sdavidch	callout_stop(&sc->bce_tick_callout);
4548157642Sps
4549157642Sps	/* Disable the transmit/receive blocks. */
4550179771Sdavidch	REG_WR(sc, BCE_MISC_ENABLE_CLR_BITS, BCE_MISC_ENABLE_CLR_DEFAULT);
4551157642Sps	REG_RD(sc, BCE_MISC_ENABLE_CLR_BITS);
4552157642Sps	DELAY(20);
4553157642Sps
4554157642Sps	bce_disable_intr(sc);
4555157642Sps
4556171667Sdavidch	/* Free RX buffers. */
4557198320Sstas#ifdef BCE_JUMBO_HDRSPLIT
4558179771Sdavidch	bce_free_pg_chain(sc);
4559179695Sdavidch#endif
4560157642Sps	bce_free_rx_chain(sc);
4561157642Sps
4562157642Sps	/* Free TX buffers. */
4563157642Sps	bce_free_tx_chain(sc);
4564157642Sps
4565157642Sps	/*
4566157642Sps	 * Isolate/power down the PHY, but leave the media selection
4567157642Sps	 * unchanged so that things will be put back to normal when
4568157642Sps	 * we bring the interface back up.
4569157642Sps	 */
4570157642Sps
4571157642Sps	itmp = ifp->if_flags;
4572157642Sps	ifp->if_flags |= IFF_UP;
4573170810Sdavidch
4574170810Sdavidch	/* If we are called from bce_detach(), mii is already NULL. */
4575157642Sps	if (mii != NULL) {
4576157642Sps		ifm = mii->mii_media.ifm_cur;
4577157642Sps		mtmp = ifm->ifm_media;
4578157642Sps		ifm->ifm_media = IFM_ETHER | IFM_NONE;
4579157642Sps		mii_mediachg(mii);
4580157642Sps		ifm->ifm_media = mtmp;
4581157642Sps	}
4582157642Sps
4583157642Sps	ifp->if_flags = itmp;
4584165933Sdelphij	sc->watchdog_timer = 0;
4585157642Sps
4586157642Sps	sc->bce_link = 0;
4587157642Sps
4588157642Sps	ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
4589157642Sps
4590179771Sdavidch	DBEXIT(BCE_VERBOSE_RESET);
4591157642Sps}
4592157642Sps
4593157642Sps
4594157642Spsstatic int
4595157642Spsbce_reset(struct bce_softc *sc, u32 reset_code)
4596157642Sps{
4597157642Sps	u32 val;
4598157642Sps	int i, rc = 0;
4599157642Sps
4600179771Sdavidch	DBENTER(BCE_VERBOSE_RESET);
4601179771Sdavidch
4602179771Sdavidch	DBPRINT(sc, BCE_VERBOSE_RESET, "%s(): reset_code = 0x%08X\n",
4603170810Sdavidch		__FUNCTION__, reset_code);
4604157642Sps
4605157642Sps	/* Wait for pending PCI transactions to complete. */
4606157642Sps	REG_WR(sc, BCE_MISC_ENABLE_CLR_BITS,
4607157642Sps	       BCE_MISC_ENABLE_CLR_BITS_TX_DMA_ENABLE |
4608157642Sps	       BCE_MISC_ENABLE_CLR_BITS_DMA_ENGINE_ENABLE |
4609157642Sps	       BCE_MISC_ENABLE_CLR_BITS_RX_DMA_ENABLE |
4610157642Sps	       BCE_MISC_ENABLE_CLR_BITS_HOST_COALESCE_ENABLE);
4611157642Sps	val = REG_RD(sc, BCE_MISC_ENABLE_CLR_BITS);
4612157642Sps	DELAY(5);
4613157642Sps
4614179771Sdavidch	/* Disable DMA */
4615182293Sdavidch	if ((BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5709) ||
4616182293Sdavidch		(BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5716)) {
4617179771Sdavidch		val = REG_RD(sc, BCE_MISC_NEW_CORE_CTL);
4618179771Sdavidch		val &= ~BCE_MISC_NEW_CORE_CTL_DMA_ENABLE;
4619179771Sdavidch		REG_WR(sc, BCE_MISC_NEW_CORE_CTL, val);
4620179771Sdavidch	}
4621179771Sdavidch
4622157642Sps	/* Assume bootcode is running. */
4623157642Sps	sc->bce_fw_timed_out = 0;
4624157642Sps
4625157642Sps	/* Give the firmware a chance to prepare for the reset. */
4626157642Sps	rc = bce_fw_sync(sc, BCE_DRV_MSG_DATA_WAIT0 | reset_code);
4627157642Sps	if (rc)
4628157642Sps		goto bce_reset_exit;
4629157642Sps
4630157642Sps	/* Set a firmware reminder that this is a soft reset. */
4631194781Sdavidch	bce_shmem_wr(sc, BCE_DRV_RESET_SIGNATURE, BCE_DRV_RESET_SIGNATURE_MAGIC);
4632157642Sps
4633157642Sps	/* Dummy read to force the chip to complete all current transactions. */
4634157642Sps	val = REG_RD(sc, BCE_MISC_ID);
4635157642Sps
4636157642Sps	/* Chip reset. */
4637182293Sdavidch	if ((BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5709) ||
4638182293Sdavidch		(BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5716)) {
4639179771Sdavidch		REG_WR(sc, BCE_MISC_COMMAND, BCE_MISC_COMMAND_SW_RESET);
4640179771Sdavidch		REG_RD(sc, BCE_MISC_COMMAND);
4641179771Sdavidch		DELAY(5);
4642157642Sps
4643179771Sdavidch		val = BCE_PCICFG_MISC_CONFIG_REG_WINDOW_ENA |
4644179771Sdavidch		      BCE_PCICFG_MISC_CONFIG_TARGET_MB_WORD_SWAP;
4645179771Sdavidch
4646179771Sdavidch		pci_write_config(sc->bce_dev, BCE_PCICFG_MISC_CONFIG, val, 4);
4647179771Sdavidch	} else {
4648179771Sdavidch		val = BCE_PCICFG_MISC_CONFIG_CORE_RST_REQ |
4649179771Sdavidch			BCE_PCICFG_MISC_CONFIG_REG_WINDOW_ENA |
4650179771Sdavidch			BCE_PCICFG_MISC_CONFIG_TARGET_MB_WORD_SWAP;
4651179771Sdavidch		REG_WR(sc, BCE_PCICFG_MISC_CONFIG, val);
4652179771Sdavidch
4653179771Sdavidch		/* Allow up to 30us for reset to complete. */
4654179771Sdavidch		for (i = 0; i < 10; i++) {
4655179771Sdavidch			val = REG_RD(sc, BCE_PCICFG_MISC_CONFIG);
4656179771Sdavidch			if ((val & (BCE_PCICFG_MISC_CONFIG_CORE_RST_REQ |
4657179771Sdavidch				BCE_PCICFG_MISC_CONFIG_CORE_RST_BSY)) == 0) {
4658179771Sdavidch				break;
4659179771Sdavidch			}
4660179771Sdavidch			DELAY(10);
4661157642Sps		}
4662157642Sps
4663179771Sdavidch		/* Check that reset completed successfully. */
4664179771Sdavidch		if (val & (BCE_PCICFG_MISC_CONFIG_CORE_RST_REQ |
4665179771Sdavidch			BCE_PCICFG_MISC_CONFIG_CORE_RST_BSY)) {
4666179771Sdavidch			BCE_PRINTF("%s(%d): Reset failed!\n",
4667179771Sdavidch				__FILE__, __LINE__);
4668179771Sdavidch			rc = EBUSY;
4669179771Sdavidch			goto bce_reset_exit;
4670179771Sdavidch		}
4671157642Sps	}
4672157642Sps
4673157642Sps	/* Make sure byte swapping is properly configured. */
4674157642Sps	val = REG_RD(sc, BCE_PCI_SWAP_DIAG0);
4675157642Sps	if (val != 0x01020304) {
4676179771Sdavidch		BCE_PRINTF("%s(%d): Byte swap is incorrect!\n",
4677157642Sps			__FILE__, __LINE__);
4678157642Sps		rc = ENODEV;
4679157642Sps		goto bce_reset_exit;
4680157642Sps	}
4681157642Sps
4682157642Sps	/* Just completed a reset, assume that firmware is running again. */
4683157642Sps	sc->bce_fw_timed_out = 0;
4684157642Sps
4685157642Sps	/* Wait for the firmware to finish its initialization. */
4686157642Sps	rc = bce_fw_sync(sc, BCE_DRV_MSG_DATA_WAIT1 | reset_code);
4687157642Sps	if (rc)
4688169271Sdavidch		BCE_PRINTF("%s(%d): Firmware did not complete initialization!\n",
4689157642Sps			__FILE__, __LINE__);
4690157642Sps
4691157642Spsbce_reset_exit:
4692179771Sdavidch	DBEXIT(BCE_VERBOSE_RESET);
4693157642Sps	return (rc);
4694157642Sps}
4695157642Sps
4696157642Sps
4697157642Spsstatic int
4698157642Spsbce_chipinit(struct bce_softc *sc)
4699157642Sps{
4700157642Sps	u32 val;
4701157642Sps	int rc = 0;
4702157642Sps
4703179771Sdavidch	DBENTER(BCE_VERBOSE_RESET);
4704157642Sps
4705179771Sdavidch	bce_disable_intr(sc);
4706157642Sps
4707179771Sdavidch	/*
4708169632Sdavidch	 * Initialize DMA byte/word swapping, configure the number of DMA
4709170392Sdavidch	 * channels and PCI clock compensation delay.
4710169632Sdavidch	 */
4711157642Sps	val = BCE_DMA_CONFIG_DATA_BYTE_SWAP |
4712157642Sps	      BCE_DMA_CONFIG_DATA_WORD_SWAP |
4713157642Sps#if BYTE_ORDER == BIG_ENDIAN
4714157642Sps	      BCE_DMA_CONFIG_CNTL_BYTE_SWAP |
4715157642Sps#endif
4716157642Sps	      BCE_DMA_CONFIG_CNTL_WORD_SWAP |
4717157642Sps	      DMA_READ_CHANS << 12 |
4718157642Sps	      DMA_WRITE_CHANS << 16;
4719157642Sps
4720157642Sps	val |= (0x2 << 20) | BCE_DMA_CONFIG_CNTL_PCI_COMP_DLY;
4721157642Sps
4722157642Sps	if ((sc->bce_flags & BCE_PCIX_FLAG) && (sc->bus_speed_mhz == 133))
4723157642Sps		val |= BCE_DMA_CONFIG_PCI_FAST_CLK_CMP;
4724157642Sps
4725157642Sps	/*
4726157642Sps	 * This setting resolves a problem observed on certain Intel PCI
4727157642Sps	 * chipsets that cannot handle multiple outstanding DMA operations.
4728157642Sps	 * See errata E9_5706A1_65.
4729157642Sps	 */
4730157642Sps	if ((BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5706) &&
4731157642Sps	    (BCE_CHIP_ID(sc) != BCE_CHIP_ID_5706_A0) &&
4732157642Sps	    !(sc->bce_flags & BCE_PCIX_FLAG))
4733157642Sps		val |= BCE_DMA_CONFIG_CNTL_PING_PONG_DMA;
4734157642Sps
4735157642Sps	REG_WR(sc, BCE_DMA_CONFIG, val);
4736157642Sps
4737157642Sps	/* Enable the RX_V2P and Context state machines before access. */
4738157642Sps	REG_WR(sc, BCE_MISC_ENABLE_SET_BITS,
4739157642Sps	       BCE_MISC_ENABLE_SET_BITS_HOST_COALESCE_ENABLE |
4740157642Sps	       BCE_MISC_ENABLE_STATUS_BITS_RX_V2P_ENABLE |
4741157642Sps	       BCE_MISC_ENABLE_STATUS_BITS_CONTEXT_ENABLE);
4742157642Sps
4743157642Sps	/* Initialize context mapping and zero out the quick contexts. */
4744176448Sdavidch	bce_init_ctx(sc);
4745157642Sps
4746157642Sps	/* Initialize the on-boards CPUs */
4747157642Sps	bce_init_cpus(sc);
4748157642Sps
4749202717Sdavidch    /* Enable management frames (NC-SI) to flow to the MCP. */
4750202717Sdavidch    if (sc->bce_flags & BCE_MFW_ENABLE_FLAG) {
4751202717Sdavidch        val = REG_RD(sc, BCE_RPM_MGMT_PKT_CTRL) | BCE_RPM_MGMT_PKT_CTRL_MGMT_EN;
4752202717Sdavidch        REG_WR(sc, BCE_RPM_MGMT_PKT_CTRL, val);
4753202717Sdavidch    }
4754202717Sdavidch
4755157642Sps	/* Prepare NVRAM for access. */
4756157642Sps	if (bce_init_nvram(sc)) {
4757157642Sps		rc = ENODEV;
4758157642Sps		goto bce_chipinit_exit;
4759157642Sps	}
4760157642Sps
4761157642Sps	/* Set the kernel bypass block size */
4762157642Sps	val = REG_RD(sc, BCE_MQ_CONFIG);
4763157642Sps	val &= ~BCE_MQ_CONFIG_KNL_BYP_BLK_SIZE;
4764157642Sps	val |= BCE_MQ_CONFIG_KNL_BYP_BLK_SIZE_256;
4765179771Sdavidch
4766182293Sdavidch	/* Enable bins used on the 5709. */
4767182293Sdavidch	if ((BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5709) ||
4768182293Sdavidch		(BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5716)) {
4769179771Sdavidch		val |= BCE_MQ_CONFIG_BIN_MQ_MODE;
4770179771Sdavidch		if (BCE_CHIP_ID(sc) == BCE_CHIP_ID_5709_A1)
4771179771Sdavidch			val |= BCE_MQ_CONFIG_HALT_DIS;
4772179771Sdavidch	}
4773179771Sdavidch
4774157642Sps	REG_WR(sc, BCE_MQ_CONFIG, val);
4775157642Sps
4776157642Sps	val = 0x10000 + (MAX_CID_CNT * MB_KERNEL_CTX_SIZE);
4777157642Sps	REG_WR(sc, BCE_MQ_KNL_BYP_WIND_START, val);
4778157642Sps	REG_WR(sc, BCE_MQ_KNL_WIND_END, val);
4779170392Sdavidch
4780169271Sdavidch	/* Set the page size and clear the RV2P processor stall bits. */
4781157642Sps	val = (BCM_PAGE_BITS - 8) << 24;
4782157642Sps	REG_WR(sc, BCE_RV2P_CONFIG, val);
4783157642Sps
4784157642Sps	/* Configure page size. */
4785157642Sps	val = REG_RD(sc, BCE_TBDR_CONFIG);
4786157642Sps	val &= ~BCE_TBDR_CONFIG_PAGE_SIZE;
4787157642Sps	val |= (BCM_PAGE_BITS - 8) << 24 | 0x40;
4788157642Sps	REG_WR(sc, BCE_TBDR_CONFIG, val);
4789157642Sps
4790179771Sdavidch	/* Set the perfect match control register to default. */
4791179771Sdavidch	REG_WR_IND(sc, BCE_RXP_PM_CTRL, 0);
4792179771Sdavidch
4793157642Spsbce_chipinit_exit:
4794179771Sdavidch	DBEXIT(BCE_VERBOSE_RESET);
4795157642Sps
4796157642Sps	return(rc);
4797157642Sps}
4798157642Sps
4799157642Sps
4800157642Sps/****************************************************************************/
4801157642Sps/* Initialize the controller in preparation to send/receive traffic.        */
4802157642Sps/*                                                                          */
4803157642Sps/* Returns:                                                                 */
4804157642Sps/*   0 for success, positive value for failure.                             */
4805157642Sps/****************************************************************************/
4806157642Spsstatic int
4807157642Spsbce_blockinit(struct bce_softc *sc)
4808157642Sps{
4809157642Sps	u32 reg, val;
4810157642Sps	int rc = 0;
4811157642Sps
4812179771Sdavidch	DBENTER(BCE_VERBOSE_RESET);
4813157642Sps
4814157642Sps	/* Load the hardware default MAC address. */
4815157642Sps	bce_set_mac_addr(sc);
4816157642Sps
4817157642Sps	/* Set the Ethernet backoff seed value */
4818157642Sps	val = sc->eaddr[0]         + (sc->eaddr[1] << 8) +
4819157642Sps	      (sc->eaddr[2] << 16) + (sc->eaddr[3]     ) +
4820157642Sps	      (sc->eaddr[4] << 8)  + (sc->eaddr[5] << 16);
4821157642Sps	REG_WR(sc, BCE_EMAC_BACKOFF_SEED, val);
4822157642Sps
4823157642Sps	sc->last_status_idx = 0;
4824157642Sps	sc->rx_mode = BCE_EMAC_RX_MODE_SORT_MODE;
4825157642Sps
4826157642Sps	/* Set up link change interrupt generation. */
4827157642Sps	REG_WR(sc, BCE_EMAC_ATTENTION_ENA, BCE_EMAC_ATTENTION_ENA_LINK);
4828157642Sps
4829157642Sps	/* Program the physical address of the status block. */
4830157642Sps	REG_WR(sc, BCE_HC_STATUS_ADDR_L,
4831157642Sps		BCE_ADDR_LO(sc->status_block_paddr));
4832157642Sps	REG_WR(sc, BCE_HC_STATUS_ADDR_H,
4833157642Sps		BCE_ADDR_HI(sc->status_block_paddr));
4834157642Sps
4835157642Sps	/* Program the physical address of the statistics block. */
4836157642Sps	REG_WR(sc, BCE_HC_STATISTICS_ADDR_L,
4837157642Sps		BCE_ADDR_LO(sc->stats_block_paddr));
4838157642Sps	REG_WR(sc, BCE_HC_STATISTICS_ADDR_H,
4839157642Sps		BCE_ADDR_HI(sc->stats_block_paddr));
4840157642Sps
4841157642Sps	/* Program various host coalescing parameters. */
4842157642Sps	REG_WR(sc, BCE_HC_TX_QUICK_CONS_TRIP,
4843157642Sps		(sc->bce_tx_quick_cons_trip_int << 16) | sc->bce_tx_quick_cons_trip);
4844157642Sps	REG_WR(sc, BCE_HC_RX_QUICK_CONS_TRIP,
4845157642Sps		(sc->bce_rx_quick_cons_trip_int << 16) | sc->bce_rx_quick_cons_trip);
4846157642Sps	REG_WR(sc, BCE_HC_COMP_PROD_TRIP,
4847157642Sps		(sc->bce_comp_prod_trip_int << 16) | sc->bce_comp_prod_trip);
4848157642Sps	REG_WR(sc, BCE_HC_TX_TICKS,
4849157642Sps		(sc->bce_tx_ticks_int << 16) | sc->bce_tx_ticks);
4850157642Sps	REG_WR(sc, BCE_HC_RX_TICKS,
4851157642Sps		(sc->bce_rx_ticks_int << 16) | sc->bce_rx_ticks);
4852157642Sps	REG_WR(sc, BCE_HC_COM_TICKS,
4853157642Sps		(sc->bce_com_ticks_int << 16) | sc->bce_com_ticks);
4854157642Sps	REG_WR(sc, BCE_HC_CMD_TICKS,
4855157642Sps		(sc->bce_cmd_ticks_int << 16) | sc->bce_cmd_ticks);
4856157642Sps	REG_WR(sc, BCE_HC_STATS_TICKS,
4857157642Sps		(sc->bce_stats_ticks & 0xffff00));
4858179771Sdavidch	REG_WR(sc, BCE_HC_STAT_COLLECT_TICKS, 0xbb8);  /* 3ms */
4859157642Sps
4860179771Sdavidch	/* Configure the Host Coalescing block. */
4861179771Sdavidch	val = BCE_HC_CONFIG_RX_TMR_MODE | BCE_HC_CONFIG_TX_TMR_MODE |
4862179771Sdavidch		      BCE_HC_CONFIG_COLLECT_STATS;
4863179771Sdavidch
4864179771Sdavidch#if 0
4865179771Sdavidch	/* ToDo: Add MSI-X support. */
4866179771Sdavidch	if (sc->bce_flags & BCE_USING_MSIX_FLAG) {
4867179771Sdavidch		u32 base = ((BCE_TX_VEC - 1) * BCE_HC_SB_CONFIG_SIZE) +
4868179771Sdavidch			   BCE_HC_SB_CONFIG_1;
4869179771Sdavidch
4870179771Sdavidch		REG_WR(sc, BCE_HC_MSIX_BIT_VECTOR, BCE_HC_MSIX_BIT_VECTOR_VAL);
4871179771Sdavidch
4872179771Sdavidch		REG_WR(sc, base, BCE_HC_SB_CONFIG_1_TX_TMR_MODE |
4873179771Sdavidch			BCE_HC_SB_CONFIG_1_ONE_SHOT);
4874179771Sdavidch
4875179771Sdavidch		REG_WR(sc, base + BCE_HC_TX_QUICK_CONS_TRIP_OFF,
4876179771Sdavidch			(sc->tx_quick_cons_trip_int << 16) |
4877179771Sdavidch			 sc->tx_quick_cons_trip);
4878179771Sdavidch
4879179771Sdavidch		REG_WR(sc, base + BCE_HC_TX_TICKS_OFF,
4880179771Sdavidch			(sc->tx_ticks_int << 16) | sc->tx_ticks);
4881179771Sdavidch
4882179771Sdavidch		val |= BCE_HC_CONFIG_SB_ADDR_INC_128B;
4883179771Sdavidch	}
4884179771Sdavidch
4885179771Sdavidch	/*
4886179771Sdavidch	 * Tell the HC block to automatically set the
4887179771Sdavidch	 * INT_MASK bit after an MSI/MSI-X interrupt
4888179771Sdavidch	 * is generated so the driver doesn't have to.
4889179771Sdavidch	 */
4890179771Sdavidch	if (sc->bce_flags & BCE_ONE_SHOT_MSI_FLAG)
4891179771Sdavidch		val |= BCE_HC_CONFIG_ONE_SHOT;
4892179771Sdavidch
4893179771Sdavidch	/* Set the MSI-X status blocks to 128 byte boundaries. */
4894179771Sdavidch	if (sc->bce_flags & BCE_USING_MSIX_FLAG)
4895179771Sdavidch		val |= BCE_HC_CONFIG_SB_ADDR_INC_128B;
4896179771Sdavidch#endif
4897179771Sdavidch
4898179771Sdavidch	REG_WR(sc, BCE_HC_CONFIG, val);
4899179771Sdavidch
4900157642Sps	/* Clear the internal statistics counters. */
4901157642Sps	REG_WR(sc, BCE_HC_COMMAND, BCE_HC_COMMAND_CLR_STAT_NOW);
4902157642Sps
4903157642Sps	/* Verify that bootcode is running. */
4904194781Sdavidch	reg = bce_shmem_rd(sc, BCE_DEV_INFO_SIGNATURE);
4905157642Sps
4906189325Sdavidch	DBRUNIF(DB_RANDOMTRUE(bootcode_running_failure_sim_control),
4907169271Sdavidch		BCE_PRINTF("%s(%d): Simulating bootcode failure.\n",
4908157642Sps			__FILE__, __LINE__);
4909157642Sps		reg = 0);
4910157642Sps
4911157642Sps	if ((reg & BCE_DEV_INFO_SIGNATURE_MAGIC_MASK) !=
4912157642Sps	    BCE_DEV_INFO_SIGNATURE_MAGIC) {
4913169271Sdavidch		BCE_PRINTF("%s(%d): Bootcode not running! Found: 0x%08X, "
4914157642Sps			"Expected: 08%08X\n", __FILE__, __LINE__,
4915157642Sps			(reg & BCE_DEV_INFO_SIGNATURE_MAGIC_MASK),
4916157642Sps			BCE_DEV_INFO_SIGNATURE_MAGIC);
4917157642Sps		rc = ENODEV;
4918157642Sps		goto bce_blockinit_exit;
4919157642Sps	}
4920157642Sps
4921179771Sdavidch	/* Enable DMA */
4922182293Sdavidch	if ((BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5709) ||
4923182293Sdavidch		(BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5716)) {
4924179771Sdavidch		val = REG_RD(sc, BCE_MISC_NEW_CORE_CTL);
4925179771Sdavidch		val |= BCE_MISC_NEW_CORE_CTL_DMA_ENABLE;
4926179771Sdavidch		REG_WR(sc, BCE_MISC_NEW_CORE_CTL, val);
4927179771Sdavidch	}
4928179771Sdavidch
4929157642Sps	/* Allow bootcode to apply any additional fixes before enabling MAC. */
4930157642Sps	rc = bce_fw_sync(sc, BCE_DRV_MSG_DATA_WAIT2 | BCE_DRV_MSG_CODE_RESET);
4931157642Sps
4932157642Sps	/* Enable link state change interrupt generation. */
4933157642Sps	REG_WR(sc, BCE_HC_ATTN_BITS_ENABLE, STATUS_ATTN_BITS_LINK_STATE);
4934157642Sps
4935202717Sdavidch    /* Enable the RXP. */
4936202717Sdavidch    bce_start_rxp_cpu(sc);
4937202717Sdavidch
4938202717Sdavidch    /* Disable management frames (NC-SI) from flowing to the MCP. */
4939202717Sdavidch    if (sc->bce_flags & BCE_MFW_ENABLE_FLAG) {
4940202717Sdavidch        val = REG_RD(sc, BCE_RPM_MGMT_PKT_CTRL) & ~BCE_RPM_MGMT_PKT_CTRL_MGMT_EN;
4941202717Sdavidch        REG_WR(sc, BCE_RPM_MGMT_PKT_CTRL, val);
4942202717Sdavidch    }
4943202717Sdavidch
4944157642Sps	/* Enable all remaining blocks in the MAC. */
4945182293Sdavidch	if ((BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5709)	||
4946182293Sdavidch		(BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5716))
4947182293Sdavidch		REG_WR(sc, BCE_MISC_ENABLE_SET_BITS, BCE_MISC_ENABLE_DEFAULT_XI);
4948182293Sdavidch	else
4949182293Sdavidch		REG_WR(sc, BCE_MISC_ENABLE_SET_BITS, BCE_MISC_ENABLE_DEFAULT);
4950182293Sdavidch
4951157642Sps	REG_RD(sc, BCE_MISC_ENABLE_SET_BITS);
4952157642Sps	DELAY(20);
4953157642Sps
4954179771Sdavidch	/* Save the current host coalescing block settings. */
4955179771Sdavidch	sc->hc_command = REG_RD(sc, BCE_HC_COMMAND);
4956179771Sdavidch
4957157642Spsbce_blockinit_exit:
4958179771Sdavidch	DBEXIT(BCE_VERBOSE_RESET);
4959157642Sps
4960157642Sps	return (rc);
4961157642Sps}
4962157642Sps
4963157642Sps
4964157642Sps/****************************************************************************/
4965176448Sdavidch/* Encapsulate an mbuf into the rx_bd chain.                                */
4966157642Sps/*                                                                          */
4967157642Sps/* Returns:                                                                 */
4968157642Sps/*   0 for success, positive value for failure.                             */
4969157642Sps/****************************************************************************/
4970157642Spsstatic int
4971176448Sdavidchbce_get_rx_buf(struct bce_softc *sc, struct mbuf *m, u16 *prod,
4972176448Sdavidch	u16 *chain_prod, u32 *prod_bseq)
4973157642Sps{
4974171667Sdavidch	bus_dmamap_t map;
4975171667Sdavidch	bus_dma_segment_t segs[BCE_MAX_SEGMENTS];
4976157642Sps	struct mbuf *m_new = NULL;
4977171667Sdavidch	struct rx_bd *rxbd;
4978176448Sdavidch	int nsegs, error, rc = 0;
4979157642Sps#ifdef BCE_DEBUG
4980157642Sps	u16 debug_chain_prod = *chain_prod;
4981157642Sps#endif
4982157642Sps
4983179771Sdavidch	DBENTER(BCE_EXTREME_RESET | BCE_EXTREME_RECV | BCE_EXTREME_LOAD);
4984157642Sps
4985157642Sps	/* Make sure the inputs are valid. */
4986157642Sps	DBRUNIF((*chain_prod > MAX_RX_BD),
4987169271Sdavidch		BCE_PRINTF("%s(%d): RX producer out of range: 0x%04X > 0x%04X\n",
4988157642Sps		__FILE__, __LINE__, *chain_prod, (u16) MAX_RX_BD));
4989157642Sps
4990179771Sdavidch	DBPRINT(sc, BCE_EXTREME_RECV, "%s(enter): prod = 0x%04X, chain_prod = 0x%04X, "
4991157642Sps		"prod_bseq = 0x%08X\n", __FUNCTION__, *prod, *chain_prod, *prod_bseq);
4992157642Sps
4993176448Sdavidch	/* Update some debug statistic counters */
4994179771Sdavidch	DBRUNIF((sc->free_rx_bd < sc->rx_low_watermark),
4995176448Sdavidch		sc->rx_low_watermark = sc->free_rx_bd);
4996176448Sdavidch	DBRUNIF((sc->free_rx_bd == sc->max_rx_bd), sc->rx_empty_count++);
4997176448Sdavidch
4998171667Sdavidch	/* Check whether this is a new mbuf allocation. */
4999157642Sps	if (m == NULL) {
5000157642Sps
5001171667Sdavidch		/* Simulate an mbuf allocation failure. */
5002189325Sdavidch		DBRUNIF(DB_RANDOMTRUE(mbuf_alloc_failed_sim_control),
5003189325Sdavidch			sc->mbuf_alloc_failed_count++;
5004189325Sdavidch			sc->mbuf_alloc_failed_sim_count++;
5005157642Sps			rc = ENOBUFS;
5006176448Sdavidch			goto bce_get_rx_buf_exit);
5007157642Sps
5008157642Sps		/* This is a new mbuf allocation. */
5009198320Sstas#ifdef BCE_JUMBO_HDRSPLIT
5010157642Sps		MGETHDR(m_new, M_DONTWAIT, MT_DATA);
5011178853Sscottl#else
5012179771Sdavidch		if (sc->rx_bd_mbuf_alloc_size <= MCLBYTES)
5013179771Sdavidch			m_new = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
5014179771Sdavidch		else
5015179695Sdavidch			m_new = m_getjcl(M_DONTWAIT, MT_DATA, M_PKTHDR, sc->rx_bd_mbuf_alloc_size);
5016178853Sscottl#endif
5017179771Sdavidch
5018157642Sps		if (m_new == NULL) {
5019189325Sdavidch			sc->mbuf_alloc_failed_count++;
5020157642Sps			rc = ENOBUFS;
5021176448Sdavidch			goto bce_get_rx_buf_exit;
5022157642Sps		}
5023157642Sps
5024176448Sdavidch		DBRUN(sc->debug_rx_mbuf_alloc++);
5025157642Sps	} else {
5026171667Sdavidch		/* Reuse an existing mbuf. */
5027157642Sps		m_new = m;
5028157642Sps	}
5029157642Sps
5030179771Sdavidch	/* Make sure we have a valid packet header. */
5031176448Sdavidch	M_ASSERTPKTHDR(m_new);
5032176448Sdavidch
5033179771Sdavidch	/* Initialize the mbuf size and pad if necessary for alignment. */
5034179771Sdavidch	m_new->m_pkthdr.len = m_new->m_len = sc->rx_bd_mbuf_alloc_size;
5035179695Sdavidch	m_adj(m_new, sc->rx_bd_mbuf_align_pad);
5036176448Sdavidch
5037176448Sdavidch	/* ToDo: Consider calling m_fragment() to test error handling. */
5038176448Sdavidch
5039157642Sps	/* Map the mbuf cluster into device memory. */
5040157642Sps	map = sc->rx_mbuf_map[*chain_prod];
5041157642Sps	error = bus_dmamap_load_mbuf_sg(sc->rx_mbuf_tag, map, m_new,
5042157642Sps	    segs, &nsegs, BUS_DMA_NOWAIT);
5043157642Sps
5044171667Sdavidch	/* Handle any mapping errors. */
5045157642Sps	if (error) {
5046179695Sdavidch		BCE_PRINTF("%s(%d): Error mapping mbuf into RX chain (%d)!\n",
5047179695Sdavidch			__FILE__, __LINE__, error);
5048157642Sps
5049189325Sdavidch		sc->dma_map_addr_rx_failed_count++;
5050157642Sps		m_freem(m_new);
5051189325Sdavidch
5052176448Sdavidch		DBRUN(sc->debug_rx_mbuf_alloc--);
5053157642Sps
5054157642Sps		rc = ENOBUFS;
5055176448Sdavidch		goto bce_get_rx_buf_exit;
5056157642Sps	}
5057179771Sdavidch
5058176448Sdavidch	/* All mbufs must map to a single segment. */
5059176448Sdavidch	KASSERT(nsegs == 1, ("%s(): Too many segments returned (%d)!",
5060176448Sdavidch		 __FUNCTION__, nsegs));
5061157642Sps
5062192281Sdelphij	/* ToDo: Do we need bus_dmamap_sync(,,BUS_DMASYNC_PREREAD) here? */
5063170392Sdavidch
5064176448Sdavidch	/* Setup the rx_bd for the segment. */
5065157642Sps	rxbd = &sc->rx_bd_chain[RX_PAGE(*chain_prod)][RX_IDX(*chain_prod)];
5066157642Sps
5067157642Sps	rxbd->rx_bd_haddr_lo  = htole32(BCE_ADDR_LO(segs[0].ds_addr));
5068157642Sps	rxbd->rx_bd_haddr_hi  = htole32(BCE_ADDR_HI(segs[0].ds_addr));
5069157642Sps	rxbd->rx_bd_len       = htole32(segs[0].ds_len);
5070176448Sdavidch	rxbd->rx_bd_flags     = htole32(RX_BD_FLAGS_START | RX_BD_FLAGS_END);
5071179771Sdavidch	*prod_bseq += segs[0].ds_len;
5072157642Sps
5073176448Sdavidch	/* Save the mbuf and update our counter. */
5074176448Sdavidch	sc->rx_mbuf_ptr[*chain_prod] = m_new;
5075176448Sdavidch	sc->free_rx_bd -= nsegs;
5076182293Sdavidch
5077179771Sdavidch	DBRUNMSG(BCE_INSANE_RECV, bce_dump_rx_mbuf_chain(sc, debug_chain_prod,
5078176448Sdavidch		nsegs));
5079157642Sps
5080179771Sdavidch	DBPRINT(sc, BCE_EXTREME_RECV, "%s(exit): prod = 0x%04X, chain_prod = 0x%04X, "
5081176448Sdavidch		"prod_bseq = 0x%08X\n", __FUNCTION__, *prod, *chain_prod, *prod_bseq);
5082157642Sps
5083176448Sdavidchbce_get_rx_buf_exit:
5084179771Sdavidch	DBEXIT(BCE_EXTREME_RESET | BCE_EXTREME_RECV | BCE_EXTREME_LOAD);
5085176448Sdavidch
5086176448Sdavidch	return(rc);
5087176448Sdavidch}
5088176448Sdavidch
5089176448Sdavidch
5090198320Sstas#ifdef BCE_JUMBO_HDRSPLIT
5091176448Sdavidch/****************************************************************************/
5092176448Sdavidch/* Encapsulate an mbuf cluster into the page chain.                        */
5093176448Sdavidch/*                                                                          */
5094176448Sdavidch/* Returns:                                                                 */
5095176448Sdavidch/*   0 for success, positive value for failure.                             */
5096176448Sdavidch/****************************************************************************/
5097176448Sdavidchstatic int
5098176448Sdavidchbce_get_pg_buf(struct bce_softc *sc, struct mbuf *m, u16 *prod,
5099176448Sdavidch	u16 *prod_idx)
5100176448Sdavidch{
5101176448Sdavidch	bus_dmamap_t map;
5102176448Sdavidch	bus_addr_t busaddr;
5103176448Sdavidch	struct mbuf *m_new = NULL;
5104176448Sdavidch	struct rx_bd *pgbd;
5105176448Sdavidch	int error, rc = 0;
5106176448Sdavidch#ifdef BCE_DEBUG
5107176448Sdavidch	u16 debug_prod_idx = *prod_idx;
5108176448Sdavidch#endif
5109176448Sdavidch
5110179771Sdavidch	DBENTER(BCE_EXTREME_RESET | BCE_EXTREME_RECV | BCE_EXTREME_LOAD);
5111176448Sdavidch
5112176448Sdavidch	/* Make sure the inputs are valid. */
5113176448Sdavidch	DBRUNIF((*prod_idx > MAX_PG_BD),
5114176448Sdavidch		BCE_PRINTF("%s(%d): page producer out of range: 0x%04X > 0x%04X\n",
5115176448Sdavidch		__FILE__, __LINE__, *prod_idx, (u16) MAX_PG_BD));
5116176448Sdavidch
5117179771Sdavidch	DBPRINT(sc, BCE_EXTREME_RECV, "%s(enter): prod = 0x%04X, "
5118176448Sdavidch		"chain_prod = 0x%04X\n", __FUNCTION__, *prod, *prod_idx);
5119176448Sdavidch
5120176448Sdavidch	/* Update counters if we've hit a new low or run out of pages. */
5121179771Sdavidch	DBRUNIF((sc->free_pg_bd < sc->pg_low_watermark),
5122176448Sdavidch		sc->pg_low_watermark = sc->free_pg_bd);
5123176448Sdavidch	DBRUNIF((sc->free_pg_bd == sc->max_pg_bd), sc->pg_empty_count++);
5124176448Sdavidch
5125176448Sdavidch	/* Check whether this is a new mbuf allocation. */
5126176448Sdavidch	if (m == NULL) {
5127176448Sdavidch
5128176448Sdavidch		/* Simulate an mbuf allocation failure. */
5129189325Sdavidch		DBRUNIF(DB_RANDOMTRUE(mbuf_alloc_failed_sim_control),
5130189325Sdavidch			sc->mbuf_alloc_failed_count++;
5131189325Sdavidch			sc->mbuf_alloc_failed_sim_count++;
5132176448Sdavidch			rc = ENOBUFS;
5133176448Sdavidch			goto bce_get_pg_buf_exit);
5134176448Sdavidch
5135176448Sdavidch		/* This is a new mbuf allocation. */
5136176448Sdavidch		m_new = m_getcl(M_DONTWAIT, MT_DATA, 0);
5137176448Sdavidch		if (m_new == NULL) {
5138189325Sdavidch			sc->mbuf_alloc_failed_count++;
5139176448Sdavidch			rc = ENOBUFS;
5140176448Sdavidch			goto bce_get_pg_buf_exit;
5141176448Sdavidch		}
5142176448Sdavidch
5143176448Sdavidch		DBRUN(sc->debug_pg_mbuf_alloc++);
5144176448Sdavidch	} else {
5145176448Sdavidch		/* Reuse an existing mbuf. */
5146176448Sdavidch		m_new = m;
5147176448Sdavidch		m_new->m_data = m_new->m_ext.ext_buf;
5148157642Sps	}
5149157642Sps
5150176448Sdavidch	m_new->m_len = sc->pg_bd_mbuf_alloc_size;
5151157642Sps
5152176448Sdavidch	/* ToDo: Consider calling m_fragment() to test error handling. */
5153176448Sdavidch
5154176448Sdavidch	/* Map the mbuf cluster into device memory. */
5155176448Sdavidch	map = sc->pg_mbuf_map[*prod_idx];
5156176448Sdavidch	error = bus_dmamap_load(sc->pg_mbuf_tag, map, mtod(m_new, void *),
5157176448Sdavidch	    sc->pg_bd_mbuf_alloc_size, bce_dma_map_addr, &busaddr, BUS_DMA_NOWAIT);
5158176448Sdavidch
5159176448Sdavidch	/* Handle any mapping errors. */
5160176448Sdavidch	if (error) {
5161176448Sdavidch		BCE_PRINTF("%s(%d): Error mapping mbuf into page chain!\n",
5162176448Sdavidch			__FILE__, __LINE__);
5163176448Sdavidch
5164176448Sdavidch		m_freem(m_new);
5165176448Sdavidch		DBRUN(sc->debug_pg_mbuf_alloc--);
5166176448Sdavidch
5167176448Sdavidch		rc = ENOBUFS;
5168176448Sdavidch		goto bce_get_pg_buf_exit;
5169176448Sdavidch	}
5170176448Sdavidch
5171192281Sdelphij	/* ToDo: Do we need bus_dmamap_sync(,,BUS_DMASYNC_PREREAD) here? */
5172176448Sdavidch
5173179771Sdavidch	/*
5174176448Sdavidch	 * The page chain uses the same rx_bd data structure
5175176448Sdavidch	 * as the receive chain but doesn't require a byte sequence (bseq).
5176176448Sdavidch	 */
5177176448Sdavidch	pgbd = &sc->pg_bd_chain[PG_PAGE(*prod_idx)][PG_IDX(*prod_idx)];
5178176448Sdavidch
5179176448Sdavidch	pgbd->rx_bd_haddr_lo  = htole32(BCE_ADDR_LO(busaddr));
5180176448Sdavidch	pgbd->rx_bd_haddr_hi  = htole32(BCE_ADDR_HI(busaddr));
5181176448Sdavidch	pgbd->rx_bd_len       = htole32(sc->pg_bd_mbuf_alloc_size);
5182176448Sdavidch	pgbd->rx_bd_flags     = htole32(RX_BD_FLAGS_START | RX_BD_FLAGS_END);
5183176448Sdavidch
5184157642Sps	/* Save the mbuf and update our counter. */
5185176448Sdavidch	sc->pg_mbuf_ptr[*prod_idx] = m_new;
5186176448Sdavidch	sc->free_pg_bd--;
5187157642Sps
5188179771Sdavidch	DBRUNMSG(BCE_INSANE_RECV, bce_dump_pg_mbuf_chain(sc, debug_prod_idx,
5189176448Sdavidch		1));
5190157642Sps
5191179771Sdavidch	DBPRINT(sc, BCE_EXTREME_RECV, "%s(exit): prod = 0x%04X, "
5192176448Sdavidch		"prod_idx = 0x%04X\n", __FUNCTION__, *prod, *prod_idx);
5193157642Sps
5194176448Sdavidchbce_get_pg_buf_exit:
5195179771Sdavidch	DBEXIT(BCE_EXTREME_RESET | BCE_EXTREME_RECV | BCE_EXTREME_LOAD);
5196157642Sps
5197157642Sps	return(rc);
5198157642Sps}
5199198320Sstas#endif /* BCE_JUMBO_HDRSPLIT */
5200157642Sps
5201179771Sdavidch/****************************************************************************/
5202179771Sdavidch/* Initialize the TX context memory.                                        */
5203179771Sdavidch/*                                                                          */
5204179771Sdavidch/* Returns:                                                                 */
5205179771Sdavidch/*   Nothing                                                                */
5206179771Sdavidch/****************************************************************************/
5207179771Sdavidchstatic void
5208179771Sdavidchbce_init_tx_context(struct bce_softc *sc)
5209179771Sdavidch{
5210179771Sdavidch	u32 val;
5211157642Sps
5212179771Sdavidch	DBENTER(BCE_VERBOSE_RESET | BCE_VERBOSE_SEND | BCE_VERBOSE_CTX);
5213179771Sdavidch
5214179771Sdavidch	/* Initialize the context ID for an L2 TX chain. */
5215182293Sdavidch	if ((BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5709) ||
5216182293Sdavidch		(BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5716)) {
5217179771Sdavidch		/* Set the CID type to support an L2 connection. */
5218182293Sdavidch		val = BCE_L2CTX_TX_TYPE_TYPE_L2_XI | BCE_L2CTX_TX_TYPE_SIZE_L2_XI;
5219182293Sdavidch		CTX_WR(sc, GET_CID_ADDR(TX_CID), BCE_L2CTX_TX_TYPE_XI, val);
5220182293Sdavidch		val = BCE_L2CTX_TX_CMD_TYPE_TYPE_L2_XI | (8 << 16);
5221182293Sdavidch		CTX_WR(sc, GET_CID_ADDR(TX_CID), BCE_L2CTX_TX_CMD_TYPE_XI, val);
5222179771Sdavidch
5223179771Sdavidch		/* Point the hardware to the first page in the chain. */
5224179771Sdavidch		val = BCE_ADDR_HI(sc->tx_bd_chain_paddr[0]);
5225182293Sdavidch		CTX_WR(sc, GET_CID_ADDR(TX_CID), BCE_L2CTX_TX_TBDR_BHADDR_HI_XI, val);
5226179771Sdavidch		val = BCE_ADDR_LO(sc->tx_bd_chain_paddr[0]);
5227182293Sdavidch		CTX_WR(sc, GET_CID_ADDR(TX_CID), BCE_L2CTX_TX_TBDR_BHADDR_LO_XI, val);
5228179771Sdavidch	} else {
5229179771Sdavidch		/* Set the CID type to support an L2 connection. */
5230182293Sdavidch		val = BCE_L2CTX_TX_TYPE_TYPE_L2 | BCE_L2CTX_TX_TYPE_SIZE_L2;
5231182293Sdavidch		CTX_WR(sc, GET_CID_ADDR(TX_CID), BCE_L2CTX_TX_TYPE, val);
5232182293Sdavidch		val = BCE_L2CTX_TX_CMD_TYPE_TYPE_L2 | (8 << 16);
5233182293Sdavidch		CTX_WR(sc, GET_CID_ADDR(TX_CID), BCE_L2CTX_TX_CMD_TYPE, val);
5234179771Sdavidch
5235179771Sdavidch		/* Point the hardware to the first page in the chain. */
5236179771Sdavidch		val = BCE_ADDR_HI(sc->tx_bd_chain_paddr[0]);
5237182293Sdavidch		CTX_WR(sc, GET_CID_ADDR(TX_CID), BCE_L2CTX_TX_TBDR_BHADDR_HI, val);
5238179771Sdavidch		val = BCE_ADDR_LO(sc->tx_bd_chain_paddr[0]);
5239182293Sdavidch		CTX_WR(sc, GET_CID_ADDR(TX_CID), BCE_L2CTX_TX_TBDR_BHADDR_LO, val);
5240179771Sdavidch	}
5241179771Sdavidch
5242179771Sdavidch	DBEXIT(BCE_VERBOSE_RESET | BCE_VERBOSE_SEND | BCE_VERBOSE_CTX);
5243179771Sdavidch}
5244179771Sdavidch
5245182293Sdavidch
5246157642Sps/****************************************************************************/
5247157642Sps/* Allocate memory and initialize the TX data structures.                   */
5248157642Sps/*                                                                          */
5249157642Sps/* Returns:                                                                 */
5250157642Sps/*   0 for success, positive value for failure.                             */
5251157642Sps/****************************************************************************/
5252157642Spsstatic int
5253157642Spsbce_init_tx_chain(struct bce_softc *sc)
5254157642Sps{
5255157642Sps	struct tx_bd *txbd;
5256157642Sps	int i, rc = 0;
5257157642Sps
5258179771Sdavidch	DBENTER(BCE_VERBOSE_RESET | BCE_VERBOSE_SEND | BCE_VERBOSE_LOAD);
5259157642Sps
5260157642Sps	/* Set the initial TX producer/consumer indices. */
5261157642Sps	sc->tx_prod        = 0;
5262157642Sps	sc->tx_cons        = 0;
5263157642Sps	sc->tx_prod_bseq   = 0;
5264170392Sdavidch	sc->used_tx_bd     = 0;
5265169632Sdavidch	sc->max_tx_bd      = USABLE_TX_BD;
5266176448Sdavidch	DBRUN(sc->tx_hi_watermark = USABLE_TX_BD);
5267176448Sdavidch	DBRUN(sc->tx_full_count = 0);
5268157642Sps
5269157642Sps	/*
5270157642Sps	 * The NetXtreme II supports a linked-list structre called
5271157642Sps	 * a Buffer Descriptor Chain (or BD chain).  A BD chain
5272157642Sps	 * consists of a series of 1 or more chain pages, each of which
5273157642Sps	 * consists of a fixed number of BD entries.
5274157642Sps	 * The last BD entry on each page is a pointer to the next page
5275157642Sps	 * in the chain, and the last pointer in the BD chain
5276157642Sps	 * points back to the beginning of the chain.
5277157642Sps	 */
5278157642Sps
5279157642Sps	/* Set the TX next pointer chain entries. */
5280157642Sps	for (i = 0; i < TX_PAGES; i++) {
5281157642Sps		int j;
5282157642Sps
5283157642Sps		txbd = &sc->tx_bd_chain[i][USABLE_TX_BD_PER_PAGE];
5284157642Sps
5285157642Sps		/* Check if we've reached the last page. */
5286157642Sps		if (i == (TX_PAGES - 1))
5287157642Sps			j = 0;
5288157642Sps		else
5289157642Sps			j = i + 1;
5290157642Sps
5291157642Sps		txbd->tx_bd_haddr_hi = htole32(BCE_ADDR_HI(sc->tx_bd_chain_paddr[j]));
5292157642Sps		txbd->tx_bd_haddr_lo = htole32(BCE_ADDR_LO(sc->tx_bd_chain_paddr[j]));
5293157642Sps	}
5294157642Sps
5295179771Sdavidch	bce_init_tx_context(sc);
5296157642Sps
5297179771Sdavidch	DBRUNMSG(BCE_INSANE_SEND, bce_dump_tx_chain(sc, 0, TOTAL_TX_BD));
5298179771Sdavidch	DBEXIT(BCE_VERBOSE_RESET | BCE_VERBOSE_SEND | BCE_VERBOSE_LOAD);
5299157642Sps
5300157642Sps	return(rc);
5301157642Sps}
5302157642Sps
5303157642Sps
5304157642Sps/****************************************************************************/
5305157642Sps/* Free memory and clear the TX data structures.                            */
5306157642Sps/*                                                                          */
5307157642Sps/* Returns:                                                                 */
5308157642Sps/*   Nothing.                                                               */
5309157642Sps/****************************************************************************/
5310157642Spsstatic void
5311157642Spsbce_free_tx_chain(struct bce_softc *sc)
5312157642Sps{
5313157642Sps	int i;
5314157642Sps
5315179771Sdavidch	DBENTER(BCE_VERBOSE_RESET | BCE_VERBOSE_SEND | BCE_VERBOSE_UNLOAD);
5316157642Sps
5317157642Sps	/* Unmap, unload, and free any mbufs still in the TX mbuf chain. */
5318157642Sps	for (i = 0; i < TOTAL_TX_BD; i++) {
5319157642Sps		if (sc->tx_mbuf_ptr[i] != NULL) {
5320186168Sdelphij			if (sc->tx_mbuf_map[i] != NULL)
5321157642Sps				bus_dmamap_sync(sc->tx_mbuf_tag, sc->tx_mbuf_map[i],
5322157642Sps					BUS_DMASYNC_POSTWRITE);
5323157642Sps			m_freem(sc->tx_mbuf_ptr[i]);
5324157642Sps			sc->tx_mbuf_ptr[i] = NULL;
5325176448Sdavidch			DBRUN(sc->debug_tx_mbuf_alloc--);
5326179771Sdavidch		}
5327157642Sps	}
5328157642Sps
5329157642Sps	/* Clear each TX chain page. */
5330157642Sps	for (i = 0; i < TX_PAGES; i++)
5331157642Sps		bzero((char *)sc->tx_bd_chain[i], BCE_TX_CHAIN_PAGE_SZ);
5332157642Sps
5333171667Sdavidch	sc->used_tx_bd     = 0;
5334171667Sdavidch
5335157642Sps	/* Check if we lost any mbufs in the process. */
5336176448Sdavidch	DBRUNIF((sc->debug_tx_mbuf_alloc),
5337169271Sdavidch		BCE_PRINTF("%s(%d): Memory leak! Lost %d mbufs "
5338157642Sps			"from tx chain!\n",
5339176448Sdavidch			__FILE__, __LINE__, sc->debug_tx_mbuf_alloc));
5340157642Sps
5341179771Sdavidch	DBEXIT(BCE_VERBOSE_RESET | BCE_VERBOSE_SEND | BCE_VERBOSE_UNLOAD);
5342157642Sps}
5343157642Sps
5344157642Sps
5345157642Sps/****************************************************************************/
5346179771Sdavidch/* Initialize the RX context memory.                                        */
5347179771Sdavidch/*                                                                          */
5348179771Sdavidch/* Returns:                                                                 */
5349179771Sdavidch/*   Nothing                                                                */
5350179771Sdavidch/****************************************************************************/
5351179771Sdavidchstatic void
5352179771Sdavidchbce_init_rx_context(struct bce_softc *sc)
5353179771Sdavidch{
5354179771Sdavidch	u32 val;
5355179771Sdavidch
5356179771Sdavidch	DBENTER(BCE_VERBOSE_RESET | BCE_VERBOSE_RECV | BCE_VERBOSE_CTX);
5357179771Sdavidch
5358182293Sdavidch	/* Initialize the type, size, and BD cache levels for the RX context. */
5359182293Sdavidch	val = BCE_L2CTX_RX_CTX_TYPE_CTX_BD_CHN_TYPE_VALUE |
5360182293Sdavidch		BCE_L2CTX_RX_CTX_TYPE_SIZE_L2 |
5361182293Sdavidch		(0x02 << BCE_L2CTX_RX_BD_PRE_READ_SHIFT);
5362179771Sdavidch
5363182293Sdavidch	/*
5364182293Sdavidch	 * Set the level for generating pause frames
5365182293Sdavidch	 * when the number of available rx_bd's gets
5366182293Sdavidch	 * too low (the low watermark) and the level
5367182293Sdavidch	 * when pause frames can be stopped (the high
5368182293Sdavidch	 * watermark).
5369182293Sdavidch	 */
5370182293Sdavidch	if ((BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5709) ||
5371182293Sdavidch		(BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5716)) {
5372179771Sdavidch		u32 lo_water, hi_water;
5373179771Sdavidch
5374182293Sdavidch		lo_water = BCE_L2CTX_RX_LO_WATER_MARK_DEFAULT;
5375179771Sdavidch		hi_water = USABLE_RX_BD / 4;
5376179771Sdavidch
5377182293Sdavidch		lo_water /= BCE_L2CTX_RX_LO_WATER_MARK_SCALE;
5378182293Sdavidch		hi_water /= BCE_L2CTX_RX_HI_WATER_MARK_SCALE;
5379179771Sdavidch
5380179771Sdavidch		if (hi_water > 0xf)
5381179771Sdavidch			hi_water = 0xf;
5382179771Sdavidch		else if (hi_water == 0)
5383179771Sdavidch			lo_water = 0;
5384182293Sdavidch		val |= (lo_water << BCE_L2CTX_RX_LO_WATER_MARK_SHIFT) |
5385182293Sdavidch			(hi_water << BCE_L2CTX_RX_HI_WATER_MARK_SHIFT);
5386182293Sdavidch	}
5387179771Sdavidch
5388182293Sdavidch 	CTX_WR(sc, GET_CID_ADDR(RX_CID), BCE_L2CTX_RX_CTX_TYPE, val);
5389179771Sdavidch
5390182293Sdavidch	/* Setup the MQ BIN mapping for l2_ctx_host_bseq. */
5391182293Sdavidch	if ((BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5709) ||
5392182293Sdavidch		(BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5716)) {
5393179771Sdavidch		val = REG_RD(sc, BCE_MQ_MAP_L2_5);
5394179771Sdavidch		REG_WR(sc, BCE_MQ_MAP_L2_5, val | BCE_MQ_MAP_L2_5_ARM);
5395179771Sdavidch	}
5396182293Sdavidch
5397179771Sdavidch	/* Point the hardware to the first page in the chain. */
5398179771Sdavidch	val = BCE_ADDR_HI(sc->rx_bd_chain_paddr[0]);
5399182293Sdavidch	CTX_WR(sc, GET_CID_ADDR(RX_CID), BCE_L2CTX_RX_NX_BDHADDR_HI, val);
5400179771Sdavidch	val = BCE_ADDR_LO(sc->rx_bd_chain_paddr[0]);
5401182293Sdavidch	CTX_WR(sc, GET_CID_ADDR(RX_CID), BCE_L2CTX_RX_NX_BDHADDR_LO, val);
5402179771Sdavidch
5403179771Sdavidch	DBEXIT(BCE_VERBOSE_RESET | BCE_VERBOSE_RECV | BCE_VERBOSE_CTX);
5404179771Sdavidch}
5405179771Sdavidch
5406179771Sdavidch
5407179771Sdavidch/****************************************************************************/
5408157642Sps/* Allocate memory and initialize the RX data structures.                   */
5409157642Sps/*                                                                          */
5410157642Sps/* Returns:                                                                 */
5411157642Sps/*   0 for success, positive value for failure.                             */
5412157642Sps/****************************************************************************/
5413157642Spsstatic int
5414157642Spsbce_init_rx_chain(struct bce_softc *sc)
5415157642Sps{
5416157642Sps	struct rx_bd *rxbd;
5417157642Sps	int i, rc = 0;
5418157642Sps
5419179771Sdavidch	DBENTER(BCE_VERBOSE_RESET | BCE_VERBOSE_RECV | BCE_VERBOSE_LOAD |
5420179771Sdavidch		BCE_VERBOSE_CTX);
5421157642Sps
5422157642Sps	/* Initialize the RX producer and consumer indices. */
5423157642Sps	sc->rx_prod        = 0;
5424157642Sps	sc->rx_cons        = 0;
5425157642Sps	sc->rx_prod_bseq   = 0;
5426170392Sdavidch	sc->free_rx_bd     = USABLE_RX_BD;
5427178132Sdavidch	sc->max_rx_bd      = USABLE_RX_BD;
5428176448Sdavidch	DBRUN(sc->rx_low_watermark = sc->max_rx_bd);
5429176448Sdavidch	DBRUN(sc->rx_empty_count = 0);
5430157642Sps
5431157642Sps	/* Initialize the RX next pointer chain entries. */
5432157642Sps	for (i = 0; i < RX_PAGES; i++) {
5433157642Sps		int j;
5434157642Sps
5435157642Sps		rxbd = &sc->rx_bd_chain[i][USABLE_RX_BD_PER_PAGE];
5436157642Sps
5437157642Sps		/* Check if we've reached the last page. */
5438157642Sps		if (i == (RX_PAGES - 1))
5439157642Sps			j = 0;
5440157642Sps		else
5441157642Sps			j = i + 1;
5442157642Sps
5443157642Sps		/* Setup the chain page pointers. */
5444157642Sps		rxbd->rx_bd_haddr_hi = htole32(BCE_ADDR_HI(sc->rx_bd_chain_paddr[j]));
5445157642Sps		rxbd->rx_bd_haddr_lo = htole32(BCE_ADDR_LO(sc->rx_bd_chain_paddr[j]));
5446157642Sps	}
5447157642Sps
5448192281Sdelphij	/* Fill up the RX chain. */
5449171667Sdavidch	bce_fill_rx_chain(sc);
5450157642Sps
5451157642Sps	for (i = 0; i < RX_PAGES; i++) {
5452192281Sdelphij		bus_dmamap_sync(sc->rx_bd_chain_tag, sc->rx_bd_chain_map[i],
5453157642Sps		    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
5454157642Sps	}
5455157642Sps
5456179771Sdavidch	bce_init_rx_context(sc);
5457157642Sps
5458179771Sdavidch	DBRUNMSG(BCE_EXTREME_RECV, bce_dump_rx_chain(sc, 0, TOTAL_RX_BD));
5459179771Sdavidch	DBEXIT(BCE_VERBOSE_RESET | BCE_VERBOSE_RECV | BCE_VERBOSE_LOAD |
5460179771Sdavidch		BCE_VERBOSE_CTX);
5461179771Sdavidch	/* ToDo: Are there possible failure modes here? */
5462157642Sps	return(rc);
5463157642Sps}
5464157642Sps
5465157642Sps
5466157642Sps/****************************************************************************/
5467176448Sdavidch/* Add mbufs to the RX chain until its full or an mbuf allocation error     */
5468176448Sdavidch/* occurs.                                                                  */
5469176448Sdavidch/*                                                                          */
5470176448Sdavidch/* Returns:                                                                 */
5471176448Sdavidch/*   Nothing                                                                */
5472176448Sdavidch/****************************************************************************/
5473176448Sdavidchstatic void
5474176448Sdavidchbce_fill_rx_chain(struct bce_softc *sc)
5475176448Sdavidch{
5476176448Sdavidch	u16 prod, prod_idx;
5477176448Sdavidch	u32 prod_bseq;
5478176448Sdavidch
5479179771Sdavidch	DBENTER(BCE_VERBOSE_RESET | BCE_EXTREME_RECV | BCE_VERBOSE_LOAD |
5480179771Sdavidch		BCE_VERBOSE_CTX);
5481176448Sdavidch
5482179771Sdavidch	/* Get the RX chain producer indices. */
5483176448Sdavidch	prod      = sc->rx_prod;
5484176448Sdavidch	prod_bseq = sc->rx_prod_bseq;
5485176448Sdavidch
5486176448Sdavidch	/* Keep filling the RX chain until it's full. */
5487176448Sdavidch	while (sc->free_rx_bd > 0) {
5488176448Sdavidch		prod_idx = RX_CHAIN_IDX(prod);
5489176448Sdavidch		if (bce_get_rx_buf(sc, NULL, &prod, &prod_idx, &prod_bseq)) {
5490176448Sdavidch			/* Bail out if we can't add an mbuf to the chain. */
5491176448Sdavidch			break;
5492176448Sdavidch		}
5493176448Sdavidch		prod = NEXT_RX_BD(prod);
5494176448Sdavidch	}
5495176448Sdavidch
5496179771Sdavidch	/* Save the RX chain producer indices. */
5497176448Sdavidch	sc->rx_prod      = prod;
5498176448Sdavidch	sc->rx_prod_bseq = prod_bseq;
5499176448Sdavidch
5500178132Sdavidch	DBRUNIF(((prod & USABLE_RX_BD_PER_PAGE) == USABLE_RX_BD_PER_PAGE),
5501179771Sdavidch		BCE_PRINTF("%s(): Invalid rx_prod value: 0x%04X\n",
5502178132Sdavidch		__FUNCTION__, sc->rx_prod));
5503178132Sdavidch
5504179771Sdavidch	/* Write the mailbox and tell the chip about the waiting rx_bd's. */
5505182293Sdavidch	REG_WR16(sc, MB_GET_CID_ADDR(RX_CID) + BCE_L2MQ_RX_HOST_BDIDX,
5506179771Sdavidch		sc->rx_prod);
5507182293Sdavidch	REG_WR(sc, MB_GET_CID_ADDR(RX_CID) + BCE_L2MQ_RX_HOST_BSEQ,
5508179771Sdavidch		sc->rx_prod_bseq);
5509176448Sdavidch
5510179771Sdavidch	DBEXIT(BCE_VERBOSE_RESET | BCE_EXTREME_RECV | BCE_VERBOSE_LOAD |
5511179771Sdavidch		BCE_VERBOSE_CTX);
5512176448Sdavidch}
5513176448Sdavidch
5514176448Sdavidch
5515176448Sdavidch/****************************************************************************/
5516157642Sps/* Free memory and clear the RX data structures.                            */
5517157642Sps/*                                                                          */
5518157642Sps/* Returns:                                                                 */
5519157642Sps/*   Nothing.                                                               */
5520157642Sps/****************************************************************************/
5521157642Spsstatic void
5522157642Spsbce_free_rx_chain(struct bce_softc *sc)
5523157642Sps{
5524157642Sps	int i;
5525157642Sps
5526179771Sdavidch	DBENTER(BCE_VERBOSE_RESET | BCE_VERBOSE_RECV | BCE_VERBOSE_UNLOAD);
5527182293Sdavidch
5528157642Sps	/* Free any mbufs still in the RX mbuf chain. */
5529157642Sps	for (i = 0; i < TOTAL_RX_BD; i++) {
5530157642Sps		if (sc->rx_mbuf_ptr[i] != NULL) {
5531157642Sps			if (sc->rx_mbuf_map[i] != NULL)
5532157642Sps				bus_dmamap_sync(sc->rx_mbuf_tag, sc->rx_mbuf_map[i],
5533157642Sps					BUS_DMASYNC_POSTREAD);
5534157642Sps			m_freem(sc->rx_mbuf_ptr[i]);
5535157642Sps			sc->rx_mbuf_ptr[i] = NULL;
5536176448Sdavidch			DBRUN(sc->debug_rx_mbuf_alloc--);
5537157642Sps		}
5538157642Sps	}
5539157642Sps
5540157642Sps	/* Clear each RX chain page. */
5541157642Sps	for (i = 0; i < RX_PAGES; i++)
5542157642Sps		bzero((char *)sc->rx_bd_chain[i], BCE_RX_CHAIN_PAGE_SZ);
5543157642Sps
5544171667Sdavidch	sc->free_rx_bd = sc->max_rx_bd;
5545171667Sdavidch
5546157642Sps	/* Check if we lost any mbufs in the process. */
5547176448Sdavidch	DBRUNIF((sc->debug_rx_mbuf_alloc),
5548176448Sdavidch		BCE_PRINTF("%s(): Memory leak! Lost %d mbufs from rx chain!\n",
5549176448Sdavidch			__FUNCTION__, sc->debug_rx_mbuf_alloc));
5550157642Sps
5551179771Sdavidch	DBEXIT(BCE_VERBOSE_RESET | BCE_VERBOSE_RECV | BCE_VERBOSE_UNLOAD);
5552157642Sps}
5553157642Sps
5554157642Sps
5555198320Sstas#ifdef BCE_JUMBO_HDRSPLIT
5556157642Sps/****************************************************************************/
5557176448Sdavidch/* Allocate memory and initialize the page data structures.                 */
5558176448Sdavidch/* Assumes that bce_init_rx_chain() has not already been called.            */
5559176448Sdavidch/*                                                                          */
5560176448Sdavidch/* Returns:                                                                 */
5561176448Sdavidch/*   0 for success, positive value for failure.                             */
5562176448Sdavidch/****************************************************************************/
5563176448Sdavidchstatic int
5564176448Sdavidchbce_init_pg_chain(struct bce_softc *sc)
5565176448Sdavidch{
5566176448Sdavidch	struct rx_bd *pgbd;
5567176448Sdavidch	int i, rc = 0;
5568176448Sdavidch	u32 val;
5569176448Sdavidch
5570179771Sdavidch	DBENTER(BCE_VERBOSE_RESET | BCE_VERBOSE_RECV | BCE_VERBOSE_LOAD |
5571179771Sdavidch		BCE_VERBOSE_CTX);
5572176448Sdavidch
5573176448Sdavidch	/* Initialize the page producer and consumer indices. */
5574176448Sdavidch	sc->pg_prod        = 0;
5575176448Sdavidch	sc->pg_cons        = 0;
5576176448Sdavidch	sc->free_pg_bd     = USABLE_PG_BD;
5577176448Sdavidch	sc->max_pg_bd      = USABLE_PG_BD;
5578176448Sdavidch	DBRUN(sc->pg_low_watermark = sc->max_pg_bd);
5579176448Sdavidch	DBRUN(sc->pg_empty_count = 0);
5580176448Sdavidch
5581176448Sdavidch	/* Initialize the page next pointer chain entries. */
5582176448Sdavidch	for (i = 0; i < PG_PAGES; i++) {
5583176448Sdavidch		int j;
5584176448Sdavidch
5585176448Sdavidch		pgbd = &sc->pg_bd_chain[i][USABLE_PG_BD_PER_PAGE];
5586176448Sdavidch
5587176448Sdavidch		/* Check if we've reached the last page. */
5588176448Sdavidch		if (i == (PG_PAGES - 1))
5589176448Sdavidch			j = 0;
5590176448Sdavidch		else
5591176448Sdavidch			j = i + 1;
5592176448Sdavidch
5593176448Sdavidch		/* Setup the chain page pointers. */
5594176448Sdavidch		pgbd->rx_bd_haddr_hi = htole32(BCE_ADDR_HI(sc->pg_bd_chain_paddr[j]));
5595176448Sdavidch		pgbd->rx_bd_haddr_lo = htole32(BCE_ADDR_LO(sc->pg_bd_chain_paddr[j]));
5596176448Sdavidch	}
5597176448Sdavidch
5598182293Sdavidch	/* Setup the MQ BIN mapping for host_pg_bidx. */
5599182293Sdavidch	if ((BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5709)	||
5600182293Sdavidch		(BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5716))
5601179771Sdavidch		REG_WR(sc, BCE_MQ_MAP_L2_3, BCE_MQ_MAP_L2_3_DEFAULT);
5602176448Sdavidch
5603182293Sdavidch	CTX_WR(sc, GET_CID_ADDR(RX_CID), BCE_L2CTX_RX_PG_BUF_SIZE, 0);
5604179771Sdavidch
5605176448Sdavidch	/* Configure the rx_bd and page chain mbuf cluster size. */
5606179771Sdavidch	val = (sc->rx_bd_mbuf_data_len << 16) | sc->pg_bd_mbuf_alloc_size;
5607182293Sdavidch	CTX_WR(sc, GET_CID_ADDR(RX_CID), BCE_L2CTX_RX_PG_BUF_SIZE, val);
5608176448Sdavidch
5609176448Sdavidch	/* Configure the context reserved for jumbo support. */
5610182293Sdavidch	CTX_WR(sc, GET_CID_ADDR(RX_CID), BCE_L2CTX_RX_RBDC_KEY,
5611182293Sdavidch		BCE_L2CTX_RX_RBDC_JUMBO_KEY);
5612176448Sdavidch
5613179771Sdavidch	/* Point the hardware to the first page in the page chain. */
5614179771Sdavidch	val = BCE_ADDR_HI(sc->pg_bd_chain_paddr[0]);
5615182293Sdavidch	CTX_WR(sc, GET_CID_ADDR(RX_CID), BCE_L2CTX_RX_NX_PG_BDHADDR_HI, val);
5616179771Sdavidch	val = BCE_ADDR_LO(sc->pg_bd_chain_paddr[0]);
5617182293Sdavidch	CTX_WR(sc, GET_CID_ADDR(RX_CID), BCE_L2CTX_RX_NX_PG_BDHADDR_LO, val);
5618179771Sdavidch
5619176448Sdavidch	/* Fill up the page chain. */
5620176448Sdavidch	bce_fill_pg_chain(sc);
5621176448Sdavidch
5622176448Sdavidch	for (i = 0; i < PG_PAGES; i++) {
5623192281Sdelphij		bus_dmamap_sync(sc->pg_bd_chain_tag, sc->pg_bd_chain_map[i],
5624176448Sdavidch		    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
5625176448Sdavidch	}
5626176448Sdavidch
5627179771Sdavidch	DBRUNMSG(BCE_EXTREME_RECV, bce_dump_pg_chain(sc, 0, TOTAL_PG_BD));
5628179771Sdavidch	DBEXIT(BCE_VERBOSE_RESET | BCE_VERBOSE_RECV | BCE_VERBOSE_LOAD |
5629179771Sdavidch		BCE_VERBOSE_CTX);
5630176448Sdavidch	return(rc);
5631176448Sdavidch}
5632176448Sdavidch
5633179771Sdavidch
5634176448Sdavidch/****************************************************************************/
5635176448Sdavidch/* Add mbufs to the page chain until its full or an mbuf allocation error   */
5636176448Sdavidch/* occurs.                                                                  */
5637176448Sdavidch/*                                                                          */
5638176448Sdavidch/* Returns:                                                                 */
5639176448Sdavidch/*   Nothing                                                                */
5640176448Sdavidch/****************************************************************************/
5641176448Sdavidchstatic void
5642176448Sdavidchbce_fill_pg_chain(struct bce_softc *sc)
5643176448Sdavidch{
5644178132Sdavidch	u16 prod, prod_idx;
5645176448Sdavidch
5646179771Sdavidch	DBENTER(BCE_VERBOSE_RESET | BCE_EXTREME_RECV | BCE_VERBOSE_LOAD |
5647179771Sdavidch		BCE_VERBOSE_CTX);
5648176448Sdavidch
5649179771Sdavidch	/* Get the page chain prodcuer index. */
5650176448Sdavidch	prod = sc->pg_prod;
5651176448Sdavidch
5652176448Sdavidch	/* Keep filling the page chain until it's full. */
5653176448Sdavidch	while (sc->free_pg_bd > 0) {
5654176448Sdavidch		prod_idx = PG_CHAIN_IDX(prod);
5655176448Sdavidch		if (bce_get_pg_buf(sc, NULL, &prod, &prod_idx)) {
5656176448Sdavidch			/* Bail out if we can't add an mbuf to the chain. */
5657176448Sdavidch			break;
5658178132Sdavidch		}
5659176448Sdavidch		prod = NEXT_PG_BD(prod);
5660176448Sdavidch	}
5661176448Sdavidch
5662176448Sdavidch	/* Save the page chain producer index. */
5663176448Sdavidch	sc->pg_prod = prod;
5664176448Sdavidch
5665178132Sdavidch	DBRUNIF(((prod & USABLE_RX_BD_PER_PAGE) == USABLE_RX_BD_PER_PAGE),
5666179771Sdavidch		BCE_PRINTF("%s(): Invalid pg_prod value: 0x%04X\n",
5667178132Sdavidch		__FUNCTION__, sc->pg_prod));
5668176448Sdavidch
5669179771Sdavidch	/*
5670179771Sdavidch	 * Write the mailbox and tell the chip about
5671179771Sdavidch	 * the new rx_bd's in the page chain.
5672179771Sdavidch	 */
5673182293Sdavidch	REG_WR16(sc, MB_GET_CID_ADDR(RX_CID) + BCE_L2MQ_RX_HOST_PG_BDIDX,
5674179771Sdavidch		sc->pg_prod);
5675178132Sdavidch
5676179771Sdavidch	DBEXIT(BCE_VERBOSE_RESET | BCE_EXTREME_RECV | BCE_VERBOSE_LOAD |
5677179771Sdavidch		BCE_VERBOSE_CTX);
5678176448Sdavidch}
5679176448Sdavidch
5680176448Sdavidch
5681176448Sdavidch/****************************************************************************/
5682176448Sdavidch/* Free memory and clear the RX data structures.                            */
5683176448Sdavidch/*                                                                          */
5684176448Sdavidch/* Returns:                                                                 */
5685176448Sdavidch/*   Nothing.                                                               */
5686176448Sdavidch/****************************************************************************/
5687176448Sdavidchstatic void
5688176448Sdavidchbce_free_pg_chain(struct bce_softc *sc)
5689176448Sdavidch{
5690176448Sdavidch	int i;
5691176448Sdavidch
5692179771Sdavidch	DBENTER(BCE_VERBOSE_RESET | BCE_VERBOSE_RECV | BCE_VERBOSE_UNLOAD);
5693176448Sdavidch
5694176448Sdavidch	/* Free any mbufs still in the mbuf page chain. */
5695176448Sdavidch	for (i = 0; i < TOTAL_PG_BD; i++) {
5696176448Sdavidch		if (sc->pg_mbuf_ptr[i] != NULL) {
5697176448Sdavidch			if (sc->pg_mbuf_map[i] != NULL)
5698176448Sdavidch				bus_dmamap_sync(sc->pg_mbuf_tag, sc->pg_mbuf_map[i],
5699176448Sdavidch					BUS_DMASYNC_POSTREAD);
5700176448Sdavidch			m_freem(sc->pg_mbuf_ptr[i]);
5701176448Sdavidch			sc->pg_mbuf_ptr[i] = NULL;
5702178132Sdavidch			DBRUN(sc->debug_pg_mbuf_alloc--);
5703176448Sdavidch		}
5704176448Sdavidch	}
5705176448Sdavidch
5706176448Sdavidch	/* Clear each page chain pages. */
5707176448Sdavidch	for (i = 0; i < PG_PAGES; i++)
5708176448Sdavidch		bzero((char *)sc->pg_bd_chain[i], BCE_PG_CHAIN_PAGE_SZ);
5709176448Sdavidch
5710176448Sdavidch	sc->free_pg_bd = sc->max_pg_bd;
5711176448Sdavidch
5712176448Sdavidch	/* Check if we lost any mbufs in the process. */
5713176448Sdavidch	DBRUNIF((sc->debug_pg_mbuf_alloc),
5714176448Sdavidch		BCE_PRINTF("%s(): Memory leak! Lost %d mbufs from page chain!\n",
5715176448Sdavidch			__FUNCTION__, sc->debug_pg_mbuf_alloc));
5716176448Sdavidch
5717179771Sdavidch	DBEXIT(BCE_VERBOSE_RESET | BCE_VERBOSE_RECV | BCE_VERBOSE_UNLOAD);
5718176448Sdavidch}
5719198320Sstas#endif /* BCE_JUMBO_HDRSPLIT */
5720176448Sdavidch
5721176448Sdavidch
5722176448Sdavidch/****************************************************************************/
5723157642Sps/* Set media options.                                                       */
5724157642Sps/*                                                                          */
5725157642Sps/* Returns:                                                                 */
5726157642Sps/*   0 for success, positive value for failure.                             */
5727157642Sps/****************************************************************************/
5728157642Spsstatic int
5729157642Spsbce_ifmedia_upd(struct ifnet *ifp)
5730157642Sps{
5731179771Sdavidch	struct bce_softc *sc = ifp->if_softc;
5732165994Sjhb
5733179771Sdavidch	DBENTER(BCE_VERBOSE);
5734179771Sdavidch
5735165994Sjhb	BCE_LOCK(sc);
5736165994Sjhb	bce_ifmedia_upd_locked(ifp);
5737165994Sjhb	BCE_UNLOCK(sc);
5738179771Sdavidch
5739179771Sdavidch	DBEXIT(BCE_VERBOSE);
5740165994Sjhb	return (0);
5741165994Sjhb}
5742165994Sjhb
5743170392Sdavidch
5744169632Sdavidch/****************************************************************************/
5745169632Sdavidch/* Set media options.                                                       */
5746169632Sdavidch/*                                                                          */
5747169632Sdavidch/* Returns:                                                                 */
5748169632Sdavidch/*   Nothing.                                                               */
5749169632Sdavidch/****************************************************************************/
5750165994Sjhbstatic void
5751165994Sjhbbce_ifmedia_upd_locked(struct ifnet *ifp)
5752165994Sjhb{
5753179771Sdavidch	struct bce_softc *sc = ifp->if_softc;
5754157642Sps	struct mii_data *mii;
5755170392Sdavidch
5756179771Sdavidch	DBENTER(BCE_VERBOSE);
5757179771Sdavidch
5758165994Sjhb	BCE_LOCK_ASSERT(sc);
5759157642Sps
5760157642Sps	mii = device_get_softc(sc->bce_miibus);
5761170392Sdavidch
5762170392Sdavidch	/* Make sure the MII bus has been enumerated. */
5763170392Sdavidch	if (mii) {
5764169271Sdavidch		sc->bce_link = 0;
5765169271Sdavidch		if (mii->mii_instance) {
5766169271Sdavidch			struct mii_softc *miisc;
5767165994Sjhb
5768169271Sdavidch			LIST_FOREACH(miisc, &mii->mii_phys, mii_list)
5769169271Sdavidch				mii_phy_reset(miisc);
5770169271Sdavidch		}
5771170392Sdavidch		mii_mediachg(mii);
5772157642Sps	}
5773179771Sdavidch
5774179771Sdavidch	DBEXIT(BCE_VERBOSE);
5775157642Sps}
5776157642Sps
5777157642Sps
5778157642Sps/****************************************************************************/
5779157642Sps/* Reports current media status.                                            */
5780157642Sps/*                                                                          */
5781157642Sps/* Returns:                                                                 */
5782157642Sps/*   Nothing.                                                               */
5783157642Sps/****************************************************************************/
5784157642Spsstatic void
5785157642Spsbce_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
5786157642Sps{
5787179771Sdavidch	struct bce_softc *sc = ifp->if_softc;
5788157642Sps	struct mii_data *mii;
5789157642Sps
5790179771Sdavidch	DBENTER(BCE_VERBOSE);
5791157642Sps
5792157642Sps	BCE_LOCK(sc);
5793157642Sps
5794157642Sps	mii = device_get_softc(sc->bce_miibus);
5795157642Sps
5796157642Sps	mii_pollstat(mii);
5797157642Sps	ifmr->ifm_active = mii->mii_media_active;
5798157642Sps	ifmr->ifm_status = mii->mii_media_status;
5799157642Sps
5800157642Sps	BCE_UNLOCK(sc);
5801179771Sdavidch
5802179771Sdavidch	DBEXIT(BCE_VERBOSE);
5803157642Sps}
5804157642Sps
5805157642Sps
5806157642Sps/****************************************************************************/
5807157642Sps/* Handles PHY generated interrupt events.                                  */
5808157642Sps/*                                                                          */
5809157642Sps/* Returns:                                                                 */
5810157642Sps/*   Nothing.                                                               */
5811157642Sps/****************************************************************************/
5812157642Spsstatic void
5813157642Spsbce_phy_intr(struct bce_softc *sc)
5814157642Sps{
5815157642Sps	u32 new_link_state, old_link_state;
5816157642Sps
5817179771Sdavidch	DBENTER(BCE_VERBOSE_PHY | BCE_VERBOSE_INTR);
5818179771Sdavidch
5819157642Sps	new_link_state = sc->status_block->status_attn_bits &
5820157642Sps		STATUS_ATTN_BITS_LINK_STATE;
5821157642Sps	old_link_state = sc->status_block->status_attn_bits_ack &
5822157642Sps		STATUS_ATTN_BITS_LINK_STATE;
5823157642Sps
5824157642Sps	/* Handle any changes if the link state has changed. */
5825157642Sps	if (new_link_state != old_link_state) {
5826157642Sps
5827157642Sps		/* Update the status_attn_bits_ack field in the status block. */
5828157642Sps		if (new_link_state) {
5829157642Sps			REG_WR(sc, BCE_PCICFG_STATUS_BIT_SET_CMD,
5830157642Sps				STATUS_ATTN_BITS_LINK_STATE);
5831179771Sdavidch			DBPRINT(sc, BCE_INFO_PHY, "%s(): Link is now UP.\n",
5832179771Sdavidch				__FUNCTION__);
5833157642Sps		}
5834157642Sps		else {
5835157642Sps			REG_WR(sc, BCE_PCICFG_STATUS_BIT_CLEAR_CMD,
5836157642Sps				STATUS_ATTN_BITS_LINK_STATE);
5837179771Sdavidch			DBPRINT(sc, BCE_INFO_PHY, "%s(): Link is now DOWN.\n",
5838179771Sdavidch				__FUNCTION__);
5839157642Sps		}
5840157642Sps
5841179771Sdavidch		/*
5842179771Sdavidch		 * Assume link is down and allow
5843179771Sdavidch		 * tick routine to update the state
5844179771Sdavidch		 * based on the actual media state.
5845179771Sdavidch		 */
5846179771Sdavidch		sc->bce_link = 0;
5847179771Sdavidch		callout_stop(&sc->bce_tick_callout);
5848179771Sdavidch		bce_tick(sc);
5849157642Sps	}
5850157642Sps
5851157642Sps	/* Acknowledge the link change interrupt. */
5852157642Sps	REG_WR(sc, BCE_EMAC_STATUS, BCE_EMAC_STATUS_LINK_CHANGE);
5853179771Sdavidch
5854179771Sdavidch	DBEXIT(BCE_VERBOSE_PHY | BCE_VERBOSE_INTR);
5855157642Sps}
5856157642Sps
5857157642Sps
5858157642Sps/****************************************************************************/
5859178132Sdavidch/* Reads the receive consumer value from the status block (skipping over    */
5860176448Sdavidch/* chain page pointer if necessary).                                        */
5861176448Sdavidch/*                                                                          */
5862176448Sdavidch/* Returns:                                                                 */
5863176448Sdavidch/*   hw_cons                                                                */
5864176448Sdavidch/****************************************************************************/
5865176448Sdavidchstatic inline u16
5866176448Sdavidchbce_get_hw_rx_cons(struct bce_softc *sc)
5867176448Sdavidch{
5868182293Sdavidch	u16 hw_cons;
5869176448Sdavidch
5870182293Sdavidch	rmb();
5871182293Sdavidch	hw_cons = sc->status_block->status_rx_quick_consumer_index0;
5872176448Sdavidch	if ((hw_cons & USABLE_RX_BD_PER_PAGE) == USABLE_RX_BD_PER_PAGE)
5873176448Sdavidch		hw_cons++;
5874176448Sdavidch
5875176448Sdavidch	return hw_cons;
5876176448Sdavidch}
5877176448Sdavidch
5878176448Sdavidch/****************************************************************************/
5879157642Sps/* Handles received frame interrupt events.                                 */
5880157642Sps/*                                                                          */
5881157642Sps/* Returns:                                                                 */
5882157642Sps/*   Nothing.                                                               */
5883157642Sps/****************************************************************************/
5884157642Spsstatic void
5885157642Spsbce_rx_intr(struct bce_softc *sc)
5886157642Sps{
5887178132Sdavidch	struct ifnet *ifp = sc->bce_ifp;
5888178132Sdavidch	struct l2_fhdr *l2fhdr;
5889204368Syongari	struct ether_vlan_header *vh;
5890179695Sdavidch	unsigned int pkt_len;
5891179771Sdavidch	u16 sw_rx_cons, sw_rx_cons_idx, hw_rx_cons;
5892178132Sdavidch	u32 status;
5893198320Sstas#ifdef BCE_JUMBO_HDRSPLIT
5894179771Sdavidch	unsigned int rem_len;
5895179771Sdavidch	u16 sw_pg_cons, sw_pg_cons_idx;
5896179695Sdavidch#endif
5897178132Sdavidch
5898179771Sdavidch	DBENTER(BCE_VERBOSE_RECV | BCE_VERBOSE_INTR);
5899179771Sdavidch	DBRUN(sc->rx_interrupts++);
5900179771Sdavidch	DBPRINT(sc, BCE_EXTREME_RECV, "%s(enter): rx_prod = 0x%04X, "
5901179771Sdavidch		"rx_cons = 0x%04X, rx_prod_bseq = 0x%08X\n",
5902179771Sdavidch		__FUNCTION__, sc->rx_prod, sc->rx_cons, sc->rx_prod_bseq);
5903178132Sdavidch
5904157642Sps	/* Prepare the RX chain pages to be accessed by the host CPU. */
5905157642Sps	for (int i = 0; i < RX_PAGES; i++)
5906157642Sps		bus_dmamap_sync(sc->rx_bd_chain_tag,
5907192281Sdelphij		    sc->rx_bd_chain_map[i], BUS_DMASYNC_POSTREAD);
5908157642Sps
5909198320Sstas#ifdef BCE_JUMBO_HDRSPLIT
5910176448Sdavidch	/* Prepare the page chain pages to be accessed by the host CPU. */
5911176448Sdavidch	for (int i = 0; i < PG_PAGES; i++)
5912176448Sdavidch		bus_dmamap_sync(sc->pg_bd_chain_tag,
5913192281Sdelphij		    sc->pg_bd_chain_map[i], BUS_DMASYNC_POSTREAD);
5914179695Sdavidch#endif
5915176448Sdavidch
5916157642Sps	/* Get the hardware's view of the RX consumer index. */
5917176448Sdavidch	hw_rx_cons = sc->hw_rx_cons = bce_get_hw_rx_cons(sc);
5918157642Sps
5919176448Sdavidch	/* Get working copies of the driver's view of the consumer indices. */
5920176448Sdavidch	sw_rx_cons = sc->rx_cons;
5921198320Sstas#ifdef BCE_JUMBO_HDRSPLIT
5922179771Sdavidch	sw_pg_cons = sc->pg_cons;
5923179695Sdavidch#endif
5924157642Sps
5925170392Sdavidch	/* Update some debug statistics counters */
5926157642Sps	DBRUNIF((sc->free_rx_bd < sc->rx_low_watermark),
5927170392Sdavidch		sc->rx_low_watermark = sc->free_rx_bd);
5928176448Sdavidch	DBRUNIF((sc->free_rx_bd == sc->max_rx_bd), sc->rx_empty_count++);
5929157642Sps
5930178132Sdavidch	/* Scan through the receive chain as long as there is work to do */
5931176448Sdavidch	/* ToDo: Consider setting a limit on the number of packets processed. */
5932182293Sdavidch	rmb();
5933176448Sdavidch	while (sw_rx_cons != hw_rx_cons) {
5934176448Sdavidch		struct mbuf *m0;
5935179771Sdavidch
5936157642Sps		/* Convert the producer/consumer indices to an actual rx_bd index. */
5937176448Sdavidch		sw_rx_cons_idx = RX_CHAIN_IDX(sw_rx_cons);
5938157642Sps
5939176448Sdavidch		/* Unmap the mbuf from DMA space. */
5940192281Sdelphij		bus_dmamap_sync(sc->rx_mbuf_tag, sc->rx_mbuf_map[sw_rx_cons_idx],
5941192281Sdelphij		    BUS_DMASYNC_POSTREAD);
5942176448Sdavidch		bus_dmamap_unload(sc->rx_mbuf_tag,
5943176448Sdavidch		    sc->rx_mbuf_map[sw_rx_cons_idx]);
5944157642Sps
5945176448Sdavidch		/* Remove the mbuf from the RX chain. */
5946176448Sdavidch		m0 = sc->rx_mbuf_ptr[sw_rx_cons_idx];
5947176448Sdavidch		sc->rx_mbuf_ptr[sw_rx_cons_idx] = NULL;
5948176448Sdavidch		DBRUN(sc->debug_rx_mbuf_alloc--);
5949176448Sdavidch		sc->free_rx_bd++;
5950179771Sdavidch
5951202717Sdavidch        if(m0 == NULL) {
5952202717Sdavidch            DBPRINT(sc, BCE_EXTREME_RECV, "%s(): Oops! Empty mbuf pointer "
5953202717Sdavidch                "found in sc->rx_mbuf_ptr[0x%04X]!\n",
5954202717Sdavidch                __FUNCTION__, sw_rx_cons_idx);
5955202717Sdavidch            goto bce_rx_int_next_rx;
5956202717Sdavidch        }
5957202717Sdavidch
5958202717Sdavidch        /*
5959202717Sdavidch         * Frames received on the NetXteme II are prepended	with an
5960202717Sdavidch         * l2_fhdr structure which provides status information about
5961202717Sdavidch         * the received frame (including VLAN tags and checksum info).
5962202717Sdavidch         * The frames are also automatically adjusted to align the IP
5963202717Sdavidch         * header (i.e. two null bytes are inserted before the Ethernet
5964202717Sdavidch         * header).  As a result the data DMA'd by the controller into
5965202717Sdavidch         * the mbuf is as follows:
5966202717Sdavidch         *
5967202717Sdavidch         * +---------+-----+---------------------+-----+
5968202717Sdavidch         * | l2_fhdr | pad | packet data         | FCS |
5969202717Sdavidch         * +---------+-----+---------------------+-----+
5970202717Sdavidch         *
5971202717Sdavidch         * The l2_fhdr needs to be checked and skipped and the FCS needs
5972202717Sdavidch         * to be stripped before sending the packet up the stack.
5973202717Sdavidch         */
5974176448Sdavidch		l2fhdr  = mtod(m0, struct l2_fhdr *);
5975157642Sps
5976176448Sdavidch		/* Get the packet data + FCS length and the status. */
5977176448Sdavidch		pkt_len = l2fhdr->l2_fhdr_pkt_len;
5978176448Sdavidch		status  = l2fhdr->l2_fhdr_status;
5979178132Sdavidch
5980176448Sdavidch		/*
5981178132Sdavidch		 * Skip over the l2_fhdr and pad, resulting in the
5982179771Sdavidch		 * following data in the mbuf:
5983178132Sdavidch		 * +---------------------+-----+
5984178132Sdavidch		 * | packet data         | FCS |
5985178132Sdavidch		 * +---------------------+-----+
5986178132Sdavidch		 */
5987176448Sdavidch		m_adj(m0, sizeof(struct l2_fhdr) + ETHER_ALIGN);
5988178132Sdavidch
5989198320Sstas#ifdef BCE_JUMBO_HDRSPLIT
5990178132Sdavidch		/*
5991178132Sdavidch		 * Check whether the received frame fits in a single
5992179771Sdavidch		 * mbuf or not (i.e. packet data + FCS <=
5993179695Sdavidch		 * sc->rx_bd_mbuf_data_len bytes).
5994176448Sdavidch		 */
5995176448Sdavidch		if (pkt_len > m0->m_len) {
5996170392Sdavidch			/*
5997178132Sdavidch			 * The received frame is larger than a single mbuf.
5998178132Sdavidch			 * If the frame was a TCP frame then only the TCP
5999179771Sdavidch			 * header is placed in the mbuf, the remaining
6000178132Sdavidch			 * payload (including FCS) is placed in the page
6001178132Sdavidch			 * chain, the SPLIT flag is set, and the header
6002178132Sdavidch			 * length is placed in the IP checksum field.
6003178132Sdavidch			 * If the frame is not a TCP frame then the mbuf
6004179771Sdavidch			 * is filled and the remaining bytes are placed
6005178132Sdavidch			 * in the page chain.
6006169632Sdavidch			 */
6007178132Sdavidch
6008178132Sdavidch			DBPRINT(sc, BCE_INFO_RECV, "%s(): Found a large packet.\n",
6009178132Sdavidch				__FUNCTION__);
6010178132Sdavidch
6011182293Sdavidch			/*
6012182293Sdavidch			 * When the page chain is enabled and the TCP
6013182293Sdavidch			 * header has been split from the TCP payload,
6014182293Sdavidch			 * the ip_xsum structure will reflect the length
6015182293Sdavidch			 * of the TCP header, not the IP checksum.  Set
6016182293Sdavidch			 * the packet length of the mbuf accordingly.
6017182293Sdavidch			 */
6018178132Sdavidch		 	if (status & L2_FHDR_STATUS_SPLIT)
6019178132Sdavidch				m0->m_len = l2fhdr->l2_fhdr_ip_xsum;
6020178132Sdavidch
6021178132Sdavidch			rem_len = pkt_len - m0->m_len;
6022178132Sdavidch
6023176448Sdavidch			/* Pull mbufs off the page chain for the remaining data. */
6024178132Sdavidch			while (rem_len > 0) {
6025178132Sdavidch				struct mbuf *m_pg;
6026179771Sdavidch
6027178132Sdavidch				sw_pg_cons_idx = PG_CHAIN_IDX(sw_pg_cons);
6028178132Sdavidch
6029176448Sdavidch				/* Remove the mbuf from the page chain. */
6030176448Sdavidch				m_pg = sc->pg_mbuf_ptr[sw_pg_cons_idx];
6031176448Sdavidch				sc->pg_mbuf_ptr[sw_pg_cons_idx] = NULL;
6032176448Sdavidch				DBRUN(sc->debug_pg_mbuf_alloc--);
6033176448Sdavidch				sc->free_pg_bd++;
6034157642Sps
6035176448Sdavidch				/* Unmap the page chain mbuf from DMA space. */
6036179771Sdavidch				bus_dmamap_sync(sc->pg_mbuf_tag,
6037176448Sdavidch					sc->pg_mbuf_map[sw_pg_cons_idx],
6038176448Sdavidch					BUS_DMASYNC_POSTREAD);
6039176448Sdavidch				bus_dmamap_unload(sc->pg_mbuf_tag,
6040176448Sdavidch					sc->pg_mbuf_map[sw_pg_cons_idx]);
6041157642Sps
6042178132Sdavidch				/* Adjust the mbuf length. */
6043176448Sdavidch				if (rem_len < m_pg->m_len) {
6044176448Sdavidch					/* The mbuf chain is complete. */
6045176448Sdavidch					m_pg->m_len = rem_len;
6046176448Sdavidch					rem_len = 0;
6047178132Sdavidch				} else {
6048178132Sdavidch					/* More packet data is waiting. */
6049176448Sdavidch					rem_len -= m_pg->m_len;
6050178132Sdavidch				}
6051178132Sdavidch
6052176448Sdavidch				/* Concatenate the mbuf cluster to the mbuf. */
6053176448Sdavidch				m_cat(m0, m_pg);
6054157642Sps
6055178132Sdavidch				sw_pg_cons = NEXT_PG_BD(sw_pg_cons);
6056176448Sdavidch			}
6057176448Sdavidch
6058178132Sdavidch			/* Set the total packet length. */
6059178132Sdavidch			m0->m_pkthdr.len = pkt_len;
6060178132Sdavidch
6061176448Sdavidch		} else {
6062157642Sps			/*
6063176448Sdavidch			 * The received packet is small and fits in a
6064178132Sdavidch			 * single mbuf (i.e. the l2_fhdr + pad + packet +
6065178132Sdavidch			 * FCS <= MHLEN).  In other words, the packet is
6066176448Sdavidch			 * 154 bytes or less in size.
6067157642Sps			 */
6068157642Sps
6069178132Sdavidch			DBPRINT(sc, BCE_INFO_RECV, "%s(): Found a small packet.\n",
6070178132Sdavidch				__FUNCTION__);
6071178132Sdavidch
6072176448Sdavidch			/* Set the total packet length. */
6073176448Sdavidch			m0->m_pkthdr.len = m0->m_len = pkt_len;
6074179771Sdavidch		}
6075191923Sdavidch#else
6076191923Sdavidch        /* Set the total packet length. */
6077191923Sdavidch		m0->m_pkthdr.len = m0->m_len = pkt_len;
6078179695Sdavidch#endif
6079178132Sdavidch
6080178132Sdavidch		/* Remove the trailing Ethernet FCS. */
6081178132Sdavidch		m_adj(m0, -ETHER_CRC_LEN);
6082178132Sdavidch
6083176448Sdavidch		/* Check that the resulting mbuf chain is valid. */
6084176448Sdavidch		DBRUN(m_sanity(m0, FALSE));
6085179771Sdavidch		DBRUNIF(((m0->m_len < ETHER_HDR_LEN) |
6086179771Sdavidch			(m0->m_pkthdr.len > BCE_MAX_JUMBO_ETHER_MTU_VLAN)),
6087179771Sdavidch			BCE_PRINTF("Invalid Ethernet frame size!\n");
6088179771Sdavidch			m_print(m0, 128));
6089157642Sps
6090189325Sdavidch		DBRUNIF(DB_RANDOMTRUE(l2fhdr_error_sim_control),
6091176448Sdavidch			BCE_PRINTF("Simulating l2_fhdr status error.\n");
6092189325Sdavidch			sc->l2fhdr_error_sim_count++;
6093176448Sdavidch			status = status | L2_FHDR_ERRORS_PHY_DECODE);
6094157642Sps
6095176448Sdavidch		/* Check the received frame for errors. */
6096179771Sdavidch		if (status & (L2_FHDR_ERRORS_BAD_CRC |
6097179771Sdavidch			L2_FHDR_ERRORS_PHY_DECODE | L2_FHDR_ERRORS_ALIGNMENT |
6098176448Sdavidch			L2_FHDR_ERRORS_TOO_SHORT  | L2_FHDR_ERRORS_GIANT_FRAME)) {
6099157642Sps
6100176448Sdavidch			/* Log the error and release the mbuf. */
6101176448Sdavidch			ifp->if_ierrors++;
6102189325Sdavidch			sc->l2fhdr_error_count++;
6103179771Sdavidch
6104176448Sdavidch			m_freem(m0);
6105176448Sdavidch			m0 = NULL;
6106176448Sdavidch			goto bce_rx_int_next_rx;
6107176448Sdavidch		}
6108157642Sps
6109176448Sdavidch		/* Send the packet to the appropriate interface. */
6110176448Sdavidch		m0->m_pkthdr.rcvif = ifp;
6111178132Sdavidch
6112178132Sdavidch		/* Assume no hardware checksum. */
6113176448Sdavidch		m0->m_pkthdr.csum_flags = 0;
6114178132Sdavidch
6115176448Sdavidch		/* Validate the checksum if offload enabled. */
6116176448Sdavidch		if (ifp->if_capenable & IFCAP_RXCSUM) {
6117157642Sps
6118176448Sdavidch			/* Check for an IP datagram. */
6119178132Sdavidch		 	if (!(status & L2_FHDR_STATUS_SPLIT) &&
6120176448Sdavidch				(status & L2_FHDR_STATUS_IP_DATAGRAM)) {
6121176448Sdavidch				m0->m_pkthdr.csum_flags |= CSUM_IP_CHECKED;
6122157642Sps
6123176448Sdavidch				/* Check if the IP checksum is valid. */
6124176448Sdavidch				if ((l2fhdr->l2_fhdr_ip_xsum ^ 0xffff) == 0)
6125176448Sdavidch					m0->m_pkthdr.csum_flags |= CSUM_IP_VALID;
6126178132Sdavidch			}
6127157642Sps
6128176448Sdavidch			/* Check for a valid TCP/UDP frame. */
6129176448Sdavidch			if (status & (L2_FHDR_STATUS_TCP_SEGMENT |
6130176448Sdavidch				L2_FHDR_STATUS_UDP_DATAGRAM)) {
6131157642Sps
6132176448Sdavidch				/* Check for a good TCP/UDP checksum. */
6133176448Sdavidch				if ((status & (L2_FHDR_ERRORS_TCP_XSUM |
6134176448Sdavidch					      L2_FHDR_ERRORS_UDP_XSUM)) == 0) {
6135176448Sdavidch					m0->m_pkthdr.csum_data =
6136176448Sdavidch					    l2fhdr->l2_fhdr_tcp_udp_xsum;
6137179771Sdavidch					m0->m_pkthdr.csum_flags |= (CSUM_DATA_VALID
6138176448Sdavidch						| CSUM_PSEUDO_HDR);
6139157642Sps				}
6140176448Sdavidch			}
6141179771Sdavidch		}
6142157642Sps
6143189325Sdavidch		/* Attach the VLAN tag.	*/
6144176448Sdavidch		if (status & L2_FHDR_STATUS_L2_VLAN_TAG) {
6145204368Syongari			if (ifp->if_capenable & IFCAP_VLAN_HWTAGGING) {
6146157642Sps#if __FreeBSD_version < 700000
6147204368Syongari				VLAN_INPUT_TAG(ifp, m0,
6148204368Syongari				    l2fhdr->l2_fhdr_vlan_tag, continue);
6149157642Sps#else
6150204368Syongari				m0->m_pkthdr.ether_vtag =
6151204368Syongari				    l2fhdr->l2_fhdr_vlan_tag;
6152204368Syongari				m0->m_flags |= M_VLANTAG;
6153179771Sdavidch#endif
6154204368Syongari			} else {
6155204368Syongari				/*
6156204368Syongari				 * bce(4) controllers can't disable VLAN
6157204368Syongari				 * tag stripping if management firmware
6158204368Syongari				 * (ASF/IPMI/UMP) is running. So we always
6159204368Syongari				 * strip VLAN tag and manually reconstruct
6160204368Syongari				 * the VLAN frame by appending stripped
6161204368Syongari				 * VLAN tag in driver if VLAN tag stripping
6162204368Syongari				 * was disabled.
6163204368Syongari				 *
6164204368Syongari				 * TODO: LLC SNAP handling.
6165204368Syongari				 */
6166204368Syongari				bcopy(mtod(m0, uint8_t *),
6167204368Syongari				    mtod(m0, uint8_t *) - ETHER_VLAN_ENCAP_LEN,
6168204368Syongari				    ETHER_ADDR_LEN * 2);
6169204368Syongari				m0->m_data -= ETHER_VLAN_ENCAP_LEN;
6170204368Syongari				vh = mtod(m0, struct ether_vlan_header *);
6171204368Syongari				vh->evl_encap_proto = htons(ETHERTYPE_VLAN);
6172204368Syongari				vh->evl_tag = htons(l2fhdr->l2_fhdr_vlan_tag);
6173204368Syongari				m0->m_pkthdr.len += ETHER_VLAN_ENCAP_LEN;
6174204368Syongari				m0->m_len += ETHER_VLAN_ENCAP_LEN;
6175204368Syongari			}
6176176448Sdavidch		}
6177157642Sps
6178189325Sdavidch		/* Increment received packet statistics. */
6179176448Sdavidch		ifp->if_ipackets++;
6180157642Sps
6181157642Spsbce_rx_int_next_rx:
6182176448Sdavidch		sw_rx_cons = NEXT_RX_BD(sw_rx_cons);
6183157642Sps
6184170392Sdavidch		/* If we have a packet, pass it up the stack */
6185176448Sdavidch		if (m0) {
6186170392Sdavidch			/* Make sure we don't lose our place when we release the lock. */
6187178132Sdavidch			sc->rx_cons = sw_rx_cons;
6188198320Sstas#ifdef BCE_JUMBO_HDRSPLIT
6189179771Sdavidch			sc->pg_cons = sw_pg_cons;
6190179695Sdavidch#endif
6191170392Sdavidch
6192169271Sdavidch			BCE_UNLOCK(sc);
6193176448Sdavidch			(*ifp->if_input)(ifp, m0);
6194170392Sdavidch			BCE_LOCK(sc);
6195179771Sdavidch
6196170392Sdavidch			/* Recover our place. */
6197178132Sdavidch			sw_rx_cons = sc->rx_cons;
6198198320Sstas#ifdef BCE_JUMBO_HDRSPLIT
6199179771Sdavidch			sw_pg_cons = sc->pg_cons;
6200179695Sdavidch#endif
6201170392Sdavidch		}
6202170392Sdavidch
6203157642Sps		/* Refresh hw_cons to see if there's new work */
6204176448Sdavidch		if (sw_rx_cons == hw_rx_cons)
6205176448Sdavidch			hw_rx_cons = sc->hw_rx_cons = bce_get_hw_rx_cons(sc);
6206157642Sps	}
6207157642Sps
6208176448Sdavidch	/* No new packets to process.  Refill the RX and page chains and exit. */
6209198320Sstas#ifdef BCE_JUMBO_HDRSPLIT
6210176448Sdavidch	sc->pg_cons = sw_pg_cons;
6211179771Sdavidch	bce_fill_pg_chain(sc);
6212179695Sdavidch#endif
6213176448Sdavidch
6214176448Sdavidch	sc->rx_cons = sw_rx_cons;
6215171667Sdavidch	bce_fill_rx_chain(sc);
6216171667Sdavidch
6217192281Sdelphij	/* Prepare the page chain pages to be accessed by the NIC. */
6218157642Sps	for (int i = 0; i < RX_PAGES; i++)
6219157642Sps		bus_dmamap_sync(sc->rx_bd_chain_tag,
6220157642Sps		    sc->rx_bd_chain_map[i], BUS_DMASYNC_PREWRITE);
6221157642Sps
6222198320Sstas#ifdef BCE_JUMBO_HDRSPLIT
6223176448Sdavidch	for (int i = 0; i < PG_PAGES; i++)
6224176448Sdavidch		bus_dmamap_sync(sc->pg_bd_chain_tag,
6225179771Sdavidch		    sc->pg_bd_chain_map[i], BUS_DMASYNC_PREWRITE);
6226179695Sdavidch#endif
6227176448Sdavidch
6228179771Sdavidch	DBPRINT(sc, BCE_EXTREME_RECV, "%s(exit): rx_prod = 0x%04X, "
6229157642Sps		"rx_cons = 0x%04X, rx_prod_bseq = 0x%08X\n",
6230178132Sdavidch		__FUNCTION__, sc->rx_prod, sc->rx_cons, sc->rx_prod_bseq);
6231179771Sdavidch	DBEXIT(BCE_VERBOSE_RECV | BCE_VERBOSE_INTR);
6232157642Sps}
6233157642Sps
6234157642Sps
6235157642Sps/****************************************************************************/
6236178132Sdavidch/* Reads the transmit consumer value from the status block (skipping over   */
6237178132Sdavidch/* chain page pointer if necessary).                                        */
6238178132Sdavidch/*                                                                          */
6239178132Sdavidch/* Returns:                                                                 */
6240178132Sdavidch/*   hw_cons                                                                */
6241178132Sdavidch/****************************************************************************/
6242178132Sdavidchstatic inline u16
6243178132Sdavidchbce_get_hw_tx_cons(struct bce_softc *sc)
6244178132Sdavidch{
6245182293Sdavidch	u16 hw_cons;
6246178132Sdavidch
6247182293Sdavidch	mb();
6248182293Sdavidch	hw_cons = sc->status_block->status_tx_quick_consumer_index0;
6249178132Sdavidch	if ((hw_cons & USABLE_TX_BD_PER_PAGE) == USABLE_TX_BD_PER_PAGE)
6250178132Sdavidch		hw_cons++;
6251178132Sdavidch
6252178132Sdavidch	return hw_cons;
6253178132Sdavidch}
6254178132Sdavidch
6255178132Sdavidch
6256178132Sdavidch/****************************************************************************/
6257157642Sps/* Handles transmit completion interrupt events.                            */
6258157642Sps/*                                                                          */
6259157642Sps/* Returns:                                                                 */
6260157642Sps/*   Nothing.                                                               */
6261157642Sps/****************************************************************************/
6262157642Spsstatic void
6263157642Spsbce_tx_intr(struct bce_softc *sc)
6264157642Sps{
6265157642Sps	struct ifnet *ifp = sc->bce_ifp;
6266157642Sps	u16 hw_tx_cons, sw_tx_cons, sw_tx_chain_cons;
6267178132Sdavidch
6268179771Sdavidch	DBENTER(BCE_VERBOSE_SEND | BCE_VERBOSE_INTR);
6269179771Sdavidch	DBRUN(sc->tx_interrupts++);
6270179771Sdavidch	DBPRINT(sc, BCE_EXTREME_SEND, "%s(enter): tx_prod = 0x%04X, "
6271179771Sdavidch		"tx_cons = 0x%04X, tx_prod_bseq = 0x%08X\n",
6272179771Sdavidch		__FUNCTION__, sc->tx_prod, sc->tx_cons, sc->tx_prod_bseq);
6273157642Sps
6274157642Sps	BCE_LOCK_ASSERT(sc);
6275157642Sps
6276157642Sps	/* Get the hardware's view of the TX consumer index. */
6277178132Sdavidch	hw_tx_cons = sc->hw_tx_cons = bce_get_hw_tx_cons(sc);
6278157642Sps	sw_tx_cons = sc->tx_cons;
6279157642Sps
6280157642Sps	/* Prevent speculative reads from getting ahead of the status block. */
6281179771Sdavidch	bus_space_barrier(sc->bce_btag, sc->bce_bhandle, 0, 0,
6282157642Sps		BUS_SPACE_BARRIER_READ);
6283157642Sps
6284157642Sps	/* Cycle through any completed TX chain page entries. */
6285157642Sps	while (sw_tx_cons != hw_tx_cons) {
6286157642Sps#ifdef BCE_DEBUG
6287157642Sps		struct tx_bd *txbd = NULL;
6288157642Sps#endif
6289157642Sps		sw_tx_chain_cons = TX_CHAIN_IDX(sw_tx_cons);
6290157642Sps
6291157642Sps		DBPRINT(sc, BCE_INFO_SEND,
6292157642Sps			"%s(): hw_tx_cons = 0x%04X, sw_tx_cons = 0x%04X, "
6293157642Sps			"sw_tx_chain_cons = 0x%04X\n",
6294157642Sps			__FUNCTION__, hw_tx_cons, sw_tx_cons, sw_tx_chain_cons);
6295157642Sps
6296157642Sps		DBRUNIF((sw_tx_chain_cons > MAX_TX_BD),
6297169271Sdavidch			BCE_PRINTF("%s(%d): TX chain consumer out of range! "
6298179771Sdavidch				" 0x%04X > 0x%04X\n", __FILE__, __LINE__, sw_tx_chain_cons,
6299157642Sps				(int) MAX_TX_BD);
6300157642Sps			bce_breakpoint(sc));
6301157642Sps
6302176448Sdavidch		DBRUN(txbd = &sc->tx_bd_chain[TX_PAGE(sw_tx_chain_cons)]
6303157642Sps				[TX_IDX(sw_tx_chain_cons)]);
6304179771Sdavidch
6305157642Sps		DBRUNIF((txbd == NULL),
6306179771Sdavidch			BCE_PRINTF("%s(%d): Unexpected NULL tx_bd[0x%04X]!\n",
6307157642Sps				__FILE__, __LINE__, sw_tx_chain_cons);
6308157642Sps			bce_breakpoint(sc));
6309157642Sps
6310176448Sdavidch		DBRUNMSG(BCE_INFO_SEND, BCE_PRINTF("%s(): ", __FUNCTION__);
6311157642Sps			bce_dump_txbd(sc, sw_tx_chain_cons, txbd));
6312157642Sps
6313157642Sps		/*
6314157642Sps		 * Free the associated mbuf. Remember
6315157642Sps		 * that only the last tx_bd of a packet
6316157642Sps		 * has an mbuf pointer and DMA map.
6317157642Sps		 */
6318157642Sps		if (sc->tx_mbuf_ptr[sw_tx_chain_cons] != NULL) {
6319157642Sps
6320157642Sps			/* Validate that this is the last tx_bd. */
6321164329Sscottl			DBRUNIF((!(txbd->tx_bd_flags & TX_BD_FLAGS_END)),
6322169271Sdavidch				BCE_PRINTF("%s(%d): tx_bd END flag not set but "
6323157642Sps				"txmbuf == NULL!\n", __FILE__, __LINE__);
6324157642Sps				bce_breakpoint(sc));
6325157642Sps
6326179771Sdavidch			DBRUNMSG(BCE_INFO_SEND,
6327169271Sdavidch				BCE_PRINTF("%s(): Unloading map/freeing mbuf "
6328157642Sps					"from tx_bd[0x%04X]\n", __FUNCTION__, sw_tx_chain_cons));
6329157642Sps
6330157642Sps			/* Unmap the mbuf. */
6331157642Sps			bus_dmamap_unload(sc->tx_mbuf_tag,
6332157642Sps			    sc->tx_mbuf_map[sw_tx_chain_cons]);
6333179771Sdavidch
6334157642Sps			/* Free the mbuf. */
6335157642Sps			m_freem(sc->tx_mbuf_ptr[sw_tx_chain_cons]);
6336157642Sps			sc->tx_mbuf_ptr[sw_tx_chain_cons] = NULL;
6337176448Sdavidch			DBRUN(sc->debug_tx_mbuf_alloc--);
6338157642Sps
6339157642Sps			ifp->if_opackets++;
6340157642Sps		}
6341157642Sps
6342157642Sps		sc->used_tx_bd--;
6343157642Sps		sw_tx_cons = NEXT_TX_BD(sw_tx_cons);
6344157642Sps
6345157642Sps		/* Refresh hw_cons to see if there's new work. */
6346178132Sdavidch		hw_tx_cons = sc->hw_tx_cons = bce_get_hw_tx_cons(sc);
6347157642Sps
6348157642Sps		/* Prevent speculative reads from getting ahead of the status block. */
6349179771Sdavidch		bus_space_barrier(sc->bce_btag, sc->bce_bhandle, 0, 0,
6350157642Sps			BUS_SPACE_BARRIER_READ);
6351157642Sps	}
6352157642Sps
6353157642Sps	/* Clear the TX timeout timer. */
6354165933Sdelphij	sc->watchdog_timer = 0;
6355157642Sps
6356157642Sps	/* Clear the tx hardware queue full flag. */
6357169632Sdavidch	if (sc->used_tx_bd < sc->max_tx_bd) {
6358169632Sdavidch		DBRUNIF((ifp->if_drv_flags & IFF_DRV_OACTIVE),
6359179771Sdavidch			DBPRINT(sc, BCE_INFO_SEND,
6360179771Sdavidch				"%s(): Open TX chain! %d/%d (used/total)\n",
6361169632Sdavidch				__FUNCTION__, sc->used_tx_bd, sc->max_tx_bd));
6362157642Sps		ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
6363157642Sps	}
6364157642Sps
6365157642Sps	sc->tx_cons = sw_tx_cons;
6366179771Sdavidch
6367179771Sdavidch	DBPRINT(sc, BCE_EXTREME_SEND, "%s(exit): tx_prod = 0x%04X, "
6368179771Sdavidch		"tx_cons = 0x%04X, tx_prod_bseq = 0x%08X\n",
6369179771Sdavidch		__FUNCTION__, sc->tx_prod, sc->tx_cons, sc->tx_prod_bseq);
6370179771Sdavidch	DBEXIT(BCE_VERBOSE_SEND | BCE_VERBOSE_INTR);
6371157642Sps}
6372157642Sps
6373157642Sps
6374157642Sps/****************************************************************************/
6375157642Sps/* Disables interrupt generation.                                           */
6376157642Sps/*                                                                          */
6377157642Sps/* Returns:                                                                 */
6378157642Sps/*   Nothing.                                                               */
6379157642Sps/****************************************************************************/
6380157642Spsstatic void
6381157642Spsbce_disable_intr(struct bce_softc *sc)
6382157642Sps{
6383179771Sdavidch	DBENTER(BCE_VERBOSE_INTR);
6384179771Sdavidch
6385179771Sdavidch	REG_WR(sc, BCE_PCICFG_INT_ACK_CMD, BCE_PCICFG_INT_ACK_CMD_MASK_INT);
6386157642Sps	REG_RD(sc, BCE_PCICFG_INT_ACK_CMD);
6387179771Sdavidch
6388179771Sdavidch	DBEXIT(BCE_VERBOSE_INTR);
6389157642Sps}
6390157642Sps
6391157642Sps
6392157642Sps/****************************************************************************/
6393157642Sps/* Enables interrupt generation.                                            */
6394157642Sps/*                                                                          */
6395157642Sps/* Returns:                                                                 */
6396157642Sps/*   Nothing.                                                               */
6397157642Sps/****************************************************************************/
6398157642Spsstatic void
6399179771Sdavidchbce_enable_intr(struct bce_softc *sc, int coal_now)
6400157642Sps{
6401179771Sdavidch	DBENTER(BCE_VERBOSE_INTR);
6402157642Sps
6403157642Sps	REG_WR(sc, BCE_PCICFG_INT_ACK_CMD,
6404157642Sps	       BCE_PCICFG_INT_ACK_CMD_INDEX_VALID |
6405157642Sps	       BCE_PCICFG_INT_ACK_CMD_MASK_INT | sc->last_status_idx);
6406157642Sps
6407157642Sps	REG_WR(sc, BCE_PCICFG_INT_ACK_CMD,
6408157642Sps	       BCE_PCICFG_INT_ACK_CMD_INDEX_VALID | sc->last_status_idx);
6409157642Sps
6410179771Sdavidch	/* Force an immediate interrupt (whether there is new data or not). */
6411179771Sdavidch	if (coal_now)
6412179771Sdavidch		REG_WR(sc, BCE_HC_COMMAND, sc->hc_command | BCE_HC_COMMAND_COAL_NOW);
6413179771Sdavidch
6414179771Sdavidch	DBEXIT(BCE_VERBOSE_INTR);
6415157642Sps}
6416157642Sps
6417157642Sps
6418157642Sps/****************************************************************************/
6419157642Sps/* Handles controller initialization.                                       */
6420157642Sps/*                                                                          */
6421157642Sps/* Returns:                                                                 */
6422157642Sps/*   Nothing.                                                               */
6423157642Sps/****************************************************************************/
6424157642Spsstatic void
6425157642Spsbce_init_locked(struct bce_softc *sc)
6426157642Sps{
6427157642Sps	struct ifnet *ifp;
6428176448Sdavidch	u32 ether_mtu = 0;
6429157642Sps
6430179771Sdavidch	DBENTER(BCE_VERBOSE_RESET);
6431157642Sps
6432157642Sps	BCE_LOCK_ASSERT(sc);
6433157642Sps
6434157642Sps	ifp = sc->bce_ifp;
6435157642Sps
6436157642Sps	/* Check if the driver is still running and bail out if it is. */
6437157642Sps	if (ifp->if_drv_flags & IFF_DRV_RUNNING)
6438157642Sps		goto bce_init_locked_exit;
6439157642Sps
6440157642Sps	bce_stop(sc);
6441157642Sps
6442157642Sps	if (bce_reset(sc, BCE_DRV_MSG_CODE_RESET)) {
6443179771Sdavidch		BCE_PRINTF("%s(%d): Controller reset failed!\n",
6444157642Sps			__FILE__, __LINE__);
6445157642Sps		goto bce_init_locked_exit;
6446157642Sps	}
6447157642Sps
6448157642Sps	if (bce_chipinit(sc)) {
6449179771Sdavidch		BCE_PRINTF("%s(%d): Controller initialization failed!\n",
6450157642Sps			__FILE__, __LINE__);
6451157642Sps		goto bce_init_locked_exit;
6452157642Sps	}
6453157642Sps
6454157642Sps	if (bce_blockinit(sc)) {
6455179771Sdavidch		BCE_PRINTF("%s(%d): Block initialization failed!\n",
6456157642Sps			__FILE__, __LINE__);
6457157642Sps		goto bce_init_locked_exit;
6458157642Sps	}
6459157642Sps
6460157642Sps	/* Load our MAC address. */
6461157642Sps	bcopy(IF_LLADDR(sc->bce_ifp), sc->eaddr, ETHER_ADDR_LEN);
6462157642Sps	bce_set_mac_addr(sc);
6463157642Sps
6464182293Sdavidch	/*
6465182293Sdavidch	 * Calculate and program the hardware Ethernet MTU
6466179771Sdavidch	 * size. Be generous on the receive if we have room.
6467179695Sdavidch	 */
6468198320Sstas#ifdef BCE_JUMBO_HDRSPLIT
6469179695Sdavidch	if (ifp->if_mtu <= (sc->rx_bd_mbuf_data_len + sc->pg_bd_mbuf_alloc_size))
6470179695Sdavidch		ether_mtu = sc->rx_bd_mbuf_data_len + sc->pg_bd_mbuf_alloc_size;
6471179771Sdavidch#else
6472179695Sdavidch	if (ifp->if_mtu <= sc->rx_bd_mbuf_data_len)
6473179695Sdavidch		ether_mtu = sc->rx_bd_mbuf_data_len;
6474179695Sdavidch#endif
6475178132Sdavidch	else
6476179771Sdavidch		ether_mtu = ifp->if_mtu;
6477178132Sdavidch
6478176448Sdavidch	ether_mtu += ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN + ETHER_CRC_LEN;
6479157642Sps
6480179771Sdavidch	DBPRINT(sc, BCE_INFO_MISC, "%s(): setting h/w mtu = %d\n", __FUNCTION__,
6481176448Sdavidch		ether_mtu);
6482157642Sps
6483176448Sdavidch	/* Program the mtu, enabling jumbo frame support if necessary. */
6484176448Sdavidch	if (ether_mtu > (ETHER_MAX_LEN + ETHER_VLAN_ENCAP_LEN))
6485179771Sdavidch		REG_WR(sc, BCE_EMAC_RX_MTU_SIZE,
6486179771Sdavidch			min(ether_mtu, BCE_MAX_JUMBO_ETHER_MTU) |
6487157642Sps			BCE_EMAC_RX_MTU_SIZE_JUMBO_ENA);
6488176448Sdavidch	else
6489157642Sps		REG_WR(sc, BCE_EMAC_RX_MTU_SIZE, ether_mtu);
6490157642Sps
6491182293Sdavidch	DBPRINT(sc, BCE_INFO_LOAD,
6492179771Sdavidch		"%s(): rx_bd_mbuf_alloc_size = %d, rx_bce_mbuf_data_len = %d, "
6493189325Sdavidch		"rx_bd_mbuf_align_pad = %d\n", __FUNCTION__,
6494189325Sdavidch		sc->rx_bd_mbuf_alloc_size, sc->rx_bd_mbuf_data_len,
6495189325Sdavidch		sc->rx_bd_mbuf_align_pad);
6496157642Sps
6497157642Sps	/* Program appropriate promiscuous/multicast filtering. */
6498157642Sps	bce_set_rx_mode(sc);
6499157642Sps
6500198320Sstas#ifdef BCE_JUMBO_HDRSPLIT
6501189325Sdavidch	DBPRINT(sc, BCE_INFO_LOAD, "%s(): pg_bd_mbuf_alloc_size = %d\n",
6502189325Sdavidch		__FUNCTION__, sc->pg_bd_mbuf_alloc_size);
6503189325Sdavidch
6504176448Sdavidch	/* Init page buffer descriptor chain. */
6505179771Sdavidch	bce_init_pg_chain(sc);
6506179695Sdavidch#endif
6507176448Sdavidch
6508157642Sps	/* Init RX buffer descriptor chain. */
6509157642Sps	bce_init_rx_chain(sc);
6510179771Sdavidch
6511157642Sps	/* Init TX buffer descriptor chain. */
6512157642Sps	bce_init_tx_chain(sc);
6513157642Sps
6514157642Sps	/* Enable host interrupts. */
6515179771Sdavidch	bce_enable_intr(sc, 1);
6516157642Sps
6517165994Sjhb	bce_ifmedia_upd_locked(ifp);
6518157642Sps
6519202717Sdavidch	/* Let the OS know the driver is up and running. */
6520157642Sps	ifp->if_drv_flags |= IFF_DRV_RUNNING;
6521157642Sps	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
6522157642Sps
6523170810Sdavidch	callout_reset(&sc->bce_tick_callout, hz, bce_tick, sc);
6524157642Sps
6525157642Spsbce_init_locked_exit:
6526179771Sdavidch	DBEXIT(BCE_VERBOSE_RESET);
6527157642Sps}
6528157642Sps
6529170392Sdavidch
6530169271Sdavidch/****************************************************************************/
6531170392Sdavidch/* Initialize the controller just enough so that any management firmware    */
6532170810Sdavidch/* running on the device will continue to operate correctly.                */
6533169271Sdavidch/*                                                                          */
6534169271Sdavidch/* Returns:                                                                 */
6535169271Sdavidch/*   Nothing.                                                               */
6536169271Sdavidch/****************************************************************************/
6537162474Sambriskostatic void
6538162474Sambriskobce_mgmt_init_locked(struct bce_softc *sc)
6539162474Sambrisko{
6540162474Sambrisko	struct ifnet *ifp;
6541157642Sps
6542179771Sdavidch	DBENTER(BCE_VERBOSE_RESET);
6543162474Sambrisko
6544162474Sambrisko	BCE_LOCK_ASSERT(sc);
6545162474Sambrisko
6546170810Sdavidch	/* Bail out if management firmware is not running. */
6547170810Sdavidch	if (!(sc->bce_flags & BCE_MFW_ENABLE_FLAG)) {
6548179771Sdavidch		DBPRINT(sc, BCE_VERBOSE_SPECIAL,
6549170810Sdavidch			"No management firmware running...\n");
6550162474Sambrisko		goto bce_mgmt_init_locked_exit;
6551170810Sdavidch	}
6552162474Sambrisko
6553170810Sdavidch	ifp = sc->bce_ifp;
6554162474Sambrisko
6555162474Sambrisko	/* Enable all critical blocks in the MAC. */
6556179771Sdavidch	REG_WR(sc, BCE_MISC_ENABLE_SET_BITS, BCE_MISC_ENABLE_DEFAULT);
6557162474Sambrisko	REG_RD(sc, BCE_MISC_ENABLE_SET_BITS);
6558162474Sambrisko	DELAY(20);
6559162474Sambrisko
6560165994Sjhb	bce_ifmedia_upd_locked(ifp);
6561179771Sdavidch
6562162474Sambriskobce_mgmt_init_locked_exit:
6563179771Sdavidch	DBEXIT(BCE_VERBOSE_RESET);
6564162474Sambrisko}
6565162474Sambrisko
6566162474Sambrisko
6567157642Sps/****************************************************************************/
6568157642Sps/* Handles controller initialization when called from an unlocked routine.  */
6569157642Sps/*                                                                          */
6570157642Sps/* Returns:                                                                 */
6571157642Sps/*   Nothing.                                                               */
6572157642Sps/****************************************************************************/
6573157642Spsstatic void
6574157642Spsbce_init(void *xsc)
6575157642Sps{
6576178132Sdavidch	struct bce_softc *sc = xsc;
6577157642Sps
6578179771Sdavidch	DBENTER(BCE_VERBOSE_RESET);
6579179771Sdavidch
6580157642Sps	BCE_LOCK(sc);
6581157642Sps	bce_init_locked(sc);
6582157642Sps	BCE_UNLOCK(sc);
6583179771Sdavidch
6584179771Sdavidch	DBEXIT(BCE_VERBOSE_RESET);
6585157642Sps}
6586157642Sps
6587157642Sps
6588157642Sps/****************************************************************************/
6589157642Sps/* Encapsultes an mbuf cluster into the tx_bd chain structure and makes the */
6590157642Sps/* memory visible to the controller.                                        */
6591157642Sps/*                                                                          */
6592157642Sps/* Returns:                                                                 */
6593157642Sps/*   0 for success, positive value for failure.                             */
6594171667Sdavidch/* Modified:                                                                */
6595171667Sdavidch/*   m_head: May be set to NULL if MBUF is excessively fragmented.          */
6596157642Sps/****************************************************************************/
6597157642Spsstatic int
6598163393Sscottlbce_tx_encap(struct bce_softc *sc, struct mbuf **m_head)
6599157642Sps{
6600163393Sscottl	bus_dma_segment_t segs[BCE_MAX_SEGMENTS];
6601163393Sscottl	bus_dmamap_t map;
6602163393Sscottl	struct tx_bd *txbd = NULL;
6603163393Sscottl	struct mbuf *m0;
6604169632Sdavidch	struct ether_vlan_header *eh;
6605169632Sdavidch	struct ip *ip;
6606169632Sdavidch	struct tcphdr *th;
6607169632Sdavidch	u16 prod, chain_prod, etype, mss = 0, vlan_tag = 0, flags = 0;
6608170392Sdavidch	u32 prod_bseq;
6609170392Sdavidch	int hdr_len = 0, e_hlen = 0, ip_hlen = 0, tcp_hlen = 0, ip_len = 0;
6610157642Sps
6611163393Sscottl#ifdef BCE_DEBUG
6612163393Sscottl	u16 debug_prod;
6613163393Sscottl#endif
6614163393Sscottl	int i, error, nsegs, rc = 0;
6615163393Sscottl
6616179771Sdavidch	DBENTER(BCE_VERBOSE_SEND);
6617179771Sdavidch	DBPRINT(sc, BCE_INFO_SEND,
6618179771Sdavidch		"%s(enter): tx_prod = 0x%04X, tx_chain_prod = %04X, "
6619179771Sdavidch		"tx_prod_bseq = 0x%08X\n",
6620179771Sdavidch		__FUNCTION__, sc->tx_prod, (u16) TX_CHAIN_IDX(sc->tx_prod),
6621179771Sdavidch		sc->tx_prod_bseq);
6622179771Sdavidch
6623157642Sps	/* Transfer any checksum offload flags to the bd. */
6624163393Sscottl	m0 = *m_head;
6625163393Sscottl	if (m0->m_pkthdr.csum_flags) {
6626163393Sscottl		if (m0->m_pkthdr.csum_flags & CSUM_IP)
6627164329Sscottl			flags |= TX_BD_FLAGS_IP_CKSUM;
6628163393Sscottl		if (m0->m_pkthdr.csum_flags & (CSUM_TCP | CSUM_UDP))
6629170392Sdavidch			flags |= TX_BD_FLAGS_TCP_UDP_CKSUM;
6630170392Sdavidch		if (m0->m_pkthdr.csum_flags & CSUM_TSO) {
6631170392Sdavidch			/* For TSO the controller needs two pieces of info, */
6632170392Sdavidch			/* the MSS and the IP+TCP options length.           */
6633170392Sdavidch			mss = htole16(m0->m_pkthdr.tso_segsz);
6634170392Sdavidch
6635169632Sdavidch			/* Map the header and find the Ethernet type & header length */
6636169632Sdavidch			eh = mtod(m0, struct ether_vlan_header *);
6637169632Sdavidch			if (eh->evl_encap_proto == htons(ETHERTYPE_VLAN)) {
6638169632Sdavidch				etype = ntohs(eh->evl_proto);
6639169632Sdavidch				e_hlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN;
6640169632Sdavidch			} else {
6641169632Sdavidch				etype = ntohs(eh->evl_encap_proto);
6642169632Sdavidch				e_hlen = ETHER_HDR_LEN;
6643170392Sdavidch			}
6644170392Sdavidch
6645170392Sdavidch			/* Check for supported TSO Ethernet types (only IPv4 for now) */
6646169632Sdavidch			switch (etype) {
6647169632Sdavidch				case ETHERTYPE_IP:
6648169632Sdavidch					ip = (struct ip *)(m0->m_data + e_hlen);
6649170392Sdavidch
6650170392Sdavidch					/* TSO only supported for TCP protocol */
6651169632Sdavidch					if (ip->ip_p != IPPROTO_TCP) {
6652169632Sdavidch						BCE_PRINTF("%s(%d): TSO enabled for non-TCP frame!.\n",
6653170392Sdavidch							__FILE__, __LINE__);
6654170392Sdavidch						goto bce_tx_encap_skip_tso;
6655169632Sdavidch					}
6656179771Sdavidch
6657170392Sdavidch					/* Get IP header length in bytes (min 20) */
6658170392Sdavidch					ip_hlen = ip->ip_hl << 2;
6659170392Sdavidch
6660170392Sdavidch					/* Get the TCP header length in bytes (min 20) */
6661169632Sdavidch					th = (struct tcphdr *)((caddr_t)ip + ip_hlen);
6662170392Sdavidch					tcp_hlen = (th->th_off << 2);
6663170392Sdavidch
6664170392Sdavidch					/* IP header length and checksum will be calc'd by hardware */
6665170392Sdavidch					ip_len = ip->ip_len;
6666170392Sdavidch					ip->ip_len = 0;
6667169632Sdavidch					ip->ip_sum = 0;
6668169632Sdavidch					break;
6669169632Sdavidch				case ETHERTYPE_IPV6:
6670169632Sdavidch					BCE_PRINTF("%s(%d): TSO over IPv6 not supported!.\n",
6671170392Sdavidch						__FILE__, __LINE__);
6672170392Sdavidch					goto bce_tx_encap_skip_tso;
6673169632Sdavidch				default:
6674169632Sdavidch					BCE_PRINTF("%s(%d): TSO enabled for unsupported protocol!.\n",
6675170392Sdavidch						__FILE__, __LINE__);
6676170392Sdavidch					goto bce_tx_encap_skip_tso;
6677169632Sdavidch			}
6678170392Sdavidch
6679169632Sdavidch			hdr_len = e_hlen + ip_hlen + tcp_hlen;
6680169632Sdavidch
6681179771Sdavidch			DBPRINT(sc, BCE_EXTREME_SEND,
6682170392Sdavidch				"%s(): hdr_len = %d, e_hlen = %d, ip_hlen = %d, tcp_hlen = %d, ip_len = %d\n",
6683170392Sdavidch				 __FUNCTION__, hdr_len, e_hlen, ip_hlen, tcp_hlen, ip_len);
6684170392Sdavidch
6685170392Sdavidch			/* Set the LSO flag in the TX BD */
6686170392Sdavidch			flags |= TX_BD_FLAGS_SW_LSO;
6687170392Sdavidch			/* Set the length of IP + TCP options (in 32 bit words) */
6688170392Sdavidch			flags |= (((ip_hlen + tcp_hlen - 40) >> 2) << 8);
6689170392Sdavidch
6690170392Sdavidchbce_tx_encap_skip_tso:
6691176448Sdavidch			DBRUN(sc->requested_tso_frames++);
6692169632Sdavidch		}
6693157642Sps	}
6694157642Sps
6695157642Sps	/* Transfer any VLAN tags to the bd. */
6696164329Sscottl	if (m0->m_flags & M_VLANTAG) {
6697164329Sscottl		flags |= TX_BD_FLAGS_VLAN_TAG;
6698164329Sscottl		vlan_tag = m0->m_pkthdr.ether_vtag;
6699164329Sscottl	}
6700157642Sps
6701157642Sps	/* Map the mbuf into DMAable memory. */
6702163393Sscottl	prod = sc->tx_prod;
6703163393Sscottl	chain_prod = TX_CHAIN_IDX(prod);
6704163339Sscottl	map = sc->tx_mbuf_map[chain_prod];
6705157642Sps
6706157642Sps	/* Map the mbuf into our DMA address space. */
6707163393Sscottl	error = bus_dmamap_load_mbuf_sg(sc->tx_mbuf_tag, map, m0,
6708163393Sscottl	    segs, &nsegs, BUS_DMA_NOWAIT);
6709157642Sps
6710170392Sdavidch	/* Check if the DMA mapping was successful */
6711163393Sscottl	if (error == EFBIG) {
6712179771Sdavidch
6713189325Sdavidch		sc->fragmented_mbuf_count++;
6714170392Sdavidch
6715171667Sdavidch		/* Try to defrag the mbuf. */
6716169632Sdavidch		m0 = m_defrag(*m_head, M_DONTWAIT);
6717171667Sdavidch		if (m0 == NULL) {
6718169632Sdavidch			/* Defrag was unsuccessful */
6719163499Sscottl			m_freem(*m_head);
6720163499Sscottl			*m_head = NULL;
6721189325Sdavidch			sc->mbuf_alloc_failed_count++;
6722179771Sdavidch			rc = ENOBUFS;
6723179771Sdavidch			goto bce_tx_encap_exit;
6724163499Sscottl		}
6725159411Sdavidch
6726170392Sdavidch		/* Defrag was successful, try mapping again */
6727163499Sscottl		*m_head = m0;
6728163499Sscottl		error = bus_dmamap_load_mbuf_sg(sc->tx_mbuf_tag, map, m0,
6729163499Sscottl		    segs, &nsegs, BUS_DMA_NOWAIT);
6730163499Sscottl
6731163393Sscottl		/* Still getting an error after a defrag. */
6732163499Sscottl		if (error == ENOMEM) {
6733171667Sdavidch			/* Insufficient DMA buffers available. */
6734189325Sdavidch			sc->dma_map_addr_tx_failed_count++;
6735179771Sdavidch			rc = error;
6736179771Sdavidch			goto bce_tx_encap_exit;
6737163499Sscottl		} else if (error != 0) {
6738171667Sdavidch			/* Still can't map the mbuf, release it and return an error. */
6739169271Sdavidch			BCE_PRINTF(
6740169632Sdavidch			    "%s(%d): Unknown error mapping mbuf into TX chain!\n",
6741163393Sscottl			    __FILE__, __LINE__);
6742163499Sscottl			m_freem(m0);
6743163499Sscottl			*m_head = NULL;
6744189325Sdavidch			sc->dma_map_addr_tx_failed_count++;
6745179771Sdavidch			rc = ENOBUFS;
6746179771Sdavidch			goto bce_tx_encap_exit;
6747163393Sscottl		}
6748163499Sscottl	} else if (error == ENOMEM) {
6749171667Sdavidch		/* Insufficient DMA buffers available. */
6750189325Sdavidch		sc->dma_map_addr_tx_failed_count++;
6751179771Sdavidch		rc = error;
6752179771Sdavidch		goto bce_tx_encap_exit;
6753163499Sscottl	} else if (error != 0) {
6754163499Sscottl		m_freem(m0);
6755163499Sscottl		*m_head = NULL;
6756189325Sdavidch		sc->dma_map_addr_tx_failed_count++;
6757179771Sdavidch		rc = error;
6758179771Sdavidch		goto bce_tx_encap_exit;
6759163499Sscottl	}
6760170392Sdavidch
6761169632Sdavidch	/* Make sure there's room in the chain */
6762169632Sdavidch	if (nsegs > (sc->max_tx_bd - sc->used_tx_bd)) {
6763163558Sscottl		bus_dmamap_unload(sc->tx_mbuf_tag, map);
6764179771Sdavidch		rc = ENOBUFS;
6765179771Sdavidch		goto bce_tx_encap_exit;
6766163558Sscottl	}
6767163393Sscottl
6768163393Sscottl	/* prod points to an empty tx_bd at this point. */
6769163393Sscottl	prod_bseq  = sc->tx_prod_bseq;
6770163393Sscottl
6771163393Sscottl#ifdef BCE_DEBUG
6772163393Sscottl	debug_prod = chain_prod;
6773163393Sscottl#endif
6774163393Sscottl
6775163393Sscottl	DBPRINT(sc, BCE_INFO_SEND,
6776178132Sdavidch		"%s(start): prod = 0x%04X, chain_prod = 0x%04X, "
6777163393Sscottl		"prod_bseq = 0x%08X\n",
6778164968Sjhb		__FUNCTION__, prod, chain_prod, prod_bseq);
6779163393Sscottl
6780163393Sscottl	/*
6781163393Sscottl	 * Cycle through each mbuf segment that makes up
6782163393Sscottl	 * the outgoing frame, gathering the mapping info
6783176448Sdavidch	 * for that segment and creating a tx_bd for
6784163393Sscottl	 * the mbuf.
6785163393Sscottl	 */
6786163393Sscottl	for (i = 0; i < nsegs ; i++) {
6787163393Sscottl
6788163393Sscottl		chain_prod = TX_CHAIN_IDX(prod);
6789163393Sscottl		txbd= &sc->tx_bd_chain[TX_PAGE(chain_prod)][TX_IDX(chain_prod)];
6790163393Sscottl
6791163393Sscottl		txbd->tx_bd_haddr_lo = htole32(BCE_ADDR_LO(segs[i].ds_addr));
6792163393Sscottl		txbd->tx_bd_haddr_hi = htole32(BCE_ADDR_HI(segs[i].ds_addr));
6793169632Sdavidch		txbd->tx_bd_mss_nbytes = htole32(mss << 16) | htole16(segs[i].ds_len);
6794164329Sscottl		txbd->tx_bd_vlan_tag = htole16(vlan_tag);
6795164329Sscottl		txbd->tx_bd_flags = htole16(flags);
6796163393Sscottl		prod_bseq += segs[i].ds_len;
6797163393Sscottl		if (i == 0)
6798170392Sdavidch			txbd->tx_bd_flags |= htole16(TX_BD_FLAGS_START);
6799163393Sscottl		prod = NEXT_TX_BD(prod);
6800157642Sps	}
6801157642Sps
6802163393Sscottl	/* Set the END flag on the last TX buffer descriptor. */
6803164329Sscottl	txbd->tx_bd_flags |= htole16(TX_BD_FLAGS_END);
6804163393Sscottl
6805179771Sdavidch	DBRUNMSG(BCE_EXTREME_SEND, bce_dump_tx_chain(sc, debug_prod, nsegs));
6806163393Sscottl
6807163393Sscottl	DBPRINT(sc, BCE_INFO_SEND,
6808178132Sdavidch		"%s( end ): prod = 0x%04X, chain_prod = 0x%04X, "
6809163393Sscottl		"prod_bseq = 0x%08X\n",
6810163393Sscottl		__FUNCTION__, prod, chain_prod, prod_bseq);
6811163393Sscottl
6812157642Sps	/*
6813164327Sjdp	 * Ensure that the mbuf pointer for this transmission
6814157642Sps	 * is placed at the array index of the last
6815157642Sps	 * descriptor in this chain.  This is done
6816179771Sdavidch	 * because a single map is used for all
6817157642Sps	 * segments of the mbuf and we don't want to
6818164327Sjdp	 * unload the map before all of the segments
6819157642Sps	 * have been freed.
6820157642Sps	 */
6821163393Sscottl	sc->tx_mbuf_ptr[chain_prod] = m0;
6822163393Sscottl	sc->used_tx_bd += nsegs;
6823157642Sps
6824170392Sdavidch	/* Update some debug statistic counters */
6825179771Sdavidch	DBRUNIF((sc->used_tx_bd > sc->tx_hi_watermark),
6826170392Sdavidch		sc->tx_hi_watermark = sc->used_tx_bd);
6827169632Sdavidch	DBRUNIF((sc->used_tx_bd == sc->max_tx_bd), sc->tx_full_count++);
6828176448Sdavidch	DBRUNIF(sc->debug_tx_mbuf_alloc++);
6829157642Sps
6830179771Sdavidch	DBRUNMSG(BCE_EXTREME_SEND, bce_dump_tx_mbuf_chain(sc, chain_prod, 1));
6831157642Sps
6832164327Sjdp	/* prod points to the next free tx_bd at this point. */
6833163393Sscottl	sc->tx_prod = prod;
6834163393Sscottl	sc->tx_prod_bseq = prod_bseq;
6835157642Sps
6836179771Sdavidch	DBPRINT(sc, BCE_INFO_SEND,
6837179771Sdavidch		"%s(exit): prod = 0x%04X, chain_prod = %04X, "
6838179771Sdavidch		"prod_bseq = 0x%08X\n",
6839179771Sdavidch		__FUNCTION__, sc->tx_prod, (u16) TX_CHAIN_IDX(sc->tx_prod),
6840179771Sdavidch		sc->tx_prod_bseq);
6841179771Sdavidch
6842179771Sdavidchbce_tx_encap_exit:
6843179771Sdavidch	DBEXIT(BCE_VERBOSE_SEND);
6844157642Sps	return(rc);
6845157642Sps}
6846157642Sps
6847157642Sps
6848157642Sps/****************************************************************************/
6849157642Sps/* Main transmit routine when called from another routine with a lock.      */
6850157642Sps/*                                                                          */
6851157642Sps/* Returns:                                                                 */
6852157642Sps/*   Nothing.                                                               */
6853157642Sps/****************************************************************************/
6854157642Spsstatic void
6855157642Spsbce_start_locked(struct ifnet *ifp)
6856157642Sps{
6857157642Sps	struct bce_softc *sc = ifp->if_softc;
6858157642Sps	struct mbuf *m_head = NULL;
6859157642Sps	int count = 0;
6860157642Sps	u16 tx_prod, tx_chain_prod;
6861157642Sps
6862179771Sdavidch	DBENTER(BCE_VERBOSE_SEND | BCE_VERBOSE_CTX);
6863179771Sdavidch
6864179771Sdavidch	BCE_LOCK_ASSERT(sc);
6865179771Sdavidch
6866157642Sps	/* prod points to the next free tx_bd. */
6867157642Sps	tx_prod = sc->tx_prod;
6868157642Sps	tx_chain_prod = TX_CHAIN_IDX(tx_prod);
6869157642Sps
6870157642Sps	DBPRINT(sc, BCE_INFO_SEND,
6871178132Sdavidch		"%s(enter): tx_prod = 0x%04X, tx_chain_prod = 0x%04X, "
6872157642Sps		"tx_prod_bseq = 0x%08X\n",
6873163339Sscottl		__FUNCTION__, tx_prod, tx_chain_prod, sc->tx_prod_bseq);
6874157642Sps
6875178132Sdavidch	/* If there's no link or the transmit queue is empty then just exit. */
6876178132Sdavidch	if (!sc->bce_link) {
6877179771Sdavidch		DBPRINT(sc, BCE_INFO_SEND, "%s(): No link.\n",
6878178132Sdavidch			__FUNCTION__);
6879178132Sdavidch		goto bce_start_locked_exit;
6880178132Sdavidch	}
6881178132Sdavidch
6882178132Sdavidch	if (IFQ_DRV_IS_EMPTY(&ifp->if_snd)) {
6883179771Sdavidch		DBPRINT(sc, BCE_INFO_SEND, "%s(): Transmit queue empty.\n",
6884178132Sdavidch			__FUNCTION__);
6885178132Sdavidch		goto bce_start_locked_exit;
6886178132Sdavidch	}
6887178132Sdavidch
6888164327Sjdp	/*
6889169632Sdavidch	 * Keep adding entries while there is space in the ring.
6890164327Sjdp	 */
6891169632Sdavidch	while (sc->used_tx_bd < sc->max_tx_bd) {
6892157642Sps
6893157642Sps		/* Check for any frames to send. */
6894157642Sps		IFQ_DRV_DEQUEUE(&ifp->if_snd, m_head);
6895179771Sdavidch
6896179771Sdavidch		/* Stop when the transmit queue is empty. */
6897157642Sps		if (m_head == NULL)
6898157642Sps			break;
6899157642Sps
6900157642Sps		/*
6901157642Sps		 * Pack the data into the transmit ring. If we
6902157642Sps		 * don't have room, place the mbuf back at the
6903157642Sps		 * head of the queue and set the OACTIVE flag
6904157642Sps		 * to wait for the NIC to drain the chain.
6905157642Sps		 */
6906163393Sscottl		if (bce_tx_encap(sc, &m_head)) {
6907179771Sdavidch			/* No room, put the frame back on the transmit queue. */
6908171667Sdavidch			if (m_head != NULL)
6909171667Sdavidch				IFQ_DRV_PREPEND(&ifp->if_snd, m_head);
6910157642Sps			ifp->if_drv_flags |= IFF_DRV_OACTIVE;
6911157642Sps			DBPRINT(sc, BCE_INFO_SEND,
6912179771Sdavidch				"TX chain is closed for business! Total tx_bd used = %d\n",
6913157642Sps				sc->used_tx_bd);
6914157642Sps			break;
6915157642Sps		}
6916157642Sps
6917157642Sps		count++;
6918157642Sps
6919157642Sps		/* Send a copy of the frame to any BPF listeners. */
6920167190Scsjp		ETHER_BPF_MTAP(ifp, m_head);
6921157642Sps	}
6922157642Sps
6923179771Sdavidch	/* Exit if no packets were dequeued. */
6924157642Sps	if (count == 0) {
6925179771Sdavidch		DBPRINT(sc, BCE_VERBOSE_SEND, "%s(): No packets were dequeued\n",
6926157642Sps			__FUNCTION__);
6927157642Sps		goto bce_start_locked_exit;
6928157642Sps	}
6929157642Sps
6930179771Sdavidch	DBPRINT(sc, BCE_VERBOSE_SEND, "%s(): Inserted %d frames into send queue.\n",
6931179771Sdavidch		__FUNCTION__, count);
6932157642Sps
6933179771Sdavidch	REG_WR(sc, BCE_MQ_COMMAND, REG_RD(sc, BCE_MQ_COMMAND) | BCE_MQ_COMMAND_NO_MAP_ERROR);
6934157642Sps
6935182293Sdavidch	/* Write the mailbox and tell the chip about the waiting tx_bd's. */
6936182293Sdavidch	DBPRINT(sc, BCE_VERBOSE_SEND, "%s(): MB_GET_CID_ADDR(TX_CID) = 0x%08X; "
6937182293Sdavidch		"BCE_L2MQ_TX_HOST_BIDX = 0x%08X, sc->tx_prod = 0x%04X\n",
6938182293Sdavidch		__FUNCTION__,
6939182293Sdavidch		MB_GET_CID_ADDR(TX_CID), BCE_L2MQ_TX_HOST_BIDX, sc->tx_prod);
6940182293Sdavidch	REG_WR16(sc, MB_GET_CID_ADDR(TX_CID) + BCE_L2MQ_TX_HOST_BIDX, sc->tx_prod);
6941182293Sdavidch	DBPRINT(sc, BCE_VERBOSE_SEND, "%s(): MB_GET_CID_ADDR(TX_CID) = 0x%08X; "
6942182293Sdavidch		"BCE_L2MQ_TX_HOST_BSEQ = 0x%08X, sc->tx_prod_bseq = 0x%04X\n",
6943182293Sdavidch		__FUNCTION__,
6944182293Sdavidch		MB_GET_CID_ADDR(TX_CID), BCE_L2MQ_TX_HOST_BSEQ, sc->tx_prod_bseq);
6945182293Sdavidch	REG_WR(sc, MB_GET_CID_ADDR(TX_CID) + BCE_L2MQ_TX_HOST_BSEQ, sc->tx_prod_bseq);
6946182293Sdavidch
6947157642Sps	/* Set the tx timeout. */
6948165933Sdelphij	sc->watchdog_timer = BCE_TX_TIMEOUT;
6949157642Sps
6950182293Sdavidch	DBRUNMSG(BCE_VERBOSE_SEND, bce_dump_ctx(sc, TX_CID));
6951179771Sdavidch	DBRUNMSG(BCE_VERBOSE_SEND, bce_dump_mq_regs(sc));
6952179771Sdavidch
6953157642Spsbce_start_locked_exit:
6954179771Sdavidch	DBEXIT(BCE_VERBOSE_SEND | BCE_VERBOSE_CTX);
6955157642Sps	return;
6956157642Sps}
6957157642Sps
6958157642Sps
6959157642Sps/****************************************************************************/
6960157642Sps/* Main transmit routine when called from another routine without a lock.   */
6961157642Sps/*                                                                          */
6962157642Sps/* Returns:                                                                 */
6963157642Sps/*   Nothing.                                                               */
6964157642Sps/****************************************************************************/
6965157642Spsstatic void
6966157642Spsbce_start(struct ifnet *ifp)
6967157642Sps{
6968157642Sps	struct bce_softc *sc = ifp->if_softc;
6969157642Sps
6970179771Sdavidch	DBENTER(BCE_VERBOSE_SEND);
6971179771Sdavidch
6972157642Sps	BCE_LOCK(sc);
6973157642Sps	bce_start_locked(ifp);
6974157642Sps	BCE_UNLOCK(sc);
6975179771Sdavidch
6976179771Sdavidch	DBEXIT(BCE_VERBOSE_SEND);
6977157642Sps}
6978157642Sps
6979157642Sps
6980157642Sps/****************************************************************************/
6981157642Sps/* Handles any IOCTL calls from the operating system.                       */
6982157642Sps/*                                                                          */
6983157642Sps/* Returns:                                                                 */
6984157642Sps/*   0 for success, positive value for failure.                             */
6985157642Sps/****************************************************************************/
6986157642Spsstatic int
6987157642Spsbce_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
6988157642Sps{
6989157642Sps	struct bce_softc *sc = ifp->if_softc;
6990157642Sps	struct ifreq *ifr = (struct ifreq *) data;
6991157642Sps	struct mii_data *mii;
6992204370Syongari	int mask, error = 0, reinit;
6993157642Sps
6994179771Sdavidch	DBENTER(BCE_VERBOSE_MISC);
6995179771Sdavidch
6996157642Sps	switch(command) {
6997157642Sps
6998170810Sdavidch		/* Set the interface MTU. */
6999157642Sps		case SIOCSIFMTU:
7000157642Sps			/* Check that the MTU setting is supported. */
7001179771Sdavidch			if ((ifr->ifr_mtu < BCE_MIN_MTU) ||
7002157642Sps				(ifr->ifr_mtu > BCE_MAX_JUMBO_MTU)) {
7003157642Sps				error = EINVAL;
7004157642Sps				break;
7005157642Sps			}
7006157642Sps
7007170810Sdavidch			DBPRINT(sc, BCE_INFO_MISC,
7008179771Sdavidch				"SIOCSIFMTU: Changing MTU from %d to %d\n",
7009170810Sdavidch				(int) ifp->if_mtu, (int) ifr->ifr_mtu);
7010157642Sps
7011160526Sjhb			BCE_LOCK(sc);
7012157642Sps			ifp->if_mtu = ifr->ifr_mtu;
7013204370Syongari			reinit = 0;
7014204370Syongari			if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
7015204370Syongari				/*
7016204370Syongari				 * Because allocation size is used in RX
7017204370Syongari				 * buffer allocation, stop controller if
7018204370Syongari				 * it is already running.
7019204370Syongari				 */
7020204370Syongari				bce_stop(sc);
7021204370Syongari				reinit = 1;
7022204370Syongari			}
7023198320Sstas#ifdef BCE_JUMBO_HDRSPLIT
7024179771Sdavidch			/* No buffer allocation size changes are necessary. */
7025179771Sdavidch#else
7026179771Sdavidch			/* Recalculate our buffer allocation sizes. */
7027179771Sdavidch			if ((ifp->if_mtu + ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN + ETHER_CRC_LEN) > MCLBYTES) {
7028179695Sdavidch				sc->rx_bd_mbuf_alloc_size = MJUM9BYTES;
7029179695Sdavidch				sc->rx_bd_mbuf_align_pad  = roundup2(MJUM9BYTES, 16) - MJUM9BYTES;
7030179771Sdavidch				sc->rx_bd_mbuf_data_len   = sc->rx_bd_mbuf_alloc_size -
7031179771Sdavidch					sc->rx_bd_mbuf_align_pad;
7032179771Sdavidch			} else {
7033179695Sdavidch				sc->rx_bd_mbuf_alloc_size = MCLBYTES;
7034179695Sdavidch				sc->rx_bd_mbuf_align_pad  = roundup2(MCLBYTES, 16) - MCLBYTES;
7035179771Sdavidch				sc->rx_bd_mbuf_data_len   = sc->rx_bd_mbuf_alloc_size -
7036179771Sdavidch					sc->rx_bd_mbuf_align_pad;
7037179695Sdavidch			}
7038179771Sdavidch#endif
7039179771Sdavidch
7040204370Syongari			if (reinit != 0)
7041204370Syongari				bce_init_locked(sc);
7042160526Sjhb			BCE_UNLOCK(sc);
7043157642Sps			break;
7044157642Sps
7045170810Sdavidch		/* Set interface flags. */
7046157642Sps		case SIOCSIFFLAGS:
7047170810Sdavidch			DBPRINT(sc, BCE_VERBOSE_SPECIAL, "Received SIOCSIFFLAGS\n");
7048157642Sps
7049157642Sps			BCE_LOCK(sc);
7050157642Sps
7051157642Sps			/* Check if the interface is up. */
7052157642Sps			if (ifp->if_flags & IFF_UP) {
7053160315Sambrisko				if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
7054170810Sdavidch					/* Change promiscuous/multicast flags as necessary. */
7055160315Sambrisko					bce_set_rx_mode(sc);
7056160315Sambrisko				} else {
7057160315Sambrisko					/* Start the HW */
7058160315Sambrisko					bce_init_locked(sc);
7059160315Sambrisko				}
7060157642Sps			} else {
7061170810Sdavidch				/* The interface is down, check if driver is running. */
7062157642Sps				if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
7063157642Sps					bce_stop(sc);
7064170810Sdavidch
7065170810Sdavidch					/* If MFW is running, restart the controller a bit. */
7066170810Sdavidch					if (sc->bce_flags & BCE_MFW_ENABLE_FLAG) {
7067170810Sdavidch						bce_reset(sc, BCE_DRV_MSG_CODE_RESET);
7068170810Sdavidch						bce_chipinit(sc);
7069170810Sdavidch						bce_mgmt_init_locked(sc);
7070170810Sdavidch					}
7071157642Sps				}
7072157642Sps			}
7073157642Sps
7074157642Sps			BCE_UNLOCK(sc);
7075157642Sps
7076157642Sps			break;
7077157642Sps
7078157642Sps		/* Add/Delete multicast address */
7079157642Sps		case SIOCADDMULTI:
7080157642Sps		case SIOCDELMULTI:
7081170810Sdavidch			DBPRINT(sc, BCE_VERBOSE_MISC, "Received SIOCADDMULTI/SIOCDELMULTI\n");
7082157642Sps
7083160526Sjhb			BCE_LOCK(sc);
7084204370Syongari			if (ifp->if_drv_flags & IFF_DRV_RUNNING)
7085157642Sps				bce_set_rx_mode(sc);
7086160526Sjhb			BCE_UNLOCK(sc);
7087157642Sps
7088157642Sps			break;
7089157642Sps
7090157642Sps		/* Set/Get Interface media */
7091157642Sps		case SIOCSIFMEDIA:
7092157642Sps		case SIOCGIFMEDIA:
7093170810Sdavidch			DBPRINT(sc, BCE_VERBOSE_MISC, "Received SIOCSIFMEDIA/SIOCGIFMEDIA\n");
7094157642Sps
7095166261Sdwhite			mii = device_get_softc(sc->bce_miibus);
7096166261Sdwhite			error = ifmedia_ioctl(ifp, ifr,
7097166261Sdwhite			    &mii->mii_media, command);
7098157642Sps			break;
7099157642Sps
7100157642Sps		/* Set interface capability */
7101157642Sps		case SIOCSIFCAP:
7102157642Sps			mask = ifr->ifr_reqcap ^ ifp->if_capenable;
7103170810Sdavidch			DBPRINT(sc, BCE_INFO_MISC, "Received SIOCSIFCAP = 0x%08X\n", (u32) mask);
7104157642Sps
7105204371Syongari			/* Toggle the TX checksum capabilities enable flag. */
7106204371Syongari			if (mask & IFCAP_TXCSUM &&
7107204371Syongari			    ifp->if_capabilities & IFCAP_TXCSUM) {
7108157642Sps				ifp->if_capenable ^= IFCAP_TXCSUM;
7109157642Sps				if (IFCAP_TXCSUM & ifp->if_capenable)
7110204371Syongari					ifp->if_hwassist |= BCE_IF_HWASSIST;
7111157642Sps				else
7112204371Syongari					ifp->if_hwassist &= ~BCE_IF_HWASSIST;
7113157642Sps			}
7114157642Sps
7115157642Sps			/* Toggle the RX checksum capabilities enable flag. */
7116204371Syongari			if (mask & IFCAP_RXCSUM &&
7117204371Syongari			    ifp->if_capabilities & IFCAP_RXCSUM)
7118157642Sps				ifp->if_capenable ^= IFCAP_RXCSUM;
7119157642Sps
7120169632Sdavidch			/* Toggle the TSO capabilities enable flag. */
7121204371Syongari			if (bce_tso_enable && (mask & IFCAP_TSO4) &&
7122204371Syongari			    ifp->if_capabilities & IFCAP_TSO4) {
7123169632Sdavidch				ifp->if_capenable ^= IFCAP_TSO4;
7124204371Syongari				if (IFCAP_TSO4 & ifp->if_capenable)
7125204371Syongari					ifp->if_hwassist |= CSUM_TSO;
7126169632Sdavidch				else
7127204371Syongari					ifp->if_hwassist &= ~CSUM_TSO;
7128169632Sdavidch			}
7129169632Sdavidch
7130204371Syongari			if (mask & IFCAP_VLAN_HWCSUM &&
7131204371Syongari			    ifp->if_capabilities & IFCAP_VLAN_HWCSUM)
7132204371Syongari				ifp->if_capenable ^= IFCAP_VLAN_HWCSUM;
7133204371Syongari
7134204368Syongari			/*
7135204368Syongari			 * Don't actually disable VLAN tag stripping as
7136204368Syongari			 * management firmware (ASF/IPMI/UMP) requires the
7137204368Syongari			 * feature. If VLAN tag stripping is disabled driver
7138204368Syongari			 * will manually reconstruct the VLAN frame by
7139204368Syongari			 * appending stripped VLAN tag.
7140204368Syongari			 */
7141204368Syongari			if ((mask & IFCAP_VLAN_HWTAGGING) != 0 &&
7142204368Syongari			    (ifp->if_capabilities & IFCAP_VLAN_HWTAGGING))
7143204368Syongari				ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING;
7144204368Syongari			VLAN_CAPABILITIES(ifp);
7145157642Sps			break;
7146157642Sps		default:
7147157642Sps			/* We don't know how to handle the IOCTL, pass it on. */
7148157642Sps			error = ether_ioctl(ifp, command, data);
7149157642Sps			break;
7150157642Sps	}
7151157642Sps
7152179771Sdavidch	DBEXIT(BCE_VERBOSE_MISC);
7153157642Sps	return(error);
7154157642Sps}
7155157642Sps
7156157642Sps
7157157642Sps/****************************************************************************/
7158157642Sps/* Transmit timeout handler.                                                */
7159157642Sps/*                                                                          */
7160157642Sps/* Returns:                                                                 */
7161157642Sps/*   Nothing.                                                               */
7162157642Sps/****************************************************************************/
7163157642Spsstatic void
7164165933Sdelphijbce_watchdog(struct bce_softc *sc)
7165157642Sps{
7166179771Sdavidch	DBENTER(BCE_EXTREME_SEND);
7167157642Sps
7168165933Sdelphij	BCE_LOCK_ASSERT(sc);
7169165933Sdelphij
7170179771Sdavidch	/* If the watchdog timer hasn't expired then just exit. */
7171165933Sdelphij	if (sc->watchdog_timer == 0 || --sc->watchdog_timer)
7172179771Sdavidch		goto bce_watchdog_exit;
7173165933Sdelphij
7174179771Sdavidch	/* If pause frames are active then don't reset the hardware. */
7175179771Sdavidch	/* ToDo: Should we reset the timer here? */
7176179771Sdavidch	if (REG_RD(sc, BCE_EMAC_TX_STATUS) & BCE_EMAC_TX_STATUS_XOFFED)
7177179771Sdavidch		goto bce_watchdog_exit;
7178165933Sdelphij
7179179771Sdavidch	BCE_PRINTF("%s(%d): Watchdog timeout occurred, resetting!\n",
7180157642Sps		__FILE__, __LINE__);
7181157642Sps
7182179771Sdavidch	DBRUNMSG(BCE_INFO,
7183170810Sdavidch		bce_dump_driver_state(sc);
7184179771Sdavidch		bce_dump_status_block(sc);
7185179771Sdavidch		bce_dump_stats_block(sc);
7186179771Sdavidch		bce_dump_ftqs(sc);
7187179771Sdavidch		bce_dump_txp_state(sc, 0);
7188179771Sdavidch		bce_dump_rxp_state(sc, 0);
7189179771Sdavidch		bce_dump_tpat_state(sc, 0);
7190179771Sdavidch		bce_dump_cp_state(sc, 0);
7191179771Sdavidch		bce_dump_com_state(sc, 0));
7192170810Sdavidch
7193179771Sdavidch	DBRUN(bce_breakpoint(sc));
7194157642Sps
7195165933Sdelphij	sc->bce_ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
7196157642Sps
7197160526Sjhb	bce_init_locked(sc);
7198165933Sdelphij	sc->bce_ifp->if_oerrors++;
7199157642Sps
7200179771Sdavidchbce_watchdog_exit:
7201179771Sdavidch	DBEXIT(BCE_EXTREME_SEND);
7202157642Sps}
7203157642Sps
7204157642Sps
7205157642Sps/*
7206157642Sps * Interrupt handler.
7207157642Sps */
7208157642Sps/****************************************************************************/
7209157642Sps/* Main interrupt entry point.  Verifies that the controller generated the  */
7210157642Sps/* interrupt and then calls a separate routine for handle the various       */
7211157642Sps/* interrupt causes (PHY, TX, RX).                                          */
7212157642Sps/*                                                                          */
7213157642Sps/* Returns:                                                                 */
7214157642Sps/*   0 for success, positive value for failure.                             */
7215157642Sps/****************************************************************************/
7216157642Spsstatic void
7217157642Spsbce_intr(void *xsc)
7218157642Sps{
7219157642Sps	struct bce_softc *sc;
7220157642Sps	struct ifnet *ifp;
7221157642Sps	u32 status_attn_bits;
7222178132Sdavidch	u16 hw_rx_cons, hw_tx_cons;
7223157642Sps
7224157642Sps	sc = xsc;
7225157642Sps	ifp = sc->bce_ifp;
7226157642Sps
7227179771Sdavidch	DBENTER(BCE_VERBOSE_SEND | BCE_VERBOSE_RECV | BCE_VERBOSE_INTR);
7228179771Sdavidch	DBRUNMSG(BCE_VERBOSE_INTR, bce_dump_status_block(sc));
7229179771Sdavidch
7230157642Sps	BCE_LOCK(sc);
7231157642Sps
7232176448Sdavidch	DBRUN(sc->interrupts_generated++);
7233157642Sps
7234192281Sdelphij	/* Synchnorize before we read from interface's status block */
7235157642Sps	bus_dmamap_sync(sc->status_tag, sc->status_map,
7236192281Sdelphij	    BUS_DMASYNC_POSTREAD);
7237157642Sps
7238157642Sps	/*
7239157642Sps	 * If the hardware status block index
7240157642Sps	 * matches the last value read by the
7241157642Sps	 * driver and we haven't asserted our
7242157642Sps	 * interrupt then there's nothing to do.
7243157642Sps	 */
7244179771Sdavidch	if ((sc->status_block->status_idx == sc->last_status_idx) &&
7245179771Sdavidch		(REG_RD(sc, BCE_PCICFG_MISC_STATUS) & BCE_PCICFG_MISC_STATUS_INTA_VALUE)) {
7246179771Sdavidch			DBPRINT(sc, BCE_VERBOSE_INTR, "%s(): Spurious interrupt.\n",
7247179771Sdavidch				__FUNCTION__);
7248179771Sdavidch			goto bce_intr_exit;
7249179771Sdavidch	}
7250157642Sps
7251157642Sps	/* Ack the interrupt and stop others from occuring. */
7252157642Sps	REG_WR(sc, BCE_PCICFG_INT_ACK_CMD,
7253157642Sps		BCE_PCICFG_INT_ACK_CMD_USE_INT_HC_PARAM |
7254157642Sps		BCE_PCICFG_INT_ACK_CMD_MASK_INT);
7255157642Sps
7256178132Sdavidch	/* Check if the hardware has finished any work. */
7257178132Sdavidch	hw_rx_cons = bce_get_hw_rx_cons(sc);
7258178132Sdavidch	hw_tx_cons = bce_get_hw_tx_cons(sc);
7259178132Sdavidch
7260157642Sps	/* Keep processing data as long as there is work to do. */
7261157642Sps	for (;;) {
7262157642Sps
7263157642Sps		status_attn_bits = sc->status_block->status_attn_bits;
7264157642Sps
7265189325Sdavidch	DBRUNIF(DB_RANDOMTRUE(unexpected_attention_sim_control),
7266189325Sdavidch		BCE_PRINTF("Simulating unexpected status attention bit set.");
7267189325Sdavidch		sc->unexpected_attention_sim_count++;
7268189325Sdavidch		status_attn_bits = status_attn_bits | STATUS_ATTN_BITS_PARITY_ERROR);
7269157642Sps
7270157642Sps		/* Was it a link change interrupt? */
7271157642Sps		if ((status_attn_bits & STATUS_ATTN_BITS_LINK_STATE) !=
7272185593Sdelphij			(sc->status_block->status_attn_bits_ack & STATUS_ATTN_BITS_LINK_STATE)) {
7273157642Sps			bce_phy_intr(sc);
7274157642Sps
7275185593Sdelphij			/* Clear any transient status updates during link state change. */
7276185593Sdelphij			REG_WR(sc, BCE_HC_COMMAND,
7277185593Sdelphij				sc->hc_command | BCE_HC_COMMAND_COAL_NOW_WO_INT);
7278185593Sdelphij			REG_RD(sc, BCE_HC_COMMAND);
7279185593Sdelphij		}
7280179771Sdavidch
7281157642Sps		/* If any other attention is asserted then the chip is toast. */
7282157642Sps		if (((status_attn_bits & ~STATUS_ATTN_BITS_LINK_STATE) !=
7283179771Sdavidch			(sc->status_block->status_attn_bits_ack &
7284157642Sps			~STATUS_ATTN_BITS_LINK_STATE))) {
7285157642Sps
7286189325Sdavidch		sc->unexpected_attention_count++;
7287157642Sps
7288179771Sdavidch			BCE_PRINTF("%s(%d): Fatal attention detected: 0x%08X\n",
7289157642Sps				__FILE__, __LINE__, sc->status_block->status_attn_bits);
7290157642Sps
7291179771Sdavidch			DBRUNMSG(BCE_FATAL,
7292189325Sdavidch				if (unexpected_attention_sim_control == 0)
7293157642Sps					bce_breakpoint(sc));
7294157642Sps
7295157642Sps			bce_init_locked(sc);
7296157642Sps			goto bce_intr_exit;
7297157642Sps		}
7298157642Sps
7299157642Sps		/* Check for any completed RX frames. */
7300178132Sdavidch		if (hw_rx_cons != sc->hw_rx_cons)
7301157642Sps			bce_rx_intr(sc);
7302157642Sps
7303157642Sps		/* Check for any completed TX frames. */
7304178132Sdavidch		if (hw_tx_cons != sc->hw_tx_cons)
7305157642Sps			bce_tx_intr(sc);
7306157642Sps
7307157642Sps		/* Save the status block index value for use during the next interrupt. */
7308157642Sps		sc->last_status_idx = sc->status_block->status_idx;
7309157642Sps
7310157642Sps		/* Prevent speculative reads from getting ahead of the status block. */
7311179771Sdavidch		bus_space_barrier(sc->bce_btag, sc->bce_bhandle, 0, 0,
7312157642Sps			BUS_SPACE_BARRIER_READ);
7313157642Sps
7314157642Sps		/* If there's no work left then exit the interrupt service routine. */
7315178132Sdavidch		hw_rx_cons = bce_get_hw_rx_cons(sc);
7316178132Sdavidch		hw_tx_cons = bce_get_hw_tx_cons(sc);
7317178132Sdavidch
7318178132Sdavidch		if ((hw_rx_cons == sc->hw_rx_cons) && (hw_tx_cons == sc->hw_tx_cons))
7319157642Sps			break;
7320179771Sdavidch
7321157642Sps	}
7322157642Sps
7323157642Sps	bus_dmamap_sync(sc->status_tag,	sc->status_map,
7324192281Sdelphij	    BUS_DMASYNC_PREREAD);
7325157642Sps
7326157642Sps	/* Re-enable interrupts. */
7327179771Sdavidch	bce_enable_intr(sc, 0);
7328157642Sps
7329157642Sps	/* Handle any frames that arrived while handling the interrupt. */
7330157642Sps	if (ifp->if_drv_flags & IFF_DRV_RUNNING && !IFQ_DRV_IS_EMPTY(&ifp->if_snd))
7331157642Sps		bce_start_locked(ifp);
7332157642Sps
7333157642Spsbce_intr_exit:
7334157642Sps	BCE_UNLOCK(sc);
7335179771Sdavidch
7336179771Sdavidch	DBEXIT(BCE_VERBOSE_SEND | BCE_VERBOSE_RECV | BCE_VERBOSE_INTR);
7337157642Sps}
7338157642Sps
7339157642Sps
7340157642Sps/****************************************************************************/
7341157642Sps/* Programs the various packet receive modes (broadcast and multicast).     */
7342157642Sps/*                                                                          */
7343157642Sps/* Returns:                                                                 */
7344157642Sps/*   Nothing.                                                               */
7345157642Sps/****************************************************************************/
7346157642Spsstatic void
7347157642Spsbce_set_rx_mode(struct bce_softc *sc)
7348157642Sps{
7349157642Sps	struct ifnet *ifp;
7350157642Sps	struct ifmultiaddr *ifma;
7351166153Sscottl	u32 hashes[NUM_MC_HASH_REGISTERS] = { 0, 0, 0, 0, 0, 0, 0, 0 };
7352157642Sps	u32 rx_mode, sort_mode;
7353157642Sps	int h, i;
7354157642Sps
7355179771Sdavidch	DBENTER(BCE_VERBOSE_MISC);
7356179771Sdavidch
7357157642Sps	BCE_LOCK_ASSERT(sc);
7358157642Sps
7359157642Sps	ifp = sc->bce_ifp;
7360157642Sps
7361157642Sps	/* Initialize receive mode default settings. */
7362157642Sps	rx_mode   = sc->rx_mode & ~(BCE_EMAC_RX_MODE_PROMISCUOUS |
7363157642Sps			    BCE_EMAC_RX_MODE_KEEP_VLAN_TAG);
7364157642Sps	sort_mode = 1 | BCE_RPM_SORT_USER0_BC_EN;
7365157642Sps
7366157642Sps	/*
7367157642Sps	 * ASF/IPMI/UMP firmware requires that VLAN tag stripping
7368157642Sps	 * be enbled.
7369157642Sps	 */
7370157642Sps	if (!(BCE_IF_CAPABILITIES & IFCAP_VLAN_HWTAGGING) &&
7371157642Sps		(!(sc->bce_flags & BCE_MFW_ENABLE_FLAG)))
7372157642Sps		rx_mode |= BCE_EMAC_RX_MODE_KEEP_VLAN_TAG;
7373157642Sps
7374157642Sps	/*
7375157642Sps	 * Check for promiscuous, all multicast, or selected
7376157642Sps	 * multicast address filtering.
7377157642Sps	 */
7378157642Sps	if (ifp->if_flags & IFF_PROMISC) {
7379170810Sdavidch		DBPRINT(sc, BCE_INFO_MISC, "Enabling promiscuous mode.\n");
7380157642Sps
7381157642Sps		/* Enable promiscuous mode. */
7382157642Sps		rx_mode |= BCE_EMAC_RX_MODE_PROMISCUOUS;
7383157642Sps		sort_mode |= BCE_RPM_SORT_USER0_PROM_EN;
7384157642Sps	} else if (ifp->if_flags & IFF_ALLMULTI) {
7385170810Sdavidch		DBPRINT(sc, BCE_INFO_MISC, "Enabling all multicast mode.\n");
7386157642Sps
7387157642Sps		/* Enable all multicast addresses. */
7388157642Sps		for (i = 0; i < NUM_MC_HASH_REGISTERS; i++) {
7389157642Sps			REG_WR(sc, BCE_EMAC_MULTICAST_HASH0 + (i * 4), 0xffffffff);
7390157642Sps       	}
7391157642Sps		sort_mode |= BCE_RPM_SORT_USER0_MC_EN;
7392157642Sps	} else {
7393157642Sps		/* Accept one or more multicast(s). */
7394170810Sdavidch		DBPRINT(sc, BCE_INFO_MISC, "Enabling selective multicast mode.\n");
7395157642Sps
7396195049Srwatson		if_maddr_rlock(ifp);
7397157642Sps		TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
7398157642Sps			if (ifma->ifma_addr->sa_family != AF_LINK)
7399157642Sps				continue;
7400157642Sps			h = ether_crc32_le(LLADDR((struct sockaddr_dl *)
7401166153Sscottl			    ifma->ifma_addr), ETHER_ADDR_LEN) & 0xFF;
7402166153Sscottl			    hashes[(h & 0xE0) >> 5] |= 1 << (h & 0x1F);
7403157642Sps		}
7404195049Srwatson		if_maddr_runlock(ifp);
7405157642Sps
7406166153Sscottl		for (i = 0; i < NUM_MC_HASH_REGISTERS; i++)
7407157642Sps			REG_WR(sc, BCE_EMAC_MULTICAST_HASH0 + (i * 4), hashes[i]);
7408157642Sps
7409157642Sps		sort_mode |= BCE_RPM_SORT_USER0_MC_HSH_EN;
7410157642Sps	}
7411157642Sps
7412157642Sps	/* Only make changes if the recive mode has actually changed. */
7413157642Sps	if (rx_mode != sc->rx_mode) {
7414179771Sdavidch		DBPRINT(sc, BCE_VERBOSE_MISC, "Enabling new receive mode: 0x%08X\n",
7415157642Sps			rx_mode);
7416157642Sps
7417157642Sps		sc->rx_mode = rx_mode;
7418157642Sps		REG_WR(sc, BCE_EMAC_RX_MODE, rx_mode);
7419157642Sps	}
7420157642Sps
7421157642Sps	/* Disable and clear the exisitng sort before enabling a new sort. */
7422157642Sps	REG_WR(sc, BCE_RPM_SORT_USER0, 0x0);
7423157642Sps	REG_WR(sc, BCE_RPM_SORT_USER0, sort_mode);
7424157642Sps	REG_WR(sc, BCE_RPM_SORT_USER0, sort_mode | BCE_RPM_SORT_USER0_ENA);
7425179771Sdavidch
7426179771Sdavidch	DBEXIT(BCE_VERBOSE_MISC);
7427157642Sps}
7428157642Sps
7429157642Sps
7430157642Sps/****************************************************************************/
7431157642Sps/* Called periodically to updates statistics from the controllers           */
7432157642Sps/* statistics block.                                                        */
7433157642Sps/*                                                                          */
7434157642Sps/* Returns:                                                                 */
7435157642Sps/*   Nothing.                                                               */
7436157642Sps/****************************************************************************/
7437157642Spsstatic void
7438157642Spsbce_stats_update(struct bce_softc *sc)
7439157642Sps{
7440157642Sps	struct ifnet *ifp;
7441157642Sps	struct statistics_block *stats;
7442157642Sps
7443179771Sdavidch	DBENTER(BCE_EXTREME_MISC);
7444157642Sps
7445157642Sps	ifp = sc->bce_ifp;
7446157642Sps
7447157642Sps	stats = (struct statistics_block *) sc->stats_block;
7448157642Sps
7449179771Sdavidch	/*
7450179771Sdavidch	 * Certain controllers don't report
7451157642Sps	 * carrier sense errors correctly.
7452179771Sdavidch	 * See errata E11_5708CA0_1165.
7453157642Sps	 */
7454157642Sps	if (!(BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5706) &&
7455157642Sps	    !(BCE_CHIP_ID(sc) == BCE_CHIP_ID_5708_A0))
7456157642Sps		ifp->if_oerrors += (u_long) stats->stat_Dot3StatsCarrierSenseErrors;
7457157642Sps
7458157642Sps	/*
7459157642Sps	 * Update the sysctl statistics from the
7460157642Sps	 * hardware statistics.
7461157642Sps	 */
7462179771Sdavidch	sc->stat_IfHCInOctets =
7463179771Sdavidch		((u64) stats->stat_IfHCInOctets_hi << 32) +
7464157642Sps		 (u64) stats->stat_IfHCInOctets_lo;
7465157642Sps
7466157642Sps	sc->stat_IfHCInBadOctets =
7467179771Sdavidch		((u64) stats->stat_IfHCInBadOctets_hi << 32) +
7468157642Sps		 (u64) stats->stat_IfHCInBadOctets_lo;
7469157642Sps
7470157642Sps	sc->stat_IfHCOutOctets =
7471157642Sps		((u64) stats->stat_IfHCOutOctets_hi << 32) +
7472157642Sps		 (u64) stats->stat_IfHCOutOctets_lo;
7473157642Sps
7474157642Sps	sc->stat_IfHCOutBadOctets =
7475157642Sps		((u64) stats->stat_IfHCOutBadOctets_hi << 32) +
7476157642Sps		 (u64) stats->stat_IfHCOutBadOctets_lo;
7477157642Sps
7478157642Sps	sc->stat_IfHCInUcastPkts =
7479157642Sps		((u64) stats->stat_IfHCInUcastPkts_hi << 32) +
7480157642Sps		 (u64) stats->stat_IfHCInUcastPkts_lo;
7481157642Sps
7482157642Sps	sc->stat_IfHCInMulticastPkts =
7483157642Sps		((u64) stats->stat_IfHCInMulticastPkts_hi << 32) +
7484157642Sps		 (u64) stats->stat_IfHCInMulticastPkts_lo;
7485157642Sps
7486157642Sps	sc->stat_IfHCInBroadcastPkts =
7487157642Sps		((u64) stats->stat_IfHCInBroadcastPkts_hi << 32) +
7488157642Sps		 (u64) stats->stat_IfHCInBroadcastPkts_lo;
7489157642Sps
7490157642Sps	sc->stat_IfHCOutUcastPkts =
7491157642Sps		((u64) stats->stat_IfHCOutUcastPkts_hi << 32) +
7492157642Sps		 (u64) stats->stat_IfHCOutUcastPkts_lo;
7493157642Sps
7494157642Sps	sc->stat_IfHCOutMulticastPkts =
7495157642Sps		((u64) stats->stat_IfHCOutMulticastPkts_hi << 32) +
7496157642Sps		 (u64) stats->stat_IfHCOutMulticastPkts_lo;
7497157642Sps
7498157642Sps	sc->stat_IfHCOutBroadcastPkts =
7499157642Sps		((u64) stats->stat_IfHCOutBroadcastPkts_hi << 32) +
7500157642Sps		 (u64) stats->stat_IfHCOutBroadcastPkts_lo;
7501157642Sps
7502157642Sps	sc->stat_emac_tx_stat_dot3statsinternalmactransmiterrors =
7503157642Sps		stats->stat_emac_tx_stat_dot3statsinternalmactransmiterrors;
7504157642Sps
7505157642Sps	sc->stat_Dot3StatsCarrierSenseErrors =
7506157642Sps		stats->stat_Dot3StatsCarrierSenseErrors;
7507157642Sps
7508179771Sdavidch	sc->stat_Dot3StatsFCSErrors =
7509157642Sps		stats->stat_Dot3StatsFCSErrors;
7510157642Sps
7511157642Sps	sc->stat_Dot3StatsAlignmentErrors =
7512157642Sps		stats->stat_Dot3StatsAlignmentErrors;
7513157642Sps
7514157642Sps	sc->stat_Dot3StatsSingleCollisionFrames =
7515157642Sps		stats->stat_Dot3StatsSingleCollisionFrames;
7516157642Sps
7517157642Sps	sc->stat_Dot3StatsMultipleCollisionFrames =
7518157642Sps		stats->stat_Dot3StatsMultipleCollisionFrames;
7519157642Sps
7520157642Sps	sc->stat_Dot3StatsDeferredTransmissions =
7521157642Sps		stats->stat_Dot3StatsDeferredTransmissions;
7522157642Sps
7523157642Sps	sc->stat_Dot3StatsExcessiveCollisions =
7524157642Sps		stats->stat_Dot3StatsExcessiveCollisions;
7525157642Sps
7526157642Sps	sc->stat_Dot3StatsLateCollisions =
7527157642Sps		stats->stat_Dot3StatsLateCollisions;
7528157642Sps
7529157642Sps	sc->stat_EtherStatsCollisions =
7530157642Sps		stats->stat_EtherStatsCollisions;
7531157642Sps
7532157642Sps	sc->stat_EtherStatsFragments =
7533157642Sps		stats->stat_EtherStatsFragments;
7534157642Sps
7535157642Sps	sc->stat_EtherStatsJabbers =
7536157642Sps		stats->stat_EtherStatsJabbers;
7537157642Sps
7538157642Sps	sc->stat_EtherStatsUndersizePkts =
7539157642Sps		stats->stat_EtherStatsUndersizePkts;
7540157642Sps
7541189325Sdavidch	sc->stat_EtherStatsOversizePkts =
7542189325Sdavidch		stats->stat_EtherStatsOversizePkts;
7543157642Sps
7544157642Sps	sc->stat_EtherStatsPktsRx64Octets =
7545157642Sps		stats->stat_EtherStatsPktsRx64Octets;
7546157642Sps
7547157642Sps	sc->stat_EtherStatsPktsRx65Octetsto127Octets =
7548157642Sps		stats->stat_EtherStatsPktsRx65Octetsto127Octets;
7549157642Sps
7550157642Sps	sc->stat_EtherStatsPktsRx128Octetsto255Octets =
7551157642Sps		stats->stat_EtherStatsPktsRx128Octetsto255Octets;
7552157642Sps
7553157642Sps	sc->stat_EtherStatsPktsRx256Octetsto511Octets =
7554157642Sps		stats->stat_EtherStatsPktsRx256Octetsto511Octets;
7555157642Sps
7556157642Sps	sc->stat_EtherStatsPktsRx512Octetsto1023Octets =
7557157642Sps		stats->stat_EtherStatsPktsRx512Octetsto1023Octets;
7558157642Sps
7559157642Sps	sc->stat_EtherStatsPktsRx1024Octetsto1522Octets =
7560157642Sps		stats->stat_EtherStatsPktsRx1024Octetsto1522Octets;
7561157642Sps
7562157642Sps	sc->stat_EtherStatsPktsRx1523Octetsto9022Octets =
7563157642Sps		stats->stat_EtherStatsPktsRx1523Octetsto9022Octets;
7564157642Sps
7565157642Sps	sc->stat_EtherStatsPktsTx64Octets =
7566157642Sps		stats->stat_EtherStatsPktsTx64Octets;
7567157642Sps
7568157642Sps	sc->stat_EtherStatsPktsTx65Octetsto127Octets =
7569157642Sps		stats->stat_EtherStatsPktsTx65Octetsto127Octets;
7570157642Sps
7571157642Sps	sc->stat_EtherStatsPktsTx128Octetsto255Octets =
7572157642Sps		stats->stat_EtherStatsPktsTx128Octetsto255Octets;
7573157642Sps
7574157642Sps	sc->stat_EtherStatsPktsTx256Octetsto511Octets =
7575157642Sps		stats->stat_EtherStatsPktsTx256Octetsto511Octets;
7576157642Sps
7577157642Sps	sc->stat_EtherStatsPktsTx512Octetsto1023Octets =
7578157642Sps		stats->stat_EtherStatsPktsTx512Octetsto1023Octets;
7579157642Sps
7580157642Sps	sc->stat_EtherStatsPktsTx1024Octetsto1522Octets =
7581157642Sps		stats->stat_EtherStatsPktsTx1024Octetsto1522Octets;
7582157642Sps
7583157642Sps	sc->stat_EtherStatsPktsTx1523Octetsto9022Octets =
7584157642Sps		stats->stat_EtherStatsPktsTx1523Octetsto9022Octets;
7585157642Sps
7586157642Sps	sc->stat_XonPauseFramesReceived =
7587157642Sps		stats->stat_XonPauseFramesReceived;
7588157642Sps
7589157642Sps	sc->stat_XoffPauseFramesReceived =
7590157642Sps		stats->stat_XoffPauseFramesReceived;
7591157642Sps
7592157642Sps	sc->stat_OutXonSent =
7593157642Sps		stats->stat_OutXonSent;
7594157642Sps
7595157642Sps	sc->stat_OutXoffSent =
7596157642Sps		stats->stat_OutXoffSent;
7597157642Sps
7598157642Sps	sc->stat_FlowControlDone =
7599157642Sps		stats->stat_FlowControlDone;
7600157642Sps
7601157642Sps	sc->stat_MacControlFramesReceived =
7602157642Sps		stats->stat_MacControlFramesReceived;
7603157642Sps
7604157642Sps	sc->stat_XoffStateEntered =
7605157642Sps		stats->stat_XoffStateEntered;
7606157642Sps
7607157642Sps	sc->stat_IfInFramesL2FilterDiscards =
7608157642Sps		stats->stat_IfInFramesL2FilterDiscards;
7609157642Sps
7610157642Sps	sc->stat_IfInRuleCheckerDiscards =
7611157642Sps		stats->stat_IfInRuleCheckerDiscards;
7612157642Sps
7613157642Sps	sc->stat_IfInFTQDiscards =
7614157642Sps		stats->stat_IfInFTQDiscards;
7615157642Sps
7616157642Sps	sc->stat_IfInMBUFDiscards =
7617157642Sps		stats->stat_IfInMBUFDiscards;
7618157642Sps
7619157642Sps	sc->stat_IfInRuleCheckerP4Hit =
7620157642Sps		stats->stat_IfInRuleCheckerP4Hit;
7621157642Sps
7622157642Sps	sc->stat_CatchupInRuleCheckerDiscards =
7623157642Sps		stats->stat_CatchupInRuleCheckerDiscards;
7624157642Sps
7625157642Sps	sc->stat_CatchupInFTQDiscards =
7626157642Sps		stats->stat_CatchupInFTQDiscards;
7627157642Sps
7628157642Sps	sc->stat_CatchupInMBUFDiscards =
7629157642Sps		stats->stat_CatchupInMBUFDiscards;
7630157642Sps
7631157642Sps	sc->stat_CatchupInRuleCheckerP4Hit =
7632157642Sps		stats->stat_CatchupInRuleCheckerP4Hit;
7633157642Sps
7634170392Sdavidch	sc->com_no_buffers = REG_RD_IND(sc, 0x120084);
7635170392Sdavidch
7636179771Sdavidch	/*
7637179771Sdavidch	 * Update the interface statistics from the
7638179771Sdavidch	 * hardware statistics.
7639179771Sdavidch	 */
7640182293Sdavidch	ifp->if_collisions =
7641182293Sdavidch		(u_long) sc->stat_EtherStatsCollisions;
7642179771Sdavidch
7643182293Sdavidch	/* ToDo: This method loses soft errors. */
7644182293Sdavidch	ifp->if_ierrors =
7645182293Sdavidch		(u_long) sc->stat_EtherStatsUndersizePkts +
7646189325Sdavidch		(u_long) sc->stat_EtherStatsOversizePkts +
7647182293Sdavidch		(u_long) sc->stat_IfInMBUFDiscards +
7648182293Sdavidch		(u_long) sc->stat_Dot3StatsAlignmentErrors +
7649182293Sdavidch		(u_long) sc->stat_Dot3StatsFCSErrors +
7650182293Sdavidch		(u_long) sc->stat_IfInRuleCheckerDiscards +
7651182293Sdavidch		(u_long) sc->stat_IfInFTQDiscards +
7652182293Sdavidch		(u_long) sc->com_no_buffers;
7653179771Sdavidch
7654182293Sdavidch	/* ToDo: This method loses soft errors. */
7655182293Sdavidch	ifp->if_oerrors =
7656182293Sdavidch		(u_long) sc->stat_emac_tx_stat_dot3statsinternalmactransmiterrors +
7657182293Sdavidch		(u_long) sc->stat_Dot3StatsExcessiveCollisions +
7658182293Sdavidch		(u_long) sc->stat_Dot3StatsLateCollisions;
7659179771Sdavidch
7660182293Sdavidch	/* ToDo: Add additional statistics. */
7661182293Sdavidch
7662179771Sdavidch	DBEXIT(BCE_EXTREME_MISC);
7663157642Sps}
7664157642Sps
7665157642Sps
7666169271Sdavidch/****************************************************************************/
7667170810Sdavidch/* Periodic function to notify the bootcode that the driver is still        */
7668170810Sdavidch/* present.                                                                 */
7669170810Sdavidch/*                                                                          */
7670170810Sdavidch/* Returns:                                                                 */
7671170810Sdavidch/*   Nothing.                                                               */
7672170810Sdavidch/****************************************************************************/
7673170810Sdavidchstatic void
7674170810Sdavidchbce_pulse(void *xsc)
7675170810Sdavidch{
7676170810Sdavidch	struct bce_softc *sc = xsc;
7677170810Sdavidch	u32 msg;
7678170810Sdavidch
7679179771Sdavidch	DBENTER(BCE_EXTREME_MISC);
7680170810Sdavidch
7681170810Sdavidch	BCE_LOCK_ASSERT(sc);
7682170810Sdavidch
7683170810Sdavidch	/* Tell the firmware that the driver is still running. */
7684170810Sdavidch	msg = (u32) ++sc->bce_fw_drv_pulse_wr_seq;
7685194781Sdavidch	bce_shmem_wr(sc, BCE_DRV_PULSE_MB, msg);
7686170810Sdavidch
7687170810Sdavidch	/* Schedule the next pulse. */
7688170810Sdavidch	callout_reset(&sc->bce_pulse_callout, hz, bce_pulse, sc);
7689170810Sdavidch
7690179771Sdavidch	DBEXIT(BCE_EXTREME_MISC);
7691170810Sdavidch}
7692170810Sdavidch
7693170810Sdavidch
7694170810Sdavidch/****************************************************************************/
7695170392Sdavidch/* Periodic function to perform maintenance tasks.                          */
7696169271Sdavidch/*                                                                          */
7697169271Sdavidch/* Returns:                                                                 */
7698169271Sdavidch/*   Nothing.                                                               */
7699169271Sdavidch/****************************************************************************/
7700157642Spsstatic void
7701165933Sdelphijbce_tick(void *xsc)
7702157642Sps{
7703165933Sdelphij	struct bce_softc *sc = xsc;
7704169271Sdavidch	struct mii_data *mii;
7705157642Sps	struct ifnet *ifp;
7706157642Sps
7707157642Sps	ifp = sc->bce_ifp;
7708157642Sps
7709179771Sdavidch	DBENTER(BCE_EXTREME_MISC);
7710179771Sdavidch
7711157642Sps	BCE_LOCK_ASSERT(sc);
7712157642Sps
7713176448Sdavidch	/* Schedule the next tick. */
7714176448Sdavidch	callout_reset(&sc->bce_tick_callout, hz, bce_tick, sc);
7715176448Sdavidch
7716157642Sps	/* Update the statistics from the hardware statistics block. */
7717157642Sps	bce_stats_update(sc);
7718157642Sps
7719176448Sdavidch	/* Top off the receive and page chains. */
7720198320Sstas#ifdef BCE_JUMBO_HDRSPLIT
7721179771Sdavidch	bce_fill_pg_chain(sc);
7722179695Sdavidch#endif
7723176448Sdavidch	bce_fill_rx_chain(sc);
7724176448Sdavidch
7725169271Sdavidch	/* Check that chip hasn't hung. */
7726165933Sdelphij	bce_watchdog(sc);
7727165933Sdelphij
7728157642Sps	/* If link is up already up then we're done. */
7729157642Sps	if (sc->bce_link)
7730179771Sdavidch		goto bce_tick_exit;
7731157642Sps
7732182293Sdavidch	/* Link is down.  Check what the PHY's doing. */
7733157642Sps	mii = device_get_softc(sc->bce_miibus);
7734157642Sps	mii_tick(mii);
7735157642Sps
7736157642Sps	/* Check if the link has come up. */
7737179771Sdavidch	if ((mii->mii_media_status & IFM_ACTIVE) &&
7738179771Sdavidch	    (IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE)) {
7739179771Sdavidch		DBPRINT(sc, BCE_VERBOSE_MISC, "%s(): Link up!\n", __FUNCTION__);
7740157642Sps		sc->bce_link++;
7741157642Sps		if ((IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_T ||
7742157642Sps		    IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_SX) &&
7743157642Sps		    bootverbose)
7744179771Sdavidch			BCE_PRINTF("Gigabit link up!\n");
7745157642Sps		/* Now that link is up, handle any outstanding TX traffic. */
7746179771Sdavidch		if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) {
7747179771Sdavidch			DBPRINT(sc, BCE_VERBOSE_MISC, "%s(): Found pending TX traffic.\n",
7748179771Sdavidch				 __FUNCTION__);
7749157642Sps			bce_start_locked(ifp);
7750179771Sdavidch		}
7751157642Sps	}
7752157642Sps
7753179771Sdavidchbce_tick_exit:
7754179771Sdavidch	DBEXIT(BCE_EXTREME_MISC);
7755157642Sps	return;
7756157642Sps}
7757157642Sps
7758157642Sps
7759157642Sps#ifdef BCE_DEBUG
7760157642Sps/****************************************************************************/
7761157642Sps/* Allows the driver state to be dumped through the sysctl interface.       */
7762157642Sps/*                                                                          */
7763157642Sps/* Returns:                                                                 */
7764157642Sps/*   0 for success, positive value for failure.                             */
7765157642Sps/****************************************************************************/
7766157642Spsstatic int
7767157642Spsbce_sysctl_driver_state(SYSCTL_HANDLER_ARGS)
7768157642Sps{
7769157642Sps        int error;
7770157642Sps        int result;
7771157642Sps        struct bce_softc *sc;
7772157642Sps
7773157642Sps        result = -1;
7774157642Sps        error = sysctl_handle_int(oidp, &result, 0, req);
7775157642Sps
7776157642Sps        if (error || !req->newptr)
7777157642Sps                return (error);
7778157642Sps
7779157642Sps        if (result == 1) {
7780157642Sps                sc = (struct bce_softc *)arg1;
7781157642Sps                bce_dump_driver_state(sc);
7782157642Sps        }
7783157642Sps
7784157642Sps        return error;
7785157642Sps}
7786157642Sps
7787157642Sps
7788157642Sps/****************************************************************************/
7789157642Sps/* Allows the hardware state to be dumped through the sysctl interface.     */
7790157642Sps/*                                                                          */
7791157642Sps/* Returns:                                                                 */
7792157642Sps/*   0 for success, positive value for failure.                             */
7793157642Sps/****************************************************************************/
7794157642Spsstatic int
7795157642Spsbce_sysctl_hw_state(SYSCTL_HANDLER_ARGS)
7796157642Sps{
7797157642Sps        int error;
7798157642Sps        int result;
7799157642Sps        struct bce_softc *sc;
7800157642Sps
7801157642Sps        result = -1;
7802157642Sps        error = sysctl_handle_int(oidp, &result, 0, req);
7803157642Sps
7804157642Sps        if (error || !req->newptr)
7805157642Sps                return (error);
7806157642Sps
7807157642Sps        if (result == 1) {
7808157642Sps                sc = (struct bce_softc *)arg1;
7809157642Sps                bce_dump_hw_state(sc);
7810157642Sps        }
7811157642Sps
7812157642Sps        return error;
7813157642Sps}
7814157642Sps
7815157642Sps
7816157642Sps/****************************************************************************/
7817170810Sdavidch/* Allows the bootcode state to be dumped through the sysctl interface.     */
7818157642Sps/*                                                                          */
7819157642Sps/* Returns:                                                                 */
7820157642Sps/*   0 for success, positive value for failure.                             */
7821157642Sps/****************************************************************************/
7822157642Spsstatic int
7823170810Sdavidchbce_sysctl_bc_state(SYSCTL_HANDLER_ARGS)
7824170810Sdavidch{
7825170810Sdavidch        int error;
7826170810Sdavidch        int result;
7827170810Sdavidch        struct bce_softc *sc;
7828170810Sdavidch
7829170810Sdavidch        result = -1;
7830170810Sdavidch        error = sysctl_handle_int(oidp, &result, 0, req);
7831170810Sdavidch
7832170810Sdavidch        if (error || !req->newptr)
7833170810Sdavidch                return (error);
7834170810Sdavidch
7835170810Sdavidch        if (result == 1) {
7836170810Sdavidch                sc = (struct bce_softc *)arg1;
7837170810Sdavidch                bce_dump_bc_state(sc);
7838170810Sdavidch        }
7839170810Sdavidch
7840170810Sdavidch        return error;
7841170810Sdavidch}
7842170810Sdavidch
7843170810Sdavidch
7844170810Sdavidch/****************************************************************************/
7845170810Sdavidch/* Provides a sysctl interface to allow dumping the RX chain.               */
7846170810Sdavidch/*                                                                          */
7847170810Sdavidch/* Returns:                                                                 */
7848170810Sdavidch/*   0 for success, positive value for failure.                             */
7849170810Sdavidch/****************************************************************************/
7850170810Sdavidchstatic int
7851157642Spsbce_sysctl_dump_rx_chain(SYSCTL_HANDLER_ARGS)
7852157642Sps{
7853157642Sps        int error;
7854157642Sps        int result;
7855157642Sps        struct bce_softc *sc;
7856157642Sps
7857157642Sps        result = -1;
7858157642Sps        error = sysctl_handle_int(oidp, &result, 0, req);
7859157642Sps
7860157642Sps        if (error || !req->newptr)
7861157642Sps                return (error);
7862157642Sps
7863157642Sps        if (result == 1) {
7864157642Sps                sc = (struct bce_softc *)arg1;
7865176448Sdavidch                bce_dump_rx_chain(sc, 0, TOTAL_RX_BD);
7866157642Sps        }
7867157642Sps
7868157642Sps        return error;
7869157642Sps}
7870157642Sps
7871157642Sps
7872157642Sps/****************************************************************************/
7873170810Sdavidch/* Provides a sysctl interface to allow dumping the TX chain.               */
7874157642Sps/*                                                                          */
7875169271Sdavidch/* Returns:                                                                 */
7876169271Sdavidch/*   0 for success, positive value for failure.                             */
7877169271Sdavidch/****************************************************************************/
7878169271Sdavidchstatic int
7879169271Sdavidchbce_sysctl_dump_tx_chain(SYSCTL_HANDLER_ARGS)
7880169271Sdavidch{
7881169271Sdavidch        int error;
7882169271Sdavidch        int result;
7883169271Sdavidch        struct bce_softc *sc;
7884169271Sdavidch
7885169271Sdavidch        result = -1;
7886169271Sdavidch        error = sysctl_handle_int(oidp, &result, 0, req);
7887169271Sdavidch
7888169271Sdavidch        if (error || !req->newptr)
7889169271Sdavidch                return (error);
7890169271Sdavidch
7891169271Sdavidch        if (result == 1) {
7892169271Sdavidch                sc = (struct bce_softc *)arg1;
7893169271Sdavidch                bce_dump_tx_chain(sc, 0, USABLE_TX_BD);
7894169271Sdavidch        }
7895169271Sdavidch
7896169271Sdavidch        return error;
7897169271Sdavidch}
7898169271Sdavidch
7899169271Sdavidch
7900198320Sstas#ifdef BCE_JUMBO_HDRSPLIT
7901169271Sdavidch/****************************************************************************/
7902176448Sdavidch/* Provides a sysctl interface to allow dumping the page chain.             */
7903176448Sdavidch/*                                                                          */
7904176448Sdavidch/* Returns:                                                                 */
7905176448Sdavidch/*   0 for success, positive value for failure.                             */
7906176448Sdavidch/****************************************************************************/
7907176448Sdavidchstatic int
7908176448Sdavidchbce_sysctl_dump_pg_chain(SYSCTL_HANDLER_ARGS)
7909176448Sdavidch{
7910176448Sdavidch        int error;
7911176448Sdavidch        int result;
7912176448Sdavidch        struct bce_softc *sc;
7913176448Sdavidch
7914176448Sdavidch        result = -1;
7915176448Sdavidch        error = sysctl_handle_int(oidp, &result, 0, req);
7916176448Sdavidch
7917176448Sdavidch        if (error || !req->newptr)
7918176448Sdavidch                return (error);
7919176448Sdavidch
7920176448Sdavidch        if (result == 1) {
7921176448Sdavidch                sc = (struct bce_softc *)arg1;
7922176448Sdavidch                bce_dump_pg_chain(sc, 0, TOTAL_PG_BD);
7923176448Sdavidch        }
7924176448Sdavidch
7925176448Sdavidch        return error;
7926179771Sdavidch}
7927179695Sdavidch#endif
7928176448Sdavidch
7929179771Sdavidch/****************************************************************************/
7930179771Sdavidch/* Provides a sysctl interface to allow reading arbitrary NVRAM offsets in  */
7931179771Sdavidch/* the device.  DO NOT ENABLE ON PRODUCTION SYSTEMS!                        */
7932179771Sdavidch/*                                                                          */
7933179771Sdavidch/* Returns:                                                                 */
7934179771Sdavidch/*   0 for success, positive value for failure.                             */
7935179771Sdavidch/****************************************************************************/
7936179771Sdavidchstatic int
7937179771Sdavidchbce_sysctl_nvram_read(SYSCTL_HANDLER_ARGS)
7938179771Sdavidch{
7939179771Sdavidch	struct bce_softc *sc = (struct bce_softc *)arg1;
7940179771Sdavidch	int error;
7941182293Sdavidch	u32 result;
7942182293Sdavidch	u32 val[1];
7943179771Sdavidch	u8 *data = (u8 *) val;
7944176448Sdavidch
7945179771Sdavidch	result = -1;
7946179771Sdavidch	error = sysctl_handle_int(oidp, &result, 0, req);
7947179771Sdavidch	if (error || (req->newptr == NULL))
7948179771Sdavidch		return (error);
7949179771Sdavidch
7950179771Sdavidch	bce_nvram_read(sc, result, data, 4);
7951179771Sdavidch	BCE_PRINTF("offset 0x%08X = 0x%08X\n", result, bce_be32toh(val[0]));
7952182293Sdavidch
7953179771Sdavidch	return (error);
7954179771Sdavidch}
7955182293Sdavidch
7956182293Sdavidch
7957176448Sdavidch/****************************************************************************/
7958170392Sdavidch/* Provides a sysctl interface to allow reading arbitrary registers in the  */
7959170392Sdavidch/* device.  DO NOT ENABLE ON PRODUCTION SYSTEMS!                            */
7960157642Sps/*                                                                          */
7961157642Sps/* Returns:                                                                 */
7962157642Sps/*   0 for success, positive value for failure.                             */
7963157642Sps/****************************************************************************/
7964157642Spsstatic int
7965169271Sdavidchbce_sysctl_reg_read(SYSCTL_HANDLER_ARGS)
7966169271Sdavidch{
7967179771Sdavidch	struct bce_softc *sc = (struct bce_softc *)arg1;
7968169271Sdavidch	int error;
7969170810Sdavidch	u32 val, result;
7970179771Sdavidch
7971169271Sdavidch	result = -1;
7972169271Sdavidch	error = sysctl_handle_int(oidp, &result, 0, req);
7973169271Sdavidch	if (error || (req->newptr == NULL))
7974169271Sdavidch		return (error);
7975179771Sdavidch
7976170392Sdavidch	/* Make sure the register is accessible. */
7977169271Sdavidch	if (result < 0x8000) {
7978169271Sdavidch		val = REG_RD(sc, result);
7979169271Sdavidch		BCE_PRINTF("reg 0x%08X = 0x%08X\n", result, val);
7980169271Sdavidch	} else if (result < 0x0280000) {
7981169271Sdavidch		val = REG_RD_IND(sc, result);
7982170392Sdavidch		BCE_PRINTF("reg 0x%08X = 0x%08X\n", result, val);
7983169271Sdavidch	}
7984179771Sdavidch
7985169271Sdavidch	return (error);
7986169271Sdavidch}
7987170392Sdavidch
7988179771Sdavidch
7989169271Sdavidch/****************************************************************************/
7990170392Sdavidch/* Provides a sysctl interface to allow reading arbitrary PHY registers in  */
7991170392Sdavidch/* the device.  DO NOT ENABLE ON PRODUCTION SYSTEMS!                        */
7992169632Sdavidch/*                                                                          */
7993169632Sdavidch/* Returns:                                                                 */
7994169632Sdavidch/*   0 for success, positive value for failure.                             */
7995169632Sdavidch/****************************************************************************/
7996169632Sdavidchstatic int
7997169632Sdavidchbce_sysctl_phy_read(SYSCTL_HANDLER_ARGS)
7998169632Sdavidch{
7999170392Sdavidch	struct bce_softc *sc;
8000169632Sdavidch	device_t dev;
8001169632Sdavidch	int error, result;
8002169632Sdavidch	u16 val;
8003169632Sdavidch
8004169632Sdavidch	result = -1;
8005169632Sdavidch	error = sysctl_handle_int(oidp, &result, 0, req);
8006169632Sdavidch	if (error || (req->newptr == NULL))
8007169632Sdavidch		return (error);
8008169632Sdavidch
8009170392Sdavidch	/* Make sure the register is accessible. */
8010169632Sdavidch	if (result < 0x20) {
8011170392Sdavidch		sc = (struct bce_softc *)arg1;
8012169632Sdavidch		dev = sc->bce_dev;
8013169632Sdavidch		val = bce_miibus_read_reg(dev, sc->bce_phy_addr, result);
8014169632Sdavidch		BCE_PRINTF("phy 0x%02X = 0x%04X\n", result, val);
8015169632Sdavidch	}
8016169632Sdavidch	return (error);
8017169632Sdavidch}
8018170392Sdavidch
8019170392Sdavidch
8020169632Sdavidch/****************************************************************************/
8021179771Sdavidch/* Provides a sysctl interface to allow reading a CID.                      */
8022179771Sdavidch/*                                                                          */
8023179771Sdavidch/* Returns:                                                                 */
8024179771Sdavidch/*   0 for success, positive value for failure.                             */
8025179771Sdavidch/****************************************************************************/
8026179771Sdavidchstatic int
8027179771Sdavidchbce_sysctl_dump_ctx(SYSCTL_HANDLER_ARGS)
8028179771Sdavidch{
8029179771Sdavidch	struct bce_softc *sc;
8030179771Sdavidch	int error;
8031179771Sdavidch	u16 result;
8032179771Sdavidch
8033179771Sdavidch	result = -1;
8034179771Sdavidch	error = sysctl_handle_int(oidp, &result, 0, req);
8035179771Sdavidch	if (error || (req->newptr == NULL))
8036179771Sdavidch		return (error);
8037179771Sdavidch
8038179771Sdavidch	/* Make sure the register is accessible. */
8039179771Sdavidch	if (result <= TX_CID) {
8040179771Sdavidch		sc = (struct bce_softc *)arg1;
8041179771Sdavidch		bce_dump_ctx(sc, result);
8042179771Sdavidch	}
8043179771Sdavidch
8044179771Sdavidch	return (error);
8045179771Sdavidch}
8046179771Sdavidch
8047179771Sdavidch
8048179771Sdavidch /****************************************************************************/
8049170392Sdavidch/* Provides a sysctl interface to forcing the driver to dump state and      */
8050169271Sdavidch/* enter the debugger.  DO NOT ENABLE ON PRODUCTION SYSTEMS!                */
8051169271Sdavidch/*                                                                          */
8052169271Sdavidch/* Returns:                                                                 */
8053169271Sdavidch/*   0 for success, positive value for failure.                             */
8054169271Sdavidch/****************************************************************************/
8055169271Sdavidchstatic int
8056157642Spsbce_sysctl_breakpoint(SYSCTL_HANDLER_ARGS)
8057157642Sps{
8058157642Sps        int error;
8059157642Sps        int result;
8060157642Sps        struct bce_softc *sc;
8061157642Sps
8062157642Sps        result = -1;
8063157642Sps        error = sysctl_handle_int(oidp, &result, 0, req);
8064157642Sps
8065157642Sps        if (error || !req->newptr)
8066157642Sps                return (error);
8067157642Sps
8068157642Sps        if (result == 1) {
8069157642Sps                sc = (struct bce_softc *)arg1;
8070157642Sps                bce_breakpoint(sc);
8071157642Sps        }
8072157642Sps
8073157642Sps        return error;
8074157642Sps}
8075157642Sps#endif
8076157642Sps
8077157642Sps
8078157642Sps/****************************************************************************/
8079157642Sps/* Adds any sysctl parameters for tuning or debugging purposes.             */
8080157642Sps/*                                                                          */
8081157642Sps/* Returns:                                                                 */
8082157642Sps/*   0 for success, positive value for failure.                             */
8083157642Sps/****************************************************************************/
8084157642Spsstatic void
8085157642Spsbce_add_sysctls(struct bce_softc *sc)
8086157642Sps{
8087157642Sps	struct sysctl_ctx_list *ctx;
8088157642Sps	struct sysctl_oid_list *children;
8089157642Sps
8090179771Sdavidch	DBENTER(BCE_VERBOSE_MISC);
8091179771Sdavidch
8092157642Sps	ctx = device_get_sysctl_ctx(sc->bce_dev);
8093157642Sps	children = SYSCTL_CHILDREN(device_get_sysctl_tree(sc->bce_dev));
8094157642Sps
8095157642Sps#ifdef BCE_DEBUG
8096179771Sdavidch	SYSCTL_ADD_INT(ctx, children, OID_AUTO,
8097189325Sdavidch		"l2fhdr_error_sim_control",
8098189325Sdavidch		CTLFLAG_RW, &l2fhdr_error_sim_control,
8099189325Sdavidch		0, "Debug control to force l2fhdr errors");
8100189325Sdavidch
8101189325Sdavidch	SYSCTL_ADD_INT(ctx, children, OID_AUTO,
8102189325Sdavidch		"l2fhdr_error_sim_count",
8103189325Sdavidch		CTLFLAG_RD, &sc->l2fhdr_error_sim_count,
8104189325Sdavidch		0, "Number of simulated l2_fhdr errors");
8105189325Sdavidch#endif
8106189325Sdavidch
8107189325Sdavidch	SYSCTL_ADD_INT(ctx, children, OID_AUTO,
8108189325Sdavidch		"l2fhdr_error_count",
8109189325Sdavidch		CTLFLAG_RD, &sc->l2fhdr_error_count,
8110189325Sdavidch		0, "Number of l2_fhdr errors");
8111189325Sdavidch
8112189325Sdavidch#ifdef BCE_DEBUG
8113189325Sdavidch	SYSCTL_ADD_INT(ctx, children, OID_AUTO,
8114189325Sdavidch		"mbuf_alloc_failed_sim_control",
8115189325Sdavidch		CTLFLAG_RW, &mbuf_alloc_failed_sim_control,
8116189325Sdavidch		0, "Debug control to force mbuf allocation failures");
8117189325Sdavidch
8118189325Sdavidch	SYSCTL_ADD_INT(ctx, children, OID_AUTO,
8119189325Sdavidch		"mbuf_alloc_failed_sim_count",
8120189325Sdavidch		CTLFLAG_RD, &sc->mbuf_alloc_failed_sim_count,
8121189325Sdavidch		0, "Number of simulated mbuf cluster allocation failures");
8122189325Sdavidch#endif
8123189325Sdavidch
8124189325Sdavidch	SYSCTL_ADD_INT(ctx, children, OID_AUTO,
8125189325Sdavidch		"mbuf_alloc_failed_count",
8126189325Sdavidch		CTLFLAG_RD, &sc->mbuf_alloc_failed_count,
8127189325Sdavidch		0, "Number of mbuf allocation failures");
8128189325Sdavidch
8129189325Sdavidch	SYSCTL_ADD_INT(ctx, children, OID_AUTO,
8130189325Sdavidch		"fragmented_mbuf_count",
8131189325Sdavidch		CTLFLAG_RD, &sc->fragmented_mbuf_count,
8132189325Sdavidch		0, "Number of fragmented mbufs");
8133189325Sdavidch
8134189325Sdavidch#ifdef BCE_DEBUG
8135189325Sdavidch	SYSCTL_ADD_INT(ctx, children, OID_AUTO,
8136189325Sdavidch		"dma_map_addr_failed_sim_control",
8137189325Sdavidch		CTLFLAG_RW, &dma_map_addr_failed_sim_control,
8138189325Sdavidch		0, "Debug control to force DMA mapping failures");
8139189325Sdavidch
8140189325Sdavidch	/* ToDo: Figure out how to update this value in bce_dma_map_addr(). */
8141189325Sdavidch	SYSCTL_ADD_INT(ctx, children, OID_AUTO,
8142189325Sdavidch		"dma_map_addr_failed_sim_count",
8143189325Sdavidch		CTLFLAG_RD, &sc->dma_map_addr_failed_sim_count,
8144189325Sdavidch		0, "Number of simulated DMA mapping failures");
8145189325Sdavidch
8146189325Sdavidch#endif
8147189325Sdavidch
8148189325Sdavidch	SYSCTL_ADD_INT(ctx, children, OID_AUTO,
8149189325Sdavidch		"dma_map_addr_rx_failed_count",
8150189325Sdavidch		CTLFLAG_RD, &sc->dma_map_addr_rx_failed_count,
8151189325Sdavidch		0, "Number of RX DMA mapping failures");
8152189325Sdavidch
8153189325Sdavidch	SYSCTL_ADD_INT(ctx, children, OID_AUTO,
8154189325Sdavidch		"dma_map_addr_tx_failed_count",
8155189325Sdavidch		CTLFLAG_RD, &sc->dma_map_addr_tx_failed_count,
8156189325Sdavidch		0, "Number of TX DMA mapping failures");
8157189325Sdavidch
8158189325Sdavidch#ifdef BCE_DEBUG
8159189325Sdavidch	SYSCTL_ADD_INT(ctx, children, OID_AUTO,
8160189325Sdavidch		"unexpected_attention_sim_control",
8161189325Sdavidch		CTLFLAG_RW, &unexpected_attention_sim_control,
8162189325Sdavidch		0, "Debug control to simulate unexpected attentions");
8163189325Sdavidch
8164189325Sdavidch	SYSCTL_ADD_INT(ctx, children, OID_AUTO,
8165189325Sdavidch		"unexpected_attention_sim_count",
8166189325Sdavidch		CTLFLAG_RW, &sc->unexpected_attention_sim_count,
8167189325Sdavidch		0, "Number of simulated unexpected attentions");
8168189325Sdavidch#endif
8169189325Sdavidch
8170189325Sdavidch	SYSCTL_ADD_INT(ctx, children, OID_AUTO,
8171189325Sdavidch		"unexpected_attention_count",
8172189325Sdavidch		CTLFLAG_RW, &sc->unexpected_attention_count,
8173189325Sdavidch		0, "Number of unexpected attentions");
8174189325Sdavidch
8175189325Sdavidch#ifdef BCE_DEBUG
8176189325Sdavidch	SYSCTL_ADD_INT(ctx, children, OID_AUTO,
8177189325Sdavidch		"debug_bootcode_running_failure",
8178189325Sdavidch		CTLFLAG_RW, &bootcode_running_failure_sim_control,
8179189325Sdavidch		0, "Debug control to force bootcode running failures");
8180189325Sdavidch
8181189325Sdavidch	SYSCTL_ADD_INT(ctx, children, OID_AUTO,
8182157642Sps		"rx_low_watermark",
8183157642Sps		CTLFLAG_RD, &sc->rx_low_watermark,
8184157642Sps		0, "Lowest level of free rx_bd's");
8185157642Sps
8186179771Sdavidch	SYSCTL_ADD_INT(ctx, children, OID_AUTO,
8187169632Sdavidch		"rx_empty_count",
8188169632Sdavidch		CTLFLAG_RD, &sc->rx_empty_count,
8189169632Sdavidch		0, "Number of times the RX chain was empty");
8190169632Sdavidch
8191179771Sdavidch	SYSCTL_ADD_INT(ctx, children, OID_AUTO,
8192157642Sps		"tx_hi_watermark",
8193157642Sps		CTLFLAG_RD, &sc->tx_hi_watermark,
8194157642Sps		0, "Highest level of used tx_bd's");
8195157642Sps
8196179771Sdavidch	SYSCTL_ADD_INT(ctx, children, OID_AUTO,
8197169632Sdavidch		"tx_full_count",
8198169632Sdavidch		CTLFLAG_RD, &sc->tx_full_count,
8199169632Sdavidch		0, "Number of times the TX chain was full");
8200169632Sdavidch
8201179771Sdavidch	SYSCTL_ADD_INT(ctx, children, OID_AUTO,
8202169632Sdavidch		"requested_tso_frames",
8203169632Sdavidch		CTLFLAG_RD, &sc->requested_tso_frames,
8204176448Sdavidch		0, "Number of TSO frames received");
8205171667Sdavidch
8206179771Sdavidch	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
8207176448Sdavidch		"rx_interrupts",
8208176448Sdavidch		CTLFLAG_RD, &sc->rx_interrupts,
8209176448Sdavidch		0, "Number of RX interrupts");
8210171667Sdavidch
8211179771Sdavidch	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
8212176448Sdavidch		"tx_interrupts",
8213176448Sdavidch		CTLFLAG_RD, &sc->tx_interrupts,
8214176448Sdavidch		0, "Number of TX interrupts");
8215171667Sdavidch
8216179771Sdavidch	SYSCTL_ADD_ULONG(ctx, children, OID_AUTO,
8217176448Sdavidch		"rx_intr_time",
8218176448Sdavidch		CTLFLAG_RD, &sc->rx_intr_time,
8219176448Sdavidch		"RX interrupt time");
8220171667Sdavidch
8221179771Sdavidch	SYSCTL_ADD_ULONG(ctx, children, OID_AUTO,
8222176448Sdavidch		"tx_intr_time",
8223176448Sdavidch		CTLFLAG_RD, &sc->tx_intr_time,
8224176448Sdavidch		"TX interrupt time");
8225179771Sdavidch#endif
8226171667Sdavidch
8227179771Sdavidch	SYSCTL_ADD_ULONG(ctx, children, OID_AUTO,
8228157642Sps		"stat_IfHcInOctets",
8229157642Sps		CTLFLAG_RD, &sc->stat_IfHCInOctets,
8230157642Sps		"Bytes received");
8231157642Sps
8232179771Sdavidch	SYSCTL_ADD_ULONG(ctx, children, OID_AUTO,
8233157642Sps		"stat_IfHCInBadOctets",
8234157642Sps		CTLFLAG_RD, &sc->stat_IfHCInBadOctets,
8235157642Sps		"Bad bytes received");
8236157642Sps
8237179771Sdavidch	SYSCTL_ADD_ULONG(ctx, children, OID_AUTO,
8238157642Sps		"stat_IfHCOutOctets",
8239157642Sps		CTLFLAG_RD, &sc->stat_IfHCOutOctets,
8240157642Sps		"Bytes sent");
8241157642Sps
8242179771Sdavidch	SYSCTL_ADD_ULONG(ctx, children, OID_AUTO,
8243157642Sps		"stat_IfHCOutBadOctets",
8244157642Sps		CTLFLAG_RD, &sc->stat_IfHCOutBadOctets,
8245157642Sps		"Bad bytes sent");
8246157642Sps
8247179771Sdavidch	SYSCTL_ADD_ULONG(ctx, children, OID_AUTO,
8248157642Sps		"stat_IfHCInUcastPkts",
8249157642Sps		CTLFLAG_RD, &sc->stat_IfHCInUcastPkts,
8250157642Sps		"Unicast packets received");
8251157642Sps
8252179771Sdavidch	SYSCTL_ADD_ULONG(ctx, children, OID_AUTO,
8253157642Sps		"stat_IfHCInMulticastPkts",
8254157642Sps		CTLFLAG_RD, &sc->stat_IfHCInMulticastPkts,
8255157642Sps		"Multicast packets received");
8256157642Sps
8257179771Sdavidch	SYSCTL_ADD_ULONG(ctx, children, OID_AUTO,
8258157642Sps		"stat_IfHCInBroadcastPkts",
8259157642Sps		CTLFLAG_RD, &sc->stat_IfHCInBroadcastPkts,
8260157642Sps		"Broadcast packets received");
8261157642Sps
8262179771Sdavidch	SYSCTL_ADD_ULONG(ctx, children, OID_AUTO,
8263157642Sps		"stat_IfHCOutUcastPkts",
8264157642Sps		CTLFLAG_RD, &sc->stat_IfHCOutUcastPkts,
8265157642Sps		"Unicast packets sent");
8266157642Sps
8267179771Sdavidch	SYSCTL_ADD_ULONG(ctx, children, OID_AUTO,
8268157642Sps		"stat_IfHCOutMulticastPkts",
8269157642Sps		CTLFLAG_RD, &sc->stat_IfHCOutMulticastPkts,
8270157642Sps		"Multicast packets sent");
8271157642Sps
8272179771Sdavidch	SYSCTL_ADD_ULONG(ctx, children, OID_AUTO,
8273157642Sps		"stat_IfHCOutBroadcastPkts",
8274157642Sps		CTLFLAG_RD, &sc->stat_IfHCOutBroadcastPkts,
8275157642Sps		"Broadcast packets sent");
8276157642Sps
8277179771Sdavidch	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
8278157642Sps		"stat_emac_tx_stat_dot3statsinternalmactransmiterrors",
8279157642Sps		CTLFLAG_RD, &sc->stat_emac_tx_stat_dot3statsinternalmactransmiterrors,
8280157642Sps		0, "Internal MAC transmit errors");
8281157642Sps
8282179771Sdavidch	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
8283157642Sps		"stat_Dot3StatsCarrierSenseErrors",
8284157642Sps		CTLFLAG_RD, &sc->stat_Dot3StatsCarrierSenseErrors,
8285157642Sps		0, "Carrier sense errors");
8286157642Sps
8287179771Sdavidch	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
8288157642Sps		"stat_Dot3StatsFCSErrors",
8289157642Sps		CTLFLAG_RD, &sc->stat_Dot3StatsFCSErrors,
8290157642Sps		0, "Frame check sequence errors");
8291157642Sps
8292179771Sdavidch	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
8293157642Sps		"stat_Dot3StatsAlignmentErrors",
8294157642Sps		CTLFLAG_RD, &sc->stat_Dot3StatsAlignmentErrors,
8295157642Sps		0, "Alignment errors");
8296157642Sps
8297179771Sdavidch	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
8298157642Sps		"stat_Dot3StatsSingleCollisionFrames",
8299157642Sps		CTLFLAG_RD, &sc->stat_Dot3StatsSingleCollisionFrames,
8300157642Sps		0, "Single Collision Frames");
8301157642Sps
8302179771Sdavidch	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
8303157642Sps		"stat_Dot3StatsMultipleCollisionFrames",
8304157642Sps		CTLFLAG_RD, &sc->stat_Dot3StatsMultipleCollisionFrames,
8305157642Sps		0, "Multiple Collision Frames");
8306157642Sps
8307179771Sdavidch	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
8308157642Sps		"stat_Dot3StatsDeferredTransmissions",
8309157642Sps		CTLFLAG_RD, &sc->stat_Dot3StatsDeferredTransmissions,
8310157642Sps		0, "Deferred Transmissions");
8311157642Sps
8312179771Sdavidch	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
8313157642Sps		"stat_Dot3StatsExcessiveCollisions",
8314157642Sps		CTLFLAG_RD, &sc->stat_Dot3StatsExcessiveCollisions,
8315157642Sps		0, "Excessive Collisions");
8316157642Sps
8317179771Sdavidch	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
8318157642Sps		"stat_Dot3StatsLateCollisions",
8319157642Sps		CTLFLAG_RD, &sc->stat_Dot3StatsLateCollisions,
8320157642Sps		0, "Late Collisions");
8321157642Sps
8322179771Sdavidch	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
8323157642Sps		"stat_EtherStatsCollisions",
8324157642Sps		CTLFLAG_RD, &sc->stat_EtherStatsCollisions,
8325157642Sps		0, "Collisions");
8326157642Sps
8327179771Sdavidch	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
8328157642Sps		"stat_EtherStatsFragments",
8329157642Sps		CTLFLAG_RD, &sc->stat_EtherStatsFragments,
8330157642Sps		0, "Fragments");
8331157642Sps
8332179771Sdavidch	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
8333157642Sps		"stat_EtherStatsJabbers",
8334157642Sps		CTLFLAG_RD, &sc->stat_EtherStatsJabbers,
8335157642Sps		0, "Jabbers");
8336157642Sps
8337179771Sdavidch	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
8338157642Sps		"stat_EtherStatsUndersizePkts",
8339157642Sps		CTLFLAG_RD, &sc->stat_EtherStatsUndersizePkts,
8340157642Sps		0, "Undersize packets");
8341157642Sps
8342179771Sdavidch	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
8343189325Sdavidch		"stat_EtherStatsOversizePkts",
8344189325Sdavidch		CTLFLAG_RD, &sc->stat_EtherStatsOversizePkts,
8345189325Sdavidch		0, "stat_EtherStatsOversizePkts");
8346157642Sps
8347179771Sdavidch	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
8348157642Sps		"stat_EtherStatsPktsRx64Octets",
8349157642Sps		CTLFLAG_RD, &sc->stat_EtherStatsPktsRx64Octets,
8350157642Sps		0, "Bytes received in 64 byte packets");
8351157642Sps
8352179771Sdavidch	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
8353157642Sps		"stat_EtherStatsPktsRx65Octetsto127Octets",
8354157642Sps		CTLFLAG_RD, &sc->stat_EtherStatsPktsRx65Octetsto127Octets,
8355157642Sps		0, "Bytes received in 65 to 127 byte packets");
8356157642Sps
8357179771Sdavidch	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
8358157642Sps		"stat_EtherStatsPktsRx128Octetsto255Octets",
8359157642Sps		CTLFLAG_RD, &sc->stat_EtherStatsPktsRx128Octetsto255Octets,
8360157642Sps		0, "Bytes received in 128 to 255 byte packets");
8361157642Sps
8362179771Sdavidch	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
8363157642Sps		"stat_EtherStatsPktsRx256Octetsto511Octets",
8364157642Sps		CTLFLAG_RD, &sc->stat_EtherStatsPktsRx256Octetsto511Octets,
8365157642Sps		0, "Bytes received in 256 to 511 byte packets");
8366157642Sps
8367179771Sdavidch	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
8368157642Sps		"stat_EtherStatsPktsRx512Octetsto1023Octets",
8369157642Sps		CTLFLAG_RD, &sc->stat_EtherStatsPktsRx512Octetsto1023Octets,
8370157642Sps		0, "Bytes received in 512 to 1023 byte packets");
8371157642Sps
8372179771Sdavidch	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
8373157642Sps		"stat_EtherStatsPktsRx1024Octetsto1522Octets",
8374157642Sps		CTLFLAG_RD, &sc->stat_EtherStatsPktsRx1024Octetsto1522Octets,
8375157642Sps		0, "Bytes received in 1024 t0 1522 byte packets");
8376157642Sps
8377179771Sdavidch	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
8378157642Sps		"stat_EtherStatsPktsRx1523Octetsto9022Octets",
8379157642Sps		CTLFLAG_RD, &sc->stat_EtherStatsPktsRx1523Octetsto9022Octets,
8380157642Sps		0, "Bytes received in 1523 to 9022 byte packets");
8381157642Sps
8382179771Sdavidch	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
8383157642Sps		"stat_EtherStatsPktsTx64Octets",
8384157642Sps		CTLFLAG_RD, &sc->stat_EtherStatsPktsTx64Octets,
8385157642Sps		0, "Bytes sent in 64 byte packets");
8386157642Sps
8387179771Sdavidch	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
8388157642Sps		"stat_EtherStatsPktsTx65Octetsto127Octets",
8389157642Sps		CTLFLAG_RD, &sc->stat_EtherStatsPktsTx65Octetsto127Octets,
8390157642Sps		0, "Bytes sent in 65 to 127 byte packets");
8391157642Sps
8392179771Sdavidch	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
8393157642Sps		"stat_EtherStatsPktsTx128Octetsto255Octets",
8394157642Sps		CTLFLAG_RD, &sc->stat_EtherStatsPktsTx128Octetsto255Octets,
8395157642Sps		0, "Bytes sent in 128 to 255 byte packets");
8396157642Sps
8397179771Sdavidch	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
8398157642Sps		"stat_EtherStatsPktsTx256Octetsto511Octets",
8399157642Sps		CTLFLAG_RD, &sc->stat_EtherStatsPktsTx256Octetsto511Octets,
8400157642Sps		0, "Bytes sent in 256 to 511 byte packets");
8401157642Sps
8402179771Sdavidch	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
8403157642Sps		"stat_EtherStatsPktsTx512Octetsto1023Octets",
8404157642Sps		CTLFLAG_RD, &sc->stat_EtherStatsPktsTx512Octetsto1023Octets,
8405157642Sps		0, "Bytes sent in 512 to 1023 byte packets");
8406157642Sps
8407179771Sdavidch	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
8408157642Sps		"stat_EtherStatsPktsTx1024Octetsto1522Octets",
8409157642Sps		CTLFLAG_RD, &sc->stat_EtherStatsPktsTx1024Octetsto1522Octets,
8410157642Sps		0, "Bytes sent in 1024 to 1522 byte packets");
8411157642Sps
8412179771Sdavidch	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
8413157642Sps		"stat_EtherStatsPktsTx1523Octetsto9022Octets",
8414157642Sps		CTLFLAG_RD, &sc->stat_EtherStatsPktsTx1523Octetsto9022Octets,
8415157642Sps		0, "Bytes sent in 1523 to 9022 byte packets");
8416157642Sps
8417179771Sdavidch	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
8418157642Sps		"stat_XonPauseFramesReceived",
8419157642Sps		CTLFLAG_RD, &sc->stat_XonPauseFramesReceived,
8420157642Sps		0, "XON pause frames receved");
8421157642Sps
8422179771Sdavidch	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
8423157642Sps		"stat_XoffPauseFramesReceived",
8424157642Sps		CTLFLAG_RD, &sc->stat_XoffPauseFramesReceived,
8425157642Sps		0, "XOFF pause frames received");
8426157642Sps
8427179771Sdavidch	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
8428157642Sps		"stat_OutXonSent",
8429157642Sps		CTLFLAG_RD, &sc->stat_OutXonSent,
8430157642Sps		0, "XON pause frames sent");
8431157642Sps
8432179771Sdavidch	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
8433157642Sps		"stat_OutXoffSent",
8434157642Sps		CTLFLAG_RD, &sc->stat_OutXoffSent,
8435157642Sps		0, "XOFF pause frames sent");
8436157642Sps
8437179771Sdavidch	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
8438157642Sps		"stat_FlowControlDone",
8439157642Sps		CTLFLAG_RD, &sc->stat_FlowControlDone,
8440157642Sps		0, "Flow control done");
8441157642Sps
8442179771Sdavidch	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
8443157642Sps		"stat_MacControlFramesReceived",
8444157642Sps		CTLFLAG_RD, &sc->stat_MacControlFramesReceived,
8445157642Sps		0, "MAC control frames received");
8446157642Sps
8447179771Sdavidch	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
8448157642Sps		"stat_XoffStateEntered",
8449157642Sps		CTLFLAG_RD, &sc->stat_XoffStateEntered,
8450157642Sps		0, "XOFF state entered");
8451157642Sps
8452179771Sdavidch	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
8453157642Sps		"stat_IfInFramesL2FilterDiscards",
8454157642Sps		CTLFLAG_RD, &sc->stat_IfInFramesL2FilterDiscards,
8455157642Sps		0, "Received L2 packets discarded");
8456157642Sps
8457179771Sdavidch	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
8458157642Sps		"stat_IfInRuleCheckerDiscards",
8459157642Sps		CTLFLAG_RD, &sc->stat_IfInRuleCheckerDiscards,
8460157642Sps		0, "Received packets discarded by rule");
8461157642Sps
8462179771Sdavidch	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
8463157642Sps		"stat_IfInFTQDiscards",
8464157642Sps		CTLFLAG_RD, &sc->stat_IfInFTQDiscards,
8465157642Sps		0, "Received packet FTQ discards");
8466157642Sps
8467179771Sdavidch	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
8468157642Sps		"stat_IfInMBUFDiscards",
8469157642Sps		CTLFLAG_RD, &sc->stat_IfInMBUFDiscards,
8470157642Sps		0, "Received packets discarded due to lack of controller buffer memory");
8471157642Sps
8472179771Sdavidch	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
8473157642Sps		"stat_IfInRuleCheckerP4Hit",
8474157642Sps		CTLFLAG_RD, &sc->stat_IfInRuleCheckerP4Hit,
8475157642Sps		0, "Received packets rule checker hits");
8476157642Sps
8477179771Sdavidch	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
8478157642Sps		"stat_CatchupInRuleCheckerDiscards",
8479157642Sps		CTLFLAG_RD, &sc->stat_CatchupInRuleCheckerDiscards,
8480157642Sps		0, "Received packets discarded in Catchup path");
8481157642Sps
8482179771Sdavidch	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
8483157642Sps		"stat_CatchupInFTQDiscards",
8484157642Sps		CTLFLAG_RD, &sc->stat_CatchupInFTQDiscards,
8485157642Sps		0, "Received packets discarded in FTQ in Catchup path");
8486157642Sps
8487179771Sdavidch	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
8488157642Sps		"stat_CatchupInMBUFDiscards",
8489157642Sps		CTLFLAG_RD, &sc->stat_CatchupInMBUFDiscards,
8490157642Sps		0, "Received packets discarded in controller buffer memory in Catchup path");
8491157642Sps
8492179771Sdavidch	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
8493157642Sps		"stat_CatchupInRuleCheckerP4Hit",
8494157642Sps		CTLFLAG_RD, &sc->stat_CatchupInRuleCheckerP4Hit,
8495157642Sps		0, "Received packets rule checker hits in Catchup path");
8496157642Sps
8497179771Sdavidch	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
8498169271Sdavidch		"com_no_buffers",
8499169271Sdavidch		CTLFLAG_RD, &sc->com_no_buffers,
8500169271Sdavidch		0, "Valid packets received but no RX buffers available");
8501169271Sdavidch
8502157642Sps#ifdef BCE_DEBUG
8503157642Sps	SYSCTL_ADD_PROC(ctx, children, OID_AUTO,
8504157642Sps		"driver_state", CTLTYPE_INT | CTLFLAG_RW,
8505157642Sps		(void *)sc, 0,
8506157642Sps		bce_sysctl_driver_state, "I", "Drive state information");
8507157642Sps
8508157642Sps	SYSCTL_ADD_PROC(ctx, children, OID_AUTO,
8509157642Sps		"hw_state", CTLTYPE_INT | CTLFLAG_RW,
8510157642Sps		(void *)sc, 0,
8511157642Sps		bce_sysctl_hw_state, "I", "Hardware state information");
8512157642Sps
8513157642Sps	SYSCTL_ADD_PROC(ctx, children, OID_AUTO,
8514170810Sdavidch		"bc_state", CTLTYPE_INT | CTLFLAG_RW,
8515170810Sdavidch		(void *)sc, 0,
8516170810Sdavidch		bce_sysctl_bc_state, "I", "Bootcode state information");
8517170810Sdavidch
8518170810Sdavidch	SYSCTL_ADD_PROC(ctx, children, OID_AUTO,
8519157642Sps		"dump_rx_chain", CTLTYPE_INT | CTLFLAG_RW,
8520157642Sps		(void *)sc, 0,
8521157642Sps		bce_sysctl_dump_rx_chain, "I", "Dump rx_bd chain");
8522157642Sps
8523157642Sps	SYSCTL_ADD_PROC(ctx, children, OID_AUTO,
8524169271Sdavidch		"dump_tx_chain", CTLTYPE_INT | CTLFLAG_RW,
8525169271Sdavidch		(void *)sc, 0,
8526169271Sdavidch		bce_sysctl_dump_tx_chain, "I", "Dump tx_bd chain");
8527169271Sdavidch
8528198320Sstas#ifdef BCE_JUMBO_HDRSPLIT
8529169271Sdavidch	SYSCTL_ADD_PROC(ctx, children, OID_AUTO,
8530176448Sdavidch		"dump_pg_chain", CTLTYPE_INT | CTLFLAG_RW,
8531176448Sdavidch		(void *)sc, 0,
8532179771Sdavidch		bce_sysctl_dump_pg_chain, "I", "Dump page chain");
8533179695Sdavidch#endif
8534179771Sdavidch	SYSCTL_ADD_PROC(ctx, children, OID_AUTO,
8535179771Sdavidch		"dump_ctx", CTLTYPE_INT | CTLFLAG_RW,
8536179771Sdavidch		(void *)sc, 0,
8537179771Sdavidch		bce_sysctl_dump_ctx, "I", "Dump context memory");
8538176448Sdavidch
8539176448Sdavidch	SYSCTL_ADD_PROC(ctx, children, OID_AUTO,
8540157642Sps		"breakpoint", CTLTYPE_INT | CTLFLAG_RW,
8541157642Sps		(void *)sc, 0,
8542157642Sps		bce_sysctl_breakpoint, "I", "Driver breakpoint");
8543170392Sdavidch
8544179771Sdavidch	SYSCTL_ADD_PROC(ctx, children, OID_AUTO,
8545179771Sdavidch		"reg_read", CTLTYPE_INT | CTLFLAG_RW,
8546179771Sdavidch		(void *)sc, 0,
8547169632Sdavidch		bce_sysctl_reg_read, "I", "Register read");
8548169271Sdavidch
8549179771Sdavidch	SYSCTL_ADD_PROC(ctx, children, OID_AUTO,
8550179771Sdavidch		"nvram_read", CTLTYPE_INT | CTLFLAG_RW,
8551179771Sdavidch		(void *)sc, 0,
8552179771Sdavidch		bce_sysctl_nvram_read, "I", "NVRAM read");
8553179771Sdavidch
8554179771Sdavidch	SYSCTL_ADD_PROC(ctx, children, OID_AUTO,
8555179771Sdavidch		"phy_read", CTLTYPE_INT | CTLFLAG_RW,
8556179771Sdavidch		(void *)sc, 0,
8557169632Sdavidch		bce_sysctl_phy_read, "I", "PHY register read");
8558169632Sdavidch
8559157642Sps#endif
8560157642Sps
8561179771Sdavidch	DBEXIT(BCE_VERBOSE_MISC);
8562157642Sps}
8563157642Sps
8564157642Sps
8565157642Sps/****************************************************************************/
8566157642Sps/* BCE Debug Routines                                                       */
8567157642Sps/****************************************************************************/
8568157642Sps#ifdef BCE_DEBUG
8569170392Sdavidch
8570169632Sdavidch/****************************************************************************/
8571169632Sdavidch/* Freezes the controller to allow for a cohesive state dump.               */
8572169632Sdavidch/*                                                                          */
8573169632Sdavidch/* Returns:                                                                 */
8574169632Sdavidch/*   Nothing.                                                               */
8575169632Sdavidch/****************************************************************************/
8576169632Sdavidchstatic void
8577169632Sdavidchbce_freeze_controller(struct bce_softc *sc)
8578169632Sdavidch{
8579169632Sdavidch	u32 val;
8580170392Sdavidch	val = REG_RD(sc, BCE_MISC_COMMAND);
8581170392Sdavidch	val |= BCE_MISC_COMMAND_DISABLE_ALL;
8582169632Sdavidch	REG_WR(sc, BCE_MISC_COMMAND, val);
8583170392Sdavidch}
8584157642Sps
8585170392Sdavidch
8586157642Sps/****************************************************************************/
8587170392Sdavidch/* Unfreezes the controller after a freeze operation.  This may not always  */
8588169632Sdavidch/* work and the controller will require a reset!                            */
8589169632Sdavidch/*                                                                          */
8590169632Sdavidch/* Returns:                                                                 */
8591169632Sdavidch/*   Nothing.                                                               */
8592169632Sdavidch/****************************************************************************/
8593169632Sdavidchstatic void
8594169632Sdavidchbce_unfreeze_controller(struct bce_softc *sc)
8595169632Sdavidch{
8596169632Sdavidch	u32 val;
8597170392Sdavidch	val = REG_RD(sc, BCE_MISC_COMMAND);
8598170392Sdavidch	val |= BCE_MISC_COMMAND_ENABLE_ALL;
8599169632Sdavidch	REG_WR(sc, BCE_MISC_COMMAND, val);
8600170392Sdavidch}
8601170392Sdavidch
8602182293Sdavidch
8603169632Sdavidch/****************************************************************************/
8604182293Sdavidch/* Prints out Ethernet frame information from an mbuf.                      */
8605182293Sdavidch/*                                                                          */
8606182293Sdavidch/* Partially decode an Ethernet frame to look at some important headers.    */
8607182293Sdavidch/*                                                                          */
8608182293Sdavidch/* Returns:                                                                 */
8609182293Sdavidch/*   Nothing.                                                               */
8610182293Sdavidch/****************************************************************************/
8611182293Sdavidchstatic void
8612182293Sdavidchbce_dump_enet(struct bce_softc *sc, struct mbuf *m)
8613182293Sdavidch{
8614182293Sdavidch	struct ether_vlan_header *eh;
8615182293Sdavidch	u16 etype;
8616182293Sdavidch	int ehlen;
8617182293Sdavidch	struct ip *ip;
8618182293Sdavidch	struct tcphdr *th;
8619182293Sdavidch	struct udphdr *uh;
8620182293Sdavidch	struct arphdr *ah;
8621182293Sdavidch
8622182293Sdavidch		BCE_PRINTF(
8623182293Sdavidch			"-----------------------------"
8624182293Sdavidch			" Frame Decode "
8625182293Sdavidch			"-----------------------------\n");
8626182293Sdavidch
8627182293Sdavidch	eh = mtod(m, struct ether_vlan_header *);
8628182293Sdavidch
8629182293Sdavidch	/* Handle VLAN encapsulation if present. */
8630182293Sdavidch	if (eh->evl_encap_proto == htons(ETHERTYPE_VLAN)) {
8631182293Sdavidch		etype = ntohs(eh->evl_proto);
8632182293Sdavidch		ehlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN;
8633182293Sdavidch	} else {
8634182293Sdavidch		etype = ntohs(eh->evl_encap_proto);
8635182293Sdavidch		ehlen = ETHER_HDR_LEN;
8636182293Sdavidch	}
8637182293Sdavidch
8638182293Sdavidch	/* ToDo: Add VLAN output. */
8639182293Sdavidch	BCE_PRINTF("enet: dest = %6D, src = %6D, type = 0x%04X, hlen = %d\n",
8640182293Sdavidch		eh->evl_dhost, ":", eh->evl_shost, ":", etype, ehlen);
8641182293Sdavidch
8642182293Sdavidch	switch (etype) {
8643182293Sdavidch		case ETHERTYPE_IP:
8644182293Sdavidch			ip = (struct ip *)(m->m_data + ehlen);
8645182293Sdavidch			BCE_PRINTF("--ip: dest = 0x%08X , src = 0x%08X, len = %d bytes, "
8646182293Sdavidch				"protocol = 0x%02X, xsum = 0x%04X\n",
8647182293Sdavidch				ntohl(ip->ip_dst.s_addr), ntohl(ip->ip_src.s_addr),
8648182293Sdavidch				ntohs(ip->ip_len), ip->ip_p, ntohs(ip->ip_sum));
8649182293Sdavidch
8650182293Sdavidch			switch (ip->ip_p) {
8651182293Sdavidch				case IPPROTO_TCP:
8652182293Sdavidch					th = (struct tcphdr *)((caddr_t)ip + (ip->ip_hl << 2));
8653182293Sdavidch					BCE_PRINTF("-tcp: dest = %d, src = %d, hlen = %d bytes, "
8654182293Sdavidch						"flags = 0x%b, csum = 0x%04X\n",
8655182293Sdavidch						ntohs(th->th_dport), ntohs(th->th_sport), (th->th_off << 2),
8656182293Sdavidch						th->th_flags, "\20\10CWR\07ECE\06URG\05ACK\04PSH\03RST\02SYN\01FIN",
8657182293Sdavidch						ntohs(th->th_sum));
8658182293Sdavidch					break;
8659182293Sdavidch				case IPPROTO_UDP:
8660182293Sdavidch        		    uh = (struct udphdr *)((caddr_t)ip + (ip->ip_hl << 2));
8661182293Sdavidch					BCE_PRINTF("-udp: dest = %d, src = %d, len = %d bytes, "
8662182293Sdavidch						"csum = 0x%04X\n", ntohs(uh->uh_dport), ntohs(uh->uh_sport),
8663182293Sdavidch						ntohs(uh->uh_ulen), ntohs(uh->uh_sum));
8664182293Sdavidch					break;
8665182293Sdavidch				case IPPROTO_ICMP:
8666182293Sdavidch					BCE_PRINTF("icmp:\n");
8667182293Sdavidch					break;
8668182293Sdavidch				default:
8669182293Sdavidch					BCE_PRINTF("----: Other IP protocol.\n");
8670182293Sdavidch			}
8671182293Sdavidch			break;
8672182293Sdavidch		case ETHERTYPE_IPV6:
8673182293Sdavidch			BCE_PRINTF("ipv6: No decode supported.\n");
8674182293Sdavidch			break;
8675182293Sdavidch		case ETHERTYPE_ARP:
8676182293Sdavidch			BCE_PRINTF("-arp: ");
8677182293Sdavidch			ah = (struct arphdr *) (m->m_data + ehlen);
8678182293Sdavidch			switch (ntohs(ah->ar_op)) {
8679182293Sdavidch				case ARPOP_REVREQUEST:
8680182293Sdavidch					printf("reverse ARP request\n");
8681182293Sdavidch					break;
8682182293Sdavidch				case ARPOP_REVREPLY:
8683182293Sdavidch					printf("reverse ARP reply\n");
8684182293Sdavidch					break;
8685182293Sdavidch				case ARPOP_REQUEST:
8686182293Sdavidch					printf("ARP request\n");
8687182293Sdavidch					break;
8688182293Sdavidch				case ARPOP_REPLY:
8689182293Sdavidch					printf("ARP reply\n");
8690182293Sdavidch					break;
8691182293Sdavidch				default:
8692182293Sdavidch					printf("other ARP operation\n");
8693182293Sdavidch			}
8694182293Sdavidch			break;
8695182293Sdavidch		default:
8696182293Sdavidch			BCE_PRINTF("----: Other protocol.\n");
8697182293Sdavidch	}
8698182293Sdavidch
8699182293Sdavidch	BCE_PRINTF(
8700182293Sdavidch		"-----------------------------"
8701182293Sdavidch		"--------------"
8702182293Sdavidch		"-----------------------------\n");
8703182293Sdavidch}
8704182293Sdavidch
8705182293Sdavidch
8706182293Sdavidch/****************************************************************************/
8707157642Sps/* Prints out information about an mbuf.                                    */
8708157642Sps/*                                                                          */
8709157642Sps/* Returns:                                                                 */
8710157642Sps/*   Nothing.                                                               */
8711157642Sps/****************************************************************************/
8712179771Sdavidchstatic __attribute__ ((noinline)) void
8713157642Spsbce_dump_mbuf(struct bce_softc *sc, struct mbuf *m)
8714157642Sps{
8715157642Sps	struct mbuf *mp = m;
8716157642Sps
8717157642Sps	if (m == NULL) {
8718169632Sdavidch		BCE_PRINTF("mbuf: null pointer\n");
8719157642Sps		return;
8720157642Sps	}
8721157642Sps
8722157642Sps	while (mp) {
8723179771Sdavidch		BCE_PRINTF("mbuf: %p, m_len = %d, m_flags = 0x%b, m_data = %p\n",
8724179771Sdavidch			mp, mp->m_len, mp->m_flags,
8725176448Sdavidch			"\20\1M_EXT\2M_PKTHDR\3M_EOR\4M_RDONLY",
8726176448Sdavidch			mp->m_data);
8727157642Sps
8728170392Sdavidch		if (mp->m_flags & M_PKTHDR) {
8729179771Sdavidch			BCE_PRINTF("- m_pkthdr: len = %d, flags = 0x%b, csum_flags = %b\n",
8730176448Sdavidch				mp->m_pkthdr.len, mp->m_flags,
8731176448Sdavidch				"\20\12M_BCAST\13M_MCAST\14M_FRAG\15M_FIRSTFRAG"
8732176448Sdavidch				"\16M_LASTFRAG\21M_VLANTAG\22M_PROMISC\23M_NOFREE",
8733176448Sdavidch				mp->m_pkthdr.csum_flags,
8734176448Sdavidch				"\20\1CSUM_IP\2CSUM_TCP\3CSUM_UDP\4CSUM_IP_FRAGS"
8735176448Sdavidch				"\5CSUM_FRAGMENT\6CSUM_TSO\11CSUM_IP_CHECKED"
8736176448Sdavidch				"\12CSUM_IP_VALID\13CSUM_DATA_VALID\14CSUM_PSEUDO_HDR");
8737170392Sdavidch		}
8738169632Sdavidch
8739157642Sps		if (mp->m_flags & M_EXT) {
8740179771Sdavidch			BCE_PRINTF("- m_ext: %p, ext_size = %d, type = ",
8741176448Sdavidch				mp->m_ext.ext_buf, mp->m_ext.ext_size);
8742170392Sdavidch			switch (mp->m_ext.ext_type) {
8743170392Sdavidch				case EXT_CLUSTER:    printf("EXT_CLUSTER\n"); break;
8744170392Sdavidch				case EXT_SFBUF:      printf("EXT_SFBUF\n"); break;
8745170392Sdavidch				case EXT_JUMBO9:     printf("EXT_JUMBO9\n"); break;
8746170392Sdavidch				case EXT_JUMBO16:    printf("EXT_JUMBO16\n"); break;
8747170392Sdavidch				case EXT_PACKET:     printf("EXT_PACKET\n"); break;
8748170392Sdavidch				case EXT_MBUF:       printf("EXT_MBUF\n"); break;
8749170392Sdavidch				case EXT_NET_DRV:    printf("EXT_NET_DRV\n"); break;
8750170392Sdavidch				case EXT_MOD_TYPE:   printf("EXT_MDD_TYPE\n"); break;
8751170392Sdavidch				case EXT_DISPOSABLE: printf("EXT_DISPOSABLE\n"); break;
8752170392Sdavidch				case EXT_EXTREF:     printf("EXT_EXTREF\n"); break;
8753170392Sdavidch				default:             printf("UNKNOWN\n");
8754170392Sdavidch			}
8755157642Sps		}
8756157642Sps
8757157642Sps		mp = mp->m_next;
8758157642Sps	}
8759157642Sps}
8760157642Sps
8761157642Sps
8762157642Sps/****************************************************************************/
8763157642Sps/* Prints out the mbufs in the TX mbuf chain.                               */
8764157642Sps/*                                                                          */
8765157642Sps/* Returns:                                                                 */
8766157642Sps/*   Nothing.                                                               */
8767157642Sps/****************************************************************************/
8768179771Sdavidchstatic __attribute__ ((noinline)) void
8769176448Sdavidchbce_dump_tx_mbuf_chain(struct bce_softc *sc, u16 chain_prod, int count)
8770157642Sps{
8771157642Sps	struct mbuf *m;
8772157642Sps
8773169271Sdavidch	BCE_PRINTF(
8774157642Sps		"----------------------------"
8775157642Sps		"  tx mbuf data  "
8776157642Sps		"----------------------------\n");
8777157642Sps
8778157642Sps	for (int i = 0; i < count; i++) {
8779157642Sps	 	m = sc->tx_mbuf_ptr[chain_prod];
8780176448Sdavidch		BCE_PRINTF("txmbuf[0x%04X]\n", chain_prod);
8781157642Sps		bce_dump_mbuf(sc, m);
8782157642Sps		chain_prod = TX_CHAIN_IDX(NEXT_TX_BD(chain_prod));
8783157642Sps	}
8784157642Sps
8785169271Sdavidch	BCE_PRINTF(
8786157642Sps		"----------------------------"
8787157642Sps		"----------------"
8788157642Sps		"----------------------------\n");
8789157642Sps}
8790157642Sps
8791157642Sps
8792169271Sdavidch/****************************************************************************/
8793169271Sdavidch/* Prints out the mbufs in the RX mbuf chain.                               */
8794169271Sdavidch/*                                                                          */
8795169271Sdavidch/* Returns:                                                                 */
8796169271Sdavidch/*   Nothing.                                                               */
8797169271Sdavidch/****************************************************************************/
8798179771Sdavidchstatic __attribute__ ((noinline)) void
8799176448Sdavidchbce_dump_rx_mbuf_chain(struct bce_softc *sc, u16 chain_prod, int count)
8800157642Sps{
8801157642Sps	struct mbuf *m;
8802157642Sps
8803169271Sdavidch	BCE_PRINTF(
8804157642Sps		"----------------------------"
8805157642Sps		"  rx mbuf data  "
8806157642Sps		"----------------------------\n");
8807157642Sps
8808157642Sps	for (int i = 0; i < count; i++) {
8809157642Sps	 	m = sc->rx_mbuf_ptr[chain_prod];
8810169271Sdavidch		BCE_PRINTF("rxmbuf[0x%04X]\n", chain_prod);
8811157642Sps		bce_dump_mbuf(sc, m);
8812157642Sps		chain_prod = RX_CHAIN_IDX(NEXT_RX_BD(chain_prod));
8813157642Sps	}
8814157642Sps
8815157642Sps
8816169271Sdavidch	BCE_PRINTF(
8817157642Sps		"----------------------------"
8818157642Sps		"----------------"
8819157642Sps		"----------------------------\n");
8820157642Sps}
8821157642Sps
8822157642Sps
8823198320Sstas#ifdef BCE_JUMBO_HDRSPLIT
8824169271Sdavidch/****************************************************************************/
8825176448Sdavidch/* Prints out the mbufs in the mbuf page chain.                             */
8826176448Sdavidch/*                                                                          */
8827176448Sdavidch/* Returns:                                                                 */
8828176448Sdavidch/*   Nothing.                                                               */
8829176448Sdavidch/****************************************************************************/
8830179771Sdavidchstatic __attribute__ ((noinline)) void
8831176448Sdavidchbce_dump_pg_mbuf_chain(struct bce_softc *sc, u16 chain_prod, int count)
8832176448Sdavidch{
8833176448Sdavidch	struct mbuf *m;
8834176448Sdavidch
8835176448Sdavidch	BCE_PRINTF(
8836176448Sdavidch		"----------------------------"
8837176448Sdavidch		"  pg mbuf data  "
8838176448Sdavidch		"----------------------------\n");
8839176448Sdavidch
8840176448Sdavidch	for (int i = 0; i < count; i++) {
8841176448Sdavidch	 	m = sc->pg_mbuf_ptr[chain_prod];
8842176448Sdavidch		BCE_PRINTF("pgmbuf[0x%04X]\n", chain_prod);
8843176448Sdavidch		bce_dump_mbuf(sc, m);
8844176448Sdavidch		chain_prod = PG_CHAIN_IDX(NEXT_PG_BD(chain_prod));
8845176448Sdavidch	}
8846176448Sdavidch
8847176448Sdavidch
8848176448Sdavidch	BCE_PRINTF(
8849176448Sdavidch		"----------------------------"
8850176448Sdavidch		"----------------"
8851176448Sdavidch		"----------------------------\n");
8852179771Sdavidch}
8853179695Sdavidch#endif
8854176448Sdavidch
8855176448Sdavidch
8856176448Sdavidch/****************************************************************************/
8857169271Sdavidch/* Prints out a tx_bd structure.                                            */
8858169271Sdavidch/*                                                                          */
8859169271Sdavidch/* Returns:                                                                 */
8860169271Sdavidch/*   Nothing.                                                               */
8861169271Sdavidch/****************************************************************************/
8862179771Sdavidchstatic __attribute__ ((noinline)) void
8863157642Spsbce_dump_txbd(struct bce_softc *sc, int idx, struct tx_bd *txbd)
8864157642Sps{
8865157642Sps	if (idx > MAX_TX_BD)
8866157642Sps		/* Index out of range. */
8867169271Sdavidch		BCE_PRINTF("tx_bd[0x%04X]: Invalid tx_bd index!\n", idx);
8868157642Sps	else if ((idx & USABLE_TX_BD_PER_PAGE) == USABLE_TX_BD_PER_PAGE)
8869157642Sps		/* TX Chain page pointer. */
8870179771Sdavidch		BCE_PRINTF("tx_bd[0x%04X]: haddr = 0x%08X:%08X, chain page pointer\n",
8871157642Sps			idx, txbd->tx_bd_haddr_hi, txbd->tx_bd_haddr_lo);
8872169271Sdavidch	else {
8873169271Sdavidch			/* Normal tx_bd entry. */
8874169271Sdavidch			BCE_PRINTF("tx_bd[0x%04X]: haddr = 0x%08X:%08X, nbytes = 0x%08X, "
8875179771Sdavidch				"vlan tag= 0x%04X, flags = 0x%04X (", idx,
8876169271Sdavidch				txbd->tx_bd_haddr_hi, txbd->tx_bd_haddr_lo,
8877169271Sdavidch				txbd->tx_bd_mss_nbytes, txbd->tx_bd_vlan_tag,
8878169271Sdavidch				txbd->tx_bd_flags);
8879170392Sdavidch
8880170392Sdavidch			if (txbd->tx_bd_flags & TX_BD_FLAGS_CONN_FAULT)
8881170392Sdavidch				printf(" CONN_FAULT");
8882170392Sdavidch
8883170392Sdavidch			if (txbd->tx_bd_flags & TX_BD_FLAGS_TCP_UDP_CKSUM)
8884170392Sdavidch				printf(" TCP_UDP_CKSUM");
8885170392Sdavidch
8886170392Sdavidch			if (txbd->tx_bd_flags & TX_BD_FLAGS_IP_CKSUM)
8887170392Sdavidch				printf(" IP_CKSUM");
8888170392Sdavidch
8889170392Sdavidch			if (txbd->tx_bd_flags & TX_BD_FLAGS_VLAN_TAG)
8890170392Sdavidch				printf("  VLAN");
8891170392Sdavidch
8892170392Sdavidch			if (txbd->tx_bd_flags & TX_BD_FLAGS_COAL_NOW)
8893170392Sdavidch				printf(" COAL_NOW");
8894170392Sdavidch
8895170392Sdavidch			if (txbd->tx_bd_flags & TX_BD_FLAGS_DONT_GEN_CRC)
8896170392Sdavidch				printf(" DONT_GEN_CRC");
8897170392Sdavidch
8898170392Sdavidch			if (txbd->tx_bd_flags & TX_BD_FLAGS_START)
8899170392Sdavidch				printf(" START");
8900170392Sdavidch
8901170392Sdavidch			if (txbd->tx_bd_flags & TX_BD_FLAGS_END)
8902170392Sdavidch				printf(" END");
8903170392Sdavidch
8904170392Sdavidch			if (txbd->tx_bd_flags & TX_BD_FLAGS_SW_LSO)
8905170392Sdavidch				printf(" LSO");
8906170392Sdavidch
8907170392Sdavidch			if (txbd->tx_bd_flags & TX_BD_FLAGS_SW_OPTION_WORD)
8908170392Sdavidch				printf(" OPTION_WORD");
8909170392Sdavidch
8910170392Sdavidch			if (txbd->tx_bd_flags & TX_BD_FLAGS_SW_FLAGS)
8911170392Sdavidch				printf(" FLAGS");
8912170392Sdavidch
8913170392Sdavidch			if (txbd->tx_bd_flags & TX_BD_FLAGS_SW_SNAP)
8914170392Sdavidch				printf(" SNAP");
8915170392Sdavidch
8916170392Sdavidch			printf(" )\n");
8917170392Sdavidch		}
8918179771Sdavidch
8919157642Sps}
8920157642Sps
8921157642Sps
8922169271Sdavidch/****************************************************************************/
8923169271Sdavidch/* Prints out a rx_bd structure.                                            */
8924169271Sdavidch/*                                                                          */
8925169271Sdavidch/* Returns:                                                                 */
8926169271Sdavidch/*   Nothing.                                                               */
8927169271Sdavidch/****************************************************************************/
8928179771Sdavidchstatic __attribute__ ((noinline)) void
8929157642Spsbce_dump_rxbd(struct bce_softc *sc, int idx, struct rx_bd *rxbd)
8930157642Sps{
8931157642Sps	if (idx > MAX_RX_BD)
8932157642Sps		/* Index out of range. */
8933169271Sdavidch		BCE_PRINTF("rx_bd[0x%04X]: Invalid rx_bd index!\n", idx);
8934157642Sps	else if ((idx & USABLE_RX_BD_PER_PAGE) == USABLE_RX_BD_PER_PAGE)
8935176448Sdavidch		/* RX Chain page pointer. */
8936179771Sdavidch		BCE_PRINTF("rx_bd[0x%04X]: haddr = 0x%08X:%08X, chain page pointer\n",
8937157642Sps			idx, rxbd->rx_bd_haddr_hi, rxbd->rx_bd_haddr_lo);
8938157642Sps	else
8939176448Sdavidch		/* Normal rx_bd entry. */
8940169271Sdavidch		BCE_PRINTF("rx_bd[0x%04X]: haddr = 0x%08X:%08X, nbytes = 0x%08X, "
8941179771Sdavidch			"flags = 0x%08X\n", idx,
8942157642Sps			rxbd->rx_bd_haddr_hi, rxbd->rx_bd_haddr_lo,
8943157642Sps			rxbd->rx_bd_len, rxbd->rx_bd_flags);
8944157642Sps}
8945157642Sps
8946157642Sps
8947198320Sstas#ifdef BCE_JUMBO_HDRSPLIT
8948169271Sdavidch/****************************************************************************/
8949176448Sdavidch/* Prints out a rx_bd structure in the page chain.                          */
8950176448Sdavidch/*                                                                          */
8951176448Sdavidch/* Returns:                                                                 */
8952176448Sdavidch/*   Nothing.                                                               */
8953176448Sdavidch/****************************************************************************/
8954179771Sdavidchstatic __attribute__ ((noinline)) void
8955176448Sdavidchbce_dump_pgbd(struct bce_softc *sc, int idx, struct rx_bd *pgbd)
8956176448Sdavidch{
8957176448Sdavidch	if (idx > MAX_PG_BD)
8958176448Sdavidch		/* Index out of range. */
8959176448Sdavidch		BCE_PRINTF("pg_bd[0x%04X]: Invalid pg_bd index!\n", idx);
8960176448Sdavidch	else if ((idx & USABLE_PG_BD_PER_PAGE) == USABLE_PG_BD_PER_PAGE)
8961176448Sdavidch		/* Page Chain page pointer. */
8962179771Sdavidch		BCE_PRINTF("px_bd[0x%04X]: haddr = 0x%08X:%08X, chain page pointer\n",
8963176448Sdavidch			idx, pgbd->rx_bd_haddr_hi, pgbd->rx_bd_haddr_lo);
8964176448Sdavidch	else
8965176448Sdavidch		/* Normal rx_bd entry. */
8966176448Sdavidch		BCE_PRINTF("pg_bd[0x%04X]: haddr = 0x%08X:%08X, nbytes = 0x%08X, "
8967179771Sdavidch			"flags = 0x%08X\n", idx,
8968176448Sdavidch			pgbd->rx_bd_haddr_hi, pgbd->rx_bd_haddr_lo,
8969176448Sdavidch			pgbd->rx_bd_len, pgbd->rx_bd_flags);
8970179771Sdavidch}
8971179695Sdavidch#endif
8972176448Sdavidch
8973176448Sdavidch
8974176448Sdavidch/****************************************************************************/
8975170810Sdavidch/* Prints out a l2_fhdr structure.                                          */
8976169271Sdavidch/*                                                                          */
8977169271Sdavidch/* Returns:                                                                 */
8978169271Sdavidch/*   Nothing.                                                               */
8979169271Sdavidch/****************************************************************************/
8980179771Sdavidchstatic __attribute__ ((noinline)) void
8981157642Spsbce_dump_l2fhdr(struct bce_softc *sc, int idx, struct l2_fhdr *l2fhdr)
8982157642Sps{
8983176448Sdavidch	BCE_PRINTF("l2_fhdr[0x%04X]: status = 0x%b, "
8984176448Sdavidch		"pkt_len = %d, vlan = 0x%04x, ip_xsum/hdr_len = 0x%04X, "
8985157642Sps		"tcp_udp_xsum = 0x%04X\n", idx,
8986179771Sdavidch		l2fhdr->l2_fhdr_status, BCE_L2FHDR_PRINTFB,
8987179771Sdavidch		l2fhdr->l2_fhdr_pkt_len, l2fhdr->l2_fhdr_vlan_tag,
8988176448Sdavidch		l2fhdr->l2_fhdr_ip_xsum, l2fhdr->l2_fhdr_tcp_udp_xsum);
8989157642Sps}
8990157642Sps
8991157642Sps
8992169271Sdavidch/****************************************************************************/
8993179771Sdavidch/* Prints out context memory info.  (Only useful for CID 0 to 16.)          */
8994176448Sdavidch/*                                                                          */
8995176448Sdavidch/* Returns:                                                                 */
8996176448Sdavidch/*   Nothing.                                                               */
8997176448Sdavidch/****************************************************************************/
8998179771Sdavidchstatic __attribute__ ((noinline)) void
8999176448Sdavidchbce_dump_ctx(struct bce_softc *sc, u16 cid)
9000176448Sdavidch{
9001179771Sdavidch	if (cid <= TX_CID) {
9002176448Sdavidch		BCE_PRINTF(
9003176448Sdavidch			"----------------------------"
9004176448Sdavidch			"    CTX Data    "
9005176448Sdavidch			"----------------------------\n");
9006178132Sdavidch
9007176448Sdavidch		BCE_PRINTF("     0x%04X - (CID) Context ID\n", cid);
9008182293Sdavidch
9009179771Sdavidch		if (cid == RX_CID) {
9010182293Sdavidch			BCE_PRINTF(" 0x%08X - (L2CTX_RX_HOST_BDIDX) host rx "
9011182293Sdavidch				"producer index\n",
9012182293Sdavidch				CTX_RD(sc, GET_CID_ADDR(cid), BCE_L2CTX_RX_HOST_BDIDX));
9013182293Sdavidch			BCE_PRINTF(" 0x%08X - (L2CTX_RX_HOST_BSEQ) host byte sequence\n",
9014182293Sdavidch				CTX_RD(sc, GET_CID_ADDR(cid), BCE_L2CTX_RX_HOST_BSEQ));
9015182293Sdavidch			BCE_PRINTF(" 0x%08X - (L2CTX_RX_NX_BSEQ) h/w byte sequence\n",
9016182293Sdavidch				CTX_RD(sc, GET_CID_ADDR(cid), BCE_L2CTX_RX_NX_BSEQ));
9017182293Sdavidch			BCE_PRINTF(" 0x%08X - (L2CTX_RX_NX_BDHADDR_HI) h/w buffer "
9018182293Sdavidch				"descriptor address\n",
9019182293Sdavidch 				CTX_RD(sc, GET_CID_ADDR(cid), BCE_L2CTX_RX_NX_BDHADDR_HI));
9020182293Sdavidch			BCE_PRINTF(" 0x%08X - (L2CTX_RX_NX_BDHADDR_LO) h/w buffer "
9021182293Sdavidch				"descriptor address\n",
9022182293Sdavidch				CTX_RD(sc, GET_CID_ADDR(cid), BCE_L2CTX_RX_NX_BDHADDR_LO));
9023182293Sdavidch			BCE_PRINTF(" 0x%08X - (L2CTX_RX_NX_BDIDX) h/w rx consumer index\n",
9024182293Sdavidch				CTX_RD(sc, GET_CID_ADDR(cid), BCE_L2CTX_RX_NX_BDIDX));
9025182293Sdavidch			BCE_PRINTF(" 0x%08X - (L2CTX_RX_HOST_PG_BDIDX) host page "
9026182293Sdavidch				"producer index\n",
9027182293Sdavidch				CTX_RD(sc, GET_CID_ADDR(cid), BCE_L2CTX_RX_HOST_PG_BDIDX));
9028182293Sdavidch			BCE_PRINTF(" 0x%08X - (L2CTX_RX_PG_BUF_SIZE) host rx_bd/page "
9029182293Sdavidch				"buffer size\n",
9030182293Sdavidch				CTX_RD(sc, GET_CID_ADDR(cid), BCE_L2CTX_RX_PG_BUF_SIZE));
9031182293Sdavidch			BCE_PRINTF(" 0x%08X - (L2CTX_RX_NX_PG_BDHADDR_HI) h/w page "
9032182293Sdavidch				"chain address\n",
9033182293Sdavidch				CTX_RD(sc, GET_CID_ADDR(cid), BCE_L2CTX_RX_NX_PG_BDHADDR_HI));
9034182293Sdavidch			BCE_PRINTF(" 0x%08X - (L2CTX_RX_NX_PG_BDHADDR_LO) h/w page "
9035182293Sdavidch				"chain address\n",
9036182293Sdavidch				CTX_RD(sc, GET_CID_ADDR(cid), BCE_L2CTX_RX_NX_PG_BDHADDR_LO));
9037182293Sdavidch			BCE_PRINTF(" 0x%08X - (L2CTX_RX_NX_PG_BDIDX) h/w page "
9038182293Sdavidch				"consumer index\n",
9039182293Sdavidch				CTX_RD(sc, GET_CID_ADDR(cid), BCE_L2CTX_RX_NX_PG_BDIDX));
9040179771Sdavidch		} else if (cid == TX_CID) {
9041182293Sdavidch			if ((BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5709) ||
9042182293Sdavidch				(BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5716)) {
9043182293Sdavidch				BCE_PRINTF(" 0x%08X - (L2CTX_TX_TYPE_XI) ctx type\n",
9044182293Sdavidch					CTX_RD(sc, GET_CID_ADDR(cid), BCE_L2CTX_TX_TYPE_XI));
9045182293Sdavidch				BCE_PRINTF(" 0x%08X - (L2CTX_CMD_TX_TYPE_XI) ctx cmd\n",
9046182293Sdavidch					CTX_RD(sc, GET_CID_ADDR(cid), BCE_L2CTX_TX_CMD_TYPE_XI));
9047182293Sdavidch				BCE_PRINTF(" 0x%08X - (L2CTX_TX_TBDR_BDHADDR_HI_XI) h/w buffer "
9048182293Sdavidch					"descriptor address\n",	CTX_RD(sc,
9049182293Sdavidch					GET_CID_ADDR(cid), BCE_L2CTX_TX_TBDR_BHADDR_HI_XI));
9050182293Sdavidch				BCE_PRINTF(" 0x%08X - (L2CTX_TX_TBDR_BHADDR_LO_XI) h/w buffer "
9051182293Sdavidch					"descriptor address\n", CTX_RD(sc,
9052182293Sdavidch					GET_CID_ADDR(cid), BCE_L2CTX_TX_TBDR_BHADDR_LO_XI));
9053182293Sdavidch				BCE_PRINTF(" 0x%08X - (L2CTX_TX_HOST_BIDX_XI) host producer "
9054182293Sdavidch					"index\n", CTX_RD(sc, GET_CID_ADDR(cid),
9055182293Sdavidch					BCE_L2CTX_TX_HOST_BIDX_XI));
9056182293Sdavidch				BCE_PRINTF(" 0x%08X - (L2CTX_TX_HOST_BSEQ_XI) host byte "
9057182293Sdavidch					"sequence\n", CTX_RD(sc, GET_CID_ADDR(cid),
9058182293Sdavidch					BCE_L2CTX_TX_HOST_BSEQ_XI));
9059179771Sdavidch			} else {
9060182293Sdavidch				BCE_PRINTF(" 0x%08X - (L2CTX_TX_TYPE) ctx type\n",
9061182293Sdavidch					CTX_RD(sc, GET_CID_ADDR(cid), BCE_L2CTX_TX_TYPE));
9062182293Sdavidch				BCE_PRINTF(" 0x%08X - (L2CTX_TX_CMD_TYPE) ctx cmd\n",
9063182293Sdavidch					CTX_RD(sc, GET_CID_ADDR(cid), BCE_L2CTX_TX_CMD_TYPE));
9064182293Sdavidch				BCE_PRINTF(" 0x%08X - (L2CTX_TX_TBDR_BDHADDR_HI) h/w buffer "
9065182293Sdavidch					"descriptor address\n", CTX_RD(sc, GET_CID_ADDR(cid),
9066182293Sdavidch					BCE_L2CTX_TX_TBDR_BHADDR_HI));
9067182293Sdavidch				BCE_PRINTF(" 0x%08X - (L2CTX_TX_TBDR_BHADDR_LO) h/w buffer "
9068182293Sdavidch					"descriptor address\n", CTX_RD(sc, GET_CID_ADDR(cid),
9069182293Sdavidch					BCE_L2CTX_TX_TBDR_BHADDR_LO));
9070182293Sdavidch				BCE_PRINTF(" 0x%08X - (L2CTX_TX_HOST_BIDX) host producer "
9071182293Sdavidch					"index\n", CTX_RD(sc, GET_CID_ADDR(cid),
9072182293Sdavidch					BCE_L2CTX_TX_HOST_BIDX));
9073182293Sdavidch				BCE_PRINTF(" 0x%08X - (L2CTX_TX_HOST_BSEQ) host byte "
9074182293Sdavidch					"sequence\n", CTX_RD(sc, GET_CID_ADDR(cid),
9075182293Sdavidch					BCE_L2CTX_TX_HOST_BSEQ));
9076179771Sdavidch			}
9077179771Sdavidch		} else
9078182293Sdavidch			BCE_PRINTF(" Unknown CID\n");
9079176448Sdavidch
9080176448Sdavidch		BCE_PRINTF(
9081176448Sdavidch			"----------------------------"
9082179771Sdavidch			"    Raw CTX     "
9083179771Sdavidch			"----------------------------\n");
9084179771Sdavidch
9085179771Sdavidch		for (int i = 0x0; i < 0x300; i += 0x10) {
9086182293Sdavidch			BCE_PRINTF("0x%04X: 0x%08X 0x%08X 0x%08X 0x%08X\n", i,
9087182293Sdavidch				CTX_RD(sc, GET_CID_ADDR(cid), i),
9088182293Sdavidch				CTX_RD(sc, GET_CID_ADDR(cid), i + 0x4),
9089182293Sdavidch				CTX_RD(sc, GET_CID_ADDR(cid), i + 0x8),
9090179771Sdavidch				CTX_RD(sc, GET_CID_ADDR(cid), i + 0xc));
9091179771Sdavidch		}
9092179771Sdavidch
9093179771Sdavidch
9094179771Sdavidch		BCE_PRINTF(
9095179771Sdavidch			"----------------------------"
9096176448Sdavidch			"----------------"
9097178132Sdavidch			"----------------------------\n");
9098176448Sdavidch	}
9099176448Sdavidch}
9100176448Sdavidch
9101176448Sdavidch
9102176448Sdavidch/****************************************************************************/
9103176448Sdavidch/* Prints out the FTQ data.                                                 */
9104176448Sdavidch/*                                                                          */
9105176448Sdavidch/* Returns:                                                                */
9106176448Sdavidch/*   Nothing.                                                               */
9107176448Sdavidch/****************************************************************************/
9108179771Sdavidchstatic __attribute__ ((noinline)) void
9109176448Sdavidchbce_dump_ftqs(struct bce_softc *sc)
9110178132Sdavidch{
9111179771Sdavidch	u32 cmd, ctl, cur_depth, max_depth, valid_cnt, val;
9112176448Sdavidch
9113176448Sdavidch	BCE_PRINTF(
9114176448Sdavidch		"----------------------------"
9115176448Sdavidch		"    FTQ Data    "
9116176448Sdavidch		"----------------------------\n");
9117176448Sdavidch
9118179771Sdavidch	BCE_PRINTF("   FTQ    Command    Control   Depth_Now  Max_Depth  Valid_Cnt \n");
9119179771Sdavidch	BCE_PRINTF(" ------- ---------- ---------- ---------- ---------- ----------\n");
9120178132Sdavidch
9121178132Sdavidch	/* Setup the generic statistic counters for the FTQ valid count. */
9122179771Sdavidch	val = (BCE_HC_STAT_GEN_SEL_0_GEN_SEL_0_RV2PPQ_VALID_CNT << 24) |
9123179771Sdavidch		(BCE_HC_STAT_GEN_SEL_0_GEN_SEL_0_RXPCQ_VALID_CNT  << 16) |
9124179771Sdavidch		(BCE_HC_STAT_GEN_SEL_0_GEN_SEL_0_RXPQ_VALID_CNT   <<  8) |
9125179771Sdavidch		(BCE_HC_STAT_GEN_SEL_0_GEN_SEL_0_RLUPQ_VALID_CNT);
9126179771Sdavidch	REG_WR(sc, BCE_HC_STAT_GEN_SEL_0, val);
9127182293Sdavidch
9128179771Sdavidch	val = (BCE_HC_STAT_GEN_SEL_0_GEN_SEL_0_TSCHQ_VALID_CNT  << 24) |
9129179771Sdavidch		(BCE_HC_STAT_GEN_SEL_0_GEN_SEL_0_RDMAQ_VALID_CNT  << 16) |
9130179771Sdavidch		(BCE_HC_STAT_GEN_SEL_0_GEN_SEL_0_RV2PTQ_VALID_CNT <<  8) |
9131179771Sdavidch		(BCE_HC_STAT_GEN_SEL_0_GEN_SEL_0_RV2PMQ_VALID_CNT);
9132179771Sdavidch	REG_WR(sc, BCE_HC_STAT_GEN_SEL_1, val);
9133182293Sdavidch
9134179771Sdavidch	val = (BCE_HC_STAT_GEN_SEL_0_GEN_SEL_0_TPATQ_VALID_CNT  << 24) |
9135179771Sdavidch		(BCE_HC_STAT_GEN_SEL_0_GEN_SEL_0_TDMAQ_VALID_CNT  << 16) |
9136179771Sdavidch		(BCE_HC_STAT_GEN_SEL_0_GEN_SEL_0_TXPQ_VALID_CNT   <<  8) |
9137179771Sdavidch		(BCE_HC_STAT_GEN_SEL_0_GEN_SEL_0_TBDRQ_VALID_CNT);
9138179771Sdavidch	REG_WR(sc, BCE_HC_STAT_GEN_SEL_2, val);
9139182293Sdavidch
9140179771Sdavidch	val = (BCE_HC_STAT_GEN_SEL_0_GEN_SEL_0_COMQ_VALID_CNT   << 24) |
9141179771Sdavidch		(BCE_HC_STAT_GEN_SEL_0_GEN_SEL_0_COMTQ_VALID_CNT  << 16) |
9142179771Sdavidch		(BCE_HC_STAT_GEN_SEL_0_GEN_SEL_0_COMXQ_VALID_CNT  <<  8) |
9143179771Sdavidch		(BCE_HC_STAT_GEN_SEL_0_GEN_SEL_0_TASQ_VALID_CNT);
9144179771Sdavidch	REG_WR(sc, BCE_HC_STAT_GEN_SEL_3, val);
9145178132Sdavidch
9146182293Sdavidch	/* Input queue to the Receive Lookup state machine */
9147178132Sdavidch	cmd = REG_RD(sc, BCE_RLUP_FTQ_CMD);
9148178132Sdavidch	ctl = REG_RD(sc, BCE_RLUP_FTQ_CTL);
9149178132Sdavidch	cur_depth = (ctl & BCE_RLUP_FTQ_CTL_CUR_DEPTH) >> 22;
9150178132Sdavidch	max_depth = (ctl & BCE_RLUP_FTQ_CTL_MAX_DEPTH) >> 12;
9151178132Sdavidch	valid_cnt = REG_RD(sc, BCE_HC_STAT_GEN_STAT0);
9152179771Sdavidch	BCE_PRINTF(" RLUP    0x%08X 0x%08X 0x%08X 0x%08X 0x%08X\n",
9153176448Sdavidch		cmd, ctl, cur_depth, max_depth, valid_cnt);
9154178132Sdavidch
9155182293Sdavidch	/* Input queue to the Receive Processor */
9156178132Sdavidch	cmd = REG_RD_IND(sc, BCE_RXP_FTQ_CMD);
9157178132Sdavidch	ctl = REG_RD_IND(sc, BCE_RXP_FTQ_CTL);
9158178132Sdavidch	cur_depth = (ctl & BCE_RXP_FTQ_CTL_CUR_DEPTH) >> 22;
9159178132Sdavidch	max_depth = (ctl & BCE_RXP_FTQ_CTL_MAX_DEPTH) >> 12;
9160178132Sdavidch	valid_cnt = REG_RD(sc, BCE_HC_STAT_GEN_STAT1);
9161179771Sdavidch	BCE_PRINTF(" RXP     0x%08X 0x%08X 0x%08X 0x%08X 0x%08X\n",
9162176448Sdavidch		cmd, ctl, cur_depth, max_depth, valid_cnt);
9163178132Sdavidch
9164182293Sdavidch	/* Input queue to the Recevie Processor */
9165178132Sdavidch	cmd = REG_RD_IND(sc, BCE_RXP_CFTQ_CMD);
9166178132Sdavidch	ctl = REG_RD_IND(sc, BCE_RXP_CFTQ_CTL);
9167178132Sdavidch	cur_depth = (ctl & BCE_RXP_CFTQ_CTL_CUR_DEPTH) >> 22;
9168178132Sdavidch	max_depth = (ctl & BCE_RXP_CFTQ_CTL_MAX_DEPTH) >> 12;
9169178132Sdavidch	valid_cnt = REG_RD(sc, BCE_HC_STAT_GEN_STAT2);
9170179771Sdavidch	BCE_PRINTF(" RXPC    0x%08X 0x%08X 0x%08X 0x%08X 0x%08X\n",
9171176448Sdavidch		cmd, ctl, cur_depth, max_depth, valid_cnt);
9172178132Sdavidch
9173182293Sdavidch	/* Input queue to the Receive Virtual to Physical state machine */
9174178132Sdavidch	cmd = REG_RD(sc, BCE_RV2P_PFTQ_CMD);
9175178132Sdavidch	ctl = REG_RD(sc, BCE_RV2P_PFTQ_CTL);
9176178132Sdavidch	cur_depth = (ctl & BCE_RV2P_PFTQ_CTL_CUR_DEPTH) >> 22;
9177178132Sdavidch	max_depth = (ctl & BCE_RV2P_PFTQ_CTL_MAX_DEPTH) >> 12;
9178178132Sdavidch	valid_cnt = REG_RD(sc, BCE_HC_STAT_GEN_STAT3);
9179179771Sdavidch	BCE_PRINTF(" RV2PP   0x%08X 0x%08X 0x%08X 0x%08X 0x%08X\n",
9180176448Sdavidch		cmd, ctl, cur_depth, max_depth, valid_cnt);
9181178132Sdavidch
9182182293Sdavidch	/* Input queue to the Recevie Virtual to Physical state machine */
9183178132Sdavidch	cmd = REG_RD(sc, BCE_RV2P_MFTQ_CMD);
9184178132Sdavidch	ctl = REG_RD(sc, BCE_RV2P_MFTQ_CTL);
9185178132Sdavidch	cur_depth = (ctl & BCE_RV2P_MFTQ_CTL_CUR_DEPTH) >> 22;
9186178132Sdavidch	max_depth = (ctl & BCE_RV2P_MFTQ_CTL_MAX_DEPTH) >> 12;
9187178132Sdavidch	valid_cnt = REG_RD(sc, BCE_HC_STAT_GEN_STAT4);
9188179771Sdavidch	BCE_PRINTF(" RV2PM   0x%08X 0x%08X 0x%08X 0x%08X 0x%08X\n",
9189176448Sdavidch		cmd, ctl, cur_depth, max_depth, valid_cnt);
9190178132Sdavidch
9191182293Sdavidch	/* Input queue to the Receive Virtual to Physical state machine */
9192178132Sdavidch	cmd = REG_RD(sc, BCE_RV2P_TFTQ_CMD);
9193178132Sdavidch	ctl = REG_RD(sc, BCE_RV2P_TFTQ_CTL);
9194178132Sdavidch	cur_depth = (ctl & BCE_RV2P_TFTQ_CTL_CUR_DEPTH) >> 22;
9195178132Sdavidch	max_depth = (ctl & BCE_RV2P_TFTQ_CTL_MAX_DEPTH) >> 12;
9196178132Sdavidch	valid_cnt = REG_RD(sc, BCE_HC_STAT_GEN_STAT5);
9197179771Sdavidch	BCE_PRINTF(" RV2PT   0x%08X 0x%08X 0x%08X 0x%08X 0x%08X\n",
9198176448Sdavidch		cmd, ctl, cur_depth, max_depth, valid_cnt);
9199178132Sdavidch
9200182293Sdavidch	/* Input queue to the Receive DMA state machine */
9201178132Sdavidch	cmd = REG_RD(sc, BCE_RDMA_FTQ_CMD);
9202178132Sdavidch	ctl = REG_RD(sc, BCE_RDMA_FTQ_CTL);
9203178132Sdavidch	cur_depth = (ctl & BCE_RDMA_FTQ_CTL_CUR_DEPTH) >> 22;
9204178132Sdavidch	max_depth = (ctl & BCE_RDMA_FTQ_CTL_MAX_DEPTH) >> 12;
9205178132Sdavidch	valid_cnt = REG_RD(sc, BCE_HC_STAT_GEN_STAT6);
9206179771Sdavidch	BCE_PRINTF(" RDMA    0x%08X 0x%08X 0x%08X 0x%08X 0x%08X\n",
9207176448Sdavidch		cmd, ctl, cur_depth, max_depth, valid_cnt);
9208178132Sdavidch
9209182293Sdavidch	/* Input queue to the Transmit Scheduler state machine */
9210178132Sdavidch	cmd = REG_RD(sc, BCE_TSCH_FTQ_CMD);
9211178132Sdavidch	ctl = REG_RD(sc, BCE_TSCH_FTQ_CTL);
9212178132Sdavidch	cur_depth = (ctl & BCE_TSCH_FTQ_CTL_CUR_DEPTH) >> 22;
9213178132Sdavidch	max_depth = (ctl & BCE_TSCH_FTQ_CTL_MAX_DEPTH) >> 12;
9214178132Sdavidch	valid_cnt = REG_RD(sc, BCE_HC_STAT_GEN_STAT7);
9215179771Sdavidch	BCE_PRINTF(" TSCH    0x%08X 0x%08X 0x%08X 0x%08X 0x%08X\n",
9216176448Sdavidch		cmd, ctl, cur_depth, max_depth, valid_cnt);
9217178132Sdavidch
9218182293Sdavidch	/* Input queue to the Transmit Buffer Descriptor state machine */
9219178132Sdavidch	cmd = REG_RD(sc, BCE_TBDR_FTQ_CMD);
9220178132Sdavidch	ctl = REG_RD(sc, BCE_TBDR_FTQ_CTL);
9221178132Sdavidch	cur_depth = (ctl & BCE_TBDR_FTQ_CTL_CUR_DEPTH) >> 22;
9222178132Sdavidch	max_depth = (ctl & BCE_TBDR_FTQ_CTL_MAX_DEPTH) >> 12;
9223178132Sdavidch	valid_cnt = REG_RD(sc, BCE_HC_STAT_GEN_STAT8);
9224179771Sdavidch	BCE_PRINTF(" TBDR    0x%08X 0x%08X 0x%08X 0x%08X 0x%08X\n",
9225176448Sdavidch		cmd, ctl, cur_depth, max_depth, valid_cnt);
9226178132Sdavidch
9227182293Sdavidch	/* Input queue to the Transmit Processor */
9228178132Sdavidch	cmd = REG_RD_IND(sc, BCE_TXP_FTQ_CMD);
9229178132Sdavidch	ctl = REG_RD_IND(sc, BCE_TXP_FTQ_CTL);
9230178132Sdavidch	cur_depth = (ctl & BCE_TXP_FTQ_CTL_CUR_DEPTH) >> 22;
9231178132Sdavidch	max_depth = (ctl & BCE_TXP_FTQ_CTL_MAX_DEPTH) >> 12;
9232178132Sdavidch	valid_cnt = REG_RD(sc, BCE_HC_STAT_GEN_STAT9);
9233179771Sdavidch	BCE_PRINTF(" TXP     0x%08X 0x%08X 0x%08X 0x%08X 0x%08X\n",
9234176448Sdavidch		cmd, ctl, cur_depth, max_depth, valid_cnt);
9235178132Sdavidch
9236182293Sdavidch	/* Input queue to the Transmit DMA state machine */
9237178132Sdavidch	cmd = REG_RD(sc, BCE_TDMA_FTQ_CMD);
9238178132Sdavidch	ctl = REG_RD(sc, BCE_TDMA_FTQ_CTL);
9239178132Sdavidch	cur_depth = (ctl & BCE_TDMA_FTQ_CTL_CUR_DEPTH) >> 22;
9240178132Sdavidch	max_depth = (ctl & BCE_TDMA_FTQ_CTL_MAX_DEPTH) >> 12;
9241178132Sdavidch	valid_cnt = REG_RD(sc, BCE_HC_STAT_GEN_STAT10);
9242179771Sdavidch	BCE_PRINTF(" TDMA    0x%08X 0x%08X 0x%08X 0x%08X 0x%08X\n",
9243176448Sdavidch		cmd, ctl, cur_depth, max_depth, valid_cnt);
9244178132Sdavidch
9245182293Sdavidch	/* Input queue to the Transmit Patch-Up Processor */
9246178132Sdavidch	cmd = REG_RD_IND(sc, BCE_TPAT_FTQ_CMD);
9247178132Sdavidch	ctl = REG_RD_IND(sc, BCE_TPAT_FTQ_CTL);
9248178132Sdavidch	cur_depth = (ctl & BCE_TPAT_FTQ_CTL_CUR_DEPTH) >> 22;
9249178132Sdavidch	max_depth = (ctl & BCE_TPAT_FTQ_CTL_MAX_DEPTH) >> 12;
9250178132Sdavidch	valid_cnt = REG_RD(sc, BCE_HC_STAT_GEN_STAT11);
9251179771Sdavidch	BCE_PRINTF(" TPAT    0x%08X 0x%08X 0x%08X 0x%08X 0x%08X\n",
9252176448Sdavidch		cmd, ctl, cur_depth, max_depth, valid_cnt);
9253178132Sdavidch
9254182293Sdavidch	/* Input queue to the Transmit Assembler state machine */
9255178132Sdavidch	cmd = REG_RD_IND(sc, BCE_TAS_FTQ_CMD);
9256178132Sdavidch	ctl = REG_RD_IND(sc, BCE_TAS_FTQ_CTL);
9257178132Sdavidch	cur_depth = (ctl & BCE_TAS_FTQ_CTL_CUR_DEPTH) >> 22;
9258178132Sdavidch	max_depth = (ctl & BCE_TAS_FTQ_CTL_MAX_DEPTH) >> 12;
9259178132Sdavidch	valid_cnt = REG_RD(sc, BCE_HC_STAT_GEN_STAT12);
9260179771Sdavidch	BCE_PRINTF(" TAS     0x%08X 0x%08X 0x%08X 0x%08X 0x%08X\n",
9261176448Sdavidch		cmd, ctl, cur_depth, max_depth, valid_cnt);
9262178132Sdavidch
9263182293Sdavidch	/* Input queue to the Completion Processor */
9264178132Sdavidch	cmd = REG_RD_IND(sc, BCE_COM_COMXQ_FTQ_CMD);
9265178132Sdavidch	ctl = REG_RD_IND(sc, BCE_COM_COMXQ_FTQ_CTL);
9266178132Sdavidch	cur_depth = (ctl & BCE_COM_COMXQ_FTQ_CTL_CUR_DEPTH) >> 22;
9267178132Sdavidch	max_depth = (ctl & BCE_COM_COMXQ_FTQ_CTL_MAX_DEPTH) >> 12;
9268178132Sdavidch	valid_cnt = REG_RD(sc, BCE_HC_STAT_GEN_STAT13);
9269179771Sdavidch	BCE_PRINTF(" COMX    0x%08X 0x%08X 0x%08X 0x%08X 0x%08X\n",
9270176448Sdavidch		cmd, ctl, cur_depth, max_depth, valid_cnt);
9271178132Sdavidch
9272182293Sdavidch	/* Input queue to the Completion Processor */
9273178132Sdavidch	cmd = REG_RD_IND(sc, BCE_COM_COMTQ_FTQ_CMD);
9274178132Sdavidch	ctl = REG_RD_IND(sc, BCE_COM_COMTQ_FTQ_CTL);
9275178132Sdavidch	cur_depth = (ctl & BCE_COM_COMTQ_FTQ_CTL_CUR_DEPTH) >> 22;
9276178132Sdavidch	max_depth = (ctl & BCE_COM_COMTQ_FTQ_CTL_MAX_DEPTH) >> 12;
9277178132Sdavidch	valid_cnt = REG_RD(sc, BCE_HC_STAT_GEN_STAT14);
9278179771Sdavidch	BCE_PRINTF(" COMT    0x%08X 0x%08X 0x%08X 0x%08X 0x%08X\n",
9279176448Sdavidch		cmd, ctl, cur_depth, max_depth, valid_cnt);
9280178132Sdavidch
9281182293Sdavidch	/* Input queue to the Completion Processor */
9282178132Sdavidch	cmd = REG_RD_IND(sc, BCE_COM_COMQ_FTQ_CMD);
9283178132Sdavidch	ctl = REG_RD_IND(sc, BCE_COM_COMQ_FTQ_CTL);
9284178132Sdavidch	cur_depth = (ctl & BCE_COM_COMQ_FTQ_CTL_CUR_DEPTH) >> 22;
9285178132Sdavidch	max_depth = (ctl & BCE_COM_COMQ_FTQ_CTL_MAX_DEPTH) >> 12;
9286178132Sdavidch	valid_cnt = REG_RD(sc, BCE_HC_STAT_GEN_STAT15);
9287179771Sdavidch	BCE_PRINTF(" COMX    0x%08X 0x%08X 0x%08X 0x%08X 0x%08X\n",
9288176448Sdavidch		cmd, ctl, cur_depth, max_depth, valid_cnt);
9289178132Sdavidch
9290178132Sdavidch	/* Setup the generic statistic counters for the FTQ valid count. */
9291179771Sdavidch	val = (BCE_HC_STAT_GEN_SEL_0_GEN_SEL_0_CSQ_VALID_CNT  << 16) |
9292179771Sdavidch		(BCE_HC_STAT_GEN_SEL_0_GEN_SEL_0_CPQ_VALID_CNT  <<  8) |
9293179771Sdavidch		(BCE_HC_STAT_GEN_SEL_0_GEN_SEL_0_MGMQ_VALID_CNT);
9294182293Sdavidch
9295182293Sdavidch	if ((BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5709)	||
9296182293Sdavidch		(BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5716))
9297179771Sdavidch		val = val | (BCE_HC_STAT_GEN_SEL_0_GEN_SEL_0_RV2PCSQ_VALID_CNT_XI << 24);
9298182293Sdavidch		REG_WR(sc, BCE_HC_STAT_GEN_SEL_0, val);
9299182293Sdavidch
9300182293Sdavidch	/* Input queue to the Management Control Processor */
9301178132Sdavidch	cmd = REG_RD_IND(sc, BCE_MCP_MCPQ_FTQ_CMD);
9302178132Sdavidch	ctl = REG_RD_IND(sc, BCE_MCP_MCPQ_FTQ_CTL);
9303178132Sdavidch	cur_depth = (ctl & BCE_MCP_MCPQ_FTQ_CTL_CUR_DEPTH) >> 22;
9304178132Sdavidch	max_depth = (ctl & BCE_MCP_MCPQ_FTQ_CTL_MAX_DEPTH) >> 12;
9305178132Sdavidch	valid_cnt = REG_RD(sc, BCE_HC_STAT_GEN_STAT0);
9306179771Sdavidch	BCE_PRINTF(" MCP     0x%08X 0x%08X 0x%08X 0x%08X 0x%08X\n",
9307176448Sdavidch		cmd, ctl, cur_depth, max_depth, valid_cnt);
9308178132Sdavidch
9309182293Sdavidch	/* Input queue to the Command Processor */
9310178132Sdavidch	cmd = REG_RD_IND(sc, BCE_CP_CPQ_FTQ_CMD);
9311178132Sdavidch	ctl = REG_RD_IND(sc, BCE_CP_CPQ_FTQ_CTL);
9312178132Sdavidch	cur_depth = (ctl & BCE_CP_CPQ_FTQ_CTL_CUR_DEPTH) >> 22;
9313178132Sdavidch	max_depth = (ctl & BCE_CP_CPQ_FTQ_CTL_MAX_DEPTH) >> 12;
9314178132Sdavidch	valid_cnt = REG_RD(sc, BCE_HC_STAT_GEN_STAT1);
9315179771Sdavidch	BCE_PRINTF(" CP      0x%08X 0x%08X 0x%08X 0x%08X 0x%08X\n",
9316176448Sdavidch		cmd, ctl, cur_depth, max_depth, valid_cnt);
9317178132Sdavidch
9318182293Sdavidch	/* Input queue to the Completion Scheduler state machine */
9319178132Sdavidch	cmd = REG_RD(sc, BCE_CSCH_CH_FTQ_CMD);
9320178132Sdavidch	ctl = REG_RD(sc, BCE_CSCH_CH_FTQ_CTL);
9321178132Sdavidch	cur_depth = (ctl & BCE_CSCH_CH_FTQ_CTL_CUR_DEPTH) >> 22;
9322178132Sdavidch	max_depth = (ctl & BCE_CSCH_CH_FTQ_CTL_MAX_DEPTH) >> 12;
9323178132Sdavidch	valid_cnt = REG_RD(sc, BCE_HC_STAT_GEN_STAT2);
9324179771Sdavidch	BCE_PRINTF(" CS      0x%08X 0x%08X 0x%08X 0x%08X 0x%08X\n",
9325176448Sdavidch		cmd, ctl, cur_depth, max_depth, valid_cnt);
9326178132Sdavidch
9327182293Sdavidch	if ((BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5709) ||
9328182293Sdavidch		(BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5716)) {
9329182293Sdavidch		/* Input queue to the Receive Virtual to Physical Command Scheduler */
9330179771Sdavidch		cmd = REG_RD(sc, BCE_RV2PCSR_FTQ_CMD);
9331179771Sdavidch		ctl = REG_RD(sc, BCE_RV2PCSR_FTQ_CTL);
9332179771Sdavidch		cur_depth = (ctl & 0xFFC00000) >> 22;
9333179771Sdavidch		max_depth = (ctl & 0x003FF000) >> 12;
9334179771Sdavidch		valid_cnt = REG_RD(sc, BCE_HC_STAT_GEN_STAT3);
9335179771Sdavidch		BCE_PRINTF(" RV2PCSR 0x%08X 0x%08X 0x%08X 0x%08X 0x%08X\n",
9336182293Sdavidch			cmd, ctl, cur_depth, max_depth, valid_cnt);
9337179771Sdavidch	}
9338182293Sdavidch
9339176448Sdavidch	BCE_PRINTF(
9340176448Sdavidch		"----------------------------"
9341176448Sdavidch		"----------------"
9342176448Sdavidch		"----------------------------\n");
9343176448Sdavidch}
9344176448Sdavidch
9345176448Sdavidch
9346176448Sdavidch/****************************************************************************/
9347170810Sdavidch/* Prints out the TX chain.                                                 */
9348169271Sdavidch/*                                                                          */
9349169271Sdavidch/* Returns:                                                                 */
9350169271Sdavidch/*   Nothing.                                                               */
9351169271Sdavidch/****************************************************************************/
9352179771Sdavidchstatic __attribute__ ((noinline)) void
9353176448Sdavidchbce_dump_tx_chain(struct bce_softc *sc, u16 tx_prod, int count)
9354157642Sps{
9355157642Sps	struct tx_bd *txbd;
9356157642Sps
9357157642Sps	/* First some info about the tx_bd chain structure. */
9358169271Sdavidch	BCE_PRINTF(
9359157642Sps		"----------------------------"
9360157642Sps		"  tx_bd  chain  "
9361157642Sps		"----------------------------\n");
9362157642Sps
9363169271Sdavidch	BCE_PRINTF("page size      = 0x%08X, tx chain pages        = 0x%08X\n",
9364157642Sps		(u32) BCM_PAGE_SIZE, (u32) TX_PAGES);
9365157642Sps
9366169271Sdavidch	BCE_PRINTF("tx_bd per page = 0x%08X, usable tx_bd per page = 0x%08X\n",
9367157642Sps		(u32) TOTAL_TX_BD_PER_PAGE, (u32) USABLE_TX_BD_PER_PAGE);
9368157642Sps
9369169271Sdavidch	BCE_PRINTF("total tx_bd    = 0x%08X\n", (u32) TOTAL_TX_BD);
9370157642Sps
9371170810Sdavidch	BCE_PRINTF(
9372169271Sdavidch		"----------------------------"
9373169632Sdavidch		"   tx_bd data   "
9374169271Sdavidch		"----------------------------\n");
9375157642Sps
9376157642Sps	/* Now print out the tx_bd's themselves. */
9377157642Sps	for (int i = 0; i < count; i++) {
9378157642Sps	 	txbd = &sc->tx_bd_chain[TX_PAGE(tx_prod)][TX_IDX(tx_prod)];
9379157642Sps		bce_dump_txbd(sc, tx_prod, txbd);
9380176448Sdavidch		tx_prod = NEXT_TX_BD(tx_prod);
9381157642Sps	}
9382157642Sps
9383169271Sdavidch	BCE_PRINTF(
9384169271Sdavidch		"----------------------------"
9385169271Sdavidch		"----------------"
9386169271Sdavidch		"----------------------------\n");
9387157642Sps}
9388157642Sps
9389157642Sps
9390169271Sdavidch/****************************************************************************/
9391170810Sdavidch/* Prints out the RX chain.                                                 */
9392169271Sdavidch/*                                                                          */
9393169271Sdavidch/* Returns:                                                                 */
9394169271Sdavidch/*   Nothing.                                                               */
9395169271Sdavidch/****************************************************************************/
9396179771Sdavidchstatic __attribute__ ((noinline)) void
9397176448Sdavidchbce_dump_rx_chain(struct bce_softc *sc, u16 rx_prod, int count)
9398157642Sps{
9399157642Sps	struct rx_bd *rxbd;
9400157642Sps
9401176448Sdavidch	/* First some info about the rx_bd chain structure. */
9402169271Sdavidch	BCE_PRINTF(
9403157642Sps		"----------------------------"
9404157642Sps		"  rx_bd  chain  "
9405157642Sps		"----------------------------\n");
9406157642Sps
9407169271Sdavidch	BCE_PRINTF("page size      = 0x%08X, rx chain pages        = 0x%08X\n",
9408157642Sps		(u32) BCM_PAGE_SIZE, (u32) RX_PAGES);
9409157642Sps
9410169271Sdavidch	BCE_PRINTF("rx_bd per page = 0x%08X, usable rx_bd per page = 0x%08X\n",
9411157642Sps		(u32) TOTAL_RX_BD_PER_PAGE, (u32) USABLE_RX_BD_PER_PAGE);
9412157642Sps
9413169271Sdavidch	BCE_PRINTF("total rx_bd    = 0x%08X\n", (u32) TOTAL_RX_BD);
9414157642Sps
9415169271Sdavidch	BCE_PRINTF(
9416157642Sps		"----------------------------"
9417157642Sps		"   rx_bd data   "
9418157642Sps		"----------------------------\n");
9419157642Sps
9420157642Sps	/* Now print out the rx_bd's themselves. */
9421157642Sps	for (int i = 0; i < count; i++) {
9422157642Sps		rxbd = &sc->rx_bd_chain[RX_PAGE(rx_prod)][RX_IDX(rx_prod)];
9423157642Sps		bce_dump_rxbd(sc, rx_prod, rxbd);
9424176448Sdavidch		rx_prod = RX_CHAIN_IDX(rx_prod + 1);
9425157642Sps	}
9426157642Sps
9427169271Sdavidch	BCE_PRINTF(
9428157642Sps		"----------------------------"
9429169271Sdavidch		"----------------"
9430157642Sps		"----------------------------\n");
9431157642Sps}
9432157642Sps
9433157642Sps
9434198320Sstas#ifdef BCE_JUMBO_HDRSPLIT
9435169271Sdavidch/****************************************************************************/
9436176448Sdavidch/* Prints out the page chain.                                               */
9437176448Sdavidch/*                                                                          */
9438176448Sdavidch/* Returns:                                                                 */
9439176448Sdavidch/*   Nothing.                                                               */
9440176448Sdavidch/****************************************************************************/
9441179771Sdavidchstatic __attribute__ ((noinline)) void
9442176448Sdavidchbce_dump_pg_chain(struct bce_softc *sc, u16 pg_prod, int count)
9443176448Sdavidch{
9444176448Sdavidch	struct rx_bd *pgbd;
9445176448Sdavidch
9446176448Sdavidch	/* First some info about the page chain structure. */
9447176448Sdavidch	BCE_PRINTF(
9448176448Sdavidch		"----------------------------"
9449176448Sdavidch		"   page chain   "
9450176448Sdavidch		"----------------------------\n");
9451176448Sdavidch
9452176448Sdavidch	BCE_PRINTF("page size      = 0x%08X, pg chain pages        = 0x%08X\n",
9453176448Sdavidch		(u32) BCM_PAGE_SIZE, (u32) PG_PAGES);
9454176448Sdavidch
9455176448Sdavidch	BCE_PRINTF("rx_bd per page = 0x%08X, usable rx_bd per page = 0x%08X\n",
9456176448Sdavidch		(u32) TOTAL_PG_BD_PER_PAGE, (u32) USABLE_PG_BD_PER_PAGE);
9457176448Sdavidch
9458178132Sdavidch	BCE_PRINTF("total rx_bd    = 0x%08X, max_pg_bd             = 0x%08X\n",
9459176448Sdavidch		(u32) TOTAL_PG_BD, (u32) MAX_PG_BD);
9460176448Sdavidch
9461176448Sdavidch	BCE_PRINTF(
9462176448Sdavidch		"----------------------------"
9463176448Sdavidch		"   page data    "
9464176448Sdavidch		"----------------------------\n");
9465176448Sdavidch
9466176448Sdavidch	/* Now print out the rx_bd's themselves. */
9467176448Sdavidch	for (int i = 0; i < count; i++) {
9468178132Sdavidch		pgbd = &sc->pg_bd_chain[PG_PAGE(pg_prod)][PG_IDX(pg_prod)];
9469176448Sdavidch		bce_dump_pgbd(sc, pg_prod, pgbd);
9470176448Sdavidch		pg_prod = PG_CHAIN_IDX(pg_prod + 1);
9471176448Sdavidch	}
9472176448Sdavidch
9473176448Sdavidch	BCE_PRINTF(
9474176448Sdavidch		"----------------------------"
9475176448Sdavidch		"----------------"
9476176448Sdavidch		"----------------------------\n");
9477179771Sdavidch}
9478179695Sdavidch#endif
9479176448Sdavidch
9480176448Sdavidch
9481176448Sdavidch/****************************************************************************/
9482169271Sdavidch/* Prints out the status block from host memory.                            */
9483169271Sdavidch/*                                                                          */
9484169271Sdavidch/* Returns:                                                                 */
9485169271Sdavidch/*   Nothing.                                                               */
9486169271Sdavidch/****************************************************************************/
9487179771Sdavidchstatic __attribute__ ((noinline)) void
9488157642Spsbce_dump_status_block(struct bce_softc *sc)
9489157642Sps{
9490157642Sps	struct status_block *sblk;
9491157642Sps
9492157642Sps	sblk = sc->status_block;
9493157642Sps
9494169271Sdavidch   	BCE_PRINTF(
9495169271Sdavidch		"----------------------------"
9496169271Sdavidch		"  Status Block  "
9497169271Sdavidch		"----------------------------\n");
9498170392Sdavidch
9499169632Sdavidch	BCE_PRINTF("    0x%08X - attn_bits\n",
9500169632Sdavidch		sblk->status_attn_bits);
9501157642Sps
9502169632Sdavidch	BCE_PRINTF("    0x%08X - attn_bits_ack\n",
9503169632Sdavidch		sblk->status_attn_bits_ack);
9504157642Sps
9505169632Sdavidch	BCE_PRINTF("0x%04X(0x%04X) - rx_cons0\n",
9506179771Sdavidch		sblk->status_rx_quick_consumer_index0,
9507169632Sdavidch		(u16) RX_CHAIN_IDX(sblk->status_rx_quick_consumer_index0));
9508170392Sdavidch
9509169632Sdavidch	BCE_PRINTF("0x%04X(0x%04X) - tx_cons0\n",
9510179771Sdavidch		sblk->status_tx_quick_consumer_index0,
9511169632Sdavidch		(u16) TX_CHAIN_IDX(sblk->status_tx_quick_consumer_index0));
9512157642Sps
9513169632Sdavidch	BCE_PRINTF("        0x%04X - status_idx\n", sblk->status_idx);
9514169632Sdavidch
9515157642Sps	/* Theses indices are not used for normal L2 drivers. */
9516169632Sdavidch	if (sblk->status_rx_quick_consumer_index1)
9517169632Sdavidch		BCE_PRINTF("0x%04X(0x%04X) - rx_cons1\n",
9518157642Sps			sblk->status_rx_quick_consumer_index1,
9519169632Sdavidch			(u16) RX_CHAIN_IDX(sblk->status_rx_quick_consumer_index1));
9520170392Sdavidch
9521169632Sdavidch	if (sblk->status_tx_quick_consumer_index1)
9522169632Sdavidch		BCE_PRINTF("0x%04X(0x%04X) - tx_cons1\n",
9523169632Sdavidch			sblk->status_tx_quick_consumer_index1,
9524169632Sdavidch			(u16) TX_CHAIN_IDX(sblk->status_tx_quick_consumer_index1));
9525157642Sps
9526169632Sdavidch	if (sblk->status_rx_quick_consumer_index2)
9527169632Sdavidch		BCE_PRINTF("0x%04X(0x%04X)- rx_cons2\n",
9528157642Sps			sblk->status_rx_quick_consumer_index2,
9529169632Sdavidch			(u16) RX_CHAIN_IDX(sblk->status_rx_quick_consumer_index2));
9530170392Sdavidch
9531169632Sdavidch	if (sblk->status_tx_quick_consumer_index2)
9532169632Sdavidch		BCE_PRINTF("0x%04X(0x%04X) - tx_cons2\n",
9533169632Sdavidch			sblk->status_tx_quick_consumer_index2,
9534169632Sdavidch			(u16) TX_CHAIN_IDX(sblk->status_tx_quick_consumer_index2));
9535170392Sdavidch
9536169632Sdavidch	if (sblk->status_rx_quick_consumer_index3)
9537169632Sdavidch		BCE_PRINTF("0x%04X(0x%04X) - rx_cons3\n",
9538157642Sps			sblk->status_rx_quick_consumer_index3,
9539169632Sdavidch			(u16) RX_CHAIN_IDX(sblk->status_rx_quick_consumer_index3));
9540170392Sdavidch
9541169632Sdavidch	if (sblk->status_tx_quick_consumer_index3)
9542169632Sdavidch		BCE_PRINTF("0x%04X(0x%04X) - tx_cons3\n",
9543169632Sdavidch			sblk->status_tx_quick_consumer_index3,
9544169632Sdavidch			(u16) TX_CHAIN_IDX(sblk->status_tx_quick_consumer_index3));
9545170392Sdavidch
9546179771Sdavidch	if (sblk->status_rx_quick_consumer_index4 ||
9547157642Sps		sblk->status_rx_quick_consumer_index5)
9548169271Sdavidch		BCE_PRINTF("rx_cons4  = 0x%08X, rx_cons5      = 0x%08X\n",
9549157642Sps			sblk->status_rx_quick_consumer_index4,
9550157642Sps			sblk->status_rx_quick_consumer_index5);
9551157642Sps
9552179771Sdavidch	if (sblk->status_rx_quick_consumer_index6 ||
9553157642Sps		sblk->status_rx_quick_consumer_index7)
9554169271Sdavidch		BCE_PRINTF("rx_cons6  = 0x%08X, rx_cons7      = 0x%08X\n",
9555157642Sps			sblk->status_rx_quick_consumer_index6,
9556157642Sps			sblk->status_rx_quick_consumer_index7);
9557157642Sps
9558179771Sdavidch	if (sblk->status_rx_quick_consumer_index8 ||
9559157642Sps		sblk->status_rx_quick_consumer_index9)
9560169271Sdavidch		BCE_PRINTF("rx_cons8  = 0x%08X, rx_cons9      = 0x%08X\n",
9561157642Sps			sblk->status_rx_quick_consumer_index8,
9562157642Sps			sblk->status_rx_quick_consumer_index9);
9563157642Sps
9564179771Sdavidch	if (sblk->status_rx_quick_consumer_index10 ||
9565157642Sps		sblk->status_rx_quick_consumer_index11)
9566169271Sdavidch		BCE_PRINTF("rx_cons10 = 0x%08X, rx_cons11     = 0x%08X\n",
9567157642Sps			sblk->status_rx_quick_consumer_index10,
9568157642Sps			sblk->status_rx_quick_consumer_index11);
9569157642Sps
9570179771Sdavidch	if (sblk->status_rx_quick_consumer_index12 ||
9571157642Sps		sblk->status_rx_quick_consumer_index13)
9572169271Sdavidch		BCE_PRINTF("rx_cons12 = 0x%08X, rx_cons13     = 0x%08X\n",
9573157642Sps			sblk->status_rx_quick_consumer_index12,
9574157642Sps			sblk->status_rx_quick_consumer_index13);
9575157642Sps
9576179771Sdavidch	if (sblk->status_rx_quick_consumer_index14 ||
9577157642Sps		sblk->status_rx_quick_consumer_index15)
9578169271Sdavidch		BCE_PRINTF("rx_cons14 = 0x%08X, rx_cons15     = 0x%08X\n",
9579157642Sps			sblk->status_rx_quick_consumer_index14,
9580157642Sps			sblk->status_rx_quick_consumer_index15);
9581157642Sps
9582179771Sdavidch	if (sblk->status_completion_producer_index ||
9583157642Sps		sblk->status_cmd_consumer_index)
9584169271Sdavidch		BCE_PRINTF("com_prod  = 0x%08X, cmd_cons      = 0x%08X\n",
9585157642Sps			sblk->status_completion_producer_index,
9586157642Sps			sblk->status_cmd_consumer_index);
9587170392Sdavidch
9588169271Sdavidch	BCE_PRINTF(
9589169271Sdavidch		"----------------------------"
9590169271Sdavidch		"----------------"
9591169271Sdavidch		"----------------------------\n");
9592157642Sps}
9593157642Sps
9594157642Sps
9595169271Sdavidch/****************************************************************************/
9596170810Sdavidch/* Prints out the statistics block from host memory.                        */
9597169271Sdavidch/*                                                                          */
9598169271Sdavidch/* Returns:                                                                 */
9599169271Sdavidch/*   Nothing.                                                               */
9600169271Sdavidch/****************************************************************************/
9601179771Sdavidchstatic __attribute__ ((noinline)) void
9602157642Spsbce_dump_stats_block(struct bce_softc *sc)
9603157642Sps{
9604157642Sps	struct statistics_block *sblk;
9605157642Sps
9606157642Sps	sblk = sc->stats_block;
9607170392Sdavidch
9608169271Sdavidch	BCE_PRINTF(
9609169632Sdavidch		"---------------"
9610169632Sdavidch		" Stats Block  (All Stats Not Shown Are 0) "
9611169632Sdavidch		"---------------\n");
9612157642Sps
9613179771Sdavidch	if (sblk->stat_IfHCInOctets_hi
9614169632Sdavidch		|| sblk->stat_IfHCInOctets_lo)
9615169632Sdavidch		BCE_PRINTF("0x%08X:%08X : "
9616179771Sdavidch			"IfHcInOctets\n",
9617179771Sdavidch			sblk->stat_IfHCInOctets_hi,
9618170392Sdavidch			sblk->stat_IfHCInOctets_lo);
9619170392Sdavidch
9620179771Sdavidch	if (sblk->stat_IfHCInBadOctets_hi
9621169632Sdavidch		|| sblk->stat_IfHCInBadOctets_lo)
9622169632Sdavidch		BCE_PRINTF("0x%08X:%08X : "
9623179771Sdavidch			"IfHcInBadOctets\n",
9624179771Sdavidch			sblk->stat_IfHCInBadOctets_hi,
9625170392Sdavidch			sblk->stat_IfHCInBadOctets_lo);
9626170392Sdavidch
9627179771Sdavidch	if (sblk->stat_IfHCOutOctets_hi
9628169632Sdavidch		|| sblk->stat_IfHCOutOctets_lo)
9629169632Sdavidch		BCE_PRINTF("0x%08X:%08X : "
9630179771Sdavidch			"IfHcOutOctets\n",
9631179771Sdavidch			sblk->stat_IfHCOutOctets_hi,
9632170392Sdavidch			sblk->stat_IfHCOutOctets_lo);
9633170392Sdavidch
9634179771Sdavidch	if (sblk->stat_IfHCOutBadOctets_hi
9635169632Sdavidch		|| sblk->stat_IfHCOutBadOctets_lo)
9636169632Sdavidch		BCE_PRINTF("0x%08X:%08X : "
9637179771Sdavidch			"IfHcOutBadOctets\n",
9638179771Sdavidch			sblk->stat_IfHCOutBadOctets_hi,
9639170392Sdavidch			sblk->stat_IfHCOutBadOctets_lo);
9640170392Sdavidch
9641179771Sdavidch	if (sblk->stat_IfHCInUcastPkts_hi
9642169632Sdavidch		|| sblk->stat_IfHCInUcastPkts_lo)
9643169632Sdavidch		BCE_PRINTF("0x%08X:%08X : "
9644179771Sdavidch			"IfHcInUcastPkts\n",
9645179771Sdavidch			sblk->stat_IfHCInUcastPkts_hi,
9646170392Sdavidch			sblk->stat_IfHCInUcastPkts_lo);
9647170392Sdavidch
9648179771Sdavidch	if (sblk->stat_IfHCInBroadcastPkts_hi
9649169632Sdavidch		|| sblk->stat_IfHCInBroadcastPkts_lo)
9650169632Sdavidch		BCE_PRINTF("0x%08X:%08X : "
9651179771Sdavidch			"IfHcInBroadcastPkts\n",
9652179771Sdavidch			sblk->stat_IfHCInBroadcastPkts_hi,
9653170392Sdavidch			sblk->stat_IfHCInBroadcastPkts_lo);
9654170392Sdavidch
9655179771Sdavidch	if (sblk->stat_IfHCInMulticastPkts_hi
9656169632Sdavidch		|| sblk->stat_IfHCInMulticastPkts_lo)
9657169632Sdavidch		BCE_PRINTF("0x%08X:%08X : "
9658179771Sdavidch			"IfHcInMulticastPkts\n",
9659179771Sdavidch			sblk->stat_IfHCInMulticastPkts_hi,
9660170392Sdavidch			sblk->stat_IfHCInMulticastPkts_lo);
9661170392Sdavidch
9662179771Sdavidch	if (sblk->stat_IfHCOutUcastPkts_hi
9663169632Sdavidch		|| sblk->stat_IfHCOutUcastPkts_lo)
9664169632Sdavidch		BCE_PRINTF("0x%08X:%08X : "
9665179771Sdavidch			"IfHcOutUcastPkts\n",
9666179771Sdavidch			sblk->stat_IfHCOutUcastPkts_hi,
9667170392Sdavidch			sblk->stat_IfHCOutUcastPkts_lo);
9668170392Sdavidch
9669179771Sdavidch	if (sblk->stat_IfHCOutBroadcastPkts_hi
9670169632Sdavidch		|| sblk->stat_IfHCOutBroadcastPkts_lo)
9671169632Sdavidch		BCE_PRINTF("0x%08X:%08X : "
9672179771Sdavidch			"IfHcOutBroadcastPkts\n",
9673179771Sdavidch			sblk->stat_IfHCOutBroadcastPkts_hi,
9674170392Sdavidch			sblk->stat_IfHCOutBroadcastPkts_lo);
9675170392Sdavidch
9676179771Sdavidch	if (sblk->stat_IfHCOutMulticastPkts_hi
9677169632Sdavidch		|| sblk->stat_IfHCOutMulticastPkts_lo)
9678169632Sdavidch		BCE_PRINTF("0x%08X:%08X : "
9679179771Sdavidch			"IfHcOutMulticastPkts\n",
9680179771Sdavidch			sblk->stat_IfHCOutMulticastPkts_hi,
9681170392Sdavidch			sblk->stat_IfHCOutMulticastPkts_lo);
9682170392Sdavidch
9683157642Sps	if (sblk->stat_emac_tx_stat_dot3statsinternalmactransmiterrors)
9684169632Sdavidch		BCE_PRINTF("         0x%08X : "
9685179771Sdavidch			"emac_tx_stat_dot3statsinternalmactransmiterrors\n",
9686169632Sdavidch			sblk->stat_emac_tx_stat_dot3statsinternalmactransmiterrors);
9687157642Sps
9688157642Sps	if (sblk->stat_Dot3StatsCarrierSenseErrors)
9689169632Sdavidch		BCE_PRINTF("         0x%08X : Dot3StatsCarrierSenseErrors\n",
9690157642Sps			sblk->stat_Dot3StatsCarrierSenseErrors);
9691157642Sps
9692157642Sps	if (sblk->stat_Dot3StatsFCSErrors)
9693169632Sdavidch		BCE_PRINTF("         0x%08X : Dot3StatsFCSErrors\n",
9694157642Sps			sblk->stat_Dot3StatsFCSErrors);
9695157642Sps
9696157642Sps	if (sblk->stat_Dot3StatsAlignmentErrors)
9697169632Sdavidch		BCE_PRINTF("         0x%08X : Dot3StatsAlignmentErrors\n",
9698157642Sps			sblk->stat_Dot3StatsAlignmentErrors);
9699157642Sps
9700157642Sps	if (sblk->stat_Dot3StatsSingleCollisionFrames)
9701169632Sdavidch		BCE_PRINTF("         0x%08X : Dot3StatsSingleCollisionFrames\n",
9702157642Sps			sblk->stat_Dot3StatsSingleCollisionFrames);
9703157642Sps
9704157642Sps	if (sblk->stat_Dot3StatsMultipleCollisionFrames)
9705169632Sdavidch		BCE_PRINTF("         0x%08X : Dot3StatsMultipleCollisionFrames\n",
9706157642Sps			sblk->stat_Dot3StatsMultipleCollisionFrames);
9707179771Sdavidch
9708157642Sps	if (sblk->stat_Dot3StatsDeferredTransmissions)
9709169632Sdavidch		BCE_PRINTF("         0x%08X : Dot3StatsDeferredTransmissions\n",
9710157642Sps			sblk->stat_Dot3StatsDeferredTransmissions);
9711157642Sps
9712157642Sps	if (sblk->stat_Dot3StatsExcessiveCollisions)
9713169632Sdavidch		BCE_PRINTF("         0x%08X : Dot3StatsExcessiveCollisions\n",
9714157642Sps			sblk->stat_Dot3StatsExcessiveCollisions);
9715157642Sps
9716157642Sps	if (sblk->stat_Dot3StatsLateCollisions)
9717169632Sdavidch		BCE_PRINTF("         0x%08X : Dot3StatsLateCollisions\n",
9718157642Sps			sblk->stat_Dot3StatsLateCollisions);
9719157642Sps
9720157642Sps	if (sblk->stat_EtherStatsCollisions)
9721169632Sdavidch		BCE_PRINTF("         0x%08X : EtherStatsCollisions\n",
9722157642Sps			sblk->stat_EtherStatsCollisions);
9723157642Sps
9724179771Sdavidch	if (sblk->stat_EtherStatsFragments)
9725169632Sdavidch		BCE_PRINTF("         0x%08X : EtherStatsFragments\n",
9726157642Sps			sblk->stat_EtherStatsFragments);
9727157642Sps
9728157642Sps	if (sblk->stat_EtherStatsJabbers)
9729169632Sdavidch		BCE_PRINTF("         0x%08X : EtherStatsJabbers\n",
9730157642Sps			sblk->stat_EtherStatsJabbers);
9731157642Sps
9732157642Sps	if (sblk->stat_EtherStatsUndersizePkts)
9733169632Sdavidch		BCE_PRINTF("         0x%08X : EtherStatsUndersizePkts\n",
9734157642Sps			sblk->stat_EtherStatsUndersizePkts);
9735157642Sps
9736189325Sdavidch	if (sblk->stat_EtherStatsOversizePkts)
9737169632Sdavidch		BCE_PRINTF("         0x%08X : EtherStatsOverrsizePkts\n",
9738189325Sdavidch			sblk->stat_EtherStatsOversizePkts);
9739157642Sps
9740157642Sps	if (sblk->stat_EtherStatsPktsRx64Octets)
9741169632Sdavidch		BCE_PRINTF("         0x%08X : EtherStatsPktsRx64Octets\n",
9742157642Sps			sblk->stat_EtherStatsPktsRx64Octets);
9743157642Sps
9744157642Sps	if (sblk->stat_EtherStatsPktsRx65Octetsto127Octets)
9745169632Sdavidch		BCE_PRINTF("         0x%08X : EtherStatsPktsRx65Octetsto127Octets\n",
9746157642Sps			sblk->stat_EtherStatsPktsRx65Octetsto127Octets);
9747157642Sps
9748157642Sps	if (sblk->stat_EtherStatsPktsRx128Octetsto255Octets)
9749169632Sdavidch		BCE_PRINTF("         0x%08X : EtherStatsPktsRx128Octetsto255Octets\n",
9750157642Sps			sblk->stat_EtherStatsPktsRx128Octetsto255Octets);
9751157642Sps
9752157642Sps	if (sblk->stat_EtherStatsPktsRx256Octetsto511Octets)
9753169632Sdavidch		BCE_PRINTF("         0x%08X : EtherStatsPktsRx256Octetsto511Octets\n",
9754157642Sps			sblk->stat_EtherStatsPktsRx256Octetsto511Octets);
9755157642Sps
9756157642Sps	if (sblk->stat_EtherStatsPktsRx512Octetsto1023Octets)
9757169632Sdavidch		BCE_PRINTF("         0x%08X : EtherStatsPktsRx512Octetsto1023Octets\n",
9758157642Sps			sblk->stat_EtherStatsPktsRx512Octetsto1023Octets);
9759157642Sps
9760157642Sps	if (sblk->stat_EtherStatsPktsRx1024Octetsto1522Octets)
9761169632Sdavidch		BCE_PRINTF("         0x%08X : EtherStatsPktsRx1024Octetsto1522Octets\n",
9762157642Sps			sblk->stat_EtherStatsPktsRx1024Octetsto1522Octets);
9763157642Sps
9764157642Sps	if (sblk->stat_EtherStatsPktsRx1523Octetsto9022Octets)
9765169632Sdavidch		BCE_PRINTF("         0x%08X : EtherStatsPktsRx1523Octetsto9022Octets\n",
9766157642Sps			sblk->stat_EtherStatsPktsRx1523Octetsto9022Octets);
9767157642Sps
9768157642Sps	if (sblk->stat_EtherStatsPktsTx64Octets)
9769169632Sdavidch		BCE_PRINTF("         0x%08X : EtherStatsPktsTx64Octets\n",
9770157642Sps			sblk->stat_EtherStatsPktsTx64Octets);
9771157642Sps
9772157642Sps	if (sblk->stat_EtherStatsPktsTx65Octetsto127Octets)
9773169632Sdavidch		BCE_PRINTF("         0x%08X : EtherStatsPktsTx65Octetsto127Octets\n",
9774157642Sps			sblk->stat_EtherStatsPktsTx65Octetsto127Octets);
9775157642Sps
9776157642Sps	if (sblk->stat_EtherStatsPktsTx128Octetsto255Octets)
9777169632Sdavidch		BCE_PRINTF("         0x%08X : EtherStatsPktsTx128Octetsto255Octets\n",
9778157642Sps			sblk->stat_EtherStatsPktsTx128Octetsto255Octets);
9779157642Sps
9780157642Sps	if (sblk->stat_EtherStatsPktsTx256Octetsto511Octets)
9781169632Sdavidch		BCE_PRINTF("         0x%08X : EtherStatsPktsTx256Octetsto511Octets\n",
9782157642Sps			sblk->stat_EtherStatsPktsTx256Octetsto511Octets);
9783157642Sps
9784157642Sps	if (sblk->stat_EtherStatsPktsTx512Octetsto1023Octets)
9785169632Sdavidch		BCE_PRINTF("         0x%08X : EtherStatsPktsTx512Octetsto1023Octets\n",
9786157642Sps			sblk->stat_EtherStatsPktsTx512Octetsto1023Octets);
9787157642Sps
9788157642Sps	if (sblk->stat_EtherStatsPktsTx1024Octetsto1522Octets)
9789169632Sdavidch		BCE_PRINTF("         0x%08X : EtherStatsPktsTx1024Octetsto1522Octets\n",
9790157642Sps			sblk->stat_EtherStatsPktsTx1024Octetsto1522Octets);
9791157642Sps
9792157642Sps	if (sblk->stat_EtherStatsPktsTx1523Octetsto9022Octets)
9793169632Sdavidch		BCE_PRINTF("         0x%08X : EtherStatsPktsTx1523Octetsto9022Octets\n",
9794157642Sps			sblk->stat_EtherStatsPktsTx1523Octetsto9022Octets);
9795157642Sps
9796157642Sps	if (sblk->stat_XonPauseFramesReceived)
9797169632Sdavidch		BCE_PRINTF("         0x%08X : XonPauseFramesReceived\n",
9798157642Sps			sblk->stat_XonPauseFramesReceived);
9799157642Sps
9800157642Sps	if (sblk->stat_XoffPauseFramesReceived)
9801169632Sdavidch	   BCE_PRINTF("          0x%08X : XoffPauseFramesReceived\n",
9802157642Sps			sblk->stat_XoffPauseFramesReceived);
9803157642Sps
9804157642Sps	if (sblk->stat_OutXonSent)
9805169632Sdavidch		BCE_PRINTF("         0x%08X : OutXonSent\n",
9806157642Sps			sblk->stat_OutXonSent);
9807157642Sps
9808157642Sps	if (sblk->stat_OutXoffSent)
9809169632Sdavidch		BCE_PRINTF("         0x%08X : OutXoffSent\n",
9810157642Sps			sblk->stat_OutXoffSent);
9811157642Sps
9812157642Sps	if (sblk->stat_FlowControlDone)
9813169632Sdavidch		BCE_PRINTF("         0x%08X : FlowControlDone\n",
9814157642Sps			sblk->stat_FlowControlDone);
9815157642Sps
9816157642Sps	if (sblk->stat_MacControlFramesReceived)
9817169632Sdavidch		BCE_PRINTF("         0x%08X : MacControlFramesReceived\n",
9818157642Sps			sblk->stat_MacControlFramesReceived);
9819157642Sps
9820157642Sps	if (sblk->stat_XoffStateEntered)
9821169632Sdavidch		BCE_PRINTF("         0x%08X : XoffStateEntered\n",
9822157642Sps			sblk->stat_XoffStateEntered);
9823157642Sps
9824157642Sps	if (sblk->stat_IfInFramesL2FilterDiscards)
9825169632Sdavidch		BCE_PRINTF("         0x%08X : IfInFramesL2FilterDiscards\n",
9826157642Sps			sblk->stat_IfInFramesL2FilterDiscards);
9827157642Sps
9828157642Sps	if (sblk->stat_IfInRuleCheckerDiscards)
9829169632Sdavidch		BCE_PRINTF("         0x%08X : IfInRuleCheckerDiscards\n",
9830157642Sps			sblk->stat_IfInRuleCheckerDiscards);
9831157642Sps
9832157642Sps	if (sblk->stat_IfInFTQDiscards)
9833169632Sdavidch		BCE_PRINTF("         0x%08X : IfInFTQDiscards\n",
9834157642Sps			sblk->stat_IfInFTQDiscards);
9835157642Sps
9836157642Sps	if (sblk->stat_IfInMBUFDiscards)
9837169632Sdavidch		BCE_PRINTF("         0x%08X : IfInMBUFDiscards\n",
9838157642Sps			sblk->stat_IfInMBUFDiscards);
9839157642Sps
9840157642Sps	if (sblk->stat_IfInRuleCheckerP4Hit)
9841169632Sdavidch		BCE_PRINTF("         0x%08X : IfInRuleCheckerP4Hit\n",
9842157642Sps			sblk->stat_IfInRuleCheckerP4Hit);
9843157642Sps
9844157642Sps	if (sblk->stat_CatchupInRuleCheckerDiscards)
9845169632Sdavidch		BCE_PRINTF("         0x%08X : CatchupInRuleCheckerDiscards\n",
9846157642Sps			sblk->stat_CatchupInRuleCheckerDiscards);
9847157642Sps
9848157642Sps	if (sblk->stat_CatchupInFTQDiscards)
9849169632Sdavidch		BCE_PRINTF("         0x%08X : CatchupInFTQDiscards\n",
9850157642Sps			sblk->stat_CatchupInFTQDiscards);
9851157642Sps
9852157642Sps	if (sblk->stat_CatchupInMBUFDiscards)
9853169632Sdavidch		BCE_PRINTF("         0x%08X : CatchupInMBUFDiscards\n",
9854157642Sps			sblk->stat_CatchupInMBUFDiscards);
9855157642Sps
9856157642Sps	if (sblk->stat_CatchupInRuleCheckerP4Hit)
9857169632Sdavidch		BCE_PRINTF("         0x%08X : CatchupInRuleCheckerP4Hit\n",
9858157642Sps			sblk->stat_CatchupInRuleCheckerP4Hit);
9859157642Sps
9860169271Sdavidch	BCE_PRINTF(
9861169271Sdavidch		"----------------------------"
9862169271Sdavidch		"----------------"
9863169271Sdavidch		"----------------------------\n");
9864157642Sps}
9865157642Sps
9866157642Sps
9867169271Sdavidch/****************************************************************************/
9868169271Sdavidch/* Prints out a summary of the driver state.                                */
9869169271Sdavidch/*                                                                          */
9870169271Sdavidch/* Returns:                                                                 */
9871169271Sdavidch/*   Nothing.                                                               */
9872169271Sdavidch/****************************************************************************/
9873179771Sdavidchstatic __attribute__ ((noinline)) void
9874157642Spsbce_dump_driver_state(struct bce_softc *sc)
9875157642Sps{
9876157642Sps	u32 val_hi, val_lo;
9877157642Sps
9878169271Sdavidch	BCE_PRINTF(
9879157642Sps		"-----------------------------"
9880157642Sps		" Driver State "
9881157642Sps		"-----------------------------\n");
9882157642Sps
9883157642Sps	val_hi = BCE_ADDR_HI(sc);
9884157642Sps	val_lo = BCE_ADDR_LO(sc);
9885169271Sdavidch	BCE_PRINTF("0x%08X:%08X - (sc) driver softc structure virtual address\n",
9886157642Sps		val_hi, val_lo);
9887157642Sps
9888157642Sps	val_hi = BCE_ADDR_HI(sc->bce_vhandle);
9889157642Sps	val_lo = BCE_ADDR_LO(sc->bce_vhandle);
9890169271Sdavidch	BCE_PRINTF("0x%08X:%08X - (sc->bce_vhandle) PCI BAR virtual address\n",
9891157642Sps		val_hi, val_lo);
9892157642Sps
9893157642Sps	val_hi = BCE_ADDR_HI(sc->status_block);
9894157642Sps	val_lo = BCE_ADDR_LO(sc->status_block);
9895169271Sdavidch	BCE_PRINTF("0x%08X:%08X - (sc->status_block) status block virtual address\n",
9896157642Sps		val_hi, val_lo);
9897157642Sps
9898157642Sps	val_hi = BCE_ADDR_HI(sc->stats_block);
9899157642Sps	val_lo = BCE_ADDR_LO(sc->stats_block);
9900169271Sdavidch	BCE_PRINTF("0x%08X:%08X - (sc->stats_block) statistics block virtual address\n",
9901157642Sps		val_hi, val_lo);
9902157642Sps
9903157642Sps	val_hi = BCE_ADDR_HI(sc->tx_bd_chain);
9904157642Sps	val_lo = BCE_ADDR_LO(sc->tx_bd_chain);
9905169271Sdavidch	BCE_PRINTF(
9906157642Sps		"0x%08X:%08X - (sc->tx_bd_chain) tx_bd chain virtual adddress\n",
9907157642Sps		val_hi, val_lo);
9908157642Sps
9909157642Sps	val_hi = BCE_ADDR_HI(sc->rx_bd_chain);
9910157642Sps	val_lo = BCE_ADDR_LO(sc->rx_bd_chain);
9911169271Sdavidch	BCE_PRINTF(
9912157642Sps		"0x%08X:%08X - (sc->rx_bd_chain) rx_bd chain virtual address\n",
9913157642Sps		val_hi, val_lo);
9914157642Sps
9915198320Sstas#ifdef BCE_JUMBO_HDRSPLIT
9916176448Sdavidch	val_hi = BCE_ADDR_HI(sc->pg_bd_chain);
9917176448Sdavidch	val_lo = BCE_ADDR_LO(sc->pg_bd_chain);
9918176448Sdavidch	BCE_PRINTF(
9919176448Sdavidch		"0x%08X:%08X - (sc->pg_bd_chain) page chain virtual address\n",
9920179771Sdavidch		val_hi, val_lo);
9921179695Sdavidch#endif
9922176448Sdavidch
9923157642Sps	val_hi = BCE_ADDR_HI(sc->tx_mbuf_ptr);
9924157642Sps	val_lo = BCE_ADDR_LO(sc->tx_mbuf_ptr);
9925169271Sdavidch	BCE_PRINTF(
9926157642Sps		"0x%08X:%08X - (sc->tx_mbuf_ptr) tx mbuf chain virtual address\n",
9927157642Sps		val_hi, val_lo);
9928157642Sps
9929157642Sps	val_hi = BCE_ADDR_HI(sc->rx_mbuf_ptr);
9930157642Sps	val_lo = BCE_ADDR_LO(sc->rx_mbuf_ptr);
9931179771Sdavidch	BCE_PRINTF(
9932157642Sps		"0x%08X:%08X - (sc->rx_mbuf_ptr) rx mbuf chain virtual address\n",
9933157642Sps		val_hi, val_lo);
9934157642Sps
9935198320Sstas#ifdef BCE_JUMBO_HDRSPLIT
9936176448Sdavidch	val_hi = BCE_ADDR_HI(sc->pg_mbuf_ptr);
9937176448Sdavidch	val_lo = BCE_ADDR_LO(sc->pg_mbuf_ptr);
9938179771Sdavidch	BCE_PRINTF(
9939176448Sdavidch		"0x%08X:%08X - (sc->pg_mbuf_ptr) page mbuf chain virtual address\n",
9940179771Sdavidch		val_hi, val_lo);
9941179695Sdavidch#endif
9942176448Sdavidch
9943169271Sdavidch	BCE_PRINTF("         0x%08X - (sc->interrupts_generated) h/w intrs\n",
9944157642Sps		sc->interrupts_generated);
9945179771Sdavidch
9946169271Sdavidch	BCE_PRINTF("         0x%08X - (sc->rx_interrupts) rx interrupts handled\n",
9947157642Sps		sc->rx_interrupts);
9948157642Sps
9949169271Sdavidch	BCE_PRINTF("         0x%08X - (sc->tx_interrupts) tx interrupts handled\n",
9950157642Sps		sc->tx_interrupts);
9951157642Sps
9952169271Sdavidch	BCE_PRINTF("         0x%08X - (sc->last_status_idx) status block index\n",
9953157642Sps		sc->last_status_idx);
9954157642Sps
9955169632Sdavidch	BCE_PRINTF("     0x%04X(0x%04X) - (sc->tx_prod) tx producer index\n",
9956169632Sdavidch		sc->tx_prod, (u16) TX_CHAIN_IDX(sc->tx_prod));
9957157642Sps
9958169632Sdavidch	BCE_PRINTF("     0x%04X(0x%04X) - (sc->tx_cons) tx consumer index\n",
9959169632Sdavidch		sc->tx_cons, (u16) TX_CHAIN_IDX(sc->tx_cons));
9960157642Sps
9961169271Sdavidch	BCE_PRINTF("         0x%08X - (sc->tx_prod_bseq) tx producer bseq index\n",
9962157642Sps		sc->tx_prod_bseq);
9963157642Sps
9964176448Sdavidch	BCE_PRINTF("         0x%08X - (sc->debug_tx_mbuf_alloc) tx mbufs allocated\n",
9965176448Sdavidch		sc->debug_tx_mbuf_alloc);
9966171667Sdavidch
9967171667Sdavidch	BCE_PRINTF("         0x%08X - (sc->used_tx_bd) used tx_bd's\n",
9968171667Sdavidch		sc->used_tx_bd);
9969171667Sdavidch
9970171667Sdavidch	BCE_PRINTF("0x%08X/%08X - (sc->tx_hi_watermark) tx hi watermark\n",
9971171667Sdavidch		sc->tx_hi_watermark, sc->max_tx_bd);
9972171667Sdavidch
9973169632Sdavidch	BCE_PRINTF("     0x%04X(0x%04X) - (sc->rx_prod) rx producer index\n",
9974169632Sdavidch		sc->rx_prod, (u16) RX_CHAIN_IDX(sc->rx_prod));
9975157642Sps
9976169632Sdavidch	BCE_PRINTF("     0x%04X(0x%04X) - (sc->rx_cons) rx consumer index\n",
9977169632Sdavidch		sc->rx_cons, (u16) RX_CHAIN_IDX(sc->rx_cons));
9978157642Sps
9979169271Sdavidch	BCE_PRINTF("         0x%08X - (sc->rx_prod_bseq) rx producer bseq index\n",
9980157642Sps		sc->rx_prod_bseq);
9981157642Sps
9982176448Sdavidch	BCE_PRINTF("         0x%08X - (sc->debug_rx_mbuf_alloc) rx mbufs allocated\n",
9983176448Sdavidch		sc->debug_rx_mbuf_alloc);
9984157642Sps
9985169271Sdavidch	BCE_PRINTF("         0x%08X - (sc->free_rx_bd) free rx_bd's\n",
9986157642Sps		sc->free_rx_bd);
9987157642Sps
9988198320Sstas#ifdef BCE_JUMBO_HDRSPLIT
9989176448Sdavidch	BCE_PRINTF("     0x%04X(0x%04X) - (sc->pg_prod) page producer index\n",
9990176448Sdavidch		sc->pg_prod, (u16) PG_CHAIN_IDX(sc->pg_prod));
9991157642Sps
9992176448Sdavidch	BCE_PRINTF("     0x%04X(0x%04X) - (sc->pg_cons) page consumer index\n",
9993176448Sdavidch		sc->pg_cons, (u16) PG_CHAIN_IDX(sc->pg_cons));
9994176448Sdavidch
9995176448Sdavidch	BCE_PRINTF("         0x%08X - (sc->debug_pg_mbuf_alloc) page mbufs allocated\n",
9996176448Sdavidch		sc->debug_pg_mbuf_alloc);
9997176448Sdavidch
9998176448Sdavidch	BCE_PRINTF("         0x%08X - (sc->free_pg_bd) free page rx_bd's\n",
9999176448Sdavidch		sc->free_pg_bd);
10000176448Sdavidch
10001176448Sdavidch	BCE_PRINTF("0x%08X/%08X - (sc->pg_low_watermark) page low watermark\n",
10002176448Sdavidch		sc->pg_low_watermark, sc->max_pg_bd);
10003179771Sdavidch#endif
10004176448Sdavidch
10005189325Sdavidch	BCE_PRINTF("         0x%08X - (sc->mbuf_alloc_failed_count) "
10006171667Sdavidch		"mbuf alloc failures\n",
10007189325Sdavidch		sc->mbuf_alloc_failed_count);
10008157642Sps
10009179771Sdavidch	BCE_PRINTF("         0x%08X - (sc->bce_flags) bce mac flags\n",
10010179771Sdavidch		sc->bce_flags);
10011179771Sdavidch
10012179771Sdavidch	BCE_PRINTF("         0x%08X - (sc->bce_phy_flags) bce phy flags\n",
10013179771Sdavidch		sc->bce_phy_flags);
10014179771Sdavidch
10015169271Sdavidch	BCE_PRINTF(
10016169271Sdavidch		"----------------------------"
10017169271Sdavidch		"----------------"
10018169271Sdavidch		"----------------------------\n");
10019157642Sps}
10020157642Sps
10021170392Sdavidch
10022169271Sdavidch/****************************************************************************/
10023170810Sdavidch/* Prints out the hardware state through a summary of important register,   */
10024169271Sdavidch/* followed by a complete register dump.                                    */
10025169271Sdavidch/*                                                                          */
10026169271Sdavidch/* Returns:                                                                 */
10027169271Sdavidch/*   Nothing.                                                               */
10028169271Sdavidch/****************************************************************************/
10029179771Sdavidchstatic __attribute__ ((noinline)) void
10030157642Spsbce_dump_hw_state(struct bce_softc *sc)
10031157642Sps{
10032176448Sdavidch	u32 val;
10033157642Sps
10034169271Sdavidch	BCE_PRINTF(
10035157642Sps		"----------------------------"
10036157642Sps		" Hardware State "
10037157642Sps		"----------------------------\n");
10038157642Sps
10039194781Sdavidch	BCE_PRINTF("%s - bootcode version\n", sc->bce_bc_ver);
10040157642Sps
10041176448Sdavidch	val = REG_RD(sc, BCE_MISC_ENABLE_STATUS_BITS);
10042169632Sdavidch	BCE_PRINTF("0x%08X - (0x%06X) misc_enable_status_bits\n",
10043176448Sdavidch		val, BCE_MISC_ENABLE_STATUS_BITS);
10044157642Sps
10045176448Sdavidch	val = REG_RD(sc, BCE_DMA_STATUS);
10046176448Sdavidch	BCE_PRINTF("0x%08X - (0x%06X) dma_status\n", val, BCE_DMA_STATUS);
10047157642Sps
10048176448Sdavidch	val = REG_RD(sc, BCE_CTX_STATUS);
10049176448Sdavidch	BCE_PRINTF("0x%08X - (0x%06X) ctx_status\n", val, BCE_CTX_STATUS);
10050157642Sps
10051176448Sdavidch	val = REG_RD(sc, BCE_EMAC_STATUS);
10052176448Sdavidch	BCE_PRINTF("0x%08X - (0x%06X) emac_status\n", val, BCE_EMAC_STATUS);
10053157642Sps
10054176448Sdavidch	val = REG_RD(sc, BCE_RPM_STATUS);
10055176448Sdavidch	BCE_PRINTF("0x%08X - (0x%06X) rpm_status\n", val, BCE_RPM_STATUS);
10056157642Sps
10057176448Sdavidch	val = REG_RD(sc, 0x2004);
10058176448Sdavidch	BCE_PRINTF("0x%08X - (0x%06X) rlup_status\n", val, 0x2004);
10059157642Sps
10060176448Sdavidch	val = REG_RD(sc, BCE_RV2P_STATUS);
10061176448Sdavidch	BCE_PRINTF("0x%08X - (0x%06X) rv2p_status\n", val, BCE_RV2P_STATUS);
10062157642Sps
10063176448Sdavidch	val = REG_RD(sc, 0x2c04);
10064176448Sdavidch	BCE_PRINTF("0x%08X - (0x%06X) rdma_status\n", val, 0x2c04);
10065157642Sps
10066176448Sdavidch	val = REG_RD(sc, BCE_TBDR_STATUS);
10067176448Sdavidch	BCE_PRINTF("0x%08X - (0x%06X) tbdr_status\n", val, BCE_TBDR_STATUS);
10068169632Sdavidch
10069176448Sdavidch	val = REG_RD(sc, BCE_TDMA_STATUS);
10070176448Sdavidch	BCE_PRINTF("0x%08X - (0x%06X) tdma_status\n", val, BCE_TDMA_STATUS);
10071169632Sdavidch
10072176448Sdavidch	val = REG_RD(sc, BCE_HC_STATUS);
10073176448Sdavidch	BCE_PRINTF("0x%08X - (0x%06X) hc_status\n", val, BCE_HC_STATUS);
10074169632Sdavidch
10075176448Sdavidch	val = REG_RD_IND(sc, BCE_TXP_CPU_STATE);
10076176448Sdavidch	BCE_PRINTF("0x%08X - (0x%06X) txp_cpu_state\n", val, BCE_TXP_CPU_STATE);
10077169632Sdavidch
10078176448Sdavidch	val = REG_RD_IND(sc, BCE_TPAT_CPU_STATE);
10079176448Sdavidch	BCE_PRINTF("0x%08X - (0x%06X) tpat_cpu_state\n", val, BCE_TPAT_CPU_STATE);
10080169632Sdavidch
10081176448Sdavidch	val = REG_RD_IND(sc, BCE_RXP_CPU_STATE);
10082176448Sdavidch	BCE_PRINTF("0x%08X - (0x%06X) rxp_cpu_state\n", val, BCE_RXP_CPU_STATE);
10083169632Sdavidch
10084176448Sdavidch	val = REG_RD_IND(sc, BCE_COM_CPU_STATE);
10085176448Sdavidch	BCE_PRINTF("0x%08X - (0x%06X) com_cpu_state\n", val, BCE_COM_CPU_STATE);
10086176448Sdavidch
10087176448Sdavidch	val = REG_RD_IND(sc, BCE_MCP_CPU_STATE);
10088176448Sdavidch	BCE_PRINTF("0x%08X - (0x%06X) mcp_cpu_state\n", val, BCE_MCP_CPU_STATE);
10089176448Sdavidch
10090176448Sdavidch	val = REG_RD_IND(sc, BCE_CP_CPU_STATE);
10091176448Sdavidch	BCE_PRINTF("0x%08X - (0x%06X) cp_cpu_state\n", val, BCE_CP_CPU_STATE);
10092176448Sdavidch
10093179771Sdavidch	BCE_PRINTF(
10094157642Sps		"----------------------------"
10095157642Sps		"----------------"
10096157642Sps		"----------------------------\n");
10097157642Sps
10098179771Sdavidch	BCE_PRINTF(
10099157642Sps		"----------------------------"
10100157642Sps		" Register  Dump "
10101157642Sps		"----------------------------\n");
10102170392Sdavidch
10103178132Sdavidch	for (int i = 0x400; i < 0x8000; i += 0x10) {
10104169271Sdavidch		BCE_PRINTF("0x%04X: 0x%08X 0x%08X 0x%08X 0x%08X\n",
10105157642Sps			i, REG_RD(sc, i), REG_RD(sc, i + 0x4),
10106178132Sdavidch			REG_RD(sc, i + 0x8), REG_RD(sc, i + 0xC));
10107176448Sdavidch	}
10108157642Sps
10109179771Sdavidch	BCE_PRINTF(
10110157642Sps		"----------------------------"
10111157642Sps		"----------------"
10112157642Sps		"----------------------------\n");
10113157642Sps}
10114157642Sps
10115157642Sps
10116169271Sdavidch/****************************************************************************/
10117179771Sdavidch/* Prints out the mailbox queue registers.                                  */
10118179771Sdavidch/*                                                                          */
10119179771Sdavidch/* Returns:                                                                 */
10120179771Sdavidch/*   Nothing.                                                               */
10121179771Sdavidch/****************************************************************************/
10122179771Sdavidchstatic __attribute__ ((noinline)) void
10123179771Sdavidchbce_dump_mq_regs(struct bce_softc *sc)
10124179771Sdavidch{
10125179771Sdavidch	BCE_PRINTF(
10126179771Sdavidch		"----------------------------"
10127179771Sdavidch		"    MQ Regs     "
10128179771Sdavidch		"----------------------------\n");
10129179771Sdavidch
10130179771Sdavidch	BCE_PRINTF(
10131179771Sdavidch		"----------------------------"
10132179771Sdavidch		"----------------"
10133179771Sdavidch		"----------------------------\n");
10134179771Sdavidch
10135179771Sdavidch	for (int i = 0x3c00; i < 0x4000; i += 0x10) {
10136179771Sdavidch		BCE_PRINTF("0x%04X: 0x%08X 0x%08X 0x%08X 0x%08X\n",
10137179771Sdavidch			i, REG_RD(sc, i), REG_RD(sc, i + 0x4),
10138179771Sdavidch			REG_RD(sc, i + 0x8), REG_RD(sc, i + 0xC));
10139179771Sdavidch	}
10140179771Sdavidch
10141179771Sdavidch	BCE_PRINTF(
10142179771Sdavidch		"----------------------------"
10143179771Sdavidch		"----------------"
10144179771Sdavidch		"----------------------------\n");
10145179771Sdavidch}
10146179771Sdavidch
10147179771Sdavidch
10148179771Sdavidch/****************************************************************************/
10149170810Sdavidch/* Prints out the bootcode state.                                           */
10150170810Sdavidch/*                                                                          */
10151170810Sdavidch/* Returns:                                                                 */
10152170810Sdavidch/*   Nothing.                                                               */
10153170810Sdavidch/****************************************************************************/
10154179771Sdavidchstatic __attribute__ ((noinline)) void
10155170810Sdavidchbce_dump_bc_state(struct bce_softc *sc)
10156170810Sdavidch{
10157170810Sdavidch	u32 val;
10158170810Sdavidch
10159170810Sdavidch	BCE_PRINTF(
10160170810Sdavidch		"----------------------------"
10161170810Sdavidch		" Bootcode State "
10162170810Sdavidch		"----------------------------\n");
10163170810Sdavidch
10164194781Sdavidch	BCE_PRINTF("%s - bootcode version\n", sc->bce_bc_ver);
10165170810Sdavidch
10166194781Sdavidch	val = bce_shmem_rd(sc, BCE_BC_RESET_TYPE);
10167170810Sdavidch	BCE_PRINTF("0x%08X - (0x%06X) reset_type\n",
10168170810Sdavidch		val, BCE_BC_RESET_TYPE);
10169170810Sdavidch
10170194781Sdavidch	val = bce_shmem_rd(sc, BCE_BC_STATE);
10171170810Sdavidch	BCE_PRINTF("0x%08X - (0x%06X) state\n",
10172170810Sdavidch		val, BCE_BC_STATE);
10173170810Sdavidch
10174202717Sdavidch	val = bce_shmem_rd(sc, BCE_BC_STATE_CONDITION);
10175170810Sdavidch	BCE_PRINTF("0x%08X - (0x%06X) condition\n",
10176202717Sdavidch		val, BCE_BC_STATE_CONDITION);
10177170810Sdavidch
10178194781Sdavidch	val = bce_shmem_rd(sc, BCE_BC_STATE_DEBUG_CMD);
10179170810Sdavidch	BCE_PRINTF("0x%08X - (0x%06X) debug_cmd\n",
10180170810Sdavidch		val, BCE_BC_STATE_DEBUG_CMD);
10181170810Sdavidch
10182179771Sdavidch	BCE_PRINTF(
10183170810Sdavidch		"----------------------------"
10184170810Sdavidch		"----------------"
10185170810Sdavidch		"----------------------------\n");
10186170810Sdavidch}
10187170810Sdavidch
10188170810Sdavidch
10189170810Sdavidch/****************************************************************************/
10190179771Sdavidch/* Prints out the TXP processor state.                                      */
10191169632Sdavidch/*                                                                          */
10192169632Sdavidch/* Returns:                                                                 */
10193169632Sdavidch/*   Nothing.                                                               */
10194169632Sdavidch/****************************************************************************/
10195179771Sdavidchstatic __attribute__ ((noinline)) void
10196179771Sdavidchbce_dump_txp_state(struct bce_softc *sc, int regs)
10197169632Sdavidch{
10198179771Sdavidch	u32 val;
10199182293Sdavidch	u32 fw_version[3];
10200169632Sdavidch
10201169632Sdavidch	BCE_PRINTF(
10202169632Sdavidch		"----------------------------"
10203169632Sdavidch		"   TXP  State   "
10204169632Sdavidch		"----------------------------\n");
10205169632Sdavidch
10206182293Sdavidch	for (int i = 0; i < 3; i++)
10207182293Sdavidch		fw_version[i] = htonl(REG_RD_IND(sc,
10208182293Sdavidch			(BCE_TXP_SCRATCH + 0x10 + i * 4)));
10209182293Sdavidch	BCE_PRINTF("Firmware version - %s\n", (char *) fw_version);
10210182293Sdavidch
10211179771Sdavidch	val = REG_RD_IND(sc, BCE_TXP_CPU_MODE);
10212179771Sdavidch	BCE_PRINTF("0x%08X - (0x%06X) txp_cpu_mode\n", val, BCE_TXP_CPU_MODE);
10213169632Sdavidch
10214179771Sdavidch	val = REG_RD_IND(sc, BCE_TXP_CPU_STATE);
10215179771Sdavidch	BCE_PRINTF("0x%08X - (0x%06X) txp_cpu_state\n", val, BCE_TXP_CPU_STATE);
10216169632Sdavidch
10217179771Sdavidch	val = REG_RD_IND(sc, BCE_TXP_CPU_EVENT_MASK);
10218179771Sdavidch	BCE_PRINTF("0x%08X - (0x%06X) txp_cpu_event_mask\n", val,
10219179771Sdavidch		BCE_TXP_CPU_EVENT_MASK);
10220169632Sdavidch
10221179771Sdavidch	if (regs) {
10222179771Sdavidch		BCE_PRINTF(
10223179771Sdavidch			"----------------------------"
10224179771Sdavidch			" Register  Dump "
10225179771Sdavidch			"----------------------------\n");
10226170392Sdavidch
10227179771Sdavidch		for (int i = BCE_TXP_CPU_MODE; i < 0x68000; i += 0x10) {
10228179771Sdavidch			/* Skip the big blank spaces */
10229179771Sdavidch			if (i < 0x454000 && i > 0x5ffff)
10230179771Sdavidch				BCE_PRINTF("0x%04X: 0x%08X 0x%08X 0x%08X 0x%08X\n",
10231179771Sdavidch					i, REG_RD_IND(sc, i), REG_RD_IND(sc, i + 0x4),
10232179771Sdavidch					REG_RD_IND(sc, i + 0x8), REG_RD_IND(sc, i + 0xC));
10233179771Sdavidch		}
10234169632Sdavidch	}
10235169632Sdavidch
10236179771Sdavidch	BCE_PRINTF(
10237169632Sdavidch		"----------------------------"
10238169632Sdavidch		"----------------"
10239169632Sdavidch		"----------------------------\n");
10240169632Sdavidch}
10241169632Sdavidch
10242169632Sdavidch
10243169632Sdavidch/****************************************************************************/
10244179771Sdavidch/* Prints out the RXP processor state.                                      */
10245169632Sdavidch/*                                                                          */
10246169632Sdavidch/* Returns:                                                                 */
10247169632Sdavidch/*   Nothing.                                                               */
10248169632Sdavidch/****************************************************************************/
10249179771Sdavidchstatic __attribute__ ((noinline)) void
10250179771Sdavidchbce_dump_rxp_state(struct bce_softc *sc, int regs)
10251169632Sdavidch{
10252179771Sdavidch	u32 val;
10253182293Sdavidch	u32 fw_version[3];
10254169632Sdavidch
10255169632Sdavidch	BCE_PRINTF(
10256169632Sdavidch		"----------------------------"
10257169632Sdavidch		"   RXP  State   "
10258169632Sdavidch		"----------------------------\n");
10259169632Sdavidch
10260182293Sdavidch	for (int i = 0; i < 3; i++)
10261182293Sdavidch		fw_version[i] = htonl(REG_RD_IND(sc,
10262182293Sdavidch			(BCE_RXP_SCRATCH + 0x10 + i * 4)));
10263182293Sdavidch	BCE_PRINTF("Firmware version - %s\n", (char *) fw_version);
10264182293Sdavidch
10265179771Sdavidch	val = REG_RD_IND(sc, BCE_RXP_CPU_MODE);
10266179771Sdavidch	BCE_PRINTF("0x%08X - (0x%06X) rxp_cpu_mode\n", val, BCE_RXP_CPU_MODE);
10267169632Sdavidch
10268179771Sdavidch	val = REG_RD_IND(sc, BCE_RXP_CPU_STATE);
10269179771Sdavidch	BCE_PRINTF("0x%08X - (0x%06X) rxp_cpu_state\n", val, BCE_RXP_CPU_STATE);
10270169632Sdavidch
10271179771Sdavidch	val = REG_RD_IND(sc, BCE_RXP_CPU_EVENT_MASK);
10272179771Sdavidch	BCE_PRINTF("0x%08X - (0x%06X) rxp_cpu_event_mask\n", val,
10273179771Sdavidch		BCE_RXP_CPU_EVENT_MASK);
10274169632Sdavidch
10275179771Sdavidch	if (regs) {
10276179771Sdavidch		BCE_PRINTF(
10277179771Sdavidch			"----------------------------"
10278179771Sdavidch			" Register  Dump "
10279179771Sdavidch			"----------------------------\n");
10280179771Sdavidch
10281179771Sdavidch		for (int i = BCE_RXP_CPU_MODE; i < 0xe8fff; i += 0x10) {
10282179771Sdavidch			/* Skip the big blank sapces */
10283179771Sdavidch			if (i < 0xc5400 && i > 0xdffff)
10284179771Sdavidch				BCE_PRINTF("0x%04X: 0x%08X 0x%08X 0x%08X 0x%08X\n",
10285179771Sdavidch	 				i, REG_RD_IND(sc, i), REG_RD_IND(sc, i + 0x4),
10286179771Sdavidch					REG_RD_IND(sc, i + 0x8), REG_RD_IND(sc, i + 0xC));
10287179771Sdavidch		}
10288179771Sdavidch	}
10289179771Sdavidch
10290179771Sdavidch	BCE_PRINTF(
10291169632Sdavidch		"----------------------------"
10292179771Sdavidch		"----------------"
10293169632Sdavidch		"----------------------------\n");
10294179771Sdavidch}
10295170392Sdavidch
10296179771Sdavidch
10297179771Sdavidch/****************************************************************************/
10298179771Sdavidch/* Prints out the TPAT processor state.                                     */
10299179771Sdavidch/*                                                                          */
10300179771Sdavidch/* Returns:                                                                 */
10301179771Sdavidch/*   Nothing.                                                               */
10302179771Sdavidch/****************************************************************************/
10303179771Sdavidchstatic __attribute__ ((noinline)) void
10304179771Sdavidchbce_dump_tpat_state(struct bce_softc *sc, int regs)
10305179771Sdavidch{
10306179771Sdavidch	u32 val;
10307182293Sdavidch	u32 fw_version[3];
10308179771Sdavidch
10309179771Sdavidch	BCE_PRINTF(
10310179771Sdavidch		"----------------------------"
10311179771Sdavidch		"   TPAT State   "
10312179771Sdavidch		"----------------------------\n");
10313179771Sdavidch
10314182293Sdavidch	for (int i = 0; i < 3; i++)
10315182293Sdavidch		fw_version[i] = htonl(REG_RD_IND(sc,
10316182293Sdavidch			(BCE_TPAT_SCRATCH + 0x410 + i * 4)));
10317182293Sdavidch	BCE_PRINTF("Firmware version - %s\n", (char *) fw_version);
10318182293Sdavidch
10319179771Sdavidch	val = REG_RD_IND(sc, BCE_TPAT_CPU_MODE);
10320179771Sdavidch	BCE_PRINTF("0x%08X - (0x%06X) tpat_cpu_mode\n", val, BCE_TPAT_CPU_MODE);
10321179771Sdavidch
10322179771Sdavidch	val = REG_RD_IND(sc, BCE_TPAT_CPU_STATE);
10323179771Sdavidch	BCE_PRINTF("0x%08X - (0x%06X) tpat_cpu_state\n", val, BCE_TPAT_CPU_STATE);
10324179771Sdavidch
10325179771Sdavidch	val = REG_RD_IND(sc, BCE_TPAT_CPU_EVENT_MASK);
10326179771Sdavidch	BCE_PRINTF("0x%08X - (0x%06X) tpat_cpu_event_mask\n", val,
10327179771Sdavidch		BCE_TPAT_CPU_EVENT_MASK);
10328179771Sdavidch
10329179771Sdavidch	if (regs) {
10330179771Sdavidch		BCE_PRINTF(
10331179771Sdavidch			"----------------------------"
10332179771Sdavidch			" Register  Dump "
10333179771Sdavidch			"----------------------------\n");
10334179771Sdavidch
10335179771Sdavidch		for (int i = BCE_TPAT_CPU_MODE; i < 0xa3fff; i += 0x10) {
10336179771Sdavidch			/* Skip the big blank spaces */
10337179771Sdavidch			if (i < 0x854000 && i > 0x9ffff)
10338179771Sdavidch				BCE_PRINTF("0x%04X: 0x%08X 0x%08X 0x%08X 0x%08X\n",
10339179771Sdavidch					i, REG_RD_IND(sc, i), REG_RD_IND(sc, i + 0x4),
10340179771Sdavidch					REG_RD_IND(sc, i + 0x8), REG_RD_IND(sc, i + 0xC));
10341179771Sdavidch		}
10342169632Sdavidch	}
10343169632Sdavidch
10344179771Sdavidch	BCE_PRINTF(
10345169632Sdavidch		"----------------------------"
10346169632Sdavidch		"----------------"
10347169632Sdavidch		"----------------------------\n");
10348169632Sdavidch}
10349169632Sdavidch
10350169632Sdavidch
10351169632Sdavidch/****************************************************************************/
10352179771Sdavidch/* Prints out the Command Procesor (CP) state.                              */
10353169632Sdavidch/*                                                                          */
10354169632Sdavidch/* Returns:                                                                 */
10355169632Sdavidch/*   Nothing.                                                               */
10356169632Sdavidch/****************************************************************************/
10357179771Sdavidchstatic __attribute__ ((noinline)) void
10358179771Sdavidchbce_dump_cp_state(struct bce_softc *sc, int regs)
10359169632Sdavidch{
10360179771Sdavidch	u32 val;
10361182293Sdavidch	u32 fw_version[3];
10362169632Sdavidch
10363169632Sdavidch	BCE_PRINTF(
10364169632Sdavidch		"----------------------------"
10365179771Sdavidch		"    CP State    "
10366169632Sdavidch		"----------------------------\n");
10367169632Sdavidch
10368182293Sdavidch	for (int i = 0; i < 3; i++)
10369182293Sdavidch		fw_version[i] = htonl(REG_RD_IND(sc,
10370182293Sdavidch			(BCE_CP_SCRATCH + 0x10 + i * 4)));
10371182293Sdavidch	BCE_PRINTF("Firmware version - %s\n", (char *) fw_version);
10372182293Sdavidch
10373179771Sdavidch	val = REG_RD_IND(sc, BCE_CP_CPU_MODE);
10374179771Sdavidch	BCE_PRINTF("0x%08X - (0x%06X) cp_cpu_mode\n", val, BCE_CP_CPU_MODE);
10375169632Sdavidch
10376179771Sdavidch	val = REG_RD_IND(sc, BCE_CP_CPU_STATE);
10377179771Sdavidch	BCE_PRINTF("0x%08X - (0x%06X) cp_cpu_state\n", val, BCE_CP_CPU_STATE);
10378169632Sdavidch
10379179771Sdavidch	val = REG_RD_IND(sc, BCE_CP_CPU_EVENT_MASK);
10380179771Sdavidch	BCE_PRINTF("0x%08X - (0x%06X) cp_cpu_event_mask\n", val,
10381179771Sdavidch		BCE_CP_CPU_EVENT_MASK);
10382169632Sdavidch
10383179771Sdavidch	if (regs) {
10384179771Sdavidch		BCE_PRINTF(
10385179771Sdavidch			"----------------------------"
10386179771Sdavidch			" Register  Dump "
10387179771Sdavidch			"----------------------------\n");
10388179771Sdavidch
10389179771Sdavidch		for (int i = BCE_CP_CPU_MODE; i < 0x1aa000; i += 0x10) {
10390179771Sdavidch			/* Skip the big blank spaces */
10391179771Sdavidch			if (i < 0x185400 && i > 0x19ffff)
10392179771Sdavidch				BCE_PRINTF("0x%04X: 0x%08X 0x%08X 0x%08X 0x%08X\n",
10393179771Sdavidch					i, REG_RD_IND(sc, i), REG_RD_IND(sc, i + 0x4),
10394179771Sdavidch					REG_RD_IND(sc, i + 0x8), REG_RD_IND(sc, i + 0xC));
10395179771Sdavidch		}
10396179771Sdavidch	}
10397179771Sdavidch
10398179771Sdavidch	BCE_PRINTF(
10399169632Sdavidch		"----------------------------"
10400179771Sdavidch		"----------------"
10401169632Sdavidch		"----------------------------\n");
10402179771Sdavidch}
10403170392Sdavidch
10404179771Sdavidch
10405179771Sdavidch/****************************************************************************/
10406179771Sdavidch/* Prints out the Completion Procesor (COM) state.                          */
10407179771Sdavidch/*                                                                          */
10408179771Sdavidch/* Returns:                                                                 */
10409179771Sdavidch/*   Nothing.                                                               */
10410179771Sdavidch/****************************************************************************/
10411179771Sdavidchstatic __attribute__ ((noinline)) void
10412179771Sdavidchbce_dump_com_state(struct bce_softc *sc, int regs)
10413179771Sdavidch{
10414179771Sdavidch	u32 val;
10415182293Sdavidch	u32 fw_version[3];
10416179771Sdavidch
10417179771Sdavidch	BCE_PRINTF(
10418179771Sdavidch		"----------------------------"
10419179771Sdavidch		"   COM State    "
10420179771Sdavidch		"----------------------------\n");
10421179771Sdavidch
10422182293Sdavidch	for (int i = 0; i < 3; i++)
10423182293Sdavidch		fw_version[i] = htonl(REG_RD_IND(sc,
10424182293Sdavidch			(BCE_COM_SCRATCH + 0x10 + i * 4)));
10425182293Sdavidch	BCE_PRINTF("Firmware version - %s\n", (char *) fw_version);
10426182293Sdavidch
10427179771Sdavidch	val = REG_RD_IND(sc, BCE_COM_CPU_MODE);
10428179771Sdavidch	BCE_PRINTF("0x%08X - (0x%06X) com_cpu_mode\n", val, BCE_COM_CPU_MODE);
10429179771Sdavidch
10430179771Sdavidch	val = REG_RD_IND(sc, BCE_COM_CPU_STATE);
10431179771Sdavidch	BCE_PRINTF("0x%08X - (0x%06X) com_cpu_state\n", val, BCE_COM_CPU_STATE);
10432179771Sdavidch
10433179771Sdavidch	val = REG_RD_IND(sc, BCE_COM_CPU_EVENT_MASK);
10434179771Sdavidch	BCE_PRINTF("0x%08X - (0x%06X) com_cpu_event_mask\n", val,
10435179771Sdavidch		BCE_COM_CPU_EVENT_MASK);
10436179771Sdavidch
10437179771Sdavidch	if (regs) {
10438179771Sdavidch		BCE_PRINTF(
10439179771Sdavidch			"----------------------------"
10440179771Sdavidch			" Register  Dump "
10441179771Sdavidch			"----------------------------\n");
10442179771Sdavidch
10443179771Sdavidch		for (int i = BCE_COM_CPU_MODE; i < 0x1053e8; i += 0x10) {
10444169632Sdavidch			BCE_PRINTF("0x%04X: 0x%08X 0x%08X 0x%08X 0x%08X\n",
10445169632Sdavidch				i, REG_RD_IND(sc, i), REG_RD_IND(sc, i + 0x4),
10446170392Sdavidch				REG_RD_IND(sc, i + 0x8), REG_RD_IND(sc, i + 0xC));
10447179771Sdavidch		}
10448169632Sdavidch	}
10449169632Sdavidch
10450179771Sdavidch	BCE_PRINTF(
10451169632Sdavidch		"----------------------------"
10452169632Sdavidch		"----------------"
10453169632Sdavidch		"----------------------------\n");
10454169632Sdavidch}
10455169632Sdavidch
10456169632Sdavidch
10457169632Sdavidch/****************************************************************************/
10458170392Sdavidch/* Prints out the driver state and then enters the debugger.                */
10459169271Sdavidch/*                                                                          */
10460169271Sdavidch/* Returns:                                                                 */
10461169271Sdavidch/*   Nothing.                                                               */
10462169271Sdavidch/****************************************************************************/
10463157642Spsstatic void
10464157642Spsbce_breakpoint(struct bce_softc *sc)
10465157642Sps{
10466157642Sps
10467179771Sdavidch	/*
10468179771Sdavidch	 * Unreachable code to silence compiler warnings
10469179771Sdavidch	 * about unused functions.
10470176448Sdavidch	 */
10471157642Sps	if (0) {
10472170392Sdavidch		bce_freeze_controller(sc);
10473170392Sdavidch		bce_unfreeze_controller(sc);
10474182293Sdavidch		bce_dump_enet(sc, NULL);
10475157642Sps   		bce_dump_txbd(sc, 0, NULL);
10476157642Sps		bce_dump_rxbd(sc, 0, NULL);
10477157642Sps		bce_dump_tx_mbuf_chain(sc, 0, USABLE_TX_BD);
10478176448Sdavidch		bce_dump_rx_mbuf_chain(sc, 0, USABLE_RX_BD);
10479157642Sps		bce_dump_l2fhdr(sc, 0, NULL);
10480176448Sdavidch		bce_dump_ctx(sc, RX_CID);
10481176448Sdavidch		bce_dump_ftqs(sc);
10482157642Sps		bce_dump_tx_chain(sc, 0, USABLE_TX_BD);
10483176448Sdavidch		bce_dump_rx_chain(sc, 0, USABLE_RX_BD);
10484157642Sps		bce_dump_status_block(sc);
10485157642Sps		bce_dump_stats_block(sc);
10486157642Sps		bce_dump_driver_state(sc);
10487157642Sps		bce_dump_hw_state(sc);
10488170810Sdavidch		bce_dump_bc_state(sc);
10489179771Sdavidch		bce_dump_txp_state(sc, 0);
10490179771Sdavidch		bce_dump_rxp_state(sc, 0);
10491179771Sdavidch		bce_dump_tpat_state(sc, 0);
10492179771Sdavidch		bce_dump_cp_state(sc, 0);
10493182293Sdavidch		bce_dump_com_state(sc, 0);
10494198320Sstas#ifdef BCE_JUMBO_HDRSPLIT
10495179695Sdavidch		bce_dump_pgbd(sc, 0, NULL);
10496179771Sdavidch		bce_dump_pg_mbuf_chain(sc, 0, USABLE_PG_BD);
10497179695Sdavidch		bce_dump_pg_chain(sc, 0, USABLE_PG_BD);
10498179695Sdavidch#endif
10499157642Sps	}
10500157642Sps
10501176448Sdavidch	bce_dump_status_block(sc);
10502157642Sps	bce_dump_driver_state(sc);
10503178132Sdavidch
10504157642Sps	/* Call the debugger. */
10505157642Sps	breakpoint();
10506157642Sps
10507157642Sps	return;
10508157642Sps}
10509157642Sps#endif
10510170810Sdavidch
10511