1157642Sps/*-
2265703Sdavidcs * Copyright (c) 2006-2014 QLogic Corporation
3157642Sps *
4157642Sps * Redistribution and use in source and binary forms, with or without
5157642Sps * modification, are permitted provided that the following conditions
6157642Sps * are met:
7157642Sps *
8157642Sps * 1. Redistributions of source code must retain the above copyright
9157642Sps *    notice, this list of conditions and the following disclaimer.
10157642Sps * 2. Redistributions in binary form must reproduce the above copyright
11157642Sps *    notice, this list of conditions and the following disclaimer in the
12157642Sps *    documentation and/or other materials provided with the distribution.
13157642Sps *
14157642Sps * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS'
15157642Sps * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16157642Sps * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17157642Sps * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
18157642Sps * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19157642Sps * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20157642Sps * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21157642Sps * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22157642Sps * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23157642Sps * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
24157642Sps * THE POSSIBILITY OF SUCH DAMAGE.
25157642Sps */
26157642Sps
27157642Sps#include <sys/cdefs.h>
28157642Sps__FBSDID("$FreeBSD: stable/11/sys/dev/bce/if_bce.c 315221 2017-03-14 02:06:03Z pfg $");
29157642Sps
30157642Sps/*
31157642Sps * The following controllers are supported by this driver:
32157642Sps *   BCM5706C A2, A3
33176448Sdavidch *   BCM5706S A2, A3
34169271Sdavidch *   BCM5708C B1, B2
35176448Sdavidch *   BCM5708S B1, B2
36182293Sdavidch *   BCM5709C A1, C0
37205300Sdavidch *   BCM5709S A1, C0
38206268Sdavidch *   BCM5716C C0
39206268Sdavidch *   BCM5716S C0
40157642Sps *
41157642Sps * The following controllers are not supported by this driver:
42176448Sdavidch *   BCM5706C A0, A1 (pre-production)
43176448Sdavidch *   BCM5706S A0, A1 (pre-production)
44176448Sdavidch *   BCM5708C A0, B0 (pre-production)
45176448Sdavidch *   BCM5708S A0, B0 (pre-production)
46179771Sdavidch *   BCM5709C A0  B0, B1, B2 (pre-production)
47205300Sdavidch *   BCM5709S A0, B0, B1, B2 (pre-production)
48157642Sps */
49157642Sps
50157643Sps#include "opt_bce.h"
51157643Sps
52257173Sglebius#include <sys/param.h>
53257173Sglebius#include <sys/endian.h>
54257173Sglebius#include <sys/systm.h>
55257173Sglebius#include <sys/sockio.h>
56257173Sglebius#include <sys/lock.h>
57257173Sglebius#include <sys/mbuf.h>
58257173Sglebius#include <sys/malloc.h>
59257173Sglebius#include <sys/mutex.h>
60257173Sglebius#include <sys/kernel.h>
61257173Sglebius#include <sys/module.h>
62257173Sglebius#include <sys/socket.h>
63257173Sglebius#include <sys/sysctl.h>
64257173Sglebius#include <sys/queue.h>
65257173Sglebius
66257173Sglebius#include <net/bpf.h>
67257173Sglebius#include <net/ethernet.h>
68257173Sglebius#include <net/if.h>
69257173Sglebius#include <net/if_var.h>
70257173Sglebius#include <net/if_arp.h>
71257173Sglebius#include <net/if_dl.h>
72257173Sglebius#include <net/if_media.h>
73257173Sglebius
74257173Sglebius#include <net/if_types.h>
75257173Sglebius#include <net/if_vlan_var.h>
76257173Sglebius
77257173Sglebius#include <netinet/in_systm.h>
78257173Sglebius#include <netinet/in.h>
79257173Sglebius#include <netinet/if_ether.h>
80257173Sglebius#include <netinet/ip.h>
81257173Sglebius#include <netinet/ip6.h>
82257173Sglebius#include <netinet/tcp.h>
83257173Sglebius#include <netinet/udp.h>
84257173Sglebius
85257173Sglebius#include <machine/bus.h>
86257173Sglebius#include <machine/resource.h>
87257173Sglebius#include <sys/bus.h>
88257173Sglebius#include <sys/rman.h>
89257173Sglebius
90257173Sglebius#include <dev/mii/mii.h>
91257173Sglebius#include <dev/mii/miivar.h>
92257173Sglebius#include "miidevs.h"
93257173Sglebius#include <dev/mii/brgphyreg.h>
94257173Sglebius
95257173Sglebius#include <dev/pci/pcireg.h>
96257173Sglebius#include <dev/pci/pcivar.h>
97257173Sglebius
98257173Sglebius#include "miibus_if.h"
99257173Sglebius
100157642Sps#include <dev/bce/if_bcereg.h>
101157642Sps#include <dev/bce/if_bcefw.h>
102157642Sps
103157642Sps/****************************************************************************/
104157642Sps/* BCE Debug Options                                                        */
105157642Sps/****************************************************************************/
106157642Sps#ifdef BCE_DEBUG
107157642Sps	u32 bce_debug = BCE_WARN;
108157642Sps
109157642Sps	/*          0 = Never              */
110157642Sps	/*          1 = 1 in 2,147,483,648 */
111157642Sps	/*        256 = 1 in     8,388,608 */
112157642Sps	/*       2048 = 1 in     1,048,576 */
113157642Sps	/*      65536 = 1 in        32,768 */
114157642Sps	/*    1048576 = 1 in         2,048 */
115157642Sps	/*  268435456 =	1 in             8 */
116157642Sps	/*  536870912 = 1 in             4 */
117157642Sps	/* 1073741824 = 1 in             2 */
118157642Sps
119157642Sps	/* Controls how often the l2_fhdr frame error check will fail. */
120189325Sdavidch	int l2fhdr_error_sim_control = 0;
121157642Sps
122157642Sps	/* Controls how often the unexpected attention check will fail. */
123189325Sdavidch	int unexpected_attention_sim_control = 0;
124157642Sps
125157642Sps	/* Controls how often to simulate an mbuf allocation failure. */
126189325Sdavidch	int mbuf_alloc_failed_sim_control = 0;
127157642Sps
128157642Sps	/* Controls how often to simulate a DMA mapping failure. */
129189325Sdavidch	int dma_map_addr_failed_sim_control = 0;
130157642Sps
131157642Sps	/* Controls how often to simulate a bootcode failure. */
132189325Sdavidch	int bootcode_running_failure_sim_control = 0;
133157642Sps#endif
134178132Sdavidch
135179695Sdavidch/****************************************************************************/
136157642Sps/* PCI Device ID Table                                                      */
137157642Sps/*                                                                          */
138157642Sps/* Used by bce_probe() to identify the devices supported by this driver.    */
139157642Sps/****************************************************************************/
140157642Sps#define BCE_DEVDESC_MAX		64
141157642Sps
142247565Smariusstatic const struct bce_type bce_devs[] = {
143157642Sps	/* BCM5706C Controllers and OEM boards. */
144157642Sps	{ BRCM_VENDORID, BRCM_DEVICEID_BCM5706,  HP_VENDORID, 0x3101,
145157642Sps		"HP NC370T Multifunction Gigabit Server Adapter" },
146157642Sps	{ BRCM_VENDORID, BRCM_DEVICEID_BCM5706,  HP_VENDORID, 0x3106,
147157642Sps		"HP NC370i Multifunction Gigabit Server Adapter" },
148187133Sdelphij	{ BRCM_VENDORID, BRCM_DEVICEID_BCM5706,  HP_VENDORID, 0x3070,
149187317Sdelphij		"HP NC380T PCIe DP Multifunc Gig Server Adapter" },
150187317Sdelphij	{ BRCM_VENDORID, BRCM_DEVICEID_BCM5706,  HP_VENDORID, 0x1709,
151187317Sdelphij		"HP NC371i Multifunction Gigabit Server Adapter" },
152157642Sps	{ BRCM_VENDORID, BRCM_DEVICEID_BCM5706,  PCI_ANY_ID,  PCI_ANY_ID,
153265703Sdavidcs		"QLogic NetXtreme II BCM5706 1000Base-T" },
154157642Sps
155157642Sps	/* BCM5706S controllers and OEM boards. */
156157642Sps	{ BRCM_VENDORID, BRCM_DEVICEID_BCM5706S, HP_VENDORID, 0x3102,
157157642Sps		"HP NC370F Multifunction Gigabit Server Adapter" },
158157642Sps	{ BRCM_VENDORID, BRCM_DEVICEID_BCM5706S, PCI_ANY_ID,  PCI_ANY_ID,
159265703Sdavidcs		"QLogic NetXtreme II BCM5706 1000Base-SX" },
160157642Sps
161157642Sps	/* BCM5708C controllers and OEM boards. */
162187133Sdelphij	{ BRCM_VENDORID, BRCM_DEVICEID_BCM5708,  HP_VENDORID, 0x7037,
163187317Sdelphij		"HP NC373T PCIe Multifunction Gig Server Adapter" },
164187133Sdelphij	{ BRCM_VENDORID, BRCM_DEVICEID_BCM5708,  HP_VENDORID, 0x7038,
165187317Sdelphij		"HP NC373i Multifunction Gigabit Server Adapter" },
166187317Sdelphij	{ BRCM_VENDORID, BRCM_DEVICEID_BCM5708,  HP_VENDORID, 0x7045,
167187317Sdelphij		"HP NC374m PCIe Multifunction Adapter" },
168157642Sps	{ BRCM_VENDORID, BRCM_DEVICEID_BCM5708,  PCI_ANY_ID,  PCI_ANY_ID,
169265703Sdavidcs		"QLogic NetXtreme II BCM5708 1000Base-T" },
170157642Sps
171157642Sps	/* BCM5708S controllers and OEM boards. */
172187133Sdelphij	{ BRCM_VENDORID, BRCM_DEVICEID_BCM5708S,  HP_VENDORID, 0x1706,
173187317Sdelphij		"HP NC373m Multifunction Gigabit Server Adapter" },
174187133Sdelphij	{ BRCM_VENDORID, BRCM_DEVICEID_BCM5708S,  HP_VENDORID, 0x703b,
175187317Sdelphij		"HP NC373i Multifunction Gigabit Server Adapter" },
176187133Sdelphij	{ BRCM_VENDORID, BRCM_DEVICEID_BCM5708S,  HP_VENDORID, 0x703d,
177187317Sdelphij		"HP NC373F PCIe Multifunc Giga Server Adapter" },
178163814Sscottl	{ BRCM_VENDORID, BRCM_DEVICEID_BCM5708S,  PCI_ANY_ID,  PCI_ANY_ID,
179265703Sdavidcs		"QLogic NetXtreme II BCM5708 1000Base-SX" },
180179771Sdavidch
181179771Sdavidch	/* BCM5709C controllers and OEM boards. */
182187133Sdelphij	{ BRCM_VENDORID, BRCM_DEVICEID_BCM5709,  HP_VENDORID, 0x7055,
183187317Sdelphij		"HP NC382i DP Multifunction Gigabit Server Adapter" },
184187133Sdelphij	{ BRCM_VENDORID, BRCM_DEVICEID_BCM5709,  HP_VENDORID, 0x7059,
185187317Sdelphij		"HP NC382T PCIe DP Multifunction Gigabit Server Adapter" },
186179771Sdavidch	{ BRCM_VENDORID, BRCM_DEVICEID_BCM5709,  PCI_ANY_ID,  PCI_ANY_ID,
187265703Sdavidcs		"QLogic NetXtreme II BCM5709 1000Base-T" },
188179771Sdavidch
189179771Sdavidch	/* BCM5709S controllers and OEM boards. */
190187133Sdelphij	{ BRCM_VENDORID, BRCM_DEVICEID_BCM5709S,  HP_VENDORID, 0x171d,
191187317Sdelphij		"HP NC382m DP 1GbE Multifunction BL-c Adapter" },
192187133Sdelphij	{ BRCM_VENDORID, BRCM_DEVICEID_BCM5709S,  HP_VENDORID, 0x7056,
193187317Sdelphij		"HP NC382i DP Multifunction Gigabit Server Adapter" },
194179771Sdavidch	{ BRCM_VENDORID, BRCM_DEVICEID_BCM5709S,  PCI_ANY_ID,  PCI_ANY_ID,
195265703Sdavidcs		"QLogic NetXtreme II BCM5709 1000Base-SX" },
196179771Sdavidch
197179771Sdavidch	/* BCM5716 controllers and OEM boards. */
198179771Sdavidch	{ BRCM_VENDORID, BRCM_DEVICEID_BCM5716,  PCI_ANY_ID,  PCI_ANY_ID,
199265703Sdavidcs		"QLogic NetXtreme II BCM5716 1000Base-T" },
200179771Sdavidch
201157642Sps	{ 0, 0, 0, 0, NULL }
202157642Sps};
203157642Sps
204157642Sps
205157642Sps/****************************************************************************/
206157642Sps/* Supported Flash NVRAM device data.                                       */
207157642Sps/****************************************************************************/
208247565Smariusstatic const struct flash_spec flash_table[] =
209157642Sps{
210179771Sdavidch#define BUFFERED_FLAGS		(BCE_NV_BUFFERED | BCE_NV_TRANSLATE)
211179771Sdavidch#define NONBUFFERED_FLAGS	(BCE_NV_WREN)
212179771Sdavidch
213157642Sps	/* Slow EEPROM */
214157642Sps	{0x00000000, 0x40830380, 0x009f0081, 0xa184a053, 0xaf000400,
215179771Sdavidch	 BUFFERED_FLAGS, SEEPROM_PAGE_BITS, SEEPROM_PAGE_SIZE,
216157642Sps	 SEEPROM_BYTE_ADDR_MASK, SEEPROM_TOTAL_SIZE,
217157642Sps	 "EEPROM - slow"},
218157642Sps	/* Expansion entry 0001 */
219157642Sps	{0x08000002, 0x4b808201, 0x00050081, 0x03840253, 0xaf020406,
220179771Sdavidch	 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
221157642Sps	 SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
222157642Sps	 "Entry 0001"},
223157642Sps	/* Saifun SA25F010 (non-buffered flash) */
224157642Sps	/* strap, cfg1, & write1 need updates */
225157642Sps	{0x04000001, 0x47808201, 0x00050081, 0x03840253, 0xaf020406,
226179771Sdavidch	 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
227157642Sps	 SAIFUN_FLASH_BYTE_ADDR_MASK, SAIFUN_FLASH_BASE_TOTAL_SIZE*2,
228157642Sps	 "Non-buffered flash (128kB)"},
229157642Sps	/* Saifun SA25F020 (non-buffered flash) */
230157642Sps	/* strap, cfg1, & write1 need updates */
231157642Sps	{0x0c000003, 0x4f808201, 0x00050081, 0x03840253, 0xaf020406,
232179771Sdavidch	 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
233157642Sps	 SAIFUN_FLASH_BYTE_ADDR_MASK, SAIFUN_FLASH_BASE_TOTAL_SIZE*4,
234157642Sps	 "Non-buffered flash (256kB)"},
235157642Sps	/* Expansion entry 0100 */
236157642Sps	{0x11000000, 0x53808201, 0x00050081, 0x03840253, 0xaf020406,
237179771Sdavidch	 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
238157642Sps	 SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
239157642Sps	 "Entry 0100"},
240157642Sps	/* Entry 0101: ST M45PE10 (non-buffered flash, TetonII B0) */
241157642Sps	{0x19000002, 0x5b808201, 0x000500db, 0x03840253, 0xaf020406,
242179771Sdavidch	 NONBUFFERED_FLAGS, ST_MICRO_FLASH_PAGE_BITS, ST_MICRO_FLASH_PAGE_SIZE,
243157642Sps	 ST_MICRO_FLASH_BYTE_ADDR_MASK, ST_MICRO_FLASH_BASE_TOTAL_SIZE*2,
244157642Sps	 "Entry 0101: ST M45PE10 (128kB non-bufferred)"},
245157642Sps	/* Entry 0110: ST M45PE20 (non-buffered flash)*/
246157642Sps	{0x15000001, 0x57808201, 0x000500db, 0x03840253, 0xaf020406,
247179771Sdavidch	 NONBUFFERED_FLAGS, ST_MICRO_FLASH_PAGE_BITS, ST_MICRO_FLASH_PAGE_SIZE,
248157642Sps	 ST_MICRO_FLASH_BYTE_ADDR_MASK, ST_MICRO_FLASH_BASE_TOTAL_SIZE*4,
249157642Sps	 "Entry 0110: ST M45PE20 (256kB non-bufferred)"},
250157642Sps	/* Saifun SA25F005 (non-buffered flash) */
251157642Sps	/* strap, cfg1, & write1 need updates */
252157642Sps	{0x1d000003, 0x5f808201, 0x00050081, 0x03840253, 0xaf020406,
253179771Sdavidch	 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
254157642Sps	 SAIFUN_FLASH_BYTE_ADDR_MASK, SAIFUN_FLASH_BASE_TOTAL_SIZE,
255157642Sps	 "Non-buffered flash (64kB)"},
256157642Sps	/* Fast EEPROM */
257157642Sps	{0x22000000, 0x62808380, 0x009f0081, 0xa184a053, 0xaf000400,
258179771Sdavidch	 BUFFERED_FLAGS, SEEPROM_PAGE_BITS, SEEPROM_PAGE_SIZE,
259157642Sps	 SEEPROM_BYTE_ADDR_MASK, SEEPROM_TOTAL_SIZE,
260157642Sps	 "EEPROM - fast"},
261157642Sps	/* Expansion entry 1001 */
262157642Sps	{0x2a000002, 0x6b808201, 0x00050081, 0x03840253, 0xaf020406,
263179771Sdavidch	 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
264157642Sps	 SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
265157642Sps	 "Entry 1001"},
266157642Sps	/* Expansion entry 1010 */
267157642Sps	{0x26000001, 0x67808201, 0x00050081, 0x03840253, 0xaf020406,
268179771Sdavidch	 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
269157642Sps	 SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
270157642Sps	 "Entry 1010"},
271157642Sps	/* ATMEL AT45DB011B (buffered flash) */
272157642Sps	{0x2e000003, 0x6e808273, 0x00570081, 0x68848353, 0xaf000400,
273179771Sdavidch	 BUFFERED_FLAGS, BUFFERED_FLASH_PAGE_BITS, BUFFERED_FLASH_PAGE_SIZE,
274157642Sps	 BUFFERED_FLASH_BYTE_ADDR_MASK, BUFFERED_FLASH_TOTAL_SIZE,
275157642Sps	 "Buffered flash (128kB)"},
276157642Sps	/* Expansion entry 1100 */
277157642Sps	{0x33000000, 0x73808201, 0x00050081, 0x03840253, 0xaf020406,
278179771Sdavidch	 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
279157642Sps	 SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
280157642Sps	 "Entry 1100"},
281157642Sps	/* Expansion entry 1101 */
282157642Sps	{0x3b000002, 0x7b808201, 0x00050081, 0x03840253, 0xaf020406,
283179771Sdavidch	 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
284157642Sps	 SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
285157642Sps	 "Entry 1101"},
286157642Sps	/* Ateml Expansion entry 1110 */
287157642Sps	{0x37000001, 0x76808273, 0x00570081, 0x68848353, 0xaf000400,
288179771Sdavidch	 BUFFERED_FLAGS, BUFFERED_FLASH_PAGE_BITS, BUFFERED_FLASH_PAGE_SIZE,
289157642Sps	 BUFFERED_FLASH_BYTE_ADDR_MASK, 0,
290157642Sps	 "Entry 1110 (Atmel)"},
291157642Sps	/* ATMEL AT45DB021B (buffered flash) */
292157642Sps	{0x3f000003, 0x7e808273, 0x00570081, 0x68848353, 0xaf000400,
293179771Sdavidch	 BUFFERED_FLAGS, BUFFERED_FLASH_PAGE_BITS, BUFFERED_FLASH_PAGE_SIZE,
294157642Sps	 BUFFERED_FLASH_BYTE_ADDR_MASK, BUFFERED_FLASH_TOTAL_SIZE*2,
295157642Sps	 "Buffered flash (256kB)"},
296157642Sps};
297157642Sps
298179771Sdavidch/*
299179771Sdavidch * The BCM5709 controllers transparently handle the
300179771Sdavidch * differences between Atmel 264 byte pages and all
301179771Sdavidch * flash devices which use 256 byte pages, so no
302179771Sdavidch * logical-to-physical mapping is required in the
303179771Sdavidch * driver.
304179771Sdavidch */
305247565Smariusstatic const struct flash_spec flash_5709 = {
306179771Sdavidch	.flags		= BCE_NV_BUFFERED,
307179771Sdavidch	.page_bits	= BCM5709_FLASH_PAGE_BITS,
308179771Sdavidch	.page_size	= BCM5709_FLASH_PAGE_SIZE,
309179771Sdavidch	.addr_mask	= BCM5709_FLASH_BYTE_ADDR_MASK,
310179771Sdavidch	.total_size	= BUFFERED_FLASH_TOTAL_SIZE * 2,
311182293Sdavidch	.name		= "5709/5716 buffered flash (256kB)",
312179771Sdavidch};
313157642Sps
314179771Sdavidch
315157642Sps/****************************************************************************/
316157642Sps/* FreeBSD device entry points.                                             */
317157642Sps/****************************************************************************/
318206268Sdavidchstatic int  bce_probe			(device_t);
319206268Sdavidchstatic int  bce_attach			(device_t);
320206268Sdavidchstatic int  bce_detach			(device_t);
321206268Sdavidchstatic int  bce_shutdown		(device_t);
322157642Sps
323157642Sps
324157642Sps/****************************************************************************/
325157642Sps/* BCE Debug Data Structure Dump Routines                                   */
326157642Sps/****************************************************************************/
327157642Sps#ifdef BCE_DEBUG
328218423Sdavidchstatic u32  bce_reg_rd				(struct bce_softc *, u32);
329218423Sdavidchstatic void bce_reg_wr				(struct bce_softc *, u32, u32);
330218423Sdavidchstatic void bce_reg_wr16			(struct bce_softc *, u32, u16);
331218423Sdavidchstatic u32  bce_ctx_rd				(struct bce_softc *, u32, u32);
332218423Sdavidchstatic void bce_dump_enet			(struct bce_softc *, struct mbuf *);
333218423Sdavidchstatic void bce_dump_mbuf			(struct bce_softc *, struct mbuf *);
334176448Sdavidchstatic void bce_dump_tx_mbuf_chain	(struct bce_softc *, u16, int);
335176448Sdavidchstatic void bce_dump_rx_mbuf_chain	(struct bce_softc *, u16, int);
336179771Sdavidchstatic void bce_dump_pg_mbuf_chain	(struct bce_softc *, u16, int);
337218423Sdavidchstatic void bce_dump_txbd			(struct bce_softc *,
338206268Sdavidch    int, struct tx_bd *);
339218423Sdavidchstatic void bce_dump_rxbd			(struct bce_softc *,
340206268Sdavidch    int, struct rx_bd *);
341218423Sdavidchstatic void bce_dump_pgbd			(struct bce_softc *,
342206268Sdavidch    int, struct rx_bd *);
343206268Sdavidchstatic void bce_dump_l2fhdr		(struct bce_softc *,
344206268Sdavidch    int, struct l2_fhdr *);
345218423Sdavidchstatic void bce_dump_ctx			(struct bce_softc *, u16);
346218423Sdavidchstatic void bce_dump_ftqs			(struct bce_softc *);
347176448Sdavidchstatic void bce_dump_tx_chain		(struct bce_softc *, u16, int);
348206268Sdavidchstatic void bce_dump_rx_bd_chain	(struct bce_softc *, u16, int);
349179771Sdavidchstatic void bce_dump_pg_chain		(struct bce_softc *, u16, int);
350157642Spsstatic void bce_dump_status_block	(struct bce_softc *);
351157642Spsstatic void bce_dump_stats_block	(struct bce_softc *);
352157642Spsstatic void bce_dump_driver_state	(struct bce_softc *);
353157642Spsstatic void bce_dump_hw_state		(struct bce_softc *);
354218423Sdavidchstatic void bce_dump_shmem_state	(struct bce_softc *);
355206268Sdavidchstatic void bce_dump_mq_regs		(struct bce_softc *);
356170810Sdavidchstatic void bce_dump_bc_state		(struct bce_softc *);
357179771Sdavidchstatic void bce_dump_txp_state		(struct bce_softc *, int);
358179771Sdavidchstatic void bce_dump_rxp_state		(struct bce_softc *, int);
359218423Sdavidchstatic void bce_dump_tpat_state	(struct bce_softc *, int);
360179771Sdavidchstatic void bce_dump_cp_state		(struct bce_softc *, int);
361179771Sdavidchstatic void bce_dump_com_state		(struct bce_softc *, int);
362218423Sdavidchstatic void bce_dump_rv2p_state	(struct bce_softc *);
363218423Sdavidchstatic void bce_breakpoint			(struct bce_softc *);
364218423Sdavidch#endif /*BCE_DEBUG */
365157642Sps
366157642Sps
367157642Sps/****************************************************************************/
368157642Sps/* BCE Register/Memory Access Routines                                      */
369157642Sps/****************************************************************************/
370206268Sdavidchstatic u32  bce_reg_rd_ind		(struct bce_softc *, u32);
371206268Sdavidchstatic void bce_reg_wr_ind		(struct bce_softc *, u32, u32);
372206268Sdavidchstatic void bce_shmem_wr		(struct bce_softc *, u32, u32);
373206268Sdavidchstatic u32  bce_shmem_rd		(struct bce_softc *, u32);
374206268Sdavidchstatic void bce_ctx_wr			(struct bce_softc *, u32, u32, u32);
375157642Spsstatic int  bce_miibus_read_reg		(device_t, int, int);
376157642Spsstatic int  bce_miibus_write_reg	(device_t, int, int, int);
377157642Spsstatic void bce_miibus_statchg		(device_t);
378157642Sps
379213489Sambrisko#ifdef BCE_DEBUG
380218527Sdavidchstatic int bce_sysctl_nvram_dump(SYSCTL_HANDLER_ARGS);
381213489Sambrisko#ifdef BCE_NVRAM_WRITE_SUPPORT
382218527Sdavidchstatic int bce_sysctl_nvram_write(SYSCTL_HANDLER_ARGS);
383213489Sambrisko#endif
384213489Sambrisko#endif
385157642Sps
386157642Sps/****************************************************************************/
387157642Sps/* BCE NVRAM Access Routines                                                */
388157642Sps/****************************************************************************/
389157642Spsstatic int  bce_acquire_nvram_lock	(struct bce_softc *);
390157642Spsstatic int  bce_release_nvram_lock	(struct bce_softc *);
391218423Sdavidchstatic void bce_enable_nvram_access(struct bce_softc *);
392218423Sdavidchstatic void bce_disable_nvram_access(struct bce_softc *);
393157642Spsstatic int  bce_nvram_read_dword	(struct bce_softc *, u32, u8 *, u32);
394218423Sdavidchstatic int  bce_init_nvram			(struct bce_softc *);
395218423Sdavidchstatic int  bce_nvram_read			(struct bce_softc *, u32, u8 *, int);
396218423Sdavidchstatic int  bce_nvram_test			(struct bce_softc *);
397157642Sps#ifdef BCE_NVRAM_WRITE_SUPPORT
398157642Spsstatic int  bce_enable_nvram_write	(struct bce_softc *);
399218423Sdavidchstatic void bce_disable_nvram_write(struct bce_softc *);
400157642Spsstatic int  bce_nvram_erase_page	(struct bce_softc *, u32);
401157642Spsstatic int  bce_nvram_write_dword	(struct bce_softc *, u32, u8 *, u32);
402206268Sdavidchstatic int  bce_nvram_write		(struct bce_softc *, u32, u8 *, int);
403157642Sps#endif
404157642Sps
405157642Sps/****************************************************************************/
406157642Sps/*                                                                          */
407157642Sps/****************************************************************************/
408218423Sdavidchstatic void bce_get_rx_buffer_sizes(struct bce_softc *, int);
409218423Sdavidchstatic void bce_get_media			(struct bce_softc *);
410218423Sdavidchstatic void bce_init_media			(struct bce_softc *);
411235151Syongaristatic u32 bce_get_rphy_link		(struct bce_softc *);
412218423Sdavidchstatic void bce_dma_map_addr		(void *, bus_dma_segment_t *, int, int);
413218423Sdavidchstatic int  bce_dma_alloc			(device_t);
414218423Sdavidchstatic void bce_dma_free			(struct bce_softc *);
415157642Spsstatic void bce_release_resources	(struct bce_softc *);
416157642Sps
417157642Sps/****************************************************************************/
418157642Sps/* BCE Firmware Synchronization and Load                                    */
419157642Sps/****************************************************************************/
420235151Syongaristatic void bce_fw_cap_init			(struct bce_softc *);
421206268Sdavidchstatic int  bce_fw_sync			(struct bce_softc *, u32);
422251142Smariusstatic void bce_load_rv2p_fw		(struct bce_softc *, const u32 *, u32,
423251142Smarius    u32);
424207411Sdavidchstatic void bce_load_cpu_fw		(struct bce_softc *,
425206268Sdavidch    struct cpu_reg *, struct fw_info *);
426218423Sdavidchstatic void bce_start_cpu			(struct bce_softc *, struct cpu_reg *);
427218423Sdavidchstatic void bce_halt_cpu			(struct bce_softc *, struct cpu_reg *);
428206268Sdavidchstatic void bce_start_rxp_cpu		(struct bce_softc *);
429179771Sdavidchstatic void bce_init_rxp_cpu		(struct bce_softc *);
430179771Sdavidchstatic void bce_init_txp_cpu 		(struct bce_softc *);
431179771Sdavidchstatic void bce_init_tpat_cpu		(struct bce_softc *);
432206268Sdavidchstatic void bce_init_cp_cpu	  	(struct bce_softc *);
433179771Sdavidchstatic void bce_init_com_cpu	  	(struct bce_softc *);
434218423Sdavidchstatic void bce_init_cpus			(struct bce_softc *);
435157642Sps
436218423Sdavidchstatic void bce_print_adapter_info	(struct bce_softc *);
437179771Sdavidchstatic void bce_probe_pci_caps		(device_t, struct bce_softc *);
438218423Sdavidchstatic void bce_stop				(struct bce_softc *);
439218423Sdavidchstatic int  bce_reset				(struct bce_softc *, u32);
440218423Sdavidchstatic int  bce_chipinit 			(struct bce_softc *);
441218423Sdavidchstatic int  bce_blockinit 			(struct bce_softc *);
442157642Sps
443157642Spsstatic int  bce_init_tx_chain		(struct bce_softc *);
444176448Sdavidchstatic void bce_free_tx_chain		(struct bce_softc *);
445176448Sdavidch
446251146Smariusstatic int  bce_get_rx_buf		(struct bce_softc *, u16, u16, u32 *);
447176448Sdavidchstatic int  bce_init_rx_chain		(struct bce_softc *);
448171667Sdavidchstatic void bce_fill_rx_chain		(struct bce_softc *);
449157642Spsstatic void bce_free_rx_chain		(struct bce_softc *);
450179771Sdavidch
451251146Smariusstatic int  bce_get_pg_buf		(struct bce_softc *, u16, u16);
452176448Sdavidchstatic int  bce_init_pg_chain		(struct bce_softc *);
453176448Sdavidchstatic void bce_fill_pg_chain		(struct bce_softc *);
454179771Sdavidchstatic void bce_free_pg_chain		(struct bce_softc *);
455176448Sdavidch
456207411Sdavidchstatic struct mbuf *bce_tso_setup	(struct bce_softc *,
457206268Sdavidch    struct mbuf **, u16 *);
458218423Sdavidchstatic int  bce_tx_encap			(struct bce_softc *, struct mbuf **);
459157642Spsstatic void bce_start_locked		(struct ifnet *);
460272096Sglebiusstatic void bce_start			(struct ifnet *);
461272096Sglebiusstatic int  bce_ioctl			(struct ifnet *, u_long, caddr_t);
462272096Sglebiusstatic uint64_t bce_get_counter		(struct ifnet *, ift_counter);
463272096Sglebiusstatic void bce_watchdog		(struct bce_softc *);
464206268Sdavidchstatic int  bce_ifmedia_upd		(struct ifnet *);
465210261Syongaristatic int  bce_ifmedia_upd_locked	(struct ifnet *);
466206268Sdavidchstatic void bce_ifmedia_sts		(struct ifnet *, struct ifmediareq *);
467235151Syongaristatic void bce_ifmedia_sts_rphy	(struct bce_softc *, struct ifmediareq *);
468206268Sdavidchstatic void bce_init_locked		(struct bce_softc *);
469218423Sdavidchstatic void bce_init				(void *);
470171667Sdavidchstatic void bce_mgmt_init_locked	(struct bce_softc *sc);
471157642Sps
472218423Sdavidchstatic int  bce_init_ctx			(struct bce_softc *);
473157642Spsstatic void bce_get_mac_addr		(struct bce_softc *);
474157642Spsstatic void bce_set_mac_addr		(struct bce_softc *);
475218423Sdavidchstatic void bce_phy_intr			(struct bce_softc *);
476206268Sdavidchstatic inline u16 bce_get_hw_rx_cons	(struct bce_softc *);
477206268Sdavidchstatic void bce_rx_intr			(struct bce_softc *);
478206268Sdavidchstatic void bce_tx_intr			(struct bce_softc *);
479157642Spsstatic void bce_disable_intr		(struct bce_softc *);
480206268Sdavidchstatic void bce_enable_intr		(struct bce_softc *, int);
481179771Sdavidch
482218423Sdavidchstatic void bce_intr				(void *);
483206268Sdavidchstatic void bce_set_rx_mode		(struct bce_softc *);
484157642Spsstatic void bce_stats_update		(struct bce_softc *);
485218423Sdavidchstatic void bce_tick				(void *);
486218423Sdavidchstatic void bce_pulse				(void *);
487206268Sdavidchstatic void bce_add_sysctls		(struct bce_softc *);
488157642Sps
489157642Sps
490157642Sps/****************************************************************************/
491157642Sps/* FreeBSD device dispatch table.                                           */
492157642Sps/****************************************************************************/
493157642Spsstatic device_method_t bce_methods[] = {
494176448Sdavidch	/* Device interface (device_if.h) */
495157642Sps	DEVMETHOD(device_probe,		bce_probe),
496157642Sps	DEVMETHOD(device_attach,	bce_attach),
497157642Sps	DEVMETHOD(device_detach,	bce_detach),
498157642Sps	DEVMETHOD(device_shutdown,	bce_shutdown),
499178132Sdavidch/* Supported by device interface but not used here. */
500176448Sdavidch/*	DEVMETHOD(device_identify,	bce_identify),      */
501176448Sdavidch/*	DEVMETHOD(device_suspend,	bce_suspend),       */
502176448Sdavidch/*	DEVMETHOD(device_resume,	bce_resume),        */
503176448Sdavidch/*	DEVMETHOD(device_quiesce,	bce_quiesce),       */
504157642Sps
505176448Sdavidch	/* MII interface (miibus_if.h) */
506157642Sps	DEVMETHOD(miibus_readreg,	bce_miibus_read_reg),
507157642Sps	DEVMETHOD(miibus_writereg,	bce_miibus_write_reg),
508157642Sps	DEVMETHOD(miibus_statchg,	bce_miibus_statchg),
509178132Sdavidch/* Supported by MII interface but not used here.       */
510176448Sdavidch/*	DEVMETHOD(miibus_linkchg,	bce_miibus_linkchg),   */
511176448Sdavidch/*	DEVMETHOD(miibus_mediainit,	bce_miibus_mediainit), */
512157642Sps
513227843Smarius	DEVMETHOD_END
514157642Sps};
515157642Sps
516157642Spsstatic driver_t bce_driver = {
517157642Sps	"bce",
518157642Sps	bce_methods,
519157642Sps	sizeof(struct bce_softc)
520157642Sps};
521157642Sps
522157642Spsstatic devclass_t bce_devclass;
523157642Sps
524157642SpsMODULE_DEPEND(bce, pci, 1, 1, 1);
525157642SpsMODULE_DEPEND(bce, ether, 1, 1, 1);
526157642SpsMODULE_DEPEND(bce, miibus, 1, 1, 1);
527157642Sps
528247565SmariusDRIVER_MODULE(bce, pci, bce_driver, bce_devclass, NULL, NULL);
529247565SmariusDRIVER_MODULE(miibus, bce, miibus_driver, miibus_devclass, NULL, NULL);
530170392Sdavidch
531170392Sdavidch
532169632Sdavidch/****************************************************************************/
533169632Sdavidch/* Tunable device values                                                    */
534169632Sdavidch/****************************************************************************/
535227309Sedstatic SYSCTL_NODE(_hw, OID_AUTO, bce, CTLFLAG_RD, 0, "bce driver parameters");
536176448Sdavidch
537170392Sdavidch/* Allowable values are TRUE or FALSE */
538218423Sdavidchstatic int bce_verbose = TRUE;
539218423SdavidchSYSCTL_INT(_hw_bce, OID_AUTO, verbose, CTLFLAG_RDTUN, &bce_verbose, 0,
540218423Sdavidch    "Verbose output enable/disable");
541218423Sdavidch
542218423Sdavidch/* Allowable values are TRUE or FALSE */
543179771Sdavidchstatic int bce_tso_enable = TRUE;
544217323SmdfSYSCTL_INT(_hw_bce, OID_AUTO, tso_enable, CTLFLAG_RDTUN, &bce_tso_enable, 0,
545218423Sdavidch    "TSO Enable/Disable");
546176448Sdavidch
547179771Sdavidch/* Allowable values are 0 (IRQ), 1 (MSI/IRQ), and 2 (MSI-X/MSI/IRQ) */
548179771Sdavidch/* ToDo: Add MSI-X support. */
549179771Sdavidchstatic int bce_msi_enable = 1;
550217323SmdfSYSCTL_INT(_hw_bce, OID_AUTO, msi_enable, CTLFLAG_RDTUN, &bce_msi_enable, 0,
551218423Sdavidch    "MSI-X|MSI|INTx selector");
552178132Sdavidch
553218423Sdavidch/* Allowable values are 1, 2, 4, 8. */
554218423Sdavidchstatic int bce_rx_pages = DEFAULT_RX_PAGES;
555218423SdavidchSYSCTL_UINT(_hw_bce, OID_AUTO, rx_pages, CTLFLAG_RDTUN, &bce_rx_pages, 0,
556218423Sdavidch    "Receive buffer descriptor pages (1 page = 255 buffer descriptors)");
557170392Sdavidch
558218423Sdavidch/* Allowable values are 1, 2, 4, 8. */
559218423Sdavidchstatic int bce_tx_pages = DEFAULT_TX_PAGES;
560218423SdavidchSYSCTL_UINT(_hw_bce, OID_AUTO, tx_pages, CTLFLAG_RDTUN, &bce_tx_pages, 0,
561218423Sdavidch    "Transmit buffer descriptor pages (1 page = 255 buffer descriptors)");
562182293Sdavidch
563218423Sdavidch/* Allowable values are TRUE or FALSE. */
564218423Sdavidchstatic int bce_hdr_split = TRUE;
565218423SdavidchSYSCTL_UINT(_hw_bce, OID_AUTO, hdr_split, CTLFLAG_RDTUN, &bce_hdr_split, 0,
566218423Sdavidch    "Frame header/payload splitting Enable/Disable");
567218423Sdavidch
568218423Sdavidch/* Allowable values are TRUE or FALSE. */
569218423Sdavidchstatic int bce_strict_rx_mtu = FALSE;
570235145SdavidchSYSCTL_UINT(_hw_bce, OID_AUTO, strict_rx_mtu, CTLFLAG_RDTUN,
571218423Sdavidch    &bce_strict_rx_mtu, 0,
572218423Sdavidch    "Enable/Disable strict RX frame size checking");
573218423Sdavidch
574218423Sdavidch/* Allowable values are 0 ... 100 */
575218423Sdavidch#ifdef BCE_DEBUG
576218423Sdavidch/* Generate 1 interrupt for every transmit completion. */
577218423Sdavidchstatic int bce_tx_quick_cons_trip_int = 1;
578218423Sdavidch#else
579218423Sdavidch/* Generate 1 interrupt for every 20 transmit completions. */
580218423Sdavidchstatic int bce_tx_quick_cons_trip_int = DEFAULT_TX_QUICK_CONS_TRIP_INT;
581218423Sdavidch#endif
582218423SdavidchSYSCTL_UINT(_hw_bce, OID_AUTO, tx_quick_cons_trip_int, CTLFLAG_RDTUN,
583218423Sdavidch    &bce_tx_quick_cons_trip_int, 0,
584218423Sdavidch    "Transmit BD trip point during interrupts");
585218423Sdavidch
586218423Sdavidch/* Allowable values are 0 ... 100 */
587218423Sdavidch/* Generate 1 interrupt for every transmit completion. */
588218423Sdavidch#ifdef BCE_DEBUG
589218423Sdavidchstatic int bce_tx_quick_cons_trip = 1;
590218423Sdavidch#else
591218423Sdavidch/* Generate 1 interrupt for every 20 transmit completions. */
592218423Sdavidchstatic int bce_tx_quick_cons_trip = DEFAULT_TX_QUICK_CONS_TRIP;
593218423Sdavidch#endif
594218423SdavidchSYSCTL_UINT(_hw_bce, OID_AUTO, tx_quick_cons_trip, CTLFLAG_RDTUN,
595218423Sdavidch    &bce_tx_quick_cons_trip, 0,
596218423Sdavidch    "Transmit BD trip point");
597218423Sdavidch
598218423Sdavidch/* Allowable values are 0 ... 100 */
599218423Sdavidch#ifdef BCE_DEBUG
600218423Sdavidch/* Generate an interrupt if 0us have elapsed since the last TX completion. */
601218423Sdavidchstatic int bce_tx_ticks_int = 0;
602218423Sdavidch#else
603218423Sdavidch/* Generate an interrupt if 80us have elapsed since the last TX completion. */
604218423Sdavidchstatic int bce_tx_ticks_int = DEFAULT_TX_TICKS_INT;
605218423Sdavidch#endif
606218423SdavidchSYSCTL_UINT(_hw_bce, OID_AUTO, tx_ticks_int, CTLFLAG_RDTUN,
607218423Sdavidch    &bce_tx_ticks_int, 0, "Transmit ticks count during interrupt");
608218423Sdavidch
609218423Sdavidch/* Allowable values are 0 ... 100 */
610218423Sdavidch#ifdef BCE_DEBUG
611218423Sdavidch/* Generate an interrupt if 0us have elapsed since the last TX completion. */
612218423Sdavidchstatic int bce_tx_ticks = 0;
613218423Sdavidch#else
614218423Sdavidch/* Generate an interrupt if 80us have elapsed since the last TX completion. */
615218423Sdavidchstatic int bce_tx_ticks = DEFAULT_TX_TICKS;
616218423Sdavidch#endif
617218423SdavidchSYSCTL_UINT(_hw_bce, OID_AUTO, tx_ticks, CTLFLAG_RDTUN,
618218423Sdavidch    &bce_tx_ticks, 0, "Transmit ticks count");
619218423Sdavidch
620218423Sdavidch/* Allowable values are 1 ... 100 */
621218423Sdavidch#ifdef BCE_DEBUG
622218423Sdavidch/* Generate 1 interrupt for every received frame. */
623218423Sdavidchstatic int bce_rx_quick_cons_trip_int = 1;
624218423Sdavidch#else
625218423Sdavidch/* Generate 1 interrupt for every 6 received frames. */
626218423Sdavidchstatic int bce_rx_quick_cons_trip_int = DEFAULT_RX_QUICK_CONS_TRIP_INT;
627218423Sdavidch#endif
628218423SdavidchSYSCTL_UINT(_hw_bce, OID_AUTO, rx_quick_cons_trip_int, CTLFLAG_RDTUN,
629218423Sdavidch    &bce_rx_quick_cons_trip_int, 0,
630218423Sdavidch    "Receive BD trip point duirng interrupts");
631218423Sdavidch
632218423Sdavidch/* Allowable values are 1 ... 100 */
633218423Sdavidch#ifdef BCE_DEBUG
634218423Sdavidch/* Generate 1 interrupt for every received frame. */
635218423Sdavidchstatic int bce_rx_quick_cons_trip = 1;
636218423Sdavidch#else
637218423Sdavidch/* Generate 1 interrupt for every 6 received frames. */
638218423Sdavidchstatic int bce_rx_quick_cons_trip = DEFAULT_RX_QUICK_CONS_TRIP;
639218423Sdavidch#endif
640218423SdavidchSYSCTL_UINT(_hw_bce, OID_AUTO, rx_quick_cons_trip, CTLFLAG_RDTUN,
641218423Sdavidch    &bce_rx_quick_cons_trip, 0,
642218423Sdavidch    "Receive BD trip point");
643218423Sdavidch
644218423Sdavidch/* Allowable values are 0 ... 100 */
645218423Sdavidch#ifdef BCE_DEBUG
646218423Sdavidch/* Generate an int. if 0us have elapsed since the last received frame. */
647218423Sdavidchstatic int bce_rx_ticks_int = 0;
648218423Sdavidch#else
649218423Sdavidch/* Generate an int. if 18us have elapsed since the last received frame. */
650218423Sdavidchstatic int bce_rx_ticks_int = DEFAULT_RX_TICKS_INT;
651218423Sdavidch#endif
652218423SdavidchSYSCTL_UINT(_hw_bce, OID_AUTO, rx_ticks_int, CTLFLAG_RDTUN,
653218423Sdavidch    &bce_rx_ticks_int, 0, "Receive ticks count during interrupt");
654218423Sdavidch
655218423Sdavidch/* Allowable values are 0 ... 100 */
656218423Sdavidch#ifdef BCE_DEBUG
657218423Sdavidch/* Generate an int. if 0us have elapsed since the last received frame. */
658218423Sdavidchstatic int bce_rx_ticks = 0;
659218423Sdavidch#else
660218423Sdavidch/* Generate an int. if 18us have elapsed since the last received frame. */
661218423Sdavidchstatic int bce_rx_ticks = DEFAULT_RX_TICKS;
662218423Sdavidch#endif
663218423SdavidchSYSCTL_UINT(_hw_bce, OID_AUTO, rx_ticks, CTLFLAG_RDTUN,
664218423Sdavidch    &bce_rx_ticks, 0, "Receive ticks count");
665218423Sdavidch
666218423Sdavidch
667157642Sps/****************************************************************************/
668157642Sps/* Device probe function.                                                   */
669157642Sps/*                                                                          */
670157642Sps/* Compares the device to the driver's list of supported devices and        */
671157642Sps/* reports back to the OS whether this is the right driver for the device.  */
672157642Sps/*                                                                          */
673157642Sps/* Returns:                                                                 */
674157642Sps/*   BUS_PROBE_DEFAULT on success, positive value on failure.               */
675157642Sps/****************************************************************************/
676157642Spsstatic int
677157642Spsbce_probe(device_t dev)
678157642Sps{
679247565Smarius	const struct bce_type *t;
680157642Sps	struct bce_softc *sc;
681157642Sps	char *descbuf;
682157642Sps	u16 vid = 0, did = 0, svid = 0, sdid = 0;
683157642Sps
684157642Sps	t = bce_devs;
685157642Sps
686157642Sps	sc = device_get_softc(dev);
687157642Sps	sc->bce_unit = device_get_unit(dev);
688157642Sps	sc->bce_dev = dev;
689157642Sps
690157642Sps	/* Get the data for the device to be probed. */
691157642Sps	vid  = pci_get_vendor(dev);
692157642Sps	did  = pci_get_device(dev);
693157642Sps	svid = pci_get_subvendor(dev);
694157642Sps	sdid = pci_get_subdevice(dev);
695157642Sps
696179771Sdavidch	DBPRINT(sc, BCE_EXTREME_LOAD,
697206268Sdavidch	    "%s(); VID = 0x%04X, DID = 0x%04X, SVID = 0x%04X, "
698206268Sdavidch	    "SDID = 0x%04X\n", __FUNCTION__, vid, did, svid, sdid);
699157642Sps
700157642Sps	/* Look through the list of known devices for a match. */
701157642Sps	while(t->bce_name != NULL) {
702157642Sps
703179771Sdavidch		if ((vid == t->bce_vid) && (did == t->bce_did) &&
704206268Sdavidch		    ((svid == t->bce_svid) || (t->bce_svid == PCI_ANY_ID)) &&
705206268Sdavidch		    ((sdid == t->bce_sdid) || (t->bce_sdid == PCI_ANY_ID))) {
706157642Sps
707157642Sps			descbuf = malloc(BCE_DEVDESC_MAX, M_TEMP, M_NOWAIT);
708157642Sps
709157642Sps			if (descbuf == NULL)
710157642Sps				return(ENOMEM);
711157642Sps
712157642Sps			/* Print out the device identity. */
713179771Sdavidch			snprintf(descbuf, BCE_DEVDESC_MAX, "%s (%c%d)",
714207411Sdavidch			    t->bce_name, (((pci_read_config(dev,
715206268Sdavidch			    PCIR_REVID, 4) & 0xf0) >> 4) + 'A'),
716169271Sdavidch			    (pci_read_config(dev, PCIR_REVID, 4) & 0xf));
717157642Sps
718157642Sps			device_set_desc_copy(dev, descbuf);
719157642Sps			free(descbuf, M_TEMP);
720157642Sps			return(BUS_PROBE_DEFAULT);
721157642Sps		}
722157642Sps		t++;
723157642Sps	}
724157642Sps
725157642Sps	return(ENXIO);
726157642Sps}
727157642Sps
728157642Sps
729157642Sps/****************************************************************************/
730179771Sdavidch/* PCI Capabilities Probe Function.                                         */
731179771Sdavidch/*                                                                          */
732179771Sdavidch/* Walks the PCI capabiites list for the device to find what features are   */
733179771Sdavidch/* supported.                                                               */
734179771Sdavidch/*                                                                          */
735179771Sdavidch/* Returns:                                                                 */
736179771Sdavidch/*   None.                                                                  */
737179771Sdavidch/****************************************************************************/
738179771Sdavidchstatic void
739179771Sdavidchbce_print_adapter_info(struct bce_softc *sc)
740179771Sdavidch{
741207411Sdavidch	int i = 0;
742194781Sdavidch
743179771Sdavidch	DBENTER(BCE_VERBOSE_LOAD);
744179771Sdavidch
745218423Sdavidch	if (bce_verbose || bootverbose) {
746207411Sdavidch		BCE_PRINTF("ASIC (0x%08X); ", sc->bce_chipid);
747207411Sdavidch		printf("Rev (%c%d); ", ((BCE_CHIP_ID(sc) & 0xf000) >>
748207411Sdavidch		    12) + 'A', ((BCE_CHIP_ID(sc) & 0x0ff0) >> 4));
749179771Sdavidch
750207411Sdavidch
751207411Sdavidch		/* Bus info. */
752207411Sdavidch		if (sc->bce_flags & BCE_PCIE_FLAG) {
753207411Sdavidch			printf("Bus (PCIe x%d, ", sc->link_width);
754207411Sdavidch			switch (sc->link_speed) {
755207411Sdavidch			case 1: printf("2.5Gbps); "); break;
756207411Sdavidch			case 2:	printf("5Gbps); "); break;
757207411Sdavidch			default: printf("Unknown link speed); ");
758207411Sdavidch			}
759207411Sdavidch		} else {
760207411Sdavidch			printf("Bus (PCI%s, %s, %dMHz); ",
761207411Sdavidch			    ((sc->bce_flags & BCE_PCIX_FLAG) ? "-X" : ""),
762207411Sdavidch			    ((sc->bce_flags & BCE_PCI_32BIT_FLAG) ?
763207411Sdavidch			    "32-bit" : "64-bit"), sc->bus_speed_mhz);
764179771Sdavidch		}
765179771Sdavidch
766207411Sdavidch		/* Firmware version and device features. */
767218423Sdavidch		printf("B/C (%s); Bufs (RX:%d;TX:%d;PG:%d); Flags (",
768218423Sdavidch		    sc->bce_bc_ver,	sc->rx_pages, sc->tx_pages,
769218423Sdavidch		    (bce_hdr_split == TRUE ? sc->pg_pages: 0));
770194781Sdavidch
771218423Sdavidch		if (bce_hdr_split == TRUE) {
772218423Sdavidch			printf("SPLT");
773218423Sdavidch			i++;
774218423Sdavidch		}
775202717Sdavidch
776207411Sdavidch		if (sc->bce_flags & BCE_USING_MSI_FLAG) {
777207411Sdavidch			if (i > 0) printf("|");
778207411Sdavidch			printf("MSI"); i++;
779207411Sdavidch		}
780179771Sdavidch
781207411Sdavidch		if (sc->bce_flags & BCE_USING_MSIX_FLAG) {
782207411Sdavidch			if (i > 0) printf("|");
783207411Sdavidch			printf("MSI-X"); i++;
784207411Sdavidch		}
785194781Sdavidch
786207411Sdavidch		if (sc->bce_phy_flags & BCE_PHY_2_5G_CAPABLE_FLAG) {
787207411Sdavidch			if (i > 0) printf("|");
788207411Sdavidch			printf("2.5G"); i++;
789207411Sdavidch		}
790194781Sdavidch
791235151Syongari		if (sc->bce_phy_flags & BCE_PHY_REMOTE_CAP_FLAG) {
792235151Syongari			if (i > 0) printf("|");
793235151Syongari			printf("Remote PHY(%s)",
794235151Syongari			    sc->bce_phy_flags & BCE_PHY_REMOTE_PORT_FIBER_FLAG ?
795235151Syongari			    "FIBER" : "TP"); i++;
796235151Syongari		}
797235151Syongari
798207411Sdavidch		if (sc->bce_flags & BCE_MFW_ENABLE_FLAG) {
799207411Sdavidch			if (i > 0) printf("|");
800207411Sdavidch			printf("MFW); MFW (%s)\n", sc->bce_mfw_ver);
801207411Sdavidch		} else {
802207411Sdavidch			printf(")\n");
803207411Sdavidch		}
804218423Sdavidch
805218423Sdavidch		printf("Coal (RX:%d,%d,%d,%d; TX:%d,%d,%d,%d)\n",
806218423Sdavidch		    sc->bce_rx_quick_cons_trip_int,
807218423Sdavidch		    sc->bce_rx_quick_cons_trip,
808218423Sdavidch		    sc->bce_rx_ticks_int,
809218423Sdavidch		    sc->bce_rx_ticks,
810218423Sdavidch		    sc->bce_tx_quick_cons_trip_int,
811218423Sdavidch		    sc->bce_tx_quick_cons_trip,
812218423Sdavidch		    sc->bce_tx_ticks_int,
813218423Sdavidch		    sc->bce_tx_ticks);
814218423Sdavidch
815206268Sdavidch	}
816194781Sdavidch
817196970Sphk	DBEXIT(BCE_VERBOSE_LOAD);
818179771Sdavidch}
819179771Sdavidch
820179771Sdavidch
821179771Sdavidch/****************************************************************************/
822179771Sdavidch/* PCI Capabilities Probe Function.                                         */
823179771Sdavidch/*                                                                          */
824179771Sdavidch/* Walks the PCI capabiites list for the device to find what features are   */
825179771Sdavidch/* supported.                                                               */
826179771Sdavidch/*                                                                          */
827179771Sdavidch/* Returns:                                                                 */
828179771Sdavidch/*   None.                                                                  */
829179771Sdavidch/****************************************************************************/
830179771Sdavidchstatic void
831179771Sdavidchbce_probe_pci_caps(device_t dev, struct bce_softc *sc)
832179771Sdavidch{
833179771Sdavidch	u32 reg;
834179771Sdavidch
835179771Sdavidch	DBENTER(BCE_VERBOSE_LOAD);
836179771Sdavidch
837179771Sdavidch	/* Check if PCI-X capability is enabled. */
838219902Sjhb	if (pci_find_cap(dev, PCIY_PCIX, &reg) == 0) {
839179771Sdavidch		if (reg != 0)
840179771Sdavidch			sc->bce_cap_flags |= BCE_PCIX_CAPABLE_FLAG;
841179771Sdavidch	}
842179771Sdavidch
843179771Sdavidch	/* Check if PCIe capability is enabled. */
844219902Sjhb	if (pci_find_cap(dev, PCIY_EXPRESS, &reg) == 0) {
845179771Sdavidch		if (reg != 0) {
846179771Sdavidch			u16 link_status = pci_read_config(dev, reg + 0x12, 2);
847206268Sdavidch			DBPRINT(sc, BCE_INFO_LOAD, "PCIe link_status = "
848206268Sdavidch			    "0x%08X\n",	link_status);
849179771Sdavidch			sc->link_speed = link_status & 0xf;
850179771Sdavidch			sc->link_width = (link_status >> 4) & 0x3f;
851179771Sdavidch			sc->bce_cap_flags |= BCE_PCIE_CAPABLE_FLAG;
852179771Sdavidch			sc->bce_flags |= BCE_PCIE_FLAG;
853179771Sdavidch		}
854179771Sdavidch	}
855179771Sdavidch
856179771Sdavidch	/* Check if MSI capability is enabled. */
857219902Sjhb	if (pci_find_cap(dev, PCIY_MSI, &reg) == 0) {
858179771Sdavidch		if (reg != 0)
859179771Sdavidch			sc->bce_cap_flags |= BCE_MSI_CAPABLE_FLAG;
860179771Sdavidch	}
861179771Sdavidch
862179771Sdavidch	/* Check if MSI-X capability is enabled. */
863219902Sjhb	if (pci_find_cap(dev, PCIY_MSIX, &reg) == 0) {
864179771Sdavidch		if (reg != 0)
865179771Sdavidch			sc->bce_cap_flags |= BCE_MSIX_CAPABLE_FLAG;
866179771Sdavidch	}
867179771Sdavidch
868179771Sdavidch	DBEXIT(BCE_VERBOSE_LOAD);
869179771Sdavidch}
870179771Sdavidch
871179771Sdavidch
872179771Sdavidch/****************************************************************************/
873218423Sdavidch/* Load and validate user tunable settings.                                 */
874218423Sdavidch/*                                                                          */
875218423Sdavidch/* Returns:                                                                 */
876218423Sdavidch/*   Nothing.                                                               */
877218423Sdavidch/****************************************************************************/
878218423Sdavidchstatic void
879218423Sdavidchbce_set_tunables(struct bce_softc *sc)
880218423Sdavidch{
881218423Sdavidch	/* Set sysctl values for RX page count. */
882218423Sdavidch	switch (bce_rx_pages) {
883218423Sdavidch	case 1:
884218423Sdavidch		/* fall-through */
885218423Sdavidch	case 2:
886218423Sdavidch		/* fall-through */
887218423Sdavidch	case 4:
888218423Sdavidch		/* fall-through */
889218423Sdavidch	case 8:
890218423Sdavidch		sc->rx_pages = bce_rx_pages;
891218423Sdavidch		break;
892218423Sdavidch	default:
893218423Sdavidch		sc->rx_pages = DEFAULT_RX_PAGES;
894218423Sdavidch		BCE_PRINTF("%s(%d): Illegal value (%d) specified for "
895218423Sdavidch		    "hw.bce.rx_pages!  Setting default of %d.\n",
896218423Sdavidch		    __FILE__, __LINE__, bce_rx_pages, DEFAULT_RX_PAGES);
897218423Sdavidch	}
898218423Sdavidch
899218423Sdavidch	/* ToDo: Consider allowing user setting for pg_pages. */
900218423Sdavidch	sc->pg_pages = min((sc->rx_pages * 4), MAX_PG_PAGES);
901218423Sdavidch
902218423Sdavidch	/* Set sysctl values for TX page count. */
903218423Sdavidch	switch (bce_tx_pages) {
904218423Sdavidch	case 1:
905218423Sdavidch		/* fall-through */
906218423Sdavidch	case 2:
907218423Sdavidch		/* fall-through */
908218423Sdavidch	case 4:
909218423Sdavidch		/* fall-through */
910218423Sdavidch	case 8:
911218423Sdavidch		sc->tx_pages = bce_tx_pages;
912218423Sdavidch		break;
913218423Sdavidch	default:
914218423Sdavidch		sc->tx_pages = DEFAULT_TX_PAGES;
915218423Sdavidch		BCE_PRINTF("%s(%d): Illegal value (%d) specified for "
916218423Sdavidch		    "hw.bce.tx_pages!  Setting default of %d.\n",
917218423Sdavidch		    __FILE__, __LINE__, bce_tx_pages, DEFAULT_TX_PAGES);
918218423Sdavidch	}
919218423Sdavidch
920218423Sdavidch	/*
921218423Sdavidch	 * Validate the TX trip point (i.e. the number of
922218423Sdavidch	 * TX completions before a status block update is
923218423Sdavidch	 * generated and an interrupt is asserted.
924218423Sdavidch	 */
925218423Sdavidch	if (bce_tx_quick_cons_trip_int <= 100) {
926218423Sdavidch		sc->bce_tx_quick_cons_trip_int =
927218423Sdavidch		    bce_tx_quick_cons_trip_int;
928218423Sdavidch	} else {
929218423Sdavidch		BCE_PRINTF("%s(%d): Illegal value (%d) specified for "
930218423Sdavidch		    "hw.bce.tx_quick_cons_trip_int!  Setting default of %d.\n",
931218423Sdavidch		    __FILE__, __LINE__, bce_tx_quick_cons_trip_int,
932218423Sdavidch		    DEFAULT_TX_QUICK_CONS_TRIP_INT);
933218423Sdavidch		sc->bce_tx_quick_cons_trip_int =
934218423Sdavidch		    DEFAULT_TX_QUICK_CONS_TRIP_INT;
935218423Sdavidch	}
936218423Sdavidch
937218423Sdavidch	if (bce_tx_quick_cons_trip <= 100) {
938218423Sdavidch		sc->bce_tx_quick_cons_trip =
939218423Sdavidch		    bce_tx_quick_cons_trip;
940218423Sdavidch	} else {
941218423Sdavidch		BCE_PRINTF("%s(%d): Illegal value (%d) specified for "
942218423Sdavidch		    "hw.bce.tx_quick_cons_trip!  Setting default of %d.\n",
943218423Sdavidch		    __FILE__, __LINE__, bce_tx_quick_cons_trip,
944218423Sdavidch		    DEFAULT_TX_QUICK_CONS_TRIP);
945218423Sdavidch		sc->bce_tx_quick_cons_trip =
946218423Sdavidch		    DEFAULT_TX_QUICK_CONS_TRIP;
947218423Sdavidch	}
948218423Sdavidch
949218423Sdavidch	/*
950218423Sdavidch	 * Validate the TX ticks count (i.e. the maximum amount
951218423Sdavidch	 * of time to wait after the last TX completion has
952218423Sdavidch	 * occurred before a status block update is generated
953218423Sdavidch	 * and an interrupt is asserted.
954218423Sdavidch	 */
955218423Sdavidch	if (bce_tx_ticks_int <= 100) {
956218423Sdavidch		sc->bce_tx_ticks_int =
957218423Sdavidch		    bce_tx_ticks_int;
958218423Sdavidch	} else {
959218423Sdavidch		BCE_PRINTF("%s(%d): Illegal value (%d) specified for "
960218423Sdavidch		    "hw.bce.tx_ticks_int!  Setting default of %d.\n",
961218423Sdavidch		    __FILE__, __LINE__, bce_tx_ticks_int,
962218423Sdavidch		    DEFAULT_TX_TICKS_INT);
963218423Sdavidch		sc->bce_tx_ticks_int =
964218423Sdavidch		    DEFAULT_TX_TICKS_INT;
965218423Sdavidch	   }
966218423Sdavidch
967218423Sdavidch	if (bce_tx_ticks <= 100) {
968218423Sdavidch		sc->bce_tx_ticks =
969218423Sdavidch		    bce_tx_ticks;
970218423Sdavidch	} else {
971218423Sdavidch		BCE_PRINTF("%s(%d): Illegal value (%d) specified for "
972218423Sdavidch		    "hw.bce.tx_ticks!  Setting default of %d.\n",
973218423Sdavidch		    __FILE__, __LINE__, bce_tx_ticks,
974218423Sdavidch		    DEFAULT_TX_TICKS);
975218423Sdavidch		sc->bce_tx_ticks =
976218423Sdavidch		    DEFAULT_TX_TICKS;
977218423Sdavidch	}
978218423Sdavidch
979218423Sdavidch	/*
980218423Sdavidch	 * Validate the RX trip point (i.e. the number of
981218423Sdavidch	 * RX frames received before a status block update is
982218423Sdavidch	 * generated and an interrupt is asserted.
983218423Sdavidch	 */
984218423Sdavidch	if (bce_rx_quick_cons_trip_int <= 100) {
985218423Sdavidch		sc->bce_rx_quick_cons_trip_int =
986218423Sdavidch		    bce_rx_quick_cons_trip_int;
987218423Sdavidch	} else {
988218423Sdavidch		BCE_PRINTF("%s(%d): Illegal value (%d) specified for "
989218423Sdavidch		    "hw.bce.rx_quick_cons_trip_int!  Setting default of %d.\n",
990218423Sdavidch		    __FILE__, __LINE__, bce_rx_quick_cons_trip_int,
991218423Sdavidch		    DEFAULT_RX_QUICK_CONS_TRIP_INT);
992218423Sdavidch		sc->bce_rx_quick_cons_trip_int =
993218423Sdavidch		    DEFAULT_RX_QUICK_CONS_TRIP_INT;
994218423Sdavidch	}
995218423Sdavidch
996218423Sdavidch	if (bce_rx_quick_cons_trip <= 100) {
997218423Sdavidch		sc->bce_rx_quick_cons_trip =
998218423Sdavidch		    bce_rx_quick_cons_trip;
999218423Sdavidch	} else {
1000218423Sdavidch		BCE_PRINTF("%s(%d): Illegal value (%d) specified for "
1001218423Sdavidch		    "hw.bce.rx_quick_cons_trip!  Setting default of %d.\n",
1002218423Sdavidch		    __FILE__, __LINE__, bce_rx_quick_cons_trip,
1003218423Sdavidch		    DEFAULT_RX_QUICK_CONS_TRIP);
1004218423Sdavidch		sc->bce_rx_quick_cons_trip =
1005218423Sdavidch		    DEFAULT_RX_QUICK_CONS_TRIP;
1006218423Sdavidch	}
1007218423Sdavidch
1008218423Sdavidch	/*
1009218423Sdavidch	 * Validate the RX ticks count (i.e. the maximum amount
1010218423Sdavidch	 * of time to wait after the last RX frame has been
1011218423Sdavidch	 * received before a status block update is generated
1012218423Sdavidch	 * and an interrupt is asserted.
1013218423Sdavidch	 */
1014218423Sdavidch	if (bce_rx_ticks_int <= 100) {
1015218423Sdavidch		sc->bce_rx_ticks_int = bce_rx_ticks_int;
1016218423Sdavidch	} else {
1017218423Sdavidch		BCE_PRINTF("%s(%d): Illegal value (%d) specified for "
1018218423Sdavidch		    "hw.bce.rx_ticks_int!  Setting default of %d.\n",
1019218423Sdavidch		    __FILE__, __LINE__, bce_rx_ticks_int,
1020218423Sdavidch		    DEFAULT_RX_TICKS_INT);
1021218423Sdavidch		sc->bce_rx_ticks_int = DEFAULT_RX_TICKS_INT;
1022218423Sdavidch	}
1023218423Sdavidch
1024218423Sdavidch	if (bce_rx_ticks <= 100) {
1025218423Sdavidch		sc->bce_rx_ticks = bce_rx_ticks;
1026218423Sdavidch	} else {
1027218423Sdavidch		BCE_PRINTF("%s(%d): Illegal value (%d) specified for "
1028218423Sdavidch		    "hw.bce.rx_ticks!  Setting default of %d.\n",
1029218423Sdavidch		    __FILE__, __LINE__, bce_rx_ticks,
1030218423Sdavidch		    DEFAULT_RX_TICKS);
1031218423Sdavidch		sc->bce_rx_ticks = DEFAULT_RX_TICKS;
1032218423Sdavidch	}
1033218423Sdavidch
1034218423Sdavidch	/* Disabling both RX ticks and RX trips will prevent interrupts. */
1035218423Sdavidch	if ((bce_rx_quick_cons_trip == 0) && (bce_rx_ticks == 0)) {
1036218423Sdavidch		BCE_PRINTF("%s(%d): Cannot set both hw.bce.rx_ticks and "
1037218423Sdavidch		    "hw.bce.rx_quick_cons_trip to 0. Setting default values.\n",
1038218423Sdavidch		   __FILE__, __LINE__);
1039218423Sdavidch		sc->bce_rx_ticks = DEFAULT_RX_TICKS;
1040218423Sdavidch		sc->bce_rx_quick_cons_trip = DEFAULT_RX_QUICK_CONS_TRIP;
1041218423Sdavidch	}
1042218423Sdavidch
1043218423Sdavidch	/* Disabling both TX ticks and TX trips will prevent interrupts. */
1044218423Sdavidch	if ((bce_tx_quick_cons_trip == 0) && (bce_tx_ticks == 0)) {
1045218423Sdavidch		BCE_PRINTF("%s(%d): Cannot set both hw.bce.tx_ticks and "
1046218423Sdavidch		    "hw.bce.tx_quick_cons_trip to 0. Setting default values.\n",
1047218423Sdavidch		   __FILE__, __LINE__);
1048218423Sdavidch		sc->bce_tx_ticks = DEFAULT_TX_TICKS;
1049218423Sdavidch		sc->bce_tx_quick_cons_trip = DEFAULT_TX_QUICK_CONS_TRIP;
1050218423Sdavidch	}
1051218423Sdavidch}
1052218423Sdavidch
1053218423Sdavidch
1054218423Sdavidch/****************************************************************************/
1055157642Sps/* Device attach function.                                                  */
1056157642Sps/*                                                                          */
1057157642Sps/* Allocates device resources, performs secondary chip identification,      */
1058157642Sps/* resets and initializes the hardware, and initializes driver instance     */
1059157642Sps/* variables.                                                               */
1060157642Sps/*                                                                          */
1061157642Sps/* Returns:                                                                 */
1062157642Sps/*   0 on success, positive value on failure.                               */
1063157642Sps/****************************************************************************/
1064157642Spsstatic int
1065157642Spsbce_attach(device_t dev)
1066157642Sps{
1067157642Sps	struct bce_softc *sc;
1068157642Sps	struct ifnet *ifp;
1069157642Sps	u32 val;
1070247565Smarius	int count, error, rc = 0, rid;
1071157642Sps
1072157642Sps	sc = device_get_softc(dev);
1073157642Sps	sc->bce_dev = dev;
1074157642Sps
1075179771Sdavidch	DBENTER(BCE_VERBOSE_LOAD | BCE_VERBOSE_RESET);
1076157642Sps
1077176448Sdavidch	sc->bce_unit = device_get_unit(dev);
1078170392Sdavidch
1079169632Sdavidch	/* Set initial device and PHY flags */
1080169632Sdavidch	sc->bce_flags = 0;
1081169632Sdavidch	sc->bce_phy_flags = 0;
1082169632Sdavidch
1083218423Sdavidch	bce_set_tunables(sc);
1084218423Sdavidch
1085157642Sps	pci_enable_busmaster(dev);
1086157642Sps
1087157642Sps	/* Allocate PCI memory resources. */
1088157642Sps	rid = PCIR_BAR(0);
1089169632Sdavidch	sc->bce_res_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
1090178588Smarius		&rid, RF_ACTIVE);
1091157642Sps
1092169632Sdavidch	if (sc->bce_res_mem == NULL) {
1093179771Sdavidch		BCE_PRINTF("%s(%d): PCI memory allocation failed\n",
1094206268Sdavidch		    __FILE__, __LINE__);
1095157642Sps		rc = ENXIO;
1096157642Sps		goto bce_attach_fail;
1097157642Sps	}
1098157642Sps
1099157642Sps	/* Get various resource handles. */
1100169632Sdavidch	sc->bce_btag    = rman_get_bustag(sc->bce_res_mem);
1101169632Sdavidch	sc->bce_bhandle = rman_get_bushandle(sc->bce_res_mem);
1102169632Sdavidch	sc->bce_vhandle = (vm_offset_t) rman_get_virtual(sc->bce_res_mem);
1103157642Sps
1104179771Sdavidch	bce_probe_pci_caps(dev, sc);
1105170392Sdavidch
1106179771Sdavidch	rid = 1;
1107247590Smarius	count = 0;
1108179771Sdavidch#if 0
1109179771Sdavidch	/* Try allocating MSI-X interrupts. */
1110179771Sdavidch	if ((sc->bce_cap_flags & BCE_MSIX_CAPABLE_FLAG) &&
1111179771Sdavidch		(bce_msi_enable >= 2) &&
1112179771Sdavidch		((sc->bce_res_irq = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
1113179771Sdavidch		&rid, RF_ACTIVE)) != NULL)) {
1114179771Sdavidch
1115247565Smarius		msi_needed = count = 1;
1116179771Sdavidch
1117247565Smarius		if (((error = pci_alloc_msix(dev, &count)) != 0) ||
1118247565Smarius			(count != msi_needed)) {
1119179771Sdavidch			BCE_PRINTF("%s(%d): MSI-X allocation failed! Requested = %d,"
1120179771Sdavidch				"Received = %d, error = %d\n", __FILE__, __LINE__,
1121247565Smarius				msi_needed, count, error);
1122247565Smarius			count = 0;
1123179771Sdavidch			pci_release_msi(dev);
1124179771Sdavidch			bus_release_resource(dev, SYS_RES_MEMORY, rid,
1125179771Sdavidch				sc->bce_res_irq);
1126179771Sdavidch			sc->bce_res_irq = NULL;
1127179771Sdavidch		} else {
1128179771Sdavidch			DBPRINT(sc, BCE_INFO_LOAD, "%s(): Using MSI-X interrupt.\n",
1129179771Sdavidch				__FUNCTION__);
1130179771Sdavidch			sc->bce_flags |= BCE_USING_MSIX_FLAG;
1131179771Sdavidch		}
1132179771Sdavidch	}
1133179771Sdavidch#endif
1134179771Sdavidch
1135179771Sdavidch	/* Try allocating a MSI interrupt. */
1136179771Sdavidch	if ((sc->bce_cap_flags & BCE_MSI_CAPABLE_FLAG) &&
1137247565Smarius		(bce_msi_enable >= 1) && (count == 0)) {
1138247565Smarius		count = 1;
1139247565Smarius		if ((error = pci_alloc_msi(dev, &count)) != 0) {
1140207411Sdavidch			BCE_PRINTF("%s(%d): MSI allocation failed! "
1141207411Sdavidch			    "error = %d\n", __FILE__, __LINE__, error);
1142247565Smarius			count = 0;
1143179771Sdavidch			pci_release_msi(dev);
1144179771Sdavidch		} else {
1145207411Sdavidch			DBPRINT(sc, BCE_INFO_LOAD, "%s(): Using MSI "
1146207411Sdavidch			    "interrupt.\n", __FUNCTION__);
1147179771Sdavidch			sc->bce_flags |= BCE_USING_MSI_FLAG;
1148226123Syongari			if (BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5709)
1149179771Sdavidch				sc->bce_flags |= BCE_ONE_SHOT_MSI_FLAG;
1150247565Smarius			rid = 1;
1151179771Sdavidch		}
1152179771Sdavidch	}
1153179771Sdavidch
1154179771Sdavidch	/* Try allocating a legacy interrupt. */
1155247565Smarius	if (count == 0) {
1156179771Sdavidch		DBPRINT(sc, BCE_INFO_LOAD, "%s(): Using INTx interrupt.\n",
1157179771Sdavidch			__FUNCTION__);
1158170392Sdavidch		rid = 0;
1159169632Sdavidch	}
1160170392Sdavidch
1161179771Sdavidch	sc->bce_res_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ,
1162247565Smarius	    &rid, RF_ACTIVE | (count != 0 ? 0 : RF_SHAREABLE));
1163157642Sps
1164179771Sdavidch	/* Report any IRQ allocation errors. */
1165169632Sdavidch	if (sc->bce_res_irq == NULL) {
1166179771Sdavidch		BCE_PRINTF("%s(%d): PCI map interrupt failed!\n",
1167206268Sdavidch		    __FILE__, __LINE__);
1168157642Sps		rc = ENXIO;
1169157642Sps		goto bce_attach_fail;
1170157642Sps	}
1171157642Sps
1172157642Sps	/* Initialize mutex for the current device instance. */
1173157642Sps	BCE_LOCK_INIT(sc, device_get_nameunit(dev));
1174157642Sps
1175157642Sps	/*
1176157642Sps	 * Configure byte swap and enable indirect register access.
1177157642Sps	 * Rely on CPU to do target byte swapping on big endian systems.
1178157642Sps	 * Access to registers outside of PCI configurtion space are not
1179157642Sps	 * valid until this is done.
1180157642Sps	 */
1181157642Sps	pci_write_config(dev, BCE_PCICFG_MISC_CONFIG,
1182206268Sdavidch	    BCE_PCICFG_MISC_CONFIG_REG_WINDOW_ENA |
1183206268Sdavidch	    BCE_PCICFG_MISC_CONFIG_TARGET_MB_WORD_SWAP, 4);
1184157642Sps
1185157642Sps	/* Save ASIC revsion info. */
1186157642Sps	sc->bce_chipid =  REG_RD(sc, BCE_MISC_ID);
1187157642Sps
1188157642Sps	/* Weed out any non-production controller revisions. */
1189157642Sps	switch(BCE_CHIP_ID(sc)) {
1190206268Sdavidch	case BCE_CHIP_ID_5706_A0:
1191206268Sdavidch	case BCE_CHIP_ID_5706_A1:
1192206268Sdavidch	case BCE_CHIP_ID_5708_A0:
1193206268Sdavidch	case BCE_CHIP_ID_5708_B0:
1194206268Sdavidch	case BCE_CHIP_ID_5709_A0:
1195206268Sdavidch	case BCE_CHIP_ID_5709_B0:
1196206268Sdavidch	case BCE_CHIP_ID_5709_B1:
1197206268Sdavidch	case BCE_CHIP_ID_5709_B2:
1198207411Sdavidch		BCE_PRINTF("%s(%d): Unsupported controller "
1199207411Sdavidch		    "revision (%c%d)!\n", __FILE__, __LINE__,
1200207411Sdavidch		    (((pci_read_config(dev, PCIR_REVID, 4) &
1201207411Sdavidch		    0xf0) >> 4) + 'A'), (pci_read_config(dev,
1202207411Sdavidch		    PCIR_REVID, 4) & 0xf));
1203206268Sdavidch		rc = ENODEV;
1204206268Sdavidch		goto bce_attach_fail;
1205157642Sps	}
1206157642Sps
1207179771Sdavidch	/*
1208179771Sdavidch	 * The embedded PCIe to PCI-X bridge (EPB)
1209179771Sdavidch	 * in the 5708 cannot address memory above
1210179771Sdavidch	 * 40 bits (E7_5708CB1_23043 & E6_5708SB1_23043).
1211157642Sps	 */
1212157642Sps	if (BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5708)
1213157642Sps		sc->max_bus_addr = BCE_BUS_SPACE_MAXADDR;
1214157642Sps	else
1215157642Sps		sc->max_bus_addr = BUS_SPACE_MAXADDR;
1216157642Sps
1217157642Sps	/*
1218157642Sps	 * Find the base address for shared memory access.
1219157642Sps	 * Newer versions of bootcode use a signature and offset
1220157642Sps	 * while older versions use a fixed address.
1221157642Sps	 */
1222157642Sps	val = REG_RD_IND(sc, BCE_SHM_HDR_SIGNATURE);
1223157642Sps	if ((val & BCE_SHM_HDR_SIGNATURE_SIG_MASK) == BCE_SHM_HDR_SIGNATURE_SIG)
1224179771Sdavidch		/* Multi-port devices use different offsets in shared memory. */
1225179771Sdavidch		sc->bce_shmem_base = REG_RD_IND(sc, BCE_SHM_HDR_ADDR_0 +
1226206268Sdavidch		    (pci_get_function(sc->bce_dev) << 2));
1227157642Sps	else
1228157642Sps		sc->bce_shmem_base = HOST_VIEW_SHMEM_BASE;
1229157642Sps
1230179771Sdavidch	DBPRINT(sc, BCE_VERBOSE_FIRMWARE, "%s(): bce_shmem_base = 0x%08X\n",
1231206268Sdavidch	    __FUNCTION__, sc->bce_shmem_base);
1232157642Sps
1233178132Sdavidch	/* Fetch the bootcode revision. */
1234206268Sdavidch	val = bce_shmem_rd(sc, BCE_DEV_INFO_BC_REV);
1235206268Sdavidch	for (int i = 0, j = 0; i < 3; i++) {
1236206268Sdavidch		u8 num;
1237170810Sdavidch
1238206268Sdavidch		num = (u8) (val >> (24 - (i * 8)));
1239206268Sdavidch		for (int k = 100, skip0 = 1; k >= 1; num %= k, k /= 10) {
1240206268Sdavidch			if (num >= k || !skip0 || k == 1) {
1241206268Sdavidch				sc->bce_bc_ver[j++] = (num / k) + '0';
1242206268Sdavidch				skip0 = 0;
1243206268Sdavidch			}
1244206268Sdavidch		}
1245170810Sdavidch
1246206268Sdavidch		if (i != 2)
1247206268Sdavidch			sc->bce_bc_ver[j++] = '.';
1248206268Sdavidch	}
1249194781Sdavidch
1250206268Sdavidch	/* Check if any management firwmare is enabled. */
1251206268Sdavidch	val = bce_shmem_rd(sc, BCE_PORT_FEATURE);
1252206268Sdavidch	if (val & BCE_PORT_FEATURE_ASF_ENABLED) {
1253206268Sdavidch		sc->bce_flags |= BCE_MFW_ENABLE_FLAG;
1254194781Sdavidch
1255206268Sdavidch		/* Allow time for firmware to enter the running state. */
1256206268Sdavidch		for (int i = 0; i < 30; i++) {
1257206268Sdavidch			val = bce_shmem_rd(sc, BCE_BC_STATE_CONDITION);
1258206268Sdavidch			if (val & BCE_CONDITION_MFW_RUN_MASK)
1259206268Sdavidch				break;
1260206268Sdavidch			DELAY(10000);
1261206268Sdavidch		}
1262194781Sdavidch
1263206268Sdavidch		/* Check if management firmware is running. */
1264206268Sdavidch		val = bce_shmem_rd(sc, BCE_BC_STATE_CONDITION);
1265206268Sdavidch		val &= BCE_CONDITION_MFW_RUN_MASK;
1266206268Sdavidch		if ((val != BCE_CONDITION_MFW_RUN_UNKNOWN) &&
1267206268Sdavidch		    (val != BCE_CONDITION_MFW_RUN_NONE)) {
1268206268Sdavidch			u32 addr = bce_shmem_rd(sc, BCE_MFW_VER_PTR);
1269206268Sdavidch			int i = 0;
1270194781Sdavidch
1271206268Sdavidch			/* Read the management firmware version string. */
1272206268Sdavidch			for (int j = 0; j < 3; j++) {
1273206268Sdavidch				val = bce_reg_rd_ind(sc, addr + j * 4);
1274206268Sdavidch				val = bswap32(val);
1275206268Sdavidch				memcpy(&sc->bce_mfw_ver[i], &val, 4);
1276206268Sdavidch				i += 4;
1277206268Sdavidch			}
1278206268Sdavidch		} else {
1279206268Sdavidch			/* May cause firmware synchronization timeouts. */
1280206268Sdavidch			BCE_PRINTF("%s(%d): Management firmware enabled "
1281206268Sdavidch			    "but not running!\n", __FILE__, __LINE__);
1282206268Sdavidch			strcpy(sc->bce_mfw_ver, "NOT RUNNING!");
1283206268Sdavidch
1284206268Sdavidch			/* ToDo: Any action the driver should take? */
1285206268Sdavidch		}
1286206268Sdavidch	}
1287206268Sdavidch
1288157642Sps	/* Get PCI bus information (speed and type). */
1289157642Sps	val = REG_RD(sc, BCE_PCICFG_MISC_STATUS);
1290157642Sps	if (val & BCE_PCICFG_MISC_STATUS_PCIX_DET) {
1291157642Sps		u32 clkreg;
1292157642Sps
1293157642Sps		sc->bce_flags |= BCE_PCIX_FLAG;
1294157642Sps
1295157642Sps		clkreg = REG_RD(sc, BCE_PCICFG_PCI_CLOCK_CONTROL_BITS);
1296157642Sps
1297157642Sps		clkreg &= BCE_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET;
1298157642Sps		switch (clkreg) {
1299157642Sps		case BCE_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_133MHZ:
1300157642Sps			sc->bus_speed_mhz = 133;
1301157642Sps			break;
1302157642Sps
1303157642Sps		case BCE_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_95MHZ:
1304157642Sps			sc->bus_speed_mhz = 100;
1305157642Sps			break;
1306157642Sps
1307157642Sps		case BCE_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_66MHZ:
1308157642Sps		case BCE_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_80MHZ:
1309157642Sps			sc->bus_speed_mhz = 66;
1310157642Sps			break;
1311157642Sps
1312157642Sps		case BCE_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_48MHZ:
1313157642Sps		case BCE_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_55MHZ:
1314157642Sps			sc->bus_speed_mhz = 50;
1315157642Sps			break;
1316157642Sps
1317157642Sps		case BCE_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_LOW:
1318157642Sps		case BCE_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_32MHZ:
1319157642Sps		case BCE_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_38MHZ:
1320157642Sps			sc->bus_speed_mhz = 33;
1321157642Sps			break;
1322157642Sps		}
1323157642Sps	} else {
1324157642Sps		if (val & BCE_PCICFG_MISC_STATUS_M66EN)
1325157642Sps			sc->bus_speed_mhz = 66;
1326157642Sps		else
1327157642Sps			sc->bus_speed_mhz = 33;
1328157642Sps	}
1329157642Sps
1330157642Sps	if (val & BCE_PCICFG_MISC_STATUS_32BIT_DET)
1331157642Sps		sc->bce_flags |= BCE_PCI_32BIT_FLAG;
1332157642Sps
1333235151Syongari	/* Find the media type for the adapter. */
1334235151Syongari	bce_get_media(sc);
1335235151Syongari
1336206268Sdavidch	/* Reset controller and announce to bootcode that driver is present. */
1337157642Sps	if (bce_reset(sc, BCE_DRV_MSG_CODE_RESET)) {
1338179771Sdavidch		BCE_PRINTF("%s(%d): Controller reset failed!\n",
1339206268Sdavidch		    __FILE__, __LINE__);
1340157642Sps		rc = ENXIO;
1341157642Sps		goto bce_attach_fail;
1342157642Sps	}
1343157642Sps
1344157642Sps	/* Initialize the controller. */
1345157642Sps	if (bce_chipinit(sc)) {
1346169271Sdavidch		BCE_PRINTF("%s(%d): Controller initialization failed!\n",
1347206268Sdavidch		    __FILE__, __LINE__);
1348157642Sps		rc = ENXIO;
1349157642Sps		goto bce_attach_fail;
1350157642Sps	}
1351157642Sps
1352157642Sps	/* Perform NVRAM test. */
1353157642Sps	if (bce_nvram_test(sc)) {
1354169271Sdavidch		BCE_PRINTF("%s(%d): NVRAM test failed!\n",
1355206268Sdavidch		    __FILE__, __LINE__);
1356157642Sps		rc = ENXIO;
1357157642Sps		goto bce_attach_fail;
1358157642Sps	}
1359157642Sps
1360157642Sps	/* Fetch the permanent Ethernet MAC address. */
1361157642Sps	bce_get_mac_addr(sc);
1362157642Sps
1363157642Sps	/* Update statistics once every second. */
1364157642Sps	sc->bce_stats_ticks = 1000000 & 0xffff00;
1365157642Sps
1366170810Sdavidch	/* Store data needed by PHY driver for backplane applications */
1367194781Sdavidch	sc->bce_shared_hw_cfg = bce_shmem_rd(sc, BCE_SHARED_HW_CFG_CONFIG);
1368194781Sdavidch	sc->bce_port_hw_cfg   = bce_shmem_rd(sc, BCE_PORT_HW_CFG_CONFIG);
1369170392Sdavidch
1370157642Sps	/* Allocate DMA memory resources. */
1371157642Sps	if (bce_dma_alloc(dev)) {
1372169271Sdavidch		BCE_PRINTF("%s(%d): DMA resource allocation failed!\n",
1373157642Sps		    __FILE__, __LINE__);
1374157642Sps		rc = ENXIO;
1375157642Sps		goto bce_attach_fail;
1376157642Sps	}
1377157642Sps
1378157642Sps	/* Allocate an ifnet structure. */
1379157642Sps	ifp = sc->bce_ifp = if_alloc(IFT_ETHER);
1380157642Sps	if (ifp == NULL) {
1381179771Sdavidch		BCE_PRINTF("%s(%d): Interface allocation failed!\n",
1382207411Sdavidch		    __FILE__, __LINE__);
1383157642Sps		rc = ENXIO;
1384157642Sps		goto bce_attach_fail;
1385157642Sps	}
1386157642Sps
1387157642Sps	/* Initialize the ifnet interface. */
1388207411Sdavidch	ifp->if_softc	= sc;
1389157642Sps	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
1390207411Sdavidch	ifp->if_flags	= IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
1391207411Sdavidch	ifp->if_ioctl	= bce_ioctl;
1392207411Sdavidch	ifp->if_start	= bce_start;
1393272096Sglebius	ifp->if_get_counter = bce_get_counter;
1394207411Sdavidch	ifp->if_init	= bce_init;
1395207411Sdavidch	ifp->if_mtu	= ETHERMTU;
1396170392Sdavidch
1397170392Sdavidch	if (bce_tso_enable) {
1398170392Sdavidch		ifp->if_hwassist = BCE_IF_HWASSIST | CSUM_TSO;
1399204374Syongari		ifp->if_capabilities = BCE_IF_CAPABILITIES | IFCAP_TSO4 |
1400204374Syongari		    IFCAP_VLAN_HWTSO;
1401170392Sdavidch	} else {
1402170392Sdavidch		ifp->if_hwassist = BCE_IF_HWASSIST;
1403170392Sdavidch		ifp->if_capabilities = BCE_IF_CAPABILITIES;
1404170392Sdavidch	}
1405169632Sdavidch
1406235151Syongari#if __FreeBSD_version >= 800505
1407235151Syongari	/*
1408235151Syongari	 * Introducing IFCAP_LINKSTATE didn't bump __FreeBSD_version
1409235151Syongari	 * so it's approximate value.
1410235151Syongari	 */
1411235151Syongari	if ((sc->bce_phy_flags & BCE_PHY_REMOTE_CAP_FLAG) != 0)
1412235151Syongari		ifp->if_capabilities |= IFCAP_LINKSTATE;
1413235151Syongari#endif
1414235151Syongari
1415207411Sdavidch	ifp->if_capenable = ifp->if_capabilities;
1416157642Sps
1417182293Sdavidch	/*
1418182293Sdavidch	 * Assume standard mbuf sizes for buffer allocation.
1419182293Sdavidch	 * This may change later if the MTU size is set to
1420182293Sdavidch	 * something other than 1500.
1421179771Sdavidch	 */
1422218423Sdavidch	bce_get_rx_buffer_sizes(sc,
1423218423Sdavidch	    (ETHER_MAX_LEN - ETHER_HDR_LEN - ETHER_CRC_LEN));
1424176448Sdavidch
1425218423Sdavidch	/* Recalculate our buffer allocation sizes. */
1426218423Sdavidch	ifp->if_snd.ifq_drv_maxlen = USABLE_TX_BD_ALLOC;
1427170810Sdavidch	IFQ_SET_MAXLEN(&ifp->if_snd, ifp->if_snd.ifq_drv_maxlen);
1428170810Sdavidch	IFQ_SET_READY(&ifp->if_snd);
1429170810Sdavidch
1430157642Sps	if (sc->bce_phy_flags & BCE_PHY_2_5G_CAPABLE_FLAG)
1431170392Sdavidch		ifp->if_baudrate = IF_Mbps(2500ULL);
1432157642Sps	else
1433170392Sdavidch		ifp->if_baudrate = IF_Mbps(1000);
1434157642Sps
1435207411Sdavidch	/* Handle any special PHY initialization for SerDes PHYs. */
1436207411Sdavidch	bce_init_media(sc);
1437205300Sdavidch
1438235151Syongari	if ((sc->bce_phy_flags & BCE_PHY_REMOTE_CAP_FLAG) != 0) {
1439235151Syongari		ifmedia_init(&sc->bce_ifmedia, IFM_IMASK, bce_ifmedia_upd,
1440235151Syongari		    bce_ifmedia_sts);
1441235151Syongari		/*
1442235151Syongari		 * We can't manually override remote PHY's link and assume
1443235151Syongari		 * PHY port configuration(Fiber or TP) is not changed after
1444235151Syongari		 * device attach.  This may not be correct though.
1445235151Syongari		 */
1446235151Syongari		if ((sc->bce_phy_flags & BCE_PHY_REMOTE_PORT_FIBER_FLAG) != 0) {
1447235151Syongari			if (sc->bce_phy_flags & BCE_PHY_2_5G_CAPABLE_FLAG) {
1448235151Syongari				ifmedia_add(&sc->bce_ifmedia,
1449235151Syongari				    IFM_ETHER | IFM_2500_SX, 0, NULL);
1450235151Syongari				ifmedia_add(&sc->bce_ifmedia,
1451235151Syongari				    IFM_ETHER | IFM_2500_SX | IFM_FDX, 0, NULL);
1452235151Syongari			}
1453235151Syongari			ifmedia_add(&sc->bce_ifmedia,
1454235151Syongari			    IFM_ETHER | IFM_1000_SX, 0, NULL);
1455235151Syongari			ifmedia_add(&sc->bce_ifmedia,
1456235151Syongari			    IFM_ETHER | IFM_1000_SX | IFM_FDX, 0, NULL);
1457235151Syongari		} else {
1458235151Syongari			ifmedia_add(&sc->bce_ifmedia,
1459235151Syongari			    IFM_ETHER | IFM_10_T, 0, NULL);
1460235151Syongari			ifmedia_add(&sc->bce_ifmedia,
1461235151Syongari			    IFM_ETHER | IFM_10_T | IFM_FDX, 0, NULL);
1462235151Syongari			ifmedia_add(&sc->bce_ifmedia,
1463235151Syongari			    IFM_ETHER | IFM_100_TX, 0, NULL);
1464235151Syongari			ifmedia_add(&sc->bce_ifmedia,
1465235151Syongari			    IFM_ETHER | IFM_100_TX | IFM_FDX, 0, NULL);
1466235151Syongari			ifmedia_add(&sc->bce_ifmedia,
1467235151Syongari			    IFM_ETHER | IFM_1000_T, 0, NULL);
1468235151Syongari			ifmedia_add(&sc->bce_ifmedia,
1469235151Syongari			    IFM_ETHER | IFM_1000_T | IFM_FDX, 0, NULL);
1470235151Syongari		}
1471235151Syongari		ifmedia_add(&sc->bce_ifmedia, IFM_ETHER | IFM_AUTO, 0, NULL);
1472235151Syongari		ifmedia_set(&sc->bce_ifmedia, IFM_ETHER | IFM_AUTO);
1473235151Syongari		sc->bce_ifmedia.ifm_media = sc->bce_ifmedia.ifm_cur->ifm_media;
1474235151Syongari	} else {
1475235151Syongari		/* MII child bus by attaching the PHY. */
1476235151Syongari		rc = mii_attach(dev, &sc->bce_miibus, ifp, bce_ifmedia_upd,
1477235151Syongari		    bce_ifmedia_sts, BMSR_DEFCAPMASK, sc->bce_phy_addr,
1478235151Syongari		    MII_OFFSET_ANY, MIIF_DOPAUSE);
1479235151Syongari		if (rc != 0) {
1480235151Syongari			BCE_PRINTF("%s(%d): attaching PHYs failed\n", __FILE__,
1481235151Syongari			    __LINE__);
1482235151Syongari			goto bce_attach_fail;
1483235151Syongari		}
1484157642Sps	}
1485157642Sps
1486157642Sps	/* Attach to the Ethernet interface list. */
1487157642Sps	ether_ifattach(ifp, sc->eaddr);
1488157642Sps
1489157642Sps#if __FreeBSD_version < 500000
1490170810Sdavidch	callout_init(&sc->bce_tick_callout);
1491170810Sdavidch	callout_init(&sc->bce_pulse_callout);
1492157642Sps#else
1493170810Sdavidch	callout_init_mtx(&sc->bce_tick_callout, &sc->bce_mtx, 0);
1494170810Sdavidch	callout_init_mtx(&sc->bce_pulse_callout, &sc->bce_mtx, 0);
1495157642Sps#endif
1496157642Sps
1497157642Sps	/* Hookup IRQ last. */
1498179771Sdavidch	rc = bus_setup_intr(dev, sc->bce_res_irq, INTR_TYPE_NET | INTR_MPSAFE,
1499179771Sdavidch		NULL, bce_intr, sc, &sc->bce_intrhand);
1500157642Sps
1501157642Sps	if (rc) {
1502179771Sdavidch		BCE_PRINTF("%s(%d): Failed to setup IRQ!\n",
1503207411Sdavidch		    __FILE__, __LINE__);
1504157642Sps		bce_detach(dev);
1505157642Sps		goto bce_attach_exit;
1506157642Sps	}
1507157642Sps
1508179771Sdavidch	/*
1509179771Sdavidch	 * At this point we've acquired all the resources
1510170810Sdavidch	 * we need to run so there's no turning back, we're
1511170810Sdavidch	 * cleared for launch.
1512170810Sdavidch	 */
1513170810Sdavidch
1514157642Sps	/* Print some important debugging info. */
1515176448Sdavidch	DBRUNMSG(BCE_INFO, bce_dump_driver_state(sc));
1516157642Sps
1517157642Sps	/* Add the supported sysctls to the kernel. */
1518157642Sps	bce_add_sysctls(sc);
1519157642Sps
1520170810Sdavidch	BCE_LOCK(sc);
1521182293Sdavidch
1522179771Sdavidch	/*
1523170810Sdavidch	 * The chip reset earlier notified the bootcode that
1524170810Sdavidch	 * a driver is present.  We now need to start our pulse
1525170810Sdavidch	 * routine so that the bootcode is reminded that we're
1526170810Sdavidch	 * still running.
1527170810Sdavidch	 */
1528170810Sdavidch	bce_pulse(sc);
1529170810Sdavidch
1530162474Sambrisko	bce_mgmt_init_locked(sc);
1531170392Sdavidch	BCE_UNLOCK(sc);
1532162474Sambrisko
1533170810Sdavidch	/* Finally, print some useful adapter info */
1534179771Sdavidch	bce_print_adapter_info(sc);
1535176448Sdavidch	DBPRINT(sc, BCE_FATAL, "%s(): sc = %p\n",
1536176448Sdavidch		__FUNCTION__, sc);
1537170810Sdavidch
1538157642Sps	goto bce_attach_exit;
1539157642Sps
1540157642Spsbce_attach_fail:
1541157642Sps	bce_release_resources(sc);
1542157642Sps
1543157642Spsbce_attach_exit:
1544157642Sps
1545179771Sdavidch	DBEXIT(BCE_VERBOSE_LOAD | BCE_VERBOSE_RESET);
1546157642Sps
1547157642Sps	return(rc);
1548157642Sps}
1549157642Sps
1550157642Sps
1551157642Sps/****************************************************************************/
1552157642Sps/* Device detach function.                                                  */
1553157642Sps/*                                                                          */
1554157642Sps/* Stops the controller, resets the controller, and releases resources.     */
1555157642Sps/*                                                                          */
1556157642Sps/* Returns:                                                                 */
1557157642Sps/*   0 on success, positive value on failure.                               */
1558157642Sps/****************************************************************************/
1559157642Spsstatic int
1560157642Spsbce_detach(device_t dev)
1561157642Sps{
1562170810Sdavidch	struct bce_softc *sc = device_get_softc(dev);
1563157642Sps	struct ifnet *ifp;
1564170810Sdavidch	u32 msg;
1565157642Sps
1566179771Sdavidch	DBENTER(BCE_VERBOSE_UNLOAD | BCE_VERBOSE_RESET);
1567157642Sps
1568157642Sps	ifp = sc->bce_ifp;
1569157642Sps
1570176448Sdavidch	/* Stop and reset the controller. */
1571176448Sdavidch	BCE_LOCK(sc);
1572176448Sdavidch
1573170810Sdavidch	/* Stop the pulse so the bootcode can go to driver absent state. */
1574170810Sdavidch	callout_stop(&sc->bce_pulse_callout);
1575170810Sdavidch
1576157642Sps	bce_stop(sc);
1577170810Sdavidch	if (sc->bce_flags & BCE_NO_WOL_FLAG)
1578170810Sdavidch		msg = BCE_DRV_MSG_CODE_UNLOAD_LNK_DN;
1579170810Sdavidch	else
1580170810Sdavidch		msg = BCE_DRV_MSG_CODE_UNLOAD;
1581170810Sdavidch	bce_reset(sc, msg);
1582176448Sdavidch
1583157642Sps	BCE_UNLOCK(sc);
1584157642Sps
1585157642Sps	ether_ifdetach(ifp);
1586157642Sps
1587157642Sps	/* If we have a child device on the MII bus remove it too. */
1588235151Syongari	if ((sc->bce_phy_flags & BCE_PHY_REMOTE_CAP_FLAG) != 0)
1589235151Syongari		ifmedia_removeall(&sc->bce_ifmedia);
1590235151Syongari	else {
1591235151Syongari		bus_generic_detach(dev);
1592235151Syongari		device_delete_child(dev, sc->bce_miibus);
1593235151Syongari	}
1594157642Sps
1595157642Sps	/* Release all remaining resources. */
1596157642Sps	bce_release_resources(sc);
1597157642Sps
1598179771Sdavidch	DBEXIT(BCE_VERBOSE_UNLOAD | BCE_VERBOSE_RESET);
1599157642Sps
1600157642Sps	return(0);
1601157642Sps}
1602157642Sps
1603157642Sps
1604157642Sps/****************************************************************************/
1605157642Sps/* Device shutdown function.                                                */
1606157642Sps/*                                                                          */
1607157642Sps/* Stops and resets the controller.                                         */
1608157642Sps/*                                                                          */
1609157642Sps/* Returns:                                                                 */
1610173839Syongari/*   0 on success, positive value on failure.                               */
1611157642Sps/****************************************************************************/
1612173839Syongaristatic int
1613157642Spsbce_shutdown(device_t dev)
1614157642Sps{
1615157642Sps	struct bce_softc *sc = device_get_softc(dev);
1616170810Sdavidch	u32 msg;
1617157642Sps
1618179771Sdavidch	DBENTER(BCE_VERBOSE);
1619170810Sdavidch
1620157642Sps	BCE_LOCK(sc);
1621157642Sps	bce_stop(sc);
1622170810Sdavidch	if (sc->bce_flags & BCE_NO_WOL_FLAG)
1623170810Sdavidch		msg = BCE_DRV_MSG_CODE_UNLOAD_LNK_DN;
1624170810Sdavidch	else
1625170810Sdavidch		msg = BCE_DRV_MSG_CODE_UNLOAD;
1626170810Sdavidch	bce_reset(sc, msg);
1627157642Sps	BCE_UNLOCK(sc);
1628173839Syongari
1629179771Sdavidch	DBEXIT(BCE_VERBOSE);
1630179771Sdavidch
1631173839Syongari	return (0);
1632157642Sps}
1633157642Sps
1634157642Sps
1635179771Sdavidch#ifdef BCE_DEBUG
1636157642Sps/****************************************************************************/
1637179771Sdavidch/* Register read.                                                           */
1638179771Sdavidch/*                                                                          */
1639179771Sdavidch/* Returns:                                                                 */
1640179771Sdavidch/*   The value of the register.                                             */
1641179771Sdavidch/****************************************************************************/
1642179771Sdavidchstatic u32
1643179771Sdavidchbce_reg_rd(struct bce_softc *sc, u32 offset)
1644179771Sdavidch{
1645247565Smarius	u32 val = REG_RD(sc, offset);
1646179771Sdavidch	DBPRINT(sc, BCE_INSANE_REG, "%s(); offset = 0x%08X, val = 0x%08X\n",
1647179771Sdavidch		__FUNCTION__, offset, val);
1648179771Sdavidch	return val;
1649179771Sdavidch}
1650179771Sdavidch
1651179771Sdavidch
1652179771Sdavidch/****************************************************************************/
1653179771Sdavidch/* Register write (16 bit).                                                 */
1654179771Sdavidch/*                                                                          */
1655179771Sdavidch/* Returns:                                                                 */
1656179771Sdavidch/*   Nothing.                                                               */
1657179771Sdavidch/****************************************************************************/
1658179771Sdavidchstatic void
1659179771Sdavidchbce_reg_wr16(struct bce_softc *sc, u32 offset, u16 val)
1660179771Sdavidch{
1661179771Sdavidch	DBPRINT(sc, BCE_INSANE_REG, "%s(); offset = 0x%08X, val = 0x%04X\n",
1662179771Sdavidch		__FUNCTION__, offset, val);
1663247565Smarius	REG_WR16(sc, offset, val);
1664179771Sdavidch}
1665179771Sdavidch
1666179771Sdavidch
1667179771Sdavidch/****************************************************************************/
1668179771Sdavidch/* Register write.                                                          */
1669179771Sdavidch/*                                                                          */
1670179771Sdavidch/* Returns:                                                                 */
1671179771Sdavidch/*   Nothing.                                                               */
1672179771Sdavidch/****************************************************************************/
1673179771Sdavidchstatic void
1674179771Sdavidchbce_reg_wr(struct bce_softc *sc, u32 offset, u32 val)
1675179771Sdavidch{
1676179771Sdavidch	DBPRINT(sc, BCE_INSANE_REG, "%s(); offset = 0x%08X, val = 0x%08X\n",
1677179771Sdavidch		__FUNCTION__, offset, val);
1678247565Smarius	REG_WR(sc, offset, val);
1679179771Sdavidch}
1680179771Sdavidch#endif
1681179771Sdavidch
1682179771Sdavidch/****************************************************************************/
1683157642Sps/* Indirect register read.                                                  */
1684157642Sps/*                                                                          */
1685157642Sps/* Reads NetXtreme II registers using an index/data register pair in PCI    */
1686157642Sps/* configuration space.  Using this mechanism avoids issues with posted     */
1687157642Sps/* reads but is much slower than memory-mapped I/O.                         */
1688157642Sps/*                                                                          */
1689157642Sps/* Returns:                                                                 */
1690157642Sps/*   The value of the register.                                             */
1691157642Sps/****************************************************************************/
1692157642Spsstatic u32
1693157642Spsbce_reg_rd_ind(struct bce_softc *sc, u32 offset)
1694157642Sps{
1695157642Sps	device_t dev;
1696157642Sps	dev = sc->bce_dev;
1697157642Sps
1698157642Sps	pci_write_config(dev, BCE_PCICFG_REG_WINDOW_ADDRESS, offset, 4);
1699157642Sps#ifdef BCE_DEBUG
1700157642Sps	{
1701157642Sps		u32 val;
1702157642Sps		val = pci_read_config(dev, BCE_PCICFG_REG_WINDOW, 4);
1703179771Sdavidch		DBPRINT(sc, BCE_INSANE_REG, "%s(); offset = 0x%08X, val = 0x%08X\n",
1704157642Sps			__FUNCTION__, offset, val);
1705157642Sps		return val;
1706157642Sps	}
1707157642Sps#else
1708157642Sps	return pci_read_config(dev, BCE_PCICFG_REG_WINDOW, 4);
1709157642Sps#endif
1710157642Sps}
1711157642Sps
1712157642Sps
1713157642Sps/****************************************************************************/
1714157642Sps/* Indirect register write.                                                 */
1715157642Sps/*                                                                          */
1716157642Sps/* Writes NetXtreme II registers using an index/data register pair in PCI   */
1717157642Sps/* configuration space.  Using this mechanism avoids issues with posted     */
1718157642Sps/* writes but is muchh slower than memory-mapped I/O.                       */
1719157642Sps/*                                                                          */
1720157642Sps/* Returns:                                                                 */
1721157642Sps/*   Nothing.                                                               */
1722157642Sps/****************************************************************************/
1723157642Spsstatic void
1724157642Spsbce_reg_wr_ind(struct bce_softc *sc, u32 offset, u32 val)
1725157642Sps{
1726157642Sps	device_t dev;
1727157642Sps	dev = sc->bce_dev;
1728157642Sps
1729179771Sdavidch	DBPRINT(sc, BCE_INSANE_REG, "%s(); offset = 0x%08X, val = 0x%08X\n",
1730157642Sps		__FUNCTION__, offset, val);
1731157642Sps
1732157642Sps	pci_write_config(dev, BCE_PCICFG_REG_WINDOW_ADDRESS, offset, 4);
1733157642Sps	pci_write_config(dev, BCE_PCICFG_REG_WINDOW, val, 4);
1734157642Sps}
1735157642Sps
1736178132Sdavidch
1737194781Sdavidch/****************************************************************************/
1738194781Sdavidch/* Shared memory write.                                                     */
1739194781Sdavidch/*                                                                          */
1740194781Sdavidch/* Writes NetXtreme II shared memory region.                                */
1741194781Sdavidch/*                                                                          */
1742194781Sdavidch/* Returns:                                                                 */
1743194781Sdavidch/*   Nothing.                                                               */
1744194781Sdavidch/****************************************************************************/
1745194781Sdavidchstatic void
1746194781Sdavidchbce_shmem_wr(struct bce_softc *sc, u32 offset, u32 val)
1747194781Sdavidch{
1748207411Sdavidch	DBPRINT(sc, BCE_VERBOSE_FIRMWARE, "%s(): Writing 0x%08X  to  "
1749207411Sdavidch	    "0x%08X\n",	__FUNCTION__, val, offset);
1750207411Sdavidch
1751194781Sdavidch	bce_reg_wr_ind(sc, sc->bce_shmem_base + offset, val);
1752194781Sdavidch}
1753194781Sdavidch
1754194781Sdavidch
1755194781Sdavidch/****************************************************************************/
1756194781Sdavidch/* Shared memory read.                                                      */
1757194781Sdavidch/*                                                                          */
1758194781Sdavidch/* Reads NetXtreme II shared memory region.                                 */
1759194781Sdavidch/*                                                                          */
1760194781Sdavidch/* Returns:                                                                 */
1761194781Sdavidch/*   The 32 bit value read.                                                 */
1762194781Sdavidch/****************************************************************************/
1763194781Sdavidchstatic u32
1764194781Sdavidchbce_shmem_rd(struct bce_softc *sc, u32 offset)
1765194781Sdavidch{
1766207411Sdavidch	u32 val = bce_reg_rd_ind(sc, sc->bce_shmem_base + offset);
1767207411Sdavidch
1768207411Sdavidch	DBPRINT(sc, BCE_VERBOSE_FIRMWARE, "%s(): Reading 0x%08X from "
1769207411Sdavidch	    "0x%08X\n",	__FUNCTION__, val, offset);
1770207411Sdavidch
1771207411Sdavidch	return val;
1772194781Sdavidch}
1773194781Sdavidch
1774194781Sdavidch
1775176448Sdavidch#ifdef BCE_DEBUG
1776176448Sdavidch/****************************************************************************/
1777176448Sdavidch/* Context memory read.                                                     */
1778176448Sdavidch/*                                                                          */
1779176448Sdavidch/* The NetXtreme II controller uses context memory to track connection      */
1780176448Sdavidch/* information for L2 and higher network protocols.                         */
1781176448Sdavidch/*                                                                          */
1782176448Sdavidch/* Returns:                                                                 */
1783176448Sdavidch/*   The requested 32 bit value of context memory.                          */
1784176448Sdavidch/****************************************************************************/
1785176448Sdavidchstatic u32
1786179771Sdavidchbce_ctx_rd(struct bce_softc *sc, u32 cid_addr, u32 ctx_offset)
1787176448Sdavidch{
1788179771Sdavidch	u32 idx, offset, retry_cnt = 5, val;
1789157642Sps
1790207411Sdavidch	DBRUNIF((cid_addr > MAX_CID_ADDR || ctx_offset & 0x3 ||
1791207411Sdavidch	    cid_addr & CTX_MASK), BCE_PRINTF("%s(): Invalid CID "
1792207411Sdavidch	    "address: 0x%08X.\n", __FUNCTION__, cid_addr));
1793176448Sdavidch
1794179771Sdavidch	offset = ctx_offset + cid_addr;
1795176448Sdavidch
1796226123Syongari	if (BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5709) {
1797179771Sdavidch
1798179771Sdavidch		REG_WR(sc, BCE_CTX_CTX_CTRL, (offset | BCE_CTX_CTX_CTRL_READ_REQ));
1799179771Sdavidch
1800179771Sdavidch		for (idx = 0; idx < retry_cnt; idx++) {
1801179771Sdavidch			val = REG_RD(sc, BCE_CTX_CTX_CTRL);
1802179771Sdavidch			if ((val & BCE_CTX_CTX_CTRL_READ_REQ) == 0)
1803179771Sdavidch				break;
1804179771Sdavidch			DELAY(5);
1805179771Sdavidch		}
1806179771Sdavidch
1807179771Sdavidch		if (val & BCE_CTX_CTX_CTRL_READ_REQ)
1808179771Sdavidch			BCE_PRINTF("%s(%d); Unable to read CTX memory: "
1809207411Sdavidch			    "cid_addr = 0x%08X, offset = 0x%08X!\n",
1810207411Sdavidch			    __FILE__, __LINE__, cid_addr, ctx_offset);
1811179771Sdavidch
1812179771Sdavidch		val = REG_RD(sc, BCE_CTX_CTX_DATA);
1813179771Sdavidch	} else {
1814179771Sdavidch		REG_WR(sc, BCE_CTX_DATA_ADR, offset);
1815179771Sdavidch		val = REG_RD(sc, BCE_CTX_DATA);
1816179771Sdavidch	}
1817179771Sdavidch
1818179771Sdavidch	DBPRINT(sc, BCE_EXTREME_CTX, "%s(); cid_addr = 0x%08X, offset = 0x%08X, "
1819179771Sdavidch		"val = 0x%08X\n", __FUNCTION__, cid_addr, ctx_offset, val);
1820179771Sdavidch
1821176448Sdavidch	return(val);
1822176448Sdavidch}
1823176448Sdavidch#endif
1824176448Sdavidch
1825178132Sdavidch
1826157642Sps/****************************************************************************/
1827157642Sps/* Context memory write.                                                    */
1828157642Sps/*                                                                          */
1829157642Sps/* The NetXtreme II controller uses context memory to track connection      */
1830157642Sps/* information for L2 and higher network protocols.                         */
1831157642Sps/*                                                                          */
1832157642Sps/* Returns:                                                                 */
1833157642Sps/*   Nothing.                                                               */
1834157642Sps/****************************************************************************/
1835157642Spsstatic void
1836179771Sdavidchbce_ctx_wr(struct bce_softc *sc, u32 cid_addr, u32 ctx_offset, u32 ctx_val)
1837157642Sps{
1838179771Sdavidch	u32 idx, offset = ctx_offset + cid_addr;
1839179771Sdavidch	u32 val, retry_cnt = 5;
1840157642Sps
1841179771Sdavidch	DBPRINT(sc, BCE_EXTREME_CTX, "%s(); cid_addr = 0x%08X, offset = 0x%08X, "
1842179771Sdavidch		"val = 0x%08X\n", __FUNCTION__, cid_addr, ctx_offset, ctx_val);
1843157642Sps
1844179771Sdavidch	DBRUNIF((cid_addr > MAX_CID_ADDR || ctx_offset & 0x3 || cid_addr & CTX_MASK),
1845179771Sdavidch		BCE_PRINTF("%s(): Invalid CID address: 0x%08X.\n",
1846207411Sdavidch		    __FUNCTION__, cid_addr));
1847179771Sdavidch
1848226123Syongari	if (BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5709) {
1849179771Sdavidch
1850179771Sdavidch		REG_WR(sc, BCE_CTX_CTX_DATA, ctx_val);
1851179771Sdavidch		REG_WR(sc, BCE_CTX_CTX_CTRL, (offset | BCE_CTX_CTX_CTRL_WRITE_REQ));
1852179771Sdavidch
1853179771Sdavidch		for (idx = 0; idx < retry_cnt; idx++) {
1854179771Sdavidch			val = REG_RD(sc, BCE_CTX_CTX_CTRL);
1855179771Sdavidch			if ((val & BCE_CTX_CTX_CTRL_WRITE_REQ) == 0)
1856179771Sdavidch				break;
1857179771Sdavidch			DELAY(5);
1858179771Sdavidch		}
1859179771Sdavidch
1860179771Sdavidch		if (val & BCE_CTX_CTX_CTRL_WRITE_REQ)
1861179771Sdavidch			BCE_PRINTF("%s(%d); Unable to write CTX memory: "
1862207411Sdavidch			    "cid_addr = 0x%08X, offset = 0x%08X!\n",
1863207411Sdavidch			    __FILE__, __LINE__, cid_addr, ctx_offset);
1864179771Sdavidch
1865179771Sdavidch	} else {
1866179771Sdavidch		REG_WR(sc, BCE_CTX_DATA_ADR, offset);
1867179771Sdavidch		REG_WR(sc, BCE_CTX_DATA, ctx_val);
1868179771Sdavidch	}
1869157642Sps}
1870157642Sps
1871157642Sps
1872157642Sps/****************************************************************************/
1873157642Sps/* PHY register read.                                                       */
1874157642Sps/*                                                                          */
1875157642Sps/* Implements register reads on the MII bus.                                */
1876157642Sps/*                                                                          */
1877157642Sps/* Returns:                                                                 */
1878157642Sps/*   The value of the register.                                             */
1879157642Sps/****************************************************************************/
1880157642Spsstatic int
1881157642Spsbce_miibus_read_reg(device_t dev, int phy, int reg)
1882157642Sps{
1883157642Sps	struct bce_softc *sc;
1884157642Sps	u32 val;
1885157642Sps	int i;
1886157642Sps
1887157642Sps	sc = device_get_softc(dev);
1888157642Sps
1889205300Sdavidch    /*
1890205300Sdavidch     * The 5709S PHY is an IEEE Clause 45 PHY
1891205300Sdavidch     * with special mappings to work with IEEE
1892205300Sdavidch     * Clause 22 register accesses.
1893205300Sdavidch     */
1894205300Sdavidch	if ((sc->bce_phy_flags & BCE_PHY_IEEE_CLAUSE_45_FLAG) != 0) {
1895205300Sdavidch		if (reg >= MII_BMCR && reg <= MII_ANLPRNP)
1896205300Sdavidch			reg += 0x10;
1897205300Sdavidch	}
1898205300Sdavidch
1899205300Sdavidch    if (sc->bce_phy_flags & BCE_PHY_INT_MODE_AUTO_POLLING_FLAG) {
1900157642Sps		val = REG_RD(sc, BCE_EMAC_MDIO_MODE);
1901157642Sps		val &= ~BCE_EMAC_MDIO_MODE_AUTO_POLL;
1902157642Sps
1903157642Sps		REG_WR(sc, BCE_EMAC_MDIO_MODE, val);
1904157642Sps		REG_RD(sc, BCE_EMAC_MDIO_MODE);
1905157642Sps
1906157642Sps		DELAY(40);
1907157642Sps	}
1908157642Sps
1909179771Sdavidch
1910157642Sps	val = BCE_MIPHY(phy) | BCE_MIREG(reg) |
1911206268Sdavidch	    BCE_EMAC_MDIO_COMM_COMMAND_READ | BCE_EMAC_MDIO_COMM_DISEXT |
1912206268Sdavidch	    BCE_EMAC_MDIO_COMM_START_BUSY;
1913157642Sps	REG_WR(sc, BCE_EMAC_MDIO_COMM, val);
1914157642Sps
1915157642Sps	for (i = 0; i < BCE_PHY_TIMEOUT; i++) {
1916157642Sps		DELAY(10);
1917157642Sps
1918157642Sps		val = REG_RD(sc, BCE_EMAC_MDIO_COMM);
1919157642Sps		if (!(val & BCE_EMAC_MDIO_COMM_START_BUSY)) {
1920157642Sps			DELAY(5);
1921157642Sps
1922157642Sps			val = REG_RD(sc, BCE_EMAC_MDIO_COMM);
1923157642Sps			val &= BCE_EMAC_MDIO_COMM_DATA;
1924157642Sps
1925157642Sps			break;
1926157642Sps		}
1927157642Sps	}
1928157642Sps
1929157642Sps	if (val & BCE_EMAC_MDIO_COMM_START_BUSY) {
1930206268Sdavidch		BCE_PRINTF("%s(%d): Error: PHY read timeout! phy = %d, "
1931206268Sdavidch		    "reg = 0x%04X\n", __FILE__, __LINE__, phy, reg);
1932157642Sps		val = 0x0;
1933157642Sps	} else {
1934157642Sps		val = REG_RD(sc, BCE_EMAC_MDIO_COMM);
1935157642Sps	}
1936157642Sps
1937157642Sps
1938157642Sps	if (sc->bce_phy_flags & BCE_PHY_INT_MODE_AUTO_POLLING_FLAG) {
1939157642Sps		val = REG_RD(sc, BCE_EMAC_MDIO_MODE);
1940157642Sps		val |= BCE_EMAC_MDIO_MODE_AUTO_POLL;
1941157642Sps
1942157642Sps		REG_WR(sc, BCE_EMAC_MDIO_MODE, val);
1943157642Sps		REG_RD(sc, BCE_EMAC_MDIO_MODE);
1944157642Sps
1945157642Sps		DELAY(40);
1946157642Sps	}
1947157642Sps
1948179771Sdavidch	DB_PRINT_PHY_REG(reg, val);
1949157642Sps	return (val & 0xffff);
1950157642Sps}
1951157642Sps
1952157642Sps
1953157642Sps/****************************************************************************/
1954157642Sps/* PHY register write.                                                      */
1955157642Sps/*                                                                          */
1956157642Sps/* Implements register writes on the MII bus.                               */
1957157642Sps/*                                                                          */
1958157642Sps/* Returns:                                                                 */
1959157642Sps/*   The value of the register.                                             */
1960157642Sps/****************************************************************************/
1961157642Spsstatic int
1962157642Spsbce_miibus_write_reg(device_t dev, int phy, int reg, int val)
1963157642Sps{
1964157642Sps	struct bce_softc *sc;
1965157642Sps	u32 val1;
1966157642Sps	int i;
1967157642Sps
1968157642Sps	sc = device_get_softc(dev);
1969157642Sps
1970179771Sdavidch	DB_PRINT_PHY_REG(reg, val);
1971157642Sps
1972206268Sdavidch	/*
1973206268Sdavidch	 * The 5709S PHY is an IEEE Clause 45 PHY
1974206268Sdavidch	 * with special mappings to work with IEEE
1975206268Sdavidch	 * Clause 22 register accesses.
1976206268Sdavidch	 */
1977205300Sdavidch	if ((sc->bce_phy_flags & BCE_PHY_IEEE_CLAUSE_45_FLAG) != 0) {
1978205300Sdavidch		if (reg >= MII_BMCR && reg <= MII_ANLPRNP)
1979205300Sdavidch			reg += 0x10;
1980205300Sdavidch	}
1981205300Sdavidch
1982157642Sps	if (sc->bce_phy_flags & BCE_PHY_INT_MODE_AUTO_POLLING_FLAG) {
1983157642Sps		val1 = REG_RD(sc, BCE_EMAC_MDIO_MODE);
1984157642Sps		val1 &= ~BCE_EMAC_MDIO_MODE_AUTO_POLL;
1985157642Sps
1986157642Sps		REG_WR(sc, BCE_EMAC_MDIO_MODE, val1);
1987157642Sps		REG_RD(sc, BCE_EMAC_MDIO_MODE);
1988157642Sps
1989157642Sps		DELAY(40);
1990157642Sps	}
1991157642Sps
1992157642Sps	val1 = BCE_MIPHY(phy) | BCE_MIREG(reg) | val |
1993206268Sdavidch	    BCE_EMAC_MDIO_COMM_COMMAND_WRITE |
1994206268Sdavidch	    BCE_EMAC_MDIO_COMM_START_BUSY | BCE_EMAC_MDIO_COMM_DISEXT;
1995157642Sps	REG_WR(sc, BCE_EMAC_MDIO_COMM, val1);
1996157642Sps
1997157642Sps	for (i = 0; i < BCE_PHY_TIMEOUT; i++) {
1998157642Sps		DELAY(10);
1999157642Sps
2000157642Sps		val1 = REG_RD(sc, BCE_EMAC_MDIO_COMM);
2001157642Sps		if (!(val1 & BCE_EMAC_MDIO_COMM_START_BUSY)) {
2002157642Sps			DELAY(5);
2003157642Sps			break;
2004157642Sps		}
2005157642Sps	}
2006157642Sps
2007157642Sps	if (val1 & BCE_EMAC_MDIO_COMM_START_BUSY)
2008179771Sdavidch		BCE_PRINTF("%s(%d): PHY write timeout!\n",
2009206268Sdavidch		    __FILE__, __LINE__);
2010157642Sps
2011157642Sps	if (sc->bce_phy_flags & BCE_PHY_INT_MODE_AUTO_POLLING_FLAG) {
2012157642Sps		val1 = REG_RD(sc, BCE_EMAC_MDIO_MODE);
2013157642Sps		val1 |= BCE_EMAC_MDIO_MODE_AUTO_POLL;
2014157642Sps
2015157642Sps		REG_WR(sc, BCE_EMAC_MDIO_MODE, val1);
2016157642Sps		REG_RD(sc, BCE_EMAC_MDIO_MODE);
2017157642Sps
2018157642Sps		DELAY(40);
2019157642Sps	}
2020157642Sps
2021157642Sps	return 0;
2022157642Sps}
2023157642Sps
2024157642Sps
2025157642Sps/****************************************************************************/
2026157642Sps/* MII bus status change.                                                   */
2027157642Sps/*                                                                          */
2028157642Sps/* Called by the MII bus driver when the PHY establishes link to set the    */
2029157642Sps/* MAC interface registers.                                                 */
2030157642Sps/*                                                                          */
2031157642Sps/* Returns:                                                                 */
2032157642Sps/*   Nothing.                                                               */
2033157642Sps/****************************************************************************/
2034157642Spsstatic void
2035157642Spsbce_miibus_statchg(device_t dev)
2036157642Sps{
2037157642Sps	struct bce_softc *sc;
2038157642Sps	struct mii_data *mii;
2039235151Syongari	struct ifmediareq ifmr;
2040235151Syongari	int media_active, media_status, val;
2041157642Sps
2042157642Sps	sc = device_get_softc(dev);
2043157642Sps
2044179771Sdavidch	DBENTER(BCE_VERBOSE_PHY);
2045179771Sdavidch
2046235151Syongari	if ((sc->bce_phy_flags & BCE_PHY_REMOTE_CAP_FLAG) != 0) {
2047235151Syongari		bzero(&ifmr, sizeof(ifmr));
2048235151Syongari		bce_ifmedia_sts_rphy(sc, &ifmr);
2049235151Syongari		media_active = ifmr.ifm_active;
2050235151Syongari		media_status = ifmr.ifm_status;
2051235151Syongari	} else {
2052235151Syongari		mii = device_get_softc(sc->bce_miibus);
2053235151Syongari		media_active = mii->mii_media_active;
2054235151Syongari		media_status = mii->mii_media_status;
2055235151Syongari	}
2056157642Sps
2057235816Syongari	/* Ignore invalid media status. */
2058235816Syongari	if ((media_status & (IFM_ACTIVE | IFM_AVALID)) !=
2059235816Syongari	    (IFM_ACTIVE | IFM_AVALID))
2060235816Syongari		goto bce_miibus_statchg_exit;
2061235816Syongari
2062170392Sdavidch	val = REG_RD(sc, BCE_EMAC_MODE);
2063179771Sdavidch	val &= ~(BCE_EMAC_MODE_PORT | BCE_EMAC_MODE_HALF_DUPLEX |
2064207411Sdavidch	    BCE_EMAC_MODE_MAC_LOOP | BCE_EMAC_MODE_FORCE_LINK |
2065207411Sdavidch	    BCE_EMAC_MODE_25G);
2066157642Sps
2067207411Sdavidch	/* Set MII or GMII interface based on the PHY speed. */
2068235151Syongari	switch (IFM_SUBTYPE(media_active)) {
2069234121Syongari	case IFM_10_T:
2070234121Syongari		if (BCE_CHIP_NUM(sc) != BCE_CHIP_NUM_5706) {
2071234121Syongari			DBPRINT(sc, BCE_INFO_PHY,
2072234121Syongari			    "Enabling 10Mb interface.\n");
2073234121Syongari			val |= BCE_EMAC_MODE_PORT_MII_10;
2074170392Sdavidch			break;
2075170392Sdavidch		}
2076234121Syongari		/* fall-through */
2077234121Syongari	case IFM_100_TX:
2078234121Syongari		DBPRINT(sc, BCE_INFO_PHY, "Enabling MII interface.\n");
2079234121Syongari		val |= BCE_EMAC_MODE_PORT_MII;
2080234121Syongari		break;
2081234121Syongari	case IFM_2500_SX:
2082234121Syongari		DBPRINT(sc, BCE_INFO_PHY, "Enabling 2.5G MAC mode.\n");
2083234121Syongari		val |= BCE_EMAC_MODE_25G;
2084234121Syongari		/* fall-through */
2085234121Syongari	case IFM_1000_T:
2086234121Syongari	case IFM_1000_SX:
2087234121Syongari		DBPRINT(sc, BCE_INFO_PHY, "Enabling GMII interface.\n");
2088234121Syongari		val |= BCE_EMAC_MODE_PORT_GMII;
2089234121Syongari		break;
2090234121Syongari	default:
2091234121Syongari		DBPRINT(sc, BCE_INFO_PHY, "Unknown link speed, enabling "
2092234121Syongari		    "default GMII interface.\n");
2093234121Syongari		val |= BCE_EMAC_MODE_PORT_GMII;
2094157642Sps	}
2095157642Sps
2096207411Sdavidch	/* Set half or full duplex based on PHY settings. */
2097235151Syongari	if ((IFM_OPTIONS(media_active) & IFM_FDX) == 0) {
2098207411Sdavidch		DBPRINT(sc, BCE_INFO_PHY,
2099207411Sdavidch		    "Setting Half-Duplex interface.\n");
2100170392Sdavidch		val |= BCE_EMAC_MODE_HALF_DUPLEX;
2101170392Sdavidch	} else
2102207411Sdavidch		DBPRINT(sc, BCE_INFO_PHY,
2103207411Sdavidch		    "Setting Full-Duplex interface.\n");
2104170392Sdavidch
2105170392Sdavidch	REG_WR(sc, BCE_EMAC_MODE, val);
2106170392Sdavidch
2107235151Syongari	if ((IFM_OPTIONS(media_active) & IFM_ETH_RXPAUSE) != 0) {
2108207411Sdavidch		DBPRINT(sc, BCE_INFO_PHY,
2109207411Sdavidch		    "%s(): Enabling RX flow control.\n", __FUNCTION__);
2110170392Sdavidch		BCE_SETBIT(sc, BCE_EMAC_RX_MODE, BCE_EMAC_RX_MODE_FLOW_EN);
2111252402Syongari		sc->bce_flags |= BCE_USING_RX_FLOW_CONTROL;
2112207411Sdavidch	} else {
2113207411Sdavidch		DBPRINT(sc, BCE_INFO_PHY,
2114207411Sdavidch		    "%s(): Disabling RX flow control.\n", __FUNCTION__);
2115207411Sdavidch		BCE_CLRBIT(sc, BCE_EMAC_RX_MODE, BCE_EMAC_RX_MODE_FLOW_EN);
2116252402Syongari		sc->bce_flags &= ~BCE_USING_RX_FLOW_CONTROL;
2117207411Sdavidch	}
2118170392Sdavidch
2119235151Syongari	if ((IFM_OPTIONS(media_active) & IFM_ETH_TXPAUSE) != 0) {
2120207411Sdavidch		DBPRINT(sc, BCE_INFO_PHY,
2121207411Sdavidch		    "%s(): Enabling TX flow control.\n", __FUNCTION__);
2122207411Sdavidch		BCE_SETBIT(sc, BCE_EMAC_TX_MODE, BCE_EMAC_TX_MODE_FLOW_EN);
2123207411Sdavidch		sc->bce_flags |= BCE_USING_TX_FLOW_CONTROL;
2124207411Sdavidch	} else {
2125207411Sdavidch		DBPRINT(sc, BCE_INFO_PHY,
2126207411Sdavidch		    "%s(): Disabling TX flow control.\n", __FUNCTION__);
2127207411Sdavidch		BCE_CLRBIT(sc, BCE_EMAC_TX_MODE, BCE_EMAC_TX_MODE_FLOW_EN);
2128207411Sdavidch		sc->bce_flags &= ~BCE_USING_TX_FLOW_CONTROL;
2129207411Sdavidch	}
2130207411Sdavidch
2131207411Sdavidch	/* ToDo: Update watermarks in bce_init_rx_context(). */
2132207411Sdavidch
2133235816Syongaribce_miibus_statchg_exit:
2134179771Sdavidch	DBEXIT(BCE_VERBOSE_PHY);
2135157642Sps}
2136157642Sps
2137157642Sps
2138157642Sps/****************************************************************************/
2139157642Sps/* Acquire NVRAM lock.                                                      */
2140157642Sps/*                                                                          */
2141157642Sps/* Before the NVRAM can be accessed the caller must acquire an NVRAM lock.  */
2142157642Sps/* Locks 0 and 2 are reserved, lock 1 is used by firmware and lock 2 is     */
2143157642Sps/* for use by the driver.                                                   */
2144157642Sps/*                                                                          */
2145157642Sps/* Returns:                                                                 */
2146157642Sps/*   0 on success, positive value on failure.                               */
2147157642Sps/****************************************************************************/
2148157642Spsstatic int
2149157642Spsbce_acquire_nvram_lock(struct bce_softc *sc)
2150157642Sps{
2151157642Sps	u32 val;
2152179771Sdavidch	int j, rc = 0;
2153157642Sps
2154179771Sdavidch	DBENTER(BCE_VERBOSE_NVRAM);
2155157642Sps
2156157642Sps	/* Request access to the flash interface. */
2157157642Sps	REG_WR(sc, BCE_NVM_SW_ARB, BCE_NVM_SW_ARB_ARB_REQ_SET2);
2158157642Sps	for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) {
2159157642Sps		val = REG_RD(sc, BCE_NVM_SW_ARB);
2160157642Sps		if (val & BCE_NVM_SW_ARB_ARB_ARB2)
2161157642Sps			break;
2162157642Sps
2163157642Sps		DELAY(5);
2164157642Sps	}
2165157642Sps
2166157642Sps	if (j >= NVRAM_TIMEOUT_COUNT) {
2167157642Sps		DBPRINT(sc, BCE_WARN, "Timeout acquiring NVRAM lock!\n");
2168179771Sdavidch		rc = EBUSY;
2169157642Sps	}
2170157642Sps
2171179771Sdavidch	DBEXIT(BCE_VERBOSE_NVRAM);
2172179771Sdavidch	return (rc);
2173157642Sps}
2174157642Sps
2175157642Sps
2176157642Sps/****************************************************************************/
2177157642Sps/* Release NVRAM lock.                                                      */
2178157642Sps/*                                                                          */
2179157642Sps/* When the caller is finished accessing NVRAM the lock must be released.   */
2180157642Sps/* Locks 0 and 2 are reserved, lock 1 is used by firmware and lock 2 is     */
2181157642Sps/* for use by the driver.                                                   */
2182157642Sps/*                                                                          */
2183157642Sps/* Returns:                                                                 */
2184157642Sps/*   0 on success, positive value on failure.                               */
2185157642Sps/****************************************************************************/
2186157642Spsstatic int
2187157642Spsbce_release_nvram_lock(struct bce_softc *sc)
2188157642Sps{
2189157642Sps	u32 val;
2190179771Sdavidch	int j, rc = 0;
2191157642Sps
2192179771Sdavidch	DBENTER(BCE_VERBOSE_NVRAM);
2193157642Sps
2194157642Sps	/*
2195157642Sps	 * Relinquish nvram interface.
2196157642Sps	 */
2197157642Sps	REG_WR(sc, BCE_NVM_SW_ARB, BCE_NVM_SW_ARB_ARB_REQ_CLR2);
2198157642Sps
2199157642Sps	for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) {
2200157642Sps		val = REG_RD(sc, BCE_NVM_SW_ARB);
2201157642Sps		if (!(val & BCE_NVM_SW_ARB_ARB_ARB2))
2202157642Sps			break;
2203157642Sps
2204157642Sps		DELAY(5);
2205157642Sps	}
2206157642Sps
2207157642Sps	if (j >= NVRAM_TIMEOUT_COUNT) {
2208179771Sdavidch		DBPRINT(sc, BCE_WARN, "Timeout releasing NVRAM lock!\n");
2209179771Sdavidch		rc = EBUSY;
2210157642Sps	}
2211157642Sps
2212179771Sdavidch	DBEXIT(BCE_VERBOSE_NVRAM);
2213179771Sdavidch	return (rc);
2214157642Sps}
2215157642Sps
2216157642Sps
2217157642Sps#ifdef BCE_NVRAM_WRITE_SUPPORT
2218157642Sps/****************************************************************************/
2219157642Sps/* Enable NVRAM write access.                                               */
2220157642Sps/*                                                                          */
2221157642Sps/* Before writing to NVRAM the caller must enable NVRAM writes.             */
2222157642Sps/*                                                                          */
2223157642Sps/* Returns:                                                                 */
2224157642Sps/*   0 on success, positive value on failure.                               */
2225157642Sps/****************************************************************************/
2226157642Spsstatic int
2227157642Spsbce_enable_nvram_write(struct bce_softc *sc)
2228157642Sps{
2229157642Sps	u32 val;
2230179771Sdavidch	int rc = 0;
2231157642Sps
2232179771Sdavidch	DBENTER(BCE_VERBOSE_NVRAM);
2233157642Sps
2234157642Sps	val = REG_RD(sc, BCE_MISC_CFG);
2235157642Sps	REG_WR(sc, BCE_MISC_CFG, val | BCE_MISC_CFG_NVM_WR_EN_PCI);
2236157642Sps
2237179771Sdavidch	if (!(sc->bce_flash_info->flags & BCE_NV_BUFFERED)) {
2238157642Sps		int j;
2239157642Sps
2240157642Sps		REG_WR(sc, BCE_NVM_COMMAND, BCE_NVM_COMMAND_DONE);
2241157642Sps		REG_WR(sc, BCE_NVM_COMMAND,	BCE_NVM_COMMAND_WREN | BCE_NVM_COMMAND_DOIT);
2242157642Sps
2243157642Sps		for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) {
2244157642Sps			DELAY(5);
2245157642Sps
2246157642Sps			val = REG_RD(sc, BCE_NVM_COMMAND);
2247157642Sps			if (val & BCE_NVM_COMMAND_DONE)
2248157642Sps				break;
2249157642Sps		}
2250157642Sps
2251157642Sps		if (j >= NVRAM_TIMEOUT_COUNT) {
2252157642Sps			DBPRINT(sc, BCE_WARN, "Timeout writing NVRAM!\n");
2253179771Sdavidch			rc = EBUSY;
2254157642Sps		}
2255157642Sps	}
2256179771Sdavidch
2257179771Sdavidch	DBENTER(BCE_VERBOSE_NVRAM);
2258179771Sdavidch	return (rc);
2259157642Sps}
2260157642Sps
2261157642Sps
2262157642Sps/****************************************************************************/
2263157642Sps/* Disable NVRAM write access.                                              */
2264157642Sps/*                                                                          */
2265157642Sps/* When the caller is finished writing to NVRAM write access must be        */
2266157642Sps/* disabled.                                                                */
2267157642Sps/*                                                                          */
2268157642Sps/* Returns:                                                                 */
2269157642Sps/*   Nothing.                                                               */
2270157642Sps/****************************************************************************/
2271157642Spsstatic void
2272157642Spsbce_disable_nvram_write(struct bce_softc *sc)
2273157642Sps{
2274157642Sps	u32 val;
2275157642Sps
2276179771Sdavidch	DBENTER(BCE_VERBOSE_NVRAM);
2277157642Sps
2278157642Sps	val = REG_RD(sc, BCE_MISC_CFG);
2279157642Sps	REG_WR(sc, BCE_MISC_CFG, val & ~BCE_MISC_CFG_NVM_WR_EN);
2280179771Sdavidch
2281179771Sdavidch	DBEXIT(BCE_VERBOSE_NVRAM);
2282179771Sdavidch
2283157642Sps}
2284157642Sps#endif
2285157642Sps
2286157642Sps
2287157642Sps/****************************************************************************/
2288157642Sps/* Enable NVRAM access.                                                     */
2289157642Sps/*                                                                          */
2290157642Sps/* Before accessing NVRAM for read or write operations the caller must      */
2291157642Sps/* enabled NVRAM access.                                                    */
2292157642Sps/*                                                                          */
2293157642Sps/* Returns:                                                                 */
2294157642Sps/*   Nothing.                                                               */
2295157642Sps/****************************************************************************/
2296157642Spsstatic void
2297157642Spsbce_enable_nvram_access(struct bce_softc *sc)
2298157642Sps{
2299157642Sps	u32 val;
2300157642Sps
2301179771Sdavidch	DBENTER(BCE_VERBOSE_NVRAM);
2302157642Sps
2303157642Sps	val = REG_RD(sc, BCE_NVM_ACCESS_ENABLE);
2304157642Sps	/* Enable both bits, even on read. */
2305207411Sdavidch	REG_WR(sc, BCE_NVM_ACCESS_ENABLE, val |
2306207411Sdavidch	    BCE_NVM_ACCESS_ENABLE_EN | BCE_NVM_ACCESS_ENABLE_WR_EN);
2307179771Sdavidch
2308179771Sdavidch	DBEXIT(BCE_VERBOSE_NVRAM);
2309157642Sps}
2310157642Sps
2311157642Sps
2312157642Sps/****************************************************************************/
2313157642Sps/* Disable NVRAM access.                                                    */
2314157642Sps/*                                                                          */
2315157642Sps/* When the caller is finished accessing NVRAM access must be disabled.     */
2316157642Sps/*                                                                          */
2317157642Sps/* Returns:                                                                 */
2318157642Sps/*   Nothing.                                                               */
2319157642Sps/****************************************************************************/
2320157642Spsstatic void
2321157642Spsbce_disable_nvram_access(struct bce_softc *sc)
2322157642Sps{
2323157642Sps	u32 val;
2324157642Sps
2325179771Sdavidch	DBENTER(BCE_VERBOSE_NVRAM);
2326157642Sps
2327157642Sps	val = REG_RD(sc, BCE_NVM_ACCESS_ENABLE);
2328157642Sps
2329157642Sps	/* Disable both bits, even after read. */
2330207411Sdavidch	REG_WR(sc, BCE_NVM_ACCESS_ENABLE, val &
2331207411Sdavidch	    ~(BCE_NVM_ACCESS_ENABLE_EN | BCE_NVM_ACCESS_ENABLE_WR_EN));
2332179771Sdavidch
2333179771Sdavidch	DBEXIT(BCE_VERBOSE_NVRAM);
2334157642Sps}
2335157642Sps
2336157642Sps
2337157642Sps#ifdef BCE_NVRAM_WRITE_SUPPORT
2338157642Sps/****************************************************************************/
2339157642Sps/* Erase NVRAM page before writing.                                         */
2340157642Sps/*                                                                          */
2341157642Sps/* Non-buffered flash parts require that a page be erased before it is      */
2342157642Sps/* written.                                                                 */
2343157642Sps/*                                                                          */
2344157642Sps/* Returns:                                                                 */
2345157642Sps/*   0 on success, positive value on failure.                               */
2346157642Sps/****************************************************************************/
2347157642Spsstatic int
2348157642Spsbce_nvram_erase_page(struct bce_softc *sc, u32 offset)
2349157642Sps{
2350157642Sps	u32 cmd;
2351179771Sdavidch	int j, rc = 0;
2352157642Sps
2353179771Sdavidch	DBENTER(BCE_VERBOSE_NVRAM);
2354179771Sdavidch
2355157642Sps	/* Buffered flash doesn't require an erase. */
2356179771Sdavidch	if (sc->bce_flash_info->flags & BCE_NV_BUFFERED)
2357179771Sdavidch		goto bce_nvram_erase_page_exit;
2358157642Sps
2359157642Sps	/* Build an erase command. */
2360157642Sps	cmd = BCE_NVM_COMMAND_ERASE | BCE_NVM_COMMAND_WR |
2361207411Sdavidch	    BCE_NVM_COMMAND_DOIT;
2362157642Sps
2363157642Sps	/*
2364298955Spfg	 * Clear the DONE bit separately, set the NVRAM address to erase,
2365157642Sps	 * and issue the erase command.
2366157642Sps	 */
2367157642Sps	REG_WR(sc, BCE_NVM_COMMAND, BCE_NVM_COMMAND_DONE);
2368157642Sps	REG_WR(sc, BCE_NVM_ADDR, offset & BCE_NVM_ADDR_NVM_ADDR_VALUE);
2369157642Sps	REG_WR(sc, BCE_NVM_COMMAND, cmd);
2370157642Sps
2371157642Sps	/* Wait for completion. */
2372157642Sps	for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) {
2373157642Sps		u32 val;
2374157642Sps
2375157642Sps		DELAY(5);
2376157642Sps
2377157642Sps		val = REG_RD(sc, BCE_NVM_COMMAND);
2378157642Sps		if (val & BCE_NVM_COMMAND_DONE)
2379157642Sps			break;
2380157642Sps	}
2381157642Sps
2382157642Sps	if (j >= NVRAM_TIMEOUT_COUNT) {
2383157642Sps		DBPRINT(sc, BCE_WARN, "Timeout erasing NVRAM.\n");
2384179771Sdavidch		rc = EBUSY;
2385157642Sps	}
2386157642Sps
2387179771Sdavidchbce_nvram_erase_page_exit:
2388179771Sdavidch	DBEXIT(BCE_VERBOSE_NVRAM);
2389179771Sdavidch	return (rc);
2390157642Sps}
2391157642Sps#endif /* BCE_NVRAM_WRITE_SUPPORT */
2392157642Sps
2393157642Sps
2394157642Sps/****************************************************************************/
2395157642Sps/* Read a dword (32 bits) from NVRAM.                                       */
2396157642Sps/*                                                                          */
2397157642Sps/* Read a 32 bit word from NVRAM.  The caller is assumed to have already    */
2398157642Sps/* obtained the NVRAM lock and enabled the controller for NVRAM access.     */
2399157642Sps/*                                                                          */
2400157642Sps/* Returns:                                                                 */
2401157642Sps/*   0 on success and the 32 bit value read, positive value on failure.     */
2402157642Sps/****************************************************************************/
2403157642Spsstatic int
2404207411Sdavidchbce_nvram_read_dword(struct bce_softc *sc,
2405207411Sdavidch    u32 offset, u8 *ret_val, u32 cmd_flags)
2406157642Sps{
2407157642Sps	u32 cmd;
2408157642Sps	int i, rc = 0;
2409157642Sps
2410179771Sdavidch	DBENTER(BCE_EXTREME_NVRAM);
2411179771Sdavidch
2412157642Sps	/* Build the command word. */
2413157642Sps	cmd = BCE_NVM_COMMAND_DOIT | cmd_flags;
2414157642Sps
2415179771Sdavidch	/* Calculate the offset for buffered flash if translation is used. */
2416179771Sdavidch	if (sc->bce_flash_info->flags & BCE_NV_TRANSLATE) {
2417157642Sps		offset = ((offset / sc->bce_flash_info->page_size) <<
2418207411Sdavidch		    sc->bce_flash_info->page_bits) +
2419207411Sdavidch		    (offset % sc->bce_flash_info->page_size);
2420157642Sps	}
2421157642Sps
2422157642Sps	/*
2423157642Sps	 * Clear the DONE bit separately, set the address to read,
2424157642Sps	 * and issue the read.
2425157642Sps	 */
2426157642Sps	REG_WR(sc, BCE_NVM_COMMAND, BCE_NVM_COMMAND_DONE);
2427157642Sps	REG_WR(sc, BCE_NVM_ADDR, offset & BCE_NVM_ADDR_NVM_ADDR_VALUE);
2428157642Sps	REG_WR(sc, BCE_NVM_COMMAND, cmd);
2429157642Sps
2430157642Sps	/* Wait for completion. */
2431157642Sps	for (i = 0; i < NVRAM_TIMEOUT_COUNT; i++) {
2432157642Sps		u32 val;
2433157642Sps
2434157642Sps		DELAY(5);
2435157642Sps
2436157642Sps		val = REG_RD(sc, BCE_NVM_COMMAND);
2437157642Sps		if (val & BCE_NVM_COMMAND_DONE) {
2438157642Sps			val = REG_RD(sc, BCE_NVM_READ);
2439157642Sps
2440157642Sps			val = bce_be32toh(val);
2441157642Sps			memcpy(ret_val, &val, 4);
2442157642Sps			break;
2443157642Sps		}
2444157642Sps	}
2445157642Sps
2446157642Sps	/* Check for errors. */
2447157642Sps	if (i >= NVRAM_TIMEOUT_COUNT) {
2448207411Sdavidch		BCE_PRINTF("%s(%d): Timeout error reading NVRAM at "
2449207411Sdavidch		    "offset 0x%08X!\n",	__FILE__, __LINE__, offset);
2450157642Sps		rc = EBUSY;
2451157642Sps	}
2452157642Sps
2453179771Sdavidch	DBEXIT(BCE_EXTREME_NVRAM);
2454157642Sps	return(rc);
2455157642Sps}
2456157642Sps
2457157642Sps
2458157642Sps#ifdef BCE_NVRAM_WRITE_SUPPORT
2459157642Sps/****************************************************************************/
2460157642Sps/* Write a dword (32 bits) to NVRAM.                                        */
2461157642Sps/*                                                                          */
2462157642Sps/* Write a 32 bit word to NVRAM.  The caller is assumed to have already     */
2463157642Sps/* obtained the NVRAM lock, enabled the controller for NVRAM access, and    */
2464157642Sps/* enabled NVRAM write access.                                              */
2465157642Sps/*                                                                          */
2466157642Sps/* Returns:                                                                 */
2467157642Sps/*   0 on success, positive value on failure.                               */
2468157642Sps/****************************************************************************/
2469157642Spsstatic int
2470157642Spsbce_nvram_write_dword(struct bce_softc *sc, u32 offset, u8 *val,
2471157642Sps	u32 cmd_flags)
2472157642Sps{
2473157642Sps	u32 cmd, val32;
2474179771Sdavidch	int j, rc = 0;
2475157642Sps
2476179771Sdavidch	DBENTER(BCE_VERBOSE_NVRAM);
2477179771Sdavidch
2478157642Sps	/* Build the command word. */
2479157642Sps	cmd = BCE_NVM_COMMAND_DOIT | BCE_NVM_COMMAND_WR | cmd_flags;
2480157642Sps
2481179771Sdavidch	/* Calculate the offset for buffered flash if translation is used. */
2482179771Sdavidch	if (sc->bce_flash_info->flags & BCE_NV_TRANSLATE) {
2483157642Sps		offset = ((offset / sc->bce_flash_info->page_size) <<
2484207411Sdavidch		    sc->bce_flash_info->page_bits) +
2485207411Sdavidch		    (offset % sc->bce_flash_info->page_size);
2486157642Sps	}
2487157642Sps
2488157642Sps	/*
2489157642Sps	 * Clear the DONE bit separately, convert NVRAM data to big-endian,
2490157642Sps	 * set the NVRAM address to write, and issue the write command
2491157642Sps	 */
2492157642Sps	REG_WR(sc, BCE_NVM_COMMAND, BCE_NVM_COMMAND_DONE);
2493157642Sps	memcpy(&val32, val, 4);
2494157642Sps	val32 = htobe32(val32);
2495157642Sps	REG_WR(sc, BCE_NVM_WRITE, val32);
2496157642Sps	REG_WR(sc, BCE_NVM_ADDR, offset & BCE_NVM_ADDR_NVM_ADDR_VALUE);
2497157642Sps	REG_WR(sc, BCE_NVM_COMMAND, cmd);
2498157642Sps
2499157642Sps	/* Wait for completion. */
2500157642Sps	for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) {
2501157642Sps		DELAY(5);
2502157642Sps
2503157642Sps		if (REG_RD(sc, BCE_NVM_COMMAND) & BCE_NVM_COMMAND_DONE)
2504157642Sps			break;
2505157642Sps	}
2506157642Sps	if (j >= NVRAM_TIMEOUT_COUNT) {
2507207411Sdavidch		BCE_PRINTF("%s(%d): Timeout error writing NVRAM at "
2508207411Sdavidch		    "offset 0x%08X\n", __FILE__, __LINE__, offset);
2509179771Sdavidch		rc = EBUSY;
2510157642Sps	}
2511157642Sps
2512179771Sdavidch	DBEXIT(BCE_VERBOSE_NVRAM);
2513179771Sdavidch	return (rc);
2514157642Sps}
2515157642Sps#endif /* BCE_NVRAM_WRITE_SUPPORT */
2516157642Sps
2517157642Sps
2518157642Sps/****************************************************************************/
2519157642Sps/* Initialize NVRAM access.                                                 */
2520157642Sps/*                                                                          */
2521157642Sps/* Identify the NVRAM device in use and prepare the NVRAM interface to      */
2522157642Sps/* access that device.                                                      */
2523157642Sps/*                                                                          */
2524157642Sps/* Returns:                                                                 */
2525157642Sps/*   0 on success, positive value on failure.                               */
2526157642Sps/****************************************************************************/
2527157642Spsstatic int
2528157642Spsbce_init_nvram(struct bce_softc *sc)
2529157642Sps{
2530157642Sps	u32 val;
2531179771Sdavidch	int j, entry_count, rc = 0;
2532247565Smarius	const struct flash_spec *flash;
2533157642Sps
2534179771Sdavidch	DBENTER(BCE_VERBOSE_NVRAM);
2535157642Sps
2536226123Syongari	if (BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5709) {
2537179771Sdavidch		sc->bce_flash_info = &flash_5709;
2538179771Sdavidch		goto bce_init_nvram_get_flash_size;
2539179771Sdavidch	}
2540179771Sdavidch
2541157642Sps	/* Determine the selected interface. */
2542157642Sps	val = REG_RD(sc, BCE_NVM_CFG1);
2543157642Sps
2544157642Sps	entry_count = sizeof(flash_table) / sizeof(struct flash_spec);
2545157642Sps
2546157642Sps	/*
2547157642Sps	 * Flash reconfiguration is required to support additional
2548157642Sps	 * NVRAM devices not directly supported in hardware.
2549157642Sps	 * Check if the flash interface was reconfigured
2550157642Sps	 * by the bootcode.
2551157642Sps	 */
2552157642Sps
2553157642Sps	if (val & 0x40000000) {
2554157642Sps		/* Flash interface reconfigured by bootcode. */
2555157642Sps
2556179771Sdavidch		DBPRINT(sc,BCE_INFO_LOAD,
2557157642Sps			"bce_init_nvram(): Flash WAS reconfigured.\n");
2558157642Sps
2559157642Sps		for (j = 0, flash = &flash_table[0]; j < entry_count;
2560157642Sps		     j++, flash++) {
2561157642Sps			if ((val & FLASH_BACKUP_STRAP_MASK) ==
2562157642Sps			    (flash->config1 & FLASH_BACKUP_STRAP_MASK)) {
2563157642Sps				sc->bce_flash_info = flash;
2564157642Sps				break;
2565157642Sps			}
2566157642Sps		}
2567157642Sps	} else {
2568157642Sps		/* Flash interface not yet reconfigured. */
2569157642Sps		u32 mask;
2570157642Sps
2571179771Sdavidch		DBPRINT(sc, BCE_INFO_LOAD, "%s(): Flash was NOT reconfigured.\n",
2572179771Sdavidch			__FUNCTION__);
2573157642Sps
2574157642Sps		if (val & (1 << 23))
2575157642Sps			mask = FLASH_BACKUP_STRAP_MASK;
2576157642Sps		else
2577157642Sps			mask = FLASH_STRAP_MASK;
2578157642Sps
2579157642Sps		/* Look for the matching NVRAM device configuration data. */
2580157642Sps		for (j = 0, flash = &flash_table[0]; j < entry_count; j++, flash++) {
2581157642Sps
2582157642Sps			/* Check if the device matches any of the known devices. */
2583157642Sps			if ((val & mask) == (flash->strapping & mask)) {
2584157642Sps				/* Found a device match. */
2585157642Sps				sc->bce_flash_info = flash;
2586157642Sps
2587157642Sps				/* Request access to the flash interface. */
2588157642Sps				if ((rc = bce_acquire_nvram_lock(sc)) != 0)
2589157642Sps					return rc;
2590157642Sps
2591157642Sps				/* Reconfigure the flash interface. */
2592157642Sps				bce_enable_nvram_access(sc);
2593157642Sps				REG_WR(sc, BCE_NVM_CFG1, flash->config1);
2594157642Sps				REG_WR(sc, BCE_NVM_CFG2, flash->config2);
2595157642Sps				REG_WR(sc, BCE_NVM_CFG3, flash->config3);
2596157642Sps				REG_WR(sc, BCE_NVM_WRITE1, flash->write1);
2597157642Sps				bce_disable_nvram_access(sc);
2598157642Sps				bce_release_nvram_lock(sc);
2599157642Sps
2600157642Sps				break;
2601157642Sps			}
2602157642Sps		}
2603157642Sps	}
2604157642Sps
2605157642Sps	/* Check if a matching device was found. */
2606157642Sps	if (j == entry_count) {
2607157642Sps		sc->bce_flash_info = NULL;
2608179771Sdavidch		BCE_PRINTF("%s(%d): Unknown Flash NVRAM found!\n",
2609207411Sdavidch		    __FILE__, __LINE__);
2610210257Syongari		DBEXIT(BCE_VERBOSE_NVRAM);
2611210257Syongari		return (ENODEV);
2612157642Sps	}
2613157642Sps
2614179771Sdavidchbce_init_nvram_get_flash_size:
2615157642Sps	/* Write the flash config data to the shared memory interface. */
2616194781Sdavidch	val = bce_shmem_rd(sc, BCE_SHARED_HW_CFG_CONFIG2);
2617157642Sps	val &= BCE_SHARED_HW_CFG2_NVM_SIZE_MASK;
2618157642Sps	if (val)
2619157642Sps		sc->bce_flash_size = val;
2620157642Sps	else
2621157642Sps		sc->bce_flash_size = sc->bce_flash_info->total_size;
2622157642Sps
2623179771Sdavidch	DBPRINT(sc, BCE_INFO_LOAD, "%s(): Found %s, size = 0x%08X\n",
2624207411Sdavidch	    __FUNCTION__, sc->bce_flash_info->name,
2625207411Sdavidch	    sc->bce_flash_info->total_size);
2626157642Sps
2627179771Sdavidch	DBEXIT(BCE_VERBOSE_NVRAM);
2628157642Sps	return rc;
2629157642Sps}
2630157642Sps
2631157642Sps
2632157642Sps/****************************************************************************/
2633157642Sps/* Read an arbitrary range of data from NVRAM.                              */
2634157642Sps/*                                                                          */
2635157642Sps/* Prepares the NVRAM interface for access and reads the requested data     */
2636157642Sps/* into the supplied buffer.                                                */
2637157642Sps/*                                                                          */
2638157642Sps/* Returns:                                                                 */
2639157642Sps/*   0 on success and the data read, positive value on failure.             */
2640157642Sps/****************************************************************************/
2641157642Spsstatic int
2642157642Spsbce_nvram_read(struct bce_softc *sc, u32 offset, u8 *ret_buf,
2643157642Sps	int buf_size)
2644157642Sps{
2645157642Sps	int rc = 0;
2646157642Sps	u32 cmd_flags, offset32, len32, extra;
2647157642Sps
2648179771Sdavidch	DBENTER(BCE_VERBOSE_NVRAM);
2649179771Sdavidch
2650157642Sps	if (buf_size == 0)
2651179771Sdavidch		goto bce_nvram_read_exit;
2652157642Sps
2653157642Sps	/* Request access to the flash interface. */
2654157642Sps	if ((rc = bce_acquire_nvram_lock(sc)) != 0)
2655179771Sdavidch		goto bce_nvram_read_exit;
2656157642Sps
2657157642Sps	/* Enable access to flash interface */
2658157642Sps	bce_enable_nvram_access(sc);
2659157642Sps
2660157642Sps	len32 = buf_size;
2661157642Sps	offset32 = offset;
2662157642Sps	extra = 0;
2663157642Sps
2664157642Sps	cmd_flags = 0;
2665157642Sps
2666157642Sps	if (offset32 & 3) {
2667157642Sps		u8 buf[4];
2668157642Sps		u32 pre_len;
2669157642Sps
2670157642Sps		offset32 &= ~3;
2671157642Sps		pre_len = 4 - (offset & 3);
2672157642Sps
2673157642Sps		if (pre_len >= len32) {
2674157642Sps			pre_len = len32;
2675157642Sps			cmd_flags = BCE_NVM_COMMAND_FIRST | BCE_NVM_COMMAND_LAST;
2676157642Sps		}
2677157642Sps		else {
2678157642Sps			cmd_flags = BCE_NVM_COMMAND_FIRST;
2679157642Sps		}
2680157642Sps
2681157642Sps		rc = bce_nvram_read_dword(sc, offset32, buf, cmd_flags);
2682157642Sps
2683157642Sps		if (rc)
2684157642Sps			return rc;
2685157642Sps
2686157642Sps		memcpy(ret_buf, buf + (offset & 3), pre_len);
2687157642Sps
2688157642Sps		offset32 += 4;
2689157642Sps		ret_buf += pre_len;
2690157642Sps		len32 -= pre_len;
2691157642Sps	}
2692157642Sps
2693157642Sps	if (len32 & 3) {
2694157642Sps		extra = 4 - (len32 & 3);
2695157642Sps		len32 = (len32 + 4) & ~3;
2696157642Sps	}
2697157642Sps
2698157642Sps	if (len32 == 4) {
2699157642Sps		u8 buf[4];
2700157642Sps
2701157642Sps		if (cmd_flags)
2702157642Sps			cmd_flags = BCE_NVM_COMMAND_LAST;
2703157642Sps		else
2704157642Sps			cmd_flags = BCE_NVM_COMMAND_FIRST |
2705157642Sps				    BCE_NVM_COMMAND_LAST;
2706157642Sps
2707157642Sps		rc = bce_nvram_read_dword(sc, offset32, buf, cmd_flags);
2708157642Sps
2709157642Sps		memcpy(ret_buf, buf, 4 - extra);
2710157642Sps	}
2711157642Sps	else if (len32 > 0) {
2712157642Sps		u8 buf[4];
2713157642Sps
2714157642Sps		/* Read the first word. */
2715157642Sps		if (cmd_flags)
2716157642Sps			cmd_flags = 0;
2717157642Sps		else
2718157642Sps			cmd_flags = BCE_NVM_COMMAND_FIRST;
2719157642Sps
2720157642Sps		rc = bce_nvram_read_dword(sc, offset32, ret_buf, cmd_flags);
2721157642Sps
2722157642Sps		/* Advance to the next dword. */
2723157642Sps		offset32 += 4;
2724157642Sps		ret_buf += 4;
2725157642Sps		len32 -= 4;
2726157642Sps
2727157642Sps		while (len32 > 4 && rc == 0) {
2728157642Sps			rc = bce_nvram_read_dword(sc, offset32, ret_buf, 0);
2729157642Sps
2730157642Sps			/* Advance to the next dword. */
2731157642Sps			offset32 += 4;
2732157642Sps			ret_buf += 4;
2733157642Sps			len32 -= 4;
2734157642Sps		}
2735157642Sps
2736157642Sps		if (rc)
2737179771Sdavidch			goto bce_nvram_read_locked_exit;
2738157642Sps
2739157642Sps		cmd_flags = BCE_NVM_COMMAND_LAST;
2740157642Sps		rc = bce_nvram_read_dword(sc, offset32, buf, cmd_flags);
2741157642Sps
2742157642Sps		memcpy(ret_buf, buf, 4 - extra);
2743157642Sps	}
2744157642Sps
2745179771Sdavidchbce_nvram_read_locked_exit:
2746157642Sps	/* Disable access to flash interface and release the lock. */
2747157642Sps	bce_disable_nvram_access(sc);
2748157642Sps	bce_release_nvram_lock(sc);
2749157642Sps
2750179771Sdavidchbce_nvram_read_exit:
2751179771Sdavidch	DBEXIT(BCE_VERBOSE_NVRAM);
2752157642Sps	return rc;
2753157642Sps}
2754157642Sps
2755157642Sps
2756157642Sps#ifdef BCE_NVRAM_WRITE_SUPPORT
2757157642Sps/****************************************************************************/
2758157642Sps/* Write an arbitrary range of data from NVRAM.                             */
2759157642Sps/*                                                                          */
2760157642Sps/* Prepares the NVRAM interface for write access and writes the requested   */
2761157642Sps/* data from the supplied buffer.  The caller is responsible for            */
2762157642Sps/* calculating any appropriate CRCs.                                        */
2763157642Sps/*                                                                          */
2764157642Sps/* Returns:                                                                 */
2765157642Sps/*   0 on success, positive value on failure.                               */
2766157642Sps/****************************************************************************/
2767157642Spsstatic int
2768157642Spsbce_nvram_write(struct bce_softc *sc, u32 offset, u8 *data_buf,
2769157642Sps	int buf_size)
2770157642Sps{
2771157642Sps	u32 written, offset32, len32;
2772157642Sps	u8 *buf, start[4], end[4];
2773157642Sps	int rc = 0;
2774157642Sps	int align_start, align_end;
2775157642Sps
2776179771Sdavidch	DBENTER(BCE_VERBOSE_NVRAM);
2777179771Sdavidch
2778157642Sps	buf = data_buf;
2779157642Sps	offset32 = offset;
2780157642Sps	len32 = buf_size;
2781157642Sps	align_start = align_end = 0;
2782157642Sps
2783157642Sps	if ((align_start = (offset32 & 3))) {
2784157642Sps		offset32 &= ~3;
2785157642Sps		len32 += align_start;
2786157642Sps		if ((rc = bce_nvram_read(sc, offset32, start, 4)))
2787179771Sdavidch			goto bce_nvram_write_exit;
2788157642Sps	}
2789157642Sps
2790157642Sps	if (len32 & 3) {
2791157642Sps	       	if ((len32 > 4) || !align_start) {
2792157642Sps			align_end = 4 - (len32 & 3);
2793157642Sps			len32 += align_end;
2794157642Sps			if ((rc = bce_nvram_read(sc, offset32 + len32 - 4,
2795157642Sps				end, 4))) {
2796179771Sdavidch				goto bce_nvram_write_exit;
2797157642Sps			}
2798157642Sps		}
2799157642Sps	}
2800157642Sps
2801157642Sps	if (align_start || align_end) {
2802157642Sps		buf = malloc(len32, M_DEVBUF, M_NOWAIT);
2803315221Spfg		if (buf == NULL) {
2804179771Sdavidch			rc = ENOMEM;
2805179771Sdavidch			goto bce_nvram_write_exit;
2806179771Sdavidch		}
2807179771Sdavidch
2808157642Sps		if (align_start) {
2809157642Sps			memcpy(buf, start, 4);
2810157642Sps		}
2811179771Sdavidch
2812157642Sps		if (align_end) {
2813157642Sps			memcpy(buf + len32 - 4, end, 4);
2814157642Sps		}
2815157642Sps		memcpy(buf + align_start, data_buf, buf_size);
2816157642Sps	}
2817157642Sps
2818157642Sps	written = 0;
2819157642Sps	while ((written < len32) && (rc == 0)) {
2820157642Sps		u32 page_start, page_end, data_start, data_end;
2821157642Sps		u32 addr, cmd_flags;
2822157642Sps		int i;
2823157642Sps		u8 flash_buffer[264];
2824157642Sps
2825157642Sps	    /* Find the page_start addr */
2826157642Sps		page_start = offset32 + written;
2827157642Sps		page_start -= (page_start % sc->bce_flash_info->page_size);
2828157642Sps		/* Find the page_end addr */
2829157642Sps		page_end = page_start + sc->bce_flash_info->page_size;
2830157642Sps		/* Find the data_start addr */
2831157642Sps		data_start = (written == 0) ? offset32 : page_start;
2832157642Sps		/* Find the data_end addr */
2833157642Sps		data_end = (page_end > offset32 + len32) ?
2834157642Sps			(offset32 + len32) : page_end;
2835157642Sps
2836157642Sps		/* Request access to the flash interface. */
2837157642Sps		if ((rc = bce_acquire_nvram_lock(sc)) != 0)
2838179771Sdavidch			goto bce_nvram_write_exit;
2839157642Sps
2840157642Sps		/* Enable access to flash interface */
2841157642Sps		bce_enable_nvram_access(sc);
2842157642Sps
2843157642Sps		cmd_flags = BCE_NVM_COMMAND_FIRST;
2844179771Sdavidch		if (!(sc->bce_flash_info->flags & BCE_NV_BUFFERED)) {
2845157642Sps			int j;
2846157642Sps
2847157642Sps			/* Read the whole page into the buffer
2848157642Sps			 * (non-buffer flash only) */
2849157642Sps			for (j = 0; j < sc->bce_flash_info->page_size; j += 4) {
2850157642Sps				if (j == (sc->bce_flash_info->page_size - 4)) {
2851157642Sps					cmd_flags |= BCE_NVM_COMMAND_LAST;
2852157642Sps				}
2853157642Sps				rc = bce_nvram_read_dword(sc,
2854157642Sps					page_start + j,
2855157642Sps					&flash_buffer[j],
2856157642Sps					cmd_flags);
2857157642Sps
2858157642Sps				if (rc)
2859179771Sdavidch					goto bce_nvram_write_locked_exit;
2860157642Sps
2861157642Sps				cmd_flags = 0;
2862157642Sps			}
2863157642Sps		}
2864157642Sps
2865157642Sps		/* Enable writes to flash interface (unlock write-protect) */
2866157642Sps		if ((rc = bce_enable_nvram_write(sc)) != 0)
2867179771Sdavidch			goto bce_nvram_write_locked_exit;
2868157642Sps
2869157642Sps		/* Erase the page */
2870157642Sps		if ((rc = bce_nvram_erase_page(sc, page_start)) != 0)
2871179771Sdavidch			goto bce_nvram_write_locked_exit;
2872157642Sps
2873157642Sps		/* Re-enable the write again for the actual write */
2874157642Sps		bce_enable_nvram_write(sc);
2875157642Sps
2876157642Sps		/* Loop to write back the buffer data from page_start to
2877157642Sps		 * data_start */
2878157642Sps		i = 0;
2879179771Sdavidch		if (!(sc->bce_flash_info->flags & BCE_NV_BUFFERED)) {
2880157642Sps			for (addr = page_start; addr < data_start;
2881157642Sps				addr += 4, i += 4) {
2882157642Sps
2883157642Sps				rc = bce_nvram_write_dword(sc, addr,
2884157642Sps					&flash_buffer[i], cmd_flags);
2885157642Sps
2886157642Sps				if (rc != 0)
2887179771Sdavidch					goto bce_nvram_write_locked_exit;
2888157642Sps
2889157642Sps				cmd_flags = 0;
2890157642Sps			}
2891157642Sps		}
2892157642Sps
2893157642Sps		/* Loop to write the new data from data_start to data_end */
2894157642Sps		for (addr = data_start; addr < data_end; addr += 4, i++) {
2895157642Sps			if ((addr == page_end - 4) ||
2896179771Sdavidch				((sc->bce_flash_info->flags & BCE_NV_BUFFERED) &&
2897179771Sdavidch				(addr == data_end - 4))) {
2898157642Sps
2899157642Sps				cmd_flags |= BCE_NVM_COMMAND_LAST;
2900157642Sps			}
2901157642Sps			rc = bce_nvram_write_dword(sc, addr, buf,
2902157642Sps				cmd_flags);
2903157642Sps
2904157642Sps			if (rc != 0)
2905179771Sdavidch				goto bce_nvram_write_locked_exit;
2906157642Sps
2907157642Sps			cmd_flags = 0;
2908157642Sps			buf += 4;
2909157642Sps		}
2910157642Sps
2911157642Sps		/* Loop to write back the buffer data from data_end
2912157642Sps		 * to page_end */
2913179771Sdavidch		if (!(sc->bce_flash_info->flags & BCE_NV_BUFFERED)) {
2914157642Sps			for (addr = data_end; addr < page_end;
2915157642Sps				addr += 4, i += 4) {
2916157642Sps
2917157642Sps				if (addr == page_end-4) {
2918157642Sps					cmd_flags = BCE_NVM_COMMAND_LAST;
2919157642Sps                		}
2920157642Sps				rc = bce_nvram_write_dword(sc, addr,
2921157642Sps					&flash_buffer[i], cmd_flags);
2922157642Sps
2923157642Sps				if (rc != 0)
2924179771Sdavidch					goto bce_nvram_write_locked_exit;
2925157642Sps
2926157642Sps				cmd_flags = 0;
2927157642Sps			}
2928157642Sps		}
2929157642Sps
2930157642Sps		/* Disable writes to flash interface (lock write-protect) */
2931157642Sps		bce_disable_nvram_write(sc);
2932157642Sps
2933157642Sps		/* Disable access to flash interface */
2934157642Sps		bce_disable_nvram_access(sc);
2935157642Sps		bce_release_nvram_lock(sc);
2936157642Sps
2937157642Sps		/* Increment written */
2938157642Sps		written += data_end - data_start;
2939157642Sps	}
2940157642Sps
2941179771Sdavidch	goto bce_nvram_write_exit;
2942179771Sdavidch
2943179771Sdavidchbce_nvram_write_locked_exit:
2944218527Sdavidch	bce_disable_nvram_write(sc);
2945218527Sdavidch	bce_disable_nvram_access(sc);
2946218527Sdavidch	bce_release_nvram_lock(sc);
2947179771Sdavidch
2948179771Sdavidchbce_nvram_write_exit:
2949157642Sps	if (align_start || align_end)
2950157642Sps		free(buf, M_DEVBUF);
2951157642Sps
2952179771Sdavidch	DBEXIT(BCE_VERBOSE_NVRAM);
2953179771Sdavidch	return (rc);
2954157642Sps}
2955157642Sps#endif /* BCE_NVRAM_WRITE_SUPPORT */
2956157642Sps
2957157642Sps
2958157642Sps/****************************************************************************/
2959157642Sps/* Verifies that NVRAM is accessible and contains valid data.               */
2960157642Sps/*                                                                          */
2961157642Sps/* Reads the configuration data from NVRAM and verifies that the CRC is     */
2962157642Sps/* correct.                                                                 */
2963157642Sps/*                                                                          */
2964157642Sps/* Returns:                                                                 */
2965157642Sps/*   0 on success, positive value on failure.                               */
2966157642Sps/****************************************************************************/
2967157642Spsstatic int
2968157642Spsbce_nvram_test(struct bce_softc *sc)
2969157642Sps{
2970157642Sps	u32 buf[BCE_NVRAM_SIZE / 4];
2971157642Sps	u8 *data = (u8 *) buf;
2972157642Sps	int rc = 0;
2973157642Sps	u32 magic, csum;
2974157642Sps
2975179771Sdavidch	DBENTER(BCE_VERBOSE_NVRAM | BCE_VERBOSE_LOAD | BCE_VERBOSE_RESET);
2976157642Sps
2977157642Sps	/*
2978157642Sps	 * Check that the device NVRAM is valid by reading
2979157642Sps	 * the magic value at offset 0.
2980157642Sps	 */
2981179771Sdavidch	if ((rc = bce_nvram_read(sc, 0, data, 4)) != 0) {
2982207411Sdavidch		BCE_PRINTF("%s(%d): Unable to read NVRAM!\n",
2983207411Sdavidch		    __FILE__, __LINE__);
2984179771Sdavidch		goto bce_nvram_test_exit;
2985179771Sdavidch	}
2986157642Sps
2987179771Sdavidch	/*
2988179771Sdavidch	 * Verify that offset 0 of the NVRAM contains
2989179771Sdavidch	 * a valid magic number.
2990179771Sdavidch	 */
2991218527Sdavidch	magic = bce_be32toh(buf[0]);
2992157642Sps	if (magic != BCE_NVRAM_MAGIC) {
2993157642Sps		rc = ENODEV;
2994207411Sdavidch		BCE_PRINTF("%s(%d): Invalid NVRAM magic value! "
2995207411Sdavidch		    "Expected: 0x%08X, Found: 0x%08X\n",
2996207411Sdavidch		    __FILE__, __LINE__, BCE_NVRAM_MAGIC, magic);
2997179771Sdavidch		goto bce_nvram_test_exit;
2998157642Sps	}
2999157642Sps
3000157642Sps	/*
3001157642Sps	 * Verify that the device NVRAM includes valid
3002157642Sps	 * configuration data.
3003157642Sps	 */
3004179771Sdavidch	if ((rc = bce_nvram_read(sc, 0x100, data, BCE_NVRAM_SIZE)) != 0) {
3005207411Sdavidch		BCE_PRINTF("%s(%d): Unable to read manufacturing "
3006207411Sdavidch		    "Information from  NVRAM!\n", __FILE__, __LINE__);
3007179771Sdavidch		goto bce_nvram_test_exit;
3008179771Sdavidch	}
3009157642Sps
3010157642Sps	csum = ether_crc32_le(data, 0x100);
3011157642Sps	if (csum != BCE_CRC32_RESIDUAL) {
3012157642Sps		rc = ENODEV;
3013207411Sdavidch		BCE_PRINTF("%s(%d): Invalid manufacturing information "
3014207411Sdavidch		    "NVRAM CRC!	Expected: 0x%08X, Found: 0x%08X\n",
3015207411Sdavidch		    __FILE__, __LINE__, BCE_CRC32_RESIDUAL, csum);
3016179771Sdavidch		goto bce_nvram_test_exit;
3017157642Sps	}
3018157642Sps
3019157642Sps	csum = ether_crc32_le(data + 0x100, 0x100);
3020157642Sps	if (csum != BCE_CRC32_RESIDUAL) {
3021179771Sdavidch		rc = ENODEV;
3022207411Sdavidch		BCE_PRINTF("%s(%d): Invalid feature configuration "
3023207411Sdavidch		    "information NVRAM CRC! Expected: 0x%08X, "
3024207411Sdavidch		    "Found: 08%08X\n", __FILE__, __LINE__,
3025207411Sdavidch		    BCE_CRC32_RESIDUAL, csum);
3026157642Sps	}
3027157642Sps
3028179771Sdavidchbce_nvram_test_exit:
3029179771Sdavidch	DBEXIT(BCE_VERBOSE_NVRAM | BCE_VERBOSE_LOAD | BCE_VERBOSE_RESET);
3030157642Sps	return rc;
3031157642Sps}
3032157642Sps
3033157642Sps
3034157642Sps/****************************************************************************/
3035218423Sdavidch/* Calculates the size of the buffers to allocate based on the MTU.         */
3036218423Sdavidch/*                                                                          */
3037218423Sdavidch/* Returns:                                                                 */
3038218423Sdavidch/*   Nothing.                                                               */
3039218423Sdavidch/****************************************************************************/
3040218423Sdavidchstatic void
3041218423Sdavidchbce_get_rx_buffer_sizes(struct bce_softc *sc, int mtu)
3042218423Sdavidch{
3043218423Sdavidch	DBENTER(BCE_VERBOSE_LOAD);
3044218423Sdavidch
3045218423Sdavidch	/* Use a single allocation type when header splitting enabled. */
3046218423Sdavidch	if (bce_hdr_split == TRUE) {
3047218423Sdavidch		sc->rx_bd_mbuf_alloc_size = MHLEN;
3048218423Sdavidch		/* Make sure offset is 16 byte aligned for hardware. */
3049218423Sdavidch		sc->rx_bd_mbuf_align_pad =
3050298433Spfg			roundup2(MSIZE - MHLEN, 16) - (MSIZE - MHLEN);
3051218423Sdavidch		sc->rx_bd_mbuf_data_len = sc->rx_bd_mbuf_alloc_size -
3052218423Sdavidch			sc->rx_bd_mbuf_align_pad;
3053218423Sdavidch	} else {
3054218423Sdavidch		if ((mtu + ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN +
3055218423Sdavidch		    ETHER_CRC_LEN) > MCLBYTES) {
3056218423Sdavidch			/* Setup for jumbo RX buffer allocations. */
3057218423Sdavidch			sc->rx_bd_mbuf_alloc_size = MJUM9BYTES;
3058218423Sdavidch			sc->rx_bd_mbuf_align_pad  =
3059218423Sdavidch				roundup2(MJUM9BYTES, 16) - MJUM9BYTES;
3060218423Sdavidch			sc->rx_bd_mbuf_data_len =
3061218423Sdavidch			    sc->rx_bd_mbuf_alloc_size -
3062218423Sdavidch			    sc->rx_bd_mbuf_align_pad;
3063218423Sdavidch		} else {
3064218423Sdavidch			/* Setup for standard RX buffer allocations. */
3065218423Sdavidch			sc->rx_bd_mbuf_alloc_size = MCLBYTES;
3066218423Sdavidch			sc->rx_bd_mbuf_align_pad  =
3067218423Sdavidch			    roundup2(MCLBYTES, 16) - MCLBYTES;
3068218423Sdavidch			sc->rx_bd_mbuf_data_len =
3069218423Sdavidch			    sc->rx_bd_mbuf_alloc_size -
3070218423Sdavidch			    sc->rx_bd_mbuf_align_pad;
3071218423Sdavidch		}
3072218423Sdavidch	}
3073218423Sdavidch
3074218423Sdavidch//	DBPRINT(sc, BCE_INFO_LOAD,
3075218423Sdavidch	DBPRINT(sc, BCE_WARN,
3076218423Sdavidch	   "%s(): rx_bd_mbuf_alloc_size = %d, rx_bd_mbuf_data_len = %d, "
3077218423Sdavidch	   "rx_bd_mbuf_align_pad = %d\n", __FUNCTION__,
3078218423Sdavidch	   sc->rx_bd_mbuf_alloc_size, sc->rx_bd_mbuf_data_len,
3079218423Sdavidch	   sc->rx_bd_mbuf_align_pad);
3080218423Sdavidch
3081218423Sdavidch	DBEXIT(BCE_VERBOSE_LOAD);
3082218423Sdavidch}
3083218423Sdavidch
3084218423Sdavidch/****************************************************************************/
3085179771Sdavidch/* Identifies the current media type of the controller and sets the PHY     */
3086179771Sdavidch/* address.                                                                 */
3087179771Sdavidch/*                                                                          */
3088179771Sdavidch/* Returns:                                                                 */
3089179771Sdavidch/*   Nothing.                                                               */
3090179771Sdavidch/****************************************************************************/
3091179771Sdavidchstatic void
3092179771Sdavidchbce_get_media(struct bce_softc *sc)
3093179771Sdavidch{
3094179771Sdavidch	u32 val;
3095179771Sdavidch
3096207411Sdavidch	DBENTER(BCE_VERBOSE_PHY);
3097179771Sdavidch
3098182293Sdavidch	/* Assume PHY address for copper controllers. */
3099179771Sdavidch	sc->bce_phy_addr = 1;
3100179771Sdavidch
3101179771Sdavidch	if (BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5709) {
3102179771Sdavidch 		u32 val = REG_RD(sc, BCE_MISC_DUAL_MEDIA_CTRL);
3103179771Sdavidch		u32 bond_id = val & BCE_MISC_DUAL_MEDIA_CTRL_BOND_ID;
3104179771Sdavidch		u32 strap;
3105179771Sdavidch
3106179771Sdavidch		/*
3107179771Sdavidch		 * The BCM5709S is software configurable
3108179771Sdavidch		 * for Copper or SerDes operation.
3109179771Sdavidch		 */
3110179771Sdavidch		if (bond_id == BCE_MISC_DUAL_MEDIA_CTRL_BOND_ID_C) {
3111206268Sdavidch			DBPRINT(sc, BCE_INFO_LOAD, "5709 bonded "
3112206268Sdavidch			    "for copper.\n");
3113179771Sdavidch			goto bce_get_media_exit;
3114179771Sdavidch		} else if (bond_id == BCE_MISC_DUAL_MEDIA_CTRL_BOND_ID_S) {
3115206268Sdavidch			DBPRINT(sc, BCE_INFO_LOAD, "5709 bonded "
3116206268Sdavidch			    "for dual media.\n");
3117179771Sdavidch			sc->bce_phy_flags |= BCE_PHY_SERDES_FLAG;
3118179771Sdavidch			goto bce_get_media_exit;
3119179771Sdavidch		}
3120179771Sdavidch
3121179771Sdavidch		if (val & BCE_MISC_DUAL_MEDIA_CTRL_STRAP_OVERRIDE)
3122207411Sdavidch			strap = (val &
3123206268Sdavidch			    BCE_MISC_DUAL_MEDIA_CTRL_PHY_CTRL) >> 21;
3124179771Sdavidch		else
3125207411Sdavidch			strap = (val &
3126206268Sdavidch			    BCE_MISC_DUAL_MEDIA_CTRL_PHY_CTRL_STRAP) >> 8;
3127179771Sdavidch
3128179771Sdavidch		if (pci_get_function(sc->bce_dev) == 0) {
3129179771Sdavidch			switch (strap) {
3130179771Sdavidch			case 0x4:
3131179771Sdavidch			case 0x5:
3132179771Sdavidch			case 0x6:
3133182293Sdavidch				DBPRINT(sc, BCE_INFO_LOAD,
3134206268Sdavidch				    "BCM5709 s/w configured for SerDes.\n");
3135179771Sdavidch				sc->bce_phy_flags |= BCE_PHY_SERDES_FLAG;
3136206268Sdavidch				break;
3137179771Sdavidch			default:
3138182293Sdavidch				DBPRINT(sc, BCE_INFO_LOAD,
3139206268Sdavidch				    "BCM5709 s/w configured for Copper.\n");
3140206268Sdavidch				break;
3141179771Sdavidch			}
3142179771Sdavidch		} else {
3143179771Sdavidch			switch (strap) {
3144179771Sdavidch			case 0x1:
3145179771Sdavidch			case 0x2:
3146179771Sdavidch			case 0x4:
3147182293Sdavidch				DBPRINT(sc, BCE_INFO_LOAD,
3148206268Sdavidch				    "BCM5709 s/w configured for SerDes.\n");
3149179771Sdavidch				sc->bce_phy_flags |= BCE_PHY_SERDES_FLAG;
3150206268Sdavidch				break;
3151179771Sdavidch			default:
3152182293Sdavidch				DBPRINT(sc, BCE_INFO_LOAD,
3153206268Sdavidch				    "BCM5709 s/w configured for Copper.\n");
3154206268Sdavidch				break;
3155179771Sdavidch			}
3156179771Sdavidch		}
3157179771Sdavidch
3158179771Sdavidch	} else if (BCE_CHIP_BOND_ID(sc) & BCE_CHIP_BOND_ID_SERDES_BIT)
3159179771Sdavidch		sc->bce_phy_flags |= BCE_PHY_SERDES_FLAG;
3160179771Sdavidch
3161185082Sdelphij	if (sc->bce_phy_flags & BCE_PHY_SERDES_FLAG) {
3162205300Sdavidch
3163179771Sdavidch		sc->bce_flags |= BCE_NO_WOL_FLAG;
3164205300Sdavidch
3165206268Sdavidch		if (BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5709)
3166206268Sdavidch			sc->bce_phy_flags |= BCE_PHY_IEEE_CLAUSE_45_FLAG;
3167206268Sdavidch
3168206268Sdavidch		if (BCE_CHIP_NUM(sc) != BCE_CHIP_NUM_5706) {
3169206268Sdavidch			/* 5708S/09S/16S use a separate PHY for SerDes. */
3170179771Sdavidch			sc->bce_phy_addr = 2;
3171205300Sdavidch
3172194781Sdavidch			val = bce_shmem_rd(sc, BCE_SHARED_HW_CFG_CONFIG);
3173179771Sdavidch			if (val & BCE_SHARED_HW_CFG_PHY_2_5G) {
3174207411Sdavidch				sc->bce_phy_flags |=
3175206268Sdavidch				    BCE_PHY_2_5G_CAPABLE_FLAG;
3176206268Sdavidch				DBPRINT(sc, BCE_INFO_LOAD, "Found 2.5Gb "
3177206268Sdavidch				    "capable adapter\n");
3178179771Sdavidch			}
3179206268Sdavidch		}
3180179771Sdavidch	} else if ((BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5706) ||
3181206268Sdavidch	    (BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5708))
3182179771Sdavidch		sc->bce_phy_flags |= BCE_PHY_CRC_FIX_FLAG;
3183179771Sdavidch
3184179771Sdavidchbce_get_media_exit:
3185182293Sdavidch	DBPRINT(sc, (BCE_INFO_LOAD | BCE_INFO_PHY),
3186179771Sdavidch		"Using PHY address %d.\n", sc->bce_phy_addr);
3187182293Sdavidch
3188207411Sdavidch	DBEXIT(BCE_VERBOSE_PHY);
3189179771Sdavidch}
3190179771Sdavidch
3191179771Sdavidch
3192179771Sdavidch/****************************************************************************/
3193205300Sdavidch/* Performs PHY initialization required before MII drivers access the       */
3194205300Sdavidch/* device.                                                                  */
3195205300Sdavidch/*                                                                          */
3196205300Sdavidch/* Returns:                                                                 */
3197205300Sdavidch/*   Nothing.                                                               */
3198205300Sdavidch/****************************************************************************/
3199205300Sdavidchstatic void
3200205300Sdavidchbce_init_media(struct bce_softc *sc)
3201205300Sdavidch{
3202235151Syongari	if ((sc->bce_phy_flags & (BCE_PHY_IEEE_CLAUSE_45_FLAG |
3203235151Syongari	    BCE_PHY_REMOTE_CAP_FLAG)) == BCE_PHY_IEEE_CLAUSE_45_FLAG) {
3204205300Sdavidch		/*
3205205300Sdavidch		 * Configure 5709S/5716S PHYs to use traditional IEEE
3206205300Sdavidch		 * Clause 22 method. Otherwise we have no way to attach
3207205300Sdavidch		 * the PHY in mii(4) layer. PHY specific configuration
3208205300Sdavidch		 * is done in mii layer.
3209205300Sdavidch		 */
3210205300Sdavidch
3211206268Sdavidch		/* Select auto-negotiation MMD of the PHY. */
3212206268Sdavidch		bce_miibus_write_reg(sc->bce_dev, sc->bce_phy_addr,
3213205300Sdavidch		    BRGPHY_BLOCK_ADDR, BRGPHY_BLOCK_ADDR_ADDR_EXT);
3214205300Sdavidch		bce_miibus_write_reg(sc->bce_dev, sc->bce_phy_addr,
3215205300Sdavidch		    BRGPHY_ADDR_EXT, BRGPHY_ADDR_EXT_AN_MMD);
3216205300Sdavidch
3217206268Sdavidch		/* Set IEEE0 block of AN MMD (assumed in brgphy(4) code). */
3218205300Sdavidch		bce_miibus_write_reg(sc->bce_dev, sc->bce_phy_addr,
3219205300Sdavidch		    BRGPHY_BLOCK_ADDR, BRGPHY_BLOCK_ADDR_COMBO_IEEE0);
3220205300Sdavidch	}
3221205300Sdavidch}
3222205300Sdavidch
3223205300Sdavidch
3224205300Sdavidch/****************************************************************************/
3225157642Sps/* Free any DMA memory owned by the driver.                                 */
3226157642Sps/*                                                                          */
3227157642Sps/* Scans through each data structre that requires DMA memory and frees      */
3228157642Sps/* the memory if allocated.                                                 */
3229157642Sps/*                                                                          */
3230157642Sps/* Returns:                                                                 */
3231157642Sps/*   Nothing.                                                               */
3232157642Sps/****************************************************************************/
3233157642Spsstatic void
3234157642Spsbce_dma_free(struct bce_softc *sc)
3235157642Sps{
3236157642Sps	int i;
3237157642Sps
3238179771Sdavidch	DBENTER(BCE_VERBOSE_RESET | BCE_VERBOSE_UNLOAD | BCE_VERBOSE_CTX);
3239157642Sps
3240179771Sdavidch	/* Free, unmap, and destroy the status block. */
3241267377Sjhb	if (sc->status_block_paddr != 0) {
3242267377Sjhb		bus_dmamap_unload(
3243267377Sjhb		    sc->status_tag,
3244267377Sjhb		    sc->status_map);
3245267377Sjhb		sc->status_block_paddr = 0;
3246267377Sjhb	}
3247267377Sjhb
3248176448Sdavidch	if (sc->status_block != NULL) {
3249157642Sps		bus_dmamem_free(
3250206268Sdavidch		   sc->status_tag,
3251157642Sps		    sc->status_block,
3252157642Sps		    sc->status_map);
3253176448Sdavidch		sc->status_block = NULL;
3254176448Sdavidch	}
3255157642Sps
3256176448Sdavidch	if (sc->status_tag != NULL) {
3257157642Sps		bus_dma_tag_destroy(sc->status_tag);
3258176448Sdavidch		sc->status_tag = NULL;
3259176448Sdavidch	}
3260157642Sps
3261157642Sps
3262179771Sdavidch	/* Free, unmap, and destroy the statistics block. */
3263267377Sjhb	if (sc->stats_block_paddr != 0) {
3264267377Sjhb		bus_dmamap_unload(
3265267377Sjhb		    sc->stats_tag,
3266267377Sjhb		    sc->stats_map);
3267267377Sjhb		sc->stats_block_paddr = 0;
3268267377Sjhb	}
3269267377Sjhb
3270176448Sdavidch	if (sc->stats_block != NULL) {
3271157642Sps		bus_dmamem_free(
3272206268Sdavidch		    sc->stats_tag,
3273157642Sps		    sc->stats_block,
3274157642Sps		    sc->stats_map);
3275176448Sdavidch		sc->stats_block = NULL;
3276176448Sdavidch	}
3277157642Sps
3278176448Sdavidch	if (sc->stats_tag != NULL) {
3279157642Sps		bus_dma_tag_destroy(sc->stats_tag);
3280176448Sdavidch		sc->stats_tag = NULL;
3281176448Sdavidch	}
3282157642Sps
3283157642Sps
3284179771Sdavidch	/* Free, unmap and destroy all context memory pages. */
3285226123Syongari	if (BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5709) {
3286179771Sdavidch		for (i = 0; i < sc->ctx_pages; i++ ) {
3287267377Sjhb			if (sc->ctx_paddr[i] != 0) {
3288267377Sjhb				bus_dmamap_unload(
3289267377Sjhb				    sc->ctx_tag,
3290267377Sjhb				    sc->ctx_map[i]);
3291267377Sjhb				sc->ctx_paddr[i] = 0;
3292267377Sjhb			}
3293267377Sjhb
3294179771Sdavidch			if (sc->ctx_block[i] != NULL) {
3295179771Sdavidch				bus_dmamem_free(
3296206268Sdavidch				    sc->ctx_tag,
3297179771Sdavidch				    sc->ctx_block[i],
3298179771Sdavidch				    sc->ctx_map[i]);
3299179771Sdavidch				sc->ctx_block[i] = NULL;
3300179771Sdavidch			}
3301179771Sdavidch		}
3302179771Sdavidch
3303179771Sdavidch		/* Destroy the context memory tag. */
3304179771Sdavidch		if (sc->ctx_tag != NULL) {
3305179771Sdavidch			bus_dma_tag_destroy(sc->ctx_tag);
3306179771Sdavidch			sc->ctx_tag = NULL;
3307179771Sdavidch		}
3308179771Sdavidch	}
3309179771Sdavidch
3310179771Sdavidch
3311157642Sps	/* Free, unmap and destroy all TX buffer descriptor chain pages. */
3312218423Sdavidch	for (i = 0; i < sc->tx_pages; i++ ) {
3313267377Sjhb		if (sc->tx_bd_chain_paddr[i] != 0) {
3314267377Sjhb			bus_dmamap_unload(
3315267377Sjhb			    sc->tx_bd_chain_tag,
3316267377Sjhb			    sc->tx_bd_chain_map[i]);
3317267377Sjhb			sc->tx_bd_chain_paddr[i] = 0;
3318267377Sjhb		}
3319267377Sjhb
3320176448Sdavidch		if (sc->tx_bd_chain[i] != NULL) {
3321157642Sps			bus_dmamem_free(
3322206268Sdavidch			    sc->tx_bd_chain_tag,
3323157642Sps			    sc->tx_bd_chain[i],
3324157642Sps			    sc->tx_bd_chain_map[i]);
3325176448Sdavidch			sc->tx_bd_chain[i] = NULL;
3326176448Sdavidch		}
3327157642Sps	}
3328157642Sps
3329157642Sps	/* Destroy the TX buffer descriptor tag. */
3330176448Sdavidch	if (sc->tx_bd_chain_tag != NULL) {
3331157642Sps		bus_dma_tag_destroy(sc->tx_bd_chain_tag);
3332176448Sdavidch		sc->tx_bd_chain_tag = NULL;
3333176448Sdavidch	}
3334157642Sps
3335157642Sps
3336157642Sps	/* Free, unmap and destroy all RX buffer descriptor chain pages. */
3337218423Sdavidch	for (i = 0; i < sc->rx_pages; i++ ) {
3338267377Sjhb		if (sc->rx_bd_chain_paddr[i] != 0) {
3339267377Sjhb			bus_dmamap_unload(
3340267377Sjhb			    sc->rx_bd_chain_tag,
3341267377Sjhb			    sc->rx_bd_chain_map[i]);
3342267377Sjhb			sc->rx_bd_chain_paddr[i] = 0;
3343267377Sjhb		}
3344267377Sjhb
3345176448Sdavidch		if (sc->rx_bd_chain[i] != NULL) {
3346157642Sps			bus_dmamem_free(
3347206268Sdavidch			    sc->rx_bd_chain_tag,
3348157642Sps			    sc->rx_bd_chain[i],
3349157642Sps			    sc->rx_bd_chain_map[i]);
3350176448Sdavidch			sc->rx_bd_chain[i] = NULL;
3351176448Sdavidch		}
3352157642Sps	}
3353157642Sps
3354157642Sps	/* Destroy the RX buffer descriptor tag. */
3355176448Sdavidch	if (sc->rx_bd_chain_tag != NULL) {
3356157642Sps		bus_dma_tag_destroy(sc->rx_bd_chain_tag);
3357176448Sdavidch		sc->rx_bd_chain_tag = NULL;
3358176448Sdavidch	}
3359157642Sps
3360157642Sps
3361176448Sdavidch	/* Free, unmap and destroy all page buffer descriptor chain pages. */
3362218423Sdavidch	if (bce_hdr_split == TRUE) {
3363218423Sdavidch		for (i = 0; i < sc->pg_pages; i++ ) {
3364267377Sjhb			if (sc->pg_bd_chain_paddr[i] != 0) {
3365267377Sjhb				bus_dmamap_unload(
3366267377Sjhb				    sc->pg_bd_chain_tag,
3367267377Sjhb				    sc->pg_bd_chain_map[i]);
3368267377Sjhb				sc->pg_bd_chain_paddr[i] = 0;
3369267377Sjhb			}
3370267377Sjhb
3371218423Sdavidch			if (sc->pg_bd_chain[i] != NULL) {
3372218423Sdavidch				bus_dmamem_free(
3373218423Sdavidch				    sc->pg_bd_chain_tag,
3374218423Sdavidch				    sc->pg_bd_chain[i],
3375218423Sdavidch				    sc->pg_bd_chain_map[i]);
3376218423Sdavidch				sc->pg_bd_chain[i] = NULL;
3377218423Sdavidch			}
3378176448Sdavidch		}
3379176448Sdavidch
3380218423Sdavidch		/* Destroy the page buffer descriptor tag. */
3381218423Sdavidch		if (sc->pg_bd_chain_tag != NULL) {
3382218423Sdavidch			bus_dma_tag_destroy(sc->pg_bd_chain_tag);
3383218423Sdavidch			sc->pg_bd_chain_tag = NULL;
3384176448Sdavidch		}
3385176448Sdavidch	}
3386176448Sdavidch
3387176448Sdavidch
3388157642Sps	/* Unload and destroy the TX mbuf maps. */
3389218423Sdavidch	for (i = 0; i < MAX_TX_BD_AVAIL; i++) {
3390157642Sps		if (sc->tx_mbuf_map[i] != NULL) {
3391179771Sdavidch			bus_dmamap_unload(sc->tx_mbuf_tag,
3392206268Sdavidch			    sc->tx_mbuf_map[i]);
3393179771Sdavidch			bus_dmamap_destroy(sc->tx_mbuf_tag,
3394206268Sdavidch	 		    sc->tx_mbuf_map[i]);
3395176448Sdavidch			sc->tx_mbuf_map[i] = NULL;
3396157642Sps		}
3397157642Sps	}
3398157642Sps
3399157642Sps	/* Destroy the TX mbuf tag. */
3400176448Sdavidch	if (sc->tx_mbuf_tag != NULL) {
3401157642Sps		bus_dma_tag_destroy(sc->tx_mbuf_tag);
3402176448Sdavidch		sc->tx_mbuf_tag = NULL;
3403176448Sdavidch	}
3404157642Sps
3405157642Sps	/* Unload and destroy the RX mbuf maps. */
3406218423Sdavidch	for (i = 0; i < MAX_RX_BD_AVAIL; i++) {
3407157642Sps		if (sc->rx_mbuf_map[i] != NULL) {
3408179771Sdavidch			bus_dmamap_unload(sc->rx_mbuf_tag,
3409206268Sdavidch			    sc->rx_mbuf_map[i]);
3410179771Sdavidch			bus_dmamap_destroy(sc->rx_mbuf_tag,
3411206268Sdavidch	 		    sc->rx_mbuf_map[i]);
3412176448Sdavidch			sc->rx_mbuf_map[i] = NULL;
3413157642Sps		}
3414157642Sps	}
3415157642Sps
3416157642Sps	/* Destroy the RX mbuf tag. */
3417176448Sdavidch	if (sc->rx_mbuf_tag != NULL) {
3418157642Sps		bus_dma_tag_destroy(sc->rx_mbuf_tag);
3419176448Sdavidch		sc->rx_mbuf_tag = NULL;
3420176448Sdavidch	}
3421157642Sps
3422176448Sdavidch	/* Unload and destroy the page mbuf maps. */
3423218423Sdavidch	if (bce_hdr_split == TRUE) {
3424218423Sdavidch		for (i = 0; i < MAX_PG_BD_AVAIL; i++) {
3425218423Sdavidch			if (sc->pg_mbuf_map[i] != NULL) {
3426218423Sdavidch				bus_dmamap_unload(sc->pg_mbuf_tag,
3427218423Sdavidch				    sc->pg_mbuf_map[i]);
3428218423Sdavidch				bus_dmamap_destroy(sc->pg_mbuf_tag,
3429218423Sdavidch				    sc->pg_mbuf_map[i]);
3430218423Sdavidch				sc->pg_mbuf_map[i] = NULL;
3431218423Sdavidch			}
3432176448Sdavidch		}
3433157642Sps
3434218423Sdavidch		/* Destroy the page mbuf tag. */
3435218423Sdavidch		if (sc->pg_mbuf_tag != NULL) {
3436218423Sdavidch			bus_dma_tag_destroy(sc->pg_mbuf_tag);
3437218423Sdavidch			sc->pg_mbuf_tag = NULL;
3438218423Sdavidch		}
3439176448Sdavidch	}
3440176448Sdavidch
3441157642Sps	/* Destroy the parent tag */
3442176448Sdavidch	if (sc->parent_tag != NULL) {
3443157642Sps		bus_dma_tag_destroy(sc->parent_tag);
3444176448Sdavidch		sc->parent_tag = NULL;
3445176448Sdavidch	}
3446157642Sps
3447179771Sdavidch	DBEXIT(BCE_VERBOSE_RESET | BCE_VERBOSE_UNLOAD | BCE_VERBOSE_CTX);
3448157642Sps}
3449157642Sps
3450157642Sps
3451157642Sps/****************************************************************************/
3452157642Sps/* Get DMA memory from the OS.                                              */
3453157642Sps/*                                                                          */
3454157642Sps/* Validates that the OS has provided DMA buffers in response to a          */
3455157642Sps/* bus_dmamap_load() call and saves the physical address of those buffers.  */
3456157642Sps/* When the callback is used the OS will return 0 for the mapping function  */
3457157642Sps/* (bus_dmamap_load()) so we use the value of map_arg->maxsegs to pass any  */
3458157642Sps/* failures back to the caller.                                             */
3459157642Sps/*                                                                          */
3460157642Sps/* Returns:                                                                 */
3461157642Sps/*   Nothing.                                                               */
3462157642Sps/****************************************************************************/
3463157642Spsstatic void
3464157642Spsbce_dma_map_addr(void *arg, bus_dma_segment_t *segs, int nseg, int error)
3465157642Sps{
3466163393Sscottl	bus_addr_t *busaddr = arg;
3467157642Sps
3468210267Syongari	KASSERT(nseg == 1, ("%s(): Too many segments returned (%d)!",
3469210267Syongari	    __FUNCTION__, nseg));
3470157642Sps	/* Simulate a mapping failure. */
3471189325Sdavidch	DBRUNIF(DB_RANDOMTRUE(dma_map_addr_failed_sim_control),
3472207411Sdavidch	    error = ENOMEM);
3473179771Sdavidch
3474207411Sdavidch	/* ToDo: How to increment debug sim_count variable here? */
3475207411Sdavidch
3476157642Sps	/* Check for an error and signal the caller that an error occurred. */
3477157642Sps	if (error) {
3478163393Sscottl		*busaddr = 0;
3479189325Sdavidch	} else {
3480189325Sdavidch		*busaddr = segs->ds_addr;
3481157642Sps	}
3482157642Sps}
3483157642Sps
3484157642Sps
3485157642Sps/****************************************************************************/
3486157642Sps/* Allocate any DMA memory needed by the driver.                            */
3487157642Sps/*                                                                          */
3488157642Sps/* Allocates DMA memory needed for the various global structures needed by  */
3489182293Sdavidch/* hardware.                                                                */
3490157642Sps/*                                                                          */
3491182293Sdavidch/* Memory alignment requirements:                                           */
3492182293Sdavidch/* +-----------------+----------+----------+----------+----------+          */
3493182293Sdavidch/* |                 |   5706   |   5708   |   5709   |   5716   |          */
3494182293Sdavidch/* +-----------------+----------+----------+----------+----------+          */
3495182293Sdavidch/* |Status Block     | 8 bytes  | 8 bytes  | 16 bytes | 16 bytes |          */
3496182293Sdavidch/* |Statistics Block | 8 bytes  | 8 bytes  | 16 bytes | 16 bytes |          */
3497182293Sdavidch/* |RX Buffers       | 16 bytes | 16 bytes | 16 bytes | 16 bytes |          */
3498182293Sdavidch/* |PG Buffers       |   none   |   none   |   none   |   none   |          */
3499182293Sdavidch/* |TX Buffers       |   none   |   none   |   none   |   none   |          */
3500182293Sdavidch/* |Chain Pages(1)   |   4KiB   |   4KiB   |   4KiB   |   4KiB   |          */
3501202717Sdavidch/* |Context Memory   |          |          |          |          |          */
3502182293Sdavidch/* +-----------------+----------+----------+----------+----------+          */
3503182293Sdavidch/*                                                                          */
3504182293Sdavidch/* (1) Must align with CPU page size (BCM_PAGE_SZIE).                       */
3505182293Sdavidch/*                                                                          */
3506157642Sps/* Returns:                                                                 */
3507157642Sps/*   0 for success, positive value for failure.                             */
3508157642Sps/****************************************************************************/
3509157642Spsstatic int
3510157642Spsbce_dma_alloc(device_t dev)
3511157642Sps{
3512157642Sps	struct bce_softc *sc;
3513157642Sps	int i, error, rc = 0;
3514170392Sdavidch	bus_size_t max_size, max_seg_size;
3515170392Sdavidch	int max_segments;
3516157642Sps
3517157642Sps	sc = device_get_softc(dev);
3518157642Sps
3519179771Sdavidch	DBENTER(BCE_VERBOSE_RESET | BCE_VERBOSE_CTX);
3520179771Sdavidch
3521157642Sps	/*
3522157642Sps	 * Allocate the parent bus DMA tag appropriate for PCI.
3523157642Sps	 */
3524210269Syongari	if (bus_dma_tag_create(bus_get_dma_tag(dev), 1, BCE_DMA_BOUNDARY,
3525206268Sdavidch	    sc->max_bus_addr, BUS_SPACE_MAXADDR, NULL, NULL,
3526210269Syongari	    BUS_SPACE_MAXSIZE_32BIT, 0, BUS_SPACE_MAXSIZE_32BIT, 0, NULL, NULL,
3527210269Syongari	    &sc->parent_tag)) {
3528169271Sdavidch		BCE_PRINTF("%s(%d): Could not allocate parent DMA tag!\n",
3529206268Sdavidch		    __FILE__, __LINE__);
3530157642Sps		rc = ENOMEM;
3531157642Sps		goto bce_dma_alloc_exit;
3532157642Sps	}
3533157642Sps
3534157642Sps	/*
3535157642Sps	 * Create a DMA tag for the status block, allocate and clear the
3536179771Sdavidch	 * memory, map the memory into DMA space, and fetch the physical
3537157642Sps	 * address of the block.
3538157642Sps	 */
3539206268Sdavidch	if (bus_dma_tag_create(sc->parent_tag, BCE_DMA_ALIGN,
3540206268Sdavidch	    BCE_DMA_BOUNDARY, sc->max_bus_addr,	BUS_SPACE_MAXADDR,
3541206268Sdavidch	    NULL, NULL,	BCE_STATUS_BLK_SZ, 1, BCE_STATUS_BLK_SZ,
3542206268Sdavidch	    0, NULL, NULL, &sc->status_tag)) {
3543206268Sdavidch		BCE_PRINTF("%s(%d): Could not allocate status block "
3544206268Sdavidch		    "DMA tag!\n", __FILE__, __LINE__);
3545157642Sps		rc = ENOMEM;
3546157642Sps		goto bce_dma_alloc_exit;
3547157642Sps	}
3548157642Sps
3549206268Sdavidch	if(bus_dmamem_alloc(sc->status_tag, (void **)&sc->status_block,
3550210270Syongari	    BUS_DMA_NOWAIT | BUS_DMA_ZERO | BUS_DMA_COHERENT,
3551210270Syongari	    &sc->status_map)) {
3552206268Sdavidch		BCE_PRINTF("%s(%d): Could not allocate status block "
3553206268Sdavidch		    "DMA memory!\n", __FILE__, __LINE__);
3554157642Sps		rc = ENOMEM;
3555157642Sps		goto bce_dma_alloc_exit;
3556157642Sps	}
3557157642Sps
3558206268Sdavidch	error = bus_dmamap_load(sc->status_tag,	sc->status_map,
3559206268Sdavidch	    sc->status_block, BCE_STATUS_BLK_SZ, bce_dma_map_addr,
3560206268Sdavidch	    &sc->status_block_paddr, BUS_DMA_NOWAIT);
3561179771Sdavidch
3562251146Smarius	if (error || sc->status_block_paddr == 0) {
3563206268Sdavidch		BCE_PRINTF("%s(%d): Could not map status block "
3564206268Sdavidch		    "DMA memory!\n", __FILE__, __LINE__);
3565157642Sps		rc = ENOMEM;
3566157642Sps		goto bce_dma_alloc_exit;
3567157642Sps	}
3568157642Sps
3569207411Sdavidch	DBPRINT(sc, BCE_INFO_LOAD, "%s(): status_block_paddr = 0x%jX\n",
3570206268Sdavidch	    __FUNCTION__, (uintmax_t) sc->status_block_paddr);
3571157642Sps
3572157642Sps	/*
3573157642Sps	 * Create a DMA tag for the statistics block, allocate and clear the
3574179771Sdavidch	 * memory, map the memory into DMA space, and fetch the physical
3575157642Sps	 * address of the block.
3576157642Sps	 */
3577206268Sdavidch	if (bus_dma_tag_create(sc->parent_tag, BCE_DMA_ALIGN,
3578206268Sdavidch	    BCE_DMA_BOUNDARY, sc->max_bus_addr,	BUS_SPACE_MAXADDR,
3579206268Sdavidch	    NULL, NULL,	BCE_STATS_BLK_SZ, 1, BCE_STATS_BLK_SZ,
3580206268Sdavidch	    0, NULL, NULL, &sc->stats_tag)) {
3581206268Sdavidch		BCE_PRINTF("%s(%d): Could not allocate statistics block "
3582206268Sdavidch		    "DMA tag!\n", __FILE__, __LINE__);
3583157642Sps		rc = ENOMEM;
3584157642Sps		goto bce_dma_alloc_exit;
3585157642Sps	}
3586157642Sps
3587206268Sdavidch	if (bus_dmamem_alloc(sc->stats_tag, (void **)&sc->stats_block,
3588210270Syongari	    BUS_DMA_NOWAIT | BUS_DMA_ZERO | BUS_DMA_COHERENT, &sc->stats_map)) {
3589206268Sdavidch		BCE_PRINTF("%s(%d): Could not allocate statistics block "
3590206268Sdavidch		    "DMA memory!\n", __FILE__, __LINE__);
3591157642Sps		rc = ENOMEM;
3592157642Sps		goto bce_dma_alloc_exit;
3593157642Sps	}
3594157642Sps
3595206268Sdavidch	error = bus_dmamap_load(sc->stats_tag, sc->stats_map,
3596206268Sdavidch	    sc->stats_block, BCE_STATS_BLK_SZ, bce_dma_map_addr,
3597206268Sdavidch	    &sc->stats_block_paddr, BUS_DMA_NOWAIT);
3598157642Sps
3599251146Smarius	if (error || sc->stats_block_paddr == 0) {
3600206268Sdavidch		BCE_PRINTF("%s(%d): Could not map statistics block "
3601206268Sdavidch		    "DMA memory!\n", __FILE__, __LINE__);
3602157642Sps		rc = ENOMEM;
3603157642Sps		goto bce_dma_alloc_exit;
3604157642Sps	}
3605157642Sps
3606207411Sdavidch	DBPRINT(sc, BCE_INFO_LOAD, "%s(): stats_block_paddr = 0x%jX\n",
3607206268Sdavidch	    __FUNCTION__, (uintmax_t) sc->stats_block_paddr);
3608157642Sps
3609179771Sdavidch	/* BCM5709 uses host memory as cache for context memory. */
3610226123Syongari	if (BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5709) {
3611179771Sdavidch		sc->ctx_pages = 0x2000 / BCM_PAGE_SIZE;
3612179771Sdavidch		if (sc->ctx_pages == 0)
3613179771Sdavidch			sc->ctx_pages = 1;
3614179771Sdavidch
3615179771Sdavidch		DBRUNIF((sc->ctx_pages > 512),
3616206268Sdavidch		    BCE_PRINTF("%s(%d): Too many CTX pages! %d > 512\n",
3617206268Sdavidch		    __FILE__, __LINE__, sc->ctx_pages));
3618179771Sdavidch
3619179771Sdavidch		/*
3620179771Sdavidch		 * Create a DMA tag for the context pages,
3621179771Sdavidch		 * allocate and clear the memory, map the
3622179771Sdavidch		 * memory into DMA space, and fetch the
3623179771Sdavidch		 * physical address of the block.
3624179771Sdavidch		 */
3625206268Sdavidch		if(bus_dma_tag_create(sc->parent_tag, BCM_PAGE_SIZE,
3626206268Sdavidch		    BCE_DMA_BOUNDARY, sc->max_bus_addr,	BUS_SPACE_MAXADDR,
3627206268Sdavidch		    NULL, NULL,	BCM_PAGE_SIZE, 1, BCM_PAGE_SIZE,
3628206268Sdavidch		    0, NULL, NULL, &sc->ctx_tag)) {
3629207411Sdavidch			BCE_PRINTF("%s(%d): Could not allocate CTX "
3630207411Sdavidch			    "DMA tag!\n", __FILE__, __LINE__);
3631179771Sdavidch			rc = ENOMEM;
3632179771Sdavidch			goto bce_dma_alloc_exit;
3633179771Sdavidch		}
3634179771Sdavidch
3635179771Sdavidch		for (i = 0; i < sc->ctx_pages; i++) {
3636179771Sdavidch
3637179771Sdavidch			if(bus_dmamem_alloc(sc->ctx_tag,
3638206268Sdavidch			    (void **)&sc->ctx_block[i],
3639210270Syongari			    BUS_DMA_NOWAIT | BUS_DMA_ZERO | BUS_DMA_COHERENT,
3640206268Sdavidch			    &sc->ctx_map[i])) {
3641179771Sdavidch				BCE_PRINTF("%s(%d): Could not allocate CTX "
3642206268Sdavidch				    "DMA memory!\n", __FILE__, __LINE__);
3643179771Sdavidch				rc = ENOMEM;
3644179771Sdavidch				goto bce_dma_alloc_exit;
3645179771Sdavidch			}
3646179771Sdavidch
3647206268Sdavidch			error = bus_dmamap_load(sc->ctx_tag, sc->ctx_map[i],
3648206268Sdavidch			    sc->ctx_block[i], BCM_PAGE_SIZE, bce_dma_map_addr,
3649206268Sdavidch			    &sc->ctx_paddr[i], BUS_DMA_NOWAIT);
3650179771Sdavidch
3651251146Smarius			if (error || sc->ctx_paddr[i] == 0) {
3652206268Sdavidch				BCE_PRINTF("%s(%d): Could not map CTX "
3653206268Sdavidch				    "DMA memory!\n", __FILE__, __LINE__);
3654179771Sdavidch				rc = ENOMEM;
3655179771Sdavidch				goto bce_dma_alloc_exit;
3656179771Sdavidch			}
3657179771Sdavidch
3658207411Sdavidch			DBPRINT(sc, BCE_INFO_LOAD, "%s(): ctx_paddr[%d] "
3659207411Sdavidch			    "= 0x%jX\n", __FUNCTION__, i,
3660207411Sdavidch			    (uintmax_t) sc->ctx_paddr[i]);
3661179771Sdavidch		}
3662179771Sdavidch	}
3663179771Sdavidch
3664157642Sps	/*
3665157642Sps	 * Create a DMA tag for the TX buffer descriptor chain,
3666157642Sps	 * allocate and clear the  memory, and fetch the
3667157642Sps	 * physical address of the block.
3668157642Sps	 */
3669206268Sdavidch	if(bus_dma_tag_create(sc->parent_tag, BCM_PAGE_SIZE, BCE_DMA_BOUNDARY,
3670206268Sdavidch	    sc->max_bus_addr, BUS_SPACE_MAXADDR, NULL, NULL,
3671206268Sdavidch	    BCE_TX_CHAIN_PAGE_SZ, 1, BCE_TX_CHAIN_PAGE_SZ, 0,
3672206268Sdavidch	    NULL, NULL,	&sc->tx_bd_chain_tag)) {
3673207411Sdavidch		BCE_PRINTF("%s(%d): Could not allocate TX descriptor "
3674207411Sdavidch		    "chain DMA tag!\n", __FILE__, __LINE__);
3675157642Sps		rc = ENOMEM;
3676157642Sps		goto bce_dma_alloc_exit;
3677157642Sps	}
3678157642Sps
3679218423Sdavidch	for (i = 0; i < sc->tx_pages; i++) {
3680157642Sps
3681207411Sdavidch		if(bus_dmamem_alloc(sc->tx_bd_chain_tag,
3682210270Syongari		    (void **)&sc->tx_bd_chain[i],
3683210270Syongari		    BUS_DMA_NOWAIT | BUS_DMA_ZERO | BUS_DMA_COHERENT,
3684206268Sdavidch		    &sc->tx_bd_chain_map[i])) {
3685169271Sdavidch			BCE_PRINTF("%s(%d): Could not allocate TX descriptor "
3686206268Sdavidch			    "chain DMA memory!\n", __FILE__, __LINE__);
3687157642Sps			rc = ENOMEM;
3688157642Sps			goto bce_dma_alloc_exit;
3689157642Sps		}
3690157642Sps
3691169632Sdavidch		error = bus_dmamap_load(sc->tx_bd_chain_tag,
3692206268Sdavidch		    sc->tx_bd_chain_map[i], sc->tx_bd_chain[i],
3693206268Sdavidch		    BCE_TX_CHAIN_PAGE_SZ, bce_dma_map_addr,
3694206268Sdavidch		    &sc->tx_bd_chain_paddr[i], BUS_DMA_NOWAIT);
3695157642Sps
3696251146Smarius		if (error || sc->tx_bd_chain_paddr[i] == 0) {
3697206268Sdavidch			BCE_PRINTF("%s(%d): Could not map TX descriptor "
3698206268Sdavidch			    "chain DMA memory!\n", __FILE__, __LINE__);
3699157642Sps			rc = ENOMEM;
3700157642Sps			goto bce_dma_alloc_exit;
3701157642Sps		}
3702157642Sps
3703207411Sdavidch		DBPRINT(sc, BCE_INFO_LOAD, "%s(): tx_bd_chain_paddr[%d] = "
3704207411Sdavidch		    "0x%jX\n", __FUNCTION__, i,
3705207411Sdavidch		    (uintmax_t) sc->tx_bd_chain_paddr[i]);
3706157642Sps	}
3707170392Sdavidch
3708170392Sdavidch	/* Check the required size before mapping to conserve resources. */
3709170392Sdavidch	if (bce_tso_enable) {
3710170392Sdavidch		max_size     = BCE_TSO_MAX_SIZE;
3711170392Sdavidch		max_segments = BCE_MAX_SEGMENTS;
3712170392Sdavidch		max_seg_size = BCE_TSO_MAX_SEG_SIZE;
3713170392Sdavidch	} else {
3714170392Sdavidch		max_size     = MCLBYTES * BCE_MAX_SEGMENTS;
3715170392Sdavidch		max_segments = BCE_MAX_SEGMENTS;
3716170392Sdavidch		max_seg_size = MCLBYTES;
3717170392Sdavidch	}
3718179771Sdavidch
3719157642Sps	/* Create a DMA tag for TX mbufs. */
3720206268Sdavidch	if (bus_dma_tag_create(sc->parent_tag, 1, BCE_DMA_BOUNDARY,
3721206268Sdavidch	    sc->max_bus_addr, BUS_SPACE_MAXADDR, NULL, NULL, max_size,
3722206268Sdavidch	    max_segments, max_seg_size,	0, NULL, NULL, &sc->tx_mbuf_tag)) {
3723169271Sdavidch		BCE_PRINTF("%s(%d): Could not allocate TX mbuf DMA tag!\n",
3724206268Sdavidch		    __FILE__, __LINE__);
3725157642Sps		rc = ENOMEM;
3726157642Sps		goto bce_dma_alloc_exit;
3727157642Sps	}
3728157642Sps
3729157642Sps	/* Create DMA maps for the TX mbufs clusters. */
3730218423Sdavidch	for (i = 0; i < TOTAL_TX_BD_ALLOC; i++) {
3731179771Sdavidch		if (bus_dmamap_create(sc->tx_mbuf_tag, BUS_DMA_NOWAIT,
3732157642Sps			&sc->tx_mbuf_map[i])) {
3733206268Sdavidch			BCE_PRINTF("%s(%d): Unable to create TX mbuf DMA "
3734206268Sdavidch			    "map!\n", __FILE__, __LINE__);
3735157642Sps			rc = ENOMEM;
3736157642Sps			goto bce_dma_alloc_exit;
3737157642Sps		}
3738157642Sps	}
3739157642Sps
3740157642Sps	/*
3741157642Sps	 * Create a DMA tag for the RX buffer descriptor chain,
3742176448Sdavidch	 * allocate and clear the memory, and fetch the physical
3743157642Sps	 * address of the blocks.
3744157642Sps	 */
3745206268Sdavidch	if (bus_dma_tag_create(sc->parent_tag, BCM_PAGE_SIZE,
3746206268Sdavidch			BCE_DMA_BOUNDARY, BUS_SPACE_MAXADDR,
3747206268Sdavidch			sc->max_bus_addr, NULL, NULL,
3748206268Sdavidch			BCE_RX_CHAIN_PAGE_SZ, 1, BCE_RX_CHAIN_PAGE_SZ,
3749206268Sdavidch			0, NULL, NULL, &sc->rx_bd_chain_tag)) {
3750206268Sdavidch		BCE_PRINTF("%s(%d): Could not allocate RX descriptor chain "
3751206268Sdavidch		    "DMA tag!\n", __FILE__, __LINE__);
3752157642Sps		rc = ENOMEM;
3753157642Sps		goto bce_dma_alloc_exit;
3754157642Sps	}
3755157642Sps
3756218423Sdavidch	for (i = 0; i < sc->rx_pages; i++) {
3757157642Sps
3758169632Sdavidch		if (bus_dmamem_alloc(sc->rx_bd_chain_tag,
3759210270Syongari		    (void **)&sc->rx_bd_chain[i],
3760210270Syongari		    BUS_DMA_NOWAIT | BUS_DMA_ZERO | BUS_DMA_COHERENT,
3761206268Sdavidch		    &sc->rx_bd_chain_map[i])) {
3762206268Sdavidch			BCE_PRINTF("%s(%d): Could not allocate RX descriptor "
3763206268Sdavidch			    "chain DMA memory!\n", __FILE__, __LINE__);
3764157642Sps			rc = ENOMEM;
3765157642Sps			goto bce_dma_alloc_exit;
3766157642Sps		}
3767157642Sps
3768169632Sdavidch		error = bus_dmamap_load(sc->rx_bd_chain_tag,
3769206268Sdavidch		    sc->rx_bd_chain_map[i], sc->rx_bd_chain[i],
3770206268Sdavidch		    BCE_RX_CHAIN_PAGE_SZ, bce_dma_map_addr,
3771206268Sdavidch		    &sc->rx_bd_chain_paddr[i], BUS_DMA_NOWAIT);
3772157642Sps
3773251146Smarius		if (error || sc->rx_bd_chain_paddr[i] == 0) {
3774206268Sdavidch			BCE_PRINTF("%s(%d): Could not map RX descriptor "
3775206268Sdavidch			    "chain DMA memory!\n", __FILE__, __LINE__);
3776157642Sps			rc = ENOMEM;
3777157642Sps			goto bce_dma_alloc_exit;
3778157642Sps		}
3779157642Sps
3780207411Sdavidch		DBPRINT(sc, BCE_INFO_LOAD, "%s(): rx_bd_chain_paddr[%d] = "
3781207411Sdavidch		    "0x%jX\n", __FUNCTION__, i,
3782207411Sdavidch		    (uintmax_t) sc->rx_bd_chain_paddr[i]);
3783157642Sps	}
3784157642Sps
3785157642Sps	/*
3786157642Sps	 * Create a DMA tag for RX mbufs.
3787178132Sdavidch	 */
3788218423Sdavidch	if (bce_hdr_split == TRUE)
3789251142Smarius		max_size = ((sc->rx_bd_mbuf_alloc_size < MCLBYTES) ?
3790218423Sdavidch		    MCLBYTES : sc->rx_bd_mbuf_alloc_size);
3791218423Sdavidch	else
3792251142Smarius		max_size = MJUM9BYTES;
3793176448Sdavidch
3794207411Sdavidch	DBPRINT(sc, BCE_INFO_LOAD, "%s(): Creating rx_mbuf_tag "
3795251142Smarius	    "(max size = 0x%jX)\n", __FUNCTION__, (uintmax_t)max_size);
3796189325Sdavidch
3797210271Syongari	if (bus_dma_tag_create(sc->parent_tag, BCE_RX_BUF_ALIGN,
3798210270Syongari	    BCE_DMA_BOUNDARY, sc->max_bus_addr, BUS_SPACE_MAXADDR, NULL, NULL,
3799251142Smarius	    max_size, 1, max_size, 0, NULL, NULL, &sc->rx_mbuf_tag)) {
3800169271Sdavidch		BCE_PRINTF("%s(%d): Could not allocate RX mbuf DMA tag!\n",
3801206268Sdavidch		    __FILE__, __LINE__);
3802157642Sps		rc = ENOMEM;
3803157642Sps		goto bce_dma_alloc_exit;
3804157642Sps	}
3805157642Sps
3806157642Sps	/* Create DMA maps for the RX mbuf clusters. */
3807218423Sdavidch	for (i = 0; i < TOTAL_RX_BD_ALLOC; i++) {
3808157642Sps		if (bus_dmamap_create(sc->rx_mbuf_tag, BUS_DMA_NOWAIT,
3809206268Sdavidch		    &sc->rx_mbuf_map[i])) {
3810206268Sdavidch			BCE_PRINTF("%s(%d): Unable to create RX mbuf "
3811206268Sdavidch			    "DMA map!\n", __FILE__, __LINE__);
3812157642Sps			rc = ENOMEM;
3813157642Sps			goto bce_dma_alloc_exit;
3814157642Sps		}
3815157642Sps	}
3816157642Sps
3817218423Sdavidch	if (bce_hdr_split == TRUE) {
3818218423Sdavidch		/*
3819218423Sdavidch		 * Create a DMA tag for the page buffer descriptor chain,
3820218423Sdavidch		 * allocate and clear the memory, and fetch the physical
3821218423Sdavidch		 * address of the blocks.
3822218423Sdavidch		 */
3823218423Sdavidch		if (bus_dma_tag_create(sc->parent_tag, BCM_PAGE_SIZE,
3824218423Sdavidch			    BCE_DMA_BOUNDARY, BUS_SPACE_MAXADDR, sc->max_bus_addr,
3825218423Sdavidch			    NULL, NULL,	BCE_PG_CHAIN_PAGE_SZ, 1, BCE_PG_CHAIN_PAGE_SZ,
3826218423Sdavidch			    0, NULL, NULL, &sc->pg_bd_chain_tag)) {
3827218423Sdavidch			BCE_PRINTF("%s(%d): Could not allocate page descriptor "
3828218423Sdavidch			    "chain DMA tag!\n",	__FILE__, __LINE__);
3829176448Sdavidch			rc = ENOMEM;
3830176448Sdavidch			goto bce_dma_alloc_exit;
3831176448Sdavidch		}
3832176448Sdavidch
3833218423Sdavidch		for (i = 0; i < sc->pg_pages; i++) {
3834218423Sdavidch			if (bus_dmamem_alloc(sc->pg_bd_chain_tag,
3835218423Sdavidch			    (void **)&sc->pg_bd_chain[i],
3836218423Sdavidch			    BUS_DMA_NOWAIT | BUS_DMA_ZERO | BUS_DMA_COHERENT,
3837218423Sdavidch			    &sc->pg_bd_chain_map[i])) {
3838218423Sdavidch				BCE_PRINTF("%s(%d): Could not allocate page "
3839218423Sdavidch				    "descriptor chain DMA memory!\n",
3840218423Sdavidch				    __FILE__, __LINE__);
3841218423Sdavidch				rc = ENOMEM;
3842218423Sdavidch				goto bce_dma_alloc_exit;
3843218423Sdavidch			}
3844176448Sdavidch
3845218423Sdavidch			error = bus_dmamap_load(sc->pg_bd_chain_tag,
3846218423Sdavidch			    sc->pg_bd_chain_map[i], sc->pg_bd_chain[i],
3847218423Sdavidch			    BCE_PG_CHAIN_PAGE_SZ, bce_dma_map_addr,
3848218423Sdavidch			    &sc->pg_bd_chain_paddr[i], BUS_DMA_NOWAIT);
3849176448Sdavidch
3850251146Smarius			if (error || sc->pg_bd_chain_paddr[i] == 0) {
3851218423Sdavidch				BCE_PRINTF("%s(%d): Could not map page descriptor "
3852218423Sdavidch					"chain DMA memory!\n", __FILE__, __LINE__);
3853218423Sdavidch				rc = ENOMEM;
3854218423Sdavidch				goto bce_dma_alloc_exit;
3855218423Sdavidch			}
3856176448Sdavidch
3857218423Sdavidch			DBPRINT(sc, BCE_INFO_LOAD, "%s(): pg_bd_chain_paddr[%d] = "
3858218423Sdavidch				"0x%jX\n", __FUNCTION__, i,
3859218423Sdavidch				(uintmax_t) sc->pg_bd_chain_paddr[i]);
3860218423Sdavidch		}
3861176448Sdavidch
3862218423Sdavidch		/*
3863218423Sdavidch		 * Create a DMA tag for page mbufs.
3864218423Sdavidch		 */
3865218423Sdavidch		if (bus_dma_tag_create(sc->parent_tag, 1, BCE_DMA_BOUNDARY,
3866251142Smarius		    sc->max_bus_addr, BUS_SPACE_MAXADDR, NULL, NULL, MCLBYTES,
3867251142Smarius		    1, MCLBYTES, 0, NULL, NULL, &sc->pg_mbuf_tag)) {
3868218423Sdavidch			BCE_PRINTF("%s(%d): Could not allocate page mbuf "
3869218423Sdavidch				"DMA tag!\n", __FILE__, __LINE__);
3870176448Sdavidch			rc = ENOMEM;
3871176448Sdavidch			goto bce_dma_alloc_exit;
3872176448Sdavidch		}
3873218423Sdavidch
3874218423Sdavidch		/* Create DMA maps for the page mbuf clusters. */
3875218423Sdavidch		for (i = 0; i < TOTAL_PG_BD_ALLOC; i++) {
3876218423Sdavidch			if (bus_dmamap_create(sc->pg_mbuf_tag, BUS_DMA_NOWAIT,
3877218423Sdavidch				&sc->pg_mbuf_map[i])) {
3878218423Sdavidch				BCE_PRINTF("%s(%d): Unable to create page mbuf "
3879218423Sdavidch					"DMA map!\n", __FILE__, __LINE__);
3880218423Sdavidch				rc = ENOMEM;
3881218423Sdavidch				goto bce_dma_alloc_exit;
3882218423Sdavidch			}
3883218423Sdavidch		}
3884176448Sdavidch	}
3885176448Sdavidch
3886157642Spsbce_dma_alloc_exit:
3887179771Sdavidch	DBEXIT(BCE_VERBOSE_RESET | BCE_VERBOSE_CTX);
3888157642Sps	return(rc);
3889157642Sps}
3890157642Sps
3891157642Sps
3892157642Sps/****************************************************************************/
3893157642Sps/* Release all resources used by the driver.                                */
3894157642Sps/*                                                                          */
3895157642Sps/* Releases all resources acquired by the driver including interrupts,      */
3896157642Sps/* interrupt handler, interfaces, mutexes, and DMA memory.                  */
3897157642Sps/*                                                                          */
3898157642Sps/* Returns:                                                                 */
3899157642Sps/*   Nothing.                                                               */
3900157642Sps/****************************************************************************/
3901157642Spsstatic void
3902157642Spsbce_release_resources(struct bce_softc *sc)
3903157642Sps{
3904157642Sps	device_t dev;
3905157642Sps
3906179771Sdavidch	DBENTER(BCE_VERBOSE_RESET);
3907157642Sps
3908157642Sps	dev = sc->bce_dev;
3909157642Sps
3910157642Sps	bce_dma_free(sc);
3911170392Sdavidch
3912170392Sdavidch	if (sc->bce_intrhand != NULL) {
3913169632Sdavidch		DBPRINT(sc, BCE_INFO_RESET, "Removing interrupt handler.\n");
3914170392Sdavidch		bus_teardown_intr(dev, sc->bce_res_irq, sc->bce_intrhand);
3915169632Sdavidch	}
3916157642Sps
3917170392Sdavidch	if (sc->bce_res_irq != NULL) {
3918169632Sdavidch		DBPRINT(sc, BCE_INFO_RESET, "Releasing IRQ.\n");
3919247565Smarius		bus_release_resource(dev, SYS_RES_IRQ,
3920247565Smarius		    rman_get_rid(sc->bce_res_irq), sc->bce_res_irq);
3921169632Sdavidch	}
3922170392Sdavidch
3923179771Sdavidch	if (sc->bce_flags & (BCE_USING_MSI_FLAG | BCE_USING_MSIX_FLAG)) {
3924179771Sdavidch		DBPRINT(sc, BCE_INFO_RESET, "Releasing MSI/MSI-X vector.\n");
3925170392Sdavidch		pci_release_msi(dev);
3926170392Sdavidch	}
3927157642Sps
3928170392Sdavidch	if (sc->bce_res_mem != NULL) {
3929169632Sdavidch		DBPRINT(sc, BCE_INFO_RESET, "Releasing PCI memory.\n");
3930207411Sdavidch		    bus_release_resource(dev, SYS_RES_MEMORY, PCIR_BAR(0),
3931206268Sdavidch		    sc->bce_res_mem);
3932169632Sdavidch	}
3933157642Sps
3934170392Sdavidch	if (sc->bce_ifp != NULL) {
3935169632Sdavidch		DBPRINT(sc, BCE_INFO_RESET, "Releasing IF.\n");
3936170392Sdavidch		if_free(sc->bce_ifp);
3937169632Sdavidch	}
3938164305Sjhb
3939157642Sps	if (mtx_initialized(&sc->bce_mtx))
3940157642Sps		BCE_LOCK_DESTROY(sc);
3941157642Sps
3942179771Sdavidch	DBEXIT(BCE_VERBOSE_RESET);
3943157642Sps}
3944157642Sps
3945157642Sps
3946157642Sps/****************************************************************************/
3947157642Sps/* Firmware synchronization.                                                */
3948157642Sps/*                                                                          */
3949157642Sps/* Before performing certain events such as a chip reset, synchronize with  */
3950157642Sps/* the firmware first.                                                      */
3951157642Sps/*                                                                          */
3952157642Sps/* Returns:                                                                 */
3953157642Sps/*   0 for success, positive value for failure.                             */
3954157642Sps/****************************************************************************/
3955157642Spsstatic int
3956157642Spsbce_fw_sync(struct bce_softc *sc, u32 msg_data)
3957157642Sps{
3958157642Sps	int i, rc = 0;
3959157642Sps	u32 val;
3960157642Sps
3961179771Sdavidch	DBENTER(BCE_VERBOSE_RESET);
3962179771Sdavidch
3963157642Sps	/* Don't waste any time if we've timed out before. */
3964206268Sdavidch	if (sc->bce_fw_timed_out == TRUE) {
3965157642Sps		rc = EBUSY;
3966157642Sps		goto bce_fw_sync_exit;
3967157642Sps	}
3968157642Sps
3969157642Sps	/* Increment the message sequence number. */
3970157642Sps	sc->bce_fw_wr_seq++;
3971157642Sps	msg_data |= sc->bce_fw_wr_seq;
3972157642Sps
3973206268Sdavidch 	DBPRINT(sc, BCE_VERBOSE_FIRMWARE, "bce_fw_sync(): msg_data = "
3974206268Sdavidch	    "0x%08X\n",	msg_data);
3975157642Sps
3976157642Sps	/* Send the message to the bootcode driver mailbox. */
3977194781Sdavidch	bce_shmem_wr(sc, BCE_DRV_MB, msg_data);
3978157642Sps
3979157642Sps	/* Wait for the bootcode to acknowledge the message. */
3980157642Sps	for (i = 0; i < FW_ACK_TIME_OUT_MS; i++) {
3981157642Sps		/* Check for a response in the bootcode firmware mailbox. */
3982194781Sdavidch		val = bce_shmem_rd(sc, BCE_FW_MB);
3983157642Sps		if ((val & BCE_FW_MSG_ACK) == (msg_data & BCE_DRV_MSG_SEQ))
3984157642Sps			break;
3985157642Sps		DELAY(1000);
3986157642Sps	}
3987157642Sps
3988207411Sdavidch	/* If we've timed out, tell bootcode that we've stopped waiting. */
3989157642Sps	if (((val & BCE_FW_MSG_ACK) != (msg_data & BCE_DRV_MSG_SEQ)) &&
3990206268Sdavidch	    ((msg_data & BCE_DRV_MSG_DATA) != BCE_DRV_MSG_DATA_WAIT0)) {
3991157642Sps
3992169271Sdavidch		BCE_PRINTF("%s(%d): Firmware synchronization timeout! "
3993206268Sdavidch		    "msg_data = 0x%08X\n", __FILE__, __LINE__, msg_data);
3994157642Sps
3995157642Sps		msg_data &= ~BCE_DRV_MSG_CODE;
3996157642Sps		msg_data |= BCE_DRV_MSG_CODE_FW_TIMEOUT;
3997157642Sps
3998194781Sdavidch		bce_shmem_wr(sc, BCE_DRV_MB, msg_data);
3999157642Sps
4000206268Sdavidch		sc->bce_fw_timed_out = TRUE;
4001157642Sps		rc = EBUSY;
4002157642Sps	}
4003157642Sps
4004157642Spsbce_fw_sync_exit:
4005179771Sdavidch	DBEXIT(BCE_VERBOSE_RESET);
4006157642Sps	return (rc);
4007157642Sps}
4008157642Sps
4009157642Sps
4010157642Sps/****************************************************************************/
4011157642Sps/* Load Receive Virtual 2 Physical (RV2P) processor firmware.               */
4012157642Sps/*                                                                          */
4013157642Sps/* Returns:                                                                 */
4014157642Sps/*   Nothing.                                                               */
4015157642Sps/****************************************************************************/
4016157642Spsstatic void
4017251142Smariusbce_load_rv2p_fw(struct bce_softc *sc, const u32 *rv2p_code,
4018157642Sps	u32 rv2p_code_len, u32 rv2p_proc)
4019157642Sps{
4020157642Sps	int i;
4021157642Sps	u32 val;
4022178132Sdavidch
4023179771Sdavidch	DBENTER(BCE_VERBOSE_RESET);
4024179771Sdavidch
4025176448Sdavidch	/* Set the page size used by RV2P. */
4026176448Sdavidch	if (rv2p_proc == RV2P_PROC2) {
4027178132Sdavidch		BCE_RV2P_PROC2_CHG_MAX_BD_PAGE(USABLE_RX_BD_PER_PAGE);
4028176448Sdavidch	}
4029178132Sdavidch
4030157642Sps	for (i = 0; i < rv2p_code_len; i += 8) {
4031157642Sps		REG_WR(sc, BCE_RV2P_INSTR_HIGH, *rv2p_code);
4032157642Sps		rv2p_code++;
4033157642Sps		REG_WR(sc, BCE_RV2P_INSTR_LOW, *rv2p_code);
4034157642Sps		rv2p_code++;
4035157642Sps
4036157642Sps		if (rv2p_proc == RV2P_PROC1) {
4037157642Sps			val = (i / 8) | BCE_RV2P_PROC1_ADDR_CMD_RDWR;
4038157642Sps			REG_WR(sc, BCE_RV2P_PROC1_ADDR_CMD, val);
4039157642Sps		}
4040157642Sps		else {
4041157642Sps			val = (i / 8) | BCE_RV2P_PROC2_ADDR_CMD_RDWR;
4042157642Sps			REG_WR(sc, BCE_RV2P_PROC2_ADDR_CMD, val);
4043157642Sps		}
4044157642Sps	}
4045157642Sps
4046157642Sps	/* Reset the processor, un-stall is done later. */
4047157642Sps	if (rv2p_proc == RV2P_PROC1) {
4048157642Sps		REG_WR(sc, BCE_RV2P_COMMAND, BCE_RV2P_COMMAND_PROC1_RESET);
4049157642Sps	}
4050157642Sps	else {
4051157642Sps		REG_WR(sc, BCE_RV2P_COMMAND, BCE_RV2P_COMMAND_PROC2_RESET);
4052157642Sps	}
4053179771Sdavidch
4054179771Sdavidch	DBEXIT(BCE_VERBOSE_RESET);
4055157642Sps}
4056157642Sps
4057157642Sps
4058157642Sps/****************************************************************************/
4059157642Sps/* Load RISC processor firmware.                                            */
4060157642Sps/*                                                                          */
4061157642Sps/* Loads firmware from the file if_bcefw.h into the scratchpad memory       */
4062157642Sps/* associated with a particular processor.                                  */
4063157642Sps/*                                                                          */
4064157642Sps/* Returns:                                                                 */
4065157642Sps/*   Nothing.                                                               */
4066157642Sps/****************************************************************************/
4067157642Spsstatic void
4068157642Spsbce_load_cpu_fw(struct bce_softc *sc, struct cpu_reg *cpu_reg,
4069157642Sps	struct fw_info *fw)
4070157642Sps{
4071157642Sps	u32 offset;
4072157642Sps
4073179771Sdavidch	DBENTER(BCE_VERBOSE_RESET);
4074179771Sdavidch
4075202717Sdavidch    bce_halt_cpu(sc, cpu_reg);
4076157642Sps
4077157642Sps	/* Load the Text area. */
4078157642Sps	offset = cpu_reg->spad_base + (fw->text_addr - cpu_reg->mips_view_base);
4079157642Sps	if (fw->text) {
4080157642Sps		int j;
4081157642Sps
4082157642Sps		for (j = 0; j < (fw->text_len / 4); j++, offset += 4) {
4083157642Sps			REG_WR_IND(sc, offset, fw->text[j]);
4084157642Sps	        }
4085157642Sps	}
4086157642Sps
4087157642Sps	/* Load the Data area. */
4088157642Sps	offset = cpu_reg->spad_base + (fw->data_addr - cpu_reg->mips_view_base);
4089157642Sps	if (fw->data) {
4090157642Sps		int j;
4091157642Sps
4092157642Sps		for (j = 0; j < (fw->data_len / 4); j++, offset += 4) {
4093157642Sps			REG_WR_IND(sc, offset, fw->data[j]);
4094157642Sps		}
4095157642Sps	}
4096157642Sps
4097157642Sps	/* Load the SBSS area. */
4098157642Sps	offset = cpu_reg->spad_base + (fw->sbss_addr - cpu_reg->mips_view_base);
4099157642Sps	if (fw->sbss) {
4100157642Sps		int j;
4101157642Sps
4102157642Sps		for (j = 0; j < (fw->sbss_len / 4); j++, offset += 4) {
4103157642Sps			REG_WR_IND(sc, offset, fw->sbss[j]);
4104157642Sps		}
4105157642Sps	}
4106157642Sps
4107157642Sps	/* Load the BSS area. */
4108157642Sps	offset = cpu_reg->spad_base + (fw->bss_addr - cpu_reg->mips_view_base);
4109157642Sps	if (fw->bss) {
4110157642Sps		int j;
4111157642Sps
4112157642Sps		for (j = 0; j < (fw->bss_len/4); j++, offset += 4) {
4113157642Sps			REG_WR_IND(sc, offset, fw->bss[j]);
4114157642Sps		}
4115157642Sps	}
4116157642Sps
4117157642Sps	/* Load the Read-Only area. */
4118157642Sps	offset = cpu_reg->spad_base +
4119157642Sps		(fw->rodata_addr - cpu_reg->mips_view_base);
4120157642Sps	if (fw->rodata) {
4121157642Sps		int j;
4122157642Sps
4123157642Sps		for (j = 0; j < (fw->rodata_len / 4); j++, offset += 4) {
4124157642Sps			REG_WR_IND(sc, offset, fw->rodata[j]);
4125157642Sps		}
4126157642Sps	}
4127157642Sps
4128206268Sdavidch	/* Clear the pre-fetch instruction and set the FW start address. */
4129206268Sdavidch	REG_WR_IND(sc, cpu_reg->inst, 0);
4130206268Sdavidch	REG_WR_IND(sc, cpu_reg->pc, fw->start_addr);
4131157642Sps
4132202717Sdavidch	DBEXIT(BCE_VERBOSE_RESET);
4133202717Sdavidch}
4134202717Sdavidch
4135202717Sdavidch
4136202717Sdavidch/****************************************************************************/
4137202717Sdavidch/* Starts the RISC processor.                                               */
4138202717Sdavidch/*                                                                          */
4139202717Sdavidch/* Assumes the CPU starting address has already been set.                   */
4140202717Sdavidch/*                                                                          */
4141202717Sdavidch/* Returns:                                                                 */
4142202717Sdavidch/*   Nothing.                                                               */
4143202717Sdavidch/****************************************************************************/
4144202717Sdavidchstatic void
4145202717Sdavidchbce_start_cpu(struct bce_softc *sc, struct cpu_reg *cpu_reg)
4146202717Sdavidch{
4147202717Sdavidch	u32 val;
4148202717Sdavidch
4149202717Sdavidch	DBENTER(BCE_VERBOSE_RESET);
4150202717Sdavidch
4151157642Sps	/* Start the CPU. */
4152157642Sps	val = REG_RD_IND(sc, cpu_reg->mode);
4153157642Sps	val &= ~cpu_reg->mode_value_halt;
4154157642Sps	REG_WR_IND(sc, cpu_reg->state, cpu_reg->state_value_clear);
4155157642Sps	REG_WR_IND(sc, cpu_reg->mode, val);
4156179771Sdavidch
4157179771Sdavidch	DBEXIT(BCE_VERBOSE_RESET);
4158157642Sps}
4159157642Sps
4160157642Sps
4161157642Sps/****************************************************************************/
4162202717Sdavidch/* Halts the RISC processor.                                                */
4163202717Sdavidch/*                                                                          */
4164202717Sdavidch/* Returns:                                                                 */
4165202717Sdavidch/*   Nothing.                                                               */
4166202717Sdavidch/****************************************************************************/
4167202717Sdavidchstatic void
4168202717Sdavidchbce_halt_cpu(struct bce_softc *sc, struct cpu_reg *cpu_reg)
4169202717Sdavidch{
4170202717Sdavidch	u32 val;
4171202717Sdavidch
4172202717Sdavidch	DBENTER(BCE_VERBOSE_RESET);
4173202717Sdavidch
4174206268Sdavidch	/* Halt the CPU. */
4175206268Sdavidch	val = REG_RD_IND(sc, cpu_reg->mode);
4176206268Sdavidch	val |= cpu_reg->mode_value_halt;
4177206268Sdavidch	REG_WR_IND(sc, cpu_reg->mode, val);
4178206268Sdavidch	REG_WR_IND(sc, cpu_reg->state, cpu_reg->state_value_clear);
4179202717Sdavidch
4180202717Sdavidch	DBEXIT(BCE_VERBOSE_RESET);
4181202717Sdavidch}
4182202717Sdavidch
4183202717Sdavidch
4184202717Sdavidch/****************************************************************************/
4185179771Sdavidch/* Initialize the RX CPU.                                                   */
4186157642Sps/*                                                                          */
4187157642Sps/* Returns:                                                                 */
4188157642Sps/*   Nothing.                                                               */
4189157642Sps/****************************************************************************/
4190157642Spsstatic void
4191202717Sdavidchbce_start_rxp_cpu(struct bce_softc *sc)
4192202717Sdavidch{
4193202717Sdavidch	struct cpu_reg cpu_reg;
4194202717Sdavidch
4195202717Sdavidch	DBENTER(BCE_VERBOSE_RESET);
4196202717Sdavidch
4197202717Sdavidch	cpu_reg.mode = BCE_RXP_CPU_MODE;
4198202717Sdavidch	cpu_reg.mode_value_halt = BCE_RXP_CPU_MODE_SOFT_HALT;
4199202717Sdavidch	cpu_reg.mode_value_sstep = BCE_RXP_CPU_MODE_STEP_ENA;
4200202717Sdavidch	cpu_reg.state = BCE_RXP_CPU_STATE;
4201202717Sdavidch	cpu_reg.state_value_clear = 0xffffff;
4202202717Sdavidch	cpu_reg.gpr0 = BCE_RXP_CPU_REG_FILE;
4203202717Sdavidch	cpu_reg.evmask = BCE_RXP_CPU_EVENT_MASK;
4204202717Sdavidch	cpu_reg.pc = BCE_RXP_CPU_PROGRAM_COUNTER;
4205202717Sdavidch	cpu_reg.inst = BCE_RXP_CPU_INSTRUCTION;
4206202717Sdavidch	cpu_reg.bp = BCE_RXP_CPU_HW_BREAKPOINT;
4207202717Sdavidch	cpu_reg.spad_base = BCE_RXP_SCRATCH;
4208202717Sdavidch	cpu_reg.mips_view_base = 0x8000000;
4209202717Sdavidch
4210202717Sdavidch	DBPRINT(sc, BCE_INFO_RESET, "Starting RX firmware.\n");
4211202717Sdavidch	bce_start_cpu(sc, &cpu_reg);
4212202717Sdavidch
4213202717Sdavidch	DBEXIT(BCE_VERBOSE_RESET);
4214202717Sdavidch}
4215202717Sdavidch
4216202717Sdavidch
4217202717Sdavidch/****************************************************************************/
4218202717Sdavidch/* Initialize the RX CPU.                                                   */
4219202717Sdavidch/*                                                                          */
4220202717Sdavidch/* Returns:                                                                 */
4221202717Sdavidch/*   Nothing.                                                               */
4222202717Sdavidch/****************************************************************************/
4223202717Sdavidchstatic void
4224179771Sdavidchbce_init_rxp_cpu(struct bce_softc *sc)
4225157642Sps{
4226157642Sps	struct cpu_reg cpu_reg;
4227157642Sps	struct fw_info fw;
4228157642Sps
4229179771Sdavidch	DBENTER(BCE_VERBOSE_RESET);
4230157642Sps
4231157642Sps	cpu_reg.mode = BCE_RXP_CPU_MODE;
4232157642Sps	cpu_reg.mode_value_halt = BCE_RXP_CPU_MODE_SOFT_HALT;
4233157642Sps	cpu_reg.mode_value_sstep = BCE_RXP_CPU_MODE_STEP_ENA;
4234157642Sps	cpu_reg.state = BCE_RXP_CPU_STATE;
4235157642Sps	cpu_reg.state_value_clear = 0xffffff;
4236157642Sps	cpu_reg.gpr0 = BCE_RXP_CPU_REG_FILE;
4237157642Sps	cpu_reg.evmask = BCE_RXP_CPU_EVENT_MASK;
4238157642Sps	cpu_reg.pc = BCE_RXP_CPU_PROGRAM_COUNTER;
4239157642Sps	cpu_reg.inst = BCE_RXP_CPU_INSTRUCTION;
4240157642Sps	cpu_reg.bp = BCE_RXP_CPU_HW_BREAKPOINT;
4241157642Sps	cpu_reg.spad_base = BCE_RXP_SCRATCH;
4242157642Sps	cpu_reg.mips_view_base = 0x8000000;
4243157642Sps
4244226123Syongari	if (BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5709) {
4245179771Sdavidch 		fw.ver_major = bce_RXP_b09FwReleaseMajor;
4246179771Sdavidch		fw.ver_minor = bce_RXP_b09FwReleaseMinor;
4247179771Sdavidch		fw.ver_fix = bce_RXP_b09FwReleaseFix;
4248179771Sdavidch		fw.start_addr = bce_RXP_b09FwStartAddr;
4249157642Sps
4250179771Sdavidch		fw.text_addr = bce_RXP_b09FwTextAddr;
4251179771Sdavidch		fw.text_len = bce_RXP_b09FwTextLen;
4252179771Sdavidch		fw.text_index = 0;
4253179771Sdavidch		fw.text = bce_RXP_b09FwText;
4254157642Sps
4255179771Sdavidch		fw.data_addr = bce_RXP_b09FwDataAddr;
4256179771Sdavidch		fw.data_len = bce_RXP_b09FwDataLen;
4257179771Sdavidch		fw.data_index = 0;
4258179771Sdavidch		fw.data = bce_RXP_b09FwData;
4259157642Sps
4260179771Sdavidch		fw.sbss_addr = bce_RXP_b09FwSbssAddr;
4261179771Sdavidch		fw.sbss_len = bce_RXP_b09FwSbssLen;
4262179771Sdavidch		fw.sbss_index = 0;
4263179771Sdavidch		fw.sbss = bce_RXP_b09FwSbss;
4264157642Sps
4265179771Sdavidch		fw.bss_addr = bce_RXP_b09FwBssAddr;
4266179771Sdavidch		fw.bss_len = bce_RXP_b09FwBssLen;
4267179771Sdavidch		fw.bss_index = 0;
4268179771Sdavidch		fw.bss = bce_RXP_b09FwBss;
4269157642Sps
4270179771Sdavidch		fw.rodata_addr = bce_RXP_b09FwRodataAddr;
4271179771Sdavidch		fw.rodata_len = bce_RXP_b09FwRodataLen;
4272179771Sdavidch		fw.rodata_index = 0;
4273179771Sdavidch		fw.rodata = bce_RXP_b09FwRodata;
4274179771Sdavidch	} else {
4275179771Sdavidch		fw.ver_major = bce_RXP_b06FwReleaseMajor;
4276179771Sdavidch		fw.ver_minor = bce_RXP_b06FwReleaseMinor;
4277179771Sdavidch		fw.ver_fix = bce_RXP_b06FwReleaseFix;
4278179771Sdavidch		fw.start_addr = bce_RXP_b06FwStartAddr;
4279157642Sps
4280179771Sdavidch		fw.text_addr = bce_RXP_b06FwTextAddr;
4281179771Sdavidch		fw.text_len = bce_RXP_b06FwTextLen;
4282179771Sdavidch		fw.text_index = 0;
4283179771Sdavidch		fw.text = bce_RXP_b06FwText;
4284179771Sdavidch
4285179771Sdavidch		fw.data_addr = bce_RXP_b06FwDataAddr;
4286179771Sdavidch		fw.data_len = bce_RXP_b06FwDataLen;
4287179771Sdavidch		fw.data_index = 0;
4288179771Sdavidch		fw.data = bce_RXP_b06FwData;
4289179771Sdavidch
4290179771Sdavidch		fw.sbss_addr = bce_RXP_b06FwSbssAddr;
4291179771Sdavidch		fw.sbss_len = bce_RXP_b06FwSbssLen;
4292179771Sdavidch		fw.sbss_index = 0;
4293179771Sdavidch		fw.sbss = bce_RXP_b06FwSbss;
4294179771Sdavidch
4295179771Sdavidch		fw.bss_addr = bce_RXP_b06FwBssAddr;
4296179771Sdavidch		fw.bss_len = bce_RXP_b06FwBssLen;
4297179771Sdavidch		fw.bss_index = 0;
4298179771Sdavidch		fw.bss = bce_RXP_b06FwBss;
4299179771Sdavidch
4300179771Sdavidch		fw.rodata_addr = bce_RXP_b06FwRodataAddr;
4301179771Sdavidch		fw.rodata_len = bce_RXP_b06FwRodataLen;
4302179771Sdavidch		fw.rodata_index = 0;
4303179771Sdavidch		fw.rodata = bce_RXP_b06FwRodata;
4304179771Sdavidch	}
4305179771Sdavidch
4306157642Sps	DBPRINT(sc, BCE_INFO_RESET, "Loading RX firmware.\n");
4307157642Sps	bce_load_cpu_fw(sc, &cpu_reg, &fw);
4308157642Sps
4309202717Sdavidch    /* Delay RXP start until initialization is complete. */
4310202717Sdavidch
4311179771Sdavidch	DBEXIT(BCE_VERBOSE_RESET);
4312179771Sdavidch}
4313179771Sdavidch
4314179771Sdavidch
4315179771Sdavidch/****************************************************************************/
4316179771Sdavidch/* Initialize the TX CPU.                                                   */
4317179771Sdavidch/*                                                                          */
4318179771Sdavidch/* Returns:                                                                 */
4319179771Sdavidch/*   Nothing.                                                               */
4320179771Sdavidch/****************************************************************************/
4321179771Sdavidchstatic void
4322179771Sdavidchbce_init_txp_cpu(struct bce_softc *sc)
4323179771Sdavidch{
4324179771Sdavidch	struct cpu_reg cpu_reg;
4325179771Sdavidch	struct fw_info fw;
4326179771Sdavidch
4327179771Sdavidch	DBENTER(BCE_VERBOSE_RESET);
4328179771Sdavidch
4329157642Sps	cpu_reg.mode = BCE_TXP_CPU_MODE;
4330157642Sps	cpu_reg.mode_value_halt = BCE_TXP_CPU_MODE_SOFT_HALT;
4331157642Sps	cpu_reg.mode_value_sstep = BCE_TXP_CPU_MODE_STEP_ENA;
4332157642Sps	cpu_reg.state = BCE_TXP_CPU_STATE;
4333157642Sps	cpu_reg.state_value_clear = 0xffffff;
4334157642Sps	cpu_reg.gpr0 = BCE_TXP_CPU_REG_FILE;
4335157642Sps	cpu_reg.evmask = BCE_TXP_CPU_EVENT_MASK;
4336157642Sps	cpu_reg.pc = BCE_TXP_CPU_PROGRAM_COUNTER;
4337157642Sps	cpu_reg.inst = BCE_TXP_CPU_INSTRUCTION;
4338157642Sps	cpu_reg.bp = BCE_TXP_CPU_HW_BREAKPOINT;
4339157642Sps	cpu_reg.spad_base = BCE_TXP_SCRATCH;
4340157642Sps	cpu_reg.mips_view_base = 0x8000000;
4341157642Sps
4342226123Syongari	if (BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5709) {
4343179771Sdavidch		fw.ver_major = bce_TXP_b09FwReleaseMajor;
4344179771Sdavidch		fw.ver_minor = bce_TXP_b09FwReleaseMinor;
4345179771Sdavidch		fw.ver_fix = bce_TXP_b09FwReleaseFix;
4346179771Sdavidch		fw.start_addr = bce_TXP_b09FwStartAddr;
4347157642Sps
4348179771Sdavidch		fw.text_addr = bce_TXP_b09FwTextAddr;
4349179771Sdavidch		fw.text_len = bce_TXP_b09FwTextLen;
4350179771Sdavidch		fw.text_index = 0;
4351179771Sdavidch		fw.text = bce_TXP_b09FwText;
4352157642Sps
4353179771Sdavidch		fw.data_addr = bce_TXP_b09FwDataAddr;
4354179771Sdavidch		fw.data_len = bce_TXP_b09FwDataLen;
4355179771Sdavidch		fw.data_index = 0;
4356179771Sdavidch		fw.data = bce_TXP_b09FwData;
4357157642Sps
4358179771Sdavidch		fw.sbss_addr = bce_TXP_b09FwSbssAddr;
4359179771Sdavidch		fw.sbss_len = bce_TXP_b09FwSbssLen;
4360179771Sdavidch		fw.sbss_index = 0;
4361179771Sdavidch		fw.sbss = bce_TXP_b09FwSbss;
4362157642Sps
4363179771Sdavidch		fw.bss_addr = bce_TXP_b09FwBssAddr;
4364179771Sdavidch		fw.bss_len = bce_TXP_b09FwBssLen;
4365179771Sdavidch		fw.bss_index = 0;
4366179771Sdavidch		fw.bss = bce_TXP_b09FwBss;
4367157642Sps
4368179771Sdavidch		fw.rodata_addr = bce_TXP_b09FwRodataAddr;
4369179771Sdavidch		fw.rodata_len = bce_TXP_b09FwRodataLen;
4370179771Sdavidch		fw.rodata_index = 0;
4371179771Sdavidch		fw.rodata = bce_TXP_b09FwRodata;
4372179771Sdavidch	} else {
4373179771Sdavidch		fw.ver_major = bce_TXP_b06FwReleaseMajor;
4374179771Sdavidch		fw.ver_minor = bce_TXP_b06FwReleaseMinor;
4375179771Sdavidch		fw.ver_fix = bce_TXP_b06FwReleaseFix;
4376179771Sdavidch		fw.start_addr = bce_TXP_b06FwStartAddr;
4377157642Sps
4378179771Sdavidch		fw.text_addr = bce_TXP_b06FwTextAddr;
4379179771Sdavidch		fw.text_len = bce_TXP_b06FwTextLen;
4380179771Sdavidch		fw.text_index = 0;
4381179771Sdavidch		fw.text = bce_TXP_b06FwText;
4382179771Sdavidch
4383179771Sdavidch		fw.data_addr = bce_TXP_b06FwDataAddr;
4384179771Sdavidch		fw.data_len = bce_TXP_b06FwDataLen;
4385179771Sdavidch		fw.data_index = 0;
4386179771Sdavidch		fw.data = bce_TXP_b06FwData;
4387179771Sdavidch
4388179771Sdavidch		fw.sbss_addr = bce_TXP_b06FwSbssAddr;
4389179771Sdavidch		fw.sbss_len = bce_TXP_b06FwSbssLen;
4390179771Sdavidch		fw.sbss_index = 0;
4391179771Sdavidch		fw.sbss = bce_TXP_b06FwSbss;
4392179771Sdavidch
4393179771Sdavidch		fw.bss_addr = bce_TXP_b06FwBssAddr;
4394179771Sdavidch		fw.bss_len = bce_TXP_b06FwBssLen;
4395179771Sdavidch		fw.bss_index = 0;
4396179771Sdavidch		fw.bss = bce_TXP_b06FwBss;
4397179771Sdavidch
4398179771Sdavidch		fw.rodata_addr = bce_TXP_b06FwRodataAddr;
4399179771Sdavidch		fw.rodata_len = bce_TXP_b06FwRodataLen;
4400179771Sdavidch		fw.rodata_index = 0;
4401179771Sdavidch		fw.rodata = bce_TXP_b06FwRodata;
4402179771Sdavidch	}
4403179771Sdavidch
4404157642Sps	DBPRINT(sc, BCE_INFO_RESET, "Loading TX firmware.\n");
4405157642Sps	bce_load_cpu_fw(sc, &cpu_reg, &fw);
4406202717Sdavidch    bce_start_cpu(sc, &cpu_reg);
4407157642Sps
4408179771Sdavidch	DBEXIT(BCE_VERBOSE_RESET);
4409179771Sdavidch}
4410179771Sdavidch
4411179771Sdavidch
4412179771Sdavidch/****************************************************************************/
4413179771Sdavidch/* Initialize the TPAT CPU.                                                 */
4414179771Sdavidch/*                                                                          */
4415179771Sdavidch/* Returns:                                                                 */
4416179771Sdavidch/*   Nothing.                                                               */
4417179771Sdavidch/****************************************************************************/
4418179771Sdavidchstatic void
4419179771Sdavidchbce_init_tpat_cpu(struct bce_softc *sc)
4420179771Sdavidch{
4421179771Sdavidch	struct cpu_reg cpu_reg;
4422179771Sdavidch	struct fw_info fw;
4423179771Sdavidch
4424179771Sdavidch	DBENTER(BCE_VERBOSE_RESET);
4425179771Sdavidch
4426157642Sps	cpu_reg.mode = BCE_TPAT_CPU_MODE;
4427157642Sps	cpu_reg.mode_value_halt = BCE_TPAT_CPU_MODE_SOFT_HALT;
4428157642Sps	cpu_reg.mode_value_sstep = BCE_TPAT_CPU_MODE_STEP_ENA;
4429157642Sps	cpu_reg.state = BCE_TPAT_CPU_STATE;
4430157642Sps	cpu_reg.state_value_clear = 0xffffff;
4431157642Sps	cpu_reg.gpr0 = BCE_TPAT_CPU_REG_FILE;
4432157642Sps	cpu_reg.evmask = BCE_TPAT_CPU_EVENT_MASK;
4433157642Sps	cpu_reg.pc = BCE_TPAT_CPU_PROGRAM_COUNTER;
4434157642Sps	cpu_reg.inst = BCE_TPAT_CPU_INSTRUCTION;
4435157642Sps	cpu_reg.bp = BCE_TPAT_CPU_HW_BREAKPOINT;
4436157642Sps	cpu_reg.spad_base = BCE_TPAT_SCRATCH;
4437157642Sps	cpu_reg.mips_view_base = 0x8000000;
4438157642Sps
4439226123Syongari	if (BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5709) {
4440179771Sdavidch		fw.ver_major = bce_TPAT_b09FwReleaseMajor;
4441179771Sdavidch		fw.ver_minor = bce_TPAT_b09FwReleaseMinor;
4442179771Sdavidch		fw.ver_fix = bce_TPAT_b09FwReleaseFix;
4443179771Sdavidch		fw.start_addr = bce_TPAT_b09FwStartAddr;
4444157642Sps
4445179771Sdavidch		fw.text_addr = bce_TPAT_b09FwTextAddr;
4446179771Sdavidch		fw.text_len = bce_TPAT_b09FwTextLen;
4447179771Sdavidch		fw.text_index = 0;
4448179771Sdavidch		fw.text = bce_TPAT_b09FwText;
4449157642Sps
4450179771Sdavidch		fw.data_addr = bce_TPAT_b09FwDataAddr;
4451179771Sdavidch		fw.data_len = bce_TPAT_b09FwDataLen;
4452179771Sdavidch		fw.data_index = 0;
4453179771Sdavidch		fw.data = bce_TPAT_b09FwData;
4454157642Sps
4455179771Sdavidch		fw.sbss_addr = bce_TPAT_b09FwSbssAddr;
4456179771Sdavidch		fw.sbss_len = bce_TPAT_b09FwSbssLen;
4457179771Sdavidch		fw.sbss_index = 0;
4458179771Sdavidch		fw.sbss = bce_TPAT_b09FwSbss;
4459157642Sps
4460179771Sdavidch		fw.bss_addr = bce_TPAT_b09FwBssAddr;
4461179771Sdavidch		fw.bss_len = bce_TPAT_b09FwBssLen;
4462179771Sdavidch		fw.bss_index = 0;
4463179771Sdavidch		fw.bss = bce_TPAT_b09FwBss;
4464157642Sps
4465179771Sdavidch		fw.rodata_addr = bce_TPAT_b09FwRodataAddr;
4466179771Sdavidch		fw.rodata_len = bce_TPAT_b09FwRodataLen;
4467179771Sdavidch		fw.rodata_index = 0;
4468179771Sdavidch		fw.rodata = bce_TPAT_b09FwRodata;
4469179771Sdavidch	} else {
4470179771Sdavidch		fw.ver_major = bce_TPAT_b06FwReleaseMajor;
4471179771Sdavidch		fw.ver_minor = bce_TPAT_b06FwReleaseMinor;
4472179771Sdavidch		fw.ver_fix = bce_TPAT_b06FwReleaseFix;
4473179771Sdavidch		fw.start_addr = bce_TPAT_b06FwStartAddr;
4474157642Sps
4475179771Sdavidch		fw.text_addr = bce_TPAT_b06FwTextAddr;
4476179771Sdavidch		fw.text_len = bce_TPAT_b06FwTextLen;
4477179771Sdavidch		fw.text_index = 0;
4478179771Sdavidch		fw.text = bce_TPAT_b06FwText;
4479157642Sps
4480179771Sdavidch		fw.data_addr = bce_TPAT_b06FwDataAddr;
4481179771Sdavidch		fw.data_len = bce_TPAT_b06FwDataLen;
4482179771Sdavidch		fw.data_index = 0;
4483179771Sdavidch		fw.data = bce_TPAT_b06FwData;
4484157642Sps
4485179771Sdavidch		fw.sbss_addr = bce_TPAT_b06FwSbssAddr;
4486179771Sdavidch		fw.sbss_len = bce_TPAT_b06FwSbssLen;
4487179771Sdavidch		fw.sbss_index = 0;
4488179771Sdavidch		fw.sbss = bce_TPAT_b06FwSbss;
4489157642Sps
4490179771Sdavidch		fw.bss_addr = bce_TPAT_b06FwBssAddr;
4491179771Sdavidch		fw.bss_len = bce_TPAT_b06FwBssLen;
4492179771Sdavidch		fw.bss_index = 0;
4493179771Sdavidch		fw.bss = bce_TPAT_b06FwBss;
4494157642Sps
4495179771Sdavidch		fw.rodata_addr = bce_TPAT_b06FwRodataAddr;
4496179771Sdavidch		fw.rodata_len = bce_TPAT_b06FwRodataLen;
4497179771Sdavidch		fw.rodata_index = 0;
4498179771Sdavidch		fw.rodata = bce_TPAT_b06FwRodata;
4499179771Sdavidch	}
4500157642Sps
4501179771Sdavidch	DBPRINT(sc, BCE_INFO_RESET, "Loading TPAT firmware.\n");
4502179771Sdavidch	bce_load_cpu_fw(sc, &cpu_reg, &fw);
4503206268Sdavidch	bce_start_cpu(sc, &cpu_reg);
4504157642Sps
4505179771Sdavidch	DBEXIT(BCE_VERBOSE_RESET);
4506179771Sdavidch}
4507157642Sps
4508157642Sps
4509179771Sdavidch/****************************************************************************/
4510179771Sdavidch/* Initialize the CP CPU.                                                   */
4511179771Sdavidch/*                                                                          */
4512179771Sdavidch/* Returns:                                                                 */
4513179771Sdavidch/*   Nothing.                                                               */
4514179771Sdavidch/****************************************************************************/
4515179771Sdavidchstatic void
4516179771Sdavidchbce_init_cp_cpu(struct bce_softc *sc)
4517179771Sdavidch{
4518179771Sdavidch	struct cpu_reg cpu_reg;
4519179771Sdavidch	struct fw_info fw;
4520176448Sdavidch
4521179771Sdavidch	DBENTER(BCE_VERBOSE_RESET);
4522179771Sdavidch
4523176448Sdavidch	cpu_reg.mode = BCE_CP_CPU_MODE;
4524176448Sdavidch	cpu_reg.mode_value_halt = BCE_CP_CPU_MODE_SOFT_HALT;
4525176448Sdavidch	cpu_reg.mode_value_sstep = BCE_CP_CPU_MODE_STEP_ENA;
4526176448Sdavidch	cpu_reg.state = BCE_CP_CPU_STATE;
4527176448Sdavidch	cpu_reg.state_value_clear = 0xffffff;
4528176448Sdavidch	cpu_reg.gpr0 = BCE_CP_CPU_REG_FILE;
4529176448Sdavidch	cpu_reg.evmask = BCE_CP_CPU_EVENT_MASK;
4530176448Sdavidch	cpu_reg.pc = BCE_CP_CPU_PROGRAM_COUNTER;
4531176448Sdavidch	cpu_reg.inst = BCE_CP_CPU_INSTRUCTION;
4532176448Sdavidch	cpu_reg.bp = BCE_CP_CPU_HW_BREAKPOINT;
4533176448Sdavidch	cpu_reg.spad_base = BCE_CP_SCRATCH;
4534176448Sdavidch	cpu_reg.mips_view_base = 0x8000000;
4535176448Sdavidch
4536226123Syongari	if (BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5709) {
4537179771Sdavidch		fw.ver_major = bce_CP_b09FwReleaseMajor;
4538179771Sdavidch		fw.ver_minor = bce_CP_b09FwReleaseMinor;
4539179771Sdavidch		fw.ver_fix = bce_CP_b09FwReleaseFix;
4540179771Sdavidch		fw.start_addr = bce_CP_b09FwStartAddr;
4541176448Sdavidch
4542179771Sdavidch		fw.text_addr = bce_CP_b09FwTextAddr;
4543179771Sdavidch		fw.text_len = bce_CP_b09FwTextLen;
4544179771Sdavidch		fw.text_index = 0;
4545179771Sdavidch		fw.text = bce_CP_b09FwText;
4546176448Sdavidch
4547179771Sdavidch		fw.data_addr = bce_CP_b09FwDataAddr;
4548179771Sdavidch		fw.data_len = bce_CP_b09FwDataLen;
4549179771Sdavidch		fw.data_index = 0;
4550179771Sdavidch		fw.data = bce_CP_b09FwData;
4551176448Sdavidch
4552179771Sdavidch		fw.sbss_addr = bce_CP_b09FwSbssAddr;
4553179771Sdavidch		fw.sbss_len = bce_CP_b09FwSbssLen;
4554179771Sdavidch		fw.sbss_index = 0;
4555179771Sdavidch		fw.sbss = bce_CP_b09FwSbss;
4556176448Sdavidch
4557179771Sdavidch		fw.bss_addr = bce_CP_b09FwBssAddr;
4558179771Sdavidch		fw.bss_len = bce_CP_b09FwBssLen;
4559179771Sdavidch		fw.bss_index = 0;
4560179771Sdavidch		fw.bss = bce_CP_b09FwBss;
4561176448Sdavidch
4562179771Sdavidch		fw.rodata_addr = bce_CP_b09FwRodataAddr;
4563179771Sdavidch		fw.rodata_len = bce_CP_b09FwRodataLen;
4564179771Sdavidch		fw.rodata_index = 0;
4565179771Sdavidch		fw.rodata = bce_CP_b09FwRodata;
4566179771Sdavidch	} else {
4567179771Sdavidch		fw.ver_major = bce_CP_b06FwReleaseMajor;
4568179771Sdavidch		fw.ver_minor = bce_CP_b06FwReleaseMinor;
4569179771Sdavidch		fw.ver_fix = bce_CP_b06FwReleaseFix;
4570179771Sdavidch		fw.start_addr = bce_CP_b06FwStartAddr;
4571176448Sdavidch
4572179771Sdavidch		fw.text_addr = bce_CP_b06FwTextAddr;
4573179771Sdavidch		fw.text_len = bce_CP_b06FwTextLen;
4574179771Sdavidch		fw.text_index = 0;
4575179771Sdavidch		fw.text = bce_CP_b06FwText;
4576179771Sdavidch
4577179771Sdavidch		fw.data_addr = bce_CP_b06FwDataAddr;
4578179771Sdavidch		fw.data_len = bce_CP_b06FwDataLen;
4579179771Sdavidch		fw.data_index = 0;
4580179771Sdavidch		fw.data = bce_CP_b06FwData;
4581179771Sdavidch
4582179771Sdavidch		fw.sbss_addr = bce_CP_b06FwSbssAddr;
4583179771Sdavidch		fw.sbss_len = bce_CP_b06FwSbssLen;
4584179771Sdavidch		fw.sbss_index = 0;
4585179771Sdavidch		fw.sbss = bce_CP_b06FwSbss;
4586179771Sdavidch
4587179771Sdavidch		fw.bss_addr = bce_CP_b06FwBssAddr;
4588179771Sdavidch		fw.bss_len = bce_CP_b06FwBssLen;
4589179771Sdavidch		fw.bss_index = 0;
4590179771Sdavidch		fw.bss = bce_CP_b06FwBss;
4591179771Sdavidch
4592179771Sdavidch		fw.rodata_addr = bce_CP_b06FwRodataAddr;
4593179771Sdavidch		fw.rodata_len = bce_CP_b06FwRodataLen;
4594179771Sdavidch		fw.rodata_index = 0;
4595179771Sdavidch		fw.rodata = bce_CP_b06FwRodata;
4596179771Sdavidch	}
4597179771Sdavidch
4598176448Sdavidch	DBPRINT(sc, BCE_INFO_RESET, "Loading CP firmware.\n");
4599176448Sdavidch	bce_load_cpu_fw(sc, &cpu_reg, &fw);
4600206268Sdavidch	bce_start_cpu(sc, &cpu_reg);
4601179771Sdavidch
4602179771Sdavidch	DBEXIT(BCE_VERBOSE_RESET);
4603157642Sps}
4604157642Sps
4605157642Sps
4606157642Sps/****************************************************************************/
4607179771Sdavidch/* Initialize the COM CPU.                                                 */
4608179771Sdavidch/*                                                                          */
4609179771Sdavidch/* Returns:                                                                 */
4610179771Sdavidch/*   Nothing.                                                               */
4611179771Sdavidch/****************************************************************************/
4612179771Sdavidchstatic void
4613179771Sdavidchbce_init_com_cpu(struct bce_softc *sc)
4614179771Sdavidch{
4615179771Sdavidch	struct cpu_reg cpu_reg;
4616179771Sdavidch	struct fw_info fw;
4617179771Sdavidch
4618179771Sdavidch	DBENTER(BCE_VERBOSE_RESET);
4619179771Sdavidch
4620179771Sdavidch	cpu_reg.mode = BCE_COM_CPU_MODE;
4621179771Sdavidch	cpu_reg.mode_value_halt = BCE_COM_CPU_MODE_SOFT_HALT;
4622179771Sdavidch	cpu_reg.mode_value_sstep = BCE_COM_CPU_MODE_STEP_ENA;
4623179771Sdavidch	cpu_reg.state = BCE_COM_CPU_STATE;
4624179771Sdavidch	cpu_reg.state_value_clear = 0xffffff;
4625179771Sdavidch	cpu_reg.gpr0 = BCE_COM_CPU_REG_FILE;
4626179771Sdavidch	cpu_reg.evmask = BCE_COM_CPU_EVENT_MASK;
4627179771Sdavidch	cpu_reg.pc = BCE_COM_CPU_PROGRAM_COUNTER;
4628179771Sdavidch	cpu_reg.inst = BCE_COM_CPU_INSTRUCTION;
4629179771Sdavidch	cpu_reg.bp = BCE_COM_CPU_HW_BREAKPOINT;
4630179771Sdavidch	cpu_reg.spad_base = BCE_COM_SCRATCH;
4631179771Sdavidch	cpu_reg.mips_view_base = 0x8000000;
4632179771Sdavidch
4633226123Syongari	if (BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5709) {
4634179771Sdavidch		fw.ver_major = bce_COM_b09FwReleaseMajor;
4635179771Sdavidch		fw.ver_minor = bce_COM_b09FwReleaseMinor;
4636179771Sdavidch		fw.ver_fix = bce_COM_b09FwReleaseFix;
4637179771Sdavidch		fw.start_addr = bce_COM_b09FwStartAddr;
4638179771Sdavidch
4639179771Sdavidch		fw.text_addr = bce_COM_b09FwTextAddr;
4640179771Sdavidch		fw.text_len = bce_COM_b09FwTextLen;
4641179771Sdavidch		fw.text_index = 0;
4642179771Sdavidch		fw.text = bce_COM_b09FwText;
4643179771Sdavidch
4644179771Sdavidch		fw.data_addr = bce_COM_b09FwDataAddr;
4645179771Sdavidch		fw.data_len = bce_COM_b09FwDataLen;
4646179771Sdavidch		fw.data_index = 0;
4647179771Sdavidch		fw.data = bce_COM_b09FwData;
4648179771Sdavidch
4649179771Sdavidch		fw.sbss_addr = bce_COM_b09FwSbssAddr;
4650179771Sdavidch		fw.sbss_len = bce_COM_b09FwSbssLen;
4651179771Sdavidch		fw.sbss_index = 0;
4652179771Sdavidch		fw.sbss = bce_COM_b09FwSbss;
4653179771Sdavidch
4654179771Sdavidch		fw.bss_addr = bce_COM_b09FwBssAddr;
4655179771Sdavidch		fw.bss_len = bce_COM_b09FwBssLen;
4656179771Sdavidch		fw.bss_index = 0;
4657179771Sdavidch		fw.bss = bce_COM_b09FwBss;
4658179771Sdavidch
4659179771Sdavidch		fw.rodata_addr = bce_COM_b09FwRodataAddr;
4660179771Sdavidch		fw.rodata_len = bce_COM_b09FwRodataLen;
4661179771Sdavidch		fw.rodata_index = 0;
4662179771Sdavidch		fw.rodata = bce_COM_b09FwRodata;
4663179771Sdavidch	} else {
4664179771Sdavidch		fw.ver_major = bce_COM_b06FwReleaseMajor;
4665179771Sdavidch		fw.ver_minor = bce_COM_b06FwReleaseMinor;
4666179771Sdavidch		fw.ver_fix = bce_COM_b06FwReleaseFix;
4667179771Sdavidch		fw.start_addr = bce_COM_b06FwStartAddr;
4668179771Sdavidch
4669179771Sdavidch		fw.text_addr = bce_COM_b06FwTextAddr;
4670179771Sdavidch		fw.text_len = bce_COM_b06FwTextLen;
4671179771Sdavidch		fw.text_index = 0;
4672179771Sdavidch		fw.text = bce_COM_b06FwText;
4673179771Sdavidch
4674179771Sdavidch		fw.data_addr = bce_COM_b06FwDataAddr;
4675179771Sdavidch		fw.data_len = bce_COM_b06FwDataLen;
4676179771Sdavidch		fw.data_index = 0;
4677179771Sdavidch		fw.data = bce_COM_b06FwData;
4678179771Sdavidch
4679179771Sdavidch		fw.sbss_addr = bce_COM_b06FwSbssAddr;
4680179771Sdavidch		fw.sbss_len = bce_COM_b06FwSbssLen;
4681179771Sdavidch		fw.sbss_index = 0;
4682179771Sdavidch		fw.sbss = bce_COM_b06FwSbss;
4683179771Sdavidch
4684179771Sdavidch		fw.bss_addr = bce_COM_b06FwBssAddr;
4685179771Sdavidch		fw.bss_len = bce_COM_b06FwBssLen;
4686179771Sdavidch		fw.bss_index = 0;
4687179771Sdavidch		fw.bss = bce_COM_b06FwBss;
4688179771Sdavidch
4689179771Sdavidch		fw.rodata_addr = bce_COM_b06FwRodataAddr;
4690179771Sdavidch		fw.rodata_len = bce_COM_b06FwRodataLen;
4691179771Sdavidch		fw.rodata_index = 0;
4692179771Sdavidch		fw.rodata = bce_COM_b06FwRodata;
4693179771Sdavidch	}
4694179771Sdavidch
4695179771Sdavidch	DBPRINT(sc, BCE_INFO_RESET, "Loading COM firmware.\n");
4696179771Sdavidch	bce_load_cpu_fw(sc, &cpu_reg, &fw);
4697206268Sdavidch	bce_start_cpu(sc, &cpu_reg);
4698179771Sdavidch
4699179771Sdavidch	DBEXIT(BCE_VERBOSE_RESET);
4700179771Sdavidch}
4701179771Sdavidch
4702179771Sdavidch
4703179771Sdavidch/****************************************************************************/
4704179771Sdavidch/* Initialize the RV2P, RX, TX, TPAT, COM, and CP CPUs.                     */
4705179771Sdavidch/*                                                                          */
4706179771Sdavidch/* Loads the firmware for each CPU and starts the CPU.                      */
4707179771Sdavidch/*                                                                          */
4708179771Sdavidch/* Returns:                                                                 */
4709179771Sdavidch/*   Nothing.                                                               */
4710179771Sdavidch/****************************************************************************/
4711179771Sdavidchstatic void
4712179771Sdavidchbce_init_cpus(struct bce_softc *sc)
4713179771Sdavidch{
4714179771Sdavidch	DBENTER(BCE_VERBOSE_RESET);
4715179771Sdavidch
4716226123Syongari	if (BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5709) {
4717189325Sdavidch
4718189325Sdavidch		if ((BCE_CHIP_REV(sc) == BCE_CHIP_REV_Ax)) {
4719207411Sdavidch			bce_load_rv2p_fw(sc, bce_xi90_rv2p_proc1,
4720207411Sdavidch			    sizeof(bce_xi90_rv2p_proc1), RV2P_PROC1);
4721207411Sdavidch			bce_load_rv2p_fw(sc, bce_xi90_rv2p_proc2,
4722207411Sdavidch			    sizeof(bce_xi90_rv2p_proc2), RV2P_PROC2);
4723189325Sdavidch		} else {
4724207411Sdavidch			bce_load_rv2p_fw(sc, bce_xi_rv2p_proc1,
4725207411Sdavidch			    sizeof(bce_xi_rv2p_proc1), RV2P_PROC1);
4726207411Sdavidch			bce_load_rv2p_fw(sc, bce_xi_rv2p_proc2,
4727207411Sdavidch			    sizeof(bce_xi_rv2p_proc2), RV2P_PROC2);
4728189325Sdavidch		}
4729189325Sdavidch
4730179771Sdavidch	} else {
4731207411Sdavidch		bce_load_rv2p_fw(sc, bce_rv2p_proc1,
4732207411Sdavidch		    sizeof(bce_rv2p_proc1), RV2P_PROC1);
4733189325Sdavidch		bce_load_rv2p_fw(sc, bce_rv2p_proc2,
4734207411Sdavidch		    sizeof(bce_rv2p_proc2), RV2P_PROC2);
4735179771Sdavidch	}
4736179771Sdavidch
4737179771Sdavidch	bce_init_rxp_cpu(sc);
4738179771Sdavidch	bce_init_txp_cpu(sc);
4739179771Sdavidch	bce_init_tpat_cpu(sc);
4740179771Sdavidch	bce_init_com_cpu(sc);
4741179771Sdavidch	bce_init_cp_cpu(sc);
4742179771Sdavidch
4743179771Sdavidch	DBEXIT(BCE_VERBOSE_RESET);
4744179771Sdavidch}
4745179771Sdavidch
4746179771Sdavidch
4747179771Sdavidch/****************************************************************************/
4748157642Sps/* Initialize context memory.                                               */
4749157642Sps/*                                                                          */
4750157642Sps/* Clears the memory associated with each Context ID (CID).                 */
4751157642Sps/*                                                                          */
4752157642Sps/* Returns:                                                                 */
4753157642Sps/*   Nothing.                                                               */
4754157642Sps/****************************************************************************/
4755210259Syongaristatic int
4756176448Sdavidchbce_init_ctx(struct bce_softc *sc)
4757157642Sps{
4758210259Syongari	u32 offset, val, vcid_addr;
4759210259Syongari	int i, j, rc, retry_cnt;
4760157642Sps
4761210259Syongari	rc = 0;
4762179771Sdavidch	DBENTER(BCE_VERBOSE_RESET | BCE_VERBOSE_CTX);
4763157642Sps
4764226123Syongari	if (BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5709) {
4765210259Syongari		retry_cnt = CTX_INIT_RETRY_COUNT;
4766157642Sps
4767179771Sdavidch		DBPRINT(sc, BCE_INFO_CTX, "Initializing 5709 context.\n");
4768157642Sps
4769179771Sdavidch		/*
4770179771Sdavidch		 * BCM5709 context memory may be cached
4771179771Sdavidch		 * in host memory so prepare the host memory
4772179771Sdavidch		 * for access.
4773179771Sdavidch		 */
4774207411Sdavidch		val = BCE_CTX_COMMAND_ENABLED |
4775206268Sdavidch		    BCE_CTX_COMMAND_MEM_INIT | (1 << 12);
4776179771Sdavidch		val |= (BCM_PAGE_BITS - 8) << 16;
4777179771Sdavidch		REG_WR(sc, BCE_CTX_COMMAND, val);
4778157642Sps
4779179771Sdavidch		/* Wait for mem init command to complete. */
4780179771Sdavidch		for (i = 0; i < retry_cnt; i++) {
4781179771Sdavidch			val = REG_RD(sc, BCE_CTX_COMMAND);
4782179771Sdavidch			if (!(val & BCE_CTX_COMMAND_MEM_INIT))
4783179771Sdavidch				break;
4784179771Sdavidch			DELAY(2);
4785179771Sdavidch		}
4786210259Syongari		if ((val & BCE_CTX_COMMAND_MEM_INIT) != 0) {
4787210259Syongari			BCE_PRINTF("%s(): Context memory initialization failed!\n",
4788210259Syongari			    __FUNCTION__);
4789210259Syongari			rc = EBUSY;
4790210259Syongari			goto init_ctx_fail;
4791210259Syongari		}
4792182293Sdavidch
4793179771Sdavidch		for (i = 0; i < sc->ctx_pages; i++) {
4794206268Sdavidch			/* Set the physical address of the context memory. */
4795179771Sdavidch			REG_WR(sc, BCE_CTX_HOST_PAGE_TBL_DATA0,
4796206268Sdavidch			    BCE_ADDR_LO(sc->ctx_paddr[i] & 0xfffffff0) |
4797206268Sdavidch			    BCE_CTX_HOST_PAGE_TBL_DATA0_VALID);
4798179771Sdavidch			REG_WR(sc, BCE_CTX_HOST_PAGE_TBL_DATA1,
4799206268Sdavidch			    BCE_ADDR_HI(sc->ctx_paddr[i]));
4800179771Sdavidch			REG_WR(sc, BCE_CTX_HOST_PAGE_TBL_CTRL, i |
4801206268Sdavidch			    BCE_CTX_HOST_PAGE_TBL_CTRL_WRITE_REQ);
4802179771Sdavidch
4803206268Sdavidch			/* Verify the context memory write was successful. */
4804179771Sdavidch			for (j = 0; j < retry_cnt; j++) {
4805179771Sdavidch				val = REG_RD(sc, BCE_CTX_HOST_PAGE_TBL_CTRL);
4806207411Sdavidch				if ((val &
4807206268Sdavidch				    BCE_CTX_HOST_PAGE_TBL_CTRL_WRITE_REQ) == 0)
4808179771Sdavidch					break;
4809179771Sdavidch				DELAY(5);
4810179771Sdavidch			}
4811210259Syongari			if ((val & BCE_CTX_HOST_PAGE_TBL_CTRL_WRITE_REQ) != 0) {
4812210259Syongari				BCE_PRINTF("%s(): Failed to initialize "
4813210259Syongari				    "context page %d!\n", __FUNCTION__, i);
4814210259Syongari				rc = EBUSY;
4815210259Syongari				goto init_ctx_fail;
4816210259Syongari			}
4817179771Sdavidch		}
4818179771Sdavidch	} else {
4819179771Sdavidch
4820179771Sdavidch		DBPRINT(sc, BCE_INFO, "Initializing 5706/5708 context.\n");
4821179771Sdavidch
4822179771Sdavidch		/*
4823179771Sdavidch		 * For the 5706/5708, context memory is local to
4824179771Sdavidch		 * the controller, so initialize the controller
4825179771Sdavidch		 * context memory.
4826179771Sdavidch		 */
4827179771Sdavidch
4828179771Sdavidch		vcid_addr = GET_CID_ADDR(96);
4829179771Sdavidch		while (vcid_addr) {
4830179771Sdavidch
4831179771Sdavidch			vcid_addr -= PHY_CTX_SIZE;
4832179771Sdavidch
4833179771Sdavidch			REG_WR(sc, BCE_CTX_VIRT_ADDR, 0);
4834179771Sdavidch			REG_WR(sc, BCE_CTX_PAGE_TBL, vcid_addr);
4835179771Sdavidch
4836206268Sdavidch			for(offset = 0; offset < PHY_CTX_SIZE; offset += 4) {
4837206268Sdavidch				CTX_WR(sc, 0x00, offset, 0);
4838206268Sdavidch			}
4839179771Sdavidch
4840176448Sdavidch			REG_WR(sc, BCE_CTX_VIRT_ADDR, vcid_addr);
4841179771Sdavidch			REG_WR(sc, BCE_CTX_PAGE_TBL, vcid_addr);
4842179771Sdavidch		}
4843176448Sdavidch
4844157642Sps	}
4845210259Syongariinit_ctx_fail:
4846179771Sdavidch	DBEXIT(BCE_VERBOSE_RESET | BCE_VERBOSE_CTX);
4847210259Syongari	return (rc);
4848157642Sps}
4849157642Sps
4850182293Sdavidch
4851157642Sps/****************************************************************************/
4852157642Sps/* Fetch the permanent MAC address of the controller.                       */
4853157642Sps/*                                                                          */
4854157642Sps/* Returns:                                                                 */
4855157642Sps/*   Nothing.                                                               */
4856157642Sps/****************************************************************************/
4857157642Spsstatic void
4858157642Spsbce_get_mac_addr(struct bce_softc *sc)
4859157642Sps{
4860157642Sps	u32 mac_lo = 0, mac_hi = 0;
4861157642Sps
4862179771Sdavidch	DBENTER(BCE_VERBOSE_RESET);
4863207411Sdavidch
4864157642Sps	/*
4865157642Sps	 * The NetXtreme II bootcode populates various NIC
4866157642Sps	 * power-on and runtime configuration items in a
4867157642Sps	 * shared memory area.  The factory configured MAC
4868157642Sps	 * address is available from both NVRAM and the
4869157642Sps	 * shared memory area so we'll read the value from
4870157642Sps	 * shared memory for speed.
4871157642Sps	 */
4872157642Sps
4873194781Sdavidch	mac_hi = bce_shmem_rd(sc, BCE_PORT_HW_CFG_MAC_UPPER);
4874194781Sdavidch	mac_lo = bce_shmem_rd(sc, BCE_PORT_HW_CFG_MAC_LOWER);
4875157642Sps
4876157642Sps	if ((mac_lo == 0) && (mac_hi == 0)) {
4877179771Sdavidch		BCE_PRINTF("%s(%d): Invalid Ethernet address!\n",
4878207411Sdavidch		    __FILE__, __LINE__);
4879157642Sps	} else {
4880157642Sps		sc->eaddr[0] = (u_char)(mac_hi >> 8);
4881157642Sps		sc->eaddr[1] = (u_char)(mac_hi >> 0);
4882157642Sps		sc->eaddr[2] = (u_char)(mac_lo >> 24);
4883157642Sps		sc->eaddr[3] = (u_char)(mac_lo >> 16);
4884157642Sps		sc->eaddr[4] = (u_char)(mac_lo >> 8);
4885157642Sps		sc->eaddr[5] = (u_char)(mac_lo >> 0);
4886157642Sps	}
4887157642Sps
4888207411Sdavidch	DBPRINT(sc, BCE_INFO_MISC, "Permanent Ethernet "
4889207411Sdavidch	    "address = %6D\n", sc->eaddr, ":");
4890179771Sdavidch	DBEXIT(BCE_VERBOSE_RESET);
4891157642Sps}
4892157642Sps
4893157642Sps
4894157642Sps/****************************************************************************/
4895157642Sps/* Program the MAC address.                                                 */
4896157642Sps/*                                                                          */
4897157642Sps/* Returns:                                                                 */
4898157642Sps/*   Nothing.                                                               */
4899157642Sps/****************************************************************************/
4900157642Spsstatic void
4901157642Spsbce_set_mac_addr(struct bce_softc *sc)
4902157642Sps{
4903157642Sps	u32 val;
4904157642Sps	u8 *mac_addr = sc->eaddr;
4905157642Sps
4906179771Sdavidch	/* ToDo: Add support for setting multiple MAC addresses. */
4907179771Sdavidch
4908179771Sdavidch	DBENTER(BCE_VERBOSE_RESET);
4909207411Sdavidch	DBPRINT(sc, BCE_INFO_MISC, "Setting Ethernet address = "
4910207411Sdavidch	    "%6D\n", sc->eaddr, ":");
4911157642Sps
4912157642Sps	val = (mac_addr[0] << 8) | mac_addr[1];
4913157642Sps
4914157642Sps	REG_WR(sc, BCE_EMAC_MAC_MATCH0, val);
4915157642Sps
4916157642Sps	val = (mac_addr[2] << 24) | (mac_addr[3] << 16) |
4917207411Sdavidch	    (mac_addr[4] << 8) | mac_addr[5];
4918157642Sps
4919157642Sps	REG_WR(sc, BCE_EMAC_MAC_MATCH1, val);
4920179771Sdavidch
4921179771Sdavidch	DBEXIT(BCE_VERBOSE_RESET);
4922157642Sps}
4923157642Sps
4924157642Sps
4925157642Sps/****************************************************************************/
4926157642Sps/* Stop the controller.                                                     */
4927157642Sps/*                                                                          */
4928157642Sps/* Returns:                                                                 */
4929157642Sps/*   Nothing.                                                               */
4930157642Sps/****************************************************************************/
4931157642Spsstatic void
4932157642Spsbce_stop(struct bce_softc *sc)
4933157642Sps{
4934157642Sps	struct ifnet *ifp;
4935157642Sps
4936179771Sdavidch	DBENTER(BCE_VERBOSE_RESET);
4937157642Sps
4938157642Sps	BCE_LOCK_ASSERT(sc);
4939157642Sps
4940157642Sps	ifp = sc->bce_ifp;
4941157642Sps
4942170810Sdavidch	callout_stop(&sc->bce_tick_callout);
4943157642Sps
4944157642Sps	/* Disable the transmit/receive blocks. */
4945179771Sdavidch	REG_WR(sc, BCE_MISC_ENABLE_CLR_BITS, BCE_MISC_ENABLE_CLR_DEFAULT);
4946157642Sps	REG_RD(sc, BCE_MISC_ENABLE_CLR_BITS);
4947157642Sps	DELAY(20);
4948157642Sps
4949157642Sps	bce_disable_intr(sc);
4950157642Sps
4951171667Sdavidch	/* Free RX buffers. */
4952218423Sdavidch	if (bce_hdr_split == TRUE) {
4953218423Sdavidch		bce_free_pg_chain(sc);
4954218423Sdavidch	}
4955157642Sps	bce_free_rx_chain(sc);
4956157642Sps
4957157642Sps	/* Free TX buffers. */
4958157642Sps	bce_free_tx_chain(sc);
4959157642Sps
4960165933Sdelphij	sc->watchdog_timer = 0;
4961157642Sps
4962206268Sdavidch	sc->bce_link_up = FALSE;
4963157642Sps
4964157642Sps	ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
4965157642Sps
4966179771Sdavidch	DBEXIT(BCE_VERBOSE_RESET);
4967157642Sps}
4968157642Sps
4969157642Sps
4970157642Spsstatic int
4971157642Spsbce_reset(struct bce_softc *sc, u32 reset_code)
4972157642Sps{
4973235816Syongari	u32 emac_mode_save, val;
4974157642Sps	int i, rc = 0;
4975235816Syongari	static const u32 emac_mode_mask = BCE_EMAC_MODE_PORT |
4976235816Syongari	    BCE_EMAC_MODE_HALF_DUPLEX | BCE_EMAC_MODE_25G;
4977157642Sps
4978179771Sdavidch	DBENTER(BCE_VERBOSE_RESET);
4979179771Sdavidch
4980179771Sdavidch	DBPRINT(sc, BCE_VERBOSE_RESET, "%s(): reset_code = 0x%08X\n",
4981207411Sdavidch	    __FUNCTION__, reset_code);
4982157642Sps
4983235816Syongari	/*
4984235816Syongari	 * If ASF/IPMI is operational, then the EMAC Mode register already
4985235816Syongari	 * contains appropriate values for the link settings that have
4986235816Syongari	 * been auto-negotiated.  Resetting the chip will clobber those
4987235816Syongari	 * values.  Save the important bits so we can restore them after
4988235816Syongari	 * the reset.
4989235816Syongari	 */
4990235816Syongari	emac_mode_save = REG_RD(sc, BCE_EMAC_MODE) & emac_mode_mask;
4991235816Syongari
4992157642Sps	/* Wait for pending PCI transactions to complete. */
4993157642Sps	REG_WR(sc, BCE_MISC_ENABLE_CLR_BITS,
4994207411Sdavidch	    BCE_MISC_ENABLE_CLR_BITS_TX_DMA_ENABLE |
4995207411Sdavidch	    BCE_MISC_ENABLE_CLR_BITS_DMA_ENGINE_ENABLE |
4996207411Sdavidch	    BCE_MISC_ENABLE_CLR_BITS_RX_DMA_ENABLE |
4997207411Sdavidch	    BCE_MISC_ENABLE_CLR_BITS_HOST_COALESCE_ENABLE);
4998157642Sps	val = REG_RD(sc, BCE_MISC_ENABLE_CLR_BITS);
4999157642Sps	DELAY(5);
5000157642Sps
5001179771Sdavidch	/* Disable DMA */
5002226123Syongari	if (BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5709) {
5003179771Sdavidch		val = REG_RD(sc, BCE_MISC_NEW_CORE_CTL);
5004179771Sdavidch		val &= ~BCE_MISC_NEW_CORE_CTL_DMA_ENABLE;
5005179771Sdavidch		REG_WR(sc, BCE_MISC_NEW_CORE_CTL, val);
5006179771Sdavidch	}
5007179771Sdavidch
5008157642Sps	/* Assume bootcode is running. */
5009206268Sdavidch	sc->bce_fw_timed_out = FALSE;
5010206268Sdavidch	sc->bce_drv_cardiac_arrest = FALSE;
5011157642Sps
5012157642Sps	/* Give the firmware a chance to prepare for the reset. */
5013157642Sps	rc = bce_fw_sync(sc, BCE_DRV_MSG_DATA_WAIT0 | reset_code);
5014157642Sps	if (rc)
5015157642Sps		goto bce_reset_exit;
5016157642Sps
5017157642Sps	/* Set a firmware reminder that this is a soft reset. */
5018194781Sdavidch	bce_shmem_wr(sc, BCE_DRV_RESET_SIGNATURE, BCE_DRV_RESET_SIGNATURE_MAGIC);
5019157642Sps
5020157642Sps	/* Dummy read to force the chip to complete all current transactions. */
5021157642Sps	val = REG_RD(sc, BCE_MISC_ID);
5022157642Sps
5023157642Sps	/* Chip reset. */
5024226123Syongari	if (BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5709) {
5025179771Sdavidch		REG_WR(sc, BCE_MISC_COMMAND, BCE_MISC_COMMAND_SW_RESET);
5026179771Sdavidch		REG_RD(sc, BCE_MISC_COMMAND);
5027179771Sdavidch		DELAY(5);
5028157642Sps
5029179771Sdavidch		val = BCE_PCICFG_MISC_CONFIG_REG_WINDOW_ENA |
5030207411Sdavidch		    BCE_PCICFG_MISC_CONFIG_TARGET_MB_WORD_SWAP;
5031179771Sdavidch
5032179771Sdavidch		pci_write_config(sc->bce_dev, BCE_PCICFG_MISC_CONFIG, val, 4);
5033179771Sdavidch	} else {
5034179771Sdavidch		val = BCE_PCICFG_MISC_CONFIG_CORE_RST_REQ |
5035207411Sdavidch		    BCE_PCICFG_MISC_CONFIG_REG_WINDOW_ENA |
5036207411Sdavidch		    BCE_PCICFG_MISC_CONFIG_TARGET_MB_WORD_SWAP;
5037179771Sdavidch		REG_WR(sc, BCE_PCICFG_MISC_CONFIG, val);
5038179771Sdavidch
5039179771Sdavidch		/* Allow up to 30us for reset to complete. */
5040179771Sdavidch		for (i = 0; i < 10; i++) {
5041179771Sdavidch			val = REG_RD(sc, BCE_PCICFG_MISC_CONFIG);
5042179771Sdavidch			if ((val & (BCE_PCICFG_MISC_CONFIG_CORE_RST_REQ |
5043207411Sdavidch			    BCE_PCICFG_MISC_CONFIG_CORE_RST_BSY)) == 0) {
5044179771Sdavidch				break;
5045179771Sdavidch			}
5046179771Sdavidch			DELAY(10);
5047157642Sps		}
5048157642Sps
5049179771Sdavidch		/* Check that reset completed successfully. */
5050179771Sdavidch		if (val & (BCE_PCICFG_MISC_CONFIG_CORE_RST_REQ |
5051207411Sdavidch		    BCE_PCICFG_MISC_CONFIG_CORE_RST_BSY)) {
5052179771Sdavidch			BCE_PRINTF("%s(%d): Reset failed!\n",
5053207411Sdavidch			    __FILE__, __LINE__);
5054179771Sdavidch			rc = EBUSY;
5055179771Sdavidch			goto bce_reset_exit;
5056179771Sdavidch		}
5057157642Sps	}
5058157642Sps
5059157642Sps	/* Make sure byte swapping is properly configured. */
5060157642Sps	val = REG_RD(sc, BCE_PCI_SWAP_DIAG0);
5061157642Sps	if (val != 0x01020304) {
5062179771Sdavidch		BCE_PRINTF("%s(%d): Byte swap is incorrect!\n",
5063207411Sdavidch		    __FILE__, __LINE__);
5064157642Sps		rc = ENODEV;
5065157642Sps		goto bce_reset_exit;
5066157642Sps	}
5067157642Sps
5068157642Sps	/* Just completed a reset, assume that firmware is running again. */
5069206268Sdavidch	sc->bce_fw_timed_out = FALSE;
5070206268Sdavidch	sc->bce_drv_cardiac_arrest = FALSE;
5071157642Sps
5072157642Sps	/* Wait for the firmware to finish its initialization. */
5073157642Sps	rc = bce_fw_sync(sc, BCE_DRV_MSG_DATA_WAIT1 | reset_code);
5074157642Sps	if (rc)
5075207411Sdavidch		BCE_PRINTF("%s(%d): Firmware did not complete "
5076207411Sdavidch		    "initialization!\n", __FILE__, __LINE__);
5077235151Syongari	/* Get firmware capabilities. */
5078235151Syongari	bce_fw_cap_init(sc);
5079157642Sps
5080157642Spsbce_reset_exit:
5081235816Syongari	/* Restore EMAC Mode bits needed to keep ASF/IPMI running. */
5082257307Syongari	if (reset_code == BCE_DRV_MSG_CODE_RESET) {
5083257307Syongari		val = REG_RD(sc, BCE_EMAC_MODE);
5084257307Syongari		val = (val & ~emac_mode_mask) | emac_mode_save;
5085257307Syongari		REG_WR(sc, BCE_EMAC_MODE, val);
5086257307Syongari	}
5087235816Syongari
5088179771Sdavidch	DBEXIT(BCE_VERBOSE_RESET);
5089157642Sps	return (rc);
5090157642Sps}
5091157642Sps
5092157642Sps
5093157642Spsstatic int
5094157642Spsbce_chipinit(struct bce_softc *sc)
5095157642Sps{
5096157642Sps	u32 val;
5097157642Sps	int rc = 0;
5098157642Sps
5099179771Sdavidch	DBENTER(BCE_VERBOSE_RESET);
5100157642Sps
5101179771Sdavidch	bce_disable_intr(sc);
5102157642Sps
5103179771Sdavidch	/*
5104169632Sdavidch	 * Initialize DMA byte/word swapping, configure the number of DMA
5105170392Sdavidch	 * channels and PCI clock compensation delay.
5106169632Sdavidch	 */
5107157642Sps	val = BCE_DMA_CONFIG_DATA_BYTE_SWAP |
5108207411Sdavidch	    BCE_DMA_CONFIG_DATA_WORD_SWAP |
5109157642Sps#if BYTE_ORDER == BIG_ENDIAN
5110207411Sdavidch	    BCE_DMA_CONFIG_CNTL_BYTE_SWAP |
5111157642Sps#endif
5112207411Sdavidch	    BCE_DMA_CONFIG_CNTL_WORD_SWAP |
5113207411Sdavidch	    DMA_READ_CHANS << 12 |
5114207411Sdavidch	    DMA_WRITE_CHANS << 16;
5115157642Sps
5116157642Sps	val |= (0x2 << 20) | BCE_DMA_CONFIG_CNTL_PCI_COMP_DLY;
5117157642Sps
5118157642Sps	if ((sc->bce_flags & BCE_PCIX_FLAG) && (sc->bus_speed_mhz == 133))
5119157642Sps		val |= BCE_DMA_CONFIG_PCI_FAST_CLK_CMP;
5120157642Sps
5121157642Sps	/*
5122157642Sps	 * This setting resolves a problem observed on certain Intel PCI
5123157642Sps	 * chipsets that cannot handle multiple outstanding DMA operations.
5124157642Sps	 * See errata E9_5706A1_65.
5125157642Sps	 */
5126157642Sps	if ((BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5706) &&
5127157642Sps	    (BCE_CHIP_ID(sc) != BCE_CHIP_ID_5706_A0) &&
5128157642Sps	    !(sc->bce_flags & BCE_PCIX_FLAG))
5129157642Sps		val |= BCE_DMA_CONFIG_CNTL_PING_PONG_DMA;
5130157642Sps
5131157642Sps	REG_WR(sc, BCE_DMA_CONFIG, val);
5132157642Sps
5133157642Sps	/* Enable the RX_V2P and Context state machines before access. */
5134157642Sps	REG_WR(sc, BCE_MISC_ENABLE_SET_BITS,
5135206268Sdavidch	    BCE_MISC_ENABLE_SET_BITS_HOST_COALESCE_ENABLE |
5136206268Sdavidch	    BCE_MISC_ENABLE_STATUS_BITS_RX_V2P_ENABLE |
5137206268Sdavidch	    BCE_MISC_ENABLE_STATUS_BITS_CONTEXT_ENABLE);
5138157642Sps
5139157642Sps	/* Initialize context mapping and zero out the quick contexts. */
5140210259Syongari	if ((rc = bce_init_ctx(sc)) != 0)
5141210259Syongari		goto bce_chipinit_exit;
5142157642Sps
5143157642Sps	/* Initialize the on-boards CPUs */
5144157642Sps	bce_init_cpus(sc);
5145157642Sps
5146206268Sdavidch	/* Enable management frames (NC-SI) to flow to the MCP. */
5147206268Sdavidch	if (sc->bce_flags & BCE_MFW_ENABLE_FLAG) {
5148206268Sdavidch		val = REG_RD(sc, BCE_RPM_MGMT_PKT_CTRL) | BCE_RPM_MGMT_PKT_CTRL_MGMT_EN;
5149206268Sdavidch		REG_WR(sc, BCE_RPM_MGMT_PKT_CTRL, val);
5150206268Sdavidch	}
5151202717Sdavidch
5152157642Sps	/* Prepare NVRAM for access. */
5153210257Syongari	if ((rc = bce_init_nvram(sc)) != 0)
5154157642Sps		goto bce_chipinit_exit;
5155157642Sps
5156157642Sps	/* Set the kernel bypass block size */
5157157642Sps	val = REG_RD(sc, BCE_MQ_CONFIG);
5158157642Sps	val &= ~BCE_MQ_CONFIG_KNL_BYP_BLK_SIZE;
5159157642Sps	val |= BCE_MQ_CONFIG_KNL_BYP_BLK_SIZE_256;
5160179771Sdavidch
5161182293Sdavidch	/* Enable bins used on the 5709. */
5162226123Syongari	if (BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5709) {
5163179771Sdavidch		val |= BCE_MQ_CONFIG_BIN_MQ_MODE;
5164179771Sdavidch		if (BCE_CHIP_ID(sc) == BCE_CHIP_ID_5709_A1)
5165179771Sdavidch			val |= BCE_MQ_CONFIG_HALT_DIS;
5166179771Sdavidch	}
5167179771Sdavidch
5168157642Sps	REG_WR(sc, BCE_MQ_CONFIG, val);
5169157642Sps
5170157642Sps	val = 0x10000 + (MAX_CID_CNT * MB_KERNEL_CTX_SIZE);
5171157642Sps	REG_WR(sc, BCE_MQ_KNL_BYP_WIND_START, val);
5172157642Sps	REG_WR(sc, BCE_MQ_KNL_WIND_END, val);
5173170392Sdavidch
5174169271Sdavidch	/* Set the page size and clear the RV2P processor stall bits. */
5175157642Sps	val = (BCM_PAGE_BITS - 8) << 24;
5176157642Sps	REG_WR(sc, BCE_RV2P_CONFIG, val);
5177157642Sps
5178157642Sps	/* Configure page size. */
5179157642Sps	val = REG_RD(sc, BCE_TBDR_CONFIG);
5180157642Sps	val &= ~BCE_TBDR_CONFIG_PAGE_SIZE;
5181157642Sps	val |= (BCM_PAGE_BITS - 8) << 24 | 0x40;
5182157642Sps	REG_WR(sc, BCE_TBDR_CONFIG, val);
5183157642Sps
5184179771Sdavidch	/* Set the perfect match control register to default. */
5185179771Sdavidch	REG_WR_IND(sc, BCE_RXP_PM_CTRL, 0);
5186179771Sdavidch
5187157642Spsbce_chipinit_exit:
5188179771Sdavidch	DBEXIT(BCE_VERBOSE_RESET);
5189157642Sps
5190157642Sps	return(rc);
5191157642Sps}
5192157642Sps
5193157642Sps
5194157642Sps/****************************************************************************/
5195157642Sps/* Initialize the controller in preparation to send/receive traffic.        */
5196157642Sps/*                                                                          */
5197157642Sps/* Returns:                                                                 */
5198157642Sps/*   0 for success, positive value for failure.                             */
5199157642Sps/****************************************************************************/
5200157642Spsstatic int
5201157642Spsbce_blockinit(struct bce_softc *sc)
5202157642Sps{
5203157642Sps	u32 reg, val;
5204157642Sps	int rc = 0;
5205157642Sps
5206179771Sdavidch	DBENTER(BCE_VERBOSE_RESET);
5207157642Sps
5208157642Sps	/* Load the hardware default MAC address. */
5209157642Sps	bce_set_mac_addr(sc);
5210157642Sps
5211157642Sps	/* Set the Ethernet backoff seed value */
5212157642Sps	val = sc->eaddr[0]         + (sc->eaddr[1] << 8) +
5213157642Sps	      (sc->eaddr[2] << 16) + (sc->eaddr[3]     ) +
5214157642Sps	      (sc->eaddr[4] << 8)  + (sc->eaddr[5] << 16);
5215157642Sps	REG_WR(sc, BCE_EMAC_BACKOFF_SEED, val);
5216157642Sps
5217157642Sps	sc->last_status_idx = 0;
5218157642Sps	sc->rx_mode = BCE_EMAC_RX_MODE_SORT_MODE;
5219157642Sps
5220157642Sps	/* Set up link change interrupt generation. */
5221157642Sps	REG_WR(sc, BCE_EMAC_ATTENTION_ENA, BCE_EMAC_ATTENTION_ENA_LINK);
5222157642Sps
5223157642Sps	/* Program the physical address of the status block. */
5224157642Sps	REG_WR(sc, BCE_HC_STATUS_ADDR_L,
5225206268Sdavidch	    BCE_ADDR_LO(sc->status_block_paddr));
5226157642Sps	REG_WR(sc, BCE_HC_STATUS_ADDR_H,
5227206268Sdavidch	    BCE_ADDR_HI(sc->status_block_paddr));
5228157642Sps
5229157642Sps	/* Program the physical address of the statistics block. */
5230157642Sps	REG_WR(sc, BCE_HC_STATISTICS_ADDR_L,
5231206268Sdavidch	    BCE_ADDR_LO(sc->stats_block_paddr));
5232157642Sps	REG_WR(sc, BCE_HC_STATISTICS_ADDR_H,
5233206268Sdavidch	    BCE_ADDR_HI(sc->stats_block_paddr));
5234157642Sps
5235251142Smarius	/*
5236251142Smarius	 * Program various host coalescing parameters.
5237251142Smarius	 * Trip points control how many BDs should be ready before generating
5238251142Smarius	 * an interrupt while ticks control how long a BD can sit in the chain
5239251142Smarius	 * before generating an interrupt.
5240251142Smarius	 */
5241157642Sps	REG_WR(sc, BCE_HC_TX_QUICK_CONS_TRIP,
5242251142Smarius	    (sc->bce_tx_quick_cons_trip_int << 16) |
5243251142Smarius	    sc->bce_tx_quick_cons_trip);
5244157642Sps	REG_WR(sc, BCE_HC_RX_QUICK_CONS_TRIP,
5245251142Smarius	    (sc->bce_rx_quick_cons_trip_int << 16) |
5246251142Smarius	    sc->bce_rx_quick_cons_trip);
5247157642Sps	REG_WR(sc, BCE_HC_TX_TICKS,
5248206268Sdavidch	    (sc->bce_tx_ticks_int << 16) | sc->bce_tx_ticks);
5249157642Sps	REG_WR(sc, BCE_HC_RX_TICKS,
5250206268Sdavidch	    (sc->bce_rx_ticks_int << 16) | sc->bce_rx_ticks);
5251251142Smarius	REG_WR(sc, BCE_HC_STATS_TICKS, sc->bce_stats_ticks & 0xffff00);
5252179771Sdavidch	REG_WR(sc, BCE_HC_STAT_COLLECT_TICKS, 0xbb8);  /* 3ms */
5253251142Smarius	/* Not used for L2. */
5254251142Smarius	REG_WR(sc, BCE_HC_COMP_PROD_TRIP, 0);
5255251142Smarius	REG_WR(sc, BCE_HC_COM_TICKS, 0);
5256251142Smarius	REG_WR(sc, BCE_HC_CMD_TICKS, 0);
5257157642Sps
5258179771Sdavidch	/* Configure the Host Coalescing block. */
5259179771Sdavidch	val = BCE_HC_CONFIG_RX_TMR_MODE | BCE_HC_CONFIG_TX_TMR_MODE |
5260206268Sdavidch	    BCE_HC_CONFIG_COLLECT_STATS;
5261179771Sdavidch
5262179771Sdavidch#if 0
5263179771Sdavidch	/* ToDo: Add MSI-X support. */
5264179771Sdavidch	if (sc->bce_flags & BCE_USING_MSIX_FLAG) {
5265179771Sdavidch		u32 base = ((BCE_TX_VEC - 1) * BCE_HC_SB_CONFIG_SIZE) +
5266206268Sdavidch		    BCE_HC_SB_CONFIG_1;
5267179771Sdavidch
5268179771Sdavidch		REG_WR(sc, BCE_HC_MSIX_BIT_VECTOR, BCE_HC_MSIX_BIT_VECTOR_VAL);
5269179771Sdavidch
5270179771Sdavidch		REG_WR(sc, base, BCE_HC_SB_CONFIG_1_TX_TMR_MODE |
5271206268Sdavidch		    BCE_HC_SB_CONFIG_1_ONE_SHOT);
5272179771Sdavidch
5273179771Sdavidch		REG_WR(sc, base + BCE_HC_TX_QUICK_CONS_TRIP_OFF,
5274206268Sdavidch		    (sc->tx_quick_cons_trip_int << 16) |
5275206268Sdavidch		     sc->tx_quick_cons_trip);
5276179771Sdavidch
5277179771Sdavidch		REG_WR(sc, base + BCE_HC_TX_TICKS_OFF,
5278206268Sdavidch		    (sc->tx_ticks_int << 16) | sc->tx_ticks);
5279179771Sdavidch
5280179771Sdavidch		val |= BCE_HC_CONFIG_SB_ADDR_INC_128B;
5281179771Sdavidch	}
5282179771Sdavidch
5283179771Sdavidch	/*
5284179771Sdavidch	 * Tell the HC block to automatically set the
5285179771Sdavidch	 * INT_MASK bit after an MSI/MSI-X interrupt
5286179771Sdavidch	 * is generated so the driver doesn't have to.
5287179771Sdavidch	 */
5288179771Sdavidch	if (sc->bce_flags & BCE_ONE_SHOT_MSI_FLAG)
5289179771Sdavidch		val |= BCE_HC_CONFIG_ONE_SHOT;
5290179771Sdavidch
5291179771Sdavidch	/* Set the MSI-X status blocks to 128 byte boundaries. */
5292179771Sdavidch	if (sc->bce_flags & BCE_USING_MSIX_FLAG)
5293179771Sdavidch		val |= BCE_HC_CONFIG_SB_ADDR_INC_128B;
5294179771Sdavidch#endif
5295179771Sdavidch
5296179771Sdavidch	REG_WR(sc, BCE_HC_CONFIG, val);
5297179771Sdavidch
5298157642Sps	/* Clear the internal statistics counters. */
5299157642Sps	REG_WR(sc, BCE_HC_COMMAND, BCE_HC_COMMAND_CLR_STAT_NOW);
5300157642Sps
5301157642Sps	/* Verify that bootcode is running. */
5302194781Sdavidch	reg = bce_shmem_rd(sc, BCE_DEV_INFO_SIGNATURE);
5303157642Sps
5304189325Sdavidch	DBRUNIF(DB_RANDOMTRUE(bootcode_running_failure_sim_control),
5305206268Sdavidch	    BCE_PRINTF("%s(%d): Simulating bootcode failure.\n",
5306206268Sdavidch	    __FILE__, __LINE__);
5307206268Sdavidch	    reg = 0);
5308157642Sps
5309157642Sps	if ((reg & BCE_DEV_INFO_SIGNATURE_MAGIC_MASK) !=
5310157642Sps	    BCE_DEV_INFO_SIGNATURE_MAGIC) {
5311169271Sdavidch		BCE_PRINTF("%s(%d): Bootcode not running! Found: 0x%08X, "
5312206268Sdavidch		    "Expected: 08%08X\n", __FILE__, __LINE__,
5313206268Sdavidch		    (reg & BCE_DEV_INFO_SIGNATURE_MAGIC_MASK),
5314206268Sdavidch		    BCE_DEV_INFO_SIGNATURE_MAGIC);
5315157642Sps		rc = ENODEV;
5316157642Sps		goto bce_blockinit_exit;
5317157642Sps	}
5318157642Sps
5319179771Sdavidch	/* Enable DMA */
5320226123Syongari	if (BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5709) {
5321179771Sdavidch		val = REG_RD(sc, BCE_MISC_NEW_CORE_CTL);
5322179771Sdavidch		val |= BCE_MISC_NEW_CORE_CTL_DMA_ENABLE;
5323179771Sdavidch		REG_WR(sc, BCE_MISC_NEW_CORE_CTL, val);
5324179771Sdavidch	}
5325179771Sdavidch
5326206268Sdavidch	/* Allow bootcode to apply additional fixes before enabling MAC. */
5327207411Sdavidch	rc = bce_fw_sync(sc, BCE_DRV_MSG_DATA_WAIT2 |
5328206268Sdavidch	    BCE_DRV_MSG_CODE_RESET);
5329157642Sps
5330157642Sps	/* Enable link state change interrupt generation. */
5331157642Sps	REG_WR(sc, BCE_HC_ATTN_BITS_ENABLE, STATUS_ATTN_BITS_LINK_STATE);
5332157642Sps
5333206268Sdavidch	/* Enable the RXP. */
5334206268Sdavidch	bce_start_rxp_cpu(sc);
5335202717Sdavidch
5336206268Sdavidch	/* Disable management frames (NC-SI) from flowing to the MCP. */
5337206268Sdavidch	if (sc->bce_flags & BCE_MFW_ENABLE_FLAG) {
5338207411Sdavidch		val = REG_RD(sc, BCE_RPM_MGMT_PKT_CTRL) &
5339206268Sdavidch		    ~BCE_RPM_MGMT_PKT_CTRL_MGMT_EN;
5340206268Sdavidch		REG_WR(sc, BCE_RPM_MGMT_PKT_CTRL, val);
5341206268Sdavidch	}
5342202717Sdavidch
5343157642Sps	/* Enable all remaining blocks in the MAC. */
5344226123Syongari	if (BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5709)
5345207411Sdavidch		REG_WR(sc, BCE_MISC_ENABLE_SET_BITS,
5346206268Sdavidch		    BCE_MISC_ENABLE_DEFAULT_XI);
5347182293Sdavidch	else
5348207411Sdavidch		REG_WR(sc, BCE_MISC_ENABLE_SET_BITS,
5349206268Sdavidch		    BCE_MISC_ENABLE_DEFAULT);
5350182293Sdavidch
5351157642Sps	REG_RD(sc, BCE_MISC_ENABLE_SET_BITS);
5352157642Sps	DELAY(20);
5353157642Sps
5354179771Sdavidch	/* Save the current host coalescing block settings. */
5355179771Sdavidch	sc->hc_command = REG_RD(sc, BCE_HC_COMMAND);
5356179771Sdavidch
5357157642Spsbce_blockinit_exit:
5358179771Sdavidch	DBEXIT(BCE_VERBOSE_RESET);
5359157642Sps
5360157642Sps	return (rc);
5361157642Sps}
5362157642Sps
5363157642Sps
5364157642Sps/****************************************************************************/
5365176448Sdavidch/* Encapsulate an mbuf into the rx_bd chain.                                */
5366157642Sps/*                                                                          */
5367157642Sps/* Returns:                                                                 */
5368157642Sps/*   0 for success, positive value for failure.                             */
5369157642Sps/****************************************************************************/
5370157642Spsstatic int
5371251146Smariusbce_get_rx_buf(struct bce_softc *sc, u16 prod, u16 chain_prod, u32 *prod_bseq)
5372157642Sps{
5373251146Smarius	bus_dma_segment_t segs[1];
5374157642Sps	struct mbuf *m_new = NULL;
5375171667Sdavidch	struct rx_bd *rxbd;
5376176448Sdavidch	int nsegs, error, rc = 0;
5377157642Sps#ifdef BCE_DEBUG
5378251146Smarius	u16 debug_chain_prod = chain_prod;
5379157642Sps#endif
5380157642Sps
5381179771Sdavidch	DBENTER(BCE_EXTREME_RESET | BCE_EXTREME_RECV | BCE_EXTREME_LOAD);
5382157642Sps
5383157642Sps	/* Make sure the inputs are valid. */
5384251146Smarius	DBRUNIF((chain_prod > MAX_RX_BD_ALLOC),
5385207411Sdavidch	    BCE_PRINTF("%s(%d): RX producer out of range: "
5386207411Sdavidch	    "0x%04X > 0x%04X\n", __FILE__, __LINE__,
5387251146Smarius	    chain_prod, (u16)MAX_RX_BD_ALLOC));
5388157642Sps
5389206268Sdavidch	DBPRINT(sc, BCE_EXTREME_RECV, "%s(enter): prod = 0x%04X, "
5390206268Sdavidch	    "chain_prod = 0x%04X, prod_bseq = 0x%08X\n", __FUNCTION__,
5391251146Smarius	    prod, chain_prod, *prod_bseq);
5392157642Sps
5393176448Sdavidch	/* Update some debug statistic counters */
5394179771Sdavidch	DBRUNIF((sc->free_rx_bd < sc->rx_low_watermark),
5395207411Sdavidch	    sc->rx_low_watermark = sc->free_rx_bd);
5396207411Sdavidch	DBRUNIF((sc->free_rx_bd == sc->max_rx_bd),
5397207411Sdavidch	    sc->rx_empty_count++);
5398176448Sdavidch
5399251146Smarius	/* Simulate an mbuf allocation failure. */
5400251146Smarius	DBRUNIF(DB_RANDOMTRUE(mbuf_alloc_failed_sim_control),
5401251146Smarius	    sc->mbuf_alloc_failed_count++;
5402251146Smarius	    sc->mbuf_alloc_failed_sim_count++;
5403251146Smarius	    rc = ENOBUFS;
5404251146Smarius	    goto bce_get_rx_buf_exit);
5405157642Sps
5406251146Smarius	/* This is a new mbuf allocation. */
5407251146Smarius	if (bce_hdr_split == TRUE)
5408251146Smarius		MGETHDR(m_new, M_NOWAIT, MT_DATA);
5409251146Smarius	else
5410251146Smarius		m_new = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR,
5411251146Smarius		    sc->rx_bd_mbuf_alloc_size);
5412157642Sps
5413251146Smarius	if (m_new == NULL) {
5414251146Smarius		sc->mbuf_alloc_failed_count++;
5415251146Smarius		rc = ENOBUFS;
5416251146Smarius		goto bce_get_rx_buf_exit;
5417251146Smarius	}
5418179771Sdavidch
5419251146Smarius	DBRUN(sc->debug_rx_mbuf_alloc++);
5420157642Sps
5421179771Sdavidch	/* Make sure we have a valid packet header. */
5422176448Sdavidch	M_ASSERTPKTHDR(m_new);
5423176448Sdavidch
5424179771Sdavidch	/* Initialize the mbuf size and pad if necessary for alignment. */
5425179771Sdavidch	m_new->m_pkthdr.len = m_new->m_len = sc->rx_bd_mbuf_alloc_size;
5426179695Sdavidch	m_adj(m_new, sc->rx_bd_mbuf_align_pad);
5427176448Sdavidch
5428176448Sdavidch	/* ToDo: Consider calling m_fragment() to test error handling. */
5429176448Sdavidch
5430157642Sps	/* Map the mbuf cluster into device memory. */
5431251146Smarius	error = bus_dmamap_load_mbuf_sg(sc->rx_mbuf_tag,
5432251146Smarius	    sc->rx_mbuf_map[chain_prod], m_new, segs, &nsegs, BUS_DMA_NOWAIT);
5433157642Sps
5434171667Sdavidch	/* Handle any mapping errors. */
5435157642Sps	if (error) {
5436207411Sdavidch		BCE_PRINTF("%s(%d): Error mapping mbuf into RX "
5437207411Sdavidch		    "chain (%d)!\n", __FILE__, __LINE__, error);
5438157642Sps
5439189325Sdavidch		sc->dma_map_addr_rx_failed_count++;
5440157642Sps		m_freem(m_new);
5441189325Sdavidch
5442176448Sdavidch		DBRUN(sc->debug_rx_mbuf_alloc--);
5443157642Sps
5444157642Sps		rc = ENOBUFS;
5445176448Sdavidch		goto bce_get_rx_buf_exit;
5446157642Sps	}
5447179771Sdavidch
5448176448Sdavidch	/* All mbufs must map to a single segment. */
5449176448Sdavidch	KASSERT(nsegs == 1, ("%s(): Too many segments returned (%d)!",
5450206268Sdavidch	    __FUNCTION__, nsegs));
5451157642Sps
5452176448Sdavidch	/* Setup the rx_bd for the segment. */
5453251146Smarius	rxbd = &sc->rx_bd_chain[RX_PAGE(chain_prod)][RX_IDX(chain_prod)];
5454157642Sps
5455157642Sps	rxbd->rx_bd_haddr_lo  = htole32(BCE_ADDR_LO(segs[0].ds_addr));
5456157642Sps	rxbd->rx_bd_haddr_hi  = htole32(BCE_ADDR_HI(segs[0].ds_addr));
5457157642Sps	rxbd->rx_bd_len       = htole32(segs[0].ds_len);
5458176448Sdavidch	rxbd->rx_bd_flags     = htole32(RX_BD_FLAGS_START | RX_BD_FLAGS_END);
5459179771Sdavidch	*prod_bseq += segs[0].ds_len;
5460157642Sps
5461176448Sdavidch	/* Save the mbuf and update our counter. */
5462251146Smarius	sc->rx_mbuf_ptr[chain_prod] = m_new;
5463176448Sdavidch	sc->free_rx_bd -= nsegs;
5464182293Sdavidch
5465207411Sdavidch	DBRUNMSG(BCE_INSANE_RECV,
5466206268Sdavidch	    bce_dump_rx_mbuf_chain(sc, debug_chain_prod, nsegs));
5467157642Sps
5468206268Sdavidch	DBPRINT(sc, BCE_EXTREME_RECV, "%s(exit): prod = 0x%04X, "
5469251146Smarius	    "chain_prod = 0x%04X, prod_bseq = 0x%08X\n", __FUNCTION__, prod,
5470251146Smarius	    chain_prod, *prod_bseq);
5471157642Sps
5472176448Sdavidchbce_get_rx_buf_exit:
5473179771Sdavidch	DBEXIT(BCE_EXTREME_RESET | BCE_EXTREME_RECV | BCE_EXTREME_LOAD);
5474176448Sdavidch
5475176448Sdavidch	return(rc);
5476176448Sdavidch}
5477176448Sdavidch
5478176448Sdavidch
5479176448Sdavidch/****************************************************************************/
5480206268Sdavidch/* Encapsulate an mbuf cluster into the page chain.                         */
5481176448Sdavidch/*                                                                          */
5482176448Sdavidch/* Returns:                                                                 */
5483176448Sdavidch/*   0 for success, positive value for failure.                             */
5484176448Sdavidch/****************************************************************************/
5485176448Sdavidchstatic int
5486251146Smariusbce_get_pg_buf(struct bce_softc *sc, u16 prod, u16 prod_idx)
5487176448Sdavidch{
5488251146Smarius	bus_dma_segment_t segs[1];
5489176448Sdavidch	struct mbuf *m_new = NULL;
5490176448Sdavidch	struct rx_bd *pgbd;
5491251146Smarius	int error, nsegs, rc = 0;
5492176448Sdavidch#ifdef BCE_DEBUG
5493251146Smarius	u16 debug_prod_idx = prod_idx;
5494176448Sdavidch#endif
5495176448Sdavidch
5496179771Sdavidch	DBENTER(BCE_EXTREME_RESET | BCE_EXTREME_RECV | BCE_EXTREME_LOAD);
5497176448Sdavidch
5498176448Sdavidch	/* Make sure the inputs are valid. */
5499251146Smarius	DBRUNIF((prod_idx > MAX_PG_BD_ALLOC),
5500207411Sdavidch	    BCE_PRINTF("%s(%d): page producer out of range: "
5501207411Sdavidch	    "0x%04X > 0x%04X\n", __FILE__, __LINE__,
5502251146Smarius	    prod_idx, (u16)MAX_PG_BD_ALLOC));
5503176448Sdavidch
5504179771Sdavidch	DBPRINT(sc, BCE_EXTREME_RECV, "%s(enter): prod = 0x%04X, "
5505251146Smarius	    "chain_prod = 0x%04X\n", __FUNCTION__, prod, prod_idx);
5506176448Sdavidch
5507176448Sdavidch	/* Update counters if we've hit a new low or run out of pages. */
5508179771Sdavidch	DBRUNIF((sc->free_pg_bd < sc->pg_low_watermark),
5509206268Sdavidch	    sc->pg_low_watermark = sc->free_pg_bd);
5510176448Sdavidch	DBRUNIF((sc->free_pg_bd == sc->max_pg_bd), sc->pg_empty_count++);
5511176448Sdavidch
5512251146Smarius	/* Simulate an mbuf allocation failure. */
5513251146Smarius	DBRUNIF(DB_RANDOMTRUE(mbuf_alloc_failed_sim_control),
5514251146Smarius	    sc->mbuf_alloc_failed_count++;
5515251146Smarius	    sc->mbuf_alloc_failed_sim_count++;
5516251146Smarius	    rc = ENOBUFS;
5517251146Smarius	    goto bce_get_pg_buf_exit);
5518176448Sdavidch
5519251146Smarius	/* This is a new mbuf allocation. */
5520251146Smarius	m_new = m_getcl(M_NOWAIT, MT_DATA, 0);
5521251146Smarius	if (m_new == NULL) {
5522251146Smarius		sc->mbuf_alloc_failed_count++;
5523251146Smarius		rc = ENOBUFS;
5524251146Smarius		goto bce_get_pg_buf_exit;
5525251146Smarius	}
5526176448Sdavidch
5527251146Smarius	DBRUN(sc->debug_pg_mbuf_alloc++);
5528176448Sdavidch
5529251142Smarius	m_new->m_len = MCLBYTES;
5530157642Sps
5531176448Sdavidch	/* ToDo: Consider calling m_fragment() to test error handling. */
5532176448Sdavidch
5533176448Sdavidch	/* Map the mbuf cluster into device memory. */
5534251146Smarius	error = bus_dmamap_load_mbuf_sg(sc->pg_mbuf_tag,
5535251146Smarius	    sc->pg_mbuf_map[prod_idx], m_new, segs, &nsegs, BUS_DMA_NOWAIT);
5536176448Sdavidch
5537176448Sdavidch	/* Handle any mapping errors. */
5538176448Sdavidch	if (error) {
5539176448Sdavidch		BCE_PRINTF("%s(%d): Error mapping mbuf into page chain!\n",
5540206268Sdavidch		    __FILE__, __LINE__);
5541176448Sdavidch
5542176448Sdavidch		m_freem(m_new);
5543176448Sdavidch		DBRUN(sc->debug_pg_mbuf_alloc--);
5544176448Sdavidch
5545176448Sdavidch		rc = ENOBUFS;
5546176448Sdavidch		goto bce_get_pg_buf_exit;
5547176448Sdavidch	}
5548176448Sdavidch
5549251146Smarius	/* All mbufs must map to a single segment. */
5550251146Smarius	KASSERT(nsegs == 1, ("%s(): Too many segments returned (%d)!",
5551251146Smarius	    __FUNCTION__, nsegs));
5552251146Smarius
5553192281Sdelphij	/* ToDo: Do we need bus_dmamap_sync(,,BUS_DMASYNC_PREREAD) here? */
5554176448Sdavidch
5555179771Sdavidch	/*
5556176448Sdavidch	 * The page chain uses the same rx_bd data structure
5557176448Sdavidch	 * as the receive chain but doesn't require a byte sequence (bseq).
5558176448Sdavidch	 */
5559251146Smarius	pgbd = &sc->pg_bd_chain[PG_PAGE(prod_idx)][PG_IDX(prod_idx)];
5560176448Sdavidch
5561251146Smarius	pgbd->rx_bd_haddr_lo  = htole32(BCE_ADDR_LO(segs[0].ds_addr));
5562251146Smarius	pgbd->rx_bd_haddr_hi  = htole32(BCE_ADDR_HI(segs[0].ds_addr));
5563251142Smarius	pgbd->rx_bd_len       = htole32(MCLBYTES);
5564176448Sdavidch	pgbd->rx_bd_flags     = htole32(RX_BD_FLAGS_START | RX_BD_FLAGS_END);
5565176448Sdavidch
5566157642Sps	/* Save the mbuf and update our counter. */
5567251146Smarius	sc->pg_mbuf_ptr[prod_idx] = m_new;
5568176448Sdavidch	sc->free_pg_bd--;
5569157642Sps
5570207411Sdavidch	DBRUNMSG(BCE_INSANE_RECV,
5571206268Sdavidch	    bce_dump_pg_mbuf_chain(sc, debug_prod_idx, 1));
5572157642Sps
5573179771Sdavidch	DBPRINT(sc, BCE_EXTREME_RECV, "%s(exit): prod = 0x%04X, "
5574251146Smarius	    "prod_idx = 0x%04X\n", __FUNCTION__, prod, prod_idx);
5575157642Sps
5576176448Sdavidchbce_get_pg_buf_exit:
5577179771Sdavidch	DBEXIT(BCE_EXTREME_RESET | BCE_EXTREME_RECV | BCE_EXTREME_LOAD);
5578157642Sps
5579157642Sps	return(rc);
5580157642Sps}
5581157642Sps
5582206268Sdavidch
5583179771Sdavidch/****************************************************************************/
5584179771Sdavidch/* Initialize the TX context memory.                                        */
5585179771Sdavidch/*                                                                          */
5586179771Sdavidch/* Returns:                                                                 */
5587179771Sdavidch/*   Nothing                                                                */
5588179771Sdavidch/****************************************************************************/
5589179771Sdavidchstatic void
5590179771Sdavidchbce_init_tx_context(struct bce_softc *sc)
5591179771Sdavidch{
5592179771Sdavidch	u32 val;
5593157642Sps
5594179771Sdavidch	DBENTER(BCE_VERBOSE_RESET | BCE_VERBOSE_SEND | BCE_VERBOSE_CTX);
5595179771Sdavidch
5596179771Sdavidch	/* Initialize the context ID for an L2 TX chain. */
5597226123Syongari	if (BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5709) {
5598179771Sdavidch		/* Set the CID type to support an L2 connection. */
5599207411Sdavidch		val = BCE_L2CTX_TX_TYPE_TYPE_L2_XI |
5600206268Sdavidch		    BCE_L2CTX_TX_TYPE_SIZE_L2_XI;
5601182293Sdavidch		CTX_WR(sc, GET_CID_ADDR(TX_CID), BCE_L2CTX_TX_TYPE_XI, val);
5602182293Sdavidch		val = BCE_L2CTX_TX_CMD_TYPE_TYPE_L2_XI | (8 << 16);
5603207411Sdavidch		CTX_WR(sc, GET_CID_ADDR(TX_CID),
5604206268Sdavidch		    BCE_L2CTX_TX_CMD_TYPE_XI, val);
5605179771Sdavidch
5606179771Sdavidch		/* Point the hardware to the first page in the chain. */
5607179771Sdavidch		val = BCE_ADDR_HI(sc->tx_bd_chain_paddr[0]);
5608207411Sdavidch		CTX_WR(sc, GET_CID_ADDR(TX_CID),
5609206268Sdavidch		    BCE_L2CTX_TX_TBDR_BHADDR_HI_XI, val);
5610179771Sdavidch		val = BCE_ADDR_LO(sc->tx_bd_chain_paddr[0]);
5611207411Sdavidch		CTX_WR(sc, GET_CID_ADDR(TX_CID),
5612206268Sdavidch		    BCE_L2CTX_TX_TBDR_BHADDR_LO_XI, val);
5613179771Sdavidch	} else {
5614179771Sdavidch		/* Set the CID type to support an L2 connection. */
5615182293Sdavidch		val = BCE_L2CTX_TX_TYPE_TYPE_L2 | BCE_L2CTX_TX_TYPE_SIZE_L2;
5616182293Sdavidch		CTX_WR(sc, GET_CID_ADDR(TX_CID), BCE_L2CTX_TX_TYPE, val);
5617182293Sdavidch		val = BCE_L2CTX_TX_CMD_TYPE_TYPE_L2 | (8 << 16);
5618182293Sdavidch		CTX_WR(sc, GET_CID_ADDR(TX_CID), BCE_L2CTX_TX_CMD_TYPE, val);
5619179771Sdavidch
5620179771Sdavidch		/* Point the hardware to the first page in the chain. */
5621179771Sdavidch		val = BCE_ADDR_HI(sc->tx_bd_chain_paddr[0]);
5622207411Sdavidch		CTX_WR(sc, GET_CID_ADDR(TX_CID),
5623206268Sdavidch		    BCE_L2CTX_TX_TBDR_BHADDR_HI, val);
5624179771Sdavidch		val = BCE_ADDR_LO(sc->tx_bd_chain_paddr[0]);
5625207411Sdavidch		CTX_WR(sc, GET_CID_ADDR(TX_CID),
5626206268Sdavidch		    BCE_L2CTX_TX_TBDR_BHADDR_LO, val);
5627179771Sdavidch	}
5628179771Sdavidch
5629179771Sdavidch	DBEXIT(BCE_VERBOSE_RESET | BCE_VERBOSE_SEND | BCE_VERBOSE_CTX);
5630179771Sdavidch}
5631179771Sdavidch
5632182293Sdavidch
5633157642Sps/****************************************************************************/
5634157642Sps/* Allocate memory and initialize the TX data structures.                   */
5635157642Sps/*                                                                          */
5636157642Sps/* Returns:                                                                 */
5637157642Sps/*   0 for success, positive value for failure.                             */
5638157642Sps/****************************************************************************/
5639157642Spsstatic int
5640157642Spsbce_init_tx_chain(struct bce_softc *sc)
5641157642Sps{
5642157642Sps	struct tx_bd *txbd;
5643157642Sps	int i, rc = 0;
5644157642Sps
5645179771Sdavidch	DBENTER(BCE_VERBOSE_RESET | BCE_VERBOSE_SEND | BCE_VERBOSE_LOAD);
5646157642Sps
5647157642Sps	/* Set the initial TX producer/consumer indices. */
5648157642Sps	sc->tx_prod        = 0;
5649157642Sps	sc->tx_cons        = 0;
5650157642Sps	sc->tx_prod_bseq   = 0;
5651170392Sdavidch	sc->used_tx_bd     = 0;
5652218423Sdavidch	sc->max_tx_bd      = USABLE_TX_BD_ALLOC;
5653206268Sdavidch	DBRUN(sc->tx_hi_watermark = 0);
5654176448Sdavidch	DBRUN(sc->tx_full_count = 0);
5655157642Sps
5656157642Sps	/*
5657157642Sps	 * The NetXtreme II supports a linked-list structre called
5658157642Sps	 * a Buffer Descriptor Chain (or BD chain).  A BD chain
5659157642Sps	 * consists of a series of 1 or more chain pages, each of which
5660157642Sps	 * consists of a fixed number of BD entries.
5661157642Sps	 * The last BD entry on each page is a pointer to the next page
5662157642Sps	 * in the chain, and the last pointer in the BD chain
5663157642Sps	 * points back to the beginning of the chain.
5664157642Sps	 */
5665157642Sps
5666157642Sps	/* Set the TX next pointer chain entries. */
5667218423Sdavidch	for (i = 0; i < sc->tx_pages; i++) {
5668157642Sps		int j;
5669157642Sps
5670157642Sps		txbd = &sc->tx_bd_chain[i][USABLE_TX_BD_PER_PAGE];
5671157642Sps
5672157642Sps		/* Check if we've reached the last page. */
5673218423Sdavidch		if (i == (sc->tx_pages - 1))
5674157642Sps			j = 0;
5675157642Sps		else
5676157642Sps			j = i + 1;
5677157642Sps
5678218423Sdavidch		txbd->tx_bd_haddr_hi =
5679218423Sdavidch		    htole32(BCE_ADDR_HI(sc->tx_bd_chain_paddr[j]));
5680218423Sdavidch		txbd->tx_bd_haddr_lo =
5681218423Sdavidch		    htole32(BCE_ADDR_LO(sc->tx_bd_chain_paddr[j]));
5682157642Sps	}
5683157642Sps
5684179771Sdavidch	bce_init_tx_context(sc);
5685157642Sps
5686218423Sdavidch	DBRUNMSG(BCE_INSANE_SEND, bce_dump_tx_chain(sc, 0, TOTAL_TX_BD_ALLOC));
5687179771Sdavidch	DBEXIT(BCE_VERBOSE_RESET | BCE_VERBOSE_SEND | BCE_VERBOSE_LOAD);
5688157642Sps
5689157642Sps	return(rc);
5690157642Sps}
5691157642Sps
5692157642Sps
5693157642Sps/****************************************************************************/
5694157642Sps/* Free memory and clear the TX data structures.                            */
5695157642Sps/*                                                                          */
5696157642Sps/* Returns:                                                                 */
5697157642Sps/*   Nothing.                                                               */
5698157642Sps/****************************************************************************/
5699157642Spsstatic void
5700157642Spsbce_free_tx_chain(struct bce_softc *sc)
5701157642Sps{
5702157642Sps	int i;
5703157642Sps
5704179771Sdavidch	DBENTER(BCE_VERBOSE_RESET | BCE_VERBOSE_SEND | BCE_VERBOSE_UNLOAD);
5705157642Sps
5706157642Sps	/* Unmap, unload, and free any mbufs still in the TX mbuf chain. */
5707218423Sdavidch	for (i = 0; i < MAX_TX_BD_AVAIL; i++) {
5708157642Sps		if (sc->tx_mbuf_ptr[i] != NULL) {
5709186168Sdelphij			if (sc->tx_mbuf_map[i] != NULL)
5710207411Sdavidch				bus_dmamap_sync(sc->tx_mbuf_tag,
5711206268Sdavidch				    sc->tx_mbuf_map[i],
5712206268Sdavidch				    BUS_DMASYNC_POSTWRITE);
5713157642Sps			m_freem(sc->tx_mbuf_ptr[i]);
5714157642Sps			sc->tx_mbuf_ptr[i] = NULL;
5715176448Sdavidch			DBRUN(sc->debug_tx_mbuf_alloc--);
5716179771Sdavidch		}
5717157642Sps	}
5718157642Sps
5719157642Sps	/* Clear each TX chain page. */
5720218423Sdavidch	for (i = 0; i < sc->tx_pages; i++)
5721157642Sps		bzero((char *)sc->tx_bd_chain[i], BCE_TX_CHAIN_PAGE_SZ);
5722157642Sps
5723206268Sdavidch	sc->used_tx_bd = 0;
5724171667Sdavidch
5725157642Sps	/* Check if we lost any mbufs in the process. */
5726176448Sdavidch	DBRUNIF((sc->debug_tx_mbuf_alloc),
5727206268Sdavidch	    BCE_PRINTF("%s(%d): Memory leak! Lost %d mbufs "
5728207411Sdavidch	    "from tx chain!\n",	__FILE__, __LINE__,
5729206268Sdavidch	    sc->debug_tx_mbuf_alloc));
5730157642Sps
5731179771Sdavidch	DBEXIT(BCE_VERBOSE_RESET | BCE_VERBOSE_SEND | BCE_VERBOSE_UNLOAD);
5732157642Sps}
5733157642Sps
5734157642Sps
5735157642Sps/****************************************************************************/
5736179771Sdavidch/* Initialize the RX context memory.                                        */
5737179771Sdavidch/*                                                                          */
5738179771Sdavidch/* Returns:                                                                 */
5739179771Sdavidch/*   Nothing                                                                */
5740179771Sdavidch/****************************************************************************/
5741179771Sdavidchstatic void
5742179771Sdavidchbce_init_rx_context(struct bce_softc *sc)
5743179771Sdavidch{
5744179771Sdavidch	u32 val;
5745179771Sdavidch
5746179771Sdavidch	DBENTER(BCE_VERBOSE_RESET | BCE_VERBOSE_RECV | BCE_VERBOSE_CTX);
5747179771Sdavidch
5748206268Sdavidch	/* Init the type, size, and BD cache levels for the RX context. */
5749182293Sdavidch	val = BCE_L2CTX_RX_CTX_TYPE_CTX_BD_CHN_TYPE_VALUE |
5750206268Sdavidch	    BCE_L2CTX_RX_CTX_TYPE_SIZE_L2 |
5751206268Sdavidch	    (0x02 << BCE_L2CTX_RX_BD_PRE_READ_SHIFT);
5752179771Sdavidch
5753182293Sdavidch	/*
5754182293Sdavidch	 * Set the level for generating pause frames
5755182293Sdavidch	 * when the number of available rx_bd's gets
5756182293Sdavidch	 * too low (the low watermark) and the level
5757182293Sdavidch	 * when pause frames can be stopped (the high
5758182293Sdavidch	 * watermark).
5759182293Sdavidch	 */
5760226123Syongari	if (BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5709) {
5761179771Sdavidch		u32 lo_water, hi_water;
5762179771Sdavidch
5763210522Sjkim		if (sc->bce_flags & BCE_USING_TX_FLOW_CONTROL) {
5764207411Sdavidch			lo_water = BCE_L2CTX_RX_LO_WATER_MARK_DEFAULT;
5765207411Sdavidch		} else {
5766207411Sdavidch			lo_water = 0;
5767207411Sdavidch		}
5768207411Sdavidch
5769218423Sdavidch		if (lo_water >= USABLE_RX_BD_ALLOC) {
5770207411Sdavidch			lo_water = 0;
5771207411Sdavidch		}
5772207411Sdavidch
5773218423Sdavidch		hi_water = USABLE_RX_BD_ALLOC / 4;
5774179771Sdavidch
5775207411Sdavidch		if (hi_water <= lo_water) {
5776207411Sdavidch			lo_water = 0;
5777207411Sdavidch		}
5778207411Sdavidch
5779182293Sdavidch		lo_water /= BCE_L2CTX_RX_LO_WATER_MARK_SCALE;
5780182293Sdavidch		hi_water /= BCE_L2CTX_RX_HI_WATER_MARK_SCALE;
5781179771Sdavidch
5782179771Sdavidch		if (hi_water > 0xf)
5783179771Sdavidch			hi_water = 0xf;
5784179771Sdavidch		else if (hi_water == 0)
5785179771Sdavidch			lo_water = 0;
5786207411Sdavidch
5787182293Sdavidch		val |= (lo_water << BCE_L2CTX_RX_LO_WATER_MARK_SHIFT) |
5788207411Sdavidch		    (hi_water << BCE_L2CTX_RX_HI_WATER_MARK_SHIFT);
5789182293Sdavidch	}
5790179771Sdavidch
5791207411Sdavidch	CTX_WR(sc, GET_CID_ADDR(RX_CID), BCE_L2CTX_RX_CTX_TYPE, val);
5792179771Sdavidch
5793182293Sdavidch	/* Setup the MQ BIN mapping for l2_ctx_host_bseq. */
5794226123Syongari	if (BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5709) {
5795179771Sdavidch		val = REG_RD(sc, BCE_MQ_MAP_L2_5);
5796179771Sdavidch		REG_WR(sc, BCE_MQ_MAP_L2_5, val | BCE_MQ_MAP_L2_5_ARM);
5797179771Sdavidch	}
5798182293Sdavidch
5799179771Sdavidch	/* Point the hardware to the first page in the chain. */
5800179771Sdavidch	val = BCE_ADDR_HI(sc->rx_bd_chain_paddr[0]);
5801182293Sdavidch	CTX_WR(sc, GET_CID_ADDR(RX_CID), BCE_L2CTX_RX_NX_BDHADDR_HI, val);
5802179771Sdavidch	val = BCE_ADDR_LO(sc->rx_bd_chain_paddr[0]);
5803182293Sdavidch	CTX_WR(sc, GET_CID_ADDR(RX_CID), BCE_L2CTX_RX_NX_BDHADDR_LO, val);
5804179771Sdavidch
5805179771Sdavidch	DBEXIT(BCE_VERBOSE_RESET | BCE_VERBOSE_RECV | BCE_VERBOSE_CTX);
5806179771Sdavidch}
5807179771Sdavidch
5808179771Sdavidch
5809179771Sdavidch/****************************************************************************/
5810157642Sps/* Allocate memory and initialize the RX data structures.                   */
5811157642Sps/*                                                                          */
5812157642Sps/* Returns:                                                                 */
5813157642Sps/*   0 for success, positive value for failure.                             */
5814157642Sps/****************************************************************************/
5815157642Spsstatic int
5816157642Spsbce_init_rx_chain(struct bce_softc *sc)
5817157642Sps{
5818157642Sps	struct rx_bd *rxbd;
5819157642Sps	int i, rc = 0;
5820157642Sps
5821179771Sdavidch	DBENTER(BCE_VERBOSE_RESET | BCE_VERBOSE_RECV | BCE_VERBOSE_LOAD |
5822206268Sdavidch	    BCE_VERBOSE_CTX);
5823157642Sps
5824157642Sps	/* Initialize the RX producer and consumer indices. */
5825157642Sps	sc->rx_prod        = 0;
5826157642Sps	sc->rx_cons        = 0;
5827157642Sps	sc->rx_prod_bseq   = 0;
5828218423Sdavidch	sc->free_rx_bd     = USABLE_RX_BD_ALLOC;
5829218423Sdavidch	sc->max_rx_bd      = USABLE_RX_BD_ALLOC;
5830157642Sps
5831157642Sps	/* Initialize the RX next pointer chain entries. */
5832218423Sdavidch	for (i = 0; i < sc->rx_pages; i++) {
5833157642Sps		int j;
5834157642Sps
5835157642Sps		rxbd = &sc->rx_bd_chain[i][USABLE_RX_BD_PER_PAGE];
5836157642Sps
5837157642Sps		/* Check if we've reached the last page. */
5838218423Sdavidch		if (i == (sc->rx_pages - 1))
5839157642Sps			j = 0;
5840157642Sps		else
5841157642Sps			j = i + 1;
5842157642Sps
5843157642Sps		/* Setup the chain page pointers. */
5844207411Sdavidch		rxbd->rx_bd_haddr_hi =
5845206268Sdavidch		    htole32(BCE_ADDR_HI(sc->rx_bd_chain_paddr[j]));
5846207411Sdavidch		rxbd->rx_bd_haddr_lo =
5847206268Sdavidch		    htole32(BCE_ADDR_LO(sc->rx_bd_chain_paddr[j]));
5848157642Sps	}
5849157642Sps
5850192281Sdelphij	/* Fill up the RX chain. */
5851171667Sdavidch	bce_fill_rx_chain(sc);
5852157642Sps
5853218423Sdavidch	DBRUN(sc->rx_low_watermark = USABLE_RX_BD_ALLOC);
5854206268Sdavidch	DBRUN(sc->rx_empty_count = 0);
5855218423Sdavidch	for (i = 0; i < sc->rx_pages; i++) {
5856192281Sdelphij		bus_dmamap_sync(sc->rx_bd_chain_tag, sc->rx_bd_chain_map[i],
5857157642Sps		    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
5858157642Sps	}
5859157642Sps
5860179771Sdavidch	bce_init_rx_context(sc);
5861157642Sps
5862218423Sdavidch	DBRUNMSG(BCE_EXTREME_RECV,
5863218423Sdavidch	    bce_dump_rx_bd_chain(sc, 0, TOTAL_RX_BD_ALLOC));
5864179771Sdavidch	DBEXIT(BCE_VERBOSE_RESET | BCE_VERBOSE_RECV | BCE_VERBOSE_LOAD |
5865206268Sdavidch	    BCE_VERBOSE_CTX);
5866206268Sdavidch
5867179771Sdavidch	/* ToDo: Are there possible failure modes here? */
5868206268Sdavidch
5869157642Sps	return(rc);
5870157642Sps}
5871157642Sps
5872157642Sps
5873157642Sps/****************************************************************************/
5874176448Sdavidch/* Add mbufs to the RX chain until its full or an mbuf allocation error     */
5875176448Sdavidch/* occurs.                                                                  */
5876176448Sdavidch/*                                                                          */
5877176448Sdavidch/* Returns:                                                                 */
5878176448Sdavidch/*   Nothing                                                                */
5879176448Sdavidch/****************************************************************************/
5880176448Sdavidchstatic void
5881176448Sdavidchbce_fill_rx_chain(struct bce_softc *sc)
5882176448Sdavidch{
5883176448Sdavidch	u16 prod, prod_idx;
5884176448Sdavidch	u32 prod_bseq;
5885176448Sdavidch
5886179771Sdavidch	DBENTER(BCE_VERBOSE_RESET | BCE_EXTREME_RECV | BCE_VERBOSE_LOAD |
5887206268Sdavidch	    BCE_VERBOSE_CTX);
5888176448Sdavidch
5889179771Sdavidch	/* Get the RX chain producer indices. */
5890176448Sdavidch	prod      = sc->rx_prod;
5891176448Sdavidch	prod_bseq = sc->rx_prod_bseq;
5892176448Sdavidch
5893176448Sdavidch	/* Keep filling the RX chain until it's full. */
5894176448Sdavidch	while (sc->free_rx_bd > 0) {
5895176448Sdavidch		prod_idx = RX_CHAIN_IDX(prod);
5896251146Smarius		if (bce_get_rx_buf(sc, prod, prod_idx, &prod_bseq)) {
5897176448Sdavidch			/* Bail out if we can't add an mbuf to the chain. */
5898176448Sdavidch			break;
5899176448Sdavidch		}
5900176448Sdavidch		prod = NEXT_RX_BD(prod);
5901176448Sdavidch	}
5902176448Sdavidch
5903179771Sdavidch	/* Save the RX chain producer indices. */
5904176448Sdavidch	sc->rx_prod      = prod;
5905176448Sdavidch	sc->rx_prod_bseq = prod_bseq;
5906176448Sdavidch
5907206268Sdavidch	/* We should never end up pointing to a next page pointer. */
5908178132Sdavidch	DBRUNIF(((prod & USABLE_RX_BD_PER_PAGE) == USABLE_RX_BD_PER_PAGE),
5909207411Sdavidch	    BCE_PRINTF("%s(): Invalid rx_prod value: 0x%04X\n",
5910251146Smarius	    __FUNCTION__, rx_prod));
5911178132Sdavidch
5912179771Sdavidch	/* Write the mailbox and tell the chip about the waiting rx_bd's. */
5913251146Smarius	REG_WR16(sc, MB_GET_CID_ADDR(RX_CID) + BCE_L2MQ_RX_HOST_BDIDX, prod);
5914251146Smarius	REG_WR(sc, MB_GET_CID_ADDR(RX_CID) + BCE_L2MQ_RX_HOST_BSEQ, prod_bseq);
5915176448Sdavidch
5916179771Sdavidch	DBEXIT(BCE_VERBOSE_RESET | BCE_EXTREME_RECV | BCE_VERBOSE_LOAD |
5917206268Sdavidch	    BCE_VERBOSE_CTX);
5918176448Sdavidch}
5919176448Sdavidch
5920176448Sdavidch
5921176448Sdavidch/****************************************************************************/
5922157642Sps/* Free memory and clear the RX data structures.                            */
5923157642Sps/*                                                                          */
5924157642Sps/* Returns:                                                                 */
5925157642Sps/*   Nothing.                                                               */
5926157642Sps/****************************************************************************/
5927157642Spsstatic void
5928157642Spsbce_free_rx_chain(struct bce_softc *sc)
5929157642Sps{
5930157642Sps	int i;
5931157642Sps
5932179771Sdavidch	DBENTER(BCE_VERBOSE_RESET | BCE_VERBOSE_RECV | BCE_VERBOSE_UNLOAD);
5933182293Sdavidch
5934157642Sps	/* Free any mbufs still in the RX mbuf chain. */
5935218423Sdavidch	for (i = 0; i < MAX_RX_BD_AVAIL; i++) {
5936157642Sps		if (sc->rx_mbuf_ptr[i] != NULL) {
5937157642Sps			if (sc->rx_mbuf_map[i] != NULL)
5938207411Sdavidch				bus_dmamap_sync(sc->rx_mbuf_tag,
5939206268Sdavidch				    sc->rx_mbuf_map[i],
5940206268Sdavidch				    BUS_DMASYNC_POSTREAD);
5941157642Sps			m_freem(sc->rx_mbuf_ptr[i]);
5942157642Sps			sc->rx_mbuf_ptr[i] = NULL;
5943176448Sdavidch			DBRUN(sc->debug_rx_mbuf_alloc--);
5944157642Sps		}
5945157642Sps	}
5946157642Sps
5947157642Sps	/* Clear each RX chain page. */
5948218423Sdavidch	for (i = 0; i < sc->rx_pages; i++)
5949251142Smarius		if (sc->rx_bd_chain[i] != NULL)
5950207411Sdavidch			bzero((char *)sc->rx_bd_chain[i],
5951206268Sdavidch			    BCE_RX_CHAIN_PAGE_SZ);
5952157642Sps
5953171667Sdavidch	sc->free_rx_bd = sc->max_rx_bd;
5954171667Sdavidch
5955157642Sps	/* Check if we lost any mbufs in the process. */
5956176448Sdavidch	DBRUNIF((sc->debug_rx_mbuf_alloc),
5957206268Sdavidch	    BCE_PRINTF("%s(): Memory leak! Lost %d mbufs from rx chain!\n",
5958206268Sdavidch	    __FUNCTION__, sc->debug_rx_mbuf_alloc));
5959157642Sps
5960179771Sdavidch	DBEXIT(BCE_VERBOSE_RESET | BCE_VERBOSE_RECV | BCE_VERBOSE_UNLOAD);
5961157642Sps}
5962157642Sps
5963157642Sps
5964157642Sps/****************************************************************************/
5965176448Sdavidch/* Allocate memory and initialize the page data structures.                 */
5966176448Sdavidch/* Assumes that bce_init_rx_chain() has not already been called.            */
5967176448Sdavidch/*                                                                          */
5968176448Sdavidch/* Returns:                                                                 */
5969176448Sdavidch/*   0 for success, positive value for failure.                             */
5970176448Sdavidch/****************************************************************************/
5971176448Sdavidchstatic int
5972176448Sdavidchbce_init_pg_chain(struct bce_softc *sc)
5973176448Sdavidch{
5974176448Sdavidch	struct rx_bd *pgbd;
5975176448Sdavidch	int i, rc = 0;
5976176448Sdavidch	u32 val;
5977176448Sdavidch
5978179771Sdavidch	DBENTER(BCE_VERBOSE_RESET | BCE_VERBOSE_RECV | BCE_VERBOSE_LOAD |
5979179771Sdavidch		BCE_VERBOSE_CTX);
5980176448Sdavidch
5981176448Sdavidch	/* Initialize the page producer and consumer indices. */
5982176448Sdavidch	sc->pg_prod        = 0;
5983176448Sdavidch	sc->pg_cons        = 0;
5984218423Sdavidch	sc->free_pg_bd     = USABLE_PG_BD_ALLOC;
5985218423Sdavidch	sc->max_pg_bd      = USABLE_PG_BD_ALLOC;
5986176448Sdavidch	DBRUN(sc->pg_low_watermark = sc->max_pg_bd);
5987176448Sdavidch	DBRUN(sc->pg_empty_count = 0);
5988176448Sdavidch
5989176448Sdavidch	/* Initialize the page next pointer chain entries. */
5990218423Sdavidch	for (i = 0; i < sc->pg_pages; i++) {
5991176448Sdavidch		int j;
5992176448Sdavidch
5993176448Sdavidch		pgbd = &sc->pg_bd_chain[i][USABLE_PG_BD_PER_PAGE];
5994176448Sdavidch
5995176448Sdavidch		/* Check if we've reached the last page. */
5996218423Sdavidch		if (i == (sc->pg_pages - 1))
5997176448Sdavidch			j = 0;
5998176448Sdavidch		else
5999176448Sdavidch			j = i + 1;
6000176448Sdavidch
6001176448Sdavidch		/* Setup the chain page pointers. */
6002218423Sdavidch		pgbd->rx_bd_haddr_hi =
6003218423Sdavidch		    htole32(BCE_ADDR_HI(sc->pg_bd_chain_paddr[j]));
6004218423Sdavidch		pgbd->rx_bd_haddr_lo =
6005218423Sdavidch		    htole32(BCE_ADDR_LO(sc->pg_bd_chain_paddr[j]));
6006176448Sdavidch	}
6007176448Sdavidch
6008182293Sdavidch	/* Setup the MQ BIN mapping for host_pg_bidx. */
6009226123Syongari	if (BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5709)
6010179771Sdavidch		REG_WR(sc, BCE_MQ_MAP_L2_3, BCE_MQ_MAP_L2_3_DEFAULT);
6011176448Sdavidch
6012182293Sdavidch	CTX_WR(sc, GET_CID_ADDR(RX_CID), BCE_L2CTX_RX_PG_BUF_SIZE, 0);
6013179771Sdavidch
6014176448Sdavidch	/* Configure the rx_bd and page chain mbuf cluster size. */
6015251142Smarius	val = (sc->rx_bd_mbuf_data_len << 16) | MCLBYTES;
6016182293Sdavidch	CTX_WR(sc, GET_CID_ADDR(RX_CID), BCE_L2CTX_RX_PG_BUF_SIZE, val);
6017176448Sdavidch
6018176448Sdavidch	/* Configure the context reserved for jumbo support. */
6019182293Sdavidch	CTX_WR(sc, GET_CID_ADDR(RX_CID), BCE_L2CTX_RX_RBDC_KEY,
6020182293Sdavidch		BCE_L2CTX_RX_RBDC_JUMBO_KEY);
6021176448Sdavidch
6022179771Sdavidch	/* Point the hardware to the first page in the page chain. */
6023179771Sdavidch	val = BCE_ADDR_HI(sc->pg_bd_chain_paddr[0]);
6024182293Sdavidch	CTX_WR(sc, GET_CID_ADDR(RX_CID), BCE_L2CTX_RX_NX_PG_BDHADDR_HI, val);
6025179771Sdavidch	val = BCE_ADDR_LO(sc->pg_bd_chain_paddr[0]);
6026182293Sdavidch	CTX_WR(sc, GET_CID_ADDR(RX_CID), BCE_L2CTX_RX_NX_PG_BDHADDR_LO, val);
6027179771Sdavidch
6028176448Sdavidch	/* Fill up the page chain. */
6029176448Sdavidch	bce_fill_pg_chain(sc);
6030176448Sdavidch
6031218423Sdavidch	for (i = 0; i < sc->pg_pages; i++) {
6032192281Sdelphij		bus_dmamap_sync(sc->pg_bd_chain_tag, sc->pg_bd_chain_map[i],
6033176448Sdavidch		    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
6034176448Sdavidch	}
6035176448Sdavidch
6036218423Sdavidch	DBRUNMSG(BCE_EXTREME_RECV,
6037218423Sdavidch	    bce_dump_pg_chain(sc, 0, TOTAL_PG_BD_ALLOC));
6038179771Sdavidch	DBEXIT(BCE_VERBOSE_RESET | BCE_VERBOSE_RECV | BCE_VERBOSE_LOAD |
6039179771Sdavidch		BCE_VERBOSE_CTX);
6040176448Sdavidch	return(rc);
6041176448Sdavidch}
6042176448Sdavidch
6043179771Sdavidch
6044176448Sdavidch/****************************************************************************/
6045176448Sdavidch/* Add mbufs to the page chain until its full or an mbuf allocation error   */
6046176448Sdavidch/* occurs.                                                                  */
6047176448Sdavidch/*                                                                          */
6048176448Sdavidch/* Returns:                                                                 */
6049176448Sdavidch/*   Nothing                                                                */
6050176448Sdavidch/****************************************************************************/
6051176448Sdavidchstatic void
6052176448Sdavidchbce_fill_pg_chain(struct bce_softc *sc)
6053176448Sdavidch{
6054178132Sdavidch	u16 prod, prod_idx;
6055176448Sdavidch
6056179771Sdavidch	DBENTER(BCE_VERBOSE_RESET | BCE_EXTREME_RECV | BCE_VERBOSE_LOAD |
6057207411Sdavidch	    BCE_VERBOSE_CTX);
6058176448Sdavidch
6059179771Sdavidch	/* Get the page chain prodcuer index. */
6060176448Sdavidch	prod = sc->pg_prod;
6061176448Sdavidch
6062176448Sdavidch	/* Keep filling the page chain until it's full. */
6063176448Sdavidch	while (sc->free_pg_bd > 0) {
6064176448Sdavidch		prod_idx = PG_CHAIN_IDX(prod);
6065251146Smarius		if (bce_get_pg_buf(sc, prod, prod_idx)) {
6066176448Sdavidch			/* Bail out if we can't add an mbuf to the chain. */
6067176448Sdavidch			break;
6068178132Sdavidch		}
6069176448Sdavidch		prod = NEXT_PG_BD(prod);
6070176448Sdavidch	}
6071176448Sdavidch
6072176448Sdavidch	/* Save the page chain producer index. */
6073176448Sdavidch	sc->pg_prod = prod;
6074176448Sdavidch
6075178132Sdavidch	DBRUNIF(((prod & USABLE_RX_BD_PER_PAGE) == USABLE_RX_BD_PER_PAGE),
6076207411Sdavidch	    BCE_PRINTF("%s(): Invalid pg_prod value: 0x%04X\n",
6077251146Smarius	    __FUNCTION__, pg_prod));
6078176448Sdavidch
6079179771Sdavidch	/*
6080179771Sdavidch	 * Write the mailbox and tell the chip about
6081179771Sdavidch	 * the new rx_bd's in the page chain.
6082179771Sdavidch	 */
6083251146Smarius	REG_WR16(sc, MB_GET_CID_ADDR(RX_CID) + BCE_L2MQ_RX_HOST_PG_BDIDX,
6084251146Smarius	    prod);
6085178132Sdavidch
6086179771Sdavidch	DBEXIT(BCE_VERBOSE_RESET | BCE_EXTREME_RECV | BCE_VERBOSE_LOAD |
6087207411Sdavidch	    BCE_VERBOSE_CTX);
6088176448Sdavidch}
6089176448Sdavidch
6090176448Sdavidch
6091176448Sdavidch/****************************************************************************/
6092176448Sdavidch/* Free memory and clear the RX data structures.                            */
6093176448Sdavidch/*                                                                          */
6094176448Sdavidch/* Returns:                                                                 */
6095176448Sdavidch/*   Nothing.                                                               */
6096176448Sdavidch/****************************************************************************/
6097176448Sdavidchstatic void
6098176448Sdavidchbce_free_pg_chain(struct bce_softc *sc)
6099176448Sdavidch{
6100176448Sdavidch	int i;
6101176448Sdavidch
6102179771Sdavidch	DBENTER(BCE_VERBOSE_RESET | BCE_VERBOSE_RECV | BCE_VERBOSE_UNLOAD);
6103176448Sdavidch
6104176448Sdavidch	/* Free any mbufs still in the mbuf page chain. */
6105218423Sdavidch	for (i = 0; i < MAX_PG_BD_AVAIL; i++) {
6106176448Sdavidch		if (sc->pg_mbuf_ptr[i] != NULL) {
6107176448Sdavidch			if (sc->pg_mbuf_map[i] != NULL)
6108207411Sdavidch				bus_dmamap_sync(sc->pg_mbuf_tag,
6109207411Sdavidch				    sc->pg_mbuf_map[i],
6110207411Sdavidch				    BUS_DMASYNC_POSTREAD);
6111176448Sdavidch			m_freem(sc->pg_mbuf_ptr[i]);
6112176448Sdavidch			sc->pg_mbuf_ptr[i] = NULL;
6113178132Sdavidch			DBRUN(sc->debug_pg_mbuf_alloc--);
6114176448Sdavidch		}
6115176448Sdavidch	}
6116176448Sdavidch
6117176448Sdavidch	/* Clear each page chain pages. */
6118218423Sdavidch	for (i = 0; i < sc->pg_pages; i++)
6119176448Sdavidch		bzero((char *)sc->pg_bd_chain[i], BCE_PG_CHAIN_PAGE_SZ);
6120176448Sdavidch
6121176448Sdavidch	sc->free_pg_bd = sc->max_pg_bd;
6122176448Sdavidch
6123176448Sdavidch	/* Check if we lost any mbufs in the process. */
6124176448Sdavidch	DBRUNIF((sc->debug_pg_mbuf_alloc),
6125207411Sdavidch	    BCE_PRINTF("%s(): Memory leak! Lost %d mbufs from page chain!\n",
6126207411Sdavidch	    __FUNCTION__, sc->debug_pg_mbuf_alloc));
6127176448Sdavidch
6128179771Sdavidch	DBEXIT(BCE_VERBOSE_RESET | BCE_VERBOSE_RECV | BCE_VERBOSE_UNLOAD);
6129176448Sdavidch}
6130176448Sdavidch
6131176448Sdavidch
6132235151Syongaristatic u32
6133235151Syongaribce_get_rphy_link(struct bce_softc *sc)
6134235151Syongari{
6135235151Syongari	u32 advertise, link;
6136235151Syongari	int fdpx;
6137235151Syongari
6138235151Syongari	advertise = 0;
6139235151Syongari	fdpx = 0;
6140235151Syongari	if ((sc->bce_phy_flags & BCE_PHY_REMOTE_PORT_FIBER_FLAG) != 0)
6141235151Syongari		link = bce_shmem_rd(sc, BCE_RPHY_SERDES_LINK);
6142235151Syongari	else
6143235151Syongari		link = bce_shmem_rd(sc, BCE_RPHY_COPPER_LINK);
6144235151Syongari	if (link & BCE_NETLINK_ANEG_ENB)
6145235151Syongari		advertise |= BCE_NETLINK_ANEG_ENB;
6146235151Syongari	if (link & BCE_NETLINK_SPEED_10HALF)
6147235151Syongari		advertise |= BCE_NETLINK_SPEED_10HALF;
6148235151Syongari	if (link & BCE_NETLINK_SPEED_10FULL) {
6149235151Syongari		advertise |= BCE_NETLINK_SPEED_10FULL;
6150235151Syongari		fdpx++;
6151235151Syongari	}
6152235151Syongari	if (link & BCE_NETLINK_SPEED_100HALF)
6153235151Syongari		advertise |= BCE_NETLINK_SPEED_100HALF;
6154235151Syongari	if (link & BCE_NETLINK_SPEED_100FULL) {
6155235151Syongari		advertise |= BCE_NETLINK_SPEED_100FULL;
6156235151Syongari		fdpx++;
6157235151Syongari	}
6158235151Syongari	if (link & BCE_NETLINK_SPEED_1000HALF)
6159235151Syongari		advertise |= BCE_NETLINK_SPEED_1000HALF;
6160235151Syongari	if (link & BCE_NETLINK_SPEED_1000FULL) {
6161235151Syongari		advertise |= BCE_NETLINK_SPEED_1000FULL;
6162235151Syongari		fdpx++;
6163235151Syongari	}
6164235151Syongari	if (link & BCE_NETLINK_SPEED_2500HALF)
6165235151Syongari		advertise |= BCE_NETLINK_SPEED_2500HALF;
6166235151Syongari	if (link & BCE_NETLINK_SPEED_2500FULL) {
6167235151Syongari		advertise |= BCE_NETLINK_SPEED_2500FULL;
6168235151Syongari		fdpx++;
6169235151Syongari	}
6170235151Syongari	if (fdpx)
6171235151Syongari		advertise |= BCE_NETLINK_FC_PAUSE_SYM |
6172235151Syongari		    BCE_NETLINK_FC_PAUSE_ASYM;
6173235151Syongari	if ((sc->bce_phy_flags & BCE_PHY_REMOTE_PORT_FIBER_FLAG) == 0)
6174235151Syongari		advertise |= BCE_NETLINK_PHY_APP_REMOTE |
6175235151Syongari		    BCE_NETLINK_ETH_AT_WIRESPEED;
6176235151Syongari
6177235151Syongari	return (advertise);
6178235151Syongari}
6179235151Syongari
6180235151Syongari
6181176448Sdavidch/****************************************************************************/
6182157642Sps/* Set media options.                                                       */
6183157642Sps/*                                                                          */
6184157642Sps/* Returns:                                                                 */
6185157642Sps/*   0 for success, positive value for failure.                             */
6186157642Sps/****************************************************************************/
6187157642Spsstatic int
6188157642Spsbce_ifmedia_upd(struct ifnet *ifp)
6189157642Sps{
6190179771Sdavidch	struct bce_softc *sc = ifp->if_softc;
6191210261Syongari	int error;
6192165994Sjhb
6193179771Sdavidch	DBENTER(BCE_VERBOSE);
6194179771Sdavidch
6195165994Sjhb	BCE_LOCK(sc);
6196210261Syongari	error = bce_ifmedia_upd_locked(ifp);
6197165994Sjhb	BCE_UNLOCK(sc);
6198179771Sdavidch
6199179771Sdavidch	DBEXIT(BCE_VERBOSE);
6200210261Syongari	return (error);
6201165994Sjhb}
6202165994Sjhb
6203170392Sdavidch
6204169632Sdavidch/****************************************************************************/
6205169632Sdavidch/* Set media options.                                                       */
6206169632Sdavidch/*                                                                          */
6207169632Sdavidch/* Returns:                                                                 */
6208169632Sdavidch/*   Nothing.                                                               */
6209169632Sdavidch/****************************************************************************/
6210210261Syongaristatic int
6211165994Sjhbbce_ifmedia_upd_locked(struct ifnet *ifp)
6212165994Sjhb{
6213179771Sdavidch	struct bce_softc *sc = ifp->if_softc;
6214157642Sps	struct mii_data *mii;
6215221407Smarius	struct mii_softc *miisc;
6216235151Syongari	struct ifmedia *ifm;
6217235151Syongari	u32 link;
6218235151Syongari	int error, fdx;
6219170392Sdavidch
6220207411Sdavidch	DBENTER(BCE_VERBOSE_PHY);
6221179771Sdavidch
6222210261Syongari	error = 0;
6223165994Sjhb	BCE_LOCK_ASSERT(sc);
6224157642Sps
6225235151Syongari	sc->bce_link_up = FALSE;
6226235151Syongari	if ((sc->bce_phy_flags & BCE_PHY_REMOTE_CAP_FLAG) != 0) {
6227235151Syongari		ifm = &sc->bce_ifmedia;
6228235151Syongari		if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER)
6229235151Syongari			return (EINVAL);
6230235151Syongari		link = 0;
6231235151Syongari		fdx = IFM_OPTIONS(ifm->ifm_media) & IFM_FDX;
6232235151Syongari		switch(IFM_SUBTYPE(ifm->ifm_media)) {
6233235151Syongari		case IFM_AUTO:
6234235151Syongari			/*
6235235151Syongari			 * Check advertised link of remote PHY by reading
6236235151Syongari			 * BCE_RPHY_SERDES_LINK or BCE_RPHY_COPPER_LINK.
6237235151Syongari			 * Always use the same link type of remote PHY.
6238235151Syongari			 */
6239235151Syongari			link = bce_get_rphy_link(sc);
6240235151Syongari			break;
6241235151Syongari		case IFM_2500_SX:
6242235151Syongari			if ((sc->bce_phy_flags &
6243235151Syongari			    (BCE_PHY_REMOTE_PORT_FIBER_FLAG |
6244235151Syongari			    BCE_PHY_2_5G_CAPABLE_FLAG)) == 0)
6245235151Syongari				return (EINVAL);
6246235151Syongari			/*
6247235151Syongari			 * XXX
6248235151Syongari			 * Have to enable forced 2.5Gbps configuration.
6249235151Syongari			 */
6250235151Syongari			if (fdx != 0)
6251235151Syongari				link |= BCE_NETLINK_SPEED_2500FULL;
6252235151Syongari			else
6253235151Syongari				link |= BCE_NETLINK_SPEED_2500HALF;
6254235151Syongari			break;
6255235151Syongari		case IFM_1000_SX:
6256235151Syongari			if ((sc->bce_phy_flags &
6257235151Syongari			    BCE_PHY_REMOTE_PORT_FIBER_FLAG) == 0)
6258235151Syongari				return (EINVAL);
6259235151Syongari			/*
6260235151Syongari			 * XXX
6261235151Syongari			 * Have to disable 2.5Gbps configuration.
6262235151Syongari			 */
6263235151Syongari			if (fdx != 0)
6264235151Syongari				link = BCE_NETLINK_SPEED_1000FULL;
6265235151Syongari			else
6266235151Syongari				link = BCE_NETLINK_SPEED_1000HALF;
6267235151Syongari			break;
6268235151Syongari		case IFM_1000_T:
6269235151Syongari			if (sc->bce_phy_flags & BCE_PHY_REMOTE_PORT_FIBER_FLAG)
6270235151Syongari				return (EINVAL);
6271235151Syongari			if (fdx != 0)
6272235151Syongari				link = BCE_NETLINK_SPEED_1000FULL;
6273235151Syongari			else
6274235151Syongari				link = BCE_NETLINK_SPEED_1000HALF;
6275235151Syongari			break;
6276235151Syongari		case IFM_100_TX:
6277235151Syongari			if (sc->bce_phy_flags & BCE_PHY_REMOTE_PORT_FIBER_FLAG)
6278235151Syongari				return (EINVAL);
6279235151Syongari			if (fdx != 0)
6280235151Syongari				link = BCE_NETLINK_SPEED_100FULL;
6281235151Syongari			else
6282235151Syongari				link = BCE_NETLINK_SPEED_100HALF;
6283235151Syongari			break;
6284235151Syongari		case IFM_10_T:
6285235151Syongari			if (sc->bce_phy_flags & BCE_PHY_REMOTE_PORT_FIBER_FLAG)
6286235151Syongari				return (EINVAL);
6287235151Syongari			if (fdx != 0)
6288235151Syongari				link = BCE_NETLINK_SPEED_10FULL;
6289235151Syongari			else
6290235151Syongari				link = BCE_NETLINK_SPEED_10HALF;
6291235151Syongari			break;
6292235151Syongari		default:
6293235151Syongari			return (EINVAL);
6294235151Syongari		}
6295235151Syongari		if (IFM_SUBTYPE(ifm->ifm_media) != IFM_AUTO) {
6296235151Syongari			/*
6297235151Syongari			 * XXX
6298235151Syongari			 * Advertise pause capability for full-duplex media.
6299235151Syongari			 */
6300235151Syongari			if (fdx != 0)
6301235151Syongari				link |= BCE_NETLINK_FC_PAUSE_SYM |
6302235151Syongari				    BCE_NETLINK_FC_PAUSE_ASYM;
6303235151Syongari			if ((sc->bce_phy_flags &
6304235151Syongari			    BCE_PHY_REMOTE_PORT_FIBER_FLAG) == 0)
6305235151Syongari				link |= BCE_NETLINK_PHY_APP_REMOTE |
6306235151Syongari				    BCE_NETLINK_ETH_AT_WIRESPEED;
6307235151Syongari		}
6308170392Sdavidch
6309235151Syongari		bce_shmem_wr(sc, BCE_MB_ARGS_0, link);
6310235151Syongari		error = bce_fw_sync(sc, BCE_DRV_MSG_CODE_CMD_SET_LINK);
6311235151Syongari	} else {
6312235151Syongari		mii = device_get_softc(sc->bce_miibus);
6313235151Syongari
6314235151Syongari		/* Make sure the MII bus has been enumerated. */
6315235151Syongari		if (mii) {
6316235151Syongari			LIST_FOREACH(miisc, &mii->mii_phys, mii_list)
6317235151Syongari				PHY_RESET(miisc);
6318235151Syongari			error = mii_mediachg(mii);
6319235151Syongari		}
6320157642Sps	}
6321179771Sdavidch
6322207411Sdavidch	DBEXIT(BCE_VERBOSE_PHY);
6323210261Syongari	return (error);
6324157642Sps}
6325157642Sps
6326157642Sps
6327235151Syongaristatic void
6328235151Syongaribce_ifmedia_sts_rphy(struct bce_softc *sc, struct ifmediareq *ifmr)
6329235151Syongari{
6330235151Syongari	struct ifnet *ifp;
6331235151Syongari	u32 link;
6332235151Syongari
6333235151Syongari	ifp = sc->bce_ifp;
6334235151Syongari	BCE_LOCK_ASSERT(sc);
6335235151Syongari
6336235151Syongari	ifmr->ifm_status = IFM_AVALID;
6337235151Syongari	ifmr->ifm_active = IFM_ETHER;
6338235151Syongari	link = bce_shmem_rd(sc, BCE_LINK_STATUS);
6339235151Syongari	/* XXX Handle heart beat status? */
6340235151Syongari	if ((link & BCE_LINK_STATUS_LINK_UP) != 0)
6341235151Syongari		ifmr->ifm_status |= IFM_ACTIVE;
6342235151Syongari	else {
6343235151Syongari		ifmr->ifm_active |= IFM_NONE;
6344235151Syongari		ifp->if_baudrate = 0;
6345235151Syongari		return;
6346235151Syongari	}
6347235151Syongari	switch (link & BCE_LINK_STATUS_SPEED_MASK) {
6348235151Syongari	case BCE_LINK_STATUS_10HALF:
6349235151Syongari		ifmr->ifm_active |= IFM_10_T | IFM_HDX;
6350235151Syongari		ifp->if_baudrate = IF_Mbps(10UL);
6351235151Syongari		break;
6352235151Syongari	case BCE_LINK_STATUS_10FULL:
6353235151Syongari		ifmr->ifm_active |= IFM_10_T | IFM_FDX;
6354235151Syongari		ifp->if_baudrate = IF_Mbps(10UL);
6355235151Syongari		break;
6356235151Syongari	case BCE_LINK_STATUS_100HALF:
6357235151Syongari		ifmr->ifm_active |= IFM_100_TX | IFM_HDX;
6358235151Syongari		ifp->if_baudrate = IF_Mbps(100UL);
6359235151Syongari		break;
6360235151Syongari	case BCE_LINK_STATUS_100FULL:
6361235151Syongari		ifmr->ifm_active |= IFM_100_TX | IFM_FDX;
6362235151Syongari		ifp->if_baudrate = IF_Mbps(100UL);
6363235151Syongari		break;
6364235151Syongari	case BCE_LINK_STATUS_1000HALF:
6365235151Syongari		if ((sc->bce_phy_flags & BCE_PHY_REMOTE_PORT_FIBER_FLAG) == 0)
6366235151Syongari			ifmr->ifm_active |= IFM_1000_T | IFM_HDX;
6367235151Syongari		else
6368235151Syongari			ifmr->ifm_active |= IFM_1000_SX | IFM_HDX;
6369235151Syongari		ifp->if_baudrate = IF_Mbps(1000UL);
6370235151Syongari		break;
6371235151Syongari	case BCE_LINK_STATUS_1000FULL:
6372235151Syongari		if ((sc->bce_phy_flags & BCE_PHY_REMOTE_PORT_FIBER_FLAG) == 0)
6373235151Syongari			ifmr->ifm_active |= IFM_1000_T | IFM_FDX;
6374235151Syongari		else
6375235151Syongari			ifmr->ifm_active |= IFM_1000_SX | IFM_FDX;
6376235151Syongari		ifp->if_baudrate = IF_Mbps(1000UL);
6377235151Syongari		break;
6378235151Syongari	case BCE_LINK_STATUS_2500HALF:
6379235151Syongari		if ((sc->bce_phy_flags & BCE_PHY_REMOTE_PORT_FIBER_FLAG) == 0) {
6380235151Syongari			ifmr->ifm_active |= IFM_NONE;
6381235151Syongari			return;
6382235151Syongari		} else
6383235151Syongari			ifmr->ifm_active |= IFM_2500_SX | IFM_HDX;
6384235151Syongari		ifp->if_baudrate = IF_Mbps(2500UL);
6385235151Syongari		break;
6386235151Syongari	case BCE_LINK_STATUS_2500FULL:
6387235151Syongari		if ((sc->bce_phy_flags & BCE_PHY_REMOTE_PORT_FIBER_FLAG) == 0) {
6388235151Syongari			ifmr->ifm_active |= IFM_NONE;
6389235151Syongari			return;
6390235151Syongari		} else
6391235151Syongari			ifmr->ifm_active |= IFM_2500_SX | IFM_FDX;
6392235151Syongari		ifp->if_baudrate = IF_Mbps(2500UL);
6393235151Syongari		break;
6394235151Syongari	default:
6395235151Syongari		ifmr->ifm_active |= IFM_NONE;
6396235151Syongari		return;
6397235151Syongari	}
6398235151Syongari
6399235151Syongari	if ((link & BCE_LINK_STATUS_RX_FC_ENABLED) != 0)
6400235151Syongari		ifmr->ifm_active |= IFM_ETH_RXPAUSE;
6401235151Syongari	if ((link & BCE_LINK_STATUS_TX_FC_ENABLED) != 0)
6402235151Syongari		ifmr->ifm_active |= IFM_ETH_TXPAUSE;
6403235151Syongari}
6404235151Syongari
6405235151Syongari
6406157642Sps/****************************************************************************/
6407157642Sps/* Reports current media status.                                            */
6408157642Sps/*                                                                          */
6409157642Sps/* Returns:                                                                 */
6410157642Sps/*   Nothing.                                                               */
6411157642Sps/****************************************************************************/
6412157642Spsstatic void
6413157642Spsbce_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
6414157642Sps{
6415179771Sdavidch	struct bce_softc *sc = ifp->if_softc;
6416157642Sps	struct mii_data *mii;
6417157642Sps
6418207411Sdavidch	DBENTER(BCE_VERBOSE_PHY);
6419157642Sps
6420157642Sps	BCE_LOCK(sc);
6421157642Sps
6422210263Syongari	if ((ifp->if_flags & IFF_UP) == 0) {
6423210263Syongari		BCE_UNLOCK(sc);
6424210263Syongari		return;
6425210263Syongari	}
6426157642Sps
6427235151Syongari	if ((sc->bce_phy_flags & BCE_PHY_REMOTE_CAP_FLAG) != 0)
6428235151Syongari		bce_ifmedia_sts_rphy(sc, ifmr);
6429235151Syongari	else {
6430235151Syongari		mii = device_get_softc(sc->bce_miibus);
6431235151Syongari		mii_pollstat(mii);
6432235151Syongari		ifmr->ifm_active = mii->mii_media_active;
6433235151Syongari		ifmr->ifm_status = mii->mii_media_status;
6434235151Syongari	}
6435157642Sps
6436157642Sps	BCE_UNLOCK(sc);
6437179771Sdavidch
6438207411Sdavidch	DBEXIT(BCE_VERBOSE_PHY);
6439157642Sps}
6440157642Sps
6441157642Sps
6442157642Sps/****************************************************************************/
6443157642Sps/* Handles PHY generated interrupt events.                                  */
6444157642Sps/*                                                                          */
6445157642Sps/* Returns:                                                                 */
6446157642Sps/*   Nothing.                                                               */
6447157642Sps/****************************************************************************/
6448157642Spsstatic void
6449157642Spsbce_phy_intr(struct bce_softc *sc)
6450157642Sps{
6451157642Sps	u32 new_link_state, old_link_state;
6452157642Sps
6453179771Sdavidch	DBENTER(BCE_VERBOSE_PHY | BCE_VERBOSE_INTR);
6454179771Sdavidch
6455206268Sdavidch	DBRUN(sc->phy_interrupts++);
6456206268Sdavidch
6457157642Sps	new_link_state = sc->status_block->status_attn_bits &
6458206268Sdavidch	    STATUS_ATTN_BITS_LINK_STATE;
6459157642Sps	old_link_state = sc->status_block->status_attn_bits_ack &
6460206268Sdavidch	    STATUS_ATTN_BITS_LINK_STATE;
6461157642Sps
6462157642Sps	/* Handle any changes if the link state has changed. */
6463157642Sps	if (new_link_state != old_link_state) {
6464157642Sps
6465206268Sdavidch		/* Update the status_attn_bits_ack field. */
6466157642Sps		if (new_link_state) {
6467157642Sps			REG_WR(sc, BCE_PCICFG_STATUS_BIT_SET_CMD,
6468206268Sdavidch			    STATUS_ATTN_BITS_LINK_STATE);
6469179771Sdavidch			DBPRINT(sc, BCE_INFO_PHY, "%s(): Link is now UP.\n",
6470206268Sdavidch			    __FUNCTION__);
6471235151Syongari		} else {
6472157642Sps			REG_WR(sc, BCE_PCICFG_STATUS_BIT_CLEAR_CMD,
6473206268Sdavidch			    STATUS_ATTN_BITS_LINK_STATE);
6474179771Sdavidch			DBPRINT(sc, BCE_INFO_PHY, "%s(): Link is now DOWN.\n",
6475206268Sdavidch			    __FUNCTION__);
6476157642Sps		}
6477234121Syongari
6478235151Syongari		if ((sc->bce_phy_flags & BCE_PHY_REMOTE_CAP_FLAG) != 0) {
6479235151Syongari			if (new_link_state) {
6480235151Syongari				if (bootverbose)
6481235151Syongari					if_printf(sc->bce_ifp, "link UP\n");
6482235151Syongari				if_link_state_change(sc->bce_ifp,
6483235151Syongari				    LINK_STATE_UP);
6484235151Syongari			} else {
6485235151Syongari				if (bootverbose)
6486235151Syongari					if_printf(sc->bce_ifp, "link DOWN\n");
6487235151Syongari				if_link_state_change(sc->bce_ifp,
6488235151Syongari				    LINK_STATE_DOWN);
6489235151Syongari			}
6490235151Syongari		}
6491179771Sdavidch		/*
6492234121Syongari		 * Assume link is down and allow
6493234121Syongari		 * tick routine to update the state
6494234121Syongari		 * based on the actual media state.
6495179771Sdavidch		 */
6496234121Syongari		sc->bce_link_up = FALSE;
6497234121Syongari		callout_stop(&sc->bce_tick_callout);
6498234121Syongari		bce_tick(sc);
6499157642Sps	}
6500157642Sps
6501157642Sps	/* Acknowledge the link change interrupt. */
6502157642Sps	REG_WR(sc, BCE_EMAC_STATUS, BCE_EMAC_STATUS_LINK_CHANGE);
6503179771Sdavidch
6504179771Sdavidch	DBEXIT(BCE_VERBOSE_PHY | BCE_VERBOSE_INTR);
6505157642Sps}
6506157642Sps
6507157642Sps
6508157642Sps/****************************************************************************/
6509178132Sdavidch/* Reads the receive consumer value from the status block (skipping over    */
6510176448Sdavidch/* chain page pointer if necessary).                                        */
6511176448Sdavidch/*                                                                          */
6512176448Sdavidch/* Returns:                                                                 */
6513176448Sdavidch/*   hw_cons                                                                */
6514176448Sdavidch/****************************************************************************/
6515176448Sdavidchstatic inline u16
6516176448Sdavidchbce_get_hw_rx_cons(struct bce_softc *sc)
6517176448Sdavidch{
6518182293Sdavidch	u16 hw_cons;
6519176448Sdavidch
6520182293Sdavidch	rmb();
6521182293Sdavidch	hw_cons = sc->status_block->status_rx_quick_consumer_index0;
6522176448Sdavidch	if ((hw_cons & USABLE_RX_BD_PER_PAGE) == USABLE_RX_BD_PER_PAGE)
6523176448Sdavidch		hw_cons++;
6524176448Sdavidch
6525176448Sdavidch	return hw_cons;
6526176448Sdavidch}
6527176448Sdavidch
6528176448Sdavidch/****************************************************************************/
6529157642Sps/* Handles received frame interrupt events.                                 */
6530157642Sps/*                                                                          */
6531157642Sps/* Returns:                                                                 */
6532157642Sps/*   Nothing.                                                               */
6533157642Sps/****************************************************************************/
6534157642Spsstatic void
6535157642Spsbce_rx_intr(struct bce_softc *sc)
6536157642Sps{
6537178132Sdavidch	struct ifnet *ifp = sc->bce_ifp;
6538178132Sdavidch	struct l2_fhdr *l2fhdr;
6539204368Syongari	struct ether_vlan_header *vh;
6540179695Sdavidch	unsigned int pkt_len;
6541179771Sdavidch	u16 sw_rx_cons, sw_rx_cons_idx, hw_rx_cons;
6542178132Sdavidch	u32 status;
6543179771Sdavidch	unsigned int rem_len;
6544179771Sdavidch	u16 sw_pg_cons, sw_pg_cons_idx;
6545178132Sdavidch
6546179771Sdavidch	DBENTER(BCE_VERBOSE_RECV | BCE_VERBOSE_INTR);
6547207411Sdavidch	DBRUN(sc->interrupts_rx++);
6548179771Sdavidch	DBPRINT(sc, BCE_EXTREME_RECV, "%s(enter): rx_prod = 0x%04X, "
6549206268Sdavidch	    "rx_cons = 0x%04X, rx_prod_bseq = 0x%08X\n",
6550206268Sdavidch	    __FUNCTION__, sc->rx_prod, sc->rx_cons, sc->rx_prod_bseq);
6551178132Sdavidch
6552157642Sps	/* Prepare the RX chain pages to be accessed by the host CPU. */
6553218423Sdavidch	for (int i = 0; i < sc->rx_pages; i++)
6554157642Sps		bus_dmamap_sync(sc->rx_bd_chain_tag,
6555192281Sdelphij		    sc->rx_bd_chain_map[i], BUS_DMASYNC_POSTREAD);
6556157642Sps
6557176448Sdavidch	/* Prepare the page chain pages to be accessed by the host CPU. */
6558218423Sdavidch	if (bce_hdr_split == TRUE) {
6559218423Sdavidch		for (int i = 0; i < sc->pg_pages; i++)
6560218423Sdavidch			bus_dmamap_sync(sc->pg_bd_chain_tag,
6561218423Sdavidch			    sc->pg_bd_chain_map[i], BUS_DMASYNC_POSTREAD);
6562218423Sdavidch	}
6563176448Sdavidch
6564157642Sps	/* Get the hardware's view of the RX consumer index. */
6565176448Sdavidch	hw_rx_cons = sc->hw_rx_cons = bce_get_hw_rx_cons(sc);
6566157642Sps
6567176448Sdavidch	/* Get working copies of the driver's view of the consumer indices. */
6568176448Sdavidch	sw_rx_cons = sc->rx_cons;
6569179771Sdavidch	sw_pg_cons = sc->pg_cons;
6570157642Sps
6571170392Sdavidch	/* Update some debug statistics counters */
6572157642Sps	DBRUNIF((sc->free_rx_bd < sc->rx_low_watermark),
6573207411Sdavidch	    sc->rx_low_watermark = sc->free_rx_bd);
6574207411Sdavidch	DBRUNIF((sc->free_rx_bd == sc->max_rx_bd),
6575207411Sdavidch	    sc->rx_empty_count++);
6576157642Sps
6577178132Sdavidch	/* Scan through the receive chain as long as there is work to do */
6578176448Sdavidch	/* ToDo: Consider setting a limit on the number of packets processed. */
6579182293Sdavidch	rmb();
6580176448Sdavidch	while (sw_rx_cons != hw_rx_cons) {
6581176448Sdavidch		struct mbuf *m0;
6582179771Sdavidch
6583157642Sps		/* Convert the producer/consumer indices to an actual rx_bd index. */
6584176448Sdavidch		sw_rx_cons_idx = RX_CHAIN_IDX(sw_rx_cons);
6585157642Sps
6586176448Sdavidch		/* Unmap the mbuf from DMA space. */
6587207411Sdavidch		bus_dmamap_sync(sc->rx_mbuf_tag,
6588206268Sdavidch		    sc->rx_mbuf_map[sw_rx_cons_idx],
6589192281Sdelphij		    BUS_DMASYNC_POSTREAD);
6590176448Sdavidch		bus_dmamap_unload(sc->rx_mbuf_tag,
6591176448Sdavidch		    sc->rx_mbuf_map[sw_rx_cons_idx]);
6592157642Sps
6593176448Sdavidch		/* Remove the mbuf from the RX chain. */
6594176448Sdavidch		m0 = sc->rx_mbuf_ptr[sw_rx_cons_idx];
6595176448Sdavidch		sc->rx_mbuf_ptr[sw_rx_cons_idx] = NULL;
6596176448Sdavidch		DBRUN(sc->debug_rx_mbuf_alloc--);
6597176448Sdavidch		sc->free_rx_bd++;
6598179771Sdavidch
6599206268Sdavidch		/*
6600207411Sdavidch 		 * Frames received on the NetXteme II are prepended
6601207411Sdavidch 		 * with an l2_fhdr structure which provides status
6602207411Sdavidch 		 * information about the received frame (including
6603207411Sdavidch 		 * VLAN tags and checksum info).  The frames are
6604218423Sdavidch		 * also automatically adjusted to word align the IP
6605207411Sdavidch 		 * header (i.e. two null bytes are inserted before
6606207411Sdavidch 		 * the Ethernet	header).  As a result the data
6607207411Sdavidch 		 * DMA'd by the controller into	the mbuf looks
6608207411Sdavidch		 * like this:
6609207411Sdavidch		 *
6610206268Sdavidch		 * +---------+-----+---------------------+-----+
6611206268Sdavidch		 * | l2_fhdr | pad | packet data         | FCS |
6612206268Sdavidch		 * +---------+-----+---------------------+-----+
6613207411Sdavidch		 *
6614207411Sdavidch 		 * The l2_fhdr needs to be checked and skipped and
6615207411Sdavidch 		 * the FCS needs to be stripped before sending the
6616207411Sdavidch		 * packet up the stack.
6617206268Sdavidch		 */
6618176448Sdavidch		l2fhdr  = mtod(m0, struct l2_fhdr *);
6619157642Sps
6620176448Sdavidch		/* Get the packet data + FCS length and the status. */
6621176448Sdavidch		pkt_len = l2fhdr->l2_fhdr_pkt_len;
6622176448Sdavidch		status  = l2fhdr->l2_fhdr_status;
6623178132Sdavidch
6624176448Sdavidch		/*
6625178132Sdavidch		 * Skip over the l2_fhdr and pad, resulting in the
6626179771Sdavidch		 * following data in the mbuf:
6627178132Sdavidch		 * +---------------------+-----+
6628178132Sdavidch		 * | packet data         | FCS |
6629178132Sdavidch		 * +---------------------+-----+
6630178132Sdavidch		 */
6631176448Sdavidch		m_adj(m0, sizeof(struct l2_fhdr) + ETHER_ALIGN);
6632178132Sdavidch
6633178132Sdavidch		/*
6634218423Sdavidch 		 * When split header mode is used, an ethernet frame
6635218423Sdavidch 		 * may be split across the receive chain and the
6636218423Sdavidch 		 * page chain. If that occurs an mbuf cluster must be
6637218423Sdavidch 		 * reassembled from the individual mbuf pieces.
6638176448Sdavidch		 */
6639218423Sdavidch		if (bce_hdr_split == TRUE) {
6640170392Sdavidch			/*
6641218423Sdavidch			 * Check whether the received frame fits in a single
6642218423Sdavidch			 * mbuf or not (i.e. packet data + FCS <=
6643218423Sdavidch			 * sc->rx_bd_mbuf_data_len bytes).
6644169632Sdavidch			 */
6645218423Sdavidch			if (pkt_len > m0->m_len) {
6646218423Sdavidch				/*
6647218423Sdavidch				 * The received frame is larger than a single mbuf.
6648218423Sdavidch				 * If the frame was a TCP frame then only the TCP
6649218423Sdavidch				 * header is placed in the mbuf, the remaining
6650218423Sdavidch				 * payload (including FCS) is placed in the page
6651218423Sdavidch				 * chain, the SPLIT flag is set, and the header
6652218423Sdavidch				 * length is placed in the IP checksum field.
6653218423Sdavidch				 * If the frame is not a TCP frame then the mbuf
6654218423Sdavidch				 * is filled and the remaining bytes are placed
6655218423Sdavidch				 * in the page chain.
6656218423Sdavidch				 */
6657178132Sdavidch
6658218423Sdavidch				DBPRINT(sc, BCE_INFO_RECV, "%s(): Found a large "
6659218423Sdavidch					"packet.\n", __FUNCTION__);
6660218423Sdavidch				DBRUN(sc->split_header_frames_rcvd++);
6661178132Sdavidch
6662218423Sdavidch				/*
6663218423Sdavidch				 * When the page chain is enabled and the TCP
6664218423Sdavidch				 * header has been split from the TCP payload,
6665218423Sdavidch				 * the ip_xsum structure will reflect the length
6666218423Sdavidch				 * of the TCP header, not the IP checksum.  Set
6667218423Sdavidch				 * the packet length of the mbuf accordingly.
6668218423Sdavidch				 */
6669218423Sdavidch				if (status & L2_FHDR_STATUS_SPLIT) {
6670218423Sdavidch					m0->m_len = l2fhdr->l2_fhdr_ip_xsum;
6671218423Sdavidch					DBRUN(sc->split_header_tcp_frames_rcvd++);
6672218423Sdavidch				}
6673178132Sdavidch
6674218423Sdavidch				rem_len = pkt_len - m0->m_len;
6675178132Sdavidch
6676218423Sdavidch				/* Pull mbufs off the page chain for any remaining data. */
6677218423Sdavidch				while (rem_len > 0) {
6678218423Sdavidch					struct mbuf *m_pg;
6679179771Sdavidch
6680218423Sdavidch					sw_pg_cons_idx = PG_CHAIN_IDX(sw_pg_cons);
6681178132Sdavidch
6682218423Sdavidch					/* Remove the mbuf from the page chain. */
6683218423Sdavidch					m_pg = sc->pg_mbuf_ptr[sw_pg_cons_idx];
6684218423Sdavidch					sc->pg_mbuf_ptr[sw_pg_cons_idx] = NULL;
6685218423Sdavidch					DBRUN(sc->debug_pg_mbuf_alloc--);
6686218423Sdavidch					sc->free_pg_bd++;
6687157642Sps
6688218423Sdavidch					/* Unmap the page chain mbuf from DMA space. */
6689218423Sdavidch					bus_dmamap_sync(sc->pg_mbuf_tag,
6690218423Sdavidch						sc->pg_mbuf_map[sw_pg_cons_idx],
6691218423Sdavidch						BUS_DMASYNC_POSTREAD);
6692218423Sdavidch					bus_dmamap_unload(sc->pg_mbuf_tag,
6693218423Sdavidch						sc->pg_mbuf_map[sw_pg_cons_idx]);
6694157642Sps
6695218423Sdavidch					/* Adjust the mbuf length. */
6696218423Sdavidch					if (rem_len < m_pg->m_len) {
6697218423Sdavidch						/* The mbuf chain is complete. */
6698218423Sdavidch						m_pg->m_len = rem_len;
6699218423Sdavidch						rem_len = 0;
6700218423Sdavidch					} else {
6701218423Sdavidch						/* More packet data is waiting. */
6702218423Sdavidch						rem_len -= m_pg->m_len;
6703218423Sdavidch					}
6704178132Sdavidch
6705218423Sdavidch					/* Concatenate the mbuf cluster to the mbuf. */
6706218423Sdavidch					m_cat(m0, m_pg);
6707157642Sps
6708218423Sdavidch					sw_pg_cons = NEXT_PG_BD(sw_pg_cons);
6709218423Sdavidch				}
6710176448Sdavidch
6711218423Sdavidch				/* Set the total packet length. */
6712218423Sdavidch				m0->m_pkthdr.len = pkt_len;
6713178132Sdavidch
6714218423Sdavidch			} else {
6715218423Sdavidch				/*
6716218423Sdavidch				 * The received packet is small and fits in a
6717218423Sdavidch				 * single mbuf (i.e. the l2_fhdr + pad + packet +
6718218423Sdavidch				 * FCS <= MHLEN).  In other words, the packet is
6719218423Sdavidch				 * 154 bytes or less in size.
6720218423Sdavidch				 */
6721157642Sps
6722218423Sdavidch				DBPRINT(sc, BCE_INFO_RECV, "%s(): Found a small "
6723218423Sdavidch					"packet.\n", __FUNCTION__);
6724178132Sdavidch
6725218423Sdavidch				/* Set the total packet length. */
6726218423Sdavidch				m0->m_pkthdr.len = m0->m_len = pkt_len;
6727218423Sdavidch			}
6728218423Sdavidch		} else
6729176448Sdavidch			/* Set the total packet length. */
6730176448Sdavidch			m0->m_pkthdr.len = m0->m_len = pkt_len;
6731178132Sdavidch
6732178132Sdavidch		/* Remove the trailing Ethernet FCS. */
6733178132Sdavidch		m_adj(m0, -ETHER_CRC_LEN);
6734178132Sdavidch
6735176448Sdavidch		/* Check that the resulting mbuf chain is valid. */
6736176448Sdavidch		DBRUN(m_sanity(m0, FALSE));
6737179771Sdavidch		DBRUNIF(((m0->m_len < ETHER_HDR_LEN) |
6738206268Sdavidch		    (m0->m_pkthdr.len > BCE_MAX_JUMBO_ETHER_MTU_VLAN)),
6739218423Sdavidch		    BCE_PRINTF("Invalid Ethernet frame size!\n");
6740218423Sdavidch		    m_print(m0, 128));
6741157642Sps
6742189325Sdavidch		DBRUNIF(DB_RANDOMTRUE(l2fhdr_error_sim_control),
6743206268Sdavidch		    sc->l2fhdr_error_sim_count++;
6744206268Sdavidch		    status = status | L2_FHDR_ERRORS_PHY_DECODE);
6745157642Sps
6746176448Sdavidch		/* Check the received frame for errors. */
6747207411Sdavidch		if (status & (L2_FHDR_ERRORS_BAD_CRC |
6748206268Sdavidch		    L2_FHDR_ERRORS_PHY_DECODE | L2_FHDR_ERRORS_ALIGNMENT |
6749206268Sdavidch		    L2_FHDR_ERRORS_TOO_SHORT  | L2_FHDR_ERRORS_GIANT_FRAME)) {
6750157642Sps
6751176448Sdavidch			/* Log the error and release the mbuf. */
6752189325Sdavidch			sc->l2fhdr_error_count++;
6753176448Sdavidch			m_freem(m0);
6754176448Sdavidch			m0 = NULL;
6755251146Smarius			goto bce_rx_intr_next_rx;
6756176448Sdavidch		}
6757157642Sps
6758176448Sdavidch		/* Send the packet to the appropriate interface. */
6759176448Sdavidch		m0->m_pkthdr.rcvif = ifp;
6760178132Sdavidch
6761178132Sdavidch		/* Assume no hardware checksum. */
6762176448Sdavidch		m0->m_pkthdr.csum_flags = 0;
6763178132Sdavidch
6764176448Sdavidch		/* Validate the checksum if offload enabled. */
6765176448Sdavidch		if (ifp->if_capenable & IFCAP_RXCSUM) {
6766176448Sdavidch			/* Check for an IP datagram. */
6767178132Sdavidch		 	if (!(status & L2_FHDR_STATUS_SPLIT) &&
6768207411Sdavidch			    (status & L2_FHDR_STATUS_IP_DATAGRAM)) {
6769176448Sdavidch				m0->m_pkthdr.csum_flags |= CSUM_IP_CHECKED;
6770207411Sdavidch				DBRUN(sc->csum_offload_ip++);
6771176448Sdavidch				/* Check if the IP checksum is valid. */
6772176448Sdavidch				if ((l2fhdr->l2_fhdr_ip_xsum ^ 0xffff) == 0)
6773207411Sdavidch					m0->m_pkthdr.csum_flags |=
6774206268Sdavidch					    CSUM_IP_VALID;
6775178132Sdavidch			}
6776157642Sps
6777176448Sdavidch			/* Check for a valid TCP/UDP frame. */
6778176448Sdavidch			if (status & (L2_FHDR_STATUS_TCP_SEGMENT |
6779206268Sdavidch			    L2_FHDR_STATUS_UDP_DATAGRAM)) {
6780157642Sps
6781176448Sdavidch				/* Check for a good TCP/UDP checksum. */
6782176448Sdavidch				if ((status & (L2_FHDR_ERRORS_TCP_XSUM |
6783206268Sdavidch				    L2_FHDR_ERRORS_UDP_XSUM)) == 0) {
6784207411Sdavidch					DBRUN(sc->csum_offload_tcp_udp++);
6785176448Sdavidch					m0->m_pkthdr.csum_data =
6786176448Sdavidch					    l2fhdr->l2_fhdr_tcp_udp_xsum;
6787207411Sdavidch					m0->m_pkthdr.csum_flags |=
6788206268Sdavidch					    (CSUM_DATA_VALID
6789206268Sdavidch					    | CSUM_PSEUDO_HDR);
6790157642Sps				}
6791176448Sdavidch			}
6792179771Sdavidch		}
6793157642Sps
6794189325Sdavidch		/* Attach the VLAN tag.	*/
6795251146Smarius		if ((status & L2_FHDR_STATUS_L2_VLAN_TAG) &&
6796251146Smarius		    !(sc->rx_mode & BCE_EMAC_RX_MODE_KEEP_VLAN_TAG)) {
6797218423Sdavidch			DBRUN(sc->vlan_tagged_frames_rcvd++);
6798204368Syongari			if (ifp->if_capenable & IFCAP_VLAN_HWTAGGING) {
6799218423Sdavidch				DBRUN(sc->vlan_tagged_frames_stripped++);
6800157642Sps#if __FreeBSD_version < 700000
6801204368Syongari				VLAN_INPUT_TAG(ifp, m0,
6802204368Syongari				    l2fhdr->l2_fhdr_vlan_tag, continue);
6803157642Sps#else
6804204368Syongari				m0->m_pkthdr.ether_vtag =
6805204368Syongari				    l2fhdr->l2_fhdr_vlan_tag;
6806204368Syongari				m0->m_flags |= M_VLANTAG;
6807179771Sdavidch#endif
6808204368Syongari			} else {
6809204368Syongari				/*
6810204368Syongari				 * bce(4) controllers can't disable VLAN
6811204368Syongari				 * tag stripping if management firmware
6812204368Syongari				 * (ASF/IPMI/UMP) is running. So we always
6813204368Syongari				 * strip VLAN tag and manually reconstruct
6814204368Syongari				 * the VLAN frame by appending stripped
6815204368Syongari				 * VLAN tag in driver if VLAN tag stripping
6816204368Syongari				 * was disabled.
6817204368Syongari				 *
6818204368Syongari				 * TODO: LLC SNAP handling.
6819204368Syongari				 */
6820204368Syongari				bcopy(mtod(m0, uint8_t *),
6821204368Syongari				    mtod(m0, uint8_t *) - ETHER_VLAN_ENCAP_LEN,
6822204368Syongari				    ETHER_ADDR_LEN * 2);
6823204368Syongari				m0->m_data -= ETHER_VLAN_ENCAP_LEN;
6824204368Syongari				vh = mtod(m0, struct ether_vlan_header *);
6825204368Syongari				vh->evl_encap_proto = htons(ETHERTYPE_VLAN);
6826204368Syongari				vh->evl_tag = htons(l2fhdr->l2_fhdr_vlan_tag);
6827204368Syongari				m0->m_pkthdr.len += ETHER_VLAN_ENCAP_LEN;
6828204368Syongari				m0->m_len += ETHER_VLAN_ENCAP_LEN;
6829204368Syongari			}
6830176448Sdavidch		}
6831157642Sps
6832189325Sdavidch		/* Increment received packet statistics. */
6833272096Sglebius		if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1);
6834157642Sps
6835251146Smariusbce_rx_intr_next_rx:
6836176448Sdavidch		sw_rx_cons = NEXT_RX_BD(sw_rx_cons);
6837157642Sps
6838170392Sdavidch		/* If we have a packet, pass it up the stack */
6839176448Sdavidch		if (m0) {
6840170392Sdavidch			/* Make sure we don't lose our place when we release the lock. */
6841178132Sdavidch			sc->rx_cons = sw_rx_cons;
6842179771Sdavidch			sc->pg_cons = sw_pg_cons;
6843170392Sdavidch
6844169271Sdavidch			BCE_UNLOCK(sc);
6845176448Sdavidch			(*ifp->if_input)(ifp, m0);
6846170392Sdavidch			BCE_LOCK(sc);
6847179771Sdavidch
6848170392Sdavidch			/* Recover our place. */
6849178132Sdavidch			sw_rx_cons = sc->rx_cons;
6850179771Sdavidch			sw_pg_cons = sc->pg_cons;
6851170392Sdavidch		}
6852170392Sdavidch
6853157642Sps		/* Refresh hw_cons to see if there's new work */
6854176448Sdavidch		if (sw_rx_cons == hw_rx_cons)
6855176448Sdavidch			hw_rx_cons = sc->hw_rx_cons = bce_get_hw_rx_cons(sc);
6856157642Sps	}
6857157642Sps
6858207411Sdavidch	/* No new packets.  Refill the page chain. */
6859218423Sdavidch	if (bce_hdr_split == TRUE) {
6860218423Sdavidch		sc->pg_cons = sw_pg_cons;
6861218423Sdavidch		bce_fill_pg_chain(sc);
6862218423Sdavidch	}
6863176448Sdavidch
6864207411Sdavidch	/* No new packets.  Refill the RX chain. */
6865176448Sdavidch	sc->rx_cons = sw_rx_cons;
6866171667Sdavidch	bce_fill_rx_chain(sc);
6867171667Sdavidch
6868192281Sdelphij	/* Prepare the page chain pages to be accessed by the NIC. */
6869218423Sdavidch	for (int i = 0; i < sc->rx_pages; i++)
6870157642Sps		bus_dmamap_sync(sc->rx_bd_chain_tag,
6871157642Sps		    sc->rx_bd_chain_map[i], BUS_DMASYNC_PREWRITE);
6872157642Sps
6873218423Sdavidch	if (bce_hdr_split == TRUE) {
6874218423Sdavidch		for (int i = 0; i < sc->pg_pages; i++)
6875218423Sdavidch			bus_dmamap_sync(sc->pg_bd_chain_tag,
6876218423Sdavidch			    sc->pg_bd_chain_map[i], BUS_DMASYNC_PREWRITE);
6877218423Sdavidch	}
6878176448Sdavidch
6879179771Sdavidch	DBPRINT(sc, BCE_EXTREME_RECV, "%s(exit): rx_prod = 0x%04X, "
6880206268Sdavidch	    "rx_cons = 0x%04X, rx_prod_bseq = 0x%08X\n",
6881206268Sdavidch	    __FUNCTION__, sc->rx_prod, sc->rx_cons, sc->rx_prod_bseq);
6882179771Sdavidch	DBEXIT(BCE_VERBOSE_RECV | BCE_VERBOSE_INTR);
6883157642Sps}
6884157642Sps
6885157642Sps
6886157642Sps/****************************************************************************/
6887178132Sdavidch/* Reads the transmit consumer value from the status block (skipping over   */
6888178132Sdavidch/* chain page pointer if necessary).                                        */
6889178132Sdavidch/*                                                                          */
6890178132Sdavidch/* Returns:                                                                 */
6891178132Sdavidch/*   hw_cons                                                                */
6892178132Sdavidch/****************************************************************************/
6893178132Sdavidchstatic inline u16
6894178132Sdavidchbce_get_hw_tx_cons(struct bce_softc *sc)
6895178132Sdavidch{
6896182293Sdavidch	u16 hw_cons;
6897178132Sdavidch
6898182293Sdavidch	mb();
6899182293Sdavidch	hw_cons = sc->status_block->status_tx_quick_consumer_index0;
6900178132Sdavidch	if ((hw_cons & USABLE_TX_BD_PER_PAGE) == USABLE_TX_BD_PER_PAGE)
6901178132Sdavidch		hw_cons++;
6902178132Sdavidch
6903178132Sdavidch	return hw_cons;
6904178132Sdavidch}
6905178132Sdavidch
6906178132Sdavidch
6907178132Sdavidch/****************************************************************************/
6908157642Sps/* Handles transmit completion interrupt events.                            */
6909157642Sps/*                                                                          */
6910157642Sps/* Returns:                                                                 */
6911157642Sps/*   Nothing.                                                               */
6912157642Sps/****************************************************************************/
6913157642Spsstatic void
6914157642Spsbce_tx_intr(struct bce_softc *sc)
6915157642Sps{
6916157642Sps	struct ifnet *ifp = sc->bce_ifp;
6917157642Sps	u16 hw_tx_cons, sw_tx_cons, sw_tx_chain_cons;
6918178132Sdavidch
6919179771Sdavidch	DBENTER(BCE_VERBOSE_SEND | BCE_VERBOSE_INTR);
6920207411Sdavidch	DBRUN(sc->interrupts_tx++);
6921179771Sdavidch	DBPRINT(sc, BCE_EXTREME_SEND, "%s(enter): tx_prod = 0x%04X, "
6922206268Sdavidch	    "tx_cons = 0x%04X, tx_prod_bseq = 0x%08X\n",
6923206268Sdavidch	    __FUNCTION__, sc->tx_prod, sc->tx_cons, sc->tx_prod_bseq);
6924157642Sps
6925157642Sps	BCE_LOCK_ASSERT(sc);
6926157642Sps
6927157642Sps	/* Get the hardware's view of the TX consumer index. */
6928178132Sdavidch	hw_tx_cons = sc->hw_tx_cons = bce_get_hw_tx_cons(sc);
6929157642Sps	sw_tx_cons = sc->tx_cons;
6930157642Sps
6931207411Sdavidch	/* Prevent speculative reads of the status block. */
6932179771Sdavidch	bus_space_barrier(sc->bce_btag, sc->bce_bhandle, 0, 0,
6933206268Sdavidch	    BUS_SPACE_BARRIER_READ);
6934157642Sps
6935157642Sps	/* Cycle through any completed TX chain page entries. */
6936157642Sps	while (sw_tx_cons != hw_tx_cons) {
6937157642Sps#ifdef BCE_DEBUG
6938157642Sps		struct tx_bd *txbd = NULL;
6939157642Sps#endif
6940157642Sps		sw_tx_chain_cons = TX_CHAIN_IDX(sw_tx_cons);
6941157642Sps
6942157642Sps		DBPRINT(sc, BCE_INFO_SEND,
6943206268Sdavidch		    "%s(): hw_tx_cons = 0x%04X, sw_tx_cons = 0x%04X, "
6944206268Sdavidch		    "sw_tx_chain_cons = 0x%04X\n",
6945206268Sdavidch		    __FUNCTION__, hw_tx_cons, sw_tx_cons, sw_tx_chain_cons);
6946157642Sps
6947218423Sdavidch		DBRUNIF((sw_tx_chain_cons > MAX_TX_BD_ALLOC),
6948206268Sdavidch		    BCE_PRINTF("%s(%d): TX chain consumer out of range! "
6949206268Sdavidch		    " 0x%04X > 0x%04X\n", __FILE__, __LINE__, sw_tx_chain_cons,
6950218423Sdavidch		    (int) MAX_TX_BD_ALLOC);
6951206268Sdavidch		    bce_breakpoint(sc));
6952157642Sps
6953176448Sdavidch		DBRUN(txbd = &sc->tx_bd_chain[TX_PAGE(sw_tx_chain_cons)]
6954206268Sdavidch		    [TX_IDX(sw_tx_chain_cons)]);
6955179771Sdavidch
6956157642Sps		DBRUNIF((txbd == NULL),
6957206268Sdavidch		    BCE_PRINTF("%s(%d): Unexpected NULL tx_bd[0x%04X]!\n",
6958206268Sdavidch		    __FILE__, __LINE__, sw_tx_chain_cons);
6959206268Sdavidch		    bce_breakpoint(sc));
6960157642Sps
6961176448Sdavidch		DBRUNMSG(BCE_INFO_SEND, BCE_PRINTF("%s(): ", __FUNCTION__);
6962206268Sdavidch		    bce_dump_txbd(sc, sw_tx_chain_cons, txbd));
6963157642Sps
6964157642Sps		/*
6965157642Sps		 * Free the associated mbuf. Remember
6966157642Sps		 * that only the last tx_bd of a packet
6967157642Sps		 * has an mbuf pointer and DMA map.
6968157642Sps		 */
6969157642Sps		if (sc->tx_mbuf_ptr[sw_tx_chain_cons] != NULL) {
6970157642Sps
6971157642Sps			/* Validate that this is the last tx_bd. */
6972164329Sscottl			DBRUNIF((!(txbd->tx_bd_flags & TX_BD_FLAGS_END)),
6973206268Sdavidch			    BCE_PRINTF("%s(%d): tx_bd END flag not set but "
6974206268Sdavidch			    "txmbuf == NULL!\n", __FILE__, __LINE__);
6975206268Sdavidch			    bce_breakpoint(sc));
6976157642Sps
6977179771Sdavidch			DBRUNMSG(BCE_INFO_SEND,
6978206268Sdavidch			    BCE_PRINTF("%s(): Unloading map/freeing mbuf "
6979207411Sdavidch			    "from tx_bd[0x%04X]\n", __FUNCTION__,
6980206268Sdavidch			    sw_tx_chain_cons));
6981157642Sps
6982157642Sps			/* Unmap the mbuf. */
6983157642Sps			bus_dmamap_unload(sc->tx_mbuf_tag,
6984157642Sps			    sc->tx_mbuf_map[sw_tx_chain_cons]);
6985179771Sdavidch
6986157642Sps			/* Free the mbuf. */
6987157642Sps			m_freem(sc->tx_mbuf_ptr[sw_tx_chain_cons]);
6988157642Sps			sc->tx_mbuf_ptr[sw_tx_chain_cons] = NULL;
6989176448Sdavidch			DBRUN(sc->debug_tx_mbuf_alloc--);
6990157642Sps
6991272096Sglebius			if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1);
6992157642Sps		}
6993157642Sps
6994157642Sps		sc->used_tx_bd--;
6995157642Sps		sw_tx_cons = NEXT_TX_BD(sw_tx_cons);
6996157642Sps
6997157642Sps		/* Refresh hw_cons to see if there's new work. */
6998178132Sdavidch		hw_tx_cons = sc->hw_tx_cons = bce_get_hw_tx_cons(sc);
6999157642Sps
7000206268Sdavidch		/* Prevent speculative reads of the status block. */
7001179771Sdavidch		bus_space_barrier(sc->bce_btag, sc->bce_bhandle, 0, 0,
7002206268Sdavidch		    BUS_SPACE_BARRIER_READ);
7003157642Sps	}
7004157642Sps
7005157642Sps	/* Clear the TX timeout timer. */
7006165933Sdelphij	sc->watchdog_timer = 0;
7007157642Sps
7008157642Sps	/* Clear the tx hardware queue full flag. */
7009169632Sdavidch	if (sc->used_tx_bd < sc->max_tx_bd) {
7010169632Sdavidch		DBRUNIF((ifp->if_drv_flags & IFF_DRV_OACTIVE),
7011206268Sdavidch		    DBPRINT(sc, BCE_INFO_SEND,
7012206268Sdavidch		    "%s(): Open TX chain! %d/%d (used/total)\n",
7013206268Sdavidch		    __FUNCTION__, sc->used_tx_bd, sc->max_tx_bd));
7014157642Sps		ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
7015157642Sps	}
7016157642Sps
7017157642Sps	sc->tx_cons = sw_tx_cons;
7018179771Sdavidch
7019179771Sdavidch	DBPRINT(sc, BCE_EXTREME_SEND, "%s(exit): tx_prod = 0x%04X, "
7020206268Sdavidch	    "tx_cons = 0x%04X, tx_prod_bseq = 0x%08X\n",
7021206268Sdavidch	    __FUNCTION__, sc->tx_prod, sc->tx_cons, sc->tx_prod_bseq);
7022179771Sdavidch	DBEXIT(BCE_VERBOSE_SEND | BCE_VERBOSE_INTR);
7023157642Sps}
7024157642Sps
7025157642Sps
7026157642Sps/****************************************************************************/
7027157642Sps/* Disables interrupt generation.                                           */
7028157642Sps/*                                                                          */
7029157642Sps/* Returns:                                                                 */
7030157642Sps/*   Nothing.                                                               */
7031157642Sps/****************************************************************************/
7032157642Spsstatic void
7033157642Spsbce_disable_intr(struct bce_softc *sc)
7034157642Sps{
7035179771Sdavidch	DBENTER(BCE_VERBOSE_INTR);
7036179771Sdavidch
7037179771Sdavidch	REG_WR(sc, BCE_PCICFG_INT_ACK_CMD, BCE_PCICFG_INT_ACK_CMD_MASK_INT);
7038157642Sps	REG_RD(sc, BCE_PCICFG_INT_ACK_CMD);
7039179771Sdavidch
7040179771Sdavidch	DBEXIT(BCE_VERBOSE_INTR);
7041157642Sps}
7042157642Sps
7043157642Sps
7044157642Sps/****************************************************************************/
7045157642Sps/* Enables interrupt generation.                                            */
7046157642Sps/*                                                                          */
7047157642Sps/* Returns:                                                                 */
7048157642Sps/*   Nothing.                                                               */
7049157642Sps/****************************************************************************/
7050157642Spsstatic void
7051179771Sdavidchbce_enable_intr(struct bce_softc *sc, int coal_now)
7052157642Sps{
7053179771Sdavidch	DBENTER(BCE_VERBOSE_INTR);
7054157642Sps
7055157642Sps	REG_WR(sc, BCE_PCICFG_INT_ACK_CMD,
7056206268Sdavidch	    BCE_PCICFG_INT_ACK_CMD_INDEX_VALID |
7057206268Sdavidch	    BCE_PCICFG_INT_ACK_CMD_MASK_INT | sc->last_status_idx);
7058157642Sps
7059157642Sps	REG_WR(sc, BCE_PCICFG_INT_ACK_CMD,
7060206268Sdavidch	    BCE_PCICFG_INT_ACK_CMD_INDEX_VALID | sc->last_status_idx);
7061157642Sps
7062179771Sdavidch	/* Force an immediate interrupt (whether there is new data or not). */
7063179771Sdavidch	if (coal_now)
7064179771Sdavidch		REG_WR(sc, BCE_HC_COMMAND, sc->hc_command | BCE_HC_COMMAND_COAL_NOW);
7065179771Sdavidch
7066179771Sdavidch	DBEXIT(BCE_VERBOSE_INTR);
7067157642Sps}
7068157642Sps
7069157642Sps
7070157642Sps/****************************************************************************/
7071157642Sps/* Handles controller initialization.                                       */
7072157642Sps/*                                                                          */
7073157642Sps/* Returns:                                                                 */
7074157642Sps/*   Nothing.                                                               */
7075157642Sps/****************************************************************************/
7076157642Spsstatic void
7077157642Spsbce_init_locked(struct bce_softc *sc)
7078157642Sps{
7079157642Sps	struct ifnet *ifp;
7080176448Sdavidch	u32 ether_mtu = 0;
7081157642Sps
7082179771Sdavidch	DBENTER(BCE_VERBOSE_RESET);
7083157642Sps
7084157642Sps	BCE_LOCK_ASSERT(sc);
7085157642Sps
7086157642Sps	ifp = sc->bce_ifp;
7087157642Sps
7088157642Sps	/* Check if the driver is still running and bail out if it is. */
7089157642Sps	if (ifp->if_drv_flags & IFF_DRV_RUNNING)
7090157642Sps		goto bce_init_locked_exit;
7091157642Sps
7092157642Sps	bce_stop(sc);
7093157642Sps
7094157642Sps	if (bce_reset(sc, BCE_DRV_MSG_CODE_RESET)) {
7095179771Sdavidch		BCE_PRINTF("%s(%d): Controller reset failed!\n",
7096206268Sdavidch		    __FILE__, __LINE__);
7097157642Sps		goto bce_init_locked_exit;
7098157642Sps	}
7099157642Sps
7100157642Sps	if (bce_chipinit(sc)) {
7101179771Sdavidch		BCE_PRINTF("%s(%d): Controller initialization failed!\n",
7102206268Sdavidch		    __FILE__, __LINE__);
7103157642Sps		goto bce_init_locked_exit;
7104157642Sps	}
7105157642Sps
7106157642Sps	if (bce_blockinit(sc)) {
7107179771Sdavidch		BCE_PRINTF("%s(%d): Block initialization failed!\n",
7108206268Sdavidch		    __FILE__, __LINE__);
7109157642Sps		goto bce_init_locked_exit;
7110157642Sps	}
7111157642Sps
7112157642Sps	/* Load our MAC address. */
7113157642Sps	bcopy(IF_LLADDR(sc->bce_ifp), sc->eaddr, ETHER_ADDR_LEN);
7114157642Sps	bce_set_mac_addr(sc);
7115157642Sps
7116235119Syongari	if (bce_hdr_split == FALSE)
7117235119Syongari		bce_get_rx_buffer_sizes(sc, ifp->if_mtu);
7118182293Sdavidch	/*
7119182293Sdavidch	 * Calculate and program the hardware Ethernet MTU
7120218423Sdavidch 	 * size. Be generous on the receive if we have room
7121218423Sdavidch 	 * and allowed by the user.
7122179695Sdavidch	 */
7123218423Sdavidch	if (bce_strict_rx_mtu == TRUE)
7124179771Sdavidch		ether_mtu = ifp->if_mtu;
7125218423Sdavidch	else {
7126218423Sdavidch		if (bce_hdr_split == TRUE) {
7127251142Smarius			if (ifp->if_mtu <= sc->rx_bd_mbuf_data_len + MCLBYTES)
7128251142Smarius				ether_mtu = sc->rx_bd_mbuf_data_len +
7129251142Smarius				    MCLBYTES;
7130218423Sdavidch			else
7131218423Sdavidch				ether_mtu = ifp->if_mtu;
7132218423Sdavidch		} else {
7133218423Sdavidch			if (ifp->if_mtu <= sc->rx_bd_mbuf_data_len)
7134218423Sdavidch				ether_mtu = sc->rx_bd_mbuf_data_len;
7135218423Sdavidch			else
7136218423Sdavidch				ether_mtu = ifp->if_mtu;
7137218423Sdavidch		}
7138218423Sdavidch	}
7139178132Sdavidch
7140176448Sdavidch	ether_mtu += ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN + ETHER_CRC_LEN;
7141157642Sps
7142207411Sdavidch	DBPRINT(sc, BCE_INFO_MISC, "%s(): setting h/w mtu = %d\n",
7143206268Sdavidch	    __FUNCTION__, ether_mtu);
7144157642Sps
7145176448Sdavidch	/* Program the mtu, enabling jumbo frame support if necessary. */
7146176448Sdavidch	if (ether_mtu > (ETHER_MAX_LEN + ETHER_VLAN_ENCAP_LEN))
7147179771Sdavidch		REG_WR(sc, BCE_EMAC_RX_MTU_SIZE,
7148206268Sdavidch		    min(ether_mtu, BCE_MAX_JUMBO_ETHER_MTU) |
7149206268Sdavidch		    BCE_EMAC_RX_MTU_SIZE_JUMBO_ENA);
7150176448Sdavidch	else
7151157642Sps		REG_WR(sc, BCE_EMAC_RX_MTU_SIZE, ether_mtu);
7152157642Sps
7153157642Sps	/* Program appropriate promiscuous/multicast filtering. */
7154157642Sps	bce_set_rx_mode(sc);
7155157642Sps
7156218423Sdavidch	if (bce_hdr_split == TRUE) {
7157218423Sdavidch		/* Init page buffer descriptor chain. */
7158218423Sdavidch		bce_init_pg_chain(sc);
7159218423Sdavidch	}
7160176448Sdavidch
7161157642Sps	/* Init RX buffer descriptor chain. */
7162157642Sps	bce_init_rx_chain(sc);
7163179771Sdavidch
7164157642Sps	/* Init TX buffer descriptor chain. */
7165157642Sps	bce_init_tx_chain(sc);
7166157642Sps
7167157642Sps	/* Enable host interrupts. */
7168179771Sdavidch	bce_enable_intr(sc, 1);
7169157642Sps
7170234121Syongari	bce_ifmedia_upd_locked(ifp);
7171234121Syongari
7172202717Sdavidch	/* Let the OS know the driver is up and running. */
7173157642Sps	ifp->if_drv_flags |= IFF_DRV_RUNNING;
7174157642Sps	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
7175157642Sps
7176170810Sdavidch	callout_reset(&sc->bce_tick_callout, hz, bce_tick, sc);
7177157642Sps
7178157642Spsbce_init_locked_exit:
7179179771Sdavidch	DBEXIT(BCE_VERBOSE_RESET);
7180157642Sps}
7181157642Sps
7182170392Sdavidch
7183169271Sdavidch/****************************************************************************/
7184170392Sdavidch/* Initialize the controller just enough so that any management firmware    */
7185170810Sdavidch/* running on the device will continue to operate correctly.                */
7186169271Sdavidch/*                                                                          */
7187169271Sdavidch/* Returns:                                                                 */
7188169271Sdavidch/*   Nothing.                                                               */
7189169271Sdavidch/****************************************************************************/
7190162474Sambriskostatic void
7191162474Sambriskobce_mgmt_init_locked(struct bce_softc *sc)
7192162474Sambrisko{
7193162474Sambrisko	struct ifnet *ifp;
7194157642Sps
7195179771Sdavidch	DBENTER(BCE_VERBOSE_RESET);
7196162474Sambrisko
7197162474Sambrisko	BCE_LOCK_ASSERT(sc);
7198162474Sambrisko
7199170810Sdavidch	/* Bail out if management firmware is not running. */
7200170810Sdavidch	if (!(sc->bce_flags & BCE_MFW_ENABLE_FLAG)) {
7201179771Sdavidch		DBPRINT(sc, BCE_VERBOSE_SPECIAL,
7202206268Sdavidch		    "No management firmware running...\n");
7203162474Sambrisko		goto bce_mgmt_init_locked_exit;
7204170810Sdavidch	}
7205162474Sambrisko
7206170810Sdavidch	ifp = sc->bce_ifp;
7207162474Sambrisko
7208162474Sambrisko	/* Enable all critical blocks in the MAC. */
7209179771Sdavidch	REG_WR(sc, BCE_MISC_ENABLE_SET_BITS, BCE_MISC_ENABLE_DEFAULT);
7210162474Sambrisko	REG_RD(sc, BCE_MISC_ENABLE_SET_BITS);
7211162474Sambrisko	DELAY(20);
7212162474Sambrisko
7213165994Sjhb	bce_ifmedia_upd_locked(ifp);
7214179771Sdavidch
7215162474Sambriskobce_mgmt_init_locked_exit:
7216179771Sdavidch	DBEXIT(BCE_VERBOSE_RESET);
7217162474Sambrisko}
7218162474Sambrisko
7219162474Sambrisko
7220157642Sps/****************************************************************************/
7221157642Sps/* Handles controller initialization when called from an unlocked routine.  */
7222157642Sps/*                                                                          */
7223157642Sps/* Returns:                                                                 */
7224157642Sps/*   Nothing.                                                               */
7225157642Sps/****************************************************************************/
7226157642Spsstatic void
7227157642Spsbce_init(void *xsc)
7228157642Sps{
7229178132Sdavidch	struct bce_softc *sc = xsc;
7230157642Sps
7231179771Sdavidch	DBENTER(BCE_VERBOSE_RESET);
7232179771Sdavidch
7233157642Sps	BCE_LOCK(sc);
7234157642Sps	bce_init_locked(sc);
7235157642Sps	BCE_UNLOCK(sc);
7236179771Sdavidch
7237179771Sdavidch	DBEXIT(BCE_VERBOSE_RESET);
7238157642Sps}
7239157642Sps
7240157642Sps
7241207411Sdavidch/****************************************************************************/
7242207411Sdavidch/* Modifies an mbuf for TSO on the hardware.                                */
7243207411Sdavidch/*                                                                          */
7244207411Sdavidch/* Returns:                                                                 */
7245207411Sdavidch/*   Pointer to a modified mbuf.                                            */
7246207411Sdavidch/****************************************************************************/
7247204373Syongaristatic struct mbuf *
7248204373Syongaribce_tso_setup(struct bce_softc *sc, struct mbuf **m_head, u16 *flags)
7249204373Syongari{
7250204373Syongari	struct mbuf *m;
7251204373Syongari	struct ether_header *eh;
7252204373Syongari	struct ip *ip;
7253204373Syongari	struct tcphdr *th;
7254204373Syongari	u16 etype;
7255204373Syongari	int hdr_len, ip_hlen = 0, tcp_hlen = 0, ip_len = 0;
7256204373Syongari
7257207411Sdavidch	DBRUN(sc->tso_frames_requested++);
7258207411Sdavidch
7259207411Sdavidch	/* Controller may modify mbuf chains. */
7260204373Syongari	if (M_WRITABLE(*m_head) == 0) {
7261243857Sglebius		m = m_dup(*m_head, M_NOWAIT);
7262204373Syongari		m_freem(*m_head);
7263204373Syongari		if (m == NULL) {
7264204373Syongari			sc->mbuf_alloc_failed_count++;
7265204373Syongari			*m_head = NULL;
7266204373Syongari			return (NULL);
7267204373Syongari		}
7268204373Syongari		*m_head = m;
7269204373Syongari	}
7270207411Sdavidch
7271204373Syongari	/*
7272204373Syongari	 * For TSO the controller needs two pieces of info,
7273204373Syongari	 * the MSS and the IP+TCP options length.
7274204373Syongari	 */
7275204373Syongari	m = m_pullup(*m_head, sizeof(struct ether_header) + sizeof(struct ip));
7276204373Syongari	if (m == NULL) {
7277204373Syongari		*m_head = NULL;
7278204373Syongari		return (NULL);
7279204373Syongari	}
7280204373Syongari	eh = mtod(m, struct ether_header *);
7281204373Syongari	etype = ntohs(eh->ether_type);
7282204373Syongari
7283204373Syongari	/* Check for supported TSO Ethernet types (only IPv4 for now) */
7284204373Syongari	switch (etype) {
7285204373Syongari	case ETHERTYPE_IP:
7286204373Syongari		ip = (struct ip *)(m->m_data + sizeof(struct ether_header));
7287204373Syongari		/* TSO only supported for TCP protocol. */
7288204373Syongari		if (ip->ip_p != IPPROTO_TCP) {
7289204373Syongari			BCE_PRINTF("%s(%d): TSO enabled for non-TCP frame!.\n",
7290204373Syongari			    __FILE__, __LINE__);
7291204373Syongari			m_freem(*m_head);
7292204373Syongari			*m_head = NULL;
7293204373Syongari			return (NULL);
7294204373Syongari		}
7295204373Syongari
7296204373Syongari		/* Get IP header length in bytes (min 20) */
7297204373Syongari		ip_hlen = ip->ip_hl << 2;
7298204373Syongari		m = m_pullup(*m_head, sizeof(struct ether_header) + ip_hlen +
7299204373Syongari		    sizeof(struct tcphdr));
7300204373Syongari		if (m == NULL) {
7301204373Syongari			*m_head = NULL;
7302204373Syongari			return (NULL);
7303204373Syongari		}
7304204373Syongari
7305204373Syongari		/* Get the TCP header length in bytes (min 20) */
7306213844Syongari		ip = (struct ip *)(m->m_data + sizeof(struct ether_header));
7307204373Syongari		th = (struct tcphdr *)((caddr_t)ip + ip_hlen);
7308204373Syongari		tcp_hlen = (th->th_off << 2);
7309204373Syongari
7310204373Syongari		/* Make sure all IP/TCP options live in the same buffer. */
7311204373Syongari		m = m_pullup(*m_head,  sizeof(struct ether_header)+ ip_hlen +
7312204373Syongari		    tcp_hlen);
7313204373Syongari		if (m == NULL) {
7314204373Syongari			*m_head = NULL;
7315204373Syongari			return (NULL);
7316204373Syongari		}
7317204373Syongari
7318218423Sdavidch		/* Clear IP header length and checksum, will be calc'd by h/w. */
7319213844Syongari		ip = (struct ip *)(m->m_data + sizeof(struct ether_header));
7320204373Syongari		ip_len = ip->ip_len;
7321204373Syongari		ip->ip_len = 0;
7322204373Syongari		ip->ip_sum = 0;
7323204373Syongari		break;
7324204373Syongari	case ETHERTYPE_IPV6:
7325204373Syongari		BCE_PRINTF("%s(%d): TSO over IPv6 not supported!.\n",
7326204373Syongari		    __FILE__, __LINE__);
7327204373Syongari		m_freem(*m_head);
7328204373Syongari		*m_head = NULL;
7329204373Syongari		return (NULL);
7330204373Syongari		/* NOT REACHED */
7331204373Syongari	default:
7332204373Syongari		BCE_PRINTF("%s(%d): TSO enabled for unsupported protocol!.\n",
7333204373Syongari		    __FILE__, __LINE__);
7334204373Syongari		m_freem(*m_head);
7335204373Syongari		*m_head = NULL;
7336204373Syongari		return (NULL);
7337204373Syongari	}
7338204373Syongari
7339204373Syongari	hdr_len = sizeof(struct ether_header) + ip_hlen + tcp_hlen;
7340204373Syongari
7341204373Syongari	DBPRINT(sc, BCE_EXTREME_SEND, "%s(): hdr_len = %d, e_hlen = %d, "
7342204373Syongari	    "ip_hlen = %d, tcp_hlen = %d, ip_len = %d\n",
7343205300Sdavidch	    __FUNCTION__, hdr_len, (int) sizeof(struct ether_header), ip_hlen,
7344204373Syongari	    tcp_hlen, ip_len);
7345204373Syongari
7346204373Syongari	/* Set the LSO flag in the TX BD */
7347204373Syongari	*flags |= TX_BD_FLAGS_SW_LSO;
7348207411Sdavidch
7349204373Syongari	/* Set the length of IP + TCP options (in 32 bit words) */
7350204373Syongari	*flags |= (((ip_hlen + tcp_hlen - sizeof(struct ip) -
7351204373Syongari	    sizeof(struct tcphdr)) >> 2) << 8);
7352207411Sdavidch
7353207411Sdavidch	DBRUN(sc->tso_frames_completed++);
7354204373Syongari	return (*m_head);
7355204373Syongari}
7356204373Syongari
7357204373Syongari
7358157642Sps/****************************************************************************/
7359157642Sps/* Encapsultes an mbuf cluster into the tx_bd chain structure and makes the */
7360157642Sps/* memory visible to the controller.                                        */
7361157642Sps/*                                                                          */
7362157642Sps/* Returns:                                                                 */
7363157642Sps/*   0 for success, positive value for failure.                             */
7364171667Sdavidch/* Modified:                                                                */
7365171667Sdavidch/*   m_head: May be set to NULL if MBUF is excessively fragmented.          */
7366157642Sps/****************************************************************************/
7367157642Spsstatic int
7368163393Sscottlbce_tx_encap(struct bce_softc *sc, struct mbuf **m_head)
7369157642Sps{
7370163393Sscottl	bus_dma_segment_t segs[BCE_MAX_SEGMENTS];
7371163393Sscottl	bus_dmamap_t map;
7372163393Sscottl	struct tx_bd *txbd = NULL;
7373163393Sscottl	struct mbuf *m0;
7374204373Syongari	u16 prod, chain_prod, mss = 0, vlan_tag = 0, flags = 0;
7375170392Sdavidch	u32 prod_bseq;
7376157642Sps
7377163393Sscottl#ifdef BCE_DEBUG
7378163393Sscottl	u16 debug_prod;
7379163393Sscottl#endif
7380207411Sdavidch
7381163393Sscottl	int i, error, nsegs, rc = 0;
7382163393Sscottl
7383179771Sdavidch	DBENTER(BCE_VERBOSE_SEND);
7384179771Sdavidch
7385207411Sdavidch	/* Make sure we have room in the TX chain. */
7386207411Sdavidch	if (sc->used_tx_bd >= sc->max_tx_bd)
7387207411Sdavidch		goto bce_tx_encap_exit;
7388207411Sdavidch
7389157642Sps	/* Transfer any checksum offload flags to the bd. */
7390163393Sscottl	m0 = *m_head;
7391163393Sscottl	if (m0->m_pkthdr.csum_flags) {
7392170392Sdavidch		if (m0->m_pkthdr.csum_flags & CSUM_TSO) {
7393204373Syongari			m0 = bce_tso_setup(sc, m_head, &flags);
7394207411Sdavidch			if (m0 == NULL) {
7395207411Sdavidch				DBRUN(sc->tso_frames_failed++);
7396204373Syongari				goto bce_tx_encap_exit;
7397207411Sdavidch			}
7398170392Sdavidch			mss = htole16(m0->m_pkthdr.tso_segsz);
7399204373Syongari		} else {
7400204373Syongari			if (m0->m_pkthdr.csum_flags & CSUM_IP)
7401204373Syongari				flags |= TX_BD_FLAGS_IP_CKSUM;
7402204373Syongari			if (m0->m_pkthdr.csum_flags & (CSUM_TCP | CSUM_UDP))
7403204373Syongari				flags |= TX_BD_FLAGS_TCP_UDP_CKSUM;
7404169632Sdavidch		}
7405157642Sps	}
7406157642Sps
7407157642Sps	/* Transfer any VLAN tags to the bd. */
7408164329Sscottl	if (m0->m_flags & M_VLANTAG) {
7409164329Sscottl		flags |= TX_BD_FLAGS_VLAN_TAG;
7410164329Sscottl		vlan_tag = m0->m_pkthdr.ether_vtag;
7411164329Sscottl	}
7412157642Sps
7413157642Sps	/* Map the mbuf into DMAable memory. */
7414163393Sscottl	prod = sc->tx_prod;
7415163393Sscottl	chain_prod = TX_CHAIN_IDX(prod);
7416163339Sscottl	map = sc->tx_mbuf_map[chain_prod];
7417157642Sps
7418157642Sps	/* Map the mbuf into our DMA address space. */
7419163393Sscottl	error = bus_dmamap_load_mbuf_sg(sc->tx_mbuf_tag, map, m0,
7420163393Sscottl	    segs, &nsegs, BUS_DMA_NOWAIT);
7421157642Sps
7422170392Sdavidch	/* Check if the DMA mapping was successful */
7423163393Sscottl	if (error == EFBIG) {
7424207411Sdavidch		sc->mbuf_frag_count++;
7425179771Sdavidch
7426171667Sdavidch		/* Try to defrag the mbuf. */
7427243857Sglebius		m0 = m_collapse(*m_head, M_NOWAIT, BCE_MAX_SEGMENTS);
7428171667Sdavidch		if (m0 == NULL) {
7429169632Sdavidch			/* Defrag was unsuccessful */
7430163499Sscottl			m_freem(*m_head);
7431163499Sscottl			*m_head = NULL;
7432189325Sdavidch			sc->mbuf_alloc_failed_count++;
7433179771Sdavidch			rc = ENOBUFS;
7434179771Sdavidch			goto bce_tx_encap_exit;
7435163499Sscottl		}
7436159411Sdavidch
7437170392Sdavidch		/* Defrag was successful, try mapping again */
7438163499Sscottl		*m_head = m0;
7439207411Sdavidch		error = bus_dmamap_load_mbuf_sg(sc->tx_mbuf_tag,
7440207411Sdavidch		    map, m0, segs, &nsegs, BUS_DMA_NOWAIT);
7441163499Sscottl
7442163393Sscottl		/* Still getting an error after a defrag. */
7443163499Sscottl		if (error == ENOMEM) {
7444171667Sdavidch			/* Insufficient DMA buffers available. */
7445189325Sdavidch			sc->dma_map_addr_tx_failed_count++;
7446179771Sdavidch			rc = error;
7447179771Sdavidch			goto bce_tx_encap_exit;
7448163499Sscottl		} else if (error != 0) {
7449206268Sdavidch			/* Release it and return an error. */
7450206268Sdavidch			BCE_PRINTF("%s(%d): Unknown error mapping mbuf into "
7451206268Sdavidch			    "TX chain!\n", __FILE__, __LINE__);
7452163499Sscottl			m_freem(m0);
7453163499Sscottl			*m_head = NULL;
7454189325Sdavidch			sc->dma_map_addr_tx_failed_count++;
7455179771Sdavidch			rc = ENOBUFS;
7456179771Sdavidch			goto bce_tx_encap_exit;
7457163393Sscottl		}
7458163499Sscottl	} else if (error == ENOMEM) {
7459171667Sdavidch		/* Insufficient DMA buffers available. */
7460189325Sdavidch		sc->dma_map_addr_tx_failed_count++;
7461179771Sdavidch		rc = error;
7462179771Sdavidch		goto bce_tx_encap_exit;
7463163499Sscottl	} else if (error != 0) {
7464163499Sscottl		m_freem(m0);
7465163499Sscottl		*m_head = NULL;
7466189325Sdavidch		sc->dma_map_addr_tx_failed_count++;
7467179771Sdavidch		rc = error;
7468179771Sdavidch		goto bce_tx_encap_exit;
7469163499Sscottl	}
7470170392Sdavidch
7471169632Sdavidch	/* Make sure there's room in the chain */
7472169632Sdavidch	if (nsegs > (sc->max_tx_bd - sc->used_tx_bd)) {
7473163558Sscottl		bus_dmamap_unload(sc->tx_mbuf_tag, map);
7474179771Sdavidch		rc = ENOBUFS;
7475179771Sdavidch		goto bce_tx_encap_exit;
7476163558Sscottl	}
7477163393Sscottl
7478163393Sscottl	/* prod points to an empty tx_bd at this point. */
7479163393Sscottl	prod_bseq  = sc->tx_prod_bseq;
7480163393Sscottl
7481163393Sscottl#ifdef BCE_DEBUG
7482163393Sscottl	debug_prod = chain_prod;
7483163393Sscottl#endif
7484163393Sscottl
7485163393Sscottl	DBPRINT(sc, BCE_INFO_SEND,
7486206268Sdavidch	    "%s(start): prod = 0x%04X, chain_prod = 0x%04X, "
7487206268Sdavidch	    "prod_bseq = 0x%08X\n",
7488206268Sdavidch	    __FUNCTION__, prod, chain_prod, prod_bseq);
7489163393Sscottl
7490163393Sscottl	/*
7491163393Sscottl	 * Cycle through each mbuf segment that makes up
7492163393Sscottl	 * the outgoing frame, gathering the mapping info
7493176448Sdavidch	 * for that segment and creating a tx_bd for
7494163393Sscottl	 * the mbuf.
7495163393Sscottl	 */
7496163393Sscottl	for (i = 0; i < nsegs ; i++) {
7497163393Sscottl
7498163393Sscottl		chain_prod = TX_CHAIN_IDX(prod);
7499206268Sdavidch		txbd= &sc->tx_bd_chain[TX_PAGE(chain_prod)]
7500206268Sdavidch		    [TX_IDX(chain_prod)];
7501163393Sscottl
7502207411Sdavidch		txbd->tx_bd_haddr_lo =
7503207411Sdavidch		    htole32(BCE_ADDR_LO(segs[i].ds_addr));
7504207411Sdavidch		txbd->tx_bd_haddr_hi =
7505207411Sdavidch		    htole32(BCE_ADDR_HI(segs[i].ds_addr));
7506207411Sdavidch		txbd->tx_bd_mss_nbytes = htole32(mss << 16) |
7507206268Sdavidch		    htole16(segs[i].ds_len);
7508164329Sscottl		txbd->tx_bd_vlan_tag = htole16(vlan_tag);
7509164329Sscottl		txbd->tx_bd_flags = htole16(flags);
7510163393Sscottl		prod_bseq += segs[i].ds_len;
7511163393Sscottl		if (i == 0)
7512170392Sdavidch			txbd->tx_bd_flags |= htole16(TX_BD_FLAGS_START);
7513163393Sscottl		prod = NEXT_TX_BD(prod);
7514157642Sps	}
7515157642Sps
7516163393Sscottl	/* Set the END flag on the last TX buffer descriptor. */
7517164329Sscottl	txbd->tx_bd_flags |= htole16(TX_BD_FLAGS_END);
7518163393Sscottl
7519207411Sdavidch	DBRUNMSG(BCE_EXTREME_SEND,
7520207411Sdavidch	    bce_dump_tx_chain(sc, debug_prod, nsegs));
7521163393Sscottl
7522157642Sps	/*
7523164327Sjdp	 * Ensure that the mbuf pointer for this transmission
7524157642Sps	 * is placed at the array index of the last
7525157642Sps	 * descriptor in this chain.  This is done
7526179771Sdavidch	 * because a single map is used for all
7527157642Sps	 * segments of the mbuf and we don't want to
7528164327Sjdp	 * unload the map before all of the segments
7529157642Sps	 * have been freed.
7530157642Sps	 */
7531163393Sscottl	sc->tx_mbuf_ptr[chain_prod] = m0;
7532163393Sscottl	sc->used_tx_bd += nsegs;
7533157642Sps
7534170392Sdavidch	/* Update some debug statistic counters */
7535179771Sdavidch	DBRUNIF((sc->used_tx_bd > sc->tx_hi_watermark),
7536206268Sdavidch	    sc->tx_hi_watermark = sc->used_tx_bd);
7537169632Sdavidch	DBRUNIF((sc->used_tx_bd == sc->max_tx_bd), sc->tx_full_count++);
7538176448Sdavidch	DBRUNIF(sc->debug_tx_mbuf_alloc++);
7539157642Sps
7540179771Sdavidch	DBRUNMSG(BCE_EXTREME_SEND, bce_dump_tx_mbuf_chain(sc, chain_prod, 1));
7541157642Sps
7542164327Sjdp	/* prod points to the next free tx_bd at this point. */
7543163393Sscottl	sc->tx_prod = prod;
7544163393Sscottl	sc->tx_prod_bseq = prod_bseq;
7545157642Sps
7546207411Sdavidch	/* Tell the chip about the waiting TX frames. */
7547207411Sdavidch	REG_WR16(sc, MB_GET_CID_ADDR(TX_CID) +
7548207411Sdavidch	    BCE_L2MQ_TX_HOST_BIDX, sc->tx_prod);
7549207411Sdavidch	REG_WR(sc, MB_GET_CID_ADDR(TX_CID) +
7550207411Sdavidch	    BCE_L2MQ_TX_HOST_BSEQ, sc->tx_prod_bseq);
7551179771Sdavidch
7552179771Sdavidchbce_tx_encap_exit:
7553179771Sdavidch	DBEXIT(BCE_VERBOSE_SEND);
7554157642Sps	return(rc);
7555157642Sps}
7556157642Sps
7557157642Sps
7558157642Sps/****************************************************************************/
7559157642Sps/* Main transmit routine when called from another routine with a lock.      */
7560157642Sps/*                                                                          */
7561157642Sps/* Returns:                                                                 */
7562157642Sps/*   Nothing.                                                               */
7563157642Sps/****************************************************************************/
7564157642Spsstatic void
7565157642Spsbce_start_locked(struct ifnet *ifp)
7566157642Sps{
7567157642Sps	struct bce_softc *sc = ifp->if_softc;
7568157642Sps	struct mbuf *m_head = NULL;
7569157642Sps	int count = 0;
7570157642Sps	u16 tx_prod, tx_chain_prod;
7571157642Sps
7572179771Sdavidch	DBENTER(BCE_VERBOSE_SEND | BCE_VERBOSE_CTX);
7573179771Sdavidch
7574179771Sdavidch	BCE_LOCK_ASSERT(sc);
7575179771Sdavidch
7576157642Sps	/* prod points to the next free tx_bd. */
7577157642Sps	tx_prod = sc->tx_prod;
7578157642Sps	tx_chain_prod = TX_CHAIN_IDX(tx_prod);
7579157642Sps
7580157642Sps	DBPRINT(sc, BCE_INFO_SEND,
7581206268Sdavidch	    "%s(enter): tx_prod = 0x%04X, tx_chain_prod = 0x%04X, "
7582206268Sdavidch	    "tx_prod_bseq = 0x%08X\n",
7583206268Sdavidch	    __FUNCTION__, tx_prod, tx_chain_prod, sc->tx_prod_bseq);
7584157642Sps
7585178132Sdavidch	/* If there's no link or the transmit queue is empty then just exit. */
7586206268Sdavidch	if (sc->bce_link_up == FALSE) {
7587179771Sdavidch		DBPRINT(sc, BCE_INFO_SEND, "%s(): No link.\n",
7588206268Sdavidch		    __FUNCTION__);
7589178132Sdavidch		goto bce_start_locked_exit;
7590178132Sdavidch	}
7591178132Sdavidch
7592178132Sdavidch	if (IFQ_DRV_IS_EMPTY(&ifp->if_snd)) {
7593179771Sdavidch		DBPRINT(sc, BCE_INFO_SEND, "%s(): Transmit queue empty.\n",
7594206268Sdavidch		    __FUNCTION__);
7595178132Sdavidch		goto bce_start_locked_exit;
7596178132Sdavidch	}
7597178132Sdavidch
7598164327Sjdp	/*
7599169632Sdavidch	 * Keep adding entries while there is space in the ring.
7600164327Sjdp	 */
7601169632Sdavidch	while (sc->used_tx_bd < sc->max_tx_bd) {
7602157642Sps
7603157642Sps		/* Check for any frames to send. */
7604157642Sps		IFQ_DRV_DEQUEUE(&ifp->if_snd, m_head);
7605179771Sdavidch
7606179771Sdavidch		/* Stop when the transmit queue is empty. */
7607157642Sps		if (m_head == NULL)
7608157642Sps			break;
7609157642Sps
7610157642Sps		/*
7611157642Sps		 * Pack the data into the transmit ring. If we
7612157642Sps		 * don't have room, place the mbuf back at the
7613157642Sps		 * head of the queue and set the OACTIVE flag
7614157642Sps		 * to wait for the NIC to drain the chain.
7615157642Sps		 */
7616163393Sscottl		if (bce_tx_encap(sc, &m_head)) {
7617171667Sdavidch			if (m_head != NULL)
7618171667Sdavidch				IFQ_DRV_PREPEND(&ifp->if_snd, m_head);
7619157642Sps			ifp->if_drv_flags |= IFF_DRV_OACTIVE;
7620157642Sps			DBPRINT(sc, BCE_INFO_SEND,
7621206268Sdavidch			    "TX chain is closed for business! Total "
7622206268Sdavidch			    "tx_bd used = %d\n", sc->used_tx_bd);
7623157642Sps			break;
7624157642Sps		}
7625157642Sps
7626157642Sps		count++;
7627157642Sps
7628157642Sps		/* Send a copy of the frame to any BPF listeners. */
7629167190Scsjp		ETHER_BPF_MTAP(ifp, m_head);
7630157642Sps	}
7631157642Sps
7632179771Sdavidch	/* Exit if no packets were dequeued. */
7633157642Sps	if (count == 0) {
7634206268Sdavidch		DBPRINT(sc, BCE_VERBOSE_SEND, "%s(): No packets were "
7635206268Sdavidch		    "dequeued\n", __FUNCTION__);
7636157642Sps		goto bce_start_locked_exit;
7637157642Sps	}
7638157642Sps
7639206268Sdavidch	DBPRINT(sc, BCE_VERBOSE_SEND, "%s(): Inserted %d frames into "
7640206268Sdavidch	    "send queue.\n", __FUNCTION__, count);
7641157642Sps
7642157642Sps	/* Set the tx timeout. */
7643165933Sdelphij	sc->watchdog_timer = BCE_TX_TIMEOUT;
7644157642Sps
7645182293Sdavidch	DBRUNMSG(BCE_VERBOSE_SEND, bce_dump_ctx(sc, TX_CID));
7646179771Sdavidch	DBRUNMSG(BCE_VERBOSE_SEND, bce_dump_mq_regs(sc));
7647179771Sdavidch
7648157642Spsbce_start_locked_exit:
7649179771Sdavidch	DBEXIT(BCE_VERBOSE_SEND | BCE_VERBOSE_CTX);
7650157642Sps}
7651157642Sps
7652157642Sps
7653157642Sps/****************************************************************************/
7654157642Sps/* Main transmit routine when called from another routine without a lock.   */
7655157642Sps/*                                                                          */
7656157642Sps/* Returns:                                                                 */
7657157642Sps/*   Nothing.                                                               */
7658157642Sps/****************************************************************************/
7659157642Spsstatic void
7660157642Spsbce_start(struct ifnet *ifp)
7661157642Sps{
7662157642Sps	struct bce_softc *sc = ifp->if_softc;
7663157642Sps
7664179771Sdavidch	DBENTER(BCE_VERBOSE_SEND);
7665179771Sdavidch
7666157642Sps	BCE_LOCK(sc);
7667157642Sps	bce_start_locked(ifp);
7668157642Sps	BCE_UNLOCK(sc);
7669179771Sdavidch
7670179771Sdavidch	DBEXIT(BCE_VERBOSE_SEND);
7671157642Sps}
7672157642Sps
7673157642Sps
7674157642Sps/****************************************************************************/
7675157642Sps/* Handles any IOCTL calls from the operating system.                       */
7676157642Sps/*                                                                          */
7677157642Sps/* Returns:                                                                 */
7678157642Sps/*   0 for success, positive value for failure.                             */
7679157642Sps/****************************************************************************/
7680157642Spsstatic int
7681157642Spsbce_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
7682157642Sps{
7683157642Sps	struct bce_softc *sc = ifp->if_softc;
7684157642Sps	struct ifreq *ifr = (struct ifreq *) data;
7685157642Sps	struct mii_data *mii;
7686218423Sdavidch	int mask, error = 0;
7687157642Sps
7688179771Sdavidch	DBENTER(BCE_VERBOSE_MISC);
7689179771Sdavidch
7690157642Sps	switch(command) {
7691157642Sps
7692206268Sdavidch	/* Set the interface MTU. */
7693206268Sdavidch	case SIOCSIFMTU:
7694206268Sdavidch		/* Check that the MTU setting is supported. */
7695206268Sdavidch		if ((ifr->ifr_mtu < BCE_MIN_MTU) ||
7696206268Sdavidch			(ifr->ifr_mtu > BCE_MAX_JUMBO_MTU)) {
7697206268Sdavidch			error = EINVAL;
7698206268Sdavidch			break;
7699206268Sdavidch		}
7700157642Sps
7701206268Sdavidch		DBPRINT(sc, BCE_INFO_MISC,
7702206268Sdavidch		    "SIOCSIFMTU: Changing MTU from %d to %d\n",
7703206268Sdavidch		    (int) ifp->if_mtu, (int) ifr->ifr_mtu);
7704157642Sps
7705206268Sdavidch		BCE_LOCK(sc);
7706206268Sdavidch		ifp->if_mtu = ifr->ifr_mtu;
7707235119Syongari		if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
7708235119Syongari			ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
7709218423Sdavidch			bce_init_locked(sc);
7710206268Sdavidch		}
7711206268Sdavidch		BCE_UNLOCK(sc);
7712206268Sdavidch		break;
7713157642Sps
7714206268Sdavidch	/* Set interface flags. */
7715206268Sdavidch	case SIOCSIFFLAGS:
7716206268Sdavidch		DBPRINT(sc, BCE_VERBOSE_SPECIAL, "Received SIOCSIFFLAGS\n");
7717157642Sps
7718206268Sdavidch		BCE_LOCK(sc);
7719157642Sps
7720206268Sdavidch		/* Check if the interface is up. */
7721206268Sdavidch		if (ifp->if_flags & IFF_UP) {
7722206268Sdavidch			if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
7723206268Sdavidch				/* Change promiscuous/multicast flags as necessary. */
7724206268Sdavidch				bce_set_rx_mode(sc);
7725157642Sps			} else {
7726206268Sdavidch				/* Start the HW */
7727206268Sdavidch				bce_init_locked(sc);
7728206268Sdavidch			}
7729206268Sdavidch		} else {
7730206268Sdavidch			/* The interface is down, check if driver is running. */
7731206268Sdavidch			if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
7732206268Sdavidch				bce_stop(sc);
7733170810Sdavidch
7734206268Sdavidch				/* If MFW is running, restart the controller a bit. */
7735206268Sdavidch				if (sc->bce_flags & BCE_MFW_ENABLE_FLAG) {
7736206268Sdavidch					bce_reset(sc, BCE_DRV_MSG_CODE_RESET);
7737206268Sdavidch					bce_chipinit(sc);
7738206268Sdavidch					bce_mgmt_init_locked(sc);
7739157642Sps				}
7740157642Sps			}
7741206268Sdavidch		}
7742157642Sps
7743206268Sdavidch		BCE_UNLOCK(sc);
7744206268Sdavidch		break;
7745157642Sps
7746206268Sdavidch	/* Add/Delete multicast address */
7747206268Sdavidch	case SIOCADDMULTI:
7748206268Sdavidch	case SIOCDELMULTI:
7749207411Sdavidch		DBPRINT(sc, BCE_VERBOSE_MISC,
7750206268Sdavidch		    "Received SIOCADDMULTI/SIOCDELMULTI\n");
7751157642Sps
7752206268Sdavidch		BCE_LOCK(sc);
7753206268Sdavidch		if (ifp->if_drv_flags & IFF_DRV_RUNNING)
7754206268Sdavidch			bce_set_rx_mode(sc);
7755206268Sdavidch		BCE_UNLOCK(sc);
7756157642Sps
7757206268Sdavidch		break;
7758157642Sps
7759206268Sdavidch	/* Set/Get Interface media */
7760206268Sdavidch	case SIOCSIFMEDIA:
7761206268Sdavidch	case SIOCGIFMEDIA:
7762207411Sdavidch		DBPRINT(sc, BCE_VERBOSE_MISC,
7763206268Sdavidch		    "Received SIOCSIFMEDIA/SIOCGIFMEDIA\n");
7764235151Syongari		if ((sc->bce_phy_flags & BCE_PHY_REMOTE_CAP_FLAG) != 0)
7765235151Syongari			error = ifmedia_ioctl(ifp, ifr, &sc->bce_ifmedia,
7766235151Syongari			    command);
7767235151Syongari		else {
7768235151Syongari			mii = device_get_softc(sc->bce_miibus);
7769235151Syongari			error = ifmedia_ioctl(ifp, ifr, &mii->mii_media,
7770235151Syongari			    command);
7771235151Syongari		}
7772206268Sdavidch		break;
7773157642Sps
7774206268Sdavidch	/* Set interface capability */
7775206268Sdavidch	case SIOCSIFCAP:
7776206268Sdavidch		mask = ifr->ifr_reqcap ^ ifp->if_capenable;
7777207411Sdavidch		DBPRINT(sc, BCE_INFO_MISC,
7778206268Sdavidch		    "Received SIOCSIFCAP = 0x%08X\n", (u32) mask);
7779157642Sps
7780206268Sdavidch		/* Toggle the TX checksum capabilities enable flag. */
7781206268Sdavidch		if (mask & IFCAP_TXCSUM &&
7782206268Sdavidch		    ifp->if_capabilities & IFCAP_TXCSUM) {
7783206268Sdavidch			ifp->if_capenable ^= IFCAP_TXCSUM;
7784206268Sdavidch			if (IFCAP_TXCSUM & ifp->if_capenable)
7785206268Sdavidch				ifp->if_hwassist |= BCE_IF_HWASSIST;
7786206268Sdavidch			else
7787206268Sdavidch				ifp->if_hwassist &= ~BCE_IF_HWASSIST;
7788206268Sdavidch		}
7789157642Sps
7790206268Sdavidch		/* Toggle the RX checksum capabilities enable flag. */
7791206268Sdavidch		if (mask & IFCAP_RXCSUM &&
7792206268Sdavidch		    ifp->if_capabilities & IFCAP_RXCSUM)
7793206268Sdavidch			ifp->if_capenable ^= IFCAP_RXCSUM;
7794157642Sps
7795206268Sdavidch		/* Toggle the TSO capabilities enable flag. */
7796206268Sdavidch		if (bce_tso_enable && (mask & IFCAP_TSO4) &&
7797206268Sdavidch		    ifp->if_capabilities & IFCAP_TSO4) {
7798206268Sdavidch			ifp->if_capenable ^= IFCAP_TSO4;
7799206268Sdavidch			if (IFCAP_TSO4 & ifp->if_capenable)
7800206268Sdavidch				ifp->if_hwassist |= CSUM_TSO;
7801206268Sdavidch			else
7802206268Sdavidch				ifp->if_hwassist &= ~CSUM_TSO;
7803206268Sdavidch		}
7804157642Sps
7805206268Sdavidch		if (mask & IFCAP_VLAN_HWCSUM &&
7806206268Sdavidch		    ifp->if_capabilities & IFCAP_VLAN_HWCSUM)
7807206268Sdavidch			ifp->if_capenable ^= IFCAP_VLAN_HWCSUM;
7808169632Sdavidch
7809206268Sdavidch		if ((mask & IFCAP_VLAN_HWTSO) != 0 &&
7810206268Sdavidch		    (ifp->if_capabilities & IFCAP_VLAN_HWTSO) != 0)
7811206268Sdavidch			ifp->if_capenable ^= IFCAP_VLAN_HWTSO;
7812206268Sdavidch		/*
7813206268Sdavidch		 * Don't actually disable VLAN tag stripping as
7814206268Sdavidch		 * management firmware (ASF/IPMI/UMP) requires the
7815206268Sdavidch		 * feature. If VLAN tag stripping is disabled driver
7816206268Sdavidch		 * will manually reconstruct the VLAN frame by
7817206268Sdavidch		 * appending stripped VLAN tag.
7818206268Sdavidch		 */
7819206268Sdavidch		if ((mask & IFCAP_VLAN_HWTAGGING) != 0 &&
7820206268Sdavidch		    (ifp->if_capabilities & IFCAP_VLAN_HWTAGGING)) {
7821206268Sdavidch			ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING;
7822206268Sdavidch			if ((ifp->if_capenable & IFCAP_VLAN_HWTAGGING)
7823206268Sdavidch			    == 0)
7824206268Sdavidch				ifp->if_capenable &= ~IFCAP_VLAN_HWTSO;
7825206268Sdavidch		}
7826206268Sdavidch		VLAN_CAPABILITIES(ifp);
7827206268Sdavidch		break;
7828206268Sdavidch	default:
7829206268Sdavidch		/* We don't know how to handle the IOCTL, pass it on. */
7830206268Sdavidch		error = ether_ioctl(ifp, command, data);
7831206268Sdavidch		break;
7832157642Sps	}
7833157642Sps
7834179771Sdavidch	DBEXIT(BCE_VERBOSE_MISC);
7835157642Sps	return(error);
7836157642Sps}
7837157642Sps
7838157642Sps
7839157642Sps/****************************************************************************/
7840157642Sps/* Transmit timeout handler.                                                */
7841157642Sps/*                                                                          */
7842157642Sps/* Returns:                                                                 */
7843157642Sps/*   Nothing.                                                               */
7844157642Sps/****************************************************************************/
7845157642Spsstatic void
7846165933Sdelphijbce_watchdog(struct bce_softc *sc)
7847157642Sps{
7848252402Syongari	uint32_t status;
7849252402Syongari
7850179771Sdavidch	DBENTER(BCE_EXTREME_SEND);
7851157642Sps
7852165933Sdelphij	BCE_LOCK_ASSERT(sc);
7853165933Sdelphij
7854252402Syongari	status = 0;
7855179771Sdavidch	/* If the watchdog timer hasn't expired then just exit. */
7856165933Sdelphij	if (sc->watchdog_timer == 0 || --sc->watchdog_timer)
7857179771Sdavidch		goto bce_watchdog_exit;
7858165933Sdelphij
7859252402Syongari	status = REG_RD(sc, BCE_EMAC_RX_STATUS);
7860179771Sdavidch	/* If pause frames are active then don't reset the hardware. */
7861252402Syongari	if ((sc->bce_flags & BCE_USING_RX_FLOW_CONTROL) != 0) {
7862252402Syongari		if ((status & BCE_EMAC_RX_STATUS_FFED) != 0) {
7863252402Syongari			/*
7864252402Syongari			 * If link partner has us in XOFF state then wait for
7865252402Syongari			 * the condition to clear.
7866252402Syongari			 */
7867252402Syongari			sc->watchdog_timer = BCE_TX_TIMEOUT;
7868252402Syongari			goto bce_watchdog_exit;
7869252402Syongari		} else if ((status & BCE_EMAC_RX_STATUS_FF_RECEIVED) != 0 &&
7870252402Syongari			(status & BCE_EMAC_RX_STATUS_N_RECEIVED) != 0) {
7871252402Syongari			/*
7872252402Syongari			 * If we're not currently XOFF'ed but have recently
7873252402Syongari			 * been XOFF'd/XON'd then assume that's delaying TX
7874252402Syongari			 * this time around.
7875252402Syongari			 */
7876252402Syongari			sc->watchdog_timer = BCE_TX_TIMEOUT;
7877252402Syongari			goto bce_watchdog_exit;
7878252402Syongari		}
7879252402Syongari		/*
7880252402Syongari		 * Any other condition is unexpected and the controller
7881252402Syongari		 * should be reset.
7882252402Syongari		 */
7883252402Syongari	}
7884165933Sdelphij
7885179771Sdavidch	BCE_PRINTF("%s(%d): Watchdog timeout occurred, resetting!\n",
7886207411Sdavidch	    __FILE__, __LINE__);
7887157642Sps
7888179771Sdavidch	DBRUNMSG(BCE_INFO,
7889206268Sdavidch	    bce_dump_driver_state(sc);
7890206268Sdavidch	    bce_dump_status_block(sc);
7891206268Sdavidch	    bce_dump_stats_block(sc);
7892206268Sdavidch	    bce_dump_ftqs(sc);
7893206268Sdavidch	    bce_dump_txp_state(sc, 0);
7894206268Sdavidch	    bce_dump_rxp_state(sc, 0);
7895206268Sdavidch	    bce_dump_tpat_state(sc, 0);
7896206268Sdavidch	    bce_dump_cp_state(sc, 0);
7897206268Sdavidch	    bce_dump_com_state(sc, 0));
7898170810Sdavidch
7899179771Sdavidch	DBRUN(bce_breakpoint(sc));
7900157642Sps
7901165933Sdelphij	sc->bce_ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
7902157642Sps
7903160526Sjhb	bce_init_locked(sc);
7904272096Sglebius	sc->watchdog_timeouts++;
7905157642Sps
7906179771Sdavidchbce_watchdog_exit:
7907252402Syongari	REG_WR(sc, BCE_EMAC_RX_STATUS, status);
7908179771Sdavidch	DBEXIT(BCE_EXTREME_SEND);
7909157642Sps}
7910157642Sps
7911157642Sps
7912157642Sps/*
7913157642Sps * Interrupt handler.
7914157642Sps */
7915157642Sps/****************************************************************************/
7916157642Sps/* Main interrupt entry point.  Verifies that the controller generated the  */
7917157642Sps/* interrupt and then calls a separate routine for handle the various       */
7918157642Sps/* interrupt causes (PHY, TX, RX).                                          */
7919157642Sps/*                                                                          */
7920157642Sps/* Returns:                                                                 */
7921251159Smarius/*   Nothing.                                                               */
7922157642Sps/****************************************************************************/
7923157642Spsstatic void
7924157642Spsbce_intr(void *xsc)
7925157642Sps{
7926157642Sps	struct bce_softc *sc;
7927157642Sps	struct ifnet *ifp;
7928157642Sps	u32 status_attn_bits;
7929178132Sdavidch	u16 hw_rx_cons, hw_tx_cons;
7930157642Sps
7931157642Sps	sc = xsc;
7932157642Sps	ifp = sc->bce_ifp;
7933157642Sps
7934179771Sdavidch	DBENTER(BCE_VERBOSE_SEND | BCE_VERBOSE_RECV | BCE_VERBOSE_INTR);
7935179771Sdavidch	DBRUNMSG(BCE_VERBOSE_INTR, bce_dump_status_block(sc));
7936206268Sdavidch	DBRUNMSG(BCE_VERBOSE_INTR, bce_dump_stats_block(sc));
7937179771Sdavidch
7938157642Sps	BCE_LOCK(sc);
7939157642Sps
7940176448Sdavidch	DBRUN(sc->interrupts_generated++);
7941157642Sps
7942192281Sdelphij	/* Synchnorize before we read from interface's status block */
7943251159Smarius	bus_dmamap_sync(sc->status_tag, sc->status_map, BUS_DMASYNC_POSTREAD);
7944157642Sps
7945157642Sps	/*
7946251159Smarius	 * If the hardware status block index matches the last value read
7947251159Smarius	 * by the driver and we haven't asserted our interrupt then there's
7948251159Smarius	 * nothing to do.  This may only happen in case of INTx due to the
7949251159Smarius	 * interrupt arriving at the CPU before the status block is updated.
7950157642Sps	 */
7951251159Smarius	if ((sc->bce_flags & (BCE_USING_MSI_FLAG | BCE_USING_MSIX_FLAG)) == 0 &&
7952251159Smarius	    sc->status_block->status_idx == sc->last_status_idx &&
7953207411Sdavidch	    (REG_RD(sc, BCE_PCICFG_MISC_STATUS) &
7954206268Sdavidch	     BCE_PCICFG_MISC_STATUS_INTA_VALUE)) {
7955206268Sdavidch		DBPRINT(sc, BCE_VERBOSE_INTR, "%s(): Spurious interrupt.\n",
7956206268Sdavidch		    __FUNCTION__);
7957206268Sdavidch		goto bce_intr_exit;
7958179771Sdavidch	}
7959157642Sps
7960298955Spfg	/* Ack the interrupt and stop others from occurring. */
7961157642Sps	REG_WR(sc, BCE_PCICFG_INT_ACK_CMD,
7962206268Sdavidch	    BCE_PCICFG_INT_ACK_CMD_USE_INT_HC_PARAM |
7963206268Sdavidch	    BCE_PCICFG_INT_ACK_CMD_MASK_INT);
7964157642Sps
7965178132Sdavidch	/* Check if the hardware has finished any work. */
7966178132Sdavidch	hw_rx_cons = bce_get_hw_rx_cons(sc);
7967178132Sdavidch	hw_tx_cons = bce_get_hw_tx_cons(sc);
7968178132Sdavidch
7969157642Sps	/* Keep processing data as long as there is work to do. */
7970157642Sps	for (;;) {
7971157642Sps
7972157642Sps		status_attn_bits = sc->status_block->status_attn_bits;
7973157642Sps
7974206268Sdavidch		DBRUNIF(DB_RANDOMTRUE(unexpected_attention_sim_control),
7975206268Sdavidch		    BCE_PRINTF("Simulating unexpected status attention "
7976206268Sdavidch		    "bit set.");
7977206268Sdavidch		    sc->unexpected_attention_sim_count++;
7978207411Sdavidch		    status_attn_bits = status_attn_bits |
7979206268Sdavidch		    STATUS_ATTN_BITS_PARITY_ERROR);
7980157642Sps
7981157642Sps		/* Was it a link change interrupt? */
7982157642Sps		if ((status_attn_bits & STATUS_ATTN_BITS_LINK_STATE) !=
7983207411Sdavidch		    (sc->status_block->status_attn_bits_ack &
7984206268Sdavidch		     STATUS_ATTN_BITS_LINK_STATE)) {
7985157642Sps			bce_phy_intr(sc);
7986157642Sps
7987206268Sdavidch			/* Clear transient updates during link state change. */
7988207411Sdavidch			REG_WR(sc, BCE_HC_COMMAND, sc->hc_command |
7989206268Sdavidch			    BCE_HC_COMMAND_COAL_NOW_WO_INT);
7990185593Sdelphij			REG_RD(sc, BCE_HC_COMMAND);
7991185593Sdelphij		}
7992179771Sdavidch
7993206268Sdavidch		/* If any other attention is asserted, the chip is toast. */
7994157642Sps		if (((status_attn_bits & ~STATUS_ATTN_BITS_LINK_STATE) !=
7995206268Sdavidch		    (sc->status_block->status_attn_bits_ack &
7996206268Sdavidch		    ~STATUS_ATTN_BITS_LINK_STATE))) {
7997157642Sps
7998206268Sdavidch			sc->unexpected_attention_count++;
7999157642Sps
8000206268Sdavidch			BCE_PRINTF("%s(%d): Fatal attention detected: "
8001207411Sdavidch			    "0x%08X\n",	__FILE__, __LINE__,
8002206268Sdavidch			    sc->status_block->status_attn_bits);
8003157642Sps
8004179771Sdavidch			DBRUNMSG(BCE_FATAL,
8005206268Sdavidch			    if (unexpected_attention_sim_control == 0)
8006206268Sdavidch				bce_breakpoint(sc));
8007157642Sps
8008157642Sps			bce_init_locked(sc);
8009157642Sps			goto bce_intr_exit;
8010157642Sps		}
8011157642Sps
8012157642Sps		/* Check for any completed RX frames. */
8013178132Sdavidch		if (hw_rx_cons != sc->hw_rx_cons)
8014157642Sps			bce_rx_intr(sc);
8015157642Sps
8016157642Sps		/* Check for any completed TX frames. */
8017178132Sdavidch		if (hw_tx_cons != sc->hw_tx_cons)
8018157642Sps			bce_tx_intr(sc);
8019157642Sps
8020206268Sdavidch		/* Save status block index value for the next interrupt. */
8021157642Sps		sc->last_status_idx = sc->status_block->status_idx;
8022157642Sps
8023206268Sdavidch 		/*
8024206268Sdavidch 		 * Prevent speculative reads from getting
8025206268Sdavidch 		 * ahead of the status block.
8026206268Sdavidch		 */
8027179771Sdavidch		bus_space_barrier(sc->bce_btag, sc->bce_bhandle, 0, 0,
8028206268Sdavidch		    BUS_SPACE_BARRIER_READ);
8029157642Sps
8030206268Sdavidch 		/*
8031206268Sdavidch 		 * If there's no work left then exit the
8032206268Sdavidch 		 * interrupt service routine.
8033206268Sdavidch		 */
8034178132Sdavidch		hw_rx_cons = bce_get_hw_rx_cons(sc);
8035178132Sdavidch		hw_tx_cons = bce_get_hw_tx_cons(sc);
8036178132Sdavidch
8037207411Sdavidch		if ((hw_rx_cons == sc->hw_rx_cons) &&
8038206268Sdavidch		    (hw_tx_cons == sc->hw_tx_cons))
8039157642Sps			break;
8040157642Sps	}
8041157642Sps
8042251159Smarius	bus_dmamap_sync(sc->status_tag,	sc->status_map, BUS_DMASYNC_PREREAD);
8043157642Sps
8044157642Sps	/* Re-enable interrupts. */
8045179771Sdavidch	bce_enable_intr(sc, 0);
8046157642Sps
8047157642Sps	/* Handle any frames that arrived while handling the interrupt. */
8048207411Sdavidch	if (ifp->if_drv_flags & IFF_DRV_RUNNING &&
8049206268Sdavidch	    !IFQ_DRV_IS_EMPTY(&ifp->if_snd))
8050157642Sps		bce_start_locked(ifp);
8051157642Sps
8052157642Spsbce_intr_exit:
8053157642Sps	BCE_UNLOCK(sc);
8054179771Sdavidch
8055179771Sdavidch	DBEXIT(BCE_VERBOSE_SEND | BCE_VERBOSE_RECV | BCE_VERBOSE_INTR);
8056157642Sps}
8057157642Sps
8058157642Sps
8059157642Sps/****************************************************************************/
8060157642Sps/* Programs the various packet receive modes (broadcast and multicast).     */
8061157642Sps/*                                                                          */
8062157642Sps/* Returns:                                                                 */
8063157642Sps/*   Nothing.                                                               */
8064157642Sps/****************************************************************************/
8065157642Spsstatic void
8066157642Spsbce_set_rx_mode(struct bce_softc *sc)
8067157642Sps{
8068157642Sps	struct ifnet *ifp;
8069157642Sps	struct ifmultiaddr *ifma;
8070166153Sscottl	u32 hashes[NUM_MC_HASH_REGISTERS] = { 0, 0, 0, 0, 0, 0, 0, 0 };
8071157642Sps	u32 rx_mode, sort_mode;
8072157642Sps	int h, i;
8073157642Sps
8074179771Sdavidch	DBENTER(BCE_VERBOSE_MISC);
8075179771Sdavidch
8076157642Sps	BCE_LOCK_ASSERT(sc);
8077157642Sps
8078157642Sps	ifp = sc->bce_ifp;
8079157642Sps
8080157642Sps	/* Initialize receive mode default settings. */
8081157642Sps	rx_mode   = sc->rx_mode & ~(BCE_EMAC_RX_MODE_PROMISCUOUS |
8082206268Sdavidch	    BCE_EMAC_RX_MODE_KEEP_VLAN_TAG);
8083157642Sps	sort_mode = 1 | BCE_RPM_SORT_USER0_BC_EN;
8084157642Sps
8085157642Sps	/*
8086157642Sps	 * ASF/IPMI/UMP firmware requires that VLAN tag stripping
8087157642Sps	 * be enbled.
8088157642Sps	 */
8089157642Sps	if (!(BCE_IF_CAPABILITIES & IFCAP_VLAN_HWTAGGING) &&
8090206268Sdavidch	    (!(sc->bce_flags & BCE_MFW_ENABLE_FLAG)))
8091157642Sps		rx_mode |= BCE_EMAC_RX_MODE_KEEP_VLAN_TAG;
8092157642Sps
8093157642Sps	/*
8094157642Sps	 * Check for promiscuous, all multicast, or selected
8095157642Sps	 * multicast address filtering.
8096157642Sps	 */
8097157642Sps	if (ifp->if_flags & IFF_PROMISC) {
8098170810Sdavidch		DBPRINT(sc, BCE_INFO_MISC, "Enabling promiscuous mode.\n");
8099157642Sps
8100157642Sps		/* Enable promiscuous mode. */
8101157642Sps		rx_mode |= BCE_EMAC_RX_MODE_PROMISCUOUS;
8102157642Sps		sort_mode |= BCE_RPM_SORT_USER0_PROM_EN;
8103157642Sps	} else if (ifp->if_flags & IFF_ALLMULTI) {
8104170810Sdavidch		DBPRINT(sc, BCE_INFO_MISC, "Enabling all multicast mode.\n");
8105157642Sps
8106157642Sps		/* Enable all multicast addresses. */
8107157642Sps		for (i = 0; i < NUM_MC_HASH_REGISTERS; i++) {
8108251146Smarius			REG_WR(sc, BCE_EMAC_MULTICAST_HASH0 + (i * 4),
8109251146Smarius			    0xffffffff);
8110251146Smarius		}
8111157642Sps		sort_mode |= BCE_RPM_SORT_USER0_MC_EN;
8112157642Sps	} else {
8113157642Sps		/* Accept one or more multicast(s). */
8114170810Sdavidch		DBPRINT(sc, BCE_INFO_MISC, "Enabling selective multicast mode.\n");
8115157642Sps
8116195049Srwatson		if_maddr_rlock(ifp);
8117157642Sps		TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
8118157642Sps			if (ifma->ifma_addr->sa_family != AF_LINK)
8119157642Sps				continue;
8120157642Sps			h = ether_crc32_le(LLADDR((struct sockaddr_dl *)
8121166153Sscottl			    ifma->ifma_addr), ETHER_ADDR_LEN) & 0xFF;
8122166153Sscottl			    hashes[(h & 0xE0) >> 5] |= 1 << (h & 0x1F);
8123157642Sps		}
8124195049Srwatson		if_maddr_runlock(ifp);
8125157642Sps
8126166153Sscottl		for (i = 0; i < NUM_MC_HASH_REGISTERS; i++)
8127157642Sps			REG_WR(sc, BCE_EMAC_MULTICAST_HASH0 + (i * 4), hashes[i]);
8128157642Sps
8129157642Sps		sort_mode |= BCE_RPM_SORT_USER0_MC_HSH_EN;
8130157642Sps	}
8131157642Sps
8132157642Sps	/* Only make changes if the recive mode has actually changed. */
8133157642Sps	if (rx_mode != sc->rx_mode) {
8134206268Sdavidch		DBPRINT(sc, BCE_VERBOSE_MISC, "Enabling new receive mode: "
8135206268Sdavidch		    "0x%08X\n", rx_mode);
8136157642Sps
8137157642Sps		sc->rx_mode = rx_mode;
8138157642Sps		REG_WR(sc, BCE_EMAC_RX_MODE, rx_mode);
8139157642Sps	}
8140157642Sps
8141157642Sps	/* Disable and clear the exisitng sort before enabling a new sort. */
8142157642Sps	REG_WR(sc, BCE_RPM_SORT_USER0, 0x0);
8143157642Sps	REG_WR(sc, BCE_RPM_SORT_USER0, sort_mode);
8144157642Sps	REG_WR(sc, BCE_RPM_SORT_USER0, sort_mode | BCE_RPM_SORT_USER0_ENA);
8145179771Sdavidch
8146179771Sdavidch	DBEXIT(BCE_VERBOSE_MISC);
8147157642Sps}
8148157642Sps
8149157642Sps
8150157642Sps/****************************************************************************/
8151157642Sps/* Called periodically to updates statistics from the controllers           */
8152157642Sps/* statistics block.                                                        */
8153157642Sps/*                                                                          */
8154157642Sps/* Returns:                                                                 */
8155157642Sps/*   Nothing.                                                               */
8156157642Sps/****************************************************************************/
8157157642Spsstatic void
8158157642Spsbce_stats_update(struct bce_softc *sc)
8159157642Sps{
8160157642Sps	struct statistics_block *stats;
8161157642Sps
8162179771Sdavidch	DBENTER(BCE_EXTREME_MISC);
8163157642Sps
8164251159Smarius	bus_dmamap_sync(sc->stats_tag, sc->stats_map, BUS_DMASYNC_POSTREAD);
8165251159Smarius
8166157642Sps	stats = (struct statistics_block *) sc->stats_block;
8167157642Sps
8168179771Sdavidch	/*
8169157642Sps	 * Update the sysctl statistics from the
8170157642Sps	 * hardware statistics.
8171157642Sps	 */
8172179771Sdavidch	sc->stat_IfHCInOctets =
8173206268Sdavidch	    ((u64) stats->stat_IfHCInOctets_hi << 32) +
8174206268Sdavidch	     (u64) stats->stat_IfHCInOctets_lo;
8175157642Sps
8176157642Sps	sc->stat_IfHCInBadOctets =
8177206268Sdavidch	    ((u64) stats->stat_IfHCInBadOctets_hi << 32) +
8178206268Sdavidch	     (u64) stats->stat_IfHCInBadOctets_lo;
8179157642Sps
8180157642Sps	sc->stat_IfHCOutOctets =
8181206268Sdavidch	    ((u64) stats->stat_IfHCOutOctets_hi << 32) +
8182206268Sdavidch	     (u64) stats->stat_IfHCOutOctets_lo;
8183157642Sps
8184157642Sps	sc->stat_IfHCOutBadOctets =
8185206268Sdavidch	    ((u64) stats->stat_IfHCOutBadOctets_hi << 32) +
8186206268Sdavidch	     (u64) stats->stat_IfHCOutBadOctets_lo;
8187157642Sps
8188157642Sps	sc->stat_IfHCInUcastPkts =
8189206268Sdavidch	    ((u64) stats->stat_IfHCInUcastPkts_hi << 32) +
8190206268Sdavidch	     (u64) stats->stat_IfHCInUcastPkts_lo;
8191157642Sps
8192157642Sps	sc->stat_IfHCInMulticastPkts =
8193206268Sdavidch	    ((u64) stats->stat_IfHCInMulticastPkts_hi << 32) +
8194206268Sdavidch	     (u64) stats->stat_IfHCInMulticastPkts_lo;
8195157642Sps
8196157642Sps	sc->stat_IfHCInBroadcastPkts =
8197206268Sdavidch	    ((u64) stats->stat_IfHCInBroadcastPkts_hi << 32) +
8198206268Sdavidch	     (u64) stats->stat_IfHCInBroadcastPkts_lo;
8199157642Sps
8200157642Sps	sc->stat_IfHCOutUcastPkts =
8201206268Sdavidch	    ((u64) stats->stat_IfHCOutUcastPkts_hi << 32) +
8202206268Sdavidch	     (u64) stats->stat_IfHCOutUcastPkts_lo;
8203157642Sps
8204157642Sps	sc->stat_IfHCOutMulticastPkts =
8205206268Sdavidch	    ((u64) stats->stat_IfHCOutMulticastPkts_hi << 32) +
8206206268Sdavidch	     (u64) stats->stat_IfHCOutMulticastPkts_lo;
8207157642Sps
8208157642Sps	sc->stat_IfHCOutBroadcastPkts =
8209206268Sdavidch	    ((u64) stats->stat_IfHCOutBroadcastPkts_hi << 32) +
8210206268Sdavidch	     (u64) stats->stat_IfHCOutBroadcastPkts_lo;
8211157642Sps
8212206268Sdavidch	/* ToDo: Preserve counters beyond 32 bits? */
8213206268Sdavidch	/* ToDo: Read the statistics from auto-clear regs? */
8214206268Sdavidch
8215157642Sps	sc->stat_emac_tx_stat_dot3statsinternalmactransmiterrors =
8216206268Sdavidch	    stats->stat_emac_tx_stat_dot3statsinternalmactransmiterrors;
8217157642Sps
8218157642Sps	sc->stat_Dot3StatsCarrierSenseErrors =
8219206268Sdavidch	    stats->stat_Dot3StatsCarrierSenseErrors;
8220157642Sps
8221179771Sdavidch	sc->stat_Dot3StatsFCSErrors =
8222206268Sdavidch	    stats->stat_Dot3StatsFCSErrors;
8223157642Sps
8224157642Sps	sc->stat_Dot3StatsAlignmentErrors =
8225206268Sdavidch	    stats->stat_Dot3StatsAlignmentErrors;
8226157642Sps
8227157642Sps	sc->stat_Dot3StatsSingleCollisionFrames =
8228206268Sdavidch	    stats->stat_Dot3StatsSingleCollisionFrames;
8229157642Sps
8230157642Sps	sc->stat_Dot3StatsMultipleCollisionFrames =
8231206268Sdavidch	    stats->stat_Dot3StatsMultipleCollisionFrames;
8232157642Sps
8233157642Sps	sc->stat_Dot3StatsDeferredTransmissions =
8234206268Sdavidch	    stats->stat_Dot3StatsDeferredTransmissions;
8235157642Sps
8236157642Sps	sc->stat_Dot3StatsExcessiveCollisions =
8237206268Sdavidch	    stats->stat_Dot3StatsExcessiveCollisions;
8238157642Sps
8239157642Sps	sc->stat_Dot3StatsLateCollisions =
8240206268Sdavidch	    stats->stat_Dot3StatsLateCollisions;
8241157642Sps
8242157642Sps	sc->stat_EtherStatsCollisions =
8243206268Sdavidch	    stats->stat_EtherStatsCollisions;
8244157642Sps
8245157642Sps	sc->stat_EtherStatsFragments =
8246206268Sdavidch	    stats->stat_EtherStatsFragments;
8247157642Sps
8248157642Sps	sc->stat_EtherStatsJabbers =
8249206268Sdavidch	    stats->stat_EtherStatsJabbers;
8250157642Sps
8251157642Sps	sc->stat_EtherStatsUndersizePkts =
8252206268Sdavidch	    stats->stat_EtherStatsUndersizePkts;
8253157642Sps
8254189325Sdavidch	sc->stat_EtherStatsOversizePkts =
8255206268Sdavidch	     stats->stat_EtherStatsOversizePkts;
8256157642Sps
8257157642Sps	sc->stat_EtherStatsPktsRx64Octets =
8258206268Sdavidch	    stats->stat_EtherStatsPktsRx64Octets;
8259157642Sps
8260157642Sps	sc->stat_EtherStatsPktsRx65Octetsto127Octets =
8261206268Sdavidch	    stats->stat_EtherStatsPktsRx65Octetsto127Octets;
8262157642Sps
8263157642Sps	sc->stat_EtherStatsPktsRx128Octetsto255Octets =
8264206268Sdavidch	    stats->stat_EtherStatsPktsRx128Octetsto255Octets;
8265157642Sps
8266157642Sps	sc->stat_EtherStatsPktsRx256Octetsto511Octets =
8267206268Sdavidch	    stats->stat_EtherStatsPktsRx256Octetsto511Octets;
8268157642Sps
8269157642Sps	sc->stat_EtherStatsPktsRx512Octetsto1023Octets =
8270206268Sdavidch	    stats->stat_EtherStatsPktsRx512Octetsto1023Octets;
8271157642Sps
8272157642Sps	sc->stat_EtherStatsPktsRx1024Octetsto1522Octets =
8273206268Sdavidch	    stats->stat_EtherStatsPktsRx1024Octetsto1522Octets;
8274157642Sps
8275157642Sps	sc->stat_EtherStatsPktsRx1523Octetsto9022Octets =
8276206268Sdavidch	    stats->stat_EtherStatsPktsRx1523Octetsto9022Octets;
8277157642Sps
8278157642Sps	sc->stat_EtherStatsPktsTx64Octets =
8279206268Sdavidch	    stats->stat_EtherStatsPktsTx64Octets;
8280157642Sps
8281157642Sps	sc->stat_EtherStatsPktsTx65Octetsto127Octets =
8282206268Sdavidch	    stats->stat_EtherStatsPktsTx65Octetsto127Octets;
8283157642Sps
8284157642Sps	sc->stat_EtherStatsPktsTx128Octetsto255Octets =
8285206268Sdavidch	    stats->stat_EtherStatsPktsTx128Octetsto255Octets;
8286157642Sps
8287157642Sps	sc->stat_EtherStatsPktsTx256Octetsto511Octets =
8288206268Sdavidch	    stats->stat_EtherStatsPktsTx256Octetsto511Octets;
8289157642Sps
8290157642Sps	sc->stat_EtherStatsPktsTx512Octetsto1023Octets =
8291206268Sdavidch	    stats->stat_EtherStatsPktsTx512Octetsto1023Octets;
8292157642Sps
8293157642Sps	sc->stat_EtherStatsPktsTx1024Octetsto1522Octets =
8294206268Sdavidch	    stats->stat_EtherStatsPktsTx1024Octetsto1522Octets;
8295157642Sps
8296157642Sps	sc->stat_EtherStatsPktsTx1523Octetsto9022Octets =
8297206268Sdavidch	    stats->stat_EtherStatsPktsTx1523Octetsto9022Octets;
8298157642Sps
8299157642Sps	sc->stat_XonPauseFramesReceived =
8300206268Sdavidch	    stats->stat_XonPauseFramesReceived;
8301157642Sps
8302157642Sps	sc->stat_XoffPauseFramesReceived =
8303206268Sdavidch	    stats->stat_XoffPauseFramesReceived;
8304157642Sps
8305157642Sps	sc->stat_OutXonSent =
8306206268Sdavidch	    stats->stat_OutXonSent;
8307157642Sps
8308157642Sps	sc->stat_OutXoffSent =
8309206268Sdavidch	    stats->stat_OutXoffSent;
8310157642Sps
8311157642Sps	sc->stat_FlowControlDone =
8312206268Sdavidch	    stats->stat_FlowControlDone;
8313157642Sps
8314157642Sps	sc->stat_MacControlFramesReceived =
8315206268Sdavidch	    stats->stat_MacControlFramesReceived;
8316157642Sps
8317157642Sps	sc->stat_XoffStateEntered =
8318206268Sdavidch	    stats->stat_XoffStateEntered;
8319157642Sps
8320157642Sps	sc->stat_IfInFramesL2FilterDiscards =
8321206268Sdavidch	    stats->stat_IfInFramesL2FilterDiscards;
8322157642Sps
8323157642Sps	sc->stat_IfInRuleCheckerDiscards =
8324206268Sdavidch	    stats->stat_IfInRuleCheckerDiscards;
8325157642Sps
8326157642Sps	sc->stat_IfInFTQDiscards =
8327206268Sdavidch	    stats->stat_IfInFTQDiscards;
8328157642Sps
8329157642Sps	sc->stat_IfInMBUFDiscards =
8330206268Sdavidch	    stats->stat_IfInMBUFDiscards;
8331157642Sps
8332157642Sps	sc->stat_IfInRuleCheckerP4Hit =
8333206268Sdavidch	    stats->stat_IfInRuleCheckerP4Hit;
8334157642Sps
8335157642Sps	sc->stat_CatchupInRuleCheckerDiscards =
8336206268Sdavidch	    stats->stat_CatchupInRuleCheckerDiscards;
8337157642Sps
8338157642Sps	sc->stat_CatchupInFTQDiscards =
8339206268Sdavidch	    stats->stat_CatchupInFTQDiscards;
8340157642Sps
8341157642Sps	sc->stat_CatchupInMBUFDiscards =
8342206268Sdavidch	    stats->stat_CatchupInMBUFDiscards;
8343157642Sps
8344157642Sps	sc->stat_CatchupInRuleCheckerP4Hit =
8345206268Sdavidch	    stats->stat_CatchupInRuleCheckerP4Hit;
8346157642Sps
8347170392Sdavidch	sc->com_no_buffers = REG_RD_IND(sc, 0x120084);
8348170392Sdavidch
8349272096Sglebius	/* ToDo: Add additional statistics? */
8350179771Sdavidch
8351272096Sglebius	DBEXIT(BCE_EXTREME_MISC);
8352272096Sglebius}
8353179771Sdavidch
8354272096Sglebiusstatic uint64_t
8355272096Sglebiusbce_get_counter(struct ifnet *ifp, ift_counter cnt)
8356272096Sglebius{
8357272096Sglebius	struct bce_softc *sc;
8358272096Sglebius	uint64_t rv;
8359179771Sdavidch
8360272096Sglebius	sc = if_getsoftc(ifp);
8361182293Sdavidch
8362272096Sglebius	switch (cnt) {
8363272096Sglebius	case IFCOUNTER_COLLISIONS:
8364272096Sglebius		return (sc->stat_EtherStatsCollisions);
8365272096Sglebius	case IFCOUNTER_IERRORS:
8366272096Sglebius		return (sc->stat_EtherStatsUndersizePkts +
8367272096Sglebius		    sc->stat_EtherStatsOversizePkts +
8368272096Sglebius		    sc->stat_IfInMBUFDiscards +
8369272096Sglebius		    sc->stat_Dot3StatsAlignmentErrors +
8370272096Sglebius		    sc->stat_Dot3StatsFCSErrors +
8371272096Sglebius		    sc->stat_IfInRuleCheckerDiscards +
8372272096Sglebius		    sc->stat_IfInFTQDiscards +
8373272096Sglebius		    sc->l2fhdr_error_count +
8374272096Sglebius		    sc->com_no_buffers);
8375272096Sglebius	case IFCOUNTER_OERRORS:
8376272096Sglebius		rv = sc->stat_Dot3StatsExcessiveCollisions +
8377272096Sglebius		    sc->stat_emac_tx_stat_dot3statsinternalmactransmiterrors +
8378272096Sglebius		    sc->stat_Dot3StatsLateCollisions +
8379272096Sglebius		    sc->watchdog_timeouts;
8380272096Sglebius		/*
8381272096Sglebius		 * Certain controllers don't report
8382272096Sglebius		 * carrier sense errors correctly.
8383272096Sglebius		 * See errata E11_5708CA0_1165.
8384272096Sglebius		 */
8385272096Sglebius		if (!(BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5706) &&
8386272096Sglebius		    !(BCE_CHIP_ID(sc) == BCE_CHIP_ID_5708_A0))
8387272096Sglebius			rv += sc->stat_Dot3StatsCarrierSenseErrors;
8388272096Sglebius		return (rv);
8389272096Sglebius	default:
8390272096Sglebius		return (if_get_counter_default(ifp, cnt));
8391272096Sglebius	}
8392157642Sps}
8393157642Sps
8394157642Sps
8395169271Sdavidch/****************************************************************************/
8396170810Sdavidch/* Periodic function to notify the bootcode that the driver is still        */
8397170810Sdavidch/* present.                                                                 */
8398170810Sdavidch/*                                                                          */
8399170810Sdavidch/* Returns:                                                                 */
8400170810Sdavidch/*   Nothing.                                                               */
8401170810Sdavidch/****************************************************************************/
8402170810Sdavidchstatic void
8403170810Sdavidchbce_pulse(void *xsc)
8404170810Sdavidch{
8405170810Sdavidch	struct bce_softc *sc = xsc;
8406170810Sdavidch	u32 msg;
8407170810Sdavidch
8408179771Sdavidch	DBENTER(BCE_EXTREME_MISC);
8409170810Sdavidch
8410170810Sdavidch	BCE_LOCK_ASSERT(sc);
8411170810Sdavidch
8412170810Sdavidch	/* Tell the firmware that the driver is still running. */
8413170810Sdavidch	msg = (u32) ++sc->bce_fw_drv_pulse_wr_seq;
8414194781Sdavidch	bce_shmem_wr(sc, BCE_DRV_PULSE_MB, msg);
8415170810Sdavidch
8416206268Sdavidch	/* Update the bootcode condition. */
8417206268Sdavidch	sc->bc_state = bce_shmem_rd(sc, BCE_BC_STATE_CONDITION);
8418206268Sdavidch
8419206268Sdavidch	/* Report whether the bootcode still knows the driver is running. */
8420218423Sdavidch	if (bce_verbose || bootverbose) {
8421207411Sdavidch		if (sc->bce_drv_cardiac_arrest == FALSE) {
8422207411Sdavidch			if (!(sc->bc_state & BCE_CONDITION_DRV_PRESENT)) {
8423207411Sdavidch				sc->bce_drv_cardiac_arrest = TRUE;
8424207411Sdavidch				BCE_PRINTF("%s(): Warning: bootcode "
8425207411Sdavidch				    "thinks driver is absent! "
8426207411Sdavidch				    "(bc_state = 0x%08X)\n",
8427207411Sdavidch				    __FUNCTION__, sc->bc_state);
8428207411Sdavidch			}
8429207411Sdavidch		} else {
8430207411Sdavidch			/*
8431207411Sdavidch			 * Not supported by all bootcode versions.
8432207411Sdavidch			 * (v5.0.11+ and v5.2.1+)  Older bootcode
8433207411Sdavidch			 * will require the driver to reset the
8434207411Sdavidch			 * controller to clear this condition.
8435207411Sdavidch			 */
8436207411Sdavidch			if (sc->bc_state & BCE_CONDITION_DRV_PRESENT) {
8437207411Sdavidch				sc->bce_drv_cardiac_arrest = FALSE;
8438207411Sdavidch				BCE_PRINTF("%s(): Bootcode found the "
8439207411Sdavidch				    "driver pulse! (bc_state = 0x%08X)\n",
8440207411Sdavidch				    __FUNCTION__, sc->bc_state);
8441207411Sdavidch			}
8442206268Sdavidch		}
8443206268Sdavidch	}
8444206268Sdavidch
8445206268Sdavidch
8446170810Sdavidch	/* Schedule the next pulse. */
8447170810Sdavidch	callout_reset(&sc->bce_pulse_callout, hz, bce_pulse, sc);
8448170810Sdavidch
8449179771Sdavidch	DBEXIT(BCE_EXTREME_MISC);
8450170810Sdavidch}
8451170810Sdavidch
8452170810Sdavidch
8453170810Sdavidch/****************************************************************************/
8454170392Sdavidch/* Periodic function to perform maintenance tasks.                          */
8455169271Sdavidch/*                                                                          */
8456169271Sdavidch/* Returns:                                                                 */
8457169271Sdavidch/*   Nothing.                                                               */
8458169271Sdavidch/****************************************************************************/
8459157642Spsstatic void
8460165933Sdelphijbce_tick(void *xsc)
8461157642Sps{
8462165933Sdelphij	struct bce_softc *sc = xsc;
8463169271Sdavidch	struct mii_data *mii;
8464157642Sps	struct ifnet *ifp;
8465235151Syongari	struct ifmediareq ifmr;
8466157642Sps
8467157642Sps	ifp = sc->bce_ifp;
8468157642Sps
8469179771Sdavidch	DBENTER(BCE_EXTREME_MISC);
8470179771Sdavidch
8471157642Sps	BCE_LOCK_ASSERT(sc);
8472157642Sps
8473176448Sdavidch	/* Schedule the next tick. */
8474176448Sdavidch	callout_reset(&sc->bce_tick_callout, hz, bce_tick, sc);
8475176448Sdavidch
8476157642Sps	/* Update the statistics from the hardware statistics block. */
8477157642Sps	bce_stats_update(sc);
8478157642Sps
8479251142Smarius 	/* Ensure page and RX chains get refilled in low-memory situations. */
8480218423Sdavidch	if (bce_hdr_split == TRUE)
8481218423Sdavidch		bce_fill_pg_chain(sc);
8482176448Sdavidch	bce_fill_rx_chain(sc);
8483176448Sdavidch
8484169271Sdavidch	/* Check that chip hasn't hung. */
8485165933Sdelphij	bce_watchdog(sc);
8486165933Sdelphij
8487157642Sps	/* If link is up already up then we're done. */
8488234121Syongari	if (sc->bce_link_up == TRUE)
8489179771Sdavidch		goto bce_tick_exit;
8490157642Sps
8491182293Sdavidch	/* Link is down.  Check what the PHY's doing. */
8492235151Syongari	if ((sc->bce_phy_flags & BCE_PHY_REMOTE_CAP_FLAG) != 0) {
8493235151Syongari		bzero(&ifmr, sizeof(ifmr));
8494235151Syongari		bce_ifmedia_sts_rphy(sc, &ifmr);
8495235151Syongari		if ((ifmr.ifm_status & (IFM_ACTIVE | IFM_AVALID)) ==
8496235151Syongari		    (IFM_ACTIVE | IFM_AVALID)) {
8497235151Syongari			sc->bce_link_up = TRUE;
8498235151Syongari			bce_miibus_statchg(sc->bce_dev);
8499235151Syongari		}
8500235151Syongari	} else {
8501235151Syongari		mii = device_get_softc(sc->bce_miibus);
8502235151Syongari		mii_tick(mii);
8503235151Syongari		/* Check if the link has come up. */
8504235151Syongari		if ((mii->mii_media_status & IFM_ACTIVE) &&
8505235151Syongari		    (IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE)) {
8506235151Syongari			DBPRINT(sc, BCE_VERBOSE_MISC, "%s(): Link up!\n",
8507235151Syongari			    __FUNCTION__);
8508235151Syongari			sc->bce_link_up = TRUE;
8509235151Syongari			if ((IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_T ||
8510235151Syongari			    IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_SX ||
8511235151Syongari			    IFM_SUBTYPE(mii->mii_media_active) == IFM_2500_SX) &&
8512235151Syongari			    (bce_verbose || bootverbose))
8513235151Syongari				BCE_PRINTF("Gigabit link up!\n");
8514235151Syongari		}
8515157642Sps
8516235151Syongari	}
8517235151Syongari	if (sc->bce_link_up == TRUE) {
8518234121Syongari		/* Now that link is up, handle any outstanding TX traffic. */
8519234121Syongari		if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) {
8520234121Syongari			DBPRINT(sc, BCE_VERBOSE_MISC, "%s(): Found "
8521234121Syongari			    "pending TX traffic.\n", __FUNCTION__);
8522234121Syongari			bce_start_locked(ifp);
8523234121Syongari		}
8524157642Sps	}
8525157642Sps
8526179771Sdavidchbce_tick_exit:
8527179771Sdavidch	DBEXIT(BCE_EXTREME_MISC);
8528157642Sps}
8529157642Sps
8530235151Syongaristatic void
8531235151Syongaribce_fw_cap_init(struct bce_softc *sc)
8532235151Syongari{
8533235151Syongari	u32 ack, cap, link;
8534235151Syongari
8535235151Syongari	ack = 0;
8536235151Syongari	cap = bce_shmem_rd(sc, BCE_FW_CAP_MB);
8537235151Syongari	if ((cap & BCE_FW_CAP_SIGNATURE_MAGIC_MASK) !=
8538235151Syongari	    BCE_FW_CAP_SIGNATURE_MAGIC)
8539235151Syongari		return;
8540235151Syongari	if ((cap & (BCE_FW_CAP_MFW_KEEP_VLAN | BCE_FW_CAP_BC_KEEP_VLAN)) ==
8541235151Syongari	    (BCE_FW_CAP_MFW_KEEP_VLAN | BCE_FW_CAP_BC_KEEP_VLAN))
8542235151Syongari		ack |= BCE_DRV_ACK_CAP_SIGNATURE_MAGIC |
8543235151Syongari		    BCE_FW_CAP_MFW_KEEP_VLAN | BCE_FW_CAP_BC_KEEP_VLAN;
8544235151Syongari	if ((sc->bce_phy_flags & BCE_PHY_SERDES_FLAG) != 0 &&
8545235151Syongari	    (cap & BCE_FW_CAP_REMOTE_PHY_CAP) != 0) {
8546235151Syongari		sc->bce_phy_flags &= ~BCE_PHY_REMOTE_PORT_FIBER_FLAG;
8547235151Syongari		sc->bce_phy_flags |= BCE_PHY_REMOTE_CAP_FLAG;
8548235151Syongari		link = bce_shmem_rd(sc, BCE_LINK_STATUS);
8549235151Syongari		if ((link & BCE_LINK_STATUS_SERDES_LINK) != 0)
8550235151Syongari			sc->bce_phy_flags |= BCE_PHY_REMOTE_PORT_FIBER_FLAG;
8551235151Syongari		ack |= BCE_DRV_ACK_CAP_SIGNATURE_MAGIC |
8552235151Syongari		    BCE_FW_CAP_REMOTE_PHY_CAP;
8553235151Syongari	}
8554235151Syongari
8555235151Syongari	if (ack != 0)
8556235151Syongari		bce_shmem_wr(sc, BCE_DRV_ACK_CAP_MB, ack);
8557235151Syongari}
8558235151Syongari
8559235151Syongari
8560157642Sps#ifdef BCE_DEBUG
8561157642Sps/****************************************************************************/
8562157642Sps/* Allows the driver state to be dumped through the sysctl interface.       */
8563157642Sps/*                                                                          */
8564157642Sps/* Returns:                                                                 */
8565157642Sps/*   0 for success, positive value for failure.                             */
8566157642Sps/****************************************************************************/
8567157642Spsstatic int
8568157642Spsbce_sysctl_driver_state(SYSCTL_HANDLER_ARGS)
8569157642Sps{
8570206268Sdavidch	int error;
8571206268Sdavidch	int result;
8572206268Sdavidch	struct bce_softc *sc;
8573157642Sps
8574206268Sdavidch	result = -1;
8575206268Sdavidch	error = sysctl_handle_int(oidp, &result, 0, req);
8576157642Sps
8577206268Sdavidch	if (error || !req->newptr)
8578206268Sdavidch		return (error);
8579157642Sps
8580206268Sdavidch	if (result == 1) {
8581206268Sdavidch		sc = (struct bce_softc *)arg1;
8582206268Sdavidch		bce_dump_driver_state(sc);
8583206268Sdavidch	}
8584157642Sps
8585206268Sdavidch	return error;
8586157642Sps}
8587157642Sps
8588157642Sps
8589157642Sps/****************************************************************************/
8590157642Sps/* Allows the hardware state to be dumped through the sysctl interface.     */
8591157642Sps/*                                                                          */
8592157642Sps/* Returns:                                                                 */
8593157642Sps/*   0 for success, positive value for failure.                             */
8594157642Sps/****************************************************************************/
8595157642Spsstatic int
8596157642Spsbce_sysctl_hw_state(SYSCTL_HANDLER_ARGS)
8597157642Sps{
8598206268Sdavidch	int error;
8599206268Sdavidch	int result;
8600206268Sdavidch	struct bce_softc *sc;
8601157642Sps
8602206268Sdavidch	result = -1;
8603206268Sdavidch	error = sysctl_handle_int(oidp, &result, 0, req);
8604157642Sps
8605206268Sdavidch	if (error || !req->newptr)
8606206268Sdavidch		return (error);
8607157642Sps
8608206268Sdavidch	if (result == 1) {
8609206268Sdavidch		sc = (struct bce_softc *)arg1;
8610206268Sdavidch		bce_dump_hw_state(sc);
8611206268Sdavidch	}
8612157642Sps
8613206268Sdavidch	return error;
8614157642Sps}
8615157642Sps
8616157642Sps
8617157642Sps/****************************************************************************/
8618206268Sdavidch/* Allows the status block to be dumped through the sysctl interface.       */
8619206268Sdavidch/*                                                                          */
8620206268Sdavidch/* Returns:                                                                 */
8621206268Sdavidch/*   0 for success, positive value for failure.                             */
8622206268Sdavidch/****************************************************************************/
8623206268Sdavidchstatic int
8624206268Sdavidchbce_sysctl_status_block(SYSCTL_HANDLER_ARGS)
8625206268Sdavidch{
8626206268Sdavidch	int error;
8627206268Sdavidch	int result;
8628206268Sdavidch	struct bce_softc *sc;
8629206268Sdavidch
8630206268Sdavidch	result = -1;
8631206268Sdavidch	error = sysctl_handle_int(oidp, &result, 0, req);
8632206268Sdavidch
8633206268Sdavidch	if (error || !req->newptr)
8634206268Sdavidch		return (error);
8635206268Sdavidch
8636206268Sdavidch	if (result == 1) {
8637206268Sdavidch		sc = (struct bce_softc *)arg1;
8638206268Sdavidch		bce_dump_status_block(sc);
8639206268Sdavidch	}
8640206268Sdavidch
8641206268Sdavidch	return error;
8642206268Sdavidch}
8643206268Sdavidch
8644206268Sdavidch
8645206268Sdavidch/****************************************************************************/
8646206268Sdavidch/* Allows the stats block to be dumped through the sysctl interface.        */
8647206268Sdavidch/*                                                                          */
8648206268Sdavidch/* Returns:                                                                 */
8649206268Sdavidch/*   0 for success, positive value for failure.                             */
8650206268Sdavidch/****************************************************************************/
8651206268Sdavidchstatic int
8652206268Sdavidchbce_sysctl_stats_block(SYSCTL_HANDLER_ARGS)
8653206268Sdavidch{
8654206268Sdavidch	int error;
8655206268Sdavidch	int result;
8656206268Sdavidch	struct bce_softc *sc;
8657206268Sdavidch
8658206268Sdavidch	result = -1;
8659206268Sdavidch	error = sysctl_handle_int(oidp, &result, 0, req);
8660206268Sdavidch
8661206268Sdavidch	if (error || !req->newptr)
8662206268Sdavidch		return (error);
8663206268Sdavidch
8664206268Sdavidch	if (result == 1) {
8665206268Sdavidch		sc = (struct bce_softc *)arg1;
8666206268Sdavidch		bce_dump_stats_block(sc);
8667206268Sdavidch	}
8668206268Sdavidch
8669206268Sdavidch	return error;
8670206268Sdavidch}
8671206268Sdavidch
8672206268Sdavidch
8673206268Sdavidch/****************************************************************************/
8674207411Sdavidch/* Allows the stat counters to be cleared without unloading/reloading the   */
8675207411Sdavidch/* driver.                                                                  */
8676207411Sdavidch/*                                                                          */
8677207411Sdavidch/* Returns:                                                                 */
8678207411Sdavidch/*   0 for success, positive value for failure.                             */
8679207411Sdavidch/****************************************************************************/
8680207411Sdavidchstatic int
8681207411Sdavidchbce_sysctl_stats_clear(SYSCTL_HANDLER_ARGS)
8682207411Sdavidch{
8683207411Sdavidch	int error;
8684207411Sdavidch	int result;
8685207411Sdavidch	struct bce_softc *sc;
8686207411Sdavidch
8687207411Sdavidch	result = -1;
8688207411Sdavidch	error = sysctl_handle_int(oidp, &result, 0, req);
8689207411Sdavidch
8690207411Sdavidch	if (error || !req->newptr)
8691207411Sdavidch		return (error);
8692207411Sdavidch
8693207411Sdavidch	if (result == 1) {
8694207411Sdavidch		sc = (struct bce_softc *)arg1;
8695218423Sdavidch		struct statistics_block *stats;
8696207411Sdavidch
8697218423Sdavidch		stats = (struct statistics_block *) sc->stats_block;
8698218423Sdavidch		bzero(stats, sizeof(struct statistics_block));
8699251159Smarius		bus_dmamap_sync(sc->stats_tag, sc->stats_map,
8700251159Smarius		    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
8701218423Sdavidch
8702207411Sdavidch		/* Clear the internal H/W statistics counters. */
8703207411Sdavidch		REG_WR(sc, BCE_HC_COMMAND, BCE_HC_COMMAND_CLR_STAT_NOW);
8704207411Sdavidch
8705207411Sdavidch		/* Reset the driver maintained statistics. */
8706207411Sdavidch		sc->interrupts_rx =
8707207411Sdavidch		    sc->interrupts_tx = 0;
8708207411Sdavidch		sc->tso_frames_requested =
8709207411Sdavidch		    sc->tso_frames_completed =
8710207411Sdavidch		    sc->tso_frames_failed = 0;
8711207411Sdavidch		sc->rx_empty_count =
8712207411Sdavidch		    sc->tx_full_count = 0;
8713218423Sdavidch		sc->rx_low_watermark = USABLE_RX_BD_ALLOC;
8714207411Sdavidch		sc->tx_hi_watermark = 0;
8715207411Sdavidch		sc->l2fhdr_error_count =
8716207411Sdavidch		    sc->l2fhdr_error_sim_count = 0;
8717207411Sdavidch		sc->mbuf_alloc_failed_count =
8718207411Sdavidch		    sc->mbuf_alloc_failed_sim_count = 0;
8719207411Sdavidch		sc->dma_map_addr_rx_failed_count =
8720207411Sdavidch		    sc->dma_map_addr_tx_failed_count = 0;
8721207411Sdavidch		sc->mbuf_frag_count = 0;
8722207411Sdavidch		sc->csum_offload_tcp_udp =
8723218423Sdavidch		    sc->csum_offload_ip = 0;
8724207411Sdavidch		sc->vlan_tagged_frames_rcvd =
8725218423Sdavidch		    sc->vlan_tagged_frames_stripped = 0;
8726218423Sdavidch		sc->split_header_frames_rcvd =
8727218423Sdavidch		    sc->split_header_tcp_frames_rcvd = 0;
8728207411Sdavidch
8729207411Sdavidch		/* Clear firmware maintained statistics. */
8730207411Sdavidch		REG_WR_IND(sc, 0x120084, 0);
8731207411Sdavidch	}
8732207411Sdavidch
8733207411Sdavidch	return error;
8734207411Sdavidch}
8735207411Sdavidch
8736207411Sdavidch
8737207411Sdavidch/****************************************************************************/
8738218423Sdavidch/* Allows the shared memory contents to be dumped through the sysctl  .     */
8739218423Sdavidch/* interface.                                                               */
8740218423Sdavidch/*                                                                          */
8741218423Sdavidch/* Returns:                                                                 */
8742218423Sdavidch/*   0 for success, positive value for failure.                             */
8743218423Sdavidch/****************************************************************************/
8744218423Sdavidchstatic int
8745218423Sdavidchbce_sysctl_shmem_state(SYSCTL_HANDLER_ARGS)
8746218423Sdavidch{
8747218423Sdavidch	int error;
8748218423Sdavidch	int result;
8749218423Sdavidch	struct bce_softc *sc;
8750218423Sdavidch
8751218423Sdavidch	result = -1;
8752218423Sdavidch	error = sysctl_handle_int(oidp, &result, 0, req);
8753218423Sdavidch
8754218423Sdavidch	if (error || !req->newptr)
8755218423Sdavidch		return (error);
8756218423Sdavidch
8757218423Sdavidch	if (result == 1) {
8758218423Sdavidch		sc = (struct bce_softc *)arg1;
8759218423Sdavidch		bce_dump_shmem_state(sc);
8760218423Sdavidch	}
8761218423Sdavidch
8762218423Sdavidch	return error;
8763218423Sdavidch}
8764218423Sdavidch
8765218423Sdavidch
8766218423Sdavidch/****************************************************************************/
8767170810Sdavidch/* Allows the bootcode state to be dumped through the sysctl interface.     */
8768157642Sps/*                                                                          */
8769157642Sps/* Returns:                                                                 */
8770157642Sps/*   0 for success, positive value for failure.                             */
8771157642Sps/****************************************************************************/
8772157642Spsstatic int
8773170810Sdavidchbce_sysctl_bc_state(SYSCTL_HANDLER_ARGS)
8774170810Sdavidch{
8775206268Sdavidch	int error;
8776206268Sdavidch	int result;
8777206268Sdavidch	struct bce_softc *sc;
8778170810Sdavidch
8779206268Sdavidch	result = -1;
8780206268Sdavidch	error = sysctl_handle_int(oidp, &result, 0, req);
8781170810Sdavidch
8782206268Sdavidch	if (error || !req->newptr)
8783206268Sdavidch		return (error);
8784170810Sdavidch
8785206268Sdavidch	if (result == 1) {
8786206268Sdavidch		sc = (struct bce_softc *)arg1;
8787206268Sdavidch		bce_dump_bc_state(sc);
8788206268Sdavidch	}
8789170810Sdavidch
8790206268Sdavidch	return error;
8791170810Sdavidch}
8792170810Sdavidch
8793170810Sdavidch
8794170810Sdavidch/****************************************************************************/
8795206268Sdavidch/* Provides a sysctl interface to allow dumping the RX BD chain.            */
8796170810Sdavidch/*                                                                          */
8797170810Sdavidch/* Returns:                                                                 */
8798170810Sdavidch/*   0 for success, positive value for failure.                             */
8799170810Sdavidch/****************************************************************************/
8800170810Sdavidchstatic int
8801206268Sdavidchbce_sysctl_dump_rx_bd_chain(SYSCTL_HANDLER_ARGS)
8802157642Sps{
8803206268Sdavidch	int error;
8804206268Sdavidch	int result;
8805206268Sdavidch	struct bce_softc *sc;
8806157642Sps
8807206268Sdavidch	result = -1;
8808206268Sdavidch	error = sysctl_handle_int(oidp, &result, 0, req);
8809157642Sps
8810206268Sdavidch	if (error || !req->newptr)
8811206268Sdavidch		return (error);
8812157642Sps
8813206268Sdavidch	if (result == 1) {
8814206268Sdavidch		sc = (struct bce_softc *)arg1;
8815218423Sdavidch		bce_dump_rx_bd_chain(sc, 0, TOTAL_RX_BD_ALLOC);
8816206268Sdavidch	}
8817157642Sps
8818206268Sdavidch	return error;
8819157642Sps}
8820157642Sps
8821157642Sps
8822157642Sps/****************************************************************************/
8823206268Sdavidch/* Provides a sysctl interface to allow dumping the RX MBUF chain.          */
8824206268Sdavidch/*                                                                          */
8825206268Sdavidch/* Returns:                                                                 */
8826206268Sdavidch/*   0 for success, positive value for failure.                             */
8827206268Sdavidch/****************************************************************************/
8828206268Sdavidchstatic int
8829206268Sdavidchbce_sysctl_dump_rx_mbuf_chain(SYSCTL_HANDLER_ARGS)
8830206268Sdavidch{
8831206268Sdavidch	int error;
8832206268Sdavidch	int result;
8833206268Sdavidch	struct bce_softc *sc;
8834206268Sdavidch
8835206268Sdavidch	result = -1;
8836206268Sdavidch	error = sysctl_handle_int(oidp, &result, 0, req);
8837206268Sdavidch
8838206268Sdavidch	if (error || !req->newptr)
8839206268Sdavidch		return (error);
8840206268Sdavidch
8841206268Sdavidch	if (result == 1) {
8842206268Sdavidch		sc = (struct bce_softc *)arg1;
8843218423Sdavidch		bce_dump_rx_mbuf_chain(sc, 0, USABLE_RX_BD_ALLOC);
8844206268Sdavidch	}
8845206268Sdavidch
8846206268Sdavidch	return error;
8847206268Sdavidch}
8848206268Sdavidch
8849206268Sdavidch
8850206268Sdavidch/****************************************************************************/
8851170810Sdavidch/* Provides a sysctl interface to allow dumping the TX chain.               */
8852157642Sps/*                                                                          */
8853169271Sdavidch/* Returns:                                                                 */
8854169271Sdavidch/*   0 for success, positive value for failure.                             */
8855169271Sdavidch/****************************************************************************/
8856169271Sdavidchstatic int
8857169271Sdavidchbce_sysctl_dump_tx_chain(SYSCTL_HANDLER_ARGS)
8858169271Sdavidch{
8859206268Sdavidch	int error;
8860206268Sdavidch	int result;
8861206268Sdavidch	struct bce_softc *sc;
8862169271Sdavidch
8863206268Sdavidch	result = -1;
8864206268Sdavidch	error = sysctl_handle_int(oidp, &result, 0, req);
8865169271Sdavidch
8866206268Sdavidch	if (error || !req->newptr)
8867206268Sdavidch		return (error);
8868169271Sdavidch
8869206268Sdavidch	if (result == 1) {
8870206268Sdavidch		sc = (struct bce_softc *)arg1;
8871218423Sdavidch		bce_dump_tx_chain(sc, 0, TOTAL_TX_BD_ALLOC);
8872206268Sdavidch	}
8873169271Sdavidch
8874206268Sdavidch	return error;
8875169271Sdavidch}
8876169271Sdavidch
8877169271Sdavidch
8878169271Sdavidch/****************************************************************************/
8879176448Sdavidch/* Provides a sysctl interface to allow dumping the page chain.             */
8880176448Sdavidch/*                                                                          */
8881176448Sdavidch/* Returns:                                                                 */
8882176448Sdavidch/*   0 for success, positive value for failure.                             */
8883176448Sdavidch/****************************************************************************/
8884176448Sdavidchstatic int
8885176448Sdavidchbce_sysctl_dump_pg_chain(SYSCTL_HANDLER_ARGS)
8886176448Sdavidch{
8887206268Sdavidch	int error;
8888206268Sdavidch	int result;
8889206268Sdavidch	struct bce_softc *sc;
8890176448Sdavidch
8891206268Sdavidch	result = -1;
8892206268Sdavidch	error = sysctl_handle_int(oidp, &result, 0, req);
8893176448Sdavidch
8894206268Sdavidch	if (error || !req->newptr)
8895206268Sdavidch		return (error);
8896176448Sdavidch
8897206268Sdavidch	if (result == 1) {
8898206268Sdavidch		sc = (struct bce_softc *)arg1;
8899218423Sdavidch		bce_dump_pg_chain(sc, 0, TOTAL_PG_BD_ALLOC);
8900206268Sdavidch	}
8901176448Sdavidch
8902206268Sdavidch	return error;
8903179771Sdavidch}
8904176448Sdavidch
8905179771Sdavidch/****************************************************************************/
8906179771Sdavidch/* Provides a sysctl interface to allow reading arbitrary NVRAM offsets in  */
8907179771Sdavidch/* the device.  DO NOT ENABLE ON PRODUCTION SYSTEMS!                        */
8908179771Sdavidch/*                                                                          */
8909179771Sdavidch/* Returns:                                                                 */
8910179771Sdavidch/*   0 for success, positive value for failure.                             */
8911179771Sdavidch/****************************************************************************/
8912179771Sdavidchstatic int
8913179771Sdavidchbce_sysctl_nvram_read(SYSCTL_HANDLER_ARGS)
8914179771Sdavidch{
8915179771Sdavidch	struct bce_softc *sc = (struct bce_softc *)arg1;
8916179771Sdavidch	int error;
8917182293Sdavidch	u32 result;
8918182293Sdavidch	u32 val[1];
8919179771Sdavidch	u8 *data = (u8 *) val;
8920176448Sdavidch
8921179771Sdavidch	result = -1;
8922179771Sdavidch	error = sysctl_handle_int(oidp, &result, 0, req);
8923179771Sdavidch	if (error || (req->newptr == NULL))
8924179771Sdavidch		return (error);
8925179771Sdavidch
8926218527Sdavidch	error = bce_nvram_read(sc, result, data, 4);
8927218527Sdavidch
8928179771Sdavidch	BCE_PRINTF("offset 0x%08X = 0x%08X\n", result, bce_be32toh(val[0]));
8929182293Sdavidch
8930179771Sdavidch	return (error);
8931179771Sdavidch}
8932182293Sdavidch
8933182293Sdavidch
8934176448Sdavidch/****************************************************************************/
8935170392Sdavidch/* Provides a sysctl interface to allow reading arbitrary registers in the  */
8936170392Sdavidch/* device.  DO NOT ENABLE ON PRODUCTION SYSTEMS!                            */
8937157642Sps/*                                                                          */
8938157642Sps/* Returns:                                                                 */
8939157642Sps/*   0 for success, positive value for failure.                             */
8940157642Sps/****************************************************************************/
8941157642Spsstatic int
8942169271Sdavidchbce_sysctl_reg_read(SYSCTL_HANDLER_ARGS)
8943169271Sdavidch{
8944179771Sdavidch	struct bce_softc *sc = (struct bce_softc *)arg1;
8945169271Sdavidch	int error;
8946170810Sdavidch	u32 val, result;
8947179771Sdavidch
8948169271Sdavidch	result = -1;
8949169271Sdavidch	error = sysctl_handle_int(oidp, &result, 0, req);
8950169271Sdavidch	if (error || (req->newptr == NULL))
8951169271Sdavidch		return (error);
8952179771Sdavidch
8953170392Sdavidch	/* Make sure the register is accessible. */
8954169271Sdavidch	if (result < 0x8000) {
8955169271Sdavidch		val = REG_RD(sc, result);
8956169271Sdavidch		BCE_PRINTF("reg 0x%08X = 0x%08X\n", result, val);
8957169271Sdavidch	} else if (result < 0x0280000) {
8958169271Sdavidch		val = REG_RD_IND(sc, result);
8959170392Sdavidch		BCE_PRINTF("reg 0x%08X = 0x%08X\n", result, val);
8960169271Sdavidch	}
8961179771Sdavidch
8962169271Sdavidch	return (error);
8963169271Sdavidch}
8964170392Sdavidch
8965179771Sdavidch
8966169271Sdavidch/****************************************************************************/
8967170392Sdavidch/* Provides a sysctl interface to allow reading arbitrary PHY registers in  */
8968170392Sdavidch/* the device.  DO NOT ENABLE ON PRODUCTION SYSTEMS!                        */
8969169632Sdavidch/*                                                                          */
8970169632Sdavidch/* Returns:                                                                 */
8971169632Sdavidch/*   0 for success, positive value for failure.                             */
8972169632Sdavidch/****************************************************************************/
8973169632Sdavidchstatic int
8974169632Sdavidchbce_sysctl_phy_read(SYSCTL_HANDLER_ARGS)
8975169632Sdavidch{
8976170392Sdavidch	struct bce_softc *sc;
8977169632Sdavidch	device_t dev;
8978169632Sdavidch	int error, result;
8979169632Sdavidch	u16 val;
8980169632Sdavidch
8981169632Sdavidch	result = -1;
8982169632Sdavidch	error = sysctl_handle_int(oidp, &result, 0, req);
8983169632Sdavidch	if (error || (req->newptr == NULL))
8984169632Sdavidch		return (error);
8985169632Sdavidch
8986170392Sdavidch	/* Make sure the register is accessible. */
8987169632Sdavidch	if (result < 0x20) {
8988170392Sdavidch		sc = (struct bce_softc *)arg1;
8989169632Sdavidch		dev = sc->bce_dev;
8990169632Sdavidch		val = bce_miibus_read_reg(dev, sc->bce_phy_addr, result);
8991169632Sdavidch		BCE_PRINTF("phy 0x%02X = 0x%04X\n", result, val);
8992169632Sdavidch	}
8993169632Sdavidch	return (error);
8994169632Sdavidch}
8995170392Sdavidch
8996170392Sdavidch
8997218527Sdavidch/****************************************************************************/
8998218527Sdavidch/* Provides a sysctl interface for dumping the nvram contents.              */
8999218527Sdavidch/* DO NOT ENABLE ON PRODUCTION SYSTEMS!					    */
9000218527Sdavidch/*									    */
9001218527Sdavidch/* Returns:								    */
9002218527Sdavidch/*   0 for success, positive errno for failure.				    */
9003218527Sdavidch/****************************************************************************/
9004213489Sambriskostatic int
9005218527Sdavidchbce_sysctl_nvram_dump(SYSCTL_HANDLER_ARGS)
9006213489Sambrisko{
9007213489Sambrisko	struct bce_softc *sc = (struct bce_softc *)arg1;
9008213489Sambrisko	int error, i;
9009213489Sambrisko
9010218527Sdavidch	if (sc->nvram_buf == NULL)
9011213489Sambrisko		sc->nvram_buf = malloc(sc->bce_flash_size,
9012218527Sdavidch				    M_TEMP, M_ZERO | M_WAITOK);
9013218527Sdavidch
9014218527Sdavidch	error = 0;
9015213489Sambrisko	if (req->oldlen == sc->bce_flash_size) {
9016218527Sdavidch		for (i = 0; i < sc->bce_flash_size && error == 0; i++)
9017218527Sdavidch			error = bce_nvram_read(sc, i, &sc->nvram_buf[i], 1);
9018213489Sambrisko	}
9019213489Sambrisko
9020218527Sdavidch	if (error == 0)
9021218527Sdavidch		error = SYSCTL_OUT(req, sc->nvram_buf, sc->bce_flash_size);
9022213489Sambrisko
9023213489Sambrisko	return error;
9024213489Sambrisko}
9025213489Sambrisko
9026213489Sambrisko#ifdef BCE_NVRAM_WRITE_SUPPORT
9027218527Sdavidch/****************************************************************************/
9028218527Sdavidch/* Provides a sysctl interface for writing to nvram.                        */
9029218527Sdavidch/* DO NOT ENABLE ON PRODUCTION SYSTEMS!					    */
9030218527Sdavidch/*									    */
9031218527Sdavidch/* Returns:								    */
9032218527Sdavidch/*   0 for success, positive errno for failure.				    */
9033218527Sdavidch/****************************************************************************/
9034213489Sambriskostatic int
9035218527Sdavidchbce_sysctl_nvram_write(SYSCTL_HANDLER_ARGS)
9036213489Sambrisko{
9037213489Sambrisko	struct bce_softc *sc = (struct bce_softc *)arg1;
9038213489Sambrisko	int error;
9039213489Sambrisko
9040218527Sdavidch	if (sc->nvram_buf == NULL)
9041213489Sambrisko		sc->nvram_buf = malloc(sc->bce_flash_size,
9042218527Sdavidch				    M_TEMP, M_ZERO | M_WAITOK);
9043218527Sdavidch	else
9044218527Sdavidch		bzero(sc->nvram_buf, sc->bce_flash_size);
9045218527Sdavidch
9046213489Sambrisko	error = SYSCTL_IN(req, sc->nvram_buf, sc->bce_flash_size);
9047218527Sdavidch	if (error == 0)
9048218527Sdavidch		return (error);
9049213489Sambrisko
9050218527Sdavidch	if (req->newlen == sc->bce_flash_size)
9051218527Sdavidch		error = bce_nvram_write(sc, 0, sc->nvram_buf,
9052218527Sdavidch			    sc->bce_flash_size);
9053213489Sambrisko
9054213489Sambrisko
9055213489Sambrisko	return error;
9056213489Sambrisko}
9057213489Sambrisko#endif
9058213489Sambrisko
9059213489Sambrisko
9060169632Sdavidch/****************************************************************************/
9061179771Sdavidch/* Provides a sysctl interface to allow reading a CID.                      */
9062179771Sdavidch/*                                                                          */
9063179771Sdavidch/* Returns:                                                                 */
9064179771Sdavidch/*   0 for success, positive value for failure.                             */
9065179771Sdavidch/****************************************************************************/
9066179771Sdavidchstatic int
9067179771Sdavidchbce_sysctl_dump_ctx(SYSCTL_HANDLER_ARGS)
9068179771Sdavidch{
9069179771Sdavidch	struct bce_softc *sc;
9070207411Sdavidch	int error, result;
9071179771Sdavidch
9072179771Sdavidch	result = -1;
9073179771Sdavidch	error = sysctl_handle_int(oidp, &result, 0, req);
9074179771Sdavidch	if (error || (req->newptr == NULL))
9075179771Sdavidch		return (error);
9076179771Sdavidch
9077179771Sdavidch	/* Make sure the register is accessible. */
9078179771Sdavidch	if (result <= TX_CID) {
9079179771Sdavidch		sc = (struct bce_softc *)arg1;
9080179771Sdavidch		bce_dump_ctx(sc, result);
9081179771Sdavidch	}
9082179771Sdavidch
9083179771Sdavidch	return (error);
9084179771Sdavidch}
9085179771Sdavidch
9086179771Sdavidch
9087218527Sdavidch/****************************************************************************/
9088170392Sdavidch/* Provides a sysctl interface to forcing the driver to dump state and      */
9089169271Sdavidch/* enter the debugger.  DO NOT ENABLE ON PRODUCTION SYSTEMS!                */
9090169271Sdavidch/*                                                                          */
9091169271Sdavidch/* Returns:                                                                 */
9092169271Sdavidch/*   0 for success, positive value for failure.                             */
9093169271Sdavidch/****************************************************************************/
9094169271Sdavidchstatic int
9095157642Spsbce_sysctl_breakpoint(SYSCTL_HANDLER_ARGS)
9096157642Sps{
9097206268Sdavidch	int error;
9098206268Sdavidch	int result;
9099206268Sdavidch	struct bce_softc *sc;
9100157642Sps
9101206268Sdavidch	result = -1;
9102206268Sdavidch	error = sysctl_handle_int(oidp, &result, 0, req);
9103157642Sps
9104206268Sdavidch	if (error || !req->newptr)
9105206268Sdavidch		return (error);
9106157642Sps
9107206268Sdavidch	if (result == 1) {
9108206268Sdavidch		sc = (struct bce_softc *)arg1;
9109206268Sdavidch		bce_breakpoint(sc);
9110206268Sdavidch	}
9111157642Sps
9112206268Sdavidch	return error;
9113157642Sps}
9114157642Sps#endif
9115157642Sps
9116157642Sps/****************************************************************************/
9117157642Sps/* Adds any sysctl parameters for tuning or debugging purposes.             */
9118157642Sps/*                                                                          */
9119157642Sps/* Returns:                                                                 */
9120157642Sps/*   0 for success, positive value for failure.                             */
9121157642Sps/****************************************************************************/
9122157642Spsstatic void
9123157642Spsbce_add_sysctls(struct bce_softc *sc)
9124157642Sps{
9125157642Sps	struct sysctl_ctx_list *ctx;
9126157642Sps	struct sysctl_oid_list *children;
9127157642Sps
9128179771Sdavidch	DBENTER(BCE_VERBOSE_MISC);
9129179771Sdavidch
9130157642Sps	ctx = device_get_sysctl_ctx(sc->bce_dev);
9131157642Sps	children = SYSCTL_CHILDREN(device_get_sysctl_tree(sc->bce_dev));
9132157642Sps
9133157642Sps#ifdef BCE_DEBUG
9134179771Sdavidch	SYSCTL_ADD_INT(ctx, children, OID_AUTO,
9135206268Sdavidch	    "l2fhdr_error_sim_control",
9136206268Sdavidch	    CTLFLAG_RW, &l2fhdr_error_sim_control,
9137206268Sdavidch	    0, "Debug control to force l2fhdr errors");
9138189325Sdavidch
9139189325Sdavidch	SYSCTL_ADD_INT(ctx, children, OID_AUTO,
9140206268Sdavidch	    "l2fhdr_error_sim_count",
9141206268Sdavidch	    CTLFLAG_RD, &sc->l2fhdr_error_sim_count,
9142206268Sdavidch	    0, "Number of simulated l2_fhdr errors");
9143189325Sdavidch#endif
9144189325Sdavidch
9145217323Smdf	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
9146206268Sdavidch	    "l2fhdr_error_count",
9147206268Sdavidch	    CTLFLAG_RD, &sc->l2fhdr_error_count,
9148206268Sdavidch	    0, "Number of l2_fhdr errors");
9149189325Sdavidch
9150189325Sdavidch#ifdef BCE_DEBUG
9151189325Sdavidch	SYSCTL_ADD_INT(ctx, children, OID_AUTO,
9152206268Sdavidch	    "mbuf_alloc_failed_sim_control",
9153206268Sdavidch	    CTLFLAG_RW, &mbuf_alloc_failed_sim_control,
9154206268Sdavidch	    0, "Debug control to force mbuf allocation failures");
9155189325Sdavidch
9156217323Smdf	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
9157206268Sdavidch	    "mbuf_alloc_failed_sim_count",
9158206268Sdavidch	    CTLFLAG_RD, &sc->mbuf_alloc_failed_sim_count,
9159206268Sdavidch	    0, "Number of simulated mbuf cluster allocation failures");
9160189325Sdavidch#endif
9161189325Sdavidch
9162217323Smdf	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
9163206268Sdavidch	    "mbuf_alloc_failed_count",
9164206268Sdavidch	    CTLFLAG_RD, &sc->mbuf_alloc_failed_count,
9165206268Sdavidch	    0, "Number of mbuf allocation failures");
9166189325Sdavidch
9167217323Smdf	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
9168207411Sdavidch	    "mbuf_frag_count",
9169207411Sdavidch	    CTLFLAG_RD, &sc->mbuf_frag_count,
9170206268Sdavidch	    0, "Number of fragmented mbufs");
9171189325Sdavidch
9172189325Sdavidch#ifdef BCE_DEBUG
9173189325Sdavidch	SYSCTL_ADD_INT(ctx, children, OID_AUTO,
9174206268Sdavidch	    "dma_map_addr_failed_sim_control",
9175206268Sdavidch	    CTLFLAG_RW, &dma_map_addr_failed_sim_control,
9176206268Sdavidch	    0, "Debug control to force DMA mapping failures");
9177189325Sdavidch
9178189325Sdavidch	/* ToDo: Figure out how to update this value in bce_dma_map_addr(). */
9179217323Smdf	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
9180206268Sdavidch	    "dma_map_addr_failed_sim_count",
9181206268Sdavidch	    CTLFLAG_RD, &sc->dma_map_addr_failed_sim_count,
9182206268Sdavidch	    0, "Number of simulated DMA mapping failures");
9183207411Sdavidch
9184189325Sdavidch#endif
9185189325Sdavidch
9186217323Smdf	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
9187206268Sdavidch	    "dma_map_addr_rx_failed_count",
9188206268Sdavidch	    CTLFLAG_RD, &sc->dma_map_addr_rx_failed_count,
9189206268Sdavidch	    0, "Number of RX DMA mapping failures");
9190189325Sdavidch
9191217323Smdf	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
9192206268Sdavidch	    "dma_map_addr_tx_failed_count",
9193206268Sdavidch	    CTLFLAG_RD, &sc->dma_map_addr_tx_failed_count,
9194206268Sdavidch	    0, "Number of TX DMA mapping failures");
9195189325Sdavidch
9196189325Sdavidch#ifdef BCE_DEBUG
9197189325Sdavidch	SYSCTL_ADD_INT(ctx, children, OID_AUTO,
9198206268Sdavidch	    "unexpected_attention_sim_control",
9199206268Sdavidch	    CTLFLAG_RW, &unexpected_attention_sim_control,
9200206268Sdavidch	    0, "Debug control to simulate unexpected attentions");
9201189325Sdavidch
9202217323Smdf	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
9203206268Sdavidch	    "unexpected_attention_sim_count",
9204206268Sdavidch	    CTLFLAG_RW, &sc->unexpected_attention_sim_count,
9205206268Sdavidch	    0, "Number of simulated unexpected attentions");
9206189325Sdavidch#endif
9207189325Sdavidch
9208217323Smdf	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
9209206268Sdavidch	    "unexpected_attention_count",
9210206268Sdavidch	    CTLFLAG_RW, &sc->unexpected_attention_count,
9211206268Sdavidch	    0, "Number of unexpected attentions");
9212189325Sdavidch
9213189325Sdavidch#ifdef BCE_DEBUG
9214189325Sdavidch	SYSCTL_ADD_INT(ctx, children, OID_AUTO,
9215206268Sdavidch	    "debug_bootcode_running_failure",
9216206268Sdavidch	    CTLFLAG_RW, &bootcode_running_failure_sim_control,
9217206268Sdavidch	    0, "Debug control to force bootcode running failures");
9218189325Sdavidch
9219189325Sdavidch	SYSCTL_ADD_INT(ctx, children, OID_AUTO,
9220206268Sdavidch	    "rx_low_watermark",
9221206268Sdavidch	    CTLFLAG_RD, &sc->rx_low_watermark,
9222206268Sdavidch	    0, "Lowest level of free rx_bd's");
9223157642Sps
9224218423Sdavidch	SYSCTL_ADD_QUAD(ctx, children, OID_AUTO,
9225206268Sdavidch	    "rx_empty_count",
9226206268Sdavidch	    CTLFLAG_RD, &sc->rx_empty_count,
9227218423Sdavidch	    "Number of times the RX chain was empty");
9228169632Sdavidch
9229179771Sdavidch	SYSCTL_ADD_INT(ctx, children, OID_AUTO,
9230206268Sdavidch	    "tx_hi_watermark",
9231206268Sdavidch	    CTLFLAG_RD, &sc->tx_hi_watermark,
9232206268Sdavidch	    0, "Highest level of used tx_bd's");
9233157642Sps
9234218423Sdavidch	SYSCTL_ADD_QUAD(ctx, children, OID_AUTO,
9235206268Sdavidch	    "tx_full_count",
9236206268Sdavidch	    CTLFLAG_RD, &sc->tx_full_count,
9237218423Sdavidch	    "Number of times the TX chain was full");
9238169632Sdavidch
9239218423Sdavidch	SYSCTL_ADD_QUAD(ctx, children, OID_AUTO,
9240207411Sdavidch	    "tso_frames_requested",
9241207411Sdavidch	    CTLFLAG_RD, &sc->tso_frames_requested,
9242218423Sdavidch	    "Number of TSO frames requested");
9243171667Sdavidch
9244218423Sdavidch	SYSCTL_ADD_QUAD(ctx, children, OID_AUTO,
9245207411Sdavidch	    "tso_frames_completed",
9246207411Sdavidch	    CTLFLAG_RD, &sc->tso_frames_completed,
9247218423Sdavidch	    "Number of TSO frames completed");
9248207411Sdavidch
9249218423Sdavidch	SYSCTL_ADD_QUAD(ctx, children, OID_AUTO,
9250207411Sdavidch	    "tso_frames_failed",
9251207411Sdavidch	    CTLFLAG_RD, &sc->tso_frames_failed,
9252218423Sdavidch	    "Number of TSO frames failed");
9253207411Sdavidch
9254218423Sdavidch	SYSCTL_ADD_QUAD(ctx, children, OID_AUTO,
9255207411Sdavidch	    "csum_offload_ip",
9256207411Sdavidch	    CTLFLAG_RD, &sc->csum_offload_ip,
9257218423Sdavidch	    "Number of IP checksum offload frames");
9258207411Sdavidch
9259218423Sdavidch	SYSCTL_ADD_QUAD(ctx, children, OID_AUTO,
9260207411Sdavidch	    "csum_offload_tcp_udp",
9261207411Sdavidch	    CTLFLAG_RD, &sc->csum_offload_tcp_udp,
9262218423Sdavidch	    "Number of TCP/UDP checksum offload frames");
9263207411Sdavidch
9264218423Sdavidch	SYSCTL_ADD_QUAD(ctx, children, OID_AUTO,
9265207411Sdavidch	    "vlan_tagged_frames_rcvd",
9266207411Sdavidch	    CTLFLAG_RD, &sc->vlan_tagged_frames_rcvd,
9267218423Sdavidch	    "Number of VLAN tagged frames received");
9268207411Sdavidch
9269218423Sdavidch	SYSCTL_ADD_QUAD(ctx, children, OID_AUTO,
9270207411Sdavidch	    "vlan_tagged_frames_stripped",
9271207411Sdavidch	    CTLFLAG_RD, &sc->vlan_tagged_frames_stripped,
9272218423Sdavidch	    "Number of VLAN tagged frames stripped");
9273207411Sdavidch
9274218423Sdavidch	SYSCTL_ADD_QUAD(ctx, children, OID_AUTO,
9275207411Sdavidch	    "interrupts_rx",
9276207411Sdavidch	    CTLFLAG_RD, &sc->interrupts_rx,
9277218423Sdavidch	    "Number of RX interrupts");
9278171667Sdavidch
9279218423Sdavidch	SYSCTL_ADD_QUAD(ctx, children, OID_AUTO,
9280207411Sdavidch	    "interrupts_tx",
9281207411Sdavidch	    CTLFLAG_RD, &sc->interrupts_tx,
9282218423Sdavidch	    "Number of TX interrupts");
9283218423Sdavidch
9284218423Sdavidch	if (bce_hdr_split == TRUE) {
9285218423Sdavidch		SYSCTL_ADD_QUAD(ctx, children, OID_AUTO,
9286218423Sdavidch		    "split_header_frames_rcvd",
9287218423Sdavidch		    CTLFLAG_RD, &sc->split_header_frames_rcvd,
9288218423Sdavidch		    "Number of split header frames received");
9289218423Sdavidch
9290218423Sdavidch		SYSCTL_ADD_QUAD(ctx, children, OID_AUTO,
9291218423Sdavidch		    "split_header_tcp_frames_rcvd",
9292218423Sdavidch		    CTLFLAG_RD, &sc->split_header_tcp_frames_rcvd,
9293218423Sdavidch		    "Number of split header TCP frames received");
9294218423Sdavidch	}
9295218423Sdavidch
9296213489Sambrisko	SYSCTL_ADD_PROC(ctx, children, OID_AUTO,
9297213489Sambrisko	    "nvram_dump", CTLTYPE_OPAQUE | CTLFLAG_RD,
9298213489Sambrisko	    (void *)sc, 0,
9299218527Sdavidch	    bce_sysctl_nvram_dump, "S", "");
9300218423Sdavidch
9301213489Sambrisko#ifdef BCE_NVRAM_WRITE_SUPPORT
9302213489Sambrisko	SYSCTL_ADD_PROC(ctx, children, OID_AUTO,
9303213489Sambrisko	    "nvram_write", CTLTYPE_OPAQUE | CTLFLAG_WR,
9304213489Sambrisko	    (void *)sc, 0,
9305218527Sdavidch	    bce_sysctl_nvram_write, "S", "");
9306179771Sdavidch#endif
9307218423Sdavidch#endif /* BCE_DEBUG */
9308171667Sdavidch
9309218423Sdavidch	SYSCTL_ADD_QUAD(ctx, children, OID_AUTO,
9310206268Sdavidch	    "stat_IfHcInOctets",
9311206268Sdavidch	    CTLFLAG_RD, &sc->stat_IfHCInOctets,
9312206268Sdavidch	    "Bytes received");
9313157642Sps
9314218423Sdavidch	SYSCTL_ADD_QUAD(ctx, children, OID_AUTO,
9315206268Sdavidch	    "stat_IfHCInBadOctets",
9316206268Sdavidch	    CTLFLAG_RD, &sc->stat_IfHCInBadOctets,
9317206268Sdavidch	    "Bad bytes received");
9318157642Sps
9319218423Sdavidch	SYSCTL_ADD_QUAD(ctx, children, OID_AUTO,
9320206268Sdavidch	    "stat_IfHCOutOctets",
9321206268Sdavidch	    CTLFLAG_RD, &sc->stat_IfHCOutOctets,
9322206268Sdavidch	    "Bytes sent");
9323157642Sps
9324218423Sdavidch	SYSCTL_ADD_QUAD(ctx, children, OID_AUTO,
9325206268Sdavidch	    "stat_IfHCOutBadOctets",
9326206268Sdavidch	    CTLFLAG_RD, &sc->stat_IfHCOutBadOctets,
9327206268Sdavidch	    "Bad bytes sent");
9328157642Sps
9329218423Sdavidch	SYSCTL_ADD_QUAD(ctx, children, OID_AUTO,
9330206268Sdavidch	    "stat_IfHCInUcastPkts",
9331206268Sdavidch	    CTLFLAG_RD, &sc->stat_IfHCInUcastPkts,
9332206268Sdavidch	    "Unicast packets received");
9333157642Sps
9334218423Sdavidch	SYSCTL_ADD_QUAD(ctx, children, OID_AUTO,
9335206268Sdavidch	    "stat_IfHCInMulticastPkts",
9336206268Sdavidch	    CTLFLAG_RD, &sc->stat_IfHCInMulticastPkts,
9337206268Sdavidch	    "Multicast packets received");
9338157642Sps
9339218423Sdavidch	SYSCTL_ADD_QUAD(ctx, children, OID_AUTO,
9340206268Sdavidch	    "stat_IfHCInBroadcastPkts",
9341206268Sdavidch	    CTLFLAG_RD, &sc->stat_IfHCInBroadcastPkts,
9342206268Sdavidch	    "Broadcast packets received");
9343157642Sps
9344218423Sdavidch	SYSCTL_ADD_QUAD(ctx, children, OID_AUTO,
9345206268Sdavidch	    "stat_IfHCOutUcastPkts",
9346206268Sdavidch	    CTLFLAG_RD, &sc->stat_IfHCOutUcastPkts,
9347206268Sdavidch	    "Unicast packets sent");
9348157642Sps
9349218423Sdavidch	SYSCTL_ADD_QUAD(ctx, children, OID_AUTO,
9350206268Sdavidch	    "stat_IfHCOutMulticastPkts",
9351206268Sdavidch	    CTLFLAG_RD, &sc->stat_IfHCOutMulticastPkts,
9352206268Sdavidch	    "Multicast packets sent");
9353157642Sps
9354218423Sdavidch	SYSCTL_ADD_QUAD(ctx, children, OID_AUTO,
9355206268Sdavidch	    "stat_IfHCOutBroadcastPkts",
9356206268Sdavidch	    CTLFLAG_RD, &sc->stat_IfHCOutBroadcastPkts,
9357206268Sdavidch	    "Broadcast packets sent");
9358157642Sps
9359179771Sdavidch	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
9360206268Sdavidch	    "stat_emac_tx_stat_dot3statsinternalmactransmiterrors",
9361206268Sdavidch	    CTLFLAG_RD, &sc->stat_emac_tx_stat_dot3statsinternalmactransmiterrors,
9362206268Sdavidch	    0, "Internal MAC transmit errors");
9363157642Sps
9364179771Sdavidch	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
9365206268Sdavidch	    "stat_Dot3StatsCarrierSenseErrors",
9366206268Sdavidch	    CTLFLAG_RD, &sc->stat_Dot3StatsCarrierSenseErrors,
9367206268Sdavidch	    0, "Carrier sense errors");
9368157642Sps
9369179771Sdavidch	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
9370206268Sdavidch	    "stat_Dot3StatsFCSErrors",
9371206268Sdavidch	    CTLFLAG_RD, &sc->stat_Dot3StatsFCSErrors,
9372206268Sdavidch	    0, "Frame check sequence errors");
9373157642Sps
9374179771Sdavidch	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
9375206268Sdavidch	    "stat_Dot3StatsAlignmentErrors",
9376206268Sdavidch	    CTLFLAG_RD, &sc->stat_Dot3StatsAlignmentErrors,
9377206268Sdavidch	    0, "Alignment errors");
9378157642Sps
9379179771Sdavidch	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
9380206268Sdavidch	    "stat_Dot3StatsSingleCollisionFrames",
9381206268Sdavidch	    CTLFLAG_RD, &sc->stat_Dot3StatsSingleCollisionFrames,
9382206268Sdavidch	    0, "Single Collision Frames");
9383157642Sps
9384179771Sdavidch	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
9385206268Sdavidch	    "stat_Dot3StatsMultipleCollisionFrames",
9386206268Sdavidch	    CTLFLAG_RD, &sc->stat_Dot3StatsMultipleCollisionFrames,
9387206268Sdavidch	    0, "Multiple Collision Frames");
9388157642Sps
9389179771Sdavidch	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
9390206268Sdavidch	    "stat_Dot3StatsDeferredTransmissions",
9391206268Sdavidch	    CTLFLAG_RD, &sc->stat_Dot3StatsDeferredTransmissions,
9392206268Sdavidch	    0, "Deferred Transmissions");
9393157642Sps
9394179771Sdavidch	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
9395206268Sdavidch	    "stat_Dot3StatsExcessiveCollisions",
9396206268Sdavidch	    CTLFLAG_RD, &sc->stat_Dot3StatsExcessiveCollisions,
9397206268Sdavidch	    0, "Excessive Collisions");
9398157642Sps
9399179771Sdavidch	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
9400206268Sdavidch	    "stat_Dot3StatsLateCollisions",
9401206268Sdavidch	    CTLFLAG_RD, &sc->stat_Dot3StatsLateCollisions,
9402206268Sdavidch	    0, "Late Collisions");
9403157642Sps
9404179771Sdavidch	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
9405206268Sdavidch	    "stat_EtherStatsCollisions",
9406206268Sdavidch	    CTLFLAG_RD, &sc->stat_EtherStatsCollisions,
9407206268Sdavidch	    0, "Collisions");
9408157642Sps
9409179771Sdavidch	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
9410206268Sdavidch	    "stat_EtherStatsFragments",
9411206268Sdavidch	    CTLFLAG_RD, &sc->stat_EtherStatsFragments,
9412206268Sdavidch	    0, "Fragments");
9413157642Sps
9414179771Sdavidch	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
9415206268Sdavidch	    "stat_EtherStatsJabbers",
9416206268Sdavidch	    CTLFLAG_RD, &sc->stat_EtherStatsJabbers,
9417206268Sdavidch	    0, "Jabbers");
9418157642Sps
9419179771Sdavidch	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
9420206268Sdavidch	    "stat_EtherStatsUndersizePkts",
9421206268Sdavidch	    CTLFLAG_RD, &sc->stat_EtherStatsUndersizePkts,
9422206268Sdavidch	    0, "Undersize packets");
9423157642Sps
9424179771Sdavidch	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
9425206268Sdavidch	    "stat_EtherStatsOversizePkts",
9426206268Sdavidch	    CTLFLAG_RD, &sc->stat_EtherStatsOversizePkts,
9427206268Sdavidch	    0, "stat_EtherStatsOversizePkts");
9428157642Sps
9429179771Sdavidch	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
9430206268Sdavidch	    "stat_EtherStatsPktsRx64Octets",
9431206268Sdavidch	    CTLFLAG_RD, &sc->stat_EtherStatsPktsRx64Octets,
9432206268Sdavidch	    0, "Bytes received in 64 byte packets");
9433157642Sps
9434179771Sdavidch	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
9435206268Sdavidch	    "stat_EtherStatsPktsRx65Octetsto127Octets",
9436206268Sdavidch	    CTLFLAG_RD, &sc->stat_EtherStatsPktsRx65Octetsto127Octets,
9437206268Sdavidch	    0, "Bytes received in 65 to 127 byte packets");
9438157642Sps
9439179771Sdavidch	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
9440206268Sdavidch	    "stat_EtherStatsPktsRx128Octetsto255Octets",
9441206268Sdavidch	    CTLFLAG_RD, &sc->stat_EtherStatsPktsRx128Octetsto255Octets,
9442206268Sdavidch	    0, "Bytes received in 128 to 255 byte packets");
9443157642Sps
9444179771Sdavidch	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
9445206268Sdavidch	    "stat_EtherStatsPktsRx256Octetsto511Octets",
9446206268Sdavidch	    CTLFLAG_RD, &sc->stat_EtherStatsPktsRx256Octetsto511Octets,
9447206268Sdavidch	    0, "Bytes received in 256 to 511 byte packets");
9448157642Sps
9449179771Sdavidch	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
9450206268Sdavidch	    "stat_EtherStatsPktsRx512Octetsto1023Octets",
9451206268Sdavidch	    CTLFLAG_RD, &sc->stat_EtherStatsPktsRx512Octetsto1023Octets,
9452206268Sdavidch	    0, "Bytes received in 512 to 1023 byte packets");
9453157642Sps
9454179771Sdavidch	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
9455206268Sdavidch	    "stat_EtherStatsPktsRx1024Octetsto1522Octets",
9456206268Sdavidch	    CTLFLAG_RD, &sc->stat_EtherStatsPktsRx1024Octetsto1522Octets,
9457206268Sdavidch	    0, "Bytes received in 1024 t0 1522 byte packets");
9458157642Sps
9459179771Sdavidch	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
9460206268Sdavidch	    "stat_EtherStatsPktsRx1523Octetsto9022Octets",
9461206268Sdavidch	    CTLFLAG_RD, &sc->stat_EtherStatsPktsRx1523Octetsto9022Octets,
9462206268Sdavidch	    0, "Bytes received in 1523 to 9022 byte packets");
9463157642Sps
9464179771Sdavidch	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
9465206268Sdavidch	    "stat_EtherStatsPktsTx64Octets",
9466206268Sdavidch	    CTLFLAG_RD, &sc->stat_EtherStatsPktsTx64Octets,
9467206268Sdavidch	    0, "Bytes sent in 64 byte packets");
9468157642Sps
9469179771Sdavidch	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
9470206268Sdavidch	    "stat_EtherStatsPktsTx65Octetsto127Octets",
9471206268Sdavidch	    CTLFLAG_RD, &sc->stat_EtherStatsPktsTx65Octetsto127Octets,
9472206268Sdavidch	    0, "Bytes sent in 65 to 127 byte packets");
9473157642Sps
9474179771Sdavidch	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
9475206268Sdavidch	    "stat_EtherStatsPktsTx128Octetsto255Octets",
9476206268Sdavidch	    CTLFLAG_RD, &sc->stat_EtherStatsPktsTx128Octetsto255Octets,
9477206268Sdavidch	    0, "Bytes sent in 128 to 255 byte packets");
9478157642Sps
9479179771Sdavidch	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
9480206268Sdavidch	    "stat_EtherStatsPktsTx256Octetsto511Octets",
9481206268Sdavidch	    CTLFLAG_RD, &sc->stat_EtherStatsPktsTx256Octetsto511Octets,
9482206268Sdavidch	    0, "Bytes sent in 256 to 511 byte packets");
9483157642Sps
9484179771Sdavidch	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
9485206268Sdavidch	    "stat_EtherStatsPktsTx512Octetsto1023Octets",
9486206268Sdavidch	    CTLFLAG_RD, &sc->stat_EtherStatsPktsTx512Octetsto1023Octets,
9487206268Sdavidch	    0, "Bytes sent in 512 to 1023 byte packets");
9488157642Sps
9489179771Sdavidch	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
9490206268Sdavidch	    "stat_EtherStatsPktsTx1024Octetsto1522Octets",
9491206268Sdavidch	    CTLFLAG_RD, &sc->stat_EtherStatsPktsTx1024Octetsto1522Octets,
9492206268Sdavidch	    0, "Bytes sent in 1024 to 1522 byte packets");
9493157642Sps
9494179771Sdavidch	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
9495206268Sdavidch	    "stat_EtherStatsPktsTx1523Octetsto9022Octets",
9496206268Sdavidch	    CTLFLAG_RD, &sc->stat_EtherStatsPktsTx1523Octetsto9022Octets,
9497206268Sdavidch	    0, "Bytes sent in 1523 to 9022 byte packets");
9498157642Sps
9499179771Sdavidch	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
9500206268Sdavidch	    "stat_XonPauseFramesReceived",
9501206268Sdavidch	    CTLFLAG_RD, &sc->stat_XonPauseFramesReceived,
9502206268Sdavidch	    0, "XON pause frames receved");
9503157642Sps
9504179771Sdavidch	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
9505206268Sdavidch	    "stat_XoffPauseFramesReceived",
9506206268Sdavidch	    CTLFLAG_RD, &sc->stat_XoffPauseFramesReceived,
9507206268Sdavidch	    0, "XOFF pause frames received");
9508157642Sps
9509179771Sdavidch	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
9510206268Sdavidch	    "stat_OutXonSent",
9511206268Sdavidch	    CTLFLAG_RD, &sc->stat_OutXonSent,
9512206268Sdavidch	    0, "XON pause frames sent");
9513157642Sps
9514179771Sdavidch	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
9515206268Sdavidch	    "stat_OutXoffSent",
9516206268Sdavidch	    CTLFLAG_RD, &sc->stat_OutXoffSent,
9517206268Sdavidch	    0, "XOFF pause frames sent");
9518157642Sps
9519179771Sdavidch	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
9520206268Sdavidch	    "stat_FlowControlDone",
9521206268Sdavidch	    CTLFLAG_RD, &sc->stat_FlowControlDone,
9522206268Sdavidch	    0, "Flow control done");
9523157642Sps
9524179771Sdavidch	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
9525206268Sdavidch	    "stat_MacControlFramesReceived",
9526206268Sdavidch	    CTLFLAG_RD, &sc->stat_MacControlFramesReceived,
9527206268Sdavidch	    0, "MAC control frames received");
9528157642Sps
9529179771Sdavidch	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
9530206268Sdavidch	    "stat_XoffStateEntered",
9531206268Sdavidch	    CTLFLAG_RD, &sc->stat_XoffStateEntered,
9532206268Sdavidch	    0, "XOFF state entered");
9533157642Sps
9534179771Sdavidch	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
9535206268Sdavidch	    "stat_IfInFramesL2FilterDiscards",
9536206268Sdavidch	    CTLFLAG_RD, &sc->stat_IfInFramesL2FilterDiscards,
9537206268Sdavidch	    0, "Received L2 packets discarded");
9538157642Sps
9539179771Sdavidch	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
9540206268Sdavidch	    "stat_IfInRuleCheckerDiscards",
9541206268Sdavidch	    CTLFLAG_RD, &sc->stat_IfInRuleCheckerDiscards,
9542206268Sdavidch	    0, "Received packets discarded by rule");
9543157642Sps
9544179771Sdavidch	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
9545206268Sdavidch	    "stat_IfInFTQDiscards",
9546206268Sdavidch	    CTLFLAG_RD, &sc->stat_IfInFTQDiscards,
9547206268Sdavidch	    0, "Received packet FTQ discards");
9548157642Sps
9549179771Sdavidch	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
9550206268Sdavidch	    "stat_IfInMBUFDiscards",
9551206268Sdavidch	    CTLFLAG_RD, &sc->stat_IfInMBUFDiscards,
9552206268Sdavidch	    0, "Received packets discarded due to lack "
9553206268Sdavidch	    "of controller buffer memory");
9554157642Sps
9555179771Sdavidch	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
9556206268Sdavidch	    "stat_IfInRuleCheckerP4Hit",
9557206268Sdavidch	    CTLFLAG_RD, &sc->stat_IfInRuleCheckerP4Hit,
9558206268Sdavidch	    0, "Received packets rule checker hits");
9559157642Sps
9560179771Sdavidch	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
9561206268Sdavidch	    "stat_CatchupInRuleCheckerDiscards",
9562206268Sdavidch	    CTLFLAG_RD, &sc->stat_CatchupInRuleCheckerDiscards,
9563206268Sdavidch	    0, "Received packets discarded in Catchup path");
9564157642Sps
9565179771Sdavidch	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
9566206268Sdavidch	    "stat_CatchupInFTQDiscards",
9567206268Sdavidch	    CTLFLAG_RD, &sc->stat_CatchupInFTQDiscards,
9568206268Sdavidch	    0, "Received packets discarded in FTQ in Catchup path");
9569157642Sps
9570179771Sdavidch	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
9571206268Sdavidch	    "stat_CatchupInMBUFDiscards",
9572206268Sdavidch	    CTLFLAG_RD, &sc->stat_CatchupInMBUFDiscards,
9573206268Sdavidch	    0, "Received packets discarded in controller "
9574206268Sdavidch	    "buffer memory in Catchup path");
9575157642Sps
9576179771Sdavidch	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
9577206268Sdavidch	    "stat_CatchupInRuleCheckerP4Hit",
9578206268Sdavidch	    CTLFLAG_RD, &sc->stat_CatchupInRuleCheckerP4Hit,
9579206268Sdavidch	    0, "Received packets rule checker hits in Catchup path");
9580157642Sps
9581179771Sdavidch	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
9582206268Sdavidch	    "com_no_buffers",
9583206268Sdavidch	    CTLFLAG_RD, &sc->com_no_buffers,
9584206268Sdavidch	    0, "Valid packets received but no RX buffers available");
9585169271Sdavidch
9586157642Sps#ifdef BCE_DEBUG
9587157642Sps	SYSCTL_ADD_PROC(ctx, children, OID_AUTO,
9588206268Sdavidch	    "driver_state", CTLTYPE_INT | CTLFLAG_RW,
9589206268Sdavidch	    (void *)sc, 0,
9590206268Sdavidch	    bce_sysctl_driver_state, "I", "Drive state information");
9591157642Sps
9592157642Sps	SYSCTL_ADD_PROC(ctx, children, OID_AUTO,
9593206268Sdavidch	    "hw_state", CTLTYPE_INT | CTLFLAG_RW,
9594206268Sdavidch	    (void *)sc, 0,
9595206268Sdavidch	    bce_sysctl_hw_state, "I", "Hardware state information");
9596157642Sps
9597157642Sps	SYSCTL_ADD_PROC(ctx, children, OID_AUTO,
9598206268Sdavidch	    "status_block", CTLTYPE_INT | CTLFLAG_RW,
9599206268Sdavidch	    (void *)sc, 0,
9600207411Sdavidch	    bce_sysctl_status_block, "I", "Dump status block");
9601170810Sdavidch
9602170810Sdavidch	SYSCTL_ADD_PROC(ctx, children, OID_AUTO,
9603206268Sdavidch	    "stats_block", CTLTYPE_INT | CTLFLAG_RW,
9604206268Sdavidch	    (void *)sc, 0,
9605207411Sdavidch	    bce_sysctl_stats_block, "I", "Dump statistics block");
9606157642Sps
9607157642Sps	SYSCTL_ADD_PROC(ctx, children, OID_AUTO,
9608207411Sdavidch	    "stats_clear", CTLTYPE_INT | CTLFLAG_RW,
9609207411Sdavidch	    (void *)sc, 0,
9610207411Sdavidch	    bce_sysctl_stats_clear, "I", "Clear statistics block");
9611207411Sdavidch
9612207411Sdavidch	SYSCTL_ADD_PROC(ctx, children, OID_AUTO,
9613218423Sdavidch	    "shmem_state", CTLTYPE_INT | CTLFLAG_RW,
9614218423Sdavidch	    (void *)sc, 0,
9615218423Sdavidch	    bce_sysctl_shmem_state, "I", "Shared memory state information");
9616218423Sdavidch
9617218423Sdavidch	SYSCTL_ADD_PROC(ctx, children, OID_AUTO,
9618206268Sdavidch	    "bc_state", CTLTYPE_INT | CTLFLAG_RW,
9619206268Sdavidch	    (void *)sc, 0,
9620206268Sdavidch	    bce_sysctl_bc_state, "I", "Bootcode state information");
9621169271Sdavidch
9622206268Sdavidch	SYSCTL_ADD_PROC(ctx, children, OID_AUTO,
9623206268Sdavidch	    "dump_rx_bd_chain", CTLTYPE_INT | CTLFLAG_RW,
9624206268Sdavidch	    (void *)sc, 0,
9625206268Sdavidch	    bce_sysctl_dump_rx_bd_chain, "I", "Dump RX BD chain");
9626206268Sdavidch
9627206268Sdavidch	SYSCTL_ADD_PROC(ctx, children, OID_AUTO,
9628206268Sdavidch	    "dump_rx_mbuf_chain", CTLTYPE_INT | CTLFLAG_RW,
9629206268Sdavidch	    (void *)sc, 0,
9630206268Sdavidch	    bce_sysctl_dump_rx_mbuf_chain, "I", "Dump RX MBUF chain");
9631206268Sdavidch
9632206268Sdavidch	SYSCTL_ADD_PROC(ctx, children, OID_AUTO,
9633206268Sdavidch	    "dump_tx_chain", CTLTYPE_INT | CTLFLAG_RW,
9634206268Sdavidch	    (void *)sc, 0,
9635206268Sdavidch	    bce_sysctl_dump_tx_chain, "I", "Dump tx_bd chain");
9636206268Sdavidch
9637218423Sdavidch	if (bce_hdr_split == TRUE) {
9638218423Sdavidch		SYSCTL_ADD_PROC(ctx, children, OID_AUTO,
9639218423Sdavidch		    "dump_pg_chain", CTLTYPE_INT | CTLFLAG_RW,
9640218423Sdavidch		    (void *)sc, 0,
9641218423Sdavidch		    bce_sysctl_dump_pg_chain, "I", "Dump page chain");
9642218423Sdavidch	}
9643218423Sdavidch
9644169271Sdavidch	SYSCTL_ADD_PROC(ctx, children, OID_AUTO,
9645206268Sdavidch	    "dump_ctx", CTLTYPE_INT | CTLFLAG_RW,
9646206268Sdavidch	    (void *)sc, 0,
9647206268Sdavidch	    bce_sysctl_dump_ctx, "I", "Dump context memory");
9648176448Sdavidch
9649176448Sdavidch	SYSCTL_ADD_PROC(ctx, children, OID_AUTO,
9650206268Sdavidch	    "breakpoint", CTLTYPE_INT | CTLFLAG_RW,
9651206268Sdavidch	    (void *)sc, 0,
9652206268Sdavidch	    bce_sysctl_breakpoint, "I", "Driver breakpoint");
9653170392Sdavidch
9654179771Sdavidch	SYSCTL_ADD_PROC(ctx, children, OID_AUTO,
9655206268Sdavidch	    "reg_read", CTLTYPE_INT | CTLFLAG_RW,
9656206268Sdavidch	    (void *)sc, 0,
9657206268Sdavidch	    bce_sysctl_reg_read, "I", "Register read");
9658169271Sdavidch
9659179771Sdavidch	SYSCTL_ADD_PROC(ctx, children, OID_AUTO,
9660206268Sdavidch	    "nvram_read", CTLTYPE_INT | CTLFLAG_RW,
9661206268Sdavidch	    (void *)sc, 0,
9662206268Sdavidch	    bce_sysctl_nvram_read, "I", "NVRAM read");
9663179771Sdavidch
9664179771Sdavidch	SYSCTL_ADD_PROC(ctx, children, OID_AUTO,
9665206268Sdavidch	    "phy_read", CTLTYPE_INT | CTLFLAG_RW,
9666206268Sdavidch	    (void *)sc, 0,
9667206268Sdavidch	    bce_sysctl_phy_read, "I", "PHY register read");
9668169632Sdavidch
9669157642Sps#endif
9670157642Sps
9671179771Sdavidch	DBEXIT(BCE_VERBOSE_MISC);
9672157642Sps}
9673157642Sps
9674157642Sps
9675157642Sps/****************************************************************************/
9676157642Sps/* BCE Debug Routines                                                       */
9677157642Sps/****************************************************************************/
9678157642Sps#ifdef BCE_DEBUG
9679170392Sdavidch
9680169632Sdavidch/****************************************************************************/
9681169632Sdavidch/* Freezes the controller to allow for a cohesive state dump.               */
9682169632Sdavidch/*                                                                          */
9683169632Sdavidch/* Returns:                                                                 */
9684169632Sdavidch/*   Nothing.                                                               */
9685169632Sdavidch/****************************************************************************/
9686205300Sdavidchstatic __attribute__ ((noinline)) void
9687169632Sdavidchbce_freeze_controller(struct bce_softc *sc)
9688169632Sdavidch{
9689169632Sdavidch	u32 val;
9690170392Sdavidch	val = REG_RD(sc, BCE_MISC_COMMAND);
9691170392Sdavidch	val |= BCE_MISC_COMMAND_DISABLE_ALL;
9692169632Sdavidch	REG_WR(sc, BCE_MISC_COMMAND, val);
9693170392Sdavidch}
9694157642Sps
9695170392Sdavidch
9696157642Sps/****************************************************************************/
9697170392Sdavidch/* Unfreezes the controller after a freeze operation.  This may not always  */
9698169632Sdavidch/* work and the controller will require a reset!                            */
9699169632Sdavidch/*                                                                          */
9700169632Sdavidch/* Returns:                                                                 */
9701169632Sdavidch/*   Nothing.                                                               */
9702169632Sdavidch/****************************************************************************/
9703205300Sdavidchstatic __attribute__ ((noinline)) void
9704169632Sdavidchbce_unfreeze_controller(struct bce_softc *sc)
9705169632Sdavidch{
9706169632Sdavidch	u32 val;
9707170392Sdavidch	val = REG_RD(sc, BCE_MISC_COMMAND);
9708170392Sdavidch	val |= BCE_MISC_COMMAND_ENABLE_ALL;
9709169632Sdavidch	REG_WR(sc, BCE_MISC_COMMAND, val);
9710170392Sdavidch}
9711170392Sdavidch
9712182293Sdavidch
9713169632Sdavidch/****************************************************************************/
9714182293Sdavidch/* Prints out Ethernet frame information from an mbuf.                      */
9715182293Sdavidch/*                                                                          */
9716182293Sdavidch/* Partially decode an Ethernet frame to look at some important headers.    */
9717182293Sdavidch/*                                                                          */
9718182293Sdavidch/* Returns:                                                                 */
9719182293Sdavidch/*   Nothing.                                                               */
9720182293Sdavidch/****************************************************************************/
9721205300Sdavidchstatic __attribute__ ((noinline)) void
9722182293Sdavidchbce_dump_enet(struct bce_softc *sc, struct mbuf *m)
9723182293Sdavidch{
9724182293Sdavidch	struct ether_vlan_header *eh;
9725182293Sdavidch	u16 etype;
9726182293Sdavidch	int ehlen;
9727182293Sdavidch	struct ip *ip;
9728182293Sdavidch	struct tcphdr *th;
9729182293Sdavidch	struct udphdr *uh;
9730182293Sdavidch	struct arphdr *ah;
9731182293Sdavidch
9732206268Sdavidch	BCE_PRINTF(
9733206268Sdavidch	    "-----------------------------"
9734206268Sdavidch	    " Frame Decode "
9735206268Sdavidch	    "-----------------------------\n");
9736182293Sdavidch
9737182293Sdavidch	eh = mtod(m, struct ether_vlan_header *);
9738182293Sdavidch
9739182293Sdavidch	/* Handle VLAN encapsulation if present. */
9740182293Sdavidch	if (eh->evl_encap_proto == htons(ETHERTYPE_VLAN)) {
9741182293Sdavidch		etype = ntohs(eh->evl_proto);
9742182293Sdavidch		ehlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN;
9743182293Sdavidch	} else {
9744182293Sdavidch		etype = ntohs(eh->evl_encap_proto);
9745182293Sdavidch		ehlen = ETHER_HDR_LEN;
9746182293Sdavidch	}
9747182293Sdavidch
9748182293Sdavidch	/* ToDo: Add VLAN output. */
9749182293Sdavidch	BCE_PRINTF("enet: dest = %6D, src = %6D, type = 0x%04X, hlen = %d\n",
9750206268Sdavidch	    eh->evl_dhost, ":", eh->evl_shost, ":", etype, ehlen);
9751182293Sdavidch
9752182293Sdavidch	switch (etype) {
9753206268Sdavidch	case ETHERTYPE_IP:
9754206268Sdavidch		ip = (struct ip *)(m->m_data + ehlen);
9755206268Sdavidch		BCE_PRINTF("--ip: dest = 0x%08X , src = 0x%08X, "
9756206268Sdavidch		    "len = %d bytes, protocol = 0x%02X, xsum = 0x%04X\n",
9757206268Sdavidch		    ntohl(ip->ip_dst.s_addr), ntohl(ip->ip_src.s_addr),
9758206268Sdavidch		    ntohs(ip->ip_len), ip->ip_p, ntohs(ip->ip_sum));
9759182293Sdavidch
9760206268Sdavidch		switch (ip->ip_p) {
9761206268Sdavidch		case IPPROTO_TCP:
9762206268Sdavidch			th = (struct tcphdr *)((caddr_t)ip + (ip->ip_hl << 2));
9763207411Sdavidch			BCE_PRINTF("-tcp: dest = %d, src = %d, hlen = "
9764207411Sdavidch			    "%d bytes, flags = 0x%b, csum = 0x%04X\n",
9765207411Sdavidch			    ntohs(th->th_dport), ntohs(th->th_sport),
9766207411Sdavidch			    (th->th_off << 2), th->th_flags,
9767206268Sdavidch			    "\20\10CWR\07ECE\06URG\05ACK\04PSH\03RST"
9768206268Sdavidch			    "\02SYN\01FIN", ntohs(th->th_sum));
9769182293Sdavidch			break;
9770206268Sdavidch		case IPPROTO_UDP:
9771206268Sdavidch			uh = (struct udphdr *)((caddr_t)ip + (ip->ip_hl << 2));
9772206268Sdavidch			BCE_PRINTF("-udp: dest = %d, src = %d, len = %d "
9773207411Sdavidch			    "bytes, csum = 0x%04X\n", ntohs(uh->uh_dport),
9774207411Sdavidch			    ntohs(uh->uh_sport), ntohs(uh->uh_ulen),
9775206268Sdavidch			    ntohs(uh->uh_sum));
9776182293Sdavidch			break;
9777206268Sdavidch		case IPPROTO_ICMP:
9778206268Sdavidch			BCE_PRINTF("icmp:\n");
9779206268Sdavidch			break;
9780206268Sdavidch		default:
9781206268Sdavidch			BCE_PRINTF("----: Other IP protocol.\n");
9782182293Sdavidch			}
9783206268Sdavidch		break;
9784206268Sdavidch	case ETHERTYPE_IPV6:
9785206268Sdavidch		BCE_PRINTF("ipv6: No decode supported.\n");
9786206268Sdavidch		break;
9787206268Sdavidch	case ETHERTYPE_ARP:
9788206268Sdavidch		BCE_PRINTF("-arp: ");
9789206268Sdavidch		ah = (struct arphdr *) (m->m_data + ehlen);
9790206268Sdavidch		switch (ntohs(ah->ar_op)) {
9791206268Sdavidch		case ARPOP_REVREQUEST:
9792206268Sdavidch			printf("reverse ARP request\n");
9793182293Sdavidch			break;
9794206268Sdavidch		case ARPOP_REVREPLY:
9795206268Sdavidch			printf("reverse ARP reply\n");
9796206268Sdavidch			break;
9797206268Sdavidch		case ARPOP_REQUEST:
9798206268Sdavidch			printf("ARP request\n");
9799206268Sdavidch			break;
9800206268Sdavidch		case ARPOP_REPLY:
9801206268Sdavidch			printf("ARP reply\n");
9802206268Sdavidch			break;
9803182293Sdavidch		default:
9804206268Sdavidch			printf("other ARP operation\n");
9805206268Sdavidch		}
9806206268Sdavidch		break;
9807206268Sdavidch	default:
9808206268Sdavidch		BCE_PRINTF("----: Other protocol.\n");
9809182293Sdavidch	}
9810182293Sdavidch
9811182293Sdavidch	BCE_PRINTF(
9812182293Sdavidch		"-----------------------------"
9813182293Sdavidch		"--------------"
9814182293Sdavidch		"-----------------------------\n");
9815182293Sdavidch}
9816182293Sdavidch
9817182293Sdavidch
9818182293Sdavidch/****************************************************************************/
9819157642Sps/* Prints out information about an mbuf.                                    */
9820157642Sps/*                                                                          */
9821157642Sps/* Returns:                                                                 */
9822157642Sps/*   Nothing.                                                               */
9823157642Sps/****************************************************************************/
9824179771Sdavidchstatic __attribute__ ((noinline)) void
9825157642Spsbce_dump_mbuf(struct bce_softc *sc, struct mbuf *m)
9826157642Sps{
9827157642Sps	struct mbuf *mp = m;
9828157642Sps
9829157642Sps	if (m == NULL) {
9830169632Sdavidch		BCE_PRINTF("mbuf: null pointer\n");
9831157642Sps		return;
9832157642Sps	}
9833157642Sps
9834157642Sps	while (mp) {
9835206268Sdavidch		BCE_PRINTF("mbuf: %p, m_len = %d, m_flags = 0x%b, "
9836206268Sdavidch		    "m_data = %p\n", mp, mp->m_len, mp->m_flags,
9837206268Sdavidch		    "\20\1M_EXT\2M_PKTHDR\3M_EOR\4M_RDONLY", mp->m_data);
9838157642Sps
9839170392Sdavidch		if (mp->m_flags & M_PKTHDR) {
9840206268Sdavidch			BCE_PRINTF("- m_pkthdr: len = %d, flags = 0x%b, "
9841207411Sdavidch			    "csum_flags = %b\n", mp->m_pkthdr.len,
9842254516Sandre			    mp->m_flags, M_FLAG_PRINTF,
9843271005Sglebius			    mp->m_pkthdr.csum_flags, CSUM_BITS);
9844170392Sdavidch		}
9845169632Sdavidch
9846157642Sps		if (mp->m_flags & M_EXT) {
9847179771Sdavidch			BCE_PRINTF("- m_ext: %p, ext_size = %d, type = ",
9848206268Sdavidch			    mp->m_ext.ext_buf, mp->m_ext.ext_size);
9849170392Sdavidch			switch (mp->m_ext.ext_type) {
9850206268Sdavidch			case EXT_CLUSTER:
9851206268Sdavidch				printf("EXT_CLUSTER\n"); break;
9852206268Sdavidch			case EXT_SFBUF:
9853206268Sdavidch				printf("EXT_SFBUF\n"); break;
9854206268Sdavidch			case EXT_JUMBO9:
9855206268Sdavidch				printf("EXT_JUMBO9\n"); break;
9856206268Sdavidch			case EXT_JUMBO16:
9857206268Sdavidch				printf("EXT_JUMBO16\n"); break;
9858206268Sdavidch			case EXT_PACKET:
9859206268Sdavidch				printf("EXT_PACKET\n"); break;
9860206268Sdavidch			case EXT_MBUF:
9861206268Sdavidch				printf("EXT_MBUF\n"); break;
9862206268Sdavidch			case EXT_NET_DRV:
9863206268Sdavidch				printf("EXT_NET_DRV\n"); break;
9864206268Sdavidch			case EXT_MOD_TYPE:
9865206268Sdavidch				printf("EXT_MDD_TYPE\n"); break;
9866206268Sdavidch			case EXT_DISPOSABLE:
9867206268Sdavidch				printf("EXT_DISPOSABLE\n"); break;
9868206268Sdavidch			case EXT_EXTREF:
9869206268Sdavidch				printf("EXT_EXTREF\n"); break;
9870207411Sdavidch			default:
9871206268Sdavidch				printf("UNKNOWN\n");
9872170392Sdavidch			}
9873157642Sps		}
9874157642Sps
9875157642Sps		mp = mp->m_next;
9876157642Sps	}
9877157642Sps}
9878157642Sps
9879157642Sps
9880157642Sps/****************************************************************************/
9881157642Sps/* Prints out the mbufs in the TX mbuf chain.                               */
9882157642Sps/*                                                                          */
9883157642Sps/* Returns:                                                                 */
9884157642Sps/*   Nothing.                                                               */
9885157642Sps/****************************************************************************/
9886179771Sdavidchstatic __attribute__ ((noinline)) void
9887176448Sdavidchbce_dump_tx_mbuf_chain(struct bce_softc *sc, u16 chain_prod, int count)
9888157642Sps{
9889157642Sps	struct mbuf *m;
9890157642Sps
9891169271Sdavidch	BCE_PRINTF(
9892157642Sps		"----------------------------"
9893157642Sps		"  tx mbuf data  "
9894157642Sps		"----------------------------\n");
9895157642Sps
9896157642Sps	for (int i = 0; i < count; i++) {
9897157642Sps	 	m = sc->tx_mbuf_ptr[chain_prod];
9898176448Sdavidch		BCE_PRINTF("txmbuf[0x%04X]\n", chain_prod);
9899157642Sps		bce_dump_mbuf(sc, m);
9900157642Sps		chain_prod = TX_CHAIN_IDX(NEXT_TX_BD(chain_prod));
9901157642Sps	}
9902157642Sps
9903169271Sdavidch	BCE_PRINTF(
9904157642Sps		"----------------------------"
9905157642Sps		"----------------"
9906157642Sps		"----------------------------\n");
9907157642Sps}
9908157642Sps
9909157642Sps
9910169271Sdavidch/****************************************************************************/
9911169271Sdavidch/* Prints out the mbufs in the RX mbuf chain.                               */
9912169271Sdavidch/*                                                                          */
9913169271Sdavidch/* Returns:                                                                 */
9914169271Sdavidch/*   Nothing.                                                               */
9915169271Sdavidch/****************************************************************************/
9916179771Sdavidchstatic __attribute__ ((noinline)) void
9917176448Sdavidchbce_dump_rx_mbuf_chain(struct bce_softc *sc, u16 chain_prod, int count)
9918157642Sps{
9919157642Sps	struct mbuf *m;
9920157642Sps
9921169271Sdavidch	BCE_PRINTF(
9922157642Sps		"----------------------------"
9923157642Sps		"  rx mbuf data  "
9924157642Sps		"----------------------------\n");
9925157642Sps
9926157642Sps	for (int i = 0; i < count; i++) {
9927157642Sps	 	m = sc->rx_mbuf_ptr[chain_prod];
9928169271Sdavidch		BCE_PRINTF("rxmbuf[0x%04X]\n", chain_prod);
9929157642Sps		bce_dump_mbuf(sc, m);
9930157642Sps		chain_prod = RX_CHAIN_IDX(NEXT_RX_BD(chain_prod));
9931157642Sps	}
9932157642Sps
9933157642Sps
9934169271Sdavidch	BCE_PRINTF(
9935157642Sps		"----------------------------"
9936157642Sps		"----------------"
9937157642Sps		"----------------------------\n");
9938157642Sps}
9939157642Sps
9940157642Sps
9941169271Sdavidch/****************************************************************************/
9942176448Sdavidch/* Prints out the mbufs in the mbuf page chain.                             */
9943176448Sdavidch/*                                                                          */
9944176448Sdavidch/* Returns:                                                                 */
9945176448Sdavidch/*   Nothing.                                                               */
9946176448Sdavidch/****************************************************************************/
9947179771Sdavidchstatic __attribute__ ((noinline)) void
9948176448Sdavidchbce_dump_pg_mbuf_chain(struct bce_softc *sc, u16 chain_prod, int count)
9949176448Sdavidch{
9950176448Sdavidch	struct mbuf *m;
9951176448Sdavidch
9952176448Sdavidch	BCE_PRINTF(
9953176448Sdavidch		"----------------------------"
9954176448Sdavidch		"  pg mbuf data  "
9955176448Sdavidch		"----------------------------\n");
9956176448Sdavidch
9957176448Sdavidch	for (int i = 0; i < count; i++) {
9958176448Sdavidch	 	m = sc->pg_mbuf_ptr[chain_prod];
9959176448Sdavidch		BCE_PRINTF("pgmbuf[0x%04X]\n", chain_prod);
9960176448Sdavidch		bce_dump_mbuf(sc, m);
9961176448Sdavidch		chain_prod = PG_CHAIN_IDX(NEXT_PG_BD(chain_prod));
9962176448Sdavidch	}
9963176448Sdavidch
9964176448Sdavidch
9965176448Sdavidch	BCE_PRINTF(
9966176448Sdavidch		"----------------------------"
9967176448Sdavidch		"----------------"
9968176448Sdavidch		"----------------------------\n");
9969179771Sdavidch}
9970176448Sdavidch
9971176448Sdavidch
9972176448Sdavidch/****************************************************************************/
9973169271Sdavidch/* Prints out a tx_bd structure.                                            */
9974169271Sdavidch/*                                                                          */
9975169271Sdavidch/* Returns:                                                                 */
9976169271Sdavidch/*   Nothing.                                                               */
9977169271Sdavidch/****************************************************************************/
9978179771Sdavidchstatic __attribute__ ((noinline)) void
9979157642Spsbce_dump_txbd(struct bce_softc *sc, int idx, struct tx_bd *txbd)
9980157642Sps{
9981206268Sdavidch	int i = 0;
9982205300Sdavidch
9983218423Sdavidch	if (idx > MAX_TX_BD_ALLOC)
9984157642Sps		/* Index out of range. */
9985169271Sdavidch		BCE_PRINTF("tx_bd[0x%04X]: Invalid tx_bd index!\n", idx);
9986157642Sps	else if ((idx & USABLE_TX_BD_PER_PAGE) == USABLE_TX_BD_PER_PAGE)
9987157642Sps		/* TX Chain page pointer. */
9988206268Sdavidch		BCE_PRINTF("tx_bd[0x%04X]: haddr = 0x%08X:%08X, chain page "
9989207411Sdavidch		    "pointer\n", idx, txbd->tx_bd_haddr_hi,
9990206268Sdavidch		    txbd->tx_bd_haddr_lo);
9991169271Sdavidch	else {
9992205300Sdavidch		/* Normal tx_bd entry. */
9993206268Sdavidch		BCE_PRINTF("tx_bd[0x%04X]: haddr = 0x%08X:%08X, "
9994206268Sdavidch		    "mss_nbytes = 0x%08X, vlan tag = 0x%04X, flags = "
9995207411Sdavidch		    "0x%04X (", idx, txbd->tx_bd_haddr_hi,
9996207411Sdavidch		    txbd->tx_bd_haddr_lo, txbd->tx_bd_mss_nbytes,
9997206268Sdavidch		    txbd->tx_bd_vlan_tag, txbd->tx_bd_flags);
9998170392Sdavidch
9999205300Sdavidch		if (txbd->tx_bd_flags & TX_BD_FLAGS_CONN_FAULT) {
10000207411Sdavidch			if (i>0)
10001207411Sdavidch				printf("|");
10002207411Sdavidch			printf("CONN_FAULT");
10003206268Sdavidch			i++;
10004206268Sdavidch		}
10005170392Sdavidch
10006205300Sdavidch		if (txbd->tx_bd_flags & TX_BD_FLAGS_TCP_UDP_CKSUM) {
10007207411Sdavidch			if (i>0)
10008207411Sdavidch				printf("|");
10009207411Sdavidch			printf("TCP_UDP_CKSUM");
10010206268Sdavidch			i++;
10011206268Sdavidch		}
10012170392Sdavidch
10013206268Sdavidch		if (txbd->tx_bd_flags & TX_BD_FLAGS_IP_CKSUM) {
10014207411Sdavidch			if (i>0)
10015207411Sdavidch				printf("|");
10016207411Sdavidch			printf("IP_CKSUM");
10017206268Sdavidch			i++;
10018206268Sdavidch		}
10019170392Sdavidch
10020205300Sdavidch		if (txbd->tx_bd_flags & TX_BD_FLAGS_VLAN_TAG) {
10021207411Sdavidch			if (i>0)
10022207411Sdavidch				printf("|");
10023207411Sdavidch			printf("VLAN");
10024206268Sdavidch			i++;
10025206268Sdavidch		}
10026170392Sdavidch
10027205300Sdavidch		if (txbd->tx_bd_flags & TX_BD_FLAGS_COAL_NOW) {
10028207411Sdavidch			if (i>0)
10029207411Sdavidch				printf("|");
10030207411Sdavidch			printf("COAL_NOW");
10031206268Sdavidch			i++;
10032206268Sdavidch		}
10033170392Sdavidch
10034206268Sdavidch		if (txbd->tx_bd_flags & TX_BD_FLAGS_DONT_GEN_CRC) {
10035207411Sdavidch			if (i>0)
10036207411Sdavidch				printf("|");
10037207411Sdavidch			printf("DONT_GEN_CRC");
10038206268Sdavidch			i++;
10039206268Sdavidch		}
10040170392Sdavidch
10041206268Sdavidch		if (txbd->tx_bd_flags & TX_BD_FLAGS_START) {
10042207411Sdavidch			if (i>0)
10043207411Sdavidch				printf("|");
10044207411Sdavidch			printf("START");
10045206268Sdavidch			i++;
10046206268Sdavidch		}
10047170392Sdavidch
10048205300Sdavidch		if (txbd->tx_bd_flags & TX_BD_FLAGS_END) {
10049207411Sdavidch			if (i>0)
10050207411Sdavidch				printf("|");
10051207411Sdavidch			printf("END");
10052206268Sdavidch			i++;
10053206268Sdavidch		}
10054170392Sdavidch
10055205300Sdavidch		if (txbd->tx_bd_flags & TX_BD_FLAGS_SW_LSO) {
10056207411Sdavidch			if (i>0)
10057207411Sdavidch				printf("|");
10058207411Sdavidch			printf("LSO");
10059206268Sdavidch			i++;
10060206268Sdavidch		}
10061170392Sdavidch
10062206268Sdavidch		if (txbd->tx_bd_flags & TX_BD_FLAGS_SW_OPTION_WORD) {
10063207411Sdavidch			if (i>0)
10064207411Sdavidch				printf("|");
10065207411Sdavidch			printf("SW_OPTION=%d", ((txbd->tx_bd_flags &
10066206268Sdavidch			    TX_BD_FLAGS_SW_OPTION_WORD) >> 8)); i++;
10067206268Sdavidch		}
10068170392Sdavidch
10069205300Sdavidch		if (txbd->tx_bd_flags & TX_BD_FLAGS_SW_FLAGS) {
10070207411Sdavidch			if (i>0)
10071207411Sdavidch				printf("|");
10072207411Sdavidch			printf("SW_FLAGS");
10073206268Sdavidch			i++;
10074206268Sdavidch		}
10075170392Sdavidch
10076205300Sdavidch		if (txbd->tx_bd_flags & TX_BD_FLAGS_SW_SNAP) {
10077207411Sdavidch			if (i>0)
10078207411Sdavidch				printf("|");
10079206268Sdavidch			printf("SNAP)");
10080206268Sdavidch		} else {
10081206268Sdavidch			printf(")\n");
10082206268Sdavidch		}
10083206268Sdavidch	}
10084157642Sps}
10085157642Sps
10086157642Sps
10087169271Sdavidch/****************************************************************************/
10088169271Sdavidch/* Prints out a rx_bd structure.                                            */
10089169271Sdavidch/*                                                                          */
10090169271Sdavidch/* Returns:                                                                 */
10091169271Sdavidch/*   Nothing.                                                               */
10092169271Sdavidch/****************************************************************************/
10093179771Sdavidchstatic __attribute__ ((noinline)) void
10094157642Spsbce_dump_rxbd(struct bce_softc *sc, int idx, struct rx_bd *rxbd)
10095157642Sps{
10096218423Sdavidch	if (idx > MAX_RX_BD_ALLOC)
10097157642Sps		/* Index out of range. */
10098169271Sdavidch		BCE_PRINTF("rx_bd[0x%04X]: Invalid rx_bd index!\n", idx);
10099157642Sps	else if ((idx & USABLE_RX_BD_PER_PAGE) == USABLE_RX_BD_PER_PAGE)
10100176448Sdavidch		/* RX Chain page pointer. */
10101206268Sdavidch		BCE_PRINTF("rx_bd[0x%04X]: haddr = 0x%08X:%08X, chain page "
10102207411Sdavidch		    "pointer\n", idx, rxbd->rx_bd_haddr_hi,
10103206268Sdavidch		    rxbd->rx_bd_haddr_lo);
10104157642Sps	else
10105176448Sdavidch		/* Normal rx_bd entry. */
10106206268Sdavidch		BCE_PRINTF("rx_bd[0x%04X]: haddr = 0x%08X:%08X, nbytes = "
10107207411Sdavidch		    "0x%08X, flags = 0x%08X\n", idx, rxbd->rx_bd_haddr_hi,
10108207411Sdavidch		    rxbd->rx_bd_haddr_lo, rxbd->rx_bd_len,
10109206268Sdavidch		    rxbd->rx_bd_flags);
10110157642Sps}
10111157642Sps
10112157642Sps
10113169271Sdavidch/****************************************************************************/
10114176448Sdavidch/* Prints out a rx_bd structure in the page chain.                          */
10115176448Sdavidch/*                                                                          */
10116176448Sdavidch/* Returns:                                                                 */
10117176448Sdavidch/*   Nothing.                                                               */
10118176448Sdavidch/****************************************************************************/
10119179771Sdavidchstatic __attribute__ ((noinline)) void
10120176448Sdavidchbce_dump_pgbd(struct bce_softc *sc, int idx, struct rx_bd *pgbd)
10121176448Sdavidch{
10122218423Sdavidch	if (idx > MAX_PG_BD_ALLOC)
10123176448Sdavidch		/* Index out of range. */
10124176448Sdavidch		BCE_PRINTF("pg_bd[0x%04X]: Invalid pg_bd index!\n", idx);
10125176448Sdavidch	else if ((idx & USABLE_PG_BD_PER_PAGE) == USABLE_PG_BD_PER_PAGE)
10126176448Sdavidch		/* Page Chain page pointer. */
10127179771Sdavidch		BCE_PRINTF("px_bd[0x%04X]: haddr = 0x%08X:%08X, chain page pointer\n",
10128176448Sdavidch			idx, pgbd->rx_bd_haddr_hi, pgbd->rx_bd_haddr_lo);
10129176448Sdavidch	else
10130176448Sdavidch		/* Normal rx_bd entry. */
10131176448Sdavidch		BCE_PRINTF("pg_bd[0x%04X]: haddr = 0x%08X:%08X, nbytes = 0x%08X, "
10132179771Sdavidch			"flags = 0x%08X\n", idx,
10133176448Sdavidch			pgbd->rx_bd_haddr_hi, pgbd->rx_bd_haddr_lo,
10134176448Sdavidch			pgbd->rx_bd_len, pgbd->rx_bd_flags);
10135179771Sdavidch}
10136176448Sdavidch
10137176448Sdavidch
10138176448Sdavidch/****************************************************************************/
10139170810Sdavidch/* Prints out a l2_fhdr structure.                                          */
10140169271Sdavidch/*                                                                          */
10141169271Sdavidch/* Returns:                                                                 */
10142169271Sdavidch/*   Nothing.                                                               */
10143169271Sdavidch/****************************************************************************/
10144179771Sdavidchstatic __attribute__ ((noinline)) void
10145157642Spsbce_dump_l2fhdr(struct bce_softc *sc, int idx, struct l2_fhdr *l2fhdr)
10146157642Sps{
10147176448Sdavidch	BCE_PRINTF("l2_fhdr[0x%04X]: status = 0x%b, "
10148176448Sdavidch		"pkt_len = %d, vlan = 0x%04x, ip_xsum/hdr_len = 0x%04X, "
10149157642Sps		"tcp_udp_xsum = 0x%04X\n", idx,
10150179771Sdavidch		l2fhdr->l2_fhdr_status, BCE_L2FHDR_PRINTFB,
10151179771Sdavidch		l2fhdr->l2_fhdr_pkt_len, l2fhdr->l2_fhdr_vlan_tag,
10152176448Sdavidch		l2fhdr->l2_fhdr_ip_xsum, l2fhdr->l2_fhdr_tcp_udp_xsum);
10153157642Sps}
10154157642Sps
10155157642Sps
10156169271Sdavidch/****************************************************************************/
10157179771Sdavidch/* Prints out context memory info.  (Only useful for CID 0 to 16.)          */
10158176448Sdavidch/*                                                                          */
10159176448Sdavidch/* Returns:                                                                 */
10160176448Sdavidch/*   Nothing.                                                               */
10161176448Sdavidch/****************************************************************************/
10162179771Sdavidchstatic __attribute__ ((noinline)) void
10163176448Sdavidchbce_dump_ctx(struct bce_softc *sc, u16 cid)
10164176448Sdavidch{
10165206268Sdavidch	if (cid > TX_CID) {
10166206268Sdavidch		BCE_PRINTF(" Unknown CID\n");
10167206268Sdavidch		return;
10168206268Sdavidch	}
10169178132Sdavidch
10170206268Sdavidch	BCE_PRINTF(
10171206268Sdavidch	    "----------------------------"
10172206268Sdavidch	    "    CTX Data    "
10173206268Sdavidch	    "----------------------------\n");
10174182293Sdavidch
10175206268Sdavidch	BCE_PRINTF("     0x%04X - (CID) Context ID\n", cid);
10176176448Sdavidch
10177206268Sdavidch	if (cid == RX_CID) {
10178206268Sdavidch		BCE_PRINTF(" 0x%08X - (L2CTX_RX_HOST_BDIDX) host rx "
10179206268Sdavidch		   "producer index\n",
10180206268Sdavidch		    CTX_RD(sc, GET_CID_ADDR(cid), BCE_L2CTX_RX_HOST_BDIDX));
10181206268Sdavidch		BCE_PRINTF(" 0x%08X - (L2CTX_RX_HOST_BSEQ) host "
10182206268Sdavidch		    "byte sequence\n", CTX_RD(sc, GET_CID_ADDR(cid),
10183206268Sdavidch		    BCE_L2CTX_RX_HOST_BSEQ));
10184206268Sdavidch		BCE_PRINTF(" 0x%08X - (L2CTX_RX_NX_BSEQ) h/w byte sequence\n",
10185206268Sdavidch		    CTX_RD(sc, GET_CID_ADDR(cid), BCE_L2CTX_RX_NX_BSEQ));
10186206268Sdavidch		BCE_PRINTF(" 0x%08X - (L2CTX_RX_NX_BDHADDR_HI) h/w buffer "
10187206268Sdavidch		    "descriptor address\n",
10188206268Sdavidch 		    CTX_RD(sc, GET_CID_ADDR(cid), BCE_L2CTX_RX_NX_BDHADDR_HI));
10189206268Sdavidch		BCE_PRINTF(" 0x%08X - (L2CTX_RX_NX_BDHADDR_LO) h/w buffer "
10190206268Sdavidch		    "descriptor address\n",
10191206268Sdavidch		    CTX_RD(sc, GET_CID_ADDR(cid), BCE_L2CTX_RX_NX_BDHADDR_LO));
10192206268Sdavidch		BCE_PRINTF(" 0x%08X - (L2CTX_RX_NX_BDIDX) h/w rx consumer "
10193206268Sdavidch		    "index\n", CTX_RD(sc, GET_CID_ADDR(cid),
10194206268Sdavidch		    BCE_L2CTX_RX_NX_BDIDX));
10195206268Sdavidch		BCE_PRINTF(" 0x%08X - (L2CTX_RX_HOST_PG_BDIDX) host page "
10196207411Sdavidch		    "producer index\n", CTX_RD(sc, GET_CID_ADDR(cid),
10197206268Sdavidch		    BCE_L2CTX_RX_HOST_PG_BDIDX));
10198206268Sdavidch		BCE_PRINTF(" 0x%08X - (L2CTX_RX_PG_BUF_SIZE) host rx_bd/page "
10199207411Sdavidch		    "buffer size\n", CTX_RD(sc, GET_CID_ADDR(cid),
10200206268Sdavidch		    BCE_L2CTX_RX_PG_BUF_SIZE));
10201206268Sdavidch		BCE_PRINTF(" 0x%08X - (L2CTX_RX_NX_PG_BDHADDR_HI) h/w page "
10202207411Sdavidch		    "chain address\n", CTX_RD(sc, GET_CID_ADDR(cid),
10203206268Sdavidch		    BCE_L2CTX_RX_NX_PG_BDHADDR_HI));
10204206268Sdavidch		BCE_PRINTF(" 0x%08X - (L2CTX_RX_NX_PG_BDHADDR_LO) h/w page "
10205207411Sdavidch		    "chain address\n", CTX_RD(sc, GET_CID_ADDR(cid),
10206206268Sdavidch		    BCE_L2CTX_RX_NX_PG_BDHADDR_LO));
10207206268Sdavidch		BCE_PRINTF(" 0x%08X - (L2CTX_RX_NX_PG_BDIDX) h/w page "
10208207411Sdavidch		    "consumer index\n",	CTX_RD(sc, GET_CID_ADDR(cid),
10209206268Sdavidch		    BCE_L2CTX_RX_NX_PG_BDIDX));
10210206268Sdavidch	} else if (cid == TX_CID) {
10211226123Syongari		if (BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5709) {
10212206268Sdavidch			BCE_PRINTF(" 0x%08X - (L2CTX_TX_TYPE_XI) ctx type\n",
10213207411Sdavidch			    CTX_RD(sc, GET_CID_ADDR(cid),
10214206268Sdavidch			    BCE_L2CTX_TX_TYPE_XI));
10215206268Sdavidch			BCE_PRINTF(" 0x%08X - (L2CTX_CMD_TX_TYPE_XI) ctx "
10216207411Sdavidch			    "cmd\n", CTX_RD(sc, GET_CID_ADDR(cid),
10217206268Sdavidch			    BCE_L2CTX_TX_CMD_TYPE_XI));
10218206268Sdavidch			BCE_PRINTF(" 0x%08X - (L2CTX_TX_TBDR_BDHADDR_HI_XI) "
10219207411Sdavidch			    "h/w buffer descriptor address\n",
10220207411Sdavidch			    CTX_RD(sc, GET_CID_ADDR(cid),
10221206268Sdavidch			    BCE_L2CTX_TX_TBDR_BHADDR_HI_XI));
10222206268Sdavidch			BCE_PRINTF(" 0x%08X - (L2CTX_TX_TBDR_BHADDR_LO_XI) "
10223207411Sdavidch			    "h/w buffer	descriptor address\n",
10224206268Sdavidch			    CTX_RD(sc, GET_CID_ADDR(cid),
10225206268Sdavidch			    BCE_L2CTX_TX_TBDR_BHADDR_LO_XI));
10226206268Sdavidch			BCE_PRINTF(" 0x%08X - (L2CTX_TX_HOST_BIDX_XI) "
10227207411Sdavidch			    "host producer index\n",
10228206268Sdavidch			    CTX_RD(sc, GET_CID_ADDR(cid),
10229206268Sdavidch			    BCE_L2CTX_TX_HOST_BIDX_XI));
10230206268Sdavidch			BCE_PRINTF(" 0x%08X - (L2CTX_TX_HOST_BSEQ_XI) "
10231207411Sdavidch			    "host byte sequence\n",
10232206268Sdavidch			    CTX_RD(sc, GET_CID_ADDR(cid),
10233206268Sdavidch			    BCE_L2CTX_TX_HOST_BSEQ_XI));
10234206268Sdavidch		} else {
10235206268Sdavidch			BCE_PRINTF(" 0x%08X - (L2CTX_TX_TYPE) ctx type\n",
10236206268Sdavidch			    CTX_RD(sc, GET_CID_ADDR(cid), BCE_L2CTX_TX_TYPE));
10237206268Sdavidch			BCE_PRINTF(" 0x%08X - (L2CTX_TX_CMD_TYPE) ctx cmd\n",
10238207411Sdavidch			    CTX_RD(sc, GET_CID_ADDR(cid),
10239206268Sdavidch			    BCE_L2CTX_TX_CMD_TYPE));
10240206268Sdavidch			BCE_PRINTF(" 0x%08X - (L2CTX_TX_TBDR_BDHADDR_HI) "
10241207411Sdavidch			    "h/w buffer	descriptor address\n",
10242206268Sdavidch			    CTX_RD(sc, GET_CID_ADDR(cid),
10243206268Sdavidch			    BCE_L2CTX_TX_TBDR_BHADDR_HI));
10244206268Sdavidch			BCE_PRINTF(" 0x%08X - (L2CTX_TX_TBDR_BHADDR_LO) "
10245207411Sdavidch			    "h/w buffer	descriptor address\n",
10246206268Sdavidch			    CTX_RD(sc, GET_CID_ADDR(cid),
10247206268Sdavidch			    BCE_L2CTX_TX_TBDR_BHADDR_LO));
10248206268Sdavidch			BCE_PRINTF(" 0x%08X - (L2CTX_TX_HOST_BIDX) host "
10249206268Sdavidch			    "producer index\n", CTX_RD(sc, GET_CID_ADDR(cid),
10250206268Sdavidch			    BCE_L2CTX_TX_HOST_BIDX));
10251206268Sdavidch			BCE_PRINTF(" 0x%08X - (L2CTX_TX_HOST_BSEQ) host byte "
10252206268Sdavidch			    "sequence\n", CTX_RD(sc, GET_CID_ADDR(cid),
10253206268Sdavidch			    BCE_L2CTX_TX_HOST_BSEQ));
10254179771Sdavidch		}
10255206268Sdavidch	}
10256179771Sdavidch
10257206268Sdavidch	BCE_PRINTF(
10258206268Sdavidch	   "----------------------------"
10259206268Sdavidch	   "    Raw CTX     "
10260206268Sdavidch	   "----------------------------\n");
10261179771Sdavidch
10262206268Sdavidch	for (int i = 0x0; i < 0x300; i += 0x10) {
10263206268Sdavidch		BCE_PRINTF("0x%04X: 0x%08X 0x%08X 0x%08X 0x%08X\n", i,
10264206268Sdavidch		   CTX_RD(sc, GET_CID_ADDR(cid), i),
10265206268Sdavidch		   CTX_RD(sc, GET_CID_ADDR(cid), i + 0x4),
10266206268Sdavidch		   CTX_RD(sc, GET_CID_ADDR(cid), i + 0x8),
10267206268Sdavidch		   CTX_RD(sc, GET_CID_ADDR(cid), i + 0xc));
10268176448Sdavidch	}
10269206268Sdavidch
10270206268Sdavidch
10271206268Sdavidch	BCE_PRINTF(
10272206268Sdavidch	   "----------------------------"
10273206268Sdavidch	   "----------------"
10274206268Sdavidch	   "----------------------------\n");
10275176448Sdavidch}
10276176448Sdavidch
10277176448Sdavidch
10278176448Sdavidch/****************************************************************************/
10279176448Sdavidch/* Prints out the FTQ data.                                                 */
10280176448Sdavidch/*                                                                          */
10281176448Sdavidch/* Returns:                                                                */
10282176448Sdavidch/*   Nothing.                                                               */
10283176448Sdavidch/****************************************************************************/
10284179771Sdavidchstatic __attribute__ ((noinline)) void
10285176448Sdavidchbce_dump_ftqs(struct bce_softc *sc)
10286178132Sdavidch{
10287179771Sdavidch	u32 cmd, ctl, cur_depth, max_depth, valid_cnt, val;
10288176448Sdavidch
10289176448Sdavidch	BCE_PRINTF(
10290206268Sdavidch	    "----------------------------"
10291206268Sdavidch	    "    FTQ Data    "
10292206268Sdavidch	    "----------------------------\n");
10293176448Sdavidch
10294206268Sdavidch	BCE_PRINTF("   FTQ    Command    Control   Depth_Now  "
10295206268Sdavidch	    "Max_Depth  Valid_Cnt \n");
10296206268Sdavidch	BCE_PRINTF(" ------- ---------- ---------- ---------- "
10297206268Sdavidch	    "---------- ----------\n");
10298178132Sdavidch
10299178132Sdavidch	/* Setup the generic statistic counters for the FTQ valid count. */
10300179771Sdavidch	val = (BCE_HC_STAT_GEN_SEL_0_GEN_SEL_0_RV2PPQ_VALID_CNT << 24) |
10301206268Sdavidch	    (BCE_HC_STAT_GEN_SEL_0_GEN_SEL_0_RXPCQ_VALID_CNT  << 16) |
10302206268Sdavidch	    (BCE_HC_STAT_GEN_SEL_0_GEN_SEL_0_RXPQ_VALID_CNT   <<  8) |
10303206268Sdavidch	    (BCE_HC_STAT_GEN_SEL_0_GEN_SEL_0_RLUPQ_VALID_CNT);
10304179771Sdavidch	REG_WR(sc, BCE_HC_STAT_GEN_SEL_0, val);
10305182293Sdavidch
10306179771Sdavidch	val = (BCE_HC_STAT_GEN_SEL_0_GEN_SEL_0_TSCHQ_VALID_CNT  << 24) |
10307206268Sdavidch	    (BCE_HC_STAT_GEN_SEL_0_GEN_SEL_0_RDMAQ_VALID_CNT  << 16) |
10308206268Sdavidch	    (BCE_HC_STAT_GEN_SEL_0_GEN_SEL_0_RV2PTQ_VALID_CNT <<  8) |
10309206268Sdavidch	    (BCE_HC_STAT_GEN_SEL_0_GEN_SEL_0_RV2PMQ_VALID_CNT);
10310179771Sdavidch	REG_WR(sc, BCE_HC_STAT_GEN_SEL_1, val);
10311182293Sdavidch
10312179771Sdavidch	val = (BCE_HC_STAT_GEN_SEL_0_GEN_SEL_0_TPATQ_VALID_CNT  << 24) |
10313206268Sdavidch	    (BCE_HC_STAT_GEN_SEL_0_GEN_SEL_0_TDMAQ_VALID_CNT  << 16) |
10314206268Sdavidch	    (BCE_HC_STAT_GEN_SEL_0_GEN_SEL_0_TXPQ_VALID_CNT   <<  8) |
10315206268Sdavidch	    (BCE_HC_STAT_GEN_SEL_0_GEN_SEL_0_TBDRQ_VALID_CNT);
10316179771Sdavidch	REG_WR(sc, BCE_HC_STAT_GEN_SEL_2, val);
10317182293Sdavidch
10318179771Sdavidch	val = (BCE_HC_STAT_GEN_SEL_0_GEN_SEL_0_COMQ_VALID_CNT   << 24) |
10319206268Sdavidch	    (BCE_HC_STAT_GEN_SEL_0_GEN_SEL_0_COMTQ_VALID_CNT  << 16) |
10320206268Sdavidch	    (BCE_HC_STAT_GEN_SEL_0_GEN_SEL_0_COMXQ_VALID_CNT  <<  8) |
10321206268Sdavidch	    (BCE_HC_STAT_GEN_SEL_0_GEN_SEL_0_TASQ_VALID_CNT);
10322179771Sdavidch	REG_WR(sc, BCE_HC_STAT_GEN_SEL_3, val);
10323178132Sdavidch
10324182293Sdavidch	/* Input queue to the Receive Lookup state machine */
10325178132Sdavidch	cmd = REG_RD(sc, BCE_RLUP_FTQ_CMD);
10326178132Sdavidch	ctl = REG_RD(sc, BCE_RLUP_FTQ_CTL);
10327178132Sdavidch	cur_depth = (ctl & BCE_RLUP_FTQ_CTL_CUR_DEPTH) >> 22;
10328178132Sdavidch	max_depth = (ctl & BCE_RLUP_FTQ_CTL_MAX_DEPTH) >> 12;
10329178132Sdavidch	valid_cnt = REG_RD(sc, BCE_HC_STAT_GEN_STAT0);
10330179771Sdavidch	BCE_PRINTF(" RLUP    0x%08X 0x%08X 0x%08X 0x%08X 0x%08X\n",
10331206268Sdavidch	    cmd, ctl, cur_depth, max_depth, valid_cnt);
10332178132Sdavidch
10333182293Sdavidch	/* Input queue to the Receive Processor */
10334178132Sdavidch	cmd = REG_RD_IND(sc, BCE_RXP_FTQ_CMD);
10335178132Sdavidch	ctl = REG_RD_IND(sc, BCE_RXP_FTQ_CTL);
10336178132Sdavidch	cur_depth = (ctl & BCE_RXP_FTQ_CTL_CUR_DEPTH) >> 22;
10337178132Sdavidch	max_depth = (ctl & BCE_RXP_FTQ_CTL_MAX_DEPTH) >> 12;
10338178132Sdavidch	valid_cnt = REG_RD(sc, BCE_HC_STAT_GEN_STAT1);
10339179771Sdavidch	BCE_PRINTF(" RXP     0x%08X 0x%08X 0x%08X 0x%08X 0x%08X\n",
10340206268Sdavidch	    cmd, ctl, cur_depth, max_depth, valid_cnt);
10341178132Sdavidch
10342182293Sdavidch	/* Input queue to the Recevie Processor */
10343178132Sdavidch	cmd = REG_RD_IND(sc, BCE_RXP_CFTQ_CMD);
10344178132Sdavidch	ctl = REG_RD_IND(sc, BCE_RXP_CFTQ_CTL);
10345178132Sdavidch	cur_depth = (ctl & BCE_RXP_CFTQ_CTL_CUR_DEPTH) >> 22;
10346178132Sdavidch	max_depth = (ctl & BCE_RXP_CFTQ_CTL_MAX_DEPTH) >> 12;
10347178132Sdavidch	valid_cnt = REG_RD(sc, BCE_HC_STAT_GEN_STAT2);
10348179771Sdavidch	BCE_PRINTF(" RXPC    0x%08X 0x%08X 0x%08X 0x%08X 0x%08X\n",
10349206268Sdavidch	    cmd, ctl, cur_depth, max_depth, valid_cnt);
10350178132Sdavidch
10351182293Sdavidch	/* Input queue to the Receive Virtual to Physical state machine */
10352178132Sdavidch	cmd = REG_RD(sc, BCE_RV2P_PFTQ_CMD);
10353178132Sdavidch	ctl = REG_RD(sc, BCE_RV2P_PFTQ_CTL);
10354178132Sdavidch	cur_depth = (ctl & BCE_RV2P_PFTQ_CTL_CUR_DEPTH) >> 22;
10355178132Sdavidch	max_depth = (ctl & BCE_RV2P_PFTQ_CTL_MAX_DEPTH) >> 12;
10356178132Sdavidch	valid_cnt = REG_RD(sc, BCE_HC_STAT_GEN_STAT3);
10357179771Sdavidch	BCE_PRINTF(" RV2PP   0x%08X 0x%08X 0x%08X 0x%08X 0x%08X\n",
10358206268Sdavidch	    cmd, ctl, cur_depth, max_depth, valid_cnt);
10359178132Sdavidch
10360182293Sdavidch	/* Input queue to the Recevie Virtual to Physical state machine */
10361178132Sdavidch	cmd = REG_RD(sc, BCE_RV2P_MFTQ_CMD);
10362178132Sdavidch	ctl = REG_RD(sc, BCE_RV2P_MFTQ_CTL);
10363178132Sdavidch	cur_depth = (ctl & BCE_RV2P_MFTQ_CTL_CUR_DEPTH) >> 22;
10364178132Sdavidch	max_depth = (ctl & BCE_RV2P_MFTQ_CTL_MAX_DEPTH) >> 12;
10365178132Sdavidch	valid_cnt = REG_RD(sc, BCE_HC_STAT_GEN_STAT4);
10366179771Sdavidch	BCE_PRINTF(" RV2PM   0x%08X 0x%08X 0x%08X 0x%08X 0x%08X\n",
10367206268Sdavidch	    cmd, ctl, cur_depth, max_depth, valid_cnt);
10368178132Sdavidch
10369182293Sdavidch	/* Input queue to the Receive Virtual to Physical state machine */
10370178132Sdavidch	cmd = REG_RD(sc, BCE_RV2P_TFTQ_CMD);
10371178132Sdavidch	ctl = REG_RD(sc, BCE_RV2P_TFTQ_CTL);
10372178132Sdavidch	cur_depth = (ctl & BCE_RV2P_TFTQ_CTL_CUR_DEPTH) >> 22;
10373178132Sdavidch	max_depth = (ctl & BCE_RV2P_TFTQ_CTL_MAX_DEPTH) >> 12;
10374178132Sdavidch	valid_cnt = REG_RD(sc, BCE_HC_STAT_GEN_STAT5);
10375179771Sdavidch	BCE_PRINTF(" RV2PT   0x%08X 0x%08X 0x%08X 0x%08X 0x%08X\n",
10376206268Sdavidch	    cmd, ctl, cur_depth, max_depth, valid_cnt);
10377178132Sdavidch
10378182293Sdavidch	/* Input queue to the Receive DMA state machine */
10379178132Sdavidch	cmd = REG_RD(sc, BCE_RDMA_FTQ_CMD);
10380178132Sdavidch	ctl = REG_RD(sc, BCE_RDMA_FTQ_CTL);
10381178132Sdavidch	cur_depth = (ctl & BCE_RDMA_FTQ_CTL_CUR_DEPTH) >> 22;
10382178132Sdavidch	max_depth = (ctl & BCE_RDMA_FTQ_CTL_MAX_DEPTH) >> 12;
10383178132Sdavidch	valid_cnt = REG_RD(sc, BCE_HC_STAT_GEN_STAT6);
10384179771Sdavidch	BCE_PRINTF(" RDMA    0x%08X 0x%08X 0x%08X 0x%08X 0x%08X\n",
10385206268Sdavidch	    cmd, ctl, cur_depth, max_depth, valid_cnt);
10386178132Sdavidch
10387182293Sdavidch	/* Input queue to the Transmit Scheduler state machine */
10388178132Sdavidch	cmd = REG_RD(sc, BCE_TSCH_FTQ_CMD);
10389178132Sdavidch	ctl = REG_RD(sc, BCE_TSCH_FTQ_CTL);
10390178132Sdavidch	cur_depth = (ctl & BCE_TSCH_FTQ_CTL_CUR_DEPTH) >> 22;
10391178132Sdavidch	max_depth = (ctl & BCE_TSCH_FTQ_CTL_MAX_DEPTH) >> 12;
10392178132Sdavidch	valid_cnt = REG_RD(sc, BCE_HC_STAT_GEN_STAT7);
10393179771Sdavidch	BCE_PRINTF(" TSCH    0x%08X 0x%08X 0x%08X 0x%08X 0x%08X\n",
10394206268Sdavidch	    cmd, ctl, cur_depth, max_depth, valid_cnt);
10395178132Sdavidch
10396182293Sdavidch	/* Input queue to the Transmit Buffer Descriptor state machine */
10397178132Sdavidch	cmd = REG_RD(sc, BCE_TBDR_FTQ_CMD);
10398178132Sdavidch	ctl = REG_RD(sc, BCE_TBDR_FTQ_CTL);
10399178132Sdavidch	cur_depth = (ctl & BCE_TBDR_FTQ_CTL_CUR_DEPTH) >> 22;
10400178132Sdavidch	max_depth = (ctl & BCE_TBDR_FTQ_CTL_MAX_DEPTH) >> 12;
10401178132Sdavidch	valid_cnt = REG_RD(sc, BCE_HC_STAT_GEN_STAT8);
10402179771Sdavidch	BCE_PRINTF(" TBDR    0x%08X 0x%08X 0x%08X 0x%08X 0x%08X\n",
10403206268Sdavidch	    cmd, ctl, cur_depth, max_depth, valid_cnt);
10404178132Sdavidch
10405182293Sdavidch	/* Input queue to the Transmit Processor */
10406178132Sdavidch	cmd = REG_RD_IND(sc, BCE_TXP_FTQ_CMD);
10407178132Sdavidch	ctl = REG_RD_IND(sc, BCE_TXP_FTQ_CTL);
10408178132Sdavidch	cur_depth = (ctl & BCE_TXP_FTQ_CTL_CUR_DEPTH) >> 22;
10409178132Sdavidch	max_depth = (ctl & BCE_TXP_FTQ_CTL_MAX_DEPTH) >> 12;
10410178132Sdavidch	valid_cnt = REG_RD(sc, BCE_HC_STAT_GEN_STAT9);
10411179771Sdavidch	BCE_PRINTF(" TXP     0x%08X 0x%08X 0x%08X 0x%08X 0x%08X\n",
10412206268Sdavidch	    cmd, ctl, cur_depth, max_depth, valid_cnt);
10413178132Sdavidch
10414182293Sdavidch	/* Input queue to the Transmit DMA state machine */
10415178132Sdavidch	cmd = REG_RD(sc, BCE_TDMA_FTQ_CMD);
10416178132Sdavidch	ctl = REG_RD(sc, BCE_TDMA_FTQ_CTL);
10417178132Sdavidch	cur_depth = (ctl & BCE_TDMA_FTQ_CTL_CUR_DEPTH) >> 22;
10418178132Sdavidch	max_depth = (ctl & BCE_TDMA_FTQ_CTL_MAX_DEPTH) >> 12;
10419178132Sdavidch	valid_cnt = REG_RD(sc, BCE_HC_STAT_GEN_STAT10);
10420179771Sdavidch	BCE_PRINTF(" TDMA    0x%08X 0x%08X 0x%08X 0x%08X 0x%08X\n",
10421206268Sdavidch	    cmd, ctl, cur_depth, max_depth, valid_cnt);
10422178132Sdavidch
10423182293Sdavidch	/* Input queue to the Transmit Patch-Up Processor */
10424178132Sdavidch	cmd = REG_RD_IND(sc, BCE_TPAT_FTQ_CMD);
10425178132Sdavidch	ctl = REG_RD_IND(sc, BCE_TPAT_FTQ_CTL);
10426178132Sdavidch	cur_depth = (ctl & BCE_TPAT_FTQ_CTL_CUR_DEPTH) >> 22;
10427178132Sdavidch	max_depth = (ctl & BCE_TPAT_FTQ_CTL_MAX_DEPTH) >> 12;
10428178132Sdavidch	valid_cnt = REG_RD(sc, BCE_HC_STAT_GEN_STAT11);
10429179771Sdavidch	BCE_PRINTF(" TPAT    0x%08X 0x%08X 0x%08X 0x%08X 0x%08X\n",
10430206268Sdavidch	    cmd, ctl, cur_depth, max_depth, valid_cnt);
10431178132Sdavidch
10432182293Sdavidch	/* Input queue to the Transmit Assembler state machine */
10433178132Sdavidch	cmd = REG_RD_IND(sc, BCE_TAS_FTQ_CMD);
10434178132Sdavidch	ctl = REG_RD_IND(sc, BCE_TAS_FTQ_CTL);
10435178132Sdavidch	cur_depth = (ctl & BCE_TAS_FTQ_CTL_CUR_DEPTH) >> 22;
10436178132Sdavidch	max_depth = (ctl & BCE_TAS_FTQ_CTL_MAX_DEPTH) >> 12;
10437178132Sdavidch	valid_cnt = REG_RD(sc, BCE_HC_STAT_GEN_STAT12);
10438179771Sdavidch	BCE_PRINTF(" TAS     0x%08X 0x%08X 0x%08X 0x%08X 0x%08X\n",
10439206268Sdavidch	    cmd, ctl, cur_depth, max_depth, valid_cnt);
10440178132Sdavidch
10441182293Sdavidch	/* Input queue to the Completion Processor */
10442178132Sdavidch	cmd = REG_RD_IND(sc, BCE_COM_COMXQ_FTQ_CMD);
10443178132Sdavidch	ctl = REG_RD_IND(sc, BCE_COM_COMXQ_FTQ_CTL);
10444178132Sdavidch	cur_depth = (ctl & BCE_COM_COMXQ_FTQ_CTL_CUR_DEPTH) >> 22;
10445178132Sdavidch	max_depth = (ctl & BCE_COM_COMXQ_FTQ_CTL_MAX_DEPTH) >> 12;
10446178132Sdavidch	valid_cnt = REG_RD(sc, BCE_HC_STAT_GEN_STAT13);
10447179771Sdavidch	BCE_PRINTF(" COMX    0x%08X 0x%08X 0x%08X 0x%08X 0x%08X\n",
10448206268Sdavidch	    cmd, ctl, cur_depth, max_depth, valid_cnt);
10449178132Sdavidch
10450182293Sdavidch	/* Input queue to the Completion Processor */
10451178132Sdavidch	cmd = REG_RD_IND(sc, BCE_COM_COMTQ_FTQ_CMD);
10452178132Sdavidch	ctl = REG_RD_IND(sc, BCE_COM_COMTQ_FTQ_CTL);
10453178132Sdavidch	cur_depth = (ctl & BCE_COM_COMTQ_FTQ_CTL_CUR_DEPTH) >> 22;
10454178132Sdavidch	max_depth = (ctl & BCE_COM_COMTQ_FTQ_CTL_MAX_DEPTH) >> 12;
10455178132Sdavidch	valid_cnt = REG_RD(sc, BCE_HC_STAT_GEN_STAT14);
10456179771Sdavidch	BCE_PRINTF(" COMT    0x%08X 0x%08X 0x%08X 0x%08X 0x%08X\n",
10457206268Sdavidch	    cmd, ctl, cur_depth, max_depth, valid_cnt);
10458178132Sdavidch
10459182293Sdavidch	/* Input queue to the Completion Processor */
10460178132Sdavidch	cmd = REG_RD_IND(sc, BCE_COM_COMQ_FTQ_CMD);
10461178132Sdavidch	ctl = REG_RD_IND(sc, BCE_COM_COMQ_FTQ_CTL);
10462178132Sdavidch	cur_depth = (ctl & BCE_COM_COMQ_FTQ_CTL_CUR_DEPTH) >> 22;
10463178132Sdavidch	max_depth = (ctl & BCE_COM_COMQ_FTQ_CTL_MAX_DEPTH) >> 12;
10464178132Sdavidch	valid_cnt = REG_RD(sc, BCE_HC_STAT_GEN_STAT15);
10465179771Sdavidch	BCE_PRINTF(" COMX    0x%08X 0x%08X 0x%08X 0x%08X 0x%08X\n",
10466206268Sdavidch	    cmd, ctl, cur_depth, max_depth, valid_cnt);
10467178132Sdavidch
10468178132Sdavidch	/* Setup the generic statistic counters for the FTQ valid count. */
10469179771Sdavidch	val = (BCE_HC_STAT_GEN_SEL_0_GEN_SEL_0_CSQ_VALID_CNT  << 16) |
10470206268Sdavidch	    (BCE_HC_STAT_GEN_SEL_0_GEN_SEL_0_CPQ_VALID_CNT  <<  8) |
10471206268Sdavidch	    (BCE_HC_STAT_GEN_SEL_0_GEN_SEL_0_MGMQ_VALID_CNT);
10472182293Sdavidch
10473239110Sdavide	if (BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5709)
10474207411Sdavidch		val = val |
10475207411Sdavidch		    (BCE_HC_STAT_GEN_SEL_0_GEN_SEL_0_RV2PCSQ_VALID_CNT_XI <<
10476206268Sdavidch		     24);
10477206268Sdavidch	REG_WR(sc, BCE_HC_STAT_GEN_SEL_0, val);
10478182293Sdavidch
10479182293Sdavidch	/* Input queue to the Management Control Processor */
10480178132Sdavidch	cmd = REG_RD_IND(sc, BCE_MCP_MCPQ_FTQ_CMD);
10481178132Sdavidch	ctl = REG_RD_IND(sc, BCE_MCP_MCPQ_FTQ_CTL);
10482178132Sdavidch	cur_depth = (ctl & BCE_MCP_MCPQ_FTQ_CTL_CUR_DEPTH) >> 22;
10483178132Sdavidch	max_depth = (ctl & BCE_MCP_MCPQ_FTQ_CTL_MAX_DEPTH) >> 12;
10484178132Sdavidch	valid_cnt = REG_RD(sc, BCE_HC_STAT_GEN_STAT0);
10485179771Sdavidch	BCE_PRINTF(" MCP     0x%08X 0x%08X 0x%08X 0x%08X 0x%08X\n",
10486206268Sdavidch	    cmd, ctl, cur_depth, max_depth, valid_cnt);
10487178132Sdavidch
10488182293Sdavidch	/* Input queue to the Command Processor */
10489178132Sdavidch	cmd = REG_RD_IND(sc, BCE_CP_CPQ_FTQ_CMD);
10490178132Sdavidch	ctl = REG_RD_IND(sc, BCE_CP_CPQ_FTQ_CTL);
10491178132Sdavidch	cur_depth = (ctl & BCE_CP_CPQ_FTQ_CTL_CUR_DEPTH) >> 22;
10492178132Sdavidch	max_depth = (ctl & BCE_CP_CPQ_FTQ_CTL_MAX_DEPTH) >> 12;
10493178132Sdavidch	valid_cnt = REG_RD(sc, BCE_HC_STAT_GEN_STAT1);
10494179771Sdavidch	BCE_PRINTF(" CP      0x%08X 0x%08X 0x%08X 0x%08X 0x%08X\n",
10495206268Sdavidch	    cmd, ctl, cur_depth, max_depth, valid_cnt);
10496178132Sdavidch
10497182293Sdavidch	/* Input queue to the Completion Scheduler state machine */
10498178132Sdavidch	cmd = REG_RD(sc, BCE_CSCH_CH_FTQ_CMD);
10499178132Sdavidch	ctl = REG_RD(sc, BCE_CSCH_CH_FTQ_CTL);
10500178132Sdavidch	cur_depth = (ctl & BCE_CSCH_CH_FTQ_CTL_CUR_DEPTH) >> 22;
10501178132Sdavidch	max_depth = (ctl & BCE_CSCH_CH_FTQ_CTL_MAX_DEPTH) >> 12;
10502178132Sdavidch	valid_cnt = REG_RD(sc, BCE_HC_STAT_GEN_STAT2);
10503179771Sdavidch	BCE_PRINTF(" CS      0x%08X 0x%08X 0x%08X 0x%08X 0x%08X\n",
10504206268Sdavidch	    cmd, ctl, cur_depth, max_depth, valid_cnt);
10505178132Sdavidch
10506226123Syongari	if (BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5709) {
10507206268Sdavidch		/* Input queue to the RV2P Command Scheduler */
10508179771Sdavidch		cmd = REG_RD(sc, BCE_RV2PCSR_FTQ_CMD);
10509179771Sdavidch		ctl = REG_RD(sc, BCE_RV2PCSR_FTQ_CTL);
10510179771Sdavidch		cur_depth = (ctl & 0xFFC00000) >> 22;
10511179771Sdavidch		max_depth = (ctl & 0x003FF000) >> 12;
10512179771Sdavidch		valid_cnt = REG_RD(sc, BCE_HC_STAT_GEN_STAT3);
10513179771Sdavidch		BCE_PRINTF(" RV2PCSR 0x%08X 0x%08X 0x%08X 0x%08X 0x%08X\n",
10514206268Sdavidch		    cmd, ctl, cur_depth, max_depth, valid_cnt);
10515179771Sdavidch	}
10516182293Sdavidch
10517176448Sdavidch	BCE_PRINTF(
10518206268Sdavidch	    "----------------------------"
10519206268Sdavidch	    "----------------"
10520206268Sdavidch	    "----------------------------\n");
10521176448Sdavidch}
10522176448Sdavidch
10523176448Sdavidch
10524176448Sdavidch/****************************************************************************/
10525170810Sdavidch/* Prints out the TX chain.                                                 */
10526169271Sdavidch/*                                                                          */
10527169271Sdavidch/* Returns:                                                                 */
10528169271Sdavidch/*   Nothing.                                                               */
10529169271Sdavidch/****************************************************************************/
10530179771Sdavidchstatic __attribute__ ((noinline)) void
10531176448Sdavidchbce_dump_tx_chain(struct bce_softc *sc, u16 tx_prod, int count)
10532157642Sps{
10533157642Sps	struct tx_bd *txbd;
10534157642Sps
10535157642Sps	/* First some info about the tx_bd chain structure. */
10536169271Sdavidch	BCE_PRINTF(
10537206268Sdavidch	    "----------------------------"
10538206268Sdavidch	    "  tx_bd  chain  "
10539206268Sdavidch	    "----------------------------\n");
10540157642Sps
10541169271Sdavidch	BCE_PRINTF("page size      = 0x%08X, tx chain pages        = 0x%08X\n",
10542218423Sdavidch	    (u32) BCM_PAGE_SIZE, (u32) sc->tx_pages);
10543169271Sdavidch	BCE_PRINTF("tx_bd per page = 0x%08X, usable tx_bd per page = 0x%08X\n",
10544206268Sdavidch	    (u32) TOTAL_TX_BD_PER_PAGE, (u32) USABLE_TX_BD_PER_PAGE);
10545218423Sdavidch	BCE_PRINTF("total tx_bd    = 0x%08X\n", (u32) TOTAL_TX_BD_ALLOC);
10546157642Sps
10547170810Sdavidch	BCE_PRINTF(
10548206268Sdavidch	    "----------------------------"
10549206268Sdavidch	    "   tx_bd data   "
10550206268Sdavidch	    "----------------------------\n");
10551157642Sps
10552205300Sdavidch	/* Now print out a decoded list of TX buffer descriptors. */
10553157642Sps	for (int i = 0; i < count; i++) {
10554157642Sps	 	txbd = &sc->tx_bd_chain[TX_PAGE(tx_prod)][TX_IDX(tx_prod)];
10555157642Sps		bce_dump_txbd(sc, tx_prod, txbd);
10556205300Sdavidch		tx_prod++;
10557157642Sps	}
10558157642Sps
10559169271Sdavidch	BCE_PRINTF(
10560206268Sdavidch	    "----------------------------"
10561206268Sdavidch	    "----------------"
10562206268Sdavidch	    "----------------------------\n");
10563157642Sps}
10564157642Sps
10565157642Sps
10566169271Sdavidch/****************************************************************************/
10567170810Sdavidch/* Prints out the RX chain.                                                 */
10568169271Sdavidch/*                                                                          */
10569169271Sdavidch/* Returns:                                                                 */
10570169271Sdavidch/*   Nothing.                                                               */
10571169271Sdavidch/****************************************************************************/
10572179771Sdavidchstatic __attribute__ ((noinline)) void
10573206268Sdavidchbce_dump_rx_bd_chain(struct bce_softc *sc, u16 rx_prod, int count)
10574157642Sps{
10575157642Sps	struct rx_bd *rxbd;
10576157642Sps
10577176448Sdavidch	/* First some info about the rx_bd chain structure. */
10578169271Sdavidch	BCE_PRINTF(
10579206268Sdavidch	    "----------------------------"
10580206268Sdavidch	    "  rx_bd  chain  "
10581206268Sdavidch	    "----------------------------\n");
10582157642Sps
10583169271Sdavidch	BCE_PRINTF("page size      = 0x%08X, rx chain pages        = 0x%08X\n",
10584218423Sdavidch	    (u32) BCM_PAGE_SIZE, (u32) sc->rx_pages);
10585157642Sps
10586169271Sdavidch	BCE_PRINTF("rx_bd per page = 0x%08X, usable rx_bd per page = 0x%08X\n",
10587206268Sdavidch	    (u32) TOTAL_RX_BD_PER_PAGE, (u32) USABLE_RX_BD_PER_PAGE);
10588157642Sps
10589218423Sdavidch	BCE_PRINTF("total rx_bd    = 0x%08X\n", (u32) TOTAL_RX_BD_ALLOC);
10590157642Sps
10591169271Sdavidch	BCE_PRINTF(
10592206268Sdavidch	    "----------------------------"
10593206268Sdavidch	    "   rx_bd data   "
10594206268Sdavidch	    "----------------------------\n");
10595157642Sps
10596157642Sps	/* Now print out the rx_bd's themselves. */
10597157642Sps	for (int i = 0; i < count; i++) {
10598157642Sps		rxbd = &sc->rx_bd_chain[RX_PAGE(rx_prod)][RX_IDX(rx_prod)];
10599157642Sps		bce_dump_rxbd(sc, rx_prod, rxbd);
10600176448Sdavidch		rx_prod = RX_CHAIN_IDX(rx_prod + 1);
10601157642Sps	}
10602157642Sps
10603169271Sdavidch	BCE_PRINTF(
10604206268Sdavidch	    "----------------------------"
10605206268Sdavidch	    "----------------"
10606206268Sdavidch	    "----------------------------\n");
10607157642Sps}
10608157642Sps
10609157642Sps
10610169271Sdavidch/****************************************************************************/
10611176448Sdavidch/* Prints out the page chain.                                               */
10612176448Sdavidch/*                                                                          */
10613176448Sdavidch/* Returns:                                                                 */
10614176448Sdavidch/*   Nothing.                                                               */
10615176448Sdavidch/****************************************************************************/
10616179771Sdavidchstatic __attribute__ ((noinline)) void
10617176448Sdavidchbce_dump_pg_chain(struct bce_softc *sc, u16 pg_prod, int count)
10618176448Sdavidch{
10619176448Sdavidch	struct rx_bd *pgbd;
10620176448Sdavidch
10621176448Sdavidch	/* First some info about the page chain structure. */
10622176448Sdavidch	BCE_PRINTF(
10623206268Sdavidch	    "----------------------------"
10624206268Sdavidch	    "   page chain   "
10625206268Sdavidch	    "----------------------------\n");
10626176448Sdavidch
10627176448Sdavidch	BCE_PRINTF("page size      = 0x%08X, pg chain pages        = 0x%08X\n",
10628218423Sdavidch	    (u32) BCM_PAGE_SIZE, (u32) sc->pg_pages);
10629176448Sdavidch
10630176448Sdavidch	BCE_PRINTF("rx_bd per page = 0x%08X, usable rx_bd per page = 0x%08X\n",
10631206268Sdavidch	    (u32) TOTAL_PG_BD_PER_PAGE, (u32) USABLE_PG_BD_PER_PAGE);
10632176448Sdavidch
10633218423Sdavidch	BCE_PRINTF("total pg_bd             = 0x%08X\n", (u32) TOTAL_PG_BD_ALLOC);
10634176448Sdavidch
10635176448Sdavidch	BCE_PRINTF(
10636206268Sdavidch	    "----------------------------"
10637206268Sdavidch	    "   page data    "
10638206268Sdavidch	    "----------------------------\n");
10639176448Sdavidch
10640176448Sdavidch	/* Now print out the rx_bd's themselves. */
10641176448Sdavidch	for (int i = 0; i < count; i++) {
10642178132Sdavidch		pgbd = &sc->pg_bd_chain[PG_PAGE(pg_prod)][PG_IDX(pg_prod)];
10643176448Sdavidch		bce_dump_pgbd(sc, pg_prod, pgbd);
10644176448Sdavidch		pg_prod = PG_CHAIN_IDX(pg_prod + 1);
10645176448Sdavidch	}
10646176448Sdavidch
10647176448Sdavidch	BCE_PRINTF(
10648206268Sdavidch	    "----------------------------"
10649206268Sdavidch	    "----------------"
10650206268Sdavidch	    "----------------------------\n");
10651179771Sdavidch}
10652176448Sdavidch
10653176448Sdavidch
10654206268Sdavidch#define BCE_PRINT_RX_CONS(arg)						\
10655206268Sdavidchif (sblk->status_rx_quick_consumer_index##arg)				\
10656206268Sdavidch	BCE_PRINTF("0x%04X(0x%04X) - rx_quick_consumer_index%d\n",	\
10657206268Sdavidch	    sblk->status_rx_quick_consumer_index##arg, (u16)		\
10658206268Sdavidch	    RX_CHAIN_IDX(sblk->status_rx_quick_consumer_index##arg),	\
10659206268Sdavidch	    arg);
10660205300Sdavidch
10661206268Sdavidch
10662206268Sdavidch#define BCE_PRINT_TX_CONS(arg)						\
10663206268Sdavidchif (sblk->status_tx_quick_consumer_index##arg)				\
10664206268Sdavidch	BCE_PRINTF("0x%04X(0x%04X) - tx_quick_consumer_index%d\n",	\
10665206268Sdavidch	    sblk->status_tx_quick_consumer_index##arg, (u16)		\
10666206268Sdavidch	    TX_CHAIN_IDX(sblk->status_tx_quick_consumer_index##arg),	\
10667206268Sdavidch	    arg);
10668206268Sdavidch
10669176448Sdavidch/****************************************************************************/
10670169271Sdavidch/* Prints out the status block from host memory.                            */
10671169271Sdavidch/*                                                                          */
10672169271Sdavidch/* Returns:                                                                 */
10673169271Sdavidch/*   Nothing.                                                               */
10674169271Sdavidch/****************************************************************************/
10675179771Sdavidchstatic __attribute__ ((noinline)) void
10676157642Spsbce_dump_status_block(struct bce_softc *sc)
10677157642Sps{
10678157642Sps	struct status_block *sblk;
10679157642Sps
10680251159Smarius	bus_dmamap_sync(sc->status_tag, sc->status_map, BUS_DMASYNC_POSTREAD);
10681251159Smarius
10682157642Sps	sblk = sc->status_block;
10683157642Sps
10684206268Sdavidch	BCE_PRINTF(
10685206268Sdavidch	    "----------------------------"
10686206268Sdavidch	    "  Status Block  "
10687206268Sdavidch	    "----------------------------\n");
10688170392Sdavidch
10689206268Sdavidch	/* Theses indices are used for normal L2 drivers. */
10690169632Sdavidch	BCE_PRINTF("    0x%08X - attn_bits\n",
10691206268Sdavidch	    sblk->status_attn_bits);
10692157642Sps
10693169632Sdavidch	BCE_PRINTF("    0x%08X - attn_bits_ack\n",
10694206268Sdavidch	    sblk->status_attn_bits_ack);
10695157642Sps
10696206268Sdavidch	BCE_PRINT_RX_CONS(0);
10697206268Sdavidch	BCE_PRINT_TX_CONS(0)
10698170392Sdavidch
10699169632Sdavidch	BCE_PRINTF("        0x%04X - status_idx\n", sblk->status_idx);
10700169632Sdavidch
10701157642Sps	/* Theses indices are not used for normal L2 drivers. */
10702206268Sdavidch	BCE_PRINT_RX_CONS(1);   BCE_PRINT_RX_CONS(2);   BCE_PRINT_RX_CONS(3);
10703206268Sdavidch	BCE_PRINT_RX_CONS(4);   BCE_PRINT_RX_CONS(5);   BCE_PRINT_RX_CONS(6);
10704206268Sdavidch	BCE_PRINT_RX_CONS(7);   BCE_PRINT_RX_CONS(8);   BCE_PRINT_RX_CONS(9);
10705206268Sdavidch	BCE_PRINT_RX_CONS(10);  BCE_PRINT_RX_CONS(11);  BCE_PRINT_RX_CONS(12);
10706206268Sdavidch	BCE_PRINT_RX_CONS(13);  BCE_PRINT_RX_CONS(14);  BCE_PRINT_RX_CONS(15);
10707170392Sdavidch
10708206268Sdavidch	BCE_PRINT_TX_CONS(1);   BCE_PRINT_TX_CONS(2);   BCE_PRINT_TX_CONS(3);
10709157642Sps
10710206268Sdavidch	if (sblk->status_completion_producer_index ||
10711206268Sdavidch	    sblk->status_cmd_consumer_index)
10712169271Sdavidch		BCE_PRINTF("com_prod  = 0x%08X, cmd_cons      = 0x%08X\n",
10713206268Sdavidch		    sblk->status_completion_producer_index,
10714206268Sdavidch		    sblk->status_cmd_consumer_index);
10715170392Sdavidch
10716169271Sdavidch	BCE_PRINTF(
10717206268Sdavidch	    "----------------------------"
10718206268Sdavidch	    "----------------"
10719206268Sdavidch	    "----------------------------\n");
10720157642Sps}
10721157642Sps
10722157642Sps
10723206268Sdavidch#define BCE_PRINT_64BIT_STAT(arg) 				\
10724206268Sdavidchif (sblk->arg##_lo || sblk->arg##_hi)				\
10725206268Sdavidch	BCE_PRINTF("0x%08X:%08X : %s\n", sblk->arg##_hi,	\
10726206268Sdavidch	    sblk->arg##_lo, #arg);
10727205300Sdavidch
10728206268Sdavidch#define BCE_PRINT_32BIT_STAT(arg)				\
10729206268Sdavidchif (sblk->arg)							\
10730206268Sdavidch	BCE_PRINTF("         0x%08X : %s\n", 			\
10731206268Sdavidch	    sblk->arg, #arg);
10732205300Sdavidch
10733169271Sdavidch/****************************************************************************/
10734170810Sdavidch/* Prints out the statistics block from host memory.                        */
10735169271Sdavidch/*                                                                          */
10736169271Sdavidch/* Returns:                                                                 */
10737169271Sdavidch/*   Nothing.                                                               */
10738169271Sdavidch/****************************************************************************/
10739179771Sdavidchstatic __attribute__ ((noinline)) void
10740157642Spsbce_dump_stats_block(struct bce_softc *sc)
10741157642Sps{
10742157642Sps	struct statistics_block *sblk;
10743157642Sps
10744251159Smarius	bus_dmamap_sync(sc->stats_tag, sc->stats_map, BUS_DMASYNC_POSTREAD);
10745251159Smarius
10746157642Sps	sblk = sc->stats_block;
10747170392Sdavidch
10748169271Sdavidch	BCE_PRINTF(
10749206268Sdavidch	    "---------------"
10750206268Sdavidch	    " Stats Block  (All Stats Not Shown Are 0) "
10751206268Sdavidch	    "---------------\n");
10752157642Sps
10753206268Sdavidch	BCE_PRINT_64BIT_STAT(stat_IfHCInOctets);
10754206268Sdavidch	BCE_PRINT_64BIT_STAT(stat_IfHCInBadOctets);
10755206268Sdavidch	BCE_PRINT_64BIT_STAT(stat_IfHCOutOctets);
10756206268Sdavidch	BCE_PRINT_64BIT_STAT(stat_IfHCOutBadOctets);
10757206268Sdavidch	BCE_PRINT_64BIT_STAT(stat_IfHCInUcastPkts);
10758206268Sdavidch	BCE_PRINT_64BIT_STAT(stat_IfHCInBroadcastPkts);
10759206268Sdavidch	BCE_PRINT_64BIT_STAT(stat_IfHCInMulticastPkts);
10760206268Sdavidch	BCE_PRINT_64BIT_STAT(stat_IfHCOutUcastPkts);
10761206268Sdavidch	BCE_PRINT_64BIT_STAT(stat_IfHCOutBroadcastPkts);
10762206268Sdavidch	BCE_PRINT_64BIT_STAT(stat_IfHCOutMulticastPkts);
10763206268Sdavidch	BCE_PRINT_32BIT_STAT(
10764206268Sdavidch	    stat_emac_tx_stat_dot3statsinternalmactransmiterrors);
10765206268Sdavidch	BCE_PRINT_32BIT_STAT(stat_Dot3StatsCarrierSenseErrors);
10766206268Sdavidch	BCE_PRINT_32BIT_STAT(stat_Dot3StatsFCSErrors);
10767206268Sdavidch	BCE_PRINT_32BIT_STAT(stat_Dot3StatsAlignmentErrors);
10768206268Sdavidch	BCE_PRINT_32BIT_STAT(stat_Dot3StatsSingleCollisionFrames);
10769206268Sdavidch	BCE_PRINT_32BIT_STAT(stat_Dot3StatsMultipleCollisionFrames);
10770206268Sdavidch	BCE_PRINT_32BIT_STAT(stat_Dot3StatsDeferredTransmissions);
10771206268Sdavidch	BCE_PRINT_32BIT_STAT(stat_Dot3StatsExcessiveCollisions);
10772206268Sdavidch	BCE_PRINT_32BIT_STAT(stat_Dot3StatsLateCollisions);
10773206268Sdavidch	BCE_PRINT_32BIT_STAT(stat_EtherStatsCollisions);
10774206268Sdavidch	BCE_PRINT_32BIT_STAT(stat_EtherStatsFragments);
10775206268Sdavidch	BCE_PRINT_32BIT_STAT(stat_EtherStatsJabbers);
10776206268Sdavidch	BCE_PRINT_32BIT_STAT(stat_EtherStatsUndersizePkts);
10777206268Sdavidch	BCE_PRINT_32BIT_STAT(stat_EtherStatsOversizePkts);
10778206268Sdavidch	BCE_PRINT_32BIT_STAT(stat_EtherStatsPktsRx64Octets);
10779206268Sdavidch	BCE_PRINT_32BIT_STAT(stat_EtherStatsPktsRx65Octetsto127Octets);
10780206268Sdavidch	BCE_PRINT_32BIT_STAT(stat_EtherStatsPktsRx128Octetsto255Octets);
10781206268Sdavidch	BCE_PRINT_32BIT_STAT(stat_EtherStatsPktsRx256Octetsto511Octets);
10782206268Sdavidch	BCE_PRINT_32BIT_STAT(stat_EtherStatsPktsRx512Octetsto1023Octets);
10783206268Sdavidch	BCE_PRINT_32BIT_STAT(stat_EtherStatsPktsRx1024Octetsto1522Octets);
10784206268Sdavidch	BCE_PRINT_32BIT_STAT(stat_EtherStatsPktsRx1523Octetsto9022Octets);
10785206268Sdavidch	BCE_PRINT_32BIT_STAT(stat_EtherStatsPktsTx64Octets);
10786206268Sdavidch	BCE_PRINT_32BIT_STAT(stat_EtherStatsPktsTx65Octetsto127Octets);
10787206268Sdavidch	BCE_PRINT_32BIT_STAT(stat_EtherStatsPktsTx128Octetsto255Octets);
10788206268Sdavidch	BCE_PRINT_32BIT_STAT(stat_EtherStatsPktsTx256Octetsto511Octets);
10789206268Sdavidch	BCE_PRINT_32BIT_STAT(stat_EtherStatsPktsTx512Octetsto1023Octets);
10790206268Sdavidch	BCE_PRINT_32BIT_STAT(stat_EtherStatsPktsTx1024Octetsto1522Octets);
10791206268Sdavidch	BCE_PRINT_32BIT_STAT(stat_EtherStatsPktsTx1523Octetsto9022Octets);
10792206268Sdavidch	BCE_PRINT_32BIT_STAT(stat_XonPauseFramesReceived);
10793206268Sdavidch	BCE_PRINT_32BIT_STAT(stat_XoffPauseFramesReceived);
10794206268Sdavidch	BCE_PRINT_32BIT_STAT(stat_OutXonSent);
10795206268Sdavidch	BCE_PRINT_32BIT_STAT(stat_OutXoffSent);
10796206268Sdavidch	BCE_PRINT_32BIT_STAT(stat_FlowControlDone);
10797206268Sdavidch	BCE_PRINT_32BIT_STAT(stat_MacControlFramesReceived);
10798206268Sdavidch	BCE_PRINT_32BIT_STAT(stat_XoffStateEntered);
10799206268Sdavidch	BCE_PRINT_32BIT_STAT(stat_IfInFramesL2FilterDiscards);
10800206268Sdavidch	BCE_PRINT_32BIT_STAT(stat_IfInRuleCheckerDiscards);
10801206268Sdavidch	BCE_PRINT_32BIT_STAT(stat_IfInFTQDiscards);
10802206268Sdavidch	BCE_PRINT_32BIT_STAT(stat_IfInMBUFDiscards);
10803206268Sdavidch	BCE_PRINT_32BIT_STAT(stat_IfInRuleCheckerP4Hit);
10804206268Sdavidch	BCE_PRINT_32BIT_STAT(stat_CatchupInRuleCheckerDiscards);
10805206268Sdavidch	BCE_PRINT_32BIT_STAT(stat_CatchupInFTQDiscards);
10806206268Sdavidch	BCE_PRINT_32BIT_STAT(stat_CatchupInMBUFDiscards);
10807206268Sdavidch	BCE_PRINT_32BIT_STAT(stat_CatchupInRuleCheckerP4Hit);
10808170392Sdavidch
10809169271Sdavidch	BCE_PRINTF(
10810206268Sdavidch	    "----------------------------"
10811206268Sdavidch	    "----------------"
10812206268Sdavidch	    "----------------------------\n");
10813157642Sps}
10814157642Sps
10815157642Sps
10816169271Sdavidch/****************************************************************************/
10817169271Sdavidch/* Prints out a summary of the driver state.                                */
10818169271Sdavidch/*                                                                          */
10819169271Sdavidch/* Returns:                                                                 */
10820169271Sdavidch/*   Nothing.                                                               */
10821169271Sdavidch/****************************************************************************/
10822179771Sdavidchstatic __attribute__ ((noinline)) void
10823157642Spsbce_dump_driver_state(struct bce_softc *sc)
10824157642Sps{
10825157642Sps	u32 val_hi, val_lo;
10826157642Sps
10827169271Sdavidch	BCE_PRINTF(
10828206268Sdavidch	    "-----------------------------"
10829206268Sdavidch	    " Driver State "
10830206268Sdavidch	    "-----------------------------\n");
10831157642Sps
10832157642Sps	val_hi = BCE_ADDR_HI(sc);
10833157642Sps	val_lo = BCE_ADDR_LO(sc);
10834206268Sdavidch	BCE_PRINTF("0x%08X:%08X - (sc) driver softc structure virtual "
10835206268Sdavidch	    "address\n", val_hi, val_lo);
10836157642Sps
10837157642Sps	val_hi = BCE_ADDR_HI(sc->bce_vhandle);
10838157642Sps	val_lo = BCE_ADDR_LO(sc->bce_vhandle);
10839206268Sdavidch	BCE_PRINTF("0x%08X:%08X - (sc->bce_vhandle) PCI BAR virtual "
10840206268Sdavidch	    "address\n", val_hi, val_lo);
10841157642Sps
10842157642Sps	val_hi = BCE_ADDR_HI(sc->status_block);
10843157642Sps	val_lo = BCE_ADDR_LO(sc->status_block);
10844206268Sdavidch	BCE_PRINTF("0x%08X:%08X - (sc->status_block) status block "
10845206268Sdavidch	    "virtual address\n",	val_hi, val_lo);
10846157642Sps
10847157642Sps	val_hi = BCE_ADDR_HI(sc->stats_block);
10848157642Sps	val_lo = BCE_ADDR_LO(sc->stats_block);
10849206268Sdavidch	BCE_PRINTF("0x%08X:%08X - (sc->stats_block) statistics block "
10850206268Sdavidch	    "virtual address\n", val_hi, val_lo);
10851157642Sps
10852157642Sps	val_hi = BCE_ADDR_HI(sc->tx_bd_chain);
10853157642Sps	val_lo = BCE_ADDR_LO(sc->tx_bd_chain);
10854206268Sdavidch	BCE_PRINTF("0x%08X:%08X - (sc->tx_bd_chain) tx_bd chain "
10855206268Sdavidch	    "virtual adddress\n", val_hi, val_lo);
10856157642Sps
10857157642Sps	val_hi = BCE_ADDR_HI(sc->rx_bd_chain);
10858157642Sps	val_lo = BCE_ADDR_LO(sc->rx_bd_chain);
10859206268Sdavidch	BCE_PRINTF("0x%08X:%08X - (sc->rx_bd_chain) rx_bd chain "
10860206268Sdavidch	    "virtual address\n", val_hi, val_lo);
10861157642Sps
10862218423Sdavidch	if (bce_hdr_split == TRUE) {
10863218423Sdavidch		val_hi = BCE_ADDR_HI(sc->pg_bd_chain);
10864218423Sdavidch		val_lo = BCE_ADDR_LO(sc->pg_bd_chain);
10865218423Sdavidch		BCE_PRINTF("0x%08X:%08X - (sc->pg_bd_chain) page chain "
10866218423Sdavidch		    "virtual address\n", val_hi, val_lo);
10867218423Sdavidch	}
10868176448Sdavidch
10869157642Sps	val_hi = BCE_ADDR_HI(sc->tx_mbuf_ptr);
10870157642Sps	val_lo = BCE_ADDR_LO(sc->tx_mbuf_ptr);
10871206268Sdavidch	BCE_PRINTF("0x%08X:%08X - (sc->tx_mbuf_ptr) tx mbuf chain "
10872206268Sdavidch	    "virtual address\n",	val_hi, val_lo);
10873157642Sps
10874157642Sps	val_hi = BCE_ADDR_HI(sc->rx_mbuf_ptr);
10875157642Sps	val_lo = BCE_ADDR_LO(sc->rx_mbuf_ptr);
10876206268Sdavidch	BCE_PRINTF("0x%08X:%08X - (sc->rx_mbuf_ptr) rx mbuf chain "
10877206268Sdavidch	    "virtual address\n", val_hi, val_lo);
10878157642Sps
10879218423Sdavidch	if (bce_hdr_split == TRUE) {
10880218423Sdavidch		val_hi = BCE_ADDR_HI(sc->pg_mbuf_ptr);
10881218423Sdavidch		val_lo = BCE_ADDR_LO(sc->pg_mbuf_ptr);
10882218423Sdavidch		BCE_PRINTF("0x%08X:%08X - (sc->pg_mbuf_ptr) page mbuf chain "
10883218423Sdavidch		    "virtual address\n", val_hi, val_lo);
10884218423Sdavidch	}
10885176448Sdavidch
10886218423Sdavidch	BCE_PRINTF(" 0x%016llX - (sc->interrupts_generated) "
10887218423Sdavidch	    "h/w intrs\n",
10888218423Sdavidch	    (long long unsigned int) sc->interrupts_generated);
10889179771Sdavidch
10890218423Sdavidch	BCE_PRINTF(" 0x%016llX - (sc->interrupts_rx) "
10891218423Sdavidch	    "rx interrupts handled\n",
10892218423Sdavidch	    (long long unsigned int) sc->interrupts_rx);
10893157642Sps
10894218423Sdavidch	BCE_PRINTF(" 0x%016llX - (sc->interrupts_tx) "
10895218423Sdavidch	    "tx interrupts handled\n",
10896218423Sdavidch	    (long long unsigned int) sc->interrupts_tx);
10897157642Sps
10898218423Sdavidch	BCE_PRINTF(" 0x%016llX - (sc->phy_interrupts) "
10899218423Sdavidch	    "phy interrupts handled\n",
10900218423Sdavidch	    (long long unsigned int) sc->phy_interrupts);
10901157642Sps
10902206268Sdavidch	BCE_PRINTF("         0x%08X - (sc->last_status_idx) "
10903206268Sdavidch	    "status block index\n", sc->last_status_idx);
10904157642Sps
10905206268Sdavidch	BCE_PRINTF("     0x%04X(0x%04X) - (sc->tx_prod) tx producer "
10906206268Sdavidch	    "index\n", sc->tx_prod, (u16) TX_CHAIN_IDX(sc->tx_prod));
10907157642Sps
10908206268Sdavidch	BCE_PRINTF("     0x%04X(0x%04X) - (sc->tx_cons) tx consumer "
10909206268Sdavidch	    "index\n", sc->tx_cons, (u16) TX_CHAIN_IDX(sc->tx_cons));
10910157642Sps
10911206268Sdavidch	BCE_PRINTF("         0x%08X - (sc->tx_prod_bseq) tx producer "
10912206268Sdavidch	    "byte seq index\n",	sc->tx_prod_bseq);
10913171667Sdavidch
10914206268Sdavidch	BCE_PRINTF("         0x%08X - (sc->debug_tx_mbuf_alloc) tx "
10915206268Sdavidch	    "mbufs allocated\n", sc->debug_tx_mbuf_alloc);
10916171667Sdavidch
10917206268Sdavidch	BCE_PRINTF("         0x%08X - (sc->used_tx_bd) used "
10918206268Sdavidch	    "tx_bd's\n", sc->used_tx_bd);
10919171667Sdavidch
10920218423Sdavidch	BCE_PRINTF("      0x%04X/0x%04X - (sc->tx_hi_watermark)/"
10921218423Sdavidch	    "(sc->max_tx_bd)\n", sc->tx_hi_watermark, sc->max_tx_bd);
10922157642Sps
10923206268Sdavidch	BCE_PRINTF("     0x%04X(0x%04X) - (sc->rx_prod) rx producer "
10924206268Sdavidch	    "index\n", sc->rx_prod, (u16) RX_CHAIN_IDX(sc->rx_prod));
10925157642Sps
10926206268Sdavidch	BCE_PRINTF("     0x%04X(0x%04X) - (sc->rx_cons) rx consumer "
10927206268Sdavidch	    "index\n", sc->rx_cons, (u16) RX_CHAIN_IDX(sc->rx_cons));
10928157642Sps
10929206268Sdavidch	BCE_PRINTF("         0x%08X - (sc->rx_prod_bseq) rx producer "
10930206268Sdavidch	    "byte seq index\n",	sc->rx_prod_bseq);
10931157642Sps
10932218423Sdavidch	BCE_PRINTF("      0x%04X/0x%04X - (sc->rx_low_watermark)/"
10933218423Sdavidch		   "(sc->max_rx_bd)\n", sc->rx_low_watermark, sc->max_rx_bd);
10934218423Sdavidch
10935206268Sdavidch	BCE_PRINTF("         0x%08X - (sc->debug_rx_mbuf_alloc) rx "
10936206268Sdavidch	    "mbufs allocated\n", sc->debug_rx_mbuf_alloc);
10937157642Sps
10938206268Sdavidch	BCE_PRINTF("         0x%08X - (sc->free_rx_bd) free "
10939206268Sdavidch	    "rx_bd's\n", sc->free_rx_bd);
10940206268Sdavidch
10941218423Sdavidch	if (bce_hdr_split == TRUE) {
10942218423Sdavidch		BCE_PRINTF("     0x%04X(0x%04X) - (sc->pg_prod) page producer "
10943218423Sdavidch		    "index\n", sc->pg_prod, (u16) PG_CHAIN_IDX(sc->pg_prod));
10944157642Sps
10945218423Sdavidch		BCE_PRINTF("     0x%04X(0x%04X) - (sc->pg_cons) page consumer "
10946218423Sdavidch		    "index\n", sc->pg_cons, (u16) PG_CHAIN_IDX(sc->pg_cons));
10947176448Sdavidch
10948218423Sdavidch		BCE_PRINTF("         0x%08X - (sc->debug_pg_mbuf_alloc) page "
10949218423Sdavidch		    "mbufs allocated\n", sc->debug_pg_mbuf_alloc);
10950218423Sdavidch	}
10951176448Sdavidch
10952206268Sdavidch	BCE_PRINTF("         0x%08X - (sc->free_pg_bd) free page "
10953206268Sdavidch	    "rx_bd's\n", sc->free_pg_bd);
10954176448Sdavidch
10955218423Sdavidch	BCE_PRINTF("      0x%04X/0x%04X - (sc->pg_low_watermark)/"
10956218423Sdavidch	    "(sc->max_pg_bd)\n", sc->pg_low_watermark, sc->max_pg_bd);
10957176448Sdavidch
10958189325Sdavidch	BCE_PRINTF("         0x%08X - (sc->mbuf_alloc_failed_count) "
10959206268Sdavidch	    "mbuf alloc failures\n", sc->mbuf_alloc_failed_count);
10960157642Sps
10961206268Sdavidch	BCE_PRINTF("         0x%08X - (sc->bce_flags) "
10962206268Sdavidch	    "bce mac flags\n", sc->bce_flags);
10963179771Sdavidch
10964206268Sdavidch	BCE_PRINTF("         0x%08X - (sc->bce_phy_flags) "
10965206268Sdavidch	    "bce phy flags\n", sc->bce_phy_flags);
10966179771Sdavidch
10967169271Sdavidch	BCE_PRINTF(
10968206268Sdavidch	    "----------------------------"
10969206268Sdavidch	    "----------------"
10970206268Sdavidch	    "----------------------------\n");
10971157642Sps}
10972157642Sps
10973170392Sdavidch
10974169271Sdavidch/****************************************************************************/
10975170810Sdavidch/* Prints out the hardware state through a summary of important register,   */
10976169271Sdavidch/* followed by a complete register dump.                                    */
10977169271Sdavidch/*                                                                          */
10978169271Sdavidch/* Returns:                                                                 */
10979169271Sdavidch/*   Nothing.                                                               */
10980169271Sdavidch/****************************************************************************/
10981179771Sdavidchstatic __attribute__ ((noinline)) void
10982157642Spsbce_dump_hw_state(struct bce_softc *sc)
10983157642Sps{
10984176448Sdavidch	u32 val;
10985157642Sps
10986169271Sdavidch	BCE_PRINTF(
10987206268Sdavidch	    "----------------------------"
10988206268Sdavidch	    " Hardware State "
10989206268Sdavidch	    "----------------------------\n");
10990157642Sps
10991194781Sdavidch	BCE_PRINTF("%s - bootcode version\n", sc->bce_bc_ver);
10992157642Sps
10993176448Sdavidch	val = REG_RD(sc, BCE_MISC_ENABLE_STATUS_BITS);
10994169632Sdavidch	BCE_PRINTF("0x%08X - (0x%06X) misc_enable_status_bits\n",
10995206268Sdavidch	    val, BCE_MISC_ENABLE_STATUS_BITS);
10996157642Sps
10997176448Sdavidch	val = REG_RD(sc, BCE_DMA_STATUS);
10998207411Sdavidch	BCE_PRINTF("0x%08X - (0x%06X) dma_status\n",
10999206268Sdavidch	    val, BCE_DMA_STATUS);
11000157642Sps
11001176448Sdavidch	val = REG_RD(sc, BCE_CTX_STATUS);
11002207411Sdavidch	BCE_PRINTF("0x%08X - (0x%06X) ctx_status\n",
11003206268Sdavidch	    val, BCE_CTX_STATUS);
11004157642Sps
11005176448Sdavidch	val = REG_RD(sc, BCE_EMAC_STATUS);
11006207411Sdavidch	BCE_PRINTF("0x%08X - (0x%06X) emac_status\n",
11007206268Sdavidch	    val, BCE_EMAC_STATUS);
11008157642Sps
11009176448Sdavidch	val = REG_RD(sc, BCE_RPM_STATUS);
11010206268Sdavidch	BCE_PRINTF("0x%08X - (0x%06X) rpm_status\n",
11011206268Sdavidch	    val, BCE_RPM_STATUS);
11012157642Sps
11013206268Sdavidch	/* ToDo: Create a #define for this constant. */
11014176448Sdavidch	val = REG_RD(sc, 0x2004);
11015207411Sdavidch	BCE_PRINTF("0x%08X - (0x%06X) rlup_status\n",
11016206268Sdavidch	    val, 0x2004);
11017157642Sps
11018176448Sdavidch	val = REG_RD(sc, BCE_RV2P_STATUS);
11019207411Sdavidch	BCE_PRINTF("0x%08X - (0x%06X) rv2p_status\n",
11020206268Sdavidch	    val, BCE_RV2P_STATUS);
11021157642Sps
11022206268Sdavidch	/* ToDo: Create a #define for this constant. */
11023176448Sdavidch	val = REG_RD(sc, 0x2c04);
11024207411Sdavidch	BCE_PRINTF("0x%08X - (0x%06X) rdma_status\n",
11025206268Sdavidch	    val, 0x2c04);
11026157642Sps
11027176448Sdavidch	val = REG_RD(sc, BCE_TBDR_STATUS);
11028206268Sdavidch	BCE_PRINTF("0x%08X - (0x%06X) tbdr_status\n",
11029206268Sdavidch	    val, BCE_TBDR_STATUS);
11030169632Sdavidch
11031176448Sdavidch	val = REG_RD(sc, BCE_TDMA_STATUS);
11032207411Sdavidch	BCE_PRINTF("0x%08X - (0x%06X) tdma_status\n",
11033206268Sdavidch	    val, BCE_TDMA_STATUS);
11034169632Sdavidch
11035176448Sdavidch	val = REG_RD(sc, BCE_HC_STATUS);
11036206268Sdavidch	BCE_PRINTF("0x%08X - (0x%06X) hc_status\n",
11037206268Sdavidch	    val, BCE_HC_STATUS);
11038169632Sdavidch
11039176448Sdavidch	val = REG_RD_IND(sc, BCE_TXP_CPU_STATE);
11040207411Sdavidch	BCE_PRINTF("0x%08X - (0x%06X) txp_cpu_state\n",
11041206268Sdavidch	    val, BCE_TXP_CPU_STATE);
11042169632Sdavidch
11043176448Sdavidch	val = REG_RD_IND(sc, BCE_TPAT_CPU_STATE);
11044207411Sdavidch	BCE_PRINTF("0x%08X - (0x%06X) tpat_cpu_state\n",
11045206268Sdavidch	    val, BCE_TPAT_CPU_STATE);
11046169632Sdavidch
11047176448Sdavidch	val = REG_RD_IND(sc, BCE_RXP_CPU_STATE);
11048207411Sdavidch	BCE_PRINTF("0x%08X - (0x%06X) rxp_cpu_state\n",
11049206268Sdavidch	    val, BCE_RXP_CPU_STATE);
11050169632Sdavidch
11051176448Sdavidch	val = REG_RD_IND(sc, BCE_COM_CPU_STATE);
11052207411Sdavidch	BCE_PRINTF("0x%08X - (0x%06X) com_cpu_state\n",
11053206268Sdavidch	    val, BCE_COM_CPU_STATE);
11054176448Sdavidch
11055176448Sdavidch	val = REG_RD_IND(sc, BCE_MCP_CPU_STATE);
11056207411Sdavidch	BCE_PRINTF("0x%08X - (0x%06X) mcp_cpu_state\n",
11057206268Sdavidch	    val, BCE_MCP_CPU_STATE);
11058176448Sdavidch
11059176448Sdavidch	val = REG_RD_IND(sc, BCE_CP_CPU_STATE);
11060207411Sdavidch	BCE_PRINTF("0x%08X - (0x%06X) cp_cpu_state\n",
11061206268Sdavidch	    val, BCE_CP_CPU_STATE);
11062176448Sdavidch
11063179771Sdavidch	BCE_PRINTF(
11064206268Sdavidch	    "----------------------------"
11065206268Sdavidch	    "----------------"
11066206268Sdavidch	    "----------------------------\n");
11067157642Sps
11068179771Sdavidch	BCE_PRINTF(
11069206268Sdavidch	    "----------------------------"
11070206268Sdavidch	    " Register  Dump "
11071206268Sdavidch	    "----------------------------\n");
11072170392Sdavidch
11073178132Sdavidch	for (int i = 0x400; i < 0x8000; i += 0x10) {
11074169271Sdavidch		BCE_PRINTF("0x%04X: 0x%08X 0x%08X 0x%08X 0x%08X\n",
11075206268Sdavidch		    i, REG_RD(sc, i), REG_RD(sc, i + 0x4),
11076206268Sdavidch		    REG_RD(sc, i + 0x8), REG_RD(sc, i + 0xC));
11077176448Sdavidch	}
11078157642Sps
11079179771Sdavidch	BCE_PRINTF(
11080206268Sdavidch	    "----------------------------"
11081206268Sdavidch	    "----------------"
11082206268Sdavidch	    "----------------------------\n");
11083157642Sps}
11084157642Sps
11085157642Sps
11086169271Sdavidch/****************************************************************************/
11087218423Sdavidch/* Prints out the contentst of shared memory which is used for host driver  */
11088218423Sdavidch/* to bootcode firmware communication.                                      */
11089218423Sdavidch/*                                                                          */
11090218423Sdavidch/* Returns:                                                                 */
11091218423Sdavidch/*   Nothing.                                                               */
11092218423Sdavidch/****************************************************************************/
11093218423Sdavidchstatic __attribute__ ((noinline)) void
11094218423Sdavidchbce_dump_shmem_state(struct bce_softc *sc)
11095218423Sdavidch{
11096218423Sdavidch	BCE_PRINTF(
11097218423Sdavidch	    "----------------------------"
11098218423Sdavidch	    " Hardware State "
11099218423Sdavidch	    "----------------------------\n");
11100218423Sdavidch
11101218423Sdavidch	BCE_PRINTF("0x%08X - Shared memory base address\n",
11102218423Sdavidch	    sc->bce_shmem_base);
11103218423Sdavidch	BCE_PRINTF("%s - bootcode version\n",
11104218423Sdavidch	    sc->bce_bc_ver);
11105218423Sdavidch
11106218423Sdavidch	BCE_PRINTF(
11107218423Sdavidch	    "----------------------------"
11108218423Sdavidch	    "   Shared Mem   "
11109218423Sdavidch	    "----------------------------\n");
11110218423Sdavidch
11111218423Sdavidch	for (int i = 0x0; i < 0x200; i += 0x10) {
11112218423Sdavidch		BCE_PRINTF("0x%04X: 0x%08X 0x%08X 0x%08X 0x%08X\n",
11113218423Sdavidch		    i, bce_shmem_rd(sc, i), bce_shmem_rd(sc, i + 0x4),
11114218423Sdavidch		    bce_shmem_rd(sc, i + 0x8), bce_shmem_rd(sc, i + 0xC));
11115218423Sdavidch	}
11116218423Sdavidch
11117218423Sdavidch	BCE_PRINTF(
11118218423Sdavidch	    "----------------------------"
11119218423Sdavidch	    "----------------"
11120218423Sdavidch	    "----------------------------\n");
11121218423Sdavidch}
11122218423Sdavidch
11123218423Sdavidch
11124218423Sdavidch/****************************************************************************/
11125179771Sdavidch/* Prints out the mailbox queue registers.                                  */
11126179771Sdavidch/*                                                                          */
11127179771Sdavidch/* Returns:                                                                 */
11128179771Sdavidch/*   Nothing.                                                               */
11129179771Sdavidch/****************************************************************************/
11130179771Sdavidchstatic __attribute__ ((noinline)) void
11131179771Sdavidchbce_dump_mq_regs(struct bce_softc *sc)
11132179771Sdavidch{
11133179771Sdavidch	BCE_PRINTF(
11134206268Sdavidch	    "----------------------------"
11135206268Sdavidch	    "    MQ Regs     "
11136206268Sdavidch	    "----------------------------\n");
11137179771Sdavidch
11138179771Sdavidch	BCE_PRINTF(
11139206268Sdavidch	    "----------------------------"
11140206268Sdavidch	    "----------------"
11141206268Sdavidch	    "----------------------------\n");
11142179771Sdavidch
11143179771Sdavidch	for (int i = 0x3c00; i < 0x4000; i += 0x10) {
11144179771Sdavidch		BCE_PRINTF("0x%04X: 0x%08X 0x%08X 0x%08X 0x%08X\n",
11145206268Sdavidch		    i, REG_RD(sc, i), REG_RD(sc, i + 0x4),
11146206268Sdavidch		    REG_RD(sc, i + 0x8), REG_RD(sc, i + 0xC));
11147179771Sdavidch	}
11148179771Sdavidch
11149179771Sdavidch	BCE_PRINTF(
11150206268Sdavidch	    "----------------------------"
11151206268Sdavidch	    "----------------"
11152206268Sdavidch	    "----------------------------\n");
11153179771Sdavidch}
11154179771Sdavidch
11155179771Sdavidch
11156179771Sdavidch/****************************************************************************/
11157170810Sdavidch/* Prints out the bootcode state.                                           */
11158170810Sdavidch/*                                                                          */
11159170810Sdavidch/* Returns:                                                                 */
11160170810Sdavidch/*   Nothing.                                                               */
11161170810Sdavidch/****************************************************************************/
11162179771Sdavidchstatic __attribute__ ((noinline)) void
11163170810Sdavidchbce_dump_bc_state(struct bce_softc *sc)
11164170810Sdavidch{
11165170810Sdavidch	u32 val;
11166170810Sdavidch
11167170810Sdavidch	BCE_PRINTF(
11168206268Sdavidch	    "----------------------------"
11169206268Sdavidch	    " Bootcode State "
11170206268Sdavidch	    "----------------------------\n");
11171170810Sdavidch
11172194781Sdavidch	BCE_PRINTF("%s - bootcode version\n", sc->bce_bc_ver);
11173170810Sdavidch
11174194781Sdavidch	val = bce_shmem_rd(sc, BCE_BC_RESET_TYPE);
11175170810Sdavidch	BCE_PRINTF("0x%08X - (0x%06X) reset_type\n",
11176206268Sdavidch	    val, BCE_BC_RESET_TYPE);
11177170810Sdavidch
11178194781Sdavidch	val = bce_shmem_rd(sc, BCE_BC_STATE);
11179170810Sdavidch	BCE_PRINTF("0x%08X - (0x%06X) state\n",
11180206268Sdavidch	    val, BCE_BC_STATE);
11181170810Sdavidch
11182202717Sdavidch	val = bce_shmem_rd(sc, BCE_BC_STATE_CONDITION);
11183170810Sdavidch	BCE_PRINTF("0x%08X - (0x%06X) condition\n",
11184206268Sdavidch	    val, BCE_BC_STATE_CONDITION);
11185170810Sdavidch
11186194781Sdavidch	val = bce_shmem_rd(sc, BCE_BC_STATE_DEBUG_CMD);
11187170810Sdavidch	BCE_PRINTF("0x%08X - (0x%06X) debug_cmd\n",
11188206268Sdavidch	    val, BCE_BC_STATE_DEBUG_CMD);
11189170810Sdavidch
11190179771Sdavidch	BCE_PRINTF(
11191206268Sdavidch	    "----------------------------"
11192206268Sdavidch	    "----------------"
11193206268Sdavidch	    "----------------------------\n");
11194170810Sdavidch}
11195170810Sdavidch
11196170810Sdavidch
11197170810Sdavidch/****************************************************************************/
11198179771Sdavidch/* Prints out the TXP processor state.                                      */
11199169632Sdavidch/*                                                                          */
11200169632Sdavidch/* Returns:                                                                 */
11201169632Sdavidch/*   Nothing.                                                               */
11202169632Sdavidch/****************************************************************************/
11203179771Sdavidchstatic __attribute__ ((noinline)) void
11204179771Sdavidchbce_dump_txp_state(struct bce_softc *sc, int regs)
11205169632Sdavidch{
11206179771Sdavidch	u32 val;
11207182293Sdavidch	u32 fw_version[3];
11208169632Sdavidch
11209169632Sdavidch	BCE_PRINTF(
11210206268Sdavidch	    "----------------------------"
11211206268Sdavidch	    "   TXP  State   "
11212206268Sdavidch	    "----------------------------\n");
11213169632Sdavidch
11214182293Sdavidch	for (int i = 0; i < 3; i++)
11215182293Sdavidch		fw_version[i] = htonl(REG_RD_IND(sc,
11216206268Sdavidch		    (BCE_TXP_SCRATCH + 0x10 + i * 4)));
11217182293Sdavidch	BCE_PRINTF("Firmware version - %s\n", (char *) fw_version);
11218182293Sdavidch
11219179771Sdavidch	val = REG_RD_IND(sc, BCE_TXP_CPU_MODE);
11220207411Sdavidch	BCE_PRINTF("0x%08X - (0x%06X) txp_cpu_mode\n",
11221206268Sdavidch	    val, BCE_TXP_CPU_MODE);
11222169632Sdavidch
11223179771Sdavidch	val = REG_RD_IND(sc, BCE_TXP_CPU_STATE);
11224207411Sdavidch	BCE_PRINTF("0x%08X - (0x%06X) txp_cpu_state\n",
11225206268Sdavidch	    val, BCE_TXP_CPU_STATE);
11226169632Sdavidch
11227179771Sdavidch	val = REG_RD_IND(sc, BCE_TXP_CPU_EVENT_MASK);
11228207411Sdavidch	BCE_PRINTF("0x%08X - (0x%06X) txp_cpu_event_mask\n",
11229206268Sdavidch	    val, BCE_TXP_CPU_EVENT_MASK);
11230169632Sdavidch
11231179771Sdavidch	if (regs) {
11232179771Sdavidch		BCE_PRINTF(
11233206268Sdavidch		    "----------------------------"
11234206268Sdavidch		    " Register  Dump "
11235206268Sdavidch		    "----------------------------\n");
11236170392Sdavidch
11237179771Sdavidch		for (int i = BCE_TXP_CPU_MODE; i < 0x68000; i += 0x10) {
11238179771Sdavidch			/* Skip the big blank spaces */
11239179771Sdavidch			if (i < 0x454000 && i > 0x5ffff)
11240206268Sdavidch				BCE_PRINTF("0x%04X: 0x%08X 0x%08X "
11241207411Sdavidch				    "0x%08X 0x%08X\n", i,
11242207411Sdavidch				    REG_RD_IND(sc, i),
11243206268Sdavidch				    REG_RD_IND(sc, i + 0x4),
11244206268Sdavidch				    REG_RD_IND(sc, i + 0x8),
11245206268Sdavidch				    REG_RD_IND(sc, i + 0xC));
11246179771Sdavidch		}
11247169632Sdavidch	}
11248169632Sdavidch
11249179771Sdavidch	BCE_PRINTF(
11250206268Sdavidch	    "----------------------------"
11251206268Sdavidch	    "----------------"
11252206268Sdavidch	    "----------------------------\n");
11253169632Sdavidch}
11254169632Sdavidch
11255169632Sdavidch
11256169632Sdavidch/****************************************************************************/
11257179771Sdavidch/* Prints out the RXP processor state.                                      */
11258169632Sdavidch/*                                                                          */
11259169632Sdavidch/* Returns:                                                                 */
11260169632Sdavidch/*   Nothing.                                                               */
11261169632Sdavidch/****************************************************************************/
11262179771Sdavidchstatic __attribute__ ((noinline)) void
11263179771Sdavidchbce_dump_rxp_state(struct bce_softc *sc, int regs)
11264169632Sdavidch{
11265179771Sdavidch	u32 val;
11266182293Sdavidch	u32 fw_version[3];
11267169632Sdavidch
11268169632Sdavidch	BCE_PRINTF(
11269206268Sdavidch	    "----------------------------"
11270206268Sdavidch	    "   RXP  State   "
11271206268Sdavidch	    "----------------------------\n");
11272169632Sdavidch
11273182293Sdavidch	for (int i = 0; i < 3; i++)
11274182293Sdavidch		fw_version[i] = htonl(REG_RD_IND(sc,
11275206268Sdavidch		    (BCE_RXP_SCRATCH + 0x10 + i * 4)));
11276206268Sdavidch
11277182293Sdavidch	BCE_PRINTF("Firmware version - %s\n", (char *) fw_version);
11278182293Sdavidch
11279179771Sdavidch	val = REG_RD_IND(sc, BCE_RXP_CPU_MODE);
11280207411Sdavidch	BCE_PRINTF("0x%08X - (0x%06X) rxp_cpu_mode\n",
11281206268Sdavidch	    val, BCE_RXP_CPU_MODE);
11282169632Sdavidch
11283179771Sdavidch	val = REG_RD_IND(sc, BCE_RXP_CPU_STATE);
11284207411Sdavidch	BCE_PRINTF("0x%08X - (0x%06X) rxp_cpu_state\n",
11285206268Sdavidch	    val, BCE_RXP_CPU_STATE);
11286169632Sdavidch
11287179771Sdavidch	val = REG_RD_IND(sc, BCE_RXP_CPU_EVENT_MASK);
11288207411Sdavidch	BCE_PRINTF("0x%08X - (0x%06X) rxp_cpu_event_mask\n",
11289206268Sdavidch	    val, BCE_RXP_CPU_EVENT_MASK);
11290169632Sdavidch
11291179771Sdavidch	if (regs) {
11292179771Sdavidch		BCE_PRINTF(
11293206268Sdavidch		    "----------------------------"
11294206268Sdavidch		    " Register  Dump "
11295206268Sdavidch		    "----------------------------\n");
11296179771Sdavidch
11297179771Sdavidch		for (int i = BCE_RXP_CPU_MODE; i < 0xe8fff; i += 0x10) {
11298179771Sdavidch			/* Skip the big blank sapces */
11299179771Sdavidch			if (i < 0xc5400 && i > 0xdffff)
11300206268Sdavidch				BCE_PRINTF("0x%04X: 0x%08X 0x%08X "
11301207411Sdavidch				    "0x%08X 0x%08X\n", i,
11302207411Sdavidch				    REG_RD_IND(sc, i),
11303206268Sdavidch				    REG_RD_IND(sc, i + 0x4),
11304207411Sdavidch				    REG_RD_IND(sc, i + 0x8),
11305206268Sdavidch				    REG_RD_IND(sc, i + 0xC));
11306179771Sdavidch		}
11307179771Sdavidch	}
11308179771Sdavidch
11309179771Sdavidch	BCE_PRINTF(
11310206268Sdavidch	    "----------------------------"
11311206268Sdavidch	    "----------------"
11312206268Sdavidch	    "----------------------------\n");
11313179771Sdavidch}
11314170392Sdavidch
11315179771Sdavidch
11316179771Sdavidch/****************************************************************************/
11317179771Sdavidch/* Prints out the TPAT processor state.                                     */
11318179771Sdavidch/*                                                                          */
11319179771Sdavidch/* Returns:                                                                 */
11320179771Sdavidch/*   Nothing.                                                               */
11321179771Sdavidch/****************************************************************************/
11322179771Sdavidchstatic __attribute__ ((noinline)) void
11323179771Sdavidchbce_dump_tpat_state(struct bce_softc *sc, int regs)
11324179771Sdavidch{
11325179771Sdavidch	u32 val;
11326182293Sdavidch	u32 fw_version[3];
11327179771Sdavidch
11328179771Sdavidch	BCE_PRINTF(
11329206268Sdavidch	    "----------------------------"
11330206268Sdavidch	    "   TPAT State   "
11331206268Sdavidch	    "----------------------------\n");
11332179771Sdavidch
11333182293Sdavidch	for (int i = 0; i < 3; i++)
11334182293Sdavidch		fw_version[i] = htonl(REG_RD_IND(sc,
11335206268Sdavidch		    (BCE_TPAT_SCRATCH + 0x410 + i * 4)));
11336206268Sdavidch
11337182293Sdavidch	BCE_PRINTF("Firmware version - %s\n", (char *) fw_version);
11338182293Sdavidch
11339179771Sdavidch	val = REG_RD_IND(sc, BCE_TPAT_CPU_MODE);
11340207411Sdavidch	BCE_PRINTF("0x%08X - (0x%06X) tpat_cpu_mode\n",
11341206268Sdavidch	    val, BCE_TPAT_CPU_MODE);
11342179771Sdavidch
11343179771Sdavidch	val = REG_RD_IND(sc, BCE_TPAT_CPU_STATE);
11344207411Sdavidch	BCE_PRINTF("0x%08X - (0x%06X) tpat_cpu_state\n",
11345206268Sdavidch	    val, BCE_TPAT_CPU_STATE);
11346179771Sdavidch
11347179771Sdavidch	val = REG_RD_IND(sc, BCE_TPAT_CPU_EVENT_MASK);
11348207411Sdavidch	BCE_PRINTF("0x%08X - (0x%06X) tpat_cpu_event_mask\n",
11349206268Sdavidch	    val, BCE_TPAT_CPU_EVENT_MASK);
11350179771Sdavidch
11351179771Sdavidch	if (regs) {
11352179771Sdavidch		BCE_PRINTF(
11353206268Sdavidch		    "----------------------------"
11354206268Sdavidch		    " Register  Dump "
11355206268Sdavidch		    "----------------------------\n");
11356179771Sdavidch
11357179771Sdavidch		for (int i = BCE_TPAT_CPU_MODE; i < 0xa3fff; i += 0x10) {
11358179771Sdavidch			/* Skip the big blank spaces */
11359179771Sdavidch			if (i < 0x854000 && i > 0x9ffff)
11360206268Sdavidch				BCE_PRINTF("0x%04X: 0x%08X 0x%08X "
11361206268Sdavidch				    "0x%08X 0x%08X\n", i,
11362207411Sdavidch				    REG_RD_IND(sc, i),
11363206268Sdavidch				    REG_RD_IND(sc, i + 0x4),
11364207411Sdavidch				    REG_RD_IND(sc, i + 0x8),
11365206268Sdavidch				    REG_RD_IND(sc, i + 0xC));
11366179771Sdavidch		}
11367169632Sdavidch	}
11368169632Sdavidch
11369179771Sdavidch	BCE_PRINTF(
11370169632Sdavidch		"----------------------------"
11371169632Sdavidch		"----------------"
11372169632Sdavidch		"----------------------------\n");
11373169632Sdavidch}
11374169632Sdavidch
11375169632Sdavidch
11376169632Sdavidch/****************************************************************************/
11377179771Sdavidch/* Prints out the Command Procesor (CP) state.                              */
11378169632Sdavidch/*                                                                          */
11379169632Sdavidch/* Returns:                                                                 */
11380169632Sdavidch/*   Nothing.                                                               */
11381169632Sdavidch/****************************************************************************/
11382179771Sdavidchstatic __attribute__ ((noinline)) void
11383179771Sdavidchbce_dump_cp_state(struct bce_softc *sc, int regs)
11384169632Sdavidch{
11385179771Sdavidch	u32 val;
11386182293Sdavidch	u32 fw_version[3];
11387169632Sdavidch
11388169632Sdavidch	BCE_PRINTF(
11389206268Sdavidch	    "----------------------------"
11390206268Sdavidch	    "    CP State    "
11391206268Sdavidch	    "----------------------------\n");
11392169632Sdavidch
11393182293Sdavidch	for (int i = 0; i < 3; i++)
11394182293Sdavidch		fw_version[i] = htonl(REG_RD_IND(sc,
11395206268Sdavidch		    (BCE_CP_SCRATCH + 0x10 + i * 4)));
11396206268Sdavidch
11397182293Sdavidch	BCE_PRINTF("Firmware version - %s\n", (char *) fw_version);
11398182293Sdavidch
11399179771Sdavidch	val = REG_RD_IND(sc, BCE_CP_CPU_MODE);
11400207411Sdavidch	BCE_PRINTF("0x%08X - (0x%06X) cp_cpu_mode\n",
11401206268Sdavidch	    val, BCE_CP_CPU_MODE);
11402169632Sdavidch
11403179771Sdavidch	val = REG_RD_IND(sc, BCE_CP_CPU_STATE);
11404207411Sdavidch	BCE_PRINTF("0x%08X - (0x%06X) cp_cpu_state\n",
11405206268Sdavidch	    val, BCE_CP_CPU_STATE);
11406169632Sdavidch
11407179771Sdavidch	val = REG_RD_IND(sc, BCE_CP_CPU_EVENT_MASK);
11408179771Sdavidch	BCE_PRINTF("0x%08X - (0x%06X) cp_cpu_event_mask\n", val,
11409206268Sdavidch	    BCE_CP_CPU_EVENT_MASK);
11410169632Sdavidch
11411179771Sdavidch	if (regs) {
11412179771Sdavidch		BCE_PRINTF(
11413206268Sdavidch		    "----------------------------"
11414206268Sdavidch		    " Register  Dump "
11415206268Sdavidch		    "----------------------------\n");
11416179771Sdavidch
11417179771Sdavidch		for (int i = BCE_CP_CPU_MODE; i < 0x1aa000; i += 0x10) {
11418179771Sdavidch			/* Skip the big blank spaces */
11419179771Sdavidch			if (i < 0x185400 && i > 0x19ffff)
11420206268Sdavidch				BCE_PRINTF("0x%04X: 0x%08X 0x%08X "
11421207411Sdavidch				    "0x%08X 0x%08X\n", i,
11422207411Sdavidch				    REG_RD_IND(sc, i),
11423206268Sdavidch				    REG_RD_IND(sc, i + 0x4),
11424207411Sdavidch				    REG_RD_IND(sc, i + 0x8),
11425206268Sdavidch				    REG_RD_IND(sc, i + 0xC));
11426179771Sdavidch		}
11427179771Sdavidch	}
11428179771Sdavidch
11429179771Sdavidch	BCE_PRINTF(
11430206268Sdavidch	    "----------------------------"
11431206268Sdavidch	    "----------------"
11432206268Sdavidch	    "----------------------------\n");
11433179771Sdavidch}
11434170392Sdavidch
11435179771Sdavidch
11436179771Sdavidch/****************************************************************************/
11437179771Sdavidch/* Prints out the Completion Procesor (COM) state.                          */
11438179771Sdavidch/*                                                                          */
11439179771Sdavidch/* Returns:                                                                 */
11440179771Sdavidch/*   Nothing.                                                               */
11441179771Sdavidch/****************************************************************************/
11442179771Sdavidchstatic __attribute__ ((noinline)) void
11443179771Sdavidchbce_dump_com_state(struct bce_softc *sc, int regs)
11444179771Sdavidch{
11445179771Sdavidch	u32 val;
11446205300Sdavidch	u32 fw_version[4];
11447179771Sdavidch
11448179771Sdavidch	BCE_PRINTF(
11449206268Sdavidch	    "----------------------------"
11450206268Sdavidch	    "   COM State    "
11451206268Sdavidch	    "----------------------------\n");
11452179771Sdavidch
11453182293Sdavidch	for (int i = 0; i < 3; i++)
11454182293Sdavidch		fw_version[i] = htonl(REG_RD_IND(sc,
11455206268Sdavidch		    (BCE_COM_SCRATCH + 0x10 + i * 4)));
11456206268Sdavidch
11457182293Sdavidch	BCE_PRINTF("Firmware version - %s\n", (char *) fw_version);
11458182293Sdavidch
11459179771Sdavidch	val = REG_RD_IND(sc, BCE_COM_CPU_MODE);
11460207411Sdavidch	BCE_PRINTF("0x%08X - (0x%06X) com_cpu_mode\n",
11461206268Sdavidch	    val, BCE_COM_CPU_MODE);
11462179771Sdavidch
11463179771Sdavidch	val = REG_RD_IND(sc, BCE_COM_CPU_STATE);
11464207411Sdavidch	BCE_PRINTF("0x%08X - (0x%06X) com_cpu_state\n",
11465206268Sdavidch	    val, BCE_COM_CPU_STATE);
11466179771Sdavidch
11467179771Sdavidch	val = REG_RD_IND(sc, BCE_COM_CPU_EVENT_MASK);
11468179771Sdavidch	BCE_PRINTF("0x%08X - (0x%06X) com_cpu_event_mask\n", val,
11469206268Sdavidch	    BCE_COM_CPU_EVENT_MASK);
11470179771Sdavidch
11471179771Sdavidch	if (regs) {
11472179771Sdavidch		BCE_PRINTF(
11473206268Sdavidch		    "----------------------------"
11474206268Sdavidch		    " Register  Dump "
11475206268Sdavidch		    "----------------------------\n");
11476179771Sdavidch
11477179771Sdavidch		for (int i = BCE_COM_CPU_MODE; i < 0x1053e8; i += 0x10) {
11478206268Sdavidch			BCE_PRINTF("0x%04X: 0x%08X 0x%08X "
11479207411Sdavidch			    "0x%08X 0x%08X\n", i,
11480207411Sdavidch			    REG_RD_IND(sc, i),
11481206268Sdavidch			    REG_RD_IND(sc, i + 0x4),
11482206268Sdavidch			    REG_RD_IND(sc, i + 0x8),
11483206268Sdavidch			    REG_RD_IND(sc, i + 0xC));
11484179771Sdavidch		}
11485169632Sdavidch	}
11486169632Sdavidch
11487179771Sdavidch	BCE_PRINTF(
11488169632Sdavidch		"----------------------------"
11489169632Sdavidch		"----------------"
11490169632Sdavidch		"----------------------------\n");
11491169632Sdavidch}
11492169632Sdavidch
11493169632Sdavidch
11494169632Sdavidch/****************************************************************************/
11495205300Sdavidch/* Prints out the Receive Virtual 2 Physical (RV2P) state.                  */
11496205300Sdavidch/*                                                                          */
11497205300Sdavidch/* Returns:                                                                 */
11498205300Sdavidch/*   Nothing.                                                               */
11499205300Sdavidch/****************************************************************************/
11500205300Sdavidchstatic __attribute__ ((noinline)) void
11501205300Sdavidchbce_dump_rv2p_state(struct bce_softc *sc)
11502205300Sdavidch{
11503205300Sdavidch	u32 val, pc1, pc2, fw_ver_high, fw_ver_low;
11504205300Sdavidch
11505205300Sdavidch	BCE_PRINTF(
11506206268Sdavidch	    "----------------------------"
11507206268Sdavidch	    "   RV2P State   "
11508206268Sdavidch	    "----------------------------\n");
11509205300Sdavidch
11510206268Sdavidch	/* Stall the RV2P processors. */
11511206268Sdavidch	val = REG_RD_IND(sc, BCE_RV2P_CONFIG);
11512206268Sdavidch	val |= BCE_RV2P_CONFIG_STALL_PROC1 | BCE_RV2P_CONFIG_STALL_PROC2;
11513206268Sdavidch	REG_WR_IND(sc, BCE_RV2P_CONFIG, val);
11514205300Sdavidch
11515206268Sdavidch	/* Read the firmware version. */
11516206268Sdavidch	val = 0x00000001;
11517206268Sdavidch	REG_WR_IND(sc, BCE_RV2P_PROC1_ADDR_CMD, val);
11518206268Sdavidch	fw_ver_low = REG_RD_IND(sc, BCE_RV2P_INSTR_LOW);
11519207411Sdavidch	fw_ver_high = REG_RD_IND(sc, BCE_RV2P_INSTR_HIGH) &
11520206268Sdavidch	    BCE_RV2P_INSTR_HIGH_HIGH;
11521207411Sdavidch	BCE_PRINTF("RV2P1 Firmware version - 0x%08X:0x%08X\n",
11522206268Sdavidch	    fw_ver_high, fw_ver_low);
11523205300Sdavidch
11524206268Sdavidch	val = 0x00000001;
11525206268Sdavidch	REG_WR_IND(sc, BCE_RV2P_PROC2_ADDR_CMD, val);
11526206268Sdavidch	fw_ver_low = REG_RD_IND(sc, BCE_RV2P_INSTR_LOW);
11527207411Sdavidch	fw_ver_high = REG_RD_IND(sc, BCE_RV2P_INSTR_HIGH) &
11528206268Sdavidch	    BCE_RV2P_INSTR_HIGH_HIGH;
11529207411Sdavidch	BCE_PRINTF("RV2P2 Firmware version - 0x%08X:0x%08X\n",
11530206268Sdavidch	    fw_ver_high, fw_ver_low);
11531205300Sdavidch
11532206268Sdavidch	/* Resume the RV2P processors. */
11533206268Sdavidch	val = REG_RD_IND(sc, BCE_RV2P_CONFIG);
11534206268Sdavidch	val &= ~(BCE_RV2P_CONFIG_STALL_PROC1 | BCE_RV2P_CONFIG_STALL_PROC2);
11535206268Sdavidch	REG_WR_IND(sc, BCE_RV2P_CONFIG, val);
11536205300Sdavidch
11537206268Sdavidch	/* Fetch the program counter value. */
11538205300Sdavidch	val = 0x68007800;
11539206268Sdavidch	REG_WR_IND(sc, BCE_RV2P_DEBUG_VECT_PEEK, val);
11540206268Sdavidch	val = REG_RD_IND(sc, BCE_RV2P_DEBUG_VECT_PEEK);
11541206268Sdavidch	pc1 = (val & BCE_RV2P_DEBUG_VECT_PEEK_1_VALUE);
11542206268Sdavidch	pc2 = (val & BCE_RV2P_DEBUG_VECT_PEEK_2_VALUE) >> 16;
11543206268Sdavidch	BCE_PRINTF("0x%08X - RV2P1 program counter (1st read)\n", pc1);
11544206268Sdavidch	BCE_PRINTF("0x%08X - RV2P2 program counter (1st read)\n", pc2);
11545205300Sdavidch
11546206268Sdavidch	/* Fetch the program counter value again to see if it is advancing. */
11547206268Sdavidch	val = 0x68007800;
11548206268Sdavidch	REG_WR_IND(sc, BCE_RV2P_DEBUG_VECT_PEEK, val);
11549206268Sdavidch	val = REG_RD_IND(sc, BCE_RV2P_DEBUG_VECT_PEEK);
11550206268Sdavidch	pc1 = (val & BCE_RV2P_DEBUG_VECT_PEEK_1_VALUE);
11551206268Sdavidch	pc2 = (val & BCE_RV2P_DEBUG_VECT_PEEK_2_VALUE) >> 16;
11552206268Sdavidch	BCE_PRINTF("0x%08X - RV2P1 program counter (2nd read)\n", pc1);
11553206268Sdavidch	BCE_PRINTF("0x%08X - RV2P2 program counter (2nd read)\n", pc2);
11554205300Sdavidch
11555205300Sdavidch	BCE_PRINTF(
11556206268Sdavidch	    "----------------------------"
11557206268Sdavidch	    "----------------"
11558206268Sdavidch	    "----------------------------\n");
11559205300Sdavidch}
11560205300Sdavidch
11561205300Sdavidch
11562205300Sdavidch/****************************************************************************/
11563170392Sdavidch/* Prints out the driver state and then enters the debugger.                */
11564169271Sdavidch/*                                                                          */
11565169271Sdavidch/* Returns:                                                                 */
11566169271Sdavidch/*   Nothing.                                                               */
11567169271Sdavidch/****************************************************************************/
11568205300Sdavidchstatic __attribute__ ((noinline)) void
11569157642Spsbce_breakpoint(struct bce_softc *sc)
11570157642Sps{
11571157642Sps
11572179771Sdavidch	/*
11573179771Sdavidch	 * Unreachable code to silence compiler warnings
11574179771Sdavidch	 * about unused functions.
11575176448Sdavidch	 */
11576157642Sps	if (0) {
11577170392Sdavidch		bce_freeze_controller(sc);
11578170392Sdavidch		bce_unfreeze_controller(sc);
11579182293Sdavidch		bce_dump_enet(sc, NULL);
11580206268Sdavidch		bce_dump_txbd(sc, 0, NULL);
11581157642Sps		bce_dump_rxbd(sc, 0, NULL);
11582218423Sdavidch		bce_dump_tx_mbuf_chain(sc, 0, USABLE_TX_BD_ALLOC);
11583218423Sdavidch		bce_dump_rx_mbuf_chain(sc, 0, USABLE_RX_BD_ALLOC);
11584218423Sdavidch		bce_dump_pg_mbuf_chain(sc, 0, USABLE_PG_BD_ALLOC);
11585157642Sps		bce_dump_l2fhdr(sc, 0, NULL);
11586176448Sdavidch		bce_dump_ctx(sc, RX_CID);
11587176448Sdavidch		bce_dump_ftqs(sc);
11588218423Sdavidch		bce_dump_tx_chain(sc, 0, USABLE_TX_BD_ALLOC);
11589218423Sdavidch		bce_dump_rx_bd_chain(sc, 0, USABLE_RX_BD_ALLOC);
11590218423Sdavidch		bce_dump_pg_chain(sc, 0, USABLE_PG_BD_ALLOC);
11591157642Sps		bce_dump_status_block(sc);
11592157642Sps		bce_dump_stats_block(sc);
11593157642Sps		bce_dump_driver_state(sc);
11594157642Sps		bce_dump_hw_state(sc);
11595170810Sdavidch		bce_dump_bc_state(sc);
11596179771Sdavidch		bce_dump_txp_state(sc, 0);
11597179771Sdavidch		bce_dump_rxp_state(sc, 0);
11598179771Sdavidch		bce_dump_tpat_state(sc, 0);
11599179771Sdavidch		bce_dump_cp_state(sc, 0);
11600182293Sdavidch		bce_dump_com_state(sc, 0);
11601206268Sdavidch		bce_dump_rv2p_state(sc);
11602179695Sdavidch		bce_dump_pgbd(sc, 0, NULL);
11603157642Sps	}
11604157642Sps
11605176448Sdavidch	bce_dump_status_block(sc);
11606157642Sps	bce_dump_driver_state(sc);
11607178132Sdavidch
11608157642Sps	/* Call the debugger. */
11609157642Sps	breakpoint();
11610157642Sps}
11611157642Sps#endif
11612