xref: /freebsd/sys/dev/bge/if_bge.c (revision 3fed2d5d77572f0899c94d80c3be21aaa3f919f6)
1098ca2bdSWarner Losh /*-
295d67482SBill Paul  * Copyright (c) 2001 Wind River Systems
395d67482SBill Paul  * Copyright (c) 1997, 1998, 1999, 2001
495d67482SBill Paul  *	Bill Paul <wpaul@windriver.com>.  All rights reserved.
595d67482SBill Paul  *
695d67482SBill Paul  * Redistribution and use in source and binary forms, with or without
795d67482SBill Paul  * modification, are permitted provided that the following conditions
895d67482SBill Paul  * are met:
995d67482SBill Paul  * 1. Redistributions of source code must retain the above copyright
1095d67482SBill Paul  *    notice, this list of conditions and the following disclaimer.
1195d67482SBill Paul  * 2. Redistributions in binary form must reproduce the above copyright
1295d67482SBill Paul  *    notice, this list of conditions and the following disclaimer in the
1395d67482SBill Paul  *    documentation and/or other materials provided with the distribution.
1495d67482SBill Paul  * 3. All advertising materials mentioning features or use of this software
1595d67482SBill Paul  *    must display the following acknowledgement:
1695d67482SBill Paul  *	This product includes software developed by Bill Paul.
1795d67482SBill Paul  * 4. Neither the name of the author nor the names of any co-contributors
1895d67482SBill Paul  *    may be used to endorse or promote products derived from this software
1995d67482SBill Paul  *    without specific prior written permission.
2095d67482SBill Paul  *
2195d67482SBill Paul  * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
2295d67482SBill Paul  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2395d67482SBill Paul  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2495d67482SBill Paul  * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
2595d67482SBill Paul  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2695d67482SBill Paul  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2795d67482SBill Paul  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2895d67482SBill Paul  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2995d67482SBill Paul  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
3095d67482SBill Paul  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
3195d67482SBill Paul  * THE POSSIBILITY OF SUCH DAMAGE.
3295d67482SBill Paul  */
3395d67482SBill Paul 
34aad970f1SDavid E. O'Brien #include <sys/cdefs.h>
35aad970f1SDavid E. O'Brien __FBSDID("$FreeBSD$");
36aad970f1SDavid E. O'Brien 
3795d67482SBill Paul /*
3895d67482SBill Paul  * Broadcom BCM570x family gigabit ethernet driver for FreeBSD.
3995d67482SBill Paul  *
4095d67482SBill Paul  * The Broadcom BCM5700 is based on technology originally developed by
4195d67482SBill Paul  * Alteon Networks as part of the Tigon I and Tigon II gigabit ethernet
4222a4ecedSMarius Strobl  * MAC chips. The BCM5700, sometimes referred to as the Tigon III, has
4395d67482SBill Paul  * two on-board MIPS R4000 CPUs and can have as much as 16MB of external
4495d67482SBill Paul  * SSRAM. The BCM5700 supports TCP, UDP and IP checksum offload, jumbo
4595d67482SBill Paul  * frames, highly configurable RX filtering, and 16 RX and TX queues
4695d67482SBill Paul  * (which, along with RX filter rules, can be used for QOS applications).
4795d67482SBill Paul  * Other features, such as TCP segmentation, may be available as part
4895d67482SBill Paul  * of value-added firmware updates. Unlike the Tigon I and Tigon II,
4995d67482SBill Paul  * firmware images can be stored in hardware and need not be compiled
5095d67482SBill Paul  * into the driver.
5195d67482SBill Paul  *
5295d67482SBill Paul  * The BCM5700 supports the PCI v2.2 and PCI-X v1.0 standards, and will
5395d67482SBill Paul  * function in a 32-bit/64-bit 33/66Mhz bus, or a 64-bit/133Mhz bus.
5495d67482SBill Paul  *
5595d67482SBill Paul  * The BCM5701 is a single-chip solution incorporating both the BCM5700
5698b28ee5SBill Paul  * MAC and a BCM5401 10/100/1000 PHY. Unlike the BCM5700, the BCM5701
5795d67482SBill Paul  * does not support external SSRAM.
5895d67482SBill Paul  *
5995d67482SBill Paul  * Broadcom also produces a variation of the BCM5700 under the "Altima"
6095d67482SBill Paul  * brand name, which is functionally similar but lacks PCI-X support.
6195d67482SBill Paul  *
6295d67482SBill Paul  * Without external SSRAM, you can only have at most 4 TX rings,
6395d67482SBill Paul  * and the use of the mini RX ring is disabled. This seems to imply
6495d67482SBill Paul  * that these features are simply not available on the BCM5701. As a
6595d67482SBill Paul  * result, this driver does not implement any support for the mini RX
6695d67482SBill Paul  * ring.
6795d67482SBill Paul  */
6895d67482SBill Paul 
6975719184SGleb Smirnoff #ifdef HAVE_KERNEL_OPTION_HEADERS
7075719184SGleb Smirnoff #include "opt_device_polling.h"
7175719184SGleb Smirnoff #endif
7275719184SGleb Smirnoff 
7395d67482SBill Paul #include <sys/param.h>
74f41ac2beSBill Paul #include <sys/endian.h>
7595d67482SBill Paul #include <sys/systm.h>
7695d67482SBill Paul #include <sys/sockio.h>
7795d67482SBill Paul #include <sys/mbuf.h>
7895d67482SBill Paul #include <sys/malloc.h>
7995d67482SBill Paul #include <sys/kernel.h>
80fe12f24bSPoul-Henning Kamp #include <sys/module.h>
8195d67482SBill Paul #include <sys/socket.h>
82f1a7e6d5SScott Long #include <sys/sysctl.h>
83dfe0df9aSPyun YongHyeon #include <sys/taskqueue.h>
8495d67482SBill Paul 
8595d67482SBill Paul #include <net/if.h>
8695d67482SBill Paul #include <net/if_arp.h>
8795d67482SBill Paul #include <net/ethernet.h>
8895d67482SBill Paul #include <net/if_dl.h>
8995d67482SBill Paul #include <net/if_media.h>
9095d67482SBill Paul 
9195d67482SBill Paul #include <net/bpf.h>
9295d67482SBill Paul 
9395d67482SBill Paul #include <net/if_types.h>
9495d67482SBill Paul #include <net/if_vlan_var.h>
9595d67482SBill Paul 
9695d67482SBill Paul #include <netinet/in_systm.h>
9795d67482SBill Paul #include <netinet/in.h>
9895d67482SBill Paul #include <netinet/ip.h>
99ca3f1187SPyun YongHyeon #include <netinet/tcp.h>
10095d67482SBill Paul 
10195d67482SBill Paul #include <machine/bus.h>
10295d67482SBill Paul #include <machine/resource.h>
10395d67482SBill Paul #include <sys/bus.h>
10495d67482SBill Paul #include <sys/rman.h>
10595d67482SBill Paul 
10695d67482SBill Paul #include <dev/mii/mii.h>
10795d67482SBill Paul #include <dev/mii/miivar.h>
1082d3ce713SDavid E. O'Brien #include "miidevs.h"
10995d67482SBill Paul #include <dev/mii/brgphyreg.h>
11095d67482SBill Paul 
11108013fd3SMarius Strobl #ifdef __sparc64__
11208013fd3SMarius Strobl #include <dev/ofw/ofw_bus.h>
11308013fd3SMarius Strobl #include <dev/ofw/openfirm.h>
11408013fd3SMarius Strobl #include <machine/ofw_machdep.h>
11508013fd3SMarius Strobl #include <machine/ver.h>
11608013fd3SMarius Strobl #endif
11708013fd3SMarius Strobl 
1184fbd232cSWarner Losh #include <dev/pci/pcireg.h>
1194fbd232cSWarner Losh #include <dev/pci/pcivar.h>
12095d67482SBill Paul 
12195d67482SBill Paul #include <dev/bge/if_bgereg.h>
12295d67482SBill Paul 
12335f945cdSPyun YongHyeon #define	BGE_CSUM_FEATURES	(CSUM_IP | CSUM_TCP)
124d375e524SGleb Smirnoff #define	ETHER_MIN_NOPAD		(ETHER_MIN_LEN - ETHER_CRC_LEN) /* i.e., 60 */
12595d67482SBill Paul 
126f246e4a1SMatthew N. Dodd MODULE_DEPEND(bge, pci, 1, 1, 1);
127f246e4a1SMatthew N. Dodd MODULE_DEPEND(bge, ether, 1, 1, 1);
12895d67482SBill Paul MODULE_DEPEND(bge, miibus, 1, 1, 1);
12995d67482SBill Paul 
1307b279558SWarner Losh /* "device miibus" required.  See GENERIC if you get errors here. */
13195d67482SBill Paul #include "miibus_if.h"
13295d67482SBill Paul 
13395d67482SBill Paul /*
13495d67482SBill Paul  * Various supported device vendors/types and their names. Note: the
13595d67482SBill Paul  * spec seems to indicate that the hardware still has Alteon's vendor
13695d67482SBill Paul  * ID burned into it, though it will always be overriden by the vendor
13795d67482SBill Paul  * ID in the EEPROM. Just to be safe, we cover all possibilities.
13895d67482SBill Paul  */
139852c67f9SMarius Strobl static const struct bge_type {
1404c0da0ffSGleb Smirnoff 	uint16_t	bge_vid;
1414c0da0ffSGleb Smirnoff 	uint16_t	bge_did;
142978f2704SMarius Strobl } const bge_devs[] = {
1434c0da0ffSGleb Smirnoff 	{ ALTEON_VENDORID,	ALTEON_DEVICEID_BCM5700 },
1444c0da0ffSGleb Smirnoff 	{ ALTEON_VENDORID,	ALTEON_DEVICEID_BCM5701 },
14595d67482SBill Paul 
1464c0da0ffSGleb Smirnoff 	{ ALTIMA_VENDORID,	ALTIMA_DEVICE_AC1000 },
1474c0da0ffSGleb Smirnoff 	{ ALTIMA_VENDORID,	ALTIMA_DEVICE_AC1002 },
1484c0da0ffSGleb Smirnoff 	{ ALTIMA_VENDORID,	ALTIMA_DEVICE_AC9100 },
1494c0da0ffSGleb Smirnoff 
1504c0da0ffSGleb Smirnoff 	{ APPLE_VENDORID,	APPLE_DEVICE_BCM5701 },
1514c0da0ffSGleb Smirnoff 
1524c0da0ffSGleb Smirnoff 	{ BCOM_VENDORID,	BCOM_DEVICEID_BCM5700 },
1534c0da0ffSGleb Smirnoff 	{ BCOM_VENDORID,	BCOM_DEVICEID_BCM5701 },
1544c0da0ffSGleb Smirnoff 	{ BCOM_VENDORID,	BCOM_DEVICEID_BCM5702 },
1554c0da0ffSGleb Smirnoff 	{ BCOM_VENDORID,	BCOM_DEVICEID_BCM5702_ALT },
1564c0da0ffSGleb Smirnoff 	{ BCOM_VENDORID,	BCOM_DEVICEID_BCM5702X },
1574c0da0ffSGleb Smirnoff 	{ BCOM_VENDORID,	BCOM_DEVICEID_BCM5703 },
1584c0da0ffSGleb Smirnoff 	{ BCOM_VENDORID,	BCOM_DEVICEID_BCM5703_ALT },
1594c0da0ffSGleb Smirnoff 	{ BCOM_VENDORID,	BCOM_DEVICEID_BCM5703X },
1604c0da0ffSGleb Smirnoff 	{ BCOM_VENDORID,	BCOM_DEVICEID_BCM5704C },
1614c0da0ffSGleb Smirnoff 	{ BCOM_VENDORID,	BCOM_DEVICEID_BCM5704S },
1624c0da0ffSGleb Smirnoff 	{ BCOM_VENDORID,	BCOM_DEVICEID_BCM5704S_ALT },
1634c0da0ffSGleb Smirnoff 	{ BCOM_VENDORID,	BCOM_DEVICEID_BCM5705 },
1644c0da0ffSGleb Smirnoff 	{ BCOM_VENDORID,	BCOM_DEVICEID_BCM5705F },
1654c0da0ffSGleb Smirnoff 	{ BCOM_VENDORID,	BCOM_DEVICEID_BCM5705K },
1664c0da0ffSGleb Smirnoff 	{ BCOM_VENDORID,	BCOM_DEVICEID_BCM5705M },
1674c0da0ffSGleb Smirnoff 	{ BCOM_VENDORID,	BCOM_DEVICEID_BCM5705M_ALT },
1684c0da0ffSGleb Smirnoff 	{ BCOM_VENDORID,	BCOM_DEVICEID_BCM5714C },
1694c0da0ffSGleb Smirnoff 	{ BCOM_VENDORID,	BCOM_DEVICEID_BCM5714S },
1704c0da0ffSGleb Smirnoff 	{ BCOM_VENDORID,	BCOM_DEVICEID_BCM5715 },
1714c0da0ffSGleb Smirnoff 	{ BCOM_VENDORID,	BCOM_DEVICEID_BCM5715S },
1721108273aSPyun YongHyeon 	{ BCOM_VENDORID,	BCOM_DEVICEID_BCM5717 },
1731108273aSPyun YongHyeon 	{ BCOM_VENDORID,	BCOM_DEVICEID_BCM5718 },
174bbe2ca75SPyun YongHyeon 	{ BCOM_VENDORID,	BCOM_DEVICEID_BCM5719 },
1754c0da0ffSGleb Smirnoff 	{ BCOM_VENDORID,	BCOM_DEVICEID_BCM5720 },
1764c0da0ffSGleb Smirnoff 	{ BCOM_VENDORID,	BCOM_DEVICEID_BCM5721 },
177effef978SRemko Lodder 	{ BCOM_VENDORID,	BCOM_DEVICEID_BCM5722 },
178a5779553SStanislav Sedov 	{ BCOM_VENDORID,	BCOM_DEVICEID_BCM5723 },
1794c0da0ffSGleb Smirnoff 	{ BCOM_VENDORID,	BCOM_DEVICEID_BCM5750 },
1804c0da0ffSGleb Smirnoff 	{ BCOM_VENDORID,	BCOM_DEVICEID_BCM5750M },
1814c0da0ffSGleb Smirnoff 	{ BCOM_VENDORID,	BCOM_DEVICEID_BCM5751 },
1824c0da0ffSGleb Smirnoff 	{ BCOM_VENDORID,	BCOM_DEVICEID_BCM5751F },
1834c0da0ffSGleb Smirnoff 	{ BCOM_VENDORID,	BCOM_DEVICEID_BCM5751M },
1844c0da0ffSGleb Smirnoff 	{ BCOM_VENDORID,	BCOM_DEVICEID_BCM5752 },
1854c0da0ffSGleb Smirnoff 	{ BCOM_VENDORID,	BCOM_DEVICEID_BCM5752M },
1864c0da0ffSGleb Smirnoff 	{ BCOM_VENDORID,	BCOM_DEVICEID_BCM5753 },
1874c0da0ffSGleb Smirnoff 	{ BCOM_VENDORID,	BCOM_DEVICEID_BCM5753F },
1884c0da0ffSGleb Smirnoff 	{ BCOM_VENDORID,	BCOM_DEVICEID_BCM5753M },
1899e86676bSGleb Smirnoff 	{ BCOM_VENDORID,	BCOM_DEVICEID_BCM5754 },
1909e86676bSGleb Smirnoff 	{ BCOM_VENDORID,	BCOM_DEVICEID_BCM5754M },
1919e86676bSGleb Smirnoff 	{ BCOM_VENDORID,	BCOM_DEVICEID_BCM5755 },
1929e86676bSGleb Smirnoff 	{ BCOM_VENDORID,	BCOM_DEVICEID_BCM5755M },
193f7d1b2ebSXin LI 	{ BCOM_VENDORID,	BCOM_DEVICEID_BCM5756 },
194a5779553SStanislav Sedov 	{ BCOM_VENDORID,	BCOM_DEVICEID_BCM5761 },
195a5779553SStanislav Sedov 	{ BCOM_VENDORID,	BCOM_DEVICEID_BCM5761E },
196a5779553SStanislav Sedov 	{ BCOM_VENDORID,	BCOM_DEVICEID_BCM5761S },
197a5779553SStanislav Sedov 	{ BCOM_VENDORID,	BCOM_DEVICEID_BCM5761SE },
198a5779553SStanislav Sedov 	{ BCOM_VENDORID,	BCOM_DEVICEID_BCM5764 },
1994c0da0ffSGleb Smirnoff 	{ BCOM_VENDORID,	BCOM_DEVICEID_BCM5780 },
2004c0da0ffSGleb Smirnoff 	{ BCOM_VENDORID,	BCOM_DEVICEID_BCM5780S },
2014c0da0ffSGleb Smirnoff 	{ BCOM_VENDORID,	BCOM_DEVICEID_BCM5781 },
2024c0da0ffSGleb Smirnoff 	{ BCOM_VENDORID,	BCOM_DEVICEID_BCM5782 },
203a5779553SStanislav Sedov 	{ BCOM_VENDORID,	BCOM_DEVICEID_BCM5784 },
204a5779553SStanislav Sedov 	{ BCOM_VENDORID,	BCOM_DEVICEID_BCM5785F },
205a5779553SStanislav Sedov 	{ BCOM_VENDORID,	BCOM_DEVICEID_BCM5785G },
2069e86676bSGleb Smirnoff 	{ BCOM_VENDORID,	BCOM_DEVICEID_BCM5786 },
2079e86676bSGleb Smirnoff 	{ BCOM_VENDORID,	BCOM_DEVICEID_BCM5787 },
208a5779553SStanislav Sedov 	{ BCOM_VENDORID,	BCOM_DEVICEID_BCM5787F },
2099e86676bSGleb Smirnoff 	{ BCOM_VENDORID,	BCOM_DEVICEID_BCM5787M },
2104c0da0ffSGleb Smirnoff 	{ BCOM_VENDORID,	BCOM_DEVICEID_BCM5788 },
2114c0da0ffSGleb Smirnoff 	{ BCOM_VENDORID,	BCOM_DEVICEID_BCM5789 },
2124c0da0ffSGleb Smirnoff 	{ BCOM_VENDORID,	BCOM_DEVICEID_BCM5901 },
2134c0da0ffSGleb Smirnoff 	{ BCOM_VENDORID,	BCOM_DEVICEID_BCM5901A2 },
2144c0da0ffSGleb Smirnoff 	{ BCOM_VENDORID,	BCOM_DEVICEID_BCM5903M },
21538cc658fSJohn Baldwin 	{ BCOM_VENDORID,	BCOM_DEVICEID_BCM5906 },
21638cc658fSJohn Baldwin 	{ BCOM_VENDORID,	BCOM_DEVICEID_BCM5906M },
217a5779553SStanislav Sedov 	{ BCOM_VENDORID,	BCOM_DEVICEID_BCM57760 },
218b4a256acSPyun YongHyeon 	{ BCOM_VENDORID,	BCOM_DEVICEID_BCM57761 },
219b4a256acSPyun YongHyeon 	{ BCOM_VENDORID,	BCOM_DEVICEID_BCM57765 },
220a5779553SStanislav Sedov 	{ BCOM_VENDORID,	BCOM_DEVICEID_BCM57780 },
221b4a256acSPyun YongHyeon 	{ BCOM_VENDORID,	BCOM_DEVICEID_BCM57781 },
222b4a256acSPyun YongHyeon 	{ BCOM_VENDORID,	BCOM_DEVICEID_BCM57785 },
223a5779553SStanislav Sedov 	{ BCOM_VENDORID,	BCOM_DEVICEID_BCM57788 },
224a5779553SStanislav Sedov 	{ BCOM_VENDORID,	BCOM_DEVICEID_BCM57790 },
225b4a256acSPyun YongHyeon 	{ BCOM_VENDORID,	BCOM_DEVICEID_BCM57791 },
226b4a256acSPyun YongHyeon 	{ BCOM_VENDORID,	BCOM_DEVICEID_BCM57795 },
2274c0da0ffSGleb Smirnoff 
2284c0da0ffSGleb Smirnoff 	{ SK_VENDORID,		SK_DEVICEID_ALTIMA },
2294c0da0ffSGleb Smirnoff 
2304c0da0ffSGleb Smirnoff 	{ TC_VENDORID,		TC_DEVICEID_3C996 },
2314c0da0ffSGleb Smirnoff 
232a5779553SStanislav Sedov 	{ FJTSU_VENDORID,	FJTSU_DEVICEID_PW008GE4 },
233a5779553SStanislav Sedov 	{ FJTSU_VENDORID,	FJTSU_DEVICEID_PW008GE5 },
234a5779553SStanislav Sedov 	{ FJTSU_VENDORID,	FJTSU_DEVICEID_PP250450 },
235a5779553SStanislav Sedov 
2364c0da0ffSGleb Smirnoff 	{ 0, 0 }
23795d67482SBill Paul };
23895d67482SBill Paul 
2394c0da0ffSGleb Smirnoff static const struct bge_vendor {
2404c0da0ffSGleb Smirnoff 	uint16_t	v_id;
2414c0da0ffSGleb Smirnoff 	const char	*v_name;
242978f2704SMarius Strobl } const bge_vendors[] = {
2434c0da0ffSGleb Smirnoff 	{ ALTEON_VENDORID,	"Alteon" },
2444c0da0ffSGleb Smirnoff 	{ ALTIMA_VENDORID,	"Altima" },
2454c0da0ffSGleb Smirnoff 	{ APPLE_VENDORID,	"Apple" },
2464c0da0ffSGleb Smirnoff 	{ BCOM_VENDORID,	"Broadcom" },
2474c0da0ffSGleb Smirnoff 	{ SK_VENDORID,		"SysKonnect" },
2484c0da0ffSGleb Smirnoff 	{ TC_VENDORID,		"3Com" },
249a5779553SStanislav Sedov 	{ FJTSU_VENDORID,	"Fujitsu" },
2504c0da0ffSGleb Smirnoff 
2514c0da0ffSGleb Smirnoff 	{ 0, NULL }
2524c0da0ffSGleb Smirnoff };
2534c0da0ffSGleb Smirnoff 
2544c0da0ffSGleb Smirnoff static const struct bge_revision {
2554c0da0ffSGleb Smirnoff 	uint32_t	br_chipid;
2564c0da0ffSGleb Smirnoff 	const char	*br_name;
257978f2704SMarius Strobl } const bge_revisions[] = {
2584c0da0ffSGleb Smirnoff 	{ BGE_CHIPID_BCM5700_A0,	"BCM5700 A0" },
2594c0da0ffSGleb Smirnoff 	{ BGE_CHIPID_BCM5700_A1,	"BCM5700 A1" },
2604c0da0ffSGleb Smirnoff 	{ BGE_CHIPID_BCM5700_B0,	"BCM5700 B0" },
2614c0da0ffSGleb Smirnoff 	{ BGE_CHIPID_BCM5700_B1,	"BCM5700 B1" },
2624c0da0ffSGleb Smirnoff 	{ BGE_CHIPID_BCM5700_B2,	"BCM5700 B2" },
2634c0da0ffSGleb Smirnoff 	{ BGE_CHIPID_BCM5700_B3,	"BCM5700 B3" },
2644c0da0ffSGleb Smirnoff 	{ BGE_CHIPID_BCM5700_ALTIMA,	"BCM5700 Altima" },
2654c0da0ffSGleb Smirnoff 	{ BGE_CHIPID_BCM5700_C0,	"BCM5700 C0" },
2664c0da0ffSGleb Smirnoff 	{ BGE_CHIPID_BCM5701_A0,	"BCM5701 A0" },
2674c0da0ffSGleb Smirnoff 	{ BGE_CHIPID_BCM5701_B0,	"BCM5701 B0" },
2684c0da0ffSGleb Smirnoff 	{ BGE_CHIPID_BCM5701_B2,	"BCM5701 B2" },
2694c0da0ffSGleb Smirnoff 	{ BGE_CHIPID_BCM5701_B5,	"BCM5701 B5" },
2704c0da0ffSGleb Smirnoff 	{ BGE_CHIPID_BCM5703_A0,	"BCM5703 A0" },
2714c0da0ffSGleb Smirnoff 	{ BGE_CHIPID_BCM5703_A1,	"BCM5703 A1" },
2724c0da0ffSGleb Smirnoff 	{ BGE_CHIPID_BCM5703_A2,	"BCM5703 A2" },
2734c0da0ffSGleb Smirnoff 	{ BGE_CHIPID_BCM5703_A3,	"BCM5703 A3" },
2749e86676bSGleb Smirnoff 	{ BGE_CHIPID_BCM5703_B0,	"BCM5703 B0" },
2754c0da0ffSGleb Smirnoff 	{ BGE_CHIPID_BCM5704_A0,	"BCM5704 A0" },
2764c0da0ffSGleb Smirnoff 	{ BGE_CHIPID_BCM5704_A1,	"BCM5704 A1" },
2774c0da0ffSGleb Smirnoff 	{ BGE_CHIPID_BCM5704_A2,	"BCM5704 A2" },
2784c0da0ffSGleb Smirnoff 	{ BGE_CHIPID_BCM5704_A3,	"BCM5704 A3" },
2794c0da0ffSGleb Smirnoff 	{ BGE_CHIPID_BCM5704_B0,	"BCM5704 B0" },
2804c0da0ffSGleb Smirnoff 	{ BGE_CHIPID_BCM5705_A0,	"BCM5705 A0" },
2814c0da0ffSGleb Smirnoff 	{ BGE_CHIPID_BCM5705_A1,	"BCM5705 A1" },
2824c0da0ffSGleb Smirnoff 	{ BGE_CHIPID_BCM5705_A2,	"BCM5705 A2" },
2834c0da0ffSGleb Smirnoff 	{ BGE_CHIPID_BCM5705_A3,	"BCM5705 A3" },
2844c0da0ffSGleb Smirnoff 	{ BGE_CHIPID_BCM5750_A0,	"BCM5750 A0" },
2854c0da0ffSGleb Smirnoff 	{ BGE_CHIPID_BCM5750_A1,	"BCM5750 A1" },
2864c0da0ffSGleb Smirnoff 	{ BGE_CHIPID_BCM5750_A3,	"BCM5750 A3" },
2874c0da0ffSGleb Smirnoff 	{ BGE_CHIPID_BCM5750_B0,	"BCM5750 B0" },
2884c0da0ffSGleb Smirnoff 	{ BGE_CHIPID_BCM5750_B1,	"BCM5750 B1" },
2894c0da0ffSGleb Smirnoff 	{ BGE_CHIPID_BCM5750_C0,	"BCM5750 C0" },
2904c0da0ffSGleb Smirnoff 	{ BGE_CHIPID_BCM5750_C1,	"BCM5750 C1" },
29142787b76SGleb Smirnoff 	{ BGE_CHIPID_BCM5750_C2,	"BCM5750 C2" },
2924c0da0ffSGleb Smirnoff 	{ BGE_CHIPID_BCM5714_A0,	"BCM5714 A0" },
2934c0da0ffSGleb Smirnoff 	{ BGE_CHIPID_BCM5752_A0,	"BCM5752 A0" },
2944c0da0ffSGleb Smirnoff 	{ BGE_CHIPID_BCM5752_A1,	"BCM5752 A1" },
2954c0da0ffSGleb Smirnoff 	{ BGE_CHIPID_BCM5752_A2,	"BCM5752 A2" },
2964c0da0ffSGleb Smirnoff 	{ BGE_CHIPID_BCM5714_B0,	"BCM5714 B0" },
2974c0da0ffSGleb Smirnoff 	{ BGE_CHIPID_BCM5714_B3,	"BCM5714 B3" },
2984c0da0ffSGleb Smirnoff 	{ BGE_CHIPID_BCM5715_A0,	"BCM5715 A0" },
2994c0da0ffSGleb Smirnoff 	{ BGE_CHIPID_BCM5715_A1,	"BCM5715 A1" },
3000c4a1ef8SJung-uk Kim 	{ BGE_CHIPID_BCM5715_A3,	"BCM5715 A3" },
3011108273aSPyun YongHyeon 	{ BGE_CHIPID_BCM5717_A0,	"BCM5717 A0" },
3021108273aSPyun YongHyeon 	{ BGE_CHIPID_BCM5717_B0,	"BCM5717 B0" },
303bbe2ca75SPyun YongHyeon 	{ BGE_CHIPID_BCM5719_A0,	"BCM5719 A0" },
3040c4a1ef8SJung-uk Kim 	{ BGE_CHIPID_BCM5755_A0,	"BCM5755 A0" },
3050c4a1ef8SJung-uk Kim 	{ BGE_CHIPID_BCM5755_A1,	"BCM5755 A1" },
3060c4a1ef8SJung-uk Kim 	{ BGE_CHIPID_BCM5755_A2,	"BCM5755 A2" },
307bcc20328SJohn Baldwin 	{ BGE_CHIPID_BCM5722_A0,	"BCM5722 A0" },
308a5779553SStanislav Sedov 	{ BGE_CHIPID_BCM5761_A0,	"BCM5761 A0" },
309a5779553SStanislav Sedov 	{ BGE_CHIPID_BCM5761_A1,	"BCM5761 A1" },
310a5779553SStanislav Sedov 	{ BGE_CHIPID_BCM5784_A0,	"BCM5784 A0" },
311a5779553SStanislav Sedov 	{ BGE_CHIPID_BCM5784_A1,	"BCM5784 A1" },
31281179070SJung-uk Kim 	/* 5754 and 5787 share the same ASIC ID */
3136f8718a3SScott Long 	{ BGE_CHIPID_BCM5787_A0,	"BCM5754/5787 A0" },
3146f8718a3SScott Long 	{ BGE_CHIPID_BCM5787_A1,	"BCM5754/5787 A1" },
3156f8718a3SScott Long 	{ BGE_CHIPID_BCM5787_A2,	"BCM5754/5787 A2" },
31638cc658fSJohn Baldwin 	{ BGE_CHIPID_BCM5906_A1,	"BCM5906 A1" },
31738cc658fSJohn Baldwin 	{ BGE_CHIPID_BCM5906_A2,	"BCM5906 A2" },
318b4a256acSPyun YongHyeon 	{ BGE_CHIPID_BCM57765_A0,	"BCM57765 A0" },
319b4a256acSPyun YongHyeon 	{ BGE_CHIPID_BCM57765_B0,	"BCM57765 B0" },
320a5779553SStanislav Sedov 	{ BGE_CHIPID_BCM57780_A0,	"BCM57780 A0" },
321a5779553SStanislav Sedov 	{ BGE_CHIPID_BCM57780_A1,	"BCM57780 A1" },
3224c0da0ffSGleb Smirnoff 
3234c0da0ffSGleb Smirnoff 	{ 0, NULL }
3244c0da0ffSGleb Smirnoff };
3254c0da0ffSGleb Smirnoff 
3264c0da0ffSGleb Smirnoff /*
3274c0da0ffSGleb Smirnoff  * Some defaults for major revisions, so that newer steppings
3284c0da0ffSGleb Smirnoff  * that we don't know about have a shot at working.
3294c0da0ffSGleb Smirnoff  */
330978f2704SMarius Strobl static const struct bge_revision const bge_majorrevs[] = {
3319e86676bSGleb Smirnoff 	{ BGE_ASICREV_BCM5700,		"unknown BCM5700" },
3329e86676bSGleb Smirnoff 	{ BGE_ASICREV_BCM5701,		"unknown BCM5701" },
3339e86676bSGleb Smirnoff 	{ BGE_ASICREV_BCM5703,		"unknown BCM5703" },
3349e86676bSGleb Smirnoff 	{ BGE_ASICREV_BCM5704,		"unknown BCM5704" },
3359e86676bSGleb Smirnoff 	{ BGE_ASICREV_BCM5705,		"unknown BCM5705" },
3369e86676bSGleb Smirnoff 	{ BGE_ASICREV_BCM5750,		"unknown BCM5750" },
3379e86676bSGleb Smirnoff 	{ BGE_ASICREV_BCM5714_A0,	"unknown BCM5714" },
3389e86676bSGleb Smirnoff 	{ BGE_ASICREV_BCM5752,		"unknown BCM5752" },
3399e86676bSGleb Smirnoff 	{ BGE_ASICREV_BCM5780,		"unknown BCM5780" },
3409e86676bSGleb Smirnoff 	{ BGE_ASICREV_BCM5714,		"unknown BCM5714" },
3419e86676bSGleb Smirnoff 	{ BGE_ASICREV_BCM5755,		"unknown BCM5755" },
342a5779553SStanislav Sedov 	{ BGE_ASICREV_BCM5761,		"unknown BCM5761" },
343a5779553SStanislav Sedov 	{ BGE_ASICREV_BCM5784,		"unknown BCM5784" },
344a5779553SStanislav Sedov 	{ BGE_ASICREV_BCM5785,		"unknown BCM5785" },
34581179070SJung-uk Kim 	/* 5754 and 5787 share the same ASIC ID */
3466f8718a3SScott Long 	{ BGE_ASICREV_BCM5787,		"unknown BCM5754/5787" },
34738cc658fSJohn Baldwin 	{ BGE_ASICREV_BCM5906,		"unknown BCM5906" },
348b4a256acSPyun YongHyeon 	{ BGE_ASICREV_BCM57765,		"unknown BCM57765" },
349a5779553SStanislav Sedov 	{ BGE_ASICREV_BCM57780,		"unknown BCM57780" },
3501108273aSPyun YongHyeon 	{ BGE_ASICREV_BCM5717,		"unknown BCM5717" },
351bbe2ca75SPyun YongHyeon 	{ BGE_ASICREV_BCM5719,		"unknown BCM5719" },
3524c0da0ffSGleb Smirnoff 
3534c0da0ffSGleb Smirnoff 	{ 0, NULL }
3544c0da0ffSGleb Smirnoff };
3554c0da0ffSGleb Smirnoff 
3560c8aa4eaSJung-uk Kim #define	BGE_IS_JUMBO_CAPABLE(sc)	((sc)->bge_flags & BGE_FLAG_JUMBO)
3570c8aa4eaSJung-uk Kim #define	BGE_IS_5700_FAMILY(sc)		((sc)->bge_flags & BGE_FLAG_5700_FAMILY)
3580c8aa4eaSJung-uk Kim #define	BGE_IS_5705_PLUS(sc)		((sc)->bge_flags & BGE_FLAG_5705_PLUS)
3590c8aa4eaSJung-uk Kim #define	BGE_IS_5714_FAMILY(sc)		((sc)->bge_flags & BGE_FLAG_5714_FAMILY)
3600c8aa4eaSJung-uk Kim #define	BGE_IS_575X_PLUS(sc)		((sc)->bge_flags & BGE_FLAG_575X_PLUS)
361a5779553SStanislav Sedov #define	BGE_IS_5755_PLUS(sc)		((sc)->bge_flags & BGE_FLAG_5755_PLUS)
3621108273aSPyun YongHyeon #define	BGE_IS_5717_PLUS(sc)		((sc)->bge_flags & BGE_FLAG_5717_PLUS)
3634c0da0ffSGleb Smirnoff 
3644c0da0ffSGleb Smirnoff const struct bge_revision * bge_lookup_rev(uint32_t);
3654c0da0ffSGleb Smirnoff const struct bge_vendor * bge_lookup_vendor(uint16_t);
36638cc658fSJohn Baldwin 
36738cc658fSJohn Baldwin typedef int	(*bge_eaddr_fcn_t)(struct bge_softc *, uint8_t[]);
36838cc658fSJohn Baldwin 
369e51a25f8SAlfred Perlstein static int bge_probe(device_t);
370e51a25f8SAlfred Perlstein static int bge_attach(device_t);
371e51a25f8SAlfred Perlstein static int bge_detach(device_t);
37214afefa3SPawel Jakub Dawidek static int bge_suspend(device_t);
37314afefa3SPawel Jakub Dawidek static int bge_resume(device_t);
3743f74909aSGleb Smirnoff static void bge_release_resources(struct bge_softc *);
375f41ac2beSBill Paul static void bge_dma_map_addr(void *, bus_dma_segment_t *, int, int);
3765b610048SPyun YongHyeon static int bge_dma_alloc(struct bge_softc *);
377f41ac2beSBill Paul static void bge_dma_free(struct bge_softc *);
3785b610048SPyun YongHyeon static int bge_dma_ring_alloc(struct bge_softc *, bus_size_t, bus_size_t,
3795b610048SPyun YongHyeon     bus_dma_tag_t *, uint8_t **, bus_dmamap_t *, bus_addr_t *, const char *);
380f41ac2beSBill Paul 
3815fea260fSMarius Strobl static int bge_get_eaddr_fw(struct bge_softc *sc, uint8_t ether_addr[]);
38238cc658fSJohn Baldwin static int bge_get_eaddr_mem(struct bge_softc *, uint8_t[]);
38338cc658fSJohn Baldwin static int bge_get_eaddr_nvram(struct bge_softc *, uint8_t[]);
38438cc658fSJohn Baldwin static int bge_get_eaddr_eeprom(struct bge_softc *, uint8_t[]);
38538cc658fSJohn Baldwin static int bge_get_eaddr(struct bge_softc *, uint8_t[]);
38638cc658fSJohn Baldwin 
387b9c05fa5SPyun YongHyeon static void bge_txeof(struct bge_softc *, uint16_t);
3881108273aSPyun YongHyeon static void bge_rxcsum(struct bge_softc *, struct bge_rx_bd *, struct mbuf *);
389dfe0df9aSPyun YongHyeon static int bge_rxeof(struct bge_softc *, uint16_t, int);
39095d67482SBill Paul 
3918cb1383cSDoug Ambrisko static void bge_asf_driver_up (struct bge_softc *);
392e51a25f8SAlfred Perlstein static void bge_tick(void *);
3932280c16bSPyun YongHyeon static void bge_stats_clear_regs(struct bge_softc *);
394e51a25f8SAlfred Perlstein static void bge_stats_update(struct bge_softc *);
3953f74909aSGleb Smirnoff static void bge_stats_update_regs(struct bge_softc *);
396d598b626SPyun YongHyeon static struct mbuf *bge_check_short_dma(struct mbuf *);
3972e1d4df4SPyun YongHyeon static struct mbuf *bge_setup_tso(struct bge_softc *, struct mbuf *,
3981108273aSPyun YongHyeon     uint16_t *, uint16_t *);
399676ad2c9SGleb Smirnoff static int bge_encap(struct bge_softc *, struct mbuf **, uint32_t *);
40095d67482SBill Paul 
401e51a25f8SAlfred Perlstein static void bge_intr(void *);
402dfe0df9aSPyun YongHyeon static int bge_msi_intr(void *);
403dfe0df9aSPyun YongHyeon static void bge_intr_task(void *, int);
4040f9bd73bSSam Leffler static void bge_start_locked(struct ifnet *);
405e51a25f8SAlfred Perlstein static void bge_start(struct ifnet *);
406e51a25f8SAlfred Perlstein static int bge_ioctl(struct ifnet *, u_long, caddr_t);
4070f9bd73bSSam Leffler static void bge_init_locked(struct bge_softc *);
408e51a25f8SAlfred Perlstein static void bge_init(void *);
4095a147ba6SPyun YongHyeon static void bge_stop_block(struct bge_softc *, bus_size_t, uint32_t);
410e51a25f8SAlfred Perlstein static void bge_stop(struct bge_softc *);
411b74e67fbSGleb Smirnoff static void bge_watchdog(struct bge_softc *);
412b6c974e8SWarner Losh static int bge_shutdown(device_t);
41367d5e043SOleg Bulyzhin static int bge_ifmedia_upd_locked(struct ifnet *);
414e51a25f8SAlfred Perlstein static int bge_ifmedia_upd(struct ifnet *);
415e51a25f8SAlfred Perlstein static void bge_ifmedia_sts(struct ifnet *, struct ifmediareq *);
41695d67482SBill Paul 
41738cc658fSJohn Baldwin static uint8_t bge_nvram_getbyte(struct bge_softc *, int, uint8_t *);
41838cc658fSJohn Baldwin static int bge_read_nvram(struct bge_softc *, caddr_t, int, int);
41938cc658fSJohn Baldwin 
4203f74909aSGleb Smirnoff static uint8_t bge_eeprom_getbyte(struct bge_softc *, int, uint8_t *);
421e51a25f8SAlfred Perlstein static int bge_read_eeprom(struct bge_softc *, caddr_t, int, int);
42295d67482SBill Paul 
4233e9b1bcaSJung-uk Kim static void bge_setpromisc(struct bge_softc *);
424e51a25f8SAlfred Perlstein static void bge_setmulti(struct bge_softc *);
425cb2eacc7SYaroslav Tykhiy static void bge_setvlan(struct bge_softc *);
42695d67482SBill Paul 
427e0b7b101SPyun YongHyeon static __inline void bge_rxreuse_std(struct bge_softc *, int);
428e0b7b101SPyun YongHyeon static __inline void bge_rxreuse_jumbo(struct bge_softc *, int);
429943787f3SPyun YongHyeon static int bge_newbuf_std(struct bge_softc *, int);
430943787f3SPyun YongHyeon static int bge_newbuf_jumbo(struct bge_softc *, int);
431e51a25f8SAlfred Perlstein static int bge_init_rx_ring_std(struct bge_softc *);
432e51a25f8SAlfred Perlstein static void bge_free_rx_ring_std(struct bge_softc *);
433e51a25f8SAlfred Perlstein static int bge_init_rx_ring_jumbo(struct bge_softc *);
434e51a25f8SAlfred Perlstein static void bge_free_rx_ring_jumbo(struct bge_softc *);
435e51a25f8SAlfred Perlstein static void bge_free_tx_ring(struct bge_softc *);
436e51a25f8SAlfred Perlstein static int bge_init_tx_ring(struct bge_softc *);
43795d67482SBill Paul 
438e51a25f8SAlfred Perlstein static int bge_chipinit(struct bge_softc *);
439e51a25f8SAlfred Perlstein static int bge_blockinit(struct bge_softc *);
44095d67482SBill Paul 
4415fea260fSMarius Strobl static int bge_has_eaddr(struct bge_softc *);
4423f74909aSGleb Smirnoff static uint32_t bge_readmem_ind(struct bge_softc *, int);
443e51a25f8SAlfred Perlstein static void bge_writemem_ind(struct bge_softc *, int, int);
44438cc658fSJohn Baldwin static void bge_writembx(struct bge_softc *, int, int);
44595d67482SBill Paul #ifdef notdef
4463f74909aSGleb Smirnoff static uint32_t bge_readreg_ind(struct bge_softc *, int);
44795d67482SBill Paul #endif
4489ba784dbSScott Long static void bge_writemem_direct(struct bge_softc *, int, int);
449e51a25f8SAlfred Perlstein static void bge_writereg_ind(struct bge_softc *, int, int);
45095d67482SBill Paul 
451e51a25f8SAlfred Perlstein static int bge_miibus_readreg(device_t, int, int);
452e51a25f8SAlfred Perlstein static int bge_miibus_writereg(device_t, int, int, int);
453e51a25f8SAlfred Perlstein static void bge_miibus_statchg(device_t);
45475719184SGleb Smirnoff #ifdef DEVICE_POLLING
4551abcdbd1SAttilio Rao static int bge_poll(struct ifnet *ifp, enum poll_cmd cmd, int count);
45675719184SGleb Smirnoff #endif
45795d67482SBill Paul 
4588cb1383cSDoug Ambrisko #define	BGE_RESET_START 1
4598cb1383cSDoug Ambrisko #define	BGE_RESET_STOP  2
4608cb1383cSDoug Ambrisko static void bge_sig_post_reset(struct bge_softc *, int);
4618cb1383cSDoug Ambrisko static void bge_sig_legacy(struct bge_softc *, int);
4628cb1383cSDoug Ambrisko static void bge_sig_pre_reset(struct bge_softc *, int);
463797ab05eSPyun YongHyeon static void bge_stop_fw(struct bge_softc *);
4648cb1383cSDoug Ambrisko static int bge_reset(struct bge_softc *);
465dab5cd05SOleg Bulyzhin static void bge_link_upd(struct bge_softc *);
46695d67482SBill Paul 
4676f8718a3SScott Long /*
4686f8718a3SScott Long  * The BGE_REGISTER_DEBUG option is only for low-level debugging.  It may
4696f8718a3SScott Long  * leak information to untrusted users.  It is also known to cause alignment
4706f8718a3SScott Long  * traps on certain architectures.
4716f8718a3SScott Long  */
4726f8718a3SScott Long #ifdef BGE_REGISTER_DEBUG
4736f8718a3SScott Long static int bge_sysctl_debug_info(SYSCTL_HANDLER_ARGS);
4746f8718a3SScott Long static int bge_sysctl_reg_read(SYSCTL_HANDLER_ARGS);
4756f8718a3SScott Long static int bge_sysctl_mem_read(SYSCTL_HANDLER_ARGS);
4766f8718a3SScott Long #endif
4776f8718a3SScott Long static void bge_add_sysctls(struct bge_softc *);
4782280c16bSPyun YongHyeon static void bge_add_sysctl_stats_regs(struct bge_softc *,
4792280c16bSPyun YongHyeon     struct sysctl_ctx_list *, struct sysctl_oid_list *);
4802280c16bSPyun YongHyeon static void bge_add_sysctl_stats(struct bge_softc *, struct sysctl_ctx_list *,
4812280c16bSPyun YongHyeon     struct sysctl_oid_list *);
482763757b2SScott Long static int bge_sysctl_stats(SYSCTL_HANDLER_ARGS);
4836f8718a3SScott Long 
48495d67482SBill Paul static device_method_t bge_methods[] = {
48595d67482SBill Paul 	/* Device interface */
48695d67482SBill Paul 	DEVMETHOD(device_probe,		bge_probe),
48795d67482SBill Paul 	DEVMETHOD(device_attach,	bge_attach),
48895d67482SBill Paul 	DEVMETHOD(device_detach,	bge_detach),
48995d67482SBill Paul 	DEVMETHOD(device_shutdown,	bge_shutdown),
49014afefa3SPawel Jakub Dawidek 	DEVMETHOD(device_suspend,	bge_suspend),
49114afefa3SPawel Jakub Dawidek 	DEVMETHOD(device_resume,	bge_resume),
49295d67482SBill Paul 
49395d67482SBill Paul 	/* bus interface */
49495d67482SBill Paul 	DEVMETHOD(bus_print_child,	bus_generic_print_child),
49595d67482SBill Paul 	DEVMETHOD(bus_driver_added,	bus_generic_driver_added),
49695d67482SBill Paul 
49795d67482SBill Paul 	/* MII interface */
49895d67482SBill Paul 	DEVMETHOD(miibus_readreg,	bge_miibus_readreg),
49995d67482SBill Paul 	DEVMETHOD(miibus_writereg,	bge_miibus_writereg),
50095d67482SBill Paul 	DEVMETHOD(miibus_statchg,	bge_miibus_statchg),
50195d67482SBill Paul 
50295d67482SBill Paul 	{ 0, 0 }
50395d67482SBill Paul };
50495d67482SBill Paul 
50595d67482SBill Paul static driver_t bge_driver = {
50695d67482SBill Paul 	"bge",
50795d67482SBill Paul 	bge_methods,
50895d67482SBill Paul 	sizeof(struct bge_softc)
50995d67482SBill Paul };
51095d67482SBill Paul 
51195d67482SBill Paul static devclass_t bge_devclass;
51295d67482SBill Paul 
513f246e4a1SMatthew N. Dodd DRIVER_MODULE(bge, pci, bge_driver, bge_devclass, 0, 0);
51495d67482SBill Paul DRIVER_MODULE(miibus, bge, miibus_driver, miibus_devclass, 0, 0);
51595d67482SBill Paul 
516f1a7e6d5SScott Long static int bge_allow_asf = 1;
517f1a7e6d5SScott Long 
518f1a7e6d5SScott Long TUNABLE_INT("hw.bge.allow_asf", &bge_allow_asf);
519f1a7e6d5SScott Long 
520f1a7e6d5SScott Long SYSCTL_NODE(_hw, OID_AUTO, bge, CTLFLAG_RD, 0, "BGE driver parameters");
521f1a7e6d5SScott Long SYSCTL_INT(_hw_bge, OID_AUTO, allow_asf, CTLFLAG_RD, &bge_allow_asf, 0,
522f1a7e6d5SScott Long 	"Allow ASF mode if available");
523c4529f41SMichael Reifenberger 
52408013fd3SMarius Strobl #define	SPARC64_BLADE_1500_MODEL	"SUNW,Sun-Blade-1500"
52508013fd3SMarius Strobl #define	SPARC64_BLADE_1500_PATH_BGE	"/pci@1f,700000/network@2"
52608013fd3SMarius Strobl #define	SPARC64_BLADE_2500_MODEL	"SUNW,Sun-Blade-2500"
52708013fd3SMarius Strobl #define	SPARC64_BLADE_2500_PATH_BGE	"/pci@1c,600000/network@3"
52808013fd3SMarius Strobl #define	SPARC64_OFW_SUBVENDOR		"subsystem-vendor-id"
52908013fd3SMarius Strobl 
53008013fd3SMarius Strobl static int
5315fea260fSMarius Strobl bge_has_eaddr(struct bge_softc *sc)
53208013fd3SMarius Strobl {
53308013fd3SMarius Strobl #ifdef __sparc64__
53408013fd3SMarius Strobl 	char buf[sizeof(SPARC64_BLADE_1500_PATH_BGE)];
53508013fd3SMarius Strobl 	device_t dev;
53608013fd3SMarius Strobl 	uint32_t subvendor;
53708013fd3SMarius Strobl 
53808013fd3SMarius Strobl 	dev = sc->bge_dev;
53908013fd3SMarius Strobl 
54008013fd3SMarius Strobl 	/*
54108013fd3SMarius Strobl 	 * The on-board BGEs found in sun4u machines aren't fitted with
54208013fd3SMarius Strobl 	 * an EEPROM which means that we have to obtain the MAC address
54308013fd3SMarius Strobl 	 * via OFW and that some tests will always fail.  We distinguish
54408013fd3SMarius Strobl 	 * such BGEs by the subvendor ID, which also has to be obtained
54508013fd3SMarius Strobl 	 * from OFW instead of the PCI configuration space as the latter
54608013fd3SMarius Strobl 	 * indicates Broadcom as the subvendor of the netboot interface.
54708013fd3SMarius Strobl 	 * For early Blade 1500 and 2500 we even have to check the OFW
54808013fd3SMarius Strobl 	 * device path as the subvendor ID always defaults to Broadcom
54908013fd3SMarius Strobl 	 * there.
55008013fd3SMarius Strobl 	 */
55108013fd3SMarius Strobl 	if (OF_getprop(ofw_bus_get_node(dev), SPARC64_OFW_SUBVENDOR,
55208013fd3SMarius Strobl 	    &subvendor, sizeof(subvendor)) == sizeof(subvendor) &&
5532d857b9bSMarius Strobl 	    (subvendor == FJTSU_VENDORID || subvendor == SUN_VENDORID))
55408013fd3SMarius Strobl 		return (0);
55508013fd3SMarius Strobl 	memset(buf, 0, sizeof(buf));
55608013fd3SMarius Strobl 	if (OF_package_to_path(ofw_bus_get_node(dev), buf, sizeof(buf)) > 0) {
55708013fd3SMarius Strobl 		if (strcmp(sparc64_model, SPARC64_BLADE_1500_MODEL) == 0 &&
55808013fd3SMarius Strobl 		    strcmp(buf, SPARC64_BLADE_1500_PATH_BGE) == 0)
55908013fd3SMarius Strobl 			return (0);
56008013fd3SMarius Strobl 		if (strcmp(sparc64_model, SPARC64_BLADE_2500_MODEL) == 0 &&
56108013fd3SMarius Strobl 		    strcmp(buf, SPARC64_BLADE_2500_PATH_BGE) == 0)
56208013fd3SMarius Strobl 			return (0);
56308013fd3SMarius Strobl 	}
56408013fd3SMarius Strobl #endif
56508013fd3SMarius Strobl 	return (1);
56608013fd3SMarius Strobl }
56708013fd3SMarius Strobl 
5683f74909aSGleb Smirnoff static uint32_t
5693f74909aSGleb Smirnoff bge_readmem_ind(struct bge_softc *sc, int off)
57095d67482SBill Paul {
57195d67482SBill Paul 	device_t dev;
5726f8718a3SScott Long 	uint32_t val;
57395d67482SBill Paul 
574a4431ebaSPyun YongHyeon 	if (sc->bge_asicrev == BGE_ASICREV_BCM5906 &&
575a4431ebaSPyun YongHyeon 	    off >= BGE_STATS_BLOCK && off < BGE_SEND_RING_1_TO_4)
576a4431ebaSPyun YongHyeon 		return (0);
577a4431ebaSPyun YongHyeon 
57895d67482SBill Paul 	dev = sc->bge_dev;
57995d67482SBill Paul 
58095d67482SBill Paul 	pci_write_config(dev, BGE_PCI_MEMWIN_BASEADDR, off, 4);
5816f8718a3SScott Long 	val = pci_read_config(dev, BGE_PCI_MEMWIN_DATA, 4);
5826f8718a3SScott Long 	pci_write_config(dev, BGE_PCI_MEMWIN_BASEADDR, 0, 4);
5836f8718a3SScott Long 	return (val);
58495d67482SBill Paul }
58595d67482SBill Paul 
58695d67482SBill Paul static void
5873f74909aSGleb Smirnoff bge_writemem_ind(struct bge_softc *sc, int off, int val)
58895d67482SBill Paul {
58995d67482SBill Paul 	device_t dev;
59095d67482SBill Paul 
591a4431ebaSPyun YongHyeon 	if (sc->bge_asicrev == BGE_ASICREV_BCM5906 &&
592a4431ebaSPyun YongHyeon 	    off >= BGE_STATS_BLOCK && off < BGE_SEND_RING_1_TO_4)
593a4431ebaSPyun YongHyeon 		return;
594a4431ebaSPyun YongHyeon 
59595d67482SBill Paul 	dev = sc->bge_dev;
59695d67482SBill Paul 
59795d67482SBill Paul 	pci_write_config(dev, BGE_PCI_MEMWIN_BASEADDR, off, 4);
59895d67482SBill Paul 	pci_write_config(dev, BGE_PCI_MEMWIN_DATA, val, 4);
5996f8718a3SScott Long 	pci_write_config(dev, BGE_PCI_MEMWIN_BASEADDR, 0, 4);
60095d67482SBill Paul }
60195d67482SBill Paul 
60295d67482SBill Paul #ifdef notdef
6033f74909aSGleb Smirnoff static uint32_t
6043f74909aSGleb Smirnoff bge_readreg_ind(struct bge_softc *sc, int off)
60595d67482SBill Paul {
60695d67482SBill Paul 	device_t dev;
60795d67482SBill Paul 
60895d67482SBill Paul 	dev = sc->bge_dev;
60995d67482SBill Paul 
61095d67482SBill Paul 	pci_write_config(dev, BGE_PCI_REG_BASEADDR, off, 4);
61195d67482SBill Paul 	return (pci_read_config(dev, BGE_PCI_REG_DATA, 4));
61295d67482SBill Paul }
61395d67482SBill Paul #endif
61495d67482SBill Paul 
61595d67482SBill Paul static void
6163f74909aSGleb Smirnoff bge_writereg_ind(struct bge_softc *sc, int off, int val)
61795d67482SBill Paul {
61895d67482SBill Paul 	device_t dev;
61995d67482SBill Paul 
62095d67482SBill Paul 	dev = sc->bge_dev;
62195d67482SBill Paul 
62295d67482SBill Paul 	pci_write_config(dev, BGE_PCI_REG_BASEADDR, off, 4);
62395d67482SBill Paul 	pci_write_config(dev, BGE_PCI_REG_DATA, val, 4);
62495d67482SBill Paul }
62595d67482SBill Paul 
6266f8718a3SScott Long static void
6276f8718a3SScott Long bge_writemem_direct(struct bge_softc *sc, int off, int val)
6286f8718a3SScott Long {
6296f8718a3SScott Long 	CSR_WRITE_4(sc, off, val);
6306f8718a3SScott Long }
6316f8718a3SScott Long 
63238cc658fSJohn Baldwin static void
63338cc658fSJohn Baldwin bge_writembx(struct bge_softc *sc, int off, int val)
63438cc658fSJohn Baldwin {
63538cc658fSJohn Baldwin 	if (sc->bge_asicrev == BGE_ASICREV_BCM5906)
63638cc658fSJohn Baldwin 		off += BGE_LPMBX_IRQ0_HI - BGE_MBX_IRQ0_HI;
63738cc658fSJohn Baldwin 
63838cc658fSJohn Baldwin 	CSR_WRITE_4(sc, off, val);
63938cc658fSJohn Baldwin }
64038cc658fSJohn Baldwin 
641f41ac2beSBill Paul /*
642f41ac2beSBill Paul  * Map a single buffer address.
643f41ac2beSBill Paul  */
644f41ac2beSBill Paul 
645f41ac2beSBill Paul static void
6463f74909aSGleb Smirnoff bge_dma_map_addr(void *arg, bus_dma_segment_t *segs, int nseg, int error)
647f41ac2beSBill Paul {
648f41ac2beSBill Paul 	struct bge_dmamap_arg *ctx;
649f41ac2beSBill Paul 
650f41ac2beSBill Paul 	if (error)
651f41ac2beSBill Paul 		return;
652f41ac2beSBill Paul 
6535b610048SPyun YongHyeon 	KASSERT(nseg == 1, ("%s: %d segments returned!", __func__, nseg));
6545b610048SPyun YongHyeon 
655f41ac2beSBill Paul 	ctx = arg;
656f41ac2beSBill Paul 	ctx->bge_busaddr = segs->ds_addr;
657f41ac2beSBill Paul }
658f41ac2beSBill Paul 
65938cc658fSJohn Baldwin static uint8_t
66038cc658fSJohn Baldwin bge_nvram_getbyte(struct bge_softc *sc, int addr, uint8_t *dest)
66138cc658fSJohn Baldwin {
66238cc658fSJohn Baldwin 	uint32_t access, byte = 0;
66338cc658fSJohn Baldwin 	int i;
66438cc658fSJohn Baldwin 
66538cc658fSJohn Baldwin 	/* Lock. */
66638cc658fSJohn Baldwin 	CSR_WRITE_4(sc, BGE_NVRAM_SWARB, BGE_NVRAMSWARB_SET1);
66738cc658fSJohn Baldwin 	for (i = 0; i < 8000; i++) {
66838cc658fSJohn Baldwin 		if (CSR_READ_4(sc, BGE_NVRAM_SWARB) & BGE_NVRAMSWARB_GNT1)
66938cc658fSJohn Baldwin 			break;
67038cc658fSJohn Baldwin 		DELAY(20);
67138cc658fSJohn Baldwin 	}
67238cc658fSJohn Baldwin 	if (i == 8000)
67338cc658fSJohn Baldwin 		return (1);
67438cc658fSJohn Baldwin 
67538cc658fSJohn Baldwin 	/* Enable access. */
67638cc658fSJohn Baldwin 	access = CSR_READ_4(sc, BGE_NVRAM_ACCESS);
67738cc658fSJohn Baldwin 	CSR_WRITE_4(sc, BGE_NVRAM_ACCESS, access | BGE_NVRAMACC_ENABLE);
67838cc658fSJohn Baldwin 
67938cc658fSJohn Baldwin 	CSR_WRITE_4(sc, BGE_NVRAM_ADDR, addr & 0xfffffffc);
68038cc658fSJohn Baldwin 	CSR_WRITE_4(sc, BGE_NVRAM_CMD, BGE_NVRAM_READCMD);
68138cc658fSJohn Baldwin 	for (i = 0; i < BGE_TIMEOUT * 10; i++) {
68238cc658fSJohn Baldwin 		DELAY(10);
68338cc658fSJohn Baldwin 		if (CSR_READ_4(sc, BGE_NVRAM_CMD) & BGE_NVRAMCMD_DONE) {
68438cc658fSJohn Baldwin 			DELAY(10);
68538cc658fSJohn Baldwin 			break;
68638cc658fSJohn Baldwin 		}
68738cc658fSJohn Baldwin 	}
68838cc658fSJohn Baldwin 
68938cc658fSJohn Baldwin 	if (i == BGE_TIMEOUT * 10) {
69038cc658fSJohn Baldwin 		if_printf(sc->bge_ifp, "nvram read timed out\n");
69138cc658fSJohn Baldwin 		return (1);
69238cc658fSJohn Baldwin 	}
69338cc658fSJohn Baldwin 
69438cc658fSJohn Baldwin 	/* Get result. */
69538cc658fSJohn Baldwin 	byte = CSR_READ_4(sc, BGE_NVRAM_RDDATA);
69638cc658fSJohn Baldwin 
69738cc658fSJohn Baldwin 	*dest = (bswap32(byte) >> ((addr % 4) * 8)) & 0xFF;
69838cc658fSJohn Baldwin 
69938cc658fSJohn Baldwin 	/* Disable access. */
70038cc658fSJohn Baldwin 	CSR_WRITE_4(sc, BGE_NVRAM_ACCESS, access);
70138cc658fSJohn Baldwin 
70238cc658fSJohn Baldwin 	/* Unlock. */
70338cc658fSJohn Baldwin 	CSR_WRITE_4(sc, BGE_NVRAM_SWARB, BGE_NVRAMSWARB_CLR1);
70438cc658fSJohn Baldwin 	CSR_READ_4(sc, BGE_NVRAM_SWARB);
70538cc658fSJohn Baldwin 
70638cc658fSJohn Baldwin 	return (0);
70738cc658fSJohn Baldwin }
70838cc658fSJohn Baldwin 
70938cc658fSJohn Baldwin /*
71038cc658fSJohn Baldwin  * Read a sequence of bytes from NVRAM.
71138cc658fSJohn Baldwin  */
71238cc658fSJohn Baldwin static int
71338cc658fSJohn Baldwin bge_read_nvram(struct bge_softc *sc, caddr_t dest, int off, int cnt)
71438cc658fSJohn Baldwin {
71538cc658fSJohn Baldwin 	int err = 0, i;
71638cc658fSJohn Baldwin 	uint8_t byte = 0;
71738cc658fSJohn Baldwin 
71838cc658fSJohn Baldwin 	if (sc->bge_asicrev != BGE_ASICREV_BCM5906)
71938cc658fSJohn Baldwin 		return (1);
72038cc658fSJohn Baldwin 
72138cc658fSJohn Baldwin 	for (i = 0; i < cnt; i++) {
72238cc658fSJohn Baldwin 		err = bge_nvram_getbyte(sc, off + i, &byte);
72338cc658fSJohn Baldwin 		if (err)
72438cc658fSJohn Baldwin 			break;
72538cc658fSJohn Baldwin 		*(dest + i) = byte;
72638cc658fSJohn Baldwin 	}
72738cc658fSJohn Baldwin 
72838cc658fSJohn Baldwin 	return (err ? 1 : 0);
72938cc658fSJohn Baldwin }
73038cc658fSJohn Baldwin 
73195d67482SBill Paul /*
73295d67482SBill Paul  * Read a byte of data stored in the EEPROM at address 'addr.' The
73395d67482SBill Paul  * BCM570x supports both the traditional bitbang interface and an
73495d67482SBill Paul  * auto access interface for reading the EEPROM. We use the auto
73595d67482SBill Paul  * access method.
73695d67482SBill Paul  */
7373f74909aSGleb Smirnoff static uint8_t
7383f74909aSGleb Smirnoff bge_eeprom_getbyte(struct bge_softc *sc, int addr, uint8_t *dest)
73995d67482SBill Paul {
74095d67482SBill Paul 	int i;
7413f74909aSGleb Smirnoff 	uint32_t byte = 0;
74295d67482SBill Paul 
74395d67482SBill Paul 	/*
74495d67482SBill Paul 	 * Enable use of auto EEPROM access so we can avoid
74595d67482SBill Paul 	 * having to use the bitbang method.
74695d67482SBill Paul 	 */
74795d67482SBill Paul 	BGE_SETBIT(sc, BGE_MISC_LOCAL_CTL, BGE_MLC_AUTO_EEPROM);
74895d67482SBill Paul 
74995d67482SBill Paul 	/* Reset the EEPROM, load the clock period. */
75095d67482SBill Paul 	CSR_WRITE_4(sc, BGE_EE_ADDR,
75195d67482SBill Paul 	    BGE_EEADDR_RESET | BGE_EEHALFCLK(BGE_HALFCLK_384SCL));
75295d67482SBill Paul 	DELAY(20);
75395d67482SBill Paul 
75495d67482SBill Paul 	/* Issue the read EEPROM command. */
75595d67482SBill Paul 	CSR_WRITE_4(sc, BGE_EE_ADDR, BGE_EE_READCMD | addr);
75695d67482SBill Paul 
75795d67482SBill Paul 	/* Wait for completion */
75895d67482SBill Paul 	for(i = 0; i < BGE_TIMEOUT * 10; i++) {
75995d67482SBill Paul 		DELAY(10);
76095d67482SBill Paul 		if (CSR_READ_4(sc, BGE_EE_ADDR) & BGE_EEADDR_DONE)
76195d67482SBill Paul 			break;
76295d67482SBill Paul 	}
76395d67482SBill Paul 
764d5d23857SJung-uk Kim 	if (i == BGE_TIMEOUT * 10) {
765fe806fdaSPyun YongHyeon 		device_printf(sc->bge_dev, "EEPROM read timed out\n");
766f6789fbaSPyun YongHyeon 		return (1);
76795d67482SBill Paul 	}
76895d67482SBill Paul 
76995d67482SBill Paul 	/* Get result. */
77095d67482SBill Paul 	byte = CSR_READ_4(sc, BGE_EE_DATA);
77195d67482SBill Paul 
7720c8aa4eaSJung-uk Kim 	*dest = (byte >> ((addr % 4) * 8)) & 0xFF;
77395d67482SBill Paul 
77495d67482SBill Paul 	return (0);
77595d67482SBill Paul }
77695d67482SBill Paul 
77795d67482SBill Paul /*
77895d67482SBill Paul  * Read a sequence of bytes from the EEPROM.
77995d67482SBill Paul  */
78095d67482SBill Paul static int
7813f74909aSGleb Smirnoff bge_read_eeprom(struct bge_softc *sc, caddr_t dest, int off, int cnt)
78295d67482SBill Paul {
7833f74909aSGleb Smirnoff 	int i, error = 0;
7843f74909aSGleb Smirnoff 	uint8_t byte = 0;
78595d67482SBill Paul 
78695d67482SBill Paul 	for (i = 0; i < cnt; i++) {
7873f74909aSGleb Smirnoff 		error = bge_eeprom_getbyte(sc, off + i, &byte);
7883f74909aSGleb Smirnoff 		if (error)
78995d67482SBill Paul 			break;
79095d67482SBill Paul 		*(dest + i) = byte;
79195d67482SBill Paul 	}
79295d67482SBill Paul 
7933f74909aSGleb Smirnoff 	return (error ? 1 : 0);
79495d67482SBill Paul }
79595d67482SBill Paul 
79695d67482SBill Paul static int
7973f74909aSGleb Smirnoff bge_miibus_readreg(device_t dev, int phy, int reg)
79895d67482SBill Paul {
79995d67482SBill Paul 	struct bge_softc *sc;
800a813ed78SPyun YongHyeon 	uint32_t val;
80195d67482SBill Paul 	int i;
80295d67482SBill Paul 
80395d67482SBill Paul 	sc = device_get_softc(dev);
80495d67482SBill Paul 
805a813ed78SPyun YongHyeon 	/* Clear the autopoll bit if set, otherwise may trigger PCI errors. */
806a813ed78SPyun YongHyeon 	if ((sc->bge_mi_mode & BGE_MIMODE_AUTOPOLL) != 0) {
807a813ed78SPyun YongHyeon 		CSR_WRITE_4(sc, BGE_MI_MODE,
808a813ed78SPyun YongHyeon 		    sc->bge_mi_mode & ~BGE_MIMODE_AUTOPOLL);
809a813ed78SPyun YongHyeon 		DELAY(80);
81037ceeb4dSPaul Saab 	}
81137ceeb4dSPaul Saab 
81295d67482SBill Paul 	CSR_WRITE_4(sc, BGE_MI_COMM, BGE_MICMD_READ | BGE_MICOMM_BUSY |
81395d67482SBill Paul 	    BGE_MIPHY(phy) | BGE_MIREG(reg));
81495d67482SBill Paul 
815a813ed78SPyun YongHyeon 	/* Poll for the PHY register access to complete. */
81695d67482SBill Paul 	for (i = 0; i < BGE_TIMEOUT; i++) {
817d5d23857SJung-uk Kim 		DELAY(10);
81895d67482SBill Paul 		val = CSR_READ_4(sc, BGE_MI_COMM);
819a813ed78SPyun YongHyeon 		if ((val & BGE_MICOMM_BUSY) == 0) {
820a813ed78SPyun YongHyeon 			DELAY(5);
821a813ed78SPyun YongHyeon 			val = CSR_READ_4(sc, BGE_MI_COMM);
82295d67482SBill Paul 			break;
82395d67482SBill Paul 		}
824a813ed78SPyun YongHyeon 	}
82595d67482SBill Paul 
82695d67482SBill Paul 	if (i == BGE_TIMEOUT) {
8275fea260fSMarius Strobl 		device_printf(sc->bge_dev,
8285fea260fSMarius Strobl 		    "PHY read timed out (phy %d, reg %d, val 0x%08x)\n",
8295fea260fSMarius Strobl 		    phy, reg, val);
83037ceeb4dSPaul Saab 		val = 0;
83195d67482SBill Paul 	}
83295d67482SBill Paul 
833a813ed78SPyun YongHyeon 	/* Restore the autopoll bit if necessary. */
834a813ed78SPyun YongHyeon 	if ((sc->bge_mi_mode & BGE_MIMODE_AUTOPOLL) != 0) {
835a813ed78SPyun YongHyeon 		CSR_WRITE_4(sc, BGE_MI_MODE, sc->bge_mi_mode);
836a813ed78SPyun YongHyeon 		DELAY(80);
83737ceeb4dSPaul Saab 	}
83837ceeb4dSPaul Saab 
83995d67482SBill Paul 	if (val & BGE_MICOMM_READFAIL)
84095d67482SBill Paul 		return (0);
84195d67482SBill Paul 
8420c8aa4eaSJung-uk Kim 	return (val & 0xFFFF);
84395d67482SBill Paul }
84495d67482SBill Paul 
84595d67482SBill Paul static int
8463f74909aSGleb Smirnoff bge_miibus_writereg(device_t dev, int phy, int reg, int val)
84795d67482SBill Paul {
84895d67482SBill Paul 	struct bge_softc *sc;
84995d67482SBill Paul 	int i;
85095d67482SBill Paul 
85195d67482SBill Paul 	sc = device_get_softc(dev);
85295d67482SBill Paul 
85338cc658fSJohn Baldwin 	if (sc->bge_asicrev == BGE_ASICREV_BCM5906 &&
85438cc658fSJohn Baldwin 	    (reg == BRGPHY_MII_1000CTL || reg == BRGPHY_MII_AUXCTL))
85538cc658fSJohn Baldwin 		return (0);
85638cc658fSJohn Baldwin 
857a813ed78SPyun YongHyeon 	/* Clear the autopoll bit if set, otherwise may trigger PCI errors. */
858a813ed78SPyun YongHyeon 	if ((sc->bge_mi_mode & BGE_MIMODE_AUTOPOLL) != 0) {
859a813ed78SPyun YongHyeon 		CSR_WRITE_4(sc, BGE_MI_MODE,
860a813ed78SPyun YongHyeon 		    sc->bge_mi_mode & ~BGE_MIMODE_AUTOPOLL);
861a813ed78SPyun YongHyeon 		DELAY(80);
86237ceeb4dSPaul Saab 	}
86337ceeb4dSPaul Saab 
86495d67482SBill Paul 	CSR_WRITE_4(sc, BGE_MI_COMM, BGE_MICMD_WRITE | BGE_MICOMM_BUSY |
86595d67482SBill Paul 	    BGE_MIPHY(phy) | BGE_MIREG(reg) | val);
86695d67482SBill Paul 
86795d67482SBill Paul 	for (i = 0; i < BGE_TIMEOUT; i++) {
868d5d23857SJung-uk Kim 		DELAY(10);
86938cc658fSJohn Baldwin 		if (!(CSR_READ_4(sc, BGE_MI_COMM) & BGE_MICOMM_BUSY)) {
87038cc658fSJohn Baldwin 			DELAY(5);
87138cc658fSJohn Baldwin 			CSR_READ_4(sc, BGE_MI_COMM); /* dummy read */
87295d67482SBill Paul 			break;
873d5d23857SJung-uk Kim 		}
87438cc658fSJohn Baldwin 	}
875d5d23857SJung-uk Kim 
876a813ed78SPyun YongHyeon 	/* Restore the autopoll bit if necessary. */
877a813ed78SPyun YongHyeon 	if ((sc->bge_mi_mode & BGE_MIMODE_AUTOPOLL) != 0) {
878a813ed78SPyun YongHyeon 		CSR_WRITE_4(sc, BGE_MI_MODE, sc->bge_mi_mode);
879a813ed78SPyun YongHyeon 		DELAY(80);
880a813ed78SPyun YongHyeon 	}
881a813ed78SPyun YongHyeon 
882a813ed78SPyun YongHyeon 	if (i == BGE_TIMEOUT)
88338cc658fSJohn Baldwin 		device_printf(sc->bge_dev,
88438cc658fSJohn Baldwin 		    "PHY write timed out (phy %d, reg %d, val %d)\n",
88538cc658fSJohn Baldwin 		    phy, reg, val);
88637ceeb4dSPaul Saab 
88795d67482SBill Paul 	return (0);
88895d67482SBill Paul }
88995d67482SBill Paul 
89095d67482SBill Paul static void
8913f74909aSGleb Smirnoff bge_miibus_statchg(device_t dev)
89295d67482SBill Paul {
89395d67482SBill Paul 	struct bge_softc *sc;
89495d67482SBill Paul 	struct mii_data *mii;
89595d67482SBill Paul 	sc = device_get_softc(dev);
89695d67482SBill Paul 	mii = device_get_softc(sc->bge_miibus);
89795d67482SBill Paul 
898d4f5240aSPyun YongHyeon 	if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) ==
899d4f5240aSPyun YongHyeon 	    (IFM_ACTIVE | IFM_AVALID)) {
900d4f5240aSPyun YongHyeon 		switch (IFM_SUBTYPE(mii->mii_media_active)) {
901d4f5240aSPyun YongHyeon 		case IFM_10_T:
902d4f5240aSPyun YongHyeon 		case IFM_100_TX:
903d4f5240aSPyun YongHyeon 			sc->bge_link = 1;
904d4f5240aSPyun YongHyeon 			break;
905d4f5240aSPyun YongHyeon 		case IFM_1000_T:
906d4f5240aSPyun YongHyeon 		case IFM_1000_SX:
907d4f5240aSPyun YongHyeon 		case IFM_2500_SX:
908d4f5240aSPyun YongHyeon 			if (sc->bge_asicrev != BGE_ASICREV_BCM5906)
909d4f5240aSPyun YongHyeon 				sc->bge_link = 1;
910d4f5240aSPyun YongHyeon 			else
911d4f5240aSPyun YongHyeon 				sc->bge_link = 0;
912d4f5240aSPyun YongHyeon 			break;
913d4f5240aSPyun YongHyeon 		default:
914d4f5240aSPyun YongHyeon 			sc->bge_link = 0;
915d4f5240aSPyun YongHyeon 			break;
916d4f5240aSPyun YongHyeon 		}
917d4f5240aSPyun YongHyeon 	} else
918d4f5240aSPyun YongHyeon 		sc->bge_link = 0;
919d4f5240aSPyun YongHyeon 	if (sc->bge_link == 0)
920d4f5240aSPyun YongHyeon 		return;
92195d67482SBill Paul 	BGE_CLRBIT(sc, BGE_MAC_MODE, BGE_MACMODE_PORTMODE);
922ea3b4127SPyun YongHyeon 	if (IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_T ||
923ea3b4127SPyun YongHyeon 	    IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_SX)
92495d67482SBill Paul 		BGE_SETBIT(sc, BGE_MAC_MODE, BGE_PORTMODE_GMII);
9253f74909aSGleb Smirnoff 	else
92695d67482SBill Paul 		BGE_SETBIT(sc, BGE_MAC_MODE, BGE_PORTMODE_MII);
92795d67482SBill Paul 
9286854be25SPyun YongHyeon 	if (IFM_OPTIONS(mii->mii_media_active & IFM_FDX) != 0) {
92995d67482SBill Paul 		BGE_CLRBIT(sc, BGE_MAC_MODE, BGE_MACMODE_HALF_DUPLEX);
930efd4fc3fSMarius Strobl 		if ((IFM_OPTIONS(mii->mii_media_active) &
931efd4fc3fSMarius Strobl 		    IFM_ETH_TXPAUSE) != 0)
9326854be25SPyun YongHyeon 			BGE_SETBIT(sc, BGE_TX_MODE, BGE_TXMODE_FLOWCTL_ENABLE);
9333f74909aSGleb Smirnoff 		else
9346854be25SPyun YongHyeon 			BGE_CLRBIT(sc, BGE_TX_MODE, BGE_TXMODE_FLOWCTL_ENABLE);
935efd4fc3fSMarius Strobl 		if ((IFM_OPTIONS(mii->mii_media_active) &
936efd4fc3fSMarius Strobl 		    IFM_ETH_RXPAUSE) != 0)
9376854be25SPyun YongHyeon 			BGE_SETBIT(sc, BGE_RX_MODE, BGE_RXMODE_FLOWCTL_ENABLE);
9386854be25SPyun YongHyeon 		else
9396854be25SPyun YongHyeon 			BGE_CLRBIT(sc, BGE_RX_MODE, BGE_RXMODE_FLOWCTL_ENABLE);
9406854be25SPyun YongHyeon 	} else {
94195d67482SBill Paul 		BGE_SETBIT(sc, BGE_MAC_MODE, BGE_MACMODE_HALF_DUPLEX);
9426854be25SPyun YongHyeon 		BGE_CLRBIT(sc, BGE_TX_MODE, BGE_TXMODE_FLOWCTL_ENABLE);
9436854be25SPyun YongHyeon 		BGE_CLRBIT(sc, BGE_RX_MODE, BGE_RXMODE_FLOWCTL_ENABLE);
9446854be25SPyun YongHyeon 	}
94595d67482SBill Paul }
94695d67482SBill Paul 
94795d67482SBill Paul /*
94895d67482SBill Paul  * Intialize a standard receive ring descriptor.
94995d67482SBill Paul  */
95095d67482SBill Paul static int
951943787f3SPyun YongHyeon bge_newbuf_std(struct bge_softc *sc, int i)
95295d67482SBill Paul {
953943787f3SPyun YongHyeon 	struct mbuf *m;
95495d67482SBill Paul 	struct bge_rx_bd *r;
955a23634a1SPyun YongHyeon 	bus_dma_segment_t segs[1];
956943787f3SPyun YongHyeon 	bus_dmamap_t map;
957a23634a1SPyun YongHyeon 	int error, nsegs;
95895d67482SBill Paul 
959f5459d4cSPyun YongHyeon 	if (sc->bge_flags & BGE_FLAG_JUMBO_STD &&
960f5459d4cSPyun YongHyeon 	    (sc->bge_ifp->if_mtu + ETHER_HDR_LEN + ETHER_CRC_LEN +
961f5459d4cSPyun YongHyeon 	    ETHER_VLAN_ENCAP_LEN > (MCLBYTES - ETHER_ALIGN))) {
962f5459d4cSPyun YongHyeon 		m = m_getjcl(M_DONTWAIT, MT_DATA, M_PKTHDR, MJUM9BYTES);
963f5459d4cSPyun YongHyeon 		if (m == NULL)
964f5459d4cSPyun YongHyeon 			return (ENOBUFS);
965f5459d4cSPyun YongHyeon 		m->m_len = m->m_pkthdr.len = MJUM9BYTES;
966f5459d4cSPyun YongHyeon 	} else {
967943787f3SPyun YongHyeon 		m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
968943787f3SPyun YongHyeon 		if (m == NULL)
96995d67482SBill Paul 			return (ENOBUFS);
970943787f3SPyun YongHyeon 		m->m_len = m->m_pkthdr.len = MCLBYTES;
971f5459d4cSPyun YongHyeon 	}
972652ae483SGleb Smirnoff 	if ((sc->bge_flags & BGE_FLAG_RX_ALIGNBUG) == 0)
973943787f3SPyun YongHyeon 		m_adj(m, ETHER_ALIGN);
974943787f3SPyun YongHyeon 
9750ac56796SPyun YongHyeon 	error = bus_dmamap_load_mbuf_sg(sc->bge_cdata.bge_rx_mtag,
976943787f3SPyun YongHyeon 	    sc->bge_cdata.bge_rx_std_sparemap, m, segs, &nsegs, 0);
977a23634a1SPyun YongHyeon 	if (error != 0) {
978943787f3SPyun YongHyeon 		m_freem(m);
979a23634a1SPyun YongHyeon 		return (error);
980f41ac2beSBill Paul 	}
981943787f3SPyun YongHyeon 	if (sc->bge_cdata.bge_rx_std_chain[i] != NULL) {
982943787f3SPyun YongHyeon 		bus_dmamap_sync(sc->bge_cdata.bge_rx_mtag,
983943787f3SPyun YongHyeon 		    sc->bge_cdata.bge_rx_std_dmamap[i], BUS_DMASYNC_POSTREAD);
984943787f3SPyun YongHyeon 		bus_dmamap_unload(sc->bge_cdata.bge_rx_mtag,
985943787f3SPyun YongHyeon 		    sc->bge_cdata.bge_rx_std_dmamap[i]);
986943787f3SPyun YongHyeon 	}
987943787f3SPyun YongHyeon 	map = sc->bge_cdata.bge_rx_std_dmamap[i];
988943787f3SPyun YongHyeon 	sc->bge_cdata.bge_rx_std_dmamap[i] = sc->bge_cdata.bge_rx_std_sparemap;
989943787f3SPyun YongHyeon 	sc->bge_cdata.bge_rx_std_sparemap = map;
990943787f3SPyun YongHyeon 	sc->bge_cdata.bge_rx_std_chain[i] = m;
991e0b7b101SPyun YongHyeon 	sc->bge_cdata.bge_rx_std_seglen[i] = segs[0].ds_len;
992943787f3SPyun YongHyeon 	r = &sc->bge_ldata.bge_rx_std_ring[sc->bge_std];
993a23634a1SPyun YongHyeon 	r->bge_addr.bge_addr_lo = BGE_ADDR_LO(segs[0].ds_addr);
994a23634a1SPyun YongHyeon 	r->bge_addr.bge_addr_hi = BGE_ADDR_HI(segs[0].ds_addr);
995e907febfSPyun YongHyeon 	r->bge_flags = BGE_RXBDFLAG_END;
996a23634a1SPyun YongHyeon 	r->bge_len = segs[0].ds_len;
997e907febfSPyun YongHyeon 	r->bge_idx = i;
998f41ac2beSBill Paul 
9990ac56796SPyun YongHyeon 	bus_dmamap_sync(sc->bge_cdata.bge_rx_mtag,
1000943787f3SPyun YongHyeon 	    sc->bge_cdata.bge_rx_std_dmamap[i], BUS_DMASYNC_PREREAD);
100195d67482SBill Paul 
100295d67482SBill Paul 	return (0);
100395d67482SBill Paul }
100495d67482SBill Paul 
100595d67482SBill Paul /*
100695d67482SBill Paul  * Initialize a jumbo receive ring descriptor. This allocates
100795d67482SBill Paul  * a jumbo buffer from the pool managed internally by the driver.
100895d67482SBill Paul  */
100995d67482SBill Paul static int
1010943787f3SPyun YongHyeon bge_newbuf_jumbo(struct bge_softc *sc, int i)
101195d67482SBill Paul {
10121be6acb7SGleb Smirnoff 	bus_dma_segment_t segs[BGE_NSEG_JUMBO];
1013943787f3SPyun YongHyeon 	bus_dmamap_t map;
10141be6acb7SGleb Smirnoff 	struct bge_extrx_bd *r;
1015943787f3SPyun YongHyeon 	struct mbuf *m;
1016943787f3SPyun YongHyeon 	int error, nsegs;
101795d67482SBill Paul 
1018943787f3SPyun YongHyeon 	MGETHDR(m, M_DONTWAIT, MT_DATA);
1019943787f3SPyun YongHyeon 	if (m == NULL)
102095d67482SBill Paul 		return (ENOBUFS);
102195d67482SBill Paul 
1022943787f3SPyun YongHyeon 	m_cljget(m, M_DONTWAIT, MJUM9BYTES);
1023943787f3SPyun YongHyeon 	if (!(m->m_flags & M_EXT)) {
1024943787f3SPyun YongHyeon 		m_freem(m);
102595d67482SBill Paul 		return (ENOBUFS);
102695d67482SBill Paul 	}
1027943787f3SPyun YongHyeon 	m->m_len = m->m_pkthdr.len = MJUM9BYTES;
1028652ae483SGleb Smirnoff 	if ((sc->bge_flags & BGE_FLAG_RX_ALIGNBUG) == 0)
1029943787f3SPyun YongHyeon 		m_adj(m, ETHER_ALIGN);
10301be6acb7SGleb Smirnoff 
10311be6acb7SGleb Smirnoff 	error = bus_dmamap_load_mbuf_sg(sc->bge_cdata.bge_mtag_jumbo,
1032943787f3SPyun YongHyeon 	    sc->bge_cdata.bge_rx_jumbo_sparemap, m, segs, &nsegs, 0);
1033943787f3SPyun YongHyeon 	if (error != 0) {
1034943787f3SPyun YongHyeon 		m_freem(m);
10351be6acb7SGleb Smirnoff 		return (error);
1036f7cea149SGleb Smirnoff 	}
10371be6acb7SGleb Smirnoff 
1038aa8cbdbfSMarius Strobl 	if (sc->bge_cdata.bge_rx_jumbo_chain[i] != NULL) {
1039943787f3SPyun YongHyeon 		bus_dmamap_sync(sc->bge_cdata.bge_mtag_jumbo,
1040943787f3SPyun YongHyeon 		    sc->bge_cdata.bge_rx_jumbo_dmamap[i], BUS_DMASYNC_POSTREAD);
1041943787f3SPyun YongHyeon 		bus_dmamap_unload(sc->bge_cdata.bge_mtag_jumbo,
1042943787f3SPyun YongHyeon 		    sc->bge_cdata.bge_rx_jumbo_dmamap[i]);
1043943787f3SPyun YongHyeon 	}
1044943787f3SPyun YongHyeon 	map = sc->bge_cdata.bge_rx_jumbo_dmamap[i];
1045943787f3SPyun YongHyeon 	sc->bge_cdata.bge_rx_jumbo_dmamap[i] =
1046943787f3SPyun YongHyeon 	    sc->bge_cdata.bge_rx_jumbo_sparemap;
1047943787f3SPyun YongHyeon 	sc->bge_cdata.bge_rx_jumbo_sparemap = map;
1048943787f3SPyun YongHyeon 	sc->bge_cdata.bge_rx_jumbo_chain[i] = m;
1049e0b7b101SPyun YongHyeon 	sc->bge_cdata.bge_rx_jumbo_seglen[i][0] = 0;
1050e0b7b101SPyun YongHyeon 	sc->bge_cdata.bge_rx_jumbo_seglen[i][1] = 0;
1051e0b7b101SPyun YongHyeon 	sc->bge_cdata.bge_rx_jumbo_seglen[i][2] = 0;
1052e0b7b101SPyun YongHyeon 	sc->bge_cdata.bge_rx_jumbo_seglen[i][3] = 0;
1053e0b7b101SPyun YongHyeon 
10541be6acb7SGleb Smirnoff 	/*
10551be6acb7SGleb Smirnoff 	 * Fill in the extended RX buffer descriptor.
10561be6acb7SGleb Smirnoff 	 */
1057943787f3SPyun YongHyeon 	r = &sc->bge_ldata.bge_rx_jumbo_ring[sc->bge_jumbo];
10584e7ba1abSGleb Smirnoff 	r->bge_flags = BGE_RXBDFLAG_JUMBO_RING | BGE_RXBDFLAG_END;
10594e7ba1abSGleb Smirnoff 	r->bge_idx = i;
10604e7ba1abSGleb Smirnoff 	r->bge_len3 = r->bge_len2 = r->bge_len1 = 0;
10614e7ba1abSGleb Smirnoff 	switch (nsegs) {
10624e7ba1abSGleb Smirnoff 	case 4:
10634e7ba1abSGleb Smirnoff 		r->bge_addr3.bge_addr_lo = BGE_ADDR_LO(segs[3].ds_addr);
10644e7ba1abSGleb Smirnoff 		r->bge_addr3.bge_addr_hi = BGE_ADDR_HI(segs[3].ds_addr);
10654e7ba1abSGleb Smirnoff 		r->bge_len3 = segs[3].ds_len;
1066e0b7b101SPyun YongHyeon 		sc->bge_cdata.bge_rx_jumbo_seglen[i][3] = segs[3].ds_len;
10674e7ba1abSGleb Smirnoff 	case 3:
1068e907febfSPyun YongHyeon 		r->bge_addr2.bge_addr_lo = BGE_ADDR_LO(segs[2].ds_addr);
1069e907febfSPyun YongHyeon 		r->bge_addr2.bge_addr_hi = BGE_ADDR_HI(segs[2].ds_addr);
1070e907febfSPyun YongHyeon 		r->bge_len2 = segs[2].ds_len;
1071e0b7b101SPyun YongHyeon 		sc->bge_cdata.bge_rx_jumbo_seglen[i][2] = segs[2].ds_len;
10724e7ba1abSGleb Smirnoff 	case 2:
10734e7ba1abSGleb Smirnoff 		r->bge_addr1.bge_addr_lo = BGE_ADDR_LO(segs[1].ds_addr);
10744e7ba1abSGleb Smirnoff 		r->bge_addr1.bge_addr_hi = BGE_ADDR_HI(segs[1].ds_addr);
10754e7ba1abSGleb Smirnoff 		r->bge_len1 = segs[1].ds_len;
1076e0b7b101SPyun YongHyeon 		sc->bge_cdata.bge_rx_jumbo_seglen[i][1] = segs[1].ds_len;
10774e7ba1abSGleb Smirnoff 	case 1:
10784e7ba1abSGleb Smirnoff 		r->bge_addr0.bge_addr_lo = BGE_ADDR_LO(segs[0].ds_addr);
10794e7ba1abSGleb Smirnoff 		r->bge_addr0.bge_addr_hi = BGE_ADDR_HI(segs[0].ds_addr);
10804e7ba1abSGleb Smirnoff 		r->bge_len0 = segs[0].ds_len;
1081e0b7b101SPyun YongHyeon 		sc->bge_cdata.bge_rx_jumbo_seglen[i][0] = segs[0].ds_len;
10824e7ba1abSGleb Smirnoff 		break;
10834e7ba1abSGleb Smirnoff 	default:
10844e7ba1abSGleb Smirnoff 		panic("%s: %d segments\n", __func__, nsegs);
10854e7ba1abSGleb Smirnoff 	}
1086f41ac2beSBill Paul 
1087a41504a9SPyun YongHyeon 	bus_dmamap_sync(sc->bge_cdata.bge_mtag_jumbo,
1088943787f3SPyun YongHyeon 	    sc->bge_cdata.bge_rx_jumbo_dmamap[i], BUS_DMASYNC_PREREAD);
108995d67482SBill Paul 
109095d67482SBill Paul 	return (0);
109195d67482SBill Paul }
109295d67482SBill Paul 
109395d67482SBill Paul static int
10943f74909aSGleb Smirnoff bge_init_rx_ring_std(struct bge_softc *sc)
109595d67482SBill Paul {
10963ee5d7daSPyun YongHyeon 	int error, i;
109795d67482SBill Paul 
1098e6bf277eSPyun YongHyeon 	bzero(sc->bge_ldata.bge_rx_std_ring, BGE_STD_RX_RING_SZ);
109903e78bd0SPyun YongHyeon 	sc->bge_std = 0;
1100e0b7b101SPyun YongHyeon 	for (i = 0; i < BGE_STD_RX_RING_CNT; i++) {
1101943787f3SPyun YongHyeon 		if ((error = bge_newbuf_std(sc, i)) != 0)
11023ee5d7daSPyun YongHyeon 			return (error);
110303e78bd0SPyun YongHyeon 		BGE_INC(sc->bge_std, BGE_STD_RX_RING_CNT);
11041888f324SPyun YongHyeon 	}
110595d67482SBill Paul 
1106f41ac2beSBill Paul 	bus_dmamap_sync(sc->bge_cdata.bge_rx_std_ring_tag,
1107d77e9fa7SPyun YongHyeon 	    sc->bge_cdata.bge_rx_std_ring_map, BUS_DMASYNC_PREWRITE);
1108f41ac2beSBill Paul 
1109e0b7b101SPyun YongHyeon 	sc->bge_std = 0;
1110e0b7b101SPyun YongHyeon 	bge_writembx(sc, BGE_MBX_RX_STD_PROD_LO, BGE_STD_RX_RING_CNT - 1);
111195d67482SBill Paul 
111295d67482SBill Paul 	return (0);
111395d67482SBill Paul }
111495d67482SBill Paul 
111595d67482SBill Paul static void
11163f74909aSGleb Smirnoff bge_free_rx_ring_std(struct bge_softc *sc)
111795d67482SBill Paul {
111895d67482SBill Paul 	int i;
111995d67482SBill Paul 
112095d67482SBill Paul 	for (i = 0; i < BGE_STD_RX_RING_CNT; i++) {
112195d67482SBill Paul 		if (sc->bge_cdata.bge_rx_std_chain[i] != NULL) {
11220ac56796SPyun YongHyeon 			bus_dmamap_sync(sc->bge_cdata.bge_rx_mtag,
1123e65bed95SPyun YongHyeon 			    sc->bge_cdata.bge_rx_std_dmamap[i],
1124e65bed95SPyun YongHyeon 			    BUS_DMASYNC_POSTREAD);
11250ac56796SPyun YongHyeon 			bus_dmamap_unload(sc->bge_cdata.bge_rx_mtag,
1126f41ac2beSBill Paul 			    sc->bge_cdata.bge_rx_std_dmamap[i]);
1127e65bed95SPyun YongHyeon 			m_freem(sc->bge_cdata.bge_rx_std_chain[i]);
1128e65bed95SPyun YongHyeon 			sc->bge_cdata.bge_rx_std_chain[i] = NULL;
112995d67482SBill Paul 		}
1130f41ac2beSBill Paul 		bzero((char *)&sc->bge_ldata.bge_rx_std_ring[i],
113195d67482SBill Paul 		    sizeof(struct bge_rx_bd));
113295d67482SBill Paul 	}
113395d67482SBill Paul }
113495d67482SBill Paul 
113595d67482SBill Paul static int
11363f74909aSGleb Smirnoff bge_init_rx_ring_jumbo(struct bge_softc *sc)
113795d67482SBill Paul {
113895d67482SBill Paul 	struct bge_rcb *rcb;
11393ee5d7daSPyun YongHyeon 	int error, i;
114095d67482SBill Paul 
1141e6bf277eSPyun YongHyeon 	bzero(sc->bge_ldata.bge_rx_jumbo_ring, BGE_JUMBO_RX_RING_SZ);
114203e78bd0SPyun YongHyeon 	sc->bge_jumbo = 0;
114395d67482SBill Paul 	for (i = 0; i < BGE_JUMBO_RX_RING_CNT; i++) {
1144943787f3SPyun YongHyeon 		if ((error = bge_newbuf_jumbo(sc, i)) != 0)
11453ee5d7daSPyun YongHyeon 			return (error);
114603e78bd0SPyun YongHyeon 		BGE_INC(sc->bge_jumbo, BGE_JUMBO_RX_RING_CNT);
11471888f324SPyun YongHyeon 	}
114895d67482SBill Paul 
1149f41ac2beSBill Paul 	bus_dmamap_sync(sc->bge_cdata.bge_rx_jumbo_ring_tag,
1150d77e9fa7SPyun YongHyeon 	    sc->bge_cdata.bge_rx_jumbo_ring_map, BUS_DMASYNC_PREWRITE);
1151f41ac2beSBill Paul 
1152e0b7b101SPyun YongHyeon 	sc->bge_jumbo = 0;
115395d67482SBill Paul 
11548a315a6dSPyun YongHyeon 	/* Enable the jumbo receive producer ring. */
1155f41ac2beSBill Paul 	rcb = &sc->bge_ldata.bge_info.bge_jumbo_rx_rcb;
11568a315a6dSPyun YongHyeon 	rcb->bge_maxlen_flags =
11578a315a6dSPyun YongHyeon 	    BGE_RCB_MAXLEN_FLAGS(0, BGE_RCB_FLAG_USE_EXT_RX_BD);
115867111612SJohn Polstra 	CSR_WRITE_4(sc, BGE_RX_JUMBO_RCB_MAXLEN_FLAGS, rcb->bge_maxlen_flags);
115995d67482SBill Paul 
1160e0b7b101SPyun YongHyeon 	bge_writembx(sc, BGE_MBX_RX_JUMBO_PROD_LO, BGE_JUMBO_RX_RING_CNT - 1);
116195d67482SBill Paul 
116295d67482SBill Paul 	return (0);
116395d67482SBill Paul }
116495d67482SBill Paul 
116595d67482SBill Paul static void
11663f74909aSGleb Smirnoff bge_free_rx_ring_jumbo(struct bge_softc *sc)
116795d67482SBill Paul {
116895d67482SBill Paul 	int i;
116995d67482SBill Paul 
117095d67482SBill Paul 	for (i = 0; i < BGE_JUMBO_RX_RING_CNT; i++) {
117195d67482SBill Paul 		if (sc->bge_cdata.bge_rx_jumbo_chain[i] != NULL) {
1172e65bed95SPyun YongHyeon 			bus_dmamap_sync(sc->bge_cdata.bge_mtag_jumbo,
1173e65bed95SPyun YongHyeon 			    sc->bge_cdata.bge_rx_jumbo_dmamap[i],
1174e65bed95SPyun YongHyeon 			    BUS_DMASYNC_POSTREAD);
1175f41ac2beSBill Paul 			bus_dmamap_unload(sc->bge_cdata.bge_mtag_jumbo,
1176f41ac2beSBill Paul 			    sc->bge_cdata.bge_rx_jumbo_dmamap[i]);
1177e65bed95SPyun YongHyeon 			m_freem(sc->bge_cdata.bge_rx_jumbo_chain[i]);
1178e65bed95SPyun YongHyeon 			sc->bge_cdata.bge_rx_jumbo_chain[i] = NULL;
117995d67482SBill Paul 		}
1180f41ac2beSBill Paul 		bzero((char *)&sc->bge_ldata.bge_rx_jumbo_ring[i],
11811be6acb7SGleb Smirnoff 		    sizeof(struct bge_extrx_bd));
118295d67482SBill Paul 	}
118395d67482SBill Paul }
118495d67482SBill Paul 
118595d67482SBill Paul static void
11863f74909aSGleb Smirnoff bge_free_tx_ring(struct bge_softc *sc)
118795d67482SBill Paul {
118895d67482SBill Paul 	int i;
118995d67482SBill Paul 
1190f41ac2beSBill Paul 	if (sc->bge_ldata.bge_tx_ring == NULL)
119195d67482SBill Paul 		return;
119295d67482SBill Paul 
119395d67482SBill Paul 	for (i = 0; i < BGE_TX_RING_CNT; i++) {
119495d67482SBill Paul 		if (sc->bge_cdata.bge_tx_chain[i] != NULL) {
11950ac56796SPyun YongHyeon 			bus_dmamap_sync(sc->bge_cdata.bge_tx_mtag,
1196e65bed95SPyun YongHyeon 			    sc->bge_cdata.bge_tx_dmamap[i],
1197e65bed95SPyun YongHyeon 			    BUS_DMASYNC_POSTWRITE);
11980ac56796SPyun YongHyeon 			bus_dmamap_unload(sc->bge_cdata.bge_tx_mtag,
1199f41ac2beSBill Paul 			    sc->bge_cdata.bge_tx_dmamap[i]);
1200e65bed95SPyun YongHyeon 			m_freem(sc->bge_cdata.bge_tx_chain[i]);
1201e65bed95SPyun YongHyeon 			sc->bge_cdata.bge_tx_chain[i] = NULL;
120295d67482SBill Paul 		}
1203f41ac2beSBill Paul 		bzero((char *)&sc->bge_ldata.bge_tx_ring[i],
120495d67482SBill Paul 		    sizeof(struct bge_tx_bd));
120595d67482SBill Paul 	}
120695d67482SBill Paul }
120795d67482SBill Paul 
120895d67482SBill Paul static int
12093f74909aSGleb Smirnoff bge_init_tx_ring(struct bge_softc *sc)
121095d67482SBill Paul {
121195d67482SBill Paul 	sc->bge_txcnt = 0;
121295d67482SBill Paul 	sc->bge_tx_saved_considx = 0;
12133927098fSPaul Saab 
1214e6bf277eSPyun YongHyeon 	bzero(sc->bge_ldata.bge_tx_ring, BGE_TX_RING_SZ);
1215e6bf277eSPyun YongHyeon 	bus_dmamap_sync(sc->bge_cdata.bge_tx_ring_tag,
12165c1da2faSPyun YongHyeon 	    sc->bge_cdata.bge_tx_ring_map, BUS_DMASYNC_PREWRITE);
1217e6bf277eSPyun YongHyeon 
121814bbd30fSGleb Smirnoff 	/* Initialize transmit producer index for host-memory send ring. */
121914bbd30fSGleb Smirnoff 	sc->bge_tx_prodidx = 0;
122038cc658fSJohn Baldwin 	bge_writembx(sc, BGE_MBX_TX_HOST_PROD0_LO, sc->bge_tx_prodidx);
122114bbd30fSGleb Smirnoff 
12223927098fSPaul Saab 	/* 5700 b2 errata */
1223e0ced696SPaul Saab 	if (sc->bge_chiprev == BGE_CHIPREV_5700_BX)
122438cc658fSJohn Baldwin 		bge_writembx(sc, BGE_MBX_TX_HOST_PROD0_LO, sc->bge_tx_prodidx);
12253927098fSPaul Saab 
122614bbd30fSGleb Smirnoff 	/* NIC-memory send ring not used; initialize to zero. */
122738cc658fSJohn Baldwin 	bge_writembx(sc, BGE_MBX_TX_NIC_PROD0_LO, 0);
12283927098fSPaul Saab 	/* 5700 b2 errata */
1229e0ced696SPaul Saab 	if (sc->bge_chiprev == BGE_CHIPREV_5700_BX)
123038cc658fSJohn Baldwin 		bge_writembx(sc, BGE_MBX_TX_NIC_PROD0_LO, 0);
123195d67482SBill Paul 
123295d67482SBill Paul 	return (0);
123395d67482SBill Paul }
123495d67482SBill Paul 
123595d67482SBill Paul static void
12363e9b1bcaSJung-uk Kim bge_setpromisc(struct bge_softc *sc)
12373e9b1bcaSJung-uk Kim {
12383e9b1bcaSJung-uk Kim 	struct ifnet *ifp;
12393e9b1bcaSJung-uk Kim 
12403e9b1bcaSJung-uk Kim 	BGE_LOCK_ASSERT(sc);
12413e9b1bcaSJung-uk Kim 
12423e9b1bcaSJung-uk Kim 	ifp = sc->bge_ifp;
12433e9b1bcaSJung-uk Kim 
124445ee6ab3SJung-uk Kim 	/* Enable or disable promiscuous mode as needed. */
12453e9b1bcaSJung-uk Kim 	if (ifp->if_flags & IFF_PROMISC)
124645ee6ab3SJung-uk Kim 		BGE_SETBIT(sc, BGE_RX_MODE, BGE_RXMODE_RX_PROMISC);
12473e9b1bcaSJung-uk Kim 	else
124845ee6ab3SJung-uk Kim 		BGE_CLRBIT(sc, BGE_RX_MODE, BGE_RXMODE_RX_PROMISC);
12493e9b1bcaSJung-uk Kim }
12503e9b1bcaSJung-uk Kim 
12513e9b1bcaSJung-uk Kim static void
12523f74909aSGleb Smirnoff bge_setmulti(struct bge_softc *sc)
125395d67482SBill Paul {
125495d67482SBill Paul 	struct ifnet *ifp;
125595d67482SBill Paul 	struct ifmultiaddr *ifma;
12563f74909aSGleb Smirnoff 	uint32_t hashes[4] = { 0, 0, 0, 0 };
125795d67482SBill Paul 	int h, i;
125895d67482SBill Paul 
12590f9bd73bSSam Leffler 	BGE_LOCK_ASSERT(sc);
12600f9bd73bSSam Leffler 
1261fc74a9f9SBrooks Davis 	ifp = sc->bge_ifp;
126295d67482SBill Paul 
126395d67482SBill Paul 	if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) {
126495d67482SBill Paul 		for (i = 0; i < 4; i++)
12650c8aa4eaSJung-uk Kim 			CSR_WRITE_4(sc, BGE_MAR0 + (i * 4), 0xFFFFFFFF);
126695d67482SBill Paul 		return;
126795d67482SBill Paul 	}
126895d67482SBill Paul 
126995d67482SBill Paul 	/* First, zot all the existing filters. */
127095d67482SBill Paul 	for (i = 0; i < 4; i++)
127195d67482SBill Paul 		CSR_WRITE_4(sc, BGE_MAR0 + (i * 4), 0);
127295d67482SBill Paul 
127395d67482SBill Paul 	/* Now program new ones. */
1274eb956cd0SRobert Watson 	if_maddr_rlock(ifp);
127595d67482SBill Paul 	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
127695d67482SBill Paul 		if (ifma->ifma_addr->sa_family != AF_LINK)
127795d67482SBill Paul 			continue;
12780e939c0cSChristian Weisgerber 		h = ether_crc32_le(LLADDR((struct sockaddr_dl *)
12790c8aa4eaSJung-uk Kim 		    ifma->ifma_addr), ETHER_ADDR_LEN) & 0x7F;
12800c8aa4eaSJung-uk Kim 		hashes[(h & 0x60) >> 5] |= 1 << (h & 0x1F);
128195d67482SBill Paul 	}
1282eb956cd0SRobert Watson 	if_maddr_runlock(ifp);
128395d67482SBill Paul 
128495d67482SBill Paul 	for (i = 0; i < 4; i++)
128595d67482SBill Paul 		CSR_WRITE_4(sc, BGE_MAR0 + (i * 4), hashes[i]);
128695d67482SBill Paul }
128795d67482SBill Paul 
12888cb1383cSDoug Ambrisko static void
1289cb2eacc7SYaroslav Tykhiy bge_setvlan(struct bge_softc *sc)
1290cb2eacc7SYaroslav Tykhiy {
1291cb2eacc7SYaroslav Tykhiy 	struct ifnet *ifp;
1292cb2eacc7SYaroslav Tykhiy 
1293cb2eacc7SYaroslav Tykhiy 	BGE_LOCK_ASSERT(sc);
1294cb2eacc7SYaroslav Tykhiy 
1295cb2eacc7SYaroslav Tykhiy 	ifp = sc->bge_ifp;
1296cb2eacc7SYaroslav Tykhiy 
1297cb2eacc7SYaroslav Tykhiy 	/* Enable or disable VLAN tag stripping as needed. */
1298cb2eacc7SYaroslav Tykhiy 	if (ifp->if_capenable & IFCAP_VLAN_HWTAGGING)
1299cb2eacc7SYaroslav Tykhiy 		BGE_CLRBIT(sc, BGE_RX_MODE, BGE_RXMODE_RX_KEEP_VLAN_DIAG);
1300cb2eacc7SYaroslav Tykhiy 	else
1301cb2eacc7SYaroslav Tykhiy 		BGE_SETBIT(sc, BGE_RX_MODE, BGE_RXMODE_RX_KEEP_VLAN_DIAG);
1302cb2eacc7SYaroslav Tykhiy }
1303cb2eacc7SYaroslav Tykhiy 
1304cb2eacc7SYaroslav Tykhiy static void
1305797ab05eSPyun YongHyeon bge_sig_pre_reset(struct bge_softc *sc, int type)
13068cb1383cSDoug Ambrisko {
1307797ab05eSPyun YongHyeon 
13088cb1383cSDoug Ambrisko 	/*
13098cb1383cSDoug Ambrisko 	 * Some chips don't like this so only do this if ASF is enabled
13108cb1383cSDoug Ambrisko 	 */
13118cb1383cSDoug Ambrisko 	if (sc->bge_asf_mode)
1312888b47f0SPyun YongHyeon 		bge_writemem_ind(sc, BGE_SRAM_FW_MB, BGE_SRAM_FW_MB_MAGIC);
13138cb1383cSDoug Ambrisko 
13148cb1383cSDoug Ambrisko 	if (sc->bge_asf_mode & ASF_NEW_HANDSHAKE) {
13158cb1383cSDoug Ambrisko 		switch (type) {
13168cb1383cSDoug Ambrisko 		case BGE_RESET_START:
13178cb1383cSDoug Ambrisko 			bge_writemem_ind(sc, BGE_SDI_STATUS, 0x1); /* START */
13188cb1383cSDoug Ambrisko 			break;
13198cb1383cSDoug Ambrisko 		case BGE_RESET_STOP:
13208cb1383cSDoug Ambrisko 			bge_writemem_ind(sc, BGE_SDI_STATUS, 0x2); /* UNLOAD */
13218cb1383cSDoug Ambrisko 			break;
13228cb1383cSDoug Ambrisko 		}
13238cb1383cSDoug Ambrisko 	}
13248cb1383cSDoug Ambrisko }
13258cb1383cSDoug Ambrisko 
13268cb1383cSDoug Ambrisko static void
1327797ab05eSPyun YongHyeon bge_sig_post_reset(struct bge_softc *sc, int type)
13288cb1383cSDoug Ambrisko {
1329797ab05eSPyun YongHyeon 
13308cb1383cSDoug Ambrisko 	if (sc->bge_asf_mode & ASF_NEW_HANDSHAKE) {
13318cb1383cSDoug Ambrisko 		switch (type) {
13328cb1383cSDoug Ambrisko 		case BGE_RESET_START:
13338cb1383cSDoug Ambrisko 			bge_writemem_ind(sc, BGE_SDI_STATUS, 0x80000001);
13348cb1383cSDoug Ambrisko 			/* START DONE */
13358cb1383cSDoug Ambrisko 			break;
13368cb1383cSDoug Ambrisko 		case BGE_RESET_STOP:
13378cb1383cSDoug Ambrisko 			bge_writemem_ind(sc, BGE_SDI_STATUS, 0x80000002);
13388cb1383cSDoug Ambrisko 			break;
13398cb1383cSDoug Ambrisko 		}
13408cb1383cSDoug Ambrisko 	}
13418cb1383cSDoug Ambrisko }
13428cb1383cSDoug Ambrisko 
13438cb1383cSDoug Ambrisko static void
1344797ab05eSPyun YongHyeon bge_sig_legacy(struct bge_softc *sc, int type)
13458cb1383cSDoug Ambrisko {
1346797ab05eSPyun YongHyeon 
13478cb1383cSDoug Ambrisko 	if (sc->bge_asf_mode) {
13488cb1383cSDoug Ambrisko 		switch (type) {
13498cb1383cSDoug Ambrisko 		case BGE_RESET_START:
13508cb1383cSDoug Ambrisko 			bge_writemem_ind(sc, BGE_SDI_STATUS, 0x1); /* START */
13518cb1383cSDoug Ambrisko 			break;
13528cb1383cSDoug Ambrisko 		case BGE_RESET_STOP:
13538cb1383cSDoug Ambrisko 			bge_writemem_ind(sc, BGE_SDI_STATUS, 0x2); /* UNLOAD */
13548cb1383cSDoug Ambrisko 			break;
13558cb1383cSDoug Ambrisko 		}
13568cb1383cSDoug Ambrisko 	}
13578cb1383cSDoug Ambrisko }
13588cb1383cSDoug Ambrisko 
1359797ab05eSPyun YongHyeon static void
1360797ab05eSPyun YongHyeon bge_stop_fw(struct bge_softc *sc)
13618cb1383cSDoug Ambrisko {
13628cb1383cSDoug Ambrisko 	int i;
13638cb1383cSDoug Ambrisko 
13648cb1383cSDoug Ambrisko 	if (sc->bge_asf_mode) {
1365888b47f0SPyun YongHyeon 		bge_writemem_ind(sc, BGE_SRAM_FW_CMD_MB, BGE_FW_PAUSE);
1366*3fed2d5dSPyun YongHyeon 		CSR_WRITE_4(sc, BGE_RX_CPU_EVENT,
1367*3fed2d5dSPyun YongHyeon 		    CSR_READ_4(sc, BGE_RX_CPU_EVENT) | (1 << 14));
13688cb1383cSDoug Ambrisko 
13698cb1383cSDoug Ambrisko 		for (i = 0; i < 100; i++ ) {
1370*3fed2d5dSPyun YongHyeon 			if (!(CSR_READ_4(sc, BGE_RX_CPU_EVENT) & (1 << 14)))
13718cb1383cSDoug Ambrisko 				break;
13728cb1383cSDoug Ambrisko 			DELAY(10);
13738cb1383cSDoug Ambrisko 		}
13748cb1383cSDoug Ambrisko 	}
13758cb1383cSDoug Ambrisko }
13768cb1383cSDoug Ambrisko 
137795d67482SBill Paul /*
1378c9ffd9f0SMarius Strobl  * Do endian, PCI and DMA initialization.
137995d67482SBill Paul  */
138095d67482SBill Paul static int
13813f74909aSGleb Smirnoff bge_chipinit(struct bge_softc *sc)
138295d67482SBill Paul {
13831108273aSPyun YongHyeon 	uint32_t dma_rw_ctl, misc_ctl;
1384fbc374afSPyun YongHyeon 	uint16_t val;
138595d67482SBill Paul 	int i;
138695d67482SBill Paul 
13878cb1383cSDoug Ambrisko 	/* Set endianness before we access any non-PCI registers. */
13881108273aSPyun YongHyeon 	misc_ctl = BGE_INIT;
13891108273aSPyun YongHyeon 	if (sc->bge_flags & BGE_FLAG_TAGGED_STATUS)
13901108273aSPyun YongHyeon 		misc_ctl |= BGE_PCIMISCCTL_TAGGED_STATUS;
13911108273aSPyun YongHyeon 	pci_write_config(sc->bge_dev, BGE_PCI_MISC_CTL, misc_ctl, 4);
139295d67482SBill Paul 
139395d67482SBill Paul 	/* Clear the MAC control register */
139495d67482SBill Paul 	CSR_WRITE_4(sc, BGE_MAC_MODE, 0);
139595d67482SBill Paul 
139695d67482SBill Paul 	/*
139795d67482SBill Paul 	 * Clear the MAC statistics block in the NIC's
139895d67482SBill Paul 	 * internal memory.
139995d67482SBill Paul 	 */
140095d67482SBill Paul 	for (i = BGE_STATS_BLOCK;
14013f74909aSGleb Smirnoff 	    i < BGE_STATS_BLOCK_END + 1; i += sizeof(uint32_t))
140295d67482SBill Paul 		BGE_MEMWIN_WRITE(sc, i, 0);
140395d67482SBill Paul 
140495d67482SBill Paul 	for (i = BGE_STATUS_BLOCK;
14053f74909aSGleb Smirnoff 	    i < BGE_STATUS_BLOCK_END + 1; i += sizeof(uint32_t))
140695d67482SBill Paul 		BGE_MEMWIN_WRITE(sc, i, 0);
140795d67482SBill Paul 
1408fbc374afSPyun YongHyeon 	if (sc->bge_chiprev == BGE_CHIPREV_5704_BX) {
1409fbc374afSPyun YongHyeon 		/*
1410d896b3feSPyun YongHyeon 		 *  Fix data corruption caused by non-qword write with WB.
1411fbc374afSPyun YongHyeon 		 *  Fix master abort in PCI mode.
1412fbc374afSPyun YongHyeon 		 *  Fix PCI latency timer.
1413fbc374afSPyun YongHyeon 		 */
1414fbc374afSPyun YongHyeon 		val = pci_read_config(sc->bge_dev, BGE_PCI_MSI_DATA + 2, 2);
1415fbc374afSPyun YongHyeon 		val |= (1 << 10) | (1 << 12) | (1 << 13);
1416fbc374afSPyun YongHyeon 		pci_write_config(sc->bge_dev, BGE_PCI_MSI_DATA + 2, val, 2);
1417fbc374afSPyun YongHyeon 	}
1418fbc374afSPyun YongHyeon 
1419186f842bSJung-uk Kim 	/*
1420186f842bSJung-uk Kim 	 * Set up the PCI DMA control register.
1421186f842bSJung-uk Kim 	 */
1422186f842bSJung-uk Kim 	dma_rw_ctl = BGE_PCIDMARWCTL_RD_CMD_SHIFT(6) |
1423186f842bSJung-uk Kim 	    BGE_PCIDMARWCTL_WR_CMD_SHIFT(7);
1424652ae483SGleb Smirnoff 	if (sc->bge_flags & BGE_FLAG_PCIE) {
1425186f842bSJung-uk Kim 		/* Read watermark not used, 128 bytes for write. */
1426186f842bSJung-uk Kim 		dma_rw_ctl |= BGE_PCIDMARWCTL_WR_WAT_SHIFT(3);
1427652ae483SGleb Smirnoff 	} else if (sc->bge_flags & BGE_FLAG_PCIX) {
14284c0da0ffSGleb Smirnoff 		if (BGE_IS_5714_FAMILY(sc)) {
1429186f842bSJung-uk Kim 			/* 256 bytes for read and write. */
1430186f842bSJung-uk Kim 			dma_rw_ctl |= BGE_PCIDMARWCTL_RD_WAT_SHIFT(2) |
1431186f842bSJung-uk Kim 			    BGE_PCIDMARWCTL_WR_WAT_SHIFT(2);
1432186f842bSJung-uk Kim 			dma_rw_ctl |= (sc->bge_asicrev == BGE_ASICREV_BCM5780) ?
1433186f842bSJung-uk Kim 			    BGE_PCIDMARWCTL_ONEDMA_ATONCE_GLOBAL :
1434186f842bSJung-uk Kim 			    BGE_PCIDMARWCTL_ONEDMA_ATONCE_LOCAL;
1435cbb2b2feSPyun YongHyeon 		} else if (sc->bge_asicrev == BGE_ASICREV_BCM5703) {
1436cbb2b2feSPyun YongHyeon 			/*
1437cbb2b2feSPyun YongHyeon 			 * In the BCM5703, the DMA read watermark should
1438cbb2b2feSPyun YongHyeon 			 * be set to less than or equal to the maximum
1439cbb2b2feSPyun YongHyeon 			 * memory read byte count of the PCI-X command
1440cbb2b2feSPyun YongHyeon 			 * register.
1441cbb2b2feSPyun YongHyeon 			 */
1442cbb2b2feSPyun YongHyeon 			dma_rw_ctl |= BGE_PCIDMARWCTL_RD_WAT_SHIFT(4) |
1443cbb2b2feSPyun YongHyeon 			    BGE_PCIDMARWCTL_WR_WAT_SHIFT(3);
1444186f842bSJung-uk Kim 		} else if (sc->bge_asicrev == BGE_ASICREV_BCM5704) {
1445186f842bSJung-uk Kim 			/* 1536 bytes for read, 384 bytes for write. */
1446186f842bSJung-uk Kim 			dma_rw_ctl |= BGE_PCIDMARWCTL_RD_WAT_SHIFT(7) |
1447186f842bSJung-uk Kim 			    BGE_PCIDMARWCTL_WR_WAT_SHIFT(3);
1448186f842bSJung-uk Kim 		} else {
1449186f842bSJung-uk Kim 			/* 384 bytes for read and write. */
1450186f842bSJung-uk Kim 			dma_rw_ctl |= BGE_PCIDMARWCTL_RD_WAT_SHIFT(3) |
1451186f842bSJung-uk Kim 			    BGE_PCIDMARWCTL_WR_WAT_SHIFT(3) |
14520c8aa4eaSJung-uk Kim 			    0x0F;
1453186f842bSJung-uk Kim 		}
1454e0ced696SPaul Saab 		if (sc->bge_asicrev == BGE_ASICREV_BCM5703 ||
1455e0ced696SPaul Saab 		    sc->bge_asicrev == BGE_ASICREV_BCM5704) {
14563f74909aSGleb Smirnoff 			uint32_t tmp;
14575cba12d3SPaul Saab 
1458186f842bSJung-uk Kim 			/* Set ONE_DMA_AT_ONCE for hardware workaround. */
14590c8aa4eaSJung-uk Kim 			tmp = CSR_READ_4(sc, BGE_PCI_CLKCTL) & 0x1F;
1460186f842bSJung-uk Kim 			if (tmp == 6 || tmp == 7)
1461186f842bSJung-uk Kim 				dma_rw_ctl |=
1462186f842bSJung-uk Kim 				    BGE_PCIDMARWCTL_ONEDMA_ATONCE_GLOBAL;
14635cba12d3SPaul Saab 
1464186f842bSJung-uk Kim 			/* Set PCI-X DMA write workaround. */
1465186f842bSJung-uk Kim 			dma_rw_ctl |= BGE_PCIDMARWCTL_ASRT_ALL_BE;
1466186f842bSJung-uk Kim 		}
1467186f842bSJung-uk Kim 	} else {
1468186f842bSJung-uk Kim 		/* Conventional PCI bus: 256 bytes for read and write. */
1469186f842bSJung-uk Kim 		dma_rw_ctl |= BGE_PCIDMARWCTL_RD_WAT_SHIFT(7) |
1470186f842bSJung-uk Kim 		    BGE_PCIDMARWCTL_WR_WAT_SHIFT(7);
1471186f842bSJung-uk Kim 
1472186f842bSJung-uk Kim 		if (sc->bge_asicrev != BGE_ASICREV_BCM5705 &&
1473186f842bSJung-uk Kim 		    sc->bge_asicrev != BGE_ASICREV_BCM5750)
1474186f842bSJung-uk Kim 			dma_rw_ctl |= 0x0F;
1475186f842bSJung-uk Kim 	}
1476186f842bSJung-uk Kim 	if (sc->bge_asicrev == BGE_ASICREV_BCM5700 ||
1477186f842bSJung-uk Kim 	    sc->bge_asicrev == BGE_ASICREV_BCM5701)
1478186f842bSJung-uk Kim 		dma_rw_ctl |= BGE_PCIDMARWCTL_USE_MRM |
1479186f842bSJung-uk Kim 		    BGE_PCIDMARWCTL_ASRT_ALL_BE;
1480e0ced696SPaul Saab 	if (sc->bge_asicrev == BGE_ASICREV_BCM5703 ||
1481186f842bSJung-uk Kim 	    sc->bge_asicrev == BGE_ASICREV_BCM5704)
14825cba12d3SPaul Saab 		dma_rw_ctl &= ~BGE_PCIDMARWCTL_MINDMA;
1483b4a256acSPyun YongHyeon 	if (BGE_IS_5717_PLUS(sc)) {
14841108273aSPyun YongHyeon 		dma_rw_ctl &= ~BGE_PCIDMARWCTL_DIS_CACHE_ALIGNMENT;
1485b4a256acSPyun YongHyeon 		if (sc->bge_chipid == BGE_CHIPID_BCM57765_A0)
1486b4a256acSPyun YongHyeon 			dma_rw_ctl &= ~BGE_PCIDMARWCTL_CRDRDR_RDMA_MRRS_MSK;
1487bbe2ca75SPyun YongHyeon 		/*
1488bbe2ca75SPyun YongHyeon 		 * Enable HW workaround for controllers that misinterpret
1489bbe2ca75SPyun YongHyeon 		 * a status tag update and leave interrupts permanently
1490bbe2ca75SPyun YongHyeon 		 * disabled.
1491bbe2ca75SPyun YongHyeon 		 */
1492bbe2ca75SPyun YongHyeon 		if (sc->bge_asicrev != BGE_ASICREV_BCM5717 &&
1493bbe2ca75SPyun YongHyeon 		    sc->bge_asicrev != BGE_ASICREV_BCM57765)
1494bbe2ca75SPyun YongHyeon 			dma_rw_ctl |= BGE_PCIDMARWCTL_TAGGED_STATUS_WA;
1495b4a256acSPyun YongHyeon 	}
14965cba12d3SPaul Saab 	pci_write_config(sc->bge_dev, BGE_PCI_DMA_RW_CTL, dma_rw_ctl, 4);
149795d67482SBill Paul 
149895d67482SBill Paul 	/*
149995d67482SBill Paul 	 * Set up general mode register.
150095d67482SBill Paul 	 */
1501e907febfSPyun YongHyeon 	CSR_WRITE_4(sc, BGE_MODE_CTL, BGE_DMA_SWAP_OPTIONS |
150295d67482SBill Paul 	    BGE_MODECTL_MAC_ATTN_INTR | BGE_MODECTL_HOST_SEND_BDS |
1503ee7ef91cSOleg Bulyzhin 	    BGE_MODECTL_TX_NO_PHDR_CSUM);
150495d67482SBill Paul 
150595d67482SBill Paul 	/*
150690447aadSMarius Strobl 	 * BCM5701 B5 have a bug causing data corruption when using
150790447aadSMarius Strobl 	 * 64-bit DMA reads, which can be terminated early and then
150890447aadSMarius Strobl 	 * completed later as 32-bit accesses, in combination with
150990447aadSMarius Strobl 	 * certain bridges.
151090447aadSMarius Strobl 	 */
151190447aadSMarius Strobl 	if (sc->bge_asicrev == BGE_ASICREV_BCM5701 &&
151290447aadSMarius Strobl 	    sc->bge_chipid == BGE_CHIPID_BCM5701_B5)
151390447aadSMarius Strobl 		BGE_SETBIT(sc, BGE_MODE_CTL, BGE_MODECTL_FORCE_PCI32);
151490447aadSMarius Strobl 
151590447aadSMarius Strobl 	/*
15168cb1383cSDoug Ambrisko 	 * Tell the firmware the driver is running
15178cb1383cSDoug Ambrisko 	 */
15188cb1383cSDoug Ambrisko 	if (sc->bge_asf_mode & ASF_STACKUP)
15198cb1383cSDoug Ambrisko 		BGE_SETBIT(sc, BGE_MODE_CTL, BGE_MODECTL_STACKUP);
15208cb1383cSDoug Ambrisko 
15218cb1383cSDoug Ambrisko 	/*
1522ea13bdd5SJohn Polstra 	 * Disable memory write invalidate.  Apparently it is not supported
1523c9ffd9f0SMarius Strobl 	 * properly by these devices.  Also ensure that INTx isn't disabled,
1524c9ffd9f0SMarius Strobl 	 * as these chips need it even when using MSI.
152595d67482SBill Paul 	 */
1526c9ffd9f0SMarius Strobl 	PCI_CLRBIT(sc->bge_dev, BGE_PCI_CMD,
1527c9ffd9f0SMarius Strobl 	    PCIM_CMD_INTxDIS | PCIM_CMD_MWIEN, 4);
152895d67482SBill Paul 
152995d67482SBill Paul 	/* Set the timer prescaler (always 66Mhz) */
15300c8aa4eaSJung-uk Kim 	CSR_WRITE_4(sc, BGE_MISC_CFG, BGE_32BITTIME_66MHZ);
153195d67482SBill Paul 
153238cc658fSJohn Baldwin 	/* XXX: The Linux tg3 driver does this at the start of brgphy_reset. */
153338cc658fSJohn Baldwin 	if (sc->bge_asicrev == BGE_ASICREV_BCM5906) {
153438cc658fSJohn Baldwin 		DELAY(40);	/* XXX */
153538cc658fSJohn Baldwin 
153638cc658fSJohn Baldwin 		/* Put PHY into ready state */
153738cc658fSJohn Baldwin 		BGE_CLRBIT(sc, BGE_MISC_CFG, BGE_MISCCFG_EPHY_IDDQ);
153838cc658fSJohn Baldwin 		CSR_READ_4(sc, BGE_MISC_CFG); /* Flush */
153938cc658fSJohn Baldwin 		DELAY(40);
154038cc658fSJohn Baldwin 	}
154138cc658fSJohn Baldwin 
154295d67482SBill Paul 	return (0);
154395d67482SBill Paul }
154495d67482SBill Paul 
154595d67482SBill Paul static int
15463f74909aSGleb Smirnoff bge_blockinit(struct bge_softc *sc)
154795d67482SBill Paul {
154895d67482SBill Paul 	struct bge_rcb *rcb;
1549e907febfSPyun YongHyeon 	bus_size_t vrcb;
1550e907febfSPyun YongHyeon 	bge_hostaddr taddr;
1551bbe2ca75SPyun YongHyeon 	uint32_t dmactl, val;
15528a315a6dSPyun YongHyeon 	int i, limit;
155395d67482SBill Paul 
155495d67482SBill Paul 	/*
155595d67482SBill Paul 	 * Initialize the memory window pointer register so that
155695d67482SBill Paul 	 * we can access the first 32K of internal NIC RAM. This will
155795d67482SBill Paul 	 * allow us to set up the TX send ring RCBs and the RX return
155895d67482SBill Paul 	 * ring RCBs, plus other things which live in NIC memory.
155995d67482SBill Paul 	 */
156095d67482SBill Paul 	CSR_WRITE_4(sc, BGE_PCI_MEMWIN_BASEADDR, 0);
156195d67482SBill Paul 
1562822f63fcSBill Paul 	/* Note: the BCM5704 has a smaller mbuf space than other chips. */
1563822f63fcSBill Paul 
15647ee00338SJung-uk Kim 	if (!(BGE_IS_5705_PLUS(sc))) {
156595d67482SBill Paul 		/* Configure mbuf memory pool */
15660dae9719SJung-uk Kim 		CSR_WRITE_4(sc, BGE_BMAN_MBUFPOOL_BASEADDR, BGE_BUFFPOOL_1);
1567822f63fcSBill Paul 		if (sc->bge_asicrev == BGE_ASICREV_BCM5704)
1568822f63fcSBill Paul 			CSR_WRITE_4(sc, BGE_BMAN_MBUFPOOL_LEN, 0x10000);
1569822f63fcSBill Paul 		else
157095d67482SBill Paul 			CSR_WRITE_4(sc, BGE_BMAN_MBUFPOOL_LEN, 0x18000);
157195d67482SBill Paul 
157295d67482SBill Paul 		/* Configure DMA resource pool */
15730434d1b8SBill Paul 		CSR_WRITE_4(sc, BGE_BMAN_DMA_DESCPOOL_BASEADDR,
15740434d1b8SBill Paul 		    BGE_DMA_DESCRIPTORS);
157595d67482SBill Paul 		CSR_WRITE_4(sc, BGE_BMAN_DMA_DESCPOOL_LEN, 0x2000);
15760434d1b8SBill Paul 	}
157795d67482SBill Paul 
157895d67482SBill Paul 	/* Configure mbuf pool watermarks */
1579b4a256acSPyun YongHyeon 	if (sc->bge_asicrev == BGE_ASICREV_BCM5717 ||
1580b4a256acSPyun YongHyeon 	    sc->bge_asicrev == BGE_ASICREV_BCM57765) {
15811108273aSPyun YongHyeon 		CSR_WRITE_4(sc, BGE_BMAN_MBUFPOOL_READDMA_LOWAT, 0x0);
15821108273aSPyun YongHyeon 		if (sc->bge_ifp->if_mtu > ETHERMTU) {
15831108273aSPyun YongHyeon 			CSR_WRITE_4(sc, BGE_BMAN_MBUFPOOL_MACRX_LOWAT, 0x7e);
15841108273aSPyun YongHyeon 			CSR_WRITE_4(sc, BGE_BMAN_MBUFPOOL_HIWAT, 0xea);
15851108273aSPyun YongHyeon 		} else {
15861108273aSPyun YongHyeon 			CSR_WRITE_4(sc, BGE_BMAN_MBUFPOOL_MACRX_LOWAT, 0x2a);
15871108273aSPyun YongHyeon 			CSR_WRITE_4(sc, BGE_BMAN_MBUFPOOL_HIWAT, 0xa0);
15881108273aSPyun YongHyeon 		}
15891108273aSPyun YongHyeon 	} else if (!BGE_IS_5705_PLUS(sc)) {
1590fa228020SPaul Saab 		CSR_WRITE_4(sc, BGE_BMAN_MBUFPOOL_READDMA_LOWAT, 0x50);
1591fa228020SPaul Saab 		CSR_WRITE_4(sc, BGE_BMAN_MBUFPOOL_MACRX_LOWAT, 0x20);
1592fa228020SPaul Saab 		CSR_WRITE_4(sc, BGE_BMAN_MBUFPOOL_HIWAT, 0x60);
159338cc658fSJohn Baldwin 	} else if (sc->bge_asicrev == BGE_ASICREV_BCM5906) {
159438cc658fSJohn Baldwin 		CSR_WRITE_4(sc, BGE_BMAN_MBUFPOOL_READDMA_LOWAT, 0x0);
159538cc658fSJohn Baldwin 		CSR_WRITE_4(sc, BGE_BMAN_MBUFPOOL_MACRX_LOWAT, 0x04);
159638cc658fSJohn Baldwin 		CSR_WRITE_4(sc, BGE_BMAN_MBUFPOOL_HIWAT, 0x10);
159738cc658fSJohn Baldwin 	} else {
159838cc658fSJohn Baldwin 		CSR_WRITE_4(sc, BGE_BMAN_MBUFPOOL_READDMA_LOWAT, 0x0);
159938cc658fSJohn Baldwin 		CSR_WRITE_4(sc, BGE_BMAN_MBUFPOOL_MACRX_LOWAT, 0x10);
160038cc658fSJohn Baldwin 		CSR_WRITE_4(sc, BGE_BMAN_MBUFPOOL_HIWAT, 0x60);
160138cc658fSJohn Baldwin 	}
160295d67482SBill Paul 
160395d67482SBill Paul 	/* Configure DMA resource watermarks */
160495d67482SBill Paul 	CSR_WRITE_4(sc, BGE_BMAN_DMA_DESCPOOL_LOWAT, 5);
160595d67482SBill Paul 	CSR_WRITE_4(sc, BGE_BMAN_DMA_DESCPOOL_HIWAT, 10);
160695d67482SBill Paul 
160795d67482SBill Paul 	/* Enable buffer manager */
1608bbe2ca75SPyun YongHyeon 	val = BGE_BMANMODE_ENABLE | BGE_BMANMODE_LOMBUF_ATTN;
1609bbe2ca75SPyun YongHyeon 	/*
1610bbe2ca75SPyun YongHyeon 	 * Change the arbitration algorithm of TXMBUF read request to
1611bbe2ca75SPyun YongHyeon 	 * round-robin instead of priority based for BCM5719.  When
1612bbe2ca75SPyun YongHyeon 	 * TXFIFO is almost empty, RDMA will hold its request until
1613bbe2ca75SPyun YongHyeon 	 * TXFIFO is not almost empty.
1614bbe2ca75SPyun YongHyeon 	 */
1615bbe2ca75SPyun YongHyeon 	if (sc->bge_asicrev == BGE_ASICREV_BCM5719)
1616bbe2ca75SPyun YongHyeon 		val |= BGE_BMANMODE_NO_TX_UNDERRUN;
1617bbe2ca75SPyun YongHyeon 	CSR_WRITE_4(sc, BGE_BMAN_MODE, val);
161895d67482SBill Paul 
161995d67482SBill Paul 	/* Poll for buffer manager start indication */
162095d67482SBill Paul 	for (i = 0; i < BGE_TIMEOUT; i++) {
1621d5d23857SJung-uk Kim 		DELAY(10);
16220c8aa4eaSJung-uk Kim 		if (CSR_READ_4(sc, BGE_BMAN_MODE) & BGE_BMANMODE_ENABLE)
162395d67482SBill Paul 			break;
162495d67482SBill Paul 	}
162595d67482SBill Paul 
162695d67482SBill Paul 	if (i == BGE_TIMEOUT) {
16275a147ba6SPyun YongHyeon 		device_printf(sc->bge_dev, "buffer manager failed to start\n");
162895d67482SBill Paul 		return (ENXIO);
162995d67482SBill Paul 	}
163095d67482SBill Paul 
163195d67482SBill Paul 	/* Enable flow-through queues */
16320c8aa4eaSJung-uk Kim 	CSR_WRITE_4(sc, BGE_FTQ_RESET, 0xFFFFFFFF);
163395d67482SBill Paul 	CSR_WRITE_4(sc, BGE_FTQ_RESET, 0);
163495d67482SBill Paul 
163595d67482SBill Paul 	/* Wait until queue initialization is complete */
163695d67482SBill Paul 	for (i = 0; i < BGE_TIMEOUT; i++) {
1637d5d23857SJung-uk Kim 		DELAY(10);
163895d67482SBill Paul 		if (CSR_READ_4(sc, BGE_FTQ_RESET) == 0)
163995d67482SBill Paul 			break;
164095d67482SBill Paul 	}
164195d67482SBill Paul 
164295d67482SBill Paul 	if (i == BGE_TIMEOUT) {
1643fe806fdaSPyun YongHyeon 		device_printf(sc->bge_dev, "flow-through queue init failed\n");
164495d67482SBill Paul 		return (ENXIO);
164595d67482SBill Paul 	}
164695d67482SBill Paul 
16478a315a6dSPyun YongHyeon 	/*
16488a315a6dSPyun YongHyeon 	 * Summary of rings supported by the controller:
16498a315a6dSPyun YongHyeon 	 *
16508a315a6dSPyun YongHyeon 	 * Standard Receive Producer Ring
16518a315a6dSPyun YongHyeon 	 * - This ring is used to feed receive buffers for "standard"
16528a315a6dSPyun YongHyeon 	 *   sized frames (typically 1536 bytes) to the controller.
16538a315a6dSPyun YongHyeon 	 *
16548a315a6dSPyun YongHyeon 	 * Jumbo Receive Producer Ring
16558a315a6dSPyun YongHyeon 	 * - This ring is used to feed receive buffers for jumbo sized
16568a315a6dSPyun YongHyeon 	 *   frames (i.e. anything bigger than the "standard" frames)
16578a315a6dSPyun YongHyeon 	 *   to the controller.
16588a315a6dSPyun YongHyeon 	 *
16598a315a6dSPyun YongHyeon 	 * Mini Receive Producer Ring
16608a315a6dSPyun YongHyeon 	 * - This ring is used to feed receive buffers for "mini"
16618a315a6dSPyun YongHyeon 	 *   sized frames to the controller.
16628a315a6dSPyun YongHyeon 	 * - This feature required external memory for the controller
16638a315a6dSPyun YongHyeon 	 *   but was never used in a production system.  Should always
16648a315a6dSPyun YongHyeon 	 *   be disabled.
16658a315a6dSPyun YongHyeon 	 *
16668a315a6dSPyun YongHyeon 	 * Receive Return Ring
16678a315a6dSPyun YongHyeon 	 * - After the controller has placed an incoming frame into a
16688a315a6dSPyun YongHyeon 	 *   receive buffer that buffer is moved into a receive return
16698a315a6dSPyun YongHyeon 	 *   ring.  The driver is then responsible to passing the
16708a315a6dSPyun YongHyeon 	 *   buffer up to the stack.  Many versions of the controller
16718a315a6dSPyun YongHyeon 	 *   support multiple RR rings.
16728a315a6dSPyun YongHyeon 	 *
16738a315a6dSPyun YongHyeon 	 * Send Ring
16748a315a6dSPyun YongHyeon 	 * - This ring is used for outgoing frames.  Many versions of
16758a315a6dSPyun YongHyeon 	 *   the controller support multiple send rings.
16768a315a6dSPyun YongHyeon 	 */
16778a315a6dSPyun YongHyeon 
16788a315a6dSPyun YongHyeon 	/* Initialize the standard receive producer ring control block. */
1679f41ac2beSBill Paul 	rcb = &sc->bge_ldata.bge_info.bge_std_rx_rcb;
1680f41ac2beSBill Paul 	rcb->bge_hostaddr.bge_addr_lo =
1681f41ac2beSBill Paul 	    BGE_ADDR_LO(sc->bge_ldata.bge_rx_std_ring_paddr);
1682f41ac2beSBill Paul 	rcb->bge_hostaddr.bge_addr_hi =
1683f41ac2beSBill Paul 	    BGE_ADDR_HI(sc->bge_ldata.bge_rx_std_ring_paddr);
1684f41ac2beSBill Paul 	bus_dmamap_sync(sc->bge_cdata.bge_rx_std_ring_tag,
1685f41ac2beSBill Paul 	    sc->bge_cdata.bge_rx_std_ring_map, BUS_DMASYNC_PREREAD);
16861108273aSPyun YongHyeon 	if (BGE_IS_5717_PLUS(sc)) {
16871108273aSPyun YongHyeon 		/*
16881108273aSPyun YongHyeon 		 * Bits 31-16: Programmable ring size (2048, 1024, 512, .., 32)
16891108273aSPyun YongHyeon 		 * Bits 15-2 : Maximum RX frame size
16901108273aSPyun YongHyeon 		 * Bit 1     : 1 = Ring Disabled, 0 = Ring ENabled
16911108273aSPyun YongHyeon 		 * Bit 0     : Reserved
16921108273aSPyun YongHyeon 		 */
16931108273aSPyun YongHyeon 		rcb->bge_maxlen_flags =
16941108273aSPyun YongHyeon 		    BGE_RCB_MAXLEN_FLAGS(512, BGE_MAX_FRAMELEN << 2);
16951108273aSPyun YongHyeon 	} else if (BGE_IS_5705_PLUS(sc)) {
16968a315a6dSPyun YongHyeon 		/*
16978a315a6dSPyun YongHyeon 		 * Bits 31-16: Programmable ring size (512, 256, 128, 64, 32)
16988a315a6dSPyun YongHyeon 		 * Bits 15-2 : Reserved (should be 0)
16998a315a6dSPyun YongHyeon 		 * Bit 1     : 1 = Ring Disabled, 0 = Ring Enabled
17008a315a6dSPyun YongHyeon 		 * Bit 0     : Reserved
17018a315a6dSPyun YongHyeon 		 */
17020434d1b8SBill Paul 		rcb->bge_maxlen_flags = BGE_RCB_MAXLEN_FLAGS(512, 0);
17038a315a6dSPyun YongHyeon 	} else {
17048a315a6dSPyun YongHyeon 		/*
17058a315a6dSPyun YongHyeon 		 * Ring size is always XXX entries
17068a315a6dSPyun YongHyeon 		 * Bits 31-16: Maximum RX frame size
17078a315a6dSPyun YongHyeon 		 * Bits 15-2 : Reserved (should be 0)
17088a315a6dSPyun YongHyeon 		 * Bit 1     : 1 = Ring Disabled, 0 = Ring Enabled
17098a315a6dSPyun YongHyeon 		 * Bit 0     : Reserved
17108a315a6dSPyun YongHyeon 		 */
17110434d1b8SBill Paul 		rcb->bge_maxlen_flags =
17120434d1b8SBill Paul 		    BGE_RCB_MAXLEN_FLAGS(BGE_MAX_FRAMELEN, 0);
17138a315a6dSPyun YongHyeon 	}
1714bbe2ca75SPyun YongHyeon 	if (sc->bge_asicrev == BGE_ASICREV_BCM5717 ||
1715bbe2ca75SPyun YongHyeon 	    sc->bge_asicrev == BGE_ASICREV_BCM5719)
17161108273aSPyun YongHyeon 		rcb->bge_nicaddr = BGE_STD_RX_RINGS_5717;
17171108273aSPyun YongHyeon 	else
171895d67482SBill Paul 		rcb->bge_nicaddr = BGE_STD_RX_RINGS;
17198a315a6dSPyun YongHyeon 	/* Write the standard receive producer ring control block. */
17200c8aa4eaSJung-uk Kim 	CSR_WRITE_4(sc, BGE_RX_STD_RCB_HADDR_HI, rcb->bge_hostaddr.bge_addr_hi);
17210c8aa4eaSJung-uk Kim 	CSR_WRITE_4(sc, BGE_RX_STD_RCB_HADDR_LO, rcb->bge_hostaddr.bge_addr_lo);
172267111612SJohn Polstra 	CSR_WRITE_4(sc, BGE_RX_STD_RCB_MAXLEN_FLAGS, rcb->bge_maxlen_flags);
172367111612SJohn Polstra 	CSR_WRITE_4(sc, BGE_RX_STD_RCB_NICADDR, rcb->bge_nicaddr);
172495d67482SBill Paul 
17258a315a6dSPyun YongHyeon 	/* Reset the standard receive producer ring producer index. */
17268a315a6dSPyun YongHyeon 	bge_writembx(sc, BGE_MBX_RX_STD_PROD_LO, 0);
17278a315a6dSPyun YongHyeon 
172895d67482SBill Paul 	/*
17298a315a6dSPyun YongHyeon 	 * Initialize the jumbo RX producer ring control
17308a315a6dSPyun YongHyeon 	 * block.  We set the 'ring disabled' bit in the
17318a315a6dSPyun YongHyeon 	 * flags field until we're actually ready to start
173295d67482SBill Paul 	 * using this ring (i.e. once we set the MTU
173395d67482SBill Paul 	 * high enough to require it).
173495d67482SBill Paul 	 */
17354c0da0ffSGleb Smirnoff 	if (BGE_IS_JUMBO_CAPABLE(sc)) {
1736f41ac2beSBill Paul 		rcb = &sc->bge_ldata.bge_info.bge_jumbo_rx_rcb;
17378a315a6dSPyun YongHyeon 		/* Get the jumbo receive producer ring RCB parameters. */
1738f41ac2beSBill Paul 		rcb->bge_hostaddr.bge_addr_lo =
1739f41ac2beSBill Paul 		    BGE_ADDR_LO(sc->bge_ldata.bge_rx_jumbo_ring_paddr);
1740f41ac2beSBill Paul 		rcb->bge_hostaddr.bge_addr_hi =
1741f41ac2beSBill Paul 		    BGE_ADDR_HI(sc->bge_ldata.bge_rx_jumbo_ring_paddr);
1742f41ac2beSBill Paul 		bus_dmamap_sync(sc->bge_cdata.bge_rx_jumbo_ring_tag,
1743f41ac2beSBill Paul 		    sc->bge_cdata.bge_rx_jumbo_ring_map,
1744f41ac2beSBill Paul 		    BUS_DMASYNC_PREREAD);
17451be6acb7SGleb Smirnoff 		rcb->bge_maxlen_flags = BGE_RCB_MAXLEN_FLAGS(0,
17461be6acb7SGleb Smirnoff 		    BGE_RCB_FLAG_USE_EXT_RX_BD | BGE_RCB_FLAG_RING_DISABLED);
1747bbe2ca75SPyun YongHyeon 		if (sc->bge_asicrev == BGE_ASICREV_BCM5717 ||
1748bbe2ca75SPyun YongHyeon 		    sc->bge_asicrev == BGE_ASICREV_BCM5719)
17491108273aSPyun YongHyeon 			rcb->bge_nicaddr = BGE_JUMBO_RX_RINGS_5717;
17501108273aSPyun YongHyeon 		else
175195d67482SBill Paul 			rcb->bge_nicaddr = BGE_JUMBO_RX_RINGS;
175267111612SJohn Polstra 		CSR_WRITE_4(sc, BGE_RX_JUMBO_RCB_HADDR_HI,
175367111612SJohn Polstra 		    rcb->bge_hostaddr.bge_addr_hi);
175467111612SJohn Polstra 		CSR_WRITE_4(sc, BGE_RX_JUMBO_RCB_HADDR_LO,
175567111612SJohn Polstra 		    rcb->bge_hostaddr.bge_addr_lo);
17568a315a6dSPyun YongHyeon 		/* Program the jumbo receive producer ring RCB parameters. */
17570434d1b8SBill Paul 		CSR_WRITE_4(sc, BGE_RX_JUMBO_RCB_MAXLEN_FLAGS,
17580434d1b8SBill Paul 		    rcb->bge_maxlen_flags);
175967111612SJohn Polstra 		CSR_WRITE_4(sc, BGE_RX_JUMBO_RCB_NICADDR, rcb->bge_nicaddr);
17608a315a6dSPyun YongHyeon 		/* Reset the jumbo receive producer ring producer index. */
17618a315a6dSPyun YongHyeon 		bge_writembx(sc, BGE_MBX_RX_JUMBO_PROD_LO, 0);
17628a315a6dSPyun YongHyeon 	}
176395d67482SBill Paul 
17648a315a6dSPyun YongHyeon 	/* Disable the mini receive producer ring RCB. */
17655e2f96bfSPyun YongHyeon 	if (BGE_IS_5700_FAMILY(sc)) {
1766f41ac2beSBill Paul 		rcb = &sc->bge_ldata.bge_info.bge_mini_rx_rcb;
176767111612SJohn Polstra 		rcb->bge_maxlen_flags =
176867111612SJohn Polstra 		    BGE_RCB_MAXLEN_FLAGS(0, BGE_RCB_FLAG_RING_DISABLED);
17690434d1b8SBill Paul 		CSR_WRITE_4(sc, BGE_RX_MINI_RCB_MAXLEN_FLAGS,
17700434d1b8SBill Paul 		    rcb->bge_maxlen_flags);
17718a315a6dSPyun YongHyeon 		/* Reset the mini receive producer ring producer index. */
17728a315a6dSPyun YongHyeon 		bge_writembx(sc, BGE_MBX_RX_MINI_PROD_LO, 0);
17730434d1b8SBill Paul 	}
177495d67482SBill Paul 
1775ca4f8986SPyun YongHyeon 	/* Choose de-pipeline mode for BCM5906 A0, A1 and A2. */
1776ca4f8986SPyun YongHyeon 	if (sc->bge_asicrev == BGE_ASICREV_BCM5906) {
1777427d3f33SPyun YongHyeon 		if (sc->bge_chipid == BGE_CHIPID_BCM5906_A0 ||
1778427d3f33SPyun YongHyeon 		    sc->bge_chipid == BGE_CHIPID_BCM5906_A1 ||
1779427d3f33SPyun YongHyeon 		    sc->bge_chipid == BGE_CHIPID_BCM5906_A2)
17808d5f7181SPyun YongHyeon 			CSR_WRITE_4(sc, BGE_ISO_PKT_TX,
17818d5f7181SPyun YongHyeon 			    (CSR_READ_4(sc, BGE_ISO_PKT_TX) & ~3) | 2);
1782ca4f8986SPyun YongHyeon 	}
178395d67482SBill Paul 	/*
17848a315a6dSPyun YongHyeon 	 * The BD ring replenish thresholds control how often the
17858a315a6dSPyun YongHyeon 	 * hardware fetches new BD's from the producer rings in host
17868a315a6dSPyun YongHyeon 	 * memory.  Setting the value too low on a busy system can
17878a315a6dSPyun YongHyeon 	 * starve the hardware and recue the throughpout.
17888a315a6dSPyun YongHyeon 	 *
178995d67482SBill Paul 	 * Set the BD ring replentish thresholds. The recommended
179095d67482SBill Paul 	 * values are 1/8th the number of descriptors allocated to
179195d67482SBill Paul 	 * each ring.
17929ba784dbSScott Long 	 * XXX The 5754 requires a lower threshold, so it might be a
17939ba784dbSScott Long 	 * requirement of all 575x family chips.  The Linux driver sets
17949ba784dbSScott Long 	 * the lower threshold for all 5705 family chips as well, but there
17959ba784dbSScott Long 	 * are reports that it might not need to be so strict.
179638cc658fSJohn Baldwin 	 *
179738cc658fSJohn Baldwin 	 * XXX Linux does some extra fiddling here for the 5906 parts as
179838cc658fSJohn Baldwin 	 * well.
179995d67482SBill Paul 	 */
18005345bad0SScott Long 	if (BGE_IS_5705_PLUS(sc))
18016f8718a3SScott Long 		val = 8;
18026f8718a3SScott Long 	else
18036f8718a3SScott Long 		val = BGE_STD_RX_RING_CNT / 8;
18046f8718a3SScott Long 	CSR_WRITE_4(sc, BGE_RBDI_STD_REPL_THRESH, val);
18052a141b94SPyun YongHyeon 	if (BGE_IS_JUMBO_CAPABLE(sc))
18062a141b94SPyun YongHyeon 		CSR_WRITE_4(sc, BGE_RBDI_JUMBO_REPL_THRESH,
18072a141b94SPyun YongHyeon 		    BGE_JUMBO_RX_RING_CNT/8);
18081108273aSPyun YongHyeon 	if (BGE_IS_5717_PLUS(sc)) {
18091108273aSPyun YongHyeon 		CSR_WRITE_4(sc, BGE_STD_REPLENISH_LWM, 32);
18101108273aSPyun YongHyeon 		CSR_WRITE_4(sc, BGE_JMB_REPLENISH_LWM, 16);
18111108273aSPyun YongHyeon 	}
181295d67482SBill Paul 
181395d67482SBill Paul 	/*
18148a315a6dSPyun YongHyeon 	 * Disable all send rings by setting the 'ring disabled' bit
18158a315a6dSPyun YongHyeon 	 * in the flags field of all the TX send ring control blocks,
18168a315a6dSPyun YongHyeon 	 * located in NIC memory.
181795d67482SBill Paul 	 */
18188a315a6dSPyun YongHyeon 	if (!BGE_IS_5705_PLUS(sc))
18198a315a6dSPyun YongHyeon 		/* 5700 to 5704 had 16 send rings. */
18208a315a6dSPyun YongHyeon 		limit = BGE_TX_RINGS_EXTSSRAM_MAX;
18218a315a6dSPyun YongHyeon 	else
18228a315a6dSPyun YongHyeon 		limit = 1;
1823e907febfSPyun YongHyeon 	vrcb = BGE_MEMWIN_START + BGE_SEND_RING_RCB;
18248a315a6dSPyun YongHyeon 	for (i = 0; i < limit; i++) {
1825e907febfSPyun YongHyeon 		RCB_WRITE_4(sc, vrcb, bge_maxlen_flags,
1826e907febfSPyun YongHyeon 		    BGE_RCB_MAXLEN_FLAGS(0, BGE_RCB_FLAG_RING_DISABLED));
1827e907febfSPyun YongHyeon 		RCB_WRITE_4(sc, vrcb, bge_nicaddr, 0);
1828e907febfSPyun YongHyeon 		vrcb += sizeof(struct bge_rcb);
182995d67482SBill Paul 	}
183095d67482SBill Paul 
18318a315a6dSPyun YongHyeon 	/* Configure send ring RCB 0 (we use only the first ring) */
1832e907febfSPyun YongHyeon 	vrcb = BGE_MEMWIN_START + BGE_SEND_RING_RCB;
1833e907febfSPyun YongHyeon 	BGE_HOSTADDR(taddr, sc->bge_ldata.bge_tx_ring_paddr);
1834e907febfSPyun YongHyeon 	RCB_WRITE_4(sc, vrcb, bge_hostaddr.bge_addr_hi, taddr.bge_addr_hi);
1835e907febfSPyun YongHyeon 	RCB_WRITE_4(sc, vrcb, bge_hostaddr.bge_addr_lo, taddr.bge_addr_lo);
1836bbe2ca75SPyun YongHyeon 	if (sc->bge_asicrev == BGE_ASICREV_BCM5717 ||
1837bbe2ca75SPyun YongHyeon 	    sc->bge_asicrev == BGE_ASICREV_BCM5719)
18381108273aSPyun YongHyeon 		RCB_WRITE_4(sc, vrcb, bge_nicaddr, BGE_SEND_RING_5717);
18391108273aSPyun YongHyeon 	else
1840e907febfSPyun YongHyeon 		RCB_WRITE_4(sc, vrcb, bge_nicaddr,
1841e907febfSPyun YongHyeon 		    BGE_NIC_TXRING_ADDR(0, BGE_TX_RING_CNT));
1842e907febfSPyun YongHyeon 	RCB_WRITE_4(sc, vrcb, bge_maxlen_flags,
1843e907febfSPyun YongHyeon 	    BGE_RCB_MAXLEN_FLAGS(BGE_TX_RING_CNT, 0));
184495d67482SBill Paul 
18458a315a6dSPyun YongHyeon 	/*
18468a315a6dSPyun YongHyeon 	 * Disable all receive return rings by setting the
18478a315a6dSPyun YongHyeon 	 * 'ring diabled' bit in the flags field of all the receive
18488a315a6dSPyun YongHyeon 	 * return ring control blocks, located in NIC memory.
18498a315a6dSPyun YongHyeon 	 */
1850bbe2ca75SPyun YongHyeon 	if (sc->bge_asicrev == BGE_ASICREV_BCM5717 ||
1851bbe2ca75SPyun YongHyeon 	    sc->bge_asicrev == BGE_ASICREV_BCM5719) {
18521108273aSPyun YongHyeon 		/* Should be 17, use 16 until we get an SRAM map. */
18531108273aSPyun YongHyeon 		limit = 16;
18541108273aSPyun YongHyeon 	} else if (!BGE_IS_5705_PLUS(sc))
18558a315a6dSPyun YongHyeon 		limit = BGE_RX_RINGS_MAX;
1856b4a256acSPyun YongHyeon 	else if (sc->bge_asicrev == BGE_ASICREV_BCM5755 ||
1857b4a256acSPyun YongHyeon 	    sc->bge_asicrev == BGE_ASICREV_BCM57765)
18588a315a6dSPyun YongHyeon 		limit = 4;
18598a315a6dSPyun YongHyeon 	else
18608a315a6dSPyun YongHyeon 		limit = 1;
18618a315a6dSPyun YongHyeon 	/* Disable all receive return rings. */
1862e907febfSPyun YongHyeon 	vrcb = BGE_MEMWIN_START + BGE_RX_RETURN_RING_RCB;
18638a315a6dSPyun YongHyeon 	for (i = 0; i < limit; i++) {
1864e907febfSPyun YongHyeon 		RCB_WRITE_4(sc, vrcb, bge_hostaddr.bge_addr_hi, 0);
1865e907febfSPyun YongHyeon 		RCB_WRITE_4(sc, vrcb, bge_hostaddr.bge_addr_lo, 0);
1866e907febfSPyun YongHyeon 		RCB_WRITE_4(sc, vrcb, bge_maxlen_flags,
18678a315a6dSPyun YongHyeon 		    BGE_RCB_FLAG_RING_DISABLED);
1868e907febfSPyun YongHyeon 		RCB_WRITE_4(sc, vrcb, bge_nicaddr, 0);
186938cc658fSJohn Baldwin 		bge_writembx(sc, BGE_MBX_RX_CONS0_LO +
18703f74909aSGleb Smirnoff 		    (i * (sizeof(uint64_t))), 0);
1871e907febfSPyun YongHyeon 		vrcb += sizeof(struct bge_rcb);
187295d67482SBill Paul 	}
187395d67482SBill Paul 
187495d67482SBill Paul 	/*
18758a315a6dSPyun YongHyeon 	 * Set up receive return ring 0.  Note that the NIC address
18768a315a6dSPyun YongHyeon 	 * for RX return rings is 0x0.  The return rings live entirely
18778a315a6dSPyun YongHyeon 	 * within the host, so the nicaddr field in the RCB isn't used.
187895d67482SBill Paul 	 */
1879e907febfSPyun YongHyeon 	vrcb = BGE_MEMWIN_START + BGE_RX_RETURN_RING_RCB;
1880e907febfSPyun YongHyeon 	BGE_HOSTADDR(taddr, sc->bge_ldata.bge_rx_return_ring_paddr);
1881e907febfSPyun YongHyeon 	RCB_WRITE_4(sc, vrcb, bge_hostaddr.bge_addr_hi, taddr.bge_addr_hi);
1882e907febfSPyun YongHyeon 	RCB_WRITE_4(sc, vrcb, bge_hostaddr.bge_addr_lo, taddr.bge_addr_lo);
18838a315a6dSPyun YongHyeon 	RCB_WRITE_4(sc, vrcb, bge_nicaddr, 0);
1884e907febfSPyun YongHyeon 	RCB_WRITE_4(sc, vrcb, bge_maxlen_flags,
1885e907febfSPyun YongHyeon 	    BGE_RCB_MAXLEN_FLAGS(sc->bge_return_ring_cnt, 0));
188695d67482SBill Paul 
188795d67482SBill Paul 	/* Set random backoff seed for TX */
188895d67482SBill Paul 	CSR_WRITE_4(sc, BGE_TX_RANDOM_BACKOFF,
18894a0d6638SRuslan Ermilov 	    IF_LLADDR(sc->bge_ifp)[0] + IF_LLADDR(sc->bge_ifp)[1] +
18904a0d6638SRuslan Ermilov 	    IF_LLADDR(sc->bge_ifp)[2] + IF_LLADDR(sc->bge_ifp)[3] +
18914a0d6638SRuslan Ermilov 	    IF_LLADDR(sc->bge_ifp)[4] + IF_LLADDR(sc->bge_ifp)[5] +
189295d67482SBill Paul 	    BGE_TX_BACKOFF_SEED_MASK);
189395d67482SBill Paul 
189495d67482SBill Paul 	/* Set inter-packet gap */
189595d67482SBill Paul 	CSR_WRITE_4(sc, BGE_TX_LENGTHS, 0x2620);
189695d67482SBill Paul 
189795d67482SBill Paul 	/*
189895d67482SBill Paul 	 * Specify which ring to use for packets that don't match
189995d67482SBill Paul 	 * any RX rules.
190095d67482SBill Paul 	 */
190195d67482SBill Paul 	CSR_WRITE_4(sc, BGE_RX_RULES_CFG, 0x08);
190295d67482SBill Paul 
190395d67482SBill Paul 	/*
190495d67482SBill Paul 	 * Configure number of RX lists. One interrupt distribution
190595d67482SBill Paul 	 * list, sixteen active lists, one bad frames class.
190695d67482SBill Paul 	 */
190795d67482SBill Paul 	CSR_WRITE_4(sc, BGE_RXLP_CFG, 0x181);
190895d67482SBill Paul 
190995d67482SBill Paul 	/* Inialize RX list placement stats mask. */
19100c8aa4eaSJung-uk Kim 	CSR_WRITE_4(sc, BGE_RXLP_STATS_ENABLE_MASK, 0x007FFFFF);
191195d67482SBill Paul 	CSR_WRITE_4(sc, BGE_RXLP_STATS_CTL, 0x1);
191295d67482SBill Paul 
191395d67482SBill Paul 	/* Disable host coalescing until we get it set up */
191495d67482SBill Paul 	CSR_WRITE_4(sc, BGE_HCC_MODE, 0x00000000);
191595d67482SBill Paul 
191695d67482SBill Paul 	/* Poll to make sure it's shut down. */
191795d67482SBill Paul 	for (i = 0; i < BGE_TIMEOUT; i++) {
1918d5d23857SJung-uk Kim 		DELAY(10);
191995d67482SBill Paul 		if (!(CSR_READ_4(sc, BGE_HCC_MODE) & BGE_HCCMODE_ENABLE))
192095d67482SBill Paul 			break;
192195d67482SBill Paul 	}
192295d67482SBill Paul 
192395d67482SBill Paul 	if (i == BGE_TIMEOUT) {
1924fe806fdaSPyun YongHyeon 		device_printf(sc->bge_dev,
1925fe806fdaSPyun YongHyeon 		    "host coalescing engine failed to idle\n");
192695d67482SBill Paul 		return (ENXIO);
192795d67482SBill Paul 	}
192895d67482SBill Paul 
192995d67482SBill Paul 	/* Set up host coalescing defaults */
193095d67482SBill Paul 	CSR_WRITE_4(sc, BGE_HCC_RX_COAL_TICKS, sc->bge_rx_coal_ticks);
193195d67482SBill Paul 	CSR_WRITE_4(sc, BGE_HCC_TX_COAL_TICKS, sc->bge_tx_coal_ticks);
193295d67482SBill Paul 	CSR_WRITE_4(sc, BGE_HCC_RX_MAX_COAL_BDS, sc->bge_rx_max_coal_bds);
193395d67482SBill Paul 	CSR_WRITE_4(sc, BGE_HCC_TX_MAX_COAL_BDS, sc->bge_tx_max_coal_bds);
19347ee00338SJung-uk Kim 	if (!(BGE_IS_5705_PLUS(sc))) {
193595d67482SBill Paul 		CSR_WRITE_4(sc, BGE_HCC_RX_COAL_TICKS_INT, 0);
193695d67482SBill Paul 		CSR_WRITE_4(sc, BGE_HCC_TX_COAL_TICKS_INT, 0);
19370434d1b8SBill Paul 	}
1938b64728e5SBruce Evans 	CSR_WRITE_4(sc, BGE_HCC_RX_MAX_COAL_BDS_INT, 1);
1939b64728e5SBruce Evans 	CSR_WRITE_4(sc, BGE_HCC_TX_MAX_COAL_BDS_INT, 1);
194095d67482SBill Paul 
194195d67482SBill Paul 	/* Set up address of statistics block */
19427ee00338SJung-uk Kim 	if (!(BGE_IS_5705_PLUS(sc))) {
1943f41ac2beSBill Paul 		CSR_WRITE_4(sc, BGE_HCC_STATS_ADDR_HI,
1944f41ac2beSBill Paul 		    BGE_ADDR_HI(sc->bge_ldata.bge_stats_paddr));
194595d67482SBill Paul 		CSR_WRITE_4(sc, BGE_HCC_STATS_ADDR_LO,
1946f41ac2beSBill Paul 		    BGE_ADDR_LO(sc->bge_ldata.bge_stats_paddr));
19470434d1b8SBill Paul 		CSR_WRITE_4(sc, BGE_HCC_STATS_BASEADDR, BGE_STATS_BLOCK);
194895d67482SBill Paul 		CSR_WRITE_4(sc, BGE_HCC_STATUSBLK_BASEADDR, BGE_STATUS_BLOCK);
19490434d1b8SBill Paul 		CSR_WRITE_4(sc, BGE_HCC_STATS_TICKS, sc->bge_stat_ticks);
19500434d1b8SBill Paul 	}
19510434d1b8SBill Paul 
19520434d1b8SBill Paul 	/* Set up address of status block */
1953f41ac2beSBill Paul 	CSR_WRITE_4(sc, BGE_HCC_STATUSBLK_ADDR_HI,
1954f41ac2beSBill Paul 	    BGE_ADDR_HI(sc->bge_ldata.bge_status_block_paddr));
195595d67482SBill Paul 	CSR_WRITE_4(sc, BGE_HCC_STATUSBLK_ADDR_LO,
1956f41ac2beSBill Paul 	    BGE_ADDR_LO(sc->bge_ldata.bge_status_block_paddr));
195795d67482SBill Paul 
195830f57f61SPyun YongHyeon 	/* Set up status block size. */
195930f57f61SPyun YongHyeon 	if (sc->bge_asicrev == BGE_ASICREV_BCM5700 &&
1960864104feSPyun YongHyeon 	    sc->bge_chipid != BGE_CHIPID_BCM5700_C0) {
196130f57f61SPyun YongHyeon 		val = BGE_STATBLKSZ_FULL;
1962864104feSPyun YongHyeon 		bzero(sc->bge_ldata.bge_status_block, BGE_STATUS_BLK_SZ);
1963864104feSPyun YongHyeon 	} else {
196430f57f61SPyun YongHyeon 		val = BGE_STATBLKSZ_32BYTE;
1965864104feSPyun YongHyeon 		bzero(sc->bge_ldata.bge_status_block, 32);
1966864104feSPyun YongHyeon 	}
1967864104feSPyun YongHyeon 	bus_dmamap_sync(sc->bge_cdata.bge_status_tag,
1968864104feSPyun YongHyeon 	    sc->bge_cdata.bge_status_map,
1969864104feSPyun YongHyeon 	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
197030f57f61SPyun YongHyeon 
197195d67482SBill Paul 	/* Turn on host coalescing state machine */
197230f57f61SPyun YongHyeon 	CSR_WRITE_4(sc, BGE_HCC_MODE, val | BGE_HCCMODE_ENABLE);
197395d67482SBill Paul 
197495d67482SBill Paul 	/* Turn on RX BD completion state machine and enable attentions */
197595d67482SBill Paul 	CSR_WRITE_4(sc, BGE_RBDC_MODE,
197695d67482SBill Paul 	    BGE_RBDCMODE_ENABLE | BGE_RBDCMODE_ATTN);
197795d67482SBill Paul 
197895d67482SBill Paul 	/* Turn on RX list placement state machine */
197995d67482SBill Paul 	CSR_WRITE_4(sc, BGE_RXLP_MODE, BGE_RXLPMODE_ENABLE);
198095d67482SBill Paul 
198195d67482SBill Paul 	/* Turn on RX list selector state machine. */
19827ee00338SJung-uk Kim 	if (!(BGE_IS_5705_PLUS(sc)))
198395d67482SBill Paul 		CSR_WRITE_4(sc, BGE_RXLS_MODE, BGE_RXLSMODE_ENABLE);
198495d67482SBill Paul 
1985ea3b4127SPyun YongHyeon 	val = BGE_MACMODE_TXDMA_ENB | BGE_MACMODE_RXDMA_ENB |
1986ea3b4127SPyun YongHyeon 	    BGE_MACMODE_RX_STATS_CLEAR | BGE_MACMODE_TX_STATS_CLEAR |
1987ea3b4127SPyun YongHyeon 	    BGE_MACMODE_RX_STATS_ENB | BGE_MACMODE_TX_STATS_ENB |
1988ea3b4127SPyun YongHyeon 	    BGE_MACMODE_FRMHDR_DMA_ENB;
1989ea3b4127SPyun YongHyeon 
1990ea3b4127SPyun YongHyeon 	if (sc->bge_flags & BGE_FLAG_TBI)
1991ea3b4127SPyun YongHyeon 		val |= BGE_PORTMODE_TBI;
1992ea3b4127SPyun YongHyeon 	else if (sc->bge_flags & BGE_FLAG_MII_SERDES)
1993ea3b4127SPyun YongHyeon 		val |= BGE_PORTMODE_GMII;
1994ea3b4127SPyun YongHyeon 	else
1995ea3b4127SPyun YongHyeon 		val |= BGE_PORTMODE_MII;
1996ea3b4127SPyun YongHyeon 
199795d67482SBill Paul 	/* Turn on DMA, clear stats */
1998ea3b4127SPyun YongHyeon 	CSR_WRITE_4(sc, BGE_MAC_MODE, val);
199995d67482SBill Paul 
200095d67482SBill Paul 	/* Set misc. local control, enable interrupts on attentions */
200195d67482SBill Paul 	CSR_WRITE_4(sc, BGE_MISC_LOCAL_CTL, BGE_MLC_INTR_ONATTN);
200295d67482SBill Paul 
200395d67482SBill Paul #ifdef notdef
200495d67482SBill Paul 	/* Assert GPIO pins for PHY reset */
200595d67482SBill Paul 	BGE_SETBIT(sc, BGE_MISC_LOCAL_CTL, BGE_MLC_MISCIO_OUT0 |
200695d67482SBill Paul 	    BGE_MLC_MISCIO_OUT1 | BGE_MLC_MISCIO_OUT2);
200795d67482SBill Paul 	BGE_SETBIT(sc, BGE_MISC_LOCAL_CTL, BGE_MLC_MISCIO_OUTEN0 |
200895d67482SBill Paul 	    BGE_MLC_MISCIO_OUTEN1 | BGE_MLC_MISCIO_OUTEN2);
200995d67482SBill Paul #endif
201095d67482SBill Paul 
201195d67482SBill Paul 	/* Turn on DMA completion state machine */
20127ee00338SJung-uk Kim 	if (!(BGE_IS_5705_PLUS(sc)))
201395d67482SBill Paul 		CSR_WRITE_4(sc, BGE_DMAC_MODE, BGE_DMACMODE_ENABLE);
201495d67482SBill Paul 
20156f8718a3SScott Long 	val = BGE_WDMAMODE_ENABLE | BGE_WDMAMODE_ALL_ATTNS;
20166f8718a3SScott Long 
20176f8718a3SScott Long 	/* Enable host coalescing bug fix. */
2018a5779553SStanislav Sedov 	if (BGE_IS_5755_PLUS(sc))
20193889907fSStanislav Sedov 		val |= BGE_WDMAMODE_STATUS_TAG_FIX;
20206f8718a3SScott Long 
20217aa4b937SPyun YongHyeon 	/* Request larger DMA burst size to get better performance. */
20227aa4b937SPyun YongHyeon 	if (sc->bge_asicrev == BGE_ASICREV_BCM5785)
20237aa4b937SPyun YongHyeon 		val |= BGE_WDMAMODE_BURST_ALL_DATA;
20247aa4b937SPyun YongHyeon 
202595d67482SBill Paul 	/* Turn on write DMA state machine */
20266f8718a3SScott Long 	CSR_WRITE_4(sc, BGE_WDMA_MODE, val);
20274f09c4c7SMarius Strobl 	DELAY(40);
202895d67482SBill Paul 
202995d67482SBill Paul 	/* Turn on read DMA state machine */
20304f09c4c7SMarius Strobl 	val = BGE_RDMAMODE_ENABLE | BGE_RDMAMODE_ALL_ATTNS;
20311108273aSPyun YongHyeon 
20321108273aSPyun YongHyeon 	if (sc->bge_asicrev == BGE_ASICREV_BCM5717)
20331108273aSPyun YongHyeon 		val |= BGE_RDMAMODE_MULT_DMA_RD_DIS;
20341108273aSPyun YongHyeon 
2035a5779553SStanislav Sedov 	if (sc->bge_asicrev == BGE_ASICREV_BCM5784 ||
2036a5779553SStanislav Sedov 	    sc->bge_asicrev == BGE_ASICREV_BCM5785 ||
2037a5779553SStanislav Sedov 	    sc->bge_asicrev == BGE_ASICREV_BCM57780)
2038a5779553SStanislav Sedov 		val |= BGE_RDMAMODE_BD_SBD_CRPT_ATTN |
2039a5779553SStanislav Sedov 		    BGE_RDMAMODE_MBUF_RBD_CRPT_ATTN |
2040a5779553SStanislav Sedov 		    BGE_RDMAMODE_MBUF_SBD_CRPT_ATTN;
20414f09c4c7SMarius Strobl 	if (sc->bge_flags & BGE_FLAG_PCIE)
20424f09c4c7SMarius Strobl 		val |= BGE_RDMAMODE_FIFO_LONG_BURST;
20431108273aSPyun YongHyeon 	if (sc->bge_flags & (BGE_FLAG_TSO | BGE_FLAG_TSO3)) {
2044ca3f1187SPyun YongHyeon 		val |= BGE_RDMAMODE_TSO4_ENABLE;
20451108273aSPyun YongHyeon 		if (sc->bge_flags & BGE_FLAG_TSO3 ||
20461108273aSPyun YongHyeon 		    sc->bge_asicrev == BGE_ASICREV_BCM5785 ||
204755a24a05SPyun YongHyeon 		    sc->bge_asicrev == BGE_ASICREV_BCM57780)
204855a24a05SPyun YongHyeon 			val |= BGE_RDMAMODE_TSO6_ENABLE;
204955a24a05SPyun YongHyeon 	}
2050d255f2a9SPyun YongHyeon 	if (sc->bge_asicrev == BGE_ASICREV_BCM5761 ||
2051d255f2a9SPyun YongHyeon 	    sc->bge_asicrev == BGE_ASICREV_BCM5784 ||
2052d255f2a9SPyun YongHyeon 	    sc->bge_asicrev == BGE_ASICREV_BCM5785 ||
20531108273aSPyun YongHyeon 	    sc->bge_asicrev == BGE_ASICREV_BCM57780 ||
20541108273aSPyun YongHyeon 	    BGE_IS_5717_PLUS(sc)) {
2055bbe2ca75SPyun YongHyeon 		dmactl = CSR_READ_4(sc, BGE_RDMA_RSRVCTRL);
2056bbe2ca75SPyun YongHyeon 		/*
2057bbe2ca75SPyun YongHyeon 		 * Adjust tx margin to prevent TX data corruption and
2058bbe2ca75SPyun YongHyeon 		 * fix internal FIFO overflow.
2059bbe2ca75SPyun YongHyeon 		 */
2060bbe2ca75SPyun YongHyeon 		if (sc->bge_asicrev == BGE_ASICREV_BCM5719) {
2061bbe2ca75SPyun YongHyeon 			dmactl &= ~(BGE_RDMA_RSRVCTRL_FIFO_LWM_MASK |
2062bbe2ca75SPyun YongHyeon 			    BGE_RDMA_RSRVCTRL_FIFO_HWM_MASK |
2063bbe2ca75SPyun YongHyeon 			    BGE_RDMA_RSRVCTRL_TXMRGN_MASK);
2064bbe2ca75SPyun YongHyeon 			dmactl |= BGE_RDMA_RSRVCTRL_FIFO_LWM_1_5K |
2065bbe2ca75SPyun YongHyeon 			    BGE_RDMA_RSRVCTRL_FIFO_HWM_1_5K |
2066bbe2ca75SPyun YongHyeon 			    BGE_RDMA_RSRVCTRL_TXMRGN_320B;
2067bbe2ca75SPyun YongHyeon 		}
2068d255f2a9SPyun YongHyeon 		/*
2069d255f2a9SPyun YongHyeon 		 * Enable fix for read DMA FIFO overruns.
2070d255f2a9SPyun YongHyeon 		 * The fix is to limit the number of RX BDs
2071d255f2a9SPyun YongHyeon 		 * the hardware would fetch at a fime.
2072d255f2a9SPyun YongHyeon 		 */
2073bbe2ca75SPyun YongHyeon 		CSR_WRITE_4(sc, BGE_RDMA_RSRVCTRL, dmactl |
2074d255f2a9SPyun YongHyeon 		    BGE_RDMA_RSRVCTRL_FIFO_OFLW_FIX);
2075d255f2a9SPyun YongHyeon 	}
2076bbe2ca75SPyun YongHyeon 
2077bbe2ca75SPyun YongHyeon 	if (sc->bge_asicrev == BGE_ASICREV_BCM5719) {
2078bbe2ca75SPyun YongHyeon 		CSR_WRITE_4(sc, BGE_RDMA_LSO_CRPTEN_CTRL,
2079bbe2ca75SPyun YongHyeon 		    CSR_READ_4(sc, BGE_RDMA_LSO_CRPTEN_CTRL) |
2080bbe2ca75SPyun YongHyeon 		    BGE_RDMA_LSO_CRPTEN_CTRL_BLEN_BD_4K |
2081bbe2ca75SPyun YongHyeon 		    BGE_RDMA_LSO_CRPTEN_CTRL_BLEN_LSO_4K);
2082bbe2ca75SPyun YongHyeon 	}
2083bbe2ca75SPyun YongHyeon 
20844f09c4c7SMarius Strobl 	CSR_WRITE_4(sc, BGE_RDMA_MODE, val);
20854f09c4c7SMarius Strobl 	DELAY(40);
208695d67482SBill Paul 
208795d67482SBill Paul 	/* Turn on RX data completion state machine */
208895d67482SBill Paul 	CSR_WRITE_4(sc, BGE_RDC_MODE, BGE_RDCMODE_ENABLE);
208995d67482SBill Paul 
209095d67482SBill Paul 	/* Turn on RX BD initiator state machine */
209195d67482SBill Paul 	CSR_WRITE_4(sc, BGE_RBDI_MODE, BGE_RBDIMODE_ENABLE);
209295d67482SBill Paul 
209395d67482SBill Paul 	/* Turn on RX data and RX BD initiator state machine */
209495d67482SBill Paul 	CSR_WRITE_4(sc, BGE_RDBDI_MODE, BGE_RDBDIMODE_ENABLE);
209595d67482SBill Paul 
209695d67482SBill Paul 	/* Turn on Mbuf cluster free state machine */
20977ee00338SJung-uk Kim 	if (!(BGE_IS_5705_PLUS(sc)))
209895d67482SBill Paul 		CSR_WRITE_4(sc, BGE_MBCF_MODE, BGE_MBCFMODE_ENABLE);
209995d67482SBill Paul 
210095d67482SBill Paul 	/* Turn on send BD completion state machine */
210195d67482SBill Paul 	CSR_WRITE_4(sc, BGE_SBDC_MODE, BGE_SBDCMODE_ENABLE);
210295d67482SBill Paul 
210395d67482SBill Paul 	/* Turn on send data completion state machine */
2104a5779553SStanislav Sedov 	val = BGE_SDCMODE_ENABLE;
2105a5779553SStanislav Sedov 	if (sc->bge_asicrev == BGE_ASICREV_BCM5761)
2106a5779553SStanislav Sedov 		val |= BGE_SDCMODE_CDELAY;
2107a5779553SStanislav Sedov 	CSR_WRITE_4(sc, BGE_SDC_MODE, val);
210895d67482SBill Paul 
210995d67482SBill Paul 	/* Turn on send data initiator state machine */
21101108273aSPyun YongHyeon 	if (sc->bge_flags & (BGE_FLAG_TSO | BGE_FLAG_TSO3))
21111108273aSPyun YongHyeon 		CSR_WRITE_4(sc, BGE_SDI_MODE, BGE_SDIMODE_ENABLE |
21121108273aSPyun YongHyeon 		    BGE_SDIMODE_HW_LSO_PRE_DMA);
2113ca3f1187SPyun YongHyeon 	else
211495d67482SBill Paul 		CSR_WRITE_4(sc, BGE_SDI_MODE, BGE_SDIMODE_ENABLE);
211595d67482SBill Paul 
211695d67482SBill Paul 	/* Turn on send BD initiator state machine */
211795d67482SBill Paul 	CSR_WRITE_4(sc, BGE_SBDI_MODE, BGE_SBDIMODE_ENABLE);
211895d67482SBill Paul 
211995d67482SBill Paul 	/* Turn on send BD selector state machine */
212095d67482SBill Paul 	CSR_WRITE_4(sc, BGE_SRS_MODE, BGE_SRSMODE_ENABLE);
212195d67482SBill Paul 
21220c8aa4eaSJung-uk Kim 	CSR_WRITE_4(sc, BGE_SDI_STATS_ENABLE_MASK, 0x007FFFFF);
212395d67482SBill Paul 	CSR_WRITE_4(sc, BGE_SDI_STATS_CTL,
212495d67482SBill Paul 	    BGE_SDISTATSCTL_ENABLE | BGE_SDISTATSCTL_FASTER);
212595d67482SBill Paul 
212695d67482SBill Paul 	/* ack/clear link change events */
212795d67482SBill Paul 	CSR_WRITE_4(sc, BGE_MAC_STS, BGE_MACSTAT_SYNC_CHANGED |
21280434d1b8SBill Paul 	    BGE_MACSTAT_CFG_CHANGED | BGE_MACSTAT_MI_COMPLETE |
21290434d1b8SBill Paul 	    BGE_MACSTAT_LINK_CHANGED);
2130f41ac2beSBill Paul 	CSR_WRITE_4(sc, BGE_MI_STS, 0);
213195d67482SBill Paul 
21326ede2cfaSPyun YongHyeon 	/*
21336ede2cfaSPyun YongHyeon 	 * Enable attention when the link has changed state for
21346ede2cfaSPyun YongHyeon 	 * devices that use auto polling.
21356ede2cfaSPyun YongHyeon 	 */
2136652ae483SGleb Smirnoff 	if (sc->bge_flags & BGE_FLAG_TBI) {
213795d67482SBill Paul 		CSR_WRITE_4(sc, BGE_MI_STS, BGE_MISTS_LINK);
2138a1d52896SBill Paul 	} else {
21397ed3f0f0SPyun YongHyeon 		if (sc->bge_mi_mode & BGE_MIMODE_AUTOPOLL) {
21407ed3f0f0SPyun YongHyeon 			CSR_WRITE_4(sc, BGE_MI_MODE, sc->bge_mi_mode);
21417ed3f0f0SPyun YongHyeon 			DELAY(80);
21427ed3f0f0SPyun YongHyeon 		}
21431f313773SOleg Bulyzhin 		if (sc->bge_asicrev == BGE_ASICREV_BCM5700 &&
21444c0da0ffSGleb Smirnoff 		    sc->bge_chipid != BGE_CHIPID_BCM5700_B2)
2145a1d52896SBill Paul 			CSR_WRITE_4(sc, BGE_MAC_EVT_ENB,
2146a1d52896SBill Paul 			    BGE_EVTENB_MI_INTERRUPT);
2147a1d52896SBill Paul 	}
214895d67482SBill Paul 
21491f313773SOleg Bulyzhin 	/*
21501f313773SOleg Bulyzhin 	 * Clear any pending link state attention.
21511f313773SOleg Bulyzhin 	 * Otherwise some link state change events may be lost until attention
21521f313773SOleg Bulyzhin 	 * is cleared by bge_intr() -> bge_link_upd() sequence.
21531f313773SOleg Bulyzhin 	 * It's not necessary on newer BCM chips - perhaps enabling link
21541f313773SOleg Bulyzhin 	 * state change attentions implies clearing pending attention.
21551f313773SOleg Bulyzhin 	 */
21561f313773SOleg Bulyzhin 	CSR_WRITE_4(sc, BGE_MAC_STS, BGE_MACSTAT_SYNC_CHANGED |
21571f313773SOleg Bulyzhin 	    BGE_MACSTAT_CFG_CHANGED | BGE_MACSTAT_MI_COMPLETE |
21581f313773SOleg Bulyzhin 	    BGE_MACSTAT_LINK_CHANGED);
21591f313773SOleg Bulyzhin 
216095d67482SBill Paul 	/* Enable link state change attentions. */
216195d67482SBill Paul 	BGE_SETBIT(sc, BGE_MAC_EVT_ENB, BGE_EVTENB_LINK_CHANGED);
216295d67482SBill Paul 
216395d67482SBill Paul 	return (0);
216495d67482SBill Paul }
216595d67482SBill Paul 
21664c0da0ffSGleb Smirnoff const struct bge_revision *
21674c0da0ffSGleb Smirnoff bge_lookup_rev(uint32_t chipid)
21684c0da0ffSGleb Smirnoff {
21694c0da0ffSGleb Smirnoff 	const struct bge_revision *br;
21704c0da0ffSGleb Smirnoff 
21714c0da0ffSGleb Smirnoff 	for (br = bge_revisions; br->br_name != NULL; br++) {
21724c0da0ffSGleb Smirnoff 		if (br->br_chipid == chipid)
21734c0da0ffSGleb Smirnoff 			return (br);
21744c0da0ffSGleb Smirnoff 	}
21754c0da0ffSGleb Smirnoff 
21764c0da0ffSGleb Smirnoff 	for (br = bge_majorrevs; br->br_name != NULL; br++) {
21774c0da0ffSGleb Smirnoff 		if (br->br_chipid == BGE_ASICREV(chipid))
21784c0da0ffSGleb Smirnoff 			return (br);
21794c0da0ffSGleb Smirnoff 	}
21804c0da0ffSGleb Smirnoff 
21814c0da0ffSGleb Smirnoff 	return (NULL);
21824c0da0ffSGleb Smirnoff }
21834c0da0ffSGleb Smirnoff 
21844c0da0ffSGleb Smirnoff const struct bge_vendor *
21854c0da0ffSGleb Smirnoff bge_lookup_vendor(uint16_t vid)
21864c0da0ffSGleb Smirnoff {
21874c0da0ffSGleb Smirnoff 	const struct bge_vendor *v;
21884c0da0ffSGleb Smirnoff 
21894c0da0ffSGleb Smirnoff 	for (v = bge_vendors; v->v_name != NULL; v++)
21904c0da0ffSGleb Smirnoff 		if (v->v_id == vid)
21914c0da0ffSGleb Smirnoff 			return (v);
21924c0da0ffSGleb Smirnoff 
21934c0da0ffSGleb Smirnoff 	panic("%s: unknown vendor %d", __func__, vid);
21944c0da0ffSGleb Smirnoff 	return (NULL);
21954c0da0ffSGleb Smirnoff }
21964c0da0ffSGleb Smirnoff 
219795d67482SBill Paul /*
219895d67482SBill Paul  * Probe for a Broadcom chip. Check the PCI vendor and device IDs
21994c0da0ffSGleb Smirnoff  * against our list and return its name if we find a match.
22004c0da0ffSGleb Smirnoff  *
22014c0da0ffSGleb Smirnoff  * Note that since the Broadcom controller contains VPD support, we
22027c929cf9SJung-uk Kim  * try to get the device name string from the controller itself instead
22037c929cf9SJung-uk Kim  * of the compiled-in string. It guarantees we'll always announce the
22047c929cf9SJung-uk Kim  * right product name. We fall back to the compiled-in string when
22057c929cf9SJung-uk Kim  * VPD is unavailable or corrupt.
220695d67482SBill Paul  */
220795d67482SBill Paul static int
22083f74909aSGleb Smirnoff bge_probe(device_t dev)
220995d67482SBill Paul {
2210978f2704SMarius Strobl 	char buf[96];
2211978f2704SMarius Strobl 	char model[64];
2212978f2704SMarius Strobl 	const struct bge_revision *br;
2213978f2704SMarius Strobl 	const char *pname;
22144c0da0ffSGleb Smirnoff 	struct bge_softc *sc = device_get_softc(dev);
2215978f2704SMarius Strobl 	const struct bge_type *t = bge_devs;
2216978f2704SMarius Strobl 	const struct bge_vendor *v;
2217978f2704SMarius Strobl 	uint32_t id;
2218978f2704SMarius Strobl 	uint16_t did, vid;
221995d67482SBill Paul 
222095d67482SBill Paul 	sc->bge_dev = dev;
22217c929cf9SJung-uk Kim 	vid = pci_get_vendor(dev);
22227c929cf9SJung-uk Kim 	did = pci_get_device(dev);
22234c0da0ffSGleb Smirnoff 	while(t->bge_vid != 0) {
22247c929cf9SJung-uk Kim 		if ((vid == t->bge_vid) && (did == t->bge_did)) {
2225a5779553SStanislav Sedov 			id = pci_read_config(dev, BGE_PCI_MISC_CTL, 4) >>
2226a5779553SStanislav Sedov 			    BGE_PCIMISCCTL_ASICREV_SHIFT;
22271108273aSPyun YongHyeon 			if (BGE_ASICREV(id) == BGE_ASICREV_USE_PRODID_REG) {
22281108273aSPyun YongHyeon 				/*
22291108273aSPyun YongHyeon 				 * Find the ASCI revision.  Different chips
22301108273aSPyun YongHyeon 				 * use different registers.
22311108273aSPyun YongHyeon 				 */
22321108273aSPyun YongHyeon 				switch (pci_get_device(dev)) {
22331108273aSPyun YongHyeon 				case BCOM_DEVICEID_BCM5717:
22341108273aSPyun YongHyeon 				case BCOM_DEVICEID_BCM5718:
2235bbe2ca75SPyun YongHyeon 				case BCOM_DEVICEID_BCM5719:
22361108273aSPyun YongHyeon 					id = pci_read_config(dev,
22371108273aSPyun YongHyeon 					    BGE_PCI_GEN2_PRODID_ASICREV, 4);
22381108273aSPyun YongHyeon 					break;
2239b4a256acSPyun YongHyeon 				case BCOM_DEVICEID_BCM57761:
2240b4a256acSPyun YongHyeon 				case BCOM_DEVICEID_BCM57765:
2241b4a256acSPyun YongHyeon 				case BCOM_DEVICEID_BCM57781:
2242b4a256acSPyun YongHyeon 				case BCOM_DEVICEID_BCM57785:
2243b4a256acSPyun YongHyeon 				case BCOM_DEVICEID_BCM57791:
2244b4a256acSPyun YongHyeon 				case BCOM_DEVICEID_BCM57795:
2245b4a256acSPyun YongHyeon 					id = pci_read_config(dev,
2246b4a256acSPyun YongHyeon 					    BGE_PCI_GEN15_PRODID_ASICREV, 4);
2247b4a256acSPyun YongHyeon 					break;
22481108273aSPyun YongHyeon 				default:
2249a5779553SStanislav Sedov 					id = pci_read_config(dev,
2250a5779553SStanislav Sedov 					    BGE_PCI_PRODID_ASICREV, 4);
22511108273aSPyun YongHyeon 				}
22521108273aSPyun YongHyeon 			}
22534c0da0ffSGleb Smirnoff 			br = bge_lookup_rev(id);
22547c929cf9SJung-uk Kim 			v = bge_lookup_vendor(vid);
2255852c67f9SMarius Strobl 			if (bge_has_eaddr(sc) &&
2256852c67f9SMarius Strobl 			    pci_get_vpd_ident(dev, &pname) == 0)
22574e35d186SJung-uk Kim 				snprintf(model, 64, "%s", pname);
22584e35d186SJung-uk Kim 			else
2259978f2704SMarius Strobl 				snprintf(model, 64, "%s %s", v->v_name,
22607c929cf9SJung-uk Kim 				    br != NULL ? br->br_name :
22617c929cf9SJung-uk Kim 				    "NetXtreme Ethernet Controller");
2262a5779553SStanislav Sedov 			snprintf(buf, 96, "%s, %sASIC rev. %#08x", model,
2263a5779553SStanislav Sedov 			    br != NULL ? "" : "unknown ", id);
22644c0da0ffSGleb Smirnoff 			device_set_desc_copy(dev, buf);
226595d67482SBill Paul 			return (0);
226695d67482SBill Paul 		}
226795d67482SBill Paul 		t++;
226895d67482SBill Paul 	}
226995d67482SBill Paul 
227095d67482SBill Paul 	return (ENXIO);
227195d67482SBill Paul }
227295d67482SBill Paul 
2273f41ac2beSBill Paul static void
22743f74909aSGleb Smirnoff bge_dma_free(struct bge_softc *sc)
2275f41ac2beSBill Paul {
2276f41ac2beSBill Paul 	int i;
2277f41ac2beSBill Paul 
22783f74909aSGleb Smirnoff 	/* Destroy DMA maps for RX buffers. */
2279f41ac2beSBill Paul 	for (i = 0; i < BGE_STD_RX_RING_CNT; i++) {
2280f41ac2beSBill Paul 		if (sc->bge_cdata.bge_rx_std_dmamap[i])
22810ac56796SPyun YongHyeon 			bus_dmamap_destroy(sc->bge_cdata.bge_rx_mtag,
2282f41ac2beSBill Paul 			    sc->bge_cdata.bge_rx_std_dmamap[i]);
2283f41ac2beSBill Paul 	}
2284943787f3SPyun YongHyeon 	if (sc->bge_cdata.bge_rx_std_sparemap)
2285943787f3SPyun YongHyeon 		bus_dmamap_destroy(sc->bge_cdata.bge_rx_mtag,
2286943787f3SPyun YongHyeon 		    sc->bge_cdata.bge_rx_std_sparemap);
2287f41ac2beSBill Paul 
22883f74909aSGleb Smirnoff 	/* Destroy DMA maps for jumbo RX buffers. */
2289f41ac2beSBill Paul 	for (i = 0; i < BGE_JUMBO_RX_RING_CNT; i++) {
2290f41ac2beSBill Paul 		if (sc->bge_cdata.bge_rx_jumbo_dmamap[i])
2291f41ac2beSBill Paul 			bus_dmamap_destroy(sc->bge_cdata.bge_mtag_jumbo,
2292f41ac2beSBill Paul 			    sc->bge_cdata.bge_rx_jumbo_dmamap[i]);
2293f41ac2beSBill Paul 	}
2294943787f3SPyun YongHyeon 	if (sc->bge_cdata.bge_rx_jumbo_sparemap)
2295943787f3SPyun YongHyeon 		bus_dmamap_destroy(sc->bge_cdata.bge_mtag_jumbo,
2296943787f3SPyun YongHyeon 		    sc->bge_cdata.bge_rx_jumbo_sparemap);
2297f41ac2beSBill Paul 
22983f74909aSGleb Smirnoff 	/* Destroy DMA maps for TX buffers. */
2299f41ac2beSBill Paul 	for (i = 0; i < BGE_TX_RING_CNT; i++) {
2300f41ac2beSBill Paul 		if (sc->bge_cdata.bge_tx_dmamap[i])
23010ac56796SPyun YongHyeon 			bus_dmamap_destroy(sc->bge_cdata.bge_tx_mtag,
2302f41ac2beSBill Paul 			    sc->bge_cdata.bge_tx_dmamap[i]);
2303f41ac2beSBill Paul 	}
2304f41ac2beSBill Paul 
23050ac56796SPyun YongHyeon 	if (sc->bge_cdata.bge_rx_mtag)
23060ac56796SPyun YongHyeon 		bus_dma_tag_destroy(sc->bge_cdata.bge_rx_mtag);
23070ac56796SPyun YongHyeon 	if (sc->bge_cdata.bge_tx_mtag)
23080ac56796SPyun YongHyeon 		bus_dma_tag_destroy(sc->bge_cdata.bge_tx_mtag);
2309f41ac2beSBill Paul 
2310f41ac2beSBill Paul 
23113f74909aSGleb Smirnoff 	/* Destroy standard RX ring. */
2312e65bed95SPyun YongHyeon 	if (sc->bge_cdata.bge_rx_std_ring_map)
2313e65bed95SPyun YongHyeon 		bus_dmamap_unload(sc->bge_cdata.bge_rx_std_ring_tag,
2314e65bed95SPyun YongHyeon 		    sc->bge_cdata.bge_rx_std_ring_map);
2315e65bed95SPyun YongHyeon 	if (sc->bge_cdata.bge_rx_std_ring_map && sc->bge_ldata.bge_rx_std_ring)
2316f41ac2beSBill Paul 		bus_dmamem_free(sc->bge_cdata.bge_rx_std_ring_tag,
2317f41ac2beSBill Paul 		    sc->bge_ldata.bge_rx_std_ring,
2318f41ac2beSBill Paul 		    sc->bge_cdata.bge_rx_std_ring_map);
2319f41ac2beSBill Paul 
2320f41ac2beSBill Paul 	if (sc->bge_cdata.bge_rx_std_ring_tag)
2321f41ac2beSBill Paul 		bus_dma_tag_destroy(sc->bge_cdata.bge_rx_std_ring_tag);
2322f41ac2beSBill Paul 
23233f74909aSGleb Smirnoff 	/* Destroy jumbo RX ring. */
2324e65bed95SPyun YongHyeon 	if (sc->bge_cdata.bge_rx_jumbo_ring_map)
2325e65bed95SPyun YongHyeon 		bus_dmamap_unload(sc->bge_cdata.bge_rx_jumbo_ring_tag,
2326e65bed95SPyun YongHyeon 		    sc->bge_cdata.bge_rx_jumbo_ring_map);
2327e65bed95SPyun YongHyeon 
2328e65bed95SPyun YongHyeon 	if (sc->bge_cdata.bge_rx_jumbo_ring_map &&
2329e65bed95SPyun YongHyeon 	    sc->bge_ldata.bge_rx_jumbo_ring)
2330f41ac2beSBill Paul 		bus_dmamem_free(sc->bge_cdata.bge_rx_jumbo_ring_tag,
2331f41ac2beSBill Paul 		    sc->bge_ldata.bge_rx_jumbo_ring,
2332f41ac2beSBill Paul 		    sc->bge_cdata.bge_rx_jumbo_ring_map);
2333f41ac2beSBill Paul 
2334f41ac2beSBill Paul 	if (sc->bge_cdata.bge_rx_jumbo_ring_tag)
2335f41ac2beSBill Paul 		bus_dma_tag_destroy(sc->bge_cdata.bge_rx_jumbo_ring_tag);
2336f41ac2beSBill Paul 
23373f74909aSGleb Smirnoff 	/* Destroy RX return ring. */
2338e65bed95SPyun YongHyeon 	if (sc->bge_cdata.bge_rx_return_ring_map)
2339e65bed95SPyun YongHyeon 		bus_dmamap_unload(sc->bge_cdata.bge_rx_return_ring_tag,
2340e65bed95SPyun YongHyeon 		    sc->bge_cdata.bge_rx_return_ring_map);
2341e65bed95SPyun YongHyeon 
2342e65bed95SPyun YongHyeon 	if (sc->bge_cdata.bge_rx_return_ring_map &&
2343e65bed95SPyun YongHyeon 	    sc->bge_ldata.bge_rx_return_ring)
2344f41ac2beSBill Paul 		bus_dmamem_free(sc->bge_cdata.bge_rx_return_ring_tag,
2345f41ac2beSBill Paul 		    sc->bge_ldata.bge_rx_return_ring,
2346f41ac2beSBill Paul 		    sc->bge_cdata.bge_rx_return_ring_map);
2347f41ac2beSBill Paul 
2348f41ac2beSBill Paul 	if (sc->bge_cdata.bge_rx_return_ring_tag)
2349f41ac2beSBill Paul 		bus_dma_tag_destroy(sc->bge_cdata.bge_rx_return_ring_tag);
2350f41ac2beSBill Paul 
23513f74909aSGleb Smirnoff 	/* Destroy TX ring. */
2352e65bed95SPyun YongHyeon 	if (sc->bge_cdata.bge_tx_ring_map)
2353e65bed95SPyun YongHyeon 		bus_dmamap_unload(sc->bge_cdata.bge_tx_ring_tag,
2354e65bed95SPyun YongHyeon 		    sc->bge_cdata.bge_tx_ring_map);
2355e65bed95SPyun YongHyeon 
2356e65bed95SPyun YongHyeon 	if (sc->bge_cdata.bge_tx_ring_map && sc->bge_ldata.bge_tx_ring)
2357f41ac2beSBill Paul 		bus_dmamem_free(sc->bge_cdata.bge_tx_ring_tag,
2358f41ac2beSBill Paul 		    sc->bge_ldata.bge_tx_ring,
2359f41ac2beSBill Paul 		    sc->bge_cdata.bge_tx_ring_map);
2360f41ac2beSBill Paul 
2361f41ac2beSBill Paul 	if (sc->bge_cdata.bge_tx_ring_tag)
2362f41ac2beSBill Paul 		bus_dma_tag_destroy(sc->bge_cdata.bge_tx_ring_tag);
2363f41ac2beSBill Paul 
23643f74909aSGleb Smirnoff 	/* Destroy status block. */
2365e65bed95SPyun YongHyeon 	if (sc->bge_cdata.bge_status_map)
2366e65bed95SPyun YongHyeon 		bus_dmamap_unload(sc->bge_cdata.bge_status_tag,
2367e65bed95SPyun YongHyeon 		    sc->bge_cdata.bge_status_map);
2368e65bed95SPyun YongHyeon 
2369e65bed95SPyun YongHyeon 	if (sc->bge_cdata.bge_status_map && sc->bge_ldata.bge_status_block)
2370f41ac2beSBill Paul 		bus_dmamem_free(sc->bge_cdata.bge_status_tag,
2371f41ac2beSBill Paul 		    sc->bge_ldata.bge_status_block,
2372f41ac2beSBill Paul 		    sc->bge_cdata.bge_status_map);
2373f41ac2beSBill Paul 
2374f41ac2beSBill Paul 	if (sc->bge_cdata.bge_status_tag)
2375f41ac2beSBill Paul 		bus_dma_tag_destroy(sc->bge_cdata.bge_status_tag);
2376f41ac2beSBill Paul 
23773f74909aSGleb Smirnoff 	/* Destroy statistics block. */
2378e65bed95SPyun YongHyeon 	if (sc->bge_cdata.bge_stats_map)
2379e65bed95SPyun YongHyeon 		bus_dmamap_unload(sc->bge_cdata.bge_stats_tag,
2380e65bed95SPyun YongHyeon 		    sc->bge_cdata.bge_stats_map);
2381e65bed95SPyun YongHyeon 
2382e65bed95SPyun YongHyeon 	if (sc->bge_cdata.bge_stats_map && sc->bge_ldata.bge_stats)
2383f41ac2beSBill Paul 		bus_dmamem_free(sc->bge_cdata.bge_stats_tag,
2384f41ac2beSBill Paul 		    sc->bge_ldata.bge_stats,
2385f41ac2beSBill Paul 		    sc->bge_cdata.bge_stats_map);
2386f41ac2beSBill Paul 
2387f41ac2beSBill Paul 	if (sc->bge_cdata.bge_stats_tag)
2388f41ac2beSBill Paul 		bus_dma_tag_destroy(sc->bge_cdata.bge_stats_tag);
2389f41ac2beSBill Paul 
23905b610048SPyun YongHyeon 	if (sc->bge_cdata.bge_buffer_tag)
23915b610048SPyun YongHyeon 		bus_dma_tag_destroy(sc->bge_cdata.bge_buffer_tag);
23925b610048SPyun YongHyeon 
23933f74909aSGleb Smirnoff 	/* Destroy the parent tag. */
2394f41ac2beSBill Paul 	if (sc->bge_cdata.bge_parent_tag)
2395f41ac2beSBill Paul 		bus_dma_tag_destroy(sc->bge_cdata.bge_parent_tag);
2396f41ac2beSBill Paul }
2397f41ac2beSBill Paul 
2398f41ac2beSBill Paul static int
23995b610048SPyun YongHyeon bge_dma_ring_alloc(struct bge_softc *sc, bus_size_t alignment,
24005b610048SPyun YongHyeon     bus_size_t maxsize, bus_dma_tag_t *tag, uint8_t **ring, bus_dmamap_t *map,
24015b610048SPyun YongHyeon     bus_addr_t *paddr, const char *msg)
2402f41ac2beSBill Paul {
24033f74909aSGleb Smirnoff 	struct bge_dmamap_arg ctx;
2404f681b29aSPyun YongHyeon 	bus_addr_t lowaddr;
24055b610048SPyun YongHyeon 	bus_size_t ring_end;
24065b610048SPyun YongHyeon 	int error;
2407f41ac2beSBill Paul 
24085b610048SPyun YongHyeon 	lowaddr = BUS_SPACE_MAXADDR;
24095b610048SPyun YongHyeon again:
24105b610048SPyun YongHyeon 	error = bus_dma_tag_create(sc->bge_cdata.bge_parent_tag,
24115b610048SPyun YongHyeon 	    alignment, 0, lowaddr, BUS_SPACE_MAXADDR, NULL,
24125b610048SPyun YongHyeon 	    NULL, maxsize, 1, maxsize, 0, NULL, NULL, tag);
24135b610048SPyun YongHyeon 	if (error != 0) {
24145b610048SPyun YongHyeon 		device_printf(sc->bge_dev,
24155b610048SPyun YongHyeon 		    "could not create %s dma tag\n", msg);
24165b610048SPyun YongHyeon 		return (ENOMEM);
24175b610048SPyun YongHyeon 	}
24185b610048SPyun YongHyeon 	/* Allocate DMA'able memory for ring. */
24195b610048SPyun YongHyeon 	error = bus_dmamem_alloc(*tag, (void **)ring,
24205b610048SPyun YongHyeon 	    BUS_DMA_NOWAIT | BUS_DMA_ZERO | BUS_DMA_COHERENT, map);
24215b610048SPyun YongHyeon 	if (error != 0) {
24225b610048SPyun YongHyeon 		device_printf(sc->bge_dev,
24235b610048SPyun YongHyeon 		    "could not allocate DMA'able memory for %s\n", msg);
24245b610048SPyun YongHyeon 		return (ENOMEM);
24255b610048SPyun YongHyeon 	}
24265b610048SPyun YongHyeon 	/* Load the address of the ring. */
24275b610048SPyun YongHyeon 	ctx.bge_busaddr = 0;
24285b610048SPyun YongHyeon 	error = bus_dmamap_load(*tag, *map, *ring, maxsize, bge_dma_map_addr,
24295b610048SPyun YongHyeon 	    &ctx, BUS_DMA_NOWAIT);
24305b610048SPyun YongHyeon 	if (error != 0) {
24315b610048SPyun YongHyeon 		device_printf(sc->bge_dev,
24325b610048SPyun YongHyeon 		    "could not load DMA'able memory for %s\n", msg);
24335b610048SPyun YongHyeon 		return (ENOMEM);
24345b610048SPyun YongHyeon 	}
24355b610048SPyun YongHyeon 	*paddr = ctx.bge_busaddr;
24365b610048SPyun YongHyeon 	ring_end = *paddr + maxsize;
24375b610048SPyun YongHyeon 	if ((sc->bge_flags & BGE_FLAG_4G_BNDRY_BUG) != 0 &&
24385b610048SPyun YongHyeon 	    BGE_ADDR_HI(*paddr) != BGE_ADDR_HI(ring_end)) {
24395b610048SPyun YongHyeon 		/*
24405b610048SPyun YongHyeon 		 * 4GB boundary crossed.  Limit maximum allowable DMA
24415b610048SPyun YongHyeon 		 * address space to 32bit and try again.
24425b610048SPyun YongHyeon 		 */
24435b610048SPyun YongHyeon 		bus_dmamap_unload(*tag, *map);
24445b610048SPyun YongHyeon 		bus_dmamem_free(*tag, *ring, *map);
24455b610048SPyun YongHyeon 		bus_dma_tag_destroy(*tag);
24465b610048SPyun YongHyeon 		if (bootverbose)
24475b610048SPyun YongHyeon 			device_printf(sc->bge_dev, "4GB boundary crossed, "
24485b610048SPyun YongHyeon 			    "limit DMA address space to 32bit for %s\n", msg);
24495b610048SPyun YongHyeon 		*ring = NULL;
24505b610048SPyun YongHyeon 		*tag = NULL;
24515b610048SPyun YongHyeon 		*map = NULL;
24525b610048SPyun YongHyeon 		lowaddr = BUS_SPACE_MAXADDR_32BIT;
24535b610048SPyun YongHyeon 		goto again;
24545b610048SPyun YongHyeon 	}
24555b610048SPyun YongHyeon 	return (0);
24565b610048SPyun YongHyeon }
24575b610048SPyun YongHyeon 
24585b610048SPyun YongHyeon static int
24595b610048SPyun YongHyeon bge_dma_alloc(struct bge_softc *sc)
24605b610048SPyun YongHyeon {
24615b610048SPyun YongHyeon 	bus_addr_t lowaddr;
2462f5459d4cSPyun YongHyeon 	bus_size_t boundary, sbsz, rxmaxsegsz, txsegsz, txmaxsegsz;
24635b610048SPyun YongHyeon 	int i, error;
2464f41ac2beSBill Paul 
2465f681b29aSPyun YongHyeon 	lowaddr = BUS_SPACE_MAXADDR;
2466f681b29aSPyun YongHyeon 	if ((sc->bge_flags & BGE_FLAG_40BIT_BUG) != 0)
2467f681b29aSPyun YongHyeon 		lowaddr = BGE_DMA_MAXADDR;
2468f41ac2beSBill Paul 	/*
2469f41ac2beSBill Paul 	 * Allocate the parent bus DMA tag appropriate for PCI.
2470f41ac2beSBill Paul 	 */
24714eee14cbSMarius Strobl 	error = bus_dma_tag_create(bus_get_dma_tag(sc->bge_dev),
2472f681b29aSPyun YongHyeon 	    1, 0, lowaddr, BUS_SPACE_MAXADDR, NULL,
24734eee14cbSMarius Strobl 	    NULL, BUS_SPACE_MAXSIZE_32BIT, 0, BUS_SPACE_MAXSIZE_32BIT,
24744eee14cbSMarius Strobl 	    0, NULL, NULL, &sc->bge_cdata.bge_parent_tag);
2475e65bed95SPyun YongHyeon 	if (error != 0) {
2476fe806fdaSPyun YongHyeon 		device_printf(sc->bge_dev,
2477fe806fdaSPyun YongHyeon 		    "could not allocate parent dma tag\n");
2478e65bed95SPyun YongHyeon 		return (ENOMEM);
2479e65bed95SPyun YongHyeon 	}
2480e65bed95SPyun YongHyeon 
24815b610048SPyun YongHyeon 	/* Create tag for standard RX ring. */
24825b610048SPyun YongHyeon 	error = bge_dma_ring_alloc(sc, PAGE_SIZE, BGE_STD_RX_RING_SZ,
24835b610048SPyun YongHyeon 	    &sc->bge_cdata.bge_rx_std_ring_tag,
24845b610048SPyun YongHyeon 	    (uint8_t **)&sc->bge_ldata.bge_rx_std_ring,
24855b610048SPyun YongHyeon 	    &sc->bge_cdata.bge_rx_std_ring_map,
24865b610048SPyun YongHyeon 	    &sc->bge_ldata.bge_rx_std_ring_paddr, "RX ring");
24875b610048SPyun YongHyeon 	if (error)
24885b610048SPyun YongHyeon 		return (error);
24895b610048SPyun YongHyeon 
24905b610048SPyun YongHyeon 	/* Create tag for RX return ring. */
24915b610048SPyun YongHyeon 	error = bge_dma_ring_alloc(sc, PAGE_SIZE, BGE_RX_RTN_RING_SZ(sc),
24925b610048SPyun YongHyeon 	    &sc->bge_cdata.bge_rx_return_ring_tag,
24935b610048SPyun YongHyeon 	    (uint8_t **)&sc->bge_ldata.bge_rx_return_ring,
24945b610048SPyun YongHyeon 	    &sc->bge_cdata.bge_rx_return_ring_map,
24955b610048SPyun YongHyeon 	    &sc->bge_ldata.bge_rx_return_ring_paddr, "RX return ring");
24965b610048SPyun YongHyeon 	if (error)
24975b610048SPyun YongHyeon 		return (error);
24985b610048SPyun YongHyeon 
24995b610048SPyun YongHyeon 	/* Create tag for TX ring. */
25005b610048SPyun YongHyeon 	error = bge_dma_ring_alloc(sc, PAGE_SIZE, BGE_TX_RING_SZ,
25015b610048SPyun YongHyeon 	    &sc->bge_cdata.bge_tx_ring_tag,
25025b610048SPyun YongHyeon 	    (uint8_t **)&sc->bge_ldata.bge_tx_ring,
25035b610048SPyun YongHyeon 	    &sc->bge_cdata.bge_tx_ring_map,
25045b610048SPyun YongHyeon 	    &sc->bge_ldata.bge_tx_ring_paddr, "TX ring");
25055b610048SPyun YongHyeon 	if (error)
25065b610048SPyun YongHyeon 		return (error);
25075b610048SPyun YongHyeon 
2508f41ac2beSBill Paul 	/*
25095b610048SPyun YongHyeon 	 * Create tag for status block.
25105b610048SPyun YongHyeon 	 * Because we only use single Tx/Rx/Rx return ring, use
25115b610048SPyun YongHyeon 	 * minimum status block size except BCM5700 AX/BX which
25125b610048SPyun YongHyeon 	 * seems to want to see full status block size regardless
25135b610048SPyun YongHyeon 	 * of configured number of ring.
2514f41ac2beSBill Paul 	 */
25155b610048SPyun YongHyeon 	if (sc->bge_asicrev == BGE_ASICREV_BCM5700 &&
25165b610048SPyun YongHyeon 	    sc->bge_chipid != BGE_CHIPID_BCM5700_C0)
25175b610048SPyun YongHyeon 		sbsz = BGE_STATUS_BLK_SZ;
25185b610048SPyun YongHyeon 	else
25195b610048SPyun YongHyeon 		sbsz = 32;
25205b610048SPyun YongHyeon 	error = bge_dma_ring_alloc(sc, PAGE_SIZE, sbsz,
25215b610048SPyun YongHyeon 	    &sc->bge_cdata.bge_status_tag,
25225b610048SPyun YongHyeon 	    (uint8_t **)&sc->bge_ldata.bge_status_block,
25235b610048SPyun YongHyeon 	    &sc->bge_cdata.bge_status_map,
25245b610048SPyun YongHyeon 	    &sc->bge_ldata.bge_status_block_paddr, "status block");
25255b610048SPyun YongHyeon 	if (error)
25265b610048SPyun YongHyeon 		return (error);
25275b610048SPyun YongHyeon 
252812c65daeSPyun YongHyeon 	/* Create tag for statistics block. */
252912c65daeSPyun YongHyeon 	error = bge_dma_ring_alloc(sc, PAGE_SIZE, BGE_STATS_SZ,
253012c65daeSPyun YongHyeon 	    &sc->bge_cdata.bge_stats_tag,
253112c65daeSPyun YongHyeon 	    (uint8_t **)&sc->bge_ldata.bge_stats,
253212c65daeSPyun YongHyeon 	    &sc->bge_cdata.bge_stats_map,
253312c65daeSPyun YongHyeon 	    &sc->bge_ldata.bge_stats_paddr, "statistics block");
253412c65daeSPyun YongHyeon 	if (error)
253512c65daeSPyun YongHyeon 		return (error);
253612c65daeSPyun YongHyeon 
25375b610048SPyun YongHyeon 	/* Create tag for jumbo RX ring. */
25385b610048SPyun YongHyeon 	if (BGE_IS_JUMBO_CAPABLE(sc)) {
25395b610048SPyun YongHyeon 		error = bge_dma_ring_alloc(sc, PAGE_SIZE, BGE_JUMBO_RX_RING_SZ,
25405b610048SPyun YongHyeon 		    &sc->bge_cdata.bge_rx_jumbo_ring_tag,
25415b610048SPyun YongHyeon 		    (uint8_t **)&sc->bge_ldata.bge_rx_jumbo_ring,
25425b610048SPyun YongHyeon 		    &sc->bge_cdata.bge_rx_jumbo_ring_map,
25435b610048SPyun YongHyeon 		    &sc->bge_ldata.bge_rx_jumbo_ring_paddr, "jumbo RX ring");
25445b610048SPyun YongHyeon 		if (error)
25455b610048SPyun YongHyeon 			return (error);
25465b610048SPyun YongHyeon 	}
25475b610048SPyun YongHyeon 
25485b610048SPyun YongHyeon 	/* Create parent tag for buffers. */
25495b610048SPyun YongHyeon 	boundary = 0;
2550d2ffe15aSPyun YongHyeon 	if ((sc->bge_flags & BGE_FLAG_4G_BNDRY_BUG) != 0) {
255138cc6151SPyun YongHyeon 		boundary = BGE_DMA_BNDRY;
2552d2ffe15aSPyun YongHyeon 		/*
2553d2ffe15aSPyun YongHyeon 		 * XXX
2554d2ffe15aSPyun YongHyeon 		 * watchdog timeout issue was observed on BCM5704 which
2555d2ffe15aSPyun YongHyeon 		 * lives behind PCI-X bridge(e.g AMD 8131 PCI-X bridge).
2556d2ffe15aSPyun YongHyeon 		 * Limiting DMA address space to 32bits seems to address
2557d2ffe15aSPyun YongHyeon 		 * it.
2558d2ffe15aSPyun YongHyeon 		 */
2559d2ffe15aSPyun YongHyeon 		if (sc->bge_flags & BGE_FLAG_PCIX)
2560d2ffe15aSPyun YongHyeon 			lowaddr = BUS_SPACE_MAXADDR_32BIT;
2561d2ffe15aSPyun YongHyeon 	}
25625b610048SPyun YongHyeon 	error = bus_dma_tag_create(bus_get_dma_tag(sc->bge_dev),
256392c0b021SPyun YongHyeon 	    1, boundary, lowaddr, BUS_SPACE_MAXADDR, NULL,
25645b610048SPyun YongHyeon 	    NULL, BUS_SPACE_MAXSIZE_32BIT, 0, BUS_SPACE_MAXSIZE_32BIT,
25655b610048SPyun YongHyeon 	    0, NULL, NULL, &sc->bge_cdata.bge_buffer_tag);
25665b610048SPyun YongHyeon 	if (error != 0) {
25675b610048SPyun YongHyeon 		device_printf(sc->bge_dev,
25685b610048SPyun YongHyeon 		    "could not allocate buffer dma tag\n");
25695b610048SPyun YongHyeon 		return (ENOMEM);
25705b610048SPyun YongHyeon 	}
25715b610048SPyun YongHyeon 	/* Create tag for Tx mbufs. */
25721108273aSPyun YongHyeon 	if (sc->bge_flags & (BGE_FLAG_TSO | BGE_FLAG_TSO3)) {
2573ca3f1187SPyun YongHyeon 		txsegsz = BGE_TSOSEG_SZ;
2574ca3f1187SPyun YongHyeon 		txmaxsegsz = 65535 + sizeof(struct ether_vlan_header);
2575ca3f1187SPyun YongHyeon 	} else {
2576ca3f1187SPyun YongHyeon 		txsegsz = MCLBYTES;
2577ca3f1187SPyun YongHyeon 		txmaxsegsz = MCLBYTES * BGE_NSEG_NEW;
2578ca3f1187SPyun YongHyeon 	}
25795b610048SPyun YongHyeon 	error = bus_dma_tag_create(sc->bge_cdata.bge_buffer_tag, 1,
2580ca3f1187SPyun YongHyeon 	    0, BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL,
2581ca3f1187SPyun YongHyeon 	    txmaxsegsz, BGE_NSEG_NEW, txsegsz, 0, NULL, NULL,
2582ca3f1187SPyun YongHyeon 	    &sc->bge_cdata.bge_tx_mtag);
2583f41ac2beSBill Paul 
2584f41ac2beSBill Paul 	if (error) {
25850ac56796SPyun YongHyeon 		device_printf(sc->bge_dev, "could not allocate TX dma tag\n");
25860ac56796SPyun YongHyeon 		return (ENOMEM);
25870ac56796SPyun YongHyeon 	}
25880ac56796SPyun YongHyeon 
25895b610048SPyun YongHyeon 	/* Create tag for Rx mbufs. */
2590f5459d4cSPyun YongHyeon 	if (sc->bge_flags & BGE_FLAG_JUMBO_STD)
2591f5459d4cSPyun YongHyeon 		rxmaxsegsz = MJUM9BYTES;
2592f5459d4cSPyun YongHyeon 	else
2593f5459d4cSPyun YongHyeon 		rxmaxsegsz = MCLBYTES;
25945b610048SPyun YongHyeon 	error = bus_dma_tag_create(sc->bge_cdata.bge_buffer_tag, 1, 0,
2595f5459d4cSPyun YongHyeon 	    BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL, rxmaxsegsz, 1,
2596f5459d4cSPyun YongHyeon 	    rxmaxsegsz, 0, NULL, NULL, &sc->bge_cdata.bge_rx_mtag);
25970ac56796SPyun YongHyeon 
25980ac56796SPyun YongHyeon 	if (error) {
25990ac56796SPyun YongHyeon 		device_printf(sc->bge_dev, "could not allocate RX dma tag\n");
2600f41ac2beSBill Paul 		return (ENOMEM);
2601f41ac2beSBill Paul 	}
2602f41ac2beSBill Paul 
26033f74909aSGleb Smirnoff 	/* Create DMA maps for RX buffers. */
2604943787f3SPyun YongHyeon 	error = bus_dmamap_create(sc->bge_cdata.bge_rx_mtag, 0,
2605943787f3SPyun YongHyeon 	    &sc->bge_cdata.bge_rx_std_sparemap);
2606943787f3SPyun YongHyeon 	if (error) {
2607943787f3SPyun YongHyeon 		device_printf(sc->bge_dev,
2608943787f3SPyun YongHyeon 		    "can't create spare DMA map for RX\n");
2609943787f3SPyun YongHyeon 		return (ENOMEM);
2610943787f3SPyun YongHyeon 	}
2611f41ac2beSBill Paul 	for (i = 0; i < BGE_STD_RX_RING_CNT; i++) {
26120ac56796SPyun YongHyeon 		error = bus_dmamap_create(sc->bge_cdata.bge_rx_mtag, 0,
2613f41ac2beSBill Paul 			    &sc->bge_cdata.bge_rx_std_dmamap[i]);
2614f41ac2beSBill Paul 		if (error) {
2615fe806fdaSPyun YongHyeon 			device_printf(sc->bge_dev,
2616fe806fdaSPyun YongHyeon 			    "can't create DMA map for RX\n");
2617f41ac2beSBill Paul 			return (ENOMEM);
2618f41ac2beSBill Paul 		}
2619f41ac2beSBill Paul 	}
2620f41ac2beSBill Paul 
26213f74909aSGleb Smirnoff 	/* Create DMA maps for TX buffers. */
2622f41ac2beSBill Paul 	for (i = 0; i < BGE_TX_RING_CNT; i++) {
26230ac56796SPyun YongHyeon 		error = bus_dmamap_create(sc->bge_cdata.bge_tx_mtag, 0,
2624f41ac2beSBill Paul 			    &sc->bge_cdata.bge_tx_dmamap[i]);
2625f41ac2beSBill Paul 		if (error) {
2626fe806fdaSPyun YongHyeon 			device_printf(sc->bge_dev,
26270ac56796SPyun YongHyeon 			    "can't create DMA map for TX\n");
2628f41ac2beSBill Paul 			return (ENOMEM);
2629f41ac2beSBill Paul 		}
2630f41ac2beSBill Paul 	}
2631f41ac2beSBill Paul 
26325b610048SPyun YongHyeon 	/* Create tags for jumbo RX buffers. */
26334c0da0ffSGleb Smirnoff 	if (BGE_IS_JUMBO_CAPABLE(sc)) {
26345b610048SPyun YongHyeon 		error = bus_dma_tag_create(sc->bge_cdata.bge_buffer_tag,
26358a2e22deSScott Long 		    1, 0, BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL,
26361be6acb7SGleb Smirnoff 		    NULL, MJUM9BYTES, BGE_NSEG_JUMBO, PAGE_SIZE,
26371be6acb7SGleb Smirnoff 		    0, NULL, NULL, &sc->bge_cdata.bge_mtag_jumbo);
2638f41ac2beSBill Paul 		if (error) {
2639fe806fdaSPyun YongHyeon 			device_printf(sc->bge_dev,
26403f74909aSGleb Smirnoff 			    "could not allocate jumbo dma tag\n");
2641f41ac2beSBill Paul 			return (ENOMEM);
2642f41ac2beSBill Paul 		}
26433f74909aSGleb Smirnoff 		/* Create DMA maps for jumbo RX buffers. */
2644943787f3SPyun YongHyeon 		error = bus_dmamap_create(sc->bge_cdata.bge_mtag_jumbo,
2645943787f3SPyun YongHyeon 		    0, &sc->bge_cdata.bge_rx_jumbo_sparemap);
2646943787f3SPyun YongHyeon 		if (error) {
2647943787f3SPyun YongHyeon 			device_printf(sc->bge_dev,
26481b90d0bdSPyun YongHyeon 			    "can't create spare DMA map for jumbo RX\n");
2649943787f3SPyun YongHyeon 			return (ENOMEM);
2650943787f3SPyun YongHyeon 		}
2651f41ac2beSBill Paul 		for (i = 0; i < BGE_JUMBO_RX_RING_CNT; i++) {
2652f41ac2beSBill Paul 			error = bus_dmamap_create(sc->bge_cdata.bge_mtag_jumbo,
2653f41ac2beSBill Paul 				    0, &sc->bge_cdata.bge_rx_jumbo_dmamap[i]);
2654f41ac2beSBill Paul 			if (error) {
2655fe806fdaSPyun YongHyeon 				device_printf(sc->bge_dev,
26563f74909aSGleb Smirnoff 				    "can't create DMA map for jumbo RX\n");
2657f41ac2beSBill Paul 				return (ENOMEM);
2658f41ac2beSBill Paul 			}
2659f41ac2beSBill Paul 		}
2660f41ac2beSBill Paul 	}
2661f41ac2beSBill Paul 
2662f41ac2beSBill Paul 	return (0);
2663f41ac2beSBill Paul }
2664f41ac2beSBill Paul 
2665bf6ef57aSJohn Polstra /*
2666bf6ef57aSJohn Polstra  * Return true if this device has more than one port.
2667bf6ef57aSJohn Polstra  */
2668bf6ef57aSJohn Polstra static int
2669bf6ef57aSJohn Polstra bge_has_multiple_ports(struct bge_softc *sc)
2670bf6ef57aSJohn Polstra {
2671bf6ef57aSJohn Polstra 	device_t dev = sc->bge_dev;
267255aaf894SMarius Strobl 	u_int b, d, f, fscan, s;
2673bf6ef57aSJohn Polstra 
267455aaf894SMarius Strobl 	d = pci_get_domain(dev);
2675bf6ef57aSJohn Polstra 	b = pci_get_bus(dev);
2676bf6ef57aSJohn Polstra 	s = pci_get_slot(dev);
2677bf6ef57aSJohn Polstra 	f = pci_get_function(dev);
2678bf6ef57aSJohn Polstra 	for (fscan = 0; fscan <= PCI_FUNCMAX; fscan++)
267955aaf894SMarius Strobl 		if (fscan != f && pci_find_dbsf(d, b, s, fscan) != NULL)
2680bf6ef57aSJohn Polstra 			return (1);
2681bf6ef57aSJohn Polstra 	return (0);
2682bf6ef57aSJohn Polstra }
2683bf6ef57aSJohn Polstra 
2684bf6ef57aSJohn Polstra /*
2685bf6ef57aSJohn Polstra  * Return true if MSI can be used with this device.
2686bf6ef57aSJohn Polstra  */
2687bf6ef57aSJohn Polstra static int
2688bf6ef57aSJohn Polstra bge_can_use_msi(struct bge_softc *sc)
2689bf6ef57aSJohn Polstra {
2690bf6ef57aSJohn Polstra 	int can_use_msi = 0;
2691bf6ef57aSJohn Polstra 
26921108273aSPyun YongHyeon 	/* Disable MSI for polling(4). */
26931108273aSPyun YongHyeon #ifdef DEVICE_POLLING
26941108273aSPyun YongHyeon 	return (0);
26951108273aSPyun YongHyeon #endif
2696bf6ef57aSJohn Polstra 	switch (sc->bge_asicrev) {
2697a8376f70SMarius Strobl 	case BGE_ASICREV_BCM5714_A0:
2698bf6ef57aSJohn Polstra 	case BGE_ASICREV_BCM5714:
2699bf6ef57aSJohn Polstra 		/*
2700a8376f70SMarius Strobl 		 * Apparently, MSI doesn't work when these chips are
2701a8376f70SMarius Strobl 		 * configured in single-port mode.
2702bf6ef57aSJohn Polstra 		 */
2703bf6ef57aSJohn Polstra 		if (bge_has_multiple_ports(sc))
2704bf6ef57aSJohn Polstra 			can_use_msi = 1;
2705bf6ef57aSJohn Polstra 		break;
2706bf6ef57aSJohn Polstra 	case BGE_ASICREV_BCM5750:
2707bf6ef57aSJohn Polstra 		if (sc->bge_chiprev != BGE_CHIPREV_5750_AX &&
2708bf6ef57aSJohn Polstra 		    sc->bge_chiprev != BGE_CHIPREV_5750_BX)
2709bf6ef57aSJohn Polstra 			can_use_msi = 1;
2710bf6ef57aSJohn Polstra 		break;
2711a8376f70SMarius Strobl 	default:
2712a8376f70SMarius Strobl 		if (BGE_IS_575X_PLUS(sc))
2713bf6ef57aSJohn Polstra 			can_use_msi = 1;
2714bf6ef57aSJohn Polstra 	}
2715bf6ef57aSJohn Polstra 	return (can_use_msi);
2716bf6ef57aSJohn Polstra }
2717bf6ef57aSJohn Polstra 
271895d67482SBill Paul static int
27193f74909aSGleb Smirnoff bge_attach(device_t dev)
272095d67482SBill Paul {
272195d67482SBill Paul 	struct ifnet *ifp;
272295d67482SBill Paul 	struct bge_softc *sc;
27234f0794ffSBjoern A. Zeeb 	uint32_t hwcfg = 0, misccfg;
272408013fd3SMarius Strobl 	u_char eaddr[ETHER_ADDR_LEN];
2725fb772a6cSMarius Strobl 	int capmask, error, f, msicount, phy_addr, reg, rid, trys;
272695d67482SBill Paul 
272795d67482SBill Paul 	sc = device_get_softc(dev);
272895d67482SBill Paul 	sc->bge_dev = dev;
272995d67482SBill Paul 
2730dfe0df9aSPyun YongHyeon 	TASK_INIT(&sc->bge_intr_task, 0, bge_intr_task, sc);
2731dfe0df9aSPyun YongHyeon 
273295d67482SBill Paul 	/*
273395d67482SBill Paul 	 * Map control/status registers.
273495d67482SBill Paul 	 */
273595d67482SBill Paul 	pci_enable_busmaster(dev);
273695d67482SBill Paul 
2737736b9319SPyun YongHyeon 	rid = PCIR_BAR(0);
27385f96beb9SNate Lawson 	sc->bge_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
273944f8f2fcSMarius Strobl 	    RF_ACTIVE);
274095d67482SBill Paul 
274195d67482SBill Paul 	if (sc->bge_res == NULL) {
2742fe806fdaSPyun YongHyeon 		device_printf (sc->bge_dev, "couldn't map memory\n");
274395d67482SBill Paul 		error = ENXIO;
274495d67482SBill Paul 		goto fail;
274595d67482SBill Paul 	}
274695d67482SBill Paul 
27474f09c4c7SMarius Strobl 	/* Save various chip information. */
2748e53d81eeSPaul Saab 	sc->bge_chipid =
2749a5779553SStanislav Sedov 	    pci_read_config(dev, BGE_PCI_MISC_CTL, 4) >>
2750a5779553SStanislav Sedov 	    BGE_PCIMISCCTL_ASICREV_SHIFT;
27511108273aSPyun YongHyeon 	if (BGE_ASICREV(sc->bge_chipid) == BGE_ASICREV_USE_PRODID_REG) {
27521108273aSPyun YongHyeon 		/*
27531108273aSPyun YongHyeon 		 * Find the ASCI revision.  Different chips use different
27541108273aSPyun YongHyeon 		 * registers.
27551108273aSPyun YongHyeon 		 */
27561108273aSPyun YongHyeon 		switch (pci_get_device(dev)) {
27571108273aSPyun YongHyeon 		case BCOM_DEVICEID_BCM5717:
27581108273aSPyun YongHyeon 		case BCOM_DEVICEID_BCM5718:
2759bbe2ca75SPyun YongHyeon 		case BCOM_DEVICEID_BCM5719:
27601108273aSPyun YongHyeon 			sc->bge_chipid = pci_read_config(dev,
27611108273aSPyun YongHyeon 			    BGE_PCI_GEN2_PRODID_ASICREV, 4);
27621108273aSPyun YongHyeon 			break;
2763b4a256acSPyun YongHyeon 		case BCOM_DEVICEID_BCM57761:
2764b4a256acSPyun YongHyeon 		case BCOM_DEVICEID_BCM57765:
2765b4a256acSPyun YongHyeon 		case BCOM_DEVICEID_BCM57781:
2766b4a256acSPyun YongHyeon 		case BCOM_DEVICEID_BCM57785:
2767b4a256acSPyun YongHyeon 		case BCOM_DEVICEID_BCM57791:
2768b4a256acSPyun YongHyeon 		case BCOM_DEVICEID_BCM57795:
2769b4a256acSPyun YongHyeon 			sc->bge_chipid = pci_read_config(dev,
2770b4a256acSPyun YongHyeon 			    BGE_PCI_GEN15_PRODID_ASICREV, 4);
2771b4a256acSPyun YongHyeon 			break;
27721108273aSPyun YongHyeon 		default:
27731108273aSPyun YongHyeon 			sc->bge_chipid = pci_read_config(dev,
27741108273aSPyun YongHyeon 			    BGE_PCI_PRODID_ASICREV, 4);
27751108273aSPyun YongHyeon 		}
27761108273aSPyun YongHyeon 	}
2777e53d81eeSPaul Saab 	sc->bge_asicrev = BGE_ASICREV(sc->bge_chipid);
2778e53d81eeSPaul Saab 	sc->bge_chiprev = BGE_CHIPREV(sc->bge_chipid);
2779e53d81eeSPaul Saab 
2780a813ed78SPyun YongHyeon 	/* Set default PHY address. */
27818e5d93dbSMarius Strobl 	phy_addr = 1;
27821108273aSPyun YongHyeon 	 /*
27831108273aSPyun YongHyeon 	  * PHY address mapping for various devices.
27841108273aSPyun YongHyeon 	  *
27851108273aSPyun YongHyeon 	  *          | F0 Cu | F0 Sr | F1 Cu | F1 Sr |
27861108273aSPyun YongHyeon 	  * ---------+-------+-------+-------+-------+
27871108273aSPyun YongHyeon 	  * BCM57XX  |   1   |   X   |   X   |   X   |
27881108273aSPyun YongHyeon 	  * BCM5704  |   1   |   X   |   1   |   X   |
27891108273aSPyun YongHyeon 	  * BCM5717  |   1   |   8   |   2   |   9   |
2790bbe2ca75SPyun YongHyeon 	  * BCM5719  |   1   |   8   |   2   |   9   |
27911108273aSPyun YongHyeon 	  *
27921108273aSPyun YongHyeon 	  * Other addresses may respond but they are not
27931108273aSPyun YongHyeon 	  * IEEE compliant PHYs and should be ignored.
27941108273aSPyun YongHyeon 	  */
2795bbe2ca75SPyun YongHyeon 	if (sc->bge_asicrev == BGE_ASICREV_BCM5717 ||
2796bbe2ca75SPyun YongHyeon 	    sc->bge_asicrev == BGE_ASICREV_BCM5719) {
27971108273aSPyun YongHyeon 		f = pci_get_function(dev);
27981108273aSPyun YongHyeon 		if (sc->bge_chipid == BGE_CHIPID_BCM5717_A0) {
27991108273aSPyun YongHyeon 			if (CSR_READ_4(sc, BGE_SGDIG_STS) &
28001108273aSPyun YongHyeon 			    BGE_SGDIGSTS_IS_SERDES)
28011108273aSPyun YongHyeon 				phy_addr = f + 8;
28021108273aSPyun YongHyeon 			else
28031108273aSPyun YongHyeon 				phy_addr = f + 1;
2804bbe2ca75SPyun YongHyeon 		} else {
28051108273aSPyun YongHyeon 			if (CSR_READ_4(sc, BGE_CPMU_PHY_STRAP) &
28061108273aSPyun YongHyeon 			    BGE_CPMU_PHY_STRAP_IS_SERDES)
28071108273aSPyun YongHyeon 				phy_addr = f + 8;
28081108273aSPyun YongHyeon 			else
28091108273aSPyun YongHyeon 				phy_addr = f + 1;
28101108273aSPyun YongHyeon 		}
28111108273aSPyun YongHyeon 	}
2812a813ed78SPyun YongHyeon 
281386543395SJung-uk Kim 	/*
281438cc658fSJohn Baldwin 	 * Don't enable Ethernet@WireSpeed for the 5700, 5906, or the
281586543395SJung-uk Kim 	 * 5705 A0 and A1 chips.
281686543395SJung-uk Kim 	 */
2817cb777a07SPyun YongHyeon 	if (sc->bge_asicrev == BGE_ASICREV_BCM5700 ||
2818cb777a07SPyun YongHyeon 	    (sc->bge_asicrev == BGE_ASICREV_BCM5705 &&
2819cb777a07SPyun YongHyeon 	    (sc->bge_chipid != BGE_CHIPID_BCM5705_A0 &&
2820cb777a07SPyun YongHyeon 	    sc->bge_chipid != BGE_CHIPID_BCM5705_A1)) ||
2821cb777a07SPyun YongHyeon 	    sc->bge_asicrev == BGE_ASICREV_BCM5906)
2822cb777a07SPyun YongHyeon 		sc->bge_phy_flags |= BGE_PHY_NO_WIRESPEED;
282386543395SJung-uk Kim 
28245fea260fSMarius Strobl 	if (bge_has_eaddr(sc))
28255fea260fSMarius Strobl 		sc->bge_flags |= BGE_FLAG_EADDR;
282608013fd3SMarius Strobl 
28270dae9719SJung-uk Kim 	/* Save chipset family. */
28280dae9719SJung-uk Kim 	switch (sc->bge_asicrev) {
28291108273aSPyun YongHyeon 	case BGE_ASICREV_BCM5717:
2830bbe2ca75SPyun YongHyeon 	case BGE_ASICREV_BCM5719:
2831b4a256acSPyun YongHyeon 	case BGE_ASICREV_BCM57765:
28321108273aSPyun YongHyeon 		sc->bge_flags |= BGE_FLAG_5717_PLUS | BGE_FLAG_5755_PLUS |
28331108273aSPyun YongHyeon 		    BGE_FLAG_575X_PLUS | BGE_FLAG_5705_PLUS | BGE_FLAG_JUMBO |
2834b4a256acSPyun YongHyeon 		    BGE_FLAG_JUMBO_FRAME;
2835bbe2ca75SPyun YongHyeon 		if (sc->bge_asicrev == BGE_ASICREV_BCM5719 &&
2836bbe2ca75SPyun YongHyeon 		    sc->bge_chipid == BGE_CHIPID_BCM5719_A0) {
2837bbe2ca75SPyun YongHyeon 			/* Jumbo frame on BCM5719 A0 does not work. */
2838463a7e27SPyun YongHyeon 			sc->bge_flags &= ~BGE_FLAG_JUMBO;
2839bbe2ca75SPyun YongHyeon 		}
28401108273aSPyun YongHyeon 		break;
2841a5779553SStanislav Sedov 	case BGE_ASICREV_BCM5755:
2842a5779553SStanislav Sedov 	case BGE_ASICREV_BCM5761:
2843a5779553SStanislav Sedov 	case BGE_ASICREV_BCM5784:
2844a5779553SStanislav Sedov 	case BGE_ASICREV_BCM5785:
2845a5779553SStanislav Sedov 	case BGE_ASICREV_BCM5787:
2846a5779553SStanislav Sedov 	case BGE_ASICREV_BCM57780:
2847a5779553SStanislav Sedov 		sc->bge_flags |= BGE_FLAG_5755_PLUS | BGE_FLAG_575X_PLUS |
2848a5779553SStanislav Sedov 		    BGE_FLAG_5705_PLUS;
2849a5779553SStanislav Sedov 		break;
28500dae9719SJung-uk Kim 	case BGE_ASICREV_BCM5700:
28510dae9719SJung-uk Kim 	case BGE_ASICREV_BCM5701:
28520dae9719SJung-uk Kim 	case BGE_ASICREV_BCM5703:
28530dae9719SJung-uk Kim 	case BGE_ASICREV_BCM5704:
28547ee00338SJung-uk Kim 		sc->bge_flags |= BGE_FLAG_5700_FAMILY | BGE_FLAG_JUMBO;
28550dae9719SJung-uk Kim 		break;
28560dae9719SJung-uk Kim 	case BGE_ASICREV_BCM5714_A0:
28570dae9719SJung-uk Kim 	case BGE_ASICREV_BCM5780:
28580dae9719SJung-uk Kim 	case BGE_ASICREV_BCM5714:
2859f5459d4cSPyun YongHyeon 		sc->bge_flags |= BGE_FLAG_5714_FAMILY | BGE_FLAG_JUMBO_STD;
28609fe569d8SXin LI 		/* FALLTHROUGH */
28610dae9719SJung-uk Kim 	case BGE_ASICREV_BCM5750:
28620dae9719SJung-uk Kim 	case BGE_ASICREV_BCM5752:
286338cc658fSJohn Baldwin 	case BGE_ASICREV_BCM5906:
28640dae9719SJung-uk Kim 		sc->bge_flags |= BGE_FLAG_575X_PLUS;
28659fe569d8SXin LI 		/* FALLTHROUGH */
28660dae9719SJung-uk Kim 	case BGE_ASICREV_BCM5705:
28670dae9719SJung-uk Kim 		sc->bge_flags |= BGE_FLAG_5705_PLUS;
28680dae9719SJung-uk Kim 		break;
28690dae9719SJung-uk Kim 	}
28700dae9719SJung-uk Kim 
2871757402fbSPyun YongHyeon 	/* Set various PHY bug flags. */
28721ec4c3a8SJung-uk Kim 	if (sc->bge_chipid == BGE_CHIPID_BCM5701_A0 ||
28731ec4c3a8SJung-uk Kim 	    sc->bge_chipid == BGE_CHIPID_BCM5701_B0)
2874757402fbSPyun YongHyeon 		sc->bge_phy_flags |= BGE_PHY_CRC_BUG;
28755ee49a3aSJung-uk Kim 	if (sc->bge_chiprev == BGE_CHIPREV_5703_AX ||
28765ee49a3aSJung-uk Kim 	    sc->bge_chiprev == BGE_CHIPREV_5704_AX)
2877757402fbSPyun YongHyeon 		sc->bge_phy_flags |= BGE_PHY_ADC_BUG;
28785ee49a3aSJung-uk Kim 	if (sc->bge_chipid == BGE_CHIPID_BCM5704_A0)
2879757402fbSPyun YongHyeon 		sc->bge_phy_flags |= BGE_PHY_5704_A0_BUG;
28804150ce6fSPyun YongHyeon 	if (pci_get_subvendor(dev) == DELL_VENDORID)
2881757402fbSPyun YongHyeon 		sc->bge_phy_flags |= BGE_PHY_NO_3LED;
2882eea8956aSPyun YongHyeon 	if ((BGE_IS_5705_PLUS(sc)) &&
2883eea8956aSPyun YongHyeon 	    sc->bge_asicrev != BGE_ASICREV_BCM5906 &&
28841108273aSPyun YongHyeon 	    sc->bge_asicrev != BGE_ASICREV_BCM5717 &&
2885bbe2ca75SPyun YongHyeon 	    sc->bge_asicrev != BGE_ASICREV_BCM5719 &&
2886eea8956aSPyun YongHyeon 	    sc->bge_asicrev != BGE_ASICREV_BCM5785 &&
2887b4a256acSPyun YongHyeon 	    sc->bge_asicrev != BGE_ASICREV_BCM57765 &&
2888eea8956aSPyun YongHyeon 	    sc->bge_asicrev != BGE_ASICREV_BCM57780) {
28895ee49a3aSJung-uk Kim 		if (sc->bge_asicrev == BGE_ASICREV_BCM5755 ||
2890a5779553SStanislav Sedov 		    sc->bge_asicrev == BGE_ASICREV_BCM5761 ||
2891a5779553SStanislav Sedov 		    sc->bge_asicrev == BGE_ASICREV_BCM5784 ||
28924fcf220bSJohn Baldwin 		    sc->bge_asicrev == BGE_ASICREV_BCM5787) {
2893f7d1b2ebSXin LI 			if (pci_get_device(dev) != BCOM_DEVICEID_BCM5722 &&
2894f7d1b2ebSXin LI 			    pci_get_device(dev) != BCOM_DEVICEID_BCM5756)
2895757402fbSPyun YongHyeon 				sc->bge_phy_flags |= BGE_PHY_JITTER_BUG;
2896eea8956aSPyun YongHyeon 			if (pci_get_device(dev) == BCOM_DEVICEID_BCM5755M)
2897eea8956aSPyun YongHyeon 				sc->bge_phy_flags |= BGE_PHY_ADJUST_TRIM;
2898eea8956aSPyun YongHyeon 		} else
2899757402fbSPyun YongHyeon 			sc->bge_phy_flags |= BGE_PHY_BER_BUG;
29005ee49a3aSJung-uk Kim 	}
29015ee49a3aSJung-uk Kim 
2902a813ed78SPyun YongHyeon 	/* Identify the chips that use an CPMU. */
29031108273aSPyun YongHyeon 	if (BGE_IS_5717_PLUS(sc) ||
29041108273aSPyun YongHyeon 	    sc->bge_asicrev == BGE_ASICREV_BCM5784 ||
2905a813ed78SPyun YongHyeon 	    sc->bge_asicrev == BGE_ASICREV_BCM5761 ||
2906a813ed78SPyun YongHyeon 	    sc->bge_asicrev == BGE_ASICREV_BCM5785 ||
2907a813ed78SPyun YongHyeon 	    sc->bge_asicrev == BGE_ASICREV_BCM57780)
2908a813ed78SPyun YongHyeon 		sc->bge_flags |= BGE_FLAG_CPMU_PRESENT;
2909a813ed78SPyun YongHyeon 	if ((sc->bge_flags & BGE_FLAG_CPMU_PRESENT) != 0)
2910a813ed78SPyun YongHyeon 		sc->bge_mi_mode = BGE_MIMODE_500KHZ_CONST;
2911a813ed78SPyun YongHyeon 	else
2912a813ed78SPyun YongHyeon 		sc->bge_mi_mode = BGE_MIMODE_BASE;
29137ed3f0f0SPyun YongHyeon 	/* Enable auto polling for BCM570[0-5]. */
29147ed3f0f0SPyun YongHyeon 	if (BGE_IS_5700_FAMILY(sc) || sc->bge_asicrev == BGE_ASICREV_BCM5705)
29157ed3f0f0SPyun YongHyeon 		sc->bge_mi_mode |= BGE_MIMODE_AUTOPOLL;
2916a813ed78SPyun YongHyeon 
2917f681b29aSPyun YongHyeon 	/*
2918d4622124SPyun YongHyeon 	 * All Broadcom controllers have 4GB boundary DMA bug.
2919f681b29aSPyun YongHyeon 	 * Whenever an address crosses a multiple of the 4GB boundary
2920f681b29aSPyun YongHyeon 	 * (including 4GB, 8Gb, 12Gb, etc.) and makes the transition
2921f681b29aSPyun YongHyeon 	 * from 0xX_FFFF_FFFF to 0x(X+1)_0000_0000 an internal DMA
2922f681b29aSPyun YongHyeon 	 * state machine will lockup and cause the device to hang.
2923f681b29aSPyun YongHyeon 	 */
2924f681b29aSPyun YongHyeon 	sc->bge_flags |= BGE_FLAG_4G_BNDRY_BUG;
29254f0794ffSBjoern A. Zeeb 
2926d9820cd8SPyun YongHyeon 	/* BCM5755 or higher and BCM5906 have short DMA bug. */
2927d9820cd8SPyun YongHyeon 	if (BGE_IS_5755_PLUS(sc) || sc->bge_asicrev == BGE_ASICREV_BCM5906)
2928d9820cd8SPyun YongHyeon 		sc->bge_flags |= BGE_FLAG_SHORT_DMA_BUG;
2929d9820cd8SPyun YongHyeon 
2930a7fcfcf3SPyun YongHyeon 	/*
2931a7fcfcf3SPyun YongHyeon 	 * BCM5719 cannot handle DMA requests for DMA segments that
2932a7fcfcf3SPyun YongHyeon 	 * have larger than 4KB in size.  However the maximum DMA
2933a7fcfcf3SPyun YongHyeon 	 * segment size created in DMA tag is 4KB for TSO, so we
2934a7fcfcf3SPyun YongHyeon 	 * wouldn't encounter the issue here.
2935a7fcfcf3SPyun YongHyeon 	 */
2936a7fcfcf3SPyun YongHyeon 	if (sc->bge_asicrev == BGE_ASICREV_BCM5719)
2937a7fcfcf3SPyun YongHyeon 		sc->bge_flags |= BGE_FLAG_4K_RDMA_BUG;
2938a7fcfcf3SPyun YongHyeon 
29394f0794ffSBjoern A. Zeeb 	misccfg = CSR_READ_4(sc, BGE_MISC_CFG) & BGE_MISCCFG_BOARD_ID;
2940fb772a6cSMarius Strobl 	if (sc->bge_asicrev == BGE_ASICREV_BCM5705) {
29414f0794ffSBjoern A. Zeeb 		if (misccfg == BGE_MISCCFG_BOARD_ID_5788 ||
29424f0794ffSBjoern A. Zeeb 		    misccfg == BGE_MISCCFG_BOARD_ID_5788M)
29434f0794ffSBjoern A. Zeeb 			sc->bge_flags |= BGE_FLAG_5788;
294484ac96f8SPyun YongHyeon 	}
29454f0794ffSBjoern A. Zeeb 
2946fb772a6cSMarius Strobl 	capmask = BMSR_DEFCAPMASK;
2947fb772a6cSMarius Strobl 	if ((sc->bge_asicrev == BGE_ASICREV_BCM5703 &&
2948fb772a6cSMarius Strobl 	    (misccfg == 0x4000 || misccfg == 0x8000)) ||
2949fb772a6cSMarius Strobl 	    (sc->bge_asicrev == BGE_ASICREV_BCM5705 &&
2950fb772a6cSMarius Strobl 	    pci_get_vendor(dev) == BCOM_VENDORID &&
2951fb772a6cSMarius Strobl 	    (pci_get_device(dev) == BCOM_DEVICEID_BCM5901 ||
2952fb772a6cSMarius Strobl 	    pci_get_device(dev) == BCOM_DEVICEID_BCM5901A2 ||
2953fb772a6cSMarius Strobl 	    pci_get_device(dev) == BCOM_DEVICEID_BCM5705F)) ||
2954fb772a6cSMarius Strobl 	    (pci_get_vendor(dev) == BCOM_VENDORID &&
2955fb772a6cSMarius Strobl 	    (pci_get_device(dev) == BCOM_DEVICEID_BCM5751F ||
2956fb772a6cSMarius Strobl 	    pci_get_device(dev) == BCOM_DEVICEID_BCM5753F ||
2957fb772a6cSMarius Strobl 	    pci_get_device(dev) == BCOM_DEVICEID_BCM5787F)) ||
2958fb772a6cSMarius Strobl 	    pci_get_device(dev) == BCOM_DEVICEID_BCM57790 ||
2959fb772a6cSMarius Strobl 	    sc->bge_asicrev == BGE_ASICREV_BCM5906) {
2960fb772a6cSMarius Strobl 		/* These chips are 10/100 only. */
2961fb772a6cSMarius Strobl 		capmask &= ~BMSR_EXTSTAT;
2962fb772a6cSMarius Strobl 	}
2963fb772a6cSMarius Strobl 
2964e53d81eeSPaul Saab 	/*
2965ca3f1187SPyun YongHyeon 	 * Some controllers seem to require a special firmware to use
2966ca3f1187SPyun YongHyeon 	 * TSO. But the firmware is not available to FreeBSD and Linux
2967ca3f1187SPyun YongHyeon 	 * claims that the TSO performed by the firmware is slower than
2968ca3f1187SPyun YongHyeon 	 * hardware based TSO. Moreover the firmware based TSO has one
2969ca3f1187SPyun YongHyeon 	 * known bug which can't handle TSO if ethernet header + IP/TCP
2970ca3f1187SPyun YongHyeon 	 * header is greater than 80 bytes. The workaround for the TSO
2971ca3f1187SPyun YongHyeon 	 * bug exist but it seems it's too expensive than not using
2972ca3f1187SPyun YongHyeon 	 * TSO at all. Some hardwares also have the TSO bug so limit
2973ca3f1187SPyun YongHyeon 	 * the TSO to the controllers that are not affected TSO issues
2974ca3f1187SPyun YongHyeon 	 * (e.g. 5755 or higher).
2975ca3f1187SPyun YongHyeon 	 */
29761108273aSPyun YongHyeon 	if (BGE_IS_5717_PLUS(sc)) {
29771108273aSPyun YongHyeon 		/* BCM5717 requires different TSO configuration. */
29781108273aSPyun YongHyeon 		sc->bge_flags |= BGE_FLAG_TSO3;
2979bbe2ca75SPyun YongHyeon 		if (sc->bge_asicrev == BGE_ASICREV_BCM5719 &&
2980bbe2ca75SPyun YongHyeon 		    sc->bge_chipid == BGE_CHIPID_BCM5719_A0) {
2981bbe2ca75SPyun YongHyeon 			/* TSO on BCM5719 A0 does not work. */
2982bbe2ca75SPyun YongHyeon 			sc->bge_flags &= ~BGE_FLAG_TSO3;
2983bbe2ca75SPyun YongHyeon 		}
29841108273aSPyun YongHyeon 	} else if (BGE_IS_5755_PLUS(sc)) {
29854f4a16e1SPyun YongHyeon 		/*
29864f4a16e1SPyun YongHyeon 		 * BCM5754 and BCM5787 shares the same ASIC id so
29874f4a16e1SPyun YongHyeon 		 * explicit device id check is required.
2988be95548dSPyun YongHyeon 		 * Due to unknown reason TSO does not work on BCM5755M.
29894f4a16e1SPyun YongHyeon 		 */
29904f4a16e1SPyun YongHyeon 		if (pci_get_device(dev) != BCOM_DEVICEID_BCM5754 &&
2991be95548dSPyun YongHyeon 		    pci_get_device(dev) != BCOM_DEVICEID_BCM5754M &&
2992be95548dSPyun YongHyeon 		    pci_get_device(dev) != BCOM_DEVICEID_BCM5755M)
2993ca3f1187SPyun YongHyeon 			sc->bge_flags |= BGE_FLAG_TSO;
29944f4a16e1SPyun YongHyeon 	}
2995ca3f1187SPyun YongHyeon 
2996ca3f1187SPyun YongHyeon 	/*
29976f8718a3SScott Long 	 * Check if this is a PCI-X or PCI Express device.
2998e53d81eeSPaul Saab 	 */
29993b0a4aefSJohn Baldwin 	if (pci_find_cap(dev, PCIY_EXPRESS, &reg) == 0) {
30004c0da0ffSGleb Smirnoff 		/*
30016f8718a3SScott Long 		 * Found a PCI Express capabilities register, this
30026f8718a3SScott Long 		 * must be a PCI Express device.
30036f8718a3SScott Long 		 */
30046f8718a3SScott Long 		sc->bge_flags |= BGE_FLAG_PCIE;
30050aaf1057SPyun YongHyeon 		sc->bge_expcap = reg;
3006bbe2ca75SPyun YongHyeon 		if (sc->bge_asicrev == BGE_ASICREV_BCM5719)
3007bbe2ca75SPyun YongHyeon 			pci_set_max_read_req(dev, 2048);
3008bbe2ca75SPyun YongHyeon 		else if (pci_get_max_read_req(dev) != 4096)
3009d2b6e9a0SPyun YongHyeon 			pci_set_max_read_req(dev, 4096);
30106f8718a3SScott Long 	} else {
30116f8718a3SScott Long 		/*
30126f8718a3SScott Long 		 * Check if the device is in PCI-X Mode.
30136f8718a3SScott Long 		 * (This bit is not valid on PCI Express controllers.)
30144c0da0ffSGleb Smirnoff 		 */
30153b0a4aefSJohn Baldwin 		if (pci_find_cap(dev, PCIY_PCIX, &reg) == 0)
30160aaf1057SPyun YongHyeon 			sc->bge_pcixcap = reg;
301790447aadSMarius Strobl 		if ((pci_read_config(dev, BGE_PCI_PCISTATE, 4) &
30184c0da0ffSGleb Smirnoff 		    BGE_PCISTATE_PCI_BUSMODE) == 0)
3019652ae483SGleb Smirnoff 			sc->bge_flags |= BGE_FLAG_PCIX;
30206f8718a3SScott Long 	}
30214c0da0ffSGleb Smirnoff 
3022bf6ef57aSJohn Polstra 	/*
3023fd4d32feSPyun YongHyeon 	 * The 40bit DMA bug applies to the 5714/5715 controllers and is
3024fd4d32feSPyun YongHyeon 	 * not actually a MAC controller bug but an issue with the embedded
3025fd4d32feSPyun YongHyeon 	 * PCIe to PCI-X bridge in the device. Use 40bit DMA workaround.
3026fd4d32feSPyun YongHyeon 	 */
3027fd4d32feSPyun YongHyeon 	if (BGE_IS_5714_FAMILY(sc) && (sc->bge_flags & BGE_FLAG_PCIX))
3028fd4d32feSPyun YongHyeon 		sc->bge_flags |= BGE_FLAG_40BIT_BUG;
3029fd4d32feSPyun YongHyeon 	/*
3030bf6ef57aSJohn Polstra 	 * Allocate the interrupt, using MSI if possible.  These devices
3031bf6ef57aSJohn Polstra 	 * support 8 MSI messages, but only the first one is used in
3032bf6ef57aSJohn Polstra 	 * normal operation.
3033bf6ef57aSJohn Polstra 	 */
30340aaf1057SPyun YongHyeon 	rid = 0;
30353b0a4aefSJohn Baldwin 	if (pci_find_cap(sc->bge_dev, PCIY_MSI, &reg) == 0) {
30360aaf1057SPyun YongHyeon 		sc->bge_msicap = reg;
3037bf6ef57aSJohn Polstra 		if (bge_can_use_msi(sc)) {
3038bf6ef57aSJohn Polstra 			msicount = pci_msi_count(dev);
3039bf6ef57aSJohn Polstra 			if (msicount > 1)
3040bf6ef57aSJohn Polstra 				msicount = 1;
3041bf6ef57aSJohn Polstra 		} else
3042bf6ef57aSJohn Polstra 			msicount = 0;
3043bf6ef57aSJohn Polstra 		if (msicount == 1 && pci_alloc_msi(dev, &msicount) == 0) {
3044bf6ef57aSJohn Polstra 			rid = 1;
3045bf6ef57aSJohn Polstra 			sc->bge_flags |= BGE_FLAG_MSI;
30460aaf1057SPyun YongHyeon 		}
30470aaf1057SPyun YongHyeon 	}
3048bf6ef57aSJohn Polstra 
30491108273aSPyun YongHyeon 	/*
30501108273aSPyun YongHyeon 	 * All controllers except BCM5700 supports tagged status but
30511108273aSPyun YongHyeon 	 * we use tagged status only for MSI case on BCM5717. Otherwise
30521108273aSPyun YongHyeon 	 * MSI on BCM5717 does not work.
30531108273aSPyun YongHyeon 	 */
30541108273aSPyun YongHyeon #ifndef DEVICE_POLLING
30551108273aSPyun YongHyeon 	if (sc->bge_flags & BGE_FLAG_MSI && BGE_IS_5717_PLUS(sc))
30561108273aSPyun YongHyeon 		sc->bge_flags |= BGE_FLAG_TAGGED_STATUS;
30571108273aSPyun YongHyeon #endif
30581108273aSPyun YongHyeon 
3059bf6ef57aSJohn Polstra 	sc->bge_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
3060bf6ef57aSJohn Polstra 	    RF_SHAREABLE | RF_ACTIVE);
3061bf6ef57aSJohn Polstra 
3062bf6ef57aSJohn Polstra 	if (sc->bge_irq == NULL) {
3063bf6ef57aSJohn Polstra 		device_printf(sc->bge_dev, "couldn't map interrupt\n");
3064bf6ef57aSJohn Polstra 		error = ENXIO;
3065bf6ef57aSJohn Polstra 		goto fail;
3066bf6ef57aSJohn Polstra 	}
3067bf6ef57aSJohn Polstra 
30684f09c4c7SMarius Strobl 	device_printf(dev,
30694f09c4c7SMarius Strobl 	    "CHIP ID 0x%08x; ASIC REV 0x%02x; CHIP REV 0x%02x; %s\n",
30704f09c4c7SMarius Strobl 	    sc->bge_chipid, sc->bge_asicrev, sc->bge_chiprev,
30714f09c4c7SMarius Strobl 	    (sc->bge_flags & BGE_FLAG_PCIX) ? "PCI-X" :
30724f09c4c7SMarius Strobl 	    ((sc->bge_flags & BGE_FLAG_PCIE) ? "PCI-E" : "PCI"));
30734f09c4c7SMarius Strobl 
3074bf6ef57aSJohn Polstra 	BGE_LOCK_INIT(sc, device_get_nameunit(dev));
3075bf6ef57aSJohn Polstra 
307695d67482SBill Paul 	/* Try to reset the chip. */
30778cb1383cSDoug Ambrisko 	if (bge_reset(sc)) {
30788cb1383cSDoug Ambrisko 		device_printf(sc->bge_dev, "chip reset failed\n");
30798cb1383cSDoug Ambrisko 		error = ENXIO;
30808cb1383cSDoug Ambrisko 		goto fail;
30818cb1383cSDoug Ambrisko 	}
30828cb1383cSDoug Ambrisko 
30838cb1383cSDoug Ambrisko 	sc->bge_asf_mode = 0;
3084888b47f0SPyun YongHyeon 	if (bge_allow_asf && (bge_readmem_ind(sc, BGE_SRAM_DATA_SIG) ==
3085888b47f0SPyun YongHyeon 	    BGE_SRAM_DATA_SIG_MAGIC)) {
3086888b47f0SPyun YongHyeon 		if (bge_readmem_ind(sc, BGE_SRAM_DATA_CFG)
30878cb1383cSDoug Ambrisko 		    & BGE_HWCFG_ASF) {
30888cb1383cSDoug Ambrisko 			sc->bge_asf_mode |= ASF_ENABLE;
30898cb1383cSDoug Ambrisko 			sc->bge_asf_mode |= ASF_STACKUP;
3090d67eba2fSPyun YongHyeon 			if (BGE_IS_575X_PLUS(sc))
30918cb1383cSDoug Ambrisko 				sc->bge_asf_mode |= ASF_NEW_HANDSHAKE;
30928cb1383cSDoug Ambrisko 		}
30938cb1383cSDoug Ambrisko 	}
30948cb1383cSDoug Ambrisko 
30958cb1383cSDoug Ambrisko 	/* Try to reset the chip again the nice way. */
30968cb1383cSDoug Ambrisko 	bge_stop_fw(sc);
30978cb1383cSDoug Ambrisko 	bge_sig_pre_reset(sc, BGE_RESET_STOP);
30988cb1383cSDoug Ambrisko 	if (bge_reset(sc)) {
30998cb1383cSDoug Ambrisko 		device_printf(sc->bge_dev, "chip reset failed\n");
31008cb1383cSDoug Ambrisko 		error = ENXIO;
31018cb1383cSDoug Ambrisko 		goto fail;
31028cb1383cSDoug Ambrisko 	}
31038cb1383cSDoug Ambrisko 
31048cb1383cSDoug Ambrisko 	bge_sig_legacy(sc, BGE_RESET_STOP);
31058cb1383cSDoug Ambrisko 	bge_sig_post_reset(sc, BGE_RESET_STOP);
310695d67482SBill Paul 
310795d67482SBill Paul 	if (bge_chipinit(sc)) {
3108fe806fdaSPyun YongHyeon 		device_printf(sc->bge_dev, "chip initialization failed\n");
310995d67482SBill Paul 		error = ENXIO;
311095d67482SBill Paul 		goto fail;
311195d67482SBill Paul 	}
311295d67482SBill Paul 
311338cc658fSJohn Baldwin 	error = bge_get_eaddr(sc, eaddr);
311438cc658fSJohn Baldwin 	if (error) {
311508013fd3SMarius Strobl 		device_printf(sc->bge_dev,
311608013fd3SMarius Strobl 		    "failed to read station address\n");
311795d67482SBill Paul 		error = ENXIO;
311895d67482SBill Paul 		goto fail;
311995d67482SBill Paul 	}
312095d67482SBill Paul 
3121f41ac2beSBill Paul 	/* 5705 limits RX return ring to 512 entries. */
31221108273aSPyun YongHyeon 	if (BGE_IS_5717_PLUS(sc))
31231108273aSPyun YongHyeon 		sc->bge_return_ring_cnt = BGE_RETURN_RING_CNT;
31241108273aSPyun YongHyeon 	else if (BGE_IS_5705_PLUS(sc))
3125f41ac2beSBill Paul 		sc->bge_return_ring_cnt = BGE_RETURN_RING_CNT_5705;
3126f41ac2beSBill Paul 	else
3127f41ac2beSBill Paul 		sc->bge_return_ring_cnt = BGE_RETURN_RING_CNT;
3128f41ac2beSBill Paul 
31295b610048SPyun YongHyeon 	if (bge_dma_alloc(sc)) {
3130fe806fdaSPyun YongHyeon 		device_printf(sc->bge_dev,
3131fe806fdaSPyun YongHyeon 		    "failed to allocate DMA resources\n");
3132f41ac2beSBill Paul 		error = ENXIO;
3133f41ac2beSBill Paul 		goto fail;
3134f41ac2beSBill Paul 	}
3135f41ac2beSBill Paul 
313635f945cdSPyun YongHyeon 	bge_add_sysctls(sc);
313735f945cdSPyun YongHyeon 
313895d67482SBill Paul 	/* Set default tuneable values. */
313995d67482SBill Paul 	sc->bge_stat_ticks = BGE_TICKS_PER_SEC;
314095d67482SBill Paul 	sc->bge_rx_coal_ticks = 150;
314195d67482SBill Paul 	sc->bge_tx_coal_ticks = 150;
31426f8718a3SScott Long 	sc->bge_rx_max_coal_bds = 10;
31436f8718a3SScott Long 	sc->bge_tx_max_coal_bds = 10;
314495d67482SBill Paul 
314535f945cdSPyun YongHyeon 	/* Initialize checksum features to use. */
314635f945cdSPyun YongHyeon 	sc->bge_csum_features = BGE_CSUM_FEATURES;
314735f945cdSPyun YongHyeon 	if (sc->bge_forced_udpcsum != 0)
314835f945cdSPyun YongHyeon 		sc->bge_csum_features |= CSUM_UDP;
314935f945cdSPyun YongHyeon 
315095d67482SBill Paul 	/* Set up ifnet structure */
3151fc74a9f9SBrooks Davis 	ifp = sc->bge_ifp = if_alloc(IFT_ETHER);
3152fc74a9f9SBrooks Davis 	if (ifp == NULL) {
3153fe806fdaSPyun YongHyeon 		device_printf(sc->bge_dev, "failed to if_alloc()\n");
3154fc74a9f9SBrooks Davis 		error = ENXIO;
3155fc74a9f9SBrooks Davis 		goto fail;
3156fc74a9f9SBrooks Davis 	}
315795d67482SBill Paul 	ifp->if_softc = sc;
31589bf40edeSBrooks Davis 	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
315995d67482SBill Paul 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
316095d67482SBill Paul 	ifp->if_ioctl = bge_ioctl;
316195d67482SBill Paul 	ifp->if_start = bge_start;
316295d67482SBill Paul 	ifp->if_init = bge_init;
31634d665c4dSDag-Erling Smørgrav 	ifp->if_snd.ifq_drv_maxlen = BGE_TX_RING_CNT - 1;
31644d665c4dSDag-Erling Smørgrav 	IFQ_SET_MAXLEN(&ifp->if_snd, ifp->if_snd.ifq_drv_maxlen);
31654d665c4dSDag-Erling Smørgrav 	IFQ_SET_READY(&ifp->if_snd);
316635f945cdSPyun YongHyeon 	ifp->if_hwassist = sc->bge_csum_features;
3167d375e524SGleb Smirnoff 	ifp->if_capabilities = IFCAP_HWCSUM | IFCAP_VLAN_HWTAGGING |
31684e35d186SJung-uk Kim 	    IFCAP_VLAN_MTU;
31691108273aSPyun YongHyeon 	if ((sc->bge_flags & (BGE_FLAG_TSO | BGE_FLAG_TSO3)) != 0) {
3170ca3f1187SPyun YongHyeon 		ifp->if_hwassist |= CSUM_TSO;
317104bde852SPyun YongHyeon 		ifp->if_capabilities |= IFCAP_TSO4 | IFCAP_VLAN_HWTSO;
3172ca3f1187SPyun YongHyeon 	}
31734e35d186SJung-uk Kim #ifdef IFCAP_VLAN_HWCSUM
31744e35d186SJung-uk Kim 	ifp->if_capabilities |= IFCAP_VLAN_HWCSUM;
31754e35d186SJung-uk Kim #endif
317695d67482SBill Paul 	ifp->if_capenable = ifp->if_capabilities;
317775719184SGleb Smirnoff #ifdef DEVICE_POLLING
317875719184SGleb Smirnoff 	ifp->if_capabilities |= IFCAP_POLLING;
317975719184SGleb Smirnoff #endif
318095d67482SBill Paul 
3181a1d52896SBill Paul 	/*
3182d375e524SGleb Smirnoff 	 * 5700 B0 chips do not support checksumming correctly due
3183d375e524SGleb Smirnoff 	 * to hardware bugs.
3184d375e524SGleb Smirnoff 	 */
3185d375e524SGleb Smirnoff 	if (sc->bge_chipid == BGE_CHIPID_BCM5700_B0) {
3186d375e524SGleb Smirnoff 		ifp->if_capabilities &= ~IFCAP_HWCSUM;
31874d3a629cSPyun YongHyeon 		ifp->if_capenable &= ~IFCAP_HWCSUM;
3188d375e524SGleb Smirnoff 		ifp->if_hwassist = 0;
3189d375e524SGleb Smirnoff 	}
3190d375e524SGleb Smirnoff 
3191d375e524SGleb Smirnoff 	/*
3192a1d52896SBill Paul 	 * Figure out what sort of media we have by checking the
319341abcc1bSPaul Saab 	 * hardware config word in the first 32k of NIC internal memory,
319441abcc1bSPaul Saab 	 * or fall back to examining the EEPROM if necessary.
319541abcc1bSPaul Saab 	 * Note: on some BCM5700 cards, this value appears to be unset.
319641abcc1bSPaul Saab 	 * If that's the case, we have to rely on identifying the NIC
319741abcc1bSPaul Saab 	 * by its PCI subsystem ID, as we do below for the SysKonnect
319841abcc1bSPaul Saab 	 * SK-9D41.
3199a1d52896SBill Paul 	 */
3200888b47f0SPyun YongHyeon 	if (bge_readmem_ind(sc, BGE_SRAM_DATA_SIG) == BGE_SRAM_DATA_SIG_MAGIC)
3201888b47f0SPyun YongHyeon 		hwcfg = bge_readmem_ind(sc, BGE_SRAM_DATA_CFG);
32025fea260fSMarius Strobl 	else if ((sc->bge_flags & BGE_FLAG_EADDR) &&
32035fea260fSMarius Strobl 	    (sc->bge_asicrev != BGE_ASICREV_BCM5906)) {
3204f6789fbaSPyun YongHyeon 		if (bge_read_eeprom(sc, (caddr_t)&hwcfg, BGE_EE_HWCFG_OFFSET,
3205f6789fbaSPyun YongHyeon 		    sizeof(hwcfg))) {
3206fe806fdaSPyun YongHyeon 			device_printf(sc->bge_dev, "failed to read EEPROM\n");
3207f6789fbaSPyun YongHyeon 			error = ENXIO;
3208f6789fbaSPyun YongHyeon 			goto fail;
3209f6789fbaSPyun YongHyeon 		}
321041abcc1bSPaul Saab 		hwcfg = ntohl(hwcfg);
321141abcc1bSPaul Saab 	}
321241abcc1bSPaul Saab 
321395d67482SBill Paul 	/* The SysKonnect SK-9D41 is a 1000baseSX card. */
3214ea3b4127SPyun YongHyeon 	if ((pci_read_config(dev, BGE_PCI_SUBSYS, 4) >> 16) ==
3215ea3b4127SPyun YongHyeon 	    SK_SUBSYSID_9D41 || (hwcfg & BGE_HWCFG_MEDIA) == BGE_MEDIA_FIBER) {
3216ea3b4127SPyun YongHyeon 		if (BGE_IS_5714_FAMILY(sc))
3217ea3b4127SPyun YongHyeon 			sc->bge_flags |= BGE_FLAG_MII_SERDES;
3218ea3b4127SPyun YongHyeon 		else
3219652ae483SGleb Smirnoff 			sc->bge_flags |= BGE_FLAG_TBI;
3220ea3b4127SPyun YongHyeon 	}
322195d67482SBill Paul 
3222652ae483SGleb Smirnoff 	if (sc->bge_flags & BGE_FLAG_TBI) {
32230c8aa4eaSJung-uk Kim 		ifmedia_init(&sc->bge_ifmedia, IFM_IMASK, bge_ifmedia_upd,
32240c8aa4eaSJung-uk Kim 		    bge_ifmedia_sts);
32250c8aa4eaSJung-uk Kim 		ifmedia_add(&sc->bge_ifmedia, IFM_ETHER | IFM_1000_SX, 0, NULL);
32266098821cSJung-uk Kim 		ifmedia_add(&sc->bge_ifmedia, IFM_ETHER | IFM_1000_SX | IFM_FDX,
32276098821cSJung-uk Kim 		    0, NULL);
322895d67482SBill Paul 		ifmedia_add(&sc->bge_ifmedia, IFM_ETHER | IFM_AUTO, 0, NULL);
322995d67482SBill Paul 		ifmedia_set(&sc->bge_ifmedia, IFM_ETHER | IFM_AUTO);
3230da3003f0SBill Paul 		sc->bge_ifmedia.ifm_media = sc->bge_ifmedia.ifm_cur->ifm_media;
323195d67482SBill Paul 	} else {
323295d67482SBill Paul 		/*
32338cb1383cSDoug Ambrisko 		 * Do transceiver setup and tell the firmware the
32348cb1383cSDoug Ambrisko 		 * driver is down so we can try to get access the
32358cb1383cSDoug Ambrisko 		 * probe if ASF is running.  Retry a couple of times
32368cb1383cSDoug Ambrisko 		 * if we get a conflict with the ASF firmware accessing
32378cb1383cSDoug Ambrisko 		 * the PHY.
323895d67482SBill Paul 		 */
32394012d104SMarius Strobl 		trys = 0;
32408cb1383cSDoug Ambrisko 		BGE_CLRBIT(sc, BGE_MODE_CTL, BGE_MODECTL_STACKUP);
32418cb1383cSDoug Ambrisko again:
32428cb1383cSDoug Ambrisko 		bge_asf_driver_up(sc);
32438cb1383cSDoug Ambrisko 
3244fb772a6cSMarius Strobl 		error = mii_attach(dev, &sc->bge_miibus, ifp, bge_ifmedia_upd,
3245fb772a6cSMarius Strobl 		    bge_ifmedia_sts, capmask, phy_addr, MII_OFFSET_ANY,
3246fb772a6cSMarius Strobl 		    MIIF_DOPAUSE);
32478e5d93dbSMarius Strobl 		if (error != 0) {
32488cb1383cSDoug Ambrisko 			if (trys++ < 4) {
32498cb1383cSDoug Ambrisko 				device_printf(sc->bge_dev, "Try again\n");
32504e35d186SJung-uk Kim 				bge_miibus_writereg(sc->bge_dev, 1, MII_BMCR,
32514e35d186SJung-uk Kim 				    BMCR_RESET);
32528cb1383cSDoug Ambrisko 				goto again;
32538cb1383cSDoug Ambrisko 			}
32548e5d93dbSMarius Strobl 			device_printf(sc->bge_dev, "attaching PHYs failed\n");
325595d67482SBill Paul 			goto fail;
325695d67482SBill Paul 		}
32578cb1383cSDoug Ambrisko 
32588cb1383cSDoug Ambrisko 		/*
32598cb1383cSDoug Ambrisko 		 * Now tell the firmware we are going up after probing the PHY
32608cb1383cSDoug Ambrisko 		 */
32618cb1383cSDoug Ambrisko 		if (sc->bge_asf_mode & ASF_STACKUP)
32628cb1383cSDoug Ambrisko 			BGE_SETBIT(sc, BGE_MODE_CTL, BGE_MODECTL_STACKUP);
326395d67482SBill Paul 	}
326495d67482SBill Paul 
326595d67482SBill Paul 	/*
3266e255b776SJohn Polstra 	 * When using the BCM5701 in PCI-X mode, data corruption has
3267e255b776SJohn Polstra 	 * been observed in the first few bytes of some received packets.
3268e255b776SJohn Polstra 	 * Aligning the packet buffer in memory eliminates the corruption.
3269e255b776SJohn Polstra 	 * Unfortunately, this misaligns the packet payloads.  On platforms
3270e255b776SJohn Polstra 	 * which do not support unaligned accesses, we will realign the
3271e255b776SJohn Polstra 	 * payloads by copying the received packets.
3272e255b776SJohn Polstra 	 */
3273652ae483SGleb Smirnoff 	if (sc->bge_asicrev == BGE_ASICREV_BCM5701 &&
3274652ae483SGleb Smirnoff 	    sc->bge_flags & BGE_FLAG_PCIX)
3275652ae483SGleb Smirnoff                 sc->bge_flags |= BGE_FLAG_RX_ALIGNBUG;
3276e255b776SJohn Polstra 
3277e255b776SJohn Polstra 	/*
327895d67482SBill Paul 	 * Call MI attach routine.
327995d67482SBill Paul 	 */
3280fc74a9f9SBrooks Davis 	ether_ifattach(ifp, eaddr);
3281b74e67fbSGleb Smirnoff 	callout_init_mtx(&sc->bge_stat_ch, &sc->bge_mtx, 0);
32820f9bd73bSSam Leffler 
328361ccb9daSPyun YongHyeon 	/* Tell upper layer we support long frames. */
328461ccb9daSPyun YongHyeon 	ifp->if_data.ifi_hdrlen = sizeof(struct ether_vlan_header);
328561ccb9daSPyun YongHyeon 
32860f9bd73bSSam Leffler 	/*
32870f9bd73bSSam Leffler 	 * Hookup IRQ last.
32880f9bd73bSSam Leffler 	 */
3289dfe0df9aSPyun YongHyeon 	if (BGE_IS_5755_PLUS(sc) && sc->bge_flags & BGE_FLAG_MSI) {
3290dfe0df9aSPyun YongHyeon 		/* Take advantage of single-shot MSI. */
32917e6acdf1SPyun YongHyeon 		CSR_WRITE_4(sc, BGE_MSI_MODE, CSR_READ_4(sc, BGE_MSI_MODE) &
32927e6acdf1SPyun YongHyeon 		    ~BGE_MSIMODE_ONE_SHOT_DISABLE);
3293dfe0df9aSPyun YongHyeon 		sc->bge_tq = taskqueue_create_fast("bge_taskq", M_WAITOK,
3294dfe0df9aSPyun YongHyeon 		    taskqueue_thread_enqueue, &sc->bge_tq);
3295dfe0df9aSPyun YongHyeon 		if (sc->bge_tq == NULL) {
3296dfe0df9aSPyun YongHyeon 			device_printf(dev, "could not create taskqueue.\n");
3297dfe0df9aSPyun YongHyeon 			ether_ifdetach(ifp);
3298dfe0df9aSPyun YongHyeon 			error = ENXIO;
3299dfe0df9aSPyun YongHyeon 			goto fail;
3300dfe0df9aSPyun YongHyeon 		}
3301dfe0df9aSPyun YongHyeon 		taskqueue_start_threads(&sc->bge_tq, 1, PI_NET, "%s taskq",
3302dfe0df9aSPyun YongHyeon 		    device_get_nameunit(sc->bge_dev));
3303dfe0df9aSPyun YongHyeon 		error = bus_setup_intr(dev, sc->bge_irq,
3304dfe0df9aSPyun YongHyeon 		    INTR_TYPE_NET | INTR_MPSAFE, bge_msi_intr, NULL, sc,
3305dfe0df9aSPyun YongHyeon 		    &sc->bge_intrhand);
3306dfe0df9aSPyun YongHyeon 		if (error)
3307dfe0df9aSPyun YongHyeon 			ether_ifdetach(ifp);
3308dfe0df9aSPyun YongHyeon 	} else
3309dfe0df9aSPyun YongHyeon 		error = bus_setup_intr(dev, sc->bge_irq,
3310dfe0df9aSPyun YongHyeon 		    INTR_TYPE_NET | INTR_MPSAFE, NULL, bge_intr, sc,
3311dfe0df9aSPyun YongHyeon 		    &sc->bge_intrhand);
33120f9bd73bSSam Leffler 
33130f9bd73bSSam Leffler 	if (error) {
3314fc74a9f9SBrooks Davis 		bge_detach(dev);
3315fe806fdaSPyun YongHyeon 		device_printf(sc->bge_dev, "couldn't set up irq\n");
33160f9bd73bSSam Leffler 	}
331795d67482SBill Paul 
331808013fd3SMarius Strobl 	return (0);
331908013fd3SMarius Strobl 
332095d67482SBill Paul fail:
332108013fd3SMarius Strobl 	bge_release_resources(sc);
332208013fd3SMarius Strobl 
332395d67482SBill Paul 	return (error);
332495d67482SBill Paul }
332595d67482SBill Paul 
332695d67482SBill Paul static int
33273f74909aSGleb Smirnoff bge_detach(device_t dev)
332895d67482SBill Paul {
332995d67482SBill Paul 	struct bge_softc *sc;
333095d67482SBill Paul 	struct ifnet *ifp;
333195d67482SBill Paul 
333295d67482SBill Paul 	sc = device_get_softc(dev);
3333fc74a9f9SBrooks Davis 	ifp = sc->bge_ifp;
333495d67482SBill Paul 
333575719184SGleb Smirnoff #ifdef DEVICE_POLLING
333675719184SGleb Smirnoff 	if (ifp->if_capenable & IFCAP_POLLING)
333775719184SGleb Smirnoff 		ether_poll_deregister(ifp);
333875719184SGleb Smirnoff #endif
333975719184SGleb Smirnoff 
33400f9bd73bSSam Leffler 	BGE_LOCK(sc);
334195d67482SBill Paul 	bge_stop(sc);
334295d67482SBill Paul 	bge_reset(sc);
33430f9bd73bSSam Leffler 	BGE_UNLOCK(sc);
33440f9bd73bSSam Leffler 
33455dda8085SOleg Bulyzhin 	callout_drain(&sc->bge_stat_ch);
33465dda8085SOleg Bulyzhin 
3347dfe0df9aSPyun YongHyeon 	if (sc->bge_tq)
3348dfe0df9aSPyun YongHyeon 		taskqueue_drain(sc->bge_tq, &sc->bge_intr_task);
33490f9bd73bSSam Leffler 	ether_ifdetach(ifp);
335095d67482SBill Paul 
3351652ae483SGleb Smirnoff 	if (sc->bge_flags & BGE_FLAG_TBI) {
335295d67482SBill Paul 		ifmedia_removeall(&sc->bge_ifmedia);
335395d67482SBill Paul 	} else {
335495d67482SBill Paul 		bus_generic_detach(dev);
335595d67482SBill Paul 		device_delete_child(dev, sc->bge_miibus);
335695d67482SBill Paul 	}
335795d67482SBill Paul 
335895d67482SBill Paul 	bge_release_resources(sc);
335995d67482SBill Paul 
336095d67482SBill Paul 	return (0);
336195d67482SBill Paul }
336295d67482SBill Paul 
336395d67482SBill Paul static void
33643f74909aSGleb Smirnoff bge_release_resources(struct bge_softc *sc)
336595d67482SBill Paul {
336695d67482SBill Paul 	device_t dev;
336795d67482SBill Paul 
336895d67482SBill Paul 	dev = sc->bge_dev;
336995d67482SBill Paul 
3370dfe0df9aSPyun YongHyeon 	if (sc->bge_tq != NULL)
3371dfe0df9aSPyun YongHyeon 		taskqueue_free(sc->bge_tq);
3372dfe0df9aSPyun YongHyeon 
337395d67482SBill Paul 	if (sc->bge_intrhand != NULL)
337495d67482SBill Paul 		bus_teardown_intr(dev, sc->bge_irq, sc->bge_intrhand);
337595d67482SBill Paul 
337695d67482SBill Paul 	if (sc->bge_irq != NULL)
3377724bd939SJohn Polstra 		bus_release_resource(dev, SYS_RES_IRQ,
3378724bd939SJohn Polstra 		    sc->bge_flags & BGE_FLAG_MSI ? 1 : 0, sc->bge_irq);
3379724bd939SJohn Polstra 
3380724bd939SJohn Polstra 	if (sc->bge_flags & BGE_FLAG_MSI)
3381724bd939SJohn Polstra 		pci_release_msi(dev);
338295d67482SBill Paul 
338395d67482SBill Paul 	if (sc->bge_res != NULL)
338495d67482SBill Paul 		bus_release_resource(dev, SYS_RES_MEMORY,
3385736b9319SPyun YongHyeon 		    PCIR_BAR(0), sc->bge_res);
338695d67482SBill Paul 
3387ad61f896SRuslan Ermilov 	if (sc->bge_ifp != NULL)
3388ad61f896SRuslan Ermilov 		if_free(sc->bge_ifp);
3389ad61f896SRuslan Ermilov 
3390f41ac2beSBill Paul 	bge_dma_free(sc);
339195d67482SBill Paul 
33920f9bd73bSSam Leffler 	if (mtx_initialized(&sc->bge_mtx))	/* XXX */
33930f9bd73bSSam Leffler 		BGE_LOCK_DESTROY(sc);
339495d67482SBill Paul }
339595d67482SBill Paul 
33968cb1383cSDoug Ambrisko static int
33973f74909aSGleb Smirnoff bge_reset(struct bge_softc *sc)
339895d67482SBill Paul {
339995d67482SBill Paul 	device_t dev;
34005fea260fSMarius Strobl 	uint32_t cachesize, command, pcistate, reset, val;
34016f8718a3SScott Long 	void (*write_op)(struct bge_softc *, int, int);
34020aaf1057SPyun YongHyeon 	uint16_t devctl;
34035fea260fSMarius Strobl 	int i;
340495d67482SBill Paul 
340595d67482SBill Paul 	dev = sc->bge_dev;
340695d67482SBill Paul 
340738cc658fSJohn Baldwin 	if (BGE_IS_575X_PLUS(sc) && !BGE_IS_5714_FAMILY(sc) &&
340838cc658fSJohn Baldwin 	    (sc->bge_asicrev != BGE_ASICREV_BCM5906)) {
34096f8718a3SScott Long 		if (sc->bge_flags & BGE_FLAG_PCIE)
34106f8718a3SScott Long 			write_op = bge_writemem_direct;
34116f8718a3SScott Long 		else
34126f8718a3SScott Long 			write_op = bge_writemem_ind;
34139ba784dbSScott Long 	} else
34146f8718a3SScott Long 		write_op = bge_writereg_ind;
34156f8718a3SScott Long 
341695d67482SBill Paul 	/* Save some important PCI state. */
341795d67482SBill Paul 	cachesize = pci_read_config(dev, BGE_PCI_CACHESZ, 4);
341895d67482SBill Paul 	command = pci_read_config(dev, BGE_PCI_CMD, 4);
341995d67482SBill Paul 	pcistate = pci_read_config(dev, BGE_PCI_PCISTATE, 4);
342095d67482SBill Paul 
342195d67482SBill Paul 	pci_write_config(dev, BGE_PCI_MISC_CTL,
342295d67482SBill Paul 	    BGE_PCIMISCCTL_INDIRECT_ACCESS | BGE_PCIMISCCTL_MASK_PCI_INTR |
3423e907febfSPyun YongHyeon 	    BGE_HIF_SWAP_OPTIONS | BGE_PCIMISCCTL_PCISTATE_RW, 4);
342495d67482SBill Paul 
34256f8718a3SScott Long 	/* Disable fastboot on controllers that support it. */
34266f8718a3SScott Long 	if (sc->bge_asicrev == BGE_ASICREV_BCM5752 ||
3427a5779553SStanislav Sedov 	    BGE_IS_5755_PLUS(sc)) {
34286f8718a3SScott Long 		if (bootverbose)
3429333704a3SPyun YongHyeon 			device_printf(dev, "Disabling fastboot\n");
34306f8718a3SScott Long 		CSR_WRITE_4(sc, BGE_FASTBOOT_PC, 0x0);
34316f8718a3SScott Long 	}
34326f8718a3SScott Long 
34336f8718a3SScott Long 	/*
34346f8718a3SScott Long 	 * Write the magic number to SRAM at offset 0xB50.
34356f8718a3SScott Long 	 * When firmware finishes its initialization it will
3436888b47f0SPyun YongHyeon 	 * write ~BGE_SRAM_FW_MB_MAGIC to the same location.
34376f8718a3SScott Long 	 */
3438888b47f0SPyun YongHyeon 	bge_writemem_ind(sc, BGE_SRAM_FW_MB, BGE_SRAM_FW_MB_MAGIC);
34396f8718a3SScott Long 
34400c8aa4eaSJung-uk Kim 	reset = BGE_MISCCFG_RESET_CORE_CLOCKS | BGE_32BITTIME_66MHZ;
3441e53d81eeSPaul Saab 
3442e53d81eeSPaul Saab 	/* XXX: Broadcom Linux driver. */
3443652ae483SGleb Smirnoff 	if (sc->bge_flags & BGE_FLAG_PCIE) {
34440c8aa4eaSJung-uk Kim 		if (CSR_READ_4(sc, 0x7E2C) == 0x60)	/* PCIE 1.0 */
34450c8aa4eaSJung-uk Kim 			CSR_WRITE_4(sc, 0x7E2C, 0x20);
3446e53d81eeSPaul Saab 		if (sc->bge_chipid != BGE_CHIPID_BCM5750_A0) {
3447e53d81eeSPaul Saab 			/* Prevent PCIE link training during global reset */
34480c8aa4eaSJung-uk Kim 			CSR_WRITE_4(sc, BGE_MISC_CFG, 1 << 29);
34490c8aa4eaSJung-uk Kim 			reset |= 1 << 29;
3450e53d81eeSPaul Saab 		}
3451e53d81eeSPaul Saab 	}
3452e53d81eeSPaul Saab 
345321c9e407SDavid Christensen 	/*
34546f8718a3SScott Long 	 * Set GPHY Power Down Override to leave GPHY
34556f8718a3SScott Long 	 * powered up in D0 uninitialized.
34566f8718a3SScott Long 	 */
34575512ca01SPyun YongHyeon 	if (BGE_IS_5705_PLUS(sc) &&
34585512ca01SPyun YongHyeon 	    (sc->bge_flags & BGE_FLAG_CPMU_PRESENT) == 0)
3459caf088fcSPyun YongHyeon 		reset |= BGE_MISCCFG_GPHY_PD_OVERRIDE;
34606f8718a3SScott Long 
346195d67482SBill Paul 	/* Issue global reset */
34626f8718a3SScott Long 	write_op(sc, BGE_MISC_CFG, reset);
346395d67482SBill Paul 
346438cc658fSJohn Baldwin 	if (sc->bge_asicrev == BGE_ASICREV_BCM5906) {
34655fea260fSMarius Strobl 		val = CSR_READ_4(sc, BGE_VCPU_STATUS);
346638cc658fSJohn Baldwin 		CSR_WRITE_4(sc, BGE_VCPU_STATUS,
34675fea260fSMarius Strobl 		    val | BGE_VCPU_STATUS_DRV_RESET);
34685fea260fSMarius Strobl 		val = CSR_READ_4(sc, BGE_VCPU_EXT_CTRL);
346938cc658fSJohn Baldwin 		CSR_WRITE_4(sc, BGE_VCPU_EXT_CTRL,
34705fea260fSMarius Strobl 		    val & ~BGE_VCPU_EXT_CTRL_HALT_CPU);
347138cc658fSJohn Baldwin 	}
347238cc658fSJohn Baldwin 
347395d67482SBill Paul 	DELAY(1000);
347495d67482SBill Paul 
3475e53d81eeSPaul Saab 	/* XXX: Broadcom Linux driver. */
3476652ae483SGleb Smirnoff 	if (sc->bge_flags & BGE_FLAG_PCIE) {
3477e53d81eeSPaul Saab 		if (sc->bge_chipid == BGE_CHIPID_BCM5750_A0) {
3478e53d81eeSPaul Saab 			DELAY(500000); /* wait for link training to complete */
34795fea260fSMarius Strobl 			val = pci_read_config(dev, 0xC4, 4);
34805fea260fSMarius Strobl 			pci_write_config(dev, 0xC4, val | (1 << 15), 4);
3481e53d81eeSPaul Saab 		}
34820aaf1057SPyun YongHyeon 		devctl = pci_read_config(dev,
34830aaf1057SPyun YongHyeon 		    sc->bge_expcap + PCIR_EXPRESS_DEVICE_CTL, 2);
34840aaf1057SPyun YongHyeon 		/* Clear enable no snoop and disable relaxed ordering. */
34859a6e301dSPyun YongHyeon 		devctl &= ~(PCIM_EXP_CTL_RELAXED_ORD_ENABLE |
34869a6e301dSPyun YongHyeon 		    PCIM_EXP_CTL_NOSNOOP_ENABLE);
34870aaf1057SPyun YongHyeon 		/* Set PCIE max payload size to 128. */
34880aaf1057SPyun YongHyeon 		devctl &= ~PCIM_EXP_CTL_MAX_PAYLOAD;
34890aaf1057SPyun YongHyeon 		pci_write_config(dev, sc->bge_expcap + PCIR_EXPRESS_DEVICE_CTL,
34900aaf1057SPyun YongHyeon 		    devctl, 2);
34910aaf1057SPyun YongHyeon 		/* Clear error status. */
34920aaf1057SPyun YongHyeon 		pci_write_config(dev, sc->bge_expcap + PCIR_EXPRESS_DEVICE_STA,
34939a6e301dSPyun YongHyeon 		    PCIM_EXP_STA_CORRECTABLE_ERROR |
34949a6e301dSPyun YongHyeon 		    PCIM_EXP_STA_NON_FATAL_ERROR | PCIM_EXP_STA_FATAL_ERROR |
34959a6e301dSPyun YongHyeon 		    PCIM_EXP_STA_UNSUPPORTED_REQ, 2);
3496e53d81eeSPaul Saab 	}
3497e53d81eeSPaul Saab 
34983f74909aSGleb Smirnoff 	/* Reset some of the PCI state that got zapped by reset. */
349995d67482SBill Paul 	pci_write_config(dev, BGE_PCI_MISC_CTL,
350095d67482SBill Paul 	    BGE_PCIMISCCTL_INDIRECT_ACCESS | BGE_PCIMISCCTL_MASK_PCI_INTR |
3501e907febfSPyun YongHyeon 	    BGE_HIF_SWAP_OPTIONS | BGE_PCIMISCCTL_PCISTATE_RW, 4);
350295d67482SBill Paul 	pci_write_config(dev, BGE_PCI_CACHESZ, cachesize, 4);
350395d67482SBill Paul 	pci_write_config(dev, BGE_PCI_CMD, command, 4);
35040c8aa4eaSJung-uk Kim 	write_op(sc, BGE_MISC_CFG, BGE_32BITTIME_66MHZ);
3505cbb2b2feSPyun YongHyeon 	/*
3506cbb2b2feSPyun YongHyeon 	 * Disable PCI-X relaxed ordering to ensure status block update
3507fa8b4d63SPyun YongHyeon 	 * comes first then packet buffer DMA. Otherwise driver may
3508cbb2b2feSPyun YongHyeon 	 * read stale status block.
3509cbb2b2feSPyun YongHyeon 	 */
3510cbb2b2feSPyun YongHyeon 	if (sc->bge_flags & BGE_FLAG_PCIX) {
3511cbb2b2feSPyun YongHyeon 		devctl = pci_read_config(dev,
3512cbb2b2feSPyun YongHyeon 		    sc->bge_pcixcap + PCIXR_COMMAND, 2);
3513cbb2b2feSPyun YongHyeon 		devctl &= ~PCIXM_COMMAND_ERO;
3514cbb2b2feSPyun YongHyeon 		if (sc->bge_asicrev == BGE_ASICREV_BCM5703) {
3515cbb2b2feSPyun YongHyeon 			devctl &= ~PCIXM_COMMAND_MAX_READ;
3516cbb2b2feSPyun YongHyeon 			devctl |= PCIXM_COMMAND_MAX_READ_2048;
3517cbb2b2feSPyun YongHyeon 		} else if (sc->bge_asicrev == BGE_ASICREV_BCM5704) {
3518cbb2b2feSPyun YongHyeon 			devctl &= ~(PCIXM_COMMAND_MAX_SPLITS |
3519cbb2b2feSPyun YongHyeon 			    PCIXM_COMMAND_MAX_READ);
3520cbb2b2feSPyun YongHyeon 			devctl |= PCIXM_COMMAND_MAX_READ_2048;
3521cbb2b2feSPyun YongHyeon 		}
3522cbb2b2feSPyun YongHyeon 		pci_write_config(dev, sc->bge_pcixcap + PCIXR_COMMAND,
3523cbb2b2feSPyun YongHyeon 		    devctl, 2);
3524cbb2b2feSPyun YongHyeon 	}
352522a4ecedSMarius Strobl 	/* Re-enable MSI, if necessary, and enable the memory arbiter. */
35264c0da0ffSGleb Smirnoff 	if (BGE_IS_5714_FAMILY(sc)) {
3527bf6ef57aSJohn Polstra 		/* This chip disables MSI on reset. */
3528bf6ef57aSJohn Polstra 		if (sc->bge_flags & BGE_FLAG_MSI) {
35290aaf1057SPyun YongHyeon 			val = pci_read_config(dev,
35300aaf1057SPyun YongHyeon 			    sc->bge_msicap + PCIR_MSI_CTRL, 2);
35310aaf1057SPyun YongHyeon 			pci_write_config(dev,
35320aaf1057SPyun YongHyeon 			    sc->bge_msicap + PCIR_MSI_CTRL,
3533bf6ef57aSJohn Polstra 			    val | PCIM_MSICTRL_MSI_ENABLE, 2);
3534bf6ef57aSJohn Polstra 			val = CSR_READ_4(sc, BGE_MSI_MODE);
3535bf6ef57aSJohn Polstra 			CSR_WRITE_4(sc, BGE_MSI_MODE,
3536bf6ef57aSJohn Polstra 			    val | BGE_MSIMODE_ENABLE);
3537bf6ef57aSJohn Polstra 		}
35384c0da0ffSGleb Smirnoff 		val = CSR_READ_4(sc, BGE_MARB_MODE);
35394c0da0ffSGleb Smirnoff 		CSR_WRITE_4(sc, BGE_MARB_MODE, BGE_MARBMODE_ENABLE | val);
35404c0da0ffSGleb Smirnoff 	} else
3541a7b0c314SPaul Saab 		CSR_WRITE_4(sc, BGE_MARB_MODE, BGE_MARBMODE_ENABLE);
3542a7b0c314SPaul Saab 
354338cc658fSJohn Baldwin 	if (sc->bge_asicrev == BGE_ASICREV_BCM5906) {
354438cc658fSJohn Baldwin 		for (i = 0; i < BGE_TIMEOUT; i++) {
354538cc658fSJohn Baldwin 			val = CSR_READ_4(sc, BGE_VCPU_STATUS);
354638cc658fSJohn Baldwin 			if (val & BGE_VCPU_STATUS_INIT_DONE)
354738cc658fSJohn Baldwin 				break;
354838cc658fSJohn Baldwin 			DELAY(100);
354938cc658fSJohn Baldwin 		}
355038cc658fSJohn Baldwin 		if (i == BGE_TIMEOUT) {
3551333704a3SPyun YongHyeon 			device_printf(dev, "reset timed out\n");
355238cc658fSJohn Baldwin 			return (1);
355338cc658fSJohn Baldwin 		}
355438cc658fSJohn Baldwin 	} else {
355595d67482SBill Paul 		/*
35566f8718a3SScott Long 		 * Poll until we see the 1's complement of the magic number.
355708013fd3SMarius Strobl 		 * This indicates that the firmware initialization is complete.
35585fea260fSMarius Strobl 		 * We expect this to fail if no chip containing the Ethernet
35595fea260fSMarius Strobl 		 * address is fitted though.
356095d67482SBill Paul 		 */
356195d67482SBill Paul 		for (i = 0; i < BGE_TIMEOUT; i++) {
3562d5d23857SJung-uk Kim 			DELAY(10);
3563888b47f0SPyun YongHyeon 			val = bge_readmem_ind(sc, BGE_SRAM_FW_MB);
3564888b47f0SPyun YongHyeon 			if (val == ~BGE_SRAM_FW_MB_MAGIC)
356595d67482SBill Paul 				break;
356695d67482SBill Paul 		}
356795d67482SBill Paul 
35685fea260fSMarius Strobl 		if ((sc->bge_flags & BGE_FLAG_EADDR) && i == BGE_TIMEOUT)
3569333704a3SPyun YongHyeon 			device_printf(dev,
3570333704a3SPyun YongHyeon 			    "firmware handshake timed out, found 0x%08x\n",
3571333704a3SPyun YongHyeon 			    val);
3572b4a256acSPyun YongHyeon 		/* BCM57765 A0 needs additional time before accessing. */
3573b4a256acSPyun YongHyeon 		if (sc->bge_chipid == BGE_CHIPID_BCM57765_A0)
3574b4a256acSPyun YongHyeon 			DELAY(10 * 1000);	/* XXX */
357538cc658fSJohn Baldwin 	}
357695d67482SBill Paul 
357795d67482SBill Paul 	/*
357895d67482SBill Paul 	 * XXX Wait for the value of the PCISTATE register to
357995d67482SBill Paul 	 * return to its original pre-reset state. This is a
358095d67482SBill Paul 	 * fairly good indicator of reset completion. If we don't
358195d67482SBill Paul 	 * wait for the reset to fully complete, trying to read
358295d67482SBill Paul 	 * from the device's non-PCI registers may yield garbage
358395d67482SBill Paul 	 * results.
358495d67482SBill Paul 	 */
358595d67482SBill Paul 	for (i = 0; i < BGE_TIMEOUT; i++) {
358695d67482SBill Paul 		if (pci_read_config(dev, BGE_PCI_PCISTATE, 4) == pcistate)
358795d67482SBill Paul 			break;
358895d67482SBill Paul 		DELAY(10);
358995d67482SBill Paul 	}
359095d67482SBill Paul 
35913f74909aSGleb Smirnoff 	/* Fix up byte swapping. */
3592e907febfSPyun YongHyeon 	CSR_WRITE_4(sc, BGE_MODE_CTL, BGE_DMA_SWAP_OPTIONS |
359395d67482SBill Paul 	    BGE_MODECTL_BYTESWAP_DATA);
359495d67482SBill Paul 
35958cb1383cSDoug Ambrisko 	/* Tell the ASF firmware we are up */
35968cb1383cSDoug Ambrisko 	if (sc->bge_asf_mode & ASF_STACKUP)
35978cb1383cSDoug Ambrisko 		BGE_SETBIT(sc, BGE_MODE_CTL, BGE_MODECTL_STACKUP);
35988cb1383cSDoug Ambrisko 
359995d67482SBill Paul 	CSR_WRITE_4(sc, BGE_MAC_MODE, 0);
360095d67482SBill Paul 
3601da3003f0SBill Paul 	/*
3602da3003f0SBill Paul 	 * The 5704 in TBI mode apparently needs some special
3603da3003f0SBill Paul 	 * adjustment to insure the SERDES drive level is set
3604da3003f0SBill Paul 	 * to 1.2V.
3605da3003f0SBill Paul 	 */
3606652ae483SGleb Smirnoff 	if (sc->bge_asicrev == BGE_ASICREV_BCM5704 &&
3607652ae483SGleb Smirnoff 	    sc->bge_flags & BGE_FLAG_TBI) {
36085fea260fSMarius Strobl 		val = CSR_READ_4(sc, BGE_SERDES_CFG);
36095fea260fSMarius Strobl 		val = (val & ~0xFFF) | 0x880;
36105fea260fSMarius Strobl 		CSR_WRITE_4(sc, BGE_SERDES_CFG, val);
3611da3003f0SBill Paul 	}
3612da3003f0SBill Paul 
3613e53d81eeSPaul Saab 	/* XXX: Broadcom Linux driver. */
3614652ae483SGleb Smirnoff 	if (sc->bge_flags & BGE_FLAG_PCIE &&
3615b4a256acSPyun YongHyeon 	    !BGE_IS_5717_PLUS(sc) &&
3616a5ad2f15SPyun YongHyeon 	    sc->bge_chipid != BGE_CHIPID_BCM5750_A0 &&
3617a5ad2f15SPyun YongHyeon 	    sc->bge_asicrev != BGE_ASICREV_BCM5785) {
3618a5ad2f15SPyun YongHyeon 		/* Enable Data FIFO protection. */
36195fea260fSMarius Strobl 		val = CSR_READ_4(sc, 0x7C00);
36205fea260fSMarius Strobl 		CSR_WRITE_4(sc, 0x7C00, val | (1 << 25));
3621e53d81eeSPaul Saab 	}
362295d67482SBill Paul 	DELAY(10000);
36238cb1383cSDoug Ambrisko 
36248cb1383cSDoug Ambrisko 	return (0);
362595d67482SBill Paul }
362695d67482SBill Paul 
3627e0b7b101SPyun YongHyeon static __inline void
3628e0b7b101SPyun YongHyeon bge_rxreuse_std(struct bge_softc *sc, int i)
3629e0b7b101SPyun YongHyeon {
3630e0b7b101SPyun YongHyeon 	struct bge_rx_bd *r;
3631e0b7b101SPyun YongHyeon 
3632e0b7b101SPyun YongHyeon 	r = &sc->bge_ldata.bge_rx_std_ring[sc->bge_std];
3633e0b7b101SPyun YongHyeon 	r->bge_flags = BGE_RXBDFLAG_END;
3634e0b7b101SPyun YongHyeon 	r->bge_len = sc->bge_cdata.bge_rx_std_seglen[i];
3635e0b7b101SPyun YongHyeon 	r->bge_idx = i;
3636e0b7b101SPyun YongHyeon 	BGE_INC(sc->bge_std, BGE_STD_RX_RING_CNT);
3637e0b7b101SPyun YongHyeon }
3638e0b7b101SPyun YongHyeon 
3639e0b7b101SPyun YongHyeon static __inline void
3640e0b7b101SPyun YongHyeon bge_rxreuse_jumbo(struct bge_softc *sc, int i)
3641e0b7b101SPyun YongHyeon {
3642e0b7b101SPyun YongHyeon 	struct bge_extrx_bd *r;
3643e0b7b101SPyun YongHyeon 
3644e0b7b101SPyun YongHyeon 	r = &sc->bge_ldata.bge_rx_jumbo_ring[sc->bge_jumbo];
3645e0b7b101SPyun YongHyeon 	r->bge_flags = BGE_RXBDFLAG_JUMBO_RING | BGE_RXBDFLAG_END;
3646e0b7b101SPyun YongHyeon 	r->bge_len0 = sc->bge_cdata.bge_rx_jumbo_seglen[i][0];
3647e0b7b101SPyun YongHyeon 	r->bge_len1 = sc->bge_cdata.bge_rx_jumbo_seglen[i][1];
3648e0b7b101SPyun YongHyeon 	r->bge_len2 = sc->bge_cdata.bge_rx_jumbo_seglen[i][2];
3649e0b7b101SPyun YongHyeon 	r->bge_len3 = sc->bge_cdata.bge_rx_jumbo_seglen[i][3];
3650e0b7b101SPyun YongHyeon 	r->bge_idx = i;
3651e0b7b101SPyun YongHyeon 	BGE_INC(sc->bge_jumbo, BGE_JUMBO_RX_RING_CNT);
3652e0b7b101SPyun YongHyeon }
3653e0b7b101SPyun YongHyeon 
365495d67482SBill Paul /*
365595d67482SBill Paul  * Frame reception handling. This is called if there's a frame
365695d67482SBill Paul  * on the receive return list.
365795d67482SBill Paul  *
365895d67482SBill Paul  * Note: we have to be able to handle two possibilities here:
36591be6acb7SGleb Smirnoff  * 1) the frame is from the jumbo receive ring
366095d67482SBill Paul  * 2) the frame is from the standard receive ring
366195d67482SBill Paul  */
366295d67482SBill Paul 
36631abcdbd1SAttilio Rao static int
3664dfe0df9aSPyun YongHyeon bge_rxeof(struct bge_softc *sc, uint16_t rx_prod, int holdlck)
366595d67482SBill Paul {
366695d67482SBill Paul 	struct ifnet *ifp;
36671abcdbd1SAttilio Rao 	int rx_npkts = 0, stdcnt = 0, jumbocnt = 0;
3668b9c05fa5SPyun YongHyeon 	uint16_t rx_cons;
366995d67482SBill Paul 
36707f21e273SStanislav Sedov 	rx_cons = sc->bge_rx_saved_considx;
36710f9bd73bSSam Leffler 
36723f74909aSGleb Smirnoff 	/* Nothing to do. */
36737f21e273SStanislav Sedov 	if (rx_cons == rx_prod)
36741abcdbd1SAttilio Rao 		return (rx_npkts);
3675cfcb5025SOleg Bulyzhin 
3676fc74a9f9SBrooks Davis 	ifp = sc->bge_ifp;
367795d67482SBill Paul 
3678f41ac2beSBill Paul 	bus_dmamap_sync(sc->bge_cdata.bge_rx_return_ring_tag,
3679e65bed95SPyun YongHyeon 	    sc->bge_cdata.bge_rx_return_ring_map, BUS_DMASYNC_POSTREAD);
3680f41ac2beSBill Paul 	bus_dmamap_sync(sc->bge_cdata.bge_rx_std_ring_tag,
368115eda801SStanislav Sedov 	    sc->bge_cdata.bge_rx_std_ring_map, BUS_DMASYNC_POSTWRITE);
3682f5459d4cSPyun YongHyeon 	if (BGE_IS_JUMBO_CAPABLE(sc) &&
3683f5459d4cSPyun YongHyeon 	    ifp->if_mtu + ETHER_HDR_LEN + ETHER_CRC_LEN + ETHER_VLAN_ENCAP_LEN >
3684c215fd77SPyun YongHyeon 	    (MCLBYTES - ETHER_ALIGN))
3685f41ac2beSBill Paul 		bus_dmamap_sync(sc->bge_cdata.bge_rx_jumbo_ring_tag,
368615eda801SStanislav Sedov 		    sc->bge_cdata.bge_rx_jumbo_ring_map, BUS_DMASYNC_POSTWRITE);
3687f41ac2beSBill Paul 
36887f21e273SStanislav Sedov 	while (rx_cons != rx_prod) {
368995d67482SBill Paul 		struct bge_rx_bd	*cur_rx;
36903f74909aSGleb Smirnoff 		uint32_t		rxidx;
369195d67482SBill Paul 		struct mbuf		*m = NULL;
36923f74909aSGleb Smirnoff 		uint16_t		vlan_tag = 0;
369395d67482SBill Paul 		int			have_tag = 0;
369495d67482SBill Paul 
369575719184SGleb Smirnoff #ifdef DEVICE_POLLING
369675719184SGleb Smirnoff 		if (ifp->if_capenable & IFCAP_POLLING) {
369775719184SGleb Smirnoff 			if (sc->rxcycles <= 0)
369875719184SGleb Smirnoff 				break;
369975719184SGleb Smirnoff 			sc->rxcycles--;
370075719184SGleb Smirnoff 		}
370175719184SGleb Smirnoff #endif
370275719184SGleb Smirnoff 
37037f21e273SStanislav Sedov 		cur_rx = &sc->bge_ldata.bge_rx_return_ring[rx_cons];
370495d67482SBill Paul 
370595d67482SBill Paul 		rxidx = cur_rx->bge_idx;
37067f21e273SStanislav Sedov 		BGE_INC(rx_cons, sc->bge_return_ring_cnt);
370795d67482SBill Paul 
3708cb2eacc7SYaroslav Tykhiy 		if (ifp->if_capenable & IFCAP_VLAN_HWTAGGING &&
3709cb2eacc7SYaroslav Tykhiy 		    cur_rx->bge_flags & BGE_RXBDFLAG_VLAN_TAG) {
371095d67482SBill Paul 			have_tag = 1;
371195d67482SBill Paul 			vlan_tag = cur_rx->bge_vlan_tag;
371295d67482SBill Paul 		}
371395d67482SBill Paul 
371495d67482SBill Paul 		if (cur_rx->bge_flags & BGE_RXBDFLAG_JUMBO_RING) {
371595d67482SBill Paul 			jumbocnt++;
3716943787f3SPyun YongHyeon 			m = sc->bge_cdata.bge_rx_jumbo_chain[rxidx];
371795d67482SBill Paul 			if (cur_rx->bge_flags & BGE_RXBDFLAG_ERROR) {
3718e0b7b101SPyun YongHyeon 				bge_rxreuse_jumbo(sc, rxidx);
371995d67482SBill Paul 				continue;
372095d67482SBill Paul 			}
3721943787f3SPyun YongHyeon 			if (bge_newbuf_jumbo(sc, rxidx) != 0) {
3722e0b7b101SPyun YongHyeon 				bge_rxreuse_jumbo(sc, rxidx);
3723943787f3SPyun YongHyeon 				ifp->if_iqdrops++;
372495d67482SBill Paul 				continue;
372595d67482SBill Paul 			}
372603e78bd0SPyun YongHyeon 			BGE_INC(sc->bge_jumbo, BGE_JUMBO_RX_RING_CNT);
372795d67482SBill Paul 		} else {
372895d67482SBill Paul 			stdcnt++;
3729e0b7b101SPyun YongHyeon 			m = sc->bge_cdata.bge_rx_std_chain[rxidx];
373095d67482SBill Paul 			if (cur_rx->bge_flags & BGE_RXBDFLAG_ERROR) {
3731e0b7b101SPyun YongHyeon 				bge_rxreuse_std(sc, rxidx);
373295d67482SBill Paul 				continue;
373395d67482SBill Paul 			}
3734943787f3SPyun YongHyeon 			if (bge_newbuf_std(sc, rxidx) != 0) {
3735e0b7b101SPyun YongHyeon 				bge_rxreuse_std(sc, rxidx);
3736943787f3SPyun YongHyeon 				ifp->if_iqdrops++;
373795d67482SBill Paul 				continue;
373895d67482SBill Paul 			}
373903e78bd0SPyun YongHyeon 			BGE_INC(sc->bge_std, BGE_STD_RX_RING_CNT);
374095d67482SBill Paul 		}
374195d67482SBill Paul 
374295d67482SBill Paul 		ifp->if_ipackets++;
3743e65bed95SPyun YongHyeon #ifndef __NO_STRICT_ALIGNMENT
3744e255b776SJohn Polstra 		/*
3745e65bed95SPyun YongHyeon 		 * For architectures with strict alignment we must make sure
3746e65bed95SPyun YongHyeon 		 * the payload is aligned.
3747e255b776SJohn Polstra 		 */
3748652ae483SGleb Smirnoff 		if (sc->bge_flags & BGE_FLAG_RX_ALIGNBUG) {
3749e255b776SJohn Polstra 			bcopy(m->m_data, m->m_data + ETHER_ALIGN,
3750e255b776SJohn Polstra 			    cur_rx->bge_len);
3751e255b776SJohn Polstra 			m->m_data += ETHER_ALIGN;
3752e255b776SJohn Polstra 		}
3753e255b776SJohn Polstra #endif
3754473851baSPaul Saab 		m->m_pkthdr.len = m->m_len = cur_rx->bge_len - ETHER_CRC_LEN;
375595d67482SBill Paul 		m->m_pkthdr.rcvif = ifp;
375695d67482SBill Paul 
37571108273aSPyun YongHyeon 		if (ifp->if_capenable & IFCAP_RXCSUM)
37581108273aSPyun YongHyeon 			bge_rxcsum(sc, cur_rx, m);
375995d67482SBill Paul 
376095d67482SBill Paul 		/*
3761673d9191SSam Leffler 		 * If we received a packet with a vlan tag,
3762673d9191SSam Leffler 		 * attach that information to the packet.
376395d67482SBill Paul 		 */
3764d147662cSGleb Smirnoff 		if (have_tag) {
376578ba57b9SAndre Oppermann 			m->m_pkthdr.ether_vtag = vlan_tag;
376678ba57b9SAndre Oppermann 			m->m_flags |= M_VLANTAG;
3767d147662cSGleb Smirnoff 		}
376895d67482SBill Paul 
3769dfe0df9aSPyun YongHyeon 		if (holdlck != 0) {
37700f9bd73bSSam Leffler 			BGE_UNLOCK(sc);
3771673d9191SSam Leffler 			(*ifp->if_input)(ifp, m);
37720f9bd73bSSam Leffler 			BGE_LOCK(sc);
3773dfe0df9aSPyun YongHyeon 		} else
3774dfe0df9aSPyun YongHyeon 			(*ifp->if_input)(ifp, m);
3775d4da719cSAttilio Rao 		rx_npkts++;
377625e13e68SXin LI 
377725e13e68SXin LI 		if (!(ifp->if_drv_flags & IFF_DRV_RUNNING))
37788cf7d13dSAttilio Rao 			return (rx_npkts);
377995d67482SBill Paul 	}
378095d67482SBill Paul 
378115eda801SStanislav Sedov 	bus_dmamap_sync(sc->bge_cdata.bge_rx_return_ring_tag,
378215eda801SStanislav Sedov 	    sc->bge_cdata.bge_rx_return_ring_map, BUS_DMASYNC_PREREAD);
3783e65bed95SPyun YongHyeon 	if (stdcnt > 0)
3784f41ac2beSBill Paul 		bus_dmamap_sync(sc->bge_cdata.bge_rx_std_ring_tag,
3785e65bed95SPyun YongHyeon 		    sc->bge_cdata.bge_rx_std_ring_map, BUS_DMASYNC_PREWRITE);
37864c0da0ffSGleb Smirnoff 
3787c215fd77SPyun YongHyeon 	if (jumbocnt > 0)
3788f41ac2beSBill Paul 		bus_dmamap_sync(sc->bge_cdata.bge_rx_jumbo_ring_tag,
37894c0da0ffSGleb Smirnoff 		    sc->bge_cdata.bge_rx_jumbo_ring_map, BUS_DMASYNC_PREWRITE);
3790f41ac2beSBill Paul 
37917f21e273SStanislav Sedov 	sc->bge_rx_saved_considx = rx_cons;
379238cc658fSJohn Baldwin 	bge_writembx(sc, BGE_MBX_RX_CONS0_LO, sc->bge_rx_saved_considx);
379395d67482SBill Paul 	if (stdcnt)
3794767c3593SPyun YongHyeon 		bge_writembx(sc, BGE_MBX_RX_STD_PROD_LO, (sc->bge_std +
3795767c3593SPyun YongHyeon 		    BGE_STD_RX_RING_CNT - 1) % BGE_STD_RX_RING_CNT);
379695d67482SBill Paul 	if (jumbocnt)
3797767c3593SPyun YongHyeon 		bge_writembx(sc, BGE_MBX_RX_JUMBO_PROD_LO, (sc->bge_jumbo +
3798767c3593SPyun YongHyeon 		    BGE_JUMBO_RX_RING_CNT - 1) % BGE_JUMBO_RX_RING_CNT);
3799f5a034f9SPyun YongHyeon #ifdef notyet
3800f5a034f9SPyun YongHyeon 	/*
3801f5a034f9SPyun YongHyeon 	 * This register wraps very quickly under heavy packet drops.
3802f5a034f9SPyun YongHyeon 	 * If you need correct statistics, you can enable this check.
3803f5a034f9SPyun YongHyeon 	 */
3804f5a034f9SPyun YongHyeon 	if (BGE_IS_5705_PLUS(sc))
3805f5a034f9SPyun YongHyeon 		ifp->if_ierrors += CSR_READ_4(sc, BGE_RXLP_LOCSTAT_IFIN_DROPS);
3806f5a034f9SPyun YongHyeon #endif
38071abcdbd1SAttilio Rao 	return (rx_npkts);
380895d67482SBill Paul }
380995d67482SBill Paul 
381095d67482SBill Paul static void
38111108273aSPyun YongHyeon bge_rxcsum(struct bge_softc *sc, struct bge_rx_bd *cur_rx, struct mbuf *m)
38121108273aSPyun YongHyeon {
38131108273aSPyun YongHyeon 
38141108273aSPyun YongHyeon 	if (BGE_IS_5717_PLUS(sc)) {
38151108273aSPyun YongHyeon 		if ((cur_rx->bge_flags & BGE_RXBDFLAG_IPV6) == 0) {
38161108273aSPyun YongHyeon 			if (cur_rx->bge_flags & BGE_RXBDFLAG_IP_CSUM) {
38171108273aSPyun YongHyeon 				m->m_pkthdr.csum_flags |= CSUM_IP_CHECKED;
38181108273aSPyun YongHyeon 				if ((cur_rx->bge_error_flag &
38191108273aSPyun YongHyeon 				    BGE_RXERRFLAG_IP_CSUM_NOK) == 0)
38201108273aSPyun YongHyeon 					m->m_pkthdr.csum_flags |= CSUM_IP_VALID;
38211108273aSPyun YongHyeon 			}
38221108273aSPyun YongHyeon 			if (cur_rx->bge_flags & BGE_RXBDFLAG_TCP_UDP_CSUM) {
38231108273aSPyun YongHyeon 				m->m_pkthdr.csum_data =
38241108273aSPyun YongHyeon 				    cur_rx->bge_tcp_udp_csum;
38251108273aSPyun YongHyeon 				m->m_pkthdr.csum_flags |= CSUM_DATA_VALID |
38261108273aSPyun YongHyeon 				    CSUM_PSEUDO_HDR;
38271108273aSPyun YongHyeon 			}
38281108273aSPyun YongHyeon 		}
38291108273aSPyun YongHyeon 	} else {
38301108273aSPyun YongHyeon 		if (cur_rx->bge_flags & BGE_RXBDFLAG_IP_CSUM) {
38311108273aSPyun YongHyeon 			m->m_pkthdr.csum_flags |= CSUM_IP_CHECKED;
38321108273aSPyun YongHyeon 			if ((cur_rx->bge_ip_csum ^ 0xFFFF) == 0)
38331108273aSPyun YongHyeon 				m->m_pkthdr.csum_flags |= CSUM_IP_VALID;
38341108273aSPyun YongHyeon 		}
38351108273aSPyun YongHyeon 		if (cur_rx->bge_flags & BGE_RXBDFLAG_TCP_UDP_CSUM &&
38361108273aSPyun YongHyeon 		    m->m_pkthdr.len >= ETHER_MIN_NOPAD) {
38371108273aSPyun YongHyeon 			m->m_pkthdr.csum_data =
38381108273aSPyun YongHyeon 			    cur_rx->bge_tcp_udp_csum;
38391108273aSPyun YongHyeon 			m->m_pkthdr.csum_flags |= CSUM_DATA_VALID |
38401108273aSPyun YongHyeon 			    CSUM_PSEUDO_HDR;
38411108273aSPyun YongHyeon 		}
38421108273aSPyun YongHyeon 	}
38431108273aSPyun YongHyeon }
38441108273aSPyun YongHyeon 
38451108273aSPyun YongHyeon static void
3846b9c05fa5SPyun YongHyeon bge_txeof(struct bge_softc *sc, uint16_t tx_cons)
384795d67482SBill Paul {
384895a0a340SPyun YongHyeon 	struct bge_tx_bd *cur_tx;
384995d67482SBill Paul 	struct ifnet *ifp;
385095d67482SBill Paul 
38510f9bd73bSSam Leffler 	BGE_LOCK_ASSERT(sc);
38520f9bd73bSSam Leffler 
38533f74909aSGleb Smirnoff 	/* Nothing to do. */
3854b9c05fa5SPyun YongHyeon 	if (sc->bge_tx_saved_considx == tx_cons)
3855cfcb5025SOleg Bulyzhin 		return;
3856cfcb5025SOleg Bulyzhin 
3857fc74a9f9SBrooks Davis 	ifp = sc->bge_ifp;
385895d67482SBill Paul 
3859e65bed95SPyun YongHyeon 	bus_dmamap_sync(sc->bge_cdata.bge_tx_ring_tag,
38605c1da2faSPyun YongHyeon 	    sc->bge_cdata.bge_tx_ring_map, BUS_DMASYNC_POSTWRITE);
386195d67482SBill Paul 	/*
386295d67482SBill Paul 	 * Go through our tx ring and free mbufs for those
386395d67482SBill Paul 	 * frames that have been sent.
386495d67482SBill Paul 	 */
3865b9c05fa5SPyun YongHyeon 	while (sc->bge_tx_saved_considx != tx_cons) {
386695a0a340SPyun YongHyeon 		uint32_t		idx;
386795d67482SBill Paul 
386895d67482SBill Paul 		idx = sc->bge_tx_saved_considx;
3869f41ac2beSBill Paul 		cur_tx = &sc->bge_ldata.bge_tx_ring[idx];
387095d67482SBill Paul 		if (cur_tx->bge_flags & BGE_TXBDFLAG_END)
387195d67482SBill Paul 			ifp->if_opackets++;
387295d67482SBill Paul 		if (sc->bge_cdata.bge_tx_chain[idx] != NULL) {
38730ac56796SPyun YongHyeon 			bus_dmamap_sync(sc->bge_cdata.bge_tx_mtag,
3874e65bed95SPyun YongHyeon 			    sc->bge_cdata.bge_tx_dmamap[idx],
3875e65bed95SPyun YongHyeon 			    BUS_DMASYNC_POSTWRITE);
38760ac56796SPyun YongHyeon 			bus_dmamap_unload(sc->bge_cdata.bge_tx_mtag,
3877f41ac2beSBill Paul 			    sc->bge_cdata.bge_tx_dmamap[idx]);
3878e65bed95SPyun YongHyeon 			m_freem(sc->bge_cdata.bge_tx_chain[idx]);
3879e65bed95SPyun YongHyeon 			sc->bge_cdata.bge_tx_chain[idx] = NULL;
388095d67482SBill Paul 		}
388195d67482SBill Paul 		sc->bge_txcnt--;
388295d67482SBill Paul 		BGE_INC(sc->bge_tx_saved_considx, BGE_TX_RING_CNT);
388395d67482SBill Paul 	}
388495d67482SBill Paul 
388513f4c340SRobert Watson 	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
38865b01e77cSBruce Evans 	if (sc->bge_txcnt == 0)
38875b01e77cSBruce Evans 		sc->bge_timer = 0;
388895d67482SBill Paul }
388995d67482SBill Paul 
389075719184SGleb Smirnoff #ifdef DEVICE_POLLING
38911abcdbd1SAttilio Rao static int
389275719184SGleb Smirnoff bge_poll(struct ifnet *ifp, enum poll_cmd cmd, int count)
389375719184SGleb Smirnoff {
389475719184SGleb Smirnoff 	struct bge_softc *sc = ifp->if_softc;
3895b9c05fa5SPyun YongHyeon 	uint16_t rx_prod, tx_cons;
3896366454f2SOleg Bulyzhin 	uint32_t statusword;
38971abcdbd1SAttilio Rao 	int rx_npkts = 0;
389875719184SGleb Smirnoff 
38993f74909aSGleb Smirnoff 	BGE_LOCK(sc);
39003f74909aSGleb Smirnoff 	if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) {
39013f74909aSGleb Smirnoff 		BGE_UNLOCK(sc);
39021abcdbd1SAttilio Rao 		return (rx_npkts);
39033f74909aSGleb Smirnoff 	}
390475719184SGleb Smirnoff 
3905dab5cd05SOleg Bulyzhin 	bus_dmamap_sync(sc->bge_cdata.bge_status_tag,
3906b9c05fa5SPyun YongHyeon 	    sc->bge_cdata.bge_status_map,
3907b9c05fa5SPyun YongHyeon 	    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
3908b9c05fa5SPyun YongHyeon 	rx_prod = sc->bge_ldata.bge_status_block->bge_idx[0].bge_rx_prod_idx;
3909b9c05fa5SPyun YongHyeon 	tx_cons = sc->bge_ldata.bge_status_block->bge_idx[0].bge_tx_cons_idx;
3910dab5cd05SOleg Bulyzhin 
3911175f8742SPyun YongHyeon 	statusword = sc->bge_ldata.bge_status_block->bge_status;
3912175f8742SPyun YongHyeon 	sc->bge_ldata.bge_status_block->bge_status = 0;
3913dab5cd05SOleg Bulyzhin 
3914dab5cd05SOleg Bulyzhin 	bus_dmamap_sync(sc->bge_cdata.bge_status_tag,
3915b9c05fa5SPyun YongHyeon 	    sc->bge_cdata.bge_status_map,
3916b9c05fa5SPyun YongHyeon 	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
3917366454f2SOleg Bulyzhin 
39180c8aa4eaSJung-uk Kim 	/* Note link event. It will be processed by POLL_AND_CHECK_STATUS. */
3919366454f2SOleg Bulyzhin 	if (statusword & BGE_STATFLAG_LINKSTATE_CHANGED)
3920366454f2SOleg Bulyzhin 		sc->bge_link_evt++;
3921366454f2SOleg Bulyzhin 
3922366454f2SOleg Bulyzhin 	if (cmd == POLL_AND_CHECK_STATUS)
3923366454f2SOleg Bulyzhin 		if ((sc->bge_asicrev == BGE_ASICREV_BCM5700 &&
39244c0da0ffSGleb Smirnoff 		    sc->bge_chipid != BGE_CHIPID_BCM5700_B2) ||
3925652ae483SGleb Smirnoff 		    sc->bge_link_evt || (sc->bge_flags & BGE_FLAG_TBI))
3926366454f2SOleg Bulyzhin 			bge_link_upd(sc);
3927366454f2SOleg Bulyzhin 
3928366454f2SOleg Bulyzhin 	sc->rxcycles = count;
3929dfe0df9aSPyun YongHyeon 	rx_npkts = bge_rxeof(sc, rx_prod, 1);
393025e13e68SXin LI 	if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) {
393125e13e68SXin LI 		BGE_UNLOCK(sc);
39328cf7d13dSAttilio Rao 		return (rx_npkts);
393325e13e68SXin LI 	}
3934b9c05fa5SPyun YongHyeon 	bge_txeof(sc, tx_cons);
3935366454f2SOleg Bulyzhin 	if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
3936366454f2SOleg Bulyzhin 		bge_start_locked(ifp);
39373f74909aSGleb Smirnoff 
39383f74909aSGleb Smirnoff 	BGE_UNLOCK(sc);
39391abcdbd1SAttilio Rao 	return (rx_npkts);
394075719184SGleb Smirnoff }
394175719184SGleb Smirnoff #endif /* DEVICE_POLLING */
394275719184SGleb Smirnoff 
3943dfe0df9aSPyun YongHyeon static int
3944dfe0df9aSPyun YongHyeon bge_msi_intr(void *arg)
3945dfe0df9aSPyun YongHyeon {
3946dfe0df9aSPyun YongHyeon 	struct bge_softc *sc;
3947dfe0df9aSPyun YongHyeon 
3948dfe0df9aSPyun YongHyeon 	sc = (struct bge_softc *)arg;
3949dfe0df9aSPyun YongHyeon 	/*
3950dfe0df9aSPyun YongHyeon 	 * This interrupt is not shared and controller already
3951dfe0df9aSPyun YongHyeon 	 * disabled further interrupt.
3952dfe0df9aSPyun YongHyeon 	 */
3953dfe0df9aSPyun YongHyeon 	taskqueue_enqueue(sc->bge_tq, &sc->bge_intr_task);
3954dfe0df9aSPyun YongHyeon 	return (FILTER_HANDLED);
3955dfe0df9aSPyun YongHyeon }
3956dfe0df9aSPyun YongHyeon 
3957dfe0df9aSPyun YongHyeon static void
3958dfe0df9aSPyun YongHyeon bge_intr_task(void *arg, int pending)
3959dfe0df9aSPyun YongHyeon {
3960dfe0df9aSPyun YongHyeon 	struct bge_softc *sc;
3961dfe0df9aSPyun YongHyeon 	struct ifnet *ifp;
39621108273aSPyun YongHyeon 	uint32_t status, status_tag;
3963dfe0df9aSPyun YongHyeon 	uint16_t rx_prod, tx_cons;
3964dfe0df9aSPyun YongHyeon 
3965dfe0df9aSPyun YongHyeon 	sc = (struct bge_softc *)arg;
3966dfe0df9aSPyun YongHyeon 	ifp = sc->bge_ifp;
3967dfe0df9aSPyun YongHyeon 
396866151edfSPyun YongHyeon 	BGE_LOCK(sc);
396966151edfSPyun YongHyeon 	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) {
397066151edfSPyun YongHyeon 		BGE_UNLOCK(sc);
3971dfe0df9aSPyun YongHyeon 		return;
397266151edfSPyun YongHyeon 	}
3973dfe0df9aSPyun YongHyeon 
3974dfe0df9aSPyun YongHyeon 	/* Get updated status block. */
3975dfe0df9aSPyun YongHyeon 	bus_dmamap_sync(sc->bge_cdata.bge_status_tag,
3976dfe0df9aSPyun YongHyeon 	    sc->bge_cdata.bge_status_map,
3977dfe0df9aSPyun YongHyeon 	    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
3978dfe0df9aSPyun YongHyeon 
3979dfe0df9aSPyun YongHyeon 	/* Save producer/consumer indexess. */
3980dfe0df9aSPyun YongHyeon 	rx_prod = sc->bge_ldata.bge_status_block->bge_idx[0].bge_rx_prod_idx;
3981dfe0df9aSPyun YongHyeon 	tx_cons = sc->bge_ldata.bge_status_block->bge_idx[0].bge_tx_cons_idx;
3982dfe0df9aSPyun YongHyeon 	status = sc->bge_ldata.bge_status_block->bge_status;
39831108273aSPyun YongHyeon 	status_tag = sc->bge_ldata.bge_status_block->bge_status_tag << 24;
3984dfe0df9aSPyun YongHyeon 	sc->bge_ldata.bge_status_block->bge_status = 0;
3985dfe0df9aSPyun YongHyeon 	bus_dmamap_sync(sc->bge_cdata.bge_status_tag,
3986dfe0df9aSPyun YongHyeon 	    sc->bge_cdata.bge_status_map,
3987dfe0df9aSPyun YongHyeon 	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
39881108273aSPyun YongHyeon 	if ((sc->bge_flags & BGE_FLAG_TAGGED_STATUS) == 0)
39891108273aSPyun YongHyeon 		status_tag = 0;
399066151edfSPyun YongHyeon 
399166151edfSPyun YongHyeon 	if ((status & BGE_STATFLAG_LINKSTATE_CHANGED) != 0)
399266151edfSPyun YongHyeon 		bge_link_upd(sc);
399366151edfSPyun YongHyeon 
3994dfe0df9aSPyun YongHyeon 	/* Let controller work. */
39951108273aSPyun YongHyeon 	bge_writembx(sc, BGE_MBX_IRQ0_LO, status_tag);
3996dfe0df9aSPyun YongHyeon 
399766151edfSPyun YongHyeon 	if (ifp->if_drv_flags & IFF_DRV_RUNNING &&
399866151edfSPyun YongHyeon 	    sc->bge_rx_saved_considx != rx_prod) {
3999dfe0df9aSPyun YongHyeon 		/* Check RX return ring producer/consumer. */
400066151edfSPyun YongHyeon 		BGE_UNLOCK(sc);
4001dfe0df9aSPyun YongHyeon 		bge_rxeof(sc, rx_prod, 0);
400266151edfSPyun YongHyeon 		BGE_LOCK(sc);
4003dfe0df9aSPyun YongHyeon 	}
4004dfe0df9aSPyun YongHyeon 	if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
4005dfe0df9aSPyun YongHyeon 		/* Check TX ring producer/consumer. */
4006dfe0df9aSPyun YongHyeon 		bge_txeof(sc, tx_cons);
4007dfe0df9aSPyun YongHyeon 		if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
4008dfe0df9aSPyun YongHyeon 			bge_start_locked(ifp);
4009dfe0df9aSPyun YongHyeon 	}
401066151edfSPyun YongHyeon 	BGE_UNLOCK(sc);
4011dfe0df9aSPyun YongHyeon }
4012dfe0df9aSPyun YongHyeon 
401395d67482SBill Paul static void
40143f74909aSGleb Smirnoff bge_intr(void *xsc)
401595d67482SBill Paul {
401695d67482SBill Paul 	struct bge_softc *sc;
401795d67482SBill Paul 	struct ifnet *ifp;
4018dab5cd05SOleg Bulyzhin 	uint32_t statusword;
4019b9c05fa5SPyun YongHyeon 	uint16_t rx_prod, tx_cons;
402095d67482SBill Paul 
402195d67482SBill Paul 	sc = xsc;
4022f41ac2beSBill Paul 
40230f9bd73bSSam Leffler 	BGE_LOCK(sc);
40240f9bd73bSSam Leffler 
4025dab5cd05SOleg Bulyzhin 	ifp = sc->bge_ifp;
4026dab5cd05SOleg Bulyzhin 
402775719184SGleb Smirnoff #ifdef DEVICE_POLLING
402875719184SGleb Smirnoff 	if (ifp->if_capenable & IFCAP_POLLING) {
402975719184SGleb Smirnoff 		BGE_UNLOCK(sc);
403075719184SGleb Smirnoff 		return;
403175719184SGleb Smirnoff 	}
403275719184SGleb Smirnoff #endif
403375719184SGleb Smirnoff 
4034f30cbfc6SScott Long 	/*
4035b848e032SBruce Evans 	 * Ack the interrupt by writing something to BGE_MBX_IRQ0_LO.  Don't
4036b848e032SBruce Evans 	 * disable interrupts by writing nonzero like we used to, since with
4037b848e032SBruce Evans 	 * our current organization this just gives complications and
4038b848e032SBruce Evans 	 * pessimizations for re-enabling interrupts.  We used to have races
4039b848e032SBruce Evans 	 * instead of the necessary complications.  Disabling interrupts
4040b848e032SBruce Evans 	 * would just reduce the chance of a status update while we are
4041b848e032SBruce Evans 	 * running (by switching to the interrupt-mode coalescence
4042b848e032SBruce Evans 	 * parameters), but this chance is already very low so it is more
4043b848e032SBruce Evans 	 * efficient to get another interrupt than prevent it.
4044b848e032SBruce Evans 	 *
4045b848e032SBruce Evans 	 * We do the ack first to ensure another interrupt if there is a
4046b848e032SBruce Evans 	 * status update after the ack.  We don't check for the status
4047b848e032SBruce Evans 	 * changing later because it is more efficient to get another
4048b848e032SBruce Evans 	 * interrupt than prevent it, not quite as above (not checking is
4049b848e032SBruce Evans 	 * a smaller optimization than not toggling the interrupt enable,
4050b848e032SBruce Evans 	 * since checking doesn't involve PCI accesses and toggling require
4051b848e032SBruce Evans 	 * the status check).  So toggling would probably be a pessimization
4052b848e032SBruce Evans 	 * even with MSI.  It would only be needed for using a task queue.
4053b848e032SBruce Evans 	 */
405438cc658fSJohn Baldwin 	bge_writembx(sc, BGE_MBX_IRQ0_LO, 0);
4055b848e032SBruce Evans 
4056f584dfd1SPyun YongHyeon 	/*
4057f584dfd1SPyun YongHyeon 	 * Do the mandatory PCI flush as well as get the link status.
4058f584dfd1SPyun YongHyeon 	 */
4059f584dfd1SPyun YongHyeon 	statusword = CSR_READ_4(sc, BGE_MAC_STS) & BGE_MACSTAT_LINK_CHANGED;
4060f584dfd1SPyun YongHyeon 
4061f584dfd1SPyun YongHyeon 	/* Make sure the descriptor ring indexes are coherent. */
4062f584dfd1SPyun YongHyeon 	bus_dmamap_sync(sc->bge_cdata.bge_status_tag,
4063f584dfd1SPyun YongHyeon 	    sc->bge_cdata.bge_status_map,
4064f584dfd1SPyun YongHyeon 	    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
4065f584dfd1SPyun YongHyeon 	rx_prod = sc->bge_ldata.bge_status_block->bge_idx[0].bge_rx_prod_idx;
4066f584dfd1SPyun YongHyeon 	tx_cons = sc->bge_ldata.bge_status_block->bge_idx[0].bge_tx_cons_idx;
4067f584dfd1SPyun YongHyeon 	sc->bge_ldata.bge_status_block->bge_status = 0;
4068f584dfd1SPyun YongHyeon 	bus_dmamap_sync(sc->bge_cdata.bge_status_tag,
4069f584dfd1SPyun YongHyeon 	    sc->bge_cdata.bge_status_map,
4070f584dfd1SPyun YongHyeon 	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
4071f584dfd1SPyun YongHyeon 
40721f313773SOleg Bulyzhin 	if ((sc->bge_asicrev == BGE_ASICREV_BCM5700 &&
40734c0da0ffSGleb Smirnoff 	    sc->bge_chipid != BGE_CHIPID_BCM5700_B2) ||
4074f30cbfc6SScott Long 	    statusword || sc->bge_link_evt)
4075dab5cd05SOleg Bulyzhin 		bge_link_upd(sc);
407695d67482SBill Paul 
407713f4c340SRobert Watson 	if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
40783f74909aSGleb Smirnoff 		/* Check RX return ring producer/consumer. */
4079dfe0df9aSPyun YongHyeon 		bge_rxeof(sc, rx_prod, 1);
408025e13e68SXin LI 	}
408195d67482SBill Paul 
408225e13e68SXin LI 	if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
40833f74909aSGleb Smirnoff 		/* Check TX ring producer/consumer. */
4084b9c05fa5SPyun YongHyeon 		bge_txeof(sc, tx_cons);
408595d67482SBill Paul 	}
408695d67482SBill Paul 
408713f4c340SRobert Watson 	if (ifp->if_drv_flags & IFF_DRV_RUNNING &&
408813f4c340SRobert Watson 	    !IFQ_DRV_IS_EMPTY(&ifp->if_snd))
40890f9bd73bSSam Leffler 		bge_start_locked(ifp);
40900f9bd73bSSam Leffler 
40910f9bd73bSSam Leffler 	BGE_UNLOCK(sc);
409295d67482SBill Paul }
409395d67482SBill Paul 
409495d67482SBill Paul static void
40958cb1383cSDoug Ambrisko bge_asf_driver_up(struct bge_softc *sc)
40968cb1383cSDoug Ambrisko {
40978cb1383cSDoug Ambrisko 	if (sc->bge_asf_mode & ASF_STACKUP) {
40988cb1383cSDoug Ambrisko 		/* Send ASF heartbeat aprox. every 2s */
40998cb1383cSDoug Ambrisko 		if (sc->bge_asf_count)
41008cb1383cSDoug Ambrisko 			sc->bge_asf_count --;
41018cb1383cSDoug Ambrisko 		else {
4102899d6846SPyun YongHyeon 			sc->bge_asf_count = 2;
4103888b47f0SPyun YongHyeon 			bge_writemem_ind(sc, BGE_SRAM_FW_CMD_MB,
41048cb1383cSDoug Ambrisko 			    BGE_FW_DRV_ALIVE);
4105888b47f0SPyun YongHyeon 			bge_writemem_ind(sc, BGE_SRAM_FW_CMD_LEN_MB, 4);
4106888b47f0SPyun YongHyeon 			bge_writemem_ind(sc, BGE_SRAM_FW_CMD_DATA_MB, 3);
4107*3fed2d5dSPyun YongHyeon 			CSR_WRITE_4(sc, BGE_RX_CPU_EVENT,
4108*3fed2d5dSPyun YongHyeon 			    CSR_READ_4(sc, BGE_RX_CPU_EVENT) | (1 << 14));
41098cb1383cSDoug Ambrisko 		}
41108cb1383cSDoug Ambrisko 	}
41118cb1383cSDoug Ambrisko }
41128cb1383cSDoug Ambrisko 
41138cb1383cSDoug Ambrisko static void
4114b74e67fbSGleb Smirnoff bge_tick(void *xsc)
41150f9bd73bSSam Leffler {
4116b74e67fbSGleb Smirnoff 	struct bge_softc *sc = xsc;
411795d67482SBill Paul 	struct mii_data *mii = NULL;
411895d67482SBill Paul 
41190f9bd73bSSam Leffler 	BGE_LOCK_ASSERT(sc);
412095d67482SBill Paul 
41215dda8085SOleg Bulyzhin 	/* Synchronize with possible callout reset/stop. */
41225dda8085SOleg Bulyzhin 	if (callout_pending(&sc->bge_stat_ch) ||
41235dda8085SOleg Bulyzhin 	    !callout_active(&sc->bge_stat_ch))
41245dda8085SOleg Bulyzhin 		return;
41255dda8085SOleg Bulyzhin 
41267ee00338SJung-uk Kim 	if (BGE_IS_5705_PLUS(sc))
41270434d1b8SBill Paul 		bge_stats_update_regs(sc);
41280434d1b8SBill Paul 	else
412995d67482SBill Paul 		bge_stats_update(sc);
413095d67482SBill Paul 
4131652ae483SGleb Smirnoff 	if ((sc->bge_flags & BGE_FLAG_TBI) == 0) {
413295d67482SBill Paul 		mii = device_get_softc(sc->bge_miibus);
413382b67c01SOleg Bulyzhin 		/*
413482b67c01SOleg Bulyzhin 		 * Do not touch PHY if we have link up. This could break
413582b67c01SOleg Bulyzhin 		 * IPMI/ASF mode or produce extra input errors
413682b67c01SOleg Bulyzhin 		 * (extra errors was reported for bcm5701 & bcm5704).
413782b67c01SOleg Bulyzhin 		 */
413882b67c01SOleg Bulyzhin 		if (!sc->bge_link)
413995d67482SBill Paul 			mii_tick(mii);
41407b97099dSOleg Bulyzhin 	} else {
41417b97099dSOleg Bulyzhin 		/*
41427b97099dSOleg Bulyzhin 		 * Since in TBI mode auto-polling can't be used we should poll
41437b97099dSOleg Bulyzhin 		 * link status manually. Here we register pending link event
41447b97099dSOleg Bulyzhin 		 * and trigger interrupt.
41457b97099dSOleg Bulyzhin 		 */
41467b97099dSOleg Bulyzhin #ifdef DEVICE_POLLING
41473f74909aSGleb Smirnoff 		/* In polling mode we poll link state in bge_poll(). */
41487b97099dSOleg Bulyzhin 		if (!(sc->bge_ifp->if_capenable & IFCAP_POLLING))
41497b97099dSOleg Bulyzhin #endif
41507b97099dSOleg Bulyzhin 		{
41517b97099dSOleg Bulyzhin 		sc->bge_link_evt++;
41524f0794ffSBjoern A. Zeeb 		if (sc->bge_asicrev == BGE_ASICREV_BCM5700 ||
41534f0794ffSBjoern A. Zeeb 		    sc->bge_flags & BGE_FLAG_5788)
41547b97099dSOleg Bulyzhin 			BGE_SETBIT(sc, BGE_MISC_LOCAL_CTL, BGE_MLC_INTR_SET);
41554f0794ffSBjoern A. Zeeb 		else
41564f0794ffSBjoern A. Zeeb 			BGE_SETBIT(sc, BGE_HCC_MODE, BGE_HCCMODE_COAL_NOW);
41577b97099dSOleg Bulyzhin 		}
4158dab5cd05SOleg Bulyzhin 	}
415995d67482SBill Paul 
41608cb1383cSDoug Ambrisko 	bge_asf_driver_up(sc);
4161b74e67fbSGleb Smirnoff 	bge_watchdog(sc);
41628cb1383cSDoug Ambrisko 
4163dab5cd05SOleg Bulyzhin 	callout_reset(&sc->bge_stat_ch, hz, bge_tick, sc);
416495d67482SBill Paul }
416595d67482SBill Paul 
416695d67482SBill Paul static void
41673f74909aSGleb Smirnoff bge_stats_update_regs(struct bge_softc *sc)
41680434d1b8SBill Paul {
41693f74909aSGleb Smirnoff 	struct ifnet *ifp;
41702280c16bSPyun YongHyeon 	struct bge_mac_stats *stats;
41710434d1b8SBill Paul 
4172fc74a9f9SBrooks Davis 	ifp = sc->bge_ifp;
41732280c16bSPyun YongHyeon 	stats = &sc->bge_mac_stats;
41740434d1b8SBill Paul 
41752280c16bSPyun YongHyeon 	stats->ifHCOutOctets +=
41762280c16bSPyun YongHyeon 	    CSR_READ_4(sc, BGE_TX_MAC_STATS_OCTETS);
41772280c16bSPyun YongHyeon 	stats->etherStatsCollisions +=
41782280c16bSPyun YongHyeon 	    CSR_READ_4(sc, BGE_TX_MAC_STATS_COLLS);
41792280c16bSPyun YongHyeon 	stats->outXonSent +=
41802280c16bSPyun YongHyeon 	    CSR_READ_4(sc, BGE_TX_MAC_STATS_XON_SENT);
41812280c16bSPyun YongHyeon 	stats->outXoffSent +=
41822280c16bSPyun YongHyeon 	    CSR_READ_4(sc, BGE_TX_MAC_STATS_XOFF_SENT);
41832280c16bSPyun YongHyeon 	stats->dot3StatsInternalMacTransmitErrors +=
41842280c16bSPyun YongHyeon 	    CSR_READ_4(sc, BGE_TX_MAC_STATS_ERRORS);
41852280c16bSPyun YongHyeon 	stats->dot3StatsSingleCollisionFrames +=
41862280c16bSPyun YongHyeon 	    CSR_READ_4(sc, BGE_TX_MAC_STATS_SINGLE_COLL);
41872280c16bSPyun YongHyeon 	stats->dot3StatsMultipleCollisionFrames +=
41882280c16bSPyun YongHyeon 	    CSR_READ_4(sc, BGE_TX_MAC_STATS_MULTI_COLL);
41892280c16bSPyun YongHyeon 	stats->dot3StatsDeferredTransmissions +=
41902280c16bSPyun YongHyeon 	    CSR_READ_4(sc, BGE_TX_MAC_STATS_DEFERRED);
41912280c16bSPyun YongHyeon 	stats->dot3StatsExcessiveCollisions +=
41922280c16bSPyun YongHyeon 	    CSR_READ_4(sc, BGE_TX_MAC_STATS_EXCESS_COLL);
41932280c16bSPyun YongHyeon 	stats->dot3StatsLateCollisions +=
41942280c16bSPyun YongHyeon 	    CSR_READ_4(sc, BGE_TX_MAC_STATS_LATE_COLL);
41952280c16bSPyun YongHyeon 	stats->ifHCOutUcastPkts +=
41962280c16bSPyun YongHyeon 	    CSR_READ_4(sc, BGE_TX_MAC_STATS_UCAST);
41972280c16bSPyun YongHyeon 	stats->ifHCOutMulticastPkts +=
41982280c16bSPyun YongHyeon 	    CSR_READ_4(sc, BGE_TX_MAC_STATS_MCAST);
41992280c16bSPyun YongHyeon 	stats->ifHCOutBroadcastPkts +=
42002280c16bSPyun YongHyeon 	    CSR_READ_4(sc, BGE_TX_MAC_STATS_BCAST);
42017e6e2507SJung-uk Kim 
42022280c16bSPyun YongHyeon 	stats->ifHCInOctets +=
42032280c16bSPyun YongHyeon 	    CSR_READ_4(sc, BGE_RX_MAC_STATS_OCTESTS);
42042280c16bSPyun YongHyeon 	stats->etherStatsFragments +=
42052280c16bSPyun YongHyeon 	    CSR_READ_4(sc, BGE_RX_MAC_STATS_FRAGMENTS);
42062280c16bSPyun YongHyeon 	stats->ifHCInUcastPkts +=
42072280c16bSPyun YongHyeon 	    CSR_READ_4(sc, BGE_RX_MAC_STATS_UCAST);
42082280c16bSPyun YongHyeon 	stats->ifHCInMulticastPkts +=
42092280c16bSPyun YongHyeon 	    CSR_READ_4(sc, BGE_RX_MAC_STATS_MCAST);
42102280c16bSPyun YongHyeon 	stats->ifHCInBroadcastPkts +=
42112280c16bSPyun YongHyeon 	    CSR_READ_4(sc, BGE_RX_MAC_STATS_BCAST);
42122280c16bSPyun YongHyeon 	stats->dot3StatsFCSErrors +=
42132280c16bSPyun YongHyeon 	    CSR_READ_4(sc, BGE_RX_MAC_STATS_FCS_ERRORS);
42142280c16bSPyun YongHyeon 	stats->dot3StatsAlignmentErrors +=
42152280c16bSPyun YongHyeon 	    CSR_READ_4(sc, BGE_RX_MAC_STATS_ALGIN_ERRORS);
42162280c16bSPyun YongHyeon 	stats->xonPauseFramesReceived +=
42172280c16bSPyun YongHyeon 	    CSR_READ_4(sc, BGE_RX_MAC_STATS_XON_RCVD);
42182280c16bSPyun YongHyeon 	stats->xoffPauseFramesReceived +=
42192280c16bSPyun YongHyeon 	    CSR_READ_4(sc, BGE_RX_MAC_STATS_XOFF_RCVD);
42202280c16bSPyun YongHyeon 	stats->macControlFramesReceived +=
42212280c16bSPyun YongHyeon 	    CSR_READ_4(sc, BGE_RX_MAC_STATS_CTRL_RCVD);
42222280c16bSPyun YongHyeon 	stats->xoffStateEntered +=
42232280c16bSPyun YongHyeon 	    CSR_READ_4(sc, BGE_RX_MAC_STATS_XOFF_ENTERED);
42242280c16bSPyun YongHyeon 	stats->dot3StatsFramesTooLong +=
42252280c16bSPyun YongHyeon 	    CSR_READ_4(sc, BGE_RX_MAC_STATS_FRAME_TOO_LONG);
42262280c16bSPyun YongHyeon 	stats->etherStatsJabbers +=
42272280c16bSPyun YongHyeon 	    CSR_READ_4(sc, BGE_RX_MAC_STATS_JABBERS);
42282280c16bSPyun YongHyeon 	stats->etherStatsUndersizePkts +=
42292280c16bSPyun YongHyeon 	    CSR_READ_4(sc, BGE_RX_MAC_STATS_UNDERSIZE);
42302280c16bSPyun YongHyeon 
42312280c16bSPyun YongHyeon 	stats->FramesDroppedDueToFilters +=
42322280c16bSPyun YongHyeon 	    CSR_READ_4(sc, BGE_RXLP_LOCSTAT_FILTDROP);
42332280c16bSPyun YongHyeon 	stats->DmaWriteQueueFull +=
42342280c16bSPyun YongHyeon 	    CSR_READ_4(sc, BGE_RXLP_LOCSTAT_DMA_WRQ_FULL);
42352280c16bSPyun YongHyeon 	stats->DmaWriteHighPriQueueFull +=
42362280c16bSPyun YongHyeon 	    CSR_READ_4(sc, BGE_RXLP_LOCSTAT_DMA_HPWRQ_FULL);
42372280c16bSPyun YongHyeon 	stats->NoMoreRxBDs +=
42382280c16bSPyun YongHyeon 	    CSR_READ_4(sc, BGE_RXLP_LOCSTAT_OUT_OF_BDS);
42392280c16bSPyun YongHyeon 	stats->InputDiscards +=
42402280c16bSPyun YongHyeon 	    CSR_READ_4(sc, BGE_RXLP_LOCSTAT_IFIN_DROPS);
42412280c16bSPyun YongHyeon 	stats->InputErrors +=
42422280c16bSPyun YongHyeon 	    CSR_READ_4(sc, BGE_RXLP_LOCSTAT_IFIN_ERRORS);
42432280c16bSPyun YongHyeon 	stats->RecvThresholdHit +=
42442280c16bSPyun YongHyeon 	    CSR_READ_4(sc, BGE_RXLP_LOCSTAT_RXTHRESH_HIT);
42452280c16bSPyun YongHyeon 
42462280c16bSPyun YongHyeon 	ifp->if_collisions = (u_long)stats->etherStatsCollisions;
42472280c16bSPyun YongHyeon 	ifp->if_ierrors = (u_long)(stats->NoMoreRxBDs + stats->InputDiscards +
42482280c16bSPyun YongHyeon 	    stats->InputErrors);
42492280c16bSPyun YongHyeon }
42502280c16bSPyun YongHyeon 
42512280c16bSPyun YongHyeon static void
42522280c16bSPyun YongHyeon bge_stats_clear_regs(struct bge_softc *sc)
42532280c16bSPyun YongHyeon {
42542280c16bSPyun YongHyeon 
42552280c16bSPyun YongHyeon 	CSR_READ_4(sc, BGE_TX_MAC_STATS_OCTETS);
42562280c16bSPyun YongHyeon 	CSR_READ_4(sc, BGE_TX_MAC_STATS_COLLS);
42572280c16bSPyun YongHyeon 	CSR_READ_4(sc, BGE_TX_MAC_STATS_XON_SENT);
42582280c16bSPyun YongHyeon 	CSR_READ_4(sc, BGE_TX_MAC_STATS_XOFF_SENT);
42592280c16bSPyun YongHyeon 	CSR_READ_4(sc, BGE_TX_MAC_STATS_ERRORS);
42602280c16bSPyun YongHyeon 	CSR_READ_4(sc, BGE_TX_MAC_STATS_SINGLE_COLL);
42612280c16bSPyun YongHyeon 	CSR_READ_4(sc, BGE_TX_MAC_STATS_MULTI_COLL);
42622280c16bSPyun YongHyeon 	CSR_READ_4(sc, BGE_TX_MAC_STATS_DEFERRED);
42632280c16bSPyun YongHyeon 	CSR_READ_4(sc, BGE_TX_MAC_STATS_EXCESS_COLL);
42642280c16bSPyun YongHyeon 	CSR_READ_4(sc, BGE_TX_MAC_STATS_LATE_COLL);
42652280c16bSPyun YongHyeon 	CSR_READ_4(sc, BGE_TX_MAC_STATS_UCAST);
42662280c16bSPyun YongHyeon 	CSR_READ_4(sc, BGE_TX_MAC_STATS_MCAST);
42672280c16bSPyun YongHyeon 	CSR_READ_4(sc, BGE_TX_MAC_STATS_BCAST);
42682280c16bSPyun YongHyeon 
42692280c16bSPyun YongHyeon 	CSR_READ_4(sc, BGE_RX_MAC_STATS_OCTESTS);
42702280c16bSPyun YongHyeon 	CSR_READ_4(sc, BGE_RX_MAC_STATS_FRAGMENTS);
42712280c16bSPyun YongHyeon 	CSR_READ_4(sc, BGE_RX_MAC_STATS_UCAST);
42722280c16bSPyun YongHyeon 	CSR_READ_4(sc, BGE_RX_MAC_STATS_MCAST);
42732280c16bSPyun YongHyeon 	CSR_READ_4(sc, BGE_RX_MAC_STATS_BCAST);
42742280c16bSPyun YongHyeon 	CSR_READ_4(sc, BGE_RX_MAC_STATS_FCS_ERRORS);
42752280c16bSPyun YongHyeon 	CSR_READ_4(sc, BGE_RX_MAC_STATS_ALGIN_ERRORS);
42762280c16bSPyun YongHyeon 	CSR_READ_4(sc, BGE_RX_MAC_STATS_XON_RCVD);
42772280c16bSPyun YongHyeon 	CSR_READ_4(sc, BGE_RX_MAC_STATS_XOFF_RCVD);
42782280c16bSPyun YongHyeon 	CSR_READ_4(sc, BGE_RX_MAC_STATS_CTRL_RCVD);
42792280c16bSPyun YongHyeon 	CSR_READ_4(sc, BGE_RX_MAC_STATS_XOFF_ENTERED);
42802280c16bSPyun YongHyeon 	CSR_READ_4(sc, BGE_RX_MAC_STATS_FRAME_TOO_LONG);
42812280c16bSPyun YongHyeon 	CSR_READ_4(sc, BGE_RX_MAC_STATS_JABBERS);
42822280c16bSPyun YongHyeon 	CSR_READ_4(sc, BGE_RX_MAC_STATS_UNDERSIZE);
42832280c16bSPyun YongHyeon 
42842280c16bSPyun YongHyeon 	CSR_READ_4(sc, BGE_RXLP_LOCSTAT_FILTDROP);
42852280c16bSPyun YongHyeon 	CSR_READ_4(sc, BGE_RXLP_LOCSTAT_DMA_WRQ_FULL);
42862280c16bSPyun YongHyeon 	CSR_READ_4(sc, BGE_RXLP_LOCSTAT_DMA_HPWRQ_FULL);
42872280c16bSPyun YongHyeon 	CSR_READ_4(sc, BGE_RXLP_LOCSTAT_OUT_OF_BDS);
42882280c16bSPyun YongHyeon 	CSR_READ_4(sc, BGE_RXLP_LOCSTAT_IFIN_DROPS);
42892280c16bSPyun YongHyeon 	CSR_READ_4(sc, BGE_RXLP_LOCSTAT_IFIN_ERRORS);
42902280c16bSPyun YongHyeon 	CSR_READ_4(sc, BGE_RXLP_LOCSTAT_RXTHRESH_HIT);
42910434d1b8SBill Paul }
42920434d1b8SBill Paul 
42930434d1b8SBill Paul static void
42943f74909aSGleb Smirnoff bge_stats_update(struct bge_softc *sc)
429595d67482SBill Paul {
429695d67482SBill Paul 	struct ifnet *ifp;
4297e907febfSPyun YongHyeon 	bus_size_t stats;
42987e6e2507SJung-uk Kim 	uint32_t cnt;	/* current register value */
429995d67482SBill Paul 
4300fc74a9f9SBrooks Davis 	ifp = sc->bge_ifp;
430195d67482SBill Paul 
4302e907febfSPyun YongHyeon 	stats = BGE_MEMWIN_START + BGE_STATS_BLOCK;
4303e907febfSPyun YongHyeon 
4304e907febfSPyun YongHyeon #define	READ_STAT(sc, stats, stat) \
4305e907febfSPyun YongHyeon 	CSR_READ_4(sc, stats + offsetof(struct bge_stats, stat))
430695d67482SBill Paul 
43078634dfffSJung-uk Kim 	cnt = READ_STAT(sc, stats, txstats.etherStatsCollisions.bge_addr_lo);
43086b037352SJung-uk Kim 	ifp->if_collisions += (uint32_t)(cnt - sc->bge_tx_collisions);
43096fb34dd2SOleg Bulyzhin 	sc->bge_tx_collisions = cnt;
43106fb34dd2SOleg Bulyzhin 
43116fb34dd2SOleg Bulyzhin 	cnt = READ_STAT(sc, stats, ifInDiscards.bge_addr_lo);
43126b037352SJung-uk Kim 	ifp->if_ierrors += (uint32_t)(cnt - sc->bge_rx_discards);
43136fb34dd2SOleg Bulyzhin 	sc->bge_rx_discards = cnt;
43146fb34dd2SOleg Bulyzhin 
43156fb34dd2SOleg Bulyzhin 	cnt = READ_STAT(sc, stats, txstats.ifOutDiscards.bge_addr_lo);
43166b037352SJung-uk Kim 	ifp->if_oerrors += (uint32_t)(cnt - sc->bge_tx_discards);
43176fb34dd2SOleg Bulyzhin 	sc->bge_tx_discards = cnt;
431895d67482SBill Paul 
4319e907febfSPyun YongHyeon #undef	READ_STAT
432095d67482SBill Paul }
432195d67482SBill Paul 
432295d67482SBill Paul /*
4323d375e524SGleb Smirnoff  * Pad outbound frame to ETHER_MIN_NOPAD for an unusual reason.
4324d375e524SGleb Smirnoff  * The bge hardware will pad out Tx runts to ETHER_MIN_NOPAD,
4325d375e524SGleb Smirnoff  * but when such padded frames employ the bge IP/TCP checksum offload,
4326d375e524SGleb Smirnoff  * the hardware checksum assist gives incorrect results (possibly
4327d375e524SGleb Smirnoff  * from incorporating its own padding into the UDP/TCP checksum; who knows).
4328d375e524SGleb Smirnoff  * If we pad such runts with zeros, the onboard checksum comes out correct.
4329d375e524SGleb Smirnoff  */
4330d375e524SGleb Smirnoff static __inline int
4331d375e524SGleb Smirnoff bge_cksum_pad(struct mbuf *m)
4332d375e524SGleb Smirnoff {
4333d375e524SGleb Smirnoff 	int padlen = ETHER_MIN_NOPAD - m->m_pkthdr.len;
4334d375e524SGleb Smirnoff 	struct mbuf *last;
4335d375e524SGleb Smirnoff 
4336d375e524SGleb Smirnoff 	/* If there's only the packet-header and we can pad there, use it. */
4337d375e524SGleb Smirnoff 	if (m->m_pkthdr.len == m->m_len && M_WRITABLE(m) &&
4338d375e524SGleb Smirnoff 	    M_TRAILINGSPACE(m) >= padlen) {
4339d375e524SGleb Smirnoff 		last = m;
4340d375e524SGleb Smirnoff 	} else {
4341d375e524SGleb Smirnoff 		/*
4342d375e524SGleb Smirnoff 		 * Walk packet chain to find last mbuf. We will either
4343d375e524SGleb Smirnoff 		 * pad there, or append a new mbuf and pad it.
4344d375e524SGleb Smirnoff 		 */
4345d375e524SGleb Smirnoff 		for (last = m; last->m_next != NULL; last = last->m_next);
4346d375e524SGleb Smirnoff 		if (!(M_WRITABLE(last) && M_TRAILINGSPACE(last) >= padlen)) {
4347d375e524SGleb Smirnoff 			/* Allocate new empty mbuf, pad it. Compact later. */
4348d375e524SGleb Smirnoff 			struct mbuf *n;
4349d375e524SGleb Smirnoff 
4350d375e524SGleb Smirnoff 			MGET(n, M_DONTWAIT, MT_DATA);
4351d375e524SGleb Smirnoff 			if (n == NULL)
4352d375e524SGleb Smirnoff 				return (ENOBUFS);
4353d375e524SGleb Smirnoff 			n->m_len = 0;
4354d375e524SGleb Smirnoff 			last->m_next = n;
4355d375e524SGleb Smirnoff 			last = n;
4356d375e524SGleb Smirnoff 		}
4357d375e524SGleb Smirnoff 	}
4358d375e524SGleb Smirnoff 
4359d375e524SGleb Smirnoff 	/* Now zero the pad area, to avoid the bge cksum-assist bug. */
4360d375e524SGleb Smirnoff 	memset(mtod(last, caddr_t) + last->m_len, 0, padlen);
4361d375e524SGleb Smirnoff 	last->m_len += padlen;
4362d375e524SGleb Smirnoff 	m->m_pkthdr.len += padlen;
4363d375e524SGleb Smirnoff 
4364d375e524SGleb Smirnoff 	return (0);
4365d375e524SGleb Smirnoff }
4366d375e524SGleb Smirnoff 
4367ca3f1187SPyun YongHyeon static struct mbuf *
4368d598b626SPyun YongHyeon bge_check_short_dma(struct mbuf *m)
4369d598b626SPyun YongHyeon {
4370d598b626SPyun YongHyeon 	struct mbuf *n;
4371d598b626SPyun YongHyeon 	int found;
4372d598b626SPyun YongHyeon 
4373d598b626SPyun YongHyeon 	/*
4374d598b626SPyun YongHyeon 	 * If device receive two back-to-back send BDs with less than
4375d598b626SPyun YongHyeon 	 * or equal to 8 total bytes then the device may hang.  The two
4376d598b626SPyun YongHyeon 	 * back-to-back send BDs must in the same frame for this failure
4377d598b626SPyun YongHyeon 	 * to occur.  Scan mbuf chains and see whether two back-to-back
4378d598b626SPyun YongHyeon 	 * send BDs are there. If this is the case, allocate new mbuf
4379d598b626SPyun YongHyeon 	 * and copy the frame to workaround the silicon bug.
4380d598b626SPyun YongHyeon 	 */
4381d598b626SPyun YongHyeon 	for (n = m, found = 0; n != NULL; n = n->m_next) {
4382d598b626SPyun YongHyeon 		if (n->m_len < 8) {
4383d598b626SPyun YongHyeon 			found++;
4384d598b626SPyun YongHyeon 			if (found > 1)
4385d598b626SPyun YongHyeon 				break;
4386d598b626SPyun YongHyeon 			continue;
4387d598b626SPyun YongHyeon 		}
4388d598b626SPyun YongHyeon 		found = 0;
4389d598b626SPyun YongHyeon 	}
4390d598b626SPyun YongHyeon 
4391d598b626SPyun YongHyeon 	if (found > 1) {
4392d598b626SPyun YongHyeon 		n = m_defrag(m, M_DONTWAIT);
4393d598b626SPyun YongHyeon 		if (n == NULL)
4394d598b626SPyun YongHyeon 			m_freem(m);
4395d598b626SPyun YongHyeon 	} else
4396d598b626SPyun YongHyeon 		n = m;
4397d598b626SPyun YongHyeon 	return (n);
4398d598b626SPyun YongHyeon }
4399d598b626SPyun YongHyeon 
4400d598b626SPyun YongHyeon static struct mbuf *
44011108273aSPyun YongHyeon bge_setup_tso(struct bge_softc *sc, struct mbuf *m, uint16_t *mss,
44021108273aSPyun YongHyeon     uint16_t *flags)
4403ca3f1187SPyun YongHyeon {
4404ca3f1187SPyun YongHyeon 	struct ip *ip;
4405ca3f1187SPyun YongHyeon 	struct tcphdr *tcp;
4406ca3f1187SPyun YongHyeon 	struct mbuf *n;
4407ca3f1187SPyun YongHyeon 	uint16_t hlen;
44085b355c4fSPyun YongHyeon 	uint32_t poff;
4409ca3f1187SPyun YongHyeon 
4410ca3f1187SPyun YongHyeon 	if (M_WRITABLE(m) == 0) {
4411ca3f1187SPyun YongHyeon 		/* Get a writable copy. */
4412ca3f1187SPyun YongHyeon 		n = m_dup(m, M_DONTWAIT);
4413ca3f1187SPyun YongHyeon 		m_freem(m);
4414ca3f1187SPyun YongHyeon 		if (n == NULL)
4415ca3f1187SPyun YongHyeon 			return (NULL);
4416ca3f1187SPyun YongHyeon 		m = n;
4417ca3f1187SPyun YongHyeon 	}
44185b355c4fSPyun YongHyeon 	m = m_pullup(m, sizeof(struct ether_header) + sizeof(struct ip));
4419ca3f1187SPyun YongHyeon 	if (m == NULL)
4420ca3f1187SPyun YongHyeon 		return (NULL);
44215b355c4fSPyun YongHyeon 	ip = (struct ip *)(mtod(m, char *) + sizeof(struct ether_header));
44225b355c4fSPyun YongHyeon 	poff = sizeof(struct ether_header) + (ip->ip_hl << 2);
4423ca3f1187SPyun YongHyeon 	m = m_pullup(m, poff + sizeof(struct tcphdr));
4424ca3f1187SPyun YongHyeon 	if (m == NULL)
4425ca3f1187SPyun YongHyeon 		return (NULL);
4426ca3f1187SPyun YongHyeon 	tcp = (struct tcphdr *)(mtod(m, char *) + poff);
44275b355c4fSPyun YongHyeon 	m = m_pullup(m, poff + (tcp->th_off << 2));
4428ca3f1187SPyun YongHyeon 	if (m == NULL)
4429ca3f1187SPyun YongHyeon 		return (NULL);
4430ca3f1187SPyun YongHyeon 	/*
4431ca3f1187SPyun YongHyeon 	 * It seems controller doesn't modify IP length and TCP pseudo
4432ca3f1187SPyun YongHyeon 	 * checksum. These checksum computed by upper stack should be 0.
4433ca3f1187SPyun YongHyeon 	 */
4434ca3f1187SPyun YongHyeon 	*mss = m->m_pkthdr.tso_segsz;
443596486faaSPyun YongHyeon 	ip = (struct ip *)(mtod(m, char *) + sizeof(struct ether_header));
4436ca3f1187SPyun YongHyeon 	ip->ip_sum = 0;
4437ca3f1187SPyun YongHyeon 	ip->ip_len = htons(*mss + (ip->ip_hl << 2) + (tcp->th_off << 2));
4438ca3f1187SPyun YongHyeon 	/* Clear pseudo checksum computed by TCP stack. */
443996486faaSPyun YongHyeon 	tcp = (struct tcphdr *)(mtod(m, char *) + poff);
4440ca3f1187SPyun YongHyeon 	tcp->th_sum = 0;
4441ca3f1187SPyun YongHyeon 	/*
4442ca3f1187SPyun YongHyeon 	 * Broadcom controllers uses different descriptor format for
4443ca3f1187SPyun YongHyeon 	 * TSO depending on ASIC revision. Due to TSO-capable firmware
4444ca3f1187SPyun YongHyeon 	 * license issue and lower performance of firmware based TSO
44451108273aSPyun YongHyeon 	 * we only support hardware based TSO.
4446ca3f1187SPyun YongHyeon 	 */
44471108273aSPyun YongHyeon 	/* Calculate header length, incl. TCP/IP options, in 32 bit units. */
4448ca3f1187SPyun YongHyeon 	hlen = ((ip->ip_hl << 2) + (tcp->th_off << 2)) >> 2;
44491108273aSPyun YongHyeon 	if (sc->bge_flags & BGE_FLAG_TSO3) {
44501108273aSPyun YongHyeon 		/*
44511108273aSPyun YongHyeon 		 * For BCM5717 and newer controllers, hardware based TSO
44521108273aSPyun YongHyeon 		 * uses the 14 lower bits of the bge_mss field to store the
44531108273aSPyun YongHyeon 		 * MSS and the upper 2 bits to store the lowest 2 bits of
44541108273aSPyun YongHyeon 		 * the IP/TCP header length.  The upper 6 bits of the header
44551108273aSPyun YongHyeon 		 * length are stored in the bge_flags[14:10,4] field.  Jumbo
44561108273aSPyun YongHyeon 		 * frames are supported.
44571108273aSPyun YongHyeon 		 */
44581108273aSPyun YongHyeon 		*mss |= ((hlen & 0x3) << 14);
44591108273aSPyun YongHyeon 		*flags |= ((hlen & 0xF8) << 7) | ((hlen & 0x4) << 2);
44601108273aSPyun YongHyeon 	} else {
44611108273aSPyun YongHyeon 		/*
44621108273aSPyun YongHyeon 		 * For BCM5755 and newer controllers, hardware based TSO uses
44631108273aSPyun YongHyeon 		 * the lower 11	bits to store the MSS and the upper 5 bits to
44641108273aSPyun YongHyeon 		 * store the IP/TCP header length. Jumbo frames are not
44651108273aSPyun YongHyeon 		 * supported.
44661108273aSPyun YongHyeon 		 */
4467ca3f1187SPyun YongHyeon 		*mss |= (hlen << 11);
44681108273aSPyun YongHyeon 	}
4469ca3f1187SPyun YongHyeon 	return (m);
4470ca3f1187SPyun YongHyeon }
4471ca3f1187SPyun YongHyeon 
4472d375e524SGleb Smirnoff /*
447395d67482SBill Paul  * Encapsulate an mbuf chain in the tx ring  by coupling the mbuf data
447495d67482SBill Paul  * pointers to descriptors.
447595d67482SBill Paul  */
447695d67482SBill Paul static int
4477676ad2c9SGleb Smirnoff bge_encap(struct bge_softc *sc, struct mbuf **m_head, uint32_t *txidx)
447895d67482SBill Paul {
44797e27542aSGleb Smirnoff 	bus_dma_segment_t	segs[BGE_NSEG_NEW];
4480f41ac2beSBill Paul 	bus_dmamap_t		map;
4481676ad2c9SGleb Smirnoff 	struct bge_tx_bd	*d;
4482676ad2c9SGleb Smirnoff 	struct mbuf		*m = *m_head;
44837e27542aSGleb Smirnoff 	uint32_t		idx = *txidx;
4484ca3f1187SPyun YongHyeon 	uint16_t		csum_flags, mss, vlan_tag;
44857e27542aSGleb Smirnoff 	int			nsegs, i, error;
448695d67482SBill Paul 
44876909dc43SGleb Smirnoff 	csum_flags = 0;
4488ca3f1187SPyun YongHyeon 	mss = 0;
4489ca3f1187SPyun YongHyeon 	vlan_tag = 0;
4490d598b626SPyun YongHyeon 	if ((sc->bge_flags & BGE_FLAG_SHORT_DMA_BUG) != 0 &&
4491d598b626SPyun YongHyeon 	    m->m_next != NULL) {
4492d598b626SPyun YongHyeon 		*m_head = bge_check_short_dma(m);
4493d598b626SPyun YongHyeon 		if (*m_head == NULL)
4494d598b626SPyun YongHyeon 			return (ENOBUFS);
4495d598b626SPyun YongHyeon 		m = *m_head;
4496d598b626SPyun YongHyeon 	}
4497ca3f1187SPyun YongHyeon 	if ((m->m_pkthdr.csum_flags & CSUM_TSO) != 0) {
44981108273aSPyun YongHyeon 		*m_head = m = bge_setup_tso(sc, m, &mss, &csum_flags);
4499ca3f1187SPyun YongHyeon 		if (*m_head == NULL)
4500ca3f1187SPyun YongHyeon 			return (ENOBUFS);
4501ca3f1187SPyun YongHyeon 		csum_flags |= BGE_TXBDFLAG_CPU_PRE_DMA |
4502ca3f1187SPyun YongHyeon 		    BGE_TXBDFLAG_CPU_POST_DMA;
450335f945cdSPyun YongHyeon 	} else if ((m->m_pkthdr.csum_flags & sc->bge_csum_features) != 0) {
45046909dc43SGleb Smirnoff 		if (m->m_pkthdr.csum_flags & CSUM_IP)
45056909dc43SGleb Smirnoff 			csum_flags |= BGE_TXBDFLAG_IP_CSUM;
45066909dc43SGleb Smirnoff 		if (m->m_pkthdr.csum_flags & (CSUM_TCP | CSUM_UDP)) {
45076909dc43SGleb Smirnoff 			csum_flags |= BGE_TXBDFLAG_TCP_UDP_CSUM;
45086909dc43SGleb Smirnoff 			if (m->m_pkthdr.len < ETHER_MIN_NOPAD &&
45096909dc43SGleb Smirnoff 			    (error = bge_cksum_pad(m)) != 0) {
45106909dc43SGleb Smirnoff 				m_freem(m);
45116909dc43SGleb Smirnoff 				*m_head = NULL;
45126909dc43SGleb Smirnoff 				return (error);
45136909dc43SGleb Smirnoff 			}
45146909dc43SGleb Smirnoff 		}
45156909dc43SGleb Smirnoff 		if (m->m_flags & M_LASTFRAG)
45166909dc43SGleb Smirnoff 			csum_flags |= BGE_TXBDFLAG_IP_FRAG_END;
45176909dc43SGleb Smirnoff 		else if (m->m_flags & M_FRAG)
45186909dc43SGleb Smirnoff 			csum_flags |= BGE_TXBDFLAG_IP_FRAG;
45196909dc43SGleb Smirnoff 	}
45206909dc43SGleb Smirnoff 
45211108273aSPyun YongHyeon 	if ((m->m_pkthdr.csum_flags & CSUM_TSO) == 0) {
45221108273aSPyun YongHyeon 		if (sc->bge_flags & BGE_FLAG_JUMBO_FRAME &&
45231108273aSPyun YongHyeon 		    m->m_pkthdr.len > ETHER_MAX_LEN)
45241108273aSPyun YongHyeon 			csum_flags |= BGE_TXBDFLAG_JUMBO_FRAME;
45251108273aSPyun YongHyeon 		if (sc->bge_forced_collapse > 0 &&
4526beaa2ae1SPyun YongHyeon 		    (sc->bge_flags & BGE_FLAG_PCIE) != 0 && m->m_next != NULL) {
4527d94f2b85SPyun YongHyeon 			/*
4528d94f2b85SPyun YongHyeon 			 * Forcedly collapse mbuf chains to overcome hardware
4529d94f2b85SPyun YongHyeon 			 * limitation which only support a single outstanding
4530d94f2b85SPyun YongHyeon 			 * DMA read operation.
4531d94f2b85SPyun YongHyeon 			 */
4532beaa2ae1SPyun YongHyeon 			if (sc->bge_forced_collapse == 1)
4533d94f2b85SPyun YongHyeon 				m = m_defrag(m, M_DONTWAIT);
4534d94f2b85SPyun YongHyeon 			else
45351108273aSPyun YongHyeon 				m = m_collapse(m, M_DONTWAIT,
45361108273aSPyun YongHyeon 				    sc->bge_forced_collapse);
4537261f04d6SPyun YongHyeon 			if (m == NULL)
4538261f04d6SPyun YongHyeon 				m = *m_head;
4539d94f2b85SPyun YongHyeon 			*m_head = m;
4540d94f2b85SPyun YongHyeon 		}
45411108273aSPyun YongHyeon 	}
4542d94f2b85SPyun YongHyeon 
45437e27542aSGleb Smirnoff 	map = sc->bge_cdata.bge_tx_dmamap[idx];
45440ac56796SPyun YongHyeon 	error = bus_dmamap_load_mbuf_sg(sc->bge_cdata.bge_tx_mtag, map, m, segs,
4545676ad2c9SGleb Smirnoff 	    &nsegs, BUS_DMA_NOWAIT);
45467e27542aSGleb Smirnoff 	if (error == EFBIG) {
45474eee14cbSMarius Strobl 		m = m_collapse(m, M_DONTWAIT, BGE_NSEG_NEW);
4548676ad2c9SGleb Smirnoff 		if (m == NULL) {
4549676ad2c9SGleb Smirnoff 			m_freem(*m_head);
4550676ad2c9SGleb Smirnoff 			*m_head = NULL;
45517e27542aSGleb Smirnoff 			return (ENOBUFS);
45527e27542aSGleb Smirnoff 		}
4553676ad2c9SGleb Smirnoff 		*m_head = m;
45540ac56796SPyun YongHyeon 		error = bus_dmamap_load_mbuf_sg(sc->bge_cdata.bge_tx_mtag, map,
45550ac56796SPyun YongHyeon 		    m, segs, &nsegs, BUS_DMA_NOWAIT);
4556676ad2c9SGleb Smirnoff 		if (error) {
4557676ad2c9SGleb Smirnoff 			m_freem(m);
4558676ad2c9SGleb Smirnoff 			*m_head = NULL;
45597e27542aSGleb Smirnoff 			return (error);
45607e27542aSGleb Smirnoff 		}
4561676ad2c9SGleb Smirnoff 	} else if (error != 0)
4562676ad2c9SGleb Smirnoff 		return (error);
45637e27542aSGleb Smirnoff 
4564167fdb62SPyun YongHyeon 	/* Check if we have enough free send BDs. */
4565167fdb62SPyun YongHyeon 	if (sc->bge_txcnt + nsegs >= BGE_TX_RING_CNT) {
45660ac56796SPyun YongHyeon 		bus_dmamap_unload(sc->bge_cdata.bge_tx_mtag, map);
456795d67482SBill Paul 		return (ENOBUFS);
45687e27542aSGleb Smirnoff 	}
45697e27542aSGleb Smirnoff 
45700ac56796SPyun YongHyeon 	bus_dmamap_sync(sc->bge_cdata.bge_tx_mtag, map, BUS_DMASYNC_PREWRITE);
4571e65bed95SPyun YongHyeon 
4572ca3f1187SPyun YongHyeon 	if (m->m_flags & M_VLANTAG) {
4573ca3f1187SPyun YongHyeon 		csum_flags |= BGE_TXBDFLAG_VLAN_TAG;
4574ca3f1187SPyun YongHyeon 		vlan_tag = m->m_pkthdr.ether_vtag;
4575ca3f1187SPyun YongHyeon 	}
45767e27542aSGleb Smirnoff 	for (i = 0; ; i++) {
45777e27542aSGleb Smirnoff 		d = &sc->bge_ldata.bge_tx_ring[idx];
45787e27542aSGleb Smirnoff 		d->bge_addr.bge_addr_lo = BGE_ADDR_LO(segs[i].ds_addr);
45797e27542aSGleb Smirnoff 		d->bge_addr.bge_addr_hi = BGE_ADDR_HI(segs[i].ds_addr);
45807e27542aSGleb Smirnoff 		d->bge_len = segs[i].ds_len;
45817e27542aSGleb Smirnoff 		d->bge_flags = csum_flags;
4582ca3f1187SPyun YongHyeon 		d->bge_vlan_tag = vlan_tag;
4583ca3f1187SPyun YongHyeon 		d->bge_mss = mss;
45847e27542aSGleb Smirnoff 		if (i == nsegs - 1)
45857e27542aSGleb Smirnoff 			break;
45867e27542aSGleb Smirnoff 		BGE_INC(idx, BGE_TX_RING_CNT);
45877e27542aSGleb Smirnoff 	}
45887e27542aSGleb Smirnoff 
45897e27542aSGleb Smirnoff 	/* Mark the last segment as end of packet... */
45907e27542aSGleb Smirnoff 	d->bge_flags |= BGE_TXBDFLAG_END;
4591676ad2c9SGleb Smirnoff 
4592f41ac2beSBill Paul 	/*
4593f41ac2beSBill Paul 	 * Insure that the map for this transmission
4594f41ac2beSBill Paul 	 * is placed at the array index of the last descriptor
4595f41ac2beSBill Paul 	 * in this chain.
4596f41ac2beSBill Paul 	 */
45977e27542aSGleb Smirnoff 	sc->bge_cdata.bge_tx_dmamap[*txidx] = sc->bge_cdata.bge_tx_dmamap[idx];
45987e27542aSGleb Smirnoff 	sc->bge_cdata.bge_tx_dmamap[idx] = map;
4599676ad2c9SGleb Smirnoff 	sc->bge_cdata.bge_tx_chain[idx] = m;
46007e27542aSGleb Smirnoff 	sc->bge_txcnt += nsegs;
460195d67482SBill Paul 
46027e27542aSGleb Smirnoff 	BGE_INC(idx, BGE_TX_RING_CNT);
46037e27542aSGleb Smirnoff 	*txidx = idx;
460495d67482SBill Paul 
460595d67482SBill Paul 	return (0);
460695d67482SBill Paul }
460795d67482SBill Paul 
460895d67482SBill Paul /*
460995d67482SBill Paul  * Main transmit routine. To avoid having to do mbuf copies, we put pointers
461095d67482SBill Paul  * to the mbuf data regions directly in the transmit descriptors.
461195d67482SBill Paul  */
461295d67482SBill Paul static void
46133f74909aSGleb Smirnoff bge_start_locked(struct ifnet *ifp)
461495d67482SBill Paul {
461595d67482SBill Paul 	struct bge_softc *sc;
4616167fdb62SPyun YongHyeon 	struct mbuf *m_head;
461714bbd30fSGleb Smirnoff 	uint32_t prodidx;
4618167fdb62SPyun YongHyeon 	int count;
461995d67482SBill Paul 
462095d67482SBill Paul 	sc = ifp->if_softc;
4621167fdb62SPyun YongHyeon 	BGE_LOCK_ASSERT(sc);
462295d67482SBill Paul 
4623167fdb62SPyun YongHyeon 	if (!sc->bge_link ||
4624167fdb62SPyun YongHyeon 	    (ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) !=
4625167fdb62SPyun YongHyeon 	    IFF_DRV_RUNNING)
462695d67482SBill Paul 		return;
462795d67482SBill Paul 
462814bbd30fSGleb Smirnoff 	prodidx = sc->bge_tx_prodidx;
462995d67482SBill Paul 
4630167fdb62SPyun YongHyeon 	for (count = 0; !IFQ_DRV_IS_EMPTY(&ifp->if_snd);) {
4631167fdb62SPyun YongHyeon 		if (sc->bge_txcnt > BGE_TX_RING_CNT - 16) {
4632167fdb62SPyun YongHyeon 			ifp->if_drv_flags |= IFF_DRV_OACTIVE;
4633167fdb62SPyun YongHyeon 			break;
4634167fdb62SPyun YongHyeon 		}
46354d665c4dSDag-Erling Smørgrav 		IFQ_DRV_DEQUEUE(&ifp->if_snd, m_head);
463695d67482SBill Paul 		if (m_head == NULL)
463795d67482SBill Paul 			break;
463895d67482SBill Paul 
463995d67482SBill Paul 		/*
464095d67482SBill Paul 		 * XXX
4641b874fdd4SYaroslav Tykhiy 		 * The code inside the if() block is never reached since we
4642b874fdd4SYaroslav Tykhiy 		 * must mark CSUM_IP_FRAGS in our if_hwassist to start getting
4643b874fdd4SYaroslav Tykhiy 		 * requests to checksum TCP/UDP in a fragmented packet.
4644b874fdd4SYaroslav Tykhiy 		 *
4645b874fdd4SYaroslav Tykhiy 		 * XXX
464695d67482SBill Paul 		 * safety overkill.  If this is a fragmented packet chain
464795d67482SBill Paul 		 * with delayed TCP/UDP checksums, then only encapsulate
464895d67482SBill Paul 		 * it if we have enough descriptors to handle the entire
464995d67482SBill Paul 		 * chain at once.
465095d67482SBill Paul 		 * (paranoia -- may not actually be needed)
465195d67482SBill Paul 		 */
465295d67482SBill Paul 		if (m_head->m_flags & M_FIRSTFRAG &&
465395d67482SBill Paul 		    m_head->m_pkthdr.csum_flags & (CSUM_DELAY_DATA)) {
465495d67482SBill Paul 			if ((BGE_TX_RING_CNT - sc->bge_txcnt) <
465595d67482SBill Paul 			    m_head->m_pkthdr.csum_data + 16) {
46564d665c4dSDag-Erling Smørgrav 				IFQ_DRV_PREPEND(&ifp->if_snd, m_head);
465713f4c340SRobert Watson 				ifp->if_drv_flags |= IFF_DRV_OACTIVE;
465895d67482SBill Paul 				break;
465995d67482SBill Paul 			}
466095d67482SBill Paul 		}
466195d67482SBill Paul 
466295d67482SBill Paul 		/*
466395d67482SBill Paul 		 * Pack the data into the transmit ring. If we
466495d67482SBill Paul 		 * don't have room, set the OACTIVE flag and wait
466595d67482SBill Paul 		 * for the NIC to drain the ring.
466695d67482SBill Paul 		 */
4667676ad2c9SGleb Smirnoff 		if (bge_encap(sc, &m_head, &prodidx)) {
4668676ad2c9SGleb Smirnoff 			if (m_head == NULL)
4669676ad2c9SGleb Smirnoff 				break;
46704d665c4dSDag-Erling Smørgrav 			IFQ_DRV_PREPEND(&ifp->if_snd, m_head);
467113f4c340SRobert Watson 			ifp->if_drv_flags |= IFF_DRV_OACTIVE;
467295d67482SBill Paul 			break;
467395d67482SBill Paul 		}
4674303a718cSDag-Erling Smørgrav 		++count;
467595d67482SBill Paul 
467695d67482SBill Paul 		/*
467795d67482SBill Paul 		 * If there's a BPF listener, bounce a copy of this frame
467895d67482SBill Paul 		 * to him.
467995d67482SBill Paul 		 */
46804e35d186SJung-uk Kim #ifdef ETHER_BPF_MTAP
468145ee6ab3SJung-uk Kim 		ETHER_BPF_MTAP(ifp, m_head);
46824e35d186SJung-uk Kim #else
46834e35d186SJung-uk Kim 		BPF_MTAP(ifp, m_head);
46844e35d186SJung-uk Kim #endif
468595d67482SBill Paul 	}
468695d67482SBill Paul 
4687167fdb62SPyun YongHyeon 	if (count > 0) {
4688aa94f333SPyun YongHyeon 		bus_dmamap_sync(sc->bge_cdata.bge_tx_ring_tag,
46895c1da2faSPyun YongHyeon 		    sc->bge_cdata.bge_tx_ring_map, BUS_DMASYNC_PREWRITE);
46903f74909aSGleb Smirnoff 		/* Transmit. */
469138cc658fSJohn Baldwin 		bge_writembx(sc, BGE_MBX_TX_HOST_PROD0_LO, prodidx);
46923927098fSPaul Saab 		/* 5700 b2 errata */
4693e0ced696SPaul Saab 		if (sc->bge_chiprev == BGE_CHIPREV_5700_BX)
469438cc658fSJohn Baldwin 			bge_writembx(sc, BGE_MBX_TX_HOST_PROD0_LO, prodidx);
469595d67482SBill Paul 
469614bbd30fSGleb Smirnoff 		sc->bge_tx_prodidx = prodidx;
469714bbd30fSGleb Smirnoff 
469895d67482SBill Paul 		/*
469995d67482SBill Paul 		 * Set a timeout in case the chip goes out to lunch.
470095d67482SBill Paul 		 */
4701b74e67fbSGleb Smirnoff 		sc->bge_timer = 5;
470295d67482SBill Paul 	}
4703167fdb62SPyun YongHyeon }
470495d67482SBill Paul 
47050f9bd73bSSam Leffler /*
47060f9bd73bSSam Leffler  * Main transmit routine. To avoid having to do mbuf copies, we put pointers
47070f9bd73bSSam Leffler  * to the mbuf data regions directly in the transmit descriptors.
47080f9bd73bSSam Leffler  */
470995d67482SBill Paul static void
47103f74909aSGleb Smirnoff bge_start(struct ifnet *ifp)
471195d67482SBill Paul {
47120f9bd73bSSam Leffler 	struct bge_softc *sc;
47130f9bd73bSSam Leffler 
47140f9bd73bSSam Leffler 	sc = ifp->if_softc;
47150f9bd73bSSam Leffler 	BGE_LOCK(sc);
47160f9bd73bSSam Leffler 	bge_start_locked(ifp);
47170f9bd73bSSam Leffler 	BGE_UNLOCK(sc);
47180f9bd73bSSam Leffler }
47190f9bd73bSSam Leffler 
47200f9bd73bSSam Leffler static void
47213f74909aSGleb Smirnoff bge_init_locked(struct bge_softc *sc)
47220f9bd73bSSam Leffler {
472395d67482SBill Paul 	struct ifnet *ifp;
47243f74909aSGleb Smirnoff 	uint16_t *m;
4725f6a65488SPyun YongHyeon 	uint32_t mode;
472695d67482SBill Paul 
47270f9bd73bSSam Leffler 	BGE_LOCK_ASSERT(sc);
472895d67482SBill Paul 
4729fc74a9f9SBrooks Davis 	ifp = sc->bge_ifp;
473095d67482SBill Paul 
473113f4c340SRobert Watson 	if (ifp->if_drv_flags & IFF_DRV_RUNNING)
473295d67482SBill Paul 		return;
473395d67482SBill Paul 
473495d67482SBill Paul 	/* Cancel pending I/O and flush buffers. */
473595d67482SBill Paul 	bge_stop(sc);
47368cb1383cSDoug Ambrisko 
47378cb1383cSDoug Ambrisko 	bge_stop_fw(sc);
47388cb1383cSDoug Ambrisko 	bge_sig_pre_reset(sc, BGE_RESET_START);
473995d67482SBill Paul 	bge_reset(sc);
47408cb1383cSDoug Ambrisko 	bge_sig_legacy(sc, BGE_RESET_START);
47418cb1383cSDoug Ambrisko 	bge_sig_post_reset(sc, BGE_RESET_START);
47428cb1383cSDoug Ambrisko 
474395d67482SBill Paul 	bge_chipinit(sc);
474495d67482SBill Paul 
474595d67482SBill Paul 	/*
474695d67482SBill Paul 	 * Init the various state machines, ring
474795d67482SBill Paul 	 * control blocks and firmware.
474895d67482SBill Paul 	 */
474995d67482SBill Paul 	if (bge_blockinit(sc)) {
4750fe806fdaSPyun YongHyeon 		device_printf(sc->bge_dev, "initialization failure\n");
475195d67482SBill Paul 		return;
475295d67482SBill Paul 	}
475395d67482SBill Paul 
4754fc74a9f9SBrooks Davis 	ifp = sc->bge_ifp;
475595d67482SBill Paul 
475695d67482SBill Paul 	/* Specify MTU. */
475795d67482SBill Paul 	CSR_WRITE_4(sc, BGE_RX_MTU, ifp->if_mtu +
4758cb2eacc7SYaroslav Tykhiy 	    ETHER_HDR_LEN + ETHER_CRC_LEN +
4759cb2eacc7SYaroslav Tykhiy 	    (ifp->if_capenable & IFCAP_VLAN_MTU ? ETHER_VLAN_ENCAP_LEN : 0));
476095d67482SBill Paul 
476195d67482SBill Paul 	/* Load our MAC address. */
47623f74909aSGleb Smirnoff 	m = (uint16_t *)IF_LLADDR(sc->bge_ifp);
476395d67482SBill Paul 	CSR_WRITE_4(sc, BGE_MAC_ADDR1_LO, htons(m[0]));
476495d67482SBill Paul 	CSR_WRITE_4(sc, BGE_MAC_ADDR1_HI, (htons(m[1]) << 16) | htons(m[2]));
476595d67482SBill Paul 
47663e9b1bcaSJung-uk Kim 	/* Program promiscuous mode. */
47673e9b1bcaSJung-uk Kim 	bge_setpromisc(sc);
476895d67482SBill Paul 
476995d67482SBill Paul 	/* Program multicast filter. */
477095d67482SBill Paul 	bge_setmulti(sc);
477195d67482SBill Paul 
4772cb2eacc7SYaroslav Tykhiy 	/* Program VLAN tag stripping. */
4773cb2eacc7SYaroslav Tykhiy 	bge_setvlan(sc);
4774cb2eacc7SYaroslav Tykhiy 
477535f945cdSPyun YongHyeon 	/* Override UDP checksum offloading. */
477635f945cdSPyun YongHyeon 	if (sc->bge_forced_udpcsum == 0)
477735f945cdSPyun YongHyeon 		sc->bge_csum_features &= ~CSUM_UDP;
477835f945cdSPyun YongHyeon 	else
477935f945cdSPyun YongHyeon 		sc->bge_csum_features |= CSUM_UDP;
478035f945cdSPyun YongHyeon 	if (ifp->if_capabilities & IFCAP_TXCSUM &&
478135f945cdSPyun YongHyeon 	    ifp->if_capenable & IFCAP_TXCSUM) {
478235f945cdSPyun YongHyeon 		ifp->if_hwassist &= ~(BGE_CSUM_FEATURES | CSUM_UDP);
478335f945cdSPyun YongHyeon 		ifp->if_hwassist |= sc->bge_csum_features;
478435f945cdSPyun YongHyeon 	}
478535f945cdSPyun YongHyeon 
478695d67482SBill Paul 	/* Init RX ring. */
47873ee5d7daSPyun YongHyeon 	if (bge_init_rx_ring_std(sc) != 0) {
47883ee5d7daSPyun YongHyeon 		device_printf(sc->bge_dev, "no memory for std Rx buffers.\n");
47893ee5d7daSPyun YongHyeon 		bge_stop(sc);
47903ee5d7daSPyun YongHyeon 		return;
47913ee5d7daSPyun YongHyeon 	}
479295d67482SBill Paul 
47930434d1b8SBill Paul 	/*
47940434d1b8SBill Paul 	 * Workaround for a bug in 5705 ASIC rev A0. Poll the NIC's
47950434d1b8SBill Paul 	 * memory to insure that the chip has in fact read the first
47960434d1b8SBill Paul 	 * entry of the ring.
47970434d1b8SBill Paul 	 */
47980434d1b8SBill Paul 	if (sc->bge_chipid == BGE_CHIPID_BCM5705_A0) {
47993f74909aSGleb Smirnoff 		uint32_t		v, i;
48000434d1b8SBill Paul 		for (i = 0; i < 10; i++) {
48010434d1b8SBill Paul 			DELAY(20);
48020434d1b8SBill Paul 			v = bge_readmem_ind(sc, BGE_STD_RX_RINGS + 8);
48030434d1b8SBill Paul 			if (v == (MCLBYTES - ETHER_ALIGN))
48040434d1b8SBill Paul 				break;
48050434d1b8SBill Paul 		}
48060434d1b8SBill Paul 		if (i == 10)
4807fe806fdaSPyun YongHyeon 			device_printf (sc->bge_dev,
4808fe806fdaSPyun YongHyeon 			    "5705 A0 chip failed to load RX ring\n");
48090434d1b8SBill Paul 	}
48100434d1b8SBill Paul 
481195d67482SBill Paul 	/* Init jumbo RX ring. */
4812f5459d4cSPyun YongHyeon 	if (BGE_IS_JUMBO_CAPABLE(sc) &&
4813f5459d4cSPyun YongHyeon 	    ifp->if_mtu + ETHER_HDR_LEN + ETHER_CRC_LEN + ETHER_VLAN_ENCAP_LEN >
4814c215fd77SPyun YongHyeon 	    (MCLBYTES - ETHER_ALIGN)) {
48153ee5d7daSPyun YongHyeon 		if (bge_init_rx_ring_jumbo(sc) != 0) {
4816333704a3SPyun YongHyeon 			device_printf(sc->bge_dev,
4817b65256d7SPyun YongHyeon 			    "no memory for jumbo Rx buffers.\n");
48183ee5d7daSPyun YongHyeon 			bge_stop(sc);
48193ee5d7daSPyun YongHyeon 			return;
48203ee5d7daSPyun YongHyeon 		}
48213ee5d7daSPyun YongHyeon 	}
482295d67482SBill Paul 
48233f74909aSGleb Smirnoff 	/* Init our RX return ring index. */
482495d67482SBill Paul 	sc->bge_rx_saved_considx = 0;
482595d67482SBill Paul 
48267e6e2507SJung-uk Kim 	/* Init our RX/TX stat counters. */
48277e6e2507SJung-uk Kim 	sc->bge_rx_discards = sc->bge_tx_discards = sc->bge_tx_collisions = 0;
48287e6e2507SJung-uk Kim 
482995d67482SBill Paul 	/* Init TX ring. */
483095d67482SBill Paul 	bge_init_tx_ring(sc);
483195d67482SBill Paul 
4832f6a65488SPyun YongHyeon 	/* Enable TX MAC state machine lockup fix. */
4833f6a65488SPyun YongHyeon 	mode = CSR_READ_4(sc, BGE_TX_MODE);
4834f6a65488SPyun YongHyeon 	if (BGE_IS_5755_PLUS(sc) || sc->bge_asicrev == BGE_ASICREV_BCM5906)
4835f6a65488SPyun YongHyeon 		mode |= BGE_TXMODE_MBUF_LOCKUP_FIX;
48363f74909aSGleb Smirnoff 	/* Turn on transmitter. */
4837f6a65488SPyun YongHyeon 	CSR_WRITE_4(sc, BGE_TX_MODE, mode | BGE_TXMODE_ENABLE);
483895d67482SBill Paul 
48393f74909aSGleb Smirnoff 	/* Turn on receiver. */
484095d67482SBill Paul 	BGE_SETBIT(sc, BGE_RX_MODE, BGE_RXMODE_ENABLE);
484195d67482SBill Paul 
4842dedcdf57SPyun YongHyeon 	/*
4843dedcdf57SPyun YongHyeon 	 * Set the number of good frames to receive after RX MBUF
4844dedcdf57SPyun YongHyeon 	 * Low Watermark has been reached. After the RX MAC receives
4845dedcdf57SPyun YongHyeon 	 * this number of frames, it will drop subsequent incoming
4846dedcdf57SPyun YongHyeon 	 * frames until the MBUF High Watermark is reached.
4847dedcdf57SPyun YongHyeon 	 */
4848b4a256acSPyun YongHyeon 	if (sc->bge_asicrev == BGE_ASICREV_BCM57765)
4849b4a256acSPyun YongHyeon 		CSR_WRITE_4(sc, BGE_MAX_RX_FRAME_LOWAT, 1);
4850b4a256acSPyun YongHyeon 	else
4851dedcdf57SPyun YongHyeon 		CSR_WRITE_4(sc, BGE_MAX_RX_FRAME_LOWAT, 2);
4852dedcdf57SPyun YongHyeon 
48532280c16bSPyun YongHyeon 	/* Clear MAC statistics. */
48542280c16bSPyun YongHyeon 	if (BGE_IS_5705_PLUS(sc))
48552280c16bSPyun YongHyeon 		bge_stats_clear_regs(sc);
48562280c16bSPyun YongHyeon 
485795d67482SBill Paul 	/* Tell firmware we're alive. */
485895d67482SBill Paul 	BGE_SETBIT(sc, BGE_MODE_CTL, BGE_MODECTL_STACKUP);
485995d67482SBill Paul 
486075719184SGleb Smirnoff #ifdef DEVICE_POLLING
486175719184SGleb Smirnoff 	/* Disable interrupts if we are polling. */
486275719184SGleb Smirnoff 	if (ifp->if_capenable & IFCAP_POLLING) {
486375719184SGleb Smirnoff 		BGE_SETBIT(sc, BGE_PCI_MISC_CTL,
486475719184SGleb Smirnoff 		    BGE_PCIMISCCTL_MASK_PCI_INTR);
486538cc658fSJohn Baldwin 		bge_writembx(sc, BGE_MBX_IRQ0_LO, 1);
486675719184SGleb Smirnoff 	} else
486775719184SGleb Smirnoff #endif
486875719184SGleb Smirnoff 
486995d67482SBill Paul 	/* Enable host interrupts. */
487075719184SGleb Smirnoff 	{
487195d67482SBill Paul 	BGE_SETBIT(sc, BGE_PCI_MISC_CTL, BGE_PCIMISCCTL_CLEAR_INTA);
487295d67482SBill Paul 	BGE_CLRBIT(sc, BGE_PCI_MISC_CTL, BGE_PCIMISCCTL_MASK_PCI_INTR);
487338cc658fSJohn Baldwin 	bge_writembx(sc, BGE_MBX_IRQ0_LO, 0);
487475719184SGleb Smirnoff 	}
487595d67482SBill Paul 
487667d5e043SOleg Bulyzhin 	bge_ifmedia_upd_locked(ifp);
487795d67482SBill Paul 
487813f4c340SRobert Watson 	ifp->if_drv_flags |= IFF_DRV_RUNNING;
487913f4c340SRobert Watson 	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
488095d67482SBill Paul 
48810f9bd73bSSam Leffler 	callout_reset(&sc->bge_stat_ch, hz, bge_tick, sc);
48820f9bd73bSSam Leffler }
48830f9bd73bSSam Leffler 
48840f9bd73bSSam Leffler static void
48853f74909aSGleb Smirnoff bge_init(void *xsc)
48860f9bd73bSSam Leffler {
48870f9bd73bSSam Leffler 	struct bge_softc *sc = xsc;
48880f9bd73bSSam Leffler 
48890f9bd73bSSam Leffler 	BGE_LOCK(sc);
48900f9bd73bSSam Leffler 	bge_init_locked(sc);
48910f9bd73bSSam Leffler 	BGE_UNLOCK(sc);
489295d67482SBill Paul }
489395d67482SBill Paul 
489495d67482SBill Paul /*
489595d67482SBill Paul  * Set media options.
489695d67482SBill Paul  */
489795d67482SBill Paul static int
48983f74909aSGleb Smirnoff bge_ifmedia_upd(struct ifnet *ifp)
489995d67482SBill Paul {
490067d5e043SOleg Bulyzhin 	struct bge_softc *sc = ifp->if_softc;
490167d5e043SOleg Bulyzhin 	int res;
490267d5e043SOleg Bulyzhin 
490367d5e043SOleg Bulyzhin 	BGE_LOCK(sc);
490467d5e043SOleg Bulyzhin 	res = bge_ifmedia_upd_locked(ifp);
490567d5e043SOleg Bulyzhin 	BGE_UNLOCK(sc);
490667d5e043SOleg Bulyzhin 
490767d5e043SOleg Bulyzhin 	return (res);
490867d5e043SOleg Bulyzhin }
490967d5e043SOleg Bulyzhin 
491067d5e043SOleg Bulyzhin static int
491167d5e043SOleg Bulyzhin bge_ifmedia_upd_locked(struct ifnet *ifp)
491267d5e043SOleg Bulyzhin {
491367d5e043SOleg Bulyzhin 	struct bge_softc *sc = ifp->if_softc;
491495d67482SBill Paul 	struct mii_data *mii;
49154f09c4c7SMarius Strobl 	struct mii_softc *miisc;
491695d67482SBill Paul 	struct ifmedia *ifm;
491795d67482SBill Paul 
491867d5e043SOleg Bulyzhin 	BGE_LOCK_ASSERT(sc);
491967d5e043SOleg Bulyzhin 
492095d67482SBill Paul 	ifm = &sc->bge_ifmedia;
492195d67482SBill Paul 
492295d67482SBill Paul 	/* If this is a 1000baseX NIC, enable the TBI port. */
4923652ae483SGleb Smirnoff 	if (sc->bge_flags & BGE_FLAG_TBI) {
492495d67482SBill Paul 		if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER)
492595d67482SBill Paul 			return (EINVAL);
492695d67482SBill Paul 		switch(IFM_SUBTYPE(ifm->ifm_media)) {
492795d67482SBill Paul 		case IFM_AUTO:
4928ff50922bSDoug White 			/*
4929ff50922bSDoug White 			 * The BCM5704 ASIC appears to have a special
4930ff50922bSDoug White 			 * mechanism for programming the autoneg
4931ff50922bSDoug White 			 * advertisement registers in TBI mode.
4932ff50922bSDoug White 			 */
49330f89fde2SJung-uk Kim 			if (sc->bge_asicrev == BGE_ASICREV_BCM5704) {
4934ff50922bSDoug White 				uint32_t sgdig;
49350f89fde2SJung-uk Kim 				sgdig = CSR_READ_4(sc, BGE_SGDIG_STS);
49360f89fde2SJung-uk Kim 				if (sgdig & BGE_SGDIGSTS_DONE) {
4937ff50922bSDoug White 					CSR_WRITE_4(sc, BGE_TX_TBI_AUTONEG, 0);
4938ff50922bSDoug White 					sgdig = CSR_READ_4(sc, BGE_SGDIG_CFG);
4939ff50922bSDoug White 					sgdig |= BGE_SGDIGCFG_AUTO |
4940ff50922bSDoug White 					    BGE_SGDIGCFG_PAUSE_CAP |
4941ff50922bSDoug White 					    BGE_SGDIGCFG_ASYM_PAUSE;
4942ff50922bSDoug White 					CSR_WRITE_4(sc, BGE_SGDIG_CFG,
4943ff50922bSDoug White 					    sgdig | BGE_SGDIGCFG_SEND);
4944ff50922bSDoug White 					DELAY(5);
4945ff50922bSDoug White 					CSR_WRITE_4(sc, BGE_SGDIG_CFG, sgdig);
4946ff50922bSDoug White 				}
49470f89fde2SJung-uk Kim 			}
494895d67482SBill Paul 			break;
494995d67482SBill Paul 		case IFM_1000_SX:
495095d67482SBill Paul 			if ((ifm->ifm_media & IFM_GMASK) == IFM_FDX) {
495195d67482SBill Paul 				BGE_CLRBIT(sc, BGE_MAC_MODE,
495295d67482SBill Paul 				    BGE_MACMODE_HALF_DUPLEX);
495395d67482SBill Paul 			} else {
495495d67482SBill Paul 				BGE_SETBIT(sc, BGE_MAC_MODE,
495595d67482SBill Paul 				    BGE_MACMODE_HALF_DUPLEX);
495695d67482SBill Paul 			}
495795d67482SBill Paul 			break;
495895d67482SBill Paul 		default:
495995d67482SBill Paul 			return (EINVAL);
496095d67482SBill Paul 		}
496195d67482SBill Paul 		return (0);
496295d67482SBill Paul 	}
496395d67482SBill Paul 
49641493e883SOleg Bulyzhin 	sc->bge_link_evt++;
496595d67482SBill Paul 	mii = device_get_softc(sc->bge_miibus);
49664f09c4c7SMarius Strobl 	LIST_FOREACH(miisc, &mii->mii_phys, mii_list)
49673fcb7a53SMarius Strobl 		PHY_RESET(miisc);
496895d67482SBill Paul 	mii_mediachg(mii);
496995d67482SBill Paul 
4970902827f6SBjoern A. Zeeb 	/*
4971902827f6SBjoern A. Zeeb 	 * Force an interrupt so that we will call bge_link_upd
4972902827f6SBjoern A. Zeeb 	 * if needed and clear any pending link state attention.
4973902827f6SBjoern A. Zeeb 	 * Without this we are not getting any further interrupts
4974902827f6SBjoern A. Zeeb 	 * for link state changes and thus will not UP the link and
4975902827f6SBjoern A. Zeeb 	 * not be able to send in bge_start_locked. The only
4976902827f6SBjoern A. Zeeb 	 * way to get things working was to receive a packet and
4977902827f6SBjoern A. Zeeb 	 * get an RX intr.
4978902827f6SBjoern A. Zeeb 	 * bge_tick should help for fiber cards and we might not
4979902827f6SBjoern A. Zeeb 	 * need to do this here if BGE_FLAG_TBI is set but as
4980902827f6SBjoern A. Zeeb 	 * we poll for fiber anyway it should not harm.
4981902827f6SBjoern A. Zeeb 	 */
49824f0794ffSBjoern A. Zeeb 	if (sc->bge_asicrev == BGE_ASICREV_BCM5700 ||
49834f0794ffSBjoern A. Zeeb 	    sc->bge_flags & BGE_FLAG_5788)
4984902827f6SBjoern A. Zeeb 		BGE_SETBIT(sc, BGE_MISC_LOCAL_CTL, BGE_MLC_INTR_SET);
49854f0794ffSBjoern A. Zeeb 	else
498663ccfe30SBjoern A. Zeeb 		BGE_SETBIT(sc, BGE_HCC_MODE, BGE_HCCMODE_COAL_NOW);
4987902827f6SBjoern A. Zeeb 
498895d67482SBill Paul 	return (0);
498995d67482SBill Paul }
499095d67482SBill Paul 
499195d67482SBill Paul /*
499295d67482SBill Paul  * Report current media status.
499395d67482SBill Paul  */
499495d67482SBill Paul static void
49953f74909aSGleb Smirnoff bge_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
499695d67482SBill Paul {
499767d5e043SOleg Bulyzhin 	struct bge_softc *sc = ifp->if_softc;
499895d67482SBill Paul 	struct mii_data *mii;
499995d67482SBill Paul 
500067d5e043SOleg Bulyzhin 	BGE_LOCK(sc);
500195d67482SBill Paul 
5002652ae483SGleb Smirnoff 	if (sc->bge_flags & BGE_FLAG_TBI) {
500395d67482SBill Paul 		ifmr->ifm_status = IFM_AVALID;
500495d67482SBill Paul 		ifmr->ifm_active = IFM_ETHER;
500595d67482SBill Paul 		if (CSR_READ_4(sc, BGE_MAC_STS) &
500695d67482SBill Paul 		    BGE_MACSTAT_TBI_PCS_SYNCHED)
500795d67482SBill Paul 			ifmr->ifm_status |= IFM_ACTIVE;
50084c0da0ffSGleb Smirnoff 		else {
50094c0da0ffSGleb Smirnoff 			ifmr->ifm_active |= IFM_NONE;
501067d5e043SOleg Bulyzhin 			BGE_UNLOCK(sc);
50114c0da0ffSGleb Smirnoff 			return;
50124c0da0ffSGleb Smirnoff 		}
501395d67482SBill Paul 		ifmr->ifm_active |= IFM_1000_SX;
501495d67482SBill Paul 		if (CSR_READ_4(sc, BGE_MAC_MODE) & BGE_MACMODE_HALF_DUPLEX)
501595d67482SBill Paul 			ifmr->ifm_active |= IFM_HDX;
501695d67482SBill Paul 		else
501795d67482SBill Paul 			ifmr->ifm_active |= IFM_FDX;
501867d5e043SOleg Bulyzhin 		BGE_UNLOCK(sc);
501995d67482SBill Paul 		return;
502095d67482SBill Paul 	}
502195d67482SBill Paul 
502295d67482SBill Paul 	mii = device_get_softc(sc->bge_miibus);
502395d67482SBill Paul 	mii_pollstat(mii);
502495d67482SBill Paul 	ifmr->ifm_active = mii->mii_media_active;
502595d67482SBill Paul 	ifmr->ifm_status = mii->mii_media_status;
502667d5e043SOleg Bulyzhin 
502767d5e043SOleg Bulyzhin 	BGE_UNLOCK(sc);
502895d67482SBill Paul }
502995d67482SBill Paul 
503095d67482SBill Paul static int
50313f74909aSGleb Smirnoff bge_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
503295d67482SBill Paul {
503395d67482SBill Paul 	struct bge_softc *sc = ifp->if_softc;
503495d67482SBill Paul 	struct ifreq *ifr = (struct ifreq *) data;
503595d67482SBill Paul 	struct mii_data *mii;
5036f9004b6dSJung-uk Kim 	int flags, mask, error = 0;
503795d67482SBill Paul 
503895d67482SBill Paul 	switch (command) {
503995d67482SBill Paul 	case SIOCSIFMTU:
5040f5459d4cSPyun YongHyeon 		if (BGE_IS_JUMBO_CAPABLE(sc) ||
5041f5459d4cSPyun YongHyeon 		    (sc->bge_flags & BGE_FLAG_JUMBO_STD)) {
50424c0da0ffSGleb Smirnoff 			if (ifr->ifr_mtu < ETHERMIN ||
5043f5459d4cSPyun YongHyeon 			    ifr->ifr_mtu > BGE_JUMBO_MTU) {
504495d67482SBill Paul 				error = EINVAL;
5045f5459d4cSPyun YongHyeon 				break;
5046f5459d4cSPyun YongHyeon 			}
5047f5459d4cSPyun YongHyeon 		} else if (ifr->ifr_mtu < ETHERMIN || ifr->ifr_mtu > ETHERMTU) {
5048f5459d4cSPyun YongHyeon 			error = EINVAL;
5049f5459d4cSPyun YongHyeon 			break;
5050f5459d4cSPyun YongHyeon 		}
5051f5459d4cSPyun YongHyeon 		BGE_LOCK(sc);
5052f5459d4cSPyun YongHyeon 		if (ifp->if_mtu != ifr->ifr_mtu) {
505395d67482SBill Paul 			ifp->if_mtu = ifr->ifr_mtu;
50543a429c8fSPyun YongHyeon 			if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
505513f4c340SRobert Watson 				ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
50563a429c8fSPyun YongHyeon 				bge_init_locked(sc);
505795d67482SBill Paul 			}
50583a429c8fSPyun YongHyeon 		}
50593a429c8fSPyun YongHyeon 		BGE_UNLOCK(sc);
506095d67482SBill Paul 		break;
506195d67482SBill Paul 	case SIOCSIFFLAGS:
50620f9bd73bSSam Leffler 		BGE_LOCK(sc);
506395d67482SBill Paul 		if (ifp->if_flags & IFF_UP) {
506495d67482SBill Paul 			/*
506595d67482SBill Paul 			 * If only the state of the PROMISC flag changed,
506695d67482SBill Paul 			 * then just use the 'set promisc mode' command
506795d67482SBill Paul 			 * instead of reinitializing the entire NIC. Doing
506895d67482SBill Paul 			 * a full re-init means reloading the firmware and
506995d67482SBill Paul 			 * waiting for it to start up, which may take a
5070d183af7fSRuslan Ermilov 			 * second or two.  Similarly for ALLMULTI.
507195d67482SBill Paul 			 */
5072f9004b6dSJung-uk Kim 			if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
5073f9004b6dSJung-uk Kim 				flags = ifp->if_flags ^ sc->bge_if_flags;
50743e9b1bcaSJung-uk Kim 				if (flags & IFF_PROMISC)
50753e9b1bcaSJung-uk Kim 					bge_setpromisc(sc);
5076f9004b6dSJung-uk Kim 				if (flags & IFF_ALLMULTI)
5077d183af7fSRuslan Ermilov 					bge_setmulti(sc);
507895d67482SBill Paul 			} else
50790f9bd73bSSam Leffler 				bge_init_locked(sc);
508095d67482SBill Paul 		} else {
508113f4c340SRobert Watson 			if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
508295d67482SBill Paul 				bge_stop(sc);
508395d67482SBill Paul 			}
508495d67482SBill Paul 		}
508595d67482SBill Paul 		sc->bge_if_flags = ifp->if_flags;
50860f9bd73bSSam Leffler 		BGE_UNLOCK(sc);
508795d67482SBill Paul 		error = 0;
508895d67482SBill Paul 		break;
508995d67482SBill Paul 	case SIOCADDMULTI:
509095d67482SBill Paul 	case SIOCDELMULTI:
509113f4c340SRobert Watson 		if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
50920f9bd73bSSam Leffler 			BGE_LOCK(sc);
509395d67482SBill Paul 			bge_setmulti(sc);
50940f9bd73bSSam Leffler 			BGE_UNLOCK(sc);
509595d67482SBill Paul 			error = 0;
509695d67482SBill Paul 		}
509795d67482SBill Paul 		break;
509895d67482SBill Paul 	case SIOCSIFMEDIA:
509995d67482SBill Paul 	case SIOCGIFMEDIA:
5100652ae483SGleb Smirnoff 		if (sc->bge_flags & BGE_FLAG_TBI) {
510195d67482SBill Paul 			error = ifmedia_ioctl(ifp, ifr,
510295d67482SBill Paul 			    &sc->bge_ifmedia, command);
510395d67482SBill Paul 		} else {
510495d67482SBill Paul 			mii = device_get_softc(sc->bge_miibus);
510595d67482SBill Paul 			error = ifmedia_ioctl(ifp, ifr,
510695d67482SBill Paul 			    &mii->mii_media, command);
510795d67482SBill Paul 		}
510895d67482SBill Paul 		break;
510995d67482SBill Paul 	case SIOCSIFCAP:
511095d67482SBill Paul 		mask = ifr->ifr_reqcap ^ ifp->if_capenable;
511175719184SGleb Smirnoff #ifdef DEVICE_POLLING
511275719184SGleb Smirnoff 		if (mask & IFCAP_POLLING) {
511375719184SGleb Smirnoff 			if (ifr->ifr_reqcap & IFCAP_POLLING) {
511475719184SGleb Smirnoff 				error = ether_poll_register(bge_poll, ifp);
511575719184SGleb Smirnoff 				if (error)
511675719184SGleb Smirnoff 					return (error);
511775719184SGleb Smirnoff 				BGE_LOCK(sc);
511875719184SGleb Smirnoff 				BGE_SETBIT(sc, BGE_PCI_MISC_CTL,
511975719184SGleb Smirnoff 				    BGE_PCIMISCCTL_MASK_PCI_INTR);
512038cc658fSJohn Baldwin 				bge_writembx(sc, BGE_MBX_IRQ0_LO, 1);
512175719184SGleb Smirnoff 				ifp->if_capenable |= IFCAP_POLLING;
512275719184SGleb Smirnoff 				BGE_UNLOCK(sc);
512375719184SGleb Smirnoff 			} else {
512475719184SGleb Smirnoff 				error = ether_poll_deregister(ifp);
512575719184SGleb Smirnoff 				/* Enable interrupt even in error case */
512675719184SGleb Smirnoff 				BGE_LOCK(sc);
512775719184SGleb Smirnoff 				BGE_CLRBIT(sc, BGE_PCI_MISC_CTL,
512875719184SGleb Smirnoff 				    BGE_PCIMISCCTL_MASK_PCI_INTR);
512938cc658fSJohn Baldwin 				bge_writembx(sc, BGE_MBX_IRQ0_LO, 0);
513075719184SGleb Smirnoff 				ifp->if_capenable &= ~IFCAP_POLLING;
513175719184SGleb Smirnoff 				BGE_UNLOCK(sc);
513275719184SGleb Smirnoff 			}
513375719184SGleb Smirnoff 		}
513475719184SGleb Smirnoff #endif
5135d8b57f98SPyun YongHyeon 		if ((mask & IFCAP_TXCSUM) != 0 &&
5136d8b57f98SPyun YongHyeon 		    (ifp->if_capabilities & IFCAP_TXCSUM) != 0) {
5137d8b57f98SPyun YongHyeon 			ifp->if_capenable ^= IFCAP_TXCSUM;
5138d8b57f98SPyun YongHyeon 			if ((ifp->if_capenable & IFCAP_TXCSUM) != 0)
513935f945cdSPyun YongHyeon 				ifp->if_hwassist |= sc->bge_csum_features;
514095d67482SBill Paul 			else
514135f945cdSPyun YongHyeon 				ifp->if_hwassist &= ~sc->bge_csum_features;
514295d67482SBill Paul 		}
5143cb2eacc7SYaroslav Tykhiy 
5144d8b57f98SPyun YongHyeon 		if ((mask & IFCAP_RXCSUM) != 0 &&
5145d8b57f98SPyun YongHyeon 		    (ifp->if_capabilities & IFCAP_RXCSUM) != 0)
5146d8b57f98SPyun YongHyeon 			ifp->if_capenable ^= IFCAP_RXCSUM;
5147d8b57f98SPyun YongHyeon 
5148ca3f1187SPyun YongHyeon 		if ((mask & IFCAP_TSO4) != 0 &&
5149ca3f1187SPyun YongHyeon 		    (ifp->if_capabilities & IFCAP_TSO4) != 0) {
5150ca3f1187SPyun YongHyeon 			ifp->if_capenable ^= IFCAP_TSO4;
5151ca3f1187SPyun YongHyeon 			if ((ifp->if_capenable & IFCAP_TSO4) != 0)
5152ca3f1187SPyun YongHyeon 				ifp->if_hwassist |= CSUM_TSO;
5153ca3f1187SPyun YongHyeon 			else
5154ca3f1187SPyun YongHyeon 				ifp->if_hwassist &= ~CSUM_TSO;
5155ca3f1187SPyun YongHyeon 		}
5156ca3f1187SPyun YongHyeon 
5157cb2eacc7SYaroslav Tykhiy 		if (mask & IFCAP_VLAN_MTU) {
5158cb2eacc7SYaroslav Tykhiy 			ifp->if_capenable ^= IFCAP_VLAN_MTU;
5159cb2eacc7SYaroslav Tykhiy 			ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
5160cb2eacc7SYaroslav Tykhiy 			bge_init(sc);
5161cb2eacc7SYaroslav Tykhiy 		}
5162cb2eacc7SYaroslav Tykhiy 
516304bde852SPyun YongHyeon 		if ((mask & IFCAP_VLAN_HWTSO) != 0 &&
516404bde852SPyun YongHyeon 		    (ifp->if_capabilities & IFCAP_VLAN_HWTSO) != 0)
516504bde852SPyun YongHyeon 			ifp->if_capenable ^= IFCAP_VLAN_HWTSO;
516604bde852SPyun YongHyeon 		if ((mask & IFCAP_VLAN_HWTAGGING) != 0 &&
516704bde852SPyun YongHyeon 		    (ifp->if_capabilities & IFCAP_VLAN_HWTAGGING) != 0) {
5168cb2eacc7SYaroslav Tykhiy 			ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING;
516904bde852SPyun YongHyeon 			if ((ifp->if_capenable & IFCAP_VLAN_HWTAGGING) == 0)
517004bde852SPyun YongHyeon 				ifp->if_capenable &= ~IFCAP_VLAN_HWTSO;
5171cb2eacc7SYaroslav Tykhiy 			BGE_LOCK(sc);
5172cb2eacc7SYaroslav Tykhiy 			bge_setvlan(sc);
5173cb2eacc7SYaroslav Tykhiy 			BGE_UNLOCK(sc);
517404bde852SPyun YongHyeon 		}
5175cb2eacc7SYaroslav Tykhiy #ifdef VLAN_CAPABILITIES
5176cb2eacc7SYaroslav Tykhiy 		VLAN_CAPABILITIES(ifp);
5177cb2eacc7SYaroslav Tykhiy #endif
517895d67482SBill Paul 		break;
517995d67482SBill Paul 	default:
5180673d9191SSam Leffler 		error = ether_ioctl(ifp, command, data);
518195d67482SBill Paul 		break;
518295d67482SBill Paul 	}
518395d67482SBill Paul 
518495d67482SBill Paul 	return (error);
518595d67482SBill Paul }
518695d67482SBill Paul 
518795d67482SBill Paul static void
5188b74e67fbSGleb Smirnoff bge_watchdog(struct bge_softc *sc)
518995d67482SBill Paul {
5190b74e67fbSGleb Smirnoff 	struct ifnet *ifp;
519195d67482SBill Paul 
5192b74e67fbSGleb Smirnoff 	BGE_LOCK_ASSERT(sc);
5193b74e67fbSGleb Smirnoff 
5194b74e67fbSGleb Smirnoff 	if (sc->bge_timer == 0 || --sc->bge_timer)
5195b74e67fbSGleb Smirnoff 		return;
5196b74e67fbSGleb Smirnoff 
5197b74e67fbSGleb Smirnoff 	ifp = sc->bge_ifp;
519895d67482SBill Paul 
5199fe806fdaSPyun YongHyeon 	if_printf(ifp, "watchdog timeout -- resetting\n");
520095d67482SBill Paul 
520113f4c340SRobert Watson 	ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
5202426742bfSGleb Smirnoff 	bge_init_locked(sc);
520395d67482SBill Paul 
520495d67482SBill Paul 	ifp->if_oerrors++;
520595d67482SBill Paul }
520695d67482SBill Paul 
52075a147ba6SPyun YongHyeon static void
52085a147ba6SPyun YongHyeon bge_stop_block(struct bge_softc *sc, bus_size_t reg, uint32_t bit)
52095a147ba6SPyun YongHyeon {
52105a147ba6SPyun YongHyeon 	int i;
52115a147ba6SPyun YongHyeon 
52125a147ba6SPyun YongHyeon 	BGE_CLRBIT(sc, reg, bit);
52135a147ba6SPyun YongHyeon 
52145a147ba6SPyun YongHyeon 	for (i = 0; i < BGE_TIMEOUT; i++) {
52155a147ba6SPyun YongHyeon 		if ((CSR_READ_4(sc, reg) & bit) == 0)
52165a147ba6SPyun YongHyeon 			return;
52175a147ba6SPyun YongHyeon 		DELAY(100);
52185a147ba6SPyun YongHyeon         }
52195a147ba6SPyun YongHyeon }
52205a147ba6SPyun YongHyeon 
522195d67482SBill Paul /*
522295d67482SBill Paul  * Stop the adapter and free any mbufs allocated to the
522395d67482SBill Paul  * RX and TX lists.
522495d67482SBill Paul  */
522595d67482SBill Paul static void
52263f74909aSGleb Smirnoff bge_stop(struct bge_softc *sc)
522795d67482SBill Paul {
522895d67482SBill Paul 	struct ifnet *ifp;
522995d67482SBill Paul 
52300f9bd73bSSam Leffler 	BGE_LOCK_ASSERT(sc);
52310f9bd73bSSam Leffler 
5232fc74a9f9SBrooks Davis 	ifp = sc->bge_ifp;
523395d67482SBill Paul 
52340f9bd73bSSam Leffler 	callout_stop(&sc->bge_stat_ch);
523595d67482SBill Paul 
523644b63691SBjoern A. Zeeb 	/* Disable host interrupts. */
523744b63691SBjoern A. Zeeb 	BGE_SETBIT(sc, BGE_PCI_MISC_CTL, BGE_PCIMISCCTL_MASK_PCI_INTR);
523844b63691SBjoern A. Zeeb 	bge_writembx(sc, BGE_MBX_IRQ0_LO, 1);
523944b63691SBjoern A. Zeeb 
524044b63691SBjoern A. Zeeb 	/*
524144b63691SBjoern A. Zeeb 	 * Tell firmware we're shutting down.
524244b63691SBjoern A. Zeeb 	 */
524344b63691SBjoern A. Zeeb 	bge_stop_fw(sc);
524444b63691SBjoern A. Zeeb 	bge_sig_pre_reset(sc, BGE_RESET_STOP);
524544b63691SBjoern A. Zeeb 
524695d67482SBill Paul 	/*
52473f74909aSGleb Smirnoff 	 * Disable all of the receiver blocks.
524895d67482SBill Paul 	 */
52495a147ba6SPyun YongHyeon 	bge_stop_block(sc, BGE_RX_MODE, BGE_RXMODE_ENABLE);
52505a147ba6SPyun YongHyeon 	bge_stop_block(sc, BGE_RBDI_MODE, BGE_RBDIMODE_ENABLE);
52515a147ba6SPyun YongHyeon 	bge_stop_block(sc, BGE_RXLP_MODE, BGE_RXLPMODE_ENABLE);
52525a147ba6SPyun YongHyeon 	if (BGE_IS_5700_FAMILY(sc))
52535a147ba6SPyun YongHyeon 		bge_stop_block(sc, BGE_RXLS_MODE, BGE_RXLSMODE_ENABLE);
52545a147ba6SPyun YongHyeon 	bge_stop_block(sc, BGE_RDBDI_MODE, BGE_RBDIMODE_ENABLE);
52555a147ba6SPyun YongHyeon 	bge_stop_block(sc, BGE_RDC_MODE, BGE_RDCMODE_ENABLE);
52565a147ba6SPyun YongHyeon 	bge_stop_block(sc, BGE_RBDC_MODE, BGE_RBDCMODE_ENABLE);
525795d67482SBill Paul 
525895d67482SBill Paul 	/*
52593f74909aSGleb Smirnoff 	 * Disable all of the transmit blocks.
526095d67482SBill Paul 	 */
52615a147ba6SPyun YongHyeon 	bge_stop_block(sc, BGE_SRS_MODE, BGE_SRSMODE_ENABLE);
52625a147ba6SPyun YongHyeon 	bge_stop_block(sc, BGE_SBDI_MODE, BGE_SBDIMODE_ENABLE);
52635a147ba6SPyun YongHyeon 	bge_stop_block(sc, BGE_SDI_MODE, BGE_SDIMODE_ENABLE);
52645a147ba6SPyun YongHyeon 	bge_stop_block(sc, BGE_RDMA_MODE, BGE_RDMAMODE_ENABLE);
52655a147ba6SPyun YongHyeon 	bge_stop_block(sc, BGE_SDC_MODE, BGE_SDCMODE_ENABLE);
52665a147ba6SPyun YongHyeon 	if (BGE_IS_5700_FAMILY(sc))
52675a147ba6SPyun YongHyeon 		bge_stop_block(sc, BGE_DMAC_MODE, BGE_DMACMODE_ENABLE);
52685a147ba6SPyun YongHyeon 	bge_stop_block(sc, BGE_SBDC_MODE, BGE_SBDCMODE_ENABLE);
526995d67482SBill Paul 
527095d67482SBill Paul 	/*
527195d67482SBill Paul 	 * Shut down all of the memory managers and related
527295d67482SBill Paul 	 * state machines.
527395d67482SBill Paul 	 */
52745a147ba6SPyun YongHyeon 	bge_stop_block(sc, BGE_HCC_MODE, BGE_HCCMODE_ENABLE);
52755a147ba6SPyun YongHyeon 	bge_stop_block(sc, BGE_WDMA_MODE, BGE_WDMAMODE_ENABLE);
52765a147ba6SPyun YongHyeon 	if (BGE_IS_5700_FAMILY(sc))
52775a147ba6SPyun YongHyeon 		bge_stop_block(sc, BGE_MBCF_MODE, BGE_MBCFMODE_ENABLE);
52785a147ba6SPyun YongHyeon 
52790c8aa4eaSJung-uk Kim 	CSR_WRITE_4(sc, BGE_FTQ_RESET, 0xFFFFFFFF);
528095d67482SBill Paul 	CSR_WRITE_4(sc, BGE_FTQ_RESET, 0);
52817ee00338SJung-uk Kim 	if (!(BGE_IS_5705_PLUS(sc))) {
528295d67482SBill Paul 		BGE_CLRBIT(sc, BGE_BMAN_MODE, BGE_BMANMODE_ENABLE);
528395d67482SBill Paul 		BGE_CLRBIT(sc, BGE_MARB_MODE, BGE_MARBMODE_ENABLE);
52840434d1b8SBill Paul 	}
52852280c16bSPyun YongHyeon 	/* Update MAC statistics. */
52862280c16bSPyun YongHyeon 	if (BGE_IS_5705_PLUS(sc))
52872280c16bSPyun YongHyeon 		bge_stats_update_regs(sc);
528895d67482SBill Paul 
52898cb1383cSDoug Ambrisko 	bge_reset(sc);
52908cb1383cSDoug Ambrisko 	bge_sig_legacy(sc, BGE_RESET_STOP);
52918cb1383cSDoug Ambrisko 	bge_sig_post_reset(sc, BGE_RESET_STOP);
52928cb1383cSDoug Ambrisko 
52938cb1383cSDoug Ambrisko 	/*
52948cb1383cSDoug Ambrisko 	 * Keep the ASF firmware running if up.
52958cb1383cSDoug Ambrisko 	 */
52968cb1383cSDoug Ambrisko 	if (sc->bge_asf_mode & ASF_STACKUP)
52978cb1383cSDoug Ambrisko 		BGE_SETBIT(sc, BGE_MODE_CTL, BGE_MODECTL_STACKUP);
52988cb1383cSDoug Ambrisko 	else
529995d67482SBill Paul 		BGE_CLRBIT(sc, BGE_MODE_CTL, BGE_MODECTL_STACKUP);
530095d67482SBill Paul 
530195d67482SBill Paul 	/* Free the RX lists. */
530295d67482SBill Paul 	bge_free_rx_ring_std(sc);
530395d67482SBill Paul 
530495d67482SBill Paul 	/* Free jumbo RX list. */
53054c0da0ffSGleb Smirnoff 	if (BGE_IS_JUMBO_CAPABLE(sc))
530695d67482SBill Paul 		bge_free_rx_ring_jumbo(sc);
530795d67482SBill Paul 
530895d67482SBill Paul 	/* Free TX buffers. */
530995d67482SBill Paul 	bge_free_tx_ring(sc);
531095d67482SBill Paul 
531195d67482SBill Paul 	sc->bge_tx_saved_considx = BGE_TXCONS_UNSET;
531295d67482SBill Paul 
53135dda8085SOleg Bulyzhin 	/* Clear MAC's link state (PHY may still have link UP). */
53141493e883SOleg Bulyzhin 	if (bootverbose && sc->bge_link)
53151493e883SOleg Bulyzhin 		if_printf(sc->bge_ifp, "link DOWN\n");
53161493e883SOleg Bulyzhin 	sc->bge_link = 0;
531795d67482SBill Paul 
53181493e883SOleg Bulyzhin 	ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
531995d67482SBill Paul }
532095d67482SBill Paul 
532195d67482SBill Paul /*
532295d67482SBill Paul  * Stop all chip I/O so that the kernel's probe routines don't
532395d67482SBill Paul  * get confused by errant DMAs when rebooting.
532495d67482SBill Paul  */
5325b6c974e8SWarner Losh static int
53263f74909aSGleb Smirnoff bge_shutdown(device_t dev)
532795d67482SBill Paul {
532895d67482SBill Paul 	struct bge_softc *sc;
532995d67482SBill Paul 
533095d67482SBill Paul 	sc = device_get_softc(dev);
53310f9bd73bSSam Leffler 	BGE_LOCK(sc);
533295d67482SBill Paul 	bge_stop(sc);
533395d67482SBill Paul 	bge_reset(sc);
53340f9bd73bSSam Leffler 	BGE_UNLOCK(sc);
5335b6c974e8SWarner Losh 
5336b6c974e8SWarner Losh 	return (0);
533795d67482SBill Paul }
533814afefa3SPawel Jakub Dawidek 
533914afefa3SPawel Jakub Dawidek static int
534014afefa3SPawel Jakub Dawidek bge_suspend(device_t dev)
534114afefa3SPawel Jakub Dawidek {
534214afefa3SPawel Jakub Dawidek 	struct bge_softc *sc;
534314afefa3SPawel Jakub Dawidek 
534414afefa3SPawel Jakub Dawidek 	sc = device_get_softc(dev);
534514afefa3SPawel Jakub Dawidek 	BGE_LOCK(sc);
534614afefa3SPawel Jakub Dawidek 	bge_stop(sc);
534714afefa3SPawel Jakub Dawidek 	BGE_UNLOCK(sc);
534814afefa3SPawel Jakub Dawidek 
534914afefa3SPawel Jakub Dawidek 	return (0);
535014afefa3SPawel Jakub Dawidek }
535114afefa3SPawel Jakub Dawidek 
535214afefa3SPawel Jakub Dawidek static int
535314afefa3SPawel Jakub Dawidek bge_resume(device_t dev)
535414afefa3SPawel Jakub Dawidek {
535514afefa3SPawel Jakub Dawidek 	struct bge_softc *sc;
535614afefa3SPawel Jakub Dawidek 	struct ifnet *ifp;
535714afefa3SPawel Jakub Dawidek 
535814afefa3SPawel Jakub Dawidek 	sc = device_get_softc(dev);
535914afefa3SPawel Jakub Dawidek 	BGE_LOCK(sc);
536014afefa3SPawel Jakub Dawidek 	ifp = sc->bge_ifp;
536114afefa3SPawel Jakub Dawidek 	if (ifp->if_flags & IFF_UP) {
536214afefa3SPawel Jakub Dawidek 		bge_init_locked(sc);
536314afefa3SPawel Jakub Dawidek 		if (ifp->if_drv_flags & IFF_DRV_RUNNING)
536414afefa3SPawel Jakub Dawidek 			bge_start_locked(ifp);
536514afefa3SPawel Jakub Dawidek 	}
536614afefa3SPawel Jakub Dawidek 	BGE_UNLOCK(sc);
536714afefa3SPawel Jakub Dawidek 
536814afefa3SPawel Jakub Dawidek 	return (0);
536914afefa3SPawel Jakub Dawidek }
5370dab5cd05SOleg Bulyzhin 
5371dab5cd05SOleg Bulyzhin static void
53723f74909aSGleb Smirnoff bge_link_upd(struct bge_softc *sc)
5373dab5cd05SOleg Bulyzhin {
53741f313773SOleg Bulyzhin 	struct mii_data *mii;
53751f313773SOleg Bulyzhin 	uint32_t link, status;
5376dab5cd05SOleg Bulyzhin 
5377dab5cd05SOleg Bulyzhin 	BGE_LOCK_ASSERT(sc);
53781f313773SOleg Bulyzhin 
53793f74909aSGleb Smirnoff 	/* Clear 'pending link event' flag. */
53807b97099dSOleg Bulyzhin 	sc->bge_link_evt = 0;
53817b97099dSOleg Bulyzhin 
5382dab5cd05SOleg Bulyzhin 	/*
5383dab5cd05SOleg Bulyzhin 	 * Process link state changes.
5384dab5cd05SOleg Bulyzhin 	 * Grrr. The link status word in the status block does
5385dab5cd05SOleg Bulyzhin 	 * not work correctly on the BCM5700 rev AX and BX chips,
5386dab5cd05SOleg Bulyzhin 	 * according to all available information. Hence, we have
5387dab5cd05SOleg Bulyzhin 	 * to enable MII interrupts in order to properly obtain
5388dab5cd05SOleg Bulyzhin 	 * async link changes. Unfortunately, this also means that
5389dab5cd05SOleg Bulyzhin 	 * we have to read the MAC status register to detect link
5390dab5cd05SOleg Bulyzhin 	 * changes, thereby adding an additional register access to
5391dab5cd05SOleg Bulyzhin 	 * the interrupt handler.
53921f313773SOleg Bulyzhin 	 *
53931f313773SOleg Bulyzhin 	 * XXX: perhaps link state detection procedure used for
53944c0da0ffSGleb Smirnoff 	 * BGE_CHIPID_BCM5700_B2 can be used for others BCM5700 revisions.
5395dab5cd05SOleg Bulyzhin 	 */
5396dab5cd05SOleg Bulyzhin 
53971f313773SOleg Bulyzhin 	if (sc->bge_asicrev == BGE_ASICREV_BCM5700 &&
53984c0da0ffSGleb Smirnoff 	    sc->bge_chipid != BGE_CHIPID_BCM5700_B2) {
5399dab5cd05SOleg Bulyzhin 		status = CSR_READ_4(sc, BGE_MAC_STS);
5400dab5cd05SOleg Bulyzhin 		if (status & BGE_MACSTAT_MI_INTERRUPT) {
54011f313773SOleg Bulyzhin 			mii = device_get_softc(sc->bge_miibus);
54025dda8085SOleg Bulyzhin 			mii_pollstat(mii);
54031f313773SOleg Bulyzhin 			if (!sc->bge_link &&
54041f313773SOleg Bulyzhin 			    mii->mii_media_status & IFM_ACTIVE &&
54051f313773SOleg Bulyzhin 			    IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) {
54061f313773SOleg Bulyzhin 				sc->bge_link++;
54071f313773SOleg Bulyzhin 				if (bootverbose)
54081f313773SOleg Bulyzhin 					if_printf(sc->bge_ifp, "link UP\n");
54091f313773SOleg Bulyzhin 			} else if (sc->bge_link &&
54101f313773SOleg Bulyzhin 			    (!(mii->mii_media_status & IFM_ACTIVE) ||
54111f313773SOleg Bulyzhin 			    IFM_SUBTYPE(mii->mii_media_active) == IFM_NONE)) {
54121f313773SOleg Bulyzhin 				sc->bge_link = 0;
54131f313773SOleg Bulyzhin 				if (bootverbose)
54141f313773SOleg Bulyzhin 					if_printf(sc->bge_ifp, "link DOWN\n");
54151f313773SOleg Bulyzhin 			}
54161f313773SOleg Bulyzhin 
54173f74909aSGleb Smirnoff 			/* Clear the interrupt. */
5418dab5cd05SOleg Bulyzhin 			CSR_WRITE_4(sc, BGE_MAC_EVT_ENB,
5419dab5cd05SOleg Bulyzhin 			    BGE_EVTENB_MI_INTERRUPT);
5420dab5cd05SOleg Bulyzhin 			bge_miibus_readreg(sc->bge_dev, 1, BRGPHY_MII_ISR);
5421dab5cd05SOleg Bulyzhin 			bge_miibus_writereg(sc->bge_dev, 1, BRGPHY_MII_IMR,
5422dab5cd05SOleg Bulyzhin 			    BRGPHY_INTRS);
5423dab5cd05SOleg Bulyzhin 		}
5424dab5cd05SOleg Bulyzhin 		return;
5425dab5cd05SOleg Bulyzhin 	}
5426dab5cd05SOleg Bulyzhin 
5427652ae483SGleb Smirnoff 	if (sc->bge_flags & BGE_FLAG_TBI) {
54281f313773SOleg Bulyzhin 		status = CSR_READ_4(sc, BGE_MAC_STS);
54297b97099dSOleg Bulyzhin 		if (status & BGE_MACSTAT_TBI_PCS_SYNCHED) {
54307b97099dSOleg Bulyzhin 			if (!sc->bge_link) {
54311f313773SOleg Bulyzhin 				sc->bge_link++;
54321f313773SOleg Bulyzhin 				if (sc->bge_asicrev == BGE_ASICREV_BCM5704)
54331f313773SOleg Bulyzhin 					BGE_CLRBIT(sc, BGE_MAC_MODE,
54341f313773SOleg Bulyzhin 					    BGE_MACMODE_TBI_SEND_CFGS);
54350c8aa4eaSJung-uk Kim 				CSR_WRITE_4(sc, BGE_MAC_STS, 0xFFFFFFFF);
54361f313773SOleg Bulyzhin 				if (bootverbose)
54371f313773SOleg Bulyzhin 					if_printf(sc->bge_ifp, "link UP\n");
54383f74909aSGleb Smirnoff 				if_link_state_change(sc->bge_ifp,
54393f74909aSGleb Smirnoff 				    LINK_STATE_UP);
54407b97099dSOleg Bulyzhin 			}
54411f313773SOleg Bulyzhin 		} else if (sc->bge_link) {
5442dab5cd05SOleg Bulyzhin 			sc->bge_link = 0;
54431f313773SOleg Bulyzhin 			if (bootverbose)
54441f313773SOleg Bulyzhin 				if_printf(sc->bge_ifp, "link DOWN\n");
54457b97099dSOleg Bulyzhin 			if_link_state_change(sc->bge_ifp, LINK_STATE_DOWN);
54461f313773SOleg Bulyzhin 		}
54476ede2cfaSPyun YongHyeon 	} else if ((sc->bge_mi_mode & BGE_MIMODE_AUTOPOLL) != 0) {
54481f313773SOleg Bulyzhin 		/*
54490c8aa4eaSJung-uk Kim 		 * Some broken BCM chips have BGE_STATFLAG_LINKSTATE_CHANGED bit
54500c8aa4eaSJung-uk Kim 		 * in status word always set. Workaround this bug by reading
54510c8aa4eaSJung-uk Kim 		 * PHY link status directly.
54521f313773SOleg Bulyzhin 		 */
54531f313773SOleg Bulyzhin 		link = (CSR_READ_4(sc, BGE_MI_STS) & BGE_MISTS_LINK) ? 1 : 0;
54541f313773SOleg Bulyzhin 
54551f313773SOleg Bulyzhin 		if (link != sc->bge_link ||
54561f313773SOleg Bulyzhin 		    sc->bge_asicrev == BGE_ASICREV_BCM5700) {
54571f313773SOleg Bulyzhin 			mii = device_get_softc(sc->bge_miibus);
54585dda8085SOleg Bulyzhin 			mii_pollstat(mii);
54591f313773SOleg Bulyzhin 			if (!sc->bge_link &&
54601f313773SOleg Bulyzhin 			    mii->mii_media_status & IFM_ACTIVE &&
54611f313773SOleg Bulyzhin 			    IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) {
54621f313773SOleg Bulyzhin 				sc->bge_link++;
54631f313773SOleg Bulyzhin 				if (bootverbose)
54641f313773SOleg Bulyzhin 					if_printf(sc->bge_ifp, "link UP\n");
54651f313773SOleg Bulyzhin 			} else if (sc->bge_link &&
54661f313773SOleg Bulyzhin 			    (!(mii->mii_media_status & IFM_ACTIVE) ||
54671f313773SOleg Bulyzhin 			    IFM_SUBTYPE(mii->mii_media_active) == IFM_NONE)) {
54681f313773SOleg Bulyzhin 				sc->bge_link = 0;
54691f313773SOleg Bulyzhin 				if (bootverbose)
54701f313773SOleg Bulyzhin 					if_printf(sc->bge_ifp, "link DOWN\n");
54711f313773SOleg Bulyzhin 			}
54721f313773SOleg Bulyzhin 		}
54730c8aa4eaSJung-uk Kim 	} else {
54740c8aa4eaSJung-uk Kim 		/*
54756ede2cfaSPyun YongHyeon 		 * For controllers that call mii_tick, we have to poll
54766ede2cfaSPyun YongHyeon 		 * link status.
54770c8aa4eaSJung-uk Kim 		 */
54786ede2cfaSPyun YongHyeon 		mii = device_get_softc(sc->bge_miibus);
54796ede2cfaSPyun YongHyeon 		mii_pollstat(mii);
54806ede2cfaSPyun YongHyeon 		bge_miibus_statchg(sc->bge_dev);
5481dab5cd05SOleg Bulyzhin 	}
5482dab5cd05SOleg Bulyzhin 
54833f74909aSGleb Smirnoff 	/* Clear the attention. */
5484dab5cd05SOleg Bulyzhin 	CSR_WRITE_4(sc, BGE_MAC_STS, BGE_MACSTAT_SYNC_CHANGED |
5485dab5cd05SOleg Bulyzhin 	    BGE_MACSTAT_CFG_CHANGED | BGE_MACSTAT_MI_COMPLETE |
5486dab5cd05SOleg Bulyzhin 	    BGE_MACSTAT_LINK_CHANGED);
5487dab5cd05SOleg Bulyzhin }
54886f8718a3SScott Long 
54896f8718a3SScott Long static void
54906f8718a3SScott Long bge_add_sysctls(struct bge_softc *sc)
54916f8718a3SScott Long {
54926f8718a3SScott Long 	struct sysctl_ctx_list *ctx;
54932280c16bSPyun YongHyeon 	struct sysctl_oid_list *children;
54947e32f79aSPyun YongHyeon 	char tn[32];
54957e32f79aSPyun YongHyeon 	int unit;
54966f8718a3SScott Long 
54976f8718a3SScott Long 	ctx = device_get_sysctl_ctx(sc->bge_dev);
54986f8718a3SScott Long 	children = SYSCTL_CHILDREN(device_get_sysctl_tree(sc->bge_dev));
54996f8718a3SScott Long 
55006f8718a3SScott Long #ifdef BGE_REGISTER_DEBUG
55016f8718a3SScott Long 	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "debug_info",
55026f8718a3SScott Long 	    CTLTYPE_INT | CTLFLAG_RW, sc, 0, bge_sysctl_debug_info, "I",
55036f8718a3SScott Long 	    "Debug Information");
55046f8718a3SScott Long 
55056f8718a3SScott Long 	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "reg_read",
55066f8718a3SScott Long 	    CTLTYPE_INT | CTLFLAG_RW, sc, 0, bge_sysctl_reg_read, "I",
55076f8718a3SScott Long 	    "Register Read");
55086f8718a3SScott Long 
55096f8718a3SScott Long 	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "mem_read",
55106f8718a3SScott Long 	    CTLTYPE_INT | CTLFLAG_RW, sc, 0, bge_sysctl_mem_read, "I",
55116f8718a3SScott Long 	    "Memory Read");
55126f8718a3SScott Long 
55136f8718a3SScott Long #endif
5514763757b2SScott Long 
55157e32f79aSPyun YongHyeon 	unit = device_get_unit(sc->bge_dev);
5516beaa2ae1SPyun YongHyeon 	/*
5517beaa2ae1SPyun YongHyeon 	 * A common design characteristic for many Broadcom client controllers
5518beaa2ae1SPyun YongHyeon 	 * is that they only support a single outstanding DMA read operation
5519beaa2ae1SPyun YongHyeon 	 * on the PCIe bus. This means that it will take twice as long to fetch
5520beaa2ae1SPyun YongHyeon 	 * a TX frame that is split into header and payload buffers as it does
5521beaa2ae1SPyun YongHyeon 	 * to fetch a single, contiguous TX frame (2 reads vs. 1 read). For
5522beaa2ae1SPyun YongHyeon 	 * these controllers, coalescing buffers to reduce the number of memory
5523beaa2ae1SPyun YongHyeon 	 * reads is effective way to get maximum performance(about 940Mbps).
5524beaa2ae1SPyun YongHyeon 	 * Without collapsing TX buffers the maximum TCP bulk transfer
5525beaa2ae1SPyun YongHyeon 	 * performance is about 850Mbps. However forcing coalescing mbufs
5526beaa2ae1SPyun YongHyeon 	 * consumes a lot of CPU cycles, so leave it off by default.
5527beaa2ae1SPyun YongHyeon 	 */
55287e32f79aSPyun YongHyeon 	sc->bge_forced_collapse = 0;
55297e32f79aSPyun YongHyeon 	snprintf(tn, sizeof(tn), "dev.bge.%d.forced_collapse", unit);
55307e32f79aSPyun YongHyeon 	TUNABLE_INT_FETCH(tn, &sc->bge_forced_collapse);
5531beaa2ae1SPyun YongHyeon 	SYSCTL_ADD_INT(ctx, children, OID_AUTO, "forced_collapse",
5532beaa2ae1SPyun YongHyeon 	    CTLFLAG_RW, &sc->bge_forced_collapse, 0,
5533beaa2ae1SPyun YongHyeon 	    "Number of fragmented TX buffers of a frame allowed before "
5534beaa2ae1SPyun YongHyeon 	    "forced collapsing");
5535beaa2ae1SPyun YongHyeon 
553635f945cdSPyun YongHyeon 	/*
553735f945cdSPyun YongHyeon 	 * It seems all Broadcom controllers have a bug that can generate UDP
553835f945cdSPyun YongHyeon 	 * datagrams with checksum value 0 when TX UDP checksum offloading is
553935f945cdSPyun YongHyeon 	 * enabled.  Generating UDP checksum value 0 is RFC 768 violation.
554035f945cdSPyun YongHyeon 	 * Even though the probability of generating such UDP datagrams is
554135f945cdSPyun YongHyeon 	 * low, I don't want to see FreeBSD boxes to inject such datagrams
554235f945cdSPyun YongHyeon 	 * into network so disable UDP checksum offloading by default.  Users
554335f945cdSPyun YongHyeon 	 * still override this behavior by setting a sysctl variable,
554435f945cdSPyun YongHyeon 	 * dev.bge.0.forced_udpcsum.
554535f945cdSPyun YongHyeon 	 */
554635f945cdSPyun YongHyeon 	sc->bge_forced_udpcsum = 0;
554735f945cdSPyun YongHyeon 	snprintf(tn, sizeof(tn), "dev.bge.%d.bge_forced_udpcsum", unit);
554835f945cdSPyun YongHyeon 	TUNABLE_INT_FETCH(tn, &sc->bge_forced_udpcsum);
554935f945cdSPyun YongHyeon 	SYSCTL_ADD_INT(ctx, children, OID_AUTO, "forced_udpcsum",
555035f945cdSPyun YongHyeon 	    CTLFLAG_RW, &sc->bge_forced_udpcsum, 0,
555135f945cdSPyun YongHyeon 	    "Enable UDP checksum offloading even if controller can "
555235f945cdSPyun YongHyeon 	    "generate UDP checksum value 0");
555335f945cdSPyun YongHyeon 
5554d949071dSJung-uk Kim 	if (BGE_IS_5705_PLUS(sc))
55552280c16bSPyun YongHyeon 		bge_add_sysctl_stats_regs(sc, ctx, children);
55562280c16bSPyun YongHyeon 	else
55572280c16bSPyun YongHyeon 		bge_add_sysctl_stats(sc, ctx, children);
55582280c16bSPyun YongHyeon }
5559d949071dSJung-uk Kim 
55602280c16bSPyun YongHyeon #define BGE_SYSCTL_STAT(sc, ctx, desc, parent, node, oid) \
55612280c16bSPyun YongHyeon 	SYSCTL_ADD_PROC(ctx, parent, OID_AUTO, oid, CTLTYPE_UINT|CTLFLAG_RD, \
55622280c16bSPyun YongHyeon 	    sc, offsetof(struct bge_stats, node), bge_sysctl_stats, "IU", \
55632280c16bSPyun YongHyeon 	    desc)
55642280c16bSPyun YongHyeon 
55652280c16bSPyun YongHyeon static void
55662280c16bSPyun YongHyeon bge_add_sysctl_stats(struct bge_softc *sc, struct sysctl_ctx_list *ctx,
55672280c16bSPyun YongHyeon     struct sysctl_oid_list *parent)
55682280c16bSPyun YongHyeon {
55692280c16bSPyun YongHyeon 	struct sysctl_oid *tree;
55702280c16bSPyun YongHyeon 	struct sysctl_oid_list *children, *schildren;
55712280c16bSPyun YongHyeon 
55722280c16bSPyun YongHyeon 	tree = SYSCTL_ADD_NODE(ctx, parent, OID_AUTO, "stats", CTLFLAG_RD,
5573763757b2SScott Long 	    NULL, "BGE Statistics");
5574763757b2SScott Long 	schildren = children = SYSCTL_CHILDREN(tree);
5575763757b2SScott Long 	BGE_SYSCTL_STAT(sc, ctx, "Frames Dropped Due To Filters",
5576763757b2SScott Long 	    children, COSFramesDroppedDueToFilters,
5577763757b2SScott Long 	    "FramesDroppedDueToFilters");
5578763757b2SScott Long 	BGE_SYSCTL_STAT(sc, ctx, "NIC DMA Write Queue Full",
5579763757b2SScott Long 	    children, nicDmaWriteQueueFull, "DmaWriteQueueFull");
5580763757b2SScott Long 	BGE_SYSCTL_STAT(sc, ctx, "NIC DMA Write High Priority Queue Full",
5581763757b2SScott Long 	    children, nicDmaWriteHighPriQueueFull, "DmaWriteHighPriQueueFull");
5582763757b2SScott Long 	BGE_SYSCTL_STAT(sc, ctx, "NIC No More RX Buffer Descriptors",
5583763757b2SScott Long 	    children, nicNoMoreRxBDs, "NoMoreRxBDs");
558406e83c7eSScott Long 	BGE_SYSCTL_STAT(sc, ctx, "Discarded Input Frames",
558506e83c7eSScott Long 	    children, ifInDiscards, "InputDiscards");
558606e83c7eSScott Long 	BGE_SYSCTL_STAT(sc, ctx, "Input Errors",
558706e83c7eSScott Long 	    children, ifInErrors, "InputErrors");
5588763757b2SScott Long 	BGE_SYSCTL_STAT(sc, ctx, "NIC Recv Threshold Hit",
5589763757b2SScott Long 	    children, nicRecvThresholdHit, "RecvThresholdHit");
5590763757b2SScott Long 	BGE_SYSCTL_STAT(sc, ctx, "NIC DMA Read Queue Full",
5591763757b2SScott Long 	    children, nicDmaReadQueueFull, "DmaReadQueueFull");
5592763757b2SScott Long 	BGE_SYSCTL_STAT(sc, ctx, "NIC DMA Read High Priority Queue Full",
5593763757b2SScott Long 	    children, nicDmaReadHighPriQueueFull, "DmaReadHighPriQueueFull");
5594763757b2SScott Long 	BGE_SYSCTL_STAT(sc, ctx, "NIC Send Data Complete Queue Full",
5595763757b2SScott Long 	    children, nicSendDataCompQueueFull, "SendDataCompQueueFull");
5596763757b2SScott Long 	BGE_SYSCTL_STAT(sc, ctx, "NIC Ring Set Send Producer Index",
5597763757b2SScott Long 	    children, nicRingSetSendProdIndex, "RingSetSendProdIndex");
5598763757b2SScott Long 	BGE_SYSCTL_STAT(sc, ctx, "NIC Ring Status Update",
5599763757b2SScott Long 	    children, nicRingStatusUpdate, "RingStatusUpdate");
5600763757b2SScott Long 	BGE_SYSCTL_STAT(sc, ctx, "NIC Interrupts",
5601763757b2SScott Long 	    children, nicInterrupts, "Interrupts");
5602763757b2SScott Long 	BGE_SYSCTL_STAT(sc, ctx, "NIC Avoided Interrupts",
5603763757b2SScott Long 	    children, nicAvoidedInterrupts, "AvoidedInterrupts");
5604763757b2SScott Long 	BGE_SYSCTL_STAT(sc, ctx, "NIC Send Threshold Hit",
5605763757b2SScott Long 	    children, nicSendThresholdHit, "SendThresholdHit");
5606763757b2SScott Long 
5607763757b2SScott Long 	tree = SYSCTL_ADD_NODE(ctx, schildren, OID_AUTO, "rx", CTLFLAG_RD,
5608763757b2SScott Long 	    NULL, "BGE RX Statistics");
5609763757b2SScott Long 	children = SYSCTL_CHILDREN(tree);
5610763757b2SScott Long 	BGE_SYSCTL_STAT(sc, ctx, "Inbound Octets",
56111cd4773bSPyun YongHyeon 	    children, rxstats.ifHCInOctets, "ifHCInOctets");
5612763757b2SScott Long 	BGE_SYSCTL_STAT(sc, ctx, "Fragments",
5613763757b2SScott Long 	    children, rxstats.etherStatsFragments, "Fragments");
5614763757b2SScott Long 	BGE_SYSCTL_STAT(sc, ctx, "Inbound Unicast Packets",
56151cd4773bSPyun YongHyeon 	    children, rxstats.ifHCInUcastPkts, "UnicastPkts");
5616763757b2SScott Long 	BGE_SYSCTL_STAT(sc, ctx, "Inbound Multicast Packets",
5617763757b2SScott Long 	    children, rxstats.ifHCInMulticastPkts, "MulticastPkts");
5618763757b2SScott Long 	BGE_SYSCTL_STAT(sc, ctx, "FCS Errors",
5619763757b2SScott Long 	    children, rxstats.dot3StatsFCSErrors, "FCSErrors");
5620763757b2SScott Long 	BGE_SYSCTL_STAT(sc, ctx, "Alignment Errors",
5621763757b2SScott Long 	    children, rxstats.dot3StatsAlignmentErrors, "AlignmentErrors");
5622763757b2SScott Long 	BGE_SYSCTL_STAT(sc, ctx, "XON Pause Frames Received",
5623763757b2SScott Long 	    children, rxstats.xonPauseFramesReceived, "xonPauseFramesReceived");
5624763757b2SScott Long 	BGE_SYSCTL_STAT(sc, ctx, "XOFF Pause Frames Received",
5625763757b2SScott Long 	    children, rxstats.xoffPauseFramesReceived,
5626763757b2SScott Long 	    "xoffPauseFramesReceived");
5627763757b2SScott Long 	BGE_SYSCTL_STAT(sc, ctx, "MAC Control Frames Received",
5628763757b2SScott Long 	    children, rxstats.macControlFramesReceived,
5629763757b2SScott Long 	    "ControlFramesReceived");
5630763757b2SScott Long 	BGE_SYSCTL_STAT(sc, ctx, "XOFF State Entered",
5631763757b2SScott Long 	    children, rxstats.xoffStateEntered, "xoffStateEntered");
5632763757b2SScott Long 	BGE_SYSCTL_STAT(sc, ctx, "Frames Too Long",
5633763757b2SScott Long 	    children, rxstats.dot3StatsFramesTooLong, "FramesTooLong");
5634763757b2SScott Long 	BGE_SYSCTL_STAT(sc, ctx, "Jabbers",
5635763757b2SScott Long 	    children, rxstats.etherStatsJabbers, "Jabbers");
5636763757b2SScott Long 	BGE_SYSCTL_STAT(sc, ctx, "Undersized Packets",
5637763757b2SScott Long 	    children, rxstats.etherStatsUndersizePkts, "UndersizePkts");
5638763757b2SScott Long 	BGE_SYSCTL_STAT(sc, ctx, "Inbound Range Length Errors",
563906e83c7eSScott Long 	    children, rxstats.inRangeLengthError, "inRangeLengthError");
5640763757b2SScott Long 	BGE_SYSCTL_STAT(sc, ctx, "Outbound Range Length Errors",
564106e83c7eSScott Long 	    children, rxstats.outRangeLengthError, "outRangeLengthError");
5642763757b2SScott Long 
5643763757b2SScott Long 	tree = SYSCTL_ADD_NODE(ctx, schildren, OID_AUTO, "tx", CTLFLAG_RD,
5644763757b2SScott Long 	    NULL, "BGE TX Statistics");
5645763757b2SScott Long 	children = SYSCTL_CHILDREN(tree);
5646763757b2SScott Long 	BGE_SYSCTL_STAT(sc, ctx, "Outbound Octets",
56471cd4773bSPyun YongHyeon 	    children, txstats.ifHCOutOctets, "ifHCOutOctets");
5648763757b2SScott Long 	BGE_SYSCTL_STAT(sc, ctx, "TX Collisions",
5649763757b2SScott Long 	    children, txstats.etherStatsCollisions, "Collisions");
5650763757b2SScott Long 	BGE_SYSCTL_STAT(sc, ctx, "XON Sent",
5651763757b2SScott Long 	    children, txstats.outXonSent, "XonSent");
5652763757b2SScott Long 	BGE_SYSCTL_STAT(sc, ctx, "XOFF Sent",
5653763757b2SScott Long 	    children, txstats.outXoffSent, "XoffSent");
5654763757b2SScott Long 	BGE_SYSCTL_STAT(sc, ctx, "Flow Control Done",
5655763757b2SScott Long 	    children, txstats.flowControlDone, "flowControlDone");
5656763757b2SScott Long 	BGE_SYSCTL_STAT(sc, ctx, "Internal MAC TX errors",
5657763757b2SScott Long 	    children, txstats.dot3StatsInternalMacTransmitErrors,
5658763757b2SScott Long 	    "InternalMacTransmitErrors");
5659763757b2SScott Long 	BGE_SYSCTL_STAT(sc, ctx, "Single Collision Frames",
5660763757b2SScott Long 	    children, txstats.dot3StatsSingleCollisionFrames,
5661763757b2SScott Long 	    "SingleCollisionFrames");
5662763757b2SScott Long 	BGE_SYSCTL_STAT(sc, ctx, "Multiple Collision Frames",
5663763757b2SScott Long 	    children, txstats.dot3StatsMultipleCollisionFrames,
5664763757b2SScott Long 	    "MultipleCollisionFrames");
5665763757b2SScott Long 	BGE_SYSCTL_STAT(sc, ctx, "Deferred Transmissions",
5666763757b2SScott Long 	    children, txstats.dot3StatsDeferredTransmissions,
5667763757b2SScott Long 	    "DeferredTransmissions");
5668763757b2SScott Long 	BGE_SYSCTL_STAT(sc, ctx, "Excessive Collisions",
5669763757b2SScott Long 	    children, txstats.dot3StatsExcessiveCollisions,
5670763757b2SScott Long 	    "ExcessiveCollisions");
5671763757b2SScott Long 	BGE_SYSCTL_STAT(sc, ctx, "Late Collisions",
567206e83c7eSScott Long 	    children, txstats.dot3StatsLateCollisions,
567306e83c7eSScott Long 	    "LateCollisions");
5674763757b2SScott Long 	BGE_SYSCTL_STAT(sc, ctx, "Outbound Unicast Packets",
56751cd4773bSPyun YongHyeon 	    children, txstats.ifHCOutUcastPkts, "UnicastPkts");
5676763757b2SScott Long 	BGE_SYSCTL_STAT(sc, ctx, "Outbound Multicast Packets",
5677763757b2SScott Long 	    children, txstats.ifHCOutMulticastPkts, "MulticastPkts");
5678763757b2SScott Long 	BGE_SYSCTL_STAT(sc, ctx, "Outbound Broadcast Packets",
5679763757b2SScott Long 	    children, txstats.ifHCOutBroadcastPkts, "BroadcastPkts");
5680763757b2SScott Long 	BGE_SYSCTL_STAT(sc, ctx, "Carrier Sense Errors",
5681763757b2SScott Long 	    children, txstats.dot3StatsCarrierSenseErrors,
5682763757b2SScott Long 	    "CarrierSenseErrors");
5683763757b2SScott Long 	BGE_SYSCTL_STAT(sc, ctx, "Outbound Discards",
5684763757b2SScott Long 	    children, txstats.ifOutDiscards, "Discards");
5685763757b2SScott Long 	BGE_SYSCTL_STAT(sc, ctx, "Outbound Errors",
5686763757b2SScott Long 	    children, txstats.ifOutErrors, "Errors");
5687763757b2SScott Long }
5688763757b2SScott Long 
56892280c16bSPyun YongHyeon #undef BGE_SYSCTL_STAT
56902280c16bSPyun YongHyeon 
56912280c16bSPyun YongHyeon #define	BGE_SYSCTL_STAT_ADD64(c, h, n, p, d)	\
56926dc7dc9aSMatthew D Fleming 	    SYSCTL_ADD_UQUAD(c, h, OID_AUTO, n, CTLFLAG_RD, p, d)
56932280c16bSPyun YongHyeon 
56942280c16bSPyun YongHyeon static void
56952280c16bSPyun YongHyeon bge_add_sysctl_stats_regs(struct bge_softc *sc, struct sysctl_ctx_list *ctx,
56962280c16bSPyun YongHyeon     struct sysctl_oid_list *parent)
56972280c16bSPyun YongHyeon {
56982280c16bSPyun YongHyeon 	struct sysctl_oid *tree;
56992280c16bSPyun YongHyeon 	struct sysctl_oid_list *child, *schild;
57002280c16bSPyun YongHyeon 	struct bge_mac_stats *stats;
57012280c16bSPyun YongHyeon 
57022280c16bSPyun YongHyeon 	stats = &sc->bge_mac_stats;
57032280c16bSPyun YongHyeon 	tree = SYSCTL_ADD_NODE(ctx, parent, OID_AUTO, "stats", CTLFLAG_RD,
57042280c16bSPyun YongHyeon 	    NULL, "BGE Statistics");
57052280c16bSPyun YongHyeon 	schild = child = SYSCTL_CHILDREN(tree);
57062280c16bSPyun YongHyeon 	BGE_SYSCTL_STAT_ADD64(ctx, child, "FramesDroppedDueToFilters",
57072280c16bSPyun YongHyeon 	    &stats->FramesDroppedDueToFilters, "Frames Dropped Due to Filters");
57082280c16bSPyun YongHyeon 	BGE_SYSCTL_STAT_ADD64(ctx, child, "DmaWriteQueueFull",
57092280c16bSPyun YongHyeon 	    &stats->DmaWriteQueueFull, "NIC DMA Write Queue Full");
57102280c16bSPyun YongHyeon 	BGE_SYSCTL_STAT_ADD64(ctx, child, "DmaWriteHighPriQueueFull",
57112280c16bSPyun YongHyeon 	    &stats->DmaWriteHighPriQueueFull,
57122280c16bSPyun YongHyeon 	    "NIC DMA Write High Priority Queue Full");
57132280c16bSPyun YongHyeon 	BGE_SYSCTL_STAT_ADD64(ctx, child, "NoMoreRxBDs",
57142280c16bSPyun YongHyeon 	    &stats->NoMoreRxBDs, "NIC No More RX Buffer Descriptors");
57152280c16bSPyun YongHyeon 	BGE_SYSCTL_STAT_ADD64(ctx, child, "InputDiscards",
57162280c16bSPyun YongHyeon 	    &stats->InputDiscards, "Discarded Input Frames");
57172280c16bSPyun YongHyeon 	BGE_SYSCTL_STAT_ADD64(ctx, child, "InputErrors",
57182280c16bSPyun YongHyeon 	    &stats->InputErrors, "Input Errors");
57192280c16bSPyun YongHyeon 	BGE_SYSCTL_STAT_ADD64(ctx, child, "RecvThresholdHit",
57202280c16bSPyun YongHyeon 	    &stats->RecvThresholdHit, "NIC Recv Threshold Hit");
57212280c16bSPyun YongHyeon 
57222280c16bSPyun YongHyeon 	tree = SYSCTL_ADD_NODE(ctx, schild, OID_AUTO, "rx", CTLFLAG_RD,
57232280c16bSPyun YongHyeon 	    NULL, "BGE RX Statistics");
57242280c16bSPyun YongHyeon 	child = SYSCTL_CHILDREN(tree);
57252280c16bSPyun YongHyeon 	BGE_SYSCTL_STAT_ADD64(ctx, child, "ifHCInOctets",
57262280c16bSPyun YongHyeon 	    &stats->ifHCInOctets, "Inbound Octets");
57272280c16bSPyun YongHyeon 	BGE_SYSCTL_STAT_ADD64(ctx, child, "Fragments",
57282280c16bSPyun YongHyeon 	    &stats->etherStatsFragments, "Fragments");
57291cd4773bSPyun YongHyeon 	BGE_SYSCTL_STAT_ADD64(ctx, child, "UnicastPkts",
57302280c16bSPyun YongHyeon 	    &stats->ifHCInUcastPkts, "Inbound Unicast Packets");
57312280c16bSPyun YongHyeon 	BGE_SYSCTL_STAT_ADD64(ctx, child, "MulticastPkts",
57322280c16bSPyun YongHyeon 	    &stats->ifHCInMulticastPkts, "Inbound Multicast Packets");
57332280c16bSPyun YongHyeon 	BGE_SYSCTL_STAT_ADD64(ctx, child, "BroadcastPkts",
57342280c16bSPyun YongHyeon 	    &stats->ifHCInBroadcastPkts, "Inbound Broadcast Packets");
57352280c16bSPyun YongHyeon 	BGE_SYSCTL_STAT_ADD64(ctx, child, "FCSErrors",
57362280c16bSPyun YongHyeon 	    &stats->dot3StatsFCSErrors, "FCS Errors");
57372280c16bSPyun YongHyeon 	BGE_SYSCTL_STAT_ADD64(ctx, child, "AlignmentErrors",
57382280c16bSPyun YongHyeon 	    &stats->dot3StatsAlignmentErrors, "Alignment Errors");
57392280c16bSPyun YongHyeon 	BGE_SYSCTL_STAT_ADD64(ctx, child, "xonPauseFramesReceived",
57402280c16bSPyun YongHyeon 	    &stats->xonPauseFramesReceived, "XON Pause Frames Received");
57412280c16bSPyun YongHyeon 	BGE_SYSCTL_STAT_ADD64(ctx, child, "xoffPauseFramesReceived",
57422280c16bSPyun YongHyeon 	    &stats->xoffPauseFramesReceived, "XOFF Pause Frames Received");
57432280c16bSPyun YongHyeon 	BGE_SYSCTL_STAT_ADD64(ctx, child, "ControlFramesReceived",
57442280c16bSPyun YongHyeon 	    &stats->macControlFramesReceived, "MAC Control Frames Received");
57452280c16bSPyun YongHyeon 	BGE_SYSCTL_STAT_ADD64(ctx, child, "xoffStateEntered",
57462280c16bSPyun YongHyeon 	    &stats->xoffStateEntered, "XOFF State Entered");
57472280c16bSPyun YongHyeon 	BGE_SYSCTL_STAT_ADD64(ctx, child, "FramesTooLong",
57482280c16bSPyun YongHyeon 	    &stats->dot3StatsFramesTooLong, "Frames Too Long");
57492280c16bSPyun YongHyeon 	BGE_SYSCTL_STAT_ADD64(ctx, child, "Jabbers",
57502280c16bSPyun YongHyeon 	    &stats->etherStatsJabbers, "Jabbers");
57512280c16bSPyun YongHyeon 	BGE_SYSCTL_STAT_ADD64(ctx, child, "UndersizePkts",
57522280c16bSPyun YongHyeon 	    &stats->etherStatsUndersizePkts, "Undersized Packets");
57532280c16bSPyun YongHyeon 
57542280c16bSPyun YongHyeon 	tree = SYSCTL_ADD_NODE(ctx, schild, OID_AUTO, "tx", CTLFLAG_RD,
57552280c16bSPyun YongHyeon 	    NULL, "BGE TX Statistics");
57562280c16bSPyun YongHyeon 	child = SYSCTL_CHILDREN(tree);
57571cd4773bSPyun YongHyeon 	BGE_SYSCTL_STAT_ADD64(ctx, child, "ifHCOutOctets",
57582280c16bSPyun YongHyeon 	    &stats->ifHCOutOctets, "Outbound Octets");
57592280c16bSPyun YongHyeon 	BGE_SYSCTL_STAT_ADD64(ctx, child, "Collisions",
57602280c16bSPyun YongHyeon 	    &stats->etherStatsCollisions, "TX Collisions");
57612280c16bSPyun YongHyeon 	BGE_SYSCTL_STAT_ADD64(ctx, child, "XonSent",
57622280c16bSPyun YongHyeon 	    &stats->outXonSent, "XON Sent");
57632280c16bSPyun YongHyeon 	BGE_SYSCTL_STAT_ADD64(ctx, child, "XoffSent",
57642280c16bSPyun YongHyeon 	    &stats->outXoffSent, "XOFF Sent");
57652280c16bSPyun YongHyeon 	BGE_SYSCTL_STAT_ADD64(ctx, child, "InternalMacTransmitErrors",
57662280c16bSPyun YongHyeon 	    &stats->dot3StatsInternalMacTransmitErrors,
57672280c16bSPyun YongHyeon 	    "Internal MAC TX Errors");
57682280c16bSPyun YongHyeon 	BGE_SYSCTL_STAT_ADD64(ctx, child, "SingleCollisionFrames",
57692280c16bSPyun YongHyeon 	    &stats->dot3StatsSingleCollisionFrames, "Single Collision Frames");
57702280c16bSPyun YongHyeon 	BGE_SYSCTL_STAT_ADD64(ctx, child, "MultipleCollisionFrames",
57712280c16bSPyun YongHyeon 	    &stats->dot3StatsMultipleCollisionFrames,
57722280c16bSPyun YongHyeon 	    "Multiple Collision Frames");
57732280c16bSPyun YongHyeon 	BGE_SYSCTL_STAT_ADD64(ctx, child, "DeferredTransmissions",
57742280c16bSPyun YongHyeon 	    &stats->dot3StatsDeferredTransmissions, "Deferred Transmissions");
57752280c16bSPyun YongHyeon 	BGE_SYSCTL_STAT_ADD64(ctx, child, "ExcessiveCollisions",
57762280c16bSPyun YongHyeon 	    &stats->dot3StatsExcessiveCollisions, "Excessive Collisions");
57772280c16bSPyun YongHyeon 	BGE_SYSCTL_STAT_ADD64(ctx, child, "LateCollisions",
57782280c16bSPyun YongHyeon 	    &stats->dot3StatsLateCollisions, "Late Collisions");
57791cd4773bSPyun YongHyeon 	BGE_SYSCTL_STAT_ADD64(ctx, child, "UnicastPkts",
57802280c16bSPyun YongHyeon 	    &stats->ifHCOutUcastPkts, "Outbound Unicast Packets");
57811cd4773bSPyun YongHyeon 	BGE_SYSCTL_STAT_ADD64(ctx, child, "MulticastPkts",
57822280c16bSPyun YongHyeon 	    &stats->ifHCOutMulticastPkts, "Outbound Multicast Packets");
57831cd4773bSPyun YongHyeon 	BGE_SYSCTL_STAT_ADD64(ctx, child, "BroadcastPkts",
57842280c16bSPyun YongHyeon 	    &stats->ifHCOutBroadcastPkts, "Outbound Broadcast Packets");
57852280c16bSPyun YongHyeon }
57862280c16bSPyun YongHyeon 
57872280c16bSPyun YongHyeon #undef	BGE_SYSCTL_STAT_ADD64
57882280c16bSPyun YongHyeon 
5789763757b2SScott Long static int
5790763757b2SScott Long bge_sysctl_stats(SYSCTL_HANDLER_ARGS)
5791763757b2SScott Long {
5792763757b2SScott Long 	struct bge_softc *sc;
579306e83c7eSScott Long 	uint32_t result;
5794d949071dSJung-uk Kim 	int offset;
5795763757b2SScott Long 
5796763757b2SScott Long 	sc = (struct bge_softc *)arg1;
5797763757b2SScott Long 	offset = arg2;
5798d949071dSJung-uk Kim 	result = CSR_READ_4(sc, BGE_MEMWIN_START + BGE_STATS_BLOCK + offset +
5799d949071dSJung-uk Kim 	    offsetof(bge_hostaddr, bge_addr_lo));
5800041b706bSDavid Malone 	return (sysctl_handle_int(oidp, &result, 0, req));
58016f8718a3SScott Long }
58026f8718a3SScott Long 
58036f8718a3SScott Long #ifdef BGE_REGISTER_DEBUG
58046f8718a3SScott Long static int
58056f8718a3SScott Long bge_sysctl_debug_info(SYSCTL_HANDLER_ARGS)
58066f8718a3SScott Long {
58076f8718a3SScott Long 	struct bge_softc *sc;
58086f8718a3SScott Long 	uint16_t *sbdata;
580928276ad6SPyun YongHyeon 	int error, result, sbsz;
58106f8718a3SScott Long 	int i, j;
58116f8718a3SScott Long 
58126f8718a3SScott Long 	result = -1;
58136f8718a3SScott Long 	error = sysctl_handle_int(oidp, &result, 0, req);
58146f8718a3SScott Long 	if (error || (req->newptr == NULL))
58156f8718a3SScott Long 		return (error);
58166f8718a3SScott Long 
58176f8718a3SScott Long 	if (result == 1) {
58186f8718a3SScott Long 		sc = (struct bge_softc *)arg1;
58196f8718a3SScott Long 
582028276ad6SPyun YongHyeon 		if (sc->bge_asicrev == BGE_ASICREV_BCM5700 &&
582128276ad6SPyun YongHyeon 		    sc->bge_chipid != BGE_CHIPID_BCM5700_C0)
582228276ad6SPyun YongHyeon 			sbsz = BGE_STATUS_BLK_SZ;
582328276ad6SPyun YongHyeon 		else
582428276ad6SPyun YongHyeon 			sbsz = 32;
58256f8718a3SScott Long 		sbdata = (uint16_t *)sc->bge_ldata.bge_status_block;
58266f8718a3SScott Long 		printf("Status Block:\n");
582728276ad6SPyun YongHyeon 		BGE_LOCK(sc);
582828276ad6SPyun YongHyeon 		bus_dmamap_sync(sc->bge_cdata.bge_status_tag,
582928276ad6SPyun YongHyeon 		    sc->bge_cdata.bge_status_map,
583028276ad6SPyun YongHyeon 		    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
583128276ad6SPyun YongHyeon 		for (i = 0x0; i < sbsz / sizeof(uint16_t); ) {
58326f8718a3SScott Long 			printf("%06x:", i);
583328276ad6SPyun YongHyeon 			for (j = 0; j < 8; j++)
583428276ad6SPyun YongHyeon 				printf(" %04x", sbdata[i++]);
58356f8718a3SScott Long 			printf("\n");
58366f8718a3SScott Long 		}
58376f8718a3SScott Long 
58386f8718a3SScott Long 		printf("Registers:\n");
58390c8aa4eaSJung-uk Kim 		for (i = 0x800; i < 0xA00; ) {
58406f8718a3SScott Long 			printf("%06x:", i);
58416f8718a3SScott Long 			for (j = 0; j < 8; j++) {
58426f8718a3SScott Long 				printf(" %08x", CSR_READ_4(sc, i));
58436f8718a3SScott Long 				i += 4;
58446f8718a3SScott Long 			}
58456f8718a3SScott Long 			printf("\n");
58466f8718a3SScott Long 		}
584728276ad6SPyun YongHyeon 		BGE_UNLOCK(sc);
58486f8718a3SScott Long 
58496f8718a3SScott Long 		printf("Hardware Flags:\n");
585028276ad6SPyun YongHyeon 		if (BGE_IS_5717_PLUS(sc))
585128276ad6SPyun YongHyeon 			printf(" - 5717 Plus\n");
5852a5779553SStanislav Sedov 		if (BGE_IS_5755_PLUS(sc))
5853a5779553SStanislav Sedov 			printf(" - 5755 Plus\n");
58545345bad0SScott Long 		if (BGE_IS_575X_PLUS(sc))
58556f8718a3SScott Long 			printf(" - 575X Plus\n");
58565345bad0SScott Long 		if (BGE_IS_5705_PLUS(sc))
58576f8718a3SScott Long 			printf(" - 5705 Plus\n");
58585345bad0SScott Long 		if (BGE_IS_5714_FAMILY(sc))
58595345bad0SScott Long 			printf(" - 5714 Family\n");
58605345bad0SScott Long 		if (BGE_IS_5700_FAMILY(sc))
58615345bad0SScott Long 			printf(" - 5700 Family\n");
58626f8718a3SScott Long 		if (sc->bge_flags & BGE_FLAG_JUMBO)
58636f8718a3SScott Long 			printf(" - Supports Jumbo Frames\n");
58646f8718a3SScott Long 		if (sc->bge_flags & BGE_FLAG_PCIX)
58656f8718a3SScott Long 			printf(" - PCI-X Bus\n");
58666f8718a3SScott Long 		if (sc->bge_flags & BGE_FLAG_PCIE)
58676f8718a3SScott Long 			printf(" - PCI Express Bus\n");
58687d3d9608SPyun YongHyeon 		if (sc->bge_phy_flags & BGE_PHY_NO_3LED)
58696f8718a3SScott Long 			printf(" - No 3 LEDs\n");
58706f8718a3SScott Long 		if (sc->bge_flags & BGE_FLAG_RX_ALIGNBUG)
58716f8718a3SScott Long 			printf(" - RX Alignment Bug\n");
58726f8718a3SScott Long 	}
58736f8718a3SScott Long 
58746f8718a3SScott Long 	return (error);
58756f8718a3SScott Long }
58766f8718a3SScott Long 
58776f8718a3SScott Long static int
58786f8718a3SScott Long bge_sysctl_reg_read(SYSCTL_HANDLER_ARGS)
58796f8718a3SScott Long {
58806f8718a3SScott Long 	struct bge_softc *sc;
58816f8718a3SScott Long 	int error;
58826f8718a3SScott Long 	uint16_t result;
58836f8718a3SScott Long 	uint32_t val;
58846f8718a3SScott Long 
58856f8718a3SScott Long 	result = -1;
58866f8718a3SScott Long 	error = sysctl_handle_int(oidp, &result, 0, req);
58876f8718a3SScott Long 	if (error || (req->newptr == NULL))
58886f8718a3SScott Long 		return (error);
58896f8718a3SScott Long 
58906f8718a3SScott Long 	if (result < 0x8000) {
58916f8718a3SScott Long 		sc = (struct bge_softc *)arg1;
58926f8718a3SScott Long 		val = CSR_READ_4(sc, result);
58936f8718a3SScott Long 		printf("reg 0x%06X = 0x%08X\n", result, val);
58946f8718a3SScott Long 	}
58956f8718a3SScott Long 
58966f8718a3SScott Long 	return (error);
58976f8718a3SScott Long }
58986f8718a3SScott Long 
58996f8718a3SScott Long static int
59006f8718a3SScott Long bge_sysctl_mem_read(SYSCTL_HANDLER_ARGS)
59016f8718a3SScott Long {
59026f8718a3SScott Long 	struct bge_softc *sc;
59036f8718a3SScott Long 	int error;
59046f8718a3SScott Long 	uint16_t result;
59056f8718a3SScott Long 	uint32_t val;
59066f8718a3SScott Long 
59076f8718a3SScott Long 	result = -1;
59086f8718a3SScott Long 	error = sysctl_handle_int(oidp, &result, 0, req);
59096f8718a3SScott Long 	if (error || (req->newptr == NULL))
59106f8718a3SScott Long 		return (error);
59116f8718a3SScott Long 
59126f8718a3SScott Long 	if (result < 0x8000) {
59136f8718a3SScott Long 		sc = (struct bge_softc *)arg1;
59146f8718a3SScott Long 		val = bge_readmem_ind(sc, result);
59156f8718a3SScott Long 		printf("mem 0x%06X = 0x%08X\n", result, val);
59166f8718a3SScott Long 	}
59176f8718a3SScott Long 
59186f8718a3SScott Long 	return (error);
59196f8718a3SScott Long }
59206f8718a3SScott Long #endif
592138cc658fSJohn Baldwin 
592238cc658fSJohn Baldwin static int
59235fea260fSMarius Strobl bge_get_eaddr_fw(struct bge_softc *sc, uint8_t ether_addr[])
59245fea260fSMarius Strobl {
59255fea260fSMarius Strobl 
59265fea260fSMarius Strobl 	if (sc->bge_flags & BGE_FLAG_EADDR)
59275fea260fSMarius Strobl 		return (1);
59285fea260fSMarius Strobl 
59295fea260fSMarius Strobl #ifdef __sparc64__
59305fea260fSMarius Strobl 	OF_getetheraddr(sc->bge_dev, ether_addr);
59315fea260fSMarius Strobl 	return (0);
59325fea260fSMarius Strobl #endif
59335fea260fSMarius Strobl 	return (1);
59345fea260fSMarius Strobl }
59355fea260fSMarius Strobl 
59365fea260fSMarius Strobl static int
593738cc658fSJohn Baldwin bge_get_eaddr_mem(struct bge_softc *sc, uint8_t ether_addr[])
593838cc658fSJohn Baldwin {
593938cc658fSJohn Baldwin 	uint32_t mac_addr;
594038cc658fSJohn Baldwin 
594173635418SPyun YongHyeon 	mac_addr = bge_readmem_ind(sc, BGE_SRAM_MAC_ADDR_HIGH_MB);
594238cc658fSJohn Baldwin 	if ((mac_addr >> 16) == 0x484b) {
594338cc658fSJohn Baldwin 		ether_addr[0] = (uint8_t)(mac_addr >> 8);
594438cc658fSJohn Baldwin 		ether_addr[1] = (uint8_t)mac_addr;
594573635418SPyun YongHyeon 		mac_addr = bge_readmem_ind(sc, BGE_SRAM_MAC_ADDR_LOW_MB);
594638cc658fSJohn Baldwin 		ether_addr[2] = (uint8_t)(mac_addr >> 24);
594738cc658fSJohn Baldwin 		ether_addr[3] = (uint8_t)(mac_addr >> 16);
594838cc658fSJohn Baldwin 		ether_addr[4] = (uint8_t)(mac_addr >> 8);
594938cc658fSJohn Baldwin 		ether_addr[5] = (uint8_t)mac_addr;
59505fea260fSMarius Strobl 		return (0);
595138cc658fSJohn Baldwin 	}
59525fea260fSMarius Strobl 	return (1);
595338cc658fSJohn Baldwin }
595438cc658fSJohn Baldwin 
595538cc658fSJohn Baldwin static int
595638cc658fSJohn Baldwin bge_get_eaddr_nvram(struct bge_softc *sc, uint8_t ether_addr[])
595738cc658fSJohn Baldwin {
595838cc658fSJohn Baldwin 	int mac_offset = BGE_EE_MAC_OFFSET;
595938cc658fSJohn Baldwin 
596038cc658fSJohn Baldwin 	if (sc->bge_asicrev == BGE_ASICREV_BCM5906)
596138cc658fSJohn Baldwin 		mac_offset = BGE_EE_MAC_OFFSET_5906;
596238cc658fSJohn Baldwin 
59635fea260fSMarius Strobl 	return (bge_read_nvram(sc, ether_addr, mac_offset + 2,
59645fea260fSMarius Strobl 	    ETHER_ADDR_LEN));
596538cc658fSJohn Baldwin }
596638cc658fSJohn Baldwin 
596738cc658fSJohn Baldwin static int
596838cc658fSJohn Baldwin bge_get_eaddr_eeprom(struct bge_softc *sc, uint8_t ether_addr[])
596938cc658fSJohn Baldwin {
597038cc658fSJohn Baldwin 
59715fea260fSMarius Strobl 	if (sc->bge_asicrev == BGE_ASICREV_BCM5906)
59725fea260fSMarius Strobl 		return (1);
59735fea260fSMarius Strobl 
59745fea260fSMarius Strobl 	return (bge_read_eeprom(sc, ether_addr, BGE_EE_MAC_OFFSET + 2,
59755fea260fSMarius Strobl 	   ETHER_ADDR_LEN));
597638cc658fSJohn Baldwin }
597738cc658fSJohn Baldwin 
597838cc658fSJohn Baldwin static int
597938cc658fSJohn Baldwin bge_get_eaddr(struct bge_softc *sc, uint8_t eaddr[])
598038cc658fSJohn Baldwin {
598138cc658fSJohn Baldwin 	static const bge_eaddr_fcn_t bge_eaddr_funcs[] = {
598238cc658fSJohn Baldwin 		/* NOTE: Order is critical */
59835fea260fSMarius Strobl 		bge_get_eaddr_fw,
598438cc658fSJohn Baldwin 		bge_get_eaddr_mem,
598538cc658fSJohn Baldwin 		bge_get_eaddr_nvram,
598638cc658fSJohn Baldwin 		bge_get_eaddr_eeprom,
598738cc658fSJohn Baldwin 		NULL
598838cc658fSJohn Baldwin 	};
598938cc658fSJohn Baldwin 	const bge_eaddr_fcn_t *func;
599038cc658fSJohn Baldwin 
599138cc658fSJohn Baldwin 	for (func = bge_eaddr_funcs; *func != NULL; ++func) {
599238cc658fSJohn Baldwin 		if ((*func)(sc, eaddr) == 0)
599338cc658fSJohn Baldwin 			break;
599438cc658fSJohn Baldwin 	}
599538cc658fSJohn Baldwin 	return (*func == NULL ? ENXIO : 0);
599638cc658fSJohn Baldwin }
5997