if_nfe.c revision 176859
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 176859 2008-03-06 01:47:53Z yongari $");
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 __inline void nfe_discard_rxbuf(struct nfe_softc *, int);
93170589Syongaristatic __inline void nfe_discard_jrxbuf(struct nfe_softc *, int);
94170589Syongaristatic int nfe_newbuf(struct nfe_softc *, int);
95170589Syongaristatic int nfe_jnewbuf(struct nfe_softc *, int);
96170589Syongaristatic int  nfe_rxeof(struct nfe_softc *, int);
97170589Syongaristatic int  nfe_jrxeof(struct nfe_softc *, int);
98159967Sobrienstatic void nfe_txeof(struct nfe_softc *);
99170589Syongaristatic int  nfe_encap(struct nfe_softc *, struct mbuf **);
100159967Sobrienstatic void nfe_setmulti(struct nfe_softc *);
101170589Syongaristatic void nfe_tx_task(void *, int);
102159967Sobrienstatic void nfe_start(struct ifnet *);
103159967Sobrienstatic void nfe_watchdog(struct ifnet *);
104159967Sobrienstatic void nfe_init(void *);
105159967Sobrienstatic void nfe_init_locked(void *);
106170589Syongaristatic void nfe_stop(struct ifnet *);
107159967Sobrienstatic int  nfe_alloc_rx_ring(struct nfe_softc *, struct nfe_rx_ring *);
108171559Syongaristatic void nfe_alloc_jrx_ring(struct nfe_softc *, struct nfe_jrx_ring *);
109170589Syongaristatic int  nfe_init_rx_ring(struct nfe_softc *, struct nfe_rx_ring *);
110170589Syongaristatic int  nfe_init_jrx_ring(struct nfe_softc *, struct nfe_jrx_ring *);
111159967Sobrienstatic void nfe_free_rx_ring(struct nfe_softc *, struct nfe_rx_ring *);
112170589Syongaristatic void nfe_free_jrx_ring(struct nfe_softc *, struct nfe_jrx_ring *);
113159967Sobrienstatic int  nfe_alloc_tx_ring(struct nfe_softc *, struct nfe_tx_ring *);
114170589Syongaristatic void nfe_init_tx_ring(struct nfe_softc *, struct nfe_tx_ring *);
115159967Sobrienstatic void nfe_free_tx_ring(struct nfe_softc *, struct nfe_tx_ring *);
116159967Sobrienstatic int  nfe_ifmedia_upd(struct ifnet *);
117159967Sobrienstatic void nfe_ifmedia_sts(struct ifnet *, struct ifmediareq *);
118159967Sobrienstatic void nfe_tick(void *);
119170589Syongaristatic void nfe_get_macaddr(struct nfe_softc *, uint8_t *);
120170589Syongaristatic void nfe_set_macaddr(struct nfe_softc *, uint8_t *);
121170589Syongaristatic void nfe_dma_map_segs(void *, bus_dma_segment_t *, int, int);
122159952Sobrien
123170589Syongaristatic int sysctl_int_range(SYSCTL_HANDLER_ARGS, int, int);
124170589Syongaristatic int sysctl_hw_nfe_proc_limit(SYSCTL_HANDLER_ARGS);
125170589Syongari
126159952Sobrien#ifdef NFE_DEBUG
127170589Syongaristatic int nfedebug = 0;
128170589Syongari#define	DPRINTF(sc, ...)	do {				\
129170589Syongari	if (nfedebug)						\
130170589Syongari		device_printf((sc)->nfe_dev, __VA_ARGS__);	\
131170589Syongari} while (0)
132170589Syongari#define	DPRINTFN(sc, n, ...)	do {				\
133170589Syongari	if (nfedebug >= (n))					\
134170589Syongari		device_printf((sc)->nfe_dev, __VA_ARGS__);	\
135170589Syongari} while (0)
136159952Sobrien#else
137170589Syongari#define	DPRINTF(sc, ...)
138170589Syongari#define	DPRINTFN(sc, n, ...)
139159952Sobrien#endif
140159952Sobrien
141159967Sobrien#define	NFE_LOCK(_sc)		mtx_lock(&(_sc)->nfe_mtx)
142159967Sobrien#define	NFE_UNLOCK(_sc)		mtx_unlock(&(_sc)->nfe_mtx)
143159967Sobrien#define	NFE_LOCK_ASSERT(_sc)	mtx_assert(&(_sc)->nfe_mtx, MA_OWNED)
144159967Sobrien
145170589Syongari/* Tunables. */
146170589Syongaristatic int msi_disable = 0;
147170589Syongaristatic int msix_disable = 0;
148171559Syongaristatic int jumbo_disable = 0;
149170589SyongariTUNABLE_INT("hw.nfe.msi_disable", &msi_disable);
150170589SyongariTUNABLE_INT("hw.nfe.msix_disable", &msix_disable);
151171559SyongariTUNABLE_INT("hw.nfe.jumbo_disable", &jumbo_disable);
152159967Sobrien
153159967Sobrienstatic device_method_t nfe_methods[] = {
154159967Sobrien	/* Device interface */
155159967Sobrien	DEVMETHOD(device_probe,		nfe_probe),
156159967Sobrien	DEVMETHOD(device_attach,	nfe_attach),
157159967Sobrien	DEVMETHOD(device_detach,	nfe_detach),
158170589Syongari	DEVMETHOD(device_suspend,	nfe_suspend),
159170589Syongari	DEVMETHOD(device_resume,	nfe_resume),
160159967Sobrien	DEVMETHOD(device_shutdown,	nfe_shutdown),
161159967Sobrien
162159967Sobrien	/* bus interface */
163159967Sobrien	DEVMETHOD(bus_print_child,	bus_generic_print_child),
164159967Sobrien	DEVMETHOD(bus_driver_added,	bus_generic_driver_added),
165159967Sobrien
166159967Sobrien	/* MII interface */
167159967Sobrien	DEVMETHOD(miibus_readreg,	nfe_miibus_readreg),
168159967Sobrien	DEVMETHOD(miibus_writereg,	nfe_miibus_writereg),
169163503Sobrien	DEVMETHOD(miibus_statchg,	nfe_miibus_statchg),
170159967Sobrien
171170589Syongari	{ NULL, NULL }
172159952Sobrien};
173159952Sobrien
174159967Sobrienstatic driver_t nfe_driver = {
175159967Sobrien	"nfe",
176159967Sobrien	nfe_methods,
177159967Sobrien	sizeof(struct nfe_softc)
178159967Sobrien};
179159967Sobrien
180159967Sobrienstatic devclass_t nfe_devclass;
181159967Sobrien
182159967SobrienDRIVER_MODULE(nfe, pci, nfe_driver, nfe_devclass, 0, 0);
183159967SobrienDRIVER_MODULE(miibus, nfe, miibus_driver, miibus_devclass, 0, 0);
184159967Sobrien
185159967Sobrienstatic struct nfe_type nfe_devs[] = {
186159967Sobrien	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE_LAN,
187163503Sobrien	    "NVIDIA nForce MCP Networking Adapter"},
188159967Sobrien	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE2_LAN,
189163503Sobrien	    "NVIDIA nForce2 MCP2 Networking Adapter"},
190159967Sobrien	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE2_400_LAN1,
191163503Sobrien	    "NVIDIA nForce2 400 MCP4 Networking Adapter"},
192159967Sobrien	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE2_400_LAN2,
193163503Sobrien	    "NVIDIA nForce2 400 MCP5 Networking Adapter"},
194163437Sobrien	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE3_LAN1,
195163503Sobrien	    "NVIDIA nForce3 MCP3 Networking Adapter"},
196159967Sobrien	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE3_250_LAN,
197163503Sobrien	    "NVIDIA nForce3 250 MCP6 Networking Adapter"},
198159967Sobrien	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE3_LAN4,
199163503Sobrien	    "NVIDIA nForce3 MCP7 Networking Adapter"},
200159967Sobrien	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE4_LAN1,
201163503Sobrien	    "NVIDIA nForce4 CK804 MCP8 Networking Adapter"},
202159967Sobrien	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE4_LAN2,
203163503Sobrien	    "NVIDIA nForce4 CK804 MCP9 Networking Adapter"},
204159967Sobrien	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP04_LAN1,
205170589Syongari	    "NVIDIA nForce MCP04 Networking Adapter"},		/* MCP10 */
206159967Sobrien	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP04_LAN2,
207170589Syongari	    "NVIDIA nForce MCP04 Networking Adapter"},		/* MCP11 */
208159967Sobrien	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE430_LAN1,
209163503Sobrien	    "NVIDIA nForce 430 MCP12 Networking Adapter"},
210159967Sobrien	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE430_LAN2,
211163503Sobrien	    "NVIDIA nForce 430 MCP13 Networking Adapter"},
212159967Sobrien	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP55_LAN1,
213163503Sobrien	    "NVIDIA nForce MCP55 Networking Adapter"},
214159967Sobrien	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP55_LAN2,
215163503Sobrien	    "NVIDIA nForce MCP55 Networking Adapter"},
216162212Sobrien	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP61_LAN1,
217163503Sobrien	    "NVIDIA nForce MCP61 Networking Adapter"},
218162212Sobrien	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP61_LAN2,
219163503Sobrien	    "NVIDIA nForce MCP61 Networking Adapter"},
220162212Sobrien	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP61_LAN3,
221163503Sobrien	    "NVIDIA nForce MCP61 Networking Adapter"},
222170589Syongari	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP61_LAN4,
223163503Sobrien	    "NVIDIA nForce MCP61 Networking Adapter"},
224162212Sobrien	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP65_LAN1,
225163503Sobrien	    "NVIDIA nForce MCP65 Networking Adapter"},
226162212Sobrien	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP65_LAN2,
227163503Sobrien	    "NVIDIA nForce MCP65 Networking Adapter"},
228162212Sobrien	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP65_LAN3,
229163503Sobrien	    "NVIDIA nForce MCP65 Networking Adapter"},
230170589Syongari	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP65_LAN4,
231163503Sobrien	    "NVIDIA nForce MCP65 Networking Adapter"},
232170589Syongari	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP67_LAN1,
233170589Syongari	    "NVIDIA nForce MCP67 Networking Adapter"},
234170589Syongari	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP67_LAN2,
235170589Syongari	    "NVIDIA nForce MCP67 Networking Adapter"},
236170589Syongari	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP67_LAN3,
237170589Syongari	    "NVIDIA nForce MCP67 Networking Adapter"},
238170589Syongari	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP67_LAN4,
239170589Syongari	    "NVIDIA nForce MCP67 Networking Adapter"},
240159967Sobrien	{0, 0, NULL}
241159967Sobrien};
242159967Sobrien
243159967Sobrien
244159967Sobrien/* Probe for supported hardware ID's */
245159967Sobrienstatic int
246159967Sobriennfe_probe(device_t dev)
247159952Sobrien{
248159967Sobrien	struct nfe_type *t;
249159967Sobrien
250159967Sobrien	t = nfe_devs;
251159967Sobrien	/* Check for matching PCI DEVICE ID's */
252159967Sobrien	while (t->name != NULL) {
253159967Sobrien		if ((pci_get_vendor(dev) == t->vid_id) &&
254159967Sobrien		    (pci_get_device(dev) == t->dev_id)) {
255159967Sobrien			device_set_desc(dev, t->name);
256170589Syongari			return (BUS_PROBE_DEFAULT);
257159967Sobrien		}
258159967Sobrien		t++;
259159967Sobrien	}
260159967Sobrien
261159967Sobrien	return (ENXIO);
262159952Sobrien}
263159952Sobrien
264170589Syongaristatic void
265170589Syongarinfe_alloc_msix(struct nfe_softc *sc, int count)
266170589Syongari{
267170589Syongari	int rid;
268163503Sobrien
269170589Syongari	rid = PCIR_BAR(2);
270170589Syongari	sc->nfe_msix_res = bus_alloc_resource_any(sc->nfe_dev, SYS_RES_MEMORY,
271170589Syongari	    &rid, RF_ACTIVE);
272170589Syongari	if (sc->nfe_msix_res == NULL) {
273170589Syongari		device_printf(sc->nfe_dev,
274170589Syongari		    "couldn't allocate MSIX table resource\n");
275170589Syongari		return;
276170589Syongari	}
277170589Syongari	rid = PCIR_BAR(3);
278170589Syongari	sc->nfe_msix_pba_res = bus_alloc_resource_any(sc->nfe_dev,
279170589Syongari	    SYS_RES_MEMORY, &rid, RF_ACTIVE);
280170589Syongari	if (sc->nfe_msix_pba_res == NULL) {
281170589Syongari		device_printf(sc->nfe_dev,
282170589Syongari		    "couldn't allocate MSIX PBA resource\n");
283170589Syongari		bus_release_resource(sc->nfe_dev, SYS_RES_MEMORY, PCIR_BAR(2),
284170589Syongari		    sc->nfe_msix_res);
285170589Syongari		sc->nfe_msix_res = NULL;
286170589Syongari		return;
287170589Syongari	}
288170589Syongari
289170589Syongari	if (pci_alloc_msix(sc->nfe_dev, &count) == 0) {
290170589Syongari		if (count == NFE_MSI_MESSAGES) {
291170589Syongari			if (bootverbose)
292170589Syongari				device_printf(sc->nfe_dev,
293170589Syongari				    "Using %d MSIX messages\n", count);
294170589Syongari			sc->nfe_msix = 1;
295170589Syongari		} else {
296170589Syongari			if (bootverbose)
297170589Syongari				device_printf(sc->nfe_dev,
298170589Syongari				    "couldn't allocate MSIX\n");
299170589Syongari			pci_release_msi(sc->nfe_dev);
300170589Syongari			bus_release_resource(sc->nfe_dev, SYS_RES_MEMORY,
301170589Syongari			    PCIR_BAR(3), sc->nfe_msix_pba_res);
302170589Syongari			bus_release_resource(sc->nfe_dev, SYS_RES_MEMORY,
303170589Syongari			    PCIR_BAR(2), sc->nfe_msix_res);
304170589Syongari			sc->nfe_msix_pba_res = NULL;
305170589Syongari			sc->nfe_msix_res = NULL;
306170589Syongari		}
307170589Syongari	}
308170589Syongari}
309170589Syongari
310159967Sobrienstatic int
311159967Sobriennfe_attach(device_t dev)
312159952Sobrien{
313159967Sobrien	struct nfe_softc *sc;
314159952Sobrien	struct ifnet *ifp;
315170589Syongari	bus_addr_t dma_addr_max;
316170589Syongari	int error = 0, i, msic, reg, rid;
317159952Sobrien
318159967Sobrien	sc = device_get_softc(dev);
319159967Sobrien	sc->nfe_dev = dev;
320159952Sobrien
321159967Sobrien	mtx_init(&sc->nfe_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK,
322170589Syongari	    MTX_DEF);
323159967Sobrien	callout_init_mtx(&sc->nfe_stat_ch, &sc->nfe_mtx, 0);
324170589Syongari	TASK_INIT(&sc->nfe_link_task, 0, nfe_link_task, sc);
325159967Sobrien
326163503Sobrien	pci_enable_busmaster(dev);
327159967Sobrien
328170589Syongari	rid = PCIR_BAR(0);
329170589Syongari	sc->nfe_res[0] = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
330170589Syongari	    RF_ACTIVE);
331170589Syongari	if (sc->nfe_res[0] == NULL) {
332170589Syongari		device_printf(dev, "couldn't map memory resources\n");
333170589Syongari		mtx_destroy(&sc->nfe_mtx);
334170589Syongari		return (ENXIO);
335170589Syongari	}
336159967Sobrien
337170589Syongari	if (pci_find_extcap(dev, PCIY_EXPRESS, &reg) == 0) {
338170589Syongari		uint16_t v, width;
339170589Syongari
340170589Syongari		v = pci_read_config(dev, reg + 0x08, 2);
341170589Syongari		/* Change max. read request size to 4096. */
342170589Syongari		v &= ~(7 << 12);
343170589Syongari		v |= (5 << 12);
344170589Syongari		pci_write_config(dev, reg + 0x08, v, 2);
345170589Syongari
346170589Syongari		v = pci_read_config(dev, reg + 0x0c, 2);
347170589Syongari		/* link capability */
348170589Syongari		v = (v >> 4) & 0x0f;
349170589Syongari		width = pci_read_config(dev, reg + 0x12, 2);
350170589Syongari		/* negotiated link width */
351170589Syongari		width = (width >> 4) & 0x3f;
352170589Syongari		if (v != width)
353170589Syongari			device_printf(sc->nfe_dev,
354170589Syongari			    "warning, negotiated width of link(x%d) != "
355170589Syongari			    "max. width of link(x%d)\n", width, v);
356159952Sobrien	}
357159952Sobrien
358159967Sobrien	/* Allocate interrupt */
359170589Syongari	if (msix_disable == 0 || msi_disable == 0) {
360170589Syongari		if (msix_disable == 0 &&
361170589Syongari		    (msic = pci_msix_count(dev)) == NFE_MSI_MESSAGES)
362170589Syongari			nfe_alloc_msix(sc, msic);
363170589Syongari		if (msi_disable == 0 && sc->nfe_msix == 0 &&
364170589Syongari		    (msic = pci_msi_count(dev)) == NFE_MSI_MESSAGES &&
365170589Syongari		    pci_alloc_msi(dev, &msic) == 0) {
366170589Syongari			if (msic == NFE_MSI_MESSAGES) {
367170589Syongari				if (bootverbose)
368170589Syongari					device_printf(dev,
369170589Syongari					    "Using %d MSI messages\n", msic);
370170589Syongari				sc->nfe_msi = 1;
371170589Syongari			} else
372170589Syongari				pci_release_msi(dev);
373170589Syongari		}
374170589Syongari	}
375159967Sobrien
376170589Syongari	if (sc->nfe_msix == 0 && sc->nfe_msi == 0) {
377170589Syongari		rid = 0;
378170589Syongari		sc->nfe_irq[0] = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
379170589Syongari		    RF_SHAREABLE | RF_ACTIVE);
380170589Syongari		if (sc->nfe_irq[0] == NULL) {
381170589Syongari			device_printf(dev, "couldn't allocate IRQ resources\n");
382170589Syongari			error = ENXIO;
383170589Syongari			goto fail;
384170589Syongari		}
385170589Syongari	} else {
386170589Syongari		for (i = 0, rid = 1; i < NFE_MSI_MESSAGES; i++, rid++) {
387170589Syongari			sc->nfe_irq[i] = bus_alloc_resource_any(dev,
388170589Syongari			    SYS_RES_IRQ, &rid, RF_ACTIVE);
389170589Syongari			if (sc->nfe_irq[i] == NULL) {
390170589Syongari				device_printf(dev,
391170589Syongari				    "couldn't allocate IRQ resources for "
392170589Syongari				    "message %d\n", rid);
393170589Syongari				error = ENXIO;
394170589Syongari				goto fail;
395170589Syongari			}
396170589Syongari		}
397170589Syongari		/* Map interrupts to vector 0. */
398170589Syongari		if (sc->nfe_msix != 0) {
399170589Syongari			NFE_WRITE(sc, NFE_MSIX_MAP0, 0);
400170589Syongari			NFE_WRITE(sc, NFE_MSIX_MAP1, 0);
401170589Syongari		} else if (sc->nfe_msi != 0) {
402170589Syongari			NFE_WRITE(sc, NFE_MSI_MAP0, 0);
403170589Syongari			NFE_WRITE(sc, NFE_MSI_MAP1, 0);
404170589Syongari		}
405159952Sobrien	}
406159952Sobrien
407170589Syongari	/* Set IRQ status/mask register. */
408170589Syongari	sc->nfe_irq_status = NFE_IRQ_STATUS;
409170589Syongari	sc->nfe_irq_mask = NFE_IRQ_MASK;
410170589Syongari	sc->nfe_intrs = NFE_IRQ_WANTED;
411170589Syongari	sc->nfe_nointrs = 0;
412170589Syongari	if (sc->nfe_msix != 0) {
413170589Syongari		sc->nfe_irq_status = NFE_MSIX_IRQ_STATUS;
414170589Syongari		sc->nfe_nointrs = NFE_IRQ_WANTED;
415170589Syongari	} else if (sc->nfe_msi != 0) {
416170589Syongari		sc->nfe_irq_mask = NFE_MSI_IRQ_MASK;
417170589Syongari		sc->nfe_intrs = NFE_MSI_VECTOR_0_ENABLED;
418170589Syongari	}
419159952Sobrien
420170589Syongari	sc->nfe_devid = pci_get_device(dev);
421170589Syongari	sc->nfe_revid = pci_get_revid(dev);
422159967Sobrien	sc->nfe_flags = 0;
423159952Sobrien
424170589Syongari	switch (sc->nfe_devid) {
425159952Sobrien	case PCI_PRODUCT_NVIDIA_NFORCE3_LAN2:
426159952Sobrien	case PCI_PRODUCT_NVIDIA_NFORCE3_LAN3:
427159952Sobrien	case PCI_PRODUCT_NVIDIA_NFORCE3_LAN4:
428159952Sobrien	case PCI_PRODUCT_NVIDIA_NFORCE3_LAN5:
429159967Sobrien		sc->nfe_flags |= NFE_JUMBO_SUP | NFE_HW_CSUM;
430159952Sobrien		break;
431159952Sobrien	case PCI_PRODUCT_NVIDIA_MCP51_LAN1:
432159952Sobrien	case PCI_PRODUCT_NVIDIA_MCP51_LAN2:
433170589Syongari		sc->nfe_flags |= NFE_40BIT_ADDR | NFE_PWR_MGMT;
434159952Sobrien		break;
435159952Sobrien	case PCI_PRODUCT_NVIDIA_CK804_LAN1:
436159952Sobrien	case PCI_PRODUCT_NVIDIA_CK804_LAN2:
437159952Sobrien	case PCI_PRODUCT_NVIDIA_MCP04_LAN1:
438159952Sobrien	case PCI_PRODUCT_NVIDIA_MCP04_LAN2:
439159967Sobrien		sc->nfe_flags |= NFE_JUMBO_SUP | NFE_40BIT_ADDR | NFE_HW_CSUM;
440159952Sobrien		break;
441159952Sobrien	case PCI_PRODUCT_NVIDIA_MCP55_LAN1:
442159952Sobrien	case PCI_PRODUCT_NVIDIA_MCP55_LAN2:
443163503Sobrien		sc->nfe_flags |= NFE_JUMBO_SUP | NFE_40BIT_ADDR | NFE_HW_CSUM |
444170589Syongari		    NFE_HW_VLAN | NFE_PWR_MGMT | NFE_TX_FLOW_CTRL;
445159952Sobrien		break;
446170589Syongari
447162212Sobrien	case PCI_PRODUCT_NVIDIA_MCP61_LAN1:
448162212Sobrien	case PCI_PRODUCT_NVIDIA_MCP61_LAN2:
449162212Sobrien	case PCI_PRODUCT_NVIDIA_MCP61_LAN3:
450162212Sobrien	case PCI_PRODUCT_NVIDIA_MCP61_LAN4:
451170589Syongari	case PCI_PRODUCT_NVIDIA_MCP67_LAN1:
452170589Syongari	case PCI_PRODUCT_NVIDIA_MCP67_LAN2:
453170589Syongari	case PCI_PRODUCT_NVIDIA_MCP67_LAN3:
454170589Syongari	case PCI_PRODUCT_NVIDIA_MCP67_LAN4:
455170589Syongari		sc->nfe_flags |= NFE_40BIT_ADDR | NFE_PWR_MGMT |
456173377Syongari		    NFE_CORRECT_MACADDR | NFE_TX_FLOW_CTRL;
457162212Sobrien		break;
458162212Sobrien	case PCI_PRODUCT_NVIDIA_MCP65_LAN1:
459162212Sobrien	case PCI_PRODUCT_NVIDIA_MCP65_LAN2:
460162212Sobrien	case PCI_PRODUCT_NVIDIA_MCP65_LAN3:
461162212Sobrien	case PCI_PRODUCT_NVIDIA_MCP65_LAN4:
462170589Syongari		sc->nfe_flags |= NFE_JUMBO_SUP | NFE_40BIT_ADDR |
463173377Syongari		    NFE_PWR_MGMT | NFE_CORRECT_MACADDR | NFE_TX_FLOW_CTRL;
464163503Sobrien		break;
465159952Sobrien	}
466159952Sobrien
467170589Syongari	nfe_power(sc);
468170589Syongari	/* Check for reversed ethernet address */
469170589Syongari	if ((NFE_READ(sc, NFE_TX_UNK) & NFE_MAC_ADDR_INORDER) != 0)
470170589Syongari		sc->nfe_flags |= NFE_CORRECT_MACADDR;
471170589Syongari	nfe_get_macaddr(sc, sc->eaddr);
472159952Sobrien	/*
473159967Sobrien	 * Allocate the parent bus DMA tag appropriate for PCI.
474159967Sobrien	 */
475170589Syongari	dma_addr_max = BUS_SPACE_MAXADDR_32BIT;
476170589Syongari	if ((sc->nfe_flags & NFE_40BIT_ADDR) != 0)
477170589Syongari		dma_addr_max = NFE_DMA_MAXADDR;
478170589Syongari	error = bus_dma_tag_create(
479170589Syongari	    bus_get_dma_tag(sc->nfe_dev),	/* parent */
480163503Sobrien	    1, 0,				/* alignment, boundary */
481170589Syongari	    dma_addr_max,			/* lowaddr */
482163503Sobrien	    BUS_SPACE_MAXADDR,			/* highaddr */
483163503Sobrien	    NULL, NULL,				/* filter, filterarg */
484170589Syongari	    BUS_SPACE_MAXSIZE_32BIT, 0,		/* maxsize, nsegments */
485163503Sobrien	    BUS_SPACE_MAXSIZE_32BIT,		/* maxsegsize */
486170589Syongari	    0,					/* flags */
487163503Sobrien	    NULL, NULL,				/* lockfunc, lockarg */
488163503Sobrien	    &sc->nfe_parent_tag);
489159967Sobrien	if (error)
490159967Sobrien		goto fail;
491159967Sobrien
492164650Sobrien	ifp = sc->nfe_ifp = if_alloc(IFT_ETHER);
493164650Sobrien	if (ifp == NULL) {
494170589Syongari		device_printf(dev, "can not if_alloc()\n");
495164650Sobrien		error = ENOSPC;
496164650Sobrien		goto fail;
497164650Sobrien	}
498170589Syongari	TASK_INIT(&sc->nfe_tx_task, 1, nfe_tx_task, ifp);
499164650Sobrien
500159967Sobrien	/*
501159952Sobrien	 * Allocate Tx and Rx rings.
502159952Sobrien	 */
503170589Syongari	if ((error = nfe_alloc_tx_ring(sc, &sc->txq)) != 0)
504159967Sobrien		goto fail;
505159952Sobrien
506170589Syongari	if ((error = nfe_alloc_rx_ring(sc, &sc->rxq)) != 0)
507159967Sobrien		goto fail;
508170589Syongari
509171559Syongari	nfe_alloc_jrx_ring(sc, &sc->jrxq);
510170589Syongari
511170589Syongari	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
512170589Syongari	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
513170589Syongari	    OID_AUTO, "process_limit", CTLTYPE_INT | CTLFLAG_RW,
514170589Syongari	    &sc->nfe_process_limit, 0, sysctl_hw_nfe_proc_limit, "I",
515170589Syongari	    "max number of Rx events to process");
516170589Syongari
517170589Syongari	sc->nfe_process_limit = NFE_PROC_DEFAULT;
518170589Syongari	error = resource_int_value(device_get_name(dev), device_get_unit(dev),
519170589Syongari	    "process_limit", &sc->nfe_process_limit);
520170589Syongari	if (error == 0) {
521170589Syongari		if (sc->nfe_process_limit < NFE_PROC_MIN ||
522170589Syongari		    sc->nfe_process_limit > NFE_PROC_MAX) {
523170589Syongari			device_printf(dev, "process_limit value out of range; "
524170589Syongari			    "using default: %d\n", NFE_PROC_DEFAULT);
525170589Syongari			sc->nfe_process_limit = NFE_PROC_DEFAULT;
526170589Syongari		}
527159952Sobrien	}
528159952Sobrien
529159952Sobrien	ifp->if_softc = sc;
530159967Sobrien	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
531170589Syongari	ifp->if_mtu = ETHERMTU;
532159952Sobrien	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
533159952Sobrien	ifp->if_ioctl = nfe_ioctl;
534159952Sobrien	ifp->if_start = nfe_start;
535170589Syongari	ifp->if_hwassist = 0;
536170589Syongari	ifp->if_capabilities = 0;
537170589Syongari	ifp->if_watchdog = NULL;
538159952Sobrien	ifp->if_init = nfe_init;
539170589Syongari	IFQ_SET_MAXLEN(&ifp->if_snd, NFE_TX_RING_COUNT - 1);
540170589Syongari	ifp->if_snd.ifq_drv_maxlen = NFE_TX_RING_COUNT - 1;
541170589Syongari	IFQ_SET_READY(&ifp->if_snd);
542159952Sobrien
543170589Syongari	if (sc->nfe_flags & NFE_HW_CSUM) {
544170589Syongari		ifp->if_capabilities |= IFCAP_HWCSUM | IFCAP_TSO4;
545170589Syongari		ifp->if_hwassist |= NFE_CSUM_FEATURES | CSUM_TSO;
546170589Syongari	}
547170589Syongari	ifp->if_capenable = ifp->if_capabilities;
548164650Sobrien
549170589Syongari	sc->nfe_framesize = ifp->if_mtu + NFE_RX_HEADERS;
550170589Syongari	/* VLAN capability setup. */
551170589Syongari	ifp->if_capabilities |= IFCAP_VLAN_MTU;
552170589Syongari	if ((sc->nfe_flags & NFE_HW_VLAN) != 0) {
553159952Sobrien		ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING;
554170589Syongari		if ((ifp->if_capabilities & IFCAP_HWCSUM) != 0)
555170589Syongari			ifp->if_capabilities |= IFCAP_VLAN_HWCSUM;
556159952Sobrien	}
557159967Sobrien	ifp->if_capenable = ifp->if_capabilities;
558159952Sobrien
559170589Syongari	/*
560170589Syongari	 * Tell the upper layer(s) we support long frames.
561170589Syongari	 * Must appear after the call to ether_ifattach() because
562170589Syongari	 * ether_ifattach() sets ifi_hdrlen to the default value.
563170589Syongari	 */
564170589Syongari	ifp->if_data.ifi_hdrlen = sizeof(struct ether_vlan_header);
565170589Syongari
566159967Sobrien#ifdef DEVICE_POLLING
567159967Sobrien	ifp->if_capabilities |= IFCAP_POLLING;
568159967Sobrien#endif
569159952Sobrien
570159967Sobrien	/* Do MII setup */
571163503Sobrien	if (mii_phy_probe(dev, &sc->nfe_miibus, nfe_ifmedia_upd,
572163503Sobrien	    nfe_ifmedia_sts)) {
573170589Syongari		device_printf(dev, "MII without any phy!\n");
574159967Sobrien		error = ENXIO;
575159967Sobrien		goto fail;
576159967Sobrien	}
577159967Sobrien	ether_ifattach(ifp, sc->eaddr);
578159952Sobrien
579170589Syongari	TASK_INIT(&sc->nfe_int_task, 0, nfe_int_task, sc);
580170589Syongari	sc->nfe_tq = taskqueue_create_fast("nfe_taskq", M_WAITOK,
581170589Syongari	    taskqueue_thread_enqueue, &sc->nfe_tq);
582170589Syongari	taskqueue_start_threads(&sc->nfe_tq, 1, PI_NET, "%s taskq",
583170589Syongari	    device_get_nameunit(sc->nfe_dev));
584170589Syongari	error = 0;
585170589Syongari	if (sc->nfe_msi == 0 && sc->nfe_msix == 0) {
586170589Syongari		error = bus_setup_intr(dev, sc->nfe_irq[0],
587170589Syongari		    INTR_TYPE_NET | INTR_MPSAFE, nfe_intr, NULL, sc,
588170589Syongari		    &sc->nfe_intrhand[0]);
589170589Syongari	} else {
590170589Syongari		for (i = 0; i < NFE_MSI_MESSAGES; i++) {
591170589Syongari			error = bus_setup_intr(dev, sc->nfe_irq[i],
592170589Syongari			    INTR_TYPE_NET | INTR_MPSAFE, nfe_intr, NULL, sc,
593170589Syongari			    &sc->nfe_intrhand[i]);
594170589Syongari			if (error != 0)
595170589Syongari				break;
596170589Syongari		}
597170589Syongari	}
598159967Sobrien	if (error) {
599170589Syongari		device_printf(dev, "couldn't set up irq\n");
600170589Syongari		taskqueue_free(sc->nfe_tq);
601170589Syongari		sc->nfe_tq = NULL;
602159967Sobrien		ether_ifdetach(ifp);
603159967Sobrien		goto fail;
604159967Sobrien	}
605159967Sobrien
606159967Sobrienfail:
607159967Sobrien	if (error)
608159967Sobrien		nfe_detach(dev);
609159967Sobrien
610159967Sobrien	return (error);
611159952Sobrien}
612159952Sobrien
613159967Sobrien
614159967Sobrienstatic int
615159967Sobriennfe_detach(device_t dev)
616159952Sobrien{
617163503Sobrien	struct nfe_softc *sc;
618163503Sobrien	struct ifnet *ifp;
619170589Syongari	uint8_t eaddr[ETHER_ADDR_LEN];
620170589Syongari	int i, rid;
621159952Sobrien
622159967Sobrien	sc = device_get_softc(dev);
623159967Sobrien	KASSERT(mtx_initialized(&sc->nfe_mtx), ("nfe mutex not initialized"));
624159967Sobrien	ifp = sc->nfe_ifp;
625159967Sobrien
626159967Sobrien#ifdef DEVICE_POLLING
627170589Syongari	if (ifp != NULL && ifp->if_capenable & IFCAP_POLLING)
628159967Sobrien		ether_poll_deregister(ifp);
629159967Sobrien#endif
630159967Sobrien	if (device_is_attached(dev)) {
631164649Sobrien		NFE_LOCK(sc);
632170589Syongari		nfe_stop(ifp);
633159967Sobrien		ifp->if_flags &= ~IFF_UP;
634164649Sobrien		NFE_UNLOCK(sc);
635159967Sobrien		callout_drain(&sc->nfe_stat_ch);
636170589Syongari		taskqueue_drain(taskqueue_fast, &sc->nfe_tx_task);
637170589Syongari		taskqueue_drain(taskqueue_swi, &sc->nfe_link_task);
638159967Sobrien		ether_ifdetach(ifp);
639159967Sobrien	}
640159967Sobrien
641170589Syongari	if (ifp) {
642170589Syongari		/* restore ethernet address */
643170589Syongari		if ((sc->nfe_flags & NFE_CORRECT_MACADDR) == 0) {
644170589Syongari			for (i = 0; i < ETHER_ADDR_LEN; i++) {
645170589Syongari				eaddr[i] = sc->eaddr[5 - i];
646170589Syongari			}
647170589Syongari		} else
648170589Syongari			bcopy(sc->eaddr, eaddr, ETHER_ADDR_LEN);
649170589Syongari		nfe_set_macaddr(sc, eaddr);
650159967Sobrien		if_free(ifp);
651170589Syongari	}
652159967Sobrien	if (sc->nfe_miibus)
653159967Sobrien		device_delete_child(dev, sc->nfe_miibus);
654159967Sobrien	bus_generic_detach(dev);
655170589Syongari	if (sc->nfe_tq != NULL) {
656170589Syongari		taskqueue_drain(sc->nfe_tq, &sc->nfe_int_task);
657170589Syongari		taskqueue_free(sc->nfe_tq);
658170589Syongari		sc->nfe_tq = NULL;
659170589Syongari	}
660159967Sobrien
661170589Syongari	for (i = 0; i < NFE_MSI_MESSAGES; i++) {
662170589Syongari		if (sc->nfe_intrhand[i] != NULL) {
663170589Syongari			bus_teardown_intr(dev, sc->nfe_irq[i],
664170589Syongari			    sc->nfe_intrhand[i]);
665170589Syongari			sc->nfe_intrhand[i] = NULL;
666170589Syongari		}
667170589Syongari	}
668159967Sobrien
669170589Syongari	if (sc->nfe_msi == 0 && sc->nfe_msix == 0) {
670170589Syongari		if (sc->nfe_irq[0] != NULL)
671170589Syongari			bus_release_resource(dev, SYS_RES_IRQ, 0,
672170589Syongari			    sc->nfe_irq[0]);
673170589Syongari	} else {
674170589Syongari		for (i = 0, rid = 1; i < NFE_MSI_MESSAGES; i++, rid++) {
675170589Syongari			if (sc->nfe_irq[i] != NULL) {
676170589Syongari				bus_release_resource(dev, SYS_RES_IRQ, rid,
677170589Syongari				    sc->nfe_irq[i]);
678170589Syongari				sc->nfe_irq[i] = NULL;
679170589Syongari			}
680170589Syongari		}
681170589Syongari		pci_release_msi(dev);
682170589Syongari	}
683170589Syongari	if (sc->nfe_msix_pba_res != NULL) {
684170589Syongari		bus_release_resource(dev, SYS_RES_MEMORY, PCIR_BAR(3),
685170589Syongari		    sc->nfe_msix_pba_res);
686170589Syongari		sc->nfe_msix_pba_res = NULL;
687170589Syongari	}
688170589Syongari	if (sc->nfe_msix_res != NULL) {
689170589Syongari		bus_release_resource(dev, SYS_RES_MEMORY, PCIR_BAR(2),
690170589Syongari		    sc->nfe_msix_res);
691170589Syongari		sc->nfe_msix_res = NULL;
692170589Syongari	}
693170589Syongari	if (sc->nfe_res[0] != NULL) {
694170589Syongari		bus_release_resource(dev, SYS_RES_MEMORY, PCIR_BAR(0),
695170589Syongari		    sc->nfe_res[0]);
696170589Syongari		sc->nfe_res[0] = NULL;
697170589Syongari	}
698170589Syongari
699159967Sobrien	nfe_free_tx_ring(sc, &sc->txq);
700159967Sobrien	nfe_free_rx_ring(sc, &sc->rxq);
701170589Syongari	nfe_free_jrx_ring(sc, &sc->jrxq);
702159967Sobrien
703170589Syongari	if (sc->nfe_parent_tag) {
704159967Sobrien		bus_dma_tag_destroy(sc->nfe_parent_tag);
705170589Syongari		sc->nfe_parent_tag = NULL;
706170589Syongari	}
707159967Sobrien
708159967Sobrien	mtx_destroy(&sc->nfe_mtx);
709159967Sobrien
710159967Sobrien	return (0);
711159952Sobrien}
712159952Sobrien
713159967Sobrien
714170589Syongaristatic int
715170589Syongarinfe_suspend(device_t dev)
716170589Syongari{
717170589Syongari	struct nfe_softc *sc;
718170589Syongari
719170589Syongari	sc = device_get_softc(dev);
720170589Syongari
721170589Syongari	NFE_LOCK(sc);
722170589Syongari	nfe_stop(sc->nfe_ifp);
723170589Syongari	sc->nfe_suspended = 1;
724170589Syongari	NFE_UNLOCK(sc);
725170589Syongari
726170589Syongari	return (0);
727170589Syongari}
728170589Syongari
729170589Syongari
730170589Syongaristatic int
731170589Syongarinfe_resume(device_t dev)
732170589Syongari{
733170589Syongari	struct nfe_softc *sc;
734170589Syongari	struct ifnet *ifp;
735170589Syongari
736170589Syongari	sc = device_get_softc(dev);
737170589Syongari
738170589Syongari	NFE_LOCK(sc);
739170589Syongari	ifp = sc->nfe_ifp;
740170589Syongari	if (ifp->if_flags & IFF_UP)
741170589Syongari		nfe_init_locked(sc);
742170589Syongari	sc->nfe_suspended = 0;
743170589Syongari	NFE_UNLOCK(sc);
744170589Syongari
745170589Syongari	return (0);
746170589Syongari}
747170589Syongari
748170589Syongari
749170589Syongari/* Take PHY/NIC out of powerdown, from Linux */
750159967Sobrienstatic void
751170589Syongarinfe_power(struct nfe_softc *sc)
752170589Syongari{
753170589Syongari	uint32_t pwr;
754170589Syongari
755170589Syongari	if ((sc->nfe_flags & NFE_PWR_MGMT) == 0)
756170589Syongari		return;
757170589Syongari	NFE_WRITE(sc, NFE_RXTX_CTL, NFE_RXTX_RESET | NFE_RXTX_BIT2);
758170589Syongari	NFE_WRITE(sc, NFE_MAC_RESET, NFE_MAC_RESET_MAGIC);
759170589Syongari	DELAY(100);
760170589Syongari	NFE_WRITE(sc, NFE_MAC_RESET, 0);
761170589Syongari	DELAY(100);
762170589Syongari	NFE_WRITE(sc, NFE_RXTX_CTL, NFE_RXTX_BIT2);
763170589Syongari	pwr = NFE_READ(sc, NFE_PWR2_CTL);
764170589Syongari	pwr &= ~NFE_PWR2_WAKEUP_MASK;
765170589Syongari	if (sc->nfe_revid >= 0xa3 &&
766170589Syongari	    (sc->nfe_devid == PCI_PRODUCT_NVIDIA_NFORCE430_LAN1 ||
767170589Syongari	    sc->nfe_devid == PCI_PRODUCT_NVIDIA_NFORCE430_LAN2))
768170589Syongari		pwr |= NFE_PWR2_REVA3;
769170589Syongari	NFE_WRITE(sc, NFE_PWR2_CTL, pwr);
770170589Syongari}
771170589Syongari
772170589Syongari
773170589Syongaristatic void
774159967Sobriennfe_miibus_statchg(device_t dev)
775159952Sobrien{
776159967Sobrien	struct nfe_softc *sc;
777170589Syongari
778170589Syongari	sc = device_get_softc(dev);
779170589Syongari	taskqueue_enqueue(taskqueue_swi, &sc->nfe_link_task);
780170589Syongari}
781170589Syongari
782170589Syongari
783170589Syongaristatic void
784170589Syongarinfe_link_task(void *arg, int pending)
785170589Syongari{
786170589Syongari	struct nfe_softc *sc;
787159967Sobrien	struct mii_data *mii;
788170589Syongari	struct ifnet *ifp;
789170589Syongari	uint32_t phy, seed, misc = NFE_MISC1_MAGIC, link = NFE_MEDIA_SET;
790170589Syongari	uint32_t gmask, rxctl, txctl, val;
791159952Sobrien
792170589Syongari	sc = (struct nfe_softc *)arg;
793170589Syongari
794170589Syongari	NFE_LOCK(sc);
795170589Syongari
796159967Sobrien	mii = device_get_softc(sc->nfe_miibus);
797170589Syongari	ifp = sc->nfe_ifp;
798170589Syongari	if (mii == NULL || ifp == NULL) {
799170589Syongari		NFE_UNLOCK(sc);
800170589Syongari		return;
801170589Syongari	}
802159967Sobrien
803170589Syongari	if (mii->mii_media_status & IFM_ACTIVE) {
804170589Syongari		if (IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE)
805170589Syongari			sc->nfe_link = 1;
806170589Syongari	} else
807170589Syongari		sc->nfe_link = 0;
808170589Syongari
809159952Sobrien	phy = NFE_READ(sc, NFE_PHY_IFACE);
810159952Sobrien	phy &= ~(NFE_PHY_HDX | NFE_PHY_100TX | NFE_PHY_1000T);
811159952Sobrien
812159952Sobrien	seed = NFE_READ(sc, NFE_RNDSEED);
813159952Sobrien	seed &= ~NFE_SEED_MASK;
814159952Sobrien
815170589Syongari	if (((mii->mii_media_active & IFM_GMASK) & IFM_FDX) == 0) {
816159952Sobrien		phy  |= NFE_PHY_HDX;	/* half-duplex */
817159952Sobrien		misc |= NFE_MISC1_HDX;
818159952Sobrien	}
819159952Sobrien
820159952Sobrien	switch (IFM_SUBTYPE(mii->mii_media_active)) {
821159952Sobrien	case IFM_1000_T:	/* full-duplex only */
822159952Sobrien		link |= NFE_MEDIA_1000T;
823159952Sobrien		seed |= NFE_SEED_1000T;
824159952Sobrien		phy  |= NFE_PHY_1000T;
825159952Sobrien		break;
826159952Sobrien	case IFM_100_TX:
827159952Sobrien		link |= NFE_MEDIA_100TX;
828159952Sobrien		seed |= NFE_SEED_100TX;
829159952Sobrien		phy  |= NFE_PHY_100TX;
830159952Sobrien		break;
831159952Sobrien	case IFM_10_T:
832159952Sobrien		link |= NFE_MEDIA_10T;
833159952Sobrien		seed |= NFE_SEED_10T;
834159952Sobrien		break;
835159952Sobrien	}
836159952Sobrien
837170589Syongari	if ((phy & 0x10000000) != 0) {
838170589Syongari		if (IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_T)
839170589Syongari			val = NFE_R1_MAGIC_1000;
840170589Syongari		else
841170589Syongari			val = NFE_R1_MAGIC_10_100;
842170589Syongari	} else
843170589Syongari		val = NFE_R1_MAGIC_DEFAULT;
844170589Syongari	NFE_WRITE(sc, NFE_SETUP_R1, val);
845170589Syongari
846159952Sobrien	NFE_WRITE(sc, NFE_RNDSEED, seed);	/* XXX: gigabit NICs only? */
847159952Sobrien
848159952Sobrien	NFE_WRITE(sc, NFE_PHY_IFACE, phy);
849159952Sobrien	NFE_WRITE(sc, NFE_MISC1, misc);
850159952Sobrien	NFE_WRITE(sc, NFE_LINKSPEED, link);
851170589Syongari
852170589Syongari	gmask = mii->mii_media_active & IFM_GMASK;
853170589Syongari	if ((gmask & IFM_FDX) != 0) {
854170589Syongari		/* It seems all hardwares supports Rx pause frames. */
855170589Syongari		val = NFE_READ(sc, NFE_RXFILTER);
856170589Syongari		if ((gmask & IFM_FLAG0) != 0)
857170589Syongari			val |= NFE_PFF_RX_PAUSE;
858170589Syongari		else
859170589Syongari			val &= ~NFE_PFF_RX_PAUSE;
860170589Syongari		NFE_WRITE(sc, NFE_RXFILTER, val);
861170589Syongari		if ((sc->nfe_flags & NFE_TX_FLOW_CTRL) != 0) {
862170589Syongari			val = NFE_READ(sc, NFE_MISC1);
863170589Syongari			if ((gmask & IFM_FLAG1) != 0) {
864170589Syongari				NFE_WRITE(sc, NFE_TX_PAUSE_FRAME,
865170589Syongari				    NFE_TX_PAUSE_FRAME_ENABLE);
866170589Syongari				val |= NFE_MISC1_TX_PAUSE;
867170589Syongari			} else {
868170589Syongari				val &= ~NFE_MISC1_TX_PAUSE;
869170589Syongari				NFE_WRITE(sc, NFE_TX_PAUSE_FRAME,
870170589Syongari				    NFE_TX_PAUSE_FRAME_DISABLE);
871170589Syongari			}
872170589Syongari			NFE_WRITE(sc, NFE_MISC1, val);
873170589Syongari		}
874170589Syongari	} else {
875170589Syongari		/* disable rx/tx pause frames */
876170589Syongari		val = NFE_READ(sc, NFE_RXFILTER);
877170589Syongari		val &= ~NFE_PFF_RX_PAUSE;
878170589Syongari		NFE_WRITE(sc, NFE_RXFILTER, val);
879170589Syongari		if ((sc->nfe_flags & NFE_TX_FLOW_CTRL) != 0) {
880170589Syongari			NFE_WRITE(sc, NFE_TX_PAUSE_FRAME,
881170589Syongari			    NFE_TX_PAUSE_FRAME_DISABLE);
882170589Syongari			val = NFE_READ(sc, NFE_MISC1);
883170589Syongari			val &= ~NFE_MISC1_TX_PAUSE;
884170589Syongari			NFE_WRITE(sc, NFE_MISC1, val);
885170589Syongari		}
886170589Syongari	}
887170589Syongari
888170589Syongari	txctl = NFE_READ(sc, NFE_TX_CTL);
889170589Syongari	rxctl = NFE_READ(sc, NFE_RX_CTL);
890170589Syongari	if (sc->nfe_link != 0 && (ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) {
891170589Syongari		txctl |= NFE_TX_START;
892170589Syongari		rxctl |= NFE_RX_START;
893170589Syongari	} else {
894170589Syongari		txctl &= ~NFE_TX_START;
895170589Syongari		rxctl &= ~NFE_RX_START;
896170589Syongari	}
897172164Syongari	NFE_WRITE(sc, NFE_TX_CTL, txctl);
898172164Syongari	NFE_WRITE(sc, NFE_RX_CTL, rxctl);
899170589Syongari
900170589Syongari	NFE_UNLOCK(sc);
901159952Sobrien}
902159952Sobrien
903163503Sobrien
904159967Sobrienstatic int
905159967Sobriennfe_miibus_readreg(device_t dev, int phy, int reg)
906159952Sobrien{
907159967Sobrien	struct nfe_softc *sc = device_get_softc(dev);
908170589Syongari	uint32_t val;
909159952Sobrien	int ntries;
910159952Sobrien
911159952Sobrien	NFE_WRITE(sc, NFE_PHY_STATUS, 0xf);
912159952Sobrien
913159952Sobrien	if (NFE_READ(sc, NFE_PHY_CTL) & NFE_PHY_BUSY) {
914159952Sobrien		NFE_WRITE(sc, NFE_PHY_CTL, NFE_PHY_BUSY);
915159952Sobrien		DELAY(100);
916159952Sobrien	}
917159952Sobrien
918159952Sobrien	NFE_WRITE(sc, NFE_PHY_CTL, (phy << NFE_PHYADD_SHIFT) | reg);
919159952Sobrien
920170589Syongari	for (ntries = 0; ntries < NFE_TIMEOUT; ntries++) {
921159952Sobrien		DELAY(100);
922159952Sobrien		if (!(NFE_READ(sc, NFE_PHY_CTL) & NFE_PHY_BUSY))
923159952Sobrien			break;
924159952Sobrien	}
925170589Syongari	if (ntries == NFE_TIMEOUT) {
926170589Syongari		DPRINTFN(sc, 2, "timeout waiting for PHY\n");
927159952Sobrien		return 0;
928159952Sobrien	}
929159952Sobrien
930159952Sobrien	if (NFE_READ(sc, NFE_PHY_STATUS) & NFE_PHY_ERROR) {
931170589Syongari		DPRINTFN(sc, 2, "could not read PHY\n");
932159952Sobrien		return 0;
933159952Sobrien	}
934159952Sobrien
935159952Sobrien	val = NFE_READ(sc, NFE_PHY_DATA);
936159952Sobrien	if (val != 0xffffffff && val != 0)
937159952Sobrien		sc->mii_phyaddr = phy;
938159952Sobrien
939170589Syongari	DPRINTFN(sc, 2, "mii read phy %d reg 0x%x ret 0x%x\n", phy, reg, val);
940159952Sobrien
941170589Syongari	return (val);
942159952Sobrien}
943159952Sobrien
944163503Sobrien
945159967Sobrienstatic int
946159967Sobriennfe_miibus_writereg(device_t dev, int phy, int reg, int val)
947159952Sobrien{
948159967Sobrien	struct nfe_softc *sc = device_get_softc(dev);
949170589Syongari	uint32_t ctl;
950163503Sobrien	int ntries;
951159952Sobrien
952159952Sobrien	NFE_WRITE(sc, NFE_PHY_STATUS, 0xf);
953159952Sobrien
954159952Sobrien	if (NFE_READ(sc, NFE_PHY_CTL) & NFE_PHY_BUSY) {
955159952Sobrien		NFE_WRITE(sc, NFE_PHY_CTL, NFE_PHY_BUSY);
956159952Sobrien		DELAY(100);
957159952Sobrien	}
958159952Sobrien
959159952Sobrien	NFE_WRITE(sc, NFE_PHY_DATA, val);
960159952Sobrien	ctl = NFE_PHY_WRITE | (phy << NFE_PHYADD_SHIFT) | reg;
961159952Sobrien	NFE_WRITE(sc, NFE_PHY_CTL, ctl);
962159952Sobrien
963170589Syongari	for (ntries = 0; ntries < NFE_TIMEOUT; ntries++) {
964159952Sobrien		DELAY(100);
965159952Sobrien		if (!(NFE_READ(sc, NFE_PHY_CTL) & NFE_PHY_BUSY))
966159952Sobrien			break;
967159952Sobrien	}
968159952Sobrien#ifdef NFE_DEBUG
969170589Syongari	if (nfedebug >= 2 && ntries == NFE_TIMEOUT)
970170589Syongari		device_printf(sc->nfe_dev, "could not write to PHY\n");
971159952Sobrien#endif
972170589Syongari	return (0);
973159952Sobrien}
974159952Sobrien
975170589Syongaristruct nfe_dmamap_arg {
976170589Syongari	bus_addr_t nfe_busaddr;
977170589Syongari};
978170589Syongari
979159967Sobrienstatic int
980159967Sobriennfe_alloc_rx_ring(struct nfe_softc *sc, struct nfe_rx_ring *ring)
981159952Sobrien{
982170589Syongari	struct nfe_dmamap_arg ctx;
983159967Sobrien	struct nfe_rx_data *data;
984170589Syongari	void *desc;
985159967Sobrien	int i, error, descsize;
986159967Sobrien
987159967Sobrien	if (sc->nfe_flags & NFE_40BIT_ADDR) {
988170589Syongari		desc = ring->desc64;
989159967Sobrien		descsize = sizeof (struct nfe_desc64);
990159967Sobrien	} else {
991170589Syongari		desc = ring->desc32;
992159967Sobrien		descsize = sizeof (struct nfe_desc32);
993159967Sobrien	}
994159967Sobrien
995159967Sobrien	ring->cur = ring->next = 0;
996159967Sobrien
997163503Sobrien	error = bus_dma_tag_create(sc->nfe_parent_tag,
998170589Syongari	    NFE_RING_ALIGN, 0,			/* alignment, boundary */
999170589Syongari	    BUS_SPACE_MAXADDR,			/* lowaddr */
1000170589Syongari	    BUS_SPACE_MAXADDR,			/* highaddr */
1001170589Syongari	    NULL, NULL,				/* filter, filterarg */
1002170589Syongari	    NFE_RX_RING_COUNT * descsize, 1,	/* maxsize, nsegments */
1003170589Syongari	    NFE_RX_RING_COUNT * descsize,	/* maxsegsize */
1004170589Syongari	    0,					/* flags */
1005170589Syongari	    NULL, NULL,				/* lockfunc, lockarg */
1006170589Syongari	    &ring->rx_desc_tag);
1007159967Sobrien	if (error != 0) {
1008170589Syongari		device_printf(sc->nfe_dev, "could not create desc DMA tag\n");
1009159967Sobrien		goto fail;
1010159967Sobrien	}
1011159967Sobrien
1012159967Sobrien	/* allocate memory to desc */
1013170589Syongari	error = bus_dmamem_alloc(ring->rx_desc_tag, &desc, BUS_DMA_WAITOK |
1014170589Syongari	    BUS_DMA_COHERENT | BUS_DMA_ZERO, &ring->rx_desc_map);
1015159967Sobrien	if (error != 0) {
1016170589Syongari		device_printf(sc->nfe_dev, "could not create desc DMA map\n");
1017159967Sobrien		goto fail;
1018159967Sobrien	}
1019170589Syongari	if (sc->nfe_flags & NFE_40BIT_ADDR)
1020170589Syongari		ring->desc64 = desc;
1021170589Syongari	else
1022170589Syongari		ring->desc32 = desc;
1023159967Sobrien
1024159967Sobrien	/* map desc to device visible address space */
1025170589Syongari	ctx.nfe_busaddr = 0;
1026170589Syongari	error = bus_dmamap_load(ring->rx_desc_tag, ring->rx_desc_map, desc,
1027170589Syongari	    NFE_RX_RING_COUNT * descsize, nfe_dma_map_segs, &ctx, 0);
1028159967Sobrien	if (error != 0) {
1029170589Syongari		device_printf(sc->nfe_dev, "could not load desc DMA map\n");
1030159967Sobrien		goto fail;
1031159967Sobrien	}
1032170589Syongari	ring->physaddr = ctx.nfe_busaddr;
1033159967Sobrien
1034170589Syongari	error = bus_dma_tag_create(sc->nfe_parent_tag,
1035170589Syongari	    1, 0,			/* alignment, boundary */
1036170589Syongari	    BUS_SPACE_MAXADDR,		/* lowaddr */
1037170589Syongari	    BUS_SPACE_MAXADDR,		/* highaddr */
1038170589Syongari	    NULL, NULL,			/* filter, filterarg */
1039170589Syongari	    MCLBYTES, 1,		/* maxsize, nsegments */
1040170589Syongari	    MCLBYTES,			/* maxsegsize */
1041170589Syongari	    0,				/* flags */
1042170589Syongari	    NULL, NULL,			/* lockfunc, lockarg */
1043170589Syongari	    &ring->rx_data_tag);
1044170589Syongari	if (error != 0) {
1045170589Syongari		device_printf(sc->nfe_dev, "could not create Rx DMA tag\n");
1046170589Syongari		goto fail;
1047170589Syongari	}
1048159967Sobrien
1049170589Syongari	error = bus_dmamap_create(ring->rx_data_tag, 0, &ring->rx_spare_map);
1050170589Syongari	if (error != 0) {
1051170589Syongari		device_printf(sc->nfe_dev,
1052170589Syongari		    "could not create Rx DMA spare map\n");
1053170589Syongari		goto fail;
1054170589Syongari	}
1055170589Syongari
1056159967Sobrien	/*
1057159967Sobrien	 * Pre-allocate Rx buffers and populate Rx ring.
1058159967Sobrien	 */
1059159967Sobrien	for (i = 0; i < NFE_RX_RING_COUNT; i++) {
1060159967Sobrien		data = &sc->rxq.data[i];
1061170589Syongari		data->rx_data_map = NULL;
1062170589Syongari		data->m = NULL;
1063170589Syongari		error = bus_dmamap_create(ring->rx_data_tag, 0,
1064170589Syongari		    &data->rx_data_map);
1065164651Sobrien		if (error != 0) {
1066170589Syongari			device_printf(sc->nfe_dev,
1067170589Syongari			    "could not create Rx DMA map\n");
1068164651Sobrien			goto fail;
1069164651Sobrien		}
1070170589Syongari	}
1071159967Sobrien
1072170589Syongarifail:
1073170589Syongari	return (error);
1074170589Syongari}
1075170589Syongari
1076170589Syongari
1077171559Syongaristatic void
1078170589Syongarinfe_alloc_jrx_ring(struct nfe_softc *sc, struct nfe_jrx_ring *ring)
1079170589Syongari{
1080170589Syongari	struct nfe_dmamap_arg ctx;
1081170589Syongari	struct nfe_rx_data *data;
1082170589Syongari	void *desc;
1083170589Syongari	int i, error, descsize;
1084170589Syongari
1085170589Syongari	if ((sc->nfe_flags & NFE_JUMBO_SUP) == 0)
1086171559Syongari		return;
1087171559Syongari	if (jumbo_disable != 0) {
1088171559Syongari		device_printf(sc->nfe_dev, "disabling jumbo frame support\n");
1089171559Syongari		sc->nfe_jumbo_disable = 1;
1090171559Syongari		return;
1091171559Syongari	}
1092170589Syongari
1093170589Syongari	if (sc->nfe_flags & NFE_40BIT_ADDR) {
1094170589Syongari		desc = ring->jdesc64;
1095170589Syongari		descsize = sizeof (struct nfe_desc64);
1096170589Syongari	} else {
1097170589Syongari		desc = ring->jdesc32;
1098170589Syongari		descsize = sizeof (struct nfe_desc32);
1099170589Syongari	}
1100170589Syongari
1101170589Syongari	ring->jcur = ring->jnext = 0;
1102170589Syongari
1103170589Syongari	/* Create DMA tag for jumbo Rx ring. */
1104170589Syongari	error = bus_dma_tag_create(sc->nfe_parent_tag,
1105170589Syongari	    NFE_RING_ALIGN, 0,			/* alignment, boundary */
1106170589Syongari	    BUS_SPACE_MAXADDR,			/* lowaddr */
1107170589Syongari	    BUS_SPACE_MAXADDR,			/* highaddr */
1108170589Syongari	    NULL, NULL,				/* filter, filterarg */
1109170589Syongari	    NFE_JUMBO_RX_RING_COUNT * descsize,	/* maxsize */
1110170589Syongari	    1, 					/* nsegments */
1111170589Syongari	    NFE_JUMBO_RX_RING_COUNT * descsize,	/* maxsegsize */
1112170589Syongari	    0,					/* flags */
1113170589Syongari	    NULL, NULL,				/* lockfunc, lockarg */
1114170589Syongari	    &ring->jrx_desc_tag);
1115170589Syongari	if (error != 0) {
1116170589Syongari		device_printf(sc->nfe_dev,
1117170589Syongari		    "could not create jumbo ring DMA tag\n");
1118170589Syongari		goto fail;
1119170589Syongari	}
1120170589Syongari
1121170589Syongari	/* Create DMA tag for jumbo Rx buffers. */
1122170589Syongari	error = bus_dma_tag_create(sc->nfe_parent_tag,
1123170589Syongari	    PAGE_SIZE, 0,			/* alignment, boundary */
1124170589Syongari	    BUS_SPACE_MAXADDR,			/* lowaddr */
1125170589Syongari	    BUS_SPACE_MAXADDR,			/* highaddr */
1126170589Syongari	    NULL, NULL,				/* filter, filterarg */
1127176859Syongari	    MJUM9BYTES,				/* maxsize */
1128170589Syongari	    1,					/* nsegments */
1129176859Syongari	    MJUM9BYTES,				/* maxsegsize */
1130170589Syongari	    0,					/* flags */
1131170589Syongari	    NULL, NULL,				/* lockfunc, lockarg */
1132170589Syongari	    &ring->jrx_data_tag);
1133170589Syongari	if (error != 0) {
1134170589Syongari		device_printf(sc->nfe_dev,
1135170589Syongari		    "could not create jumbo Rx buffer DMA tag\n");
1136170589Syongari		goto fail;
1137170589Syongari	}
1138170589Syongari
1139170589Syongari	/* Allocate DMA'able memory and load the DMA map for jumbo Rx ring. */
1140170589Syongari	error = bus_dmamem_alloc(ring->jrx_desc_tag, &desc, BUS_DMA_WAITOK |
1141170589Syongari	    BUS_DMA_COHERENT | BUS_DMA_ZERO, &ring->jrx_desc_map);
1142170589Syongari	if (error != 0) {
1143170589Syongari		device_printf(sc->nfe_dev,
1144170589Syongari		    "could not allocate DMA'able memory for jumbo Rx ring\n");
1145170589Syongari		goto fail;
1146170589Syongari	}
1147170589Syongari	if (sc->nfe_flags & NFE_40BIT_ADDR)
1148170589Syongari		ring->jdesc64 = desc;
1149170589Syongari	else
1150170589Syongari		ring->jdesc32 = desc;
1151170589Syongari
1152170589Syongari	ctx.nfe_busaddr = 0;
1153170589Syongari	error = bus_dmamap_load(ring->jrx_desc_tag, ring->jrx_desc_map, desc,
1154170589Syongari	    NFE_JUMBO_RX_RING_COUNT * descsize, nfe_dma_map_segs, &ctx, 0);
1155170589Syongari	if (error != 0) {
1156170589Syongari		device_printf(sc->nfe_dev,
1157170589Syongari		    "could not load DMA'able memory for jumbo Rx ring\n");
1158170589Syongari		goto fail;
1159170589Syongari	}
1160170589Syongari	ring->jphysaddr = ctx.nfe_busaddr;
1161170589Syongari
1162170589Syongari	/* Create DMA maps for jumbo Rx buffers. */
1163170589Syongari	error = bus_dmamap_create(ring->jrx_data_tag, 0, &ring->jrx_spare_map);
1164170589Syongari	if (error != 0) {
1165170589Syongari		device_printf(sc->nfe_dev,
1166170589Syongari		    "could not create jumbo Rx DMA spare map\n");
1167170589Syongari		goto fail;
1168170589Syongari	}
1169170589Syongari
1170170589Syongari	for (i = 0; i < NFE_JUMBO_RX_RING_COUNT; i++) {
1171170589Syongari		data = &sc->jrxq.jdata[i];
1172170589Syongari		data->rx_data_map = NULL;
1173170589Syongari		data->m = NULL;
1174170589Syongari		error = bus_dmamap_create(ring->jrx_data_tag, 0,
1175164651Sobrien		    &data->rx_data_map);
1176164651Sobrien		if (error != 0) {
1177170589Syongari			device_printf(sc->nfe_dev,
1178170589Syongari			    "could not create jumbo Rx DMA map\n");
1179164651Sobrien			goto fail;
1180164651Sobrien		}
1181170589Syongari	}
1182159967Sobrien
1183171559Syongari	return;
1184159967Sobrien
1185170589Syongarifail:
1186171559Syongari	/*
1187171559Syongari	 * Running without jumbo frame support is ok for most cases
1188171559Syongari	 * so don't fail on creating dma tag/map for jumbo frame.
1189171559Syongari	 */
1190170589Syongari	nfe_free_jrx_ring(sc, ring);
1191171559Syongari	device_printf(sc->nfe_dev, "disabling jumbo frame support due to "
1192171559Syongari	    "resource shortage\n");
1193171559Syongari	sc->nfe_jumbo_disable = 1;
1194170589Syongari}
1195159967Sobrien
1196159967Sobrien
1197170589Syongaristatic int
1198170589Syongarinfe_init_rx_ring(struct nfe_softc *sc, struct nfe_rx_ring *ring)
1199170589Syongari{
1200170589Syongari	void *desc;
1201170589Syongari	size_t descsize;
1202170589Syongari	int i;
1203159967Sobrien
1204170589Syongari	ring->cur = ring->next = 0;
1205170589Syongari	if (sc->nfe_flags & NFE_40BIT_ADDR) {
1206170589Syongari		desc = ring->desc64;
1207170589Syongari		descsize = sizeof (struct nfe_desc64);
1208170589Syongari	} else {
1209170589Syongari		desc = ring->desc32;
1210170589Syongari		descsize = sizeof (struct nfe_desc32);
1211159967Sobrien	}
1212170589Syongari	bzero(desc, descsize * NFE_RX_RING_COUNT);
1213170589Syongari	for (i = 0; i < NFE_RX_RING_COUNT; i++) {
1214170589Syongari		if (nfe_newbuf(sc, i) != 0)
1215170589Syongari			return (ENOBUFS);
1216170589Syongari	}
1217159967Sobrien
1218163503Sobrien	bus_dmamap_sync(ring->rx_desc_tag, ring->rx_desc_map,
1219170589Syongari	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1220159967Sobrien
1221170589Syongari	return (0);
1222159967Sobrien}
1223159967Sobrien
1224163503Sobrien
1225170589Syongaristatic int
1226170589Syongarinfe_init_jrx_ring(struct nfe_softc *sc, struct nfe_jrx_ring *ring)
1227159967Sobrien{
1228170589Syongari	void *desc;
1229170589Syongari	size_t descsize;
1230159967Sobrien	int i;
1231159967Sobrien
1232170589Syongari	ring->jcur = ring->jnext = 0;
1233170589Syongari	if (sc->nfe_flags & NFE_40BIT_ADDR) {
1234170589Syongari		desc = ring->jdesc64;
1235170589Syongari		descsize = sizeof (struct nfe_desc64);
1236170589Syongari	} else {
1237170589Syongari		desc = ring->jdesc32;
1238170589Syongari		descsize = sizeof (struct nfe_desc32);
1239159952Sobrien	}
1240176859Syongari	bzero(desc, descsize * NFE_JUMBO_RX_RING_COUNT);
1241170589Syongari	for (i = 0; i < NFE_JUMBO_RX_RING_COUNT; i++) {
1242170589Syongari		if (nfe_jnewbuf(sc, i) != 0)
1243170589Syongari			return (ENOBUFS);
1244170589Syongari	}
1245159952Sobrien
1246170589Syongari	bus_dmamap_sync(ring->jrx_desc_tag, ring->jrx_desc_map,
1247170589Syongari	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1248159952Sobrien
1249170589Syongari	return (0);
1250159967Sobrien}
1251159967Sobrien
1252159967Sobrien
1253159967Sobrienstatic void
1254159967Sobriennfe_free_rx_ring(struct nfe_softc *sc, struct nfe_rx_ring *ring)
1255159967Sobrien{
1256159967Sobrien	struct nfe_rx_data *data;
1257159967Sobrien	void *desc;
1258159967Sobrien	int i, descsize;
1259159967Sobrien
1260159967Sobrien	if (sc->nfe_flags & NFE_40BIT_ADDR) {
1261159967Sobrien		desc = ring->desc64;
1262159967Sobrien		descsize = sizeof (struct nfe_desc64);
1263159967Sobrien	} else {
1264159967Sobrien		desc = ring->desc32;
1265159967Sobrien		descsize = sizeof (struct nfe_desc32);
1266159952Sobrien	}
1267159952Sobrien
1268170589Syongari	for (i = 0; i < NFE_RX_RING_COUNT; i++) {
1269170589Syongari		data = &ring->data[i];
1270170589Syongari		if (data->rx_data_map != NULL) {
1271170589Syongari			bus_dmamap_destroy(ring->rx_data_tag,
1272170589Syongari			    data->rx_data_map);
1273170589Syongari			data->rx_data_map = NULL;
1274170589Syongari		}
1275170589Syongari		if (data->m != NULL) {
1276170589Syongari			m_freem(data->m);
1277170589Syongari			data->m = NULL;
1278170589Syongari		}
1279170589Syongari	}
1280170589Syongari	if (ring->rx_data_tag != NULL) {
1281170589Syongari		if (ring->rx_spare_map != NULL) {
1282170589Syongari			bus_dmamap_destroy(ring->rx_data_tag,
1283170589Syongari			    ring->rx_spare_map);
1284170589Syongari			ring->rx_spare_map = NULL;
1285170589Syongari		}
1286170589Syongari		bus_dma_tag_destroy(ring->rx_data_tag);
1287170589Syongari		ring->rx_data_tag = NULL;
1288170589Syongari	}
1289170589Syongari
1290159967Sobrien	if (desc != NULL) {
1291159967Sobrien		bus_dmamap_unload(ring->rx_desc_tag, ring->rx_desc_map);
1292159967Sobrien		bus_dmamem_free(ring->rx_desc_tag, desc, ring->rx_desc_map);
1293170589Syongari		ring->desc64 = NULL;
1294170589Syongari		ring->desc32 = NULL;
1295170589Syongari		ring->rx_desc_map = NULL;
1296170589Syongari	}
1297170589Syongari	if (ring->rx_desc_tag != NULL) {
1298159967Sobrien		bus_dma_tag_destroy(ring->rx_desc_tag);
1299170589Syongari		ring->rx_desc_tag = NULL;
1300159967Sobrien	}
1301170589Syongari}
1302159967Sobrien
1303164650Sobrien
1304170589Syongaristatic void
1305170589Syongarinfe_free_jrx_ring(struct nfe_softc *sc, struct nfe_jrx_ring *ring)
1306170589Syongari{
1307170589Syongari	struct nfe_rx_data *data;
1308170589Syongari	void *desc;
1309170589Syongari	int i, descsize;
1310170589Syongari
1311170589Syongari	if ((sc->nfe_flags & NFE_JUMBO_SUP) == 0)
1312170589Syongari		return;
1313170589Syongari
1314170589Syongari	if (sc->nfe_flags & NFE_40BIT_ADDR) {
1315170589Syongari		desc = ring->jdesc64;
1316170589Syongari		descsize = sizeof (struct nfe_desc64);
1317170589Syongari	} else {
1318170589Syongari		desc = ring->jdesc32;
1319170589Syongari		descsize = sizeof (struct nfe_desc32);
1320170589Syongari	}
1321170589Syongari
1322170589Syongari	for (i = 0; i < NFE_JUMBO_RX_RING_COUNT; i++) {
1323170589Syongari		data = &ring->jdata[i];
1324164651Sobrien		if (data->rx_data_map != NULL) {
1325170589Syongari			bus_dmamap_destroy(ring->jrx_data_tag,
1326164651Sobrien			    data->rx_data_map);
1327170589Syongari			data->rx_data_map = NULL;
1328164651Sobrien		}
1329170589Syongari		if (data->m != NULL) {
1330164651Sobrien			m_freem(data->m);
1331170589Syongari			data->m = NULL;
1332170589Syongari		}
1333164651Sobrien	}
1334170589Syongari	if (ring->jrx_data_tag != NULL) {
1335170589Syongari		if (ring->jrx_spare_map != NULL) {
1336170589Syongari			bus_dmamap_destroy(ring->jrx_data_tag,
1337170589Syongari			    ring->jrx_spare_map);
1338170589Syongari			ring->jrx_spare_map = NULL;
1339170589Syongari		}
1340170589Syongari		bus_dma_tag_destroy(ring->jrx_data_tag);
1341170589Syongari		ring->jrx_data_tag = NULL;
1342170589Syongari	}
1343170589Syongari
1344170589Syongari	if (desc != NULL) {
1345170589Syongari		bus_dmamap_unload(ring->jrx_desc_tag, ring->jrx_desc_map);
1346170589Syongari		bus_dmamem_free(ring->jrx_desc_tag, desc, ring->jrx_desc_map);
1347170589Syongari		ring->jdesc64 = NULL;
1348170589Syongari		ring->jdesc32 = NULL;
1349170589Syongari		ring->jrx_desc_map = NULL;
1350170589Syongari	}
1351176859Syongari
1352170589Syongari	if (ring->jrx_desc_tag != NULL) {
1353170589Syongari		bus_dma_tag_destroy(ring->jrx_desc_tag);
1354170589Syongari		ring->jrx_desc_tag = NULL;
1355170589Syongari	}
1356159952Sobrien}
1357159952Sobrien
1358163503Sobrien
1359159967Sobrienstatic int
1360159967Sobriennfe_alloc_tx_ring(struct nfe_softc *sc, struct nfe_tx_ring *ring)
1361159952Sobrien{
1362170589Syongari	struct nfe_dmamap_arg ctx;
1363159967Sobrien	int i, error;
1364170589Syongari	void *desc;
1365159967Sobrien	int descsize;
1366159952Sobrien
1367159967Sobrien	if (sc->nfe_flags & NFE_40BIT_ADDR) {
1368170589Syongari		desc = ring->desc64;
1369159967Sobrien		descsize = sizeof (struct nfe_desc64);
1370159967Sobrien	} else {
1371170589Syongari		desc = ring->desc32;
1372159967Sobrien		descsize = sizeof (struct nfe_desc32);
1373159967Sobrien	}
1374159952Sobrien
1375159967Sobrien	ring->queued = 0;
1376159967Sobrien	ring->cur = ring->next = 0;
1377159967Sobrien
1378163503Sobrien	error = bus_dma_tag_create(sc->nfe_parent_tag,
1379170589Syongari	    NFE_RING_ALIGN, 0,			/* alignment, boundary */
1380170589Syongari	    BUS_SPACE_MAXADDR,			/* lowaddr */
1381170589Syongari	    BUS_SPACE_MAXADDR,			/* highaddr */
1382170589Syongari	    NULL, NULL,				/* filter, filterarg */
1383170589Syongari	    NFE_TX_RING_COUNT * descsize, 1,	/* maxsize, nsegments */
1384170589Syongari	    NFE_TX_RING_COUNT * descsize,	/* maxsegsize */
1385170589Syongari	    0,					/* flags */
1386170589Syongari	    NULL, NULL,				/* lockfunc, lockarg */
1387170589Syongari	    &ring->tx_desc_tag);
1388159967Sobrien	if (error != 0) {
1389170589Syongari		device_printf(sc->nfe_dev, "could not create desc DMA tag\n");
1390159967Sobrien		goto fail;
1391159952Sobrien	}
1392159952Sobrien
1393170589Syongari	error = bus_dmamem_alloc(ring->tx_desc_tag, &desc, BUS_DMA_WAITOK |
1394170589Syongari	    BUS_DMA_COHERENT | BUS_DMA_ZERO, &ring->tx_desc_map);
1395159967Sobrien	if (error != 0) {
1396170589Syongari		device_printf(sc->nfe_dev, "could not create desc DMA map\n");
1397159967Sobrien		goto fail;
1398159967Sobrien	}
1399170589Syongari	if (sc->nfe_flags & NFE_40BIT_ADDR)
1400170589Syongari		ring->desc64 = desc;
1401170589Syongari	else
1402170589Syongari		ring->desc32 = desc;
1403159967Sobrien
1404170589Syongari	ctx.nfe_busaddr = 0;
1405170589Syongari	error = bus_dmamap_load(ring->tx_desc_tag, ring->tx_desc_map, desc,
1406170589Syongari	    NFE_TX_RING_COUNT * descsize, nfe_dma_map_segs, &ctx, 0);
1407159967Sobrien	if (error != 0) {
1408170589Syongari		device_printf(sc->nfe_dev, "could not load desc DMA map\n");
1409159967Sobrien		goto fail;
1410159967Sobrien	}
1411170589Syongari	ring->physaddr = ctx.nfe_busaddr;
1412159967Sobrien
1413163503Sobrien	error = bus_dma_tag_create(sc->nfe_parent_tag,
1414170589Syongari	    1, 0,
1415170589Syongari	    BUS_SPACE_MAXADDR,
1416170589Syongari	    BUS_SPACE_MAXADDR,
1417170589Syongari	    NULL, NULL,
1418170595Syongari	    NFE_TSO_MAXSIZE,
1419170589Syongari	    NFE_MAX_SCATTER,
1420170595Syongari	    NFE_TSO_MAXSGSIZE,
1421170589Syongari	    0,
1422170589Syongari	    NULL, NULL,
1423170589Syongari	    &ring->tx_data_tag);
1424159967Sobrien	if (error != 0) {
1425170589Syongari		device_printf(sc->nfe_dev, "could not create Tx DMA tag\n");
1426170589Syongari		goto fail;
1427159967Sobrien	}
1428159967Sobrien
1429159967Sobrien	for (i = 0; i < NFE_TX_RING_COUNT; i++) {
1430163503Sobrien		error = bus_dmamap_create(ring->tx_data_tag, 0,
1431163503Sobrien		    &ring->data[i].tx_data_map);
1432159967Sobrien		if (error != 0) {
1433170589Syongari			device_printf(sc->nfe_dev,
1434170589Syongari			    "could not create Tx DMA map\n");
1435159967Sobrien			goto fail;
1436159967Sobrien		}
1437159967Sobrien	}
1438159967Sobrien
1439170589Syongarifail:
1440170589Syongari	return (error);
1441159967Sobrien}
1442159967Sobrien
1443159967Sobrien
1444159967Sobrienstatic void
1445170589Syongarinfe_init_tx_ring(struct nfe_softc *sc, struct nfe_tx_ring *ring)
1446159967Sobrien{
1447170589Syongari	void *desc;
1448170589Syongari	size_t descsize;
1449159967Sobrien
1450170589Syongari	sc->nfe_force_tx = 0;
1451170589Syongari	ring->queued = 0;
1452170589Syongari	ring->cur = ring->next = 0;
1453170589Syongari	if (sc->nfe_flags & NFE_40BIT_ADDR) {
1454170589Syongari		desc = ring->desc64;
1455170589Syongari		descsize = sizeof (struct nfe_desc64);
1456170589Syongari	} else {
1457170589Syongari		desc = ring->desc32;
1458170589Syongari		descsize = sizeof (struct nfe_desc32);
1459159967Sobrien	}
1460170589Syongari	bzero(desc, descsize * NFE_TX_RING_COUNT);
1461159967Sobrien
1462163503Sobrien	bus_dmamap_sync(ring->tx_desc_tag, ring->tx_desc_map,
1463170589Syongari	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1464159967Sobrien}
1465159967Sobrien
1466163503Sobrien
1467159967Sobrienstatic void
1468159967Sobriennfe_free_tx_ring(struct nfe_softc *sc, struct nfe_tx_ring *ring)
1469159967Sobrien{
1470159967Sobrien	struct nfe_tx_data *data;
1471159967Sobrien	void *desc;
1472159967Sobrien	int i, descsize;
1473159967Sobrien
1474159967Sobrien	if (sc->nfe_flags & NFE_40BIT_ADDR) {
1475159967Sobrien		desc = ring->desc64;
1476159967Sobrien		descsize = sizeof (struct nfe_desc64);
1477159967Sobrien	} else {
1478159967Sobrien		desc = ring->desc32;
1479159967Sobrien		descsize = sizeof (struct nfe_desc32);
1480159967Sobrien	}
1481159967Sobrien
1482159967Sobrien	for (i = 0; i < NFE_TX_RING_COUNT; i++) {
1483159967Sobrien		data = &ring->data[i];
1484159967Sobrien
1485159967Sobrien		if (data->m != NULL) {
1486170589Syongari			bus_dmamap_sync(ring->tx_data_tag, data->tx_data_map,
1487163503Sobrien			    BUS_DMASYNC_POSTWRITE);
1488170589Syongari			bus_dmamap_unload(ring->tx_data_tag, data->tx_data_map);
1489159967Sobrien			m_freem(data->m);
1490170589Syongari			data->m = NULL;
1491159967Sobrien		}
1492170589Syongari		if (data->tx_data_map != NULL) {
1493170589Syongari			bus_dmamap_destroy(ring->tx_data_tag,
1494170589Syongari			    data->tx_data_map);
1495170589Syongari			data->tx_data_map = NULL;
1496170589Syongari		}
1497159967Sobrien	}
1498159967Sobrien
1499170589Syongari	if (ring->tx_data_tag != NULL) {
1500170589Syongari		bus_dma_tag_destroy(ring->tx_data_tag);
1501170589Syongari		ring->tx_data_tag = NULL;
1502159967Sobrien	}
1503159967Sobrien
1504170589Syongari	if (desc != NULL) {
1505170589Syongari		bus_dmamap_sync(ring->tx_desc_tag, ring->tx_desc_map,
1506170589Syongari		    BUS_DMASYNC_POSTWRITE);
1507170589Syongari		bus_dmamap_unload(ring->tx_desc_tag, ring->tx_desc_map);
1508170589Syongari		bus_dmamem_free(ring->tx_desc_tag, desc, ring->tx_desc_map);
1509170589Syongari		ring->desc64 = NULL;
1510170589Syongari		ring->desc32 = NULL;
1511170589Syongari		ring->tx_desc_map = NULL;
1512170589Syongari		bus_dma_tag_destroy(ring->tx_desc_tag);
1513170589Syongari		ring->tx_desc_tag = NULL;
1514170589Syongari	}
1515159967Sobrien}
1516159967Sobrien
1517159967Sobrien#ifdef DEVICE_POLLING
1518159967Sobrienstatic poll_handler_t nfe_poll;
1519159967Sobrien
1520163503Sobrien
1521159967Sobrienstatic void
1522159967Sobriennfe_poll(struct ifnet *ifp, enum poll_cmd cmd, int count)
1523159967Sobrien{
1524164360Sobrien	struct nfe_softc *sc = ifp->if_softc;
1525170589Syongari	uint32_t r;
1526159967Sobrien
1527159967Sobrien	NFE_LOCK(sc);
1528159967Sobrien
1529159967Sobrien	if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) {
1530170589Syongari		NFE_UNLOCK(sc);
1531159967Sobrien		return;
1532159967Sobrien	}
1533159967Sobrien
1534171559Syongari	if (sc->nfe_framesize > MCLBYTES - ETHER_HDR_LEN)
1535171559Syongari		nfe_jrxeof(sc, count);
1536171559Syongari	else
1537171559Syongari		nfe_rxeof(sc, count);
1538159967Sobrien	nfe_txeof(sc);
1539159967Sobrien	if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
1540173674Ssam		taskqueue_enqueue_fast(sc->nfe_tq, &sc->nfe_tx_task);
1541159967Sobrien
1542159967Sobrien	if (cmd == POLL_AND_CHECK_STATUS) {
1543170589Syongari		if ((r = NFE_READ(sc, sc->nfe_irq_status)) == 0) {
1544170589Syongari			NFE_UNLOCK(sc);
1545163503Sobrien			return;
1546163503Sobrien		}
1547170589Syongari		NFE_WRITE(sc, sc->nfe_irq_status, r);
1548159967Sobrien
1549163503Sobrien		if (r & NFE_IRQ_LINK) {
1550163503Sobrien			NFE_READ(sc, NFE_PHY_STATUS);
1551163503Sobrien			NFE_WRITE(sc, NFE_PHY_STATUS, 0xf);
1552170589Syongari			DPRINTF(sc, "link state changed\n");
1553163503Sobrien		}
1554159967Sobrien	}
1555170589Syongari	NFE_UNLOCK(sc);
1556159967Sobrien}
1557159967Sobrien#endif /* DEVICE_POLLING */
1558159967Sobrien
1559170589Syongaristatic void
1560170589Syongarinfe_set_intr(struct nfe_softc *sc)
1561170589Syongari{
1562159967Sobrien
1563170589Syongari	if (sc->nfe_msi != 0)
1564170589Syongari		NFE_WRITE(sc, NFE_IRQ_MASK, NFE_IRQ_WANTED);
1565170589Syongari}
1566170589Syongari
1567170589Syongari
1568170589Syongari/* In MSIX, a write to mask reegisters behaves as XOR. */
1569170589Syongaristatic __inline void
1570170589Syongarinfe_enable_intr(struct nfe_softc *sc)
1571170589Syongari{
1572170589Syongari
1573170589Syongari	if (sc->nfe_msix != 0) {
1574170589Syongari		/* XXX Should have a better way to enable interrupts! */
1575170589Syongari		if (NFE_READ(sc, sc->nfe_irq_mask) == 0)
1576170589Syongari			NFE_WRITE(sc, sc->nfe_irq_mask, sc->nfe_intrs);
1577170589Syongari	} else
1578170589Syongari		NFE_WRITE(sc, sc->nfe_irq_mask, sc->nfe_intrs);
1579170589Syongari}
1580170589Syongari
1581170589Syongari
1582170589Syongaristatic __inline void
1583170589Syongarinfe_disable_intr(struct nfe_softc *sc)
1584170589Syongari{
1585170589Syongari
1586170589Syongari	if (sc->nfe_msix != 0) {
1587170589Syongari		/* XXX Should have a better way to disable interrupts! */
1588170589Syongari		if (NFE_READ(sc, sc->nfe_irq_mask) != 0)
1589170589Syongari			NFE_WRITE(sc, sc->nfe_irq_mask, sc->nfe_nointrs);
1590170589Syongari	} else
1591170589Syongari		NFE_WRITE(sc, sc->nfe_irq_mask, sc->nfe_nointrs);
1592170589Syongari}
1593170589Syongari
1594170589Syongari
1595159967Sobrienstatic int
1596159967Sobriennfe_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
1597159967Sobrien{
1598170589Syongari	struct nfe_softc *sc;
1599170589Syongari	struct ifreq *ifr;
1600163503Sobrien	struct mii_data *mii;
1601170589Syongari	int error, init, mask;
1602159967Sobrien
1603170589Syongari	sc = ifp->if_softc;
1604170589Syongari	ifr = (struct ifreq *) data;
1605170589Syongari	error = 0;
1606170589Syongari	init = 0;
1607159952Sobrien	switch (cmd) {
1608159952Sobrien	case SIOCSIFMTU:
1609170589Syongari		if (ifr->ifr_mtu < ETHERMIN || ifr->ifr_mtu > NFE_JUMBO_MTU)
1610159952Sobrien			error = EINVAL;
1611170589Syongari		else if (ifp->if_mtu != ifr->ifr_mtu) {
1612171559Syongari			if ((((sc->nfe_flags & NFE_JUMBO_SUP) == 0) ||
1613171559Syongari			    (sc->nfe_jumbo_disable != 0)) &&
1614170589Syongari			    ifr->ifr_mtu > ETHERMTU)
1615170589Syongari				error = EINVAL;
1616170589Syongari			else {
1617170589Syongari				NFE_LOCK(sc);
1618170589Syongari				ifp->if_mtu = ifr->ifr_mtu;
1619170589Syongari				if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0)
1620170589Syongari					nfe_init_locked(sc);
1621170589Syongari				NFE_UNLOCK(sc);
1622164650Sobrien			}
1623164650Sobrien		}
1624159952Sobrien		break;
1625159952Sobrien	case SIOCSIFFLAGS:
1626159967Sobrien		NFE_LOCK(sc);
1627159952Sobrien		if (ifp->if_flags & IFF_UP) {
1628159952Sobrien			/*
1629159952Sobrien			 * If only the PROMISC or ALLMULTI flag changes, then
1630159952Sobrien			 * don't do a full re-init of the chip, just update
1631159952Sobrien			 * the Rx filter.
1632159952Sobrien			 */
1633159967Sobrien			if ((ifp->if_drv_flags & IFF_DRV_RUNNING) &&
1634159967Sobrien			    ((ifp->if_flags ^ sc->nfe_if_flags) &
1635159967Sobrien			     (IFF_ALLMULTI | IFF_PROMISC)) != 0)
1636159952Sobrien				nfe_setmulti(sc);
1637159967Sobrien			else
1638159967Sobrien				nfe_init_locked(sc);
1639159952Sobrien		} else {
1640159967Sobrien			if (ifp->if_drv_flags & IFF_DRV_RUNNING)
1641170589Syongari				nfe_stop(ifp);
1642159952Sobrien		}
1643159967Sobrien		sc->nfe_if_flags = ifp->if_flags;
1644159967Sobrien		NFE_UNLOCK(sc);
1645159967Sobrien		error = 0;
1646159952Sobrien		break;
1647159952Sobrien	case SIOCADDMULTI:
1648159952Sobrien	case SIOCDELMULTI:
1649170589Syongari		if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) {
1650159967Sobrien			NFE_LOCK(sc);
1651159967Sobrien			nfe_setmulti(sc);
1652159967Sobrien			NFE_UNLOCK(sc);
1653159952Sobrien			error = 0;
1654159952Sobrien		}
1655159952Sobrien		break;
1656159952Sobrien	case SIOCSIFMEDIA:
1657159952Sobrien	case SIOCGIFMEDIA:
1658159967Sobrien		mii = device_get_softc(sc->nfe_miibus);
1659159967Sobrien		error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, cmd);
1660159952Sobrien		break;
1661159967Sobrien	case SIOCSIFCAP:
1662170589Syongari		mask = ifr->ifr_reqcap ^ ifp->if_capenable;
1663159967Sobrien#ifdef DEVICE_POLLING
1664170589Syongari		if ((mask & IFCAP_POLLING) != 0) {
1665170589Syongari			if ((ifr->ifr_reqcap & IFCAP_POLLING) != 0) {
1666159967Sobrien				error = ether_poll_register(nfe_poll, ifp);
1667159967Sobrien				if (error)
1668170589Syongari					break;
1669159967Sobrien				NFE_LOCK(sc);
1670170589Syongari				nfe_disable_intr(sc);
1671163503Sobrien				ifp->if_capenable |= IFCAP_POLLING;
1672159967Sobrien				NFE_UNLOCK(sc);
1673159967Sobrien			} else {
1674159967Sobrien				error = ether_poll_deregister(ifp);
1675159967Sobrien				/* Enable interrupt even in error case */
1676159967Sobrien				NFE_LOCK(sc);
1677170589Syongari				nfe_enable_intr(sc);
1678159967Sobrien				ifp->if_capenable &= ~IFCAP_POLLING;
1679159967Sobrien				NFE_UNLOCK(sc);
1680159967Sobrien			}
1681159967Sobrien		}
1682163503Sobrien#endif /* DEVICE_POLLING */
1683170589Syongari		if ((sc->nfe_flags & NFE_HW_CSUM) != 0 &&
1684170589Syongari		    (mask & IFCAP_HWCSUM) != 0) {
1685159967Sobrien			ifp->if_capenable ^= IFCAP_HWCSUM;
1686170589Syongari			if ((IFCAP_TXCSUM & ifp->if_capenable) != 0 &&
1687170589Syongari			    (IFCAP_TXCSUM & ifp->if_capabilities) != 0)
1688170589Syongari				ifp->if_hwassist |= NFE_CSUM_FEATURES;
1689159967Sobrien			else
1690170589Syongari				ifp->if_hwassist &= ~NFE_CSUM_FEATURES;
1691170589Syongari			init++;
1692159967Sobrien		}
1693170589Syongari		if ((sc->nfe_flags & NFE_HW_VLAN) != 0 &&
1694170589Syongari		    (mask & IFCAP_VLAN_HWTAGGING) != 0) {
1695170589Syongari			ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING;
1696170589Syongari			init++;
1697170589Syongari		}
1698170589Syongari		/*
1699170589Syongari		 * XXX
1700170589Syongari		 * It seems that VLAN stripping requires Rx checksum offload.
1701170589Syongari		 * Unfortunately FreeBSD has no way to disable only Rx side
1702170589Syongari		 * VLAN stripping. So when we know Rx checksum offload is
1703170589Syongari		 * disabled turn entire hardware VLAN assist off.
1704170589Syongari		 */
1705170589Syongari		if ((sc->nfe_flags & (NFE_HW_CSUM | NFE_HW_VLAN)) ==
1706170589Syongari		    (NFE_HW_CSUM | NFE_HW_VLAN)) {
1707170589Syongari			if ((ifp->if_capenable & IFCAP_RXCSUM) == 0)
1708170589Syongari				ifp->if_capenable &= ~IFCAP_VLAN_HWTAGGING;
1709170589Syongari		}
1710170589Syongari
1711170589Syongari		if ((sc->nfe_flags & NFE_HW_CSUM) != 0 &&
1712170589Syongari		    (mask & IFCAP_TSO4) != 0) {
1713170589Syongari			ifp->if_capenable ^= IFCAP_TSO4;
1714170589Syongari			if ((IFCAP_TSO4 & ifp->if_capenable) != 0 &&
1715170589Syongari			    (IFCAP_TSO4 & ifp->if_capabilities) != 0)
1716170589Syongari				ifp->if_hwassist |= CSUM_TSO;
1717170589Syongari			else
1718170589Syongari				ifp->if_hwassist &= ~CSUM_TSO;
1719170589Syongari		}
1720170589Syongari
1721170589Syongari		if (init > 0 && (ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) {
1722170589Syongari			ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
1723164656Sobrien			nfe_init(sc);
1724170589Syongari		}
1725170589Syongari		if ((sc->nfe_flags & NFE_HW_VLAN) != 0)
1726170589Syongari			VLAN_CAPABILITIES(ifp);
1727159967Sobrien		break;
1728159952Sobrien	default:
1729159967Sobrien		error = ether_ioctl(ifp, cmd, data);
1730159967Sobrien		break;
1731159952Sobrien	}
1732159952Sobrien
1733170589Syongari	return (error);
1734159952Sobrien}
1735159952Sobrien
1736159967Sobrien
1737170589Syongaristatic int
1738163503Sobriennfe_intr(void *arg)
1739159967Sobrien{
1740170589Syongari	struct nfe_softc *sc;
1741170589Syongari	uint32_t status;
1742170589Syongari
1743170589Syongari	sc = (struct nfe_softc *)arg;
1744170589Syongari
1745170589Syongari	status = NFE_READ(sc, sc->nfe_irq_status);
1746170589Syongari	if (status == 0 || status == 0xffffffff)
1747170589Syongari		return (FILTER_STRAY);
1748170589Syongari	nfe_disable_intr(sc);
1749173674Ssam	taskqueue_enqueue_fast(sc->nfe_tq, &sc->nfe_int_task);
1750170589Syongari
1751170589Syongari	return (FILTER_HANDLED);
1752170589Syongari}
1753170589Syongari
1754170589Syongari
1755170589Syongaristatic void
1756170589Syongarinfe_int_task(void *arg, int pending)
1757170589Syongari{
1758159967Sobrien	struct nfe_softc *sc = arg;
1759159967Sobrien	struct ifnet *ifp = sc->nfe_ifp;
1760170589Syongari	uint32_t r;
1761170589Syongari	int domore;
1762159967Sobrien
1763163503Sobrien	NFE_LOCK(sc);
1764159967Sobrien
1765170589Syongari	if ((r = NFE_READ(sc, sc->nfe_irq_status)) == 0) {
1766170589Syongari		nfe_enable_intr(sc);
1767170589Syongari		NFE_UNLOCK(sc);
1768170589Syongari		return;	/* not for us */
1769170589Syongari	}
1770170589Syongari	NFE_WRITE(sc, sc->nfe_irq_status, r);
1771170589Syongari
1772170589Syongari	DPRINTFN(sc, 5, "nfe_intr: interrupt register %x\n", r);
1773170589Syongari
1774159967Sobrien#ifdef DEVICE_POLLING
1775159967Sobrien	if (ifp->if_capenable & IFCAP_POLLING) {
1776159967Sobrien		NFE_UNLOCK(sc);
1777159967Sobrien		return;
1778159967Sobrien	}
1779159967Sobrien#endif
1780159967Sobrien
1781172169Syongari	if (r & NFE_IRQ_LINK) {
1782172169Syongari		NFE_READ(sc, NFE_PHY_STATUS);
1783172169Syongari		NFE_WRITE(sc, NFE_PHY_STATUS, 0xf);
1784172169Syongari		DPRINTF(sc, "link state changed\n");
1785172169Syongari	}
1786172169Syongari
1787170589Syongari	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) {
1788163503Sobrien		NFE_UNLOCK(sc);
1789170589Syongari		nfe_enable_intr(sc);
1790170589Syongari		return;
1791159967Sobrien	}
1792159967Sobrien
1793170589Syongari	domore = 0;
1794170589Syongari	/* check Rx ring */
1795170589Syongari	if (sc->nfe_framesize > MCLBYTES - ETHER_HDR_LEN)
1796170589Syongari		domore = nfe_jrxeof(sc, sc->nfe_process_limit);
1797170589Syongari	else
1798170589Syongari		domore = nfe_rxeof(sc, sc->nfe_process_limit);
1799170589Syongari	/* check Tx ring */
1800170589Syongari	nfe_txeof(sc);
1801159967Sobrien
1802170589Syongari	if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
1803173674Ssam		taskqueue_enqueue_fast(sc->nfe_tq, &sc->nfe_tx_task);
1804159967Sobrien
1805159967Sobrien	NFE_UNLOCK(sc);
1806159967Sobrien
1807170589Syongari	if (domore || (NFE_READ(sc, sc->nfe_irq_status) != 0)) {
1808173674Ssam		taskqueue_enqueue_fast(sc->nfe_tq, &sc->nfe_int_task);
1809170589Syongari		return;
1810170589Syongari	}
1811170589Syongari
1812170589Syongari	/* Reenable interrupts. */
1813170589Syongari	nfe_enable_intr(sc);
1814159967Sobrien}
1815159967Sobrien
1816163503Sobrien
1817170589Syongaristatic __inline void
1818170589Syongarinfe_discard_rxbuf(struct nfe_softc *sc, int idx)
1819159952Sobrien{
1820170589Syongari	struct nfe_desc32 *desc32;
1821170589Syongari	struct nfe_desc64 *desc64;
1822170589Syongari	struct nfe_rx_data *data;
1823170589Syongari	struct mbuf *m;
1824163503Sobrien
1825170589Syongari	data = &sc->rxq.data[idx];
1826170589Syongari	m = data->m;
1827170589Syongari
1828170589Syongari	if (sc->nfe_flags & NFE_40BIT_ADDR) {
1829170589Syongari		desc64 = &sc->rxq.desc64[idx];
1830170589Syongari		/* VLAN packet may have overwritten it. */
1831170589Syongari		desc64->physaddr[0] = htole32(NFE_ADDR_HI(data->paddr));
1832170589Syongari		desc64->physaddr[1] = htole32(NFE_ADDR_LO(data->paddr));
1833170589Syongari		desc64->length = htole16(m->m_len);
1834170589Syongari		desc64->flags = htole16(NFE_RX_READY);
1835170589Syongari	} else {
1836170589Syongari		desc32 = &sc->rxq.desc32[idx];
1837170589Syongari		desc32->length = htole16(m->m_len);
1838170589Syongari		desc32->flags = htole16(NFE_RX_READY);
1839170589Syongari	}
1840159952Sobrien}
1841159952Sobrien
1842163503Sobrien
1843170589Syongaristatic __inline void
1844170589Syongarinfe_discard_jrxbuf(struct nfe_softc *sc, int idx)
1845159952Sobrien{
1846170589Syongari	struct nfe_desc32 *desc32;
1847170589Syongari	struct nfe_desc64 *desc64;
1848170589Syongari	struct nfe_rx_data *data;
1849170589Syongari	struct mbuf *m;
1850163503Sobrien
1851170589Syongari	data = &sc->jrxq.jdata[idx];
1852170589Syongari	m = data->m;
1853170589Syongari
1854170589Syongari	if (sc->nfe_flags & NFE_40BIT_ADDR) {
1855170589Syongari		desc64 = &sc->jrxq.jdesc64[idx];
1856170589Syongari		/* VLAN packet may have overwritten it. */
1857170589Syongari		desc64->physaddr[0] = htole32(NFE_ADDR_HI(data->paddr));
1858170589Syongari		desc64->physaddr[1] = htole32(NFE_ADDR_LO(data->paddr));
1859170589Syongari		desc64->length = htole16(m->m_len);
1860170589Syongari		desc64->flags = htole16(NFE_RX_READY);
1861170589Syongari	} else {
1862170589Syongari		desc32 = &sc->jrxq.jdesc32[idx];
1863170589Syongari		desc32->length = htole16(m->m_len);
1864170589Syongari		desc32->flags = htole16(NFE_RX_READY);
1865170589Syongari	}
1866159952Sobrien}
1867159952Sobrien
1868163503Sobrien
1869170589Syongaristatic int
1870170589Syongarinfe_newbuf(struct nfe_softc *sc, int idx)
1871159952Sobrien{
1872170589Syongari	struct nfe_rx_data *data;
1873170589Syongari	struct nfe_desc32 *desc32;
1874170589Syongari	struct nfe_desc64 *desc64;
1875170589Syongari	struct mbuf *m;
1876170589Syongari	bus_dma_segment_t segs[1];
1877170589Syongari	bus_dmamap_t map;
1878170589Syongari	int nsegs;
1879163503Sobrien
1880170589Syongari	m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
1881170589Syongari	if (m == NULL)
1882170589Syongari		return (ENOBUFS);
1883159952Sobrien
1884170589Syongari	m->m_len = m->m_pkthdr.len = MCLBYTES;
1885170589Syongari	m_adj(m, ETHER_ALIGN);
1886163503Sobrien
1887170589Syongari	if (bus_dmamap_load_mbuf_sg(sc->rxq.rx_data_tag, sc->rxq.rx_spare_map,
1888170589Syongari	    m, segs, &nsegs, BUS_DMA_NOWAIT) != 0) {
1889170589Syongari		m_freem(m);
1890170589Syongari		return (ENOBUFS);
1891170589Syongari	}
1892170589Syongari	KASSERT(nsegs == 1, ("%s: %d segments returned!", __func__, nsegs));
1893163503Sobrien
1894170589Syongari	data = &sc->rxq.data[idx];
1895170589Syongari	if (data->m != NULL) {
1896170589Syongari		bus_dmamap_sync(sc->rxq.rx_data_tag, data->rx_data_map,
1897170589Syongari		    BUS_DMASYNC_POSTREAD);
1898170589Syongari		bus_dmamap_unload(sc->rxq.rx_data_tag, data->rx_data_map);
1899170589Syongari	}
1900170589Syongari	map = data->rx_data_map;
1901170589Syongari	data->rx_data_map = sc->rxq.rx_spare_map;
1902170589Syongari	sc->rxq.rx_spare_map = map;
1903170589Syongari	bus_dmamap_sync(sc->rxq.rx_data_tag, data->rx_data_map,
1904170589Syongari	    BUS_DMASYNC_PREREAD);
1905170589Syongari	data->paddr = segs[0].ds_addr;
1906170589Syongari	data->m = m;
1907170589Syongari	/* update mapping address in h/w descriptor */
1908170589Syongari	if (sc->nfe_flags & NFE_40BIT_ADDR) {
1909170589Syongari		desc64 = &sc->rxq.desc64[idx];
1910170589Syongari		desc64->physaddr[0] = htole32(NFE_ADDR_HI(segs[0].ds_addr));
1911170589Syongari		desc64->physaddr[1] = htole32(NFE_ADDR_LO(segs[0].ds_addr));
1912170589Syongari		desc64->length = htole16(segs[0].ds_len);
1913170589Syongari		desc64->flags = htole16(NFE_RX_READY);
1914170589Syongari	} else {
1915170589Syongari		desc32 = &sc->rxq.desc32[idx];
1916170589Syongari		desc32->physaddr = htole32(NFE_ADDR_LO(segs[0].ds_addr));
1917170589Syongari		desc32->length = htole16(segs[0].ds_len);
1918170589Syongari		desc32->flags = htole16(NFE_RX_READY);
1919170589Syongari	}
1920170589Syongari
1921170589Syongari	return (0);
1922159952Sobrien}
1923159952Sobrien
1924163503Sobrien
1925170589Syongaristatic int
1926170589Syongarinfe_jnewbuf(struct nfe_softc *sc, int idx)
1927159952Sobrien{
1928170589Syongari	struct nfe_rx_data *data;
1929170589Syongari	struct nfe_desc32 *desc32;
1930170589Syongari	struct nfe_desc64 *desc64;
1931170589Syongari	struct mbuf *m;
1932170589Syongari	bus_dma_segment_t segs[1];
1933170589Syongari	bus_dmamap_t map;
1934170589Syongari	int nsegs;
1935163503Sobrien
1936176859Syongari	m = m_getjcl(M_DONTWAIT, MT_DATA, M_PKTHDR, MJUM9BYTES);
1937170589Syongari	if (m == NULL)
1938170589Syongari		return (ENOBUFS);
1939170589Syongari	if ((m->m_flags & M_EXT) == 0) {
1940170589Syongari		m_freem(m);
1941170589Syongari		return (ENOBUFS);
1942170589Syongari	}
1943176859Syongari	m->m_pkthdr.len = m->m_len = MJUM9BYTES;
1944170589Syongari	m_adj(m, ETHER_ALIGN);
1945159952Sobrien
1946170589Syongari	if (bus_dmamap_load_mbuf_sg(sc->jrxq.jrx_data_tag,
1947170589Syongari	    sc->jrxq.jrx_spare_map, m, segs, &nsegs, BUS_DMA_NOWAIT) != 0) {
1948170589Syongari		m_freem(m);
1949170589Syongari		return (ENOBUFS);
1950170589Syongari	}
1951170589Syongari	KASSERT(nsegs == 1, ("%s: %d segments returned!", __func__, nsegs));
1952163503Sobrien
1953170589Syongari	data = &sc->jrxq.jdata[idx];
1954170589Syongari	if (data->m != NULL) {
1955170589Syongari		bus_dmamap_sync(sc->jrxq.jrx_data_tag, data->rx_data_map,
1956170589Syongari		    BUS_DMASYNC_POSTREAD);
1957170589Syongari		bus_dmamap_unload(sc->jrxq.jrx_data_tag, data->rx_data_map);
1958170589Syongari	}
1959170589Syongari	map = data->rx_data_map;
1960170589Syongari	data->rx_data_map = sc->jrxq.jrx_spare_map;
1961170589Syongari	sc->jrxq.jrx_spare_map = map;
1962170589Syongari	bus_dmamap_sync(sc->jrxq.jrx_data_tag, data->rx_data_map,
1963170589Syongari	    BUS_DMASYNC_PREREAD);
1964170589Syongari	data->paddr = segs[0].ds_addr;
1965170589Syongari	data->m = m;
1966170589Syongari	/* update mapping address in h/w descriptor */
1967170589Syongari	if (sc->nfe_flags & NFE_40BIT_ADDR) {
1968170589Syongari		desc64 = &sc->jrxq.jdesc64[idx];
1969170589Syongari		desc64->physaddr[0] = htole32(NFE_ADDR_HI(segs[0].ds_addr));
1970170589Syongari		desc64->physaddr[1] = htole32(NFE_ADDR_LO(segs[0].ds_addr));
1971170589Syongari		desc64->length = htole16(segs[0].ds_len);
1972170589Syongari		desc64->flags = htole16(NFE_RX_READY);
1973170589Syongari	} else {
1974170589Syongari		desc32 = &sc->jrxq.jdesc32[idx];
1975170589Syongari		desc32->physaddr = htole32(NFE_ADDR_LO(segs[0].ds_addr));
1976170589Syongari		desc32->length = htole16(segs[0].ds_len);
1977170589Syongari		desc32->flags = htole16(NFE_RX_READY);
1978170589Syongari	}
1979159967Sobrien
1980170589Syongari	return (0);
1981159952Sobrien}
1982159952Sobrien
1983163503Sobrien
1984170589Syongaristatic int
1985170589Syongarinfe_rxeof(struct nfe_softc *sc, int count)
1986159952Sobrien{
1987159967Sobrien	struct ifnet *ifp = sc->nfe_ifp;
1988170589Syongari	struct nfe_desc32 *desc32;
1989170589Syongari	struct nfe_desc64 *desc64;
1990159952Sobrien	struct nfe_rx_data *data;
1991170589Syongari	struct mbuf *m;
1992170589Syongari	uint16_t flags;
1993170589Syongari	int len, prog;
1994170589Syongari	uint32_t vtag = 0;
1995159952Sobrien
1996159967Sobrien	NFE_LOCK_ASSERT(sc);
1997159967Sobrien
1998170589Syongari	bus_dmamap_sync(sc->rxq.rx_desc_tag, sc->rxq.rx_desc_map,
1999170589Syongari	    BUS_DMASYNC_POSTREAD);
2000159967Sobrien
2001170589Syongari	for (prog = 0;;NFE_INC(sc->rxq.cur, NFE_RX_RING_COUNT), vtag = 0) {
2002170589Syongari		if (count <= 0)
2003170589Syongari			break;
2004170589Syongari		count--;
2005159967Sobrien
2006159952Sobrien		data = &sc->rxq.data[sc->rxq.cur];
2007159952Sobrien
2008159967Sobrien		if (sc->nfe_flags & NFE_40BIT_ADDR) {
2009159952Sobrien			desc64 = &sc->rxq.desc64[sc->rxq.cur];
2010170589Syongari			vtag = le32toh(desc64->physaddr[1]);
2011170589Syongari			flags = le16toh(desc64->flags);
2012170589Syongari			len = le16toh(desc64->length) & NFE_RX_LEN_MASK;
2013159952Sobrien		} else {
2014159952Sobrien			desc32 = &sc->rxq.desc32[sc->rxq.cur];
2015170589Syongari			flags = le16toh(desc32->flags);
2016170589Syongari			len = le16toh(desc32->length) & NFE_RX_LEN_MASK;
2017159952Sobrien		}
2018159952Sobrien
2019159952Sobrien		if (flags & NFE_RX_READY)
2020159952Sobrien			break;
2021170589Syongari		prog++;
2022159967Sobrien		if ((sc->nfe_flags & (NFE_JUMBO_SUP | NFE_40BIT_ADDR)) == 0) {
2023170589Syongari			if (!(flags & NFE_RX_VALID_V1)) {
2024170589Syongari				ifp->if_ierrors++;
2025170589Syongari				nfe_discard_rxbuf(sc, sc->rxq.cur);
2026170589Syongari				continue;
2027170589Syongari			}
2028159952Sobrien			if ((flags & NFE_RX_FIXME_V1) == NFE_RX_FIXME_V1) {
2029159952Sobrien				flags &= ~NFE_RX_ERROR;
2030159952Sobrien				len--;	/* fix buffer length */
2031159952Sobrien			}
2032159952Sobrien		} else {
2033170589Syongari			if (!(flags & NFE_RX_VALID_V2)) {
2034170589Syongari				ifp->if_ierrors++;
2035170589Syongari				nfe_discard_rxbuf(sc, sc->rxq.cur);
2036170589Syongari				continue;
2037170589Syongari			}
2038159952Sobrien
2039159952Sobrien			if ((flags & NFE_RX_FIXME_V2) == NFE_RX_FIXME_V2) {
2040159952Sobrien				flags &= ~NFE_RX_ERROR;
2041159952Sobrien				len--;	/* fix buffer length */
2042159952Sobrien			}
2043159952Sobrien		}
2044159952Sobrien
2045159952Sobrien		if (flags & NFE_RX_ERROR) {
2046159952Sobrien			ifp->if_ierrors++;
2047170589Syongari			nfe_discard_rxbuf(sc, sc->rxq.cur);
2048170589Syongari			continue;
2049159952Sobrien		}
2050159952Sobrien
2051170589Syongari		m = data->m;
2052170589Syongari		if (nfe_newbuf(sc, sc->rxq.cur) != 0) {
2053170589Syongari			ifp->if_iqdrops++;
2054170589Syongari			nfe_discard_rxbuf(sc, sc->rxq.cur);
2055170589Syongari			continue;
2056159952Sobrien		}
2057159952Sobrien
2058170589Syongari		if ((vtag & NFE_RX_VTAG) != 0 &&
2059170589Syongari		    (ifp->if_capenable & IFCAP_VLAN_HWTAGGING) != 0) {
2060170589Syongari			m->m_pkthdr.ether_vtag = vtag & 0xffff;
2061170589Syongari			m->m_flags |= M_VLANTAG;
2062164651Sobrien		}
2063159952Sobrien
2064170589Syongari		m->m_pkthdr.len = m->m_len = len;
2065170589Syongari		m->m_pkthdr.rcvif = ifp;
2066164651Sobrien
2067170589Syongari		if ((ifp->if_capenable & IFCAP_RXCSUM) != 0) {
2068170589Syongari			if ((flags & NFE_RX_IP_CSUMOK) != 0) {
2069170589Syongari				m->m_pkthdr.csum_flags |= CSUM_IP_CHECKED;
2070170589Syongari				m->m_pkthdr.csum_flags |= CSUM_IP_VALID;
2071170589Syongari				if ((flags & NFE_RX_TCP_CSUMOK) != 0 ||
2072170589Syongari				    (flags & NFE_RX_UDP_CSUMOK) != 0) {
2073170589Syongari					m->m_pkthdr.csum_flags |=
2074170589Syongari					    CSUM_DATA_VALID | CSUM_PSEUDO_HDR;
2075170589Syongari					m->m_pkthdr.csum_data = 0xffff;
2076170589Syongari				}
2077159952Sobrien			}
2078170589Syongari		}
2079170589Syongari
2080170589Syongari		ifp->if_ipackets++;
2081170589Syongari
2082170589Syongari		NFE_UNLOCK(sc);
2083170589Syongari		(*ifp->if_input)(ifp, m);
2084170589Syongari		NFE_LOCK(sc);
2085170589Syongari	}
2086170589Syongari
2087170589Syongari	if (prog > 0)
2088170589Syongari		bus_dmamap_sync(sc->rxq.rx_desc_tag, sc->rxq.rx_desc_map,
2089170589Syongari		    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
2090170589Syongari
2091170589Syongari	return (count > 0 ? 0 : EAGAIN);
2092170589Syongari}
2093170589Syongari
2094170589Syongari
2095170589Syongaristatic int
2096170589Syongarinfe_jrxeof(struct nfe_softc *sc, int count)
2097170589Syongari{
2098170589Syongari	struct ifnet *ifp = sc->nfe_ifp;
2099170589Syongari	struct nfe_desc32 *desc32;
2100170589Syongari	struct nfe_desc64 *desc64;
2101170589Syongari	struct nfe_rx_data *data;
2102170589Syongari	struct mbuf *m;
2103170589Syongari	uint16_t flags;
2104170589Syongari	int len, prog;
2105170589Syongari	uint32_t vtag = 0;
2106170589Syongari
2107170589Syongari	NFE_LOCK_ASSERT(sc);
2108170589Syongari
2109170589Syongari	bus_dmamap_sync(sc->jrxq.jrx_desc_tag, sc->jrxq.jrx_desc_map,
2110170589Syongari	    BUS_DMASYNC_POSTREAD);
2111170589Syongari
2112170589Syongari	for (prog = 0;;NFE_INC(sc->jrxq.jcur, NFE_JUMBO_RX_RING_COUNT),
2113170589Syongari	    vtag = 0) {
2114170589Syongari		if (count <= 0)
2115170589Syongari			break;
2116170589Syongari		count--;
2117170589Syongari
2118170589Syongari		data = &sc->jrxq.jdata[sc->jrxq.jcur];
2119170589Syongari
2120170589Syongari		if (sc->nfe_flags & NFE_40BIT_ADDR) {
2121170589Syongari			desc64 = &sc->jrxq.jdesc64[sc->jrxq.jcur];
2122170589Syongari			vtag = le32toh(desc64->physaddr[1]);
2123170589Syongari			flags = le16toh(desc64->flags);
2124170589Syongari			len = le16toh(desc64->length) & NFE_RX_LEN_MASK;
2125170589Syongari		} else {
2126170589Syongari			desc32 = &sc->jrxq.jdesc32[sc->jrxq.jcur];
2127170589Syongari			flags = le16toh(desc32->flags);
2128170589Syongari			len = le16toh(desc32->length) & NFE_RX_LEN_MASK;
2129170589Syongari		}
2130170589Syongari
2131170589Syongari		if (flags & NFE_RX_READY)
2132170589Syongari			break;
2133170589Syongari		prog++;
2134170589Syongari		if ((sc->nfe_flags & (NFE_JUMBO_SUP | NFE_40BIT_ADDR)) == 0) {
2135170589Syongari			if (!(flags & NFE_RX_VALID_V1)) {
2136170589Syongari				ifp->if_ierrors++;
2137170589Syongari				nfe_discard_jrxbuf(sc, sc->jrxq.jcur);
2138170589Syongari				continue;
2139170589Syongari			}
2140170589Syongari			if ((flags & NFE_RX_FIXME_V1) == NFE_RX_FIXME_V1) {
2141170589Syongari				flags &= ~NFE_RX_ERROR;
2142170589Syongari				len--;	/* fix buffer length */
2143170589Syongari			}
2144170589Syongari		} else {
2145170589Syongari			if (!(flags & NFE_RX_VALID_V2)) {
2146170589Syongari				ifp->if_ierrors++;
2147170589Syongari				nfe_discard_jrxbuf(sc, sc->jrxq.jcur);
2148170589Syongari				continue;
2149170589Syongari			}
2150170589Syongari
2151170589Syongari			if ((flags & NFE_RX_FIXME_V2) == NFE_RX_FIXME_V2) {
2152170589Syongari				flags &= ~NFE_RX_ERROR;
2153170589Syongari				len--;	/* fix buffer length */
2154170589Syongari			}
2155170589Syongari		}
2156170589Syongari
2157170589Syongari		if (flags & NFE_RX_ERROR) {
2158164651Sobrien			ifp->if_ierrors++;
2159170589Syongari			nfe_discard_jrxbuf(sc, sc->jrxq.jcur);
2160170589Syongari			continue;
2161164651Sobrien		}
2162159952Sobrien
2163159952Sobrien		m = data->m;
2164170589Syongari		if (nfe_jnewbuf(sc, sc->jrxq.jcur) != 0) {
2165170589Syongari			ifp->if_iqdrops++;
2166170589Syongari			nfe_discard_jrxbuf(sc, sc->jrxq.jcur);
2167170589Syongari			continue;
2168170589Syongari		}
2169159952Sobrien
2170170589Syongari		if ((vtag & NFE_RX_VTAG) != 0 &&
2171170589Syongari		    (ifp->if_capenable & IFCAP_VLAN_HWTAGGING) != 0) {
2172170589Syongari			m->m_pkthdr.ether_vtag = vtag & 0xffff;
2173170589Syongari			m->m_flags |= M_VLANTAG;
2174170589Syongari		}
2175170589Syongari
2176159952Sobrien		m->m_pkthdr.len = m->m_len = len;
2177159952Sobrien		m->m_pkthdr.rcvif = ifp;
2178159952Sobrien
2179170589Syongari		if ((ifp->if_capenable & IFCAP_RXCSUM) != 0) {
2180170589Syongari			if ((flags & NFE_RX_IP_CSUMOK) != 0) {
2181170589Syongari				m->m_pkthdr.csum_flags |= CSUM_IP_CHECKED;
2182159967Sobrien				m->m_pkthdr.csum_flags |= CSUM_IP_VALID;
2183170589Syongari				if ((flags & NFE_RX_TCP_CSUMOK) != 0 ||
2184170589Syongari				    (flags & NFE_RX_UDP_CSUMOK) != 0) {
2185170589Syongari					m->m_pkthdr.csum_flags |=
2186170589Syongari					    CSUM_DATA_VALID | CSUM_PSEUDO_HDR;
2187170589Syongari					m->m_pkthdr.csum_data = 0xffff;
2188170589Syongari				}
2189159967Sobrien			}
2190159952Sobrien		}
2191159952Sobrien
2192159952Sobrien		ifp->if_ipackets++;
2193159952Sobrien
2194159967Sobrien		NFE_UNLOCK(sc);
2195159967Sobrien		(*ifp->if_input)(ifp, m);
2196159967Sobrien		NFE_LOCK(sc);
2197170589Syongari	}
2198159967Sobrien
2199170589Syongari	if (prog > 0)
2200170589Syongari		bus_dmamap_sync(sc->jrxq.jrx_desc_tag, sc->jrxq.jrx_desc_map,
2201170589Syongari		    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
2202159952Sobrien
2203170589Syongari	return (count > 0 ? 0 : EAGAIN);
2204159952Sobrien}
2205159952Sobrien
2206163503Sobrien
2207163503Sobrienstatic void
2208163503Sobriennfe_txeof(struct nfe_softc *sc)
2209159952Sobrien{
2210159967Sobrien	struct ifnet *ifp = sc->nfe_ifp;
2211159952Sobrien	struct nfe_desc32 *desc32;
2212159952Sobrien	struct nfe_desc64 *desc64;
2213159952Sobrien	struct nfe_tx_data *data = NULL;
2214170589Syongari	uint16_t flags;
2215170589Syongari	int cons, prog;
2216159952Sobrien
2217159967Sobrien	NFE_LOCK_ASSERT(sc);
2218159967Sobrien
2219170589Syongari	bus_dmamap_sync(sc->txq.tx_desc_tag, sc->txq.tx_desc_map,
2220170589Syongari	    BUS_DMASYNC_POSTREAD);
2221170589Syongari
2222170589Syongari	prog = 0;
2223170589Syongari	for (cons = sc->txq.next; cons != sc->txq.cur;
2224170589Syongari	    NFE_INC(cons, NFE_TX_RING_COUNT)) {
2225159967Sobrien		if (sc->nfe_flags & NFE_40BIT_ADDR) {
2226170589Syongari			desc64 = &sc->txq.desc64[cons];
2227170589Syongari			flags = le16toh(desc64->flags);
2228159952Sobrien		} else {
2229170589Syongari			desc32 = &sc->txq.desc32[cons];
2230170589Syongari			flags = le16toh(desc32->flags);
2231159952Sobrien		}
2232159952Sobrien
2233159952Sobrien		if (flags & NFE_TX_VALID)
2234159952Sobrien			break;
2235159952Sobrien
2236170589Syongari		prog++;
2237170589Syongari		sc->txq.queued--;
2238170589Syongari		data = &sc->txq.data[cons];
2239159952Sobrien
2240159967Sobrien		if ((sc->nfe_flags & (NFE_JUMBO_SUP | NFE_40BIT_ADDR)) == 0) {
2241170589Syongari			if ((flags & NFE_TX_LASTFRAG_V1) == 0)
2242170589Syongari				continue;
2243159952Sobrien			if ((flags & NFE_TX_ERROR_V1) != 0) {
2244170589Syongari				device_printf(sc->nfe_dev,
2245170589Syongari				    "tx v1 error 0x%4b\n", flags, NFE_V1_TXERR);
2246159967Sobrien
2247159952Sobrien				ifp->if_oerrors++;
2248159952Sobrien			} else
2249159952Sobrien				ifp->if_opackets++;
2250159952Sobrien		} else {
2251170589Syongari			if ((flags & NFE_TX_LASTFRAG_V2) == 0)
2252170589Syongari				continue;
2253159952Sobrien			if ((flags & NFE_TX_ERROR_V2) != 0) {
2254170589Syongari				device_printf(sc->nfe_dev,
2255170589Syongari				    "tx v2 error 0x%4b\n", flags, NFE_V2_TXERR);
2256159952Sobrien				ifp->if_oerrors++;
2257159952Sobrien			} else
2258159952Sobrien				ifp->if_opackets++;
2259159952Sobrien		}
2260159952Sobrien
2261159952Sobrien		/* last fragment of the mbuf chain transmitted */
2262170589Syongari		KASSERT(data->m != NULL, ("%s: freeing NULL mbuf!", __func__));
2263170589Syongari		bus_dmamap_sync(sc->txq.tx_data_tag, data->tx_data_map,
2264159967Sobrien		    BUS_DMASYNC_POSTWRITE);
2265170589Syongari		bus_dmamap_unload(sc->txq.tx_data_tag, data->tx_data_map);
2266159952Sobrien		m_freem(data->m);
2267159952Sobrien		data->m = NULL;
2268159952Sobrien	}
2269159952Sobrien
2270170589Syongari	if (prog > 0) {
2271170589Syongari		sc->nfe_force_tx = 0;
2272170589Syongari		sc->txq.next = cons;
2273159967Sobrien		ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
2274170589Syongari		if (sc->txq.queued == 0)
2275170589Syongari			sc->nfe_watchdog_timer = 0;
2276159952Sobrien	}
2277159952Sobrien}
2278159952Sobrien
2279163503Sobrienstatic int
2280170589Syongarinfe_encap(struct nfe_softc *sc, struct mbuf **m_head)
2281159952Sobrien{
2282170589Syongari	struct nfe_desc32 *desc32 = NULL;
2283170589Syongari	struct nfe_desc64 *desc64 = NULL;
2284159952Sobrien	bus_dmamap_t map;
2285163503Sobrien	bus_dma_segment_t segs[NFE_MAX_SCATTER];
2286170589Syongari	int error, i, nsegs, prod, si;
2287170589Syongari	uint32_t tso_segsz;
2288170589Syongari	uint16_t cflags, flags;
2289170589Syongari	struct mbuf *m;
2290159952Sobrien
2291170589Syongari	prod = si = sc->txq.cur;
2292170589Syongari	map = sc->txq.data[prod].tx_data_map;
2293159952Sobrien
2294170589Syongari	error = bus_dmamap_load_mbuf_sg(sc->txq.tx_data_tag, map, *m_head, segs,
2295159967Sobrien	    &nsegs, BUS_DMA_NOWAIT);
2296170589Syongari	if (error == EFBIG) {
2297175418Sjhb		m = m_collapse(*m_head, M_DONTWAIT, NFE_MAX_SCATTER);
2298170589Syongari		if (m == NULL) {
2299170589Syongari			m_freem(*m_head);
2300170589Syongari			*m_head = NULL;
2301170589Syongari			return (ENOBUFS);
2302170589Syongari		}
2303170589Syongari		*m_head = m;
2304170589Syongari		error = bus_dmamap_load_mbuf_sg(sc->txq.tx_data_tag, map,
2305170589Syongari		    *m_head, segs, &nsegs, BUS_DMA_NOWAIT);
2306170589Syongari		if (error != 0) {
2307170589Syongari			m_freem(*m_head);
2308170589Syongari			*m_head = NULL;
2309170589Syongari			return (ENOBUFS);
2310170589Syongari		}
2311170589Syongari	} else if (error != 0)
2312170589Syongari		return (error);
2313170589Syongari	if (nsegs == 0) {
2314170589Syongari		m_freem(*m_head);
2315170589Syongari		*m_head = NULL;
2316170589Syongari		return (EIO);
2317159952Sobrien	}
2318159952Sobrien
2319170589Syongari	if (sc->txq.queued + nsegs >= NFE_TX_RING_COUNT - 2) {
2320159967Sobrien		bus_dmamap_unload(sc->txq.tx_data_tag, map);
2321170589Syongari		return (ENOBUFS);
2322159952Sobrien	}
2323159952Sobrien
2324170589Syongari	m = *m_head;
2325170589Syongari	cflags = flags = 0;
2326170589Syongari	tso_segsz = 0;
2327170589Syongari	if ((m->m_pkthdr.csum_flags & NFE_CSUM_FEATURES) != 0) {
2328170589Syongari		if ((m->m_pkthdr.csum_flags & CSUM_IP) != 0)
2329170589Syongari			cflags |= NFE_TX_IP_CSUM;
2330170589Syongari		if ((m->m_pkthdr.csum_flags & CSUM_TCP) != 0)
2331170589Syongari			cflags |= NFE_TX_TCP_UDP_CSUM;
2332170589Syongari		if ((m->m_pkthdr.csum_flags & CSUM_UDP) != 0)
2333170589Syongari			cflags |= NFE_TX_TCP_UDP_CSUM;
2334164656Sobrien	}
2335170589Syongari	if ((m->m_pkthdr.csum_flags & CSUM_TSO) != 0) {
2336170589Syongari		tso_segsz = (uint32_t)m->m_pkthdr.tso_segsz <<
2337170589Syongari		    NFE_TX_TSO_SHIFT;
2338170589Syongari		cflags &= ~(NFE_TX_IP_CSUM | NFE_TX_TCP_UDP_CSUM);
2339170589Syongari		cflags |= NFE_TX_TSO;
2340170589Syongari	}
2341159967Sobrien
2342159967Sobrien	for (i = 0; i < nsegs; i++) {
2343159967Sobrien		if (sc->nfe_flags & NFE_40BIT_ADDR) {
2344170589Syongari			desc64 = &sc->txq.desc64[prod];
2345170589Syongari			desc64->physaddr[0] =
2346170589Syongari			    htole32(NFE_ADDR_HI(segs[i].ds_addr));
2347170589Syongari			desc64->physaddr[1] =
2348170589Syongari			    htole32(NFE_ADDR_LO(segs[i].ds_addr));
2349170589Syongari			desc64->vtag = 0;
2350159967Sobrien			desc64->length = htole16(segs[i].ds_len - 1);
2351159952Sobrien			desc64->flags = htole16(flags);
2352159952Sobrien		} else {
2353170589Syongari			desc32 = &sc->txq.desc32[prod];
2354170589Syongari			desc32->physaddr =
2355170589Syongari			    htole32(NFE_ADDR_LO(segs[i].ds_addr));
2356159967Sobrien			desc32->length = htole16(segs[i].ds_len - 1);
2357159952Sobrien			desc32->flags = htole16(flags);
2358159952Sobrien		}
2359159952Sobrien
2360170589Syongari		/*
2361170589Syongari		 * Setting of the valid bit in the first descriptor is
2362170589Syongari		 * deferred until the whole chain is fully setup.
2363170589Syongari		 */
2364170589Syongari		flags |= NFE_TX_VALID;
2365163503Sobrien
2366159952Sobrien		sc->txq.queued++;
2367170589Syongari		NFE_INC(prod, NFE_TX_RING_COUNT);
2368159952Sobrien	}
2369159952Sobrien
2370170589Syongari	/*
2371170589Syongari	 * the whole mbuf chain has been DMA mapped, fix last/first descriptor.
2372170589Syongari	 * csum flags, vtag and TSO belong to the first fragment only.
2373170589Syongari	 */
2374159967Sobrien	if (sc->nfe_flags & NFE_40BIT_ADDR) {
2375170589Syongari		desc64->flags |= htole16(NFE_TX_LASTFRAG_V2);
2376170589Syongari		desc64 = &sc->txq.desc64[si];
2377170589Syongari		if ((m->m_flags & M_VLANTAG) != 0)
2378170589Syongari			desc64->vtag = htole32(NFE_TX_VTAG |
2379170589Syongari			    m->m_pkthdr.ether_vtag);
2380170589Syongari		if (tso_segsz != 0) {
2381170589Syongari			/*
2382170589Syongari			 * XXX
2383170589Syongari			 * The following indicates the descriptor element
2384170589Syongari			 * is a 32bit quantity.
2385170589Syongari			 */
2386170589Syongari			desc64->length |= htole16((uint16_t)tso_segsz);
2387170589Syongari			desc64->flags |= htole16(tso_segsz >> 16);
2388170589Syongari		}
2389170589Syongari		/*
2390170589Syongari		 * finally, set the valid/checksum/TSO bit in the first
2391170589Syongari		 * descriptor.
2392170589Syongari		 */
2393170589Syongari		desc64->flags |= htole16(NFE_TX_VALID | cflags);
2394159952Sobrien	} else {
2395159967Sobrien		if (sc->nfe_flags & NFE_JUMBO_SUP)
2396170589Syongari			desc32->flags |= htole16(NFE_TX_LASTFRAG_V2);
2397159952Sobrien		else
2398170589Syongari			desc32->flags |= htole16(NFE_TX_LASTFRAG_V1);
2399170589Syongari		desc32 = &sc->txq.desc32[si];
2400170589Syongari		if (tso_segsz != 0) {
2401170589Syongari			/*
2402170589Syongari			 * XXX
2403170589Syongari			 * The following indicates the descriptor element
2404170589Syongari			 * is a 32bit quantity.
2405170589Syongari			 */
2406170589Syongari			desc32->length |= htole16((uint16_t)tso_segsz);
2407170589Syongari			desc32->flags |= htole16(tso_segsz >> 16);
2408170589Syongari		}
2409170589Syongari		/*
2410170589Syongari		 * finally, set the valid/checksum/TSO bit in the first
2411170589Syongari		 * descriptor.
2412170589Syongari		 */
2413170589Syongari		desc32->flags |= htole16(NFE_TX_VALID | cflags);
2414159952Sobrien	}
2415159952Sobrien
2416170589Syongari	sc->txq.cur = prod;
2417170589Syongari	prod = (prod + NFE_TX_RING_COUNT - 1) % NFE_TX_RING_COUNT;
2418170589Syongari	sc->txq.data[si].tx_data_map = sc->txq.data[prod].tx_data_map;
2419170589Syongari	sc->txq.data[prod].tx_data_map = map;
2420170589Syongari	sc->txq.data[prod].m = m;
2421159952Sobrien
2422159967Sobrien	bus_dmamap_sync(sc->txq.tx_data_tag, map, BUS_DMASYNC_PREWRITE);
2423159952Sobrien
2424170589Syongari	return (0);
2425159952Sobrien}
2426159952Sobrien
2427159967Sobrien
2428163503Sobrienstatic void
2429163503Sobriennfe_setmulti(struct nfe_softc *sc)
2430159952Sobrien{
2431159967Sobrien	struct ifnet *ifp = sc->nfe_ifp;
2432163503Sobrien	struct ifmultiaddr *ifma;
2433163503Sobrien	int i;
2434170589Syongari	uint32_t filter;
2435170589Syongari	uint8_t addr[ETHER_ADDR_LEN], mask[ETHER_ADDR_LEN];
2436170589Syongari	uint8_t etherbroadcastaddr[ETHER_ADDR_LEN] = {
2437163503Sobrien		0xff, 0xff, 0xff, 0xff, 0xff, 0xff
2438163503Sobrien	};
2439159967Sobrien
2440159967Sobrien	NFE_LOCK_ASSERT(sc);
2441159967Sobrien
2442159967Sobrien	if ((ifp->if_flags & (IFF_ALLMULTI | IFF_PROMISC)) != 0) {
2443159967Sobrien		bzero(addr, ETHER_ADDR_LEN);
2444159967Sobrien		bzero(mask, ETHER_ADDR_LEN);
2445159967Sobrien		goto done;
2446159967Sobrien	}
2447159967Sobrien
2448159967Sobrien	bcopy(etherbroadcastaddr, addr, ETHER_ADDR_LEN);
2449159967Sobrien	bcopy(etherbroadcastaddr, mask, ETHER_ADDR_LEN);
2450159967Sobrien
2451159967Sobrien	IF_ADDR_LOCK(ifp);
2452159967Sobrien	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
2453159967Sobrien		u_char *addrp;
2454159967Sobrien
2455159967Sobrien		if (ifma->ifma_addr->sa_family != AF_LINK)
2456159967Sobrien			continue;
2457159967Sobrien
2458159967Sobrien		addrp = LLADDR((struct sockaddr_dl *) ifma->ifma_addr);
2459159967Sobrien		for (i = 0; i < ETHER_ADDR_LEN; i++) {
2460159967Sobrien			u_int8_t mcaddr = addrp[i];
2461159967Sobrien			addr[i] &= mcaddr;
2462159967Sobrien			mask[i] &= ~mcaddr;
2463159967Sobrien		}
2464159967Sobrien	}
2465159967Sobrien	IF_ADDR_UNLOCK(ifp);
2466159967Sobrien
2467159967Sobrien	for (i = 0; i < ETHER_ADDR_LEN; i++) {
2468159967Sobrien		mask[i] |= addr[i];
2469159967Sobrien	}
2470159967Sobrien
2471159967Sobriendone:
2472159967Sobrien	addr[0] |= 0x01;	/* make sure multicast bit is set */
2473159967Sobrien
2474159967Sobrien	NFE_WRITE(sc, NFE_MULTIADDR_HI,
2475159967Sobrien	    addr[3] << 24 | addr[2] << 16 | addr[1] << 8 | addr[0]);
2476159967Sobrien	NFE_WRITE(sc, NFE_MULTIADDR_LO,
2477159967Sobrien	    addr[5] <<  8 | addr[4]);
2478159967Sobrien	NFE_WRITE(sc, NFE_MULTIMASK_HI,
2479159967Sobrien	    mask[3] << 24 | mask[2] << 16 | mask[1] << 8 | mask[0]);
2480159967Sobrien	NFE_WRITE(sc, NFE_MULTIMASK_LO,
2481159967Sobrien	    mask[5] <<  8 | mask[4]);
2482159967Sobrien
2483170589Syongari	filter = NFE_READ(sc, NFE_RXFILTER);
2484170589Syongari	filter &= NFE_PFF_RX_PAUSE;
2485170589Syongari	filter |= NFE_RXFILTER_MAGIC;
2486170589Syongari	filter |= (ifp->if_flags & IFF_PROMISC) ? NFE_PFF_PROMISC : NFE_PFF_U2M;
2487159967Sobrien	NFE_WRITE(sc, NFE_RXFILTER, filter);
2488159967Sobrien}
2489159967Sobrien
2490163503Sobrien
2491163503Sobrienstatic void
2492170589Syongarinfe_tx_task(void *arg, int pending)
2493159967Sobrien{
2494170589Syongari	struct ifnet *ifp;
2495159967Sobrien
2496170589Syongari	ifp = (struct ifnet *)arg;
2497170589Syongari	nfe_start(ifp);
2498159967Sobrien}
2499159967Sobrien
2500163503Sobrien
2501163503Sobrienstatic void
2502170589Syongarinfe_start(struct ifnet *ifp)
2503159967Sobrien{
2504159952Sobrien	struct nfe_softc *sc = ifp->if_softc;
2505163503Sobrien	struct mbuf *m0;
2506170589Syongari	int enq;
2507159952Sobrien
2508170589Syongari	NFE_LOCK(sc);
2509170589Syongari
2510170589Syongari	if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) !=
2511170589Syongari	    IFF_DRV_RUNNING || sc->nfe_link == 0) {
2512170589Syongari		NFE_UNLOCK(sc);
2513159967Sobrien		return;
2514159967Sobrien	}
2515159967Sobrien
2516170589Syongari	for (enq = 0; !IFQ_DRV_IS_EMPTY(&ifp->if_snd);) {
2517170589Syongari		IFQ_DRV_DEQUEUE(&ifp->if_snd, m0);
2518159952Sobrien		if (m0 == NULL)
2519159952Sobrien			break;
2520159952Sobrien
2521170589Syongari		if (nfe_encap(sc, &m0) != 0) {
2522170589Syongari			if (m0 == NULL)
2523170589Syongari				break;
2524170589Syongari			IFQ_DRV_PREPEND(&ifp->if_snd, m0);
2525159967Sobrien			ifp->if_drv_flags |= IFF_DRV_OACTIVE;
2526159952Sobrien			break;
2527159952Sobrien		}
2528170589Syongari		enq++;
2529167190Scsjp		ETHER_BPF_MTAP(ifp, m0);
2530159952Sobrien	}
2531159952Sobrien
2532170589Syongari	if (enq > 0) {
2533170589Syongari		bus_dmamap_sync(sc->txq.tx_desc_tag, sc->txq.tx_desc_map,
2534170589Syongari		    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
2535159952Sobrien
2536170589Syongari		/* kick Tx */
2537170589Syongari		NFE_WRITE(sc, NFE_RXTX_CTL, NFE_RXTX_KICKTX | sc->rxtxctl);
2538159952Sobrien
2539170589Syongari		/*
2540170589Syongari		 * Set a timeout in case the chip goes out to lunch.
2541170589Syongari		 */
2542170589Syongari		sc->nfe_watchdog_timer = 5;
2543170589Syongari	}
2544159967Sobrien
2545170589Syongari	NFE_UNLOCK(sc);
2546159952Sobrien}
2547159952Sobrien
2548163503Sobrien
2549163503Sobrienstatic void
2550163503Sobriennfe_watchdog(struct ifnet *ifp)
2551159952Sobrien{
2552159952Sobrien	struct nfe_softc *sc = ifp->if_softc;
2553159952Sobrien
2554170589Syongari	if (sc->nfe_watchdog_timer == 0 || --sc->nfe_watchdog_timer)
2555170589Syongari		return;
2556159952Sobrien
2557170589Syongari	/* Check if we've lost Tx completion interrupt. */
2558170589Syongari	nfe_txeof(sc);
2559170589Syongari	if (sc->txq.queued == 0) {
2560170589Syongari		if_printf(ifp, "watchdog timeout (missed Tx interrupts) "
2561170589Syongari		    "-- recovering\n");
2562170589Syongari		if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
2563173674Ssam			taskqueue_enqueue_fast(sc->nfe_tq, &sc->nfe_tx_task);
2564170589Syongari		return;
2565170589Syongari	}
2566170589Syongari	/* Check if we've lost start Tx command. */
2567170589Syongari	sc->nfe_force_tx++;
2568170589Syongari	if (sc->nfe_force_tx <= 3) {
2569170589Syongari		/*
2570170589Syongari		 * If this is the case for watchdog timeout, the following
2571170589Syongari		 * code should go to nfe_txeof().
2572170589Syongari		 */
2573170589Syongari		NFE_WRITE(sc, NFE_RXTX_CTL, NFE_RXTX_KICKTX | sc->rxtxctl);
2574170589Syongari		return;
2575170589Syongari	}
2576170589Syongari	sc->nfe_force_tx = 0;
2577170589Syongari
2578170589Syongari	if_printf(ifp, "watchdog timeout\n");
2579170589Syongari
2580159967Sobrien	ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
2581159952Sobrien	ifp->if_oerrors++;
2582170589Syongari	nfe_init_locked(sc);
2583159952Sobrien}
2584159952Sobrien
2585163503Sobrien
2586163503Sobrienstatic void
2587163503Sobriennfe_init(void *xsc)
2588159952Sobrien{
2589159967Sobrien	struct nfe_softc *sc = xsc;
2590159952Sobrien
2591159967Sobrien	NFE_LOCK(sc);
2592159967Sobrien	nfe_init_locked(sc);
2593159967Sobrien	NFE_UNLOCK(sc);
2594159967Sobrien}
2595159967Sobrien
2596163503Sobrien
2597163503Sobrienstatic void
2598163503Sobriennfe_init_locked(void *xsc)
2599159967Sobrien{
2600159967Sobrien	struct nfe_softc *sc = xsc;
2601159967Sobrien	struct ifnet *ifp = sc->nfe_ifp;
2602159967Sobrien	struct mii_data *mii;
2603170589Syongari	uint32_t val;
2604170589Syongari	int error;
2605159967Sobrien
2606159967Sobrien	NFE_LOCK_ASSERT(sc);
2607159967Sobrien
2608159967Sobrien	mii = device_get_softc(sc->nfe_miibus);
2609159967Sobrien
2610170589Syongari	if (ifp->if_drv_flags & IFF_DRV_RUNNING)
2611159967Sobrien		return;
2612170589Syongari
2613170589Syongari	nfe_stop(ifp);
2614170589Syongari
2615170589Syongari	sc->nfe_framesize = ifp->if_mtu + NFE_RX_HEADERS;
2616170589Syongari
2617170589Syongari	nfe_init_tx_ring(sc, &sc->txq);
2618170589Syongari	if (sc->nfe_framesize > (MCLBYTES - ETHER_HDR_LEN))
2619170589Syongari		error = nfe_init_jrx_ring(sc, &sc->jrxq);
2620170589Syongari	else
2621170589Syongari		error = nfe_init_rx_ring(sc, &sc->rxq);
2622170589Syongari	if (error != 0) {
2623170589Syongari		device_printf(sc->nfe_dev,
2624170589Syongari		    "initialization failed: no memory for rx buffers\n");
2625170589Syongari		nfe_stop(ifp);
2626170589Syongari		return;
2627159967Sobrien	}
2628159967Sobrien
2629170589Syongari	val = 0;
2630170589Syongari	if ((sc->nfe_flags & NFE_CORRECT_MACADDR) != 0)
2631170589Syongari		val |= NFE_MAC_ADDR_INORDER;
2632170589Syongari	NFE_WRITE(sc, NFE_TX_UNK, val);
2633159952Sobrien	NFE_WRITE(sc, NFE_STATUS, 0);
2634159952Sobrien
2635170589Syongari	if ((sc->nfe_flags & NFE_TX_FLOW_CTRL) != 0)
2636170589Syongari		NFE_WRITE(sc, NFE_TX_PAUSE_FRAME, NFE_TX_PAUSE_FRAME_DISABLE);
2637170589Syongari
2638159952Sobrien	sc->rxtxctl = NFE_RXTX_BIT2;
2639159967Sobrien	if (sc->nfe_flags & NFE_40BIT_ADDR)
2640159952Sobrien		sc->rxtxctl |= NFE_RXTX_V3MAGIC;
2641159967Sobrien	else if (sc->nfe_flags & NFE_JUMBO_SUP)
2642159952Sobrien		sc->rxtxctl |= NFE_RXTX_V2MAGIC;
2643164656Sobrien
2644170589Syongari	if ((ifp->if_capenable & IFCAP_RXCSUM) != 0)
2645159952Sobrien		sc->rxtxctl |= NFE_RXTX_RXCSUM;
2646170589Syongari	if ((ifp->if_capenable & IFCAP_VLAN_HWTAGGING) != 0)
2647170589Syongari		sc->rxtxctl |= NFE_RXTX_VTAG_INSERT | NFE_RXTX_VTAG_STRIP;
2648159967Sobrien
2649159952Sobrien	NFE_WRITE(sc, NFE_RXTX_CTL, NFE_RXTX_RESET | sc->rxtxctl);
2650159952Sobrien	DELAY(10);
2651159952Sobrien	NFE_WRITE(sc, NFE_RXTX_CTL, sc->rxtxctl);
2652159952Sobrien
2653170589Syongari	if ((ifp->if_capenable & IFCAP_VLAN_HWTAGGING) != 0)
2654159952Sobrien		NFE_WRITE(sc, NFE_VTAG_CTL, NFE_VTAG_ENABLE);
2655170589Syongari	else
2656170589Syongari		NFE_WRITE(sc, NFE_VTAG_CTL, 0);
2657159952Sobrien
2658159952Sobrien	NFE_WRITE(sc, NFE_SETUP_R6, 0);
2659159952Sobrien
2660159952Sobrien	/* set MAC address */
2661170589Syongari	nfe_set_macaddr(sc, IF_LLADDR(ifp));
2662159952Sobrien
2663159952Sobrien	/* tell MAC where rings are in memory */
2664170589Syongari	if (sc->nfe_framesize > MCLBYTES - ETHER_HDR_LEN) {
2665170589Syongari		NFE_WRITE(sc, NFE_RX_RING_ADDR_HI,
2666170589Syongari		    NFE_ADDR_HI(sc->jrxq.jphysaddr));
2667170589Syongari		NFE_WRITE(sc, NFE_RX_RING_ADDR_LO,
2668170589Syongari		    NFE_ADDR_LO(sc->jrxq.jphysaddr));
2669170589Syongari	} else {
2670170589Syongari		NFE_WRITE(sc, NFE_RX_RING_ADDR_HI,
2671170589Syongari		    NFE_ADDR_HI(sc->rxq.physaddr));
2672170589Syongari		NFE_WRITE(sc, NFE_RX_RING_ADDR_LO,
2673170589Syongari		    NFE_ADDR_LO(sc->rxq.physaddr));
2674170589Syongari	}
2675170589Syongari	NFE_WRITE(sc, NFE_TX_RING_ADDR_HI, NFE_ADDR_HI(sc->txq.physaddr));
2676170589Syongari	NFE_WRITE(sc, NFE_TX_RING_ADDR_LO, NFE_ADDR_LO(sc->txq.physaddr));
2677159952Sobrien
2678159952Sobrien	NFE_WRITE(sc, NFE_RING_SIZE,
2679159952Sobrien	    (NFE_RX_RING_COUNT - 1) << 16 |
2680159952Sobrien	    (NFE_TX_RING_COUNT - 1));
2681159952Sobrien
2682170589Syongari	NFE_WRITE(sc, NFE_RXBUFSZ, sc->nfe_framesize);
2683159952Sobrien
2684159952Sobrien	/* force MAC to wakeup */
2685170589Syongari	val = NFE_READ(sc, NFE_PWR_STATE);
2686170589Syongari	if ((val & NFE_PWR_WAKEUP) == 0)
2687170589Syongari		NFE_WRITE(sc, NFE_PWR_STATE, val | NFE_PWR_WAKEUP);
2688159952Sobrien	DELAY(10);
2689170589Syongari	val = NFE_READ(sc, NFE_PWR_STATE);
2690170589Syongari	NFE_WRITE(sc, NFE_PWR_STATE, val | NFE_PWR_VALID);
2691159952Sobrien
2692159952Sobrien#if 1
2693159952Sobrien	/* configure interrupts coalescing/mitigation */
2694159952Sobrien	NFE_WRITE(sc, NFE_IMTIMER, NFE_IM_DEFAULT);
2695159952Sobrien#else
2696159952Sobrien	/* no interrupt mitigation: one interrupt per packet */
2697159952Sobrien	NFE_WRITE(sc, NFE_IMTIMER, 970);
2698159952Sobrien#endif
2699159952Sobrien
2700170589Syongari	NFE_WRITE(sc, NFE_SETUP_R1, NFE_R1_MAGIC_10_100);
2701159952Sobrien	NFE_WRITE(sc, NFE_SETUP_R2, NFE_R2_MAGIC);
2702159952Sobrien	NFE_WRITE(sc, NFE_SETUP_R6, NFE_R6_MAGIC);
2703159952Sobrien
2704159952Sobrien	/* update MAC knowledge of PHY; generates a NFE_IRQ_LINK interrupt */
2705159952Sobrien	NFE_WRITE(sc, NFE_STATUS, sc->mii_phyaddr << 24 | NFE_STATUS_MAGIC);
2706159952Sobrien
2707159952Sobrien	NFE_WRITE(sc, NFE_SETUP_R4, NFE_R4_MAGIC);
2708159952Sobrien	NFE_WRITE(sc, NFE_WOL_CTL, NFE_WOL_MAGIC);
2709159952Sobrien
2710159952Sobrien	sc->rxtxctl &= ~NFE_RXTX_BIT2;
2711159952Sobrien	NFE_WRITE(sc, NFE_RXTX_CTL, sc->rxtxctl);
2712159952Sobrien	DELAY(10);
2713159952Sobrien	NFE_WRITE(sc, NFE_RXTX_CTL, NFE_RXTX_BIT1 | sc->rxtxctl);
2714159952Sobrien
2715159952Sobrien	/* set Rx filter */
2716159952Sobrien	nfe_setmulti(sc);
2717159952Sobrien
2718159952Sobrien	/* enable Rx */
2719159952Sobrien	NFE_WRITE(sc, NFE_RX_CTL, NFE_RX_START);
2720159952Sobrien
2721159952Sobrien	/* enable Tx */
2722159952Sobrien	NFE_WRITE(sc, NFE_TX_CTL, NFE_TX_START);
2723159952Sobrien
2724159952Sobrien	NFE_WRITE(sc, NFE_PHY_STATUS, 0xf);
2725159952Sobrien
2726159967Sobrien#ifdef DEVICE_POLLING
2727159967Sobrien	if (ifp->if_capenable & IFCAP_POLLING)
2728170589Syongari		nfe_disable_intr(sc);
2729159967Sobrien	else
2730159967Sobrien#endif
2731170589Syongari	nfe_set_intr(sc);
2732170589Syongari	nfe_enable_intr(sc); /* enable interrupts */
2733159952Sobrien
2734159967Sobrien	ifp->if_drv_flags |= IFF_DRV_RUNNING;
2735159967Sobrien	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
2736159952Sobrien
2737159967Sobrien	sc->nfe_link = 0;
2738170589Syongari	mii_mediachg(mii);
2739159952Sobrien
2740170589Syongari	callout_reset(&sc->nfe_stat_ch, hz, nfe_tick, sc);
2741159952Sobrien}
2742159952Sobrien
2743163503Sobrien
2744163503Sobrienstatic void
2745170589Syongarinfe_stop(struct ifnet *ifp)
2746159952Sobrien{
2747159952Sobrien	struct nfe_softc *sc = ifp->if_softc;
2748170589Syongari	struct nfe_rx_ring *rx_ring;
2749170589Syongari	struct nfe_jrx_ring *jrx_ring;
2750170589Syongari	struct nfe_tx_ring *tx_ring;
2751170589Syongari	struct nfe_rx_data *rdata;
2752170589Syongari	struct nfe_tx_data *tdata;
2753170589Syongari	int i;
2754159952Sobrien
2755159967Sobrien	NFE_LOCK_ASSERT(sc);
2756159952Sobrien
2757170589Syongari	sc->nfe_watchdog_timer = 0;
2758159967Sobrien	ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
2759159952Sobrien
2760159967Sobrien	callout_stop(&sc->nfe_stat_ch);
2761159967Sobrien
2762159952Sobrien	/* abort Tx */
2763159952Sobrien	NFE_WRITE(sc, NFE_TX_CTL, 0);
2764159952Sobrien
2765159952Sobrien	/* disable Rx */
2766159952Sobrien	NFE_WRITE(sc, NFE_RX_CTL, 0);
2767159952Sobrien
2768159952Sobrien	/* disable interrupts */
2769170589Syongari	nfe_disable_intr(sc);
2770159952Sobrien
2771159967Sobrien	sc->nfe_link = 0;
2772159967Sobrien
2773170589Syongari	/* free Rx and Tx mbufs still in the queues. */
2774170589Syongari	rx_ring = &sc->rxq;
2775170589Syongari	for (i = 0; i < NFE_RX_RING_COUNT; i++) {
2776170589Syongari		rdata = &rx_ring->data[i];
2777170589Syongari		if (rdata->m != NULL) {
2778170589Syongari			bus_dmamap_sync(rx_ring->rx_data_tag,
2779170589Syongari			    rdata->rx_data_map, BUS_DMASYNC_POSTREAD);
2780170589Syongari			bus_dmamap_unload(rx_ring->rx_data_tag,
2781170589Syongari			    rdata->rx_data_map);
2782170589Syongari			m_freem(rdata->m);
2783170589Syongari			rdata->m = NULL;
2784170589Syongari		}
2785170589Syongari	}
2786159952Sobrien
2787170589Syongari	if ((sc->nfe_flags & NFE_JUMBO_SUP) != 0) {
2788170589Syongari		jrx_ring = &sc->jrxq;
2789170589Syongari		for (i = 0; i < NFE_JUMBO_RX_RING_COUNT; i++) {
2790170589Syongari			rdata = &jrx_ring->jdata[i];
2791170589Syongari			if (rdata->m != NULL) {
2792170589Syongari				bus_dmamap_sync(jrx_ring->jrx_data_tag,
2793170589Syongari				    rdata->rx_data_map, BUS_DMASYNC_POSTREAD);
2794170589Syongari				bus_dmamap_unload(jrx_ring->jrx_data_tag,
2795170589Syongari				    rdata->rx_data_map);
2796170589Syongari				m_freem(rdata->m);
2797170589Syongari				rdata->m = NULL;
2798170589Syongari			}
2799170589Syongari		}
2800170589Syongari	}
2801170589Syongari
2802170589Syongari	tx_ring = &sc->txq;
2803170589Syongari	for (i = 0; i < NFE_RX_RING_COUNT; i++) {
2804170589Syongari		tdata = &tx_ring->data[i];
2805170589Syongari		if (tdata->m != NULL) {
2806170589Syongari			bus_dmamap_sync(tx_ring->tx_data_tag,
2807170589Syongari			    tdata->tx_data_map, BUS_DMASYNC_POSTWRITE);
2808170589Syongari			bus_dmamap_unload(tx_ring->tx_data_tag,
2809170589Syongari			    tdata->tx_data_map);
2810170589Syongari			m_freem(tdata->m);
2811170589Syongari			tdata->m = NULL;
2812170589Syongari		}
2813170589Syongari	}
2814159952Sobrien}
2815159952Sobrien
2816163503Sobrien
2817163503Sobrienstatic int
2818163503Sobriennfe_ifmedia_upd(struct ifnet *ifp)
2819159952Sobrien{
2820159967Sobrien	struct nfe_softc *sc = ifp->if_softc;
2821170589Syongari	struct mii_data *mii;
2822159952Sobrien
2823159967Sobrien	NFE_LOCK(sc);
2824159967Sobrien	mii = device_get_softc(sc->nfe_miibus);
2825159967Sobrien	mii_mediachg(mii);
2826170589Syongari	NFE_UNLOCK(sc);
2827159967Sobrien
2828159967Sobrien	return (0);
2829159952Sobrien}
2830159952Sobrien
2831163503Sobrien
2832163503Sobrienstatic void
2833163503Sobriennfe_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
2834159952Sobrien{
2835163503Sobrien	struct nfe_softc *sc;
2836163503Sobrien	struct mii_data *mii;
2837159952Sobrien
2838159967Sobrien	sc = ifp->if_softc;
2839159952Sobrien
2840159967Sobrien	NFE_LOCK(sc);
2841159967Sobrien	mii = device_get_softc(sc->nfe_miibus);
2842159967Sobrien	mii_pollstat(mii);
2843159967Sobrien	NFE_UNLOCK(sc);
2844159952Sobrien
2845159967Sobrien	ifmr->ifm_active = mii->mii_media_active;
2846159967Sobrien	ifmr->ifm_status = mii->mii_media_status;
2847159952Sobrien}
2848159952Sobrien
2849163503Sobrien
2850170589Syongarivoid
2851159967Sobriennfe_tick(void *xsc)
2852159952Sobrien{
2853159967Sobrien	struct nfe_softc *sc;
2854163503Sobrien	struct mii_data *mii;
2855163503Sobrien	struct ifnet *ifp;
2856159952Sobrien
2857170589Syongari	sc = (struct nfe_softc *)xsc;
2858159952Sobrien
2859163503Sobrien	NFE_LOCK_ASSERT(sc);
2860159952Sobrien
2861159967Sobrien	ifp = sc->nfe_ifp;
2862159952Sobrien
2863159967Sobrien	mii = device_get_softc(sc->nfe_miibus);
2864159967Sobrien	mii_tick(mii);
2865170589Syongari	nfe_watchdog(ifp);
2866159967Sobrien	callout_reset(&sc->nfe_stat_ch, hz, nfe_tick, sc);
2867159952Sobrien}
2868159952Sobrien
2869159952Sobrien
2870173839Syongaristatic int
2871163503Sobriennfe_shutdown(device_t dev)
2872159952Sobrien{
2873159967Sobrien	struct nfe_softc *sc;
2874159967Sobrien	struct ifnet *ifp;
2875159952Sobrien
2876159967Sobrien	sc = device_get_softc(dev);
2877159952Sobrien
2878159967Sobrien	NFE_LOCK(sc);
2879159967Sobrien	ifp = sc->nfe_ifp;
2880170589Syongari	nfe_stop(ifp);
2881159967Sobrien	/* nfe_reset(sc); */
2882159967Sobrien	NFE_UNLOCK(sc);
2883173839Syongari
2884173839Syongari	return (0);
2885159952Sobrien}
2886159952Sobrien
2887159952Sobrien
2888163503Sobrienstatic void
2889170589Syongarinfe_get_macaddr(struct nfe_softc *sc, uint8_t *addr)
2890159952Sobrien{
2891170589Syongari	uint32_t val;
2892159952Sobrien
2893170589Syongari	if ((sc->nfe_flags & NFE_CORRECT_MACADDR) == 0) {
2894170589Syongari		val = NFE_READ(sc, NFE_MACADDR_LO);
2895170589Syongari		addr[0] = (val >> 8) & 0xff;
2896170589Syongari		addr[1] = (val & 0xff);
2897159952Sobrien
2898170589Syongari		val = NFE_READ(sc, NFE_MACADDR_HI);
2899170589Syongari		addr[2] = (val >> 24) & 0xff;
2900170589Syongari		addr[3] = (val >> 16) & 0xff;
2901170589Syongari		addr[4] = (val >>  8) & 0xff;
2902170589Syongari		addr[5] = (val & 0xff);
2903170589Syongari	} else {
2904170589Syongari		val = NFE_READ(sc, NFE_MACADDR_LO);
2905170589Syongari		addr[5] = (val >> 8) & 0xff;
2906170589Syongari		addr[4] = (val & 0xff);
2907170589Syongari
2908170589Syongari		val = NFE_READ(sc, NFE_MACADDR_HI);
2909170589Syongari		addr[3] = (val >> 24) & 0xff;
2910170589Syongari		addr[2] = (val >> 16) & 0xff;
2911170589Syongari		addr[1] = (val >>  8) & 0xff;
2912170589Syongari		addr[0] = (val & 0xff);
2913170589Syongari	}
2914159952Sobrien}
2915159952Sobrien
2916163503Sobrien
2917163503Sobrienstatic void
2918170589Syongarinfe_set_macaddr(struct nfe_softc *sc, uint8_t *addr)
2919159952Sobrien{
2920159967Sobrien
2921159967Sobrien	NFE_WRITE(sc, NFE_MACADDR_LO, addr[5] <<  8 | addr[4]);
2922159967Sobrien	NFE_WRITE(sc, NFE_MACADDR_HI, addr[3] << 24 | addr[2] << 16 |
2923159967Sobrien	    addr[1] << 8 | addr[0]);
2924159952Sobrien}
2925159952Sobrien
2926163503Sobrien
2927159967Sobrien/*
2928159967Sobrien * Map a single buffer address.
2929159967Sobrien */
2930159967Sobrien
2931159967Sobrienstatic void
2932170589Syongarinfe_dma_map_segs(void *arg, bus_dma_segment_t *segs, int nseg, int error)
2933159952Sobrien{
2934170589Syongari	struct nfe_dmamap_arg *ctx;
2935159952Sobrien
2936170589Syongari	if (error != 0)
2937159967Sobrien		return;
2938159952Sobrien
2939159967Sobrien	KASSERT(nseg == 1, ("too many DMA segments, %d should be 1", nseg));
2940159967Sobrien
2941170589Syongari	ctx = (struct nfe_dmamap_arg *)arg;
2942170589Syongari	ctx->nfe_busaddr = segs[0].ds_addr;
2943170589Syongari}
2944159967Sobrien
2945170589Syongari
2946170589Syongaristatic int
2947170589Syongarisysctl_int_range(SYSCTL_HANDLER_ARGS, int low, int high)
2948170589Syongari{
2949170589Syongari	int error, value;
2950170589Syongari
2951170589Syongari	if (!arg1)
2952170589Syongari		return (EINVAL);
2953170589Syongari	value = *(int *)arg1;
2954170589Syongari	error = sysctl_handle_int(oidp, &value, 0, req);
2955170589Syongari	if (error || !req->newptr)
2956170589Syongari		return (error);
2957170589Syongari	if (value < low || value > high)
2958170589Syongari		return (EINVAL);
2959170589Syongari	*(int *)arg1 = value;
2960170589Syongari
2961170589Syongari	return (0);
2962159952Sobrien}
2963170589Syongari
2964170589Syongari
2965170589Syongaristatic int
2966170589Syongarisysctl_hw_nfe_proc_limit(SYSCTL_HANDLER_ARGS)
2967170589Syongari{
2968170589Syongari
2969170589Syongari	return (sysctl_int_range(oidp, arg1, arg2, req, NFE_PROC_MIN,
2970170589Syongari	    NFE_PROC_MAX));
2971170589Syongari}
2972