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