xref: /dflybsd-src/sys/dev/netif/bce/if_bce.c (revision 030b0c8c4cf27c560ccec70410c8e21934ae677d)
143c2aeb0SSepherosa Ziehau /*-
243c2aeb0SSepherosa Ziehau  * Copyright (c) 2006-2007 Broadcom Corporation
343c2aeb0SSepherosa Ziehau  *	David Christensen <davidch@broadcom.com>.  All rights reserved.
443c2aeb0SSepherosa Ziehau  *
543c2aeb0SSepherosa Ziehau  * Redistribution and use in source and binary forms, with or without
643c2aeb0SSepherosa Ziehau  * modification, are permitted provided that the following conditions
743c2aeb0SSepherosa Ziehau  * are met:
843c2aeb0SSepherosa Ziehau  *
943c2aeb0SSepherosa Ziehau  * 1. Redistributions of source code must retain the above copyright
1043c2aeb0SSepherosa Ziehau  *    notice, this list of conditions and the following disclaimer.
1143c2aeb0SSepherosa Ziehau  * 2. Redistributions in binary form must reproduce the above copyright
1243c2aeb0SSepherosa Ziehau  *    notice, this list of conditions and the following disclaimer in the
1343c2aeb0SSepherosa Ziehau  *    documentation and/or other materials provided with the distribution.
1443c2aeb0SSepherosa Ziehau  * 3. Neither the name of Broadcom Corporation nor the name of its contributors
1543c2aeb0SSepherosa Ziehau  *    may be used to endorse or promote products derived from this software
1643c2aeb0SSepherosa Ziehau  *    without specific prior written consent.
1743c2aeb0SSepherosa Ziehau  *
1843c2aeb0SSepherosa Ziehau  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS'
1943c2aeb0SSepherosa Ziehau  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2043c2aeb0SSepherosa Ziehau  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2143c2aeb0SSepherosa Ziehau  * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
2243c2aeb0SSepherosa Ziehau  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2343c2aeb0SSepherosa Ziehau  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2443c2aeb0SSepherosa Ziehau  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2543c2aeb0SSepherosa Ziehau  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2643c2aeb0SSepherosa Ziehau  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2743c2aeb0SSepherosa Ziehau  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
2843c2aeb0SSepherosa Ziehau  * THE POSSIBILITY OF SUCH DAMAGE.
2943c2aeb0SSepherosa Ziehau  *
3043c2aeb0SSepherosa Ziehau  * $FreeBSD: src/sys/dev/bce/if_bce.c,v 1.31 2007/05/16 23:34:11 davidch Exp $
3143c2aeb0SSepherosa Ziehau  */
3243c2aeb0SSepherosa Ziehau 
3343c2aeb0SSepherosa Ziehau /*
3443c2aeb0SSepherosa Ziehau  * The following controllers are supported by this driver:
3543c2aeb0SSepherosa Ziehau  *   BCM5706C A2, A3
36d0092544SSepherosa Ziehau  *   BCM5706S A2, A3
3743c2aeb0SSepherosa Ziehau  *   BCM5708C B1, B2
38d0092544SSepherosa Ziehau  *   BCM5708S B1, B2
39f358071bSSepherosa Ziehau  *   BCM5709C A1, B2, C0
40d0092544SSepherosa Ziehau  *   BCM5716  C0
4143c2aeb0SSepherosa Ziehau  *
4243c2aeb0SSepherosa Ziehau  * The following controllers are not supported by this driver:
4343c2aeb0SSepherosa Ziehau  *   BCM5706C A0, A1
44d0092544SSepherosa Ziehau  *   BCM5706S A0, A1
4543c2aeb0SSepherosa Ziehau  *   BCM5708C A0, B0
46d0092544SSepherosa Ziehau  *   BCM5708S A0, B0
47d0092544SSepherosa Ziehau  *   BCM5709C A0, B0, B1
48d0092544SSepherosa Ziehau  *   BCM5709S A0, A1, B0, B1, B2, C0
49b42386eeSSepherosa Ziehau  *
50b42386eeSSepherosa Ziehau  *
51b42386eeSSepherosa Ziehau  * Note about MSI-X on 5709/5716:
52b42386eeSSepherosa Ziehau  * - 9 MSI-X vectors are supported.
53b42386eeSSepherosa Ziehau  * - MSI-X vectors, RX/TX rings and status blocks' association
54b42386eeSSepherosa Ziehau  *   are fixed:
55b42386eeSSepherosa Ziehau  *   o  The first RX ring and the first TX ring use the first
56b42386eeSSepherosa Ziehau  *      status block.
57b42386eeSSepherosa Ziehau  *   o  The first MSI-X vector is associated with the first
58b42386eeSSepherosa Ziehau  *      status block.
59b42386eeSSepherosa Ziehau  *   o  The second RX ring and the second TX ring use the second
60b42386eeSSepherosa Ziehau  *      status block.
61b42386eeSSepherosa Ziehau  *   o  The second MSI-X vector is associated with the second
62b42386eeSSepherosa Ziehau  *      status block.
63b42386eeSSepherosa Ziehau  *   ...
64b42386eeSSepherosa Ziehau  *   and so on so forth.
65b42386eeSSepherosa Ziehau  * - Status blocks must reside in physically contiguous memory
66b42386eeSSepherosa Ziehau  *   and each status block consumes 128bytes.  In addition to
67b42386eeSSepherosa Ziehau  *   this, the memory for the status blocks is aligned on 128bytes
68b42386eeSSepherosa Ziehau  *   in this driver.  (see bce_dma_alloc() and HC_CONFIG)
69b42386eeSSepherosa Ziehau  * - Each status block has its own coalesce parameters, which also
70b42386eeSSepherosa Ziehau  *   serve as the related MSI-X vector's interrupt moderation
71b42386eeSSepherosa Ziehau  *   parameters.  (see bce_coal_change())
7243c2aeb0SSepherosa Ziehau  */
7343c2aeb0SSepherosa Ziehau 
7443c2aeb0SSepherosa Ziehau #include "opt_bce.h"
754a331bf7SSepherosa Ziehau #include "opt_ifpoll.h"
7643c2aeb0SSepherosa Ziehau 
7743c2aeb0SSepherosa Ziehau #include <sys/param.h>
7843c2aeb0SSepherosa Ziehau #include <sys/bus.h>
7943c2aeb0SSepherosa Ziehau #include <sys/endian.h>
8043c2aeb0SSepherosa Ziehau #include <sys/kernel.h>
819db4b353SSepherosa Ziehau #include <sys/interrupt.h>
8243c2aeb0SSepherosa Ziehau #include <sys/mbuf.h>
8343c2aeb0SSepherosa Ziehau #include <sys/malloc.h>
8443c2aeb0SSepherosa Ziehau #include <sys/queue.h>
8543c2aeb0SSepherosa Ziehau #include <sys/rman.h>
8643c2aeb0SSepherosa Ziehau #include <sys/serialize.h>
8743c2aeb0SSepherosa Ziehau #include <sys/socket.h>
8843c2aeb0SSepherosa Ziehau #include <sys/sockio.h>
8943c2aeb0SSepherosa Ziehau #include <sys/sysctl.h>
9043c2aeb0SSepherosa Ziehau 
91eefd160dSSepherosa Ziehau #include <netinet/ip.h>
92eefd160dSSepherosa Ziehau #include <netinet/tcp.h>
93eefd160dSSepherosa Ziehau 
9443c2aeb0SSepherosa Ziehau #include <net/bpf.h>
9543c2aeb0SSepherosa Ziehau #include <net/ethernet.h>
9643c2aeb0SSepherosa Ziehau #include <net/if.h>
9743c2aeb0SSepherosa Ziehau #include <net/if_arp.h>
9843c2aeb0SSepherosa Ziehau #include <net/if_dl.h>
9943c2aeb0SSepherosa Ziehau #include <net/if_media.h>
1004a331bf7SSepherosa Ziehau #include <net/if_poll.h>
10143c2aeb0SSepherosa Ziehau #include <net/if_types.h>
10243c2aeb0SSepherosa Ziehau #include <net/ifq_var.h>
10339ea245fSSepherosa Ziehau #include <net/if_ringmap.h>
104b42386eeSSepherosa Ziehau #include <net/toeplitz.h>
105b42386eeSSepherosa Ziehau #include <net/toeplitz2.h>
10643c2aeb0SSepherosa Ziehau #include <net/vlan/if_vlan_var.h>
107b637f170SSepherosa Ziehau #include <net/vlan/if_vlan_ether.h>
10843c2aeb0SSepherosa Ziehau 
10943c2aeb0SSepherosa Ziehau #include <dev/netif/mii_layer/mii.h>
11043c2aeb0SSepherosa Ziehau #include <dev/netif/mii_layer/miivar.h>
111f31c6e4dSSepherosa Ziehau #include <dev/netif/mii_layer/brgphyreg.h>
11243c2aeb0SSepherosa Ziehau 
11343c2aeb0SSepherosa Ziehau #include <bus/pci/pcireg.h>
11443c2aeb0SSepherosa Ziehau #include <bus/pci/pcivar.h>
11543c2aeb0SSepherosa Ziehau 
11643c2aeb0SSepherosa Ziehau #include "miibus_if.h"
11743c2aeb0SSepherosa Ziehau 
1189382dc55SSepherosa Ziehau #include <dev/netif/bce/if_bcereg.h>
1199382dc55SSepherosa Ziehau #include <dev/netif/bce/if_bcefw.h>
12043c2aeb0SSepherosa Ziehau 
12128ef7645SSepherosa Ziehau #define BCE_MSI_CKINTVL		((10 * hz) / 1000)	/* 10ms */
12228ef7645SSepherosa Ziehau 
123b42386eeSSepherosa Ziehau #ifdef BCE_RSS_DEBUG
124b42386eeSSepherosa Ziehau #define BCE_RSS_DPRINTF(sc, lvl, fmt, ...) \
125b42386eeSSepherosa Ziehau do { \
126b42386eeSSepherosa Ziehau 	if (sc->rss_debug >= lvl) \
127b42386eeSSepherosa Ziehau 		if_printf(&sc->arpcom.ac_if, fmt, __VA_ARGS__); \
128b42386eeSSepherosa Ziehau } while (0)
129b42386eeSSepherosa Ziehau #else	/* !BCE_RSS_DEBUG */
130b42386eeSSepherosa Ziehau #define BCE_RSS_DPRINTF(sc, lvl, fmt, ...)	((void)0)
131b42386eeSSepherosa Ziehau #endif	/* BCE_RSS_DEBUG */
132b42386eeSSepherosa Ziehau 
13343c2aeb0SSepherosa Ziehau /****************************************************************************/
13443c2aeb0SSepherosa Ziehau /* PCI Device ID Table                                                      */
13543c2aeb0SSepherosa Ziehau /*                                                                          */
13643c2aeb0SSepherosa Ziehau /* Used by bce_probe() to identify the devices supported by this driver.    */
13743c2aeb0SSepherosa Ziehau /****************************************************************************/
13843c2aeb0SSepherosa Ziehau #define BCE_DEVDESC_MAX		64
13943c2aeb0SSepherosa Ziehau 
14043c2aeb0SSepherosa Ziehau static struct bce_type bce_devs[] = {
14143c2aeb0SSepherosa Ziehau 	/* BCM5706C Controllers and OEM boards. */
14243c2aeb0SSepherosa Ziehau 	{ BRCM_VENDORID, BRCM_DEVICEID_BCM5706,  HP_VENDORID, 0x3101,
14343c2aeb0SSepherosa Ziehau 		"HP NC370T Multifunction Gigabit Server Adapter" },
14443c2aeb0SSepherosa Ziehau 	{ BRCM_VENDORID, BRCM_DEVICEID_BCM5706,  HP_VENDORID, 0x3106,
14543c2aeb0SSepherosa Ziehau 		"HP NC370i Multifunction Gigabit Server Adapter" },
1463482f06cSSepherosa Ziehau 	{ BRCM_VENDORID, BRCM_DEVICEID_BCM5706,  HP_VENDORID, 0x3070,
1473482f06cSSepherosa Ziehau 		"HP NC380T PCIe DP Multifunc Gig Server Adapter" },
1483482f06cSSepherosa Ziehau 	{ BRCM_VENDORID, BRCM_DEVICEID_BCM5706,  HP_VENDORID, 0x1709,
1493482f06cSSepherosa Ziehau 		"HP NC371i Multifunction Gigabit Server Adapter" },
15043c2aeb0SSepherosa Ziehau 	{ BRCM_VENDORID, BRCM_DEVICEID_BCM5706,  PCI_ANY_ID,  PCI_ANY_ID,
15143c2aeb0SSepherosa Ziehau 		"Broadcom NetXtreme II BCM5706 1000Base-T" },
15243c2aeb0SSepherosa Ziehau 
15343c2aeb0SSepherosa Ziehau 	/* BCM5706S controllers and OEM boards. */
15443c2aeb0SSepherosa Ziehau 	{ BRCM_VENDORID, BRCM_DEVICEID_BCM5706S, HP_VENDORID, 0x3102,
15543c2aeb0SSepherosa Ziehau 		"HP NC370F Multifunction Gigabit Server Adapter" },
15643c2aeb0SSepherosa Ziehau 	{ BRCM_VENDORID, BRCM_DEVICEID_BCM5706S, PCI_ANY_ID,  PCI_ANY_ID,
15743c2aeb0SSepherosa Ziehau 		"Broadcom NetXtreme II BCM5706 1000Base-SX" },
15843c2aeb0SSepherosa Ziehau 
15943c2aeb0SSepherosa Ziehau 	/* BCM5708C controllers and OEM boards. */
1603482f06cSSepherosa Ziehau 	{ BRCM_VENDORID, BRCM_DEVICEID_BCM5708,  HP_VENDORID, 0x7037,
1613482f06cSSepherosa Ziehau 		"HP NC373T PCIe Multifunction Gig Server Adapter" },
1623482f06cSSepherosa Ziehau 	{ BRCM_VENDORID, BRCM_DEVICEID_BCM5708,  HP_VENDORID, 0x7038,
1633482f06cSSepherosa Ziehau 		"HP NC373i Multifunction Gigabit Server Adapter" },
1643482f06cSSepherosa Ziehau 	{ BRCM_VENDORID, BRCM_DEVICEID_BCM5708,  HP_VENDORID, 0x7045,
1653482f06cSSepherosa Ziehau 		"HP NC374m PCIe Multifunction Adapter" },
16643c2aeb0SSepherosa Ziehau 	{ BRCM_VENDORID, BRCM_DEVICEID_BCM5708,  PCI_ANY_ID,  PCI_ANY_ID,
16743c2aeb0SSepherosa Ziehau 		"Broadcom NetXtreme II BCM5708 1000Base-T" },
16843c2aeb0SSepherosa Ziehau 
16943c2aeb0SSepherosa Ziehau 	/* BCM5708S controllers and OEM boards. */
1703482f06cSSepherosa Ziehau 	{ BRCM_VENDORID, BRCM_DEVICEID_BCM5708S,  HP_VENDORID, 0x1706,
1713482f06cSSepherosa Ziehau 		"HP NC373m Multifunction Gigabit Server Adapter" },
1723482f06cSSepherosa Ziehau 	{ BRCM_VENDORID, BRCM_DEVICEID_BCM5708S,  HP_VENDORID, 0x703b,
1733482f06cSSepherosa Ziehau 		"HP NC373i Multifunction Gigabit Server Adapter" },
1743482f06cSSepherosa Ziehau 	{ BRCM_VENDORID, BRCM_DEVICEID_BCM5708S,  HP_VENDORID, 0x703d,
1753482f06cSSepherosa Ziehau 		"HP NC373F PCIe Multifunc Giga Server Adapter" },
17643c2aeb0SSepherosa Ziehau 	{ BRCM_VENDORID, BRCM_DEVICEID_BCM5708S,  PCI_ANY_ID,  PCI_ANY_ID,
17743c2aeb0SSepherosa Ziehau 		"Broadcom NetXtreme II BCM5708S 1000Base-T" },
178d0092544SSepherosa Ziehau 
179d0092544SSepherosa Ziehau 	/* BCM5709C controllers and OEM boards. */
1803482f06cSSepherosa Ziehau 	{ BRCM_VENDORID, BRCM_DEVICEID_BCM5709,  HP_VENDORID, 0x7055,
1813482f06cSSepherosa Ziehau 		"HP NC382i DP Multifunction Gigabit Server Adapter" },
1823482f06cSSepherosa Ziehau 	{ BRCM_VENDORID, BRCM_DEVICEID_BCM5709,  HP_VENDORID, 0x7059,
1833482f06cSSepherosa Ziehau 		"HP NC382T PCIe DP Multifunction Gigabit Server Adapter" },
184d0092544SSepherosa Ziehau 	{ BRCM_VENDORID, BRCM_DEVICEID_BCM5709,  PCI_ANY_ID,  PCI_ANY_ID,
185d0092544SSepherosa Ziehau 		"Broadcom NetXtreme II BCM5709 1000Base-T" },
186d0092544SSepherosa Ziehau 
187d0092544SSepherosa Ziehau 	/* BCM5709S controllers and OEM boards. */
1883482f06cSSepherosa Ziehau 	{ BRCM_VENDORID, BRCM_DEVICEID_BCM5709S,  HP_VENDORID, 0x171d,
1893482f06cSSepherosa Ziehau 		"HP NC382m DP 1GbE Multifunction BL-c Adapter" },
1903482f06cSSepherosa Ziehau 	{ BRCM_VENDORID, BRCM_DEVICEID_BCM5709S,  HP_VENDORID, 0x7056,
1913482f06cSSepherosa Ziehau 		"HP NC382i DP Multifunction Gigabit Server Adapter" },
192d0092544SSepherosa Ziehau 	{ BRCM_VENDORID, BRCM_DEVICEID_BCM5709S,  PCI_ANY_ID,  PCI_ANY_ID,
193d0092544SSepherosa Ziehau 		"Broadcom NetXtreme II BCM5709 1000Base-SX" },
194d0092544SSepherosa Ziehau 
195d0092544SSepherosa Ziehau 	/* BCM5716 controllers and OEM boards. */
196d0092544SSepherosa Ziehau 	{ BRCM_VENDORID, BRCM_DEVICEID_BCM5716,   PCI_ANY_ID,  PCI_ANY_ID,
197d0092544SSepherosa Ziehau 		"Broadcom NetXtreme II BCM5716 1000Base-T" },
198d0092544SSepherosa Ziehau 
19943c2aeb0SSepherosa Ziehau 	{ 0, 0, 0, 0, NULL }
20043c2aeb0SSepherosa Ziehau };
20143c2aeb0SSepherosa Ziehau 
20243c2aeb0SSepherosa Ziehau /****************************************************************************/
20343c2aeb0SSepherosa Ziehau /* Supported Flash NVRAM device data.                                       */
20443c2aeb0SSepherosa Ziehau /****************************************************************************/
20543c2aeb0SSepherosa Ziehau static const struct flash_spec flash_table[] =
20643c2aeb0SSepherosa Ziehau {
207d0092544SSepherosa Ziehau #define BUFFERED_FLAGS		(BCE_NV_BUFFERED | BCE_NV_TRANSLATE)
208d0092544SSepherosa Ziehau #define NONBUFFERED_FLAGS	(BCE_NV_WREN)
209d0092544SSepherosa Ziehau 
21043c2aeb0SSepherosa Ziehau 	/* Slow EEPROM */
21143c2aeb0SSepherosa Ziehau 	{0x00000000, 0x40830380, 0x009f0081, 0xa184a053, 0xaf000400,
212d0092544SSepherosa Ziehau 	 BUFFERED_FLAGS, SEEPROM_PAGE_BITS, SEEPROM_PAGE_SIZE,
21343c2aeb0SSepherosa Ziehau 	 SEEPROM_BYTE_ADDR_MASK, SEEPROM_TOTAL_SIZE,
21443c2aeb0SSepherosa Ziehau 	 "EEPROM - slow"},
21543c2aeb0SSepherosa Ziehau 	/* Expansion entry 0001 */
21643c2aeb0SSepherosa Ziehau 	{0x08000002, 0x4b808201, 0x00050081, 0x03840253, 0xaf020406,
217d0092544SSepherosa Ziehau 	 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
21843c2aeb0SSepherosa Ziehau 	 SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
21943c2aeb0SSepherosa Ziehau 	 "Entry 0001"},
22043c2aeb0SSepherosa Ziehau 	/* Saifun SA25F010 (non-buffered flash) */
22143c2aeb0SSepherosa Ziehau 	/* strap, cfg1, & write1 need updates */
22243c2aeb0SSepherosa Ziehau 	{0x04000001, 0x47808201, 0x00050081, 0x03840253, 0xaf020406,
223d0092544SSepherosa Ziehau 	 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
22443c2aeb0SSepherosa Ziehau 	 SAIFUN_FLASH_BYTE_ADDR_MASK, SAIFUN_FLASH_BASE_TOTAL_SIZE*2,
22543c2aeb0SSepherosa Ziehau 	 "Non-buffered flash (128kB)"},
22643c2aeb0SSepherosa Ziehau 	/* Saifun SA25F020 (non-buffered flash) */
22743c2aeb0SSepherosa Ziehau 	/* strap, cfg1, & write1 need updates */
22843c2aeb0SSepherosa Ziehau 	{0x0c000003, 0x4f808201, 0x00050081, 0x03840253, 0xaf020406,
229d0092544SSepherosa Ziehau 	 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
23043c2aeb0SSepherosa Ziehau 	 SAIFUN_FLASH_BYTE_ADDR_MASK, SAIFUN_FLASH_BASE_TOTAL_SIZE*4,
23143c2aeb0SSepherosa Ziehau 	 "Non-buffered flash (256kB)"},
23243c2aeb0SSepherosa Ziehau 	/* Expansion entry 0100 */
23343c2aeb0SSepherosa Ziehau 	{0x11000000, 0x53808201, 0x00050081, 0x03840253, 0xaf020406,
234d0092544SSepherosa Ziehau 	 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
23543c2aeb0SSepherosa Ziehau 	 SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
23643c2aeb0SSepherosa Ziehau 	 "Entry 0100"},
23743c2aeb0SSepherosa Ziehau 	/* Entry 0101: ST M45PE10 (non-buffered flash, TetonII B0) */
23843c2aeb0SSepherosa Ziehau 	{0x19000002, 0x5b808201, 0x000500db, 0x03840253, 0xaf020406,
239d0092544SSepherosa Ziehau 	 NONBUFFERED_FLAGS, ST_MICRO_FLASH_PAGE_BITS, ST_MICRO_FLASH_PAGE_SIZE,
24043c2aeb0SSepherosa Ziehau 	 ST_MICRO_FLASH_BYTE_ADDR_MASK, ST_MICRO_FLASH_BASE_TOTAL_SIZE*2,
24143c2aeb0SSepherosa Ziehau 	 "Entry 0101: ST M45PE10 (128kB non-bufferred)"},
24243c2aeb0SSepherosa Ziehau 	/* Entry 0110: ST M45PE20 (non-buffered flash)*/
24343c2aeb0SSepherosa Ziehau 	{0x15000001, 0x57808201, 0x000500db, 0x03840253, 0xaf020406,
244d0092544SSepherosa Ziehau 	 NONBUFFERED_FLAGS, ST_MICRO_FLASH_PAGE_BITS, ST_MICRO_FLASH_PAGE_SIZE,
24543c2aeb0SSepherosa Ziehau 	 ST_MICRO_FLASH_BYTE_ADDR_MASK, ST_MICRO_FLASH_BASE_TOTAL_SIZE*4,
24643c2aeb0SSepherosa Ziehau 	 "Entry 0110: ST M45PE20 (256kB non-bufferred)"},
24743c2aeb0SSepherosa Ziehau 	/* Saifun SA25F005 (non-buffered flash) */
24843c2aeb0SSepherosa Ziehau 	/* strap, cfg1, & write1 need updates */
24943c2aeb0SSepherosa Ziehau 	{0x1d000003, 0x5f808201, 0x00050081, 0x03840253, 0xaf020406,
250d0092544SSepherosa Ziehau 	 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
25143c2aeb0SSepherosa Ziehau 	 SAIFUN_FLASH_BYTE_ADDR_MASK, SAIFUN_FLASH_BASE_TOTAL_SIZE,
25243c2aeb0SSepherosa Ziehau 	 "Non-buffered flash (64kB)"},
25343c2aeb0SSepherosa Ziehau 	/* Fast EEPROM */
25443c2aeb0SSepherosa Ziehau 	{0x22000000, 0x62808380, 0x009f0081, 0xa184a053, 0xaf000400,
255d0092544SSepherosa Ziehau 	 BUFFERED_FLAGS, SEEPROM_PAGE_BITS, SEEPROM_PAGE_SIZE,
25643c2aeb0SSepherosa Ziehau 	 SEEPROM_BYTE_ADDR_MASK, SEEPROM_TOTAL_SIZE,
25743c2aeb0SSepherosa Ziehau 	 "EEPROM - fast"},
25843c2aeb0SSepherosa Ziehau 	/* Expansion entry 1001 */
25943c2aeb0SSepherosa Ziehau 	{0x2a000002, 0x6b808201, 0x00050081, 0x03840253, 0xaf020406,
260d0092544SSepherosa Ziehau 	 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
26143c2aeb0SSepherosa Ziehau 	 SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
26243c2aeb0SSepherosa Ziehau 	 "Entry 1001"},
26343c2aeb0SSepherosa Ziehau 	/* Expansion entry 1010 */
26443c2aeb0SSepherosa Ziehau 	{0x26000001, 0x67808201, 0x00050081, 0x03840253, 0xaf020406,
265d0092544SSepherosa Ziehau 	 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
26643c2aeb0SSepherosa Ziehau 	 SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
26743c2aeb0SSepherosa Ziehau 	 "Entry 1010"},
26843c2aeb0SSepherosa Ziehau 	/* ATMEL AT45DB011B (buffered flash) */
26943c2aeb0SSepherosa Ziehau 	{0x2e000003, 0x6e808273, 0x00570081, 0x68848353, 0xaf000400,
270d0092544SSepherosa Ziehau 	 BUFFERED_FLAGS, BUFFERED_FLASH_PAGE_BITS, BUFFERED_FLASH_PAGE_SIZE,
27143c2aeb0SSepherosa Ziehau 	 BUFFERED_FLASH_BYTE_ADDR_MASK, BUFFERED_FLASH_TOTAL_SIZE,
27243c2aeb0SSepherosa Ziehau 	 "Buffered flash (128kB)"},
27343c2aeb0SSepherosa Ziehau 	/* Expansion entry 1100 */
27443c2aeb0SSepherosa Ziehau 	{0x33000000, 0x73808201, 0x00050081, 0x03840253, 0xaf020406,
275d0092544SSepherosa Ziehau 	 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
27643c2aeb0SSepherosa Ziehau 	 SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
27743c2aeb0SSepherosa Ziehau 	 "Entry 1100"},
27843c2aeb0SSepherosa Ziehau 	/* Expansion entry 1101 */
27943c2aeb0SSepherosa Ziehau 	{0x3b000002, 0x7b808201, 0x00050081, 0x03840253, 0xaf020406,
280d0092544SSepherosa Ziehau 	 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
28143c2aeb0SSepherosa Ziehau 	 SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
28243c2aeb0SSepherosa Ziehau 	 "Entry 1101"},
28343c2aeb0SSepherosa Ziehau 	/* Ateml Expansion entry 1110 */
28443c2aeb0SSepherosa Ziehau 	{0x37000001, 0x76808273, 0x00570081, 0x68848353, 0xaf000400,
285d0092544SSepherosa Ziehau 	 BUFFERED_FLAGS, BUFFERED_FLASH_PAGE_BITS, BUFFERED_FLASH_PAGE_SIZE,
28643c2aeb0SSepherosa Ziehau 	 BUFFERED_FLASH_BYTE_ADDR_MASK, 0,
28743c2aeb0SSepherosa Ziehau 	 "Entry 1110 (Atmel)"},
28843c2aeb0SSepherosa Ziehau 	/* ATMEL AT45DB021B (buffered flash) */
28943c2aeb0SSepherosa Ziehau 	{0x3f000003, 0x7e808273, 0x00570081, 0x68848353, 0xaf000400,
290d0092544SSepherosa Ziehau 	 BUFFERED_FLAGS, BUFFERED_FLASH_PAGE_BITS, BUFFERED_FLASH_PAGE_SIZE,
29143c2aeb0SSepherosa Ziehau 	 BUFFERED_FLASH_BYTE_ADDR_MASK, BUFFERED_FLASH_TOTAL_SIZE*2,
29243c2aeb0SSepherosa Ziehau 	 "Buffered flash (256kB)"},
29343c2aeb0SSepherosa Ziehau };
29443c2aeb0SSepherosa Ziehau 
295d0092544SSepherosa Ziehau /*
296d0092544SSepherosa Ziehau  * The BCM5709 controllers transparently handle the
297d0092544SSepherosa Ziehau  * differences between Atmel 264 byte pages and all
298d0092544SSepherosa Ziehau  * flash devices which use 256 byte pages, so no
299d0092544SSepherosa Ziehau  * logical-to-physical mapping is required in the
300d0092544SSepherosa Ziehau  * driver.
301d0092544SSepherosa Ziehau  */
302d0092544SSepherosa Ziehau static struct flash_spec flash_5709 = {
303d0092544SSepherosa Ziehau 	.flags		= BCE_NV_BUFFERED,
304d0092544SSepherosa Ziehau 	.page_bits	= BCM5709_FLASH_PAGE_BITS,
305d0092544SSepherosa Ziehau 	.page_size	= BCM5709_FLASH_PAGE_SIZE,
306d0092544SSepherosa Ziehau 	.addr_mask	= BCM5709_FLASH_BYTE_ADDR_MASK,
307d0092544SSepherosa Ziehau 	.total_size	= BUFFERED_FLASH_TOTAL_SIZE * 2,
308d0092544SSepherosa Ziehau 	.name		= "5709/5716 buffered flash (256kB)",
309d0092544SSepherosa Ziehau };
310d0092544SSepherosa Ziehau 
31143c2aeb0SSepherosa Ziehau /****************************************************************************/
31243c2aeb0SSepherosa Ziehau /* DragonFly device entry points.                                           */
31343c2aeb0SSepherosa Ziehau /****************************************************************************/
31443c2aeb0SSepherosa Ziehau static int	bce_probe(device_t);
31543c2aeb0SSepherosa Ziehau static int	bce_attach(device_t);
31643c2aeb0SSepherosa Ziehau static int	bce_detach(device_t);
31743c2aeb0SSepherosa Ziehau static void	bce_shutdown(device_t);
3188aca6ad9SSepherosa Ziehau static int	bce_miibus_read_reg(device_t, int, int);
3198aca6ad9SSepherosa Ziehau static int	bce_miibus_write_reg(device_t, int, int, int);
3208aca6ad9SSepherosa Ziehau static void	bce_miibus_statchg(device_t);
32143c2aeb0SSepherosa Ziehau 
32243c2aeb0SSepherosa Ziehau /****************************************************************************/
32343c2aeb0SSepherosa Ziehau /* BCE Register/Memory Access Routines                                      */
32443c2aeb0SSepherosa Ziehau /****************************************************************************/
32543c2aeb0SSepherosa Ziehau static uint32_t	bce_reg_rd_ind(struct bce_softc *, uint32_t);
32643c2aeb0SSepherosa Ziehau static void	bce_reg_wr_ind(struct bce_softc *, uint32_t, uint32_t);
327bc30d40dSSepherosa Ziehau static void	bce_shmem_wr(struct bce_softc *, uint32_t, uint32_t);
328bc30d40dSSepherosa Ziehau static uint32_t	bce_shmem_rd(struct bce_softc *, u32);
32943c2aeb0SSepherosa Ziehau static void	bce_ctx_wr(struct bce_softc *, uint32_t, uint32_t, uint32_t);
33043c2aeb0SSepherosa Ziehau 
33143c2aeb0SSepherosa Ziehau /****************************************************************************/
33243c2aeb0SSepherosa Ziehau /* BCE NVRAM Access Routines                                                */
33343c2aeb0SSepherosa Ziehau /****************************************************************************/
33443c2aeb0SSepherosa Ziehau static int	bce_acquire_nvram_lock(struct bce_softc *);
33543c2aeb0SSepherosa Ziehau static int	bce_release_nvram_lock(struct bce_softc *);
33643c2aeb0SSepherosa Ziehau static void	bce_enable_nvram_access(struct bce_softc *);
33743c2aeb0SSepherosa Ziehau static void	bce_disable_nvram_access(struct bce_softc *);
33843c2aeb0SSepherosa Ziehau static int	bce_nvram_read_dword(struct bce_softc *, uint32_t, uint8_t *,
33943c2aeb0SSepherosa Ziehau 		    uint32_t);
34043c2aeb0SSepherosa Ziehau static int	bce_init_nvram(struct bce_softc *);
34143c2aeb0SSepherosa Ziehau static int	bce_nvram_read(struct bce_softc *, uint32_t, uint8_t *, int);
34243c2aeb0SSepherosa Ziehau static int	bce_nvram_test(struct bce_softc *);
34343c2aeb0SSepherosa Ziehau 
34443c2aeb0SSepherosa Ziehau /****************************************************************************/
34543c2aeb0SSepherosa Ziehau /* BCE DMA Allocate/Free Routines                                           */
34643c2aeb0SSepherosa Ziehau /****************************************************************************/
34743c2aeb0SSepherosa Ziehau static int	bce_dma_alloc(struct bce_softc *);
34843c2aeb0SSepherosa Ziehau static void	bce_dma_free(struct bce_softc *);
34943c2aeb0SSepherosa Ziehau static void	bce_dma_map_addr(void *, bus_dma_segment_t *, int, int);
35043c2aeb0SSepherosa Ziehau 
35143c2aeb0SSepherosa Ziehau /****************************************************************************/
35243c2aeb0SSepherosa Ziehau /* BCE Firmware Synchronization and Load                                    */
35343c2aeb0SSepherosa Ziehau /****************************************************************************/
35443c2aeb0SSepherosa Ziehau static int	bce_fw_sync(struct bce_softc *, uint32_t);
35543c2aeb0SSepherosa Ziehau static void	bce_load_rv2p_fw(struct bce_softc *, uint32_t *,
35643c2aeb0SSepherosa Ziehau 		    uint32_t, uint32_t);
35743c2aeb0SSepherosa Ziehau static void	bce_load_cpu_fw(struct bce_softc *, struct cpu_reg *,
35843c2aeb0SSepherosa Ziehau 		    struct fw_info *);
3595d05a208SSepherosa Ziehau static void	bce_start_cpu(struct bce_softc *, struct cpu_reg *);
3605d05a208SSepherosa Ziehau static void	bce_halt_cpu(struct bce_softc *, struct cpu_reg *);
3615d05a208SSepherosa Ziehau static void	bce_start_rxp_cpu(struct bce_softc *);
362d0092544SSepherosa Ziehau static void	bce_init_rxp_cpu(struct bce_softc *);
363d0092544SSepherosa Ziehau static void	bce_init_txp_cpu(struct bce_softc *);
364d0092544SSepherosa Ziehau static void	bce_init_tpat_cpu(struct bce_softc *);
365d0092544SSepherosa Ziehau static void	bce_init_cp_cpu(struct bce_softc *);
366d0092544SSepherosa Ziehau static void	bce_init_com_cpu(struct bce_softc *);
36743c2aeb0SSepherosa Ziehau static void	bce_init_cpus(struct bce_softc *);
368b42386eeSSepherosa Ziehau static void	bce_setup_msix_table(struct bce_softc *);
369b42386eeSSepherosa Ziehau static void	bce_init_rss(struct bce_softc *);
37043c2aeb0SSepherosa Ziehau 
37143c2aeb0SSepherosa Ziehau static void	bce_stop(struct bce_softc *);
37243c2aeb0SSepherosa Ziehau static int	bce_reset(struct bce_softc *, uint32_t);
37343c2aeb0SSepherosa Ziehau static int	bce_chipinit(struct bce_softc *);
37443c2aeb0SSepherosa Ziehau static int	bce_blockinit(struct bce_softc *);
375d0092544SSepherosa Ziehau static void	bce_probe_pci_caps(struct bce_softc *);
376d0092544SSepherosa Ziehau static void	bce_print_adapter_info(struct bce_softc *);
377d0092544SSepherosa Ziehau static void	bce_get_media(struct bce_softc *);
3788aca6ad9SSepherosa Ziehau static void	bce_mgmt_init(struct bce_softc *);
3798aca6ad9SSepherosa Ziehau static int	bce_init_ctx(struct bce_softc *);
3808aca6ad9SSepherosa Ziehau static void	bce_get_mac_addr(struct bce_softc *);
3818aca6ad9SSepherosa Ziehau static void	bce_set_mac_addr(struct bce_softc *);
3828aca6ad9SSepherosa Ziehau static void	bce_set_rx_mode(struct bce_softc *);
3838aca6ad9SSepherosa Ziehau static void	bce_coal_change(struct bce_softc *);
384b42386eeSSepherosa Ziehau static void	bce_npoll_coal_change(struct bce_softc *);
38584464af5SSepherosa Ziehau static void	bce_setup_serialize(struct bce_softc *);
38684464af5SSepherosa Ziehau static void	bce_serialize_skipmain(struct bce_softc *);
38784464af5SSepherosa Ziehau static void	bce_deserialize_skipmain(struct bce_softc *);
388745b3d68SSepherosa Ziehau static void	bce_set_timer_cpuid(struct bce_softc *, boolean_t);
389b42386eeSSepherosa Ziehau static int	bce_alloc_intr(struct bce_softc *);
390b42386eeSSepherosa Ziehau static void	bce_free_intr(struct bce_softc *);
391b42386eeSSepherosa Ziehau static void	bce_try_alloc_msix(struct bce_softc *);
392b42386eeSSepherosa Ziehau static void	bce_free_msix(struct bce_softc *, boolean_t);
393b42386eeSSepherosa Ziehau static void	bce_setup_ring_cnt(struct bce_softc *);
394b42386eeSSepherosa Ziehau static int	bce_setup_intr(struct bce_softc *);
395b42386eeSSepherosa Ziehau static void	bce_teardown_intr(struct bce_softc *);
396b42386eeSSepherosa Ziehau static int	bce_setup_msix(struct bce_softc *);
397b42386eeSSepherosa Ziehau static void	bce_teardown_msix(struct bce_softc *, int);
39843c2aeb0SSepherosa Ziehau 
39910bcbdabSSepherosa Ziehau static int	bce_create_tx_ring(struct bce_tx_ring *);
40010bcbdabSSepherosa Ziehau static void	bce_destroy_tx_ring(struct bce_tx_ring *);
40110bcbdabSSepherosa Ziehau static void	bce_init_tx_context(struct bce_tx_ring *);
40210bcbdabSSepherosa Ziehau static int	bce_init_tx_chain(struct bce_tx_ring *);
40310bcbdabSSepherosa Ziehau static void	bce_free_tx_chain(struct bce_tx_ring *);
4048aca6ad9SSepherosa Ziehau static void	bce_xmit(struct bce_tx_ring *);
4058aca6ad9SSepherosa Ziehau static int	bce_encap(struct bce_tx_ring *, struct mbuf **, int *);
4068aca6ad9SSepherosa Ziehau static int	bce_tso_setup(struct bce_tx_ring *, struct mbuf **,
4078aca6ad9SSepherosa Ziehau 		    uint16_t *, uint16_t *);
4088aca6ad9SSepherosa Ziehau 
40908b64767SSepherosa Ziehau static int	bce_create_rx_ring(struct bce_rx_ring *);
41008b64767SSepherosa Ziehau static void	bce_destroy_rx_ring(struct bce_rx_ring *);
41108b64767SSepherosa Ziehau static void	bce_init_rx_context(struct bce_rx_ring *);
41208b64767SSepherosa Ziehau static int	bce_init_rx_chain(struct bce_rx_ring *);
41308b64767SSepherosa Ziehau static void	bce_free_rx_chain(struct bce_rx_ring *);
41486ae632dSSepherosa Ziehau static int	bce_newbuf_std(struct bce_rx_ring *, uint16_t *, uint16_t,
4158aca6ad9SSepherosa Ziehau 		    uint32_t *, int);
4168aca6ad9SSepherosa Ziehau static void	bce_setup_rxdesc_std(struct bce_rx_ring *, uint16_t,
4178aca6ad9SSepherosa Ziehau 		    uint32_t *);
41842ad0e07SSepherosa Ziehau static struct pktinfo *bce_rss_pktinfo(struct pktinfo *, uint32_t,
41942ad0e07SSepherosa Ziehau 		    const struct l2_fhdr *);
42043c2aeb0SSepherosa Ziehau 
421f0a26983SSepherosa Ziehau static void	bce_start(struct ifnet *, struct ifaltq_subque *);
42243c2aeb0SSepherosa Ziehau static int	bce_ioctl(struct ifnet *, u_long, caddr_t, struct ucred *);
423f774fa0fSSepherosa Ziehau static void	bce_watchdog(struct ifaltq_subque *);
42443c2aeb0SSepherosa Ziehau static int	bce_ifmedia_upd(struct ifnet *);
42543c2aeb0SSepherosa Ziehau static void	bce_ifmedia_sts(struct ifnet *, struct ifmediareq *);
42643c2aeb0SSepherosa Ziehau static void	bce_init(void *);
4274a331bf7SSepherosa Ziehau #ifdef IFPOLL_ENABLE
4284a331bf7SSepherosa Ziehau static void	bce_npoll(struct ifnet *, struct ifpoll_info *);
42957b3ecd9SSepherosa Ziehau static void	bce_npoll_rx(struct ifnet *, void *, int);
43057b3ecd9SSepherosa Ziehau static void	bce_npoll_tx(struct ifnet *, void *, int);
43157b3ecd9SSepherosa Ziehau static void	bce_npoll_status(struct ifnet *);
432b42386eeSSepherosa Ziehau static void	bce_npoll_rx_pack(struct ifnet *, void *, int);
43343c2aeb0SSepherosa Ziehau #endif
43484464af5SSepherosa Ziehau static void	bce_serialize(struct ifnet *, enum ifnet_serialize);
43584464af5SSepherosa Ziehau static void	bce_deserialize(struct ifnet *, enum ifnet_serialize);
43684464af5SSepherosa Ziehau static int	bce_tryserialize(struct ifnet *, enum ifnet_serialize);
43784464af5SSepherosa Ziehau #ifdef INVARIANTS
43884464af5SSepherosa Ziehau static void	bce_serialize_assert(struct ifnet *, enum ifnet_serialize,
43984464af5SSepherosa Ziehau 		    boolean_t);
44084464af5SSepherosa Ziehau #endif
4418aca6ad9SSepherosa Ziehau 
442eac57ffbSSepherosa Ziehau static void	bce_intr(struct bce_softc *);
443eac57ffbSSepherosa Ziehau static void	bce_intr_legacy(void *);
444eac57ffbSSepherosa Ziehau static void	bce_intr_msi(void *);
445eac57ffbSSepherosa Ziehau static void	bce_intr_msi_oneshot(void *);
446b42386eeSSepherosa Ziehau static void	bce_intr_msix_rxtx(void *);
447b42386eeSSepherosa Ziehau static void	bce_intr_msix_rx(void *);
4488aca6ad9SSepherosa Ziehau static void	bce_tx_intr(struct bce_tx_ring *, uint16_t);
4498aca6ad9SSepherosa Ziehau static void	bce_rx_intr(struct bce_rx_ring *, int, uint16_t);
4508aca6ad9SSepherosa Ziehau static void	bce_phy_intr(struct bce_softc *);
4518aca6ad9SSepherosa Ziehau static void	bce_disable_intr(struct bce_softc *);
4528aca6ad9SSepherosa Ziehau static void	bce_enable_intr(struct bce_softc *);
453ba268ba5SSepherosa Ziehau static void	bce_reenable_intr(struct bce_rx_ring *);
4548aca6ad9SSepherosa Ziehau static void	bce_check_msi(void *);
4558aca6ad9SSepherosa Ziehau 
45643c2aeb0SSepherosa Ziehau static void	bce_stats_update(struct bce_softc *);
45743c2aeb0SSepherosa Ziehau static void	bce_tick(void *);
45843c2aeb0SSepherosa Ziehau static void	bce_tick_serialized(struct bce_softc *);
459d0092544SSepherosa Ziehau static void	bce_pulse(void *);
46043c2aeb0SSepherosa Ziehau 
4618aca6ad9SSepherosa Ziehau static void	bce_add_sysctls(struct bce_softc *);
462bdeb8fffSSepherosa Ziehau static int	bce_sysctl_tx_bds_int(SYSCTL_HANDLER_ARGS);
463bdeb8fffSSepherosa Ziehau static int	bce_sysctl_tx_bds(SYSCTL_HANDLER_ARGS);
464bdeb8fffSSepherosa Ziehau static int	bce_sysctl_tx_ticks_int(SYSCTL_HANDLER_ARGS);
465bdeb8fffSSepherosa Ziehau static int	bce_sysctl_tx_ticks(SYSCTL_HANDLER_ARGS);
466bdeb8fffSSepherosa Ziehau static int	bce_sysctl_rx_bds_int(SYSCTL_HANDLER_ARGS);
467bdeb8fffSSepherosa Ziehau static int	bce_sysctl_rx_bds(SYSCTL_HANDLER_ARGS);
468bdeb8fffSSepherosa Ziehau static int	bce_sysctl_rx_ticks_int(SYSCTL_HANDLER_ARGS);
469bdeb8fffSSepherosa Ziehau static int	bce_sysctl_rx_ticks(SYSCTL_HANDLER_ARGS);
470bdeb8fffSSepherosa Ziehau static int	bce_sysctl_coal_change(SYSCTL_HANDLER_ARGS,
471bdeb8fffSSepherosa Ziehau 		    uint32_t *, uint32_t);
472bdeb8fffSSepherosa Ziehau 
4733fb4bb6cSSepherosa Ziehau /*
4743fb4bb6cSSepherosa Ziehau  * NOTE:
4753fb4bb6cSSepherosa Ziehau  * Don't set bce_tx_ticks_int/bce_tx_ticks to 1023.  Linux's bnx2
4763fb4bb6cSSepherosa Ziehau  * takes 1023 as the TX ticks limit.  However, using 1023 will
4773fb4bb6cSSepherosa Ziehau  * cause 5708(B2) to generate extra interrupts (~2000/s) even when
4783fb4bb6cSSepherosa Ziehau  * there is _no_ network activity on the NIC.
4793fb4bb6cSSepherosa Ziehau  */
4803fb4bb6cSSepherosa Ziehau static uint32_t	bce_tx_bds_int = 255;		/* bcm: 20 */
4813fb4bb6cSSepherosa Ziehau static uint32_t	bce_tx_bds = 255;		/* bcm: 20 */
4823fb4bb6cSSepherosa Ziehau static uint32_t	bce_tx_ticks_int = 1022;	/* bcm: 80 */
4833fb4bb6cSSepherosa Ziehau static uint32_t	bce_tx_ticks = 1022;		/* bcm: 80 */
4841af951abSSepherosa Ziehau static uint32_t	bce_rx_bds_int = 128;		/* bcm: 6 */
48547388162SSepherosa Ziehau static uint32_t	bce_rx_bds = 0;			/* bcm: 6 */
4862b3bab8aSSepherosa Ziehau static uint32_t	bce_rx_ticks_int = 150;		/* bcm: 18 */
4872b3bab8aSSepherosa Ziehau static uint32_t	bce_rx_ticks = 150;		/* bcm: 18 */
488bdeb8fffSSepherosa Ziehau 
489c19b6815SSepherosa Ziehau static int	bce_tx_wreg = 8;
490c19b6815SSepherosa Ziehau 
49183ce3dceSSepherosa Ziehau static int	bce_msi_enable = 1;
492b42386eeSSepherosa Ziehau static int	bce_msix_enable = 1;
49383ce3dceSSepherosa Ziehau 
4944b166d4eSSepherosa Ziehau static int	bce_rx_pages = RX_PAGES_DEFAULT;
4954b166d4eSSepherosa Ziehau static int	bce_tx_pages = TX_PAGES_DEFAULT;
4964b166d4eSSepherosa Ziehau 
497b42386eeSSepherosa Ziehau static int	bce_rx_rings = 0;	/* auto */
498b42386eeSSepherosa Ziehau static int	bce_tx_rings = 0;	/* auto */
499b42386eeSSepherosa Ziehau 
500bdeb8fffSSepherosa Ziehau TUNABLE_INT("hw.bce.tx_bds_int", &bce_tx_bds_int);
501bdeb8fffSSepherosa Ziehau TUNABLE_INT("hw.bce.tx_bds", &bce_tx_bds);
502bdeb8fffSSepherosa Ziehau TUNABLE_INT("hw.bce.tx_ticks_int", &bce_tx_ticks_int);
503bdeb8fffSSepherosa Ziehau TUNABLE_INT("hw.bce.tx_ticks", &bce_tx_ticks);
504bdeb8fffSSepherosa Ziehau TUNABLE_INT("hw.bce.rx_bds_int", &bce_rx_bds_int);
505bdeb8fffSSepherosa Ziehau TUNABLE_INT("hw.bce.rx_bds", &bce_rx_bds);
506bdeb8fffSSepherosa Ziehau TUNABLE_INT("hw.bce.rx_ticks_int", &bce_rx_ticks_int);
507bdeb8fffSSepherosa Ziehau TUNABLE_INT("hw.bce.rx_ticks", &bce_rx_ticks);
50883ce3dceSSepherosa Ziehau TUNABLE_INT("hw.bce.msi.enable", &bce_msi_enable);
509b42386eeSSepherosa Ziehau TUNABLE_INT("hw.bce.msix.enable", &bce_msix_enable);
5104b166d4eSSepherosa Ziehau TUNABLE_INT("hw.bce.rx_pages", &bce_rx_pages);
5114b166d4eSSepherosa Ziehau TUNABLE_INT("hw.bce.tx_pages", &bce_tx_pages);
512c19b6815SSepherosa Ziehau TUNABLE_INT("hw.bce.tx_wreg", &bce_tx_wreg);
513b42386eeSSepherosa Ziehau TUNABLE_INT("hw.bce.tx_rings", &bce_tx_rings);
514b42386eeSSepherosa Ziehau TUNABLE_INT("hw.bce.rx_rings", &bce_rx_rings);
51543c2aeb0SSepherosa Ziehau 
51643c2aeb0SSepherosa Ziehau /****************************************************************************/
51743c2aeb0SSepherosa Ziehau /* DragonFly device dispatch table.                                         */
51843c2aeb0SSepherosa Ziehau /****************************************************************************/
51943c2aeb0SSepherosa Ziehau static device_method_t bce_methods[] = {
52043c2aeb0SSepherosa Ziehau 	/* Device interface */
52143c2aeb0SSepherosa Ziehau 	DEVMETHOD(device_probe,		bce_probe),
52243c2aeb0SSepherosa Ziehau 	DEVMETHOD(device_attach,	bce_attach),
52343c2aeb0SSepherosa Ziehau 	DEVMETHOD(device_detach,	bce_detach),
52443c2aeb0SSepherosa Ziehau 	DEVMETHOD(device_shutdown,	bce_shutdown),
52543c2aeb0SSepherosa Ziehau 
52643c2aeb0SSepherosa Ziehau 	/* bus interface */
52743c2aeb0SSepherosa Ziehau 	DEVMETHOD(bus_print_child,	bus_generic_print_child),
52843c2aeb0SSepherosa Ziehau 	DEVMETHOD(bus_driver_added,	bus_generic_driver_added),
52943c2aeb0SSepherosa Ziehau 
53043c2aeb0SSepherosa Ziehau 	/* MII interface */
53143c2aeb0SSepherosa Ziehau 	DEVMETHOD(miibus_readreg,	bce_miibus_read_reg),
53243c2aeb0SSepherosa Ziehau 	DEVMETHOD(miibus_writereg,	bce_miibus_write_reg),
53343c2aeb0SSepherosa Ziehau 	DEVMETHOD(miibus_statchg,	bce_miibus_statchg),
53443c2aeb0SSepherosa Ziehau 
535d3c9c58eSSascha Wildner 	DEVMETHOD_END
53643c2aeb0SSepherosa Ziehau };
53743c2aeb0SSepherosa Ziehau 
53843c2aeb0SSepherosa Ziehau static driver_t bce_driver = {
53943c2aeb0SSepherosa Ziehau 	"bce",
54043c2aeb0SSepherosa Ziehau 	bce_methods,
54143c2aeb0SSepherosa Ziehau 	sizeof(struct bce_softc)
54243c2aeb0SSepherosa Ziehau };
54343c2aeb0SSepherosa Ziehau 
54443c2aeb0SSepherosa Ziehau static devclass_t bce_devclass;
54543c2aeb0SSepherosa Ziehau 
546d0092544SSepherosa Ziehau DECLARE_DUMMY_MODULE(if_bce);
5471be78fa8SSepherosa Ziehau MODULE_DEPEND(bce, miibus, 1, 1, 1);
548aa2b9d05SSascha Wildner DRIVER_MODULE(if_bce, pci, bce_driver, bce_devclass, NULL, NULL);
549aa2b9d05SSascha Wildner DRIVER_MODULE(miibus, bce, miibus_driver, miibus_devclass, NULL, NULL);
55043c2aeb0SSepherosa Ziehau 
55143c2aeb0SSepherosa Ziehau /****************************************************************************/
55243c2aeb0SSepherosa Ziehau /* Device probe function.                                                   */
55343c2aeb0SSepherosa Ziehau /*                                                                          */
55443c2aeb0SSepherosa Ziehau /* Compares the device to the driver's list of supported devices and        */
55543c2aeb0SSepherosa Ziehau /* reports back to the OS whether this is the right driver for the device.  */
55643c2aeb0SSepherosa Ziehau /*                                                                          */
55743c2aeb0SSepherosa Ziehau /* Returns:                                                                 */
55843c2aeb0SSepherosa Ziehau /*   BUS_PROBE_DEFAULT on success, positive value on failure.               */
55943c2aeb0SSepherosa Ziehau /****************************************************************************/
56043c2aeb0SSepherosa Ziehau static int
bce_probe(device_t dev)56143c2aeb0SSepherosa Ziehau bce_probe(device_t dev)
56243c2aeb0SSepherosa Ziehau {
56343c2aeb0SSepherosa Ziehau 	struct bce_type *t;
56443c2aeb0SSepherosa Ziehau 	uint16_t vid, did, svid, sdid;
56543c2aeb0SSepherosa Ziehau 
56643c2aeb0SSepherosa Ziehau 	/* Get the data for the device to be probed. */
56743c2aeb0SSepherosa Ziehau 	vid  = pci_get_vendor(dev);
56843c2aeb0SSepherosa Ziehau 	did  = pci_get_device(dev);
56943c2aeb0SSepherosa Ziehau 	svid = pci_get_subvendor(dev);
57043c2aeb0SSepherosa Ziehau 	sdid = pci_get_subdevice(dev);
57143c2aeb0SSepherosa Ziehau 
57243c2aeb0SSepherosa Ziehau 	/* Look through the list of known devices for a match. */
57343c2aeb0SSepherosa Ziehau 	for (t = bce_devs; t->bce_name != NULL; ++t) {
57443c2aeb0SSepherosa Ziehau 		if (vid == t->bce_vid && did == t->bce_did &&
57543c2aeb0SSepherosa Ziehau 		    (svid == t->bce_svid || t->bce_svid == PCI_ANY_ID) &&
57643c2aeb0SSepherosa Ziehau 		    (sdid == t->bce_sdid || t->bce_sdid == PCI_ANY_ID)) {
57743c2aeb0SSepherosa Ziehau 		    	uint32_t revid = pci_read_config(dev, PCIR_REVID, 4);
57843c2aeb0SSepherosa Ziehau 			char *descbuf;
57943c2aeb0SSepherosa Ziehau 
58043c2aeb0SSepherosa Ziehau 			descbuf = kmalloc(BCE_DEVDESC_MAX, M_TEMP, M_WAITOK);
58143c2aeb0SSepherosa Ziehau 
58243c2aeb0SSepherosa Ziehau 			/* Print out the device identity. */
58343c2aeb0SSepherosa Ziehau 			ksnprintf(descbuf, BCE_DEVDESC_MAX, "%s (%c%d)",
58443c2aeb0SSepherosa Ziehau 				  t->bce_name,
58543c2aeb0SSepherosa Ziehau 				  ((revid & 0xf0) >> 4) + 'A', revid & 0xf);
58643c2aeb0SSepherosa Ziehau 
58743c2aeb0SSepherosa Ziehau 			device_set_desc_copy(dev, descbuf);
58843c2aeb0SSepherosa Ziehau 			kfree(descbuf, M_TEMP);
58943c2aeb0SSepherosa Ziehau 			return 0;
59043c2aeb0SSepherosa Ziehau 		}
59143c2aeb0SSepherosa Ziehau 	}
59243c2aeb0SSepherosa Ziehau 	return ENXIO;
59343c2aeb0SSepherosa Ziehau }
59443c2aeb0SSepherosa Ziehau 
59543c2aeb0SSepherosa Ziehau /****************************************************************************/
596d0092544SSepherosa Ziehau /* PCI Capabilities Probe Function.                                         */
597d0092544SSepherosa Ziehau /*                                                                          */
598d0092544SSepherosa Ziehau /* Walks the PCI capabiites list for the device to find what features are   */
599d0092544SSepherosa Ziehau /* supported.                                                               */
600d0092544SSepherosa Ziehau /*                                                                          */
601d0092544SSepherosa Ziehau /* Returns:                                                                 */
602d0092544SSepherosa Ziehau /*   None.                                                                  */
603d0092544SSepherosa Ziehau /****************************************************************************/
604d0092544SSepherosa Ziehau static void
bce_print_adapter_info(struct bce_softc * sc)605d0092544SSepherosa Ziehau bce_print_adapter_info(struct bce_softc *sc)
606d0092544SSepherosa Ziehau {
607d0092544SSepherosa Ziehau 	device_printf(sc->bce_dev, "ASIC (0x%08X); ", sc->bce_chipid);
608d0092544SSepherosa Ziehau 
609d0092544SSepherosa Ziehau 	kprintf("Rev (%c%d); ", ((BCE_CHIP_ID(sc) & 0xf000) >> 12) + 'A',
610d0092544SSepherosa Ziehau 		((BCE_CHIP_ID(sc) & 0x0ff0) >> 4));
611d0092544SSepherosa Ziehau 
612d0092544SSepherosa Ziehau 	/* Bus info. */
613d0092544SSepherosa Ziehau 	if (sc->bce_flags & BCE_PCIE_FLAG) {
614d0092544SSepherosa Ziehau 		kprintf("Bus (PCIe x%d, ", sc->link_width);
615d0092544SSepherosa Ziehau 		switch (sc->link_speed) {
616d0092544SSepherosa Ziehau 		case 1:
617d0092544SSepherosa Ziehau 			kprintf("2.5Gbps); ");
618d0092544SSepherosa Ziehau 			break;
619d0092544SSepherosa Ziehau 		case 2:
620d0092544SSepherosa Ziehau 			kprintf("5Gbps); ");
621d0092544SSepherosa Ziehau 			break;
622d0092544SSepherosa Ziehau 		default:
623d0092544SSepherosa Ziehau 			kprintf("Unknown link speed); ");
624d0092544SSepherosa Ziehau 			break;
625d0092544SSepherosa Ziehau 		}
626d0092544SSepherosa Ziehau 	} else {
627d0092544SSepherosa Ziehau 		kprintf("Bus (PCI%s, %s, %dMHz); ",
628d0092544SSepherosa Ziehau 		    ((sc->bce_flags & BCE_PCIX_FLAG) ? "-X" : ""),
629d0092544SSepherosa Ziehau 		    ((sc->bce_flags & BCE_PCI_32BIT_FLAG) ? "32-bit" : "64-bit"),
630d0092544SSepherosa Ziehau 		    sc->bus_speed_mhz);
631d0092544SSepherosa Ziehau 	}
632d0092544SSepherosa Ziehau 
633d0092544SSepherosa Ziehau 	/* Firmware version and device features. */
634bc30d40dSSepherosa Ziehau 	kprintf("B/C (%s)", sc->bce_bc_ver);
635d0092544SSepherosa Ziehau 
636cff16e71SSepherosa Ziehau 	if ((sc->bce_flags & BCE_MFW_ENABLE_FLAG) ||
637cff16e71SSepherosa Ziehau 	    (sc->bce_phy_flags & BCE_PHY_2_5G_CAPABLE_FLAG)) {
638cff16e71SSepherosa Ziehau 		kprintf("; Flags(");
639d0092544SSepherosa Ziehau 		if (sc->bce_flags & BCE_MFW_ENABLE_FLAG)
640bc30d40dSSepherosa Ziehau 			kprintf("MFW[%s]", sc->bce_mfw_ver);
641d0092544SSepherosa Ziehau 		if (sc->bce_phy_flags & BCE_PHY_2_5G_CAPABLE_FLAG)
642d0092544SSepherosa Ziehau 			kprintf(" 2.5G");
643cff16e71SSepherosa Ziehau 		kprintf(")");
644cff16e71SSepherosa Ziehau 	}
645cff16e71SSepherosa Ziehau 	kprintf("\n");
646d0092544SSepherosa Ziehau }
647d0092544SSepherosa Ziehau 
648d0092544SSepherosa Ziehau /****************************************************************************/
649d0092544SSepherosa Ziehau /* PCI Capabilities Probe Function.                                         */
650d0092544SSepherosa Ziehau /*                                                                          */
651d0092544SSepherosa Ziehau /* Walks the PCI capabiites list for the device to find what features are   */
652d0092544SSepherosa Ziehau /* supported.                                                               */
653d0092544SSepherosa Ziehau /*                                                                          */
654d0092544SSepherosa Ziehau /* Returns:                                                                 */
655d0092544SSepherosa Ziehau /*   None.                                                                  */
656d0092544SSepherosa Ziehau /****************************************************************************/
657d0092544SSepherosa Ziehau static void
bce_probe_pci_caps(struct bce_softc * sc)658d0092544SSepherosa Ziehau bce_probe_pci_caps(struct bce_softc *sc)
659d0092544SSepherosa Ziehau {
660d0092544SSepherosa Ziehau 	device_t dev = sc->bce_dev;
661d0092544SSepherosa Ziehau 	uint8_t ptr;
662d0092544SSepherosa Ziehau 
663d0092544SSepherosa Ziehau 	if (pci_is_pcix(dev))
664d0092544SSepherosa Ziehau 		sc->bce_cap_flags |= BCE_PCIX_CAPABLE_FLAG;
665d0092544SSepherosa Ziehau 
666d0092544SSepherosa Ziehau 	ptr = pci_get_pciecap_ptr(dev);
667d0092544SSepherosa Ziehau 	if (ptr) {
668d0092544SSepherosa Ziehau 		uint16_t link_status = pci_read_config(dev, ptr + 0x12, 2);
669d0092544SSepherosa Ziehau 
670d0092544SSepherosa Ziehau 		sc->link_speed = link_status & 0xf;
671d0092544SSepherosa Ziehau 		sc->link_width = (link_status >> 4) & 0x3f;
672d0092544SSepherosa Ziehau 		sc->bce_cap_flags |= BCE_PCIE_CAPABLE_FLAG;
673d0092544SSepherosa Ziehau 		sc->bce_flags |= BCE_PCIE_FLAG;
674d0092544SSepherosa Ziehau 	}
675d0092544SSepherosa Ziehau }
676d0092544SSepherosa Ziehau 
677d0092544SSepherosa Ziehau /****************************************************************************/
67843c2aeb0SSepherosa Ziehau /* Device attach function.                                                  */
67943c2aeb0SSepherosa Ziehau /*                                                                          */
68043c2aeb0SSepherosa Ziehau /* Allocates device resources, performs secondary chip identification,      */
68143c2aeb0SSepherosa Ziehau /* resets and initializes the hardware, and initializes driver instance     */
68243c2aeb0SSepherosa Ziehau /* variables.                                                               */
68343c2aeb0SSepherosa Ziehau /*                                                                          */
68443c2aeb0SSepherosa Ziehau /* Returns:                                                                 */
68543c2aeb0SSepherosa Ziehau /*   0 on success, positive value on failure.                               */
68643c2aeb0SSepherosa Ziehau /****************************************************************************/
68743c2aeb0SSepherosa Ziehau static int
bce_attach(device_t dev)68843c2aeb0SSepherosa Ziehau bce_attach(device_t dev)
68943c2aeb0SSepherosa Ziehau {
69043c2aeb0SSepherosa Ziehau 	struct bce_softc *sc = device_get_softc(dev);
69143c2aeb0SSepherosa Ziehau 	struct ifnet *ifp = &sc->arpcom.ac_if;
69243c2aeb0SSepherosa Ziehau 	uint32_t val;
6937fb43956SSepherosa Ziehau 	int rid, rc = 0;
694bc30d40dSSepherosa Ziehau 	int i, j;
695f31c6e4dSSepherosa Ziehau 	struct mii_probe_args mii_args;
696f31c6e4dSSepherosa Ziehau 	uintptr_t mii_priv = 0;
69743c2aeb0SSepherosa Ziehau 
69843c2aeb0SSepherosa Ziehau 	sc->bce_dev = dev;
69943c2aeb0SSepherosa Ziehau 	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
70043c2aeb0SSepherosa Ziehau 
70184464af5SSepherosa Ziehau 	lwkt_serialize_init(&sc->main_serialize);
702b42386eeSSepherosa Ziehau 	for (i = 0; i < BCE_MSIX_MAX; ++i) {
703b42386eeSSepherosa Ziehau 		struct bce_msix_data *msix = &sc->bce_msix[i];
704b42386eeSSepherosa Ziehau 
705b42386eeSSepherosa Ziehau 		msix->msix_cpuid = -1;
706b42386eeSSepherosa Ziehau 		msix->msix_rid = -1;
707b42386eeSSepherosa Ziehau 	}
70884464af5SSepherosa Ziehau 
70943c2aeb0SSepherosa Ziehau 	pci_enable_busmaster(dev);
71043c2aeb0SSepherosa Ziehau 
711d0092544SSepherosa Ziehau 	bce_probe_pci_caps(sc);
712d0092544SSepherosa Ziehau 
71343c2aeb0SSepherosa Ziehau 	/* Allocate PCI memory resources. */
71443c2aeb0SSepherosa Ziehau 	rid = PCIR_BAR(0);
71543c2aeb0SSepherosa Ziehau 	sc->bce_res_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
71643c2aeb0SSepherosa Ziehau 						 RF_ACTIVE | PCI_RF_DENSE);
71743c2aeb0SSepherosa Ziehau 	if (sc->bce_res_mem == NULL) {
71843c2aeb0SSepherosa Ziehau 		device_printf(dev, "PCI memory allocation failed\n");
71943c2aeb0SSepherosa Ziehau 		return ENXIO;
72043c2aeb0SSepherosa Ziehau 	}
72143c2aeb0SSepherosa Ziehau 	sc->bce_btag = rman_get_bustag(sc->bce_res_mem);
72243c2aeb0SSepherosa Ziehau 	sc->bce_bhandle = rman_get_bushandle(sc->bce_res_mem);
72343c2aeb0SSepherosa Ziehau 
72443c2aeb0SSepherosa Ziehau 	/*
72543c2aeb0SSepherosa Ziehau 	 * Configure byte swap and enable indirect register access.
72643c2aeb0SSepherosa Ziehau 	 * Rely on CPU to do target byte swapping on big endian systems.
72743c2aeb0SSepherosa Ziehau 	 * Access to registers outside of PCI configurtion space are not
72843c2aeb0SSepherosa Ziehau 	 * valid until this is done.
72943c2aeb0SSepherosa Ziehau 	 */
73043c2aeb0SSepherosa Ziehau 	pci_write_config(dev, BCE_PCICFG_MISC_CONFIG,
73143c2aeb0SSepherosa Ziehau 			 BCE_PCICFG_MISC_CONFIG_REG_WINDOW_ENA |
73243c2aeb0SSepherosa Ziehau 			 BCE_PCICFG_MISC_CONFIG_TARGET_MB_WORD_SWAP, 4);
73343c2aeb0SSepherosa Ziehau 
73443c2aeb0SSepherosa Ziehau 	/* Save ASIC revsion info. */
73543c2aeb0SSepherosa Ziehau 	sc->bce_chipid =  REG_RD(sc, BCE_MISC_ID);
73643c2aeb0SSepherosa Ziehau 
73743c2aeb0SSepherosa Ziehau 	/* Weed out any non-production controller revisions. */
73843c2aeb0SSepherosa Ziehau 	switch (BCE_CHIP_ID(sc)) {
73943c2aeb0SSepherosa Ziehau 	case BCE_CHIP_ID_5706_A0:
74043c2aeb0SSepherosa Ziehau 	case BCE_CHIP_ID_5706_A1:
74143c2aeb0SSepherosa Ziehau 	case BCE_CHIP_ID_5708_A0:
74243c2aeb0SSepherosa Ziehau 	case BCE_CHIP_ID_5708_B0:
743d0092544SSepherosa Ziehau 	case BCE_CHIP_ID_5709_A0:
744d0092544SSepherosa Ziehau 	case BCE_CHIP_ID_5709_B0:
745d0092544SSepherosa Ziehau 	case BCE_CHIP_ID_5709_B1:
746d0092544SSepherosa Ziehau #ifdef foo
747d0092544SSepherosa Ziehau 	/* 5709C B2 seems to work fine */
748d0092544SSepherosa Ziehau 	case BCE_CHIP_ID_5709_B2:
749d0092544SSepherosa Ziehau #endif
75043c2aeb0SSepherosa Ziehau 		device_printf(dev, "Unsupported chip id 0x%08x!\n",
75143c2aeb0SSepherosa Ziehau 			      BCE_CHIP_ID(sc));
75243c2aeb0SSepherosa Ziehau 		rc = ENODEV;
75343c2aeb0SSepherosa Ziehau 		goto fail;
75443c2aeb0SSepherosa Ziehau 	}
75543c2aeb0SSepherosa Ziehau 
756f31c6e4dSSepherosa Ziehau 	mii_priv |= BRGPHY_FLAG_WIRESPEED;
757f31c6e4dSSepherosa Ziehau 	if (BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5709) {
758f31c6e4dSSepherosa Ziehau 		if (BCE_CHIP_REV(sc) == BCE_CHIP_REV_Ax ||
759f31c6e4dSSepherosa Ziehau 		    BCE_CHIP_REV(sc) == BCE_CHIP_REV_Bx)
760f31c6e4dSSepherosa Ziehau 			mii_priv |= BRGPHY_FLAG_NO_EARLYDAC;
761f31c6e4dSSepherosa Ziehau 	} else {
762f31c6e4dSSepherosa Ziehau 		mii_priv |= BRGPHY_FLAG_BER_BUG;
763f31c6e4dSSepherosa Ziehau 	}
764f31c6e4dSSepherosa Ziehau 
76543c2aeb0SSepherosa Ziehau 	/*
76643c2aeb0SSepherosa Ziehau 	 * Find the base address for shared memory access.
76743c2aeb0SSepherosa Ziehau 	 * Newer versions of bootcode use a signature and offset
76843c2aeb0SSepherosa Ziehau 	 * while older versions use a fixed address.
76943c2aeb0SSepherosa Ziehau 	 */
77043c2aeb0SSepherosa Ziehau 	val = REG_RD_IND(sc, BCE_SHM_HDR_SIGNATURE);
771d0092544SSepherosa Ziehau 	if ((val & BCE_SHM_HDR_SIGNATURE_SIG_MASK) ==
772d0092544SSepherosa Ziehau 	    BCE_SHM_HDR_SIGNATURE_SIG) {
773d0092544SSepherosa Ziehau 		/* Multi-port devices use different offsets in shared memory. */
774d0092544SSepherosa Ziehau 		sc->bce_shmem_base = REG_RD_IND(sc,
775d0092544SSepherosa Ziehau 		    BCE_SHM_HDR_ADDR_0 + (pci_get_function(sc->bce_dev) << 2));
776d0092544SSepherosa Ziehau 	} else {
77743c2aeb0SSepherosa Ziehau 		sc->bce_shmem_base = HOST_VIEW_SHMEM_BASE;
778d0092544SSepherosa Ziehau 	}
77943c2aeb0SSepherosa Ziehau 
780d0092544SSepherosa Ziehau 	/* Fetch the bootcode revision. */
781bc30d40dSSepherosa Ziehau 	val = bce_shmem_rd(sc, BCE_DEV_INFO_BC_REV);
782bc30d40dSSepherosa Ziehau 	for (i = 0, j = 0; i < 3; i++) {
783bc30d40dSSepherosa Ziehau 		uint8_t num;
784bc30d40dSSepherosa Ziehau 		int k, skip0;
785d0092544SSepherosa Ziehau 
786bc30d40dSSepherosa Ziehau 		num = (uint8_t)(val >> (24 - (i * 8)));
787bc30d40dSSepherosa Ziehau 		for (k = 100, skip0 = 1; k >= 1; num %= k, k /= 10) {
788bc30d40dSSepherosa Ziehau 			if (num >= k || !skip0 || k == 1) {
789bc30d40dSSepherosa Ziehau 				sc->bce_bc_ver[j++] = (num / k) + '0';
790bc30d40dSSepherosa Ziehau 				skip0 = 0;
791bc30d40dSSepherosa Ziehau 			}
792bc30d40dSSepherosa Ziehau 		}
793bc30d40dSSepherosa Ziehau 		if (i != 2)
794bc30d40dSSepherosa Ziehau 			sc->bce_bc_ver[j++] = '.';
795bc30d40dSSepherosa Ziehau 	}
796bc30d40dSSepherosa Ziehau 
797bc30d40dSSepherosa Ziehau 	/* Check if any management firwmare is running. */
798bc30d40dSSepherosa Ziehau 	val = bce_shmem_rd(sc, BCE_PORT_FEATURE);
799bc30d40dSSepherosa Ziehau 	if (val & BCE_PORT_FEATURE_ASF_ENABLED) {
800d0092544SSepherosa Ziehau 		sc->bce_flags |= BCE_MFW_ENABLE_FLAG;
801d0092544SSepherosa Ziehau 
802bc30d40dSSepherosa Ziehau 		/* Allow time for firmware to enter the running state. */
803bc30d40dSSepherosa Ziehau 		for (i = 0; i < 30; i++) {
804bc30d40dSSepherosa Ziehau 			val = bce_shmem_rd(sc, BCE_BC_STATE_CONDITION);
805bc30d40dSSepherosa Ziehau 			if (val & BCE_CONDITION_MFW_RUN_MASK)
806bc30d40dSSepherosa Ziehau 				break;
807bc30d40dSSepherosa Ziehau 			DELAY(10000);
808bc30d40dSSepherosa Ziehau 		}
809bc30d40dSSepherosa Ziehau 	}
810bc30d40dSSepherosa Ziehau 
811bc30d40dSSepherosa Ziehau 	/* Check the current bootcode state. */
812bc30d40dSSepherosa Ziehau 	val = bce_shmem_rd(sc, BCE_BC_STATE_CONDITION) &
813bc30d40dSSepherosa Ziehau 	    BCE_CONDITION_MFW_RUN_MASK;
814bc30d40dSSepherosa Ziehau 	if (val != BCE_CONDITION_MFW_RUN_UNKNOWN &&
815bc30d40dSSepherosa Ziehau 	    val != BCE_CONDITION_MFW_RUN_NONE) {
816bc30d40dSSepherosa Ziehau 		uint32_t addr = bce_shmem_rd(sc, BCE_MFW_VER_PTR);
817bc30d40dSSepherosa Ziehau 
818bc30d40dSSepherosa Ziehau 		for (i = 0, j = 0; j < 3; j++) {
819bc30d40dSSepherosa Ziehau 			val = bce_reg_rd_ind(sc, addr + j * 4);
820bc30d40dSSepherosa Ziehau 			val = bswap32(val);
821bc30d40dSSepherosa Ziehau 			memcpy(&sc->bce_mfw_ver[i], &val, 4);
822bc30d40dSSepherosa Ziehau 			i += 4;
823bc30d40dSSepherosa Ziehau 		}
824bc30d40dSSepherosa Ziehau 	}
825bc30d40dSSepherosa Ziehau 
82643c2aeb0SSepherosa Ziehau 	/* Get PCI bus information (speed and type). */
82743c2aeb0SSepherosa Ziehau 	val = REG_RD(sc, BCE_PCICFG_MISC_STATUS);
82843c2aeb0SSepherosa Ziehau 	if (val & BCE_PCICFG_MISC_STATUS_PCIX_DET) {
82943c2aeb0SSepherosa Ziehau 		uint32_t clkreg;
83043c2aeb0SSepherosa Ziehau 
83143c2aeb0SSepherosa Ziehau 		sc->bce_flags |= BCE_PCIX_FLAG;
83243c2aeb0SSepherosa Ziehau 
83343c2aeb0SSepherosa Ziehau 		clkreg = REG_RD(sc, BCE_PCICFG_PCI_CLOCK_CONTROL_BITS) &
83443c2aeb0SSepherosa Ziehau 			 BCE_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET;
83543c2aeb0SSepherosa Ziehau 		switch (clkreg) {
83643c2aeb0SSepherosa Ziehau 		case BCE_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_133MHZ:
83743c2aeb0SSepherosa Ziehau 			sc->bus_speed_mhz = 133;
83843c2aeb0SSepherosa Ziehau 			break;
83943c2aeb0SSepherosa Ziehau 
84043c2aeb0SSepherosa Ziehau 		case BCE_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_95MHZ:
84143c2aeb0SSepherosa Ziehau 			sc->bus_speed_mhz = 100;
84243c2aeb0SSepherosa Ziehau 			break;
84343c2aeb0SSepherosa Ziehau 
84443c2aeb0SSepherosa Ziehau 		case BCE_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_66MHZ:
84543c2aeb0SSepherosa Ziehau 		case BCE_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_80MHZ:
84643c2aeb0SSepherosa Ziehau 			sc->bus_speed_mhz = 66;
84743c2aeb0SSepherosa Ziehau 			break;
84843c2aeb0SSepherosa Ziehau 
84943c2aeb0SSepherosa Ziehau 		case BCE_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_48MHZ:
85043c2aeb0SSepherosa Ziehau 		case BCE_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_55MHZ:
85143c2aeb0SSepherosa Ziehau 			sc->bus_speed_mhz = 50;
85243c2aeb0SSepherosa Ziehau 			break;
85343c2aeb0SSepherosa Ziehau 
85443c2aeb0SSepherosa Ziehau 		case BCE_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_LOW:
85543c2aeb0SSepherosa Ziehau 		case BCE_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_32MHZ:
85643c2aeb0SSepherosa Ziehau 		case BCE_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_38MHZ:
85743c2aeb0SSepherosa Ziehau 			sc->bus_speed_mhz = 33;
85843c2aeb0SSepherosa Ziehau 			break;
85943c2aeb0SSepherosa Ziehau 		}
86043c2aeb0SSepherosa Ziehau 	} else {
86143c2aeb0SSepherosa Ziehau 		if (val & BCE_PCICFG_MISC_STATUS_M66EN)
86243c2aeb0SSepherosa Ziehau 			sc->bus_speed_mhz = 66;
86343c2aeb0SSepherosa Ziehau 		else
86443c2aeb0SSepherosa Ziehau 			sc->bus_speed_mhz = 33;
86543c2aeb0SSepherosa Ziehau 	}
86643c2aeb0SSepherosa Ziehau 
86743c2aeb0SSepherosa Ziehau 	if (val & BCE_PCICFG_MISC_STATUS_32BIT_DET)
86843c2aeb0SSepherosa Ziehau 		sc->bce_flags |= BCE_PCI_32BIT_FLAG;
86943c2aeb0SSepherosa Ziehau 
87043c2aeb0SSepherosa Ziehau 	/* Reset the controller. */
87143c2aeb0SSepherosa Ziehau 	rc = bce_reset(sc, BCE_DRV_MSG_CODE_RESET);
87243c2aeb0SSepherosa Ziehau 	if (rc != 0)
87343c2aeb0SSepherosa Ziehau 		goto fail;
87443c2aeb0SSepherosa Ziehau 
87543c2aeb0SSepherosa Ziehau 	/* Initialize the controller. */
87643c2aeb0SSepherosa Ziehau 	rc = bce_chipinit(sc);
87743c2aeb0SSepherosa Ziehau 	if (rc != 0) {
87843c2aeb0SSepherosa Ziehau 		device_printf(dev, "Controller initialization failed!\n");
87943c2aeb0SSepherosa Ziehau 		goto fail;
88043c2aeb0SSepherosa Ziehau 	}
88143c2aeb0SSepherosa Ziehau 
88243c2aeb0SSepherosa Ziehau 	/* Perform NVRAM test. */
88343c2aeb0SSepherosa Ziehau 	rc = bce_nvram_test(sc);
88443c2aeb0SSepherosa Ziehau 	if (rc != 0) {
88543c2aeb0SSepherosa Ziehau 		device_printf(dev, "NVRAM test failed!\n");
88643c2aeb0SSepherosa Ziehau 		goto fail;
88743c2aeb0SSepherosa Ziehau 	}
88843c2aeb0SSepherosa Ziehau 
88943c2aeb0SSepherosa Ziehau 	/* Fetch the permanent Ethernet MAC address. */
89043c2aeb0SSepherosa Ziehau 	bce_get_mac_addr(sc);
89143c2aeb0SSepherosa Ziehau 
89243c2aeb0SSepherosa Ziehau 	/*
89343c2aeb0SSepherosa Ziehau 	 * Trip points control how many BDs
89443c2aeb0SSepherosa Ziehau 	 * should be ready before generating an
89543c2aeb0SSepherosa Ziehau 	 * interrupt while ticks control how long
89643c2aeb0SSepherosa Ziehau 	 * a BD can sit in the chain before
89743c2aeb0SSepherosa Ziehau 	 * generating an interrupt.  Set the default
89843c2aeb0SSepherosa Ziehau 	 * values for the RX and TX rings.
89943c2aeb0SSepherosa Ziehau 	 */
90043c2aeb0SSepherosa Ziehau 
90143c2aeb0SSepherosa Ziehau #ifdef BCE_DRBUG
90243c2aeb0SSepherosa Ziehau 	/* Force more frequent interrupts. */
90343c2aeb0SSepherosa Ziehau 	sc->bce_tx_quick_cons_trip_int = 1;
90443c2aeb0SSepherosa Ziehau 	sc->bce_tx_quick_cons_trip     = 1;
90543c2aeb0SSepherosa Ziehau 	sc->bce_tx_ticks_int           = 0;
90643c2aeb0SSepherosa Ziehau 	sc->bce_tx_ticks               = 0;
90743c2aeb0SSepherosa Ziehau 
90843c2aeb0SSepherosa Ziehau 	sc->bce_rx_quick_cons_trip_int = 1;
90943c2aeb0SSepherosa Ziehau 	sc->bce_rx_quick_cons_trip     = 1;
91043c2aeb0SSepherosa Ziehau 	sc->bce_rx_ticks_int           = 0;
91143c2aeb0SSepherosa Ziehau 	sc->bce_rx_ticks               = 0;
91243c2aeb0SSepherosa Ziehau #else
913bdeb8fffSSepherosa Ziehau 	sc->bce_tx_quick_cons_trip_int = bce_tx_bds_int;
914bdeb8fffSSepherosa Ziehau 	sc->bce_tx_quick_cons_trip     = bce_tx_bds;
915bdeb8fffSSepherosa Ziehau 	sc->bce_tx_ticks_int           = bce_tx_ticks_int;
916bdeb8fffSSepherosa Ziehau 	sc->bce_tx_ticks               = bce_tx_ticks;
91743c2aeb0SSepherosa Ziehau 
918bdeb8fffSSepherosa Ziehau 	sc->bce_rx_quick_cons_trip_int = bce_rx_bds_int;
919bdeb8fffSSepherosa Ziehau 	sc->bce_rx_quick_cons_trip     = bce_rx_bds;
920bdeb8fffSSepherosa Ziehau 	sc->bce_rx_ticks_int           = bce_rx_ticks_int;
921bdeb8fffSSepherosa Ziehau 	sc->bce_rx_ticks               = bce_rx_ticks;
92243c2aeb0SSepherosa Ziehau #endif
92343c2aeb0SSepherosa Ziehau 
92443c2aeb0SSepherosa Ziehau 	/* Update statistics once every second. */
92543c2aeb0SSepherosa Ziehau 	sc->bce_stats_ticks = 1000000 & 0xffff00;
92643c2aeb0SSepherosa Ziehau 
927d0092544SSepherosa Ziehau 	/* Find the media type for the adapter. */
928d0092544SSepherosa Ziehau 	bce_get_media(sc);
92943c2aeb0SSepherosa Ziehau 
93010bcbdabSSepherosa Ziehau 	/* Find out RX/TX ring count */
931b42386eeSSepherosa Ziehau 	bce_setup_ring_cnt(sc);
93210bcbdabSSepherosa Ziehau 
93343c2aeb0SSepherosa Ziehau 	/* Allocate DMA memory resources. */
93443c2aeb0SSepherosa Ziehau 	rc = bce_dma_alloc(sc);
93543c2aeb0SSepherosa Ziehau 	if (rc != 0) {
93643c2aeb0SSepherosa Ziehau 		device_printf(dev, "DMA resource allocation failed!\n");
93743c2aeb0SSepherosa Ziehau 		goto fail;
93843c2aeb0SSepherosa Ziehau 	}
93943c2aeb0SSepherosa Ziehau 
940ff36bdc4SSepherosa Ziehau 	/* Allocate PCI IRQ resources. */
941b42386eeSSepherosa Ziehau 	rc = bce_alloc_intr(sc);
942b42386eeSSepherosa Ziehau 	if (rc != 0)
943ff36bdc4SSepherosa Ziehau 		goto fail;
944ff36bdc4SSepherosa Ziehau 
94584464af5SSepherosa Ziehau 	/* Setup serializer */
94684464af5SSepherosa Ziehau 	bce_setup_serialize(sc);
94784464af5SSepherosa Ziehau 
94843c2aeb0SSepherosa Ziehau 	/* Initialize the ifnet interface. */
94943c2aeb0SSepherosa Ziehau 	ifp->if_softc = sc;
95043c2aeb0SSepherosa Ziehau 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
95143c2aeb0SSepherosa Ziehau 	ifp->if_ioctl = bce_ioctl;
95243c2aeb0SSepherosa Ziehau 	ifp->if_start = bce_start;
95343c2aeb0SSepherosa Ziehau 	ifp->if_init = bce_init;
95484464af5SSepherosa Ziehau 	ifp->if_serialize = bce_serialize;
95584464af5SSepherosa Ziehau 	ifp->if_deserialize = bce_deserialize;
95684464af5SSepherosa Ziehau 	ifp->if_tryserialize = bce_tryserialize;
95784464af5SSepherosa Ziehau #ifdef INVARIANTS
95884464af5SSepherosa Ziehau 	ifp->if_serialize_assert = bce_serialize_assert;
95984464af5SSepherosa Ziehau #endif
9604a331bf7SSepherosa Ziehau #ifdef IFPOLL_ENABLE
9614a331bf7SSepherosa Ziehau 	ifp->if_npoll = bce_npoll;
96243c2aeb0SSepherosa Ziehau #endif
96384464af5SSepherosa Ziehau 
96443c2aeb0SSepherosa Ziehau 	ifp->if_mtu = ETHERMTU;
965eefd160dSSepherosa Ziehau 	ifp->if_hwassist = BCE_CSUM_FEATURES | CSUM_TSO;
96643c2aeb0SSepherosa Ziehau 	ifp->if_capabilities = BCE_IF_CAPABILITIES;
96742ad0e07SSepherosa Ziehau 	if (sc->rx_ring_cnt > 1)
96842ad0e07SSepherosa Ziehau 		ifp->if_capabilities |= IFCAP_RSS;
96943c2aeb0SSepherosa Ziehau 	ifp->if_capenable = ifp->if_capabilities;
97043c2aeb0SSepherosa Ziehau 
97143c2aeb0SSepherosa Ziehau 	if (sc->bce_phy_flags & BCE_PHY_2_5G_CAPABLE_FLAG)
9721e1c5facSSepherosa Ziehau 		ifp->if_baudrate = IF_Mbps(2500ULL);
97343c2aeb0SSepherosa Ziehau 	else
9741e1c5facSSepherosa Ziehau 		ifp->if_baudrate = IF_Mbps(1000ULL);
97543c2aeb0SSepherosa Ziehau 
97614929979SSepherosa Ziehau 	ifp->if_nmbclusters = sc->rx_ring_cnt * USABLE_RX_BD(&sc->rx_rings[0]);
97714929979SSepherosa Ziehau 
97884464af5SSepherosa Ziehau 	ifq_set_maxlen(&ifp->if_snd, USABLE_TX_BD(&sc->tx_rings[0]));
97984464af5SSepherosa Ziehau 	ifq_set_ready(&ifp->if_snd);
980ac2202eaSSepherosa Ziehau 	ifq_set_subq_cnt(&ifp->if_snd, sc->tx_ring_cnt);
98184464af5SSepherosa Ziehau 
982b42386eeSSepherosa Ziehau 	if (sc->tx_ring_cnt > 1) {
98339ea245fSSepherosa Ziehau 		ifp->if_mapsubq = ifq_mapsubq_modulo;
98439ea245fSSepherosa Ziehau 		ifq_set_subq_divisor(&ifp->if_snd, sc->tx_ring_cnt);
985b42386eeSSepherosa Ziehau 	}
986b42386eeSSepherosa Ziehau 
987f31c6e4dSSepherosa Ziehau 	/*
988f31c6e4dSSepherosa Ziehau 	 * Look for our PHY.
989f31c6e4dSSepherosa Ziehau 	 */
990f31c6e4dSSepherosa Ziehau 	mii_probe_args_init(&mii_args, bce_ifmedia_upd, bce_ifmedia_sts);
991f31c6e4dSSepherosa Ziehau 	mii_args.mii_probemask = 1 << sc->bce_phy_addr;
992f31c6e4dSSepherosa Ziehau 	mii_args.mii_privtag = MII_PRIVTAG_BRGPHY;
993f31c6e4dSSepherosa Ziehau 	mii_args.mii_priv = mii_priv;
994f31c6e4dSSepherosa Ziehau 
995f31c6e4dSSepherosa Ziehau 	rc = mii_probe(dev, &sc->bce_miibus, &mii_args);
99643c2aeb0SSepherosa Ziehau 	if (rc != 0) {
99743c2aeb0SSepherosa Ziehau 		device_printf(dev, "PHY probe failed!\n");
99843c2aeb0SSepherosa Ziehau 		goto fail;
99943c2aeb0SSepherosa Ziehau 	}
100043c2aeb0SSepherosa Ziehau 
100143c2aeb0SSepherosa Ziehau 	/* Attach to the Ethernet interface list. */
100243c2aeb0SSepherosa Ziehau 	ether_ifattach(ifp, sc->eaddr, NULL);
100343c2aeb0SSepherosa Ziehau 
10042760ec42SSepherosa Ziehau 	/* Setup TX rings and subqueues */
1005ac2202eaSSepherosa Ziehau 	for (i = 0; i < sc->tx_ring_cnt; ++i) {
1006f774fa0fSSepherosa Ziehau 		struct ifaltq_subque *ifsq = ifq_get_subq(&ifp->if_snd, i);
1007f774fa0fSSepherosa Ziehau 		struct bce_tx_ring *txr = &sc->tx_rings[i];
1008f774fa0fSSepherosa Ziehau 
1009b42386eeSSepherosa Ziehau 		ifsq_set_cpuid(ifsq, sc->bce_msix[i].msix_cpuid);
1010f774fa0fSSepherosa Ziehau 		ifsq_set_priv(ifsq, txr);
1011bfefe4a6SSepherosa Ziehau 		ifsq_set_hw_serialize(ifsq, &txr->tx_serialize);
1012f774fa0fSSepherosa Ziehau 		txr->ifsq = ifsq;
1013f774fa0fSSepherosa Ziehau 
1014e2292763SMatthew Dillon 		ifsq_watchdog_init(&txr->tx_watchdog, ifsq, bce_watchdog, 0);
1015f774fa0fSSepherosa Ziehau 	}
10169db4b353SSepherosa Ziehau 
10172760ec42SSepherosa Ziehau 	callout_init_mp(&sc->bce_tick_callout);
10182760ec42SSepherosa Ziehau 	callout_init_mp(&sc->bce_pulse_callout);
10192760ec42SSepherosa Ziehau 	callout_init_mp(&sc->bce_ckmsi_callout);
10202760ec42SSepherosa Ziehau 
10212760ec42SSepherosa Ziehau 	rc = bce_setup_intr(sc);
10222760ec42SSepherosa Ziehau 	if (rc != 0) {
10232760ec42SSepherosa Ziehau 		device_printf(dev, "Failed to setup IRQ!\n");
10242760ec42SSepherosa Ziehau 		ether_ifdetach(ifp);
10252760ec42SSepherosa Ziehau 		goto fail;
10262760ec42SSepherosa Ziehau 	}
10272760ec42SSepherosa Ziehau 
1028745b3d68SSepherosa Ziehau 	/* Set timer CPUID */
1029745b3d68SSepherosa Ziehau 	bce_set_timer_cpuid(sc, FALSE);
1030745b3d68SSepherosa Ziehau 
103143c2aeb0SSepherosa Ziehau 	/* Add the supported sysctls to the kernel. */
103243c2aeb0SSepherosa Ziehau 	bce_add_sysctls(sc);
103343c2aeb0SSepherosa Ziehau 
1034d0092544SSepherosa Ziehau 	/*
1035d0092544SSepherosa Ziehau 	 * The chip reset earlier notified the bootcode that
1036d0092544SSepherosa Ziehau 	 * a driver is present.  We now need to start our pulse
1037d0092544SSepherosa Ziehau 	 * routine so that the bootcode is reminded that we're
1038d0092544SSepherosa Ziehau 	 * still running.
1039d0092544SSepherosa Ziehau 	 */
1040d0092544SSepherosa Ziehau 	bce_pulse(sc);
1041d0092544SSepherosa Ziehau 
104243c2aeb0SSepherosa Ziehau 	/* Get the firmware running so IPMI still works */
104343c2aeb0SSepherosa Ziehau 	bce_mgmt_init(sc);
104443c2aeb0SSepherosa Ziehau 
1045b51a4d98SSepherosa Ziehau 	if (bootverbose)
1046d0092544SSepherosa Ziehau 		bce_print_adapter_info(sc);
1047d0092544SSepherosa Ziehau 
104843c2aeb0SSepherosa Ziehau 	return 0;
104943c2aeb0SSepherosa Ziehau fail:
105043c2aeb0SSepherosa Ziehau 	bce_detach(dev);
105143c2aeb0SSepherosa Ziehau 	return(rc);
105243c2aeb0SSepherosa Ziehau }
105343c2aeb0SSepherosa Ziehau 
105443c2aeb0SSepherosa Ziehau /****************************************************************************/
105543c2aeb0SSepherosa Ziehau /* Device detach function.                                                  */
105643c2aeb0SSepherosa Ziehau /*                                                                          */
105743c2aeb0SSepherosa Ziehau /* Stops the controller, resets the controller, and releases resources.     */
105843c2aeb0SSepherosa Ziehau /*                                                                          */
105943c2aeb0SSepherosa Ziehau /* Returns:                                                                 */
106043c2aeb0SSepherosa Ziehau /*   0 on success, positive value on failure.                               */
106143c2aeb0SSepherosa Ziehau /****************************************************************************/
106243c2aeb0SSepherosa Ziehau static int
bce_detach(device_t dev)106343c2aeb0SSepherosa Ziehau bce_detach(device_t dev)
106443c2aeb0SSepherosa Ziehau {
106543c2aeb0SSepherosa Ziehau 	struct bce_softc *sc = device_get_softc(dev);
106643c2aeb0SSepherosa Ziehau 
106743c2aeb0SSepherosa Ziehau 	if (device_is_attached(dev)) {
106843c2aeb0SSepherosa Ziehau 		struct ifnet *ifp = &sc->arpcom.ac_if;
1069d0092544SSepherosa Ziehau 		uint32_t msg;
107043c2aeb0SSepherosa Ziehau 
107184464af5SSepherosa Ziehau 		ifnet_serialize_all(ifp);
107284464af5SSepherosa Ziehau 
107343c2aeb0SSepherosa Ziehau 		/* Stop and reset the controller. */
1074d0092544SSepherosa Ziehau 		callout_stop(&sc->bce_pulse_callout);
107543c2aeb0SSepherosa Ziehau 		bce_stop(sc);
1076d0092544SSepherosa Ziehau 		if (sc->bce_flags & BCE_NO_WOL_FLAG)
1077d0092544SSepherosa Ziehau 			msg = BCE_DRV_MSG_CODE_UNLOAD_LNK_DN;
1078d0092544SSepherosa Ziehau 		else
1079d0092544SSepherosa Ziehau 			msg = BCE_DRV_MSG_CODE_UNLOAD;
1080d0092544SSepherosa Ziehau 		bce_reset(sc, msg);
1081b42386eeSSepherosa Ziehau 
1082b42386eeSSepherosa Ziehau 		bce_teardown_intr(sc);
108384464af5SSepherosa Ziehau 
108484464af5SSepherosa Ziehau 		ifnet_deserialize_all(ifp);
108543c2aeb0SSepherosa Ziehau 
108643c2aeb0SSepherosa Ziehau 		ether_ifdetach(ifp);
108743c2aeb0SSepherosa Ziehau 	}
108843c2aeb0SSepherosa Ziehau 
108943c2aeb0SSepherosa Ziehau 	/* If we have a child device on the MII bus remove it too. */
109043c2aeb0SSepherosa Ziehau 	if (sc->bce_miibus)
109143c2aeb0SSepherosa Ziehau 		device_delete_child(dev, sc->bce_miibus);
109243c2aeb0SSepherosa Ziehau 	bus_generic_detach(dev);
109343c2aeb0SSepherosa Ziehau 
1094b42386eeSSepherosa Ziehau 	bce_free_intr(sc);
109543c2aeb0SSepherosa Ziehau 
109643c2aeb0SSepherosa Ziehau 	if (sc->bce_res_mem != NULL) {
109743c2aeb0SSepherosa Ziehau 		bus_release_resource(dev, SYS_RES_MEMORY, PCIR_BAR(0),
109843c2aeb0SSepherosa Ziehau 				     sc->bce_res_mem);
109943c2aeb0SSepherosa Ziehau 	}
110043c2aeb0SSepherosa Ziehau 
110143c2aeb0SSepherosa Ziehau 	bce_dma_free(sc);
110243c2aeb0SSepherosa Ziehau 
110351e9979fSSepherosa Ziehau 	if (sc->serializes != NULL)
110451e9979fSSepherosa Ziehau 		kfree(sc->serializes, M_DEVBUF);
110551e9979fSSepherosa Ziehau 
110639ea245fSSepherosa Ziehau 	if (sc->tx_rmap != NULL)
110739ea245fSSepherosa Ziehau 		if_ringmap_free(sc->tx_rmap);
110839ea245fSSepherosa Ziehau 	if (sc->rx_rmap != NULL)
110939ea245fSSepherosa Ziehau 		if_ringmap_free(sc->rx_rmap);
111039ea245fSSepherosa Ziehau 
111143c2aeb0SSepherosa Ziehau 	return 0;
111243c2aeb0SSepherosa Ziehau }
111343c2aeb0SSepherosa Ziehau 
111443c2aeb0SSepherosa Ziehau /****************************************************************************/
111543c2aeb0SSepherosa Ziehau /* Device shutdown function.                                                */
111643c2aeb0SSepherosa Ziehau /*                                                                          */
111743c2aeb0SSepherosa Ziehau /* Stops and resets the controller.                                         */
111843c2aeb0SSepherosa Ziehau /*                                                                          */
111943c2aeb0SSepherosa Ziehau /* Returns:                                                                 */
112043c2aeb0SSepherosa Ziehau /*   Nothing                                                                */
112143c2aeb0SSepherosa Ziehau /****************************************************************************/
112243c2aeb0SSepherosa Ziehau static void
bce_shutdown(device_t dev)112343c2aeb0SSepherosa Ziehau bce_shutdown(device_t dev)
112443c2aeb0SSepherosa Ziehau {
112543c2aeb0SSepherosa Ziehau 	struct bce_softc *sc = device_get_softc(dev);
112643c2aeb0SSepherosa Ziehau 	struct ifnet *ifp = &sc->arpcom.ac_if;
1127d0092544SSepherosa Ziehau 	uint32_t msg;
112843c2aeb0SSepherosa Ziehau 
112984464af5SSepherosa Ziehau 	ifnet_serialize_all(ifp);
113084464af5SSepherosa Ziehau 
113143c2aeb0SSepherosa Ziehau 	bce_stop(sc);
1132d0092544SSepherosa Ziehau 	if (sc->bce_flags & BCE_NO_WOL_FLAG)
1133d0092544SSepherosa Ziehau 		msg = BCE_DRV_MSG_CODE_UNLOAD_LNK_DN;
1134d0092544SSepherosa Ziehau 	else
1135d0092544SSepherosa Ziehau 		msg = BCE_DRV_MSG_CODE_UNLOAD;
1136d0092544SSepherosa Ziehau 	bce_reset(sc, msg);
113784464af5SSepherosa Ziehau 
113884464af5SSepherosa Ziehau 	ifnet_deserialize_all(ifp);
113943c2aeb0SSepherosa Ziehau }
114043c2aeb0SSepherosa Ziehau 
114143c2aeb0SSepherosa Ziehau /****************************************************************************/
114243c2aeb0SSepherosa Ziehau /* Indirect register read.                                                  */
114343c2aeb0SSepherosa Ziehau /*                                                                          */
114443c2aeb0SSepherosa Ziehau /* Reads NetXtreme II registers using an index/data register pair in PCI    */
114543c2aeb0SSepherosa Ziehau /* configuration space.  Using this mechanism avoids issues with posted     */
114643c2aeb0SSepherosa Ziehau /* reads but is much slower than memory-mapped I/O.                         */
114743c2aeb0SSepherosa Ziehau /*                                                                          */
114843c2aeb0SSepherosa Ziehau /* Returns:                                                                 */
114943c2aeb0SSepherosa Ziehau /*   The value of the register.                                             */
115043c2aeb0SSepherosa Ziehau /****************************************************************************/
115143c2aeb0SSepherosa Ziehau static uint32_t
bce_reg_rd_ind(struct bce_softc * sc,uint32_t offset)115243c2aeb0SSepherosa Ziehau bce_reg_rd_ind(struct bce_softc *sc, uint32_t offset)
115343c2aeb0SSepherosa Ziehau {
115443c2aeb0SSepherosa Ziehau 	device_t dev = sc->bce_dev;
115543c2aeb0SSepherosa Ziehau 
115643c2aeb0SSepherosa Ziehau 	pci_write_config(dev, BCE_PCICFG_REG_WINDOW_ADDRESS, offset, 4);
115743c2aeb0SSepherosa Ziehau 	return pci_read_config(dev, BCE_PCICFG_REG_WINDOW, 4);
115843c2aeb0SSepherosa Ziehau }
115943c2aeb0SSepherosa Ziehau 
116043c2aeb0SSepherosa Ziehau /****************************************************************************/
116143c2aeb0SSepherosa Ziehau /* Indirect register write.                                                 */
116243c2aeb0SSepherosa Ziehau /*                                                                          */
116343c2aeb0SSepherosa Ziehau /* Writes NetXtreme II registers using an index/data register pair in PCI   */
116443c2aeb0SSepherosa Ziehau /* configuration space.  Using this mechanism avoids issues with posted     */
116543c2aeb0SSepherosa Ziehau /* writes but is muchh slower than memory-mapped I/O.                       */
116643c2aeb0SSepherosa Ziehau /*                                                                          */
116743c2aeb0SSepherosa Ziehau /* Returns:                                                                 */
116843c2aeb0SSepherosa Ziehau /*   Nothing.                                                               */
116943c2aeb0SSepherosa Ziehau /****************************************************************************/
117043c2aeb0SSepherosa Ziehau static void
bce_reg_wr_ind(struct bce_softc * sc,uint32_t offset,uint32_t val)117143c2aeb0SSepherosa Ziehau bce_reg_wr_ind(struct bce_softc *sc, uint32_t offset, uint32_t val)
117243c2aeb0SSepherosa Ziehau {
117343c2aeb0SSepherosa Ziehau 	device_t dev = sc->bce_dev;
117443c2aeb0SSepherosa Ziehau 
117543c2aeb0SSepherosa Ziehau 	pci_write_config(dev, BCE_PCICFG_REG_WINDOW_ADDRESS, offset, 4);
117643c2aeb0SSepherosa Ziehau 	pci_write_config(dev, BCE_PCICFG_REG_WINDOW, val, 4);
117743c2aeb0SSepherosa Ziehau }
117843c2aeb0SSepherosa Ziehau 
117943c2aeb0SSepherosa Ziehau /****************************************************************************/
1180bc30d40dSSepherosa Ziehau /* Shared memory write.                                                     */
1181bc30d40dSSepherosa Ziehau /*                                                                          */
1182bc30d40dSSepherosa Ziehau /* Writes NetXtreme II shared memory region.                                */
1183bc30d40dSSepherosa Ziehau /*                                                                          */
1184bc30d40dSSepherosa Ziehau /* Returns:                                                                 */
1185bc30d40dSSepherosa Ziehau /*   Nothing.                                                               */
1186bc30d40dSSepherosa Ziehau /****************************************************************************/
1187bc30d40dSSepherosa Ziehau static void
bce_shmem_wr(struct bce_softc * sc,uint32_t offset,uint32_t val)1188bc30d40dSSepherosa Ziehau bce_shmem_wr(struct bce_softc *sc, uint32_t offset, uint32_t val)
1189bc30d40dSSepherosa Ziehau {
1190bc30d40dSSepherosa Ziehau 	bce_reg_wr_ind(sc, sc->bce_shmem_base + offset, val);
1191bc30d40dSSepherosa Ziehau }
1192bc30d40dSSepherosa Ziehau 
1193bc30d40dSSepherosa Ziehau /****************************************************************************/
1194bc30d40dSSepherosa Ziehau /* Shared memory read.                                                      */
1195bc30d40dSSepherosa Ziehau /*                                                                          */
1196bc30d40dSSepherosa Ziehau /* Reads NetXtreme II shared memory region.                                 */
1197bc30d40dSSepherosa Ziehau /*                                                                          */
1198bc30d40dSSepherosa Ziehau /* Returns:                                                                 */
1199bc30d40dSSepherosa Ziehau /*   The 32 bit value read.                                                 */
1200bc30d40dSSepherosa Ziehau /****************************************************************************/
1201bc30d40dSSepherosa Ziehau static u32
bce_shmem_rd(struct bce_softc * sc,uint32_t offset)1202bc30d40dSSepherosa Ziehau bce_shmem_rd(struct bce_softc *sc, uint32_t offset)
1203bc30d40dSSepherosa Ziehau {
1204bc30d40dSSepherosa Ziehau 	return bce_reg_rd_ind(sc, sc->bce_shmem_base + offset);
1205bc30d40dSSepherosa Ziehau }
1206bc30d40dSSepherosa Ziehau 
1207bc30d40dSSepherosa Ziehau /****************************************************************************/
120843c2aeb0SSepherosa Ziehau /* Context memory write.                                                    */
120943c2aeb0SSepherosa Ziehau /*                                                                          */
121043c2aeb0SSepherosa Ziehau /* The NetXtreme II controller uses context memory to track connection      */
121143c2aeb0SSepherosa Ziehau /* information for L2 and higher network protocols.                         */
121243c2aeb0SSepherosa Ziehau /*                                                                          */
121343c2aeb0SSepherosa Ziehau /* Returns:                                                                 */
121443c2aeb0SSepherosa Ziehau /*   Nothing.                                                               */
121543c2aeb0SSepherosa Ziehau /****************************************************************************/
121643c2aeb0SSepherosa Ziehau static void
bce_ctx_wr(struct bce_softc * sc,uint32_t cid_addr,uint32_t ctx_offset,uint32_t ctx_val)1217d0092544SSepherosa Ziehau bce_ctx_wr(struct bce_softc *sc, uint32_t cid_addr, uint32_t ctx_offset,
1218d0092544SSepherosa Ziehau     uint32_t ctx_val)
121943c2aeb0SSepherosa Ziehau {
1220d0092544SSepherosa Ziehau 	uint32_t idx, offset = ctx_offset + cid_addr;
1221d0092544SSepherosa Ziehau 	uint32_t val, retry_cnt = 5;
122243c2aeb0SSepherosa Ziehau 
1223d0092544SSepherosa Ziehau 	if (BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5709 ||
1224d0092544SSepherosa Ziehau 	    BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5716) {
1225d0092544SSepherosa Ziehau 		REG_WR(sc, BCE_CTX_CTX_DATA, ctx_val);
1226d0092544SSepherosa Ziehau 		REG_WR(sc, BCE_CTX_CTX_CTRL, (offset | BCE_CTX_CTX_CTRL_WRITE_REQ));
1227d0092544SSepherosa Ziehau 
1228d0092544SSepherosa Ziehau 		for (idx = 0; idx < retry_cnt; idx++) {
1229d0092544SSepherosa Ziehau 			val = REG_RD(sc, BCE_CTX_CTX_CTRL);
1230d0092544SSepherosa Ziehau 			if ((val & BCE_CTX_CTX_CTRL_WRITE_REQ) == 0)
1231d0092544SSepherosa Ziehau 				break;
1232d0092544SSepherosa Ziehau 			DELAY(5);
1233d0092544SSepherosa Ziehau 		}
1234d0092544SSepherosa Ziehau 
1235d0092544SSepherosa Ziehau 		if (val & BCE_CTX_CTX_CTRL_WRITE_REQ) {
1236d0092544SSepherosa Ziehau 			device_printf(sc->bce_dev,
1237d0092544SSepherosa Ziehau 			    "Unable to write CTX memory: "
1238d0092544SSepherosa Ziehau 			    "cid_addr = 0x%08X, offset = 0x%08X!\n",
1239d0092544SSepherosa Ziehau 			    cid_addr, ctx_offset);
1240d0092544SSepherosa Ziehau 		}
1241d0092544SSepherosa Ziehau 	} else {
124243c2aeb0SSepherosa Ziehau 		REG_WR(sc, BCE_CTX_DATA_ADR, offset);
1243d0092544SSepherosa Ziehau 		REG_WR(sc, BCE_CTX_DATA, ctx_val);
1244d0092544SSepherosa Ziehau 	}
124543c2aeb0SSepherosa Ziehau }
124643c2aeb0SSepherosa Ziehau 
124743c2aeb0SSepherosa Ziehau /****************************************************************************/
124843c2aeb0SSepherosa Ziehau /* PHY register read.                                                       */
124943c2aeb0SSepherosa Ziehau /*                                                                          */
125043c2aeb0SSepherosa Ziehau /* Implements register reads on the MII bus.                                */
125143c2aeb0SSepherosa Ziehau /*                                                                          */
125243c2aeb0SSepherosa Ziehau /* Returns:                                                                 */
125343c2aeb0SSepherosa Ziehau /*   The value of the register.                                             */
125443c2aeb0SSepherosa Ziehau /****************************************************************************/
125543c2aeb0SSepherosa Ziehau static int
bce_miibus_read_reg(device_t dev,int phy,int reg)125643c2aeb0SSepherosa Ziehau bce_miibus_read_reg(device_t dev, int phy, int reg)
125743c2aeb0SSepherosa Ziehau {
125843c2aeb0SSepherosa Ziehau 	struct bce_softc *sc = device_get_softc(dev);
125943c2aeb0SSepherosa Ziehau 	uint32_t val;
126043c2aeb0SSepherosa Ziehau 	int i;
126143c2aeb0SSepherosa Ziehau 
126243c2aeb0SSepherosa Ziehau 	/* Make sure we are accessing the correct PHY address. */
1263f31c6e4dSSepherosa Ziehau 	KASSERT(phy == sc->bce_phy_addr,
1264f31c6e4dSSepherosa Ziehau 	    ("invalid phyno %d, should be %d\n", phy, sc->bce_phy_addr));
126543c2aeb0SSepherosa Ziehau 
126643c2aeb0SSepherosa Ziehau 	if (sc->bce_phy_flags & BCE_PHY_INT_MODE_AUTO_POLLING_FLAG) {
126743c2aeb0SSepherosa Ziehau 		val = REG_RD(sc, BCE_EMAC_MDIO_MODE);
126843c2aeb0SSepherosa Ziehau 		val &= ~BCE_EMAC_MDIO_MODE_AUTO_POLL;
126943c2aeb0SSepherosa Ziehau 
127043c2aeb0SSepherosa Ziehau 		REG_WR(sc, BCE_EMAC_MDIO_MODE, val);
127143c2aeb0SSepherosa Ziehau 		REG_RD(sc, BCE_EMAC_MDIO_MODE);
127243c2aeb0SSepherosa Ziehau 
127343c2aeb0SSepherosa Ziehau 		DELAY(40);
127443c2aeb0SSepherosa Ziehau 	}
127543c2aeb0SSepherosa Ziehau 
127643c2aeb0SSepherosa Ziehau 	val = BCE_MIPHY(phy) | BCE_MIREG(reg) |
127743c2aeb0SSepherosa Ziehau 	      BCE_EMAC_MDIO_COMM_COMMAND_READ | BCE_EMAC_MDIO_COMM_DISEXT |
127843c2aeb0SSepherosa Ziehau 	      BCE_EMAC_MDIO_COMM_START_BUSY;
127943c2aeb0SSepherosa Ziehau 	REG_WR(sc, BCE_EMAC_MDIO_COMM, val);
128043c2aeb0SSepherosa Ziehau 
128143c2aeb0SSepherosa Ziehau 	for (i = 0; i < BCE_PHY_TIMEOUT; i++) {
128243c2aeb0SSepherosa Ziehau 		DELAY(10);
128343c2aeb0SSepherosa Ziehau 
128443c2aeb0SSepherosa Ziehau 		val = REG_RD(sc, BCE_EMAC_MDIO_COMM);
128543c2aeb0SSepherosa Ziehau 		if (!(val & BCE_EMAC_MDIO_COMM_START_BUSY)) {
128643c2aeb0SSepherosa Ziehau 			DELAY(5);
128743c2aeb0SSepherosa Ziehau 
128843c2aeb0SSepherosa Ziehau 			val = REG_RD(sc, BCE_EMAC_MDIO_COMM);
128943c2aeb0SSepherosa Ziehau 			val &= BCE_EMAC_MDIO_COMM_DATA;
129043c2aeb0SSepherosa Ziehau 			break;
129143c2aeb0SSepherosa Ziehau 		}
129243c2aeb0SSepherosa Ziehau 	}
129343c2aeb0SSepherosa Ziehau 
129443c2aeb0SSepherosa Ziehau 	if (val & BCE_EMAC_MDIO_COMM_START_BUSY) {
129543c2aeb0SSepherosa Ziehau 		if_printf(&sc->arpcom.ac_if,
129643c2aeb0SSepherosa Ziehau 			  "Error: PHY read timeout! phy = %d, reg = 0x%04X\n",
129743c2aeb0SSepherosa Ziehau 			  phy, reg);
129843c2aeb0SSepherosa Ziehau 		val = 0x0;
129943c2aeb0SSepherosa Ziehau 	} else {
130043c2aeb0SSepherosa Ziehau 		val = REG_RD(sc, BCE_EMAC_MDIO_COMM);
130143c2aeb0SSepherosa Ziehau 	}
130243c2aeb0SSepherosa Ziehau 
130343c2aeb0SSepherosa Ziehau 	if (sc->bce_phy_flags & BCE_PHY_INT_MODE_AUTO_POLLING_FLAG) {
130443c2aeb0SSepherosa Ziehau 		val = REG_RD(sc, BCE_EMAC_MDIO_MODE);
130543c2aeb0SSepherosa Ziehau 		val |= BCE_EMAC_MDIO_MODE_AUTO_POLL;
130643c2aeb0SSepherosa Ziehau 
130743c2aeb0SSepherosa Ziehau 		REG_WR(sc, BCE_EMAC_MDIO_MODE, val);
130843c2aeb0SSepherosa Ziehau 		REG_RD(sc, BCE_EMAC_MDIO_MODE);
130943c2aeb0SSepherosa Ziehau 
131043c2aeb0SSepherosa Ziehau 		DELAY(40);
131143c2aeb0SSepherosa Ziehau 	}
131243c2aeb0SSepherosa Ziehau 	return (val & 0xffff);
131343c2aeb0SSepherosa Ziehau }
131443c2aeb0SSepherosa Ziehau 
131543c2aeb0SSepherosa Ziehau /****************************************************************************/
131643c2aeb0SSepherosa Ziehau /* PHY register write.                                                      */
131743c2aeb0SSepherosa Ziehau /*                                                                          */
131843c2aeb0SSepherosa Ziehau /* Implements register writes on the MII bus.                               */
131943c2aeb0SSepherosa Ziehau /*                                                                          */
132043c2aeb0SSepherosa Ziehau /* Returns:                                                                 */
132143c2aeb0SSepherosa Ziehau /*   The value of the register.                                             */
132243c2aeb0SSepherosa Ziehau /****************************************************************************/
132343c2aeb0SSepherosa Ziehau static int
bce_miibus_write_reg(device_t dev,int phy,int reg,int val)132443c2aeb0SSepherosa Ziehau bce_miibus_write_reg(device_t dev, int phy, int reg, int val)
132543c2aeb0SSepherosa Ziehau {
132643c2aeb0SSepherosa Ziehau 	struct bce_softc *sc = device_get_softc(dev);
132743c2aeb0SSepherosa Ziehau 	uint32_t val1;
132843c2aeb0SSepherosa Ziehau 	int i;
132943c2aeb0SSepherosa Ziehau 
133043c2aeb0SSepherosa Ziehau 	/* Make sure we are accessing the correct PHY address. */
1331f31c6e4dSSepherosa Ziehau 	KASSERT(phy == sc->bce_phy_addr,
1332f31c6e4dSSepherosa Ziehau 	    ("invalid phyno %d, should be %d\n", phy, sc->bce_phy_addr));
133343c2aeb0SSepherosa Ziehau 
133443c2aeb0SSepherosa Ziehau 	if (sc->bce_phy_flags & BCE_PHY_INT_MODE_AUTO_POLLING_FLAG) {
133543c2aeb0SSepherosa Ziehau 		val1 = REG_RD(sc, BCE_EMAC_MDIO_MODE);
133643c2aeb0SSepherosa Ziehau 		val1 &= ~BCE_EMAC_MDIO_MODE_AUTO_POLL;
133743c2aeb0SSepherosa Ziehau 
133843c2aeb0SSepherosa Ziehau 		REG_WR(sc, BCE_EMAC_MDIO_MODE, val1);
133943c2aeb0SSepherosa Ziehau 		REG_RD(sc, BCE_EMAC_MDIO_MODE);
134043c2aeb0SSepherosa Ziehau 
134143c2aeb0SSepherosa Ziehau 		DELAY(40);
134243c2aeb0SSepherosa Ziehau 	}
134343c2aeb0SSepherosa Ziehau 
134443c2aeb0SSepherosa Ziehau 	val1 = BCE_MIPHY(phy) | BCE_MIREG(reg) | val |
134543c2aeb0SSepherosa Ziehau 		BCE_EMAC_MDIO_COMM_COMMAND_WRITE |
134643c2aeb0SSepherosa Ziehau 		BCE_EMAC_MDIO_COMM_START_BUSY | BCE_EMAC_MDIO_COMM_DISEXT;
134743c2aeb0SSepherosa Ziehau 	REG_WR(sc, BCE_EMAC_MDIO_COMM, val1);
134843c2aeb0SSepherosa Ziehau 
134943c2aeb0SSepherosa Ziehau 	for (i = 0; i < BCE_PHY_TIMEOUT; i++) {
135043c2aeb0SSepherosa Ziehau 		DELAY(10);
135143c2aeb0SSepherosa Ziehau 
135243c2aeb0SSepherosa Ziehau 		val1 = REG_RD(sc, BCE_EMAC_MDIO_COMM);
135343c2aeb0SSepherosa Ziehau 		if (!(val1 & BCE_EMAC_MDIO_COMM_START_BUSY)) {
135443c2aeb0SSepherosa Ziehau 			DELAY(5);
135543c2aeb0SSepherosa Ziehau 			break;
135643c2aeb0SSepherosa Ziehau 		}
135743c2aeb0SSepherosa Ziehau 	}
135843c2aeb0SSepherosa Ziehau 
135943c2aeb0SSepherosa Ziehau 	if (val1 & BCE_EMAC_MDIO_COMM_START_BUSY)
136043c2aeb0SSepherosa Ziehau 		if_printf(&sc->arpcom.ac_if, "PHY write timeout!\n");
136143c2aeb0SSepherosa Ziehau 
136243c2aeb0SSepherosa Ziehau 	if (sc->bce_phy_flags & BCE_PHY_INT_MODE_AUTO_POLLING_FLAG) {
136343c2aeb0SSepherosa Ziehau 		val1 = REG_RD(sc, BCE_EMAC_MDIO_MODE);
136443c2aeb0SSepherosa Ziehau 		val1 |= BCE_EMAC_MDIO_MODE_AUTO_POLL;
136543c2aeb0SSepherosa Ziehau 
136643c2aeb0SSepherosa Ziehau 		REG_WR(sc, BCE_EMAC_MDIO_MODE, val1);
136743c2aeb0SSepherosa Ziehau 		REG_RD(sc, BCE_EMAC_MDIO_MODE);
136843c2aeb0SSepherosa Ziehau 
136943c2aeb0SSepherosa Ziehau 		DELAY(40);
137043c2aeb0SSepherosa Ziehau 	}
137143c2aeb0SSepherosa Ziehau 	return 0;
137243c2aeb0SSepherosa Ziehau }
137343c2aeb0SSepherosa Ziehau 
137443c2aeb0SSepherosa Ziehau /****************************************************************************/
137543c2aeb0SSepherosa Ziehau /* MII bus status change.                                                   */
137643c2aeb0SSepherosa Ziehau /*                                                                          */
137743c2aeb0SSepherosa Ziehau /* Called by the MII bus driver when the PHY establishes link to set the    */
137843c2aeb0SSepherosa Ziehau /* MAC interface registers.                                                 */
137943c2aeb0SSepherosa Ziehau /*                                                                          */
138043c2aeb0SSepherosa Ziehau /* Returns:                                                                 */
138143c2aeb0SSepherosa Ziehau /*   Nothing.                                                               */
138243c2aeb0SSepherosa Ziehau /****************************************************************************/
138343c2aeb0SSepherosa Ziehau static void
bce_miibus_statchg(device_t dev)138443c2aeb0SSepherosa Ziehau bce_miibus_statchg(device_t dev)
138543c2aeb0SSepherosa Ziehau {
138643c2aeb0SSepherosa Ziehau 	struct bce_softc *sc = device_get_softc(dev);
138743c2aeb0SSepherosa Ziehau 	struct mii_data *mii = device_get_softc(sc->bce_miibus);
138843c2aeb0SSepherosa Ziehau 
138943c2aeb0SSepherosa Ziehau 	BCE_CLRBIT(sc, BCE_EMAC_MODE, BCE_EMAC_MODE_PORT);
139043c2aeb0SSepherosa Ziehau 
139143c2aeb0SSepherosa Ziehau 	/*
139243c2aeb0SSepherosa Ziehau 	 * Set MII or GMII interface based on the speed negotiated
139343c2aeb0SSepherosa Ziehau 	 * by the PHY.
139443c2aeb0SSepherosa Ziehau 	 */
139543c2aeb0SSepherosa Ziehau 	if (IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_T ||
139643c2aeb0SSepherosa Ziehau 	    IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_SX) {
139743c2aeb0SSepherosa Ziehau 		BCE_SETBIT(sc, BCE_EMAC_MODE, BCE_EMAC_MODE_PORT_GMII);
139843c2aeb0SSepherosa Ziehau 	} else {
139943c2aeb0SSepherosa Ziehau 		BCE_SETBIT(sc, BCE_EMAC_MODE, BCE_EMAC_MODE_PORT_MII);
140043c2aeb0SSepherosa Ziehau 	}
140143c2aeb0SSepherosa Ziehau 
140243c2aeb0SSepherosa Ziehau 	/*
140343c2aeb0SSepherosa Ziehau 	 * Set half or full duplex based on the duplicity negotiated
140443c2aeb0SSepherosa Ziehau 	 * by the PHY.
140543c2aeb0SSepherosa Ziehau 	 */
140643c2aeb0SSepherosa Ziehau 	if ((mii->mii_media_active & IFM_GMASK) == IFM_FDX) {
140743c2aeb0SSepherosa Ziehau 		BCE_CLRBIT(sc, BCE_EMAC_MODE, BCE_EMAC_MODE_HALF_DUPLEX);
140843c2aeb0SSepherosa Ziehau 	} else {
140943c2aeb0SSepherosa Ziehau 		BCE_SETBIT(sc, BCE_EMAC_MODE, BCE_EMAC_MODE_HALF_DUPLEX);
141043c2aeb0SSepherosa Ziehau 	}
141143c2aeb0SSepherosa Ziehau }
141243c2aeb0SSepherosa Ziehau 
141343c2aeb0SSepherosa Ziehau /****************************************************************************/
141443c2aeb0SSepherosa Ziehau /* Acquire NVRAM lock.                                                      */
141543c2aeb0SSepherosa Ziehau /*                                                                          */
141643c2aeb0SSepherosa Ziehau /* Before the NVRAM can be accessed the caller must acquire an NVRAM lock.  */
141743c2aeb0SSepherosa Ziehau /* Locks 0 and 2 are reserved, lock 1 is used by firmware and lock 2 is     */
141843c2aeb0SSepherosa Ziehau /* for use by the driver.                                                   */
141943c2aeb0SSepherosa Ziehau /*                                                                          */
142043c2aeb0SSepherosa Ziehau /* Returns:                                                                 */
142143c2aeb0SSepherosa Ziehau /*   0 on success, positive value on failure.                               */
142243c2aeb0SSepherosa Ziehau /****************************************************************************/
142343c2aeb0SSepherosa Ziehau static int
bce_acquire_nvram_lock(struct bce_softc * sc)142443c2aeb0SSepherosa Ziehau bce_acquire_nvram_lock(struct bce_softc *sc)
142543c2aeb0SSepherosa Ziehau {
142643c2aeb0SSepherosa Ziehau 	uint32_t val;
142743c2aeb0SSepherosa Ziehau 	int j;
142843c2aeb0SSepherosa Ziehau 
142943c2aeb0SSepherosa Ziehau 	/* Request access to the flash interface. */
143043c2aeb0SSepherosa Ziehau 	REG_WR(sc, BCE_NVM_SW_ARB, BCE_NVM_SW_ARB_ARB_REQ_SET2);
143143c2aeb0SSepherosa Ziehau 	for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) {
143243c2aeb0SSepherosa Ziehau 		val = REG_RD(sc, BCE_NVM_SW_ARB);
143343c2aeb0SSepherosa Ziehau 		if (val & BCE_NVM_SW_ARB_ARB_ARB2)
143443c2aeb0SSepherosa Ziehau 			break;
143543c2aeb0SSepherosa Ziehau 
143643c2aeb0SSepherosa Ziehau 		DELAY(5);
143743c2aeb0SSepherosa Ziehau 	}
143843c2aeb0SSepherosa Ziehau 
143943c2aeb0SSepherosa Ziehau 	if (j >= NVRAM_TIMEOUT_COUNT) {
144043c2aeb0SSepherosa Ziehau 		return EBUSY;
144143c2aeb0SSepherosa Ziehau 	}
144243c2aeb0SSepherosa Ziehau 	return 0;
144343c2aeb0SSepherosa Ziehau }
144443c2aeb0SSepherosa Ziehau 
144543c2aeb0SSepherosa Ziehau /****************************************************************************/
144643c2aeb0SSepherosa Ziehau /* Release NVRAM lock.                                                      */
144743c2aeb0SSepherosa Ziehau /*                                                                          */
144843c2aeb0SSepherosa Ziehau /* When the caller is finished accessing NVRAM the lock must be released.   */
144943c2aeb0SSepherosa Ziehau /* Locks 0 and 2 are reserved, lock 1 is used by firmware and lock 2 is     */
145043c2aeb0SSepherosa Ziehau /* for use by the driver.                                                   */
145143c2aeb0SSepherosa Ziehau /*                                                                          */
145243c2aeb0SSepherosa Ziehau /* Returns:                                                                 */
145343c2aeb0SSepherosa Ziehau /*   0 on success, positive value on failure.                               */
145443c2aeb0SSepherosa Ziehau /****************************************************************************/
145543c2aeb0SSepherosa Ziehau static int
bce_release_nvram_lock(struct bce_softc * sc)145643c2aeb0SSepherosa Ziehau bce_release_nvram_lock(struct bce_softc *sc)
145743c2aeb0SSepherosa Ziehau {
145843c2aeb0SSepherosa Ziehau 	int j;
145943c2aeb0SSepherosa Ziehau 	uint32_t val;
146043c2aeb0SSepherosa Ziehau 
146143c2aeb0SSepherosa Ziehau 	/*
146243c2aeb0SSepherosa Ziehau 	 * Relinquish nvram interface.
146343c2aeb0SSepherosa Ziehau 	 */
146443c2aeb0SSepherosa Ziehau 	REG_WR(sc, BCE_NVM_SW_ARB, BCE_NVM_SW_ARB_ARB_REQ_CLR2);
146543c2aeb0SSepherosa Ziehau 
146643c2aeb0SSepherosa Ziehau 	for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) {
146743c2aeb0SSepherosa Ziehau 		val = REG_RD(sc, BCE_NVM_SW_ARB);
146843c2aeb0SSepherosa Ziehau 		if (!(val & BCE_NVM_SW_ARB_ARB_ARB2))
146943c2aeb0SSepherosa Ziehau 			break;
147043c2aeb0SSepherosa Ziehau 
147143c2aeb0SSepherosa Ziehau 		DELAY(5);
147243c2aeb0SSepherosa Ziehau 	}
147343c2aeb0SSepherosa Ziehau 
147443c2aeb0SSepherosa Ziehau 	if (j >= NVRAM_TIMEOUT_COUNT) {
147543c2aeb0SSepherosa Ziehau 		return EBUSY;
147643c2aeb0SSepherosa Ziehau 	}
147743c2aeb0SSepherosa Ziehau 	return 0;
147843c2aeb0SSepherosa Ziehau }
147943c2aeb0SSepherosa Ziehau 
148043c2aeb0SSepherosa Ziehau /****************************************************************************/
148143c2aeb0SSepherosa Ziehau /* Enable NVRAM access.                                                     */
148243c2aeb0SSepherosa Ziehau /*                                                                          */
148343c2aeb0SSepherosa Ziehau /* Before accessing NVRAM for read or write operations the caller must      */
148443c2aeb0SSepherosa Ziehau /* enabled NVRAM access.                                                    */
148543c2aeb0SSepherosa Ziehau /*                                                                          */
148643c2aeb0SSepherosa Ziehau /* Returns:                                                                 */
148743c2aeb0SSepherosa Ziehau /*   Nothing.                                                               */
148843c2aeb0SSepherosa Ziehau /****************************************************************************/
148943c2aeb0SSepherosa Ziehau static void
bce_enable_nvram_access(struct bce_softc * sc)149043c2aeb0SSepherosa Ziehau bce_enable_nvram_access(struct bce_softc *sc)
149143c2aeb0SSepherosa Ziehau {
149243c2aeb0SSepherosa Ziehau 	uint32_t val;
149343c2aeb0SSepherosa Ziehau 
149443c2aeb0SSepherosa Ziehau 	val = REG_RD(sc, BCE_NVM_ACCESS_ENABLE);
149543c2aeb0SSepherosa Ziehau 	/* Enable both bits, even on read. */
149643c2aeb0SSepherosa Ziehau 	REG_WR(sc, BCE_NVM_ACCESS_ENABLE,
149743c2aeb0SSepherosa Ziehau 	       val | BCE_NVM_ACCESS_ENABLE_EN | BCE_NVM_ACCESS_ENABLE_WR_EN);
149843c2aeb0SSepherosa Ziehau }
149943c2aeb0SSepherosa Ziehau 
150043c2aeb0SSepherosa Ziehau /****************************************************************************/
150143c2aeb0SSepherosa Ziehau /* Disable NVRAM access.                                                    */
150243c2aeb0SSepherosa Ziehau /*                                                                          */
150343c2aeb0SSepherosa Ziehau /* When the caller is finished accessing NVRAM access must be disabled.     */
150443c2aeb0SSepherosa Ziehau /*                                                                          */
150543c2aeb0SSepherosa Ziehau /* Returns:                                                                 */
150643c2aeb0SSepherosa Ziehau /*   Nothing.                                                               */
150743c2aeb0SSepherosa Ziehau /****************************************************************************/
150843c2aeb0SSepherosa Ziehau static void
bce_disable_nvram_access(struct bce_softc * sc)150943c2aeb0SSepherosa Ziehau bce_disable_nvram_access(struct bce_softc *sc)
151043c2aeb0SSepherosa Ziehau {
151143c2aeb0SSepherosa Ziehau 	uint32_t val;
151243c2aeb0SSepherosa Ziehau 
151343c2aeb0SSepherosa Ziehau 	val = REG_RD(sc, BCE_NVM_ACCESS_ENABLE);
151443c2aeb0SSepherosa Ziehau 
151543c2aeb0SSepherosa Ziehau 	/* Disable both bits, even after read. */
151643c2aeb0SSepherosa Ziehau 	REG_WR(sc, BCE_NVM_ACCESS_ENABLE,
151743c2aeb0SSepherosa Ziehau 	       val & ~(BCE_NVM_ACCESS_ENABLE_EN | BCE_NVM_ACCESS_ENABLE_WR_EN));
151843c2aeb0SSepherosa Ziehau }
151943c2aeb0SSepherosa Ziehau 
152043c2aeb0SSepherosa Ziehau /****************************************************************************/
152143c2aeb0SSepherosa Ziehau /* Read a dword (32 bits) from NVRAM.                                       */
152243c2aeb0SSepherosa Ziehau /*                                                                          */
152343c2aeb0SSepherosa Ziehau /* Read a 32 bit word from NVRAM.  The caller is assumed to have already    */
152443c2aeb0SSepherosa Ziehau /* obtained the NVRAM lock and enabled the controller for NVRAM access.     */
152543c2aeb0SSepherosa Ziehau /*                                                                          */
152643c2aeb0SSepherosa Ziehau /* Returns:                                                                 */
152743c2aeb0SSepherosa Ziehau /*   0 on success and the 32 bit value read, positive value on failure.     */
152843c2aeb0SSepherosa Ziehau /****************************************************************************/
152943c2aeb0SSepherosa Ziehau static int
bce_nvram_read_dword(struct bce_softc * sc,uint32_t offset,uint8_t * ret_val,uint32_t cmd_flags)153043c2aeb0SSepherosa Ziehau bce_nvram_read_dword(struct bce_softc *sc, uint32_t offset, uint8_t *ret_val,
153143c2aeb0SSepherosa Ziehau 		     uint32_t cmd_flags)
153243c2aeb0SSepherosa Ziehau {
153343c2aeb0SSepherosa Ziehau 	uint32_t cmd;
153443c2aeb0SSepherosa Ziehau 	int i, rc = 0;
153543c2aeb0SSepherosa Ziehau 
153643c2aeb0SSepherosa Ziehau 	/* Build the command word. */
153743c2aeb0SSepherosa Ziehau 	cmd = BCE_NVM_COMMAND_DOIT | cmd_flags;
153843c2aeb0SSepherosa Ziehau 
153943c2aeb0SSepherosa Ziehau 	/* Calculate the offset for buffered flash. */
1540d0092544SSepherosa Ziehau 	if (sc->bce_flash_info->flags & BCE_NV_TRANSLATE) {
154143c2aeb0SSepherosa Ziehau 		offset = ((offset / sc->bce_flash_info->page_size) <<
154243c2aeb0SSepherosa Ziehau 			  sc->bce_flash_info->page_bits) +
154343c2aeb0SSepherosa Ziehau 			 (offset % sc->bce_flash_info->page_size);
154443c2aeb0SSepherosa Ziehau 	}
154543c2aeb0SSepherosa Ziehau 
154643c2aeb0SSepherosa Ziehau 	/*
154743c2aeb0SSepherosa Ziehau 	 * Clear the DONE bit separately, set the address to read,
154843c2aeb0SSepherosa Ziehau 	 * and issue the read.
154943c2aeb0SSepherosa Ziehau 	 */
155043c2aeb0SSepherosa Ziehau 	REG_WR(sc, BCE_NVM_COMMAND, BCE_NVM_COMMAND_DONE);
155143c2aeb0SSepherosa Ziehau 	REG_WR(sc, BCE_NVM_ADDR, offset & BCE_NVM_ADDR_NVM_ADDR_VALUE);
155243c2aeb0SSepherosa Ziehau 	REG_WR(sc, BCE_NVM_COMMAND, cmd);
155343c2aeb0SSepherosa Ziehau 
155443c2aeb0SSepherosa Ziehau 	/* Wait for completion. */
155543c2aeb0SSepherosa Ziehau 	for (i = 0; i < NVRAM_TIMEOUT_COUNT; i++) {
155643c2aeb0SSepherosa Ziehau 		uint32_t val;
155743c2aeb0SSepherosa Ziehau 
155843c2aeb0SSepherosa Ziehau 		DELAY(5);
155943c2aeb0SSepherosa Ziehau 
156043c2aeb0SSepherosa Ziehau 		val = REG_RD(sc, BCE_NVM_COMMAND);
156143c2aeb0SSepherosa Ziehau 		if (val & BCE_NVM_COMMAND_DONE) {
156243c2aeb0SSepherosa Ziehau 			val = REG_RD(sc, BCE_NVM_READ);
156343c2aeb0SSepherosa Ziehau 
156443c2aeb0SSepherosa Ziehau 			val = be32toh(val);
156543c2aeb0SSepherosa Ziehau 			memcpy(ret_val, &val, 4);
156643c2aeb0SSepherosa Ziehau 			break;
156743c2aeb0SSepherosa Ziehau 		}
156843c2aeb0SSepherosa Ziehau 	}
156943c2aeb0SSepherosa Ziehau 
157043c2aeb0SSepherosa Ziehau 	/* Check for errors. */
157143c2aeb0SSepherosa Ziehau 	if (i >= NVRAM_TIMEOUT_COUNT) {
157243c2aeb0SSepherosa Ziehau 		if_printf(&sc->arpcom.ac_if,
157343c2aeb0SSepherosa Ziehau 			  "Timeout error reading NVRAM at offset 0x%08X!\n",
157443c2aeb0SSepherosa Ziehau 			  offset);
157543c2aeb0SSepherosa Ziehau 		rc = EBUSY;
157643c2aeb0SSepherosa Ziehau 	}
157743c2aeb0SSepherosa Ziehau 	return rc;
157843c2aeb0SSepherosa Ziehau }
157943c2aeb0SSepherosa Ziehau 
158043c2aeb0SSepherosa Ziehau /****************************************************************************/
158143c2aeb0SSepherosa Ziehau /* Initialize NVRAM access.                                                 */
158243c2aeb0SSepherosa Ziehau /*                                                                          */
158343c2aeb0SSepherosa Ziehau /* Identify the NVRAM device in use and prepare the NVRAM interface to      */
158443c2aeb0SSepherosa Ziehau /* access that device.                                                      */
158543c2aeb0SSepherosa Ziehau /*                                                                          */
158643c2aeb0SSepherosa Ziehau /* Returns:                                                                 */
158743c2aeb0SSepherosa Ziehau /*   0 on success, positive value on failure.                               */
158843c2aeb0SSepherosa Ziehau /****************************************************************************/
158943c2aeb0SSepherosa Ziehau static int
bce_init_nvram(struct bce_softc * sc)159043c2aeb0SSepherosa Ziehau bce_init_nvram(struct bce_softc *sc)
159143c2aeb0SSepherosa Ziehau {
159243c2aeb0SSepherosa Ziehau 	uint32_t val;
159343c2aeb0SSepherosa Ziehau 	int j, entry_count, rc = 0;
159443c2aeb0SSepherosa Ziehau 	const struct flash_spec *flash;
159543c2aeb0SSepherosa Ziehau 
1596d0092544SSepherosa Ziehau 	if (BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5709 ||
1597d0092544SSepherosa Ziehau 	    BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5716) {
1598d0092544SSepherosa Ziehau 		sc->bce_flash_info = &flash_5709;
1599d0092544SSepherosa Ziehau 		goto bce_init_nvram_get_flash_size;
1600d0092544SSepherosa Ziehau 	}
1601d0092544SSepherosa Ziehau 
160243c2aeb0SSepherosa Ziehau 	/* Determine the selected interface. */
160343c2aeb0SSepherosa Ziehau 	val = REG_RD(sc, BCE_NVM_CFG1);
160443c2aeb0SSepherosa Ziehau 
160543c2aeb0SSepherosa Ziehau 	entry_count = sizeof(flash_table) / sizeof(struct flash_spec);
160643c2aeb0SSepherosa Ziehau 
160743c2aeb0SSepherosa Ziehau 	/*
160843c2aeb0SSepherosa Ziehau 	 * Flash reconfiguration is required to support additional
160943c2aeb0SSepherosa Ziehau 	 * NVRAM devices not directly supported in hardware.
161043c2aeb0SSepherosa Ziehau 	 * Check if the flash interface was reconfigured
161143c2aeb0SSepherosa Ziehau 	 * by the bootcode.
161243c2aeb0SSepherosa Ziehau 	 */
161343c2aeb0SSepherosa Ziehau 
161443c2aeb0SSepherosa Ziehau 	if (val & 0x40000000) {
161543c2aeb0SSepherosa Ziehau 		/* Flash interface reconfigured by bootcode. */
161643c2aeb0SSepherosa Ziehau 		for (j = 0, flash = flash_table; j < entry_count;
161743c2aeb0SSepherosa Ziehau 		     j++, flash++) {
161843c2aeb0SSepherosa Ziehau 			if ((val & FLASH_BACKUP_STRAP_MASK) ==
161943c2aeb0SSepherosa Ziehau 			    (flash->config1 & FLASH_BACKUP_STRAP_MASK)) {
162043c2aeb0SSepherosa Ziehau 				sc->bce_flash_info = flash;
162143c2aeb0SSepherosa Ziehau 				break;
162243c2aeb0SSepherosa Ziehau 			}
162343c2aeb0SSepherosa Ziehau 		}
162443c2aeb0SSepherosa Ziehau 	} else {
162543c2aeb0SSepherosa Ziehau 		/* Flash interface not yet reconfigured. */
162643c2aeb0SSepherosa Ziehau 		uint32_t mask;
162743c2aeb0SSepherosa Ziehau 
162843c2aeb0SSepherosa Ziehau 		if (val & (1 << 23))
162943c2aeb0SSepherosa Ziehau 			mask = FLASH_BACKUP_STRAP_MASK;
163043c2aeb0SSepherosa Ziehau 		else
163143c2aeb0SSepherosa Ziehau 			mask = FLASH_STRAP_MASK;
163243c2aeb0SSepherosa Ziehau 
163343c2aeb0SSepherosa Ziehau 		/* Look for the matching NVRAM device configuration data. */
163443c2aeb0SSepherosa Ziehau 		for (j = 0, flash = flash_table; j < entry_count;
163543c2aeb0SSepherosa Ziehau 		     j++, flash++) {
163643c2aeb0SSepherosa Ziehau 			/* Check if the device matches any of the known devices. */
163743c2aeb0SSepherosa Ziehau 			if ((val & mask) == (flash->strapping & mask)) {
163843c2aeb0SSepherosa Ziehau 				/* Found a device match. */
163943c2aeb0SSepherosa Ziehau 				sc->bce_flash_info = flash;
164043c2aeb0SSepherosa Ziehau 
164143c2aeb0SSepherosa Ziehau 				/* Request access to the flash interface. */
164243c2aeb0SSepherosa Ziehau 				rc = bce_acquire_nvram_lock(sc);
164343c2aeb0SSepherosa Ziehau 				if (rc != 0)
164443c2aeb0SSepherosa Ziehau 					return rc;
164543c2aeb0SSepherosa Ziehau 
164643c2aeb0SSepherosa Ziehau 				/* Reconfigure the flash interface. */
164743c2aeb0SSepherosa Ziehau 				bce_enable_nvram_access(sc);
164843c2aeb0SSepherosa Ziehau 				REG_WR(sc, BCE_NVM_CFG1, flash->config1);
164943c2aeb0SSepherosa Ziehau 				REG_WR(sc, BCE_NVM_CFG2, flash->config2);
165043c2aeb0SSepherosa Ziehau 				REG_WR(sc, BCE_NVM_CFG3, flash->config3);
165143c2aeb0SSepherosa Ziehau 				REG_WR(sc, BCE_NVM_WRITE1, flash->write1);
165243c2aeb0SSepherosa Ziehau 				bce_disable_nvram_access(sc);
165343c2aeb0SSepherosa Ziehau 				bce_release_nvram_lock(sc);
165443c2aeb0SSepherosa Ziehau 				break;
165543c2aeb0SSepherosa Ziehau 			}
165643c2aeb0SSepherosa Ziehau 		}
165743c2aeb0SSepherosa Ziehau 	}
165843c2aeb0SSepherosa Ziehau 
165943c2aeb0SSepherosa Ziehau 	/* Check if a matching device was found. */
166043c2aeb0SSepherosa Ziehau 	if (j == entry_count) {
166143c2aeb0SSepherosa Ziehau 		sc->bce_flash_info = NULL;
166243c2aeb0SSepherosa Ziehau 		if_printf(&sc->arpcom.ac_if, "Unknown Flash NVRAM found!\n");
1663d819a615SSepherosa Ziehau 		return ENODEV;
166443c2aeb0SSepherosa Ziehau 	}
166543c2aeb0SSepherosa Ziehau 
1666d0092544SSepherosa Ziehau bce_init_nvram_get_flash_size:
166743c2aeb0SSepherosa Ziehau 	/* Write the flash config data to the shared memory interface. */
1668bc30d40dSSepherosa Ziehau 	val = bce_shmem_rd(sc, BCE_SHARED_HW_CFG_CONFIG2) &
166943c2aeb0SSepherosa Ziehau 	    BCE_SHARED_HW_CFG2_NVM_SIZE_MASK;
167043c2aeb0SSepherosa Ziehau 	if (val)
167143c2aeb0SSepherosa Ziehau 		sc->bce_flash_size = val;
167243c2aeb0SSepherosa Ziehau 	else
167343c2aeb0SSepherosa Ziehau 		sc->bce_flash_size = sc->bce_flash_info->total_size;
167443c2aeb0SSepherosa Ziehau 
167543c2aeb0SSepherosa Ziehau 	return rc;
167643c2aeb0SSepherosa Ziehau }
167743c2aeb0SSepherosa Ziehau 
167843c2aeb0SSepherosa Ziehau /****************************************************************************/
167943c2aeb0SSepherosa Ziehau /* Read an arbitrary range of data from NVRAM.                              */
168043c2aeb0SSepherosa Ziehau /*                                                                          */
168143c2aeb0SSepherosa Ziehau /* Prepares the NVRAM interface for access and reads the requested data     */
168243c2aeb0SSepherosa Ziehau /* into the supplied buffer.                                                */
168343c2aeb0SSepherosa Ziehau /*                                                                          */
168443c2aeb0SSepherosa Ziehau /* Returns:                                                                 */
168543c2aeb0SSepherosa Ziehau /*   0 on success and the data read, positive value on failure.             */
168643c2aeb0SSepherosa Ziehau /****************************************************************************/
168743c2aeb0SSepherosa Ziehau static int
bce_nvram_read(struct bce_softc * sc,uint32_t offset,uint8_t * ret_buf,int buf_size)168843c2aeb0SSepherosa Ziehau bce_nvram_read(struct bce_softc *sc, uint32_t offset, uint8_t *ret_buf,
168943c2aeb0SSepherosa Ziehau 	       int buf_size)
169043c2aeb0SSepherosa Ziehau {
169143c2aeb0SSepherosa Ziehau 	uint32_t cmd_flags, offset32, len32, extra;
169243c2aeb0SSepherosa Ziehau 	int rc = 0;
169343c2aeb0SSepherosa Ziehau 
169443c2aeb0SSepherosa Ziehau 	if (buf_size == 0)
169543c2aeb0SSepherosa Ziehau 		return 0;
169643c2aeb0SSepherosa Ziehau 
169743c2aeb0SSepherosa Ziehau 	/* Request access to the flash interface. */
169843c2aeb0SSepherosa Ziehau 	rc = bce_acquire_nvram_lock(sc);
169943c2aeb0SSepherosa Ziehau 	if (rc != 0)
170043c2aeb0SSepherosa Ziehau 		return rc;
170143c2aeb0SSepherosa Ziehau 
170243c2aeb0SSepherosa Ziehau 	/* Enable access to flash interface */
170343c2aeb0SSepherosa Ziehau 	bce_enable_nvram_access(sc);
170443c2aeb0SSepherosa Ziehau 
170543c2aeb0SSepherosa Ziehau 	len32 = buf_size;
170643c2aeb0SSepherosa Ziehau 	offset32 = offset;
170743c2aeb0SSepherosa Ziehau 	extra = 0;
170843c2aeb0SSepherosa Ziehau 
170943c2aeb0SSepherosa Ziehau 	cmd_flags = 0;
171043c2aeb0SSepherosa Ziehau 
171143c2aeb0SSepherosa Ziehau 	/* XXX should we release nvram lock if read_dword() fails? */
171243c2aeb0SSepherosa Ziehau 	if (offset32 & 3) {
171343c2aeb0SSepherosa Ziehau 		uint8_t buf[4];
171443c2aeb0SSepherosa Ziehau 		uint32_t pre_len;
171543c2aeb0SSepherosa Ziehau 
171643c2aeb0SSepherosa Ziehau 		offset32 &= ~3;
171743c2aeb0SSepherosa Ziehau 		pre_len = 4 - (offset & 3);
171843c2aeb0SSepherosa Ziehau 
171943c2aeb0SSepherosa Ziehau 		if (pre_len >= len32) {
172043c2aeb0SSepherosa Ziehau 			pre_len = len32;
172143c2aeb0SSepherosa Ziehau 			cmd_flags = BCE_NVM_COMMAND_FIRST | BCE_NVM_COMMAND_LAST;
172243c2aeb0SSepherosa Ziehau 		} else {
172343c2aeb0SSepherosa Ziehau 			cmd_flags = BCE_NVM_COMMAND_FIRST;
172443c2aeb0SSepherosa Ziehau 		}
172543c2aeb0SSepherosa Ziehau 
172643c2aeb0SSepherosa Ziehau 		rc = bce_nvram_read_dword(sc, offset32, buf, cmd_flags);
172743c2aeb0SSepherosa Ziehau 		if (rc)
172843c2aeb0SSepherosa Ziehau 			return rc;
172943c2aeb0SSepherosa Ziehau 
173043c2aeb0SSepherosa Ziehau 		memcpy(ret_buf, buf + (offset & 3), pre_len);
173143c2aeb0SSepherosa Ziehau 
173243c2aeb0SSepherosa Ziehau 		offset32 += 4;
173343c2aeb0SSepherosa Ziehau 		ret_buf += pre_len;
173443c2aeb0SSepherosa Ziehau 		len32 -= pre_len;
173543c2aeb0SSepherosa Ziehau 	}
173643c2aeb0SSepherosa Ziehau 
173743c2aeb0SSepherosa Ziehau 	if (len32 & 3) {
173843c2aeb0SSepherosa Ziehau 		extra = 4 - (len32 & 3);
173943c2aeb0SSepherosa Ziehau 		len32 = (len32 + 4) & ~3;
174043c2aeb0SSepherosa Ziehau 	}
174143c2aeb0SSepherosa Ziehau 
174243c2aeb0SSepherosa Ziehau 	if (len32 == 4) {
174343c2aeb0SSepherosa Ziehau 		uint8_t buf[4];
174443c2aeb0SSepherosa Ziehau 
174543c2aeb0SSepherosa Ziehau 		if (cmd_flags)
174643c2aeb0SSepherosa Ziehau 			cmd_flags = BCE_NVM_COMMAND_LAST;
174743c2aeb0SSepherosa Ziehau 		else
174843c2aeb0SSepherosa Ziehau 			cmd_flags = BCE_NVM_COMMAND_FIRST |
174943c2aeb0SSepherosa Ziehau 				    BCE_NVM_COMMAND_LAST;
175043c2aeb0SSepherosa Ziehau 
175143c2aeb0SSepherosa Ziehau 		rc = bce_nvram_read_dword(sc, offset32, buf, cmd_flags);
175243c2aeb0SSepherosa Ziehau 
175343c2aeb0SSepherosa Ziehau 		memcpy(ret_buf, buf, 4 - extra);
175443c2aeb0SSepherosa Ziehau 	} else if (len32 > 0) {
175543c2aeb0SSepherosa Ziehau 		uint8_t buf[4];
175643c2aeb0SSepherosa Ziehau 
175743c2aeb0SSepherosa Ziehau 		/* Read the first word. */
175843c2aeb0SSepherosa Ziehau 		if (cmd_flags)
175943c2aeb0SSepherosa Ziehau 			cmd_flags = 0;
176043c2aeb0SSepherosa Ziehau 		else
176143c2aeb0SSepherosa Ziehau 			cmd_flags = BCE_NVM_COMMAND_FIRST;
176243c2aeb0SSepherosa Ziehau 
176343c2aeb0SSepherosa Ziehau 		rc = bce_nvram_read_dword(sc, offset32, ret_buf, cmd_flags);
176443c2aeb0SSepherosa Ziehau 
176543c2aeb0SSepherosa Ziehau 		/* Advance to the next dword. */
176643c2aeb0SSepherosa Ziehau 		offset32 += 4;
176743c2aeb0SSepherosa Ziehau 		ret_buf += 4;
176843c2aeb0SSepherosa Ziehau 		len32 -= 4;
176943c2aeb0SSepherosa Ziehau 
177043c2aeb0SSepherosa Ziehau 		while (len32 > 4 && rc == 0) {
177143c2aeb0SSepherosa Ziehau 			rc = bce_nvram_read_dword(sc, offset32, ret_buf, 0);
177243c2aeb0SSepherosa Ziehau 
177343c2aeb0SSepherosa Ziehau 			/* Advance to the next dword. */
177443c2aeb0SSepherosa Ziehau 			offset32 += 4;
177543c2aeb0SSepherosa Ziehau 			ret_buf += 4;
177643c2aeb0SSepherosa Ziehau 			len32 -= 4;
177743c2aeb0SSepherosa Ziehau 		}
177843c2aeb0SSepherosa Ziehau 
177943c2aeb0SSepherosa Ziehau 		if (rc)
1780d0092544SSepherosa Ziehau 			goto bce_nvram_read_locked_exit;
178143c2aeb0SSepherosa Ziehau 
178243c2aeb0SSepherosa Ziehau 		cmd_flags = BCE_NVM_COMMAND_LAST;
178343c2aeb0SSepherosa Ziehau 		rc = bce_nvram_read_dword(sc, offset32, buf, cmd_flags);
178443c2aeb0SSepherosa Ziehau 
178543c2aeb0SSepherosa Ziehau 		memcpy(ret_buf, buf, 4 - extra);
178643c2aeb0SSepherosa Ziehau 	}
178743c2aeb0SSepherosa Ziehau 
1788d0092544SSepherosa Ziehau bce_nvram_read_locked_exit:
178943c2aeb0SSepherosa Ziehau 	/* Disable access to flash interface and release the lock. */
179043c2aeb0SSepherosa Ziehau 	bce_disable_nvram_access(sc);
179143c2aeb0SSepherosa Ziehau 	bce_release_nvram_lock(sc);
179243c2aeb0SSepherosa Ziehau 
179343c2aeb0SSepherosa Ziehau 	return rc;
179443c2aeb0SSepherosa Ziehau }
179543c2aeb0SSepherosa Ziehau 
179643c2aeb0SSepherosa Ziehau /****************************************************************************/
179743c2aeb0SSepherosa Ziehau /* Verifies that NVRAM is accessible and contains valid data.               */
179843c2aeb0SSepherosa Ziehau /*                                                                          */
179943c2aeb0SSepherosa Ziehau /* Reads the configuration data from NVRAM and verifies that the CRC is     */
180043c2aeb0SSepherosa Ziehau /* correct.                                                                 */
180143c2aeb0SSepherosa Ziehau /*                                                                          */
180243c2aeb0SSepherosa Ziehau /* Returns:                                                                 */
180343c2aeb0SSepherosa Ziehau /*   0 on success, positive value on failure.                               */
180443c2aeb0SSepherosa Ziehau /****************************************************************************/
180543c2aeb0SSepherosa Ziehau static int
bce_nvram_test(struct bce_softc * sc)180643c2aeb0SSepherosa Ziehau bce_nvram_test(struct bce_softc *sc)
180743c2aeb0SSepherosa Ziehau {
180843c2aeb0SSepherosa Ziehau 	uint32_t buf[BCE_NVRAM_SIZE / 4];
180943c2aeb0SSepherosa Ziehau 	uint32_t magic, csum;
181043c2aeb0SSepherosa Ziehau 	uint8_t *data = (uint8_t *)buf;
181143c2aeb0SSepherosa Ziehau 	int rc = 0;
181243c2aeb0SSepherosa Ziehau 
181343c2aeb0SSepherosa Ziehau 	/*
181443c2aeb0SSepherosa Ziehau 	 * Check that the device NVRAM is valid by reading
181543c2aeb0SSepherosa Ziehau 	 * the magic value at offset 0.
181643c2aeb0SSepherosa Ziehau 	 */
181743c2aeb0SSepherosa Ziehau 	rc = bce_nvram_read(sc, 0, data, 4);
181843c2aeb0SSepherosa Ziehau 	if (rc != 0)
181943c2aeb0SSepherosa Ziehau 		return rc;
182043c2aeb0SSepherosa Ziehau 
182143c2aeb0SSepherosa Ziehau 	magic = be32toh(buf[0]);
182243c2aeb0SSepherosa Ziehau 	if (magic != BCE_NVRAM_MAGIC) {
182343c2aeb0SSepherosa Ziehau 		if_printf(&sc->arpcom.ac_if,
182443c2aeb0SSepherosa Ziehau 			  "Invalid NVRAM magic value! Expected: 0x%08X, "
182543c2aeb0SSepherosa Ziehau 			  "Found: 0x%08X\n", BCE_NVRAM_MAGIC, magic);
182643c2aeb0SSepherosa Ziehau 		return ENODEV;
182743c2aeb0SSepherosa Ziehau 	}
182843c2aeb0SSepherosa Ziehau 
182943c2aeb0SSepherosa Ziehau 	/*
183043c2aeb0SSepherosa Ziehau 	 * Verify that the device NVRAM includes valid
183143c2aeb0SSepherosa Ziehau 	 * configuration data.
183243c2aeb0SSepherosa Ziehau 	 */
183343c2aeb0SSepherosa Ziehau 	rc = bce_nvram_read(sc, 0x100, data, BCE_NVRAM_SIZE);
183443c2aeb0SSepherosa Ziehau 	if (rc != 0)
183543c2aeb0SSepherosa Ziehau 		return rc;
183643c2aeb0SSepherosa Ziehau 
183743c2aeb0SSepherosa Ziehau 	csum = ether_crc32_le(data, 0x100);
183843c2aeb0SSepherosa Ziehau 	if (csum != BCE_CRC32_RESIDUAL) {
183943c2aeb0SSepherosa Ziehau 		if_printf(&sc->arpcom.ac_if,
184043c2aeb0SSepherosa Ziehau 			  "Invalid Manufacturing Information NVRAM CRC! "
184143c2aeb0SSepherosa Ziehau 			  "Expected: 0x%08X, Found: 0x%08X\n",
184243c2aeb0SSepherosa Ziehau 			  BCE_CRC32_RESIDUAL, csum);
184343c2aeb0SSepherosa Ziehau 		return ENODEV;
184443c2aeb0SSepherosa Ziehau 	}
184543c2aeb0SSepherosa Ziehau 
184643c2aeb0SSepherosa Ziehau 	csum = ether_crc32_le(data + 0x100, 0x100);
184743c2aeb0SSepherosa Ziehau 	if (csum != BCE_CRC32_RESIDUAL) {
184843c2aeb0SSepherosa Ziehau 		if_printf(&sc->arpcom.ac_if,
184943c2aeb0SSepherosa Ziehau 			  "Invalid Feature Configuration Information "
185043c2aeb0SSepherosa Ziehau 			  "NVRAM CRC! Expected: 0x%08X, Found: 08%08X\n",
185143c2aeb0SSepherosa Ziehau 			  BCE_CRC32_RESIDUAL, csum);
185243c2aeb0SSepherosa Ziehau 		rc = ENODEV;
185343c2aeb0SSepherosa Ziehau 	}
185443c2aeb0SSepherosa Ziehau 	return rc;
185543c2aeb0SSepherosa Ziehau }
185643c2aeb0SSepherosa Ziehau 
185743c2aeb0SSepherosa Ziehau /****************************************************************************/
1858d0092544SSepherosa Ziehau /* Identifies the current media type of the controller and sets the PHY     */
1859d0092544SSepherosa Ziehau /* address.                                                                 */
1860d0092544SSepherosa Ziehau /*                                                                          */
1861d0092544SSepherosa Ziehau /* Returns:                                                                 */
1862d0092544SSepherosa Ziehau /*   Nothing.                                                               */
1863d0092544SSepherosa Ziehau /****************************************************************************/
1864d0092544SSepherosa Ziehau static void
bce_get_media(struct bce_softc * sc)1865d0092544SSepherosa Ziehau bce_get_media(struct bce_softc *sc)
1866d0092544SSepherosa Ziehau {
1867d0092544SSepherosa Ziehau 	uint32_t val;
1868d0092544SSepherosa Ziehau 
1869d0092544SSepherosa Ziehau 	sc->bce_phy_addr = 1;
1870d0092544SSepherosa Ziehau 
1871d0092544SSepherosa Ziehau 	if (BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5709 ||
1872d0092544SSepherosa Ziehau 	    BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5716) {
1873d0092544SSepherosa Ziehau  		uint32_t val = REG_RD(sc, BCE_MISC_DUAL_MEDIA_CTRL);
1874d0092544SSepherosa Ziehau 		uint32_t bond_id = val & BCE_MISC_DUAL_MEDIA_CTRL_BOND_ID;
1875d0092544SSepherosa Ziehau 		uint32_t strap;
1876d0092544SSepherosa Ziehau 
1877d0092544SSepherosa Ziehau 		/*
1878d0092544SSepherosa Ziehau 		 * The BCM5709S is software configurable
1879d0092544SSepherosa Ziehau 		 * for Copper or SerDes operation.
1880d0092544SSepherosa Ziehau 		 */
1881d0092544SSepherosa Ziehau 		if (bond_id == BCE_MISC_DUAL_MEDIA_CTRL_BOND_ID_C) {
1882d0092544SSepherosa Ziehau 			return;
1883d0092544SSepherosa Ziehau 		} else if (bond_id == BCE_MISC_DUAL_MEDIA_CTRL_BOND_ID_S) {
1884d0092544SSepherosa Ziehau 			sc->bce_phy_flags |= BCE_PHY_SERDES_FLAG;
1885d0092544SSepherosa Ziehau 			return;
1886d0092544SSepherosa Ziehau 		}
1887d0092544SSepherosa Ziehau 
1888d0092544SSepherosa Ziehau 		if (val & BCE_MISC_DUAL_MEDIA_CTRL_STRAP_OVERRIDE) {
1889d0092544SSepherosa Ziehau 			strap = (val & BCE_MISC_DUAL_MEDIA_CTRL_PHY_CTRL) >> 21;
1890d0092544SSepherosa Ziehau 		} else {
1891d0092544SSepherosa Ziehau 			strap =
1892d0092544SSepherosa Ziehau 			(val & BCE_MISC_DUAL_MEDIA_CTRL_PHY_CTRL_STRAP) >> 8;
1893d0092544SSepherosa Ziehau 		}
1894d0092544SSepherosa Ziehau 
1895d0092544SSepherosa Ziehau 		if (pci_get_function(sc->bce_dev) == 0) {
1896d0092544SSepherosa Ziehau 			switch (strap) {
1897d0092544SSepherosa Ziehau 			case 0x4:
1898d0092544SSepherosa Ziehau 			case 0x5:
1899d0092544SSepherosa Ziehau 			case 0x6:
1900d0092544SSepherosa Ziehau 				sc->bce_phy_flags |= BCE_PHY_SERDES_FLAG;
1901d0092544SSepherosa Ziehau 				break;
1902d0092544SSepherosa Ziehau 			}
1903d0092544SSepherosa Ziehau 		} else {
1904d0092544SSepherosa Ziehau 			switch (strap) {
1905d0092544SSepherosa Ziehau 			case 0x1:
1906d0092544SSepherosa Ziehau 			case 0x2:
1907d0092544SSepherosa Ziehau 			case 0x4:
1908d0092544SSepherosa Ziehau 				sc->bce_phy_flags |= BCE_PHY_SERDES_FLAG;
1909d0092544SSepherosa Ziehau 				break;
1910d0092544SSepherosa Ziehau 			}
1911d0092544SSepherosa Ziehau 		}
1912d0092544SSepherosa Ziehau 	} else if (BCE_CHIP_BOND_ID(sc) & BCE_CHIP_BOND_ID_SERDES_BIT) {
1913d0092544SSepherosa Ziehau 		sc->bce_phy_flags |= BCE_PHY_SERDES_FLAG;
1914d0092544SSepherosa Ziehau 	}
1915d0092544SSepherosa Ziehau 
1916d0092544SSepherosa Ziehau 	if (sc->bce_phy_flags & BCE_PHY_SERDES_FLAG) {
1917d0092544SSepherosa Ziehau 		sc->bce_flags |= BCE_NO_WOL_FLAG;
1918d0092544SSepherosa Ziehau 		if (BCE_CHIP_NUM(sc) != BCE_CHIP_NUM_5706) {
1919d0092544SSepherosa Ziehau 			sc->bce_phy_addr = 2;
1920bc30d40dSSepherosa Ziehau 			val = bce_shmem_rd(sc, BCE_SHARED_HW_CFG_CONFIG);
1921d0092544SSepherosa Ziehau 			if (val & BCE_SHARED_HW_CFG_PHY_2_5G)
1922d0092544SSepherosa Ziehau 				sc->bce_phy_flags |= BCE_PHY_2_5G_CAPABLE_FLAG;
1923d0092544SSepherosa Ziehau 		}
1924d0092544SSepherosa Ziehau 	} else if ((BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5706) ||
1925d0092544SSepherosa Ziehau 	    (BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5708)) {
1926d0092544SSepherosa Ziehau 		sc->bce_phy_flags |= BCE_PHY_CRC_FIX_FLAG;
1927d0092544SSepherosa Ziehau 	}
1928d0092544SSepherosa Ziehau }
1929d0092544SSepherosa Ziehau 
193010bcbdabSSepherosa Ziehau static void
bce_destroy_tx_ring(struct bce_tx_ring * txr)193110bcbdabSSepherosa Ziehau bce_destroy_tx_ring(struct bce_tx_ring *txr)
193210bcbdabSSepherosa Ziehau {
193310bcbdabSSepherosa Ziehau 	int i;
193410bcbdabSSepherosa Ziehau 
193510bcbdabSSepherosa Ziehau 	/* Destroy the TX buffer descriptor DMA stuffs. */
193610bcbdabSSepherosa Ziehau 	if (txr->tx_bd_chain_tag != NULL) {
193710bcbdabSSepherosa Ziehau 		for (i = 0; i < txr->tx_pages; i++) {
193810bcbdabSSepherosa Ziehau 			if (txr->tx_bd_chain[i] != NULL) {
193910bcbdabSSepherosa Ziehau 				bus_dmamap_unload(txr->tx_bd_chain_tag,
194010bcbdabSSepherosa Ziehau 				    txr->tx_bd_chain_map[i]);
194110bcbdabSSepherosa Ziehau 				bus_dmamem_free(txr->tx_bd_chain_tag,
194210bcbdabSSepherosa Ziehau 				    txr->tx_bd_chain[i],
194310bcbdabSSepherosa Ziehau 				    txr->tx_bd_chain_map[i]);
194410bcbdabSSepherosa Ziehau 			}
194510bcbdabSSepherosa Ziehau 		}
194610bcbdabSSepherosa Ziehau 		bus_dma_tag_destroy(txr->tx_bd_chain_tag);
194710bcbdabSSepherosa Ziehau 	}
194810bcbdabSSepherosa Ziehau 
194910bcbdabSSepherosa Ziehau 	/* Destroy the TX mbuf DMA stuffs. */
195010bcbdabSSepherosa Ziehau 	if (txr->tx_mbuf_tag != NULL) {
195110bcbdabSSepherosa Ziehau 		for (i = 0; i < TOTAL_TX_BD(txr); i++) {
195210bcbdabSSepherosa Ziehau 			/* Must have been unloaded in bce_stop() */
195386ae632dSSepherosa Ziehau 			KKASSERT(txr->tx_bufs[i].tx_mbuf_ptr == NULL);
195410bcbdabSSepherosa Ziehau 			bus_dmamap_destroy(txr->tx_mbuf_tag,
195586ae632dSSepherosa Ziehau 			    txr->tx_bufs[i].tx_mbuf_map);
195610bcbdabSSepherosa Ziehau 		}
195710bcbdabSSepherosa Ziehau 		bus_dma_tag_destroy(txr->tx_mbuf_tag);
195810bcbdabSSepherosa Ziehau 	}
195910bcbdabSSepherosa Ziehau 
196010bcbdabSSepherosa Ziehau 	if (txr->tx_bd_chain_map != NULL)
196110bcbdabSSepherosa Ziehau 		kfree(txr->tx_bd_chain_map, M_DEVBUF);
196210bcbdabSSepherosa Ziehau 	if (txr->tx_bd_chain != NULL)
196310bcbdabSSepherosa Ziehau 		kfree(txr->tx_bd_chain, M_DEVBUF);
196410bcbdabSSepherosa Ziehau 	if (txr->tx_bd_chain_paddr != NULL)
196510bcbdabSSepherosa Ziehau 		kfree(txr->tx_bd_chain_paddr, M_DEVBUF);
196610bcbdabSSepherosa Ziehau 
196786ae632dSSepherosa Ziehau 	if (txr->tx_bufs != NULL)
196886ae632dSSepherosa Ziehau 		kfree(txr->tx_bufs, M_DEVBUF);
196910bcbdabSSepherosa Ziehau }
197010bcbdabSSepherosa Ziehau 
197108b64767SSepherosa Ziehau static void
bce_destroy_rx_ring(struct bce_rx_ring * rxr)197208b64767SSepherosa Ziehau bce_destroy_rx_ring(struct bce_rx_ring *rxr)
197308b64767SSepherosa Ziehau {
197408b64767SSepherosa Ziehau 	int i;
197508b64767SSepherosa Ziehau 
197608b64767SSepherosa Ziehau 	/* Destroy the RX buffer descriptor DMA stuffs. */
197708b64767SSepherosa Ziehau 	if (rxr->rx_bd_chain_tag != NULL) {
197808b64767SSepherosa Ziehau 		for (i = 0; i < rxr->rx_pages; i++) {
197908b64767SSepherosa Ziehau 			if (rxr->rx_bd_chain[i] != NULL) {
198008b64767SSepherosa Ziehau 				bus_dmamap_unload(rxr->rx_bd_chain_tag,
198108b64767SSepherosa Ziehau 				    rxr->rx_bd_chain_map[i]);
198208b64767SSepherosa Ziehau 				bus_dmamem_free(rxr->rx_bd_chain_tag,
198308b64767SSepherosa Ziehau 				    rxr->rx_bd_chain[i],
198408b64767SSepherosa Ziehau 				    rxr->rx_bd_chain_map[i]);
198508b64767SSepherosa Ziehau 			}
198608b64767SSepherosa Ziehau 		}
198708b64767SSepherosa Ziehau 		bus_dma_tag_destroy(rxr->rx_bd_chain_tag);
198808b64767SSepherosa Ziehau 	}
198908b64767SSepherosa Ziehau 
199008b64767SSepherosa Ziehau 	/* Destroy the RX mbuf DMA stuffs. */
199108b64767SSepherosa Ziehau 	if (rxr->rx_mbuf_tag != NULL) {
199208b64767SSepherosa Ziehau 		for (i = 0; i < TOTAL_RX_BD(rxr); i++) {
199308b64767SSepherosa Ziehau 			/* Must have been unloaded in bce_stop() */
199486ae632dSSepherosa Ziehau 			KKASSERT(rxr->rx_bufs[i].rx_mbuf_ptr == NULL);
199508b64767SSepherosa Ziehau 			bus_dmamap_destroy(rxr->rx_mbuf_tag,
199686ae632dSSepherosa Ziehau 			    rxr->rx_bufs[i].rx_mbuf_map);
199708b64767SSepherosa Ziehau 		}
199808b64767SSepherosa Ziehau 		bus_dmamap_destroy(rxr->rx_mbuf_tag, rxr->rx_mbuf_tmpmap);
199908b64767SSepherosa Ziehau 		bus_dma_tag_destroy(rxr->rx_mbuf_tag);
200008b64767SSepherosa Ziehau 	}
200108b64767SSepherosa Ziehau 
200208b64767SSepherosa Ziehau 	if (rxr->rx_bd_chain_map != NULL)
200308b64767SSepherosa Ziehau 		kfree(rxr->rx_bd_chain_map, M_DEVBUF);
200408b64767SSepherosa Ziehau 	if (rxr->rx_bd_chain != NULL)
200508b64767SSepherosa Ziehau 		kfree(rxr->rx_bd_chain, M_DEVBUF);
200608b64767SSepherosa Ziehau 	if (rxr->rx_bd_chain_paddr != NULL)
200708b64767SSepherosa Ziehau 		kfree(rxr->rx_bd_chain_paddr, M_DEVBUF);
200808b64767SSepherosa Ziehau 
200986ae632dSSepherosa Ziehau 	if (rxr->rx_bufs != NULL)
201086ae632dSSepherosa Ziehau 		kfree(rxr->rx_bufs, M_DEVBUF);
201108b64767SSepherosa Ziehau }
201208b64767SSepherosa Ziehau 
2013d0092544SSepherosa Ziehau /****************************************************************************/
201443c2aeb0SSepherosa Ziehau /* Free any DMA memory owned by the driver.                                 */
201543c2aeb0SSepherosa Ziehau /*                                                                          */
201643c2aeb0SSepherosa Ziehau /* Scans through each data structre that requires DMA memory and frees      */
201743c2aeb0SSepherosa Ziehau /* the memory if allocated.                                                 */
201843c2aeb0SSepherosa Ziehau /*                                                                          */
201943c2aeb0SSepherosa Ziehau /* Returns:                                                                 */
202043c2aeb0SSepherosa Ziehau /*   Nothing.                                                               */
202143c2aeb0SSepherosa Ziehau /****************************************************************************/
202243c2aeb0SSepherosa Ziehau static void
bce_dma_free(struct bce_softc * sc)202343c2aeb0SSepherosa Ziehau bce_dma_free(struct bce_softc *sc)
202443c2aeb0SSepherosa Ziehau {
202543c2aeb0SSepherosa Ziehau 	int i;
202643c2aeb0SSepherosa Ziehau 
202743c2aeb0SSepherosa Ziehau 	/* Destroy the status block. */
202843c2aeb0SSepherosa Ziehau 	if (sc->status_tag != NULL) {
202943c2aeb0SSepherosa Ziehau 		if (sc->status_block != NULL) {
203043c2aeb0SSepherosa Ziehau 			bus_dmamap_unload(sc->status_tag, sc->status_map);
203143c2aeb0SSepherosa Ziehau 			bus_dmamem_free(sc->status_tag, sc->status_block,
203243c2aeb0SSepherosa Ziehau 					sc->status_map);
203343c2aeb0SSepherosa Ziehau 		}
203443c2aeb0SSepherosa Ziehau 		bus_dma_tag_destroy(sc->status_tag);
203543c2aeb0SSepherosa Ziehau 	}
203643c2aeb0SSepherosa Ziehau 
203743c2aeb0SSepherosa Ziehau 	/* Destroy the statistics block. */
203843c2aeb0SSepherosa Ziehau 	if (sc->stats_tag != NULL) {
203943c2aeb0SSepherosa Ziehau 		if (sc->stats_block != NULL) {
204043c2aeb0SSepherosa Ziehau 			bus_dmamap_unload(sc->stats_tag, sc->stats_map);
204143c2aeb0SSepherosa Ziehau 			bus_dmamem_free(sc->stats_tag, sc->stats_block,
204243c2aeb0SSepherosa Ziehau 					sc->stats_map);
204343c2aeb0SSepherosa Ziehau 		}
204443c2aeb0SSepherosa Ziehau 		bus_dma_tag_destroy(sc->stats_tag);
204543c2aeb0SSepherosa Ziehau 	}
204643c2aeb0SSepherosa Ziehau 
2047d0092544SSepherosa Ziehau 	/* Destroy the CTX DMA stuffs. */
2048d0092544SSepherosa Ziehau 	if (sc->ctx_tag != NULL) {
2049d0092544SSepherosa Ziehau 		for (i = 0; i < sc->ctx_pages; i++) {
2050d0092544SSepherosa Ziehau 			if (sc->ctx_block[i] != NULL) {
2051d0092544SSepherosa Ziehau 				bus_dmamap_unload(sc->ctx_tag, sc->ctx_map[i]);
2052d0092544SSepherosa Ziehau 				bus_dmamem_free(sc->ctx_tag, sc->ctx_block[i],
2053d0092544SSepherosa Ziehau 						sc->ctx_map[i]);
2054d0092544SSepherosa Ziehau 			}
2055d0092544SSepherosa Ziehau 		}
2056d0092544SSepherosa Ziehau 		bus_dma_tag_destroy(sc->ctx_tag);
2057d0092544SSepherosa Ziehau 	}
2058d0092544SSepherosa Ziehau 
205910bcbdabSSepherosa Ziehau 	/* Free TX rings */
206010bcbdabSSepherosa Ziehau 	if (sc->tx_rings != NULL) {
2061ac2202eaSSepherosa Ziehau 		for (i = 0; i < sc->tx_ring_cnt; ++i)
206210bcbdabSSepherosa Ziehau 			bce_destroy_tx_ring(&sc->tx_rings[i]);
206310bcbdabSSepherosa Ziehau 		kfree(sc->tx_rings, M_DEVBUF);
206443c2aeb0SSepherosa Ziehau 	}
206543c2aeb0SSepherosa Ziehau 
206608b64767SSepherosa Ziehau 	/* Free RX rings */
206708b64767SSepherosa Ziehau 	if (sc->rx_rings != NULL) {
2068ac2202eaSSepherosa Ziehau 		for (i = 0; i < sc->rx_ring_cnt; ++i)
206908b64767SSepherosa Ziehau 			bce_destroy_rx_ring(&sc->rx_rings[i]);
207008b64767SSepherosa Ziehau 		kfree(sc->rx_rings, M_DEVBUF);
207143c2aeb0SSepherosa Ziehau 	}
207243c2aeb0SSepherosa Ziehau 
207343c2aeb0SSepherosa Ziehau 	/* Destroy the parent tag */
207443c2aeb0SSepherosa Ziehau 	if (sc->parent_tag != NULL)
207543c2aeb0SSepherosa Ziehau 		bus_dma_tag_destroy(sc->parent_tag);
207643c2aeb0SSepherosa Ziehau }
207743c2aeb0SSepherosa Ziehau 
207843c2aeb0SSepherosa Ziehau /****************************************************************************/
207943c2aeb0SSepherosa Ziehau /* Get DMA memory from the OS.                                              */
208043c2aeb0SSepherosa Ziehau /*                                                                          */
208143c2aeb0SSepherosa Ziehau /* Validates that the OS has provided DMA buffers in response to a          */
208243c2aeb0SSepherosa Ziehau /* bus_dmamap_load() call and saves the physical address of those buffers.  */
208343c2aeb0SSepherosa Ziehau /* When the callback is used the OS will return 0 for the mapping function  */
208443c2aeb0SSepherosa Ziehau /* (bus_dmamap_load()) so we use the value of map_arg->maxsegs to pass any  */
208543c2aeb0SSepherosa Ziehau /* failures back to the caller.                                             */
208643c2aeb0SSepherosa Ziehau /*                                                                          */
208743c2aeb0SSepherosa Ziehau /* Returns:                                                                 */
208843c2aeb0SSepherosa Ziehau /*   Nothing.                                                               */
208943c2aeb0SSepherosa Ziehau /****************************************************************************/
209043c2aeb0SSepherosa Ziehau static void
bce_dma_map_addr(void * arg,bus_dma_segment_t * segs,int nseg,int error)209143c2aeb0SSepherosa Ziehau bce_dma_map_addr(void *arg, bus_dma_segment_t *segs, int nseg, int error)
209243c2aeb0SSepherosa Ziehau {
209343c2aeb0SSepherosa Ziehau 	bus_addr_t *busaddr = arg;
209443c2aeb0SSepherosa Ziehau 
209543c2aeb0SSepherosa Ziehau 	/* Check for an error and signal the caller that an error occurred. */
209643c2aeb0SSepherosa Ziehau 	if (error)
209743c2aeb0SSepherosa Ziehau 		return;
209843c2aeb0SSepherosa Ziehau 
2099ed20d0e3SSascha Wildner 	KASSERT(nseg == 1, ("only one segment is allowed"));
210043c2aeb0SSepherosa Ziehau 	*busaddr = segs->ds_addr;
210143c2aeb0SSepherosa Ziehau }
210243c2aeb0SSepherosa Ziehau 
210310bcbdabSSepherosa Ziehau static int
bce_create_tx_ring(struct bce_tx_ring * txr)210410bcbdabSSepherosa Ziehau bce_create_tx_ring(struct bce_tx_ring *txr)
210510bcbdabSSepherosa Ziehau {
210610bcbdabSSepherosa Ziehau 	int pages, rc, i;
210710bcbdabSSepherosa Ziehau 
210884464af5SSepherosa Ziehau 	lwkt_serialize_init(&txr->tx_serialize);
210910bcbdabSSepherosa Ziehau 	txr->tx_wreg = bce_tx_wreg;
211010bcbdabSSepherosa Ziehau 
211110bcbdabSSepherosa Ziehau 	pages = device_getenv_int(txr->sc->bce_dev, "tx_pages", bce_tx_pages);
211210bcbdabSSepherosa Ziehau 	if (pages <= 0 || pages > TX_PAGES_MAX || !powerof2(pages)) {
211310bcbdabSSepherosa Ziehau 		device_printf(txr->sc->bce_dev, "invalid # of TX pages\n");
211410bcbdabSSepherosa Ziehau 		pages = TX_PAGES_DEFAULT;
211510bcbdabSSepherosa Ziehau 	}
211610bcbdabSSepherosa Ziehau 	txr->tx_pages = pages;
211710bcbdabSSepherosa Ziehau 
211810bcbdabSSepherosa Ziehau 	txr->tx_bd_chain_map = kmalloc(sizeof(bus_dmamap_t) * txr->tx_pages,
211910bcbdabSSepherosa Ziehau 	    M_DEVBUF, M_WAITOK | M_ZERO);
212010bcbdabSSepherosa Ziehau 	txr->tx_bd_chain = kmalloc(sizeof(struct tx_bd *) * txr->tx_pages,
212110bcbdabSSepherosa Ziehau 	    M_DEVBUF, M_WAITOK | M_ZERO);
212210bcbdabSSepherosa Ziehau 	txr->tx_bd_chain_paddr = kmalloc(sizeof(bus_addr_t) * txr->tx_pages,
212310bcbdabSSepherosa Ziehau 	    M_DEVBUF, M_WAITOK | M_ZERO);
212410bcbdabSSepherosa Ziehau 
212562938642SMatthew Dillon 	txr->tx_bufs = kmalloc(sizeof(struct bce_tx_buf) * TOTAL_TX_BD(txr),
212662938642SMatthew Dillon 			       M_DEVBUF,
212762938642SMatthew Dillon 			       M_WAITOK | M_ZERO | M_CACHEALIGN);
212810bcbdabSSepherosa Ziehau 
212910bcbdabSSepherosa Ziehau 	/*
213010bcbdabSSepherosa Ziehau 	 * Create a DMA tag for the TX buffer descriptor chain,
213110bcbdabSSepherosa Ziehau 	 * allocate and clear the  memory, and fetch the
213210bcbdabSSepherosa Ziehau 	 * physical address of the block.
213310bcbdabSSepherosa Ziehau 	 */
213410bcbdabSSepherosa Ziehau 	rc = bus_dma_tag_create(txr->sc->parent_tag, BCM_PAGE_SIZE, 0,
2135*030b0c8cSMichael Neumann 	    BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR,
213610bcbdabSSepherosa Ziehau 	    BCE_TX_CHAIN_PAGE_SZ, 1, BCE_TX_CHAIN_PAGE_SZ,
213710bcbdabSSepherosa Ziehau 	    0, &txr->tx_bd_chain_tag);
213810bcbdabSSepherosa Ziehau 	if (rc != 0) {
213910bcbdabSSepherosa Ziehau 		device_printf(txr->sc->bce_dev, "Could not allocate "
214010bcbdabSSepherosa Ziehau 		    "TX descriptor chain DMA tag!\n");
214110bcbdabSSepherosa Ziehau 		return rc;
214210bcbdabSSepherosa Ziehau 	}
214310bcbdabSSepherosa Ziehau 
214410bcbdabSSepherosa Ziehau 	for (i = 0; i < txr->tx_pages; i++) {
214510bcbdabSSepherosa Ziehau 		bus_addr_t busaddr;
214610bcbdabSSepherosa Ziehau 
214710bcbdabSSepherosa Ziehau 		rc = bus_dmamem_alloc(txr->tx_bd_chain_tag,
214810bcbdabSSepherosa Ziehau 		    (void **)&txr->tx_bd_chain[i],
214910bcbdabSSepherosa Ziehau 		    BUS_DMA_WAITOK | BUS_DMA_ZERO | BUS_DMA_COHERENT,
215010bcbdabSSepherosa Ziehau 		    &txr->tx_bd_chain_map[i]);
215110bcbdabSSepherosa Ziehau 		if (rc != 0) {
215210bcbdabSSepherosa Ziehau 			device_printf(txr->sc->bce_dev,
215310bcbdabSSepherosa Ziehau 			    "Could not allocate %dth TX descriptor "
215410bcbdabSSepherosa Ziehau 			    "chain DMA memory!\n", i);
215510bcbdabSSepherosa Ziehau 			return rc;
215610bcbdabSSepherosa Ziehau 		}
215710bcbdabSSepherosa Ziehau 
215810bcbdabSSepherosa Ziehau 		rc = bus_dmamap_load(txr->tx_bd_chain_tag,
215910bcbdabSSepherosa Ziehau 		    txr->tx_bd_chain_map[i],
216010bcbdabSSepherosa Ziehau 		    txr->tx_bd_chain[i],
216110bcbdabSSepherosa Ziehau 		    BCE_TX_CHAIN_PAGE_SZ,
216210bcbdabSSepherosa Ziehau 		    bce_dma_map_addr, &busaddr,
216310bcbdabSSepherosa Ziehau 		    BUS_DMA_WAITOK);
216410bcbdabSSepherosa Ziehau 		if (rc != 0) {
216510bcbdabSSepherosa Ziehau 			if (rc == EINPROGRESS) {
216610bcbdabSSepherosa Ziehau 				panic("%s coherent memory loading "
216710bcbdabSSepherosa Ziehau 				    "is still in progress!",
216810bcbdabSSepherosa Ziehau 				    txr->sc->arpcom.ac_if.if_xname);
216910bcbdabSSepherosa Ziehau 			}
217010bcbdabSSepherosa Ziehau 			device_printf(txr->sc->bce_dev, "Could not map %dth "
217110bcbdabSSepherosa Ziehau 			    "TX descriptor chain DMA memory!\n", i);
217210bcbdabSSepherosa Ziehau 			bus_dmamem_free(txr->tx_bd_chain_tag,
217310bcbdabSSepherosa Ziehau 			    txr->tx_bd_chain[i],
217410bcbdabSSepherosa Ziehau 			    txr->tx_bd_chain_map[i]);
217510bcbdabSSepherosa Ziehau 			txr->tx_bd_chain[i] = NULL;
217610bcbdabSSepherosa Ziehau 			return rc;
217710bcbdabSSepherosa Ziehau 		}
217810bcbdabSSepherosa Ziehau 
217910bcbdabSSepherosa Ziehau 		txr->tx_bd_chain_paddr[i] = busaddr;
218010bcbdabSSepherosa Ziehau 	}
218110bcbdabSSepherosa Ziehau 
218210bcbdabSSepherosa Ziehau 	/* Create a DMA tag for TX mbufs. */
218310bcbdabSSepherosa Ziehau 	rc = bus_dma_tag_create(txr->sc->parent_tag, 1, 0,
2184*030b0c8cSMichael Neumann 	    BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR,
218510bcbdabSSepherosa Ziehau 	    IP_MAXPACKET + sizeof(struct ether_vlan_header),
218610bcbdabSSepherosa Ziehau 	    BCE_MAX_SEGMENTS, PAGE_SIZE,
218710bcbdabSSepherosa Ziehau 	    BUS_DMA_ALLOCNOW | BUS_DMA_WAITOK | BUS_DMA_ONEBPAGE,
218810bcbdabSSepherosa Ziehau 	    &txr->tx_mbuf_tag);
218910bcbdabSSepherosa Ziehau 	if (rc != 0) {
219010bcbdabSSepherosa Ziehau 		device_printf(txr->sc->bce_dev,
219110bcbdabSSepherosa Ziehau 		    "Could not allocate TX mbuf DMA tag!\n");
219210bcbdabSSepherosa Ziehau 		return rc;
219310bcbdabSSepherosa Ziehau 	}
219410bcbdabSSepherosa Ziehau 
219510bcbdabSSepherosa Ziehau 	/* Create DMA maps for the TX mbufs clusters. */
219610bcbdabSSepherosa Ziehau 	for (i = 0; i < TOTAL_TX_BD(txr); i++) {
219710bcbdabSSepherosa Ziehau 		rc = bus_dmamap_create(txr->tx_mbuf_tag,
219810bcbdabSSepherosa Ziehau 		    BUS_DMA_WAITOK | BUS_DMA_ONEBPAGE,
219986ae632dSSepherosa Ziehau 		    &txr->tx_bufs[i].tx_mbuf_map);
220010bcbdabSSepherosa Ziehau 		if (rc != 0) {
220110bcbdabSSepherosa Ziehau 			int j;
220210bcbdabSSepherosa Ziehau 
220310bcbdabSSepherosa Ziehau 			for (j = 0; j < i; ++j) {
220410bcbdabSSepherosa Ziehau 				bus_dmamap_destroy(txr->tx_mbuf_tag,
220586ae632dSSepherosa Ziehau 				    txr->tx_bufs[j].tx_mbuf_map);
220610bcbdabSSepherosa Ziehau 			}
220710bcbdabSSepherosa Ziehau 			bus_dma_tag_destroy(txr->tx_mbuf_tag);
220810bcbdabSSepherosa Ziehau 			txr->tx_mbuf_tag = NULL;
220910bcbdabSSepherosa Ziehau 
221010bcbdabSSepherosa Ziehau 			device_printf(txr->sc->bce_dev, "Unable to create "
221110bcbdabSSepherosa Ziehau 			    "%dth TX mbuf DMA map!\n", i);
221210bcbdabSSepherosa Ziehau 			return rc;
221310bcbdabSSepherosa Ziehau 		}
221410bcbdabSSepherosa Ziehau 	}
221510bcbdabSSepherosa Ziehau 	return 0;
221610bcbdabSSepherosa Ziehau }
221710bcbdabSSepherosa Ziehau 
221808b64767SSepherosa Ziehau static int
bce_create_rx_ring(struct bce_rx_ring * rxr)221908b64767SSepherosa Ziehau bce_create_rx_ring(struct bce_rx_ring *rxr)
222008b64767SSepherosa Ziehau {
222108b64767SSepherosa Ziehau 	int pages, rc, i;
222208b64767SSepherosa Ziehau 
222384464af5SSepherosa Ziehau 	lwkt_serialize_init(&rxr->rx_serialize);
222484464af5SSepherosa Ziehau 
222508b64767SSepherosa Ziehau 	pages = device_getenv_int(rxr->sc->bce_dev, "rx_pages", bce_rx_pages);
222608b64767SSepherosa Ziehau 	if (pages <= 0 || pages > RX_PAGES_MAX || !powerof2(pages)) {
222708b64767SSepherosa Ziehau 		device_printf(rxr->sc->bce_dev, "invalid # of RX pages\n");
222808b64767SSepherosa Ziehau 		pages = RX_PAGES_DEFAULT;
222908b64767SSepherosa Ziehau 	}
223008b64767SSepherosa Ziehau 	rxr->rx_pages = pages;
223108b64767SSepherosa Ziehau 
223208b64767SSepherosa Ziehau 	rxr->rx_bd_chain_map = kmalloc(sizeof(bus_dmamap_t) * rxr->rx_pages,
223308b64767SSepherosa Ziehau 	    M_DEVBUF, M_WAITOK | M_ZERO);
223408b64767SSepherosa Ziehau 	rxr->rx_bd_chain = kmalloc(sizeof(struct rx_bd *) * rxr->rx_pages,
223508b64767SSepherosa Ziehau 	    M_DEVBUF, M_WAITOK | M_ZERO);
223608b64767SSepherosa Ziehau 	rxr->rx_bd_chain_paddr = kmalloc(sizeof(bus_addr_t) * rxr->rx_pages,
223708b64767SSepherosa Ziehau 	    M_DEVBUF, M_WAITOK | M_ZERO);
223808b64767SSepherosa Ziehau 
223962938642SMatthew Dillon 	rxr->rx_bufs = kmalloc(sizeof(struct bce_rx_buf) * TOTAL_RX_BD(rxr),
224062938642SMatthew Dillon 			       M_DEVBUF,
224162938642SMatthew Dillon 			       M_WAITOK | M_ZERO | M_CACHEALIGN);
224208b64767SSepherosa Ziehau 
224308b64767SSepherosa Ziehau 	/*
224408b64767SSepherosa Ziehau 	 * Create a DMA tag for the RX buffer descriptor chain,
224508b64767SSepherosa Ziehau 	 * allocate and clear the  memory, and fetch the physical
224608b64767SSepherosa Ziehau 	 * address of the blocks.
224708b64767SSepherosa Ziehau 	 */
224808b64767SSepherosa Ziehau 	rc = bus_dma_tag_create(rxr->sc->parent_tag, BCM_PAGE_SIZE, 0,
2249*030b0c8cSMichael Neumann 	    BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR,
225008b64767SSepherosa Ziehau 	    BCE_RX_CHAIN_PAGE_SZ, 1, BCE_RX_CHAIN_PAGE_SZ,
225108b64767SSepherosa Ziehau 	    0, &rxr->rx_bd_chain_tag);
225208b64767SSepherosa Ziehau 	if (rc != 0) {
225308b64767SSepherosa Ziehau 		device_printf(rxr->sc->bce_dev, "Could not allocate "
225408b64767SSepherosa Ziehau 		    "RX descriptor chain DMA tag!\n");
225508b64767SSepherosa Ziehau 		return rc;
225608b64767SSepherosa Ziehau 	}
225708b64767SSepherosa Ziehau 
225808b64767SSepherosa Ziehau 	for (i = 0; i < rxr->rx_pages; i++) {
225908b64767SSepherosa Ziehau 		bus_addr_t busaddr;
226008b64767SSepherosa Ziehau 
226108b64767SSepherosa Ziehau 		rc = bus_dmamem_alloc(rxr->rx_bd_chain_tag,
226208b64767SSepherosa Ziehau 		    (void **)&rxr->rx_bd_chain[i],
226308b64767SSepherosa Ziehau 		    BUS_DMA_WAITOK | BUS_DMA_ZERO | BUS_DMA_COHERENT,
226408b64767SSepherosa Ziehau 		    &rxr->rx_bd_chain_map[i]);
226508b64767SSepherosa Ziehau 		if (rc != 0) {
226608b64767SSepherosa Ziehau 			device_printf(rxr->sc->bce_dev,
226708b64767SSepherosa Ziehau 			    "Could not allocate %dth RX descriptor "
226808b64767SSepherosa Ziehau 			    "chain DMA memory!\n", i);
226908b64767SSepherosa Ziehau 			return rc;
227008b64767SSepherosa Ziehau 		}
227108b64767SSepherosa Ziehau 
227208b64767SSepherosa Ziehau 		rc = bus_dmamap_load(rxr->rx_bd_chain_tag,
227308b64767SSepherosa Ziehau 		    rxr->rx_bd_chain_map[i],
227408b64767SSepherosa Ziehau 		    rxr->rx_bd_chain[i],
227508b64767SSepherosa Ziehau 		    BCE_RX_CHAIN_PAGE_SZ,
227608b64767SSepherosa Ziehau 		    bce_dma_map_addr, &busaddr,
227708b64767SSepherosa Ziehau 		    BUS_DMA_WAITOK);
227808b64767SSepherosa Ziehau 		if (rc != 0) {
227908b64767SSepherosa Ziehau 			if (rc == EINPROGRESS) {
228008b64767SSepherosa Ziehau 				panic("%s coherent memory loading "
228108b64767SSepherosa Ziehau 				    "is still in progress!",
228208b64767SSepherosa Ziehau 				    rxr->sc->arpcom.ac_if.if_xname);
228308b64767SSepherosa Ziehau 			}
228408b64767SSepherosa Ziehau 			device_printf(rxr->sc->bce_dev,
228508b64767SSepherosa Ziehau 			    "Could not map %dth RX descriptor "
228608b64767SSepherosa Ziehau 			    "chain DMA memory!\n", i);
228708b64767SSepherosa Ziehau 			bus_dmamem_free(rxr->rx_bd_chain_tag,
228808b64767SSepherosa Ziehau 			    rxr->rx_bd_chain[i],
228908b64767SSepherosa Ziehau 			    rxr->rx_bd_chain_map[i]);
229008b64767SSepherosa Ziehau 			rxr->rx_bd_chain[i] = NULL;
229108b64767SSepherosa Ziehau 			return rc;
229208b64767SSepherosa Ziehau 		}
229308b64767SSepherosa Ziehau 
229408b64767SSepherosa Ziehau 		rxr->rx_bd_chain_paddr[i] = busaddr;
229508b64767SSepherosa Ziehau 	}
229608b64767SSepherosa Ziehau 
229708b64767SSepherosa Ziehau 	/* Create a DMA tag for RX mbufs. */
229808b64767SSepherosa Ziehau 	rc = bus_dma_tag_create(rxr->sc->parent_tag, BCE_DMA_RX_ALIGN, 0,
2299*030b0c8cSMichael Neumann 	    BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR,
230008b64767SSepherosa Ziehau 	    MCLBYTES, 1, MCLBYTES,
230108b64767SSepherosa Ziehau 	    BUS_DMA_ALLOCNOW | BUS_DMA_ALIGNED | BUS_DMA_WAITOK,
230208b64767SSepherosa Ziehau 	    &rxr->rx_mbuf_tag);
230308b64767SSepherosa Ziehau 	if (rc != 0) {
230408b64767SSepherosa Ziehau 		device_printf(rxr->sc->bce_dev,
230508b64767SSepherosa Ziehau 		    "Could not allocate RX mbuf DMA tag!\n");
230608b64767SSepherosa Ziehau 		return rc;
230708b64767SSepherosa Ziehau 	}
230808b64767SSepherosa Ziehau 
230908b64767SSepherosa Ziehau 	/* Create tmp DMA map for RX mbuf clusters. */
231008b64767SSepherosa Ziehau 	rc = bus_dmamap_create(rxr->rx_mbuf_tag, BUS_DMA_WAITOK,
231108b64767SSepherosa Ziehau 	    &rxr->rx_mbuf_tmpmap);
231208b64767SSepherosa Ziehau 	if (rc != 0) {
231308b64767SSepherosa Ziehau 		bus_dma_tag_destroy(rxr->rx_mbuf_tag);
231408b64767SSepherosa Ziehau 		rxr->rx_mbuf_tag = NULL;
231508b64767SSepherosa Ziehau 
231608b64767SSepherosa Ziehau 		device_printf(rxr->sc->bce_dev,
231708b64767SSepherosa Ziehau 		    "Could not create RX mbuf tmp DMA map!\n");
231808b64767SSepherosa Ziehau 		return rc;
231908b64767SSepherosa Ziehau 	}
232008b64767SSepherosa Ziehau 
232108b64767SSepherosa Ziehau 	/* Create DMA maps for the RX mbuf clusters. */
232208b64767SSepherosa Ziehau 	for (i = 0; i < TOTAL_RX_BD(rxr); i++) {
232308b64767SSepherosa Ziehau 		rc = bus_dmamap_create(rxr->rx_mbuf_tag, BUS_DMA_WAITOK,
232486ae632dSSepherosa Ziehau 		    &rxr->rx_bufs[i].rx_mbuf_map);
232508b64767SSepherosa Ziehau 		if (rc != 0) {
232608b64767SSepherosa Ziehau 			int j;
232708b64767SSepherosa Ziehau 
232808b64767SSepherosa Ziehau 			for (j = 0; j < i; ++j) {
232908b64767SSepherosa Ziehau 				bus_dmamap_destroy(rxr->rx_mbuf_tag,
233086ae632dSSepherosa Ziehau 				    rxr->rx_bufs[j].rx_mbuf_map);
233108b64767SSepherosa Ziehau 			}
233208b64767SSepherosa Ziehau 			bus_dma_tag_destroy(rxr->rx_mbuf_tag);
233308b64767SSepherosa Ziehau 			rxr->rx_mbuf_tag = NULL;
233408b64767SSepherosa Ziehau 
233508b64767SSepherosa Ziehau 			device_printf(rxr->sc->bce_dev, "Unable to create "
233608b64767SSepherosa Ziehau 			    "%dth RX mbuf DMA map!\n", i);
233708b64767SSepherosa Ziehau 			return rc;
233808b64767SSepherosa Ziehau 		}
233908b64767SSepherosa Ziehau 	}
234008b64767SSepherosa Ziehau 	return 0;
234108b64767SSepherosa Ziehau }
234208b64767SSepherosa Ziehau 
234343c2aeb0SSepherosa Ziehau /****************************************************************************/
234443c2aeb0SSepherosa Ziehau /* Allocate any DMA memory needed by the driver.                            */
234543c2aeb0SSepherosa Ziehau /*                                                                          */
234643c2aeb0SSepherosa Ziehau /* Allocates DMA memory needed for the various global structures needed by  */
234743c2aeb0SSepherosa Ziehau /* hardware.                                                                */
234843c2aeb0SSepherosa Ziehau /*                                                                          */
2349cffea833SSepherosa Ziehau /* Memory alignment requirements:                                           */
2350d0092544SSepherosa Ziehau /* -----------------+----------+----------+----------+----------+           */
2351d0092544SSepherosa Ziehau /*  Data Structure  |   5706   |   5708   |   5709   |   5716   |           */
2352d0092544SSepherosa Ziehau /* -----------------+----------+----------+----------+----------+           */
2353d0092544SSepherosa Ziehau /* Status Block     | 8 bytes  | 8 bytes  | 16 bytes | 16 bytes |           */
2354d0092544SSepherosa Ziehau /* Statistics Block | 8 bytes  | 8 bytes  | 16 bytes | 16 bytes |           */
2355d0092544SSepherosa Ziehau /* RX Buffers       | 16 bytes | 16 bytes | 16 bytes | 16 bytes |           */
2356d0092544SSepherosa Ziehau /* PG Buffers       |   none   |   none   |   none   |   none   |           */
2357d0092544SSepherosa Ziehau /* TX Buffers       |   none   |   none   |   none   |   none   |           */
2358d0092544SSepherosa Ziehau /* Chain Pages(1)   |   4KiB   |   4KiB   |   4KiB   |   4KiB   |           */
2359d0092544SSepherosa Ziehau /* Context Pages(1) |   N/A    |   N/A    |   4KiB   |   4KiB   |           */
2360d0092544SSepherosa Ziehau /* -----------------+----------+----------+----------+----------+           */
2361cffea833SSepherosa Ziehau /*                                                                          */
2362cffea833SSepherosa Ziehau /* (1) Must align with CPU page size (BCM_PAGE_SZIE).                       */
2363cffea833SSepherosa Ziehau /*                                                                          */
236443c2aeb0SSepherosa Ziehau /* Returns:                                                                 */
236543c2aeb0SSepherosa Ziehau /*   0 for success, positive value for failure.                             */
236643c2aeb0SSepherosa Ziehau /****************************************************************************/
236743c2aeb0SSepherosa Ziehau static int
bce_dma_alloc(struct bce_softc * sc)236843c2aeb0SSepherosa Ziehau bce_dma_alloc(struct bce_softc *sc)
236943c2aeb0SSepherosa Ziehau {
237043c2aeb0SSepherosa Ziehau 	struct ifnet *ifp = &sc->arpcom.ac_if;
237108b64767SSepherosa Ziehau 	int i, rc = 0;
2372d0092544SSepherosa Ziehau 	bus_addr_t busaddr, max_busaddr;
2373b42386eeSSepherosa Ziehau 	bus_size_t status_align, stats_align, status_size;
2374d0092544SSepherosa Ziehau 
2375d0092544SSepherosa Ziehau 	/*
2376d0092544SSepherosa Ziehau 	 * The embedded PCIe to PCI-X bridge (EPB)
2377d0092544SSepherosa Ziehau 	 * in the 5708 cannot address memory above
2378d0092544SSepherosa Ziehau 	 * 40 bits (E7_5708CB1_23043 & E6_5708SB1_23043).
2379d0092544SSepherosa Ziehau 	 */
2380d0092544SSepherosa Ziehau 	if (BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5708)
2381d0092544SSepherosa Ziehau 		max_busaddr = BCE_BUS_SPACE_MAXADDR;
2382d0092544SSepherosa Ziehau 	else
2383d0092544SSepherosa Ziehau 		max_busaddr = BUS_SPACE_MAXADDR;
2384d0092544SSepherosa Ziehau 
2385d0092544SSepherosa Ziehau 	/*
2386d0092544SSepherosa Ziehau 	 * BCM5709 and BCM5716 uses host memory as cache for context memory.
2387d0092544SSepherosa Ziehau 	 */
2388d0092544SSepherosa Ziehau 	if (BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5709 ||
2389d0092544SSepherosa Ziehau 	    BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5716) {
2390d0092544SSepherosa Ziehau 		sc->ctx_pages = BCE_CTX_BLK_SZ / BCM_PAGE_SIZE;
2391d0092544SSepherosa Ziehau 		if (sc->ctx_pages == 0)
2392d0092544SSepherosa Ziehau 			sc->ctx_pages = 1;
2393d0092544SSepherosa Ziehau 		if (sc->ctx_pages > BCE_CTX_PAGES) {
2394d0092544SSepherosa Ziehau 			device_printf(sc->bce_dev, "excessive ctx pages %d\n",
2395d0092544SSepherosa Ziehau 			    sc->ctx_pages);
2396d0092544SSepherosa Ziehau 			return ENOMEM;
2397d0092544SSepherosa Ziehau 		}
2398d0092544SSepherosa Ziehau 		status_align = 16;
2399d0092544SSepherosa Ziehau 		stats_align = 16;
2400d0092544SSepherosa Ziehau 	} else {
2401d0092544SSepherosa Ziehau 		status_align = 8;
2402d0092544SSepherosa Ziehau 		stats_align = 8;
2403d0092544SSepherosa Ziehau 	}
240443c2aeb0SSepherosa Ziehau 
240543c2aeb0SSepherosa Ziehau 	/*
2406b42386eeSSepherosa Ziehau 	 * Each MSI-X vector needs a status block; each status block
2407b42386eeSSepherosa Ziehau 	 * consumes 128bytes and is 128bytes aligned.
2408b42386eeSSepherosa Ziehau 	 */
2409b42386eeSSepherosa Ziehau 	if (sc->rx_ring_cnt > 1) {
2410b42386eeSSepherosa Ziehau 		status_size = BCE_MSIX_MAX * BCE_STATUS_BLK_MSIX_ALIGN;
2411b42386eeSSepherosa Ziehau 		status_align = BCE_STATUS_BLK_MSIX_ALIGN;
2412b42386eeSSepherosa Ziehau 	} else {
2413b42386eeSSepherosa Ziehau 		status_size = BCE_STATUS_BLK_SZ;
2414b42386eeSSepherosa Ziehau 	}
2415b42386eeSSepherosa Ziehau 
2416b42386eeSSepherosa Ziehau 	/*
241743c2aeb0SSepherosa Ziehau 	 * Allocate the parent bus DMA tag appropriate for PCI.
241843c2aeb0SSepherosa Ziehau 	 */
241943c2aeb0SSepherosa Ziehau 	rc = bus_dma_tag_create(NULL, 1, BCE_DMA_BOUNDARY,
2420d0092544SSepherosa Ziehau 				max_busaddr, BUS_SPACE_MAXADDR,
242145010e4dSSepherosa Ziehau 				BUS_SPACE_MAXSIZE_32BIT, 0,
242243c2aeb0SSepherosa Ziehau 				BUS_SPACE_MAXSIZE_32BIT,
242343c2aeb0SSepherosa Ziehau 				0, &sc->parent_tag);
242443c2aeb0SSepherosa Ziehau 	if (rc != 0) {
242543c2aeb0SSepherosa Ziehau 		if_printf(ifp, "Could not allocate parent DMA tag!\n");
242643c2aeb0SSepherosa Ziehau 		return rc;
242743c2aeb0SSepherosa Ziehau 	}
242843c2aeb0SSepherosa Ziehau 
242943c2aeb0SSepherosa Ziehau 	/*
24304a458e9dSSepherosa Ziehau 	 * Allocate status block.
243143c2aeb0SSepherosa Ziehau 	 */
24324a458e9dSSepherosa Ziehau 	sc->status_block = bus_dmamem_coherent_any(sc->parent_tag,
2433b42386eeSSepherosa Ziehau 				status_align, status_size,
243443c2aeb0SSepherosa Ziehau 				BUS_DMA_WAITOK | BUS_DMA_ZERO,
24354a458e9dSSepherosa Ziehau 				&sc->status_tag, &sc->status_map,
24364a458e9dSSepherosa Ziehau 				&sc->status_block_paddr);
24374a458e9dSSepherosa Ziehau 	if (sc->status_block == NULL) {
24384a458e9dSSepherosa Ziehau 		if_printf(ifp, "Could not allocate status block!\n");
24394a458e9dSSepherosa Ziehau 		return ENOMEM;
244043c2aeb0SSepherosa Ziehau 	}
244143c2aeb0SSepherosa Ziehau 
244243c2aeb0SSepherosa Ziehau 	/*
24434a458e9dSSepherosa Ziehau 	 * Allocate statistics block.
244443c2aeb0SSepherosa Ziehau 	 */
24454a458e9dSSepherosa Ziehau 	sc->stats_block = bus_dmamem_coherent_any(sc->parent_tag,
2446d0092544SSepherosa Ziehau 				stats_align, BCE_STATS_BLK_SZ,
244743c2aeb0SSepherosa Ziehau 				BUS_DMA_WAITOK | BUS_DMA_ZERO,
24484a458e9dSSepherosa Ziehau 				&sc->stats_tag, &sc->stats_map,
24494a458e9dSSepherosa Ziehau 				&sc->stats_block_paddr);
24504a458e9dSSepherosa Ziehau 	if (sc->stats_block == NULL) {
24514a458e9dSSepherosa Ziehau 		if_printf(ifp, "Could not allocate statistics block!\n");
24524a458e9dSSepherosa Ziehau 		return ENOMEM;
245343c2aeb0SSepherosa Ziehau 	}
245443c2aeb0SSepherosa Ziehau 
245543c2aeb0SSepherosa Ziehau 	/*
2456d0092544SSepherosa Ziehau 	 * Allocate context block, if needed
2457d0092544SSepherosa Ziehau 	 */
2458d0092544SSepherosa Ziehau 	if (sc->ctx_pages != 0) {
2459d0092544SSepherosa Ziehau 		rc = bus_dma_tag_create(sc->parent_tag, BCM_PAGE_SIZE, 0,
2460d0092544SSepherosa Ziehau 					BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR,
2461d0092544SSepherosa Ziehau 					BCM_PAGE_SIZE, 1, BCM_PAGE_SIZE,
2462d0092544SSepherosa Ziehau 					0, &sc->ctx_tag);
2463d0092544SSepherosa Ziehau 		if (rc != 0) {
2464d0092544SSepherosa Ziehau 			if_printf(ifp, "Could not allocate "
2465d0092544SSepherosa Ziehau 				  "context block DMA tag!\n");
2466d0092544SSepherosa Ziehau 			return rc;
2467d0092544SSepherosa Ziehau 		}
2468d0092544SSepherosa Ziehau 
2469d0092544SSepherosa Ziehau 		for (i = 0; i < sc->ctx_pages; i++) {
2470d0092544SSepherosa Ziehau 			rc = bus_dmamem_alloc(sc->ctx_tag,
2471d0092544SSepherosa Ziehau 					      (void **)&sc->ctx_block[i],
2472d0092544SSepherosa Ziehau 					      BUS_DMA_WAITOK | BUS_DMA_ZERO |
2473d0092544SSepherosa Ziehau 					      BUS_DMA_COHERENT,
2474d0092544SSepherosa Ziehau 					      &sc->ctx_map[i]);
2475d0092544SSepherosa Ziehau 			if (rc != 0) {
2476d0092544SSepherosa Ziehau 				if_printf(ifp, "Could not allocate %dth context "
2477d0092544SSepherosa Ziehau 					  "DMA memory!\n", i);
2478d0092544SSepherosa Ziehau 				return rc;
2479d0092544SSepherosa Ziehau 			}
2480d0092544SSepherosa Ziehau 
2481d0092544SSepherosa Ziehau 			rc = bus_dmamap_load(sc->ctx_tag, sc->ctx_map[i],
2482d0092544SSepherosa Ziehau 					     sc->ctx_block[i], BCM_PAGE_SIZE,
2483d0092544SSepherosa Ziehau 					     bce_dma_map_addr, &busaddr,
2484d0092544SSepherosa Ziehau 					     BUS_DMA_WAITOK);
2485d0092544SSepherosa Ziehau 			if (rc != 0) {
2486d0092544SSepherosa Ziehau 				if (rc == EINPROGRESS) {
2487d0092544SSepherosa Ziehau 					panic("%s coherent memory loading "
2488d0092544SSepherosa Ziehau 					      "is still in progress!", ifp->if_xname);
2489d0092544SSepherosa Ziehau 				}
2490d0092544SSepherosa Ziehau 				if_printf(ifp, "Could not map %dth context "
2491d0092544SSepherosa Ziehau 					  "DMA memory!\n", i);
2492d0092544SSepherosa Ziehau 				bus_dmamem_free(sc->ctx_tag, sc->ctx_block[i],
2493d0092544SSepherosa Ziehau 						sc->ctx_map[i]);
2494d0092544SSepherosa Ziehau 				sc->ctx_block[i] = NULL;
2495d0092544SSepherosa Ziehau 				return rc;
2496d0092544SSepherosa Ziehau 			}
2497d0092544SSepherosa Ziehau 			sc->ctx_paddr[i] = busaddr;
2498d0092544SSepherosa Ziehau 		}
2499d0092544SSepherosa Ziehau 	}
2500d0092544SSepherosa Ziehau 
250162938642SMatthew Dillon 	sc->tx_rings = kmalloc(sizeof(struct bce_tx_ring) * sc->tx_ring_cnt,
250262938642SMatthew Dillon 			       M_DEVBUF,
250362938642SMatthew Dillon 			       M_WAITOK | M_ZERO | M_CACHEALIGN);
2504ac2202eaSSepherosa Ziehau 	for (i = 0; i < sc->tx_ring_cnt; ++i) {
250510bcbdabSSepherosa Ziehau 		sc->tx_rings[i].sc = sc;
2506b42386eeSSepherosa Ziehau 		if (i == 0) {
25075abd7f19SSepherosa Ziehau 			sc->tx_rings[i].tx_cid = TX_CID;
25085abd7f19SSepherosa Ziehau 			sc->tx_rings[i].tx_hw_cons =
25095abd7f19SSepherosa Ziehau 			    &sc->status_block->status_tx_quick_consumer_index0;
2510b42386eeSSepherosa Ziehau 		} else {
2511b42386eeSSepherosa Ziehau 			struct status_block_msix *sblk =
2512b42386eeSSepherosa Ziehau 			    (struct status_block_msix *)
2513b42386eeSSepherosa Ziehau 			    (((uint8_t *)(sc->status_block)) +
2514b42386eeSSepherosa Ziehau 			     (i * BCE_STATUS_BLK_MSIX_ALIGN));
2515b42386eeSSepherosa Ziehau 
2516b42386eeSSepherosa Ziehau 			sc->tx_rings[i].tx_cid = TX_TSS_CID + i - 1;
2517b42386eeSSepherosa Ziehau 			sc->tx_rings[i].tx_hw_cons =
2518b42386eeSSepherosa Ziehau 			    &sblk->status_tx_quick_consumer_index;
2519b42386eeSSepherosa Ziehau 		}
252010bcbdabSSepherosa Ziehau 
252110bcbdabSSepherosa Ziehau 		rc = bce_create_tx_ring(&sc->tx_rings[i]);
252243c2aeb0SSepherosa Ziehau 		if (rc != 0) {
252310bcbdabSSepherosa Ziehau 			device_printf(sc->bce_dev,
252410bcbdabSSepherosa Ziehau 			    "can't create %dth tx ring\n", i);
252543c2aeb0SSepherosa Ziehau 			return rc;
252643c2aeb0SSepherosa Ziehau 		}
252743c2aeb0SSepherosa Ziehau 	}
252843c2aeb0SSepherosa Ziehau 
252962938642SMatthew Dillon 	sc->rx_rings = kmalloc(sizeof(struct bce_rx_ring) * sc->rx_ring_cnt,
253062938642SMatthew Dillon 			       M_DEVBUF,
253162938642SMatthew Dillon 			       M_WAITOK | M_ZERO | M_CACHEALIGN);
2532ac2202eaSSepherosa Ziehau 	for (i = 0; i < sc->rx_ring_cnt; ++i) {
253308b64767SSepherosa Ziehau 		sc->rx_rings[i].sc = sc;
2534b42386eeSSepherosa Ziehau 		sc->rx_rings[i].idx = i;
2535b42386eeSSepherosa Ziehau 		if (i == 0) {
25365abd7f19SSepherosa Ziehau 			sc->rx_rings[i].rx_cid = RX_CID;
25375abd7f19SSepherosa Ziehau 			sc->rx_rings[i].rx_hw_cons =
25385abd7f19SSepherosa Ziehau 			    &sc->status_block->status_rx_quick_consumer_index0;
2539ba268ba5SSepherosa Ziehau 			sc->rx_rings[i].hw_status_idx =
2540ba268ba5SSepherosa Ziehau 			    &sc->status_block->status_idx;
2541b42386eeSSepherosa Ziehau 		} else {
2542b42386eeSSepherosa Ziehau 			struct status_block_msix *sblk =
2543b42386eeSSepherosa Ziehau 			    (struct status_block_msix *)
2544b42386eeSSepherosa Ziehau 			    (((uint8_t *)(sc->status_block)) +
2545b42386eeSSepherosa Ziehau 			     (i * BCE_STATUS_BLK_MSIX_ALIGN));
2546b42386eeSSepherosa Ziehau 
2547b42386eeSSepherosa Ziehau 			sc->rx_rings[i].rx_cid = RX_RSS_CID + i - 1;
2548b42386eeSSepherosa Ziehau 			sc->rx_rings[i].rx_hw_cons =
2549b42386eeSSepherosa Ziehau 			    &sblk->status_rx_quick_consumer_index;
2550b42386eeSSepherosa Ziehau 			sc->rx_rings[i].hw_status_idx = &sblk->status_idx;
2551b42386eeSSepherosa Ziehau 		}
255210bcbdabSSepherosa Ziehau 
255308b64767SSepherosa Ziehau 		rc = bce_create_rx_ring(&sc->rx_rings[i]);
255443c2aeb0SSepherosa Ziehau 		if (rc != 0) {
255508b64767SSepherosa Ziehau 			device_printf(sc->bce_dev,
255608b64767SSepherosa Ziehau 			    "can't create %dth rx ring\n", i);
255743c2aeb0SSepherosa Ziehau 			return rc;
255843c2aeb0SSepherosa Ziehau 		}
255943c2aeb0SSepherosa Ziehau 	}
256008b64767SSepherosa Ziehau 
256143c2aeb0SSepherosa Ziehau 	return 0;
256243c2aeb0SSepherosa Ziehau }
256343c2aeb0SSepherosa Ziehau 
256443c2aeb0SSepherosa Ziehau /****************************************************************************/
256543c2aeb0SSepherosa Ziehau /* Firmware synchronization.                                                */
256643c2aeb0SSepherosa Ziehau /*                                                                          */
256743c2aeb0SSepherosa Ziehau /* Before performing certain events such as a chip reset, synchronize with  */
256843c2aeb0SSepherosa Ziehau /* the firmware first.                                                      */
256943c2aeb0SSepherosa Ziehau /*                                                                          */
257043c2aeb0SSepherosa Ziehau /* Returns:                                                                 */
257143c2aeb0SSepherosa Ziehau /*   0 for success, positive value for failure.                             */
257243c2aeb0SSepherosa Ziehau /****************************************************************************/
257343c2aeb0SSepherosa Ziehau static int
bce_fw_sync(struct bce_softc * sc,uint32_t msg_data)257443c2aeb0SSepherosa Ziehau bce_fw_sync(struct bce_softc *sc, uint32_t msg_data)
257543c2aeb0SSepherosa Ziehau {
257643c2aeb0SSepherosa Ziehau 	int i, rc = 0;
257743c2aeb0SSepherosa Ziehau 	uint32_t val;
257843c2aeb0SSepherosa Ziehau 
257943c2aeb0SSepherosa Ziehau 	/* Don't waste any time if we've timed out before. */
258043c2aeb0SSepherosa Ziehau 	if (sc->bce_fw_timed_out)
258143c2aeb0SSepherosa Ziehau 		return EBUSY;
258243c2aeb0SSepherosa Ziehau 
258343c2aeb0SSepherosa Ziehau 	/* Increment the message sequence number. */
258443c2aeb0SSepherosa Ziehau 	sc->bce_fw_wr_seq++;
258543c2aeb0SSepherosa Ziehau 	msg_data |= sc->bce_fw_wr_seq;
258643c2aeb0SSepherosa Ziehau 
258743c2aeb0SSepherosa Ziehau 	/* Send the message to the bootcode driver mailbox. */
2588bc30d40dSSepherosa Ziehau 	bce_shmem_wr(sc, BCE_DRV_MB, msg_data);
258943c2aeb0SSepherosa Ziehau 
259043c2aeb0SSepherosa Ziehau 	/* Wait for the bootcode to acknowledge the message. */
259143c2aeb0SSepherosa Ziehau 	for (i = 0; i < FW_ACK_TIME_OUT_MS; i++) {
259243c2aeb0SSepherosa Ziehau 		/* Check for a response in the bootcode firmware mailbox. */
2593bc30d40dSSepherosa Ziehau 		val = bce_shmem_rd(sc, BCE_FW_MB);
259443c2aeb0SSepherosa Ziehau 		if ((val & BCE_FW_MSG_ACK) == (msg_data & BCE_DRV_MSG_SEQ))
259543c2aeb0SSepherosa Ziehau 			break;
259643c2aeb0SSepherosa Ziehau 		DELAY(1000);
259743c2aeb0SSepherosa Ziehau 	}
259843c2aeb0SSepherosa Ziehau 
259943c2aeb0SSepherosa Ziehau 	/* If we've timed out, tell the bootcode that we've stopped waiting. */
260043c2aeb0SSepherosa Ziehau 	if ((val & BCE_FW_MSG_ACK) != (msg_data & BCE_DRV_MSG_SEQ) &&
260143c2aeb0SSepherosa Ziehau 	    (msg_data & BCE_DRV_MSG_DATA) != BCE_DRV_MSG_DATA_WAIT0) {
260243c2aeb0SSepherosa Ziehau 		if_printf(&sc->arpcom.ac_if,
260343c2aeb0SSepherosa Ziehau 			  "Firmware synchronization timeout! "
260443c2aeb0SSepherosa Ziehau 			  "msg_data = 0x%08X\n", msg_data);
260543c2aeb0SSepherosa Ziehau 
260643c2aeb0SSepherosa Ziehau 		msg_data &= ~BCE_DRV_MSG_CODE;
260743c2aeb0SSepherosa Ziehau 		msg_data |= BCE_DRV_MSG_CODE_FW_TIMEOUT;
260843c2aeb0SSepherosa Ziehau 
2609bc30d40dSSepherosa Ziehau 		bce_shmem_wr(sc, BCE_DRV_MB, msg_data);
261043c2aeb0SSepherosa Ziehau 
261143c2aeb0SSepherosa Ziehau 		sc->bce_fw_timed_out = 1;
261243c2aeb0SSepherosa Ziehau 		rc = EBUSY;
261343c2aeb0SSepherosa Ziehau 	}
261443c2aeb0SSepherosa Ziehau 	return rc;
261543c2aeb0SSepherosa Ziehau }
261643c2aeb0SSepherosa Ziehau 
261743c2aeb0SSepherosa Ziehau /****************************************************************************/
261843c2aeb0SSepherosa Ziehau /* Load Receive Virtual 2 Physical (RV2P) processor firmware.               */
261943c2aeb0SSepherosa Ziehau /*                                                                          */
262043c2aeb0SSepherosa Ziehau /* Returns:                                                                 */
262143c2aeb0SSepherosa Ziehau /*   Nothing.                                                               */
262243c2aeb0SSepherosa Ziehau /****************************************************************************/
262343c2aeb0SSepherosa Ziehau static void
bce_load_rv2p_fw(struct bce_softc * sc,uint32_t * rv2p_code,uint32_t rv2p_code_len,uint32_t rv2p_proc)262443c2aeb0SSepherosa Ziehau bce_load_rv2p_fw(struct bce_softc *sc, uint32_t *rv2p_code,
262543c2aeb0SSepherosa Ziehau 		 uint32_t rv2p_code_len, uint32_t rv2p_proc)
262643c2aeb0SSepherosa Ziehau {
262743c2aeb0SSepherosa Ziehau 	int i;
262843c2aeb0SSepherosa Ziehau 	uint32_t val;
262943c2aeb0SSepherosa Ziehau 
263043c2aeb0SSepherosa Ziehau 	for (i = 0; i < rv2p_code_len; i += 8) {
263143c2aeb0SSepherosa Ziehau 		REG_WR(sc, BCE_RV2P_INSTR_HIGH, *rv2p_code);
263243c2aeb0SSepherosa Ziehau 		rv2p_code++;
263343c2aeb0SSepherosa Ziehau 		REG_WR(sc, BCE_RV2P_INSTR_LOW, *rv2p_code);
263443c2aeb0SSepherosa Ziehau 		rv2p_code++;
263543c2aeb0SSepherosa Ziehau 
263643c2aeb0SSepherosa Ziehau 		if (rv2p_proc == RV2P_PROC1) {
263743c2aeb0SSepherosa Ziehau 			val = (i / 8) | BCE_RV2P_PROC1_ADDR_CMD_RDWR;
263843c2aeb0SSepherosa Ziehau 			REG_WR(sc, BCE_RV2P_PROC1_ADDR_CMD, val);
263943c2aeb0SSepherosa Ziehau 		} else {
264043c2aeb0SSepherosa Ziehau 			val = (i / 8) | BCE_RV2P_PROC2_ADDR_CMD_RDWR;
264143c2aeb0SSepherosa Ziehau 			REG_WR(sc, BCE_RV2P_PROC2_ADDR_CMD, val);
264243c2aeb0SSepherosa Ziehau 		}
264343c2aeb0SSepherosa Ziehau 	}
264443c2aeb0SSepherosa Ziehau 
264543c2aeb0SSepherosa Ziehau 	/* Reset the processor, un-stall is done later. */
264643c2aeb0SSepherosa Ziehau 	if (rv2p_proc == RV2P_PROC1)
264743c2aeb0SSepherosa Ziehau 		REG_WR(sc, BCE_RV2P_COMMAND, BCE_RV2P_COMMAND_PROC1_RESET);
264843c2aeb0SSepherosa Ziehau 	else
264943c2aeb0SSepherosa Ziehau 		REG_WR(sc, BCE_RV2P_COMMAND, BCE_RV2P_COMMAND_PROC2_RESET);
265043c2aeb0SSepherosa Ziehau }
265143c2aeb0SSepherosa Ziehau 
265243c2aeb0SSepherosa Ziehau /****************************************************************************/
265343c2aeb0SSepherosa Ziehau /* Load RISC processor firmware.                                            */
265443c2aeb0SSepherosa Ziehau /*                                                                          */
265543c2aeb0SSepherosa Ziehau /* Loads firmware from the file if_bcefw.h into the scratchpad memory       */
265643c2aeb0SSepherosa Ziehau /* associated with a particular processor.                                  */
265743c2aeb0SSepherosa Ziehau /*                                                                          */
265843c2aeb0SSepherosa Ziehau /* Returns:                                                                 */
265943c2aeb0SSepherosa Ziehau /*   Nothing.                                                               */
266043c2aeb0SSepherosa Ziehau /****************************************************************************/
266143c2aeb0SSepherosa Ziehau static void
bce_load_cpu_fw(struct bce_softc * sc,struct cpu_reg * cpu_reg,struct fw_info * fw)266243c2aeb0SSepherosa Ziehau bce_load_cpu_fw(struct bce_softc *sc, struct cpu_reg *cpu_reg,
266343c2aeb0SSepherosa Ziehau 		struct fw_info *fw)
266443c2aeb0SSepherosa Ziehau {
26655d05a208SSepherosa Ziehau 	uint32_t offset;
266643c2aeb0SSepherosa Ziehau 	int j;
266743c2aeb0SSepherosa Ziehau 
26685d05a208SSepherosa Ziehau 	bce_halt_cpu(sc, cpu_reg);
266943c2aeb0SSepherosa Ziehau 
267043c2aeb0SSepherosa Ziehau 	/* Load the Text area. */
267143c2aeb0SSepherosa Ziehau 	offset = cpu_reg->spad_base + (fw->text_addr - cpu_reg->mips_view_base);
267243c2aeb0SSepherosa Ziehau 	if (fw->text) {
267343c2aeb0SSepherosa Ziehau 		for (j = 0; j < (fw->text_len / 4); j++, offset += 4)
267443c2aeb0SSepherosa Ziehau 			REG_WR_IND(sc, offset, fw->text[j]);
267543c2aeb0SSepherosa Ziehau 	}
267643c2aeb0SSepherosa Ziehau 
267743c2aeb0SSepherosa Ziehau 	/* Load the Data area. */
267843c2aeb0SSepherosa Ziehau 	offset = cpu_reg->spad_base + (fw->data_addr - cpu_reg->mips_view_base);
267943c2aeb0SSepherosa Ziehau 	if (fw->data) {
268043c2aeb0SSepherosa Ziehau 		for (j = 0; j < (fw->data_len / 4); j++, offset += 4)
268143c2aeb0SSepherosa Ziehau 			REG_WR_IND(sc, offset, fw->data[j]);
268243c2aeb0SSepherosa Ziehau 	}
268343c2aeb0SSepherosa Ziehau 
268443c2aeb0SSepherosa Ziehau 	/* Load the SBSS area. */
268543c2aeb0SSepherosa Ziehau 	offset = cpu_reg->spad_base + (fw->sbss_addr - cpu_reg->mips_view_base);
268643c2aeb0SSepherosa Ziehau 	if (fw->sbss) {
268743c2aeb0SSepherosa Ziehau 		for (j = 0; j < (fw->sbss_len / 4); j++, offset += 4)
268843c2aeb0SSepherosa Ziehau 			REG_WR_IND(sc, offset, fw->sbss[j]);
268943c2aeb0SSepherosa Ziehau 	}
269043c2aeb0SSepherosa Ziehau 
269143c2aeb0SSepherosa Ziehau 	/* Load the BSS area. */
269243c2aeb0SSepherosa Ziehau 	offset = cpu_reg->spad_base + (fw->bss_addr - cpu_reg->mips_view_base);
269343c2aeb0SSepherosa Ziehau 	if (fw->bss) {
269443c2aeb0SSepherosa Ziehau 		for (j = 0; j < (fw->bss_len/4); j++, offset += 4)
269543c2aeb0SSepherosa Ziehau 			REG_WR_IND(sc, offset, fw->bss[j]);
269643c2aeb0SSepherosa Ziehau 	}
269743c2aeb0SSepherosa Ziehau 
269843c2aeb0SSepherosa Ziehau 	/* Load the Read-Only area. */
269943c2aeb0SSepherosa Ziehau 	offset = cpu_reg->spad_base +
270043c2aeb0SSepherosa Ziehau 		(fw->rodata_addr - cpu_reg->mips_view_base);
270143c2aeb0SSepherosa Ziehau 	if (fw->rodata) {
270243c2aeb0SSepherosa Ziehau 		for (j = 0; j < (fw->rodata_len / 4); j++, offset += 4)
270343c2aeb0SSepherosa Ziehau 			REG_WR_IND(sc, offset, fw->rodata[j]);
270443c2aeb0SSepherosa Ziehau 	}
270543c2aeb0SSepherosa Ziehau 
27065d05a208SSepherosa Ziehau 	/* Clear the pre-fetch instruction and set the FW start address. */
270743c2aeb0SSepherosa Ziehau 	REG_WR_IND(sc, cpu_reg->inst, 0);
270843c2aeb0SSepherosa Ziehau 	REG_WR_IND(sc, cpu_reg->pc, fw->start_addr);
27095d05a208SSepherosa Ziehau }
27105d05a208SSepherosa Ziehau 
27115d05a208SSepherosa Ziehau /****************************************************************************/
27125d05a208SSepherosa Ziehau /* Starts the RISC processor.                                               */
27135d05a208SSepherosa Ziehau /*                                                                          */
27145d05a208SSepherosa Ziehau /* Assumes the CPU starting address has already been set.                   */
27155d05a208SSepherosa Ziehau /*                                                                          */
27165d05a208SSepherosa Ziehau /* Returns:                                                                 */
27175d05a208SSepherosa Ziehau /*   Nothing.                                                               */
27185d05a208SSepherosa Ziehau /****************************************************************************/
27195d05a208SSepherosa Ziehau static void
bce_start_cpu(struct bce_softc * sc,struct cpu_reg * cpu_reg)27205d05a208SSepherosa Ziehau bce_start_cpu(struct bce_softc *sc, struct cpu_reg *cpu_reg)
27215d05a208SSepherosa Ziehau {
27225d05a208SSepherosa Ziehau 	uint32_t val;
272343c2aeb0SSepherosa Ziehau 
272443c2aeb0SSepherosa Ziehau 	/* Start the CPU. */
272543c2aeb0SSepherosa Ziehau 	val = REG_RD_IND(sc, cpu_reg->mode);
272643c2aeb0SSepherosa Ziehau 	val &= ~cpu_reg->mode_value_halt;
272743c2aeb0SSepherosa Ziehau 	REG_WR_IND(sc, cpu_reg->state, cpu_reg->state_value_clear);
272843c2aeb0SSepherosa Ziehau 	REG_WR_IND(sc, cpu_reg->mode, val);
272943c2aeb0SSepherosa Ziehau }
273043c2aeb0SSepherosa Ziehau 
273143c2aeb0SSepherosa Ziehau /****************************************************************************/
27325d05a208SSepherosa Ziehau /* Halts the RISC processor.                                                */
27335d05a208SSepherosa Ziehau /*                                                                          */
27345d05a208SSepherosa Ziehau /* Returns:                                                                 */
27355d05a208SSepherosa Ziehau /*   Nothing.                                                               */
27365d05a208SSepherosa Ziehau /****************************************************************************/
27375d05a208SSepherosa Ziehau static void
bce_halt_cpu(struct bce_softc * sc,struct cpu_reg * cpu_reg)27385d05a208SSepherosa Ziehau bce_halt_cpu(struct bce_softc *sc, struct cpu_reg *cpu_reg)
27395d05a208SSepherosa Ziehau {
27405d05a208SSepherosa Ziehau 	uint32_t val;
27415d05a208SSepherosa Ziehau 
27425d05a208SSepherosa Ziehau 	/* Halt the CPU. */
27435d05a208SSepherosa Ziehau 	val = REG_RD_IND(sc, cpu_reg->mode);
27445d05a208SSepherosa Ziehau 	val |= cpu_reg->mode_value_halt;
27455d05a208SSepherosa Ziehau 	REG_WR_IND(sc, cpu_reg->mode, val);
27465d05a208SSepherosa Ziehau 	REG_WR_IND(sc, cpu_reg->state, cpu_reg->state_value_clear);
27475d05a208SSepherosa Ziehau }
27485d05a208SSepherosa Ziehau 
27495d05a208SSepherosa Ziehau /****************************************************************************/
27505d05a208SSepherosa Ziehau /* Start the RX CPU.                                                        */
27515d05a208SSepherosa Ziehau /*                                                                          */
27525d05a208SSepherosa Ziehau /* Returns:                                                                 */
27535d05a208SSepherosa Ziehau /*   Nothing.                                                               */
27545d05a208SSepherosa Ziehau /****************************************************************************/
27555d05a208SSepherosa Ziehau static void
bce_start_rxp_cpu(struct bce_softc * sc)27565d05a208SSepherosa Ziehau bce_start_rxp_cpu(struct bce_softc *sc)
27575d05a208SSepherosa Ziehau {
27585d05a208SSepherosa Ziehau 	struct cpu_reg cpu_reg;
27595d05a208SSepherosa Ziehau 
27605d05a208SSepherosa Ziehau 	cpu_reg.mode = BCE_RXP_CPU_MODE;
27615d05a208SSepherosa Ziehau 	cpu_reg.mode_value_halt = BCE_RXP_CPU_MODE_SOFT_HALT;
27625d05a208SSepherosa Ziehau 	cpu_reg.mode_value_sstep = BCE_RXP_CPU_MODE_STEP_ENA;
27635d05a208SSepherosa Ziehau 	cpu_reg.state = BCE_RXP_CPU_STATE;
27645d05a208SSepherosa Ziehau 	cpu_reg.state_value_clear = 0xffffff;
27655d05a208SSepherosa Ziehau 	cpu_reg.gpr0 = BCE_RXP_CPU_REG_FILE;
27665d05a208SSepherosa Ziehau 	cpu_reg.evmask = BCE_RXP_CPU_EVENT_MASK;
27675d05a208SSepherosa Ziehau 	cpu_reg.pc = BCE_RXP_CPU_PROGRAM_COUNTER;
27685d05a208SSepherosa Ziehau 	cpu_reg.inst = BCE_RXP_CPU_INSTRUCTION;
27695d05a208SSepherosa Ziehau 	cpu_reg.bp = BCE_RXP_CPU_HW_BREAKPOINT;
27705d05a208SSepherosa Ziehau 	cpu_reg.spad_base = BCE_RXP_SCRATCH;
27715d05a208SSepherosa Ziehau 	cpu_reg.mips_view_base = 0x8000000;
27725d05a208SSepherosa Ziehau 
27735d05a208SSepherosa Ziehau 	bce_start_cpu(sc, &cpu_reg);
27745d05a208SSepherosa Ziehau }
27755d05a208SSepherosa Ziehau 
27765d05a208SSepherosa Ziehau /****************************************************************************/
2777d0092544SSepherosa Ziehau /* Initialize the RX CPU.                                                   */
277843c2aeb0SSepherosa Ziehau /*                                                                          */
277943c2aeb0SSepherosa Ziehau /* Returns:                                                                 */
278043c2aeb0SSepherosa Ziehau /*   Nothing.                                                               */
278143c2aeb0SSepherosa Ziehau /****************************************************************************/
278243c2aeb0SSepherosa Ziehau static void
bce_init_rxp_cpu(struct bce_softc * sc)2783d0092544SSepherosa Ziehau bce_init_rxp_cpu(struct bce_softc *sc)
278443c2aeb0SSepherosa Ziehau {
278543c2aeb0SSepherosa Ziehau 	struct cpu_reg cpu_reg;
278643c2aeb0SSepherosa Ziehau 	struct fw_info fw;
278743c2aeb0SSepherosa Ziehau 
278843c2aeb0SSepherosa Ziehau 	cpu_reg.mode = BCE_RXP_CPU_MODE;
278943c2aeb0SSepherosa Ziehau 	cpu_reg.mode_value_halt = BCE_RXP_CPU_MODE_SOFT_HALT;
279043c2aeb0SSepherosa Ziehau 	cpu_reg.mode_value_sstep = BCE_RXP_CPU_MODE_STEP_ENA;
279143c2aeb0SSepherosa Ziehau 	cpu_reg.state = BCE_RXP_CPU_STATE;
279243c2aeb0SSepherosa Ziehau 	cpu_reg.state_value_clear = 0xffffff;
279343c2aeb0SSepherosa Ziehau 	cpu_reg.gpr0 = BCE_RXP_CPU_REG_FILE;
279443c2aeb0SSepherosa Ziehau 	cpu_reg.evmask = BCE_RXP_CPU_EVENT_MASK;
279543c2aeb0SSepherosa Ziehau 	cpu_reg.pc = BCE_RXP_CPU_PROGRAM_COUNTER;
279643c2aeb0SSepherosa Ziehau 	cpu_reg.inst = BCE_RXP_CPU_INSTRUCTION;
279743c2aeb0SSepherosa Ziehau 	cpu_reg.bp = BCE_RXP_CPU_HW_BREAKPOINT;
279843c2aeb0SSepherosa Ziehau 	cpu_reg.spad_base = BCE_RXP_SCRATCH;
279943c2aeb0SSepherosa Ziehau 	cpu_reg.mips_view_base = 0x8000000;
280043c2aeb0SSepherosa Ziehau 
2801d0092544SSepherosa Ziehau 	if (BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5709 ||
2802d0092544SSepherosa Ziehau 	    BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5716) {
2803d0092544SSepherosa Ziehau  		fw.ver_major = bce_RXP_b09FwReleaseMajor;
2804d0092544SSepherosa Ziehau 		fw.ver_minor = bce_RXP_b09FwReleaseMinor;
2805d0092544SSepherosa Ziehau 		fw.ver_fix = bce_RXP_b09FwReleaseFix;
2806d0092544SSepherosa Ziehau 		fw.start_addr = bce_RXP_b09FwStartAddr;
2807d0092544SSepherosa Ziehau 
2808d0092544SSepherosa Ziehau 		fw.text_addr = bce_RXP_b09FwTextAddr;
2809d0092544SSepherosa Ziehau 		fw.text_len = bce_RXP_b09FwTextLen;
2810d0092544SSepherosa Ziehau 		fw.text_index = 0;
2811d0092544SSepherosa Ziehau 		fw.text = bce_RXP_b09FwText;
2812d0092544SSepherosa Ziehau 
2813d0092544SSepherosa Ziehau 		fw.data_addr = bce_RXP_b09FwDataAddr;
2814d0092544SSepherosa Ziehau 		fw.data_len = bce_RXP_b09FwDataLen;
2815d0092544SSepherosa Ziehau 		fw.data_index = 0;
2816d0092544SSepherosa Ziehau 		fw.data = bce_RXP_b09FwData;
2817d0092544SSepherosa Ziehau 
2818d0092544SSepherosa Ziehau 		fw.sbss_addr = bce_RXP_b09FwSbssAddr;
2819d0092544SSepherosa Ziehau 		fw.sbss_len = bce_RXP_b09FwSbssLen;
2820d0092544SSepherosa Ziehau 		fw.sbss_index = 0;
2821d0092544SSepherosa Ziehau 		fw.sbss = bce_RXP_b09FwSbss;
2822d0092544SSepherosa Ziehau 
2823d0092544SSepherosa Ziehau 		fw.bss_addr = bce_RXP_b09FwBssAddr;
2824d0092544SSepherosa Ziehau 		fw.bss_len = bce_RXP_b09FwBssLen;
2825d0092544SSepherosa Ziehau 		fw.bss_index = 0;
2826d0092544SSepherosa Ziehau 		fw.bss = bce_RXP_b09FwBss;
2827d0092544SSepherosa Ziehau 
2828d0092544SSepherosa Ziehau 		fw.rodata_addr = bce_RXP_b09FwRodataAddr;
2829d0092544SSepherosa Ziehau 		fw.rodata_len = bce_RXP_b09FwRodataLen;
2830d0092544SSepherosa Ziehau 		fw.rodata_index = 0;
2831d0092544SSepherosa Ziehau 		fw.rodata = bce_RXP_b09FwRodata;
2832d0092544SSepherosa Ziehau 	} else {
283343c2aeb0SSepherosa Ziehau 		fw.ver_major = bce_RXP_b06FwReleaseMajor;
283443c2aeb0SSepherosa Ziehau 		fw.ver_minor = bce_RXP_b06FwReleaseMinor;
283543c2aeb0SSepherosa Ziehau 		fw.ver_fix = bce_RXP_b06FwReleaseFix;
283643c2aeb0SSepherosa Ziehau 		fw.start_addr = bce_RXP_b06FwStartAddr;
283743c2aeb0SSepherosa Ziehau 
283843c2aeb0SSepherosa Ziehau 		fw.text_addr = bce_RXP_b06FwTextAddr;
283943c2aeb0SSepherosa Ziehau 		fw.text_len = bce_RXP_b06FwTextLen;
284043c2aeb0SSepherosa Ziehau 		fw.text_index = 0;
284143c2aeb0SSepherosa Ziehau 		fw.text = bce_RXP_b06FwText;
284243c2aeb0SSepherosa Ziehau 
284343c2aeb0SSepherosa Ziehau 		fw.data_addr = bce_RXP_b06FwDataAddr;
284443c2aeb0SSepherosa Ziehau 		fw.data_len = bce_RXP_b06FwDataLen;
284543c2aeb0SSepherosa Ziehau 		fw.data_index = 0;
284643c2aeb0SSepherosa Ziehau 		fw.data = bce_RXP_b06FwData;
284743c2aeb0SSepherosa Ziehau 
284843c2aeb0SSepherosa Ziehau 		fw.sbss_addr = bce_RXP_b06FwSbssAddr;
284943c2aeb0SSepherosa Ziehau 		fw.sbss_len = bce_RXP_b06FwSbssLen;
285043c2aeb0SSepherosa Ziehau 		fw.sbss_index = 0;
285143c2aeb0SSepherosa Ziehau 		fw.sbss = bce_RXP_b06FwSbss;
285243c2aeb0SSepherosa Ziehau 
285343c2aeb0SSepherosa Ziehau 		fw.bss_addr = bce_RXP_b06FwBssAddr;
285443c2aeb0SSepherosa Ziehau 		fw.bss_len = bce_RXP_b06FwBssLen;
285543c2aeb0SSepherosa Ziehau 		fw.bss_index = 0;
285643c2aeb0SSepherosa Ziehau 		fw.bss = bce_RXP_b06FwBss;
285743c2aeb0SSepherosa Ziehau 
285843c2aeb0SSepherosa Ziehau 		fw.rodata_addr = bce_RXP_b06FwRodataAddr;
285943c2aeb0SSepherosa Ziehau 		fw.rodata_len = bce_RXP_b06FwRodataLen;
286043c2aeb0SSepherosa Ziehau 		fw.rodata_index = 0;
286143c2aeb0SSepherosa Ziehau 		fw.rodata = bce_RXP_b06FwRodata;
2862d0092544SSepherosa Ziehau 	}
286343c2aeb0SSepherosa Ziehau 
286443c2aeb0SSepherosa Ziehau 	bce_load_cpu_fw(sc, &cpu_reg, &fw);
28655d05a208SSepherosa Ziehau 	/* Delay RXP start until initialization is complete. */
2866d0092544SSepherosa Ziehau }
286743c2aeb0SSepherosa Ziehau 
2868d0092544SSepherosa Ziehau /****************************************************************************/
2869d0092544SSepherosa Ziehau /* Initialize the TX CPU.                                                   */
2870d0092544SSepherosa Ziehau /*                                                                          */
2871d0092544SSepherosa Ziehau /* Returns:                                                                 */
2872d0092544SSepherosa Ziehau /*   Nothing.                                                               */
2873d0092544SSepherosa Ziehau /****************************************************************************/
2874d0092544SSepherosa Ziehau static void
bce_init_txp_cpu(struct bce_softc * sc)2875d0092544SSepherosa Ziehau bce_init_txp_cpu(struct bce_softc *sc)
2876d0092544SSepherosa Ziehau {
2877d0092544SSepherosa Ziehau 	struct cpu_reg cpu_reg;
2878d0092544SSepherosa Ziehau 	struct fw_info fw;
2879d0092544SSepherosa Ziehau 
288043c2aeb0SSepherosa Ziehau 	cpu_reg.mode = BCE_TXP_CPU_MODE;
288143c2aeb0SSepherosa Ziehau 	cpu_reg.mode_value_halt = BCE_TXP_CPU_MODE_SOFT_HALT;
288243c2aeb0SSepherosa Ziehau 	cpu_reg.mode_value_sstep = BCE_TXP_CPU_MODE_STEP_ENA;
288343c2aeb0SSepherosa Ziehau 	cpu_reg.state = BCE_TXP_CPU_STATE;
288443c2aeb0SSepherosa Ziehau 	cpu_reg.state_value_clear = 0xffffff;
288543c2aeb0SSepherosa Ziehau 	cpu_reg.gpr0 = BCE_TXP_CPU_REG_FILE;
288643c2aeb0SSepherosa Ziehau 	cpu_reg.evmask = BCE_TXP_CPU_EVENT_MASK;
288743c2aeb0SSepherosa Ziehau 	cpu_reg.pc = BCE_TXP_CPU_PROGRAM_COUNTER;
288843c2aeb0SSepherosa Ziehau 	cpu_reg.inst = BCE_TXP_CPU_INSTRUCTION;
288943c2aeb0SSepherosa Ziehau 	cpu_reg.bp = BCE_TXP_CPU_HW_BREAKPOINT;
289043c2aeb0SSepherosa Ziehau 	cpu_reg.spad_base = BCE_TXP_SCRATCH;
289143c2aeb0SSepherosa Ziehau 	cpu_reg.mips_view_base = 0x8000000;
289243c2aeb0SSepherosa Ziehau 
2893d0092544SSepherosa Ziehau 	if (BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5709 ||
2894d0092544SSepherosa Ziehau 	    BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5716) {
2895d0092544SSepherosa Ziehau 		fw.ver_major = bce_TXP_b09FwReleaseMajor;
2896d0092544SSepherosa Ziehau 		fw.ver_minor = bce_TXP_b09FwReleaseMinor;
2897d0092544SSepherosa Ziehau 		fw.ver_fix = bce_TXP_b09FwReleaseFix;
2898d0092544SSepherosa Ziehau 		fw.start_addr = bce_TXP_b09FwStartAddr;
2899d0092544SSepherosa Ziehau 
2900d0092544SSepherosa Ziehau 		fw.text_addr = bce_TXP_b09FwTextAddr;
2901d0092544SSepherosa Ziehau 		fw.text_len = bce_TXP_b09FwTextLen;
2902d0092544SSepherosa Ziehau 		fw.text_index = 0;
2903d0092544SSepherosa Ziehau 		fw.text = bce_TXP_b09FwText;
2904d0092544SSepherosa Ziehau 
2905d0092544SSepherosa Ziehau 		fw.data_addr = bce_TXP_b09FwDataAddr;
2906d0092544SSepherosa Ziehau 		fw.data_len = bce_TXP_b09FwDataLen;
2907d0092544SSepherosa Ziehau 		fw.data_index = 0;
2908d0092544SSepherosa Ziehau 		fw.data = bce_TXP_b09FwData;
2909d0092544SSepherosa Ziehau 
2910d0092544SSepherosa Ziehau 		fw.sbss_addr = bce_TXP_b09FwSbssAddr;
2911d0092544SSepherosa Ziehau 		fw.sbss_len = bce_TXP_b09FwSbssLen;
2912d0092544SSepherosa Ziehau 		fw.sbss_index = 0;
2913d0092544SSepherosa Ziehau 		fw.sbss = bce_TXP_b09FwSbss;
2914d0092544SSepherosa Ziehau 
2915d0092544SSepherosa Ziehau 		fw.bss_addr = bce_TXP_b09FwBssAddr;
2916d0092544SSepherosa Ziehau 		fw.bss_len = bce_TXP_b09FwBssLen;
2917d0092544SSepherosa Ziehau 		fw.bss_index = 0;
2918d0092544SSepherosa Ziehau 		fw.bss = bce_TXP_b09FwBss;
2919d0092544SSepherosa Ziehau 
2920d0092544SSepherosa Ziehau 		fw.rodata_addr = bce_TXP_b09FwRodataAddr;
2921d0092544SSepherosa Ziehau 		fw.rodata_len = bce_TXP_b09FwRodataLen;
2922d0092544SSepherosa Ziehau 		fw.rodata_index = 0;
2923d0092544SSepherosa Ziehau 		fw.rodata = bce_TXP_b09FwRodata;
2924d0092544SSepherosa Ziehau 	} else {
292543c2aeb0SSepherosa Ziehau 		fw.ver_major = bce_TXP_b06FwReleaseMajor;
292643c2aeb0SSepherosa Ziehau 		fw.ver_minor = bce_TXP_b06FwReleaseMinor;
292743c2aeb0SSepherosa Ziehau 		fw.ver_fix = bce_TXP_b06FwReleaseFix;
292843c2aeb0SSepherosa Ziehau 		fw.start_addr = bce_TXP_b06FwStartAddr;
292943c2aeb0SSepherosa Ziehau 
293043c2aeb0SSepherosa Ziehau 		fw.text_addr = bce_TXP_b06FwTextAddr;
293143c2aeb0SSepherosa Ziehau 		fw.text_len = bce_TXP_b06FwTextLen;
293243c2aeb0SSepherosa Ziehau 		fw.text_index = 0;
293343c2aeb0SSepherosa Ziehau 		fw.text = bce_TXP_b06FwText;
293443c2aeb0SSepherosa Ziehau 
293543c2aeb0SSepherosa Ziehau 		fw.data_addr = bce_TXP_b06FwDataAddr;
293643c2aeb0SSepherosa Ziehau 		fw.data_len = bce_TXP_b06FwDataLen;
293743c2aeb0SSepherosa Ziehau 		fw.data_index = 0;
293843c2aeb0SSepherosa Ziehau 		fw.data = bce_TXP_b06FwData;
293943c2aeb0SSepherosa Ziehau 
294043c2aeb0SSepherosa Ziehau 		fw.sbss_addr = bce_TXP_b06FwSbssAddr;
294143c2aeb0SSepherosa Ziehau 		fw.sbss_len = bce_TXP_b06FwSbssLen;
294243c2aeb0SSepherosa Ziehau 		fw.sbss_index = 0;
294343c2aeb0SSepherosa Ziehau 		fw.sbss = bce_TXP_b06FwSbss;
294443c2aeb0SSepherosa Ziehau 
294543c2aeb0SSepherosa Ziehau 		fw.bss_addr = bce_TXP_b06FwBssAddr;
294643c2aeb0SSepherosa Ziehau 		fw.bss_len = bce_TXP_b06FwBssLen;
294743c2aeb0SSepherosa Ziehau 		fw.bss_index = 0;
294843c2aeb0SSepherosa Ziehau 		fw.bss = bce_TXP_b06FwBss;
294943c2aeb0SSepherosa Ziehau 
295043c2aeb0SSepherosa Ziehau 		fw.rodata_addr = bce_TXP_b06FwRodataAddr;
295143c2aeb0SSepherosa Ziehau 		fw.rodata_len = bce_TXP_b06FwRodataLen;
295243c2aeb0SSepherosa Ziehau 		fw.rodata_index = 0;
295343c2aeb0SSepherosa Ziehau 		fw.rodata = bce_TXP_b06FwRodata;
2954d0092544SSepherosa Ziehau 	}
295543c2aeb0SSepherosa Ziehau 
295643c2aeb0SSepherosa Ziehau 	bce_load_cpu_fw(sc, &cpu_reg, &fw);
29575d05a208SSepherosa Ziehau 	bce_start_cpu(sc, &cpu_reg);
2958d0092544SSepherosa Ziehau }
295943c2aeb0SSepherosa Ziehau 
2960d0092544SSepherosa Ziehau /****************************************************************************/
2961d0092544SSepherosa Ziehau /* Initialize the TPAT CPU.                                                 */
2962d0092544SSepherosa Ziehau /*                                                                          */
2963d0092544SSepherosa Ziehau /* Returns:                                                                 */
2964d0092544SSepherosa Ziehau /*   Nothing.                                                               */
2965d0092544SSepherosa Ziehau /****************************************************************************/
2966d0092544SSepherosa Ziehau static void
bce_init_tpat_cpu(struct bce_softc * sc)2967d0092544SSepherosa Ziehau bce_init_tpat_cpu(struct bce_softc *sc)
2968d0092544SSepherosa Ziehau {
2969d0092544SSepherosa Ziehau 	struct cpu_reg cpu_reg;
2970d0092544SSepherosa Ziehau 	struct fw_info fw;
2971d0092544SSepherosa Ziehau 
297243c2aeb0SSepherosa Ziehau 	cpu_reg.mode = BCE_TPAT_CPU_MODE;
297343c2aeb0SSepherosa Ziehau 	cpu_reg.mode_value_halt = BCE_TPAT_CPU_MODE_SOFT_HALT;
297443c2aeb0SSepherosa Ziehau 	cpu_reg.mode_value_sstep = BCE_TPAT_CPU_MODE_STEP_ENA;
297543c2aeb0SSepherosa Ziehau 	cpu_reg.state = BCE_TPAT_CPU_STATE;
297643c2aeb0SSepherosa Ziehau 	cpu_reg.state_value_clear = 0xffffff;
297743c2aeb0SSepherosa Ziehau 	cpu_reg.gpr0 = BCE_TPAT_CPU_REG_FILE;
297843c2aeb0SSepherosa Ziehau 	cpu_reg.evmask = BCE_TPAT_CPU_EVENT_MASK;
297943c2aeb0SSepherosa Ziehau 	cpu_reg.pc = BCE_TPAT_CPU_PROGRAM_COUNTER;
298043c2aeb0SSepherosa Ziehau 	cpu_reg.inst = BCE_TPAT_CPU_INSTRUCTION;
298143c2aeb0SSepherosa Ziehau 	cpu_reg.bp = BCE_TPAT_CPU_HW_BREAKPOINT;
298243c2aeb0SSepherosa Ziehau 	cpu_reg.spad_base = BCE_TPAT_SCRATCH;
298343c2aeb0SSepherosa Ziehau 	cpu_reg.mips_view_base = 0x8000000;
298443c2aeb0SSepherosa Ziehau 
2985d0092544SSepherosa Ziehau 	if (BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5709 ||
2986d0092544SSepherosa Ziehau 	    BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5716) {
2987d0092544SSepherosa Ziehau 		fw.ver_major = bce_TPAT_b09FwReleaseMajor;
2988d0092544SSepherosa Ziehau 		fw.ver_minor = bce_TPAT_b09FwReleaseMinor;
2989d0092544SSepherosa Ziehau 		fw.ver_fix = bce_TPAT_b09FwReleaseFix;
2990d0092544SSepherosa Ziehau 		fw.start_addr = bce_TPAT_b09FwStartAddr;
2991d0092544SSepherosa Ziehau 
2992d0092544SSepherosa Ziehau 		fw.text_addr = bce_TPAT_b09FwTextAddr;
2993d0092544SSepherosa Ziehau 		fw.text_len = bce_TPAT_b09FwTextLen;
2994d0092544SSepherosa Ziehau 		fw.text_index = 0;
2995d0092544SSepherosa Ziehau 		fw.text = bce_TPAT_b09FwText;
2996d0092544SSepherosa Ziehau 
2997d0092544SSepherosa Ziehau 		fw.data_addr = bce_TPAT_b09FwDataAddr;
2998d0092544SSepherosa Ziehau 		fw.data_len = bce_TPAT_b09FwDataLen;
2999d0092544SSepherosa Ziehau 		fw.data_index = 0;
3000d0092544SSepherosa Ziehau 		fw.data = bce_TPAT_b09FwData;
3001d0092544SSepherosa Ziehau 
3002d0092544SSepherosa Ziehau 		fw.sbss_addr = bce_TPAT_b09FwSbssAddr;
3003d0092544SSepherosa Ziehau 		fw.sbss_len = bce_TPAT_b09FwSbssLen;
3004d0092544SSepherosa Ziehau 		fw.sbss_index = 0;
3005d0092544SSepherosa Ziehau 		fw.sbss = bce_TPAT_b09FwSbss;
3006d0092544SSepherosa Ziehau 
3007d0092544SSepherosa Ziehau 		fw.bss_addr = bce_TPAT_b09FwBssAddr;
3008d0092544SSepherosa Ziehau 		fw.bss_len = bce_TPAT_b09FwBssLen;
3009d0092544SSepherosa Ziehau 		fw.bss_index = 0;
3010d0092544SSepherosa Ziehau 		fw.bss = bce_TPAT_b09FwBss;
3011d0092544SSepherosa Ziehau 
3012d0092544SSepherosa Ziehau 		fw.rodata_addr = bce_TPAT_b09FwRodataAddr;
3013d0092544SSepherosa Ziehau 		fw.rodata_len = bce_TPAT_b09FwRodataLen;
3014d0092544SSepherosa Ziehau 		fw.rodata_index = 0;
3015d0092544SSepherosa Ziehau 		fw.rodata = bce_TPAT_b09FwRodata;
3016d0092544SSepherosa Ziehau 	} else {
301743c2aeb0SSepherosa Ziehau 		fw.ver_major = bce_TPAT_b06FwReleaseMajor;
301843c2aeb0SSepherosa Ziehau 		fw.ver_minor = bce_TPAT_b06FwReleaseMinor;
301943c2aeb0SSepherosa Ziehau 		fw.ver_fix = bce_TPAT_b06FwReleaseFix;
302043c2aeb0SSepherosa Ziehau 		fw.start_addr = bce_TPAT_b06FwStartAddr;
302143c2aeb0SSepherosa Ziehau 
302243c2aeb0SSepherosa Ziehau 		fw.text_addr = bce_TPAT_b06FwTextAddr;
302343c2aeb0SSepherosa Ziehau 		fw.text_len = bce_TPAT_b06FwTextLen;
302443c2aeb0SSepherosa Ziehau 		fw.text_index = 0;
302543c2aeb0SSepherosa Ziehau 		fw.text = bce_TPAT_b06FwText;
302643c2aeb0SSepherosa Ziehau 
302743c2aeb0SSepherosa Ziehau 		fw.data_addr = bce_TPAT_b06FwDataAddr;
302843c2aeb0SSepherosa Ziehau 		fw.data_len = bce_TPAT_b06FwDataLen;
302943c2aeb0SSepherosa Ziehau 		fw.data_index = 0;
303043c2aeb0SSepherosa Ziehau 		fw.data = bce_TPAT_b06FwData;
303143c2aeb0SSepherosa Ziehau 
303243c2aeb0SSepherosa Ziehau 		fw.sbss_addr = bce_TPAT_b06FwSbssAddr;
303343c2aeb0SSepherosa Ziehau 		fw.sbss_len = bce_TPAT_b06FwSbssLen;
303443c2aeb0SSepherosa Ziehau 		fw.sbss_index = 0;
303543c2aeb0SSepherosa Ziehau 		fw.sbss = bce_TPAT_b06FwSbss;
303643c2aeb0SSepherosa Ziehau 
303743c2aeb0SSepherosa Ziehau 		fw.bss_addr = bce_TPAT_b06FwBssAddr;
303843c2aeb0SSepherosa Ziehau 		fw.bss_len = bce_TPAT_b06FwBssLen;
303943c2aeb0SSepherosa Ziehau 		fw.bss_index = 0;
304043c2aeb0SSepherosa Ziehau 		fw.bss = bce_TPAT_b06FwBss;
304143c2aeb0SSepherosa Ziehau 
304243c2aeb0SSepherosa Ziehau 		fw.rodata_addr = bce_TPAT_b06FwRodataAddr;
304343c2aeb0SSepherosa Ziehau 		fw.rodata_len = bce_TPAT_b06FwRodataLen;
304443c2aeb0SSepherosa Ziehau 		fw.rodata_index = 0;
304543c2aeb0SSepherosa Ziehau 		fw.rodata = bce_TPAT_b06FwRodata;
3046d0092544SSepherosa Ziehau 	}
304743c2aeb0SSepherosa Ziehau 
304843c2aeb0SSepherosa Ziehau 	bce_load_cpu_fw(sc, &cpu_reg, &fw);
30495d05a208SSepherosa Ziehau 	bce_start_cpu(sc, &cpu_reg);
3050d0092544SSepherosa Ziehau }
305143c2aeb0SSepherosa Ziehau 
3052d0092544SSepherosa Ziehau /****************************************************************************/
3053d0092544SSepherosa Ziehau /* Initialize the CP CPU.                                                   */
3054d0092544SSepherosa Ziehau /*                                                                          */
3055d0092544SSepherosa Ziehau /* Returns:                                                                 */
3056d0092544SSepherosa Ziehau /*   Nothing.                                                               */
3057d0092544SSepherosa Ziehau /****************************************************************************/
3058d0092544SSepherosa Ziehau static void
bce_init_cp_cpu(struct bce_softc * sc)3059d0092544SSepherosa Ziehau bce_init_cp_cpu(struct bce_softc *sc)
3060d0092544SSepherosa Ziehau {
3061d0092544SSepherosa Ziehau 	struct cpu_reg cpu_reg;
3062d0092544SSepherosa Ziehau 	struct fw_info fw;
3063d0092544SSepherosa Ziehau 
3064d0092544SSepherosa Ziehau 	cpu_reg.mode = BCE_CP_CPU_MODE;
3065d0092544SSepherosa Ziehau 	cpu_reg.mode_value_halt = BCE_CP_CPU_MODE_SOFT_HALT;
3066d0092544SSepherosa Ziehau 	cpu_reg.mode_value_sstep = BCE_CP_CPU_MODE_STEP_ENA;
3067d0092544SSepherosa Ziehau 	cpu_reg.state = BCE_CP_CPU_STATE;
3068d0092544SSepherosa Ziehau 	cpu_reg.state_value_clear = 0xffffff;
3069d0092544SSepherosa Ziehau 	cpu_reg.gpr0 = BCE_CP_CPU_REG_FILE;
3070d0092544SSepherosa Ziehau 	cpu_reg.evmask = BCE_CP_CPU_EVENT_MASK;
3071d0092544SSepherosa Ziehau 	cpu_reg.pc = BCE_CP_CPU_PROGRAM_COUNTER;
3072d0092544SSepherosa Ziehau 	cpu_reg.inst = BCE_CP_CPU_INSTRUCTION;
3073d0092544SSepherosa Ziehau 	cpu_reg.bp = BCE_CP_CPU_HW_BREAKPOINT;
3074d0092544SSepherosa Ziehau 	cpu_reg.spad_base = BCE_CP_SCRATCH;
3075d0092544SSepherosa Ziehau 	cpu_reg.mips_view_base = 0x8000000;
3076d0092544SSepherosa Ziehau 
3077d0092544SSepherosa Ziehau 	if (BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5709 ||
3078d0092544SSepherosa Ziehau 	    BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5716) {
3079d0092544SSepherosa Ziehau 		fw.ver_major = bce_CP_b09FwReleaseMajor;
3080d0092544SSepherosa Ziehau 		fw.ver_minor = bce_CP_b09FwReleaseMinor;
3081d0092544SSepherosa Ziehau 		fw.ver_fix = bce_CP_b09FwReleaseFix;
3082d0092544SSepherosa Ziehau 		fw.start_addr = bce_CP_b09FwStartAddr;
3083d0092544SSepherosa Ziehau 
3084d0092544SSepherosa Ziehau 		fw.text_addr = bce_CP_b09FwTextAddr;
3085d0092544SSepherosa Ziehau 		fw.text_len = bce_CP_b09FwTextLen;
3086d0092544SSepherosa Ziehau 		fw.text_index = 0;
3087d0092544SSepherosa Ziehau 		fw.text = bce_CP_b09FwText;
3088d0092544SSepherosa Ziehau 
3089d0092544SSepherosa Ziehau 		fw.data_addr = bce_CP_b09FwDataAddr;
3090d0092544SSepherosa Ziehau 		fw.data_len = bce_CP_b09FwDataLen;
3091d0092544SSepherosa Ziehau 		fw.data_index = 0;
3092d0092544SSepherosa Ziehau 		fw.data = bce_CP_b09FwData;
3093d0092544SSepherosa Ziehau 
3094d0092544SSepherosa Ziehau 		fw.sbss_addr = bce_CP_b09FwSbssAddr;
3095d0092544SSepherosa Ziehau 		fw.sbss_len = bce_CP_b09FwSbssLen;
3096d0092544SSepherosa Ziehau 		fw.sbss_index = 0;
3097d0092544SSepherosa Ziehau 		fw.sbss = bce_CP_b09FwSbss;
3098d0092544SSepherosa Ziehau 
3099d0092544SSepherosa Ziehau 		fw.bss_addr = bce_CP_b09FwBssAddr;
3100d0092544SSepherosa Ziehau 		fw.bss_len = bce_CP_b09FwBssLen;
3101d0092544SSepherosa Ziehau 		fw.bss_index = 0;
3102d0092544SSepherosa Ziehau 		fw.bss = bce_CP_b09FwBss;
3103d0092544SSepherosa Ziehau 
3104d0092544SSepherosa Ziehau 		fw.rodata_addr = bce_CP_b09FwRodataAddr;
3105d0092544SSepherosa Ziehau 		fw.rodata_len = bce_CP_b09FwRodataLen;
3106d0092544SSepherosa Ziehau 		fw.rodata_index = 0;
3107d0092544SSepherosa Ziehau 		fw.rodata = bce_CP_b09FwRodata;
3108d0092544SSepherosa Ziehau 	} else {
3109d0092544SSepherosa Ziehau 		fw.ver_major = bce_CP_b06FwReleaseMajor;
3110d0092544SSepherosa Ziehau 		fw.ver_minor = bce_CP_b06FwReleaseMinor;
3111d0092544SSepherosa Ziehau 		fw.ver_fix = bce_CP_b06FwReleaseFix;
3112d0092544SSepherosa Ziehau 		fw.start_addr = bce_CP_b06FwStartAddr;
3113d0092544SSepherosa Ziehau 
3114d0092544SSepherosa Ziehau 		fw.text_addr = bce_CP_b06FwTextAddr;
3115d0092544SSepherosa Ziehau 		fw.text_len = bce_CP_b06FwTextLen;
3116d0092544SSepherosa Ziehau 		fw.text_index = 0;
3117d0092544SSepherosa Ziehau 		fw.text = bce_CP_b06FwText;
3118d0092544SSepherosa Ziehau 
3119d0092544SSepherosa Ziehau 		fw.data_addr = bce_CP_b06FwDataAddr;
3120d0092544SSepherosa Ziehau 		fw.data_len = bce_CP_b06FwDataLen;
3121d0092544SSepherosa Ziehau 		fw.data_index = 0;
3122d0092544SSepherosa Ziehau 		fw.data = bce_CP_b06FwData;
3123d0092544SSepherosa Ziehau 
3124d0092544SSepherosa Ziehau 		fw.sbss_addr = bce_CP_b06FwSbssAddr;
3125d0092544SSepherosa Ziehau 		fw.sbss_len = bce_CP_b06FwSbssLen;
3126d0092544SSepherosa Ziehau 		fw.sbss_index = 0;
3127d0092544SSepherosa Ziehau 		fw.sbss = bce_CP_b06FwSbss;
3128d0092544SSepherosa Ziehau 
3129d0092544SSepherosa Ziehau 		fw.bss_addr = bce_CP_b06FwBssAddr;
3130d0092544SSepherosa Ziehau 		fw.bss_len = bce_CP_b06FwBssLen;
3131d0092544SSepherosa Ziehau 		fw.bss_index = 0;
3132d0092544SSepherosa Ziehau 		fw.bss = bce_CP_b06FwBss;
3133d0092544SSepherosa Ziehau 
3134d0092544SSepherosa Ziehau 		fw.rodata_addr = bce_CP_b06FwRodataAddr;
3135d0092544SSepherosa Ziehau 		fw.rodata_len = bce_CP_b06FwRodataLen;
3136d0092544SSepherosa Ziehau 		fw.rodata_index = 0;
3137d0092544SSepherosa Ziehau 		fw.rodata = bce_CP_b06FwRodata;
3138d0092544SSepherosa Ziehau 	}
3139d0092544SSepherosa Ziehau 
3140d0092544SSepherosa Ziehau 	bce_load_cpu_fw(sc, &cpu_reg, &fw);
31415d05a208SSepherosa Ziehau 	bce_start_cpu(sc, &cpu_reg);
3142d0092544SSepherosa Ziehau }
3143d0092544SSepherosa Ziehau 
3144d0092544SSepherosa Ziehau /****************************************************************************/
3145d0092544SSepherosa Ziehau /* Initialize the COM CPU.                                                 */
3146d0092544SSepherosa Ziehau /*                                                                          */
3147d0092544SSepherosa Ziehau /* Returns:                                                                 */
3148d0092544SSepherosa Ziehau /*   Nothing.                                                               */
3149d0092544SSepherosa Ziehau /****************************************************************************/
3150d0092544SSepherosa Ziehau static void
bce_init_com_cpu(struct bce_softc * sc)3151d0092544SSepherosa Ziehau bce_init_com_cpu(struct bce_softc *sc)
3152d0092544SSepherosa Ziehau {
3153d0092544SSepherosa Ziehau 	struct cpu_reg cpu_reg;
3154d0092544SSepherosa Ziehau 	struct fw_info fw;
3155d0092544SSepherosa Ziehau 
315643c2aeb0SSepherosa Ziehau 	cpu_reg.mode = BCE_COM_CPU_MODE;
315743c2aeb0SSepherosa Ziehau 	cpu_reg.mode_value_halt = BCE_COM_CPU_MODE_SOFT_HALT;
315843c2aeb0SSepherosa Ziehau 	cpu_reg.mode_value_sstep = BCE_COM_CPU_MODE_STEP_ENA;
315943c2aeb0SSepherosa Ziehau 	cpu_reg.state = BCE_COM_CPU_STATE;
316043c2aeb0SSepherosa Ziehau 	cpu_reg.state_value_clear = 0xffffff;
316143c2aeb0SSepherosa Ziehau 	cpu_reg.gpr0 = BCE_COM_CPU_REG_FILE;
316243c2aeb0SSepherosa Ziehau 	cpu_reg.evmask = BCE_COM_CPU_EVENT_MASK;
316343c2aeb0SSepherosa Ziehau 	cpu_reg.pc = BCE_COM_CPU_PROGRAM_COUNTER;
316443c2aeb0SSepherosa Ziehau 	cpu_reg.inst = BCE_COM_CPU_INSTRUCTION;
316543c2aeb0SSepherosa Ziehau 	cpu_reg.bp = BCE_COM_CPU_HW_BREAKPOINT;
316643c2aeb0SSepherosa Ziehau 	cpu_reg.spad_base = BCE_COM_SCRATCH;
316743c2aeb0SSepherosa Ziehau 	cpu_reg.mips_view_base = 0x8000000;
316843c2aeb0SSepherosa Ziehau 
3169d0092544SSepherosa Ziehau 	if (BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5709 ||
3170d0092544SSepherosa Ziehau 	    BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5716) {
3171d0092544SSepherosa Ziehau 		fw.ver_major = bce_COM_b09FwReleaseMajor;
3172d0092544SSepherosa Ziehau 		fw.ver_minor = bce_COM_b09FwReleaseMinor;
3173d0092544SSepherosa Ziehau 		fw.ver_fix = bce_COM_b09FwReleaseFix;
3174d0092544SSepherosa Ziehau 		fw.start_addr = bce_COM_b09FwStartAddr;
3175d0092544SSepherosa Ziehau 
3176d0092544SSepherosa Ziehau 		fw.text_addr = bce_COM_b09FwTextAddr;
3177d0092544SSepherosa Ziehau 		fw.text_len = bce_COM_b09FwTextLen;
3178d0092544SSepherosa Ziehau 		fw.text_index = 0;
3179d0092544SSepherosa Ziehau 		fw.text = bce_COM_b09FwText;
3180d0092544SSepherosa Ziehau 
3181d0092544SSepherosa Ziehau 		fw.data_addr = bce_COM_b09FwDataAddr;
3182d0092544SSepherosa Ziehau 		fw.data_len = bce_COM_b09FwDataLen;
3183d0092544SSepherosa Ziehau 		fw.data_index = 0;
3184d0092544SSepherosa Ziehau 		fw.data = bce_COM_b09FwData;
3185d0092544SSepherosa Ziehau 
3186d0092544SSepherosa Ziehau 		fw.sbss_addr = bce_COM_b09FwSbssAddr;
3187d0092544SSepherosa Ziehau 		fw.sbss_len = bce_COM_b09FwSbssLen;
3188d0092544SSepherosa Ziehau 		fw.sbss_index = 0;
3189d0092544SSepherosa Ziehau 		fw.sbss = bce_COM_b09FwSbss;
3190d0092544SSepherosa Ziehau 
3191d0092544SSepherosa Ziehau 		fw.bss_addr = bce_COM_b09FwBssAddr;
3192d0092544SSepherosa Ziehau 		fw.bss_len = bce_COM_b09FwBssLen;
3193d0092544SSepherosa Ziehau 		fw.bss_index = 0;
3194d0092544SSepherosa Ziehau 		fw.bss = bce_COM_b09FwBss;
3195d0092544SSepherosa Ziehau 
3196d0092544SSepherosa Ziehau 		fw.rodata_addr = bce_COM_b09FwRodataAddr;
3197d0092544SSepherosa Ziehau 		fw.rodata_len = bce_COM_b09FwRodataLen;
3198d0092544SSepherosa Ziehau 		fw.rodata_index = 0;
3199d0092544SSepherosa Ziehau 		fw.rodata = bce_COM_b09FwRodata;
3200d0092544SSepherosa Ziehau 	} else {
320143c2aeb0SSepherosa Ziehau 		fw.ver_major = bce_COM_b06FwReleaseMajor;
320243c2aeb0SSepherosa Ziehau 		fw.ver_minor = bce_COM_b06FwReleaseMinor;
320343c2aeb0SSepherosa Ziehau 		fw.ver_fix = bce_COM_b06FwReleaseFix;
320443c2aeb0SSepherosa Ziehau 		fw.start_addr = bce_COM_b06FwStartAddr;
320543c2aeb0SSepherosa Ziehau 
320643c2aeb0SSepherosa Ziehau 		fw.text_addr = bce_COM_b06FwTextAddr;
320743c2aeb0SSepherosa Ziehau 		fw.text_len = bce_COM_b06FwTextLen;
320843c2aeb0SSepherosa Ziehau 		fw.text_index = 0;
320943c2aeb0SSepherosa Ziehau 		fw.text = bce_COM_b06FwText;
321043c2aeb0SSepherosa Ziehau 
321143c2aeb0SSepherosa Ziehau 		fw.data_addr = bce_COM_b06FwDataAddr;
321243c2aeb0SSepherosa Ziehau 		fw.data_len = bce_COM_b06FwDataLen;
321343c2aeb0SSepherosa Ziehau 		fw.data_index = 0;
321443c2aeb0SSepherosa Ziehau 		fw.data = bce_COM_b06FwData;
321543c2aeb0SSepherosa Ziehau 
321643c2aeb0SSepherosa Ziehau 		fw.sbss_addr = bce_COM_b06FwSbssAddr;
321743c2aeb0SSepherosa Ziehau 		fw.sbss_len = bce_COM_b06FwSbssLen;
321843c2aeb0SSepherosa Ziehau 		fw.sbss_index = 0;
321943c2aeb0SSepherosa Ziehau 		fw.sbss = bce_COM_b06FwSbss;
322043c2aeb0SSepherosa Ziehau 
322143c2aeb0SSepherosa Ziehau 		fw.bss_addr = bce_COM_b06FwBssAddr;
322243c2aeb0SSepherosa Ziehau 		fw.bss_len = bce_COM_b06FwBssLen;
322343c2aeb0SSepherosa Ziehau 		fw.bss_index = 0;
322443c2aeb0SSepherosa Ziehau 		fw.bss = bce_COM_b06FwBss;
322543c2aeb0SSepherosa Ziehau 
322643c2aeb0SSepherosa Ziehau 		fw.rodata_addr = bce_COM_b06FwRodataAddr;
322743c2aeb0SSepherosa Ziehau 		fw.rodata_len = bce_COM_b06FwRodataLen;
322843c2aeb0SSepherosa Ziehau 		fw.rodata_index = 0;
322943c2aeb0SSepherosa Ziehau 		fw.rodata = bce_COM_b06FwRodata;
3230d0092544SSepherosa Ziehau 	}
323143c2aeb0SSepherosa Ziehau 
323243c2aeb0SSepherosa Ziehau 	bce_load_cpu_fw(sc, &cpu_reg, &fw);
32335d05a208SSepherosa Ziehau 	bce_start_cpu(sc, &cpu_reg);
323443c2aeb0SSepherosa Ziehau }
323543c2aeb0SSepherosa Ziehau 
323643c2aeb0SSepherosa Ziehau /****************************************************************************/
3237d0092544SSepherosa Ziehau /* Initialize the RV2P, RX, TX, TPAT, COM, and CP CPUs.                     */
3238d0092544SSepherosa Ziehau /*                                                                          */
3239d0092544SSepherosa Ziehau /* Loads the firmware for each CPU and starts the CPU.                      */
3240d0092544SSepherosa Ziehau /*                                                                          */
3241d0092544SSepherosa Ziehau /* Returns:                                                                 */
3242d0092544SSepherosa Ziehau /*   Nothing.                                                               */
3243d0092544SSepherosa Ziehau /****************************************************************************/
3244d0092544SSepherosa Ziehau static void
bce_init_cpus(struct bce_softc * sc)3245d0092544SSepherosa Ziehau bce_init_cpus(struct bce_softc *sc)
3246d0092544SSepherosa Ziehau {
3247d0092544SSepherosa Ziehau 	if (BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5709 ||
3248d0092544SSepherosa Ziehau 	    BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5716) {
3249cff16e71SSepherosa Ziehau 		if (BCE_CHIP_REV(sc) == BCE_CHIP_REV_Ax) {
3250cff16e71SSepherosa Ziehau 			bce_load_rv2p_fw(sc, bce_xi90_rv2p_proc1,
3251cff16e71SSepherosa Ziehau 			    sizeof(bce_xi90_rv2p_proc1), RV2P_PROC1);
3252cff16e71SSepherosa Ziehau 			bce_load_rv2p_fw(sc, bce_xi90_rv2p_proc2,
3253cff16e71SSepherosa Ziehau 			    sizeof(bce_xi90_rv2p_proc2), RV2P_PROC2);
3254d0092544SSepherosa Ziehau 		} else {
3255cff16e71SSepherosa Ziehau 			bce_load_rv2p_fw(sc, bce_xi_rv2p_proc1,
3256cff16e71SSepherosa Ziehau 			    sizeof(bce_xi_rv2p_proc1), RV2P_PROC1);
3257cff16e71SSepherosa Ziehau 			bce_load_rv2p_fw(sc, bce_xi_rv2p_proc2,
3258cff16e71SSepherosa Ziehau 			    sizeof(bce_xi_rv2p_proc2), RV2P_PROC2);
3259cff16e71SSepherosa Ziehau 		}
3260cff16e71SSepherosa Ziehau 	} else {
3261cff16e71SSepherosa Ziehau 		bce_load_rv2p_fw(sc, bce_rv2p_proc1,
3262cff16e71SSepherosa Ziehau 		    sizeof(bce_rv2p_proc1), RV2P_PROC1);
3263cff16e71SSepherosa Ziehau 		bce_load_rv2p_fw(sc, bce_rv2p_proc2,
3264cff16e71SSepherosa Ziehau 		    sizeof(bce_rv2p_proc2), RV2P_PROC2);
3265d0092544SSepherosa Ziehau 	}
3266d0092544SSepherosa Ziehau 
3267d0092544SSepherosa Ziehau 	bce_init_rxp_cpu(sc);
3268d0092544SSepherosa Ziehau 	bce_init_txp_cpu(sc);
3269d0092544SSepherosa Ziehau 	bce_init_tpat_cpu(sc);
3270d0092544SSepherosa Ziehau 	bce_init_com_cpu(sc);
3271d0092544SSepherosa Ziehau 	bce_init_cp_cpu(sc);
3272d0092544SSepherosa Ziehau }
3273d0092544SSepherosa Ziehau 
3274d0092544SSepherosa Ziehau /****************************************************************************/
327543c2aeb0SSepherosa Ziehau /* Initialize context memory.                                               */
327643c2aeb0SSepherosa Ziehau /*                                                                          */
327743c2aeb0SSepherosa Ziehau /* Clears the memory associated with each Context ID (CID).                 */
327843c2aeb0SSepherosa Ziehau /*                                                                          */
327943c2aeb0SSepherosa Ziehau /* Returns:                                                                 */
328043c2aeb0SSepherosa Ziehau /*   Nothing.                                                               */
328143c2aeb0SSepherosa Ziehau /****************************************************************************/
32825b609aa3SSepherosa Ziehau static int
bce_init_ctx(struct bce_softc * sc)32833a41a80bSSepherosa Ziehau bce_init_ctx(struct bce_softc *sc)
328443c2aeb0SSepherosa Ziehau {
3285d0092544SSepherosa Ziehau 	if (BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5709 ||
3286d0092544SSepherosa Ziehau 	    BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5716) {
3287d0092544SSepherosa Ziehau 		/* DRC: Replace this constant value with a #define. */
3288d0092544SSepherosa Ziehau 		int i, retry_cnt = 10;
3289d0092544SSepherosa Ziehau 		uint32_t val;
329043c2aeb0SSepherosa Ziehau 
3291d0092544SSepherosa Ziehau 		/*
3292d0092544SSepherosa Ziehau 		 * BCM5709 context memory may be cached
3293d0092544SSepherosa Ziehau 		 * in host memory so prepare the host memory
3294d0092544SSepherosa Ziehau 		 * for access.
3295d0092544SSepherosa Ziehau 		 */
3296d0092544SSepherosa Ziehau 		val = BCE_CTX_COMMAND_ENABLED | BCE_CTX_COMMAND_MEM_INIT |
3297d0092544SSepherosa Ziehau 		    (1 << 12);
3298d0092544SSepherosa Ziehau 		val |= (BCM_PAGE_BITS - 8) << 16;
3299d0092544SSepherosa Ziehau 		REG_WR(sc, BCE_CTX_COMMAND, val);
330043c2aeb0SSepherosa Ziehau 
3301d0092544SSepherosa Ziehau 		/* Wait for mem init command to complete. */
3302d0092544SSepherosa Ziehau 		for (i = 0; i < retry_cnt; i++) {
3303d0092544SSepherosa Ziehau 			val = REG_RD(sc, BCE_CTX_COMMAND);
3304d0092544SSepherosa Ziehau 			if (!(val & BCE_CTX_COMMAND_MEM_INIT))
3305d0092544SSepherosa Ziehau 				break;
3306d0092544SSepherosa Ziehau 			DELAY(2);
3307d0092544SSepherosa Ziehau 		}
33085b609aa3SSepherosa Ziehau 		if (i == retry_cnt) {
33095b609aa3SSepherosa Ziehau 			device_printf(sc->bce_dev,
33105b609aa3SSepherosa Ziehau 			    "Context memory initialization failed!\n");
33115b609aa3SSepherosa Ziehau 			return ETIMEDOUT;
33125b609aa3SSepherosa Ziehau 		}
331343c2aeb0SSepherosa Ziehau 
3314d0092544SSepherosa Ziehau 		for (i = 0; i < sc->ctx_pages; i++) {
3315d0092544SSepherosa Ziehau 			int j;
331643c2aeb0SSepherosa Ziehau 
3317d0092544SSepherosa Ziehau 			/*
3318d0092544SSepherosa Ziehau 			 * Set the physical address of the context
3319d0092544SSepherosa Ziehau 			 * memory cache.
3320d0092544SSepherosa Ziehau 			 */
3321d0092544SSepherosa Ziehau 			REG_WR(sc, BCE_CTX_HOST_PAGE_TBL_DATA0,
3322d0092544SSepherosa Ziehau 			    BCE_ADDR_LO(sc->ctx_paddr[i] & 0xfffffff0) |
3323d0092544SSepherosa Ziehau 			    BCE_CTX_HOST_PAGE_TBL_DATA0_VALID);
3324d0092544SSepherosa Ziehau 			REG_WR(sc, BCE_CTX_HOST_PAGE_TBL_DATA1,
3325d0092544SSepherosa Ziehau 			    BCE_ADDR_HI(sc->ctx_paddr[i]));
3326d0092544SSepherosa Ziehau 			REG_WR(sc, BCE_CTX_HOST_PAGE_TBL_CTRL,
3327d0092544SSepherosa Ziehau 			    i | BCE_CTX_HOST_PAGE_TBL_CTRL_WRITE_REQ);
3328d0092544SSepherosa Ziehau 
3329d0092544SSepherosa Ziehau 			/*
3330d0092544SSepherosa Ziehau 			 * Verify that the context memory write was successful.
3331d0092544SSepherosa Ziehau 			 */
3332d0092544SSepherosa Ziehau 			for (j = 0; j < retry_cnt; j++) {
3333d0092544SSepherosa Ziehau 				val = REG_RD(sc, BCE_CTX_HOST_PAGE_TBL_CTRL);
3334d0092544SSepherosa Ziehau 				if ((val &
3335d0092544SSepherosa Ziehau 				    BCE_CTX_HOST_PAGE_TBL_CTRL_WRITE_REQ) == 0)
3336d0092544SSepherosa Ziehau 					break;
3337d0092544SSepherosa Ziehau 				DELAY(5);
3338d0092544SSepherosa Ziehau 			}
33395b609aa3SSepherosa Ziehau 			if (j == retry_cnt) {
33405b609aa3SSepherosa Ziehau 				device_printf(sc->bce_dev,
33415b609aa3SSepherosa Ziehau 				    "Failed to initialize context page!\n");
33425b609aa3SSepherosa Ziehau 				return ETIMEDOUT;
33435b609aa3SSepherosa Ziehau 			}
3344d0092544SSepherosa Ziehau 		}
3345d0092544SSepherosa Ziehau 	} else {
3346d0092544SSepherosa Ziehau 		uint32_t vcid_addr, offset;
3347d0092544SSepherosa Ziehau 
3348d0092544SSepherosa Ziehau 		/*
3349d0092544SSepherosa Ziehau 		 * For the 5706/5708, context memory is local to
3350d0092544SSepherosa Ziehau 		 * the controller, so initialize the controller
3351d0092544SSepherosa Ziehau 		 * context memory.
3352d0092544SSepherosa Ziehau 		 */
3353d0092544SSepherosa Ziehau 
3354d0092544SSepherosa Ziehau 		vcid_addr = GET_CID_ADDR(96);
3355d0092544SSepherosa Ziehau 		while (vcid_addr) {
3356d0092544SSepherosa Ziehau 			vcid_addr -= PHY_CTX_SIZE;
3357d0092544SSepherosa Ziehau 
3358d0092544SSepherosa Ziehau 			REG_WR(sc, BCE_CTX_VIRT_ADDR, 0);
3359d0092544SSepherosa Ziehau 			REG_WR(sc, BCE_CTX_PAGE_TBL, vcid_addr);
3360d0092544SSepherosa Ziehau 
3361d0092544SSepherosa Ziehau 			for (offset = 0; offset < PHY_CTX_SIZE; offset += 4)
3362d0092544SSepherosa Ziehau 				CTX_WR(sc, 0x00, offset, 0);
33633a41a80bSSepherosa Ziehau 
33643a41a80bSSepherosa Ziehau 			REG_WR(sc, BCE_CTX_VIRT_ADDR, vcid_addr);
3365d0092544SSepherosa Ziehau 			REG_WR(sc, BCE_CTX_PAGE_TBL, vcid_addr);
33663a41a80bSSepherosa Ziehau 		}
336743c2aeb0SSepherosa Ziehau 	}
33685b609aa3SSepherosa Ziehau 	return 0;
336943c2aeb0SSepherosa Ziehau }
337043c2aeb0SSepherosa Ziehau 
337143c2aeb0SSepherosa Ziehau /****************************************************************************/
337243c2aeb0SSepherosa Ziehau /* Fetch the permanent MAC address of the controller.                       */
337343c2aeb0SSepherosa Ziehau /*                                                                          */
337443c2aeb0SSepherosa Ziehau /* Returns:                                                                 */
337543c2aeb0SSepherosa Ziehau /*   Nothing.                                                               */
337643c2aeb0SSepherosa Ziehau /****************************************************************************/
337743c2aeb0SSepherosa Ziehau static void
bce_get_mac_addr(struct bce_softc * sc)337843c2aeb0SSepherosa Ziehau bce_get_mac_addr(struct bce_softc *sc)
337943c2aeb0SSepherosa Ziehau {
338043c2aeb0SSepherosa Ziehau 	uint32_t mac_lo = 0, mac_hi = 0;
33813970c114SSepherosa Ziehau 
338243c2aeb0SSepherosa Ziehau 	/*
338343c2aeb0SSepherosa Ziehau 	 * The NetXtreme II bootcode populates various NIC
338443c2aeb0SSepherosa Ziehau 	 * power-on and runtime configuration items in a
338543c2aeb0SSepherosa Ziehau 	 * shared memory area.  The factory configured MAC
338643c2aeb0SSepherosa Ziehau 	 * address is available from both NVRAM and the
338743c2aeb0SSepherosa Ziehau 	 * shared memory area so we'll read the value from
338843c2aeb0SSepherosa Ziehau 	 * shared memory for speed.
338943c2aeb0SSepherosa Ziehau 	 */
339043c2aeb0SSepherosa Ziehau 
3391bc30d40dSSepherosa Ziehau 	mac_hi = bce_shmem_rd(sc,  BCE_PORT_HW_CFG_MAC_UPPER);
3392bc30d40dSSepherosa Ziehau 	mac_lo = bce_shmem_rd(sc, BCE_PORT_HW_CFG_MAC_LOWER);
339343c2aeb0SSepherosa Ziehau 
339443c2aeb0SSepherosa Ziehau 	if (mac_lo == 0 && mac_hi == 0) {
339543c2aeb0SSepherosa Ziehau 		if_printf(&sc->arpcom.ac_if, "Invalid Ethernet address!\n");
339643c2aeb0SSepherosa Ziehau 	} else {
339743c2aeb0SSepherosa Ziehau 		sc->eaddr[0] = (u_char)(mac_hi >> 8);
339843c2aeb0SSepherosa Ziehau 		sc->eaddr[1] = (u_char)(mac_hi >> 0);
339943c2aeb0SSepherosa Ziehau 		sc->eaddr[2] = (u_char)(mac_lo >> 24);
340043c2aeb0SSepherosa Ziehau 		sc->eaddr[3] = (u_char)(mac_lo >> 16);
340143c2aeb0SSepherosa Ziehau 		sc->eaddr[4] = (u_char)(mac_lo >> 8);
340243c2aeb0SSepherosa Ziehau 		sc->eaddr[5] = (u_char)(mac_lo >> 0);
340343c2aeb0SSepherosa Ziehau 	}
340443c2aeb0SSepherosa Ziehau }
340543c2aeb0SSepherosa Ziehau 
340643c2aeb0SSepherosa Ziehau /****************************************************************************/
340743c2aeb0SSepherosa Ziehau /* Program the MAC address.                                                 */
340843c2aeb0SSepherosa Ziehau /*                                                                          */
340943c2aeb0SSepherosa Ziehau /* Returns:                                                                 */
341043c2aeb0SSepherosa Ziehau /*   Nothing.                                                               */
341143c2aeb0SSepherosa Ziehau /****************************************************************************/
341243c2aeb0SSepherosa Ziehau static void
bce_set_mac_addr(struct bce_softc * sc)341343c2aeb0SSepherosa Ziehau bce_set_mac_addr(struct bce_softc *sc)
341443c2aeb0SSepherosa Ziehau {
341543c2aeb0SSepherosa Ziehau 	const uint8_t *mac_addr = sc->eaddr;
341643c2aeb0SSepherosa Ziehau 	uint32_t val;
341743c2aeb0SSepherosa Ziehau 
341843c2aeb0SSepherosa Ziehau 	val = (mac_addr[0] << 8) | mac_addr[1];
341943c2aeb0SSepherosa Ziehau 	REG_WR(sc, BCE_EMAC_MAC_MATCH0, val);
342043c2aeb0SSepherosa Ziehau 
342143c2aeb0SSepherosa Ziehau 	val = (mac_addr[2] << 24) |
342243c2aeb0SSepherosa Ziehau 	      (mac_addr[3] << 16) |
342343c2aeb0SSepherosa Ziehau 	      (mac_addr[4] << 8) |
342443c2aeb0SSepherosa Ziehau 	      mac_addr[5];
342543c2aeb0SSepherosa Ziehau 	REG_WR(sc, BCE_EMAC_MAC_MATCH1, val);
342643c2aeb0SSepherosa Ziehau }
342743c2aeb0SSepherosa Ziehau 
342843c2aeb0SSepherosa Ziehau /****************************************************************************/
342943c2aeb0SSepherosa Ziehau /* Stop the controller.                                                     */
343043c2aeb0SSepherosa Ziehau /*                                                                          */
343143c2aeb0SSepherosa Ziehau /* Returns:                                                                 */
343243c2aeb0SSepherosa Ziehau /*   Nothing.                                                               */
343343c2aeb0SSepherosa Ziehau /****************************************************************************/
343443c2aeb0SSepherosa Ziehau static void
bce_stop(struct bce_softc * sc)343543c2aeb0SSepherosa Ziehau bce_stop(struct bce_softc *sc)
343643c2aeb0SSepherosa Ziehau {
343743c2aeb0SSepherosa Ziehau 	struct ifnet *ifp = &sc->arpcom.ac_if;
343810bcbdabSSepherosa Ziehau 	int i;
343943c2aeb0SSepherosa Ziehau 
344084464af5SSepherosa Ziehau 	ASSERT_IFNET_SERIALIZED_ALL(ifp);
344143c2aeb0SSepherosa Ziehau 
3442d0092544SSepherosa Ziehau 	callout_stop(&sc->bce_tick_callout);
344343c2aeb0SSepherosa Ziehau 
344443c2aeb0SSepherosa Ziehau 	/* Disable the transmit/receive blocks. */
3445d0092544SSepherosa Ziehau 	REG_WR(sc, BCE_MISC_ENABLE_CLR_BITS, BCE_MISC_ENABLE_CLR_DEFAULT);
344643c2aeb0SSepherosa Ziehau 	REG_RD(sc, BCE_MISC_ENABLE_CLR_BITS);
344743c2aeb0SSepherosa Ziehau 	DELAY(20);
344843c2aeb0SSepherosa Ziehau 
344943c2aeb0SSepherosa Ziehau 	bce_disable_intr(sc);
345043c2aeb0SSepherosa Ziehau 
3451f774fa0fSSepherosa Ziehau 	ifp->if_flags &= ~IFF_RUNNING;
3452ac2202eaSSepherosa Ziehau 	for (i = 0; i < sc->tx_ring_cnt; ++i) {
3453f774fa0fSSepherosa Ziehau 		ifsq_clr_oactive(sc->tx_rings[i].ifsq);
3454f774fa0fSSepherosa Ziehau 		ifsq_watchdog_stop(&sc->tx_rings[i].tx_watchdog);
3455f774fa0fSSepherosa Ziehau 	}
3456f774fa0fSSepherosa Ziehau 
345743c2aeb0SSepherosa Ziehau 	/* Free the RX lists. */
3458ac2202eaSSepherosa Ziehau 	for (i = 0; i < sc->rx_ring_cnt; ++i)
345908b64767SSepherosa Ziehau 		bce_free_rx_chain(&sc->rx_rings[i]);
346043c2aeb0SSepherosa Ziehau 
346143c2aeb0SSepherosa Ziehau 	/* Free TX buffers. */
3462ac2202eaSSepherosa Ziehau 	for (i = 0; i < sc->tx_ring_cnt; ++i)
346310bcbdabSSepherosa Ziehau 		bce_free_tx_chain(&sc->tx_rings[i]);
346443c2aeb0SSepherosa Ziehau 
346543c2aeb0SSepherosa Ziehau 	sc->bce_link = 0;
3466bdeb8fffSSepherosa Ziehau 	sc->bce_coalchg_mask = 0;
346743c2aeb0SSepherosa Ziehau }
346843c2aeb0SSepherosa Ziehau 
346943c2aeb0SSepherosa Ziehau static int
bce_reset(struct bce_softc * sc,uint32_t reset_code)347043c2aeb0SSepherosa Ziehau bce_reset(struct bce_softc *sc, uint32_t reset_code)
347143c2aeb0SSepherosa Ziehau {
347243c2aeb0SSepherosa Ziehau 	uint32_t val;
347343c2aeb0SSepherosa Ziehau 	int i, rc = 0;
347443c2aeb0SSepherosa Ziehau 
347543c2aeb0SSepherosa Ziehau 	/* Wait for pending PCI transactions to complete. */
347643c2aeb0SSepherosa Ziehau 	REG_WR(sc, BCE_MISC_ENABLE_CLR_BITS,
347743c2aeb0SSepherosa Ziehau 	       BCE_MISC_ENABLE_CLR_BITS_TX_DMA_ENABLE |
347843c2aeb0SSepherosa Ziehau 	       BCE_MISC_ENABLE_CLR_BITS_DMA_ENGINE_ENABLE |
347943c2aeb0SSepherosa Ziehau 	       BCE_MISC_ENABLE_CLR_BITS_RX_DMA_ENABLE |
348043c2aeb0SSepherosa Ziehau 	       BCE_MISC_ENABLE_CLR_BITS_HOST_COALESCE_ENABLE);
348143c2aeb0SSepherosa Ziehau 	val = REG_RD(sc, BCE_MISC_ENABLE_CLR_BITS);
348243c2aeb0SSepherosa Ziehau 	DELAY(5);
348343c2aeb0SSepherosa Ziehau 
3484d0092544SSepherosa Ziehau 	/* Disable DMA */
3485d0092544SSepherosa Ziehau 	if (BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5709 ||
3486d0092544SSepherosa Ziehau 	    BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5716) {
3487d0092544SSepherosa Ziehau 		val = REG_RD(sc, BCE_MISC_NEW_CORE_CTL);
3488d0092544SSepherosa Ziehau 		val &= ~BCE_MISC_NEW_CORE_CTL_DMA_ENABLE;
3489d0092544SSepherosa Ziehau 		REG_WR(sc, BCE_MISC_NEW_CORE_CTL, val);
3490d0092544SSepherosa Ziehau 	}
3491d0092544SSepherosa Ziehau 
349243c2aeb0SSepherosa Ziehau 	/* Assume bootcode is running. */
349343c2aeb0SSepherosa Ziehau 	sc->bce_fw_timed_out = 0;
3494d8870c52SSepherosa Ziehau 	sc->bce_drv_cardiac_arrest = 0;
349543c2aeb0SSepherosa Ziehau 
349643c2aeb0SSepherosa Ziehau 	/* Give the firmware a chance to prepare for the reset. */
349743c2aeb0SSepherosa Ziehau 	rc = bce_fw_sync(sc, BCE_DRV_MSG_DATA_WAIT0 | reset_code);
349843c2aeb0SSepherosa Ziehau 	if (rc) {
349943c2aeb0SSepherosa Ziehau 		if_printf(&sc->arpcom.ac_if,
350043c2aeb0SSepherosa Ziehau 			  "Firmware is not ready for reset\n");
350143c2aeb0SSepherosa Ziehau 		return rc;
350243c2aeb0SSepherosa Ziehau 	}
350343c2aeb0SSepherosa Ziehau 
350443c2aeb0SSepherosa Ziehau 	/* Set a firmware reminder that this is a soft reset. */
3505bc30d40dSSepherosa Ziehau 	bce_shmem_wr(sc, BCE_DRV_RESET_SIGNATURE,
350643c2aeb0SSepherosa Ziehau 	    BCE_DRV_RESET_SIGNATURE_MAGIC);
350743c2aeb0SSepherosa Ziehau 
350843c2aeb0SSepherosa Ziehau 	/* Dummy read to force the chip to complete all current transactions. */
350943c2aeb0SSepherosa Ziehau 	val = REG_RD(sc, BCE_MISC_ID);
351043c2aeb0SSepherosa Ziehau 
351143c2aeb0SSepherosa Ziehau 	/* Chip reset. */
3512d0092544SSepherosa Ziehau 	if (BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5709 ||
3513d0092544SSepherosa Ziehau 	    BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5716) {
3514d0092544SSepherosa Ziehau 		REG_WR(sc, BCE_MISC_COMMAND, BCE_MISC_COMMAND_SW_RESET);
3515d0092544SSepherosa Ziehau 		REG_RD(sc, BCE_MISC_COMMAND);
3516d0092544SSepherosa Ziehau 		DELAY(5);
3517d0092544SSepherosa Ziehau 
3518d0092544SSepherosa Ziehau 		val = BCE_PCICFG_MISC_CONFIG_REG_WINDOW_ENA |
3519d0092544SSepherosa Ziehau 		    BCE_PCICFG_MISC_CONFIG_TARGET_MB_WORD_SWAP;
3520d0092544SSepherosa Ziehau 
3521d0092544SSepherosa Ziehau 		pci_write_config(sc->bce_dev, BCE_PCICFG_MISC_CONFIG, val, 4);
3522d0092544SSepherosa Ziehau 	} else {
352343c2aeb0SSepherosa Ziehau 		val = BCE_PCICFG_MISC_CONFIG_CORE_RST_REQ |
352443c2aeb0SSepherosa Ziehau 		    BCE_PCICFG_MISC_CONFIG_REG_WINDOW_ENA |
352543c2aeb0SSepherosa Ziehau 		    BCE_PCICFG_MISC_CONFIG_TARGET_MB_WORD_SWAP;
352643c2aeb0SSepherosa Ziehau 		REG_WR(sc, BCE_PCICFG_MISC_CONFIG, val);
352743c2aeb0SSepherosa Ziehau 
352843c2aeb0SSepherosa Ziehau 		/* Allow up to 30us for reset to complete. */
352943c2aeb0SSepherosa Ziehau 		for (i = 0; i < 10; i++) {
353043c2aeb0SSepherosa Ziehau 			val = REG_RD(sc, BCE_PCICFG_MISC_CONFIG);
353143c2aeb0SSepherosa Ziehau 			if ((val & (BCE_PCICFG_MISC_CONFIG_CORE_RST_REQ |
3532d0092544SSepherosa Ziehau 			    BCE_PCICFG_MISC_CONFIG_CORE_RST_BSY)) == 0)
353343c2aeb0SSepherosa Ziehau 				break;
353443c2aeb0SSepherosa Ziehau 			DELAY(10);
353543c2aeb0SSepherosa Ziehau 		}
353643c2aeb0SSepherosa Ziehau 
353743c2aeb0SSepherosa Ziehau 		/* Check that reset completed successfully. */
353843c2aeb0SSepherosa Ziehau 		if (val & (BCE_PCICFG_MISC_CONFIG_CORE_RST_REQ |
353943c2aeb0SSepherosa Ziehau 		    BCE_PCICFG_MISC_CONFIG_CORE_RST_BSY)) {
354043c2aeb0SSepherosa Ziehau 			if_printf(&sc->arpcom.ac_if, "Reset failed!\n");
354143c2aeb0SSepherosa Ziehau 			return EBUSY;
354243c2aeb0SSepherosa Ziehau 		}
3543d0092544SSepherosa Ziehau 	}
354443c2aeb0SSepherosa Ziehau 
354543c2aeb0SSepherosa Ziehau 	/* Make sure byte swapping is properly configured. */
354643c2aeb0SSepherosa Ziehau 	val = REG_RD(sc, BCE_PCI_SWAP_DIAG0);
354743c2aeb0SSepherosa Ziehau 	if (val != 0x01020304) {
354843c2aeb0SSepherosa Ziehau 		if_printf(&sc->arpcom.ac_if, "Byte swap is incorrect!\n");
354943c2aeb0SSepherosa Ziehau 		return ENODEV;
355043c2aeb0SSepherosa Ziehau 	}
355143c2aeb0SSepherosa Ziehau 
355243c2aeb0SSepherosa Ziehau 	/* Just completed a reset, assume that firmware is running again. */
355343c2aeb0SSepherosa Ziehau 	sc->bce_fw_timed_out = 0;
3554d8870c52SSepherosa Ziehau 	sc->bce_drv_cardiac_arrest = 0;
355543c2aeb0SSepherosa Ziehau 
355643c2aeb0SSepherosa Ziehau 	/* Wait for the firmware to finish its initialization. */
355743c2aeb0SSepherosa Ziehau 	rc = bce_fw_sync(sc, BCE_DRV_MSG_DATA_WAIT1 | reset_code);
355843c2aeb0SSepherosa Ziehau 	if (rc) {
355943c2aeb0SSepherosa Ziehau 		if_printf(&sc->arpcom.ac_if,
356043c2aeb0SSepherosa Ziehau 			  "Firmware did not complete initialization!\n");
356143c2aeb0SSepherosa Ziehau 	}
3562b42386eeSSepherosa Ziehau 
3563b42386eeSSepherosa Ziehau 	if (sc->bce_irq_type == PCI_INTR_TYPE_MSIX) {
3564b42386eeSSepherosa Ziehau 		bce_setup_msix_table(sc);
3565b42386eeSSepherosa Ziehau 		/* Prevent MSIX table reads and write from timing out */
3566b42386eeSSepherosa Ziehau 		REG_WR(sc, BCE_MISC_ECO_HW_CTL,
3567b42386eeSSepherosa Ziehau 		    BCE_MISC_ECO_HW_CTL_LARGE_GRC_TMOUT_EN);
3568b42386eeSSepherosa Ziehau 
3569b42386eeSSepherosa Ziehau 	}
357043c2aeb0SSepherosa Ziehau 	return rc;
357143c2aeb0SSepherosa Ziehau }
357243c2aeb0SSepherosa Ziehau 
357343c2aeb0SSepherosa Ziehau static int
bce_chipinit(struct bce_softc * sc)357443c2aeb0SSepherosa Ziehau bce_chipinit(struct bce_softc *sc)
357543c2aeb0SSepherosa Ziehau {
357643c2aeb0SSepherosa Ziehau 	uint32_t val;
357743c2aeb0SSepherosa Ziehau 	int rc = 0;
357843c2aeb0SSepherosa Ziehau 
357943c2aeb0SSepherosa Ziehau 	/* Make sure the interrupt is not active. */
358043c2aeb0SSepherosa Ziehau 	REG_WR(sc, BCE_PCICFG_INT_ACK_CMD, BCE_PCICFG_INT_ACK_CMD_MASK_INT);
3581d0092544SSepherosa Ziehau 	REG_RD(sc, BCE_PCICFG_INT_ACK_CMD);
358243c2aeb0SSepherosa Ziehau 
358343c2aeb0SSepherosa Ziehau 	/*
358443c2aeb0SSepherosa Ziehau 	 * Initialize DMA byte/word swapping, configure the number of DMA
358543c2aeb0SSepherosa Ziehau 	 * channels and PCI clock compensation delay.
358643c2aeb0SSepherosa Ziehau 	 */
358743c2aeb0SSepherosa Ziehau 	val = BCE_DMA_CONFIG_DATA_BYTE_SWAP |
358843c2aeb0SSepherosa Ziehau 	      BCE_DMA_CONFIG_DATA_WORD_SWAP |
358943c2aeb0SSepherosa Ziehau #if BYTE_ORDER == BIG_ENDIAN
359043c2aeb0SSepherosa Ziehau 	      BCE_DMA_CONFIG_CNTL_BYTE_SWAP |
359143c2aeb0SSepherosa Ziehau #endif
359243c2aeb0SSepherosa Ziehau 	      BCE_DMA_CONFIG_CNTL_WORD_SWAP |
359343c2aeb0SSepherosa Ziehau 	      DMA_READ_CHANS << 12 |
359443c2aeb0SSepherosa Ziehau 	      DMA_WRITE_CHANS << 16;
359543c2aeb0SSepherosa Ziehau 
359643c2aeb0SSepherosa Ziehau 	val |= (0x2 << 20) | BCE_DMA_CONFIG_CNTL_PCI_COMP_DLY;
359743c2aeb0SSepherosa Ziehau 
359843c2aeb0SSepherosa Ziehau 	if ((sc->bce_flags & BCE_PCIX_FLAG) && sc->bus_speed_mhz == 133)
359943c2aeb0SSepherosa Ziehau 		val |= BCE_DMA_CONFIG_PCI_FAST_CLK_CMP;
360043c2aeb0SSepherosa Ziehau 
360143c2aeb0SSepherosa Ziehau 	/*
360243c2aeb0SSepherosa Ziehau 	 * This setting resolves a problem observed on certain Intel PCI
360343c2aeb0SSepherosa Ziehau 	 * chipsets that cannot handle multiple outstanding DMA operations.
360443c2aeb0SSepherosa Ziehau 	 * See errata E9_5706A1_65.
360543c2aeb0SSepherosa Ziehau 	 */
360643c2aeb0SSepherosa Ziehau 	if (BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5706 &&
360743c2aeb0SSepherosa Ziehau 	    BCE_CHIP_ID(sc) != BCE_CHIP_ID_5706_A0 &&
360843c2aeb0SSepherosa Ziehau 	    !(sc->bce_flags & BCE_PCIX_FLAG))
360943c2aeb0SSepherosa Ziehau 		val |= BCE_DMA_CONFIG_CNTL_PING_PONG_DMA;
361043c2aeb0SSepherosa Ziehau 
361143c2aeb0SSepherosa Ziehau 	REG_WR(sc, BCE_DMA_CONFIG, val);
361243c2aeb0SSepherosa Ziehau 
361343c2aeb0SSepherosa Ziehau 	/* Enable the RX_V2P and Context state machines before access. */
361443c2aeb0SSepherosa Ziehau 	REG_WR(sc, BCE_MISC_ENABLE_SET_BITS,
361543c2aeb0SSepherosa Ziehau 	       BCE_MISC_ENABLE_SET_BITS_HOST_COALESCE_ENABLE |
361643c2aeb0SSepherosa Ziehau 	       BCE_MISC_ENABLE_STATUS_BITS_RX_V2P_ENABLE |
361743c2aeb0SSepherosa Ziehau 	       BCE_MISC_ENABLE_STATUS_BITS_CONTEXT_ENABLE);
361843c2aeb0SSepherosa Ziehau 
361943c2aeb0SSepherosa Ziehau 	/* Initialize context mapping and zero out the quick contexts. */
36205b609aa3SSepherosa Ziehau 	rc = bce_init_ctx(sc);
36215b609aa3SSepherosa Ziehau 	if (rc != 0)
36225b609aa3SSepherosa Ziehau 		return rc;
362343c2aeb0SSepherosa Ziehau 
362443c2aeb0SSepherosa Ziehau 	/* Initialize the on-boards CPUs */
362543c2aeb0SSepherosa Ziehau 	bce_init_cpus(sc);
362643c2aeb0SSepherosa Ziehau 
36275d05a208SSepherosa Ziehau 	/* Enable management frames (NC-SI) to flow to the MCP. */
36285d05a208SSepherosa Ziehau 	if (sc->bce_flags & BCE_MFW_ENABLE_FLAG) {
36295d05a208SSepherosa Ziehau 		val = REG_RD(sc, BCE_RPM_MGMT_PKT_CTRL) |
36305d05a208SSepherosa Ziehau 		    BCE_RPM_MGMT_PKT_CTRL_MGMT_EN;
36315d05a208SSepherosa Ziehau 		REG_WR(sc, BCE_RPM_MGMT_PKT_CTRL, val);
36325d05a208SSepherosa Ziehau 	}
36335d05a208SSepherosa Ziehau 
363443c2aeb0SSepherosa Ziehau 	/* Prepare NVRAM for access. */
363543c2aeb0SSepherosa Ziehau 	rc = bce_init_nvram(sc);
363643c2aeb0SSepherosa Ziehau 	if (rc != 0)
363743c2aeb0SSepherosa Ziehau 		return rc;
363843c2aeb0SSepherosa Ziehau 
363943c2aeb0SSepherosa Ziehau 	/* Set the kernel bypass block size */
364043c2aeb0SSepherosa Ziehau 	val = REG_RD(sc, BCE_MQ_CONFIG);
364143c2aeb0SSepherosa Ziehau 	val &= ~BCE_MQ_CONFIG_KNL_BYP_BLK_SIZE;
364243c2aeb0SSepherosa Ziehau 	val |= BCE_MQ_CONFIG_KNL_BYP_BLK_SIZE_256;
3643d0092544SSepherosa Ziehau 
3644d0092544SSepherosa Ziehau 	/* Enable bins used on the 5709/5716. */
3645d0092544SSepherosa Ziehau 	if (BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5709 ||
3646d0092544SSepherosa Ziehau 	    BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5716) {
3647d0092544SSepherosa Ziehau 		val |= BCE_MQ_CONFIG_BIN_MQ_MODE;
3648d0092544SSepherosa Ziehau 		if (BCE_CHIP_ID(sc) == BCE_CHIP_ID_5709_A1)
3649d0092544SSepherosa Ziehau 			val |= BCE_MQ_CONFIG_HALT_DIS;
3650d0092544SSepherosa Ziehau 	}
3651d0092544SSepherosa Ziehau 
365243c2aeb0SSepherosa Ziehau 	REG_WR(sc, BCE_MQ_CONFIG, val);
365343c2aeb0SSepherosa Ziehau 
365443c2aeb0SSepherosa Ziehau 	val = 0x10000 + (MAX_CID_CNT * MB_KERNEL_CTX_SIZE);
365543c2aeb0SSepherosa Ziehau 	REG_WR(sc, BCE_MQ_KNL_BYP_WIND_START, val);
365643c2aeb0SSepherosa Ziehau 	REG_WR(sc, BCE_MQ_KNL_WIND_END, val);
365743c2aeb0SSepherosa Ziehau 
365843c2aeb0SSepherosa Ziehau 	/* Set the page size and clear the RV2P processor stall bits. */
365943c2aeb0SSepherosa Ziehau 	val = (BCM_PAGE_BITS - 8) << 24;
366043c2aeb0SSepherosa Ziehau 	REG_WR(sc, BCE_RV2P_CONFIG, val);
366143c2aeb0SSepherosa Ziehau 
366243c2aeb0SSepherosa Ziehau 	/* Configure page size. */
366343c2aeb0SSepherosa Ziehau 	val = REG_RD(sc, BCE_TBDR_CONFIG);
366443c2aeb0SSepherosa Ziehau 	val &= ~BCE_TBDR_CONFIG_PAGE_SIZE;
366543c2aeb0SSepherosa Ziehau 	val |= (BCM_PAGE_BITS - 8) << 24 | 0x40;
366643c2aeb0SSepherosa Ziehau 	REG_WR(sc, BCE_TBDR_CONFIG, val);
366743c2aeb0SSepherosa Ziehau 
3668d0092544SSepherosa Ziehau 	/* Set the perfect match control register to default. */
3669d0092544SSepherosa Ziehau 	REG_WR_IND(sc, BCE_RXP_PM_CTRL, 0);
3670d0092544SSepherosa Ziehau 
367143c2aeb0SSepherosa Ziehau 	return 0;
367243c2aeb0SSepherosa Ziehau }
367343c2aeb0SSepherosa Ziehau 
367443c2aeb0SSepherosa Ziehau /****************************************************************************/
367543c2aeb0SSepherosa Ziehau /* Initialize the controller in preparation to send/receive traffic.        */
367643c2aeb0SSepherosa Ziehau /*                                                                          */
367743c2aeb0SSepherosa Ziehau /* Returns:                                                                 */
367843c2aeb0SSepherosa Ziehau /*   0 for success, positive value for failure.                             */
367943c2aeb0SSepherosa Ziehau /****************************************************************************/
368043c2aeb0SSepherosa Ziehau static int
bce_blockinit(struct bce_softc * sc)368143c2aeb0SSepherosa Ziehau bce_blockinit(struct bce_softc *sc)
368243c2aeb0SSepherosa Ziehau {
368343c2aeb0SSepherosa Ziehau 	uint32_t reg, val;
3684b42386eeSSepherosa Ziehau 	int i;
368543c2aeb0SSepherosa Ziehau 
368643c2aeb0SSepherosa Ziehau 	/* Load the hardware default MAC address. */
368743c2aeb0SSepherosa Ziehau 	bce_set_mac_addr(sc);
368843c2aeb0SSepherosa Ziehau 
368943c2aeb0SSepherosa Ziehau 	/* Set the Ethernet backoff seed value */
369043c2aeb0SSepherosa Ziehau 	val = sc->eaddr[0] + (sc->eaddr[1] << 8) + (sc->eaddr[2] << 16) +
369143c2aeb0SSepherosa Ziehau 	      sc->eaddr[3] + (sc->eaddr[4] << 8) + (sc->eaddr[5] << 16);
369243c2aeb0SSepherosa Ziehau 	REG_WR(sc, BCE_EMAC_BACKOFF_SEED, val);
369343c2aeb0SSepherosa Ziehau 
369443c2aeb0SSepherosa Ziehau 	sc->rx_mode = BCE_EMAC_RX_MODE_SORT_MODE;
369543c2aeb0SSepherosa Ziehau 
369643c2aeb0SSepherosa Ziehau 	/* Set up link change interrupt generation. */
369743c2aeb0SSepherosa Ziehau 	REG_WR(sc, BCE_EMAC_ATTENTION_ENA, BCE_EMAC_ATTENTION_ENA_LINK);
369843c2aeb0SSepherosa Ziehau 
369943c2aeb0SSepherosa Ziehau 	/* Program the physical address of the status block. */
370043c2aeb0SSepherosa Ziehau 	REG_WR(sc, BCE_HC_STATUS_ADDR_L, BCE_ADDR_LO(sc->status_block_paddr));
370143c2aeb0SSepherosa Ziehau 	REG_WR(sc, BCE_HC_STATUS_ADDR_H, BCE_ADDR_HI(sc->status_block_paddr));
370243c2aeb0SSepherosa Ziehau 
370343c2aeb0SSepherosa Ziehau 	/* Program the physical address of the statistics block. */
370443c2aeb0SSepherosa Ziehau 	REG_WR(sc, BCE_HC_STATISTICS_ADDR_L,
370543c2aeb0SSepherosa Ziehau 	       BCE_ADDR_LO(sc->stats_block_paddr));
370643c2aeb0SSepherosa Ziehau 	REG_WR(sc, BCE_HC_STATISTICS_ADDR_H,
370743c2aeb0SSepherosa Ziehau 	       BCE_ADDR_HI(sc->stats_block_paddr));
370843c2aeb0SSepherosa Ziehau 
370943c2aeb0SSepherosa Ziehau 	/* Program various host coalescing parameters. */
371043c2aeb0SSepherosa Ziehau 	REG_WR(sc, BCE_HC_TX_QUICK_CONS_TRIP,
371143c2aeb0SSepherosa Ziehau 	       (sc->bce_tx_quick_cons_trip_int << 16) |
371243c2aeb0SSepherosa Ziehau 	       sc->bce_tx_quick_cons_trip);
371343c2aeb0SSepherosa Ziehau 	REG_WR(sc, BCE_HC_RX_QUICK_CONS_TRIP,
371443c2aeb0SSepherosa Ziehau 	       (sc->bce_rx_quick_cons_trip_int << 16) |
371543c2aeb0SSepherosa Ziehau 	       sc->bce_rx_quick_cons_trip);
371643c2aeb0SSepherosa Ziehau 	REG_WR(sc, BCE_HC_COMP_PROD_TRIP,
371743c2aeb0SSepherosa Ziehau 	       (sc->bce_comp_prod_trip_int << 16) | sc->bce_comp_prod_trip);
371843c2aeb0SSepherosa Ziehau 	REG_WR(sc, BCE_HC_TX_TICKS,
371943c2aeb0SSepherosa Ziehau 	       (sc->bce_tx_ticks_int << 16) | sc->bce_tx_ticks);
372043c2aeb0SSepherosa Ziehau 	REG_WR(sc, BCE_HC_RX_TICKS,
372143c2aeb0SSepherosa Ziehau 	       (sc->bce_rx_ticks_int << 16) | sc->bce_rx_ticks);
372243c2aeb0SSepherosa Ziehau 	REG_WR(sc, BCE_HC_COM_TICKS,
372343c2aeb0SSepherosa Ziehau 	       (sc->bce_com_ticks_int << 16) | sc->bce_com_ticks);
372443c2aeb0SSepherosa Ziehau 	REG_WR(sc, BCE_HC_CMD_TICKS,
372543c2aeb0SSepherosa Ziehau 	       (sc->bce_cmd_ticks_int << 16) | sc->bce_cmd_ticks);
372643c2aeb0SSepherosa Ziehau 	REG_WR(sc, BCE_HC_STATS_TICKS, (sc->bce_stats_ticks & 0xffff00));
372743c2aeb0SSepherosa Ziehau 	REG_WR(sc, BCE_HC_STAT_COLLECT_TICKS, 0xbb8);	/* 3ms */
3728eac57ffbSSepherosa Ziehau 
3729b42386eeSSepherosa Ziehau 	if (sc->bce_irq_type == PCI_INTR_TYPE_MSIX)
3730b42386eeSSepherosa Ziehau 		REG_WR(sc, BCE_HC_MSIX_BIT_VECTOR, BCE_HC_MSIX_BIT_VECTOR_VAL);
3731b42386eeSSepherosa Ziehau 
3732eac57ffbSSepherosa Ziehau 	val = BCE_HC_CONFIG_TX_TMR_MODE | BCE_HC_CONFIG_COLLECT_STATS;
3733b42386eeSSepherosa Ziehau 	if ((sc->bce_flags & BCE_ONESHOT_MSI_FLAG) ||
3734b42386eeSSepherosa Ziehau 	    sc->bce_irq_type == PCI_INTR_TYPE_MSIX) {
3735b42386eeSSepherosa Ziehau 		if (bootverbose) {
3736b42386eeSSepherosa Ziehau 			if (sc->bce_irq_type == PCI_INTR_TYPE_MSIX) {
3737b42386eeSSepherosa Ziehau 				if_printf(&sc->arpcom.ac_if,
3738b42386eeSSepherosa Ziehau 				    "using MSI-X\n");
3739b42386eeSSepherosa Ziehau 			} else {
3740b42386eeSSepherosa Ziehau 				if_printf(&sc->arpcom.ac_if,
3741b42386eeSSepherosa Ziehau 				    "using oneshot MSI\n");
3742b42386eeSSepherosa Ziehau 			}
3743b42386eeSSepherosa Ziehau 		}
3744eac57ffbSSepherosa Ziehau 		val |= BCE_HC_CONFIG_ONE_SHOT | BCE_HC_CONFIG_USE_INT_PARAM;
3745b42386eeSSepherosa Ziehau 		if (sc->bce_irq_type == PCI_INTR_TYPE_MSIX)
3746b42386eeSSepherosa Ziehau 			val |= BCE_HC_CONFIG_SB_ADDR_INC_128B;
3747eac57ffbSSepherosa Ziehau 	}
3748eac57ffbSSepherosa Ziehau 	REG_WR(sc, BCE_HC_CONFIG, val);
374943c2aeb0SSepherosa Ziehau 
3750b42386eeSSepherosa Ziehau 	for (i = 1; i < sc->rx_ring_cnt; ++i) {
3751b42386eeSSepherosa Ziehau 		uint32_t base;
3752b42386eeSSepherosa Ziehau 
3753b42386eeSSepherosa Ziehau 		base = ((i - 1) * BCE_HC_SB_CONFIG_SIZE) + BCE_HC_SB_CONFIG_1;
3754b42386eeSSepherosa Ziehau 		KKASSERT(base <= BCE_HC_SB_CONFIG_8);
3755b42386eeSSepherosa Ziehau 
3756b42386eeSSepherosa Ziehau 		REG_WR(sc, base,
3757b42386eeSSepherosa Ziehau 		    BCE_HC_SB_CONFIG_1_TX_TMR_MODE |
3758b42386eeSSepherosa Ziehau 		    /* BCE_HC_SB_CONFIG_1_RX_TMR_MODE | */
3759b42386eeSSepherosa Ziehau 		    BCE_HC_SB_CONFIG_1_ONE_SHOT);
3760b42386eeSSepherosa Ziehau 
3761b42386eeSSepherosa Ziehau 		REG_WR(sc, base + BCE_HC_TX_QUICK_CONS_TRIP_OFF,
3762b42386eeSSepherosa Ziehau 		    (sc->bce_tx_quick_cons_trip_int << 16) |
3763b42386eeSSepherosa Ziehau 		    sc->bce_tx_quick_cons_trip);
3764b42386eeSSepherosa Ziehau 		REG_WR(sc, base + BCE_HC_RX_QUICK_CONS_TRIP_OFF,
3765b42386eeSSepherosa Ziehau 		    (sc->bce_rx_quick_cons_trip_int << 16) |
3766b42386eeSSepherosa Ziehau 		    sc->bce_rx_quick_cons_trip);
3767b42386eeSSepherosa Ziehau 		REG_WR(sc, base + BCE_HC_TX_TICKS_OFF,
3768b42386eeSSepherosa Ziehau 		    (sc->bce_tx_ticks_int << 16) | sc->bce_tx_ticks);
3769b42386eeSSepherosa Ziehau 		REG_WR(sc, base + BCE_HC_RX_TICKS_OFF,
3770b42386eeSSepherosa Ziehau 		    (sc->bce_rx_ticks_int << 16) | sc->bce_rx_ticks);
3771b42386eeSSepherosa Ziehau 	}
3772b42386eeSSepherosa Ziehau 
377343c2aeb0SSepherosa Ziehau 	/* Clear the internal statistics counters. */
377443c2aeb0SSepherosa Ziehau 	REG_WR(sc, BCE_HC_COMMAND, BCE_HC_COMMAND_CLR_STAT_NOW);
377543c2aeb0SSepherosa Ziehau 
377643c2aeb0SSepherosa Ziehau 	/* Verify that bootcode is running. */
3777bc30d40dSSepherosa Ziehau 	reg = bce_shmem_rd(sc, BCE_DEV_INFO_SIGNATURE);
377843c2aeb0SSepherosa Ziehau 
377943c2aeb0SSepherosa Ziehau 	if ((reg & BCE_DEV_INFO_SIGNATURE_MAGIC_MASK) !=
378043c2aeb0SSepherosa Ziehau 	    BCE_DEV_INFO_SIGNATURE_MAGIC) {
378143c2aeb0SSepherosa Ziehau 		if_printf(&sc->arpcom.ac_if,
378243c2aeb0SSepherosa Ziehau 			  "Bootcode not running! Found: 0x%08X, "
378343c2aeb0SSepherosa Ziehau 			  "Expected: 08%08X\n",
378443c2aeb0SSepherosa Ziehau 			  reg & BCE_DEV_INFO_SIGNATURE_MAGIC_MASK,
378543c2aeb0SSepherosa Ziehau 			  BCE_DEV_INFO_SIGNATURE_MAGIC);
378643c2aeb0SSepherosa Ziehau 		return ENODEV;
378743c2aeb0SSepherosa Ziehau 	}
378843c2aeb0SSepherosa Ziehau 
3789d0092544SSepherosa Ziehau 	/* Enable DMA */
3790d0092544SSepherosa Ziehau 	if (BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5709 ||
3791d0092544SSepherosa Ziehau 	    BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5716) {
3792d0092544SSepherosa Ziehau 		val = REG_RD(sc, BCE_MISC_NEW_CORE_CTL);
3793d0092544SSepherosa Ziehau 		val |= BCE_MISC_NEW_CORE_CTL_DMA_ENABLE;
3794d0092544SSepherosa Ziehau 		REG_WR(sc, BCE_MISC_NEW_CORE_CTL, val);
379543c2aeb0SSepherosa Ziehau 	}
379643c2aeb0SSepherosa Ziehau 
379743c2aeb0SSepherosa Ziehau 	/* Allow bootcode to apply any additional fixes before enabling MAC. */
3798805eb96fSSepherosa Ziehau 	bce_fw_sync(sc, BCE_DRV_MSG_DATA_WAIT2 | BCE_DRV_MSG_CODE_RESET);
379943c2aeb0SSepherosa Ziehau 
380043c2aeb0SSepherosa Ziehau 	/* Enable link state change interrupt generation. */
380143c2aeb0SSepherosa Ziehau 	REG_WR(sc, BCE_HC_ATTN_BITS_ENABLE, STATUS_ATTN_BITS_LINK_STATE);
380243c2aeb0SSepherosa Ziehau 
38035d05a208SSepherosa Ziehau 	/* Enable the RXP. */
38045d05a208SSepherosa Ziehau 	bce_start_rxp_cpu(sc);
38055d05a208SSepherosa Ziehau 
38065d05a208SSepherosa Ziehau 	/* Disable management frames (NC-SI) from flowing to the MCP. */
38075d05a208SSepherosa Ziehau 	if (sc->bce_flags & BCE_MFW_ENABLE_FLAG) {
38085d05a208SSepherosa Ziehau 		val = REG_RD(sc, BCE_RPM_MGMT_PKT_CTRL) &
38095d05a208SSepherosa Ziehau 		    ~BCE_RPM_MGMT_PKT_CTRL_MGMT_EN;
38105d05a208SSepherosa Ziehau 		REG_WR(sc, BCE_RPM_MGMT_PKT_CTRL, val);
38115d05a208SSepherosa Ziehau 	}
38125d05a208SSepherosa Ziehau 
381343c2aeb0SSepherosa Ziehau 	/* Enable all remaining blocks in the MAC. */
3814d0092544SSepherosa Ziehau 	if (BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5709 ||
3815d0092544SSepherosa Ziehau 	    BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5716) {
3816d0092544SSepherosa Ziehau 		REG_WR(sc, BCE_MISC_ENABLE_SET_BITS,
3817d0092544SSepherosa Ziehau 		    BCE_MISC_ENABLE_DEFAULT_XI);
3818d0092544SSepherosa Ziehau 	} else {
3819d0092544SSepherosa Ziehau 		REG_WR(sc, BCE_MISC_ENABLE_SET_BITS, BCE_MISC_ENABLE_DEFAULT);
3820d0092544SSepherosa Ziehau 	}
382143c2aeb0SSepherosa Ziehau 	REG_RD(sc, BCE_MISC_ENABLE_SET_BITS);
382243c2aeb0SSepherosa Ziehau 	DELAY(20);
382343c2aeb0SSepherosa Ziehau 
3824d0092544SSepherosa Ziehau 	/* Save the current host coalescing block settings. */
3825d0092544SSepherosa Ziehau 	sc->hc_command = REG_RD(sc, BCE_HC_COMMAND);
3826d0092544SSepherosa Ziehau 
382743c2aeb0SSepherosa Ziehau 	return 0;
382843c2aeb0SSepherosa Ziehau }
382943c2aeb0SSepherosa Ziehau 
383043c2aeb0SSepherosa Ziehau /****************************************************************************/
383143c2aeb0SSepherosa Ziehau /* Encapsulate an mbuf cluster into the rx_bd chain.                        */
383243c2aeb0SSepherosa Ziehau /*                                                                          */
383343c2aeb0SSepherosa Ziehau /* The NetXtreme II can support Jumbo frames by using multiple rx_bd's.     */
383443c2aeb0SSepherosa Ziehau /* This routine will map an mbuf cluster into 1 or more rx_bd's as          */
383543c2aeb0SSepherosa Ziehau /* necessary.                                                               */
383643c2aeb0SSepherosa Ziehau /*                                                                          */
383743c2aeb0SSepherosa Ziehau /* Returns:                                                                 */
383843c2aeb0SSepherosa Ziehau /*   0 for success, positive value for failure.                             */
383943c2aeb0SSepherosa Ziehau /****************************************************************************/
384043c2aeb0SSepherosa Ziehau static int
bce_newbuf_std(struct bce_rx_ring * rxr,uint16_t * prod,uint16_t chain_prod,uint32_t * prod_bseq,int init)384186ae632dSSepherosa Ziehau bce_newbuf_std(struct bce_rx_ring *rxr, uint16_t *prod, uint16_t chain_prod,
3842c36fd9eeSSepherosa Ziehau     uint32_t *prod_bseq, int init)
384343c2aeb0SSepherosa Ziehau {
384486ae632dSSepherosa Ziehau 	struct bce_rx_buf *rx_buf;
384543c2aeb0SSepherosa Ziehau 	bus_dmamap_t map;
384643c2aeb0SSepherosa Ziehau 	bus_dma_segment_t seg;
384743c2aeb0SSepherosa Ziehau 	struct mbuf *m_new;
3848c36fd9eeSSepherosa Ziehau 	int error, nseg;
384943c2aeb0SSepherosa Ziehau 
385043c2aeb0SSepherosa Ziehau 	/* This is a new mbuf allocation. */
3851b5523eacSSascha Wildner 	m_new = m_getcl(init ? M_WAITOK : M_NOWAIT, MT_DATA, M_PKTHDR);
385243c2aeb0SSepherosa Ziehau 	if (m_new == NULL)
385343c2aeb0SSepherosa Ziehau 		return ENOBUFS;
3854c36fd9eeSSepherosa Ziehau 
385543c2aeb0SSepherosa Ziehau 	m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
385643c2aeb0SSepherosa Ziehau 
385743c2aeb0SSepherosa Ziehau 	/* Map the mbuf cluster into device memory. */
385808b64767SSepherosa Ziehau 	error = bus_dmamap_load_mbuf_segment(rxr->rx_mbuf_tag,
385908b64767SSepherosa Ziehau 	    rxr->rx_mbuf_tmpmap, m_new, &seg, 1, &nseg, BUS_DMA_NOWAIT);
3860c36fd9eeSSepherosa Ziehau 	if (error) {
3861c36fd9eeSSepherosa Ziehau 		m_freem(m_new);
3862c36fd9eeSSepherosa Ziehau 		if (init) {
386308b64767SSepherosa Ziehau 			if_printf(&rxr->sc->arpcom.ac_if,
386443c2aeb0SSepherosa Ziehau 			    "Error mapping mbuf into RX chain!\n");
386543c2aeb0SSepherosa Ziehau 		}
3866c36fd9eeSSepherosa Ziehau 		return error;
3867c36fd9eeSSepherosa Ziehau 	}
3868c36fd9eeSSepherosa Ziehau 
386986ae632dSSepherosa Ziehau 	rx_buf = &rxr->rx_bufs[chain_prod];
387086ae632dSSepherosa Ziehau 	if (rx_buf->rx_mbuf_ptr != NULL)
387186ae632dSSepherosa Ziehau 		bus_dmamap_unload(rxr->rx_mbuf_tag, rx_buf->rx_mbuf_map);
3872c36fd9eeSSepherosa Ziehau 
387386ae632dSSepherosa Ziehau 	map = rx_buf->rx_mbuf_map;
387486ae632dSSepherosa Ziehau 	rx_buf->rx_mbuf_map = rxr->rx_mbuf_tmpmap;
387508b64767SSepherosa Ziehau 	rxr->rx_mbuf_tmpmap = map;
387643c2aeb0SSepherosa Ziehau 
387743c2aeb0SSepherosa Ziehau 	/* Save the mbuf and update our counter. */
387886ae632dSSepherosa Ziehau 	rx_buf->rx_mbuf_ptr = m_new;
387986ae632dSSepherosa Ziehau 	rx_buf->rx_mbuf_paddr = seg.ds_addr;
388008b64767SSepherosa Ziehau 	rxr->free_rx_bd--;
388143c2aeb0SSepherosa Ziehau 
388286ae632dSSepherosa Ziehau 	bce_setup_rxdesc_std(rxr, chain_prod, prod_bseq);
3883314a2fccSSepherosa Ziehau 
388443c2aeb0SSepherosa Ziehau 	return 0;
388543c2aeb0SSepherosa Ziehau }
388643c2aeb0SSepherosa Ziehau 
3887314a2fccSSepherosa Ziehau static void
bce_setup_rxdesc_std(struct bce_rx_ring * rxr,uint16_t chain_prod,uint32_t * prod_bseq)388808b64767SSepherosa Ziehau bce_setup_rxdesc_std(struct bce_rx_ring *rxr, uint16_t chain_prod,
388908b64767SSepherosa Ziehau     uint32_t *prod_bseq)
3890314a2fccSSepherosa Ziehau {
389186ae632dSSepherosa Ziehau 	const struct bce_rx_buf *rx_buf;
3892314a2fccSSepherosa Ziehau 	struct rx_bd *rxbd;
3893314a2fccSSepherosa Ziehau 	bus_addr_t paddr;
3894314a2fccSSepherosa Ziehau 	int len;
3895314a2fccSSepherosa Ziehau 
389686ae632dSSepherosa Ziehau 	rx_buf = &rxr->rx_bufs[chain_prod];
389786ae632dSSepherosa Ziehau 	paddr = rx_buf->rx_mbuf_paddr;
389886ae632dSSepherosa Ziehau 	len = rx_buf->rx_mbuf_ptr->m_len;
3899314a2fccSSepherosa Ziehau 
3900314a2fccSSepherosa Ziehau 	/* Setup the rx_bd for the first segment. */
390108b64767SSepherosa Ziehau 	rxbd = &rxr->rx_bd_chain[RX_PAGE(chain_prod)][RX_IDX(chain_prod)];
3902314a2fccSSepherosa Ziehau 
3903314a2fccSSepherosa Ziehau 	rxbd->rx_bd_haddr_lo = htole32(BCE_ADDR_LO(paddr));
3904314a2fccSSepherosa Ziehau 	rxbd->rx_bd_haddr_hi = htole32(BCE_ADDR_HI(paddr));
3905314a2fccSSepherosa Ziehau 	rxbd->rx_bd_len = htole32(len);
3906314a2fccSSepherosa Ziehau 	rxbd->rx_bd_flags = htole32(RX_BD_FLAGS_START);
3907314a2fccSSepherosa Ziehau 	*prod_bseq += len;
3908314a2fccSSepherosa Ziehau 
3909314a2fccSSepherosa Ziehau 	rxbd->rx_bd_flags |= htole32(RX_BD_FLAGS_END);
3910314a2fccSSepherosa Ziehau }
3911314a2fccSSepherosa Ziehau 
391243c2aeb0SSepherosa Ziehau /****************************************************************************/
3913d0092544SSepherosa Ziehau /* Initialize the TX context memory.                                        */
3914d0092544SSepherosa Ziehau /*                                                                          */
3915d0092544SSepherosa Ziehau /* Returns:                                                                 */
3916d0092544SSepherosa Ziehau /*   Nothing                                                                */
3917d0092544SSepherosa Ziehau /****************************************************************************/
3918d0092544SSepherosa Ziehau static void
bce_init_tx_context(struct bce_tx_ring * txr)391910bcbdabSSepherosa Ziehau bce_init_tx_context(struct bce_tx_ring *txr)
3920d0092544SSepherosa Ziehau {
3921d0092544SSepherosa Ziehau 	uint32_t val;
3922d0092544SSepherosa Ziehau 
3923d0092544SSepherosa Ziehau 	/* Initialize the context ID for an L2 TX chain. */
392410bcbdabSSepherosa Ziehau 	if (BCE_CHIP_NUM(txr->sc) == BCE_CHIP_NUM_5709 ||
392510bcbdabSSepherosa Ziehau 	    BCE_CHIP_NUM(txr->sc) == BCE_CHIP_NUM_5716) {
3926d0092544SSepherosa Ziehau 		/* Set the CID type to support an L2 connection. */
3927d0092544SSepherosa Ziehau 		val = BCE_L2CTX_TX_TYPE_TYPE_L2 | BCE_L2CTX_TX_TYPE_SIZE_L2;
39280080c09fSSepherosa Ziehau 		CTX_WR(txr->sc, GET_CID_ADDR(txr->tx_cid),
392910bcbdabSSepherosa Ziehau 		    BCE_L2CTX_TX_TYPE_XI, val);
3930d0092544SSepherosa Ziehau 		val = BCE_L2CTX_TX_CMD_TYPE_TYPE_L2 | (8 << 16);
39310080c09fSSepherosa Ziehau 		CTX_WR(txr->sc, GET_CID_ADDR(txr->tx_cid),
393210bcbdabSSepherosa Ziehau 		    BCE_L2CTX_TX_CMD_TYPE_XI, val);
3933d0092544SSepherosa Ziehau 
3934d0092544SSepherosa Ziehau 		/* Point the hardware to the first page in the chain. */
393510bcbdabSSepherosa Ziehau 		val = BCE_ADDR_HI(txr->tx_bd_chain_paddr[0]);
39360080c09fSSepherosa Ziehau 		CTX_WR(txr->sc, GET_CID_ADDR(txr->tx_cid),
3937d0092544SSepherosa Ziehau 		    BCE_L2CTX_TX_TBDR_BHADDR_HI_XI, val);
393810bcbdabSSepherosa Ziehau 		val = BCE_ADDR_LO(txr->tx_bd_chain_paddr[0]);
39390080c09fSSepherosa Ziehau 		CTX_WR(txr->sc, GET_CID_ADDR(txr->tx_cid),
3940d0092544SSepherosa Ziehau 		    BCE_L2CTX_TX_TBDR_BHADDR_LO_XI, val);
3941d0092544SSepherosa Ziehau 	} else {
3942d0092544SSepherosa Ziehau 		/* Set the CID type to support an L2 connection. */
3943d0092544SSepherosa Ziehau 		val = BCE_L2CTX_TX_TYPE_TYPE_L2 | BCE_L2CTX_TX_TYPE_SIZE_L2;
39440080c09fSSepherosa Ziehau 		CTX_WR(txr->sc, GET_CID_ADDR(txr->tx_cid),
39450080c09fSSepherosa Ziehau 		    BCE_L2CTX_TX_TYPE, val);
3946d0092544SSepherosa Ziehau 		val = BCE_L2CTX_TX_CMD_TYPE_TYPE_L2 | (8 << 16);
39470080c09fSSepherosa Ziehau 		CTX_WR(txr->sc, GET_CID_ADDR(txr->tx_cid),
394810bcbdabSSepherosa Ziehau 		    BCE_L2CTX_TX_CMD_TYPE, val);
3949d0092544SSepherosa Ziehau 
3950d0092544SSepherosa Ziehau 		/* Point the hardware to the first page in the chain. */
395110bcbdabSSepherosa Ziehau 		val = BCE_ADDR_HI(txr->tx_bd_chain_paddr[0]);
39520080c09fSSepherosa Ziehau 		CTX_WR(txr->sc, GET_CID_ADDR(txr->tx_cid),
3953d0092544SSepherosa Ziehau 		    BCE_L2CTX_TX_TBDR_BHADDR_HI, val);
395410bcbdabSSepherosa Ziehau 		val = BCE_ADDR_LO(txr->tx_bd_chain_paddr[0]);
39550080c09fSSepherosa Ziehau 		CTX_WR(txr->sc, GET_CID_ADDR(txr->tx_cid),
3956d0092544SSepherosa Ziehau 		    BCE_L2CTX_TX_TBDR_BHADDR_LO, val);
3957d0092544SSepherosa Ziehau 	}
3958d0092544SSepherosa Ziehau }
3959d0092544SSepherosa Ziehau 
3960d0092544SSepherosa Ziehau /****************************************************************************/
396143c2aeb0SSepherosa Ziehau /* Allocate memory and initialize the TX data structures.                   */
396243c2aeb0SSepherosa Ziehau /*                                                                          */
396343c2aeb0SSepherosa Ziehau /* Returns:                                                                 */
396443c2aeb0SSepherosa Ziehau /*   0 for success, positive value for failure.                             */
396543c2aeb0SSepherosa Ziehau /****************************************************************************/
396643c2aeb0SSepherosa Ziehau static int
bce_init_tx_chain(struct bce_tx_ring * txr)396710bcbdabSSepherosa Ziehau bce_init_tx_chain(struct bce_tx_ring *txr)
396843c2aeb0SSepherosa Ziehau {
396943c2aeb0SSepherosa Ziehau 	struct tx_bd *txbd;
397043c2aeb0SSepherosa Ziehau 	int i, rc = 0;
397143c2aeb0SSepherosa Ziehau 
397243c2aeb0SSepherosa Ziehau 	/* Set the initial TX producer/consumer indices. */
397310bcbdabSSepherosa Ziehau 	txr->tx_prod = 0;
397410bcbdabSSepherosa Ziehau 	txr->tx_cons = 0;
397510bcbdabSSepherosa Ziehau 	txr->tx_prod_bseq = 0;
397610bcbdabSSepherosa Ziehau 	txr->used_tx_bd = 0;
397710bcbdabSSepherosa Ziehau 	txr->max_tx_bd = USABLE_TX_BD(txr);
397843c2aeb0SSepherosa Ziehau 
397943c2aeb0SSepherosa Ziehau 	/*
398043c2aeb0SSepherosa Ziehau 	 * The NetXtreme II supports a linked-list structre called
398143c2aeb0SSepherosa Ziehau 	 * a Buffer Descriptor Chain (or BD chain).  A BD chain
398243c2aeb0SSepherosa Ziehau 	 * consists of a series of 1 or more chain pages, each of which
398343c2aeb0SSepherosa Ziehau 	 * consists of a fixed number of BD entries.
398443c2aeb0SSepherosa Ziehau 	 * The last BD entry on each page is a pointer to the next page
398543c2aeb0SSepherosa Ziehau 	 * in the chain, and the last pointer in the BD chain
398643c2aeb0SSepherosa Ziehau 	 * points back to the beginning of the chain.
398743c2aeb0SSepherosa Ziehau 	 */
398843c2aeb0SSepherosa Ziehau 
398943c2aeb0SSepherosa Ziehau 	/* Set the TX next pointer chain entries. */
399010bcbdabSSepherosa Ziehau 	for (i = 0; i < txr->tx_pages; i++) {
399143c2aeb0SSepherosa Ziehau 		int j;
399243c2aeb0SSepherosa Ziehau 
399310bcbdabSSepherosa Ziehau 		txbd = &txr->tx_bd_chain[i][USABLE_TX_BD_PER_PAGE];
399443c2aeb0SSepherosa Ziehau 
399543c2aeb0SSepherosa Ziehau 		/* Check if we've reached the last page. */
399610bcbdabSSepherosa Ziehau 		if (i == (txr->tx_pages - 1))
399743c2aeb0SSepherosa Ziehau 			j = 0;
399843c2aeb0SSepherosa Ziehau 		else
399943c2aeb0SSepherosa Ziehau 			j = i + 1;
400043c2aeb0SSepherosa Ziehau 
400143c2aeb0SSepherosa Ziehau 		txbd->tx_bd_haddr_hi =
400210bcbdabSSepherosa Ziehau 		    htole32(BCE_ADDR_HI(txr->tx_bd_chain_paddr[j]));
400343c2aeb0SSepherosa Ziehau 		txbd->tx_bd_haddr_lo =
400410bcbdabSSepherosa Ziehau 		    htole32(BCE_ADDR_LO(txr->tx_bd_chain_paddr[j]));
400543c2aeb0SSepherosa Ziehau 	}
400610bcbdabSSepherosa Ziehau 	bce_init_tx_context(txr);
400743c2aeb0SSepherosa Ziehau 
400843c2aeb0SSepherosa Ziehau 	return(rc);
400943c2aeb0SSepherosa Ziehau }
401043c2aeb0SSepherosa Ziehau 
401143c2aeb0SSepherosa Ziehau /****************************************************************************/
401243c2aeb0SSepherosa Ziehau /* Free memory and clear the TX data structures.                            */
401343c2aeb0SSepherosa Ziehau /*                                                                          */
401443c2aeb0SSepherosa Ziehau /* Returns:                                                                 */
401543c2aeb0SSepherosa Ziehau /*   Nothing.                                                               */
401643c2aeb0SSepherosa Ziehau /****************************************************************************/
401743c2aeb0SSepherosa Ziehau static void
bce_free_tx_chain(struct bce_tx_ring * txr)401810bcbdabSSepherosa Ziehau bce_free_tx_chain(struct bce_tx_ring *txr)
401943c2aeb0SSepherosa Ziehau {
402043c2aeb0SSepherosa Ziehau 	int i;
402143c2aeb0SSepherosa Ziehau 
402243c2aeb0SSepherosa Ziehau 	/* Unmap, unload, and free any mbufs still in the TX mbuf chain. */
402310bcbdabSSepherosa Ziehau 	for (i = 0; i < TOTAL_TX_BD(txr); i++) {
402486ae632dSSepherosa Ziehau 		struct bce_tx_buf *tx_buf = &txr->tx_bufs[i];
402586ae632dSSepherosa Ziehau 
402686ae632dSSepherosa Ziehau 		if (tx_buf->tx_mbuf_ptr != NULL) {
402710bcbdabSSepherosa Ziehau 			bus_dmamap_unload(txr->tx_mbuf_tag,
402886ae632dSSepherosa Ziehau 			    tx_buf->tx_mbuf_map);
402986ae632dSSepherosa Ziehau 			m_freem(tx_buf->tx_mbuf_ptr);
403086ae632dSSepherosa Ziehau 			tx_buf->tx_mbuf_ptr = NULL;
403143c2aeb0SSepherosa Ziehau 		}
403243c2aeb0SSepherosa Ziehau 	}
403343c2aeb0SSepherosa Ziehau 
403443c2aeb0SSepherosa Ziehau 	/* Clear each TX chain page. */
403510bcbdabSSepherosa Ziehau 	for (i = 0; i < txr->tx_pages; i++)
403610bcbdabSSepherosa Ziehau 		bzero(txr->tx_bd_chain[i], BCE_TX_CHAIN_PAGE_SZ);
403710bcbdabSSepherosa Ziehau 	txr->used_tx_bd = 0;
403843c2aeb0SSepherosa Ziehau }
403943c2aeb0SSepherosa Ziehau 
404043c2aeb0SSepherosa Ziehau /****************************************************************************/
4041d0092544SSepherosa Ziehau /* Initialize the RX context memory.                                        */
4042d0092544SSepherosa Ziehau /*                                                                          */
4043d0092544SSepherosa Ziehau /* Returns:                                                                 */
4044d0092544SSepherosa Ziehau /*   Nothing                                                                */
4045d0092544SSepherosa Ziehau /****************************************************************************/
4046d0092544SSepherosa Ziehau static void
bce_init_rx_context(struct bce_rx_ring * rxr)404708b64767SSepherosa Ziehau bce_init_rx_context(struct bce_rx_ring *rxr)
4048d0092544SSepherosa Ziehau {
4049d0092544SSepherosa Ziehau 	uint32_t val;
4050d0092544SSepherosa Ziehau 
4051d0092544SSepherosa Ziehau 	/* Initialize the context ID for an L2 RX chain. */
4052d0092544SSepherosa Ziehau 	val = BCE_L2CTX_RX_CTX_TYPE_CTX_BD_CHN_TYPE_VALUE |
4053d0092544SSepherosa Ziehau 	    BCE_L2CTX_RX_CTX_TYPE_SIZE_L2 | (0x02 << 8);
4054d0092544SSepherosa Ziehau 
4055d0092544SSepherosa Ziehau 	/*
4056d0092544SSepherosa Ziehau 	 * Set the level for generating pause frames
4057d0092544SSepherosa Ziehau 	 * when the number of available rx_bd's gets
4058d0092544SSepherosa Ziehau 	 * too low (the low watermark) and the level
4059d0092544SSepherosa Ziehau 	 * when pause frames can be stopped (the high
4060d0092544SSepherosa Ziehau 	 * watermark).
4061d0092544SSepherosa Ziehau 	 */
406208b64767SSepherosa Ziehau 	if (BCE_CHIP_NUM(rxr->sc) == BCE_CHIP_NUM_5709 ||
406308b64767SSepherosa Ziehau 	    BCE_CHIP_NUM(rxr->sc) == BCE_CHIP_NUM_5716) {
4064d0092544SSepherosa Ziehau 		uint32_t lo_water, hi_water;
4065d0092544SSepherosa Ziehau 
4066d0092544SSepherosa Ziehau 		lo_water = BCE_L2CTX_RX_LO_WATER_MARK_DEFAULT;
406708b64767SSepherosa Ziehau 		hi_water = USABLE_RX_BD(rxr) / 4;
4068d0092544SSepherosa Ziehau 
4069d0092544SSepherosa Ziehau 		lo_water /= BCE_L2CTX_RX_LO_WATER_MARK_SCALE;
4070d0092544SSepherosa Ziehau 		hi_water /= BCE_L2CTX_RX_HI_WATER_MARK_SCALE;
4071d0092544SSepherosa Ziehau 
4072d0092544SSepherosa Ziehau 		if (hi_water > 0xf)
4073d0092544SSepherosa Ziehau 			hi_water = 0xf;
4074d0092544SSepherosa Ziehau 		else if (hi_water == 0)
4075d0092544SSepherosa Ziehau 			lo_water = 0;
4076d0092544SSepherosa Ziehau 		val |= lo_water |
4077d0092544SSepherosa Ziehau 		    (hi_water << BCE_L2CTX_RX_HI_WATER_MARK_SHIFT);
4078d0092544SSepherosa Ziehau 	}
4079d0092544SSepherosa Ziehau 
40800080c09fSSepherosa Ziehau  	CTX_WR(rxr->sc, GET_CID_ADDR(rxr->rx_cid),
40810080c09fSSepherosa Ziehau 	    BCE_L2CTX_RX_CTX_TYPE, val);
4082d0092544SSepherosa Ziehau 
4083d0092544SSepherosa Ziehau 	/* Setup the MQ BIN mapping for l2_ctx_host_bseq. */
408408b64767SSepherosa Ziehau 	if (BCE_CHIP_NUM(rxr->sc) == BCE_CHIP_NUM_5709 ||
408508b64767SSepherosa Ziehau 	    BCE_CHIP_NUM(rxr->sc) == BCE_CHIP_NUM_5716) {
408608b64767SSepherosa Ziehau 		val = REG_RD(rxr->sc, BCE_MQ_MAP_L2_5);
408708b64767SSepherosa Ziehau 		REG_WR(rxr->sc, BCE_MQ_MAP_L2_5, val | BCE_MQ_MAP_L2_5_ARM);
4088d0092544SSepherosa Ziehau 	}
4089d0092544SSepherosa Ziehau 
4090d0092544SSepherosa Ziehau 	/* Point the hardware to the first page in the chain. */
409108b64767SSepherosa Ziehau 	val = BCE_ADDR_HI(rxr->rx_bd_chain_paddr[0]);
40920080c09fSSepherosa Ziehau 	CTX_WR(rxr->sc, GET_CID_ADDR(rxr->rx_cid),
40930080c09fSSepherosa Ziehau 	    BCE_L2CTX_RX_NX_BDHADDR_HI, val);
409408b64767SSepherosa Ziehau 	val = BCE_ADDR_LO(rxr->rx_bd_chain_paddr[0]);
40950080c09fSSepherosa Ziehau 	CTX_WR(rxr->sc, GET_CID_ADDR(rxr->rx_cid),
40960080c09fSSepherosa Ziehau 	    BCE_L2CTX_RX_NX_BDHADDR_LO, val);
4097d0092544SSepherosa Ziehau }
4098d0092544SSepherosa Ziehau 
4099d0092544SSepherosa Ziehau /****************************************************************************/
410043c2aeb0SSepherosa Ziehau /* Allocate memory and initialize the RX data structures.                   */
410143c2aeb0SSepherosa Ziehau /*                                                                          */
410243c2aeb0SSepherosa Ziehau /* Returns:                                                                 */
410343c2aeb0SSepherosa Ziehau /*   0 for success, positive value for failure.                             */
410443c2aeb0SSepherosa Ziehau /****************************************************************************/
410543c2aeb0SSepherosa Ziehau static int
bce_init_rx_chain(struct bce_rx_ring * rxr)410608b64767SSepherosa Ziehau bce_init_rx_chain(struct bce_rx_ring *rxr)
410743c2aeb0SSepherosa Ziehau {
410843c2aeb0SSepherosa Ziehau 	struct rx_bd *rxbd;
410943c2aeb0SSepherosa Ziehau 	int i, rc = 0;
411043c2aeb0SSepherosa Ziehau 	uint16_t prod, chain_prod;
4111d0092544SSepherosa Ziehau 	uint32_t prod_bseq;
411243c2aeb0SSepherosa Ziehau 
411343c2aeb0SSepherosa Ziehau 	/* Initialize the RX producer and consumer indices. */
411408b64767SSepherosa Ziehau 	rxr->rx_prod = 0;
411508b64767SSepherosa Ziehau 	rxr->rx_cons = 0;
411608b64767SSepherosa Ziehau 	rxr->rx_prod_bseq = 0;
411708b64767SSepherosa Ziehau 	rxr->free_rx_bd = USABLE_RX_BD(rxr);
411808b64767SSepherosa Ziehau 	rxr->max_rx_bd = USABLE_RX_BD(rxr);
411943c2aeb0SSepherosa Ziehau 
4120ba268ba5SSepherosa Ziehau 	/* Clear cache status index */
4121ba268ba5SSepherosa Ziehau 	rxr->last_status_idx = 0;
4122ba268ba5SSepherosa Ziehau 
412343c2aeb0SSepherosa Ziehau 	/* Initialize the RX next pointer chain entries. */
412408b64767SSepherosa Ziehau 	for (i = 0; i < rxr->rx_pages; i++) {
412543c2aeb0SSepherosa Ziehau 		int j;
412643c2aeb0SSepherosa Ziehau 
412708b64767SSepherosa Ziehau 		rxbd = &rxr->rx_bd_chain[i][USABLE_RX_BD_PER_PAGE];
412843c2aeb0SSepherosa Ziehau 
412943c2aeb0SSepherosa Ziehau 		/* Check if we've reached the last page. */
413008b64767SSepherosa Ziehau 		if (i == (rxr->rx_pages - 1))
413143c2aeb0SSepherosa Ziehau 			j = 0;
413243c2aeb0SSepherosa Ziehau 		else
413343c2aeb0SSepherosa Ziehau 			j = i + 1;
413443c2aeb0SSepherosa Ziehau 
413543c2aeb0SSepherosa Ziehau 		/* Setup the chain page pointers. */
413643c2aeb0SSepherosa Ziehau 		rxbd->rx_bd_haddr_hi =
413708b64767SSepherosa Ziehau 		    htole32(BCE_ADDR_HI(rxr->rx_bd_chain_paddr[j]));
413843c2aeb0SSepherosa Ziehau 		rxbd->rx_bd_haddr_lo =
413908b64767SSepherosa Ziehau 		    htole32(BCE_ADDR_LO(rxr->rx_bd_chain_paddr[j]));
414043c2aeb0SSepherosa Ziehau 	}
414143c2aeb0SSepherosa Ziehau 
414243c2aeb0SSepherosa Ziehau 	/* Allocate mbuf clusters for the rx_bd chain. */
414343c2aeb0SSepherosa Ziehau 	prod = prod_bseq = 0;
414408b64767SSepherosa Ziehau 	while (prod < TOTAL_RX_BD(rxr)) {
414508b64767SSepherosa Ziehau 		chain_prod = RX_CHAIN_IDX(rxr, prod);
414686ae632dSSepherosa Ziehau 		if (bce_newbuf_std(rxr, &prod, chain_prod, &prod_bseq, 1)) {
414708b64767SSepherosa Ziehau 			if_printf(&rxr->sc->arpcom.ac_if,
414843c2aeb0SSepherosa Ziehau 			    "Error filling RX chain: rx_bd[0x%04X]!\n",
414943c2aeb0SSepherosa Ziehau 			    chain_prod);
415043c2aeb0SSepherosa Ziehau 			rc = ENOBUFS;
415143c2aeb0SSepherosa Ziehau 			break;
415243c2aeb0SSepherosa Ziehau 		}
415343c2aeb0SSepherosa Ziehau 		prod = NEXT_RX_BD(prod);
415443c2aeb0SSepherosa Ziehau 	}
415543c2aeb0SSepherosa Ziehau 
415643c2aeb0SSepherosa Ziehau 	/* Save the RX chain producer index. */
415708b64767SSepherosa Ziehau 	rxr->rx_prod = prod;
415808b64767SSepherosa Ziehau 	rxr->rx_prod_bseq = prod_bseq;
415943c2aeb0SSepherosa Ziehau 
416043c2aeb0SSepherosa Ziehau 	/* Tell the chip about the waiting rx_bd's. */
41610080c09fSSepherosa Ziehau 	REG_WR16(rxr->sc, MB_GET_CID_ADDR(rxr->rx_cid) + BCE_L2MQ_RX_HOST_BDIDX,
416208b64767SSepherosa Ziehau 	    rxr->rx_prod);
41630080c09fSSepherosa Ziehau 	REG_WR(rxr->sc, MB_GET_CID_ADDR(rxr->rx_cid) + BCE_L2MQ_RX_HOST_BSEQ,
416408b64767SSepherosa Ziehau 	    rxr->rx_prod_bseq);
416543c2aeb0SSepherosa Ziehau 
416608b64767SSepherosa Ziehau 	bce_init_rx_context(rxr);
416743c2aeb0SSepherosa Ziehau 
416843c2aeb0SSepherosa Ziehau 	return(rc);
416943c2aeb0SSepherosa Ziehau }
417043c2aeb0SSepherosa Ziehau 
417143c2aeb0SSepherosa Ziehau /****************************************************************************/
417243c2aeb0SSepherosa Ziehau /* Free memory and clear the RX data structures.                            */
417343c2aeb0SSepherosa Ziehau /*                                                                          */
417443c2aeb0SSepherosa Ziehau /* Returns:                                                                 */
417543c2aeb0SSepherosa Ziehau /*   Nothing.                                                               */
417643c2aeb0SSepherosa Ziehau /****************************************************************************/
417743c2aeb0SSepherosa Ziehau static void
bce_free_rx_chain(struct bce_rx_ring * rxr)417808b64767SSepherosa Ziehau bce_free_rx_chain(struct bce_rx_ring *rxr)
417943c2aeb0SSepherosa Ziehau {
418043c2aeb0SSepherosa Ziehau 	int i;
418143c2aeb0SSepherosa Ziehau 
418243c2aeb0SSepherosa Ziehau 	/* Free any mbufs still in the RX mbuf chain. */
418308b64767SSepherosa Ziehau 	for (i = 0; i < TOTAL_RX_BD(rxr); i++) {
418486ae632dSSepherosa Ziehau 		struct bce_rx_buf *rx_buf = &rxr->rx_bufs[i];
418586ae632dSSepherosa Ziehau 
418686ae632dSSepherosa Ziehau 		if (rx_buf->rx_mbuf_ptr != NULL) {
418708b64767SSepherosa Ziehau 			bus_dmamap_unload(rxr->rx_mbuf_tag,
418886ae632dSSepherosa Ziehau 			    rx_buf->rx_mbuf_map);
418986ae632dSSepherosa Ziehau 			m_freem(rx_buf->rx_mbuf_ptr);
419086ae632dSSepherosa Ziehau 			rx_buf->rx_mbuf_ptr = NULL;
419143c2aeb0SSepherosa Ziehau 		}
419243c2aeb0SSepherosa Ziehau 	}
419343c2aeb0SSepherosa Ziehau 
419443c2aeb0SSepherosa Ziehau 	/* Clear each RX chain page. */
419508b64767SSepherosa Ziehau 	for (i = 0; i < rxr->rx_pages; i++)
419608b64767SSepherosa Ziehau 		bzero(rxr->rx_bd_chain[i], BCE_RX_CHAIN_PAGE_SZ);
419743c2aeb0SSepherosa Ziehau }
419843c2aeb0SSepherosa Ziehau 
419943c2aeb0SSepherosa Ziehau /****************************************************************************/
420043c2aeb0SSepherosa Ziehau /* Set media options.                                                       */
420143c2aeb0SSepherosa Ziehau /*                                                                          */
420243c2aeb0SSepherosa Ziehau /* Returns:                                                                 */
420343c2aeb0SSepherosa Ziehau /*   0 for success, positive value for failure.                             */
420443c2aeb0SSepherosa Ziehau /****************************************************************************/
420543c2aeb0SSepherosa Ziehau static int
bce_ifmedia_upd(struct ifnet * ifp)420643c2aeb0SSepherosa Ziehau bce_ifmedia_upd(struct ifnet *ifp)
420743c2aeb0SSepherosa Ziehau {
420843c2aeb0SSepherosa Ziehau 	struct bce_softc *sc = ifp->if_softc;
420943c2aeb0SSepherosa Ziehau 	struct mii_data *mii = device_get_softc(sc->bce_miibus);
421039f10431SSepherosa Ziehau 	int error = 0;
421143c2aeb0SSepherosa Ziehau 
421243c2aeb0SSepherosa Ziehau 	/*
421343c2aeb0SSepherosa Ziehau 	 * 'mii' will be NULL, when this function is called on following
421443c2aeb0SSepherosa Ziehau 	 * code path: bce_attach() -> bce_mgmt_init()
421543c2aeb0SSepherosa Ziehau 	 */
421643c2aeb0SSepherosa Ziehau 	if (mii != NULL) {
421743c2aeb0SSepherosa Ziehau 		/* Make sure the MII bus has been enumerated. */
421843c2aeb0SSepherosa Ziehau 		sc->bce_link = 0;
421943c2aeb0SSepherosa Ziehau 		if (mii->mii_instance) {
422043c2aeb0SSepherosa Ziehau 			struct mii_softc *miisc;
422143c2aeb0SSepherosa Ziehau 
422243c2aeb0SSepherosa Ziehau 			LIST_FOREACH(miisc, &mii->mii_phys, mii_list)
422343c2aeb0SSepherosa Ziehau 				mii_phy_reset(miisc);
422443c2aeb0SSepherosa Ziehau 		}
422539f10431SSepherosa Ziehau 		error = mii_mediachg(mii);
422643c2aeb0SSepherosa Ziehau 	}
422739f10431SSepherosa Ziehau 	return error;
422843c2aeb0SSepherosa Ziehau }
422943c2aeb0SSepherosa Ziehau 
423043c2aeb0SSepherosa Ziehau /****************************************************************************/
423143c2aeb0SSepherosa Ziehau /* Reports current media status.                                            */
423243c2aeb0SSepherosa Ziehau /*                                                                          */
423343c2aeb0SSepherosa Ziehau /* Returns:                                                                 */
423443c2aeb0SSepherosa Ziehau /*   Nothing.                                                               */
423543c2aeb0SSepherosa Ziehau /****************************************************************************/
423643c2aeb0SSepherosa Ziehau static void
bce_ifmedia_sts(struct ifnet * ifp,struct ifmediareq * ifmr)423743c2aeb0SSepherosa Ziehau bce_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
423843c2aeb0SSepherosa Ziehau {
423943c2aeb0SSepherosa Ziehau 	struct bce_softc *sc = ifp->if_softc;
424043c2aeb0SSepherosa Ziehau 	struct mii_data *mii = device_get_softc(sc->bce_miibus);
424143c2aeb0SSepherosa Ziehau 
424243c2aeb0SSepherosa Ziehau 	mii_pollstat(mii);
424343c2aeb0SSepherosa Ziehau 	ifmr->ifm_active = mii->mii_media_active;
424443c2aeb0SSepherosa Ziehau 	ifmr->ifm_status = mii->mii_media_status;
424543c2aeb0SSepherosa Ziehau }
424643c2aeb0SSepherosa Ziehau 
424743c2aeb0SSepherosa Ziehau /****************************************************************************/
424843c2aeb0SSepherosa Ziehau /* Handles PHY generated interrupt events.                                  */
424943c2aeb0SSepherosa Ziehau /*                                                                          */
425043c2aeb0SSepherosa Ziehau /* Returns:                                                                 */
425143c2aeb0SSepherosa Ziehau /*   Nothing.                                                               */
425243c2aeb0SSepherosa Ziehau /****************************************************************************/
425343c2aeb0SSepherosa Ziehau static void
bce_phy_intr(struct bce_softc * sc)425443c2aeb0SSepherosa Ziehau bce_phy_intr(struct bce_softc *sc)
425543c2aeb0SSepherosa Ziehau {
425643c2aeb0SSepherosa Ziehau 	uint32_t new_link_state, old_link_state;
425743c2aeb0SSepherosa Ziehau 	struct ifnet *ifp = &sc->arpcom.ac_if;
425843c2aeb0SSepherosa Ziehau 
425984464af5SSepherosa Ziehau 	ASSERT_SERIALIZED(&sc->main_serialize);
426043c2aeb0SSepherosa Ziehau 
426143c2aeb0SSepherosa Ziehau 	new_link_state = sc->status_block->status_attn_bits &
426243c2aeb0SSepherosa Ziehau 			 STATUS_ATTN_BITS_LINK_STATE;
426343c2aeb0SSepherosa Ziehau 	old_link_state = sc->status_block->status_attn_bits_ack &
426443c2aeb0SSepherosa Ziehau 			 STATUS_ATTN_BITS_LINK_STATE;
426543c2aeb0SSepherosa Ziehau 
426643c2aeb0SSepherosa Ziehau 	/* Handle any changes if the link state has changed. */
426743c2aeb0SSepherosa Ziehau 	if (new_link_state != old_link_state) {	/* XXX redundant? */
426843c2aeb0SSepherosa Ziehau 		/* Update the status_attn_bits_ack field in the status block. */
426943c2aeb0SSepherosa Ziehau 		if (new_link_state) {
427043c2aeb0SSepherosa Ziehau 			REG_WR(sc, BCE_PCICFG_STATUS_BIT_SET_CMD,
427143c2aeb0SSepherosa Ziehau 			       STATUS_ATTN_BITS_LINK_STATE);
427243c2aeb0SSepherosa Ziehau 			if (bootverbose)
427343c2aeb0SSepherosa Ziehau 				if_printf(ifp, "Link is now UP.\n");
427443c2aeb0SSepherosa Ziehau 		} else {
427543c2aeb0SSepherosa Ziehau 			REG_WR(sc, BCE_PCICFG_STATUS_BIT_CLEAR_CMD,
427643c2aeb0SSepherosa Ziehau 			       STATUS_ATTN_BITS_LINK_STATE);
427743c2aeb0SSepherosa Ziehau 			if (bootverbose)
427843c2aeb0SSepherosa Ziehau 				if_printf(ifp, "Link is now DOWN.\n");
427943c2aeb0SSepherosa Ziehau 		}
4280d0092544SSepherosa Ziehau 
4281d0092544SSepherosa Ziehau 		/*
4282d0092544SSepherosa Ziehau 		 * Assume link is down and allow tick routine to
4283d0092544SSepherosa Ziehau 		 * update the state based on the actual media state.
4284d0092544SSepherosa Ziehau 		 */
4285d0092544SSepherosa Ziehau 		sc->bce_link = 0;
4286d0092544SSepherosa Ziehau 		callout_stop(&sc->bce_tick_callout);
4287d0092544SSepherosa Ziehau 		bce_tick_serialized(sc);
428843c2aeb0SSepherosa Ziehau 	}
428943c2aeb0SSepherosa Ziehau 
429043c2aeb0SSepherosa Ziehau 	/* Acknowledge the link change interrupt. */
429143c2aeb0SSepherosa Ziehau 	REG_WR(sc, BCE_EMAC_STATUS, BCE_EMAC_STATUS_LINK_CHANGE);
429243c2aeb0SSepherosa Ziehau }
429343c2aeb0SSepherosa Ziehau 
429443c2aeb0SSepherosa Ziehau /****************************************************************************/
429524603545SSepherosa Ziehau /* Reads the receive consumer value from the status block (skipping over    */
429624603545SSepherosa Ziehau /* chain page pointer if necessary).                                        */
429724603545SSepherosa Ziehau /*                                                                          */
429824603545SSepherosa Ziehau /* Returns:                                                                 */
429924603545SSepherosa Ziehau /*   hw_cons                                                                */
430024603545SSepherosa Ziehau /****************************************************************************/
430124603545SSepherosa Ziehau static __inline uint16_t
bce_get_hw_rx_cons(struct bce_rx_ring * rxr)43025abd7f19SSepherosa Ziehau bce_get_hw_rx_cons(struct bce_rx_ring *rxr)
430324603545SSepherosa Ziehau {
43045abd7f19SSepherosa Ziehau 	uint16_t hw_cons = *rxr->rx_hw_cons;
430524603545SSepherosa Ziehau 
430624603545SSepherosa Ziehau 	if ((hw_cons & USABLE_RX_BD_PER_PAGE) == USABLE_RX_BD_PER_PAGE)
430724603545SSepherosa Ziehau 		hw_cons++;
430824603545SSepherosa Ziehau 	return hw_cons;
430924603545SSepherosa Ziehau }
431024603545SSepherosa Ziehau 
431124603545SSepherosa Ziehau /****************************************************************************/
431243c2aeb0SSepherosa Ziehau /* Handles received frame interrupt events.                                 */
431343c2aeb0SSepherosa Ziehau /*                                                                          */
431443c2aeb0SSepherosa Ziehau /* Returns:                                                                 */
431543c2aeb0SSepherosa Ziehau /*   Nothing.                                                               */
431643c2aeb0SSepherosa Ziehau /****************************************************************************/
431743c2aeb0SSepherosa Ziehau static void
bce_rx_intr(struct bce_rx_ring * rxr,int count,uint16_t hw_cons)431808b64767SSepherosa Ziehau bce_rx_intr(struct bce_rx_ring *rxr, int count, uint16_t hw_cons)
431943c2aeb0SSepherosa Ziehau {
432008b64767SSepherosa Ziehau 	struct ifnet *ifp = &rxr->sc->arpcom.ac_if;
4321a5eaa4bfSSepherosa Ziehau 	uint16_t sw_cons, sw_chain_cons, sw_prod, sw_chain_prod;
432243c2aeb0SSepherosa Ziehau 	uint32_t sw_prod_bseq;
4323ff37a356SSepherosa Ziehau 	int cpuid = mycpuid;
432443c2aeb0SSepherosa Ziehau 
432584464af5SSepherosa Ziehau 	ASSERT_SERIALIZED(&rxr->rx_serialize);
432643c2aeb0SSepherosa Ziehau 
432743c2aeb0SSepherosa Ziehau 	/* Get working copies of the driver's view of the RX indices. */
432808b64767SSepherosa Ziehau 	sw_cons = rxr->rx_cons;
432908b64767SSepherosa Ziehau 	sw_prod = rxr->rx_prod;
433008b64767SSepherosa Ziehau 	sw_prod_bseq = rxr->rx_prod_bseq;
433143c2aeb0SSepherosa Ziehau 
433243c2aeb0SSepherosa Ziehau 	/* Scan through the receive chain as long as there is work to do. */
433343c2aeb0SSepherosa Ziehau 	while (sw_cons != hw_cons) {
433442ad0e07SSepherosa Ziehau 		struct pktinfo pi0, *pi = NULL;
433586ae632dSSepherosa Ziehau 		struct bce_rx_buf *rx_buf;
433643c2aeb0SSepherosa Ziehau 		struct mbuf *m = NULL;
433743c2aeb0SSepherosa Ziehau 		struct l2_fhdr *l2fhdr = NULL;
433843c2aeb0SSepherosa Ziehau 		unsigned int len;
433943c2aeb0SSepherosa Ziehau 		uint32_t status = 0;
434043c2aeb0SSepherosa Ziehau 
43414a331bf7SSepherosa Ziehau #ifdef IFPOLL_ENABLE
4342a5eaa4bfSSepherosa Ziehau 		if (count >= 0 && count-- == 0)
434343c2aeb0SSepherosa Ziehau 			break;
434443c2aeb0SSepherosa Ziehau #endif
434543c2aeb0SSepherosa Ziehau 
434643c2aeb0SSepherosa Ziehau 		/*
434743c2aeb0SSepherosa Ziehau 		 * Convert the producer/consumer indices
434843c2aeb0SSepherosa Ziehau 		 * to an actual rx_bd index.
434943c2aeb0SSepherosa Ziehau 		 */
435008b64767SSepherosa Ziehau 		sw_chain_cons = RX_CHAIN_IDX(rxr, sw_cons);
435108b64767SSepherosa Ziehau 		sw_chain_prod = RX_CHAIN_IDX(rxr, sw_prod);
435286ae632dSSepherosa Ziehau 		rx_buf = &rxr->rx_bufs[sw_chain_cons];
435343c2aeb0SSepherosa Ziehau 
435408b64767SSepherosa Ziehau 		rxr->free_rx_bd++;
435543c2aeb0SSepherosa Ziehau 
435643c2aeb0SSepherosa Ziehau 		/* The mbuf is stored with the last rx_bd entry of a packet. */
435786ae632dSSepherosa Ziehau 		if (rx_buf->rx_mbuf_ptr != NULL) {
4358c36fd9eeSSepherosa Ziehau 			if (sw_chain_cons != sw_chain_prod) {
4359c36fd9eeSSepherosa Ziehau 				if_printf(ifp, "RX cons(%d) != prod(%d), "
436008b64767SSepherosa Ziehau 				    "drop!\n", sw_chain_cons, sw_chain_prod);
4361d40991efSSepherosa Ziehau 				IFNET_STAT_INC(ifp, ierrors, 1);
4362c36fd9eeSSepherosa Ziehau 
436308b64767SSepherosa Ziehau 				bce_setup_rxdesc_std(rxr, sw_chain_cons,
4364c36fd9eeSSepherosa Ziehau 				    &sw_prod_bseq);
4365c36fd9eeSSepherosa Ziehau 				m = NULL;
4366c36fd9eeSSepherosa Ziehau 				goto bce_rx_int_next_rx;
4367c36fd9eeSSepherosa Ziehau 			}
436843c2aeb0SSepherosa Ziehau 
436943c2aeb0SSepherosa Ziehau 			/* Unmap the mbuf from DMA space. */
437086ae632dSSepherosa Ziehau 			bus_dmamap_sync(rxr->rx_mbuf_tag, rx_buf->rx_mbuf_map,
437143c2aeb0SSepherosa Ziehau 			    BUS_DMASYNC_POSTREAD);
437243c2aeb0SSepherosa Ziehau 
4373c36fd9eeSSepherosa Ziehau 			/* Save the mbuf from the driver's chain. */
437486ae632dSSepherosa Ziehau 			m = rx_buf->rx_mbuf_ptr;
437543c2aeb0SSepherosa Ziehau 
437643c2aeb0SSepherosa Ziehau 			/*
437743c2aeb0SSepherosa Ziehau 			 * Frames received on the NetXteme II are prepended
437843c2aeb0SSepherosa Ziehau 			 * with an l2_fhdr structure which provides status
437943c2aeb0SSepherosa Ziehau 			 * information about the received frame (including
438043c2aeb0SSepherosa Ziehau 			 * VLAN tags and checksum info).  The frames are also
438143c2aeb0SSepherosa Ziehau 			 * automatically adjusted to align the IP header
438243c2aeb0SSepherosa Ziehau 			 * (i.e. two null bytes are inserted before the
4383cff16e71SSepherosa Ziehau 			 * Ethernet header).  As a result the data DMA'd by
4384cff16e71SSepherosa Ziehau 			 * the controller into the mbuf is as follows:
4385cff16e71SSepherosa Ziehau 			 *
4386cff16e71SSepherosa Ziehau 			 * +---------+-----+---------------------+-----+
4387cff16e71SSepherosa Ziehau 			 * | l2_fhdr | pad | packet data         | FCS |
4388cff16e71SSepherosa Ziehau 			 * +---------+-----+---------------------+-----+
4389cff16e71SSepherosa Ziehau 			 *
4390cff16e71SSepherosa Ziehau 			 * The l2_fhdr needs to be checked and skipped and the
4391cff16e71SSepherosa Ziehau 			 * FCS needs to be stripped before sending the packet
4392cff16e71SSepherosa Ziehau 			 * up the stack.
439343c2aeb0SSepherosa Ziehau 			 */
439443c2aeb0SSepherosa Ziehau 			l2fhdr = mtod(m, struct l2_fhdr *);
439543c2aeb0SSepherosa Ziehau 
439643c2aeb0SSepherosa Ziehau 			len = l2fhdr->l2_fhdr_pkt_len;
439743c2aeb0SSepherosa Ziehau 			status = l2fhdr->l2_fhdr_status;
439843c2aeb0SSepherosa Ziehau 
439943c2aeb0SSepherosa Ziehau 			len -= ETHER_CRC_LEN;
440043c2aeb0SSepherosa Ziehau 
440143c2aeb0SSepherosa Ziehau 			/* Check the received frame for errors. */
440243c2aeb0SSepherosa Ziehau 			if (status & (L2_FHDR_ERRORS_BAD_CRC |
440343c2aeb0SSepherosa Ziehau 				      L2_FHDR_ERRORS_PHY_DECODE |
440443c2aeb0SSepherosa Ziehau 				      L2_FHDR_ERRORS_ALIGNMENT |
440543c2aeb0SSepherosa Ziehau 				      L2_FHDR_ERRORS_TOO_SHORT |
440643c2aeb0SSepherosa Ziehau 				      L2_FHDR_ERRORS_GIANT_FRAME)) {
4407d40991efSSepherosa Ziehau 				IFNET_STAT_INC(ifp, ierrors, 1);
440843c2aeb0SSepherosa Ziehau 
440943c2aeb0SSepherosa Ziehau 				/* Reuse the mbuf for a new frame. */
441008b64767SSepherosa Ziehau 				bce_setup_rxdesc_std(rxr, sw_chain_prod,
4411c36fd9eeSSepherosa Ziehau 				    &sw_prod_bseq);
441243c2aeb0SSepherosa Ziehau 				m = NULL;
441343c2aeb0SSepherosa Ziehau 				goto bce_rx_int_next_rx;
441443c2aeb0SSepherosa Ziehau 			}
441543c2aeb0SSepherosa Ziehau 
441643c2aeb0SSepherosa Ziehau 			/*
441743c2aeb0SSepherosa Ziehau 			 * Get a new mbuf for the rx_bd.   If no new
441843c2aeb0SSepherosa Ziehau 			 * mbufs are available then reuse the current mbuf,
441943c2aeb0SSepherosa Ziehau 			 * log an ierror on the interface, and generate
442043c2aeb0SSepherosa Ziehau 			 * an error in the system log.
442143c2aeb0SSepherosa Ziehau 			 */
442286ae632dSSepherosa Ziehau 			if (bce_newbuf_std(rxr, &sw_prod, sw_chain_prod,
4423c36fd9eeSSepherosa Ziehau 			    &sw_prod_bseq, 0)) {
4424d40991efSSepherosa Ziehau 				IFNET_STAT_INC(ifp, ierrors, 1);
442543c2aeb0SSepherosa Ziehau 
442643c2aeb0SSepherosa Ziehau 				/* Try and reuse the exisitng mbuf. */
442708b64767SSepherosa Ziehau 				bce_setup_rxdesc_std(rxr, sw_chain_prod,
4428c36fd9eeSSepherosa Ziehau 				    &sw_prod_bseq);
442943c2aeb0SSepherosa Ziehau 				m = NULL;
443043c2aeb0SSepherosa Ziehau 				goto bce_rx_int_next_rx;
443143c2aeb0SSepherosa Ziehau 			}
443243c2aeb0SSepherosa Ziehau 
443343c2aeb0SSepherosa Ziehau 			/*
443443c2aeb0SSepherosa Ziehau 			 * Skip over the l2_fhdr when passing
443543c2aeb0SSepherosa Ziehau 			 * the data up the stack.
443643c2aeb0SSepherosa Ziehau 			 */
443743c2aeb0SSepherosa Ziehau 			m_adj(m, sizeof(struct l2_fhdr) + ETHER_ALIGN);
443843c2aeb0SSepherosa Ziehau 
443943c2aeb0SSepherosa Ziehau 			m->m_pkthdr.len = m->m_len = len;
444043c2aeb0SSepherosa Ziehau 			m->m_pkthdr.rcvif = ifp;
444143c2aeb0SSepherosa Ziehau 
444243c2aeb0SSepherosa Ziehau 			/* Validate the checksum if offload enabled. */
444343c2aeb0SSepherosa Ziehau 			if (ifp->if_capenable & IFCAP_RXCSUM) {
444443c2aeb0SSepherosa Ziehau 				/* Check for an IP datagram. */
444543c2aeb0SSepherosa Ziehau 				if (status & L2_FHDR_STATUS_IP_DATAGRAM) {
444643c2aeb0SSepherosa Ziehau 					m->m_pkthdr.csum_flags |=
444743c2aeb0SSepherosa Ziehau 						CSUM_IP_CHECKED;
444843c2aeb0SSepherosa Ziehau 
444943c2aeb0SSepherosa Ziehau 					/* Check if the IP checksum is valid. */
445043c2aeb0SSepherosa Ziehau 					if ((l2fhdr->l2_fhdr_ip_xsum ^
445143c2aeb0SSepherosa Ziehau 					     0xffff) == 0) {
445243c2aeb0SSepherosa Ziehau 						m->m_pkthdr.csum_flags |=
445343c2aeb0SSepherosa Ziehau 							CSUM_IP_VALID;
445443c2aeb0SSepherosa Ziehau 					}
445543c2aeb0SSepherosa Ziehau 				}
445643c2aeb0SSepherosa Ziehau 
445743c2aeb0SSepherosa Ziehau 				/* Check for a valid TCP/UDP frame. */
445843c2aeb0SSepherosa Ziehau 				if (status & (L2_FHDR_STATUS_TCP_SEGMENT |
445943c2aeb0SSepherosa Ziehau 					      L2_FHDR_STATUS_UDP_DATAGRAM)) {
446043c2aeb0SSepherosa Ziehau 
446143c2aeb0SSepherosa Ziehau 					/* Check for a good TCP/UDP checksum. */
446243c2aeb0SSepherosa Ziehau 					if ((status &
446343c2aeb0SSepherosa Ziehau 					     (L2_FHDR_ERRORS_TCP_XSUM |
446443c2aeb0SSepherosa Ziehau 					      L2_FHDR_ERRORS_UDP_XSUM)) == 0) {
446543c2aeb0SSepherosa Ziehau 						m->m_pkthdr.csum_data =
446643c2aeb0SSepherosa Ziehau 						l2fhdr->l2_fhdr_tcp_udp_xsum;
446743c2aeb0SSepherosa Ziehau 						m->m_pkthdr.csum_flags |=
446843c2aeb0SSepherosa Ziehau 							CSUM_DATA_VALID |
446943c2aeb0SSepherosa Ziehau 							CSUM_PSEUDO_HDR;
447043c2aeb0SSepherosa Ziehau 					}
447143c2aeb0SSepherosa Ziehau 				}
447243c2aeb0SSepherosa Ziehau 			}
447342ad0e07SSepherosa Ziehau 			if (ifp->if_capenable & IFCAP_RSS) {
447442ad0e07SSepherosa Ziehau 				pi = bce_rss_pktinfo(&pi0, status, l2fhdr);
447542ad0e07SSepherosa Ziehau 				if (pi != NULL &&
447642ad0e07SSepherosa Ziehau 				    (status & L2_FHDR_STATUS_RSS_HASH)) {
44777558541bSSepherosa Ziehau 					m_sethash(m,
44787558541bSSepherosa Ziehau 					    toeplitz_hash(l2fhdr->l2_fhdr_hash));
447942ad0e07SSepherosa Ziehau 				}
448042ad0e07SSepherosa Ziehau 			}
448143c2aeb0SSepherosa Ziehau 
4482d40991efSSepherosa Ziehau 			IFNET_STAT_INC(ifp, ipackets, 1);
448343c2aeb0SSepherosa Ziehau bce_rx_int_next_rx:
448443c2aeb0SSepherosa Ziehau 			sw_prod = NEXT_RX_BD(sw_prod);
448543c2aeb0SSepherosa Ziehau 		}
448643c2aeb0SSepherosa Ziehau 
448743c2aeb0SSepherosa Ziehau 		sw_cons = NEXT_RX_BD(sw_cons);
448843c2aeb0SSepherosa Ziehau 
448943c2aeb0SSepherosa Ziehau 		/* If we have a packet, pass it up the stack */
449043c2aeb0SSepherosa Ziehau 		if (m) {
4491e6b5847cSSepherosa Ziehau 			if (status & L2_FHDR_STATUS_L2_VLAN_TAG) {
4492e6b5847cSSepherosa Ziehau 				m->m_flags |= M_VLANTAG;
4493e6b5847cSSepherosa Ziehau 				m->m_pkthdr.ether_vlantag =
4494e6b5847cSSepherosa Ziehau 					l2fhdr->l2_fhdr_vlan_tag;
4495e6b5847cSSepherosa Ziehau 			}
4496be4134c6SFranco Fichtner 			ifp->if_input(ifp, m, pi, cpuid);
4497e8dcbfd4SSepherosa Ziehau #ifdef BCE_RSS_DEBUG
4498b42386eeSSepherosa Ziehau 			rxr->rx_pkts++;
4499e8dcbfd4SSepherosa Ziehau #endif
450043c2aeb0SSepherosa Ziehau 		}
450143c2aeb0SSepherosa Ziehau 	}
450243c2aeb0SSepherosa Ziehau 
450308b64767SSepherosa Ziehau 	rxr->rx_cons = sw_cons;
450408b64767SSepherosa Ziehau 	rxr->rx_prod = sw_prod;
450508b64767SSepherosa Ziehau 	rxr->rx_prod_bseq = sw_prod_bseq;
450643c2aeb0SSepherosa Ziehau 
45070080c09fSSepherosa Ziehau 	REG_WR16(rxr->sc, MB_GET_CID_ADDR(rxr->rx_cid) + BCE_L2MQ_RX_HOST_BDIDX,
450808b64767SSepherosa Ziehau 	    rxr->rx_prod);
45090080c09fSSepherosa Ziehau 	REG_WR(rxr->sc, MB_GET_CID_ADDR(rxr->rx_cid) + BCE_L2MQ_RX_HOST_BSEQ,
451008b64767SSepherosa Ziehau 	    rxr->rx_prod_bseq);
451143c2aeb0SSepherosa Ziehau }
451243c2aeb0SSepherosa Ziehau 
451343c2aeb0SSepherosa Ziehau /****************************************************************************/
451424603545SSepherosa Ziehau /* Reads the transmit consumer value from the status block (skipping over   */
451524603545SSepherosa Ziehau /* chain page pointer if necessary).                                        */
451624603545SSepherosa Ziehau /*                                                                          */
451724603545SSepherosa Ziehau /* Returns:                                                                 */
451824603545SSepherosa Ziehau /*   hw_cons                                                                */
451924603545SSepherosa Ziehau /****************************************************************************/
452024603545SSepherosa Ziehau static __inline uint16_t
bce_get_hw_tx_cons(struct bce_tx_ring * txr)45215abd7f19SSepherosa Ziehau bce_get_hw_tx_cons(struct bce_tx_ring *txr)
452224603545SSepherosa Ziehau {
45235abd7f19SSepherosa Ziehau 	uint16_t hw_cons = *txr->tx_hw_cons;
452424603545SSepherosa Ziehau 
452524603545SSepherosa Ziehau 	if ((hw_cons & USABLE_TX_BD_PER_PAGE) == USABLE_TX_BD_PER_PAGE)
452624603545SSepherosa Ziehau 		hw_cons++;
452724603545SSepherosa Ziehau 	return hw_cons;
452824603545SSepherosa Ziehau }
452924603545SSepherosa Ziehau 
453024603545SSepherosa Ziehau /****************************************************************************/
453143c2aeb0SSepherosa Ziehau /* Handles transmit completion interrupt events.                            */
453243c2aeb0SSepherosa Ziehau /*                                                                          */
453343c2aeb0SSepherosa Ziehau /* Returns:                                                                 */
453443c2aeb0SSepherosa Ziehau /*   Nothing.                                                               */
453543c2aeb0SSepherosa Ziehau /****************************************************************************/
453643c2aeb0SSepherosa Ziehau static void
bce_tx_intr(struct bce_tx_ring * txr,uint16_t hw_tx_cons)453710bcbdabSSepherosa Ziehau bce_tx_intr(struct bce_tx_ring *txr, uint16_t hw_tx_cons)
453843c2aeb0SSepherosa Ziehau {
453910bcbdabSSepherosa Ziehau 	struct ifnet *ifp = &txr->sc->arpcom.ac_if;
4540a5eaa4bfSSepherosa Ziehau 	uint16_t sw_tx_cons, sw_tx_chain_cons;
454143c2aeb0SSepherosa Ziehau 
454284464af5SSepherosa Ziehau 	ASSERT_SERIALIZED(&txr->tx_serialize);
454343c2aeb0SSepherosa Ziehau 
454443c2aeb0SSepherosa Ziehau 	/* Get the hardware's view of the TX consumer index. */
454510bcbdabSSepherosa Ziehau 	sw_tx_cons = txr->tx_cons;
454643c2aeb0SSepherosa Ziehau 
454743c2aeb0SSepherosa Ziehau 	/* Cycle through any completed TX chain page entries. */
454843c2aeb0SSepherosa Ziehau 	while (sw_tx_cons != hw_tx_cons) {
454986ae632dSSepherosa Ziehau 		struct bce_tx_buf *tx_buf;
455086ae632dSSepherosa Ziehau 
455110bcbdabSSepherosa Ziehau 		sw_tx_chain_cons = TX_CHAIN_IDX(txr, sw_tx_cons);
455286ae632dSSepherosa Ziehau 		tx_buf = &txr->tx_bufs[sw_tx_chain_cons];
455343c2aeb0SSepherosa Ziehau 
455443c2aeb0SSepherosa Ziehau 		/*
455543c2aeb0SSepherosa Ziehau 		 * Free the associated mbuf. Remember
455643c2aeb0SSepherosa Ziehau 		 * that only the last tx_bd of a packet
455743c2aeb0SSepherosa Ziehau 		 * has an mbuf pointer and DMA map.
455843c2aeb0SSepherosa Ziehau 		 */
455986ae632dSSepherosa Ziehau 		if (tx_buf->tx_mbuf_ptr != NULL) {
456043c2aeb0SSepherosa Ziehau 			/* Unmap the mbuf. */
456110bcbdabSSepherosa Ziehau 			bus_dmamap_unload(txr->tx_mbuf_tag,
456286ae632dSSepherosa Ziehau 			    tx_buf->tx_mbuf_map);
456343c2aeb0SSepherosa Ziehau 
456443c2aeb0SSepherosa Ziehau 			/* Free the mbuf. */
456586ae632dSSepherosa Ziehau 			m_freem(tx_buf->tx_mbuf_ptr);
456686ae632dSSepherosa Ziehau 			tx_buf->tx_mbuf_ptr = NULL;
456743c2aeb0SSepherosa Ziehau 
4568d40991efSSepherosa Ziehau 			IFNET_STAT_INC(ifp, opackets, 1);
4569b42386eeSSepherosa Ziehau #ifdef BCE_TSS_DEBUG
4570b42386eeSSepherosa Ziehau 			txr->tx_pkts++;
4571b42386eeSSepherosa Ziehau #endif
457243c2aeb0SSepherosa Ziehau 		}
457343c2aeb0SSepherosa Ziehau 
457410bcbdabSSepherosa Ziehau 		txr->used_tx_bd--;
457543c2aeb0SSepherosa Ziehau 		sw_tx_cons = NEXT_TX_BD(sw_tx_cons);
457643c2aeb0SSepherosa Ziehau 	}
457743c2aeb0SSepherosa Ziehau 
457810bcbdabSSepherosa Ziehau 	if (txr->used_tx_bd == 0) {
457943c2aeb0SSepherosa Ziehau 		/* Clear the TX timeout timer. */
4580e2292763SMatthew Dillon 		ifsq_watchdog_set_count(&txr->tx_watchdog, 0);
458143c2aeb0SSepherosa Ziehau 	}
458243c2aeb0SSepherosa Ziehau 
458343c2aeb0SSepherosa Ziehau 	/* Clear the tx hardware queue full flag. */
458410bcbdabSSepherosa Ziehau 	if (txr->max_tx_bd - txr->used_tx_bd >= BCE_TX_SPARE_SPACE)
4585f774fa0fSSepherosa Ziehau 		ifsq_clr_oactive(txr->ifsq);
458610bcbdabSSepherosa Ziehau 	txr->tx_cons = sw_tx_cons;
458743c2aeb0SSepherosa Ziehau }
458843c2aeb0SSepherosa Ziehau 
458943c2aeb0SSepherosa Ziehau /****************************************************************************/
459043c2aeb0SSepherosa Ziehau /* Disables interrupt generation.                                           */
459143c2aeb0SSepherosa Ziehau /*                                                                          */
459243c2aeb0SSepherosa Ziehau /* Returns:                                                                 */
459343c2aeb0SSepherosa Ziehau /*   Nothing.                                                               */
459443c2aeb0SSepherosa Ziehau /****************************************************************************/
459543c2aeb0SSepherosa Ziehau static void
bce_disable_intr(struct bce_softc * sc)459643c2aeb0SSepherosa Ziehau bce_disable_intr(struct bce_softc *sc)
459743c2aeb0SSepherosa Ziehau {
4598b42386eeSSepherosa Ziehau 	int i;
4599b42386eeSSepherosa Ziehau 
4600b42386eeSSepherosa Ziehau 	for (i = 0; i < sc->rx_ring_cnt; ++i) {
4601b42386eeSSepherosa Ziehau 		REG_WR(sc, BCE_PCICFG_INT_ACK_CMD,
4602b42386eeSSepherosa Ziehau 		    (sc->rx_rings[i].idx << 24) |
4603b42386eeSSepherosa Ziehau 		    BCE_PCICFG_INT_ACK_CMD_MASK_INT);
4604b42386eeSSepherosa Ziehau 	}
460543c2aeb0SSepherosa Ziehau 	REG_RD(sc, BCE_PCICFG_INT_ACK_CMD);
460628ef7645SSepherosa Ziehau 
460728ef7645SSepherosa Ziehau 	callout_stop(&sc->bce_ckmsi_callout);
460828ef7645SSepherosa Ziehau 	sc->bce_msi_maylose = FALSE;
460928ef7645SSepherosa Ziehau 	sc->bce_check_rx_cons = 0;
461028ef7645SSepherosa Ziehau 	sc->bce_check_tx_cons = 0;
461128ef7645SSepherosa Ziehau 	sc->bce_check_status_idx = 0xffff;
461228ef7645SSepherosa Ziehau 
4613b42386eeSSepherosa Ziehau 	for (i = 0; i < sc->rx_ring_cnt; ++i)
4614b42386eeSSepherosa Ziehau 		lwkt_serialize_handler_disable(sc->bce_msix[i].msix_serialize);
461543c2aeb0SSepherosa Ziehau }
461643c2aeb0SSepherosa Ziehau 
461743c2aeb0SSepherosa Ziehau /****************************************************************************/
461843c2aeb0SSepherosa Ziehau /* Enables interrupt generation.                                            */
461943c2aeb0SSepherosa Ziehau /*                                                                          */
462043c2aeb0SSepherosa Ziehau /* Returns:                                                                 */
462143c2aeb0SSepherosa Ziehau /*   Nothing.                                                               */
462243c2aeb0SSepherosa Ziehau /****************************************************************************/
462343c2aeb0SSepherosa Ziehau static void
bce_enable_intr(struct bce_softc * sc)4624d4274f6bSSepherosa Ziehau bce_enable_intr(struct bce_softc *sc)
462543c2aeb0SSepherosa Ziehau {
4626b42386eeSSepherosa Ziehau 	int i;
4627ba268ba5SSepherosa Ziehau 
4628b42386eeSSepherosa Ziehau 	for (i = 0; i < sc->rx_ring_cnt; ++i)
4629b42386eeSSepherosa Ziehau 		lwkt_serialize_handler_enable(sc->bce_msix[i].msix_serialize);
463043c2aeb0SSepherosa Ziehau 
4631b42386eeSSepherosa Ziehau 	for (i = 0; i < sc->rx_ring_cnt; ++i) {
4632b42386eeSSepherosa Ziehau 		struct bce_rx_ring *rxr = &sc->rx_rings[i];
4633b42386eeSSepherosa Ziehau 
4634b42386eeSSepherosa Ziehau 		REG_WR(sc, BCE_PCICFG_INT_ACK_CMD, (rxr->idx << 24) |
463543c2aeb0SSepherosa Ziehau 		       BCE_PCICFG_INT_ACK_CMD_INDEX_VALID |
4636b42386eeSSepherosa Ziehau 		       BCE_PCICFG_INT_ACK_CMD_MASK_INT |
4637b42386eeSSepherosa Ziehau 		       rxr->last_status_idx);
4638b42386eeSSepherosa Ziehau 		REG_WR(sc, BCE_PCICFG_INT_ACK_CMD, (rxr->idx << 24) |
4639b42386eeSSepherosa Ziehau 		       BCE_PCICFG_INT_ACK_CMD_INDEX_VALID |
4640b42386eeSSepherosa Ziehau 		       rxr->last_status_idx);
4641b42386eeSSepherosa Ziehau 	}
4642d4274f6bSSepherosa Ziehau 	REG_WR(sc, BCE_HC_COMMAND, sc->hc_command | BCE_HC_COMMAND_COAL_NOW);
464328ef7645SSepherosa Ziehau 
464428ef7645SSepherosa Ziehau 	if (sc->bce_flags & BCE_CHECK_MSI_FLAG) {
464528ef7645SSepherosa Ziehau 		sc->bce_msi_maylose = FALSE;
464628ef7645SSepherosa Ziehau 		sc->bce_check_rx_cons = 0;
464728ef7645SSepherosa Ziehau 		sc->bce_check_tx_cons = 0;
464828ef7645SSepherosa Ziehau 		sc->bce_check_status_idx = 0xffff;
464928ef7645SSepherosa Ziehau 
465028ef7645SSepherosa Ziehau 		if (bootverbose)
465128ef7645SSepherosa Ziehau 			if_printf(&sc->arpcom.ac_if, "check msi\n");
465228ef7645SSepherosa Ziehau 
465328ef7645SSepherosa Ziehau 		callout_reset_bycpu(&sc->bce_ckmsi_callout, BCE_MSI_CKINTVL,
4654b42386eeSSepherosa Ziehau 		    bce_check_msi, sc, sc->bce_msix[0].msix_cpuid);
465528ef7645SSepherosa Ziehau 	}
465643c2aeb0SSepherosa Ziehau }
465743c2aeb0SSepherosa Ziehau 
465843c2aeb0SSepherosa Ziehau /****************************************************************************/
4659d4274f6bSSepherosa Ziehau /* Reenables interrupt generation during interrupt handling.                */
4660d4274f6bSSepherosa Ziehau /*                                                                          */
4661d4274f6bSSepherosa Ziehau /* Returns:                                                                 */
4662d4274f6bSSepherosa Ziehau /*   Nothing.                                                               */
4663d4274f6bSSepherosa Ziehau /****************************************************************************/
4664d4274f6bSSepherosa Ziehau static void
bce_reenable_intr(struct bce_rx_ring * rxr)4665ba268ba5SSepherosa Ziehau bce_reenable_intr(struct bce_rx_ring *rxr)
4666d4274f6bSSepherosa Ziehau {
4667b42386eeSSepherosa Ziehau 	REG_WR(rxr->sc, BCE_PCICFG_INT_ACK_CMD, (rxr->idx << 24) |
4668ba268ba5SSepherosa Ziehau 	       BCE_PCICFG_INT_ACK_CMD_INDEX_VALID | rxr->last_status_idx);
4669d4274f6bSSepherosa Ziehau }
4670d4274f6bSSepherosa Ziehau 
4671d4274f6bSSepherosa Ziehau /****************************************************************************/
467243c2aeb0SSepherosa Ziehau /* Handles controller initialization.                                       */
467343c2aeb0SSepherosa Ziehau /*                                                                          */
467443c2aeb0SSepherosa Ziehau /* Returns:                                                                 */
467543c2aeb0SSepherosa Ziehau /*   Nothing.                                                               */
467643c2aeb0SSepherosa Ziehau /****************************************************************************/
467743c2aeb0SSepherosa Ziehau static void
bce_init(void * xsc)467843c2aeb0SSepherosa Ziehau bce_init(void *xsc)
467943c2aeb0SSepherosa Ziehau {
468043c2aeb0SSepherosa Ziehau 	struct bce_softc *sc = xsc;
468143c2aeb0SSepherosa Ziehau 	struct ifnet *ifp = &sc->arpcom.ac_if;
468243c2aeb0SSepherosa Ziehau 	uint32_t ether_mtu;
468310bcbdabSSepherosa Ziehau 	int error, i;
4684745b3d68SSepherosa Ziehau 	boolean_t polling;
468543c2aeb0SSepherosa Ziehau 
468684464af5SSepherosa Ziehau 	ASSERT_IFNET_SERIALIZED_ALL(ifp);
468743c2aeb0SSepherosa Ziehau 
468843c2aeb0SSepherosa Ziehau 	/* Check if the driver is still running and bail out if it is. */
468943c2aeb0SSepherosa Ziehau 	if (ifp->if_flags & IFF_RUNNING)
469043c2aeb0SSepherosa Ziehau 		return;
469143c2aeb0SSepherosa Ziehau 
469243c2aeb0SSepherosa Ziehau 	bce_stop(sc);
469343c2aeb0SSepherosa Ziehau 
469443c2aeb0SSepherosa Ziehau 	error = bce_reset(sc, BCE_DRV_MSG_CODE_RESET);
469543c2aeb0SSepherosa Ziehau 	if (error) {
469643c2aeb0SSepherosa Ziehau 		if_printf(ifp, "Controller reset failed!\n");
469743c2aeb0SSepherosa Ziehau 		goto back;
469843c2aeb0SSepherosa Ziehau 	}
469943c2aeb0SSepherosa Ziehau 
470043c2aeb0SSepherosa Ziehau 	error = bce_chipinit(sc);
470143c2aeb0SSepherosa Ziehau 	if (error) {
470243c2aeb0SSepherosa Ziehau 		if_printf(ifp, "Controller initialization failed!\n");
470343c2aeb0SSepherosa Ziehau 		goto back;
470443c2aeb0SSepherosa Ziehau 	}
470543c2aeb0SSepherosa Ziehau 
470643c2aeb0SSepherosa Ziehau 	error = bce_blockinit(sc);
470743c2aeb0SSepherosa Ziehau 	if (error) {
470843c2aeb0SSepherosa Ziehau 		if_printf(ifp, "Block initialization failed!\n");
470943c2aeb0SSepherosa Ziehau 		goto back;
471043c2aeb0SSepherosa Ziehau 	}
471143c2aeb0SSepherosa Ziehau 
471243c2aeb0SSepherosa Ziehau 	/* Load our MAC address. */
471343c2aeb0SSepherosa Ziehau 	bcopy(IF_LLADDR(ifp), sc->eaddr, ETHER_ADDR_LEN);
471443c2aeb0SSepherosa Ziehau 	bce_set_mac_addr(sc);
471543c2aeb0SSepherosa Ziehau 
471643c2aeb0SSepherosa Ziehau 	/* Calculate and program the Ethernet MTU size. */
471743c2aeb0SSepherosa Ziehau 	ether_mtu = ETHER_HDR_LEN + EVL_ENCAPLEN + ifp->if_mtu + ETHER_CRC_LEN;
471843c2aeb0SSepherosa Ziehau 
471943c2aeb0SSepherosa Ziehau 	/*
472043c2aeb0SSepherosa Ziehau 	 * Program the mtu, enabling jumbo frame
472143c2aeb0SSepherosa Ziehau 	 * support if necessary.  Also set the mbuf
472243c2aeb0SSepherosa Ziehau 	 * allocation count for RX frames.
472343c2aeb0SSepherosa Ziehau 	 */
472443c2aeb0SSepherosa Ziehau 	if (ether_mtu > ETHER_MAX_LEN + EVL_ENCAPLEN) {
472543c2aeb0SSepherosa Ziehau #ifdef notyet
472643c2aeb0SSepherosa Ziehau 		REG_WR(sc, BCE_EMAC_RX_MTU_SIZE,
472743c2aeb0SSepherosa Ziehau 		       min(ether_mtu, BCE_MAX_JUMBO_ETHER_MTU) |
472843c2aeb0SSepherosa Ziehau 		       BCE_EMAC_RX_MTU_SIZE_JUMBO_ENA);
472943c2aeb0SSepherosa Ziehau #else
4730ed20d0e3SSascha Wildner 		panic("jumbo buffer is not supported yet");
473143c2aeb0SSepherosa Ziehau #endif
473243c2aeb0SSepherosa Ziehau 	} else {
473343c2aeb0SSepherosa Ziehau 		REG_WR(sc, BCE_EMAC_RX_MTU_SIZE, ether_mtu);
473443c2aeb0SSepherosa Ziehau 	}
473543c2aeb0SSepherosa Ziehau 
473643c2aeb0SSepherosa Ziehau 	/* Program appropriate promiscuous/multicast filtering. */
473743c2aeb0SSepherosa Ziehau 	bce_set_rx_mode(sc);
473843c2aeb0SSepherosa Ziehau 
4739b42386eeSSepherosa Ziehau 	/*
4740b42386eeSSepherosa Ziehau 	 * Init RX buffer descriptor chain.
4741b42386eeSSepherosa Ziehau 	 */
4742b42386eeSSepherosa Ziehau 	REG_WR(sc, BCE_RLUP_RSS_CONFIG, 0);
4743b42386eeSSepherosa Ziehau 	bce_reg_wr_ind(sc, BCE_RXP_SCRATCH_RSS_TBL_SZ, 0);
4744b42386eeSSepherosa Ziehau 
4745ac2202eaSSepherosa Ziehau 	for (i = 0; i < sc->rx_ring_cnt; ++i)
474608b64767SSepherosa Ziehau 		bce_init_rx_chain(&sc->rx_rings[i]);	/* XXX return value */
474743c2aeb0SSepherosa Ziehau 
4748b42386eeSSepherosa Ziehau 	if (sc->rx_ring_cnt > 1)
4749b42386eeSSepherosa Ziehau 		bce_init_rss(sc);
4750b42386eeSSepherosa Ziehau 
4751b42386eeSSepherosa Ziehau 	/*
4752b42386eeSSepherosa Ziehau 	 * Init TX buffer descriptor chain.
4753b42386eeSSepherosa Ziehau 	 */
4754b42386eeSSepherosa Ziehau 	REG_WR(sc, BCE_TSCH_TSS_CFG, 0);
4755b42386eeSSepherosa Ziehau 
4756ac2202eaSSepherosa Ziehau 	for (i = 0; i < sc->tx_ring_cnt; ++i)
475710bcbdabSSepherosa Ziehau 		bce_init_tx_chain(&sc->tx_rings[i]);
475843c2aeb0SSepherosa Ziehau 
4759b42386eeSSepherosa Ziehau 	if (sc->tx_ring_cnt > 1) {
4760b42386eeSSepherosa Ziehau 		REG_WR(sc, BCE_TSCH_TSS_CFG,
4761b42386eeSSepherosa Ziehau 		    ((sc->tx_ring_cnt - 1) << 24) | (TX_TSS_CID << 7));
4762b42386eeSSepherosa Ziehau 	}
4763b42386eeSSepherosa Ziehau 
4764745b3d68SSepherosa Ziehau 	polling = FALSE;
47654a331bf7SSepherosa Ziehau #ifdef IFPOLL_ENABLE
4766745b3d68SSepherosa Ziehau 	if (ifp->if_flags & IFF_NPOLLING)
4767745b3d68SSepherosa Ziehau 		polling = TRUE;
4768745b3d68SSepherosa Ziehau #endif
4769745b3d68SSepherosa Ziehau 
4770745b3d68SSepherosa Ziehau 	if (polling) {
477143c2aeb0SSepherosa Ziehau 		/* Disable interrupts if we are polling. */
477243c2aeb0SSepherosa Ziehau 		bce_disable_intr(sc);
477343c2aeb0SSepherosa Ziehau 
4774b42386eeSSepherosa Ziehau 		/* Change coalesce parameters */
4775b42386eeSSepherosa Ziehau 		bce_npoll_coal_change(sc);
4776745b3d68SSepherosa Ziehau 	} else {
477743c2aeb0SSepherosa Ziehau 		/* Enable host interrupts. */
4778d4274f6bSSepherosa Ziehau 		bce_enable_intr(sc);
4779745b3d68SSepherosa Ziehau 	}
4780745b3d68SSepherosa Ziehau 	bce_set_timer_cpuid(sc, polling);
478143c2aeb0SSepherosa Ziehau 
478243c2aeb0SSepherosa Ziehau 	bce_ifmedia_upd(ifp);
478343c2aeb0SSepherosa Ziehau 
478443c2aeb0SSepherosa Ziehau 	ifp->if_flags |= IFF_RUNNING;
4785ac2202eaSSepherosa Ziehau 	for (i = 0; i < sc->tx_ring_cnt; ++i) {
4786f774fa0fSSepherosa Ziehau 		ifsq_clr_oactive(sc->tx_rings[i].ifsq);
4787f774fa0fSSepherosa Ziehau 		ifsq_watchdog_start(&sc->tx_rings[i].tx_watchdog);
4788f774fa0fSSepherosa Ziehau 	}
478943c2aeb0SSepherosa Ziehau 
4790a131f6c2SSepherosa Ziehau 	callout_reset_bycpu(&sc->bce_tick_callout, hz, bce_tick, sc,
4791745b3d68SSepherosa Ziehau 	    sc->bce_timer_cpuid);
479243c2aeb0SSepherosa Ziehau back:
479343c2aeb0SSepherosa Ziehau 	if (error)
479443c2aeb0SSepherosa Ziehau 		bce_stop(sc);
479543c2aeb0SSepherosa Ziehau }
479643c2aeb0SSepherosa Ziehau 
479743c2aeb0SSepherosa Ziehau /****************************************************************************/
479843c2aeb0SSepherosa Ziehau /* Initialize the controller just enough so that any management firmware    */
479943c2aeb0SSepherosa Ziehau /* running on the device will continue to operate corectly.                 */
480043c2aeb0SSepherosa Ziehau /*                                                                          */
480143c2aeb0SSepherosa Ziehau /* Returns:                                                                 */
480243c2aeb0SSepherosa Ziehau /*   Nothing.                                                               */
480343c2aeb0SSepherosa Ziehau /****************************************************************************/
480443c2aeb0SSepherosa Ziehau static void
bce_mgmt_init(struct bce_softc * sc)480543c2aeb0SSepherosa Ziehau bce_mgmt_init(struct bce_softc *sc)
480643c2aeb0SSepherosa Ziehau {
480743c2aeb0SSepherosa Ziehau 	struct ifnet *ifp = &sc->arpcom.ac_if;
480843c2aeb0SSepherosa Ziehau 
4809d0092544SSepherosa Ziehau 	/* Bail out if management firmware is not running. */
4810d0092544SSepherosa Ziehau 	if (!(sc->bce_flags & BCE_MFW_ENABLE_FLAG))
481143c2aeb0SSepherosa Ziehau 		return;
481243c2aeb0SSepherosa Ziehau 
481343c2aeb0SSepherosa Ziehau 	/* Enable all critical blocks in the MAC. */
4814d0092544SSepherosa Ziehau 	if (BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5709 ||
4815d0092544SSepherosa Ziehau 	    BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5716) {
481643c2aeb0SSepherosa Ziehau 		REG_WR(sc, BCE_MISC_ENABLE_SET_BITS,
4817d0092544SSepherosa Ziehau 		    BCE_MISC_ENABLE_DEFAULT_XI);
4818d0092544SSepherosa Ziehau 	} else {
4819d0092544SSepherosa Ziehau 		REG_WR(sc, BCE_MISC_ENABLE_SET_BITS, BCE_MISC_ENABLE_DEFAULT);
4820d0092544SSepherosa Ziehau 	}
482143c2aeb0SSepherosa Ziehau 	REG_RD(sc, BCE_MISC_ENABLE_SET_BITS);
482243c2aeb0SSepherosa Ziehau 	DELAY(20);
482343c2aeb0SSepherosa Ziehau 
482443c2aeb0SSepherosa Ziehau 	bce_ifmedia_upd(ifp);
482543c2aeb0SSepherosa Ziehau }
482643c2aeb0SSepherosa Ziehau 
482743c2aeb0SSepherosa Ziehau /****************************************************************************/
482843c2aeb0SSepherosa Ziehau /* Encapsultes an mbuf cluster into the tx_bd chain structure and makes the */
482943c2aeb0SSepherosa Ziehau /* memory visible to the controller.                                        */
483043c2aeb0SSepherosa Ziehau /*                                                                          */
483143c2aeb0SSepherosa Ziehau /* Returns:                                                                 */
483243c2aeb0SSepherosa Ziehau /*   0 for success, positive value for failure.                             */
483343c2aeb0SSepherosa Ziehau /****************************************************************************/
483443c2aeb0SSepherosa Ziehau static int
bce_encap(struct bce_tx_ring * txr,struct mbuf ** m_head,int * nsegs_used)483510bcbdabSSepherosa Ziehau bce_encap(struct bce_tx_ring *txr, struct mbuf **m_head, int *nsegs_used)
483643c2aeb0SSepherosa Ziehau {
483743c2aeb0SSepherosa Ziehau 	bus_dma_segment_t segs[BCE_MAX_SEGMENTS];
483843c2aeb0SSepherosa Ziehau 	bus_dmamap_t map, tmp_map;
483943c2aeb0SSepherosa Ziehau 	struct mbuf *m0 = *m_head;
484043c2aeb0SSepherosa Ziehau 	struct tx_bd *txbd = NULL;
4841eefd160dSSepherosa Ziehau 	uint16_t vlan_tag = 0, flags = 0, mss = 0;
484243c2aeb0SSepherosa Ziehau 	uint16_t chain_prod, chain_prod_start, prod;
484343c2aeb0SSepherosa Ziehau 	uint32_t prod_bseq;
4844ba0809ceSSepherosa Ziehau 	int i, error, maxsegs, nsegs;
484543c2aeb0SSepherosa Ziehau 
484643c2aeb0SSepherosa Ziehau 	/* Transfer any checksum offload flags to the bd. */
4847eefd160dSSepherosa Ziehau 	if (m0->m_pkthdr.csum_flags & CSUM_TSO) {
484810bcbdabSSepherosa Ziehau 		error = bce_tso_setup(txr, m_head, &flags, &mss);
4849eefd160dSSepherosa Ziehau 		if (error)
4850eefd160dSSepherosa Ziehau 			return ENOBUFS;
4851eefd160dSSepherosa Ziehau 		m0 = *m_head;
4852eefd160dSSepherosa Ziehau 	} else if (m0->m_pkthdr.csum_flags & BCE_CSUM_FEATURES) {
485343c2aeb0SSepherosa Ziehau 		if (m0->m_pkthdr.csum_flags & CSUM_IP)
485443c2aeb0SSepherosa Ziehau 			flags |= TX_BD_FLAGS_IP_CKSUM;
485543c2aeb0SSepherosa Ziehau 		if (m0->m_pkthdr.csum_flags & (CSUM_TCP | CSUM_UDP))
485643c2aeb0SSepherosa Ziehau 			flags |= TX_BD_FLAGS_TCP_UDP_CKSUM;
485743c2aeb0SSepherosa Ziehau 	}
485843c2aeb0SSepherosa Ziehau 
485943c2aeb0SSepherosa Ziehau 	/* Transfer any VLAN tags to the bd. */
486083790f85SSepherosa Ziehau 	if (m0->m_flags & M_VLANTAG) {
486143c2aeb0SSepherosa Ziehau 		flags |= TX_BD_FLAGS_VLAN_TAG;
486283790f85SSepherosa Ziehau 		vlan_tag = m0->m_pkthdr.ether_vlantag;
486343c2aeb0SSepherosa Ziehau 	}
486443c2aeb0SSepherosa Ziehau 
486510bcbdabSSepherosa Ziehau 	prod = txr->tx_prod;
486610bcbdabSSepherosa Ziehau 	chain_prod_start = chain_prod = TX_CHAIN_IDX(txr, prod);
486743c2aeb0SSepherosa Ziehau 
486843c2aeb0SSepherosa Ziehau 	/* Map the mbuf into DMAable memory. */
486986ae632dSSepherosa Ziehau 	map = txr->tx_bufs[chain_prod_start].tx_mbuf_map;
487043c2aeb0SSepherosa Ziehau 
487110bcbdabSSepherosa Ziehau 	maxsegs = txr->max_tx_bd - txr->used_tx_bd;
487243c2aeb0SSepherosa Ziehau 	KASSERT(maxsegs >= BCE_TX_SPARE_SPACE,
4873ed20d0e3SSascha Wildner 		("not enough segments %d", maxsegs));
487443c2aeb0SSepherosa Ziehau 	if (maxsegs > BCE_MAX_SEGMENTS)
487543c2aeb0SSepherosa Ziehau 		maxsegs = BCE_MAX_SEGMENTS;
487643c2aeb0SSepherosa Ziehau 
487743c2aeb0SSepherosa Ziehau 	/* Map the mbuf into our DMA address space. */
487810bcbdabSSepherosa Ziehau 	error = bus_dmamap_load_mbuf_defrag(txr->tx_mbuf_tag, map, m_head,
4879ba0809ceSSepherosa Ziehau 			segs, maxsegs, &nsegs, BUS_DMA_NOWAIT);
4880ba0809ceSSepherosa Ziehau 	if (error)
4881ba0809ceSSepherosa Ziehau 		goto back;
488210bcbdabSSepherosa Ziehau 	bus_dmamap_sync(txr->tx_mbuf_tag, map, BUS_DMASYNC_PREWRITE);
488343c2aeb0SSepherosa Ziehau 
4884f52858a0SSepherosa Ziehau 	*nsegs_used += nsegs;
4885f52858a0SSepherosa Ziehau 
4886ba0809ceSSepherosa Ziehau 	/* Reset m0 */
4887ba0809ceSSepherosa Ziehau 	m0 = *m_head;
488843c2aeb0SSepherosa Ziehau 
488943c2aeb0SSepherosa Ziehau 	/* prod points to an empty tx_bd at this point. */
489010bcbdabSSepherosa Ziehau 	prod_bseq  = txr->tx_prod_bseq;
489143c2aeb0SSepherosa Ziehau 
489243c2aeb0SSepherosa Ziehau 	/*
489343c2aeb0SSepherosa Ziehau 	 * Cycle through each mbuf segment that makes up
489443c2aeb0SSepherosa Ziehau 	 * the outgoing frame, gathering the mapping info
489543c2aeb0SSepherosa Ziehau 	 * for that segment and creating a tx_bd to for
489643c2aeb0SSepherosa Ziehau 	 * the mbuf.
489743c2aeb0SSepherosa Ziehau 	 */
4898ba0809ceSSepherosa Ziehau 	for (i = 0; i < nsegs; i++) {
489910bcbdabSSepherosa Ziehau 		chain_prod = TX_CHAIN_IDX(txr, prod);
490010bcbdabSSepherosa Ziehau 		txbd =
490110bcbdabSSepherosa Ziehau 		&txr->tx_bd_chain[TX_PAGE(chain_prod)][TX_IDX(chain_prod)];
490243c2aeb0SSepherosa Ziehau 
490343c2aeb0SSepherosa Ziehau 		txbd->tx_bd_haddr_lo = htole32(BCE_ADDR_LO(segs[i].ds_addr));
490443c2aeb0SSepherosa Ziehau 		txbd->tx_bd_haddr_hi = htole32(BCE_ADDR_HI(segs[i].ds_addr));
4905eefd160dSSepherosa Ziehau 		txbd->tx_bd_mss_nbytes = htole32(mss << 16) |
4906eefd160dSSepherosa Ziehau 		    htole16(segs[i].ds_len);
490743c2aeb0SSepherosa Ziehau 		txbd->tx_bd_vlan_tag = htole16(vlan_tag);
490843c2aeb0SSepherosa Ziehau 		txbd->tx_bd_flags = htole16(flags);
4909eefd160dSSepherosa Ziehau 
491043c2aeb0SSepherosa Ziehau 		prod_bseq += segs[i].ds_len;
491143c2aeb0SSepherosa Ziehau 		if (i == 0)
491243c2aeb0SSepherosa Ziehau 			txbd->tx_bd_flags |= htole16(TX_BD_FLAGS_START);
491343c2aeb0SSepherosa Ziehau 		prod = NEXT_TX_BD(prod);
491443c2aeb0SSepherosa Ziehau 	}
491543c2aeb0SSepherosa Ziehau 
491643c2aeb0SSepherosa Ziehau 	/* Set the END flag on the last TX buffer descriptor. */
491743c2aeb0SSepherosa Ziehau 	txbd->tx_bd_flags |= htole16(TX_BD_FLAGS_END);
491843c2aeb0SSepherosa Ziehau 
491943c2aeb0SSepherosa Ziehau 	/*
492043c2aeb0SSepherosa Ziehau 	 * Ensure that the mbuf pointer for this transmission
492143c2aeb0SSepherosa Ziehau 	 * is placed at the array index of the last
492243c2aeb0SSepherosa Ziehau 	 * descriptor in this chain.  This is done
492343c2aeb0SSepherosa Ziehau 	 * because a single map is used for all
492443c2aeb0SSepherosa Ziehau 	 * segments of the mbuf and we don't want to
492543c2aeb0SSepherosa Ziehau 	 * unload the map before all of the segments
492643c2aeb0SSepherosa Ziehau 	 * have been freed.
492743c2aeb0SSepherosa Ziehau 	 */
492886ae632dSSepherosa Ziehau 	txr->tx_bufs[chain_prod].tx_mbuf_ptr = m0;
492943c2aeb0SSepherosa Ziehau 
493086ae632dSSepherosa Ziehau 	tmp_map = txr->tx_bufs[chain_prod].tx_mbuf_map;
493186ae632dSSepherosa Ziehau 	txr->tx_bufs[chain_prod].tx_mbuf_map = map;
493286ae632dSSepherosa Ziehau 	txr->tx_bufs[chain_prod_start].tx_mbuf_map = tmp_map;
493343c2aeb0SSepherosa Ziehau 
493410bcbdabSSepherosa Ziehau 	txr->used_tx_bd += nsegs;
493543c2aeb0SSepherosa Ziehau 
493643c2aeb0SSepherosa Ziehau 	/* prod points to the next free tx_bd at this point. */
493710bcbdabSSepherosa Ziehau 	txr->tx_prod = prod;
493810bcbdabSSepherosa Ziehau 	txr->tx_prod_bseq = prod_bseq;
493943c2aeb0SSepherosa Ziehau back:
494043c2aeb0SSepherosa Ziehau 	if (error) {
494143c2aeb0SSepherosa Ziehau 		m_freem(*m_head);
494243c2aeb0SSepherosa Ziehau 		*m_head = NULL;
494343c2aeb0SSepherosa Ziehau 	}
494443c2aeb0SSepherosa Ziehau 	return error;
494543c2aeb0SSepherosa Ziehau }
494643c2aeb0SSepherosa Ziehau 
494734483efcSSepherosa Ziehau static void
bce_xmit(struct bce_tx_ring * txr)494810bcbdabSSepherosa Ziehau bce_xmit(struct bce_tx_ring *txr)
494934483efcSSepherosa Ziehau {
495034483efcSSepherosa Ziehau 	/* Start the transmit. */
49510080c09fSSepherosa Ziehau 	REG_WR16(txr->sc, MB_GET_CID_ADDR(txr->tx_cid) + BCE_L2CTX_TX_HOST_BIDX,
495210bcbdabSSepherosa Ziehau 	    txr->tx_prod);
49530080c09fSSepherosa Ziehau 	REG_WR(txr->sc, MB_GET_CID_ADDR(txr->tx_cid) + BCE_L2CTX_TX_HOST_BSEQ,
495410bcbdabSSepherosa Ziehau 	    txr->tx_prod_bseq);
495534483efcSSepherosa Ziehau }
495634483efcSSepherosa Ziehau 
495743c2aeb0SSepherosa Ziehau /****************************************************************************/
495843c2aeb0SSepherosa Ziehau /* Main transmit routine when called from another routine with a lock.      */
495943c2aeb0SSepherosa Ziehau /*                                                                          */
496043c2aeb0SSepherosa Ziehau /* Returns:                                                                 */
496143c2aeb0SSepherosa Ziehau /*   Nothing.                                                               */
496243c2aeb0SSepherosa Ziehau /****************************************************************************/
496343c2aeb0SSepherosa Ziehau static void
bce_start(struct ifnet * ifp,struct ifaltq_subque * ifsq)4964f0a26983SSepherosa Ziehau bce_start(struct ifnet *ifp, struct ifaltq_subque *ifsq)
496543c2aeb0SSepherosa Ziehau {
496643c2aeb0SSepherosa Ziehau 	struct bce_softc *sc = ifp->if_softc;
4967f774fa0fSSepherosa Ziehau 	struct bce_tx_ring *txr = ifsq_get_priv(ifsq);
496843c2aeb0SSepherosa Ziehau 	int count = 0;
496943c2aeb0SSepherosa Ziehau 
4970f774fa0fSSepherosa Ziehau 	KKASSERT(txr->ifsq == ifsq);
497184464af5SSepherosa Ziehau 	ASSERT_SERIALIZED(&txr->tx_serialize);
497243c2aeb0SSepherosa Ziehau 
497343c2aeb0SSepherosa Ziehau 	/* If there's no link or the transmit queue is empty then just exit. */
49749db4b353SSepherosa Ziehau 	if (!sc->bce_link) {
4975f774fa0fSSepherosa Ziehau 		ifsq_purge(ifsq);
49769db4b353SSepherosa Ziehau 		return;
49779db4b353SSepherosa Ziehau 	}
49789db4b353SSepherosa Ziehau 
4979f774fa0fSSepherosa Ziehau 	if ((ifp->if_flags & IFF_RUNNING) == 0 || ifsq_is_oactive(ifsq))
498043c2aeb0SSepherosa Ziehau 		return;
498143c2aeb0SSepherosa Ziehau 
498243c2aeb0SSepherosa Ziehau 	for (;;) {
498343c2aeb0SSepherosa Ziehau 		struct mbuf *m_head;
498443c2aeb0SSepherosa Ziehau 
498543c2aeb0SSepherosa Ziehau 		/*
498643c2aeb0SSepherosa Ziehau 		 * We keep BCE_TX_SPARE_SPACE entries, so bce_encap() is
498743c2aeb0SSepherosa Ziehau 		 * unlikely to fail.
498843c2aeb0SSepherosa Ziehau 		 */
498910bcbdabSSepherosa Ziehau 		if (txr->max_tx_bd - txr->used_tx_bd < BCE_TX_SPARE_SPACE) {
4990f774fa0fSSepherosa Ziehau 			ifsq_set_oactive(ifsq);
499143c2aeb0SSepherosa Ziehau 			break;
499243c2aeb0SSepherosa Ziehau 		}
499343c2aeb0SSepherosa Ziehau 
499443c2aeb0SSepherosa Ziehau 		/* Check for any frames to send. */
4995ac9843a1SSepherosa Ziehau 		m_head = ifsq_dequeue(ifsq);
499643c2aeb0SSepherosa Ziehau 		if (m_head == NULL)
499743c2aeb0SSepherosa Ziehau 			break;
499843c2aeb0SSepherosa Ziehau 
499943c2aeb0SSepherosa Ziehau 		/*
500043c2aeb0SSepherosa Ziehau 		 * Pack the data into the transmit ring. If we
500143c2aeb0SSepherosa Ziehau 		 * don't have room, place the mbuf back at the
500243c2aeb0SSepherosa Ziehau 		 * head of the queue and set the OACTIVE flag
500343c2aeb0SSepherosa Ziehau 		 * to wait for the NIC to drain the chain.
500443c2aeb0SSepherosa Ziehau 		 */
500510bcbdabSSepherosa Ziehau 		if (bce_encap(txr, &m_head, &count)) {
5006d40991efSSepherosa Ziehau 			IFNET_STAT_INC(ifp, oerrors, 1);
500710bcbdabSSepherosa Ziehau 			if (txr->used_tx_bd == 0) {
5008ba0809ceSSepherosa Ziehau 				continue;
5009ba0809ceSSepherosa Ziehau 			} else {
5010f774fa0fSSepherosa Ziehau 				ifsq_set_oactive(ifsq);
501143c2aeb0SSepherosa Ziehau 				break;
501243c2aeb0SSepherosa Ziehau 			}
5013ba0809ceSSepherosa Ziehau 		}
501443c2aeb0SSepherosa Ziehau 
501510bcbdabSSepherosa Ziehau 		if (count >= txr->tx_wreg) {
501610bcbdabSSepherosa Ziehau 			bce_xmit(txr);
5017f52858a0SSepherosa Ziehau 			count = 0;
5018f52858a0SSepherosa Ziehau 		}
501943c2aeb0SSepherosa Ziehau 
502043c2aeb0SSepherosa Ziehau 		/* Send a copy of the frame to any BPF listeners. */
5021b637f170SSepherosa Ziehau 		ETHER_BPF_MTAP(ifp, m_head);
5022f52858a0SSepherosa Ziehau 
5023f52858a0SSepherosa Ziehau 		/* Set the tx timeout. */
5024e2292763SMatthew Dillon 		ifsq_watchdog_set_count(&txr->tx_watchdog, BCE_TX_TIMEOUT);
502543c2aeb0SSepherosa Ziehau 	}
502634483efcSSepherosa Ziehau 	if (count > 0)
502710bcbdabSSepherosa Ziehau 		bce_xmit(txr);
502843c2aeb0SSepherosa Ziehau }
502943c2aeb0SSepherosa Ziehau 
503043c2aeb0SSepherosa Ziehau /****************************************************************************/
503143c2aeb0SSepherosa Ziehau /* Handles any IOCTL calls from the operating system.                       */
503243c2aeb0SSepherosa Ziehau /*                                                                          */
503343c2aeb0SSepherosa Ziehau /* Returns:                                                                 */
503443c2aeb0SSepherosa Ziehau /*   0 for success, positive value for failure.                             */
503543c2aeb0SSepherosa Ziehau /****************************************************************************/
503643c2aeb0SSepherosa Ziehau static int
bce_ioctl(struct ifnet * ifp,u_long command,caddr_t data,struct ucred * cr)503743c2aeb0SSepherosa Ziehau bce_ioctl(struct ifnet *ifp, u_long command, caddr_t data, struct ucred *cr)
503843c2aeb0SSepherosa Ziehau {
503943c2aeb0SSepherosa Ziehau 	struct bce_softc *sc = ifp->if_softc;
504043c2aeb0SSepherosa Ziehau 	struct ifreq *ifr = (struct ifreq *)data;
504143c2aeb0SSepherosa Ziehau 	struct mii_data *mii;
504243c2aeb0SSepherosa Ziehau 	int mask, error = 0;
504343c2aeb0SSepherosa Ziehau 
504484464af5SSepherosa Ziehau 	ASSERT_IFNET_SERIALIZED_ALL(ifp);
504543c2aeb0SSepherosa Ziehau 
504643c2aeb0SSepherosa Ziehau 	switch(command) {
504743c2aeb0SSepherosa Ziehau 	case SIOCSIFMTU:
504843c2aeb0SSepherosa Ziehau 		/* Check that the MTU setting is supported. */
504943c2aeb0SSepherosa Ziehau 		if (ifr->ifr_mtu < BCE_MIN_MTU ||
505043c2aeb0SSepherosa Ziehau #ifdef notyet
505143c2aeb0SSepherosa Ziehau 		    ifr->ifr_mtu > BCE_MAX_JUMBO_MTU
505243c2aeb0SSepherosa Ziehau #else
505343c2aeb0SSepherosa Ziehau 		    ifr->ifr_mtu > ETHERMTU
505443c2aeb0SSepherosa Ziehau #endif
505543c2aeb0SSepherosa Ziehau 		   ) {
505643c2aeb0SSepherosa Ziehau 			error = EINVAL;
505743c2aeb0SSepherosa Ziehau 			break;
505843c2aeb0SSepherosa Ziehau 		}
505943c2aeb0SSepherosa Ziehau 
506043c2aeb0SSepherosa Ziehau 		ifp->if_mtu = ifr->ifr_mtu;
506143c2aeb0SSepherosa Ziehau 		ifp->if_flags &= ~IFF_RUNNING;	/* Force reinitialize */
506243c2aeb0SSepherosa Ziehau 		bce_init(sc);
506343c2aeb0SSepherosa Ziehau 		break;
506443c2aeb0SSepherosa Ziehau 
506543c2aeb0SSepherosa Ziehau 	case SIOCSIFFLAGS:
506643c2aeb0SSepherosa Ziehau 		if (ifp->if_flags & IFF_UP) {
506743c2aeb0SSepherosa Ziehau 			if (ifp->if_flags & IFF_RUNNING) {
506843c2aeb0SSepherosa Ziehau 				mask = ifp->if_flags ^ sc->bce_if_flags;
506943c2aeb0SSepherosa Ziehau 
507043c2aeb0SSepherosa Ziehau 				if (mask & (IFF_PROMISC | IFF_ALLMULTI))
507143c2aeb0SSepherosa Ziehau 					bce_set_rx_mode(sc);
507243c2aeb0SSepherosa Ziehau 			} else {
507343c2aeb0SSepherosa Ziehau 				bce_init(sc);
507443c2aeb0SSepherosa Ziehau 			}
507543c2aeb0SSepherosa Ziehau 		} else if (ifp->if_flags & IFF_RUNNING) {
507643c2aeb0SSepherosa Ziehau 			bce_stop(sc);
5077d0092544SSepherosa Ziehau 
5078d0092544SSepherosa Ziehau 			/* If MFW is running, restart the controller a bit. */
5079d0092544SSepherosa Ziehau 			if (sc->bce_flags & BCE_MFW_ENABLE_FLAG) {
5080d0092544SSepherosa Ziehau 				bce_reset(sc, BCE_DRV_MSG_CODE_RESET);
5081d0092544SSepherosa Ziehau 				bce_chipinit(sc);
5082d0092544SSepherosa Ziehau 				bce_mgmt_init(sc);
5083d0092544SSepherosa Ziehau 			}
508443c2aeb0SSepherosa Ziehau 		}
508543c2aeb0SSepherosa Ziehau 		sc->bce_if_flags = ifp->if_flags;
508643c2aeb0SSepherosa Ziehau 		break;
508743c2aeb0SSepherosa Ziehau 
508843c2aeb0SSepherosa Ziehau 	case SIOCADDMULTI:
508943c2aeb0SSepherosa Ziehau 	case SIOCDELMULTI:
509043c2aeb0SSepherosa Ziehau 		if (ifp->if_flags & IFF_RUNNING)
509143c2aeb0SSepherosa Ziehau 			bce_set_rx_mode(sc);
509243c2aeb0SSepherosa Ziehau 		break;
509343c2aeb0SSepherosa Ziehau 
509443c2aeb0SSepherosa Ziehau 	case SIOCSIFMEDIA:
509543c2aeb0SSepherosa Ziehau 	case SIOCGIFMEDIA:
509643c2aeb0SSepherosa Ziehau 		mii = device_get_softc(sc->bce_miibus);
509743c2aeb0SSepherosa Ziehau 		error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command);
509843c2aeb0SSepherosa Ziehau 		break;
509943c2aeb0SSepherosa Ziehau 
510043c2aeb0SSepherosa Ziehau 	case SIOCSIFCAP:
510143c2aeb0SSepherosa Ziehau 		mask = ifr->ifr_reqcap ^ ifp->if_capenable;
510243c2aeb0SSepherosa Ziehau 		if (mask & IFCAP_HWCSUM) {
510371e2c3e7SSepherosa Ziehau 			ifp->if_capenable ^= (mask & IFCAP_HWCSUM);
5104eefd160dSSepherosa Ziehau 			if (ifp->if_capenable & IFCAP_TXCSUM)
5105eefd160dSSepherosa Ziehau 				ifp->if_hwassist |= BCE_CSUM_FEATURES;
510643c2aeb0SSepherosa Ziehau 			else
5107eefd160dSSepherosa Ziehau 				ifp->if_hwassist &= ~BCE_CSUM_FEATURES;
5108eefd160dSSepherosa Ziehau 		}
5109eefd160dSSepherosa Ziehau 		if (mask & IFCAP_TSO) {
5110eefd160dSSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_TSO;
5111eefd160dSSepherosa Ziehau 			if (ifp->if_capenable & IFCAP_TSO)
5112eefd160dSSepherosa Ziehau 				ifp->if_hwassist |= CSUM_TSO;
5113eefd160dSSepherosa Ziehau 			else
5114eefd160dSSepherosa Ziehau 				ifp->if_hwassist &= ~CSUM_TSO;
511543c2aeb0SSepherosa Ziehau 		}
511642ad0e07SSepherosa Ziehau 		if (mask & IFCAP_RSS)
511742ad0e07SSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_RSS;
511843c2aeb0SSepherosa Ziehau 		break;
511943c2aeb0SSepherosa Ziehau 
512043c2aeb0SSepherosa Ziehau 	default:
512143c2aeb0SSepherosa Ziehau 		error = ether_ioctl(ifp, command, data);
512243c2aeb0SSepherosa Ziehau 		break;
512343c2aeb0SSepherosa Ziehau 	}
512443c2aeb0SSepherosa Ziehau 	return error;
512543c2aeb0SSepherosa Ziehau }
512643c2aeb0SSepherosa Ziehau 
512743c2aeb0SSepherosa Ziehau /****************************************************************************/
512843c2aeb0SSepherosa Ziehau /* Transmit timeout handler.                                                */
512943c2aeb0SSepherosa Ziehau /*                                                                          */
513043c2aeb0SSepherosa Ziehau /* Returns:                                                                 */
513143c2aeb0SSepherosa Ziehau /*   Nothing.                                                               */
513243c2aeb0SSepherosa Ziehau /****************************************************************************/
513343c2aeb0SSepherosa Ziehau static void
bce_watchdog(struct ifaltq_subque * ifsq)5134f774fa0fSSepherosa Ziehau bce_watchdog(struct ifaltq_subque *ifsq)
513543c2aeb0SSepherosa Ziehau {
5136f774fa0fSSepherosa Ziehau 	struct ifnet *ifp = ifsq_get_ifp(ifsq);
513743c2aeb0SSepherosa Ziehau 	struct bce_softc *sc = ifp->if_softc;
5138f774fa0fSSepherosa Ziehau 	int i;
513943c2aeb0SSepherosa Ziehau 
514084464af5SSepherosa Ziehau 	ASSERT_IFNET_SERIALIZED_ALL(ifp);
514143c2aeb0SSepherosa Ziehau 
514243c2aeb0SSepherosa Ziehau 	/*
514343c2aeb0SSepherosa Ziehau 	 * If we are in this routine because of pause frames, then
514443c2aeb0SSepherosa Ziehau 	 * don't reset the hardware.
514543c2aeb0SSepherosa Ziehau 	 */
514643c2aeb0SSepherosa Ziehau 	if (REG_RD(sc, BCE_EMAC_TX_STATUS) & BCE_EMAC_TX_STATUS_XOFFED)
514743c2aeb0SSepherosa Ziehau 		return;
514843c2aeb0SSepherosa Ziehau 
514943c2aeb0SSepherosa Ziehau 	if_printf(ifp, "Watchdog timeout occurred, resetting!\n");
515043c2aeb0SSepherosa Ziehau 
515143c2aeb0SSepherosa Ziehau 	ifp->if_flags &= ~IFF_RUNNING;	/* Force reinitialize */
515243c2aeb0SSepherosa Ziehau 	bce_init(sc);
515343c2aeb0SSepherosa Ziehau 
5154d40991efSSepherosa Ziehau 	IFNET_STAT_INC(ifp, oerrors, 1);
515543c2aeb0SSepherosa Ziehau 
5156ac2202eaSSepherosa Ziehau 	for (i = 0; i < sc->tx_ring_cnt; ++i)
5157f774fa0fSSepherosa Ziehau 		ifsq_devstart_sched(sc->tx_rings[i].ifsq);
515843c2aeb0SSepherosa Ziehau }
515943c2aeb0SSepherosa Ziehau 
51604a331bf7SSepherosa Ziehau #ifdef IFPOLL_ENABLE
516143c2aeb0SSepherosa Ziehau 
516243c2aeb0SSepherosa Ziehau static void
bce_npoll_status(struct ifnet * ifp)516357b3ecd9SSepherosa Ziehau bce_npoll_status(struct ifnet *ifp)
516443c2aeb0SSepherosa Ziehau {
516543c2aeb0SSepherosa Ziehau 	struct bce_softc *sc = ifp->if_softc;
516643c2aeb0SSepherosa Ziehau 	struct status_block *sblk = sc->status_block;
516743c2aeb0SSepherosa Ziehau 	uint32_t status_attn_bits;
516843c2aeb0SSepherosa Ziehau 
516957b3ecd9SSepherosa Ziehau 	ASSERT_SERIALIZED(&sc->main_serialize);
51704a331bf7SSepherosa Ziehau 
517143c2aeb0SSepherosa Ziehau 	status_attn_bits = sblk->status_attn_bits;
517243c2aeb0SSepherosa Ziehau 
517343c2aeb0SSepherosa Ziehau 	/* Was it a link change interrupt? */
517443c2aeb0SSepherosa Ziehau 	if ((status_attn_bits & STATUS_ATTN_BITS_LINK_STATE) !=
517557b3ecd9SSepherosa Ziehau 	    (sblk->status_attn_bits_ack & STATUS_ATTN_BITS_LINK_STATE)) {
517643c2aeb0SSepherosa Ziehau 		bce_phy_intr(sc);
517743c2aeb0SSepherosa Ziehau 
51786a8549eaSSepherosa Ziehau 		/*
51796a8549eaSSepherosa Ziehau 		 * Clear any transient status updates during link state change.
51806a8549eaSSepherosa Ziehau 		 */
5181d0092544SSepherosa Ziehau 		REG_WR(sc, BCE_HC_COMMAND,
5182d0092544SSepherosa Ziehau 		    sc->hc_command | BCE_HC_COMMAND_COAL_NOW_WO_INT);
5183d0092544SSepherosa Ziehau 		REG_RD(sc, BCE_HC_COMMAND);
518457b3ecd9SSepherosa Ziehau 	}
5185d0092544SSepherosa Ziehau 
518643c2aeb0SSepherosa Ziehau 	/*
51876a8549eaSSepherosa Ziehau 	 * If any other attention is asserted then the chip is toast.
518843c2aeb0SSepherosa Ziehau 	 */
518943c2aeb0SSepherosa Ziehau 	if ((status_attn_bits & ~STATUS_ATTN_BITS_LINK_STATE) !=
519057b3ecd9SSepherosa Ziehau 	     (sblk->status_attn_bits_ack & ~STATUS_ATTN_BITS_LINK_STATE)) {
519143c2aeb0SSepherosa Ziehau 		if_printf(ifp, "Fatal attention detected: 0x%08X\n",
519243c2aeb0SSepherosa Ziehau 		    sblk->status_attn_bits);
519384464af5SSepherosa Ziehau 		bce_serialize_skipmain(sc);
519443c2aeb0SSepherosa Ziehau 		bce_init(sc);
519584464af5SSepherosa Ziehau 		bce_deserialize_skipmain(sc);
519643c2aeb0SSepherosa Ziehau 	}
519743c2aeb0SSepherosa Ziehau }
519843c2aeb0SSepherosa Ziehau 
519957b3ecd9SSepherosa Ziehau static void
bce_npoll_rx(struct ifnet * ifp,void * arg,int count)520057b3ecd9SSepherosa Ziehau bce_npoll_rx(struct ifnet *ifp, void *arg, int count)
520157b3ecd9SSepherosa Ziehau {
520257b3ecd9SSepherosa Ziehau 	struct bce_rx_ring *rxr = arg;
520357b3ecd9SSepherosa Ziehau 	uint16_t hw_rx_cons;
520457b3ecd9SSepherosa Ziehau 
520557b3ecd9SSepherosa Ziehau 	ASSERT_SERIALIZED(&rxr->rx_serialize);
520657b3ecd9SSepherosa Ziehau 
520757b3ecd9SSepherosa Ziehau 	/*
520857b3ecd9SSepherosa Ziehau 	 * Save the status block index value for use when enabling
520957b3ecd9SSepherosa Ziehau 	 * the interrupt.
521057b3ecd9SSepherosa Ziehau 	 */
5211ba268ba5SSepherosa Ziehau 	rxr->last_status_idx = *rxr->hw_status_idx;
521257b3ecd9SSepherosa Ziehau 
521357b3ecd9SSepherosa Ziehau 	/* Make sure status index is extracted before RX/TX cons */
521457b3ecd9SSepherosa Ziehau 	cpu_lfence();
521557b3ecd9SSepherosa Ziehau 
52165abd7f19SSepherosa Ziehau 	hw_rx_cons = bce_get_hw_rx_cons(rxr);
521724603545SSepherosa Ziehau 
521843c2aeb0SSepherosa Ziehau 	/* Check for any completed RX frames. */
521908b64767SSepherosa Ziehau 	if (hw_rx_cons != rxr->rx_cons)
522008b64767SSepherosa Ziehau 		bce_rx_intr(rxr, count, hw_rx_cons);
522157b3ecd9SSepherosa Ziehau }
522257b3ecd9SSepherosa Ziehau 
522357b3ecd9SSepherosa Ziehau static void
bce_npoll_rx_pack(struct ifnet * ifp,void * arg,int count)5224b42386eeSSepherosa Ziehau bce_npoll_rx_pack(struct ifnet *ifp, void *arg, int count)
5225b42386eeSSepherosa Ziehau {
5226b42386eeSSepherosa Ziehau 	struct bce_rx_ring *rxr = arg;
5227b42386eeSSepherosa Ziehau 
5228b42386eeSSepherosa Ziehau 	KASSERT(rxr->idx == 0, ("not the first RX ring, but %d", rxr->idx));
5229b42386eeSSepherosa Ziehau 	bce_npoll_rx(ifp, rxr, count);
5230b42386eeSSepherosa Ziehau 
5231b42386eeSSepherosa Ziehau 	KASSERT(rxr->sc->rx_ring_cnt != rxr->sc->rx_ring_cnt2,
5232b42386eeSSepherosa Ziehau 	    ("RX ring count %d, count2 %d", rxr->sc->rx_ring_cnt,
5233b42386eeSSepherosa Ziehau 	     rxr->sc->rx_ring_cnt2));
5234b42386eeSSepherosa Ziehau 
5235b42386eeSSepherosa Ziehau 	/* Last ring carries packets whose masked hash is 0 */
5236b42386eeSSepherosa Ziehau 	rxr = &rxr->sc->rx_rings[rxr->sc->rx_ring_cnt - 1];
5237b42386eeSSepherosa Ziehau 
5238b42386eeSSepherosa Ziehau 	lwkt_serialize_enter(&rxr->rx_serialize);
5239b42386eeSSepherosa Ziehau 	bce_npoll_rx(ifp, rxr, count);
5240b42386eeSSepherosa Ziehau 	lwkt_serialize_exit(&rxr->rx_serialize);
5241b42386eeSSepherosa Ziehau }
5242b42386eeSSepherosa Ziehau 
5243b42386eeSSepherosa Ziehau static void
bce_npoll_tx(struct ifnet * ifp,void * arg,int count __unused)524457b3ecd9SSepherosa Ziehau bce_npoll_tx(struct ifnet *ifp, void *arg, int count __unused)
524557b3ecd9SSepherosa Ziehau {
524657b3ecd9SSepherosa Ziehau 	struct bce_tx_ring *txr = arg;
524757b3ecd9SSepherosa Ziehau 	uint16_t hw_tx_cons;
524857b3ecd9SSepherosa Ziehau 
524957b3ecd9SSepherosa Ziehau 	ASSERT_SERIALIZED(&txr->tx_serialize);
525057b3ecd9SSepherosa Ziehau 
52515abd7f19SSepherosa Ziehau 	hw_tx_cons = bce_get_hw_tx_cons(txr);
525243c2aeb0SSepherosa Ziehau 
525343c2aeb0SSepherosa Ziehau 	/* Check for any completed TX frames. */
525484464af5SSepherosa Ziehau 	if (hw_tx_cons != txr->tx_cons) {
525510bcbdabSSepherosa Ziehau 		bce_tx_intr(txr, hw_tx_cons);
5256f774fa0fSSepherosa Ziehau 		if (!ifsq_is_empty(txr->ifsq))
5257f774fa0fSSepherosa Ziehau 			ifsq_devstart(txr->ifsq);
525884464af5SSepherosa Ziehau 	}
525943c2aeb0SSepherosa Ziehau }
526043c2aeb0SSepherosa Ziehau 
52614a331bf7SSepherosa Ziehau static void
bce_npoll(struct ifnet * ifp,struct ifpoll_info * info)52624a331bf7SSepherosa Ziehau bce_npoll(struct ifnet *ifp, struct ifpoll_info *info)
52634a331bf7SSepherosa Ziehau {
52644a331bf7SSepherosa Ziehau 	struct bce_softc *sc = ifp->if_softc;
526557b3ecd9SSepherosa Ziehau 	int i;
52664a331bf7SSepherosa Ziehau 
526784464af5SSepherosa Ziehau 	ASSERT_IFNET_SERIALIZED_ALL(ifp);
52684a331bf7SSepherosa Ziehau 
52694a331bf7SSepherosa Ziehau 	if (info != NULL) {
527039ea245fSSepherosa Ziehau 		int cpu;
527139ea245fSSepherosa Ziehau 
527257b3ecd9SSepherosa Ziehau 		info->ifpi_status.status_func = bce_npoll_status;
527357b3ecd9SSepherosa Ziehau 		info->ifpi_status.serializer = &sc->main_serialize;
52744a331bf7SSepherosa Ziehau 
5275ac2202eaSSepherosa Ziehau 		for (i = 0; i < sc->tx_ring_cnt; ++i) {
527657b3ecd9SSepherosa Ziehau 			struct bce_tx_ring *txr = &sc->tx_rings[i];
527757b3ecd9SSepherosa Ziehau 
527839ea245fSSepherosa Ziehau 			cpu = if_ringmap_cpumap(sc->tx_rmap, i);
527939ea245fSSepherosa Ziehau 			KKASSERT(cpu < netisr_ncpus);
528039ea245fSSepherosa Ziehau 			info->ifpi_tx[cpu].poll_func = bce_npoll_tx;
528139ea245fSSepherosa Ziehau 			info->ifpi_tx[cpu].arg = txr;
528239ea245fSSepherosa Ziehau 			info->ifpi_tx[cpu].serializer = &txr->tx_serialize;
528339ea245fSSepherosa Ziehau 			ifsq_set_cpuid(txr->ifsq, cpu);
5284ac2202eaSSepherosa Ziehau 		}
528557b3ecd9SSepherosa Ziehau 
5286b42386eeSSepherosa Ziehau 		for (i = 0; i < sc->rx_ring_cnt2; ++i) {
5287ac2202eaSSepherosa Ziehau 			struct bce_rx_ring *rxr = &sc->rx_rings[i];
5288ac2202eaSSepherosa Ziehau 
528939ea245fSSepherosa Ziehau 			cpu = if_ringmap_cpumap(sc->rx_rmap, i);
529039ea245fSSepherosa Ziehau 			KKASSERT(cpu < netisr_ncpus);
5291b42386eeSSepherosa Ziehau 			if (i == 0 && sc->rx_ring_cnt2 != sc->rx_ring_cnt) {
5292b42386eeSSepherosa Ziehau 				/*
5293b42386eeSSepherosa Ziehau 				 * If RSS is enabled, the packets whose
5294b42386eeSSepherosa Ziehau 				 * masked hash are 0 are queued to the
5295b42386eeSSepherosa Ziehau 				 * last RX ring; piggyback the last RX
5296b42386eeSSepherosa Ziehau 				 * ring's processing in the first RX
5297b42386eeSSepherosa Ziehau 				 * polling handler. (see also: comment
5298b42386eeSSepherosa Ziehau 				 * in bce_setup_ring_cnt())
5299b42386eeSSepherosa Ziehau 				 */
5300b42386eeSSepherosa Ziehau 				if (bootverbose) {
5301b42386eeSSepherosa Ziehau 					if_printf(ifp, "npoll pack last "
530239ea245fSSepherosa Ziehau 					    "RX ring on cpu%d\n", cpu);
5303b42386eeSSepherosa Ziehau 				}
530439ea245fSSepherosa Ziehau 				info->ifpi_rx[cpu].poll_func =
5305b42386eeSSepherosa Ziehau 				    bce_npoll_rx_pack;
5306b42386eeSSepherosa Ziehau 			} else {
530739ea245fSSepherosa Ziehau 				info->ifpi_rx[cpu].poll_func = bce_npoll_rx;
5308b42386eeSSepherosa Ziehau 			}
530939ea245fSSepherosa Ziehau 			info->ifpi_rx[cpu].arg = rxr;
531039ea245fSSepherosa Ziehau 			info->ifpi_rx[cpu].serializer = &rxr->rx_serialize;
531157b3ecd9SSepherosa Ziehau 		}
53124a331bf7SSepherosa Ziehau 
53134a331bf7SSepherosa Ziehau 		if (ifp->if_flags & IFF_RUNNING) {
5314745b3d68SSepherosa Ziehau 			bce_set_timer_cpuid(sc, TRUE);
53154a331bf7SSepherosa Ziehau 			bce_disable_intr(sc);
5316b42386eeSSepherosa Ziehau 			bce_npoll_coal_change(sc);
53174a331bf7SSepherosa Ziehau 		}
53184a331bf7SSepherosa Ziehau 	} else {
5319ac2202eaSSepherosa Ziehau 		for (i = 0; i < sc->tx_ring_cnt; ++i) {
5320f774fa0fSSepherosa Ziehau 			ifsq_set_cpuid(sc->tx_rings[i].ifsq,
5321b42386eeSSepherosa Ziehau 			    sc->bce_msix[i].msix_cpuid);
5322f774fa0fSSepherosa Ziehau 		}
532357b3ecd9SSepherosa Ziehau 
53244a331bf7SSepherosa Ziehau 		if (ifp->if_flags & IFF_RUNNING) {
5325745b3d68SSepherosa Ziehau 			bce_set_timer_cpuid(sc, FALSE);
53264a331bf7SSepherosa Ziehau 			bce_enable_intr(sc);
53274a331bf7SSepherosa Ziehau 
5328b42386eeSSepherosa Ziehau 			sc->bce_coalchg_mask |= BCE_COALMASK_TX_BDS_INT |
5329b42386eeSSepherosa Ziehau 			    BCE_COALMASK_RX_BDS_INT;
5330b42386eeSSepherosa Ziehau 			bce_coal_change(sc);
53314a331bf7SSepherosa Ziehau 		}
53324a331bf7SSepherosa Ziehau 	}
53334a331bf7SSepherosa Ziehau }
53344a331bf7SSepherosa Ziehau 
53354a331bf7SSepherosa Ziehau #endif	/* IFPOLL_ENABLE */
533643c2aeb0SSepherosa Ziehau 
533743c2aeb0SSepherosa Ziehau /*
533843c2aeb0SSepherosa Ziehau  * Interrupt handler.
533943c2aeb0SSepherosa Ziehau  */
534043c2aeb0SSepherosa Ziehau /****************************************************************************/
534143c2aeb0SSepherosa Ziehau /* Main interrupt entry point.  Verifies that the controller generated the  */
534243c2aeb0SSepherosa Ziehau /* interrupt and then calls a separate routine for handle the various       */
534343c2aeb0SSepherosa Ziehau /* interrupt causes (PHY, TX, RX).                                          */
534443c2aeb0SSepherosa Ziehau /*                                                                          */
534543c2aeb0SSepherosa Ziehau /* Returns:                                                                 */
534643c2aeb0SSepherosa Ziehau /*   0 for success, positive value for failure.                             */
534743c2aeb0SSepherosa Ziehau /****************************************************************************/
534843c2aeb0SSepherosa Ziehau static void
bce_intr(struct bce_softc * sc)5349eac57ffbSSepherosa Ziehau bce_intr(struct bce_softc *sc)
535043c2aeb0SSepherosa Ziehau {
535143c2aeb0SSepherosa Ziehau 	struct ifnet *ifp = &sc->arpcom.ac_if;
535243c2aeb0SSepherosa Ziehau 	struct status_block *sblk;
535324603545SSepherosa Ziehau 	uint16_t hw_rx_cons, hw_tx_cons;
5354a5eaa4bfSSepherosa Ziehau 	uint32_t status_attn_bits;
535510bcbdabSSepherosa Ziehau 	struct bce_tx_ring *txr = &sc->tx_rings[0];
535608b64767SSepherosa Ziehau 	struct bce_rx_ring *rxr = &sc->rx_rings[0];
535743c2aeb0SSepherosa Ziehau 
535884464af5SSepherosa Ziehau 	ASSERT_SERIALIZED(&sc->main_serialize);
535943c2aeb0SSepherosa Ziehau 
536043c2aeb0SSepherosa Ziehau 	sblk = sc->status_block;
536143c2aeb0SSepherosa Ziehau 
5362a5eaa4bfSSepherosa Ziehau 	/*
5363a5eaa4bfSSepherosa Ziehau 	 * Save the status block index value for use during
5364a5eaa4bfSSepherosa Ziehau 	 * the next interrupt.
5365a5eaa4bfSSepherosa Ziehau 	 */
5366ba268ba5SSepherosa Ziehau 	rxr->last_status_idx = *rxr->hw_status_idx;
5367a5eaa4bfSSepherosa Ziehau 
53685abd7f19SSepherosa Ziehau 	/* Make sure status index is extracted before RX/TX cons */
5369a5eaa4bfSSepherosa Ziehau 	cpu_lfence();
5370a5eaa4bfSSepherosa Ziehau 
537124603545SSepherosa Ziehau 	/* Check if the hardware has finished any work. */
53725abd7f19SSepherosa Ziehau 	hw_rx_cons = bce_get_hw_rx_cons(rxr);
53735abd7f19SSepherosa Ziehau 	hw_tx_cons = bce_get_hw_tx_cons(txr);
537424603545SSepherosa Ziehau 
537543c2aeb0SSepherosa Ziehau 	status_attn_bits = sblk->status_attn_bits;
537643c2aeb0SSepherosa Ziehau 
537743c2aeb0SSepherosa Ziehau 	/* Was it a link change interrupt? */
537843c2aeb0SSepherosa Ziehau 	if ((status_attn_bits & STATUS_ATTN_BITS_LINK_STATE) !=
5379d0092544SSepherosa Ziehau 	    (sblk->status_attn_bits_ack & STATUS_ATTN_BITS_LINK_STATE)) {
538043c2aeb0SSepherosa Ziehau 		bce_phy_intr(sc);
538143c2aeb0SSepherosa Ziehau 
538243c2aeb0SSepherosa Ziehau 		/*
5383d0092544SSepherosa Ziehau 		 * Clear any transient status updates during link state
5384d0092544SSepherosa Ziehau 		 * change.
5385d0092544SSepherosa Ziehau 		 */
5386d0092544SSepherosa Ziehau 		REG_WR(sc, BCE_HC_COMMAND,
5387d0092544SSepherosa Ziehau 		    sc->hc_command | BCE_HC_COMMAND_COAL_NOW_WO_INT);
5388d0092544SSepherosa Ziehau 		REG_RD(sc, BCE_HC_COMMAND);
5389d0092544SSepherosa Ziehau 	}
5390d0092544SSepherosa Ziehau 
5391d0092544SSepherosa Ziehau 	/*
539243c2aeb0SSepherosa Ziehau 	 * If any other attention is asserted then
539343c2aeb0SSepherosa Ziehau 	 * the chip is toast.
539443c2aeb0SSepherosa Ziehau 	 */
539543c2aeb0SSepherosa Ziehau 	if ((status_attn_bits & ~STATUS_ATTN_BITS_LINK_STATE) !=
5396a5eaa4bfSSepherosa Ziehau 	    (sblk->status_attn_bits_ack & ~STATUS_ATTN_BITS_LINK_STATE)) {
539743c2aeb0SSepherosa Ziehau 		if_printf(ifp, "Fatal attention detected: 0x%08X\n",
539843c2aeb0SSepherosa Ziehau 			  sblk->status_attn_bits);
539984464af5SSepherosa Ziehau 		bce_serialize_skipmain(sc);
540043c2aeb0SSepherosa Ziehau 		bce_init(sc);
540184464af5SSepherosa Ziehau 		bce_deserialize_skipmain(sc);
540243c2aeb0SSepherosa Ziehau 		return;
540343c2aeb0SSepherosa Ziehau 	}
540443c2aeb0SSepherosa Ziehau 
540543c2aeb0SSepherosa Ziehau 	/* Check for any completed RX frames. */
540684464af5SSepherosa Ziehau 	lwkt_serialize_enter(&rxr->rx_serialize);
540708b64767SSepherosa Ziehau 	if (hw_rx_cons != rxr->rx_cons)
540808b64767SSepherosa Ziehau 		bce_rx_intr(rxr, -1, hw_rx_cons);
540984464af5SSepherosa Ziehau 	lwkt_serialize_exit(&rxr->rx_serialize);
541043c2aeb0SSepherosa Ziehau 
541143c2aeb0SSepherosa Ziehau 	/* Check for any completed TX frames. */
541284464af5SSepherosa Ziehau 	lwkt_serialize_enter(&txr->tx_serialize);
541384464af5SSepherosa Ziehau 	if (hw_tx_cons != txr->tx_cons) {
541410bcbdabSSepherosa Ziehau 		bce_tx_intr(txr, hw_tx_cons);
5415f774fa0fSSepherosa Ziehau 		if (!ifsq_is_empty(txr->ifsq))
5416f774fa0fSSepherosa Ziehau 			ifsq_devstart(txr->ifsq);
541784464af5SSepherosa Ziehau 	}
541884464af5SSepherosa Ziehau 	lwkt_serialize_exit(&txr->tx_serialize);
541943c2aeb0SSepherosa Ziehau }
542043c2aeb0SSepherosa Ziehau 
5421eac57ffbSSepherosa Ziehau static void
bce_intr_legacy(void * xsc)5422eac57ffbSSepherosa Ziehau bce_intr_legacy(void *xsc)
5423eac57ffbSSepherosa Ziehau {
5424eac57ffbSSepherosa Ziehau 	struct bce_softc *sc = xsc;
54254068cb22SSepherosa Ziehau 	struct bce_rx_ring *rxr = &sc->rx_rings[0];
5426eac57ffbSSepherosa Ziehau 	struct status_block *sblk;
5427eac57ffbSSepherosa Ziehau 
5428eac57ffbSSepherosa Ziehau 	sblk = sc->status_block;
5429eac57ffbSSepherosa Ziehau 
5430eac57ffbSSepherosa Ziehau 	/*
5431eac57ffbSSepherosa Ziehau 	 * If the hardware status block index matches the last value
5432eac57ffbSSepherosa Ziehau 	 * read by the driver and we haven't asserted our interrupt
5433eac57ffbSSepherosa Ziehau 	 * then there's nothing to do.
5434eac57ffbSSepherosa Ziehau 	 */
54354068cb22SSepherosa Ziehau 	if (sblk->status_idx == rxr->last_status_idx &&
5436eac57ffbSSepherosa Ziehau 	    (REG_RD(sc, BCE_PCICFG_MISC_STATUS) &
5437eac57ffbSSepherosa Ziehau 	     BCE_PCICFG_MISC_STATUS_INTA_VALUE))
5438eac57ffbSSepherosa Ziehau 		return;
5439eac57ffbSSepherosa Ziehau 
5440eac57ffbSSepherosa Ziehau 	/* Ack the interrupt and stop others from occuring. */
5441eac57ffbSSepherosa Ziehau 	REG_WR(sc, BCE_PCICFG_INT_ACK_CMD,
5442eac57ffbSSepherosa Ziehau 	       BCE_PCICFG_INT_ACK_CMD_USE_INT_HC_PARAM |
5443eac57ffbSSepherosa Ziehau 	       BCE_PCICFG_INT_ACK_CMD_MASK_INT);
5444eac57ffbSSepherosa Ziehau 
5445eac57ffbSSepherosa Ziehau 	/*
5446eac57ffbSSepherosa Ziehau 	 * Read back to deassert IRQ immediately to avoid too
5447eac57ffbSSepherosa Ziehau 	 * many spurious interrupts.
5448eac57ffbSSepherosa Ziehau 	 */
5449eac57ffbSSepherosa Ziehau 	REG_RD(sc, BCE_PCICFG_INT_ACK_CMD);
5450eac57ffbSSepherosa Ziehau 
5451eac57ffbSSepherosa Ziehau 	bce_intr(sc);
54524068cb22SSepherosa Ziehau 
54534068cb22SSepherosa Ziehau 	/* Re-enable interrupts. */
54544068cb22SSepherosa Ziehau 	REG_WR(sc, BCE_PCICFG_INT_ACK_CMD,
54554068cb22SSepherosa Ziehau 	       BCE_PCICFG_INT_ACK_CMD_INDEX_VALID |
54564068cb22SSepherosa Ziehau 	       BCE_PCICFG_INT_ACK_CMD_MASK_INT | rxr->last_status_idx);
54574068cb22SSepherosa Ziehau 	bce_reenable_intr(rxr);
5458eac57ffbSSepherosa Ziehau }
5459eac57ffbSSepherosa Ziehau 
5460eac57ffbSSepherosa Ziehau static void
bce_intr_msi(void * xsc)5461eac57ffbSSepherosa Ziehau bce_intr_msi(void *xsc)
5462eac57ffbSSepherosa Ziehau {
5463eac57ffbSSepherosa Ziehau 	struct bce_softc *sc = xsc;
5464eac57ffbSSepherosa Ziehau 
5465eac57ffbSSepherosa Ziehau 	/* Ack the interrupt and stop others from occuring. */
5466eac57ffbSSepherosa Ziehau 	REG_WR(sc, BCE_PCICFG_INT_ACK_CMD,
5467eac57ffbSSepherosa Ziehau 	       BCE_PCICFG_INT_ACK_CMD_USE_INT_HC_PARAM |
5468eac57ffbSSepherosa Ziehau 	       BCE_PCICFG_INT_ACK_CMD_MASK_INT);
5469eac57ffbSSepherosa Ziehau 
5470eac57ffbSSepherosa Ziehau 	bce_intr(sc);
54714068cb22SSepherosa Ziehau 
54724068cb22SSepherosa Ziehau 	/* Re-enable interrupts */
54734068cb22SSepherosa Ziehau 	bce_reenable_intr(&sc->rx_rings[0]);
5474eac57ffbSSepherosa Ziehau }
5475eac57ffbSSepherosa Ziehau 
5476eac57ffbSSepherosa Ziehau static void
bce_intr_msi_oneshot(void * xsc)5477eac57ffbSSepherosa Ziehau bce_intr_msi_oneshot(void *xsc)
5478eac57ffbSSepherosa Ziehau {
54794068cb22SSepherosa Ziehau 	struct bce_softc *sc = xsc;
54804068cb22SSepherosa Ziehau 
54814068cb22SSepherosa Ziehau 	bce_intr(sc);
54824068cb22SSepherosa Ziehau 
54834068cb22SSepherosa Ziehau 	/* Re-enable interrupts */
54844068cb22SSepherosa Ziehau 	bce_reenable_intr(&sc->rx_rings[0]);
5485eac57ffbSSepherosa Ziehau }
5486eac57ffbSSepherosa Ziehau 
5487b42386eeSSepherosa Ziehau static void
bce_intr_msix_rxtx(void * xrxr)5488b42386eeSSepherosa Ziehau bce_intr_msix_rxtx(void *xrxr)
5489b42386eeSSepherosa Ziehau {
5490b42386eeSSepherosa Ziehau 	struct bce_rx_ring *rxr = xrxr;
5491b42386eeSSepherosa Ziehau 	struct bce_tx_ring *txr;
5492b42386eeSSepherosa Ziehau 	uint16_t hw_rx_cons, hw_tx_cons;
5493b42386eeSSepherosa Ziehau 
5494b42386eeSSepherosa Ziehau 	ASSERT_SERIALIZED(&rxr->rx_serialize);
5495b42386eeSSepherosa Ziehau 
5496b42386eeSSepherosa Ziehau 	KKASSERT(rxr->idx < rxr->sc->tx_ring_cnt);
5497b42386eeSSepherosa Ziehau 	txr = &rxr->sc->tx_rings[rxr->idx];
5498b42386eeSSepherosa Ziehau 
5499b42386eeSSepherosa Ziehau 	/*
5500b42386eeSSepherosa Ziehau 	 * Save the status block index value for use during
5501b42386eeSSepherosa Ziehau 	 * the next interrupt.
5502b42386eeSSepherosa Ziehau 	 */
5503b42386eeSSepherosa Ziehau 	rxr->last_status_idx = *rxr->hw_status_idx;
5504b42386eeSSepherosa Ziehau 
5505b42386eeSSepherosa Ziehau 	/* Make sure status index is extracted before RX/TX cons */
5506b42386eeSSepherosa Ziehau 	cpu_lfence();
5507b42386eeSSepherosa Ziehau 
5508b42386eeSSepherosa Ziehau 	/* Check if the hardware has finished any work. */
5509b42386eeSSepherosa Ziehau 	hw_rx_cons = bce_get_hw_rx_cons(rxr);
5510b42386eeSSepherosa Ziehau 	if (hw_rx_cons != rxr->rx_cons)
5511b42386eeSSepherosa Ziehau 		bce_rx_intr(rxr, -1, hw_rx_cons);
5512b42386eeSSepherosa Ziehau 
5513b42386eeSSepherosa Ziehau 	/* Check for any completed TX frames. */
5514b42386eeSSepherosa Ziehau 	hw_tx_cons = bce_get_hw_tx_cons(txr);
5515b42386eeSSepherosa Ziehau 	lwkt_serialize_enter(&txr->tx_serialize);
5516b42386eeSSepherosa Ziehau 	if (hw_tx_cons != txr->tx_cons) {
5517b42386eeSSepherosa Ziehau 		bce_tx_intr(txr, hw_tx_cons);
5518b42386eeSSepherosa Ziehau 		if (!ifsq_is_empty(txr->ifsq))
5519b42386eeSSepherosa Ziehau 			ifsq_devstart(txr->ifsq);
5520b42386eeSSepherosa Ziehau 	}
5521b42386eeSSepherosa Ziehau 	lwkt_serialize_exit(&txr->tx_serialize);
5522b42386eeSSepherosa Ziehau 
5523b42386eeSSepherosa Ziehau 	/* Re-enable interrupts */
5524b42386eeSSepherosa Ziehau 	bce_reenable_intr(rxr);
5525b42386eeSSepherosa Ziehau }
5526b42386eeSSepherosa Ziehau 
5527b42386eeSSepherosa Ziehau static void
bce_intr_msix_rx(void * xrxr)5528b42386eeSSepherosa Ziehau bce_intr_msix_rx(void *xrxr)
5529b42386eeSSepherosa Ziehau {
5530b42386eeSSepherosa Ziehau 	struct bce_rx_ring *rxr = xrxr;
5531b42386eeSSepherosa Ziehau 	uint16_t hw_rx_cons;
5532b42386eeSSepherosa Ziehau 
5533b42386eeSSepherosa Ziehau 	ASSERT_SERIALIZED(&rxr->rx_serialize);
5534b42386eeSSepherosa Ziehau 
5535b42386eeSSepherosa Ziehau 	/*
5536b42386eeSSepherosa Ziehau 	 * Save the status block index value for use during
5537b42386eeSSepherosa Ziehau 	 * the next interrupt.
5538b42386eeSSepherosa Ziehau 	 */
5539b42386eeSSepherosa Ziehau 	rxr->last_status_idx = *rxr->hw_status_idx;
5540b42386eeSSepherosa Ziehau 
5541b42386eeSSepherosa Ziehau 	/* Make sure status index is extracted before RX cons */
5542b42386eeSSepherosa Ziehau 	cpu_lfence();
5543b42386eeSSepherosa Ziehau 
5544b42386eeSSepherosa Ziehau 	/* Check if the hardware has finished any work. */
5545b42386eeSSepherosa Ziehau 	hw_rx_cons = bce_get_hw_rx_cons(rxr);
5546b42386eeSSepherosa Ziehau 	if (hw_rx_cons != rxr->rx_cons)
5547b42386eeSSepherosa Ziehau 		bce_rx_intr(rxr, -1, hw_rx_cons);
5548b42386eeSSepherosa Ziehau 
5549b42386eeSSepherosa Ziehau 	/* Re-enable interrupts */
5550b42386eeSSepherosa Ziehau 	bce_reenable_intr(rxr);
5551b42386eeSSepherosa Ziehau }
5552b42386eeSSepherosa Ziehau 
555343c2aeb0SSepherosa Ziehau /****************************************************************************/
555443c2aeb0SSepherosa Ziehau /* Programs the various packet receive modes (broadcast and multicast).     */
555543c2aeb0SSepherosa Ziehau /*                                                                          */
555643c2aeb0SSepherosa Ziehau /* Returns:                                                                 */
555743c2aeb0SSepherosa Ziehau /*   Nothing.                                                               */
555843c2aeb0SSepherosa Ziehau /****************************************************************************/
555943c2aeb0SSepherosa Ziehau static void
bce_set_rx_mode(struct bce_softc * sc)556043c2aeb0SSepherosa Ziehau bce_set_rx_mode(struct bce_softc *sc)
556143c2aeb0SSepherosa Ziehau {
556243c2aeb0SSepherosa Ziehau 	struct ifnet *ifp = &sc->arpcom.ac_if;
556343c2aeb0SSepherosa Ziehau 	struct ifmultiaddr *ifma;
556443c2aeb0SSepherosa Ziehau 	uint32_t hashes[NUM_MC_HASH_REGISTERS] = { 0, 0, 0, 0, 0, 0, 0, 0 };
556543c2aeb0SSepherosa Ziehau 	uint32_t rx_mode, sort_mode;
556643c2aeb0SSepherosa Ziehau 	int h, i;
556743c2aeb0SSepherosa Ziehau 
556884464af5SSepherosa Ziehau 	ASSERT_IFNET_SERIALIZED_ALL(ifp);
556943c2aeb0SSepherosa Ziehau 
557043c2aeb0SSepherosa Ziehau 	/* Initialize receive mode default settings. */
557143c2aeb0SSepherosa Ziehau 	rx_mode = sc->rx_mode &
557243c2aeb0SSepherosa Ziehau 		  ~(BCE_EMAC_RX_MODE_PROMISCUOUS |
557343c2aeb0SSepherosa Ziehau 		    BCE_EMAC_RX_MODE_KEEP_VLAN_TAG);
557443c2aeb0SSepherosa Ziehau 	sort_mode = 1 | BCE_RPM_SORT_USER0_BC_EN;
557543c2aeb0SSepherosa Ziehau 
557643c2aeb0SSepherosa Ziehau 	/*
557743c2aeb0SSepherosa Ziehau 	 * ASF/IPMI/UMP firmware requires that VLAN tag stripping
557843c2aeb0SSepherosa Ziehau 	 * be enbled.
557943c2aeb0SSepherosa Ziehau 	 */
558043c2aeb0SSepherosa Ziehau 	if (!(BCE_IF_CAPABILITIES & IFCAP_VLAN_HWTAGGING) &&
558143c2aeb0SSepherosa Ziehau 	    !(sc->bce_flags & BCE_MFW_ENABLE_FLAG))
558243c2aeb0SSepherosa Ziehau 		rx_mode |= BCE_EMAC_RX_MODE_KEEP_VLAN_TAG;
558343c2aeb0SSepherosa Ziehau 
558443c2aeb0SSepherosa Ziehau 	/*
558543c2aeb0SSepherosa Ziehau 	 * Check for promiscuous, all multicast, or selected
558643c2aeb0SSepherosa Ziehau 	 * multicast address filtering.
558743c2aeb0SSepherosa Ziehau 	 */
558843c2aeb0SSepherosa Ziehau 	if (ifp->if_flags & IFF_PROMISC) {
558943c2aeb0SSepherosa Ziehau 		/* Enable promiscuous mode. */
559043c2aeb0SSepherosa Ziehau 		rx_mode |= BCE_EMAC_RX_MODE_PROMISCUOUS;
559143c2aeb0SSepherosa Ziehau 		sort_mode |= BCE_RPM_SORT_USER0_PROM_EN;
559243c2aeb0SSepherosa Ziehau 	} else if (ifp->if_flags & IFF_ALLMULTI) {
559343c2aeb0SSepherosa Ziehau 		/* Enable all multicast addresses. */
559443c2aeb0SSepherosa Ziehau 		for (i = 0; i < NUM_MC_HASH_REGISTERS; i++) {
559543c2aeb0SSepherosa Ziehau 			REG_WR(sc, BCE_EMAC_MULTICAST_HASH0 + (i * 4),
559643c2aeb0SSepherosa Ziehau 			       0xffffffff);
559743c2aeb0SSepherosa Ziehau 		}
559843c2aeb0SSepherosa Ziehau 		sort_mode |= BCE_RPM_SORT_USER0_MC_EN;
559943c2aeb0SSepherosa Ziehau 	} else {
560043c2aeb0SSepherosa Ziehau 		/* Accept one or more multicast(s). */
5601441d34b2SSascha Wildner 		TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
560243c2aeb0SSepherosa Ziehau 			if (ifma->ifma_addr->sa_family != AF_LINK)
560343c2aeb0SSepherosa Ziehau 				continue;
560443c2aeb0SSepherosa Ziehau 			h = ether_crc32_le(
560543c2aeb0SSepherosa Ziehau 			    LLADDR((struct sockaddr_dl *)ifma->ifma_addr),
560643c2aeb0SSepherosa Ziehau 			    ETHER_ADDR_LEN) & 0xFF;
560743c2aeb0SSepherosa Ziehau 			hashes[(h & 0xE0) >> 5] |= 1 << (h & 0x1F);
560843c2aeb0SSepherosa Ziehau 		}
560943c2aeb0SSepherosa Ziehau 
561043c2aeb0SSepherosa Ziehau 		for (i = 0; i < NUM_MC_HASH_REGISTERS; i++) {
561143c2aeb0SSepherosa Ziehau 			REG_WR(sc, BCE_EMAC_MULTICAST_HASH0 + (i * 4),
561243c2aeb0SSepherosa Ziehau 			       hashes[i]);
561343c2aeb0SSepherosa Ziehau 		}
561443c2aeb0SSepherosa Ziehau 		sort_mode |= BCE_RPM_SORT_USER0_MC_HSH_EN;
561543c2aeb0SSepherosa Ziehau 	}
561643c2aeb0SSepherosa Ziehau 
561743c2aeb0SSepherosa Ziehau 	/* Only make changes if the recive mode has actually changed. */
561843c2aeb0SSepherosa Ziehau 	if (rx_mode != sc->rx_mode) {
561943c2aeb0SSepherosa Ziehau 		sc->rx_mode = rx_mode;
562043c2aeb0SSepherosa Ziehau 		REG_WR(sc, BCE_EMAC_RX_MODE, rx_mode);
562143c2aeb0SSepherosa Ziehau 	}
562243c2aeb0SSepherosa Ziehau 
562343c2aeb0SSepherosa Ziehau 	/* Disable and clear the exisitng sort before enabling a new sort. */
562443c2aeb0SSepherosa Ziehau 	REG_WR(sc, BCE_RPM_SORT_USER0, 0x0);
562543c2aeb0SSepherosa Ziehau 	REG_WR(sc, BCE_RPM_SORT_USER0, sort_mode);
562643c2aeb0SSepherosa Ziehau 	REG_WR(sc, BCE_RPM_SORT_USER0, sort_mode | BCE_RPM_SORT_USER0_ENA);
562743c2aeb0SSepherosa Ziehau }
562843c2aeb0SSepherosa Ziehau 
562943c2aeb0SSepherosa Ziehau /****************************************************************************/
563043c2aeb0SSepherosa Ziehau /* Called periodically to updates statistics from the controllers           */
563143c2aeb0SSepherosa Ziehau /* statistics block.                                                        */
563243c2aeb0SSepherosa Ziehau /*                                                                          */
563343c2aeb0SSepherosa Ziehau /* Returns:                                                                 */
563443c2aeb0SSepherosa Ziehau /*   Nothing.                                                               */
563543c2aeb0SSepherosa Ziehau /****************************************************************************/
563643c2aeb0SSepherosa Ziehau static void
bce_stats_update(struct bce_softc * sc)563743c2aeb0SSepherosa Ziehau bce_stats_update(struct bce_softc *sc)
563843c2aeb0SSepherosa Ziehau {
563943c2aeb0SSepherosa Ziehau 	struct ifnet *ifp = &sc->arpcom.ac_if;
564043c2aeb0SSepherosa Ziehau 	struct statistics_block *stats = sc->stats_block;
564143c2aeb0SSepherosa Ziehau 
564284464af5SSepherosa Ziehau 	ASSERT_SERIALIZED(&sc->main_serialize);
564343c2aeb0SSepherosa Ziehau 
564443c2aeb0SSepherosa Ziehau 	/*
564543c2aeb0SSepherosa Ziehau 	 * Certain controllers don't report carrier sense errors correctly.
564643c2aeb0SSepherosa Ziehau 	 * See errata E11_5708CA0_1165.
564743c2aeb0SSepherosa Ziehau 	 */
564843c2aeb0SSepherosa Ziehau 	if (!(BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5706) &&
564943c2aeb0SSepherosa Ziehau 	    !(BCE_CHIP_ID(sc) == BCE_CHIP_ID_5708_A0)) {
5650d40991efSSepherosa Ziehau 		IFNET_STAT_INC(ifp, oerrors,
5651d40991efSSepherosa Ziehau 			(u_long)stats->stat_Dot3StatsCarrierSenseErrors);
565243c2aeb0SSepherosa Ziehau 	}
565343c2aeb0SSepherosa Ziehau 
565443c2aeb0SSepherosa Ziehau 	/*
565543c2aeb0SSepherosa Ziehau 	 * Update the sysctl statistics from the hardware statistics.
565643c2aeb0SSepherosa Ziehau 	 */
565743c2aeb0SSepherosa Ziehau 	sc->stat_IfHCInOctets =
565843c2aeb0SSepherosa Ziehau 		((uint64_t)stats->stat_IfHCInOctets_hi << 32) +
565943c2aeb0SSepherosa Ziehau 		 (uint64_t)stats->stat_IfHCInOctets_lo;
566043c2aeb0SSepherosa Ziehau 
566143c2aeb0SSepherosa Ziehau 	sc->stat_IfHCInBadOctets =
566243c2aeb0SSepherosa Ziehau 		((uint64_t)stats->stat_IfHCInBadOctets_hi << 32) +
566343c2aeb0SSepherosa Ziehau 		 (uint64_t)stats->stat_IfHCInBadOctets_lo;
566443c2aeb0SSepherosa Ziehau 
566543c2aeb0SSepherosa Ziehau 	sc->stat_IfHCOutOctets =
566643c2aeb0SSepherosa Ziehau 		((uint64_t)stats->stat_IfHCOutOctets_hi << 32) +
566743c2aeb0SSepherosa Ziehau 		 (uint64_t)stats->stat_IfHCOutOctets_lo;
566843c2aeb0SSepherosa Ziehau 
566943c2aeb0SSepherosa Ziehau 	sc->stat_IfHCOutBadOctets =
567043c2aeb0SSepherosa Ziehau 		((uint64_t)stats->stat_IfHCOutBadOctets_hi << 32) +
567143c2aeb0SSepherosa Ziehau 		 (uint64_t)stats->stat_IfHCOutBadOctets_lo;
567243c2aeb0SSepherosa Ziehau 
567343c2aeb0SSepherosa Ziehau 	sc->stat_IfHCInUcastPkts =
567443c2aeb0SSepherosa Ziehau 		((uint64_t)stats->stat_IfHCInUcastPkts_hi << 32) +
567543c2aeb0SSepherosa Ziehau 		 (uint64_t)stats->stat_IfHCInUcastPkts_lo;
567643c2aeb0SSepherosa Ziehau 
567743c2aeb0SSepherosa Ziehau 	sc->stat_IfHCInMulticastPkts =
567843c2aeb0SSepherosa Ziehau 		((uint64_t)stats->stat_IfHCInMulticastPkts_hi << 32) +
567943c2aeb0SSepherosa Ziehau 		 (uint64_t)stats->stat_IfHCInMulticastPkts_lo;
568043c2aeb0SSepherosa Ziehau 
568143c2aeb0SSepherosa Ziehau 	sc->stat_IfHCInBroadcastPkts =
568243c2aeb0SSepherosa Ziehau 		((uint64_t)stats->stat_IfHCInBroadcastPkts_hi << 32) +
568343c2aeb0SSepherosa Ziehau 		 (uint64_t)stats->stat_IfHCInBroadcastPkts_lo;
568443c2aeb0SSepherosa Ziehau 
568543c2aeb0SSepherosa Ziehau 	sc->stat_IfHCOutUcastPkts =
568643c2aeb0SSepherosa Ziehau 		((uint64_t)stats->stat_IfHCOutUcastPkts_hi << 32) +
568743c2aeb0SSepherosa Ziehau 		 (uint64_t)stats->stat_IfHCOutUcastPkts_lo;
568843c2aeb0SSepherosa Ziehau 
568943c2aeb0SSepherosa Ziehau 	sc->stat_IfHCOutMulticastPkts =
569043c2aeb0SSepherosa Ziehau 		((uint64_t)stats->stat_IfHCOutMulticastPkts_hi << 32) +
569143c2aeb0SSepherosa Ziehau 		 (uint64_t)stats->stat_IfHCOutMulticastPkts_lo;
569243c2aeb0SSepherosa Ziehau 
569343c2aeb0SSepherosa Ziehau 	sc->stat_IfHCOutBroadcastPkts =
569443c2aeb0SSepherosa Ziehau 		((uint64_t)stats->stat_IfHCOutBroadcastPkts_hi << 32) +
569543c2aeb0SSepherosa Ziehau 		 (uint64_t)stats->stat_IfHCOutBroadcastPkts_lo;
569643c2aeb0SSepherosa Ziehau 
569743c2aeb0SSepherosa Ziehau 	sc->stat_emac_tx_stat_dot3statsinternalmactransmiterrors =
569843c2aeb0SSepherosa Ziehau 		stats->stat_emac_tx_stat_dot3statsinternalmactransmiterrors;
569943c2aeb0SSepherosa Ziehau 
570043c2aeb0SSepherosa Ziehau 	sc->stat_Dot3StatsCarrierSenseErrors =
570143c2aeb0SSepherosa Ziehau 		stats->stat_Dot3StatsCarrierSenseErrors;
570243c2aeb0SSepherosa Ziehau 
570343c2aeb0SSepherosa Ziehau 	sc->stat_Dot3StatsFCSErrors =
570443c2aeb0SSepherosa Ziehau 		stats->stat_Dot3StatsFCSErrors;
570543c2aeb0SSepherosa Ziehau 
570643c2aeb0SSepherosa Ziehau 	sc->stat_Dot3StatsAlignmentErrors =
570743c2aeb0SSepherosa Ziehau 		stats->stat_Dot3StatsAlignmentErrors;
570843c2aeb0SSepherosa Ziehau 
570943c2aeb0SSepherosa Ziehau 	sc->stat_Dot3StatsSingleCollisionFrames =
571043c2aeb0SSepherosa Ziehau 		stats->stat_Dot3StatsSingleCollisionFrames;
571143c2aeb0SSepherosa Ziehau 
571243c2aeb0SSepherosa Ziehau 	sc->stat_Dot3StatsMultipleCollisionFrames =
571343c2aeb0SSepherosa Ziehau 		stats->stat_Dot3StatsMultipleCollisionFrames;
571443c2aeb0SSepherosa Ziehau 
571543c2aeb0SSepherosa Ziehau 	sc->stat_Dot3StatsDeferredTransmissions =
571643c2aeb0SSepherosa Ziehau 		stats->stat_Dot3StatsDeferredTransmissions;
571743c2aeb0SSepherosa Ziehau 
571843c2aeb0SSepherosa Ziehau 	sc->stat_Dot3StatsExcessiveCollisions =
571943c2aeb0SSepherosa Ziehau 		stats->stat_Dot3StatsExcessiveCollisions;
572043c2aeb0SSepherosa Ziehau 
572143c2aeb0SSepherosa Ziehau 	sc->stat_Dot3StatsLateCollisions =
572243c2aeb0SSepherosa Ziehau 		stats->stat_Dot3StatsLateCollisions;
572343c2aeb0SSepherosa Ziehau 
572443c2aeb0SSepherosa Ziehau 	sc->stat_EtherStatsCollisions =
572543c2aeb0SSepherosa Ziehau 		stats->stat_EtherStatsCollisions;
572643c2aeb0SSepherosa Ziehau 
572743c2aeb0SSepherosa Ziehau 	sc->stat_EtherStatsFragments =
572843c2aeb0SSepherosa Ziehau 		stats->stat_EtherStatsFragments;
572943c2aeb0SSepherosa Ziehau 
573043c2aeb0SSepherosa Ziehau 	sc->stat_EtherStatsJabbers =
573143c2aeb0SSepherosa Ziehau 		stats->stat_EtherStatsJabbers;
573243c2aeb0SSepherosa Ziehau 
573343c2aeb0SSepherosa Ziehau 	sc->stat_EtherStatsUndersizePkts =
573443c2aeb0SSepherosa Ziehau 		stats->stat_EtherStatsUndersizePkts;
573543c2aeb0SSepherosa Ziehau 
573643c2aeb0SSepherosa Ziehau 	sc->stat_EtherStatsOverrsizePkts =
573743c2aeb0SSepherosa Ziehau 		stats->stat_EtherStatsOverrsizePkts;
573843c2aeb0SSepherosa Ziehau 
573943c2aeb0SSepherosa Ziehau 	sc->stat_EtherStatsPktsRx64Octets =
574043c2aeb0SSepherosa Ziehau 		stats->stat_EtherStatsPktsRx64Octets;
574143c2aeb0SSepherosa Ziehau 
574243c2aeb0SSepherosa Ziehau 	sc->stat_EtherStatsPktsRx65Octetsto127Octets =
574343c2aeb0SSepherosa Ziehau 		stats->stat_EtherStatsPktsRx65Octetsto127Octets;
574443c2aeb0SSepherosa Ziehau 
574543c2aeb0SSepherosa Ziehau 	sc->stat_EtherStatsPktsRx128Octetsto255Octets =
574643c2aeb0SSepherosa Ziehau 		stats->stat_EtherStatsPktsRx128Octetsto255Octets;
574743c2aeb0SSepherosa Ziehau 
574843c2aeb0SSepherosa Ziehau 	sc->stat_EtherStatsPktsRx256Octetsto511Octets =
574943c2aeb0SSepherosa Ziehau 		stats->stat_EtherStatsPktsRx256Octetsto511Octets;
575043c2aeb0SSepherosa Ziehau 
575143c2aeb0SSepherosa Ziehau 	sc->stat_EtherStatsPktsRx512Octetsto1023Octets =
575243c2aeb0SSepherosa Ziehau 		stats->stat_EtherStatsPktsRx512Octetsto1023Octets;
575343c2aeb0SSepherosa Ziehau 
575443c2aeb0SSepherosa Ziehau 	sc->stat_EtherStatsPktsRx1024Octetsto1522Octets =
575543c2aeb0SSepherosa Ziehau 		stats->stat_EtherStatsPktsRx1024Octetsto1522Octets;
575643c2aeb0SSepherosa Ziehau 
575743c2aeb0SSepherosa Ziehau 	sc->stat_EtherStatsPktsRx1523Octetsto9022Octets =
575843c2aeb0SSepherosa Ziehau 		stats->stat_EtherStatsPktsRx1523Octetsto9022Octets;
575943c2aeb0SSepherosa Ziehau 
576043c2aeb0SSepherosa Ziehau 	sc->stat_EtherStatsPktsTx64Octets =
576143c2aeb0SSepherosa Ziehau 		stats->stat_EtherStatsPktsTx64Octets;
576243c2aeb0SSepherosa Ziehau 
576343c2aeb0SSepherosa Ziehau 	sc->stat_EtherStatsPktsTx65Octetsto127Octets =
576443c2aeb0SSepherosa Ziehau 		stats->stat_EtherStatsPktsTx65Octetsto127Octets;
576543c2aeb0SSepherosa Ziehau 
576643c2aeb0SSepherosa Ziehau 	sc->stat_EtherStatsPktsTx128Octetsto255Octets =
576743c2aeb0SSepherosa Ziehau 		stats->stat_EtherStatsPktsTx128Octetsto255Octets;
576843c2aeb0SSepherosa Ziehau 
576943c2aeb0SSepherosa Ziehau 	sc->stat_EtherStatsPktsTx256Octetsto511Octets =
577043c2aeb0SSepherosa Ziehau 		stats->stat_EtherStatsPktsTx256Octetsto511Octets;
577143c2aeb0SSepherosa Ziehau 
577243c2aeb0SSepherosa Ziehau 	sc->stat_EtherStatsPktsTx512Octetsto1023Octets =
577343c2aeb0SSepherosa Ziehau 		stats->stat_EtherStatsPktsTx512Octetsto1023Octets;
577443c2aeb0SSepherosa Ziehau 
577543c2aeb0SSepherosa Ziehau 	sc->stat_EtherStatsPktsTx1024Octetsto1522Octets =
577643c2aeb0SSepherosa Ziehau 		stats->stat_EtherStatsPktsTx1024Octetsto1522Octets;
577743c2aeb0SSepherosa Ziehau 
577843c2aeb0SSepherosa Ziehau 	sc->stat_EtherStatsPktsTx1523Octetsto9022Octets =
577943c2aeb0SSepherosa Ziehau 		stats->stat_EtherStatsPktsTx1523Octetsto9022Octets;
578043c2aeb0SSepherosa Ziehau 
578143c2aeb0SSepherosa Ziehau 	sc->stat_XonPauseFramesReceived =
578243c2aeb0SSepherosa Ziehau 		stats->stat_XonPauseFramesReceived;
578343c2aeb0SSepherosa Ziehau 
578443c2aeb0SSepherosa Ziehau 	sc->stat_XoffPauseFramesReceived =
578543c2aeb0SSepherosa Ziehau 		stats->stat_XoffPauseFramesReceived;
578643c2aeb0SSepherosa Ziehau 
578743c2aeb0SSepherosa Ziehau 	sc->stat_OutXonSent =
578843c2aeb0SSepherosa Ziehau 		stats->stat_OutXonSent;
578943c2aeb0SSepherosa Ziehau 
579043c2aeb0SSepherosa Ziehau 	sc->stat_OutXoffSent =
579143c2aeb0SSepherosa Ziehau 		stats->stat_OutXoffSent;
579243c2aeb0SSepherosa Ziehau 
579343c2aeb0SSepherosa Ziehau 	sc->stat_FlowControlDone =
579443c2aeb0SSepherosa Ziehau 		stats->stat_FlowControlDone;
579543c2aeb0SSepherosa Ziehau 
579643c2aeb0SSepherosa Ziehau 	sc->stat_MacControlFramesReceived =
579743c2aeb0SSepherosa Ziehau 		stats->stat_MacControlFramesReceived;
579843c2aeb0SSepherosa Ziehau 
579943c2aeb0SSepherosa Ziehau 	sc->stat_XoffStateEntered =
580043c2aeb0SSepherosa Ziehau 		stats->stat_XoffStateEntered;
580143c2aeb0SSepherosa Ziehau 
580243c2aeb0SSepherosa Ziehau 	sc->stat_IfInFramesL2FilterDiscards =
580343c2aeb0SSepherosa Ziehau 		stats->stat_IfInFramesL2FilterDiscards;
580443c2aeb0SSepherosa Ziehau 
580543c2aeb0SSepherosa Ziehau 	sc->stat_IfInRuleCheckerDiscards =
580643c2aeb0SSepherosa Ziehau 		stats->stat_IfInRuleCheckerDiscards;
580743c2aeb0SSepherosa Ziehau 
580843c2aeb0SSepherosa Ziehau 	sc->stat_IfInFTQDiscards =
580943c2aeb0SSepherosa Ziehau 		stats->stat_IfInFTQDiscards;
581043c2aeb0SSepherosa Ziehau 
581143c2aeb0SSepherosa Ziehau 	sc->stat_IfInMBUFDiscards =
581243c2aeb0SSepherosa Ziehau 		stats->stat_IfInMBUFDiscards;
581343c2aeb0SSepherosa Ziehau 
581443c2aeb0SSepherosa Ziehau 	sc->stat_IfInRuleCheckerP4Hit =
581543c2aeb0SSepherosa Ziehau 		stats->stat_IfInRuleCheckerP4Hit;
581643c2aeb0SSepherosa Ziehau 
581743c2aeb0SSepherosa Ziehau 	sc->stat_CatchupInRuleCheckerDiscards =
581843c2aeb0SSepherosa Ziehau 		stats->stat_CatchupInRuleCheckerDiscards;
581943c2aeb0SSepherosa Ziehau 
582043c2aeb0SSepherosa Ziehau 	sc->stat_CatchupInFTQDiscards =
582143c2aeb0SSepherosa Ziehau 		stats->stat_CatchupInFTQDiscards;
582243c2aeb0SSepherosa Ziehau 
582343c2aeb0SSepherosa Ziehau 	sc->stat_CatchupInMBUFDiscards =
582443c2aeb0SSepherosa Ziehau 		stats->stat_CatchupInMBUFDiscards;
582543c2aeb0SSepherosa Ziehau 
582643c2aeb0SSepherosa Ziehau 	sc->stat_CatchupInRuleCheckerP4Hit =
582743c2aeb0SSepherosa Ziehau 		stats->stat_CatchupInRuleCheckerP4Hit;
582843c2aeb0SSepherosa Ziehau 
582943c2aeb0SSepherosa Ziehau 	sc->com_no_buffers = REG_RD_IND(sc, 0x120084);
583043c2aeb0SSepherosa Ziehau 
5831d0092544SSepherosa Ziehau 	/*
5832d0092544SSepherosa Ziehau 	 * Update the interface statistics from the
5833d0092544SSepherosa Ziehau 	 * hardware statistics.
5834d0092544SSepherosa Ziehau 	 */
5835d40991efSSepherosa Ziehau 	IFNET_STAT_SET(ifp, collisions, (u_long)sc->stat_EtherStatsCollisions);
5836d0092544SSepherosa Ziehau 
5837d40991efSSepherosa Ziehau 	IFNET_STAT_SET(ifp, ierrors, (u_long)sc->stat_EtherStatsUndersizePkts +
5838d0092544SSepherosa Ziehau 	    (u_long)sc->stat_EtherStatsOverrsizePkts +
5839d0092544SSepherosa Ziehau 	    (u_long)sc->stat_IfInMBUFDiscards +
5840d0092544SSepherosa Ziehau 	    (u_long)sc->stat_Dot3StatsAlignmentErrors +
5841d0092544SSepherosa Ziehau 	    (u_long)sc->stat_Dot3StatsFCSErrors +
5842d0092544SSepherosa Ziehau 	    (u_long)sc->stat_IfInRuleCheckerDiscards +
5843d0092544SSepherosa Ziehau 	    (u_long)sc->stat_IfInFTQDiscards +
5844d40991efSSepherosa Ziehau 	    (u_long)sc->com_no_buffers);
5845d0092544SSepherosa Ziehau 
5846d40991efSSepherosa Ziehau 	IFNET_STAT_SET(ifp, oerrors,
5847d0092544SSepherosa Ziehau 	    (u_long)sc->stat_emac_tx_stat_dot3statsinternalmactransmiterrors +
5848d0092544SSepherosa Ziehau 	    (u_long)sc->stat_Dot3StatsExcessiveCollisions +
5849d40991efSSepherosa Ziehau 	    (u_long)sc->stat_Dot3StatsLateCollisions);
585043c2aeb0SSepherosa Ziehau }
585143c2aeb0SSepherosa Ziehau 
585243c2aeb0SSepherosa Ziehau /****************************************************************************/
5853d0092544SSepherosa Ziehau /* Periodic function to notify the bootcode that the driver is still        */
5854d0092544SSepherosa Ziehau /* present.                                                                 */
5855d0092544SSepherosa Ziehau /*                                                                          */
5856d0092544SSepherosa Ziehau /* Returns:                                                                 */
5857d0092544SSepherosa Ziehau /*   Nothing.                                                               */
5858d0092544SSepherosa Ziehau /****************************************************************************/
5859d0092544SSepherosa Ziehau static void
bce_pulse(void * xsc)5860d0092544SSepherosa Ziehau bce_pulse(void *xsc)
5861d0092544SSepherosa Ziehau {
5862d0092544SSepherosa Ziehau 	struct bce_softc *sc = xsc;
5863d0092544SSepherosa Ziehau 	struct ifnet *ifp = &sc->arpcom.ac_if;
5864d0092544SSepherosa Ziehau 	uint32_t msg;
5865d0092544SSepherosa Ziehau 
586684464af5SSepherosa Ziehau 	lwkt_serialize_enter(&sc->main_serialize);
5867d0092544SSepherosa Ziehau 
5868d0092544SSepherosa Ziehau 	/* Tell the firmware that the driver is still running. */
5869d0092544SSepherosa Ziehau 	msg = (uint32_t)++sc->bce_fw_drv_pulse_wr_seq;
5870bc30d40dSSepherosa Ziehau 	bce_shmem_wr(sc, BCE_DRV_PULSE_MB, msg);
5871d0092544SSepherosa Ziehau 
5872d8870c52SSepherosa Ziehau 	/* Update the bootcode condition. */
5873d8870c52SSepherosa Ziehau 	sc->bc_state = bce_shmem_rd(sc, BCE_BC_STATE_CONDITION);
5874d8870c52SSepherosa Ziehau 
5875d8870c52SSepherosa Ziehau 	/* Report whether the bootcode still knows the driver is running. */
5876d8870c52SSepherosa Ziehau 	if (!sc->bce_drv_cardiac_arrest) {
5877d8870c52SSepherosa Ziehau 		if (!(sc->bc_state & BCE_CONDITION_DRV_PRESENT)) {
5878d8870c52SSepherosa Ziehau 			sc->bce_drv_cardiac_arrest = 1;
5879d8870c52SSepherosa Ziehau 			if_printf(ifp, "Bootcode lost the driver pulse! "
5880d8870c52SSepherosa Ziehau 			    "(bc_state = 0x%08X)\n", sc->bc_state);
5881d8870c52SSepherosa Ziehau 		}
5882d8870c52SSepherosa Ziehau 	} else {
5883d8870c52SSepherosa Ziehau  		/*
5884d8870c52SSepherosa Ziehau  		 * Not supported by all bootcode versions.
5885d8870c52SSepherosa Ziehau  		 * (v5.0.11+ and v5.2.1+)  Older bootcode
5886d8870c52SSepherosa Ziehau  		 * will require the driver to reset the
5887d8870c52SSepherosa Ziehau  		 * controller to clear this condition.
5888d8870c52SSepherosa Ziehau 		 */
5889d8870c52SSepherosa Ziehau 		if (sc->bc_state & BCE_CONDITION_DRV_PRESENT) {
5890d8870c52SSepherosa Ziehau 			sc->bce_drv_cardiac_arrest = 0;
5891d8870c52SSepherosa Ziehau 			if_printf(ifp, "Bootcode found the driver pulse! "
5892d8870c52SSepherosa Ziehau 			    "(bc_state = 0x%08X)\n", sc->bc_state);
5893d8870c52SSepherosa Ziehau 		}
5894d8870c52SSepherosa Ziehau 	}
5895d8870c52SSepherosa Ziehau 
5896d0092544SSepherosa Ziehau 	/* Schedule the next pulse. */
5897a131f6c2SSepherosa Ziehau 	callout_reset_bycpu(&sc->bce_pulse_callout, hz, bce_pulse, sc,
5898745b3d68SSepherosa Ziehau 	    sc->bce_timer_cpuid);
5899d0092544SSepherosa Ziehau 
590084464af5SSepherosa Ziehau 	lwkt_serialize_exit(&sc->main_serialize);
5901d0092544SSepherosa Ziehau }
5902d0092544SSepherosa Ziehau 
590328ef7645SSepherosa Ziehau /****************************************************************************/
590428ef7645SSepherosa Ziehau /* Periodic function to check whether MSI is lost                           */
590528ef7645SSepherosa Ziehau /*                                                                          */
590628ef7645SSepherosa Ziehau /* Returns:                                                                 */
590728ef7645SSepherosa Ziehau /*   Nothing.                                                               */
590828ef7645SSepherosa Ziehau /****************************************************************************/
590928ef7645SSepherosa Ziehau static void
bce_check_msi(void * xsc)591028ef7645SSepherosa Ziehau bce_check_msi(void *xsc)
591128ef7645SSepherosa Ziehau {
591228ef7645SSepherosa Ziehau 	struct bce_softc *sc = xsc;
591328ef7645SSepherosa Ziehau 	struct ifnet *ifp = &sc->arpcom.ac_if;
5914733403d6SSepherosa Ziehau 	struct status_block *sblk = sc->status_block;
591510bcbdabSSepherosa Ziehau 	struct bce_tx_ring *txr = &sc->tx_rings[0];
591608b64767SSepherosa Ziehau 	struct bce_rx_ring *rxr = &sc->rx_rings[0];
5917733403d6SSepherosa Ziehau 
591884464af5SSepherosa Ziehau 	lwkt_serialize_enter(&sc->main_serialize);
591928ef7645SSepherosa Ziehau 
5920b42386eeSSepherosa Ziehau 	KKASSERT(mycpuid == sc->bce_msix[0].msix_cpuid);
592128ef7645SSepherosa Ziehau 
59224a331bf7SSepherosa Ziehau 	if ((ifp->if_flags & (IFF_RUNNING | IFF_NPOLLING)) != IFF_RUNNING) {
592384464af5SSepherosa Ziehau 		lwkt_serialize_exit(&sc->main_serialize);
592428ef7645SSepherosa Ziehau 		return;
5925733403d6SSepherosa Ziehau 	}
5926733403d6SSepherosa Ziehau 
59275abd7f19SSepherosa Ziehau 	if (bce_get_hw_rx_cons(rxr) != rxr->rx_cons ||
59285abd7f19SSepherosa Ziehau 	    bce_get_hw_tx_cons(txr) != txr->tx_cons ||
592928ef7645SSepherosa Ziehau 	    (sblk->status_attn_bits & STATUS_ATTN_BITS_LINK_STATE) !=
593028ef7645SSepherosa Ziehau 	    (sblk->status_attn_bits_ack & STATUS_ATTN_BITS_LINK_STATE)) {
593108b64767SSepherosa Ziehau 		if (sc->bce_check_rx_cons == rxr->rx_cons &&
593210bcbdabSSepherosa Ziehau 		    sc->bce_check_tx_cons == txr->tx_cons &&
5933ba268ba5SSepherosa Ziehau 		    sc->bce_check_status_idx == rxr->last_status_idx) {
5934733403d6SSepherosa Ziehau 			uint32_t msi_ctrl;
5935733403d6SSepherosa Ziehau 
593628ef7645SSepherosa Ziehau 			if (!sc->bce_msi_maylose) {
593728ef7645SSepherosa Ziehau 				sc->bce_msi_maylose = TRUE;
593828ef7645SSepherosa Ziehau 				goto done;
593928ef7645SSepherosa Ziehau 			}
5940733403d6SSepherosa Ziehau 
594128ef7645SSepherosa Ziehau 			msi_ctrl = REG_RD(sc, BCE_PCICFG_MSI_CONTROL);
594228ef7645SSepherosa Ziehau 			if (msi_ctrl & BCE_PCICFG_MSI_CONTROL_ENABLE) {
594328ef7645SSepherosa Ziehau 				if (bootverbose)
594428ef7645SSepherosa Ziehau 					if_printf(ifp, "lost MSI\n");
5945733403d6SSepherosa Ziehau 
5946733403d6SSepherosa Ziehau 				REG_WR(sc, BCE_PCICFG_MSI_CONTROL,
5947733403d6SSepherosa Ziehau 				    msi_ctrl & ~BCE_PCICFG_MSI_CONTROL_ENABLE);
5948733403d6SSepherosa Ziehau 				REG_WR(sc, BCE_PCICFG_MSI_CONTROL, msi_ctrl);
5949733403d6SSepherosa Ziehau 
5950733403d6SSepherosa Ziehau 				bce_intr_msi(sc);
595128ef7645SSepherosa Ziehau 			} else if (bootverbose) {
595228ef7645SSepherosa Ziehau 				if_printf(ifp, "MSI may be lost\n");
5953733403d6SSepherosa Ziehau 			}
5954733403d6SSepherosa Ziehau 		}
5955733403d6SSepherosa Ziehau 	}
595628ef7645SSepherosa Ziehau 	sc->bce_msi_maylose = FALSE;
595708b64767SSepherosa Ziehau 	sc->bce_check_rx_cons = rxr->rx_cons;
595810bcbdabSSepherosa Ziehau 	sc->bce_check_tx_cons = txr->tx_cons;
5959ba268ba5SSepherosa Ziehau 	sc->bce_check_status_idx = rxr->last_status_idx;
596028ef7645SSepherosa Ziehau 
596128ef7645SSepherosa Ziehau done:
596228ef7645SSepherosa Ziehau 	callout_reset(&sc->bce_ckmsi_callout, BCE_MSI_CKINTVL,
596328ef7645SSepherosa Ziehau 	    bce_check_msi, sc);
596484464af5SSepherosa Ziehau 	lwkt_serialize_exit(&sc->main_serialize);
596528ef7645SSepherosa Ziehau }
596628ef7645SSepherosa Ziehau 
5967d0092544SSepherosa Ziehau /****************************************************************************/
596843c2aeb0SSepherosa Ziehau /* Periodic function to perform maintenance tasks.                          */
596943c2aeb0SSepherosa Ziehau /*                                                                          */
597043c2aeb0SSepherosa Ziehau /* Returns:                                                                 */
597143c2aeb0SSepherosa Ziehau /*   Nothing.                                                               */
597243c2aeb0SSepherosa Ziehau /****************************************************************************/
597343c2aeb0SSepherosa Ziehau static void
bce_tick_serialized(struct bce_softc * sc)597443c2aeb0SSepherosa Ziehau bce_tick_serialized(struct bce_softc *sc)
597543c2aeb0SSepherosa Ziehau {
597643c2aeb0SSepherosa Ziehau 	struct mii_data *mii;
597743c2aeb0SSepherosa Ziehau 
597884464af5SSepherosa Ziehau 	ASSERT_SERIALIZED(&sc->main_serialize);
597943c2aeb0SSepherosa Ziehau 
598043c2aeb0SSepherosa Ziehau 	/* Update the statistics from the hardware statistics block. */
598143c2aeb0SSepherosa Ziehau 	bce_stats_update(sc);
598243c2aeb0SSepherosa Ziehau 
598343c2aeb0SSepherosa Ziehau 	/* Schedule the next tick. */
5984a131f6c2SSepherosa Ziehau 	callout_reset_bycpu(&sc->bce_tick_callout, hz, bce_tick, sc,
5985745b3d68SSepherosa Ziehau 	    sc->bce_timer_cpuid);
598643c2aeb0SSepherosa Ziehau 
598743c2aeb0SSepherosa Ziehau 	/* If link is up already up then we're done. */
598843c2aeb0SSepherosa Ziehau 	if (sc->bce_link)
598943c2aeb0SSepherosa Ziehau 		return;
599043c2aeb0SSepherosa Ziehau 
599143c2aeb0SSepherosa Ziehau 	mii = device_get_softc(sc->bce_miibus);
599243c2aeb0SSepherosa Ziehau 	mii_tick(mii);
599343c2aeb0SSepherosa Ziehau 
599443c2aeb0SSepherosa Ziehau 	/* Check if the link has come up. */
5995d0092544SSepherosa Ziehau 	if ((mii->mii_media_status & IFM_ACTIVE) &&
599643c2aeb0SSepherosa Ziehau 	    IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) {
5997f774fa0fSSepherosa Ziehau 		int i;
5998f774fa0fSSepherosa Ziehau 
599943c2aeb0SSepherosa Ziehau 		sc->bce_link++;
600043c2aeb0SSepherosa Ziehau 		/* Now that link is up, handle any outstanding TX traffic. */
6001ac2202eaSSepherosa Ziehau 		for (i = 0; i < sc->tx_ring_cnt; ++i)
6002f774fa0fSSepherosa Ziehau 			ifsq_devstart_sched(sc->tx_rings[i].ifsq);
600343c2aeb0SSepherosa Ziehau 	}
600443c2aeb0SSepherosa Ziehau }
600543c2aeb0SSepherosa Ziehau 
600643c2aeb0SSepherosa Ziehau static void
bce_tick(void * xsc)600743c2aeb0SSepherosa Ziehau bce_tick(void *xsc)
600843c2aeb0SSepherosa Ziehau {
600943c2aeb0SSepherosa Ziehau 	struct bce_softc *sc = xsc;
601043c2aeb0SSepherosa Ziehau 
601184464af5SSepherosa Ziehau 	lwkt_serialize_enter(&sc->main_serialize);
601243c2aeb0SSepherosa Ziehau 	bce_tick_serialized(sc);
601384464af5SSepherosa Ziehau 	lwkt_serialize_exit(&sc->main_serialize);
601443c2aeb0SSepherosa Ziehau }
601543c2aeb0SSepherosa Ziehau 
601643c2aeb0SSepherosa Ziehau /****************************************************************************/
601743c2aeb0SSepherosa Ziehau /* Adds any sysctl parameters for tuning or debugging purposes.             */
601843c2aeb0SSepherosa Ziehau /*                                                                          */
601943c2aeb0SSepherosa Ziehau /* Returns:                                                                 */
602043c2aeb0SSepherosa Ziehau /*   0 for success, positive value for failure.                             */
602143c2aeb0SSepherosa Ziehau /****************************************************************************/
602243c2aeb0SSepherosa Ziehau static void
bce_add_sysctls(struct bce_softc * sc)602343c2aeb0SSepherosa Ziehau bce_add_sysctls(struct bce_softc *sc)
602443c2aeb0SSepherosa Ziehau {
602543c2aeb0SSepherosa Ziehau 	struct sysctl_ctx_list *ctx;
602643c2aeb0SSepherosa Ziehau 	struct sysctl_oid_list *children;
6027b42386eeSSepherosa Ziehau #if defined(BCE_TSS_DEBUG) || defined(BCE_RSS_DEBUG)
6028b42386eeSSepherosa Ziehau 	char node[32];
6029b42386eeSSepherosa Ziehau 	int i;
6030b42386eeSSepherosa Ziehau #endif
603143c2aeb0SSepherosa Ziehau 
603226595b18SSascha Wildner 	ctx = device_get_sysctl_ctx(sc->bce_dev);
603326595b18SSascha Wildner 	children = SYSCTL_CHILDREN(device_get_sysctl_tree(sc->bce_dev));
603443c2aeb0SSepherosa Ziehau 
6035bdeb8fffSSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "tx_bds_int",
6036bdeb8fffSSepherosa Ziehau 			CTLTYPE_INT | CTLFLAG_RW,
6037bdeb8fffSSepherosa Ziehau 			sc, 0, bce_sysctl_tx_bds_int, "I",
6038bdeb8fffSSepherosa Ziehau 			"Send max coalesced BD count during interrupt");
6039bdeb8fffSSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "tx_bds",
6040bdeb8fffSSepherosa Ziehau 			CTLTYPE_INT | CTLFLAG_RW,
6041bdeb8fffSSepherosa Ziehau 			sc, 0, bce_sysctl_tx_bds, "I",
6042bdeb8fffSSepherosa Ziehau 			"Send max coalesced BD count");
6043bdeb8fffSSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "tx_ticks_int",
6044bdeb8fffSSepherosa Ziehau 			CTLTYPE_INT | CTLFLAG_RW,
6045bdeb8fffSSepherosa Ziehau 			sc, 0, bce_sysctl_tx_ticks_int, "I",
6046bdeb8fffSSepherosa Ziehau 			"Send coalescing ticks during interrupt");
6047bdeb8fffSSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "tx_ticks",
6048bdeb8fffSSepherosa Ziehau 			CTLTYPE_INT | CTLFLAG_RW,
6049bdeb8fffSSepherosa Ziehau 			sc, 0, bce_sysctl_tx_ticks, "I",
6050bdeb8fffSSepherosa Ziehau 			"Send coalescing ticks");
6051bdeb8fffSSepherosa Ziehau 
6052bdeb8fffSSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "rx_bds_int",
6053bdeb8fffSSepherosa Ziehau 			CTLTYPE_INT | CTLFLAG_RW,
6054bdeb8fffSSepherosa Ziehau 			sc, 0, bce_sysctl_rx_bds_int, "I",
6055bdeb8fffSSepherosa Ziehau 			"Receive max coalesced BD count during interrupt");
6056bdeb8fffSSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "rx_bds",
6057bdeb8fffSSepherosa Ziehau 			CTLTYPE_INT | CTLFLAG_RW,
6058bdeb8fffSSepherosa Ziehau 			sc, 0, bce_sysctl_rx_bds, "I",
6059bdeb8fffSSepherosa Ziehau 			"Receive max coalesced BD count");
6060bdeb8fffSSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "rx_ticks_int",
6061bdeb8fffSSepherosa Ziehau 			CTLTYPE_INT | CTLFLAG_RW,
6062bdeb8fffSSepherosa Ziehau 			sc, 0, bce_sysctl_rx_ticks_int, "I",
6063bdeb8fffSSepherosa Ziehau 			"Receive coalescing ticks during interrupt");
6064bdeb8fffSSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "rx_ticks",
6065bdeb8fffSSepherosa Ziehau 			CTLTYPE_INT | CTLFLAG_RW,
6066bdeb8fffSSepherosa Ziehau 			sc, 0, bce_sysctl_rx_ticks, "I",
6067bdeb8fffSSepherosa Ziehau 			"Receive coalescing ticks");
6068bdeb8fffSSepherosa Ziehau 
6069b42386eeSSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, children, OID_AUTO, "rx_rings",
6070b42386eeSSepherosa Ziehau 		CTLFLAG_RD, &sc->rx_ring_cnt, 0, "# of RX rings");
60714b166d4eSSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, children, OID_AUTO, "rx_pages",
607208b64767SSepherosa Ziehau 		CTLFLAG_RD, &sc->rx_rings[0].rx_pages, 0, "# of RX pages");
6073b42386eeSSepherosa Ziehau 
6074b42386eeSSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, children, OID_AUTO, "tx_rings",
6075b42386eeSSepherosa Ziehau 		CTLFLAG_RD, &sc->tx_ring_cnt, 0, "# of TX rings");
60764b166d4eSSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, children, OID_AUTO, "tx_pages",
607710bcbdabSSepherosa Ziehau 		CTLFLAG_RD, &sc->tx_rings[0].tx_pages, 0, "# of TX pages");
60784b166d4eSSepherosa Ziehau 
6079f52858a0SSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, children, OID_AUTO, "tx_wreg",
608010bcbdabSSepherosa Ziehau 	    	CTLFLAG_RW, &sc->tx_rings[0].tx_wreg, 0,
6081f52858a0SSepherosa Ziehau 		"# segments before write to hardware registers");
6082f52858a0SSepherosa Ziehau 
608339ea245fSSepherosa Ziehau 	if (sc->bce_irq_type == PCI_INTR_TYPE_MSIX) {
608439ea245fSSepherosa Ziehau 		SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "tx_cpumap",
608539ea245fSSepherosa Ziehau 		    CTLTYPE_OPAQUE | CTLFLAG_RD, sc->tx_rmap, 0,
608639ea245fSSepherosa Ziehau 		    if_ringmap_cpumap_sysctl, "I", "TX ring CPU map");
608739ea245fSSepherosa Ziehau 		SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "rx_cpumap",
608839ea245fSSepherosa Ziehau 		    CTLTYPE_OPAQUE | CTLFLAG_RD, sc->rx_rmap, 0,
608939ea245fSSepherosa Ziehau 		    if_ringmap_cpumap_sysctl, "I", "RX ring CPU map");
609039ea245fSSepherosa Ziehau 	} else {
609157b3ecd9SSepherosa Ziehau #ifdef IFPOLL_ENABLE
609239ea245fSSepherosa Ziehau 		SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "tx_poll_cpumap",
609339ea245fSSepherosa Ziehau 		    CTLTYPE_OPAQUE | CTLFLAG_RD, sc->tx_rmap, 0,
609439ea245fSSepherosa Ziehau 		    if_ringmap_cpumap_sysctl, "I", "TX poll CPU map");
609539ea245fSSepherosa Ziehau 		SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "rx_poll_cpumap",
609639ea245fSSepherosa Ziehau 		    CTLTYPE_OPAQUE | CTLFLAG_RD, sc->rx_rmap, 0,
609739ea245fSSepherosa Ziehau 		    if_ringmap_cpumap_sysctl, "I", "RX poll CPU map");
609857b3ecd9SSepherosa Ziehau #endif
609939ea245fSSepherosa Ziehau 	}
610057b3ecd9SSepherosa Ziehau 
6101b42386eeSSepherosa Ziehau #ifdef BCE_RSS_DEBUG
6102b42386eeSSepherosa Ziehau 	SYSCTL_ADD_INT(ctx, children, OID_AUTO, "rss_debug",
6103b42386eeSSepherosa Ziehau 	    CTLFLAG_RW, &sc->rss_debug, 0, "RSS debug level");
6104b42386eeSSepherosa Ziehau 	for (i = 0; i < sc->rx_ring_cnt; ++i) {
6105b42386eeSSepherosa Ziehau 		ksnprintf(node, sizeof(node), "rx%d_pkt", i);
6106b42386eeSSepherosa Ziehau 		SYSCTL_ADD_ULONG(ctx, children, OID_AUTO, node,
6107b42386eeSSepherosa Ziehau 		    CTLFLAG_RW, &sc->rx_rings[i].rx_pkts,
6108b42386eeSSepherosa Ziehau 		    "RXed packets");
6109b42386eeSSepherosa Ziehau 	}
6110b42386eeSSepherosa Ziehau #endif
6111b42386eeSSepherosa Ziehau 
6112b42386eeSSepherosa Ziehau #ifdef BCE_TSS_DEBUG
6113b42386eeSSepherosa Ziehau 	for (i = 0; i < sc->tx_ring_cnt; ++i) {
6114b42386eeSSepherosa Ziehau 		ksnprintf(node, sizeof(node), "tx%d_pkt", i);
6115b42386eeSSepherosa Ziehau 		SYSCTL_ADD_ULONG(ctx, children, OID_AUTO, node,
6116b42386eeSSepherosa Ziehau 		    CTLFLAG_RW, &sc->tx_rings[i].tx_pkts,
6117b42386eeSSepherosa Ziehau 		    "TXed packets");
6118b42386eeSSepherosa Ziehau 	}
6119b42386eeSSepherosa Ziehau #endif
6120b42386eeSSepherosa Ziehau 
612143c2aeb0SSepherosa Ziehau 	SYSCTL_ADD_ULONG(ctx, children, OID_AUTO,
612256872d4eSSepherosa Ziehau 		"stat_IfHCInOctets",
612343c2aeb0SSepherosa Ziehau 		CTLFLAG_RD, &sc->stat_IfHCInOctets,
612443c2aeb0SSepherosa Ziehau 		"Bytes received");
612543c2aeb0SSepherosa Ziehau 
612643c2aeb0SSepherosa Ziehau 	SYSCTL_ADD_ULONG(ctx, children, OID_AUTO,
612743c2aeb0SSepherosa Ziehau 		"stat_IfHCInBadOctets",
612843c2aeb0SSepherosa Ziehau 		CTLFLAG_RD, &sc->stat_IfHCInBadOctets,
612943c2aeb0SSepherosa Ziehau 		"Bad bytes received");
613043c2aeb0SSepherosa Ziehau 
613143c2aeb0SSepherosa Ziehau 	SYSCTL_ADD_ULONG(ctx, children, OID_AUTO,
613243c2aeb0SSepherosa Ziehau 		"stat_IfHCOutOctets",
613343c2aeb0SSepherosa Ziehau 		CTLFLAG_RD, &sc->stat_IfHCOutOctets,
613443c2aeb0SSepherosa Ziehau 		"Bytes sent");
613543c2aeb0SSepherosa Ziehau 
613643c2aeb0SSepherosa Ziehau 	SYSCTL_ADD_ULONG(ctx, children, OID_AUTO,
613743c2aeb0SSepherosa Ziehau 		"stat_IfHCOutBadOctets",
613843c2aeb0SSepherosa Ziehau 		CTLFLAG_RD, &sc->stat_IfHCOutBadOctets,
613943c2aeb0SSepherosa Ziehau 		"Bad bytes sent");
614043c2aeb0SSepherosa Ziehau 
614143c2aeb0SSepherosa Ziehau 	SYSCTL_ADD_ULONG(ctx, children, OID_AUTO,
614243c2aeb0SSepherosa Ziehau 		"stat_IfHCInUcastPkts",
614343c2aeb0SSepherosa Ziehau 		CTLFLAG_RD, &sc->stat_IfHCInUcastPkts,
614443c2aeb0SSepherosa Ziehau 		"Unicast packets received");
614543c2aeb0SSepherosa Ziehau 
614643c2aeb0SSepherosa Ziehau 	SYSCTL_ADD_ULONG(ctx, children, OID_AUTO,
614743c2aeb0SSepherosa Ziehau 		"stat_IfHCInMulticastPkts",
614843c2aeb0SSepherosa Ziehau 		CTLFLAG_RD, &sc->stat_IfHCInMulticastPkts,
614943c2aeb0SSepherosa Ziehau 		"Multicast packets received");
615043c2aeb0SSepherosa Ziehau 
615143c2aeb0SSepherosa Ziehau 	SYSCTL_ADD_ULONG(ctx, children, OID_AUTO,
615243c2aeb0SSepherosa Ziehau 		"stat_IfHCInBroadcastPkts",
615343c2aeb0SSepherosa Ziehau 		CTLFLAG_RD, &sc->stat_IfHCInBroadcastPkts,
615443c2aeb0SSepherosa Ziehau 		"Broadcast packets received");
615543c2aeb0SSepherosa Ziehau 
615643c2aeb0SSepherosa Ziehau 	SYSCTL_ADD_ULONG(ctx, children, OID_AUTO,
615743c2aeb0SSepherosa Ziehau 		"stat_IfHCOutUcastPkts",
615843c2aeb0SSepherosa Ziehau 		CTLFLAG_RD, &sc->stat_IfHCOutUcastPkts,
615943c2aeb0SSepherosa Ziehau 		"Unicast packets sent");
616043c2aeb0SSepherosa Ziehau 
616143c2aeb0SSepherosa Ziehau 	SYSCTL_ADD_ULONG(ctx, children, OID_AUTO,
616243c2aeb0SSepherosa Ziehau 		"stat_IfHCOutMulticastPkts",
616343c2aeb0SSepherosa Ziehau 		CTLFLAG_RD, &sc->stat_IfHCOutMulticastPkts,
616443c2aeb0SSepherosa Ziehau 		"Multicast packets sent");
616543c2aeb0SSepherosa Ziehau 
616643c2aeb0SSepherosa Ziehau 	SYSCTL_ADD_ULONG(ctx, children, OID_AUTO,
616743c2aeb0SSepherosa Ziehau 		"stat_IfHCOutBroadcastPkts",
616843c2aeb0SSepherosa Ziehau 		CTLFLAG_RD, &sc->stat_IfHCOutBroadcastPkts,
616943c2aeb0SSepherosa Ziehau 		"Broadcast packets sent");
617043c2aeb0SSepherosa Ziehau 
617143c2aeb0SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
617243c2aeb0SSepherosa Ziehau 		"stat_emac_tx_stat_dot3statsinternalmactransmiterrors",
617343c2aeb0SSepherosa Ziehau 		CTLFLAG_RD, &sc->stat_emac_tx_stat_dot3statsinternalmactransmiterrors,
617443c2aeb0SSepherosa Ziehau 		0, "Internal MAC transmit errors");
617543c2aeb0SSepherosa Ziehau 
617643c2aeb0SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
617743c2aeb0SSepherosa Ziehau 		"stat_Dot3StatsCarrierSenseErrors",
617843c2aeb0SSepherosa Ziehau 		CTLFLAG_RD, &sc->stat_Dot3StatsCarrierSenseErrors,
617943c2aeb0SSepherosa Ziehau 		0, "Carrier sense errors");
618043c2aeb0SSepherosa Ziehau 
618143c2aeb0SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
618243c2aeb0SSepherosa Ziehau 		"stat_Dot3StatsFCSErrors",
618343c2aeb0SSepherosa Ziehau 		CTLFLAG_RD, &sc->stat_Dot3StatsFCSErrors,
618443c2aeb0SSepherosa Ziehau 		0, "Frame check sequence errors");
618543c2aeb0SSepherosa Ziehau 
618643c2aeb0SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
618743c2aeb0SSepherosa Ziehau 		"stat_Dot3StatsAlignmentErrors",
618843c2aeb0SSepherosa Ziehau 		CTLFLAG_RD, &sc->stat_Dot3StatsAlignmentErrors,
618943c2aeb0SSepherosa Ziehau 		0, "Alignment errors");
619043c2aeb0SSepherosa Ziehau 
619143c2aeb0SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
619243c2aeb0SSepherosa Ziehau 		"stat_Dot3StatsSingleCollisionFrames",
619343c2aeb0SSepherosa Ziehau 		CTLFLAG_RD, &sc->stat_Dot3StatsSingleCollisionFrames,
619443c2aeb0SSepherosa Ziehau 		0, "Single Collision Frames");
619543c2aeb0SSepherosa Ziehau 
619643c2aeb0SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
619743c2aeb0SSepherosa Ziehau 		"stat_Dot3StatsMultipleCollisionFrames",
619843c2aeb0SSepherosa Ziehau 		CTLFLAG_RD, &sc->stat_Dot3StatsMultipleCollisionFrames,
619943c2aeb0SSepherosa Ziehau 		0, "Multiple Collision Frames");
620043c2aeb0SSepherosa Ziehau 
620143c2aeb0SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
620243c2aeb0SSepherosa Ziehau 		"stat_Dot3StatsDeferredTransmissions",
620343c2aeb0SSepherosa Ziehau 		CTLFLAG_RD, &sc->stat_Dot3StatsDeferredTransmissions,
620443c2aeb0SSepherosa Ziehau 		0, "Deferred Transmissions");
620543c2aeb0SSepherosa Ziehau 
620643c2aeb0SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
620743c2aeb0SSepherosa Ziehau 		"stat_Dot3StatsExcessiveCollisions",
620843c2aeb0SSepherosa Ziehau 		CTLFLAG_RD, &sc->stat_Dot3StatsExcessiveCollisions,
620943c2aeb0SSepherosa Ziehau 		0, "Excessive Collisions");
621043c2aeb0SSepherosa Ziehau 
621143c2aeb0SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
621243c2aeb0SSepherosa Ziehau 		"stat_Dot3StatsLateCollisions",
621343c2aeb0SSepherosa Ziehau 		CTLFLAG_RD, &sc->stat_Dot3StatsLateCollisions,
621443c2aeb0SSepherosa Ziehau 		0, "Late Collisions");
621543c2aeb0SSepherosa Ziehau 
621643c2aeb0SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
621743c2aeb0SSepherosa Ziehau 		"stat_EtherStatsCollisions",
621843c2aeb0SSepherosa Ziehau 		CTLFLAG_RD, &sc->stat_EtherStatsCollisions,
621943c2aeb0SSepherosa Ziehau 		0, "Collisions");
622043c2aeb0SSepherosa Ziehau 
622143c2aeb0SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
622243c2aeb0SSepherosa Ziehau 		"stat_EtherStatsFragments",
622343c2aeb0SSepherosa Ziehau 		CTLFLAG_RD, &sc->stat_EtherStatsFragments,
622443c2aeb0SSepherosa Ziehau 		0, "Fragments");
622543c2aeb0SSepherosa Ziehau 
622643c2aeb0SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
622743c2aeb0SSepherosa Ziehau 		"stat_EtherStatsJabbers",
622843c2aeb0SSepherosa Ziehau 		CTLFLAG_RD, &sc->stat_EtherStatsJabbers,
622943c2aeb0SSepherosa Ziehau 		0, "Jabbers");
623043c2aeb0SSepherosa Ziehau 
623143c2aeb0SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
623243c2aeb0SSepherosa Ziehau 		"stat_EtherStatsUndersizePkts",
623343c2aeb0SSepherosa Ziehau 		CTLFLAG_RD, &sc->stat_EtherStatsUndersizePkts,
623443c2aeb0SSepherosa Ziehau 		0, "Undersize packets");
623543c2aeb0SSepherosa Ziehau 
623643c2aeb0SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
623743c2aeb0SSepherosa Ziehau 		"stat_EtherStatsOverrsizePkts",
623843c2aeb0SSepherosa Ziehau 		CTLFLAG_RD, &sc->stat_EtherStatsOverrsizePkts,
623943c2aeb0SSepherosa Ziehau 		0, "stat_EtherStatsOverrsizePkts");
624043c2aeb0SSepherosa Ziehau 
624143c2aeb0SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
624243c2aeb0SSepherosa Ziehau 		"stat_EtherStatsPktsRx64Octets",
624343c2aeb0SSepherosa Ziehau 		CTLFLAG_RD, &sc->stat_EtherStatsPktsRx64Octets,
624443c2aeb0SSepherosa Ziehau 		0, "Bytes received in 64 byte packets");
624543c2aeb0SSepherosa Ziehau 
624643c2aeb0SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
624743c2aeb0SSepherosa Ziehau 		"stat_EtherStatsPktsRx65Octetsto127Octets",
624843c2aeb0SSepherosa Ziehau 		CTLFLAG_RD, &sc->stat_EtherStatsPktsRx65Octetsto127Octets,
624943c2aeb0SSepherosa Ziehau 		0, "Bytes received in 65 to 127 byte packets");
625043c2aeb0SSepherosa Ziehau 
625143c2aeb0SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
625243c2aeb0SSepherosa Ziehau 		"stat_EtherStatsPktsRx128Octetsto255Octets",
625343c2aeb0SSepherosa Ziehau 		CTLFLAG_RD, &sc->stat_EtherStatsPktsRx128Octetsto255Octets,
625443c2aeb0SSepherosa Ziehau 		0, "Bytes received in 128 to 255 byte packets");
625543c2aeb0SSepherosa Ziehau 
625643c2aeb0SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
625743c2aeb0SSepherosa Ziehau 		"stat_EtherStatsPktsRx256Octetsto511Octets",
625843c2aeb0SSepherosa Ziehau 		CTLFLAG_RD, &sc->stat_EtherStatsPktsRx256Octetsto511Octets,
625943c2aeb0SSepherosa Ziehau 		0, "Bytes received in 256 to 511 byte packets");
626043c2aeb0SSepherosa Ziehau 
626143c2aeb0SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
626243c2aeb0SSepherosa Ziehau 		"stat_EtherStatsPktsRx512Octetsto1023Octets",
626343c2aeb0SSepherosa Ziehau 		CTLFLAG_RD, &sc->stat_EtherStatsPktsRx512Octetsto1023Octets,
626443c2aeb0SSepherosa Ziehau 		0, "Bytes received in 512 to 1023 byte packets");
626543c2aeb0SSepherosa Ziehau 
626643c2aeb0SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
626743c2aeb0SSepherosa Ziehau 		"stat_EtherStatsPktsRx1024Octetsto1522Octets",
626843c2aeb0SSepherosa Ziehau 		CTLFLAG_RD, &sc->stat_EtherStatsPktsRx1024Octetsto1522Octets,
626943c2aeb0SSepherosa Ziehau 		0, "Bytes received in 1024 t0 1522 byte packets");
627043c2aeb0SSepherosa Ziehau 
627143c2aeb0SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
627243c2aeb0SSepherosa Ziehau 		"stat_EtherStatsPktsRx1523Octetsto9022Octets",
627343c2aeb0SSepherosa Ziehau 		CTLFLAG_RD, &sc->stat_EtherStatsPktsRx1523Octetsto9022Octets,
627443c2aeb0SSepherosa Ziehau 		0, "Bytes received in 1523 to 9022 byte packets");
627543c2aeb0SSepherosa Ziehau 
627643c2aeb0SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
627743c2aeb0SSepherosa Ziehau 		"stat_EtherStatsPktsTx64Octets",
627843c2aeb0SSepherosa Ziehau 		CTLFLAG_RD, &sc->stat_EtherStatsPktsTx64Octets,
627943c2aeb0SSepherosa Ziehau 		0, "Bytes sent in 64 byte packets");
628043c2aeb0SSepherosa Ziehau 
628143c2aeb0SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
628243c2aeb0SSepherosa Ziehau 		"stat_EtherStatsPktsTx65Octetsto127Octets",
628343c2aeb0SSepherosa Ziehau 		CTLFLAG_RD, &sc->stat_EtherStatsPktsTx65Octetsto127Octets,
628443c2aeb0SSepherosa Ziehau 		0, "Bytes sent in 65 to 127 byte packets");
628543c2aeb0SSepherosa Ziehau 
628643c2aeb0SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
628743c2aeb0SSepherosa Ziehau 		"stat_EtherStatsPktsTx128Octetsto255Octets",
628843c2aeb0SSepherosa Ziehau 		CTLFLAG_RD, &sc->stat_EtherStatsPktsTx128Octetsto255Octets,
628943c2aeb0SSepherosa Ziehau 		0, "Bytes sent in 128 to 255 byte packets");
629043c2aeb0SSepherosa Ziehau 
629143c2aeb0SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
629243c2aeb0SSepherosa Ziehau 		"stat_EtherStatsPktsTx256Octetsto511Octets",
629343c2aeb0SSepherosa Ziehau 		CTLFLAG_RD, &sc->stat_EtherStatsPktsTx256Octetsto511Octets,
629443c2aeb0SSepherosa Ziehau 		0, "Bytes sent in 256 to 511 byte packets");
629543c2aeb0SSepherosa Ziehau 
629643c2aeb0SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
629743c2aeb0SSepherosa Ziehau 		"stat_EtherStatsPktsTx512Octetsto1023Octets",
629843c2aeb0SSepherosa Ziehau 		CTLFLAG_RD, &sc->stat_EtherStatsPktsTx512Octetsto1023Octets,
629943c2aeb0SSepherosa Ziehau 		0, "Bytes sent in 512 to 1023 byte packets");
630043c2aeb0SSepherosa Ziehau 
630143c2aeb0SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
630243c2aeb0SSepherosa Ziehau 		"stat_EtherStatsPktsTx1024Octetsto1522Octets",
630343c2aeb0SSepherosa Ziehau 		CTLFLAG_RD, &sc->stat_EtherStatsPktsTx1024Octetsto1522Octets,
630443c2aeb0SSepherosa Ziehau 		0, "Bytes sent in 1024 to 1522 byte packets");
630543c2aeb0SSepherosa Ziehau 
630643c2aeb0SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
630743c2aeb0SSepherosa Ziehau 		"stat_EtherStatsPktsTx1523Octetsto9022Octets",
630843c2aeb0SSepherosa Ziehau 		CTLFLAG_RD, &sc->stat_EtherStatsPktsTx1523Octetsto9022Octets,
630943c2aeb0SSepherosa Ziehau 		0, "Bytes sent in 1523 to 9022 byte packets");
631043c2aeb0SSepherosa Ziehau 
631143c2aeb0SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
631243c2aeb0SSepherosa Ziehau 		"stat_XonPauseFramesReceived",
631343c2aeb0SSepherosa Ziehau 		CTLFLAG_RD, &sc->stat_XonPauseFramesReceived,
631443c2aeb0SSepherosa Ziehau 		0, "XON pause frames receved");
631543c2aeb0SSepherosa Ziehau 
631643c2aeb0SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
631743c2aeb0SSepherosa Ziehau 		"stat_XoffPauseFramesReceived",
631843c2aeb0SSepherosa Ziehau 		CTLFLAG_RD, &sc->stat_XoffPauseFramesReceived,
631943c2aeb0SSepherosa Ziehau 		0, "XOFF pause frames received");
632043c2aeb0SSepherosa Ziehau 
632143c2aeb0SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
632243c2aeb0SSepherosa Ziehau 		"stat_OutXonSent",
632343c2aeb0SSepherosa Ziehau 		CTLFLAG_RD, &sc->stat_OutXonSent,
632443c2aeb0SSepherosa Ziehau 		0, "XON pause frames sent");
632543c2aeb0SSepherosa Ziehau 
632643c2aeb0SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
632743c2aeb0SSepherosa Ziehau 		"stat_OutXoffSent",
632843c2aeb0SSepherosa Ziehau 		CTLFLAG_RD, &sc->stat_OutXoffSent,
632943c2aeb0SSepherosa Ziehau 		0, "XOFF pause frames sent");
633043c2aeb0SSepherosa Ziehau 
633143c2aeb0SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
633243c2aeb0SSepherosa Ziehau 		"stat_FlowControlDone",
633343c2aeb0SSepherosa Ziehau 		CTLFLAG_RD, &sc->stat_FlowControlDone,
633443c2aeb0SSepherosa Ziehau 		0, "Flow control done");
633543c2aeb0SSepherosa Ziehau 
633643c2aeb0SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
633743c2aeb0SSepherosa Ziehau 		"stat_MacControlFramesReceived",
633843c2aeb0SSepherosa Ziehau 		CTLFLAG_RD, &sc->stat_MacControlFramesReceived,
633943c2aeb0SSepherosa Ziehau 		0, "MAC control frames received");
634043c2aeb0SSepherosa Ziehau 
634143c2aeb0SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
634243c2aeb0SSepherosa Ziehau 		"stat_XoffStateEntered",
634343c2aeb0SSepherosa Ziehau 		CTLFLAG_RD, &sc->stat_XoffStateEntered,
634443c2aeb0SSepherosa Ziehau 		0, "XOFF state entered");
634543c2aeb0SSepherosa Ziehau 
634643c2aeb0SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
634743c2aeb0SSepherosa Ziehau 		"stat_IfInFramesL2FilterDiscards",
634843c2aeb0SSepherosa Ziehau 		CTLFLAG_RD, &sc->stat_IfInFramesL2FilterDiscards,
634943c2aeb0SSepherosa Ziehau 		0, "Received L2 packets discarded");
635043c2aeb0SSepherosa Ziehau 
635143c2aeb0SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
635243c2aeb0SSepherosa Ziehau 		"stat_IfInRuleCheckerDiscards",
635343c2aeb0SSepherosa Ziehau 		CTLFLAG_RD, &sc->stat_IfInRuleCheckerDiscards,
635443c2aeb0SSepherosa Ziehau 		0, "Received packets discarded by rule");
635543c2aeb0SSepherosa Ziehau 
635643c2aeb0SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
635743c2aeb0SSepherosa Ziehau 		"stat_IfInFTQDiscards",
635843c2aeb0SSepherosa Ziehau 		CTLFLAG_RD, &sc->stat_IfInFTQDiscards,
635943c2aeb0SSepherosa Ziehau 		0, "Received packet FTQ discards");
636043c2aeb0SSepherosa Ziehau 
636143c2aeb0SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
636243c2aeb0SSepherosa Ziehau 		"stat_IfInMBUFDiscards",
636343c2aeb0SSepherosa Ziehau 		CTLFLAG_RD, &sc->stat_IfInMBUFDiscards,
636443c2aeb0SSepherosa Ziehau 		0, "Received packets discarded due to lack of controller buffer memory");
636543c2aeb0SSepherosa Ziehau 
636643c2aeb0SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
636743c2aeb0SSepherosa Ziehau 		"stat_IfInRuleCheckerP4Hit",
636843c2aeb0SSepherosa Ziehau 		CTLFLAG_RD, &sc->stat_IfInRuleCheckerP4Hit,
636943c2aeb0SSepherosa Ziehau 		0, "Received packets rule checker hits");
637043c2aeb0SSepherosa Ziehau 
637143c2aeb0SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
637243c2aeb0SSepherosa Ziehau 		"stat_CatchupInRuleCheckerDiscards",
637343c2aeb0SSepherosa Ziehau 		CTLFLAG_RD, &sc->stat_CatchupInRuleCheckerDiscards,
637443c2aeb0SSepherosa Ziehau 		0, "Received packets discarded in Catchup path");
637543c2aeb0SSepherosa Ziehau 
637643c2aeb0SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
637743c2aeb0SSepherosa Ziehau 		"stat_CatchupInFTQDiscards",
637843c2aeb0SSepherosa Ziehau 		CTLFLAG_RD, &sc->stat_CatchupInFTQDiscards,
637943c2aeb0SSepherosa Ziehau 		0, "Received packets discarded in FTQ in Catchup path");
638043c2aeb0SSepherosa Ziehau 
638143c2aeb0SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
638243c2aeb0SSepherosa Ziehau 		"stat_CatchupInMBUFDiscards",
638343c2aeb0SSepherosa Ziehau 		CTLFLAG_RD, &sc->stat_CatchupInMBUFDiscards,
638443c2aeb0SSepherosa Ziehau 		0, "Received packets discarded in controller buffer memory in Catchup path");
638543c2aeb0SSepherosa Ziehau 
638643c2aeb0SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
638743c2aeb0SSepherosa Ziehau 		"stat_CatchupInRuleCheckerP4Hit",
638843c2aeb0SSepherosa Ziehau 		CTLFLAG_RD, &sc->stat_CatchupInRuleCheckerP4Hit,
638943c2aeb0SSepherosa Ziehau 		0, "Received packets rule checker hits in Catchup path");
639043c2aeb0SSepherosa Ziehau 
639143c2aeb0SSepherosa Ziehau 	SYSCTL_ADD_UINT(ctx, children, OID_AUTO,
639243c2aeb0SSepherosa Ziehau 		"com_no_buffers",
639343c2aeb0SSepherosa Ziehau 		CTLFLAG_RD, &sc->com_no_buffers,
639443c2aeb0SSepherosa Ziehau 		0, "Valid packets received but no RX buffers available");
639543c2aeb0SSepherosa Ziehau }
639643c2aeb0SSepherosa Ziehau 
6397bdeb8fffSSepherosa Ziehau static int
bce_sysctl_tx_bds_int(SYSCTL_HANDLER_ARGS)6398bdeb8fffSSepherosa Ziehau bce_sysctl_tx_bds_int(SYSCTL_HANDLER_ARGS)
6399bdeb8fffSSepherosa Ziehau {
6400bdeb8fffSSepherosa Ziehau 	struct bce_softc *sc = arg1;
6401bdeb8fffSSepherosa Ziehau 
6402bdeb8fffSSepherosa Ziehau 	return bce_sysctl_coal_change(oidp, arg1, arg2, req,
6403bdeb8fffSSepherosa Ziehau 			&sc->bce_tx_quick_cons_trip_int,
6404bdeb8fffSSepherosa Ziehau 			BCE_COALMASK_TX_BDS_INT);
6405bdeb8fffSSepherosa Ziehau }
6406bdeb8fffSSepherosa Ziehau 
6407bdeb8fffSSepherosa Ziehau static int
bce_sysctl_tx_bds(SYSCTL_HANDLER_ARGS)6408bdeb8fffSSepherosa Ziehau bce_sysctl_tx_bds(SYSCTL_HANDLER_ARGS)
6409bdeb8fffSSepherosa Ziehau {
6410bdeb8fffSSepherosa Ziehau 	struct bce_softc *sc = arg1;
6411bdeb8fffSSepherosa Ziehau 
6412bdeb8fffSSepherosa Ziehau 	return bce_sysctl_coal_change(oidp, arg1, arg2, req,
6413bdeb8fffSSepherosa Ziehau 			&sc->bce_tx_quick_cons_trip,
6414bdeb8fffSSepherosa Ziehau 			BCE_COALMASK_TX_BDS);
6415bdeb8fffSSepherosa Ziehau }
6416bdeb8fffSSepherosa Ziehau 
6417bdeb8fffSSepherosa Ziehau static int
bce_sysctl_tx_ticks_int(SYSCTL_HANDLER_ARGS)6418bdeb8fffSSepherosa Ziehau bce_sysctl_tx_ticks_int(SYSCTL_HANDLER_ARGS)
6419bdeb8fffSSepherosa Ziehau {
6420bdeb8fffSSepherosa Ziehau 	struct bce_softc *sc = arg1;
6421bdeb8fffSSepherosa Ziehau 
6422bdeb8fffSSepherosa Ziehau 	return bce_sysctl_coal_change(oidp, arg1, arg2, req,
6423bdeb8fffSSepherosa Ziehau 			&sc->bce_tx_ticks_int,
6424bdeb8fffSSepherosa Ziehau 			BCE_COALMASK_TX_TICKS_INT);
6425bdeb8fffSSepherosa Ziehau }
6426bdeb8fffSSepherosa Ziehau 
6427bdeb8fffSSepherosa Ziehau static int
bce_sysctl_tx_ticks(SYSCTL_HANDLER_ARGS)6428bdeb8fffSSepherosa Ziehau bce_sysctl_tx_ticks(SYSCTL_HANDLER_ARGS)
6429bdeb8fffSSepherosa Ziehau {
6430bdeb8fffSSepherosa Ziehau 	struct bce_softc *sc = arg1;
6431bdeb8fffSSepherosa Ziehau 
6432bdeb8fffSSepherosa Ziehau 	return bce_sysctl_coal_change(oidp, arg1, arg2, req,
6433bdeb8fffSSepherosa Ziehau 			&sc->bce_tx_ticks,
6434bdeb8fffSSepherosa Ziehau 			BCE_COALMASK_TX_TICKS);
6435bdeb8fffSSepherosa Ziehau }
6436bdeb8fffSSepherosa Ziehau 
6437bdeb8fffSSepherosa Ziehau static int
bce_sysctl_rx_bds_int(SYSCTL_HANDLER_ARGS)6438bdeb8fffSSepherosa Ziehau bce_sysctl_rx_bds_int(SYSCTL_HANDLER_ARGS)
6439bdeb8fffSSepherosa Ziehau {
6440bdeb8fffSSepherosa Ziehau 	struct bce_softc *sc = arg1;
6441bdeb8fffSSepherosa Ziehau 
6442bdeb8fffSSepherosa Ziehau 	return bce_sysctl_coal_change(oidp, arg1, arg2, req,
6443bdeb8fffSSepherosa Ziehau 			&sc->bce_rx_quick_cons_trip_int,
6444bdeb8fffSSepherosa Ziehau 			BCE_COALMASK_RX_BDS_INT);
6445bdeb8fffSSepherosa Ziehau }
6446bdeb8fffSSepherosa Ziehau 
6447bdeb8fffSSepherosa Ziehau static int
bce_sysctl_rx_bds(SYSCTL_HANDLER_ARGS)6448bdeb8fffSSepherosa Ziehau bce_sysctl_rx_bds(SYSCTL_HANDLER_ARGS)
6449bdeb8fffSSepherosa Ziehau {
6450bdeb8fffSSepherosa Ziehau 	struct bce_softc *sc = arg1;
6451bdeb8fffSSepherosa Ziehau 
6452bdeb8fffSSepherosa Ziehau 	return bce_sysctl_coal_change(oidp, arg1, arg2, req,
6453bdeb8fffSSepherosa Ziehau 			&sc->bce_rx_quick_cons_trip,
6454bdeb8fffSSepherosa Ziehau 			BCE_COALMASK_RX_BDS);
6455bdeb8fffSSepherosa Ziehau }
6456bdeb8fffSSepherosa Ziehau 
6457bdeb8fffSSepherosa Ziehau static int
bce_sysctl_rx_ticks_int(SYSCTL_HANDLER_ARGS)6458bdeb8fffSSepherosa Ziehau bce_sysctl_rx_ticks_int(SYSCTL_HANDLER_ARGS)
6459bdeb8fffSSepherosa Ziehau {
6460bdeb8fffSSepherosa Ziehau 	struct bce_softc *sc = arg1;
6461bdeb8fffSSepherosa Ziehau 
6462bdeb8fffSSepherosa Ziehau 	return bce_sysctl_coal_change(oidp, arg1, arg2, req,
6463bdeb8fffSSepherosa Ziehau 			&sc->bce_rx_ticks_int,
6464bdeb8fffSSepherosa Ziehau 			BCE_COALMASK_RX_TICKS_INT);
6465bdeb8fffSSepherosa Ziehau }
6466bdeb8fffSSepherosa Ziehau 
6467bdeb8fffSSepherosa Ziehau static int
bce_sysctl_rx_ticks(SYSCTL_HANDLER_ARGS)6468bdeb8fffSSepherosa Ziehau bce_sysctl_rx_ticks(SYSCTL_HANDLER_ARGS)
6469bdeb8fffSSepherosa Ziehau {
6470bdeb8fffSSepherosa Ziehau 	struct bce_softc *sc = arg1;
6471bdeb8fffSSepherosa Ziehau 
6472bdeb8fffSSepherosa Ziehau 	return bce_sysctl_coal_change(oidp, arg1, arg2, req,
6473bdeb8fffSSepherosa Ziehau 			&sc->bce_rx_ticks,
6474bdeb8fffSSepherosa Ziehau 			BCE_COALMASK_RX_TICKS);
6475bdeb8fffSSepherosa Ziehau }
6476bdeb8fffSSepherosa Ziehau 
6477bdeb8fffSSepherosa Ziehau static int
bce_sysctl_coal_change(SYSCTL_HANDLER_ARGS,uint32_t * coal,uint32_t coalchg_mask)6478bdeb8fffSSepherosa Ziehau bce_sysctl_coal_change(SYSCTL_HANDLER_ARGS, uint32_t *coal,
6479bdeb8fffSSepherosa Ziehau     uint32_t coalchg_mask)
6480bdeb8fffSSepherosa Ziehau {
6481bdeb8fffSSepherosa Ziehau 	struct bce_softc *sc = arg1;
6482bdeb8fffSSepherosa Ziehau 	struct ifnet *ifp = &sc->arpcom.ac_if;
6483bdeb8fffSSepherosa Ziehau 	int error = 0, v;
6484bdeb8fffSSepherosa Ziehau 
648584464af5SSepherosa Ziehau 	ifnet_serialize_all(ifp);
6486bdeb8fffSSepherosa Ziehau 
6487bdeb8fffSSepherosa Ziehau 	v = *coal;
6488bdeb8fffSSepherosa Ziehau 	error = sysctl_handle_int(oidp, &v, 0, req);
6489bdeb8fffSSepherosa Ziehau 	if (!error && req->newptr != NULL) {
6490bdeb8fffSSepherosa Ziehau 		if (v < 0) {
6491bdeb8fffSSepherosa Ziehau 			error = EINVAL;
6492bdeb8fffSSepherosa Ziehau 		} else {
6493bdeb8fffSSepherosa Ziehau 			*coal = v;
6494bdeb8fffSSepherosa Ziehau 			sc->bce_coalchg_mask |= coalchg_mask;
649557b3ecd9SSepherosa Ziehau 
649657b3ecd9SSepherosa Ziehau 			/* Commit changes */
649757b3ecd9SSepherosa Ziehau 			bce_coal_change(sc);
6498bdeb8fffSSepherosa Ziehau 		}
6499bdeb8fffSSepherosa Ziehau 	}
6500bdeb8fffSSepherosa Ziehau 
650184464af5SSepherosa Ziehau 	ifnet_deserialize_all(ifp);
6502bdeb8fffSSepherosa Ziehau 	return error;
6503bdeb8fffSSepherosa Ziehau }
6504bdeb8fffSSepherosa Ziehau 
6505bdeb8fffSSepherosa Ziehau static void
bce_coal_change(struct bce_softc * sc)6506bdeb8fffSSepherosa Ziehau bce_coal_change(struct bce_softc *sc)
6507bdeb8fffSSepherosa Ziehau {
6508bdeb8fffSSepherosa Ziehau 	struct ifnet *ifp = &sc->arpcom.ac_if;
6509b42386eeSSepherosa Ziehau 	int i;
6510bdeb8fffSSepherosa Ziehau 
651184464af5SSepherosa Ziehau 	ASSERT_SERIALIZED(&sc->main_serialize);
6512bdeb8fffSSepherosa Ziehau 
6513bdeb8fffSSepherosa Ziehau 	if ((ifp->if_flags & IFF_RUNNING) == 0) {
6514bdeb8fffSSepherosa Ziehau 		sc->bce_coalchg_mask = 0;
6515bdeb8fffSSepherosa Ziehau 		return;
6516bdeb8fffSSepherosa Ziehau 	}
6517bdeb8fffSSepherosa Ziehau 
6518bdeb8fffSSepherosa Ziehau 	if (sc->bce_coalchg_mask &
6519bdeb8fffSSepherosa Ziehau 	    (BCE_COALMASK_TX_BDS | BCE_COALMASK_TX_BDS_INT)) {
6520bdeb8fffSSepherosa Ziehau 		REG_WR(sc, BCE_HC_TX_QUICK_CONS_TRIP,
6521bdeb8fffSSepherosa Ziehau 		       (sc->bce_tx_quick_cons_trip_int << 16) |
6522bdeb8fffSSepherosa Ziehau 		       sc->bce_tx_quick_cons_trip);
6523b42386eeSSepherosa Ziehau 		for (i = 1; i < sc->rx_ring_cnt; ++i) {
6524b42386eeSSepherosa Ziehau 			uint32_t base;
6525b42386eeSSepherosa Ziehau 
6526b42386eeSSepherosa Ziehau 			base = ((i - 1) * BCE_HC_SB_CONFIG_SIZE) +
6527b42386eeSSepherosa Ziehau 			    BCE_HC_SB_CONFIG_1;
6528b42386eeSSepherosa Ziehau 			REG_WR(sc, base + BCE_HC_TX_QUICK_CONS_TRIP_OFF,
6529b42386eeSSepherosa Ziehau 			    (sc->bce_tx_quick_cons_trip_int << 16) |
6530b42386eeSSepherosa Ziehau 			    sc->bce_tx_quick_cons_trip);
6531b42386eeSSepherosa Ziehau 		}
6532bdeb8fffSSepherosa Ziehau 		if (bootverbose) {
6533bdeb8fffSSepherosa Ziehau 			if_printf(ifp, "tx_bds %u, tx_bds_int %u\n",
6534bdeb8fffSSepherosa Ziehau 				  sc->bce_tx_quick_cons_trip,
6535bdeb8fffSSepherosa Ziehau 				  sc->bce_tx_quick_cons_trip_int);
6536bdeb8fffSSepherosa Ziehau 		}
6537bdeb8fffSSepherosa Ziehau 	}
6538bdeb8fffSSepherosa Ziehau 
6539bdeb8fffSSepherosa Ziehau 	if (sc->bce_coalchg_mask &
6540bdeb8fffSSepherosa Ziehau 	    (BCE_COALMASK_TX_TICKS | BCE_COALMASK_TX_TICKS_INT)) {
6541bdeb8fffSSepherosa Ziehau 		REG_WR(sc, BCE_HC_TX_TICKS,
6542bdeb8fffSSepherosa Ziehau 		       (sc->bce_tx_ticks_int << 16) | sc->bce_tx_ticks);
6543b42386eeSSepherosa Ziehau 		for (i = 1; i < sc->rx_ring_cnt; ++i) {
6544b42386eeSSepherosa Ziehau 			uint32_t base;
6545b42386eeSSepherosa Ziehau 
6546b42386eeSSepherosa Ziehau 			base = ((i - 1) * BCE_HC_SB_CONFIG_SIZE) +
6547b42386eeSSepherosa Ziehau 			    BCE_HC_SB_CONFIG_1;
6548b42386eeSSepherosa Ziehau 			REG_WR(sc, base + BCE_HC_TX_TICKS_OFF,
6549b42386eeSSepherosa Ziehau 			    (sc->bce_tx_ticks_int << 16) | sc->bce_tx_ticks);
6550b42386eeSSepherosa Ziehau 		}
6551bdeb8fffSSepherosa Ziehau 		if (bootverbose) {
6552bdeb8fffSSepherosa Ziehau 			if_printf(ifp, "tx_ticks %u, tx_ticks_int %u\n",
6553bdeb8fffSSepherosa Ziehau 				  sc->bce_tx_ticks, sc->bce_tx_ticks_int);
6554bdeb8fffSSepherosa Ziehau 		}
6555bdeb8fffSSepherosa Ziehau 	}
6556bdeb8fffSSepherosa Ziehau 
6557bdeb8fffSSepherosa Ziehau 	if (sc->bce_coalchg_mask &
6558bdeb8fffSSepherosa Ziehau 	    (BCE_COALMASK_RX_BDS | BCE_COALMASK_RX_BDS_INT)) {
6559bdeb8fffSSepherosa Ziehau 		REG_WR(sc, BCE_HC_RX_QUICK_CONS_TRIP,
6560bdeb8fffSSepherosa Ziehau 		       (sc->bce_rx_quick_cons_trip_int << 16) |
6561bdeb8fffSSepherosa Ziehau 		       sc->bce_rx_quick_cons_trip);
6562b42386eeSSepherosa Ziehau 		for (i = 1; i < sc->rx_ring_cnt; ++i) {
6563b42386eeSSepherosa Ziehau 			uint32_t base;
6564b42386eeSSepherosa Ziehau 
6565b42386eeSSepherosa Ziehau 			base = ((i - 1) * BCE_HC_SB_CONFIG_SIZE) +
6566b42386eeSSepherosa Ziehau 			    BCE_HC_SB_CONFIG_1;
6567b42386eeSSepherosa Ziehau 			REG_WR(sc, base + BCE_HC_RX_QUICK_CONS_TRIP_OFF,
6568b42386eeSSepherosa Ziehau 			    (sc->bce_rx_quick_cons_trip_int << 16) |
6569b42386eeSSepherosa Ziehau 			    sc->bce_rx_quick_cons_trip);
6570b42386eeSSepherosa Ziehau 		}
6571bdeb8fffSSepherosa Ziehau 		if (bootverbose) {
6572bdeb8fffSSepherosa Ziehau 			if_printf(ifp, "rx_bds %u, rx_bds_int %u\n",
6573bdeb8fffSSepherosa Ziehau 				  sc->bce_rx_quick_cons_trip,
6574bdeb8fffSSepherosa Ziehau 				  sc->bce_rx_quick_cons_trip_int);
6575bdeb8fffSSepherosa Ziehau 		}
6576bdeb8fffSSepherosa Ziehau 	}
6577bdeb8fffSSepherosa Ziehau 
6578bdeb8fffSSepherosa Ziehau 	if (sc->bce_coalchg_mask &
6579bdeb8fffSSepherosa Ziehau 	    (BCE_COALMASK_RX_TICKS | BCE_COALMASK_RX_TICKS_INT)) {
6580bdeb8fffSSepherosa Ziehau 		REG_WR(sc, BCE_HC_RX_TICKS,
6581bdeb8fffSSepherosa Ziehau 		       (sc->bce_rx_ticks_int << 16) | sc->bce_rx_ticks);
6582b42386eeSSepherosa Ziehau 		for (i = 1; i < sc->rx_ring_cnt; ++i) {
6583b42386eeSSepherosa Ziehau 			uint32_t base;
6584b42386eeSSepherosa Ziehau 
6585b42386eeSSepherosa Ziehau 			base = ((i - 1) * BCE_HC_SB_CONFIG_SIZE) +
6586b42386eeSSepherosa Ziehau 			    BCE_HC_SB_CONFIG_1;
6587b42386eeSSepherosa Ziehau 			REG_WR(sc, base + BCE_HC_RX_TICKS_OFF,
6588b42386eeSSepherosa Ziehau 			    (sc->bce_rx_ticks_int << 16) | sc->bce_rx_ticks);
6589b42386eeSSepherosa Ziehau 		}
6590bdeb8fffSSepherosa Ziehau 		if (bootverbose) {
6591bdeb8fffSSepherosa Ziehau 			if_printf(ifp, "rx_ticks %u, rx_ticks_int %u\n",
6592bdeb8fffSSepherosa Ziehau 				  sc->bce_rx_ticks, sc->bce_rx_ticks_int);
6593bdeb8fffSSepherosa Ziehau 		}
6594bdeb8fffSSepherosa Ziehau 	}
6595bdeb8fffSSepherosa Ziehau 
6596bdeb8fffSSepherosa Ziehau 	sc->bce_coalchg_mask = 0;
6597bdeb8fffSSepherosa Ziehau }
6598eefd160dSSepherosa Ziehau 
6599eefd160dSSepherosa Ziehau static int
bce_tso_setup(struct bce_tx_ring * txr,struct mbuf ** mp,uint16_t * flags0,uint16_t * mss0)660010bcbdabSSepherosa Ziehau bce_tso_setup(struct bce_tx_ring *txr, struct mbuf **mp,
6601eefd160dSSepherosa Ziehau     uint16_t *flags0, uint16_t *mss0)
6602eefd160dSSepherosa Ziehau {
6603eefd160dSSepherosa Ziehau 	struct mbuf *m;
6604eefd160dSSepherosa Ziehau 	uint16_t flags;
6605eefd160dSSepherosa Ziehau 	int thoff, iphlen, hoff;
6606eefd160dSSepherosa Ziehau 
6607eefd160dSSepherosa Ziehau 	m = *mp;
6608eefd160dSSepherosa Ziehau 	KASSERT(M_WRITABLE(m), ("TSO mbuf not writable"));
6609eefd160dSSepherosa Ziehau 
6610eefd160dSSepherosa Ziehau 	hoff = m->m_pkthdr.csum_lhlen;
6611eefd160dSSepherosa Ziehau 	iphlen = m->m_pkthdr.csum_iphlen;
6612eefd160dSSepherosa Ziehau 	thoff = m->m_pkthdr.csum_thlen;
6613eefd160dSSepherosa Ziehau 
6614eefd160dSSepherosa Ziehau 	KASSERT(hoff >= sizeof(struct ether_header),
6615eefd160dSSepherosa Ziehau 	    ("invalid ether header len %d", hoff));
6616eefd160dSSepherosa Ziehau 	KASSERT(iphlen >= sizeof(struct ip),
6617eefd160dSSepherosa Ziehau 	    ("invalid ip header len %d", iphlen));
6618eefd160dSSepherosa Ziehau 	KASSERT(thoff >= sizeof(struct tcphdr),
6619eefd160dSSepherosa Ziehau 	    ("invalid tcp header len %d", thoff));
6620eefd160dSSepherosa Ziehau 
6621eefd160dSSepherosa Ziehau 	if (__predict_false(m->m_len < hoff + iphlen + thoff)) {
6622eefd160dSSepherosa Ziehau 		m = m_pullup(m, hoff + iphlen + thoff);
6623eefd160dSSepherosa Ziehau 		if (m == NULL) {
6624eefd160dSSepherosa Ziehau 			*mp = NULL;
6625eefd160dSSepherosa Ziehau 			return ENOBUFS;
6626eefd160dSSepherosa Ziehau 		}
6627eefd160dSSepherosa Ziehau 		*mp = m;
6628eefd160dSSepherosa Ziehau 	}
6629eefd160dSSepherosa Ziehau 
6630eefd160dSSepherosa Ziehau 	/* Set the LSO flag in the TX BD */
6631eefd160dSSepherosa Ziehau 	flags = TX_BD_FLAGS_SW_LSO;
6632eefd160dSSepherosa Ziehau 
6633eefd160dSSepherosa Ziehau 	/* Set the length of IP + TCP options (in 32 bit words) */
6634eefd160dSSepherosa Ziehau 	flags |= (((iphlen + thoff -
6635eefd160dSSepherosa Ziehau 	    sizeof(struct ip) - sizeof(struct tcphdr)) >> 2) << 8);
6636eefd160dSSepherosa Ziehau 
6637eefd160dSSepherosa Ziehau 	*mss0 = htole16(m->m_pkthdr.tso_segsz);
6638eefd160dSSepherosa Ziehau 	*flags0 = flags;
6639eefd160dSSepherosa Ziehau 
6640eefd160dSSepherosa Ziehau 	return 0;
6641eefd160dSSepherosa Ziehau }
664284464af5SSepherosa Ziehau 
664384464af5SSepherosa Ziehau static void
bce_setup_serialize(struct bce_softc * sc)664484464af5SSepherosa Ziehau bce_setup_serialize(struct bce_softc *sc)
664584464af5SSepherosa Ziehau {
664684464af5SSepherosa Ziehau 	int i, j;
664784464af5SSepherosa Ziehau 
664884464af5SSepherosa Ziehau 	/*
664984464af5SSepherosa Ziehau 	 * Allocate serializer array
665084464af5SSepherosa Ziehau 	 */
665184464af5SSepherosa Ziehau 
665284464af5SSepherosa Ziehau 	/* Main + TX + RX */
6653ac2202eaSSepherosa Ziehau 	sc->serialize_cnt = 1 + sc->tx_ring_cnt + sc->rx_ring_cnt;
665484464af5SSepherosa Ziehau 
665584464af5SSepherosa Ziehau 	sc->serializes =
665684464af5SSepherosa Ziehau 	    kmalloc(sc->serialize_cnt * sizeof(struct lwkt_serialize *),
665784464af5SSepherosa Ziehau 	        M_DEVBUF, M_WAITOK | M_ZERO);
665884464af5SSepherosa Ziehau 
665984464af5SSepherosa Ziehau 	/*
666084464af5SSepherosa Ziehau 	 * Setup serializers
666184464af5SSepherosa Ziehau 	 *
666284464af5SSepherosa Ziehau 	 * NOTE: Order is critical
666384464af5SSepherosa Ziehau 	 */
666484464af5SSepherosa Ziehau 
666584464af5SSepherosa Ziehau 	i = 0;
666606421337SSepherosa Ziehau 
666784464af5SSepherosa Ziehau 	KKASSERT(i < sc->serialize_cnt);
666884464af5SSepherosa Ziehau 	sc->serializes[i++] = &sc->main_serialize;
666984464af5SSepherosa Ziehau 
6670ac2202eaSSepherosa Ziehau 	for (j = 0; j < sc->rx_ring_cnt; ++j) {
667184464af5SSepherosa Ziehau 		KKASSERT(i < sc->serialize_cnt);
667284464af5SSepherosa Ziehau 		sc->serializes[i++] = &sc->rx_rings[j].rx_serialize;
667384464af5SSepherosa Ziehau 	}
667484464af5SSepherosa Ziehau 
66750d2d2c8cSSepherosa Ziehau 	for (j = 0; j < sc->tx_ring_cnt; ++j) {
66760d2d2c8cSSepherosa Ziehau 		KKASSERT(i < sc->serialize_cnt);
66770d2d2c8cSSepherosa Ziehau 		sc->serializes[i++] = &sc->tx_rings[j].tx_serialize;
66780d2d2c8cSSepherosa Ziehau 	}
66790d2d2c8cSSepherosa Ziehau 
668084464af5SSepherosa Ziehau 	KKASSERT(i == sc->serialize_cnt);
668184464af5SSepherosa Ziehau }
668284464af5SSepherosa Ziehau 
668384464af5SSepherosa Ziehau static void
bce_serialize(struct ifnet * ifp,enum ifnet_serialize slz)668484464af5SSepherosa Ziehau bce_serialize(struct ifnet *ifp, enum ifnet_serialize slz)
668584464af5SSepherosa Ziehau {
668684464af5SSepherosa Ziehau 	struct bce_softc *sc = ifp->if_softc;
668784464af5SSepherosa Ziehau 
668806421337SSepherosa Ziehau 	ifnet_serialize_array_enter(sc->serializes, sc->serialize_cnt, slz);
668984464af5SSepherosa Ziehau }
669084464af5SSepherosa Ziehau 
669184464af5SSepherosa Ziehau static void
bce_deserialize(struct ifnet * ifp,enum ifnet_serialize slz)669284464af5SSepherosa Ziehau bce_deserialize(struct ifnet *ifp, enum ifnet_serialize slz)
669384464af5SSepherosa Ziehau {
669484464af5SSepherosa Ziehau 	struct bce_softc *sc = ifp->if_softc;
669584464af5SSepherosa Ziehau 
669606421337SSepherosa Ziehau 	ifnet_serialize_array_exit(sc->serializes, sc->serialize_cnt, slz);
669784464af5SSepherosa Ziehau }
669884464af5SSepherosa Ziehau 
669984464af5SSepherosa Ziehau static int
bce_tryserialize(struct ifnet * ifp,enum ifnet_serialize slz)670084464af5SSepherosa Ziehau bce_tryserialize(struct ifnet *ifp, enum ifnet_serialize slz)
670184464af5SSepherosa Ziehau {
670284464af5SSepherosa Ziehau 	struct bce_softc *sc = ifp->if_softc;
670384464af5SSepherosa Ziehau 
670484464af5SSepherosa Ziehau 	return ifnet_serialize_array_try(sc->serializes, sc->serialize_cnt,
670506421337SSepherosa Ziehau 	    slz);
670684464af5SSepherosa Ziehau }
670784464af5SSepherosa Ziehau 
670884464af5SSepherosa Ziehau #ifdef INVARIANTS
670984464af5SSepherosa Ziehau 
671084464af5SSepherosa Ziehau static void
bce_serialize_assert(struct ifnet * ifp,enum ifnet_serialize slz,boolean_t serialized)671184464af5SSepherosa Ziehau bce_serialize_assert(struct ifnet *ifp, enum ifnet_serialize slz,
671284464af5SSepherosa Ziehau     boolean_t serialized)
671384464af5SSepherosa Ziehau {
671484464af5SSepherosa Ziehau 	struct bce_softc *sc = ifp->if_softc;
671584464af5SSepherosa Ziehau 
671684464af5SSepherosa Ziehau 	ifnet_serialize_array_assert(sc->serializes, sc->serialize_cnt,
671706421337SSepherosa Ziehau 	    slz, serialized);
671884464af5SSepherosa Ziehau }
671984464af5SSepherosa Ziehau 
672084464af5SSepherosa Ziehau #endif	/* INVARIANTS */
672184464af5SSepherosa Ziehau 
672284464af5SSepherosa Ziehau static void
bce_serialize_skipmain(struct bce_softc * sc)672384464af5SSepherosa Ziehau bce_serialize_skipmain(struct bce_softc *sc)
672484464af5SSepherosa Ziehau {
672584464af5SSepherosa Ziehau 	lwkt_serialize_array_enter(sc->serializes, sc->serialize_cnt, 1);
672684464af5SSepherosa Ziehau }
672784464af5SSepherosa Ziehau 
672884464af5SSepherosa Ziehau static void
bce_deserialize_skipmain(struct bce_softc * sc)672984464af5SSepherosa Ziehau bce_deserialize_skipmain(struct bce_softc *sc)
673084464af5SSepherosa Ziehau {
673184464af5SSepherosa Ziehau 	lwkt_serialize_array_exit(sc->serializes, sc->serialize_cnt, 1);
673284464af5SSepherosa Ziehau }
673357b3ecd9SSepherosa Ziehau 
6734745b3d68SSepherosa Ziehau static void
bce_set_timer_cpuid(struct bce_softc * sc,boolean_t polling)6735745b3d68SSepherosa Ziehau bce_set_timer_cpuid(struct bce_softc *sc, boolean_t polling)
6736745b3d68SSepherosa Ziehau {
6737745b3d68SSepherosa Ziehau 	if (polling)
6738745b3d68SSepherosa Ziehau 		sc->bce_timer_cpuid = 0; /* XXX */
6739745b3d68SSepherosa Ziehau 	else
6740b42386eeSSepherosa Ziehau 		sc->bce_timer_cpuid = sc->bce_msix[0].msix_cpuid;
6741b42386eeSSepherosa Ziehau }
6742b42386eeSSepherosa Ziehau 
6743b42386eeSSepherosa Ziehau static int
bce_alloc_intr(struct bce_softc * sc)6744b42386eeSSepherosa Ziehau bce_alloc_intr(struct bce_softc *sc)
6745b42386eeSSepherosa Ziehau {
6746b42386eeSSepherosa Ziehau 	u_int irq_flags;
6747b42386eeSSepherosa Ziehau 
6748b42386eeSSepherosa Ziehau 	bce_try_alloc_msix(sc);
6749b42386eeSSepherosa Ziehau 	if (sc->bce_irq_type == PCI_INTR_TYPE_MSIX)
6750b42386eeSSepherosa Ziehau 		return 0;
6751b42386eeSSepherosa Ziehau 
6752b42386eeSSepherosa Ziehau 	sc->bce_irq_type = pci_alloc_1intr(sc->bce_dev, bce_msi_enable,
6753b42386eeSSepherosa Ziehau 	    &sc->bce_irq_rid, &irq_flags);
6754b42386eeSSepherosa Ziehau 
6755b42386eeSSepherosa Ziehau 	sc->bce_res_irq = bus_alloc_resource_any(sc->bce_dev, SYS_RES_IRQ,
6756b42386eeSSepherosa Ziehau 	    &sc->bce_irq_rid, irq_flags);
6757b42386eeSSepherosa Ziehau 	if (sc->bce_res_irq == NULL) {
6758b42386eeSSepherosa Ziehau 		device_printf(sc->bce_dev, "PCI map interrupt failed\n");
6759b42386eeSSepherosa Ziehau 		return ENXIO;
6760b42386eeSSepherosa Ziehau 	}
67612760ec42SSepherosa Ziehau 	sc->bce_msix[0].msix_cpuid = rman_get_cpuid(sc->bce_res_irq);
67622760ec42SSepherosa Ziehau 	sc->bce_msix[0].msix_serialize = &sc->main_serialize;
67632760ec42SSepherosa Ziehau 
6764b42386eeSSepherosa Ziehau 	return 0;
6765b42386eeSSepherosa Ziehau }
6766b42386eeSSepherosa Ziehau 
6767b42386eeSSepherosa Ziehau static void
bce_try_alloc_msix(struct bce_softc * sc)6768b42386eeSSepherosa Ziehau bce_try_alloc_msix(struct bce_softc *sc)
6769b42386eeSSepherosa Ziehau {
6770b42386eeSSepherosa Ziehau 	struct bce_msix_data *msix;
677139ea245fSSepherosa Ziehau 	int i, error;
6772b42386eeSSepherosa Ziehau 	boolean_t setup = FALSE;
6773b42386eeSSepherosa Ziehau 
6774b42386eeSSepherosa Ziehau 	if (sc->rx_ring_cnt == 1)
6775b42386eeSSepherosa Ziehau 		return;
6776b42386eeSSepherosa Ziehau 
6777b42386eeSSepherosa Ziehau 	msix = &sc->bce_msix[0];
6778b42386eeSSepherosa Ziehau 	msix->msix_serialize = &sc->main_serialize;
6779b42386eeSSepherosa Ziehau 	msix->msix_func = bce_intr_msi_oneshot;
6780b42386eeSSepherosa Ziehau 	msix->msix_arg = sc;
678139ea245fSSepherosa Ziehau 	msix->msix_cpuid = if_ringmap_cpumap(sc->rx_rmap, 0);
678239ea245fSSepherosa Ziehau 	KKASSERT(msix->msix_cpuid < netisr_ncpus);
6783b42386eeSSepherosa Ziehau 	ksnprintf(msix->msix_desc, sizeof(msix->msix_desc), "%s combo",
6784b42386eeSSepherosa Ziehau 	    device_get_nameunit(sc->bce_dev));
6785b42386eeSSepherosa Ziehau 
6786b42386eeSSepherosa Ziehau 	for (i = 1; i < sc->rx_ring_cnt; ++i) {
6787b42386eeSSepherosa Ziehau 		struct bce_rx_ring *rxr = &sc->rx_rings[i];
6788b42386eeSSepherosa Ziehau 
6789b42386eeSSepherosa Ziehau 		msix = &sc->bce_msix[i];
6790b42386eeSSepherosa Ziehau 
6791b42386eeSSepherosa Ziehau 		msix->msix_serialize = &rxr->rx_serialize;
6792b42386eeSSepherosa Ziehau 		msix->msix_arg = rxr;
679339ea245fSSepherosa Ziehau 		msix->msix_cpuid = if_ringmap_cpumap(sc->rx_rmap,
679439ea245fSSepherosa Ziehau 		    i % sc->rx_ring_cnt2);
679539ea245fSSepherosa Ziehau 		KKASSERT(msix->msix_cpuid < netisr_ncpus);
6796b42386eeSSepherosa Ziehau 
6797b42386eeSSepherosa Ziehau 		if (i < sc->tx_ring_cnt) {
6798b42386eeSSepherosa Ziehau 			msix->msix_func = bce_intr_msix_rxtx;
6799b42386eeSSepherosa Ziehau 			ksnprintf(msix->msix_desc, sizeof(msix->msix_desc),
6800b42386eeSSepherosa Ziehau 			    "%s rxtx%d", device_get_nameunit(sc->bce_dev), i);
6801b42386eeSSepherosa Ziehau 		} else {
6802b42386eeSSepherosa Ziehau 			msix->msix_func = bce_intr_msix_rx;
6803b42386eeSSepherosa Ziehau 			ksnprintf(msix->msix_desc, sizeof(msix->msix_desc),
6804b42386eeSSepherosa Ziehau 			    "%s rx%d", device_get_nameunit(sc->bce_dev), i);
6805b42386eeSSepherosa Ziehau 		}
6806b42386eeSSepherosa Ziehau 	}
6807b42386eeSSepherosa Ziehau 
6808b42386eeSSepherosa Ziehau 	/*
6809b42386eeSSepherosa Ziehau 	 * Setup MSI-X table
6810b42386eeSSepherosa Ziehau 	 */
6811b42386eeSSepherosa Ziehau 	bce_setup_msix_table(sc);
6812b42386eeSSepherosa Ziehau 	REG_WR(sc, BCE_PCI_MSIX_CONTROL, BCE_MSIX_MAX - 1);
6813b42386eeSSepherosa Ziehau 	REG_WR(sc, BCE_PCI_MSIX_TBL_OFF_BIR, BCE_PCI_GRC_WINDOW2_BASE);
6814b42386eeSSepherosa Ziehau 	REG_WR(sc, BCE_PCI_MSIX_PBA_OFF_BIT, BCE_PCI_GRC_WINDOW3_BASE);
6815b42386eeSSepherosa Ziehau 	/* Flush */
6816b42386eeSSepherosa Ziehau 	REG_RD(sc, BCE_PCI_MSIX_CONTROL);
6817b42386eeSSepherosa Ziehau 
6818b42386eeSSepherosa Ziehau 	error = pci_setup_msix(sc->bce_dev);
6819b42386eeSSepherosa Ziehau 	if (error) {
6820b42386eeSSepherosa Ziehau 		device_printf(sc->bce_dev, "Setup MSI-X failed\n");
6821b42386eeSSepherosa Ziehau 		goto back;
6822b42386eeSSepherosa Ziehau 	}
6823b42386eeSSepherosa Ziehau 	setup = TRUE;
6824b42386eeSSepherosa Ziehau 
6825b42386eeSSepherosa Ziehau 	for (i = 0; i < sc->rx_ring_cnt; ++i) {
6826b42386eeSSepherosa Ziehau 		msix = &sc->bce_msix[i];
6827b42386eeSSepherosa Ziehau 
6828b42386eeSSepherosa Ziehau 		error = pci_alloc_msix_vector(sc->bce_dev, i, &msix->msix_rid,
6829b42386eeSSepherosa Ziehau 		    msix->msix_cpuid);
6830b42386eeSSepherosa Ziehau 		if (error) {
6831b42386eeSSepherosa Ziehau 			device_printf(sc->bce_dev,
6832b42386eeSSepherosa Ziehau 			    "Unable to allocate MSI-X %d on cpu%d\n",
6833b42386eeSSepherosa Ziehau 			    i, msix->msix_cpuid);
6834b42386eeSSepherosa Ziehau 			goto back;
6835b42386eeSSepherosa Ziehau 		}
6836b42386eeSSepherosa Ziehau 
6837b42386eeSSepherosa Ziehau 		msix->msix_res = bus_alloc_resource_any(sc->bce_dev,
6838b42386eeSSepherosa Ziehau 		    SYS_RES_IRQ, &msix->msix_rid, RF_ACTIVE);
6839b42386eeSSepherosa Ziehau 		if (msix->msix_res == NULL) {
6840b42386eeSSepherosa Ziehau 			device_printf(sc->bce_dev,
6841b42386eeSSepherosa Ziehau 			    "Unable to allocate MSI-X %d resource\n", i);
6842b42386eeSSepherosa Ziehau 			error = ENOMEM;
6843b42386eeSSepherosa Ziehau 			goto back;
6844b42386eeSSepherosa Ziehau 		}
6845b42386eeSSepherosa Ziehau 	}
6846b42386eeSSepherosa Ziehau 
6847b42386eeSSepherosa Ziehau 	pci_enable_msix(sc->bce_dev);
6848b42386eeSSepherosa Ziehau 	sc->bce_irq_type = PCI_INTR_TYPE_MSIX;
6849b42386eeSSepherosa Ziehau back:
6850b42386eeSSepherosa Ziehau 	if (error)
6851b42386eeSSepherosa Ziehau 		bce_free_msix(sc, setup);
6852b42386eeSSepherosa Ziehau }
6853b42386eeSSepherosa Ziehau 
6854b42386eeSSepherosa Ziehau static void
bce_setup_ring_cnt(struct bce_softc * sc)6855b42386eeSSepherosa Ziehau bce_setup_ring_cnt(struct bce_softc *sc)
6856b42386eeSSepherosa Ziehau {
685739ea245fSSepherosa Ziehau 	int msix_enable, msix_cnt, msix_ring;
685839ea245fSSepherosa Ziehau 	int ring_max, ring_cnt;
6859b42386eeSSepherosa Ziehau 
686039ea245fSSepherosa Ziehau 	sc->rx_rmap = if_ringmap_alloc(sc->bce_dev, 1, 1);
6861b42386eeSSepherosa Ziehau 
686227a8bb35SSepherosa Ziehau 	if (BCE_CHIP_NUM(sc) != BCE_CHIP_NUM_5709 &&
686327a8bb35SSepherosa Ziehau 	    BCE_CHIP_NUM(sc) != BCE_CHIP_NUM_5716)
686439ea245fSSepherosa Ziehau 		goto skip_rx;
6865b42386eeSSepherosa Ziehau 
6866b42386eeSSepherosa Ziehau 	msix_enable = device_getenv_int(sc->bce_dev, "msix.enable",
6867b42386eeSSepherosa Ziehau 	    bce_msix_enable);
6868b42386eeSSepherosa Ziehau 	if (!msix_enable)
686939ea245fSSepherosa Ziehau 		goto skip_rx;
6870b42386eeSSepherosa Ziehau 
687139ea245fSSepherosa Ziehau 	if (netisr_ncpus == 1)
687239ea245fSSepherosa Ziehau 		goto skip_rx;
6873b42386eeSSepherosa Ziehau 
6874b42386eeSSepherosa Ziehau 	/*
6875b42386eeSSepherosa Ziehau 	 * One extra RX ring will be needed (see below), so make sure
6876b42386eeSSepherosa Ziehau 	 * that there are enough MSI-X vectors.
6877b42386eeSSepherosa Ziehau 	 */
687839ea245fSSepherosa Ziehau 	msix_cnt = pci_msix_count(sc->bce_dev);
687939ea245fSSepherosa Ziehau 	if (msix_cnt <= 2)
688039ea245fSSepherosa Ziehau 		goto skip_rx;
688139ea245fSSepherosa Ziehau 	msix_ring = msix_cnt - 1;
6882b42386eeSSepherosa Ziehau 
6883b42386eeSSepherosa Ziehau 	/*
6884b42386eeSSepherosa Ziehau 	 * Setup RX ring count
6885b42386eeSSepherosa Ziehau 	 */
6886b42386eeSSepherosa Ziehau 	ring_max = BCE_RX_RING_MAX;
688739ea245fSSepherosa Ziehau 	if (ring_max > msix_ring)
688839ea245fSSepherosa Ziehau 		ring_max = msix_ring;
688939ea245fSSepherosa Ziehau 	ring_cnt = device_getenv_int(sc->bce_dev, "rx_rings", bce_rx_rings);
6890b42386eeSSepherosa Ziehau 
689139ea245fSSepherosa Ziehau 	if_ringmap_free(sc->rx_rmap);
689239ea245fSSepherosa Ziehau 	sc->rx_rmap = if_ringmap_alloc(sc->bce_dev, ring_cnt, ring_max);
68930f6c4c52SSepherosa Ziehau 
689439ea245fSSepherosa Ziehau skip_rx:
689539ea245fSSepherosa Ziehau 	sc->rx_ring_cnt2 = if_ringmap_count(sc->rx_rmap);
6896b42386eeSSepherosa Ziehau 
6897b42386eeSSepherosa Ziehau 	/*
6898b42386eeSSepherosa Ziehau 	 * Setup TX ring count
6899b42386eeSSepherosa Ziehau 	 *
6900b42386eeSSepherosa Ziehau 	 * NOTE:
6901b42386eeSSepherosa Ziehau 	 * TX ring count must be less than the effective RSS RX ring
6902b42386eeSSepherosa Ziehau 	 * count, since we use RX ring software data struct to save
6903b42386eeSSepherosa Ziehau 	 * status index and various other MSI-X related stuffs.
6904b42386eeSSepherosa Ziehau 	 */
6905b42386eeSSepherosa Ziehau 	ring_max = BCE_TX_RING_MAX;
6906b42386eeSSepherosa Ziehau 	if (ring_max > sc->rx_ring_cnt2)
6907b42386eeSSepherosa Ziehau 		ring_max = sc->rx_ring_cnt2;
690839ea245fSSepherosa Ziehau 	ring_cnt = device_getenv_int(sc->bce_dev, "tx_rings", bce_tx_rings);
690939ea245fSSepherosa Ziehau 
691039ea245fSSepherosa Ziehau 	sc->tx_rmap = if_ringmap_alloc(sc->bce_dev, ring_cnt, ring_max);
691139ea245fSSepherosa Ziehau 	if_ringmap_align(sc->bce_dev, sc->rx_rmap, sc->tx_rmap);
691239ea245fSSepherosa Ziehau 
691339ea245fSSepherosa Ziehau 	sc->tx_ring_cnt = if_ringmap_count(sc->tx_rmap);
691439ea245fSSepherosa Ziehau 
691539ea245fSSepherosa Ziehau 	if (sc->rx_ring_cnt2 == 1) {
691639ea245fSSepherosa Ziehau 		/*
691739ea245fSSepherosa Ziehau 		 * Don't use MSI-X, if the effective RX ring count is 1.
691839ea245fSSepherosa Ziehau 		 * Since if the effective RX ring count is 1, the TX ring
691939ea245fSSepherosa Ziehau 		 * count will be 1.  This RX ring and the TX ring must be
692039ea245fSSepherosa Ziehau 		 * bundled into one MSI-X vector, so the hot path will be
692139ea245fSSepherosa Ziehau 		 * exact same as using MSI.  Besides, the first RX ring
692239ea245fSSepherosa Ziehau 		 * must be fully populated, which only accepts packets whose
692339ea245fSSepherosa Ziehau 		 * RSS hash can't calculated, e.g. ARP packets; waste of
692439ea245fSSepherosa Ziehau 		 * resource at least.
692539ea245fSSepherosa Ziehau 		 */
692639ea245fSSepherosa Ziehau 		sc->rx_ring_cnt = 1;
692739ea245fSSepherosa Ziehau 	} else {
692839ea245fSSepherosa Ziehau 		/*
692939ea245fSSepherosa Ziehau 		 * One extra RX ring is allocated, since the first RX ring
693039ea245fSSepherosa Ziehau 		 * could not be used for RSS hashed packets whose masked
693139ea245fSSepherosa Ziehau 		 * hash is 0.  The first RX ring is only used for packets
693239ea245fSSepherosa Ziehau 		 * whose RSS hash could not be calculated, e.g. ARP packets.
693339ea245fSSepherosa Ziehau 		 * This extra RX ring will be used for packets whose masked
693439ea245fSSepherosa Ziehau 		 * hash is 0.  The effective RX ring count involved in RSS
693539ea245fSSepherosa Ziehau 		 * is still sc->rx_ring_cnt2.
693639ea245fSSepherosa Ziehau 		 */
693739ea245fSSepherosa Ziehau 		sc->rx_ring_cnt = sc->rx_ring_cnt2 + 1;
693839ea245fSSepherosa Ziehau 	}
6939b42386eeSSepherosa Ziehau }
6940b42386eeSSepherosa Ziehau 
6941b42386eeSSepherosa Ziehau static void
bce_free_msix(struct bce_softc * sc,boolean_t setup)6942b42386eeSSepherosa Ziehau bce_free_msix(struct bce_softc *sc, boolean_t setup)
6943b42386eeSSepherosa Ziehau {
6944b42386eeSSepherosa Ziehau 	int i;
6945b42386eeSSepherosa Ziehau 
6946b42386eeSSepherosa Ziehau 	KKASSERT(sc->rx_ring_cnt > 1);
6947b42386eeSSepherosa Ziehau 
6948b42386eeSSepherosa Ziehau 	for (i = 0; i < sc->rx_ring_cnt; ++i) {
6949b42386eeSSepherosa Ziehau 		struct bce_msix_data *msix = &sc->bce_msix[i];
6950b42386eeSSepherosa Ziehau 
6951b42386eeSSepherosa Ziehau 		if (msix->msix_res != NULL) {
6952b42386eeSSepherosa Ziehau 			bus_release_resource(sc->bce_dev, SYS_RES_IRQ,
6953b42386eeSSepherosa Ziehau 			    msix->msix_rid, msix->msix_res);
6954b42386eeSSepherosa Ziehau 		}
6955b42386eeSSepherosa Ziehau 		if (msix->msix_rid >= 0)
6956b42386eeSSepherosa Ziehau 			pci_release_msix_vector(sc->bce_dev, msix->msix_rid);
6957b42386eeSSepherosa Ziehau 	}
6958b42386eeSSepherosa Ziehau 	if (setup)
6959b42386eeSSepherosa Ziehau 		pci_teardown_msix(sc->bce_dev);
6960b42386eeSSepherosa Ziehau }
6961b42386eeSSepherosa Ziehau 
6962b42386eeSSepherosa Ziehau static void
bce_free_intr(struct bce_softc * sc)6963b42386eeSSepherosa Ziehau bce_free_intr(struct bce_softc *sc)
6964b42386eeSSepherosa Ziehau {
6965b42386eeSSepherosa Ziehau 	if (sc->bce_irq_type != PCI_INTR_TYPE_MSIX) {
6966b42386eeSSepherosa Ziehau 		if (sc->bce_res_irq != NULL) {
6967b42386eeSSepherosa Ziehau 			bus_release_resource(sc->bce_dev, SYS_RES_IRQ,
6968b42386eeSSepherosa Ziehau 			    sc->bce_irq_rid, sc->bce_res_irq);
6969b42386eeSSepherosa Ziehau 		}
6970b42386eeSSepherosa Ziehau 		if (sc->bce_irq_type == PCI_INTR_TYPE_MSI)
6971b42386eeSSepherosa Ziehau 			pci_release_msi(sc->bce_dev);
6972b42386eeSSepherosa Ziehau 	} else {
6973b42386eeSSepherosa Ziehau 		bce_free_msix(sc, TRUE);
6974b42386eeSSepherosa Ziehau 	}
6975b42386eeSSepherosa Ziehau }
6976b42386eeSSepherosa Ziehau 
6977b42386eeSSepherosa Ziehau static void
bce_setup_msix_table(struct bce_softc * sc)6978b42386eeSSepherosa Ziehau bce_setup_msix_table(struct bce_softc *sc)
6979b42386eeSSepherosa Ziehau {
6980b42386eeSSepherosa Ziehau 	REG_WR(sc, BCE_PCI_GRC_WINDOW_ADDR, BCE_PCI_GRC_WINDOW_ADDR_SEP_WIN);
6981b42386eeSSepherosa Ziehau 	REG_WR(sc, BCE_PCI_GRC_WINDOW2_ADDR, BCE_MSIX_TABLE_ADDR);
6982b42386eeSSepherosa Ziehau 	REG_WR(sc, BCE_PCI_GRC_WINDOW3_ADDR, BCE_MSIX_PBA_ADDR);
6983b42386eeSSepherosa Ziehau }
6984b42386eeSSepherosa Ziehau 
6985b42386eeSSepherosa Ziehau static int
bce_setup_intr(struct bce_softc * sc)6986b42386eeSSepherosa Ziehau bce_setup_intr(struct bce_softc *sc)
6987b42386eeSSepherosa Ziehau {
6988b42386eeSSepherosa Ziehau 	void (*irq_handle)(void *);
6989b42386eeSSepherosa Ziehau 	int error;
6990b42386eeSSepherosa Ziehau 
6991b42386eeSSepherosa Ziehau 	if (sc->bce_irq_type == PCI_INTR_TYPE_MSIX)
6992b42386eeSSepherosa Ziehau 		return bce_setup_msix(sc);
6993b42386eeSSepherosa Ziehau 
6994b42386eeSSepherosa Ziehau 	if (sc->bce_irq_type == PCI_INTR_TYPE_LEGACY) {
6995b42386eeSSepherosa Ziehau 		irq_handle = bce_intr_legacy;
6996b42386eeSSepherosa Ziehau 	} else if (sc->bce_irq_type == PCI_INTR_TYPE_MSI) {
6997bd789d01SSepherosa Ziehau 		if (BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5709 ||
6998bd789d01SSepherosa Ziehau 		    BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5716) {
6999b42386eeSSepherosa Ziehau 			irq_handle = bce_intr_msi_oneshot;
7000b42386eeSSepherosa Ziehau 			sc->bce_flags |= BCE_ONESHOT_MSI_FLAG;
7001b42386eeSSepherosa Ziehau 		} else {
7002b42386eeSSepherosa Ziehau 			irq_handle = bce_intr_msi;
7003b42386eeSSepherosa Ziehau 			sc->bce_flags |= BCE_CHECK_MSI_FLAG;
7004b42386eeSSepherosa Ziehau 		}
7005b42386eeSSepherosa Ziehau 	} else {
7006b42386eeSSepherosa Ziehau 		panic("%s: unsupported intr type %d",
7007b42386eeSSepherosa Ziehau 		    device_get_nameunit(sc->bce_dev), sc->bce_irq_type);
7008b42386eeSSepherosa Ziehau 	}
7009b42386eeSSepherosa Ziehau 
7010b42386eeSSepherosa Ziehau 	error = bus_setup_intr(sc->bce_dev, sc->bce_res_irq, INTR_MPSAFE,
7011b42386eeSSepherosa Ziehau 	    irq_handle, sc, &sc->bce_intrhand, &sc->main_serialize);
7012b42386eeSSepherosa Ziehau 	if (error != 0) {
7013b42386eeSSepherosa Ziehau 		device_printf(sc->bce_dev, "Failed to setup IRQ!\n");
7014b42386eeSSepherosa Ziehau 		return error;
7015b42386eeSSepherosa Ziehau 	}
7016b42386eeSSepherosa Ziehau 
7017b42386eeSSepherosa Ziehau 	return 0;
7018b42386eeSSepherosa Ziehau }
7019b42386eeSSepherosa Ziehau 
7020b42386eeSSepherosa Ziehau static void
bce_teardown_intr(struct bce_softc * sc)7021b42386eeSSepherosa Ziehau bce_teardown_intr(struct bce_softc *sc)
7022b42386eeSSepherosa Ziehau {
7023b42386eeSSepherosa Ziehau 	if (sc->bce_irq_type != PCI_INTR_TYPE_MSIX)
7024b42386eeSSepherosa Ziehau 		bus_teardown_intr(sc->bce_dev, sc->bce_res_irq, sc->bce_intrhand);
7025b42386eeSSepherosa Ziehau 	else
7026b42386eeSSepherosa Ziehau 		bce_teardown_msix(sc, sc->rx_ring_cnt);
7027b42386eeSSepherosa Ziehau }
7028b42386eeSSepherosa Ziehau 
7029b42386eeSSepherosa Ziehau static int
bce_setup_msix(struct bce_softc * sc)7030b42386eeSSepherosa Ziehau bce_setup_msix(struct bce_softc *sc)
7031b42386eeSSepherosa Ziehau {
7032b42386eeSSepherosa Ziehau 	int i;
7033b42386eeSSepherosa Ziehau 
7034b42386eeSSepherosa Ziehau 	for (i = 0; i < sc->rx_ring_cnt; ++i) {
7035b42386eeSSepherosa Ziehau 		struct bce_msix_data *msix = &sc->bce_msix[i];
7036b42386eeSSepherosa Ziehau 		int error;
7037b42386eeSSepherosa Ziehau 
7038b42386eeSSepherosa Ziehau 		error = bus_setup_intr_descr(sc->bce_dev, msix->msix_res,
7039b42386eeSSepherosa Ziehau 		    INTR_MPSAFE, msix->msix_func, msix->msix_arg,
7040b42386eeSSepherosa Ziehau 		    &msix->msix_handle, msix->msix_serialize, msix->msix_desc);
7041b42386eeSSepherosa Ziehau 		if (error) {
7042b42386eeSSepherosa Ziehau 			device_printf(sc->bce_dev, "could not set up %s "
7043b42386eeSSepherosa Ziehau 			    "interrupt handler.\n", msix->msix_desc);
7044b42386eeSSepherosa Ziehau 			bce_teardown_msix(sc, i);
7045b42386eeSSepherosa Ziehau 			return error;
7046b42386eeSSepherosa Ziehau 		}
7047b42386eeSSepherosa Ziehau 	}
7048b42386eeSSepherosa Ziehau 	return 0;
7049b42386eeSSepherosa Ziehau }
7050b42386eeSSepherosa Ziehau 
7051b42386eeSSepherosa Ziehau static void
bce_teardown_msix(struct bce_softc * sc,int msix_cnt)7052b42386eeSSepherosa Ziehau bce_teardown_msix(struct bce_softc *sc, int msix_cnt)
7053b42386eeSSepherosa Ziehau {
7054b42386eeSSepherosa Ziehau 	int i;
7055b42386eeSSepherosa Ziehau 
7056b42386eeSSepherosa Ziehau 	for (i = 0; i < msix_cnt; ++i) {
7057b42386eeSSepherosa Ziehau 		struct bce_msix_data *msix = &sc->bce_msix[i];
7058b42386eeSSepherosa Ziehau 
7059b42386eeSSepherosa Ziehau 		bus_teardown_intr(sc->bce_dev, msix->msix_res,
7060b42386eeSSepherosa Ziehau 		    msix->msix_handle);
7061b42386eeSSepherosa Ziehau 	}
7062b42386eeSSepherosa Ziehau }
7063b42386eeSSepherosa Ziehau 
7064b42386eeSSepherosa Ziehau static void
bce_init_rss(struct bce_softc * sc)7065b42386eeSSepherosa Ziehau bce_init_rss(struct bce_softc *sc)
7066b42386eeSSepherosa Ziehau {
7067b42386eeSSepherosa Ziehau 	uint8_t key[BCE_RLUP_RSS_KEY_CNT * BCE_RLUP_RSS_KEY_SIZE];
7068b42386eeSSepherosa Ziehau 	uint32_t tbl = 0;
7069b42386eeSSepherosa Ziehau 	int i;
7070b42386eeSSepherosa Ziehau 
7071b42386eeSSepherosa Ziehau 	KKASSERT(sc->rx_ring_cnt > 2);
7072b42386eeSSepherosa Ziehau 
7073b42386eeSSepherosa Ziehau 	/*
7074b42386eeSSepherosa Ziehau 	 * Configure RSS keys
7075b42386eeSSepherosa Ziehau 	 */
7076b42386eeSSepherosa Ziehau 	toeplitz_get_key(key, sizeof(key));
7077b42386eeSSepherosa Ziehau 	for (i = 0; i < BCE_RLUP_RSS_KEY_CNT; ++i) {
7078b42386eeSSepherosa Ziehau 		uint32_t rss_key;
7079b42386eeSSepherosa Ziehau 
7080b42386eeSSepherosa Ziehau 		rss_key = BCE_RLUP_RSS_KEYVAL(key, i);
7081b42386eeSSepherosa Ziehau 		BCE_RSS_DPRINTF(sc, 1, "rss_key%d 0x%08x\n", i, rss_key);
7082b42386eeSSepherosa Ziehau 
7083b42386eeSSepherosa Ziehau 		REG_WR(sc, BCE_RLUP_RSS_KEY(i), rss_key);
7084b42386eeSSepherosa Ziehau 	}
7085b42386eeSSepherosa Ziehau 
7086b42386eeSSepherosa Ziehau 	/*
7087b42386eeSSepherosa Ziehau 	 * Configure the redirect table
7088b42386eeSSepherosa Ziehau 	 *
7089b42386eeSSepherosa Ziehau 	 * NOTE:
7090b42386eeSSepherosa Ziehau 	 * - The "queue ID" in redirect table is the software RX ring's
7091b42386eeSSepherosa Ziehau 	 *   index _minus_ one.
7092b42386eeSSepherosa Ziehau 	 * - The last RX ring, whose "queue ID" is (sc->rx_ring_cnt - 2)
7093b42386eeSSepherosa Ziehau 	 *   will be used for packets whose masked hash is 0.
7094b42386eeSSepherosa Ziehau 	 *   (see also: comment in bce_setup_ring_cnt())
7095b42386eeSSepherosa Ziehau 	 */
709639ea245fSSepherosa Ziehau 	if_ringmap_rdrtable(sc->rx_rmap, sc->rdr_table,
709739ea245fSSepherosa Ziehau 	    BCE_RXP_SCRATCH_RSS_TBL_MAX_ENTRIES);
7098b42386eeSSepherosa Ziehau 	for (i = 0; i < BCE_RXP_SCRATCH_RSS_TBL_MAX_ENTRIES; i++) {
7099b42386eeSSepherosa Ziehau 		int shift = (i % 8) << 2, qid;
7100b42386eeSSepherosa Ziehau 
710139ea245fSSepherosa Ziehau 		qid = sc->rdr_table[i];
710239ea245fSSepherosa Ziehau 		KKASSERT(qid >= 0 && qid < sc->rx_ring_cnt2);
7103b42386eeSSepherosa Ziehau 		if (qid > 0)
7104b42386eeSSepherosa Ziehau 			--qid;
7105b42386eeSSepherosa Ziehau 		else
7106b42386eeSSepherosa Ziehau 			qid = sc->rx_ring_cnt - 2;
7107b42386eeSSepherosa Ziehau 		KKASSERT(qid < (sc->rx_ring_cnt - 1));
7108b42386eeSSepherosa Ziehau 
7109b42386eeSSepherosa Ziehau 		tbl |= qid << shift;
7110b42386eeSSepherosa Ziehau 		if (i % 8 == 7) {
7111b42386eeSSepherosa Ziehau 			BCE_RSS_DPRINTF(sc, 1, "tbl 0x%08x\n", tbl);
7112b42386eeSSepherosa Ziehau 			REG_WR(sc, BCE_RLUP_RSS_DATA, tbl);
7113b42386eeSSepherosa Ziehau 			REG_WR(sc, BCE_RLUP_RSS_COMMAND, (i >> 3) |
7114b42386eeSSepherosa Ziehau 			    BCE_RLUP_RSS_COMMAND_RSS_WRITE_MASK |
7115b42386eeSSepherosa Ziehau 			    BCE_RLUP_RSS_COMMAND_WRITE |
7116b42386eeSSepherosa Ziehau 			    BCE_RLUP_RSS_COMMAND_HASH_MASK);
7117b42386eeSSepherosa Ziehau 			tbl = 0;
7118b42386eeSSepherosa Ziehau 		}
7119b42386eeSSepherosa Ziehau 	}
7120b42386eeSSepherosa Ziehau 	REG_WR(sc, BCE_RLUP_RSS_CONFIG,
7121b42386eeSSepherosa Ziehau 	    BCE_RLUP_RSS_CONFIG_IPV4_RSS_TYPE_ALL_XI);
7122b42386eeSSepherosa Ziehau }
7123b42386eeSSepherosa Ziehau 
7124b42386eeSSepherosa Ziehau static void
bce_npoll_coal_change(struct bce_softc * sc)7125b42386eeSSepherosa Ziehau bce_npoll_coal_change(struct bce_softc *sc)
7126b42386eeSSepherosa Ziehau {
7127b42386eeSSepherosa Ziehau 	uint32_t old_rx_cons, old_tx_cons;
7128b42386eeSSepherosa Ziehau 
7129b42386eeSSepherosa Ziehau 	old_rx_cons = sc->bce_rx_quick_cons_trip_int;
7130b42386eeSSepherosa Ziehau 	old_tx_cons = sc->bce_tx_quick_cons_trip_int;
7131b42386eeSSepherosa Ziehau 	sc->bce_rx_quick_cons_trip_int = 1;
7132b42386eeSSepherosa Ziehau 	sc->bce_tx_quick_cons_trip_int = 1;
7133b42386eeSSepherosa Ziehau 
7134b42386eeSSepherosa Ziehau 	sc->bce_coalchg_mask |= BCE_COALMASK_TX_BDS_INT |
7135b42386eeSSepherosa Ziehau 	    BCE_COALMASK_RX_BDS_INT;
7136b42386eeSSepherosa Ziehau 	bce_coal_change(sc);
7137b42386eeSSepherosa Ziehau 
7138b42386eeSSepherosa Ziehau 	sc->bce_rx_quick_cons_trip_int = old_rx_cons;
7139b42386eeSSepherosa Ziehau 	sc->bce_tx_quick_cons_trip_int = old_tx_cons;
7140745b3d68SSepherosa Ziehau }
714142ad0e07SSepherosa Ziehau 
714242ad0e07SSepherosa Ziehau static struct pktinfo *
bce_rss_pktinfo(struct pktinfo * pi,uint32_t status,const struct l2_fhdr * l2fhdr)714342ad0e07SSepherosa Ziehau bce_rss_pktinfo(struct pktinfo *pi, uint32_t status,
714442ad0e07SSepherosa Ziehau     const struct l2_fhdr *l2fhdr)
714542ad0e07SSepherosa Ziehau {
714642ad0e07SSepherosa Ziehau 	/* Check for an IP datagram. */
714742ad0e07SSepherosa Ziehau 	if ((status & L2_FHDR_STATUS_IP_DATAGRAM) == 0)
714842ad0e07SSepherosa Ziehau 		return NULL;
714942ad0e07SSepherosa Ziehau 
715042ad0e07SSepherosa Ziehau 	/* Check if the IP checksum is valid. */
715142ad0e07SSepherosa Ziehau 	if (l2fhdr->l2_fhdr_ip_xsum != 0xffff)
715242ad0e07SSepherosa Ziehau 		return NULL;
715342ad0e07SSepherosa Ziehau 
715442ad0e07SSepherosa Ziehau 	/* Check for a valid TCP/UDP frame. */
715542ad0e07SSepherosa Ziehau 	if (status & L2_FHDR_STATUS_TCP_SEGMENT) {
715642ad0e07SSepherosa Ziehau 		if (status & L2_FHDR_ERRORS_TCP_XSUM)
715742ad0e07SSepherosa Ziehau 			return NULL;
715842ad0e07SSepherosa Ziehau 		if (l2fhdr->l2_fhdr_tcp_udp_xsum != 0xffff)
715942ad0e07SSepherosa Ziehau 			return NULL;
716042ad0e07SSepherosa Ziehau 		pi->pi_l3proto = IPPROTO_TCP;
716142ad0e07SSepherosa Ziehau 	} else if (status & L2_FHDR_STATUS_UDP_DATAGRAM) {
716242ad0e07SSepherosa Ziehau 		if (status & L2_FHDR_ERRORS_UDP_XSUM)
716342ad0e07SSepherosa Ziehau 			return NULL;
716442ad0e07SSepherosa Ziehau 		if (l2fhdr->l2_fhdr_tcp_udp_xsum != 0xffff)
716542ad0e07SSepherosa Ziehau 			return NULL;
716642ad0e07SSepherosa Ziehau 		pi->pi_l3proto = IPPROTO_UDP;
716742ad0e07SSepherosa Ziehau 	} else {
716842ad0e07SSepherosa Ziehau 		return NULL;
716942ad0e07SSepherosa Ziehau 	}
717042ad0e07SSepherosa Ziehau 	pi->pi_netisr = NETISR_IP;
717142ad0e07SSepherosa Ziehau 	pi->pi_flags = 0;
717242ad0e07SSepherosa Ziehau 
717342ad0e07SSepherosa Ziehau 	return pi;
717442ad0e07SSepherosa Ziehau }
7175