if_bce.c revision 163339
1157642Sps/*-
2157642Sps * Copyright (c) 2006 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 163339 2006-10-14 05:30:12Z scottl $");
33157642Sps
34157642Sps/*
35157642Sps * The following controllers are supported by this driver:
36157642Sps *   BCM5706C A2, A3
37157642Sps *   BCM5708C B1
38157642Sps *
39157642Sps * The following controllers are not supported by this driver:
40157642Sps * (These are not "Production" versions of the controller.)
41157642Sps *
42157642Sps *   BCM5706C A0, A1
43157642Sps *   BCM5706S A0, A1, A2, A3
44157642Sps *   BCM5708C A0, B0
45157642Sps *   BCM5708S A0, B0, B1
46157642Sps */
47157642Sps
48157643Sps#include "opt_bce.h"
49157643Sps
50157642Sps#include <dev/bce/if_bcereg.h>
51157642Sps#include <dev/bce/if_bcefw.h>
52157642Sps
53157642Sps/****************************************************************************/
54157642Sps/* BCE Driver Version                                                       */
55157642Sps/****************************************************************************/
56159411Sdavidchchar bce_driver_version[] = "v0.9.6";
57157642Sps
58157642Sps
59157642Sps/****************************************************************************/
60157642Sps/* BCE Debug Options                                                        */
61157642Sps/****************************************************************************/
62157642Sps#ifdef BCE_DEBUG
63157642Sps	u32 bce_debug = BCE_WARN;
64157642Sps
65157642Sps	/*          0 = Never              */
66157642Sps	/*          1 = 1 in 2,147,483,648 */
67157642Sps	/*        256 = 1 in     8,388,608 */
68157642Sps	/*       2048 = 1 in     1,048,576 */
69157642Sps	/*      65536 = 1 in        32,768 */
70157642Sps	/*    1048576 = 1 in         2,048 */
71157642Sps	/*  268435456 =	1 in             8 */
72157642Sps	/*  536870912 = 1 in             4 */
73157642Sps	/* 1073741824 = 1 in             2 */
74157642Sps
75157642Sps	/* Controls how often the l2_fhdr frame error check will fail. */
76157642Sps	int bce_debug_l2fhdr_status_check = 0;
77157642Sps
78157642Sps	/* Controls how often the unexpected attention check will fail. */
79157642Sps	int bce_debug_unexpected_attention = 0;
80157642Sps
81157642Sps	/* Controls how often to simulate an mbuf allocation failure. */
82157642Sps	int bce_debug_mbuf_allocation_failure = 0;
83157642Sps
84157642Sps	/* Controls how often to simulate a DMA mapping failure. */
85157642Sps	int bce_debug_dma_map_addr_failure = 0;
86157642Sps
87157642Sps	/* Controls how often to simulate a bootcode failure. */
88157642Sps	int bce_debug_bootcode_running_failure = 0;
89157642Sps#endif
90157642Sps
91157642Sps
92157642Sps/****************************************************************************/
93157642Sps/* PCI Device ID Table                                                      */
94157642Sps/*                                                                          */
95157642Sps/* Used by bce_probe() to identify the devices supported by this driver.    */
96157642Sps/****************************************************************************/
97157642Sps#define BCE_DEVDESC_MAX		64
98157642Sps
99157642Spsstatic struct bce_type bce_devs[] = {
100157642Sps	/* BCM5706C Controllers and OEM boards. */
101157642Sps	{ BRCM_VENDORID, BRCM_DEVICEID_BCM5706,  HP_VENDORID, 0x3101,
102157642Sps		"HP NC370T Multifunction Gigabit Server Adapter" },
103157642Sps	{ BRCM_VENDORID, BRCM_DEVICEID_BCM5706,  HP_VENDORID, 0x3106,
104157642Sps		"HP NC370i Multifunction Gigabit Server Adapter" },
105157642Sps	{ BRCM_VENDORID, BRCM_DEVICEID_BCM5706,  PCI_ANY_ID,  PCI_ANY_ID,
106157642Sps		"Broadcom NetXtreme II BCM5706 1000Base-T" },
107157642Sps
108157642Sps	/* BCM5706S controllers and OEM boards. */
109157642Sps	{ BRCM_VENDORID, BRCM_DEVICEID_BCM5706S, HP_VENDORID, 0x3102,
110157642Sps		"HP NC370F Multifunction Gigabit Server Adapter" },
111157642Sps	{ BRCM_VENDORID, BRCM_DEVICEID_BCM5706S, PCI_ANY_ID,  PCI_ANY_ID,
112157642Sps		"Broadcom NetXtreme II BCM5706 1000Base-SX" },
113157642Sps
114157642Sps	/* BCM5708C controllers and OEM boards. */
115157642Sps	{ BRCM_VENDORID, BRCM_DEVICEID_BCM5708,  PCI_ANY_ID,  PCI_ANY_ID,
116157642Sps		"Broadcom NetXtreme II BCM5708 1000Base-T" },
117157642Sps
118157642Sps	/* BCM5708S controllers and OEM boards. */
119157642Sps	{ BRCM_VENDORID, BRCM_DEVICEID_BCM5708,  PCI_ANY_ID,  PCI_ANY_ID,
120157642Sps		"Broadcom NetXtreme II BCM5708 1000Base-T" },
121157642Sps	{ 0, 0, 0, 0, NULL }
122157642Sps};
123157642Sps
124157642Sps
125157642Sps/****************************************************************************/
126157642Sps/* Supported Flash NVRAM device data.                                       */
127157642Sps/****************************************************************************/
128157642Spsstatic struct flash_spec flash_table[] =
129157642Sps{
130157642Sps	/* Slow EEPROM */
131157642Sps	{0x00000000, 0x40830380, 0x009f0081, 0xa184a053, 0xaf000400,
132157642Sps	 1, SEEPROM_PAGE_BITS, SEEPROM_PAGE_SIZE,
133157642Sps	 SEEPROM_BYTE_ADDR_MASK, SEEPROM_TOTAL_SIZE,
134157642Sps	 "EEPROM - slow"},
135157642Sps	/* Expansion entry 0001 */
136157642Sps	{0x08000002, 0x4b808201, 0x00050081, 0x03840253, 0xaf020406,
137157642Sps	 0, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
138157642Sps	 SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
139157642Sps	 "Entry 0001"},
140157642Sps	/* Saifun SA25F010 (non-buffered flash) */
141157642Sps	/* strap, cfg1, & write1 need updates */
142157642Sps	{0x04000001, 0x47808201, 0x00050081, 0x03840253, 0xaf020406,
143157642Sps	 0, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
144157642Sps	 SAIFUN_FLASH_BYTE_ADDR_MASK, SAIFUN_FLASH_BASE_TOTAL_SIZE*2,
145157642Sps	 "Non-buffered flash (128kB)"},
146157642Sps	/* Saifun SA25F020 (non-buffered flash) */
147157642Sps	/* strap, cfg1, & write1 need updates */
148157642Sps	{0x0c000003, 0x4f808201, 0x00050081, 0x03840253, 0xaf020406,
149157642Sps	 0, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
150157642Sps	 SAIFUN_FLASH_BYTE_ADDR_MASK, SAIFUN_FLASH_BASE_TOTAL_SIZE*4,
151157642Sps	 "Non-buffered flash (256kB)"},
152157642Sps	/* Expansion entry 0100 */
153157642Sps	{0x11000000, 0x53808201, 0x00050081, 0x03840253, 0xaf020406,
154157642Sps	 0, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
155157642Sps	 SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
156157642Sps	 "Entry 0100"},
157157642Sps	/* Entry 0101: ST M45PE10 (non-buffered flash, TetonII B0) */
158157642Sps	{0x19000002, 0x5b808201, 0x000500db, 0x03840253, 0xaf020406,
159157642Sps	 0, ST_MICRO_FLASH_PAGE_BITS, ST_MICRO_FLASH_PAGE_SIZE,
160157642Sps	 ST_MICRO_FLASH_BYTE_ADDR_MASK, ST_MICRO_FLASH_BASE_TOTAL_SIZE*2,
161157642Sps	 "Entry 0101: ST M45PE10 (128kB non-bufferred)"},
162157642Sps	/* Entry 0110: ST M45PE20 (non-buffered flash)*/
163157642Sps	{0x15000001, 0x57808201, 0x000500db, 0x03840253, 0xaf020406,
164157642Sps	 0, ST_MICRO_FLASH_PAGE_BITS, ST_MICRO_FLASH_PAGE_SIZE,
165157642Sps	 ST_MICRO_FLASH_BYTE_ADDR_MASK, ST_MICRO_FLASH_BASE_TOTAL_SIZE*4,
166157642Sps	 "Entry 0110: ST M45PE20 (256kB non-bufferred)"},
167157642Sps	/* Saifun SA25F005 (non-buffered flash) */
168157642Sps	/* strap, cfg1, & write1 need updates */
169157642Sps	{0x1d000003, 0x5f808201, 0x00050081, 0x03840253, 0xaf020406,
170157642Sps	 0, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
171157642Sps	 SAIFUN_FLASH_BYTE_ADDR_MASK, SAIFUN_FLASH_BASE_TOTAL_SIZE,
172157642Sps	 "Non-buffered flash (64kB)"},
173157642Sps	/* Fast EEPROM */
174157642Sps	{0x22000000, 0x62808380, 0x009f0081, 0xa184a053, 0xaf000400,
175157642Sps	 1, SEEPROM_PAGE_BITS, SEEPROM_PAGE_SIZE,
176157642Sps	 SEEPROM_BYTE_ADDR_MASK, SEEPROM_TOTAL_SIZE,
177157642Sps	 "EEPROM - fast"},
178157642Sps	/* Expansion entry 1001 */
179157642Sps	{0x2a000002, 0x6b808201, 0x00050081, 0x03840253, 0xaf020406,
180157642Sps	 0, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
181157642Sps	 SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
182157642Sps	 "Entry 1001"},
183157642Sps	/* Expansion entry 1010 */
184157642Sps	{0x26000001, 0x67808201, 0x00050081, 0x03840253, 0xaf020406,
185157642Sps	 0, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
186157642Sps	 SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
187157642Sps	 "Entry 1010"},
188157642Sps	/* ATMEL AT45DB011B (buffered flash) */
189157642Sps	{0x2e000003, 0x6e808273, 0x00570081, 0x68848353, 0xaf000400,
190157642Sps	 1, BUFFERED_FLASH_PAGE_BITS, BUFFERED_FLASH_PAGE_SIZE,
191157642Sps	 BUFFERED_FLASH_BYTE_ADDR_MASK, BUFFERED_FLASH_TOTAL_SIZE,
192157642Sps	 "Buffered flash (128kB)"},
193157642Sps	/* Expansion entry 1100 */
194157642Sps	{0x33000000, 0x73808201, 0x00050081, 0x03840253, 0xaf020406,
195157642Sps	 0, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
196157642Sps	 SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
197157642Sps	 "Entry 1100"},
198157642Sps	/* Expansion entry 1101 */
199157642Sps	{0x3b000002, 0x7b808201, 0x00050081, 0x03840253, 0xaf020406,
200157642Sps	 0, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
201157642Sps	 SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
202157642Sps	 "Entry 1101"},
203157642Sps	/* Ateml Expansion entry 1110 */
204157642Sps	{0x37000001, 0x76808273, 0x00570081, 0x68848353, 0xaf000400,
205157642Sps	 1, BUFFERED_FLASH_PAGE_BITS, BUFFERED_FLASH_PAGE_SIZE,
206157642Sps	 BUFFERED_FLASH_BYTE_ADDR_MASK, 0,
207157642Sps	 "Entry 1110 (Atmel)"},
208157642Sps	/* ATMEL AT45DB021B (buffered flash) */
209157642Sps	{0x3f000003, 0x7e808273, 0x00570081, 0x68848353, 0xaf000400,
210157642Sps	 1, BUFFERED_FLASH_PAGE_BITS, BUFFERED_FLASH_PAGE_SIZE,
211157642Sps	 BUFFERED_FLASH_BYTE_ADDR_MASK, BUFFERED_FLASH_TOTAL_SIZE*2,
212157642Sps	 "Buffered flash (256kB)"},
213157642Sps};
214157642Sps
215157642Sps
216157642Sps/****************************************************************************/
217157642Sps/* FreeBSD device entry points.                                             */
218157642Sps/****************************************************************************/
219157642Spsstatic int  bce_probe				(device_t);
220157642Spsstatic int  bce_attach				(device_t);
221157642Spsstatic int  bce_detach				(device_t);
222157642Spsstatic void bce_shutdown			(device_t);
223157642Sps
224157642Sps
225157642Sps/****************************************************************************/
226157642Sps/* BCE Debug Data Structure Dump Routines                                   */
227157642Sps/****************************************************************************/
228157642Sps#ifdef BCE_DEBUG
229157642Spsstatic void bce_dump_mbuf 			(struct bce_softc *, struct mbuf *);
230157642Spsstatic void bce_dump_tx_mbuf_chain	(struct bce_softc *, int, int);
231157642Spsstatic void bce_dump_rx_mbuf_chain	(struct bce_softc *, int, int);
232157642Spsstatic void bce_dump_txbd			(struct bce_softc *, int, struct tx_bd *);
233157642Spsstatic void bce_dump_rxbd			(struct bce_softc *, int, struct rx_bd *);
234157642Spsstatic void bce_dump_l2fhdr			(struct bce_softc *, int, struct l2_fhdr *);
235157642Spsstatic void bce_dump_tx_chain		(struct bce_softc *, int, int);
236157642Spsstatic void bce_dump_rx_chain		(struct bce_softc *, int, int);
237157642Spsstatic void bce_dump_status_block	(struct bce_softc *);
238157642Spsstatic void bce_dump_stats_block	(struct bce_softc *);
239157642Spsstatic void bce_dump_driver_state	(struct bce_softc *);
240157642Spsstatic void bce_dump_hw_state		(struct bce_softc *);
241157642Spsstatic void bce_breakpoint			(struct bce_softc *);
242157642Sps#endif
243157642Sps
244157642Sps
245157642Sps/****************************************************************************/
246157642Sps/* BCE Register/Memory Access Routines                                      */
247157642Sps/****************************************************************************/
248157642Spsstatic u32  bce_reg_rd_ind			(struct bce_softc *, u32);
249157642Spsstatic void bce_reg_wr_ind			(struct bce_softc *, u32, u32);
250157642Spsstatic void bce_ctx_wr				(struct bce_softc *, u32, u32, u32);
251157642Spsstatic int  bce_miibus_read_reg		(device_t, int, int);
252157642Spsstatic int  bce_miibus_write_reg	(device_t, int, int, int);
253157642Spsstatic void bce_miibus_statchg		(device_t);
254157642Sps
255157642Sps
256157642Sps/****************************************************************************/
257157642Sps/* BCE NVRAM Access Routines                                                */
258157642Sps/****************************************************************************/
259157642Spsstatic int  bce_acquire_nvram_lock	(struct bce_softc *);
260157642Spsstatic int  bce_release_nvram_lock	(struct bce_softc *);
261157642Spsstatic void bce_enable_nvram_access	(struct bce_softc *);
262157642Spsstatic void	bce_disable_nvram_access(struct bce_softc *);
263157642Spsstatic int  bce_nvram_read_dword	(struct bce_softc *, u32, u8 *, u32);
264157642Spsstatic int  bce_init_nvram			(struct bce_softc *);
265157642Spsstatic int  bce_nvram_read			(struct bce_softc *, u32, u8 *, int);
266157642Spsstatic int  bce_nvram_test			(struct bce_softc *);
267157642Sps#ifdef BCE_NVRAM_WRITE_SUPPORT
268157642Spsstatic int  bce_enable_nvram_write	(struct bce_softc *);
269157642Spsstatic void bce_disable_nvram_write	(struct bce_softc *);
270157642Spsstatic int  bce_nvram_erase_page	(struct bce_softc *, u32);
271157642Spsstatic int  bce_nvram_write_dword	(struct bce_softc *, u32, u8 *, u32);
272157642Spsstatic int  bce_nvram_write			(struct bce_softc *, u32, u8 *, int);
273157642Sps#endif
274157642Sps
275157642Sps/****************************************************************************/
276157642Sps/*                                                                          */
277157642Sps/****************************************************************************/
278157642Spsstatic void bce_dma_map_addr		(void *, bus_dma_segment_t *, int, int);
279157642Spsstatic void bce_dma_map_tx_desc		(void *, bus_dma_segment_t *, int, bus_size_t, int);
280157642Spsstatic int  bce_dma_alloc			(device_t);
281157642Spsstatic void bce_dma_free			(struct bce_softc *);
282157642Spsstatic void bce_release_resources	(struct bce_softc *);
283157642Sps
284157642Sps/****************************************************************************/
285157642Sps/* BCE Firmware Synchronization and Load                                    */
286157642Sps/****************************************************************************/
287157642Spsstatic int  bce_fw_sync				(struct bce_softc *, u32);
288157642Spsstatic void bce_load_rv2p_fw		(struct bce_softc *, u32 *, u32, u32);
289157642Spsstatic void bce_load_cpu_fw			(struct bce_softc *, struct cpu_reg *, struct fw_info *);
290157642Spsstatic void bce_init_cpus			(struct bce_softc *);
291157642Sps
292157642Spsstatic void bce_stop				(struct bce_softc *);
293157642Spsstatic int  bce_reset				(struct bce_softc *, u32);
294157642Spsstatic int  bce_chipinit 			(struct bce_softc *);
295157642Spsstatic int  bce_blockinit 			(struct bce_softc *);
296157642Spsstatic int  bce_get_buf				(struct bce_softc *, struct mbuf *, u16 *, u16 *, u32 *);
297157642Sps
298157642Spsstatic int  bce_init_tx_chain		(struct bce_softc *);
299157642Spsstatic int  bce_init_rx_chain		(struct bce_softc *);
300157642Spsstatic void bce_free_rx_chain		(struct bce_softc *);
301157642Spsstatic void bce_free_tx_chain		(struct bce_softc *);
302157642Sps
303163339Sscottlstatic int  bce_tx_encap			(struct bce_softc *, struct mbuf *, u16 *);
304157642Spsstatic void bce_start_locked		(struct ifnet *);
305157642Spsstatic void bce_start				(struct ifnet *);
306157642Spsstatic int  bce_ioctl				(struct ifnet *, u_long, caddr_t);
307157642Spsstatic void bce_watchdog			(struct ifnet *);
308157642Spsstatic int  bce_ifmedia_upd			(struct ifnet *);
309157642Spsstatic void bce_ifmedia_sts			(struct ifnet *, struct ifmediareq *);
310157642Spsstatic void bce_init_locked			(struct bce_softc *);
311157642Spsstatic void bce_init				(void *);
312162474Sambriskostatic void bce_mgmt_init_locked(struct bce_softc *sc);
313157642Sps
314157642Spsstatic void bce_init_context		(struct bce_softc *);
315157642Spsstatic void bce_get_mac_addr		(struct bce_softc *);
316157642Spsstatic void bce_set_mac_addr		(struct bce_softc *);
317157642Spsstatic void bce_phy_intr			(struct bce_softc *);
318157642Spsstatic void bce_rx_intr				(struct bce_softc *);
319157642Spsstatic void bce_tx_intr				(struct bce_softc *);
320157642Spsstatic void bce_disable_intr		(struct bce_softc *);
321157642Spsstatic void bce_enable_intr			(struct bce_softc *);
322157642Sps
323157642Sps#ifdef DEVICE_POLLING
324157642Spsstatic void bce_poll_locked			(struct ifnet *, enum poll_cmd, int);
325157642Spsstatic void bce_poll				(struct ifnet *, enum poll_cmd, int);
326157642Sps#endif
327157642Spsstatic void bce_intr				(void *);
328157642Spsstatic void bce_set_rx_mode			(struct bce_softc *);
329157642Spsstatic void bce_stats_update		(struct bce_softc *);
330157642Spsstatic void bce_tick_locked			(struct bce_softc *);
331157642Spsstatic void bce_tick				(void *);
332157642Spsstatic void bce_add_sysctls			(struct bce_softc *);
333157642Sps
334157642Sps
335157642Sps/****************************************************************************/
336157642Sps/* FreeBSD device dispatch table.                                           */
337157642Sps/****************************************************************************/
338157642Spsstatic device_method_t bce_methods[] = {
339157642Sps	/* Device interface */
340157642Sps	DEVMETHOD(device_probe,		bce_probe),
341157642Sps	DEVMETHOD(device_attach,	bce_attach),
342157642Sps	DEVMETHOD(device_detach,	bce_detach),
343157642Sps	DEVMETHOD(device_shutdown,	bce_shutdown),
344157642Sps
345157642Sps	/* bus interface */
346157642Sps	DEVMETHOD(bus_print_child,	bus_generic_print_child),
347157642Sps	DEVMETHOD(bus_driver_added,	bus_generic_driver_added),
348157642Sps
349157642Sps	/* MII interface */
350157642Sps	DEVMETHOD(miibus_readreg,	bce_miibus_read_reg),
351157642Sps	DEVMETHOD(miibus_writereg,	bce_miibus_write_reg),
352157642Sps	DEVMETHOD(miibus_statchg,	bce_miibus_statchg),
353157642Sps
354157642Sps	{ 0, 0 }
355157642Sps};
356157642Sps
357157642Spsstatic driver_t bce_driver = {
358157642Sps	"bce",
359157642Sps	bce_methods,
360157642Sps	sizeof(struct bce_softc)
361157642Sps};
362157642Sps
363157642Spsstatic devclass_t bce_devclass;
364157642Sps
365157642SpsMODULE_DEPEND(bce, pci, 1, 1, 1);
366157642SpsMODULE_DEPEND(bce, ether, 1, 1, 1);
367157642SpsMODULE_DEPEND(bce, miibus, 1, 1, 1);
368157642Sps
369157642SpsDRIVER_MODULE(bce, pci, bce_driver, bce_devclass, 0, 0);
370157642SpsDRIVER_MODULE(miibus, bce, miibus_driver, miibus_devclass, 0, 0);
371157642Sps
372157642Sps
373157642Sps/****************************************************************************/
374157642Sps/* Device probe function.                                                   */
375157642Sps/*                                                                          */
376157642Sps/* Compares the device to the driver's list of supported devices and        */
377157642Sps/* reports back to the OS whether this is the right driver for the device.  */
378157642Sps/*                                                                          */
379157642Sps/* Returns:                                                                 */
380157642Sps/*   BUS_PROBE_DEFAULT on success, positive value on failure.               */
381157642Sps/****************************************************************************/
382157642Spsstatic int
383157642Spsbce_probe(device_t dev)
384157642Sps{
385157642Sps	struct bce_type *t;
386157642Sps	struct bce_softc *sc;
387157642Sps	char *descbuf;
388157642Sps	u16 vid = 0, did = 0, svid = 0, sdid = 0;
389157642Sps
390157642Sps	t = bce_devs;
391157642Sps
392157642Sps	sc = device_get_softc(dev);
393157642Sps	bzero(sc, sizeof(struct bce_softc));
394157642Sps	sc->bce_unit = device_get_unit(dev);
395157642Sps	sc->bce_dev = dev;
396157642Sps
397157642Sps	/* Get the data for the device to be probed. */
398157642Sps	vid  = pci_get_vendor(dev);
399157642Sps	did  = pci_get_device(dev);
400157642Sps	svid = pci_get_subvendor(dev);
401157642Sps	sdid = pci_get_subdevice(dev);
402157642Sps
403157642Sps	DBPRINT(sc, BCE_VERBOSE_LOAD,
404157642Sps		"%s(); VID = 0x%04X, DID = 0x%04X, SVID = 0x%04X, "
405157642Sps		"SDID = 0x%04X\n", __FUNCTION__, vid, did, svid, sdid);
406157642Sps
407157642Sps	/* Look through the list of known devices for a match. */
408157642Sps	while(t->bce_name != NULL) {
409157642Sps
410157642Sps		if ((vid == t->bce_vid) && (did == t->bce_did) &&
411157642Sps			((svid == t->bce_svid) || (t->bce_svid == PCI_ANY_ID)) &&
412157642Sps			((sdid == t->bce_sdid) || (t->bce_sdid == PCI_ANY_ID))) {
413157642Sps
414157642Sps			descbuf = malloc(BCE_DEVDESC_MAX, M_TEMP, M_NOWAIT);
415157642Sps
416157642Sps			if (descbuf == NULL)
417157642Sps				return(ENOMEM);
418157642Sps
419157642Sps			/* Print out the device identity. */
420157642Sps			snprintf(descbuf, BCE_DEVDESC_MAX, "%s (%c%d), %s",
421157642Sps				t->bce_name,
422157642Sps			    (((pci_read_config(dev, PCIR_REVID, 4) & 0xf0) >> 4) + 'A'),
423157642Sps			    (pci_read_config(dev, PCIR_REVID, 4) & 0xf),
424157642Sps			    bce_driver_version);
425157642Sps
426157642Sps			device_set_desc_copy(dev, descbuf);
427157642Sps			free(descbuf, M_TEMP);
428157642Sps			return(BUS_PROBE_DEFAULT);
429157642Sps		}
430157642Sps		t++;
431157642Sps	}
432157642Sps
433157642Sps	DBPRINT(sc, BCE_VERBOSE_LOAD, "%s(%d): No IOCTL match found!\n",
434157642Sps		__FILE__, __LINE__);
435157642Sps
436157642Sps	return(ENXIO);
437157642Sps}
438157642Sps
439157642Sps
440157642Sps/****************************************************************************/
441157642Sps/* Device attach function.                                                  */
442157642Sps/*                                                                          */
443157642Sps/* Allocates device resources, performs secondary chip identification,      */
444157642Sps/* resets and initializes the hardware, and initializes driver instance     */
445157642Sps/* variables.                                                               */
446157642Sps/*                                                                          */
447157642Sps/* Returns:                                                                 */
448157642Sps/*   0 on success, positive value on failure.                               */
449157642Sps/****************************************************************************/
450157642Spsstatic int
451157642Spsbce_attach(device_t dev)
452157642Sps{
453157642Sps	struct bce_softc *sc;
454157642Sps	struct ifnet *ifp;
455157642Sps	u32 val;
456157642Sps	int mbuf, rid, rc = 0;
457157642Sps
458157642Sps	sc = device_get_softc(dev);
459157642Sps	sc->bce_dev = dev;
460157642Sps
461157642Sps	DBPRINT(sc, BCE_VERBOSE_RESET, "Entering %s()\n", __FUNCTION__);
462157642Sps
463157642Sps	mbuf = device_get_unit(dev);
464157642Sps	sc->bce_unit = mbuf;
465157642Sps
466157642Sps	pci_enable_busmaster(dev);
467157642Sps
468157642Sps	/* Allocate PCI memory resources. */
469157642Sps	rid = PCIR_BAR(0);
470157642Sps	sc->bce_res = bus_alloc_resource_any(
471163338Sscottl		dev,				/* dev */
472163338Sscottl		SYS_RES_MEMORY,			/* type */
473163338Sscottl		&rid,				/* rid */
474163338Sscottl		RF_ACTIVE | PCI_RF_DENSE);	/* flags */
475157642Sps
476157642Sps	if (sc->bce_res == NULL) {
477157642Sps		BCE_PRINTF(sc, "%s(%d): PCI memory allocation failed\n",
478157642Sps			__FILE__, __LINE__);
479157642Sps		rc = ENXIO;
480157642Sps		goto bce_attach_fail;
481157642Sps	}
482157642Sps
483157642Sps	/* Get various resource handles. */
484157642Sps	sc->bce_btag    = rman_get_bustag(sc->bce_res);
485157642Sps	sc->bce_bhandle = rman_get_bushandle(sc->bce_res);
486157642Sps	sc->bce_vhandle = (vm_offset_t) rman_get_virtual(sc->bce_res);
487157642Sps
488157642Sps	/* Allocate PCI IRQ resources. */
489157642Sps	rid = 0;
490157642Sps	sc->bce_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
491157642Sps	    RF_SHAREABLE | RF_ACTIVE);
492157642Sps
493157642Sps	if (sc->bce_irq == NULL) {
494157642Sps		BCE_PRINTF(sc, "%s(%d): PCI map interrupt failed\n",
495157642Sps			__FILE__, __LINE__);
496157642Sps		rc = ENXIO;
497157642Sps		goto bce_attach_fail;
498157642Sps	}
499157642Sps
500157642Sps	/* Initialize mutex for the current device instance. */
501157642Sps	BCE_LOCK_INIT(sc, device_get_nameunit(dev));
502157642Sps
503157642Sps	/*
504157642Sps	 * Configure byte swap and enable indirect register access.
505157642Sps	 * Rely on CPU to do target byte swapping on big endian systems.
506157642Sps	 * Access to registers outside of PCI configurtion space are not
507157642Sps	 * valid until this is done.
508157642Sps	 */
509157642Sps	pci_write_config(dev, BCE_PCICFG_MISC_CONFIG,
510157642Sps			       BCE_PCICFG_MISC_CONFIG_REG_WINDOW_ENA |
511157642Sps			       BCE_PCICFG_MISC_CONFIG_TARGET_MB_WORD_SWAP, 4);
512157642Sps
513157642Sps	/* Save ASIC revsion info. */
514157642Sps	sc->bce_chipid =  REG_RD(sc, BCE_MISC_ID);
515157642Sps
516157642Sps	/* Weed out any non-production controller revisions. */
517157642Sps	switch(BCE_CHIP_ID(sc)) {
518157642Sps		case BCE_CHIP_ID_5706_A0:
519157642Sps		case BCE_CHIP_ID_5706_A1:
520157642Sps		case BCE_CHIP_ID_5708_A0:
521157642Sps		case BCE_CHIP_ID_5708_B0:
522157642Sps			BCE_PRINTF(sc, "%s(%d): Unsupported controller revision (%c%d)!\n",
523157642Sps				__FILE__, __LINE__,
524157642Sps				(((pci_read_config(dev, PCIR_REVID, 4) & 0xf0) >> 4) + 'A'),
525157642Sps			    (pci_read_config(dev, PCIR_REVID, 4) & 0xf));
526157642Sps			rc = ENODEV;
527157642Sps			goto bce_attach_fail;
528157642Sps	}
529157642Sps
530157642Sps	if (BCE_CHIP_BOND_ID(sc) & BCE_CHIP_BOND_ID_SERDES_BIT) {
531157642Sps		BCE_PRINTF(sc, "%s(%d): SerDes controllers are not supported!\n",
532157642Sps			__FILE__, __LINE__);
533157642Sps		rc = ENODEV;
534157642Sps		goto bce_attach_fail;
535157642Sps	}
536157642Sps
537157642Sps	/*
538157642Sps	 * The embedded PCIe to PCI-X bridge (EPB)
539157642Sps	 * in the 5708 cannot address memory above
540157642Sps	 * 40 bits (E7_5708CB1_23043 & E6_5708SB1_23043).
541157642Sps	 */
542157642Sps	if (BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5708)
543157642Sps		sc->max_bus_addr = BCE_BUS_SPACE_MAXADDR;
544157642Sps	else
545157642Sps		sc->max_bus_addr = BUS_SPACE_MAXADDR;
546157642Sps
547157642Sps	/*
548157642Sps	 * Find the base address for shared memory access.
549157642Sps	 * Newer versions of bootcode use a signature and offset
550157642Sps	 * while older versions use a fixed address.
551157642Sps	 */
552157642Sps	val = REG_RD_IND(sc, BCE_SHM_HDR_SIGNATURE);
553157642Sps	if ((val & BCE_SHM_HDR_SIGNATURE_SIG_MASK) == BCE_SHM_HDR_SIGNATURE_SIG)
554157642Sps		sc->bce_shmem_base = REG_RD_IND(sc, BCE_SHM_HDR_ADDR_0);
555157642Sps	else
556157642Sps		sc->bce_shmem_base = HOST_VIEW_SHMEM_BASE;
557157642Sps
558157642Sps	DBPRINT(sc, BCE_INFO, "bce_shmem_base = 0x%08X\n", sc->bce_shmem_base);
559157642Sps
560157642Sps	/* Set initial device and PHY flags */
561157642Sps	sc->bce_flags = 0;
562157642Sps	sc->bce_phy_flags = 0;
563157642Sps
564157642Sps	/* Get PCI bus information (speed and type). */
565157642Sps	val = REG_RD(sc, BCE_PCICFG_MISC_STATUS);
566157642Sps	if (val & BCE_PCICFG_MISC_STATUS_PCIX_DET) {
567157642Sps		u32 clkreg;
568157642Sps
569157642Sps		sc->bce_flags |= BCE_PCIX_FLAG;
570157642Sps
571157642Sps		clkreg = REG_RD(sc, BCE_PCICFG_PCI_CLOCK_CONTROL_BITS);
572157642Sps
573157642Sps		clkreg &= BCE_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET;
574157642Sps		switch (clkreg) {
575157642Sps		case BCE_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_133MHZ:
576157642Sps			sc->bus_speed_mhz = 133;
577157642Sps			break;
578157642Sps
579157642Sps		case BCE_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_95MHZ:
580157642Sps			sc->bus_speed_mhz = 100;
581157642Sps			break;
582157642Sps
583157642Sps		case BCE_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_66MHZ:
584157642Sps		case BCE_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_80MHZ:
585157642Sps			sc->bus_speed_mhz = 66;
586157642Sps			break;
587157642Sps
588157642Sps		case BCE_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_48MHZ:
589157642Sps		case BCE_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_55MHZ:
590157642Sps			sc->bus_speed_mhz = 50;
591157642Sps			break;
592157642Sps
593157642Sps		case BCE_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_LOW:
594157642Sps		case BCE_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_32MHZ:
595157642Sps		case BCE_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_38MHZ:
596157642Sps			sc->bus_speed_mhz = 33;
597157642Sps			break;
598157642Sps		}
599157642Sps	} else {
600157642Sps		if (val & BCE_PCICFG_MISC_STATUS_M66EN)
601157642Sps			sc->bus_speed_mhz = 66;
602157642Sps		else
603157642Sps			sc->bus_speed_mhz = 33;
604157642Sps	}
605157642Sps
606157642Sps	if (val & BCE_PCICFG_MISC_STATUS_32BIT_DET)
607157642Sps		sc->bce_flags |= BCE_PCI_32BIT_FLAG;
608157642Sps
609157642Sps	BCE_PRINTF(sc, "ASIC ID 0x%08X; Revision (%c%d); PCI%s %s %dMHz\n",
610157642Sps		sc->bce_chipid,
611157642Sps		((BCE_CHIP_ID(sc) & 0xf000) >> 12) + 'A',
612157642Sps		((BCE_CHIP_ID(sc) & 0x0ff0) >> 4),
613157642Sps		((sc->bce_flags & BCE_PCIX_FLAG) ? "-X" : ""),
614157642Sps		((sc->bce_flags & BCE_PCI_32BIT_FLAG) ? "32-bit" : "64-bit"),
615157642Sps		sc->bus_speed_mhz);
616157642Sps
617157642Sps	/* Reset the controller. */
618157642Sps	if (bce_reset(sc, BCE_DRV_MSG_CODE_RESET)) {
619157642Sps		rc = ENXIO;
620157642Sps		goto bce_attach_fail;
621157642Sps	}
622157642Sps
623157642Sps	/* Initialize the controller. */
624157642Sps	if (bce_chipinit(sc)) {
625157642Sps		BCE_PRINTF(sc, "%s(%d): Controller initialization failed!\n",
626157642Sps			__FILE__, __LINE__);
627157642Sps		rc = ENXIO;
628157642Sps		goto bce_attach_fail;
629157642Sps	}
630157642Sps
631157642Sps	/* Perform NVRAM test. */
632157642Sps	if (bce_nvram_test(sc)) {
633157642Sps		BCE_PRINTF(sc, "%s(%d): NVRAM test failed!\n",
634157642Sps			__FILE__, __LINE__);
635157642Sps		rc = ENXIO;
636157642Sps		goto bce_attach_fail;
637157642Sps	}
638157642Sps
639157642Sps	/* Fetch the permanent Ethernet MAC address. */
640157642Sps	bce_get_mac_addr(sc);
641157642Sps
642157642Sps	/*
643157642Sps	 * Trip points control how many BDs
644157642Sps	 * should be ready before generating an
645157642Sps	 * interrupt while ticks control how long
646157642Sps	 * a BD can sit in the chain before
647157642Sps	 * generating an interrupt.  Set the default
648157642Sps	 * values for the RX and TX rings.
649157642Sps	 */
650157642Sps
651157642Sps#ifdef BCE_DRBUG
652157642Sps	/* Force more frequent interrupts. */
653157642Sps	sc->bce_tx_quick_cons_trip_int = 1;
654157642Sps	sc->bce_tx_quick_cons_trip     = 1;
655157642Sps	sc->bce_tx_ticks_int           = 0;
656157642Sps	sc->bce_tx_ticks               = 0;
657157642Sps
658157642Sps	sc->bce_rx_quick_cons_trip_int = 1;
659157642Sps	sc->bce_rx_quick_cons_trip     = 1;
660157642Sps	sc->bce_rx_ticks_int           = 0;
661157642Sps	sc->bce_rx_ticks               = 0;
662157642Sps#else
663157642Sps	sc->bce_tx_quick_cons_trip_int = 20;
664157642Sps	sc->bce_tx_quick_cons_trip     = 20;
665157642Sps	sc->bce_tx_ticks_int           = 80;
666157642Sps	sc->bce_tx_ticks               = 80;
667157642Sps
668157642Sps	sc->bce_rx_quick_cons_trip_int = 6;
669157642Sps	sc->bce_rx_quick_cons_trip     = 6;
670157642Sps	sc->bce_rx_ticks_int           = 18;
671157642Sps	sc->bce_rx_ticks               = 18;
672157642Sps#endif
673157642Sps
674157642Sps	/* Update statistics once every second. */
675157642Sps	sc->bce_stats_ticks = 1000000 & 0xffff00;
676157642Sps
677157642Sps	/*
678157642Sps	 * The copper based NetXtreme II controllers
679157642Sps	 * use an integrated PHY at address 1 while
680157642Sps	 * the SerDes controllers use a PHY at
681157642Sps	 * address 2.
682157642Sps	 */
683157642Sps	sc->bce_phy_addr = 1;
684157642Sps
685157642Sps	if (BCE_CHIP_BOND_ID(sc) & BCE_CHIP_BOND_ID_SERDES_BIT) {
686157642Sps		sc->bce_phy_flags |= BCE_PHY_SERDES_FLAG;
687157642Sps		sc->bce_flags |= BCE_NO_WOL_FLAG;
688157642Sps		if (BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5708) {
689157642Sps			sc->bce_phy_addr = 2;
690157642Sps			val = REG_RD_IND(sc, sc->bce_shmem_base +
691157642Sps					 BCE_SHARED_HW_CFG_CONFIG);
692157642Sps			if (val & BCE_SHARED_HW_CFG_PHY_2_5G)
693157642Sps				sc->bce_phy_flags |= BCE_PHY_2_5G_CAPABLE_FLAG;
694157642Sps		}
695157642Sps	}
696157642Sps
697157642Sps	/* Allocate DMA memory resources. */
698157642Sps	if (bce_dma_alloc(dev)) {
699157642Sps		BCE_PRINTF(sc, "%s(%d): DMA resource allocation failed!\n",
700157642Sps		    __FILE__, __LINE__);
701157642Sps		rc = ENXIO;
702157642Sps		goto bce_attach_fail;
703157642Sps	}
704157642Sps
705157642Sps	/* Allocate an ifnet structure. */
706157642Sps	ifp = sc->bce_ifp = if_alloc(IFT_ETHER);
707157642Sps	if (ifp == NULL) {
708157642Sps		BCE_PRINTF(sc, "%s(%d): Interface allocation failed!\n",
709157642Sps			__FILE__, __LINE__);
710157642Sps		rc = ENXIO;
711157642Sps		goto bce_attach_fail;
712157642Sps	}
713157642Sps
714157642Sps	/* Initialize the ifnet interface. */
715157642Sps	ifp->if_softc        = sc;
716157642Sps	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
717157642Sps	ifp->if_flags        = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
718157642Sps	ifp->if_ioctl        = bce_ioctl;
719157642Sps	ifp->if_start        = bce_start;
720157642Sps	ifp->if_timer        = 0;
721157642Sps	ifp->if_watchdog     = bce_watchdog;
722157642Sps	ifp->if_init         = bce_init;
723157642Sps	ifp->if_mtu          = ETHERMTU;
724157642Sps	ifp->if_hwassist     = BCE_IF_HWASSIST;
725157642Sps	ifp->if_capabilities = BCE_IF_CAPABILITIES;
726157642Sps	ifp->if_capenable    = ifp->if_capabilities;
727157642Sps
728157642Sps	/* Assume a standard 1500 byte MTU size for mbuf allocations. */
729157642Sps	sc->mbuf_alloc_size  = MCLBYTES;
730157642Sps#ifdef DEVICE_POLLING
731157642Sps	ifp->if_capabilities |= IFCAP_POLLING;
732157642Sps#endif
733157642Sps
734157642Sps	ifp->if_snd.ifq_drv_maxlen = USABLE_TX_BD;
735157642Sps	if (sc->bce_phy_flags & BCE_PHY_2_5G_CAPABLE_FLAG)
736157642Sps		ifp->if_baudrate = IF_Gbps(2.5);
737157642Sps	else
738157642Sps		ifp->if_baudrate = IF_Gbps(1);
739157642Sps
740157642Sps	IFQ_SET_MAXLEN(&ifp->if_snd, ifp->if_snd.ifq_drv_maxlen);
741157642Sps	IFQ_SET_READY(&ifp->if_snd);
742157642Sps
743157642Sps	if (sc->bce_phy_flags & BCE_PHY_SERDES_FLAG) {
744157642Sps		BCE_PRINTF(sc, "%s(%d): SerDes is not supported by this driver!\n",
745157642Sps			__FILE__, __LINE__);
746157642Sps		rc = ENODEV;
747157642Sps		goto bce_attach_fail;
748157642Sps	} else {
749157642Sps		/* Look for our PHY. */
750157642Sps		if (mii_phy_probe(dev, &sc->bce_miibus, bce_ifmedia_upd,
751157642Sps			bce_ifmedia_sts)) {
752157642Sps			BCE_PRINTF(sc, "%s(%d): PHY probe failed!\n",
753157642Sps				__FILE__, __LINE__);
754157642Sps			rc = ENXIO;
755157642Sps			goto bce_attach_fail;
756157642Sps		}
757157642Sps	}
758157642Sps
759157642Sps	/* Attach to the Ethernet interface list. */
760157642Sps	ether_ifattach(ifp, sc->eaddr);
761157642Sps
762157642Sps#if __FreeBSD_version < 500000
763157642Sps	callout_init(&sc->bce_stat_ch);
764157642Sps#else
765157642Sps	callout_init(&sc->bce_stat_ch, CALLOUT_MPSAFE);
766157642Sps#endif
767157642Sps
768157642Sps	/* Hookup IRQ last. */
769157642Sps	rc = bus_setup_intr(dev, sc->bce_irq, INTR_TYPE_NET | INTR_MPSAFE,
770157642Sps	   bce_intr, sc, &sc->bce_intrhand);
771157642Sps
772157642Sps	if (rc) {
773157642Sps		BCE_PRINTF(sc, "%s(%d): Failed to setup IRQ!\n",
774157642Sps			__FILE__, __LINE__);
775157642Sps		bce_detach(dev);
776157642Sps		goto bce_attach_exit;
777157642Sps	}
778157642Sps
779157642Sps	/* Print some important debugging info. */
780157642Sps	DBRUN(BCE_INFO, bce_dump_driver_state(sc));
781157642Sps
782157642Sps	/* Add the supported sysctls to the kernel. */
783157642Sps	bce_add_sysctls(sc);
784157642Sps
785162474Sambrisko	/* Get the firmware running so IPMI still works */
786162474Sambrisko	BCE_LOCK(sc);
787162474Sambrisko	bce_mgmt_init_locked(sc);
788162474Sambrisko	BCE_UNLOCK(sc);
789162474Sambrisko
790157642Sps	goto bce_attach_exit;
791157642Sps
792157642Spsbce_attach_fail:
793157642Sps	bce_release_resources(sc);
794157642Sps
795157642Spsbce_attach_exit:
796157642Sps
797157642Sps	DBPRINT(sc, BCE_VERBOSE_RESET, "Exiting %s()\n", __FUNCTION__);
798157642Sps
799157642Sps	return(rc);
800157642Sps}
801157642Sps
802157642Sps
803157642Sps/****************************************************************************/
804157642Sps/* Device detach function.                                                  */
805157642Sps/*                                                                          */
806157642Sps/* Stops the controller, resets the controller, and releases resources.     */
807157642Sps/*                                                                          */
808157642Sps/* Returns:                                                                 */
809157642Sps/*   0 on success, positive value on failure.                               */
810157642Sps/****************************************************************************/
811157642Spsstatic int
812157642Spsbce_detach(device_t dev)
813157642Sps{
814157642Sps	struct bce_softc *sc;
815157642Sps	struct ifnet *ifp;
816157642Sps
817157642Sps	sc = device_get_softc(dev);
818157642Sps
819157642Sps	DBPRINT(sc, BCE_VERBOSE_RESET, "Entering %s()\n", __FUNCTION__);
820157642Sps
821157642Sps	ifp = sc->bce_ifp;
822157642Sps
823157642Sps#ifdef DEVICE_POLLING
824157642Sps	if (ifp->if_capenable & IFCAP_POLLING)
825157642Sps		ether_poll_deregister(ifp);
826157642Sps#endif
827157642Sps
828157642Sps	/* Stop and reset the controller. */
829157642Sps	BCE_LOCK(sc);
830157642Sps	bce_stop(sc);
831157642Sps	bce_reset(sc, BCE_DRV_MSG_CODE_RESET);
832157642Sps	BCE_UNLOCK(sc);
833157642Sps
834157642Sps	ether_ifdetach(ifp);
835157642Sps
836157642Sps	/* If we have a child device on the MII bus remove it too. */
837157642Sps	if (sc->bce_phy_flags & BCE_PHY_SERDES_FLAG) {
838157642Sps		ifmedia_removeall(&sc->bce_ifmedia);
839157642Sps	} else {
840157642Sps		bus_generic_detach(dev);
841157642Sps		device_delete_child(dev, sc->bce_miibus);
842157642Sps	}
843157642Sps
844157642Sps	/* Release all remaining resources. */
845157642Sps	bce_release_resources(sc);
846157642Sps
847157642Sps	DBPRINT(sc, BCE_VERBOSE_RESET, "Exiting %s()\n", __FUNCTION__);
848157642Sps
849157642Sps	return(0);
850157642Sps}
851157642Sps
852157642Sps
853157642Sps/****************************************************************************/
854157642Sps/* Device shutdown function.                                                */
855157642Sps/*                                                                          */
856157642Sps/* Stops and resets the controller.                                         */
857157642Sps/*                                                                          */
858157642Sps/* Returns:                                                                 */
859157642Sps/*   Nothing                                                                */
860157642Sps/****************************************************************************/
861157642Spsstatic void
862157642Spsbce_shutdown(device_t dev)
863157642Sps{
864157642Sps	struct bce_softc *sc = device_get_softc(dev);
865157642Sps
866157642Sps	BCE_LOCK(sc);
867157642Sps	bce_stop(sc);
868157642Sps	bce_reset(sc, BCE_DRV_MSG_CODE_RESET);
869157642Sps	BCE_UNLOCK(sc);
870157642Sps}
871157642Sps
872157642Sps
873157642Sps/****************************************************************************/
874157642Sps/* Indirect register read.                                                  */
875157642Sps/*                                                                          */
876157642Sps/* Reads NetXtreme II registers using an index/data register pair in PCI    */
877157642Sps/* configuration space.  Using this mechanism avoids issues with posted     */
878157642Sps/* reads but is much slower than memory-mapped I/O.                         */
879157642Sps/*                                                                          */
880157642Sps/* Returns:                                                                 */
881157642Sps/*   The value of the register.                                             */
882157642Sps/****************************************************************************/
883157642Spsstatic u32
884157642Spsbce_reg_rd_ind(struct bce_softc *sc, u32 offset)
885157642Sps{
886157642Sps	device_t dev;
887157642Sps	dev = sc->bce_dev;
888157642Sps
889157642Sps	pci_write_config(dev, BCE_PCICFG_REG_WINDOW_ADDRESS, offset, 4);
890157642Sps#ifdef BCE_DEBUG
891157642Sps	{
892157642Sps		u32 val;
893157642Sps		val = pci_read_config(dev, BCE_PCICFG_REG_WINDOW, 4);
894157642Sps		DBPRINT(sc, BCE_EXCESSIVE, "%s(); offset = 0x%08X, val = 0x%08X\n",
895157642Sps			__FUNCTION__, offset, val);
896157642Sps		return val;
897157642Sps	}
898157642Sps#else
899157642Sps	return pci_read_config(dev, BCE_PCICFG_REG_WINDOW, 4);
900157642Sps#endif
901157642Sps}
902157642Sps
903157642Sps
904157642Sps/****************************************************************************/
905157642Sps/* Indirect register write.                                                 */
906157642Sps/*                                                                          */
907157642Sps/* Writes NetXtreme II registers using an index/data register pair in PCI   */
908157642Sps/* configuration space.  Using this mechanism avoids issues with posted     */
909157642Sps/* writes but is muchh slower than memory-mapped I/O.                       */
910157642Sps/*                                                                          */
911157642Sps/* Returns:                                                                 */
912157642Sps/*   Nothing.                                                               */
913157642Sps/****************************************************************************/
914157642Spsstatic void
915157642Spsbce_reg_wr_ind(struct bce_softc *sc, u32 offset, u32 val)
916157642Sps{
917157642Sps	device_t dev;
918157642Sps	dev = sc->bce_dev;
919157642Sps
920157642Sps	DBPRINT(sc, BCE_EXCESSIVE, "%s(); offset = 0x%08X, val = 0x%08X\n",
921157642Sps		__FUNCTION__, offset, val);
922157642Sps
923157642Sps	pci_write_config(dev, BCE_PCICFG_REG_WINDOW_ADDRESS, offset, 4);
924157642Sps	pci_write_config(dev, BCE_PCICFG_REG_WINDOW, val, 4);
925157642Sps}
926157642Sps
927157642Sps
928157642Sps/****************************************************************************/
929157642Sps/* Context memory write.                                                    */
930157642Sps/*                                                                          */
931157642Sps/* The NetXtreme II controller uses context memory to track connection      */
932157642Sps/* information for L2 and higher network protocols.                         */
933157642Sps/*                                                                          */
934157642Sps/* Returns:                                                                 */
935157642Sps/*   Nothing.                                                               */
936157642Sps/****************************************************************************/
937157642Spsstatic void
938157642Spsbce_ctx_wr(struct bce_softc *sc, u32 cid_addr, u32 offset, u32 val)
939157642Sps{
940157642Sps
941157642Sps	DBPRINT(sc, BCE_EXCESSIVE, "%s(); cid_addr = 0x%08X, offset = 0x%08X, "
942157642Sps		"val = 0x%08X\n", __FUNCTION__, cid_addr, offset, val);
943157642Sps
944157642Sps	offset += cid_addr;
945157642Sps	REG_WR(sc, BCE_CTX_DATA_ADR, offset);
946157642Sps	REG_WR(sc, BCE_CTX_DATA, val);
947157642Sps}
948157642Sps
949157642Sps
950157642Sps/****************************************************************************/
951157642Sps/* PHY register read.                                                       */
952157642Sps/*                                                                          */
953157642Sps/* Implements register reads on the MII bus.                                */
954157642Sps/*                                                                          */
955157642Sps/* Returns:                                                                 */
956157642Sps/*   The value of the register.                                             */
957157642Sps/****************************************************************************/
958157642Spsstatic int
959157642Spsbce_miibus_read_reg(device_t dev, int phy, int reg)
960157642Sps{
961157642Sps	struct bce_softc *sc;
962157642Sps	u32 val;
963157642Sps	int i;
964157642Sps
965157642Sps	sc = device_get_softc(dev);
966157642Sps
967157642Sps	/* Make sure we are accessing the correct PHY address. */
968157642Sps	if (phy != sc->bce_phy_addr) {
969157642Sps		DBPRINT(sc, BCE_VERBOSE, "Invalid PHY address %d for PHY read!\n", phy);
970157642Sps		return(0);
971157642Sps	}
972157642Sps
973157642Sps	if (sc->bce_phy_flags & BCE_PHY_INT_MODE_AUTO_POLLING_FLAG) {
974157642Sps		val = REG_RD(sc, BCE_EMAC_MDIO_MODE);
975157642Sps		val &= ~BCE_EMAC_MDIO_MODE_AUTO_POLL;
976157642Sps
977157642Sps		REG_WR(sc, BCE_EMAC_MDIO_MODE, val);
978157642Sps		REG_RD(sc, BCE_EMAC_MDIO_MODE);
979157642Sps
980157642Sps		DELAY(40);
981157642Sps	}
982157642Sps
983157642Sps	val = BCE_MIPHY(phy) | BCE_MIREG(reg) |
984157642Sps		BCE_EMAC_MDIO_COMM_COMMAND_READ | BCE_EMAC_MDIO_COMM_DISEXT |
985157642Sps		BCE_EMAC_MDIO_COMM_START_BUSY;
986157642Sps	REG_WR(sc, BCE_EMAC_MDIO_COMM, val);
987157642Sps
988157642Sps	for (i = 0; i < BCE_PHY_TIMEOUT; i++) {
989157642Sps		DELAY(10);
990157642Sps
991157642Sps		val = REG_RD(sc, BCE_EMAC_MDIO_COMM);
992157642Sps		if (!(val & BCE_EMAC_MDIO_COMM_START_BUSY)) {
993157642Sps			DELAY(5);
994157642Sps
995157642Sps			val = REG_RD(sc, BCE_EMAC_MDIO_COMM);
996157642Sps			val &= BCE_EMAC_MDIO_COMM_DATA;
997157642Sps
998157642Sps			break;
999157642Sps		}
1000157642Sps	}
1001157642Sps
1002157642Sps	if (val & BCE_EMAC_MDIO_COMM_START_BUSY) {
1003157642Sps		BCE_PRINTF(sc, "%s(%d): Error: PHY read timeout! phy = %d, reg = 0x%04X\n",
1004157642Sps			__FILE__, __LINE__, phy, reg);
1005157642Sps		val = 0x0;
1006157642Sps	} else {
1007157642Sps		val = REG_RD(sc, BCE_EMAC_MDIO_COMM);
1008157642Sps	}
1009157642Sps
1010157642Sps	DBPRINT(sc, BCE_EXCESSIVE, "%s(): phy = %d, reg = 0x%04X, val = 0x%04X\n",
1011157642Sps		__FUNCTION__, phy, (u16) reg & 0xffff, (u16) val & 0xffff);
1012157642Sps
1013157642Sps	if (sc->bce_phy_flags & BCE_PHY_INT_MODE_AUTO_POLLING_FLAG) {
1014157642Sps		val = REG_RD(sc, BCE_EMAC_MDIO_MODE);
1015157642Sps		val |= BCE_EMAC_MDIO_MODE_AUTO_POLL;
1016157642Sps
1017157642Sps		REG_WR(sc, BCE_EMAC_MDIO_MODE, val);
1018157642Sps		REG_RD(sc, BCE_EMAC_MDIO_MODE);
1019157642Sps
1020157642Sps		DELAY(40);
1021157642Sps	}
1022157642Sps
1023157642Sps	return (val & 0xffff);
1024157642Sps
1025157642Sps}
1026157642Sps
1027157642Sps
1028157642Sps/****************************************************************************/
1029157642Sps/* PHY register write.                                                      */
1030157642Sps/*                                                                          */
1031157642Sps/* Implements register writes on the MII bus.                               */
1032157642Sps/*                                                                          */
1033157642Sps/* Returns:                                                                 */
1034157642Sps/*   The value of the register.                                             */
1035157642Sps/****************************************************************************/
1036157642Spsstatic int
1037157642Spsbce_miibus_write_reg(device_t dev, int phy, int reg, int val)
1038157642Sps{
1039157642Sps	struct bce_softc *sc;
1040157642Sps	u32 val1;
1041157642Sps	int i;
1042157642Sps
1043157642Sps	sc = device_get_softc(dev);
1044157642Sps
1045157642Sps	/* Make sure we are accessing the correct PHY address. */
1046157642Sps	if (phy != sc->bce_phy_addr) {
1047157642Sps		DBPRINT(sc, BCE_WARN, "Invalid PHY address %d for PHY write!\n", phy);
1048157642Sps		return(0);
1049157642Sps	}
1050157642Sps
1051157642Sps	DBPRINT(sc, BCE_EXCESSIVE, "%s(): phy = %d, reg = 0x%04X, val = 0x%04X\n",
1052157642Sps		__FUNCTION__, phy, (u16) reg & 0xffff, (u16) val & 0xffff);
1053157642Sps
1054157642Sps	if (sc->bce_phy_flags & BCE_PHY_INT_MODE_AUTO_POLLING_FLAG) {
1055157642Sps		val1 = REG_RD(sc, BCE_EMAC_MDIO_MODE);
1056157642Sps		val1 &= ~BCE_EMAC_MDIO_MODE_AUTO_POLL;
1057157642Sps
1058157642Sps		REG_WR(sc, BCE_EMAC_MDIO_MODE, val1);
1059157642Sps		REG_RD(sc, BCE_EMAC_MDIO_MODE);
1060157642Sps
1061157642Sps		DELAY(40);
1062157642Sps	}
1063157642Sps
1064157642Sps	val1 = BCE_MIPHY(phy) | BCE_MIREG(reg) | val |
1065157642Sps		BCE_EMAC_MDIO_COMM_COMMAND_WRITE |
1066157642Sps		BCE_EMAC_MDIO_COMM_START_BUSY | BCE_EMAC_MDIO_COMM_DISEXT;
1067157642Sps	REG_WR(sc, BCE_EMAC_MDIO_COMM, val1);
1068157642Sps
1069157642Sps	for (i = 0; i < BCE_PHY_TIMEOUT; i++) {
1070157642Sps		DELAY(10);
1071157642Sps
1072157642Sps		val1 = REG_RD(sc, BCE_EMAC_MDIO_COMM);
1073157642Sps		if (!(val1 & BCE_EMAC_MDIO_COMM_START_BUSY)) {
1074157642Sps			DELAY(5);
1075157642Sps			break;
1076157642Sps		}
1077157642Sps	}
1078157642Sps
1079157642Sps	if (val1 & BCE_EMAC_MDIO_COMM_START_BUSY)
1080157642Sps		BCE_PRINTF(sc, "%s(%d): PHY write timeout!\n",
1081157642Sps			__FILE__, __LINE__);
1082157642Sps
1083157642Sps	if (sc->bce_phy_flags & BCE_PHY_INT_MODE_AUTO_POLLING_FLAG) {
1084157642Sps		val1 = REG_RD(sc, BCE_EMAC_MDIO_MODE);
1085157642Sps		val1 |= BCE_EMAC_MDIO_MODE_AUTO_POLL;
1086157642Sps
1087157642Sps		REG_WR(sc, BCE_EMAC_MDIO_MODE, val1);
1088157642Sps		REG_RD(sc, BCE_EMAC_MDIO_MODE);
1089157642Sps
1090157642Sps		DELAY(40);
1091157642Sps	}
1092157642Sps
1093157642Sps	return 0;
1094157642Sps}
1095157642Sps
1096157642Sps
1097157642Sps/****************************************************************************/
1098157642Sps/* MII bus status change.                                                   */
1099157642Sps/*                                                                          */
1100157642Sps/* Called by the MII bus driver when the PHY establishes link to set the    */
1101157642Sps/* MAC interface registers.                                                 */
1102157642Sps/*                                                                          */
1103157642Sps/* Returns:                                                                 */
1104157642Sps/*   Nothing.                                                               */
1105157642Sps/****************************************************************************/
1106157642Spsstatic void
1107157642Spsbce_miibus_statchg(device_t dev)
1108157642Sps{
1109157642Sps	struct bce_softc *sc;
1110157642Sps	struct mii_data *mii;
1111157642Sps
1112157642Sps	sc = device_get_softc(dev);
1113157642Sps
1114157642Sps	mii = device_get_softc(sc->bce_miibus);
1115157642Sps
1116157642Sps	BCE_CLRBIT(sc, BCE_EMAC_MODE, BCE_EMAC_MODE_PORT);
1117157642Sps
1118157642Sps	/* Set MII or GMII inerface based on the speed negotiated by the PHY. */
1119157642Sps	if (IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_T) {
1120157642Sps		DBPRINT(sc, BCE_INFO, "Setting GMII interface.\n");
1121157642Sps		BCE_SETBIT(sc, BCE_EMAC_MODE, BCE_EMAC_MODE_PORT_GMII);
1122157642Sps	} else {
1123157642Sps		DBPRINT(sc, BCE_INFO, "Setting MII interface.\n");
1124157642Sps		BCE_SETBIT(sc, BCE_EMAC_MODE, BCE_EMAC_MODE_PORT_MII);
1125157642Sps	}
1126157642Sps
1127157642Sps	/* Set half or full duplex based on the duplicity negotiated by the PHY. */
1128157642Sps	if ((mii->mii_media_active & IFM_GMASK) == IFM_FDX) {
1129157642Sps		DBPRINT(sc, BCE_INFO, "Setting Full-Duplex interface.\n");
1130157642Sps		BCE_CLRBIT(sc, BCE_EMAC_MODE, BCE_EMAC_MODE_HALF_DUPLEX);
1131157642Sps	} else {
1132157642Sps		DBPRINT(sc, BCE_INFO, "Setting Half-Duplex interface.\n");
1133157642Sps		BCE_SETBIT(sc, BCE_EMAC_MODE, BCE_EMAC_MODE_HALF_DUPLEX);
1134157642Sps	}
1135157642Sps}
1136157642Sps
1137157642Sps
1138157642Sps/****************************************************************************/
1139157642Sps/* Acquire NVRAM lock.                                                      */
1140157642Sps/*                                                                          */
1141157642Sps/* Before the NVRAM can be accessed the caller must acquire an NVRAM lock.  */
1142157642Sps/* Locks 0 and 2 are reserved, lock 1 is used by firmware and lock 2 is     */
1143157642Sps/* for use by the driver.                                                   */
1144157642Sps/*                                                                          */
1145157642Sps/* Returns:                                                                 */
1146157642Sps/*   0 on success, positive value on failure.                               */
1147157642Sps/****************************************************************************/
1148157642Spsstatic int
1149157642Spsbce_acquire_nvram_lock(struct bce_softc *sc)
1150157642Sps{
1151157642Sps	u32 val;
1152157642Sps	int j;
1153157642Sps
1154157642Sps	DBPRINT(sc, BCE_VERBOSE, "Acquiring NVRAM lock.\n");
1155157642Sps
1156157642Sps	/* Request access to the flash interface. */
1157157642Sps	REG_WR(sc, BCE_NVM_SW_ARB, BCE_NVM_SW_ARB_ARB_REQ_SET2);
1158157642Sps	for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) {
1159157642Sps		val = REG_RD(sc, BCE_NVM_SW_ARB);
1160157642Sps		if (val & BCE_NVM_SW_ARB_ARB_ARB2)
1161157642Sps			break;
1162157642Sps
1163157642Sps		DELAY(5);
1164157642Sps	}
1165157642Sps
1166157642Sps	if (j >= NVRAM_TIMEOUT_COUNT) {
1167157642Sps		DBPRINT(sc, BCE_WARN, "Timeout acquiring NVRAM lock!\n");
1168157642Sps		return EBUSY;
1169157642Sps	}
1170157642Sps
1171157642Sps	return 0;
1172157642Sps}
1173157642Sps
1174157642Sps
1175157642Sps/****************************************************************************/
1176157642Sps/* Release NVRAM lock.                                                      */
1177157642Sps/*                                                                          */
1178157642Sps/* When the caller is finished accessing NVRAM the lock must be released.   */
1179157642Sps/* Locks 0 and 2 are reserved, lock 1 is used by firmware and lock 2 is     */
1180157642Sps/* for use by the driver.                                                   */
1181157642Sps/*                                                                          */
1182157642Sps/* Returns:                                                                 */
1183157642Sps/*   0 on success, positive value on failure.                               */
1184157642Sps/****************************************************************************/
1185157642Spsstatic int
1186157642Spsbce_release_nvram_lock(struct bce_softc *sc)
1187157642Sps{
1188157642Sps	int j;
1189157642Sps	u32 val;
1190157642Sps
1191157642Sps	DBPRINT(sc, BCE_VERBOSE, "Releasing NVRAM lock.\n");
1192157642Sps
1193157642Sps	/*
1194157642Sps	 * Relinquish nvram interface.
1195157642Sps	 */
1196157642Sps	REG_WR(sc, BCE_NVM_SW_ARB, BCE_NVM_SW_ARB_ARB_REQ_CLR2);
1197157642Sps
1198157642Sps	for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) {
1199157642Sps		val = REG_RD(sc, BCE_NVM_SW_ARB);
1200157642Sps		if (!(val & BCE_NVM_SW_ARB_ARB_ARB2))
1201157642Sps			break;
1202157642Sps
1203157642Sps		DELAY(5);
1204157642Sps	}
1205157642Sps
1206157642Sps	if (j >= NVRAM_TIMEOUT_COUNT) {
1207157642Sps		DBPRINT(sc, BCE_WARN, "Timeout reeasing NVRAM lock!\n");
1208157642Sps		return EBUSY;
1209157642Sps	}
1210157642Sps
1211157642Sps	return 0;
1212157642Sps}
1213157642Sps
1214157642Sps
1215157642Sps#ifdef BCE_NVRAM_WRITE_SUPPORT
1216157642Sps/****************************************************************************/
1217157642Sps/* Enable NVRAM write access.                                               */
1218157642Sps/*                                                                          */
1219157642Sps/* Before writing to NVRAM the caller must enable NVRAM writes.             */
1220157642Sps/*                                                                          */
1221157642Sps/* Returns:                                                                 */
1222157642Sps/*   0 on success, positive value on failure.                               */
1223157642Sps/****************************************************************************/
1224157642Spsstatic int
1225157642Spsbce_enable_nvram_write(struct bce_softc *sc)
1226157642Sps{
1227157642Sps	u32 val;
1228157642Sps
1229157642Sps	DBPRINT(sc, BCE_VERBOSE, "Enabling NVRAM write.\n");
1230157642Sps
1231157642Sps	val = REG_RD(sc, BCE_MISC_CFG);
1232157642Sps	REG_WR(sc, BCE_MISC_CFG, val | BCE_MISC_CFG_NVM_WR_EN_PCI);
1233157642Sps
1234157642Sps	if (!sc->bce_flash_info->buffered) {
1235157642Sps		int j;
1236157642Sps
1237157642Sps		REG_WR(sc, BCE_NVM_COMMAND, BCE_NVM_COMMAND_DONE);
1238157642Sps		REG_WR(sc, BCE_NVM_COMMAND,	BCE_NVM_COMMAND_WREN | BCE_NVM_COMMAND_DOIT);
1239157642Sps
1240157642Sps		for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) {
1241157642Sps			DELAY(5);
1242157642Sps
1243157642Sps			val = REG_RD(sc, BCE_NVM_COMMAND);
1244157642Sps			if (val & BCE_NVM_COMMAND_DONE)
1245157642Sps				break;
1246157642Sps		}
1247157642Sps
1248157642Sps		if (j >= NVRAM_TIMEOUT_COUNT) {
1249157642Sps			DBPRINT(sc, BCE_WARN, "Timeout writing NVRAM!\n");
1250157642Sps			return EBUSY;
1251157642Sps		}
1252157642Sps	}
1253157642Sps	return 0;
1254157642Sps}
1255157642Sps
1256157642Sps
1257157642Sps/****************************************************************************/
1258157642Sps/* Disable NVRAM write access.                                              */
1259157642Sps/*                                                                          */
1260157642Sps/* When the caller is finished writing to NVRAM write access must be        */
1261157642Sps/* disabled.                                                                */
1262157642Sps/*                                                                          */
1263157642Sps/* Returns:                                                                 */
1264157642Sps/*   Nothing.                                                               */
1265157642Sps/****************************************************************************/
1266157642Spsstatic void
1267157642Spsbce_disable_nvram_write(struct bce_softc *sc)
1268157642Sps{
1269157642Sps	u32 val;
1270157642Sps
1271157642Sps	DBPRINT(sc, BCE_VERBOSE,  "Disabling NVRAM write.\n");
1272157642Sps
1273157642Sps	val = REG_RD(sc, BCE_MISC_CFG);
1274157642Sps	REG_WR(sc, BCE_MISC_CFG, val & ~BCE_MISC_CFG_NVM_WR_EN);
1275157642Sps}
1276157642Sps#endif
1277157642Sps
1278157642Sps
1279157642Sps/****************************************************************************/
1280157642Sps/* Enable NVRAM access.                                                     */
1281157642Sps/*                                                                          */
1282157642Sps/* Before accessing NVRAM for read or write operations the caller must      */
1283157642Sps/* enabled NVRAM access.                                                    */
1284157642Sps/*                                                                          */
1285157642Sps/* Returns:                                                                 */
1286157642Sps/*   Nothing.                                                               */
1287157642Sps/****************************************************************************/
1288157642Spsstatic void
1289157642Spsbce_enable_nvram_access(struct bce_softc *sc)
1290157642Sps{
1291157642Sps	u32 val;
1292157642Sps
1293157642Sps	DBPRINT(sc, BCE_VERBOSE, "Enabling NVRAM access.\n");
1294157642Sps
1295157642Sps	val = REG_RD(sc, BCE_NVM_ACCESS_ENABLE);
1296157642Sps	/* Enable both bits, even on read. */
1297157642Sps	REG_WR(sc, BCE_NVM_ACCESS_ENABLE,
1298157642Sps	       val | BCE_NVM_ACCESS_ENABLE_EN | BCE_NVM_ACCESS_ENABLE_WR_EN);
1299157642Sps}
1300157642Sps
1301157642Sps
1302157642Sps/****************************************************************************/
1303157642Sps/* Disable NVRAM access.                                                    */
1304157642Sps/*                                                                          */
1305157642Sps/* When the caller is finished accessing NVRAM access must be disabled.     */
1306157642Sps/*                                                                          */
1307157642Sps/* Returns:                                                                 */
1308157642Sps/*   Nothing.                                                               */
1309157642Sps/****************************************************************************/
1310157642Spsstatic void
1311157642Spsbce_disable_nvram_access(struct bce_softc *sc)
1312157642Sps{
1313157642Sps	u32 val;
1314157642Sps
1315157642Sps	DBPRINT(sc, BCE_VERBOSE, "Disabling NVRAM access.\n");
1316157642Sps
1317157642Sps	val = REG_RD(sc, BCE_NVM_ACCESS_ENABLE);
1318157642Sps
1319157642Sps	/* Disable both bits, even after read. */
1320157642Sps	REG_WR(sc, BCE_NVM_ACCESS_ENABLE,
1321157642Sps		val & ~(BCE_NVM_ACCESS_ENABLE_EN |
1322157642Sps			BCE_NVM_ACCESS_ENABLE_WR_EN));
1323157642Sps}
1324157642Sps
1325157642Sps
1326157642Sps#ifdef BCE_NVRAM_WRITE_SUPPORT
1327157642Sps/****************************************************************************/
1328157642Sps/* Erase NVRAM page before writing.                                         */
1329157642Sps/*                                                                          */
1330157642Sps/* Non-buffered flash parts require that a page be erased before it is      */
1331157642Sps/* written.                                                                 */
1332157642Sps/*                                                                          */
1333157642Sps/* Returns:                                                                 */
1334157642Sps/*   0 on success, positive value on failure.                               */
1335157642Sps/****************************************************************************/
1336157642Spsstatic int
1337157642Spsbce_nvram_erase_page(struct bce_softc *sc, u32 offset)
1338157642Sps{
1339157642Sps	u32 cmd;
1340157642Sps	int j;
1341157642Sps
1342157642Sps	/* Buffered flash doesn't require an erase. */
1343157642Sps	if (sc->bce_flash_info->buffered)
1344157642Sps		return 0;
1345157642Sps
1346157642Sps	DBPRINT(sc, BCE_VERBOSE, "Erasing NVRAM page.\n");
1347157642Sps
1348157642Sps	/* Build an erase command. */
1349157642Sps	cmd = BCE_NVM_COMMAND_ERASE | BCE_NVM_COMMAND_WR |
1350157642Sps	      BCE_NVM_COMMAND_DOIT;
1351157642Sps
1352157642Sps	/*
1353157642Sps	 * Clear the DONE bit separately, set the NVRAM adress to erase,
1354157642Sps	 * and issue the erase command.
1355157642Sps	 */
1356157642Sps	REG_WR(sc, BCE_NVM_COMMAND, BCE_NVM_COMMAND_DONE);
1357157642Sps	REG_WR(sc, BCE_NVM_ADDR, offset & BCE_NVM_ADDR_NVM_ADDR_VALUE);
1358157642Sps	REG_WR(sc, BCE_NVM_COMMAND, cmd);
1359157642Sps
1360157642Sps	/* Wait for completion. */
1361157642Sps	for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) {
1362157642Sps		u32 val;
1363157642Sps
1364157642Sps		DELAY(5);
1365157642Sps
1366157642Sps		val = REG_RD(sc, BCE_NVM_COMMAND);
1367157642Sps		if (val & BCE_NVM_COMMAND_DONE)
1368157642Sps			break;
1369157642Sps	}
1370157642Sps
1371157642Sps	if (j >= NVRAM_TIMEOUT_COUNT) {
1372157642Sps		DBPRINT(sc, BCE_WARN, "Timeout erasing NVRAM.\n");
1373157642Sps		return EBUSY;
1374157642Sps	}
1375157642Sps
1376157642Sps	return 0;
1377157642Sps}
1378157642Sps#endif /* BCE_NVRAM_WRITE_SUPPORT */
1379157642Sps
1380157642Sps
1381157642Sps/****************************************************************************/
1382157642Sps/* Read a dword (32 bits) from NVRAM.                                       */
1383157642Sps/*                                                                          */
1384157642Sps/* Read a 32 bit word from NVRAM.  The caller is assumed to have already    */
1385157642Sps/* obtained the NVRAM lock and enabled the controller for NVRAM access.     */
1386157642Sps/*                                                                          */
1387157642Sps/* Returns:                                                                 */
1388157642Sps/*   0 on success and the 32 bit value read, positive value on failure.     */
1389157642Sps/****************************************************************************/
1390157642Spsstatic int
1391157642Spsbce_nvram_read_dword(struct bce_softc *sc, u32 offset, u8 *ret_val,
1392157642Sps							u32 cmd_flags)
1393157642Sps{
1394157642Sps	u32 cmd;
1395157642Sps	int i, rc = 0;
1396157642Sps
1397157642Sps	/* Build the command word. */
1398157642Sps	cmd = BCE_NVM_COMMAND_DOIT | cmd_flags;
1399157642Sps
1400157642Sps	/* Calculate the offset for buffered flash. */
1401157642Sps	if (sc->bce_flash_info->buffered) {
1402157642Sps		offset = ((offset / sc->bce_flash_info->page_size) <<
1403157642Sps			   sc->bce_flash_info->page_bits) +
1404157642Sps			  (offset % sc->bce_flash_info->page_size);
1405157642Sps	}
1406157642Sps
1407157642Sps	/*
1408157642Sps	 * Clear the DONE bit separately, set the address to read,
1409157642Sps	 * and issue the read.
1410157642Sps	 */
1411157642Sps	REG_WR(sc, BCE_NVM_COMMAND, BCE_NVM_COMMAND_DONE);
1412157642Sps	REG_WR(sc, BCE_NVM_ADDR, offset & BCE_NVM_ADDR_NVM_ADDR_VALUE);
1413157642Sps	REG_WR(sc, BCE_NVM_COMMAND, cmd);
1414157642Sps
1415157642Sps	/* Wait for completion. */
1416157642Sps	for (i = 0; i < NVRAM_TIMEOUT_COUNT; i++) {
1417157642Sps		u32 val;
1418157642Sps
1419157642Sps		DELAY(5);
1420157642Sps
1421157642Sps		val = REG_RD(sc, BCE_NVM_COMMAND);
1422157642Sps		if (val & BCE_NVM_COMMAND_DONE) {
1423157642Sps			val = REG_RD(sc, BCE_NVM_READ);
1424157642Sps
1425157642Sps			val = bce_be32toh(val);
1426157642Sps			memcpy(ret_val, &val, 4);
1427157642Sps			break;
1428157642Sps		}
1429157642Sps	}
1430157642Sps
1431157642Sps	/* Check for errors. */
1432157642Sps	if (i >= NVRAM_TIMEOUT_COUNT) {
1433157642Sps		BCE_PRINTF(sc, "%s(%d): Timeout error reading NVRAM at offset 0x%08X!\n",
1434157642Sps			__FILE__, __LINE__, offset);
1435157642Sps		rc = EBUSY;
1436157642Sps	}
1437157642Sps
1438157642Sps	return(rc);
1439157642Sps}
1440157642Sps
1441157642Sps
1442157642Sps#ifdef BCE_NVRAM_WRITE_SUPPORT
1443157642Sps/****************************************************************************/
1444157642Sps/* Write a dword (32 bits) to NVRAM.                                        */
1445157642Sps/*                                                                          */
1446157642Sps/* Write a 32 bit word to NVRAM.  The caller is assumed to have already     */
1447157642Sps/* obtained the NVRAM lock, enabled the controller for NVRAM access, and    */
1448157642Sps/* enabled NVRAM write access.                                              */
1449157642Sps/*                                                                          */
1450157642Sps/* Returns:                                                                 */
1451157642Sps/*   0 on success, positive value on failure.                               */
1452157642Sps/****************************************************************************/
1453157642Spsstatic int
1454157642Spsbce_nvram_write_dword(struct bce_softc *sc, u32 offset, u8 *val,
1455157642Sps	u32 cmd_flags)
1456157642Sps{
1457157642Sps	u32 cmd, val32;
1458157642Sps	int j;
1459157642Sps
1460157642Sps	/* Build the command word. */
1461157642Sps	cmd = BCE_NVM_COMMAND_DOIT | BCE_NVM_COMMAND_WR | cmd_flags;
1462157642Sps
1463157642Sps	/* Calculate the offset for buffered flash. */
1464157642Sps	if (sc->bce_flash_info->buffered) {
1465157642Sps		offset = ((offset / sc->bce_flash_info->page_size) <<
1466157642Sps			  sc->bce_flash_info->page_bits) +
1467157642Sps			 (offset % sc->bce_flash_info->page_size);
1468157642Sps	}
1469157642Sps
1470157642Sps	/*
1471157642Sps	 * Clear the DONE bit separately, convert NVRAM data to big-endian,
1472157642Sps	 * set the NVRAM address to write, and issue the write command
1473157642Sps	 */
1474157642Sps	REG_WR(sc, BCE_NVM_COMMAND, BCE_NVM_COMMAND_DONE);
1475157642Sps	memcpy(&val32, val, 4);
1476157642Sps	val32 = htobe32(val32);
1477157642Sps	REG_WR(sc, BCE_NVM_WRITE, val32);
1478157642Sps	REG_WR(sc, BCE_NVM_ADDR, offset & BCE_NVM_ADDR_NVM_ADDR_VALUE);
1479157642Sps	REG_WR(sc, BCE_NVM_COMMAND, cmd);
1480157642Sps
1481157642Sps	/* Wait for completion. */
1482157642Sps	for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) {
1483157642Sps		DELAY(5);
1484157642Sps
1485157642Sps		if (REG_RD(sc, BCE_NVM_COMMAND) & BCE_NVM_COMMAND_DONE)
1486157642Sps			break;
1487157642Sps	}
1488157642Sps	if (j >= NVRAM_TIMEOUT_COUNT) {
1489157642Sps		BCE_PRINTF(sc, "%s(%d): Timeout error writing NVRAM at offset 0x%08X\n",
1490157642Sps			__FILE__, __LINE__, offset);
1491157642Sps		return EBUSY;
1492157642Sps	}
1493157642Sps
1494157642Sps	return 0;
1495157642Sps}
1496157642Sps#endif /* BCE_NVRAM_WRITE_SUPPORT */
1497157642Sps
1498157642Sps
1499157642Sps/****************************************************************************/
1500157642Sps/* Initialize NVRAM access.                                                 */
1501157642Sps/*                                                                          */
1502157642Sps/* Identify the NVRAM device in use and prepare the NVRAM interface to      */
1503157642Sps/* access that device.                                                      */
1504157642Sps/*                                                                          */
1505157642Sps/* Returns:                                                                 */
1506157642Sps/*   0 on success, positive value on failure.                               */
1507157642Sps/****************************************************************************/
1508157642Spsstatic int
1509157642Spsbce_init_nvram(struct bce_softc *sc)
1510157642Sps{
1511157642Sps	u32 val;
1512157642Sps	int j, entry_count, rc;
1513157642Sps	struct flash_spec *flash;
1514157642Sps
1515157642Sps	DBPRINT(sc,BCE_VERBOSE_RESET, "Entering %s()\n", __FUNCTION__);
1516157642Sps
1517157642Sps	/* Determine the selected interface. */
1518157642Sps	val = REG_RD(sc, BCE_NVM_CFG1);
1519157642Sps
1520157642Sps	entry_count = sizeof(flash_table) / sizeof(struct flash_spec);
1521157642Sps
1522157642Sps	rc = 0;
1523157642Sps
1524157642Sps	/*
1525157642Sps	 * Flash reconfiguration is required to support additional
1526157642Sps	 * NVRAM devices not directly supported in hardware.
1527157642Sps	 * Check if the flash interface was reconfigured
1528157642Sps	 * by the bootcode.
1529157642Sps	 */
1530157642Sps
1531157642Sps	if (val & 0x40000000) {
1532157642Sps		/* Flash interface reconfigured by bootcode. */
1533157642Sps
1534157642Sps		DBPRINT(sc,BCE_INFO_LOAD,
1535157642Sps			"bce_init_nvram(): Flash WAS reconfigured.\n");
1536157642Sps
1537157642Sps		for (j = 0, flash = &flash_table[0]; j < entry_count;
1538157642Sps		     j++, flash++) {
1539157642Sps			if ((val & FLASH_BACKUP_STRAP_MASK) ==
1540157642Sps			    (flash->config1 & FLASH_BACKUP_STRAP_MASK)) {
1541157642Sps				sc->bce_flash_info = flash;
1542157642Sps				break;
1543157642Sps			}
1544157642Sps		}
1545157642Sps	} else {
1546157642Sps		/* Flash interface not yet reconfigured. */
1547157642Sps		u32 mask;
1548157642Sps
1549157642Sps		DBPRINT(sc,BCE_INFO_LOAD,
1550157642Sps			"bce_init_nvram(): Flash was NOT reconfigured.\n");
1551157642Sps
1552157642Sps		if (val & (1 << 23))
1553157642Sps			mask = FLASH_BACKUP_STRAP_MASK;
1554157642Sps		else
1555157642Sps			mask = FLASH_STRAP_MASK;
1556157642Sps
1557157642Sps		/* Look for the matching NVRAM device configuration data. */
1558157642Sps		for (j = 0, flash = &flash_table[0]; j < entry_count; j++, flash++) {
1559157642Sps
1560157642Sps			/* Check if the device matches any of the known devices. */
1561157642Sps			if ((val & mask) == (flash->strapping & mask)) {
1562157642Sps				/* Found a device match. */
1563157642Sps				sc->bce_flash_info = flash;
1564157642Sps
1565157642Sps				/* Request access to the flash interface. */
1566157642Sps				if ((rc = bce_acquire_nvram_lock(sc)) != 0)
1567157642Sps					return rc;
1568157642Sps
1569157642Sps				/* Reconfigure the flash interface. */
1570157642Sps				bce_enable_nvram_access(sc);
1571157642Sps				REG_WR(sc, BCE_NVM_CFG1, flash->config1);
1572157642Sps				REG_WR(sc, BCE_NVM_CFG2, flash->config2);
1573157642Sps				REG_WR(sc, BCE_NVM_CFG3, flash->config3);
1574157642Sps				REG_WR(sc, BCE_NVM_WRITE1, flash->write1);
1575157642Sps				bce_disable_nvram_access(sc);
1576157642Sps				bce_release_nvram_lock(sc);
1577157642Sps
1578157642Sps				break;
1579157642Sps			}
1580157642Sps		}
1581157642Sps	}
1582157642Sps
1583157642Sps	/* Check if a matching device was found. */
1584157642Sps	if (j == entry_count) {
1585157642Sps		sc->bce_flash_info = NULL;
1586157642Sps		BCE_PRINTF(sc, "%s(%d): Unknown Flash NVRAM found!\n",
1587157642Sps			__FILE__, __LINE__);
1588157642Sps		rc = ENODEV;
1589157642Sps	}
1590157642Sps
1591157642Sps	/* Write the flash config data to the shared memory interface. */
1592157642Sps	val = REG_RD_IND(sc, sc->bce_shmem_base + BCE_SHARED_HW_CFG_CONFIG2);
1593157642Sps	val &= BCE_SHARED_HW_CFG2_NVM_SIZE_MASK;
1594157642Sps	if (val)
1595157642Sps		sc->bce_flash_size = val;
1596157642Sps	else
1597157642Sps		sc->bce_flash_size = sc->bce_flash_info->total_size;
1598157642Sps
1599157642Sps	DBPRINT(sc, BCE_INFO_LOAD, "bce_init_nvram() flash->total_size = 0x%08X\n",
1600157642Sps		sc->bce_flash_info->total_size);
1601157642Sps
1602157642Sps	DBPRINT(sc,BCE_VERBOSE_RESET, "Exiting %s()\n", __FUNCTION__);
1603157642Sps
1604157642Sps	return rc;
1605157642Sps}
1606157642Sps
1607157642Sps
1608157642Sps/****************************************************************************/
1609157642Sps/* Read an arbitrary range of data from NVRAM.                              */
1610157642Sps/*                                                                          */
1611157642Sps/* Prepares the NVRAM interface for access and reads the requested data     */
1612157642Sps/* into the supplied buffer.                                                */
1613157642Sps/*                                                                          */
1614157642Sps/* Returns:                                                                 */
1615157642Sps/*   0 on success and the data read, positive value on failure.             */
1616157642Sps/****************************************************************************/
1617157642Spsstatic int
1618157642Spsbce_nvram_read(struct bce_softc *sc, u32 offset, u8 *ret_buf,
1619157642Sps	int buf_size)
1620157642Sps{
1621157642Sps	int rc = 0;
1622157642Sps	u32 cmd_flags, offset32, len32, extra;
1623157642Sps
1624157642Sps	if (buf_size == 0)
1625157642Sps		return 0;
1626157642Sps
1627157642Sps	/* Request access to the flash interface. */
1628157642Sps	if ((rc = bce_acquire_nvram_lock(sc)) != 0)
1629157642Sps		return rc;
1630157642Sps
1631157642Sps	/* Enable access to flash interface */
1632157642Sps	bce_enable_nvram_access(sc);
1633157642Sps
1634157642Sps	len32 = buf_size;
1635157642Sps	offset32 = offset;
1636157642Sps	extra = 0;
1637157642Sps
1638157642Sps	cmd_flags = 0;
1639157642Sps
1640157642Sps	if (offset32 & 3) {
1641157642Sps		u8 buf[4];
1642157642Sps		u32 pre_len;
1643157642Sps
1644157642Sps		offset32 &= ~3;
1645157642Sps		pre_len = 4 - (offset & 3);
1646157642Sps
1647157642Sps		if (pre_len >= len32) {
1648157642Sps			pre_len = len32;
1649157642Sps			cmd_flags = BCE_NVM_COMMAND_FIRST | BCE_NVM_COMMAND_LAST;
1650157642Sps		}
1651157642Sps		else {
1652157642Sps			cmd_flags = BCE_NVM_COMMAND_FIRST;
1653157642Sps		}
1654157642Sps
1655157642Sps		rc = bce_nvram_read_dword(sc, offset32, buf, cmd_flags);
1656157642Sps
1657157642Sps		if (rc)
1658157642Sps			return rc;
1659157642Sps
1660157642Sps		memcpy(ret_buf, buf + (offset & 3), pre_len);
1661157642Sps
1662157642Sps		offset32 += 4;
1663157642Sps		ret_buf += pre_len;
1664157642Sps		len32 -= pre_len;
1665157642Sps	}
1666157642Sps
1667157642Sps	if (len32 & 3) {
1668157642Sps		extra = 4 - (len32 & 3);
1669157642Sps		len32 = (len32 + 4) & ~3;
1670157642Sps	}
1671157642Sps
1672157642Sps	if (len32 == 4) {
1673157642Sps		u8 buf[4];
1674157642Sps
1675157642Sps		if (cmd_flags)
1676157642Sps			cmd_flags = BCE_NVM_COMMAND_LAST;
1677157642Sps		else
1678157642Sps			cmd_flags = BCE_NVM_COMMAND_FIRST |
1679157642Sps				    BCE_NVM_COMMAND_LAST;
1680157642Sps
1681157642Sps		rc = bce_nvram_read_dword(sc, offset32, buf, cmd_flags);
1682157642Sps
1683157642Sps		memcpy(ret_buf, buf, 4 - extra);
1684157642Sps	}
1685157642Sps	else if (len32 > 0) {
1686157642Sps		u8 buf[4];
1687157642Sps
1688157642Sps		/* Read the first word. */
1689157642Sps		if (cmd_flags)
1690157642Sps			cmd_flags = 0;
1691157642Sps		else
1692157642Sps			cmd_flags = BCE_NVM_COMMAND_FIRST;
1693157642Sps
1694157642Sps		rc = bce_nvram_read_dword(sc, offset32, ret_buf, cmd_flags);
1695157642Sps
1696157642Sps		/* Advance to the next dword. */
1697157642Sps		offset32 += 4;
1698157642Sps		ret_buf += 4;
1699157642Sps		len32 -= 4;
1700157642Sps
1701157642Sps		while (len32 > 4 && rc == 0) {
1702157642Sps			rc = bce_nvram_read_dword(sc, offset32, ret_buf, 0);
1703157642Sps
1704157642Sps			/* Advance to the next dword. */
1705157642Sps			offset32 += 4;
1706157642Sps			ret_buf += 4;
1707157642Sps			len32 -= 4;
1708157642Sps		}
1709157642Sps
1710157642Sps		if (rc)
1711157642Sps			return rc;
1712157642Sps
1713157642Sps		cmd_flags = BCE_NVM_COMMAND_LAST;
1714157642Sps		rc = bce_nvram_read_dword(sc, offset32, buf, cmd_flags);
1715157642Sps
1716157642Sps		memcpy(ret_buf, buf, 4 - extra);
1717157642Sps	}
1718157642Sps
1719157642Sps	/* Disable access to flash interface and release the lock. */
1720157642Sps	bce_disable_nvram_access(sc);
1721157642Sps	bce_release_nvram_lock(sc);
1722157642Sps
1723157642Sps	return rc;
1724157642Sps}
1725157642Sps
1726157642Sps
1727157642Sps#ifdef BCE_NVRAM_WRITE_SUPPORT
1728157642Sps/****************************************************************************/
1729157642Sps/* Write an arbitrary range of data from NVRAM.                             */
1730157642Sps/*                                                                          */
1731157642Sps/* Prepares the NVRAM interface for write access and writes the requested   */
1732157642Sps/* data from the supplied buffer.  The caller is responsible for            */
1733157642Sps/* calculating any appropriate CRCs.                                        */
1734157642Sps/*                                                                          */
1735157642Sps/* Returns:                                                                 */
1736157642Sps/*   0 on success, positive value on failure.                               */
1737157642Sps/****************************************************************************/
1738157642Spsstatic int
1739157642Spsbce_nvram_write(struct bce_softc *sc, u32 offset, u8 *data_buf,
1740157642Sps	int buf_size)
1741157642Sps{
1742157642Sps	u32 written, offset32, len32;
1743157642Sps	u8 *buf, start[4], end[4];
1744157642Sps	int rc = 0;
1745157642Sps	int align_start, align_end;
1746157642Sps
1747157642Sps	buf = data_buf;
1748157642Sps	offset32 = offset;
1749157642Sps	len32 = buf_size;
1750157642Sps	align_start = align_end = 0;
1751157642Sps
1752157642Sps	if ((align_start = (offset32 & 3))) {
1753157642Sps		offset32 &= ~3;
1754157642Sps		len32 += align_start;
1755157642Sps		if ((rc = bce_nvram_read(sc, offset32, start, 4)))
1756157642Sps			return rc;
1757157642Sps	}
1758157642Sps
1759157642Sps	if (len32 & 3) {
1760157642Sps	       	if ((len32 > 4) || !align_start) {
1761157642Sps			align_end = 4 - (len32 & 3);
1762157642Sps			len32 += align_end;
1763157642Sps			if ((rc = bce_nvram_read(sc, offset32 + len32 - 4,
1764157642Sps				end, 4))) {
1765157642Sps				return rc;
1766157642Sps			}
1767157642Sps		}
1768157642Sps	}
1769157642Sps
1770157642Sps	if (align_start || align_end) {
1771157642Sps		buf = malloc(len32, M_DEVBUF, M_NOWAIT);
1772157642Sps		if (buf == 0)
1773157642Sps			return ENOMEM;
1774157642Sps		if (align_start) {
1775157642Sps			memcpy(buf, start, 4);
1776157642Sps		}
1777157642Sps		if (align_end) {
1778157642Sps			memcpy(buf + len32 - 4, end, 4);
1779157642Sps		}
1780157642Sps		memcpy(buf + align_start, data_buf, buf_size);
1781157642Sps	}
1782157642Sps
1783157642Sps	written = 0;
1784157642Sps	while ((written < len32) && (rc == 0)) {
1785157642Sps		u32 page_start, page_end, data_start, data_end;
1786157642Sps		u32 addr, cmd_flags;
1787157642Sps		int i;
1788157642Sps		u8 flash_buffer[264];
1789157642Sps
1790157642Sps	    /* Find the page_start addr */
1791157642Sps		page_start = offset32 + written;
1792157642Sps		page_start -= (page_start % sc->bce_flash_info->page_size);
1793157642Sps		/* Find the page_end addr */
1794157642Sps		page_end = page_start + sc->bce_flash_info->page_size;
1795157642Sps		/* Find the data_start addr */
1796157642Sps		data_start = (written == 0) ? offset32 : page_start;
1797157642Sps		/* Find the data_end addr */
1798157642Sps		data_end = (page_end > offset32 + len32) ?
1799157642Sps			(offset32 + len32) : page_end;
1800157642Sps
1801157642Sps		/* Request access to the flash interface. */
1802157642Sps		if ((rc = bce_acquire_nvram_lock(sc)) != 0)
1803157642Sps			goto nvram_write_end;
1804157642Sps
1805157642Sps		/* Enable access to flash interface */
1806157642Sps		bce_enable_nvram_access(sc);
1807157642Sps
1808157642Sps		cmd_flags = BCE_NVM_COMMAND_FIRST;
1809157642Sps		if (sc->bce_flash_info->buffered == 0) {
1810157642Sps			int j;
1811157642Sps
1812157642Sps			/* Read the whole page into the buffer
1813157642Sps			 * (non-buffer flash only) */
1814157642Sps			for (j = 0; j < sc->bce_flash_info->page_size; j += 4) {
1815157642Sps				if (j == (sc->bce_flash_info->page_size - 4)) {
1816157642Sps					cmd_flags |= BCE_NVM_COMMAND_LAST;
1817157642Sps				}
1818157642Sps				rc = bce_nvram_read_dword(sc,
1819157642Sps					page_start + j,
1820157642Sps					&flash_buffer[j],
1821157642Sps					cmd_flags);
1822157642Sps
1823157642Sps				if (rc)
1824157642Sps					goto nvram_write_end;
1825157642Sps
1826157642Sps				cmd_flags = 0;
1827157642Sps			}
1828157642Sps		}
1829157642Sps
1830157642Sps		/* Enable writes to flash interface (unlock write-protect) */
1831157642Sps		if ((rc = bce_enable_nvram_write(sc)) != 0)
1832157642Sps			goto nvram_write_end;
1833157642Sps
1834157642Sps		/* Erase the page */
1835157642Sps		if ((rc = bce_nvram_erase_page(sc, page_start)) != 0)
1836157642Sps			goto nvram_write_end;
1837157642Sps
1838157642Sps		/* Re-enable the write again for the actual write */
1839157642Sps		bce_enable_nvram_write(sc);
1840157642Sps
1841157642Sps		/* Loop to write back the buffer data from page_start to
1842157642Sps		 * data_start */
1843157642Sps		i = 0;
1844157642Sps		if (sc->bce_flash_info->buffered == 0) {
1845157642Sps			for (addr = page_start; addr < data_start;
1846157642Sps				addr += 4, i += 4) {
1847157642Sps
1848157642Sps				rc = bce_nvram_write_dword(sc, addr,
1849157642Sps					&flash_buffer[i], cmd_flags);
1850157642Sps
1851157642Sps				if (rc != 0)
1852157642Sps					goto nvram_write_end;
1853157642Sps
1854157642Sps				cmd_flags = 0;
1855157642Sps			}
1856157642Sps		}
1857157642Sps
1858157642Sps		/* Loop to write the new data from data_start to data_end */
1859157642Sps		for (addr = data_start; addr < data_end; addr += 4, i++) {
1860157642Sps			if ((addr == page_end - 4) ||
1861157642Sps				((sc->bce_flash_info->buffered) &&
1862157642Sps				 (addr == data_end - 4))) {
1863157642Sps
1864157642Sps				cmd_flags |= BCE_NVM_COMMAND_LAST;
1865157642Sps			}
1866157642Sps			rc = bce_nvram_write_dword(sc, addr, buf,
1867157642Sps				cmd_flags);
1868157642Sps
1869157642Sps			if (rc != 0)
1870157642Sps				goto nvram_write_end;
1871157642Sps
1872157642Sps			cmd_flags = 0;
1873157642Sps			buf += 4;
1874157642Sps		}
1875157642Sps
1876157642Sps		/* Loop to write back the buffer data from data_end
1877157642Sps		 * to page_end */
1878157642Sps		if (sc->bce_flash_info->buffered == 0) {
1879157642Sps			for (addr = data_end; addr < page_end;
1880157642Sps				addr += 4, i += 4) {
1881157642Sps
1882157642Sps				if (addr == page_end-4) {
1883157642Sps					cmd_flags = BCE_NVM_COMMAND_LAST;
1884157642Sps                		}
1885157642Sps				rc = bce_nvram_write_dword(sc, addr,
1886157642Sps					&flash_buffer[i], cmd_flags);
1887157642Sps
1888157642Sps				if (rc != 0)
1889157642Sps					goto nvram_write_end;
1890157642Sps
1891157642Sps				cmd_flags = 0;
1892157642Sps			}
1893157642Sps		}
1894157642Sps
1895157642Sps		/* Disable writes to flash interface (lock write-protect) */
1896157642Sps		bce_disable_nvram_write(sc);
1897157642Sps
1898157642Sps		/* Disable access to flash interface */
1899157642Sps		bce_disable_nvram_access(sc);
1900157642Sps		bce_release_nvram_lock(sc);
1901157642Sps
1902157642Sps		/* Increment written */
1903157642Sps		written += data_end - data_start;
1904157642Sps	}
1905157642Sps
1906157642Spsnvram_write_end:
1907157642Sps	if (align_start || align_end)
1908157642Sps		free(buf, M_DEVBUF);
1909157642Sps
1910157642Sps	return rc;
1911157642Sps}
1912157642Sps#endif /* BCE_NVRAM_WRITE_SUPPORT */
1913157642Sps
1914157642Sps
1915157642Sps/****************************************************************************/
1916157642Sps/* Verifies that NVRAM is accessible and contains valid data.               */
1917157642Sps/*                                                                          */
1918157642Sps/* Reads the configuration data from NVRAM and verifies that the CRC is     */
1919157642Sps/* correct.                                                                 */
1920157642Sps/*                                                                          */
1921157642Sps/* Returns:                                                                 */
1922157642Sps/*   0 on success, positive value on failure.                               */
1923157642Sps/****************************************************************************/
1924157642Spsstatic int
1925157642Spsbce_nvram_test(struct bce_softc *sc)
1926157642Sps{
1927157642Sps	u32 buf[BCE_NVRAM_SIZE / 4];
1928157642Sps	u8 *data = (u8 *) buf;
1929157642Sps	int rc = 0;
1930157642Sps	u32 magic, csum;
1931157642Sps
1932157642Sps
1933157642Sps	/*
1934157642Sps	 * Check that the device NVRAM is valid by reading
1935157642Sps	 * the magic value at offset 0.
1936157642Sps	 */
1937157642Sps	if ((rc = bce_nvram_read(sc, 0, data, 4)) != 0)
1938157642Sps		goto bce_nvram_test_done;
1939157642Sps
1940157642Sps
1941157642Sps    magic = bce_be32toh(buf[0]);
1942157642Sps	if (magic != BCE_NVRAM_MAGIC) {
1943157642Sps		rc = ENODEV;
1944157642Sps		BCE_PRINTF(sc, "%s(%d): Invalid NVRAM magic value! Expected: 0x%08X, "
1945157642Sps			"Found: 0x%08X\n",
1946157642Sps			__FILE__, __LINE__, BCE_NVRAM_MAGIC, magic);
1947157642Sps		goto bce_nvram_test_done;
1948157642Sps	}
1949157642Sps
1950157642Sps	/*
1951157642Sps	 * Verify that the device NVRAM includes valid
1952157642Sps	 * configuration data.
1953157642Sps	 */
1954157642Sps	if ((rc = bce_nvram_read(sc, 0x100, data, BCE_NVRAM_SIZE)) != 0)
1955157642Sps		goto bce_nvram_test_done;
1956157642Sps
1957157642Sps	csum = ether_crc32_le(data, 0x100);
1958157642Sps	if (csum != BCE_CRC32_RESIDUAL) {
1959157642Sps		rc = ENODEV;
1960157642Sps		BCE_PRINTF(sc, "%s(%d): Invalid Manufacturing Information NVRAM CRC! "
1961157642Sps			"Expected: 0x%08X, Found: 0x%08X\n",
1962157642Sps			__FILE__, __LINE__, BCE_CRC32_RESIDUAL, csum);
1963157642Sps		goto bce_nvram_test_done;
1964157642Sps	}
1965157642Sps
1966157642Sps	csum = ether_crc32_le(data + 0x100, 0x100);
1967157642Sps	if (csum != BCE_CRC32_RESIDUAL) {
1968157642Sps		BCE_PRINTF(sc, "%s(%d): Invalid Feature Configuration Information "
1969157642Sps			"NVRAM CRC! Expected: 0x%08X, Found: 08%08X\n",
1970157642Sps			__FILE__, __LINE__, BCE_CRC32_RESIDUAL, csum);
1971157642Sps		rc = ENODEV;
1972157642Sps	}
1973157642Sps
1974157642Spsbce_nvram_test_done:
1975157642Sps	return rc;
1976157642Sps}
1977157642Sps
1978157642Sps
1979157642Sps/****************************************************************************/
1980157642Sps/* Free any DMA memory owned by the driver.                                 */
1981157642Sps/*                                                                          */
1982157642Sps/* Scans through each data structre that requires DMA memory and frees      */
1983157642Sps/* the memory if allocated.                                                 */
1984157642Sps/*                                                                          */
1985157642Sps/* Returns:                                                                 */
1986157642Sps/*   Nothing.                                                               */
1987157642Sps/****************************************************************************/
1988157642Spsstatic void
1989157642Spsbce_dma_free(struct bce_softc *sc)
1990157642Sps{
1991157642Sps	int i;
1992157642Sps
1993157642Sps	DBPRINT(sc,BCE_VERBOSE_RESET, "Entering %s()\n", __FUNCTION__);
1994157642Sps
1995157642Sps	/* Destroy the status block. */
1996157642Sps	if (sc->status_block != NULL)
1997157642Sps		bus_dmamem_free(
1998157642Sps			sc->status_tag,
1999157642Sps		    sc->status_block,
2000157642Sps		    sc->status_map);
2001157642Sps
2002157642Sps	if (sc->status_map != NULL) {
2003157642Sps		bus_dmamap_unload(
2004157642Sps			sc->status_tag,
2005157642Sps		    sc->status_map);
2006157642Sps		bus_dmamap_destroy(sc->status_tag,
2007157642Sps		    sc->status_map);
2008157642Sps	}
2009157642Sps
2010157642Sps	if (sc->status_tag != NULL)
2011157642Sps		bus_dma_tag_destroy(sc->status_tag);
2012157642Sps
2013157642Sps
2014157642Sps	/* Destroy the statistics block. */
2015157642Sps	if (sc->stats_block != NULL)
2016157642Sps		bus_dmamem_free(
2017157642Sps			sc->stats_tag,
2018157642Sps		    sc->stats_block,
2019157642Sps		    sc->stats_map);
2020157642Sps
2021157642Sps	if (sc->stats_map != NULL) {
2022157642Sps		bus_dmamap_unload(
2023157642Sps			sc->stats_tag,
2024157642Sps		    sc->stats_map);
2025157642Sps		bus_dmamap_destroy(sc->stats_tag,
2026157642Sps		    sc->stats_map);
2027157642Sps	}
2028157642Sps
2029157642Sps	if (sc->stats_tag != NULL)
2030157642Sps		bus_dma_tag_destroy(sc->stats_tag);
2031157642Sps
2032157642Sps
2033157642Sps	/* Free, unmap and destroy all TX buffer descriptor chain pages. */
2034157642Sps	for (i = 0; i < TX_PAGES; i++ ) {
2035157642Sps		if (sc->tx_bd_chain[i] != NULL)
2036157642Sps			bus_dmamem_free(
2037157642Sps				sc->tx_bd_chain_tag,
2038157642Sps			    sc->tx_bd_chain[i],
2039157642Sps			    sc->tx_bd_chain_map[i]);
2040157642Sps
2041157642Sps		if (sc->tx_bd_chain_map[i] != NULL) {
2042157642Sps			bus_dmamap_unload(
2043157642Sps				sc->tx_bd_chain_tag,
2044157642Sps		    	sc->tx_bd_chain_map[i]);
2045157642Sps			bus_dmamap_destroy(
2046157642Sps				sc->tx_bd_chain_tag,
2047157642Sps			    sc->tx_bd_chain_map[i]);
2048157642Sps		}
2049157642Sps
2050157642Sps	}
2051157642Sps
2052157642Sps	/* Destroy the TX buffer descriptor tag. */
2053157642Sps	if (sc->tx_bd_chain_tag != NULL)
2054157642Sps		bus_dma_tag_destroy(sc->tx_bd_chain_tag);
2055157642Sps
2056157642Sps
2057157642Sps	/* Free, unmap and destroy all RX buffer descriptor chain pages. */
2058157642Sps	for (i = 0; i < RX_PAGES; i++ ) {
2059157642Sps		if (sc->rx_bd_chain[i] != NULL)
2060157642Sps			bus_dmamem_free(
2061157642Sps				sc->rx_bd_chain_tag,
2062157642Sps			    sc->rx_bd_chain[i],
2063157642Sps			    sc->rx_bd_chain_map[i]);
2064157642Sps
2065157642Sps		if (sc->rx_bd_chain_map[i] != NULL) {
2066157642Sps			bus_dmamap_unload(
2067157642Sps				sc->rx_bd_chain_tag,
2068157642Sps		    	sc->rx_bd_chain_map[i]);
2069157642Sps			bus_dmamap_destroy(
2070157642Sps				sc->rx_bd_chain_tag,
2071157642Sps			    sc->rx_bd_chain_map[i]);
2072157642Sps		}
2073157642Sps	}
2074157642Sps
2075157642Sps	/* Destroy the RX buffer descriptor tag. */
2076157642Sps	if (sc->rx_bd_chain_tag != NULL)
2077157642Sps		bus_dma_tag_destroy(sc->rx_bd_chain_tag);
2078157642Sps
2079157642Sps
2080157642Sps	/* Unload and destroy the TX mbuf maps. */
2081157642Sps	for (i = 0; i < TOTAL_TX_BD; i++) {
2082157642Sps		if (sc->tx_mbuf_map[i] != NULL) {
2083157642Sps			bus_dmamap_unload(sc->tx_mbuf_tag,
2084157642Sps				sc->tx_mbuf_map[i]);
2085157642Sps			bus_dmamap_destroy(sc->tx_mbuf_tag,
2086157642Sps	 			sc->tx_mbuf_map[i]);
2087157642Sps		}
2088157642Sps	}
2089157642Sps
2090157642Sps	/* Destroy the TX mbuf tag. */
2091157642Sps	if (sc->tx_mbuf_tag != NULL)
2092157642Sps		bus_dma_tag_destroy(sc->tx_mbuf_tag);
2093157642Sps
2094157642Sps
2095157642Sps	/* Unload and destroy the RX mbuf maps. */
2096157642Sps	for (i = 0; i < TOTAL_RX_BD; i++) {
2097157642Sps		if (sc->rx_mbuf_map[i] != NULL) {
2098157642Sps			bus_dmamap_unload(sc->rx_mbuf_tag,
2099157642Sps				sc->rx_mbuf_map[i]);
2100157642Sps			bus_dmamap_destroy(sc->rx_mbuf_tag,
2101157642Sps	 			sc->rx_mbuf_map[i]);
2102157642Sps		}
2103157642Sps	}
2104157642Sps
2105157642Sps	/* Destroy the RX mbuf tag. */
2106157642Sps	if (sc->rx_mbuf_tag != NULL)
2107157642Sps		bus_dma_tag_destroy(sc->rx_mbuf_tag);
2108157642Sps
2109157642Sps
2110157642Sps	/* Destroy the parent tag */
2111157642Sps	if (sc->parent_tag != NULL)
2112157642Sps		bus_dma_tag_destroy(sc->parent_tag);
2113157642Sps
2114157642Sps	DBPRINT(sc, BCE_VERBOSE_RESET, "Exiting %s()\n", __FUNCTION__);
2115157642Sps
2116157642Sps}
2117157642Sps
2118157642Sps
2119157642Sps/****************************************************************************/
2120157642Sps/* Get DMA memory from the OS.                                              */
2121157642Sps/*                                                                          */
2122157642Sps/* Validates that the OS has provided DMA buffers in response to a          */
2123157642Sps/* bus_dmamap_load() call and saves the physical address of those buffers.  */
2124157642Sps/* When the callback is used the OS will return 0 for the mapping function  */
2125157642Sps/* (bus_dmamap_load()) so we use the value of map_arg->maxsegs to pass any  */
2126157642Sps/* failures back to the caller.                                             */
2127157642Sps/*                                                                          */
2128157642Sps/* Returns:                                                                 */
2129157642Sps/*   Nothing.                                                               */
2130157642Sps/****************************************************************************/
2131157642Spsstatic void
2132157642Spsbce_dma_map_addr(void *arg, bus_dma_segment_t *segs, int nseg, int error)
2133157642Sps{
2134157642Sps	struct bce_dmamap_arg *map_arg = arg;
2135157642Sps	struct bce_softc *sc = map_arg->sc;
2136157642Sps
2137157642Sps	/* Simulate a mapping failure. */
2138157642Sps	DBRUNIF(DB_RANDOMTRUE(bce_debug_dma_map_addr_failure),
2139157642Sps		BCE_PRINTF(sc, "%s(%d): Simulating DMA mapping error.\n",
2140157642Sps			__FILE__, __LINE__);
2141157642Sps		error = ENOMEM);
2142157642Sps
2143157642Sps	/* Check for an error and signal the caller that an error occurred. */
2144157642Sps	if (error || (nseg > map_arg->maxsegs)) {
2145157642Sps		BCE_PRINTF(sc, "%s(%d): DMA mapping error! error = %d, "
2146157642Sps		"nseg = %d, maxsegs = %d\n",
2147157642Sps			__FILE__, __LINE__, error, nseg, map_arg->maxsegs);
2148157642Sps		map_arg->maxsegs = 0;
2149157642Sps		goto bce_dma_map_addr_exit;
2150157642Sps	}
2151157642Sps
2152157642Sps	map_arg->busaddr = segs->ds_addr;
2153157642Sps
2154157642Spsbce_dma_map_addr_exit:
2155157642Sps	return;
2156157642Sps}
2157157642Sps
2158157642Sps
2159157642Sps/****************************************************************************/
2160157642Sps/* Map TX buffers into TX buffer descriptors.                               */
2161157642Sps/*                                                                          */
2162157642Sps/* Given a series of DMA memory containting an outgoing frame, map the      */
2163157642Sps/* segments into the tx_bd structure used by the hardware.                  */
2164157642Sps/*                                                                          */
2165157642Sps/* Returns:                                                                 */
2166157642Sps/*   Nothing.                                                               */
2167157642Sps/****************************************************************************/
2168157642Spsstatic void
2169157642Spsbce_dma_map_tx_desc(void *arg, bus_dma_segment_t *segs,
2170157642Sps	int nseg, bus_size_t mapsize, int error)
2171157642Sps{
2172157642Sps	struct bce_dmamap_arg *map_arg;
2173157642Sps	struct bce_softc *sc;
2174157642Sps	struct tx_bd *txbd = NULL;
2175157642Sps	int i = 0;
2176157642Sps	u16 prod, chain_prod;
2177157642Sps	u32	prod_bseq;
2178157642Sps#ifdef BCE_DEBUG
2179157642Sps	u16 debug_prod;
2180157642Sps#endif
2181157642Sps
2182157642Sps	map_arg = arg;
2183157642Sps	sc = map_arg->sc;
2184157642Sps
2185157642Sps	if (error) {
2186157642Sps		DBPRINT(sc, BCE_WARN, "%s(): Called with error = %d\n",
2187157642Sps			__FUNCTION__, error);
2188157642Sps		return;
2189157642Sps	}
2190157642Sps
2191157642Sps	/* Signal error to caller if there's too many segments */
2192157642Sps	if (nseg > map_arg->maxsegs) {
2193157642Sps		DBPRINT(sc, BCE_WARN,
2194157642Sps			"%s(): Mapped TX descriptors: max segs = %d, "
2195157642Sps			"actual segs = %d\n",
2196157642Sps			__FUNCTION__, map_arg->maxsegs, nseg);
2197157642Sps
2198157642Sps		map_arg->maxsegs = 0;
2199157642Sps		return;
2200157642Sps	}
2201157642Sps
2202157642Sps	/* prod points to an empty tx_bd at this point. */
2203157642Sps	prod       = map_arg->prod;
2204157642Sps	chain_prod = map_arg->chain_prod;
2205157642Sps	prod_bseq  = map_arg->prod_bseq;
2206157642Sps
2207157642Sps#ifdef BCE_DEBUG
2208157642Sps	debug_prod = chain_prod;
2209157642Sps#endif
2210157642Sps
2211157642Sps	DBPRINT(sc, BCE_INFO_SEND,
2212157642Sps		"%s(): Start: prod = 0x%04X, chain_prod = %04X, "
2213157642Sps		"prod_bseq = 0x%08X\n",
2214157642Sps		__FUNCTION__, prod, chain_prod, prod_bseq);
2215157642Sps
2216157642Sps	/*
2217157642Sps	 * Cycle through each mbuf segment that makes up
2218157642Sps	 * the outgoing frame, gathering the mapping info
2219157642Sps	 * for that segment and creating a tx_bd to for
2220157642Sps	 * the mbuf.
2221157642Sps	 */
2222157642Sps
2223163337Sscottl	txbd = &sc->tx_bd_chain[TX_PAGE(chain_prod)][TX_IDX(chain_prod)];
2224157642Sps
2225157642Sps	/* Setup the first tx_bd for the first segment. */
2226157642Sps	txbd->tx_bd_haddr_lo       = htole32(BCE_ADDR_LO(segs[i].ds_addr));
2227157642Sps	txbd->tx_bd_haddr_hi       = htole32(BCE_ADDR_HI(segs[i].ds_addr));
2228157642Sps	txbd->tx_bd_mss_nbytes     = htole16(segs[i].ds_len);
2229157642Sps	txbd->tx_bd_vlan_tag_flags = htole16(map_arg->tx_flags |
2230157642Sps			TX_BD_FLAGS_START);
2231157642Sps	prod_bseq += segs[i].ds_len;
2232157642Sps
2233157642Sps	/* Setup any remaing segments. */
2234157642Sps	for (i = 1; i < nseg; i++) {
2235157642Sps		prod       = NEXT_TX_BD(prod);
2236157642Sps		chain_prod = TX_CHAIN_IDX(prod);
2237157642Sps
2238163337Sscottl		txbd = &sc->tx_bd_chain[TX_PAGE(chain_prod)][TX_IDX(chain_prod)];
2239157642Sps
2240157642Sps		txbd->tx_bd_haddr_lo       = htole32(BCE_ADDR_LO(segs[i].ds_addr));
2241157642Sps		txbd->tx_bd_haddr_hi       = htole32(BCE_ADDR_HI(segs[i].ds_addr));
2242157642Sps		txbd->tx_bd_mss_nbytes     = htole16(segs[i].ds_len);
2243157642Sps		txbd->tx_bd_vlan_tag_flags = htole16(map_arg->tx_flags);
2244157642Sps
2245157642Sps		prod_bseq += segs[i].ds_len;
2246157642Sps	}
2247157642Sps
2248157642Sps	/* Set the END flag on the last TX buffer descriptor. */
2249157642Sps	txbd->tx_bd_vlan_tag_flags |= htole16(TX_BD_FLAGS_END);
2250157642Sps
2251157642Sps	DBRUN(BCE_INFO_SEND, bce_dump_tx_chain(sc, debug_prod, nseg));
2252157642Sps
2253157642Sps	DBPRINT(sc, BCE_INFO_SEND,
2254157642Sps		"%s(): End: prod = 0x%04X, chain_prod = %04X, "
2255157642Sps		"prod_bseq = 0x%08X\n",
2256157642Sps		__FUNCTION__, prod, chain_prod, prod_bseq);
2257157642Sps
2258157642Sps	/* prod points to the last tx_bd at this point. */
2259157642Sps	map_arg->maxsegs    = nseg;
2260157642Sps	map_arg->prod       = prod;
2261157642Sps	map_arg->chain_prod = chain_prod;
2262157642Sps	map_arg->prod_bseq  = prod_bseq;
2263157642Sps}
2264157642Sps
2265157642Sps
2266157642Sps/****************************************************************************/
2267157642Sps/* Allocate any DMA memory needed by the driver.                            */
2268157642Sps/*                                                                          */
2269157642Sps/* Allocates DMA memory needed for the various global structures needed by  */
2270157642Sps/* hardware.                                                                */
2271157642Sps/*                                                                          */
2272157642Sps/* Returns:                                                                 */
2273157642Sps/*   0 for success, positive value for failure.                             */
2274157642Sps/****************************************************************************/
2275157642Spsstatic int
2276157642Spsbce_dma_alloc(device_t dev)
2277157642Sps{
2278157642Sps	struct bce_softc *sc;
2279157642Sps	int i, error, rc = 0;
2280157642Sps	struct bce_dmamap_arg map_arg;
2281157642Sps
2282157642Sps	sc = device_get_softc(dev);
2283157642Sps
2284157642Sps	DBPRINT(sc, BCE_VERBOSE_RESET, "Entering %s()\n", __FUNCTION__);
2285157642Sps
2286157642Sps	/*
2287157642Sps	 * Allocate the parent bus DMA tag appropriate for PCI.
2288157642Sps	 */
2289157642Sps	if (bus_dma_tag_create(NULL,		/* parent     */
2290163287Sscottl			BCE_DMA_ALIGN,		/* alignment  */
2291163287Sscottl			BCE_DMA_BOUNDARY,	/* boundary   */
2292163287Sscottl			sc->max_bus_addr,	/* lowaddr    */
2293163287Sscottl			BUS_SPACE_MAXADDR,	/* highaddr   */
2294163287Sscottl			NULL, 			/* filterfunc */
2295163287Sscottl			NULL,			/* filterarg  */
2296163287Sscottl			MAXBSIZE, 		/* maxsize    */
2297163287Sscottl			BUS_SPACE_UNRESTRICTED,	/* nsegments  */
2298163287Sscottl			BUS_SPACE_MAXSIZE_32BIT,/* maxsegsize */
2299163287Sscottl			0,			/* flags      */
2300163287Sscottl			NULL, 			/* locfunc    */
2301163287Sscottl			NULL,			/* lockarg    */
2302157642Sps			&sc->parent_tag)) {
2303157642Sps		BCE_PRINTF(sc, "%s(%d): Could not allocate parent DMA tag!\n",
2304157642Sps			__FILE__, __LINE__);
2305157642Sps		rc = ENOMEM;
2306157642Sps		goto bce_dma_alloc_exit;
2307157642Sps	}
2308157642Sps
2309157642Sps	/*
2310157642Sps	 * Create a DMA tag for the status block, allocate and clear the
2311157642Sps	 * memory, map the memory into DMA space, and fetch the physical
2312157642Sps	 * address of the block.
2313157642Sps	 */
2314157642Sps	if (bus_dma_tag_create(
2315163287Sscottl		sc->parent_tag,			/* parent      */
2316157642Sps	    	BCE_DMA_ALIGN,			/* alignment   */
2317157642Sps	    	BCE_DMA_BOUNDARY,		/* boundary    */
2318157642Sps	    	sc->max_bus_addr,		/* lowaddr     */
2319157642Sps	    	BUS_SPACE_MAXADDR,		/* highaddr    */
2320163287Sscottl	    	NULL, 				/* filterfunc  */
2321163287Sscottl	    	NULL, 				/* filterarg   */
2322157642Sps	    	BCE_STATUS_BLK_SZ, 		/* maxsize     */
2323163287Sscottl	    	1,				/* nsegments   */
2324157642Sps	    	BCE_STATUS_BLK_SZ, 		/* maxsegsize  */
2325163287Sscottl	    	0,				/* flags       */
2326163287Sscottl	    	NULL, 				/* lockfunc    */
2327163287Sscottl	    	NULL,				/* lockarg     */
2328157642Sps	    	&sc->status_tag)) {
2329157642Sps		BCE_PRINTF(sc, "%s(%d): Could not allocate status block DMA tag!\n",
2330157642Sps			__FILE__, __LINE__);
2331157642Sps		rc = ENOMEM;
2332157642Sps		goto bce_dma_alloc_exit;
2333157642Sps	}
2334157642Sps
2335157642Sps	if(bus_dmamem_alloc(
2336163287Sscottl		sc->status_tag,			/* dmat        */
2337157642Sps	    	(void **)&sc->status_block,	/* vaddr       */
2338163287Sscottl	    	BUS_DMA_NOWAIT,			/* flags       */
2339157642Sps	    	&sc->status_map)) {
2340157642Sps		BCE_PRINTF(sc, "%s(%d): Could not allocate status block DMA memory!\n",
2341157642Sps			__FILE__, __LINE__);
2342157642Sps		rc = ENOMEM;
2343157642Sps		goto bce_dma_alloc_exit;
2344157642Sps	}
2345157642Sps
2346157642Sps	bzero((char *)sc->status_block, BCE_STATUS_BLK_SZ);
2347157642Sps
2348157642Sps	map_arg.sc = sc;
2349157642Sps	map_arg.maxsegs = 1;
2350157642Sps
2351157642Sps	error = bus_dmamap_load(
2352163287Sscottl		sc->status_tag,	   		/* dmat        */
2353157642Sps	    	sc->status_map,	   		/* map         */
2354157642Sps	    	sc->status_block,	 	/* buf         */
2355157642Sps	    	BCE_STATUS_BLK_SZ,	 	/* buflen      */
2356157642Sps	    	bce_dma_map_addr, 	 	/* callback    */
2357163287Sscottl	    	&map_arg,		 	/* callbackarg */
2358157642Sps	    	BUS_DMA_NOWAIT);		/* flags       */
2359157642Sps
2360157642Sps	if(error || (map_arg.maxsegs == 0)) {
2361157642Sps		BCE_PRINTF(sc, "%s(%d): Could not map status block DMA memory!\n",
2362157642Sps			__FILE__, __LINE__);
2363157642Sps		rc = ENOMEM;
2364157642Sps		goto bce_dma_alloc_exit;
2365157642Sps	}
2366157642Sps
2367157642Sps	sc->status_block_paddr = map_arg.busaddr;
2368157642Sps	/* DRC - Fix for 64 bit addresses. */
2369157642Sps	DBPRINT(sc, BCE_INFO, "status_block_paddr = 0x%08X\n",
2370157642Sps		(u32) sc->status_block_paddr);
2371157642Sps
2372157642Sps	/*
2373157642Sps	 * Create a DMA tag for the statistics block, allocate and clear the
2374157642Sps	 * memory, map the memory into DMA space, and fetch the physical
2375157642Sps	 * address of the block.
2376157642Sps	 */
2377157642Sps	if (bus_dma_tag_create(
2378163287Sscottl		sc->parent_tag,			/* parent      */
2379157642Sps	    	BCE_DMA_ALIGN,	 		/* alignment   */
2380157642Sps	    	BCE_DMA_BOUNDARY, 		/* boundary    */
2381157642Sps	    	sc->max_bus_addr,		/* lowaddr     */
2382157642Sps	    	BUS_SPACE_MAXADDR,		/* highaddr    */
2383163287Sscottl	    	NULL,		   		/* filterfunc  */
2384163287Sscottl	    	NULL, 		  		/* filterarg   */
2385157642Sps	    	BCE_STATS_BLK_SZ, 		/* maxsize     */
2386163287Sscottl	    	1,		  		/* nsegments   */
2387157642Sps	    	BCE_STATS_BLK_SZ, 		/* maxsegsize  */
2388163287Sscottl	    	0, 		  		/* flags       */
2389163287Sscottl	    	NULL, 		 		/* lockfunc    */
2390163287Sscottl	    	NULL, 		  		/* lockarg     */
2391157642Sps	    	&sc->stats_tag)) {
2392157642Sps		BCE_PRINTF(sc, "%s(%d): Could not allocate statistics block DMA tag!\n",
2393157642Sps			__FILE__, __LINE__);
2394157642Sps		rc = ENOMEM;
2395157642Sps		goto bce_dma_alloc_exit;
2396157642Sps	}
2397157642Sps
2398157642Sps	if (bus_dmamem_alloc(
2399163287Sscottl		sc->stats_tag,			/* dmat        */
2400157642Sps	    	(void **)&sc->stats_block,	/* vaddr       */
2401163287Sscottl	    	BUS_DMA_NOWAIT,			/* flags       */
2402157642Sps	    	&sc->stats_map)) {
2403157642Sps		BCE_PRINTF(sc, "%s(%d): Could not allocate statistics block DMA memory!\n",
2404157642Sps			__FILE__, __LINE__);
2405157642Sps		rc = ENOMEM;
2406157642Sps		goto bce_dma_alloc_exit;
2407157642Sps	}
2408157642Sps
2409157642Sps	bzero((char *)sc->stats_block, BCE_STATS_BLK_SZ);
2410157642Sps
2411157642Sps	map_arg.sc = sc;
2412157642Sps	map_arg.maxsegs = 1;
2413157642Sps
2414157642Sps	error = bus_dmamap_load(
2415163287Sscottl		sc->stats_tag,	 	/* dmat        */
2416157642Sps	    	sc->stats_map,	 	/* map         */
2417157642Sps	    	sc->stats_block, 	/* buf         */
2418157642Sps	    	BCE_STATS_BLK_SZ,	/* buflen      */
2419157642Sps	    	bce_dma_map_addr,	/* callback    */
2420163287Sscottl	    	&map_arg, 	 	/* callbackarg */
2421157642Sps	    	BUS_DMA_NOWAIT);	/* flags       */
2422157642Sps
2423157642Sps	if(error || (map_arg.maxsegs == 0)) {
2424157642Sps		BCE_PRINTF(sc, "%s(%d): Could not map statistics block DMA memory!\n",
2425157642Sps			__FILE__, __LINE__);
2426157642Sps		rc = ENOMEM;
2427157642Sps		goto bce_dma_alloc_exit;
2428157642Sps	}
2429157642Sps
2430157642Sps	sc->stats_block_paddr = map_arg.busaddr;
2431157642Sps	/* DRC - Fix for 64 bit address. */
2432157642Sps	DBPRINT(sc,BCE_INFO, "stats_block_paddr = 0x%08X\n",
2433157642Sps		(u32) sc->stats_block_paddr);
2434157642Sps
2435157642Sps	/*
2436157642Sps	 * Create a DMA tag for the TX buffer descriptor chain,
2437157642Sps	 * allocate and clear the  memory, and fetch the
2438157642Sps	 * physical address of the block.
2439157642Sps	 */
2440157642Sps	if(bus_dma_tag_create(
2441163287Sscottl			sc->parent_tag,		/* parent      */
2442163287Sscottl			BCM_PAGE_SIZE,		/* alignment   */
2443163287Sscottl		    	BCE_DMA_BOUNDARY,	/* boundary    */
2444163287Sscottl			sc->max_bus_addr,	/* lowaddr     */
2445163287Sscottl			BUS_SPACE_MAXADDR, 	/* highaddr    */
2446163287Sscottl			NULL,			/* filterfunc  */
2447163287Sscottl			NULL,			/* filterarg   */
2448163287Sscottl			BCE_TX_CHAIN_PAGE_SZ,	/* maxsize     */
2449163287Sscottl			1,			/* nsegments   */
2450163287Sscottl			BCE_TX_CHAIN_PAGE_SZ,	/* maxsegsize  */
2451163287Sscottl			0,			/* flags       */
2452163287Sscottl			NULL,			/* lockfunc    */
2453163287Sscottl			NULL,			/* lockarg     */
2454157642Sps			&sc->tx_bd_chain_tag)) {
2455157642Sps		BCE_PRINTF(sc, "%s(%d): Could not allocate TX descriptor chain DMA tag!\n",
2456157642Sps			__FILE__, __LINE__);
2457157642Sps		rc = ENOMEM;
2458157642Sps		goto bce_dma_alloc_exit;
2459157642Sps	}
2460157642Sps
2461157642Sps	for (i = 0; i < TX_PAGES; i++) {
2462157642Sps
2463157642Sps		if(bus_dmamem_alloc(
2464163287Sscottl			sc->tx_bd_chain_tag,		/* tag   */
2465157642Sps	    		(void **)&sc->tx_bd_chain[i],	/* vaddr */
2466163287Sscottl	    		BUS_DMA_NOWAIT,			/* flags */
2467157642Sps		    	&sc->tx_bd_chain_map[i])) {
2468157642Sps			BCE_PRINTF(sc, "%s(%d): Could not allocate TX descriptor "
2469157642Sps				"chain DMA memory!\n", __FILE__, __LINE__);
2470157642Sps			rc = ENOMEM;
2471157642Sps			goto bce_dma_alloc_exit;
2472157642Sps		}
2473157642Sps
2474157642Sps		map_arg.maxsegs = 1;
2475157642Sps		map_arg.sc = sc;
2476157642Sps
2477157642Sps		error = bus_dmamap_load(
2478163287Sscottl			sc->tx_bd_chain_tag,		/* dmat        */
2479163287Sscottl	    		sc->tx_bd_chain_map[i],		/* map         */
2480163287Sscottl	    		sc->tx_bd_chain[i],		/* buf         */
2481163287Sscottl		    	BCE_TX_CHAIN_PAGE_SZ,		/* buflen      */
2482163287Sscottl		    	bce_dma_map_addr,		/* callback    */
2483163287Sscottl	    		&map_arg,			/* callbackarg */
2484163287Sscottl	    		BUS_DMA_NOWAIT);		/* flags       */
2485157642Sps
2486157642Sps		if(error || (map_arg.maxsegs == 0)) {
2487157642Sps			BCE_PRINTF(sc, "%s(%d): Could not map TX descriptor chain DMA memory!\n",
2488157642Sps				__FILE__, __LINE__);
2489157642Sps			rc = ENOMEM;
2490157642Sps			goto bce_dma_alloc_exit;
2491157642Sps		}
2492157642Sps
2493157642Sps		sc->tx_bd_chain_paddr[i] = map_arg.busaddr;
2494157642Sps		/* DRC - Fix for 64 bit systems. */
2495157642Sps		DBPRINT(sc, BCE_INFO, "tx_bd_chain_paddr[%d] = 0x%08X\n",
2496157642Sps			i, (u32) sc->tx_bd_chain_paddr[i]);
2497157642Sps	}
2498157642Sps
2499157642Sps	/* Create a DMA tag for TX mbufs. */
2500157642Sps	if (bus_dma_tag_create(
2501157642Sps			sc->parent_tag,	 	 	/* parent      */
2502163287Sscottl			BCE_DMA_ALIGN,	 		/* alignment   */
2503163287Sscottl			BCE_DMA_BOUNDARY, 		/* boundary    */
2504157642Sps			sc->max_bus_addr,		/* lowaddr     */
2505157642Sps			BUS_SPACE_MAXADDR,		/* highaddr    */
2506163287Sscottl			NULL,				/* filterfunc  */
2507163287Sscottl			NULL,				/* filterarg   */
2508157642Sps			MCLBYTES * BCE_MAX_SEGMENTS,	/* maxsize     */
2509157642Sps			BCE_MAX_SEGMENTS,  		/* nsegments   */
2510163287Sscottl			MCLBYTES,			/* maxsegsize  */
2511163287Sscottl			0,				/* flags       */
2512163287Sscottl			NULL,				/* lockfunc    */
2513163287Sscottl			NULL,				/* lockarg     */
2514163287Sscottl			&sc->tx_mbuf_tag)) {
2515157642Sps		BCE_PRINTF(sc, "%s(%d): Could not allocate TX mbuf DMA tag!\n",
2516157642Sps			__FILE__, __LINE__);
2517157642Sps		rc = ENOMEM;
2518157642Sps		goto bce_dma_alloc_exit;
2519157642Sps	}
2520157642Sps
2521157642Sps	/* Create DMA maps for the TX mbufs clusters. */
2522157642Sps	for (i = 0; i < TOTAL_TX_BD; i++) {
2523157642Sps		if (bus_dmamap_create(sc->tx_mbuf_tag, BUS_DMA_NOWAIT,
2524157642Sps			&sc->tx_mbuf_map[i])) {
2525157642Sps			BCE_PRINTF(sc, "%s(%d): Unable to create TX mbuf DMA map!\n",
2526157642Sps				__FILE__, __LINE__);
2527157642Sps			rc = ENOMEM;
2528157642Sps			goto bce_dma_alloc_exit;
2529157642Sps		}
2530157642Sps	}
2531157642Sps
2532157642Sps	/*
2533157642Sps	 * Create a DMA tag for the RX buffer descriptor chain,
2534157642Sps	 * allocate and clear the  memory, and fetch the physical
2535157642Sps	 * address of the blocks.
2536157642Sps	 */
2537157642Sps	if (bus_dma_tag_create(
2538157642Sps			sc->parent_tag,			/* parent      */
2539163287Sscottl			BCM_PAGE_SIZE,			/* alignment   */
2540163287Sscottl			BCE_DMA_BOUNDARY,		/* boundary    */
2541157642Sps			BUS_SPACE_MAXADDR,		/* lowaddr     */
2542157642Sps			sc->max_bus_addr,		/* lowaddr     */
2543163287Sscottl			NULL,				/* filter      */
2544163287Sscottl			NULL, 				/* filterarg   */
2545163287Sscottl			BCE_RX_CHAIN_PAGE_SZ,		/* maxsize     */
2546163287Sscottl			1, 				/* nsegments   */
2547163287Sscottl			BCE_RX_CHAIN_PAGE_SZ,		/* maxsegsize  */
2548163287Sscottl			0,		 		/* flags       */
2549163287Sscottl			NULL,				/* lockfunc    */
2550163287Sscottl			NULL,				/* lockarg     */
2551157642Sps			&sc->rx_bd_chain_tag)) {
2552157642Sps		BCE_PRINTF(sc, "%s(%d): Could not allocate RX descriptor chain DMA tag!\n",
2553157642Sps			__FILE__, __LINE__);
2554157642Sps		rc = ENOMEM;
2555157642Sps		goto bce_dma_alloc_exit;
2556157642Sps	}
2557157642Sps
2558157642Sps	for (i = 0; i < RX_PAGES; i++) {
2559157642Sps
2560157642Sps		if (bus_dmamem_alloc(
2561163287Sscottl			sc->rx_bd_chain_tag,		/* tag   */
2562157642Sps	    		(void **)&sc->rx_bd_chain[i], 	/* vaddr */
2563163287Sscottl	    		BUS_DMA_NOWAIT,		  	/* flags */
2564157642Sps		    	&sc->rx_bd_chain_map[i])) {
2565157642Sps			BCE_PRINTF(sc, "%s(%d): Could not allocate RX descriptor chain "
2566157642Sps				"DMA memory!\n", __FILE__, __LINE__);
2567157642Sps			rc = ENOMEM;
2568157642Sps			goto bce_dma_alloc_exit;
2569157642Sps		}
2570157642Sps
2571157642Sps		bzero((char *)sc->rx_bd_chain[i], BCE_RX_CHAIN_PAGE_SZ);
2572157642Sps
2573157642Sps		map_arg.maxsegs = 1;
2574157642Sps		map_arg.sc = sc;
2575157642Sps
2576157642Sps		error = bus_dmamap_load(
2577163287Sscottl			sc->rx_bd_chain_tag,	/* dmat        */
2578157642Sps	    		sc->rx_bd_chain_map[i],	/* map         */
2579163287Sscottl	    		sc->rx_bd_chain[i],	/* buf         */
2580157642Sps		    	BCE_RX_CHAIN_PAGE_SZ,  	/* buflen      */
2581163287Sscottl		    	bce_dma_map_addr,   	/* callback    */
2582163287Sscottl	    		&map_arg,	   	/* callbackarg */
2583163287Sscottl	    		BUS_DMA_NOWAIT);	/* flags       */
2584157642Sps
2585157642Sps		if(error || (map_arg.maxsegs == 0)) {
2586157642Sps			BCE_PRINTF(sc, "%s(%d): Could not map RX descriptor chain DMA memory!\n",
2587157642Sps				__FILE__, __LINE__);
2588157642Sps			rc = ENOMEM;
2589157642Sps			goto bce_dma_alloc_exit;
2590157642Sps		}
2591157642Sps
2592157642Sps		sc->rx_bd_chain_paddr[i] = map_arg.busaddr;
2593157642Sps		/* DRC - Fix for 64 bit systems. */
2594157642Sps		DBPRINT(sc, BCE_INFO, "rx_bd_chain_paddr[%d] = 0x%08X\n",
2595157642Sps			i, (u32) sc->rx_bd_chain_paddr[i]);
2596157642Sps	}
2597157642Sps
2598157642Sps	/*
2599157642Sps	 * Create a DMA tag for RX mbufs.
2600157642Sps	 */
2601157642Sps	if (bus_dma_tag_create(
2602163287Sscottl			sc->parent_tag,		/* parent      */
2603163287Sscottl			BCE_DMA_ALIGN,		/* alignment   */
2604163287Sscottl			BCE_DMA_BOUNDARY,  	/* boundary    */
2605163287Sscottl			sc->max_bus_addr,  	/* lowaddr     */
2606163287Sscottl			BUS_SPACE_MAXADDR,	/* highaddr    */
2607163287Sscottl			NULL, 			/* filterfunc  */
2608163287Sscottl			NULL, 			/* filterarg   */
2609163287Sscottl			MJUM9BYTES,		/* maxsize     */
2610163287Sscottl			BCE_MAX_SEGMENTS, 	/* nsegments   */
2611163287Sscottl			MJUM9BYTES,		/* maxsegsize  */
2612163287Sscottl			0,			/* flags       */
2613163287Sscottl			NULL, 			/* lockfunc    */
2614163287Sscottl			NULL,			/* lockarg     */
2615157642Sps	    	&sc->rx_mbuf_tag)) {
2616157642Sps		BCE_PRINTF(sc, "%s(%d): Could not allocate RX mbuf DMA tag!\n",
2617157642Sps			__FILE__, __LINE__);
2618157642Sps		rc = ENOMEM;
2619157642Sps		goto bce_dma_alloc_exit;
2620157642Sps	}
2621157642Sps
2622157642Sps	/* Create DMA maps for the RX mbuf clusters. */
2623157642Sps	for (i = 0; i < TOTAL_RX_BD; i++) {
2624157642Sps		if (bus_dmamap_create(sc->rx_mbuf_tag, BUS_DMA_NOWAIT,
2625157642Sps				&sc->rx_mbuf_map[i])) {
2626157642Sps			BCE_PRINTF(sc, "%s(%d): Unable to create RX mbuf DMA map!\n",
2627157642Sps				__FILE__, __LINE__);
2628157642Sps			rc = ENOMEM;
2629157642Sps			goto bce_dma_alloc_exit;
2630157642Sps		}
2631157642Sps	}
2632157642Sps
2633157642Spsbce_dma_alloc_exit:
2634157642Sps	DBPRINT(sc, BCE_VERBOSE_RESET, "Exiting %s()\n", __FUNCTION__);
2635157642Sps
2636157642Sps	return(rc);
2637157642Sps}
2638157642Sps
2639157642Sps
2640157642Sps/****************************************************************************/
2641157642Sps/* Release all resources used by the driver.                                */
2642157642Sps/*                                                                          */
2643157642Sps/* Releases all resources acquired by the driver including interrupts,      */
2644157642Sps/* interrupt handler, interfaces, mutexes, and DMA memory.                  */
2645157642Sps/*                                                                          */
2646157642Sps/* Returns:                                                                 */
2647157642Sps/*   Nothing.                                                               */
2648157642Sps/****************************************************************************/
2649157642Spsstatic void
2650157642Spsbce_release_resources(struct bce_softc *sc)
2651157642Sps{
2652157642Sps	device_t dev;
2653157642Sps
2654157642Sps	DBPRINT(sc, BCE_VERBOSE_RESET, "Entering %s()\n", __FUNCTION__);
2655157642Sps
2656157642Sps	dev = sc->bce_dev;
2657157642Sps
2658157642Sps	bce_dma_free(sc);
2659157642Sps
2660157642Sps	if (sc->bce_intrhand != NULL)
2661157642Sps		bus_teardown_intr(dev, sc->bce_irq, sc->bce_intrhand);
2662157642Sps
2663157642Sps	if (sc->bce_irq != NULL)
2664157642Sps		bus_release_resource(dev,
2665157642Sps			SYS_RES_IRQ,
2666157642Sps			0,
2667157642Sps			sc->bce_irq);
2668157642Sps
2669157642Sps	if (sc->bce_res != NULL)
2670157642Sps		bus_release_resource(dev,
2671157642Sps			SYS_RES_MEMORY,
2672157642Sps		    PCIR_BAR(0),
2673157642Sps		    sc->bce_res);
2674157642Sps
2675157642Sps	if (sc->bce_ifp != NULL)
2676157642Sps		if_free(sc->bce_ifp);
2677157642Sps
2678157642Sps
2679157642Sps	if (mtx_initialized(&sc->bce_mtx))
2680157642Sps		BCE_LOCK_DESTROY(sc);
2681157642Sps
2682157642Sps	DBPRINT(sc, BCE_VERBOSE_RESET, "Exiting %s()\n", __FUNCTION__);
2683157642Sps
2684157642Sps}
2685157642Sps
2686157642Sps
2687157642Sps/****************************************************************************/
2688157642Sps/* Firmware synchronization.                                                */
2689157642Sps/*                                                                          */
2690157642Sps/* Before performing certain events such as a chip reset, synchronize with  */
2691157642Sps/* the firmware first.                                                      */
2692157642Sps/*                                                                          */
2693157642Sps/* Returns:                                                                 */
2694157642Sps/*   0 for success, positive value for failure.                             */
2695157642Sps/****************************************************************************/
2696157642Spsstatic int
2697157642Spsbce_fw_sync(struct bce_softc *sc, u32 msg_data)
2698157642Sps{
2699157642Sps	int i, rc = 0;
2700157642Sps	u32 val;
2701157642Sps
2702157642Sps	/* Don't waste any time if we've timed out before. */
2703157642Sps	if (sc->bce_fw_timed_out) {
2704157642Sps		rc = EBUSY;
2705157642Sps		goto bce_fw_sync_exit;
2706157642Sps	}
2707157642Sps
2708157642Sps	/* Increment the message sequence number. */
2709157642Sps	sc->bce_fw_wr_seq++;
2710157642Sps	msg_data |= sc->bce_fw_wr_seq;
2711157642Sps
2712157642Sps 	DBPRINT(sc, BCE_VERBOSE, "bce_fw_sync(): msg_data = 0x%08X\n", msg_data);
2713157642Sps
2714157642Sps	/* Send the message to the bootcode driver mailbox. */
2715157642Sps	REG_WR_IND(sc, sc->bce_shmem_base + BCE_DRV_MB, msg_data);
2716157642Sps
2717157642Sps	/* Wait for the bootcode to acknowledge the message. */
2718157642Sps	for (i = 0; i < FW_ACK_TIME_OUT_MS; i++) {
2719157642Sps		/* Check for a response in the bootcode firmware mailbox. */
2720157642Sps		val = REG_RD_IND(sc, sc->bce_shmem_base + BCE_FW_MB);
2721157642Sps		if ((val & BCE_FW_MSG_ACK) == (msg_data & BCE_DRV_MSG_SEQ))
2722157642Sps			break;
2723157642Sps		DELAY(1000);
2724157642Sps	}
2725157642Sps
2726157642Sps	/* If we've timed out, tell the bootcode that we've stopped waiting. */
2727157642Sps	if (((val & BCE_FW_MSG_ACK) != (msg_data & BCE_DRV_MSG_SEQ)) &&
2728157642Sps		((msg_data & BCE_DRV_MSG_DATA) != BCE_DRV_MSG_DATA_WAIT0)) {
2729157642Sps
2730157642Sps		BCE_PRINTF(sc, "%s(%d): Firmware synchronization timeout! "
2731157642Sps			"msg_data = 0x%08X\n",
2732157642Sps			__FILE__, __LINE__, msg_data);
2733157642Sps
2734157642Sps		msg_data &= ~BCE_DRV_MSG_CODE;
2735157642Sps		msg_data |= BCE_DRV_MSG_CODE_FW_TIMEOUT;
2736157642Sps
2737157642Sps		REG_WR_IND(sc, sc->bce_shmem_base + BCE_DRV_MB, msg_data);
2738157642Sps
2739157642Sps		sc->bce_fw_timed_out = 1;
2740157642Sps		rc = EBUSY;
2741157642Sps	}
2742157642Sps
2743157642Spsbce_fw_sync_exit:
2744157642Sps	return (rc);
2745157642Sps}
2746157642Sps
2747157642Sps
2748157642Sps/****************************************************************************/
2749157642Sps/* Load Receive Virtual 2 Physical (RV2P) processor firmware.               */
2750157642Sps/*                                                                          */
2751157642Sps/* Returns:                                                                 */
2752157642Sps/*   Nothing.                                                               */
2753157642Sps/****************************************************************************/
2754157642Spsstatic void
2755157642Spsbce_load_rv2p_fw(struct bce_softc *sc, u32 *rv2p_code,
2756157642Sps	u32 rv2p_code_len, u32 rv2p_proc)
2757157642Sps{
2758157642Sps	int i;
2759157642Sps	u32 val;
2760157642Sps
2761157642Sps	for (i = 0; i < rv2p_code_len; i += 8) {
2762157642Sps		REG_WR(sc, BCE_RV2P_INSTR_HIGH, *rv2p_code);
2763157642Sps		rv2p_code++;
2764157642Sps		REG_WR(sc, BCE_RV2P_INSTR_LOW, *rv2p_code);
2765157642Sps		rv2p_code++;
2766157642Sps
2767157642Sps		if (rv2p_proc == RV2P_PROC1) {
2768157642Sps			val = (i / 8) | BCE_RV2P_PROC1_ADDR_CMD_RDWR;
2769157642Sps			REG_WR(sc, BCE_RV2P_PROC1_ADDR_CMD, val);
2770157642Sps		}
2771157642Sps		else {
2772157642Sps			val = (i / 8) | BCE_RV2P_PROC2_ADDR_CMD_RDWR;
2773157642Sps			REG_WR(sc, BCE_RV2P_PROC2_ADDR_CMD, val);
2774157642Sps		}
2775157642Sps	}
2776157642Sps
2777157642Sps	/* Reset the processor, un-stall is done later. */
2778157642Sps	if (rv2p_proc == RV2P_PROC1) {
2779157642Sps		REG_WR(sc, BCE_RV2P_COMMAND, BCE_RV2P_COMMAND_PROC1_RESET);
2780157642Sps	}
2781157642Sps	else {
2782157642Sps		REG_WR(sc, BCE_RV2P_COMMAND, BCE_RV2P_COMMAND_PROC2_RESET);
2783157642Sps	}
2784157642Sps}
2785157642Sps
2786157642Sps
2787157642Sps/****************************************************************************/
2788157642Sps/* Load RISC processor firmware.                                            */
2789157642Sps/*                                                                          */
2790157642Sps/* Loads firmware from the file if_bcefw.h into the scratchpad memory       */
2791157642Sps/* associated with a particular processor.                                  */
2792157642Sps/*                                                                          */
2793157642Sps/* Returns:                                                                 */
2794157642Sps/*   Nothing.                                                               */
2795157642Sps/****************************************************************************/
2796157642Spsstatic void
2797157642Spsbce_load_cpu_fw(struct bce_softc *sc, struct cpu_reg *cpu_reg,
2798157642Sps	struct fw_info *fw)
2799157642Sps{
2800157642Sps	u32 offset;
2801157642Sps	u32 val;
2802157642Sps
2803157642Sps	/* Halt the CPU. */
2804157642Sps	val = REG_RD_IND(sc, cpu_reg->mode);
2805157642Sps	val |= cpu_reg->mode_value_halt;
2806157642Sps	REG_WR_IND(sc, cpu_reg->mode, val);
2807157642Sps	REG_WR_IND(sc, cpu_reg->state, cpu_reg->state_value_clear);
2808157642Sps
2809157642Sps	/* Load the Text area. */
2810157642Sps	offset = cpu_reg->spad_base + (fw->text_addr - cpu_reg->mips_view_base);
2811157642Sps	if (fw->text) {
2812157642Sps		int j;
2813157642Sps
2814157642Sps		for (j = 0; j < (fw->text_len / 4); j++, offset += 4) {
2815157642Sps			REG_WR_IND(sc, offset, fw->text[j]);
2816157642Sps	        }
2817157642Sps	}
2818157642Sps
2819157642Sps	/* Load the Data area. */
2820157642Sps	offset = cpu_reg->spad_base + (fw->data_addr - cpu_reg->mips_view_base);
2821157642Sps	if (fw->data) {
2822157642Sps		int j;
2823157642Sps
2824157642Sps		for (j = 0; j < (fw->data_len / 4); j++, offset += 4) {
2825157642Sps			REG_WR_IND(sc, offset, fw->data[j]);
2826157642Sps		}
2827157642Sps	}
2828157642Sps
2829157642Sps	/* Load the SBSS area. */
2830157642Sps	offset = cpu_reg->spad_base + (fw->sbss_addr - cpu_reg->mips_view_base);
2831157642Sps	if (fw->sbss) {
2832157642Sps		int j;
2833157642Sps
2834157642Sps		for (j = 0; j < (fw->sbss_len / 4); j++, offset += 4) {
2835157642Sps			REG_WR_IND(sc, offset, fw->sbss[j]);
2836157642Sps		}
2837157642Sps	}
2838157642Sps
2839157642Sps	/* Load the BSS area. */
2840157642Sps	offset = cpu_reg->spad_base + (fw->bss_addr - cpu_reg->mips_view_base);
2841157642Sps	if (fw->bss) {
2842157642Sps		int j;
2843157642Sps
2844157642Sps		for (j = 0; j < (fw->bss_len/4); j++, offset += 4) {
2845157642Sps			REG_WR_IND(sc, offset, fw->bss[j]);
2846157642Sps		}
2847157642Sps	}
2848157642Sps
2849157642Sps	/* Load the Read-Only area. */
2850157642Sps	offset = cpu_reg->spad_base +
2851157642Sps		(fw->rodata_addr - cpu_reg->mips_view_base);
2852157642Sps	if (fw->rodata) {
2853157642Sps		int j;
2854157642Sps
2855157642Sps		for (j = 0; j < (fw->rodata_len / 4); j++, offset += 4) {
2856157642Sps			REG_WR_IND(sc, offset, fw->rodata[j]);
2857157642Sps		}
2858157642Sps	}
2859157642Sps
2860157642Sps	/* Clear the pre-fetch instruction. */
2861157642Sps	REG_WR_IND(sc, cpu_reg->inst, 0);
2862157642Sps	REG_WR_IND(sc, cpu_reg->pc, fw->start_addr);
2863157642Sps
2864157642Sps	/* Start the CPU. */
2865157642Sps	val = REG_RD_IND(sc, cpu_reg->mode);
2866157642Sps	val &= ~cpu_reg->mode_value_halt;
2867157642Sps	REG_WR_IND(sc, cpu_reg->state, cpu_reg->state_value_clear);
2868157642Sps	REG_WR_IND(sc, cpu_reg->mode, val);
2869157642Sps}
2870157642Sps
2871157642Sps
2872157642Sps/****************************************************************************/
2873157642Sps/* Initialize the RV2P, RX, TX, TPAT, and COM CPUs.                         */
2874157642Sps/*                                                                          */
2875157642Sps/* Loads the firmware for each CPU and starts the CPU.                      */
2876157642Sps/*                                                                          */
2877157642Sps/* Returns:                                                                 */
2878157642Sps/*   Nothing.                                                               */
2879157642Sps/****************************************************************************/
2880157642Spsstatic void
2881157642Spsbce_init_cpus(struct bce_softc *sc)
2882157642Sps{
2883157642Sps	struct cpu_reg cpu_reg;
2884157642Sps	struct fw_info fw;
2885157642Sps
2886157642Sps	/* Initialize the RV2P processor. */
2887157642Sps	bce_load_rv2p_fw(sc, bce_rv2p_proc1, sizeof(bce_rv2p_proc1), RV2P_PROC1);
2888157642Sps	bce_load_rv2p_fw(sc, bce_rv2p_proc2, sizeof(bce_rv2p_proc2), RV2P_PROC2);
2889157642Sps
2890157642Sps	/* Initialize the RX Processor. */
2891157642Sps	cpu_reg.mode = BCE_RXP_CPU_MODE;
2892157642Sps	cpu_reg.mode_value_halt = BCE_RXP_CPU_MODE_SOFT_HALT;
2893157642Sps	cpu_reg.mode_value_sstep = BCE_RXP_CPU_MODE_STEP_ENA;
2894157642Sps	cpu_reg.state = BCE_RXP_CPU_STATE;
2895157642Sps	cpu_reg.state_value_clear = 0xffffff;
2896157642Sps	cpu_reg.gpr0 = BCE_RXP_CPU_REG_FILE;
2897157642Sps	cpu_reg.evmask = BCE_RXP_CPU_EVENT_MASK;
2898157642Sps	cpu_reg.pc = BCE_RXP_CPU_PROGRAM_COUNTER;
2899157642Sps	cpu_reg.inst = BCE_RXP_CPU_INSTRUCTION;
2900157642Sps	cpu_reg.bp = BCE_RXP_CPU_HW_BREAKPOINT;
2901157642Sps	cpu_reg.spad_base = BCE_RXP_SCRATCH;
2902157642Sps	cpu_reg.mips_view_base = 0x8000000;
2903157642Sps
2904157642Sps	fw.ver_major = bce_RXP_b06FwReleaseMajor;
2905157642Sps	fw.ver_minor = bce_RXP_b06FwReleaseMinor;
2906157642Sps	fw.ver_fix = bce_RXP_b06FwReleaseFix;
2907157642Sps	fw.start_addr = bce_RXP_b06FwStartAddr;
2908157642Sps
2909157642Sps	fw.text_addr = bce_RXP_b06FwTextAddr;
2910157642Sps	fw.text_len = bce_RXP_b06FwTextLen;
2911157642Sps	fw.text_index = 0;
2912157642Sps	fw.text = bce_RXP_b06FwText;
2913157642Sps
2914157642Sps	fw.data_addr = bce_RXP_b06FwDataAddr;
2915157642Sps	fw.data_len = bce_RXP_b06FwDataLen;
2916157642Sps	fw.data_index = 0;
2917157642Sps	fw.data = bce_RXP_b06FwData;
2918157642Sps
2919157642Sps	fw.sbss_addr = bce_RXP_b06FwSbssAddr;
2920157642Sps	fw.sbss_len = bce_RXP_b06FwSbssLen;
2921157642Sps	fw.sbss_index = 0;
2922157642Sps	fw.sbss = bce_RXP_b06FwSbss;
2923157642Sps
2924157642Sps	fw.bss_addr = bce_RXP_b06FwBssAddr;
2925157642Sps	fw.bss_len = bce_RXP_b06FwBssLen;
2926157642Sps	fw.bss_index = 0;
2927157642Sps	fw.bss = bce_RXP_b06FwBss;
2928157642Sps
2929157642Sps	fw.rodata_addr = bce_RXP_b06FwRodataAddr;
2930157642Sps	fw.rodata_len = bce_RXP_b06FwRodataLen;
2931157642Sps	fw.rodata_index = 0;
2932157642Sps	fw.rodata = bce_RXP_b06FwRodata;
2933157642Sps
2934157642Sps	DBPRINT(sc, BCE_INFO_RESET, "Loading RX firmware.\n");
2935157642Sps	bce_load_cpu_fw(sc, &cpu_reg, &fw);
2936157642Sps
2937157642Sps	/* Initialize the TX Processor. */
2938157642Sps	cpu_reg.mode = BCE_TXP_CPU_MODE;
2939157642Sps	cpu_reg.mode_value_halt = BCE_TXP_CPU_MODE_SOFT_HALT;
2940157642Sps	cpu_reg.mode_value_sstep = BCE_TXP_CPU_MODE_STEP_ENA;
2941157642Sps	cpu_reg.state = BCE_TXP_CPU_STATE;
2942157642Sps	cpu_reg.state_value_clear = 0xffffff;
2943157642Sps	cpu_reg.gpr0 = BCE_TXP_CPU_REG_FILE;
2944157642Sps	cpu_reg.evmask = BCE_TXP_CPU_EVENT_MASK;
2945157642Sps	cpu_reg.pc = BCE_TXP_CPU_PROGRAM_COUNTER;
2946157642Sps	cpu_reg.inst = BCE_TXP_CPU_INSTRUCTION;
2947157642Sps	cpu_reg.bp = BCE_TXP_CPU_HW_BREAKPOINT;
2948157642Sps	cpu_reg.spad_base = BCE_TXP_SCRATCH;
2949157642Sps	cpu_reg.mips_view_base = 0x8000000;
2950157642Sps
2951157642Sps	fw.ver_major = bce_TXP_b06FwReleaseMajor;
2952157642Sps	fw.ver_minor = bce_TXP_b06FwReleaseMinor;
2953157642Sps	fw.ver_fix = bce_TXP_b06FwReleaseFix;
2954157642Sps	fw.start_addr = bce_TXP_b06FwStartAddr;
2955157642Sps
2956157642Sps	fw.text_addr = bce_TXP_b06FwTextAddr;
2957157642Sps	fw.text_len = bce_TXP_b06FwTextLen;
2958157642Sps	fw.text_index = 0;
2959157642Sps	fw.text = bce_TXP_b06FwText;
2960157642Sps
2961157642Sps	fw.data_addr = bce_TXP_b06FwDataAddr;
2962157642Sps	fw.data_len = bce_TXP_b06FwDataLen;
2963157642Sps	fw.data_index = 0;
2964157642Sps	fw.data = bce_TXP_b06FwData;
2965157642Sps
2966157642Sps	fw.sbss_addr = bce_TXP_b06FwSbssAddr;
2967157642Sps	fw.sbss_len = bce_TXP_b06FwSbssLen;
2968157642Sps	fw.sbss_index = 0;
2969157642Sps	fw.sbss = bce_TXP_b06FwSbss;
2970157642Sps
2971157642Sps	fw.bss_addr = bce_TXP_b06FwBssAddr;
2972157642Sps	fw.bss_len = bce_TXP_b06FwBssLen;
2973157642Sps	fw.bss_index = 0;
2974157642Sps	fw.bss = bce_TXP_b06FwBss;
2975157642Sps
2976157642Sps	fw.rodata_addr = bce_TXP_b06FwRodataAddr;
2977157642Sps	fw.rodata_len = bce_TXP_b06FwRodataLen;
2978157642Sps	fw.rodata_index = 0;
2979157642Sps	fw.rodata = bce_TXP_b06FwRodata;
2980157642Sps
2981157642Sps	DBPRINT(sc, BCE_INFO_RESET, "Loading TX firmware.\n");
2982157642Sps	bce_load_cpu_fw(sc, &cpu_reg, &fw);
2983157642Sps
2984157642Sps	/* Initialize the TX Patch-up Processor. */
2985157642Sps	cpu_reg.mode = BCE_TPAT_CPU_MODE;
2986157642Sps	cpu_reg.mode_value_halt = BCE_TPAT_CPU_MODE_SOFT_HALT;
2987157642Sps	cpu_reg.mode_value_sstep = BCE_TPAT_CPU_MODE_STEP_ENA;
2988157642Sps	cpu_reg.state = BCE_TPAT_CPU_STATE;
2989157642Sps	cpu_reg.state_value_clear = 0xffffff;
2990157642Sps	cpu_reg.gpr0 = BCE_TPAT_CPU_REG_FILE;
2991157642Sps	cpu_reg.evmask = BCE_TPAT_CPU_EVENT_MASK;
2992157642Sps	cpu_reg.pc = BCE_TPAT_CPU_PROGRAM_COUNTER;
2993157642Sps	cpu_reg.inst = BCE_TPAT_CPU_INSTRUCTION;
2994157642Sps	cpu_reg.bp = BCE_TPAT_CPU_HW_BREAKPOINT;
2995157642Sps	cpu_reg.spad_base = BCE_TPAT_SCRATCH;
2996157642Sps	cpu_reg.mips_view_base = 0x8000000;
2997157642Sps
2998157642Sps	fw.ver_major = bce_TPAT_b06FwReleaseMajor;
2999157642Sps	fw.ver_minor = bce_TPAT_b06FwReleaseMinor;
3000157642Sps	fw.ver_fix = bce_TPAT_b06FwReleaseFix;
3001157642Sps	fw.start_addr = bce_TPAT_b06FwStartAddr;
3002157642Sps
3003157642Sps	fw.text_addr = bce_TPAT_b06FwTextAddr;
3004157642Sps	fw.text_len = bce_TPAT_b06FwTextLen;
3005157642Sps	fw.text_index = 0;
3006157642Sps	fw.text = bce_TPAT_b06FwText;
3007157642Sps
3008157642Sps	fw.data_addr = bce_TPAT_b06FwDataAddr;
3009157642Sps	fw.data_len = bce_TPAT_b06FwDataLen;
3010157642Sps	fw.data_index = 0;
3011157642Sps	fw.data = bce_TPAT_b06FwData;
3012157642Sps
3013157642Sps	fw.sbss_addr = bce_TPAT_b06FwSbssAddr;
3014157642Sps	fw.sbss_len = bce_TPAT_b06FwSbssLen;
3015157642Sps	fw.sbss_index = 0;
3016157642Sps	fw.sbss = bce_TPAT_b06FwSbss;
3017157642Sps
3018157642Sps	fw.bss_addr = bce_TPAT_b06FwBssAddr;
3019157642Sps	fw.bss_len = bce_TPAT_b06FwBssLen;
3020157642Sps	fw.bss_index = 0;
3021157642Sps	fw.bss = bce_TPAT_b06FwBss;
3022157642Sps
3023157642Sps	fw.rodata_addr = bce_TPAT_b06FwRodataAddr;
3024157642Sps	fw.rodata_len = bce_TPAT_b06FwRodataLen;
3025157642Sps	fw.rodata_index = 0;
3026157642Sps	fw.rodata = bce_TPAT_b06FwRodata;
3027157642Sps
3028157642Sps	DBPRINT(sc, BCE_INFO_RESET, "Loading TPAT firmware.\n");
3029157642Sps	bce_load_cpu_fw(sc, &cpu_reg, &fw);
3030157642Sps
3031157642Sps	/* Initialize the Completion Processor. */
3032157642Sps	cpu_reg.mode = BCE_COM_CPU_MODE;
3033157642Sps	cpu_reg.mode_value_halt = BCE_COM_CPU_MODE_SOFT_HALT;
3034157642Sps	cpu_reg.mode_value_sstep = BCE_COM_CPU_MODE_STEP_ENA;
3035157642Sps	cpu_reg.state = BCE_COM_CPU_STATE;
3036157642Sps	cpu_reg.state_value_clear = 0xffffff;
3037157642Sps	cpu_reg.gpr0 = BCE_COM_CPU_REG_FILE;
3038157642Sps	cpu_reg.evmask = BCE_COM_CPU_EVENT_MASK;
3039157642Sps	cpu_reg.pc = BCE_COM_CPU_PROGRAM_COUNTER;
3040157642Sps	cpu_reg.inst = BCE_COM_CPU_INSTRUCTION;
3041157642Sps	cpu_reg.bp = BCE_COM_CPU_HW_BREAKPOINT;
3042157642Sps	cpu_reg.spad_base = BCE_COM_SCRATCH;
3043157642Sps	cpu_reg.mips_view_base = 0x8000000;
3044157642Sps
3045157642Sps	fw.ver_major = bce_COM_b06FwReleaseMajor;
3046157642Sps	fw.ver_minor = bce_COM_b06FwReleaseMinor;
3047157642Sps	fw.ver_fix = bce_COM_b06FwReleaseFix;
3048157642Sps	fw.start_addr = bce_COM_b06FwStartAddr;
3049157642Sps
3050157642Sps	fw.text_addr = bce_COM_b06FwTextAddr;
3051157642Sps	fw.text_len = bce_COM_b06FwTextLen;
3052157642Sps	fw.text_index = 0;
3053157642Sps	fw.text = bce_COM_b06FwText;
3054157642Sps
3055157642Sps	fw.data_addr = bce_COM_b06FwDataAddr;
3056157642Sps	fw.data_len = bce_COM_b06FwDataLen;
3057157642Sps	fw.data_index = 0;
3058157642Sps	fw.data = bce_COM_b06FwData;
3059157642Sps
3060157642Sps	fw.sbss_addr = bce_COM_b06FwSbssAddr;
3061157642Sps	fw.sbss_len = bce_COM_b06FwSbssLen;
3062157642Sps	fw.sbss_index = 0;
3063157642Sps	fw.sbss = bce_COM_b06FwSbss;
3064157642Sps
3065157642Sps	fw.bss_addr = bce_COM_b06FwBssAddr;
3066157642Sps	fw.bss_len = bce_COM_b06FwBssLen;
3067157642Sps	fw.bss_index = 0;
3068157642Sps	fw.bss = bce_COM_b06FwBss;
3069157642Sps
3070157642Sps	fw.rodata_addr = bce_COM_b06FwRodataAddr;
3071157642Sps	fw.rodata_len = bce_COM_b06FwRodataLen;
3072157642Sps	fw.rodata_index = 0;
3073157642Sps	fw.rodata = bce_COM_b06FwRodata;
3074157642Sps
3075157642Sps	DBPRINT(sc, BCE_INFO_RESET, "Loading COM firmware.\n");
3076157642Sps	bce_load_cpu_fw(sc, &cpu_reg, &fw);
3077157642Sps}
3078157642Sps
3079157642Sps
3080157642Sps/****************************************************************************/
3081157642Sps/* Initialize context memory.                                               */
3082157642Sps/*                                                                          */
3083157642Sps/* Clears the memory associated with each Context ID (CID).                 */
3084157642Sps/*                                                                          */
3085157642Sps/* Returns:                                                                 */
3086157642Sps/*   Nothing.                                                               */
3087157642Sps/****************************************************************************/
3088157642Spsstatic void
3089157642Spsbce_init_context(struct bce_softc *sc)
3090157642Sps{
3091157642Sps	u32 vcid;
3092157642Sps
3093157642Sps	vcid = 96;
3094157642Sps	while (vcid) {
3095157642Sps		u32 vcid_addr, pcid_addr, offset;
3096157642Sps
3097157642Sps		vcid--;
3098157642Sps
3099157642Sps   		vcid_addr = GET_CID_ADDR(vcid);
3100157642Sps		pcid_addr = vcid_addr;
3101157642Sps
3102157642Sps		REG_WR(sc, BCE_CTX_VIRT_ADDR, 0x00);
3103157642Sps		REG_WR(sc, BCE_CTX_PAGE_TBL, pcid_addr);
3104157642Sps
3105157642Sps		/* Zero out the context. */
3106157642Sps		for (offset = 0; offset < PHY_CTX_SIZE; offset += 4) {
3107157642Sps			CTX_WR(sc, 0x00, offset, 0);
3108157642Sps		}
3109157642Sps
3110157642Sps		REG_WR(sc, BCE_CTX_VIRT_ADDR, vcid_addr);
3111157642Sps		REG_WR(sc, BCE_CTX_PAGE_TBL, pcid_addr);
3112157642Sps	}
3113157642Sps}
3114157642Sps
3115157642Sps
3116157642Sps/****************************************************************************/
3117157642Sps/* Fetch the permanent MAC address of the controller.                       */
3118157642Sps/*                                                                          */
3119157642Sps/* Returns:                                                                 */
3120157642Sps/*   Nothing.                                                               */
3121157642Sps/****************************************************************************/
3122157642Spsstatic void
3123157642Spsbce_get_mac_addr(struct bce_softc *sc)
3124157642Sps{
3125157642Sps	u32 mac_lo = 0, mac_hi = 0;
3126157642Sps
3127157642Sps	/*
3128157642Sps	 * The NetXtreme II bootcode populates various NIC
3129157642Sps	 * power-on and runtime configuration items in a
3130157642Sps	 * shared memory area.  The factory configured MAC
3131157642Sps	 * address is available from both NVRAM and the
3132157642Sps	 * shared memory area so we'll read the value from
3133157642Sps	 * shared memory for speed.
3134157642Sps	 */
3135157642Sps
3136157642Sps	mac_hi = REG_RD_IND(sc, sc->bce_shmem_base +
3137157642Sps		BCE_PORT_HW_CFG_MAC_UPPER);
3138157642Sps	mac_lo = REG_RD_IND(sc, sc->bce_shmem_base +
3139157642Sps		BCE_PORT_HW_CFG_MAC_LOWER);
3140157642Sps
3141157642Sps	if ((mac_lo == 0) && (mac_hi == 0)) {
3142157642Sps		BCE_PRINTF(sc, "%s(%d): Invalid Ethernet address!\n",
3143157642Sps			__FILE__, __LINE__);
3144157642Sps	} else {
3145157642Sps		sc->eaddr[0] = (u_char)(mac_hi >> 8);
3146157642Sps		sc->eaddr[1] = (u_char)(mac_hi >> 0);
3147157642Sps		sc->eaddr[2] = (u_char)(mac_lo >> 24);
3148157642Sps		sc->eaddr[3] = (u_char)(mac_lo >> 16);
3149157642Sps		sc->eaddr[4] = (u_char)(mac_lo >> 8);
3150157642Sps		sc->eaddr[5] = (u_char)(mac_lo >> 0);
3151157642Sps	}
3152157642Sps
3153157642Sps	DBPRINT(sc, BCE_INFO, "Permanent Ethernet address = %6D\n", sc->eaddr, ":");
3154157642Sps}
3155157642Sps
3156157642Sps
3157157642Sps/****************************************************************************/
3158157642Sps/* Program the MAC address.                                                 */
3159157642Sps/*                                                                          */
3160157642Sps/* Returns:                                                                 */
3161157642Sps/*   Nothing.                                                               */
3162157642Sps/****************************************************************************/
3163157642Spsstatic void
3164157642Spsbce_set_mac_addr(struct bce_softc *sc)
3165157642Sps{
3166157642Sps	u32 val;
3167157642Sps	u8 *mac_addr = sc->eaddr;
3168157642Sps
3169157642Sps	DBPRINT(sc, BCE_INFO, "Setting Ethernet address = %6D\n", sc->eaddr, ":");
3170157642Sps
3171157642Sps	val = (mac_addr[0] << 8) | mac_addr[1];
3172157642Sps
3173157642Sps	REG_WR(sc, BCE_EMAC_MAC_MATCH0, val);
3174157642Sps
3175157642Sps	val = (mac_addr[2] << 24) | (mac_addr[3] << 16) |
3176157642Sps		(mac_addr[4] << 8) | mac_addr[5];
3177157642Sps
3178157642Sps	REG_WR(sc, BCE_EMAC_MAC_MATCH1, val);
3179157642Sps}
3180157642Sps
3181157642Sps
3182157642Sps/****************************************************************************/
3183157642Sps/* Stop the controller.                                                     */
3184157642Sps/*                                                                          */
3185157642Sps/* Returns:                                                                 */
3186157642Sps/*   Nothing.                                                               */
3187157642Sps/****************************************************************************/
3188157642Spsstatic void
3189157642Spsbce_stop(struct bce_softc *sc)
3190157642Sps{
3191157642Sps	struct ifnet *ifp;
3192157642Sps	struct ifmedia_entry *ifm;
3193157642Sps	struct mii_data *mii = NULL;
3194157642Sps	int mtmp, itmp;
3195157642Sps
3196157642Sps	DBPRINT(sc, BCE_VERBOSE_RESET, "Entering %s()\n", __FUNCTION__);
3197157642Sps
3198157642Sps	BCE_LOCK_ASSERT(sc);
3199157642Sps
3200157642Sps	ifp = sc->bce_ifp;
3201157642Sps
3202157642Sps	mii = device_get_softc(sc->bce_miibus);
3203157642Sps
3204157642Sps	callout_stop(&sc->bce_stat_ch);
3205157642Sps
3206157642Sps	/* Disable the transmit/receive blocks. */
3207157642Sps	REG_WR(sc, BCE_MISC_ENABLE_CLR_BITS, 0x5ffffff);
3208157642Sps	REG_RD(sc, BCE_MISC_ENABLE_CLR_BITS);
3209157642Sps	DELAY(20);
3210157642Sps
3211157642Sps	bce_disable_intr(sc);
3212157642Sps
3213157642Sps	/* Tell firmware that the driver is going away. */
3214157642Sps	bce_reset(sc, BCE_DRV_MSG_CODE_SUSPEND_NO_WOL);
3215157642Sps
3216157642Sps	/* Free the RX lists. */
3217157642Sps	bce_free_rx_chain(sc);
3218157642Sps
3219157642Sps	/* Free TX buffers. */
3220157642Sps	bce_free_tx_chain(sc);
3221157642Sps
3222157642Sps	/*
3223157642Sps	 * Isolate/power down the PHY, but leave the media selection
3224157642Sps	 * unchanged so that things will be put back to normal when
3225157642Sps	 * we bring the interface back up.
3226157642Sps	 */
3227157642Sps
3228157642Sps	itmp = ifp->if_flags;
3229157642Sps	ifp->if_flags |= IFF_UP;
3230157642Sps	/*
3231157642Sps	 * If we are called from bce_detach(), mii is already NULL.
3232157642Sps	 */
3233157642Sps	if (mii != NULL) {
3234157642Sps		ifm = mii->mii_media.ifm_cur;
3235157642Sps		mtmp = ifm->ifm_media;
3236157642Sps		ifm->ifm_media = IFM_ETHER | IFM_NONE;
3237157642Sps		mii_mediachg(mii);
3238157642Sps		ifm->ifm_media = mtmp;
3239157642Sps	}
3240157642Sps
3241157642Sps	ifp->if_flags = itmp;
3242157642Sps	ifp->if_timer = 0;
3243157642Sps
3244157642Sps	sc->bce_link = 0;
3245157642Sps
3246157642Sps	ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
3247157642Sps
3248157642Sps	DBPRINT(sc, BCE_VERBOSE_RESET, "Exiting %s()\n", __FUNCTION__);
3249157642Sps
3250162474Sambrisko	bce_mgmt_init_locked(sc);
3251157642Sps}
3252157642Sps
3253157642Sps
3254157642Spsstatic int
3255157642Spsbce_reset(struct bce_softc *sc, u32 reset_code)
3256157642Sps{
3257157642Sps	u32 val;
3258157642Sps	int i, rc = 0;
3259157642Sps
3260157642Sps	DBPRINT(sc, BCE_VERBOSE_RESET, "Entering %s()\n", __FUNCTION__);
3261157642Sps
3262157642Sps	/* Wait for pending PCI transactions to complete. */
3263157642Sps	REG_WR(sc, BCE_MISC_ENABLE_CLR_BITS,
3264157642Sps	       BCE_MISC_ENABLE_CLR_BITS_TX_DMA_ENABLE |
3265157642Sps	       BCE_MISC_ENABLE_CLR_BITS_DMA_ENGINE_ENABLE |
3266157642Sps	       BCE_MISC_ENABLE_CLR_BITS_RX_DMA_ENABLE |
3267157642Sps	       BCE_MISC_ENABLE_CLR_BITS_HOST_COALESCE_ENABLE);
3268157642Sps	val = REG_RD(sc, BCE_MISC_ENABLE_CLR_BITS);
3269157642Sps	DELAY(5);
3270157642Sps
3271157642Sps	/* Assume bootcode is running. */
3272157642Sps	sc->bce_fw_timed_out = 0;
3273157642Sps
3274157642Sps	/* Give the firmware a chance to prepare for the reset. */
3275157642Sps	rc = bce_fw_sync(sc, BCE_DRV_MSG_DATA_WAIT0 | reset_code);
3276157642Sps	if (rc)
3277157642Sps		goto bce_reset_exit;
3278157642Sps
3279157642Sps	/* Set a firmware reminder that this is a soft reset. */
3280157642Sps	REG_WR_IND(sc, sc->bce_shmem_base + BCE_DRV_RESET_SIGNATURE,
3281157642Sps		   BCE_DRV_RESET_SIGNATURE_MAGIC);
3282157642Sps
3283157642Sps	/* Dummy read to force the chip to complete all current transactions. */
3284157642Sps	val = REG_RD(sc, BCE_MISC_ID);
3285157642Sps
3286157642Sps	/* Chip reset. */
3287157642Sps	val = BCE_PCICFG_MISC_CONFIG_CORE_RST_REQ |
3288157642Sps	      BCE_PCICFG_MISC_CONFIG_REG_WINDOW_ENA |
3289157642Sps	      BCE_PCICFG_MISC_CONFIG_TARGET_MB_WORD_SWAP;
3290157642Sps	REG_WR(sc, BCE_PCICFG_MISC_CONFIG, val);
3291157642Sps
3292157642Sps	/* Allow up to 30us for reset to complete. */
3293157642Sps	for (i = 0; i < 10; i++) {
3294157642Sps		val = REG_RD(sc, BCE_PCICFG_MISC_CONFIG);
3295157642Sps		if ((val & (BCE_PCICFG_MISC_CONFIG_CORE_RST_REQ |
3296157642Sps			    BCE_PCICFG_MISC_CONFIG_CORE_RST_BSY)) == 0) {
3297157642Sps			break;
3298157642Sps		}
3299157642Sps		DELAY(10);
3300157642Sps	}
3301157642Sps
3302157642Sps	/* Check that reset completed successfully. */
3303157642Sps	if (val & (BCE_PCICFG_MISC_CONFIG_CORE_RST_REQ |
3304157642Sps		   BCE_PCICFG_MISC_CONFIG_CORE_RST_BSY)) {
3305157642Sps		BCE_PRINTF(sc, "%s(%d): Reset failed!\n",
3306157642Sps			__FILE__, __LINE__);
3307157642Sps		rc = EBUSY;
3308157642Sps		goto bce_reset_exit;
3309157642Sps	}
3310157642Sps
3311157642Sps	/* Make sure byte swapping is properly configured. */
3312157642Sps	val = REG_RD(sc, BCE_PCI_SWAP_DIAG0);
3313157642Sps	if (val != 0x01020304) {
3314157642Sps		BCE_PRINTF(sc, "%s(%d): Byte swap is incorrect!\n",
3315157642Sps			__FILE__, __LINE__);
3316157642Sps		rc = ENODEV;
3317157642Sps		goto bce_reset_exit;
3318157642Sps	}
3319157642Sps
3320157642Sps	/* Just completed a reset, assume that firmware is running again. */
3321157642Sps	sc->bce_fw_timed_out = 0;
3322157642Sps
3323157642Sps	/* Wait for the firmware to finish its initialization. */
3324157642Sps	rc = bce_fw_sync(sc, BCE_DRV_MSG_DATA_WAIT1 | reset_code);
3325157642Sps	if (rc)
3326157642Sps		BCE_PRINTF(sc, "%s(%d): Firmware did not complete initialization!\n",
3327157642Sps			__FILE__, __LINE__);
3328157642Sps
3329157642Spsbce_reset_exit:
3330157642Sps	DBPRINT(sc, BCE_VERBOSE_RESET, "Exiting %s()\n", __FUNCTION__);
3331157642Sps
3332157642Sps	return (rc);
3333157642Sps}
3334157642Sps
3335157642Sps
3336157642Spsstatic int
3337157642Spsbce_chipinit(struct bce_softc *sc)
3338157642Sps{
3339157642Sps	u32 val;
3340157642Sps	int rc = 0;
3341157642Sps
3342157642Sps	DBPRINT(sc, BCE_VERBOSE_RESET, "Entering %s()\n", __FUNCTION__);
3343157642Sps
3344157642Sps	/* Make sure the interrupt is not active. */
3345157642Sps	REG_WR(sc, BCE_PCICFG_INT_ACK_CMD, BCE_PCICFG_INT_ACK_CMD_MASK_INT);
3346157642Sps
3347157642Sps	/* Initialize DMA byte/word swapping, configure the number of DMA  */
3348157642Sps	/* channels and PCI clock compensation delay.                      */
3349157642Sps	val = BCE_DMA_CONFIG_DATA_BYTE_SWAP |
3350157642Sps	      BCE_DMA_CONFIG_DATA_WORD_SWAP |
3351157642Sps#if BYTE_ORDER == BIG_ENDIAN
3352157642Sps	      BCE_DMA_CONFIG_CNTL_BYTE_SWAP |
3353157642Sps#endif
3354157642Sps	      BCE_DMA_CONFIG_CNTL_WORD_SWAP |
3355157642Sps	      DMA_READ_CHANS << 12 |
3356157642Sps	      DMA_WRITE_CHANS << 16;
3357157642Sps
3358157642Sps	val |= (0x2 << 20) | BCE_DMA_CONFIG_CNTL_PCI_COMP_DLY;
3359157642Sps
3360157642Sps	if ((sc->bce_flags & BCE_PCIX_FLAG) && (sc->bus_speed_mhz == 133))
3361157642Sps		val |= BCE_DMA_CONFIG_PCI_FAST_CLK_CMP;
3362157642Sps
3363157642Sps	/*
3364157642Sps	 * This setting resolves a problem observed on certain Intel PCI
3365157642Sps	 * chipsets that cannot handle multiple outstanding DMA operations.
3366157642Sps	 * See errata E9_5706A1_65.
3367157642Sps	 */
3368157642Sps	if ((BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5706) &&
3369157642Sps	    (BCE_CHIP_ID(sc) != BCE_CHIP_ID_5706_A0) &&
3370157642Sps	    !(sc->bce_flags & BCE_PCIX_FLAG))
3371157642Sps		val |= BCE_DMA_CONFIG_CNTL_PING_PONG_DMA;
3372157642Sps
3373157642Sps	REG_WR(sc, BCE_DMA_CONFIG, val);
3374157642Sps
3375157642Sps	/* Clear the PCI-X relaxed ordering bit. See errata E3_5708CA0_570. */
3376157642Sps	if (sc->bce_flags & BCE_PCIX_FLAG) {
3377157642Sps		u16 val;
3378157642Sps
3379157642Sps		val = pci_read_config(sc->bce_dev, BCE_PCI_PCIX_CMD, 2);
3380157642Sps		pci_write_config(sc->bce_dev, BCE_PCI_PCIX_CMD, val & ~0x2, 2);
3381157642Sps	}
3382157642Sps
3383157642Sps	/* Enable the RX_V2P and Context state machines before access. */
3384157642Sps	REG_WR(sc, BCE_MISC_ENABLE_SET_BITS,
3385157642Sps	       BCE_MISC_ENABLE_SET_BITS_HOST_COALESCE_ENABLE |
3386157642Sps	       BCE_MISC_ENABLE_STATUS_BITS_RX_V2P_ENABLE |
3387157642Sps	       BCE_MISC_ENABLE_STATUS_BITS_CONTEXT_ENABLE);
3388157642Sps
3389157642Sps	/* Initialize context mapping and zero out the quick contexts. */
3390157642Sps	bce_init_context(sc);
3391157642Sps
3392157642Sps	/* Initialize the on-boards CPUs */
3393157642Sps	bce_init_cpus(sc);
3394157642Sps
3395157642Sps	/* Prepare NVRAM for access. */
3396157642Sps	if (bce_init_nvram(sc)) {
3397157642Sps		rc = ENODEV;
3398157642Sps		goto bce_chipinit_exit;
3399157642Sps	}
3400157642Sps
3401157642Sps	/* Set the kernel bypass block size */
3402157642Sps	val = REG_RD(sc, BCE_MQ_CONFIG);
3403157642Sps	val &= ~BCE_MQ_CONFIG_KNL_BYP_BLK_SIZE;
3404157642Sps	val |= BCE_MQ_CONFIG_KNL_BYP_BLK_SIZE_256;
3405157642Sps	REG_WR(sc, BCE_MQ_CONFIG, val);
3406157642Sps
3407157642Sps	val = 0x10000 + (MAX_CID_CNT * MB_KERNEL_CTX_SIZE);
3408157642Sps	REG_WR(sc, BCE_MQ_KNL_BYP_WIND_START, val);
3409157642Sps	REG_WR(sc, BCE_MQ_KNL_WIND_END, val);
3410157642Sps
3411157642Sps	val = (BCM_PAGE_BITS - 8) << 24;
3412157642Sps	REG_WR(sc, BCE_RV2P_CONFIG, val);
3413157642Sps
3414157642Sps	/* Configure page size. */
3415157642Sps	val = REG_RD(sc, BCE_TBDR_CONFIG);
3416157642Sps	val &= ~BCE_TBDR_CONFIG_PAGE_SIZE;
3417157642Sps	val |= (BCM_PAGE_BITS - 8) << 24 | 0x40;
3418157642Sps	REG_WR(sc, BCE_TBDR_CONFIG, val);
3419157642Sps
3420157642Spsbce_chipinit_exit:
3421157642Sps	DBPRINT(sc, BCE_VERBOSE_RESET, "Exiting %s()\n", __FUNCTION__);
3422157642Sps
3423157642Sps	return(rc);
3424157642Sps}
3425157642Sps
3426157642Sps
3427157642Sps/****************************************************************************/
3428157642Sps/* Initialize the controller in preparation to send/receive traffic.        */
3429157642Sps/*                                                                          */
3430157642Sps/* Returns:                                                                 */
3431157642Sps/*   0 for success, positive value for failure.                             */
3432157642Sps/****************************************************************************/
3433157642Spsstatic int
3434157642Spsbce_blockinit(struct bce_softc *sc)
3435157642Sps{
3436157642Sps	u32 reg, val;
3437157642Sps	int rc = 0;
3438157642Sps
3439157642Sps	DBPRINT(sc, BCE_VERBOSE_RESET, "Entering %s()\n", __FUNCTION__);
3440157642Sps
3441157642Sps	/* Load the hardware default MAC address. */
3442157642Sps	bce_set_mac_addr(sc);
3443157642Sps
3444157642Sps	/* Set the Ethernet backoff seed value */
3445157642Sps	val = sc->eaddr[0]         + (sc->eaddr[1] << 8) +
3446157642Sps	      (sc->eaddr[2] << 16) + (sc->eaddr[3]     ) +
3447157642Sps	      (sc->eaddr[4] << 8)  + (sc->eaddr[5] << 16);
3448157642Sps	REG_WR(sc, BCE_EMAC_BACKOFF_SEED, val);
3449157642Sps
3450157642Sps	sc->last_status_idx = 0;
3451157642Sps	sc->rx_mode = BCE_EMAC_RX_MODE_SORT_MODE;
3452157642Sps
3453157642Sps	/* Set up link change interrupt generation. */
3454157642Sps	REG_WR(sc, BCE_EMAC_ATTENTION_ENA, BCE_EMAC_ATTENTION_ENA_LINK);
3455157642Sps
3456157642Sps	/* Program the physical address of the status block. */
3457157642Sps	REG_WR(sc, BCE_HC_STATUS_ADDR_L,
3458157642Sps		BCE_ADDR_LO(sc->status_block_paddr));
3459157642Sps	REG_WR(sc, BCE_HC_STATUS_ADDR_H,
3460157642Sps		BCE_ADDR_HI(sc->status_block_paddr));
3461157642Sps
3462157642Sps	/* Program the physical address of the statistics block. */
3463157642Sps	REG_WR(sc, BCE_HC_STATISTICS_ADDR_L,
3464157642Sps		BCE_ADDR_LO(sc->stats_block_paddr));
3465157642Sps	REG_WR(sc, BCE_HC_STATISTICS_ADDR_H,
3466157642Sps		BCE_ADDR_HI(sc->stats_block_paddr));
3467157642Sps
3468157642Sps	/* Program various host coalescing parameters. */
3469157642Sps	REG_WR(sc, BCE_HC_TX_QUICK_CONS_TRIP,
3470157642Sps		(sc->bce_tx_quick_cons_trip_int << 16) | sc->bce_tx_quick_cons_trip);
3471157642Sps	REG_WR(sc, BCE_HC_RX_QUICK_CONS_TRIP,
3472157642Sps		(sc->bce_rx_quick_cons_trip_int << 16) | sc->bce_rx_quick_cons_trip);
3473157642Sps	REG_WR(sc, BCE_HC_COMP_PROD_TRIP,
3474157642Sps		(sc->bce_comp_prod_trip_int << 16) | sc->bce_comp_prod_trip);
3475157642Sps	REG_WR(sc, BCE_HC_TX_TICKS,
3476157642Sps		(sc->bce_tx_ticks_int << 16) | sc->bce_tx_ticks);
3477157642Sps	REG_WR(sc, BCE_HC_RX_TICKS,
3478157642Sps		(sc->bce_rx_ticks_int << 16) | sc->bce_rx_ticks);
3479157642Sps	REG_WR(sc, BCE_HC_COM_TICKS,
3480157642Sps		(sc->bce_com_ticks_int << 16) | sc->bce_com_ticks);
3481157642Sps	REG_WR(sc, BCE_HC_CMD_TICKS,
3482157642Sps		(sc->bce_cmd_ticks_int << 16) | sc->bce_cmd_ticks);
3483157642Sps	REG_WR(sc, BCE_HC_STATS_TICKS,
3484157642Sps		(sc->bce_stats_ticks & 0xffff00));
3485157642Sps	REG_WR(sc, BCE_HC_STAT_COLLECT_TICKS,
3486157642Sps		0xbb8);  /* 3ms */
3487157642Sps	REG_WR(sc, BCE_HC_CONFIG,
3488157642Sps		(BCE_HC_CONFIG_RX_TMR_MODE | BCE_HC_CONFIG_TX_TMR_MODE |
3489157642Sps		BCE_HC_CONFIG_COLLECT_STATS));
3490157642Sps
3491157642Sps	/* Clear the internal statistics counters. */
3492157642Sps	REG_WR(sc, BCE_HC_COMMAND, BCE_HC_COMMAND_CLR_STAT_NOW);
3493157642Sps
3494157642Sps	/* Verify that bootcode is running. */
3495157642Sps	reg = REG_RD_IND(sc, sc->bce_shmem_base + BCE_DEV_INFO_SIGNATURE);
3496157642Sps
3497157642Sps	DBRUNIF(DB_RANDOMTRUE(bce_debug_bootcode_running_failure),
3498157642Sps		BCE_PRINTF(sc, "%s(%d): Simulating bootcode failure.\n",
3499157642Sps			__FILE__, __LINE__);
3500157642Sps		reg = 0);
3501157642Sps
3502157642Sps	if ((reg & BCE_DEV_INFO_SIGNATURE_MAGIC_MASK) !=
3503157642Sps	    BCE_DEV_INFO_SIGNATURE_MAGIC) {
3504157642Sps		BCE_PRINTF(sc, "%s(%d): Bootcode not running! Found: 0x%08X, "
3505157642Sps			"Expected: 08%08X\n", __FILE__, __LINE__,
3506157642Sps			(reg & BCE_DEV_INFO_SIGNATURE_MAGIC_MASK),
3507157642Sps			BCE_DEV_INFO_SIGNATURE_MAGIC);
3508157642Sps		rc = ENODEV;
3509157642Sps		goto bce_blockinit_exit;
3510157642Sps	}
3511157642Sps
3512157642Sps	/* Check if any management firmware is running. */
3513157642Sps	reg = REG_RD_IND(sc, sc->bce_shmem_base + BCE_PORT_FEATURE);
3514157642Sps	if (reg & (BCE_PORT_FEATURE_ASF_ENABLED | BCE_PORT_FEATURE_IMD_ENABLED)) {
3515157642Sps		DBPRINT(sc, BCE_INFO, "Management F/W Enabled.\n");
3516157642Sps		sc->bce_flags |= BCE_MFW_ENABLE_FLAG;
3517157642Sps	}
3518157642Sps
3519157642Sps	sc->bce_fw_ver = REG_RD_IND(sc, sc->bce_shmem_base + BCE_DEV_INFO_BC_REV);
3520157642Sps	DBPRINT(sc, BCE_INFO, "bootcode rev = 0x%08X\n", sc->bce_fw_ver);
3521157642Sps
3522157642Sps	/* Allow bootcode to apply any additional fixes before enabling MAC. */
3523157642Sps	rc = bce_fw_sync(sc, BCE_DRV_MSG_DATA_WAIT2 | BCE_DRV_MSG_CODE_RESET);
3524157642Sps
3525157642Sps	/* Enable link state change interrupt generation. */
3526157642Sps	REG_WR(sc, BCE_HC_ATTN_BITS_ENABLE, STATUS_ATTN_BITS_LINK_STATE);
3527157642Sps
3528157642Sps	/* Enable all remaining blocks in the MAC. */
3529157642Sps	REG_WR(sc, BCE_MISC_ENABLE_SET_BITS, 0x5ffffff);
3530157642Sps	REG_RD(sc, BCE_MISC_ENABLE_SET_BITS);
3531157642Sps	DELAY(20);
3532157642Sps
3533157642Spsbce_blockinit_exit:
3534157642Sps	DBPRINT(sc, BCE_VERBOSE_RESET, "Exiting %s()\n", __FUNCTION__);
3535157642Sps
3536157642Sps	return (rc);
3537157642Sps}
3538157642Sps
3539157642Sps
3540157642Sps/****************************************************************************/
3541157642Sps/* Encapsulate an mbuf cluster into the rx_bd chain.                        */
3542157642Sps/*                                                                          */
3543157642Sps/* The NetXtreme II can support Jumbo frames by using multiple rx_bd's.     */
3544157642Sps/* This routine will map an mbuf cluster into 1 or more rx_bd's as          */
3545157642Sps/* necessary.                                                               */
3546157642Sps/*                                                                          */
3547157642Sps/* Returns:                                                                 */
3548157642Sps/*   0 for success, positive value for failure.                             */
3549157642Sps/****************************************************************************/
3550157642Spsstatic int
3551157642Spsbce_get_buf(struct bce_softc *sc, struct mbuf *m, u16 *prod, u16 *chain_prod,
3552157642Sps	u32 *prod_bseq)
3553157642Sps{
3554157642Sps	bus_dmamap_t		map;
3555157642Sps	bus_dma_segment_t	segs[4];
3556157642Sps	struct mbuf *m_new = NULL;
3557157642Sps	struct rx_bd		*rxbd;
3558157642Sps	int i, nsegs, error, rc = 0;
3559157642Sps#ifdef BCE_DEBUG
3560157642Sps	u16 debug_chain_prod = *chain_prod;
3561157642Sps#endif
3562157642Sps
3563157642Sps	DBPRINT(sc, (BCE_VERBOSE_RESET | BCE_VERBOSE_RECV), "Entering %s()\n",
3564157642Sps		__FUNCTION__);
3565157642Sps
3566157642Sps	/* Make sure the inputs are valid. */
3567157642Sps	DBRUNIF((*chain_prod > MAX_RX_BD),
3568157642Sps		BCE_PRINTF(sc, "%s(%d): RX producer out of range: 0x%04X > 0x%04X\n",
3569157642Sps		__FILE__, __LINE__, *chain_prod, (u16) MAX_RX_BD));
3570157642Sps
3571157642Sps	DBPRINT(sc, BCE_VERBOSE_RECV, "%s(enter): prod = 0x%04X, chain_prod = 0x%04X, "
3572157642Sps		"prod_bseq = 0x%08X\n", __FUNCTION__, *prod, *chain_prod, *prod_bseq);
3573157642Sps
3574157642Sps	if (m == NULL) {
3575157642Sps
3576157642Sps		DBRUNIF(DB_RANDOMTRUE(bce_debug_mbuf_allocation_failure),
3577157642Sps			BCE_PRINTF(sc, "%s(%d): Simulating mbuf allocation failure.\n",
3578157642Sps				__FILE__, __LINE__);
3579157642Sps			sc->mbuf_alloc_failed++;
3580157642Sps			rc = ENOBUFS;
3581157642Sps			goto bce_get_buf_exit);
3582157642Sps
3583157642Sps		/* This is a new mbuf allocation. */
3584157642Sps		MGETHDR(m_new, M_DONTWAIT, MT_DATA);
3585157642Sps		if (m_new == NULL) {
3586157642Sps
3587157642Sps			DBPRINT(sc, BCE_WARN, "%s(%d): RX mbuf header allocation failed!\n",
3588157642Sps				__FILE__, __LINE__);
3589157642Sps
3590157642Sps			DBRUNIF(1, sc->mbuf_alloc_failed++);
3591157642Sps
3592157642Sps			rc = ENOBUFS;
3593157642Sps			goto bce_get_buf_exit;
3594157642Sps		}
3595157642Sps
3596157642Sps		DBRUNIF(1, sc->rx_mbuf_alloc++);
3597157642Sps		m_cljget(m_new, M_DONTWAIT, sc->mbuf_alloc_size);
3598157642Sps		if (!(m_new->m_flags & M_EXT)) {
3599157642Sps
3600157642Sps			DBPRINT(sc, BCE_WARN, "%s(%d): RX mbuf chain allocation failed!\n",
3601157642Sps				__FILE__, __LINE__);
3602157642Sps
3603157642Sps			m_freem(m_new);
3604157642Sps
3605157642Sps			DBRUNIF(1, sc->rx_mbuf_alloc--);
3606157642Sps			DBRUNIF(1, sc->mbuf_alloc_failed++);
3607157642Sps
3608157642Sps			rc = ENOBUFS;
3609157642Sps			goto bce_get_buf_exit;
3610157642Sps		}
3611157642Sps
3612157642Sps		m_new->m_len = m_new->m_pkthdr.len = sc->mbuf_alloc_size;
3613157642Sps	} else {
3614157642Sps		m_new = m;
3615157642Sps		m_new->m_len = m_new->m_pkthdr.len = sc->mbuf_alloc_size;
3616157642Sps		m_new->m_data = m_new->m_ext.ext_buf;
3617157642Sps	}
3618157642Sps
3619157642Sps	/* Map the mbuf cluster into device memory. */
3620157642Sps	map = sc->rx_mbuf_map[*chain_prod];
3621157642Sps	error = bus_dmamap_load_mbuf_sg(sc->rx_mbuf_tag, map, m_new,
3622157642Sps	    segs, &nsegs, BUS_DMA_NOWAIT);
3623157642Sps
3624157642Sps	if (error) {
3625157642Sps		BCE_PRINTF(sc, "%s(%d): Error mapping mbuf into RX chain!\n",
3626157642Sps			__FILE__, __LINE__);
3627157642Sps
3628157642Sps		m_freem(m_new);
3629157642Sps
3630157642Sps		DBRUNIF(1, sc->rx_mbuf_alloc--);
3631157642Sps
3632157642Sps		rc = ENOBUFS;
3633157642Sps		goto bce_get_buf_exit;
3634157642Sps	}
3635157642Sps
3636157642Sps	/* Watch for overflow. */
3637157642Sps	DBRUNIF((sc->free_rx_bd > USABLE_RX_BD),
3638157642Sps		BCE_PRINTF(sc, "%s(%d): Too many free rx_bd (0x%04X > 0x%04X)!\n",
3639157642Sps			__FILE__, __LINE__, sc->free_rx_bd, (u16) USABLE_RX_BD));
3640157642Sps
3641157642Sps	DBRUNIF((sc->free_rx_bd < sc->rx_low_watermark),
3642157642Sps		sc->rx_low_watermark = sc->free_rx_bd);
3643157642Sps
3644157642Sps	/* Setup the rx_bd for the first segment. */
3645157642Sps	rxbd = &sc->rx_bd_chain[RX_PAGE(*chain_prod)][RX_IDX(*chain_prod)];
3646157642Sps
3647157642Sps	rxbd->rx_bd_haddr_lo  = htole32(BCE_ADDR_LO(segs[0].ds_addr));
3648157642Sps	rxbd->rx_bd_haddr_hi  = htole32(BCE_ADDR_HI(segs[0].ds_addr));
3649157642Sps	rxbd->rx_bd_len       = htole32(segs[0].ds_len);
3650157642Sps	rxbd->rx_bd_flags     = htole32(RX_BD_FLAGS_START);
3651157642Sps	*prod_bseq += segs[0].ds_len;
3652157642Sps
3653157642Sps	for (i = 1; i < nsegs; i++) {
3654157642Sps
3655157642Sps		*prod = NEXT_RX_BD(*prod);
3656157642Sps		*chain_prod = RX_CHAIN_IDX(*prod);
3657157642Sps
3658157642Sps		rxbd = &sc->rx_bd_chain[RX_PAGE(*chain_prod)][RX_IDX(*chain_prod)];
3659157642Sps
3660157642Sps		rxbd->rx_bd_haddr_lo  = htole32(BCE_ADDR_LO(segs[i].ds_addr));
3661157642Sps		rxbd->rx_bd_haddr_hi  = htole32(BCE_ADDR_HI(segs[i].ds_addr));
3662157642Sps		rxbd->rx_bd_len       = htole32(segs[i].ds_len);
3663157642Sps		rxbd->rx_bd_flags     = 0;
3664157642Sps		*prod_bseq += segs[i].ds_len;
3665157642Sps	}
3666157642Sps
3667157642Sps	rxbd->rx_bd_flags |= htole32(RX_BD_FLAGS_END);
3668157642Sps
3669157642Sps	/* Save the mbuf and update our counter. */
3670157642Sps	sc->rx_mbuf_ptr[*chain_prod] = m_new;
3671157642Sps	sc->free_rx_bd -= nsegs;
3672157642Sps
3673157642Sps	DBRUN(BCE_VERBOSE_RECV, bce_dump_rx_mbuf_chain(sc, debug_chain_prod,
3674157642Sps		nsegs));
3675157642Sps
3676157642Sps	DBPRINT(sc, BCE_VERBOSE_RECV, "%s(exit): prod = 0x%04X, chain_prod = 0x%04X, "
3677157642Sps		"prod_bseq = 0x%08X\n", __FUNCTION__, *prod, *chain_prod, *prod_bseq);
3678157642Sps
3679157642Spsbce_get_buf_exit:
3680157642Sps	DBPRINT(sc, (BCE_VERBOSE_RESET | BCE_VERBOSE_RECV), "Exiting %s()\n",
3681157642Sps		__FUNCTION__);
3682157642Sps
3683157642Sps	return(rc);
3684157642Sps}
3685157642Sps
3686157642Sps
3687157642Sps/****************************************************************************/
3688157642Sps/* Allocate memory and initialize the TX data structures.                   */
3689157642Sps/*                                                                          */
3690157642Sps/* Returns:                                                                 */
3691157642Sps/*   0 for success, positive value for failure.                             */
3692157642Sps/****************************************************************************/
3693157642Spsstatic int
3694157642Spsbce_init_tx_chain(struct bce_softc *sc)
3695157642Sps{
3696157642Sps	struct tx_bd *txbd;
3697157642Sps	u32 val;
3698157642Sps	int i, rc = 0;
3699157642Sps
3700157642Sps	DBPRINT(sc, BCE_VERBOSE_RESET, "Entering %s()\n", __FUNCTION__);
3701157642Sps
3702157642Sps	/* Set the initial TX producer/consumer indices. */
3703157642Sps	sc->tx_prod        = 0;
3704157642Sps	sc->tx_cons        = 0;
3705157642Sps	sc->tx_prod_bseq   = 0;
3706157642Sps	sc->used_tx_bd = 0;
3707157642Sps	DBRUNIF(1, sc->tx_hi_watermark = USABLE_TX_BD);
3708157642Sps
3709157642Sps	/*
3710157642Sps	 * The NetXtreme II supports a linked-list structre called
3711157642Sps	 * a Buffer Descriptor Chain (or BD chain).  A BD chain
3712157642Sps	 * consists of a series of 1 or more chain pages, each of which
3713157642Sps	 * consists of a fixed number of BD entries.
3714157642Sps	 * The last BD entry on each page is a pointer to the next page
3715157642Sps	 * in the chain, and the last pointer in the BD chain
3716157642Sps	 * points back to the beginning of the chain.
3717157642Sps	 */
3718157642Sps
3719157642Sps	/* Set the TX next pointer chain entries. */
3720157642Sps	for (i = 0; i < TX_PAGES; i++) {
3721157642Sps		int j;
3722157642Sps
3723157642Sps		txbd = &sc->tx_bd_chain[i][USABLE_TX_BD_PER_PAGE];
3724157642Sps
3725157642Sps		/* Check if we've reached the last page. */
3726157642Sps		if (i == (TX_PAGES - 1))
3727157642Sps			j = 0;
3728157642Sps		else
3729157642Sps			j = i + 1;
3730157642Sps
3731157642Sps		txbd->tx_bd_haddr_hi = htole32(BCE_ADDR_HI(sc->tx_bd_chain_paddr[j]));
3732157642Sps		txbd->tx_bd_haddr_lo = htole32(BCE_ADDR_LO(sc->tx_bd_chain_paddr[j]));
3733157642Sps	}
3734157642Sps
3735157642Sps	/*
3736157642Sps	 * Initialize the context ID for an L2 TX chain.
3737157642Sps	 */
3738157642Sps	val = BCE_L2CTX_TYPE_TYPE_L2;
3739157642Sps	val |= BCE_L2CTX_TYPE_SIZE_L2;
3740157642Sps	CTX_WR(sc, GET_CID_ADDR(TX_CID), BCE_L2CTX_TYPE, val);
3741157642Sps
3742157642Sps	val = BCE_L2CTX_CMD_TYPE_TYPE_L2 | (8 << 16);
3743157642Sps	CTX_WR(sc, GET_CID_ADDR(TX_CID), BCE_L2CTX_CMD_TYPE, val);
3744157642Sps
3745157642Sps	/* Point the hardware to the first page in the chain. */
3746157642Sps	val = BCE_ADDR_HI(sc->tx_bd_chain_paddr[0]);
3747157642Sps	CTX_WR(sc, GET_CID_ADDR(TX_CID), BCE_L2CTX_TBDR_BHADDR_HI, val);
3748157642Sps	val = BCE_ADDR_LO(sc->tx_bd_chain_paddr[0]);
3749157642Sps	CTX_WR(sc, GET_CID_ADDR(TX_CID), BCE_L2CTX_TBDR_BHADDR_LO, val);
3750157642Sps
3751157642Sps	DBRUN(BCE_VERBOSE_SEND, bce_dump_tx_chain(sc, 0, TOTAL_TX_BD));
3752157642Sps
3753157642Sps	DBPRINT(sc, BCE_VERBOSE_RESET, "Exiting %s()\n", __FUNCTION__);
3754157642Sps
3755157642Sps	return(rc);
3756157642Sps}
3757157642Sps
3758157642Sps
3759157642Sps/****************************************************************************/
3760157642Sps/* Free memory and clear the TX data structures.                            */
3761157642Sps/*                                                                          */
3762157642Sps/* Returns:                                                                 */
3763157642Sps/*   Nothing.                                                               */
3764157642Sps/****************************************************************************/
3765157642Spsstatic void
3766157642Spsbce_free_tx_chain(struct bce_softc *sc)
3767157642Sps{
3768157642Sps	int i;
3769157642Sps
3770157642Sps	DBPRINT(sc, BCE_VERBOSE_RESET, "Entering %s()\n", __FUNCTION__);
3771157642Sps
3772157642Sps	/* Unmap, unload, and free any mbufs still in the TX mbuf chain. */
3773157642Sps	for (i = 0; i < TOTAL_TX_BD; i++) {
3774157642Sps		if (sc->tx_mbuf_ptr[i] != NULL) {
3775157642Sps			if (sc->tx_mbuf_map != NULL)
3776157642Sps				bus_dmamap_sync(sc->tx_mbuf_tag, sc->tx_mbuf_map[i],
3777157642Sps					BUS_DMASYNC_POSTWRITE);
3778157642Sps			m_freem(sc->tx_mbuf_ptr[i]);
3779157642Sps			sc->tx_mbuf_ptr[i] = NULL;
3780157642Sps			DBRUNIF(1, sc->tx_mbuf_alloc--);
3781157642Sps		}
3782157642Sps	}
3783157642Sps
3784157642Sps	/* Clear each TX chain page. */
3785157642Sps	for (i = 0; i < TX_PAGES; i++)
3786157642Sps		bzero((char *)sc->tx_bd_chain[i], BCE_TX_CHAIN_PAGE_SZ);
3787157642Sps
3788157642Sps	/* Check if we lost any mbufs in the process. */
3789157642Sps	DBRUNIF((sc->tx_mbuf_alloc),
3790157642Sps		BCE_PRINTF(sc, "%s(%d): Memory leak! Lost %d mbufs "
3791157642Sps			"from tx chain!\n",
3792157642Sps			__FILE__, __LINE__, sc->tx_mbuf_alloc));
3793157642Sps
3794157642Sps	DBPRINT(sc, BCE_VERBOSE_RESET, "Exiting %s()\n", __FUNCTION__);
3795157642Sps}
3796157642Sps
3797157642Sps
3798157642Sps/****************************************************************************/
3799157642Sps/* Allocate memory and initialize the RX data structures.                   */
3800157642Sps/*                                                                          */
3801157642Sps/* Returns:                                                                 */
3802157642Sps/*   0 for success, positive value for failure.                             */
3803157642Sps/****************************************************************************/
3804157642Spsstatic int
3805157642Spsbce_init_rx_chain(struct bce_softc *sc)
3806157642Sps{
3807157642Sps	struct rx_bd *rxbd;
3808157642Sps	int i, rc = 0;
3809157642Sps	u16 prod, chain_prod;
3810157642Sps	u32 prod_bseq, val;
3811157642Sps
3812157642Sps	DBPRINT(sc, BCE_VERBOSE_RESET, "Entering %s()\n", __FUNCTION__);
3813157642Sps
3814157642Sps	/* Initialize the RX producer and consumer indices. */
3815157642Sps	sc->rx_prod        = 0;
3816157642Sps	sc->rx_cons        = 0;
3817157642Sps	sc->rx_prod_bseq   = 0;
3818157642Sps	sc->free_rx_bd     = BCE_RX_SLACK_SPACE;
3819157642Sps	DBRUNIF(1, sc->rx_low_watermark = USABLE_RX_BD);
3820157642Sps
3821157642Sps	/* Initialize the RX next pointer chain entries. */
3822157642Sps	for (i = 0; i < RX_PAGES; i++) {
3823157642Sps		int j;
3824157642Sps
3825157642Sps		rxbd = &sc->rx_bd_chain[i][USABLE_RX_BD_PER_PAGE];
3826157642Sps
3827157642Sps		/* Check if we've reached the last page. */
3828157642Sps		if (i == (RX_PAGES - 1))
3829157642Sps			j = 0;
3830157642Sps		else
3831157642Sps			j = i + 1;
3832157642Sps
3833157642Sps		/* Setup the chain page pointers. */
3834157642Sps		rxbd->rx_bd_haddr_hi = htole32(BCE_ADDR_HI(sc->rx_bd_chain_paddr[j]));
3835157642Sps		rxbd->rx_bd_haddr_lo = htole32(BCE_ADDR_LO(sc->rx_bd_chain_paddr[j]));
3836157642Sps	}
3837157642Sps
3838157642Sps	/* Initialize the context ID for an L2 RX chain. */
3839157642Sps	val = BCE_L2CTX_CTX_TYPE_CTX_BD_CHN_TYPE_VALUE;
3840157642Sps	val |= BCE_L2CTX_CTX_TYPE_SIZE_L2;
3841157642Sps	val |= 0x02 << 8;
3842157642Sps	CTX_WR(sc, GET_CID_ADDR(RX_CID), BCE_L2CTX_CTX_TYPE, val);
3843157642Sps
3844157642Sps	/* Point the hardware to the first page in the chain. */
3845157642Sps	val = BCE_ADDR_HI(sc->rx_bd_chain_paddr[0]);
3846157642Sps	CTX_WR(sc, GET_CID_ADDR(RX_CID), BCE_L2CTX_NX_BDHADDR_HI, val);
3847157642Sps	val = BCE_ADDR_LO(sc->rx_bd_chain_paddr[0]);
3848157642Sps	CTX_WR(sc, GET_CID_ADDR(RX_CID), BCE_L2CTX_NX_BDHADDR_LO, val);
3849157642Sps
3850157642Sps	/* Allocate mbuf clusters for the rx_bd chain. */
3851157642Sps	prod = prod_bseq = 0;
3852157642Sps	while (prod < BCE_RX_SLACK_SPACE) {
3853157642Sps		chain_prod = RX_CHAIN_IDX(prod);
3854157642Sps		if (bce_get_buf(sc, NULL, &prod, &chain_prod, &prod_bseq)) {
3855157642Sps			BCE_PRINTF(sc, "%s(%d): Error filling RX chain: rx_bd[0x%04X]!\n",
3856157642Sps				__FILE__, __LINE__, chain_prod);
3857157642Sps			rc = ENOBUFS;
3858157642Sps			break;
3859157642Sps		}
3860157642Sps		prod = NEXT_RX_BD(prod);
3861157642Sps	}
3862157642Sps
3863157642Sps	/* Save the RX chain producer index. */
3864157642Sps	sc->rx_prod      = prod;
3865157642Sps	sc->rx_prod_bseq = prod_bseq;
3866157642Sps
3867157642Sps	for (i = 0; i < RX_PAGES; i++) {
3868157642Sps		bus_dmamap_sync(
3869157642Sps			sc->rx_bd_chain_tag,
3870157642Sps	    	sc->rx_bd_chain_map[i],
3871157642Sps		    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
3872157642Sps	}
3873157642Sps
3874157642Sps	/* Tell the chip about the waiting rx_bd's. */
3875157642Sps	REG_WR16(sc, MB_RX_CID_ADDR + BCE_L2CTX_HOST_BDIDX, sc->rx_prod);
3876157642Sps	REG_WR(sc, MB_RX_CID_ADDR + BCE_L2CTX_HOST_BSEQ, sc->rx_prod_bseq);
3877157642Sps
3878157642Sps	DBRUN(BCE_VERBOSE_RECV, bce_dump_rx_chain(sc, 0, TOTAL_RX_BD));
3879157642Sps
3880157642Sps	DBPRINT(sc, BCE_VERBOSE_RESET, "Exiting %s()\n", __FUNCTION__);
3881157642Sps
3882157642Sps	return(rc);
3883157642Sps}
3884157642Sps
3885157642Sps
3886157642Sps/****************************************************************************/
3887157642Sps/* Free memory and clear the RX data structures.                            */
3888157642Sps/*                                                                          */
3889157642Sps/* Returns:                                                                 */
3890157642Sps/*   Nothing.                                                               */
3891157642Sps/****************************************************************************/
3892157642Spsstatic void
3893157642Spsbce_free_rx_chain(struct bce_softc *sc)
3894157642Sps{
3895157642Sps	int i;
3896157642Sps
3897157642Sps	DBPRINT(sc, BCE_VERBOSE_RESET, "Entering %s()\n", __FUNCTION__);
3898157642Sps
3899157642Sps	/* Free any mbufs still in the RX mbuf chain. */
3900157642Sps	for (i = 0; i < TOTAL_RX_BD; i++) {
3901157642Sps		if (sc->rx_mbuf_ptr[i] != NULL) {
3902157642Sps			if (sc->rx_mbuf_map[i] != NULL)
3903157642Sps				bus_dmamap_sync(sc->rx_mbuf_tag, sc->rx_mbuf_map[i],
3904157642Sps					BUS_DMASYNC_POSTREAD);
3905157642Sps			m_freem(sc->rx_mbuf_ptr[i]);
3906157642Sps			sc->rx_mbuf_ptr[i] = NULL;
3907157642Sps			DBRUNIF(1, sc->rx_mbuf_alloc--);
3908157642Sps		}
3909157642Sps	}
3910157642Sps
3911157642Sps	/* Clear each RX chain page. */
3912157642Sps	for (i = 0; i < RX_PAGES; i++)
3913157642Sps		bzero((char *)sc->rx_bd_chain[i], BCE_RX_CHAIN_PAGE_SZ);
3914157642Sps
3915157642Sps	/* Check if we lost any mbufs in the process. */
3916157642Sps	DBRUNIF((sc->rx_mbuf_alloc),
3917157642Sps		BCE_PRINTF(sc, "%s(%d): Memory leak! Lost %d mbufs from rx chain!\n",
3918157642Sps			__FILE__, __LINE__, sc->rx_mbuf_alloc));
3919157642Sps
3920157642Sps	DBPRINT(sc, BCE_VERBOSE_RESET, "Exiting %s()\n", __FUNCTION__);
3921157642Sps}
3922157642Sps
3923157642Sps
3924157642Sps/****************************************************************************/
3925157642Sps/* Set media options.                                                       */
3926157642Sps/*                                                                          */
3927157642Sps/* Returns:                                                                 */
3928157642Sps/*   0 for success, positive value for failure.                             */
3929157642Sps/****************************************************************************/
3930157642Spsstatic int
3931157642Spsbce_ifmedia_upd(struct ifnet *ifp)
3932157642Sps{
3933157642Sps	struct bce_softc *sc;
3934157642Sps	struct mii_data *mii;
3935157642Sps	struct ifmedia *ifm;
3936157642Sps	int rc = 0;
3937157642Sps
3938157642Sps	sc = ifp->if_softc;
3939157642Sps	ifm = &sc->bce_ifmedia;
3940157642Sps
3941157642Sps	/* DRC - ToDo: Add SerDes support. */
3942157642Sps
3943157642Sps	mii = device_get_softc(sc->bce_miibus);
3944157642Sps	sc->bce_link = 0;
3945157642Sps	if (mii->mii_instance) {
3946157642Sps		struct mii_softc *miisc;
3947157642Sps		for (miisc = LIST_FIRST(&mii->mii_phys); miisc != NULL;
3948157642Sps		    miisc = LIST_NEXT(miisc, mii_list))
3949157642Sps			mii_phy_reset(miisc);
3950157642Sps	}
3951157642Sps	mii_mediachg(mii);
3952157642Sps
3953157642Sps	return(rc);
3954157642Sps}
3955157642Sps
3956157642Sps
3957157642Sps/****************************************************************************/
3958157642Sps/* Reports current media status.                                            */
3959157642Sps/*                                                                          */
3960157642Sps/* Returns:                                                                 */
3961157642Sps/*   Nothing.                                                               */
3962157642Sps/****************************************************************************/
3963157642Spsstatic void
3964157642Spsbce_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
3965157642Sps{
3966157642Sps	struct bce_softc *sc;
3967157642Sps	struct mii_data *mii;
3968157642Sps
3969157642Sps	sc = ifp->if_softc;
3970157642Sps
3971157642Sps	BCE_LOCK(sc);
3972157642Sps
3973157642Sps	mii = device_get_softc(sc->bce_miibus);
3974157642Sps
3975157642Sps	/* DRC - ToDo: Add SerDes support. */
3976157642Sps
3977157642Sps	mii_pollstat(mii);
3978157642Sps	ifmr->ifm_active = mii->mii_media_active;
3979157642Sps	ifmr->ifm_status = mii->mii_media_status;
3980157642Sps
3981157642Sps	BCE_UNLOCK(sc);
3982157642Sps}
3983157642Sps
3984157642Sps
3985157642Sps/****************************************************************************/
3986157642Sps/* Handles PHY generated interrupt events.                                  */
3987157642Sps/*                                                                          */
3988157642Sps/* Returns:                                                                 */
3989157642Sps/*   Nothing.                                                               */
3990157642Sps/****************************************************************************/
3991157642Spsstatic void
3992157642Spsbce_phy_intr(struct bce_softc *sc)
3993157642Sps{
3994157642Sps	u32 new_link_state, old_link_state;
3995157642Sps
3996157642Sps	new_link_state = sc->status_block->status_attn_bits &
3997157642Sps		STATUS_ATTN_BITS_LINK_STATE;
3998157642Sps	old_link_state = sc->status_block->status_attn_bits_ack &
3999157642Sps		STATUS_ATTN_BITS_LINK_STATE;
4000157642Sps
4001157642Sps	/* Handle any changes if the link state has changed. */
4002157642Sps	if (new_link_state != old_link_state) {
4003157642Sps
4004157642Sps		DBRUN(BCE_VERBOSE_INTR, bce_dump_status_block(sc));
4005157642Sps
4006157642Sps		sc->bce_link = 0;
4007157642Sps		callout_stop(&sc->bce_stat_ch);
4008157642Sps		bce_tick_locked(sc);
4009157642Sps
4010157642Sps		/* Update the status_attn_bits_ack field in the status block. */
4011157642Sps		if (new_link_state) {
4012157642Sps			REG_WR(sc, BCE_PCICFG_STATUS_BIT_SET_CMD,
4013157642Sps				STATUS_ATTN_BITS_LINK_STATE);
4014157642Sps			DBPRINT(sc, BCE_INFO, "Link is now UP.\n");
4015157642Sps		}
4016157642Sps		else {
4017157642Sps			REG_WR(sc, BCE_PCICFG_STATUS_BIT_CLEAR_CMD,
4018157642Sps				STATUS_ATTN_BITS_LINK_STATE);
4019157642Sps			DBPRINT(sc, BCE_INFO, "Link is now DOWN.\n");
4020157642Sps		}
4021157642Sps
4022157642Sps	}
4023157642Sps
4024157642Sps	/* Acknowledge the link change interrupt. */
4025157642Sps	REG_WR(sc, BCE_EMAC_STATUS, BCE_EMAC_STATUS_LINK_CHANGE);
4026157642Sps}
4027157642Sps
4028157642Sps
4029157642Sps/****************************************************************************/
4030157642Sps/* Handles received frame interrupt events.                                 */
4031157642Sps/*                                                                          */
4032157642Sps/* Returns:                                                                 */
4033157642Sps/*   Nothing.                                                               */
4034157642Sps/****************************************************************************/
4035157642Spsstatic void
4036157642Spsbce_rx_intr(struct bce_softc *sc)
4037157642Sps{
4038157642Sps	struct status_block *sblk = sc->status_block;
4039157642Sps	struct ifnet *ifp = sc->bce_ifp;
4040157642Sps	u16 hw_cons, sw_cons, sw_chain_cons, sw_prod, sw_chain_prod;
4041157642Sps	u32 sw_prod_bseq;
4042157642Sps	struct l2_fhdr *l2fhdr;
4043157642Sps
4044157642Sps	DBRUNIF(1, sc->rx_interrupts++);
4045157642Sps
4046157642Sps	/* Prepare the RX chain pages to be accessed by the host CPU. */
4047157642Sps	for (int i = 0; i < RX_PAGES; i++)
4048157642Sps		bus_dmamap_sync(sc->rx_bd_chain_tag,
4049157642Sps		    sc->rx_bd_chain_map[i], BUS_DMASYNC_POSTWRITE);
4050157642Sps
4051157642Sps	/* Get the hardware's view of the RX consumer index. */
4052157642Sps	hw_cons = sc->hw_rx_cons = sblk->status_rx_quick_consumer_index0;
4053157642Sps	if ((hw_cons & USABLE_RX_BD_PER_PAGE) == USABLE_RX_BD_PER_PAGE)
4054157642Sps		hw_cons++;
4055157642Sps
4056157642Sps	/* Get working copies of the driver's view of the RX indices. */
4057157642Sps	sw_cons = sc->rx_cons;
4058157642Sps	sw_prod = sc->rx_prod;
4059157642Sps	sw_prod_bseq = sc->rx_prod_bseq;
4060157642Sps
4061157642Sps	DBPRINT(sc, BCE_INFO_RECV, "%s(enter): sw_prod = 0x%04X, "
4062157642Sps		"sw_cons = 0x%04X, sw_prod_bseq = 0x%08X\n",
4063157642Sps		__FUNCTION__, sw_prod, sw_cons,
4064157642Sps		sw_prod_bseq);
4065157642Sps
4066157642Sps	/* Prevent speculative reads from getting ahead of the status block. */
4067157642Sps	bus_space_barrier(sc->bce_btag, sc->bce_bhandle, 0, 0,
4068157642Sps		BUS_SPACE_BARRIER_READ);
4069157642Sps
4070157642Sps	DBRUNIF((sc->free_rx_bd < sc->rx_low_watermark),
4071157642Sps		sc->rx_low_watermark = sc->free_rx_bd);
4072157642Sps
4073157642Sps	/*
4074157642Sps	 * Scan through the receive chain as long
4075157642Sps	 * as there is work to do.
4076157642Sps	 */
4077157642Sps	while (sw_cons != hw_cons) {
4078157642Sps		struct mbuf *m;
4079157642Sps		struct rx_bd *rxbd;
4080157642Sps		unsigned int len;
4081157642Sps		u32 status;
4082157642Sps
4083157642Sps		/* Convert the producer/consumer indices to an actual rx_bd index. */
4084157642Sps		sw_chain_cons = RX_CHAIN_IDX(sw_cons);
4085157642Sps		sw_chain_prod = RX_CHAIN_IDX(sw_prod);
4086157642Sps
4087157642Sps		/* Get the used rx_bd. */
4088157642Sps		rxbd = &sc->rx_bd_chain[RX_PAGE(sw_chain_cons)][RX_IDX(sw_chain_cons)];
4089157642Sps		sc->free_rx_bd++;
4090157642Sps
4091157642Sps		DBRUN(BCE_VERBOSE_RECV,
4092157642Sps			BCE_PRINTF(sc, "%s(): ", __FUNCTION__);
4093157642Sps			bce_dump_rxbd(sc, sw_chain_cons, rxbd));
4094157642Sps
4095157642Sps#ifdef DEVICE_POLLING
4096157642Sps		if (ifp->if_capenable & IFCAP_POLLING) {
4097157642Sps			if (sc->bce_rxcycles <= 0)
4098157642Sps				break;
4099157724Sru			sc->bce_rxcycles--;
4100157642Sps		}
4101157642Sps#endif
4102157642Sps
4103157642Sps		/* The mbuf is stored with the last rx_bd entry of a packet. */
4104157642Sps		if (sc->rx_mbuf_ptr[sw_chain_cons] != NULL) {
4105157642Sps
4106157642Sps			/* Validate that this is the last rx_bd. */
4107157642Sps			DBRUNIF((!(rxbd->rx_bd_flags & RX_BD_FLAGS_END)),
4108157642Sps				BCE_PRINTF(sc, "%s(%d): Unexpected mbuf found in rx_bd[0x%04X]!\n",
4109157642Sps				__FILE__, __LINE__, sw_chain_cons);
4110157642Sps				bce_breakpoint(sc));
4111157642Sps
4112157642Sps			/* DRC - ToDo: If the received packet is small, say less */
4113157642Sps			/*             than 128 bytes, allocate a new mbuf here, */
4114157642Sps			/*             copy the data to that mbuf, and recycle   */
4115157642Sps			/*             the mapped jumbo frame.                   */
4116157642Sps
4117157642Sps			/* Unmap the mbuf from DMA space. */
4118157642Sps			bus_dmamap_sync(sc->rx_mbuf_tag,
4119157642Sps			    sc->rx_mbuf_map[sw_chain_cons],
4120157642Sps		    	BUS_DMASYNC_POSTREAD);
4121157642Sps			bus_dmamap_unload(sc->rx_mbuf_tag,
4122157642Sps			    sc->rx_mbuf_map[sw_chain_cons]);
4123157642Sps
4124157642Sps			/* Remove the mbuf from the driver's chain. */
4125157642Sps			m = sc->rx_mbuf_ptr[sw_chain_cons];
4126157642Sps			sc->rx_mbuf_ptr[sw_chain_cons] = NULL;
4127157642Sps
4128157642Sps			/*
4129157642Sps			 * Frames received on the NetXteme II are prepended
4130157642Sps			 * with the l2_fhdr structure which provides status
4131157642Sps			 * information about the received frame (including
4132157642Sps			 * VLAN tags and checksum info) and are also
4133157642Sps			 * automatically adjusted to align the IP header
4134157642Sps			 * (i.e. two null bytes are inserted before the
4135157642Sps			 * Ethernet header).
4136157642Sps			 */
4137157642Sps			l2fhdr = mtod(m, struct l2_fhdr *);
4138157642Sps
4139157642Sps			len    = l2fhdr->l2_fhdr_pkt_len;
4140157642Sps			status = l2fhdr->l2_fhdr_status;
4141157642Sps
4142157642Sps			DBRUNIF(DB_RANDOMTRUE(bce_debug_l2fhdr_status_check),
4143157642Sps				BCE_PRINTF(sc, "Simulating l2_fhdr status error.\n");
4144157642Sps				status = status | L2_FHDR_ERRORS_PHY_DECODE);
4145157642Sps
4146157642Sps			/* Watch for unusual sized frames. */
4147157642Sps			DBRUNIF(((len < BCE_MIN_MTU) || (len > BCE_MAX_JUMBO_ETHER_MTU_VLAN)),
4148157642Sps				BCE_PRINTF(sc, "%s(%d): Unusual frame size found. "
4149157642Sps					"Min(%d), Actual(%d), Max(%d)\n",
4150157642Sps					__FILE__, __LINE__, (int) BCE_MIN_MTU,
4151157642Sps					len, (int) BCE_MAX_JUMBO_ETHER_MTU_VLAN);
4152157642Sps				bce_dump_mbuf(sc, m);
4153157642Sps		 		bce_breakpoint(sc));
4154157642Sps
4155157642Sps			len -= ETHER_CRC_LEN;
4156157642Sps
4157157642Sps			/* Check the received frame for errors. */
4158157642Sps			if (status &  (L2_FHDR_ERRORS_BAD_CRC |
4159157642Sps				L2_FHDR_ERRORS_PHY_DECODE | L2_FHDR_ERRORS_ALIGNMENT |
4160157642Sps				L2_FHDR_ERRORS_TOO_SHORT  | L2_FHDR_ERRORS_GIANT_FRAME)) {
4161157642Sps
4162157642Sps				ifp->if_ierrors++;
4163157642Sps				DBRUNIF(1, sc->l2fhdr_status_errors++);
4164157642Sps
4165157642Sps				/* Reuse the mbuf for a new frame. */
4166157642Sps				if (bce_get_buf(sc, m, &sw_prod, &sw_chain_prod, &sw_prod_bseq)) {
4167157642Sps
4168157642Sps					DBRUNIF(1, bce_breakpoint(sc));
4169157642Sps					panic("bce%d: Can't reuse RX mbuf!\n", sc->bce_unit);
4170157642Sps
4171157642Sps				}
4172157642Sps				goto bce_rx_int_next_rx;
4173157642Sps			}
4174157642Sps
4175157642Sps			/*
4176157642Sps			 * Get a new mbuf for the rx_bd.   If no new
4177157642Sps			 * mbufs are available then reuse the current mbuf,
4178157642Sps			 * log an ierror on the interface, and generate
4179157642Sps			 * an error in the system log.
4180157642Sps			 */
4181157642Sps			if (bce_get_buf(sc, NULL, &sw_prod, &sw_chain_prod, &sw_prod_bseq)) {
4182157642Sps
4183157642Sps				DBRUN(BCE_WARN,
4184157642Sps					BCE_PRINTF(sc, "%s(%d): Failed to allocate "
4185157642Sps					"new mbuf, incoming frame dropped!\n",
4186157642Sps					__FILE__, __LINE__));
4187157642Sps
4188157642Sps				ifp->if_ierrors++;
4189157642Sps
4190157642Sps				/* Try and reuse the exisitng mbuf. */
4191157642Sps				if (bce_get_buf(sc, m, &sw_prod, &sw_chain_prod, &sw_prod_bseq)) {
4192157642Sps
4193157642Sps					DBRUNIF(1, bce_breakpoint(sc));
4194157642Sps					panic("bce%d: Double mbuf allocation failure!", sc->bce_unit);
4195157642Sps
4196157642Sps				}
4197157642Sps				goto bce_rx_int_next_rx;
4198157642Sps			}
4199157642Sps
4200157642Sps			/* Skip over the l2_fhdr when passing the data up the stack. */
4201157642Sps			m_adj(m, sizeof(struct l2_fhdr) + ETHER_ALIGN);
4202157642Sps
4203157642Sps			/* Adjust the packet length to match the received data. */
4204157642Sps			m->m_pkthdr.len = m->m_len = len;
4205157642Sps
4206157642Sps			/* Send the packet to the appropriate interface. */
4207157642Sps			m->m_pkthdr.rcvif = ifp;
4208157642Sps
4209157642Sps			DBRUN(BCE_VERBOSE_RECV,
4210157642Sps				struct ether_header *eh;
4211157642Sps				eh = mtod(m, struct ether_header *);
4212157642Sps				BCE_PRINTF(sc, "%s(): to: %6D, from: %6D, type: 0x%04X\n",
4213157642Sps					__FUNCTION__, eh->ether_dhost, ":",
4214157642Sps					eh->ether_shost, ":", htons(eh->ether_type)));
4215157642Sps
4216157642Sps			/* Validate the checksum if offload enabled. */
4217157642Sps			if (ifp->if_capenable & IFCAP_RXCSUM) {
4218157642Sps
4219157642Sps				/* Check for an IP datagram. */
4220157642Sps				if (status & L2_FHDR_STATUS_IP_DATAGRAM) {
4221157642Sps					m->m_pkthdr.csum_flags |= CSUM_IP_CHECKED;
4222157642Sps
4223157642Sps					/* Check if the IP checksum is valid. */
4224157642Sps					if ((l2fhdr->l2_fhdr_ip_xsum ^ 0xffff) == 0)
4225157642Sps						m->m_pkthdr.csum_flags |= CSUM_IP_VALID;
4226157642Sps					else
4227157642Sps						DBPRINT(sc, BCE_WARN_SEND,
4228157642Sps							"%s(): Invalid IP checksum = 0x%04X!\n",
4229157642Sps							__FUNCTION__, l2fhdr->l2_fhdr_ip_xsum);
4230157642Sps				}
4231157642Sps
4232157642Sps				/* Check for a valid TCP/UDP frame. */
4233157642Sps				if (status & (L2_FHDR_STATUS_TCP_SEGMENT |
4234157642Sps					L2_FHDR_STATUS_UDP_DATAGRAM)) {
4235157642Sps
4236157642Sps					/* Check for a good TCP/UDP checksum. */
4237157642Sps					if ((status & (L2_FHDR_ERRORS_TCP_XSUM |
4238157642Sps						      L2_FHDR_ERRORS_UDP_XSUM)) == 0) {
4239157642Sps						m->m_pkthdr.csum_data =
4240157642Sps						    l2fhdr->l2_fhdr_tcp_udp_xsum;
4241157642Sps						m->m_pkthdr.csum_flags |= (CSUM_DATA_VALID
4242157642Sps							| CSUM_PSEUDO_HDR);
4243157642Sps					} else
4244157642Sps						DBPRINT(sc, BCE_WARN_SEND,
4245157642Sps							"%s(): Invalid TCP/UDP checksum = 0x%04X!\n",
4246157642Sps							__FUNCTION__, l2fhdr->l2_fhdr_tcp_udp_xsum);
4247157642Sps				}
4248157642Sps			}
4249157642Sps
4250157642Sps
4251157642Sps			/*
4252157642Sps			 * If we received a packet with a vlan tag,
4253157642Sps			 * attach that information to the packet.
4254157642Sps			 */
4255157642Sps			if (status & L2_FHDR_STATUS_L2_VLAN_TAG) {
4256157642Sps				DBPRINT(sc, BCE_VERBOSE_SEND, "%s(): VLAN tag = 0x%04X\n",
4257157642Sps					__FUNCTION__, l2fhdr->l2_fhdr_vlan_tag);
4258157642Sps#if __FreeBSD_version < 700000
4259157642Sps				VLAN_INPUT_TAG(ifp, m, l2fhdr->l2_fhdr_vlan_tag, continue);
4260157642Sps#else
4261162375Sandre				m->m_pkthdr.ether_vtag = l2fhdr->l2_fhdr_vlan_tag;
4262162375Sandre				m->m_flags |= M_VLANTAG;
4263157642Sps#endif
4264157642Sps			}
4265157642Sps
4266157642Sps			/* Pass the mbuf off to the upper layers. */
4267157642Sps			ifp->if_ipackets++;
4268157642Sps			DBPRINT(sc, BCE_VERBOSE_RECV, "%s(): Passing received frame up.\n",
4269157642Sps				__FUNCTION__);
4270157642Sps			BCE_UNLOCK(sc);
4271157642Sps			(*ifp->if_input)(ifp, m);
4272157642Sps			DBRUNIF(1, sc->rx_mbuf_alloc--);
4273157642Sps			BCE_LOCK(sc);
4274157642Sps
4275157642Spsbce_rx_int_next_rx:
4276157642Sps			sw_prod = NEXT_RX_BD(sw_prod);
4277157642Sps		}
4278157642Sps
4279157642Sps		sw_cons = NEXT_RX_BD(sw_cons);
4280157642Sps
4281157642Sps		/* Refresh hw_cons to see if there's new work */
4282157642Sps		if (sw_cons == hw_cons) {
4283157642Sps			hw_cons = sc->hw_rx_cons = sblk->status_rx_quick_consumer_index0;
4284157642Sps			if ((hw_cons & USABLE_RX_BD_PER_PAGE) == USABLE_RX_BD_PER_PAGE)
4285157642Sps				hw_cons++;
4286157642Sps		}
4287157642Sps
4288157642Sps		/* Prevent speculative reads from getting ahead of the status block. */
4289157642Sps		bus_space_barrier(sc->bce_btag, sc->bce_bhandle, 0, 0,
4290157642Sps			BUS_SPACE_BARRIER_READ);
4291157642Sps	}
4292157642Sps
4293157642Sps	for (int i = 0; i < RX_PAGES; i++)
4294157642Sps		bus_dmamap_sync(sc->rx_bd_chain_tag,
4295157642Sps		    sc->rx_bd_chain_map[i], BUS_DMASYNC_PREWRITE);
4296157642Sps
4297157642Sps	sc->rx_cons = sw_cons;
4298157642Sps	sc->rx_prod = sw_prod;
4299157642Sps	sc->rx_prod_bseq = sw_prod_bseq;
4300157642Sps
4301157642Sps	REG_WR16(sc, MB_RX_CID_ADDR + BCE_L2CTX_HOST_BDIDX, sc->rx_prod);
4302157642Sps	REG_WR(sc, MB_RX_CID_ADDR + BCE_L2CTX_HOST_BSEQ, sc->rx_prod_bseq);
4303157642Sps
4304157642Sps	DBPRINT(sc, BCE_INFO_RECV, "%s(exit): rx_prod = 0x%04X, "
4305157642Sps		"rx_cons = 0x%04X, rx_prod_bseq = 0x%08X\n",
4306157642Sps		__FUNCTION__, sc->rx_prod, sc->rx_cons, sc->rx_prod_bseq);
4307157642Sps}
4308157642Sps
4309157642Sps
4310157642Sps/****************************************************************************/
4311157642Sps/* Handles transmit completion interrupt events.                            */
4312157642Sps/*                                                                          */
4313157642Sps/* Returns:                                                                 */
4314157642Sps/*   Nothing.                                                               */
4315157642Sps/****************************************************************************/
4316157642Spsstatic void
4317157642Spsbce_tx_intr(struct bce_softc *sc)
4318157642Sps{
4319157642Sps	struct status_block *sblk = sc->status_block;
4320157642Sps	struct ifnet *ifp = sc->bce_ifp;
4321157642Sps	u16 hw_tx_cons, sw_tx_cons, sw_tx_chain_cons;
4322157642Sps
4323157642Sps	BCE_LOCK_ASSERT(sc);
4324157642Sps
4325157642Sps	DBRUNIF(1, sc->tx_interrupts++);
4326157642Sps
4327157642Sps	/* Get the hardware's view of the TX consumer index. */
4328157642Sps	hw_tx_cons = sc->hw_tx_cons = sblk->status_tx_quick_consumer_index0;
4329157642Sps
4330157642Sps	/* Skip to the next entry if this is a chain page pointer. */
4331157642Sps	if ((hw_tx_cons & USABLE_TX_BD_PER_PAGE) == USABLE_TX_BD_PER_PAGE)
4332157642Sps		hw_tx_cons++;
4333157642Sps
4334157642Sps	sw_tx_cons = sc->tx_cons;
4335157642Sps
4336157642Sps	/* Prevent speculative reads from getting ahead of the status block. */
4337157642Sps	bus_space_barrier(sc->bce_btag, sc->bce_bhandle, 0, 0,
4338157642Sps		BUS_SPACE_BARRIER_READ);
4339157642Sps
4340157642Sps	/* Cycle through any completed TX chain page entries. */
4341157642Sps	while (sw_tx_cons != hw_tx_cons) {
4342157642Sps#ifdef BCE_DEBUG
4343157642Sps		struct tx_bd *txbd = NULL;
4344157642Sps#endif
4345157642Sps		sw_tx_chain_cons = TX_CHAIN_IDX(sw_tx_cons);
4346157642Sps
4347157642Sps		DBPRINT(sc, BCE_INFO_SEND,
4348157642Sps			"%s(): hw_tx_cons = 0x%04X, sw_tx_cons = 0x%04X, "
4349157642Sps			"sw_tx_chain_cons = 0x%04X\n",
4350157642Sps			__FUNCTION__, hw_tx_cons, sw_tx_cons, sw_tx_chain_cons);
4351157642Sps
4352157642Sps		DBRUNIF((sw_tx_chain_cons > MAX_TX_BD),
4353157642Sps			BCE_PRINTF(sc, "%s(%d): TX chain consumer out of range! "
4354157642Sps				" 0x%04X > 0x%04X\n",
4355157642Sps				__FILE__, __LINE__, sw_tx_chain_cons,
4356157642Sps				(int) MAX_TX_BD);
4357157642Sps			bce_breakpoint(sc));
4358157642Sps
4359157642Sps		DBRUNIF(1,
4360157642Sps			txbd = &sc->tx_bd_chain[TX_PAGE(sw_tx_chain_cons)]
4361157642Sps				[TX_IDX(sw_tx_chain_cons)]);
4362157642Sps
4363157642Sps		DBRUNIF((txbd == NULL),
4364157642Sps			BCE_PRINTF(sc, "%s(%d): Unexpected NULL tx_bd[0x%04X]!\n",
4365157642Sps				__FILE__, __LINE__, sw_tx_chain_cons);
4366157642Sps			bce_breakpoint(sc));
4367157642Sps
4368157642Sps		DBRUN(BCE_INFO_SEND,
4369157642Sps			BCE_PRINTF(sc, "%s(): ", __FUNCTION__);
4370157642Sps			bce_dump_txbd(sc, sw_tx_chain_cons, txbd));
4371157642Sps
4372157642Sps		/*
4373157642Sps		 * Free the associated mbuf. Remember
4374157642Sps		 * that only the last tx_bd of a packet
4375157642Sps		 * has an mbuf pointer and DMA map.
4376157642Sps		 */
4377157642Sps		if (sc->tx_mbuf_ptr[sw_tx_chain_cons] != NULL) {
4378157642Sps
4379157642Sps			/* Validate that this is the last tx_bd. */
4380157642Sps			DBRUNIF((!(txbd->tx_bd_vlan_tag_flags & TX_BD_FLAGS_END)),
4381157642Sps				BCE_PRINTF(sc, "%s(%d): tx_bd END flag not set but "
4382157642Sps				"txmbuf == NULL!\n", __FILE__, __LINE__);
4383157642Sps				bce_breakpoint(sc));
4384157642Sps
4385157642Sps			DBRUN(BCE_INFO_SEND,
4386157642Sps				BCE_PRINTF(sc, "%s(): Unloading map/freeing mbuf "
4387157642Sps					"from tx_bd[0x%04X]\n", __FUNCTION__, sw_tx_chain_cons));
4388157642Sps
4389157642Sps			/* Unmap the mbuf. */
4390157642Sps			bus_dmamap_unload(sc->tx_mbuf_tag,
4391157642Sps			    sc->tx_mbuf_map[sw_tx_chain_cons]);
4392157642Sps
4393157642Sps			/* Free the mbuf. */
4394157642Sps			m_freem(sc->tx_mbuf_ptr[sw_tx_chain_cons]);
4395157642Sps			sc->tx_mbuf_ptr[sw_tx_chain_cons] = NULL;
4396157642Sps			DBRUNIF(1, sc->tx_mbuf_alloc--);
4397157642Sps
4398157642Sps			ifp->if_opackets++;
4399157642Sps		}
4400157642Sps
4401157642Sps		sc->used_tx_bd--;
4402157642Sps		sw_tx_cons = NEXT_TX_BD(sw_tx_cons);
4403157642Sps
4404157642Sps		/* Refresh hw_cons to see if there's new work. */
4405157642Sps		hw_tx_cons = sc->hw_tx_cons = sblk->status_tx_quick_consumer_index0;
4406157642Sps		if ((hw_tx_cons & USABLE_TX_BD_PER_PAGE) == USABLE_TX_BD_PER_PAGE)
4407157642Sps			hw_tx_cons++;
4408157642Sps
4409157642Sps		/* Prevent speculative reads from getting ahead of the status block. */
4410157642Sps		bus_space_barrier(sc->bce_btag, sc->bce_bhandle, 0, 0,
4411157642Sps			BUS_SPACE_BARRIER_READ);
4412157642Sps	}
4413157642Sps
4414157642Sps	/* Clear the TX timeout timer. */
4415157642Sps	ifp->if_timer = 0;
4416157642Sps
4417157642Sps	/* Clear the tx hardware queue full flag. */
4418157642Sps	if ((sc->used_tx_bd + BCE_TX_SLACK_SPACE) < USABLE_TX_BD) {
4419157642Sps		DBRUNIF((ifp->if_drv_flags & IFF_DRV_OACTIVE),
4420157642Sps			BCE_PRINTF(sc, "%s(): TX chain is open for business! Used tx_bd = %d\n",
4421157642Sps				__FUNCTION__, sc->used_tx_bd));
4422157642Sps		ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
4423157642Sps	}
4424157642Sps
4425157642Sps	sc->tx_cons = sw_tx_cons;
4426157642Sps}
4427157642Sps
4428157642Sps
4429157642Sps/****************************************************************************/
4430157642Sps/* Disables interrupt generation.                                           */
4431157642Sps/*                                                                          */
4432157642Sps/* Returns:                                                                 */
4433157642Sps/*   Nothing.                                                               */
4434157642Sps/****************************************************************************/
4435157642Spsstatic void
4436157642Spsbce_disable_intr(struct bce_softc *sc)
4437157642Sps{
4438157642Sps	REG_WR(sc, BCE_PCICFG_INT_ACK_CMD,
4439157642Sps	       BCE_PCICFG_INT_ACK_CMD_MASK_INT);
4440157642Sps	REG_RD(sc, BCE_PCICFG_INT_ACK_CMD);
4441157642Sps}
4442157642Sps
4443157642Sps
4444157642Sps/****************************************************************************/
4445157642Sps/* Enables interrupt generation.                                            */
4446157642Sps/*                                                                          */
4447157642Sps/* Returns:                                                                 */
4448157642Sps/*   Nothing.                                                               */
4449157642Sps/****************************************************************************/
4450157642Spsstatic void
4451157642Spsbce_enable_intr(struct bce_softc *sc)
4452157642Sps{
4453157642Sps	u32 val;
4454157642Sps
4455157642Sps	REG_WR(sc, BCE_PCICFG_INT_ACK_CMD,
4456157642Sps	       BCE_PCICFG_INT_ACK_CMD_INDEX_VALID |
4457157642Sps	       BCE_PCICFG_INT_ACK_CMD_MASK_INT | sc->last_status_idx);
4458157642Sps
4459157642Sps	REG_WR(sc, BCE_PCICFG_INT_ACK_CMD,
4460157642Sps	       BCE_PCICFG_INT_ACK_CMD_INDEX_VALID | sc->last_status_idx);
4461157642Sps
4462157642Sps	val = REG_RD(sc, BCE_HC_COMMAND);
4463157642Sps	REG_WR(sc, BCE_HC_COMMAND, val | BCE_HC_COMMAND_COAL_NOW);
4464157642Sps}
4465157642Sps
4466157642Sps
4467157642Sps/****************************************************************************/
4468157642Sps/* Handles controller initialization.                                       */
4469157642Sps/*                                                                          */
4470157642Sps/* Must be called from a locked routine.                                    */
4471157642Sps/*                                                                          */
4472157642Sps/* Returns:                                                                 */
4473157642Sps/*   Nothing.                                                               */
4474157642Sps/****************************************************************************/
4475157642Spsstatic void
4476157642Spsbce_init_locked(struct bce_softc *sc)
4477157642Sps{
4478157642Sps	struct ifnet *ifp;
4479157642Sps	u32 ether_mtu;
4480157642Sps
4481157642Sps	DBPRINT(sc, BCE_VERBOSE_RESET, "Entering %s()\n", __FUNCTION__);
4482157642Sps
4483157642Sps	BCE_LOCK_ASSERT(sc);
4484157642Sps
4485157642Sps	ifp = sc->bce_ifp;
4486157642Sps
4487157642Sps	/* Check if the driver is still running and bail out if it is. */
4488157642Sps	if (ifp->if_drv_flags & IFF_DRV_RUNNING)
4489157642Sps		goto bce_init_locked_exit;
4490157642Sps
4491157642Sps	bce_stop(sc);
4492157642Sps
4493157642Sps	if (bce_reset(sc, BCE_DRV_MSG_CODE_RESET)) {
4494157642Sps		BCE_PRINTF(sc, "%s(%d): Controller reset failed!\n",
4495157642Sps			__FILE__, __LINE__);
4496157642Sps		goto bce_init_locked_exit;
4497157642Sps	}
4498157642Sps
4499157642Sps	if (bce_chipinit(sc)) {
4500157642Sps		BCE_PRINTF(sc, "%s(%d): Controller initialization failed!\n",
4501157642Sps			__FILE__, __LINE__);
4502157642Sps		goto bce_init_locked_exit;
4503157642Sps	}
4504157642Sps
4505157642Sps	if (bce_blockinit(sc)) {
4506157642Sps		BCE_PRINTF(sc, "%s(%d): Block initialization failed!\n",
4507157642Sps			__FILE__, __LINE__);
4508157642Sps		goto bce_init_locked_exit;
4509157642Sps	}
4510157642Sps
4511157642Sps	/* Load our MAC address. */
4512157642Sps	bcopy(IF_LLADDR(sc->bce_ifp), sc->eaddr, ETHER_ADDR_LEN);
4513157642Sps	bce_set_mac_addr(sc);
4514157642Sps
4515157642Sps	/* Calculate and program the Ethernet MTU size. */
4516157642Sps	ether_mtu = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN + ifp->if_mtu +
4517157642Sps		ETHER_CRC_LEN;
4518157642Sps
4519157642Sps	DBPRINT(sc, BCE_INFO, "%s(): setting mtu = %d\n",__FUNCTION__, ether_mtu);
4520157642Sps
4521157642Sps	/*
4522157642Sps	 * Program the mtu, enabling jumbo frame
4523157642Sps	 * support if necessary.  Also set the mbuf
4524157642Sps	 * allocation count for RX frames.
4525157642Sps	 */
4526157642Sps	if (ether_mtu > ETHER_MAX_LEN + ETHER_VLAN_ENCAP_LEN) {
4527157642Sps		REG_WR(sc, BCE_EMAC_RX_MTU_SIZE, ether_mtu |
4528157642Sps			BCE_EMAC_RX_MTU_SIZE_JUMBO_ENA);
4529157642Sps		sc->mbuf_alloc_size = MJUM9BYTES;
4530157642Sps	} else {
4531157642Sps		REG_WR(sc, BCE_EMAC_RX_MTU_SIZE, ether_mtu);
4532157642Sps		sc->mbuf_alloc_size = MCLBYTES;
4533157642Sps	}
4534157642Sps
4535157642Sps	/* Calculate the RX Ethernet frame size for rx_bd's. */
4536157642Sps	sc->max_frame_size = sizeof(struct l2_fhdr) + 2 + ether_mtu + 8;
4537157642Sps
4538157642Sps	DBPRINT(sc, BCE_INFO,
4539157642Sps		"%s(): mclbytes = %d, mbuf_alloc_size = %d, "
4540157642Sps		"max_frame_size = %d\n",
4541157642Sps		__FUNCTION__, (int) MCLBYTES, sc->mbuf_alloc_size, sc->max_frame_size);
4542157642Sps
4543157642Sps	/* Program appropriate promiscuous/multicast filtering. */
4544157642Sps	bce_set_rx_mode(sc);
4545157642Sps
4546157642Sps	/* Init RX buffer descriptor chain. */
4547157642Sps	bce_init_rx_chain(sc);
4548157642Sps
4549157642Sps	/* Init TX buffer descriptor chain. */
4550157642Sps	bce_init_tx_chain(sc);
4551157642Sps
4552157642Sps#ifdef DEVICE_POLLING
4553157642Sps	/* Disable interrupts if we are polling. */
4554157642Sps	if (ifp->if_capenable & IFCAP_POLLING) {
4555157642Sps		bce_disable_intr(sc);
4556157642Sps
4557157642Sps		REG_WR(sc, BCE_HC_RX_QUICK_CONS_TRIP,
4558157642Sps			(1 << 16) | sc->bce_rx_quick_cons_trip);
4559157642Sps		REG_WR(sc, BCE_HC_TX_QUICK_CONS_TRIP,
4560157642Sps			(1 << 16) | sc->bce_tx_quick_cons_trip);
4561157642Sps	} else
4562157642Sps#endif
4563157642Sps	/* Enable host interrupts. */
4564157642Sps	bce_enable_intr(sc);
4565157642Sps
4566157642Sps	bce_ifmedia_upd(ifp);
4567157642Sps
4568157642Sps	ifp->if_drv_flags |= IFF_DRV_RUNNING;
4569157642Sps	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
4570157642Sps
4571157642Sps	callout_reset(&sc->bce_stat_ch, hz, bce_tick, sc);
4572157642Sps
4573157642Spsbce_init_locked_exit:
4574157642Sps	DBPRINT(sc, BCE_VERBOSE_RESET, "Exiting %s()\n", __FUNCTION__);
4575157642Sps
4576157642Sps	return;
4577157642Sps}
4578157642Sps
4579162474Sambriskostatic void
4580162474Sambriskobce_mgmt_init_locked(struct bce_softc *sc)
4581162474Sambrisko{
4582162474Sambrisko	u32 val;
4583162474Sambrisko	struct ifnet *ifp;
4584157642Sps
4585162474Sambrisko	DBPRINT(sc, BCE_VERBOSE_RESET, "Entering %s()\n", __FUNCTION__);
4586162474Sambrisko
4587162474Sambrisko	BCE_LOCK_ASSERT(sc);
4588162474Sambrisko
4589162474Sambrisko	ifp = sc->bce_ifp;
4590162474Sambrisko
4591162474Sambrisko	/* Check if the driver is still running and bail out if it is. */
4592162474Sambrisko	if (ifp->if_drv_flags & IFF_DRV_RUNNING)
4593162474Sambrisko		goto bce_mgmt_init_locked_exit;
4594162474Sambrisko
4595162474Sambrisko	/* Initialize the on-boards CPUs */
4596162474Sambrisko	bce_init_cpus(sc);
4597162474Sambrisko
4598162474Sambrisko	val = (BCM_PAGE_BITS - 8) << 24;
4599162474Sambrisko	REG_WR(sc, BCE_RV2P_CONFIG, val);
4600162474Sambrisko
4601162474Sambrisko	/* Enable all critical blocks in the MAC. */
4602162474Sambrisko	REG_WR(sc, BCE_MISC_ENABLE_SET_BITS,
4603162474Sambrisko	       BCE_MISC_ENABLE_SET_BITS_RX_V2P_ENABLE |
4604162474Sambrisko	       BCE_MISC_ENABLE_SET_BITS_RX_DMA_ENABLE |
4605162474Sambrisko	       BCE_MISC_ENABLE_SET_BITS_COMPLETION_ENABLE);
4606162474Sambrisko	REG_RD(sc, BCE_MISC_ENABLE_SET_BITS);
4607162474Sambrisko	DELAY(20);
4608162474Sambrisko
4609162474Sambrisko	bce_ifmedia_upd(ifp);
4610162474Sambriskobce_mgmt_init_locked_exit:
4611162474Sambrisko	DBPRINT(sc, BCE_VERBOSE_RESET, "Exiting %s()\n", __FUNCTION__);
4612162474Sambrisko
4613162474Sambrisko	return;
4614162474Sambrisko}
4615162474Sambrisko
4616162474Sambrisko
4617157642Sps/****************************************************************************/
4618157642Sps/* Handles controller initialization when called from an unlocked routine.  */
4619157642Sps/*                                                                          */
4620157642Sps/* Returns:                                                                 */
4621157642Sps/*   Nothing.                                                               */
4622157642Sps/****************************************************************************/
4623157642Spsstatic void
4624157642Spsbce_init(void *xsc)
4625157642Sps{
4626157642Sps	struct bce_softc *sc = xsc;
4627157642Sps
4628157642Sps	BCE_LOCK(sc);
4629157642Sps	bce_init_locked(sc);
4630157642Sps	BCE_UNLOCK(sc);
4631157642Sps}
4632157642Sps
4633157642Sps
4634157642Sps/****************************************************************************/
4635157642Sps/* Encapsultes an mbuf cluster into the tx_bd chain structure and makes the */
4636157642Sps/* memory visible to the controller.                                        */
4637157642Sps/*                                                                          */
4638157642Sps/* Returns:                                                                 */
4639157642Sps/*   0 for success, positive value for failure.                             */
4640157642Sps/****************************************************************************/
4641157642Spsstatic int
4642163339Sscottlbce_tx_encap(struct bce_softc *sc, struct mbuf *m_head, u16 *prod)
4643157642Sps{
4644157642Sps	u32 vlan_tag_flags = 0;
4645163339Sscottl	u16 chain_prod;
4646157642Sps	struct bce_dmamap_arg map_arg;
4647157642Sps	bus_dmamap_t map;
4648163337Sscottl	int error, rc = 0;
4649157642Sps
4650157642Sps	/* Transfer any checksum offload flags to the bd. */
4651157642Sps	if (m_head->m_pkthdr.csum_flags) {
4652157642Sps		if (m_head->m_pkthdr.csum_flags & CSUM_IP)
4653157642Sps			vlan_tag_flags |= TX_BD_FLAGS_IP_CKSUM;
4654157642Sps		if (m_head->m_pkthdr.csum_flags & (CSUM_TCP | CSUM_UDP))
4655157642Sps			vlan_tag_flags |= TX_BD_FLAGS_TCP_UDP_CKSUM;
4656157642Sps	}
4657157642Sps
4658157642Sps	/* Transfer any VLAN tags to the bd. */
4659162375Sandre	if (m_head->m_flags & M_VLANTAG)
4660157642Sps		vlan_tag_flags |= (TX_BD_FLAGS_VLAN_TAG |
4661162375Sandre			(m_head->m_pkthdr.ether_vtag << 16));
4662157642Sps
4663157642Sps	/* Map the mbuf into DMAable memory. */
4664163339Sscottl	chain_prod = TX_CHAIN_IDX(*prod);
4665163339Sscottl	map = sc->tx_mbuf_map[chain_prod];
4666157642Sps	map_arg.sc         = sc;
4667157642Sps	map_arg.prod       = *prod;
4668163339Sscottl	map_arg.chain_prod = chain_prod;
4669163339Sscottl	map_arg.prod_bseq  = sc->tx_prod_bseq;
4670157642Sps	map_arg.tx_flags   = vlan_tag_flags;
4671157642Sps	map_arg.maxsegs    = USABLE_TX_BD - sc->used_tx_bd -
4672157642Sps		BCE_TX_SLACK_SPACE;
4673157642Sps
4674157642Sps	KASSERT(map_arg.maxsegs > 0, ("Invalid TX maxsegs value!"));
4675157642Sps
4676157642Sps	/* Map the mbuf into our DMA address space. */
4677157642Sps	error = bus_dmamap_load_mbuf(sc->tx_mbuf_tag, map, m_head,
4678157642Sps	    bce_dma_map_tx_desc, &map_arg, BUS_DMA_NOWAIT);
4679157642Sps
4680157642Sps	if (error || map_arg.maxsegs == 0) {
4681159411Sdavidch
4682159411Sdavidch            /* Try to defrag the mbuf if there are too many segments. */
4683159411Sdavidch            if (error == EFBIG && map_arg.maxsegs != 0) {
4684159411Sdavidch                struct mbuf *m0;
4685159411Sdavidch
4686159411Sdavidch	        DBPRINT(sc, BCE_WARN, "%s(): fragmented mbuf (%d pieces)\n",
4687159411Sdavidch                    __FUNCTION__, map_arg.maxsegs);
4688159411Sdavidch
4689159411Sdavidch                m0 = m_defrag(m_head, M_DONTWAIT);
4690159411Sdavidch                if (m0 != NULL) {
4691159411Sdavidch                    m_head = m0;
4692159411Sdavidch                    error = bus_dmamap_load_mbuf(sc->tx_mbuf_tag,
4693159411Sdavidch                        map, m_head, bce_dma_map_tx_desc, &map_arg,
4694159411Sdavidch                        BUS_DMA_NOWAIT);
4695159411Sdavidch                }
4696159411Sdavidch            }
4697159411Sdavidch
4698159411Sdavidch            /* Still getting an error after a defrag. */
4699159411Sdavidch            if (error) {
4700159411Sdavidch                BCE_PRINTF(sc,
4701159411Sdavidch                    "%s(%d): Error mapping mbuf into TX chain!\n",
4702159411Sdavidch                    __FILE__, __LINE__);
4703159411Sdavidch                rc = ENOBUFS;
4704159411Sdavidch                goto bce_tx_encap_exit;
4705159411Sdavidch            }
4706159411Sdavidch
4707157642Sps	}
4708157642Sps
4709157642Sps	/*
4710157642Sps	 * Ensure that the map for this transmission
4711157642Sps	 * is placed at the array index of the last
4712157642Sps	 * descriptor in this chain.  This is done
4713157642Sps	 * because a single map is used for all
4714157642Sps	 * segments of the mbuf and we don't want to
4715157642Sps	 * delete the map before all of the segments
4716157642Sps	 * have been freed.
4717157642Sps	 */
4718163339Sscottl	sc->tx_mbuf_map[chain_prod] =
4719157642Sps		sc->tx_mbuf_map[map_arg.chain_prod];
4720157642Sps	sc->tx_mbuf_map[map_arg.chain_prod] = map;
4721157642Sps	sc->tx_mbuf_ptr[map_arg.chain_prod] = m_head;
4722157642Sps	sc->used_tx_bd += map_arg.maxsegs;
4723157642Sps
4724157642Sps	DBRUNIF((sc->used_tx_bd > sc->tx_hi_watermark),
4725157642Sps		sc->tx_hi_watermark = sc->used_tx_bd);
4726157642Sps
4727157642Sps	DBRUNIF(1, sc->tx_mbuf_alloc++);
4728157642Sps
4729163339Sscottl	DBRUN(BCE_VERBOSE_SEND, bce_dump_tx_mbuf_chain(sc, chain_prod,
4730157642Sps		map_arg.maxsegs));
4731157642Sps
4732157642Sps	/* prod still points the last used tx_bd at this point. */
4733157642Sps	*prod       = map_arg.prod;
4734163339Sscottl	sc->tx_prod_bseq  = map_arg.prod_bseq;
4735157642Sps
4736157642Spsbce_tx_encap_exit:
4737157642Sps
4738157642Sps	return(rc);
4739157642Sps}
4740157642Sps
4741157642Sps
4742157642Sps/****************************************************************************/
4743157642Sps/* Main transmit routine when called from another routine with a lock.      */
4744157642Sps/*                                                                          */
4745157642Sps/* Returns:                                                                 */
4746157642Sps/*   Nothing.                                                               */
4747157642Sps/****************************************************************************/
4748157642Spsstatic void
4749157642Spsbce_start_locked(struct ifnet *ifp)
4750157642Sps{
4751157642Sps	struct bce_softc *sc = ifp->if_softc;
4752157642Sps	struct mbuf *m_head = NULL;
4753157642Sps	int count = 0;
4754157642Sps	u16 tx_prod, tx_chain_prod;
4755157642Sps
4756157642Sps	/* If there's no link or the transmit queue is empty then just exit. */
4757157642Sps	if (!sc->bce_link || IFQ_DRV_IS_EMPTY(&ifp->if_snd)) {
4758157642Sps		DBPRINT(sc, BCE_INFO_SEND, "%s(): No link or transmit queue empty.\n",
4759157642Sps			__FUNCTION__);
4760157642Sps		goto bce_start_locked_exit;
4761157642Sps	}
4762157642Sps
4763157642Sps	/* prod points to the next free tx_bd. */
4764157642Sps	tx_prod = sc->tx_prod;
4765157642Sps	tx_chain_prod = TX_CHAIN_IDX(tx_prod);
4766157642Sps
4767157642Sps	DBPRINT(sc, BCE_INFO_SEND,
4768157642Sps		"%s(): Start: tx_prod = 0x%04X, tx_chain_prod = %04X, "
4769157642Sps		"tx_prod_bseq = 0x%08X\n",
4770163339Sscottl		__FUNCTION__, tx_prod, tx_chain_prod, sc->tx_prod_bseq);
4771157642Sps
4772157642Sps	/* Keep adding entries while there is space in the ring. */
4773157642Sps	while(sc->tx_mbuf_ptr[tx_chain_prod] == NULL) {
4774157642Sps
4775157642Sps		/* Check for any frames to send. */
4776157642Sps		IFQ_DRV_DEQUEUE(&ifp->if_snd, m_head);
4777157642Sps		if (m_head == NULL)
4778157642Sps			break;
4779157642Sps
4780157642Sps		/*
4781157642Sps		 * Pack the data into the transmit ring. If we
4782157642Sps		 * don't have room, place the mbuf back at the
4783157642Sps		 * head of the queue and set the OACTIVE flag
4784157642Sps		 * to wait for the NIC to drain the chain.
4785157642Sps		 */
4786163339Sscottl		if (bce_tx_encap(sc, m_head, &tx_prod)) {
4787157642Sps			IFQ_DRV_PREPEND(&ifp->if_snd, m_head);
4788157642Sps			ifp->if_drv_flags |= IFF_DRV_OACTIVE;
4789157642Sps			DBPRINT(sc, BCE_INFO_SEND,
4790157642Sps				"TX chain is closed for business! Total tx_bd used = %d\n",
4791157642Sps				sc->used_tx_bd);
4792157642Sps			break;
4793157642Sps		}
4794157642Sps
4795157642Sps		count++;
4796157642Sps
4797157642Sps		/* Send a copy of the frame to any BPF listeners. */
4798157642Sps		BPF_MTAP(ifp, m_head);
4799157642Sps
4800157642Sps		tx_prod = NEXT_TX_BD(tx_prod);
4801157642Sps	}
4802157642Sps
4803157642Sps	if (count == 0) {
4804157642Sps		/* no packets were dequeued */
4805157642Sps		DBPRINT(sc, BCE_VERBOSE_SEND, "%s(): No packets were dequeued\n",
4806157642Sps			__FUNCTION__);
4807157642Sps		goto bce_start_locked_exit;
4808157642Sps	}
4809157642Sps
4810157642Sps	/* Update the driver's counters. */
4811157642Sps	sc->tx_prod      = tx_prod;
4812163339Sscottl	tx_chain_prod = TX_CHAIN_IDX(tx_prod);
4813157642Sps
4814157642Sps	DBPRINT(sc, BCE_INFO_SEND,
4815157642Sps		"%s(): End: tx_prod = 0x%04X, tx_chain_prod = 0x%04X, "
4816157642Sps		"tx_prod_bseq = 0x%08X\n",
4817163339Sscottl		__FUNCTION__, tx_prod, tx_chain_prod, sc->tx_prod_bseq);
4818157642Sps
4819157642Sps	/* Start the transmit. */
4820157642Sps	REG_WR16(sc, MB_TX_CID_ADDR + BCE_L2CTX_TX_HOST_BIDX, sc->tx_prod);
4821157642Sps	REG_WR(sc, MB_TX_CID_ADDR + BCE_L2CTX_TX_HOST_BSEQ, sc->tx_prod_bseq);
4822157642Sps
4823157642Sps	/* Set the tx timeout. */
4824157642Sps	ifp->if_timer = BCE_TX_TIMEOUT;
4825157642Sps
4826157642Spsbce_start_locked_exit:
4827157642Sps	return;
4828157642Sps}
4829157642Sps
4830157642Sps
4831157642Sps/****************************************************************************/
4832157642Sps/* Main transmit routine when called from another routine without a lock.   */
4833157642Sps/*                                                                          */
4834157642Sps/* Returns:                                                                 */
4835157642Sps/*   Nothing.                                                               */
4836157642Sps/****************************************************************************/
4837157642Spsstatic void
4838157642Spsbce_start(struct ifnet *ifp)
4839157642Sps{
4840157642Sps	struct bce_softc *sc = ifp->if_softc;
4841157642Sps
4842157642Sps	BCE_LOCK(sc);
4843157642Sps	bce_start_locked(ifp);
4844157642Sps	BCE_UNLOCK(sc);
4845157642Sps}
4846157642Sps
4847157642Sps
4848157642Sps/****************************************************************************/
4849157642Sps/* Handles any IOCTL calls from the operating system.                       */
4850157642Sps/*                                                                          */
4851157642Sps/* Returns:                                                                 */
4852157642Sps/*   0 for success, positive value for failure.                             */
4853157642Sps/****************************************************************************/
4854157642Spsstatic int
4855157642Spsbce_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
4856157642Sps{
4857157642Sps	struct bce_softc *sc = ifp->if_softc;
4858157642Sps	struct ifreq *ifr = (struct ifreq *) data;
4859157642Sps	struct mii_data *mii;
4860157642Sps	int mask, error = 0;
4861157642Sps
4862157642Sps	DBPRINT(sc, BCE_VERBOSE_RESET, "Entering %s()\n", __FUNCTION__);
4863157642Sps
4864157642Sps	switch(command) {
4865157642Sps
4866157642Sps		/* Set the MTU. */
4867157642Sps		case SIOCSIFMTU:
4868157642Sps			/* Check that the MTU setting is supported. */
4869157642Sps			if ((ifr->ifr_mtu < BCE_MIN_MTU) ||
4870157642Sps				(ifr->ifr_mtu > BCE_MAX_JUMBO_MTU)) {
4871157642Sps				error = EINVAL;
4872157642Sps				break;
4873157642Sps			}
4874157642Sps
4875157642Sps			DBPRINT(sc, BCE_INFO, "Setting new MTU of %d\n", ifr->ifr_mtu);
4876157642Sps
4877160526Sjhb			BCE_LOCK(sc);
4878157642Sps			ifp->if_mtu = ifr->ifr_mtu;
4879157642Sps			ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
4880160526Sjhb			bce_init_locked(sc);
4881160526Sjhb			BCE_UNLOCK(sc);
4882157642Sps			break;
4883157642Sps
4884157642Sps		/* Set interface. */
4885157642Sps		case SIOCSIFFLAGS:
4886157642Sps			DBPRINT(sc, BCE_VERBOSE, "Received SIOCSIFFLAGS\n");
4887157642Sps
4888157642Sps			BCE_LOCK(sc);
4889157642Sps
4890157642Sps			/* Check if the interface is up. */
4891157642Sps			if (ifp->if_flags & IFF_UP) {
4892160315Sambrisko				if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
4893160315Sambrisko					/* Change the promiscuous/multicast flags as necessary. */
4894160315Sambrisko					bce_set_rx_mode(sc);
4895160315Sambrisko				} else {
4896160315Sambrisko					/* Start the HW */
4897160315Sambrisko					bce_init_locked(sc);
4898160315Sambrisko				}
4899157642Sps			} else {
4900157642Sps				/* The interface is down.  Check if the driver is running. */
4901157642Sps				if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
4902157642Sps					bce_stop(sc);
4903157642Sps				}
4904157642Sps			}
4905157642Sps
4906157642Sps			BCE_UNLOCK(sc);
4907157642Sps			error = 0;
4908157642Sps
4909157642Sps			break;
4910157642Sps
4911157642Sps		/* Add/Delete multicast address */
4912157642Sps		case SIOCADDMULTI:
4913157642Sps		case SIOCDELMULTI:
4914157642Sps			DBPRINT(sc, BCE_VERBOSE, "Received SIOCADDMULTI/SIOCDELMULTI\n");
4915157642Sps
4916160526Sjhb			BCE_LOCK(sc);
4917157642Sps			if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
4918157642Sps				bce_set_rx_mode(sc);
4919157642Sps				error = 0;
4920157642Sps			}
4921160526Sjhb			BCE_UNLOCK(sc);
4922157642Sps
4923157642Sps			break;
4924157642Sps
4925157642Sps		/* Set/Get Interface media */
4926157642Sps		case SIOCSIFMEDIA:
4927157642Sps		case SIOCGIFMEDIA:
4928157642Sps			DBPRINT(sc, BCE_VERBOSE, "Received SIOCSIFMEDIA/SIOCGIFMEDIA\n");
4929157642Sps
4930157642Sps			DBPRINT(sc, BCE_VERBOSE, "bce_phy_flags = 0x%08X\n",
4931157642Sps				sc->bce_phy_flags);
4932157642Sps
4933157642Sps			if (sc->bce_phy_flags & BCE_PHY_SERDES_FLAG) {
4934157642Sps				DBPRINT(sc, BCE_VERBOSE, "SerDes media set/get\n");
4935157642Sps
4936157642Sps				error = ifmedia_ioctl(ifp, ifr,
4937157642Sps				    &sc->bce_ifmedia, command);
4938157642Sps			} else {
4939157642Sps				DBPRINT(sc, BCE_VERBOSE, "Copper media set/get\n");
4940157642Sps				mii = device_get_softc(sc->bce_miibus);
4941157642Sps				error = ifmedia_ioctl(ifp, ifr,
4942157642Sps				    &mii->mii_media, command);
4943157642Sps			}
4944157642Sps			break;
4945157642Sps
4946157642Sps		/* Set interface capability */
4947157642Sps		case SIOCSIFCAP:
4948157642Sps			mask = ifr->ifr_reqcap ^ ifp->if_capenable;
4949157642Sps			DBPRINT(sc, BCE_INFO, "Received SIOCSIFCAP = 0x%08X\n", (u32) mask);
4950157642Sps
4951157642Sps#ifdef DEVICE_POLLING
4952157642Sps			if (mask & IFCAP_POLLING) {
4953157642Sps				if (ifr->ifr_reqcap & IFCAP_POLLING) {
4954157642Sps
4955157642Sps					/* Setup the poll routine to call. */
4956157642Sps					error = ether_poll_register(bce_poll, ifp);
4957157642Sps					if (error) {
4958157642Sps						BCE_PRINTF(sc, "%s(%d): Error registering poll function!\n",
4959157642Sps							__FILE__, __LINE__);
4960157642Sps						goto bce_ioctl_exit;
4961157642Sps					}
4962157642Sps
4963157642Sps					/* Clear the interrupt. */
4964157642Sps					BCE_LOCK(sc);
4965157642Sps					bce_disable_intr(sc);
4966157642Sps
4967157642Sps					REG_WR(sc, BCE_HC_RX_QUICK_CONS_TRIP,
4968157642Sps						(1 << 16) | sc->bce_rx_quick_cons_trip);
4969157642Sps					REG_WR(sc, BCE_HC_TX_QUICK_CONS_TRIP,
4970157642Sps						(1 << 16) | sc->bce_tx_quick_cons_trip);
4971157642Sps
4972157642Sps					ifp->if_capenable |= IFCAP_POLLING;
4973157642Sps					BCE_UNLOCK(sc);
4974157642Sps				} else {
4975157642Sps					/* Clear the poll routine. */
4976157642Sps					error = ether_poll_deregister(ifp);
4977157642Sps
4978157642Sps					/* Enable interrupt even in error case */
4979157642Sps					BCE_LOCK(sc);
4980157642Sps					bce_enable_intr(sc);
4981157642Sps
4982157642Sps					REG_WR(sc, BCE_HC_TX_QUICK_CONS_TRIP,
4983157642Sps						(sc->bce_tx_quick_cons_trip_int << 16) |
4984157642Sps						sc->bce_tx_quick_cons_trip);
4985157642Sps					REG_WR(sc, BCE_HC_RX_QUICK_CONS_TRIP,
4986157642Sps						(sc->bce_rx_quick_cons_trip_int << 16) |
4987157642Sps						sc->bce_rx_quick_cons_trip);
4988157642Sps
4989157642Sps					ifp->if_capenable &= ~IFCAP_POLLING;
4990157642Sps					BCE_UNLOCK(sc);
4991157642Sps				}
4992157642Sps			}
4993157642Sps#endif /*DEVICE_POLLING */
4994157642Sps
4995157642Sps			/* Toggle the TX checksum capabilites enable flag. */
4996157642Sps			if (mask & IFCAP_TXCSUM) {
4997157642Sps				ifp->if_capenable ^= IFCAP_TXCSUM;
4998157642Sps				if (IFCAP_TXCSUM & ifp->if_capenable)
4999157642Sps					ifp->if_hwassist = BCE_IF_HWASSIST;
5000157642Sps				else
5001157642Sps					ifp->if_hwassist = 0;
5002157642Sps			}
5003157642Sps
5004157642Sps			/* Toggle the RX checksum capabilities enable flag. */
5005157642Sps			if (mask & IFCAP_RXCSUM) {
5006157642Sps				ifp->if_capenable ^= IFCAP_RXCSUM;
5007157642Sps				if (IFCAP_RXCSUM & ifp->if_capenable)
5008157642Sps					ifp->if_hwassist = BCE_IF_HWASSIST;
5009157642Sps				else
5010157642Sps					ifp->if_hwassist = 0;
5011157642Sps			}
5012157642Sps
5013157642Sps			/* Toggle VLAN_MTU capabilities enable flag. */
5014157642Sps			if (mask & IFCAP_VLAN_MTU) {
5015157642Sps				BCE_PRINTF(sc, "%s(%d): Changing VLAN_MTU not supported.\n",
5016157642Sps					__FILE__, __LINE__);
5017157642Sps			}
5018157642Sps
5019157642Sps			/* Toggle VLANHWTAG capabilities enabled flag. */
5020157642Sps			if (mask & IFCAP_VLAN_HWTAGGING) {
5021157642Sps				if (sc->bce_flags & BCE_MFW_ENABLE_FLAG)
5022157642Sps					BCE_PRINTF(sc, "%s(%d): Cannot change VLAN_HWTAGGING while "
5023157642Sps						"management firmware (ASF/IPMI/UMP) is running!\n",
5024157642Sps						__FILE__, __LINE__);
5025157642Sps				else
5026157642Sps					BCE_PRINTF(sc, "%s(%d): Changing VLAN_HWTAGGING not supported!\n",
5027157642Sps						__FILE__, __LINE__);
5028157642Sps			}
5029157642Sps
5030157642Sps			break;
5031157642Sps		default:
5032157642Sps			DBPRINT(sc, BCE_INFO, "Received unsupported IOCTL: 0x%08X\n",
5033157642Sps				(u32) command);
5034157642Sps
5035157642Sps			/* We don't know how to handle the IOCTL, pass it on. */
5036157642Sps			error = ether_ioctl(ifp, command, data);
5037157642Sps			break;
5038157642Sps	}
5039157642Sps
5040157724Sru#ifdef DEVICE_POLLING
5041157724Srubce_ioctl_exit:
5042157724Sru#endif
5043157724Sru
5044157642Sps	DBPRINT(sc, BCE_VERBOSE_RESET, "Exiting %s()\n", __FUNCTION__);
5045157642Sps
5046157642Sps	return(error);
5047157642Sps}
5048157642Sps
5049157642Sps
5050157642Sps/****************************************************************************/
5051157642Sps/* Transmit timeout handler.                                                */
5052157642Sps/*                                                                          */
5053157642Sps/* Returns:                                                                 */
5054157642Sps/*   Nothing.                                                               */
5055157642Sps/****************************************************************************/
5056157642Spsstatic void
5057157642Spsbce_watchdog(struct ifnet *ifp)
5058157642Sps{
5059157642Sps	struct bce_softc *sc = ifp->if_softc;
5060157642Sps
5061157642Sps	DBRUN(BCE_WARN_SEND,
5062157642Sps		bce_dump_driver_state(sc);
5063157642Sps		bce_dump_status_block(sc));
5064157642Sps
5065157642Sps	BCE_PRINTF(sc, "%s(%d): Watchdog timeout occurred, resetting!\n",
5066157642Sps		__FILE__, __LINE__);
5067157642Sps
5068157642Sps	/* DBRUN(BCE_FATAL, bce_breakpoint(sc)); */
5069157642Sps
5070160526Sjhb	BCE_LOCK(sc);
5071157642Sps	ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
5072157642Sps
5073160526Sjhb	bce_init_locked(sc);
5074157642Sps	ifp->if_oerrors++;
5075160526Sjhb	BCE_UNLOCK(sc);
5076157642Sps
5077157642Sps}
5078157642Sps
5079157642Sps
5080157642Sps#ifdef DEVICE_POLLING
5081157642Spsstatic void
5082157642Spsbce_poll_locked(struct ifnet *ifp, enum poll_cmd cmd, int count)
5083157642Sps{
5084157642Sps	struct bce_softc *sc = ifp->if_softc;
5085157642Sps
5086157642Sps	BCE_LOCK_ASSERT(sc);
5087157642Sps
5088157642Sps	sc->bce_rxcycles = count;
5089157642Sps
5090157642Sps	bus_dmamap_sync(sc->status_tag, sc->status_map,
5091157642Sps	    BUS_DMASYNC_POSTWRITE);
5092157642Sps
5093157642Sps	/* Check for any completed RX frames. */
5094157642Sps	if (sc->status_block->status_rx_quick_consumer_index0 !=
5095157642Sps		sc->hw_rx_cons)
5096157642Sps		bce_rx_intr(sc);
5097157642Sps
5098157642Sps	/* Check for any completed TX frames. */
5099157642Sps	if (sc->status_block->status_tx_quick_consumer_index0 !=
5100157642Sps		sc->hw_tx_cons)
5101157642Sps		bce_tx_intr(sc);
5102157642Sps
5103157642Sps	/* Check for new frames to transmit. */
5104157642Sps	if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
5105157642Sps		bce_start_locked(ifp);
5106157642Sps
5107157642Sps}
5108157642Sps
5109157642Sps
5110157642Spsstatic void
5111157642Spsbce_poll(struct ifnet *ifp, enum poll_cmd cmd, int count)
5112157642Sps{
5113157642Sps	struct bce_softc *sc = ifp->if_softc;
5114157642Sps
5115157642Sps	BCE_LOCK(sc);
5116157642Sps	if (ifp->if_drv_flags & IFF_DRV_RUNNING)
5117157642Sps		bce_poll_locked(ifp, cmd, count);
5118157642Sps	BCE_UNLOCK(sc);
5119157642Sps}
5120157642Sps#endif /* DEVICE_POLLING */
5121157642Sps
5122157642Sps
5123157642Sps#if 0
5124157642Spsstatic inline int
5125157642Spsbce_has_work(struct bce_softc *sc)
5126157642Sps{
5127157642Sps	struct status_block *stat = sc->status_block;
5128157642Sps
5129157642Sps	if ((stat->status_rx_quick_consumer_index0 != sc->hw_rx_cons) ||
5130157642Sps	    (stat->status_tx_quick_consumer_index0 != sc->hw_tx_cons))
5131157642Sps		return 1;
5132157642Sps
5133157642Sps	if (((stat->status_attn_bits & STATUS_ATTN_BITS_LINK_STATE) != 0) !=
5134157642Sps	    bp->link_up)
5135157642Sps		return 1;
5136157642Sps
5137157642Sps	return 0;
5138157642Sps}
5139157642Sps#endif
5140157642Sps
5141157642Sps
5142157642Sps/*
5143157642Sps * Interrupt handler.
5144157642Sps */
5145157642Sps/****************************************************************************/
5146157642Sps/* Main interrupt entry point.  Verifies that the controller generated the  */
5147157642Sps/* interrupt and then calls a separate routine for handle the various       */
5148157642Sps/* interrupt causes (PHY, TX, RX).                                          */
5149157642Sps/*                                                                          */
5150157642Sps/* Returns:                                                                 */
5151157642Sps/*   0 for success, positive value for failure.                             */
5152157642Sps/****************************************************************************/
5153157642Spsstatic void
5154157642Spsbce_intr(void *xsc)
5155157642Sps{
5156157642Sps	struct bce_softc *sc;
5157157642Sps	struct ifnet *ifp;
5158157642Sps	u32 status_attn_bits;
5159157642Sps
5160157642Sps	sc = xsc;
5161157642Sps	ifp = sc->bce_ifp;
5162157642Sps
5163157642Sps	BCE_LOCK(sc);
5164157642Sps
5165157642Sps	DBRUNIF(1, sc->interrupts_generated++);
5166157642Sps
5167157642Sps#ifdef DEVICE_POLLING
5168157642Sps	if (ifp->if_capenable & IFCAP_POLLING) {
5169157642Sps		DBPRINT(sc, BCE_INFO, "Polling enabled!\n");
5170157642Sps		goto bce_intr_exit;
5171157642Sps	}
5172157642Sps#endif
5173157642Sps
5174157642Sps	bus_dmamap_sync(sc->status_tag, sc->status_map,
5175157642Sps	    BUS_DMASYNC_POSTWRITE);
5176157642Sps
5177157642Sps	/*
5178157642Sps	 * If the hardware status block index
5179157642Sps	 * matches the last value read by the
5180157642Sps	 * driver and we haven't asserted our
5181157642Sps	 * interrupt then there's nothing to do.
5182157642Sps	 */
5183157642Sps	if ((sc->status_block->status_idx == sc->last_status_idx) &&
5184157642Sps		(REG_RD(sc, BCE_PCICFG_MISC_STATUS) & BCE_PCICFG_MISC_STATUS_INTA_VALUE))
5185157642Sps		goto bce_intr_exit;
5186157642Sps
5187157642Sps	/* Ack the interrupt and stop others from occuring. */
5188157642Sps	REG_WR(sc, BCE_PCICFG_INT_ACK_CMD,
5189157642Sps		BCE_PCICFG_INT_ACK_CMD_USE_INT_HC_PARAM |
5190157642Sps		BCE_PCICFG_INT_ACK_CMD_MASK_INT);
5191157642Sps
5192157642Sps	/* Keep processing data as long as there is work to do. */
5193157642Sps	for (;;) {
5194157642Sps
5195157642Sps		status_attn_bits = sc->status_block->status_attn_bits;
5196157642Sps
5197157642Sps		DBRUNIF(DB_RANDOMTRUE(bce_debug_unexpected_attention),
5198157642Sps			BCE_PRINTF(sc, "Simulating unexpected status attention bit set.");
5199157642Sps			status_attn_bits = status_attn_bits | STATUS_ATTN_BITS_PARITY_ERROR);
5200157642Sps
5201157642Sps		/* Was it a link change interrupt? */
5202157642Sps		if ((status_attn_bits & STATUS_ATTN_BITS_LINK_STATE) !=
5203157642Sps			(sc->status_block->status_attn_bits_ack & STATUS_ATTN_BITS_LINK_STATE))
5204157642Sps			bce_phy_intr(sc);
5205157642Sps
5206157642Sps		/* If any other attention is asserted then the chip is toast. */
5207157642Sps		if (((status_attn_bits & ~STATUS_ATTN_BITS_LINK_STATE) !=
5208157642Sps			(sc->status_block->status_attn_bits_ack &
5209157642Sps			~STATUS_ATTN_BITS_LINK_STATE))) {
5210157642Sps
5211157642Sps			DBRUN(1, sc->unexpected_attentions++);
5212157642Sps
5213157642Sps			BCE_PRINTF(sc, "%s(%d): Fatal attention detected: 0x%08X\n",
5214157642Sps				__FILE__, __LINE__, sc->status_block->status_attn_bits);
5215157642Sps
5216157642Sps			DBRUN(BCE_FATAL,
5217157642Sps				if (bce_debug_unexpected_attention == 0)
5218157642Sps					bce_breakpoint(sc));
5219157642Sps
5220157642Sps			bce_init_locked(sc);
5221157642Sps			goto bce_intr_exit;
5222157642Sps		}
5223157642Sps
5224157642Sps		/* Check for any completed RX frames. */
5225157642Sps		if (sc->status_block->status_rx_quick_consumer_index0 != sc->hw_rx_cons)
5226157642Sps			bce_rx_intr(sc);
5227157642Sps
5228157642Sps		/* Check for any completed TX frames. */
5229157642Sps		if (sc->status_block->status_tx_quick_consumer_index0 != sc->hw_tx_cons)
5230157642Sps			bce_tx_intr(sc);
5231157642Sps
5232157642Sps		/* Save the status block index value for use during the next interrupt. */
5233157642Sps		sc->last_status_idx = sc->status_block->status_idx;
5234157642Sps
5235157642Sps		/* Prevent speculative reads from getting ahead of the status block. */
5236157642Sps		bus_space_barrier(sc->bce_btag, sc->bce_bhandle, 0, 0,
5237157642Sps			BUS_SPACE_BARRIER_READ);
5238157642Sps
5239157642Sps		/* If there's no work left then exit the interrupt service routine. */
5240157642Sps		if ((sc->status_block->status_rx_quick_consumer_index0 == sc->hw_rx_cons) &&
5241157642Sps	    	(sc->status_block->status_tx_quick_consumer_index0 == sc->hw_tx_cons))
5242157642Sps			break;
5243157642Sps
5244157642Sps	}
5245157642Sps
5246157642Sps	bus_dmamap_sync(sc->status_tag,	sc->status_map,
5247157642Sps	    BUS_DMASYNC_PREWRITE);
5248157642Sps
5249157642Sps	/* Re-enable interrupts. */
5250157642Sps	REG_WR(sc, BCE_PCICFG_INT_ACK_CMD,
5251157642Sps	       BCE_PCICFG_INT_ACK_CMD_INDEX_VALID | sc->last_status_idx |
5252157642Sps	       BCE_PCICFG_INT_ACK_CMD_MASK_INT);
5253157642Sps	REG_WR(sc, BCE_PCICFG_INT_ACK_CMD,
5254157642Sps	       BCE_PCICFG_INT_ACK_CMD_INDEX_VALID | sc->last_status_idx);
5255157642Sps
5256157642Sps	/* Handle any frames that arrived while handling the interrupt. */
5257157642Sps	if (ifp->if_drv_flags & IFF_DRV_RUNNING && !IFQ_DRV_IS_EMPTY(&ifp->if_snd))
5258157642Sps		bce_start_locked(ifp);
5259157642Sps
5260157642Spsbce_intr_exit:
5261157642Sps	BCE_UNLOCK(sc);
5262157642Sps}
5263157642Sps
5264157642Sps
5265157642Sps/****************************************************************************/
5266157642Sps/* Programs the various packet receive modes (broadcast and multicast).     */
5267157642Sps/*                                                                          */
5268157642Sps/* Returns:                                                                 */
5269157642Sps/*   Nothing.                                                               */
5270157642Sps/****************************************************************************/
5271157642Spsstatic void
5272157642Spsbce_set_rx_mode(struct bce_softc *sc)
5273157642Sps{
5274157642Sps	struct ifnet *ifp;
5275157642Sps	struct ifmultiaddr *ifma;
5276157642Sps	u32 hashes[4] = { 0, 0, 0, 0 };
5277157642Sps	u32 rx_mode, sort_mode;
5278157642Sps	int h, i;
5279157642Sps
5280157642Sps	BCE_LOCK_ASSERT(sc);
5281157642Sps
5282157642Sps	ifp = sc->bce_ifp;
5283157642Sps
5284157642Sps	/* Initialize receive mode default settings. */
5285157642Sps	rx_mode   = sc->rx_mode & ~(BCE_EMAC_RX_MODE_PROMISCUOUS |
5286157642Sps			    BCE_EMAC_RX_MODE_KEEP_VLAN_TAG);
5287157642Sps	sort_mode = 1 | BCE_RPM_SORT_USER0_BC_EN;
5288157642Sps
5289157642Sps	/*
5290157642Sps	 * ASF/IPMI/UMP firmware requires that VLAN tag stripping
5291157642Sps	 * be enbled.
5292157642Sps	 */
5293157642Sps	if (!(BCE_IF_CAPABILITIES & IFCAP_VLAN_HWTAGGING) &&
5294157642Sps		(!(sc->bce_flags & BCE_MFW_ENABLE_FLAG)))
5295157642Sps		rx_mode |= BCE_EMAC_RX_MODE_KEEP_VLAN_TAG;
5296157642Sps
5297157642Sps	/*
5298157642Sps	 * Check for promiscuous, all multicast, or selected
5299157642Sps	 * multicast address filtering.
5300157642Sps	 */
5301157642Sps	if (ifp->if_flags & IFF_PROMISC) {
5302157642Sps		DBPRINT(sc, BCE_INFO, "Enabling promiscuous mode.\n");
5303157642Sps
5304157642Sps		/* Enable promiscuous mode. */
5305157642Sps		rx_mode |= BCE_EMAC_RX_MODE_PROMISCUOUS;
5306157642Sps		sort_mode |= BCE_RPM_SORT_USER0_PROM_EN;
5307157642Sps	} else if (ifp->if_flags & IFF_ALLMULTI) {
5308157642Sps		DBPRINT(sc, BCE_INFO, "Enabling all multicast mode.\n");
5309157642Sps
5310157642Sps		/* Enable all multicast addresses. */
5311157642Sps		for (i = 0; i < NUM_MC_HASH_REGISTERS; i++) {
5312157642Sps			REG_WR(sc, BCE_EMAC_MULTICAST_HASH0 + (i * 4), 0xffffffff);
5313157642Sps       	}
5314157642Sps		sort_mode |= BCE_RPM_SORT_USER0_MC_EN;
5315157642Sps	} else {
5316157642Sps		/* Accept one or more multicast(s). */
5317157642Sps		DBPRINT(sc, BCE_INFO, "Enabling selective multicast mode.\n");
5318157642Sps
5319157642Sps		IF_ADDR_LOCK(ifp);
5320157642Sps		TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
5321157642Sps			if (ifma->ifma_addr->sa_family != AF_LINK)
5322157642Sps				continue;
5323157642Sps			h = ether_crc32_le(LLADDR((struct sockaddr_dl *)
5324157642Sps		    	ifma->ifma_addr), ETHER_ADDR_LEN) & 0x7F;
5325157642Sps			hashes[(h & 0x60) >> 5] |= 1 << (h & 0x1F);
5326157642Sps		}
5327157642Sps		IF_ADDR_UNLOCK(ifp);
5328157642Sps
5329157642Sps		for (i = 0; i < 4; i++)
5330157642Sps			REG_WR(sc, BCE_EMAC_MULTICAST_HASH0 + (i * 4), hashes[i]);
5331157642Sps
5332157642Sps		sort_mode |= BCE_RPM_SORT_USER0_MC_HSH_EN;
5333157642Sps	}
5334157642Sps
5335157642Sps	/* Only make changes if the recive mode has actually changed. */
5336157642Sps	if (rx_mode != sc->rx_mode) {
5337157642Sps		DBPRINT(sc, BCE_VERBOSE, "Enabling new receive mode: 0x%08X\n",
5338157642Sps			rx_mode);
5339157642Sps
5340157642Sps		sc->rx_mode = rx_mode;
5341157642Sps		REG_WR(sc, BCE_EMAC_RX_MODE, rx_mode);
5342157642Sps	}
5343157642Sps
5344157642Sps	/* Disable and clear the exisitng sort before enabling a new sort. */
5345157642Sps	REG_WR(sc, BCE_RPM_SORT_USER0, 0x0);
5346157642Sps	REG_WR(sc, BCE_RPM_SORT_USER0, sort_mode);
5347157642Sps	REG_WR(sc, BCE_RPM_SORT_USER0, sort_mode | BCE_RPM_SORT_USER0_ENA);
5348157642Sps}
5349157642Sps
5350157642Sps
5351157642Sps/****************************************************************************/
5352157642Sps/* Called periodically to updates statistics from the controllers           */
5353157642Sps/* statistics block.                                                        */
5354157642Sps/*                                                                          */
5355157642Sps/* Returns:                                                                 */
5356157642Sps/*   Nothing.                                                               */
5357157642Sps/****************************************************************************/
5358157642Spsstatic void
5359157642Spsbce_stats_update(struct bce_softc *sc)
5360157642Sps{
5361157642Sps	struct ifnet *ifp;
5362157642Sps	struct statistics_block *stats;
5363157642Sps
5364157642Sps	DBPRINT(sc, BCE_EXCESSIVE, "Entering %s()\n", __FUNCTION__);
5365157642Sps
5366157642Sps	ifp = sc->bce_ifp;
5367157642Sps
5368157642Sps	stats = (struct statistics_block *) sc->stats_block;
5369157642Sps
5370157642Sps	/*
5371157642Sps	 * Update the interface statistics from the
5372157642Sps	 * hardware statistics.
5373157642Sps	 */
5374157642Sps	ifp->if_collisions = (u_long) stats->stat_EtherStatsCollisions;
5375157642Sps
5376157642Sps	ifp->if_ierrors = (u_long) stats->stat_EtherStatsUndersizePkts +
5377157642Sps				      (u_long) stats->stat_EtherStatsOverrsizePkts +
5378157642Sps					  (u_long) stats->stat_IfInMBUFDiscards +
5379157642Sps					  (u_long) stats->stat_Dot3StatsAlignmentErrors +
5380157642Sps					  (u_long) stats->stat_Dot3StatsFCSErrors;
5381157642Sps
5382157642Sps	ifp->if_oerrors = (u_long) stats->stat_emac_tx_stat_dot3statsinternalmactransmiterrors +
5383157642Sps					  (u_long) stats->stat_Dot3StatsExcessiveCollisions +
5384157642Sps					  (u_long) stats->stat_Dot3StatsLateCollisions;
5385157642Sps
5386157642Sps	/*
5387157642Sps	 * Certain controllers don't report
5388157642Sps	 * carrier sense errors correctly.
5389157642Sps	 * See errata E11_5708CA0_1165.
5390157642Sps	 */
5391157642Sps	if (!(BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5706) &&
5392157642Sps	    !(BCE_CHIP_ID(sc) == BCE_CHIP_ID_5708_A0))
5393157642Sps		ifp->if_oerrors += (u_long) stats->stat_Dot3StatsCarrierSenseErrors;
5394157642Sps
5395157642Sps	/*
5396157642Sps	 * Update the sysctl statistics from the
5397157642Sps	 * hardware statistics.
5398157642Sps	 */
5399157642Sps	sc->stat_IfHCInOctets =
5400157642Sps		((u64) stats->stat_IfHCInOctets_hi << 32) +
5401157642Sps		 (u64) stats->stat_IfHCInOctets_lo;
5402157642Sps
5403157642Sps	sc->stat_IfHCInBadOctets =
5404157642Sps		((u64) stats->stat_IfHCInBadOctets_hi << 32) +
5405157642Sps		 (u64) stats->stat_IfHCInBadOctets_lo;
5406157642Sps
5407157642Sps	sc->stat_IfHCOutOctets =
5408157642Sps		((u64) stats->stat_IfHCOutOctets_hi << 32) +
5409157642Sps		 (u64) stats->stat_IfHCOutOctets_lo;
5410157642Sps
5411157642Sps	sc->stat_IfHCOutBadOctets =
5412157642Sps		((u64) stats->stat_IfHCOutBadOctets_hi << 32) +
5413157642Sps		 (u64) stats->stat_IfHCOutBadOctets_lo;
5414157642Sps
5415157642Sps	sc->stat_IfHCInUcastPkts =
5416157642Sps		((u64) stats->stat_IfHCInUcastPkts_hi << 32) +
5417157642Sps		 (u64) stats->stat_IfHCInUcastPkts_lo;
5418157642Sps
5419157642Sps	sc->stat_IfHCInMulticastPkts =
5420157642Sps		((u64) stats->stat_IfHCInMulticastPkts_hi << 32) +
5421157642Sps		 (u64) stats->stat_IfHCInMulticastPkts_lo;
5422157642Sps
5423157642Sps	sc->stat_IfHCInBroadcastPkts =
5424157642Sps		((u64) stats->stat_IfHCInBroadcastPkts_hi << 32) +
5425157642Sps		 (u64) stats->stat_IfHCInBroadcastPkts_lo;
5426157642Sps
5427157642Sps	sc->stat_IfHCOutUcastPkts =
5428157642Sps		((u64) stats->stat_IfHCOutUcastPkts_hi << 32) +
5429157642Sps		 (u64) stats->stat_IfHCOutUcastPkts_lo;
5430157642Sps
5431157642Sps	sc->stat_IfHCOutMulticastPkts =
5432157642Sps		((u64) stats->stat_IfHCOutMulticastPkts_hi << 32) +
5433157642Sps		 (u64) stats->stat_IfHCOutMulticastPkts_lo;
5434157642Sps
5435157642Sps	sc->stat_IfHCOutBroadcastPkts =
5436157642Sps		((u64) stats->stat_IfHCOutBroadcastPkts_hi << 32) +
5437157642Sps		 (u64) stats->stat_IfHCOutBroadcastPkts_lo;
5438157642Sps
5439157642Sps	sc->stat_emac_tx_stat_dot3statsinternalmactransmiterrors =
5440157642Sps		stats->stat_emac_tx_stat_dot3statsinternalmactransmiterrors;
5441157642Sps
5442157642Sps	sc->stat_Dot3StatsCarrierSenseErrors =
5443157642Sps		stats->stat_Dot3StatsCarrierSenseErrors;
5444157642Sps
5445157642Sps	sc->stat_Dot3StatsFCSErrors =
5446157642Sps		stats->stat_Dot3StatsFCSErrors;
5447157642Sps
5448157642Sps	sc->stat_Dot3StatsAlignmentErrors =
5449157642Sps		stats->stat_Dot3StatsAlignmentErrors;
5450157642Sps
5451157642Sps	sc->stat_Dot3StatsSingleCollisionFrames =
5452157642Sps		stats->stat_Dot3StatsSingleCollisionFrames;
5453157642Sps
5454157642Sps	sc->stat_Dot3StatsMultipleCollisionFrames =
5455157642Sps		stats->stat_Dot3StatsMultipleCollisionFrames;
5456157642Sps
5457157642Sps	sc->stat_Dot3StatsDeferredTransmissions =
5458157642Sps		stats->stat_Dot3StatsDeferredTransmissions;
5459157642Sps
5460157642Sps	sc->stat_Dot3StatsExcessiveCollisions =
5461157642Sps		stats->stat_Dot3StatsExcessiveCollisions;
5462157642Sps
5463157642Sps	sc->stat_Dot3StatsLateCollisions =
5464157642Sps		stats->stat_Dot3StatsLateCollisions;
5465157642Sps
5466157642Sps	sc->stat_EtherStatsCollisions =
5467157642Sps		stats->stat_EtherStatsCollisions;
5468157642Sps
5469157642Sps	sc->stat_EtherStatsFragments =
5470157642Sps		stats->stat_EtherStatsFragments;
5471157642Sps
5472157642Sps	sc->stat_EtherStatsJabbers =
5473157642Sps		stats->stat_EtherStatsJabbers;
5474157642Sps
5475157642Sps	sc->stat_EtherStatsUndersizePkts =
5476157642Sps		stats->stat_EtherStatsUndersizePkts;
5477157642Sps
5478157642Sps	sc->stat_EtherStatsOverrsizePkts =
5479157642Sps		stats->stat_EtherStatsOverrsizePkts;
5480157642Sps
5481157642Sps	sc->stat_EtherStatsPktsRx64Octets =
5482157642Sps		stats->stat_EtherStatsPktsRx64Octets;
5483157642Sps
5484157642Sps	sc->stat_EtherStatsPktsRx65Octetsto127Octets =
5485157642Sps		stats->stat_EtherStatsPktsRx65Octetsto127Octets;
5486157642Sps
5487157642Sps	sc->stat_EtherStatsPktsRx128Octetsto255Octets =
5488157642Sps		stats->stat_EtherStatsPktsRx128Octetsto255Octets;
5489157642Sps
5490157642Sps	sc->stat_EtherStatsPktsRx256Octetsto511Octets =
5491157642Sps		stats->stat_EtherStatsPktsRx256Octetsto511Octets;
5492157642Sps
5493157642Sps	sc->stat_EtherStatsPktsRx512Octetsto1023Octets =
5494157642Sps		stats->stat_EtherStatsPktsRx512Octetsto1023Octets;
5495157642Sps
5496157642Sps	sc->stat_EtherStatsPktsRx1024Octetsto1522Octets =
5497157642Sps		stats->stat_EtherStatsPktsRx1024Octetsto1522Octets;
5498157642Sps
5499157642Sps	sc->stat_EtherStatsPktsRx1523Octetsto9022Octets =
5500157642Sps		stats->stat_EtherStatsPktsRx1523Octetsto9022Octets;
5501157642Sps
5502157642Sps	sc->stat_EtherStatsPktsTx64Octets =
5503157642Sps		stats->stat_EtherStatsPktsTx64Octets;
5504157642Sps
5505157642Sps	sc->stat_EtherStatsPktsTx65Octetsto127Octets =
5506157642Sps		stats->stat_EtherStatsPktsTx65Octetsto127Octets;
5507157642Sps
5508157642Sps	sc->stat_EtherStatsPktsTx128Octetsto255Octets =
5509157642Sps		stats->stat_EtherStatsPktsTx128Octetsto255Octets;
5510157642Sps
5511157642Sps	sc->stat_EtherStatsPktsTx256Octetsto511Octets =
5512157642Sps		stats->stat_EtherStatsPktsTx256Octetsto511Octets;
5513157642Sps
5514157642Sps	sc->stat_EtherStatsPktsTx512Octetsto1023Octets =
5515157642Sps		stats->stat_EtherStatsPktsTx512Octetsto1023Octets;
5516157642Sps
5517157642Sps	sc->stat_EtherStatsPktsTx1024Octetsto1522Octets =
5518157642Sps		stats->stat_EtherStatsPktsTx1024Octetsto1522Octets;
5519157642Sps
5520157642Sps	sc->stat_EtherStatsPktsTx1523Octetsto9022Octets =
5521157642Sps		stats->stat_EtherStatsPktsTx1523Octetsto9022Octets;
5522157642Sps
5523157642Sps	sc->stat_XonPauseFramesReceived =
5524157642Sps		stats->stat_XonPauseFramesReceived;
5525157642Sps
5526157642Sps	sc->stat_XoffPauseFramesReceived =
5527157642Sps		stats->stat_XoffPauseFramesReceived;
5528157642Sps
5529157642Sps	sc->stat_OutXonSent =
5530157642Sps		stats->stat_OutXonSent;
5531157642Sps
5532157642Sps	sc->stat_OutXoffSent =
5533157642Sps		stats->stat_OutXoffSent;
5534157642Sps
5535157642Sps	sc->stat_FlowControlDone =
5536157642Sps		stats->stat_FlowControlDone;
5537157642Sps
5538157642Sps	sc->stat_MacControlFramesReceived =
5539157642Sps		stats->stat_MacControlFramesReceived;
5540157642Sps
5541157642Sps	sc->stat_XoffStateEntered =
5542157642Sps		stats->stat_XoffStateEntered;
5543157642Sps
5544157642Sps	sc->stat_IfInFramesL2FilterDiscards =
5545157642Sps		stats->stat_IfInFramesL2FilterDiscards;
5546157642Sps
5547157642Sps	sc->stat_IfInRuleCheckerDiscards =
5548157642Sps		stats->stat_IfInRuleCheckerDiscards;
5549157642Sps
5550157642Sps	sc->stat_IfInFTQDiscards =
5551157642Sps		stats->stat_IfInFTQDiscards;
5552157642Sps
5553157642Sps	sc->stat_IfInMBUFDiscards =
5554157642Sps		stats->stat_IfInMBUFDiscards;
5555157642Sps
5556157642Sps	sc->stat_IfInRuleCheckerP4Hit =
5557157642Sps		stats->stat_IfInRuleCheckerP4Hit;
5558157642Sps
5559157642Sps	sc->stat_CatchupInRuleCheckerDiscards =
5560157642Sps		stats->stat_CatchupInRuleCheckerDiscards;
5561157642Sps
5562157642Sps	sc->stat_CatchupInFTQDiscards =
5563157642Sps		stats->stat_CatchupInFTQDiscards;
5564157642Sps
5565157642Sps	sc->stat_CatchupInMBUFDiscards =
5566157642Sps		stats->stat_CatchupInMBUFDiscards;
5567157642Sps
5568157642Sps	sc->stat_CatchupInRuleCheckerP4Hit =
5569157642Sps		stats->stat_CatchupInRuleCheckerP4Hit;
5570157642Sps
5571157642Sps	DBPRINT(sc, BCE_EXCESSIVE, "Exiting %s()\n", __FUNCTION__);
5572157642Sps}
5573157642Sps
5574157642Sps
5575157642Spsstatic void
5576157642Spsbce_tick_locked(struct bce_softc *sc)
5577157642Sps{
5578157642Sps	struct mii_data *mii = NULL;
5579157642Sps	struct ifnet *ifp;
5580157642Sps	u32 msg;
5581157642Sps
5582157642Sps	ifp = sc->bce_ifp;
5583157642Sps
5584157642Sps	BCE_LOCK_ASSERT(sc);
5585157642Sps
5586157642Sps	/* Tell the firmware that the driver is still running. */
5587157642Sps#ifdef BCE_DEBUG
5588157642Sps	msg = (u32) BCE_DRV_MSG_DATA_PULSE_CODE_ALWAYS_ALIVE;
5589157642Sps#else
5590157642Sps	msg = (u32) ++sc->bce_fw_drv_pulse_wr_seq;
5591157642Sps#endif
5592157642Sps	REG_WR_IND(sc, sc->bce_shmem_base + BCE_DRV_PULSE_MB, msg);
5593157642Sps
5594157642Sps	/* Update the statistics from the hardware statistics block. */
5595157642Sps	bce_stats_update(sc);
5596157642Sps
5597157642Sps	/* Schedule the next tick. */
5598157642Sps	callout_reset(
5599157642Sps		&sc->bce_stat_ch,		/* callout */
5600157642Sps		hz, 					/* ticks */
5601157642Sps		bce_tick, 				/* function */
5602157642Sps		sc);					/* function argument */
5603157642Sps
5604157642Sps	/* If link is up already up then we're done. */
5605157642Sps	if (sc->bce_link)
5606157642Sps		goto bce_tick_locked_exit;
5607157642Sps
5608157642Sps	/* DRC - ToDo: Add SerDes support and check SerDes link here. */
5609157642Sps
5610157642Sps	mii = device_get_softc(sc->bce_miibus);
5611157642Sps	mii_tick(mii);
5612157642Sps
5613157642Sps	/* Check if the link has come up. */
5614157642Sps	if (!sc->bce_link && mii->mii_media_status & IFM_ACTIVE &&
5615157642Sps	    IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) {
5616157642Sps		sc->bce_link++;
5617157642Sps		if ((IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_T ||
5618157642Sps		    IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_SX) &&
5619157642Sps		    bootverbose)
5620157642Sps			BCE_PRINTF(sc, "Gigabit link up\n");
5621157642Sps		/* Now that link is up, handle any outstanding TX traffic. */
5622157642Sps		if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
5623157642Sps			bce_start_locked(ifp);
5624157642Sps	}
5625157642Sps
5626157642Spsbce_tick_locked_exit:
5627157642Sps	return;
5628157642Sps}
5629157642Sps
5630157642Sps
5631157642Spsstatic void
5632157642Spsbce_tick(void *xsc)
5633157642Sps{
5634157642Sps	struct bce_softc *sc;
5635157642Sps
5636157642Sps	sc = xsc;
5637157642Sps
5638157642Sps	BCE_LOCK(sc);
5639157642Sps	bce_tick_locked(sc);
5640157642Sps	BCE_UNLOCK(sc);
5641157642Sps}
5642157642Sps
5643157642Sps
5644157642Sps#ifdef BCE_DEBUG
5645157642Sps/****************************************************************************/
5646157642Sps/* Allows the driver state to be dumped through the sysctl interface.       */
5647157642Sps/*                                                                          */
5648157642Sps/* Returns:                                                                 */
5649157642Sps/*   0 for success, positive value for failure.                             */
5650157642Sps/****************************************************************************/
5651157642Spsstatic int
5652157642Spsbce_sysctl_driver_state(SYSCTL_HANDLER_ARGS)
5653157642Sps{
5654157642Sps        int error;
5655157642Sps        int result;
5656157642Sps        struct bce_softc *sc;
5657157642Sps
5658157642Sps        result = -1;
5659157642Sps        error = sysctl_handle_int(oidp, &result, 0, req);
5660157642Sps
5661157642Sps        if (error || !req->newptr)
5662157642Sps                return (error);
5663157642Sps
5664157642Sps        if (result == 1) {
5665157642Sps                sc = (struct bce_softc *)arg1;
5666157642Sps                bce_dump_driver_state(sc);
5667157642Sps        }
5668157642Sps
5669157642Sps        return error;
5670157642Sps}
5671157642Sps
5672157642Sps
5673157642Sps/****************************************************************************/
5674157642Sps/* Allows the hardware state to be dumped through the sysctl interface.     */
5675157642Sps/*                                                                          */
5676157642Sps/* Returns:                                                                 */
5677157642Sps/*   0 for success, positive value for failure.                             */
5678157642Sps/****************************************************************************/
5679157642Spsstatic int
5680157642Spsbce_sysctl_hw_state(SYSCTL_HANDLER_ARGS)
5681157642Sps{
5682157642Sps        int error;
5683157642Sps        int result;
5684157642Sps        struct bce_softc *sc;
5685157642Sps
5686157642Sps        result = -1;
5687157642Sps        error = sysctl_handle_int(oidp, &result, 0, req);
5688157642Sps
5689157642Sps        if (error || !req->newptr)
5690157642Sps                return (error);
5691157642Sps
5692157642Sps        if (result == 1) {
5693157642Sps                sc = (struct bce_softc *)arg1;
5694157642Sps                bce_dump_hw_state(sc);
5695157642Sps        }
5696157642Sps
5697157642Sps        return error;
5698157642Sps}
5699157642Sps
5700157642Sps
5701157642Sps/****************************************************************************/
5702157642Sps/*                                                                          */
5703157642Sps/*                                                                          */
5704157642Sps/* Returns:                                                                 */
5705157642Sps/*   0 for success, positive value for failure.                             */
5706157642Sps/****************************************************************************/
5707157642Spsstatic int
5708157642Spsbce_sysctl_dump_rx_chain(SYSCTL_HANDLER_ARGS)
5709157642Sps{
5710157642Sps        int error;
5711157642Sps        int result;
5712157642Sps        struct bce_softc *sc;
5713157642Sps
5714157642Sps        result = -1;
5715157642Sps        error = sysctl_handle_int(oidp, &result, 0, req);
5716157642Sps
5717157642Sps        if (error || !req->newptr)
5718157642Sps                return (error);
5719157642Sps
5720157642Sps        if (result == 1) {
5721157642Sps                sc = (struct bce_softc *)arg1;
5722157642Sps                bce_dump_rx_chain(sc, 0, USABLE_RX_BD);
5723157642Sps        }
5724157642Sps
5725157642Sps        return error;
5726157642Sps}
5727157642Sps
5728157642Sps
5729157642Sps/****************************************************************************/
5730157642Sps/*                                                                          */
5731157642Sps/*                                                                          */
5732157642Sps/* Returns:                                                                 */
5733157642Sps/*   0 for success, positive value for failure.                             */
5734157642Sps/****************************************************************************/
5735157642Spsstatic int
5736157642Spsbce_sysctl_breakpoint(SYSCTL_HANDLER_ARGS)
5737157642Sps{
5738157642Sps        int error;
5739157642Sps        int result;
5740157642Sps        struct bce_softc *sc;
5741157642Sps
5742157642Sps        result = -1;
5743157642Sps        error = sysctl_handle_int(oidp, &result, 0, req);
5744157642Sps
5745157642Sps        if (error || !req->newptr)
5746157642Sps                return (error);
5747157642Sps
5748157642Sps        if (result == 1) {
5749157642Sps                sc = (struct bce_softc *)arg1;
5750157642Sps                bce_breakpoint(sc);
5751157642Sps        }
5752157642Sps
5753157642Sps        return error;
5754157642Sps}
5755157642Sps#endif
5756157642Sps
5757157642Sps
5758157642Sps/****************************************************************************/
5759157642Sps/* Adds any sysctl parameters for tuning or debugging purposes.             */
5760157642Sps/*                                                                          */
5761157642Sps/* Returns:                                                                 */
5762157642Sps/*   0 for success, positive value for failure.                             */
5763157642Sps/****************************************************************************/
5764157642Spsstatic void
5765157642Spsbce_add_sysctls(struct bce_softc *sc)
5766157642Sps{
5767157642Sps	struct sysctl_ctx_list *ctx;
5768157642Sps	struct sysctl_oid_list *children;
5769157642Sps
5770157642Sps	ctx = device_get_sysctl_ctx(sc->bce_dev);
5771157642Sps	children = SYSCTL_CHILDREN(device_get_sysctl_tree(sc->bce_dev));
5772157642Sps
5773157642Sps	SYSCTL_ADD_STRING(ctx, children, OID_AUTO,
5774157642Sps		"driver_version",
5775157642Sps		CTLFLAG_RD, &bce_driver_version,
5776157642Sps		0, "bce driver version");
5777157642Sps
5778157642Sps#ifdef BCE_DEBUG
5779157642Sps	SYSCTL_ADD_INT(ctx, children, OID_AUTO,
5780157642Sps		"rx_low_watermark",
5781157642Sps		CTLFLAG_RD, &sc->rx_low_watermark,
5782157642Sps		0, "Lowest level of free rx_bd's");
5783157642Sps
5784157642Sps	SYSCTL_ADD_INT(ctx, children, OID_AUTO,
5785157642Sps		"tx_hi_watermark",
5786157642Sps		CTLFLAG_RD, &sc->tx_hi_watermark,
5787157642Sps		0, "Highest level of used tx_bd's");
5788157642Sps
5789157642Sps	SYSCTL_ADD_INT(ctx, children, OID_AUTO,
5790157642Sps		"l2fhdr_status_errors",
5791157642Sps		CTLFLAG_RD, &sc->l2fhdr_status_errors,
5792157642Sps		0, "l2_fhdr status errors");
5793157642Sps
5794157642Sps	SYSCTL_ADD_INT(ctx, children, OID_AUTO,
5795157642Sps		"unexpected_attentions",
5796157642Sps		CTLFLAG_RD, &sc->unexpected_attentions,
5797157642Sps		0, "unexpected attentions");
5798157642Sps
5799157642Sps	SYSCTL_ADD_INT(ctx, children, OID_AUTO,
5800157642Sps		"lost_status_block_updates",
5801157642Sps		CTLFLAG_RD, &sc->lost_status_block_updates,
5802157642Sps		0, "lost status block updates");
5803157642Sps
5804157642Sps	SYSCTL_ADD_INT(ctx, children, OID_AUTO,
5805157642Sps		"mbuf_alloc_failed",
5806157642Sps		CTLFLAG_RD, &sc->mbuf_alloc_failed,
5807157642Sps		0, "mbuf cluster allocation failures");
5808157642Sps#endif
5809157642Sps
5810157642Sps	SYSCTL_ADD_ULONG(ctx, children, OID_AUTO,
5811157642Sps		"stat_IfHcInOctets",
5812157642Sps		CTLFLAG_RD, &sc->stat_IfHCInOctets,
5813157642Sps		"Bytes received");
5814157642Sps
5815157642Sps	SYSCTL_ADD_ULONG(ctx, children, OID_AUTO,
5816157642Sps		"stat_IfHCInBadOctets",
5817157642Sps		CTLFLAG_RD, &sc->stat_IfHCInBadOctets,
5818157642Sps		"Bad bytes received");
5819157642Sps
5820157642Sps	SYSCTL_ADD_ULONG(ctx, children, OID_AUTO,
5821157642Sps		"stat_IfHCOutOctets",
5822157642Sps		CTLFLAG_RD, &sc->stat_IfHCOutOctets,
5823157642Sps		"Bytes sent");
5824157642Sps
5825157642Sps	SYSCTL_ADD_ULONG(ctx, children, OID_AUTO,
5826157642Sps		"stat_IfHCOutBadOctets",
5827157642Sps		CTLFLAG_RD, &sc->stat_IfHCOutBadOctets,
5828157642Sps		"Bad bytes sent");
5829157642Sps
5830157642Sps	SYSCTL_ADD_ULONG(ctx, children, OID_AUTO,
5831157642Sps		"stat_IfHCInUcastPkts",
5832157642Sps		CTLFLAG_RD, &sc->stat_IfHCInUcastPkts,
5833157642Sps		"Unicast packets received");
5834157642Sps
5835157642Sps	SYSCTL_ADD_ULONG(ctx, children, OID_AUTO,
5836157642Sps		"stat_IfHCInMulticastPkts",
5837157642Sps		CTLFLAG_RD, &sc->stat_IfHCInMulticastPkts,
5838157642Sps		"Multicast packets received");
5839157642Sps
5840157642Sps	SYSCTL_ADD_ULONG(ctx, children, OID_AUTO,
5841157642Sps		"stat_IfHCInBroadcastPkts",
5842157642Sps		CTLFLAG_RD, &sc->stat_IfHCInBroadcastPkts,
5843157642Sps		"Broadcast packets received");
5844157642Sps
5845157642Sps	SYSCTL_ADD_ULONG(ctx, children, OID_AUTO,
5846157642Sps		"stat_IfHCOutUcastPkts",
5847157642Sps		CTLFLAG_RD, &sc->stat_IfHCOutUcastPkts,
5848157642Sps		"Unicast packets sent");
5849157642Sps
5850157642Sps	SYSCTL_ADD_ULONG(ctx, children, OID_AUTO,
5851157642Sps		"stat_IfHCOutMulticastPkts",
5852157642Sps		CTLFLAG_RD, &sc->stat_IfHCOutMulticastPkts,
5853157642Sps		"Multicast packets sent");
5854157642Sps
5855157642Sps	SYSCTL_ADD_ULONG(ctx, children, OID_AUTO,
5856157642Sps		"stat_IfHCOutBroadcastPkts",
5857157642Sps		CTLFLAG_RD, &sc->stat_IfHCOutBroadcastPkts,
5858157642Sps		"Broadcast packets sent");
5859157642Sps
5860157642Sps	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
5861157642Sps		"stat_emac_tx_stat_dot3statsinternalmactransmiterrors",
5862157642Sps		CTLFLAG_RD, &sc->stat_emac_tx_stat_dot3statsinternalmactransmiterrors,
5863157642Sps		0, "Internal MAC transmit errors");
5864157642Sps
5865157642Sps	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
5866157642Sps		"stat_Dot3StatsCarrierSenseErrors",
5867157642Sps		CTLFLAG_RD, &sc->stat_Dot3StatsCarrierSenseErrors,
5868157642Sps		0, "Carrier sense errors");
5869157642Sps
5870157642Sps	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
5871157642Sps		"stat_Dot3StatsFCSErrors",
5872157642Sps		CTLFLAG_RD, &sc->stat_Dot3StatsFCSErrors,
5873157642Sps		0, "Frame check sequence errors");
5874157642Sps
5875157642Sps	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
5876157642Sps		"stat_Dot3StatsAlignmentErrors",
5877157642Sps		CTLFLAG_RD, &sc->stat_Dot3StatsAlignmentErrors,
5878157642Sps		0, "Alignment errors");
5879157642Sps
5880157642Sps	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
5881157642Sps		"stat_Dot3StatsSingleCollisionFrames",
5882157642Sps		CTLFLAG_RD, &sc->stat_Dot3StatsSingleCollisionFrames,
5883157642Sps		0, "Single Collision Frames");
5884157642Sps
5885157642Sps	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
5886157642Sps		"stat_Dot3StatsMultipleCollisionFrames",
5887157642Sps		CTLFLAG_RD, &sc->stat_Dot3StatsMultipleCollisionFrames,
5888157642Sps		0, "Multiple Collision Frames");
5889157642Sps
5890157642Sps	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
5891157642Sps		"stat_Dot3StatsDeferredTransmissions",
5892157642Sps		CTLFLAG_RD, &sc->stat_Dot3StatsDeferredTransmissions,
5893157642Sps		0, "Deferred Transmissions");
5894157642Sps
5895157642Sps	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
5896157642Sps		"stat_Dot3StatsExcessiveCollisions",
5897157642Sps		CTLFLAG_RD, &sc->stat_Dot3StatsExcessiveCollisions,
5898157642Sps		0, "Excessive Collisions");
5899157642Sps
5900157642Sps	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
5901157642Sps		"stat_Dot3StatsLateCollisions",
5902157642Sps		CTLFLAG_RD, &sc->stat_Dot3StatsLateCollisions,
5903157642Sps		0, "Late Collisions");
5904157642Sps
5905157642Sps	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
5906157642Sps		"stat_EtherStatsCollisions",
5907157642Sps		CTLFLAG_RD, &sc->stat_EtherStatsCollisions,
5908157642Sps		0, "Collisions");
5909157642Sps
5910157642Sps	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
5911157642Sps		"stat_EtherStatsFragments",
5912157642Sps		CTLFLAG_RD, &sc->stat_EtherStatsFragments,
5913157642Sps		0, "Fragments");
5914157642Sps
5915157642Sps	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
5916157642Sps		"stat_EtherStatsJabbers",
5917157642Sps		CTLFLAG_RD, &sc->stat_EtherStatsJabbers,
5918157642Sps		0, "Jabbers");
5919157642Sps
5920157642Sps	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
5921157642Sps		"stat_EtherStatsUndersizePkts",
5922157642Sps		CTLFLAG_RD, &sc->stat_EtherStatsUndersizePkts,
5923157642Sps		0, "Undersize packets");
5924157642Sps
5925157642Sps	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
5926157642Sps		"stat_EtherStatsOverrsizePkts",
5927157642Sps		CTLFLAG_RD, &sc->stat_EtherStatsOverrsizePkts,
5928157642Sps		0, "stat_EtherStatsOverrsizePkts");
5929157642Sps
5930157642Sps	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
5931157642Sps		"stat_EtherStatsPktsRx64Octets",
5932157642Sps		CTLFLAG_RD, &sc->stat_EtherStatsPktsRx64Octets,
5933157642Sps		0, "Bytes received in 64 byte packets");
5934157642Sps
5935157642Sps	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
5936157642Sps		"stat_EtherStatsPktsRx65Octetsto127Octets",
5937157642Sps		CTLFLAG_RD, &sc->stat_EtherStatsPktsRx65Octetsto127Octets,
5938157642Sps		0, "Bytes received in 65 to 127 byte packets");
5939157642Sps
5940157642Sps	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
5941157642Sps		"stat_EtherStatsPktsRx128Octetsto255Octets",
5942157642Sps		CTLFLAG_RD, &sc->stat_EtherStatsPktsRx128Octetsto255Octets,
5943157642Sps		0, "Bytes received in 128 to 255 byte packets");
5944157642Sps
5945157642Sps	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
5946157642Sps		"stat_EtherStatsPktsRx256Octetsto511Octets",
5947157642Sps		CTLFLAG_RD, &sc->stat_EtherStatsPktsRx256Octetsto511Octets,
5948157642Sps		0, "Bytes received in 256 to 511 byte packets");
5949157642Sps
5950157642Sps	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
5951157642Sps		"stat_EtherStatsPktsRx512Octetsto1023Octets",
5952157642Sps		CTLFLAG_RD, &sc->stat_EtherStatsPktsRx512Octetsto1023Octets,
5953157642Sps		0, "Bytes received in 512 to 1023 byte packets");
5954157642Sps
5955157642Sps	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
5956157642Sps		"stat_EtherStatsPktsRx1024Octetsto1522Octets",
5957157642Sps		CTLFLAG_RD, &sc->stat_EtherStatsPktsRx1024Octetsto1522Octets,
5958157642Sps		0, "Bytes received in 1024 t0 1522 byte packets");
5959157642Sps
5960157642Sps	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
5961157642Sps		"stat_EtherStatsPktsRx1523Octetsto9022Octets",
5962157642Sps		CTLFLAG_RD, &sc->stat_EtherStatsPktsRx1523Octetsto9022Octets,
5963157642Sps		0, "Bytes received in 1523 to 9022 byte packets");
5964157642Sps
5965157642Sps	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
5966157642Sps		"stat_EtherStatsPktsTx64Octets",
5967157642Sps		CTLFLAG_RD, &sc->stat_EtherStatsPktsTx64Octets,
5968157642Sps		0, "Bytes sent in 64 byte packets");
5969157642Sps
5970157642Sps	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
5971157642Sps		"stat_EtherStatsPktsTx65Octetsto127Octets",
5972157642Sps		CTLFLAG_RD, &sc->stat_EtherStatsPktsTx65Octetsto127Octets,
5973157642Sps		0, "Bytes sent in 65 to 127 byte packets");
5974157642Sps
5975157642Sps	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
5976157642Sps		"stat_EtherStatsPktsTx128Octetsto255Octets",
5977157642Sps		CTLFLAG_RD, &sc->stat_EtherStatsPktsTx128Octetsto255Octets,
5978157642Sps		0, "Bytes sent in 128 to 255 byte packets");
5979157642Sps
5980157642Sps	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
5981157642Sps		"stat_EtherStatsPktsTx256Octetsto511Octets",
5982157642Sps		CTLFLAG_RD, &sc->stat_EtherStatsPktsTx256Octetsto511Octets,
5983157642Sps		0, "Bytes sent in 256 to 511 byte packets");
5984157642Sps
5985157642Sps	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
5986157642Sps		"stat_EtherStatsPktsTx512Octetsto1023Octets",
5987157642Sps		CTLFLAG_RD, &sc->stat_EtherStatsPktsTx512Octetsto1023Octets,
5988157642Sps		0, "Bytes sent in 512 to 1023 byte packets");
5989157642Sps
5990157642Sps	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
5991157642Sps		"stat_EtherStatsPktsTx1024Octetsto1522Octets",
5992157642Sps		CTLFLAG_RD, &sc->stat_EtherStatsPktsTx1024Octetsto1522Octets,
5993157642Sps		0, "Bytes sent in 1024 to 1522 byte packets");
5994157642Sps
5995157642Sps	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
5996157642Sps		"stat_EtherStatsPktsTx1523Octetsto9022Octets",
5997157642Sps		CTLFLAG_RD, &sc->stat_EtherStatsPktsTx1523Octetsto9022Octets,
5998157642Sps		0, "Bytes sent in 1523 to 9022 byte packets");
5999157642Sps
6000157642Sps	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
6001157642Sps		"stat_XonPauseFramesReceived",
6002157642Sps		CTLFLAG_RD, &sc->stat_XonPauseFramesReceived,
6003157642Sps		0, "XON pause frames receved");
6004157642Sps
6005157642Sps	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
6006157642Sps		"stat_XoffPauseFramesReceived",
6007157642Sps		CTLFLAG_RD, &sc->stat_XoffPauseFramesReceived,
6008157642Sps		0, "XOFF pause frames received");
6009157642Sps
6010157642Sps	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
6011157642Sps		"stat_OutXonSent",
6012157642Sps		CTLFLAG_RD, &sc->stat_OutXonSent,
6013157642Sps		0, "XON pause frames sent");
6014157642Sps
6015157642Sps	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
6016157642Sps		"stat_OutXoffSent",
6017157642Sps		CTLFLAG_RD, &sc->stat_OutXoffSent,
6018157642Sps		0, "XOFF pause frames sent");
6019157642Sps
6020157642Sps	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
6021157642Sps		"stat_FlowControlDone",
6022157642Sps		CTLFLAG_RD, &sc->stat_FlowControlDone,
6023157642Sps		0, "Flow control done");
6024157642Sps
6025157642Sps	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
6026157642Sps		"stat_MacControlFramesReceived",
6027157642Sps		CTLFLAG_RD, &sc->stat_MacControlFramesReceived,
6028157642Sps		0, "MAC control frames received");
6029157642Sps
6030157642Sps	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
6031157642Sps		"stat_XoffStateEntered",
6032157642Sps		CTLFLAG_RD, &sc->stat_XoffStateEntered,
6033157642Sps		0, "XOFF state entered");
6034157642Sps
6035157642Sps	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
6036157642Sps		"stat_IfInFramesL2FilterDiscards",
6037157642Sps		CTLFLAG_RD, &sc->stat_IfInFramesL2FilterDiscards,
6038157642Sps		0, "Received L2 packets discarded");
6039157642Sps
6040157642Sps	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
6041157642Sps		"stat_IfInRuleCheckerDiscards",
6042157642Sps		CTLFLAG_RD, &sc->stat_IfInRuleCheckerDiscards,
6043157642Sps		0, "Received packets discarded by rule");
6044157642Sps
6045157642Sps	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
6046157642Sps		"stat_IfInFTQDiscards",
6047157642Sps		CTLFLAG_RD, &sc->stat_IfInFTQDiscards,
6048157642Sps		0, "Received packet FTQ discards");
6049157642Sps
6050157642Sps	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
6051157642Sps		"stat_IfInMBUFDiscards",
6052157642Sps		CTLFLAG_RD, &sc->stat_IfInMBUFDiscards,
6053157642Sps		0, "Received packets discarded due to lack of controller buffer memory");
6054157642Sps
6055157642Sps	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
6056157642Sps		"stat_IfInRuleCheckerP4Hit",
6057157642Sps		CTLFLAG_RD, &sc->stat_IfInRuleCheckerP4Hit,
6058157642Sps		0, "Received packets rule checker hits");
6059157642Sps
6060157642Sps	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
6061157642Sps		"stat_CatchupInRuleCheckerDiscards",
6062157642Sps		CTLFLAG_RD, &sc->stat_CatchupInRuleCheckerDiscards,
6063157642Sps		0, "Received packets discarded in Catchup path");
6064157642Sps
6065157642Sps	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
6066157642Sps		"stat_CatchupInFTQDiscards",
6067157642Sps		CTLFLAG_RD, &sc->stat_CatchupInFTQDiscards,
6068157642Sps		0, "Received packets discarded in FTQ in Catchup path");
6069157642Sps
6070157642Sps	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
6071157642Sps		"stat_CatchupInMBUFDiscards",
6072157642Sps		CTLFLAG_RD, &sc->stat_CatchupInMBUFDiscards,
6073157642Sps		0, "Received packets discarded in controller buffer memory in Catchup path");
6074157642Sps
6075157642Sps	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
6076157642Sps		"stat_CatchupInRuleCheckerP4Hit",
6077157642Sps		CTLFLAG_RD, &sc->stat_CatchupInRuleCheckerP4Hit,
6078157642Sps		0, "Received packets rule checker hits in Catchup path");
6079157642Sps
6080157642Sps#ifdef BCE_DEBUG
6081157642Sps	SYSCTL_ADD_PROC(ctx, children, OID_AUTO,
6082157642Sps		"driver_state", CTLTYPE_INT | CTLFLAG_RW,
6083157642Sps		(void *)sc, 0,
6084157642Sps		bce_sysctl_driver_state, "I", "Drive state information");
6085157642Sps
6086157642Sps	SYSCTL_ADD_PROC(ctx, children, OID_AUTO,
6087157642Sps		"hw_state", CTLTYPE_INT | CTLFLAG_RW,
6088157642Sps		(void *)sc, 0,
6089157642Sps		bce_sysctl_hw_state, "I", "Hardware state information");
6090157642Sps
6091157642Sps	SYSCTL_ADD_PROC(ctx, children, OID_AUTO,
6092157642Sps		"dump_rx_chain", CTLTYPE_INT | CTLFLAG_RW,
6093157642Sps		(void *)sc, 0,
6094157642Sps		bce_sysctl_dump_rx_chain, "I", "Dump rx_bd chain");
6095157642Sps
6096157642Sps	SYSCTL_ADD_PROC(ctx, children, OID_AUTO,
6097157642Sps		"breakpoint", CTLTYPE_INT | CTLFLAG_RW,
6098157642Sps		(void *)sc, 0,
6099157642Sps		bce_sysctl_breakpoint, "I", "Driver breakpoint");
6100157642Sps#endif
6101157642Sps
6102157642Sps}
6103157642Sps
6104157642Sps
6105157642Sps/****************************************************************************/
6106157642Sps/* BCE Debug Routines                                                       */
6107157642Sps/****************************************************************************/
6108157642Sps#ifdef BCE_DEBUG
6109157642Sps
6110157642Sps/****************************************************************************/
6111157642Sps/* Prints out information about an mbuf.                                    */
6112157642Sps/*                                                                          */
6113157642Sps/* Returns:                                                                 */
6114157642Sps/*   Nothing.                                                               */
6115157642Sps/****************************************************************************/
6116157642Spsstatic void
6117157642Spsbce_dump_mbuf(struct bce_softc *sc, struct mbuf *m)
6118157642Sps{
6119157642Sps	u32 val_hi, val_lo;
6120157642Sps	struct mbuf *mp = m;
6121157642Sps
6122157642Sps	if (m == NULL) {
6123157642Sps		/* Index out of range. */
6124157642Sps		printf("mbuf ptr is null!\n");
6125157642Sps		return;
6126157642Sps	}
6127157642Sps
6128157642Sps	while (mp) {
6129157642Sps		val_hi = BCE_ADDR_HI(mp);
6130157642Sps		val_lo = BCE_ADDR_LO(mp);
6131157642Sps		BCE_PRINTF(sc, "mbuf: vaddr = 0x%08X:%08X, m_len = %d, m_flags = ",
6132157642Sps			   val_hi, val_lo, mp->m_len);
6133157642Sps
6134157642Sps		if (mp->m_flags & M_EXT)
6135157642Sps			printf("M_EXT ");
6136157642Sps		if (mp->m_flags & M_PKTHDR)
6137157642Sps			printf("M_PKTHDR ");
6138157642Sps		printf("\n");
6139157642Sps
6140157642Sps		if (mp->m_flags & M_EXT) {
6141157642Sps			val_hi = BCE_ADDR_HI(mp->m_ext.ext_buf);
6142157642Sps			val_lo = BCE_ADDR_LO(mp->m_ext.ext_buf);
6143157642Sps			BCE_PRINTF(sc, "- m_ext: vaddr = 0x%08X:%08X, ext_size = 0x%04X\n",
6144157642Sps				val_hi, val_lo, mp->m_ext.ext_size);
6145157642Sps		}
6146157642Sps
6147157642Sps		mp = mp->m_next;
6148157642Sps	}
6149157642Sps
6150157642Sps
6151157642Sps}
6152157642Sps
6153157642Sps
6154157642Sps/****************************************************************************/
6155157642Sps/* Prints out the mbufs in the TX mbuf chain.                               */
6156157642Sps/*                                                                          */
6157157642Sps/* Returns:                                                                 */
6158157642Sps/*   Nothing.                                                               */
6159157642Sps/****************************************************************************/
6160157642Spsstatic void
6161157642Spsbce_dump_tx_mbuf_chain(struct bce_softc *sc, int chain_prod, int count)
6162157642Sps{
6163157642Sps	struct mbuf *m;
6164157642Sps
6165157642Sps	BCE_PRINTF(sc,
6166157642Sps		"----------------------------"
6167157642Sps		"  tx mbuf data  "
6168157642Sps		"----------------------------\n");
6169157642Sps
6170157642Sps	for (int i = 0; i < count; i++) {
6171157642Sps	 	m = sc->tx_mbuf_ptr[chain_prod];
6172157642Sps		BCE_PRINTF(sc, "txmbuf[%d]\n", chain_prod);
6173157642Sps		bce_dump_mbuf(sc, m);
6174157642Sps		chain_prod = TX_CHAIN_IDX(NEXT_TX_BD(chain_prod));
6175157642Sps	}
6176157642Sps
6177157642Sps	BCE_PRINTF(sc,
6178157642Sps		"----------------------------"
6179157642Sps		"----------------"
6180157642Sps		"----------------------------\n");
6181157642Sps}
6182157642Sps
6183157642Sps
6184157642Sps/*
6185157642Sps * This routine prints the RX mbuf chain.
6186157642Sps */
6187157642Spsstatic void
6188157642Spsbce_dump_rx_mbuf_chain(struct bce_softc *sc, int chain_prod, int count)
6189157642Sps{
6190157642Sps	struct mbuf *m;
6191157642Sps
6192157642Sps	BCE_PRINTF(sc,
6193157642Sps		"----------------------------"
6194157642Sps		"  rx mbuf data  "
6195157642Sps		"----------------------------\n");
6196157642Sps
6197157642Sps	for (int i = 0; i < count; i++) {
6198157642Sps	 	m = sc->rx_mbuf_ptr[chain_prod];
6199157642Sps		BCE_PRINTF(sc, "rxmbuf[0x%04X]\n", chain_prod);
6200157642Sps		bce_dump_mbuf(sc, m);
6201157642Sps		chain_prod = RX_CHAIN_IDX(NEXT_RX_BD(chain_prod));
6202157642Sps	}
6203157642Sps
6204157642Sps
6205157642Sps	BCE_PRINTF(sc,
6206157642Sps		"----------------------------"
6207157642Sps		"----------------"
6208157642Sps		"----------------------------\n");
6209157642Sps}
6210157642Sps
6211157642Sps
6212157642Spsstatic void
6213157642Spsbce_dump_txbd(struct bce_softc *sc, int idx, struct tx_bd *txbd)
6214157642Sps{
6215157642Sps	if (idx > MAX_TX_BD)
6216157642Sps		/* Index out of range. */
6217157642Sps		BCE_PRINTF(sc, "tx_bd[0x%04X]: Invalid tx_bd index!\n", idx);
6218157642Sps	else if ((idx & USABLE_TX_BD_PER_PAGE) == USABLE_TX_BD_PER_PAGE)
6219157642Sps		/* TX Chain page pointer. */
6220157642Sps		BCE_PRINTF(sc, "tx_bd[0x%04X]: haddr = 0x%08X:%08X, chain page pointer\n",
6221157642Sps			idx, txbd->tx_bd_haddr_hi, txbd->tx_bd_haddr_lo);
6222157642Sps	else
6223157642Sps		/* Normal tx_bd entry. */
6224157642Sps		BCE_PRINTF(sc, "tx_bd[0x%04X]: haddr = 0x%08X:%08X, nbytes = 0x%08X, "
6225157642Sps			"flags = 0x%08X\n", idx,
6226157642Sps			txbd->tx_bd_haddr_hi, txbd->tx_bd_haddr_lo,
6227157642Sps			txbd->tx_bd_mss_nbytes, txbd->tx_bd_vlan_tag_flags);
6228157642Sps}
6229157642Sps
6230157642Sps
6231157642Spsstatic void
6232157642Spsbce_dump_rxbd(struct bce_softc *sc, int idx, struct rx_bd *rxbd)
6233157642Sps{
6234157642Sps	if (idx > MAX_RX_BD)
6235157642Sps		/* Index out of range. */
6236157642Sps		BCE_PRINTF(sc, "rx_bd[0x%04X]: Invalid rx_bd index!\n", idx);
6237157642Sps	else if ((idx & USABLE_RX_BD_PER_PAGE) == USABLE_RX_BD_PER_PAGE)
6238157642Sps		/* TX Chain page pointer. */
6239157642Sps		BCE_PRINTF(sc, "rx_bd[0x%04X]: haddr = 0x%08X:%08X, chain page pointer\n",
6240157642Sps			idx, rxbd->rx_bd_haddr_hi, rxbd->rx_bd_haddr_lo);
6241157642Sps	else
6242157642Sps		/* Normal tx_bd entry. */
6243157642Sps		BCE_PRINTF(sc, "rx_bd[0x%04X]: haddr = 0x%08X:%08X, nbytes = 0x%08X, "
6244157642Sps			"flags = 0x%08X\n", idx,
6245157642Sps			rxbd->rx_bd_haddr_hi, rxbd->rx_bd_haddr_lo,
6246157642Sps			rxbd->rx_bd_len, rxbd->rx_bd_flags);
6247157642Sps}
6248157642Sps
6249157642Sps
6250157642Spsstatic void
6251157642Spsbce_dump_l2fhdr(struct bce_softc *sc, int idx, struct l2_fhdr *l2fhdr)
6252157642Sps{
6253157642Sps	BCE_PRINTF(sc, "l2_fhdr[0x%04X]: status = 0x%08X, "
6254157642Sps		"pkt_len = 0x%04X, vlan = 0x%04x, ip_xsum = 0x%04X, "
6255157642Sps		"tcp_udp_xsum = 0x%04X\n", idx,
6256157642Sps		l2fhdr->l2_fhdr_status, l2fhdr->l2_fhdr_pkt_len,
6257157642Sps		l2fhdr->l2_fhdr_vlan_tag, l2fhdr->l2_fhdr_ip_xsum,
6258157642Sps		l2fhdr->l2_fhdr_tcp_udp_xsum);
6259157642Sps}
6260157642Sps
6261157642Sps
6262157642Sps/*
6263157642Sps * This routine prints the TX chain.
6264157642Sps */
6265157642Spsstatic void
6266157642Spsbce_dump_tx_chain(struct bce_softc *sc, int tx_prod, int count)
6267157642Sps{
6268157642Sps	struct tx_bd *txbd;
6269157642Sps
6270157642Sps	/* First some info about the tx_bd chain structure. */
6271157642Sps	BCE_PRINTF(sc,
6272157642Sps		"----------------------------"
6273157642Sps		"  tx_bd  chain  "
6274157642Sps		"----------------------------\n");
6275157642Sps
6276157642Sps	BCE_PRINTF(sc, "page size      = 0x%08X, tx chain pages        = 0x%08X\n",
6277157642Sps		(u32) BCM_PAGE_SIZE, (u32) TX_PAGES);
6278157642Sps
6279157642Sps	BCE_PRINTF(sc, "tx_bd per page = 0x%08X, usable tx_bd per page = 0x%08X\n",
6280157642Sps		(u32) TOTAL_TX_BD_PER_PAGE, (u32) USABLE_TX_BD_PER_PAGE);
6281157642Sps
6282157642Sps	BCE_PRINTF(sc, "total tx_bd    = 0x%08X\n", (u32) TOTAL_TX_BD);
6283157642Sps
6284157642Sps	BCE_PRINTF(sc, ""
6285157642Sps		"-----------------------------"
6286157642Sps		"   tx_bd data   "
6287157642Sps		"-----------------------------\n");
6288157642Sps
6289157642Sps	/* Now print out the tx_bd's themselves. */
6290157642Sps	for (int i = 0; i < count; i++) {
6291157642Sps	 	txbd = &sc->tx_bd_chain[TX_PAGE(tx_prod)][TX_IDX(tx_prod)];
6292157642Sps		bce_dump_txbd(sc, tx_prod, txbd);
6293157642Sps		tx_prod = TX_CHAIN_IDX(NEXT_TX_BD(tx_prod));
6294157642Sps	}
6295157642Sps
6296157642Sps	BCE_PRINTF(sc,
6297157642Sps		"-----------------------------"
6298157642Sps		"--------------"
6299157642Sps		"-----------------------------\n");
6300157642Sps}
6301157642Sps
6302157642Sps
6303157642Sps/*
6304157642Sps * This routine prints the RX chain.
6305157642Sps */
6306157642Spsstatic void
6307157642Spsbce_dump_rx_chain(struct bce_softc *sc, int rx_prod, int count)
6308157642Sps{
6309157642Sps	struct rx_bd *rxbd;
6310157642Sps
6311157642Sps	/* First some info about the tx_bd chain structure. */
6312157642Sps	BCE_PRINTF(sc,
6313157642Sps		"----------------------------"
6314157642Sps		"  rx_bd  chain  "
6315157642Sps		"----------------------------\n");
6316157642Sps
6317157642Sps	BCE_PRINTF(sc, "----- RX_BD Chain -----\n");
6318157642Sps
6319157642Sps	BCE_PRINTF(sc, "page size      = 0x%08X, rx chain pages        = 0x%08X\n",
6320157642Sps		(u32) BCM_PAGE_SIZE, (u32) RX_PAGES);
6321157642Sps
6322157642Sps	BCE_PRINTF(sc, "rx_bd per page = 0x%08X, usable rx_bd per page = 0x%08X\n",
6323157642Sps		(u32) TOTAL_RX_BD_PER_PAGE, (u32) USABLE_RX_BD_PER_PAGE);
6324157642Sps
6325157642Sps	BCE_PRINTF(sc, "total rx_bd    = 0x%08X\n", (u32) TOTAL_RX_BD);
6326157642Sps
6327157642Sps	BCE_PRINTF(sc,
6328157642Sps		"----------------------------"
6329157642Sps		"   rx_bd data   "
6330157642Sps		"----------------------------\n");
6331157642Sps
6332157642Sps	/* Now print out the rx_bd's themselves. */
6333157642Sps	for (int i = 0; i < count; i++) {
6334157642Sps		rxbd = &sc->rx_bd_chain[RX_PAGE(rx_prod)][RX_IDX(rx_prod)];
6335157642Sps		bce_dump_rxbd(sc, rx_prod, rxbd);
6336157642Sps		rx_prod = RX_CHAIN_IDX(NEXT_RX_BD(rx_prod));
6337157642Sps	}
6338157642Sps
6339157642Sps	BCE_PRINTF(sc,
6340157642Sps		"----------------------------"
6341157642Sps		"--------------"
6342157642Sps		"----------------------------\n");
6343157642Sps}
6344157642Sps
6345157642Sps
6346157642Sps/*
6347157642Sps * This routine prints the status block.
6348157642Sps */
6349157642Spsstatic void
6350157642Spsbce_dump_status_block(struct bce_softc *sc)
6351157642Sps{
6352157642Sps	struct status_block *sblk;
6353157642Sps
6354157642Sps	sblk = sc->status_block;
6355157642Sps
6356157642Sps   	BCE_PRINTF(sc, "----------------------------- Status Block "
6357157642Sps		"-----------------------------\n");
6358157642Sps
6359157642Sps	BCE_PRINTF(sc, "attn_bits  = 0x%08X, attn_bits_ack = 0x%08X, index = 0x%04X\n",
6360157642Sps		sblk->status_attn_bits, sblk->status_attn_bits_ack,
6361157642Sps		sblk->status_idx);
6362157642Sps
6363157642Sps	BCE_PRINTF(sc, "rx_cons0   = 0x%08X, tx_cons0      = 0x%08X\n",
6364157642Sps		sblk->status_rx_quick_consumer_index0,
6365157642Sps		sblk->status_tx_quick_consumer_index0);
6366157642Sps
6367157642Sps	BCE_PRINTF(sc, "status_idx = 0x%04X\n", sblk->status_idx);
6368157642Sps
6369157642Sps	/* Theses indices are not used for normal L2 drivers. */
6370157642Sps	if (sblk->status_rx_quick_consumer_index1 ||
6371157642Sps		sblk->status_tx_quick_consumer_index1)
6372157642Sps		BCE_PRINTF(sc, "rx_cons1  = 0x%08X, tx_cons1      = 0x%08X\n",
6373157642Sps			sblk->status_rx_quick_consumer_index1,
6374157642Sps			sblk->status_tx_quick_consumer_index1);
6375157642Sps
6376157642Sps	if (sblk->status_rx_quick_consumer_index2 ||
6377157642Sps		sblk->status_tx_quick_consumer_index2)
6378157642Sps		BCE_PRINTF(sc, "rx_cons2  = 0x%08X, tx_cons2      = 0x%08X\n",
6379157642Sps			sblk->status_rx_quick_consumer_index2,
6380157642Sps			sblk->status_tx_quick_consumer_index2);
6381157642Sps
6382157642Sps	if (sblk->status_rx_quick_consumer_index3 ||
6383157642Sps		sblk->status_tx_quick_consumer_index3)
6384157642Sps		BCE_PRINTF(sc, "rx_cons3  = 0x%08X, tx_cons3      = 0x%08X\n",
6385157642Sps			sblk->status_rx_quick_consumer_index3,
6386157642Sps			sblk->status_tx_quick_consumer_index3);
6387157642Sps
6388157642Sps	if (sblk->status_rx_quick_consumer_index4 ||
6389157642Sps		sblk->status_rx_quick_consumer_index5)
6390157642Sps		BCE_PRINTF(sc, "rx_cons4  = 0x%08X, rx_cons5      = 0x%08X\n",
6391157642Sps			sblk->status_rx_quick_consumer_index4,
6392157642Sps			sblk->status_rx_quick_consumer_index5);
6393157642Sps
6394157642Sps	if (sblk->status_rx_quick_consumer_index6 ||
6395157642Sps		sblk->status_rx_quick_consumer_index7)
6396157642Sps		BCE_PRINTF(sc, "rx_cons6  = 0x%08X, rx_cons7      = 0x%08X\n",
6397157642Sps			sblk->status_rx_quick_consumer_index6,
6398157642Sps			sblk->status_rx_quick_consumer_index7);
6399157642Sps
6400157642Sps	if (sblk->status_rx_quick_consumer_index8 ||
6401157642Sps		sblk->status_rx_quick_consumer_index9)
6402157642Sps		BCE_PRINTF(sc, "rx_cons8  = 0x%08X, rx_cons9      = 0x%08X\n",
6403157642Sps			sblk->status_rx_quick_consumer_index8,
6404157642Sps			sblk->status_rx_quick_consumer_index9);
6405157642Sps
6406157642Sps	if (sblk->status_rx_quick_consumer_index10 ||
6407157642Sps		sblk->status_rx_quick_consumer_index11)
6408157642Sps		BCE_PRINTF(sc, "rx_cons10 = 0x%08X, rx_cons11     = 0x%08X\n",
6409157642Sps			sblk->status_rx_quick_consumer_index10,
6410157642Sps			sblk->status_rx_quick_consumer_index11);
6411157642Sps
6412157642Sps	if (sblk->status_rx_quick_consumer_index12 ||
6413157642Sps		sblk->status_rx_quick_consumer_index13)
6414157642Sps		BCE_PRINTF(sc, "rx_cons12 = 0x%08X, rx_cons13     = 0x%08X\n",
6415157642Sps			sblk->status_rx_quick_consumer_index12,
6416157642Sps			sblk->status_rx_quick_consumer_index13);
6417157642Sps
6418157642Sps	if (sblk->status_rx_quick_consumer_index14 ||
6419157642Sps		sblk->status_rx_quick_consumer_index15)
6420157642Sps		BCE_PRINTF(sc, "rx_cons14 = 0x%08X, rx_cons15     = 0x%08X\n",
6421157642Sps			sblk->status_rx_quick_consumer_index14,
6422157642Sps			sblk->status_rx_quick_consumer_index15);
6423157642Sps
6424157642Sps	if (sblk->status_completion_producer_index ||
6425157642Sps		sblk->status_cmd_consumer_index)
6426157642Sps		BCE_PRINTF(sc, "com_prod  = 0x%08X, cmd_cons      = 0x%08X\n",
6427157642Sps			sblk->status_completion_producer_index,
6428157642Sps			sblk->status_cmd_consumer_index);
6429157642Sps
6430157642Sps	BCE_PRINTF(sc, "-------------------------------------------"
6431157642Sps		"-----------------------------\n");
6432157642Sps}
6433157642Sps
6434157642Sps
6435157642Sps/*
6436157642Sps * This routine prints the statistics block.
6437157642Sps */
6438157642Spsstatic void
6439157642Spsbce_dump_stats_block(struct bce_softc *sc)
6440157642Sps{
6441157642Sps	struct statistics_block *sblk;
6442157642Sps
6443157642Sps	sblk = sc->stats_block;
6444157642Sps
6445157642Sps	BCE_PRINTF(sc, ""
6446157642Sps		"-----------------------------"
6447157642Sps		" Stats  Block "
6448157642Sps		"-----------------------------\n");
6449157642Sps
6450157642Sps	BCE_PRINTF(sc, "IfHcInOctets         = 0x%08X:%08X, "
6451157642Sps		"IfHcInBadOctets      = 0x%08X:%08X\n",
6452157642Sps		sblk->stat_IfHCInOctets_hi, sblk->stat_IfHCInOctets_lo,
6453157642Sps		sblk->stat_IfHCInBadOctets_hi, sblk->stat_IfHCInBadOctets_lo);
6454157642Sps
6455157642Sps	BCE_PRINTF(sc, "IfHcOutOctets        = 0x%08X:%08X, "
6456157642Sps		"IfHcOutBadOctets     = 0x%08X:%08X\n",
6457157642Sps		sblk->stat_IfHCOutOctets_hi, sblk->stat_IfHCOutOctets_lo,
6458157642Sps		sblk->stat_IfHCOutBadOctets_hi, sblk->stat_IfHCOutBadOctets_lo);
6459157642Sps
6460157642Sps	BCE_PRINTF(sc, "IfHcInUcastPkts      = 0x%08X:%08X, "
6461157642Sps		"IfHcInMulticastPkts  = 0x%08X:%08X\n",
6462157642Sps		sblk->stat_IfHCInUcastPkts_hi, sblk->stat_IfHCInUcastPkts_lo,
6463157642Sps		sblk->stat_IfHCInMulticastPkts_hi, sblk->stat_IfHCInMulticastPkts_lo);
6464157642Sps
6465157642Sps	BCE_PRINTF(sc, "IfHcInBroadcastPkts  = 0x%08X:%08X, "
6466157642Sps		"IfHcOutUcastPkts     = 0x%08X:%08X\n",
6467157642Sps		sblk->stat_IfHCInBroadcastPkts_hi, sblk->stat_IfHCInBroadcastPkts_lo,
6468157642Sps		sblk->stat_IfHCOutUcastPkts_hi, sblk->stat_IfHCOutUcastPkts_lo);
6469157642Sps
6470157642Sps	BCE_PRINTF(sc, "IfHcOutMulticastPkts = 0x%08X:%08X, IfHcOutBroadcastPkts = 0x%08X:%08X\n",
6471157642Sps		sblk->stat_IfHCOutMulticastPkts_hi, sblk->stat_IfHCOutMulticastPkts_lo,
6472157642Sps		sblk->stat_IfHCOutBroadcastPkts_hi, sblk->stat_IfHCOutBroadcastPkts_lo);
6473157642Sps
6474157642Sps	if (sblk->stat_emac_tx_stat_dot3statsinternalmactransmiterrors)
6475157642Sps		BCE_PRINTF(sc, "0x%08X : "
6476157642Sps		"emac_tx_stat_dot3statsinternalmactransmiterrors\n",
6477157642Sps		sblk->stat_emac_tx_stat_dot3statsinternalmactransmiterrors);
6478157642Sps
6479157642Sps	if (sblk->stat_Dot3StatsCarrierSenseErrors)
6480157642Sps		BCE_PRINTF(sc, "0x%08X : Dot3StatsCarrierSenseErrors\n",
6481157642Sps			sblk->stat_Dot3StatsCarrierSenseErrors);
6482157642Sps
6483157642Sps	if (sblk->stat_Dot3StatsFCSErrors)
6484157642Sps		BCE_PRINTF(sc, "0x%08X : Dot3StatsFCSErrors\n",
6485157642Sps			sblk->stat_Dot3StatsFCSErrors);
6486157642Sps
6487157642Sps	if (sblk->stat_Dot3StatsAlignmentErrors)
6488157642Sps		BCE_PRINTF(sc, "0x%08X : Dot3StatsAlignmentErrors\n",
6489157642Sps			sblk->stat_Dot3StatsAlignmentErrors);
6490157642Sps
6491157642Sps	if (sblk->stat_Dot3StatsSingleCollisionFrames)
6492157642Sps		BCE_PRINTF(sc, "0x%08X : Dot3StatsSingleCollisionFrames\n",
6493157642Sps			sblk->stat_Dot3StatsSingleCollisionFrames);
6494157642Sps
6495157642Sps	if (sblk->stat_Dot3StatsMultipleCollisionFrames)
6496157642Sps		BCE_PRINTF(sc, "0x%08X : Dot3StatsMultipleCollisionFrames\n",
6497157642Sps			sblk->stat_Dot3StatsMultipleCollisionFrames);
6498157642Sps
6499157642Sps	if (sblk->stat_Dot3StatsDeferredTransmissions)
6500157642Sps		BCE_PRINTF(sc, "0x%08X : Dot3StatsDeferredTransmissions\n",
6501157642Sps			sblk->stat_Dot3StatsDeferredTransmissions);
6502157642Sps
6503157642Sps	if (sblk->stat_Dot3StatsExcessiveCollisions)
6504157642Sps		BCE_PRINTF(sc, "0x%08X : Dot3StatsExcessiveCollisions\n",
6505157642Sps			sblk->stat_Dot3StatsExcessiveCollisions);
6506157642Sps
6507157642Sps	if (sblk->stat_Dot3StatsLateCollisions)
6508157642Sps		BCE_PRINTF(sc, "0x%08X : Dot3StatsLateCollisions\n",
6509157642Sps			sblk->stat_Dot3StatsLateCollisions);
6510157642Sps
6511157642Sps	if (sblk->stat_EtherStatsCollisions)
6512157642Sps		BCE_PRINTF(sc, "0x%08X : EtherStatsCollisions\n",
6513157642Sps			sblk->stat_EtherStatsCollisions);
6514157642Sps
6515157642Sps	if (sblk->stat_EtherStatsFragments)
6516157642Sps		BCE_PRINTF(sc, "0x%08X : EtherStatsFragments\n",
6517157642Sps			sblk->stat_EtherStatsFragments);
6518157642Sps
6519157642Sps	if (sblk->stat_EtherStatsJabbers)
6520157642Sps		BCE_PRINTF(sc, "0x%08X : EtherStatsJabbers\n",
6521157642Sps			sblk->stat_EtherStatsJabbers);
6522157642Sps
6523157642Sps	if (sblk->stat_EtherStatsUndersizePkts)
6524157642Sps		BCE_PRINTF(sc, "0x%08X : EtherStatsUndersizePkts\n",
6525157642Sps			sblk->stat_EtherStatsUndersizePkts);
6526157642Sps
6527157642Sps	if (sblk->stat_EtherStatsOverrsizePkts)
6528157642Sps		BCE_PRINTF(sc, "0x%08X : EtherStatsOverrsizePkts\n",
6529157642Sps			sblk->stat_EtherStatsOverrsizePkts);
6530157642Sps
6531157642Sps	if (sblk->stat_EtherStatsPktsRx64Octets)
6532157642Sps		BCE_PRINTF(sc, "0x%08X : EtherStatsPktsRx64Octets\n",
6533157642Sps			sblk->stat_EtherStatsPktsRx64Octets);
6534157642Sps
6535157642Sps	if (sblk->stat_EtherStatsPktsRx65Octetsto127Octets)
6536157642Sps		BCE_PRINTF(sc, "0x%08X : EtherStatsPktsRx65Octetsto127Octets\n",
6537157642Sps			sblk->stat_EtherStatsPktsRx65Octetsto127Octets);
6538157642Sps
6539157642Sps	if (sblk->stat_EtherStatsPktsRx128Octetsto255Octets)
6540157642Sps		BCE_PRINTF(sc, "0x%08X : EtherStatsPktsRx128Octetsto255Octets\n",
6541157642Sps			sblk->stat_EtherStatsPktsRx128Octetsto255Octets);
6542157642Sps
6543157642Sps	if (sblk->stat_EtherStatsPktsRx256Octetsto511Octets)
6544157642Sps		BCE_PRINTF(sc, "0x%08X : EtherStatsPktsRx256Octetsto511Octets\n",
6545157642Sps			sblk->stat_EtherStatsPktsRx256Octetsto511Octets);
6546157642Sps
6547157642Sps	if (sblk->stat_EtherStatsPktsRx512Octetsto1023Octets)
6548157642Sps		BCE_PRINTF(sc, "0x%08X : EtherStatsPktsRx512Octetsto1023Octets\n",
6549157642Sps			sblk->stat_EtherStatsPktsRx512Octetsto1023Octets);
6550157642Sps
6551157642Sps	if (sblk->stat_EtherStatsPktsRx1024Octetsto1522Octets)
6552157642Sps		BCE_PRINTF(sc, "0x%08X : EtherStatsPktsRx1024Octetsto1522Octets\n",
6553157642Sps			sblk->stat_EtherStatsPktsRx1024Octetsto1522Octets);
6554157642Sps
6555157642Sps	if (sblk->stat_EtherStatsPktsRx1523Octetsto9022Octets)
6556157642Sps		BCE_PRINTF(sc, "0x%08X : EtherStatsPktsRx1523Octetsto9022Octets\n",
6557157642Sps			sblk->stat_EtherStatsPktsRx1523Octetsto9022Octets);
6558157642Sps
6559157642Sps	if (sblk->stat_EtherStatsPktsTx64Octets)
6560157642Sps		BCE_PRINTF(sc, "0x%08X : EtherStatsPktsTx64Octets\n",
6561157642Sps			sblk->stat_EtherStatsPktsTx64Octets);
6562157642Sps
6563157642Sps	if (sblk->stat_EtherStatsPktsTx65Octetsto127Octets)
6564157642Sps		BCE_PRINTF(sc, "0x%08X : EtherStatsPktsTx65Octetsto127Octets\n",
6565157642Sps			sblk->stat_EtherStatsPktsTx65Octetsto127Octets);
6566157642Sps
6567157642Sps	if (sblk->stat_EtherStatsPktsTx128Octetsto255Octets)
6568157642Sps		BCE_PRINTF(sc, "0x%08X : EtherStatsPktsTx128Octetsto255Octets\n",
6569157642Sps			sblk->stat_EtherStatsPktsTx128Octetsto255Octets);
6570157642Sps
6571157642Sps	if (sblk->stat_EtherStatsPktsTx256Octetsto511Octets)
6572157642Sps		BCE_PRINTF(sc, "0x%08X : EtherStatsPktsTx256Octetsto511Octets\n",
6573157642Sps			sblk->stat_EtherStatsPktsTx256Octetsto511Octets);
6574157642Sps
6575157642Sps	if (sblk->stat_EtherStatsPktsTx512Octetsto1023Octets)
6576157642Sps		BCE_PRINTF(sc, "0x%08X : EtherStatsPktsTx512Octetsto1023Octets\n",
6577157642Sps			sblk->stat_EtherStatsPktsTx512Octetsto1023Octets);
6578157642Sps
6579157642Sps	if (sblk->stat_EtherStatsPktsTx1024Octetsto1522Octets)
6580157642Sps		BCE_PRINTF(sc, "0x%08X : EtherStatsPktsTx1024Octetsto1522Octets\n",
6581157642Sps			sblk->stat_EtherStatsPktsTx1024Octetsto1522Octets);
6582157642Sps
6583157642Sps	if (sblk->stat_EtherStatsPktsTx1523Octetsto9022Octets)
6584157642Sps		BCE_PRINTF(sc, "0x%08X : EtherStatsPktsTx1523Octetsto9022Octets\n",
6585157642Sps			sblk->stat_EtherStatsPktsTx1523Octetsto9022Octets);
6586157642Sps
6587157642Sps	if (sblk->stat_XonPauseFramesReceived)
6588157642Sps		BCE_PRINTF(sc, "0x%08X : XonPauseFramesReceived\n",
6589157642Sps			sblk->stat_XonPauseFramesReceived);
6590157642Sps
6591157642Sps	if (sblk->stat_XoffPauseFramesReceived)
6592157642Sps	   BCE_PRINTF(sc, "0x%08X : XoffPauseFramesReceived\n",
6593157642Sps			sblk->stat_XoffPauseFramesReceived);
6594157642Sps
6595157642Sps	if (sblk->stat_OutXonSent)
6596157642Sps		BCE_PRINTF(sc, "0x%08X : OutXonSent\n",
6597157642Sps			sblk->stat_OutXonSent);
6598157642Sps
6599157642Sps	if (sblk->stat_OutXoffSent)
6600157642Sps		BCE_PRINTF(sc, "0x%08X : OutXoffSent\n",
6601157642Sps			sblk->stat_OutXoffSent);
6602157642Sps
6603157642Sps	if (sblk->stat_FlowControlDone)
6604157642Sps		BCE_PRINTF(sc, "0x%08X : FlowControlDone\n",
6605157642Sps			sblk->stat_FlowControlDone);
6606157642Sps
6607157642Sps	if (sblk->stat_MacControlFramesReceived)
6608157642Sps		BCE_PRINTF(sc, "0x%08X : MacControlFramesReceived\n",
6609157642Sps			sblk->stat_MacControlFramesReceived);
6610157642Sps
6611157642Sps	if (sblk->stat_XoffStateEntered)
6612157642Sps		BCE_PRINTF(sc, "0x%08X : XoffStateEntered\n",
6613157642Sps			sblk->stat_XoffStateEntered);
6614157642Sps
6615157642Sps	if (sblk->stat_IfInFramesL2FilterDiscards)
6616157642Sps		BCE_PRINTF(sc, "0x%08X : IfInFramesL2FilterDiscards\n",
6617157642Sps			sblk->stat_IfInFramesL2FilterDiscards);
6618157642Sps
6619157642Sps	if (sblk->stat_IfInRuleCheckerDiscards)
6620157642Sps		BCE_PRINTF(sc, "0x%08X : IfInRuleCheckerDiscards\n",
6621157642Sps			sblk->stat_IfInRuleCheckerDiscards);
6622157642Sps
6623157642Sps	if (sblk->stat_IfInFTQDiscards)
6624157642Sps		BCE_PRINTF(sc, "0x%08X : IfInFTQDiscards\n",
6625157642Sps			sblk->stat_IfInFTQDiscards);
6626157642Sps
6627157642Sps	if (sblk->stat_IfInMBUFDiscards)
6628157642Sps		BCE_PRINTF(sc, "0x%08X : IfInMBUFDiscards\n",
6629157642Sps			sblk->stat_IfInMBUFDiscards);
6630157642Sps
6631157642Sps	if (sblk->stat_IfInRuleCheckerP4Hit)
6632157642Sps		BCE_PRINTF(sc, "0x%08X : IfInRuleCheckerP4Hit\n",
6633157642Sps			sblk->stat_IfInRuleCheckerP4Hit);
6634157642Sps
6635157642Sps	if (sblk->stat_CatchupInRuleCheckerDiscards)
6636157642Sps		BCE_PRINTF(sc, "0x%08X : CatchupInRuleCheckerDiscards\n",
6637157642Sps			sblk->stat_CatchupInRuleCheckerDiscards);
6638157642Sps
6639157642Sps	if (sblk->stat_CatchupInFTQDiscards)
6640157642Sps		BCE_PRINTF(sc, "0x%08X : CatchupInFTQDiscards\n",
6641157642Sps			sblk->stat_CatchupInFTQDiscards);
6642157642Sps
6643157642Sps	if (sblk->stat_CatchupInMBUFDiscards)
6644157642Sps		BCE_PRINTF(sc, "0x%08X : CatchupInMBUFDiscards\n",
6645157642Sps			sblk->stat_CatchupInMBUFDiscards);
6646157642Sps
6647157642Sps	if (sblk->stat_CatchupInRuleCheckerP4Hit)
6648157642Sps		BCE_PRINTF(sc, "0x%08X : CatchupInRuleCheckerP4Hit\n",
6649157642Sps			sblk->stat_CatchupInRuleCheckerP4Hit);
6650157642Sps
6651157642Sps	BCE_PRINTF(sc,
6652157642Sps		"-----------------------------"
6653157642Sps		"--------------"
6654157642Sps		"-----------------------------\n");
6655157642Sps}
6656157642Sps
6657157642Sps
6658157642Spsstatic void
6659157642Spsbce_dump_driver_state(struct bce_softc *sc)
6660157642Sps{
6661157642Sps	u32 val_hi, val_lo;
6662157642Sps
6663157642Sps	BCE_PRINTF(sc,
6664157642Sps		"-----------------------------"
6665157642Sps		" Driver State "
6666157642Sps		"-----------------------------\n");
6667157642Sps
6668157642Sps	val_hi = BCE_ADDR_HI(sc);
6669157642Sps	val_lo = BCE_ADDR_LO(sc);
6670157642Sps	BCE_PRINTF(sc, "0x%08X:%08X - (sc) driver softc structure virtual address\n",
6671157642Sps		val_hi, val_lo);
6672157642Sps
6673157642Sps	val_hi = BCE_ADDR_HI(sc->bce_vhandle);
6674157642Sps	val_lo = BCE_ADDR_LO(sc->bce_vhandle);
6675157642Sps	BCE_PRINTF(sc, "0x%08X:%08X - (sc->bce_vhandle) PCI BAR virtual address\n",
6676157642Sps		val_hi, val_lo);
6677157642Sps
6678157642Sps	val_hi = BCE_ADDR_HI(sc->status_block);
6679157642Sps	val_lo = BCE_ADDR_LO(sc->status_block);
6680157642Sps	BCE_PRINTF(sc, "0x%08X:%08X - (sc->status_block) status block virtual address\n",
6681157642Sps		val_hi, val_lo);
6682157642Sps
6683157642Sps	val_hi = BCE_ADDR_HI(sc->stats_block);
6684157642Sps	val_lo = BCE_ADDR_LO(sc->stats_block);
6685157642Sps	BCE_PRINTF(sc, "0x%08X:%08X - (sc->stats_block) statistics block virtual address\n",
6686157642Sps		val_hi, val_lo);
6687157642Sps
6688157642Sps	val_hi = BCE_ADDR_HI(sc->tx_bd_chain);
6689157642Sps	val_lo = BCE_ADDR_LO(sc->tx_bd_chain);
6690157642Sps	BCE_PRINTF(sc,
6691157642Sps		"0x%08X:%08X - (sc->tx_bd_chain) tx_bd chain virtual adddress\n",
6692157642Sps		val_hi, val_lo);
6693157642Sps
6694157642Sps	val_hi = BCE_ADDR_HI(sc->rx_bd_chain);
6695157642Sps	val_lo = BCE_ADDR_LO(sc->rx_bd_chain);
6696157642Sps	BCE_PRINTF(sc,
6697157642Sps		"0x%08X:%08X - (sc->rx_bd_chain) rx_bd chain virtual address\n",
6698157642Sps		val_hi, val_lo);
6699157642Sps
6700157642Sps	val_hi = BCE_ADDR_HI(sc->tx_mbuf_ptr);
6701157642Sps	val_lo = BCE_ADDR_LO(sc->tx_mbuf_ptr);
6702157642Sps	BCE_PRINTF(sc,
6703157642Sps		"0x%08X:%08X - (sc->tx_mbuf_ptr) tx mbuf chain virtual address\n",
6704157642Sps		val_hi, val_lo);
6705157642Sps
6706157642Sps	val_hi = BCE_ADDR_HI(sc->rx_mbuf_ptr);
6707157642Sps	val_lo = BCE_ADDR_LO(sc->rx_mbuf_ptr);
6708157642Sps	BCE_PRINTF(sc,
6709157642Sps		"0x%08X:%08X - (sc->rx_mbuf_ptr) rx mbuf chain virtual address\n",
6710157642Sps		val_hi, val_lo);
6711157642Sps
6712157642Sps	BCE_PRINTF(sc, "         0x%08X - (sc->interrupts_generated) h/w intrs\n",
6713157642Sps		sc->interrupts_generated);
6714157642Sps
6715157642Sps	BCE_PRINTF(sc, "         0x%08X - (sc->rx_interrupts) rx interrupts handled\n",
6716157642Sps		sc->rx_interrupts);
6717157642Sps
6718157642Sps	BCE_PRINTF(sc, "         0x%08X - (sc->tx_interrupts) tx interrupts handled\n",
6719157642Sps		sc->tx_interrupts);
6720157642Sps
6721157642Sps	BCE_PRINTF(sc, "         0x%08X - (sc->last_status_idx) status block index\n",
6722157642Sps		sc->last_status_idx);
6723157642Sps
6724157642Sps	BCE_PRINTF(sc, "         0x%08X - (sc->tx_prod) tx producer index\n",
6725157642Sps		sc->tx_prod);
6726157642Sps
6727157642Sps	BCE_PRINTF(sc, "         0x%08X - (sc->tx_cons) tx consumer index\n",
6728157642Sps		sc->tx_cons);
6729157642Sps
6730157642Sps	BCE_PRINTF(sc, "         0x%08X - (sc->tx_prod_bseq) tx producer bseq index\n",
6731157642Sps		sc->tx_prod_bseq);
6732157642Sps
6733157642Sps	BCE_PRINTF(sc, "         0x%08X - (sc->rx_prod) rx producer index\n",
6734157642Sps		sc->rx_prod);
6735157642Sps
6736157642Sps	BCE_PRINTF(sc, "         0x%08X - (sc->rx_cons) rx consumer index\n",
6737157642Sps		sc->rx_cons);
6738157642Sps
6739157642Sps	BCE_PRINTF(sc, "         0x%08X - (sc->rx_prod_bseq) rx producer bseq index\n",
6740157642Sps		sc->rx_prod_bseq);
6741157642Sps
6742157642Sps	BCE_PRINTF(sc, "         0x%08X - (sc->rx_mbuf_alloc) rx mbufs allocated\n",
6743157642Sps		sc->rx_mbuf_alloc);
6744157642Sps
6745157642Sps	BCE_PRINTF(sc, "         0x%08X - (sc->free_rx_bd) free rx_bd's\n",
6746157642Sps		sc->free_rx_bd);
6747157642Sps
6748157642Sps	BCE_PRINTF(sc, "0x%08X/%08X - (sc->rx_low_watermark) rx low watermark\n",
6749157642Sps		sc->rx_low_watermark, (u32) USABLE_RX_BD);
6750157642Sps
6751157642Sps	BCE_PRINTF(sc, "         0x%08X - (sc->txmbuf_alloc) tx mbufs allocated\n",
6752157642Sps		sc->tx_mbuf_alloc);
6753157642Sps
6754157642Sps	BCE_PRINTF(sc, "         0x%08X - (sc->rx_mbuf_alloc) rx mbufs allocated\n",
6755157642Sps		sc->rx_mbuf_alloc);
6756157642Sps
6757157642Sps	BCE_PRINTF(sc, "         0x%08X - (sc->used_tx_bd) used tx_bd's\n",
6758157642Sps		sc->used_tx_bd);
6759157642Sps
6760157642Sps	BCE_PRINTF(sc, "0x%08X/%08X - (sc->tx_hi_watermark) tx hi watermark\n",
6761157642Sps		sc->tx_hi_watermark, (u32) USABLE_TX_BD);
6762157642Sps
6763157642Sps	BCE_PRINTF(sc, "         0x%08X - (sc->mbuf_alloc_failed) failed mbuf alloc\n",
6764157642Sps		sc->mbuf_alloc_failed);
6765157642Sps
6766157642Sps	BCE_PRINTF(sc,
6767157642Sps		"-----------------------------"
6768157642Sps		"--------------"
6769157642Sps		"-----------------------------\n");
6770157642Sps}
6771157642Sps
6772157642Sps
6773157642Spsstatic void
6774157642Spsbce_dump_hw_state(struct bce_softc *sc)
6775157642Sps{
6776157642Sps	u32 val1;
6777157642Sps
6778157642Sps	BCE_PRINTF(sc,
6779157642Sps		"----------------------------"
6780157642Sps		" Hardware State "
6781157642Sps		"----------------------------\n");
6782157642Sps
6783157642Sps	BCE_PRINTF(sc, "0x%08X : bootcode version\n", sc->bce_fw_ver);
6784157642Sps
6785157642Sps	val1 = REG_RD(sc, BCE_MISC_ENABLE_STATUS_BITS);
6786157642Sps	BCE_PRINTF(sc, "0x%08X : (0x%04X) misc_enable_status_bits\n",
6787157642Sps		val1, BCE_MISC_ENABLE_STATUS_BITS);
6788157642Sps
6789157642Sps	val1 = REG_RD(sc, BCE_DMA_STATUS);
6790157642Sps	BCE_PRINTF(sc, "0x%08X : (0x%04X) dma_status\n", val1, BCE_DMA_STATUS);
6791157642Sps
6792157642Sps	val1 = REG_RD(sc, BCE_CTX_STATUS);
6793157642Sps	BCE_PRINTF(sc, "0x%08X : (0x%04X) ctx_status\n", val1, BCE_CTX_STATUS);
6794157642Sps
6795157642Sps	val1 = REG_RD(sc, BCE_EMAC_STATUS);
6796157642Sps	BCE_PRINTF(sc, "0x%08X : (0x%04X) emac_status\n", val1, BCE_EMAC_STATUS);
6797157642Sps
6798157642Sps	val1 = REG_RD(sc, BCE_RPM_STATUS);
6799157642Sps	BCE_PRINTF(sc, "0x%08X : (0x%04X) rpm_status\n", val1, BCE_RPM_STATUS);
6800157642Sps
6801157642Sps	val1 = REG_RD(sc, BCE_TBDR_STATUS);
6802157642Sps	BCE_PRINTF(sc, "0x%08X : (0x%04X) tbdr_status\n", val1, BCE_TBDR_STATUS);
6803157642Sps
6804157642Sps	val1 = REG_RD(sc, BCE_TDMA_STATUS);
6805157642Sps	BCE_PRINTF(sc, "0x%08X : (0x%04X) tdma_status\n", val1, BCE_TDMA_STATUS);
6806157642Sps
6807157642Sps	val1 = REG_RD(sc, BCE_HC_STATUS);
6808157642Sps	BCE_PRINTF(sc, "0x%08X : (0x%04X) hc_status\n", val1, BCE_HC_STATUS);
6809157642Sps
6810157642Sps	BCE_PRINTF(sc,
6811157642Sps		"----------------------------"
6812157642Sps		"----------------"
6813157642Sps		"----------------------------\n");
6814157642Sps
6815157642Sps	BCE_PRINTF(sc,
6816157642Sps		"----------------------------"
6817157642Sps		" Register  Dump "
6818157642Sps		"----------------------------\n");
6819157642Sps
6820157642Sps	for (int i = 0x400; i < 0x8000; i += 0x10)
6821157642Sps		BCE_PRINTF(sc, "0x%04X: 0x%08X 0x%08X 0x%08X 0x%08X\n",
6822157642Sps			i, REG_RD(sc, i), REG_RD(sc, i + 0x4),
6823157642Sps			REG_RD(sc, i + 0x8), REG_RD(sc, i + 0xC));
6824157642Sps
6825157642Sps	BCE_PRINTF(sc,
6826157642Sps		"----------------------------"
6827157642Sps		"----------------"
6828157642Sps		"----------------------------\n");
6829157642Sps}
6830157642Sps
6831157642Sps
6832157642Spsstatic void
6833157642Spsbce_breakpoint(struct bce_softc *sc)
6834157642Sps{
6835157642Sps
6836157642Sps	/* Unreachable code to shut the compiler up about unused functions. */
6837157642Sps	if (0) {
6838157642Sps   		bce_dump_txbd(sc, 0, NULL);
6839157642Sps		bce_dump_rxbd(sc, 0, NULL);
6840157642Sps		bce_dump_tx_mbuf_chain(sc, 0, USABLE_TX_BD);
6841157642Sps		bce_dump_rx_mbuf_chain(sc, 0, USABLE_RX_BD);
6842157642Sps		bce_dump_l2fhdr(sc, 0, NULL);
6843157642Sps		bce_dump_tx_chain(sc, 0, USABLE_TX_BD);
6844157642Sps		bce_dump_rx_chain(sc, 0, USABLE_RX_BD);
6845157642Sps		bce_dump_status_block(sc);
6846157642Sps		bce_dump_stats_block(sc);
6847157642Sps		bce_dump_driver_state(sc);
6848157642Sps		bce_dump_hw_state(sc);
6849157642Sps	}
6850157642Sps
6851157642Sps	bce_dump_driver_state(sc);
6852157642Sps	/* Print the important status block fields. */
6853157642Sps	bce_dump_status_block(sc);
6854157642Sps
6855157642Sps	/* Call the debugger. */
6856157642Sps	breakpoint();
6857157642Sps
6858157642Sps	return;
6859157642Sps}
6860157642Sps#endif
6861