xref: /dflybsd-src/sys/dev/netif/re/if_re.c (revision bf80ef972c3e267b7100867e40580197a2f7e43b)
1af51229aSJoerg Sonnenberger /*
2af51229aSJoerg Sonnenberger  * Copyright (c) 2004
3af51229aSJoerg Sonnenberger  *	Joerg Sonnenberger <joerg@bec.de>.  All rights reserved.
4af51229aSJoerg Sonnenberger  *
5af51229aSJoerg Sonnenberger  * Copyright (c) 1997, 1998-2003
6af51229aSJoerg Sonnenberger  *	Bill Paul <wpaul@windriver.com>.  All rights reserved.
7af51229aSJoerg Sonnenberger  *
8af51229aSJoerg Sonnenberger  * Redistribution and use in source and binary forms, with or without
9af51229aSJoerg Sonnenberger  * modification, are permitted provided that the following conditions
10af51229aSJoerg Sonnenberger  * are met:
11af51229aSJoerg Sonnenberger  * 1. Redistributions of source code must retain the above copyright
12af51229aSJoerg Sonnenberger  *    notice, this list of conditions and the following disclaimer.
13af51229aSJoerg Sonnenberger  * 2. Redistributions in binary form must reproduce the above copyright
14af51229aSJoerg Sonnenberger  *    notice, this list of conditions and the following disclaimer in the
15af51229aSJoerg Sonnenberger  *    documentation and/or other materials provided with the distribution.
16af51229aSJoerg Sonnenberger  * 3. All advertising materials mentioning features or use of this software
17af51229aSJoerg Sonnenberger  *    must display the following acknowledgement:
18af51229aSJoerg Sonnenberger  *	This product includes software developed by Bill Paul.
19af51229aSJoerg Sonnenberger  * 4. Neither the name of the author nor the names of any co-contributors
20af51229aSJoerg Sonnenberger  *    may be used to endorse or promote products derived from this software
21af51229aSJoerg Sonnenberger  *    without specific prior written permission.
22af51229aSJoerg Sonnenberger  *
23af51229aSJoerg Sonnenberger  * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
24af51229aSJoerg Sonnenberger  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25af51229aSJoerg Sonnenberger  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26af51229aSJoerg Sonnenberger  * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
27af51229aSJoerg Sonnenberger  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28af51229aSJoerg Sonnenberger  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
29af51229aSJoerg Sonnenberger  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
30af51229aSJoerg Sonnenberger  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
31af51229aSJoerg Sonnenberger  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32af51229aSJoerg Sonnenberger  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
33af51229aSJoerg Sonnenberger  * THE POSSIBILITY OF SUCH DAMAGE.
34af51229aSJoerg Sonnenberger  *
35af51229aSJoerg Sonnenberger  * $FreeBSD: src/sys/dev/re/if_re.c,v 1.25 2004/06/09 14:34:01 naddy Exp $
36af51229aSJoerg Sonnenberger  */
37af51229aSJoerg Sonnenberger 
38af51229aSJoerg Sonnenberger /*
3980492964SSepherosa Ziehau  * RealTek 8169S/8110S/8168/8111/8101E/8125 PCI NIC driver
40af51229aSJoerg Sonnenberger  *
41af51229aSJoerg Sonnenberger  * Written by Bill Paul <wpaul@windriver.com>
42af51229aSJoerg Sonnenberger  * Senior Networking Software Engineer
43af51229aSJoerg Sonnenberger  * Wind River Systems
44af51229aSJoerg Sonnenberger  */
45af51229aSJoerg Sonnenberger 
46af51229aSJoerg Sonnenberger /*
47af51229aSJoerg Sonnenberger  * This driver is designed to support RealTek's next generation of
48af51229aSJoerg Sonnenberger  * 10/100 and 10/100/1000 PCI ethernet controllers. There are currently
49e5a5a436SSepherosa Ziehau  * seven devices in this family: the the RTL8169, the RTL8169S, RTL8110S,
50e5a5a436SSepherosa Ziehau  * the RTL8168, the RTL8111 and the RTL8101E.
51af51229aSJoerg Sonnenberger  *
52e5a5a436SSepherosa Ziehau  * The 8169 is a 64-bit 10/100/1000 gigabit ethernet MAC:
53af51229aSJoerg Sonnenberger  *
54af51229aSJoerg Sonnenberger  *	o Descriptor based DMA mechanism.  Each descriptor represents
55af51229aSJoerg Sonnenberger  *	  a single packet fragment. Data buffers may be aligned on
56af51229aSJoerg Sonnenberger  *	  any byte boundary.
57af51229aSJoerg Sonnenberger  *
58e5a5a436SSepherosa Ziehau  *	o 64-bit DMA.
59af51229aSJoerg Sonnenberger  *
60e5a5a436SSepherosa Ziehau  *	o TCP/IP checksum offload for both RX and TX.
61af51229aSJoerg Sonnenberger  *
62e5a5a436SSepherosa Ziehau  *	o High and normal priority transmit DMA rings.
63af51229aSJoerg Sonnenberger  *
64e5a5a436SSepherosa Ziehau  *	o VLAN tag insertion and extraction.
65af51229aSJoerg Sonnenberger  *
66e5a5a436SSepherosa Ziehau  *	o TCP large send (segmentation offload).
67af51229aSJoerg Sonnenberger  *
68e5a5a436SSepherosa Ziehau  *	o 1000Mbps mode.
69af51229aSJoerg Sonnenberger  *
70e5a5a436SSepherosa Ziehau  *	o Jumbo frames.
71af51229aSJoerg Sonnenberger  *
72af51229aSJoerg Sonnenberger  * 	o GMII and TBI ports/registers for interfacing with copper
73e5a5a436SSepherosa Ziehau  *	  or fiber PHYs.
74af51229aSJoerg Sonnenberger  *
75e5a5a436SSepherosa Ziehau  *      o RX and TX DMA rings can have up to 1024 descriptors.
76af51229aSJoerg Sonnenberger  *
77e5a5a436SSepherosa Ziehau  * The 8169 does not have a built-in PHY.  Most reference boards use a
78e5a5a436SSepherosa Ziehau  * Marvell 88E1000 'Alaska' copper gigE PHY.  8169/8110 is _no longer_
79e5a5a436SSepherosa Ziehau  * supported.
80af51229aSJoerg Sonnenberger  *
81af51229aSJoerg Sonnenberger  * The 8169S/8110S 10/100/1000 devices have built-in copper gigE PHYs
82af51229aSJoerg Sonnenberger  * (the 'S' stands for 'single-chip').  These devices have the same
83af51229aSJoerg Sonnenberger  * programming API as the older 8169, but also have some vendor-specific
84af51229aSJoerg Sonnenberger  * registers for the on-board PHY.  The 8110S is a LAN-on-motherboard
85af51229aSJoerg Sonnenberger  * part designed to be pin-compatible with the RealTek 8100 10/100 chip.
8680492964SSepherosa Ziehau  * 8125 supports 10/100/1000/2500.
87af51229aSJoerg Sonnenberger  *
88af51229aSJoerg Sonnenberger  * This driver takes advantage of the RX and TX checksum offload and
89e5a5a436SSepherosa Ziehau  * VLAN tag insertion/extraction features.  It also implements
90af51229aSJoerg Sonnenberger  * interrupt moderation using the timer interrupt registers, which
91e5a5a436SSepherosa Ziehau  * significantly reduces interrupt load.
92af51229aSJoerg Sonnenberger  */
93af51229aSJoerg Sonnenberger 
94043ecbf0SSepherosa Ziehau #define _IP_VHL
95043ecbf0SSepherosa Ziehau 
967816ba83SSepherosa Ziehau #include "opt_ifpoll.h"
972b71c8f1SSepherosa Ziehau 
98af51229aSJoerg Sonnenberger #include <sys/param.h>
991f7ab7c9SMatthew Dillon #include <sys/bus.h>
1005d686fbbSSepherosa Ziehau #include <sys/endian.h>
1015d686fbbSSepherosa Ziehau #include <sys/kernel.h>
102043ecbf0SSepherosa Ziehau #include <sys/in_cksum.h>
1039db4b353SSepherosa Ziehau #include <sys/interrupt.h>
1045d686fbbSSepherosa Ziehau #include <sys/malloc.h>
1055d686fbbSSepherosa Ziehau #include <sys/mbuf.h>
1061f7ab7c9SMatthew Dillon #include <sys/rman.h>
1075d686fbbSSepherosa Ziehau #include <sys/serialize.h>
1085d686fbbSSepherosa Ziehau #include <sys/socket.h>
1095d686fbbSSepherosa Ziehau #include <sys/sockio.h>
1105d686fbbSSepherosa Ziehau #include <sys/sysctl.h>
111af51229aSJoerg Sonnenberger 
1125d686fbbSSepherosa Ziehau #include <net/bpf.h>
1135d686fbbSSepherosa Ziehau #include <net/ethernet.h>
114af51229aSJoerg Sonnenberger #include <net/if.h>
1154d723e5aSJoerg Sonnenberger #include <net/ifq_var.h>
116af51229aSJoerg Sonnenberger #include <net/if_arp.h>
117af51229aSJoerg Sonnenberger #include <net/if_dl.h>
118af51229aSJoerg Sonnenberger #include <net/if_media.h>
1197816ba83SSepherosa Ziehau #include <net/if_poll.h>
120af51229aSJoerg Sonnenberger #include <net/if_types.h>
121af51229aSJoerg Sonnenberger #include <net/vlan/if_vlan_var.h>
122b637f170SSepherosa Ziehau #include <net/vlan/if_vlan_ether.h>
123af51229aSJoerg Sonnenberger 
124043ecbf0SSepherosa Ziehau #include <netinet/ip.h>
125043ecbf0SSepherosa Ziehau 
126dcb4b80dSSascha Wildner #include "pcidevs.h"
127af51229aSJoerg Sonnenberger #include <bus/pci/pcireg.h>
128af51229aSJoerg Sonnenberger #include <bus/pci/pcivar.h>
129af51229aSJoerg Sonnenberger 
130af51229aSJoerg Sonnenberger #include <dev/netif/re/if_rereg.h>
1315d686fbbSSepherosa Ziehau #include <dev/netif/re/if_revar.h>
132e5a5a436SSepherosa Ziehau #include <dev/netif/re/re.h>
133e5a5a436SSepherosa Ziehau #include <dev/netif/re/re_dragonfly.h>
134af51229aSJoerg Sonnenberger 
135af51229aSJoerg Sonnenberger /*
136af51229aSJoerg Sonnenberger  * Various supported device vendors/types and their names.
137af51229aSJoerg Sonnenberger  */
1380f035de6SSepherosa Ziehau static const struct re_type {
1390f035de6SSepherosa Ziehau 	uint16_t	re_vid;
1400f035de6SSepherosa Ziehau 	uint16_t	re_did;
1410f035de6SSepherosa Ziehau 	const char	*re_name;
1420f035de6SSepherosa Ziehau } re_devs[] = {
1430f035de6SSepherosa Ziehau 	{ PCI_VENDOR_DLINK, PCI_PRODUCT_DLINK_DGE528T,
14425c5ec5fSMatthew Dillon 	  "D-Link DGE-528(T) Gigabit Ethernet Adapter" },
1450f035de6SSepherosa Ziehau 
1460f035de6SSepherosa Ziehau 	{ PCI_VENDOR_REALTEK, PCI_PRODUCT_REALTEK_RT8101E,
1470f035de6SSepherosa Ziehau 	  "RealTek 810x PCIe 10/100baseTX" },
1480f035de6SSepherosa Ziehau 
1490f035de6SSepherosa Ziehau 	{ PCI_VENDOR_REALTEK, PCI_PRODUCT_REALTEK_RT8168,
1500f035de6SSepherosa Ziehau 	  "RealTek 8111/8168 PCIe Gigabit Ethernet" },
1510f035de6SSepherosa Ziehau 
152e5a5a436SSepherosa Ziehau 	{ PCI_VENDOR_REALTEK, PCI_PRODUCT_REALTEK_RT8168_1,
153e5a5a436SSepherosa Ziehau 	  "RealTek 8168 PCIe Gigabit Ethernet" },
154e5a5a436SSepherosa Ziehau 
15580492964SSepherosa Ziehau 	{ PCI_VENDOR_REALTEK, PCI_PRODUCT_REALTEK_RT8125,
15680492964SSepherosa Ziehau 	  "RealTek 8125 PCIe Gigabit Ethernet" },
15780492964SSepherosa Ziehau 
158e5a5a436SSepherosa Ziehau #ifdef notyet
159e5a5a436SSepherosa Ziehau 	/*
160e5a5a436SSepherosa Ziehau 	 * This driver now only supports built-in PHYs.
161e5a5a436SSepherosa Ziehau 	 */
1620f035de6SSepherosa Ziehau 	{ PCI_VENDOR_REALTEK, PCI_PRODUCT_REALTEK_RT8169,
1630f035de6SSepherosa Ziehau 	  "RealTek 8110/8169 Gigabit Ethernet" },
164e5a5a436SSepherosa Ziehau #endif
1650f035de6SSepherosa Ziehau 
1660f035de6SSepherosa Ziehau 	{ PCI_VENDOR_REALTEK, PCI_PRODUCT_REALTEK_RT8169SC,
167d5f8bb94SSepherosa Ziehau 	  "RealTek 8169SC/8110SC Single-chip Gigabit Ethernet" },
1680f035de6SSepherosa Ziehau 
1690f035de6SSepherosa Ziehau 	{ PCI_VENDOR_COREGA, PCI_PRODUCT_COREGA_CG_LAPCIGT,
170139efd88SSepherosa Ziehau 	  "Corega CG-LAPCIGT Gigabit Ethernet" },
1710f035de6SSepherosa Ziehau 
1720f035de6SSepherosa Ziehau 	{ PCI_VENDOR_LINKSYS, PCI_PRODUCT_LINKSYS_EG1032,
1735fdf38d0SSepherosa Ziehau 	  "Linksys EG1032 Gigabit Ethernet" },
1740f035de6SSepherosa Ziehau 
1750f035de6SSepherosa Ziehau 	{ PCI_VENDOR_USR2, PCI_PRODUCT_USR2_997902,
1765d686fbbSSepherosa Ziehau 	  "US Robotics 997902 Gigabit Ethernet" },
1770f035de6SSepherosa Ziehau 
1780263845aSSepherosa Ziehau 	{ PCI_VENDOR_TTTECH, PCI_PRODUCT_TTTECH_MC322,
1790263845aSSepherosa Ziehau 	  "TTTech MC322 Gigabit Ethernet" },
1800263845aSSepherosa Ziehau 
181*bf80ef97SShingy Shabooya 	{ PCI_VENDOR_REALTEK, PCI_PRODUCT_REALTEK_RT2600,
182*bf80ef97SShingy Shabooya            "RealTek Killer E2600 Gigabit Ethernet Controller" },
183*bf80ef97SShingy Shabooya 
1840f035de6SSepherosa Ziehau 	{ 0, 0, NULL }
185af51229aSJoerg Sonnenberger };
186af51229aSJoerg Sonnenberger 
187af51229aSJoerg Sonnenberger static int	re_probe(device_t);
188af51229aSJoerg Sonnenberger static int	re_attach(device_t);
189af51229aSJoerg Sonnenberger static int	re_detach(device_t);
1906fbd7e67SSepherosa Ziehau static int	re_suspend(device_t);
1916fbd7e67SSepherosa Ziehau static int	re_resume(device_t);
1926fbd7e67SSepherosa Ziehau static void	re_shutdown(device_t);
193af51229aSJoerg Sonnenberger 
1948d9cb301SSepherosa Ziehau static int	re_allocmem(device_t);
1958d9cb301SSepherosa Ziehau static void	re_freemem(device_t);
1968d9cb301SSepherosa Ziehau static void	re_freebufmem(struct re_softc *, int, int);
1973580fc56SSepherosa Ziehau static int	re_encap(struct re_softc *, struct mbuf **, int *);
198a7d57e62SSepherosa Ziehau static int	re_newbuf_std(struct re_softc *, int, int);
199e5a5a436SSepherosa Ziehau #ifdef RE_JUMBO
200a7d57e62SSepherosa Ziehau static int	re_newbuf_jumbo(struct re_softc *, int, int);
201e5a5a436SSepherosa Ziehau #endif
2023580fc56SSepherosa Ziehau static void	re_setup_rxdesc(struct re_softc *, int);
203af51229aSJoerg Sonnenberger static int	re_rx_list_init(struct re_softc *);
204af51229aSJoerg Sonnenberger static int	re_tx_list_init(struct re_softc *);
205d4d77345SSepherosa Ziehau static int	re_rxeof(struct re_softc *);
206d4d77345SSepherosa Ziehau static int	re_txeof(struct re_softc *);
207d3d3122dSSepherosa Ziehau static int	re_tx_collect(struct re_softc *);
208af51229aSJoerg Sonnenberger static void	re_intr(void *);
209af51229aSJoerg Sonnenberger static void	re_tick(void *);
21078195a76SMatthew Dillon static void	re_tick_serialized(void *);
211d7c373a4SSepherosa Ziehau static void	re_disable_aspm(device_t);
212e5a5a436SSepherosa Ziehau static void	re_link_up(struct re_softc *);
213e5a5a436SSepherosa Ziehau static void	re_link_down(struct re_softc *);
2146fbd7e67SSepherosa Ziehau 
21580492964SSepherosa Ziehau static void	re_start_xmit(struct re_softc *);
21680492964SSepherosa Ziehau static void	re_write_imr(struct re_softc *, uint32_t);
21780492964SSepherosa Ziehau static void	re_write_isr(struct re_softc *, uint32_t);
21880492964SSepherosa Ziehau static uint32_t	re_read_isr(struct re_softc *);
21980492964SSepherosa Ziehau static void	re_start_xmit_8125(struct re_softc *);
22080492964SSepherosa Ziehau static void	re_write_imr_8125(struct re_softc *, uint32_t);
22180492964SSepherosa Ziehau static void	re_write_isr_8125(struct re_softc *, uint32_t);
22280492964SSepherosa Ziehau static uint32_t	re_read_isr_8125(struct re_softc *);
22380492964SSepherosa Ziehau 
224f0a26983SSepherosa Ziehau static void	re_start(struct ifnet *, struct ifaltq_subque *);
225af51229aSJoerg Sonnenberger static int	re_ioctl(struct ifnet *, u_long, caddr_t, struct ucred *);
226af51229aSJoerg Sonnenberger static void	re_init(void *);
227e5a5a436SSepherosa Ziehau static void	re_stop(struct re_softc *, boolean_t);
228af51229aSJoerg Sonnenberger static void	re_watchdog(struct ifnet *);
229af51229aSJoerg Sonnenberger 
230d4d77345SSepherosa Ziehau static void	re_setup_hw_im(struct re_softc *);
231d4d77345SSepherosa Ziehau static void	re_setup_sim_im(struct re_softc *);
232d4d77345SSepherosa Ziehau static void	re_disable_hw_im(struct re_softc *);
233d4d77345SSepherosa Ziehau static void	re_disable_sim_im(struct re_softc *);
234d4d77345SSepherosa Ziehau static void	re_config_imtype(struct re_softc *, int);
235d4d77345SSepherosa Ziehau static void	re_setup_intr(struct re_softc *, int, int);
236d4d77345SSepherosa Ziehau 
237d4d77345SSepherosa Ziehau static int	re_sysctl_hwtime(SYSCTL_HANDLER_ARGS, int *);
238d4d77345SSepherosa Ziehau static int	re_sysctl_rxtime(SYSCTL_HANDLER_ARGS);
239d4d77345SSepherosa Ziehau static int	re_sysctl_txtime(SYSCTL_HANDLER_ARGS);
240d4d77345SSepherosa Ziehau static int	re_sysctl_simtime(SYSCTL_HANDLER_ARGS);
241d4d77345SSepherosa Ziehau static int	re_sysctl_imtype(SYSCTL_HANDLER_ARGS);
242d4d77345SSepherosa Ziehau 
243a7d57e62SSepherosa Ziehau static int	re_jpool_alloc(struct re_softc *);
244a7d57e62SSepherosa Ziehau static void	re_jpool_free(struct re_softc *);
245e5a5a436SSepherosa Ziehau #ifdef RE_JUMBO
246a7d57e62SSepherosa Ziehau static struct re_jbuf *re_jbuf_alloc(struct re_softc *);
247a7d57e62SSepherosa Ziehau static void	re_jbuf_free(void *);
248a7d57e62SSepherosa Ziehau static void	re_jbuf_ref(void *);
2495d686fbbSSepherosa Ziehau #endif
2505d686fbbSSepherosa Ziehau 
2517816ba83SSepherosa Ziehau #ifdef IFPOLL_ENABLE
2527816ba83SSepherosa Ziehau static void	re_npoll(struct ifnet *, struct ifpoll_info *);
2537816ba83SSepherosa Ziehau static void	re_npoll_compat(struct ifnet *, void *, int);
2549c095379SMatthew Dillon #endif
255af51229aSJoerg Sonnenberger 
256af51229aSJoerg Sonnenberger static device_method_t re_methods[] = {
257af51229aSJoerg Sonnenberger 	/* Device interface */
258af51229aSJoerg Sonnenberger 	DEVMETHOD(device_probe,		re_probe),
259af51229aSJoerg Sonnenberger 	DEVMETHOD(device_attach,	re_attach),
260af51229aSJoerg Sonnenberger 	DEVMETHOD(device_detach,	re_detach),
261af51229aSJoerg Sonnenberger 	DEVMETHOD(device_suspend,	re_suspend),
262af51229aSJoerg Sonnenberger 	DEVMETHOD(device_resume,	re_resume),
263af51229aSJoerg Sonnenberger 	DEVMETHOD(device_shutdown,	re_shutdown),
264d3c9c58eSSascha Wildner 	DEVMETHOD_END
265af51229aSJoerg Sonnenberger };
266af51229aSJoerg Sonnenberger 
267af51229aSJoerg Sonnenberger static driver_t re_driver = {
268af51229aSJoerg Sonnenberger 	"re",
269af51229aSJoerg Sonnenberger 	re_methods,
270af51229aSJoerg Sonnenberger 	sizeof(struct re_softc)
271af51229aSJoerg Sonnenberger };
272af51229aSJoerg Sonnenberger 
273af51229aSJoerg Sonnenberger static devclass_t re_devclass;
274af51229aSJoerg Sonnenberger 
275af51229aSJoerg Sonnenberger DECLARE_DUMMY_MODULE(if_re);
276aa2b9d05SSascha Wildner DRIVER_MODULE(if_re, pci, re_driver, re_devclass, NULL, NULL);
277aa2b9d05SSascha Wildner DRIVER_MODULE(if_re, cardbus, re_driver, re_devclass, NULL, NULL);
278af51229aSJoerg Sonnenberger 
27953d4588aSSepherosa Ziehau static int	re_rx_desc_count = RE_RX_DESC_CNT_DEF;
28053d4588aSSepherosa Ziehau static int	re_tx_desc_count = RE_TX_DESC_CNT_DEF;
281e5a5a436SSepherosa Ziehau static int	re_msi_enable = 1;
28253d4588aSSepherosa Ziehau 
28353d4588aSSepherosa Ziehau TUNABLE_INT("hw.re.rx_desc_count", &re_rx_desc_count);
28453d4588aSSepherosa Ziehau TUNABLE_INT("hw.re.tx_desc_count", &re_tx_desc_count);
2854dce912aSTim Bisson TUNABLE_INT("hw.re.msi.enable", &re_msi_enable);
28653d4588aSSepherosa Ziehau 
2872499e0afSSepherosa Ziehau static __inline void
re_free_rxchain(struct re_softc * sc)2882499e0afSSepherosa Ziehau re_free_rxchain(struct re_softc *sc)
2892499e0afSSepherosa Ziehau {
2902499e0afSSepherosa Ziehau 	if (sc->re_head != NULL) {
2912499e0afSSepherosa Ziehau 		m_freem(sc->re_head);
2922499e0afSSepherosa Ziehau 		sc->re_head = sc->re_tail = NULL;
2932499e0afSSepherosa Ziehau 	}
2942499e0afSSepherosa Ziehau }
2952499e0afSSepherosa Ziehau 
296af51229aSJoerg Sonnenberger static int
re_probe(device_t dev)297af51229aSJoerg Sonnenberger re_probe(device_t dev)
298af51229aSJoerg Sonnenberger {
2997caafb85SSepherosa Ziehau 	const struct re_type *t;
300af51229aSJoerg Sonnenberger 	uint16_t vendor, product;
301af51229aSJoerg Sonnenberger 
302af51229aSJoerg Sonnenberger 	vendor = pci_get_vendor(dev);
303af51229aSJoerg Sonnenberger 	product = pci_get_device(dev);
304af51229aSJoerg Sonnenberger 
3055fdf38d0SSepherosa Ziehau 	/*
3065fdf38d0SSepherosa Ziehau 	 * Only attach to rev.3 of the Linksys EG1032 adapter.
3075fdf38d0SSepherosa Ziehau 	 * Rev.2 is supported by sk(4).
3085fdf38d0SSepherosa Ziehau 	 */
3095fdf38d0SSepherosa Ziehau 	if (vendor == PCI_VENDOR_LINKSYS &&
3105fdf38d0SSepherosa Ziehau 	    product == PCI_PRODUCT_LINKSYS_EG1032 &&
3115fdf38d0SSepherosa Ziehau 	    pci_get_subdevice(dev) != PCI_SUBDEVICE_LINKSYS_EG1032_REV3)
3125fdf38d0SSepherosa Ziehau 		return ENXIO;
3135fdf38d0SSepherosa Ziehau 
314af51229aSJoerg Sonnenberger 	for (t = re_devs; t->re_name != NULL; t++) {
315af51229aSJoerg Sonnenberger 		if (product == t->re_did && vendor == t->re_vid)
316af51229aSJoerg Sonnenberger 			break;
317af51229aSJoerg Sonnenberger 	}
318af51229aSJoerg Sonnenberger 	if (t->re_name == NULL)
3190f035de6SSepherosa Ziehau 		return ENXIO;
320af51229aSJoerg Sonnenberger 
3210f035de6SSepherosa Ziehau 	device_set_desc(dev, t->re_name);
3220f035de6SSepherosa Ziehau 	return 0;
3230f035de6SSepherosa Ziehau }
324af51229aSJoerg Sonnenberger 
325af51229aSJoerg Sonnenberger static int
re_allocmem(device_t dev)3268d9cb301SSepherosa Ziehau re_allocmem(device_t dev)
327af51229aSJoerg Sonnenberger {
3288d9cb301SSepherosa Ziehau 	struct re_softc *sc = device_get_softc(dev);
3290336fbc8SSepherosa Ziehau 	bus_dmamem_t dmem;
3303580fc56SSepherosa Ziehau 	int error, i;
331af51229aSJoerg Sonnenberger 
332af51229aSJoerg Sonnenberger 	/*
33353d4588aSSepherosa Ziehau 	 * Allocate list data
33453d4588aSSepherosa Ziehau 	 */
33553d4588aSSepherosa Ziehau 	sc->re_ldata.re_tx_mbuf =
33653d4588aSSepherosa Ziehau 	kmalloc(sc->re_tx_desc_cnt * sizeof(struct mbuf *),
33753d4588aSSepherosa Ziehau 		M_DEVBUF, M_ZERO | M_WAITOK);
33853d4588aSSepherosa Ziehau 
33953d4588aSSepherosa Ziehau 	sc->re_ldata.re_rx_mbuf =
34053d4588aSSepherosa Ziehau 	kmalloc(sc->re_rx_desc_cnt * sizeof(struct mbuf *),
34153d4588aSSepherosa Ziehau 		M_DEVBUF, M_ZERO | M_WAITOK);
34253d4588aSSepherosa Ziehau 
34353d4588aSSepherosa Ziehau 	sc->re_ldata.re_rx_paddr =
34453d4588aSSepherosa Ziehau 	kmalloc(sc->re_rx_desc_cnt * sizeof(bus_addr_t),
34553d4588aSSepherosa Ziehau 		M_DEVBUF, M_ZERO | M_WAITOK);
34653d4588aSSepherosa Ziehau 
34753d4588aSSepherosa Ziehau 	sc->re_ldata.re_tx_dmamap =
34853d4588aSSepherosa Ziehau 	kmalloc(sc->re_tx_desc_cnt * sizeof(bus_dmamap_t),
34953d4588aSSepherosa Ziehau 		M_DEVBUF, M_ZERO | M_WAITOK);
35053d4588aSSepherosa Ziehau 
35153d4588aSSepherosa Ziehau 	sc->re_ldata.re_rx_dmamap =
35253d4588aSSepherosa Ziehau 	kmalloc(sc->re_rx_desc_cnt * sizeof(bus_dmamap_t),
35353d4588aSSepherosa Ziehau 		M_DEVBUF, M_ZERO | M_WAITOK);
35453d4588aSSepherosa Ziehau 
35553d4588aSSepherosa Ziehau 	/*
3568d9cb301SSepherosa Ziehau 	 * Allocate the parent bus DMA tag appropriate for PCI.
357af51229aSJoerg Sonnenberger 	 */
3588d9cb301SSepherosa Ziehau 	error = bus_dma_tag_create(NULL,	/* parent */
3598d9cb301SSepherosa Ziehau 			1, 0,			/* alignment, boundary */
360adfa5aa6SSepherosa Ziehau 			BUS_SPACE_MAXADDR,	/* lowaddr */
3618d9cb301SSepherosa Ziehau 			BUS_SPACE_MAXADDR,	/* highaddr */
362adfa5aa6SSepherosa Ziehau 			BUS_SPACE_MAXSIZE_32BIT,/* maxsize */
363adfa5aa6SSepherosa Ziehau 			0,			/* nsegments */
3648d9cb301SSepherosa Ziehau 			BUS_SPACE_MAXSIZE_32BIT,/* maxsegsize */
365adfa5aa6SSepherosa Ziehau 			0,			/* flags */
3668d9cb301SSepherosa Ziehau 			&sc->re_parent_tag);
367af51229aSJoerg Sonnenberger 	if (error) {
3688d9cb301SSepherosa Ziehau 		device_printf(dev, "could not allocate parent dma tag\n");
3698d9cb301SSepherosa Ziehau 		return error;
370af51229aSJoerg Sonnenberger 	}
371af51229aSJoerg Sonnenberger 
3720336fbc8SSepherosa Ziehau 	/* Allocate TX descriptor list. */
3730336fbc8SSepherosa Ziehau 	error = bus_dmamem_coherent(sc->re_parent_tag,
3748d9cb301SSepherosa Ziehau 			RE_RING_ALIGN, 0,
375adfa5aa6SSepherosa Ziehau 			BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR,
3760336fbc8SSepherosa Ziehau 			RE_TX_LIST_SZ(sc), BUS_DMA_WAITOK | BUS_DMA_ZERO,
3770336fbc8SSepherosa Ziehau 			&dmem);
378af51229aSJoerg Sonnenberger 	if (error) {
379af51229aSJoerg Sonnenberger 		device_printf(dev, "could not allocate TX ring\n");
3800336fbc8SSepherosa Ziehau 		return error;
381af51229aSJoerg Sonnenberger 	}
3820336fbc8SSepherosa Ziehau 	sc->re_ldata.re_tx_list_tag = dmem.dmem_tag;
3830336fbc8SSepherosa Ziehau 	sc->re_ldata.re_tx_list_map = dmem.dmem_map;
3840336fbc8SSepherosa Ziehau 	sc->re_ldata.re_tx_list = dmem.dmem_addr;
3850336fbc8SSepherosa Ziehau 	sc->re_ldata.re_tx_list_addr = dmem.dmem_busaddr;
386af51229aSJoerg Sonnenberger 
3870336fbc8SSepherosa Ziehau 	/* Allocate RX descriptor list. */
3880336fbc8SSepherosa Ziehau 	error = bus_dmamem_coherent(sc->re_parent_tag,
3898d9cb301SSepherosa Ziehau 			RE_RING_ALIGN, 0,
390adfa5aa6SSepherosa Ziehau 			BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR,
3910336fbc8SSepherosa Ziehau 			RE_RX_LIST_SZ(sc), BUS_DMA_WAITOK | BUS_DMA_ZERO,
3920336fbc8SSepherosa Ziehau 			&dmem);
393af51229aSJoerg Sonnenberger 	if (error) {
394af51229aSJoerg Sonnenberger 		device_printf(dev, "could not allocate RX ring\n");
3950336fbc8SSepherosa Ziehau 		return error;
396af51229aSJoerg Sonnenberger 	}
3970336fbc8SSepherosa Ziehau 	sc->re_ldata.re_rx_list_tag = dmem.dmem_tag;
3980336fbc8SSepherosa Ziehau 	sc->re_ldata.re_rx_list_map = dmem.dmem_map;
3990336fbc8SSepherosa Ziehau 	sc->re_ldata.re_rx_list = dmem.dmem_addr;
4000336fbc8SSepherosa Ziehau 	sc->re_ldata.re_rx_list_addr = dmem.dmem_busaddr;
401af51229aSJoerg Sonnenberger 
4028aaa1e58SSepherosa Ziehau 	/* Allocate maps for TX mbufs. */
4038d9cb301SSepherosa Ziehau 	error = bus_dma_tag_create(sc->re_parent_tag,
404adfa5aa6SSepherosa Ziehau 			1, 0,
405adfa5aa6SSepherosa Ziehau 			BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR,
406b0c15aadSSepherosa Ziehau 			RE_FRAMELEN_MAX, RE_MAXSEGS, MCLBYTES,
40790a9e482SSepherosa Ziehau 			BUS_DMA_ALLOCNOW | BUS_DMA_WAITOK | BUS_DMA_ONEBPAGE,
4088aaa1e58SSepherosa Ziehau 			&sc->re_ldata.re_tx_mtag);
409af51229aSJoerg Sonnenberger 	if (error) {
4108aaa1e58SSepherosa Ziehau 		device_printf(dev, "could not allocate TX buf dma tag\n");
4118d9cb301SSepherosa Ziehau 		return(error);
412af51229aSJoerg Sonnenberger 	}
413af51229aSJoerg Sonnenberger 
4148d9cb301SSepherosa Ziehau 	/* Create DMA maps for TX buffers */
41553d4588aSSepherosa Ziehau 	for (i = 0; i < sc->re_tx_desc_cnt; i++) {
41612aa407cSSepherosa Ziehau 		error = bus_dmamap_create(sc->re_ldata.re_tx_mtag,
41790a9e482SSepherosa Ziehau 				BUS_DMA_WAITOK | BUS_DMA_ONEBPAGE,
4188d9cb301SSepherosa Ziehau 				&sc->re_ldata.re_tx_dmamap[i]);
4198d9cb301SSepherosa Ziehau 		if (error) {
4208d9cb301SSepherosa Ziehau 			device_printf(dev, "can't create DMA map for TX buf\n");
4218d9cb301SSepherosa Ziehau 			re_freebufmem(sc, i, 0);
4228d9cb301SSepherosa Ziehau 			return(error);
4238d9cb301SSepherosa Ziehau 		}
4248d9cb301SSepherosa Ziehau 	}
4258d9cb301SSepherosa Ziehau 
4268aaa1e58SSepherosa Ziehau 	/* Allocate maps for RX mbufs. */
4278aaa1e58SSepherosa Ziehau 	error = bus_dma_tag_create(sc->re_parent_tag,
4288aaa1e58SSepherosa Ziehau 			RE_RXBUF_ALIGN, 0,
4298aaa1e58SSepherosa Ziehau 			BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR,
4308aaa1e58SSepherosa Ziehau 			MCLBYTES, 1, MCLBYTES,
43190a9e482SSepherosa Ziehau 			BUS_DMA_ALLOCNOW | BUS_DMA_WAITOK | BUS_DMA_ALIGNED,
4328aaa1e58SSepherosa Ziehau 			&sc->re_ldata.re_rx_mtag);
4338aaa1e58SSepherosa Ziehau 	if (error) {
4348aaa1e58SSepherosa Ziehau 		device_printf(dev, "could not allocate RX buf dma tag\n");
4358aaa1e58SSepherosa Ziehau 		return(error);
4368aaa1e58SSepherosa Ziehau 	}
4378aaa1e58SSepherosa Ziehau 
4388aaa1e58SSepherosa Ziehau 	/* Create spare DMA map for RX */
439b1d91829SSepherosa Ziehau 	error = bus_dmamap_create(sc->re_ldata.re_rx_mtag, BUS_DMA_WAITOK,
4408aaa1e58SSepherosa Ziehau 			&sc->re_ldata.re_rx_spare);
4418aaa1e58SSepherosa Ziehau 	if (error) {
4428aaa1e58SSepherosa Ziehau 		device_printf(dev, "can't create spare DMA map for RX\n");
4438aaa1e58SSepherosa Ziehau 		bus_dma_tag_destroy(sc->re_ldata.re_rx_mtag);
4448aaa1e58SSepherosa Ziehau 		sc->re_ldata.re_rx_mtag = NULL;
4458aaa1e58SSepherosa Ziehau 		return error;
4468aaa1e58SSepherosa Ziehau 	}
4478aaa1e58SSepherosa Ziehau 
4488d9cb301SSepherosa Ziehau 	/* Create DMA maps for RX buffers */
44953d4588aSSepherosa Ziehau 	for (i = 0; i < sc->re_rx_desc_cnt; i++) {
45012aa407cSSepherosa Ziehau 		error = bus_dmamap_create(sc->re_ldata.re_rx_mtag,
45112aa407cSSepherosa Ziehau 				BUS_DMA_WAITOK, &sc->re_ldata.re_rx_dmamap[i]);
4528d9cb301SSepherosa Ziehau 		if (error) {
4538d9cb301SSepherosa Ziehau 			device_printf(dev, "can't create DMA map for RX buf\n");
45453d4588aSSepherosa Ziehau 			re_freebufmem(sc, sc->re_tx_desc_cnt, i);
4558d9cb301SSepherosa Ziehau 			return(error);
4568d9cb301SSepherosa Ziehau 		}
4578d9cb301SSepherosa Ziehau 	}
458a7d57e62SSepherosa Ziehau 
459a7d57e62SSepherosa Ziehau 	/* Create jumbo buffer pool for RX if required */
460a7d57e62SSepherosa Ziehau 	if (sc->re_caps & RE_C_CONTIGRX) {
461a7d57e62SSepherosa Ziehau 		error = re_jpool_alloc(sc);
462a7d57e62SSepherosa Ziehau 		if (error) {
463a7d57e62SSepherosa Ziehau 			re_jpool_free(sc);
464e5a5a436SSepherosa Ziehau #ifdef RE_JUMBO
465b0c15aadSSepherosa Ziehau 			/* Disable jumbo frame support */
466a7d57e62SSepherosa Ziehau 			sc->re_maxmtu = ETHERMTU;
467e5a5a436SSepherosa Ziehau #endif
468a7d57e62SSepherosa Ziehau 		}
469a7d57e62SSepherosa Ziehau 	}
470af51229aSJoerg Sonnenberger 	return(0);
471af51229aSJoerg Sonnenberger }
472af51229aSJoerg Sonnenberger 
4738d9cb301SSepherosa Ziehau static void
re_freebufmem(struct re_softc * sc,int tx_cnt,int rx_cnt)4748d9cb301SSepherosa Ziehau re_freebufmem(struct re_softc *sc, int tx_cnt, int rx_cnt)
4758d9cb301SSepherosa Ziehau {
4768d9cb301SSepherosa Ziehau 	int i;
4778d9cb301SSepherosa Ziehau 
4788d9cb301SSepherosa Ziehau 	/* Destroy all the RX and TX buffer maps */
4798aaa1e58SSepherosa Ziehau 	if (sc->re_ldata.re_tx_mtag) {
4808d9cb301SSepherosa Ziehau 		for (i = 0; i < tx_cnt; i++) {
4818aaa1e58SSepherosa Ziehau 			bus_dmamap_destroy(sc->re_ldata.re_tx_mtag,
4828d9cb301SSepherosa Ziehau 					   sc->re_ldata.re_tx_dmamap[i]);
4838d9cb301SSepherosa Ziehau 		}
4848aaa1e58SSepherosa Ziehau 		bus_dma_tag_destroy(sc->re_ldata.re_tx_mtag);
4858aaa1e58SSepherosa Ziehau 		sc->re_ldata.re_tx_mtag = NULL;
4868aaa1e58SSepherosa Ziehau 	}
4878aaa1e58SSepherosa Ziehau 
4888aaa1e58SSepherosa Ziehau 	if (sc->re_ldata.re_rx_mtag) {
4898d9cb301SSepherosa Ziehau 		for (i = 0; i < rx_cnt; i++) {
4908aaa1e58SSepherosa Ziehau 			bus_dmamap_destroy(sc->re_ldata.re_rx_mtag,
4918d9cb301SSepherosa Ziehau 					   sc->re_ldata.re_rx_dmamap[i]);
4928d9cb301SSepherosa Ziehau 		}
4938aaa1e58SSepherosa Ziehau 		bus_dmamap_destroy(sc->re_ldata.re_rx_mtag,
4948d9cb301SSepherosa Ziehau 				   sc->re_ldata.re_rx_spare);
4958aaa1e58SSepherosa Ziehau 		bus_dma_tag_destroy(sc->re_ldata.re_rx_mtag);
4968aaa1e58SSepherosa Ziehau 		sc->re_ldata.re_rx_mtag = NULL;
4978d9cb301SSepherosa Ziehau 	}
4988d9cb301SSepherosa Ziehau }
4998d9cb301SSepherosa Ziehau 
5008d9cb301SSepherosa Ziehau static void
re_freemem(device_t dev)5018d9cb301SSepherosa Ziehau re_freemem(device_t dev)
5028d9cb301SSepherosa Ziehau {
5038d9cb301SSepherosa Ziehau 	struct re_softc *sc = device_get_softc(dev);
5048d9cb301SSepherosa Ziehau 
5058d9cb301SSepherosa Ziehau 	/* Unload and free the RX DMA ring memory and map */
5068d9cb301SSepherosa Ziehau 	if (sc->re_ldata.re_rx_list_tag) {
5078d9cb301SSepherosa Ziehau 		bus_dmamap_unload(sc->re_ldata.re_rx_list_tag,
5088d9cb301SSepherosa Ziehau 				  sc->re_ldata.re_rx_list_map);
5098d9cb301SSepherosa Ziehau 		bus_dmamem_free(sc->re_ldata.re_rx_list_tag,
5108d9cb301SSepherosa Ziehau 				sc->re_ldata.re_rx_list,
5118d9cb301SSepherosa Ziehau 				sc->re_ldata.re_rx_list_map);
5128d9cb301SSepherosa Ziehau 		bus_dma_tag_destroy(sc->re_ldata.re_rx_list_tag);
5138d9cb301SSepherosa Ziehau 	}
5148d9cb301SSepherosa Ziehau 
5158d9cb301SSepherosa Ziehau 	/* Unload and free the TX DMA ring memory and map */
5168d9cb301SSepherosa Ziehau 	if (sc->re_ldata.re_tx_list_tag) {
5178d9cb301SSepherosa Ziehau 		bus_dmamap_unload(sc->re_ldata.re_tx_list_tag,
5188d9cb301SSepherosa Ziehau 				  sc->re_ldata.re_tx_list_map);
5198d9cb301SSepherosa Ziehau 		bus_dmamem_free(sc->re_ldata.re_tx_list_tag,
5208d9cb301SSepherosa Ziehau 				sc->re_ldata.re_tx_list,
5218d9cb301SSepherosa Ziehau 				sc->re_ldata.re_tx_list_map);
5228d9cb301SSepherosa Ziehau 		bus_dma_tag_destroy(sc->re_ldata.re_tx_list_tag);
5238d9cb301SSepherosa Ziehau 	}
5248d9cb301SSepherosa Ziehau 
5258d9cb301SSepherosa Ziehau 	/* Free RX/TX buf DMA stuffs */
52653d4588aSSepherosa Ziehau 	re_freebufmem(sc, sc->re_tx_desc_cnt, sc->re_rx_desc_cnt);
5278d9cb301SSepherosa Ziehau 
5288d9cb301SSepherosa Ziehau 	/* Unload and free the stats buffer and map */
5298d9cb301SSepherosa Ziehau 	if (sc->re_ldata.re_stag) {
530e9340781SSepherosa Ziehau 		bus_dmamap_unload(sc->re_ldata.re_stag, sc->re_ldata.re_smap);
5318d9cb301SSepherosa Ziehau 		bus_dmamem_free(sc->re_ldata.re_stag,
5328d9cb301SSepherosa Ziehau 				sc->re_ldata.re_stats,
5338d9cb301SSepherosa Ziehau 				sc->re_ldata.re_smap);
5348d9cb301SSepherosa Ziehau 		bus_dma_tag_destroy(sc->re_ldata.re_stag);
5358d9cb301SSepherosa Ziehau 	}
5368d9cb301SSepherosa Ziehau 
537a7d57e62SSepherosa Ziehau 	if (sc->re_caps & RE_C_CONTIGRX)
538a7d57e62SSepherosa Ziehau 		re_jpool_free(sc);
539a7d57e62SSepherosa Ziehau 
5408d9cb301SSepherosa Ziehau 	if (sc->re_parent_tag)
5418d9cb301SSepherosa Ziehau 		bus_dma_tag_destroy(sc->re_parent_tag);
54253d4588aSSepherosa Ziehau 
54353d4588aSSepherosa Ziehau 	if (sc->re_ldata.re_tx_mbuf != NULL)
54453d4588aSSepherosa Ziehau 		kfree(sc->re_ldata.re_tx_mbuf, M_DEVBUF);
54553d4588aSSepherosa Ziehau 	if (sc->re_ldata.re_rx_mbuf != NULL)
54653d4588aSSepherosa Ziehau 		kfree(sc->re_ldata.re_rx_mbuf, M_DEVBUF);
54753d4588aSSepherosa Ziehau 	if (sc->re_ldata.re_rx_paddr != NULL)
54853d4588aSSepherosa Ziehau 		kfree(sc->re_ldata.re_rx_paddr, M_DEVBUF);
54953d4588aSSepherosa Ziehau 	if (sc->re_ldata.re_tx_dmamap != NULL)
55053d4588aSSepherosa Ziehau 		kfree(sc->re_ldata.re_tx_dmamap, M_DEVBUF);
55153d4588aSSepherosa Ziehau 	if (sc->re_ldata.re_rx_dmamap != NULL)
55253d4588aSSepherosa Ziehau 		kfree(sc->re_ldata.re_rx_dmamap, M_DEVBUF);
5538d9cb301SSepherosa Ziehau }
5548d9cb301SSepherosa Ziehau 
555e5a5a436SSepherosa Ziehau static boolean_t
re_is_faste(struct re_softc * sc)556e5a5a436SSepherosa Ziehau re_is_faste(struct re_softc *sc)
557e5a5a436SSepherosa Ziehau {
558e5a5a436SSepherosa Ziehau 	if (pci_get_vendor(sc->dev) == PCI_VENDOR_REALTEK) {
559e5a5a436SSepherosa Ziehau 		switch (sc->re_device_id) {
560e5a5a436SSepherosa Ziehau 		case PCI_PRODUCT_REALTEK_RT8169:
561e5a5a436SSepherosa Ziehau 		case PCI_PRODUCT_REALTEK_RT8169SC:
562e5a5a436SSepherosa Ziehau 		case PCI_PRODUCT_REALTEK_RT8168:
563e5a5a436SSepherosa Ziehau 		case PCI_PRODUCT_REALTEK_RT8168_1:
56480492964SSepherosa Ziehau 		case PCI_PRODUCT_REALTEK_RT8125:
565e5a5a436SSepherosa Ziehau 			return FALSE;
566e5a5a436SSepherosa Ziehau 		default:
567e5a5a436SSepherosa Ziehau 			return TRUE;
568e5a5a436SSepherosa Ziehau 		}
569e5a5a436SSepherosa Ziehau 	} else {
570e5a5a436SSepherosa Ziehau 		return FALSE;
571e5a5a436SSepherosa Ziehau 	}
572e5a5a436SSepherosa Ziehau }
573e5a5a436SSepherosa Ziehau 
57480492964SSepherosa Ziehau static bool
re_is_2500e(const struct re_softc * sc)57580492964SSepherosa Ziehau re_is_2500e(const struct re_softc *sc)
57680492964SSepherosa Ziehau {
57780492964SSepherosa Ziehau 	if (pci_get_vendor(sc->dev) == PCI_VENDOR_REALTEK) {
57880492964SSepherosa Ziehau 		switch (sc->re_device_id) {
57980492964SSepherosa Ziehau 		case PCI_PRODUCT_REALTEK_RT8125:
58080492964SSepherosa Ziehau 			return true;
58180492964SSepherosa Ziehau 
58280492964SSepherosa Ziehau 		default:
58380492964SSepherosa Ziehau 			return false;
58480492964SSepherosa Ziehau 		}
58580492964SSepherosa Ziehau 	}
58680492964SSepherosa Ziehau 	return false;
58780492964SSepherosa Ziehau }
58880492964SSepherosa Ziehau 
589af51229aSJoerg Sonnenberger /*
590af51229aSJoerg Sonnenberger  * Attach the interface. Allocate softc structures, do ifmedia
591af51229aSJoerg Sonnenberger  * setup and ethernet/BPF attach.
592af51229aSJoerg Sonnenberger  */
593af51229aSJoerg Sonnenberger static int
re_attach(device_t dev)594af51229aSJoerg Sonnenberger re_attach(device_t dev)
595af51229aSJoerg Sonnenberger {
596af51229aSJoerg Sonnenberger 	struct re_softc	*sc = device_get_softc(dev);
597af51229aSJoerg Sonnenberger 	struct ifnet *ifp;
59826595b18SSascha Wildner 	struct sysctl_ctx_list *ctx;
59926595b18SSascha Wildner 	struct sysctl_oid *tree;
600e5a5a436SSepherosa Ziehau 	uint8_t eaddr[ETHER_ADDR_LEN];
601e5a5a436SSepherosa Ziehau 	int error = 0, qlen, msi_enable;
6024dce912aSTim Bisson 	u_int irq_flags;
603af51229aSJoerg Sonnenberger 
6040545a061SFrançois Tigeot 	callout_init_mp(&sc->re_timer);
605e5a5a436SSepherosa Ziehau 	sc->dev = dev;
606e5a5a436SSepherosa Ziehau 	sc->re_device_id = pci_get_device(dev);
607e5a5a436SSepherosa Ziehau 	sc->re_unit = device_get_unit(dev);
608e5a5a436SSepherosa Ziehau 	ifmedia_init(&sc->media, IFM_IMASK, rtl_ifmedia_upd, rtl_ifmedia_sts);
6095d686fbbSSepherosa Ziehau 
61080492964SSepherosa Ziehau 	if (pci_get_vendor(dev) == PCI_VENDOR_REALTEK &&
61180492964SSepherosa Ziehau 	    sc->re_device_id == PCI_PRODUCT_REALTEK_RT8125) {
61280492964SSepherosa Ziehau 		sc->re_start_xmit = re_start_xmit_8125;
61380492964SSepherosa Ziehau 		sc->re_write_imr = re_write_imr_8125;
61480492964SSepherosa Ziehau 		sc->re_write_isr = re_write_isr_8125;
61580492964SSepherosa Ziehau 		sc->re_read_isr = re_read_isr_8125;
61680492964SSepherosa Ziehau 	} else {
61780492964SSepherosa Ziehau 		sc->re_start_xmit = re_start_xmit;
61880492964SSepherosa Ziehau 		sc->re_write_imr = re_write_imr;
61980492964SSepherosa Ziehau 		sc->re_write_isr = re_write_isr;
62080492964SSepherosa Ziehau 		sc->re_read_isr = re_read_isr;
62180492964SSepherosa Ziehau 	}
62280492964SSepherosa Ziehau 
623e5a5a436SSepherosa Ziehau 	sc->re_caps = RE_C_HWIM;
624e5a5a436SSepherosa Ziehau 
62553d4588aSSepherosa Ziehau 	sc->re_rx_desc_cnt = re_rx_desc_count;
62653d4588aSSepherosa Ziehau 	if (sc->re_rx_desc_cnt > RE_RX_DESC_CNT_MAX)
62753d4588aSSepherosa Ziehau 		sc->re_rx_desc_cnt = RE_RX_DESC_CNT_MAX;
62853d4588aSSepherosa Ziehau 
62953d4588aSSepherosa Ziehau 	sc->re_tx_desc_cnt = re_tx_desc_count;
63053d4588aSSepherosa Ziehau 	if (sc->re_tx_desc_cnt > RE_TX_DESC_CNT_MAX)
63153d4588aSSepherosa Ziehau 		sc->re_tx_desc_cnt = RE_TX_DESC_CNT_MAX;
63253d4588aSSepherosa Ziehau 
63379280061SSepherosa Ziehau 	qlen = RE_IFQ_MAXLEN;
6340f035de6SSepherosa Ziehau 	if (sc->re_tx_desc_cnt > qlen)
63579280061SSepherosa Ziehau 		qlen = sc->re_tx_desc_cnt;
63679280061SSepherosa Ziehau 
637a7d57e62SSepherosa Ziehau 	sc->re_rxbuf_size = MCLBYTES;
638a7d57e62SSepherosa Ziehau 	sc->re_newbuf = re_newbuf_std;
639a7d57e62SSepherosa Ziehau 
640e5a5a436SSepherosa Ziehau 	/*
641e5a5a436SSepherosa Ziehau 	 * Hardware interrupt moderation settings.
642e5a5a436SSepherosa Ziehau 	 * XXX does not seem correct, undocumented.
643e5a5a436SSepherosa Ziehau 	 */
644d4d77345SSepherosa Ziehau 	sc->re_tx_time = 5;		/* 125us */
645d4d77345SSepherosa Ziehau 	sc->re_rx_time = 2;		/* 50us */
646e5a5a436SSepherosa Ziehau 
647e5a5a436SSepherosa Ziehau 	/* Simulated interrupt moderation setting. */
648e5a5a436SSepherosa Ziehau 	sc->re_sim_time = 150;		/* 150us */
649e5a5a436SSepherosa Ziehau 
650e5a5a436SSepherosa Ziehau 	/* Use simulated interrupt moderation by default. */
651f633c5a9SSepherosa Ziehau 	sc->re_imtype = RE_IMTYPE_SIM;
652d4d77345SSepherosa Ziehau 	re_config_imtype(sc, sc->re_imtype);
6535d686fbbSSepherosa Ziehau 
65426595b18SSascha Wildner 	ctx = device_get_sysctl_ctx(dev);
65526595b18SSascha Wildner 	tree = device_get_sysctl_tree(dev);
65626595b18SSascha Wildner 	SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
65753d4588aSSepherosa Ziehau 		       "rx_desc_count", CTLFLAG_RD, &sc->re_rx_desc_cnt,
65853d4588aSSepherosa Ziehau 		       0, "RX desc count");
65926595b18SSascha Wildner 	SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
66053d4588aSSepherosa Ziehau 		       "tx_desc_count", CTLFLAG_RD, &sc->re_tx_desc_cnt,
66153d4588aSSepherosa Ziehau 		       0, "TX desc count");
66226595b18SSascha Wildner 	SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, "sim_time",
663d4d77345SSepherosa Ziehau 			CTLTYPE_INT | CTLFLAG_RW,
664d4d77345SSepherosa Ziehau 			sc, 0, re_sysctl_simtime, "I",
665d4d77345SSepherosa Ziehau 			"Simulated interrupt moderation time (usec).");
66626595b18SSascha Wildner 	SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, "imtype",
667d4d77345SSepherosa Ziehau 			CTLTYPE_INT | CTLFLAG_RW,
668d4d77345SSepherosa Ziehau 			sc, 0, re_sysctl_imtype, "I",
669d4d77345SSepherosa Ziehau 			"Interrupt moderation type -- "
670d4d77345SSepherosa Ziehau 			"0:disable, 1:simulated, "
671d4d77345SSepherosa Ziehau 			"2:hardware(if supported)");
6720f035de6SSepherosa Ziehau 	if (sc->re_caps & RE_C_HWIM) {
67326595b18SSascha Wildner 		SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree),
6740f035de6SSepherosa Ziehau 				OID_AUTO, "hw_rxtime",
6750f035de6SSepherosa Ziehau 				CTLTYPE_INT | CTLFLAG_RW,
6760f035de6SSepherosa Ziehau 				sc, 0, re_sysctl_rxtime, "I",
6770f035de6SSepherosa Ziehau 				"Hardware interrupt moderation time "
6780f035de6SSepherosa Ziehau 				"(unit: 25usec).");
67926595b18SSascha Wildner 		SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree),
6800f035de6SSepherosa Ziehau 				OID_AUTO, "hw_txtime",
6810f035de6SSepherosa Ziehau 				CTLTYPE_INT | CTLFLAG_RW,
6820f035de6SSepherosa Ziehau 				sc, 0, re_sysctl_txtime, "I",
6830f035de6SSepherosa Ziehau 				"Hardware interrupt moderation time "
6840f035de6SSepherosa Ziehau 				"(unit: 25usec).");
6850f035de6SSepherosa Ziehau 	}
686af51229aSJoerg Sonnenberger 
687af51229aSJoerg Sonnenberger #ifndef BURN_BRIDGES
688af51229aSJoerg Sonnenberger 	/*
689af51229aSJoerg Sonnenberger 	 * Handle power management nonsense.
690af51229aSJoerg Sonnenberger 	 */
691af51229aSJoerg Sonnenberger 
692af51229aSJoerg Sonnenberger 	if (pci_get_powerstate(dev) != PCI_POWERSTATE_D0) {
693af51229aSJoerg Sonnenberger 		uint32_t membase, irq;
694af51229aSJoerg Sonnenberger 
695af51229aSJoerg Sonnenberger 		/* Save important PCI config data. */
696af51229aSJoerg Sonnenberger 		membase = pci_read_config(dev, RE_PCI_LOMEM, 4);
697af51229aSJoerg Sonnenberger 		irq = pci_read_config(dev, PCIR_INTLINE, 4);
698af51229aSJoerg Sonnenberger 
699af51229aSJoerg Sonnenberger 		/* Reset the power state. */
700c045389bSHasso Tepper 		device_printf(dev, "chip is in D%d power mode "
701af51229aSJoerg Sonnenberger 		    "-- setting to D0\n", pci_get_powerstate(dev));
702af51229aSJoerg Sonnenberger 
703af51229aSJoerg Sonnenberger 		pci_set_powerstate(dev, PCI_POWERSTATE_D0);
704af51229aSJoerg Sonnenberger 
705af51229aSJoerg Sonnenberger 		/* Restore PCI config data. */
706af51229aSJoerg Sonnenberger 		pci_write_config(dev, RE_PCI_LOMEM, membase, 4);
707af51229aSJoerg Sonnenberger 		pci_write_config(dev, PCIR_INTLINE, irq, 4);
708af51229aSJoerg Sonnenberger 	}
709af51229aSJoerg Sonnenberger #endif
710af51229aSJoerg Sonnenberger 	/*
711af51229aSJoerg Sonnenberger 	 * Map control/status registers.
712af51229aSJoerg Sonnenberger 	 */
713af51229aSJoerg Sonnenberger 	pci_enable_busmaster(dev);
714af51229aSJoerg Sonnenberger 
715d511b4cfSSepherosa Ziehau 	if (pci_is_pcie(dev)) {
716d511b4cfSSepherosa Ziehau 		sc->re_res_rid = PCIR_BAR(2);
717d511b4cfSSepherosa Ziehau 		sc->re_res_type = SYS_RES_MEMORY;
718d511b4cfSSepherosa Ziehau 	} else {
719d511b4cfSSepherosa Ziehau 		sc->re_res_rid = PCIR_BAR(0);
720d511b4cfSSepherosa Ziehau 		sc->re_res_type = SYS_RES_IOPORT;
721d511b4cfSSepherosa Ziehau 	}
722d511b4cfSSepherosa Ziehau 	sc->re_res = bus_alloc_resource_any(dev, sc->re_res_type,
723d511b4cfSSepherosa Ziehau 	    &sc->re_res_rid, RF_ACTIVE);
724af51229aSJoerg Sonnenberger 	if (sc->re_res == NULL) {
725d511b4cfSSepherosa Ziehau 		device_printf(dev, "couldn't map IO\n");
726af51229aSJoerg Sonnenberger 		error = ENXIO;
727af51229aSJoerg Sonnenberger 		goto fail;
728af51229aSJoerg Sonnenberger 	}
729af51229aSJoerg Sonnenberger 
730af51229aSJoerg Sonnenberger 	sc->re_btag = rman_get_bustag(sc->re_res);
731af51229aSJoerg Sonnenberger 	sc->re_bhandle = rman_get_bushandle(sc->re_res);
732af51229aSJoerg Sonnenberger 
733e5a5a436SSepherosa Ziehau 	error = rtl_check_mac_version(sc);
734e5a5a436SSepherosa Ziehau 	if (error) {
735e5a5a436SSepherosa Ziehau 		device_printf(dev, "check mac version failed\n");
736e5a5a436SSepherosa Ziehau 		goto fail;
737e5a5a436SSepherosa Ziehau 	}
738e5a5a436SSepherosa Ziehau 
739e5a5a436SSepherosa Ziehau 	rtl_init_software_variable(sc);
740e5a5a436SSepherosa Ziehau 	if (pci_is_pcie(dev))
741e5a5a436SSepherosa Ziehau 		sc->re_if_flags |= RL_FLAG_PCIE;
742e5a5a436SSepherosa Ziehau 	else
743e5a5a436SSepherosa Ziehau 		sc->re_if_flags &= ~RL_FLAG_PCIE;
74452bafeb8SSepherosa Ziehau 	device_printf(dev, "MAC version 0x%08x, MACFG %u%s%s%s\n",
745e5a5a436SSepherosa Ziehau 	    (CSR_READ_4(sc, RE_TXCFG) & 0xFCF00000), sc->re_type,
746e5a5a436SSepherosa Ziehau 	    sc->re_coalesce_tx_pkt ? ", software TX defrag" : "",
74752bafeb8SSepherosa Ziehau 	    sc->re_pad_runt ? ", pad runt" : "",
748e5a5a436SSepherosa Ziehau 	    sc->re_hw_enable_msi_msix ? ", support MSI" : "");
749e5a5a436SSepherosa Ziehau 
75004724643SSepherosa Ziehau 	/*
75104724643SSepherosa Ziehau 	 * Allocate interrupt
75204724643SSepherosa Ziehau 	 */
753e5a5a436SSepherosa Ziehau 	if (pci_is_pcie(dev) && sc->re_hw_enable_msi_msix)
75404724643SSepherosa Ziehau 		msi_enable = re_msi_enable;
75504724643SSepherosa Ziehau 	else
75604724643SSepherosa Ziehau 		msi_enable = 0;
75704724643SSepherosa Ziehau 	sc->re_irq_type = pci_alloc_1intr(dev, msi_enable,
7584dce912aSTim Bisson 	    &sc->re_irq_rid, &irq_flags);
759af51229aSJoerg Sonnenberger 
7604dce912aSTim Bisson 	sc->re_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->re_irq_rid,
7614dce912aSTim Bisson 					    irq_flags);
762af51229aSJoerg Sonnenberger 	if (sc->re_irq == NULL) {
763af51229aSJoerg Sonnenberger 		device_printf(dev, "couldn't map interrupt\n");
764af51229aSJoerg Sonnenberger 		error = ENXIO;
765af51229aSJoerg Sonnenberger 		goto fail;
766af51229aSJoerg Sonnenberger 	}
767af51229aSJoerg Sonnenberger 
768d7c373a4SSepherosa Ziehau 	/* Disable ASPM */
769d7c373a4SSepherosa Ziehau 	re_disable_aspm(dev);
770d7c373a4SSepherosa Ziehau 
771e5a5a436SSepherosa Ziehau 	rtl_exit_oob(sc);
772e5a5a436SSepherosa Ziehau 	rtl_hw_init(sc);
773af51229aSJoerg Sonnenberger 
774e5a5a436SSepherosa Ziehau 	/* Reset the adapter. */
775e5a5a436SSepherosa Ziehau 	rtl_reset(sc);
776e5a5a436SSepherosa Ziehau 
777e5a5a436SSepherosa Ziehau 	rtl_get_hw_mac_address(sc, eaddr);
778e5a5a436SSepherosa Ziehau 	if (sc->re_type == MACFG_3)	/* Change PCI Latency time*/
779e5a5a436SSepherosa Ziehau 		pci_write_config(dev, PCIR_LATTIMER, 0x40, 1);
780e5a5a436SSepherosa Ziehau 
781e5a5a436SSepherosa Ziehau 	/* Allocate DMA stuffs */
782e5a5a436SSepherosa Ziehau 	error = re_allocmem(dev);
783e5a5a436SSepherosa Ziehau 	if (error)
784e5a5a436SSepherosa Ziehau 		goto fail;
785e5a5a436SSepherosa Ziehau 
786e5a5a436SSepherosa Ziehau 	if (pci_is_pcie(dev)) {
787957a8760SSepherosa Ziehau 		sc->re_bus_speed = 125;
788957a8760SSepherosa Ziehau 	} else {
789957a8760SSepherosa Ziehau 		uint8_t cfg2;
790957a8760SSepherosa Ziehau 
791957a8760SSepherosa Ziehau 		cfg2 = CSR_READ_1(sc, RE_CFG2);
792957a8760SSepherosa Ziehau 		switch (cfg2 & RE_CFG2_PCICLK_MASK) {
793957a8760SSepherosa Ziehau 		case RE_CFG2_PCICLK_33MHZ:
794957a8760SSepherosa Ziehau 			sc->re_bus_speed = 33;
795957a8760SSepherosa Ziehau 			break;
796957a8760SSepherosa Ziehau 		case RE_CFG2_PCICLK_66MHZ:
797957a8760SSepherosa Ziehau 			sc->re_bus_speed = 66;
798957a8760SSepherosa Ziehau 			break;
799957a8760SSepherosa Ziehau 		default:
800957a8760SSepherosa Ziehau 			device_printf(dev, "unknown bus speed, assume 33MHz\n");
801957a8760SSepherosa Ziehau 			sc->re_bus_speed = 33;
802957a8760SSepherosa Ziehau 			break;
803957a8760SSepherosa Ziehau 		}
804957a8760SSepherosa Ziehau 	}
805e5a5a436SSepherosa Ziehau 	device_printf(dev, "bus speed %dMHz\n", sc->re_bus_speed);
806af51229aSJoerg Sonnenberger 
807e5a5a436SSepherosa Ziehau 	/* Enable hardware checksum if available. */
808e5a5a436SSepherosa Ziehau 	sc->re_tx_cstag = 1;
809e5a5a436SSepherosa Ziehau 	sc->re_rx_cstag = 1;
810af51229aSJoerg Sonnenberger 
811af51229aSJoerg Sonnenberger 	ifp = &sc->arpcom.ac_if;
812af51229aSJoerg Sonnenberger 	ifp->if_softc = sc;
813af51229aSJoerg Sonnenberger 	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
814af51229aSJoerg Sonnenberger 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
815af51229aSJoerg Sonnenberger 	ifp->if_ioctl = re_ioctl;
816af51229aSJoerg Sonnenberger 	ifp->if_start = re_start;
8177816ba83SSepherosa Ziehau #ifdef IFPOLL_ENABLE
8187816ba83SSepherosa Ziehau 	ifp->if_npoll = re_npoll;
819af51229aSJoerg Sonnenberger #endif
820af51229aSJoerg Sonnenberger 	ifp->if_watchdog = re_watchdog;
821af51229aSJoerg Sonnenberger 	ifp->if_init = re_init;
8221e1c5facSSepherosa Ziehau 	if (re_is_faste(sc))
8231e1c5facSSepherosa Ziehau 		ifp->if_baudrate = IF_Mbps(100ULL);
8241e1c5facSSepherosa Ziehau 	else if (re_is_2500e(sc))
8251e1c5facSSepherosa Ziehau 		ifp->if_baudrate = IF_Mbps(2500ULL);
826af51229aSJoerg Sonnenberger 	else
8271e1c5facSSepherosa Ziehau 		ifp->if_baudrate = IF_Mbps(1000ULL);
82814929979SSepherosa Ziehau 	ifp->if_nmbclusters = sc->re_rx_desc_cnt;
82979280061SSepherosa Ziehau 	ifq_set_maxlen(&ifp->if_snd, qlen);
830000181b2SJoerg Sonnenberger 	ifq_set_ready(&ifp->if_snd);
831610fc460SSepherosa Ziehau 
832e5a5a436SSepherosa Ziehau 	ifp->if_capabilities = IFCAP_VLAN_MTU | IFCAP_VLAN_HWTAGGING |
833e5a5a436SSepherosa Ziehau 	    IFCAP_RXCSUM | IFCAP_TXCSUM;
834af51229aSJoerg Sonnenberger 	ifp->if_capenable = ifp->if_capabilities;
835e5a5a436SSepherosa Ziehau 	/* NOTE: if_hwassist will be setup after the interface is up. */
836af51229aSJoerg Sonnenberger 
837af51229aSJoerg Sonnenberger 	/*
838af51229aSJoerg Sonnenberger 	 * Call MI attach routine.
839af51229aSJoerg Sonnenberger 	 */
84078195a76SMatthew Dillon 	ether_ifattach(ifp, eaddr, NULL);
841af51229aSJoerg Sonnenberger 
8424c77af2dSSepherosa Ziehau 	ifq_set_cpuid(&ifp->if_snd, rman_get_cpuid(sc->re_irq));
8434c77af2dSSepherosa Ziehau 
84480492964SSepherosa Ziehau 	rtl_phy_power_up(sc);
84580492964SSepherosa Ziehau 	rtl_hw_phy_config(sc);
84680492964SSepherosa Ziehau 	rtl_clrwol(sc);
84780492964SSepherosa Ziehau 
84880492964SSepherosa Ziehau 	/* TODO: jumbo frame */
84980492964SSepherosa Ziehau 	CSR_WRITE_2(sc, RE_RxMaxSize, sc->re_rxbuf_size);
85080492964SSepherosa Ziehau 
8517816ba83SSepherosa Ziehau #ifdef IFPOLL_ENABLE
85226595b18SSascha Wildner 	ifpoll_compat_setup(&sc->re_npoll, ctx, (struct sysctl_oid *)tree,
85326595b18SSascha Wildner 	    device_get_unit(dev), ifp->if_serializer);
8547816ba83SSepherosa Ziehau #endif
8557816ba83SSepherosa Ziehau 
856af51229aSJoerg Sonnenberger 	/* Hook interrupt last to avoid having to lock softc */
857e5a5a436SSepherosa Ziehau 	error = bus_setup_intr(dev, sc->re_irq, INTR_MPSAFE | INTR_HIFREQ,
858e5a5a436SSepherosa Ziehau 	    re_intr, sc, &sc->re_intrhand, ifp->if_serializer);
859af51229aSJoerg Sonnenberger 	if (error) {
860af51229aSJoerg Sonnenberger 		device_printf(dev, "couldn't set up irq\n");
861af51229aSJoerg Sonnenberger 		ether_ifdetach(ifp);
862af51229aSJoerg Sonnenberger 		goto fail;
863af51229aSJoerg Sonnenberger 	}
864af51229aSJoerg Sonnenberger 
865e5a5a436SSepherosa Ziehau 	ifmedia_add(&sc->media, IFM_ETHER | IFM_10_T, 0, NULL);
866e5a5a436SSepherosa Ziehau 	ifmedia_add(&sc->media, IFM_ETHER | IFM_10_T | IFM_FDX, 0, NULL);
867e5a5a436SSepherosa Ziehau 	ifmedia_add(&sc->media, IFM_ETHER | IFM_100_TX, 0, NULL);
868e5a5a436SSepherosa Ziehau 	ifmedia_add(&sc->media, IFM_ETHER | IFM_100_TX | IFM_FDX, 0, NULL);
869e5a5a436SSepherosa Ziehau 	if (!re_is_faste(sc)) {
870e5a5a436SSepherosa Ziehau 		ifmedia_add(&sc->media, IFM_ETHER | IFM_1000_T | IFM_FDX,
871e5a5a436SSepherosa Ziehau 		    0, NULL);
872e5a5a436SSepherosa Ziehau 	}
87380492964SSepherosa Ziehau 	if (re_is_2500e(sc)) {
87480492964SSepherosa Ziehau #ifndef IFM_2500_T
87580492964SSepherosa Ziehau 		ifmedia_add(&sc->media, IFM_ETHER | IFM_2500_SX | IFM_FDX,
87680492964SSepherosa Ziehau 		    0, NULL);
87780492964SSepherosa Ziehau #else
87880492964SSepherosa Ziehau 		ifmedia_add(&sc->media, IFM_ETHER | IFM_2500_T | IFM_FDX,
87980492964SSepherosa Ziehau 		    0, NULL);
88080492964SSepherosa Ziehau #endif
88180492964SSepherosa Ziehau 	}
882e5a5a436SSepherosa Ziehau 	ifmedia_add(&sc->media, IFM_ETHER | IFM_AUTO, 0, NULL);
883e5a5a436SSepherosa Ziehau 	ifmedia_set(&sc->media, IFM_ETHER | IFM_AUTO);
884e5a5a436SSepherosa Ziehau 	rtl_ifmedia_upd(ifp);
885e5a5a436SSepherosa Ziehau 
886af51229aSJoerg Sonnenberger fail:
887af51229aSJoerg Sonnenberger 	if (error)
888af51229aSJoerg Sonnenberger 		re_detach(dev);
889af51229aSJoerg Sonnenberger 
890af51229aSJoerg Sonnenberger 	return (error);
891af51229aSJoerg Sonnenberger }
892af51229aSJoerg Sonnenberger 
893af51229aSJoerg Sonnenberger /*
894af51229aSJoerg Sonnenberger  * Shutdown hardware and free up resources. This can be called any
895af51229aSJoerg Sonnenberger  * time after the mutex has been initialized. It is called in both
896af51229aSJoerg Sonnenberger  * the error case in attach and the normal detach case so it needs
897af51229aSJoerg Sonnenberger  * to be careful about only freeing resources that have actually been
898af51229aSJoerg Sonnenberger  * allocated.
899af51229aSJoerg Sonnenberger  */
900af51229aSJoerg Sonnenberger static int
re_detach(device_t dev)901af51229aSJoerg Sonnenberger re_detach(device_t dev)
902af51229aSJoerg Sonnenberger {
903af51229aSJoerg Sonnenberger 	struct re_softc *sc = device_get_softc(dev);
904af51229aSJoerg Sonnenberger 	struct ifnet *ifp = &sc->arpcom.ac_if;
905af51229aSJoerg Sonnenberger 
906af51229aSJoerg Sonnenberger 	/* These should only be active if attach succeeded */
907af51229aSJoerg Sonnenberger 	if (device_is_attached(dev)) {
908cdf89432SSepherosa Ziehau 		lwkt_serialize_enter(ifp->if_serializer);
909e5a5a436SSepherosa Ziehau 		re_stop(sc, TRUE);
910cdf89432SSepherosa Ziehau 		bus_teardown_intr(dev, sc->re_irq, sc->re_intrhand);
911cdf89432SSepherosa Ziehau 		lwkt_serialize_exit(ifp->if_serializer);
912cdf89432SSepherosa Ziehau 
913af51229aSJoerg Sonnenberger 		ether_ifdetach(ifp);
914af51229aSJoerg Sonnenberger 	}
915e5a5a436SSepherosa Ziehau 	ifmedia_removeall(&sc->media);
916af51229aSJoerg Sonnenberger 
917af51229aSJoerg Sonnenberger 	if (sc->re_irq)
9184dce912aSTim Bisson 		bus_release_resource(dev, SYS_RES_IRQ, sc->re_irq_rid,
9194dce912aSTim Bisson 				     sc->re_irq);
9204dce912aSTim Bisson 
9214dce912aSTim Bisson 	if (sc->re_irq_type == PCI_INTR_TYPE_MSI)
9224dce912aSTim Bisson 		pci_release_msi(dev);
9234dce912aSTim Bisson 
924cdf89432SSepherosa Ziehau 	if (sc->re_res) {
925d511b4cfSSepherosa Ziehau 		bus_release_resource(dev, sc->re_res_type, sc->re_res_rid,
926af51229aSJoerg Sonnenberger 		    sc->re_res);
927cdf89432SSepherosa Ziehau 	}
928e6e07291SSepherosa Ziehau 	rtl_cmac_unmap(sc);
929af51229aSJoerg Sonnenberger 
9308d9cb301SSepherosa Ziehau 	/* Free DMA stuffs */
9318d9cb301SSepherosa Ziehau 	re_freemem(dev);
932af51229aSJoerg Sonnenberger 
933af51229aSJoerg Sonnenberger 	return(0);
934af51229aSJoerg Sonnenberger }
935af51229aSJoerg Sonnenberger 
9363580fc56SSepherosa Ziehau static void
re_setup_rxdesc(struct re_softc * sc,int idx)9373580fc56SSepherosa Ziehau re_setup_rxdesc(struct re_softc *sc, int idx)
9383580fc56SSepherosa Ziehau {
9393580fc56SSepherosa Ziehau 	bus_addr_t paddr;
9403580fc56SSepherosa Ziehau 	uint32_t cmdstat;
9413580fc56SSepherosa Ziehau 	struct re_desc *d;
9423580fc56SSepherosa Ziehau 
9433580fc56SSepherosa Ziehau 	paddr = sc->re_ldata.re_rx_paddr[idx];
9443580fc56SSepherosa Ziehau 	d = &sc->re_ldata.re_rx_list[idx];
9453580fc56SSepherosa Ziehau 
9463580fc56SSepherosa Ziehau 	d->re_bufaddr_lo = htole32(RE_ADDR_LO(paddr));
9473580fc56SSepherosa Ziehau 	d->re_bufaddr_hi = htole32(RE_ADDR_HI(paddr));
9483580fc56SSepherosa Ziehau 
949a7d57e62SSepherosa Ziehau 	cmdstat = sc->re_rxbuf_size | RE_RDESC_CMD_OWN;
95053d4588aSSepherosa Ziehau 	if (idx == (sc->re_rx_desc_cnt - 1))
951a7d57e62SSepherosa Ziehau 		cmdstat |= RE_RDESC_CMD_EOR;
9523580fc56SSepherosa Ziehau 	d->re_cmdstat = htole32(cmdstat);
9533580fc56SSepherosa Ziehau }
9543580fc56SSepherosa Ziehau 
955af51229aSJoerg Sonnenberger static int
re_newbuf_std(struct re_softc * sc,int idx,int init)956a7d57e62SSepherosa Ziehau re_newbuf_std(struct re_softc *sc, int idx, int init)
957af51229aSJoerg Sonnenberger {
9583580fc56SSepherosa Ziehau 	bus_dma_segment_t seg;
9593580fc56SSepherosa Ziehau 	bus_dmamap_t map;
9603580fc56SSepherosa Ziehau 	struct mbuf *m;
961782514b9SSepherosa Ziehau 	int error, nsegs;
962af51229aSJoerg Sonnenberger 
963b5523eacSSascha Wildner 	m = m_getcl(init ? M_WAITOK : M_NOWAIT, MT_DATA, M_PKTHDR);
964af51229aSJoerg Sonnenberger 	if (m == NULL) {
9653580fc56SSepherosa Ziehau 		error = ENOBUFS;
966af51229aSJoerg Sonnenberger 
9673580fc56SSepherosa Ziehau 		if (init) {
9683580fc56SSepherosa Ziehau 			if_printf(&sc->arpcom.ac_if, "m_getcl failed\n");
9693580fc56SSepherosa Ziehau 			return error;
9703580fc56SSepherosa Ziehau 		} else {
9713580fc56SSepherosa Ziehau 			goto back;
9723580fc56SSepherosa Ziehau 		}
9733580fc56SSepherosa Ziehau 	}
974af51229aSJoerg Sonnenberger 	m->m_len = m->m_pkthdr.len = MCLBYTES;
9757caafb85SSepherosa Ziehau 
9767caafb85SSepherosa Ziehau 	/*
9777caafb85SSepherosa Ziehau 	 * NOTE:
9788aaa1e58SSepherosa Ziehau 	 * re(4) chips need address of the receive buffer to be 8-byte
9798aaa1e58SSepherosa Ziehau 	 * aligned, so don't call m_adj(m, ETHER_ALIGN) here.
9807caafb85SSepherosa Ziehau 	 */
981af51229aSJoerg Sonnenberger 
982782514b9SSepherosa Ziehau 	error = bus_dmamap_load_mbuf_segment(sc->re_ldata.re_rx_mtag,
9833580fc56SSepherosa Ziehau 			sc->re_ldata.re_rx_spare, m,
984782514b9SSepherosa Ziehau 			&seg, 1, &nsegs, BUS_DMA_NOWAIT);
985782514b9SSepherosa Ziehau 	if (error) {
9863580fc56SSepherosa Ziehau 		m_freem(m);
9873580fc56SSepherosa Ziehau 		if (init) {
9883580fc56SSepherosa Ziehau 			if_printf(&sc->arpcom.ac_if, "can't load RX mbuf\n");
9893580fc56SSepherosa Ziehau 			return error;
9903580fc56SSepherosa Ziehau 		} else {
9913580fc56SSepherosa Ziehau 			goto back;
9923580fc56SSepherosa Ziehau 		}
993af51229aSJoerg Sonnenberger 	}
994af51229aSJoerg Sonnenberger 
9953580fc56SSepherosa Ziehau 	if (!init) {
9968aaa1e58SSepherosa Ziehau 		bus_dmamap_sync(sc->re_ldata.re_rx_mtag,
9973580fc56SSepherosa Ziehau 				sc->re_ldata.re_rx_dmamap[idx],
9983580fc56SSepherosa Ziehau 				BUS_DMASYNC_POSTREAD);
9998aaa1e58SSepherosa Ziehau 		bus_dmamap_unload(sc->re_ldata.re_rx_mtag,
10003580fc56SSepherosa Ziehau 				  sc->re_ldata.re_rx_dmamap[idx]);
10013580fc56SSepherosa Ziehau 	}
1002af51229aSJoerg Sonnenberger 	sc->re_ldata.re_rx_mbuf[idx] = m;
10033580fc56SSepherosa Ziehau 	sc->re_ldata.re_rx_paddr[idx] = seg.ds_addr;
1004af51229aSJoerg Sonnenberger 
10053580fc56SSepherosa Ziehau 	map = sc->re_ldata.re_rx_dmamap[idx];
10063580fc56SSepherosa Ziehau 	sc->re_ldata.re_rx_dmamap[idx] = sc->re_ldata.re_rx_spare;
10073580fc56SSepherosa Ziehau 	sc->re_ldata.re_rx_spare = map;
10083580fc56SSepherosa Ziehau back:
10093580fc56SSepherosa Ziehau 	re_setup_rxdesc(sc, idx);
10103580fc56SSepherosa Ziehau 	return error;
1011af51229aSJoerg Sonnenberger }
1012af51229aSJoerg Sonnenberger 
1013e5a5a436SSepherosa Ziehau #ifdef RE_JUMBO
1014af51229aSJoerg Sonnenberger static int
re_newbuf_jumbo(struct re_softc * sc,int idx,int init)1015a7d57e62SSepherosa Ziehau re_newbuf_jumbo(struct re_softc *sc, int idx, int init)
1016a7d57e62SSepherosa Ziehau {
1017a7d57e62SSepherosa Ziehau 	struct mbuf *m;
1018a7d57e62SSepherosa Ziehau 	struct re_jbuf *jbuf;
1019a7d57e62SSepherosa Ziehau 	int error = 0;
1020a7d57e62SSepherosa Ziehau 
1021b5523eacSSascha Wildner 	MGETHDR(m, init ? M_WAITOK : M_NOWAIT, MT_DATA);
1022a7d57e62SSepherosa Ziehau 	if (m == NULL) {
1023a7d57e62SSepherosa Ziehau 		error = ENOBUFS;
1024a7d57e62SSepherosa Ziehau 		if (init) {
1025a7d57e62SSepherosa Ziehau 			if_printf(&sc->arpcom.ac_if, "MGETHDR failed\n");
1026a7d57e62SSepherosa Ziehau 			return error;
1027a7d57e62SSepherosa Ziehau 		} else {
1028a7d57e62SSepherosa Ziehau 			goto back;
1029a7d57e62SSepherosa Ziehau 		}
1030a7d57e62SSepherosa Ziehau 	}
1031a7d57e62SSepherosa Ziehau 
1032a7d57e62SSepherosa Ziehau 	jbuf = re_jbuf_alloc(sc);
1033a7d57e62SSepherosa Ziehau 	if (jbuf == NULL) {
1034a7d57e62SSepherosa Ziehau 		m_freem(m);
1035a7d57e62SSepherosa Ziehau 
1036a7d57e62SSepherosa Ziehau 		error = ENOBUFS;
1037a7d57e62SSepherosa Ziehau 		if (init) {
1038a7d57e62SSepherosa Ziehau 			if_printf(&sc->arpcom.ac_if, "jpool is empty\n");
1039a7d57e62SSepherosa Ziehau 			return error;
1040a7d57e62SSepherosa Ziehau 		} else {
1041a7d57e62SSepherosa Ziehau 			goto back;
1042a7d57e62SSepherosa Ziehau 		}
1043a7d57e62SSepherosa Ziehau 	}
1044a7d57e62SSepherosa Ziehau 
1045a7d57e62SSepherosa Ziehau 	m->m_ext.ext_arg = jbuf;
1046a7d57e62SSepherosa Ziehau 	m->m_ext.ext_buf = jbuf->re_buf;
1047a7d57e62SSepherosa Ziehau 	m->m_ext.ext_free = re_jbuf_free;
1048a7d57e62SSepherosa Ziehau 	m->m_ext.ext_ref = re_jbuf_ref;
1049a7d57e62SSepherosa Ziehau 	m->m_ext.ext_size = sc->re_rxbuf_size;
1050a7d57e62SSepherosa Ziehau 
1051a7d57e62SSepherosa Ziehau 	m->m_data = m->m_ext.ext_buf;
1052a7d57e62SSepherosa Ziehau 	m->m_flags |= M_EXT;
1053a7d57e62SSepherosa Ziehau 	m->m_len = m->m_pkthdr.len = m->m_ext.ext_size;
1054a7d57e62SSepherosa Ziehau 
1055a7d57e62SSepherosa Ziehau 	/*
1056a7d57e62SSepherosa Ziehau 	 * NOTE:
1057a7d57e62SSepherosa Ziehau 	 * Some re(4) chips(e.g. RTL8101E) need address of the receive buffer
1058a7d57e62SSepherosa Ziehau 	 * to be 8-byte aligned, so don't call m_adj(m, ETHER_ALIGN) here.
1059a7d57e62SSepherosa Ziehau 	 */
1060a7d57e62SSepherosa Ziehau 
1061a7d57e62SSepherosa Ziehau 	sc->re_ldata.re_rx_mbuf[idx] = m;
1062a7d57e62SSepherosa Ziehau 	sc->re_ldata.re_rx_paddr[idx] = jbuf->re_paddr;
1063a7d57e62SSepherosa Ziehau back:
1064a7d57e62SSepherosa Ziehau 	re_setup_rxdesc(sc, idx);
1065a7d57e62SSepherosa Ziehau 	return error;
1066a7d57e62SSepherosa Ziehau }
1067e5a5a436SSepherosa Ziehau #endif	/* RE_JUMBO */
1068a7d57e62SSepherosa Ziehau 
1069a7d57e62SSepherosa Ziehau static int
re_tx_list_init(struct re_softc * sc)1070af51229aSJoerg Sonnenberger re_tx_list_init(struct re_softc *sc)
1071af51229aSJoerg Sonnenberger {
107253d4588aSSepherosa Ziehau 	bzero(sc->re_ldata.re_tx_list, RE_TX_LIST_SZ(sc));
1073af51229aSJoerg Sonnenberger 
1074af51229aSJoerg Sonnenberger 	sc->re_ldata.re_tx_prodidx = 0;
1075af51229aSJoerg Sonnenberger 	sc->re_ldata.re_tx_considx = 0;
107653d4588aSSepherosa Ziehau 	sc->re_ldata.re_tx_free = sc->re_tx_desc_cnt;
1077af51229aSJoerg Sonnenberger 
1078af51229aSJoerg Sonnenberger 	return(0);
1079af51229aSJoerg Sonnenberger }
1080af51229aSJoerg Sonnenberger 
1081af51229aSJoerg Sonnenberger static int
re_rx_list_init(struct re_softc * sc)1082af51229aSJoerg Sonnenberger re_rx_list_init(struct re_softc *sc)
1083af51229aSJoerg Sonnenberger {
1084af51229aSJoerg Sonnenberger 	int i, error;
1085af51229aSJoerg Sonnenberger 
108653d4588aSSepherosa Ziehau 	bzero(sc->re_ldata.re_rx_list, RE_RX_LIST_SZ(sc));
1087af51229aSJoerg Sonnenberger 
108853d4588aSSepherosa Ziehau 	for (i = 0; i < sc->re_rx_desc_cnt; i++) {
1089a7d57e62SSepherosa Ziehau 		error = sc->re_newbuf(sc, i, 1);
1090af51229aSJoerg Sonnenberger 		if (error)
1091af51229aSJoerg Sonnenberger 			return(error);
1092af51229aSJoerg Sonnenberger 	}
1093af51229aSJoerg Sonnenberger 
1094af51229aSJoerg Sonnenberger 	sc->re_ldata.re_rx_prodidx = 0;
1095af51229aSJoerg Sonnenberger 	sc->re_head = sc->re_tail = NULL;
1096af51229aSJoerg Sonnenberger 
1097af51229aSJoerg Sonnenberger 	return(0);
1098af51229aSJoerg Sonnenberger }
1099af51229aSJoerg Sonnenberger 
1100afdeb9daSSepherosa Ziehau #define RE_IP4_PACKET	0x1
1101afdeb9daSSepherosa Ziehau #define RE_TCP_PACKET	0x2
1102afdeb9daSSepherosa Ziehau #define RE_UDP_PACKET	0x4
1103afdeb9daSSepherosa Ziehau 
1104afdeb9daSSepherosa Ziehau static __inline uint8_t
re_packet_type(struct re_softc * sc,uint32_t rxstat,uint32_t rxctrl)1105afdeb9daSSepherosa Ziehau re_packet_type(struct re_softc *sc, uint32_t rxstat, uint32_t rxctrl)
1106afdeb9daSSepherosa Ziehau {
1107afdeb9daSSepherosa Ziehau 	uint8_t packet_type = 0;
1108afdeb9daSSepherosa Ziehau 
1109e5a5a436SSepherosa Ziehau 	if (sc->re_if_flags & RL_FLAG_DESCV2) {
1110afdeb9daSSepherosa Ziehau 		if (rxctrl & RE_RDESC_CTL_PROTOIP4)
1111afdeb9daSSepherosa Ziehau 			packet_type |= RE_IP4_PACKET;
1112afdeb9daSSepherosa Ziehau 	} else {
1113afdeb9daSSepherosa Ziehau 		if (rxstat & RE_RDESC_STAT_PROTOID)
1114afdeb9daSSepherosa Ziehau 			packet_type |= RE_IP4_PACKET;
1115afdeb9daSSepherosa Ziehau 	}
1116afdeb9daSSepherosa Ziehau 	if (RE_TCPPKT(rxstat))
1117afdeb9daSSepherosa Ziehau 		packet_type |= RE_TCP_PACKET;
1118afdeb9daSSepherosa Ziehau 	else if (RE_UDPPKT(rxstat))
1119afdeb9daSSepherosa Ziehau 		packet_type |= RE_UDP_PACKET;
1120afdeb9daSSepherosa Ziehau 	return packet_type;
1121afdeb9daSSepherosa Ziehau }
1122afdeb9daSSepherosa Ziehau 
1123af51229aSJoerg Sonnenberger /*
1124af51229aSJoerg Sonnenberger  * RX handler for C+ and 8169. For the gigE chips, we support
1125af51229aSJoerg Sonnenberger  * the reception of jumbo frames that have been fragmented
1126af51229aSJoerg Sonnenberger  * across multiple 2K mbuf cluster buffers.
1127af51229aSJoerg Sonnenberger  */
1128d4d77345SSepherosa Ziehau static int
re_rxeof(struct re_softc * sc)1129af51229aSJoerg Sonnenberger re_rxeof(struct re_softc *sc)
1130af51229aSJoerg Sonnenberger {
1131af51229aSJoerg Sonnenberger 	struct ifnet *ifp = &sc->arpcom.ac_if;
1132af51229aSJoerg Sonnenberger 	struct mbuf *m;
1133af51229aSJoerg Sonnenberger 	struct re_desc 	*cur_rx;
1134afdeb9daSSepherosa Ziehau 	uint32_t rxstat, rxctrl;
1135d4d77345SSepherosa Ziehau 	int i, total_len, rx = 0;
11367a53a239SSepherosa Ziehau 
1137af51229aSJoerg Sonnenberger 	for (i = sc->re_ldata.re_rx_prodidx;
113853d4588aSSepherosa Ziehau 	     RE_OWN(&sc->re_ldata.re_rx_list[i]) == 0; RE_RXDESC_INC(sc, i)) {
1139af51229aSJoerg Sonnenberger 		cur_rx = &sc->re_ldata.re_rx_list[i];
1140af51229aSJoerg Sonnenberger 		m = sc->re_ldata.re_rx_mbuf[i];
1141af51229aSJoerg Sonnenberger 		total_len = RE_RXBYTES(cur_rx);
1142af51229aSJoerg Sonnenberger 		rxstat = le32toh(cur_rx->re_cmdstat);
1143afdeb9daSSepherosa Ziehau 		rxctrl = le32toh(cur_rx->re_control);
1144af51229aSJoerg Sonnenberger 
1145d4d77345SSepherosa Ziehau 		rx = 1;
1146d4d77345SSepherosa Ziehau 
1147a7d57e62SSepherosa Ziehau #ifdef INVARIANTS
1148a7d57e62SSepherosa Ziehau 		if (sc->re_flags & RE_F_USE_JPOOL)
1149a7d57e62SSepherosa Ziehau 			KKASSERT(rxstat & RE_RDESC_STAT_EOF);
1150a7d57e62SSepherosa Ziehau #endif
1151a7d57e62SSepherosa Ziehau 
1152af51229aSJoerg Sonnenberger 		if ((rxstat & RE_RDESC_STAT_EOF) == 0) {
1153e887515bSSepherosa Ziehau 			if (sc->re_flags & RE_F_DROP_RXFRAG) {
11546070c764SSepherosa Ziehau 				re_setup_rxdesc(sc, i);
11553580fc56SSepherosa Ziehau 				continue;
11563580fc56SSepherosa Ziehau 			}
11573580fc56SSepherosa Ziehau 
1158a7d57e62SSepherosa Ziehau 			if (sc->re_newbuf(sc, i, 0)) {
11596070c764SSepherosa Ziehau 				/* Drop upcoming fragments */
1160e887515bSSepherosa Ziehau 				sc->re_flags |= RE_F_DROP_RXFRAG;
11616070c764SSepherosa Ziehau 				continue;
11626070c764SSepherosa Ziehau 			}
11636070c764SSepherosa Ziehau 
11646070c764SSepherosa Ziehau 			m->m_len = MCLBYTES;
1165af51229aSJoerg Sonnenberger 			if (sc->re_head == NULL) {
1166af51229aSJoerg Sonnenberger 				sc->re_head = sc->re_tail = m;
1167af51229aSJoerg Sonnenberger 			} else {
1168af51229aSJoerg Sonnenberger 				sc->re_tail->m_next = m;
1169af51229aSJoerg Sonnenberger 				sc->re_tail = m;
1170af51229aSJoerg Sonnenberger 			}
1171af51229aSJoerg Sonnenberger 			continue;
1172e887515bSSepherosa Ziehau 		} else if (sc->re_flags & RE_F_DROP_RXFRAG) {
11736070c764SSepherosa Ziehau 			/*
11746070c764SSepherosa Ziehau 			 * Last fragment of a multi-fragment packet.
11756070c764SSepherosa Ziehau 			 *
11766070c764SSepherosa Ziehau 			 * Since error already happened, this fragment
11776070c764SSepherosa Ziehau 			 * must be dropped as well as the fragment chain.
11786070c764SSepherosa Ziehau 			 */
11796070c764SSepherosa Ziehau 			re_setup_rxdesc(sc, i);
11806070c764SSepherosa Ziehau 			re_free_rxchain(sc);
1181e887515bSSepherosa Ziehau 			sc->re_flags &= ~RE_F_DROP_RXFRAG;
11826070c764SSepherosa Ziehau 			continue;
1183af51229aSJoerg Sonnenberger 		}
1184af51229aSJoerg Sonnenberger 
1185af51229aSJoerg Sonnenberger 		rxstat >>= 1;
1186af51229aSJoerg Sonnenberger 		if (rxstat & RE_RDESC_STAT_RXERRSUM) {
1187d40991efSSepherosa Ziehau 			IFNET_STAT_INC(ifp, ierrors, 1);
1188af51229aSJoerg Sonnenberger 			/*
1189af51229aSJoerg Sonnenberger 			 * If this is part of a multi-fragment packet,
1190af51229aSJoerg Sonnenberger 			 * discard all the pieces.
1191af51229aSJoerg Sonnenberger 			 */
11922499e0afSSepherosa Ziehau 			re_free_rxchain(sc);
11933580fc56SSepherosa Ziehau 			re_setup_rxdesc(sc, i);
1194af51229aSJoerg Sonnenberger 			continue;
1195af51229aSJoerg Sonnenberger 		}
1196af51229aSJoerg Sonnenberger 
1197af51229aSJoerg Sonnenberger 		/*
1198af51229aSJoerg Sonnenberger 		 * If allocating a replacement mbuf fails,
1199af51229aSJoerg Sonnenberger 		 * reload the current one.
1200af51229aSJoerg Sonnenberger 		 */
1201af51229aSJoerg Sonnenberger 
1202a7d57e62SSepherosa Ziehau 		if (sc->re_newbuf(sc, i, 0)) {
1203d40991efSSepherosa Ziehau 			IFNET_STAT_INC(ifp, ierrors, 1);
1204af51229aSJoerg Sonnenberger 			continue;
1205af51229aSJoerg Sonnenberger 		}
1206af51229aSJoerg Sonnenberger 
1207af51229aSJoerg Sonnenberger 		if (sc->re_head != NULL) {
12086070c764SSepherosa Ziehau 			m->m_len = total_len % MCLBYTES;
1209af51229aSJoerg Sonnenberger 			/*
1210af51229aSJoerg Sonnenberger 			 * Special case: if there's 4 bytes or less
1211af51229aSJoerg Sonnenberger 			 * in this buffer, the mbuf can be discarded:
1212af51229aSJoerg Sonnenberger 			 * the last 4 bytes is the CRC, which we don't
1213af51229aSJoerg Sonnenberger 			 * care about anyway.
1214af51229aSJoerg Sonnenberger 			 */
1215af51229aSJoerg Sonnenberger 			if (m->m_len <= ETHER_CRC_LEN) {
1216af51229aSJoerg Sonnenberger 				sc->re_tail->m_len -=
1217af51229aSJoerg Sonnenberger 				    (ETHER_CRC_LEN - m->m_len);
1218af51229aSJoerg Sonnenberger 				m_freem(m);
1219af51229aSJoerg Sonnenberger 			} else {
1220af51229aSJoerg Sonnenberger 				m->m_len -= ETHER_CRC_LEN;
1221af51229aSJoerg Sonnenberger 				sc->re_tail->m_next = m;
1222af51229aSJoerg Sonnenberger 			}
1223af51229aSJoerg Sonnenberger 			m = sc->re_head;
1224af51229aSJoerg Sonnenberger 			sc->re_head = sc->re_tail = NULL;
1225af51229aSJoerg Sonnenberger 			m->m_pkthdr.len = total_len - ETHER_CRC_LEN;
12263580fc56SSepherosa Ziehau 		} else {
1227af51229aSJoerg Sonnenberger 			m->m_pkthdr.len = m->m_len =
1228af51229aSJoerg Sonnenberger 			    (total_len - ETHER_CRC_LEN);
12293580fc56SSepherosa Ziehau 		}
1230af51229aSJoerg Sonnenberger 
1231d40991efSSepherosa Ziehau 		IFNET_STAT_INC(ifp, ipackets, 1);
1232af51229aSJoerg Sonnenberger 		m->m_pkthdr.rcvif = ifp;
1233af51229aSJoerg Sonnenberger 
1234af51229aSJoerg Sonnenberger 		/* Do RX checksumming if enabled */
1235af51229aSJoerg Sonnenberger 
1236af51229aSJoerg Sonnenberger 		if (ifp->if_capenable & IFCAP_RXCSUM) {
1237afdeb9daSSepherosa Ziehau 			uint8_t packet_type;
1238afdeb9daSSepherosa Ziehau 
1239afdeb9daSSepherosa Ziehau 			packet_type = re_packet_type(sc, rxstat, rxctrl);
1240afdeb9daSSepherosa Ziehau 
1241af51229aSJoerg Sonnenberger 			/* Check IP header checksum */
1242afdeb9daSSepherosa Ziehau 			if (packet_type & RE_IP4_PACKET) {
1243af51229aSJoerg Sonnenberger 				m->m_pkthdr.csum_flags |= CSUM_IP_CHECKED;
1244af51229aSJoerg Sonnenberger 				if ((rxstat & RE_RDESC_STAT_IPSUMBAD) == 0)
1245af51229aSJoerg Sonnenberger 					m->m_pkthdr.csum_flags |= CSUM_IP_VALID;
1246afdeb9daSSepherosa Ziehau 			}
1247af51229aSJoerg Sonnenberger 
1248af51229aSJoerg Sonnenberger 			/* Check TCP/UDP checksum */
1249afdeb9daSSepherosa Ziehau 			if (((packet_type & RE_TCP_PACKET) &&
1250af51229aSJoerg Sonnenberger 			     (rxstat & RE_RDESC_STAT_TCPSUMBAD) == 0) ||
1251afdeb9daSSepherosa Ziehau 			    ((packet_type & RE_UDP_PACKET) &&
1252afdeb9daSSepherosa Ziehau 			     (rxstat & RE_RDESC_STAT_UDPSUMBAD) == 0)) {
1253af51229aSJoerg Sonnenberger 				m->m_pkthdr.csum_flags |=
1254fbb35ef0SSepherosa Ziehau 				    CSUM_DATA_VALID|CSUM_PSEUDO_HDR|
1255fbb35ef0SSepherosa Ziehau 				    CSUM_FRAG_NOT_CHECKED;
1256af51229aSJoerg Sonnenberger 				m->m_pkthdr.csum_data = 0xffff;
1257af51229aSJoerg Sonnenberger 			}
1258af51229aSJoerg Sonnenberger 		}
1259af51229aSJoerg Sonnenberger 
1260afdeb9daSSepherosa Ziehau 		if (rxctrl & RE_RDESC_CTL_HASTAG) {
1261e6b5847cSSepherosa Ziehau 			m->m_flags |= M_VLANTAG;
1262e6b5847cSSepherosa Ziehau 			m->m_pkthdr.ether_vlantag =
1263afdeb9daSSepherosa Ziehau 				be16toh((rxctrl & RE_RDESC_CTL_TAGDATA));
126478195a76SMatthew Dillon 		}
126573029d08SFranco Fichtner 		ifp->if_input(ifp, m, NULL, -1);
1266af51229aSJoerg Sonnenberger 	}
1267af51229aSJoerg Sonnenberger 
1268af51229aSJoerg Sonnenberger 	sc->re_ldata.re_rx_prodidx = i;
1269d4d77345SSepherosa Ziehau 
1270d4d77345SSepherosa Ziehau 	return rx;
1271af51229aSJoerg Sonnenberger }
1272af51229aSJoerg Sonnenberger 
1273afdeb9daSSepherosa Ziehau #undef RE_IP4_PACKET
1274afdeb9daSSepherosa Ziehau #undef RE_TCP_PACKET
1275afdeb9daSSepherosa Ziehau #undef RE_UDP_PACKET
1276afdeb9daSSepherosa Ziehau 
1277d4d77345SSepherosa Ziehau static int
re_tx_collect(struct re_softc * sc)1278d3d3122dSSepherosa Ziehau re_tx_collect(struct re_softc *sc)
1279af51229aSJoerg Sonnenberger {
1280af51229aSJoerg Sonnenberger 	struct ifnet *ifp = &sc->arpcom.ac_if;
1281af51229aSJoerg Sonnenberger 	uint32_t txstat;
1282d4d77345SSepherosa Ziehau 	int idx, tx = 0;
1283af51229aSJoerg Sonnenberger 
1284af51229aSJoerg Sonnenberger 	for (idx = sc->re_ldata.re_tx_considx;
128553d4588aSSepherosa Ziehau 	     sc->re_ldata.re_tx_free < sc->re_tx_desc_cnt;
128653d4588aSSepherosa Ziehau 	     RE_TXDESC_INC(sc, idx)) {
1287af51229aSJoerg Sonnenberger 		txstat = le32toh(sc->re_ldata.re_tx_list[idx].re_cmdstat);
1288af51229aSJoerg Sonnenberger 		if (txstat & RE_TDESC_CMD_OWN)
1289af51229aSJoerg Sonnenberger 			break;
1290af51229aSJoerg Sonnenberger 
1291d4d77345SSepherosa Ziehau 		tx = 1;
1292d4d77345SSepherosa Ziehau 
12935d686fbbSSepherosa Ziehau 		sc->re_ldata.re_tx_list[idx].re_bufaddr_lo = 0;
12945d686fbbSSepherosa Ziehau 
1295af51229aSJoerg Sonnenberger 		/*
1296af51229aSJoerg Sonnenberger 		 * We only stash mbufs in the last descriptor
1297af51229aSJoerg Sonnenberger 		 * in a fragment chain, which also happens to
1298af51229aSJoerg Sonnenberger 		 * be the only place where the TX status bits
1299af51229aSJoerg Sonnenberger 		 * are valid.
130080492964SSepherosa Ziehau 		 *
130180492964SSepherosa Ziehau 		 * NOTE:
130280492964SSepherosa Ziehau 		 * On 8125, RE_TDESC_CMD_EOF is no longer left
130380492964SSepherosa Ziehau 		 * uncleared.
1304af51229aSJoerg Sonnenberger 		 */
130580492964SSepherosa Ziehau 		if (sc->re_ldata.re_tx_mbuf[idx] != NULL) {
13068aaa1e58SSepherosa Ziehau 			bus_dmamap_unload(sc->re_ldata.re_tx_mtag,
13078aaa1e58SSepherosa Ziehau 			    sc->re_ldata.re_tx_dmamap[idx]);
1308af51229aSJoerg Sonnenberger 			m_freem(sc->re_ldata.re_tx_mbuf[idx]);
1309af51229aSJoerg Sonnenberger 			sc->re_ldata.re_tx_mbuf[idx] = NULL;
1310af51229aSJoerg Sonnenberger 			if (txstat & (RE_TDESC_STAT_EXCESSCOL|
1311af51229aSJoerg Sonnenberger 			    RE_TDESC_STAT_COLCNT))
1312d40991efSSepherosa Ziehau 				IFNET_STAT_INC(ifp, collisions, 1);
1313af51229aSJoerg Sonnenberger 			if (txstat & RE_TDESC_STAT_TXERRSUM)
1314d40991efSSepherosa Ziehau 				IFNET_STAT_INC(ifp, oerrors, 1);
1315af51229aSJoerg Sonnenberger 			else
1316d40991efSSepherosa Ziehau 				IFNET_STAT_INC(ifp, opackets, 1);
1317af51229aSJoerg Sonnenberger 		}
1318af51229aSJoerg Sonnenberger 		sc->re_ldata.re_tx_free++;
1319af51229aSJoerg Sonnenberger 	}
1320af51229aSJoerg Sonnenberger 	sc->re_ldata.re_tx_considx = idx;
132164c24521SSepherosa Ziehau 
1322d3d3122dSSepherosa Ziehau 	return tx;
1323d3d3122dSSepherosa Ziehau }
1324d3d3122dSSepherosa Ziehau 
1325d3d3122dSSepherosa Ziehau static int
re_txeof(struct re_softc * sc)1326d3d3122dSSepherosa Ziehau re_txeof(struct re_softc *sc)
1327d3d3122dSSepherosa Ziehau {
1328d3d3122dSSepherosa Ziehau 	struct ifnet *ifp = &sc->arpcom.ac_if;
1329d3d3122dSSepherosa Ziehau 	int tx;
1330d3d3122dSSepherosa Ziehau 
1331d3d3122dSSepherosa Ziehau 	tx = re_tx_collect(sc);
1332d3d3122dSSepherosa Ziehau 
133364c24521SSepherosa Ziehau 	/* There is enough free TX descs */
133464c24521SSepherosa Ziehau 	if (sc->re_ldata.re_tx_free > RE_TXDESC_SPARE)
13359ed293e0SSepherosa Ziehau 		ifq_clr_oactive(&ifp->if_snd);
1336af51229aSJoerg Sonnenberger 
1337af51229aSJoerg Sonnenberger 	/*
13385d686fbbSSepherosa Ziehau 	 * Some chips will ignore a second TX request issued while an
13395d686fbbSSepherosa Ziehau 	 * existing transmission is in progress. If the transmitter goes
13405d686fbbSSepherosa Ziehau 	 * idle but there are still packets waiting to be sent, we need
13415d686fbbSSepherosa Ziehau 	 * to restart the channel here to flush them out. This only seems
13425d686fbbSSepherosa Ziehau 	 * to be required with the PCIe devices.
13435d686fbbSSepherosa Ziehau 	 */
134453d4588aSSepherosa Ziehau 	if (sc->re_ldata.re_tx_free < sc->re_tx_desc_cnt)
134580492964SSepherosa Ziehau 		sc->re_start_xmit(sc);
134664c24521SSepherosa Ziehau 	else
134764c24521SSepherosa Ziehau 		ifp->if_timer = 0;
13485d686fbbSSepherosa Ziehau 
1349d4d77345SSepherosa Ziehau 	return tx;
1350af51229aSJoerg Sonnenberger }
1351af51229aSJoerg Sonnenberger 
1352af51229aSJoerg Sonnenberger static void
re_tick(void * xsc)1353af51229aSJoerg Sonnenberger re_tick(void *xsc)
1354af51229aSJoerg Sonnenberger {
1355af51229aSJoerg Sonnenberger 	struct re_softc *sc = xsc;
1356af51229aSJoerg Sonnenberger 
135778195a76SMatthew Dillon 	lwkt_serialize_enter(sc->arpcom.ac_if.if_serializer);
135878195a76SMatthew Dillon 	re_tick_serialized(xsc);
135978195a76SMatthew Dillon 	lwkt_serialize_exit(sc->arpcom.ac_if.if_serializer);
136078195a76SMatthew Dillon }
136178195a76SMatthew Dillon 
136278195a76SMatthew Dillon static void
re_tick_serialized(void * xsc)136378195a76SMatthew Dillon re_tick_serialized(void *xsc)
136478195a76SMatthew Dillon {
136578195a76SMatthew Dillon 	struct re_softc *sc = xsc;
13665d686fbbSSepherosa Ziehau 	struct ifnet *ifp = &sc->arpcom.ac_if;
1367af51229aSJoerg Sonnenberger 
13686fbd7e67SSepherosa Ziehau 	ASSERT_SERIALIZED(ifp->if_serializer);
13696fbd7e67SSepherosa Ziehau 
1370e5a5a436SSepherosa Ziehau 	if ((ifp->if_flags & IFF_RUNNING) == 0)
1371e5a5a436SSepherosa Ziehau 		return;
1372af51229aSJoerg Sonnenberger 
1373e5a5a436SSepherosa Ziehau 	if (rtl_link_ok(sc)) {
1374e5a5a436SSepherosa Ziehau 		if ((sc->re_flags & RE_F_LINKED) == 0)
1375e5a5a436SSepherosa Ziehau 			re_link_up(sc);
1376e5a5a436SSepherosa Ziehau 	} else if (sc->re_flags & RE_F_LINKED) {
1377e5a5a436SSepherosa Ziehau 		re_link_down(sc);
1378e5a5a436SSepherosa Ziehau 	}
1379af51229aSJoerg Sonnenberger 	callout_reset(&sc->re_timer, hz, re_tick, sc);
1380af51229aSJoerg Sonnenberger }
1381af51229aSJoerg Sonnenberger 
13827816ba83SSepherosa Ziehau #ifdef IFPOLL_ENABLE
13839c095379SMatthew Dillon 
1384af51229aSJoerg Sonnenberger static void
re_npoll_compat(struct ifnet * ifp,void * arg __unused,int count)13857816ba83SSepherosa Ziehau re_npoll_compat(struct ifnet *ifp, void *arg __unused, int count)
1386af51229aSJoerg Sonnenberger {
1387af51229aSJoerg Sonnenberger 	struct re_softc *sc = ifp->if_softc;
1388af51229aSJoerg Sonnenberger 
13896fbd7e67SSepherosa Ziehau 	ASSERT_SERIALIZED(ifp->if_serializer);
13906fbd7e67SSepherosa Ziehau 
13917816ba83SSepherosa Ziehau 	if (sc->re_npoll.ifpc_stcount-- == 0) {
139280492964SSepherosa Ziehau 		uint32_t status;
1393af51229aSJoerg Sonnenberger 
13947816ba83SSepherosa Ziehau 		sc->re_npoll.ifpc_stcount = sc->re_npoll.ifpc_stfrac;
13957816ba83SSepherosa Ziehau 
139680492964SSepherosa Ziehau 		status = sc->re_read_isr(sc);
1397af51229aSJoerg Sonnenberger 		if (status)
139880492964SSepherosa Ziehau 			sc->re_write_isr(sc, status);
1399af51229aSJoerg Sonnenberger 
1400af51229aSJoerg Sonnenberger 		/*
1401af51229aSJoerg Sonnenberger 		 * XXX check behaviour on receiver stalls.
1402af51229aSJoerg Sonnenberger 		 */
1403af51229aSJoerg Sonnenberger 
1404e5a5a436SSepherosa Ziehau 		if (status & RE_ISR_SYSTEM_ERR) {
1405e5a5a436SSepherosa Ziehau 			rtl_reset(sc);
1406af51229aSJoerg Sonnenberger 			re_init(sc);
1407e5a5a436SSepherosa Ziehau 			/* Done! */
1408e5a5a436SSepherosa Ziehau 			return;
1409e5a5a436SSepherosa Ziehau 		}
1410af51229aSJoerg Sonnenberger 	}
14117816ba83SSepherosa Ziehau 
14127816ba83SSepherosa Ziehau 	sc->rxcycles = count;
14137816ba83SSepherosa Ziehau 	re_rxeof(sc);
14147816ba83SSepherosa Ziehau 	re_txeof(sc);
14157816ba83SSepherosa Ziehau 
14167816ba83SSepherosa Ziehau 	if (!ifq_is_empty(&ifp->if_snd))
14177816ba83SSepherosa Ziehau 		if_devstart(ifp);
14187816ba83SSepherosa Ziehau }
14197816ba83SSepherosa Ziehau 
14207816ba83SSepherosa Ziehau static void
re_npoll(struct ifnet * ifp,struct ifpoll_info * info)14217816ba83SSepherosa Ziehau re_npoll(struct ifnet *ifp, struct ifpoll_info *info)
14227816ba83SSepherosa Ziehau {
14237816ba83SSepherosa Ziehau 	struct re_softc *sc = ifp->if_softc;
14247816ba83SSepherosa Ziehau 
14257816ba83SSepherosa Ziehau 	ASSERT_SERIALIZED(ifp->if_serializer);
14267816ba83SSepherosa Ziehau 
14277816ba83SSepherosa Ziehau 	if (info != NULL) {
14287816ba83SSepherosa Ziehau 		int cpuid = sc->re_npoll.ifpc_cpuid;
14297816ba83SSepherosa Ziehau 
14307816ba83SSepherosa Ziehau 		info->ifpi_rx[cpuid].poll_func = re_npoll_compat;
14317816ba83SSepherosa Ziehau 		info->ifpi_rx[cpuid].arg = NULL;
14327816ba83SSepherosa Ziehau 		info->ifpi_rx[cpuid].serializer = ifp->if_serializer;
14337816ba83SSepherosa Ziehau 
14347816ba83SSepherosa Ziehau 		if (ifp->if_flags & IFF_RUNNING)
14357816ba83SSepherosa Ziehau 			re_setup_intr(sc, 0, RE_IMTYPE_NONE);
1436dfd3b18bSSepherosa Ziehau 		ifq_set_cpuid(&ifp->if_snd, cpuid);
14377816ba83SSepherosa Ziehau 	} else {
14387816ba83SSepherosa Ziehau 		if (ifp->if_flags & IFF_RUNNING)
14397816ba83SSepherosa Ziehau 			re_setup_intr(sc, 1, sc->re_imtype);
1440dfd3b18bSSepherosa Ziehau 		ifq_set_cpuid(&ifp->if_snd, rman_get_cpuid(sc->re_irq));
14419c095379SMatthew Dillon 	}
1442af51229aSJoerg Sonnenberger }
14437816ba83SSepherosa Ziehau #endif /* IFPOLL_ENABLE */
1444af51229aSJoerg Sonnenberger 
1445af51229aSJoerg Sonnenberger static void
re_intr(void * arg)1446af51229aSJoerg Sonnenberger re_intr(void *arg)
1447af51229aSJoerg Sonnenberger {
1448af51229aSJoerg Sonnenberger 	struct re_softc	*sc = arg;
1449af51229aSJoerg Sonnenberger 	struct ifnet *ifp = &sc->arpcom.ac_if;
145080492964SSepherosa Ziehau 	uint32_t status;
1451e5a5a436SSepherosa Ziehau 	int proc;
1452af51229aSJoerg Sonnenberger 
14536fbd7e67SSepherosa Ziehau 	ASSERT_SERIALIZED(ifp->if_serializer);
14546fbd7e67SSepherosa Ziehau 
1455e887515bSSepherosa Ziehau 	if ((sc->re_flags & RE_F_SUSPENDED) ||
1456e887515bSSepherosa Ziehau 	    (ifp->if_flags & IFF_RUNNING) == 0)
1457af51229aSJoerg Sonnenberger 		return;
1458af51229aSJoerg Sonnenberger 
1459e5a5a436SSepherosa Ziehau 	/* Disable interrupts. */
146080492964SSepherosa Ziehau 	sc->re_write_imr(sc, 0);
14612d3d2dd3SSepherosa Ziehau 
146280492964SSepherosa Ziehau 	status = sc->re_read_isr(sc);
1463e5a5a436SSepherosa Ziehau again:
1464e5a5a436SSepherosa Ziehau 	proc = 0;
1465af51229aSJoerg Sonnenberger 	if (status)
146680492964SSepherosa Ziehau 		sc->re_write_isr(sc, status);
1467e5a5a436SSepherosa Ziehau 	if (status & sc->re_intrs) {
1468e5a5a436SSepherosa Ziehau 		if (status & RE_ISR_SYSTEM_ERR) {
1469e5a5a436SSepherosa Ziehau 			rtl_reset(sc);
1470af51229aSJoerg Sonnenberger 			re_init(sc);
1471e5a5a436SSepherosa Ziehau 			/* Done! */
1472e5a5a436SSepherosa Ziehau 			return;
1473e5a5a436SSepherosa Ziehau 		}
1474e5a5a436SSepherosa Ziehau 		proc |= re_rxeof(sc);
1475e5a5a436SSepherosa Ziehau 		proc |= re_txeof(sc);
1476af51229aSJoerg Sonnenberger 	}
1477af51229aSJoerg Sonnenberger 
1478d4d77345SSepherosa Ziehau 	if (sc->re_imtype == RE_IMTYPE_SIM) {
1479d4d77345SSepherosa Ziehau 		if ((sc->re_flags & RE_F_TIMER_INTR)) {
1480e5a5a436SSepherosa Ziehau 			if (!proc) {
148164ebeab7SSepherosa Ziehau 				/*
148264ebeab7SSepherosa Ziehau 				 * Nothing needs to be processed, fallback
148364ebeab7SSepherosa Ziehau 				 * to use TX/RX interrupts.
1484e5a5a436SSepherosa Ziehau 				 *
1485e5a5a436SSepherosa Ziehau 				 * NOTE: This will re-enable interrupts.
148664ebeab7SSepherosa Ziehau 				 */
1487d4d77345SSepherosa Ziehau 				re_setup_intr(sc, 1, RE_IMTYPE_NONE);
148864ebeab7SSepherosa Ziehau 
148964ebeab7SSepherosa Ziehau 				/*
149064ebeab7SSepherosa Ziehau 				 * Recollect, mainly to avoid the possible
149164ebeab7SSepherosa Ziehau 				 * race introduced by changing interrupt
149264ebeab7SSepherosa Ziehau 				 * masks.
149364ebeab7SSepherosa Ziehau 				 */
149464ebeab7SSepherosa Ziehau 				re_rxeof(sc);
1495e5a5a436SSepherosa Ziehau 				re_txeof(sc);
149664ebeab7SSepherosa Ziehau 			} else {
1497e5a5a436SSepherosa Ziehau 				/* Re-enable interrupts. */
149880492964SSepherosa Ziehau 				sc->re_write_imr(sc, sc->re_intrs);
1499d4d77345SSepherosa Ziehau 				CSR_WRITE_4(sc, RE_TIMERCNT, 1); /* reload */
150064ebeab7SSepherosa Ziehau 			}
1501e5a5a436SSepherosa Ziehau 		} else if (proc) {
150264ebeab7SSepherosa Ziehau 			/*
150364ebeab7SSepherosa Ziehau 			 * Assume that using simulated interrupt moderation
150464ebeab7SSepherosa Ziehau 			 * (hardware timer based) could reduce the interript
150564ebeab7SSepherosa Ziehau 			 * rate.
1506e5a5a436SSepherosa Ziehau 			 *
1507e5a5a436SSepherosa Ziehau 			 * NOTE: This will re-enable interrupts.
150864ebeab7SSepherosa Ziehau 			 */
1509d4d77345SSepherosa Ziehau 			re_setup_intr(sc, 1, RE_IMTYPE_SIM);
1510e5a5a436SSepherosa Ziehau 		} else {
1511e5a5a436SSepherosa Ziehau 			/* Re-enable interrupts. */
151280492964SSepherosa Ziehau 			sc->re_write_imr(sc, sc->re_intrs);
1513d4d77345SSepherosa Ziehau 		}
1514e5a5a436SSepherosa Ziehau 	} else {
151580492964SSepherosa Ziehau 		status = sc->re_read_isr(sc);
1516e5a5a436SSepherosa Ziehau 		if (status & sc->re_intrs) {
1517e5a5a436SSepherosa Ziehau 			if (!ifq_is_empty(&ifp->if_snd))
1518e5a5a436SSepherosa Ziehau 				if_devstart(ifp);
1519e5a5a436SSepherosa Ziehau 			/* NOTE: Interrupts are still disabled. */
1520e5a5a436SSepherosa Ziehau 			goto again;
1521e5a5a436SSepherosa Ziehau 		}
1522e5a5a436SSepherosa Ziehau 		/* Re-enable interrupts. */
152380492964SSepherosa Ziehau 		sc->re_write_imr(sc, sc->re_intrs);
1524d4d77345SSepherosa Ziehau 	}
1525d4d77345SSepherosa Ziehau 
1526e5a5a436SSepherosa Ziehau 	if (!ifq_is_empty(&ifp->if_snd))
15279db4b353SSepherosa Ziehau 		if_devstart(ifp);
1528af51229aSJoerg Sonnenberger }
1529af51229aSJoerg Sonnenberger 
1530af51229aSJoerg Sonnenberger static int
re_encap(struct re_softc * sc,struct mbuf ** m_head,int * idx0)15313580fc56SSepherosa Ziehau re_encap(struct re_softc *sc, struct mbuf **m_head, int *idx0)
1532af51229aSJoerg Sonnenberger {
1533782514b9SSepherosa Ziehau 	struct mbuf *m = *m_head;
15343580fc56SSepherosa Ziehau 	bus_dma_segment_t segs[RE_MAXSEGS];
1535af51229aSJoerg Sonnenberger 	bus_dmamap_t map;
1536782514b9SSepherosa Ziehau 	int error, maxsegs, idx, i, nsegs;
15373580fc56SSepherosa Ziehau 	struct re_desc *d, *tx_ring;
15381dea81b1SSepherosa Ziehau 	uint32_t cmd_csum, ctl_csum, vlantag;
1539af51229aSJoerg Sonnenberger 
154064c24521SSepherosa Ziehau 	KASSERT(sc->re_ldata.re_tx_free > RE_TXDESC_SPARE,
1541ed20d0e3SSascha Wildner 		("not enough free TX desc"));
1542af51229aSJoerg Sonnenberger 
1543e5a5a436SSepherosa Ziehau 	if (sc->re_coalesce_tx_pkt && m->m_pkthdr.len != m->m_len) {
1544e5a5a436SSepherosa Ziehau 		struct mbuf *m_new;
1545e5a5a436SSepherosa Ziehau 
1546e5a5a436SSepherosa Ziehau 		m_new = m_defrag(m, M_NOWAIT);
1547e5a5a436SSepherosa Ziehau 		if (m_new == NULL) {
1548e5a5a436SSepherosa Ziehau 			error = ENOBUFS;
1549e5a5a436SSepherosa Ziehau 			goto back;
1550e5a5a436SSepherosa Ziehau 		} else {
1551e5a5a436SSepherosa Ziehau 			*m_head = m = m_new;
1552e5a5a436SSepherosa Ziehau 			if (m->m_pkthdr.len != m->m_len) {
1553e5a5a436SSepherosa Ziehau 				/* Still not configuous; give up. */
1554e5a5a436SSepherosa Ziehau 				error = ENOBUFS;
1555e5a5a436SSepherosa Ziehau 				goto back;
1556e5a5a436SSepherosa Ziehau 			}
1557e5a5a436SSepherosa Ziehau 		}
1558e5a5a436SSepherosa Ziehau 	}
1559e5a5a436SSepherosa Ziehau 
15603580fc56SSepherosa Ziehau 	map = sc->re_ldata.re_tx_dmamap[*idx0];
15618f77d350SJoerg Sonnenberger 
1562af51229aSJoerg Sonnenberger 	/*
1563af51229aSJoerg Sonnenberger 	 * Set up checksum offload. Note: checksum offload bits must
1564af51229aSJoerg Sonnenberger 	 * appear in all descriptors of a multi-descriptor transmit
1565af51229aSJoerg Sonnenberger 	 * attempt. (This is according to testing done with an 8169
1566af51229aSJoerg Sonnenberger 	 * chip. I'm not sure if this is a requirement or a bug.)
1567af51229aSJoerg Sonnenberger 	 */
1568afdeb9daSSepherosa Ziehau 	cmd_csum = ctl_csum = 0;
1569afdeb9daSSepherosa Ziehau 	if (m->m_pkthdr.csum_flags & CSUM_IP) {
1570afdeb9daSSepherosa Ziehau 		cmd_csum |= RE_TDESC_CMD_IPCSUM;
1571afdeb9daSSepherosa Ziehau 		ctl_csum |= RE_TDESC_CTL_IPCSUM;
1572afdeb9daSSepherosa Ziehau 	}
1573afdeb9daSSepherosa Ziehau 	if (m->m_pkthdr.csum_flags & CSUM_TCP) {
1574afdeb9daSSepherosa Ziehau 		cmd_csum |= RE_TDESC_CMD_TCPCSUM;
1575afdeb9daSSepherosa Ziehau 		ctl_csum |= RE_TDESC_CTL_TCPCSUM;
1576afdeb9daSSepherosa Ziehau 	}
1577afdeb9daSSepherosa Ziehau 	if (m->m_pkthdr.csum_flags & CSUM_UDP) {
1578afdeb9daSSepherosa Ziehau 		cmd_csum |= RE_TDESC_CMD_UDPCSUM;
1579afdeb9daSSepherosa Ziehau 		ctl_csum |= RE_TDESC_CTL_UDPCSUM;
1580afdeb9daSSepherosa Ziehau 	}
1581afdeb9daSSepherosa Ziehau 
1582e5a5a436SSepherosa Ziehau 	/* For version2 descriptor, csum flags are set on re_control */
1583e5a5a436SSepherosa Ziehau 	if (sc->re_if_flags & RL_FLAG_DESCV2)
1584afdeb9daSSepherosa Ziehau 		cmd_csum = 0;
1585afdeb9daSSepherosa Ziehau 	else
1586afdeb9daSSepherosa Ziehau 		ctl_csum = 0;
15875d686fbbSSepherosa Ziehau 
158852bafeb8SSepherosa Ziehau 	if (sc->re_pad_runt) {
15895d686fbbSSepherosa Ziehau 		/*
15905d686fbbSSepherosa Ziehau 		 * With some of the RealTek chips, using the checksum offload
15915d686fbbSSepherosa Ziehau 		 * support in conjunction with the autopadding feature results
15925d686fbbSSepherosa Ziehau 		 * in the transmission of corrupt frames. For example, if we
15935d686fbbSSepherosa Ziehau 		 * need to send a really small IP fragment that's less than 60
15945d686fbbSSepherosa Ziehau 		 * bytes in size, and IP header checksumming is enabled, the
15955d686fbbSSepherosa Ziehau 		 * resulting ethernet frame that appears on the wire will
15965d686fbbSSepherosa Ziehau 		 * have garbled payload. To work around this, if TX checksum
15975d686fbbSSepherosa Ziehau 		 * offload is enabled, we always manually pad short frames out
1598afdeb9daSSepherosa Ziehau 		 * to the minimum ethernet frame size.
15994df76d5dSSepherosa Ziehau 		 *
16004df76d5dSSepherosa Ziehau 		 * Note: this appears unnecessary for TCP, and doing it for TCP
16014df76d5dSSepherosa Ziehau 		 * with PCIe adapters seems to result in bad checksums.
16025d686fbbSSepherosa Ziehau 		 */
1603a57bab71SSepherosa Ziehau 		if ((m->m_pkthdr.csum_flags &
1604a57bab71SSepherosa Ziehau 		     (CSUM_DELAY_IP | CSUM_DELAY_DATA)) &&
1605afdeb9daSSepherosa Ziehau 		    (m->m_pkthdr.csum_flags & CSUM_TCP) == 0 &&
16064df76d5dSSepherosa Ziehau 		    m->m_pkthdr.len < RE_MIN_FRAMELEN) {
1607cf12ba3cSSepherosa Ziehau 			error = m_devpad(m, RE_MIN_FRAMELEN);
16083580fc56SSepherosa Ziehau 			if (error)
16093580fc56SSepherosa Ziehau 				goto back;
16105d686fbbSSepherosa Ziehau 		}
1611a57bab71SSepherosa Ziehau 	}
1612af51229aSJoerg Sonnenberger 
16131dea81b1SSepherosa Ziehau 	vlantag = 0;
16141dea81b1SSepherosa Ziehau 	if (m->m_flags & M_VLANTAG) {
16151dea81b1SSepherosa Ziehau 		vlantag = htobe16(m->m_pkthdr.ether_vlantag) |
16161dea81b1SSepherosa Ziehau 			  RE_TDESC_CTL_INSTAG;
16171dea81b1SSepherosa Ziehau 	}
16181dea81b1SSepherosa Ziehau 
16196070c764SSepherosa Ziehau 	maxsegs = sc->re_ldata.re_tx_free;
16203580fc56SSepherosa Ziehau 	if (maxsegs > RE_MAXSEGS)
16213580fc56SSepherosa Ziehau 		maxsegs = RE_MAXSEGS;
16223580fc56SSepherosa Ziehau 
1623782514b9SSepherosa Ziehau 	error = bus_dmamap_load_mbuf_defrag(sc->re_ldata.re_tx_mtag, map,
1624782514b9SSepherosa Ziehau 			m_head, segs, maxsegs, &nsegs, BUS_DMA_NOWAIT);
1625782514b9SSepherosa Ziehau 	if (error)
16263580fc56SSepherosa Ziehau 		goto back;
1627af51229aSJoerg Sonnenberger 
1628782514b9SSepherosa Ziehau 	m = *m_head;
16298aaa1e58SSepherosa Ziehau 	bus_dmamap_sync(sc->re_ldata.re_tx_mtag, map, BUS_DMASYNC_PREWRITE);
1630af51229aSJoerg Sonnenberger 
1631af51229aSJoerg Sonnenberger 	/*
16323580fc56SSepherosa Ziehau 	 * Map the segment array into descriptors.  We also keep track
16333580fc56SSepherosa Ziehau 	 * of the end of the ring and set the end-of-ring bits as needed,
16343580fc56SSepherosa Ziehau 	 * and we set the ownership bits in all except the very first
16353580fc56SSepherosa Ziehau 	 * descriptor, whose ownership bits will be turned on later.
1636af51229aSJoerg Sonnenberger 	 */
16373580fc56SSepherosa Ziehau 	tx_ring = sc->re_ldata.re_tx_list;
16383580fc56SSepherosa Ziehau 	idx = *idx0;
16393580fc56SSepherosa Ziehau 	i = 0;
16403580fc56SSepherosa Ziehau 	for (;;) {
16413580fc56SSepherosa Ziehau 		uint32_t cmdstat;
1642af51229aSJoerg Sonnenberger 
16433580fc56SSepherosa Ziehau 		d = &tx_ring[idx];
16443580fc56SSepherosa Ziehau 
164580492964SSepherosa Ziehau 		KKASSERT(sc->re_ldata.re_tx_mbuf[idx] == NULL);
164680492964SSepherosa Ziehau 
16473580fc56SSepherosa Ziehau 		d->re_bufaddr_lo = htole32(RE_ADDR_LO(segs[i].ds_addr));
16483580fc56SSepherosa Ziehau 		d->re_bufaddr_hi = htole32(RE_ADDR_HI(segs[i].ds_addr));
164980492964SSepherosa Ziehau 
165080492964SSepherosa Ziehau 		cmdstat = segs[i].ds_len;
165180492964SSepherosa Ziehau 		if (i == 0) {
16523580fc56SSepherosa Ziehau 			cmdstat |= RE_TDESC_CMD_SOF;
165380492964SSepherosa Ziehau 		} else if (i != nsegs - 1) {
165480492964SSepherosa Ziehau 			/*
165580492964SSepherosa Ziehau 			 * Last descriptor's ownership will be transfered
165680492964SSepherosa Ziehau 			 * later.
165780492964SSepherosa Ziehau 			 */
16583580fc56SSepherosa Ziehau 			cmdstat |= RE_TDESC_CMD_OWN;
165980492964SSepherosa Ziehau 		}
166053d4588aSSepherosa Ziehau 		if (idx == (sc->re_tx_desc_cnt - 1))
16613580fc56SSepherosa Ziehau 			cmdstat |= RE_TDESC_CMD_EOR;
166280492964SSepherosa Ziehau 
16631dea81b1SSepherosa Ziehau 		d->re_control = htole32(ctl_csum | vlantag);
166480492964SSepherosa Ziehau 		d->re_cmdstat = htole32(cmdstat | cmd_csum);
16653580fc56SSepherosa Ziehau 
16663580fc56SSepherosa Ziehau 		i++;
1667782514b9SSepherosa Ziehau 		if (i == nsegs)
16683580fc56SSepherosa Ziehau 			break;
166953d4588aSSepherosa Ziehau 		RE_TXDESC_INC(sc, idx);
16703580fc56SSepherosa Ziehau 	}
16713580fc56SSepherosa Ziehau 	d->re_cmdstat |= htole32(RE_TDESC_CMD_EOF);
1672af51229aSJoerg Sonnenberger 
1673af51229aSJoerg Sonnenberger 	/* Transfer ownership of packet to the chip. */
16743580fc56SSepherosa Ziehau 	d->re_cmdstat |= htole32(RE_TDESC_CMD_OWN);
16753580fc56SSepherosa Ziehau 	if (*idx0 != idx)
16763580fc56SSepherosa Ziehau 		tx_ring[*idx0].re_cmdstat |= htole32(RE_TDESC_CMD_OWN);
1677af51229aSJoerg Sonnenberger 
16783580fc56SSepherosa Ziehau 	/*
16793580fc56SSepherosa Ziehau 	 * Insure that the map for this transmission
16803580fc56SSepherosa Ziehau 	 * is placed at the array index of the last descriptor
16813580fc56SSepherosa Ziehau 	 * in this chain.
16823580fc56SSepherosa Ziehau 	 */
16833580fc56SSepherosa Ziehau 	sc->re_ldata.re_tx_dmamap[*idx0] = sc->re_ldata.re_tx_dmamap[idx];
16843580fc56SSepherosa Ziehau 	sc->re_ldata.re_tx_dmamap[idx] = map;
1685af51229aSJoerg Sonnenberger 
16863580fc56SSepherosa Ziehau 	sc->re_ldata.re_tx_mbuf[idx] = m;
1687782514b9SSepherosa Ziehau 	sc->re_ldata.re_tx_free -= nsegs;
1688af51229aSJoerg Sonnenberger 
168953d4588aSSepherosa Ziehau 	RE_TXDESC_INC(sc, idx);
16903580fc56SSepherosa Ziehau 	*idx0 = idx;
16913580fc56SSepherosa Ziehau back:
16923580fc56SSepherosa Ziehau 	if (error) {
1693782514b9SSepherosa Ziehau 		m_freem(*m_head);
16943580fc56SSepherosa Ziehau 		*m_head = NULL;
16953580fc56SSepherosa Ziehau 	}
16963580fc56SSepherosa Ziehau 	return error;
1697af51229aSJoerg Sonnenberger }
1698af51229aSJoerg Sonnenberger 
1699af51229aSJoerg Sonnenberger /*
1700af51229aSJoerg Sonnenberger  * Main transmit routine for C+ and gigE NICs.
1701af51229aSJoerg Sonnenberger  */
1702af51229aSJoerg Sonnenberger 
1703af51229aSJoerg Sonnenberger static void
re_start(struct ifnet * ifp,struct ifaltq_subque * ifsq)1704f0a26983SSepherosa Ziehau re_start(struct ifnet *ifp, struct ifaltq_subque *ifsq)
1705af51229aSJoerg Sonnenberger {
1706af51229aSJoerg Sonnenberger 	struct re_softc	*sc = ifp->if_softc;
1707d2c71fa0SMatthew Dillon 	struct mbuf *m_head;
1708d3d3122dSSepherosa Ziehau 	int idx, need_trans, oactive, error;
1709af51229aSJoerg Sonnenberger 
1710f0a26983SSepherosa Ziehau 	ASSERT_ALTQ_SQ_DEFAULT(ifp, ifsq);
17116fbd7e67SSepherosa Ziehau 	ASSERT_SERIALIZED(ifp->if_serializer);
17126fbd7e67SSepherosa Ziehau 
1713e887515bSSepherosa Ziehau 	if ((sc->re_flags & RE_F_LINKED) == 0) {
17149db4b353SSepherosa Ziehau 		ifq_purge(&ifp->if_snd);
17159db4b353SSepherosa Ziehau 		return;
17169db4b353SSepherosa Ziehau 	}
17179db4b353SSepherosa Ziehau 
17189ed293e0SSepherosa Ziehau 	if ((ifp->if_flags & IFF_RUNNING) == 0 || ifq_is_oactive(&ifp->if_snd))
17195d686fbbSSepherosa Ziehau 		return;
17205d686fbbSSepherosa Ziehau 
1721af51229aSJoerg Sonnenberger 	idx = sc->re_ldata.re_tx_prodidx;
1722af51229aSJoerg Sonnenberger 
17232f54d1d2SSepherosa Ziehau 	need_trans = 0;
1724d3d3122dSSepherosa Ziehau 	oactive = 0;
172580492964SSepherosa Ziehau 	for (;;) {
172664c24521SSepherosa Ziehau 		if (sc->re_ldata.re_tx_free <= RE_TXDESC_SPARE) {
1727d3d3122dSSepherosa Ziehau 			if (!oactive) {
1728d3d3122dSSepherosa Ziehau 				if (re_tx_collect(sc)) {
1729d3d3122dSSepherosa Ziehau 					oactive = 1;
1730d3d3122dSSepherosa Ziehau 					continue;
1731d3d3122dSSepherosa Ziehau 				}
1732d3d3122dSSepherosa Ziehau 			}
17339ed293e0SSepherosa Ziehau 			ifq_set_oactive(&ifp->if_snd);
17349db4b353SSepherosa Ziehau 			break;
17359db4b353SSepherosa Ziehau 		}
17369db4b353SSepherosa Ziehau 
1737ac9843a1SSepherosa Ziehau 		m_head = ifq_dequeue(&ifp->if_snd);
1738af51229aSJoerg Sonnenberger 		if (m_head == NULL)
1739af51229aSJoerg Sonnenberger 			break;
17409db4b353SSepherosa Ziehau 
1741d3d3122dSSepherosa Ziehau 		error = re_encap(sc, &m_head, &idx);
1742d3d3122dSSepherosa Ziehau 		if (error) {
17433580fc56SSepherosa Ziehau 			/* m_head is freed by re_encap(), if we reach here */
1744d40991efSSepherosa Ziehau 			IFNET_STAT_INC(ifp, oerrors, 1);
1745d3d3122dSSepherosa Ziehau 
1746d3d3122dSSepherosa Ziehau 			if (error == EFBIG && !oactive) {
1747d3d3122dSSepherosa Ziehau 				if (re_tx_collect(sc)) {
1748d3d3122dSSepherosa Ziehau 					oactive = 1;
1749d3d3122dSSepherosa Ziehau 					continue;
1750d3d3122dSSepherosa Ziehau 				}
1751d3d3122dSSepherosa Ziehau 			}
17529ed293e0SSepherosa Ziehau 			ifq_set_oactive(&ifp->if_snd);
1753af51229aSJoerg Sonnenberger 			break;
1754af51229aSJoerg Sonnenberger 		}
17558f77d350SJoerg Sonnenberger 
1756d3d3122dSSepherosa Ziehau 		oactive = 0;
17572f54d1d2SSepherosa Ziehau 		need_trans = 1;
1758af51229aSJoerg Sonnenberger 
1759af51229aSJoerg Sonnenberger 		/*
1760af51229aSJoerg Sonnenberger 		 * If there's a BPF listener, bounce a copy of this frame
1761af51229aSJoerg Sonnenberger 		 * to him.
1762af51229aSJoerg Sonnenberger 		 */
17633580fc56SSepherosa Ziehau 		ETHER_BPF_MTAP(ifp, m_head);
1764af51229aSJoerg Sonnenberger 	}
1765af51229aSJoerg Sonnenberger 
1766d4d77345SSepherosa Ziehau 	if (!need_trans)
17672f54d1d2SSepherosa Ziehau 		return;
17682f54d1d2SSepherosa Ziehau 
1769af51229aSJoerg Sonnenberger 	sc->re_ldata.re_tx_prodidx = idx;
1770af51229aSJoerg Sonnenberger 
1771af51229aSJoerg Sonnenberger 	/*
1772af51229aSJoerg Sonnenberger 	 * RealTek put the TX poll request register in a different
1773af51229aSJoerg Sonnenberger 	 * location on the 8169 gigE chip. I don't know why.
1774af51229aSJoerg Sonnenberger 	 */
177580492964SSepherosa Ziehau 	sc->re_start_xmit(sc);
1776af51229aSJoerg Sonnenberger 
1777af51229aSJoerg Sonnenberger 	/*
1778af51229aSJoerg Sonnenberger 	 * Set a timeout in case the chip goes out to lunch.
1779af51229aSJoerg Sonnenberger 	 */
1780af51229aSJoerg Sonnenberger 	ifp->if_timer = 5;
1781af51229aSJoerg Sonnenberger }
1782af51229aSJoerg Sonnenberger 
1783af51229aSJoerg Sonnenberger static void
re_link_up(struct re_softc * sc)1784e5a5a436SSepherosa Ziehau re_link_up(struct re_softc *sc)
1785af51229aSJoerg Sonnenberger {
1786af51229aSJoerg Sonnenberger 	struct ifnet *ifp = &sc->arpcom.ac_if;
1787e5a5a436SSepherosa Ziehau 	int error;
1788af51229aSJoerg Sonnenberger 
17896fbd7e67SSepherosa Ziehau 	ASSERT_SERIALIZED(ifp->if_serializer);
17906fbd7e67SSepherosa Ziehau 
1791e5a5a436SSepherosa Ziehau 	rtl_link_on_patch(sc);
1792e5a5a436SSepherosa Ziehau 	re_stop(sc, FALSE);
1793e5a5a436SSepherosa Ziehau 	rtl_set_eaddr(sc);
1794af51229aSJoerg Sonnenberger 
179528b8276aSSepherosa Ziehau 	error = re_rx_list_init(sc);
179628b8276aSSepherosa Ziehau 	if (error) {
1797e5a5a436SSepherosa Ziehau 		re_stop(sc, TRUE);
179828b8276aSSepherosa Ziehau 		return;
179928b8276aSSepherosa Ziehau 	}
180028b8276aSSepherosa Ziehau 	error = re_tx_list_init(sc);
180128b8276aSSepherosa Ziehau 	if (error) {
1802e5a5a436SSepherosa Ziehau 		re_stop(sc, TRUE);
180328b8276aSSepherosa Ziehau 		return;
180428b8276aSSepherosa Ziehau 	}
1805af51229aSJoerg Sonnenberger 
1806af51229aSJoerg Sonnenberger 	/*
18077caafb85SSepherosa Ziehau 	 * Load the addresses of the RX and TX lists into the chip.
18087caafb85SSepherosa Ziehau 	 */
18097caafb85SSepherosa Ziehau 	CSR_WRITE_4(sc, RE_RXLIST_ADDR_HI,
18107caafb85SSepherosa Ziehau 	    RE_ADDR_HI(sc->re_ldata.re_rx_list_addr));
18117caafb85SSepherosa Ziehau 	CSR_WRITE_4(sc, RE_RXLIST_ADDR_LO,
18127caafb85SSepherosa Ziehau 	    RE_ADDR_LO(sc->re_ldata.re_rx_list_addr));
18137caafb85SSepherosa Ziehau 
18147caafb85SSepherosa Ziehau 	CSR_WRITE_4(sc, RE_TXLIST_ADDR_HI,
18157caafb85SSepherosa Ziehau 	    RE_ADDR_HI(sc->re_ldata.re_tx_list_addr));
18167caafb85SSepherosa Ziehau 	CSR_WRITE_4(sc, RE_TXLIST_ADDR_LO,
18177caafb85SSepherosa Ziehau 	    RE_ADDR_LO(sc->re_ldata.re_tx_list_addr));
18187caafb85SSepherosa Ziehau 
1819e5a5a436SSepherosa Ziehau 	rtl_hw_start(sc);
1820af51229aSJoerg Sonnenberger 
18217816ba83SSepherosa Ziehau #ifdef IFPOLL_ENABLE
1822af51229aSJoerg Sonnenberger 	/*
1823af51229aSJoerg Sonnenberger 	 * Disable interrupts if we are polling.
1824af51229aSJoerg Sonnenberger 	 */
18257816ba83SSepherosa Ziehau 	if (ifp->if_flags & IFF_NPOLLING)
1826d4d77345SSepherosa Ziehau 		re_setup_intr(sc, 0, RE_IMTYPE_NONE);
1827af51229aSJoerg Sonnenberger 	else	/* otherwise ... */
18287816ba83SSepherosa Ziehau #endif /* IFPOLL_ENABLE */
1829af51229aSJoerg Sonnenberger 	/*
1830af51229aSJoerg Sonnenberger 	 * Enable interrupts.
1831af51229aSJoerg Sonnenberger 	 */
1832d4d77345SSepherosa Ziehau 	re_setup_intr(sc, 1, sc->re_imtype);
183380492964SSepherosa Ziehau 	sc->re_write_isr(sc, sc->re_intrs);
1834af51229aSJoerg Sonnenberger 
1835e5a5a436SSepherosa Ziehau 	sc->re_flags |= RE_F_LINKED;
1836e5a5a436SSepherosa Ziehau 	ifp->if_link_state = LINK_STATE_UP;
1837e5a5a436SSepherosa Ziehau 	if_link_state_change(ifp);
18385bed1fbdSSepherosa Ziehau 
1839e5a5a436SSepherosa Ziehau 	if (bootverbose)
1840e5a5a436SSepherosa Ziehau 		if_printf(ifp, "link UP\n");
1841af51229aSJoerg Sonnenberger 
1842e5a5a436SSepherosa Ziehau 	if (!ifq_is_empty(&ifp->if_snd))
1843e5a5a436SSepherosa Ziehau 		if_devstart(ifp);
1844a7d57e62SSepherosa Ziehau }
1845af51229aSJoerg Sonnenberger 
1846e5a5a436SSepherosa Ziehau static void
re_link_down(struct re_softc * sc)1847e5a5a436SSepherosa Ziehau re_link_down(struct re_softc *sc)
1848e5a5a436SSepherosa Ziehau {
1849e5a5a436SSepherosa Ziehau 	struct ifnet *ifp = &sc->arpcom.ac_if;
1850af51229aSJoerg Sonnenberger 
1851e5a5a436SSepherosa Ziehau 	/* NOTE: re_stop() will reset RE_F_LINKED. */
1852e5a5a436SSepherosa Ziehau 	ifp->if_link_state = LINK_STATE_DOWN;
1853e5a5a436SSepherosa Ziehau 	if_link_state_change(ifp);
1854af51229aSJoerg Sonnenberger 
1855e5a5a436SSepherosa Ziehau 	re_stop(sc, FALSE);
1856e5a5a436SSepherosa Ziehau 	rtl_ifmedia_upd(ifp);
1857e5a5a436SSepherosa Ziehau 
1858e5a5a436SSepherosa Ziehau 	if (bootverbose)
1859e5a5a436SSepherosa Ziehau 		if_printf(ifp, "link DOWN\n");
1860e5a5a436SSepherosa Ziehau }
1861e5a5a436SSepherosa Ziehau 
1862e5a5a436SSepherosa Ziehau static void
re_init(void * xsc)1863e5a5a436SSepherosa Ziehau re_init(void *xsc)
1864e5a5a436SSepherosa Ziehau {
1865e5a5a436SSepherosa Ziehau 	struct re_softc *sc = xsc;
1866e5a5a436SSepherosa Ziehau 	struct ifnet *ifp = &sc->arpcom.ac_if;
1867e5a5a436SSepherosa Ziehau 
1868e5a5a436SSepherosa Ziehau 	ASSERT_SERIALIZED(ifp->if_serializer);
1869e5a5a436SSepherosa Ziehau 
1870e5a5a436SSepherosa Ziehau 	re_stop(sc, TRUE);
1871e5a5a436SSepherosa Ziehau 	if (rtl_link_ok(sc)) {
1872e5a5a436SSepherosa Ziehau 		if (bootverbose)
1873e5a5a436SSepherosa Ziehau 			if_printf(ifp, "link is UP in if_init\n");
1874e5a5a436SSepherosa Ziehau 		re_link_up(sc);
1875e5a5a436SSepherosa Ziehau 	}
1876af51229aSJoerg Sonnenberger 
1877af51229aSJoerg Sonnenberger 	ifp->if_flags |= IFF_RUNNING;
18789ed293e0SSepherosa Ziehau 	ifq_clr_oactive(&ifp->if_snd);
1879af51229aSJoerg Sonnenberger 
1880af51229aSJoerg Sonnenberger 	callout_reset(&sc->re_timer, hz, re_tick, sc);
1881af51229aSJoerg Sonnenberger }
1882af51229aSJoerg Sonnenberger 
1883af51229aSJoerg Sonnenberger static int
re_ioctl(struct ifnet * ifp,u_long command,caddr_t data,struct ucred * cr)1884af51229aSJoerg Sonnenberger re_ioctl(struct ifnet *ifp, u_long command, caddr_t data, struct ucred *cr)
1885af51229aSJoerg Sonnenberger {
1886af51229aSJoerg Sonnenberger 	struct re_softc *sc = ifp->if_softc;
1887af51229aSJoerg Sonnenberger 	struct ifreq *ifr = (struct ifreq *)data;
1888a1dc54ffSSepherosa Ziehau 	int error = 0, mask;
1889af51229aSJoerg Sonnenberger 
18906fbd7e67SSepherosa Ziehau 	ASSERT_SERIALIZED(ifp->if_serializer);
18916fbd7e67SSepherosa Ziehau 
1892af51229aSJoerg Sonnenberger 	switch(command) {
1893af51229aSJoerg Sonnenberger 	case SIOCSIFMTU:
1894e5a5a436SSepherosa Ziehau #ifdef RE_JUMBO
1895089dc1b7SSepherosa Ziehau 		if (ifr->ifr_mtu > sc->re_maxmtu) {
1896af51229aSJoerg Sonnenberger 			error = EINVAL;
1897089dc1b7SSepherosa Ziehau 		} else if (ifp->if_mtu != ifr->ifr_mtu) {
1898af51229aSJoerg Sonnenberger 			ifp->if_mtu = ifr->ifr_mtu;
1899089dc1b7SSepherosa Ziehau 			if (ifp->if_flags & IFF_RUNNING)
1900089dc1b7SSepherosa Ziehau 				ifp->if_init(sc);
1901089dc1b7SSepherosa Ziehau 		}
1902e5a5a436SSepherosa Ziehau #else
1903e5a5a436SSepherosa Ziehau 		error = EOPNOTSUPP;
1904e5a5a436SSepherosa Ziehau #endif
1905af51229aSJoerg Sonnenberger 		break;
1906089dc1b7SSepherosa Ziehau 
1907af51229aSJoerg Sonnenberger 	case SIOCSIFFLAGS:
190876c6d5cfSSepherosa Ziehau 		if (ifp->if_flags & IFF_UP) {
190976c6d5cfSSepherosa Ziehau 			if (ifp->if_flags & IFF_RUNNING) {
1910e5a5a436SSepherosa Ziehau 				if ((ifp->if_flags ^ sc->re_saved_ifflags) &
191176c6d5cfSSepherosa Ziehau 				    (IFF_PROMISC | IFF_ALLMULTI))
1912e5a5a436SSepherosa Ziehau 					rtl_set_rx_packet_filter(sc);
191376c6d5cfSSepherosa Ziehau 			} else {
1914af51229aSJoerg Sonnenberger 				re_init(sc);
191576c6d5cfSSepherosa Ziehau 			}
191676c6d5cfSSepherosa Ziehau 		} else if (ifp->if_flags & IFF_RUNNING) {
1917e5a5a436SSepherosa Ziehau 			re_stop(sc, TRUE);
191876c6d5cfSSepherosa Ziehau 		}
1919e5a5a436SSepherosa Ziehau 		sc->re_saved_ifflags = ifp->if_flags;
1920af51229aSJoerg Sonnenberger 		break;
192176c6d5cfSSepherosa Ziehau 
1922af51229aSJoerg Sonnenberger 	case SIOCADDMULTI:
1923af51229aSJoerg Sonnenberger 	case SIOCDELMULTI:
1924e5a5a436SSepherosa Ziehau 		rtl_set_rx_packet_filter(sc);
1925af51229aSJoerg Sonnenberger 		break;
192676c6d5cfSSepherosa Ziehau 
1927af51229aSJoerg Sonnenberger 	case SIOCGIFMEDIA:
19281e1c5facSSepherosa Ziehau 	case SIOCGIFXMEDIA:
1929af51229aSJoerg Sonnenberger 	case SIOCSIFMEDIA:
1930e5a5a436SSepherosa Ziehau 		error = ifmedia_ioctl(ifp, ifr, &sc->media, command);
1931af51229aSJoerg Sonnenberger 		break;
193276c6d5cfSSepherosa Ziehau 
1933af51229aSJoerg Sonnenberger 	case SIOCSIFCAP:
1934a1dc54ffSSepherosa Ziehau 		mask = (ifr->ifr_reqcap ^ ifp->if_capenable) &
1935a1dc54ffSSepherosa Ziehau 		       ifp->if_capabilities;
1936a1dc54ffSSepherosa Ziehau 		ifp->if_capenable ^= mask;
1937a1dc54ffSSepherosa Ziehau 
1938e5a5a436SSepherosa Ziehau 		/* NOTE: re_init will setup if_hwassist. */
1939af51229aSJoerg Sonnenberger 		ifp->if_hwassist = 0;
1940e5a5a436SSepherosa Ziehau 
1941e5a5a436SSepherosa Ziehau 		/* Setup flags for the backend. */
1942e5a5a436SSepherosa Ziehau 		if (ifp->if_capenable & IFCAP_RXCSUM)
1943e5a5a436SSepherosa Ziehau 			sc->re_rx_cstag = 1;
1944e5a5a436SSepherosa Ziehau 		else
1945e5a5a436SSepherosa Ziehau 			sc->re_rx_cstag = 0;
1946e5a5a436SSepherosa Ziehau 		if (ifp->if_capenable & IFCAP_TXCSUM)
1947e5a5a436SSepherosa Ziehau 			sc->re_tx_cstag = 1;
1948e5a5a436SSepherosa Ziehau 		else
19491f7ae36fSSepherosa Ziehau 			sc->re_tx_cstag = 0;
1950e5a5a436SSepherosa Ziehau 
1951a1dc54ffSSepherosa Ziehau 		if (mask && (ifp->if_flags & IFF_RUNNING))
1952af51229aSJoerg Sonnenberger 			re_init(sc);
1953af51229aSJoerg Sonnenberger 		break;
195476c6d5cfSSepherosa Ziehau 
1955af51229aSJoerg Sonnenberger 	default:
1956af51229aSJoerg Sonnenberger 		error = ether_ioctl(ifp, command, data);
1957af51229aSJoerg Sonnenberger 		break;
1958af51229aSJoerg Sonnenberger 	}
1959af51229aSJoerg Sonnenberger 	return(error);
1960af51229aSJoerg Sonnenberger }
1961af51229aSJoerg Sonnenberger 
1962af51229aSJoerg Sonnenberger static void
re_watchdog(struct ifnet * ifp)1963af51229aSJoerg Sonnenberger re_watchdog(struct ifnet *ifp)
1964af51229aSJoerg Sonnenberger {
1965af51229aSJoerg Sonnenberger 	struct re_softc *sc = ifp->if_softc;
1966af51229aSJoerg Sonnenberger 
19676fbd7e67SSepherosa Ziehau 	ASSERT_SERIALIZED(ifp->if_serializer);
19686fbd7e67SSepherosa Ziehau 
1969d40991efSSepherosa Ziehau 	IFNET_STAT_INC(ifp, oerrors, 1);
1970af51229aSJoerg Sonnenberger 
1971af51229aSJoerg Sonnenberger 	re_txeof(sc);
1972af51229aSJoerg Sonnenberger 	re_rxeof(sc);
1973af51229aSJoerg Sonnenberger 
1974e5a5a436SSepherosa Ziehau 	if (sc->re_ldata.re_tx_free != sc->re_tx_desc_cnt) {
1975e5a5a436SSepherosa Ziehau 		if_printf(ifp, "watchdog timeout, txd free %d\n",
1976e5a5a436SSepherosa Ziehau 		    sc->re_ldata.re_tx_free);
1977e5a5a436SSepherosa Ziehau 		rtl_reset(sc);
1978af51229aSJoerg Sonnenberger 		re_init(sc);
1979e5a5a436SSepherosa Ziehau 	}
1980af51229aSJoerg Sonnenberger }
1981af51229aSJoerg Sonnenberger 
1982af51229aSJoerg Sonnenberger /*
1983af51229aSJoerg Sonnenberger  * Stop the adapter and free any mbufs allocated to the
1984af51229aSJoerg Sonnenberger  * RX and TX lists.
1985af51229aSJoerg Sonnenberger  */
1986af51229aSJoerg Sonnenberger static void
re_stop(struct re_softc * sc,boolean_t full_stop)1987e5a5a436SSepherosa Ziehau re_stop(struct re_softc *sc, boolean_t full_stop)
1988af51229aSJoerg Sonnenberger {
1989af51229aSJoerg Sonnenberger 	struct ifnet *ifp = &sc->arpcom.ac_if;
1990f0ee8b5bSJoerg Sonnenberger 	int i;
1991af51229aSJoerg Sonnenberger 
19926fbd7e67SSepherosa Ziehau 	ASSERT_SERIALIZED(ifp->if_serializer);
19936fbd7e67SSepherosa Ziehau 
1994e5a5a436SSepherosa Ziehau 	/* Stop the adapter. */
1995e5a5a436SSepherosa Ziehau 	rtl_stop(sc);
19960d73dcefSSepherosa Ziehau 
1997af51229aSJoerg Sonnenberger 	ifp->if_timer = 0;
1998e5a5a436SSepherosa Ziehau 	if (full_stop) {
1999af51229aSJoerg Sonnenberger 		callout_stop(&sc->re_timer);
20009ed293e0SSepherosa Ziehau 		ifp->if_flags &= ~IFF_RUNNING;
2001e5a5a436SSepherosa Ziehau 	}
20029ed293e0SSepherosa Ziehau 	ifq_clr_oactive(&ifp->if_snd);
2003e887515bSSepherosa Ziehau 	sc->re_flags &= ~(RE_F_TIMER_INTR | RE_F_DROP_RXFRAG | RE_F_LINKED);
2004af51229aSJoerg Sonnenberger 
20052499e0afSSepherosa Ziehau 	re_free_rxchain(sc);
2006af51229aSJoerg Sonnenberger 
2007af51229aSJoerg Sonnenberger 	/* Free the TX list buffers. */
200853d4588aSSepherosa Ziehau 	for (i = 0; i < sc->re_tx_desc_cnt; i++) {
2009af51229aSJoerg Sonnenberger 		if (sc->re_ldata.re_tx_mbuf[i] != NULL) {
20108aaa1e58SSepherosa Ziehau 			bus_dmamap_unload(sc->re_ldata.re_tx_mtag,
2011af51229aSJoerg Sonnenberger 					  sc->re_ldata.re_tx_dmamap[i]);
2012af51229aSJoerg Sonnenberger 			m_freem(sc->re_ldata.re_tx_mbuf[i]);
2013af51229aSJoerg Sonnenberger 			sc->re_ldata.re_tx_mbuf[i] = NULL;
2014af51229aSJoerg Sonnenberger 		}
2015af51229aSJoerg Sonnenberger 	}
2016af51229aSJoerg Sonnenberger 
2017af51229aSJoerg Sonnenberger 	/* Free the RX list buffers. */
201853d4588aSSepherosa Ziehau 	for (i = 0; i < sc->re_rx_desc_cnt; i++) {
2019af51229aSJoerg Sonnenberger 		if (sc->re_ldata.re_rx_mbuf[i] != NULL) {
2020a7d57e62SSepherosa Ziehau 			if ((sc->re_flags & RE_F_USE_JPOOL) == 0) {
20218aaa1e58SSepherosa Ziehau 				bus_dmamap_unload(sc->re_ldata.re_rx_mtag,
2022af51229aSJoerg Sonnenberger 						  sc->re_ldata.re_rx_dmamap[i]);
2023a7d57e62SSepherosa Ziehau 			}
2024af51229aSJoerg Sonnenberger 			m_freem(sc->re_ldata.re_rx_mbuf[i]);
2025af51229aSJoerg Sonnenberger 			sc->re_ldata.re_rx_mbuf[i] = NULL;
2026af51229aSJoerg Sonnenberger 		}
2027af51229aSJoerg Sonnenberger 	}
2028af51229aSJoerg Sonnenberger }
2029af51229aSJoerg Sonnenberger 
2030af51229aSJoerg Sonnenberger /*
2031af51229aSJoerg Sonnenberger  * Device suspend routine.  Stop the interface and save some PCI
2032af51229aSJoerg Sonnenberger  * settings in case the BIOS doesn't restore them properly on
2033af51229aSJoerg Sonnenberger  * resume.
2034af51229aSJoerg Sonnenberger  */
2035af51229aSJoerg Sonnenberger static int
re_suspend(device_t dev)2036af51229aSJoerg Sonnenberger re_suspend(device_t dev)
2037af51229aSJoerg Sonnenberger {
2038af51229aSJoerg Sonnenberger #ifndef BURN_BRIDGES
2039af51229aSJoerg Sonnenberger 	int i;
2040af51229aSJoerg Sonnenberger #endif
2041af51229aSJoerg Sonnenberger 	struct re_softc *sc = device_get_softc(dev);
20426fbd7e67SSepherosa Ziehau 	struct ifnet *ifp = &sc->arpcom.ac_if;
20436fbd7e67SSepherosa Ziehau 
20446fbd7e67SSepherosa Ziehau 	lwkt_serialize_enter(ifp->if_serializer);
2045af51229aSJoerg Sonnenberger 
2046e5a5a436SSepherosa Ziehau 	re_stop(sc, TRUE);
2047af51229aSJoerg Sonnenberger 
2048af51229aSJoerg Sonnenberger #ifndef BURN_BRIDGES
2049af51229aSJoerg Sonnenberger 	for (i = 0; i < 5; i++)
2050af51229aSJoerg Sonnenberger 		sc->saved_maps[i] = pci_read_config(dev, PCIR_MAPS + i * 4, 4);
2051af51229aSJoerg Sonnenberger 	sc->saved_biosaddr = pci_read_config(dev, PCIR_BIOS, 4);
2052af51229aSJoerg Sonnenberger 	sc->saved_intline = pci_read_config(dev, PCIR_INTLINE, 1);
2053af51229aSJoerg Sonnenberger 	sc->saved_cachelnsz = pci_read_config(dev, PCIR_CACHELNSZ, 1);
2054af51229aSJoerg Sonnenberger 	sc->saved_lattimer = pci_read_config(dev, PCIR_LATTIMER, 1);
2055af51229aSJoerg Sonnenberger #endif
2056af51229aSJoerg Sonnenberger 
2057e887515bSSepherosa Ziehau 	sc->re_flags |= RE_F_SUSPENDED;
2058af51229aSJoerg Sonnenberger 
20596fbd7e67SSepherosa Ziehau 	lwkt_serialize_exit(ifp->if_serializer);
20606fbd7e67SSepherosa Ziehau 
2061af51229aSJoerg Sonnenberger 	return (0);
2062af51229aSJoerg Sonnenberger }
2063af51229aSJoerg Sonnenberger 
2064af51229aSJoerg Sonnenberger /*
2065af51229aSJoerg Sonnenberger  * Device resume routine.  Restore some PCI settings in case the BIOS
2066af51229aSJoerg Sonnenberger  * doesn't, re-enable busmastering, and restart the interface if
2067af51229aSJoerg Sonnenberger  * appropriate.
2068af51229aSJoerg Sonnenberger  */
2069af51229aSJoerg Sonnenberger static int
re_resume(device_t dev)2070af51229aSJoerg Sonnenberger re_resume(device_t dev)
2071af51229aSJoerg Sonnenberger {
2072af51229aSJoerg Sonnenberger 	struct re_softc *sc = device_get_softc(dev);
2073af51229aSJoerg Sonnenberger 	struct ifnet *ifp = &sc->arpcom.ac_if;
2074af51229aSJoerg Sonnenberger #ifndef BURN_BRIDGES
2075af51229aSJoerg Sonnenberger 	int i;
2076af51229aSJoerg Sonnenberger #endif
2077af51229aSJoerg Sonnenberger 
20786fbd7e67SSepherosa Ziehau 	lwkt_serialize_enter(ifp->if_serializer);
20796fbd7e67SSepherosa Ziehau 
2080af51229aSJoerg Sonnenberger #ifndef BURN_BRIDGES
2081af51229aSJoerg Sonnenberger 	/* better way to do this? */
2082af51229aSJoerg Sonnenberger 	for (i = 0; i < 5; i++)
2083af51229aSJoerg Sonnenberger 		pci_write_config(dev, PCIR_MAPS + i * 4, sc->saved_maps[i], 4);
2084af51229aSJoerg Sonnenberger 	pci_write_config(dev, PCIR_BIOS, sc->saved_biosaddr, 4);
2085af51229aSJoerg Sonnenberger 	pci_write_config(dev, PCIR_INTLINE, sc->saved_intline, 1);
2086af51229aSJoerg Sonnenberger 	pci_write_config(dev, PCIR_CACHELNSZ, sc->saved_cachelnsz, 1);
2087af51229aSJoerg Sonnenberger 	pci_write_config(dev, PCIR_LATTIMER, sc->saved_lattimer, 1);
2088af51229aSJoerg Sonnenberger 
2089af51229aSJoerg Sonnenberger 	/* reenable busmastering */
2090af51229aSJoerg Sonnenberger 	pci_enable_busmaster(dev);
2091ecd80f47SJoerg Sonnenberger 	pci_enable_io(dev, SYS_RES_IOPORT);
2092af51229aSJoerg Sonnenberger #endif
2093af51229aSJoerg Sonnenberger 
2094af51229aSJoerg Sonnenberger 	/* reinitialize interface if necessary */
2095af51229aSJoerg Sonnenberger 	if (ifp->if_flags & IFF_UP)
2096af51229aSJoerg Sonnenberger 		re_init(sc);
2097af51229aSJoerg Sonnenberger 
2098e887515bSSepherosa Ziehau 	sc->re_flags &= ~RE_F_SUSPENDED;
2099af51229aSJoerg Sonnenberger 
21006fbd7e67SSepherosa Ziehau 	lwkt_serialize_exit(ifp->if_serializer);
21016fbd7e67SSepherosa Ziehau 
2102af51229aSJoerg Sonnenberger 	return (0);
2103af51229aSJoerg Sonnenberger }
2104af51229aSJoerg Sonnenberger 
2105af51229aSJoerg Sonnenberger /*
2106af51229aSJoerg Sonnenberger  * Stop all chip I/O so that the kernel's probe routines don't
2107af51229aSJoerg Sonnenberger  * get confused by errant DMAs when rebooting.
2108af51229aSJoerg Sonnenberger  */
2109af51229aSJoerg Sonnenberger static void
re_shutdown(device_t dev)2110af51229aSJoerg Sonnenberger re_shutdown(device_t dev)
2111af51229aSJoerg Sonnenberger {
2112af51229aSJoerg Sonnenberger 	struct re_softc *sc = device_get_softc(dev);
21135d686fbbSSepherosa Ziehau 	struct ifnet *ifp = &sc->arpcom.ac_if;
2114af51229aSJoerg Sonnenberger 
21155d686fbbSSepherosa Ziehau 	lwkt_serialize_enter(ifp->if_serializer);
2116e5a5a436SSepherosa Ziehau 	re_stop(sc, TRUE);
2117e5a5a436SSepherosa Ziehau 	rtl_hw_d3_para(sc);
2118e5a5a436SSepherosa Ziehau 	rtl_phy_power_down(sc);
21195d686fbbSSepherosa Ziehau 	lwkt_serialize_exit(ifp->if_serializer);
21205d686fbbSSepherosa Ziehau }
21215d686fbbSSepherosa Ziehau 
21225d686fbbSSepherosa Ziehau static int
re_sysctl_rxtime(SYSCTL_HANDLER_ARGS)2123d4d77345SSepherosa Ziehau re_sysctl_rxtime(SYSCTL_HANDLER_ARGS)
2124d4d77345SSepherosa Ziehau {
2125d4d77345SSepherosa Ziehau 	struct re_softc *sc = arg1;
2126d4d77345SSepherosa Ziehau 
2127d4d77345SSepherosa Ziehau 	return re_sysctl_hwtime(oidp, arg1, arg2, req, &sc->re_rx_time);
2128d4d77345SSepherosa Ziehau }
2129d4d77345SSepherosa Ziehau 
2130d4d77345SSepherosa Ziehau static int
re_sysctl_txtime(SYSCTL_HANDLER_ARGS)2131d4d77345SSepherosa Ziehau re_sysctl_txtime(SYSCTL_HANDLER_ARGS)
2132d4d77345SSepherosa Ziehau {
2133d4d77345SSepherosa Ziehau 	struct re_softc *sc = arg1;
2134d4d77345SSepherosa Ziehau 
2135d4d77345SSepherosa Ziehau 	return re_sysctl_hwtime(oidp, arg1, arg2, req, &sc->re_tx_time);
2136d4d77345SSepherosa Ziehau }
2137d4d77345SSepherosa Ziehau 
2138d4d77345SSepherosa Ziehau static int
re_sysctl_hwtime(SYSCTL_HANDLER_ARGS,int * hwtime)2139d4d77345SSepherosa Ziehau re_sysctl_hwtime(SYSCTL_HANDLER_ARGS, int *hwtime)
2140d4d77345SSepherosa Ziehau {
2141d4d77345SSepherosa Ziehau 	struct re_softc *sc = arg1;
2142d4d77345SSepherosa Ziehau 	struct ifnet *ifp = &sc->arpcom.ac_if;
2143d4d77345SSepherosa Ziehau 	int error, v;
2144d4d77345SSepherosa Ziehau 
2145d4d77345SSepherosa Ziehau 	lwkt_serialize_enter(ifp->if_serializer);
2146d4d77345SSepherosa Ziehau 
2147d4d77345SSepherosa Ziehau 	v = *hwtime;
2148d4d77345SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &v, 0, req);
2149d4d77345SSepherosa Ziehau 	if (error || req->newptr == NULL)
2150d4d77345SSepherosa Ziehau 		goto back;
2151d4d77345SSepherosa Ziehau 
2152d4d77345SSepherosa Ziehau 	if (v <= 0) {
2153d4d77345SSepherosa Ziehau 		error = EINVAL;
2154d4d77345SSepherosa Ziehau 		goto back;
2155d4d77345SSepherosa Ziehau 	}
2156d4d77345SSepherosa Ziehau 
2157d4d77345SSepherosa Ziehau 	if (v != *hwtime) {
2158d4d77345SSepherosa Ziehau 		*hwtime = v;
2159d4d77345SSepherosa Ziehau 
21607816ba83SSepherosa Ziehau 		if ((ifp->if_flags & (IFF_RUNNING | IFF_NPOLLING)) ==
2161d4d77345SSepherosa Ziehau 		    IFF_RUNNING && sc->re_imtype == RE_IMTYPE_HW)
2162d4d77345SSepherosa Ziehau 			re_setup_hw_im(sc);
2163d4d77345SSepherosa Ziehau 	}
2164d4d77345SSepherosa Ziehau back:
2165d4d77345SSepherosa Ziehau 	lwkt_serialize_exit(ifp->if_serializer);
2166d4d77345SSepherosa Ziehau 	return error;
2167d4d77345SSepherosa Ziehau }
2168d4d77345SSepherosa Ziehau 
2169d4d77345SSepherosa Ziehau static int
re_sysctl_simtime(SYSCTL_HANDLER_ARGS)2170d4d77345SSepherosa Ziehau re_sysctl_simtime(SYSCTL_HANDLER_ARGS)
2171d4d77345SSepherosa Ziehau {
2172d4d77345SSepherosa Ziehau 	struct re_softc *sc = arg1;
2173d4d77345SSepherosa Ziehau 	struct ifnet *ifp = &sc->arpcom.ac_if;
2174d4d77345SSepherosa Ziehau 	int error, v;
2175d4d77345SSepherosa Ziehau 
2176d4d77345SSepherosa Ziehau 	lwkt_serialize_enter(ifp->if_serializer);
2177d4d77345SSepherosa Ziehau 
2178d4d77345SSepherosa Ziehau 	v = sc->re_sim_time;
2179d4d77345SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &v, 0, req);
2180d4d77345SSepherosa Ziehau 	if (error || req->newptr == NULL)
2181d4d77345SSepherosa Ziehau 		goto back;
2182d4d77345SSepherosa Ziehau 
2183d4d77345SSepherosa Ziehau 	if (v <= 0) {
2184d4d77345SSepherosa Ziehau 		error = EINVAL;
2185d4d77345SSepherosa Ziehau 		goto back;
2186d4d77345SSepherosa Ziehau 	}
2187d4d77345SSepherosa Ziehau 
2188d4d77345SSepherosa Ziehau 	if (v != sc->re_sim_time) {
2189d4d77345SSepherosa Ziehau 		sc->re_sim_time = v;
2190d4d77345SSepherosa Ziehau 
21917816ba83SSepherosa Ziehau 		if ((ifp->if_flags & (IFF_RUNNING | IFF_NPOLLING)) ==
2192d4d77345SSepherosa Ziehau 		    IFF_RUNNING && sc->re_imtype == RE_IMTYPE_SIM) {
2193d4d77345SSepherosa Ziehau #ifdef foo
2194d4d77345SSepherosa Ziehau 			/*
2195d4d77345SSepherosa Ziehau 			 * Following code causes various strange
2196d4d77345SSepherosa Ziehau 			 * performance problems.  Hmm ...
2197d4d77345SSepherosa Ziehau 			 */
219880492964SSepherosa Ziehau 			sc->re_write_imr(sc, 0);
2199e5a5a436SSepherosa Ziehau 			CSR_WRITE_4(sc, RE_TIMERINT, 0);
2200e5a5a436SSepherosa Ziehau 			CSR_READ_4(sc, RE_TIMERINT); /* flush */
2201d4d77345SSepherosa Ziehau 
220280492964SSepherosa Ziehau 			sc->re_write_imr(sc, sc->re_intrs);
2203d4d77345SSepherosa Ziehau 			re_setup_sim_im(sc);
2204d4d77345SSepherosa Ziehau #else
2205d4d77345SSepherosa Ziehau 			re_setup_intr(sc, 0, RE_IMTYPE_NONE);
2206d4d77345SSepherosa Ziehau 			DELAY(10);
2207d4d77345SSepherosa Ziehau 			re_setup_intr(sc, 1, RE_IMTYPE_SIM);
2208d4d77345SSepherosa Ziehau #endif
2209d4d77345SSepherosa Ziehau 		}
2210d4d77345SSepherosa Ziehau 	}
2211d4d77345SSepherosa Ziehau back:
2212d4d77345SSepherosa Ziehau 	lwkt_serialize_exit(ifp->if_serializer);
2213d4d77345SSepherosa Ziehau 	return error;
2214d4d77345SSepherosa Ziehau }
2215d4d77345SSepherosa Ziehau 
2216d4d77345SSepherosa Ziehau static int
re_sysctl_imtype(SYSCTL_HANDLER_ARGS)2217d4d77345SSepherosa Ziehau re_sysctl_imtype(SYSCTL_HANDLER_ARGS)
2218d4d77345SSepherosa Ziehau {
2219d4d77345SSepherosa Ziehau 	struct re_softc *sc = arg1;
2220d4d77345SSepherosa Ziehau 	struct ifnet *ifp = &sc->arpcom.ac_if;
2221d4d77345SSepherosa Ziehau 	int error, v;
2222d4d77345SSepherosa Ziehau 
2223d4d77345SSepherosa Ziehau 	lwkt_serialize_enter(ifp->if_serializer);
2224d4d77345SSepherosa Ziehau 
2225d4d77345SSepherosa Ziehau 	v = sc->re_imtype;
2226d4d77345SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &v, 0, req);
2227d4d77345SSepherosa Ziehau 	if (error || req->newptr == NULL)
2228d4d77345SSepherosa Ziehau 		goto back;
2229d4d77345SSepherosa Ziehau 
2230d4d77345SSepherosa Ziehau 	if (v != RE_IMTYPE_HW && v != RE_IMTYPE_SIM && v != RE_IMTYPE_NONE) {
2231d4d77345SSepherosa Ziehau 		error = EINVAL;
2232d4d77345SSepherosa Ziehau 		goto back;
2233d4d77345SSepherosa Ziehau 	}
2234d4d77345SSepherosa Ziehau 	if (v == RE_IMTYPE_HW && (sc->re_caps & RE_C_HWIM) == 0) {
2235d4d77345SSepherosa Ziehau 		/* Can't do hardware interrupt moderation */
2236d4d77345SSepherosa Ziehau 		error = EOPNOTSUPP;
2237d4d77345SSepherosa Ziehau 		goto back;
2238d4d77345SSepherosa Ziehau 	}
2239d4d77345SSepherosa Ziehau 
2240d4d77345SSepherosa Ziehau 	if (v != sc->re_imtype) {
2241d4d77345SSepherosa Ziehau 		sc->re_imtype = v;
22427816ba83SSepherosa Ziehau 		if ((ifp->if_flags & (IFF_RUNNING | IFF_NPOLLING)) ==
2243d4d77345SSepherosa Ziehau 		    IFF_RUNNING)
2244d4d77345SSepherosa Ziehau 			re_setup_intr(sc, 1, sc->re_imtype);
2245d4d77345SSepherosa Ziehau 	}
2246d4d77345SSepherosa Ziehau back:
2247d4d77345SSepherosa Ziehau 	lwkt_serialize_exit(ifp->if_serializer);
2248d4d77345SSepherosa Ziehau 	return error;
2249d4d77345SSepherosa Ziehau }
2250d4d77345SSepherosa Ziehau 
2251d4d77345SSepherosa Ziehau static void
re_setup_hw_im(struct re_softc * sc)2252d4d77345SSepherosa Ziehau re_setup_hw_im(struct re_softc *sc)
2253d4d77345SSepherosa Ziehau {
2254d4d77345SSepherosa Ziehau 	KKASSERT(sc->re_caps & RE_C_HWIM);
2255d4d77345SSepherosa Ziehau 
2256d4d77345SSepherosa Ziehau 	/*
2257d4d77345SSepherosa Ziehau 	 * Interrupt moderation
2258d4d77345SSepherosa Ziehau 	 *
2259d4d77345SSepherosa Ziehau 	 * 0xABCD
2260d4d77345SSepherosa Ziehau 	 * A - unknown (maybe TX related)
2261d4d77345SSepherosa Ziehau 	 * B - TX timer (unit: 25us)
2262d4d77345SSepherosa Ziehau 	 * C - unknown (maybe RX related)
2263d4d77345SSepherosa Ziehau 	 * D - RX timer (unit: 25us)
2264d4d77345SSepherosa Ziehau 	 *
2265d4d77345SSepherosa Ziehau 	 *
2266d4d77345SSepherosa Ziehau 	 * re(4)'s interrupt moderation is actually controlled by
2267d4d77345SSepherosa Ziehau 	 * two variables, like most other NICs (bge, bce etc.)
2268d4d77345SSepherosa Ziehau 	 * o  timer
2269d4d77345SSepherosa Ziehau 	 * o  number of packets [P]
2270d4d77345SSepherosa Ziehau 	 *
2271d4d77345SSepherosa Ziehau 	 * The logic relationship between these two variables is
2272d4d77345SSepherosa Ziehau 	 * similar to other NICs too:
2273d4d77345SSepherosa Ziehau 	 * if (timer expire || packets > [P])
2274d4d77345SSepherosa Ziehau 	 *     Interrupt is delivered
2275d4d77345SSepherosa Ziehau 	 *
2276d4d77345SSepherosa Ziehau 	 * Currently we only know how to set 'timer', but not
2277d4d77345SSepherosa Ziehau 	 * 'number of packets', which should be ~30, as far as I
2278d4d77345SSepherosa Ziehau 	 * tested (sink ~900Kpps, interrupt rate is 30KHz)
2279d4d77345SSepherosa Ziehau 	 */
2280d4d77345SSepherosa Ziehau 	CSR_WRITE_2(sc, RE_IM,
2281d4d77345SSepherosa Ziehau 		    RE_IM_RXTIME(sc->re_rx_time) |
2282d4d77345SSepherosa Ziehau 		    RE_IM_TXTIME(sc->re_tx_time) |
2283d4d77345SSepherosa Ziehau 		    RE_IM_MAGIC);
2284d4d77345SSepherosa Ziehau }
2285d4d77345SSepherosa Ziehau 
2286d4d77345SSepherosa Ziehau static void
re_disable_hw_im(struct re_softc * sc)2287d4d77345SSepherosa Ziehau re_disable_hw_im(struct re_softc *sc)
2288d4d77345SSepherosa Ziehau {
2289d4d77345SSepherosa Ziehau 	if (sc->re_caps & RE_C_HWIM)
2290d4d77345SSepherosa Ziehau 		CSR_WRITE_2(sc, RE_IM, 0);
2291d4d77345SSepherosa Ziehau }
2292d4d77345SSepherosa Ziehau 
2293d4d77345SSepherosa Ziehau static void
re_setup_sim_im(struct re_softc * sc)2294d4d77345SSepherosa Ziehau re_setup_sim_im(struct re_softc *sc)
2295d4d77345SSepherosa Ziehau {
2296d4d77345SSepherosa Ziehau 	uint32_t ticks;
2297d4d77345SSepherosa Ziehau 
2298e5a5a436SSepherosa Ziehau 	if (sc->re_if_flags & RL_FLAG_PCIE) {
2299e5a5a436SSepherosa Ziehau 		ticks = sc->re_sim_time * sc->re_bus_speed;
2300e5a5a436SSepherosa Ziehau 	} else {
2301d4d77345SSepherosa Ziehau 		/*
2302d4d77345SSepherosa Ziehau 		 * Datasheet says tick decreases at bus speed,
2303d4d77345SSepherosa Ziehau 		 * but it seems the clock runs a little bit
2304d4d77345SSepherosa Ziehau 		 * faster, so we do some compensation here.
2305d4d77345SSepherosa Ziehau 		 */
2306d4d77345SSepherosa Ziehau 		ticks = (sc->re_sim_time * sc->re_bus_speed * 8) / 5;
2307d4d77345SSepherosa Ziehau 	}
2308e5a5a436SSepherosa Ziehau 	CSR_WRITE_4(sc, RE_TIMERINT, ticks);
2309e5a5a436SSepherosa Ziehau 
2310d4d77345SSepherosa Ziehau 	CSR_WRITE_4(sc, RE_TIMERCNT, 1); /* reload */
2311d4d77345SSepherosa Ziehau 	sc->re_flags |= RE_F_TIMER_INTR;
2312d4d77345SSepherosa Ziehau }
2313d4d77345SSepherosa Ziehau 
2314d4d77345SSepherosa Ziehau static void
re_disable_sim_im(struct re_softc * sc)2315d4d77345SSepherosa Ziehau re_disable_sim_im(struct re_softc *sc)
2316d4d77345SSepherosa Ziehau {
2317d4d77345SSepherosa Ziehau 	CSR_WRITE_4(sc, RE_TIMERINT, 0);
2318d4d77345SSepherosa Ziehau 	sc->re_flags &= ~RE_F_TIMER_INTR;
2319d4d77345SSepherosa Ziehau }
2320d4d77345SSepherosa Ziehau 
2321d4d77345SSepherosa Ziehau static void
re_config_imtype(struct re_softc * sc,int imtype)2322d4d77345SSepherosa Ziehau re_config_imtype(struct re_softc *sc, int imtype)
2323d4d77345SSepherosa Ziehau {
2324d4d77345SSepherosa Ziehau 	switch (imtype) {
2325d4d77345SSepherosa Ziehau 	case RE_IMTYPE_HW:
2326d4d77345SSepherosa Ziehau 		KKASSERT(sc->re_caps & RE_C_HWIM);
2327d4d77345SSepherosa Ziehau 		/* FALL THROUGH */
2328d4d77345SSepherosa Ziehau 	case RE_IMTYPE_NONE:
2329d4d77345SSepherosa Ziehau 		sc->re_intrs = RE_INTRS;
2330d4d77345SSepherosa Ziehau 		sc->re_rx_ack = RE_ISR_RX_OK | RE_ISR_FIFO_OFLOW |
2331d4d77345SSepherosa Ziehau 				RE_ISR_RX_OVERRUN;
2332d4d77345SSepherosa Ziehau 		sc->re_tx_ack = RE_ISR_TX_OK;
2333d4d77345SSepherosa Ziehau 		break;
2334d4d77345SSepherosa Ziehau 
2335d4d77345SSepherosa Ziehau 	case RE_IMTYPE_SIM:
2336d4d77345SSepherosa Ziehau 		sc->re_intrs = RE_INTRS_TIMER;
2337e5a5a436SSepherosa Ziehau 		sc->re_rx_ack = RE_ISR_PCS_TIMEOUT;
2338e5a5a436SSepherosa Ziehau 		sc->re_tx_ack = RE_ISR_PCS_TIMEOUT;
2339d4d77345SSepherosa Ziehau 		break;
2340d4d77345SSepherosa Ziehau 
2341d4d77345SSepherosa Ziehau 	default:
2342ed20d0e3SSascha Wildner 		panic("%s: unknown imtype %d",
2343d4d77345SSepherosa Ziehau 		      sc->arpcom.ac_if.if_xname, imtype);
2344d4d77345SSepherosa Ziehau 	}
2345d4d77345SSepherosa Ziehau }
2346d4d77345SSepherosa Ziehau 
2347d4d77345SSepherosa Ziehau static void
re_setup_intr(struct re_softc * sc,int enable_intrs,int imtype)2348d4d77345SSepherosa Ziehau re_setup_intr(struct re_softc *sc, int enable_intrs, int imtype)
2349d4d77345SSepherosa Ziehau {
2350d4d77345SSepherosa Ziehau 	re_config_imtype(sc, imtype);
2351d4d77345SSepherosa Ziehau 
2352d4d77345SSepherosa Ziehau 	if (enable_intrs)
235380492964SSepherosa Ziehau 		sc->re_write_imr(sc, sc->re_intrs);
2354d4d77345SSepherosa Ziehau 	else
235580492964SSepherosa Ziehau 		sc->re_write_imr(sc, 0);
2356d4d77345SSepherosa Ziehau 
23577816ba83SSepherosa Ziehau 	sc->re_npoll.ifpc_stcount = 0;
23587816ba83SSepherosa Ziehau 
2359d4d77345SSepherosa Ziehau 	switch (imtype) {
2360d4d77345SSepherosa Ziehau 	case RE_IMTYPE_NONE:
2361d4d77345SSepherosa Ziehau 		re_disable_sim_im(sc);
2362d4d77345SSepherosa Ziehau 		re_disable_hw_im(sc);
2363d4d77345SSepherosa Ziehau 		break;
2364d4d77345SSepherosa Ziehau 
2365d4d77345SSepherosa Ziehau 	case RE_IMTYPE_HW:
2366d4d77345SSepherosa Ziehau 		KKASSERT(sc->re_caps & RE_C_HWIM);
2367d4d77345SSepherosa Ziehau 		re_disable_sim_im(sc);
2368d4d77345SSepherosa Ziehau 		re_setup_hw_im(sc);
2369d4d77345SSepherosa Ziehau 		break;
2370d4d77345SSepherosa Ziehau 
2371d4d77345SSepherosa Ziehau 	case RE_IMTYPE_SIM:
2372d4d77345SSepherosa Ziehau 		re_disable_hw_im(sc);
2373d4d77345SSepherosa Ziehau 		re_setup_sim_im(sc);
2374d4d77345SSepherosa Ziehau 		break;
2375d4d77345SSepherosa Ziehau 
2376d4d77345SSepherosa Ziehau 	default:
2377ed20d0e3SSascha Wildner 		panic("%s: unknown imtype %d",
2378d4d77345SSepherosa Ziehau 		      sc->arpcom.ac_if.if_xname, imtype);
2379d4d77345SSepherosa Ziehau 	}
2380d4d77345SSepherosa Ziehau }
238102758a92SSepherosa Ziehau 
2382a7d57e62SSepherosa Ziehau static int
re_jpool_alloc(struct re_softc * sc)2383a7d57e62SSepherosa Ziehau re_jpool_alloc(struct re_softc *sc)
2384a7d57e62SSepherosa Ziehau {
2385a7d57e62SSepherosa Ziehau 	struct re_list_data *ldata = &sc->re_ldata;
2386a7d57e62SSepherosa Ziehau 	struct re_jbuf *jbuf;
2387a7d57e62SSepherosa Ziehau 	bus_addr_t paddr;
2388a7d57e62SSepherosa Ziehau 	bus_size_t jpool_size;
23890336fbc8SSepherosa Ziehau 	bus_dmamem_t dmem;
2390a7d57e62SSepherosa Ziehau 	caddr_t buf;
2391a7d57e62SSepherosa Ziehau 	int i, error;
2392a7d57e62SSepherosa Ziehau 
2393a7d57e62SSepherosa Ziehau 	lwkt_serialize_init(&ldata->re_jbuf_serializer);
2394a7d57e62SSepherosa Ziehau 
2395a7d57e62SSepherosa Ziehau 	ldata->re_jbuf = kmalloc(sizeof(struct re_jbuf) * RE_JBUF_COUNT(sc),
2396a7d57e62SSepherosa Ziehau 				 M_DEVBUF, M_WAITOK | M_ZERO);
2397a7d57e62SSepherosa Ziehau 
2398a7d57e62SSepherosa Ziehau 	jpool_size = RE_JBUF_COUNT(sc) * RE_JBUF_SIZE;
2399a7d57e62SSepherosa Ziehau 
24000336fbc8SSepherosa Ziehau 	error = bus_dmamem_coherent(sc->re_parent_tag,
24010336fbc8SSepherosa Ziehau 			RE_RXBUF_ALIGN, 0,
24020336fbc8SSepherosa Ziehau 			BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR,
24030336fbc8SSepherosa Ziehau 			jpool_size, BUS_DMA_WAITOK, &dmem);
2404a7d57e62SSepherosa Ziehau 	if (error) {
2405e5a5a436SSepherosa Ziehau 		device_printf(sc->dev, "could not allocate jumbo memory\n");
2406a7d57e62SSepherosa Ziehau 		return error;
2407a7d57e62SSepherosa Ziehau 	}
24080336fbc8SSepherosa Ziehau 	ldata->re_jpool_tag = dmem.dmem_tag;
24090336fbc8SSepherosa Ziehau 	ldata->re_jpool_map = dmem.dmem_map;
24100336fbc8SSepherosa Ziehau 	ldata->re_jpool = dmem.dmem_addr;
24110336fbc8SSepherosa Ziehau 	paddr = dmem.dmem_busaddr;
2412a7d57e62SSepherosa Ziehau 
2413a7d57e62SSepherosa Ziehau 	/* ..and split it into 9KB chunks */
2414a7d57e62SSepherosa Ziehau 	SLIST_INIT(&ldata->re_jbuf_free);
2415a7d57e62SSepherosa Ziehau 
2416a7d57e62SSepherosa Ziehau 	buf = ldata->re_jpool;
2417a7d57e62SSepherosa Ziehau 	for (i = 0; i < RE_JBUF_COUNT(sc); i++) {
2418a7d57e62SSepherosa Ziehau 		jbuf = &ldata->re_jbuf[i];
2419a7d57e62SSepherosa Ziehau 
2420a7d57e62SSepherosa Ziehau 		jbuf->re_sc = sc;
2421a7d57e62SSepherosa Ziehau 		jbuf->re_inuse = 0;
2422a7d57e62SSepherosa Ziehau 		jbuf->re_slot = i;
2423a7d57e62SSepherosa Ziehau 		jbuf->re_buf = buf;
2424a7d57e62SSepherosa Ziehau 		jbuf->re_paddr = paddr;
2425a7d57e62SSepherosa Ziehau 
2426a7d57e62SSepherosa Ziehau 		SLIST_INSERT_HEAD(&ldata->re_jbuf_free, jbuf, re_link);
2427a7d57e62SSepherosa Ziehau 
2428a7d57e62SSepherosa Ziehau 		buf += RE_JBUF_SIZE;
2429a7d57e62SSepherosa Ziehau 		paddr += RE_JBUF_SIZE;
2430a7d57e62SSepherosa Ziehau 	}
2431a7d57e62SSepherosa Ziehau 	return 0;
2432a7d57e62SSepherosa Ziehau }
2433a7d57e62SSepherosa Ziehau 
2434a7d57e62SSepherosa Ziehau static void
re_jpool_free(struct re_softc * sc)2435a7d57e62SSepherosa Ziehau re_jpool_free(struct re_softc *sc)
2436a7d57e62SSepherosa Ziehau {
2437a7d57e62SSepherosa Ziehau 	struct re_list_data *ldata = &sc->re_ldata;
2438a7d57e62SSepherosa Ziehau 
2439a7d57e62SSepherosa Ziehau 	if (ldata->re_jpool_tag != NULL) {
2440a7d57e62SSepherosa Ziehau 		bus_dmamap_unload(ldata->re_jpool_tag, ldata->re_jpool_map);
2441a7d57e62SSepherosa Ziehau 		bus_dmamem_free(ldata->re_jpool_tag, ldata->re_jpool,
2442a7d57e62SSepherosa Ziehau 				ldata->re_jpool_map);
2443a7d57e62SSepherosa Ziehau 		bus_dma_tag_destroy(ldata->re_jpool_tag);
2444a7d57e62SSepherosa Ziehau 		ldata->re_jpool_tag = NULL;
2445a7d57e62SSepherosa Ziehau 	}
2446a7d57e62SSepherosa Ziehau 
2447a7d57e62SSepherosa Ziehau 	if (ldata->re_jbuf != NULL) {
2448a7d57e62SSepherosa Ziehau 		kfree(ldata->re_jbuf, M_DEVBUF);
2449a7d57e62SSepherosa Ziehau 		ldata->re_jbuf = NULL;
2450a7d57e62SSepherosa Ziehau 	}
2451a7d57e62SSepherosa Ziehau }
2452a7d57e62SSepherosa Ziehau 
2453e5a5a436SSepherosa Ziehau #ifdef RE_JUMBO
2454a7d57e62SSepherosa Ziehau static struct re_jbuf *
re_jbuf_alloc(struct re_softc * sc)2455a7d57e62SSepherosa Ziehau re_jbuf_alloc(struct re_softc *sc)
2456a7d57e62SSepherosa Ziehau {
2457a7d57e62SSepherosa Ziehau 	struct re_list_data *ldata = &sc->re_ldata;
2458a7d57e62SSepherosa Ziehau 	struct re_jbuf *jbuf;
2459a7d57e62SSepherosa Ziehau 
2460a7d57e62SSepherosa Ziehau 	lwkt_serialize_enter(&ldata->re_jbuf_serializer);
2461a7d57e62SSepherosa Ziehau 
2462a7d57e62SSepherosa Ziehau 	jbuf = SLIST_FIRST(&ldata->re_jbuf_free);
2463a7d57e62SSepherosa Ziehau 	if (jbuf != NULL) {
2464a7d57e62SSepherosa Ziehau 		SLIST_REMOVE_HEAD(&ldata->re_jbuf_free, re_link);
2465a7d57e62SSepherosa Ziehau 		jbuf->re_inuse = 1;
2466a7d57e62SSepherosa Ziehau 	}
2467a7d57e62SSepherosa Ziehau 
2468a7d57e62SSepherosa Ziehau 	lwkt_serialize_exit(&ldata->re_jbuf_serializer);
2469a7d57e62SSepherosa Ziehau 
2470a7d57e62SSepherosa Ziehau 	return jbuf;
2471a7d57e62SSepherosa Ziehau }
2472a7d57e62SSepherosa Ziehau 
2473a7d57e62SSepherosa Ziehau static void
re_jbuf_free(void * arg)2474a7d57e62SSepherosa Ziehau re_jbuf_free(void *arg)
2475a7d57e62SSepherosa Ziehau {
2476a7d57e62SSepherosa Ziehau 	struct re_jbuf *jbuf = arg;
2477a7d57e62SSepherosa Ziehau 	struct re_softc *sc = jbuf->re_sc;
2478a7d57e62SSepherosa Ziehau 	struct re_list_data *ldata = &sc->re_ldata;
2479a7d57e62SSepherosa Ziehau 
2480a7d57e62SSepherosa Ziehau 	if (&ldata->re_jbuf[jbuf->re_slot] != jbuf) {
2481ed20d0e3SSascha Wildner 		panic("%s: free wrong jumbo buffer",
2482a7d57e62SSepherosa Ziehau 		      sc->arpcom.ac_if.if_xname);
2483a7d57e62SSepherosa Ziehau 	} else if (jbuf->re_inuse == 0) {
2484ed20d0e3SSascha Wildner 		panic("%s: jumbo buffer already freed",
2485a7d57e62SSepherosa Ziehau 		      sc->arpcom.ac_if.if_xname);
2486a7d57e62SSepherosa Ziehau 	}
2487a7d57e62SSepherosa Ziehau 
2488a7d57e62SSepherosa Ziehau 	lwkt_serialize_enter(&ldata->re_jbuf_serializer);
2489a7d57e62SSepherosa Ziehau 	atomic_subtract_int(&jbuf->re_inuse, 1);
2490a7d57e62SSepherosa Ziehau 	if (jbuf->re_inuse == 0)
2491a7d57e62SSepherosa Ziehau 		SLIST_INSERT_HEAD(&ldata->re_jbuf_free, jbuf, re_link);
2492a7d57e62SSepherosa Ziehau 	lwkt_serialize_exit(&ldata->re_jbuf_serializer);
2493a7d57e62SSepherosa Ziehau }
2494a7d57e62SSepherosa Ziehau 
2495a7d57e62SSepherosa Ziehau static void
re_jbuf_ref(void * arg)2496a7d57e62SSepherosa Ziehau re_jbuf_ref(void *arg)
2497a7d57e62SSepherosa Ziehau {
2498a7d57e62SSepherosa Ziehau 	struct re_jbuf *jbuf = arg;
2499a7d57e62SSepherosa Ziehau 	struct re_softc *sc = jbuf->re_sc;
2500a7d57e62SSepherosa Ziehau 	struct re_list_data *ldata = &sc->re_ldata;
2501a7d57e62SSepherosa Ziehau 
2502a7d57e62SSepherosa Ziehau 	if (&ldata->re_jbuf[jbuf->re_slot] != jbuf) {
2503ed20d0e3SSascha Wildner 		panic("%s: ref wrong jumbo buffer",
2504a7d57e62SSepherosa Ziehau 		      sc->arpcom.ac_if.if_xname);
2505a7d57e62SSepherosa Ziehau 	} else if (jbuf->re_inuse == 0) {
2506ed20d0e3SSascha Wildner 		panic("%s: jumbo buffer already freed",
2507a7d57e62SSepherosa Ziehau 		      sc->arpcom.ac_if.if_xname);
2508a7d57e62SSepherosa Ziehau 	}
2509a7d57e62SSepherosa Ziehau 	atomic_add_int(&jbuf->re_inuse, 1);
2510a7d57e62SSepherosa Ziehau }
2511e5a5a436SSepherosa Ziehau #endif	/* RE_JUMBO */
2512d7c373a4SSepherosa Ziehau 
2513d7c373a4SSepherosa Ziehau static void
re_disable_aspm(device_t dev)2514d7c373a4SSepherosa Ziehau re_disable_aspm(device_t dev)
2515d7c373a4SSepherosa Ziehau {
2516d7c373a4SSepherosa Ziehau 	uint16_t link_cap, link_ctrl;
2517d7c373a4SSepherosa Ziehau 	uint8_t pcie_ptr, reg;
2518d7c373a4SSepherosa Ziehau 
2519d7c373a4SSepherosa Ziehau 	pcie_ptr = pci_get_pciecap_ptr(dev);
2520d7c373a4SSepherosa Ziehau 	if (pcie_ptr == 0)
2521d7c373a4SSepherosa Ziehau 		return;
2522d7c373a4SSepherosa Ziehau 
2523d7c373a4SSepherosa Ziehau 	link_cap = pci_read_config(dev, pcie_ptr + PCIER_LINKCAP, 2);
2524d7c373a4SSepherosa Ziehau 	if ((link_cap & PCIEM_LNKCAP_ASPM_MASK) == 0)
2525d7c373a4SSepherosa Ziehau 		return;
2526d7c373a4SSepherosa Ziehau 
2527d7c373a4SSepherosa Ziehau 	if (bootverbose)
2528d7c373a4SSepherosa Ziehau 		device_printf(dev, "disable ASPM\n");
2529d7c373a4SSepherosa Ziehau 
2530d7c373a4SSepherosa Ziehau 	reg = pcie_ptr + PCIER_LINKCTRL;
2531d7c373a4SSepherosa Ziehau 	link_ctrl = pci_read_config(dev, reg, 2);
2532d7c373a4SSepherosa Ziehau 	link_ctrl &= ~(PCIEM_LNKCTL_ASPM_L0S | PCIEM_LNKCTL_ASPM_L1);
2533d7c373a4SSepherosa Ziehau 	pci_write_config(dev, reg, link_ctrl, 2);
2534d7c373a4SSepherosa Ziehau }
253580492964SSepherosa Ziehau 
253680492964SSepherosa Ziehau static void
re_start_xmit(struct re_softc * sc)253780492964SSepherosa Ziehau re_start_xmit(struct re_softc *sc)
253880492964SSepherosa Ziehau {
253980492964SSepherosa Ziehau 	CSR_WRITE_1(sc, RE_TPPOLL, RE_NPQ);
254080492964SSepherosa Ziehau }
254180492964SSepherosa Ziehau 
254280492964SSepherosa Ziehau static void
re_write_imr(struct re_softc * sc,uint32_t val)254380492964SSepherosa Ziehau re_write_imr(struct re_softc *sc, uint32_t val)
254480492964SSepherosa Ziehau {
254580492964SSepherosa Ziehau 	CSR_WRITE_2(sc, RE_IMR, val);
254680492964SSepherosa Ziehau }
254780492964SSepherosa Ziehau 
254880492964SSepherosa Ziehau static void
re_write_isr(struct re_softc * sc,uint32_t val)254980492964SSepherosa Ziehau re_write_isr(struct re_softc *sc, uint32_t val)
255080492964SSepherosa Ziehau {
255180492964SSepherosa Ziehau 	CSR_WRITE_2(sc, RE_ISR, val);
255280492964SSepherosa Ziehau }
255380492964SSepherosa Ziehau 
255480492964SSepherosa Ziehau static uint32_t
re_read_isr(struct re_softc * sc)255580492964SSepherosa Ziehau re_read_isr(struct re_softc *sc)
255680492964SSepherosa Ziehau {
255780492964SSepherosa Ziehau 	return CSR_READ_2(sc, RE_ISR);
255880492964SSepherosa Ziehau }
255980492964SSepherosa Ziehau 
256080492964SSepherosa Ziehau static void
re_start_xmit_8125(struct re_softc * sc)256180492964SSepherosa Ziehau re_start_xmit_8125(struct re_softc *sc)
256280492964SSepherosa Ziehau {
256380492964SSepherosa Ziehau 	CSR_WRITE_2(sc, RE_TPPOLL_8125, RE_NPQ_8125);
256480492964SSepherosa Ziehau }
256580492964SSepherosa Ziehau 
256680492964SSepherosa Ziehau static void
re_write_imr_8125(struct re_softc * sc,uint32_t val)256780492964SSepherosa Ziehau re_write_imr_8125(struct re_softc *sc, uint32_t val)
256880492964SSepherosa Ziehau {
256980492964SSepherosa Ziehau 	CSR_WRITE_4(sc, RE_IMR0_8125, val);
257080492964SSepherosa Ziehau }
257180492964SSepherosa Ziehau 
257280492964SSepherosa Ziehau static void
re_write_isr_8125(struct re_softc * sc,uint32_t val)257380492964SSepherosa Ziehau re_write_isr_8125(struct re_softc *sc, uint32_t val)
257480492964SSepherosa Ziehau {
257580492964SSepherosa Ziehau 	CSR_WRITE_4(sc, RE_ISR0_8125, val);
257680492964SSepherosa Ziehau }
257780492964SSepherosa Ziehau 
257880492964SSepherosa Ziehau static uint32_t
re_read_isr_8125(struct re_softc * sc)257980492964SSepherosa Ziehau re_read_isr_8125(struct re_softc *sc)
258080492964SSepherosa Ziehau {
258180492964SSepherosa Ziehau 	return CSR_READ_4(sc, RE_ISR0_8125);
258280492964SSepherosa Ziehau }
2583