if_nfe.c revision 175418
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 175418 2008-01-17 23:37:47Z jhb $");
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>
44159967Sobrien#include <net/if_arp.h>
45159967Sobrien#include <net/ethernet.h>
46159952Sobrien#include <net/if_dl.h>
47159952Sobrien#include <net/if_media.h>
48159952Sobrien#include <net/if_types.h>
49159952Sobrien#include <net/if_vlan_var.h>
50159952Sobrien
51159952Sobrien#include <net/bpf.h>
52159952Sobrien
53159967Sobrien#include <machine/bus.h>
54159967Sobrien#include <machine/resource.h>
55159967Sobrien#include <sys/bus.h>
56159967Sobrien#include <sys/rman.h>
57159967Sobrien
58159952Sobrien#include <dev/mii/mii.h>
59159952Sobrien#include <dev/mii/miivar.h>
60159952Sobrien
61159952Sobrien#include <dev/pci/pcireg.h>
62159952Sobrien#include <dev/pci/pcivar.h>
63159952Sobrien
64159967Sobrien#include <dev/nfe/if_nfereg.h>
65159967Sobrien#include <dev/nfe/if_nfevar.h>
66159952Sobrien
67159967SobrienMODULE_DEPEND(nfe, pci, 1, 1, 1);
68159967SobrienMODULE_DEPEND(nfe, ether, 1, 1, 1);
69159967SobrienMODULE_DEPEND(nfe, miibus, 1, 1, 1);
70170589Syongari
71170589Syongari/* "device miibus" required.  See GENERIC if you get errors here. */
72159967Sobrien#include "miibus_if.h"
73159952Sobrien
74163503Sobrienstatic int  nfe_probe(device_t);
75163503Sobrienstatic int  nfe_attach(device_t);
76163503Sobrienstatic int  nfe_detach(device_t);
77170589Syongaristatic int  nfe_suspend(device_t);
78170589Syongaristatic int  nfe_resume(device_t);
79173839Syongaristatic int nfe_shutdown(device_t);
80170589Syongaristatic void nfe_power(struct nfe_softc *);
81163503Sobrienstatic int  nfe_miibus_readreg(device_t, int, int);
82163503Sobrienstatic int  nfe_miibus_writereg(device_t, int, int, int);
83163503Sobrienstatic void nfe_miibus_statchg(device_t);
84170589Syongaristatic void nfe_link_task(void *, int);
85170589Syongaristatic void nfe_set_intr(struct nfe_softc *);
86170589Syongaristatic __inline void nfe_enable_intr(struct nfe_softc *);
87170589Syongaristatic __inline void nfe_disable_intr(struct nfe_softc *);
88163503Sobrienstatic int  nfe_ioctl(struct ifnet *, u_long, caddr_t);
89170589Syongaristatic void nfe_alloc_msix(struct nfe_softc *, int);
90170589Syongaristatic int nfe_intr(void *);
91170589Syongaristatic void nfe_int_task(void *, int);
92170589Syongaristatic void *nfe_jalloc(struct nfe_softc *);
93170589Syongaristatic void nfe_jfree(void *, void *);
94170589Syongaristatic __inline void nfe_discard_rxbuf(struct nfe_softc *, int);
95170589Syongaristatic __inline void nfe_discard_jrxbuf(struct nfe_softc *, int);
96170589Syongaristatic int nfe_newbuf(struct nfe_softc *, int);
97170589Syongaristatic int nfe_jnewbuf(struct nfe_softc *, int);
98170589Syongaristatic int  nfe_rxeof(struct nfe_softc *, int);
99170589Syongaristatic int  nfe_jrxeof(struct nfe_softc *, int);
100159967Sobrienstatic void nfe_txeof(struct nfe_softc *);
101170589Syongaristatic int  nfe_encap(struct nfe_softc *, struct mbuf **);
102159967Sobrienstatic void nfe_setmulti(struct nfe_softc *);
103170589Syongaristatic void nfe_tx_task(void *, int);
104159967Sobrienstatic void nfe_start(struct ifnet *);
105159967Sobrienstatic void nfe_watchdog(struct ifnet *);
106159967Sobrienstatic void nfe_init(void *);
107159967Sobrienstatic void nfe_init_locked(void *);
108170589Syongaristatic void nfe_stop(struct ifnet *);
109159967Sobrienstatic int  nfe_alloc_rx_ring(struct nfe_softc *, struct nfe_rx_ring *);
110171559Syongaristatic void nfe_alloc_jrx_ring(struct nfe_softc *, struct nfe_jrx_ring *);
111170589Syongaristatic int  nfe_init_rx_ring(struct nfe_softc *, struct nfe_rx_ring *);
112170589Syongaristatic int  nfe_init_jrx_ring(struct nfe_softc *, struct nfe_jrx_ring *);
113159967Sobrienstatic void nfe_free_rx_ring(struct nfe_softc *, struct nfe_rx_ring *);
114170589Syongaristatic void nfe_free_jrx_ring(struct nfe_softc *, struct nfe_jrx_ring *);
115159967Sobrienstatic int  nfe_alloc_tx_ring(struct nfe_softc *, struct nfe_tx_ring *);
116170589Syongaristatic void nfe_init_tx_ring(struct nfe_softc *, struct nfe_tx_ring *);
117159967Sobrienstatic void nfe_free_tx_ring(struct nfe_softc *, struct nfe_tx_ring *);
118159967Sobrienstatic int  nfe_ifmedia_upd(struct ifnet *);
119159967Sobrienstatic void nfe_ifmedia_sts(struct ifnet *, struct ifmediareq *);
120159967Sobrienstatic void nfe_tick(void *);
121170589Syongaristatic void nfe_get_macaddr(struct nfe_softc *, uint8_t *);
122170589Syongaristatic void nfe_set_macaddr(struct nfe_softc *, uint8_t *);
123170589Syongaristatic void nfe_dma_map_segs(void *, bus_dma_segment_t *, int, int);
124159952Sobrien
125170589Syongaristatic int sysctl_int_range(SYSCTL_HANDLER_ARGS, int, int);
126170589Syongaristatic int sysctl_hw_nfe_proc_limit(SYSCTL_HANDLER_ARGS);
127170589Syongari
128159952Sobrien#ifdef NFE_DEBUG
129170589Syongaristatic int nfedebug = 0;
130170589Syongari#define	DPRINTF(sc, ...)	do {				\
131170589Syongari	if (nfedebug)						\
132170589Syongari		device_printf((sc)->nfe_dev, __VA_ARGS__);	\
133170589Syongari} while (0)
134170589Syongari#define	DPRINTFN(sc, n, ...)	do {				\
135170589Syongari	if (nfedebug >= (n))					\
136170589Syongari		device_printf((sc)->nfe_dev, __VA_ARGS__);	\
137170589Syongari} while (0)
138159952Sobrien#else
139170589Syongari#define	DPRINTF(sc, ...)
140170589Syongari#define	DPRINTFN(sc, n, ...)
141159952Sobrien#endif
142159952Sobrien
143159967Sobrien#define	NFE_LOCK(_sc)		mtx_lock(&(_sc)->nfe_mtx)
144159967Sobrien#define	NFE_UNLOCK(_sc)		mtx_unlock(&(_sc)->nfe_mtx)
145159967Sobrien#define	NFE_LOCK_ASSERT(_sc)	mtx_assert(&(_sc)->nfe_mtx, MA_OWNED)
146159967Sobrien
147170589Syongari#define	NFE_JLIST_LOCK(_sc)	mtx_lock(&(_sc)->nfe_jlist_mtx)
148170589Syongari#define	NFE_JLIST_UNLOCK(_sc)	mtx_unlock(&(_sc)->nfe_jlist_mtx)
149159967Sobrien
150170589Syongari/* Tunables. */
151170589Syongaristatic int msi_disable = 0;
152170589Syongaristatic int msix_disable = 0;
153171559Syongaristatic int jumbo_disable = 0;
154170589SyongariTUNABLE_INT("hw.nfe.msi_disable", &msi_disable);
155170589SyongariTUNABLE_INT("hw.nfe.msix_disable", &msix_disable);
156171559SyongariTUNABLE_INT("hw.nfe.jumbo_disable", &jumbo_disable);
157159967Sobrien
158159967Sobrienstatic device_method_t nfe_methods[] = {
159159967Sobrien	/* Device interface */
160159967Sobrien	DEVMETHOD(device_probe,		nfe_probe),
161159967Sobrien	DEVMETHOD(device_attach,	nfe_attach),
162159967Sobrien	DEVMETHOD(device_detach,	nfe_detach),
163170589Syongari	DEVMETHOD(device_suspend,	nfe_suspend),
164170589Syongari	DEVMETHOD(device_resume,	nfe_resume),
165159967Sobrien	DEVMETHOD(device_shutdown,	nfe_shutdown),
166159967Sobrien
167159967Sobrien	/* bus interface */
168159967Sobrien	DEVMETHOD(bus_print_child,	bus_generic_print_child),
169159967Sobrien	DEVMETHOD(bus_driver_added,	bus_generic_driver_added),
170159967Sobrien
171159967Sobrien	/* MII interface */
172159967Sobrien	DEVMETHOD(miibus_readreg,	nfe_miibus_readreg),
173159967Sobrien	DEVMETHOD(miibus_writereg,	nfe_miibus_writereg),
174163503Sobrien	DEVMETHOD(miibus_statchg,	nfe_miibus_statchg),
175159967Sobrien
176170589Syongari	{ NULL, NULL }
177159952Sobrien};
178159952Sobrien
179159967Sobrienstatic driver_t nfe_driver = {
180159967Sobrien	"nfe",
181159967Sobrien	nfe_methods,
182159967Sobrien	sizeof(struct nfe_softc)
183159967Sobrien};
184159967Sobrien
185159967Sobrienstatic devclass_t nfe_devclass;
186159967Sobrien
187159967SobrienDRIVER_MODULE(nfe, pci, nfe_driver, nfe_devclass, 0, 0);
188159967SobrienDRIVER_MODULE(miibus, nfe, miibus_driver, miibus_devclass, 0, 0);
189159967Sobrien
190159967Sobrienstatic struct nfe_type nfe_devs[] = {
191159967Sobrien	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE_LAN,
192163503Sobrien	    "NVIDIA nForce MCP Networking Adapter"},
193159967Sobrien	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE2_LAN,
194163503Sobrien	    "NVIDIA nForce2 MCP2 Networking Adapter"},
195159967Sobrien	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE2_400_LAN1,
196163503Sobrien	    "NVIDIA nForce2 400 MCP4 Networking Adapter"},
197159967Sobrien	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE2_400_LAN2,
198163503Sobrien	    "NVIDIA nForce2 400 MCP5 Networking Adapter"},
199163437Sobrien	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE3_LAN1,
200163503Sobrien	    "NVIDIA nForce3 MCP3 Networking Adapter"},
201159967Sobrien	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE3_250_LAN,
202163503Sobrien	    "NVIDIA nForce3 250 MCP6 Networking Adapter"},
203159967Sobrien	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE3_LAN4,
204163503Sobrien	    "NVIDIA nForce3 MCP7 Networking Adapter"},
205159967Sobrien	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE4_LAN1,
206163503Sobrien	    "NVIDIA nForce4 CK804 MCP8 Networking Adapter"},
207159967Sobrien	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE4_LAN2,
208163503Sobrien	    "NVIDIA nForce4 CK804 MCP9 Networking Adapter"},
209159967Sobrien	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP04_LAN1,
210170589Syongari	    "NVIDIA nForce MCP04 Networking Adapter"},		/* MCP10 */
211159967Sobrien	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP04_LAN2,
212170589Syongari	    "NVIDIA nForce MCP04 Networking Adapter"},		/* MCP11 */
213159967Sobrien	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE430_LAN1,
214163503Sobrien	    "NVIDIA nForce 430 MCP12 Networking Adapter"},
215159967Sobrien	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE430_LAN2,
216163503Sobrien	    "NVIDIA nForce 430 MCP13 Networking Adapter"},
217159967Sobrien	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP55_LAN1,
218163503Sobrien	    "NVIDIA nForce MCP55 Networking Adapter"},
219159967Sobrien	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP55_LAN2,
220163503Sobrien	    "NVIDIA nForce MCP55 Networking Adapter"},
221162212Sobrien	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP61_LAN1,
222163503Sobrien	    "NVIDIA nForce MCP61 Networking Adapter"},
223162212Sobrien	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP61_LAN2,
224163503Sobrien	    "NVIDIA nForce MCP61 Networking Adapter"},
225162212Sobrien	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP61_LAN3,
226163503Sobrien	    "NVIDIA nForce MCP61 Networking Adapter"},
227170589Syongari	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP61_LAN4,
228163503Sobrien	    "NVIDIA nForce MCP61 Networking Adapter"},
229162212Sobrien	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP65_LAN1,
230163503Sobrien	    "NVIDIA nForce MCP65 Networking Adapter"},
231162212Sobrien	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP65_LAN2,
232163503Sobrien	    "NVIDIA nForce MCP65 Networking Adapter"},
233162212Sobrien	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP65_LAN3,
234163503Sobrien	    "NVIDIA nForce MCP65 Networking Adapter"},
235170589Syongari	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP65_LAN4,
236163503Sobrien	    "NVIDIA nForce MCP65 Networking Adapter"},
237170589Syongari	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP67_LAN1,
238170589Syongari	    "NVIDIA nForce MCP67 Networking Adapter"},
239170589Syongari	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP67_LAN2,
240170589Syongari	    "NVIDIA nForce MCP67 Networking Adapter"},
241170589Syongari	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP67_LAN3,
242170589Syongari	    "NVIDIA nForce MCP67 Networking Adapter"},
243170589Syongari	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP67_LAN4,
244170589Syongari	    "NVIDIA nForce MCP67 Networking Adapter"},
245159967Sobrien	{0, 0, NULL}
246159967Sobrien};
247159967Sobrien
248159967Sobrien
249159967Sobrien/* Probe for supported hardware ID's */
250159967Sobrienstatic int
251159967Sobriennfe_probe(device_t dev)
252159952Sobrien{
253159967Sobrien	struct nfe_type *t;
254159967Sobrien
255159967Sobrien	t = nfe_devs;
256159967Sobrien	/* Check for matching PCI DEVICE ID's */
257159967Sobrien	while (t->name != NULL) {
258159967Sobrien		if ((pci_get_vendor(dev) == t->vid_id) &&
259159967Sobrien		    (pci_get_device(dev) == t->dev_id)) {
260159967Sobrien			device_set_desc(dev, t->name);
261170589Syongari			return (BUS_PROBE_DEFAULT);
262159967Sobrien		}
263159967Sobrien		t++;
264159967Sobrien	}
265159967Sobrien
266159967Sobrien	return (ENXIO);
267159952Sobrien}
268159952Sobrien
269170589Syongaristatic void
270170589Syongarinfe_alloc_msix(struct nfe_softc *sc, int count)
271170589Syongari{
272170589Syongari	int rid;
273163503Sobrien
274170589Syongari	rid = PCIR_BAR(2);
275170589Syongari	sc->nfe_msix_res = bus_alloc_resource_any(sc->nfe_dev, SYS_RES_MEMORY,
276170589Syongari	    &rid, RF_ACTIVE);
277170589Syongari	if (sc->nfe_msix_res == NULL) {
278170589Syongari		device_printf(sc->nfe_dev,
279170589Syongari		    "couldn't allocate MSIX table resource\n");
280170589Syongari		return;
281170589Syongari	}
282170589Syongari	rid = PCIR_BAR(3);
283170589Syongari	sc->nfe_msix_pba_res = bus_alloc_resource_any(sc->nfe_dev,
284170589Syongari	    SYS_RES_MEMORY, &rid, RF_ACTIVE);
285170589Syongari	if (sc->nfe_msix_pba_res == NULL) {
286170589Syongari		device_printf(sc->nfe_dev,
287170589Syongari		    "couldn't allocate MSIX PBA resource\n");
288170589Syongari		bus_release_resource(sc->nfe_dev, SYS_RES_MEMORY, PCIR_BAR(2),
289170589Syongari		    sc->nfe_msix_res);
290170589Syongari		sc->nfe_msix_res = NULL;
291170589Syongari		return;
292170589Syongari	}
293170589Syongari
294170589Syongari	if (pci_alloc_msix(sc->nfe_dev, &count) == 0) {
295170589Syongari		if (count == NFE_MSI_MESSAGES) {
296170589Syongari			if (bootverbose)
297170589Syongari				device_printf(sc->nfe_dev,
298170589Syongari				    "Using %d MSIX messages\n", count);
299170589Syongari			sc->nfe_msix = 1;
300170589Syongari		} else {
301170589Syongari			if (bootverbose)
302170589Syongari				device_printf(sc->nfe_dev,
303170589Syongari				    "couldn't allocate MSIX\n");
304170589Syongari			pci_release_msi(sc->nfe_dev);
305170589Syongari			bus_release_resource(sc->nfe_dev, SYS_RES_MEMORY,
306170589Syongari			    PCIR_BAR(3), sc->nfe_msix_pba_res);
307170589Syongari			bus_release_resource(sc->nfe_dev, SYS_RES_MEMORY,
308170589Syongari			    PCIR_BAR(2), sc->nfe_msix_res);
309170589Syongari			sc->nfe_msix_pba_res = NULL;
310170589Syongari			sc->nfe_msix_res = NULL;
311170589Syongari		}
312170589Syongari	}
313170589Syongari}
314170589Syongari
315159967Sobrienstatic int
316159967Sobriennfe_attach(device_t dev)
317159952Sobrien{
318159967Sobrien	struct nfe_softc *sc;
319159952Sobrien	struct ifnet *ifp;
320170589Syongari	bus_addr_t dma_addr_max;
321170589Syongari	int error = 0, i, msic, reg, rid;
322159952Sobrien
323159967Sobrien	sc = device_get_softc(dev);
324159967Sobrien	sc->nfe_dev = dev;
325159952Sobrien
326159967Sobrien	mtx_init(&sc->nfe_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK,
327170589Syongari	    MTX_DEF);
328170589Syongari	mtx_init(&sc->nfe_jlist_mtx, "nfe_jlist_mtx", NULL, MTX_DEF);
329159967Sobrien	callout_init_mtx(&sc->nfe_stat_ch, &sc->nfe_mtx, 0);
330170589Syongari	TASK_INIT(&sc->nfe_link_task, 0, nfe_link_task, sc);
331170589Syongari	SLIST_INIT(&sc->nfe_jfree_listhead);
332170589Syongari	SLIST_INIT(&sc->nfe_jinuse_listhead);
333159967Sobrien
334163503Sobrien	pci_enable_busmaster(dev);
335159967Sobrien
336170589Syongari	rid = PCIR_BAR(0);
337170589Syongari	sc->nfe_res[0] = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
338170589Syongari	    RF_ACTIVE);
339170589Syongari	if (sc->nfe_res[0] == NULL) {
340170589Syongari		device_printf(dev, "couldn't map memory resources\n");
341170589Syongari		mtx_destroy(&sc->nfe_mtx);
342170589Syongari		return (ENXIO);
343170589Syongari	}
344159967Sobrien
345170589Syongari	if (pci_find_extcap(dev, PCIY_EXPRESS, &reg) == 0) {
346170589Syongari		uint16_t v, width;
347170589Syongari
348170589Syongari		v = pci_read_config(dev, reg + 0x08, 2);
349170589Syongari		/* Change max. read request size to 4096. */
350170589Syongari		v &= ~(7 << 12);
351170589Syongari		v |= (5 << 12);
352170589Syongari		pci_write_config(dev, reg + 0x08, v, 2);
353170589Syongari
354170589Syongari		v = pci_read_config(dev, reg + 0x0c, 2);
355170589Syongari		/* link capability */
356170589Syongari		v = (v >> 4) & 0x0f;
357170589Syongari		width = pci_read_config(dev, reg + 0x12, 2);
358170589Syongari		/* negotiated link width */
359170589Syongari		width = (width >> 4) & 0x3f;
360170589Syongari		if (v != width)
361170589Syongari			device_printf(sc->nfe_dev,
362170589Syongari			    "warning, negotiated width of link(x%d) != "
363170589Syongari			    "max. width of link(x%d)\n", width, v);
364159952Sobrien	}
365159952Sobrien
366159967Sobrien	/* Allocate interrupt */
367170589Syongari	if (msix_disable == 0 || msi_disable == 0) {
368170589Syongari		if (msix_disable == 0 &&
369170589Syongari		    (msic = pci_msix_count(dev)) == NFE_MSI_MESSAGES)
370170589Syongari			nfe_alloc_msix(sc, msic);
371170589Syongari		if (msi_disable == 0 && sc->nfe_msix == 0 &&
372170589Syongari		    (msic = pci_msi_count(dev)) == NFE_MSI_MESSAGES &&
373170589Syongari		    pci_alloc_msi(dev, &msic) == 0) {
374170589Syongari			if (msic == NFE_MSI_MESSAGES) {
375170589Syongari				if (bootverbose)
376170589Syongari					device_printf(dev,
377170589Syongari					    "Using %d MSI messages\n", msic);
378170589Syongari				sc->nfe_msi = 1;
379170589Syongari			} else
380170589Syongari				pci_release_msi(dev);
381170589Syongari		}
382170589Syongari	}
383159967Sobrien
384170589Syongari	if (sc->nfe_msix == 0 && sc->nfe_msi == 0) {
385170589Syongari		rid = 0;
386170589Syongari		sc->nfe_irq[0] = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
387170589Syongari		    RF_SHAREABLE | RF_ACTIVE);
388170589Syongari		if (sc->nfe_irq[0] == NULL) {
389170589Syongari			device_printf(dev, "couldn't allocate IRQ resources\n");
390170589Syongari			error = ENXIO;
391170589Syongari			goto fail;
392170589Syongari		}
393170589Syongari	} else {
394170589Syongari		for (i = 0, rid = 1; i < NFE_MSI_MESSAGES; i++, rid++) {
395170589Syongari			sc->nfe_irq[i] = bus_alloc_resource_any(dev,
396170589Syongari			    SYS_RES_IRQ, &rid, RF_ACTIVE);
397170589Syongari			if (sc->nfe_irq[i] == NULL) {
398170589Syongari				device_printf(dev,
399170589Syongari				    "couldn't allocate IRQ resources for "
400170589Syongari				    "message %d\n", rid);
401170589Syongari				error = ENXIO;
402170589Syongari				goto fail;
403170589Syongari			}
404170589Syongari		}
405170589Syongari		/* Map interrupts to vector 0. */
406170589Syongari		if (sc->nfe_msix != 0) {
407170589Syongari			NFE_WRITE(sc, NFE_MSIX_MAP0, 0);
408170589Syongari			NFE_WRITE(sc, NFE_MSIX_MAP1, 0);
409170589Syongari		} else if (sc->nfe_msi != 0) {
410170589Syongari			NFE_WRITE(sc, NFE_MSI_MAP0, 0);
411170589Syongari			NFE_WRITE(sc, NFE_MSI_MAP1, 0);
412170589Syongari		}
413159952Sobrien	}
414159952Sobrien
415170589Syongari	/* Set IRQ status/mask register. */
416170589Syongari	sc->nfe_irq_status = NFE_IRQ_STATUS;
417170589Syongari	sc->nfe_irq_mask = NFE_IRQ_MASK;
418170589Syongari	sc->nfe_intrs = NFE_IRQ_WANTED;
419170589Syongari	sc->nfe_nointrs = 0;
420170589Syongari	if (sc->nfe_msix != 0) {
421170589Syongari		sc->nfe_irq_status = NFE_MSIX_IRQ_STATUS;
422170589Syongari		sc->nfe_nointrs = NFE_IRQ_WANTED;
423170589Syongari	} else if (sc->nfe_msi != 0) {
424170589Syongari		sc->nfe_irq_mask = NFE_MSI_IRQ_MASK;
425170589Syongari		sc->nfe_intrs = NFE_MSI_VECTOR_0_ENABLED;
426170589Syongari	}
427159952Sobrien
428170589Syongari	sc->nfe_devid = pci_get_device(dev);
429170589Syongari	sc->nfe_revid = pci_get_revid(dev);
430159967Sobrien	sc->nfe_flags = 0;
431159952Sobrien
432170589Syongari	switch (sc->nfe_devid) {
433159952Sobrien	case PCI_PRODUCT_NVIDIA_NFORCE3_LAN2:
434159952Sobrien	case PCI_PRODUCT_NVIDIA_NFORCE3_LAN3:
435159952Sobrien	case PCI_PRODUCT_NVIDIA_NFORCE3_LAN4:
436159952Sobrien	case PCI_PRODUCT_NVIDIA_NFORCE3_LAN5:
437159967Sobrien		sc->nfe_flags |= NFE_JUMBO_SUP | NFE_HW_CSUM;
438159952Sobrien		break;
439159952Sobrien	case PCI_PRODUCT_NVIDIA_MCP51_LAN1:
440159952Sobrien	case PCI_PRODUCT_NVIDIA_MCP51_LAN2:
441170589Syongari		sc->nfe_flags |= NFE_40BIT_ADDR | NFE_PWR_MGMT;
442159952Sobrien		break;
443159952Sobrien	case PCI_PRODUCT_NVIDIA_CK804_LAN1:
444159952Sobrien	case PCI_PRODUCT_NVIDIA_CK804_LAN2:
445159952Sobrien	case PCI_PRODUCT_NVIDIA_MCP04_LAN1:
446159952Sobrien	case PCI_PRODUCT_NVIDIA_MCP04_LAN2:
447159967Sobrien		sc->nfe_flags |= NFE_JUMBO_SUP | NFE_40BIT_ADDR | NFE_HW_CSUM;
448159952Sobrien		break;
449159952Sobrien	case PCI_PRODUCT_NVIDIA_MCP55_LAN1:
450159952Sobrien	case PCI_PRODUCT_NVIDIA_MCP55_LAN2:
451163503Sobrien		sc->nfe_flags |= NFE_JUMBO_SUP | NFE_40BIT_ADDR | NFE_HW_CSUM |
452170589Syongari		    NFE_HW_VLAN | NFE_PWR_MGMT | NFE_TX_FLOW_CTRL;
453159952Sobrien		break;
454170589Syongari
455162212Sobrien	case PCI_PRODUCT_NVIDIA_MCP61_LAN1:
456162212Sobrien	case PCI_PRODUCT_NVIDIA_MCP61_LAN2:
457162212Sobrien	case PCI_PRODUCT_NVIDIA_MCP61_LAN3:
458162212Sobrien	case PCI_PRODUCT_NVIDIA_MCP61_LAN4:
459170589Syongari	case PCI_PRODUCT_NVIDIA_MCP67_LAN1:
460170589Syongari	case PCI_PRODUCT_NVIDIA_MCP67_LAN2:
461170589Syongari	case PCI_PRODUCT_NVIDIA_MCP67_LAN3:
462170589Syongari	case PCI_PRODUCT_NVIDIA_MCP67_LAN4:
463170589Syongari		sc->nfe_flags |= NFE_40BIT_ADDR | NFE_PWR_MGMT |
464173377Syongari		    NFE_CORRECT_MACADDR | NFE_TX_FLOW_CTRL;
465162212Sobrien		break;
466162212Sobrien	case PCI_PRODUCT_NVIDIA_MCP65_LAN1:
467162212Sobrien	case PCI_PRODUCT_NVIDIA_MCP65_LAN2:
468162212Sobrien	case PCI_PRODUCT_NVIDIA_MCP65_LAN3:
469162212Sobrien	case PCI_PRODUCT_NVIDIA_MCP65_LAN4:
470170589Syongari		sc->nfe_flags |= NFE_JUMBO_SUP | NFE_40BIT_ADDR |
471173377Syongari		    NFE_PWR_MGMT | NFE_CORRECT_MACADDR | NFE_TX_FLOW_CTRL;
472163503Sobrien		break;
473159952Sobrien	}
474159952Sobrien
475170589Syongari	nfe_power(sc);
476170589Syongari	/* Check for reversed ethernet address */
477170589Syongari	if ((NFE_READ(sc, NFE_TX_UNK) & NFE_MAC_ADDR_INORDER) != 0)
478170589Syongari		sc->nfe_flags |= NFE_CORRECT_MACADDR;
479170589Syongari	nfe_get_macaddr(sc, sc->eaddr);
480159952Sobrien	/*
481159967Sobrien	 * Allocate the parent bus DMA tag appropriate for PCI.
482159967Sobrien	 */
483170589Syongari	dma_addr_max = BUS_SPACE_MAXADDR_32BIT;
484170589Syongari	if ((sc->nfe_flags & NFE_40BIT_ADDR) != 0)
485170589Syongari		dma_addr_max = NFE_DMA_MAXADDR;
486170589Syongari	error = bus_dma_tag_create(
487170589Syongari	    bus_get_dma_tag(sc->nfe_dev),	/* parent */
488163503Sobrien	    1, 0,				/* alignment, boundary */
489170589Syongari	    dma_addr_max,			/* lowaddr */
490163503Sobrien	    BUS_SPACE_MAXADDR,			/* highaddr */
491163503Sobrien	    NULL, NULL,				/* filter, filterarg */
492170589Syongari	    BUS_SPACE_MAXSIZE_32BIT, 0,		/* maxsize, nsegments */
493163503Sobrien	    BUS_SPACE_MAXSIZE_32BIT,		/* maxsegsize */
494170589Syongari	    0,					/* flags */
495163503Sobrien	    NULL, NULL,				/* lockfunc, lockarg */
496163503Sobrien	    &sc->nfe_parent_tag);
497159967Sobrien	if (error)
498159967Sobrien		goto fail;
499159967Sobrien
500164650Sobrien	ifp = sc->nfe_ifp = if_alloc(IFT_ETHER);
501164650Sobrien	if (ifp == NULL) {
502170589Syongari		device_printf(dev, "can not if_alloc()\n");
503164650Sobrien		error = ENOSPC;
504164650Sobrien		goto fail;
505164650Sobrien	}
506170589Syongari	TASK_INIT(&sc->nfe_tx_task, 1, nfe_tx_task, ifp);
507164650Sobrien
508159967Sobrien	/*
509159952Sobrien	 * Allocate Tx and Rx rings.
510159952Sobrien	 */
511170589Syongari	if ((error = nfe_alloc_tx_ring(sc, &sc->txq)) != 0)
512159967Sobrien		goto fail;
513159952Sobrien
514170589Syongari	if ((error = nfe_alloc_rx_ring(sc, &sc->rxq)) != 0)
515159967Sobrien		goto fail;
516170589Syongari
517171559Syongari	nfe_alloc_jrx_ring(sc, &sc->jrxq);
518170589Syongari
519170589Syongari	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
520170589Syongari	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
521170589Syongari	    OID_AUTO, "process_limit", CTLTYPE_INT | CTLFLAG_RW,
522170589Syongari	    &sc->nfe_process_limit, 0, sysctl_hw_nfe_proc_limit, "I",
523170589Syongari	    "max number of Rx events to process");
524170589Syongari
525170589Syongari	sc->nfe_process_limit = NFE_PROC_DEFAULT;
526170589Syongari	error = resource_int_value(device_get_name(dev), device_get_unit(dev),
527170589Syongari	    "process_limit", &sc->nfe_process_limit);
528170589Syongari	if (error == 0) {
529170589Syongari		if (sc->nfe_process_limit < NFE_PROC_MIN ||
530170589Syongari		    sc->nfe_process_limit > NFE_PROC_MAX) {
531170589Syongari			device_printf(dev, "process_limit value out of range; "
532170589Syongari			    "using default: %d\n", NFE_PROC_DEFAULT);
533170589Syongari			sc->nfe_process_limit = NFE_PROC_DEFAULT;
534170589Syongari		}
535159952Sobrien	}
536159952Sobrien
537159952Sobrien	ifp->if_softc = sc;
538159967Sobrien	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
539170589Syongari	ifp->if_mtu = ETHERMTU;
540159952Sobrien	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
541159952Sobrien	ifp->if_ioctl = nfe_ioctl;
542159952Sobrien	ifp->if_start = nfe_start;
543170589Syongari	ifp->if_hwassist = 0;
544170589Syongari	ifp->if_capabilities = 0;
545170589Syongari	ifp->if_watchdog = NULL;
546159952Sobrien	ifp->if_init = nfe_init;
547170589Syongari	IFQ_SET_MAXLEN(&ifp->if_snd, NFE_TX_RING_COUNT - 1);
548170589Syongari	ifp->if_snd.ifq_drv_maxlen = NFE_TX_RING_COUNT - 1;
549170589Syongari	IFQ_SET_READY(&ifp->if_snd);
550159952Sobrien
551170589Syongari	if (sc->nfe_flags & NFE_HW_CSUM) {
552170589Syongari		ifp->if_capabilities |= IFCAP_HWCSUM | IFCAP_TSO4;
553170589Syongari		ifp->if_hwassist |= NFE_CSUM_FEATURES | CSUM_TSO;
554170589Syongari	}
555170589Syongari	ifp->if_capenable = ifp->if_capabilities;
556164650Sobrien
557170589Syongari	sc->nfe_framesize = ifp->if_mtu + NFE_RX_HEADERS;
558170589Syongari	/* VLAN capability setup. */
559170589Syongari	ifp->if_capabilities |= IFCAP_VLAN_MTU;
560170589Syongari	if ((sc->nfe_flags & NFE_HW_VLAN) != 0) {
561159952Sobrien		ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING;
562170589Syongari		if ((ifp->if_capabilities & IFCAP_HWCSUM) != 0)
563170589Syongari			ifp->if_capabilities |= IFCAP_VLAN_HWCSUM;
564159952Sobrien	}
565159967Sobrien	ifp->if_capenable = ifp->if_capabilities;
566159952Sobrien
567170589Syongari	/*
568170589Syongari	 * Tell the upper layer(s) we support long frames.
569170589Syongari	 * Must appear after the call to ether_ifattach() because
570170589Syongari	 * ether_ifattach() sets ifi_hdrlen to the default value.
571170589Syongari	 */
572170589Syongari	ifp->if_data.ifi_hdrlen = sizeof(struct ether_vlan_header);
573170589Syongari
574159967Sobrien#ifdef DEVICE_POLLING
575159967Sobrien	ifp->if_capabilities |= IFCAP_POLLING;
576159967Sobrien#endif
577159952Sobrien
578159967Sobrien	/* Do MII setup */
579163503Sobrien	if (mii_phy_probe(dev, &sc->nfe_miibus, nfe_ifmedia_upd,
580163503Sobrien	    nfe_ifmedia_sts)) {
581170589Syongari		device_printf(dev, "MII without any phy!\n");
582159967Sobrien		error = ENXIO;
583159967Sobrien		goto fail;
584159967Sobrien	}
585159967Sobrien	ether_ifattach(ifp, sc->eaddr);
586159952Sobrien
587170589Syongari	TASK_INIT(&sc->nfe_int_task, 0, nfe_int_task, sc);
588170589Syongari	sc->nfe_tq = taskqueue_create_fast("nfe_taskq", M_WAITOK,
589170589Syongari	    taskqueue_thread_enqueue, &sc->nfe_tq);
590170589Syongari	taskqueue_start_threads(&sc->nfe_tq, 1, PI_NET, "%s taskq",
591170589Syongari	    device_get_nameunit(sc->nfe_dev));
592170589Syongari	error = 0;
593170589Syongari	if (sc->nfe_msi == 0 && sc->nfe_msix == 0) {
594170589Syongari		error = bus_setup_intr(dev, sc->nfe_irq[0],
595170589Syongari		    INTR_TYPE_NET | INTR_MPSAFE, nfe_intr, NULL, sc,
596170589Syongari		    &sc->nfe_intrhand[0]);
597170589Syongari	} else {
598170589Syongari		for (i = 0; i < NFE_MSI_MESSAGES; i++) {
599170589Syongari			error = bus_setup_intr(dev, sc->nfe_irq[i],
600170589Syongari			    INTR_TYPE_NET | INTR_MPSAFE, nfe_intr, NULL, sc,
601170589Syongari			    &sc->nfe_intrhand[i]);
602170589Syongari			if (error != 0)
603170589Syongari				break;
604170589Syongari		}
605170589Syongari	}
606159967Sobrien	if (error) {
607170589Syongari		device_printf(dev, "couldn't set up irq\n");
608170589Syongari		taskqueue_free(sc->nfe_tq);
609170589Syongari		sc->nfe_tq = NULL;
610159967Sobrien		ether_ifdetach(ifp);
611159967Sobrien		goto fail;
612159967Sobrien	}
613159967Sobrien
614159967Sobrienfail:
615159967Sobrien	if (error)
616159967Sobrien		nfe_detach(dev);
617159967Sobrien
618159967Sobrien	return (error);
619159952Sobrien}
620159952Sobrien
621159967Sobrien
622159967Sobrienstatic int
623159967Sobriennfe_detach(device_t dev)
624159952Sobrien{
625163503Sobrien	struct nfe_softc *sc;
626163503Sobrien	struct ifnet *ifp;
627170589Syongari	uint8_t eaddr[ETHER_ADDR_LEN];
628170589Syongari	int i, rid;
629159952Sobrien
630159967Sobrien	sc = device_get_softc(dev);
631159967Sobrien	KASSERT(mtx_initialized(&sc->nfe_mtx), ("nfe mutex not initialized"));
632159967Sobrien	ifp = sc->nfe_ifp;
633159967Sobrien
634159967Sobrien#ifdef DEVICE_POLLING
635170589Syongari	if (ifp != NULL && ifp->if_capenable & IFCAP_POLLING)
636159967Sobrien		ether_poll_deregister(ifp);
637159967Sobrien#endif
638159967Sobrien	if (device_is_attached(dev)) {
639164649Sobrien		NFE_LOCK(sc);
640170589Syongari		nfe_stop(ifp);
641159967Sobrien		ifp->if_flags &= ~IFF_UP;
642164649Sobrien		NFE_UNLOCK(sc);
643159967Sobrien		callout_drain(&sc->nfe_stat_ch);
644170589Syongari		taskqueue_drain(taskqueue_fast, &sc->nfe_tx_task);
645170589Syongari		taskqueue_drain(taskqueue_swi, &sc->nfe_link_task);
646159967Sobrien		ether_ifdetach(ifp);
647159967Sobrien	}
648159967Sobrien
649170589Syongari	if (ifp) {
650170589Syongari		/* restore ethernet address */
651170589Syongari		if ((sc->nfe_flags & NFE_CORRECT_MACADDR) == 0) {
652170589Syongari			for (i = 0; i < ETHER_ADDR_LEN; i++) {
653170589Syongari				eaddr[i] = sc->eaddr[5 - i];
654170589Syongari			}
655170589Syongari		} else
656170589Syongari			bcopy(sc->eaddr, eaddr, ETHER_ADDR_LEN);
657170589Syongari		nfe_set_macaddr(sc, eaddr);
658159967Sobrien		if_free(ifp);
659170589Syongari	}
660159967Sobrien	if (sc->nfe_miibus)
661159967Sobrien		device_delete_child(dev, sc->nfe_miibus);
662159967Sobrien	bus_generic_detach(dev);
663170589Syongari	if (sc->nfe_tq != NULL) {
664170589Syongari		taskqueue_drain(sc->nfe_tq, &sc->nfe_int_task);
665170589Syongari		taskqueue_free(sc->nfe_tq);
666170589Syongari		sc->nfe_tq = NULL;
667170589Syongari	}
668159967Sobrien
669170589Syongari	for (i = 0; i < NFE_MSI_MESSAGES; i++) {
670170589Syongari		if (sc->nfe_intrhand[i] != NULL) {
671170589Syongari			bus_teardown_intr(dev, sc->nfe_irq[i],
672170589Syongari			    sc->nfe_intrhand[i]);
673170589Syongari			sc->nfe_intrhand[i] = NULL;
674170589Syongari		}
675170589Syongari	}
676159967Sobrien
677170589Syongari	if (sc->nfe_msi == 0 && sc->nfe_msix == 0) {
678170589Syongari		if (sc->nfe_irq[0] != NULL)
679170589Syongari			bus_release_resource(dev, SYS_RES_IRQ, 0,
680170589Syongari			    sc->nfe_irq[0]);
681170589Syongari	} else {
682170589Syongari		for (i = 0, rid = 1; i < NFE_MSI_MESSAGES; i++, rid++) {
683170589Syongari			if (sc->nfe_irq[i] != NULL) {
684170589Syongari				bus_release_resource(dev, SYS_RES_IRQ, rid,
685170589Syongari				    sc->nfe_irq[i]);
686170589Syongari				sc->nfe_irq[i] = NULL;
687170589Syongari			}
688170589Syongari		}
689170589Syongari		pci_release_msi(dev);
690170589Syongari	}
691170589Syongari	if (sc->nfe_msix_pba_res != NULL) {
692170589Syongari		bus_release_resource(dev, SYS_RES_MEMORY, PCIR_BAR(3),
693170589Syongari		    sc->nfe_msix_pba_res);
694170589Syongari		sc->nfe_msix_pba_res = NULL;
695170589Syongari	}
696170589Syongari	if (sc->nfe_msix_res != NULL) {
697170589Syongari		bus_release_resource(dev, SYS_RES_MEMORY, PCIR_BAR(2),
698170589Syongari		    sc->nfe_msix_res);
699170589Syongari		sc->nfe_msix_res = NULL;
700170589Syongari	}
701170589Syongari	if (sc->nfe_res[0] != NULL) {
702170589Syongari		bus_release_resource(dev, SYS_RES_MEMORY, PCIR_BAR(0),
703170589Syongari		    sc->nfe_res[0]);
704170589Syongari		sc->nfe_res[0] = NULL;
705170589Syongari	}
706170589Syongari
707159967Sobrien	nfe_free_tx_ring(sc, &sc->txq);
708159967Sobrien	nfe_free_rx_ring(sc, &sc->rxq);
709170589Syongari	nfe_free_jrx_ring(sc, &sc->jrxq);
710159967Sobrien
711170589Syongari	if (sc->nfe_parent_tag) {
712159967Sobrien		bus_dma_tag_destroy(sc->nfe_parent_tag);
713170589Syongari		sc->nfe_parent_tag = NULL;
714170589Syongari	}
715159967Sobrien
716170589Syongari	mtx_destroy(&sc->nfe_jlist_mtx);
717159967Sobrien	mtx_destroy(&sc->nfe_mtx);
718159967Sobrien
719159967Sobrien	return (0);
720159952Sobrien}
721159952Sobrien
722159967Sobrien
723170589Syongaristatic int
724170589Syongarinfe_suspend(device_t dev)
725170589Syongari{
726170589Syongari	struct nfe_softc *sc;
727170589Syongari
728170589Syongari	sc = device_get_softc(dev);
729170589Syongari
730170589Syongari	NFE_LOCK(sc);
731170589Syongari	nfe_stop(sc->nfe_ifp);
732170589Syongari	sc->nfe_suspended = 1;
733170589Syongari	NFE_UNLOCK(sc);
734170589Syongari
735170589Syongari	return (0);
736170589Syongari}
737170589Syongari
738170589Syongari
739170589Syongaristatic int
740170589Syongarinfe_resume(device_t dev)
741170589Syongari{
742170589Syongari	struct nfe_softc *sc;
743170589Syongari	struct ifnet *ifp;
744170589Syongari
745170589Syongari	sc = device_get_softc(dev);
746170589Syongari
747170589Syongari	NFE_LOCK(sc);
748170589Syongari	ifp = sc->nfe_ifp;
749170589Syongari	if (ifp->if_flags & IFF_UP)
750170589Syongari		nfe_init_locked(sc);
751170589Syongari	sc->nfe_suspended = 0;
752170589Syongari	NFE_UNLOCK(sc);
753170589Syongari
754170589Syongari	return (0);
755170589Syongari}
756170589Syongari
757170589Syongari
758170589Syongari/* Take PHY/NIC out of powerdown, from Linux */
759159967Sobrienstatic void
760170589Syongarinfe_power(struct nfe_softc *sc)
761170589Syongari{
762170589Syongari	uint32_t pwr;
763170589Syongari
764170589Syongari	if ((sc->nfe_flags & NFE_PWR_MGMT) == 0)
765170589Syongari		return;
766170589Syongari	NFE_WRITE(sc, NFE_RXTX_CTL, NFE_RXTX_RESET | NFE_RXTX_BIT2);
767170589Syongari	NFE_WRITE(sc, NFE_MAC_RESET, NFE_MAC_RESET_MAGIC);
768170589Syongari	DELAY(100);
769170589Syongari	NFE_WRITE(sc, NFE_MAC_RESET, 0);
770170589Syongari	DELAY(100);
771170589Syongari	NFE_WRITE(sc, NFE_RXTX_CTL, NFE_RXTX_BIT2);
772170589Syongari	pwr = NFE_READ(sc, NFE_PWR2_CTL);
773170589Syongari	pwr &= ~NFE_PWR2_WAKEUP_MASK;
774170589Syongari	if (sc->nfe_revid >= 0xa3 &&
775170589Syongari	    (sc->nfe_devid == PCI_PRODUCT_NVIDIA_NFORCE430_LAN1 ||
776170589Syongari	    sc->nfe_devid == PCI_PRODUCT_NVIDIA_NFORCE430_LAN2))
777170589Syongari		pwr |= NFE_PWR2_REVA3;
778170589Syongari	NFE_WRITE(sc, NFE_PWR2_CTL, pwr);
779170589Syongari}
780170589Syongari
781170589Syongari
782170589Syongaristatic void
783159967Sobriennfe_miibus_statchg(device_t dev)
784159952Sobrien{
785159967Sobrien	struct nfe_softc *sc;
786170589Syongari
787170589Syongari	sc = device_get_softc(dev);
788170589Syongari	taskqueue_enqueue(taskqueue_swi, &sc->nfe_link_task);
789170589Syongari}
790170589Syongari
791170589Syongari
792170589Syongaristatic void
793170589Syongarinfe_link_task(void *arg, int pending)
794170589Syongari{
795170589Syongari	struct nfe_softc *sc;
796159967Sobrien	struct mii_data *mii;
797170589Syongari	struct ifnet *ifp;
798170589Syongari	uint32_t phy, seed, misc = NFE_MISC1_MAGIC, link = NFE_MEDIA_SET;
799170589Syongari	uint32_t gmask, rxctl, txctl, val;
800159952Sobrien
801170589Syongari	sc = (struct nfe_softc *)arg;
802170589Syongari
803170589Syongari	NFE_LOCK(sc);
804170589Syongari
805159967Sobrien	mii = device_get_softc(sc->nfe_miibus);
806170589Syongari	ifp = sc->nfe_ifp;
807170589Syongari	if (mii == NULL || ifp == NULL) {
808170589Syongari		NFE_UNLOCK(sc);
809170589Syongari		return;
810170589Syongari	}
811159967Sobrien
812170589Syongari	if (mii->mii_media_status & IFM_ACTIVE) {
813170589Syongari		if (IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE)
814170589Syongari			sc->nfe_link = 1;
815170589Syongari	} else
816170589Syongari		sc->nfe_link = 0;
817170589Syongari
818159952Sobrien	phy = NFE_READ(sc, NFE_PHY_IFACE);
819159952Sobrien	phy &= ~(NFE_PHY_HDX | NFE_PHY_100TX | NFE_PHY_1000T);
820159952Sobrien
821159952Sobrien	seed = NFE_READ(sc, NFE_RNDSEED);
822159952Sobrien	seed &= ~NFE_SEED_MASK;
823159952Sobrien
824170589Syongari	if (((mii->mii_media_active & IFM_GMASK) & IFM_FDX) == 0) {
825159952Sobrien		phy  |= NFE_PHY_HDX;	/* half-duplex */
826159952Sobrien		misc |= NFE_MISC1_HDX;
827159952Sobrien	}
828159952Sobrien
829159952Sobrien	switch (IFM_SUBTYPE(mii->mii_media_active)) {
830159952Sobrien	case IFM_1000_T:	/* full-duplex only */
831159952Sobrien		link |= NFE_MEDIA_1000T;
832159952Sobrien		seed |= NFE_SEED_1000T;
833159952Sobrien		phy  |= NFE_PHY_1000T;
834159952Sobrien		break;
835159952Sobrien	case IFM_100_TX:
836159952Sobrien		link |= NFE_MEDIA_100TX;
837159952Sobrien		seed |= NFE_SEED_100TX;
838159952Sobrien		phy  |= NFE_PHY_100TX;
839159952Sobrien		break;
840159952Sobrien	case IFM_10_T:
841159952Sobrien		link |= NFE_MEDIA_10T;
842159952Sobrien		seed |= NFE_SEED_10T;
843159952Sobrien		break;
844159952Sobrien	}
845159952Sobrien
846170589Syongari	if ((phy & 0x10000000) != 0) {
847170589Syongari		if (IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_T)
848170589Syongari			val = NFE_R1_MAGIC_1000;
849170589Syongari		else
850170589Syongari			val = NFE_R1_MAGIC_10_100;
851170589Syongari	} else
852170589Syongari		val = NFE_R1_MAGIC_DEFAULT;
853170589Syongari	NFE_WRITE(sc, NFE_SETUP_R1, val);
854170589Syongari
855159952Sobrien	NFE_WRITE(sc, NFE_RNDSEED, seed);	/* XXX: gigabit NICs only? */
856159952Sobrien
857159952Sobrien	NFE_WRITE(sc, NFE_PHY_IFACE, phy);
858159952Sobrien	NFE_WRITE(sc, NFE_MISC1, misc);
859159952Sobrien	NFE_WRITE(sc, NFE_LINKSPEED, link);
860170589Syongari
861170589Syongari	gmask = mii->mii_media_active & IFM_GMASK;
862170589Syongari	if ((gmask & IFM_FDX) != 0) {
863170589Syongari		/* It seems all hardwares supports Rx pause frames. */
864170589Syongari		val = NFE_READ(sc, NFE_RXFILTER);
865170589Syongari		if ((gmask & IFM_FLAG0) != 0)
866170589Syongari			val |= NFE_PFF_RX_PAUSE;
867170589Syongari		else
868170589Syongari			val &= ~NFE_PFF_RX_PAUSE;
869170589Syongari		NFE_WRITE(sc, NFE_RXFILTER, val);
870170589Syongari		if ((sc->nfe_flags & NFE_TX_FLOW_CTRL) != 0) {
871170589Syongari			val = NFE_READ(sc, NFE_MISC1);
872170589Syongari			if ((gmask & IFM_FLAG1) != 0) {
873170589Syongari				NFE_WRITE(sc, NFE_TX_PAUSE_FRAME,
874170589Syongari				    NFE_TX_PAUSE_FRAME_ENABLE);
875170589Syongari				val |= NFE_MISC1_TX_PAUSE;
876170589Syongari			} else {
877170589Syongari				val &= ~NFE_MISC1_TX_PAUSE;
878170589Syongari				NFE_WRITE(sc, NFE_TX_PAUSE_FRAME,
879170589Syongari				    NFE_TX_PAUSE_FRAME_DISABLE);
880170589Syongari			}
881170589Syongari			NFE_WRITE(sc, NFE_MISC1, val);
882170589Syongari		}
883170589Syongari	} else {
884170589Syongari		/* disable rx/tx pause frames */
885170589Syongari		val = NFE_READ(sc, NFE_RXFILTER);
886170589Syongari		val &= ~NFE_PFF_RX_PAUSE;
887170589Syongari		NFE_WRITE(sc, NFE_RXFILTER, val);
888170589Syongari		if ((sc->nfe_flags & NFE_TX_FLOW_CTRL) != 0) {
889170589Syongari			NFE_WRITE(sc, NFE_TX_PAUSE_FRAME,
890170589Syongari			    NFE_TX_PAUSE_FRAME_DISABLE);
891170589Syongari			val = NFE_READ(sc, NFE_MISC1);
892170589Syongari			val &= ~NFE_MISC1_TX_PAUSE;
893170589Syongari			NFE_WRITE(sc, NFE_MISC1, val);
894170589Syongari		}
895170589Syongari	}
896170589Syongari
897170589Syongari	txctl = NFE_READ(sc, NFE_TX_CTL);
898170589Syongari	rxctl = NFE_READ(sc, NFE_RX_CTL);
899170589Syongari	if (sc->nfe_link != 0 && (ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) {
900170589Syongari		txctl |= NFE_TX_START;
901170589Syongari		rxctl |= NFE_RX_START;
902170589Syongari	} else {
903170589Syongari		txctl &= ~NFE_TX_START;
904170589Syongari		rxctl &= ~NFE_RX_START;
905170589Syongari	}
906172164Syongari	NFE_WRITE(sc, NFE_TX_CTL, txctl);
907172164Syongari	NFE_WRITE(sc, NFE_RX_CTL, rxctl);
908170589Syongari
909170589Syongari	NFE_UNLOCK(sc);
910159952Sobrien}
911159952Sobrien
912163503Sobrien
913159967Sobrienstatic int
914159967Sobriennfe_miibus_readreg(device_t dev, int phy, int reg)
915159952Sobrien{
916159967Sobrien	struct nfe_softc *sc = device_get_softc(dev);
917170589Syongari	uint32_t val;
918159952Sobrien	int ntries;
919159952Sobrien
920159952Sobrien	NFE_WRITE(sc, NFE_PHY_STATUS, 0xf);
921159952Sobrien
922159952Sobrien	if (NFE_READ(sc, NFE_PHY_CTL) & NFE_PHY_BUSY) {
923159952Sobrien		NFE_WRITE(sc, NFE_PHY_CTL, NFE_PHY_BUSY);
924159952Sobrien		DELAY(100);
925159952Sobrien	}
926159952Sobrien
927159952Sobrien	NFE_WRITE(sc, NFE_PHY_CTL, (phy << NFE_PHYADD_SHIFT) | reg);
928159952Sobrien
929170589Syongari	for (ntries = 0; ntries < NFE_TIMEOUT; ntries++) {
930159952Sobrien		DELAY(100);
931159952Sobrien		if (!(NFE_READ(sc, NFE_PHY_CTL) & NFE_PHY_BUSY))
932159952Sobrien			break;
933159952Sobrien	}
934170589Syongari	if (ntries == NFE_TIMEOUT) {
935170589Syongari		DPRINTFN(sc, 2, "timeout waiting for PHY\n");
936159952Sobrien		return 0;
937159952Sobrien	}
938159952Sobrien
939159952Sobrien	if (NFE_READ(sc, NFE_PHY_STATUS) & NFE_PHY_ERROR) {
940170589Syongari		DPRINTFN(sc, 2, "could not read PHY\n");
941159952Sobrien		return 0;
942159952Sobrien	}
943159952Sobrien
944159952Sobrien	val = NFE_READ(sc, NFE_PHY_DATA);
945159952Sobrien	if (val != 0xffffffff && val != 0)
946159952Sobrien		sc->mii_phyaddr = phy;
947159952Sobrien
948170589Syongari	DPRINTFN(sc, 2, "mii read phy %d reg 0x%x ret 0x%x\n", phy, reg, val);
949159952Sobrien
950170589Syongari	return (val);
951159952Sobrien}
952159952Sobrien
953163503Sobrien
954159967Sobrienstatic int
955159967Sobriennfe_miibus_writereg(device_t dev, int phy, int reg, int val)
956159952Sobrien{
957159967Sobrien	struct nfe_softc *sc = device_get_softc(dev);
958170589Syongari	uint32_t ctl;
959163503Sobrien	int ntries;
960159952Sobrien
961159952Sobrien	NFE_WRITE(sc, NFE_PHY_STATUS, 0xf);
962159952Sobrien
963159952Sobrien	if (NFE_READ(sc, NFE_PHY_CTL) & NFE_PHY_BUSY) {
964159952Sobrien		NFE_WRITE(sc, NFE_PHY_CTL, NFE_PHY_BUSY);
965159952Sobrien		DELAY(100);
966159952Sobrien	}
967159952Sobrien
968159952Sobrien	NFE_WRITE(sc, NFE_PHY_DATA, val);
969159952Sobrien	ctl = NFE_PHY_WRITE | (phy << NFE_PHYADD_SHIFT) | reg;
970159952Sobrien	NFE_WRITE(sc, NFE_PHY_CTL, ctl);
971159952Sobrien
972170589Syongari	for (ntries = 0; ntries < NFE_TIMEOUT; ntries++) {
973159952Sobrien		DELAY(100);
974159952Sobrien		if (!(NFE_READ(sc, NFE_PHY_CTL) & NFE_PHY_BUSY))
975159952Sobrien			break;
976159952Sobrien	}
977159952Sobrien#ifdef NFE_DEBUG
978170589Syongari	if (nfedebug >= 2 && ntries == NFE_TIMEOUT)
979170589Syongari		device_printf(sc->nfe_dev, "could not write to PHY\n");
980159952Sobrien#endif
981170589Syongari	return (0);
982159952Sobrien}
983159952Sobrien
984170589Syongari/*
985170589Syongari * Allocate a jumbo buffer.
986170589Syongari */
987170589Syongaristatic void *
988170589Syongarinfe_jalloc(struct nfe_softc *sc)
989170589Syongari{
990170589Syongari	struct nfe_jpool_entry *entry;
991163503Sobrien
992170589Syongari	NFE_JLIST_LOCK(sc);
993170589Syongari
994170589Syongari	entry = SLIST_FIRST(&sc->nfe_jfree_listhead);
995170589Syongari
996170589Syongari	if (entry == NULL) {
997170589Syongari		NFE_JLIST_UNLOCK(sc);
998170589Syongari		return (NULL);
999170589Syongari	}
1000170589Syongari
1001170589Syongari	SLIST_REMOVE_HEAD(&sc->nfe_jfree_listhead, jpool_entries);
1002170589Syongari	SLIST_INSERT_HEAD(&sc->nfe_jinuse_listhead, entry, jpool_entries);
1003170589Syongari
1004170589Syongari	NFE_JLIST_UNLOCK(sc);
1005170589Syongari
1006170589Syongari	return (sc->jrxq.jslots[entry->slot]);
1007170589Syongari}
1008170589Syongari
1009170589Syongari/*
1010170589Syongari * Release a jumbo buffer.
1011170589Syongari */
1012170589Syongaristatic void
1013170589Syongarinfe_jfree(void *buf, void *args)
1014170589Syongari{
1015170589Syongari	struct nfe_softc *sc;
1016170589Syongari	struct nfe_jpool_entry *entry;
1017170589Syongari	int i;
1018170589Syongari
1019170589Syongari	/* Extract the softc struct pointer. */
1020170589Syongari	sc = (struct nfe_softc *)args;
1021170589Syongari	KASSERT(sc != NULL, ("%s: can't find softc pointer!", __func__));
1022170589Syongari
1023170589Syongari	NFE_JLIST_LOCK(sc);
1024170589Syongari	/* Calculate the slot this buffer belongs to. */
1025170589Syongari	i = ((vm_offset_t)buf
1026170589Syongari	     - (vm_offset_t)sc->jrxq.jpool) / NFE_JLEN;
1027170589Syongari	KASSERT(i >= 0 && i < NFE_JSLOTS,
1028170589Syongari	    ("%s: asked to free buffer that we don't manage!", __func__));
1029170589Syongari
1030170589Syongari	entry = SLIST_FIRST(&sc->nfe_jinuse_listhead);
1031170589Syongari	KASSERT(entry != NULL, ("%s: buffer not in use!", __func__));
1032170589Syongari	entry->slot = i;
1033170589Syongari	SLIST_REMOVE_HEAD(&sc->nfe_jinuse_listhead, jpool_entries);
1034170589Syongari	SLIST_INSERT_HEAD(&sc->nfe_jfree_listhead, entry, jpool_entries);
1035170589Syongari	if (SLIST_EMPTY(&sc->nfe_jinuse_listhead))
1036170589Syongari		wakeup(sc);
1037170589Syongari
1038170589Syongari	NFE_JLIST_UNLOCK(sc);
1039170589Syongari}
1040170589Syongari
1041170589Syongaristruct nfe_dmamap_arg {
1042170589Syongari	bus_addr_t nfe_busaddr;
1043170589Syongari};
1044170589Syongari
1045159967Sobrienstatic int
1046159967Sobriennfe_alloc_rx_ring(struct nfe_softc *sc, struct nfe_rx_ring *ring)
1047159952Sobrien{
1048170589Syongari	struct nfe_dmamap_arg ctx;
1049159967Sobrien	struct nfe_rx_data *data;
1050170589Syongari	void *desc;
1051159967Sobrien	int i, error, descsize;
1052159967Sobrien
1053159967Sobrien	if (sc->nfe_flags & NFE_40BIT_ADDR) {
1054170589Syongari		desc = ring->desc64;
1055159967Sobrien		descsize = sizeof (struct nfe_desc64);
1056159967Sobrien	} else {
1057170589Syongari		desc = ring->desc32;
1058159967Sobrien		descsize = sizeof (struct nfe_desc32);
1059159967Sobrien	}
1060159967Sobrien
1061159967Sobrien	ring->cur = ring->next = 0;
1062159967Sobrien
1063163503Sobrien	error = bus_dma_tag_create(sc->nfe_parent_tag,
1064170589Syongari	    NFE_RING_ALIGN, 0,			/* alignment, boundary */
1065170589Syongari	    BUS_SPACE_MAXADDR,			/* lowaddr */
1066170589Syongari	    BUS_SPACE_MAXADDR,			/* highaddr */
1067170589Syongari	    NULL, NULL,				/* filter, filterarg */
1068170589Syongari	    NFE_RX_RING_COUNT * descsize, 1,	/* maxsize, nsegments */
1069170589Syongari	    NFE_RX_RING_COUNT * descsize,	/* maxsegsize */
1070170589Syongari	    0,					/* flags */
1071170589Syongari	    NULL, NULL,				/* lockfunc, lockarg */
1072170589Syongari	    &ring->rx_desc_tag);
1073159967Sobrien	if (error != 0) {
1074170589Syongari		device_printf(sc->nfe_dev, "could not create desc DMA tag\n");
1075159967Sobrien		goto fail;
1076159967Sobrien	}
1077159967Sobrien
1078159967Sobrien	/* allocate memory to desc */
1079170589Syongari	error = bus_dmamem_alloc(ring->rx_desc_tag, &desc, BUS_DMA_WAITOK |
1080170589Syongari	    BUS_DMA_COHERENT | BUS_DMA_ZERO, &ring->rx_desc_map);
1081159967Sobrien	if (error != 0) {
1082170589Syongari		device_printf(sc->nfe_dev, "could not create desc DMA map\n");
1083159967Sobrien		goto fail;
1084159967Sobrien	}
1085170589Syongari	if (sc->nfe_flags & NFE_40BIT_ADDR)
1086170589Syongari		ring->desc64 = desc;
1087170589Syongari	else
1088170589Syongari		ring->desc32 = desc;
1089159967Sobrien
1090159967Sobrien	/* map desc to device visible address space */
1091170589Syongari	ctx.nfe_busaddr = 0;
1092170589Syongari	error = bus_dmamap_load(ring->rx_desc_tag, ring->rx_desc_map, desc,
1093170589Syongari	    NFE_RX_RING_COUNT * descsize, nfe_dma_map_segs, &ctx, 0);
1094159967Sobrien	if (error != 0) {
1095170589Syongari		device_printf(sc->nfe_dev, "could not load desc DMA map\n");
1096159967Sobrien		goto fail;
1097159967Sobrien	}
1098170589Syongari	ring->physaddr = ctx.nfe_busaddr;
1099159967Sobrien
1100170589Syongari	error = bus_dma_tag_create(sc->nfe_parent_tag,
1101170589Syongari	    1, 0,			/* alignment, boundary */
1102170589Syongari	    BUS_SPACE_MAXADDR,		/* lowaddr */
1103170589Syongari	    BUS_SPACE_MAXADDR,		/* highaddr */
1104170589Syongari	    NULL, NULL,			/* filter, filterarg */
1105170589Syongari	    MCLBYTES, 1,		/* maxsize, nsegments */
1106170589Syongari	    MCLBYTES,			/* maxsegsize */
1107170589Syongari	    0,				/* flags */
1108170589Syongari	    NULL, NULL,			/* lockfunc, lockarg */
1109170589Syongari	    &ring->rx_data_tag);
1110170589Syongari	if (error != 0) {
1111170589Syongari		device_printf(sc->nfe_dev, "could not create Rx DMA tag\n");
1112170589Syongari		goto fail;
1113170589Syongari	}
1114159967Sobrien
1115170589Syongari	error = bus_dmamap_create(ring->rx_data_tag, 0, &ring->rx_spare_map);
1116170589Syongari	if (error != 0) {
1117170589Syongari		device_printf(sc->nfe_dev,
1118170589Syongari		    "could not create Rx DMA spare map\n");
1119170589Syongari		goto fail;
1120170589Syongari	}
1121170589Syongari
1122159967Sobrien	/*
1123159967Sobrien	 * Pre-allocate Rx buffers and populate Rx ring.
1124159967Sobrien	 */
1125159967Sobrien	for (i = 0; i < NFE_RX_RING_COUNT; i++) {
1126159967Sobrien		data = &sc->rxq.data[i];
1127170589Syongari		data->rx_data_map = NULL;
1128170589Syongari		data->m = NULL;
1129170589Syongari		error = bus_dmamap_create(ring->rx_data_tag, 0,
1130170589Syongari		    &data->rx_data_map);
1131164651Sobrien		if (error != 0) {
1132170589Syongari			device_printf(sc->nfe_dev,
1133170589Syongari			    "could not create Rx DMA map\n");
1134164651Sobrien			goto fail;
1135164651Sobrien		}
1136170589Syongari	}
1137159967Sobrien
1138170589Syongarifail:
1139170589Syongari	return (error);
1140170589Syongari}
1141170589Syongari
1142170589Syongari
1143171559Syongaristatic void
1144170589Syongarinfe_alloc_jrx_ring(struct nfe_softc *sc, struct nfe_jrx_ring *ring)
1145170589Syongari{
1146170589Syongari	struct nfe_dmamap_arg ctx;
1147170589Syongari	struct nfe_rx_data *data;
1148170589Syongari	void *desc;
1149170589Syongari	struct nfe_jpool_entry *entry;
1150170589Syongari	uint8_t *ptr;
1151170589Syongari	int i, error, descsize;
1152170589Syongari
1153170589Syongari	if ((sc->nfe_flags & NFE_JUMBO_SUP) == 0)
1154171559Syongari		return;
1155171559Syongari	if (jumbo_disable != 0) {
1156171559Syongari		device_printf(sc->nfe_dev, "disabling jumbo frame support\n");
1157171559Syongari		sc->nfe_jumbo_disable = 1;
1158171559Syongari		return;
1159171559Syongari	}
1160170589Syongari
1161170589Syongari	if (sc->nfe_flags & NFE_40BIT_ADDR) {
1162170589Syongari		desc = ring->jdesc64;
1163170589Syongari		descsize = sizeof (struct nfe_desc64);
1164170589Syongari	} else {
1165170589Syongari		desc = ring->jdesc32;
1166170589Syongari		descsize = sizeof (struct nfe_desc32);
1167170589Syongari	}
1168170589Syongari
1169170589Syongari	ring->jcur = ring->jnext = 0;
1170170589Syongari
1171170589Syongari	/* Create DMA tag for jumbo Rx ring. */
1172170589Syongari	error = bus_dma_tag_create(sc->nfe_parent_tag,
1173170589Syongari	    NFE_RING_ALIGN, 0,			/* alignment, boundary */
1174170589Syongari	    BUS_SPACE_MAXADDR,			/* lowaddr */
1175170589Syongari	    BUS_SPACE_MAXADDR,			/* highaddr */
1176170589Syongari	    NULL, NULL,				/* filter, filterarg */
1177170589Syongari	    NFE_JUMBO_RX_RING_COUNT * descsize,	/* maxsize */
1178170589Syongari	    1, 					/* nsegments */
1179170589Syongari	    NFE_JUMBO_RX_RING_COUNT * descsize,	/* maxsegsize */
1180170589Syongari	    0,					/* flags */
1181170589Syongari	    NULL, NULL,				/* lockfunc, lockarg */
1182170589Syongari	    &ring->jrx_desc_tag);
1183170589Syongari	if (error != 0) {
1184170589Syongari		device_printf(sc->nfe_dev,
1185170589Syongari		    "could not create jumbo ring DMA tag\n");
1186170589Syongari		goto fail;
1187170589Syongari	}
1188170589Syongari
1189170589Syongari	/* Create DMA tag for jumbo buffer blocks. */
1190170589Syongari	error = bus_dma_tag_create(sc->nfe_parent_tag,
1191170589Syongari	    PAGE_SIZE, 0,			/* alignment, boundary */
1192170589Syongari	    BUS_SPACE_MAXADDR,			/* lowaddr */
1193170589Syongari	    BUS_SPACE_MAXADDR,			/* highaddr */
1194170589Syongari	    NULL, NULL,				/* filter, filterarg */
1195170589Syongari	    NFE_JMEM,				/* maxsize */
1196170589Syongari	    1, 					/* nsegments */
1197170589Syongari	    NFE_JMEM,				/* maxsegsize */
1198170589Syongari	    0,					/* flags */
1199170589Syongari	    NULL, NULL,				/* lockfunc, lockarg */
1200170589Syongari	    &ring->jrx_jumbo_tag);
1201170589Syongari	if (error != 0) {
1202170589Syongari		device_printf(sc->nfe_dev,
1203170589Syongari		    "could not create jumbo Rx buffer block DMA tag\n");
1204170589Syongari		goto fail;
1205170589Syongari	}
1206170589Syongari
1207170589Syongari	/* Create DMA tag for jumbo Rx buffers. */
1208170589Syongari	error = bus_dma_tag_create(sc->nfe_parent_tag,
1209170589Syongari	    PAGE_SIZE, 0,			/* alignment, boundary */
1210170589Syongari	    BUS_SPACE_MAXADDR,			/* lowaddr */
1211170589Syongari	    BUS_SPACE_MAXADDR,			/* highaddr */
1212170589Syongari	    NULL, NULL,				/* filter, filterarg */
1213170589Syongari	    NFE_JLEN,				/* maxsize */
1214170589Syongari	    1,					/* nsegments */
1215170589Syongari	    NFE_JLEN,				/* maxsegsize */
1216170589Syongari	    0,					/* flags */
1217170589Syongari	    NULL, NULL,				/* lockfunc, lockarg */
1218170589Syongari	    &ring->jrx_data_tag);
1219170589Syongari	if (error != 0) {
1220170589Syongari		device_printf(sc->nfe_dev,
1221170589Syongari		    "could not create jumbo Rx buffer DMA tag\n");
1222170589Syongari		goto fail;
1223170589Syongari	}
1224170589Syongari
1225170589Syongari	/* Allocate DMA'able memory and load the DMA map for jumbo Rx ring. */
1226170589Syongari	error = bus_dmamem_alloc(ring->jrx_desc_tag, &desc, BUS_DMA_WAITOK |
1227170589Syongari	    BUS_DMA_COHERENT | BUS_DMA_ZERO, &ring->jrx_desc_map);
1228170589Syongari	if (error != 0) {
1229170589Syongari		device_printf(sc->nfe_dev,
1230170589Syongari		    "could not allocate DMA'able memory for jumbo Rx ring\n");
1231170589Syongari		goto fail;
1232170589Syongari	}
1233170589Syongari	if (sc->nfe_flags & NFE_40BIT_ADDR)
1234170589Syongari		ring->jdesc64 = desc;
1235170589Syongari	else
1236170589Syongari		ring->jdesc32 = desc;
1237170589Syongari
1238170589Syongari	ctx.nfe_busaddr = 0;
1239170589Syongari	error = bus_dmamap_load(ring->jrx_desc_tag, ring->jrx_desc_map, desc,
1240170589Syongari	    NFE_JUMBO_RX_RING_COUNT * descsize, nfe_dma_map_segs, &ctx, 0);
1241170589Syongari	if (error != 0) {
1242170589Syongari		device_printf(sc->nfe_dev,
1243170589Syongari		    "could not load DMA'able memory for jumbo Rx ring\n");
1244170589Syongari		goto fail;
1245170589Syongari	}
1246170589Syongari	ring->jphysaddr = ctx.nfe_busaddr;
1247170589Syongari
1248170589Syongari	/* Create DMA maps for jumbo Rx buffers. */
1249170589Syongari	error = bus_dmamap_create(ring->jrx_data_tag, 0, &ring->jrx_spare_map);
1250170589Syongari	if (error != 0) {
1251170589Syongari		device_printf(sc->nfe_dev,
1252170589Syongari		    "could not create jumbo Rx DMA spare map\n");
1253170589Syongari		goto fail;
1254170589Syongari	}
1255170589Syongari
1256170589Syongari	for (i = 0; i < NFE_JUMBO_RX_RING_COUNT; i++) {
1257170589Syongari		data = &sc->jrxq.jdata[i];
1258170589Syongari		data->rx_data_map = NULL;
1259170589Syongari		data->m = NULL;
1260170589Syongari		error = bus_dmamap_create(ring->jrx_data_tag, 0,
1261164651Sobrien		    &data->rx_data_map);
1262164651Sobrien		if (error != 0) {
1263170589Syongari			device_printf(sc->nfe_dev,
1264170589Syongari			    "could not create jumbo Rx DMA map\n");
1265164651Sobrien			goto fail;
1266164651Sobrien		}
1267170589Syongari	}
1268159967Sobrien
1269170589Syongari	/* Allocate DMA'able memory and load the DMA map for jumbo buf. */
1270170589Syongari	error = bus_dmamem_alloc(ring->jrx_jumbo_tag, (void **)&ring->jpool,
1271170589Syongari	    BUS_DMA_WAITOK | BUS_DMA_COHERENT | BUS_DMA_ZERO,
1272170589Syongari	    &ring->jrx_jumbo_map);
1273170589Syongari	if (error != 0) {
1274170589Syongari		device_printf(sc->nfe_dev,
1275170589Syongari		    "could not allocate DMA'able memory for jumbo pool\n");
1276170589Syongari		goto fail;
1277170589Syongari	}
1278170589Syongari
1279170589Syongari	ctx.nfe_busaddr = 0;
1280170589Syongari	error = bus_dmamap_load(ring->jrx_jumbo_tag, ring->jrx_jumbo_map,
1281170589Syongari	    ring->jpool, NFE_JMEM, nfe_dma_map_segs, &ctx, 0);
1282170589Syongari	if (error != 0) {
1283170589Syongari		device_printf(sc->nfe_dev,
1284170589Syongari		    "could not load DMA'able memory for jumbo pool\n");
1285170589Syongari		goto fail;
1286170589Syongari	}
1287170589Syongari
1288170589Syongari	/*
1289170589Syongari	 * Now divide it up into 9K pieces and save the addresses
1290170589Syongari	 * in an array.
1291170589Syongari	 */
1292170589Syongari	ptr = ring->jpool;
1293170589Syongari	for (i = 0; i < NFE_JSLOTS; i++) {
1294170589Syongari		ring->jslots[i] = ptr;
1295170589Syongari		ptr += NFE_JLEN;
1296170589Syongari		entry = malloc(sizeof(struct nfe_jpool_entry), M_DEVBUF,
1297170589Syongari		    M_WAITOK);
1298170589Syongari		if (entry == NULL) {
1299170589Syongari			device_printf(sc->nfe_dev,
1300170589Syongari			    "no memory for jumbo buffers!\n");
1301164651Sobrien			error = ENOMEM;
1302164651Sobrien			goto fail;
1303164651Sobrien		}
1304170589Syongari		entry->slot = i;
1305170589Syongari		SLIST_INSERT_HEAD(&sc->nfe_jfree_listhead, entry,
1306170589Syongari		    jpool_entries);
1307170589Syongari	}
1308159967Sobrien
1309171559Syongari	return;
1310159967Sobrien
1311170589Syongarifail:
1312171559Syongari	/*
1313171559Syongari	 * Running without jumbo frame support is ok for most cases
1314171559Syongari	 * so don't fail on creating dma tag/map for jumbo frame.
1315171559Syongari	 */
1316170589Syongari	nfe_free_jrx_ring(sc, ring);
1317171559Syongari	device_printf(sc->nfe_dev, "disabling jumbo frame support due to "
1318171559Syongari	    "resource shortage\n");
1319171559Syongari	sc->nfe_jumbo_disable = 1;
1320170589Syongari}
1321159967Sobrien
1322159967Sobrien
1323170589Syongaristatic int
1324170589Syongarinfe_init_rx_ring(struct nfe_softc *sc, struct nfe_rx_ring *ring)
1325170589Syongari{
1326170589Syongari	void *desc;
1327170589Syongari	size_t descsize;
1328170589Syongari	int i;
1329159967Sobrien
1330170589Syongari	ring->cur = ring->next = 0;
1331170589Syongari	if (sc->nfe_flags & NFE_40BIT_ADDR) {
1332170589Syongari		desc = ring->desc64;
1333170589Syongari		descsize = sizeof (struct nfe_desc64);
1334170589Syongari	} else {
1335170589Syongari		desc = ring->desc32;
1336170589Syongari		descsize = sizeof (struct nfe_desc32);
1337159967Sobrien	}
1338170589Syongari	bzero(desc, descsize * NFE_RX_RING_COUNT);
1339170589Syongari	for (i = 0; i < NFE_RX_RING_COUNT; i++) {
1340170589Syongari		if (nfe_newbuf(sc, i) != 0)
1341170589Syongari			return (ENOBUFS);
1342170589Syongari	}
1343159967Sobrien
1344163503Sobrien	bus_dmamap_sync(ring->rx_desc_tag, ring->rx_desc_map,
1345170589Syongari	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1346159967Sobrien
1347170589Syongari	return (0);
1348159967Sobrien}
1349159967Sobrien
1350163503Sobrien
1351170589Syongaristatic int
1352170589Syongarinfe_init_jrx_ring(struct nfe_softc *sc, struct nfe_jrx_ring *ring)
1353159967Sobrien{
1354170589Syongari	void *desc;
1355170589Syongari	size_t descsize;
1356159967Sobrien	int i;
1357159967Sobrien
1358170589Syongari	ring->jcur = ring->jnext = 0;
1359170589Syongari	if (sc->nfe_flags & NFE_40BIT_ADDR) {
1360170589Syongari		desc = ring->jdesc64;
1361170589Syongari		descsize = sizeof (struct nfe_desc64);
1362170589Syongari	} else {
1363170589Syongari		desc = ring->jdesc32;
1364170589Syongari		descsize = sizeof (struct nfe_desc32);
1365159952Sobrien	}
1366170589Syongari	bzero(desc, descsize * NFE_RX_RING_COUNT);
1367170589Syongari	for (i = 0; i < NFE_JUMBO_RX_RING_COUNT; i++) {
1368170589Syongari		if (nfe_jnewbuf(sc, i) != 0)
1369170589Syongari			return (ENOBUFS);
1370170589Syongari	}
1371159952Sobrien
1372170589Syongari	bus_dmamap_sync(ring->jrx_desc_tag, ring->jrx_desc_map,
1373170589Syongari	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1374159952Sobrien
1375170589Syongari	return (0);
1376159967Sobrien}
1377159967Sobrien
1378159967Sobrien
1379159967Sobrienstatic void
1380159967Sobriennfe_free_rx_ring(struct nfe_softc *sc, struct nfe_rx_ring *ring)
1381159967Sobrien{
1382159967Sobrien	struct nfe_rx_data *data;
1383159967Sobrien	void *desc;
1384159967Sobrien	int i, descsize;
1385159967Sobrien
1386159967Sobrien	if (sc->nfe_flags & NFE_40BIT_ADDR) {
1387159967Sobrien		desc = ring->desc64;
1388159967Sobrien		descsize = sizeof (struct nfe_desc64);
1389159967Sobrien	} else {
1390159967Sobrien		desc = ring->desc32;
1391159967Sobrien		descsize = sizeof (struct nfe_desc32);
1392159952Sobrien	}
1393159952Sobrien
1394170589Syongari	for (i = 0; i < NFE_RX_RING_COUNT; i++) {
1395170589Syongari		data = &ring->data[i];
1396170589Syongari		if (data->rx_data_map != NULL) {
1397170589Syongari			bus_dmamap_destroy(ring->rx_data_tag,
1398170589Syongari			    data->rx_data_map);
1399170589Syongari			data->rx_data_map = NULL;
1400170589Syongari		}
1401170589Syongari		if (data->m != NULL) {
1402170589Syongari			m_freem(data->m);
1403170589Syongari			data->m = NULL;
1404170589Syongari		}
1405170589Syongari	}
1406170589Syongari	if (ring->rx_data_tag != NULL) {
1407170589Syongari		if (ring->rx_spare_map != NULL) {
1408170589Syongari			bus_dmamap_destroy(ring->rx_data_tag,
1409170589Syongari			    ring->rx_spare_map);
1410170589Syongari			ring->rx_spare_map = NULL;
1411170589Syongari		}
1412170589Syongari		bus_dma_tag_destroy(ring->rx_data_tag);
1413170589Syongari		ring->rx_data_tag = NULL;
1414170589Syongari	}
1415170589Syongari
1416159967Sobrien	if (desc != NULL) {
1417159967Sobrien		bus_dmamap_unload(ring->rx_desc_tag, ring->rx_desc_map);
1418159967Sobrien		bus_dmamem_free(ring->rx_desc_tag, desc, ring->rx_desc_map);
1419170589Syongari		ring->desc64 = NULL;
1420170589Syongari		ring->desc32 = NULL;
1421170589Syongari		ring->rx_desc_map = NULL;
1422170589Syongari	}
1423170589Syongari	if (ring->rx_desc_tag != NULL) {
1424159967Sobrien		bus_dma_tag_destroy(ring->rx_desc_tag);
1425170589Syongari		ring->rx_desc_tag = NULL;
1426159967Sobrien	}
1427170589Syongari}
1428159967Sobrien
1429164650Sobrien
1430170589Syongaristatic void
1431170589Syongarinfe_free_jrx_ring(struct nfe_softc *sc, struct nfe_jrx_ring *ring)
1432170589Syongari{
1433170589Syongari	struct nfe_jpool_entry *entry;
1434170589Syongari	struct nfe_rx_data *data;
1435170589Syongari	void *desc;
1436170589Syongari	int i, descsize;
1437170589Syongari
1438170589Syongari	if ((sc->nfe_flags & NFE_JUMBO_SUP) == 0)
1439170589Syongari		return;
1440170589Syongari
1441170589Syongari	NFE_JLIST_LOCK(sc);
1442170589Syongari	while ((entry = SLIST_FIRST(&sc->nfe_jinuse_listhead))) {
1443170589Syongari		device_printf(sc->nfe_dev,
1444170589Syongari		    "asked to free buffer that is in use!\n");
1445170589Syongari		SLIST_REMOVE_HEAD(&sc->nfe_jinuse_listhead, jpool_entries);
1446170589Syongari		SLIST_INSERT_HEAD(&sc->nfe_jfree_listhead, entry,
1447170589Syongari		    jpool_entries);
1448170589Syongari	}
1449170589Syongari
1450170589Syongari	while (!SLIST_EMPTY(&sc->nfe_jfree_listhead)) {
1451170589Syongari		entry = SLIST_FIRST(&sc->nfe_jfree_listhead);
1452170589Syongari		SLIST_REMOVE_HEAD(&sc->nfe_jfree_listhead, jpool_entries);
1453170589Syongari		free(entry, M_DEVBUF);
1454170589Syongari	}
1455170589Syongari        NFE_JLIST_UNLOCK(sc);
1456170589Syongari
1457170589Syongari	if (sc->nfe_flags & NFE_40BIT_ADDR) {
1458170589Syongari		desc = ring->jdesc64;
1459170589Syongari		descsize = sizeof (struct nfe_desc64);
1460170589Syongari	} else {
1461170589Syongari		desc = ring->jdesc32;
1462170589Syongari		descsize = sizeof (struct nfe_desc32);
1463170589Syongari	}
1464170589Syongari
1465170589Syongari	for (i = 0; i < NFE_JUMBO_RX_RING_COUNT; i++) {
1466170589Syongari		data = &ring->jdata[i];
1467164651Sobrien		if (data->rx_data_map != NULL) {
1468170589Syongari			bus_dmamap_destroy(ring->jrx_data_tag,
1469164651Sobrien			    data->rx_data_map);
1470170589Syongari			data->rx_data_map = NULL;
1471164651Sobrien		}
1472170589Syongari		if (data->m != NULL) {
1473164651Sobrien			m_freem(data->m);
1474170589Syongari			data->m = NULL;
1475170589Syongari		}
1476164651Sobrien	}
1477170589Syongari	if (ring->jrx_data_tag != NULL) {
1478170589Syongari		if (ring->jrx_spare_map != NULL) {
1479170589Syongari			bus_dmamap_destroy(ring->jrx_data_tag,
1480170589Syongari			    ring->jrx_spare_map);
1481170589Syongari			ring->jrx_spare_map = NULL;
1482170589Syongari		}
1483170589Syongari		bus_dma_tag_destroy(ring->jrx_data_tag);
1484170589Syongari		ring->jrx_data_tag = NULL;
1485170589Syongari	}
1486170589Syongari
1487170589Syongari	if (desc != NULL) {
1488170589Syongari		bus_dmamap_unload(ring->jrx_desc_tag, ring->jrx_desc_map);
1489170589Syongari		bus_dmamem_free(ring->jrx_desc_tag, desc, ring->jrx_desc_map);
1490170589Syongari		ring->jdesc64 = NULL;
1491170589Syongari		ring->jdesc32 = NULL;
1492170589Syongari		ring->jrx_desc_map = NULL;
1493170589Syongari	}
1494170589Syongari	/* Destroy jumbo buffer block. */
1495170589Syongari	if (ring->jrx_jumbo_map != NULL)
1496170589Syongari		bus_dmamap_unload(ring->jrx_jumbo_tag, ring->jrx_jumbo_map);
1497170589Syongari	if (ring->jrx_jumbo_map != NULL) {
1498170589Syongari		bus_dmamem_free(ring->jrx_jumbo_tag, ring->jpool,
1499170589Syongari		    ring->jrx_jumbo_map);
1500170589Syongari		ring->jpool = NULL;
1501170589Syongari		ring->jrx_jumbo_map = NULL;
1502170589Syongari	}
1503170589Syongari	if (ring->jrx_desc_tag != NULL) {
1504170589Syongari		bus_dma_tag_destroy(ring->jrx_desc_tag);
1505170589Syongari		ring->jrx_desc_tag = NULL;
1506170589Syongari	}
1507159952Sobrien}
1508159952Sobrien
1509163503Sobrien
1510159967Sobrienstatic int
1511159967Sobriennfe_alloc_tx_ring(struct nfe_softc *sc, struct nfe_tx_ring *ring)
1512159952Sobrien{
1513170589Syongari	struct nfe_dmamap_arg ctx;
1514159967Sobrien	int i, error;
1515170589Syongari	void *desc;
1516159967Sobrien	int descsize;
1517159952Sobrien
1518159967Sobrien	if (sc->nfe_flags & NFE_40BIT_ADDR) {
1519170589Syongari		desc = ring->desc64;
1520159967Sobrien		descsize = sizeof (struct nfe_desc64);
1521159967Sobrien	} else {
1522170589Syongari		desc = ring->desc32;
1523159967Sobrien		descsize = sizeof (struct nfe_desc32);
1524159967Sobrien	}
1525159952Sobrien
1526159967Sobrien	ring->queued = 0;
1527159967Sobrien	ring->cur = ring->next = 0;
1528159967Sobrien
1529163503Sobrien	error = bus_dma_tag_create(sc->nfe_parent_tag,
1530170589Syongari	    NFE_RING_ALIGN, 0,			/* alignment, boundary */
1531170589Syongari	    BUS_SPACE_MAXADDR,			/* lowaddr */
1532170589Syongari	    BUS_SPACE_MAXADDR,			/* highaddr */
1533170589Syongari	    NULL, NULL,				/* filter, filterarg */
1534170589Syongari	    NFE_TX_RING_COUNT * descsize, 1,	/* maxsize, nsegments */
1535170589Syongari	    NFE_TX_RING_COUNT * descsize,	/* maxsegsize */
1536170589Syongari	    0,					/* flags */
1537170589Syongari	    NULL, NULL,				/* lockfunc, lockarg */
1538170589Syongari	    &ring->tx_desc_tag);
1539159967Sobrien	if (error != 0) {
1540170589Syongari		device_printf(sc->nfe_dev, "could not create desc DMA tag\n");
1541159967Sobrien		goto fail;
1542159952Sobrien	}
1543159952Sobrien
1544170589Syongari	error = bus_dmamem_alloc(ring->tx_desc_tag, &desc, BUS_DMA_WAITOK |
1545170589Syongari	    BUS_DMA_COHERENT | BUS_DMA_ZERO, &ring->tx_desc_map);
1546159967Sobrien	if (error != 0) {
1547170589Syongari		device_printf(sc->nfe_dev, "could not create desc DMA map\n");
1548159967Sobrien		goto fail;
1549159967Sobrien	}
1550170589Syongari	if (sc->nfe_flags & NFE_40BIT_ADDR)
1551170589Syongari		ring->desc64 = desc;
1552170589Syongari	else
1553170589Syongari		ring->desc32 = desc;
1554159967Sobrien
1555170589Syongari	ctx.nfe_busaddr = 0;
1556170589Syongari	error = bus_dmamap_load(ring->tx_desc_tag, ring->tx_desc_map, desc,
1557170589Syongari	    NFE_TX_RING_COUNT * descsize, nfe_dma_map_segs, &ctx, 0);
1558159967Sobrien	if (error != 0) {
1559170589Syongari		device_printf(sc->nfe_dev, "could not load desc DMA map\n");
1560159967Sobrien		goto fail;
1561159967Sobrien	}
1562170589Syongari	ring->physaddr = ctx.nfe_busaddr;
1563159967Sobrien
1564163503Sobrien	error = bus_dma_tag_create(sc->nfe_parent_tag,
1565170589Syongari	    1, 0,
1566170589Syongari	    BUS_SPACE_MAXADDR,
1567170589Syongari	    BUS_SPACE_MAXADDR,
1568170589Syongari	    NULL, NULL,
1569170595Syongari	    NFE_TSO_MAXSIZE,
1570170589Syongari	    NFE_MAX_SCATTER,
1571170595Syongari	    NFE_TSO_MAXSGSIZE,
1572170589Syongari	    0,
1573170589Syongari	    NULL, NULL,
1574170589Syongari	    &ring->tx_data_tag);
1575159967Sobrien	if (error != 0) {
1576170589Syongari		device_printf(sc->nfe_dev, "could not create Tx DMA tag\n");
1577170589Syongari		goto fail;
1578159967Sobrien	}
1579159967Sobrien
1580159967Sobrien	for (i = 0; i < NFE_TX_RING_COUNT; i++) {
1581163503Sobrien		error = bus_dmamap_create(ring->tx_data_tag, 0,
1582163503Sobrien		    &ring->data[i].tx_data_map);
1583159967Sobrien		if (error != 0) {
1584170589Syongari			device_printf(sc->nfe_dev,
1585170589Syongari			    "could not create Tx DMA map\n");
1586159967Sobrien			goto fail;
1587159967Sobrien		}
1588159967Sobrien	}
1589159967Sobrien
1590170589Syongarifail:
1591170589Syongari	return (error);
1592159967Sobrien}
1593159967Sobrien
1594159967Sobrien
1595159967Sobrienstatic void
1596170589Syongarinfe_init_tx_ring(struct nfe_softc *sc, struct nfe_tx_ring *ring)
1597159967Sobrien{
1598170589Syongari	void *desc;
1599170589Syongari	size_t descsize;
1600159967Sobrien
1601170589Syongari	sc->nfe_force_tx = 0;
1602170589Syongari	ring->queued = 0;
1603170589Syongari	ring->cur = ring->next = 0;
1604170589Syongari	if (sc->nfe_flags & NFE_40BIT_ADDR) {
1605170589Syongari		desc = ring->desc64;
1606170589Syongari		descsize = sizeof (struct nfe_desc64);
1607170589Syongari	} else {
1608170589Syongari		desc = ring->desc32;
1609170589Syongari		descsize = sizeof (struct nfe_desc32);
1610159967Sobrien	}
1611170589Syongari	bzero(desc, descsize * NFE_TX_RING_COUNT);
1612159967Sobrien
1613163503Sobrien	bus_dmamap_sync(ring->tx_desc_tag, ring->tx_desc_map,
1614170589Syongari	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1615159967Sobrien}
1616159967Sobrien
1617163503Sobrien
1618159967Sobrienstatic void
1619159967Sobriennfe_free_tx_ring(struct nfe_softc *sc, struct nfe_tx_ring *ring)
1620159967Sobrien{
1621159967Sobrien	struct nfe_tx_data *data;
1622159967Sobrien	void *desc;
1623159967Sobrien	int i, descsize;
1624159967Sobrien
1625159967Sobrien	if (sc->nfe_flags & NFE_40BIT_ADDR) {
1626159967Sobrien		desc = ring->desc64;
1627159967Sobrien		descsize = sizeof (struct nfe_desc64);
1628159967Sobrien	} else {
1629159967Sobrien		desc = ring->desc32;
1630159967Sobrien		descsize = sizeof (struct nfe_desc32);
1631159967Sobrien	}
1632159967Sobrien
1633159967Sobrien	for (i = 0; i < NFE_TX_RING_COUNT; i++) {
1634159967Sobrien		data = &ring->data[i];
1635159967Sobrien
1636159967Sobrien		if (data->m != NULL) {
1637170589Syongari			bus_dmamap_sync(ring->tx_data_tag, data->tx_data_map,
1638163503Sobrien			    BUS_DMASYNC_POSTWRITE);
1639170589Syongari			bus_dmamap_unload(ring->tx_data_tag, data->tx_data_map);
1640159967Sobrien			m_freem(data->m);
1641170589Syongari			data->m = NULL;
1642159967Sobrien		}
1643170589Syongari		if (data->tx_data_map != NULL) {
1644170589Syongari			bus_dmamap_destroy(ring->tx_data_tag,
1645170589Syongari			    data->tx_data_map);
1646170589Syongari			data->tx_data_map = NULL;
1647170589Syongari		}
1648159967Sobrien	}
1649159967Sobrien
1650170589Syongari	if (ring->tx_data_tag != NULL) {
1651170589Syongari		bus_dma_tag_destroy(ring->tx_data_tag);
1652170589Syongari		ring->tx_data_tag = NULL;
1653159967Sobrien	}
1654159967Sobrien
1655170589Syongari	if (desc != NULL) {
1656170589Syongari		bus_dmamap_sync(ring->tx_desc_tag, ring->tx_desc_map,
1657170589Syongari		    BUS_DMASYNC_POSTWRITE);
1658170589Syongari		bus_dmamap_unload(ring->tx_desc_tag, ring->tx_desc_map);
1659170589Syongari		bus_dmamem_free(ring->tx_desc_tag, desc, ring->tx_desc_map);
1660170589Syongari		ring->desc64 = NULL;
1661170589Syongari		ring->desc32 = NULL;
1662170589Syongari		ring->tx_desc_map = NULL;
1663170589Syongari		bus_dma_tag_destroy(ring->tx_desc_tag);
1664170589Syongari		ring->tx_desc_tag = NULL;
1665170589Syongari	}
1666159967Sobrien}
1667159967Sobrien
1668159967Sobrien#ifdef DEVICE_POLLING
1669159967Sobrienstatic poll_handler_t nfe_poll;
1670159967Sobrien
1671163503Sobrien
1672159967Sobrienstatic void
1673159967Sobriennfe_poll(struct ifnet *ifp, enum poll_cmd cmd, int count)
1674159967Sobrien{
1675164360Sobrien	struct nfe_softc *sc = ifp->if_softc;
1676170589Syongari	uint32_t r;
1677159967Sobrien
1678159967Sobrien	NFE_LOCK(sc);
1679159967Sobrien
1680159967Sobrien	if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) {
1681170589Syongari		NFE_UNLOCK(sc);
1682159967Sobrien		return;
1683159967Sobrien	}
1684159967Sobrien
1685171559Syongari	if (sc->nfe_framesize > MCLBYTES - ETHER_HDR_LEN)
1686171559Syongari		nfe_jrxeof(sc, count);
1687171559Syongari	else
1688171559Syongari		nfe_rxeof(sc, count);
1689159967Sobrien	nfe_txeof(sc);
1690159967Sobrien	if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
1691173674Ssam		taskqueue_enqueue_fast(sc->nfe_tq, &sc->nfe_tx_task);
1692159967Sobrien
1693159967Sobrien	if (cmd == POLL_AND_CHECK_STATUS) {
1694170589Syongari		if ((r = NFE_READ(sc, sc->nfe_irq_status)) == 0) {
1695170589Syongari			NFE_UNLOCK(sc);
1696163503Sobrien			return;
1697163503Sobrien		}
1698170589Syongari		NFE_WRITE(sc, sc->nfe_irq_status, r);
1699159967Sobrien
1700163503Sobrien		if (r & NFE_IRQ_LINK) {
1701163503Sobrien			NFE_READ(sc, NFE_PHY_STATUS);
1702163503Sobrien			NFE_WRITE(sc, NFE_PHY_STATUS, 0xf);
1703170589Syongari			DPRINTF(sc, "link state changed\n");
1704163503Sobrien		}
1705159967Sobrien	}
1706170589Syongari	NFE_UNLOCK(sc);
1707159967Sobrien}
1708159967Sobrien#endif /* DEVICE_POLLING */
1709159967Sobrien
1710170589Syongaristatic void
1711170589Syongarinfe_set_intr(struct nfe_softc *sc)
1712170589Syongari{
1713159967Sobrien
1714170589Syongari	if (sc->nfe_msi != 0)
1715170589Syongari		NFE_WRITE(sc, NFE_IRQ_MASK, NFE_IRQ_WANTED);
1716170589Syongari}
1717170589Syongari
1718170589Syongari
1719170589Syongari/* In MSIX, a write to mask reegisters behaves as XOR. */
1720170589Syongaristatic __inline void
1721170589Syongarinfe_enable_intr(struct nfe_softc *sc)
1722170589Syongari{
1723170589Syongari
1724170589Syongari	if (sc->nfe_msix != 0) {
1725170589Syongari		/* XXX Should have a better way to enable interrupts! */
1726170589Syongari		if (NFE_READ(sc, sc->nfe_irq_mask) == 0)
1727170589Syongari			NFE_WRITE(sc, sc->nfe_irq_mask, sc->nfe_intrs);
1728170589Syongari	} else
1729170589Syongari		NFE_WRITE(sc, sc->nfe_irq_mask, sc->nfe_intrs);
1730170589Syongari}
1731170589Syongari
1732170589Syongari
1733170589Syongaristatic __inline void
1734170589Syongarinfe_disable_intr(struct nfe_softc *sc)
1735170589Syongari{
1736170589Syongari
1737170589Syongari	if (sc->nfe_msix != 0) {
1738170589Syongari		/* XXX Should have a better way to disable interrupts! */
1739170589Syongari		if (NFE_READ(sc, sc->nfe_irq_mask) != 0)
1740170589Syongari			NFE_WRITE(sc, sc->nfe_irq_mask, sc->nfe_nointrs);
1741170589Syongari	} else
1742170589Syongari		NFE_WRITE(sc, sc->nfe_irq_mask, sc->nfe_nointrs);
1743170589Syongari}
1744170589Syongari
1745170589Syongari
1746159967Sobrienstatic int
1747159967Sobriennfe_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
1748159967Sobrien{
1749170589Syongari	struct nfe_softc *sc;
1750170589Syongari	struct ifreq *ifr;
1751163503Sobrien	struct mii_data *mii;
1752170589Syongari	int error, init, mask;
1753159967Sobrien
1754170589Syongari	sc = ifp->if_softc;
1755170589Syongari	ifr = (struct ifreq *) data;
1756170589Syongari	error = 0;
1757170589Syongari	init = 0;
1758159952Sobrien	switch (cmd) {
1759159952Sobrien	case SIOCSIFMTU:
1760170589Syongari		if (ifr->ifr_mtu < ETHERMIN || ifr->ifr_mtu > NFE_JUMBO_MTU)
1761159952Sobrien			error = EINVAL;
1762170589Syongari		else if (ifp->if_mtu != ifr->ifr_mtu) {
1763171559Syongari			if ((((sc->nfe_flags & NFE_JUMBO_SUP) == 0) ||
1764171559Syongari			    (sc->nfe_jumbo_disable != 0)) &&
1765170589Syongari			    ifr->ifr_mtu > ETHERMTU)
1766170589Syongari				error = EINVAL;
1767170589Syongari			else {
1768170589Syongari				NFE_LOCK(sc);
1769170589Syongari				ifp->if_mtu = ifr->ifr_mtu;
1770170589Syongari				if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0)
1771170589Syongari					nfe_init_locked(sc);
1772170589Syongari				NFE_UNLOCK(sc);
1773164650Sobrien			}
1774164650Sobrien		}
1775159952Sobrien		break;
1776159952Sobrien	case SIOCSIFFLAGS:
1777159967Sobrien		NFE_LOCK(sc);
1778159952Sobrien		if (ifp->if_flags & IFF_UP) {
1779159952Sobrien			/*
1780159952Sobrien			 * If only the PROMISC or ALLMULTI flag changes, then
1781159952Sobrien			 * don't do a full re-init of the chip, just update
1782159952Sobrien			 * the Rx filter.
1783159952Sobrien			 */
1784159967Sobrien			if ((ifp->if_drv_flags & IFF_DRV_RUNNING) &&
1785159967Sobrien			    ((ifp->if_flags ^ sc->nfe_if_flags) &
1786159967Sobrien			     (IFF_ALLMULTI | IFF_PROMISC)) != 0)
1787159952Sobrien				nfe_setmulti(sc);
1788159967Sobrien			else
1789159967Sobrien				nfe_init_locked(sc);
1790159952Sobrien		} else {
1791159967Sobrien			if (ifp->if_drv_flags & IFF_DRV_RUNNING)
1792170589Syongari				nfe_stop(ifp);
1793159952Sobrien		}
1794159967Sobrien		sc->nfe_if_flags = ifp->if_flags;
1795159967Sobrien		NFE_UNLOCK(sc);
1796159967Sobrien		error = 0;
1797159952Sobrien		break;
1798159952Sobrien	case SIOCADDMULTI:
1799159952Sobrien	case SIOCDELMULTI:
1800170589Syongari		if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) {
1801159967Sobrien			NFE_LOCK(sc);
1802159967Sobrien			nfe_setmulti(sc);
1803159967Sobrien			NFE_UNLOCK(sc);
1804159952Sobrien			error = 0;
1805159952Sobrien		}
1806159952Sobrien		break;
1807159952Sobrien	case SIOCSIFMEDIA:
1808159952Sobrien	case SIOCGIFMEDIA:
1809159967Sobrien		mii = device_get_softc(sc->nfe_miibus);
1810159967Sobrien		error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, cmd);
1811159952Sobrien		break;
1812159967Sobrien	case SIOCSIFCAP:
1813170589Syongari		mask = ifr->ifr_reqcap ^ ifp->if_capenable;
1814159967Sobrien#ifdef DEVICE_POLLING
1815170589Syongari		if ((mask & IFCAP_POLLING) != 0) {
1816170589Syongari			if ((ifr->ifr_reqcap & IFCAP_POLLING) != 0) {
1817159967Sobrien				error = ether_poll_register(nfe_poll, ifp);
1818159967Sobrien				if (error)
1819170589Syongari					break;
1820159967Sobrien				NFE_LOCK(sc);
1821170589Syongari				nfe_disable_intr(sc);
1822163503Sobrien				ifp->if_capenable |= IFCAP_POLLING;
1823159967Sobrien				NFE_UNLOCK(sc);
1824159967Sobrien			} else {
1825159967Sobrien				error = ether_poll_deregister(ifp);
1826159967Sobrien				/* Enable interrupt even in error case */
1827159967Sobrien				NFE_LOCK(sc);
1828170589Syongari				nfe_enable_intr(sc);
1829159967Sobrien				ifp->if_capenable &= ~IFCAP_POLLING;
1830159967Sobrien				NFE_UNLOCK(sc);
1831159967Sobrien			}
1832159967Sobrien		}
1833163503Sobrien#endif /* DEVICE_POLLING */
1834170589Syongari		if ((sc->nfe_flags & NFE_HW_CSUM) != 0 &&
1835170589Syongari		    (mask & IFCAP_HWCSUM) != 0) {
1836159967Sobrien			ifp->if_capenable ^= IFCAP_HWCSUM;
1837170589Syongari			if ((IFCAP_TXCSUM & ifp->if_capenable) != 0 &&
1838170589Syongari			    (IFCAP_TXCSUM & ifp->if_capabilities) != 0)
1839170589Syongari				ifp->if_hwassist |= NFE_CSUM_FEATURES;
1840159967Sobrien			else
1841170589Syongari				ifp->if_hwassist &= ~NFE_CSUM_FEATURES;
1842170589Syongari			init++;
1843159967Sobrien		}
1844170589Syongari		if ((sc->nfe_flags & NFE_HW_VLAN) != 0 &&
1845170589Syongari		    (mask & IFCAP_VLAN_HWTAGGING) != 0) {
1846170589Syongari			ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING;
1847170589Syongari			init++;
1848170589Syongari		}
1849170589Syongari		/*
1850170589Syongari		 * XXX
1851170589Syongari		 * It seems that VLAN stripping requires Rx checksum offload.
1852170589Syongari		 * Unfortunately FreeBSD has no way to disable only Rx side
1853170589Syongari		 * VLAN stripping. So when we know Rx checksum offload is
1854170589Syongari		 * disabled turn entire hardware VLAN assist off.
1855170589Syongari		 */
1856170589Syongari		if ((sc->nfe_flags & (NFE_HW_CSUM | NFE_HW_VLAN)) ==
1857170589Syongari		    (NFE_HW_CSUM | NFE_HW_VLAN)) {
1858170589Syongari			if ((ifp->if_capenable & IFCAP_RXCSUM) == 0)
1859170589Syongari				ifp->if_capenable &= ~IFCAP_VLAN_HWTAGGING;
1860170589Syongari		}
1861170589Syongari
1862170589Syongari		if ((sc->nfe_flags & NFE_HW_CSUM) != 0 &&
1863170589Syongari		    (mask & IFCAP_TSO4) != 0) {
1864170589Syongari			ifp->if_capenable ^= IFCAP_TSO4;
1865170589Syongari			if ((IFCAP_TSO4 & ifp->if_capenable) != 0 &&
1866170589Syongari			    (IFCAP_TSO4 & ifp->if_capabilities) != 0)
1867170589Syongari				ifp->if_hwassist |= CSUM_TSO;
1868170589Syongari			else
1869170589Syongari				ifp->if_hwassist &= ~CSUM_TSO;
1870170589Syongari		}
1871170589Syongari
1872170589Syongari		if (init > 0 && (ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) {
1873170589Syongari			ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
1874164656Sobrien			nfe_init(sc);
1875170589Syongari		}
1876170589Syongari		if ((sc->nfe_flags & NFE_HW_VLAN) != 0)
1877170589Syongari			VLAN_CAPABILITIES(ifp);
1878159967Sobrien		break;
1879159952Sobrien	default:
1880159967Sobrien		error = ether_ioctl(ifp, cmd, data);
1881159967Sobrien		break;
1882159952Sobrien	}
1883159952Sobrien
1884170589Syongari	return (error);
1885159952Sobrien}
1886159952Sobrien
1887159967Sobrien
1888170589Syongaristatic int
1889163503Sobriennfe_intr(void *arg)
1890159967Sobrien{
1891170589Syongari	struct nfe_softc *sc;
1892170589Syongari	uint32_t status;
1893170589Syongari
1894170589Syongari	sc = (struct nfe_softc *)arg;
1895170589Syongari
1896170589Syongari	status = NFE_READ(sc, sc->nfe_irq_status);
1897170589Syongari	if (status == 0 || status == 0xffffffff)
1898170589Syongari		return (FILTER_STRAY);
1899170589Syongari	nfe_disable_intr(sc);
1900173674Ssam	taskqueue_enqueue_fast(sc->nfe_tq, &sc->nfe_int_task);
1901170589Syongari
1902170589Syongari	return (FILTER_HANDLED);
1903170589Syongari}
1904170589Syongari
1905170589Syongari
1906170589Syongaristatic void
1907170589Syongarinfe_int_task(void *arg, int pending)
1908170589Syongari{
1909159967Sobrien	struct nfe_softc *sc = arg;
1910159967Sobrien	struct ifnet *ifp = sc->nfe_ifp;
1911170589Syongari	uint32_t r;
1912170589Syongari	int domore;
1913159967Sobrien
1914163503Sobrien	NFE_LOCK(sc);
1915159967Sobrien
1916170589Syongari	if ((r = NFE_READ(sc, sc->nfe_irq_status)) == 0) {
1917170589Syongari		nfe_enable_intr(sc);
1918170589Syongari		NFE_UNLOCK(sc);
1919170589Syongari		return;	/* not for us */
1920170589Syongari	}
1921170589Syongari	NFE_WRITE(sc, sc->nfe_irq_status, r);
1922170589Syongari
1923170589Syongari	DPRINTFN(sc, 5, "nfe_intr: interrupt register %x\n", r);
1924170589Syongari
1925159967Sobrien#ifdef DEVICE_POLLING
1926159967Sobrien	if (ifp->if_capenable & IFCAP_POLLING) {
1927159967Sobrien		NFE_UNLOCK(sc);
1928159967Sobrien		return;
1929159967Sobrien	}
1930159967Sobrien#endif
1931159967Sobrien
1932172169Syongari	if (r & NFE_IRQ_LINK) {
1933172169Syongari		NFE_READ(sc, NFE_PHY_STATUS);
1934172169Syongari		NFE_WRITE(sc, NFE_PHY_STATUS, 0xf);
1935172169Syongari		DPRINTF(sc, "link state changed\n");
1936172169Syongari	}
1937172169Syongari
1938170589Syongari	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) {
1939163503Sobrien		NFE_UNLOCK(sc);
1940170589Syongari		nfe_enable_intr(sc);
1941170589Syongari		return;
1942159967Sobrien	}
1943159967Sobrien
1944170589Syongari	domore = 0;
1945170589Syongari	/* check Rx ring */
1946170589Syongari	if (sc->nfe_framesize > MCLBYTES - ETHER_HDR_LEN)
1947170589Syongari		domore = nfe_jrxeof(sc, sc->nfe_process_limit);
1948170589Syongari	else
1949170589Syongari		domore = nfe_rxeof(sc, sc->nfe_process_limit);
1950170589Syongari	/* check Tx ring */
1951170589Syongari	nfe_txeof(sc);
1952159967Sobrien
1953170589Syongari	if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
1954173674Ssam		taskqueue_enqueue_fast(sc->nfe_tq, &sc->nfe_tx_task);
1955159967Sobrien
1956159967Sobrien	NFE_UNLOCK(sc);
1957159967Sobrien
1958170589Syongari	if (domore || (NFE_READ(sc, sc->nfe_irq_status) != 0)) {
1959173674Ssam		taskqueue_enqueue_fast(sc->nfe_tq, &sc->nfe_int_task);
1960170589Syongari		return;
1961170589Syongari	}
1962170589Syongari
1963170589Syongari	/* Reenable interrupts. */
1964170589Syongari	nfe_enable_intr(sc);
1965159967Sobrien}
1966159967Sobrien
1967163503Sobrien
1968170589Syongaristatic __inline void
1969170589Syongarinfe_discard_rxbuf(struct nfe_softc *sc, int idx)
1970159952Sobrien{
1971170589Syongari	struct nfe_desc32 *desc32;
1972170589Syongari	struct nfe_desc64 *desc64;
1973170589Syongari	struct nfe_rx_data *data;
1974170589Syongari	struct mbuf *m;
1975163503Sobrien
1976170589Syongari	data = &sc->rxq.data[idx];
1977170589Syongari	m = data->m;
1978170589Syongari
1979170589Syongari	if (sc->nfe_flags & NFE_40BIT_ADDR) {
1980170589Syongari		desc64 = &sc->rxq.desc64[idx];
1981170589Syongari		/* VLAN packet may have overwritten it. */
1982170589Syongari		desc64->physaddr[0] = htole32(NFE_ADDR_HI(data->paddr));
1983170589Syongari		desc64->physaddr[1] = htole32(NFE_ADDR_LO(data->paddr));
1984170589Syongari		desc64->length = htole16(m->m_len);
1985170589Syongari		desc64->flags = htole16(NFE_RX_READY);
1986170589Syongari	} else {
1987170589Syongari		desc32 = &sc->rxq.desc32[idx];
1988170589Syongari		desc32->length = htole16(m->m_len);
1989170589Syongari		desc32->flags = htole16(NFE_RX_READY);
1990170589Syongari	}
1991159952Sobrien}
1992159952Sobrien
1993163503Sobrien
1994170589Syongaristatic __inline void
1995170589Syongarinfe_discard_jrxbuf(struct nfe_softc *sc, int idx)
1996159952Sobrien{
1997170589Syongari	struct nfe_desc32 *desc32;
1998170589Syongari	struct nfe_desc64 *desc64;
1999170589Syongari	struct nfe_rx_data *data;
2000170589Syongari	struct mbuf *m;
2001163503Sobrien
2002170589Syongari	data = &sc->jrxq.jdata[idx];
2003170589Syongari	m = data->m;
2004170589Syongari
2005170589Syongari	if (sc->nfe_flags & NFE_40BIT_ADDR) {
2006170589Syongari		desc64 = &sc->jrxq.jdesc64[idx];
2007170589Syongari		/* VLAN packet may have overwritten it. */
2008170589Syongari		desc64->physaddr[0] = htole32(NFE_ADDR_HI(data->paddr));
2009170589Syongari		desc64->physaddr[1] = htole32(NFE_ADDR_LO(data->paddr));
2010170589Syongari		desc64->length = htole16(m->m_len);
2011170589Syongari		desc64->flags = htole16(NFE_RX_READY);
2012170589Syongari	} else {
2013170589Syongari		desc32 = &sc->jrxq.jdesc32[idx];
2014170589Syongari		desc32->length = htole16(m->m_len);
2015170589Syongari		desc32->flags = htole16(NFE_RX_READY);
2016170589Syongari	}
2017159952Sobrien}
2018159952Sobrien
2019163503Sobrien
2020170589Syongaristatic int
2021170589Syongarinfe_newbuf(struct nfe_softc *sc, int idx)
2022159952Sobrien{
2023170589Syongari	struct nfe_rx_data *data;
2024170589Syongari	struct nfe_desc32 *desc32;
2025170589Syongari	struct nfe_desc64 *desc64;
2026170589Syongari	struct mbuf *m;
2027170589Syongari	bus_dma_segment_t segs[1];
2028170589Syongari	bus_dmamap_t map;
2029170589Syongari	int nsegs;
2030163503Sobrien
2031170589Syongari	m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
2032170589Syongari	if (m == NULL)
2033170589Syongari		return (ENOBUFS);
2034159952Sobrien
2035170589Syongari	m->m_len = m->m_pkthdr.len = MCLBYTES;
2036170589Syongari	m_adj(m, ETHER_ALIGN);
2037163503Sobrien
2038170589Syongari	if (bus_dmamap_load_mbuf_sg(sc->rxq.rx_data_tag, sc->rxq.rx_spare_map,
2039170589Syongari	    m, segs, &nsegs, BUS_DMA_NOWAIT) != 0) {
2040170589Syongari		m_freem(m);
2041170589Syongari		return (ENOBUFS);
2042170589Syongari	}
2043170589Syongari	KASSERT(nsegs == 1, ("%s: %d segments returned!", __func__, nsegs));
2044163503Sobrien
2045170589Syongari	data = &sc->rxq.data[idx];
2046170589Syongari	if (data->m != NULL) {
2047170589Syongari		bus_dmamap_sync(sc->rxq.rx_data_tag, data->rx_data_map,
2048170589Syongari		    BUS_DMASYNC_POSTREAD);
2049170589Syongari		bus_dmamap_unload(sc->rxq.rx_data_tag, data->rx_data_map);
2050170589Syongari	}
2051170589Syongari	map = data->rx_data_map;
2052170589Syongari	data->rx_data_map = sc->rxq.rx_spare_map;
2053170589Syongari	sc->rxq.rx_spare_map = map;
2054170589Syongari	bus_dmamap_sync(sc->rxq.rx_data_tag, data->rx_data_map,
2055170589Syongari	    BUS_DMASYNC_PREREAD);
2056170589Syongari	data->paddr = segs[0].ds_addr;
2057170589Syongari	data->m = m;
2058170589Syongari	/* update mapping address in h/w descriptor */
2059170589Syongari	if (sc->nfe_flags & NFE_40BIT_ADDR) {
2060170589Syongari		desc64 = &sc->rxq.desc64[idx];
2061170589Syongari		desc64->physaddr[0] = htole32(NFE_ADDR_HI(segs[0].ds_addr));
2062170589Syongari		desc64->physaddr[1] = htole32(NFE_ADDR_LO(segs[0].ds_addr));
2063170589Syongari		desc64->length = htole16(segs[0].ds_len);
2064170589Syongari		desc64->flags = htole16(NFE_RX_READY);
2065170589Syongari	} else {
2066170589Syongari		desc32 = &sc->rxq.desc32[idx];
2067170589Syongari		desc32->physaddr = htole32(NFE_ADDR_LO(segs[0].ds_addr));
2068170589Syongari		desc32->length = htole16(segs[0].ds_len);
2069170589Syongari		desc32->flags = htole16(NFE_RX_READY);
2070170589Syongari	}
2071170589Syongari
2072170589Syongari	return (0);
2073159952Sobrien}
2074159952Sobrien
2075163503Sobrien
2076170589Syongaristatic int
2077170589Syongarinfe_jnewbuf(struct nfe_softc *sc, int idx)
2078159952Sobrien{
2079170589Syongari	struct nfe_rx_data *data;
2080170589Syongari	struct nfe_desc32 *desc32;
2081170589Syongari	struct nfe_desc64 *desc64;
2082170589Syongari	struct mbuf *m;
2083170589Syongari	bus_dma_segment_t segs[1];
2084170589Syongari	bus_dmamap_t map;
2085170589Syongari	int nsegs;
2086170589Syongari	void *buf;
2087163503Sobrien
2088170589Syongari	MGETHDR(m, M_DONTWAIT, MT_DATA);
2089170589Syongari	if (m == NULL)
2090170589Syongari		return (ENOBUFS);
2091170589Syongari	buf = nfe_jalloc(sc);
2092170589Syongari	if (buf == NULL) {
2093170589Syongari		m_freem(m);
2094170589Syongari		return (ENOBUFS);
2095170589Syongari	}
2096170589Syongari	/* Attach the buffer to the mbuf. */
2097170589Syongari	MEXTADD(m, buf, NFE_JLEN, nfe_jfree, (struct nfe_softc *)sc, 0,
2098170589Syongari	    EXT_NET_DRV);
2099170589Syongari	if ((m->m_flags & M_EXT) == 0) {
2100170589Syongari		m_freem(m);
2101170589Syongari		return (ENOBUFS);
2102170589Syongari	}
2103170589Syongari	m->m_pkthdr.len = m->m_len = NFE_JLEN;
2104170589Syongari	m_adj(m, ETHER_ALIGN);
2105159952Sobrien
2106170589Syongari	if (bus_dmamap_load_mbuf_sg(sc->jrxq.jrx_data_tag,
2107170589Syongari	    sc->jrxq.jrx_spare_map, m, segs, &nsegs, BUS_DMA_NOWAIT) != 0) {
2108170589Syongari		m_freem(m);
2109170589Syongari		return (ENOBUFS);
2110170589Syongari	}
2111170589Syongari	KASSERT(nsegs == 1, ("%s: %d segments returned!", __func__, nsegs));
2112163503Sobrien
2113170589Syongari	data = &sc->jrxq.jdata[idx];
2114170589Syongari	if (data->m != NULL) {
2115170589Syongari		bus_dmamap_sync(sc->jrxq.jrx_data_tag, data->rx_data_map,
2116170589Syongari		    BUS_DMASYNC_POSTREAD);
2117170589Syongari		bus_dmamap_unload(sc->jrxq.jrx_data_tag, data->rx_data_map);
2118170589Syongari	}
2119170589Syongari	map = data->rx_data_map;
2120170589Syongari	data->rx_data_map = sc->jrxq.jrx_spare_map;
2121170589Syongari	sc->jrxq.jrx_spare_map = map;
2122170589Syongari	bus_dmamap_sync(sc->jrxq.jrx_data_tag, data->rx_data_map,
2123170589Syongari	    BUS_DMASYNC_PREREAD);
2124170589Syongari	data->paddr = segs[0].ds_addr;
2125170589Syongari	data->m = m;
2126170589Syongari	/* update mapping address in h/w descriptor */
2127170589Syongari	if (sc->nfe_flags & NFE_40BIT_ADDR) {
2128170589Syongari		desc64 = &sc->jrxq.jdesc64[idx];
2129170589Syongari		desc64->physaddr[0] = htole32(NFE_ADDR_HI(segs[0].ds_addr));
2130170589Syongari		desc64->physaddr[1] = htole32(NFE_ADDR_LO(segs[0].ds_addr));
2131170589Syongari		desc64->length = htole16(segs[0].ds_len);
2132170589Syongari		desc64->flags = htole16(NFE_RX_READY);
2133170589Syongari	} else {
2134170589Syongari		desc32 = &sc->jrxq.jdesc32[idx];
2135170589Syongari		desc32->physaddr = htole32(NFE_ADDR_LO(segs[0].ds_addr));
2136170589Syongari		desc32->length = htole16(segs[0].ds_len);
2137170589Syongari		desc32->flags = htole16(NFE_RX_READY);
2138170589Syongari	}
2139159967Sobrien
2140170589Syongari	return (0);
2141159952Sobrien}
2142159952Sobrien
2143163503Sobrien
2144170589Syongaristatic int
2145170589Syongarinfe_rxeof(struct nfe_softc *sc, int count)
2146159952Sobrien{
2147159967Sobrien	struct ifnet *ifp = sc->nfe_ifp;
2148170589Syongari	struct nfe_desc32 *desc32;
2149170589Syongari	struct nfe_desc64 *desc64;
2150159952Sobrien	struct nfe_rx_data *data;
2151170589Syongari	struct mbuf *m;
2152170589Syongari	uint16_t flags;
2153170589Syongari	int len, prog;
2154170589Syongari	uint32_t vtag = 0;
2155159952Sobrien
2156159967Sobrien	NFE_LOCK_ASSERT(sc);
2157159967Sobrien
2158170589Syongari	bus_dmamap_sync(sc->rxq.rx_desc_tag, sc->rxq.rx_desc_map,
2159170589Syongari	    BUS_DMASYNC_POSTREAD);
2160159967Sobrien
2161170589Syongari	for (prog = 0;;NFE_INC(sc->rxq.cur, NFE_RX_RING_COUNT), vtag = 0) {
2162170589Syongari		if (count <= 0)
2163170589Syongari			break;
2164170589Syongari		count--;
2165159967Sobrien
2166159952Sobrien		data = &sc->rxq.data[sc->rxq.cur];
2167159952Sobrien
2168159967Sobrien		if (sc->nfe_flags & NFE_40BIT_ADDR) {
2169159952Sobrien			desc64 = &sc->rxq.desc64[sc->rxq.cur];
2170170589Syongari			vtag = le32toh(desc64->physaddr[1]);
2171170589Syongari			flags = le16toh(desc64->flags);
2172170589Syongari			len = le16toh(desc64->length) & NFE_RX_LEN_MASK;
2173159952Sobrien		} else {
2174159952Sobrien			desc32 = &sc->rxq.desc32[sc->rxq.cur];
2175170589Syongari			flags = le16toh(desc32->flags);
2176170589Syongari			len = le16toh(desc32->length) & NFE_RX_LEN_MASK;
2177159952Sobrien		}
2178159952Sobrien
2179159952Sobrien		if (flags & NFE_RX_READY)
2180159952Sobrien			break;
2181170589Syongari		prog++;
2182159967Sobrien		if ((sc->nfe_flags & (NFE_JUMBO_SUP | NFE_40BIT_ADDR)) == 0) {
2183170589Syongari			if (!(flags & NFE_RX_VALID_V1)) {
2184170589Syongari				ifp->if_ierrors++;
2185170589Syongari				nfe_discard_rxbuf(sc, sc->rxq.cur);
2186170589Syongari				continue;
2187170589Syongari			}
2188159952Sobrien			if ((flags & NFE_RX_FIXME_V1) == NFE_RX_FIXME_V1) {
2189159952Sobrien				flags &= ~NFE_RX_ERROR;
2190159952Sobrien				len--;	/* fix buffer length */
2191159952Sobrien			}
2192159952Sobrien		} else {
2193170589Syongari			if (!(flags & NFE_RX_VALID_V2)) {
2194170589Syongari				ifp->if_ierrors++;
2195170589Syongari				nfe_discard_rxbuf(sc, sc->rxq.cur);
2196170589Syongari				continue;
2197170589Syongari			}
2198159952Sobrien
2199159952Sobrien			if ((flags & NFE_RX_FIXME_V2) == NFE_RX_FIXME_V2) {
2200159952Sobrien				flags &= ~NFE_RX_ERROR;
2201159952Sobrien				len--;	/* fix buffer length */
2202159952Sobrien			}
2203159952Sobrien		}
2204159952Sobrien
2205159952Sobrien		if (flags & NFE_RX_ERROR) {
2206159952Sobrien			ifp->if_ierrors++;
2207170589Syongari			nfe_discard_rxbuf(sc, sc->rxq.cur);
2208170589Syongari			continue;
2209159952Sobrien		}
2210159952Sobrien
2211170589Syongari		m = data->m;
2212170589Syongari		if (nfe_newbuf(sc, sc->rxq.cur) != 0) {
2213170589Syongari			ifp->if_iqdrops++;
2214170589Syongari			nfe_discard_rxbuf(sc, sc->rxq.cur);
2215170589Syongari			continue;
2216159952Sobrien		}
2217159952Sobrien
2218170589Syongari		if ((vtag & NFE_RX_VTAG) != 0 &&
2219170589Syongari		    (ifp->if_capenable & IFCAP_VLAN_HWTAGGING) != 0) {
2220170589Syongari			m->m_pkthdr.ether_vtag = vtag & 0xffff;
2221170589Syongari			m->m_flags |= M_VLANTAG;
2222164651Sobrien		}
2223159952Sobrien
2224170589Syongari		m->m_pkthdr.len = m->m_len = len;
2225170589Syongari		m->m_pkthdr.rcvif = ifp;
2226164651Sobrien
2227170589Syongari		if ((ifp->if_capenable & IFCAP_RXCSUM) != 0) {
2228170589Syongari			if ((flags & NFE_RX_IP_CSUMOK) != 0) {
2229170589Syongari				m->m_pkthdr.csum_flags |= CSUM_IP_CHECKED;
2230170589Syongari				m->m_pkthdr.csum_flags |= CSUM_IP_VALID;
2231170589Syongari				if ((flags & NFE_RX_TCP_CSUMOK) != 0 ||
2232170589Syongari				    (flags & NFE_RX_UDP_CSUMOK) != 0) {
2233170589Syongari					m->m_pkthdr.csum_flags |=
2234170589Syongari					    CSUM_DATA_VALID | CSUM_PSEUDO_HDR;
2235170589Syongari					m->m_pkthdr.csum_data = 0xffff;
2236170589Syongari				}
2237159952Sobrien			}
2238170589Syongari		}
2239170589Syongari
2240170589Syongari		ifp->if_ipackets++;
2241170589Syongari
2242170589Syongari		NFE_UNLOCK(sc);
2243170589Syongari		(*ifp->if_input)(ifp, m);
2244170589Syongari		NFE_LOCK(sc);
2245170589Syongari	}
2246170589Syongari
2247170589Syongari	if (prog > 0)
2248170589Syongari		bus_dmamap_sync(sc->rxq.rx_desc_tag, sc->rxq.rx_desc_map,
2249170589Syongari		    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
2250170589Syongari
2251170589Syongari	return (count > 0 ? 0 : EAGAIN);
2252170589Syongari}
2253170589Syongari
2254170589Syongari
2255170589Syongaristatic int
2256170589Syongarinfe_jrxeof(struct nfe_softc *sc, int count)
2257170589Syongari{
2258170589Syongari	struct ifnet *ifp = sc->nfe_ifp;
2259170589Syongari	struct nfe_desc32 *desc32;
2260170589Syongari	struct nfe_desc64 *desc64;
2261170589Syongari	struct nfe_rx_data *data;
2262170589Syongari	struct mbuf *m;
2263170589Syongari	uint16_t flags;
2264170589Syongari	int len, prog;
2265170589Syongari	uint32_t vtag = 0;
2266170589Syongari
2267170589Syongari	NFE_LOCK_ASSERT(sc);
2268170589Syongari
2269170589Syongari	bus_dmamap_sync(sc->jrxq.jrx_desc_tag, sc->jrxq.jrx_desc_map,
2270170589Syongari	    BUS_DMASYNC_POSTREAD);
2271170589Syongari
2272170589Syongari	for (prog = 0;;NFE_INC(sc->jrxq.jcur, NFE_JUMBO_RX_RING_COUNT),
2273170589Syongari	    vtag = 0) {
2274170589Syongari		if (count <= 0)
2275170589Syongari			break;
2276170589Syongari		count--;
2277170589Syongari
2278170589Syongari		data = &sc->jrxq.jdata[sc->jrxq.jcur];
2279170589Syongari
2280170589Syongari		if (sc->nfe_flags & NFE_40BIT_ADDR) {
2281170589Syongari			desc64 = &sc->jrxq.jdesc64[sc->jrxq.jcur];
2282170589Syongari			vtag = le32toh(desc64->physaddr[1]);
2283170589Syongari			flags = le16toh(desc64->flags);
2284170589Syongari			len = le16toh(desc64->length) & NFE_RX_LEN_MASK;
2285170589Syongari		} else {
2286170589Syongari			desc32 = &sc->jrxq.jdesc32[sc->jrxq.jcur];
2287170589Syongari			flags = le16toh(desc32->flags);
2288170589Syongari			len = le16toh(desc32->length) & NFE_RX_LEN_MASK;
2289170589Syongari		}
2290170589Syongari
2291170589Syongari		if (flags & NFE_RX_READY)
2292170589Syongari			break;
2293170589Syongari		prog++;
2294170589Syongari		if ((sc->nfe_flags & (NFE_JUMBO_SUP | NFE_40BIT_ADDR)) == 0) {
2295170589Syongari			if (!(flags & NFE_RX_VALID_V1)) {
2296170589Syongari				ifp->if_ierrors++;
2297170589Syongari				nfe_discard_jrxbuf(sc, sc->jrxq.jcur);
2298170589Syongari				continue;
2299170589Syongari			}
2300170589Syongari			if ((flags & NFE_RX_FIXME_V1) == NFE_RX_FIXME_V1) {
2301170589Syongari				flags &= ~NFE_RX_ERROR;
2302170589Syongari				len--;	/* fix buffer length */
2303170589Syongari			}
2304170589Syongari		} else {
2305170589Syongari			if (!(flags & NFE_RX_VALID_V2)) {
2306170589Syongari				ifp->if_ierrors++;
2307170589Syongari				nfe_discard_jrxbuf(sc, sc->jrxq.jcur);
2308170589Syongari				continue;
2309170589Syongari			}
2310170589Syongari
2311170589Syongari			if ((flags & NFE_RX_FIXME_V2) == NFE_RX_FIXME_V2) {
2312170589Syongari				flags &= ~NFE_RX_ERROR;
2313170589Syongari				len--;	/* fix buffer length */
2314170589Syongari			}
2315170589Syongari		}
2316170589Syongari
2317170589Syongari		if (flags & NFE_RX_ERROR) {
2318164651Sobrien			ifp->if_ierrors++;
2319170589Syongari			nfe_discard_jrxbuf(sc, sc->jrxq.jcur);
2320170589Syongari			continue;
2321164651Sobrien		}
2322159952Sobrien
2323159952Sobrien		m = data->m;
2324170589Syongari		if (nfe_jnewbuf(sc, sc->jrxq.jcur) != 0) {
2325170589Syongari			ifp->if_iqdrops++;
2326170589Syongari			nfe_discard_jrxbuf(sc, sc->jrxq.jcur);
2327170589Syongari			continue;
2328170589Syongari		}
2329159952Sobrien
2330170589Syongari		if ((vtag & NFE_RX_VTAG) != 0 &&
2331170589Syongari		    (ifp->if_capenable & IFCAP_VLAN_HWTAGGING) != 0) {
2332170589Syongari			m->m_pkthdr.ether_vtag = vtag & 0xffff;
2333170589Syongari			m->m_flags |= M_VLANTAG;
2334170589Syongari		}
2335170589Syongari
2336159952Sobrien		m->m_pkthdr.len = m->m_len = len;
2337159952Sobrien		m->m_pkthdr.rcvif = ifp;
2338159952Sobrien
2339170589Syongari		if ((ifp->if_capenable & IFCAP_RXCSUM) != 0) {
2340170589Syongari			if ((flags & NFE_RX_IP_CSUMOK) != 0) {
2341170589Syongari				m->m_pkthdr.csum_flags |= CSUM_IP_CHECKED;
2342159967Sobrien				m->m_pkthdr.csum_flags |= CSUM_IP_VALID;
2343170589Syongari				if ((flags & NFE_RX_TCP_CSUMOK) != 0 ||
2344170589Syongari				    (flags & NFE_RX_UDP_CSUMOK) != 0) {
2345170589Syongari					m->m_pkthdr.csum_flags |=
2346170589Syongari					    CSUM_DATA_VALID | CSUM_PSEUDO_HDR;
2347170589Syongari					m->m_pkthdr.csum_data = 0xffff;
2348170589Syongari				}
2349159967Sobrien			}
2350159952Sobrien		}
2351159952Sobrien
2352159952Sobrien		ifp->if_ipackets++;
2353159952Sobrien
2354159967Sobrien		NFE_UNLOCK(sc);
2355159967Sobrien		(*ifp->if_input)(ifp, m);
2356159967Sobrien		NFE_LOCK(sc);
2357170589Syongari	}
2358159967Sobrien
2359170589Syongari	if (prog > 0)
2360170589Syongari		bus_dmamap_sync(sc->jrxq.jrx_desc_tag, sc->jrxq.jrx_desc_map,
2361170589Syongari		    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
2362159952Sobrien
2363170589Syongari	return (count > 0 ? 0 : EAGAIN);
2364159952Sobrien}
2365159952Sobrien
2366163503Sobrien
2367163503Sobrienstatic void
2368163503Sobriennfe_txeof(struct nfe_softc *sc)
2369159952Sobrien{
2370159967Sobrien	struct ifnet *ifp = sc->nfe_ifp;
2371159952Sobrien	struct nfe_desc32 *desc32;
2372159952Sobrien	struct nfe_desc64 *desc64;
2373159952Sobrien	struct nfe_tx_data *data = NULL;
2374170589Syongari	uint16_t flags;
2375170589Syongari	int cons, prog;
2376159952Sobrien
2377159967Sobrien	NFE_LOCK_ASSERT(sc);
2378159967Sobrien
2379170589Syongari	bus_dmamap_sync(sc->txq.tx_desc_tag, sc->txq.tx_desc_map,
2380170589Syongari	    BUS_DMASYNC_POSTREAD);
2381170589Syongari
2382170589Syongari	prog = 0;
2383170589Syongari	for (cons = sc->txq.next; cons != sc->txq.cur;
2384170589Syongari	    NFE_INC(cons, NFE_TX_RING_COUNT)) {
2385159967Sobrien		if (sc->nfe_flags & NFE_40BIT_ADDR) {
2386170589Syongari			desc64 = &sc->txq.desc64[cons];
2387170589Syongari			flags = le16toh(desc64->flags);
2388159952Sobrien		} else {
2389170589Syongari			desc32 = &sc->txq.desc32[cons];
2390170589Syongari			flags = le16toh(desc32->flags);
2391159952Sobrien		}
2392159952Sobrien
2393159952Sobrien		if (flags & NFE_TX_VALID)
2394159952Sobrien			break;
2395159952Sobrien
2396170589Syongari		prog++;
2397170589Syongari		sc->txq.queued--;
2398170589Syongari		data = &sc->txq.data[cons];
2399159952Sobrien
2400159967Sobrien		if ((sc->nfe_flags & (NFE_JUMBO_SUP | NFE_40BIT_ADDR)) == 0) {
2401170589Syongari			if ((flags & NFE_TX_LASTFRAG_V1) == 0)
2402170589Syongari				continue;
2403159952Sobrien			if ((flags & NFE_TX_ERROR_V1) != 0) {
2404170589Syongari				device_printf(sc->nfe_dev,
2405170589Syongari				    "tx v1 error 0x%4b\n", flags, NFE_V1_TXERR);
2406159967Sobrien
2407159952Sobrien				ifp->if_oerrors++;
2408159952Sobrien			} else
2409159952Sobrien				ifp->if_opackets++;
2410159952Sobrien		} else {
2411170589Syongari			if ((flags & NFE_TX_LASTFRAG_V2) == 0)
2412170589Syongari				continue;
2413159952Sobrien			if ((flags & NFE_TX_ERROR_V2) != 0) {
2414170589Syongari				device_printf(sc->nfe_dev,
2415170589Syongari				    "tx v2 error 0x%4b\n", flags, NFE_V2_TXERR);
2416159952Sobrien				ifp->if_oerrors++;
2417159952Sobrien			} else
2418159952Sobrien				ifp->if_opackets++;
2419159952Sobrien		}
2420159952Sobrien
2421159952Sobrien		/* last fragment of the mbuf chain transmitted */
2422170589Syongari		KASSERT(data->m != NULL, ("%s: freeing NULL mbuf!", __func__));
2423170589Syongari		bus_dmamap_sync(sc->txq.tx_data_tag, data->tx_data_map,
2424159967Sobrien		    BUS_DMASYNC_POSTWRITE);
2425170589Syongari		bus_dmamap_unload(sc->txq.tx_data_tag, data->tx_data_map);
2426159952Sobrien		m_freem(data->m);
2427159952Sobrien		data->m = NULL;
2428159952Sobrien	}
2429159952Sobrien
2430170589Syongari	if (prog > 0) {
2431170589Syongari		sc->nfe_force_tx = 0;
2432170589Syongari		sc->txq.next = cons;
2433159967Sobrien		ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
2434170589Syongari		if (sc->txq.queued == 0)
2435170589Syongari			sc->nfe_watchdog_timer = 0;
2436159952Sobrien	}
2437159952Sobrien}
2438159952Sobrien
2439163503Sobrienstatic int
2440170589Syongarinfe_encap(struct nfe_softc *sc, struct mbuf **m_head)
2441159952Sobrien{
2442170589Syongari	struct nfe_desc32 *desc32 = NULL;
2443170589Syongari	struct nfe_desc64 *desc64 = NULL;
2444159952Sobrien	bus_dmamap_t map;
2445163503Sobrien	bus_dma_segment_t segs[NFE_MAX_SCATTER];
2446170589Syongari	int error, i, nsegs, prod, si;
2447170589Syongari	uint32_t tso_segsz;
2448170589Syongari	uint16_t cflags, flags;
2449170589Syongari	struct mbuf *m;
2450159952Sobrien
2451170589Syongari	prod = si = sc->txq.cur;
2452170589Syongari	map = sc->txq.data[prod].tx_data_map;
2453159952Sobrien
2454170589Syongari	error = bus_dmamap_load_mbuf_sg(sc->txq.tx_data_tag, map, *m_head, segs,
2455159967Sobrien	    &nsegs, BUS_DMA_NOWAIT);
2456170589Syongari	if (error == EFBIG) {
2457175418Sjhb		m = m_collapse(*m_head, M_DONTWAIT, NFE_MAX_SCATTER);
2458170589Syongari		if (m == NULL) {
2459170589Syongari			m_freem(*m_head);
2460170589Syongari			*m_head = NULL;
2461170589Syongari			return (ENOBUFS);
2462170589Syongari		}
2463170589Syongari		*m_head = m;
2464170589Syongari		error = bus_dmamap_load_mbuf_sg(sc->txq.tx_data_tag, map,
2465170589Syongari		    *m_head, segs, &nsegs, BUS_DMA_NOWAIT);
2466170589Syongari		if (error != 0) {
2467170589Syongari			m_freem(*m_head);
2468170589Syongari			*m_head = NULL;
2469170589Syongari			return (ENOBUFS);
2470170589Syongari		}
2471170589Syongari	} else if (error != 0)
2472170589Syongari		return (error);
2473170589Syongari	if (nsegs == 0) {
2474170589Syongari		m_freem(*m_head);
2475170589Syongari		*m_head = NULL;
2476170589Syongari		return (EIO);
2477159952Sobrien	}
2478159952Sobrien
2479170589Syongari	if (sc->txq.queued + nsegs >= NFE_TX_RING_COUNT - 2) {
2480159967Sobrien		bus_dmamap_unload(sc->txq.tx_data_tag, map);
2481170589Syongari		return (ENOBUFS);
2482159952Sobrien	}
2483159952Sobrien
2484170589Syongari	m = *m_head;
2485170589Syongari	cflags = flags = 0;
2486170589Syongari	tso_segsz = 0;
2487170589Syongari	if ((m->m_pkthdr.csum_flags & NFE_CSUM_FEATURES) != 0) {
2488170589Syongari		if ((m->m_pkthdr.csum_flags & CSUM_IP) != 0)
2489170589Syongari			cflags |= NFE_TX_IP_CSUM;
2490170589Syongari		if ((m->m_pkthdr.csum_flags & CSUM_TCP) != 0)
2491170589Syongari			cflags |= NFE_TX_TCP_UDP_CSUM;
2492170589Syongari		if ((m->m_pkthdr.csum_flags & CSUM_UDP) != 0)
2493170589Syongari			cflags |= NFE_TX_TCP_UDP_CSUM;
2494164656Sobrien	}
2495170589Syongari	if ((m->m_pkthdr.csum_flags & CSUM_TSO) != 0) {
2496170589Syongari		tso_segsz = (uint32_t)m->m_pkthdr.tso_segsz <<
2497170589Syongari		    NFE_TX_TSO_SHIFT;
2498170589Syongari		cflags &= ~(NFE_TX_IP_CSUM | NFE_TX_TCP_UDP_CSUM);
2499170589Syongari		cflags |= NFE_TX_TSO;
2500170589Syongari	}
2501159967Sobrien
2502159967Sobrien	for (i = 0; i < nsegs; i++) {
2503159967Sobrien		if (sc->nfe_flags & NFE_40BIT_ADDR) {
2504170589Syongari			desc64 = &sc->txq.desc64[prod];
2505170589Syongari			desc64->physaddr[0] =
2506170589Syongari			    htole32(NFE_ADDR_HI(segs[i].ds_addr));
2507170589Syongari			desc64->physaddr[1] =
2508170589Syongari			    htole32(NFE_ADDR_LO(segs[i].ds_addr));
2509170589Syongari			desc64->vtag = 0;
2510159967Sobrien			desc64->length = htole16(segs[i].ds_len - 1);
2511159952Sobrien			desc64->flags = htole16(flags);
2512159952Sobrien		} else {
2513170589Syongari			desc32 = &sc->txq.desc32[prod];
2514170589Syongari			desc32->physaddr =
2515170589Syongari			    htole32(NFE_ADDR_LO(segs[i].ds_addr));
2516159967Sobrien			desc32->length = htole16(segs[i].ds_len - 1);
2517159952Sobrien			desc32->flags = htole16(flags);
2518159952Sobrien		}
2519159952Sobrien
2520170589Syongari		/*
2521170589Syongari		 * Setting of the valid bit in the first descriptor is
2522170589Syongari		 * deferred until the whole chain is fully setup.
2523170589Syongari		 */
2524170589Syongari		flags |= NFE_TX_VALID;
2525163503Sobrien
2526159952Sobrien		sc->txq.queued++;
2527170589Syongari		NFE_INC(prod, NFE_TX_RING_COUNT);
2528159952Sobrien	}
2529159952Sobrien
2530170589Syongari	/*
2531170589Syongari	 * the whole mbuf chain has been DMA mapped, fix last/first descriptor.
2532170589Syongari	 * csum flags, vtag and TSO belong to the first fragment only.
2533170589Syongari	 */
2534159967Sobrien	if (sc->nfe_flags & NFE_40BIT_ADDR) {
2535170589Syongari		desc64->flags |= htole16(NFE_TX_LASTFRAG_V2);
2536170589Syongari		desc64 = &sc->txq.desc64[si];
2537170589Syongari		if ((m->m_flags & M_VLANTAG) != 0)
2538170589Syongari			desc64->vtag = htole32(NFE_TX_VTAG |
2539170589Syongari			    m->m_pkthdr.ether_vtag);
2540170589Syongari		if (tso_segsz != 0) {
2541170589Syongari			/*
2542170589Syongari			 * XXX
2543170589Syongari			 * The following indicates the descriptor element
2544170589Syongari			 * is a 32bit quantity.
2545170589Syongari			 */
2546170589Syongari			desc64->length |= htole16((uint16_t)tso_segsz);
2547170589Syongari			desc64->flags |= htole16(tso_segsz >> 16);
2548170589Syongari		}
2549170589Syongari		/*
2550170589Syongari		 * finally, set the valid/checksum/TSO bit in the first
2551170589Syongari		 * descriptor.
2552170589Syongari		 */
2553170589Syongari		desc64->flags |= htole16(NFE_TX_VALID | cflags);
2554159952Sobrien	} else {
2555159967Sobrien		if (sc->nfe_flags & NFE_JUMBO_SUP)
2556170589Syongari			desc32->flags |= htole16(NFE_TX_LASTFRAG_V2);
2557159952Sobrien		else
2558170589Syongari			desc32->flags |= htole16(NFE_TX_LASTFRAG_V1);
2559170589Syongari		desc32 = &sc->txq.desc32[si];
2560170589Syongari		if (tso_segsz != 0) {
2561170589Syongari			/*
2562170589Syongari			 * XXX
2563170589Syongari			 * The following indicates the descriptor element
2564170589Syongari			 * is a 32bit quantity.
2565170589Syongari			 */
2566170589Syongari			desc32->length |= htole16((uint16_t)tso_segsz);
2567170589Syongari			desc32->flags |= htole16(tso_segsz >> 16);
2568170589Syongari		}
2569170589Syongari		/*
2570170589Syongari		 * finally, set the valid/checksum/TSO bit in the first
2571170589Syongari		 * descriptor.
2572170589Syongari		 */
2573170589Syongari		desc32->flags |= htole16(NFE_TX_VALID | cflags);
2574159952Sobrien	}
2575159952Sobrien
2576170589Syongari	sc->txq.cur = prod;
2577170589Syongari	prod = (prod + NFE_TX_RING_COUNT - 1) % NFE_TX_RING_COUNT;
2578170589Syongari	sc->txq.data[si].tx_data_map = sc->txq.data[prod].tx_data_map;
2579170589Syongari	sc->txq.data[prod].tx_data_map = map;
2580170589Syongari	sc->txq.data[prod].m = m;
2581159952Sobrien
2582159967Sobrien	bus_dmamap_sync(sc->txq.tx_data_tag, map, BUS_DMASYNC_PREWRITE);
2583159952Sobrien
2584170589Syongari	return (0);
2585159952Sobrien}
2586159952Sobrien
2587159967Sobrien
2588163503Sobrienstatic void
2589163503Sobriennfe_setmulti(struct nfe_softc *sc)
2590159952Sobrien{
2591159967Sobrien	struct ifnet *ifp = sc->nfe_ifp;
2592163503Sobrien	struct ifmultiaddr *ifma;
2593163503Sobrien	int i;
2594170589Syongari	uint32_t filter;
2595170589Syongari	uint8_t addr[ETHER_ADDR_LEN], mask[ETHER_ADDR_LEN];
2596170589Syongari	uint8_t etherbroadcastaddr[ETHER_ADDR_LEN] = {
2597163503Sobrien		0xff, 0xff, 0xff, 0xff, 0xff, 0xff
2598163503Sobrien	};
2599159967Sobrien
2600159967Sobrien	NFE_LOCK_ASSERT(sc);
2601159967Sobrien
2602159967Sobrien	if ((ifp->if_flags & (IFF_ALLMULTI | IFF_PROMISC)) != 0) {
2603159967Sobrien		bzero(addr, ETHER_ADDR_LEN);
2604159967Sobrien		bzero(mask, ETHER_ADDR_LEN);
2605159967Sobrien		goto done;
2606159967Sobrien	}
2607159967Sobrien
2608159967Sobrien	bcopy(etherbroadcastaddr, addr, ETHER_ADDR_LEN);
2609159967Sobrien	bcopy(etherbroadcastaddr, mask, ETHER_ADDR_LEN);
2610159967Sobrien
2611159967Sobrien	IF_ADDR_LOCK(ifp);
2612159967Sobrien	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
2613159967Sobrien		u_char *addrp;
2614159967Sobrien
2615159967Sobrien		if (ifma->ifma_addr->sa_family != AF_LINK)
2616159967Sobrien			continue;
2617159967Sobrien
2618159967Sobrien		addrp = LLADDR((struct sockaddr_dl *) ifma->ifma_addr);
2619159967Sobrien		for (i = 0; i < ETHER_ADDR_LEN; i++) {
2620159967Sobrien			u_int8_t mcaddr = addrp[i];
2621159967Sobrien			addr[i] &= mcaddr;
2622159967Sobrien			mask[i] &= ~mcaddr;
2623159967Sobrien		}
2624159967Sobrien	}
2625159967Sobrien	IF_ADDR_UNLOCK(ifp);
2626159967Sobrien
2627159967Sobrien	for (i = 0; i < ETHER_ADDR_LEN; i++) {
2628159967Sobrien		mask[i] |= addr[i];
2629159967Sobrien	}
2630159967Sobrien
2631159967Sobriendone:
2632159967Sobrien	addr[0] |= 0x01;	/* make sure multicast bit is set */
2633159967Sobrien
2634159967Sobrien	NFE_WRITE(sc, NFE_MULTIADDR_HI,
2635159967Sobrien	    addr[3] << 24 | addr[2] << 16 | addr[1] << 8 | addr[0]);
2636159967Sobrien	NFE_WRITE(sc, NFE_MULTIADDR_LO,
2637159967Sobrien	    addr[5] <<  8 | addr[4]);
2638159967Sobrien	NFE_WRITE(sc, NFE_MULTIMASK_HI,
2639159967Sobrien	    mask[3] << 24 | mask[2] << 16 | mask[1] << 8 | mask[0]);
2640159967Sobrien	NFE_WRITE(sc, NFE_MULTIMASK_LO,
2641159967Sobrien	    mask[5] <<  8 | mask[4]);
2642159967Sobrien
2643170589Syongari	filter = NFE_READ(sc, NFE_RXFILTER);
2644170589Syongari	filter &= NFE_PFF_RX_PAUSE;
2645170589Syongari	filter |= NFE_RXFILTER_MAGIC;
2646170589Syongari	filter |= (ifp->if_flags & IFF_PROMISC) ? NFE_PFF_PROMISC : NFE_PFF_U2M;
2647159967Sobrien	NFE_WRITE(sc, NFE_RXFILTER, filter);
2648159967Sobrien}
2649159967Sobrien
2650163503Sobrien
2651163503Sobrienstatic void
2652170589Syongarinfe_tx_task(void *arg, int pending)
2653159967Sobrien{
2654170589Syongari	struct ifnet *ifp;
2655159967Sobrien
2656170589Syongari	ifp = (struct ifnet *)arg;
2657170589Syongari	nfe_start(ifp);
2658159967Sobrien}
2659159967Sobrien
2660163503Sobrien
2661163503Sobrienstatic void
2662170589Syongarinfe_start(struct ifnet *ifp)
2663159967Sobrien{
2664159952Sobrien	struct nfe_softc *sc = ifp->if_softc;
2665163503Sobrien	struct mbuf *m0;
2666170589Syongari	int enq;
2667159952Sobrien
2668170589Syongari	NFE_LOCK(sc);
2669170589Syongari
2670170589Syongari	if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) !=
2671170589Syongari	    IFF_DRV_RUNNING || sc->nfe_link == 0) {
2672170589Syongari		NFE_UNLOCK(sc);
2673159967Sobrien		return;
2674159967Sobrien	}
2675159967Sobrien
2676170589Syongari	for (enq = 0; !IFQ_DRV_IS_EMPTY(&ifp->if_snd);) {
2677170589Syongari		IFQ_DRV_DEQUEUE(&ifp->if_snd, m0);
2678159952Sobrien		if (m0 == NULL)
2679159952Sobrien			break;
2680159952Sobrien
2681170589Syongari		if (nfe_encap(sc, &m0) != 0) {
2682170589Syongari			if (m0 == NULL)
2683170589Syongari				break;
2684170589Syongari			IFQ_DRV_PREPEND(&ifp->if_snd, m0);
2685159967Sobrien			ifp->if_drv_flags |= IFF_DRV_OACTIVE;
2686159952Sobrien			break;
2687159952Sobrien		}
2688170589Syongari		enq++;
2689167190Scsjp		ETHER_BPF_MTAP(ifp, m0);
2690159952Sobrien	}
2691159952Sobrien
2692170589Syongari	if (enq > 0) {
2693170589Syongari		bus_dmamap_sync(sc->txq.tx_desc_tag, sc->txq.tx_desc_map,
2694170589Syongari		    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
2695159952Sobrien
2696170589Syongari		/* kick Tx */
2697170589Syongari		NFE_WRITE(sc, NFE_RXTX_CTL, NFE_RXTX_KICKTX | sc->rxtxctl);
2698159952Sobrien
2699170589Syongari		/*
2700170589Syongari		 * Set a timeout in case the chip goes out to lunch.
2701170589Syongari		 */
2702170589Syongari		sc->nfe_watchdog_timer = 5;
2703170589Syongari	}
2704159967Sobrien
2705170589Syongari	NFE_UNLOCK(sc);
2706159952Sobrien}
2707159952Sobrien
2708163503Sobrien
2709163503Sobrienstatic void
2710163503Sobriennfe_watchdog(struct ifnet *ifp)
2711159952Sobrien{
2712159952Sobrien	struct nfe_softc *sc = ifp->if_softc;
2713159952Sobrien
2714170589Syongari	if (sc->nfe_watchdog_timer == 0 || --sc->nfe_watchdog_timer)
2715170589Syongari		return;
2716159952Sobrien
2717170589Syongari	/* Check if we've lost Tx completion interrupt. */
2718170589Syongari	nfe_txeof(sc);
2719170589Syongari	if (sc->txq.queued == 0) {
2720170589Syongari		if_printf(ifp, "watchdog timeout (missed Tx interrupts) "
2721170589Syongari		    "-- recovering\n");
2722170589Syongari		if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
2723173674Ssam			taskqueue_enqueue_fast(sc->nfe_tq, &sc->nfe_tx_task);
2724170589Syongari		return;
2725170589Syongari	}
2726170589Syongari	/* Check if we've lost start Tx command. */
2727170589Syongari	sc->nfe_force_tx++;
2728170589Syongari	if (sc->nfe_force_tx <= 3) {
2729170589Syongari		/*
2730170589Syongari		 * If this is the case for watchdog timeout, the following
2731170589Syongari		 * code should go to nfe_txeof().
2732170589Syongari		 */
2733170589Syongari		NFE_WRITE(sc, NFE_RXTX_CTL, NFE_RXTX_KICKTX | sc->rxtxctl);
2734170589Syongari		return;
2735170589Syongari	}
2736170589Syongari	sc->nfe_force_tx = 0;
2737170589Syongari
2738170589Syongari	if_printf(ifp, "watchdog timeout\n");
2739170589Syongari
2740159967Sobrien	ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
2741159952Sobrien	ifp->if_oerrors++;
2742170589Syongari	nfe_init_locked(sc);
2743159952Sobrien}
2744159952Sobrien
2745163503Sobrien
2746163503Sobrienstatic void
2747163503Sobriennfe_init(void *xsc)
2748159952Sobrien{
2749159967Sobrien	struct nfe_softc *sc = xsc;
2750159952Sobrien
2751159967Sobrien	NFE_LOCK(sc);
2752159967Sobrien	nfe_init_locked(sc);
2753159967Sobrien	NFE_UNLOCK(sc);
2754159967Sobrien}
2755159967Sobrien
2756163503Sobrien
2757163503Sobrienstatic void
2758163503Sobriennfe_init_locked(void *xsc)
2759159967Sobrien{
2760159967Sobrien	struct nfe_softc *sc = xsc;
2761159967Sobrien	struct ifnet *ifp = sc->nfe_ifp;
2762159967Sobrien	struct mii_data *mii;
2763170589Syongari	uint32_t val;
2764170589Syongari	int error;
2765159967Sobrien
2766159967Sobrien	NFE_LOCK_ASSERT(sc);
2767159967Sobrien
2768159967Sobrien	mii = device_get_softc(sc->nfe_miibus);
2769159967Sobrien
2770170589Syongari	if (ifp->if_drv_flags & IFF_DRV_RUNNING)
2771159967Sobrien		return;
2772170589Syongari
2773170589Syongari	nfe_stop(ifp);
2774170589Syongari
2775170589Syongari	sc->nfe_framesize = ifp->if_mtu + NFE_RX_HEADERS;
2776170589Syongari
2777170589Syongari	nfe_init_tx_ring(sc, &sc->txq);
2778170589Syongari	if (sc->nfe_framesize > (MCLBYTES - ETHER_HDR_LEN))
2779170589Syongari		error = nfe_init_jrx_ring(sc, &sc->jrxq);
2780170589Syongari	else
2781170589Syongari		error = nfe_init_rx_ring(sc, &sc->rxq);
2782170589Syongari	if (error != 0) {
2783170589Syongari		device_printf(sc->nfe_dev,
2784170589Syongari		    "initialization failed: no memory for rx buffers\n");
2785170589Syongari		nfe_stop(ifp);
2786170589Syongari		return;
2787159967Sobrien	}
2788159967Sobrien
2789170589Syongari	val = 0;
2790170589Syongari	if ((sc->nfe_flags & NFE_CORRECT_MACADDR) != 0)
2791170589Syongari		val |= NFE_MAC_ADDR_INORDER;
2792170589Syongari	NFE_WRITE(sc, NFE_TX_UNK, val);
2793159952Sobrien	NFE_WRITE(sc, NFE_STATUS, 0);
2794159952Sobrien
2795170589Syongari	if ((sc->nfe_flags & NFE_TX_FLOW_CTRL) != 0)
2796170589Syongari		NFE_WRITE(sc, NFE_TX_PAUSE_FRAME, NFE_TX_PAUSE_FRAME_DISABLE);
2797170589Syongari
2798159952Sobrien	sc->rxtxctl = NFE_RXTX_BIT2;
2799159967Sobrien	if (sc->nfe_flags & NFE_40BIT_ADDR)
2800159952Sobrien		sc->rxtxctl |= NFE_RXTX_V3MAGIC;
2801159967Sobrien	else if (sc->nfe_flags & NFE_JUMBO_SUP)
2802159952Sobrien		sc->rxtxctl |= NFE_RXTX_V2MAGIC;
2803164656Sobrien
2804170589Syongari	if ((ifp->if_capenable & IFCAP_RXCSUM) != 0)
2805159952Sobrien		sc->rxtxctl |= NFE_RXTX_RXCSUM;
2806170589Syongari	if ((ifp->if_capenable & IFCAP_VLAN_HWTAGGING) != 0)
2807170589Syongari		sc->rxtxctl |= NFE_RXTX_VTAG_INSERT | NFE_RXTX_VTAG_STRIP;
2808159967Sobrien
2809159952Sobrien	NFE_WRITE(sc, NFE_RXTX_CTL, NFE_RXTX_RESET | sc->rxtxctl);
2810159952Sobrien	DELAY(10);
2811159952Sobrien	NFE_WRITE(sc, NFE_RXTX_CTL, sc->rxtxctl);
2812159952Sobrien
2813170589Syongari	if ((ifp->if_capenable & IFCAP_VLAN_HWTAGGING) != 0)
2814159952Sobrien		NFE_WRITE(sc, NFE_VTAG_CTL, NFE_VTAG_ENABLE);
2815170589Syongari	else
2816170589Syongari		NFE_WRITE(sc, NFE_VTAG_CTL, 0);
2817159952Sobrien
2818159952Sobrien	NFE_WRITE(sc, NFE_SETUP_R6, 0);
2819159952Sobrien
2820159952Sobrien	/* set MAC address */
2821170589Syongari	nfe_set_macaddr(sc, IF_LLADDR(ifp));
2822159952Sobrien
2823159952Sobrien	/* tell MAC where rings are in memory */
2824170589Syongari	if (sc->nfe_framesize > MCLBYTES - ETHER_HDR_LEN) {
2825170589Syongari		NFE_WRITE(sc, NFE_RX_RING_ADDR_HI,
2826170589Syongari		    NFE_ADDR_HI(sc->jrxq.jphysaddr));
2827170589Syongari		NFE_WRITE(sc, NFE_RX_RING_ADDR_LO,
2828170589Syongari		    NFE_ADDR_LO(sc->jrxq.jphysaddr));
2829170589Syongari	} else {
2830170589Syongari		NFE_WRITE(sc, NFE_RX_RING_ADDR_HI,
2831170589Syongari		    NFE_ADDR_HI(sc->rxq.physaddr));
2832170589Syongari		NFE_WRITE(sc, NFE_RX_RING_ADDR_LO,
2833170589Syongari		    NFE_ADDR_LO(sc->rxq.physaddr));
2834170589Syongari	}
2835170589Syongari	NFE_WRITE(sc, NFE_TX_RING_ADDR_HI, NFE_ADDR_HI(sc->txq.physaddr));
2836170589Syongari	NFE_WRITE(sc, NFE_TX_RING_ADDR_LO, NFE_ADDR_LO(sc->txq.physaddr));
2837159952Sobrien
2838159952Sobrien	NFE_WRITE(sc, NFE_RING_SIZE,
2839159952Sobrien	    (NFE_RX_RING_COUNT - 1) << 16 |
2840159952Sobrien	    (NFE_TX_RING_COUNT - 1));
2841159952Sobrien
2842170589Syongari	NFE_WRITE(sc, NFE_RXBUFSZ, sc->nfe_framesize);
2843159952Sobrien
2844159952Sobrien	/* force MAC to wakeup */
2845170589Syongari	val = NFE_READ(sc, NFE_PWR_STATE);
2846170589Syongari	if ((val & NFE_PWR_WAKEUP) == 0)
2847170589Syongari		NFE_WRITE(sc, NFE_PWR_STATE, val | NFE_PWR_WAKEUP);
2848159952Sobrien	DELAY(10);
2849170589Syongari	val = NFE_READ(sc, NFE_PWR_STATE);
2850170589Syongari	NFE_WRITE(sc, NFE_PWR_STATE, val | NFE_PWR_VALID);
2851159952Sobrien
2852159952Sobrien#if 1
2853159952Sobrien	/* configure interrupts coalescing/mitigation */
2854159952Sobrien	NFE_WRITE(sc, NFE_IMTIMER, NFE_IM_DEFAULT);
2855159952Sobrien#else
2856159952Sobrien	/* no interrupt mitigation: one interrupt per packet */
2857159952Sobrien	NFE_WRITE(sc, NFE_IMTIMER, 970);
2858159952Sobrien#endif
2859159952Sobrien
2860170589Syongari	NFE_WRITE(sc, NFE_SETUP_R1, NFE_R1_MAGIC_10_100);
2861159952Sobrien	NFE_WRITE(sc, NFE_SETUP_R2, NFE_R2_MAGIC);
2862159952Sobrien	NFE_WRITE(sc, NFE_SETUP_R6, NFE_R6_MAGIC);
2863159952Sobrien
2864159952Sobrien	/* update MAC knowledge of PHY; generates a NFE_IRQ_LINK interrupt */
2865159952Sobrien	NFE_WRITE(sc, NFE_STATUS, sc->mii_phyaddr << 24 | NFE_STATUS_MAGIC);
2866159952Sobrien
2867159952Sobrien	NFE_WRITE(sc, NFE_SETUP_R4, NFE_R4_MAGIC);
2868159952Sobrien	NFE_WRITE(sc, NFE_WOL_CTL, NFE_WOL_MAGIC);
2869159952Sobrien
2870159952Sobrien	sc->rxtxctl &= ~NFE_RXTX_BIT2;
2871159952Sobrien	NFE_WRITE(sc, NFE_RXTX_CTL, sc->rxtxctl);
2872159952Sobrien	DELAY(10);
2873159952Sobrien	NFE_WRITE(sc, NFE_RXTX_CTL, NFE_RXTX_BIT1 | sc->rxtxctl);
2874159952Sobrien
2875159952Sobrien	/* set Rx filter */
2876159952Sobrien	nfe_setmulti(sc);
2877159952Sobrien
2878159952Sobrien	/* enable Rx */
2879159952Sobrien	NFE_WRITE(sc, NFE_RX_CTL, NFE_RX_START);
2880159952Sobrien
2881159952Sobrien	/* enable Tx */
2882159952Sobrien	NFE_WRITE(sc, NFE_TX_CTL, NFE_TX_START);
2883159952Sobrien
2884159952Sobrien	NFE_WRITE(sc, NFE_PHY_STATUS, 0xf);
2885159952Sobrien
2886159967Sobrien#ifdef DEVICE_POLLING
2887159967Sobrien	if (ifp->if_capenable & IFCAP_POLLING)
2888170589Syongari		nfe_disable_intr(sc);
2889159967Sobrien	else
2890159967Sobrien#endif
2891170589Syongari	nfe_set_intr(sc);
2892170589Syongari	nfe_enable_intr(sc); /* enable interrupts */
2893159952Sobrien
2894159967Sobrien	ifp->if_drv_flags |= IFF_DRV_RUNNING;
2895159967Sobrien	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
2896159952Sobrien
2897159967Sobrien	sc->nfe_link = 0;
2898170589Syongari	mii_mediachg(mii);
2899159952Sobrien
2900170589Syongari	callout_reset(&sc->nfe_stat_ch, hz, nfe_tick, sc);
2901159952Sobrien}
2902159952Sobrien
2903163503Sobrien
2904163503Sobrienstatic void
2905170589Syongarinfe_stop(struct ifnet *ifp)
2906159952Sobrien{
2907159952Sobrien	struct nfe_softc *sc = ifp->if_softc;
2908170589Syongari	struct nfe_rx_ring *rx_ring;
2909170589Syongari	struct nfe_jrx_ring *jrx_ring;
2910170589Syongari	struct nfe_tx_ring *tx_ring;
2911170589Syongari	struct nfe_rx_data *rdata;
2912170589Syongari	struct nfe_tx_data *tdata;
2913170589Syongari	int i;
2914159952Sobrien
2915159967Sobrien	NFE_LOCK_ASSERT(sc);
2916159952Sobrien
2917170589Syongari	sc->nfe_watchdog_timer = 0;
2918159967Sobrien	ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
2919159952Sobrien
2920159967Sobrien	callout_stop(&sc->nfe_stat_ch);
2921159967Sobrien
2922159952Sobrien	/* abort Tx */
2923159952Sobrien	NFE_WRITE(sc, NFE_TX_CTL, 0);
2924159952Sobrien
2925159952Sobrien	/* disable Rx */
2926159952Sobrien	NFE_WRITE(sc, NFE_RX_CTL, 0);
2927159952Sobrien
2928159952Sobrien	/* disable interrupts */
2929170589Syongari	nfe_disable_intr(sc);
2930159952Sobrien
2931159967Sobrien	sc->nfe_link = 0;
2932159967Sobrien
2933170589Syongari	/* free Rx and Tx mbufs still in the queues. */
2934170589Syongari	rx_ring = &sc->rxq;
2935170589Syongari	for (i = 0; i < NFE_RX_RING_COUNT; i++) {
2936170589Syongari		rdata = &rx_ring->data[i];
2937170589Syongari		if (rdata->m != NULL) {
2938170589Syongari			bus_dmamap_sync(rx_ring->rx_data_tag,
2939170589Syongari			    rdata->rx_data_map, BUS_DMASYNC_POSTREAD);
2940170589Syongari			bus_dmamap_unload(rx_ring->rx_data_tag,
2941170589Syongari			    rdata->rx_data_map);
2942170589Syongari			m_freem(rdata->m);
2943170589Syongari			rdata->m = NULL;
2944170589Syongari		}
2945170589Syongari	}
2946159952Sobrien
2947170589Syongari	if ((sc->nfe_flags & NFE_JUMBO_SUP) != 0) {
2948170589Syongari		jrx_ring = &sc->jrxq;
2949170589Syongari		for (i = 0; i < NFE_JUMBO_RX_RING_COUNT; i++) {
2950170589Syongari			rdata = &jrx_ring->jdata[i];
2951170589Syongari			if (rdata->m != NULL) {
2952170589Syongari				bus_dmamap_sync(jrx_ring->jrx_data_tag,
2953170589Syongari				    rdata->rx_data_map, BUS_DMASYNC_POSTREAD);
2954170589Syongari				bus_dmamap_unload(jrx_ring->jrx_data_tag,
2955170589Syongari				    rdata->rx_data_map);
2956170589Syongari				m_freem(rdata->m);
2957170589Syongari				rdata->m = NULL;
2958170589Syongari			}
2959170589Syongari		}
2960170589Syongari	}
2961170589Syongari
2962170589Syongari	tx_ring = &sc->txq;
2963170589Syongari	for (i = 0; i < NFE_RX_RING_COUNT; i++) {
2964170589Syongari		tdata = &tx_ring->data[i];
2965170589Syongari		if (tdata->m != NULL) {
2966170589Syongari			bus_dmamap_sync(tx_ring->tx_data_tag,
2967170589Syongari			    tdata->tx_data_map, BUS_DMASYNC_POSTWRITE);
2968170589Syongari			bus_dmamap_unload(tx_ring->tx_data_tag,
2969170589Syongari			    tdata->tx_data_map);
2970170589Syongari			m_freem(tdata->m);
2971170589Syongari			tdata->m = NULL;
2972170589Syongari		}
2973170589Syongari	}
2974159952Sobrien}
2975159952Sobrien
2976163503Sobrien
2977163503Sobrienstatic int
2978163503Sobriennfe_ifmedia_upd(struct ifnet *ifp)
2979159952Sobrien{
2980159967Sobrien	struct nfe_softc *sc = ifp->if_softc;
2981170589Syongari	struct mii_data *mii;
2982159952Sobrien
2983159967Sobrien	NFE_LOCK(sc);
2984159967Sobrien	mii = device_get_softc(sc->nfe_miibus);
2985159967Sobrien	mii_mediachg(mii);
2986170589Syongari	NFE_UNLOCK(sc);
2987159967Sobrien
2988159967Sobrien	return (0);
2989159952Sobrien}
2990159952Sobrien
2991163503Sobrien
2992163503Sobrienstatic void
2993163503Sobriennfe_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
2994159952Sobrien{
2995163503Sobrien	struct nfe_softc *sc;
2996163503Sobrien	struct mii_data *mii;
2997159952Sobrien
2998159967Sobrien	sc = ifp->if_softc;
2999159952Sobrien
3000159967Sobrien	NFE_LOCK(sc);
3001159967Sobrien	mii = device_get_softc(sc->nfe_miibus);
3002159967Sobrien	mii_pollstat(mii);
3003159967Sobrien	NFE_UNLOCK(sc);
3004159952Sobrien
3005159967Sobrien	ifmr->ifm_active = mii->mii_media_active;
3006159967Sobrien	ifmr->ifm_status = mii->mii_media_status;
3007159952Sobrien}
3008159952Sobrien
3009163503Sobrien
3010170589Syongarivoid
3011159967Sobriennfe_tick(void *xsc)
3012159952Sobrien{
3013159967Sobrien	struct nfe_softc *sc;
3014163503Sobrien	struct mii_data *mii;
3015163503Sobrien	struct ifnet *ifp;
3016159952Sobrien
3017170589Syongari	sc = (struct nfe_softc *)xsc;
3018159952Sobrien
3019163503Sobrien	NFE_LOCK_ASSERT(sc);
3020159952Sobrien
3021159967Sobrien	ifp = sc->nfe_ifp;
3022159952Sobrien
3023159967Sobrien	mii = device_get_softc(sc->nfe_miibus);
3024159967Sobrien	mii_tick(mii);
3025170589Syongari	nfe_watchdog(ifp);
3026159967Sobrien	callout_reset(&sc->nfe_stat_ch, hz, nfe_tick, sc);
3027159952Sobrien}
3028159952Sobrien
3029159952Sobrien
3030173839Syongaristatic int
3031163503Sobriennfe_shutdown(device_t dev)
3032159952Sobrien{
3033159967Sobrien	struct nfe_softc *sc;
3034159967Sobrien	struct ifnet *ifp;
3035159952Sobrien
3036159967Sobrien	sc = device_get_softc(dev);
3037159952Sobrien
3038159967Sobrien	NFE_LOCK(sc);
3039159967Sobrien	ifp = sc->nfe_ifp;
3040170589Syongari	nfe_stop(ifp);
3041159967Sobrien	/* nfe_reset(sc); */
3042159967Sobrien	NFE_UNLOCK(sc);
3043173839Syongari
3044173839Syongari	return (0);
3045159952Sobrien}
3046159952Sobrien
3047159952Sobrien
3048163503Sobrienstatic void
3049170589Syongarinfe_get_macaddr(struct nfe_softc *sc, uint8_t *addr)
3050159952Sobrien{
3051170589Syongari	uint32_t val;
3052159952Sobrien
3053170589Syongari	if ((sc->nfe_flags & NFE_CORRECT_MACADDR) == 0) {
3054170589Syongari		val = NFE_READ(sc, NFE_MACADDR_LO);
3055170589Syongari		addr[0] = (val >> 8) & 0xff;
3056170589Syongari		addr[1] = (val & 0xff);
3057159952Sobrien
3058170589Syongari		val = NFE_READ(sc, NFE_MACADDR_HI);
3059170589Syongari		addr[2] = (val >> 24) & 0xff;
3060170589Syongari		addr[3] = (val >> 16) & 0xff;
3061170589Syongari		addr[4] = (val >>  8) & 0xff;
3062170589Syongari		addr[5] = (val & 0xff);
3063170589Syongari	} else {
3064170589Syongari		val = NFE_READ(sc, NFE_MACADDR_LO);
3065170589Syongari		addr[5] = (val >> 8) & 0xff;
3066170589Syongari		addr[4] = (val & 0xff);
3067170589Syongari
3068170589Syongari		val = NFE_READ(sc, NFE_MACADDR_HI);
3069170589Syongari		addr[3] = (val >> 24) & 0xff;
3070170589Syongari		addr[2] = (val >> 16) & 0xff;
3071170589Syongari		addr[1] = (val >>  8) & 0xff;
3072170589Syongari		addr[0] = (val & 0xff);
3073170589Syongari	}
3074159952Sobrien}
3075159952Sobrien
3076163503Sobrien
3077163503Sobrienstatic void
3078170589Syongarinfe_set_macaddr(struct nfe_softc *sc, uint8_t *addr)
3079159952Sobrien{
3080159967Sobrien
3081159967Sobrien	NFE_WRITE(sc, NFE_MACADDR_LO, addr[5] <<  8 | addr[4]);
3082159967Sobrien	NFE_WRITE(sc, NFE_MACADDR_HI, addr[3] << 24 | addr[2] << 16 |
3083159967Sobrien	    addr[1] << 8 | addr[0]);
3084159952Sobrien}
3085159952Sobrien
3086163503Sobrien
3087159967Sobrien/*
3088159967Sobrien * Map a single buffer address.
3089159967Sobrien */
3090159967Sobrien
3091159967Sobrienstatic void
3092170589Syongarinfe_dma_map_segs(void *arg, bus_dma_segment_t *segs, int nseg, int error)
3093159952Sobrien{
3094170589Syongari	struct nfe_dmamap_arg *ctx;
3095159952Sobrien
3096170589Syongari	if (error != 0)
3097159967Sobrien		return;
3098159952Sobrien
3099159967Sobrien	KASSERT(nseg == 1, ("too many DMA segments, %d should be 1", nseg));
3100159967Sobrien
3101170589Syongari	ctx = (struct nfe_dmamap_arg *)arg;
3102170589Syongari	ctx->nfe_busaddr = segs[0].ds_addr;
3103170589Syongari}
3104159967Sobrien
3105170589Syongari
3106170589Syongaristatic int
3107170589Syongarisysctl_int_range(SYSCTL_HANDLER_ARGS, int low, int high)
3108170589Syongari{
3109170589Syongari	int error, value;
3110170589Syongari
3111170589Syongari	if (!arg1)
3112170589Syongari		return (EINVAL);
3113170589Syongari	value = *(int *)arg1;
3114170589Syongari	error = sysctl_handle_int(oidp, &value, 0, req);
3115170589Syongari	if (error || !req->newptr)
3116170589Syongari		return (error);
3117170589Syongari	if (value < low || value > high)
3118170589Syongari		return (EINVAL);
3119170589Syongari	*(int *)arg1 = value;
3120170589Syongari
3121170589Syongari	return (0);
3122159952Sobrien}
3123170589Syongari
3124170589Syongari
3125170589Syongaristatic int
3126170589Syongarisysctl_hw_nfe_proc_limit(SYSCTL_HANDLER_ARGS)
3127170589Syongari{
3128170589Syongari
3129170589Syongari	return (sysctl_int_range(oidp, arg1, arg2, req, NFE_PROC_MIN,
3130170589Syongari	    NFE_PROC_MAX));
3131170589Syongari}
3132