if_nfe.c revision 221407
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 221407 2011-05-03 19:51:29Z marius $");
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);
80215327Syongaristatic int  nfe_can_use_msix(struct nfe_softc *);
81170589Syongaristatic void nfe_power(struct nfe_softc *);
82163503Sobrienstatic int  nfe_miibus_readreg(device_t, int, int);
83163503Sobrienstatic int  nfe_miibus_writereg(device_t, int, int, int);
84163503Sobrienstatic void nfe_miibus_statchg(device_t);
85215132Syongaristatic void nfe_mac_config(struct nfe_softc *, struct mii_data *);
86170589Syongaristatic void nfe_set_intr(struct nfe_softc *);
87170589Syongaristatic __inline void nfe_enable_intr(struct nfe_softc *);
88170589Syongaristatic __inline void nfe_disable_intr(struct nfe_softc *);
89163503Sobrienstatic int  nfe_ioctl(struct ifnet *, u_long, caddr_t);
90170589Syongaristatic void nfe_alloc_msix(struct nfe_softc *, int);
91170589Syongaristatic int nfe_intr(void *);
92170589Syongaristatic void nfe_int_task(void *, int);
93170589Syongaristatic __inline void nfe_discard_rxbuf(struct nfe_softc *, int);
94170589Syongaristatic __inline void nfe_discard_jrxbuf(struct nfe_softc *, int);
95170589Syongaristatic int nfe_newbuf(struct nfe_softc *, int);
96170589Syongaristatic int nfe_jnewbuf(struct nfe_softc *, int);
97193096Sattiliostatic int  nfe_rxeof(struct nfe_softc *, int, int *);
98193096Sattiliostatic int  nfe_jrxeof(struct nfe_softc *, int, int *);
99159967Sobrienstatic void nfe_txeof(struct nfe_softc *);
100170589Syongaristatic int  nfe_encap(struct nfe_softc *, struct mbuf **);
101159967Sobrienstatic void nfe_setmulti(struct nfe_softc *);
102159967Sobrienstatic void nfe_start(struct ifnet *);
103216925Sjhbstatic void nfe_start_locked(struct ifnet *);
104159967Sobrienstatic void nfe_watchdog(struct ifnet *);
105159967Sobrienstatic void nfe_init(void *);
106159967Sobrienstatic void nfe_init_locked(void *);
107170589Syongaristatic void nfe_stop(struct ifnet *);
108159967Sobrienstatic int  nfe_alloc_rx_ring(struct nfe_softc *, struct nfe_rx_ring *);
109171559Syongaristatic void nfe_alloc_jrx_ring(struct nfe_softc *, struct nfe_jrx_ring *);
110170589Syongaristatic int  nfe_init_rx_ring(struct nfe_softc *, struct nfe_rx_ring *);
111170589Syongaristatic int  nfe_init_jrx_ring(struct nfe_softc *, struct nfe_jrx_ring *);
112159967Sobrienstatic void nfe_free_rx_ring(struct nfe_softc *, struct nfe_rx_ring *);
113170589Syongaristatic void nfe_free_jrx_ring(struct nfe_softc *, struct nfe_jrx_ring *);
114159967Sobrienstatic int  nfe_alloc_tx_ring(struct nfe_softc *, struct nfe_tx_ring *);
115170589Syongaristatic void nfe_init_tx_ring(struct nfe_softc *, struct nfe_tx_ring *);
116159967Sobrienstatic void nfe_free_tx_ring(struct nfe_softc *, struct nfe_tx_ring *);
117159967Sobrienstatic int  nfe_ifmedia_upd(struct ifnet *);
118159967Sobrienstatic void nfe_ifmedia_sts(struct ifnet *, struct ifmediareq *);
119159967Sobrienstatic void nfe_tick(void *);
120170589Syongaristatic void nfe_get_macaddr(struct nfe_softc *, uint8_t *);
121170589Syongaristatic void nfe_set_macaddr(struct nfe_softc *, uint8_t *);
122170589Syongaristatic void nfe_dma_map_segs(void *, bus_dma_segment_t *, int, int);
123159952Sobrien
124170589Syongaristatic int sysctl_int_range(SYSCTL_HANDLER_ARGS, int, int);
125170589Syongaristatic int sysctl_hw_nfe_proc_limit(SYSCTL_HANDLER_ARGS);
126183561Syongaristatic void nfe_sysctl_node(struct nfe_softc *);
127183561Syongaristatic void nfe_stats_clear(struct nfe_softc *);
128183561Syongaristatic void nfe_stats_update(struct nfe_softc *);
129215132Syongaristatic void nfe_set_linkspeed(struct nfe_softc *);
130215132Syongaristatic void nfe_set_wol(struct nfe_softc *);
131170589Syongari
132159952Sobrien#ifdef NFE_DEBUG
133170589Syongaristatic int nfedebug = 0;
134170589Syongari#define	DPRINTF(sc, ...)	do {				\
135170589Syongari	if (nfedebug)						\
136170589Syongari		device_printf((sc)->nfe_dev, __VA_ARGS__);	\
137170589Syongari} while (0)
138170589Syongari#define	DPRINTFN(sc, n, ...)	do {				\
139170589Syongari	if (nfedebug >= (n))					\
140170589Syongari		device_printf((sc)->nfe_dev, __VA_ARGS__);	\
141170589Syongari} while (0)
142159952Sobrien#else
143170589Syongari#define	DPRINTF(sc, ...)
144170589Syongari#define	DPRINTFN(sc, n, ...)
145159952Sobrien#endif
146159952Sobrien
147159967Sobrien#define	NFE_LOCK(_sc)		mtx_lock(&(_sc)->nfe_mtx)
148159967Sobrien#define	NFE_UNLOCK(_sc)		mtx_unlock(&(_sc)->nfe_mtx)
149159967Sobrien#define	NFE_LOCK_ASSERT(_sc)	mtx_assert(&(_sc)->nfe_mtx, MA_OWNED)
150159967Sobrien
151170589Syongari/* Tunables. */
152170589Syongaristatic int msi_disable = 0;
153170589Syongaristatic int msix_disable = 0;
154171559Syongaristatic int jumbo_disable = 0;
155170589SyongariTUNABLE_INT("hw.nfe.msi_disable", &msi_disable);
156170589SyongariTUNABLE_INT("hw.nfe.msix_disable", &msix_disable);
157171559SyongariTUNABLE_INT("hw.nfe.jumbo_disable", &jumbo_disable);
158159967Sobrien
159159967Sobrienstatic device_method_t nfe_methods[] = {
160159967Sobrien	/* Device interface */
161159967Sobrien	DEVMETHOD(device_probe,		nfe_probe),
162159967Sobrien	DEVMETHOD(device_attach,	nfe_attach),
163159967Sobrien	DEVMETHOD(device_detach,	nfe_detach),
164170589Syongari	DEVMETHOD(device_suspend,	nfe_suspend),
165170589Syongari	DEVMETHOD(device_resume,	nfe_resume),
166159967Sobrien	DEVMETHOD(device_shutdown,	nfe_shutdown),
167159967Sobrien
168159967Sobrien	/* bus interface */
169159967Sobrien	DEVMETHOD(bus_print_child,	bus_generic_print_child),
170159967Sobrien	DEVMETHOD(bus_driver_added,	bus_generic_driver_added),
171159967Sobrien
172159967Sobrien	/* MII interface */
173159967Sobrien	DEVMETHOD(miibus_readreg,	nfe_miibus_readreg),
174159967Sobrien	DEVMETHOD(miibus_writereg,	nfe_miibus_writereg),
175163503Sobrien	DEVMETHOD(miibus_statchg,	nfe_miibus_statchg),
176159967Sobrien
177170589Syongari	{ NULL, NULL }
178159952Sobrien};
179159952Sobrien
180159967Sobrienstatic driver_t nfe_driver = {
181159967Sobrien	"nfe",
182159967Sobrien	nfe_methods,
183159967Sobrien	sizeof(struct nfe_softc)
184159967Sobrien};
185159967Sobrien
186159967Sobrienstatic devclass_t nfe_devclass;
187159967Sobrien
188159967SobrienDRIVER_MODULE(nfe, pci, nfe_driver, nfe_devclass, 0, 0);
189159967SobrienDRIVER_MODULE(miibus, nfe, miibus_driver, miibus_devclass, 0, 0);
190159967Sobrien
191159967Sobrienstatic struct nfe_type nfe_devs[] = {
192159967Sobrien	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE_LAN,
193163503Sobrien	    "NVIDIA nForce MCP Networking Adapter"},
194159967Sobrien	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE2_LAN,
195163503Sobrien	    "NVIDIA nForce2 MCP2 Networking Adapter"},
196159967Sobrien	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE2_400_LAN1,
197163503Sobrien	    "NVIDIA nForce2 400 MCP4 Networking Adapter"},
198159967Sobrien	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE2_400_LAN2,
199163503Sobrien	    "NVIDIA nForce2 400 MCP5 Networking Adapter"},
200163437Sobrien	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE3_LAN1,
201163503Sobrien	    "NVIDIA nForce3 MCP3 Networking Adapter"},
202159967Sobrien	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE3_250_LAN,
203163503Sobrien	    "NVIDIA nForce3 250 MCP6 Networking Adapter"},
204159967Sobrien	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE3_LAN4,
205163503Sobrien	    "NVIDIA nForce3 MCP7 Networking Adapter"},
206159967Sobrien	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE4_LAN1,
207163503Sobrien	    "NVIDIA nForce4 CK804 MCP8 Networking Adapter"},
208159967Sobrien	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE4_LAN2,
209163503Sobrien	    "NVIDIA nForce4 CK804 MCP9 Networking Adapter"},
210159967Sobrien	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP04_LAN1,
211170589Syongari	    "NVIDIA nForce MCP04 Networking Adapter"},		/* MCP10 */
212159967Sobrien	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP04_LAN2,
213170589Syongari	    "NVIDIA nForce MCP04 Networking Adapter"},		/* MCP11 */
214159967Sobrien	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE430_LAN1,
215163503Sobrien	    "NVIDIA nForce 430 MCP12 Networking Adapter"},
216159967Sobrien	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE430_LAN2,
217163503Sobrien	    "NVIDIA nForce 430 MCP13 Networking Adapter"},
218159967Sobrien	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP55_LAN1,
219163503Sobrien	    "NVIDIA nForce MCP55 Networking Adapter"},
220159967Sobrien	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP55_LAN2,
221163503Sobrien	    "NVIDIA nForce MCP55 Networking Adapter"},
222162212Sobrien	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP61_LAN1,
223163503Sobrien	    "NVIDIA nForce MCP61 Networking Adapter"},
224162212Sobrien	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP61_LAN2,
225163503Sobrien	    "NVIDIA nForce MCP61 Networking Adapter"},
226162212Sobrien	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP61_LAN3,
227163503Sobrien	    "NVIDIA nForce MCP61 Networking Adapter"},
228170589Syongari	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP61_LAN4,
229163503Sobrien	    "NVIDIA nForce MCP61 Networking Adapter"},
230162212Sobrien	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP65_LAN1,
231163503Sobrien	    "NVIDIA nForce MCP65 Networking Adapter"},
232162212Sobrien	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP65_LAN2,
233163503Sobrien	    "NVIDIA nForce MCP65 Networking Adapter"},
234162212Sobrien	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP65_LAN3,
235163503Sobrien	    "NVIDIA nForce MCP65 Networking Adapter"},
236170589Syongari	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP65_LAN4,
237163503Sobrien	    "NVIDIA nForce MCP65 Networking Adapter"},
238170589Syongari	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP67_LAN1,
239170589Syongari	    "NVIDIA nForce MCP67 Networking Adapter"},
240170589Syongari	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP67_LAN2,
241170589Syongari	    "NVIDIA nForce MCP67 Networking Adapter"},
242170589Syongari	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP67_LAN3,
243170589Syongari	    "NVIDIA nForce MCP67 Networking Adapter"},
244170589Syongari	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP67_LAN4,
245170589Syongari	    "NVIDIA nForce MCP67 Networking Adapter"},
246178055Syongari	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP73_LAN1,
247178055Syongari	    "NVIDIA nForce MCP73 Networking Adapter"},
248178055Syongari	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP73_LAN2,
249178055Syongari	    "NVIDIA nForce MCP73 Networking Adapter"},
250178055Syongari	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP73_LAN3,
251178055Syongari	    "NVIDIA nForce MCP73 Networking Adapter"},
252178055Syongari	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP73_LAN4,
253178055Syongari	    "NVIDIA nForce MCP73 Networking Adapter"},
254183509Syongari	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP77_LAN1,
255183509Syongari	    "NVIDIA nForce MCP77 Networking Adapter"},
256183509Syongari	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP77_LAN2,
257183509Syongari	    "NVIDIA nForce MCP77 Networking Adapter"},
258183509Syongari	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP77_LAN3,
259183509Syongari	    "NVIDIA nForce MCP77 Networking Adapter"},
260183509Syongari	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP77_LAN4,
261183509Syongari	    "NVIDIA nForce MCP77 Networking Adapter"},
262183509Syongari	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP79_LAN1,
263183509Syongari	    "NVIDIA nForce MCP79 Networking Adapter"},
264183509Syongari	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP79_LAN2,
265183509Syongari	    "NVIDIA nForce MCP79 Networking Adapter"},
266183509Syongari	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP79_LAN3,
267183509Syongari	    "NVIDIA nForce MCP79 Networking Adapter"},
268183509Syongari	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP79_LAN4,
269183509Syongari	    "NVIDIA nForce MCP79 Networking Adapter"},
270159967Sobrien	{0, 0, NULL}
271159967Sobrien};
272159967Sobrien
273159967Sobrien
274159967Sobrien/* Probe for supported hardware ID's */
275159967Sobrienstatic int
276159967Sobriennfe_probe(device_t dev)
277159952Sobrien{
278159967Sobrien	struct nfe_type *t;
279159967Sobrien
280159967Sobrien	t = nfe_devs;
281159967Sobrien	/* Check for matching PCI DEVICE ID's */
282159967Sobrien	while (t->name != NULL) {
283159967Sobrien		if ((pci_get_vendor(dev) == t->vid_id) &&
284159967Sobrien		    (pci_get_device(dev) == t->dev_id)) {
285159967Sobrien			device_set_desc(dev, t->name);
286170589Syongari			return (BUS_PROBE_DEFAULT);
287159967Sobrien		}
288159967Sobrien		t++;
289159967Sobrien	}
290159967Sobrien
291159967Sobrien	return (ENXIO);
292159952Sobrien}
293159952Sobrien
294170589Syongaristatic void
295170589Syongarinfe_alloc_msix(struct nfe_softc *sc, int count)
296170589Syongari{
297170589Syongari	int rid;
298163503Sobrien
299170589Syongari	rid = PCIR_BAR(2);
300170589Syongari	sc->nfe_msix_res = bus_alloc_resource_any(sc->nfe_dev, SYS_RES_MEMORY,
301170589Syongari	    &rid, RF_ACTIVE);
302170589Syongari	if (sc->nfe_msix_res == NULL) {
303170589Syongari		device_printf(sc->nfe_dev,
304170589Syongari		    "couldn't allocate MSIX table resource\n");
305170589Syongari		return;
306170589Syongari	}
307170589Syongari	rid = PCIR_BAR(3);
308170589Syongari	sc->nfe_msix_pba_res = bus_alloc_resource_any(sc->nfe_dev,
309170589Syongari	    SYS_RES_MEMORY, &rid, RF_ACTIVE);
310170589Syongari	if (sc->nfe_msix_pba_res == NULL) {
311170589Syongari		device_printf(sc->nfe_dev,
312170589Syongari		    "couldn't allocate MSIX PBA resource\n");
313170589Syongari		bus_release_resource(sc->nfe_dev, SYS_RES_MEMORY, PCIR_BAR(2),
314170589Syongari		    sc->nfe_msix_res);
315170589Syongari		sc->nfe_msix_res = NULL;
316170589Syongari		return;
317170589Syongari	}
318170589Syongari
319170589Syongari	if (pci_alloc_msix(sc->nfe_dev, &count) == 0) {
320170589Syongari		if (count == NFE_MSI_MESSAGES) {
321170589Syongari			if (bootverbose)
322170589Syongari				device_printf(sc->nfe_dev,
323170589Syongari				    "Using %d MSIX messages\n", count);
324170589Syongari			sc->nfe_msix = 1;
325170589Syongari		} else {
326170589Syongari			if (bootverbose)
327170589Syongari				device_printf(sc->nfe_dev,
328170589Syongari				    "couldn't allocate MSIX\n");
329170589Syongari			pci_release_msi(sc->nfe_dev);
330170589Syongari			bus_release_resource(sc->nfe_dev, SYS_RES_MEMORY,
331170589Syongari			    PCIR_BAR(3), sc->nfe_msix_pba_res);
332170589Syongari			bus_release_resource(sc->nfe_dev, SYS_RES_MEMORY,
333170589Syongari			    PCIR_BAR(2), sc->nfe_msix_res);
334170589Syongari			sc->nfe_msix_pba_res = NULL;
335170589Syongari			sc->nfe_msix_res = NULL;
336170589Syongari		}
337170589Syongari	}
338170589Syongari}
339170589Syongari
340159967Sobrienstatic int
341159967Sobriennfe_attach(device_t dev)
342159952Sobrien{
343159967Sobrien	struct nfe_softc *sc;
344159952Sobrien	struct ifnet *ifp;
345170589Syongari	bus_addr_t dma_addr_max;
346170589Syongari	int error = 0, i, msic, reg, rid;
347159952Sobrien
348159967Sobrien	sc = device_get_softc(dev);
349159967Sobrien	sc->nfe_dev = dev;
350159952Sobrien
351159967Sobrien	mtx_init(&sc->nfe_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK,
352170589Syongari	    MTX_DEF);
353159967Sobrien	callout_init_mtx(&sc->nfe_stat_ch, &sc->nfe_mtx, 0);
354159967Sobrien
355163503Sobrien	pci_enable_busmaster(dev);
356159967Sobrien
357170589Syongari	rid = PCIR_BAR(0);
358170589Syongari	sc->nfe_res[0] = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
359170589Syongari	    RF_ACTIVE);
360170589Syongari	if (sc->nfe_res[0] == NULL) {
361170589Syongari		device_printf(dev, "couldn't map memory resources\n");
362170589Syongari		mtx_destroy(&sc->nfe_mtx);
363170589Syongari		return (ENXIO);
364170589Syongari	}
365159967Sobrien
366219902Sjhb	if (pci_find_cap(dev, PCIY_EXPRESS, &reg) == 0) {
367170589Syongari		uint16_t v, width;
368170589Syongari
369170589Syongari		v = pci_read_config(dev, reg + 0x08, 2);
370170589Syongari		/* Change max. read request size to 4096. */
371170589Syongari		v &= ~(7 << 12);
372170589Syongari		v |= (5 << 12);
373170589Syongari		pci_write_config(dev, reg + 0x08, v, 2);
374170589Syongari
375170589Syongari		v = pci_read_config(dev, reg + 0x0c, 2);
376170589Syongari		/* link capability */
377170589Syongari		v = (v >> 4) & 0x0f;
378170589Syongari		width = pci_read_config(dev, reg + 0x12, 2);
379170589Syongari		/* negotiated link width */
380170589Syongari		width = (width >> 4) & 0x3f;
381170589Syongari		if (v != width)
382170589Syongari			device_printf(sc->nfe_dev,
383170589Syongari			    "warning, negotiated width of link(x%d) != "
384170589Syongari			    "max. width of link(x%d)\n", width, v);
385159952Sobrien	}
386159952Sobrien
387215327Syongari	if (nfe_can_use_msix(sc) == 0) {
388215327Syongari		device_printf(sc->nfe_dev,
389215327Syongari		    "MSI/MSI-X capability black-listed, will use INTx\n");
390215327Syongari		msix_disable = 1;
391215327Syongari		msi_disable = 1;
392215327Syongari	}
393215327Syongari
394159967Sobrien	/* Allocate interrupt */
395170589Syongari	if (msix_disable == 0 || msi_disable == 0) {
396170589Syongari		if (msix_disable == 0 &&
397170589Syongari		    (msic = pci_msix_count(dev)) == NFE_MSI_MESSAGES)
398170589Syongari			nfe_alloc_msix(sc, msic);
399170589Syongari		if (msi_disable == 0 && sc->nfe_msix == 0 &&
400170589Syongari		    (msic = pci_msi_count(dev)) == NFE_MSI_MESSAGES &&
401170589Syongari		    pci_alloc_msi(dev, &msic) == 0) {
402170589Syongari			if (msic == NFE_MSI_MESSAGES) {
403170589Syongari				if (bootverbose)
404170589Syongari					device_printf(dev,
405170589Syongari					    "Using %d MSI messages\n", msic);
406170589Syongari				sc->nfe_msi = 1;
407170589Syongari			} else
408170589Syongari				pci_release_msi(dev);
409170589Syongari		}
410170589Syongari	}
411159967Sobrien
412170589Syongari	if (sc->nfe_msix == 0 && sc->nfe_msi == 0) {
413170589Syongari		rid = 0;
414170589Syongari		sc->nfe_irq[0] = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
415170589Syongari		    RF_SHAREABLE | RF_ACTIVE);
416170589Syongari		if (sc->nfe_irq[0] == NULL) {
417170589Syongari			device_printf(dev, "couldn't allocate IRQ resources\n");
418170589Syongari			error = ENXIO;
419170589Syongari			goto fail;
420170589Syongari		}
421170589Syongari	} else {
422170589Syongari		for (i = 0, rid = 1; i < NFE_MSI_MESSAGES; i++, rid++) {
423170589Syongari			sc->nfe_irq[i] = bus_alloc_resource_any(dev,
424170589Syongari			    SYS_RES_IRQ, &rid, RF_ACTIVE);
425170589Syongari			if (sc->nfe_irq[i] == NULL) {
426170589Syongari				device_printf(dev,
427170589Syongari				    "couldn't allocate IRQ resources for "
428170589Syongari				    "message %d\n", rid);
429170589Syongari				error = ENXIO;
430170589Syongari				goto fail;
431170589Syongari			}
432170589Syongari		}
433170589Syongari		/* Map interrupts to vector 0. */
434170589Syongari		if (sc->nfe_msix != 0) {
435170589Syongari			NFE_WRITE(sc, NFE_MSIX_MAP0, 0);
436170589Syongari			NFE_WRITE(sc, NFE_MSIX_MAP1, 0);
437170589Syongari		} else if (sc->nfe_msi != 0) {
438170589Syongari			NFE_WRITE(sc, NFE_MSI_MAP0, 0);
439170589Syongari			NFE_WRITE(sc, NFE_MSI_MAP1, 0);
440170589Syongari		}
441159952Sobrien	}
442159952Sobrien
443170589Syongari	/* Set IRQ status/mask register. */
444170589Syongari	sc->nfe_irq_status = NFE_IRQ_STATUS;
445170589Syongari	sc->nfe_irq_mask = NFE_IRQ_MASK;
446170589Syongari	sc->nfe_intrs = NFE_IRQ_WANTED;
447170589Syongari	sc->nfe_nointrs = 0;
448170589Syongari	if (sc->nfe_msix != 0) {
449170589Syongari		sc->nfe_irq_status = NFE_MSIX_IRQ_STATUS;
450170589Syongari		sc->nfe_nointrs = NFE_IRQ_WANTED;
451170589Syongari	} else if (sc->nfe_msi != 0) {
452170589Syongari		sc->nfe_irq_mask = NFE_MSI_IRQ_MASK;
453170589Syongari		sc->nfe_intrs = NFE_MSI_VECTOR_0_ENABLED;
454170589Syongari	}
455159952Sobrien
456170589Syongari	sc->nfe_devid = pci_get_device(dev);
457170589Syongari	sc->nfe_revid = pci_get_revid(dev);
458159967Sobrien	sc->nfe_flags = 0;
459159952Sobrien
460170589Syongari	switch (sc->nfe_devid) {
461159952Sobrien	case PCI_PRODUCT_NVIDIA_NFORCE3_LAN2:
462159952Sobrien	case PCI_PRODUCT_NVIDIA_NFORCE3_LAN3:
463159952Sobrien	case PCI_PRODUCT_NVIDIA_NFORCE3_LAN4:
464159952Sobrien	case PCI_PRODUCT_NVIDIA_NFORCE3_LAN5:
465159967Sobrien		sc->nfe_flags |= NFE_JUMBO_SUP | NFE_HW_CSUM;
466159952Sobrien		break;
467159952Sobrien	case PCI_PRODUCT_NVIDIA_MCP51_LAN1:
468159952Sobrien	case PCI_PRODUCT_NVIDIA_MCP51_LAN2:
469183561Syongari		sc->nfe_flags |= NFE_40BIT_ADDR | NFE_PWR_MGMT | NFE_MIB_V1;
470159952Sobrien		break;
471159952Sobrien	case PCI_PRODUCT_NVIDIA_CK804_LAN1:
472159952Sobrien	case PCI_PRODUCT_NVIDIA_CK804_LAN2:
473159952Sobrien	case PCI_PRODUCT_NVIDIA_MCP04_LAN1:
474159952Sobrien	case PCI_PRODUCT_NVIDIA_MCP04_LAN2:
475183561Syongari		sc->nfe_flags |= NFE_JUMBO_SUP | NFE_40BIT_ADDR | NFE_HW_CSUM |
476183561Syongari		    NFE_MIB_V1;
477159952Sobrien		break;
478159952Sobrien	case PCI_PRODUCT_NVIDIA_MCP55_LAN1:
479159952Sobrien	case PCI_PRODUCT_NVIDIA_MCP55_LAN2:
480163503Sobrien		sc->nfe_flags |= NFE_JUMBO_SUP | NFE_40BIT_ADDR | NFE_HW_CSUM |
481183561Syongari		    NFE_HW_VLAN | NFE_PWR_MGMT | NFE_TX_FLOW_CTRL | NFE_MIB_V2;
482159952Sobrien		break;
483170589Syongari
484162212Sobrien	case PCI_PRODUCT_NVIDIA_MCP61_LAN1:
485162212Sobrien	case PCI_PRODUCT_NVIDIA_MCP61_LAN2:
486162212Sobrien	case PCI_PRODUCT_NVIDIA_MCP61_LAN3:
487162212Sobrien	case PCI_PRODUCT_NVIDIA_MCP61_LAN4:
488170589Syongari	case PCI_PRODUCT_NVIDIA_MCP67_LAN1:
489170589Syongari	case PCI_PRODUCT_NVIDIA_MCP67_LAN2:
490170589Syongari	case PCI_PRODUCT_NVIDIA_MCP67_LAN3:
491170589Syongari	case PCI_PRODUCT_NVIDIA_MCP67_LAN4:
492178055Syongari	case PCI_PRODUCT_NVIDIA_MCP73_LAN1:
493178055Syongari	case PCI_PRODUCT_NVIDIA_MCP73_LAN2:
494178055Syongari	case PCI_PRODUCT_NVIDIA_MCP73_LAN3:
495178055Syongari	case PCI_PRODUCT_NVIDIA_MCP73_LAN4:
496170589Syongari		sc->nfe_flags |= NFE_40BIT_ADDR | NFE_PWR_MGMT |
497183561Syongari		    NFE_CORRECT_MACADDR | NFE_TX_FLOW_CTRL | NFE_MIB_V2;
498162212Sobrien		break;
499183509Syongari	case PCI_PRODUCT_NVIDIA_MCP77_LAN1:
500183509Syongari	case PCI_PRODUCT_NVIDIA_MCP77_LAN2:
501183509Syongari	case PCI_PRODUCT_NVIDIA_MCP77_LAN3:
502183509Syongari	case PCI_PRODUCT_NVIDIA_MCP77_LAN4:
503183509Syongari		/* XXX flow control */
504183509Syongari		sc->nfe_flags |= NFE_40BIT_ADDR | NFE_HW_CSUM | NFE_PWR_MGMT |
505183561Syongari		    NFE_CORRECT_MACADDR | NFE_MIB_V3;
506183509Syongari		break;
507183509Syongari	case PCI_PRODUCT_NVIDIA_MCP79_LAN1:
508183509Syongari	case PCI_PRODUCT_NVIDIA_MCP79_LAN2:
509183509Syongari	case PCI_PRODUCT_NVIDIA_MCP79_LAN3:
510183509Syongari	case PCI_PRODUCT_NVIDIA_MCP79_LAN4:
511183509Syongari		/* XXX flow control */
512183509Syongari		sc->nfe_flags |= NFE_JUMBO_SUP | NFE_40BIT_ADDR | NFE_HW_CSUM |
513183561Syongari		    NFE_PWR_MGMT | NFE_CORRECT_MACADDR | NFE_MIB_V3;
514183509Syongari		break;
515162212Sobrien	case PCI_PRODUCT_NVIDIA_MCP65_LAN1:
516162212Sobrien	case PCI_PRODUCT_NVIDIA_MCP65_LAN2:
517162212Sobrien	case PCI_PRODUCT_NVIDIA_MCP65_LAN3:
518162212Sobrien	case PCI_PRODUCT_NVIDIA_MCP65_LAN4:
519170589Syongari		sc->nfe_flags |= NFE_JUMBO_SUP | NFE_40BIT_ADDR |
520183561Syongari		    NFE_PWR_MGMT | NFE_CORRECT_MACADDR | NFE_TX_FLOW_CTRL |
521183561Syongari		    NFE_MIB_V2;
522163503Sobrien		break;
523159952Sobrien	}
524159952Sobrien
525170589Syongari	nfe_power(sc);
526170589Syongari	/* Check for reversed ethernet address */
527170589Syongari	if ((NFE_READ(sc, NFE_TX_UNK) & NFE_MAC_ADDR_INORDER) != 0)
528170589Syongari		sc->nfe_flags |= NFE_CORRECT_MACADDR;
529170589Syongari	nfe_get_macaddr(sc, sc->eaddr);
530159952Sobrien	/*
531159967Sobrien	 * Allocate the parent bus DMA tag appropriate for PCI.
532159967Sobrien	 */
533170589Syongari	dma_addr_max = BUS_SPACE_MAXADDR_32BIT;
534170589Syongari	if ((sc->nfe_flags & NFE_40BIT_ADDR) != 0)
535170589Syongari		dma_addr_max = NFE_DMA_MAXADDR;
536170589Syongari	error = bus_dma_tag_create(
537170589Syongari	    bus_get_dma_tag(sc->nfe_dev),	/* parent */
538163503Sobrien	    1, 0,				/* alignment, boundary */
539170589Syongari	    dma_addr_max,			/* lowaddr */
540163503Sobrien	    BUS_SPACE_MAXADDR,			/* highaddr */
541163503Sobrien	    NULL, NULL,				/* filter, filterarg */
542170589Syongari	    BUS_SPACE_MAXSIZE_32BIT, 0,		/* maxsize, nsegments */
543163503Sobrien	    BUS_SPACE_MAXSIZE_32BIT,		/* maxsegsize */
544170589Syongari	    0,					/* flags */
545163503Sobrien	    NULL, NULL,				/* lockfunc, lockarg */
546163503Sobrien	    &sc->nfe_parent_tag);
547159967Sobrien	if (error)
548159967Sobrien		goto fail;
549159967Sobrien
550164650Sobrien	ifp = sc->nfe_ifp = if_alloc(IFT_ETHER);
551164650Sobrien	if (ifp == NULL) {
552170589Syongari		device_printf(dev, "can not if_alloc()\n");
553164650Sobrien		error = ENOSPC;
554164650Sobrien		goto fail;
555164650Sobrien	}
556164650Sobrien
557159967Sobrien	/*
558159952Sobrien	 * Allocate Tx and Rx rings.
559159952Sobrien	 */
560170589Syongari	if ((error = nfe_alloc_tx_ring(sc, &sc->txq)) != 0)
561159967Sobrien		goto fail;
562159952Sobrien
563170589Syongari	if ((error = nfe_alloc_rx_ring(sc, &sc->rxq)) != 0)
564159967Sobrien		goto fail;
565170589Syongari
566171559Syongari	nfe_alloc_jrx_ring(sc, &sc->jrxq);
567183561Syongari	/* Create sysctl node. */
568183561Syongari	nfe_sysctl_node(sc);
569170589Syongari
570159952Sobrien	ifp->if_softc = sc;
571159967Sobrien	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
572170589Syongari	ifp->if_mtu = ETHERMTU;
573159952Sobrien	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
574159952Sobrien	ifp->if_ioctl = nfe_ioctl;
575159952Sobrien	ifp->if_start = nfe_start;
576170589Syongari	ifp->if_hwassist = 0;
577170589Syongari	ifp->if_capabilities = 0;
578159952Sobrien	ifp->if_init = nfe_init;
579170589Syongari	IFQ_SET_MAXLEN(&ifp->if_snd, NFE_TX_RING_COUNT - 1);
580170589Syongari	ifp->if_snd.ifq_drv_maxlen = NFE_TX_RING_COUNT - 1;
581170589Syongari	IFQ_SET_READY(&ifp->if_snd);
582159952Sobrien
583170589Syongari	if (sc->nfe_flags & NFE_HW_CSUM) {
584170589Syongari		ifp->if_capabilities |= IFCAP_HWCSUM | IFCAP_TSO4;
585170589Syongari		ifp->if_hwassist |= NFE_CSUM_FEATURES | CSUM_TSO;
586170589Syongari	}
587170589Syongari	ifp->if_capenable = ifp->if_capabilities;
588164650Sobrien
589170589Syongari	sc->nfe_framesize = ifp->if_mtu + NFE_RX_HEADERS;
590170589Syongari	/* VLAN capability setup. */
591170589Syongari	ifp->if_capabilities |= IFCAP_VLAN_MTU;
592170589Syongari	if ((sc->nfe_flags & NFE_HW_VLAN) != 0) {
593159952Sobrien		ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING;
594170589Syongari		if ((ifp->if_capabilities & IFCAP_HWCSUM) != 0)
595215432Syongari			ifp->if_capabilities |= IFCAP_VLAN_HWCSUM |
596215432Syongari			    IFCAP_VLAN_HWTSO;
597159952Sobrien	}
598215132Syongari
599219902Sjhb	if (pci_find_cap(dev, PCIY_PMG, &reg) == 0)
600215132Syongari		ifp->if_capabilities |= IFCAP_WOL_MAGIC;
601159967Sobrien	ifp->if_capenable = ifp->if_capabilities;
602159952Sobrien
603170589Syongari	/*
604170589Syongari	 * Tell the upper layer(s) we support long frames.
605170589Syongari	 * Must appear after the call to ether_ifattach() because
606170589Syongari	 * ether_ifattach() sets ifi_hdrlen to the default value.
607170589Syongari	 */
608170589Syongari	ifp->if_data.ifi_hdrlen = sizeof(struct ether_vlan_header);
609170589Syongari
610159967Sobrien#ifdef DEVICE_POLLING
611159967Sobrien	ifp->if_capabilities |= IFCAP_POLLING;
612159967Sobrien#endif
613159952Sobrien
614159967Sobrien	/* Do MII setup */
615213894Smarius	error = mii_attach(dev, &sc->nfe_miibus, ifp, nfe_ifmedia_upd,
616215297Smarius	    nfe_ifmedia_sts, BMSR_DEFCAPMASK, MII_PHY_ANY, MII_OFFSET_ANY,
617215297Smarius	    MIIF_DOPAUSE);
618213894Smarius	if (error != 0) {
619213894Smarius		device_printf(dev, "attaching PHYs failed\n");
620159967Sobrien		goto fail;
621159967Sobrien	}
622159967Sobrien	ether_ifattach(ifp, sc->eaddr);
623159952Sobrien
624170589Syongari	TASK_INIT(&sc->nfe_int_task, 0, nfe_int_task, sc);
625170589Syongari	sc->nfe_tq = taskqueue_create_fast("nfe_taskq", M_WAITOK,
626170589Syongari	    taskqueue_thread_enqueue, &sc->nfe_tq);
627170589Syongari	taskqueue_start_threads(&sc->nfe_tq, 1, PI_NET, "%s taskq",
628170589Syongari	    device_get_nameunit(sc->nfe_dev));
629170589Syongari	error = 0;
630170589Syongari	if (sc->nfe_msi == 0 && sc->nfe_msix == 0) {
631170589Syongari		error = bus_setup_intr(dev, sc->nfe_irq[0],
632170589Syongari		    INTR_TYPE_NET | INTR_MPSAFE, nfe_intr, NULL, sc,
633170589Syongari		    &sc->nfe_intrhand[0]);
634170589Syongari	} else {
635170589Syongari		for (i = 0; i < NFE_MSI_MESSAGES; i++) {
636170589Syongari			error = bus_setup_intr(dev, sc->nfe_irq[i],
637170589Syongari			    INTR_TYPE_NET | INTR_MPSAFE, nfe_intr, NULL, sc,
638170589Syongari			    &sc->nfe_intrhand[i]);
639170589Syongari			if (error != 0)
640170589Syongari				break;
641170589Syongari		}
642170589Syongari	}
643159967Sobrien	if (error) {
644170589Syongari		device_printf(dev, "couldn't set up irq\n");
645170589Syongari		taskqueue_free(sc->nfe_tq);
646170589Syongari		sc->nfe_tq = NULL;
647159967Sobrien		ether_ifdetach(ifp);
648159967Sobrien		goto fail;
649159967Sobrien	}
650159967Sobrien
651159967Sobrienfail:
652159967Sobrien	if (error)
653159967Sobrien		nfe_detach(dev);
654159967Sobrien
655159967Sobrien	return (error);
656159952Sobrien}
657159952Sobrien
658159967Sobrien
659159967Sobrienstatic int
660159967Sobriennfe_detach(device_t dev)
661159952Sobrien{
662163503Sobrien	struct nfe_softc *sc;
663163503Sobrien	struct ifnet *ifp;
664170589Syongari	uint8_t eaddr[ETHER_ADDR_LEN];
665170589Syongari	int i, rid;
666159952Sobrien
667159967Sobrien	sc = device_get_softc(dev);
668159967Sobrien	KASSERT(mtx_initialized(&sc->nfe_mtx), ("nfe mutex not initialized"));
669159967Sobrien	ifp = sc->nfe_ifp;
670159967Sobrien
671159967Sobrien#ifdef DEVICE_POLLING
672170589Syongari	if (ifp != NULL && ifp->if_capenable & IFCAP_POLLING)
673159967Sobrien		ether_poll_deregister(ifp);
674159967Sobrien#endif
675159967Sobrien	if (device_is_attached(dev)) {
676164649Sobrien		NFE_LOCK(sc);
677170589Syongari		nfe_stop(ifp);
678159967Sobrien		ifp->if_flags &= ~IFF_UP;
679164649Sobrien		NFE_UNLOCK(sc);
680159967Sobrien		callout_drain(&sc->nfe_stat_ch);
681159967Sobrien		ether_ifdetach(ifp);
682159967Sobrien	}
683159967Sobrien
684170589Syongari	if (ifp) {
685170589Syongari		/* restore ethernet address */
686170589Syongari		if ((sc->nfe_flags & NFE_CORRECT_MACADDR) == 0) {
687170589Syongari			for (i = 0; i < ETHER_ADDR_LEN; i++) {
688170589Syongari				eaddr[i] = sc->eaddr[5 - i];
689170589Syongari			}
690170589Syongari		} else
691170589Syongari			bcopy(sc->eaddr, eaddr, ETHER_ADDR_LEN);
692170589Syongari		nfe_set_macaddr(sc, eaddr);
693159967Sobrien		if_free(ifp);
694170589Syongari	}
695159967Sobrien	if (sc->nfe_miibus)
696159967Sobrien		device_delete_child(dev, sc->nfe_miibus);
697159967Sobrien	bus_generic_detach(dev);
698170589Syongari	if (sc->nfe_tq != NULL) {
699170589Syongari		taskqueue_drain(sc->nfe_tq, &sc->nfe_int_task);
700170589Syongari		taskqueue_free(sc->nfe_tq);
701170589Syongari		sc->nfe_tq = NULL;
702170589Syongari	}
703159967Sobrien
704170589Syongari	for (i = 0; i < NFE_MSI_MESSAGES; i++) {
705170589Syongari		if (sc->nfe_intrhand[i] != NULL) {
706170589Syongari			bus_teardown_intr(dev, sc->nfe_irq[i],
707170589Syongari			    sc->nfe_intrhand[i]);
708170589Syongari			sc->nfe_intrhand[i] = NULL;
709170589Syongari		}
710170589Syongari	}
711159967Sobrien
712170589Syongari	if (sc->nfe_msi == 0 && sc->nfe_msix == 0) {
713170589Syongari		if (sc->nfe_irq[0] != NULL)
714170589Syongari			bus_release_resource(dev, SYS_RES_IRQ, 0,
715170589Syongari			    sc->nfe_irq[0]);
716170589Syongari	} else {
717170589Syongari		for (i = 0, rid = 1; i < NFE_MSI_MESSAGES; i++, rid++) {
718170589Syongari			if (sc->nfe_irq[i] != NULL) {
719170589Syongari				bus_release_resource(dev, SYS_RES_IRQ, rid,
720170589Syongari				    sc->nfe_irq[i]);
721170589Syongari				sc->nfe_irq[i] = NULL;
722170589Syongari			}
723170589Syongari		}
724170589Syongari		pci_release_msi(dev);
725170589Syongari	}
726170589Syongari	if (sc->nfe_msix_pba_res != NULL) {
727170589Syongari		bus_release_resource(dev, SYS_RES_MEMORY, PCIR_BAR(3),
728170589Syongari		    sc->nfe_msix_pba_res);
729170589Syongari		sc->nfe_msix_pba_res = NULL;
730170589Syongari	}
731170589Syongari	if (sc->nfe_msix_res != NULL) {
732170589Syongari		bus_release_resource(dev, SYS_RES_MEMORY, PCIR_BAR(2),
733170589Syongari		    sc->nfe_msix_res);
734170589Syongari		sc->nfe_msix_res = NULL;
735170589Syongari	}
736170589Syongari	if (sc->nfe_res[0] != NULL) {
737170589Syongari		bus_release_resource(dev, SYS_RES_MEMORY, PCIR_BAR(0),
738170589Syongari		    sc->nfe_res[0]);
739170589Syongari		sc->nfe_res[0] = NULL;
740170589Syongari	}
741170589Syongari
742159967Sobrien	nfe_free_tx_ring(sc, &sc->txq);
743159967Sobrien	nfe_free_rx_ring(sc, &sc->rxq);
744170589Syongari	nfe_free_jrx_ring(sc, &sc->jrxq);
745159967Sobrien
746170589Syongari	if (sc->nfe_parent_tag) {
747159967Sobrien		bus_dma_tag_destroy(sc->nfe_parent_tag);
748170589Syongari		sc->nfe_parent_tag = NULL;
749170589Syongari	}
750159967Sobrien
751159967Sobrien	mtx_destroy(&sc->nfe_mtx);
752159967Sobrien
753159967Sobrien	return (0);
754159952Sobrien}
755159952Sobrien
756159967Sobrien
757170589Syongaristatic int
758170589Syongarinfe_suspend(device_t dev)
759170589Syongari{
760170589Syongari	struct nfe_softc *sc;
761170589Syongari
762170589Syongari	sc = device_get_softc(dev);
763170589Syongari
764170589Syongari	NFE_LOCK(sc);
765170589Syongari	nfe_stop(sc->nfe_ifp);
766215132Syongari	nfe_set_wol(sc);
767170589Syongari	sc->nfe_suspended = 1;
768170589Syongari	NFE_UNLOCK(sc);
769170589Syongari
770170589Syongari	return (0);
771170589Syongari}
772170589Syongari
773170589Syongari
774170589Syongaristatic int
775170589Syongarinfe_resume(device_t dev)
776170589Syongari{
777170589Syongari	struct nfe_softc *sc;
778170589Syongari	struct ifnet *ifp;
779170589Syongari
780170589Syongari	sc = device_get_softc(dev);
781170589Syongari
782170589Syongari	NFE_LOCK(sc);
783215132Syongari	nfe_power(sc);
784170589Syongari	ifp = sc->nfe_ifp;
785170589Syongari	if (ifp->if_flags & IFF_UP)
786170589Syongari		nfe_init_locked(sc);
787170589Syongari	sc->nfe_suspended = 0;
788170589Syongari	NFE_UNLOCK(sc);
789170589Syongari
790170589Syongari	return (0);
791170589Syongari}
792170589Syongari
793170589Syongari
794215327Syongaristatic int
795215327Syongarinfe_can_use_msix(struct nfe_softc *sc)
796215327Syongari{
797215327Syongari	static struct msix_blacklist {
798215327Syongari		char	*maker;
799215327Syongari		char	*product;
800215327Syongari	} msix_blacklists[] = {
801215327Syongari		{ "ASUSTeK Computer INC.", "P5N32-SLI PREMIUM" }
802215327Syongari	};
803215327Syongari
804215327Syongari	struct msix_blacklist *mblp;
805215327Syongari	char *maker, *product;
806215350Syongari	int count, n, use_msix;
807215327Syongari
808215327Syongari	/*
809215327Syongari	 * Search base board manufacturer and product name table
810215327Syongari	 * to see this system has a known MSI/MSI-X issue.
811215327Syongari	 */
812215327Syongari	maker = getenv("smbios.planar.maker");
813215327Syongari	product = getenv("smbios.planar.product");
814215350Syongari	use_msix = 1;
815215327Syongari	if (maker != NULL && product != NULL) {
816215327Syongari		count = sizeof(msix_blacklists) / sizeof(msix_blacklists[0]);
817215327Syongari		mblp = msix_blacklists;
818215327Syongari		for (n = 0; n < count; n++) {
819215327Syongari			if (strcmp(maker, mblp->maker) == 0 &&
820215350Syongari			    strcmp(product, mblp->product) == 0) {
821215350Syongari				use_msix = 0;
822215350Syongari				break;
823215350Syongari			}
824215327Syongari			mblp++;
825215327Syongari		}
826215327Syongari	}
827215350Syongari	if (maker != NULL)
828215350Syongari		freeenv(maker);
829215350Syongari	if (product != NULL)
830215350Syongari		freeenv(product);
831215327Syongari
832215350Syongari	return (use_msix);
833215327Syongari}
834215327Syongari
835215327Syongari
836170589Syongari/* Take PHY/NIC out of powerdown, from Linux */
837159967Sobrienstatic void
838170589Syongarinfe_power(struct nfe_softc *sc)
839170589Syongari{
840170589Syongari	uint32_t pwr;
841170589Syongari
842170589Syongari	if ((sc->nfe_flags & NFE_PWR_MGMT) == 0)
843170589Syongari		return;
844170589Syongari	NFE_WRITE(sc, NFE_RXTX_CTL, NFE_RXTX_RESET | NFE_RXTX_BIT2);
845170589Syongari	NFE_WRITE(sc, NFE_MAC_RESET, NFE_MAC_RESET_MAGIC);
846170589Syongari	DELAY(100);
847170589Syongari	NFE_WRITE(sc, NFE_MAC_RESET, 0);
848170589Syongari	DELAY(100);
849170589Syongari	NFE_WRITE(sc, NFE_RXTX_CTL, NFE_RXTX_BIT2);
850170589Syongari	pwr = NFE_READ(sc, NFE_PWR2_CTL);
851170589Syongari	pwr &= ~NFE_PWR2_WAKEUP_MASK;
852170589Syongari	if (sc->nfe_revid >= 0xa3 &&
853170589Syongari	    (sc->nfe_devid == PCI_PRODUCT_NVIDIA_NFORCE430_LAN1 ||
854170589Syongari	    sc->nfe_devid == PCI_PRODUCT_NVIDIA_NFORCE430_LAN2))
855170589Syongari		pwr |= NFE_PWR2_REVA3;
856170589Syongari	NFE_WRITE(sc, NFE_PWR2_CTL, pwr);
857170589Syongari}
858170589Syongari
859170589Syongari
860170589Syongaristatic void
861159967Sobriennfe_miibus_statchg(device_t dev)
862159952Sobrien{
863159967Sobrien	struct nfe_softc *sc;
864159967Sobrien	struct mii_data *mii;
865170589Syongari	struct ifnet *ifp;
866215132Syongari	uint32_t rxctl, txctl;
867159952Sobrien
868215132Syongari	sc = device_get_softc(dev);
869170589Syongari
870159967Sobrien	mii = device_get_softc(sc->nfe_miibus);
871170589Syongari	ifp = sc->nfe_ifp;
872159967Sobrien
873215132Syongari	sc->nfe_link = 0;
874215132Syongari	if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) ==
875215132Syongari	    (IFM_ACTIVE | IFM_AVALID)) {
876215132Syongari		switch (IFM_SUBTYPE(mii->mii_media_active)) {
877215132Syongari		case IFM_10_T:
878215132Syongari		case IFM_100_TX:
879215132Syongari		case IFM_1000_T:
880170589Syongari			sc->nfe_link = 1;
881215132Syongari			break;
882215132Syongari		default:
883215132Syongari			break;
884215132Syongari		}
885215132Syongari	}
886170589Syongari
887215132Syongari	nfe_mac_config(sc, mii);
888215132Syongari	txctl = NFE_READ(sc, NFE_TX_CTL);
889215132Syongari	rxctl = NFE_READ(sc, NFE_RX_CTL);
890215132Syongari	if (sc->nfe_link != 0 && (ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) {
891215132Syongari		txctl |= NFE_TX_START;
892215132Syongari		rxctl |= NFE_RX_START;
893215132Syongari	} else {
894215132Syongari		txctl &= ~NFE_TX_START;
895215132Syongari		rxctl &= ~NFE_RX_START;
896215132Syongari	}
897215132Syongari	NFE_WRITE(sc, NFE_TX_CTL, txctl);
898215132Syongari	NFE_WRITE(sc, NFE_RX_CTL, rxctl);
899215132Syongari}
900215132Syongari
901215132Syongari
902215132Syongaristatic void
903215132Syongarinfe_mac_config(struct nfe_softc *sc, struct mii_data *mii)
904215132Syongari{
905215132Syongari	uint32_t link, misc, phy, seed;
906215132Syongari	uint32_t val;
907215132Syongari
908215132Syongari	NFE_LOCK_ASSERT(sc);
909215132Syongari
910159952Sobrien	phy = NFE_READ(sc, NFE_PHY_IFACE);
911159952Sobrien	phy &= ~(NFE_PHY_HDX | NFE_PHY_100TX | NFE_PHY_1000T);
912159952Sobrien
913159952Sobrien	seed = NFE_READ(sc, NFE_RNDSEED);
914159952Sobrien	seed &= ~NFE_SEED_MASK;
915159952Sobrien
916215132Syongari	misc = NFE_MISC1_MAGIC;
917215132Syongari	link = NFE_MEDIA_SET;
918215132Syongari
919215132Syongari	if ((IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) == 0) {
920159952Sobrien		phy  |= NFE_PHY_HDX;	/* half-duplex */
921159952Sobrien		misc |= NFE_MISC1_HDX;
922159952Sobrien	}
923159952Sobrien
924159952Sobrien	switch (IFM_SUBTYPE(mii->mii_media_active)) {
925159952Sobrien	case IFM_1000_T:	/* full-duplex only */
926159952Sobrien		link |= NFE_MEDIA_1000T;
927159952Sobrien		seed |= NFE_SEED_1000T;
928159952Sobrien		phy  |= NFE_PHY_1000T;
929159952Sobrien		break;
930159952Sobrien	case IFM_100_TX:
931159952Sobrien		link |= NFE_MEDIA_100TX;
932159952Sobrien		seed |= NFE_SEED_100TX;
933159952Sobrien		phy  |= NFE_PHY_100TX;
934159952Sobrien		break;
935159952Sobrien	case IFM_10_T:
936159952Sobrien		link |= NFE_MEDIA_10T;
937159952Sobrien		seed |= NFE_SEED_10T;
938159952Sobrien		break;
939159952Sobrien	}
940159952Sobrien
941170589Syongari	if ((phy & 0x10000000) != 0) {
942170589Syongari		if (IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_T)
943170589Syongari			val = NFE_R1_MAGIC_1000;
944170589Syongari		else
945170589Syongari			val = NFE_R1_MAGIC_10_100;
946170589Syongari	} else
947170589Syongari		val = NFE_R1_MAGIC_DEFAULT;
948170589Syongari	NFE_WRITE(sc, NFE_SETUP_R1, val);
949170589Syongari
950159952Sobrien	NFE_WRITE(sc, NFE_RNDSEED, seed);	/* XXX: gigabit NICs only? */
951159952Sobrien
952159952Sobrien	NFE_WRITE(sc, NFE_PHY_IFACE, phy);
953159952Sobrien	NFE_WRITE(sc, NFE_MISC1, misc);
954159952Sobrien	NFE_WRITE(sc, NFE_LINKSPEED, link);
955170589Syongari
956215132Syongari	if ((IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) != 0) {
957170589Syongari		/* It seems all hardwares supports Rx pause frames. */
958170589Syongari		val = NFE_READ(sc, NFE_RXFILTER);
959215297Smarius		if ((IFM_OPTIONS(mii->mii_media_active) &
960215297Smarius		    IFM_ETH_RXPAUSE) != 0)
961170589Syongari			val |= NFE_PFF_RX_PAUSE;
962170589Syongari		else
963170589Syongari			val &= ~NFE_PFF_RX_PAUSE;
964170589Syongari		NFE_WRITE(sc, NFE_RXFILTER, val);
965170589Syongari		if ((sc->nfe_flags & NFE_TX_FLOW_CTRL) != 0) {
966170589Syongari			val = NFE_READ(sc, NFE_MISC1);
967215132Syongari			if ((IFM_OPTIONS(mii->mii_media_active) &
968215297Smarius			    IFM_ETH_TXPAUSE) != 0) {
969170589Syongari				NFE_WRITE(sc, NFE_TX_PAUSE_FRAME,
970170589Syongari				    NFE_TX_PAUSE_FRAME_ENABLE);
971170589Syongari				val |= NFE_MISC1_TX_PAUSE;
972170589Syongari			} else {
973170589Syongari				val &= ~NFE_MISC1_TX_PAUSE;
974170589Syongari				NFE_WRITE(sc, NFE_TX_PAUSE_FRAME,
975170589Syongari				    NFE_TX_PAUSE_FRAME_DISABLE);
976170589Syongari			}
977170589Syongari			NFE_WRITE(sc, NFE_MISC1, val);
978170589Syongari		}
979170589Syongari	} else {
980170589Syongari		/* disable rx/tx pause frames */
981170589Syongari		val = NFE_READ(sc, NFE_RXFILTER);
982170589Syongari		val &= ~NFE_PFF_RX_PAUSE;
983170589Syongari		NFE_WRITE(sc, NFE_RXFILTER, val);
984170589Syongari		if ((sc->nfe_flags & NFE_TX_FLOW_CTRL) != 0) {
985170589Syongari			NFE_WRITE(sc, NFE_TX_PAUSE_FRAME,
986170589Syongari			    NFE_TX_PAUSE_FRAME_DISABLE);
987170589Syongari			val = NFE_READ(sc, NFE_MISC1);
988170589Syongari			val &= ~NFE_MISC1_TX_PAUSE;
989170589Syongari			NFE_WRITE(sc, NFE_MISC1, val);
990170589Syongari		}
991170589Syongari	}
992159952Sobrien}
993159952Sobrien
994163503Sobrien
995159967Sobrienstatic int
996159967Sobriennfe_miibus_readreg(device_t dev, int phy, int reg)
997159952Sobrien{
998159967Sobrien	struct nfe_softc *sc = device_get_softc(dev);
999170589Syongari	uint32_t val;
1000159952Sobrien	int ntries;
1001159952Sobrien
1002159952Sobrien	NFE_WRITE(sc, NFE_PHY_STATUS, 0xf);
1003159952Sobrien
1004159952Sobrien	if (NFE_READ(sc, NFE_PHY_CTL) & NFE_PHY_BUSY) {
1005159952Sobrien		NFE_WRITE(sc, NFE_PHY_CTL, NFE_PHY_BUSY);
1006159952Sobrien		DELAY(100);
1007159952Sobrien	}
1008159952Sobrien
1009159952Sobrien	NFE_WRITE(sc, NFE_PHY_CTL, (phy << NFE_PHYADD_SHIFT) | reg);
1010159952Sobrien
1011170589Syongari	for (ntries = 0; ntries < NFE_TIMEOUT; ntries++) {
1012159952Sobrien		DELAY(100);
1013159952Sobrien		if (!(NFE_READ(sc, NFE_PHY_CTL) & NFE_PHY_BUSY))
1014159952Sobrien			break;
1015159952Sobrien	}
1016170589Syongari	if (ntries == NFE_TIMEOUT) {
1017170589Syongari		DPRINTFN(sc, 2, "timeout waiting for PHY\n");
1018159952Sobrien		return 0;
1019159952Sobrien	}
1020159952Sobrien
1021159952Sobrien	if (NFE_READ(sc, NFE_PHY_STATUS) & NFE_PHY_ERROR) {
1022170589Syongari		DPRINTFN(sc, 2, "could not read PHY\n");
1023159952Sobrien		return 0;
1024159952Sobrien	}
1025159952Sobrien
1026159952Sobrien	val = NFE_READ(sc, NFE_PHY_DATA);
1027159952Sobrien	if (val != 0xffffffff && val != 0)
1028159952Sobrien		sc->mii_phyaddr = phy;
1029159952Sobrien
1030170589Syongari	DPRINTFN(sc, 2, "mii read phy %d reg 0x%x ret 0x%x\n", phy, reg, val);
1031159952Sobrien
1032170589Syongari	return (val);
1033159952Sobrien}
1034159952Sobrien
1035163503Sobrien
1036159967Sobrienstatic int
1037159967Sobriennfe_miibus_writereg(device_t dev, int phy, int reg, int val)
1038159952Sobrien{
1039159967Sobrien	struct nfe_softc *sc = device_get_softc(dev);
1040170589Syongari	uint32_t ctl;
1041163503Sobrien	int ntries;
1042159952Sobrien
1043159952Sobrien	NFE_WRITE(sc, NFE_PHY_STATUS, 0xf);
1044159952Sobrien
1045159952Sobrien	if (NFE_READ(sc, NFE_PHY_CTL) & NFE_PHY_BUSY) {
1046159952Sobrien		NFE_WRITE(sc, NFE_PHY_CTL, NFE_PHY_BUSY);
1047159952Sobrien		DELAY(100);
1048159952Sobrien	}
1049159952Sobrien
1050159952Sobrien	NFE_WRITE(sc, NFE_PHY_DATA, val);
1051159952Sobrien	ctl = NFE_PHY_WRITE | (phy << NFE_PHYADD_SHIFT) | reg;
1052159952Sobrien	NFE_WRITE(sc, NFE_PHY_CTL, ctl);
1053159952Sobrien
1054170589Syongari	for (ntries = 0; ntries < NFE_TIMEOUT; ntries++) {
1055159952Sobrien		DELAY(100);
1056159952Sobrien		if (!(NFE_READ(sc, NFE_PHY_CTL) & NFE_PHY_BUSY))
1057159952Sobrien			break;
1058159952Sobrien	}
1059159952Sobrien#ifdef NFE_DEBUG
1060170589Syongari	if (nfedebug >= 2 && ntries == NFE_TIMEOUT)
1061170589Syongari		device_printf(sc->nfe_dev, "could not write to PHY\n");
1062159952Sobrien#endif
1063170589Syongari	return (0);
1064159952Sobrien}
1065159952Sobrien
1066170589Syongaristruct nfe_dmamap_arg {
1067170589Syongari	bus_addr_t nfe_busaddr;
1068170589Syongari};
1069170589Syongari
1070159967Sobrienstatic int
1071159967Sobriennfe_alloc_rx_ring(struct nfe_softc *sc, struct nfe_rx_ring *ring)
1072159952Sobrien{
1073170589Syongari	struct nfe_dmamap_arg ctx;
1074159967Sobrien	struct nfe_rx_data *data;
1075170589Syongari	void *desc;
1076159967Sobrien	int i, error, descsize;
1077159967Sobrien
1078159967Sobrien	if (sc->nfe_flags & NFE_40BIT_ADDR) {
1079170589Syongari		desc = ring->desc64;
1080159967Sobrien		descsize = sizeof (struct nfe_desc64);
1081159967Sobrien	} else {
1082170589Syongari		desc = ring->desc32;
1083159967Sobrien		descsize = sizeof (struct nfe_desc32);
1084159967Sobrien	}
1085159967Sobrien
1086159967Sobrien	ring->cur = ring->next = 0;
1087159967Sobrien
1088163503Sobrien	error = bus_dma_tag_create(sc->nfe_parent_tag,
1089170589Syongari	    NFE_RING_ALIGN, 0,			/* alignment, boundary */
1090170589Syongari	    BUS_SPACE_MAXADDR,			/* lowaddr */
1091170589Syongari	    BUS_SPACE_MAXADDR,			/* highaddr */
1092170589Syongari	    NULL, NULL,				/* filter, filterarg */
1093170589Syongari	    NFE_RX_RING_COUNT * descsize, 1,	/* maxsize, nsegments */
1094170589Syongari	    NFE_RX_RING_COUNT * descsize,	/* maxsegsize */
1095170589Syongari	    0,					/* flags */
1096170589Syongari	    NULL, NULL,				/* lockfunc, lockarg */
1097170589Syongari	    &ring->rx_desc_tag);
1098159967Sobrien	if (error != 0) {
1099170589Syongari		device_printf(sc->nfe_dev, "could not create desc DMA tag\n");
1100159967Sobrien		goto fail;
1101159967Sobrien	}
1102159967Sobrien
1103159967Sobrien	/* allocate memory to desc */
1104170589Syongari	error = bus_dmamem_alloc(ring->rx_desc_tag, &desc, BUS_DMA_WAITOK |
1105170589Syongari	    BUS_DMA_COHERENT | BUS_DMA_ZERO, &ring->rx_desc_map);
1106159967Sobrien	if (error != 0) {
1107170589Syongari		device_printf(sc->nfe_dev, "could not create desc DMA map\n");
1108159967Sobrien		goto fail;
1109159967Sobrien	}
1110170589Syongari	if (sc->nfe_flags & NFE_40BIT_ADDR)
1111170589Syongari		ring->desc64 = desc;
1112170589Syongari	else
1113170589Syongari		ring->desc32 = desc;
1114159967Sobrien
1115159967Sobrien	/* map desc to device visible address space */
1116170589Syongari	ctx.nfe_busaddr = 0;
1117170589Syongari	error = bus_dmamap_load(ring->rx_desc_tag, ring->rx_desc_map, desc,
1118170589Syongari	    NFE_RX_RING_COUNT * descsize, nfe_dma_map_segs, &ctx, 0);
1119159967Sobrien	if (error != 0) {
1120170589Syongari		device_printf(sc->nfe_dev, "could not load desc DMA map\n");
1121159967Sobrien		goto fail;
1122159967Sobrien	}
1123170589Syongari	ring->physaddr = ctx.nfe_busaddr;
1124159967Sobrien
1125170589Syongari	error = bus_dma_tag_create(sc->nfe_parent_tag,
1126170589Syongari	    1, 0,			/* alignment, boundary */
1127170589Syongari	    BUS_SPACE_MAXADDR,		/* lowaddr */
1128170589Syongari	    BUS_SPACE_MAXADDR,		/* highaddr */
1129170589Syongari	    NULL, NULL,			/* filter, filterarg */
1130170589Syongari	    MCLBYTES, 1,		/* maxsize, nsegments */
1131170589Syongari	    MCLBYTES,			/* maxsegsize */
1132170589Syongari	    0,				/* flags */
1133170589Syongari	    NULL, NULL,			/* lockfunc, lockarg */
1134170589Syongari	    &ring->rx_data_tag);
1135170589Syongari	if (error != 0) {
1136170589Syongari		device_printf(sc->nfe_dev, "could not create Rx DMA tag\n");
1137170589Syongari		goto fail;
1138170589Syongari	}
1139159967Sobrien
1140170589Syongari	error = bus_dmamap_create(ring->rx_data_tag, 0, &ring->rx_spare_map);
1141170589Syongari	if (error != 0) {
1142170589Syongari		device_printf(sc->nfe_dev,
1143170589Syongari		    "could not create Rx DMA spare map\n");
1144170589Syongari		goto fail;
1145170589Syongari	}
1146170589Syongari
1147159967Sobrien	/*
1148159967Sobrien	 * Pre-allocate Rx buffers and populate Rx ring.
1149159967Sobrien	 */
1150159967Sobrien	for (i = 0; i < NFE_RX_RING_COUNT; i++) {
1151159967Sobrien		data = &sc->rxq.data[i];
1152170589Syongari		data->rx_data_map = NULL;
1153170589Syongari		data->m = NULL;
1154170589Syongari		error = bus_dmamap_create(ring->rx_data_tag, 0,
1155170589Syongari		    &data->rx_data_map);
1156164651Sobrien		if (error != 0) {
1157170589Syongari			device_printf(sc->nfe_dev,
1158170589Syongari			    "could not create Rx DMA map\n");
1159164651Sobrien			goto fail;
1160164651Sobrien		}
1161170589Syongari	}
1162159967Sobrien
1163170589Syongarifail:
1164170589Syongari	return (error);
1165170589Syongari}
1166170589Syongari
1167170589Syongari
1168171559Syongaristatic void
1169170589Syongarinfe_alloc_jrx_ring(struct nfe_softc *sc, struct nfe_jrx_ring *ring)
1170170589Syongari{
1171170589Syongari	struct nfe_dmamap_arg ctx;
1172170589Syongari	struct nfe_rx_data *data;
1173170589Syongari	void *desc;
1174170589Syongari	int i, error, descsize;
1175170589Syongari
1176170589Syongari	if ((sc->nfe_flags & NFE_JUMBO_SUP) == 0)
1177171559Syongari		return;
1178171559Syongari	if (jumbo_disable != 0) {
1179171559Syongari		device_printf(sc->nfe_dev, "disabling jumbo frame support\n");
1180171559Syongari		sc->nfe_jumbo_disable = 1;
1181171559Syongari		return;
1182171559Syongari	}
1183170589Syongari
1184170589Syongari	if (sc->nfe_flags & NFE_40BIT_ADDR) {
1185170589Syongari		desc = ring->jdesc64;
1186170589Syongari		descsize = sizeof (struct nfe_desc64);
1187170589Syongari	} else {
1188170589Syongari		desc = ring->jdesc32;
1189170589Syongari		descsize = sizeof (struct nfe_desc32);
1190170589Syongari	}
1191170589Syongari
1192170589Syongari	ring->jcur = ring->jnext = 0;
1193170589Syongari
1194170589Syongari	/* Create DMA tag for jumbo Rx ring. */
1195170589Syongari	error = bus_dma_tag_create(sc->nfe_parent_tag,
1196170589Syongari	    NFE_RING_ALIGN, 0,			/* alignment, boundary */
1197170589Syongari	    BUS_SPACE_MAXADDR,			/* lowaddr */
1198170589Syongari	    BUS_SPACE_MAXADDR,			/* highaddr */
1199170589Syongari	    NULL, NULL,				/* filter, filterarg */
1200170589Syongari	    NFE_JUMBO_RX_RING_COUNT * descsize,	/* maxsize */
1201170589Syongari	    1, 					/* nsegments */
1202170589Syongari	    NFE_JUMBO_RX_RING_COUNT * descsize,	/* maxsegsize */
1203170589Syongari	    0,					/* flags */
1204170589Syongari	    NULL, NULL,				/* lockfunc, lockarg */
1205170589Syongari	    &ring->jrx_desc_tag);
1206170589Syongari	if (error != 0) {
1207170589Syongari		device_printf(sc->nfe_dev,
1208170589Syongari		    "could not create jumbo ring DMA tag\n");
1209170589Syongari		goto fail;
1210170589Syongari	}
1211170589Syongari
1212170589Syongari	/* Create DMA tag for jumbo Rx buffers. */
1213170589Syongari	error = bus_dma_tag_create(sc->nfe_parent_tag,
1214192706Syongari	    1, 0,				/* alignment, boundary */
1215170589Syongari	    BUS_SPACE_MAXADDR,			/* lowaddr */
1216170589Syongari	    BUS_SPACE_MAXADDR,			/* highaddr */
1217170589Syongari	    NULL, NULL,				/* filter, filterarg */
1218176859Syongari	    MJUM9BYTES,				/* maxsize */
1219170589Syongari	    1,					/* nsegments */
1220176859Syongari	    MJUM9BYTES,				/* maxsegsize */
1221170589Syongari	    0,					/* flags */
1222170589Syongari	    NULL, NULL,				/* lockfunc, lockarg */
1223170589Syongari	    &ring->jrx_data_tag);
1224170589Syongari	if (error != 0) {
1225170589Syongari		device_printf(sc->nfe_dev,
1226170589Syongari		    "could not create jumbo Rx buffer DMA tag\n");
1227170589Syongari		goto fail;
1228170589Syongari	}
1229170589Syongari
1230170589Syongari	/* Allocate DMA'able memory and load the DMA map for jumbo Rx ring. */
1231170589Syongari	error = bus_dmamem_alloc(ring->jrx_desc_tag, &desc, BUS_DMA_WAITOK |
1232170589Syongari	    BUS_DMA_COHERENT | BUS_DMA_ZERO, &ring->jrx_desc_map);
1233170589Syongari	if (error != 0) {
1234170589Syongari		device_printf(sc->nfe_dev,
1235170589Syongari		    "could not allocate DMA'able memory for jumbo Rx ring\n");
1236170589Syongari		goto fail;
1237170589Syongari	}
1238170589Syongari	if (sc->nfe_flags & NFE_40BIT_ADDR)
1239170589Syongari		ring->jdesc64 = desc;
1240170589Syongari	else
1241170589Syongari		ring->jdesc32 = desc;
1242170589Syongari
1243170589Syongari	ctx.nfe_busaddr = 0;
1244170589Syongari	error = bus_dmamap_load(ring->jrx_desc_tag, ring->jrx_desc_map, desc,
1245170589Syongari	    NFE_JUMBO_RX_RING_COUNT * descsize, nfe_dma_map_segs, &ctx, 0);
1246170589Syongari	if (error != 0) {
1247170589Syongari		device_printf(sc->nfe_dev,
1248170589Syongari		    "could not load DMA'able memory for jumbo Rx ring\n");
1249170589Syongari		goto fail;
1250170589Syongari	}
1251170589Syongari	ring->jphysaddr = ctx.nfe_busaddr;
1252170589Syongari
1253170589Syongari	/* Create DMA maps for jumbo Rx buffers. */
1254170589Syongari	error = bus_dmamap_create(ring->jrx_data_tag, 0, &ring->jrx_spare_map);
1255170589Syongari	if (error != 0) {
1256170589Syongari		device_printf(sc->nfe_dev,
1257170589Syongari		    "could not create jumbo Rx DMA spare map\n");
1258170589Syongari		goto fail;
1259170589Syongari	}
1260170589Syongari
1261170589Syongari	for (i = 0; i < NFE_JUMBO_RX_RING_COUNT; i++) {
1262170589Syongari		data = &sc->jrxq.jdata[i];
1263170589Syongari		data->rx_data_map = NULL;
1264170589Syongari		data->m = NULL;
1265170589Syongari		error = bus_dmamap_create(ring->jrx_data_tag, 0,
1266164651Sobrien		    &data->rx_data_map);
1267164651Sobrien		if (error != 0) {
1268170589Syongari			device_printf(sc->nfe_dev,
1269170589Syongari			    "could not create jumbo Rx DMA map\n");
1270164651Sobrien			goto fail;
1271164651Sobrien		}
1272170589Syongari	}
1273159967Sobrien
1274171559Syongari	return;
1275159967Sobrien
1276170589Syongarifail:
1277171559Syongari	/*
1278171559Syongari	 * Running without jumbo frame support is ok for most cases
1279171559Syongari	 * so don't fail on creating dma tag/map for jumbo frame.
1280171559Syongari	 */
1281170589Syongari	nfe_free_jrx_ring(sc, ring);
1282171559Syongari	device_printf(sc->nfe_dev, "disabling jumbo frame support due to "
1283171559Syongari	    "resource shortage\n");
1284171559Syongari	sc->nfe_jumbo_disable = 1;
1285170589Syongari}
1286159967Sobrien
1287159967Sobrien
1288170589Syongaristatic int
1289170589Syongarinfe_init_rx_ring(struct nfe_softc *sc, struct nfe_rx_ring *ring)
1290170589Syongari{
1291170589Syongari	void *desc;
1292170589Syongari	size_t descsize;
1293170589Syongari	int i;
1294159967Sobrien
1295170589Syongari	ring->cur = ring->next = 0;
1296170589Syongari	if (sc->nfe_flags & NFE_40BIT_ADDR) {
1297170589Syongari		desc = ring->desc64;
1298170589Syongari		descsize = sizeof (struct nfe_desc64);
1299170589Syongari	} else {
1300170589Syongari		desc = ring->desc32;
1301170589Syongari		descsize = sizeof (struct nfe_desc32);
1302159967Sobrien	}
1303170589Syongari	bzero(desc, descsize * NFE_RX_RING_COUNT);
1304170589Syongari	for (i = 0; i < NFE_RX_RING_COUNT; i++) {
1305170589Syongari		if (nfe_newbuf(sc, i) != 0)
1306170589Syongari			return (ENOBUFS);
1307170589Syongari	}
1308159967Sobrien
1309163503Sobrien	bus_dmamap_sync(ring->rx_desc_tag, ring->rx_desc_map,
1310170589Syongari	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1311159967Sobrien
1312170589Syongari	return (0);
1313159967Sobrien}
1314159967Sobrien
1315163503Sobrien
1316170589Syongaristatic int
1317170589Syongarinfe_init_jrx_ring(struct nfe_softc *sc, struct nfe_jrx_ring *ring)
1318159967Sobrien{
1319170589Syongari	void *desc;
1320170589Syongari	size_t descsize;
1321159967Sobrien	int i;
1322159967Sobrien
1323170589Syongari	ring->jcur = ring->jnext = 0;
1324170589Syongari	if (sc->nfe_flags & NFE_40BIT_ADDR) {
1325170589Syongari		desc = ring->jdesc64;
1326170589Syongari		descsize = sizeof (struct nfe_desc64);
1327170589Syongari	} else {
1328170589Syongari		desc = ring->jdesc32;
1329170589Syongari		descsize = sizeof (struct nfe_desc32);
1330159952Sobrien	}
1331176859Syongari	bzero(desc, descsize * NFE_JUMBO_RX_RING_COUNT);
1332170589Syongari	for (i = 0; i < NFE_JUMBO_RX_RING_COUNT; i++) {
1333170589Syongari		if (nfe_jnewbuf(sc, i) != 0)
1334170589Syongari			return (ENOBUFS);
1335170589Syongari	}
1336159952Sobrien
1337170589Syongari	bus_dmamap_sync(ring->jrx_desc_tag, ring->jrx_desc_map,
1338170589Syongari	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1339159952Sobrien
1340170589Syongari	return (0);
1341159967Sobrien}
1342159967Sobrien
1343159967Sobrien
1344159967Sobrienstatic void
1345159967Sobriennfe_free_rx_ring(struct nfe_softc *sc, struct nfe_rx_ring *ring)
1346159967Sobrien{
1347159967Sobrien	struct nfe_rx_data *data;
1348159967Sobrien	void *desc;
1349159967Sobrien	int i, descsize;
1350159967Sobrien
1351159967Sobrien	if (sc->nfe_flags & NFE_40BIT_ADDR) {
1352159967Sobrien		desc = ring->desc64;
1353159967Sobrien		descsize = sizeof (struct nfe_desc64);
1354159967Sobrien	} else {
1355159967Sobrien		desc = ring->desc32;
1356159967Sobrien		descsize = sizeof (struct nfe_desc32);
1357159952Sobrien	}
1358159952Sobrien
1359170589Syongari	for (i = 0; i < NFE_RX_RING_COUNT; i++) {
1360170589Syongari		data = &ring->data[i];
1361170589Syongari		if (data->rx_data_map != NULL) {
1362170589Syongari			bus_dmamap_destroy(ring->rx_data_tag,
1363170589Syongari			    data->rx_data_map);
1364170589Syongari			data->rx_data_map = NULL;
1365170589Syongari		}
1366170589Syongari		if (data->m != NULL) {
1367170589Syongari			m_freem(data->m);
1368170589Syongari			data->m = NULL;
1369170589Syongari		}
1370170589Syongari	}
1371170589Syongari	if (ring->rx_data_tag != NULL) {
1372170589Syongari		if (ring->rx_spare_map != NULL) {
1373170589Syongari			bus_dmamap_destroy(ring->rx_data_tag,
1374170589Syongari			    ring->rx_spare_map);
1375170589Syongari			ring->rx_spare_map = NULL;
1376170589Syongari		}
1377170589Syongari		bus_dma_tag_destroy(ring->rx_data_tag);
1378170589Syongari		ring->rx_data_tag = NULL;
1379170589Syongari	}
1380170589Syongari
1381159967Sobrien	if (desc != NULL) {
1382159967Sobrien		bus_dmamap_unload(ring->rx_desc_tag, ring->rx_desc_map);
1383159967Sobrien		bus_dmamem_free(ring->rx_desc_tag, desc, ring->rx_desc_map);
1384170589Syongari		ring->desc64 = NULL;
1385170589Syongari		ring->desc32 = NULL;
1386170589Syongari		ring->rx_desc_map = NULL;
1387170589Syongari	}
1388170589Syongari	if (ring->rx_desc_tag != NULL) {
1389159967Sobrien		bus_dma_tag_destroy(ring->rx_desc_tag);
1390170589Syongari		ring->rx_desc_tag = NULL;
1391159967Sobrien	}
1392170589Syongari}
1393159967Sobrien
1394164650Sobrien
1395170589Syongaristatic void
1396170589Syongarinfe_free_jrx_ring(struct nfe_softc *sc, struct nfe_jrx_ring *ring)
1397170589Syongari{
1398170589Syongari	struct nfe_rx_data *data;
1399170589Syongari	void *desc;
1400170589Syongari	int i, descsize;
1401170589Syongari
1402170589Syongari	if ((sc->nfe_flags & NFE_JUMBO_SUP) == 0)
1403170589Syongari		return;
1404170589Syongari
1405170589Syongari	if (sc->nfe_flags & NFE_40BIT_ADDR) {
1406170589Syongari		desc = ring->jdesc64;
1407170589Syongari		descsize = sizeof (struct nfe_desc64);
1408170589Syongari	} else {
1409170589Syongari		desc = ring->jdesc32;
1410170589Syongari		descsize = sizeof (struct nfe_desc32);
1411170589Syongari	}
1412170589Syongari
1413170589Syongari	for (i = 0; i < NFE_JUMBO_RX_RING_COUNT; i++) {
1414170589Syongari		data = &ring->jdata[i];
1415164651Sobrien		if (data->rx_data_map != NULL) {
1416170589Syongari			bus_dmamap_destroy(ring->jrx_data_tag,
1417164651Sobrien			    data->rx_data_map);
1418170589Syongari			data->rx_data_map = NULL;
1419164651Sobrien		}
1420170589Syongari		if (data->m != NULL) {
1421164651Sobrien			m_freem(data->m);
1422170589Syongari			data->m = NULL;
1423170589Syongari		}
1424164651Sobrien	}
1425170589Syongari	if (ring->jrx_data_tag != NULL) {
1426170589Syongari		if (ring->jrx_spare_map != NULL) {
1427170589Syongari			bus_dmamap_destroy(ring->jrx_data_tag,
1428170589Syongari			    ring->jrx_spare_map);
1429170589Syongari			ring->jrx_spare_map = NULL;
1430170589Syongari		}
1431170589Syongari		bus_dma_tag_destroy(ring->jrx_data_tag);
1432170589Syongari		ring->jrx_data_tag = NULL;
1433170589Syongari	}
1434170589Syongari
1435170589Syongari	if (desc != NULL) {
1436170589Syongari		bus_dmamap_unload(ring->jrx_desc_tag, ring->jrx_desc_map);
1437170589Syongari		bus_dmamem_free(ring->jrx_desc_tag, desc, ring->jrx_desc_map);
1438170589Syongari		ring->jdesc64 = NULL;
1439170589Syongari		ring->jdesc32 = NULL;
1440170589Syongari		ring->jrx_desc_map = NULL;
1441170589Syongari	}
1442176859Syongari
1443170589Syongari	if (ring->jrx_desc_tag != NULL) {
1444170589Syongari		bus_dma_tag_destroy(ring->jrx_desc_tag);
1445170589Syongari		ring->jrx_desc_tag = NULL;
1446170589Syongari	}
1447159952Sobrien}
1448159952Sobrien
1449163503Sobrien
1450159967Sobrienstatic int
1451159967Sobriennfe_alloc_tx_ring(struct nfe_softc *sc, struct nfe_tx_ring *ring)
1452159952Sobrien{
1453170589Syongari	struct nfe_dmamap_arg ctx;
1454159967Sobrien	int i, error;
1455170589Syongari	void *desc;
1456159967Sobrien	int descsize;
1457159952Sobrien
1458159967Sobrien	if (sc->nfe_flags & NFE_40BIT_ADDR) {
1459170589Syongari		desc = ring->desc64;
1460159967Sobrien		descsize = sizeof (struct nfe_desc64);
1461159967Sobrien	} else {
1462170589Syongari		desc = ring->desc32;
1463159967Sobrien		descsize = sizeof (struct nfe_desc32);
1464159967Sobrien	}
1465159952Sobrien
1466159967Sobrien	ring->queued = 0;
1467159967Sobrien	ring->cur = ring->next = 0;
1468159967Sobrien
1469163503Sobrien	error = bus_dma_tag_create(sc->nfe_parent_tag,
1470170589Syongari	    NFE_RING_ALIGN, 0,			/* alignment, boundary */
1471170589Syongari	    BUS_SPACE_MAXADDR,			/* lowaddr */
1472170589Syongari	    BUS_SPACE_MAXADDR,			/* highaddr */
1473170589Syongari	    NULL, NULL,				/* filter, filterarg */
1474170589Syongari	    NFE_TX_RING_COUNT * descsize, 1,	/* maxsize, nsegments */
1475170589Syongari	    NFE_TX_RING_COUNT * descsize,	/* maxsegsize */
1476170589Syongari	    0,					/* flags */
1477170589Syongari	    NULL, NULL,				/* lockfunc, lockarg */
1478170589Syongari	    &ring->tx_desc_tag);
1479159967Sobrien	if (error != 0) {
1480170589Syongari		device_printf(sc->nfe_dev, "could not create desc DMA tag\n");
1481159967Sobrien		goto fail;
1482159952Sobrien	}
1483159952Sobrien
1484170589Syongari	error = bus_dmamem_alloc(ring->tx_desc_tag, &desc, BUS_DMA_WAITOK |
1485170589Syongari	    BUS_DMA_COHERENT | BUS_DMA_ZERO, &ring->tx_desc_map);
1486159967Sobrien	if (error != 0) {
1487170589Syongari		device_printf(sc->nfe_dev, "could not create desc DMA map\n");
1488159967Sobrien		goto fail;
1489159967Sobrien	}
1490170589Syongari	if (sc->nfe_flags & NFE_40BIT_ADDR)
1491170589Syongari		ring->desc64 = desc;
1492170589Syongari	else
1493170589Syongari		ring->desc32 = desc;
1494159967Sobrien
1495170589Syongari	ctx.nfe_busaddr = 0;
1496170589Syongari	error = bus_dmamap_load(ring->tx_desc_tag, ring->tx_desc_map, desc,
1497170589Syongari	    NFE_TX_RING_COUNT * descsize, nfe_dma_map_segs, &ctx, 0);
1498159967Sobrien	if (error != 0) {
1499170589Syongari		device_printf(sc->nfe_dev, "could not load desc DMA map\n");
1500159967Sobrien		goto fail;
1501159967Sobrien	}
1502170589Syongari	ring->physaddr = ctx.nfe_busaddr;
1503159967Sobrien
1504163503Sobrien	error = bus_dma_tag_create(sc->nfe_parent_tag,
1505170589Syongari	    1, 0,
1506170589Syongari	    BUS_SPACE_MAXADDR,
1507170589Syongari	    BUS_SPACE_MAXADDR,
1508170589Syongari	    NULL, NULL,
1509170595Syongari	    NFE_TSO_MAXSIZE,
1510170589Syongari	    NFE_MAX_SCATTER,
1511170595Syongari	    NFE_TSO_MAXSGSIZE,
1512170589Syongari	    0,
1513170589Syongari	    NULL, NULL,
1514170589Syongari	    &ring->tx_data_tag);
1515159967Sobrien	if (error != 0) {
1516170589Syongari		device_printf(sc->nfe_dev, "could not create Tx DMA tag\n");
1517170589Syongari		goto fail;
1518159967Sobrien	}
1519159967Sobrien
1520159967Sobrien	for (i = 0; i < NFE_TX_RING_COUNT; i++) {
1521163503Sobrien		error = bus_dmamap_create(ring->tx_data_tag, 0,
1522163503Sobrien		    &ring->data[i].tx_data_map);
1523159967Sobrien		if (error != 0) {
1524170589Syongari			device_printf(sc->nfe_dev,
1525170589Syongari			    "could not create Tx DMA map\n");
1526159967Sobrien			goto fail;
1527159967Sobrien		}
1528159967Sobrien	}
1529159967Sobrien
1530170589Syongarifail:
1531170589Syongari	return (error);
1532159967Sobrien}
1533159967Sobrien
1534159967Sobrien
1535159967Sobrienstatic void
1536170589Syongarinfe_init_tx_ring(struct nfe_softc *sc, struct nfe_tx_ring *ring)
1537159967Sobrien{
1538170589Syongari	void *desc;
1539170589Syongari	size_t descsize;
1540159967Sobrien
1541170589Syongari	sc->nfe_force_tx = 0;
1542170589Syongari	ring->queued = 0;
1543170589Syongari	ring->cur = ring->next = 0;
1544170589Syongari	if (sc->nfe_flags & NFE_40BIT_ADDR) {
1545170589Syongari		desc = ring->desc64;
1546170589Syongari		descsize = sizeof (struct nfe_desc64);
1547170589Syongari	} else {
1548170589Syongari		desc = ring->desc32;
1549170589Syongari		descsize = sizeof (struct nfe_desc32);
1550159967Sobrien	}
1551170589Syongari	bzero(desc, descsize * NFE_TX_RING_COUNT);
1552159967Sobrien
1553163503Sobrien	bus_dmamap_sync(ring->tx_desc_tag, ring->tx_desc_map,
1554170589Syongari	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1555159967Sobrien}
1556159967Sobrien
1557163503Sobrien
1558159967Sobrienstatic void
1559159967Sobriennfe_free_tx_ring(struct nfe_softc *sc, struct nfe_tx_ring *ring)
1560159967Sobrien{
1561159967Sobrien	struct nfe_tx_data *data;
1562159967Sobrien	void *desc;
1563159967Sobrien	int i, descsize;
1564159967Sobrien
1565159967Sobrien	if (sc->nfe_flags & NFE_40BIT_ADDR) {
1566159967Sobrien		desc = ring->desc64;
1567159967Sobrien		descsize = sizeof (struct nfe_desc64);
1568159967Sobrien	} else {
1569159967Sobrien		desc = ring->desc32;
1570159967Sobrien		descsize = sizeof (struct nfe_desc32);
1571159967Sobrien	}
1572159967Sobrien
1573159967Sobrien	for (i = 0; i < NFE_TX_RING_COUNT; i++) {
1574159967Sobrien		data = &ring->data[i];
1575159967Sobrien
1576159967Sobrien		if (data->m != NULL) {
1577170589Syongari			bus_dmamap_sync(ring->tx_data_tag, data->tx_data_map,
1578163503Sobrien			    BUS_DMASYNC_POSTWRITE);
1579170589Syongari			bus_dmamap_unload(ring->tx_data_tag, data->tx_data_map);
1580159967Sobrien			m_freem(data->m);
1581170589Syongari			data->m = NULL;
1582159967Sobrien		}
1583170589Syongari		if (data->tx_data_map != NULL) {
1584170589Syongari			bus_dmamap_destroy(ring->tx_data_tag,
1585170589Syongari			    data->tx_data_map);
1586170589Syongari			data->tx_data_map = NULL;
1587170589Syongari		}
1588159967Sobrien	}
1589159967Sobrien
1590170589Syongari	if (ring->tx_data_tag != NULL) {
1591170589Syongari		bus_dma_tag_destroy(ring->tx_data_tag);
1592170589Syongari		ring->tx_data_tag = NULL;
1593159967Sobrien	}
1594159967Sobrien
1595170589Syongari	if (desc != NULL) {
1596170589Syongari		bus_dmamap_sync(ring->tx_desc_tag, ring->tx_desc_map,
1597170589Syongari		    BUS_DMASYNC_POSTWRITE);
1598170589Syongari		bus_dmamap_unload(ring->tx_desc_tag, ring->tx_desc_map);
1599170589Syongari		bus_dmamem_free(ring->tx_desc_tag, desc, ring->tx_desc_map);
1600170589Syongari		ring->desc64 = NULL;
1601170589Syongari		ring->desc32 = NULL;
1602170589Syongari		ring->tx_desc_map = NULL;
1603170589Syongari		bus_dma_tag_destroy(ring->tx_desc_tag);
1604170589Syongari		ring->tx_desc_tag = NULL;
1605170589Syongari	}
1606159967Sobrien}
1607159967Sobrien
1608159967Sobrien#ifdef DEVICE_POLLING
1609159967Sobrienstatic poll_handler_t nfe_poll;
1610159967Sobrien
1611163503Sobrien
1612193096Sattiliostatic int
1613159967Sobriennfe_poll(struct ifnet *ifp, enum poll_cmd cmd, int count)
1614159967Sobrien{
1615164360Sobrien	struct nfe_softc *sc = ifp->if_softc;
1616170589Syongari	uint32_t r;
1617193096Sattilio	int rx_npkts = 0;
1618159967Sobrien
1619159967Sobrien	NFE_LOCK(sc);
1620159967Sobrien
1621159967Sobrien	if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) {
1622170589Syongari		NFE_UNLOCK(sc);
1623193096Sattilio		return (rx_npkts);
1624159967Sobrien	}
1625159967Sobrien
1626171559Syongari	if (sc->nfe_framesize > MCLBYTES - ETHER_HDR_LEN)
1627193096Sattilio		rx_npkts = nfe_jrxeof(sc, count, &rx_npkts);
1628171559Syongari	else
1629193096Sattilio		rx_npkts = nfe_rxeof(sc, count, &rx_npkts);
1630159967Sobrien	nfe_txeof(sc);
1631159967Sobrien	if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
1632216925Sjhb		nfe_start_locked(ifp);
1633159967Sobrien
1634159967Sobrien	if (cmd == POLL_AND_CHECK_STATUS) {
1635170589Syongari		if ((r = NFE_READ(sc, sc->nfe_irq_status)) == 0) {
1636170589Syongari			NFE_UNLOCK(sc);
1637193096Sattilio			return (rx_npkts);
1638163503Sobrien		}
1639170589Syongari		NFE_WRITE(sc, sc->nfe_irq_status, r);
1640159967Sobrien
1641163503Sobrien		if (r & NFE_IRQ_LINK) {
1642163503Sobrien			NFE_READ(sc, NFE_PHY_STATUS);
1643163503Sobrien			NFE_WRITE(sc, NFE_PHY_STATUS, 0xf);
1644170589Syongari			DPRINTF(sc, "link state changed\n");
1645163503Sobrien		}
1646159967Sobrien	}
1647170589Syongari	NFE_UNLOCK(sc);
1648193096Sattilio	return (rx_npkts);
1649159967Sobrien}
1650159967Sobrien#endif /* DEVICE_POLLING */
1651159967Sobrien
1652170589Syongaristatic void
1653170589Syongarinfe_set_intr(struct nfe_softc *sc)
1654170589Syongari{
1655159967Sobrien
1656170589Syongari	if (sc->nfe_msi != 0)
1657170589Syongari		NFE_WRITE(sc, NFE_IRQ_MASK, NFE_IRQ_WANTED);
1658170589Syongari}
1659170589Syongari
1660170589Syongari
1661170589Syongari/* In MSIX, a write to mask reegisters behaves as XOR. */
1662170589Syongaristatic __inline void
1663170589Syongarinfe_enable_intr(struct nfe_softc *sc)
1664170589Syongari{
1665170589Syongari
1666170589Syongari	if (sc->nfe_msix != 0) {
1667170589Syongari		/* XXX Should have a better way to enable interrupts! */
1668170589Syongari		if (NFE_READ(sc, sc->nfe_irq_mask) == 0)
1669170589Syongari			NFE_WRITE(sc, sc->nfe_irq_mask, sc->nfe_intrs);
1670170589Syongari	} else
1671170589Syongari		NFE_WRITE(sc, sc->nfe_irq_mask, sc->nfe_intrs);
1672170589Syongari}
1673170589Syongari
1674170589Syongari
1675170589Syongaristatic __inline void
1676170589Syongarinfe_disable_intr(struct nfe_softc *sc)
1677170589Syongari{
1678170589Syongari
1679170589Syongari	if (sc->nfe_msix != 0) {
1680170589Syongari		/* XXX Should have a better way to disable interrupts! */
1681170589Syongari		if (NFE_READ(sc, sc->nfe_irq_mask) != 0)
1682170589Syongari			NFE_WRITE(sc, sc->nfe_irq_mask, sc->nfe_nointrs);
1683170589Syongari	} else
1684170589Syongari		NFE_WRITE(sc, sc->nfe_irq_mask, sc->nfe_nointrs);
1685170589Syongari}
1686170589Syongari
1687170589Syongari
1688159967Sobrienstatic int
1689159967Sobriennfe_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
1690159967Sobrien{
1691170589Syongari	struct nfe_softc *sc;
1692170589Syongari	struct ifreq *ifr;
1693163503Sobrien	struct mii_data *mii;
1694170589Syongari	int error, init, mask;
1695159967Sobrien
1696170589Syongari	sc = ifp->if_softc;
1697170589Syongari	ifr = (struct ifreq *) data;
1698170589Syongari	error = 0;
1699170589Syongari	init = 0;
1700159952Sobrien	switch (cmd) {
1701159952Sobrien	case SIOCSIFMTU:
1702170589Syongari		if (ifr->ifr_mtu < ETHERMIN || ifr->ifr_mtu > NFE_JUMBO_MTU)
1703159952Sobrien			error = EINVAL;
1704170589Syongari		else if (ifp->if_mtu != ifr->ifr_mtu) {
1705171559Syongari			if ((((sc->nfe_flags & NFE_JUMBO_SUP) == 0) ||
1706171559Syongari			    (sc->nfe_jumbo_disable != 0)) &&
1707170589Syongari			    ifr->ifr_mtu > ETHERMTU)
1708170589Syongari				error = EINVAL;
1709170589Syongari			else {
1710170589Syongari				NFE_LOCK(sc);
1711170589Syongari				ifp->if_mtu = ifr->ifr_mtu;
1712217794Syongari				if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
1713217794Syongari					ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
1714170589Syongari					nfe_init_locked(sc);
1715217794Syongari				}
1716170589Syongari				NFE_UNLOCK(sc);
1717164650Sobrien			}
1718164650Sobrien		}
1719159952Sobrien		break;
1720159952Sobrien	case SIOCSIFFLAGS:
1721159967Sobrien		NFE_LOCK(sc);
1722159952Sobrien		if (ifp->if_flags & IFF_UP) {
1723159952Sobrien			/*
1724159952Sobrien			 * If only the PROMISC or ALLMULTI flag changes, then
1725159952Sobrien			 * don't do a full re-init of the chip, just update
1726159952Sobrien			 * the Rx filter.
1727159952Sobrien			 */
1728159967Sobrien			if ((ifp->if_drv_flags & IFF_DRV_RUNNING) &&
1729159967Sobrien			    ((ifp->if_flags ^ sc->nfe_if_flags) &
1730159967Sobrien			     (IFF_ALLMULTI | IFF_PROMISC)) != 0)
1731159952Sobrien				nfe_setmulti(sc);
1732159967Sobrien			else
1733159967Sobrien				nfe_init_locked(sc);
1734159952Sobrien		} else {
1735159967Sobrien			if (ifp->if_drv_flags & IFF_DRV_RUNNING)
1736170589Syongari				nfe_stop(ifp);
1737159952Sobrien		}
1738159967Sobrien		sc->nfe_if_flags = ifp->if_flags;
1739159967Sobrien		NFE_UNLOCK(sc);
1740159967Sobrien		error = 0;
1741159952Sobrien		break;
1742159952Sobrien	case SIOCADDMULTI:
1743159952Sobrien	case SIOCDELMULTI:
1744170589Syongari		if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) {
1745159967Sobrien			NFE_LOCK(sc);
1746159967Sobrien			nfe_setmulti(sc);
1747159967Sobrien			NFE_UNLOCK(sc);
1748159952Sobrien			error = 0;
1749159952Sobrien		}
1750159952Sobrien		break;
1751159952Sobrien	case SIOCSIFMEDIA:
1752159952Sobrien	case SIOCGIFMEDIA:
1753159967Sobrien		mii = device_get_softc(sc->nfe_miibus);
1754159967Sobrien		error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, cmd);
1755159952Sobrien		break;
1756159967Sobrien	case SIOCSIFCAP:
1757170589Syongari		mask = ifr->ifr_reqcap ^ ifp->if_capenable;
1758159967Sobrien#ifdef DEVICE_POLLING
1759170589Syongari		if ((mask & IFCAP_POLLING) != 0) {
1760170589Syongari			if ((ifr->ifr_reqcap & IFCAP_POLLING) != 0) {
1761159967Sobrien				error = ether_poll_register(nfe_poll, ifp);
1762159967Sobrien				if (error)
1763170589Syongari					break;
1764159967Sobrien				NFE_LOCK(sc);
1765170589Syongari				nfe_disable_intr(sc);
1766163503Sobrien				ifp->if_capenable |= IFCAP_POLLING;
1767159967Sobrien				NFE_UNLOCK(sc);
1768159967Sobrien			} else {
1769159967Sobrien				error = ether_poll_deregister(ifp);
1770159967Sobrien				/* Enable interrupt even in error case */
1771159967Sobrien				NFE_LOCK(sc);
1772170589Syongari				nfe_enable_intr(sc);
1773159967Sobrien				ifp->if_capenable &= ~IFCAP_POLLING;
1774159967Sobrien				NFE_UNLOCK(sc);
1775159967Sobrien			}
1776159967Sobrien		}
1777163503Sobrien#endif /* DEVICE_POLLING */
1778215132Syongari		if ((mask & IFCAP_WOL_MAGIC) != 0 &&
1779215132Syongari		    (ifp->if_capabilities & IFCAP_WOL_MAGIC) != 0)
1780215132Syongari			ifp->if_capenable ^= IFCAP_WOL_MAGIC;
1781215432Syongari		if ((mask & IFCAP_TXCSUM) != 0 &&
1782215432Syongari		    (ifp->if_capabilities & IFCAP_TXCSUM) != 0) {
1783215432Syongari			ifp->if_capenable ^= IFCAP_TXCSUM;
1784215432Syongari			if ((ifp->if_capenable & IFCAP_TXCSUM) != 0)
1785170589Syongari				ifp->if_hwassist |= NFE_CSUM_FEATURES;
1786159967Sobrien			else
1787170589Syongari				ifp->if_hwassist &= ~NFE_CSUM_FEATURES;
1788215432Syongari		}
1789215432Syongari		if ((mask & IFCAP_RXCSUM) != 0 &&
1790215432Syongari		    (ifp->if_capabilities & IFCAP_RXCSUM) != 0) {
1791215432Syongari			ifp->if_capenable ^= IFCAP_RXCSUM;
1792170589Syongari			init++;
1793159967Sobrien		}
1794215432Syongari		if ((mask & IFCAP_TSO4) != 0 &&
1795215432Syongari		    (ifp->if_capabilities & IFCAP_TSO4) != 0) {
1796215432Syongari			ifp->if_capenable ^= IFCAP_TSO4;
1797215432Syongari			if ((IFCAP_TSO4 & ifp->if_capenable) != 0)
1798215432Syongari				ifp->if_hwassist |= CSUM_TSO;
1799215432Syongari			else
1800215432Syongari				ifp->if_hwassist &= ~CSUM_TSO;
1801215432Syongari		}
1802215432Syongari		if ((mask & IFCAP_VLAN_HWTSO) != 0 &&
1803215432Syongari		    (ifp->if_capabilities & IFCAP_VLAN_HWTSO) != 0)
1804215432Syongari			ifp->if_capenable ^= IFCAP_VLAN_HWTSO;
1805215432Syongari		if ((mask & IFCAP_VLAN_HWTAGGING) != 0 &&
1806215432Syongari		    (ifp->if_capabilities & IFCAP_VLAN_HWTAGGING) != 0) {
1807170589Syongari			ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING;
1808215432Syongari			if ((ifp->if_capenable & IFCAP_VLAN_HWTAGGING) == 0)
1809215432Syongari				ifp->if_capenable &= ~IFCAP_VLAN_HWTSO;
1810170589Syongari			init++;
1811170589Syongari		}
1812170589Syongari		/*
1813170589Syongari		 * XXX
1814170589Syongari		 * It seems that VLAN stripping requires Rx checksum offload.
1815170589Syongari		 * Unfortunately FreeBSD has no way to disable only Rx side
1816170589Syongari		 * VLAN stripping. So when we know Rx checksum offload is
1817170589Syongari		 * disabled turn entire hardware VLAN assist off.
1818170589Syongari		 */
1819215432Syongari		if ((ifp->if_capenable & IFCAP_RXCSUM) == 0) {
1820215432Syongari			if ((ifp->if_capenable & IFCAP_VLAN_HWTAGGING) != 0)
1821215432Syongari				init++;
1822215432Syongari			ifp->if_capenable &= ~(IFCAP_VLAN_HWTAGGING |
1823215432Syongari			    IFCAP_VLAN_HWTSO);
1824170589Syongari		}
1825170589Syongari		if (init > 0 && (ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) {
1826170589Syongari			ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
1827164656Sobrien			nfe_init(sc);
1828170589Syongari		}
1829215432Syongari		VLAN_CAPABILITIES(ifp);
1830159967Sobrien		break;
1831159952Sobrien	default:
1832159967Sobrien		error = ether_ioctl(ifp, cmd, data);
1833159967Sobrien		break;
1834159952Sobrien	}
1835159952Sobrien
1836170589Syongari	return (error);
1837159952Sobrien}
1838159952Sobrien
1839159967Sobrien
1840170589Syongaristatic int
1841163503Sobriennfe_intr(void *arg)
1842159967Sobrien{
1843170589Syongari	struct nfe_softc *sc;
1844170589Syongari	uint32_t status;
1845170589Syongari
1846170589Syongari	sc = (struct nfe_softc *)arg;
1847170589Syongari
1848170589Syongari	status = NFE_READ(sc, sc->nfe_irq_status);
1849170589Syongari	if (status == 0 || status == 0xffffffff)
1850170589Syongari		return (FILTER_STRAY);
1851170589Syongari	nfe_disable_intr(sc);
1852173674Ssam	taskqueue_enqueue_fast(sc->nfe_tq, &sc->nfe_int_task);
1853170589Syongari
1854170589Syongari	return (FILTER_HANDLED);
1855170589Syongari}
1856170589Syongari
1857170589Syongari
1858170589Syongaristatic void
1859170589Syongarinfe_int_task(void *arg, int pending)
1860170589Syongari{
1861159967Sobrien	struct nfe_softc *sc = arg;
1862159967Sobrien	struct ifnet *ifp = sc->nfe_ifp;
1863170589Syongari	uint32_t r;
1864170589Syongari	int domore;
1865159967Sobrien
1866163503Sobrien	NFE_LOCK(sc);
1867159967Sobrien
1868170589Syongari	if ((r = NFE_READ(sc, sc->nfe_irq_status)) == 0) {
1869170589Syongari		nfe_enable_intr(sc);
1870170589Syongari		NFE_UNLOCK(sc);
1871170589Syongari		return;	/* not for us */
1872170589Syongari	}
1873170589Syongari	NFE_WRITE(sc, sc->nfe_irq_status, r);
1874170589Syongari
1875170589Syongari	DPRINTFN(sc, 5, "nfe_intr: interrupt register %x\n", r);
1876170589Syongari
1877159967Sobrien#ifdef DEVICE_POLLING
1878159967Sobrien	if (ifp->if_capenable & IFCAP_POLLING) {
1879159967Sobrien		NFE_UNLOCK(sc);
1880159967Sobrien		return;
1881159967Sobrien	}
1882159967Sobrien#endif
1883159967Sobrien
1884172169Syongari	if (r & NFE_IRQ_LINK) {
1885172169Syongari		NFE_READ(sc, NFE_PHY_STATUS);
1886172169Syongari		NFE_WRITE(sc, NFE_PHY_STATUS, 0xf);
1887172169Syongari		DPRINTF(sc, "link state changed\n");
1888172169Syongari	}
1889172169Syongari
1890170589Syongari	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) {
1891163503Sobrien		NFE_UNLOCK(sc);
1892170589Syongari		nfe_enable_intr(sc);
1893170589Syongari		return;
1894159967Sobrien	}
1895159967Sobrien
1896170589Syongari	domore = 0;
1897170589Syongari	/* check Rx ring */
1898170589Syongari	if (sc->nfe_framesize > MCLBYTES - ETHER_HDR_LEN)
1899193096Sattilio		domore = nfe_jrxeof(sc, sc->nfe_process_limit, NULL);
1900170589Syongari	else
1901193096Sattilio		domore = nfe_rxeof(sc, sc->nfe_process_limit, NULL);
1902170589Syongari	/* check Tx ring */
1903170589Syongari	nfe_txeof(sc);
1904159967Sobrien
1905170589Syongari	if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
1906216925Sjhb		nfe_start_locked(ifp);
1907159967Sobrien
1908159967Sobrien	NFE_UNLOCK(sc);
1909159967Sobrien
1910170589Syongari	if (domore || (NFE_READ(sc, sc->nfe_irq_status) != 0)) {
1911173674Ssam		taskqueue_enqueue_fast(sc->nfe_tq, &sc->nfe_int_task);
1912170589Syongari		return;
1913170589Syongari	}
1914170589Syongari
1915170589Syongari	/* Reenable interrupts. */
1916170589Syongari	nfe_enable_intr(sc);
1917159967Sobrien}
1918159967Sobrien
1919163503Sobrien
1920170589Syongaristatic __inline void
1921170589Syongarinfe_discard_rxbuf(struct nfe_softc *sc, int idx)
1922159952Sobrien{
1923170589Syongari	struct nfe_desc32 *desc32;
1924170589Syongari	struct nfe_desc64 *desc64;
1925170589Syongari	struct nfe_rx_data *data;
1926170589Syongari	struct mbuf *m;
1927163503Sobrien
1928170589Syongari	data = &sc->rxq.data[idx];
1929170589Syongari	m = data->m;
1930170589Syongari
1931170589Syongari	if (sc->nfe_flags & NFE_40BIT_ADDR) {
1932170589Syongari		desc64 = &sc->rxq.desc64[idx];
1933170589Syongari		/* VLAN packet may have overwritten it. */
1934170589Syongari		desc64->physaddr[0] = htole32(NFE_ADDR_HI(data->paddr));
1935170589Syongari		desc64->physaddr[1] = htole32(NFE_ADDR_LO(data->paddr));
1936170589Syongari		desc64->length = htole16(m->m_len);
1937170589Syongari		desc64->flags = htole16(NFE_RX_READY);
1938170589Syongari	} else {
1939170589Syongari		desc32 = &sc->rxq.desc32[idx];
1940170589Syongari		desc32->length = htole16(m->m_len);
1941170589Syongari		desc32->flags = htole16(NFE_RX_READY);
1942170589Syongari	}
1943159952Sobrien}
1944159952Sobrien
1945163503Sobrien
1946170589Syongaristatic __inline void
1947170589Syongarinfe_discard_jrxbuf(struct nfe_softc *sc, int idx)
1948159952Sobrien{
1949170589Syongari	struct nfe_desc32 *desc32;
1950170589Syongari	struct nfe_desc64 *desc64;
1951170589Syongari	struct nfe_rx_data *data;
1952170589Syongari	struct mbuf *m;
1953163503Sobrien
1954170589Syongari	data = &sc->jrxq.jdata[idx];
1955170589Syongari	m = data->m;
1956170589Syongari
1957170589Syongari	if (sc->nfe_flags & NFE_40BIT_ADDR) {
1958170589Syongari		desc64 = &sc->jrxq.jdesc64[idx];
1959170589Syongari		/* VLAN packet may have overwritten it. */
1960170589Syongari		desc64->physaddr[0] = htole32(NFE_ADDR_HI(data->paddr));
1961170589Syongari		desc64->physaddr[1] = htole32(NFE_ADDR_LO(data->paddr));
1962170589Syongari		desc64->length = htole16(m->m_len);
1963170589Syongari		desc64->flags = htole16(NFE_RX_READY);
1964170589Syongari	} else {
1965170589Syongari		desc32 = &sc->jrxq.jdesc32[idx];
1966170589Syongari		desc32->length = htole16(m->m_len);
1967170589Syongari		desc32->flags = htole16(NFE_RX_READY);
1968170589Syongari	}
1969159952Sobrien}
1970159952Sobrien
1971163503Sobrien
1972170589Syongaristatic int
1973170589Syongarinfe_newbuf(struct nfe_softc *sc, int idx)
1974159952Sobrien{
1975170589Syongari	struct nfe_rx_data *data;
1976170589Syongari	struct nfe_desc32 *desc32;
1977170589Syongari	struct nfe_desc64 *desc64;
1978170589Syongari	struct mbuf *m;
1979170589Syongari	bus_dma_segment_t segs[1];
1980170589Syongari	bus_dmamap_t map;
1981170589Syongari	int nsegs;
1982163503Sobrien
1983170589Syongari	m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
1984170589Syongari	if (m == NULL)
1985170589Syongari		return (ENOBUFS);
1986159952Sobrien
1987170589Syongari	m->m_len = m->m_pkthdr.len = MCLBYTES;
1988170589Syongari	m_adj(m, ETHER_ALIGN);
1989163503Sobrien
1990170589Syongari	if (bus_dmamap_load_mbuf_sg(sc->rxq.rx_data_tag, sc->rxq.rx_spare_map,
1991170589Syongari	    m, segs, &nsegs, BUS_DMA_NOWAIT) != 0) {
1992170589Syongari		m_freem(m);
1993170589Syongari		return (ENOBUFS);
1994170589Syongari	}
1995170589Syongari	KASSERT(nsegs == 1, ("%s: %d segments returned!", __func__, nsegs));
1996163503Sobrien
1997170589Syongari	data = &sc->rxq.data[idx];
1998170589Syongari	if (data->m != NULL) {
1999170589Syongari		bus_dmamap_sync(sc->rxq.rx_data_tag, data->rx_data_map,
2000170589Syongari		    BUS_DMASYNC_POSTREAD);
2001170589Syongari		bus_dmamap_unload(sc->rxq.rx_data_tag, data->rx_data_map);
2002170589Syongari	}
2003170589Syongari	map = data->rx_data_map;
2004170589Syongari	data->rx_data_map = sc->rxq.rx_spare_map;
2005170589Syongari	sc->rxq.rx_spare_map = map;
2006170589Syongari	bus_dmamap_sync(sc->rxq.rx_data_tag, data->rx_data_map,
2007170589Syongari	    BUS_DMASYNC_PREREAD);
2008170589Syongari	data->paddr = segs[0].ds_addr;
2009170589Syongari	data->m = m;
2010170589Syongari	/* update mapping address in h/w descriptor */
2011170589Syongari	if (sc->nfe_flags & NFE_40BIT_ADDR) {
2012170589Syongari		desc64 = &sc->rxq.desc64[idx];
2013170589Syongari		desc64->physaddr[0] = htole32(NFE_ADDR_HI(segs[0].ds_addr));
2014170589Syongari		desc64->physaddr[1] = htole32(NFE_ADDR_LO(segs[0].ds_addr));
2015170589Syongari		desc64->length = htole16(segs[0].ds_len);
2016170589Syongari		desc64->flags = htole16(NFE_RX_READY);
2017170589Syongari	} else {
2018170589Syongari		desc32 = &sc->rxq.desc32[idx];
2019170589Syongari		desc32->physaddr = htole32(NFE_ADDR_LO(segs[0].ds_addr));
2020170589Syongari		desc32->length = htole16(segs[0].ds_len);
2021170589Syongari		desc32->flags = htole16(NFE_RX_READY);
2022170589Syongari	}
2023170589Syongari
2024170589Syongari	return (0);
2025159952Sobrien}
2026159952Sobrien
2027163503Sobrien
2028170589Syongaristatic int
2029170589Syongarinfe_jnewbuf(struct nfe_softc *sc, int idx)
2030159952Sobrien{
2031170589Syongari	struct nfe_rx_data *data;
2032170589Syongari	struct nfe_desc32 *desc32;
2033170589Syongari	struct nfe_desc64 *desc64;
2034170589Syongari	struct mbuf *m;
2035170589Syongari	bus_dma_segment_t segs[1];
2036170589Syongari	bus_dmamap_t map;
2037170589Syongari	int nsegs;
2038163503Sobrien
2039176859Syongari	m = m_getjcl(M_DONTWAIT, MT_DATA, M_PKTHDR, MJUM9BYTES);
2040170589Syongari	if (m == NULL)
2041170589Syongari		return (ENOBUFS);
2042170589Syongari	if ((m->m_flags & M_EXT) == 0) {
2043170589Syongari		m_freem(m);
2044170589Syongari		return (ENOBUFS);
2045170589Syongari	}
2046176859Syongari	m->m_pkthdr.len = m->m_len = MJUM9BYTES;
2047170589Syongari	m_adj(m, ETHER_ALIGN);
2048159952Sobrien
2049170589Syongari	if (bus_dmamap_load_mbuf_sg(sc->jrxq.jrx_data_tag,
2050170589Syongari	    sc->jrxq.jrx_spare_map, m, segs, &nsegs, BUS_DMA_NOWAIT) != 0) {
2051170589Syongari		m_freem(m);
2052170589Syongari		return (ENOBUFS);
2053170589Syongari	}
2054170589Syongari	KASSERT(nsegs == 1, ("%s: %d segments returned!", __func__, nsegs));
2055163503Sobrien
2056170589Syongari	data = &sc->jrxq.jdata[idx];
2057170589Syongari	if (data->m != NULL) {
2058170589Syongari		bus_dmamap_sync(sc->jrxq.jrx_data_tag, data->rx_data_map,
2059170589Syongari		    BUS_DMASYNC_POSTREAD);
2060170589Syongari		bus_dmamap_unload(sc->jrxq.jrx_data_tag, data->rx_data_map);
2061170589Syongari	}
2062170589Syongari	map = data->rx_data_map;
2063170589Syongari	data->rx_data_map = sc->jrxq.jrx_spare_map;
2064170589Syongari	sc->jrxq.jrx_spare_map = map;
2065170589Syongari	bus_dmamap_sync(sc->jrxq.jrx_data_tag, data->rx_data_map,
2066170589Syongari	    BUS_DMASYNC_PREREAD);
2067170589Syongari	data->paddr = segs[0].ds_addr;
2068170589Syongari	data->m = m;
2069170589Syongari	/* update mapping address in h/w descriptor */
2070170589Syongari	if (sc->nfe_flags & NFE_40BIT_ADDR) {
2071170589Syongari		desc64 = &sc->jrxq.jdesc64[idx];
2072170589Syongari		desc64->physaddr[0] = htole32(NFE_ADDR_HI(segs[0].ds_addr));
2073170589Syongari		desc64->physaddr[1] = htole32(NFE_ADDR_LO(segs[0].ds_addr));
2074170589Syongari		desc64->length = htole16(segs[0].ds_len);
2075170589Syongari		desc64->flags = htole16(NFE_RX_READY);
2076170589Syongari	} else {
2077170589Syongari		desc32 = &sc->jrxq.jdesc32[idx];
2078170589Syongari		desc32->physaddr = htole32(NFE_ADDR_LO(segs[0].ds_addr));
2079170589Syongari		desc32->length = htole16(segs[0].ds_len);
2080170589Syongari		desc32->flags = htole16(NFE_RX_READY);
2081170589Syongari	}
2082159967Sobrien
2083170589Syongari	return (0);
2084159952Sobrien}
2085159952Sobrien
2086163503Sobrien
2087170589Syongaristatic int
2088193096Sattilionfe_rxeof(struct nfe_softc *sc, int count, int *rx_npktsp)
2089159952Sobrien{
2090159967Sobrien	struct ifnet *ifp = sc->nfe_ifp;
2091170589Syongari	struct nfe_desc32 *desc32;
2092170589Syongari	struct nfe_desc64 *desc64;
2093159952Sobrien	struct nfe_rx_data *data;
2094170589Syongari	struct mbuf *m;
2095170589Syongari	uint16_t flags;
2096193096Sattilio	int len, prog, rx_npkts;
2097170589Syongari	uint32_t vtag = 0;
2098159952Sobrien
2099193096Sattilio	rx_npkts = 0;
2100159967Sobrien	NFE_LOCK_ASSERT(sc);
2101159967Sobrien
2102170589Syongari	bus_dmamap_sync(sc->rxq.rx_desc_tag, sc->rxq.rx_desc_map,
2103170589Syongari	    BUS_DMASYNC_POSTREAD);
2104159967Sobrien
2105170589Syongari	for (prog = 0;;NFE_INC(sc->rxq.cur, NFE_RX_RING_COUNT), vtag = 0) {
2106170589Syongari		if (count <= 0)
2107170589Syongari			break;
2108170589Syongari		count--;
2109159967Sobrien
2110159952Sobrien		data = &sc->rxq.data[sc->rxq.cur];
2111159952Sobrien
2112159967Sobrien		if (sc->nfe_flags & NFE_40BIT_ADDR) {
2113159952Sobrien			desc64 = &sc->rxq.desc64[sc->rxq.cur];
2114170589Syongari			vtag = le32toh(desc64->physaddr[1]);
2115170589Syongari			flags = le16toh(desc64->flags);
2116170589Syongari			len = le16toh(desc64->length) & NFE_RX_LEN_MASK;
2117159952Sobrien		} else {
2118159952Sobrien			desc32 = &sc->rxq.desc32[sc->rxq.cur];
2119170589Syongari			flags = le16toh(desc32->flags);
2120170589Syongari			len = le16toh(desc32->length) & NFE_RX_LEN_MASK;
2121159952Sobrien		}
2122159952Sobrien
2123159952Sobrien		if (flags & NFE_RX_READY)
2124159952Sobrien			break;
2125170589Syongari		prog++;
2126159967Sobrien		if ((sc->nfe_flags & (NFE_JUMBO_SUP | NFE_40BIT_ADDR)) == 0) {
2127170589Syongari			if (!(flags & NFE_RX_VALID_V1)) {
2128170589Syongari				ifp->if_ierrors++;
2129170589Syongari				nfe_discard_rxbuf(sc, sc->rxq.cur);
2130170589Syongari				continue;
2131170589Syongari			}
2132159952Sobrien			if ((flags & NFE_RX_FIXME_V1) == NFE_RX_FIXME_V1) {
2133159952Sobrien				flags &= ~NFE_RX_ERROR;
2134159952Sobrien				len--;	/* fix buffer length */
2135159952Sobrien			}
2136159952Sobrien		} else {
2137170589Syongari			if (!(flags & NFE_RX_VALID_V2)) {
2138170589Syongari				ifp->if_ierrors++;
2139170589Syongari				nfe_discard_rxbuf(sc, sc->rxq.cur);
2140170589Syongari				continue;
2141170589Syongari			}
2142159952Sobrien
2143159952Sobrien			if ((flags & NFE_RX_FIXME_V2) == NFE_RX_FIXME_V2) {
2144159952Sobrien				flags &= ~NFE_RX_ERROR;
2145159952Sobrien				len--;	/* fix buffer length */
2146159952Sobrien			}
2147159952Sobrien		}
2148159952Sobrien
2149159952Sobrien		if (flags & NFE_RX_ERROR) {
2150159952Sobrien			ifp->if_ierrors++;
2151170589Syongari			nfe_discard_rxbuf(sc, sc->rxq.cur);
2152170589Syongari			continue;
2153159952Sobrien		}
2154159952Sobrien
2155170589Syongari		m = data->m;
2156170589Syongari		if (nfe_newbuf(sc, sc->rxq.cur) != 0) {
2157170589Syongari			ifp->if_iqdrops++;
2158170589Syongari			nfe_discard_rxbuf(sc, sc->rxq.cur);
2159170589Syongari			continue;
2160159952Sobrien		}
2161159952Sobrien
2162170589Syongari		if ((vtag & NFE_RX_VTAG) != 0 &&
2163170589Syongari		    (ifp->if_capenable & IFCAP_VLAN_HWTAGGING) != 0) {
2164170589Syongari			m->m_pkthdr.ether_vtag = vtag & 0xffff;
2165170589Syongari			m->m_flags |= M_VLANTAG;
2166164651Sobrien		}
2167159952Sobrien
2168170589Syongari		m->m_pkthdr.len = m->m_len = len;
2169170589Syongari		m->m_pkthdr.rcvif = ifp;
2170164651Sobrien
2171170589Syongari		if ((ifp->if_capenable & IFCAP_RXCSUM) != 0) {
2172170589Syongari			if ((flags & NFE_RX_IP_CSUMOK) != 0) {
2173170589Syongari				m->m_pkthdr.csum_flags |= CSUM_IP_CHECKED;
2174170589Syongari				m->m_pkthdr.csum_flags |= CSUM_IP_VALID;
2175170589Syongari				if ((flags & NFE_RX_TCP_CSUMOK) != 0 ||
2176170589Syongari				    (flags & NFE_RX_UDP_CSUMOK) != 0) {
2177170589Syongari					m->m_pkthdr.csum_flags |=
2178170589Syongari					    CSUM_DATA_VALID | CSUM_PSEUDO_HDR;
2179170589Syongari					m->m_pkthdr.csum_data = 0xffff;
2180170589Syongari				}
2181159952Sobrien			}
2182170589Syongari		}
2183170589Syongari
2184170589Syongari		ifp->if_ipackets++;
2185170589Syongari
2186170589Syongari		NFE_UNLOCK(sc);
2187170589Syongari		(*ifp->if_input)(ifp, m);
2188170589Syongari		NFE_LOCK(sc);
2189193096Sattilio		rx_npkts++;
2190170589Syongari	}
2191170589Syongari
2192170589Syongari	if (prog > 0)
2193170589Syongari		bus_dmamap_sync(sc->rxq.rx_desc_tag, sc->rxq.rx_desc_map,
2194170589Syongari		    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
2195170589Syongari
2196193096Sattilio	if (rx_npktsp != NULL)
2197193096Sattilio		*rx_npktsp = rx_npkts;
2198170589Syongari	return (count > 0 ? 0 : EAGAIN);
2199170589Syongari}
2200170589Syongari
2201170589Syongari
2202170589Syongaristatic int
2203193096Sattilionfe_jrxeof(struct nfe_softc *sc, int count, int *rx_npktsp)
2204170589Syongari{
2205170589Syongari	struct ifnet *ifp = sc->nfe_ifp;
2206170589Syongari	struct nfe_desc32 *desc32;
2207170589Syongari	struct nfe_desc64 *desc64;
2208170589Syongari	struct nfe_rx_data *data;
2209170589Syongari	struct mbuf *m;
2210170589Syongari	uint16_t flags;
2211193096Sattilio	int len, prog, rx_npkts;
2212170589Syongari	uint32_t vtag = 0;
2213170589Syongari
2214193096Sattilio	rx_npkts = 0;
2215170589Syongari	NFE_LOCK_ASSERT(sc);
2216170589Syongari
2217170589Syongari	bus_dmamap_sync(sc->jrxq.jrx_desc_tag, sc->jrxq.jrx_desc_map,
2218170589Syongari	    BUS_DMASYNC_POSTREAD);
2219170589Syongari
2220170589Syongari	for (prog = 0;;NFE_INC(sc->jrxq.jcur, NFE_JUMBO_RX_RING_COUNT),
2221170589Syongari	    vtag = 0) {
2222170589Syongari		if (count <= 0)
2223170589Syongari			break;
2224170589Syongari		count--;
2225170589Syongari
2226170589Syongari		data = &sc->jrxq.jdata[sc->jrxq.jcur];
2227170589Syongari
2228170589Syongari		if (sc->nfe_flags & NFE_40BIT_ADDR) {
2229170589Syongari			desc64 = &sc->jrxq.jdesc64[sc->jrxq.jcur];
2230170589Syongari			vtag = le32toh(desc64->physaddr[1]);
2231170589Syongari			flags = le16toh(desc64->flags);
2232170589Syongari			len = le16toh(desc64->length) & NFE_RX_LEN_MASK;
2233170589Syongari		} else {
2234170589Syongari			desc32 = &sc->jrxq.jdesc32[sc->jrxq.jcur];
2235170589Syongari			flags = le16toh(desc32->flags);
2236170589Syongari			len = le16toh(desc32->length) & NFE_RX_LEN_MASK;
2237170589Syongari		}
2238170589Syongari
2239170589Syongari		if (flags & NFE_RX_READY)
2240170589Syongari			break;
2241170589Syongari		prog++;
2242170589Syongari		if ((sc->nfe_flags & (NFE_JUMBO_SUP | NFE_40BIT_ADDR)) == 0) {
2243170589Syongari			if (!(flags & NFE_RX_VALID_V1)) {
2244170589Syongari				ifp->if_ierrors++;
2245170589Syongari				nfe_discard_jrxbuf(sc, sc->jrxq.jcur);
2246170589Syongari				continue;
2247170589Syongari			}
2248170589Syongari			if ((flags & NFE_RX_FIXME_V1) == NFE_RX_FIXME_V1) {
2249170589Syongari				flags &= ~NFE_RX_ERROR;
2250170589Syongari				len--;	/* fix buffer length */
2251170589Syongari			}
2252170589Syongari		} else {
2253170589Syongari			if (!(flags & NFE_RX_VALID_V2)) {
2254170589Syongari				ifp->if_ierrors++;
2255170589Syongari				nfe_discard_jrxbuf(sc, sc->jrxq.jcur);
2256170589Syongari				continue;
2257170589Syongari			}
2258170589Syongari
2259170589Syongari			if ((flags & NFE_RX_FIXME_V2) == NFE_RX_FIXME_V2) {
2260170589Syongari				flags &= ~NFE_RX_ERROR;
2261170589Syongari				len--;	/* fix buffer length */
2262170589Syongari			}
2263170589Syongari		}
2264170589Syongari
2265170589Syongari		if (flags & NFE_RX_ERROR) {
2266164651Sobrien			ifp->if_ierrors++;
2267170589Syongari			nfe_discard_jrxbuf(sc, sc->jrxq.jcur);
2268170589Syongari			continue;
2269164651Sobrien		}
2270159952Sobrien
2271159952Sobrien		m = data->m;
2272170589Syongari		if (nfe_jnewbuf(sc, sc->jrxq.jcur) != 0) {
2273170589Syongari			ifp->if_iqdrops++;
2274170589Syongari			nfe_discard_jrxbuf(sc, sc->jrxq.jcur);
2275170589Syongari			continue;
2276170589Syongari		}
2277159952Sobrien
2278170589Syongari		if ((vtag & NFE_RX_VTAG) != 0 &&
2279170589Syongari		    (ifp->if_capenable & IFCAP_VLAN_HWTAGGING) != 0) {
2280170589Syongari			m->m_pkthdr.ether_vtag = vtag & 0xffff;
2281170589Syongari			m->m_flags |= M_VLANTAG;
2282170589Syongari		}
2283170589Syongari
2284159952Sobrien		m->m_pkthdr.len = m->m_len = len;
2285159952Sobrien		m->m_pkthdr.rcvif = ifp;
2286159952Sobrien
2287170589Syongari		if ((ifp->if_capenable & IFCAP_RXCSUM) != 0) {
2288170589Syongari			if ((flags & NFE_RX_IP_CSUMOK) != 0) {
2289170589Syongari				m->m_pkthdr.csum_flags |= CSUM_IP_CHECKED;
2290159967Sobrien				m->m_pkthdr.csum_flags |= CSUM_IP_VALID;
2291170589Syongari				if ((flags & NFE_RX_TCP_CSUMOK) != 0 ||
2292170589Syongari				    (flags & NFE_RX_UDP_CSUMOK) != 0) {
2293170589Syongari					m->m_pkthdr.csum_flags |=
2294170589Syongari					    CSUM_DATA_VALID | CSUM_PSEUDO_HDR;
2295170589Syongari					m->m_pkthdr.csum_data = 0xffff;
2296170589Syongari				}
2297159967Sobrien			}
2298159952Sobrien		}
2299159952Sobrien
2300159952Sobrien		ifp->if_ipackets++;
2301159952Sobrien
2302159967Sobrien		NFE_UNLOCK(sc);
2303159967Sobrien		(*ifp->if_input)(ifp, m);
2304159967Sobrien		NFE_LOCK(sc);
2305193096Sattilio		rx_npkts++;
2306170589Syongari	}
2307159967Sobrien
2308170589Syongari	if (prog > 0)
2309170589Syongari		bus_dmamap_sync(sc->jrxq.jrx_desc_tag, sc->jrxq.jrx_desc_map,
2310170589Syongari		    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
2311159952Sobrien
2312193096Sattilio	if (rx_npktsp != NULL)
2313193096Sattilio		*rx_npktsp = rx_npkts;
2314170589Syongari	return (count > 0 ? 0 : EAGAIN);
2315159952Sobrien}
2316159952Sobrien
2317163503Sobrien
2318163503Sobrienstatic void
2319163503Sobriennfe_txeof(struct nfe_softc *sc)
2320159952Sobrien{
2321159967Sobrien	struct ifnet *ifp = sc->nfe_ifp;
2322159952Sobrien	struct nfe_desc32 *desc32;
2323159952Sobrien	struct nfe_desc64 *desc64;
2324159952Sobrien	struct nfe_tx_data *data = NULL;
2325170589Syongari	uint16_t flags;
2326170589Syongari	int cons, prog;
2327159952Sobrien
2328159967Sobrien	NFE_LOCK_ASSERT(sc);
2329159967Sobrien
2330170589Syongari	bus_dmamap_sync(sc->txq.tx_desc_tag, sc->txq.tx_desc_map,
2331170589Syongari	    BUS_DMASYNC_POSTREAD);
2332170589Syongari
2333170589Syongari	prog = 0;
2334170589Syongari	for (cons = sc->txq.next; cons != sc->txq.cur;
2335170589Syongari	    NFE_INC(cons, NFE_TX_RING_COUNT)) {
2336159967Sobrien		if (sc->nfe_flags & NFE_40BIT_ADDR) {
2337170589Syongari			desc64 = &sc->txq.desc64[cons];
2338170589Syongari			flags = le16toh(desc64->flags);
2339159952Sobrien		} else {
2340170589Syongari			desc32 = &sc->txq.desc32[cons];
2341170589Syongari			flags = le16toh(desc32->flags);
2342159952Sobrien		}
2343159952Sobrien
2344159952Sobrien		if (flags & NFE_TX_VALID)
2345159952Sobrien			break;
2346159952Sobrien
2347170589Syongari		prog++;
2348170589Syongari		sc->txq.queued--;
2349170589Syongari		data = &sc->txq.data[cons];
2350159952Sobrien
2351159967Sobrien		if ((sc->nfe_flags & (NFE_JUMBO_SUP | NFE_40BIT_ADDR)) == 0) {
2352170589Syongari			if ((flags & NFE_TX_LASTFRAG_V1) == 0)
2353170589Syongari				continue;
2354159952Sobrien			if ((flags & NFE_TX_ERROR_V1) != 0) {
2355170589Syongari				device_printf(sc->nfe_dev,
2356170589Syongari				    "tx v1 error 0x%4b\n", flags, NFE_V1_TXERR);
2357159967Sobrien
2358159952Sobrien				ifp->if_oerrors++;
2359159952Sobrien			} else
2360159952Sobrien				ifp->if_opackets++;
2361159952Sobrien		} else {
2362170589Syongari			if ((flags & NFE_TX_LASTFRAG_V2) == 0)
2363170589Syongari				continue;
2364159952Sobrien			if ((flags & NFE_TX_ERROR_V2) != 0) {
2365170589Syongari				device_printf(sc->nfe_dev,
2366170589Syongari				    "tx v2 error 0x%4b\n", flags, NFE_V2_TXERR);
2367159952Sobrien				ifp->if_oerrors++;
2368159952Sobrien			} else
2369159952Sobrien				ifp->if_opackets++;
2370159952Sobrien		}
2371159952Sobrien
2372159952Sobrien		/* last fragment of the mbuf chain transmitted */
2373170589Syongari		KASSERT(data->m != NULL, ("%s: freeing NULL mbuf!", __func__));
2374170589Syongari		bus_dmamap_sync(sc->txq.tx_data_tag, data->tx_data_map,
2375159967Sobrien		    BUS_DMASYNC_POSTWRITE);
2376170589Syongari		bus_dmamap_unload(sc->txq.tx_data_tag, data->tx_data_map);
2377159952Sobrien		m_freem(data->m);
2378159952Sobrien		data->m = NULL;
2379159952Sobrien	}
2380159952Sobrien
2381170589Syongari	if (prog > 0) {
2382170589Syongari		sc->nfe_force_tx = 0;
2383170589Syongari		sc->txq.next = cons;
2384159967Sobrien		ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
2385170589Syongari		if (sc->txq.queued == 0)
2386170589Syongari			sc->nfe_watchdog_timer = 0;
2387159952Sobrien	}
2388159952Sobrien}
2389159952Sobrien
2390163503Sobrienstatic int
2391170589Syongarinfe_encap(struct nfe_softc *sc, struct mbuf **m_head)
2392159952Sobrien{
2393170589Syongari	struct nfe_desc32 *desc32 = NULL;
2394170589Syongari	struct nfe_desc64 *desc64 = NULL;
2395159952Sobrien	bus_dmamap_t map;
2396163503Sobrien	bus_dma_segment_t segs[NFE_MAX_SCATTER];
2397170589Syongari	int error, i, nsegs, prod, si;
2398170589Syongari	uint32_t tso_segsz;
2399170589Syongari	uint16_t cflags, flags;
2400170589Syongari	struct mbuf *m;
2401159952Sobrien
2402170589Syongari	prod = si = sc->txq.cur;
2403170589Syongari	map = sc->txq.data[prod].tx_data_map;
2404159952Sobrien
2405170589Syongari	error = bus_dmamap_load_mbuf_sg(sc->txq.tx_data_tag, map, *m_head, segs,
2406159967Sobrien	    &nsegs, BUS_DMA_NOWAIT);
2407170589Syongari	if (error == EFBIG) {
2408175418Sjhb		m = m_collapse(*m_head, M_DONTWAIT, NFE_MAX_SCATTER);
2409170589Syongari		if (m == NULL) {
2410170589Syongari			m_freem(*m_head);
2411170589Syongari			*m_head = NULL;
2412170589Syongari			return (ENOBUFS);
2413170589Syongari		}
2414170589Syongari		*m_head = m;
2415170589Syongari		error = bus_dmamap_load_mbuf_sg(sc->txq.tx_data_tag, map,
2416170589Syongari		    *m_head, segs, &nsegs, BUS_DMA_NOWAIT);
2417170589Syongari		if (error != 0) {
2418170589Syongari			m_freem(*m_head);
2419170589Syongari			*m_head = NULL;
2420170589Syongari			return (ENOBUFS);
2421170589Syongari		}
2422170589Syongari	} else if (error != 0)
2423170589Syongari		return (error);
2424170589Syongari	if (nsegs == 0) {
2425170589Syongari		m_freem(*m_head);
2426170589Syongari		*m_head = NULL;
2427170589Syongari		return (EIO);
2428159952Sobrien	}
2429159952Sobrien
2430170589Syongari	if (sc->txq.queued + nsegs >= NFE_TX_RING_COUNT - 2) {
2431159967Sobrien		bus_dmamap_unload(sc->txq.tx_data_tag, map);
2432170589Syongari		return (ENOBUFS);
2433159952Sobrien	}
2434159952Sobrien
2435170589Syongari	m = *m_head;
2436170589Syongari	cflags = flags = 0;
2437170589Syongari	tso_segsz = 0;
2438206876Syongari	if ((m->m_pkthdr.csum_flags & CSUM_TSO) != 0) {
2439206876Syongari		tso_segsz = (uint32_t)m->m_pkthdr.tso_segsz <<
2440206876Syongari		    NFE_TX_TSO_SHIFT;
2441206876Syongari		cflags &= ~(NFE_TX_IP_CSUM | NFE_TX_TCP_UDP_CSUM);
2442206876Syongari		cflags |= NFE_TX_TSO;
2443206876Syongari	} else if ((m->m_pkthdr.csum_flags & NFE_CSUM_FEATURES) != 0) {
2444170589Syongari		if ((m->m_pkthdr.csum_flags & CSUM_IP) != 0)
2445170589Syongari			cflags |= NFE_TX_IP_CSUM;
2446170589Syongari		if ((m->m_pkthdr.csum_flags & CSUM_TCP) != 0)
2447170589Syongari			cflags |= NFE_TX_TCP_UDP_CSUM;
2448170589Syongari		if ((m->m_pkthdr.csum_flags & CSUM_UDP) != 0)
2449170589Syongari			cflags |= NFE_TX_TCP_UDP_CSUM;
2450164656Sobrien	}
2451159967Sobrien
2452159967Sobrien	for (i = 0; i < nsegs; i++) {
2453159967Sobrien		if (sc->nfe_flags & NFE_40BIT_ADDR) {
2454170589Syongari			desc64 = &sc->txq.desc64[prod];
2455170589Syongari			desc64->physaddr[0] =
2456170589Syongari			    htole32(NFE_ADDR_HI(segs[i].ds_addr));
2457170589Syongari			desc64->physaddr[1] =
2458170589Syongari			    htole32(NFE_ADDR_LO(segs[i].ds_addr));
2459170589Syongari			desc64->vtag = 0;
2460159967Sobrien			desc64->length = htole16(segs[i].ds_len - 1);
2461159952Sobrien			desc64->flags = htole16(flags);
2462159952Sobrien		} else {
2463170589Syongari			desc32 = &sc->txq.desc32[prod];
2464170589Syongari			desc32->physaddr =
2465170589Syongari			    htole32(NFE_ADDR_LO(segs[i].ds_addr));
2466159967Sobrien			desc32->length = htole16(segs[i].ds_len - 1);
2467159952Sobrien			desc32->flags = htole16(flags);
2468159952Sobrien		}
2469159952Sobrien
2470170589Syongari		/*
2471170589Syongari		 * Setting of the valid bit in the first descriptor is
2472170589Syongari		 * deferred until the whole chain is fully setup.
2473170589Syongari		 */
2474170589Syongari		flags |= NFE_TX_VALID;
2475163503Sobrien
2476159952Sobrien		sc->txq.queued++;
2477170589Syongari		NFE_INC(prod, NFE_TX_RING_COUNT);
2478159952Sobrien	}
2479159952Sobrien
2480170589Syongari	/*
2481170589Syongari	 * the whole mbuf chain has been DMA mapped, fix last/first descriptor.
2482170589Syongari	 * csum flags, vtag and TSO belong to the first fragment only.
2483170589Syongari	 */
2484159967Sobrien	if (sc->nfe_flags & NFE_40BIT_ADDR) {
2485170589Syongari		desc64->flags |= htole16(NFE_TX_LASTFRAG_V2);
2486170589Syongari		desc64 = &sc->txq.desc64[si];
2487170589Syongari		if ((m->m_flags & M_VLANTAG) != 0)
2488170589Syongari			desc64->vtag = htole32(NFE_TX_VTAG |
2489170589Syongari			    m->m_pkthdr.ether_vtag);
2490170589Syongari		if (tso_segsz != 0) {
2491170589Syongari			/*
2492170589Syongari			 * XXX
2493170589Syongari			 * The following indicates the descriptor element
2494170589Syongari			 * is a 32bit quantity.
2495170589Syongari			 */
2496170589Syongari			desc64->length |= htole16((uint16_t)tso_segsz);
2497170589Syongari			desc64->flags |= htole16(tso_segsz >> 16);
2498170589Syongari		}
2499170589Syongari		/*
2500170589Syongari		 * finally, set the valid/checksum/TSO bit in the first
2501170589Syongari		 * descriptor.
2502170589Syongari		 */
2503170589Syongari		desc64->flags |= htole16(NFE_TX_VALID | cflags);
2504159952Sobrien	} else {
2505159967Sobrien		if (sc->nfe_flags & NFE_JUMBO_SUP)
2506170589Syongari			desc32->flags |= htole16(NFE_TX_LASTFRAG_V2);
2507159952Sobrien		else
2508170589Syongari			desc32->flags |= htole16(NFE_TX_LASTFRAG_V1);
2509170589Syongari		desc32 = &sc->txq.desc32[si];
2510170589Syongari		if (tso_segsz != 0) {
2511170589Syongari			/*
2512170589Syongari			 * XXX
2513170589Syongari			 * The following indicates the descriptor element
2514170589Syongari			 * is a 32bit quantity.
2515170589Syongari			 */
2516170589Syongari			desc32->length |= htole16((uint16_t)tso_segsz);
2517170589Syongari			desc32->flags |= htole16(tso_segsz >> 16);
2518170589Syongari		}
2519170589Syongari		/*
2520170589Syongari		 * finally, set the valid/checksum/TSO bit in the first
2521170589Syongari		 * descriptor.
2522170589Syongari		 */
2523170589Syongari		desc32->flags |= htole16(NFE_TX_VALID | cflags);
2524159952Sobrien	}
2525159952Sobrien
2526170589Syongari	sc->txq.cur = prod;
2527170589Syongari	prod = (prod + NFE_TX_RING_COUNT - 1) % NFE_TX_RING_COUNT;
2528170589Syongari	sc->txq.data[si].tx_data_map = sc->txq.data[prod].tx_data_map;
2529170589Syongari	sc->txq.data[prod].tx_data_map = map;
2530170589Syongari	sc->txq.data[prod].m = m;
2531159952Sobrien
2532159967Sobrien	bus_dmamap_sync(sc->txq.tx_data_tag, map, BUS_DMASYNC_PREWRITE);
2533159952Sobrien
2534170589Syongari	return (0);
2535159952Sobrien}
2536159952Sobrien
2537159967Sobrien
2538163503Sobrienstatic void
2539163503Sobriennfe_setmulti(struct nfe_softc *sc)
2540159952Sobrien{
2541159967Sobrien	struct ifnet *ifp = sc->nfe_ifp;
2542163503Sobrien	struct ifmultiaddr *ifma;
2543163503Sobrien	int i;
2544170589Syongari	uint32_t filter;
2545170589Syongari	uint8_t addr[ETHER_ADDR_LEN], mask[ETHER_ADDR_LEN];
2546170589Syongari	uint8_t etherbroadcastaddr[ETHER_ADDR_LEN] = {
2547163503Sobrien		0xff, 0xff, 0xff, 0xff, 0xff, 0xff
2548163503Sobrien	};
2549159967Sobrien
2550159967Sobrien	NFE_LOCK_ASSERT(sc);
2551159967Sobrien
2552159967Sobrien	if ((ifp->if_flags & (IFF_ALLMULTI | IFF_PROMISC)) != 0) {
2553159967Sobrien		bzero(addr, ETHER_ADDR_LEN);
2554159967Sobrien		bzero(mask, ETHER_ADDR_LEN);
2555159967Sobrien		goto done;
2556159967Sobrien	}
2557159967Sobrien
2558159967Sobrien	bcopy(etherbroadcastaddr, addr, ETHER_ADDR_LEN);
2559159967Sobrien	bcopy(etherbroadcastaddr, mask, ETHER_ADDR_LEN);
2560159967Sobrien
2561195049Srwatson	if_maddr_rlock(ifp);
2562159967Sobrien	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
2563159967Sobrien		u_char *addrp;
2564159967Sobrien
2565159967Sobrien		if (ifma->ifma_addr->sa_family != AF_LINK)
2566159967Sobrien			continue;
2567159967Sobrien
2568159967Sobrien		addrp = LLADDR((struct sockaddr_dl *) ifma->ifma_addr);
2569159967Sobrien		for (i = 0; i < ETHER_ADDR_LEN; i++) {
2570159967Sobrien			u_int8_t mcaddr = addrp[i];
2571159967Sobrien			addr[i] &= mcaddr;
2572159967Sobrien			mask[i] &= ~mcaddr;
2573159967Sobrien		}
2574159967Sobrien	}
2575195049Srwatson	if_maddr_runlock(ifp);
2576159967Sobrien
2577159967Sobrien	for (i = 0; i < ETHER_ADDR_LEN; i++) {
2578159967Sobrien		mask[i] |= addr[i];
2579159967Sobrien	}
2580159967Sobrien
2581159967Sobriendone:
2582159967Sobrien	addr[0] |= 0x01;	/* make sure multicast bit is set */
2583159967Sobrien
2584159967Sobrien	NFE_WRITE(sc, NFE_MULTIADDR_HI,
2585159967Sobrien	    addr[3] << 24 | addr[2] << 16 | addr[1] << 8 | addr[0]);
2586159967Sobrien	NFE_WRITE(sc, NFE_MULTIADDR_LO,
2587159967Sobrien	    addr[5] <<  8 | addr[4]);
2588159967Sobrien	NFE_WRITE(sc, NFE_MULTIMASK_HI,
2589159967Sobrien	    mask[3] << 24 | mask[2] << 16 | mask[1] << 8 | mask[0]);
2590159967Sobrien	NFE_WRITE(sc, NFE_MULTIMASK_LO,
2591159967Sobrien	    mask[5] <<  8 | mask[4]);
2592159967Sobrien
2593170589Syongari	filter = NFE_READ(sc, NFE_RXFILTER);
2594170589Syongari	filter &= NFE_PFF_RX_PAUSE;
2595170589Syongari	filter |= NFE_RXFILTER_MAGIC;
2596170589Syongari	filter |= (ifp->if_flags & IFF_PROMISC) ? NFE_PFF_PROMISC : NFE_PFF_U2M;
2597159967Sobrien	NFE_WRITE(sc, NFE_RXFILTER, filter);
2598159967Sobrien}
2599159967Sobrien
2600163503Sobrien
2601163503Sobrienstatic void
2602216925Sjhbnfe_start(struct ifnet *ifp)
2603159967Sobrien{
2604216925Sjhb	struct nfe_softc *sc = ifp->if_softc;
2605159967Sobrien
2606216925Sjhb	NFE_LOCK(sc);
2607216925Sjhb	nfe_start_locked(ifp);
2608216925Sjhb	NFE_UNLOCK(sc);
2609159967Sobrien}
2610159967Sobrien
2611163503Sobrienstatic void
2612216925Sjhbnfe_start_locked(struct ifnet *ifp)
2613159967Sobrien{
2614159952Sobrien	struct nfe_softc *sc = ifp->if_softc;
2615163503Sobrien	struct mbuf *m0;
2616170589Syongari	int enq;
2617159952Sobrien
2618216925Sjhb	NFE_LOCK_ASSERT(sc);
2619170589Syongari
2620170589Syongari	if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) !=
2621216925Sjhb	    IFF_DRV_RUNNING || sc->nfe_link == 0)
2622159967Sobrien		return;
2623159967Sobrien
2624170589Syongari	for (enq = 0; !IFQ_DRV_IS_EMPTY(&ifp->if_snd);) {
2625170589Syongari		IFQ_DRV_DEQUEUE(&ifp->if_snd, m0);
2626159952Sobrien		if (m0 == NULL)
2627159952Sobrien			break;
2628159952Sobrien
2629170589Syongari		if (nfe_encap(sc, &m0) != 0) {
2630170589Syongari			if (m0 == NULL)
2631170589Syongari				break;
2632170589Syongari			IFQ_DRV_PREPEND(&ifp->if_snd, m0);
2633159967Sobrien			ifp->if_drv_flags |= IFF_DRV_OACTIVE;
2634159952Sobrien			break;
2635159952Sobrien		}
2636170589Syongari		enq++;
2637167190Scsjp		ETHER_BPF_MTAP(ifp, m0);
2638159952Sobrien	}
2639159952Sobrien
2640170589Syongari	if (enq > 0) {
2641170589Syongari		bus_dmamap_sync(sc->txq.tx_desc_tag, sc->txq.tx_desc_map,
2642170589Syongari		    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
2643159952Sobrien
2644170589Syongari		/* kick Tx */
2645170589Syongari		NFE_WRITE(sc, NFE_RXTX_CTL, NFE_RXTX_KICKTX | sc->rxtxctl);
2646159952Sobrien
2647170589Syongari		/*
2648170589Syongari		 * Set a timeout in case the chip goes out to lunch.
2649170589Syongari		 */
2650170589Syongari		sc->nfe_watchdog_timer = 5;
2651170589Syongari	}
2652159952Sobrien}
2653159952Sobrien
2654163503Sobrien
2655163503Sobrienstatic void
2656163503Sobriennfe_watchdog(struct ifnet *ifp)
2657159952Sobrien{
2658159952Sobrien	struct nfe_softc *sc = ifp->if_softc;
2659159952Sobrien
2660170589Syongari	if (sc->nfe_watchdog_timer == 0 || --sc->nfe_watchdog_timer)
2661170589Syongari		return;
2662159952Sobrien
2663170589Syongari	/* Check if we've lost Tx completion interrupt. */
2664170589Syongari	nfe_txeof(sc);
2665170589Syongari	if (sc->txq.queued == 0) {
2666170589Syongari		if_printf(ifp, "watchdog timeout (missed Tx interrupts) "
2667170589Syongari		    "-- recovering\n");
2668170589Syongari		if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
2669216925Sjhb			nfe_start_locked(ifp);
2670170589Syongari		return;
2671170589Syongari	}
2672170589Syongari	/* Check if we've lost start Tx command. */
2673170589Syongari	sc->nfe_force_tx++;
2674170589Syongari	if (sc->nfe_force_tx <= 3) {
2675170589Syongari		/*
2676170589Syongari		 * If this is the case for watchdog timeout, the following
2677170589Syongari		 * code should go to nfe_txeof().
2678170589Syongari		 */
2679170589Syongari		NFE_WRITE(sc, NFE_RXTX_CTL, NFE_RXTX_KICKTX | sc->rxtxctl);
2680170589Syongari		return;
2681170589Syongari	}
2682170589Syongari	sc->nfe_force_tx = 0;
2683170589Syongari
2684170589Syongari	if_printf(ifp, "watchdog timeout\n");
2685170589Syongari
2686159967Sobrien	ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
2687159952Sobrien	ifp->if_oerrors++;
2688170589Syongari	nfe_init_locked(sc);
2689159952Sobrien}
2690159952Sobrien
2691163503Sobrien
2692163503Sobrienstatic void
2693163503Sobriennfe_init(void *xsc)
2694159952Sobrien{
2695159967Sobrien	struct nfe_softc *sc = xsc;
2696159952Sobrien
2697159967Sobrien	NFE_LOCK(sc);
2698159967Sobrien	nfe_init_locked(sc);
2699159967Sobrien	NFE_UNLOCK(sc);
2700159967Sobrien}
2701159967Sobrien
2702163503Sobrien
2703163503Sobrienstatic void
2704163503Sobriennfe_init_locked(void *xsc)
2705159967Sobrien{
2706159967Sobrien	struct nfe_softc *sc = xsc;
2707159967Sobrien	struct ifnet *ifp = sc->nfe_ifp;
2708159967Sobrien	struct mii_data *mii;
2709170589Syongari	uint32_t val;
2710170589Syongari	int error;
2711159967Sobrien
2712159967Sobrien	NFE_LOCK_ASSERT(sc);
2713159967Sobrien
2714159967Sobrien	mii = device_get_softc(sc->nfe_miibus);
2715159967Sobrien
2716170589Syongari	if (ifp->if_drv_flags & IFF_DRV_RUNNING)
2717159967Sobrien		return;
2718170589Syongari
2719170589Syongari	nfe_stop(ifp);
2720170589Syongari
2721170589Syongari	sc->nfe_framesize = ifp->if_mtu + NFE_RX_HEADERS;
2722170589Syongari
2723170589Syongari	nfe_init_tx_ring(sc, &sc->txq);
2724170589Syongari	if (sc->nfe_framesize > (MCLBYTES - ETHER_HDR_LEN))
2725170589Syongari		error = nfe_init_jrx_ring(sc, &sc->jrxq);
2726170589Syongari	else
2727170589Syongari		error = nfe_init_rx_ring(sc, &sc->rxq);
2728170589Syongari	if (error != 0) {
2729170589Syongari		device_printf(sc->nfe_dev,
2730170589Syongari		    "initialization failed: no memory for rx buffers\n");
2731170589Syongari		nfe_stop(ifp);
2732170589Syongari		return;
2733159967Sobrien	}
2734159967Sobrien
2735170589Syongari	val = 0;
2736170589Syongari	if ((sc->nfe_flags & NFE_CORRECT_MACADDR) != 0)
2737170589Syongari		val |= NFE_MAC_ADDR_INORDER;
2738170589Syongari	NFE_WRITE(sc, NFE_TX_UNK, val);
2739159952Sobrien	NFE_WRITE(sc, NFE_STATUS, 0);
2740159952Sobrien
2741170589Syongari	if ((sc->nfe_flags & NFE_TX_FLOW_CTRL) != 0)
2742170589Syongari		NFE_WRITE(sc, NFE_TX_PAUSE_FRAME, NFE_TX_PAUSE_FRAME_DISABLE);
2743170589Syongari
2744159952Sobrien	sc->rxtxctl = NFE_RXTX_BIT2;
2745159967Sobrien	if (sc->nfe_flags & NFE_40BIT_ADDR)
2746159952Sobrien		sc->rxtxctl |= NFE_RXTX_V3MAGIC;
2747159967Sobrien	else if (sc->nfe_flags & NFE_JUMBO_SUP)
2748159952Sobrien		sc->rxtxctl |= NFE_RXTX_V2MAGIC;
2749164656Sobrien
2750170589Syongari	if ((ifp->if_capenable & IFCAP_RXCSUM) != 0)
2751159952Sobrien		sc->rxtxctl |= NFE_RXTX_RXCSUM;
2752170589Syongari	if ((ifp->if_capenable & IFCAP_VLAN_HWTAGGING) != 0)
2753170589Syongari		sc->rxtxctl |= NFE_RXTX_VTAG_INSERT | NFE_RXTX_VTAG_STRIP;
2754159967Sobrien
2755159952Sobrien	NFE_WRITE(sc, NFE_RXTX_CTL, NFE_RXTX_RESET | sc->rxtxctl);
2756159952Sobrien	DELAY(10);
2757159952Sobrien	NFE_WRITE(sc, NFE_RXTX_CTL, sc->rxtxctl);
2758159952Sobrien
2759170589Syongari	if ((ifp->if_capenable & IFCAP_VLAN_HWTAGGING) != 0)
2760159952Sobrien		NFE_WRITE(sc, NFE_VTAG_CTL, NFE_VTAG_ENABLE);
2761170589Syongari	else
2762170589Syongari		NFE_WRITE(sc, NFE_VTAG_CTL, 0);
2763159952Sobrien
2764159952Sobrien	NFE_WRITE(sc, NFE_SETUP_R6, 0);
2765159952Sobrien
2766159952Sobrien	/* set MAC address */
2767170589Syongari	nfe_set_macaddr(sc, IF_LLADDR(ifp));
2768159952Sobrien
2769159952Sobrien	/* tell MAC where rings are in memory */
2770170589Syongari	if (sc->nfe_framesize > MCLBYTES - ETHER_HDR_LEN) {
2771170589Syongari		NFE_WRITE(sc, NFE_RX_RING_ADDR_HI,
2772170589Syongari		    NFE_ADDR_HI(sc->jrxq.jphysaddr));
2773170589Syongari		NFE_WRITE(sc, NFE_RX_RING_ADDR_LO,
2774170589Syongari		    NFE_ADDR_LO(sc->jrxq.jphysaddr));
2775170589Syongari	} else {
2776170589Syongari		NFE_WRITE(sc, NFE_RX_RING_ADDR_HI,
2777170589Syongari		    NFE_ADDR_HI(sc->rxq.physaddr));
2778170589Syongari		NFE_WRITE(sc, NFE_RX_RING_ADDR_LO,
2779170589Syongari		    NFE_ADDR_LO(sc->rxq.physaddr));
2780170589Syongari	}
2781170589Syongari	NFE_WRITE(sc, NFE_TX_RING_ADDR_HI, NFE_ADDR_HI(sc->txq.physaddr));
2782170589Syongari	NFE_WRITE(sc, NFE_TX_RING_ADDR_LO, NFE_ADDR_LO(sc->txq.physaddr));
2783159952Sobrien
2784159952Sobrien	NFE_WRITE(sc, NFE_RING_SIZE,
2785159952Sobrien	    (NFE_RX_RING_COUNT - 1) << 16 |
2786159952Sobrien	    (NFE_TX_RING_COUNT - 1));
2787159952Sobrien
2788170589Syongari	NFE_WRITE(sc, NFE_RXBUFSZ, sc->nfe_framesize);
2789159952Sobrien
2790159952Sobrien	/* force MAC to wakeup */
2791170589Syongari	val = NFE_READ(sc, NFE_PWR_STATE);
2792170589Syongari	if ((val & NFE_PWR_WAKEUP) == 0)
2793170589Syongari		NFE_WRITE(sc, NFE_PWR_STATE, val | NFE_PWR_WAKEUP);
2794159952Sobrien	DELAY(10);
2795170589Syongari	val = NFE_READ(sc, NFE_PWR_STATE);
2796170589Syongari	NFE_WRITE(sc, NFE_PWR_STATE, val | NFE_PWR_VALID);
2797159952Sobrien
2798159952Sobrien#if 1
2799159952Sobrien	/* configure interrupts coalescing/mitigation */
2800159952Sobrien	NFE_WRITE(sc, NFE_IMTIMER, NFE_IM_DEFAULT);
2801159952Sobrien#else
2802159952Sobrien	/* no interrupt mitigation: one interrupt per packet */
2803159952Sobrien	NFE_WRITE(sc, NFE_IMTIMER, 970);
2804159952Sobrien#endif
2805159952Sobrien
2806170589Syongari	NFE_WRITE(sc, NFE_SETUP_R1, NFE_R1_MAGIC_10_100);
2807159952Sobrien	NFE_WRITE(sc, NFE_SETUP_R2, NFE_R2_MAGIC);
2808159952Sobrien	NFE_WRITE(sc, NFE_SETUP_R6, NFE_R6_MAGIC);
2809159952Sobrien
2810159952Sobrien	/* update MAC knowledge of PHY; generates a NFE_IRQ_LINK interrupt */
2811159952Sobrien	NFE_WRITE(sc, NFE_STATUS, sc->mii_phyaddr << 24 | NFE_STATUS_MAGIC);
2812159952Sobrien
2813159952Sobrien	NFE_WRITE(sc, NFE_SETUP_R4, NFE_R4_MAGIC);
2814215132Syongari	/* Disable WOL. */
2815215132Syongari	NFE_WRITE(sc, NFE_WOL_CTL, 0);
2816159952Sobrien
2817159952Sobrien	sc->rxtxctl &= ~NFE_RXTX_BIT2;
2818159952Sobrien	NFE_WRITE(sc, NFE_RXTX_CTL, sc->rxtxctl);
2819159952Sobrien	DELAY(10);
2820159952Sobrien	NFE_WRITE(sc, NFE_RXTX_CTL, NFE_RXTX_BIT1 | sc->rxtxctl);
2821159952Sobrien
2822159952Sobrien	/* set Rx filter */
2823159952Sobrien	nfe_setmulti(sc);
2824159952Sobrien
2825159952Sobrien	/* enable Rx */
2826159952Sobrien	NFE_WRITE(sc, NFE_RX_CTL, NFE_RX_START);
2827159952Sobrien
2828159952Sobrien	/* enable Tx */
2829159952Sobrien	NFE_WRITE(sc, NFE_TX_CTL, NFE_TX_START);
2830159952Sobrien
2831159952Sobrien	NFE_WRITE(sc, NFE_PHY_STATUS, 0xf);
2832159952Sobrien
2833183561Syongari	/* Clear hardware stats. */
2834183561Syongari	nfe_stats_clear(sc);
2835183561Syongari
2836159967Sobrien#ifdef DEVICE_POLLING
2837159967Sobrien	if (ifp->if_capenable & IFCAP_POLLING)
2838170589Syongari		nfe_disable_intr(sc);
2839159967Sobrien	else
2840159967Sobrien#endif
2841170589Syongari	nfe_set_intr(sc);
2842170589Syongari	nfe_enable_intr(sc); /* enable interrupts */
2843159952Sobrien
2844159967Sobrien	ifp->if_drv_flags |= IFF_DRV_RUNNING;
2845159967Sobrien	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
2846159952Sobrien
2847159967Sobrien	sc->nfe_link = 0;
2848170589Syongari	mii_mediachg(mii);
2849159952Sobrien
2850170589Syongari	callout_reset(&sc->nfe_stat_ch, hz, nfe_tick, sc);
2851159952Sobrien}
2852159952Sobrien
2853163503Sobrien
2854163503Sobrienstatic void
2855170589Syongarinfe_stop(struct ifnet *ifp)
2856159952Sobrien{
2857159952Sobrien	struct nfe_softc *sc = ifp->if_softc;
2858170589Syongari	struct nfe_rx_ring *rx_ring;
2859170589Syongari	struct nfe_jrx_ring *jrx_ring;
2860170589Syongari	struct nfe_tx_ring *tx_ring;
2861170589Syongari	struct nfe_rx_data *rdata;
2862170589Syongari	struct nfe_tx_data *tdata;
2863170589Syongari	int i;
2864159952Sobrien
2865159967Sobrien	NFE_LOCK_ASSERT(sc);
2866159952Sobrien
2867170589Syongari	sc->nfe_watchdog_timer = 0;
2868159967Sobrien	ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
2869159952Sobrien
2870159967Sobrien	callout_stop(&sc->nfe_stat_ch);
2871159967Sobrien
2872159952Sobrien	/* abort Tx */
2873159952Sobrien	NFE_WRITE(sc, NFE_TX_CTL, 0);
2874159952Sobrien
2875159952Sobrien	/* disable Rx */
2876159952Sobrien	NFE_WRITE(sc, NFE_RX_CTL, 0);
2877159952Sobrien
2878159952Sobrien	/* disable interrupts */
2879170589Syongari	nfe_disable_intr(sc);
2880159952Sobrien
2881159967Sobrien	sc->nfe_link = 0;
2882159967Sobrien
2883170589Syongari	/* free Rx and Tx mbufs still in the queues. */
2884170589Syongari	rx_ring = &sc->rxq;
2885170589Syongari	for (i = 0; i < NFE_RX_RING_COUNT; i++) {
2886170589Syongari		rdata = &rx_ring->data[i];
2887170589Syongari		if (rdata->m != NULL) {
2888170589Syongari			bus_dmamap_sync(rx_ring->rx_data_tag,
2889170589Syongari			    rdata->rx_data_map, BUS_DMASYNC_POSTREAD);
2890170589Syongari			bus_dmamap_unload(rx_ring->rx_data_tag,
2891170589Syongari			    rdata->rx_data_map);
2892170589Syongari			m_freem(rdata->m);
2893170589Syongari			rdata->m = NULL;
2894170589Syongari		}
2895170589Syongari	}
2896159952Sobrien
2897170589Syongari	if ((sc->nfe_flags & NFE_JUMBO_SUP) != 0) {
2898170589Syongari		jrx_ring = &sc->jrxq;
2899170589Syongari		for (i = 0; i < NFE_JUMBO_RX_RING_COUNT; i++) {
2900170589Syongari			rdata = &jrx_ring->jdata[i];
2901170589Syongari			if (rdata->m != NULL) {
2902170589Syongari				bus_dmamap_sync(jrx_ring->jrx_data_tag,
2903170589Syongari				    rdata->rx_data_map, BUS_DMASYNC_POSTREAD);
2904170589Syongari				bus_dmamap_unload(jrx_ring->jrx_data_tag,
2905170589Syongari				    rdata->rx_data_map);
2906170589Syongari				m_freem(rdata->m);
2907170589Syongari				rdata->m = NULL;
2908170589Syongari			}
2909170589Syongari		}
2910170589Syongari	}
2911170589Syongari
2912170589Syongari	tx_ring = &sc->txq;
2913170589Syongari	for (i = 0; i < NFE_RX_RING_COUNT; i++) {
2914170589Syongari		tdata = &tx_ring->data[i];
2915170589Syongari		if (tdata->m != NULL) {
2916170589Syongari			bus_dmamap_sync(tx_ring->tx_data_tag,
2917170589Syongari			    tdata->tx_data_map, BUS_DMASYNC_POSTWRITE);
2918170589Syongari			bus_dmamap_unload(tx_ring->tx_data_tag,
2919170589Syongari			    tdata->tx_data_map);
2920170589Syongari			m_freem(tdata->m);
2921170589Syongari			tdata->m = NULL;
2922170589Syongari		}
2923170589Syongari	}
2924183561Syongari	/* Update hardware stats. */
2925183561Syongari	nfe_stats_update(sc);
2926159952Sobrien}
2927159952Sobrien
2928163503Sobrien
2929163503Sobrienstatic int
2930163503Sobriennfe_ifmedia_upd(struct ifnet *ifp)
2931159952Sobrien{
2932159967Sobrien	struct nfe_softc *sc = ifp->if_softc;
2933170589Syongari	struct mii_data *mii;
2934159952Sobrien
2935159967Sobrien	NFE_LOCK(sc);
2936159967Sobrien	mii = device_get_softc(sc->nfe_miibus);
2937159967Sobrien	mii_mediachg(mii);
2938170589Syongari	NFE_UNLOCK(sc);
2939159967Sobrien
2940159967Sobrien	return (0);
2941159952Sobrien}
2942159952Sobrien
2943163503Sobrien
2944163503Sobrienstatic void
2945163503Sobriennfe_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
2946159952Sobrien{
2947163503Sobrien	struct nfe_softc *sc;
2948163503Sobrien	struct mii_data *mii;
2949159952Sobrien
2950159967Sobrien	sc = ifp->if_softc;
2951159952Sobrien
2952159967Sobrien	NFE_LOCK(sc);
2953159967Sobrien	mii = device_get_softc(sc->nfe_miibus);
2954159967Sobrien	mii_pollstat(mii);
2955159967Sobrien	NFE_UNLOCK(sc);
2956159952Sobrien
2957159967Sobrien	ifmr->ifm_active = mii->mii_media_active;
2958159967Sobrien	ifmr->ifm_status = mii->mii_media_status;
2959159952Sobrien}
2960159952Sobrien
2961163503Sobrien
2962170589Syongarivoid
2963159967Sobriennfe_tick(void *xsc)
2964159952Sobrien{
2965159967Sobrien	struct nfe_softc *sc;
2966163503Sobrien	struct mii_data *mii;
2967163503Sobrien	struct ifnet *ifp;
2968159952Sobrien
2969170589Syongari	sc = (struct nfe_softc *)xsc;
2970159952Sobrien
2971163503Sobrien	NFE_LOCK_ASSERT(sc);
2972159952Sobrien
2973159967Sobrien	ifp = sc->nfe_ifp;
2974159952Sobrien
2975159967Sobrien	mii = device_get_softc(sc->nfe_miibus);
2976159967Sobrien	mii_tick(mii);
2977183561Syongari	nfe_stats_update(sc);
2978170589Syongari	nfe_watchdog(ifp);
2979159967Sobrien	callout_reset(&sc->nfe_stat_ch, hz, nfe_tick, sc);
2980159952Sobrien}
2981159952Sobrien
2982159952Sobrien
2983173839Syongaristatic int
2984163503Sobriennfe_shutdown(device_t dev)
2985159952Sobrien{
2986159952Sobrien
2987215132Syongari	return (nfe_suspend(dev));
2988159952Sobrien}
2989159952Sobrien
2990159952Sobrien
2991163503Sobrienstatic void
2992170589Syongarinfe_get_macaddr(struct nfe_softc *sc, uint8_t *addr)
2993159952Sobrien{
2994170589Syongari	uint32_t val;
2995159952Sobrien
2996170589Syongari	if ((sc->nfe_flags & NFE_CORRECT_MACADDR) == 0) {
2997170589Syongari		val = NFE_READ(sc, NFE_MACADDR_LO);
2998170589Syongari		addr[0] = (val >> 8) & 0xff;
2999170589Syongari		addr[1] = (val & 0xff);
3000159952Sobrien
3001170589Syongari		val = NFE_READ(sc, NFE_MACADDR_HI);
3002170589Syongari		addr[2] = (val >> 24) & 0xff;
3003170589Syongari		addr[3] = (val >> 16) & 0xff;
3004170589Syongari		addr[4] = (val >>  8) & 0xff;
3005170589Syongari		addr[5] = (val & 0xff);
3006170589Syongari	} else {
3007170589Syongari		val = NFE_READ(sc, NFE_MACADDR_LO);
3008170589Syongari		addr[5] = (val >> 8) & 0xff;
3009170589Syongari		addr[4] = (val & 0xff);
3010170589Syongari
3011170589Syongari		val = NFE_READ(sc, NFE_MACADDR_HI);
3012170589Syongari		addr[3] = (val >> 24) & 0xff;
3013170589Syongari		addr[2] = (val >> 16) & 0xff;
3014170589Syongari		addr[1] = (val >>  8) & 0xff;
3015170589Syongari		addr[0] = (val & 0xff);
3016170589Syongari	}
3017159952Sobrien}
3018159952Sobrien
3019163503Sobrien
3020163503Sobrienstatic void
3021170589Syongarinfe_set_macaddr(struct nfe_softc *sc, uint8_t *addr)
3022159952Sobrien{
3023159967Sobrien
3024159967Sobrien	NFE_WRITE(sc, NFE_MACADDR_LO, addr[5] <<  8 | addr[4]);
3025159967Sobrien	NFE_WRITE(sc, NFE_MACADDR_HI, addr[3] << 24 | addr[2] << 16 |
3026159967Sobrien	    addr[1] << 8 | addr[0]);
3027159952Sobrien}
3028159952Sobrien
3029163503Sobrien
3030159967Sobrien/*
3031159967Sobrien * Map a single buffer address.
3032159967Sobrien */
3033159967Sobrien
3034159967Sobrienstatic void
3035170589Syongarinfe_dma_map_segs(void *arg, bus_dma_segment_t *segs, int nseg, int error)
3036159952Sobrien{
3037170589Syongari	struct nfe_dmamap_arg *ctx;
3038159952Sobrien
3039170589Syongari	if (error != 0)
3040159967Sobrien		return;
3041159952Sobrien
3042159967Sobrien	KASSERT(nseg == 1, ("too many DMA segments, %d should be 1", nseg));
3043159967Sobrien
3044170589Syongari	ctx = (struct nfe_dmamap_arg *)arg;
3045170589Syongari	ctx->nfe_busaddr = segs[0].ds_addr;
3046170589Syongari}
3047159967Sobrien
3048170589Syongari
3049170589Syongaristatic int
3050170589Syongarisysctl_int_range(SYSCTL_HANDLER_ARGS, int low, int high)
3051170589Syongari{
3052170589Syongari	int error, value;
3053170589Syongari
3054170589Syongari	if (!arg1)
3055170589Syongari		return (EINVAL);
3056170589Syongari	value = *(int *)arg1;
3057170589Syongari	error = sysctl_handle_int(oidp, &value, 0, req);
3058170589Syongari	if (error || !req->newptr)
3059170589Syongari		return (error);
3060170589Syongari	if (value < low || value > high)
3061170589Syongari		return (EINVAL);
3062170589Syongari	*(int *)arg1 = value;
3063170589Syongari
3064170589Syongari	return (0);
3065159952Sobrien}
3066170589Syongari
3067170589Syongari
3068170589Syongaristatic int
3069170589Syongarisysctl_hw_nfe_proc_limit(SYSCTL_HANDLER_ARGS)
3070170589Syongari{
3071170589Syongari
3072170589Syongari	return (sysctl_int_range(oidp, arg1, arg2, req, NFE_PROC_MIN,
3073170589Syongari	    NFE_PROC_MAX));
3074170589Syongari}
3075183561Syongari
3076183561Syongari
3077183561Syongari#define	NFE_SYSCTL_STAT_ADD32(c, h, n, p, d)	\
3078183561Syongari	    SYSCTL_ADD_UINT(c, h, OID_AUTO, n, CTLFLAG_RD, p, 0, d)
3079183561Syongari#define	NFE_SYSCTL_STAT_ADD64(c, h, n, p, d)	\
3080217323Smdf	    SYSCTL_ADD_UQUAD(c, h, OID_AUTO, n, CTLFLAG_RD, p, d)
3081183561Syongari
3082183561Syongaristatic void
3083183561Syongarinfe_sysctl_node(struct nfe_softc *sc)
3084183561Syongari{
3085183561Syongari	struct sysctl_ctx_list *ctx;
3086183561Syongari	struct sysctl_oid_list *child, *parent;
3087183561Syongari	struct sysctl_oid *tree;
3088183561Syongari	struct nfe_hw_stats *stats;
3089183561Syongari	int error;
3090183561Syongari
3091183561Syongari	stats = &sc->nfe_stats;
3092183561Syongari	ctx = device_get_sysctl_ctx(sc->nfe_dev);
3093183561Syongari	child = SYSCTL_CHILDREN(device_get_sysctl_tree(sc->nfe_dev));
3094183561Syongari	SYSCTL_ADD_PROC(ctx, child,
3095183561Syongari	    OID_AUTO, "process_limit", CTLTYPE_INT | CTLFLAG_RW,
3096183561Syongari	    &sc->nfe_process_limit, 0, sysctl_hw_nfe_proc_limit, "I",
3097183561Syongari	    "max number of Rx events to process");
3098183561Syongari
3099183561Syongari	sc->nfe_process_limit = NFE_PROC_DEFAULT;
3100183561Syongari	error = resource_int_value(device_get_name(sc->nfe_dev),
3101183561Syongari	    device_get_unit(sc->nfe_dev), "process_limit",
3102183561Syongari	    &sc->nfe_process_limit);
3103183561Syongari	if (error == 0) {
3104183561Syongari		if (sc->nfe_process_limit < NFE_PROC_MIN ||
3105183561Syongari		    sc->nfe_process_limit > NFE_PROC_MAX) {
3106183561Syongari			device_printf(sc->nfe_dev,
3107183561Syongari			    "process_limit value out of range; "
3108183561Syongari			    "using default: %d\n", NFE_PROC_DEFAULT);
3109183561Syongari			sc->nfe_process_limit = NFE_PROC_DEFAULT;
3110183561Syongari		}
3111183561Syongari	}
3112183561Syongari
3113183561Syongari	if ((sc->nfe_flags & (NFE_MIB_V1 | NFE_MIB_V2 | NFE_MIB_V3)) == 0)
3114183561Syongari		return;
3115183561Syongari
3116183561Syongari	tree = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "stats", CTLFLAG_RD,
3117183561Syongari	    NULL, "NFE statistics");
3118183561Syongari	parent = SYSCTL_CHILDREN(tree);
3119183561Syongari
3120183561Syongari	/* Rx statistics. */
3121183561Syongari	tree = SYSCTL_ADD_NODE(ctx, parent, OID_AUTO, "rx", CTLFLAG_RD,
3122183561Syongari	    NULL, "Rx MAC statistics");
3123183561Syongari	child = SYSCTL_CHILDREN(tree);
3124183561Syongari
3125183561Syongari	NFE_SYSCTL_STAT_ADD32(ctx, child, "frame_errors",
3126183561Syongari	    &stats->rx_frame_errors, "Framing Errors");
3127183561Syongari	NFE_SYSCTL_STAT_ADD32(ctx, child, "extra_bytes",
3128183561Syongari	    &stats->rx_extra_bytes, "Extra Bytes");
3129183561Syongari	NFE_SYSCTL_STAT_ADD32(ctx, child, "late_cols",
3130183561Syongari	    &stats->rx_late_cols, "Late Collisions");
3131183561Syongari	NFE_SYSCTL_STAT_ADD32(ctx, child, "runts",
3132183561Syongari	    &stats->rx_runts, "Runts");
3133183561Syongari	NFE_SYSCTL_STAT_ADD32(ctx, child, "jumbos",
3134183561Syongari	    &stats->rx_jumbos, "Jumbos");
3135183561Syongari	NFE_SYSCTL_STAT_ADD32(ctx, child, "fifo_overuns",
3136183561Syongari	    &stats->rx_fifo_overuns, "FIFO Overruns");
3137183561Syongari	NFE_SYSCTL_STAT_ADD32(ctx, child, "crc_errors",
3138183561Syongari	    &stats->rx_crc_errors, "CRC Errors");
3139183561Syongari	NFE_SYSCTL_STAT_ADD32(ctx, child, "fae",
3140183561Syongari	    &stats->rx_fae, "Frame Alignment Errors");
3141183561Syongari	NFE_SYSCTL_STAT_ADD32(ctx, child, "len_errors",
3142183561Syongari	    &stats->rx_len_errors, "Length Errors");
3143183561Syongari	NFE_SYSCTL_STAT_ADD32(ctx, child, "unicast",
3144183561Syongari	    &stats->rx_unicast, "Unicast Frames");
3145183561Syongari	NFE_SYSCTL_STAT_ADD32(ctx, child, "multicast",
3146183561Syongari	    &stats->rx_multicast, "Multicast Frames");
3147186346Syongari	NFE_SYSCTL_STAT_ADD32(ctx, child, "broadcast",
3148183561Syongari	    &stats->rx_broadcast, "Broadcast Frames");
3149183561Syongari	if ((sc->nfe_flags & NFE_MIB_V2) != 0) {
3150183561Syongari		NFE_SYSCTL_STAT_ADD64(ctx, child, "octets",
3151183561Syongari		    &stats->rx_octets, "Octets");
3152183561Syongari		NFE_SYSCTL_STAT_ADD32(ctx, child, "pause",
3153183561Syongari		    &stats->rx_pause, "Pause frames");
3154183561Syongari		NFE_SYSCTL_STAT_ADD32(ctx, child, "drops",
3155183561Syongari		    &stats->rx_drops, "Drop frames");
3156183561Syongari	}
3157183561Syongari
3158183561Syongari	/* Tx statistics. */
3159183561Syongari	tree = SYSCTL_ADD_NODE(ctx, parent, OID_AUTO, "tx", CTLFLAG_RD,
3160183561Syongari	    NULL, "Tx MAC statistics");
3161183561Syongari	child = SYSCTL_CHILDREN(tree);
3162183561Syongari	NFE_SYSCTL_STAT_ADD64(ctx, child, "octets",
3163183561Syongari	    &stats->tx_octets, "Octets");
3164183561Syongari	NFE_SYSCTL_STAT_ADD32(ctx, child, "zero_rexmits",
3165183561Syongari	    &stats->tx_zero_rexmits, "Zero Retransmits");
3166183561Syongari	NFE_SYSCTL_STAT_ADD32(ctx, child, "one_rexmits",
3167183561Syongari	    &stats->tx_one_rexmits, "One Retransmits");
3168183561Syongari	NFE_SYSCTL_STAT_ADD32(ctx, child, "multi_rexmits",
3169183561Syongari	    &stats->tx_multi_rexmits, "Multiple Retransmits");
3170183561Syongari	NFE_SYSCTL_STAT_ADD32(ctx, child, "late_cols",
3171183561Syongari	    &stats->tx_late_cols, "Late Collisions");
3172183561Syongari	NFE_SYSCTL_STAT_ADD32(ctx, child, "fifo_underuns",
3173183561Syongari	    &stats->tx_fifo_underuns, "FIFO Underruns");
3174183561Syongari	NFE_SYSCTL_STAT_ADD32(ctx, child, "carrier_losts",
3175183561Syongari	    &stats->tx_carrier_losts, "Carrier Losts");
3176183561Syongari	NFE_SYSCTL_STAT_ADD32(ctx, child, "excess_deferrals",
3177183561Syongari	    &stats->tx_excess_deferals, "Excess Deferrals");
3178183561Syongari	NFE_SYSCTL_STAT_ADD32(ctx, child, "retry_errors",
3179183561Syongari	    &stats->tx_retry_errors, "Retry Errors");
3180183561Syongari	if ((sc->nfe_flags & NFE_MIB_V2) != 0) {
3181183561Syongari		NFE_SYSCTL_STAT_ADD32(ctx, child, "deferrals",
3182183561Syongari		    &stats->tx_deferals, "Deferrals");
3183183561Syongari		NFE_SYSCTL_STAT_ADD32(ctx, child, "frames",
3184183561Syongari		    &stats->tx_frames, "Frames");
3185183561Syongari		NFE_SYSCTL_STAT_ADD32(ctx, child, "pause",
3186183561Syongari		    &stats->tx_pause, "Pause Frames");
3187183561Syongari	}
3188183561Syongari	if ((sc->nfe_flags & NFE_MIB_V3) != 0) {
3189183561Syongari		NFE_SYSCTL_STAT_ADD32(ctx, child, "unicast",
3190183561Syongari		    &stats->tx_deferals, "Unicast Frames");
3191183561Syongari		NFE_SYSCTL_STAT_ADD32(ctx, child, "multicast",
3192183561Syongari		    &stats->tx_frames, "Multicast Frames");
3193183561Syongari		NFE_SYSCTL_STAT_ADD32(ctx, child, "broadcast",
3194183561Syongari		    &stats->tx_pause, "Broadcast Frames");
3195183561Syongari	}
3196183561Syongari}
3197183561Syongari
3198183561Syongari#undef NFE_SYSCTL_STAT_ADD32
3199183561Syongari#undef NFE_SYSCTL_STAT_ADD64
3200183561Syongari
3201183561Syongaristatic void
3202183561Syongarinfe_stats_clear(struct nfe_softc *sc)
3203183561Syongari{
3204183561Syongari	int i, mib_cnt;
3205183561Syongari
3206183561Syongari	if ((sc->nfe_flags & NFE_MIB_V1) != 0)
3207183561Syongari		mib_cnt = NFE_NUM_MIB_STATV1;
3208183561Syongari	else if ((sc->nfe_flags & (NFE_MIB_V2 | NFE_MIB_V3)) != 0)
3209183561Syongari		mib_cnt = NFE_NUM_MIB_STATV2;
3210183561Syongari	else
3211183561Syongari		return;
3212183561Syongari
3213183561Syongari	for (i = 0; i < mib_cnt; i += sizeof(uint32_t))
3214183561Syongari		NFE_READ(sc, NFE_TX_OCTET + i);
3215183561Syongari
3216183561Syongari	if ((sc->nfe_flags & NFE_MIB_V3) != 0) {
3217183561Syongari		NFE_READ(sc, NFE_TX_UNICAST);
3218183561Syongari		NFE_READ(sc, NFE_TX_MULTICAST);
3219183561Syongari		NFE_READ(sc, NFE_TX_BROADCAST);
3220183561Syongari	}
3221183561Syongari}
3222183561Syongari
3223183561Syongaristatic void
3224183561Syongarinfe_stats_update(struct nfe_softc *sc)
3225183561Syongari{
3226183561Syongari	struct nfe_hw_stats *stats;
3227183561Syongari
3228183561Syongari	NFE_LOCK_ASSERT(sc);
3229183561Syongari
3230183561Syongari	if ((sc->nfe_flags & (NFE_MIB_V1 | NFE_MIB_V2 | NFE_MIB_V3)) == 0)
3231183561Syongari		return;
3232183561Syongari
3233183561Syongari	stats = &sc->nfe_stats;
3234183561Syongari	stats->tx_octets += NFE_READ(sc, NFE_TX_OCTET);
3235183561Syongari	stats->tx_zero_rexmits += NFE_READ(sc, NFE_TX_ZERO_REXMIT);
3236183561Syongari	stats->tx_one_rexmits += NFE_READ(sc, NFE_TX_ONE_REXMIT);
3237183561Syongari	stats->tx_multi_rexmits += NFE_READ(sc, NFE_TX_MULTI_REXMIT);
3238183561Syongari	stats->tx_late_cols += NFE_READ(sc, NFE_TX_LATE_COL);
3239183561Syongari	stats->tx_fifo_underuns += NFE_READ(sc, NFE_TX_FIFO_UNDERUN);
3240183561Syongari	stats->tx_carrier_losts += NFE_READ(sc, NFE_TX_CARRIER_LOST);
3241183561Syongari	stats->tx_excess_deferals += NFE_READ(sc, NFE_TX_EXCESS_DEFERRAL);
3242183561Syongari	stats->tx_retry_errors += NFE_READ(sc, NFE_TX_RETRY_ERROR);
3243183561Syongari	stats->rx_frame_errors += NFE_READ(sc, NFE_RX_FRAME_ERROR);
3244183561Syongari	stats->rx_extra_bytes += NFE_READ(sc, NFE_RX_EXTRA_BYTES);
3245183561Syongari	stats->rx_late_cols += NFE_READ(sc, NFE_RX_LATE_COL);
3246183561Syongari	stats->rx_runts += NFE_READ(sc, NFE_RX_RUNT);
3247183561Syongari	stats->rx_jumbos += NFE_READ(sc, NFE_RX_JUMBO);
3248183561Syongari	stats->rx_fifo_overuns += NFE_READ(sc, NFE_RX_FIFO_OVERUN);
3249183561Syongari	stats->rx_crc_errors += NFE_READ(sc, NFE_RX_CRC_ERROR);
3250183561Syongari	stats->rx_fae += NFE_READ(sc, NFE_RX_FAE);
3251183561Syongari	stats->rx_len_errors += NFE_READ(sc, NFE_RX_LEN_ERROR);
3252183561Syongari	stats->rx_unicast += NFE_READ(sc, NFE_RX_UNICAST);
3253183561Syongari	stats->rx_multicast += NFE_READ(sc, NFE_RX_MULTICAST);
3254183561Syongari	stats->rx_broadcast += NFE_READ(sc, NFE_RX_BROADCAST);
3255183561Syongari
3256183561Syongari	if ((sc->nfe_flags & NFE_MIB_V2) != 0) {
3257183561Syongari		stats->tx_deferals += NFE_READ(sc, NFE_TX_DEFERAL);
3258183561Syongari		stats->tx_frames += NFE_READ(sc, NFE_TX_FRAME);
3259183561Syongari		stats->rx_octets += NFE_READ(sc, NFE_RX_OCTET);
3260183561Syongari		stats->tx_pause += NFE_READ(sc, NFE_TX_PAUSE);
3261183561Syongari		stats->rx_pause += NFE_READ(sc, NFE_RX_PAUSE);
3262183561Syongari		stats->rx_drops += NFE_READ(sc, NFE_RX_DROP);
3263183561Syongari	}
3264183561Syongari
3265183561Syongari	if ((sc->nfe_flags & NFE_MIB_V3) != 0) {
3266183561Syongari		stats->tx_unicast += NFE_READ(sc, NFE_TX_UNICAST);
3267183561Syongari		stats->tx_multicast += NFE_READ(sc, NFE_TX_MULTICAST);
3268183561Syongari		stats->rx_broadcast += NFE_READ(sc, NFE_TX_BROADCAST);
3269183561Syongari	}
3270183561Syongari}
3271215132Syongari
3272215132Syongari
3273215132Syongaristatic void
3274215132Syongarinfe_set_linkspeed(struct nfe_softc *sc)
3275215132Syongari{
3276215132Syongari	struct mii_softc *miisc;
3277215132Syongari	struct mii_data *mii;
3278215132Syongari	int aneg, i, phyno;
3279215132Syongari
3280215132Syongari	NFE_LOCK_ASSERT(sc);
3281215132Syongari
3282215132Syongari	mii = device_get_softc(sc->nfe_miibus);
3283215132Syongari	mii_pollstat(mii);
3284215132Syongari	aneg = 0;
3285215132Syongari	if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) ==
3286215132Syongari	    (IFM_ACTIVE | IFM_AVALID)) {
3287215132Syongari		switch IFM_SUBTYPE(mii->mii_media_active) {
3288215132Syongari		case IFM_10_T:
3289215132Syongari		case IFM_100_TX:
3290215132Syongari			return;
3291215132Syongari		case IFM_1000_T:
3292215132Syongari			aneg++;
3293215132Syongari			break;
3294215132Syongari		default:
3295215132Syongari			break;
3296215132Syongari		}
3297215132Syongari	}
3298221407Smarius	miisc = LIST_FIRST(&mii->mii_phys);
3299221407Smarius	phyno = miisc->mii_phy;
3300221407Smarius	LIST_FOREACH(miisc, &mii->mii_phys, mii_list)
3301221407Smarius		PHY_RESET(miisc);
3302215132Syongari	nfe_miibus_writereg(sc->nfe_dev, phyno, MII_100T2CR, 0);
3303215132Syongari	nfe_miibus_writereg(sc->nfe_dev, phyno,
3304215132Syongari	    MII_ANAR, ANAR_TX_FD | ANAR_TX | ANAR_10_FD | ANAR_10 | ANAR_CSMA);
3305215132Syongari	nfe_miibus_writereg(sc->nfe_dev, phyno,
3306215132Syongari	    MII_BMCR, BMCR_RESET | BMCR_AUTOEN | BMCR_STARTNEG);
3307215132Syongari	DELAY(1000);
3308215132Syongari	if (aneg != 0) {
3309215132Syongari		/*
3310215132Syongari		 * Poll link state until nfe(4) get a 10/100Mbps link.
3311215132Syongari		 */
3312215132Syongari		for (i = 0; i < MII_ANEGTICKS_GIGE; i++) {
3313215132Syongari			mii_pollstat(mii);
3314215132Syongari			if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID))
3315215132Syongari			    == (IFM_ACTIVE | IFM_AVALID)) {
3316215132Syongari				switch (IFM_SUBTYPE(mii->mii_media_active)) {
3317215132Syongari				case IFM_10_T:
3318215132Syongari				case IFM_100_TX:
3319215132Syongari					nfe_mac_config(sc, mii);
3320215132Syongari					return;
3321215132Syongari				default:
3322215132Syongari					break;
3323215132Syongari				}
3324215132Syongari			}
3325215132Syongari			NFE_UNLOCK(sc);
3326215132Syongari			pause("nfelnk", hz);
3327215132Syongari			NFE_LOCK(sc);
3328215132Syongari		}
3329215132Syongari		if (i == MII_ANEGTICKS_GIGE)
3330215132Syongari			device_printf(sc->nfe_dev,
3331215132Syongari			    "establishing a link failed, WOL may not work!");
3332215132Syongari	}
3333215132Syongari	/*
3334215132Syongari	 * No link, force MAC to have 100Mbps, full-duplex link.
3335215132Syongari	 * This is the last resort and may/may not work.
3336215132Syongari	 */
3337215132Syongari	mii->mii_media_status = IFM_AVALID | IFM_ACTIVE;
3338215132Syongari	mii->mii_media_active = IFM_ETHER | IFM_100_TX | IFM_FDX;
3339215132Syongari	nfe_mac_config(sc, mii);
3340215132Syongari}
3341215132Syongari
3342215132Syongari
3343215132Syongaristatic void
3344215132Syongarinfe_set_wol(struct nfe_softc *sc)
3345215132Syongari{
3346215132Syongari	struct ifnet *ifp;
3347215132Syongari	uint32_t wolctl;
3348215132Syongari	int pmc;
3349215132Syongari	uint16_t pmstat;
3350215132Syongari
3351215132Syongari	NFE_LOCK_ASSERT(sc);
3352215132Syongari
3353219902Sjhb	if (pci_find_cap(sc->nfe_dev, PCIY_PMG, &pmc) != 0)
3354215132Syongari		return;
3355215132Syongari	ifp = sc->nfe_ifp;
3356215132Syongari	if ((ifp->if_capenable & IFCAP_WOL_MAGIC) != 0)
3357215132Syongari		wolctl = NFE_WOL_MAGIC;
3358215132Syongari	else
3359215132Syongari		wolctl = 0;
3360215132Syongari	NFE_WRITE(sc, NFE_WOL_CTL, wolctl);
3361215132Syongari	if ((ifp->if_capenable & IFCAP_WOL_MAGIC) != 0) {
3362215132Syongari		nfe_set_linkspeed(sc);
3363215132Syongari		if ((sc->nfe_flags & NFE_PWR_MGMT) != 0)
3364215132Syongari			NFE_WRITE(sc, NFE_PWR2_CTL,
3365215132Syongari			    NFE_READ(sc, NFE_PWR2_CTL) & ~NFE_PWR2_GATE_CLOCKS);
3366215132Syongari		/* Enable RX. */
3367215132Syongari		NFE_WRITE(sc, NFE_RX_RING_ADDR_HI, 0);
3368215132Syongari		NFE_WRITE(sc, NFE_RX_RING_ADDR_LO, 0);
3369215132Syongari		NFE_WRITE(sc, NFE_RX_CTL, NFE_READ(sc, NFE_RX_CTL) |
3370215132Syongari		    NFE_RX_START);
3371215132Syongari	}
3372215132Syongari	/* Request PME if WOL is requested. */
3373215132Syongari	pmstat = pci_read_config(sc->nfe_dev, pmc + PCIR_POWER_STATUS, 2);
3374215132Syongari	pmstat &= ~(PCIM_PSTAT_PME | PCIM_PSTAT_PMEENABLE);
3375215132Syongari	if ((ifp->if_capenable & IFCAP_WOL) != 0)
3376215132Syongari		pmstat |= PCIM_PSTAT_PME | PCIM_PSTAT_PMEENABLE;
3377215132Syongari	pci_write_config(sc->nfe_dev, pmc + PCIR_POWER_STATUS, pmstat, 2);
3378215132Syongari}
3379