if_nfe.c revision 266270
1159967Sobrien/*	$OpenBSD: if_nfe.c,v 1.54 2006/04/07 12:38:12 jsg Exp $	*/
2159952Sobrien
3159952Sobrien/*-
4159967Sobrien * Copyright (c) 2006 Shigeaki Tagashira <shigeaki@se.hiroshima-u.ac.jp>
5159952Sobrien * Copyright (c) 2006 Damien Bergamini <damien.bergamini@free.fr>
6159952Sobrien * Copyright (c) 2005, 2006 Jonathan Gray <jsg@openbsd.org>
7159952Sobrien *
8159952Sobrien * Permission to use, copy, modify, and distribute this software for any
9159952Sobrien * purpose with or without fee is hereby granted, provided that the above
10159952Sobrien * copyright notice and this permission notice appear in all copies.
11159952Sobrien *
12159952Sobrien * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13159952Sobrien * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14159952Sobrien * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15159952Sobrien * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16159952Sobrien * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17159952Sobrien * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18159952Sobrien * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19159952Sobrien */
20159952Sobrien
21159952Sobrien/* Driver for NVIDIA nForce MCP Fast Ethernet and Gigabit Ethernet */
22159952Sobrien
23159967Sobrien#include <sys/cdefs.h>
24159967Sobrien__FBSDID("$FreeBSD: head/sys/dev/nfe/if_nfe.c 266270 2014-05-16 21:19:17Z brueffer $");
25159952Sobrien
26159967Sobrien#ifdef HAVE_KERNEL_OPTION_HEADERS
27159967Sobrien#include "opt_device_polling.h"
28159967Sobrien#endif
29159967Sobrien
30159952Sobrien#include <sys/param.h>
31159952Sobrien#include <sys/endian.h>
32159952Sobrien#include <sys/systm.h>
33159952Sobrien#include <sys/sockio.h>
34159952Sobrien#include <sys/mbuf.h>
35159952Sobrien#include <sys/malloc.h>
36159967Sobrien#include <sys/module.h>
37159952Sobrien#include <sys/kernel.h>
38170589Syongari#include <sys/queue.h>
39159952Sobrien#include <sys/socket.h>
40170589Syongari#include <sys/sysctl.h>
41159967Sobrien#include <sys/taskqueue.h>
42159952Sobrien
43159952Sobrien#include <net/if.h>
44257176Sglebius#include <net/if_var.h>
45159967Sobrien#include <net/if_arp.h>
46159967Sobrien#include <net/ethernet.h>
47159952Sobrien#include <net/if_dl.h>
48159952Sobrien#include <net/if_media.h>
49159952Sobrien#include <net/if_types.h>
50159952Sobrien#include <net/if_vlan_var.h>
51159952Sobrien
52159952Sobrien#include <net/bpf.h>
53159952Sobrien
54159967Sobrien#include <machine/bus.h>
55159967Sobrien#include <machine/resource.h>
56159967Sobrien#include <sys/bus.h>
57159967Sobrien#include <sys/rman.h>
58159967Sobrien
59159952Sobrien#include <dev/mii/mii.h>
60159952Sobrien#include <dev/mii/miivar.h>
61159952Sobrien
62159952Sobrien#include <dev/pci/pcireg.h>
63159952Sobrien#include <dev/pci/pcivar.h>
64159952Sobrien
65159967Sobrien#include <dev/nfe/if_nfereg.h>
66159967Sobrien#include <dev/nfe/if_nfevar.h>
67159952Sobrien
68159967SobrienMODULE_DEPEND(nfe, pci, 1, 1, 1);
69159967SobrienMODULE_DEPEND(nfe, ether, 1, 1, 1);
70159967SobrienMODULE_DEPEND(nfe, miibus, 1, 1, 1);
71170589Syongari
72170589Syongari/* "device miibus" required.  See GENERIC if you get errors here. */
73159967Sobrien#include "miibus_if.h"
74159952Sobrien
75163503Sobrienstatic int  nfe_probe(device_t);
76163503Sobrienstatic int  nfe_attach(device_t);
77163503Sobrienstatic int  nfe_detach(device_t);
78170589Syongaristatic int  nfe_suspend(device_t);
79170589Syongaristatic int  nfe_resume(device_t);
80173839Syongaristatic int nfe_shutdown(device_t);
81215327Syongaristatic int  nfe_can_use_msix(struct nfe_softc *);
82264293Syongaristatic int  nfe_detect_msik9(struct nfe_softc *);
83170589Syongaristatic void nfe_power(struct nfe_softc *);
84163503Sobrienstatic int  nfe_miibus_readreg(device_t, int, int);
85163503Sobrienstatic int  nfe_miibus_writereg(device_t, int, int, int);
86163503Sobrienstatic void nfe_miibus_statchg(device_t);
87215132Syongaristatic void nfe_mac_config(struct nfe_softc *, struct mii_data *);
88170589Syongaristatic void nfe_set_intr(struct nfe_softc *);
89170589Syongaristatic __inline void nfe_enable_intr(struct nfe_softc *);
90170589Syongaristatic __inline void nfe_disable_intr(struct nfe_softc *);
91163503Sobrienstatic int  nfe_ioctl(struct ifnet *, u_long, caddr_t);
92170589Syongaristatic void nfe_alloc_msix(struct nfe_softc *, int);
93170589Syongaristatic int nfe_intr(void *);
94170589Syongaristatic void nfe_int_task(void *, int);
95170589Syongaristatic __inline void nfe_discard_rxbuf(struct nfe_softc *, int);
96170589Syongaristatic __inline void nfe_discard_jrxbuf(struct nfe_softc *, int);
97170589Syongaristatic int nfe_newbuf(struct nfe_softc *, int);
98170589Syongaristatic int nfe_jnewbuf(struct nfe_softc *, int);
99193096Sattiliostatic int  nfe_rxeof(struct nfe_softc *, int, int *);
100193096Sattiliostatic int  nfe_jrxeof(struct nfe_softc *, int, int *);
101159967Sobrienstatic void nfe_txeof(struct nfe_softc *);
102170589Syongaristatic int  nfe_encap(struct nfe_softc *, struct mbuf **);
103159967Sobrienstatic void nfe_setmulti(struct nfe_softc *);
104159967Sobrienstatic void nfe_start(struct ifnet *);
105216925Sjhbstatic void nfe_start_locked(struct ifnet *);
106159967Sobrienstatic void nfe_watchdog(struct ifnet *);
107159967Sobrienstatic void nfe_init(void *);
108159967Sobrienstatic void nfe_init_locked(void *);
109170589Syongaristatic void nfe_stop(struct ifnet *);
110159967Sobrienstatic int  nfe_alloc_rx_ring(struct nfe_softc *, struct nfe_rx_ring *);
111171559Syongaristatic void nfe_alloc_jrx_ring(struct nfe_softc *, struct nfe_jrx_ring *);
112170589Syongaristatic int  nfe_init_rx_ring(struct nfe_softc *, struct nfe_rx_ring *);
113170589Syongaristatic int  nfe_init_jrx_ring(struct nfe_softc *, struct nfe_jrx_ring *);
114159967Sobrienstatic void nfe_free_rx_ring(struct nfe_softc *, struct nfe_rx_ring *);
115170589Syongaristatic void nfe_free_jrx_ring(struct nfe_softc *, struct nfe_jrx_ring *);
116159967Sobrienstatic int  nfe_alloc_tx_ring(struct nfe_softc *, struct nfe_tx_ring *);
117170589Syongaristatic void nfe_init_tx_ring(struct nfe_softc *, struct nfe_tx_ring *);
118159967Sobrienstatic void nfe_free_tx_ring(struct nfe_softc *, struct nfe_tx_ring *);
119159967Sobrienstatic int  nfe_ifmedia_upd(struct ifnet *);
120159967Sobrienstatic void nfe_ifmedia_sts(struct ifnet *, struct ifmediareq *);
121159967Sobrienstatic void nfe_tick(void *);
122170589Syongaristatic void nfe_get_macaddr(struct nfe_softc *, uint8_t *);
123170589Syongaristatic void nfe_set_macaddr(struct nfe_softc *, uint8_t *);
124170589Syongaristatic void nfe_dma_map_segs(void *, bus_dma_segment_t *, int, int);
125159952Sobrien
126170589Syongaristatic int sysctl_int_range(SYSCTL_HANDLER_ARGS, int, int);
127170589Syongaristatic int sysctl_hw_nfe_proc_limit(SYSCTL_HANDLER_ARGS);
128183561Syongaristatic void nfe_sysctl_node(struct nfe_softc *);
129183561Syongaristatic void nfe_stats_clear(struct nfe_softc *);
130183561Syongaristatic void nfe_stats_update(struct nfe_softc *);
131215132Syongaristatic void nfe_set_linkspeed(struct nfe_softc *);
132215132Syongaristatic void nfe_set_wol(struct nfe_softc *);
133170589Syongari
134159952Sobrien#ifdef NFE_DEBUG
135170589Syongaristatic int nfedebug = 0;
136170589Syongari#define	DPRINTF(sc, ...)	do {				\
137170589Syongari	if (nfedebug)						\
138170589Syongari		device_printf((sc)->nfe_dev, __VA_ARGS__);	\
139170589Syongari} while (0)
140170589Syongari#define	DPRINTFN(sc, n, ...)	do {				\
141170589Syongari	if (nfedebug >= (n))					\
142170589Syongari		device_printf((sc)->nfe_dev, __VA_ARGS__);	\
143170589Syongari} while (0)
144159952Sobrien#else
145170589Syongari#define	DPRINTF(sc, ...)
146170589Syongari#define	DPRINTFN(sc, n, ...)
147159952Sobrien#endif
148159952Sobrien
149159967Sobrien#define	NFE_LOCK(_sc)		mtx_lock(&(_sc)->nfe_mtx)
150159967Sobrien#define	NFE_UNLOCK(_sc)		mtx_unlock(&(_sc)->nfe_mtx)
151159967Sobrien#define	NFE_LOCK_ASSERT(_sc)	mtx_assert(&(_sc)->nfe_mtx, MA_OWNED)
152159967Sobrien
153170589Syongari/* Tunables. */
154170589Syongaristatic int msi_disable = 0;
155170589Syongaristatic int msix_disable = 0;
156171559Syongaristatic int jumbo_disable = 0;
157170589SyongariTUNABLE_INT("hw.nfe.msi_disable", &msi_disable);
158170589SyongariTUNABLE_INT("hw.nfe.msix_disable", &msix_disable);
159171559SyongariTUNABLE_INT("hw.nfe.jumbo_disable", &jumbo_disable);
160159967Sobrien
161159967Sobrienstatic device_method_t nfe_methods[] = {
162159967Sobrien	/* Device interface */
163159967Sobrien	DEVMETHOD(device_probe,		nfe_probe),
164159967Sobrien	DEVMETHOD(device_attach,	nfe_attach),
165159967Sobrien	DEVMETHOD(device_detach,	nfe_detach),
166170589Syongari	DEVMETHOD(device_suspend,	nfe_suspend),
167170589Syongari	DEVMETHOD(device_resume,	nfe_resume),
168159967Sobrien	DEVMETHOD(device_shutdown,	nfe_shutdown),
169159967Sobrien
170159967Sobrien	/* MII interface */
171159967Sobrien	DEVMETHOD(miibus_readreg,	nfe_miibus_readreg),
172159967Sobrien	DEVMETHOD(miibus_writereg,	nfe_miibus_writereg),
173163503Sobrien	DEVMETHOD(miibus_statchg,	nfe_miibus_statchg),
174159967Sobrien
175227843Smarius	DEVMETHOD_END
176159952Sobrien};
177159952Sobrien
178159967Sobrienstatic driver_t nfe_driver = {
179159967Sobrien	"nfe",
180159967Sobrien	nfe_methods,
181159967Sobrien	sizeof(struct nfe_softc)
182159967Sobrien};
183159967Sobrien
184159967Sobrienstatic devclass_t nfe_devclass;
185159967Sobrien
186159967SobrienDRIVER_MODULE(nfe, pci, nfe_driver, nfe_devclass, 0, 0);
187159967SobrienDRIVER_MODULE(miibus, nfe, miibus_driver, miibus_devclass, 0, 0);
188159967Sobrien
189159967Sobrienstatic struct nfe_type nfe_devs[] = {
190159967Sobrien	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE_LAN,
191163503Sobrien	    "NVIDIA nForce MCP Networking Adapter"},
192159967Sobrien	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE2_LAN,
193163503Sobrien	    "NVIDIA nForce2 MCP2 Networking Adapter"},
194159967Sobrien	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE2_400_LAN1,
195163503Sobrien	    "NVIDIA nForce2 400 MCP4 Networking Adapter"},
196159967Sobrien	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE2_400_LAN2,
197163503Sobrien	    "NVIDIA nForce2 400 MCP5 Networking Adapter"},
198163437Sobrien	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE3_LAN1,
199163503Sobrien	    "NVIDIA nForce3 MCP3 Networking Adapter"},
200159967Sobrien	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE3_250_LAN,
201163503Sobrien	    "NVIDIA nForce3 250 MCP6 Networking Adapter"},
202159967Sobrien	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE3_LAN4,
203163503Sobrien	    "NVIDIA nForce3 MCP7 Networking Adapter"},
204159967Sobrien	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE4_LAN1,
205163503Sobrien	    "NVIDIA nForce4 CK804 MCP8 Networking Adapter"},
206159967Sobrien	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE4_LAN2,
207163503Sobrien	    "NVIDIA nForce4 CK804 MCP9 Networking Adapter"},
208159967Sobrien	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP04_LAN1,
209170589Syongari	    "NVIDIA nForce MCP04 Networking Adapter"},		/* MCP10 */
210159967Sobrien	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP04_LAN2,
211170589Syongari	    "NVIDIA nForce MCP04 Networking Adapter"},		/* MCP11 */
212159967Sobrien	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE430_LAN1,
213163503Sobrien	    "NVIDIA nForce 430 MCP12 Networking Adapter"},
214159967Sobrien	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE430_LAN2,
215163503Sobrien	    "NVIDIA nForce 430 MCP13 Networking Adapter"},
216159967Sobrien	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP55_LAN1,
217163503Sobrien	    "NVIDIA nForce MCP55 Networking Adapter"},
218159967Sobrien	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP55_LAN2,
219163503Sobrien	    "NVIDIA nForce MCP55 Networking Adapter"},
220162212Sobrien	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP61_LAN1,
221163503Sobrien	    "NVIDIA nForce MCP61 Networking Adapter"},
222162212Sobrien	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP61_LAN2,
223163503Sobrien	    "NVIDIA nForce MCP61 Networking Adapter"},
224162212Sobrien	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP61_LAN3,
225163503Sobrien	    "NVIDIA nForce MCP61 Networking Adapter"},
226170589Syongari	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP61_LAN4,
227163503Sobrien	    "NVIDIA nForce MCP61 Networking Adapter"},
228162212Sobrien	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP65_LAN1,
229163503Sobrien	    "NVIDIA nForce MCP65 Networking Adapter"},
230162212Sobrien	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP65_LAN2,
231163503Sobrien	    "NVIDIA nForce MCP65 Networking Adapter"},
232162212Sobrien	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP65_LAN3,
233163503Sobrien	    "NVIDIA nForce MCP65 Networking Adapter"},
234170589Syongari	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP65_LAN4,
235163503Sobrien	    "NVIDIA nForce MCP65 Networking Adapter"},
236170589Syongari	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP67_LAN1,
237170589Syongari	    "NVIDIA nForce MCP67 Networking Adapter"},
238170589Syongari	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP67_LAN2,
239170589Syongari	    "NVIDIA nForce MCP67 Networking Adapter"},
240170589Syongari	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP67_LAN3,
241170589Syongari	    "NVIDIA nForce MCP67 Networking Adapter"},
242170589Syongari	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP67_LAN4,
243170589Syongari	    "NVIDIA nForce MCP67 Networking Adapter"},
244178055Syongari	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP73_LAN1,
245178055Syongari	    "NVIDIA nForce MCP73 Networking Adapter"},
246178055Syongari	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP73_LAN2,
247178055Syongari	    "NVIDIA nForce MCP73 Networking Adapter"},
248178055Syongari	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP73_LAN3,
249178055Syongari	    "NVIDIA nForce MCP73 Networking Adapter"},
250178055Syongari	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP73_LAN4,
251178055Syongari	    "NVIDIA nForce MCP73 Networking Adapter"},
252183509Syongari	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP77_LAN1,
253183509Syongari	    "NVIDIA nForce MCP77 Networking Adapter"},
254183509Syongari	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP77_LAN2,
255183509Syongari	    "NVIDIA nForce MCP77 Networking Adapter"},
256183509Syongari	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP77_LAN3,
257183509Syongari	    "NVIDIA nForce MCP77 Networking Adapter"},
258183509Syongari	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP77_LAN4,
259183509Syongari	    "NVIDIA nForce MCP77 Networking Adapter"},
260183509Syongari	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP79_LAN1,
261183509Syongari	    "NVIDIA nForce MCP79 Networking Adapter"},
262183509Syongari	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP79_LAN2,
263183509Syongari	    "NVIDIA nForce MCP79 Networking Adapter"},
264183509Syongari	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP79_LAN3,
265183509Syongari	    "NVIDIA nForce MCP79 Networking Adapter"},
266183509Syongari	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP79_LAN4,
267183509Syongari	    "NVIDIA nForce MCP79 Networking Adapter"},
268159967Sobrien	{0, 0, NULL}
269159967Sobrien};
270159967Sobrien
271159967Sobrien
272159967Sobrien/* Probe for supported hardware ID's */
273159967Sobrienstatic int
274159967Sobriennfe_probe(device_t dev)
275159952Sobrien{
276159967Sobrien	struct nfe_type *t;
277159967Sobrien
278159967Sobrien	t = nfe_devs;
279159967Sobrien	/* Check for matching PCI DEVICE ID's */
280159967Sobrien	while (t->name != NULL) {
281159967Sobrien		if ((pci_get_vendor(dev) == t->vid_id) &&
282159967Sobrien		    (pci_get_device(dev) == t->dev_id)) {
283159967Sobrien			device_set_desc(dev, t->name);
284170589Syongari			return (BUS_PROBE_DEFAULT);
285159967Sobrien		}
286159967Sobrien		t++;
287159967Sobrien	}
288159967Sobrien
289159967Sobrien	return (ENXIO);
290159952Sobrien}
291159952Sobrien
292170589Syongaristatic void
293170589Syongarinfe_alloc_msix(struct nfe_softc *sc, int count)
294170589Syongari{
295170589Syongari	int rid;
296163503Sobrien
297170589Syongari	rid = PCIR_BAR(2);
298170589Syongari	sc->nfe_msix_res = bus_alloc_resource_any(sc->nfe_dev, SYS_RES_MEMORY,
299170589Syongari	    &rid, RF_ACTIVE);
300170589Syongari	if (sc->nfe_msix_res == NULL) {
301170589Syongari		device_printf(sc->nfe_dev,
302170589Syongari		    "couldn't allocate MSIX table resource\n");
303170589Syongari		return;
304170589Syongari	}
305170589Syongari	rid = PCIR_BAR(3);
306170589Syongari	sc->nfe_msix_pba_res = bus_alloc_resource_any(sc->nfe_dev,
307170589Syongari	    SYS_RES_MEMORY, &rid, RF_ACTIVE);
308170589Syongari	if (sc->nfe_msix_pba_res == NULL) {
309170589Syongari		device_printf(sc->nfe_dev,
310170589Syongari		    "couldn't allocate MSIX PBA resource\n");
311170589Syongari		bus_release_resource(sc->nfe_dev, SYS_RES_MEMORY, PCIR_BAR(2),
312170589Syongari		    sc->nfe_msix_res);
313170589Syongari		sc->nfe_msix_res = NULL;
314170589Syongari		return;
315170589Syongari	}
316170589Syongari
317170589Syongari	if (pci_alloc_msix(sc->nfe_dev, &count) == 0) {
318170589Syongari		if (count == NFE_MSI_MESSAGES) {
319170589Syongari			if (bootverbose)
320170589Syongari				device_printf(sc->nfe_dev,
321170589Syongari				    "Using %d MSIX messages\n", count);
322170589Syongari			sc->nfe_msix = 1;
323170589Syongari		} else {
324170589Syongari			if (bootverbose)
325170589Syongari				device_printf(sc->nfe_dev,
326170589Syongari				    "couldn't allocate MSIX\n");
327170589Syongari			pci_release_msi(sc->nfe_dev);
328170589Syongari			bus_release_resource(sc->nfe_dev, SYS_RES_MEMORY,
329170589Syongari			    PCIR_BAR(3), sc->nfe_msix_pba_res);
330170589Syongari			bus_release_resource(sc->nfe_dev, SYS_RES_MEMORY,
331170589Syongari			    PCIR_BAR(2), sc->nfe_msix_res);
332170589Syongari			sc->nfe_msix_pba_res = NULL;
333170589Syongari			sc->nfe_msix_res = NULL;
334170589Syongari		}
335170589Syongari	}
336170589Syongari}
337170589Syongari
338264293Syongari
339159967Sobrienstatic int
340264293Syongarinfe_detect_msik9(struct nfe_softc *sc)
341264293Syongari{
342264293Syongari	static const char *maker = "MSI";
343264293Syongari	static const char *product = "K9N6PGM2-V2 (MS-7309)";
344264293Syongari	char *m, *p;
345264293Syongari	int found;
346264293Syongari
347264293Syongari	found = 0;
348264293Syongari	m = getenv("smbios.planar.maker");
349264293Syongari	p = getenv("smbios.planar.product");
350264293Syongari	if (m != NULL && p != NULL) {
351264293Syongari		if (strcmp(m, maker) == 0 && strcmp(p, product) == 0)
352264293Syongari			found = 1;
353264293Syongari	}
354264293Syongari	if (m != NULL)
355264293Syongari		freeenv(m);
356264293Syongari	if (p != NULL)
357264293Syongari		freeenv(p);
358264293Syongari
359264293Syongari	return (found);
360264293Syongari}
361264293Syongari
362264293Syongari
363264293Syongaristatic int
364159967Sobriennfe_attach(device_t dev)
365159952Sobrien{
366159967Sobrien	struct nfe_softc *sc;
367159952Sobrien	struct ifnet *ifp;
368170589Syongari	bus_addr_t dma_addr_max;
369264293Syongari	int error = 0, i, msic, phyloc, reg, rid;
370159952Sobrien
371159967Sobrien	sc = device_get_softc(dev);
372159967Sobrien	sc->nfe_dev = dev;
373159952Sobrien
374159967Sobrien	mtx_init(&sc->nfe_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK,
375170589Syongari	    MTX_DEF);
376159967Sobrien	callout_init_mtx(&sc->nfe_stat_ch, &sc->nfe_mtx, 0);
377159967Sobrien
378163503Sobrien	pci_enable_busmaster(dev);
379159967Sobrien
380170589Syongari	rid = PCIR_BAR(0);
381170589Syongari	sc->nfe_res[0] = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
382170589Syongari	    RF_ACTIVE);
383170589Syongari	if (sc->nfe_res[0] == NULL) {
384170589Syongari		device_printf(dev, "couldn't map memory resources\n");
385170589Syongari		mtx_destroy(&sc->nfe_mtx);
386170589Syongari		return (ENXIO);
387170589Syongari	}
388159967Sobrien
389219902Sjhb	if (pci_find_cap(dev, PCIY_EXPRESS, &reg) == 0) {
390170589Syongari		uint16_t v, width;
391170589Syongari
392170589Syongari		v = pci_read_config(dev, reg + 0x08, 2);
393170589Syongari		/* Change max. read request size to 4096. */
394170589Syongari		v &= ~(7 << 12);
395170589Syongari		v |= (5 << 12);
396170589Syongari		pci_write_config(dev, reg + 0x08, v, 2);
397170589Syongari
398170589Syongari		v = pci_read_config(dev, reg + 0x0c, 2);
399170589Syongari		/* link capability */
400170589Syongari		v = (v >> 4) & 0x0f;
401170589Syongari		width = pci_read_config(dev, reg + 0x12, 2);
402170589Syongari		/* negotiated link width */
403170589Syongari		width = (width >> 4) & 0x3f;
404170589Syongari		if (v != width)
405170589Syongari			device_printf(sc->nfe_dev,
406170589Syongari			    "warning, negotiated width of link(x%d) != "
407170589Syongari			    "max. width of link(x%d)\n", width, v);
408159952Sobrien	}
409159952Sobrien
410215327Syongari	if (nfe_can_use_msix(sc) == 0) {
411215327Syongari		device_printf(sc->nfe_dev,
412215327Syongari		    "MSI/MSI-X capability black-listed, will use INTx\n");
413215327Syongari		msix_disable = 1;
414215327Syongari		msi_disable = 1;
415215327Syongari	}
416215327Syongari
417159967Sobrien	/* Allocate interrupt */
418170589Syongari	if (msix_disable == 0 || msi_disable == 0) {
419170589Syongari		if (msix_disable == 0 &&
420170589Syongari		    (msic = pci_msix_count(dev)) == NFE_MSI_MESSAGES)
421170589Syongari			nfe_alloc_msix(sc, msic);
422170589Syongari		if (msi_disable == 0 && sc->nfe_msix == 0 &&
423170589Syongari		    (msic = pci_msi_count(dev)) == NFE_MSI_MESSAGES &&
424170589Syongari		    pci_alloc_msi(dev, &msic) == 0) {
425170589Syongari			if (msic == NFE_MSI_MESSAGES) {
426170589Syongari				if (bootverbose)
427170589Syongari					device_printf(dev,
428170589Syongari					    "Using %d MSI messages\n", msic);
429170589Syongari				sc->nfe_msi = 1;
430170589Syongari			} else
431170589Syongari				pci_release_msi(dev);
432170589Syongari		}
433170589Syongari	}
434159967Sobrien
435170589Syongari	if (sc->nfe_msix == 0 && sc->nfe_msi == 0) {
436170589Syongari		rid = 0;
437170589Syongari		sc->nfe_irq[0] = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
438170589Syongari		    RF_SHAREABLE | RF_ACTIVE);
439170589Syongari		if (sc->nfe_irq[0] == NULL) {
440170589Syongari			device_printf(dev, "couldn't allocate IRQ resources\n");
441170589Syongari			error = ENXIO;
442170589Syongari			goto fail;
443170589Syongari		}
444170589Syongari	} else {
445170589Syongari		for (i = 0, rid = 1; i < NFE_MSI_MESSAGES; i++, rid++) {
446170589Syongari			sc->nfe_irq[i] = bus_alloc_resource_any(dev,
447170589Syongari			    SYS_RES_IRQ, &rid, RF_ACTIVE);
448170589Syongari			if (sc->nfe_irq[i] == NULL) {
449170589Syongari				device_printf(dev,
450170589Syongari				    "couldn't allocate IRQ resources for "
451170589Syongari				    "message %d\n", rid);
452170589Syongari				error = ENXIO;
453170589Syongari				goto fail;
454170589Syongari			}
455170589Syongari		}
456170589Syongari		/* Map interrupts to vector 0. */
457170589Syongari		if (sc->nfe_msix != 0) {
458170589Syongari			NFE_WRITE(sc, NFE_MSIX_MAP0, 0);
459170589Syongari			NFE_WRITE(sc, NFE_MSIX_MAP1, 0);
460170589Syongari		} else if (sc->nfe_msi != 0) {
461170589Syongari			NFE_WRITE(sc, NFE_MSI_MAP0, 0);
462170589Syongari			NFE_WRITE(sc, NFE_MSI_MAP1, 0);
463170589Syongari		}
464159952Sobrien	}
465159952Sobrien
466170589Syongari	/* Set IRQ status/mask register. */
467170589Syongari	sc->nfe_irq_status = NFE_IRQ_STATUS;
468170589Syongari	sc->nfe_irq_mask = NFE_IRQ_MASK;
469170589Syongari	sc->nfe_intrs = NFE_IRQ_WANTED;
470170589Syongari	sc->nfe_nointrs = 0;
471170589Syongari	if (sc->nfe_msix != 0) {
472170589Syongari		sc->nfe_irq_status = NFE_MSIX_IRQ_STATUS;
473170589Syongari		sc->nfe_nointrs = NFE_IRQ_WANTED;
474170589Syongari	} else if (sc->nfe_msi != 0) {
475170589Syongari		sc->nfe_irq_mask = NFE_MSI_IRQ_MASK;
476170589Syongari		sc->nfe_intrs = NFE_MSI_VECTOR_0_ENABLED;
477170589Syongari	}
478159952Sobrien
479170589Syongari	sc->nfe_devid = pci_get_device(dev);
480170589Syongari	sc->nfe_revid = pci_get_revid(dev);
481159967Sobrien	sc->nfe_flags = 0;
482159952Sobrien
483170589Syongari	switch (sc->nfe_devid) {
484159952Sobrien	case PCI_PRODUCT_NVIDIA_NFORCE3_LAN2:
485159952Sobrien	case PCI_PRODUCT_NVIDIA_NFORCE3_LAN3:
486159952Sobrien	case PCI_PRODUCT_NVIDIA_NFORCE3_LAN4:
487159952Sobrien	case PCI_PRODUCT_NVIDIA_NFORCE3_LAN5:
488159967Sobrien		sc->nfe_flags |= NFE_JUMBO_SUP | NFE_HW_CSUM;
489159952Sobrien		break;
490159952Sobrien	case PCI_PRODUCT_NVIDIA_MCP51_LAN1:
491159952Sobrien	case PCI_PRODUCT_NVIDIA_MCP51_LAN2:
492183561Syongari		sc->nfe_flags |= NFE_40BIT_ADDR | NFE_PWR_MGMT | NFE_MIB_V1;
493159952Sobrien		break;
494159952Sobrien	case PCI_PRODUCT_NVIDIA_CK804_LAN1:
495159952Sobrien	case PCI_PRODUCT_NVIDIA_CK804_LAN2:
496159952Sobrien	case PCI_PRODUCT_NVIDIA_MCP04_LAN1:
497159952Sobrien	case PCI_PRODUCT_NVIDIA_MCP04_LAN2:
498183561Syongari		sc->nfe_flags |= NFE_JUMBO_SUP | NFE_40BIT_ADDR | NFE_HW_CSUM |
499183561Syongari		    NFE_MIB_V1;
500159952Sobrien		break;
501159952Sobrien	case PCI_PRODUCT_NVIDIA_MCP55_LAN1:
502159952Sobrien	case PCI_PRODUCT_NVIDIA_MCP55_LAN2:
503163503Sobrien		sc->nfe_flags |= NFE_JUMBO_SUP | NFE_40BIT_ADDR | NFE_HW_CSUM |
504183561Syongari		    NFE_HW_VLAN | NFE_PWR_MGMT | NFE_TX_FLOW_CTRL | NFE_MIB_V2;
505159952Sobrien		break;
506170589Syongari
507162212Sobrien	case PCI_PRODUCT_NVIDIA_MCP61_LAN1:
508162212Sobrien	case PCI_PRODUCT_NVIDIA_MCP61_LAN2:
509162212Sobrien	case PCI_PRODUCT_NVIDIA_MCP61_LAN3:
510162212Sobrien	case PCI_PRODUCT_NVIDIA_MCP61_LAN4:
511170589Syongari	case PCI_PRODUCT_NVIDIA_MCP67_LAN1:
512170589Syongari	case PCI_PRODUCT_NVIDIA_MCP67_LAN2:
513170589Syongari	case PCI_PRODUCT_NVIDIA_MCP67_LAN3:
514170589Syongari	case PCI_PRODUCT_NVIDIA_MCP67_LAN4:
515178055Syongari	case PCI_PRODUCT_NVIDIA_MCP73_LAN1:
516178055Syongari	case PCI_PRODUCT_NVIDIA_MCP73_LAN2:
517178055Syongari	case PCI_PRODUCT_NVIDIA_MCP73_LAN3:
518178055Syongari	case PCI_PRODUCT_NVIDIA_MCP73_LAN4:
519170589Syongari		sc->nfe_flags |= NFE_40BIT_ADDR | NFE_PWR_MGMT |
520183561Syongari		    NFE_CORRECT_MACADDR | NFE_TX_FLOW_CTRL | NFE_MIB_V2;
521162212Sobrien		break;
522183509Syongari	case PCI_PRODUCT_NVIDIA_MCP77_LAN1:
523183509Syongari	case PCI_PRODUCT_NVIDIA_MCP77_LAN2:
524183509Syongari	case PCI_PRODUCT_NVIDIA_MCP77_LAN3:
525183509Syongari	case PCI_PRODUCT_NVIDIA_MCP77_LAN4:
526183509Syongari		/* XXX flow control */
527183509Syongari		sc->nfe_flags |= NFE_40BIT_ADDR | NFE_HW_CSUM | NFE_PWR_MGMT |
528183561Syongari		    NFE_CORRECT_MACADDR | NFE_MIB_V3;
529183509Syongari		break;
530183509Syongari	case PCI_PRODUCT_NVIDIA_MCP79_LAN1:
531183509Syongari	case PCI_PRODUCT_NVIDIA_MCP79_LAN2:
532183509Syongari	case PCI_PRODUCT_NVIDIA_MCP79_LAN3:
533183509Syongari	case PCI_PRODUCT_NVIDIA_MCP79_LAN4:
534183509Syongari		/* XXX flow control */
535183509Syongari		sc->nfe_flags |= NFE_JUMBO_SUP | NFE_40BIT_ADDR | NFE_HW_CSUM |
536183561Syongari		    NFE_PWR_MGMT | NFE_CORRECT_MACADDR | NFE_MIB_V3;
537183509Syongari		break;
538162212Sobrien	case PCI_PRODUCT_NVIDIA_MCP65_LAN1:
539162212Sobrien	case PCI_PRODUCT_NVIDIA_MCP65_LAN2:
540162212Sobrien	case PCI_PRODUCT_NVIDIA_MCP65_LAN3:
541162212Sobrien	case PCI_PRODUCT_NVIDIA_MCP65_LAN4:
542170589Syongari		sc->nfe_flags |= NFE_JUMBO_SUP | NFE_40BIT_ADDR |
543183561Syongari		    NFE_PWR_MGMT | NFE_CORRECT_MACADDR | NFE_TX_FLOW_CTRL |
544183561Syongari		    NFE_MIB_V2;
545163503Sobrien		break;
546159952Sobrien	}
547159952Sobrien
548170589Syongari	nfe_power(sc);
549170589Syongari	/* Check for reversed ethernet address */
550170589Syongari	if ((NFE_READ(sc, NFE_TX_UNK) & NFE_MAC_ADDR_INORDER) != 0)
551170589Syongari		sc->nfe_flags |= NFE_CORRECT_MACADDR;
552170589Syongari	nfe_get_macaddr(sc, sc->eaddr);
553159952Sobrien	/*
554159967Sobrien	 * Allocate the parent bus DMA tag appropriate for PCI.
555159967Sobrien	 */
556170589Syongari	dma_addr_max = BUS_SPACE_MAXADDR_32BIT;
557170589Syongari	if ((sc->nfe_flags & NFE_40BIT_ADDR) != 0)
558170589Syongari		dma_addr_max = NFE_DMA_MAXADDR;
559170589Syongari	error = bus_dma_tag_create(
560170589Syongari	    bus_get_dma_tag(sc->nfe_dev),	/* parent */
561163503Sobrien	    1, 0,				/* alignment, boundary */
562170589Syongari	    dma_addr_max,			/* lowaddr */
563163503Sobrien	    BUS_SPACE_MAXADDR,			/* highaddr */
564163503Sobrien	    NULL, NULL,				/* filter, filterarg */
565170589Syongari	    BUS_SPACE_MAXSIZE_32BIT, 0,		/* maxsize, nsegments */
566163503Sobrien	    BUS_SPACE_MAXSIZE_32BIT,		/* maxsegsize */
567170589Syongari	    0,					/* flags */
568163503Sobrien	    NULL, NULL,				/* lockfunc, lockarg */
569163503Sobrien	    &sc->nfe_parent_tag);
570159967Sobrien	if (error)
571159967Sobrien		goto fail;
572159967Sobrien
573164650Sobrien	ifp = sc->nfe_ifp = if_alloc(IFT_ETHER);
574164650Sobrien	if (ifp == NULL) {
575170589Syongari		device_printf(dev, "can not if_alloc()\n");
576164650Sobrien		error = ENOSPC;
577164650Sobrien		goto fail;
578164650Sobrien	}
579164650Sobrien
580159967Sobrien	/*
581159952Sobrien	 * Allocate Tx and Rx rings.
582159952Sobrien	 */
583170589Syongari	if ((error = nfe_alloc_tx_ring(sc, &sc->txq)) != 0)
584159967Sobrien		goto fail;
585159952Sobrien
586170589Syongari	if ((error = nfe_alloc_rx_ring(sc, &sc->rxq)) != 0)
587159967Sobrien		goto fail;
588170589Syongari
589171559Syongari	nfe_alloc_jrx_ring(sc, &sc->jrxq);
590183561Syongari	/* Create sysctl node. */
591183561Syongari	nfe_sysctl_node(sc);
592170589Syongari
593159952Sobrien	ifp->if_softc = sc;
594159967Sobrien	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
595159952Sobrien	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
596159952Sobrien	ifp->if_ioctl = nfe_ioctl;
597159952Sobrien	ifp->if_start = nfe_start;
598170589Syongari	ifp->if_hwassist = 0;
599170589Syongari	ifp->if_capabilities = 0;
600159952Sobrien	ifp->if_init = nfe_init;
601170589Syongari	IFQ_SET_MAXLEN(&ifp->if_snd, NFE_TX_RING_COUNT - 1);
602170589Syongari	ifp->if_snd.ifq_drv_maxlen = NFE_TX_RING_COUNT - 1;
603170589Syongari	IFQ_SET_READY(&ifp->if_snd);
604159952Sobrien
605170589Syongari	if (sc->nfe_flags & NFE_HW_CSUM) {
606170589Syongari		ifp->if_capabilities |= IFCAP_HWCSUM | IFCAP_TSO4;
607170589Syongari		ifp->if_hwassist |= NFE_CSUM_FEATURES | CSUM_TSO;
608170589Syongari	}
609170589Syongari	ifp->if_capenable = ifp->if_capabilities;
610164650Sobrien
611170589Syongari	sc->nfe_framesize = ifp->if_mtu + NFE_RX_HEADERS;
612170589Syongari	/* VLAN capability setup. */
613170589Syongari	ifp->if_capabilities |= IFCAP_VLAN_MTU;
614170589Syongari	if ((sc->nfe_flags & NFE_HW_VLAN) != 0) {
615159952Sobrien		ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING;
616170589Syongari		if ((ifp->if_capabilities & IFCAP_HWCSUM) != 0)
617215432Syongari			ifp->if_capabilities |= IFCAP_VLAN_HWCSUM |
618215432Syongari			    IFCAP_VLAN_HWTSO;
619159952Sobrien	}
620215132Syongari
621219902Sjhb	if (pci_find_cap(dev, PCIY_PMG, &reg) == 0)
622215132Syongari		ifp->if_capabilities |= IFCAP_WOL_MAGIC;
623159967Sobrien	ifp->if_capenable = ifp->if_capabilities;
624159952Sobrien
625170589Syongari	/*
626170589Syongari	 * Tell the upper layer(s) we support long frames.
627170589Syongari	 * Must appear after the call to ether_ifattach() because
628170589Syongari	 * ether_ifattach() sets ifi_hdrlen to the default value.
629170589Syongari	 */
630170589Syongari	ifp->if_data.ifi_hdrlen = sizeof(struct ether_vlan_header);
631170589Syongari
632159967Sobrien#ifdef DEVICE_POLLING
633159967Sobrien	ifp->if_capabilities |= IFCAP_POLLING;
634159967Sobrien#endif
635159952Sobrien
636159967Sobrien	/* Do MII setup */
637264293Syongari	phyloc = MII_PHY_ANY;
638264293Syongari	if (sc->nfe_devid == PCI_PRODUCT_NVIDIA_MCP61_LAN1 ||
639264293Syongari	    sc->nfe_devid == PCI_PRODUCT_NVIDIA_MCP61_LAN2 ||
640264293Syongari	    sc->nfe_devid == PCI_PRODUCT_NVIDIA_MCP61_LAN3 ||
641264293Syongari	    sc->nfe_devid == PCI_PRODUCT_NVIDIA_MCP61_LAN4) {
642264293Syongari		if (nfe_detect_msik9(sc) != 0)
643264293Syongari			phyloc = 0;
644264293Syongari	}
645213894Smarius	error = mii_attach(dev, &sc->nfe_miibus, ifp, nfe_ifmedia_upd,
646264293Syongari	    nfe_ifmedia_sts, BMSR_DEFCAPMASK, phyloc, MII_OFFSET_ANY,
647215297Smarius	    MIIF_DOPAUSE);
648213894Smarius	if (error != 0) {
649213894Smarius		device_printf(dev, "attaching PHYs failed\n");
650159967Sobrien		goto fail;
651159967Sobrien	}
652159967Sobrien	ether_ifattach(ifp, sc->eaddr);
653159952Sobrien
654170589Syongari	TASK_INIT(&sc->nfe_int_task, 0, nfe_int_task, sc);
655170589Syongari	sc->nfe_tq = taskqueue_create_fast("nfe_taskq", M_WAITOK,
656170589Syongari	    taskqueue_thread_enqueue, &sc->nfe_tq);
657170589Syongari	taskqueue_start_threads(&sc->nfe_tq, 1, PI_NET, "%s taskq",
658170589Syongari	    device_get_nameunit(sc->nfe_dev));
659170589Syongari	error = 0;
660170589Syongari	if (sc->nfe_msi == 0 && sc->nfe_msix == 0) {
661170589Syongari		error = bus_setup_intr(dev, sc->nfe_irq[0],
662170589Syongari		    INTR_TYPE_NET | INTR_MPSAFE, nfe_intr, NULL, sc,
663170589Syongari		    &sc->nfe_intrhand[0]);
664170589Syongari	} else {
665170589Syongari		for (i = 0; i < NFE_MSI_MESSAGES; i++) {
666170589Syongari			error = bus_setup_intr(dev, sc->nfe_irq[i],
667170589Syongari			    INTR_TYPE_NET | INTR_MPSAFE, nfe_intr, NULL, sc,
668170589Syongari			    &sc->nfe_intrhand[i]);
669170589Syongari			if (error != 0)
670170589Syongari				break;
671170589Syongari		}
672170589Syongari	}
673159967Sobrien	if (error) {
674170589Syongari		device_printf(dev, "couldn't set up irq\n");
675170589Syongari		taskqueue_free(sc->nfe_tq);
676170589Syongari		sc->nfe_tq = NULL;
677159967Sobrien		ether_ifdetach(ifp);
678159967Sobrien		goto fail;
679159967Sobrien	}
680159967Sobrien
681159967Sobrienfail:
682159967Sobrien	if (error)
683159967Sobrien		nfe_detach(dev);
684159967Sobrien
685159967Sobrien	return (error);
686159952Sobrien}
687159952Sobrien
688159967Sobrien
689159967Sobrienstatic int
690159967Sobriennfe_detach(device_t dev)
691159952Sobrien{
692163503Sobrien	struct nfe_softc *sc;
693163503Sobrien	struct ifnet *ifp;
694170589Syongari	uint8_t eaddr[ETHER_ADDR_LEN];
695170589Syongari	int i, rid;
696159952Sobrien
697159967Sobrien	sc = device_get_softc(dev);
698159967Sobrien	KASSERT(mtx_initialized(&sc->nfe_mtx), ("nfe mutex not initialized"));
699159967Sobrien	ifp = sc->nfe_ifp;
700159967Sobrien
701159967Sobrien#ifdef DEVICE_POLLING
702170589Syongari	if (ifp != NULL && ifp->if_capenable & IFCAP_POLLING)
703159967Sobrien		ether_poll_deregister(ifp);
704159967Sobrien#endif
705159967Sobrien	if (device_is_attached(dev)) {
706164649Sobrien		NFE_LOCK(sc);
707170589Syongari		nfe_stop(ifp);
708159967Sobrien		ifp->if_flags &= ~IFF_UP;
709164649Sobrien		NFE_UNLOCK(sc);
710159967Sobrien		callout_drain(&sc->nfe_stat_ch);
711159967Sobrien		ether_ifdetach(ifp);
712159967Sobrien	}
713159967Sobrien
714170589Syongari	if (ifp) {
715170589Syongari		/* restore ethernet address */
716170589Syongari		if ((sc->nfe_flags & NFE_CORRECT_MACADDR) == 0) {
717170589Syongari			for (i = 0; i < ETHER_ADDR_LEN; i++) {
718170589Syongari				eaddr[i] = sc->eaddr[5 - i];
719170589Syongari			}
720170589Syongari		} else
721170589Syongari			bcopy(sc->eaddr, eaddr, ETHER_ADDR_LEN);
722170589Syongari		nfe_set_macaddr(sc, eaddr);
723159967Sobrien		if_free(ifp);
724170589Syongari	}
725159967Sobrien	if (sc->nfe_miibus)
726159967Sobrien		device_delete_child(dev, sc->nfe_miibus);
727159967Sobrien	bus_generic_detach(dev);
728170589Syongari	if (sc->nfe_tq != NULL) {
729170589Syongari		taskqueue_drain(sc->nfe_tq, &sc->nfe_int_task);
730170589Syongari		taskqueue_free(sc->nfe_tq);
731170589Syongari		sc->nfe_tq = NULL;
732170589Syongari	}
733159967Sobrien
734170589Syongari	for (i = 0; i < NFE_MSI_MESSAGES; i++) {
735170589Syongari		if (sc->nfe_intrhand[i] != NULL) {
736170589Syongari			bus_teardown_intr(dev, sc->nfe_irq[i],
737170589Syongari			    sc->nfe_intrhand[i]);
738170589Syongari			sc->nfe_intrhand[i] = NULL;
739170589Syongari		}
740170589Syongari	}
741159967Sobrien
742170589Syongari	if (sc->nfe_msi == 0 && sc->nfe_msix == 0) {
743170589Syongari		if (sc->nfe_irq[0] != NULL)
744170589Syongari			bus_release_resource(dev, SYS_RES_IRQ, 0,
745170589Syongari			    sc->nfe_irq[0]);
746170589Syongari	} else {
747170589Syongari		for (i = 0, rid = 1; i < NFE_MSI_MESSAGES; i++, rid++) {
748170589Syongari			if (sc->nfe_irq[i] != NULL) {
749170589Syongari				bus_release_resource(dev, SYS_RES_IRQ, rid,
750170589Syongari				    sc->nfe_irq[i]);
751170589Syongari				sc->nfe_irq[i] = NULL;
752170589Syongari			}
753170589Syongari		}
754170589Syongari		pci_release_msi(dev);
755170589Syongari	}
756170589Syongari	if (sc->nfe_msix_pba_res != NULL) {
757170589Syongari		bus_release_resource(dev, SYS_RES_MEMORY, PCIR_BAR(3),
758170589Syongari		    sc->nfe_msix_pba_res);
759170589Syongari		sc->nfe_msix_pba_res = NULL;
760170589Syongari	}
761170589Syongari	if (sc->nfe_msix_res != NULL) {
762170589Syongari		bus_release_resource(dev, SYS_RES_MEMORY, PCIR_BAR(2),
763170589Syongari		    sc->nfe_msix_res);
764170589Syongari		sc->nfe_msix_res = NULL;
765170589Syongari	}
766170589Syongari	if (sc->nfe_res[0] != NULL) {
767170589Syongari		bus_release_resource(dev, SYS_RES_MEMORY, PCIR_BAR(0),
768170589Syongari		    sc->nfe_res[0]);
769170589Syongari		sc->nfe_res[0] = NULL;
770170589Syongari	}
771170589Syongari
772159967Sobrien	nfe_free_tx_ring(sc, &sc->txq);
773159967Sobrien	nfe_free_rx_ring(sc, &sc->rxq);
774170589Syongari	nfe_free_jrx_ring(sc, &sc->jrxq);
775159967Sobrien
776170589Syongari	if (sc->nfe_parent_tag) {
777159967Sobrien		bus_dma_tag_destroy(sc->nfe_parent_tag);
778170589Syongari		sc->nfe_parent_tag = NULL;
779170589Syongari	}
780159967Sobrien
781159967Sobrien	mtx_destroy(&sc->nfe_mtx);
782159967Sobrien
783159967Sobrien	return (0);
784159952Sobrien}
785159952Sobrien
786159967Sobrien
787170589Syongaristatic int
788170589Syongarinfe_suspend(device_t dev)
789170589Syongari{
790170589Syongari	struct nfe_softc *sc;
791170589Syongari
792170589Syongari	sc = device_get_softc(dev);
793170589Syongari
794170589Syongari	NFE_LOCK(sc);
795170589Syongari	nfe_stop(sc->nfe_ifp);
796215132Syongari	nfe_set_wol(sc);
797170589Syongari	sc->nfe_suspended = 1;
798170589Syongari	NFE_UNLOCK(sc);
799170589Syongari
800170589Syongari	return (0);
801170589Syongari}
802170589Syongari
803170589Syongari
804170589Syongaristatic int
805170589Syongarinfe_resume(device_t dev)
806170589Syongari{
807170589Syongari	struct nfe_softc *sc;
808170589Syongari	struct ifnet *ifp;
809170589Syongari
810170589Syongari	sc = device_get_softc(dev);
811170589Syongari
812170589Syongari	NFE_LOCK(sc);
813215132Syongari	nfe_power(sc);
814170589Syongari	ifp = sc->nfe_ifp;
815170589Syongari	if (ifp->if_flags & IFF_UP)
816170589Syongari		nfe_init_locked(sc);
817170589Syongari	sc->nfe_suspended = 0;
818170589Syongari	NFE_UNLOCK(sc);
819170589Syongari
820170589Syongari	return (0);
821170589Syongari}
822170589Syongari
823170589Syongari
824215327Syongaristatic int
825215327Syongarinfe_can_use_msix(struct nfe_softc *sc)
826215327Syongari{
827215327Syongari	static struct msix_blacklist {
828215327Syongari		char	*maker;
829215327Syongari		char	*product;
830215327Syongari	} msix_blacklists[] = {
831215327Syongari		{ "ASUSTeK Computer INC.", "P5N32-SLI PREMIUM" }
832215327Syongari	};
833215327Syongari
834215327Syongari	struct msix_blacklist *mblp;
835215327Syongari	char *maker, *product;
836215350Syongari	int count, n, use_msix;
837215327Syongari
838215327Syongari	/*
839215327Syongari	 * Search base board manufacturer and product name table
840215327Syongari	 * to see this system has a known MSI/MSI-X issue.
841215327Syongari	 */
842215327Syongari	maker = getenv("smbios.planar.maker");
843215327Syongari	product = getenv("smbios.planar.product");
844215350Syongari	use_msix = 1;
845215327Syongari	if (maker != NULL && product != NULL) {
846215327Syongari		count = sizeof(msix_blacklists) / sizeof(msix_blacklists[0]);
847215327Syongari		mblp = msix_blacklists;
848215327Syongari		for (n = 0; n < count; n++) {
849215327Syongari			if (strcmp(maker, mblp->maker) == 0 &&
850215350Syongari			    strcmp(product, mblp->product) == 0) {
851215350Syongari				use_msix = 0;
852215350Syongari				break;
853215350Syongari			}
854215327Syongari			mblp++;
855215327Syongari		}
856215327Syongari	}
857215350Syongari	if (maker != NULL)
858215350Syongari		freeenv(maker);
859215350Syongari	if (product != NULL)
860215350Syongari		freeenv(product);
861215327Syongari
862215350Syongari	return (use_msix);
863215327Syongari}
864215327Syongari
865215327Syongari
866170589Syongari/* Take PHY/NIC out of powerdown, from Linux */
867159967Sobrienstatic void
868170589Syongarinfe_power(struct nfe_softc *sc)
869170589Syongari{
870170589Syongari	uint32_t pwr;
871170589Syongari
872170589Syongari	if ((sc->nfe_flags & NFE_PWR_MGMT) == 0)
873170589Syongari		return;
874170589Syongari	NFE_WRITE(sc, NFE_RXTX_CTL, NFE_RXTX_RESET | NFE_RXTX_BIT2);
875170589Syongari	NFE_WRITE(sc, NFE_MAC_RESET, NFE_MAC_RESET_MAGIC);
876170589Syongari	DELAY(100);
877170589Syongari	NFE_WRITE(sc, NFE_MAC_RESET, 0);
878170589Syongari	DELAY(100);
879170589Syongari	NFE_WRITE(sc, NFE_RXTX_CTL, NFE_RXTX_BIT2);
880170589Syongari	pwr = NFE_READ(sc, NFE_PWR2_CTL);
881170589Syongari	pwr &= ~NFE_PWR2_WAKEUP_MASK;
882170589Syongari	if (sc->nfe_revid >= 0xa3 &&
883170589Syongari	    (sc->nfe_devid == PCI_PRODUCT_NVIDIA_NFORCE430_LAN1 ||
884170589Syongari	    sc->nfe_devid == PCI_PRODUCT_NVIDIA_NFORCE430_LAN2))
885170589Syongari		pwr |= NFE_PWR2_REVA3;
886170589Syongari	NFE_WRITE(sc, NFE_PWR2_CTL, pwr);
887170589Syongari}
888170589Syongari
889170589Syongari
890170589Syongaristatic void
891159967Sobriennfe_miibus_statchg(device_t dev)
892159952Sobrien{
893159967Sobrien	struct nfe_softc *sc;
894159967Sobrien	struct mii_data *mii;
895170589Syongari	struct ifnet *ifp;
896215132Syongari	uint32_t rxctl, txctl;
897159952Sobrien
898215132Syongari	sc = device_get_softc(dev);
899170589Syongari
900159967Sobrien	mii = device_get_softc(sc->nfe_miibus);
901170589Syongari	ifp = sc->nfe_ifp;
902159967Sobrien
903215132Syongari	sc->nfe_link = 0;
904215132Syongari	if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) ==
905215132Syongari	    (IFM_ACTIVE | IFM_AVALID)) {
906215132Syongari		switch (IFM_SUBTYPE(mii->mii_media_active)) {
907215132Syongari		case IFM_10_T:
908215132Syongari		case IFM_100_TX:
909215132Syongari		case IFM_1000_T:
910170589Syongari			sc->nfe_link = 1;
911215132Syongari			break;
912215132Syongari		default:
913215132Syongari			break;
914215132Syongari		}
915215132Syongari	}
916170589Syongari
917215132Syongari	nfe_mac_config(sc, mii);
918215132Syongari	txctl = NFE_READ(sc, NFE_TX_CTL);
919215132Syongari	rxctl = NFE_READ(sc, NFE_RX_CTL);
920215132Syongari	if (sc->nfe_link != 0 && (ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) {
921215132Syongari		txctl |= NFE_TX_START;
922215132Syongari		rxctl |= NFE_RX_START;
923215132Syongari	} else {
924215132Syongari		txctl &= ~NFE_TX_START;
925215132Syongari		rxctl &= ~NFE_RX_START;
926215132Syongari	}
927215132Syongari	NFE_WRITE(sc, NFE_TX_CTL, txctl);
928215132Syongari	NFE_WRITE(sc, NFE_RX_CTL, rxctl);
929215132Syongari}
930215132Syongari
931215132Syongari
932215132Syongaristatic void
933215132Syongarinfe_mac_config(struct nfe_softc *sc, struct mii_data *mii)
934215132Syongari{
935215132Syongari	uint32_t link, misc, phy, seed;
936215132Syongari	uint32_t val;
937215132Syongari
938215132Syongari	NFE_LOCK_ASSERT(sc);
939215132Syongari
940159952Sobrien	phy = NFE_READ(sc, NFE_PHY_IFACE);
941159952Sobrien	phy &= ~(NFE_PHY_HDX | NFE_PHY_100TX | NFE_PHY_1000T);
942159952Sobrien
943159952Sobrien	seed = NFE_READ(sc, NFE_RNDSEED);
944159952Sobrien	seed &= ~NFE_SEED_MASK;
945159952Sobrien
946215132Syongari	misc = NFE_MISC1_MAGIC;
947215132Syongari	link = NFE_MEDIA_SET;
948215132Syongari
949215132Syongari	if ((IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) == 0) {
950159952Sobrien		phy  |= NFE_PHY_HDX;	/* half-duplex */
951159952Sobrien		misc |= NFE_MISC1_HDX;
952159952Sobrien	}
953159952Sobrien
954159952Sobrien	switch (IFM_SUBTYPE(mii->mii_media_active)) {
955159952Sobrien	case IFM_1000_T:	/* full-duplex only */
956159952Sobrien		link |= NFE_MEDIA_1000T;
957159952Sobrien		seed |= NFE_SEED_1000T;
958159952Sobrien		phy  |= NFE_PHY_1000T;
959159952Sobrien		break;
960159952Sobrien	case IFM_100_TX:
961159952Sobrien		link |= NFE_MEDIA_100TX;
962159952Sobrien		seed |= NFE_SEED_100TX;
963159952Sobrien		phy  |= NFE_PHY_100TX;
964159952Sobrien		break;
965159952Sobrien	case IFM_10_T:
966159952Sobrien		link |= NFE_MEDIA_10T;
967159952Sobrien		seed |= NFE_SEED_10T;
968159952Sobrien		break;
969159952Sobrien	}
970159952Sobrien
971170589Syongari	if ((phy & 0x10000000) != 0) {
972170589Syongari		if (IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_T)
973170589Syongari			val = NFE_R1_MAGIC_1000;
974170589Syongari		else
975170589Syongari			val = NFE_R1_MAGIC_10_100;
976170589Syongari	} else
977170589Syongari		val = NFE_R1_MAGIC_DEFAULT;
978170589Syongari	NFE_WRITE(sc, NFE_SETUP_R1, val);
979170589Syongari
980159952Sobrien	NFE_WRITE(sc, NFE_RNDSEED, seed);	/* XXX: gigabit NICs only? */
981159952Sobrien
982159952Sobrien	NFE_WRITE(sc, NFE_PHY_IFACE, phy);
983159952Sobrien	NFE_WRITE(sc, NFE_MISC1, misc);
984159952Sobrien	NFE_WRITE(sc, NFE_LINKSPEED, link);
985170589Syongari
986215132Syongari	if ((IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) != 0) {
987170589Syongari		/* It seems all hardwares supports Rx pause frames. */
988170589Syongari		val = NFE_READ(sc, NFE_RXFILTER);
989215297Smarius		if ((IFM_OPTIONS(mii->mii_media_active) &
990215297Smarius		    IFM_ETH_RXPAUSE) != 0)
991170589Syongari			val |= NFE_PFF_RX_PAUSE;
992170589Syongari		else
993170589Syongari			val &= ~NFE_PFF_RX_PAUSE;
994170589Syongari		NFE_WRITE(sc, NFE_RXFILTER, val);
995170589Syongari		if ((sc->nfe_flags & NFE_TX_FLOW_CTRL) != 0) {
996170589Syongari			val = NFE_READ(sc, NFE_MISC1);
997215132Syongari			if ((IFM_OPTIONS(mii->mii_media_active) &
998215297Smarius			    IFM_ETH_TXPAUSE) != 0) {
999170589Syongari				NFE_WRITE(sc, NFE_TX_PAUSE_FRAME,
1000170589Syongari				    NFE_TX_PAUSE_FRAME_ENABLE);
1001170589Syongari				val |= NFE_MISC1_TX_PAUSE;
1002170589Syongari			} else {
1003170589Syongari				val &= ~NFE_MISC1_TX_PAUSE;
1004170589Syongari				NFE_WRITE(sc, NFE_TX_PAUSE_FRAME,
1005170589Syongari				    NFE_TX_PAUSE_FRAME_DISABLE);
1006170589Syongari			}
1007170589Syongari			NFE_WRITE(sc, NFE_MISC1, val);
1008170589Syongari		}
1009170589Syongari	} else {
1010170589Syongari		/* disable rx/tx pause frames */
1011170589Syongari		val = NFE_READ(sc, NFE_RXFILTER);
1012170589Syongari		val &= ~NFE_PFF_RX_PAUSE;
1013170589Syongari		NFE_WRITE(sc, NFE_RXFILTER, val);
1014170589Syongari		if ((sc->nfe_flags & NFE_TX_FLOW_CTRL) != 0) {
1015170589Syongari			NFE_WRITE(sc, NFE_TX_PAUSE_FRAME,
1016170589Syongari			    NFE_TX_PAUSE_FRAME_DISABLE);
1017170589Syongari			val = NFE_READ(sc, NFE_MISC1);
1018170589Syongari			val &= ~NFE_MISC1_TX_PAUSE;
1019170589Syongari			NFE_WRITE(sc, NFE_MISC1, val);
1020170589Syongari		}
1021170589Syongari	}
1022159952Sobrien}
1023159952Sobrien
1024163503Sobrien
1025159967Sobrienstatic int
1026159967Sobriennfe_miibus_readreg(device_t dev, int phy, int reg)
1027159952Sobrien{
1028159967Sobrien	struct nfe_softc *sc = device_get_softc(dev);
1029170589Syongari	uint32_t val;
1030159952Sobrien	int ntries;
1031159952Sobrien
1032159952Sobrien	NFE_WRITE(sc, NFE_PHY_STATUS, 0xf);
1033159952Sobrien
1034159952Sobrien	if (NFE_READ(sc, NFE_PHY_CTL) & NFE_PHY_BUSY) {
1035159952Sobrien		NFE_WRITE(sc, NFE_PHY_CTL, NFE_PHY_BUSY);
1036159952Sobrien		DELAY(100);
1037159952Sobrien	}
1038159952Sobrien
1039159952Sobrien	NFE_WRITE(sc, NFE_PHY_CTL, (phy << NFE_PHYADD_SHIFT) | reg);
1040159952Sobrien
1041170589Syongari	for (ntries = 0; ntries < NFE_TIMEOUT; ntries++) {
1042159952Sobrien		DELAY(100);
1043159952Sobrien		if (!(NFE_READ(sc, NFE_PHY_CTL) & NFE_PHY_BUSY))
1044159952Sobrien			break;
1045159952Sobrien	}
1046170589Syongari	if (ntries == NFE_TIMEOUT) {
1047170589Syongari		DPRINTFN(sc, 2, "timeout waiting for PHY\n");
1048159952Sobrien		return 0;
1049159952Sobrien	}
1050159952Sobrien
1051159952Sobrien	if (NFE_READ(sc, NFE_PHY_STATUS) & NFE_PHY_ERROR) {
1052170589Syongari		DPRINTFN(sc, 2, "could not read PHY\n");
1053159952Sobrien		return 0;
1054159952Sobrien	}
1055159952Sobrien
1056159952Sobrien	val = NFE_READ(sc, NFE_PHY_DATA);
1057159952Sobrien	if (val != 0xffffffff && val != 0)
1058159952Sobrien		sc->mii_phyaddr = phy;
1059159952Sobrien
1060170589Syongari	DPRINTFN(sc, 2, "mii read phy %d reg 0x%x ret 0x%x\n", phy, reg, val);
1061159952Sobrien
1062170589Syongari	return (val);
1063159952Sobrien}
1064159952Sobrien
1065163503Sobrien
1066159967Sobrienstatic int
1067159967Sobriennfe_miibus_writereg(device_t dev, int phy, int reg, int val)
1068159952Sobrien{
1069159967Sobrien	struct nfe_softc *sc = device_get_softc(dev);
1070170589Syongari	uint32_t ctl;
1071163503Sobrien	int ntries;
1072159952Sobrien
1073159952Sobrien	NFE_WRITE(sc, NFE_PHY_STATUS, 0xf);
1074159952Sobrien
1075159952Sobrien	if (NFE_READ(sc, NFE_PHY_CTL) & NFE_PHY_BUSY) {
1076159952Sobrien		NFE_WRITE(sc, NFE_PHY_CTL, NFE_PHY_BUSY);
1077159952Sobrien		DELAY(100);
1078159952Sobrien	}
1079159952Sobrien
1080159952Sobrien	NFE_WRITE(sc, NFE_PHY_DATA, val);
1081159952Sobrien	ctl = NFE_PHY_WRITE | (phy << NFE_PHYADD_SHIFT) | reg;
1082159952Sobrien	NFE_WRITE(sc, NFE_PHY_CTL, ctl);
1083159952Sobrien
1084170589Syongari	for (ntries = 0; ntries < NFE_TIMEOUT; ntries++) {
1085159952Sobrien		DELAY(100);
1086159952Sobrien		if (!(NFE_READ(sc, NFE_PHY_CTL) & NFE_PHY_BUSY))
1087159952Sobrien			break;
1088159952Sobrien	}
1089159952Sobrien#ifdef NFE_DEBUG
1090170589Syongari	if (nfedebug >= 2 && ntries == NFE_TIMEOUT)
1091170589Syongari		device_printf(sc->nfe_dev, "could not write to PHY\n");
1092159952Sobrien#endif
1093170589Syongari	return (0);
1094159952Sobrien}
1095159952Sobrien
1096170589Syongaristruct nfe_dmamap_arg {
1097170589Syongari	bus_addr_t nfe_busaddr;
1098170589Syongari};
1099170589Syongari
1100159967Sobrienstatic int
1101159967Sobriennfe_alloc_rx_ring(struct nfe_softc *sc, struct nfe_rx_ring *ring)
1102159952Sobrien{
1103170589Syongari	struct nfe_dmamap_arg ctx;
1104159967Sobrien	struct nfe_rx_data *data;
1105170589Syongari	void *desc;
1106159967Sobrien	int i, error, descsize;
1107159967Sobrien
1108159967Sobrien	if (sc->nfe_flags & NFE_40BIT_ADDR) {
1109170589Syongari		desc = ring->desc64;
1110159967Sobrien		descsize = sizeof (struct nfe_desc64);
1111159967Sobrien	} else {
1112170589Syongari		desc = ring->desc32;
1113159967Sobrien		descsize = sizeof (struct nfe_desc32);
1114159967Sobrien	}
1115159967Sobrien
1116159967Sobrien	ring->cur = ring->next = 0;
1117159967Sobrien
1118163503Sobrien	error = bus_dma_tag_create(sc->nfe_parent_tag,
1119170589Syongari	    NFE_RING_ALIGN, 0,			/* alignment, boundary */
1120170589Syongari	    BUS_SPACE_MAXADDR,			/* lowaddr */
1121170589Syongari	    BUS_SPACE_MAXADDR,			/* highaddr */
1122170589Syongari	    NULL, NULL,				/* filter, filterarg */
1123170589Syongari	    NFE_RX_RING_COUNT * descsize, 1,	/* maxsize, nsegments */
1124170589Syongari	    NFE_RX_RING_COUNT * descsize,	/* maxsegsize */
1125170589Syongari	    0,					/* flags */
1126170589Syongari	    NULL, NULL,				/* lockfunc, lockarg */
1127170589Syongari	    &ring->rx_desc_tag);
1128159967Sobrien	if (error != 0) {
1129170589Syongari		device_printf(sc->nfe_dev, "could not create desc DMA tag\n");
1130159967Sobrien		goto fail;
1131159967Sobrien	}
1132159967Sobrien
1133159967Sobrien	/* allocate memory to desc */
1134170589Syongari	error = bus_dmamem_alloc(ring->rx_desc_tag, &desc, BUS_DMA_WAITOK |
1135170589Syongari	    BUS_DMA_COHERENT | BUS_DMA_ZERO, &ring->rx_desc_map);
1136159967Sobrien	if (error != 0) {
1137170589Syongari		device_printf(sc->nfe_dev, "could not create desc DMA map\n");
1138159967Sobrien		goto fail;
1139159967Sobrien	}
1140170589Syongari	if (sc->nfe_flags & NFE_40BIT_ADDR)
1141170589Syongari		ring->desc64 = desc;
1142170589Syongari	else
1143170589Syongari		ring->desc32 = desc;
1144159967Sobrien
1145159967Sobrien	/* map desc to device visible address space */
1146170589Syongari	ctx.nfe_busaddr = 0;
1147170589Syongari	error = bus_dmamap_load(ring->rx_desc_tag, ring->rx_desc_map, desc,
1148170589Syongari	    NFE_RX_RING_COUNT * descsize, nfe_dma_map_segs, &ctx, 0);
1149159967Sobrien	if (error != 0) {
1150170589Syongari		device_printf(sc->nfe_dev, "could not load desc DMA map\n");
1151159967Sobrien		goto fail;
1152159967Sobrien	}
1153170589Syongari	ring->physaddr = ctx.nfe_busaddr;
1154159967Sobrien
1155170589Syongari	error = bus_dma_tag_create(sc->nfe_parent_tag,
1156170589Syongari	    1, 0,			/* alignment, boundary */
1157170589Syongari	    BUS_SPACE_MAXADDR,		/* lowaddr */
1158170589Syongari	    BUS_SPACE_MAXADDR,		/* highaddr */
1159170589Syongari	    NULL, NULL,			/* filter, filterarg */
1160170589Syongari	    MCLBYTES, 1,		/* maxsize, nsegments */
1161170589Syongari	    MCLBYTES,			/* maxsegsize */
1162170589Syongari	    0,				/* flags */
1163170589Syongari	    NULL, NULL,			/* lockfunc, lockarg */
1164170589Syongari	    &ring->rx_data_tag);
1165170589Syongari	if (error != 0) {
1166170589Syongari		device_printf(sc->nfe_dev, "could not create Rx DMA tag\n");
1167170589Syongari		goto fail;
1168170589Syongari	}
1169159967Sobrien
1170170589Syongari	error = bus_dmamap_create(ring->rx_data_tag, 0, &ring->rx_spare_map);
1171170589Syongari	if (error != 0) {
1172170589Syongari		device_printf(sc->nfe_dev,
1173170589Syongari		    "could not create Rx DMA spare map\n");
1174170589Syongari		goto fail;
1175170589Syongari	}
1176170589Syongari
1177159967Sobrien	/*
1178159967Sobrien	 * Pre-allocate Rx buffers and populate Rx ring.
1179159967Sobrien	 */
1180159967Sobrien	for (i = 0; i < NFE_RX_RING_COUNT; i++) {
1181159967Sobrien		data = &sc->rxq.data[i];
1182170589Syongari		data->rx_data_map = NULL;
1183170589Syongari		data->m = NULL;
1184170589Syongari		error = bus_dmamap_create(ring->rx_data_tag, 0,
1185170589Syongari		    &data->rx_data_map);
1186164651Sobrien		if (error != 0) {
1187170589Syongari			device_printf(sc->nfe_dev,
1188170589Syongari			    "could not create Rx DMA map\n");
1189164651Sobrien			goto fail;
1190164651Sobrien		}
1191170589Syongari	}
1192159967Sobrien
1193170589Syongarifail:
1194170589Syongari	return (error);
1195170589Syongari}
1196170589Syongari
1197170589Syongari
1198171559Syongaristatic void
1199170589Syongarinfe_alloc_jrx_ring(struct nfe_softc *sc, struct nfe_jrx_ring *ring)
1200170589Syongari{
1201170589Syongari	struct nfe_dmamap_arg ctx;
1202170589Syongari	struct nfe_rx_data *data;
1203170589Syongari	void *desc;
1204170589Syongari	int i, error, descsize;
1205170589Syongari
1206170589Syongari	if ((sc->nfe_flags & NFE_JUMBO_SUP) == 0)
1207171559Syongari		return;
1208171559Syongari	if (jumbo_disable != 0) {
1209171559Syongari		device_printf(sc->nfe_dev, "disabling jumbo frame support\n");
1210171559Syongari		sc->nfe_jumbo_disable = 1;
1211171559Syongari		return;
1212171559Syongari	}
1213170589Syongari
1214170589Syongari	if (sc->nfe_flags & NFE_40BIT_ADDR) {
1215170589Syongari		desc = ring->jdesc64;
1216170589Syongari		descsize = sizeof (struct nfe_desc64);
1217170589Syongari	} else {
1218170589Syongari		desc = ring->jdesc32;
1219170589Syongari		descsize = sizeof (struct nfe_desc32);
1220170589Syongari	}
1221170589Syongari
1222170589Syongari	ring->jcur = ring->jnext = 0;
1223170589Syongari
1224170589Syongari	/* Create DMA tag for jumbo Rx ring. */
1225170589Syongari	error = bus_dma_tag_create(sc->nfe_parent_tag,
1226170589Syongari	    NFE_RING_ALIGN, 0,			/* alignment, boundary */
1227170589Syongari	    BUS_SPACE_MAXADDR,			/* lowaddr */
1228170589Syongari	    BUS_SPACE_MAXADDR,			/* highaddr */
1229170589Syongari	    NULL, NULL,				/* filter, filterarg */
1230170589Syongari	    NFE_JUMBO_RX_RING_COUNT * descsize,	/* maxsize */
1231170589Syongari	    1, 					/* nsegments */
1232170589Syongari	    NFE_JUMBO_RX_RING_COUNT * descsize,	/* maxsegsize */
1233170589Syongari	    0,					/* flags */
1234170589Syongari	    NULL, NULL,				/* lockfunc, lockarg */
1235170589Syongari	    &ring->jrx_desc_tag);
1236170589Syongari	if (error != 0) {
1237170589Syongari		device_printf(sc->nfe_dev,
1238170589Syongari		    "could not create jumbo ring DMA tag\n");
1239170589Syongari		goto fail;
1240170589Syongari	}
1241170589Syongari
1242170589Syongari	/* Create DMA tag for jumbo Rx buffers. */
1243170589Syongari	error = bus_dma_tag_create(sc->nfe_parent_tag,
1244192706Syongari	    1, 0,				/* alignment, boundary */
1245170589Syongari	    BUS_SPACE_MAXADDR,			/* lowaddr */
1246170589Syongari	    BUS_SPACE_MAXADDR,			/* highaddr */
1247170589Syongari	    NULL, NULL,				/* filter, filterarg */
1248176859Syongari	    MJUM9BYTES,				/* maxsize */
1249170589Syongari	    1,					/* nsegments */
1250176859Syongari	    MJUM9BYTES,				/* maxsegsize */
1251170589Syongari	    0,					/* flags */
1252170589Syongari	    NULL, NULL,				/* lockfunc, lockarg */
1253170589Syongari	    &ring->jrx_data_tag);
1254170589Syongari	if (error != 0) {
1255170589Syongari		device_printf(sc->nfe_dev,
1256170589Syongari		    "could not create jumbo Rx buffer DMA tag\n");
1257170589Syongari		goto fail;
1258170589Syongari	}
1259170589Syongari
1260170589Syongari	/* Allocate DMA'able memory and load the DMA map for jumbo Rx ring. */
1261170589Syongari	error = bus_dmamem_alloc(ring->jrx_desc_tag, &desc, BUS_DMA_WAITOK |
1262170589Syongari	    BUS_DMA_COHERENT | BUS_DMA_ZERO, &ring->jrx_desc_map);
1263170589Syongari	if (error != 0) {
1264170589Syongari		device_printf(sc->nfe_dev,
1265170589Syongari		    "could not allocate DMA'able memory for jumbo Rx ring\n");
1266170589Syongari		goto fail;
1267170589Syongari	}
1268170589Syongari	if (sc->nfe_flags & NFE_40BIT_ADDR)
1269170589Syongari		ring->jdesc64 = desc;
1270170589Syongari	else
1271170589Syongari		ring->jdesc32 = desc;
1272170589Syongari
1273170589Syongari	ctx.nfe_busaddr = 0;
1274170589Syongari	error = bus_dmamap_load(ring->jrx_desc_tag, ring->jrx_desc_map, desc,
1275170589Syongari	    NFE_JUMBO_RX_RING_COUNT * descsize, nfe_dma_map_segs, &ctx, 0);
1276170589Syongari	if (error != 0) {
1277170589Syongari		device_printf(sc->nfe_dev,
1278170589Syongari		    "could not load DMA'able memory for jumbo Rx ring\n");
1279170589Syongari		goto fail;
1280170589Syongari	}
1281170589Syongari	ring->jphysaddr = ctx.nfe_busaddr;
1282170589Syongari
1283170589Syongari	/* Create DMA maps for jumbo Rx buffers. */
1284170589Syongari	error = bus_dmamap_create(ring->jrx_data_tag, 0, &ring->jrx_spare_map);
1285170589Syongari	if (error != 0) {
1286170589Syongari		device_printf(sc->nfe_dev,
1287170589Syongari		    "could not create jumbo Rx DMA spare map\n");
1288170589Syongari		goto fail;
1289170589Syongari	}
1290170589Syongari
1291170589Syongari	for (i = 0; i < NFE_JUMBO_RX_RING_COUNT; i++) {
1292170589Syongari		data = &sc->jrxq.jdata[i];
1293170589Syongari		data->rx_data_map = NULL;
1294170589Syongari		data->m = NULL;
1295170589Syongari		error = bus_dmamap_create(ring->jrx_data_tag, 0,
1296164651Sobrien		    &data->rx_data_map);
1297164651Sobrien		if (error != 0) {
1298170589Syongari			device_printf(sc->nfe_dev,
1299170589Syongari			    "could not create jumbo Rx DMA map\n");
1300164651Sobrien			goto fail;
1301164651Sobrien		}
1302170589Syongari	}
1303159967Sobrien
1304171559Syongari	return;
1305159967Sobrien
1306170589Syongarifail:
1307171559Syongari	/*
1308171559Syongari	 * Running without jumbo frame support is ok for most cases
1309171559Syongari	 * so don't fail on creating dma tag/map for jumbo frame.
1310171559Syongari	 */
1311170589Syongari	nfe_free_jrx_ring(sc, ring);
1312171559Syongari	device_printf(sc->nfe_dev, "disabling jumbo frame support due to "
1313171559Syongari	    "resource shortage\n");
1314171559Syongari	sc->nfe_jumbo_disable = 1;
1315170589Syongari}
1316159967Sobrien
1317159967Sobrien
1318170589Syongaristatic int
1319170589Syongarinfe_init_rx_ring(struct nfe_softc *sc, struct nfe_rx_ring *ring)
1320170589Syongari{
1321170589Syongari	void *desc;
1322170589Syongari	size_t descsize;
1323170589Syongari	int i;
1324159967Sobrien
1325170589Syongari	ring->cur = ring->next = 0;
1326170589Syongari	if (sc->nfe_flags & NFE_40BIT_ADDR) {
1327170589Syongari		desc = ring->desc64;
1328170589Syongari		descsize = sizeof (struct nfe_desc64);
1329170589Syongari	} else {
1330170589Syongari		desc = ring->desc32;
1331170589Syongari		descsize = sizeof (struct nfe_desc32);
1332159967Sobrien	}
1333170589Syongari	bzero(desc, descsize * NFE_RX_RING_COUNT);
1334170589Syongari	for (i = 0; i < NFE_RX_RING_COUNT; i++) {
1335170589Syongari		if (nfe_newbuf(sc, i) != 0)
1336170589Syongari			return (ENOBUFS);
1337170589Syongari	}
1338159967Sobrien
1339163503Sobrien	bus_dmamap_sync(ring->rx_desc_tag, ring->rx_desc_map,
1340170589Syongari	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1341159967Sobrien
1342170589Syongari	return (0);
1343159967Sobrien}
1344159967Sobrien
1345163503Sobrien
1346170589Syongaristatic int
1347170589Syongarinfe_init_jrx_ring(struct nfe_softc *sc, struct nfe_jrx_ring *ring)
1348159967Sobrien{
1349170589Syongari	void *desc;
1350170589Syongari	size_t descsize;
1351159967Sobrien	int i;
1352159967Sobrien
1353170589Syongari	ring->jcur = ring->jnext = 0;
1354170589Syongari	if (sc->nfe_flags & NFE_40BIT_ADDR) {
1355170589Syongari		desc = ring->jdesc64;
1356170589Syongari		descsize = sizeof (struct nfe_desc64);
1357170589Syongari	} else {
1358170589Syongari		desc = ring->jdesc32;
1359170589Syongari		descsize = sizeof (struct nfe_desc32);
1360159952Sobrien	}
1361176859Syongari	bzero(desc, descsize * NFE_JUMBO_RX_RING_COUNT);
1362170589Syongari	for (i = 0; i < NFE_JUMBO_RX_RING_COUNT; i++) {
1363170589Syongari		if (nfe_jnewbuf(sc, i) != 0)
1364170589Syongari			return (ENOBUFS);
1365170589Syongari	}
1366159952Sobrien
1367170589Syongari	bus_dmamap_sync(ring->jrx_desc_tag, ring->jrx_desc_map,
1368170589Syongari	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1369159952Sobrien
1370170589Syongari	return (0);
1371159967Sobrien}
1372159967Sobrien
1373159967Sobrien
1374159967Sobrienstatic void
1375159967Sobriennfe_free_rx_ring(struct nfe_softc *sc, struct nfe_rx_ring *ring)
1376159967Sobrien{
1377159967Sobrien	struct nfe_rx_data *data;
1378159967Sobrien	void *desc;
1379266270Sbrueffer	int i;
1380159967Sobrien
1381266270Sbrueffer	if (sc->nfe_flags & NFE_40BIT_ADDR)
1382159967Sobrien		desc = ring->desc64;
1383266270Sbrueffer	else
1384159967Sobrien		desc = ring->desc32;
1385159952Sobrien
1386170589Syongari	for (i = 0; i < NFE_RX_RING_COUNT; i++) {
1387170589Syongari		data = &ring->data[i];
1388170589Syongari		if (data->rx_data_map != NULL) {
1389170589Syongari			bus_dmamap_destroy(ring->rx_data_tag,
1390170589Syongari			    data->rx_data_map);
1391170589Syongari			data->rx_data_map = NULL;
1392170589Syongari		}
1393170589Syongari		if (data->m != NULL) {
1394170589Syongari			m_freem(data->m);
1395170589Syongari			data->m = NULL;
1396170589Syongari		}
1397170589Syongari	}
1398170589Syongari	if (ring->rx_data_tag != NULL) {
1399170589Syongari		if (ring->rx_spare_map != NULL) {
1400170589Syongari			bus_dmamap_destroy(ring->rx_data_tag,
1401170589Syongari			    ring->rx_spare_map);
1402170589Syongari			ring->rx_spare_map = NULL;
1403170589Syongari		}
1404170589Syongari		bus_dma_tag_destroy(ring->rx_data_tag);
1405170589Syongari		ring->rx_data_tag = NULL;
1406170589Syongari	}
1407170589Syongari
1408159967Sobrien	if (desc != NULL) {
1409159967Sobrien		bus_dmamap_unload(ring->rx_desc_tag, ring->rx_desc_map);
1410159967Sobrien		bus_dmamem_free(ring->rx_desc_tag, desc, ring->rx_desc_map);
1411170589Syongari		ring->desc64 = NULL;
1412170589Syongari		ring->desc32 = NULL;
1413170589Syongari		ring->rx_desc_map = NULL;
1414170589Syongari	}
1415170589Syongari	if (ring->rx_desc_tag != NULL) {
1416159967Sobrien		bus_dma_tag_destroy(ring->rx_desc_tag);
1417170589Syongari		ring->rx_desc_tag = NULL;
1418159967Sobrien	}
1419170589Syongari}
1420159967Sobrien
1421164650Sobrien
1422170589Syongaristatic void
1423170589Syongarinfe_free_jrx_ring(struct nfe_softc *sc, struct nfe_jrx_ring *ring)
1424170589Syongari{
1425170589Syongari	struct nfe_rx_data *data;
1426170589Syongari	void *desc;
1427170589Syongari	int i, descsize;
1428170589Syongari
1429170589Syongari	if ((sc->nfe_flags & NFE_JUMBO_SUP) == 0)
1430170589Syongari		return;
1431170589Syongari
1432170589Syongari	if (sc->nfe_flags & NFE_40BIT_ADDR) {
1433170589Syongari		desc = ring->jdesc64;
1434170589Syongari		descsize = sizeof (struct nfe_desc64);
1435170589Syongari	} else {
1436170589Syongari		desc = ring->jdesc32;
1437170589Syongari		descsize = sizeof (struct nfe_desc32);
1438170589Syongari	}
1439170589Syongari
1440170589Syongari	for (i = 0; i < NFE_JUMBO_RX_RING_COUNT; i++) {
1441170589Syongari		data = &ring->jdata[i];
1442164651Sobrien		if (data->rx_data_map != NULL) {
1443170589Syongari			bus_dmamap_destroy(ring->jrx_data_tag,
1444164651Sobrien			    data->rx_data_map);
1445170589Syongari			data->rx_data_map = NULL;
1446164651Sobrien		}
1447170589Syongari		if (data->m != NULL) {
1448164651Sobrien			m_freem(data->m);
1449170589Syongari			data->m = NULL;
1450170589Syongari		}
1451164651Sobrien	}
1452170589Syongari	if (ring->jrx_data_tag != NULL) {
1453170589Syongari		if (ring->jrx_spare_map != NULL) {
1454170589Syongari			bus_dmamap_destroy(ring->jrx_data_tag,
1455170589Syongari			    ring->jrx_spare_map);
1456170589Syongari			ring->jrx_spare_map = NULL;
1457170589Syongari		}
1458170589Syongari		bus_dma_tag_destroy(ring->jrx_data_tag);
1459170589Syongari		ring->jrx_data_tag = NULL;
1460170589Syongari	}
1461170589Syongari
1462170589Syongari	if (desc != NULL) {
1463170589Syongari		bus_dmamap_unload(ring->jrx_desc_tag, ring->jrx_desc_map);
1464170589Syongari		bus_dmamem_free(ring->jrx_desc_tag, desc, ring->jrx_desc_map);
1465170589Syongari		ring->jdesc64 = NULL;
1466170589Syongari		ring->jdesc32 = NULL;
1467170589Syongari		ring->jrx_desc_map = NULL;
1468170589Syongari	}
1469176859Syongari
1470170589Syongari	if (ring->jrx_desc_tag != NULL) {
1471170589Syongari		bus_dma_tag_destroy(ring->jrx_desc_tag);
1472170589Syongari		ring->jrx_desc_tag = NULL;
1473170589Syongari	}
1474159952Sobrien}
1475159952Sobrien
1476163503Sobrien
1477159967Sobrienstatic int
1478159967Sobriennfe_alloc_tx_ring(struct nfe_softc *sc, struct nfe_tx_ring *ring)
1479159952Sobrien{
1480170589Syongari	struct nfe_dmamap_arg ctx;
1481159967Sobrien	int i, error;
1482170589Syongari	void *desc;
1483159967Sobrien	int descsize;
1484159952Sobrien
1485159967Sobrien	if (sc->nfe_flags & NFE_40BIT_ADDR) {
1486170589Syongari		desc = ring->desc64;
1487159967Sobrien		descsize = sizeof (struct nfe_desc64);
1488159967Sobrien	} else {
1489170589Syongari		desc = ring->desc32;
1490159967Sobrien		descsize = sizeof (struct nfe_desc32);
1491159967Sobrien	}
1492159952Sobrien
1493159967Sobrien	ring->queued = 0;
1494159967Sobrien	ring->cur = ring->next = 0;
1495159967Sobrien
1496163503Sobrien	error = bus_dma_tag_create(sc->nfe_parent_tag,
1497170589Syongari	    NFE_RING_ALIGN, 0,			/* alignment, boundary */
1498170589Syongari	    BUS_SPACE_MAXADDR,			/* lowaddr */
1499170589Syongari	    BUS_SPACE_MAXADDR,			/* highaddr */
1500170589Syongari	    NULL, NULL,				/* filter, filterarg */
1501170589Syongari	    NFE_TX_RING_COUNT * descsize, 1,	/* maxsize, nsegments */
1502170589Syongari	    NFE_TX_RING_COUNT * descsize,	/* maxsegsize */
1503170589Syongari	    0,					/* flags */
1504170589Syongari	    NULL, NULL,				/* lockfunc, lockarg */
1505170589Syongari	    &ring->tx_desc_tag);
1506159967Sobrien	if (error != 0) {
1507170589Syongari		device_printf(sc->nfe_dev, "could not create desc DMA tag\n");
1508159967Sobrien		goto fail;
1509159952Sobrien	}
1510159952Sobrien
1511170589Syongari	error = bus_dmamem_alloc(ring->tx_desc_tag, &desc, BUS_DMA_WAITOK |
1512170589Syongari	    BUS_DMA_COHERENT | BUS_DMA_ZERO, &ring->tx_desc_map);
1513159967Sobrien	if (error != 0) {
1514170589Syongari		device_printf(sc->nfe_dev, "could not create desc DMA map\n");
1515159967Sobrien		goto fail;
1516159967Sobrien	}
1517170589Syongari	if (sc->nfe_flags & NFE_40BIT_ADDR)
1518170589Syongari		ring->desc64 = desc;
1519170589Syongari	else
1520170589Syongari		ring->desc32 = desc;
1521159967Sobrien
1522170589Syongari	ctx.nfe_busaddr = 0;
1523170589Syongari	error = bus_dmamap_load(ring->tx_desc_tag, ring->tx_desc_map, desc,
1524170589Syongari	    NFE_TX_RING_COUNT * descsize, nfe_dma_map_segs, &ctx, 0);
1525159967Sobrien	if (error != 0) {
1526170589Syongari		device_printf(sc->nfe_dev, "could not load desc DMA map\n");
1527159967Sobrien		goto fail;
1528159967Sobrien	}
1529170589Syongari	ring->physaddr = ctx.nfe_busaddr;
1530159967Sobrien
1531163503Sobrien	error = bus_dma_tag_create(sc->nfe_parent_tag,
1532170589Syongari	    1, 0,
1533170589Syongari	    BUS_SPACE_MAXADDR,
1534170589Syongari	    BUS_SPACE_MAXADDR,
1535170589Syongari	    NULL, NULL,
1536170595Syongari	    NFE_TSO_MAXSIZE,
1537170589Syongari	    NFE_MAX_SCATTER,
1538170595Syongari	    NFE_TSO_MAXSGSIZE,
1539170589Syongari	    0,
1540170589Syongari	    NULL, NULL,
1541170589Syongari	    &ring->tx_data_tag);
1542159967Sobrien	if (error != 0) {
1543170589Syongari		device_printf(sc->nfe_dev, "could not create Tx DMA tag\n");
1544170589Syongari		goto fail;
1545159967Sobrien	}
1546159967Sobrien
1547159967Sobrien	for (i = 0; i < NFE_TX_RING_COUNT; i++) {
1548163503Sobrien		error = bus_dmamap_create(ring->tx_data_tag, 0,
1549163503Sobrien		    &ring->data[i].tx_data_map);
1550159967Sobrien		if (error != 0) {
1551170589Syongari			device_printf(sc->nfe_dev,
1552170589Syongari			    "could not create Tx DMA map\n");
1553159967Sobrien			goto fail;
1554159967Sobrien		}
1555159967Sobrien	}
1556159967Sobrien
1557170589Syongarifail:
1558170589Syongari	return (error);
1559159967Sobrien}
1560159967Sobrien
1561159967Sobrien
1562159967Sobrienstatic void
1563170589Syongarinfe_init_tx_ring(struct nfe_softc *sc, struct nfe_tx_ring *ring)
1564159967Sobrien{
1565170589Syongari	void *desc;
1566170589Syongari	size_t descsize;
1567159967Sobrien
1568170589Syongari	sc->nfe_force_tx = 0;
1569170589Syongari	ring->queued = 0;
1570170589Syongari	ring->cur = ring->next = 0;
1571170589Syongari	if (sc->nfe_flags & NFE_40BIT_ADDR) {
1572170589Syongari		desc = ring->desc64;
1573170589Syongari		descsize = sizeof (struct nfe_desc64);
1574170589Syongari	} else {
1575170589Syongari		desc = ring->desc32;
1576170589Syongari		descsize = sizeof (struct nfe_desc32);
1577159967Sobrien	}
1578170589Syongari	bzero(desc, descsize * NFE_TX_RING_COUNT);
1579159967Sobrien
1580163503Sobrien	bus_dmamap_sync(ring->tx_desc_tag, ring->tx_desc_map,
1581170589Syongari	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1582159967Sobrien}
1583159967Sobrien
1584163503Sobrien
1585159967Sobrienstatic void
1586159967Sobriennfe_free_tx_ring(struct nfe_softc *sc, struct nfe_tx_ring *ring)
1587159967Sobrien{
1588159967Sobrien	struct nfe_tx_data *data;
1589159967Sobrien	void *desc;
1590159967Sobrien	int i, descsize;
1591159967Sobrien
1592159967Sobrien	if (sc->nfe_flags & NFE_40BIT_ADDR) {
1593159967Sobrien		desc = ring->desc64;
1594159967Sobrien		descsize = sizeof (struct nfe_desc64);
1595159967Sobrien	} else {
1596159967Sobrien		desc = ring->desc32;
1597159967Sobrien		descsize = sizeof (struct nfe_desc32);
1598159967Sobrien	}
1599159967Sobrien
1600159967Sobrien	for (i = 0; i < NFE_TX_RING_COUNT; i++) {
1601159967Sobrien		data = &ring->data[i];
1602159967Sobrien
1603159967Sobrien		if (data->m != NULL) {
1604170589Syongari			bus_dmamap_sync(ring->tx_data_tag, data->tx_data_map,
1605163503Sobrien			    BUS_DMASYNC_POSTWRITE);
1606170589Syongari			bus_dmamap_unload(ring->tx_data_tag, data->tx_data_map);
1607159967Sobrien			m_freem(data->m);
1608170589Syongari			data->m = NULL;
1609159967Sobrien		}
1610170589Syongari		if (data->tx_data_map != NULL) {
1611170589Syongari			bus_dmamap_destroy(ring->tx_data_tag,
1612170589Syongari			    data->tx_data_map);
1613170589Syongari			data->tx_data_map = NULL;
1614170589Syongari		}
1615159967Sobrien	}
1616159967Sobrien
1617170589Syongari	if (ring->tx_data_tag != NULL) {
1618170589Syongari		bus_dma_tag_destroy(ring->tx_data_tag);
1619170589Syongari		ring->tx_data_tag = NULL;
1620159967Sobrien	}
1621159967Sobrien
1622170589Syongari	if (desc != NULL) {
1623170589Syongari		bus_dmamap_sync(ring->tx_desc_tag, ring->tx_desc_map,
1624170589Syongari		    BUS_DMASYNC_POSTWRITE);
1625170589Syongari		bus_dmamap_unload(ring->tx_desc_tag, ring->tx_desc_map);
1626170589Syongari		bus_dmamem_free(ring->tx_desc_tag, desc, ring->tx_desc_map);
1627170589Syongari		ring->desc64 = NULL;
1628170589Syongari		ring->desc32 = NULL;
1629170589Syongari		ring->tx_desc_map = NULL;
1630170589Syongari		bus_dma_tag_destroy(ring->tx_desc_tag);
1631170589Syongari		ring->tx_desc_tag = NULL;
1632170589Syongari	}
1633159967Sobrien}
1634159967Sobrien
1635159967Sobrien#ifdef DEVICE_POLLING
1636159967Sobrienstatic poll_handler_t nfe_poll;
1637159967Sobrien
1638163503Sobrien
1639193096Sattiliostatic int
1640159967Sobriennfe_poll(struct ifnet *ifp, enum poll_cmd cmd, int count)
1641159967Sobrien{
1642164360Sobrien	struct nfe_softc *sc = ifp->if_softc;
1643170589Syongari	uint32_t r;
1644193096Sattilio	int rx_npkts = 0;
1645159967Sobrien
1646159967Sobrien	NFE_LOCK(sc);
1647159967Sobrien
1648159967Sobrien	if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) {
1649170589Syongari		NFE_UNLOCK(sc);
1650193096Sattilio		return (rx_npkts);
1651159967Sobrien	}
1652159967Sobrien
1653171559Syongari	if (sc->nfe_framesize > MCLBYTES - ETHER_HDR_LEN)
1654193096Sattilio		rx_npkts = nfe_jrxeof(sc, count, &rx_npkts);
1655171559Syongari	else
1656193096Sattilio		rx_npkts = nfe_rxeof(sc, count, &rx_npkts);
1657159967Sobrien	nfe_txeof(sc);
1658159967Sobrien	if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
1659216925Sjhb		nfe_start_locked(ifp);
1660159967Sobrien
1661159967Sobrien	if (cmd == POLL_AND_CHECK_STATUS) {
1662170589Syongari		if ((r = NFE_READ(sc, sc->nfe_irq_status)) == 0) {
1663170589Syongari			NFE_UNLOCK(sc);
1664193096Sattilio			return (rx_npkts);
1665163503Sobrien		}
1666170589Syongari		NFE_WRITE(sc, sc->nfe_irq_status, r);
1667159967Sobrien
1668163503Sobrien		if (r & NFE_IRQ_LINK) {
1669163503Sobrien			NFE_READ(sc, NFE_PHY_STATUS);
1670163503Sobrien			NFE_WRITE(sc, NFE_PHY_STATUS, 0xf);
1671170589Syongari			DPRINTF(sc, "link state changed\n");
1672163503Sobrien		}
1673159967Sobrien	}
1674170589Syongari	NFE_UNLOCK(sc);
1675193096Sattilio	return (rx_npkts);
1676159967Sobrien}
1677159967Sobrien#endif /* DEVICE_POLLING */
1678159967Sobrien
1679170589Syongaristatic void
1680170589Syongarinfe_set_intr(struct nfe_softc *sc)
1681170589Syongari{
1682159967Sobrien
1683170589Syongari	if (sc->nfe_msi != 0)
1684170589Syongari		NFE_WRITE(sc, NFE_IRQ_MASK, NFE_IRQ_WANTED);
1685170589Syongari}
1686170589Syongari
1687170589Syongari
1688170589Syongari/* In MSIX, a write to mask reegisters behaves as XOR. */
1689170589Syongaristatic __inline void
1690170589Syongarinfe_enable_intr(struct nfe_softc *sc)
1691170589Syongari{
1692170589Syongari
1693170589Syongari	if (sc->nfe_msix != 0) {
1694170589Syongari		/* XXX Should have a better way to enable interrupts! */
1695170589Syongari		if (NFE_READ(sc, sc->nfe_irq_mask) == 0)
1696170589Syongari			NFE_WRITE(sc, sc->nfe_irq_mask, sc->nfe_intrs);
1697170589Syongari	} else
1698170589Syongari		NFE_WRITE(sc, sc->nfe_irq_mask, sc->nfe_intrs);
1699170589Syongari}
1700170589Syongari
1701170589Syongari
1702170589Syongaristatic __inline void
1703170589Syongarinfe_disable_intr(struct nfe_softc *sc)
1704170589Syongari{
1705170589Syongari
1706170589Syongari	if (sc->nfe_msix != 0) {
1707170589Syongari		/* XXX Should have a better way to disable interrupts! */
1708170589Syongari		if (NFE_READ(sc, sc->nfe_irq_mask) != 0)
1709170589Syongari			NFE_WRITE(sc, sc->nfe_irq_mask, sc->nfe_nointrs);
1710170589Syongari	} else
1711170589Syongari		NFE_WRITE(sc, sc->nfe_irq_mask, sc->nfe_nointrs);
1712170589Syongari}
1713170589Syongari
1714170589Syongari
1715159967Sobrienstatic int
1716159967Sobriennfe_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
1717159967Sobrien{
1718170589Syongari	struct nfe_softc *sc;
1719170589Syongari	struct ifreq *ifr;
1720163503Sobrien	struct mii_data *mii;
1721170589Syongari	int error, init, mask;
1722159967Sobrien
1723170589Syongari	sc = ifp->if_softc;
1724170589Syongari	ifr = (struct ifreq *) data;
1725170589Syongari	error = 0;
1726170589Syongari	init = 0;
1727159952Sobrien	switch (cmd) {
1728159952Sobrien	case SIOCSIFMTU:
1729170589Syongari		if (ifr->ifr_mtu < ETHERMIN || ifr->ifr_mtu > NFE_JUMBO_MTU)
1730159952Sobrien			error = EINVAL;
1731170589Syongari		else if (ifp->if_mtu != ifr->ifr_mtu) {
1732171559Syongari			if ((((sc->nfe_flags & NFE_JUMBO_SUP) == 0) ||
1733171559Syongari			    (sc->nfe_jumbo_disable != 0)) &&
1734170589Syongari			    ifr->ifr_mtu > ETHERMTU)
1735170589Syongari				error = EINVAL;
1736170589Syongari			else {
1737170589Syongari				NFE_LOCK(sc);
1738170589Syongari				ifp->if_mtu = ifr->ifr_mtu;
1739217794Syongari				if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
1740217794Syongari					ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
1741170589Syongari					nfe_init_locked(sc);
1742217794Syongari				}
1743170589Syongari				NFE_UNLOCK(sc);
1744164650Sobrien			}
1745164650Sobrien		}
1746159952Sobrien		break;
1747159952Sobrien	case SIOCSIFFLAGS:
1748159967Sobrien		NFE_LOCK(sc);
1749159952Sobrien		if (ifp->if_flags & IFF_UP) {
1750159952Sobrien			/*
1751159952Sobrien			 * If only the PROMISC or ALLMULTI flag changes, then
1752159952Sobrien			 * don't do a full re-init of the chip, just update
1753159952Sobrien			 * the Rx filter.
1754159952Sobrien			 */
1755159967Sobrien			if ((ifp->if_drv_flags & IFF_DRV_RUNNING) &&
1756159967Sobrien			    ((ifp->if_flags ^ sc->nfe_if_flags) &
1757159967Sobrien			     (IFF_ALLMULTI | IFF_PROMISC)) != 0)
1758159952Sobrien				nfe_setmulti(sc);
1759159967Sobrien			else
1760159967Sobrien				nfe_init_locked(sc);
1761159952Sobrien		} else {
1762159967Sobrien			if (ifp->if_drv_flags & IFF_DRV_RUNNING)
1763170589Syongari				nfe_stop(ifp);
1764159952Sobrien		}
1765159967Sobrien		sc->nfe_if_flags = ifp->if_flags;
1766159967Sobrien		NFE_UNLOCK(sc);
1767159967Sobrien		error = 0;
1768159952Sobrien		break;
1769159952Sobrien	case SIOCADDMULTI:
1770159952Sobrien	case SIOCDELMULTI:
1771170589Syongari		if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) {
1772159967Sobrien			NFE_LOCK(sc);
1773159967Sobrien			nfe_setmulti(sc);
1774159967Sobrien			NFE_UNLOCK(sc);
1775159952Sobrien			error = 0;
1776159952Sobrien		}
1777159952Sobrien		break;
1778159952Sobrien	case SIOCSIFMEDIA:
1779159952Sobrien	case SIOCGIFMEDIA:
1780159967Sobrien		mii = device_get_softc(sc->nfe_miibus);
1781159967Sobrien		error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, cmd);
1782159952Sobrien		break;
1783159967Sobrien	case SIOCSIFCAP:
1784170589Syongari		mask = ifr->ifr_reqcap ^ ifp->if_capenable;
1785159967Sobrien#ifdef DEVICE_POLLING
1786170589Syongari		if ((mask & IFCAP_POLLING) != 0) {
1787170589Syongari			if ((ifr->ifr_reqcap & IFCAP_POLLING) != 0) {
1788159967Sobrien				error = ether_poll_register(nfe_poll, ifp);
1789159967Sobrien				if (error)
1790170589Syongari					break;
1791159967Sobrien				NFE_LOCK(sc);
1792170589Syongari				nfe_disable_intr(sc);
1793163503Sobrien				ifp->if_capenable |= IFCAP_POLLING;
1794159967Sobrien				NFE_UNLOCK(sc);
1795159967Sobrien			} else {
1796159967Sobrien				error = ether_poll_deregister(ifp);
1797159967Sobrien				/* Enable interrupt even in error case */
1798159967Sobrien				NFE_LOCK(sc);
1799170589Syongari				nfe_enable_intr(sc);
1800159967Sobrien				ifp->if_capenable &= ~IFCAP_POLLING;
1801159967Sobrien				NFE_UNLOCK(sc);
1802159967Sobrien			}
1803159967Sobrien		}
1804163503Sobrien#endif /* DEVICE_POLLING */
1805215132Syongari		if ((mask & IFCAP_WOL_MAGIC) != 0 &&
1806215132Syongari		    (ifp->if_capabilities & IFCAP_WOL_MAGIC) != 0)
1807215132Syongari			ifp->if_capenable ^= IFCAP_WOL_MAGIC;
1808215432Syongari		if ((mask & IFCAP_TXCSUM) != 0 &&
1809215432Syongari		    (ifp->if_capabilities & IFCAP_TXCSUM) != 0) {
1810215432Syongari			ifp->if_capenable ^= IFCAP_TXCSUM;
1811215432Syongari			if ((ifp->if_capenable & IFCAP_TXCSUM) != 0)
1812170589Syongari				ifp->if_hwassist |= NFE_CSUM_FEATURES;
1813159967Sobrien			else
1814170589Syongari				ifp->if_hwassist &= ~NFE_CSUM_FEATURES;
1815215432Syongari		}
1816215432Syongari		if ((mask & IFCAP_RXCSUM) != 0 &&
1817215432Syongari		    (ifp->if_capabilities & IFCAP_RXCSUM) != 0) {
1818215432Syongari			ifp->if_capenable ^= IFCAP_RXCSUM;
1819170589Syongari			init++;
1820159967Sobrien		}
1821215432Syongari		if ((mask & IFCAP_TSO4) != 0 &&
1822215432Syongari		    (ifp->if_capabilities & IFCAP_TSO4) != 0) {
1823215432Syongari			ifp->if_capenable ^= IFCAP_TSO4;
1824215432Syongari			if ((IFCAP_TSO4 & ifp->if_capenable) != 0)
1825215432Syongari				ifp->if_hwassist |= CSUM_TSO;
1826215432Syongari			else
1827215432Syongari				ifp->if_hwassist &= ~CSUM_TSO;
1828215432Syongari		}
1829215432Syongari		if ((mask & IFCAP_VLAN_HWTSO) != 0 &&
1830215432Syongari		    (ifp->if_capabilities & IFCAP_VLAN_HWTSO) != 0)
1831215432Syongari			ifp->if_capenable ^= IFCAP_VLAN_HWTSO;
1832215432Syongari		if ((mask & IFCAP_VLAN_HWTAGGING) != 0 &&
1833215432Syongari		    (ifp->if_capabilities & IFCAP_VLAN_HWTAGGING) != 0) {
1834170589Syongari			ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING;
1835215432Syongari			if ((ifp->if_capenable & IFCAP_VLAN_HWTAGGING) == 0)
1836215432Syongari				ifp->if_capenable &= ~IFCAP_VLAN_HWTSO;
1837170589Syongari			init++;
1838170589Syongari		}
1839170589Syongari		/*
1840170589Syongari		 * XXX
1841170589Syongari		 * It seems that VLAN stripping requires Rx checksum offload.
1842170589Syongari		 * Unfortunately FreeBSD has no way to disable only Rx side
1843170589Syongari		 * VLAN stripping. So when we know Rx checksum offload is
1844170589Syongari		 * disabled turn entire hardware VLAN assist off.
1845170589Syongari		 */
1846215432Syongari		if ((ifp->if_capenable & IFCAP_RXCSUM) == 0) {
1847215432Syongari			if ((ifp->if_capenable & IFCAP_VLAN_HWTAGGING) != 0)
1848215432Syongari				init++;
1849215432Syongari			ifp->if_capenable &= ~(IFCAP_VLAN_HWTAGGING |
1850215432Syongari			    IFCAP_VLAN_HWTSO);
1851170589Syongari		}
1852170589Syongari		if (init > 0 && (ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) {
1853170589Syongari			ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
1854164656Sobrien			nfe_init(sc);
1855170589Syongari		}
1856215432Syongari		VLAN_CAPABILITIES(ifp);
1857159967Sobrien		break;
1858159952Sobrien	default:
1859159967Sobrien		error = ether_ioctl(ifp, cmd, data);
1860159967Sobrien		break;
1861159952Sobrien	}
1862159952Sobrien
1863170589Syongari	return (error);
1864159952Sobrien}
1865159952Sobrien
1866159967Sobrien
1867170589Syongaristatic int
1868163503Sobriennfe_intr(void *arg)
1869159967Sobrien{
1870170589Syongari	struct nfe_softc *sc;
1871170589Syongari	uint32_t status;
1872170589Syongari
1873170589Syongari	sc = (struct nfe_softc *)arg;
1874170589Syongari
1875170589Syongari	status = NFE_READ(sc, sc->nfe_irq_status);
1876170589Syongari	if (status == 0 || status == 0xffffffff)
1877170589Syongari		return (FILTER_STRAY);
1878170589Syongari	nfe_disable_intr(sc);
1879173674Ssam	taskqueue_enqueue_fast(sc->nfe_tq, &sc->nfe_int_task);
1880170589Syongari
1881170589Syongari	return (FILTER_HANDLED);
1882170589Syongari}
1883170589Syongari
1884170589Syongari
1885170589Syongaristatic void
1886170589Syongarinfe_int_task(void *arg, int pending)
1887170589Syongari{
1888159967Sobrien	struct nfe_softc *sc = arg;
1889159967Sobrien	struct ifnet *ifp = sc->nfe_ifp;
1890170589Syongari	uint32_t r;
1891170589Syongari	int domore;
1892159967Sobrien
1893163503Sobrien	NFE_LOCK(sc);
1894159967Sobrien
1895170589Syongari	if ((r = NFE_READ(sc, sc->nfe_irq_status)) == 0) {
1896170589Syongari		nfe_enable_intr(sc);
1897170589Syongari		NFE_UNLOCK(sc);
1898170589Syongari		return;	/* not for us */
1899170589Syongari	}
1900170589Syongari	NFE_WRITE(sc, sc->nfe_irq_status, r);
1901170589Syongari
1902170589Syongari	DPRINTFN(sc, 5, "nfe_intr: interrupt register %x\n", r);
1903170589Syongari
1904159967Sobrien#ifdef DEVICE_POLLING
1905159967Sobrien	if (ifp->if_capenable & IFCAP_POLLING) {
1906159967Sobrien		NFE_UNLOCK(sc);
1907159967Sobrien		return;
1908159967Sobrien	}
1909159967Sobrien#endif
1910159967Sobrien
1911172169Syongari	if (r & NFE_IRQ_LINK) {
1912172169Syongari		NFE_READ(sc, NFE_PHY_STATUS);
1913172169Syongari		NFE_WRITE(sc, NFE_PHY_STATUS, 0xf);
1914172169Syongari		DPRINTF(sc, "link state changed\n");
1915172169Syongari	}
1916172169Syongari
1917170589Syongari	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) {
1918163503Sobrien		NFE_UNLOCK(sc);
1919222542Syongari		nfe_disable_intr(sc);
1920170589Syongari		return;
1921159967Sobrien	}
1922159967Sobrien
1923170589Syongari	domore = 0;
1924170589Syongari	/* check Rx ring */
1925170589Syongari	if (sc->nfe_framesize > MCLBYTES - ETHER_HDR_LEN)
1926193096Sattilio		domore = nfe_jrxeof(sc, sc->nfe_process_limit, NULL);
1927170589Syongari	else
1928193096Sattilio		domore = nfe_rxeof(sc, sc->nfe_process_limit, NULL);
1929170589Syongari	/* check Tx ring */
1930170589Syongari	nfe_txeof(sc);
1931159967Sobrien
1932170589Syongari	if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
1933216925Sjhb		nfe_start_locked(ifp);
1934159967Sobrien
1935159967Sobrien	NFE_UNLOCK(sc);
1936159967Sobrien
1937170589Syongari	if (domore || (NFE_READ(sc, sc->nfe_irq_status) != 0)) {
1938173674Ssam		taskqueue_enqueue_fast(sc->nfe_tq, &sc->nfe_int_task);
1939170589Syongari		return;
1940170589Syongari	}
1941170589Syongari
1942170589Syongari	/* Reenable interrupts. */
1943170589Syongari	nfe_enable_intr(sc);
1944159967Sobrien}
1945159967Sobrien
1946163503Sobrien
1947170589Syongaristatic __inline void
1948170589Syongarinfe_discard_rxbuf(struct nfe_softc *sc, int idx)
1949159952Sobrien{
1950170589Syongari	struct nfe_desc32 *desc32;
1951170589Syongari	struct nfe_desc64 *desc64;
1952170589Syongari	struct nfe_rx_data *data;
1953170589Syongari	struct mbuf *m;
1954163503Sobrien
1955170589Syongari	data = &sc->rxq.data[idx];
1956170589Syongari	m = data->m;
1957170589Syongari
1958170589Syongari	if (sc->nfe_flags & NFE_40BIT_ADDR) {
1959170589Syongari		desc64 = &sc->rxq.desc64[idx];
1960170589Syongari		/* VLAN packet may have overwritten it. */
1961170589Syongari		desc64->physaddr[0] = htole32(NFE_ADDR_HI(data->paddr));
1962170589Syongari		desc64->physaddr[1] = htole32(NFE_ADDR_LO(data->paddr));
1963170589Syongari		desc64->length = htole16(m->m_len);
1964170589Syongari		desc64->flags = htole16(NFE_RX_READY);
1965170589Syongari	} else {
1966170589Syongari		desc32 = &sc->rxq.desc32[idx];
1967170589Syongari		desc32->length = htole16(m->m_len);
1968170589Syongari		desc32->flags = htole16(NFE_RX_READY);
1969170589Syongari	}
1970159952Sobrien}
1971159952Sobrien
1972163503Sobrien
1973170589Syongaristatic __inline void
1974170589Syongarinfe_discard_jrxbuf(struct nfe_softc *sc, int idx)
1975159952Sobrien{
1976170589Syongari	struct nfe_desc32 *desc32;
1977170589Syongari	struct nfe_desc64 *desc64;
1978170589Syongari	struct nfe_rx_data *data;
1979170589Syongari	struct mbuf *m;
1980163503Sobrien
1981170589Syongari	data = &sc->jrxq.jdata[idx];
1982170589Syongari	m = data->m;
1983170589Syongari
1984170589Syongari	if (sc->nfe_flags & NFE_40BIT_ADDR) {
1985170589Syongari		desc64 = &sc->jrxq.jdesc64[idx];
1986170589Syongari		/* VLAN packet may have overwritten it. */
1987170589Syongari		desc64->physaddr[0] = htole32(NFE_ADDR_HI(data->paddr));
1988170589Syongari		desc64->physaddr[1] = htole32(NFE_ADDR_LO(data->paddr));
1989170589Syongari		desc64->length = htole16(m->m_len);
1990170589Syongari		desc64->flags = htole16(NFE_RX_READY);
1991170589Syongari	} else {
1992170589Syongari		desc32 = &sc->jrxq.jdesc32[idx];
1993170589Syongari		desc32->length = htole16(m->m_len);
1994170589Syongari		desc32->flags = htole16(NFE_RX_READY);
1995170589Syongari	}
1996159952Sobrien}
1997159952Sobrien
1998163503Sobrien
1999170589Syongaristatic int
2000170589Syongarinfe_newbuf(struct nfe_softc *sc, int idx)
2001159952Sobrien{
2002170589Syongari	struct nfe_rx_data *data;
2003170589Syongari	struct nfe_desc32 *desc32;
2004170589Syongari	struct nfe_desc64 *desc64;
2005170589Syongari	struct mbuf *m;
2006170589Syongari	bus_dma_segment_t segs[1];
2007170589Syongari	bus_dmamap_t map;
2008170589Syongari	int nsegs;
2009163503Sobrien
2010243857Sglebius	m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
2011170589Syongari	if (m == NULL)
2012170589Syongari		return (ENOBUFS);
2013159952Sobrien
2014170589Syongari	m->m_len = m->m_pkthdr.len = MCLBYTES;
2015170589Syongari	m_adj(m, ETHER_ALIGN);
2016163503Sobrien
2017170589Syongari	if (bus_dmamap_load_mbuf_sg(sc->rxq.rx_data_tag, sc->rxq.rx_spare_map,
2018170589Syongari	    m, segs, &nsegs, BUS_DMA_NOWAIT) != 0) {
2019170589Syongari		m_freem(m);
2020170589Syongari		return (ENOBUFS);
2021170589Syongari	}
2022170589Syongari	KASSERT(nsegs == 1, ("%s: %d segments returned!", __func__, nsegs));
2023163503Sobrien
2024170589Syongari	data = &sc->rxq.data[idx];
2025170589Syongari	if (data->m != NULL) {
2026170589Syongari		bus_dmamap_sync(sc->rxq.rx_data_tag, data->rx_data_map,
2027170589Syongari		    BUS_DMASYNC_POSTREAD);
2028170589Syongari		bus_dmamap_unload(sc->rxq.rx_data_tag, data->rx_data_map);
2029170589Syongari	}
2030170589Syongari	map = data->rx_data_map;
2031170589Syongari	data->rx_data_map = sc->rxq.rx_spare_map;
2032170589Syongari	sc->rxq.rx_spare_map = map;
2033170589Syongari	bus_dmamap_sync(sc->rxq.rx_data_tag, data->rx_data_map,
2034170589Syongari	    BUS_DMASYNC_PREREAD);
2035170589Syongari	data->paddr = segs[0].ds_addr;
2036170589Syongari	data->m = m;
2037170589Syongari	/* update mapping address in h/w descriptor */
2038170589Syongari	if (sc->nfe_flags & NFE_40BIT_ADDR) {
2039170589Syongari		desc64 = &sc->rxq.desc64[idx];
2040170589Syongari		desc64->physaddr[0] = htole32(NFE_ADDR_HI(segs[0].ds_addr));
2041170589Syongari		desc64->physaddr[1] = htole32(NFE_ADDR_LO(segs[0].ds_addr));
2042170589Syongari		desc64->length = htole16(segs[0].ds_len);
2043170589Syongari		desc64->flags = htole16(NFE_RX_READY);
2044170589Syongari	} else {
2045170589Syongari		desc32 = &sc->rxq.desc32[idx];
2046170589Syongari		desc32->physaddr = htole32(NFE_ADDR_LO(segs[0].ds_addr));
2047170589Syongari		desc32->length = htole16(segs[0].ds_len);
2048170589Syongari		desc32->flags = htole16(NFE_RX_READY);
2049170589Syongari	}
2050170589Syongari
2051170589Syongari	return (0);
2052159952Sobrien}
2053159952Sobrien
2054163503Sobrien
2055170589Syongaristatic int
2056170589Syongarinfe_jnewbuf(struct nfe_softc *sc, int idx)
2057159952Sobrien{
2058170589Syongari	struct nfe_rx_data *data;
2059170589Syongari	struct nfe_desc32 *desc32;
2060170589Syongari	struct nfe_desc64 *desc64;
2061170589Syongari	struct mbuf *m;
2062170589Syongari	bus_dma_segment_t segs[1];
2063170589Syongari	bus_dmamap_t map;
2064170589Syongari	int nsegs;
2065163503Sobrien
2066243857Sglebius	m = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, MJUM9BYTES);
2067170589Syongari	if (m == NULL)
2068170589Syongari		return (ENOBUFS);
2069170589Syongari	if ((m->m_flags & M_EXT) == 0) {
2070170589Syongari		m_freem(m);
2071170589Syongari		return (ENOBUFS);
2072170589Syongari	}
2073176859Syongari	m->m_pkthdr.len = m->m_len = MJUM9BYTES;
2074170589Syongari	m_adj(m, ETHER_ALIGN);
2075159952Sobrien
2076170589Syongari	if (bus_dmamap_load_mbuf_sg(sc->jrxq.jrx_data_tag,
2077170589Syongari	    sc->jrxq.jrx_spare_map, m, segs, &nsegs, BUS_DMA_NOWAIT) != 0) {
2078170589Syongari		m_freem(m);
2079170589Syongari		return (ENOBUFS);
2080170589Syongari	}
2081170589Syongari	KASSERT(nsegs == 1, ("%s: %d segments returned!", __func__, nsegs));
2082163503Sobrien
2083170589Syongari	data = &sc->jrxq.jdata[idx];
2084170589Syongari	if (data->m != NULL) {
2085170589Syongari		bus_dmamap_sync(sc->jrxq.jrx_data_tag, data->rx_data_map,
2086170589Syongari		    BUS_DMASYNC_POSTREAD);
2087170589Syongari		bus_dmamap_unload(sc->jrxq.jrx_data_tag, data->rx_data_map);
2088170589Syongari	}
2089170589Syongari	map = data->rx_data_map;
2090170589Syongari	data->rx_data_map = sc->jrxq.jrx_spare_map;
2091170589Syongari	sc->jrxq.jrx_spare_map = map;
2092170589Syongari	bus_dmamap_sync(sc->jrxq.jrx_data_tag, data->rx_data_map,
2093170589Syongari	    BUS_DMASYNC_PREREAD);
2094170589Syongari	data->paddr = segs[0].ds_addr;
2095170589Syongari	data->m = m;
2096170589Syongari	/* update mapping address in h/w descriptor */
2097170589Syongari	if (sc->nfe_flags & NFE_40BIT_ADDR) {
2098170589Syongari		desc64 = &sc->jrxq.jdesc64[idx];
2099170589Syongari		desc64->physaddr[0] = htole32(NFE_ADDR_HI(segs[0].ds_addr));
2100170589Syongari		desc64->physaddr[1] = htole32(NFE_ADDR_LO(segs[0].ds_addr));
2101170589Syongari		desc64->length = htole16(segs[0].ds_len);
2102170589Syongari		desc64->flags = htole16(NFE_RX_READY);
2103170589Syongari	} else {
2104170589Syongari		desc32 = &sc->jrxq.jdesc32[idx];
2105170589Syongari		desc32->physaddr = htole32(NFE_ADDR_LO(segs[0].ds_addr));
2106170589Syongari		desc32->length = htole16(segs[0].ds_len);
2107170589Syongari		desc32->flags = htole16(NFE_RX_READY);
2108170589Syongari	}
2109159967Sobrien
2110170589Syongari	return (0);
2111159952Sobrien}
2112159952Sobrien
2113163503Sobrien
2114170589Syongaristatic int
2115193096Sattilionfe_rxeof(struct nfe_softc *sc, int count, int *rx_npktsp)
2116159952Sobrien{
2117159967Sobrien	struct ifnet *ifp = sc->nfe_ifp;
2118170589Syongari	struct nfe_desc32 *desc32;
2119170589Syongari	struct nfe_desc64 *desc64;
2120159952Sobrien	struct nfe_rx_data *data;
2121170589Syongari	struct mbuf *m;
2122170589Syongari	uint16_t flags;
2123193096Sattilio	int len, prog, rx_npkts;
2124170589Syongari	uint32_t vtag = 0;
2125159952Sobrien
2126193096Sattilio	rx_npkts = 0;
2127159967Sobrien	NFE_LOCK_ASSERT(sc);
2128159967Sobrien
2129170589Syongari	bus_dmamap_sync(sc->rxq.rx_desc_tag, sc->rxq.rx_desc_map,
2130170589Syongari	    BUS_DMASYNC_POSTREAD);
2131159967Sobrien
2132170589Syongari	for (prog = 0;;NFE_INC(sc->rxq.cur, NFE_RX_RING_COUNT), vtag = 0) {
2133170589Syongari		if (count <= 0)
2134170589Syongari			break;
2135170589Syongari		count--;
2136159967Sobrien
2137159952Sobrien		data = &sc->rxq.data[sc->rxq.cur];
2138159952Sobrien
2139159967Sobrien		if (sc->nfe_flags & NFE_40BIT_ADDR) {
2140159952Sobrien			desc64 = &sc->rxq.desc64[sc->rxq.cur];
2141170589Syongari			vtag = le32toh(desc64->physaddr[1]);
2142170589Syongari			flags = le16toh(desc64->flags);
2143170589Syongari			len = le16toh(desc64->length) & NFE_RX_LEN_MASK;
2144159952Sobrien		} else {
2145159952Sobrien			desc32 = &sc->rxq.desc32[sc->rxq.cur];
2146170589Syongari			flags = le16toh(desc32->flags);
2147170589Syongari			len = le16toh(desc32->length) & NFE_RX_LEN_MASK;
2148159952Sobrien		}
2149159952Sobrien
2150159952Sobrien		if (flags & NFE_RX_READY)
2151159952Sobrien			break;
2152170589Syongari		prog++;
2153159967Sobrien		if ((sc->nfe_flags & (NFE_JUMBO_SUP | NFE_40BIT_ADDR)) == 0) {
2154170589Syongari			if (!(flags & NFE_RX_VALID_V1)) {
2155170589Syongari				ifp->if_ierrors++;
2156170589Syongari				nfe_discard_rxbuf(sc, sc->rxq.cur);
2157170589Syongari				continue;
2158170589Syongari			}
2159159952Sobrien			if ((flags & NFE_RX_FIXME_V1) == NFE_RX_FIXME_V1) {
2160159952Sobrien				flags &= ~NFE_RX_ERROR;
2161159952Sobrien				len--;	/* fix buffer length */
2162159952Sobrien			}
2163159952Sobrien		} else {
2164170589Syongari			if (!(flags & NFE_RX_VALID_V2)) {
2165170589Syongari				ifp->if_ierrors++;
2166170589Syongari				nfe_discard_rxbuf(sc, sc->rxq.cur);
2167170589Syongari				continue;
2168170589Syongari			}
2169159952Sobrien
2170159952Sobrien			if ((flags & NFE_RX_FIXME_V2) == NFE_RX_FIXME_V2) {
2171159952Sobrien				flags &= ~NFE_RX_ERROR;
2172159952Sobrien				len--;	/* fix buffer length */
2173159952Sobrien			}
2174159952Sobrien		}
2175159952Sobrien
2176159952Sobrien		if (flags & NFE_RX_ERROR) {
2177159952Sobrien			ifp->if_ierrors++;
2178170589Syongari			nfe_discard_rxbuf(sc, sc->rxq.cur);
2179170589Syongari			continue;
2180159952Sobrien		}
2181159952Sobrien
2182170589Syongari		m = data->m;
2183170589Syongari		if (nfe_newbuf(sc, sc->rxq.cur) != 0) {
2184170589Syongari			ifp->if_iqdrops++;
2185170589Syongari			nfe_discard_rxbuf(sc, sc->rxq.cur);
2186170589Syongari			continue;
2187159952Sobrien		}
2188159952Sobrien
2189170589Syongari		if ((vtag & NFE_RX_VTAG) != 0 &&
2190170589Syongari		    (ifp->if_capenable & IFCAP_VLAN_HWTAGGING) != 0) {
2191170589Syongari			m->m_pkthdr.ether_vtag = vtag & 0xffff;
2192170589Syongari			m->m_flags |= M_VLANTAG;
2193164651Sobrien		}
2194159952Sobrien
2195170589Syongari		m->m_pkthdr.len = m->m_len = len;
2196170589Syongari		m->m_pkthdr.rcvif = ifp;
2197164651Sobrien
2198170589Syongari		if ((ifp->if_capenable & IFCAP_RXCSUM) != 0) {
2199170589Syongari			if ((flags & NFE_RX_IP_CSUMOK) != 0) {
2200170589Syongari				m->m_pkthdr.csum_flags |= CSUM_IP_CHECKED;
2201170589Syongari				m->m_pkthdr.csum_flags |= CSUM_IP_VALID;
2202170589Syongari				if ((flags & NFE_RX_TCP_CSUMOK) != 0 ||
2203170589Syongari				    (flags & NFE_RX_UDP_CSUMOK) != 0) {
2204170589Syongari					m->m_pkthdr.csum_flags |=
2205170589Syongari					    CSUM_DATA_VALID | CSUM_PSEUDO_HDR;
2206170589Syongari					m->m_pkthdr.csum_data = 0xffff;
2207170589Syongari				}
2208159952Sobrien			}
2209170589Syongari		}
2210170589Syongari
2211170589Syongari		ifp->if_ipackets++;
2212170589Syongari
2213170589Syongari		NFE_UNLOCK(sc);
2214170589Syongari		(*ifp->if_input)(ifp, m);
2215170589Syongari		NFE_LOCK(sc);
2216193096Sattilio		rx_npkts++;
2217170589Syongari	}
2218170589Syongari
2219170589Syongari	if (prog > 0)
2220170589Syongari		bus_dmamap_sync(sc->rxq.rx_desc_tag, sc->rxq.rx_desc_map,
2221170589Syongari		    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
2222170589Syongari
2223193096Sattilio	if (rx_npktsp != NULL)
2224193096Sattilio		*rx_npktsp = rx_npkts;
2225170589Syongari	return (count > 0 ? 0 : EAGAIN);
2226170589Syongari}
2227170589Syongari
2228170589Syongari
2229170589Syongaristatic int
2230193096Sattilionfe_jrxeof(struct nfe_softc *sc, int count, int *rx_npktsp)
2231170589Syongari{
2232170589Syongari	struct ifnet *ifp = sc->nfe_ifp;
2233170589Syongari	struct nfe_desc32 *desc32;
2234170589Syongari	struct nfe_desc64 *desc64;
2235170589Syongari	struct nfe_rx_data *data;
2236170589Syongari	struct mbuf *m;
2237170589Syongari	uint16_t flags;
2238193096Sattilio	int len, prog, rx_npkts;
2239170589Syongari	uint32_t vtag = 0;
2240170589Syongari
2241193096Sattilio	rx_npkts = 0;
2242170589Syongari	NFE_LOCK_ASSERT(sc);
2243170589Syongari
2244170589Syongari	bus_dmamap_sync(sc->jrxq.jrx_desc_tag, sc->jrxq.jrx_desc_map,
2245170589Syongari	    BUS_DMASYNC_POSTREAD);
2246170589Syongari
2247170589Syongari	for (prog = 0;;NFE_INC(sc->jrxq.jcur, NFE_JUMBO_RX_RING_COUNT),
2248170589Syongari	    vtag = 0) {
2249170589Syongari		if (count <= 0)
2250170589Syongari			break;
2251170589Syongari		count--;
2252170589Syongari
2253170589Syongari		data = &sc->jrxq.jdata[sc->jrxq.jcur];
2254170589Syongari
2255170589Syongari		if (sc->nfe_flags & NFE_40BIT_ADDR) {
2256170589Syongari			desc64 = &sc->jrxq.jdesc64[sc->jrxq.jcur];
2257170589Syongari			vtag = le32toh(desc64->physaddr[1]);
2258170589Syongari			flags = le16toh(desc64->flags);
2259170589Syongari			len = le16toh(desc64->length) & NFE_RX_LEN_MASK;
2260170589Syongari		} else {
2261170589Syongari			desc32 = &sc->jrxq.jdesc32[sc->jrxq.jcur];
2262170589Syongari			flags = le16toh(desc32->flags);
2263170589Syongari			len = le16toh(desc32->length) & NFE_RX_LEN_MASK;
2264170589Syongari		}
2265170589Syongari
2266170589Syongari		if (flags & NFE_RX_READY)
2267170589Syongari			break;
2268170589Syongari		prog++;
2269170589Syongari		if ((sc->nfe_flags & (NFE_JUMBO_SUP | NFE_40BIT_ADDR)) == 0) {
2270170589Syongari			if (!(flags & NFE_RX_VALID_V1)) {
2271170589Syongari				ifp->if_ierrors++;
2272170589Syongari				nfe_discard_jrxbuf(sc, sc->jrxq.jcur);
2273170589Syongari				continue;
2274170589Syongari			}
2275170589Syongari			if ((flags & NFE_RX_FIXME_V1) == NFE_RX_FIXME_V1) {
2276170589Syongari				flags &= ~NFE_RX_ERROR;
2277170589Syongari				len--;	/* fix buffer length */
2278170589Syongari			}
2279170589Syongari		} else {
2280170589Syongari			if (!(flags & NFE_RX_VALID_V2)) {
2281170589Syongari				ifp->if_ierrors++;
2282170589Syongari				nfe_discard_jrxbuf(sc, sc->jrxq.jcur);
2283170589Syongari				continue;
2284170589Syongari			}
2285170589Syongari
2286170589Syongari			if ((flags & NFE_RX_FIXME_V2) == NFE_RX_FIXME_V2) {
2287170589Syongari				flags &= ~NFE_RX_ERROR;
2288170589Syongari				len--;	/* fix buffer length */
2289170589Syongari			}
2290170589Syongari		}
2291170589Syongari
2292170589Syongari		if (flags & NFE_RX_ERROR) {
2293164651Sobrien			ifp->if_ierrors++;
2294170589Syongari			nfe_discard_jrxbuf(sc, sc->jrxq.jcur);
2295170589Syongari			continue;
2296164651Sobrien		}
2297159952Sobrien
2298159952Sobrien		m = data->m;
2299170589Syongari		if (nfe_jnewbuf(sc, sc->jrxq.jcur) != 0) {
2300170589Syongari			ifp->if_iqdrops++;
2301170589Syongari			nfe_discard_jrxbuf(sc, sc->jrxq.jcur);
2302170589Syongari			continue;
2303170589Syongari		}
2304159952Sobrien
2305170589Syongari		if ((vtag & NFE_RX_VTAG) != 0 &&
2306170589Syongari		    (ifp->if_capenable & IFCAP_VLAN_HWTAGGING) != 0) {
2307170589Syongari			m->m_pkthdr.ether_vtag = vtag & 0xffff;
2308170589Syongari			m->m_flags |= M_VLANTAG;
2309170589Syongari		}
2310170589Syongari
2311159952Sobrien		m->m_pkthdr.len = m->m_len = len;
2312159952Sobrien		m->m_pkthdr.rcvif = ifp;
2313159952Sobrien
2314170589Syongari		if ((ifp->if_capenable & IFCAP_RXCSUM) != 0) {
2315170589Syongari			if ((flags & NFE_RX_IP_CSUMOK) != 0) {
2316170589Syongari				m->m_pkthdr.csum_flags |= CSUM_IP_CHECKED;
2317159967Sobrien				m->m_pkthdr.csum_flags |= CSUM_IP_VALID;
2318170589Syongari				if ((flags & NFE_RX_TCP_CSUMOK) != 0 ||
2319170589Syongari				    (flags & NFE_RX_UDP_CSUMOK) != 0) {
2320170589Syongari					m->m_pkthdr.csum_flags |=
2321170589Syongari					    CSUM_DATA_VALID | CSUM_PSEUDO_HDR;
2322170589Syongari					m->m_pkthdr.csum_data = 0xffff;
2323170589Syongari				}
2324159967Sobrien			}
2325159952Sobrien		}
2326159952Sobrien
2327159952Sobrien		ifp->if_ipackets++;
2328159952Sobrien
2329159967Sobrien		NFE_UNLOCK(sc);
2330159967Sobrien		(*ifp->if_input)(ifp, m);
2331159967Sobrien		NFE_LOCK(sc);
2332193096Sattilio		rx_npkts++;
2333170589Syongari	}
2334159967Sobrien
2335170589Syongari	if (prog > 0)
2336170589Syongari		bus_dmamap_sync(sc->jrxq.jrx_desc_tag, sc->jrxq.jrx_desc_map,
2337170589Syongari		    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
2338159952Sobrien
2339193096Sattilio	if (rx_npktsp != NULL)
2340193096Sattilio		*rx_npktsp = rx_npkts;
2341170589Syongari	return (count > 0 ? 0 : EAGAIN);
2342159952Sobrien}
2343159952Sobrien
2344163503Sobrien
2345163503Sobrienstatic void
2346163503Sobriennfe_txeof(struct nfe_softc *sc)
2347159952Sobrien{
2348159967Sobrien	struct ifnet *ifp = sc->nfe_ifp;
2349159952Sobrien	struct nfe_desc32 *desc32;
2350159952Sobrien	struct nfe_desc64 *desc64;
2351159952Sobrien	struct nfe_tx_data *data = NULL;
2352170589Syongari	uint16_t flags;
2353170589Syongari	int cons, prog;
2354159952Sobrien
2355159967Sobrien	NFE_LOCK_ASSERT(sc);
2356159967Sobrien
2357170589Syongari	bus_dmamap_sync(sc->txq.tx_desc_tag, sc->txq.tx_desc_map,
2358170589Syongari	    BUS_DMASYNC_POSTREAD);
2359170589Syongari
2360170589Syongari	prog = 0;
2361170589Syongari	for (cons = sc->txq.next; cons != sc->txq.cur;
2362170589Syongari	    NFE_INC(cons, NFE_TX_RING_COUNT)) {
2363159967Sobrien		if (sc->nfe_flags & NFE_40BIT_ADDR) {
2364170589Syongari			desc64 = &sc->txq.desc64[cons];
2365170589Syongari			flags = le16toh(desc64->flags);
2366159952Sobrien		} else {
2367170589Syongari			desc32 = &sc->txq.desc32[cons];
2368170589Syongari			flags = le16toh(desc32->flags);
2369159952Sobrien		}
2370159952Sobrien
2371159952Sobrien		if (flags & NFE_TX_VALID)
2372159952Sobrien			break;
2373159952Sobrien
2374170589Syongari		prog++;
2375170589Syongari		sc->txq.queued--;
2376170589Syongari		data = &sc->txq.data[cons];
2377159952Sobrien
2378159967Sobrien		if ((sc->nfe_flags & (NFE_JUMBO_SUP | NFE_40BIT_ADDR)) == 0) {
2379170589Syongari			if ((flags & NFE_TX_LASTFRAG_V1) == 0)
2380170589Syongari				continue;
2381159952Sobrien			if ((flags & NFE_TX_ERROR_V1) != 0) {
2382170589Syongari				device_printf(sc->nfe_dev,
2383170589Syongari				    "tx v1 error 0x%4b\n", flags, NFE_V1_TXERR);
2384159967Sobrien
2385159952Sobrien				ifp->if_oerrors++;
2386159952Sobrien			} else
2387159952Sobrien				ifp->if_opackets++;
2388159952Sobrien		} else {
2389170589Syongari			if ((flags & NFE_TX_LASTFRAG_V2) == 0)
2390170589Syongari				continue;
2391159952Sobrien			if ((flags & NFE_TX_ERROR_V2) != 0) {
2392170589Syongari				device_printf(sc->nfe_dev,
2393170589Syongari				    "tx v2 error 0x%4b\n", flags, NFE_V2_TXERR);
2394159952Sobrien				ifp->if_oerrors++;
2395159952Sobrien			} else
2396159952Sobrien				ifp->if_opackets++;
2397159952Sobrien		}
2398159952Sobrien
2399159952Sobrien		/* last fragment of the mbuf chain transmitted */
2400170589Syongari		KASSERT(data->m != NULL, ("%s: freeing NULL mbuf!", __func__));
2401170589Syongari		bus_dmamap_sync(sc->txq.tx_data_tag, data->tx_data_map,
2402159967Sobrien		    BUS_DMASYNC_POSTWRITE);
2403170589Syongari		bus_dmamap_unload(sc->txq.tx_data_tag, data->tx_data_map);
2404159952Sobrien		m_freem(data->m);
2405159952Sobrien		data->m = NULL;
2406159952Sobrien	}
2407159952Sobrien
2408170589Syongari	if (prog > 0) {
2409170589Syongari		sc->nfe_force_tx = 0;
2410170589Syongari		sc->txq.next = cons;
2411159967Sobrien		ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
2412170589Syongari		if (sc->txq.queued == 0)
2413170589Syongari			sc->nfe_watchdog_timer = 0;
2414159952Sobrien	}
2415159952Sobrien}
2416159952Sobrien
2417163503Sobrienstatic int
2418170589Syongarinfe_encap(struct nfe_softc *sc, struct mbuf **m_head)
2419159952Sobrien{
2420170589Syongari	struct nfe_desc32 *desc32 = NULL;
2421170589Syongari	struct nfe_desc64 *desc64 = NULL;
2422159952Sobrien	bus_dmamap_t map;
2423163503Sobrien	bus_dma_segment_t segs[NFE_MAX_SCATTER];
2424170589Syongari	int error, i, nsegs, prod, si;
2425254803Sandre	uint32_t tsosegsz;
2426170589Syongari	uint16_t cflags, flags;
2427170589Syongari	struct mbuf *m;
2428159952Sobrien
2429170589Syongari	prod = si = sc->txq.cur;
2430170589Syongari	map = sc->txq.data[prod].tx_data_map;
2431159952Sobrien
2432170589Syongari	error = bus_dmamap_load_mbuf_sg(sc->txq.tx_data_tag, map, *m_head, segs,
2433159967Sobrien	    &nsegs, BUS_DMA_NOWAIT);
2434170589Syongari	if (error == EFBIG) {
2435243857Sglebius		m = m_collapse(*m_head, M_NOWAIT, NFE_MAX_SCATTER);
2436170589Syongari		if (m == NULL) {
2437170589Syongari			m_freem(*m_head);
2438170589Syongari			*m_head = NULL;
2439170589Syongari			return (ENOBUFS);
2440170589Syongari		}
2441170589Syongari		*m_head = m;
2442170589Syongari		error = bus_dmamap_load_mbuf_sg(sc->txq.tx_data_tag, map,
2443170589Syongari		    *m_head, segs, &nsegs, BUS_DMA_NOWAIT);
2444170589Syongari		if (error != 0) {
2445170589Syongari			m_freem(*m_head);
2446170589Syongari			*m_head = NULL;
2447170589Syongari			return (ENOBUFS);
2448170589Syongari		}
2449170589Syongari	} else if (error != 0)
2450170589Syongari		return (error);
2451170589Syongari	if (nsegs == 0) {
2452170589Syongari		m_freem(*m_head);
2453170589Syongari		*m_head = NULL;
2454170589Syongari		return (EIO);
2455159952Sobrien	}
2456159952Sobrien
2457170589Syongari	if (sc->txq.queued + nsegs >= NFE_TX_RING_COUNT - 2) {
2458159967Sobrien		bus_dmamap_unload(sc->txq.tx_data_tag, map);
2459170589Syongari		return (ENOBUFS);
2460159952Sobrien	}
2461159952Sobrien
2462170589Syongari	m = *m_head;
2463170589Syongari	cflags = flags = 0;
2464254803Sandre	tsosegsz = 0;
2465206876Syongari	if ((m->m_pkthdr.csum_flags & CSUM_TSO) != 0) {
2466254803Sandre		tsosegsz = (uint32_t)m->m_pkthdr.tso_segsz <<
2467206876Syongari		    NFE_TX_TSO_SHIFT;
2468206876Syongari		cflags &= ~(NFE_TX_IP_CSUM | NFE_TX_TCP_UDP_CSUM);
2469206876Syongari		cflags |= NFE_TX_TSO;
2470206876Syongari	} else if ((m->m_pkthdr.csum_flags & NFE_CSUM_FEATURES) != 0) {
2471170589Syongari		if ((m->m_pkthdr.csum_flags & CSUM_IP) != 0)
2472170589Syongari			cflags |= NFE_TX_IP_CSUM;
2473170589Syongari		if ((m->m_pkthdr.csum_flags & CSUM_TCP) != 0)
2474170589Syongari			cflags |= NFE_TX_TCP_UDP_CSUM;
2475170589Syongari		if ((m->m_pkthdr.csum_flags & CSUM_UDP) != 0)
2476170589Syongari			cflags |= NFE_TX_TCP_UDP_CSUM;
2477164656Sobrien	}
2478159967Sobrien
2479159967Sobrien	for (i = 0; i < nsegs; i++) {
2480159967Sobrien		if (sc->nfe_flags & NFE_40BIT_ADDR) {
2481170589Syongari			desc64 = &sc->txq.desc64[prod];
2482170589Syongari			desc64->physaddr[0] =
2483170589Syongari			    htole32(NFE_ADDR_HI(segs[i].ds_addr));
2484170589Syongari			desc64->physaddr[1] =
2485170589Syongari			    htole32(NFE_ADDR_LO(segs[i].ds_addr));
2486170589Syongari			desc64->vtag = 0;
2487159967Sobrien			desc64->length = htole16(segs[i].ds_len - 1);
2488159952Sobrien			desc64->flags = htole16(flags);
2489159952Sobrien		} else {
2490170589Syongari			desc32 = &sc->txq.desc32[prod];
2491170589Syongari			desc32->physaddr =
2492170589Syongari			    htole32(NFE_ADDR_LO(segs[i].ds_addr));
2493159967Sobrien			desc32->length = htole16(segs[i].ds_len - 1);
2494159952Sobrien			desc32->flags = htole16(flags);
2495159952Sobrien		}
2496159952Sobrien
2497170589Syongari		/*
2498170589Syongari		 * Setting of the valid bit in the first descriptor is
2499170589Syongari		 * deferred until the whole chain is fully setup.
2500170589Syongari		 */
2501170589Syongari		flags |= NFE_TX_VALID;
2502163503Sobrien
2503159952Sobrien		sc->txq.queued++;
2504170589Syongari		NFE_INC(prod, NFE_TX_RING_COUNT);
2505159952Sobrien	}
2506159952Sobrien
2507170589Syongari	/*
2508170589Syongari	 * the whole mbuf chain has been DMA mapped, fix last/first descriptor.
2509170589Syongari	 * csum flags, vtag and TSO belong to the first fragment only.
2510170589Syongari	 */
2511159967Sobrien	if (sc->nfe_flags & NFE_40BIT_ADDR) {
2512170589Syongari		desc64->flags |= htole16(NFE_TX_LASTFRAG_V2);
2513170589Syongari		desc64 = &sc->txq.desc64[si];
2514170589Syongari		if ((m->m_flags & M_VLANTAG) != 0)
2515170589Syongari			desc64->vtag = htole32(NFE_TX_VTAG |
2516170589Syongari			    m->m_pkthdr.ether_vtag);
2517254803Sandre		if (tsosegsz != 0) {
2518170589Syongari			/*
2519170589Syongari			 * XXX
2520170589Syongari			 * The following indicates the descriptor element
2521170589Syongari			 * is a 32bit quantity.
2522170589Syongari			 */
2523254803Sandre			desc64->length |= htole16((uint16_t)tsosegsz);
2524254803Sandre			desc64->flags |= htole16(tsosegsz >> 16);
2525170589Syongari		}
2526170589Syongari		/*
2527170589Syongari		 * finally, set the valid/checksum/TSO bit in the first
2528170589Syongari		 * descriptor.
2529170589Syongari		 */
2530170589Syongari		desc64->flags |= htole16(NFE_TX_VALID | cflags);
2531159952Sobrien	} else {
2532159967Sobrien		if (sc->nfe_flags & NFE_JUMBO_SUP)
2533170589Syongari			desc32->flags |= htole16(NFE_TX_LASTFRAG_V2);
2534159952Sobrien		else
2535170589Syongari			desc32->flags |= htole16(NFE_TX_LASTFRAG_V1);
2536170589Syongari		desc32 = &sc->txq.desc32[si];
2537254803Sandre		if (tsosegsz != 0) {
2538170589Syongari			/*
2539170589Syongari			 * XXX
2540170589Syongari			 * The following indicates the descriptor element
2541170589Syongari			 * is a 32bit quantity.
2542170589Syongari			 */
2543254803Sandre			desc32->length |= htole16((uint16_t)tsosegsz);
2544254803Sandre			desc32->flags |= htole16(tsosegsz >> 16);
2545170589Syongari		}
2546170589Syongari		/*
2547170589Syongari		 * finally, set the valid/checksum/TSO bit in the first
2548170589Syongari		 * descriptor.
2549170589Syongari		 */
2550170589Syongari		desc32->flags |= htole16(NFE_TX_VALID | cflags);
2551159952Sobrien	}
2552159952Sobrien
2553170589Syongari	sc->txq.cur = prod;
2554170589Syongari	prod = (prod + NFE_TX_RING_COUNT - 1) % NFE_TX_RING_COUNT;
2555170589Syongari	sc->txq.data[si].tx_data_map = sc->txq.data[prod].tx_data_map;
2556170589Syongari	sc->txq.data[prod].tx_data_map = map;
2557170589Syongari	sc->txq.data[prod].m = m;
2558159952Sobrien
2559159967Sobrien	bus_dmamap_sync(sc->txq.tx_data_tag, map, BUS_DMASYNC_PREWRITE);
2560159952Sobrien
2561170589Syongari	return (0);
2562159952Sobrien}
2563159952Sobrien
2564159967Sobrien
2565163503Sobrienstatic void
2566163503Sobriennfe_setmulti(struct nfe_softc *sc)
2567159952Sobrien{
2568159967Sobrien	struct ifnet *ifp = sc->nfe_ifp;
2569163503Sobrien	struct ifmultiaddr *ifma;
2570163503Sobrien	int i;
2571170589Syongari	uint32_t filter;
2572170589Syongari	uint8_t addr[ETHER_ADDR_LEN], mask[ETHER_ADDR_LEN];
2573170589Syongari	uint8_t etherbroadcastaddr[ETHER_ADDR_LEN] = {
2574163503Sobrien		0xff, 0xff, 0xff, 0xff, 0xff, 0xff
2575163503Sobrien	};
2576159967Sobrien
2577159967Sobrien	NFE_LOCK_ASSERT(sc);
2578159967Sobrien
2579159967Sobrien	if ((ifp->if_flags & (IFF_ALLMULTI | IFF_PROMISC)) != 0) {
2580159967Sobrien		bzero(addr, ETHER_ADDR_LEN);
2581159967Sobrien		bzero(mask, ETHER_ADDR_LEN);
2582159967Sobrien		goto done;
2583159967Sobrien	}
2584159967Sobrien
2585159967Sobrien	bcopy(etherbroadcastaddr, addr, ETHER_ADDR_LEN);
2586159967Sobrien	bcopy(etherbroadcastaddr, mask, ETHER_ADDR_LEN);
2587159967Sobrien
2588195049Srwatson	if_maddr_rlock(ifp);
2589159967Sobrien	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
2590159967Sobrien		u_char *addrp;
2591159967Sobrien
2592159967Sobrien		if (ifma->ifma_addr->sa_family != AF_LINK)
2593159967Sobrien			continue;
2594159967Sobrien
2595159967Sobrien		addrp = LLADDR((struct sockaddr_dl *) ifma->ifma_addr);
2596159967Sobrien		for (i = 0; i < ETHER_ADDR_LEN; i++) {
2597159967Sobrien			u_int8_t mcaddr = addrp[i];
2598159967Sobrien			addr[i] &= mcaddr;
2599159967Sobrien			mask[i] &= ~mcaddr;
2600159967Sobrien		}
2601159967Sobrien	}
2602195049Srwatson	if_maddr_runlock(ifp);
2603159967Sobrien
2604159967Sobrien	for (i = 0; i < ETHER_ADDR_LEN; i++) {
2605159967Sobrien		mask[i] |= addr[i];
2606159967Sobrien	}
2607159967Sobrien
2608159967Sobriendone:
2609159967Sobrien	addr[0] |= 0x01;	/* make sure multicast bit is set */
2610159967Sobrien
2611159967Sobrien	NFE_WRITE(sc, NFE_MULTIADDR_HI,
2612159967Sobrien	    addr[3] << 24 | addr[2] << 16 | addr[1] << 8 | addr[0]);
2613159967Sobrien	NFE_WRITE(sc, NFE_MULTIADDR_LO,
2614159967Sobrien	    addr[5] <<  8 | addr[4]);
2615159967Sobrien	NFE_WRITE(sc, NFE_MULTIMASK_HI,
2616159967Sobrien	    mask[3] << 24 | mask[2] << 16 | mask[1] << 8 | mask[0]);
2617159967Sobrien	NFE_WRITE(sc, NFE_MULTIMASK_LO,
2618159967Sobrien	    mask[5] <<  8 | mask[4]);
2619159967Sobrien
2620170589Syongari	filter = NFE_READ(sc, NFE_RXFILTER);
2621170589Syongari	filter &= NFE_PFF_RX_PAUSE;
2622170589Syongari	filter |= NFE_RXFILTER_MAGIC;
2623170589Syongari	filter |= (ifp->if_flags & IFF_PROMISC) ? NFE_PFF_PROMISC : NFE_PFF_U2M;
2624159967Sobrien	NFE_WRITE(sc, NFE_RXFILTER, filter);
2625159967Sobrien}
2626159967Sobrien
2627163503Sobrien
2628163503Sobrienstatic void
2629216925Sjhbnfe_start(struct ifnet *ifp)
2630159967Sobrien{
2631216925Sjhb	struct nfe_softc *sc = ifp->if_softc;
2632159967Sobrien
2633216925Sjhb	NFE_LOCK(sc);
2634216925Sjhb	nfe_start_locked(ifp);
2635216925Sjhb	NFE_UNLOCK(sc);
2636159967Sobrien}
2637159967Sobrien
2638163503Sobrienstatic void
2639216925Sjhbnfe_start_locked(struct ifnet *ifp)
2640159967Sobrien{
2641159952Sobrien	struct nfe_softc *sc = ifp->if_softc;
2642163503Sobrien	struct mbuf *m0;
2643170589Syongari	int enq;
2644159952Sobrien
2645216925Sjhb	NFE_LOCK_ASSERT(sc);
2646170589Syongari
2647170589Syongari	if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) !=
2648216925Sjhb	    IFF_DRV_RUNNING || sc->nfe_link == 0)
2649159967Sobrien		return;
2650159967Sobrien
2651170589Syongari	for (enq = 0; !IFQ_DRV_IS_EMPTY(&ifp->if_snd);) {
2652170589Syongari		IFQ_DRV_DEQUEUE(&ifp->if_snd, m0);
2653159952Sobrien		if (m0 == NULL)
2654159952Sobrien			break;
2655159952Sobrien
2656170589Syongari		if (nfe_encap(sc, &m0) != 0) {
2657170589Syongari			if (m0 == NULL)
2658170589Syongari				break;
2659170589Syongari			IFQ_DRV_PREPEND(&ifp->if_snd, m0);
2660159967Sobrien			ifp->if_drv_flags |= IFF_DRV_OACTIVE;
2661159952Sobrien			break;
2662159952Sobrien		}
2663170589Syongari		enq++;
2664167190Scsjp		ETHER_BPF_MTAP(ifp, m0);
2665159952Sobrien	}
2666159952Sobrien
2667170589Syongari	if (enq > 0) {
2668170589Syongari		bus_dmamap_sync(sc->txq.tx_desc_tag, sc->txq.tx_desc_map,
2669170589Syongari		    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
2670159952Sobrien
2671170589Syongari		/* kick Tx */
2672170589Syongari		NFE_WRITE(sc, NFE_RXTX_CTL, NFE_RXTX_KICKTX | sc->rxtxctl);
2673159952Sobrien
2674170589Syongari		/*
2675170589Syongari		 * Set a timeout in case the chip goes out to lunch.
2676170589Syongari		 */
2677170589Syongari		sc->nfe_watchdog_timer = 5;
2678170589Syongari	}
2679159952Sobrien}
2680159952Sobrien
2681163503Sobrien
2682163503Sobrienstatic void
2683163503Sobriennfe_watchdog(struct ifnet *ifp)
2684159952Sobrien{
2685159952Sobrien	struct nfe_softc *sc = ifp->if_softc;
2686159952Sobrien
2687170589Syongari	if (sc->nfe_watchdog_timer == 0 || --sc->nfe_watchdog_timer)
2688170589Syongari		return;
2689159952Sobrien
2690170589Syongari	/* Check if we've lost Tx completion interrupt. */
2691170589Syongari	nfe_txeof(sc);
2692170589Syongari	if (sc->txq.queued == 0) {
2693170589Syongari		if_printf(ifp, "watchdog timeout (missed Tx interrupts) "
2694170589Syongari		    "-- recovering\n");
2695170589Syongari		if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
2696216925Sjhb			nfe_start_locked(ifp);
2697170589Syongari		return;
2698170589Syongari	}
2699170589Syongari	/* Check if we've lost start Tx command. */
2700170589Syongari	sc->nfe_force_tx++;
2701170589Syongari	if (sc->nfe_force_tx <= 3) {
2702170589Syongari		/*
2703170589Syongari		 * If this is the case for watchdog timeout, the following
2704170589Syongari		 * code should go to nfe_txeof().
2705170589Syongari		 */
2706170589Syongari		NFE_WRITE(sc, NFE_RXTX_CTL, NFE_RXTX_KICKTX | sc->rxtxctl);
2707170589Syongari		return;
2708170589Syongari	}
2709170589Syongari	sc->nfe_force_tx = 0;
2710170589Syongari
2711170589Syongari	if_printf(ifp, "watchdog timeout\n");
2712170589Syongari
2713159967Sobrien	ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
2714159952Sobrien	ifp->if_oerrors++;
2715170589Syongari	nfe_init_locked(sc);
2716159952Sobrien}
2717159952Sobrien
2718163503Sobrien
2719163503Sobrienstatic void
2720163503Sobriennfe_init(void *xsc)
2721159952Sobrien{
2722159967Sobrien	struct nfe_softc *sc = xsc;
2723159952Sobrien
2724159967Sobrien	NFE_LOCK(sc);
2725159967Sobrien	nfe_init_locked(sc);
2726159967Sobrien	NFE_UNLOCK(sc);
2727159967Sobrien}
2728159967Sobrien
2729163503Sobrien
2730163503Sobrienstatic void
2731163503Sobriennfe_init_locked(void *xsc)
2732159967Sobrien{
2733159967Sobrien	struct nfe_softc *sc = xsc;
2734159967Sobrien	struct ifnet *ifp = sc->nfe_ifp;
2735159967Sobrien	struct mii_data *mii;
2736170589Syongari	uint32_t val;
2737170589Syongari	int error;
2738159967Sobrien
2739159967Sobrien	NFE_LOCK_ASSERT(sc);
2740159967Sobrien
2741159967Sobrien	mii = device_get_softc(sc->nfe_miibus);
2742159967Sobrien
2743170589Syongari	if (ifp->if_drv_flags & IFF_DRV_RUNNING)
2744159967Sobrien		return;
2745170589Syongari
2746170589Syongari	nfe_stop(ifp);
2747170589Syongari
2748170589Syongari	sc->nfe_framesize = ifp->if_mtu + NFE_RX_HEADERS;
2749170589Syongari
2750170589Syongari	nfe_init_tx_ring(sc, &sc->txq);
2751170589Syongari	if (sc->nfe_framesize > (MCLBYTES - ETHER_HDR_LEN))
2752170589Syongari		error = nfe_init_jrx_ring(sc, &sc->jrxq);
2753170589Syongari	else
2754170589Syongari		error = nfe_init_rx_ring(sc, &sc->rxq);
2755170589Syongari	if (error != 0) {
2756170589Syongari		device_printf(sc->nfe_dev,
2757170589Syongari		    "initialization failed: no memory for rx buffers\n");
2758170589Syongari		nfe_stop(ifp);
2759170589Syongari		return;
2760159967Sobrien	}
2761159967Sobrien
2762170589Syongari	val = 0;
2763170589Syongari	if ((sc->nfe_flags & NFE_CORRECT_MACADDR) != 0)
2764170589Syongari		val |= NFE_MAC_ADDR_INORDER;
2765170589Syongari	NFE_WRITE(sc, NFE_TX_UNK, val);
2766159952Sobrien	NFE_WRITE(sc, NFE_STATUS, 0);
2767159952Sobrien
2768170589Syongari	if ((sc->nfe_flags & NFE_TX_FLOW_CTRL) != 0)
2769170589Syongari		NFE_WRITE(sc, NFE_TX_PAUSE_FRAME, NFE_TX_PAUSE_FRAME_DISABLE);
2770170589Syongari
2771159952Sobrien	sc->rxtxctl = NFE_RXTX_BIT2;
2772159967Sobrien	if (sc->nfe_flags & NFE_40BIT_ADDR)
2773159952Sobrien		sc->rxtxctl |= NFE_RXTX_V3MAGIC;
2774159967Sobrien	else if (sc->nfe_flags & NFE_JUMBO_SUP)
2775159952Sobrien		sc->rxtxctl |= NFE_RXTX_V2MAGIC;
2776164656Sobrien
2777170589Syongari	if ((ifp->if_capenable & IFCAP_RXCSUM) != 0)
2778159952Sobrien		sc->rxtxctl |= NFE_RXTX_RXCSUM;
2779170589Syongari	if ((ifp->if_capenable & IFCAP_VLAN_HWTAGGING) != 0)
2780170589Syongari		sc->rxtxctl |= NFE_RXTX_VTAG_INSERT | NFE_RXTX_VTAG_STRIP;
2781159967Sobrien
2782159952Sobrien	NFE_WRITE(sc, NFE_RXTX_CTL, NFE_RXTX_RESET | sc->rxtxctl);
2783159952Sobrien	DELAY(10);
2784159952Sobrien	NFE_WRITE(sc, NFE_RXTX_CTL, sc->rxtxctl);
2785159952Sobrien
2786170589Syongari	if ((ifp->if_capenable & IFCAP_VLAN_HWTAGGING) != 0)
2787159952Sobrien		NFE_WRITE(sc, NFE_VTAG_CTL, NFE_VTAG_ENABLE);
2788170589Syongari	else
2789170589Syongari		NFE_WRITE(sc, NFE_VTAG_CTL, 0);
2790159952Sobrien
2791159952Sobrien	NFE_WRITE(sc, NFE_SETUP_R6, 0);
2792159952Sobrien
2793159952Sobrien	/* set MAC address */
2794170589Syongari	nfe_set_macaddr(sc, IF_LLADDR(ifp));
2795159952Sobrien
2796159952Sobrien	/* tell MAC where rings are in memory */
2797170589Syongari	if (sc->nfe_framesize > MCLBYTES - ETHER_HDR_LEN) {
2798170589Syongari		NFE_WRITE(sc, NFE_RX_RING_ADDR_HI,
2799170589Syongari		    NFE_ADDR_HI(sc->jrxq.jphysaddr));
2800170589Syongari		NFE_WRITE(sc, NFE_RX_RING_ADDR_LO,
2801170589Syongari		    NFE_ADDR_LO(sc->jrxq.jphysaddr));
2802170589Syongari	} else {
2803170589Syongari		NFE_WRITE(sc, NFE_RX_RING_ADDR_HI,
2804170589Syongari		    NFE_ADDR_HI(sc->rxq.physaddr));
2805170589Syongari		NFE_WRITE(sc, NFE_RX_RING_ADDR_LO,
2806170589Syongari		    NFE_ADDR_LO(sc->rxq.physaddr));
2807170589Syongari	}
2808170589Syongari	NFE_WRITE(sc, NFE_TX_RING_ADDR_HI, NFE_ADDR_HI(sc->txq.physaddr));
2809170589Syongari	NFE_WRITE(sc, NFE_TX_RING_ADDR_LO, NFE_ADDR_LO(sc->txq.physaddr));
2810159952Sobrien
2811159952Sobrien	NFE_WRITE(sc, NFE_RING_SIZE,
2812159952Sobrien	    (NFE_RX_RING_COUNT - 1) << 16 |
2813159952Sobrien	    (NFE_TX_RING_COUNT - 1));
2814159952Sobrien
2815170589Syongari	NFE_WRITE(sc, NFE_RXBUFSZ, sc->nfe_framesize);
2816159952Sobrien
2817159952Sobrien	/* force MAC to wakeup */
2818170589Syongari	val = NFE_READ(sc, NFE_PWR_STATE);
2819170589Syongari	if ((val & NFE_PWR_WAKEUP) == 0)
2820170589Syongari		NFE_WRITE(sc, NFE_PWR_STATE, val | NFE_PWR_WAKEUP);
2821159952Sobrien	DELAY(10);
2822170589Syongari	val = NFE_READ(sc, NFE_PWR_STATE);
2823170589Syongari	NFE_WRITE(sc, NFE_PWR_STATE, val | NFE_PWR_VALID);
2824159952Sobrien
2825159952Sobrien#if 1
2826159952Sobrien	/* configure interrupts coalescing/mitigation */
2827159952Sobrien	NFE_WRITE(sc, NFE_IMTIMER, NFE_IM_DEFAULT);
2828159952Sobrien#else
2829159952Sobrien	/* no interrupt mitigation: one interrupt per packet */
2830159952Sobrien	NFE_WRITE(sc, NFE_IMTIMER, 970);
2831159952Sobrien#endif
2832159952Sobrien
2833170589Syongari	NFE_WRITE(sc, NFE_SETUP_R1, NFE_R1_MAGIC_10_100);
2834159952Sobrien	NFE_WRITE(sc, NFE_SETUP_R2, NFE_R2_MAGIC);
2835159952Sobrien	NFE_WRITE(sc, NFE_SETUP_R6, NFE_R6_MAGIC);
2836159952Sobrien
2837159952Sobrien	/* update MAC knowledge of PHY; generates a NFE_IRQ_LINK interrupt */
2838159952Sobrien	NFE_WRITE(sc, NFE_STATUS, sc->mii_phyaddr << 24 | NFE_STATUS_MAGIC);
2839159952Sobrien
2840159952Sobrien	NFE_WRITE(sc, NFE_SETUP_R4, NFE_R4_MAGIC);
2841215132Syongari	/* Disable WOL. */
2842215132Syongari	NFE_WRITE(sc, NFE_WOL_CTL, 0);
2843159952Sobrien
2844159952Sobrien	sc->rxtxctl &= ~NFE_RXTX_BIT2;
2845159952Sobrien	NFE_WRITE(sc, NFE_RXTX_CTL, sc->rxtxctl);
2846159952Sobrien	DELAY(10);
2847159952Sobrien	NFE_WRITE(sc, NFE_RXTX_CTL, NFE_RXTX_BIT1 | sc->rxtxctl);
2848159952Sobrien
2849159952Sobrien	/* set Rx filter */
2850159952Sobrien	nfe_setmulti(sc);
2851159952Sobrien
2852159952Sobrien	/* enable Rx */
2853159952Sobrien	NFE_WRITE(sc, NFE_RX_CTL, NFE_RX_START);
2854159952Sobrien
2855159952Sobrien	/* enable Tx */
2856159952Sobrien	NFE_WRITE(sc, NFE_TX_CTL, NFE_TX_START);
2857159952Sobrien
2858159952Sobrien	NFE_WRITE(sc, NFE_PHY_STATUS, 0xf);
2859159952Sobrien
2860183561Syongari	/* Clear hardware stats. */
2861183561Syongari	nfe_stats_clear(sc);
2862183561Syongari
2863159967Sobrien#ifdef DEVICE_POLLING
2864159967Sobrien	if (ifp->if_capenable & IFCAP_POLLING)
2865170589Syongari		nfe_disable_intr(sc);
2866159967Sobrien	else
2867159967Sobrien#endif
2868170589Syongari	nfe_set_intr(sc);
2869170589Syongari	nfe_enable_intr(sc); /* enable interrupts */
2870159952Sobrien
2871159967Sobrien	ifp->if_drv_flags |= IFF_DRV_RUNNING;
2872159967Sobrien	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
2873159952Sobrien
2874159967Sobrien	sc->nfe_link = 0;
2875170589Syongari	mii_mediachg(mii);
2876159952Sobrien
2877170589Syongari	callout_reset(&sc->nfe_stat_ch, hz, nfe_tick, sc);
2878159952Sobrien}
2879159952Sobrien
2880163503Sobrien
2881163503Sobrienstatic void
2882170589Syongarinfe_stop(struct ifnet *ifp)
2883159952Sobrien{
2884159952Sobrien	struct nfe_softc *sc = ifp->if_softc;
2885170589Syongari	struct nfe_rx_ring *rx_ring;
2886170589Syongari	struct nfe_jrx_ring *jrx_ring;
2887170589Syongari	struct nfe_tx_ring *tx_ring;
2888170589Syongari	struct nfe_rx_data *rdata;
2889170589Syongari	struct nfe_tx_data *tdata;
2890170589Syongari	int i;
2891159952Sobrien
2892159967Sobrien	NFE_LOCK_ASSERT(sc);
2893159952Sobrien
2894170589Syongari	sc->nfe_watchdog_timer = 0;
2895159967Sobrien	ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
2896159952Sobrien
2897159967Sobrien	callout_stop(&sc->nfe_stat_ch);
2898159967Sobrien
2899159952Sobrien	/* abort Tx */
2900159952Sobrien	NFE_WRITE(sc, NFE_TX_CTL, 0);
2901159952Sobrien
2902159952Sobrien	/* disable Rx */
2903159952Sobrien	NFE_WRITE(sc, NFE_RX_CTL, 0);
2904159952Sobrien
2905159952Sobrien	/* disable interrupts */
2906170589Syongari	nfe_disable_intr(sc);
2907159952Sobrien
2908159967Sobrien	sc->nfe_link = 0;
2909159967Sobrien
2910170589Syongari	/* free Rx and Tx mbufs still in the queues. */
2911170589Syongari	rx_ring = &sc->rxq;
2912170589Syongari	for (i = 0; i < NFE_RX_RING_COUNT; i++) {
2913170589Syongari		rdata = &rx_ring->data[i];
2914170589Syongari		if (rdata->m != NULL) {
2915170589Syongari			bus_dmamap_sync(rx_ring->rx_data_tag,
2916170589Syongari			    rdata->rx_data_map, BUS_DMASYNC_POSTREAD);
2917170589Syongari			bus_dmamap_unload(rx_ring->rx_data_tag,
2918170589Syongari			    rdata->rx_data_map);
2919170589Syongari			m_freem(rdata->m);
2920170589Syongari			rdata->m = NULL;
2921170589Syongari		}
2922170589Syongari	}
2923159952Sobrien
2924170589Syongari	if ((sc->nfe_flags & NFE_JUMBO_SUP) != 0) {
2925170589Syongari		jrx_ring = &sc->jrxq;
2926170589Syongari		for (i = 0; i < NFE_JUMBO_RX_RING_COUNT; i++) {
2927170589Syongari			rdata = &jrx_ring->jdata[i];
2928170589Syongari			if (rdata->m != NULL) {
2929170589Syongari				bus_dmamap_sync(jrx_ring->jrx_data_tag,
2930170589Syongari				    rdata->rx_data_map, BUS_DMASYNC_POSTREAD);
2931170589Syongari				bus_dmamap_unload(jrx_ring->jrx_data_tag,
2932170589Syongari				    rdata->rx_data_map);
2933170589Syongari				m_freem(rdata->m);
2934170589Syongari				rdata->m = NULL;
2935170589Syongari			}
2936170589Syongari		}
2937170589Syongari	}
2938170589Syongari
2939170589Syongari	tx_ring = &sc->txq;
2940170589Syongari	for (i = 0; i < NFE_RX_RING_COUNT; i++) {
2941170589Syongari		tdata = &tx_ring->data[i];
2942170589Syongari		if (tdata->m != NULL) {
2943170589Syongari			bus_dmamap_sync(tx_ring->tx_data_tag,
2944170589Syongari			    tdata->tx_data_map, BUS_DMASYNC_POSTWRITE);
2945170589Syongari			bus_dmamap_unload(tx_ring->tx_data_tag,
2946170589Syongari			    tdata->tx_data_map);
2947170589Syongari			m_freem(tdata->m);
2948170589Syongari			tdata->m = NULL;
2949170589Syongari		}
2950170589Syongari	}
2951183561Syongari	/* Update hardware stats. */
2952183561Syongari	nfe_stats_update(sc);
2953159952Sobrien}
2954159952Sobrien
2955163503Sobrien
2956163503Sobrienstatic int
2957163503Sobriennfe_ifmedia_upd(struct ifnet *ifp)
2958159952Sobrien{
2959159967Sobrien	struct nfe_softc *sc = ifp->if_softc;
2960170589Syongari	struct mii_data *mii;
2961159952Sobrien
2962159967Sobrien	NFE_LOCK(sc);
2963159967Sobrien	mii = device_get_softc(sc->nfe_miibus);
2964159967Sobrien	mii_mediachg(mii);
2965170589Syongari	NFE_UNLOCK(sc);
2966159967Sobrien
2967159967Sobrien	return (0);
2968159952Sobrien}
2969159952Sobrien
2970163503Sobrien
2971163503Sobrienstatic void
2972163503Sobriennfe_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
2973159952Sobrien{
2974163503Sobrien	struct nfe_softc *sc;
2975163503Sobrien	struct mii_data *mii;
2976159952Sobrien
2977159967Sobrien	sc = ifp->if_softc;
2978159952Sobrien
2979159967Sobrien	NFE_LOCK(sc);
2980159967Sobrien	mii = device_get_softc(sc->nfe_miibus);
2981159967Sobrien	mii_pollstat(mii);
2982159952Sobrien
2983159967Sobrien	ifmr->ifm_active = mii->mii_media_active;
2984159967Sobrien	ifmr->ifm_status = mii->mii_media_status;
2985226478Syongari	NFE_UNLOCK(sc);
2986159952Sobrien}
2987159952Sobrien
2988163503Sobrien
2989170589Syongarivoid
2990159967Sobriennfe_tick(void *xsc)
2991159952Sobrien{
2992159967Sobrien	struct nfe_softc *sc;
2993163503Sobrien	struct mii_data *mii;
2994163503Sobrien	struct ifnet *ifp;
2995159952Sobrien
2996170589Syongari	sc = (struct nfe_softc *)xsc;
2997159952Sobrien
2998163503Sobrien	NFE_LOCK_ASSERT(sc);
2999159952Sobrien
3000159967Sobrien	ifp = sc->nfe_ifp;
3001159952Sobrien
3002159967Sobrien	mii = device_get_softc(sc->nfe_miibus);
3003159967Sobrien	mii_tick(mii);
3004183561Syongari	nfe_stats_update(sc);
3005170589Syongari	nfe_watchdog(ifp);
3006159967Sobrien	callout_reset(&sc->nfe_stat_ch, hz, nfe_tick, sc);
3007159952Sobrien}
3008159952Sobrien
3009159952Sobrien
3010173839Syongaristatic int
3011163503Sobriennfe_shutdown(device_t dev)
3012159952Sobrien{
3013159952Sobrien
3014215132Syongari	return (nfe_suspend(dev));
3015159952Sobrien}
3016159952Sobrien
3017159952Sobrien
3018163503Sobrienstatic void
3019170589Syongarinfe_get_macaddr(struct nfe_softc *sc, uint8_t *addr)
3020159952Sobrien{
3021170589Syongari	uint32_t val;
3022159952Sobrien
3023170589Syongari	if ((sc->nfe_flags & NFE_CORRECT_MACADDR) == 0) {
3024170589Syongari		val = NFE_READ(sc, NFE_MACADDR_LO);
3025170589Syongari		addr[0] = (val >> 8) & 0xff;
3026170589Syongari		addr[1] = (val & 0xff);
3027159952Sobrien
3028170589Syongari		val = NFE_READ(sc, NFE_MACADDR_HI);
3029170589Syongari		addr[2] = (val >> 24) & 0xff;
3030170589Syongari		addr[3] = (val >> 16) & 0xff;
3031170589Syongari		addr[4] = (val >>  8) & 0xff;
3032170589Syongari		addr[5] = (val & 0xff);
3033170589Syongari	} else {
3034170589Syongari		val = NFE_READ(sc, NFE_MACADDR_LO);
3035170589Syongari		addr[5] = (val >> 8) & 0xff;
3036170589Syongari		addr[4] = (val & 0xff);
3037170589Syongari
3038170589Syongari		val = NFE_READ(sc, NFE_MACADDR_HI);
3039170589Syongari		addr[3] = (val >> 24) & 0xff;
3040170589Syongari		addr[2] = (val >> 16) & 0xff;
3041170589Syongari		addr[1] = (val >>  8) & 0xff;
3042170589Syongari		addr[0] = (val & 0xff);
3043170589Syongari	}
3044159952Sobrien}
3045159952Sobrien
3046163503Sobrien
3047163503Sobrienstatic void
3048170589Syongarinfe_set_macaddr(struct nfe_softc *sc, uint8_t *addr)
3049159952Sobrien{
3050159967Sobrien
3051159967Sobrien	NFE_WRITE(sc, NFE_MACADDR_LO, addr[5] <<  8 | addr[4]);
3052159967Sobrien	NFE_WRITE(sc, NFE_MACADDR_HI, addr[3] << 24 | addr[2] << 16 |
3053159967Sobrien	    addr[1] << 8 | addr[0]);
3054159952Sobrien}
3055159952Sobrien
3056163503Sobrien
3057159967Sobrien/*
3058159967Sobrien * Map a single buffer address.
3059159967Sobrien */
3060159967Sobrien
3061159967Sobrienstatic void
3062170589Syongarinfe_dma_map_segs(void *arg, bus_dma_segment_t *segs, int nseg, int error)
3063159952Sobrien{
3064170589Syongari	struct nfe_dmamap_arg *ctx;
3065159952Sobrien
3066170589Syongari	if (error != 0)
3067159967Sobrien		return;
3068159952Sobrien
3069159967Sobrien	KASSERT(nseg == 1, ("too many DMA segments, %d should be 1", nseg));
3070159967Sobrien
3071170589Syongari	ctx = (struct nfe_dmamap_arg *)arg;
3072170589Syongari	ctx->nfe_busaddr = segs[0].ds_addr;
3073170589Syongari}
3074159967Sobrien
3075170589Syongari
3076170589Syongaristatic int
3077170589Syongarisysctl_int_range(SYSCTL_HANDLER_ARGS, int low, int high)
3078170589Syongari{
3079170589Syongari	int error, value;
3080170589Syongari
3081170589Syongari	if (!arg1)
3082170589Syongari		return (EINVAL);
3083170589Syongari	value = *(int *)arg1;
3084170589Syongari	error = sysctl_handle_int(oidp, &value, 0, req);
3085170589Syongari	if (error || !req->newptr)
3086170589Syongari		return (error);
3087170589Syongari	if (value < low || value > high)
3088170589Syongari		return (EINVAL);
3089170589Syongari	*(int *)arg1 = value;
3090170589Syongari
3091170589Syongari	return (0);
3092159952Sobrien}
3093170589Syongari
3094170589Syongari
3095170589Syongaristatic int
3096170589Syongarisysctl_hw_nfe_proc_limit(SYSCTL_HANDLER_ARGS)
3097170589Syongari{
3098170589Syongari
3099170589Syongari	return (sysctl_int_range(oidp, arg1, arg2, req, NFE_PROC_MIN,
3100170589Syongari	    NFE_PROC_MAX));
3101170589Syongari}
3102183561Syongari
3103183561Syongari
3104183561Syongari#define	NFE_SYSCTL_STAT_ADD32(c, h, n, p, d)	\
3105183561Syongari	    SYSCTL_ADD_UINT(c, h, OID_AUTO, n, CTLFLAG_RD, p, 0, d)
3106183561Syongari#define	NFE_SYSCTL_STAT_ADD64(c, h, n, p, d)	\
3107217323Smdf	    SYSCTL_ADD_UQUAD(c, h, OID_AUTO, n, CTLFLAG_RD, p, d)
3108183561Syongari
3109183561Syongaristatic void
3110183561Syongarinfe_sysctl_node(struct nfe_softc *sc)
3111183561Syongari{
3112183561Syongari	struct sysctl_ctx_list *ctx;
3113183561Syongari	struct sysctl_oid_list *child, *parent;
3114183561Syongari	struct sysctl_oid *tree;
3115183561Syongari	struct nfe_hw_stats *stats;
3116183561Syongari	int error;
3117183561Syongari
3118183561Syongari	stats = &sc->nfe_stats;
3119183561Syongari	ctx = device_get_sysctl_ctx(sc->nfe_dev);
3120183561Syongari	child = SYSCTL_CHILDREN(device_get_sysctl_tree(sc->nfe_dev));
3121183561Syongari	SYSCTL_ADD_PROC(ctx, child,
3122183561Syongari	    OID_AUTO, "process_limit", CTLTYPE_INT | CTLFLAG_RW,
3123183561Syongari	    &sc->nfe_process_limit, 0, sysctl_hw_nfe_proc_limit, "I",
3124183561Syongari	    "max number of Rx events to process");
3125183561Syongari
3126183561Syongari	sc->nfe_process_limit = NFE_PROC_DEFAULT;
3127183561Syongari	error = resource_int_value(device_get_name(sc->nfe_dev),
3128183561Syongari	    device_get_unit(sc->nfe_dev), "process_limit",
3129183561Syongari	    &sc->nfe_process_limit);
3130183561Syongari	if (error == 0) {
3131183561Syongari		if (sc->nfe_process_limit < NFE_PROC_MIN ||
3132183561Syongari		    sc->nfe_process_limit > NFE_PROC_MAX) {
3133183561Syongari			device_printf(sc->nfe_dev,
3134183561Syongari			    "process_limit value out of range; "
3135183561Syongari			    "using default: %d\n", NFE_PROC_DEFAULT);
3136183561Syongari			sc->nfe_process_limit = NFE_PROC_DEFAULT;
3137183561Syongari		}
3138183561Syongari	}
3139183561Syongari
3140183561Syongari	if ((sc->nfe_flags & (NFE_MIB_V1 | NFE_MIB_V2 | NFE_MIB_V3)) == 0)
3141183561Syongari		return;
3142183561Syongari
3143183561Syongari	tree = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "stats", CTLFLAG_RD,
3144183561Syongari	    NULL, "NFE statistics");
3145183561Syongari	parent = SYSCTL_CHILDREN(tree);
3146183561Syongari
3147183561Syongari	/* Rx statistics. */
3148183561Syongari	tree = SYSCTL_ADD_NODE(ctx, parent, OID_AUTO, "rx", CTLFLAG_RD,
3149183561Syongari	    NULL, "Rx MAC statistics");
3150183561Syongari	child = SYSCTL_CHILDREN(tree);
3151183561Syongari
3152183561Syongari	NFE_SYSCTL_STAT_ADD32(ctx, child, "frame_errors",
3153183561Syongari	    &stats->rx_frame_errors, "Framing Errors");
3154183561Syongari	NFE_SYSCTL_STAT_ADD32(ctx, child, "extra_bytes",
3155183561Syongari	    &stats->rx_extra_bytes, "Extra Bytes");
3156183561Syongari	NFE_SYSCTL_STAT_ADD32(ctx, child, "late_cols",
3157183561Syongari	    &stats->rx_late_cols, "Late Collisions");
3158183561Syongari	NFE_SYSCTL_STAT_ADD32(ctx, child, "runts",
3159183561Syongari	    &stats->rx_runts, "Runts");
3160183561Syongari	NFE_SYSCTL_STAT_ADD32(ctx, child, "jumbos",
3161183561Syongari	    &stats->rx_jumbos, "Jumbos");
3162183561Syongari	NFE_SYSCTL_STAT_ADD32(ctx, child, "fifo_overuns",
3163183561Syongari	    &stats->rx_fifo_overuns, "FIFO Overruns");
3164183561Syongari	NFE_SYSCTL_STAT_ADD32(ctx, child, "crc_errors",
3165183561Syongari	    &stats->rx_crc_errors, "CRC Errors");
3166183561Syongari	NFE_SYSCTL_STAT_ADD32(ctx, child, "fae",
3167183561Syongari	    &stats->rx_fae, "Frame Alignment Errors");
3168183561Syongari	NFE_SYSCTL_STAT_ADD32(ctx, child, "len_errors",
3169183561Syongari	    &stats->rx_len_errors, "Length Errors");
3170183561Syongari	NFE_SYSCTL_STAT_ADD32(ctx, child, "unicast",
3171183561Syongari	    &stats->rx_unicast, "Unicast Frames");
3172183561Syongari	NFE_SYSCTL_STAT_ADD32(ctx, child, "multicast",
3173183561Syongari	    &stats->rx_multicast, "Multicast Frames");
3174186346Syongari	NFE_SYSCTL_STAT_ADD32(ctx, child, "broadcast",
3175183561Syongari	    &stats->rx_broadcast, "Broadcast Frames");
3176183561Syongari	if ((sc->nfe_flags & NFE_MIB_V2) != 0) {
3177183561Syongari		NFE_SYSCTL_STAT_ADD64(ctx, child, "octets",
3178183561Syongari		    &stats->rx_octets, "Octets");
3179183561Syongari		NFE_SYSCTL_STAT_ADD32(ctx, child, "pause",
3180183561Syongari		    &stats->rx_pause, "Pause frames");
3181183561Syongari		NFE_SYSCTL_STAT_ADD32(ctx, child, "drops",
3182183561Syongari		    &stats->rx_drops, "Drop frames");
3183183561Syongari	}
3184183561Syongari
3185183561Syongari	/* Tx statistics. */
3186183561Syongari	tree = SYSCTL_ADD_NODE(ctx, parent, OID_AUTO, "tx", CTLFLAG_RD,
3187183561Syongari	    NULL, "Tx MAC statistics");
3188183561Syongari	child = SYSCTL_CHILDREN(tree);
3189183561Syongari	NFE_SYSCTL_STAT_ADD64(ctx, child, "octets",
3190183561Syongari	    &stats->tx_octets, "Octets");
3191183561Syongari	NFE_SYSCTL_STAT_ADD32(ctx, child, "zero_rexmits",
3192183561Syongari	    &stats->tx_zero_rexmits, "Zero Retransmits");
3193183561Syongari	NFE_SYSCTL_STAT_ADD32(ctx, child, "one_rexmits",
3194183561Syongari	    &stats->tx_one_rexmits, "One Retransmits");
3195183561Syongari	NFE_SYSCTL_STAT_ADD32(ctx, child, "multi_rexmits",
3196183561Syongari	    &stats->tx_multi_rexmits, "Multiple Retransmits");
3197183561Syongari	NFE_SYSCTL_STAT_ADD32(ctx, child, "late_cols",
3198183561Syongari	    &stats->tx_late_cols, "Late Collisions");
3199183561Syongari	NFE_SYSCTL_STAT_ADD32(ctx, child, "fifo_underuns",
3200183561Syongari	    &stats->tx_fifo_underuns, "FIFO Underruns");
3201183561Syongari	NFE_SYSCTL_STAT_ADD32(ctx, child, "carrier_losts",
3202183561Syongari	    &stats->tx_carrier_losts, "Carrier Losts");
3203183561Syongari	NFE_SYSCTL_STAT_ADD32(ctx, child, "excess_deferrals",
3204183561Syongari	    &stats->tx_excess_deferals, "Excess Deferrals");
3205183561Syongari	NFE_SYSCTL_STAT_ADD32(ctx, child, "retry_errors",
3206183561Syongari	    &stats->tx_retry_errors, "Retry Errors");
3207183561Syongari	if ((sc->nfe_flags & NFE_MIB_V2) != 0) {
3208183561Syongari		NFE_SYSCTL_STAT_ADD32(ctx, child, "deferrals",
3209183561Syongari		    &stats->tx_deferals, "Deferrals");
3210183561Syongari		NFE_SYSCTL_STAT_ADD32(ctx, child, "frames",
3211183561Syongari		    &stats->tx_frames, "Frames");
3212183561Syongari		NFE_SYSCTL_STAT_ADD32(ctx, child, "pause",
3213183561Syongari		    &stats->tx_pause, "Pause Frames");
3214183561Syongari	}
3215183561Syongari	if ((sc->nfe_flags & NFE_MIB_V3) != 0) {
3216183561Syongari		NFE_SYSCTL_STAT_ADD32(ctx, child, "unicast",
3217183561Syongari		    &stats->tx_deferals, "Unicast Frames");
3218183561Syongari		NFE_SYSCTL_STAT_ADD32(ctx, child, "multicast",
3219183561Syongari		    &stats->tx_frames, "Multicast Frames");
3220183561Syongari		NFE_SYSCTL_STAT_ADD32(ctx, child, "broadcast",
3221183561Syongari		    &stats->tx_pause, "Broadcast Frames");
3222183561Syongari	}
3223183561Syongari}
3224183561Syongari
3225183561Syongari#undef NFE_SYSCTL_STAT_ADD32
3226183561Syongari#undef NFE_SYSCTL_STAT_ADD64
3227183561Syongari
3228183561Syongaristatic void
3229183561Syongarinfe_stats_clear(struct nfe_softc *sc)
3230183561Syongari{
3231183561Syongari	int i, mib_cnt;
3232183561Syongari
3233183561Syongari	if ((sc->nfe_flags & NFE_MIB_V1) != 0)
3234183561Syongari		mib_cnt = NFE_NUM_MIB_STATV1;
3235183561Syongari	else if ((sc->nfe_flags & (NFE_MIB_V2 | NFE_MIB_V3)) != 0)
3236183561Syongari		mib_cnt = NFE_NUM_MIB_STATV2;
3237183561Syongari	else
3238183561Syongari		return;
3239183561Syongari
3240256038Syongari	for (i = 0; i < mib_cnt; i++)
3241256038Syongari		NFE_READ(sc, NFE_TX_OCTET + i * sizeof(uint32_t));
3242183561Syongari
3243183561Syongari	if ((sc->nfe_flags & NFE_MIB_V3) != 0) {
3244183561Syongari		NFE_READ(sc, NFE_TX_UNICAST);
3245183561Syongari		NFE_READ(sc, NFE_TX_MULTICAST);
3246183561Syongari		NFE_READ(sc, NFE_TX_BROADCAST);
3247183561Syongari	}
3248183561Syongari}
3249183561Syongari
3250183561Syongaristatic void
3251183561Syongarinfe_stats_update(struct nfe_softc *sc)
3252183561Syongari{
3253183561Syongari	struct nfe_hw_stats *stats;
3254183561Syongari
3255183561Syongari	NFE_LOCK_ASSERT(sc);
3256183561Syongari
3257183561Syongari	if ((sc->nfe_flags & (NFE_MIB_V1 | NFE_MIB_V2 | NFE_MIB_V3)) == 0)
3258183561Syongari		return;
3259183561Syongari
3260183561Syongari	stats = &sc->nfe_stats;
3261183561Syongari	stats->tx_octets += NFE_READ(sc, NFE_TX_OCTET);
3262183561Syongari	stats->tx_zero_rexmits += NFE_READ(sc, NFE_TX_ZERO_REXMIT);
3263183561Syongari	stats->tx_one_rexmits += NFE_READ(sc, NFE_TX_ONE_REXMIT);
3264183561Syongari	stats->tx_multi_rexmits += NFE_READ(sc, NFE_TX_MULTI_REXMIT);
3265183561Syongari	stats->tx_late_cols += NFE_READ(sc, NFE_TX_LATE_COL);
3266183561Syongari	stats->tx_fifo_underuns += NFE_READ(sc, NFE_TX_FIFO_UNDERUN);
3267183561Syongari	stats->tx_carrier_losts += NFE_READ(sc, NFE_TX_CARRIER_LOST);
3268183561Syongari	stats->tx_excess_deferals += NFE_READ(sc, NFE_TX_EXCESS_DEFERRAL);
3269183561Syongari	stats->tx_retry_errors += NFE_READ(sc, NFE_TX_RETRY_ERROR);
3270183561Syongari	stats->rx_frame_errors += NFE_READ(sc, NFE_RX_FRAME_ERROR);
3271183561Syongari	stats->rx_extra_bytes += NFE_READ(sc, NFE_RX_EXTRA_BYTES);
3272183561Syongari	stats->rx_late_cols += NFE_READ(sc, NFE_RX_LATE_COL);
3273183561Syongari	stats->rx_runts += NFE_READ(sc, NFE_RX_RUNT);
3274183561Syongari	stats->rx_jumbos += NFE_READ(sc, NFE_RX_JUMBO);
3275183561Syongari	stats->rx_fifo_overuns += NFE_READ(sc, NFE_RX_FIFO_OVERUN);
3276183561Syongari	stats->rx_crc_errors += NFE_READ(sc, NFE_RX_CRC_ERROR);
3277183561Syongari	stats->rx_fae += NFE_READ(sc, NFE_RX_FAE);
3278183561Syongari	stats->rx_len_errors += NFE_READ(sc, NFE_RX_LEN_ERROR);
3279183561Syongari	stats->rx_unicast += NFE_READ(sc, NFE_RX_UNICAST);
3280183561Syongari	stats->rx_multicast += NFE_READ(sc, NFE_RX_MULTICAST);
3281183561Syongari	stats->rx_broadcast += NFE_READ(sc, NFE_RX_BROADCAST);
3282183561Syongari
3283183561Syongari	if ((sc->nfe_flags & NFE_MIB_V2) != 0) {
3284183561Syongari		stats->tx_deferals += NFE_READ(sc, NFE_TX_DEFERAL);
3285183561Syongari		stats->tx_frames += NFE_READ(sc, NFE_TX_FRAME);
3286183561Syongari		stats->rx_octets += NFE_READ(sc, NFE_RX_OCTET);
3287183561Syongari		stats->tx_pause += NFE_READ(sc, NFE_TX_PAUSE);
3288183561Syongari		stats->rx_pause += NFE_READ(sc, NFE_RX_PAUSE);
3289183561Syongari		stats->rx_drops += NFE_READ(sc, NFE_RX_DROP);
3290183561Syongari	}
3291183561Syongari
3292183561Syongari	if ((sc->nfe_flags & NFE_MIB_V3) != 0) {
3293183561Syongari		stats->tx_unicast += NFE_READ(sc, NFE_TX_UNICAST);
3294183561Syongari		stats->tx_multicast += NFE_READ(sc, NFE_TX_MULTICAST);
3295255648Sdelphij		stats->tx_broadcast += NFE_READ(sc, NFE_TX_BROADCAST);
3296183561Syongari	}
3297183561Syongari}
3298215132Syongari
3299215132Syongari
3300215132Syongaristatic void
3301215132Syongarinfe_set_linkspeed(struct nfe_softc *sc)
3302215132Syongari{
3303215132Syongari	struct mii_softc *miisc;
3304215132Syongari	struct mii_data *mii;
3305215132Syongari	int aneg, i, phyno;
3306215132Syongari
3307215132Syongari	NFE_LOCK_ASSERT(sc);
3308215132Syongari
3309215132Syongari	mii = device_get_softc(sc->nfe_miibus);
3310215132Syongari	mii_pollstat(mii);
3311215132Syongari	aneg = 0;
3312215132Syongari	if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) ==
3313215132Syongari	    (IFM_ACTIVE | IFM_AVALID)) {
3314215132Syongari		switch IFM_SUBTYPE(mii->mii_media_active) {
3315215132Syongari		case IFM_10_T:
3316215132Syongari		case IFM_100_TX:
3317215132Syongari			return;
3318215132Syongari		case IFM_1000_T:
3319215132Syongari			aneg++;
3320215132Syongari			break;
3321215132Syongari		default:
3322215132Syongari			break;
3323215132Syongari		}
3324215132Syongari	}
3325221407Smarius	miisc = LIST_FIRST(&mii->mii_phys);
3326221407Smarius	phyno = miisc->mii_phy;
3327221407Smarius	LIST_FOREACH(miisc, &mii->mii_phys, mii_list)
3328221407Smarius		PHY_RESET(miisc);
3329215132Syongari	nfe_miibus_writereg(sc->nfe_dev, phyno, MII_100T2CR, 0);
3330215132Syongari	nfe_miibus_writereg(sc->nfe_dev, phyno,
3331215132Syongari	    MII_ANAR, ANAR_TX_FD | ANAR_TX | ANAR_10_FD | ANAR_10 | ANAR_CSMA);
3332215132Syongari	nfe_miibus_writereg(sc->nfe_dev, phyno,
3333215132Syongari	    MII_BMCR, BMCR_RESET | BMCR_AUTOEN | BMCR_STARTNEG);
3334215132Syongari	DELAY(1000);
3335215132Syongari	if (aneg != 0) {
3336215132Syongari		/*
3337215132Syongari		 * Poll link state until nfe(4) get a 10/100Mbps link.
3338215132Syongari		 */
3339215132Syongari		for (i = 0; i < MII_ANEGTICKS_GIGE; i++) {
3340215132Syongari			mii_pollstat(mii);
3341215132Syongari			if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID))
3342215132Syongari			    == (IFM_ACTIVE | IFM_AVALID)) {
3343215132Syongari				switch (IFM_SUBTYPE(mii->mii_media_active)) {
3344215132Syongari				case IFM_10_T:
3345215132Syongari				case IFM_100_TX:
3346215132Syongari					nfe_mac_config(sc, mii);
3347215132Syongari					return;
3348215132Syongari				default:
3349215132Syongari					break;
3350215132Syongari				}
3351215132Syongari			}
3352215132Syongari			NFE_UNLOCK(sc);
3353215132Syongari			pause("nfelnk", hz);
3354215132Syongari			NFE_LOCK(sc);
3355215132Syongari		}
3356215132Syongari		if (i == MII_ANEGTICKS_GIGE)
3357215132Syongari			device_printf(sc->nfe_dev,
3358215132Syongari			    "establishing a link failed, WOL may not work!");
3359215132Syongari	}
3360215132Syongari	/*
3361215132Syongari	 * No link, force MAC to have 100Mbps, full-duplex link.
3362215132Syongari	 * This is the last resort and may/may not work.
3363215132Syongari	 */
3364215132Syongari	mii->mii_media_status = IFM_AVALID | IFM_ACTIVE;
3365215132Syongari	mii->mii_media_active = IFM_ETHER | IFM_100_TX | IFM_FDX;
3366215132Syongari	nfe_mac_config(sc, mii);
3367215132Syongari}
3368215132Syongari
3369215132Syongari
3370215132Syongaristatic void
3371215132Syongarinfe_set_wol(struct nfe_softc *sc)
3372215132Syongari{
3373215132Syongari	struct ifnet *ifp;
3374215132Syongari	uint32_t wolctl;
3375215132Syongari	int pmc;
3376215132Syongari	uint16_t pmstat;
3377215132Syongari
3378215132Syongari	NFE_LOCK_ASSERT(sc);
3379215132Syongari
3380219902Sjhb	if (pci_find_cap(sc->nfe_dev, PCIY_PMG, &pmc) != 0)
3381215132Syongari		return;
3382215132Syongari	ifp = sc->nfe_ifp;
3383215132Syongari	if ((ifp->if_capenable & IFCAP_WOL_MAGIC) != 0)
3384215132Syongari		wolctl = NFE_WOL_MAGIC;
3385215132Syongari	else
3386215132Syongari		wolctl = 0;
3387215132Syongari	NFE_WRITE(sc, NFE_WOL_CTL, wolctl);
3388215132Syongari	if ((ifp->if_capenable & IFCAP_WOL_MAGIC) != 0) {
3389215132Syongari		nfe_set_linkspeed(sc);
3390215132Syongari		if ((sc->nfe_flags & NFE_PWR_MGMT) != 0)
3391215132Syongari			NFE_WRITE(sc, NFE_PWR2_CTL,
3392215132Syongari			    NFE_READ(sc, NFE_PWR2_CTL) & ~NFE_PWR2_GATE_CLOCKS);
3393215132Syongari		/* Enable RX. */
3394215132Syongari		NFE_WRITE(sc, NFE_RX_RING_ADDR_HI, 0);
3395215132Syongari		NFE_WRITE(sc, NFE_RX_RING_ADDR_LO, 0);
3396215132Syongari		NFE_WRITE(sc, NFE_RX_CTL, NFE_READ(sc, NFE_RX_CTL) |
3397215132Syongari		    NFE_RX_START);
3398215132Syongari	}
3399215132Syongari	/* Request PME if WOL is requested. */
3400215132Syongari	pmstat = pci_read_config(sc->nfe_dev, pmc + PCIR_POWER_STATUS, 2);
3401215132Syongari	pmstat &= ~(PCIM_PSTAT_PME | PCIM_PSTAT_PMEENABLE);
3402215132Syongari	if ((ifp->if_capenable & IFCAP_WOL) != 0)
3403215132Syongari		pmstat |= PCIM_PSTAT_PME | PCIM_PSTAT_PMEENABLE;
3404215132Syongari	pci_write_config(sc->nfe_dev, pmc + PCIR_POWER_STATUS, pmstat, 2);
3405215132Syongari}
3406