if_re.c revision 231731
1251881Speter/*-
2251881Speter * Copyright (c) 1997, 1998-2003
3251881Speter *	Bill Paul <wpaul@windriver.com>.  All rights reserved.
4251881Speter *
5251881Speter * Redistribution and use in source and binary forms, with or without
6251881Speter * modification, are permitted provided that the following conditions
7251881Speter * are met:
8251881Speter * 1. Redistributions of source code must retain the above copyright
9251881Speter *    notice, this list of conditions and the following disclaimer.
10251881Speter * 2. Redistributions in binary form must reproduce the above copyright
11251881Speter *    notice, this list of conditions and the following disclaimer in the
12251881Speter *    documentation and/or other materials provided with the distribution.
13251881Speter * 3. All advertising materials mentioning features or use of this software
14251881Speter *    must display the following acknowledgement:
15251881Speter *	This product includes software developed by Bill Paul.
16251881Speter * 4. Neither the name of the author nor the names of any co-contributors
17251881Speter *    may be used to endorse or promote products derived from this software
18251881Speter *    without specific prior written permission.
19251881Speter *
20251881Speter * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
21251881Speter * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22251881Speter * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23251881Speter * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
24251881Speter * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25251881Speter * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26251881Speter * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27251881Speter * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28251881Speter * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29251881Speter * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
30251881Speter * THE POSSIBILITY OF SUCH DAMAGE.
31251881Speter */
32251881Speter
33251881Speter#include <sys/cdefs.h>
34251881Speter__FBSDID("$FreeBSD: stable/9/sys/dev/re/if_re.c 231731 2012-02-15 03:48:22Z yongari $");
35251881Speter
36251881Speter/*
37251881Speter * RealTek 8139C+/8169/8169S/8110S/8168/8111/8101E PCI NIC driver
38251881Speter *
39251881Speter * Written by Bill Paul <wpaul@windriver.com>
40251881Speter * Senior Networking Software Engineer
41251881Speter * Wind River Systems
42251881Speter */
43251881Speter
44251881Speter/*
45251881Speter * This driver is designed to support RealTek's next generation of
46251881Speter * 10/100 and 10/100/1000 PCI ethernet controllers. There are currently
47251881Speter * seven devices in this family: the RTL8139C+, the RTL8169, the RTL8169S,
48251881Speter * RTL8110S, the RTL8168, the RTL8111 and the RTL8101E.
49251881Speter *
50251881Speter * The 8139C+ is a 10/100 ethernet chip. It is backwards compatible
51251881Speter * with the older 8139 family, however it also supports a special
52251881Speter * C+ mode of operation that provides several new performance enhancing
53251881Speter * features. These include:
54251881Speter *
55251881Speter *	o Descriptor based DMA mechanism. Each descriptor represents
56251881Speter *	  a single packet fragment. Data buffers may be aligned on
57251881Speter *	  any byte boundary.
58251881Speter *
59251881Speter *	o 64-bit DMA
60251881Speter *
61251881Speter *	o TCP/IP checksum offload for both RX and TX
62251881Speter *
63251881Speter *	o High and normal priority transmit DMA rings
64251881Speter *
65251881Speter *	o VLAN tag insertion and extraction
66251881Speter *
67251881Speter *	o TCP large send (segmentation offload)
68251881Speter *
69251881Speter * Like the 8139, the 8139C+ also has a built-in 10/100 PHY. The C+
70251881Speter * programming API is fairly straightforward. The RX filtering, EEPROM
71251881Speter * access and PHY access is the same as it is on the older 8139 series
72251881Speter * chips.
73251881Speter *
74251881Speter * The 8169 is a 64-bit 10/100/1000 gigabit ethernet MAC. It has almost the
75251881Speter * same programming API and feature set as the 8139C+ with the following
76251881Speter * differences and additions:
77251881Speter *
78251881Speter *	o 1000Mbps mode
79251881Speter *
80251881Speter *	o Jumbo frames
81251881Speter *
82251881Speter *	o GMII and TBI ports/registers for interfacing with copper
83251881Speter *	  or fiber PHYs
84251881Speter *
85251881Speter *	o RX and TX DMA rings can have up to 1024 descriptors
86251881Speter *	  (the 8139C+ allows a maximum of 64)
87251881Speter *
88251881Speter *	o Slight differences in register layout from the 8139C+
89251881Speter *
90251881Speter * The TX start and timer interrupt registers are at different locations
91251881Speter * on the 8169 than they are on the 8139C+. Also, the status word in the
92251881Speter * RX descriptor has a slightly different bit layout. The 8169 does not
93251881Speter * have a built-in PHY. Most reference boards use a Marvell 88E1000 'Alaska'
94251881Speter * copper gigE PHY.
95251881Speter *
96251881Speter * The 8169S/8110S 10/100/1000 devices have built-in copper gigE PHYs
97251881Speter * (the 'S' stands for 'single-chip'). These devices have the same
98251881Speter * programming API as the older 8169, but also have some vendor-specific
99251881Speter * registers for the on-board PHY. The 8110S is a LAN-on-motherboard
100251881Speter * part designed to be pin-compatible with the RealTek 8100 10/100 chip.
101251881Speter *
102251881Speter * This driver takes advantage of the RX and TX checksum offload and
103251881Speter * VLAN tag insertion/extraction features. It also implements TX
104251881Speter * interrupt moderation using the timer interrupt registers, which
105251881Speter * significantly reduces TX interrupt load. There is also support
106251881Speter * for jumbo frames, however the 8169/8169S/8110S can not transmit
107251881Speter * jumbo frames larger than 7440, so the max MTU possible with this
108251881Speter * driver is 7422 bytes.
109251881Speter */
110251881Speter
111251881Speter#ifdef HAVE_KERNEL_OPTION_HEADERS
112251881Speter#include "opt_device_polling.h"
113251881Speter#endif
114251881Speter
115251881Speter#include <sys/param.h>
116251881Speter#include <sys/endian.h>
117251881Speter#include <sys/systm.h>
118251881Speter#include <sys/sockio.h>
119251881Speter#include <sys/mbuf.h>
120251881Speter#include <sys/malloc.h>
121251881Speter#include <sys/module.h>
122251881Speter#include <sys/kernel.h>
123251881Speter#include <sys/socket.h>
124251881Speter#include <sys/lock.h>
125251881Speter#include <sys/mutex.h>
126251881Speter#include <sys/sysctl.h>
127251881Speter#include <sys/taskqueue.h>
128251881Speter
129251881Speter#include <net/if.h>
130251881Speter#include <net/if_arp.h>
131251881Speter#include <net/ethernet.h>
132251881Speter#include <net/if_dl.h>
133251881Speter#include <net/if_media.h>
134251881Speter#include <net/if_types.h>
135251881Speter#include <net/if_vlan_var.h>
136251881Speter
137251881Speter#include <net/bpf.h>
138251881Speter
139251881Speter#include <machine/bus.h>
140251881Speter#include <machine/resource.h>
141251881Speter#include <sys/bus.h>
142251881Speter#include <sys/rman.h>
143251881Speter
144251881Speter#include <dev/mii/mii.h>
145251881Speter#include <dev/mii/miivar.h>
146251881Speter
147251881Speter#include <dev/pci/pcireg.h>
148251881Speter#include <dev/pci/pcivar.h>
149251881Speter
150251881Speter#include <pci/if_rlreg.h>
151251881Speter
152251881SpeterMODULE_DEPEND(re, pci, 1, 1, 1);
153251881SpeterMODULE_DEPEND(re, ether, 1, 1, 1);
154251881SpeterMODULE_DEPEND(re, miibus, 1, 1, 1);
155251881Speter
156251881Speter/* "device miibus" required.  See GENERIC if you get errors here. */
157251881Speter#include "miibus_if.h"
158251881Speter
159251881Speter/* Tunables. */
160251881Speterstatic int intr_filter = 0;
161251881SpeterTUNABLE_INT("hw.re.intr_filter", &intr_filter);
162251881Speterstatic int msi_disable = 0;
163251881SpeterTUNABLE_INT("hw.re.msi_disable", &msi_disable);
164251881Speterstatic int msix_disable = 0;
165251881SpeterTUNABLE_INT("hw.re.msix_disable", &msix_disable);
166251881Speterstatic int prefer_iomap = 0;
167251881SpeterTUNABLE_INT("hw.re.prefer_iomap", &prefer_iomap);
168251881Speter
169251881Speter#define RE_CSUM_FEATURES    (CSUM_IP | CSUM_TCP | CSUM_UDP)
170251881Speter
171251881Speter/*
172251881Speter * Various supported device vendors/types and their names.
173251881Speter */
174251881Speterstatic const struct rl_type const re_devs[] = {
175251881Speter	{ DLINK_VENDORID, DLINK_DEVICEID_528T, 0,
176251881Speter	    "D-Link DGE-528(T) Gigabit Ethernet Adapter" },
177251881Speter	{ DLINK_VENDORID, DLINK_DEVICEID_530T_REVC, 0,
178251881Speter	    "D-Link DGE-530(T) Gigabit Ethernet Adapter" },
179251881Speter	{ RT_VENDORID, RT_DEVICEID_8139, 0,
180251881Speter	    "RealTek 8139C+ 10/100BaseTX" },
181251881Speter	{ RT_VENDORID, RT_DEVICEID_8101E, 0,
182251881Speter	    "RealTek 810xE PCIe 10/100baseTX" },
183251881Speter	{ RT_VENDORID, RT_DEVICEID_8168, 0,
184251881Speter	    "RealTek 8168/8111 B/C/CP/D/DP/E/F PCIe Gigabit Ethernet" },
185251881Speter	{ RT_VENDORID, RT_DEVICEID_8169, 0,
186251881Speter	    "RealTek 8169/8169S/8169SB(L)/8110S/8110SB(L) Gigabit Ethernet" },
187251881Speter	{ RT_VENDORID, RT_DEVICEID_8169SC, 0,
188251881Speter	    "RealTek 8169SC/8110SC Single-chip Gigabit Ethernet" },
189251881Speter	{ COREGA_VENDORID, COREGA_DEVICEID_CGLAPCIGT, 0,
190251881Speter	    "Corega CG-LAPCIGT (RTL8169S) Gigabit Ethernet" },
191251881Speter	{ LINKSYS_VENDORID, LINKSYS_DEVICEID_EG1032, 0,
192251881Speter	    "Linksys EG1032 (RTL8169S) Gigabit Ethernet" },
193251881Speter	{ USR_VENDORID, USR_DEVICEID_997902, 0,
194251881Speter	    "US Robotics 997902 (RTL8169S) Gigabit Ethernet" }
195251881Speter};
196251881Speter
197251881Speterstatic const struct rl_hwrev const re_hwrevs[] = {
198251881Speter	{ RL_HWREV_8139, RL_8139, "", RL_MTU },
199251881Speter	{ RL_HWREV_8139A, RL_8139, "A", RL_MTU },
200251881Speter	{ RL_HWREV_8139AG, RL_8139, "A-G", RL_MTU },
201251881Speter	{ RL_HWREV_8139B, RL_8139, "B", RL_MTU },
202251881Speter	{ RL_HWREV_8130, RL_8139, "8130", RL_MTU },
203251881Speter	{ RL_HWREV_8139C, RL_8139, "C", RL_MTU },
204251881Speter	{ RL_HWREV_8139D, RL_8139, "8139D/8100B/8100C", RL_MTU },
205251881Speter	{ RL_HWREV_8139CPLUS, RL_8139CPLUS, "C+", RL_MTU },
206251881Speter	{ RL_HWREV_8168B_SPIN1, RL_8169, "8168", RL_JUMBO_MTU },
207251881Speter	{ RL_HWREV_8169, RL_8169, "8169", RL_JUMBO_MTU },
208251881Speter	{ RL_HWREV_8169S, RL_8169, "8169S", RL_JUMBO_MTU },
209251881Speter	{ RL_HWREV_8110S, RL_8169, "8110S", RL_JUMBO_MTU },
210251881Speter	{ RL_HWREV_8169_8110SB, RL_8169, "8169SB/8110SB", RL_JUMBO_MTU },
211251881Speter	{ RL_HWREV_8169_8110SC, RL_8169, "8169SC/8110SC", RL_JUMBO_MTU },
212251881Speter	{ RL_HWREV_8169_8110SBL, RL_8169, "8169SBL/8110SBL", RL_JUMBO_MTU },
213251881Speter	{ RL_HWREV_8169_8110SCE, RL_8169, "8169SC/8110SC", RL_JUMBO_MTU },
214251881Speter	{ RL_HWREV_8100, RL_8139, "8100", RL_MTU },
215251881Speter	{ RL_HWREV_8101, RL_8139, "8101", RL_MTU },
216251881Speter	{ RL_HWREV_8100E, RL_8169, "8100E", RL_MTU },
217251881Speter	{ RL_HWREV_8101E, RL_8169, "8101E", RL_MTU },
218251881Speter	{ RL_HWREV_8102E, RL_8169, "8102E", RL_MTU },
219251881Speter	{ RL_HWREV_8102EL, RL_8169, "8102EL", RL_MTU },
220251881Speter	{ RL_HWREV_8102EL_SPIN1, RL_8169, "8102EL", RL_MTU },
221251881Speter	{ RL_HWREV_8103E, RL_8169, "8103E", RL_MTU },
222251881Speter	{ RL_HWREV_8401E, RL_8169, "8401E", RL_MTU },
223251881Speter	{ RL_HWREV_8402, RL_8169, "8402", RL_MTU },
224251881Speter	{ RL_HWREV_8105E, RL_8169, "8105E", RL_MTU },
225251881Speter	{ RL_HWREV_8105E_SPIN1, RL_8169, "8105E", RL_MTU },
226251881Speter	{ RL_HWREV_8168B_SPIN2, RL_8169, "8168", RL_JUMBO_MTU },
227251881Speter	{ RL_HWREV_8168B_SPIN3, RL_8169, "8168", RL_JUMBO_MTU },
228251881Speter	{ RL_HWREV_8168C, RL_8169, "8168C/8111C", RL_JUMBO_MTU_6K },
229251881Speter	{ RL_HWREV_8168C_SPIN2, RL_8169, "8168C/8111C", RL_JUMBO_MTU_6K },
230251881Speter	{ RL_HWREV_8168CP, RL_8169, "8168CP/8111CP", RL_JUMBO_MTU_6K },
231251881Speter	{ RL_HWREV_8168D, RL_8169, "8168D/8111D", RL_JUMBO_MTU_9K },
232251881Speter	{ RL_HWREV_8168DP, RL_8169, "8168DP/8111DP", RL_JUMBO_MTU_9K },
233251881Speter	{ RL_HWREV_8168E, RL_8169, "8168E/8111E", RL_JUMBO_MTU_9K},
234251881Speter	{ RL_HWREV_8168E_VL, RL_8169, "8168E/8111E-VL", RL_JUMBO_MTU_6K},
235251881Speter	{ RL_HWREV_8168F, RL_8169, "8168F/8111F", RL_JUMBO_MTU_9K},
236251881Speter	{ RL_HWREV_8411, RL_8169, "8411", RL_JUMBO_MTU_9K},
237251881Speter	{ 0, 0, NULL, 0 }
238251881Speter};
239251881Speter
240251881Speterstatic int re_probe		(device_t);
241251881Speterstatic int re_attach		(device_t);
242251881Speterstatic int re_detach		(device_t);
243251881Speter
244251881Speterstatic int re_encap		(struct rl_softc *, struct mbuf **);
245251881Speter
246251881Speterstatic void re_dma_map_addr	(void *, bus_dma_segment_t *, int, int);
247251881Speterstatic int re_allocmem		(device_t, struct rl_softc *);
248251881Speterstatic __inline void re_discard_rxbuf
249251881Speter				(struct rl_softc *, int);
250251881Speterstatic int re_newbuf		(struct rl_softc *, int);
251251881Speterstatic int re_jumbo_newbuf	(struct rl_softc *, int);
252251881Speterstatic int re_rx_list_init	(struct rl_softc *);
253251881Speterstatic int re_jrx_list_init	(struct rl_softc *);
254251881Speterstatic int re_tx_list_init	(struct rl_softc *);
255251881Speter#ifdef RE_FIXUP_RX
256251881Speterstatic __inline void re_fixup_rx
257251881Speter				(struct mbuf *);
258251881Speter#endif
259251881Speterstatic int re_rxeof		(struct rl_softc *, int *);
260251881Speterstatic void re_txeof		(struct rl_softc *);
261251881Speter#ifdef DEVICE_POLLING
262251881Speterstatic int re_poll		(struct ifnet *, enum poll_cmd, int);
263251881Speterstatic int re_poll_locked	(struct ifnet *, enum poll_cmd, int);
264251881Speter#endif
265251881Speterstatic int re_intr		(void *);
266251881Speterstatic void re_intr_msi		(void *);
267251881Speterstatic void re_tick		(void *);
268251881Speterstatic void re_int_task		(void *, int);
269251881Speterstatic void re_start		(struct ifnet *);
270251881Speterstatic void re_start_locked	(struct ifnet *);
271251881Speterstatic int re_ioctl		(struct ifnet *, u_long, caddr_t);
272251881Speterstatic void re_init		(void *);
273251881Speterstatic void re_init_locked	(struct rl_softc *);
274251881Speterstatic void re_stop		(struct rl_softc *);
275251881Speterstatic void re_watchdog		(struct rl_softc *);
276251881Speterstatic int re_suspend		(device_t);
277251881Speterstatic int re_resume		(device_t);
278251881Speterstatic int re_shutdown		(device_t);
279251881Speterstatic int re_ifmedia_upd	(struct ifnet *);
280251881Speterstatic void re_ifmedia_sts	(struct ifnet *, struct ifmediareq *);
281251881Speter
282251881Speterstatic void re_eeprom_putbyte	(struct rl_softc *, int);
283251881Speterstatic void re_eeprom_getword	(struct rl_softc *, int, u_int16_t *);
284251881Speterstatic void re_read_eeprom	(struct rl_softc *, caddr_t, int, int);
285251881Speterstatic int re_gmii_readreg	(device_t, int, int);
286251881Speterstatic int re_gmii_writereg	(device_t, int, int, int);
287251881Speter
288251881Speterstatic int re_miibus_readreg	(device_t, int, int);
289251881Speterstatic int re_miibus_writereg	(device_t, int, int, int);
290251881Speterstatic void re_miibus_statchg	(device_t);
291251881Speter
292251881Speterstatic void re_set_jumbo	(struct rl_softc *, int);
293251881Speterstatic void re_set_rxmode		(struct rl_softc *);
294251881Speterstatic void re_reset		(struct rl_softc *);
295251881Speterstatic void re_setwol		(struct rl_softc *);
296251881Speterstatic void re_clrwol		(struct rl_softc *);
297251881Speterstatic void re_set_linkspeed	(struct rl_softc *);
298251881Speter
299251881Speter#ifdef RE_DIAG
300251881Speterstatic int re_diag		(struct rl_softc *);
301251881Speter#endif
302251881Speter
303251881Speterstatic void re_add_sysctls	(struct rl_softc *);
304251881Speterstatic int re_sysctl_stats	(SYSCTL_HANDLER_ARGS);
305251881Speterstatic int sysctl_int_range	(SYSCTL_HANDLER_ARGS, int, int);
306251881Speterstatic int sysctl_hw_re_int_mod	(SYSCTL_HANDLER_ARGS);
307251881Speter
308251881Speterstatic device_method_t re_methods[] = {
309251881Speter	/* Device interface */
310251881Speter	DEVMETHOD(device_probe,		re_probe),
311251881Speter	DEVMETHOD(device_attach,	re_attach),
312251881Speter	DEVMETHOD(device_detach,	re_detach),
313251881Speter	DEVMETHOD(device_suspend,	re_suspend),
314251881Speter	DEVMETHOD(device_resume,	re_resume),
315251881Speter	DEVMETHOD(device_shutdown,	re_shutdown),
316251881Speter
317251881Speter	/* MII interface */
318251881Speter	DEVMETHOD(miibus_readreg,	re_miibus_readreg),
319251881Speter	DEVMETHOD(miibus_writereg,	re_miibus_writereg),
320251881Speter	DEVMETHOD(miibus_statchg,	re_miibus_statchg),
321251881Speter
322251881Speter	DEVMETHOD_END
323251881Speter};
324251881Speter
325251881Speterstatic driver_t re_driver = {
326251881Speter	"re",
327251881Speter	re_methods,
328251881Speter	sizeof(struct rl_softc)
329251881Speter};
330251881Speter
331251881Speterstatic devclass_t re_devclass;
332251881Speter
333251881SpeterDRIVER_MODULE(re, pci, re_driver, re_devclass, 0, 0);
334251881SpeterDRIVER_MODULE(miibus, re, miibus_driver, miibus_devclass, 0, 0);
335251881Speter
336251881Speter#define EE_SET(x)					\
337251881Speter	CSR_WRITE_1(sc, RL_EECMD,			\
338251881Speter		CSR_READ_1(sc, RL_EECMD) | x)
339251881Speter
340251881Speter#define EE_CLR(x)					\
341251881Speter	CSR_WRITE_1(sc, RL_EECMD,			\
342251881Speter		CSR_READ_1(sc, RL_EECMD) & ~x)
343251881Speter
344251881Speter/*
345251881Speter * Send a read command and address to the EEPROM, check for ACK.
346251881Speter */
347251881Speterstatic void
348251881Speterre_eeprom_putbyte(struct rl_softc *sc, int addr)
349251881Speter{
350251881Speter	int			d, i;
351251881Speter
352251881Speter	d = addr | (RL_9346_READ << sc->rl_eewidth);
353251881Speter
354251881Speter	/*
355251881Speter	 * Feed in each bit and strobe the clock.
356251881Speter	 */
357251881Speter
358251881Speter	for (i = 1 << (sc->rl_eewidth + 3); i; i >>= 1) {
359251881Speter		if (d & i) {
360251881Speter			EE_SET(RL_EE_DATAIN);
361251881Speter		} else {
362251881Speter			EE_CLR(RL_EE_DATAIN);
363251881Speter		}
364251881Speter		DELAY(100);
365251881Speter		EE_SET(RL_EE_CLK);
366251881Speter		DELAY(150);
367251881Speter		EE_CLR(RL_EE_CLK);
368251881Speter		DELAY(100);
369251881Speter	}
370251881Speter}
371251881Speter
372251881Speter/*
373251881Speter * Read a word of data stored in the EEPROM at address 'addr.'
374251881Speter */
375251881Speterstatic void
376251881Speterre_eeprom_getword(struct rl_softc *sc, int addr, u_int16_t *dest)
377251881Speter{
378251881Speter	int			i;
379251881Speter	u_int16_t		word = 0;
380251881Speter
381251881Speter	/*
382251881Speter	 * Send address of word we want to read.
383251881Speter	 */
384251881Speter	re_eeprom_putbyte(sc, addr);
385251881Speter
386251881Speter	/*
387251881Speter	 * Start reading bits from EEPROM.
388251881Speter	 */
389251881Speter	for (i = 0x8000; i; i >>= 1) {
390251881Speter		EE_SET(RL_EE_CLK);
391251881Speter		DELAY(100);
392251881Speter		if (CSR_READ_1(sc, RL_EECMD) & RL_EE_DATAOUT)
393251881Speter			word |= i;
394251881Speter		EE_CLR(RL_EE_CLK);
395251881Speter		DELAY(100);
396251881Speter	}
397251881Speter
398251881Speter	*dest = word;
399251881Speter}
400251881Speter
401251881Speter/*
402251881Speter * Read a sequence of words from the EEPROM.
403251881Speter */
404251881Speterstatic void
405251881Speterre_read_eeprom(struct rl_softc *sc, caddr_t dest, int off, int cnt)
406251881Speter{
407251881Speter	int			i;
408251881Speter	u_int16_t		word = 0, *ptr;
409251881Speter
410251881Speter	CSR_SETBIT_1(sc, RL_EECMD, RL_EEMODE_PROGRAM);
411251881Speter
412251881Speter        DELAY(100);
413251881Speter
414251881Speter	for (i = 0; i < cnt; i++) {
415251881Speter		CSR_SETBIT_1(sc, RL_EECMD, RL_EE_SEL);
416251881Speter		re_eeprom_getword(sc, off + i, &word);
417251881Speter		CSR_CLRBIT_1(sc, RL_EECMD, RL_EE_SEL);
418251881Speter		ptr = (u_int16_t *)(dest + (i * 2));
419251881Speter                *ptr = word;
420251881Speter	}
421251881Speter
422251881Speter	CSR_CLRBIT_1(sc, RL_EECMD, RL_EEMODE_PROGRAM);
423251881Speter}
424251881Speter
425251881Speterstatic int
426251881Speterre_gmii_readreg(device_t dev, int phy, int reg)
427251881Speter{
428251881Speter	struct rl_softc		*sc;
429251881Speter	u_int32_t		rval;
430251881Speter	int			i;
431251881Speter
432251881Speter	sc = device_get_softc(dev);
433251881Speter
434251881Speter	/* Let the rgephy driver read the GMEDIASTAT register */
435251881Speter
436251881Speter	if (reg == RL_GMEDIASTAT) {
437251881Speter		rval = CSR_READ_1(sc, RL_GMEDIASTAT);
438251881Speter		return (rval);
439251881Speter	}
440251881Speter
441251881Speter	CSR_WRITE_4(sc, RL_PHYAR, reg << 16);
442251881Speter
443251881Speter	for (i = 0; i < RL_PHY_TIMEOUT; i++) {
444251881Speter		rval = CSR_READ_4(sc, RL_PHYAR);
445251881Speter		if (rval & RL_PHYAR_BUSY)
446251881Speter			break;
447251881Speter		DELAY(25);
448251881Speter	}
449251881Speter
450251881Speter	if (i == RL_PHY_TIMEOUT) {
451251881Speter		device_printf(sc->rl_dev, "PHY read failed\n");
452251881Speter		return (0);
453251881Speter	}
454251881Speter
455251881Speter	/*
456251881Speter	 * Controller requires a 20us delay to process next MDIO request.
457251881Speter	 */
458251881Speter	DELAY(20);
459251881Speter
460251881Speter	return (rval & RL_PHYAR_PHYDATA);
461251881Speter}
462251881Speter
463251881Speterstatic int
464251881Speterre_gmii_writereg(device_t dev, int phy, int reg, int data)
465251881Speter{
466251881Speter	struct rl_softc		*sc;
467251881Speter	u_int32_t		rval;
468251881Speter	int			i;
469251881Speter
470251881Speter	sc = device_get_softc(dev);
471251881Speter
472251881Speter	CSR_WRITE_4(sc, RL_PHYAR, (reg << 16) |
473251881Speter	    (data & RL_PHYAR_PHYDATA) | RL_PHYAR_BUSY);
474251881Speter
475251881Speter	for (i = 0; i < RL_PHY_TIMEOUT; i++) {
476251881Speter		rval = CSR_READ_4(sc, RL_PHYAR);
477251881Speter		if (!(rval & RL_PHYAR_BUSY))
478251881Speter			break;
479251881Speter		DELAY(25);
480251881Speter	}
481251881Speter
482251881Speter	if (i == RL_PHY_TIMEOUT) {
483251881Speter		device_printf(sc->rl_dev, "PHY write failed\n");
484251881Speter		return (0);
485251881Speter	}
486251881Speter
487251881Speter	/*
488251881Speter	 * Controller requires a 20us delay to process next MDIO request.
489251881Speter	 */
490251881Speter	DELAY(20);
491251881Speter
492251881Speter	return (0);
493251881Speter}
494251881Speter
495251881Speterstatic int
496251881Speterre_miibus_readreg(device_t dev, int phy, int reg)
497251881Speter{
498251881Speter	struct rl_softc		*sc;
499251881Speter	u_int16_t		rval = 0;
500251881Speter	u_int16_t		re8139_reg = 0;
501251881Speter
502251881Speter	sc = device_get_softc(dev);
503251881Speter
504251881Speter	if (sc->rl_type == RL_8169) {
505251881Speter		rval = re_gmii_readreg(dev, phy, reg);
506251881Speter		return (rval);
507251881Speter	}
508251881Speter
509251881Speter	switch (reg) {
510251881Speter	case MII_BMCR:
511251881Speter		re8139_reg = RL_BMCR;
512251881Speter		break;
513251881Speter	case MII_BMSR:
514251881Speter		re8139_reg = RL_BMSR;
515251881Speter		break;
516251881Speter	case MII_ANAR:
517251881Speter		re8139_reg = RL_ANAR;
518251881Speter		break;
519251881Speter	case MII_ANER:
520251881Speter		re8139_reg = RL_ANER;
521251881Speter		break;
522251881Speter	case MII_ANLPAR:
523251881Speter		re8139_reg = RL_LPAR;
524251881Speter		break;
525251881Speter	case MII_PHYIDR1:
526251881Speter	case MII_PHYIDR2:
527251881Speter		return (0);
528251881Speter	/*
529251881Speter	 * Allow the rlphy driver to read the media status
530251881Speter	 * register. If we have a link partner which does not
531251881Speter	 * support NWAY, this is the register which will tell
532251881Speter	 * us the results of parallel detection.
533251881Speter	 */
534251881Speter	case RL_MEDIASTAT:
535251881Speter		rval = CSR_READ_1(sc, RL_MEDIASTAT);
536251881Speter		return (rval);
537251881Speter	default:
538251881Speter		device_printf(sc->rl_dev, "bad phy register\n");
539251881Speter		return (0);
540251881Speter	}
541251881Speter	rval = CSR_READ_2(sc, re8139_reg);
542251881Speter	if (sc->rl_type == RL_8139CPLUS && re8139_reg == RL_BMCR) {
543251881Speter		/* 8139C+ has different bit layout. */
544251881Speter		rval &= ~(BMCR_LOOP | BMCR_ISO);
545251881Speter	}
546251881Speter	return (rval);
547251881Speter}
548251881Speter
549251881Speterstatic int
550251881Speterre_miibus_writereg(device_t dev, int phy, int reg, int data)
551251881Speter{
552251881Speter	struct rl_softc		*sc;
553251881Speter	u_int16_t		re8139_reg = 0;
554251881Speter	int			rval = 0;
555251881Speter
556251881Speter	sc = device_get_softc(dev);
557251881Speter
558251881Speter	if (sc->rl_type == RL_8169) {
559251881Speter		rval = re_gmii_writereg(dev, phy, reg, data);
560251881Speter		return (rval);
561251881Speter	}
562251881Speter
563251881Speter	switch (reg) {
564251881Speter	case MII_BMCR:
565251881Speter		re8139_reg = RL_BMCR;
566251881Speter		if (sc->rl_type == RL_8139CPLUS) {
567251881Speter			/* 8139C+ has different bit layout. */
568251881Speter			data &= ~(BMCR_LOOP | BMCR_ISO);
569251881Speter		}
570251881Speter		break;
571251881Speter	case MII_BMSR:
572251881Speter		re8139_reg = RL_BMSR;
573251881Speter		break;
574251881Speter	case MII_ANAR:
575251881Speter		re8139_reg = RL_ANAR;
576251881Speter		break;
577251881Speter	case MII_ANER:
578251881Speter		re8139_reg = RL_ANER;
579251881Speter		break;
580251881Speter	case MII_ANLPAR:
581251881Speter		re8139_reg = RL_LPAR;
582251881Speter		break;
583251881Speter	case MII_PHYIDR1:
584251881Speter	case MII_PHYIDR2:
585251881Speter		return (0);
586251881Speter		break;
587251881Speter	default:
588251881Speter		device_printf(sc->rl_dev, "bad phy register\n");
589251881Speter		return (0);
590251881Speter	}
591251881Speter	CSR_WRITE_2(sc, re8139_reg, data);
592251881Speter	return (0);
593251881Speter}
594251881Speter
595251881Speterstatic void
596251881Speterre_miibus_statchg(device_t dev)
597251881Speter{
598251881Speter	struct rl_softc		*sc;
599251881Speter	struct ifnet		*ifp;
600251881Speter	struct mii_data		*mii;
601251881Speter
602251881Speter	sc = device_get_softc(dev);
603251881Speter	mii = device_get_softc(sc->rl_miibus);
604251881Speter	ifp = sc->rl_ifp;
605251881Speter	if (mii == NULL || ifp == NULL ||
606251881Speter	    (ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
607251881Speter		return;
608251881Speter
609251881Speter	sc->rl_flags &= ~RL_FLAG_LINK;
610251881Speter	if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) ==
611251881Speter	    (IFM_ACTIVE | IFM_AVALID)) {
612251881Speter		switch (IFM_SUBTYPE(mii->mii_media_active)) {
613251881Speter		case IFM_10_T:
614251881Speter		case IFM_100_TX:
615251881Speter			sc->rl_flags |= RL_FLAG_LINK;
616251881Speter			break;
617251881Speter		case IFM_1000_T:
618251881Speter			if ((sc->rl_flags & RL_FLAG_FASTETHER) != 0)
619251881Speter				break;
620251881Speter			sc->rl_flags |= RL_FLAG_LINK;
621251881Speter			break;
622251881Speter		default:
623251881Speter			break;
624251881Speter		}
625251881Speter	}
626251881Speter	/*
627251881Speter	 * RealTek controllers does not provide any interface to
628251881Speter	 * Tx/Rx MACs for resolved speed, duplex and flow-control
629251881Speter	 * parameters.
630269847Speter	 */
631269847Speter}
632269847Speter
633269847Speter/*
634251881Speter * Set the RX configuration and 64-bit multicast hash filter.
635251881Speter */
636251881Speterstatic void
637251881Speterre_set_rxmode(struct rl_softc *sc)
638251881Speter{
639251881Speter	struct ifnet		*ifp;
640251881Speter	struct ifmultiaddr	*ifma;
641251881Speter	uint32_t		hashes[2] = { 0, 0 };
642269847Speter	uint32_t		h, rxfilt;
643269847Speter
644269847Speter	RL_LOCK_ASSERT(sc);
645269847Speter
646251881Speter	ifp = sc->rl_ifp;
647251881Speter
648269847Speter	rxfilt = RL_RXCFG_CONFIG | RL_RXCFG_RX_INDIV | RL_RXCFG_RX_BROAD;
649251881Speter
650251881Speter	if (ifp->if_flags & (IFF_ALLMULTI | IFF_PROMISC)) {
651269847Speter		if (ifp->if_flags & IFF_PROMISC)
652251881Speter			rxfilt |= RL_RXCFG_RX_ALLPHYS;
653269847Speter		/*
654269847Speter		 * Unlike other hardwares, we have to explicitly set
655269847Speter		 * RL_RXCFG_RX_MULTI to receive multicast frames in
656269847Speter		 * promiscuous mode.
657269847Speter		 */
658269847Speter		rxfilt |= RL_RXCFG_RX_MULTI;
659269847Speter		hashes[0] = hashes[1] = 0xffffffff;
660269847Speter		goto done;
661269847Speter	}
662269847Speter
663269847Speter	if_maddr_rlock(ifp);
664269847Speter	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
665269847Speter		if (ifma->ifma_addr->sa_family != AF_LINK)
666269847Speter			continue;
667269847Speter		h = ether_crc32_be(LLADDR((struct sockaddr_dl *)
668269847Speter		    ifma->ifma_addr), ETHER_ADDR_LEN) >> 26;
669269847Speter		if (h < 32)
670269847Speter			hashes[0] |= (1 << h);
671269847Speter		else
672269847Speter			hashes[1] |= (1 << (h - 32));
673269847Speter	}
674269847Speter	if_maddr_runlock(ifp);
675269847Speter
676269847Speter	if (hashes[0] != 0 || hashes[1] != 0) {
677269847Speter		/*
678269847Speter		 * For some unfathomable reason, RealTek decided to
679269847Speter		 * reverse the order of the multicast hash registers
680269847Speter		 * in the PCI Express parts.  This means we have to
681269847Speter		 * write the hash pattern in reverse order for those
682269847Speter		 * devices.
683269847Speter		 */
684269847Speter		if ((sc->rl_flags & RL_FLAG_PCIE) != 0) {
685269847Speter			h = bswap32(hashes[0]);
686269847Speter			hashes[0] = bswap32(hashes[1]);
687269847Speter			hashes[1] = h;
688269847Speter		}
689269847Speter		rxfilt |= RL_RXCFG_RX_MULTI;
690269847Speter	}
691269847Speter
692269847Speterdone:
693269847Speter	CSR_WRITE_4(sc, RL_MAR0, hashes[0]);
694269847Speter	CSR_WRITE_4(sc, RL_MAR4, hashes[1]);
695269847Speter	CSR_WRITE_4(sc, RL_RXCFG, rxfilt);
696251881Speter}
697251881Speter
698251881Speterstatic void
699251881Speterre_reset(struct rl_softc *sc)
700251881Speter{
701251881Speter	int			i;
702251881Speter
703251881Speter	RL_LOCK_ASSERT(sc);
704251881Speter
705251881Speter	CSR_WRITE_1(sc, RL_COMMAND, RL_CMD_RESET);
706251881Speter
707251881Speter	for (i = 0; i < RL_TIMEOUT; i++) {
708251881Speter		DELAY(10);
709251881Speter		if (!(CSR_READ_1(sc, RL_COMMAND) & RL_CMD_RESET))
710251881Speter			break;
711251881Speter	}
712251881Speter	if (i == RL_TIMEOUT)
713251881Speter		device_printf(sc->rl_dev, "reset never completed!\n");
714251881Speter
715251881Speter	if ((sc->rl_flags & RL_FLAG_MACRESET) != 0)
716251881Speter		CSR_WRITE_1(sc, 0x82, 1);
717251881Speter	if (sc->rl_hwrev->rl_rev == RL_HWREV_8169S)
718251881Speter		re_gmii_writereg(sc->rl_dev, 1, 0x0b, 0);
719251881Speter}
720251881Speter
721251881Speter#ifdef RE_DIAG
722251881Speter
723251881Speter/*
724251881Speter * The following routine is designed to test for a defect on some
725251881Speter * 32-bit 8169 cards. Some of these NICs have the REQ64# and ACK64#
726251881Speter * lines connected to the bus, however for a 32-bit only card, they
727251881Speter * should be pulled high. The result of this defect is that the
728251881Speter * NIC will not work right if you plug it into a 64-bit slot: DMA
729251881Speter * operations will be done with 64-bit transfers, which will fail
730251881Speter * because the 64-bit data lines aren't connected.
731251881Speter *
732251881Speter * There's no way to work around this (short of talking a soldering
733251881Speter * iron to the board), however we can detect it. The method we use
734251881Speter * here is to put the NIC into digital loopback mode, set the receiver
735251881Speter * to promiscuous mode, and then try to send a frame. We then compare
736251881Speter * the frame data we sent to what was received. If the data matches,
737251881Speter * then the NIC is working correctly, otherwise we know the user has
738251881Speter * a defective NIC which has been mistakenly plugged into a 64-bit PCI
739251881Speter * slot. In the latter case, there's no way the NIC can work correctly,
740251881Speter * so we print out a message on the console and abort the device attach.
741251881Speter */
742251881Speter
743251881Speterstatic int
744251881Speterre_diag(struct rl_softc *sc)
745251881Speter{
746251881Speter	struct ifnet		*ifp = sc->rl_ifp;
747251881Speter	struct mbuf		*m0;
748251881Speter	struct ether_header	*eh;
749251881Speter	struct rl_desc		*cur_rx;
750251881Speter	u_int16_t		status;
751251881Speter	u_int32_t		rxstat;
752251881Speter	int			total_len, i, error = 0, phyaddr;
753251881Speter	u_int8_t		dst[] = { 0x00, 'h', 'e', 'l', 'l', 'o' };
754251881Speter	u_int8_t		src[] = { 0x00, 'w', 'o', 'r', 'l', 'd' };
755251881Speter
756251881Speter	/* Allocate a single mbuf */
757251881Speter	MGETHDR(m0, M_DONTWAIT, MT_DATA);
758251881Speter	if (m0 == NULL)
759251881Speter		return (ENOBUFS);
760251881Speter
761251881Speter	RL_LOCK(sc);
762251881Speter
763251881Speter	/*
764251881Speter	 * Initialize the NIC in test mode. This sets the chip up
765251881Speter	 * so that it can send and receive frames, but performs the
766251881Speter	 * following special functions:
767251881Speter	 * - Puts receiver in promiscuous mode
768251881Speter	 * - Enables digital loopback mode
769251881Speter	 * - Leaves interrupts turned off
770251881Speter	 */
771251881Speter
772251881Speter	ifp->if_flags |= IFF_PROMISC;
773251881Speter	sc->rl_testmode = 1;
774251881Speter	ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
775251881Speter	re_init_locked(sc);
776251881Speter	sc->rl_flags |= RL_FLAG_LINK;
777251881Speter	if (sc->rl_type == RL_8169)
778251881Speter		phyaddr = 1;
779251881Speter	else
780251881Speter		phyaddr = 0;
781251881Speter
782251881Speter	re_miibus_writereg(sc->rl_dev, phyaddr, MII_BMCR, BMCR_RESET);
783251881Speter	for (i = 0; i < RL_TIMEOUT; i++) {
784251881Speter		status = re_miibus_readreg(sc->rl_dev, phyaddr, MII_BMCR);
785251881Speter		if (!(status & BMCR_RESET))
786251881Speter			break;
787251881Speter	}
788251881Speter
789251881Speter	re_miibus_writereg(sc->rl_dev, phyaddr, MII_BMCR, BMCR_LOOP);
790251881Speter	CSR_WRITE_2(sc, RL_ISR, RL_INTRS);
791251881Speter
792251881Speter	DELAY(100000);
793251881Speter
794251881Speter	/* Put some data in the mbuf */
795251881Speter
796251881Speter	eh = mtod(m0, struct ether_header *);
797251881Speter	bcopy ((char *)&dst, eh->ether_dhost, ETHER_ADDR_LEN);
798251881Speter	bcopy ((char *)&src, eh->ether_shost, ETHER_ADDR_LEN);
799251881Speter	eh->ether_type = htons(ETHERTYPE_IP);
800251881Speter	m0->m_pkthdr.len = m0->m_len = ETHER_MIN_LEN - ETHER_CRC_LEN;
801251881Speter
802251881Speter	/*
803251881Speter	 * Queue the packet, start transmission.
804251881Speter	 * Note: IF_HANDOFF() ultimately calls re_start() for us.
805251881Speter	 */
806251881Speter
807251881Speter	CSR_WRITE_2(sc, RL_ISR, 0xFFFF);
808251881Speter	RL_UNLOCK(sc);
809251881Speter	/* XXX: re_diag must not be called when in ALTQ mode */
810251881Speter	IF_HANDOFF(&ifp->if_snd, m0, ifp);
811251881Speter	RL_LOCK(sc);
812251881Speter	m0 = NULL;
813251881Speter
814251881Speter	/* Wait for it to propagate through the chip */
815251881Speter
816251881Speter	DELAY(100000);
817251881Speter	for (i = 0; i < RL_TIMEOUT; i++) {
818251881Speter		status = CSR_READ_2(sc, RL_ISR);
819251881Speter		CSR_WRITE_2(sc, RL_ISR, status);
820251881Speter		if ((status & (RL_ISR_TIMEOUT_EXPIRED|RL_ISR_RX_OK)) ==
821251881Speter		    (RL_ISR_TIMEOUT_EXPIRED|RL_ISR_RX_OK))
822251881Speter			break;
823251881Speter		DELAY(10);
824251881Speter	}
825251881Speter
826251881Speter	if (i == RL_TIMEOUT) {
827251881Speter		device_printf(sc->rl_dev,
828251881Speter		    "diagnostic failed, failed to receive packet in"
829251881Speter		    " loopback mode\n");
830251881Speter		error = EIO;
831251881Speter		goto done;
832251881Speter	}
833251881Speter
834251881Speter	/*
835251881Speter	 * The packet should have been dumped into the first
836251881Speter	 * entry in the RX DMA ring. Grab it from there.
837251881Speter	 */
838251881Speter
839251881Speter	bus_dmamap_sync(sc->rl_ldata.rl_rx_list_tag,
840251881Speter	    sc->rl_ldata.rl_rx_list_map,
841251881Speter	    BUS_DMASYNC_POSTREAD);
842251881Speter	bus_dmamap_sync(sc->rl_ldata.rl_rx_mtag,
843251881Speter	    sc->rl_ldata.rl_rx_desc[0].rx_dmamap,
844251881Speter	    BUS_DMASYNC_POSTREAD);
845251881Speter	bus_dmamap_unload(sc->rl_ldata.rl_rx_mtag,
846251881Speter	    sc->rl_ldata.rl_rx_desc[0].rx_dmamap);
847251881Speter
848251881Speter	m0 = sc->rl_ldata.rl_rx_desc[0].rx_m;
849251881Speter	sc->rl_ldata.rl_rx_desc[0].rx_m = NULL;
850251881Speter	eh = mtod(m0, struct ether_header *);
851251881Speter
852251881Speter	cur_rx = &sc->rl_ldata.rl_rx_list[0];
853251881Speter	total_len = RL_RXBYTES(cur_rx);
854251881Speter	rxstat = le32toh(cur_rx->rl_cmdstat);
855251881Speter
856251881Speter	if (total_len != ETHER_MIN_LEN) {
857251881Speter		device_printf(sc->rl_dev,
858251881Speter		    "diagnostic failed, received short packet\n");
859251881Speter		error = EIO;
860251881Speter		goto done;
861251881Speter	}
862251881Speter
863251881Speter	/* Test that the received packet data matches what we sent. */
864251881Speter
865251881Speter	if (bcmp((char *)&eh->ether_dhost, (char *)&dst, ETHER_ADDR_LEN) ||
866251881Speter	    bcmp((char *)&eh->ether_shost, (char *)&src, ETHER_ADDR_LEN) ||
867251881Speter	    ntohs(eh->ether_type) != ETHERTYPE_IP) {
868251881Speter		device_printf(sc->rl_dev, "WARNING, DMA FAILURE!\n");
869251881Speter		device_printf(sc->rl_dev, "expected TX data: %6D/%6D/0x%x\n",
870251881Speter		    dst, ":", src, ":", ETHERTYPE_IP);
871251881Speter		device_printf(sc->rl_dev, "received RX data: %6D/%6D/0x%x\n",
872251881Speter		    eh->ether_dhost, ":", eh->ether_shost, ":",
873251881Speter		    ntohs(eh->ether_type));
874251881Speter		device_printf(sc->rl_dev, "You may have a defective 32-bit "
875251881Speter		    "NIC plugged into a 64-bit PCI slot.\n");
876251881Speter		device_printf(sc->rl_dev, "Please re-install the NIC in a "
877251881Speter		    "32-bit slot for proper operation.\n");
878251881Speter		device_printf(sc->rl_dev, "Read the re(4) man page for more "
879251881Speter		    "details.\n");
880251881Speter		error = EIO;
881251881Speter	}
882251881Speter
883251881Speterdone:
884251881Speter	/* Turn interface off, release resources */
885251881Speter
886251881Speter	sc->rl_testmode = 0;
887251881Speter	sc->rl_flags &= ~RL_FLAG_LINK;
888251881Speter	ifp->if_flags &= ~IFF_PROMISC;
889251881Speter	re_stop(sc);
890251881Speter	if (m0 != NULL)
891251881Speter		m_freem(m0);
892251881Speter
893251881Speter	RL_UNLOCK(sc);
894251881Speter
895251881Speter	return (error);
896251881Speter}
897251881Speter
898251881Speter#endif
899251881Speter
900251881Speter/*
901251881Speter * Probe for a RealTek 8139C+/8169/8110 chip. Check the PCI vendor and device
902251881Speter * IDs against our list and return a device name if we find a match.
903251881Speter */
904251881Speterstatic int
905251881Speterre_probe(device_t dev)
906251881Speter{
907251881Speter	const struct rl_type	*t;
908251881Speter	uint16_t		devid, vendor;
909251881Speter	uint16_t		revid, sdevid;
910251881Speter	int			i;
911251881Speter
912251881Speter	vendor = pci_get_vendor(dev);
913251881Speter	devid = pci_get_device(dev);
914251881Speter	revid = pci_get_revid(dev);
915251881Speter	sdevid = pci_get_subdevice(dev);
916251881Speter
917251881Speter	if (vendor == LINKSYS_VENDORID && devid == LINKSYS_DEVICEID_EG1032) {
918251881Speter		if (sdevid != LINKSYS_SUBDEVICE_EG1032_REV3) {
919251881Speter			/*
920251881Speter			 * Only attach to rev. 3 of the Linksys EG1032 adapter.
921251881Speter			 * Rev. 2 is supported by sk(4).
922251881Speter			 */
923251881Speter			return (ENXIO);
924251881Speter		}
925251881Speter	}
926251881Speter
927251881Speter	if (vendor == RT_VENDORID && devid == RT_DEVICEID_8139) {
928251881Speter		if (revid != 0x20) {
929251881Speter			/* 8139, let rl(4) take care of this device. */
930251881Speter			return (ENXIO);
931251881Speter		}
932251881Speter	}
933251881Speter
934251881Speter	t = re_devs;
935251881Speter	for (i = 0; i < sizeof(re_devs) / sizeof(re_devs[0]); i++, t++) {
936251881Speter		if (vendor == t->rl_vid && devid == t->rl_did) {
937251881Speter			device_set_desc(dev, t->rl_name);
938251881Speter			return (BUS_PROBE_DEFAULT);
939251881Speter		}
940251881Speter	}
941251881Speter
942251881Speter	return (ENXIO);
943251881Speter}
944251881Speter
945251881Speter/*
946251881Speter * Map a single buffer address.
947251881Speter */
948251881Speter
949251881Speterstatic void
950251881Speterre_dma_map_addr(void *arg, bus_dma_segment_t *segs, int nseg, int error)
951251881Speter{
952251881Speter	bus_addr_t		*addr;
953251881Speter
954251881Speter	if (error)
955251881Speter		return;
956251881Speter
957251881Speter	KASSERT(nseg == 1, ("too many DMA segments, %d should be 1", nseg));
958251881Speter	addr = arg;
959251881Speter	*addr = segs->ds_addr;
960251881Speter}
961251881Speter
962251881Speterstatic int
963251881Speterre_allocmem(device_t dev, struct rl_softc *sc)
964251881Speter{
965251881Speter	bus_addr_t		lowaddr;
966251881Speter	bus_size_t		rx_list_size, tx_list_size;
967251881Speter	int			error;
968251881Speter	int			i;
969251881Speter
970251881Speter	rx_list_size = sc->rl_ldata.rl_rx_desc_cnt * sizeof(struct rl_desc);
971251881Speter	tx_list_size = sc->rl_ldata.rl_tx_desc_cnt * sizeof(struct rl_desc);
972251881Speter
973251881Speter	/*
974251881Speter	 * Allocate the parent bus DMA tag appropriate for PCI.
975251881Speter	 * In order to use DAC, RL_CPLUSCMD_PCI_DAC bit of RL_CPLUS_CMD
976251881Speter	 * register should be set. However some RealTek chips are known
977251881Speter	 * to be buggy on DAC handling, therefore disable DAC by limiting
978251881Speter	 * DMA address space to 32bit. PCIe variants of RealTek chips
979251881Speter	 * may not have the limitation.
980251881Speter	 */
981251881Speter	lowaddr = BUS_SPACE_MAXADDR;
982251881Speter	if ((sc->rl_flags & RL_FLAG_PCIE) == 0)
983251881Speter		lowaddr = BUS_SPACE_MAXADDR_32BIT;
984251881Speter	error = bus_dma_tag_create(bus_get_dma_tag(dev), 1, 0,
985251881Speter	    lowaddr, BUS_SPACE_MAXADDR, NULL, NULL,
986251881Speter	    BUS_SPACE_MAXSIZE_32BIT, 0, BUS_SPACE_MAXSIZE_32BIT, 0,
987251881Speter	    NULL, NULL, &sc->rl_parent_tag);
988251881Speter	if (error) {
989251881Speter		device_printf(dev, "could not allocate parent DMA tag\n");
990251881Speter		return (error);
991251881Speter	}
992251881Speter
993251881Speter	/*
994251881Speter	 * Allocate map for TX mbufs.
995251881Speter	 */
996251881Speter	error = bus_dma_tag_create(sc->rl_parent_tag, 1, 0,
997251881Speter	    BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL,
998251881Speter	    NULL, MCLBYTES * RL_NTXSEGS, RL_NTXSEGS, 4096, 0,
999251881Speter	    NULL, NULL, &sc->rl_ldata.rl_tx_mtag);
1000251881Speter	if (error) {
1001251881Speter		device_printf(dev, "could not allocate TX DMA tag\n");
1002251881Speter		return (error);
1003251881Speter	}
1004251881Speter
1005251881Speter	/*
1006251881Speter	 * Allocate map for RX mbufs.
1007251881Speter	 */
1008251881Speter
1009251881Speter	if ((sc->rl_flags & RL_FLAG_JUMBOV2) != 0) {
1010251881Speter		error = bus_dma_tag_create(sc->rl_parent_tag, sizeof(uint64_t),
1011251881Speter		    0, BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL,
1012251881Speter		    MJUM9BYTES, 1, MJUM9BYTES, 0, NULL, NULL,
1013251881Speter		    &sc->rl_ldata.rl_jrx_mtag);
1014251881Speter		if (error) {
1015251881Speter			device_printf(dev,
1016251881Speter			    "could not allocate jumbo RX DMA tag\n");
1017251881Speter			return (error);
1018251881Speter		}
1019251881Speter	}
1020251881Speter	error = bus_dma_tag_create(sc->rl_parent_tag, sizeof(uint64_t), 0,
1021251881Speter	    BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL,
1022251881Speter	    MCLBYTES, 1, MCLBYTES, 0, NULL, NULL, &sc->rl_ldata.rl_rx_mtag);
1023251881Speter	if (error) {
1024251881Speter		device_printf(dev, "could not allocate RX DMA tag\n");
1025251881Speter		return (error);
1026251881Speter	}
1027251881Speter
1028251881Speter	/*
1029251881Speter	 * Allocate map for TX descriptor list.
1030251881Speter	 */
1031251881Speter	error = bus_dma_tag_create(sc->rl_parent_tag, RL_RING_ALIGN,
1032251881Speter	    0, BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL,
1033251881Speter	    NULL, tx_list_size, 1, tx_list_size, 0,
1034251881Speter	    NULL, NULL, &sc->rl_ldata.rl_tx_list_tag);
1035251881Speter	if (error) {
1036251881Speter		device_printf(dev, "could not allocate TX DMA ring tag\n");
1037251881Speter		return (error);
1038251881Speter	}
1039251881Speter
1040251881Speter	/* Allocate DMA'able memory for the TX ring */
1041251881Speter
1042251881Speter	error = bus_dmamem_alloc(sc->rl_ldata.rl_tx_list_tag,
1043251881Speter	    (void **)&sc->rl_ldata.rl_tx_list,
1044251881Speter	    BUS_DMA_WAITOK | BUS_DMA_COHERENT | BUS_DMA_ZERO,
1045251881Speter	    &sc->rl_ldata.rl_tx_list_map);
1046251881Speter	if (error) {
1047251881Speter		device_printf(dev, "could not allocate TX DMA ring\n");
1048251881Speter		return (error);
1049251881Speter	}
1050251881Speter
1051251881Speter	/* Load the map for the TX ring. */
1052251881Speter
1053251881Speter	sc->rl_ldata.rl_tx_list_addr = 0;
1054251881Speter	error = bus_dmamap_load(sc->rl_ldata.rl_tx_list_tag,
1055251881Speter	     sc->rl_ldata.rl_tx_list_map, sc->rl_ldata.rl_tx_list,
1056251881Speter	     tx_list_size, re_dma_map_addr,
1057251881Speter	     &sc->rl_ldata.rl_tx_list_addr, BUS_DMA_NOWAIT);
1058251881Speter	if (error != 0 || sc->rl_ldata.rl_tx_list_addr == 0) {
1059251881Speter		device_printf(dev, "could not load TX DMA ring\n");
1060251881Speter		return (ENOMEM);
1061251881Speter	}
1062251881Speter
1063251881Speter	/* Create DMA maps for TX buffers */
1064251881Speter
1065251881Speter	for (i = 0; i < sc->rl_ldata.rl_tx_desc_cnt; i++) {
1066251881Speter		error = bus_dmamap_create(sc->rl_ldata.rl_tx_mtag, 0,
1067251881Speter		    &sc->rl_ldata.rl_tx_desc[i].tx_dmamap);
1068251881Speter		if (error) {
1069251881Speter			device_printf(dev, "could not create DMA map for TX\n");
1070251881Speter			return (error);
1071251881Speter		}
1072251881Speter	}
1073251881Speter
1074251881Speter	/*
1075251881Speter	 * Allocate map for RX descriptor list.
1076251881Speter	 */
1077251881Speter	error = bus_dma_tag_create(sc->rl_parent_tag, RL_RING_ALIGN,
1078251881Speter	    0, BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL,
1079251881Speter	    NULL, rx_list_size, 1, rx_list_size, 0,
1080251881Speter	    NULL, NULL, &sc->rl_ldata.rl_rx_list_tag);
1081251881Speter	if (error) {
1082251881Speter		device_printf(dev, "could not create RX DMA ring tag\n");
1083251881Speter		return (error);
1084251881Speter	}
1085251881Speter
1086251881Speter	/* Allocate DMA'able memory for the RX ring */
1087251881Speter
1088251881Speter	error = bus_dmamem_alloc(sc->rl_ldata.rl_rx_list_tag,
1089251881Speter	    (void **)&sc->rl_ldata.rl_rx_list,
1090251881Speter	    BUS_DMA_WAITOK | BUS_DMA_COHERENT | BUS_DMA_ZERO,
1091251881Speter	    &sc->rl_ldata.rl_rx_list_map);
1092251881Speter	if (error) {
1093251881Speter		device_printf(dev, "could not allocate RX DMA ring\n");
1094251881Speter		return (error);
1095251881Speter	}
1096251881Speter
1097251881Speter	/* Load the map for the RX ring. */
1098251881Speter
1099251881Speter	sc->rl_ldata.rl_rx_list_addr = 0;
1100251881Speter	error = bus_dmamap_load(sc->rl_ldata.rl_rx_list_tag,
1101251881Speter	     sc->rl_ldata.rl_rx_list_map, sc->rl_ldata.rl_rx_list,
1102251881Speter	     rx_list_size, re_dma_map_addr,
1103251881Speter	     &sc->rl_ldata.rl_rx_list_addr, BUS_DMA_NOWAIT);
1104251881Speter	if (error != 0 || sc->rl_ldata.rl_rx_list_addr == 0) {
1105251881Speter		device_printf(dev, "could not load RX DMA ring\n");
1106251881Speter		return (ENOMEM);
1107251881Speter	}
1108251881Speter
1109251881Speter	/* Create DMA maps for RX buffers */
1110251881Speter
1111251881Speter	if ((sc->rl_flags & RL_FLAG_JUMBOV2) != 0) {
1112251881Speter		error = bus_dmamap_create(sc->rl_ldata.rl_jrx_mtag, 0,
1113251881Speter		    &sc->rl_ldata.rl_jrx_sparemap);
1114251881Speter		if (error) {
1115251881Speter			device_printf(dev,
1116251881Speter			    "could not create spare DMA map for jumbo RX\n");
1117251881Speter			return (error);
1118251881Speter		}
1119251881Speter		for (i = 0; i < sc->rl_ldata.rl_rx_desc_cnt; i++) {
1120251881Speter			error = bus_dmamap_create(sc->rl_ldata.rl_jrx_mtag, 0,
1121251881Speter			    &sc->rl_ldata.rl_jrx_desc[i].rx_dmamap);
1122251881Speter			if (error) {
1123251881Speter				device_printf(dev,
1124251881Speter				    "could not create DMA map for jumbo RX\n");
1125251881Speter				return (error);
1126251881Speter			}
1127251881Speter		}
1128251881Speter	}
1129251881Speter	error = bus_dmamap_create(sc->rl_ldata.rl_rx_mtag, 0,
1130251881Speter	    &sc->rl_ldata.rl_rx_sparemap);
1131251881Speter	if (error) {
1132251881Speter		device_printf(dev, "could not create spare DMA map for RX\n");
1133251881Speter		return (error);
1134251881Speter	}
1135251881Speter	for (i = 0; i < sc->rl_ldata.rl_rx_desc_cnt; i++) {
1136251881Speter		error = bus_dmamap_create(sc->rl_ldata.rl_rx_mtag, 0,
1137251881Speter		    &sc->rl_ldata.rl_rx_desc[i].rx_dmamap);
1138251881Speter		if (error) {
1139251881Speter			device_printf(dev, "could not create DMA map for RX\n");
1140251881Speter			return (error);
1141251881Speter		}
1142251881Speter	}
1143251881Speter
1144251881Speter	/* Create DMA map for statistics. */
1145251881Speter	error = bus_dma_tag_create(sc->rl_parent_tag, RL_DUMP_ALIGN, 0,
1146251881Speter	    BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL,
1147251881Speter	    sizeof(struct rl_stats), 1, sizeof(struct rl_stats), 0, NULL, NULL,
1148251881Speter	    &sc->rl_ldata.rl_stag);
1149251881Speter	if (error) {
1150251881Speter		device_printf(dev, "could not create statistics DMA tag\n");
1151251881Speter		return (error);
1152251881Speter	}
1153251881Speter	/* Allocate DMA'able memory for statistics. */
1154251881Speter	error = bus_dmamem_alloc(sc->rl_ldata.rl_stag,
1155251881Speter	    (void **)&sc->rl_ldata.rl_stats,
1156251881Speter	    BUS_DMA_WAITOK | BUS_DMA_COHERENT | BUS_DMA_ZERO,
1157251881Speter	    &sc->rl_ldata.rl_smap);
1158251881Speter	if (error) {
1159251881Speter		device_printf(dev,
1160251881Speter		    "could not allocate statistics DMA memory\n");
1161251881Speter		return (error);
1162251881Speter	}
1163251881Speter	/* Load the map for statistics. */
1164251881Speter	sc->rl_ldata.rl_stats_addr = 0;
1165251881Speter	error = bus_dmamap_load(sc->rl_ldata.rl_stag, sc->rl_ldata.rl_smap,
1166251881Speter	    sc->rl_ldata.rl_stats, sizeof(struct rl_stats), re_dma_map_addr,
1167251881Speter	     &sc->rl_ldata.rl_stats_addr, BUS_DMA_NOWAIT);
1168251881Speter	if (error != 0 || sc->rl_ldata.rl_stats_addr == 0) {
1169251881Speter		device_printf(dev, "could not load statistics DMA memory\n");
1170251881Speter		return (ENOMEM);
1171251881Speter	}
1172251881Speter
1173251881Speter	return (0);
1174251881Speter}
1175251881Speter
1176251881Speter/*
1177251881Speter * Attach the interface. Allocate softc structures, do ifmedia
1178251881Speter * setup and ethernet/BPF attach.
1179251881Speter */
1180251881Speterstatic int
1181251881Speterre_attach(device_t dev)
1182251881Speter{
1183251881Speter	u_char			eaddr[ETHER_ADDR_LEN];
1184251881Speter	u_int16_t		as[ETHER_ADDR_LEN / 2];
1185251881Speter	struct rl_softc		*sc;
1186251881Speter	struct ifnet		*ifp;
1187251881Speter	const struct rl_hwrev	*hw_rev;
1188251881Speter	u_int32_t		cap, ctl;
1189251881Speter	int			hwrev;
1190251881Speter	u_int16_t		devid, re_did = 0;
1191251881Speter	int			error = 0, i, phy, rid;
1192251881Speter	int			msic, msixc, reg;
1193251881Speter	uint8_t			cfg;
1194251881Speter
1195251881Speter	sc = device_get_softc(dev);
1196251881Speter	sc->rl_dev = dev;
1197251881Speter
1198251881Speter	mtx_init(&sc->rl_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK,
1199251881Speter	    MTX_DEF);
1200251881Speter	callout_init_mtx(&sc->rl_stat_callout, &sc->rl_mtx, 0);
1201251881Speter
1202251881Speter	/*
1203251881Speter	 * Map control/status registers.
1204251881Speter	 */
1205251881Speter	pci_enable_busmaster(dev);
1206251881Speter
1207251881Speter	devid = pci_get_device(dev);
1208251881Speter	/*
1209251881Speter	 * Prefer memory space register mapping over IO space.
1210251881Speter	 * Because RTL8169SC does not seem to work when memory mapping
1211251881Speter	 * is used always activate io mapping.
1212251881Speter	 */
1213251881Speter	if (devid == RT_DEVICEID_8169SC)
1214251881Speter		prefer_iomap = 1;
1215251881Speter	if (prefer_iomap == 0) {
1216251881Speter		sc->rl_res_id = PCIR_BAR(1);
1217251881Speter		sc->rl_res_type = SYS_RES_MEMORY;
1218251881Speter		/* RTL8168/8101E seems to use different BARs. */
1219251881Speter		if (devid == RT_DEVICEID_8168 || devid == RT_DEVICEID_8101E)
1220251881Speter			sc->rl_res_id = PCIR_BAR(2);
1221251881Speter	} else {
1222251881Speter		sc->rl_res_id = PCIR_BAR(0);
1223251881Speter		sc->rl_res_type = SYS_RES_IOPORT;
1224251881Speter	}
1225251881Speter	sc->rl_res = bus_alloc_resource_any(dev, sc->rl_res_type,
1226251881Speter	    &sc->rl_res_id, RF_ACTIVE);
1227251881Speter	if (sc->rl_res == NULL && prefer_iomap == 0) {
1228251881Speter		sc->rl_res_id = PCIR_BAR(0);
1229251881Speter		sc->rl_res_type = SYS_RES_IOPORT;
1230251881Speter		sc->rl_res = bus_alloc_resource_any(dev, sc->rl_res_type,
1231251881Speter		    &sc->rl_res_id, RF_ACTIVE);
1232251881Speter	}
1233251881Speter	if (sc->rl_res == NULL) {
1234251881Speter		device_printf(dev, "couldn't map ports/memory\n");
1235251881Speter		error = ENXIO;
1236251881Speter		goto fail;
1237251881Speter	}
1238251881Speter
1239251881Speter	sc->rl_btag = rman_get_bustag(sc->rl_res);
1240251881Speter	sc->rl_bhandle = rman_get_bushandle(sc->rl_res);
1241251881Speter
1242251881Speter	msic = pci_msi_count(dev);
1243251881Speter	msixc = pci_msix_count(dev);
1244251881Speter	if (pci_find_cap(dev, PCIY_EXPRESS, &reg) == 0) {
1245251881Speter		sc->rl_flags |= RL_FLAG_PCIE;
1246251881Speter		sc->rl_expcap = reg;
1247251881Speter	}
1248251881Speter	if (bootverbose) {
1249251881Speter		device_printf(dev, "MSI count : %d\n", msic);
1250251881Speter		device_printf(dev, "MSI-X count : %d\n", msixc);
1251251881Speter	}
1252251881Speter	if (msix_disable > 0)
1253251881Speter		msixc = 0;
1254251881Speter	if (msi_disable > 0)
1255251881Speter		msic = 0;
1256251881Speter	/* Prefer MSI-X to MSI. */
1257251881Speter	if (msixc > 0) {
1258251881Speter		msixc = 1;
1259251881Speter		rid = PCIR_BAR(4);
1260251881Speter		sc->rl_res_pba = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
1261251881Speter		    &rid, RF_ACTIVE);
1262251881Speter		if (sc->rl_res_pba == NULL) {
1263251881Speter			device_printf(sc->rl_dev,
1264251881Speter			    "could not allocate MSI-X PBA resource\n");
1265251881Speter		}
1266251881Speter		if (sc->rl_res_pba != NULL &&
1267251881Speter		    pci_alloc_msix(dev, &msixc) == 0) {
1268251881Speter			if (msixc == 1) {
1269251881Speter				device_printf(dev, "Using %d MSI-X message\n",
1270251881Speter				    msixc);
1271251881Speter				sc->rl_flags |= RL_FLAG_MSIX;
1272251881Speter			} else
1273251881Speter				pci_release_msi(dev);
1274251881Speter		}
1275251881Speter		if ((sc->rl_flags & RL_FLAG_MSIX) == 0) {
1276251881Speter			if (sc->rl_res_pba != NULL)
1277251881Speter				bus_release_resource(dev, SYS_RES_MEMORY, rid,
1278251881Speter				    sc->rl_res_pba);
1279251881Speter			sc->rl_res_pba = NULL;
1280251881Speter			msixc = 0;
1281251881Speter		}
1282251881Speter	}
1283251881Speter	/* Prefer MSI to INTx. */
1284251881Speter	if (msixc == 0 && msic > 0) {
1285251881Speter		msic = 1;
1286251881Speter		if (pci_alloc_msi(dev, &msic) == 0) {
1287251881Speter			if (msic == RL_MSI_MESSAGES) {
1288251881Speter				device_printf(dev, "Using %d MSI message\n",
1289251881Speter				    msic);
1290251881Speter				sc->rl_flags |= RL_FLAG_MSI;
1291251881Speter				/* Explicitly set MSI enable bit. */
1292251881Speter				CSR_WRITE_1(sc, RL_EECMD, RL_EE_MODE);
1293251881Speter				cfg = CSR_READ_1(sc, RL_CFG2);
1294251881Speter				cfg |= RL_CFG2_MSI;
1295251881Speter				CSR_WRITE_1(sc, RL_CFG2, cfg);
1296251881Speter				CSR_WRITE_1(sc, RL_EECMD, RL_EEMODE_OFF);
1297251881Speter			} else
1298251881Speter				pci_release_msi(dev);
1299251881Speter		}
1300251881Speter		if ((sc->rl_flags & RL_FLAG_MSI) == 0)
1301251881Speter			msic = 0;
1302251881Speter	}
1303251881Speter
1304251881Speter	/* Allocate interrupt */
1305251881Speter	if ((sc->rl_flags & (RL_FLAG_MSI | RL_FLAG_MSIX)) == 0) {
1306251881Speter		rid = 0;
1307251881Speter		sc->rl_irq[0] = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
1308251881Speter		    RF_SHAREABLE | RF_ACTIVE);
1309251881Speter		if (sc->rl_irq[0] == NULL) {
1310251881Speter			device_printf(dev, "couldn't allocate IRQ resources\n");
1311251881Speter			error = ENXIO;
1312251881Speter			goto fail;
1313251881Speter		}
1314251881Speter	} else {
1315251881Speter		for (i = 0, rid = 1; i < RL_MSI_MESSAGES; i++, rid++) {
1316251881Speter			sc->rl_irq[i] = bus_alloc_resource_any(dev,
1317251881Speter			    SYS_RES_IRQ, &rid, RF_ACTIVE);
1318251881Speter			if (sc->rl_irq[i] == NULL) {
1319251881Speter				device_printf(dev,
1320251881Speter				    "couldn't llocate IRQ resources for "
1321251881Speter				    "message %d\n", rid);
1322251881Speter				error = ENXIO;
1323251881Speter				goto fail;
1324251881Speter			}
1325251881Speter		}
1326251881Speter	}
1327251881Speter
1328251881Speter	if ((sc->rl_flags & RL_FLAG_MSI) == 0) {
1329251881Speter		CSR_WRITE_1(sc, RL_EECMD, RL_EE_MODE);
1330251881Speter		cfg = CSR_READ_1(sc, RL_CFG2);
1331251881Speter		if ((cfg & RL_CFG2_MSI) != 0) {
1332251881Speter			device_printf(dev, "turning off MSI enable bit.\n");
1333251881Speter			cfg &= ~RL_CFG2_MSI;
1334251881Speter			CSR_WRITE_1(sc, RL_CFG2, cfg);
1335251881Speter		}
1336251881Speter		CSR_WRITE_1(sc, RL_EECMD, RL_EEMODE_OFF);
1337251881Speter	}
1338251881Speter
1339251881Speter	/* Disable ASPM L0S/L1. */
1340251881Speter	if (sc->rl_expcap != 0) {
1341251881Speter		cap = pci_read_config(dev, sc->rl_expcap +
1342251881Speter		    PCIR_EXPRESS_LINK_CAP, 2);
1343251881Speter		if ((cap & PCIM_LINK_CAP_ASPM) != 0) {
1344251881Speter			ctl = pci_read_config(dev, sc->rl_expcap +
1345251881Speter			    PCIR_EXPRESS_LINK_CTL, 2);
1346251881Speter			if ((ctl & 0x0003) != 0) {
1347251881Speter				ctl &= ~0x0003;
1348251881Speter				pci_write_config(dev, sc->rl_expcap +
1349251881Speter				    PCIR_EXPRESS_LINK_CTL, ctl, 2);
1350251881Speter				device_printf(dev, "ASPM disabled\n");
1351251881Speter			}
1352251881Speter		} else
1353251881Speter			device_printf(dev, "no ASPM capability\n");
1354251881Speter	}
1355251881Speter
1356251881Speter	hw_rev = re_hwrevs;
1357251881Speter	hwrev = CSR_READ_4(sc, RL_TXCFG);
1358251881Speter	switch (hwrev & 0x70000000) {
1359251881Speter	case 0x00000000:
1360251881Speter	case 0x10000000:
1361251881Speter		device_printf(dev, "Chip rev. 0x%08x\n", hwrev & 0xfc800000);
1362251881Speter		hwrev &= (RL_TXCFG_HWREV | 0x80000000);
1363251881Speter		break;
1364251881Speter	default:
1365251881Speter		device_printf(dev, "Chip rev. 0x%08x\n", hwrev & 0x7c800000);
1366251881Speter		hwrev &= RL_TXCFG_HWREV;
1367251881Speter		break;
1368251881Speter	}
1369251881Speter	device_printf(dev, "MAC rev. 0x%08x\n", hwrev & 0x00700000);
1370251881Speter	while (hw_rev->rl_desc != NULL) {
1371251881Speter		if (hw_rev->rl_rev == hwrev) {
1372251881Speter			sc->rl_type = hw_rev->rl_type;
1373251881Speter			sc->rl_hwrev = hw_rev;
1374251881Speter			break;
1375251881Speter		}
1376251881Speter		hw_rev++;
1377251881Speter	}
1378251881Speter	if (hw_rev->rl_desc == NULL) {
1379251881Speter		device_printf(dev, "Unknown H/W revision: 0x%08x\n", hwrev);
1380251881Speter		error = ENXIO;
1381251881Speter		goto fail;
1382251881Speter	}
1383251881Speter
1384251881Speter	switch (hw_rev->rl_rev) {
1385251881Speter	case RL_HWREV_8139CPLUS:
1386251881Speter		sc->rl_flags |= RL_FLAG_FASTETHER | RL_FLAG_AUTOPAD;
1387251881Speter		break;
1388251881Speter	case RL_HWREV_8100E:
1389251881Speter	case RL_HWREV_8101E:
1390251881Speter		sc->rl_flags |= RL_FLAG_PHYWAKE | RL_FLAG_FASTETHER;
1391251881Speter		break;
1392251881Speter	case RL_HWREV_8102E:
1393251881Speter	case RL_HWREV_8102EL:
1394251881Speter	case RL_HWREV_8102EL_SPIN1:
1395251881Speter		sc->rl_flags |= RL_FLAG_PHYWAKE | RL_FLAG_PAR | RL_FLAG_DESCV2 |
1396251881Speter		    RL_FLAG_MACSTAT | RL_FLAG_FASTETHER | RL_FLAG_CMDSTOP |
1397251881Speter		    RL_FLAG_AUTOPAD;
1398251881Speter		break;
1399251881Speter	case RL_HWREV_8103E:
1400251881Speter		sc->rl_flags |= RL_FLAG_PHYWAKE | RL_FLAG_PAR | RL_FLAG_DESCV2 |
1401251881Speter		    RL_FLAG_MACSTAT | RL_FLAG_FASTETHER | RL_FLAG_CMDSTOP |
1402251881Speter		    RL_FLAG_AUTOPAD | RL_FLAG_MACSLEEP;
1403251881Speter		break;
1404251881Speter	case RL_HWREV_8401E:
1405251881Speter	case RL_HWREV_8105E:
1406251881Speter	case RL_HWREV_8105E_SPIN1:
1407251881Speter		sc->rl_flags |= RL_FLAG_PHYWAKE | RL_FLAG_PHYWAKE_PM |
1408251881Speter		    RL_FLAG_PAR | RL_FLAG_DESCV2 | RL_FLAG_MACSTAT |
1409251881Speter		    RL_FLAG_FASTETHER | RL_FLAG_CMDSTOP | RL_FLAG_AUTOPAD;
1410251881Speter		break;
1411251881Speter	case RL_HWREV_8402:
1412251881Speter		sc->rl_flags |= RL_FLAG_PHYWAKE | RL_FLAG_PHYWAKE_PM |
1413251881Speter		    RL_FLAG_PAR | RL_FLAG_DESCV2 | RL_FLAG_MACSTAT |
1414251881Speter		    RL_FLAG_FASTETHER | RL_FLAG_CMDSTOP | RL_FLAG_AUTOPAD |
1415251881Speter		    RL_FLAG_CMDSTOP_WAIT_TXQ;
1416251881Speter		break;
1417251881Speter	case RL_HWREV_8168B_SPIN1:
1418251881Speter	case RL_HWREV_8168B_SPIN2:
1419251881Speter		sc->rl_flags |= RL_FLAG_WOLRXENB;
1420251881Speter		/* FALLTHROUGH */
1421251881Speter	case RL_HWREV_8168B_SPIN3:
1422251881Speter		sc->rl_flags |= RL_FLAG_PHYWAKE | RL_FLAG_MACSTAT;
1423251881Speter		break;
1424251881Speter	case RL_HWREV_8168C_SPIN2:
1425251881Speter		sc->rl_flags |= RL_FLAG_MACSLEEP;
1426251881Speter		/* FALLTHROUGH */
1427251881Speter	case RL_HWREV_8168C:
1428251881Speter		if ((hwrev & 0x00700000) == 0x00200000)
1429251881Speter			sc->rl_flags |= RL_FLAG_MACSLEEP;
1430251881Speter		/* FALLTHROUGH */
1431251881Speter	case RL_HWREV_8168CP:
1432251881Speter	case RL_HWREV_8168D:
1433251881Speter		sc->rl_flags |= RL_FLAG_PHYWAKE | RL_FLAG_PAR |
1434251881Speter		    RL_FLAG_DESCV2 | RL_FLAG_MACSTAT | RL_FLAG_CMDSTOP |
1435251881Speter		    RL_FLAG_AUTOPAD | RL_FLAG_JUMBOV2 | RL_FLAG_WOL_MANLINK;
1436251881Speter		break;
1437251881Speter	case RL_HWREV_8168DP:
1438251881Speter		sc->rl_flags |= RL_FLAG_PHYWAKE | RL_FLAG_PAR |
1439251881Speter		    RL_FLAG_DESCV2 | RL_FLAG_MACSTAT | RL_FLAG_AUTOPAD |
1440251881Speter		    RL_FLAG_JUMBOV2 | RL_FLAG_WAIT_TXPOLL | RL_FLAG_WOL_MANLINK;
1441251881Speter		break;
1442251881Speter	case RL_HWREV_8168E:
1443262253Speter		sc->rl_flags |= RL_FLAG_PHYWAKE | RL_FLAG_PHYWAKE_PM |
1444262253Speter		    RL_FLAG_PAR | RL_FLAG_DESCV2 | RL_FLAG_MACSTAT |
1445262253Speter		    RL_FLAG_CMDSTOP | RL_FLAG_AUTOPAD | RL_FLAG_JUMBOV2 |
1446262253Speter		    RL_FLAG_WOL_MANLINK;
1447262253Speter		break;
1448262253Speter	case RL_HWREV_8168E_VL:
1449262253Speter	case RL_HWREV_8168F:
1450262253Speter	case RL_HWREV_8411:
1451262253Speter		sc->rl_flags |= RL_FLAG_PHYWAKE | RL_FLAG_PAR |
1452251881Speter		    RL_FLAG_DESCV2 | RL_FLAG_MACSTAT | RL_FLAG_CMDSTOP |
1453251881Speter		    RL_FLAG_AUTOPAD | RL_FLAG_JUMBOV2 |
1454251881Speter		    RL_FLAG_CMDSTOP_WAIT_TXQ | RL_FLAG_WOL_MANLINK;
1455251881Speter		break;
1456251881Speter	case RL_HWREV_8169_8110SB:
1457251881Speter	case RL_HWREV_8169_8110SBL:
1458251881Speter	case RL_HWREV_8169_8110SC:
1459251881Speter	case RL_HWREV_8169_8110SCE:
1460251881Speter		sc->rl_flags |= RL_FLAG_PHYWAKE;
1461251881Speter		/* FALLTHROUGH */
1462251881Speter	case RL_HWREV_8169:
1463251881Speter	case RL_HWREV_8169S:
1464251881Speter	case RL_HWREV_8110S:
1465251881Speter		sc->rl_flags |= RL_FLAG_MACRESET;
1466251881Speter		break;
1467251881Speter	default:
1468251881Speter		break;
1469251881Speter	}
1470251881Speter
1471251881Speter	/* Reset the adapter. */
1472251881Speter	RL_LOCK(sc);
1473251881Speter	re_reset(sc);
1474251881Speter	RL_UNLOCK(sc);
1475251881Speter
1476251881Speter	/* Enable PME. */
1477251881Speter	CSR_WRITE_1(sc, RL_EECMD, RL_EE_MODE);
1478251881Speter	cfg = CSR_READ_1(sc, RL_CFG1);
1479262253Speter	cfg |= RL_CFG1_PME;
1480262253Speter	CSR_WRITE_1(sc, RL_CFG1, cfg);
1481251881Speter	cfg = CSR_READ_1(sc, RL_CFG5);
1482251881Speter	cfg &= RL_CFG5_PME_STS;
1483251881Speter	CSR_WRITE_1(sc, RL_CFG5, cfg);
1484251881Speter	CSR_WRITE_1(sc, RL_EECMD, RL_EEMODE_OFF);
1485251881Speter
1486251881Speter	if ((sc->rl_flags & RL_FLAG_PAR) != 0) {
1487251881Speter		/*
1488251881Speter		 * XXX Should have a better way to extract station
1489251881Speter		 * address from EEPROM.
1490251881Speter		 */
1491251881Speter		for (i = 0; i < ETHER_ADDR_LEN; i++)
1492251881Speter			eaddr[i] = CSR_READ_1(sc, RL_IDR0 + i);
1493251881Speter	} else {
1494251881Speter		sc->rl_eewidth = RL_9356_ADDR_LEN;
1495251881Speter		re_read_eeprom(sc, (caddr_t)&re_did, 0, 1);
1496251881Speter		if (re_did != 0x8129)
1497251881Speter			sc->rl_eewidth = RL_9346_ADDR_LEN;
1498251881Speter
1499251881Speter		/*
1500251881Speter		 * Get station address from the EEPROM.
1501251881Speter		 */
1502251881Speter		re_read_eeprom(sc, (caddr_t)as, RL_EE_EADDR, 3);
1503251881Speter		for (i = 0; i < ETHER_ADDR_LEN / 2; i++)
1504251881Speter			as[i] = le16toh(as[i]);
1505251881Speter		bcopy(as, eaddr, sizeof(eaddr));
1506251881Speter	}
1507251881Speter
1508251881Speter	if (sc->rl_type == RL_8169) {
1509251881Speter		/* Set RX length mask and number of descriptors. */
1510251881Speter		sc->rl_rxlenmask = RL_RDESC_STAT_GFRAGLEN;
1511251881Speter		sc->rl_txstart = RL_GTXSTART;
1512251881Speter		sc->rl_ldata.rl_tx_desc_cnt = RL_8169_TX_DESC_CNT;
1513251881Speter		sc->rl_ldata.rl_rx_desc_cnt = RL_8169_RX_DESC_CNT;
1514251881Speter	} else {
1515251881Speter		/* Set RX length mask and number of descriptors. */
1516251881Speter		sc->rl_rxlenmask = RL_RDESC_STAT_FRAGLEN;
1517251881Speter		sc->rl_txstart = RL_TXSTART;
1518251881Speter		sc->rl_ldata.rl_tx_desc_cnt = RL_8139_TX_DESC_CNT;
1519251881Speter		sc->rl_ldata.rl_rx_desc_cnt = RL_8139_RX_DESC_CNT;
1520251881Speter	}
1521251881Speter
1522251881Speter	error = re_allocmem(dev, sc);
1523251881Speter	if (error)
1524251881Speter		goto fail;
1525251881Speter	re_add_sysctls(sc);
1526251881Speter
1527251881Speter	ifp = sc->rl_ifp = if_alloc(IFT_ETHER);
1528251881Speter	if (ifp == NULL) {
1529251881Speter		device_printf(dev, "can not if_alloc()\n");
1530251881Speter		error = ENOSPC;
1531251881Speter		goto fail;
1532251881Speter	}
1533251881Speter
1534251881Speter	/* Take controller out of deep sleep mode. */
1535251881Speter	if ((sc->rl_flags & RL_FLAG_MACSLEEP) != 0) {
1536251881Speter		if ((CSR_READ_1(sc, RL_MACDBG) & 0x80) == 0x80)
1537251881Speter			CSR_WRITE_1(sc, RL_GPIO,
1538251881Speter			    CSR_READ_1(sc, RL_GPIO) | 0x01);
1539251881Speter		else
1540251881Speter			CSR_WRITE_1(sc, RL_GPIO,
1541251881Speter			    CSR_READ_1(sc, RL_GPIO) & ~0x01);
1542251881Speter	}
1543251881Speter
1544251881Speter	/* Take PHY out of power down mode. */
1545251881Speter	if ((sc->rl_flags & RL_FLAG_PHYWAKE_PM) != 0) {
1546251881Speter		CSR_WRITE_1(sc, RL_PMCH, CSR_READ_1(sc, RL_PMCH) | 0x80);
1547251881Speter		if (hw_rev->rl_rev == RL_HWREV_8401E)
1548251881Speter			CSR_WRITE_1(sc, 0xD1, CSR_READ_1(sc, 0xD1) & ~0x08);
1549251881Speter	}
1550251881Speter	if ((sc->rl_flags & RL_FLAG_PHYWAKE) != 0) {
1551251881Speter		re_gmii_writereg(dev, 1, 0x1f, 0);
1552251881Speter		re_gmii_writereg(dev, 1, 0x0e, 0);
1553251881Speter	}
1554251881Speter
1555251881Speter#define	RE_PHYAD_INTERNAL	 0
1556251881Speter
1557251881Speter	/* Do MII setup. */
1558251881Speter	phy = RE_PHYAD_INTERNAL;
1559251881Speter	if (sc->rl_type == RL_8169)
1560251881Speter		phy = 1;
1561251881Speter	error = mii_attach(dev, &sc->rl_miibus, ifp, re_ifmedia_upd,
1562251881Speter	    re_ifmedia_sts, BMSR_DEFCAPMASK, phy, MII_OFFSET_ANY, MIIF_DOPAUSE);
1563251881Speter	if (error != 0) {
1564251881Speter		device_printf(dev, "attaching PHYs failed\n");
1565251881Speter		goto fail;
1566251881Speter	}
1567251881Speter
1568251881Speter	ifp->if_softc = sc;
1569251881Speter	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
1570251881Speter	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
1571251881Speter	ifp->if_ioctl = re_ioctl;
1572251881Speter	ifp->if_start = re_start;
1573251881Speter	/*
1574251881Speter	 * RTL8168/8111C generates wrong IP checksummed frame if the
1575251881Speter	 * packet has IP options so disable TX IP checksum offloading.
1576251881Speter	 */
1577251881Speter	if (sc->rl_hwrev->rl_rev == RL_HWREV_8168C ||
1578251881Speter	    sc->rl_hwrev->rl_rev == RL_HWREV_8168C_SPIN2)
1579251881Speter		ifp->if_hwassist = CSUM_TCP | CSUM_UDP;
1580251881Speter	else
1581251881Speter		ifp->if_hwassist = CSUM_IP | CSUM_TCP | CSUM_UDP;
1582251881Speter	ifp->if_hwassist |= CSUM_TSO;
1583251881Speter	ifp->if_capabilities = IFCAP_HWCSUM | IFCAP_TSO4;
1584251881Speter	ifp->if_capenable = ifp->if_capabilities;
1585251881Speter	ifp->if_init = re_init;
1586251881Speter	IFQ_SET_MAXLEN(&ifp->if_snd, RL_IFQ_MAXLEN);
1587251881Speter	ifp->if_snd.ifq_drv_maxlen = RL_IFQ_MAXLEN;
1588251881Speter	IFQ_SET_READY(&ifp->if_snd);
1589251881Speter
1590251881Speter	TASK_INIT(&sc->rl_inttask, 0, re_int_task, sc);
1591251881Speter
1592251881Speter	/*
1593251881Speter	 * Call MI attach routine.
1594251881Speter	 */
1595251881Speter	ether_ifattach(ifp, eaddr);
1596251881Speter
1597251881Speter	/* VLAN capability setup */
1598251881Speter	ifp->if_capabilities |= IFCAP_VLAN_MTU | IFCAP_VLAN_HWTAGGING;
1599251881Speter	if (ifp->if_capabilities & IFCAP_HWCSUM)
1600251881Speter		ifp->if_capabilities |= IFCAP_VLAN_HWCSUM;
1601251881Speter	/* Enable WOL if PM is supported. */
1602251881Speter	if (pci_find_cap(sc->rl_dev, PCIY_PMG, &reg) == 0)
1603251881Speter		ifp->if_capabilities |= IFCAP_WOL;
1604251881Speter	ifp->if_capenable = ifp->if_capabilities;
1605251881Speter	ifp->if_capenable &= ~(IFCAP_WOL_UCAST | IFCAP_WOL_MCAST);
1606251881Speter	/*
1607251881Speter	 * Don't enable TSO by default.  It is known to generate
1608251881Speter	 * corrupted TCP segments(bad TCP options) under certain
1609251881Speter	 * circumtances.
1610251881Speter	 */
1611251881Speter	ifp->if_hwassist &= ~CSUM_TSO;
1612251881Speter	ifp->if_capenable &= ~(IFCAP_TSO4 | IFCAP_VLAN_HWTSO);
1613251881Speter#ifdef DEVICE_POLLING
1614251881Speter	ifp->if_capabilities |= IFCAP_POLLING;
1615251881Speter#endif
1616251881Speter	/*
1617251881Speter	 * Tell the upper layer(s) we support long frames.
1618251881Speter	 * Must appear after the call to ether_ifattach() because
1619251881Speter	 * ether_ifattach() sets ifi_hdrlen to the default value.
1620251881Speter	 */
1621251881Speter	ifp->if_data.ifi_hdrlen = sizeof(struct ether_vlan_header);
1622251881Speter
1623251881Speter#ifdef RE_DIAG
1624251881Speter	/*
1625251881Speter	 * Perform hardware diagnostic on the original RTL8169.
1626251881Speter	 * Some 32-bit cards were incorrectly wired and would
1627251881Speter	 * malfunction if plugged into a 64-bit slot.
1628251881Speter	 */
1629251881Speter
1630251881Speter	if (hwrev == RL_HWREV_8169) {
1631251881Speter		error = re_diag(sc);
1632251881Speter		if (error) {
1633251881Speter			device_printf(dev,
1634251881Speter		    	"attach aborted due to hardware diag failure\n");
1635251881Speter			ether_ifdetach(ifp);
1636251881Speter			goto fail;
1637251881Speter		}
1638251881Speter	}
1639251881Speter#endif
1640251881Speter
1641251881Speter#ifdef RE_TX_MODERATION
1642251881Speter	intr_filter = 1;
1643251881Speter#endif
1644251881Speter	/* Hook interrupt last to avoid having to lock softc */
1645251881Speter	if ((sc->rl_flags & (RL_FLAG_MSI | RL_FLAG_MSIX)) != 0 &&
1646251881Speter	    intr_filter == 0) {
1647251881Speter		error = bus_setup_intr(dev, sc->rl_irq[0],
1648251881Speter		    INTR_TYPE_NET | INTR_MPSAFE, NULL, re_intr_msi, sc,
1649251881Speter		    &sc->rl_intrhand[0]);
1650251881Speter	} else {
1651251881Speter		error = bus_setup_intr(dev, sc->rl_irq[0],
1652251881Speter		    INTR_TYPE_NET | INTR_MPSAFE, re_intr, NULL, sc,
1653251881Speter		    &sc->rl_intrhand[0]);
1654251881Speter	}
1655251881Speter	if (error) {
1656251881Speter		device_printf(dev, "couldn't set up irq\n");
1657251881Speter		ether_ifdetach(ifp);
1658251881Speter	}
1659251881Speter
1660251881Speterfail:
1661251881Speter
1662251881Speter	if (error)
1663251881Speter		re_detach(dev);
1664251881Speter
1665251881Speter	return (error);
1666251881Speter}
1667251881Speter
1668251881Speter/*
1669251881Speter * Shutdown hardware and free up resources. This can be called any
1670251881Speter * time after the mutex has been initialized. It is called in both
1671251881Speter * the error case in attach and the normal detach case so it needs
1672251881Speter * to be careful about only freeing resources that have actually been
1673251881Speter * allocated.
1674251881Speter */
1675251881Speterstatic int
1676251881Speterre_detach(device_t dev)
1677251881Speter{
1678251881Speter	struct rl_softc		*sc;
1679251881Speter	struct ifnet		*ifp;
1680251881Speter	int			i, rid;
1681251881Speter
1682251881Speter	sc = device_get_softc(dev);
1683251881Speter	ifp = sc->rl_ifp;
1684251881Speter	KASSERT(mtx_initialized(&sc->rl_mtx), ("re mutex not initialized"));
1685251881Speter
1686251881Speter	/* These should only be active if attach succeeded */
1687251881Speter	if (device_is_attached(dev)) {
1688251881Speter#ifdef DEVICE_POLLING
1689251881Speter		if (ifp->if_capenable & IFCAP_POLLING)
1690251881Speter			ether_poll_deregister(ifp);
1691251881Speter#endif
1692251881Speter		RL_LOCK(sc);
1693251881Speter#if 0
1694251881Speter		sc->suspended = 1;
1695251881Speter#endif
1696251881Speter		re_stop(sc);
1697251881Speter		RL_UNLOCK(sc);
1698251881Speter		callout_drain(&sc->rl_stat_callout);
1699251881Speter		taskqueue_drain(taskqueue_fast, &sc->rl_inttask);
1700251881Speter		/*
1701251881Speter		 * Force off the IFF_UP flag here, in case someone
1702251881Speter		 * still had a BPF descriptor attached to this
1703251881Speter		 * interface. If they do, ether_ifdetach() will cause
1704251881Speter		 * the BPF code to try and clear the promisc mode
1705251881Speter		 * flag, which will bubble down to re_ioctl(),
1706251881Speter		 * which will try to call re_init() again. This will
1707251881Speter		 * turn the NIC back on and restart the MII ticker,
1708251881Speter		 * which will panic the system when the kernel tries
1709251881Speter		 * to invoke the re_tick() function that isn't there
1710251881Speter		 * anymore.
1711251881Speter		 */
1712251881Speter		ifp->if_flags &= ~IFF_UP;
1713251881Speter		ether_ifdetach(ifp);
1714251881Speter	}
1715251881Speter	if (sc->rl_miibus)
1716251881Speter		device_delete_child(dev, sc->rl_miibus);
1717251881Speter	bus_generic_detach(dev);
1718251881Speter
1719251881Speter	/*
1720251881Speter	 * The rest is resource deallocation, so we should already be
1721251881Speter	 * stopped here.
1722251881Speter	 */
1723251881Speter
1724251881Speter	if (sc->rl_intrhand[0] != NULL) {
1725251881Speter		bus_teardown_intr(dev, sc->rl_irq[0], sc->rl_intrhand[0]);
1726251881Speter		sc->rl_intrhand[0] = NULL;
1727251881Speter	}
1728251881Speter	if (ifp != NULL)
1729251881Speter		if_free(ifp);
1730251881Speter	if ((sc->rl_flags & (RL_FLAG_MSI | RL_FLAG_MSIX)) == 0)
1731251881Speter		rid = 0;
1732251881Speter	else
1733251881Speter		rid = 1;
1734251881Speter	if (sc->rl_irq[0] != NULL) {
1735251881Speter		bus_release_resource(dev, SYS_RES_IRQ, rid, sc->rl_irq[0]);
1736251881Speter		sc->rl_irq[0] = NULL;
1737251881Speter	}
1738251881Speter	if ((sc->rl_flags & (RL_FLAG_MSI | RL_FLAG_MSIX)) != 0)
1739251881Speter		pci_release_msi(dev);
1740251881Speter	if (sc->rl_res_pba) {
1741251881Speter		rid = PCIR_BAR(4);
1742251881Speter		bus_release_resource(dev, SYS_RES_MEMORY, rid, sc->rl_res_pba);
1743251881Speter	}
1744251881Speter	if (sc->rl_res)
1745251881Speter		bus_release_resource(dev, sc->rl_res_type, sc->rl_res_id,
1746251881Speter		    sc->rl_res);
1747251881Speter
1748251881Speter	/* Unload and free the RX DMA ring memory and map */
1749251881Speter
1750251881Speter	if (sc->rl_ldata.rl_rx_list_tag) {
1751251881Speter		if (sc->rl_ldata.rl_rx_list_map)
1752251881Speter			bus_dmamap_unload(sc->rl_ldata.rl_rx_list_tag,
1753251881Speter			    sc->rl_ldata.rl_rx_list_map);
1754251881Speter		if (sc->rl_ldata.rl_rx_list_map && sc->rl_ldata.rl_rx_list)
1755251881Speter			bus_dmamem_free(sc->rl_ldata.rl_rx_list_tag,
1756251881Speter			    sc->rl_ldata.rl_rx_list,
1757251881Speter			    sc->rl_ldata.rl_rx_list_map);
1758251881Speter		bus_dma_tag_destroy(sc->rl_ldata.rl_rx_list_tag);
1759251881Speter	}
1760251881Speter
1761251881Speter	/* Unload and free the TX DMA ring memory and map */
1762251881Speter
1763251881Speter	if (sc->rl_ldata.rl_tx_list_tag) {
1764251881Speter		if (sc->rl_ldata.rl_tx_list_map)
1765251881Speter			bus_dmamap_unload(sc->rl_ldata.rl_tx_list_tag,
1766251881Speter			    sc->rl_ldata.rl_tx_list_map);
1767251881Speter		if (sc->rl_ldata.rl_tx_list_map && sc->rl_ldata.rl_tx_list)
1768251881Speter			bus_dmamem_free(sc->rl_ldata.rl_tx_list_tag,
1769251881Speter			    sc->rl_ldata.rl_tx_list,
1770251881Speter			    sc->rl_ldata.rl_tx_list_map);
1771251881Speter		bus_dma_tag_destroy(sc->rl_ldata.rl_tx_list_tag);
1772251881Speter	}
1773251881Speter
1774251881Speter	/* Destroy all the RX and TX buffer maps */
1775251881Speter
1776251881Speter	if (sc->rl_ldata.rl_tx_mtag) {
1777251881Speter		for (i = 0; i < sc->rl_ldata.rl_tx_desc_cnt; i++) {
1778251881Speter			if (sc->rl_ldata.rl_tx_desc[i].tx_dmamap)
1779251881Speter				bus_dmamap_destroy(sc->rl_ldata.rl_tx_mtag,
1780251881Speter				    sc->rl_ldata.rl_tx_desc[i].tx_dmamap);
1781251881Speter		}
1782251881Speter		bus_dma_tag_destroy(sc->rl_ldata.rl_tx_mtag);
1783251881Speter	}
1784251881Speter	if (sc->rl_ldata.rl_rx_mtag) {
1785251881Speter		for (i = 0; i < sc->rl_ldata.rl_rx_desc_cnt; i++) {
1786251881Speter			if (sc->rl_ldata.rl_rx_desc[i].rx_dmamap)
1787251881Speter				bus_dmamap_destroy(sc->rl_ldata.rl_rx_mtag,
1788251881Speter				    sc->rl_ldata.rl_rx_desc[i].rx_dmamap);
1789251881Speter		}
1790251881Speter		if (sc->rl_ldata.rl_rx_sparemap)
1791251881Speter			bus_dmamap_destroy(sc->rl_ldata.rl_rx_mtag,
1792251881Speter			    sc->rl_ldata.rl_rx_sparemap);
1793251881Speter		bus_dma_tag_destroy(sc->rl_ldata.rl_rx_mtag);
1794251881Speter	}
1795251881Speter	if (sc->rl_ldata.rl_jrx_mtag) {
1796251881Speter		for (i = 0; i < sc->rl_ldata.rl_rx_desc_cnt; i++) {
1797251881Speter			if (sc->rl_ldata.rl_jrx_desc[i].rx_dmamap)
1798251881Speter				bus_dmamap_destroy(sc->rl_ldata.rl_jrx_mtag,
1799251881Speter				    sc->rl_ldata.rl_jrx_desc[i].rx_dmamap);
1800251881Speter		}
1801251881Speter		if (sc->rl_ldata.rl_jrx_sparemap)
1802251881Speter			bus_dmamap_destroy(sc->rl_ldata.rl_jrx_mtag,
1803251881Speter			    sc->rl_ldata.rl_jrx_sparemap);
1804251881Speter		bus_dma_tag_destroy(sc->rl_ldata.rl_jrx_mtag);
1805251881Speter	}
1806251881Speter	/* Unload and free the stats buffer and map */
1807251881Speter
1808251881Speter	if (sc->rl_ldata.rl_stag) {
1809251881Speter		if (sc->rl_ldata.rl_smap)
1810251881Speter			bus_dmamap_unload(sc->rl_ldata.rl_stag,
1811251881Speter			    sc->rl_ldata.rl_smap);
1812251881Speter		if (sc->rl_ldata.rl_smap && sc->rl_ldata.rl_stats)
1813251881Speter			bus_dmamem_free(sc->rl_ldata.rl_stag,
1814251881Speter			    sc->rl_ldata.rl_stats, sc->rl_ldata.rl_smap);
1815251881Speter		bus_dma_tag_destroy(sc->rl_ldata.rl_stag);
1816251881Speter	}
1817251881Speter
1818251881Speter	if (sc->rl_parent_tag)
1819251881Speter		bus_dma_tag_destroy(sc->rl_parent_tag);
1820251881Speter
1821251881Speter	mtx_destroy(&sc->rl_mtx);
1822251881Speter
1823251881Speter	return (0);
1824251881Speter}
1825251881Speter
1826251881Speterstatic __inline void
1827251881Speterre_discard_rxbuf(struct rl_softc *sc, int idx)
1828251881Speter{
1829251881Speter	struct rl_desc		*desc;
1830251881Speter	struct rl_rxdesc	*rxd;
1831251881Speter	uint32_t		cmdstat;
1832251881Speter
1833251881Speter	if (sc->rl_ifp->if_mtu > RL_MTU &&
1834251881Speter	    (sc->rl_flags & RL_FLAG_JUMBOV2) != 0)
1835251881Speter		rxd = &sc->rl_ldata.rl_jrx_desc[idx];
1836251881Speter	else
1837251881Speter		rxd = &sc->rl_ldata.rl_rx_desc[idx];
1838251881Speter	desc = &sc->rl_ldata.rl_rx_list[idx];
1839251881Speter	desc->rl_vlanctl = 0;
1840251881Speter	cmdstat = rxd->rx_size;
1841251881Speter	if (idx == sc->rl_ldata.rl_rx_desc_cnt - 1)
1842251881Speter		cmdstat |= RL_RDESC_CMD_EOR;
1843251881Speter	desc->rl_cmdstat = htole32(cmdstat | RL_RDESC_CMD_OWN);
1844251881Speter}
1845251881Speter
1846251881Speterstatic int
1847251881Speterre_newbuf(struct rl_softc *sc, int idx)
1848251881Speter{
1849251881Speter	struct mbuf		*m;
1850251881Speter	struct rl_rxdesc	*rxd;
1851251881Speter	bus_dma_segment_t	segs[1];
1852251881Speter	bus_dmamap_t		map;
1853251881Speter	struct rl_desc		*desc;
1854251881Speter	uint32_t		cmdstat;
1855251881Speter	int			error, nsegs;
1856251881Speter
1857251881Speter	m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
1858251881Speter	if (m == NULL)
1859251881Speter		return (ENOBUFS);
1860251881Speter
1861251881Speter	m->m_len = m->m_pkthdr.len = MCLBYTES;
1862251881Speter#ifdef RE_FIXUP_RX
1863251881Speter	/*
1864251881Speter	 * This is part of an evil trick to deal with non-x86 platforms.
1865251881Speter	 * The RealTek chip requires RX buffers to be aligned on 64-bit
1866251881Speter	 * boundaries, but that will hose non-x86 machines. To get around
1867251881Speter	 * this, we leave some empty space at the start of each buffer
1868251881Speter	 * and for non-x86 hosts, we copy the buffer back six bytes
1869251881Speter	 * to achieve word alignment. This is slightly more efficient
1870251881Speter	 * than allocating a new buffer, copying the contents, and
1871251881Speter	 * discarding the old buffer.
1872251881Speter	 */
1873251881Speter	m_adj(m, RE_ETHER_ALIGN);
1874251881Speter#endif
1875251881Speter	error = bus_dmamap_load_mbuf_sg(sc->rl_ldata.rl_rx_mtag,
1876251881Speter	    sc->rl_ldata.rl_rx_sparemap, m, segs, &nsegs, BUS_DMA_NOWAIT);
1877251881Speter	if (error != 0) {
1878251881Speter		m_freem(m);
1879251881Speter		return (ENOBUFS);
1880251881Speter	}
1881251881Speter	KASSERT(nsegs == 1, ("%s: %d segment returned!", __func__, nsegs));
1882251881Speter
1883251881Speter	rxd = &sc->rl_ldata.rl_rx_desc[idx];
1884251881Speter	if (rxd->rx_m != NULL) {
1885251881Speter		bus_dmamap_sync(sc->rl_ldata.rl_rx_mtag, rxd->rx_dmamap,
1886251881Speter		    BUS_DMASYNC_POSTREAD);
1887251881Speter		bus_dmamap_unload(sc->rl_ldata.rl_rx_mtag, rxd->rx_dmamap);
1888251881Speter	}
1889251881Speter
1890251881Speter	rxd->rx_m = m;
1891251881Speter	map = rxd->rx_dmamap;
1892251881Speter	rxd->rx_dmamap = sc->rl_ldata.rl_rx_sparemap;
1893251881Speter	rxd->rx_size = segs[0].ds_len;
1894251881Speter	sc->rl_ldata.rl_rx_sparemap = map;
1895251881Speter	bus_dmamap_sync(sc->rl_ldata.rl_rx_mtag, rxd->rx_dmamap,
1896251881Speter	    BUS_DMASYNC_PREREAD);
1897251881Speter
1898251881Speter	desc = &sc->rl_ldata.rl_rx_list[idx];
1899251881Speter	desc->rl_vlanctl = 0;
1900251881Speter	desc->rl_bufaddr_lo = htole32(RL_ADDR_LO(segs[0].ds_addr));
1901251881Speter	desc->rl_bufaddr_hi = htole32(RL_ADDR_HI(segs[0].ds_addr));
1902251881Speter	cmdstat = segs[0].ds_len;
1903251881Speter	if (idx == sc->rl_ldata.rl_rx_desc_cnt - 1)
1904251881Speter		cmdstat |= RL_RDESC_CMD_EOR;
1905251881Speter	desc->rl_cmdstat = htole32(cmdstat | RL_RDESC_CMD_OWN);
1906251881Speter
1907251881Speter	return (0);
1908251881Speter}
1909251881Speter
1910251881Speterstatic int
1911251881Speterre_jumbo_newbuf(struct rl_softc *sc, int idx)
1912251881Speter{
1913251881Speter	struct mbuf		*m;
1914251881Speter	struct rl_rxdesc	*rxd;
1915251881Speter	bus_dma_segment_t	segs[1];
1916251881Speter	bus_dmamap_t		map;
1917251881Speter	struct rl_desc		*desc;
1918251881Speter	uint32_t		cmdstat;
1919251881Speter	int			error, nsegs;
1920251881Speter
1921251881Speter	m = m_getjcl(M_DONTWAIT, MT_DATA, M_PKTHDR, MJUM9BYTES);
1922251881Speter	if (m == NULL)
1923251881Speter		return (ENOBUFS);
1924251881Speter	m->m_len = m->m_pkthdr.len = MJUM9BYTES;
1925251881Speter#ifdef RE_FIXUP_RX
1926251881Speter	m_adj(m, RE_ETHER_ALIGN);
1927251881Speter#endif
1928251881Speter	error = bus_dmamap_load_mbuf_sg(sc->rl_ldata.rl_jrx_mtag,
1929251881Speter	    sc->rl_ldata.rl_jrx_sparemap, m, segs, &nsegs, BUS_DMA_NOWAIT);
1930251881Speter	if (error != 0) {
1931251881Speter		m_freem(m);
1932251881Speter		return (ENOBUFS);
1933251881Speter	}
1934251881Speter	KASSERT(nsegs == 1, ("%s: %d segment returned!", __func__, nsegs));
1935251881Speter
1936251881Speter	rxd = &sc->rl_ldata.rl_jrx_desc[idx];
1937251881Speter	if (rxd->rx_m != NULL) {
1938251881Speter		bus_dmamap_sync(sc->rl_ldata.rl_jrx_mtag, rxd->rx_dmamap,
1939251881Speter		    BUS_DMASYNC_POSTREAD);
1940251881Speter		bus_dmamap_unload(sc->rl_ldata.rl_jrx_mtag, rxd->rx_dmamap);
1941251881Speter	}
1942251881Speter
1943251881Speter	rxd->rx_m = m;
1944251881Speter	map = rxd->rx_dmamap;
1945251881Speter	rxd->rx_dmamap = sc->rl_ldata.rl_jrx_sparemap;
1946251881Speter	rxd->rx_size = segs[0].ds_len;
1947251881Speter	sc->rl_ldata.rl_jrx_sparemap = map;
1948251881Speter	bus_dmamap_sync(sc->rl_ldata.rl_jrx_mtag, rxd->rx_dmamap,
1949251881Speter	    BUS_DMASYNC_PREREAD);
1950251881Speter
1951251881Speter	desc = &sc->rl_ldata.rl_rx_list[idx];
1952251881Speter	desc->rl_vlanctl = 0;
1953251881Speter	desc->rl_bufaddr_lo = htole32(RL_ADDR_LO(segs[0].ds_addr));
1954251881Speter	desc->rl_bufaddr_hi = htole32(RL_ADDR_HI(segs[0].ds_addr));
1955251881Speter	cmdstat = segs[0].ds_len;
1956251881Speter	if (idx == sc->rl_ldata.rl_rx_desc_cnt - 1)
1957251881Speter		cmdstat |= RL_RDESC_CMD_EOR;
1958251881Speter	desc->rl_cmdstat = htole32(cmdstat | RL_RDESC_CMD_OWN);
1959251881Speter
1960251881Speter	return (0);
1961251881Speter}
1962251881Speter
1963251881Speter#ifdef RE_FIXUP_RX
1964251881Speterstatic __inline void
1965251881Speterre_fixup_rx(struct mbuf *m)
1966251881Speter{
1967251881Speter	int                     i;
1968251881Speter	uint16_t                *src, *dst;
1969251881Speter
1970251881Speter	src = mtod(m, uint16_t *);
1971251881Speter	dst = src - (RE_ETHER_ALIGN - ETHER_ALIGN) / sizeof *src;
1972251881Speter
1973251881Speter	for (i = 0; i < (m->m_len / sizeof(uint16_t) + 1); i++)
1974251881Speter		*dst++ = *src++;
1975251881Speter
1976251881Speter	m->m_data -= RE_ETHER_ALIGN - ETHER_ALIGN;
1977251881Speter}
1978251881Speter#endif
1979251881Speter
1980251881Speterstatic int
1981251881Speterre_tx_list_init(struct rl_softc *sc)
1982251881Speter{
1983251881Speter	struct rl_desc		*desc;
1984251881Speter	int			i;
1985251881Speter
1986251881Speter	RL_LOCK_ASSERT(sc);
1987251881Speter
1988251881Speter	bzero(sc->rl_ldata.rl_tx_list,
1989251881Speter	    sc->rl_ldata.rl_tx_desc_cnt * sizeof(struct rl_desc));
1990251881Speter	for (i = 0; i < sc->rl_ldata.rl_tx_desc_cnt; i++)
1991251881Speter		sc->rl_ldata.rl_tx_desc[i].tx_m = NULL;
1992251881Speter	/* Set EOR. */
1993251881Speter	desc = &sc->rl_ldata.rl_tx_list[sc->rl_ldata.rl_tx_desc_cnt - 1];
1994251881Speter	desc->rl_cmdstat |= htole32(RL_TDESC_CMD_EOR);
1995251881Speter
1996251881Speter	bus_dmamap_sync(sc->rl_ldata.rl_tx_list_tag,
1997251881Speter	    sc->rl_ldata.rl_tx_list_map,
1998251881Speter	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1999251881Speter
2000251881Speter	sc->rl_ldata.rl_tx_prodidx = 0;
2001251881Speter	sc->rl_ldata.rl_tx_considx = 0;
2002251881Speter	sc->rl_ldata.rl_tx_free = sc->rl_ldata.rl_tx_desc_cnt;
2003251881Speter
2004251881Speter	return (0);
2005251881Speter}
2006251881Speter
2007251881Speterstatic int
2008251881Speterre_rx_list_init(struct rl_softc *sc)
2009251881Speter{
2010251881Speter	int			error, i;
2011251881Speter
2012251881Speter	bzero(sc->rl_ldata.rl_rx_list,
2013251881Speter	    sc->rl_ldata.rl_rx_desc_cnt * sizeof(struct rl_desc));
2014251881Speter	for (i = 0; i < sc->rl_ldata.rl_rx_desc_cnt; i++) {
2015251881Speter		sc->rl_ldata.rl_rx_desc[i].rx_m = NULL;
2016251881Speter		if ((error = re_newbuf(sc, i)) != 0)
2017251881Speter			return (error);
2018251881Speter	}
2019251881Speter
2020251881Speter	/* Flush the RX descriptors */
2021251881Speter
2022251881Speter	bus_dmamap_sync(sc->rl_ldata.rl_rx_list_tag,
2023251881Speter	    sc->rl_ldata.rl_rx_list_map,
2024251881Speter	    BUS_DMASYNC_PREWRITE|BUS_DMASYNC_PREREAD);
2025251881Speter
2026251881Speter	sc->rl_ldata.rl_rx_prodidx = 0;
2027251881Speter	sc->rl_head = sc->rl_tail = NULL;
2028251881Speter	sc->rl_int_rx_act = 0;
2029251881Speter
2030251881Speter	return (0);
2031251881Speter}
2032251881Speter
2033251881Speterstatic int
2034251881Speterre_jrx_list_init(struct rl_softc *sc)
2035251881Speter{
2036251881Speter	int			error, i;
2037251881Speter
2038251881Speter	bzero(sc->rl_ldata.rl_rx_list,
2039251881Speter	    sc->rl_ldata.rl_rx_desc_cnt * sizeof(struct rl_desc));
2040251881Speter	for (i = 0; i < sc->rl_ldata.rl_rx_desc_cnt; i++) {
2041251881Speter		sc->rl_ldata.rl_jrx_desc[i].rx_m = NULL;
2042251881Speter		if ((error = re_jumbo_newbuf(sc, i)) != 0)
2043251881Speter			return (error);
2044251881Speter	}
2045251881Speter
2046251881Speter	bus_dmamap_sync(sc->rl_ldata.rl_rx_list_tag,
2047251881Speter	    sc->rl_ldata.rl_rx_list_map,
2048251881Speter	    BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
2049251881Speter
2050251881Speter	sc->rl_ldata.rl_rx_prodidx = 0;
2051251881Speter	sc->rl_head = sc->rl_tail = NULL;
2052251881Speter	sc->rl_int_rx_act = 0;
2053251881Speter
2054251881Speter	return (0);
2055251881Speter}
2056251881Speter
2057251881Speter/*
2058251881Speter * RX handler for C+ and 8169. For the gigE chips, we support
2059251881Speter * the reception of jumbo frames that have been fragmented
2060251881Speter * across multiple 2K mbuf cluster buffers.
2061251881Speter */
2062251881Speterstatic int
2063251881Speterre_rxeof(struct rl_softc *sc, int *rx_npktsp)
2064251881Speter{
2065251881Speter	struct mbuf		*m;
2066251881Speter	struct ifnet		*ifp;
2067251881Speter	int			i, rxerr, total_len;
2068251881Speter	struct rl_desc		*cur_rx;
2069251881Speter	u_int32_t		rxstat, rxvlan;
2070251881Speter	int			jumbo, maxpkt = 16, rx_npkts = 0;
2071251881Speter
2072251881Speter	RL_LOCK_ASSERT(sc);
2073251881Speter
2074251881Speter	ifp = sc->rl_ifp;
2075251881Speter	if (ifp->if_mtu > RL_MTU && (sc->rl_flags & RL_FLAG_JUMBOV2) != 0)
2076251881Speter		jumbo = 1;
2077251881Speter	else
2078251881Speter		jumbo = 0;
2079251881Speter
2080251881Speter	/* Invalidate the descriptor memory */
2081251881Speter
2082251881Speter	bus_dmamap_sync(sc->rl_ldata.rl_rx_list_tag,
2083251881Speter	    sc->rl_ldata.rl_rx_list_map,
2084251881Speter	    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
2085251881Speter
2086251881Speter	for (i = sc->rl_ldata.rl_rx_prodidx; maxpkt > 0;
2087251881Speter	    i = RL_RX_DESC_NXT(sc, i)) {
2088251881Speter		if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
2089251881Speter			break;
2090251881Speter		cur_rx = &sc->rl_ldata.rl_rx_list[i];
2091251881Speter		rxstat = le32toh(cur_rx->rl_cmdstat);
2092251881Speter		if ((rxstat & RL_RDESC_STAT_OWN) != 0)
2093251881Speter			break;
2094251881Speter		total_len = rxstat & sc->rl_rxlenmask;
2095251881Speter		rxvlan = le32toh(cur_rx->rl_vlanctl);
2096251881Speter		if (jumbo != 0)
2097251881Speter			m = sc->rl_ldata.rl_jrx_desc[i].rx_m;
2098251881Speter		else
2099251881Speter			m = sc->rl_ldata.rl_rx_desc[i].rx_m;
2100251881Speter
2101251881Speter		if ((sc->rl_flags & RL_FLAG_JUMBOV2) != 0 &&
2102251881Speter		    (rxstat & (RL_RDESC_STAT_SOF | RL_RDESC_STAT_EOF)) !=
2103251881Speter		    (RL_RDESC_STAT_SOF | RL_RDESC_STAT_EOF)) {
2104251881Speter			/*
2105251881Speter			 * RTL8168C or later controllers do not
2106251881Speter			 * support multi-fragment packet.
2107251881Speter			 */
2108251881Speter			re_discard_rxbuf(sc, i);
2109251881Speter			continue;
2110251881Speter		} else if ((rxstat & RL_RDESC_STAT_EOF) == 0) {
2111251881Speter			if (re_newbuf(sc, i) != 0) {
2112251881Speter				/*
2113251881Speter				 * If this is part of a multi-fragment packet,
2114251881Speter				 * discard all the pieces.
2115251881Speter				 */
2116251881Speter				if (sc->rl_head != NULL) {
2117251881Speter					m_freem(sc->rl_head);
2118251881Speter					sc->rl_head = sc->rl_tail = NULL;
2119251881Speter				}
2120251881Speter				re_discard_rxbuf(sc, i);
2121251881Speter				continue;
2122251881Speter			}
2123251881Speter			m->m_len = RE_RX_DESC_BUFLEN;
2124251881Speter			if (sc->rl_head == NULL)
2125251881Speter				sc->rl_head = sc->rl_tail = m;
2126251881Speter			else {
2127251881Speter				m->m_flags &= ~M_PKTHDR;
2128251881Speter				sc->rl_tail->m_next = m;
2129251881Speter				sc->rl_tail = m;
2130251881Speter			}
2131251881Speter			continue;
2132251881Speter		}
2133251881Speter
2134251881Speter		/*
2135251881Speter		 * NOTE: for the 8139C+, the frame length field
2136251881Speter		 * is always 12 bits in size, but for the gigE chips,
2137251881Speter		 * it is 13 bits (since the max RX frame length is 16K).
2138251881Speter		 * Unfortunately, all 32 bits in the status word
2139251881Speter		 * were already used, so to make room for the extra
2140251881Speter		 * length bit, RealTek took out the 'frame alignment
2141251881Speter		 * error' bit and shifted the other status bits
2142251881Speter		 * over one slot. The OWN, EOR, FS and LS bits are
2143251881Speter		 * still in the same places. We have already extracted
2144251881Speter		 * the frame length and checked the OWN bit, so rather
2145251881Speter		 * than using an alternate bit mapping, we shift the
2146251881Speter		 * status bits one space to the right so we can evaluate
2147251881Speter		 * them using the 8169 status as though it was in the
2148251881Speter		 * same format as that of the 8139C+.
2149251881Speter		 */
2150253734Speter		if (sc->rl_type == RL_8169)
2151251881Speter			rxstat >>= 1;
2152251881Speter
2153251881Speter		/*
2154251881Speter		 * if total_len > 2^13-1, both _RXERRSUM and _GIANT will be
2155251881Speter		 * set, but if CRC is clear, it will still be a valid frame.
2156251881Speter		 */
2157251881Speter		if ((rxstat & RL_RDESC_STAT_RXERRSUM) != 0) {
2158251881Speter			rxerr = 1;
2159251881Speter			if ((sc->rl_flags & RL_FLAG_JUMBOV2) == 0 &&
2160251881Speter			    total_len > 8191 &&
2161251881Speter			    (rxstat & RL_RDESC_STAT_ERRS) == RL_RDESC_STAT_GIANT)
2162251881Speter				rxerr = 0;
2163251881Speter			if (rxerr != 0) {
2164251881Speter				ifp->if_ierrors++;
2165251881Speter				/*
2166251881Speter				 * If this is part of a multi-fragment packet,
2167251881Speter				 * discard all the pieces.
2168251881Speter				 */
2169251881Speter				if (sc->rl_head != NULL) {
2170251881Speter					m_freem(sc->rl_head);
2171253734Speter					sc->rl_head = sc->rl_tail = NULL;
2172253734Speter				}
2173253734Speter				re_discard_rxbuf(sc, i);
2174253734Speter				continue;
2175253734Speter			}
2176253734Speter		}
2177253734Speter
2178253734Speter		/*
2179253734Speter		 * If allocating a replacement mbuf fails,
2180253734Speter		 * reload the current one.
2181251881Speter		 */
2182251881Speter		if (jumbo != 0)
2183251881Speter			rxerr = re_jumbo_newbuf(sc, i);
2184251881Speter		else
2185251881Speter			rxerr = re_newbuf(sc, i);
2186251881Speter		if (rxerr != 0) {
2187251881Speter			ifp->if_iqdrops++;
2188251881Speter			if (sc->rl_head != NULL) {
2189251881Speter				m_freem(sc->rl_head);
2190251881Speter				sc->rl_head = sc->rl_tail = NULL;
2191251881Speter			}
2192251881Speter			re_discard_rxbuf(sc, i);
2193251881Speter			continue;
2194251881Speter		}
2195251881Speter
2196251881Speter		if (sc->rl_head != NULL) {
2197251881Speter			if (jumbo != 0)
2198251881Speter				m->m_len = total_len;
2199251881Speter			else {
2200251881Speter				m->m_len = total_len % RE_RX_DESC_BUFLEN;
2201251881Speter				if (m->m_len == 0)
2202251881Speter					m->m_len = RE_RX_DESC_BUFLEN;
2203251881Speter			}
2204251881Speter			/*
2205251881Speter			 * Special case: if there's 4 bytes or less
2206251881Speter			 * in this buffer, the mbuf can be discarded:
2207251881Speter			 * the last 4 bytes is the CRC, which we don't
2208251881Speter			 * care about anyway.
2209251881Speter			 */
2210251881Speter			if (m->m_len <= ETHER_CRC_LEN) {
2211251881Speter				sc->rl_tail->m_len -=
2212251881Speter				    (ETHER_CRC_LEN - m->m_len);
2213251881Speter				m_freem(m);
2214251881Speter			} else {
2215251881Speter				m->m_len -= ETHER_CRC_LEN;
2216251881Speter				m->m_flags &= ~M_PKTHDR;
2217251881Speter				sc->rl_tail->m_next = m;
2218251881Speter			}
2219251881Speter			m = sc->rl_head;
2220251881Speter			sc->rl_head = sc->rl_tail = NULL;
2221251881Speter			m->m_pkthdr.len = total_len - ETHER_CRC_LEN;
2222251881Speter		} else
2223251881Speter			m->m_pkthdr.len = m->m_len =
2224251881Speter			    (total_len - ETHER_CRC_LEN);
2225251881Speter
2226251881Speter#ifdef RE_FIXUP_RX
2227251881Speter		re_fixup_rx(m);
2228251881Speter#endif
2229251881Speter		ifp->if_ipackets++;
2230251881Speter		m->m_pkthdr.rcvif = ifp;
2231251881Speter
2232251881Speter		/* Do RX checksumming if enabled */
2233251881Speter
2234251881Speter		if (ifp->if_capenable & IFCAP_RXCSUM) {
2235251881Speter			if ((sc->rl_flags & RL_FLAG_DESCV2) == 0) {
2236251881Speter				/* Check IP header checksum */
2237251881Speter				if (rxstat & RL_RDESC_STAT_PROTOID)
2238251881Speter					m->m_pkthdr.csum_flags |=
2239251881Speter					    CSUM_IP_CHECKED;
2240251881Speter				if (!(rxstat & RL_RDESC_STAT_IPSUMBAD))
2241251881Speter					m->m_pkthdr.csum_flags |=
2242251881Speter					    CSUM_IP_VALID;
2243251881Speter
2244251881Speter				/* Check TCP/UDP checksum */
2245251881Speter				if ((RL_TCPPKT(rxstat) &&
2246251881Speter				    !(rxstat & RL_RDESC_STAT_TCPSUMBAD)) ||
2247251881Speter				    (RL_UDPPKT(rxstat) &&
2248251881Speter				     !(rxstat & RL_RDESC_STAT_UDPSUMBAD))) {
2249251881Speter					m->m_pkthdr.csum_flags |=
2250251881Speter						CSUM_DATA_VALID|CSUM_PSEUDO_HDR;
2251251881Speter					m->m_pkthdr.csum_data = 0xffff;
2252251881Speter				}
2253251881Speter			} else {
2254251881Speter				/*
2255251881Speter				 * RTL8168C/RTL816CP/RTL8111C/RTL8111CP
2256251881Speter				 */
2257251881Speter				if ((rxstat & RL_RDESC_STAT_PROTOID) &&
2258251881Speter				    (rxvlan & RL_RDESC_IPV4))
2259251881Speter					m->m_pkthdr.csum_flags |=
2260251881Speter					    CSUM_IP_CHECKED;
2261251881Speter				if (!(rxstat & RL_RDESC_STAT_IPSUMBAD) &&
2262251881Speter				    (rxvlan & RL_RDESC_IPV4))
2263251881Speter					m->m_pkthdr.csum_flags |=
2264251881Speter					    CSUM_IP_VALID;
2265251881Speter				if (((rxstat & RL_RDESC_STAT_TCP) &&
2266251881Speter				    !(rxstat & RL_RDESC_STAT_TCPSUMBAD)) ||
2267251881Speter				    ((rxstat & RL_RDESC_STAT_UDP) &&
2268251881Speter				    !(rxstat & RL_RDESC_STAT_UDPSUMBAD))) {
2269251881Speter					m->m_pkthdr.csum_flags |=
2270251881Speter						CSUM_DATA_VALID|CSUM_PSEUDO_HDR;
2271251881Speter					m->m_pkthdr.csum_data = 0xffff;
2272251881Speter				}
2273251881Speter			}
2274251881Speter		}
2275251881Speter		maxpkt--;
2276251881Speter		if (rxvlan & RL_RDESC_VLANCTL_TAG) {
2277251881Speter			m->m_pkthdr.ether_vtag =
2278251881Speter			    bswap16((rxvlan & RL_RDESC_VLANCTL_DATA));
2279251881Speter			m->m_flags |= M_VLANTAG;
2280251881Speter		}
2281251881Speter		RL_UNLOCK(sc);
2282251881Speter		(*ifp->if_input)(ifp, m);
2283251881Speter		RL_LOCK(sc);
2284251881Speter		rx_npkts++;
2285251881Speter	}
2286251881Speter
2287251881Speter	/* Flush the RX DMA ring */
2288251881Speter
2289251881Speter	bus_dmamap_sync(sc->rl_ldata.rl_rx_list_tag,
2290251881Speter	    sc->rl_ldata.rl_rx_list_map,
2291251881Speter	    BUS_DMASYNC_PREWRITE|BUS_DMASYNC_PREREAD);
2292251881Speter
2293251881Speter	sc->rl_ldata.rl_rx_prodidx = i;
2294251881Speter
2295251881Speter	if (rx_npktsp != NULL)
2296251881Speter		*rx_npktsp = rx_npkts;
2297251881Speter	if (maxpkt)
2298251881Speter		return (EAGAIN);
2299251881Speter
2300251881Speter	return (0);
2301251881Speter}
2302251881Speter
2303251881Speterstatic void
2304251881Speterre_txeof(struct rl_softc *sc)
2305251881Speter{
2306251881Speter	struct ifnet		*ifp;
2307251881Speter	struct rl_txdesc	*txd;
2308251881Speter	u_int32_t		txstat;
2309251881Speter	int			cons;
2310251881Speter
2311251881Speter	cons = sc->rl_ldata.rl_tx_considx;
2312262253Speter	if (cons == sc->rl_ldata.rl_tx_prodidx)
2313262253Speter		return;
2314262253Speter
2315262253Speter	ifp = sc->rl_ifp;
2316262253Speter	/* Invalidate the TX descriptor list */
2317262253Speter	bus_dmamap_sync(sc->rl_ldata.rl_tx_list_tag,
2318251881Speter	    sc->rl_ldata.rl_tx_list_map,
2319251881Speter	    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
2320251881Speter
2321251881Speter	for (; cons != sc->rl_ldata.rl_tx_prodidx;
2322251881Speter	    cons = RL_TX_DESC_NXT(sc, cons)) {
2323251881Speter		txstat = le32toh(sc->rl_ldata.rl_tx_list[cons].rl_cmdstat);
2324251881Speter		if (txstat & RL_TDESC_STAT_OWN)
2325251881Speter			break;
2326251881Speter		/*
2327251881Speter		 * We only stash mbufs in the last descriptor
2328251881Speter		 * in a fragment chain, which also happens to
2329251881Speter		 * be the only place where the TX status bits
2330251881Speter		 * are valid.
2331251881Speter		 */
2332251881Speter		if (txstat & RL_TDESC_CMD_EOF) {
2333251881Speter			txd = &sc->rl_ldata.rl_tx_desc[cons];
2334251881Speter			bus_dmamap_sync(sc->rl_ldata.rl_tx_mtag,
2335251881Speter			    txd->tx_dmamap, BUS_DMASYNC_POSTWRITE);
2336251881Speter			bus_dmamap_unload(sc->rl_ldata.rl_tx_mtag,
2337251881Speter			    txd->tx_dmamap);
2338251881Speter			KASSERT(txd->tx_m != NULL,
2339251881Speter			    ("%s: freeing NULL mbufs!", __func__));
2340251881Speter			m_freem(txd->tx_m);
2341251881Speter			txd->tx_m = NULL;
2342251881Speter			if (txstat & (RL_TDESC_STAT_EXCESSCOL|
2343251881Speter			    RL_TDESC_STAT_COLCNT))
2344251881Speter				ifp->if_collisions++;
2345251881Speter			if (txstat & RL_TDESC_STAT_TXERRSUM)
2346251881Speter				ifp->if_oerrors++;
2347251881Speter			else
2348251881Speter				ifp->if_opackets++;
2349251881Speter		}
2350251881Speter		sc->rl_ldata.rl_tx_free++;
2351251881Speter		ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
2352251881Speter	}
2353251881Speter	sc->rl_ldata.rl_tx_considx = cons;
2354251881Speter
2355251881Speter	/* No changes made to the TX ring, so no flush needed */
2356251881Speter
2357251881Speter	if (sc->rl_ldata.rl_tx_free != sc->rl_ldata.rl_tx_desc_cnt) {
2358251881Speter#ifdef RE_TX_MODERATION
2359251881Speter		/*
2360251881Speter		 * If not all descriptors have been reaped yet, reload
2361251881Speter		 * the timer so that we will eventually get another
2362251881Speter		 * interrupt that will cause us to re-enter this routine.
2363251881Speter		 * This is done in case the transmitter has gone idle.
2364251881Speter		 */
2365251881Speter		CSR_WRITE_4(sc, RL_TIMERCNT, 1);
2366251881Speter#endif
2367251881Speter	} else
2368251881Speter		sc->rl_watchdog_timer = 0;
2369251881Speter}
2370251881Speter
2371251881Speterstatic void
2372251881Speterre_tick(void *xsc)
2373251881Speter{
2374251881Speter	struct rl_softc		*sc;
2375251881Speter	struct mii_data		*mii;
2376251881Speter
2377251881Speter	sc = xsc;
2378251881Speter
2379251881Speter	RL_LOCK_ASSERT(sc);
2380251881Speter
2381251881Speter	mii = device_get_softc(sc->rl_miibus);
2382251881Speter	mii_tick(mii);
2383251881Speter	if ((sc->rl_flags & RL_FLAG_LINK) == 0)
2384251881Speter		re_miibus_statchg(sc->rl_dev);
2385251881Speter	/*
2386251881Speter	 * Reclaim transmitted frames here. Technically it is not
2387251881Speter	 * necessary to do here but it ensures periodic reclamation
2388251881Speter	 * regardless of Tx completion interrupt which seems to be
2389251881Speter	 * lost on PCIe based controllers under certain situations.
2390251881Speter	 */
2391251881Speter	re_txeof(sc);
2392251881Speter	re_watchdog(sc);
2393251881Speter	callout_reset(&sc->rl_stat_callout, hz, re_tick, sc);
2394251881Speter}
2395251881Speter
2396251881Speter#ifdef DEVICE_POLLING
2397251881Speterstatic int
2398251881Speterre_poll(struct ifnet *ifp, enum poll_cmd cmd, int count)
2399251881Speter{
2400251881Speter	struct rl_softc *sc = ifp->if_softc;
2401251881Speter	int rx_npkts = 0;
2402251881Speter
2403251881Speter	RL_LOCK(sc);
2404251881Speter	if (ifp->if_drv_flags & IFF_DRV_RUNNING)
2405251881Speter		rx_npkts = re_poll_locked(ifp, cmd, count);
2406251881Speter	RL_UNLOCK(sc);
2407251881Speter	return (rx_npkts);
2408251881Speter}
2409251881Speter
2410251881Speterstatic int
2411251881Speterre_poll_locked(struct ifnet *ifp, enum poll_cmd cmd, int count)
2412251881Speter{
2413251881Speter	struct rl_softc *sc = ifp->if_softc;
2414253734Speter	int rx_npkts;
2415251881Speter
2416251881Speter	RL_LOCK_ASSERT(sc);
2417251881Speter
2418251881Speter	sc->rxcycles = count;
2419251881Speter	re_rxeof(sc, &rx_npkts);
2420251881Speter	re_txeof(sc);
2421251881Speter
2422251881Speter	if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
2423251881Speter		re_start_locked(ifp);
2424251881Speter
2425251881Speter	if (cmd == POLL_AND_CHECK_STATUS) { /* also check status register */
2426251881Speter		u_int16_t       status;
2427251881Speter
2428251881Speter		status = CSR_READ_2(sc, RL_ISR);
2429251881Speter		if (status == 0xffff)
2430251881Speter			return (rx_npkts);
2431253734Speter		if (status)
2432251881Speter			CSR_WRITE_2(sc, RL_ISR, status);
2433251881Speter		if ((status & (RL_ISR_TX_OK | RL_ISR_TX_DESC_UNAVAIL)) &&
2434251881Speter		    (sc->rl_flags & RL_FLAG_PCIE))
2435251881Speter			CSR_WRITE_1(sc, sc->rl_txstart, RL_TXSTART_START);
2436251881Speter
2437251881Speter		/*
2438251881Speter		 * XXX check behaviour on receiver stalls.
2439251881Speter		 */
2440251881Speter
2441251881Speter		if (status & RL_ISR_SYSTEM_ERR) {
2442251881Speter			ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
2443251881Speter			re_init_locked(sc);
2444251881Speter		}
2445251881Speter	}
2446251881Speter	return (rx_npkts);
2447251881Speter}
2448251881Speter#endif /* DEVICE_POLLING */
2449251881Speter
2450251881Speterstatic int
2451251881Speterre_intr(void *arg)
2452251881Speter{
2453251881Speter	struct rl_softc		*sc;
2454251881Speter	uint16_t		status;
2455251881Speter
2456251881Speter	sc = arg;
2457251881Speter
2458251881Speter	status = CSR_READ_2(sc, RL_ISR);
2459251881Speter	if (status == 0xFFFF || (status & RL_INTRS_CPLUS) == 0)
2460251881Speter                return (FILTER_STRAY);
2461251881Speter	CSR_WRITE_2(sc, RL_IMR, 0);
2462251881Speter
2463251881Speter	taskqueue_enqueue_fast(taskqueue_fast, &sc->rl_inttask);
2464251881Speter
2465251881Speter	return (FILTER_HANDLED);
2466251881Speter}
2467251881Speter
2468251881Speterstatic void
2469251881Speterre_int_task(void *arg, int npending)
2470251881Speter{
2471251881Speter	struct rl_softc		*sc;
2472251881Speter	struct ifnet		*ifp;
2473251881Speter	u_int16_t		status;
2474251881Speter	int			rval = 0;
2475251881Speter
2476251881Speter	sc = arg;
2477251881Speter	ifp = sc->rl_ifp;
2478251881Speter
2479251881Speter	RL_LOCK(sc);
2480251881Speter
2481251881Speter	status = CSR_READ_2(sc, RL_ISR);
2482251881Speter        CSR_WRITE_2(sc, RL_ISR, status);
2483251881Speter
2484251881Speter	if (sc->suspended ||
2485251881Speter	    (ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) {
2486251881Speter		RL_UNLOCK(sc);
2487251881Speter		return;
2488251881Speter	}
2489251881Speter
2490251881Speter#ifdef DEVICE_POLLING
2491251881Speter	if  (ifp->if_capenable & IFCAP_POLLING) {
2492251881Speter		RL_UNLOCK(sc);
2493251881Speter		return;
2494251881Speter	}
2495251881Speter#endif
2496251881Speter
2497251881Speter	if (status & (RL_ISR_RX_OK|RL_ISR_RX_ERR|RL_ISR_FIFO_OFLOW))
2498251881Speter		rval = re_rxeof(sc, NULL);
2499251881Speter
2500251881Speter	/*
2501251881Speter	 * Some chips will ignore a second TX request issued
2502251881Speter	 * while an existing transmission is in progress. If
2503251881Speter	 * the transmitter goes idle but there are still
2504251881Speter	 * packets waiting to be sent, we need to restart the
2505251881Speter	 * channel here to flush them out. This only seems to
2506251881Speter	 * be required with the PCIe devices.
2507251881Speter	 */
2508251881Speter	if ((status & (RL_ISR_TX_OK | RL_ISR_TX_DESC_UNAVAIL)) &&
2509251881Speter	    (sc->rl_flags & RL_FLAG_PCIE))
2510251881Speter		CSR_WRITE_1(sc, sc->rl_txstart, RL_TXSTART_START);
2511251881Speter	if (status & (
2512251881Speter#ifdef RE_TX_MODERATION
2513251881Speter	    RL_ISR_TIMEOUT_EXPIRED|
2514251881Speter#else
2515251881Speter	    RL_ISR_TX_OK|
2516251881Speter#endif
2517251881Speter	    RL_ISR_TX_ERR|RL_ISR_TX_DESC_UNAVAIL))
2518251881Speter		re_txeof(sc);
2519251881Speter
2520251881Speter	if (status & RL_ISR_SYSTEM_ERR) {
2521251881Speter		ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
2522251881Speter		re_init_locked(sc);
2523251881Speter	}
2524251881Speter
2525251881Speter	if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
2526251881Speter		re_start_locked(ifp);
2527251881Speter
2528251881Speter	RL_UNLOCK(sc);
2529251881Speter
2530251881Speter        if ((CSR_READ_2(sc, RL_ISR) & RL_INTRS_CPLUS) || rval) {
2531251881Speter		taskqueue_enqueue_fast(taskqueue_fast, &sc->rl_inttask);
2532251881Speter		return;
2533251881Speter	}
2534251881Speter
2535251881Speter	CSR_WRITE_2(sc, RL_IMR, RL_INTRS_CPLUS);
2536251881Speter}
2537251881Speter
2538251881Speterstatic void
2539251881Speterre_intr_msi(void *xsc)
2540251881Speter{
2541251881Speter	struct rl_softc		*sc;
2542251881Speter	struct ifnet		*ifp;
2543251881Speter	uint16_t		intrs, status;
2544251881Speter
2545251881Speter	sc = xsc;
2546251881Speter	RL_LOCK(sc);
2547251881Speter
2548251881Speter	ifp = sc->rl_ifp;
2549251881Speter#ifdef DEVICE_POLLING
2550251881Speter	if (ifp->if_capenable & IFCAP_POLLING) {
2551251881Speter		RL_UNLOCK(sc);
2552251881Speter		return;
2553251881Speter	}
2554251881Speter#endif
2555251881Speter	/* Disable interrupts. */
2556251881Speter	CSR_WRITE_2(sc, RL_IMR, 0);
2557251881Speter	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) {
2558251881Speter		RL_UNLOCK(sc);
2559251881Speter		return;
2560251881Speter	}
2561251881Speter
2562251881Speter	intrs = RL_INTRS_CPLUS;
2563251881Speter	status = CSR_READ_2(sc, RL_ISR);
2564251881Speter        CSR_WRITE_2(sc, RL_ISR, status);
2565251881Speter	if (sc->rl_int_rx_act > 0) {
2566251881Speter		intrs &= ~(RL_ISR_RX_OK | RL_ISR_RX_ERR | RL_ISR_FIFO_OFLOW |
2567251881Speter		    RL_ISR_RX_OVERRUN);
2568251881Speter		status &= ~(RL_ISR_RX_OK | RL_ISR_RX_ERR | RL_ISR_FIFO_OFLOW |
2569251881Speter		    RL_ISR_RX_OVERRUN);
2570251881Speter	}
2571251881Speter
2572251881Speter	if (status & (RL_ISR_TIMEOUT_EXPIRED | RL_ISR_RX_OK | RL_ISR_RX_ERR |
2573251881Speter	    RL_ISR_FIFO_OFLOW | RL_ISR_RX_OVERRUN)) {
2574251881Speter		re_rxeof(sc, NULL);
2575251881Speter		if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) {
2576251881Speter			if (sc->rl_int_rx_mod != 0 &&
2577251881Speter			    (status & (RL_ISR_RX_OK | RL_ISR_RX_ERR |
2578251881Speter			    RL_ISR_FIFO_OFLOW | RL_ISR_RX_OVERRUN)) != 0) {
2579251881Speter				/* Rearm one-shot timer. */
2580251881Speter				CSR_WRITE_4(sc, RL_TIMERCNT, 1);
2581251881Speter				intrs &= ~(RL_ISR_RX_OK | RL_ISR_RX_ERR |
2582251881Speter				    RL_ISR_FIFO_OFLOW | RL_ISR_RX_OVERRUN);
2583251881Speter				sc->rl_int_rx_act = 1;
2584251881Speter			} else {
2585251881Speter				intrs |= RL_ISR_RX_OK | RL_ISR_RX_ERR |
2586251881Speter				    RL_ISR_FIFO_OFLOW | RL_ISR_RX_OVERRUN;
2587251881Speter				sc->rl_int_rx_act = 0;
2588251881Speter			}
2589251881Speter		}
2590251881Speter	}
2591251881Speter
2592251881Speter	/*
2593251881Speter	 * Some chips will ignore a second TX request issued
2594251881Speter	 * while an existing transmission is in progress. If
2595251881Speter	 * the transmitter goes idle but there are still
2596251881Speter	 * packets waiting to be sent, we need to restart the
2597251881Speter	 * channel here to flush them out. This only seems to
2598251881Speter	 * be required with the PCIe devices.
2599251881Speter	 */
2600251881Speter	if ((status & (RL_ISR_TX_OK | RL_ISR_TX_DESC_UNAVAIL)) &&
2601251881Speter	    (sc->rl_flags & RL_FLAG_PCIE))
2602251881Speter		CSR_WRITE_1(sc, sc->rl_txstart, RL_TXSTART_START);
2603251881Speter	if (status & (RL_ISR_TX_OK | RL_ISR_TX_ERR | RL_ISR_TX_DESC_UNAVAIL))
2604251881Speter		re_txeof(sc);
2605251881Speter
2606251881Speter	if (status & RL_ISR_SYSTEM_ERR) {
2607251881Speter		ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
2608251881Speter		re_init_locked(sc);
2609251881Speter	}
2610251881Speter
2611251881Speter	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) {
2612251881Speter		if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
2613251881Speter			re_start_locked(ifp);
2614251881Speter		CSR_WRITE_2(sc, RL_IMR, intrs);
2615251881Speter	}
2616251881Speter	RL_UNLOCK(sc);
2617251881Speter}
2618251881Speter
2619251881Speterstatic int
2620251881Speterre_encap(struct rl_softc *sc, struct mbuf **m_head)
2621251881Speter{
2622251881Speter	struct rl_txdesc	*txd, *txd_last;
2623251881Speter	bus_dma_segment_t	segs[RL_NTXSEGS];
2624251881Speter	bus_dmamap_t		map;
2625251881Speter	struct mbuf		*m_new;
2626251881Speter	struct rl_desc		*desc;
2627251881Speter	int			nsegs, prod;
2628251881Speter	int			i, error, ei, si;
2629251881Speter	int			padlen;
2630251881Speter	uint32_t		cmdstat, csum_flags, vlanctl;
2631251881Speter
2632251881Speter	RL_LOCK_ASSERT(sc);
2633251881Speter	M_ASSERTPKTHDR((*m_head));
2634251881Speter
2635251881Speter	/*
2636251881Speter	 * With some of the RealTek chips, using the checksum offload
2637251881Speter	 * support in conjunction with the autopadding feature results
2638251881Speter	 * in the transmission of corrupt frames. For example, if we
2639251881Speter	 * need to send a really small IP fragment that's less than 60
2640251881Speter	 * bytes in size, and IP header checksumming is enabled, the
2641251881Speter	 * resulting ethernet frame that appears on the wire will
2642251881Speter	 * have garbled payload. To work around this, if TX IP checksum
2643251881Speter	 * offload is enabled, we always manually pad short frames out
2644251881Speter	 * to the minimum ethernet frame size.
2645251881Speter	 */
2646251881Speter	if ((sc->rl_flags & RL_FLAG_AUTOPAD) == 0 &&
2647251881Speter	    (*m_head)->m_pkthdr.len < RL_IP4CSUMTX_PADLEN &&
2648251881Speter	    ((*m_head)->m_pkthdr.csum_flags & CSUM_IP) != 0) {
2649251881Speter		padlen = RL_MIN_FRAMELEN - (*m_head)->m_pkthdr.len;
2650251881Speter		if (M_WRITABLE(*m_head) == 0) {
2651251881Speter			/* Get a writable copy. */
2652251881Speter			m_new = m_dup(*m_head, M_DONTWAIT);
2653251881Speter			m_freem(*m_head);
2654251881Speter			if (m_new == NULL) {
2655251881Speter				*m_head = NULL;
2656251881Speter				return (ENOBUFS);
2657251881Speter			}
2658251881Speter			*m_head = m_new;
2659251881Speter		}
2660251881Speter		if ((*m_head)->m_next != NULL ||
2661251881Speter		    M_TRAILINGSPACE(*m_head) < padlen) {
2662251881Speter			m_new = m_defrag(*m_head, M_DONTWAIT);
2663251881Speter			if (m_new == NULL) {
2664251881Speter				m_freem(*m_head);
2665251881Speter				*m_head = NULL;
2666251881Speter				return (ENOBUFS);
2667251881Speter			}
2668251881Speter		} else
2669251881Speter			m_new = *m_head;
2670251881Speter
2671251881Speter		/*
2672251881Speter		 * Manually pad short frames, and zero the pad space
2673251881Speter		 * to avoid leaking data.
2674251881Speter		 */
2675251881Speter		bzero(mtod(m_new, char *) + m_new->m_pkthdr.len, padlen);
2676251881Speter		m_new->m_pkthdr.len += padlen;
2677251881Speter		m_new->m_len = m_new->m_pkthdr.len;
2678251881Speter		*m_head = m_new;
2679251881Speter	}
2680251881Speter
2681251881Speter	prod = sc->rl_ldata.rl_tx_prodidx;
2682251881Speter	txd = &sc->rl_ldata.rl_tx_desc[prod];
2683251881Speter	error = bus_dmamap_load_mbuf_sg(sc->rl_ldata.rl_tx_mtag, txd->tx_dmamap,
2684251881Speter	    *m_head, segs, &nsegs, BUS_DMA_NOWAIT);
2685251881Speter	if (error == EFBIG) {
2686251881Speter		m_new = m_collapse(*m_head, M_DONTWAIT, RL_NTXSEGS);
2687251881Speter		if (m_new == NULL) {
2688251881Speter			m_freem(*m_head);
2689251881Speter			*m_head = NULL;
2690251881Speter			return (ENOBUFS);
2691251881Speter		}
2692251881Speter		*m_head = m_new;
2693251881Speter		error = bus_dmamap_load_mbuf_sg(sc->rl_ldata.rl_tx_mtag,
2694251881Speter		    txd->tx_dmamap, *m_head, segs, &nsegs, BUS_DMA_NOWAIT);
2695251881Speter		if (error != 0) {
2696251881Speter			m_freem(*m_head);
2697251881Speter			*m_head = NULL;
2698251881Speter			return (error);
2699251881Speter		}
2700251881Speter	} else if (error != 0)
2701251881Speter		return (error);
2702251881Speter	if (nsegs == 0) {
2703251881Speter		m_freem(*m_head);
2704251881Speter		*m_head = NULL;
2705251881Speter		return (EIO);
2706251881Speter	}
2707251881Speter
2708251881Speter	/* Check for number of available descriptors. */
2709251881Speter	if (sc->rl_ldata.rl_tx_free - nsegs <= 1) {
2710251881Speter		bus_dmamap_unload(sc->rl_ldata.rl_tx_mtag, txd->tx_dmamap);
2711251881Speter		return (ENOBUFS);
2712251881Speter	}
2713251881Speter
2714251881Speter	bus_dmamap_sync(sc->rl_ldata.rl_tx_mtag, txd->tx_dmamap,
2715251881Speter	    BUS_DMASYNC_PREWRITE);
2716251881Speter
2717251881Speter	/*
2718251881Speter	 * Set up checksum offload. Note: checksum offload bits must
2719251881Speter	 * appear in all descriptors of a multi-descriptor transmit
2720251881Speter	 * attempt. This is according to testing done with an 8169
2721251881Speter	 * chip. This is a requirement.
2722251881Speter	 */
2723251881Speter	vlanctl = 0;
2724251881Speter	csum_flags = 0;
2725251881Speter	if (((*m_head)->m_pkthdr.csum_flags & CSUM_TSO) != 0) {
2726251881Speter		if ((sc->rl_flags & RL_FLAG_DESCV2) != 0) {
2727251881Speter			csum_flags |= RL_TDESC_CMD_LGSEND;
2728251881Speter			vlanctl |= ((uint32_t)(*m_head)->m_pkthdr.tso_segsz <<
2729251881Speter			    RL_TDESC_CMD_MSSVALV2_SHIFT);
2730251881Speter		} else {
2731251881Speter			csum_flags |= RL_TDESC_CMD_LGSEND |
2732251881Speter			    ((uint32_t)(*m_head)->m_pkthdr.tso_segsz <<
2733251881Speter			    RL_TDESC_CMD_MSSVAL_SHIFT);
2734251881Speter		}
2735251881Speter	} else {
2736251881Speter		/*
2737251881Speter		 * Unconditionally enable IP checksum if TCP or UDP
2738251881Speter		 * checksum is required. Otherwise, TCP/UDP checksum
2739251881Speter		 * does't make effects.
2740251881Speter		 */
2741251881Speter		if (((*m_head)->m_pkthdr.csum_flags & RE_CSUM_FEATURES) != 0) {
2742251881Speter			if ((sc->rl_flags & RL_FLAG_DESCV2) == 0) {
2743251881Speter				csum_flags |= RL_TDESC_CMD_IPCSUM;
2744251881Speter				if (((*m_head)->m_pkthdr.csum_flags &
2745251881Speter				    CSUM_TCP) != 0)
2746251881Speter					csum_flags |= RL_TDESC_CMD_TCPCSUM;
2747251881Speter				if (((*m_head)->m_pkthdr.csum_flags &
2748251881Speter				    CSUM_UDP) != 0)
2749251881Speter					csum_flags |= RL_TDESC_CMD_UDPCSUM;
2750251881Speter			} else {
2751251881Speter				vlanctl |= RL_TDESC_CMD_IPCSUMV2;
2752251881Speter				if (((*m_head)->m_pkthdr.csum_flags &
2753251881Speter				    CSUM_TCP) != 0)
2754251881Speter					vlanctl |= RL_TDESC_CMD_TCPCSUMV2;
2755251881Speter				if (((*m_head)->m_pkthdr.csum_flags &
2756251881Speter				    CSUM_UDP) != 0)
2757251881Speter					vlanctl |= RL_TDESC_CMD_UDPCSUMV2;
2758251881Speter			}
2759251881Speter		}
2760251881Speter	}
2761251881Speter
2762251881Speter	/*
2763251881Speter	 * Set up hardware VLAN tagging. Note: vlan tag info must
2764251881Speter	 * appear in all descriptors of a multi-descriptor
2765251881Speter	 * transmission attempt.
2766251881Speter	 */
2767251881Speter	if ((*m_head)->m_flags & M_VLANTAG)
2768251881Speter		vlanctl |= bswap16((*m_head)->m_pkthdr.ether_vtag) |
2769251881Speter		    RL_TDESC_VLANCTL_TAG;
2770251881Speter
2771251881Speter	si = prod;
2772251881Speter	for (i = 0; i < nsegs; i++, prod = RL_TX_DESC_NXT(sc, prod)) {
2773251881Speter		desc = &sc->rl_ldata.rl_tx_list[prod];
2774251881Speter		desc->rl_vlanctl = htole32(vlanctl);
2775251881Speter		desc->rl_bufaddr_lo = htole32(RL_ADDR_LO(segs[i].ds_addr));
2776251881Speter		desc->rl_bufaddr_hi = htole32(RL_ADDR_HI(segs[i].ds_addr));
2777251881Speter		cmdstat = segs[i].ds_len;
2778251881Speter		if (i != 0)
2779251881Speter			cmdstat |= RL_TDESC_CMD_OWN;
2780251881Speter		if (prod == sc->rl_ldata.rl_tx_desc_cnt - 1)
2781251881Speter			cmdstat |= RL_TDESC_CMD_EOR;
2782251881Speter		desc->rl_cmdstat = htole32(cmdstat | csum_flags);
2783251881Speter		sc->rl_ldata.rl_tx_free--;
2784251881Speter	}
2785251881Speter	/* Update producer index. */
2786251881Speter	sc->rl_ldata.rl_tx_prodidx = prod;
2787251881Speter
2788251881Speter	/* Set EOF on the last descriptor. */
2789251881Speter	ei = RL_TX_DESC_PRV(sc, prod);
2790251881Speter	desc = &sc->rl_ldata.rl_tx_list[ei];
2791251881Speter	desc->rl_cmdstat |= htole32(RL_TDESC_CMD_EOF);
2792251881Speter
2793251881Speter	desc = &sc->rl_ldata.rl_tx_list[si];
2794251881Speter	/* Set SOF and transfer ownership of packet to the chip. */
2795251881Speter	desc->rl_cmdstat |= htole32(RL_TDESC_CMD_OWN | RL_TDESC_CMD_SOF);
2796251881Speter
2797251881Speter	/*
2798251881Speter	 * Insure that the map for this transmission
2799251881Speter	 * is placed at the array index of the last descriptor
2800251881Speter	 * in this chain.  (Swap last and first dmamaps.)
2801251881Speter	 */
2802251881Speter	txd_last = &sc->rl_ldata.rl_tx_desc[ei];
2803251881Speter	map = txd->tx_dmamap;
2804251881Speter	txd->tx_dmamap = txd_last->tx_dmamap;
2805251881Speter	txd_last->tx_dmamap = map;
2806251881Speter	txd_last->tx_m = *m_head;
2807251881Speter
2808251881Speter	return (0);
2809251881Speter}
2810251881Speter
2811251881Speterstatic void
2812251881Speterre_start(struct ifnet *ifp)
2813251881Speter{
2814251881Speter	struct rl_softc		*sc;
2815251881Speter
2816251881Speter	sc = ifp->if_softc;
2817251881Speter	RL_LOCK(sc);
2818251881Speter	re_start_locked(ifp);
2819251881Speter	RL_UNLOCK(sc);
2820251881Speter}
2821251881Speter
2822251881Speter/*
2823251881Speter * Main transmit routine for C+ and gigE NICs.
2824251881Speter */
2825251881Speterstatic void
2826251881Speterre_start_locked(struct ifnet *ifp)
2827251881Speter{
2828251881Speter	struct rl_softc		*sc;
2829251881Speter	struct mbuf		*m_head;
2830251881Speter	int			queued;
2831251881Speter
2832251881Speter	sc = ifp->if_softc;
2833251881Speter
2834251881Speter	if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) !=
2835251881Speter	    IFF_DRV_RUNNING || (sc->rl_flags & RL_FLAG_LINK) == 0)
2836251881Speter		return;
2837251881Speter
2838251881Speter	for (queued = 0; !IFQ_DRV_IS_EMPTY(&ifp->if_snd) &&
2839251881Speter	    sc->rl_ldata.rl_tx_free > 1;) {
2840251881Speter		IFQ_DRV_DEQUEUE(&ifp->if_snd, m_head);
2841251881Speter		if (m_head == NULL)
2842251881Speter			break;
2843251881Speter
2844251881Speter		if (re_encap(sc, &m_head) != 0) {
2845251881Speter			if (m_head == NULL)
2846251881Speter				break;
2847251881Speter			IFQ_DRV_PREPEND(&ifp->if_snd, m_head);
2848251881Speter			ifp->if_drv_flags |= IFF_DRV_OACTIVE;
2849251881Speter			break;
2850251881Speter		}
2851251881Speter
2852251881Speter		/*
2853251881Speter		 * If there's a BPF listener, bounce a copy of this frame
2854251881Speter		 * to him.
2855251881Speter		 */
2856251881Speter		ETHER_BPF_MTAP(ifp, m_head);
2857251881Speter
2858251881Speter		queued++;
2859251881Speter	}
2860251881Speter
2861251881Speter	if (queued == 0) {
2862251881Speter#ifdef RE_TX_MODERATION
2863251881Speter		if (sc->rl_ldata.rl_tx_free != sc->rl_ldata.rl_tx_desc_cnt)
2864251881Speter			CSR_WRITE_4(sc, RL_TIMERCNT, 1);
2865251881Speter#endif
2866251881Speter		return;
2867251881Speter	}
2868251881Speter
2869251881Speter	/* Flush the TX descriptors */
2870251881Speter
2871251881Speter	bus_dmamap_sync(sc->rl_ldata.rl_tx_list_tag,
2872251881Speter	    sc->rl_ldata.rl_tx_list_map,
2873251881Speter	    BUS_DMASYNC_PREWRITE|BUS_DMASYNC_PREREAD);
2874251881Speter
2875251881Speter	CSR_WRITE_1(sc, sc->rl_txstart, RL_TXSTART_START);
2876251881Speter
2877251881Speter#ifdef RE_TX_MODERATION
2878251881Speter	/*
2879251881Speter	 * Use the countdown timer for interrupt moderation.
2880251881Speter	 * 'TX done' interrupts are disabled. Instead, we reset the
2881251881Speter	 * countdown timer, which will begin counting until it hits
2882251881Speter	 * the value in the TIMERINT register, and then trigger an
2883251881Speter	 * interrupt. Each time we write to the TIMERCNT register,
2884251881Speter	 * the timer count is reset to 0.
2885251881Speter	 */
2886251881Speter	CSR_WRITE_4(sc, RL_TIMERCNT, 1);
2887251881Speter#endif
2888251881Speter
2889251881Speter	/*
2890251881Speter	 * Set a timeout in case the chip goes out to lunch.
2891251881Speter	 */
2892251881Speter	sc->rl_watchdog_timer = 5;
2893251881Speter}
2894251881Speter
2895251881Speterstatic void
2896251881Speterre_set_jumbo(struct rl_softc *sc, int jumbo)
2897251881Speter{
2898251881Speter
2899251881Speter	if (sc->rl_hwrev->rl_rev == RL_HWREV_8168E_VL) {
2900251881Speter		pci_set_max_read_req(sc->rl_dev, 4096);
2901251881Speter		return;
2902251881Speter	}
2903251881Speter
2904251881Speter	CSR_WRITE_1(sc, RL_EECMD, RL_EEMODE_WRITECFG);
2905251881Speter	if (jumbo != 0) {
2906251881Speter		CSR_WRITE_1(sc, RL_CFG3, CSR_READ_1(sc, RL_CFG3) |
2907251881Speter		    RL_CFG3_JUMBO_EN0);
2908251881Speter		switch (sc->rl_hwrev->rl_rev) {
2909251881Speter		case RL_HWREV_8168DP:
2910251881Speter			break;
2911251881Speter		case RL_HWREV_8168E:
2912251881Speter			CSR_WRITE_1(sc, RL_CFG4, CSR_READ_1(sc, RL_CFG4) |
2913251881Speter			    0x01);
2914251881Speter			break;
2915251881Speter		default:
2916251881Speter			CSR_WRITE_1(sc, RL_CFG4, CSR_READ_1(sc, RL_CFG4) |
2917251881Speter			    RL_CFG4_JUMBO_EN1);
2918251881Speter		}
2919251881Speter	} else {
2920251881Speter		CSR_WRITE_1(sc, RL_CFG3, CSR_READ_1(sc, RL_CFG3) &
2921251881Speter		    ~RL_CFG3_JUMBO_EN0);
2922251881Speter		switch (sc->rl_hwrev->rl_rev) {
2923251881Speter		case RL_HWREV_8168DP:
2924251881Speter			break;
2925251881Speter		case RL_HWREV_8168E:
2926251881Speter			CSR_WRITE_1(sc, RL_CFG4, CSR_READ_1(sc, RL_CFG4) &
2927251881Speter			    ~0x01);
2928251881Speter			break;
2929251881Speter		default:
2930251881Speter			CSR_WRITE_1(sc, RL_CFG4, CSR_READ_1(sc, RL_CFG4) &
2931251881Speter			    ~RL_CFG4_JUMBO_EN1);
2932251881Speter		}
2933251881Speter	}
2934251881Speter	CSR_WRITE_1(sc, RL_EECMD, RL_EEMODE_OFF);
2935251881Speter
2936251881Speter	switch (sc->rl_hwrev->rl_rev) {
2937251881Speter	case RL_HWREV_8168DP:
2938251881Speter		pci_set_max_read_req(sc->rl_dev, 4096);
2939251881Speter		break;
2940251881Speter	default:
2941251881Speter		if (jumbo != 0)
2942251881Speter			pci_set_max_read_req(sc->rl_dev, 512);
2943251881Speter		else
2944251881Speter			pci_set_max_read_req(sc->rl_dev, 4096);
2945251881Speter	}
2946251881Speter}
2947251881Speter
2948251881Speterstatic void
2949251881Speterre_init(void *xsc)
2950251881Speter{
2951251881Speter	struct rl_softc		*sc = xsc;
2952251881Speter
2953251881Speter	RL_LOCK(sc);
2954251881Speter	re_init_locked(sc);
2955251881Speter	RL_UNLOCK(sc);
2956251881Speter}
2957251881Speter
2958251881Speterstatic void
2959251881Speterre_init_locked(struct rl_softc *sc)
2960251881Speter{
2961251881Speter	struct ifnet		*ifp = sc->rl_ifp;
2962251881Speter	struct mii_data		*mii;
2963251881Speter	uint32_t		reg;
2964251881Speter	uint16_t		cfg;
2965251881Speter	union {
2966251881Speter		uint32_t align_dummy;
2967251881Speter		u_char eaddr[ETHER_ADDR_LEN];
2968251881Speter        } eaddr;
2969251881Speter
2970251881Speter	RL_LOCK_ASSERT(sc);
2971251881Speter
2972251881Speter	mii = device_get_softc(sc->rl_miibus);
2973251881Speter
2974251881Speter	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0)
2975251881Speter		return;
2976251881Speter
2977251881Speter	/*
2978251881Speter	 * Cancel pending I/O and free all RX/TX buffers.
2979251881Speter	 */
2980251881Speter	re_stop(sc);
2981251881Speter
2982251881Speter	/* Put controller into known state. */
2983251881Speter	re_reset(sc);
2984251881Speter
2985251881Speter	/*
2986251881Speter	 * For C+ mode, initialize the RX descriptors and mbufs.
2987251881Speter	 */
2988251881Speter	if ((sc->rl_flags & RL_FLAG_JUMBOV2) != 0) {
2989251881Speter		if (ifp->if_mtu > RL_MTU) {
2990251881Speter			if (re_jrx_list_init(sc) != 0) {
2991251881Speter				device_printf(sc->rl_dev,
2992251881Speter				    "no memory for jumbo RX buffers\n");
2993251881Speter				re_stop(sc);
2994251881Speter				return;
2995251881Speter			}
2996251881Speter			/* Disable checksum offloading for jumbo frames. */
2997251881Speter			ifp->if_capenable &= ~(IFCAP_HWCSUM | IFCAP_TSO4);
2998251881Speter			ifp->if_hwassist &= ~(RE_CSUM_FEATURES | CSUM_TSO);
2999251881Speter		} else {
3000251881Speter			if (re_rx_list_init(sc) != 0) {
3001251881Speter				device_printf(sc->rl_dev,
3002251881Speter				    "no memory for RX buffers\n");
3003251881Speter				re_stop(sc);
3004251881Speter				return;
3005251881Speter			}
3006251881Speter		}
3007251881Speter		re_set_jumbo(sc, ifp->if_mtu > RL_MTU);
3008251881Speter	} else {
3009251881Speter		if (re_rx_list_init(sc) != 0) {
3010251881Speter			device_printf(sc->rl_dev, "no memory for RX buffers\n");
3011251881Speter			re_stop(sc);
3012251881Speter			return;
3013251881Speter		}
3014251881Speter		if ((sc->rl_flags & RL_FLAG_PCIE) != 0 &&
3015251881Speter		    pci_get_device(sc->rl_dev) != RT_DEVICEID_8101E) {
3016251881Speter			if (ifp->if_mtu > RL_MTU)
3017251881Speter				pci_set_max_read_req(sc->rl_dev, 512);
3018251881Speter			else
3019251881Speter				pci_set_max_read_req(sc->rl_dev, 4096);
3020251881Speter		}
3021251881Speter	}
3022251881Speter	re_tx_list_init(sc);
3023251881Speter
3024251881Speter	/*
3025251881Speter	 * Enable C+ RX and TX mode, as well as VLAN stripping and
3026251881Speter	 * RX checksum offload. We must configure the C+ register
3027251881Speter	 * before all others.
3028251881Speter	 */
3029251881Speter	cfg = RL_CPLUSCMD_PCI_MRW;
3030251881Speter	if ((ifp->if_capenable & IFCAP_RXCSUM) != 0)
3031251881Speter		cfg |= RL_CPLUSCMD_RXCSUM_ENB;
3032251881Speter	if ((ifp->if_capenable & IFCAP_VLAN_HWTAGGING) != 0)
3033251881Speter		cfg |= RL_CPLUSCMD_VLANSTRIP;
3034251881Speter	if ((sc->rl_flags & RL_FLAG_MACSTAT) != 0) {
3035251881Speter		cfg |= RL_CPLUSCMD_MACSTAT_DIS;
3036251881Speter		/* XXX magic. */
3037251881Speter		cfg |= 0x0001;
3038251881Speter	} else
3039251881Speter		cfg |= RL_CPLUSCMD_RXENB | RL_CPLUSCMD_TXENB;
3040251881Speter	CSR_WRITE_2(sc, RL_CPLUS_CMD, cfg);
3041251881Speter	if (sc->rl_hwrev->rl_rev == RL_HWREV_8169_8110SC ||
3042251881Speter	    sc->rl_hwrev->rl_rev == RL_HWREV_8169_8110SCE) {
3043251881Speter		reg = 0x000fff00;
3044251881Speter		if ((CSR_READ_1(sc, RL_CFG2) & RL_CFG2_PCI66MHZ) != 0)
3045251881Speter			reg |= 0x000000ff;
3046251881Speter		if (sc->rl_hwrev->rl_rev == RL_HWREV_8169_8110SCE)
3047251881Speter			reg |= 0x00f00000;
3048251881Speter		CSR_WRITE_4(sc, 0x7c, reg);
3049251881Speter		/* Disable interrupt mitigation. */
3050251881Speter		CSR_WRITE_2(sc, 0xe2, 0);
3051251881Speter	}
3052251881Speter	/*
3053251881Speter	 * Disable TSO if interface MTU size is greater than MSS
3054251881Speter	 * allowed in controller.
3055251881Speter	 */
3056251881Speter	if (ifp->if_mtu > RL_TSO_MTU && (ifp->if_capenable & IFCAP_TSO4) != 0) {
3057251881Speter		ifp->if_capenable &= ~IFCAP_TSO4;
3058251881Speter		ifp->if_hwassist &= ~CSUM_TSO;
3059251881Speter	}
3060251881Speter
3061251881Speter	/*
3062251881Speter	 * Init our MAC address.  Even though the chipset
3063251881Speter	 * documentation doesn't mention it, we need to enter "Config
3064251881Speter	 * register write enable" mode to modify the ID registers.
3065251881Speter	 */
3066251881Speter	/* Copy MAC address on stack to align. */
3067251881Speter	bcopy(IF_LLADDR(ifp), eaddr.eaddr, ETHER_ADDR_LEN);
3068251881Speter	CSR_WRITE_1(sc, RL_EECMD, RL_EEMODE_WRITECFG);
3069251881Speter	CSR_WRITE_4(sc, RL_IDR0,
3070251881Speter	    htole32(*(u_int32_t *)(&eaddr.eaddr[0])));
3071251881Speter	CSR_WRITE_4(sc, RL_IDR4,
3072251881Speter	    htole32(*(u_int32_t *)(&eaddr.eaddr[4])));
3073251881Speter	CSR_WRITE_1(sc, RL_EECMD, RL_EEMODE_OFF);
3074251881Speter
3075251881Speter	/*
3076251881Speter	 * Load the addresses of the RX and TX lists into the chip.
3077251881Speter	 */
3078251881Speter
3079251881Speter	CSR_WRITE_4(sc, RL_RXLIST_ADDR_HI,
3080251881Speter	    RL_ADDR_HI(sc->rl_ldata.rl_rx_list_addr));
3081251881Speter	CSR_WRITE_4(sc, RL_RXLIST_ADDR_LO,
3082251881Speter	    RL_ADDR_LO(sc->rl_ldata.rl_rx_list_addr));
3083251881Speter
3084251881Speter	CSR_WRITE_4(sc, RL_TXLIST_ADDR_HI,
3085251881Speter	    RL_ADDR_HI(sc->rl_ldata.rl_tx_list_addr));
3086251881Speter	CSR_WRITE_4(sc, RL_TXLIST_ADDR_LO,
3087251881Speter	    RL_ADDR_LO(sc->rl_ldata.rl_tx_list_addr));
3088251881Speter
3089251881Speter	/*
3090251881Speter	 * Enable transmit and receive.
3091251881Speter	 */
3092251881Speter	CSR_WRITE_1(sc, RL_COMMAND, RL_CMD_TX_ENB|RL_CMD_RX_ENB);
3093251881Speter
3094251881Speter	/*
3095251881Speter	 * Set the initial TX configuration.
3096251881Speter	 */
3097251881Speter	if (sc->rl_testmode) {
3098251881Speter		if (sc->rl_type == RL_8169)
3099251881Speter			CSR_WRITE_4(sc, RL_TXCFG,
3100251881Speter			    RL_TXCFG_CONFIG|RL_LOOPTEST_ON);
3101251881Speter		else
3102251881Speter			CSR_WRITE_4(sc, RL_TXCFG,
3103251881Speter			    RL_TXCFG_CONFIG|RL_LOOPTEST_ON_CPLUS);
3104251881Speter	} else
3105251881Speter		CSR_WRITE_4(sc, RL_TXCFG, RL_TXCFG_CONFIG);
3106251881Speter
3107251881Speter	CSR_WRITE_1(sc, RL_EARLY_TX_THRESH, 16);
3108251881Speter
3109251881Speter	/*
3110251881Speter	 * Set the initial RX configuration.
3111251881Speter	 */
3112251881Speter	re_set_rxmode(sc);
3113251881Speter
3114251881Speter	/* Configure interrupt moderation. */
3115251881Speter	if (sc->rl_type == RL_8169) {
3116251881Speter		/* Magic from vendor. */
3117251881Speter		CSR_WRITE_2(sc, RL_INTRMOD, 0x5100);
3118251881Speter	}
3119251881Speter
3120251881Speter#ifdef DEVICE_POLLING
3121251881Speter	/*
3122251881Speter	 * Disable interrupts if we are polling.
3123251881Speter	 */
3124251881Speter	if (ifp->if_capenable & IFCAP_POLLING)
3125251881Speter		CSR_WRITE_2(sc, RL_IMR, 0);
3126251881Speter	else	/* otherwise ... */
3127251881Speter#endif
3128251881Speter
3129251881Speter	/*
3130251881Speter	 * Enable interrupts.
3131251881Speter	 */
3132251881Speter	if (sc->rl_testmode)
3133251881Speter		CSR_WRITE_2(sc, RL_IMR, 0);
3134251881Speter	else
3135251881Speter		CSR_WRITE_2(sc, RL_IMR, RL_INTRS_CPLUS);
3136251881Speter	CSR_WRITE_2(sc, RL_ISR, RL_INTRS_CPLUS);
3137251881Speter
3138251881Speter	/* Set initial TX threshold */
3139251881Speter	sc->rl_txthresh = RL_TX_THRESH_INIT;
3140251881Speter
3141251881Speter	/* Start RX/TX process. */
3142251881Speter	CSR_WRITE_4(sc, RL_MISSEDPKT, 0);
3143251881Speter#ifdef notdef
3144251881Speter	/* Enable receiver and transmitter. */
3145251881Speter	CSR_WRITE_1(sc, RL_COMMAND, RL_CMD_TX_ENB|RL_CMD_RX_ENB);
3146251881Speter#endif
3147251881Speter
3148251881Speter	/*
3149251881Speter	 * Initialize the timer interrupt register so that
3150251881Speter	 * a timer interrupt will be generated once the timer
3151251881Speter	 * reaches a certain number of ticks. The timer is
3152251881Speter	 * reloaded on each transmit.
3153251881Speter	 */
3154251881Speter#ifdef RE_TX_MODERATION
3155251881Speter	/*
3156251881Speter	 * Use timer interrupt register to moderate TX interrupt
3157251881Speter	 * moderation, which dramatically improves TX frame rate.
3158251881Speter	 */
3159251881Speter	if (sc->rl_type == RL_8169)
3160251881Speter		CSR_WRITE_4(sc, RL_TIMERINT_8169, 0x800);
3161251881Speter	else
3162251881Speter		CSR_WRITE_4(sc, RL_TIMERINT, 0x400);
3163251881Speter#else
3164251881Speter	/*
3165251881Speter	 * Use timer interrupt register to moderate RX interrupt
3166251881Speter	 * moderation.
3167251881Speter	 */
3168251881Speter	if ((sc->rl_flags & (RL_FLAG_MSI | RL_FLAG_MSIX)) != 0 &&
3169251881Speter	    intr_filter == 0) {
3170251881Speter		if (sc->rl_type == RL_8169)
3171251881Speter			CSR_WRITE_4(sc, RL_TIMERINT_8169,
3172251881Speter			    RL_USECS(sc->rl_int_rx_mod));
3173251881Speter	} else {
3174251881Speter		if (sc->rl_type == RL_8169)
3175251881Speter			CSR_WRITE_4(sc, RL_TIMERINT_8169, RL_USECS(0));
3176251881Speter	}
3177251881Speter#endif
3178251881Speter
3179251881Speter	/*
3180251881Speter	 * For 8169 gigE NICs, set the max allowed RX packet
3181251881Speter	 * size so we can receive jumbo frames.
3182251881Speter	 */
3183251881Speter	if (sc->rl_type == RL_8169) {
3184251881Speter		if ((sc->rl_flags & RL_FLAG_JUMBOV2) != 0) {
3185251881Speter			/*
3186251881Speter			 * For controllers that use new jumbo frame scheme,
3187251881Speter			 * set maximum size of jumbo frame depedning on
3188251881Speter			 * controller revisions.
3189251881Speter			 */
3190251881Speter			if (ifp->if_mtu > RL_MTU)
3191251881Speter				CSR_WRITE_2(sc, RL_MAXRXPKTLEN,
3192251881Speter				    sc->rl_hwrev->rl_max_mtu +
3193251881Speter				    ETHER_VLAN_ENCAP_LEN + ETHER_HDR_LEN +
3194251881Speter				    ETHER_CRC_LEN);
3195251881Speter			else
3196251881Speter				CSR_WRITE_2(sc, RL_MAXRXPKTLEN,
3197251881Speter				    RE_RX_DESC_BUFLEN);
3198251881Speter		} else if ((sc->rl_flags & RL_FLAG_PCIE) != 0 &&
3199251881Speter		    sc->rl_hwrev->rl_max_mtu == RL_MTU) {
3200251881Speter			/* RTL810x has no jumbo frame support. */
3201251881Speter			CSR_WRITE_2(sc, RL_MAXRXPKTLEN, RE_RX_DESC_BUFLEN);
3202251881Speter		} else
3203251881Speter			CSR_WRITE_2(sc, RL_MAXRXPKTLEN, 16383);
3204251881Speter	}
3205251881Speter
3206251881Speter	if (sc->rl_testmode)
3207251881Speter		return;
3208251881Speter
3209251881Speter	CSR_WRITE_1(sc, RL_CFG1, CSR_READ_1(sc, RL_CFG1) | RL_CFG1_DRVLOAD);
3210251881Speter
3211251881Speter	ifp->if_drv_flags |= IFF_DRV_RUNNING;
3212251881Speter	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
3213251881Speter
3214251881Speter	sc->rl_flags &= ~RL_FLAG_LINK;
3215251881Speter	mii_mediachg(mii);
3216251881Speter
3217251881Speter	sc->rl_watchdog_timer = 0;
3218251881Speter	callout_reset(&sc->rl_stat_callout, hz, re_tick, sc);
3219251881Speter}
3220251881Speter
3221251881Speter/*
3222251881Speter * Set media options.
3223251881Speter */
3224251881Speterstatic int
3225251881Speterre_ifmedia_upd(struct ifnet *ifp)
3226251881Speter{
3227251881Speter	struct rl_softc		*sc;
3228251881Speter	struct mii_data		*mii;
3229251881Speter	int			error;
3230251881Speter
3231251881Speter	sc = ifp->if_softc;
3232251881Speter	mii = device_get_softc(sc->rl_miibus);
3233251881Speter	RL_LOCK(sc);
3234251881Speter	error = mii_mediachg(mii);
3235251881Speter	RL_UNLOCK(sc);
3236251881Speter
3237251881Speter	return (error);
3238251881Speter}
3239251881Speter
3240251881Speter/*
3241251881Speter * Report current media status.
3242251881Speter */
3243251881Speterstatic void
3244251881Speterre_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
3245251881Speter{
3246251881Speter	struct rl_softc		*sc;
3247251881Speter	struct mii_data		*mii;
3248251881Speter
3249251881Speter	sc = ifp->if_softc;
3250251881Speter	mii = device_get_softc(sc->rl_miibus);
3251251881Speter
3252251881Speter	RL_LOCK(sc);
3253251881Speter	mii_pollstat(mii);
3254251881Speter	ifmr->ifm_active = mii->mii_media_active;
3255251881Speter	ifmr->ifm_status = mii->mii_media_status;
3256251881Speter	RL_UNLOCK(sc);
3257251881Speter}
3258251881Speter
3259251881Speterstatic int
3260251881Speterre_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
3261251881Speter{
3262251881Speter	struct rl_softc		*sc = ifp->if_softc;
3263251881Speter	struct ifreq		*ifr = (struct ifreq *) data;
3264251881Speter	struct mii_data		*mii;
3265251881Speter	uint32_t		rev;
3266251881Speter	int			error = 0;
3267251881Speter
3268251881Speter	switch (command) {
3269251881Speter	case SIOCSIFMTU:
3270251881Speter		if (ifr->ifr_mtu < ETHERMIN ||
3271251881Speter		    ifr->ifr_mtu > sc->rl_hwrev->rl_max_mtu) {
3272251881Speter			error = EINVAL;
3273251881Speter			break;
3274251881Speter		}
3275251881Speter		RL_LOCK(sc);
3276251881Speter		if (ifp->if_mtu != ifr->ifr_mtu) {
3277251881Speter			ifp->if_mtu = ifr->ifr_mtu;
3278251881Speter			if ((sc->rl_flags & RL_FLAG_JUMBOV2) != 0 &&
3279251881Speter			    (ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) {
3280251881Speter				ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
3281251881Speter				re_init_locked(sc);
3282251881Speter			}
3283251881Speter			if (ifp->if_mtu > RL_TSO_MTU &&
3284251881Speter			    (ifp->if_capenable & IFCAP_TSO4) != 0) {
3285251881Speter				ifp->if_capenable &= ~(IFCAP_TSO4 |
3286251881Speter				    IFCAP_VLAN_HWTSO);
3287251881Speter				ifp->if_hwassist &= ~CSUM_TSO;
3288251881Speter			}
3289251881Speter			VLAN_CAPABILITIES(ifp);
3290251881Speter		}
3291251881Speter		RL_UNLOCK(sc);
3292251881Speter		break;
3293251881Speter	case SIOCSIFFLAGS:
3294251881Speter		RL_LOCK(sc);
3295251881Speter		if ((ifp->if_flags & IFF_UP) != 0) {
3296251881Speter			if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) {
3297251881Speter				if (((ifp->if_flags ^ sc->rl_if_flags)
3298251881Speter				    & (IFF_PROMISC | IFF_ALLMULTI)) != 0)
3299251881Speter					re_set_rxmode(sc);
3300251881Speter			} else
3301251881Speter				re_init_locked(sc);
3302251881Speter		} else {
3303251881Speter			if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0)
3304251881Speter				re_stop(sc);
3305251881Speter		}
3306251881Speter		sc->rl_if_flags = ifp->if_flags;
3307251881Speter		RL_UNLOCK(sc);
3308251881Speter		break;
3309251881Speter	case SIOCADDMULTI:
3310251881Speter	case SIOCDELMULTI:
3311251881Speter		RL_LOCK(sc);
3312251881Speter		if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0)
3313251881Speter			re_set_rxmode(sc);
3314251881Speter		RL_UNLOCK(sc);
3315251881Speter		break;
3316251881Speter	case SIOCGIFMEDIA:
3317251881Speter	case SIOCSIFMEDIA:
3318251881Speter		mii = device_get_softc(sc->rl_miibus);
3319251881Speter		error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command);
3320251881Speter		break;
3321251881Speter	case SIOCSIFCAP:
3322251881Speter	    {
3323251881Speter		int mask, reinit;
3324251881Speter
3325251881Speter		mask = ifr->ifr_reqcap ^ ifp->if_capenable;
3326251881Speter		reinit = 0;
3327251881Speter#ifdef DEVICE_POLLING
3328251881Speter		if (mask & IFCAP_POLLING) {
3329251881Speter			if (ifr->ifr_reqcap & IFCAP_POLLING) {
3330251881Speter				error = ether_poll_register(re_poll, ifp);
3331251881Speter				if (error)
3332251881Speter					return (error);
3333251881Speter				RL_LOCK(sc);
3334251881Speter				/* Disable interrupts */
3335251881Speter				CSR_WRITE_2(sc, RL_IMR, 0x0000);
3336251881Speter				ifp->if_capenable |= IFCAP_POLLING;
3337251881Speter				RL_UNLOCK(sc);
3338251881Speter			} else {
3339251881Speter				error = ether_poll_deregister(ifp);
3340251881Speter				/* Enable interrupts. */
3341251881Speter				RL_LOCK(sc);
3342251881Speter				CSR_WRITE_2(sc, RL_IMR, RL_INTRS_CPLUS);
3343251881Speter				ifp->if_capenable &= ~IFCAP_POLLING;
3344251881Speter				RL_UNLOCK(sc);
3345251881Speter			}
3346251881Speter		}
3347251881Speter#endif /* DEVICE_POLLING */
3348251881Speter		RL_LOCK(sc);
3349251881Speter		if ((mask & IFCAP_TXCSUM) != 0 &&
3350251881Speter		    (ifp->if_capabilities & IFCAP_TXCSUM) != 0) {
3351251881Speter			ifp->if_capenable ^= IFCAP_TXCSUM;
3352251881Speter			if ((ifp->if_capenable & IFCAP_TXCSUM) != 0) {
3353251881Speter				rev = sc->rl_hwrev->rl_rev;
3354251881Speter				if (rev == RL_HWREV_8168C ||
3355251881Speter				    rev == RL_HWREV_8168C_SPIN2)
3356251881Speter					ifp->if_hwassist |= CSUM_TCP | CSUM_UDP;
3357251881Speter				else
3358251881Speter					ifp->if_hwassist |= RE_CSUM_FEATURES;
3359251881Speter			} else
3360251881Speter				ifp->if_hwassist &= ~RE_CSUM_FEATURES;
3361251881Speter			reinit = 1;
3362251881Speter		}
3363251881Speter		if ((mask & IFCAP_RXCSUM) != 0 &&
3364251881Speter		    (ifp->if_capabilities & IFCAP_RXCSUM) != 0) {
3365251881Speter			ifp->if_capenable ^= IFCAP_RXCSUM;
3366251881Speter			reinit = 1;
3367251881Speter		}
3368251881Speter		if ((mask & IFCAP_TSO4) != 0 &&
3369251881Speter		    (ifp->if_capabilities & IFCAP_TSO) != 0) {
3370251881Speter			ifp->if_capenable ^= IFCAP_TSO4;
3371251881Speter			if ((IFCAP_TSO4 & ifp->if_capenable) != 0)
3372251881Speter				ifp->if_hwassist |= CSUM_TSO;
3373251881Speter			else
3374251881Speter				ifp->if_hwassist &= ~CSUM_TSO;
3375251881Speter			if (ifp->if_mtu > RL_TSO_MTU &&
3376251881Speter			    (ifp->if_capenable & IFCAP_TSO4) != 0) {
3377251881Speter				ifp->if_capenable &= ~IFCAP_TSO4;
3378251881Speter				ifp->if_hwassist &= ~CSUM_TSO;
3379251881Speter			}
3380251881Speter		}
3381251881Speter		if ((mask & IFCAP_VLAN_HWTSO) != 0 &&
3382251881Speter		    (ifp->if_capabilities & IFCAP_VLAN_HWTSO) != 0)
3383251881Speter			ifp->if_capenable ^= IFCAP_VLAN_HWTSO;
3384251881Speter		if ((mask & IFCAP_VLAN_HWTAGGING) != 0 &&
3385251881Speter		    (ifp->if_capabilities & IFCAP_VLAN_HWTAGGING) != 0) {
3386251881Speter			ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING;
3387251881Speter			/* TSO over VLAN requires VLAN hardware tagging. */
3388251881Speter			if ((ifp->if_capenable & IFCAP_VLAN_HWTAGGING) == 0)
3389251881Speter				ifp->if_capenable &= ~IFCAP_VLAN_HWTSO;
3390251881Speter			reinit = 1;
3391251881Speter		}
3392251881Speter		if ((sc->rl_flags & RL_FLAG_JUMBOV2) != 0 &&
3393251881Speter		    (mask & (IFCAP_HWCSUM | IFCAP_TSO4 |
3394251881Speter		    IFCAP_VLAN_HWTSO)) != 0)
3395251881Speter				reinit = 1;
3396251881Speter		if ((mask & IFCAP_WOL) != 0 &&
3397251881Speter		    (ifp->if_capabilities & IFCAP_WOL) != 0) {
3398251881Speter			if ((mask & IFCAP_WOL_UCAST) != 0)
3399251881Speter				ifp->if_capenable ^= IFCAP_WOL_UCAST;
3400251881Speter			if ((mask & IFCAP_WOL_MCAST) != 0)
3401251881Speter				ifp->if_capenable ^= IFCAP_WOL_MCAST;
3402251881Speter			if ((mask & IFCAP_WOL_MAGIC) != 0)
3403251881Speter				ifp->if_capenable ^= IFCAP_WOL_MAGIC;
3404251881Speter		}
3405251881Speter		if (reinit && ifp->if_drv_flags & IFF_DRV_RUNNING) {
3406251881Speter			ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
3407251881Speter			re_init_locked(sc);
3408251881Speter		}
3409251881Speter		RL_UNLOCK(sc);
3410251881Speter		VLAN_CAPABILITIES(ifp);
3411251881Speter	    }
3412251881Speter		break;
3413251881Speter	default:
3414251881Speter		error = ether_ioctl(ifp, command, data);
3415251881Speter		break;
3416251881Speter	}
3417251881Speter
3418251881Speter	return (error);
3419251881Speter}
3420251881Speter
3421251881Speterstatic void
3422251881Speterre_watchdog(struct rl_softc *sc)
3423251881Speter{
3424251881Speter	struct ifnet		*ifp;
3425251881Speter
3426251881Speter	RL_LOCK_ASSERT(sc);
3427251881Speter
3428251881Speter	if (sc->rl_watchdog_timer == 0 || --sc->rl_watchdog_timer != 0)
3429251881Speter		return;
3430251881Speter
3431251881Speter	ifp = sc->rl_ifp;
3432251881Speter	re_txeof(sc);
3433251881Speter	if (sc->rl_ldata.rl_tx_free == sc->rl_ldata.rl_tx_desc_cnt) {
3434251881Speter		if_printf(ifp, "watchdog timeout (missed Tx interrupts) "
3435251881Speter		    "-- recovering\n");
3436251881Speter		if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
3437251881Speter			re_start_locked(ifp);
3438251881Speter		return;
3439251881Speter	}
3440251881Speter
3441251881Speter	if_printf(ifp, "watchdog timeout\n");
3442251881Speter	ifp->if_oerrors++;
3443251881Speter
3444251881Speter	re_rxeof(sc, NULL);
3445251881Speter	ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
3446251881Speter	re_init_locked(sc);
3447251881Speter	if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
3448251881Speter		re_start_locked(ifp);
3449251881Speter}
3450251881Speter
3451251881Speter/*
3452251881Speter * Stop the adapter and free any mbufs allocated to the
3453251881Speter * RX and TX lists.
3454251881Speter */
3455251881Speterstatic void
3456251881Speterre_stop(struct rl_softc *sc)
3457251881Speter{
3458251881Speter	int			i;
3459251881Speter	struct ifnet		*ifp;
3460251881Speter	struct rl_txdesc	*txd;
3461251881Speter	struct rl_rxdesc	*rxd;
3462251881Speter
3463251881Speter	RL_LOCK_ASSERT(sc);
3464251881Speter
3465251881Speter	ifp = sc->rl_ifp;
3466251881Speter
3467251881Speter	sc->rl_watchdog_timer = 0;
3468251881Speter	callout_stop(&sc->rl_stat_callout);
3469251881Speter	ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
3470251881Speter
3471251881Speter	/*
3472251881Speter	 * Disable accepting frames to put RX MAC into idle state.
3473251881Speter	 * Otherwise it's possible to get frames while stop command
3474251881Speter	 * execution is in progress and controller can DMA the frame
3475251881Speter	 * to already freed RX buffer during that period.
3476251881Speter	 */
3477251881Speter	CSR_WRITE_4(sc, RL_RXCFG, CSR_READ_4(sc, RL_RXCFG) &
3478251881Speter	    ~(RL_RXCFG_RX_ALLPHYS | RL_RXCFG_RX_INDIV | RL_RXCFG_RX_MULTI |
3479251881Speter	    RL_RXCFG_RX_BROAD));
3480251881Speter
3481251881Speter	if ((sc->rl_flags & RL_FLAG_WAIT_TXPOLL) != 0) {
3482251881Speter		for (i = RL_TIMEOUT; i > 0; i--) {
3483251881Speter			if ((CSR_READ_1(sc, sc->rl_txstart) &
3484251881Speter			    RL_TXSTART_START) == 0)
3485251881Speter				break;
3486251881Speter			DELAY(20);
3487251881Speter		}
3488251881Speter		if (i == 0)
3489251881Speter			device_printf(sc->rl_dev,
3490251881Speter			    "stopping TX poll timed out!\n");
3491251881Speter		CSR_WRITE_1(sc, RL_COMMAND, 0x00);
3492251881Speter	} else if ((sc->rl_flags & RL_FLAG_CMDSTOP) != 0) {
3493251881Speter		CSR_WRITE_1(sc, RL_COMMAND, RL_CMD_STOPREQ | RL_CMD_TX_ENB |
3494251881Speter		    RL_CMD_RX_ENB);
3495251881Speter		if ((sc->rl_flags & RL_FLAG_CMDSTOP_WAIT_TXQ) != 0) {
3496251881Speter			for (i = RL_TIMEOUT; i > 0; i--) {
3497251881Speter				if ((CSR_READ_4(sc, RL_TXCFG) &
3498251881Speter				    RL_TXCFG_QUEUE_EMPTY) != 0)
3499251881Speter					break;
3500251881Speter				DELAY(100);
3501251881Speter			}
3502251881Speter			if (i == 0)
3503251881Speter				device_printf(sc->rl_dev,
3504251881Speter				   "stopping TXQ timed out!\n");
3505251881Speter		}
3506251881Speter	} else
3507251881Speter		CSR_WRITE_1(sc, RL_COMMAND, 0x00);
3508251881Speter	DELAY(1000);
3509251881Speter	CSR_WRITE_2(sc, RL_IMR, 0x0000);
3510251881Speter	CSR_WRITE_2(sc, RL_ISR, 0xFFFF);
3511251881Speter
3512251881Speter	if (sc->rl_head != NULL) {
3513251881Speter		m_freem(sc->rl_head);
3514251881Speter		sc->rl_head = sc->rl_tail = NULL;
3515251881Speter	}
3516251881Speter
3517251881Speter	/* Free the TX list buffers. */
3518251881Speter	for (i = 0; i < sc->rl_ldata.rl_tx_desc_cnt; i++) {
3519251881Speter		txd = &sc->rl_ldata.rl_tx_desc[i];
3520251881Speter		if (txd->tx_m != NULL) {
3521251881Speter			bus_dmamap_sync(sc->rl_ldata.rl_tx_mtag,
3522251881Speter			    txd->tx_dmamap, BUS_DMASYNC_POSTWRITE);
3523251881Speter			bus_dmamap_unload(sc->rl_ldata.rl_tx_mtag,
3524251881Speter			    txd->tx_dmamap);
3525251881Speter			m_freem(txd->tx_m);
3526251881Speter			txd->tx_m = NULL;
3527251881Speter		}
3528251881Speter	}
3529251881Speter
3530251881Speter	/* Free the RX list buffers. */
3531251881Speter	for (i = 0; i < sc->rl_ldata.rl_rx_desc_cnt; i++) {
3532251881Speter		rxd = &sc->rl_ldata.rl_rx_desc[i];
3533251881Speter		if (rxd->rx_m != NULL) {
3534251881Speter			bus_dmamap_sync(sc->rl_ldata.rl_rx_mtag,
3535251881Speter			    rxd->rx_dmamap, BUS_DMASYNC_POSTREAD);
3536251881Speter			bus_dmamap_unload(sc->rl_ldata.rl_rx_mtag,
3537251881Speter			    rxd->rx_dmamap);
3538251881Speter			m_freem(rxd->rx_m);
3539251881Speter			rxd->rx_m = NULL;
3540251881Speter		}
3541251881Speter	}
3542251881Speter
3543251881Speter	if ((sc->rl_flags & RL_FLAG_JUMBOV2) != 0) {
3544251881Speter		for (i = 0; i < sc->rl_ldata.rl_rx_desc_cnt; i++) {
3545251881Speter			rxd = &sc->rl_ldata.rl_jrx_desc[i];
3546251881Speter			if (rxd->rx_m != NULL) {
3547251881Speter				bus_dmamap_sync(sc->rl_ldata.rl_jrx_mtag,
3548251881Speter				    rxd->rx_dmamap, BUS_DMASYNC_POSTREAD);
3549251881Speter				bus_dmamap_unload(sc->rl_ldata.rl_jrx_mtag,
3550251881Speter				    rxd->rx_dmamap);
3551251881Speter				m_freem(rxd->rx_m);
3552251881Speter				rxd->rx_m = NULL;
3553251881Speter			}
3554251881Speter		}
3555251881Speter	}
3556251881Speter}
3557251881Speter
3558251881Speter/*
3559251881Speter * Device suspend routine.  Stop the interface and save some PCI
3560251881Speter * settings in case the BIOS doesn't restore them properly on
3561251881Speter * resume.
3562251881Speter */
3563251881Speterstatic int
3564251881Speterre_suspend(device_t dev)
3565251881Speter{
3566251881Speter	struct rl_softc		*sc;
3567251881Speter
3568251881Speter	sc = device_get_softc(dev);
3569251881Speter
3570251881Speter	RL_LOCK(sc);
3571251881Speter	re_stop(sc);
3572251881Speter	re_setwol(sc);
3573251881Speter	sc->suspended = 1;
3574251881Speter	RL_UNLOCK(sc);
3575251881Speter
3576251881Speter	return (0);
3577251881Speter}
3578251881Speter
3579251881Speter/*
3580251881Speter * Device resume routine.  Restore some PCI settings in case the BIOS
3581251881Speter * doesn't, re-enable busmastering, and restart the interface if
3582251881Speter * appropriate.
3583251881Speter */
3584251881Speterstatic int
3585251881Speterre_resume(device_t dev)
3586251881Speter{
3587251881Speter	struct rl_softc		*sc;
3588251881Speter	struct ifnet		*ifp;
3589251881Speter
3590251881Speter	sc = device_get_softc(dev);
3591251881Speter
3592251881Speter	RL_LOCK(sc);
3593251881Speter
3594251881Speter	ifp = sc->rl_ifp;
3595251881Speter	/* Take controller out of sleep mode. */
3596251881Speter	if ((sc->rl_flags & RL_FLAG_MACSLEEP) != 0) {
3597251881Speter		if ((CSR_READ_1(sc, RL_MACDBG) & 0x80) == 0x80)
3598251881Speter			CSR_WRITE_1(sc, RL_GPIO,
3599251881Speter			    CSR_READ_1(sc, RL_GPIO) | 0x01);
3600251881Speter	}
3601251881Speter
3602251881Speter	/*
3603251881Speter	 * Clear WOL matching such that normal Rx filtering
3604251881Speter	 * wouldn't interfere with WOL patterns.
3605251881Speter	 */
3606251881Speter	re_clrwol(sc);
3607251881Speter
3608251881Speter	/* reinitialize interface if necessary */
3609251881Speter	if (ifp->if_flags & IFF_UP)
3610251881Speter		re_init_locked(sc);
3611251881Speter
3612251881Speter	sc->suspended = 0;
3613251881Speter	RL_UNLOCK(sc);
3614251881Speter
3615251881Speter	return (0);
3616251881Speter}
3617251881Speter
3618251881Speter/*
3619251881Speter * Stop all chip I/O so that the kernel's probe routines don't
3620251881Speter * get confused by errant DMAs when rebooting.
3621251881Speter */
3622251881Speterstatic int
3623251881Speterre_shutdown(device_t dev)
3624251881Speter{
3625251881Speter	struct rl_softc		*sc;
3626251881Speter
3627251881Speter	sc = device_get_softc(dev);
3628251881Speter
3629251881Speter	RL_LOCK(sc);
3630251881Speter	re_stop(sc);
3631251881Speter	/*
3632251881Speter	 * Mark interface as down since otherwise we will panic if
3633251881Speter	 * interrupt comes in later on, which can happen in some
3634251881Speter	 * cases.
3635251881Speter	 */
3636251881Speter	sc->rl_ifp->if_flags &= ~IFF_UP;
3637251881Speter	re_setwol(sc);
3638251881Speter	RL_UNLOCK(sc);
3639251881Speter
3640251881Speter	return (0);
3641251881Speter}
3642251881Speter
3643251881Speterstatic void
3644251881Speterre_set_linkspeed(struct rl_softc *sc)
3645251881Speter{
3646251881Speter	struct mii_softc *miisc;
3647251881Speter	struct mii_data *mii;
3648251881Speter	int aneg, i, phyno;
3649251881Speter
3650251881Speter	RL_LOCK_ASSERT(sc);
3651251881Speter
3652251881Speter	mii = device_get_softc(sc->rl_miibus);
3653251881Speter	mii_pollstat(mii);
3654251881Speter	aneg = 0;
3655251881Speter	if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) ==
3656251881Speter	    (IFM_ACTIVE | IFM_AVALID)) {
3657251881Speter		switch IFM_SUBTYPE(mii->mii_media_active) {
3658251881Speter		case IFM_10_T:
3659251881Speter		case IFM_100_TX:
3660251881Speter			return;
3661251881Speter		case IFM_1000_T:
3662251881Speter			aneg++;
3663251881Speter			break;
3664251881Speter		default:
3665251881Speter			break;
3666251881Speter		}
3667251881Speter	}
3668251881Speter	miisc = LIST_FIRST(&mii->mii_phys);
3669251881Speter	phyno = miisc->mii_phy;
3670251881Speter	LIST_FOREACH(miisc, &mii->mii_phys, mii_list)
3671251881Speter		PHY_RESET(miisc);
3672251881Speter	re_miibus_writereg(sc->rl_dev, phyno, MII_100T2CR, 0);
3673251881Speter	re_miibus_writereg(sc->rl_dev, phyno,
3674251881Speter	    MII_ANAR, ANAR_TX_FD | ANAR_TX | ANAR_10_FD | ANAR_10 | ANAR_CSMA);
3675251881Speter	re_miibus_writereg(sc->rl_dev, phyno,
3676251881Speter	    MII_BMCR, BMCR_AUTOEN | BMCR_STARTNEG);
3677251881Speter	DELAY(1000);
3678251881Speter	if (aneg != 0) {
3679251881Speter		/*
3680251881Speter		 * Poll link state until re(4) get a 10/100Mbps link.
3681251881Speter		 */
3682251881Speter		for (i = 0; i < MII_ANEGTICKS_GIGE; i++) {
3683251881Speter			mii_pollstat(mii);
3684251881Speter			if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID))
3685251881Speter			    == (IFM_ACTIVE | IFM_AVALID)) {
3686251881Speter				switch (IFM_SUBTYPE(mii->mii_media_active)) {
3687251881Speter				case IFM_10_T:
3688251881Speter				case IFM_100_TX:
3689251881Speter					return;
3690251881Speter				default:
3691251881Speter					break;
3692251881Speter				}
3693251881Speter			}
3694251881Speter			RL_UNLOCK(sc);
3695251881Speter			pause("relnk", hz);
3696251881Speter			RL_LOCK(sc);
3697251881Speter		}
3698251881Speter		if (i == MII_ANEGTICKS_GIGE)
3699251881Speter			device_printf(sc->rl_dev,
3700251881Speter			    "establishing a link failed, WOL may not work!");
3701251881Speter	}
3702251881Speter	/*
3703251881Speter	 * No link, force MAC to have 100Mbps, full-duplex link.
3704251881Speter	 * MAC does not require reprogramming on resolved speed/duplex,
3705251881Speter	 * so this is just for completeness.
3706251881Speter	 */
3707251881Speter	mii->mii_media_status = IFM_AVALID | IFM_ACTIVE;
3708251881Speter	mii->mii_media_active = IFM_ETHER | IFM_100_TX | IFM_FDX;
3709251881Speter}
3710251881Speter
3711251881Speterstatic void
3712251881Speterre_setwol(struct rl_softc *sc)
3713251881Speter{
3714251881Speter	struct ifnet		*ifp;
3715251881Speter	int			pmc;
3716251881Speter	uint16_t		pmstat;
3717251881Speter	uint8_t			v;
3718251881Speter
3719251881Speter	RL_LOCK_ASSERT(sc);
3720251881Speter
3721251881Speter	if (pci_find_cap(sc->rl_dev, PCIY_PMG, &pmc) != 0)
3722251881Speter		return;
3723251881Speter
3724251881Speter	ifp = sc->rl_ifp;
3725251881Speter	/* Put controller into sleep mode. */
3726251881Speter	if ((sc->rl_flags & RL_FLAG_MACSLEEP) != 0) {
3727251881Speter		if ((CSR_READ_1(sc, RL_MACDBG) & 0x80) == 0x80)
3728251881Speter			CSR_WRITE_1(sc, RL_GPIO,
3729251881Speter			    CSR_READ_1(sc, RL_GPIO) & ~0x01);
3730251881Speter	}
3731251881Speter	if ((ifp->if_capenable & IFCAP_WOL) != 0) {
3732251881Speter		re_set_rxmode(sc);
3733251881Speter		if ((sc->rl_flags & RL_FLAG_WOL_MANLINK) != 0)
3734251881Speter			re_set_linkspeed(sc);
3735251881Speter		if ((sc->rl_flags & RL_FLAG_WOLRXENB) != 0)
3736251881Speter			CSR_WRITE_1(sc, RL_COMMAND, RL_CMD_RX_ENB);
3737251881Speter	}
3738251881Speter	/* Enable config register write. */
3739251881Speter	CSR_WRITE_1(sc, RL_EECMD, RL_EE_MODE);
3740251881Speter
3741251881Speter	/* Enable PME. */
3742251881Speter	v = CSR_READ_1(sc, RL_CFG1);
3743251881Speter	v &= ~RL_CFG1_PME;
3744251881Speter	if ((ifp->if_capenable & IFCAP_WOL) != 0)
3745251881Speter		v |= RL_CFG1_PME;
3746251881Speter	CSR_WRITE_1(sc, RL_CFG1, v);
3747251881Speter
3748251881Speter	v = CSR_READ_1(sc, RL_CFG3);
3749251881Speter	v &= ~(RL_CFG3_WOL_LINK | RL_CFG3_WOL_MAGIC);
3750251881Speter	if ((ifp->if_capenable & IFCAP_WOL_MAGIC) != 0)
3751251881Speter		v |= RL_CFG3_WOL_MAGIC;
3752251881Speter	CSR_WRITE_1(sc, RL_CFG3, v);
3753251881Speter
3754251881Speter	v = CSR_READ_1(sc, RL_CFG5);
3755251881Speter	v &= ~(RL_CFG5_WOL_BCAST | RL_CFG5_WOL_MCAST | RL_CFG5_WOL_UCAST |
3756251881Speter	    RL_CFG5_WOL_LANWAKE);
3757251881Speter	if ((ifp->if_capenable & IFCAP_WOL_UCAST) != 0)
3758251881Speter		v |= RL_CFG5_WOL_UCAST;
3759251881Speter	if ((ifp->if_capenable & IFCAP_WOL_MCAST) != 0)
3760251881Speter		v |= RL_CFG5_WOL_MCAST | RL_CFG5_WOL_BCAST;
3761251881Speter	if ((ifp->if_capenable & IFCAP_WOL) != 0)
3762251881Speter		v |= RL_CFG5_WOL_LANWAKE;
3763251881Speter	CSR_WRITE_1(sc, RL_CFG5, v);
3764251881Speter
3765251881Speter	/* Config register write done. */
3766251881Speter	CSR_WRITE_1(sc, RL_EECMD, RL_EEMODE_OFF);
3767251881Speter
3768251881Speter	if ((ifp->if_capenable & IFCAP_WOL) == 0 &&
3769251881Speter	    (sc->rl_flags & RL_FLAG_PHYWAKE_PM) != 0)
3770251881Speter		CSR_WRITE_1(sc, RL_PMCH, CSR_READ_1(sc, RL_PMCH) & ~0x80);
3771251881Speter	/*
3772251881Speter	 * It seems that hardware resets its link speed to 100Mbps in
3773251881Speter	 * power down mode so switching to 100Mbps in driver is not
3774251881Speter	 * needed.
3775251881Speter	 */
3776251881Speter
3777251881Speter	/* Request PME if WOL is requested. */
3778251881Speter	pmstat = pci_read_config(sc->rl_dev, pmc + PCIR_POWER_STATUS, 2);
3779251881Speter	pmstat &= ~(PCIM_PSTAT_PME | PCIM_PSTAT_PMEENABLE);
3780251881Speter	if ((ifp->if_capenable & IFCAP_WOL) != 0)
3781251881Speter		pmstat |= PCIM_PSTAT_PME | PCIM_PSTAT_PMEENABLE;
3782251881Speter	pci_write_config(sc->rl_dev, pmc + PCIR_POWER_STATUS, pmstat, 2);
3783251881Speter}
3784251881Speter
3785251881Speterstatic void
3786251881Speterre_clrwol(struct rl_softc *sc)
3787251881Speter{
3788251881Speter	int			pmc;
3789251881Speter	uint8_t			v;
3790251881Speter
3791251881Speter	RL_LOCK_ASSERT(sc);
3792251881Speter
3793251881Speter	if (pci_find_cap(sc->rl_dev, PCIY_PMG, &pmc) != 0)
3794251881Speter		return;
3795251881Speter
3796251881Speter	/* Enable config register write. */
3797251881Speter	CSR_WRITE_1(sc, RL_EECMD, RL_EE_MODE);
3798251881Speter
3799251881Speter	v = CSR_READ_1(sc, RL_CFG3);
3800251881Speter	v &= ~(RL_CFG3_WOL_LINK | RL_CFG3_WOL_MAGIC);
3801251881Speter	CSR_WRITE_1(sc, RL_CFG3, v);
3802251881Speter
3803251881Speter	/* Config register write done. */
3804251881Speter	CSR_WRITE_1(sc, RL_EECMD, RL_EEMODE_OFF);
3805251881Speter
3806251881Speter	v = CSR_READ_1(sc, RL_CFG5);
3807251881Speter	v &= ~(RL_CFG5_WOL_BCAST | RL_CFG5_WOL_MCAST | RL_CFG5_WOL_UCAST);
3808251881Speter	v &= ~RL_CFG5_WOL_LANWAKE;
3809251881Speter	CSR_WRITE_1(sc, RL_CFG5, v);
3810251881Speter}
3811251881Speter
3812251881Speterstatic void
3813251881Speterre_add_sysctls(struct rl_softc *sc)
3814251881Speter{
3815251881Speter	struct sysctl_ctx_list	*ctx;
3816251881Speter	struct sysctl_oid_list	*children;
3817251881Speter	int			error;
3818269847Speter
3819269847Speter	ctx = device_get_sysctl_ctx(sc->rl_dev);
3820269847Speter	children = SYSCTL_CHILDREN(device_get_sysctl_tree(sc->rl_dev));
3821269847Speter
3822269847Speter	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "stats",
3823269847Speter	    CTLTYPE_INT | CTLFLAG_RW, sc, 0, re_sysctl_stats, "I",
3824269847Speter	    "Statistics Information");
3825269847Speter	if ((sc->rl_flags & (RL_FLAG_MSI | RL_FLAG_MSIX)) == 0)
3826269847Speter		return;
3827251881Speter
3828251881Speter	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "int_rx_mod",
3829251881Speter	    CTLTYPE_INT | CTLFLAG_RW, &sc->rl_int_rx_mod, 0,
3830251881Speter	    sysctl_hw_re_int_mod, "I", "re RX interrupt moderation");
3831251881Speter	/* Pull in device tunables. */
3832251881Speter	sc->rl_int_rx_mod = RL_TIMER_DEFAULT;
3833251881Speter	error = resource_int_value(device_get_name(sc->rl_dev),
3834251881Speter	    device_get_unit(sc->rl_dev), "int_rx_mod", &sc->rl_int_rx_mod);
3835251881Speter	if (error == 0) {
3836251881Speter		if (sc->rl_int_rx_mod < RL_TIMER_MIN ||
3837251881Speter		    sc->rl_int_rx_mod > RL_TIMER_MAX) {
3838251881Speter			device_printf(sc->rl_dev, "int_rx_mod value out of "
3839251881Speter			    "range; using default: %d\n",
3840251881Speter			    RL_TIMER_DEFAULT);
3841251881Speter			sc->rl_int_rx_mod = RL_TIMER_DEFAULT;
3842251881Speter		}
3843251881Speter	}
3844251881Speter
3845251881Speter}
3846251881Speter
3847251881Speterstatic int
3848251881Speterre_sysctl_stats(SYSCTL_HANDLER_ARGS)
3849251881Speter{
3850251881Speter	struct rl_softc		*sc;
3851251881Speter	struct rl_stats		*stats;
3852251881Speter	int			error, i, result;
3853251881Speter
3854251881Speter	result = -1;
3855251881Speter	error = sysctl_handle_int(oidp, &result, 0, req);
3856251881Speter	if (error || req->newptr == NULL)
3857251881Speter		return (error);
3858251881Speter
3859251881Speter	if (result == 1) {
3860251881Speter		sc = (struct rl_softc *)arg1;
3861251881Speter		RL_LOCK(sc);
3862251881Speter		if ((sc->rl_ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) {
3863251881Speter			RL_UNLOCK(sc);
3864251881Speter			goto done;
3865251881Speter		}
3866251881Speter		bus_dmamap_sync(sc->rl_ldata.rl_stag,
3867251881Speter		    sc->rl_ldata.rl_smap, BUS_DMASYNC_PREREAD);
3868251881Speter		CSR_WRITE_4(sc, RL_DUMPSTATS_HI,
3869251881Speter		    RL_ADDR_HI(sc->rl_ldata.rl_stats_addr));
3870251881Speter		CSR_WRITE_4(sc, RL_DUMPSTATS_LO,
3871251881Speter		    RL_ADDR_LO(sc->rl_ldata.rl_stats_addr));
3872251881Speter		CSR_WRITE_4(sc, RL_DUMPSTATS_LO,
3873251881Speter		    RL_ADDR_LO(sc->rl_ldata.rl_stats_addr |
3874251881Speter		    RL_DUMPSTATS_START));
3875251881Speter		for (i = RL_TIMEOUT; i > 0; i--) {
3876251881Speter			if ((CSR_READ_4(sc, RL_DUMPSTATS_LO) &
3877251881Speter			    RL_DUMPSTATS_START) == 0)
3878251881Speter				break;
3879251881Speter			DELAY(1000);
3880251881Speter		}
3881251881Speter		bus_dmamap_sync(sc->rl_ldata.rl_stag,
3882251881Speter		    sc->rl_ldata.rl_smap, BUS_DMASYNC_POSTREAD);
3883251881Speter		RL_UNLOCK(sc);
3884251881Speter		if (i == 0) {
3885251881Speter			device_printf(sc->rl_dev,
3886251881Speter			    "DUMP statistics request timedout\n");
3887251881Speter			return (ETIMEDOUT);
3888251881Speter		}
3889251881Speterdone:
3890251881Speter		stats = sc->rl_ldata.rl_stats;
3891251881Speter		printf("%s statistics:\n", device_get_nameunit(sc->rl_dev));
3892251881Speter		printf("Tx frames : %ju\n",
3893251881Speter		    (uintmax_t)le64toh(stats->rl_tx_pkts));
3894251881Speter		printf("Rx frames : %ju\n",
3895251881Speter		    (uintmax_t)le64toh(stats->rl_rx_pkts));
3896251881Speter		printf("Tx errors : %ju\n",
3897251881Speter		    (uintmax_t)le64toh(stats->rl_tx_errs));
3898251881Speter		printf("Rx errors : %u\n",
3899251881Speter		    le32toh(stats->rl_rx_errs));
3900251881Speter		printf("Rx missed frames : %u\n",
3901251881Speter		    (uint32_t)le16toh(stats->rl_missed_pkts));
3902251881Speter		printf("Rx frame alignment errs : %u\n",
3903251881Speter		    (uint32_t)le16toh(stats->rl_rx_framealign_errs));
3904251881Speter		printf("Tx single collisions : %u\n",
3905251881Speter		    le32toh(stats->rl_tx_onecoll));
3906251881Speter		printf("Tx multiple collisions : %u\n",
3907251881Speter		    le32toh(stats->rl_tx_multicolls));
3908251881Speter		printf("Rx unicast frames : %ju\n",
3909251881Speter		    (uintmax_t)le64toh(stats->rl_rx_ucasts));
3910251881Speter		printf("Rx broadcast frames : %ju\n",
3911251881Speter		    (uintmax_t)le64toh(stats->rl_rx_bcasts));
3912251881Speter		printf("Rx multicast frames : %u\n",
3913251881Speter		    le32toh(stats->rl_rx_mcasts));
3914251881Speter		printf("Tx aborts : %u\n",
3915251881Speter		    (uint32_t)le16toh(stats->rl_tx_aborts));
3916251881Speter		printf("Tx underruns : %u\n",
3917251881Speter		    (uint32_t)le16toh(stats->rl_rx_underruns));
3918251881Speter	}
3919251881Speter
3920251881Speter	return (error);
3921251881Speter}
3922251881Speter
3923251881Speterstatic int
3924251881Spetersysctl_int_range(SYSCTL_HANDLER_ARGS, int low, int high)
3925251881Speter{
3926251881Speter	int error, value;
3927251881Speter
3928251881Speter	if (arg1 == NULL)
3929251881Speter		return (EINVAL);
3930251881Speter	value = *(int *)arg1;
3931251881Speter	error = sysctl_handle_int(oidp, &value, 0, req);
3932251881Speter	if (error || req->newptr == NULL)
3933251881Speter		return (error);
3934251881Speter	if (value < low || value > high)
3935251881Speter		return (EINVAL);
3936251881Speter	*(int *)arg1 = value;
3937251881Speter
3938251881Speter	return (0);
3939251881Speter}
3940251881Speter
3941251881Speterstatic int
3942251881Spetersysctl_hw_re_int_mod(SYSCTL_HANDLER_ARGS)
3943251881Speter{
3944251881Speter
3945251881Speter	return (sysctl_int_range(oidp, arg1, arg2, req, RL_TIMER_MIN,
3946251881Speter	    RL_TIMER_MAX));
3947251881Speter}
3948251881Speter