if_nfe.c revision 296272
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 296272 2016-03-01 17:47:32Z jhb $");
25159952Sobrien
26159967Sobrien#ifdef HAVE_KERNEL_OPTION_HEADERS
27159967Sobrien#include "opt_device_polling.h"
28159967Sobrien#endif
29159967Sobrien
30159952Sobrien#include <sys/param.h>
31159952Sobrien#include <sys/endian.h>
32159952Sobrien#include <sys/systm.h>
33159952Sobrien#include <sys/sockio.h>
34159952Sobrien#include <sys/mbuf.h>
35159952Sobrien#include <sys/malloc.h>
36159967Sobrien#include <sys/module.h>
37159952Sobrien#include <sys/kernel.h>
38170589Syongari#include <sys/queue.h>
39159952Sobrien#include <sys/socket.h>
40170589Syongari#include <sys/sysctl.h>
41159967Sobrien#include <sys/taskqueue.h>
42159952Sobrien
43159952Sobrien#include <net/if.h>
44257176Sglebius#include <net/if_var.h>
45159967Sobrien#include <net/if_arp.h>
46159967Sobrien#include <net/ethernet.h>
47159952Sobrien#include <net/if_dl.h>
48159952Sobrien#include <net/if_media.h>
49159952Sobrien#include <net/if_types.h>
50159952Sobrien#include <net/if_vlan_var.h>
51159952Sobrien
52159952Sobrien#include <net/bpf.h>
53159952Sobrien
54159967Sobrien#include <machine/bus.h>
55159967Sobrien#include <machine/resource.h>
56159967Sobrien#include <sys/bus.h>
57159967Sobrien#include <sys/rman.h>
58159967Sobrien
59159952Sobrien#include <dev/mii/mii.h>
60159952Sobrien#include <dev/mii/miivar.h>
61159952Sobrien
62159952Sobrien#include <dev/pci/pcireg.h>
63159952Sobrien#include <dev/pci/pcivar.h>
64159952Sobrien
65159967Sobrien#include <dev/nfe/if_nfereg.h>
66159967Sobrien#include <dev/nfe/if_nfevar.h>
67159952Sobrien
68159967SobrienMODULE_DEPEND(nfe, pci, 1, 1, 1);
69159967SobrienMODULE_DEPEND(nfe, ether, 1, 1, 1);
70159967SobrienMODULE_DEPEND(nfe, miibus, 1, 1, 1);
71170589Syongari
72170589Syongari/* "device miibus" required.  See GENERIC if you get errors here. */
73159967Sobrien#include "miibus_if.h"
74159952Sobrien
75163503Sobrienstatic int  nfe_probe(device_t);
76163503Sobrienstatic int  nfe_attach(device_t);
77163503Sobrienstatic int  nfe_detach(device_t);
78170589Syongaristatic int  nfe_suspend(device_t);
79170589Syongaristatic int  nfe_resume(device_t);
80173839Syongaristatic int nfe_shutdown(device_t);
81215327Syongaristatic int  nfe_can_use_msix(struct nfe_softc *);
82264293Syongaristatic int  nfe_detect_msik9(struct nfe_softc *);
83170589Syongaristatic void nfe_power(struct nfe_softc *);
84163503Sobrienstatic int  nfe_miibus_readreg(device_t, int, int);
85163503Sobrienstatic int  nfe_miibus_writereg(device_t, int, int, int);
86163503Sobrienstatic void nfe_miibus_statchg(device_t);
87215132Syongaristatic void nfe_mac_config(struct nfe_softc *, struct mii_data *);
88170589Syongaristatic void nfe_set_intr(struct nfe_softc *);
89170589Syongaristatic __inline void nfe_enable_intr(struct nfe_softc *);
90170589Syongaristatic __inline void nfe_disable_intr(struct nfe_softc *);
91268131Smarcelstatic int  nfe_ioctl(if_t, u_long, caddr_t);
92170589Syongaristatic void nfe_alloc_msix(struct nfe_softc *, int);
93170589Syongaristatic int nfe_intr(void *);
94170589Syongaristatic void nfe_int_task(void *, int);
95170589Syongaristatic __inline void nfe_discard_rxbuf(struct nfe_softc *, int);
96170589Syongaristatic __inline void nfe_discard_jrxbuf(struct nfe_softc *, int);
97170589Syongaristatic int nfe_newbuf(struct nfe_softc *, int);
98170589Syongaristatic int nfe_jnewbuf(struct nfe_softc *, int);
99193096Sattiliostatic int  nfe_rxeof(struct nfe_softc *, int, int *);
100193096Sattiliostatic int  nfe_jrxeof(struct nfe_softc *, int, int *);
101159967Sobrienstatic void nfe_txeof(struct nfe_softc *);
102170589Syongaristatic int  nfe_encap(struct nfe_softc *, struct mbuf **);
103159967Sobrienstatic void nfe_setmulti(struct nfe_softc *);
104268131Smarcelstatic void nfe_start(if_t);
105268131Smarcelstatic void nfe_start_locked(if_t);
106268131Smarcelstatic void nfe_watchdog(if_t);
107159967Sobrienstatic void nfe_init(void *);
108159967Sobrienstatic void nfe_init_locked(void *);
109268131Smarcelstatic void nfe_stop(if_t);
110159967Sobrienstatic int  nfe_alloc_rx_ring(struct nfe_softc *, struct nfe_rx_ring *);
111171559Syongaristatic void nfe_alloc_jrx_ring(struct nfe_softc *, struct nfe_jrx_ring *);
112170589Syongaristatic int  nfe_init_rx_ring(struct nfe_softc *, struct nfe_rx_ring *);
113170589Syongaristatic int  nfe_init_jrx_ring(struct nfe_softc *, struct nfe_jrx_ring *);
114159967Sobrienstatic void nfe_free_rx_ring(struct nfe_softc *, struct nfe_rx_ring *);
115170589Syongaristatic void nfe_free_jrx_ring(struct nfe_softc *, struct nfe_jrx_ring *);
116159967Sobrienstatic int  nfe_alloc_tx_ring(struct nfe_softc *, struct nfe_tx_ring *);
117170589Syongaristatic void nfe_init_tx_ring(struct nfe_softc *, struct nfe_tx_ring *);
118159967Sobrienstatic void nfe_free_tx_ring(struct nfe_softc *, struct nfe_tx_ring *);
119268131Smarcelstatic int  nfe_ifmedia_upd(if_t);
120268131Smarcelstatic void nfe_ifmedia_sts(if_t, struct ifmediareq *);
121159967Sobrienstatic void nfe_tick(void *);
122170589Syongaristatic void nfe_get_macaddr(struct nfe_softc *, uint8_t *);
123170589Syongaristatic void nfe_set_macaddr(struct nfe_softc *, uint8_t *);
124170589Syongaristatic void nfe_dma_map_segs(void *, bus_dma_segment_t *, int, int);
125159952Sobrien
126170589Syongaristatic int sysctl_int_range(SYSCTL_HANDLER_ARGS, int, int);
127170589Syongaristatic int sysctl_hw_nfe_proc_limit(SYSCTL_HANDLER_ARGS);
128183561Syongaristatic void nfe_sysctl_node(struct nfe_softc *);
129183561Syongaristatic void nfe_stats_clear(struct nfe_softc *);
130183561Syongaristatic void nfe_stats_update(struct nfe_softc *);
131215132Syongaristatic void nfe_set_linkspeed(struct nfe_softc *);
132215132Syongaristatic void nfe_set_wol(struct nfe_softc *);
133170589Syongari
134159952Sobrien#ifdef NFE_DEBUG
135170589Syongaristatic int nfedebug = 0;
136170589Syongari#define	DPRINTF(sc, ...)	do {				\
137170589Syongari	if (nfedebug)						\
138170589Syongari		device_printf((sc)->nfe_dev, __VA_ARGS__);	\
139170589Syongari} while (0)
140170589Syongari#define	DPRINTFN(sc, n, ...)	do {				\
141170589Syongari	if (nfedebug >= (n))					\
142170589Syongari		device_printf((sc)->nfe_dev, __VA_ARGS__);	\
143170589Syongari} while (0)
144159952Sobrien#else
145170589Syongari#define	DPRINTF(sc, ...)
146170589Syongari#define	DPRINTFN(sc, n, ...)
147159952Sobrien#endif
148159952Sobrien
149159967Sobrien#define	NFE_LOCK(_sc)		mtx_lock(&(_sc)->nfe_mtx)
150159967Sobrien#define	NFE_UNLOCK(_sc)		mtx_unlock(&(_sc)->nfe_mtx)
151159967Sobrien#define	NFE_LOCK_ASSERT(_sc)	mtx_assert(&(_sc)->nfe_mtx, MA_OWNED)
152159967Sobrien
153170589Syongari/* Tunables. */
154170589Syongaristatic int msi_disable = 0;
155170589Syongaristatic int msix_disable = 0;
156171559Syongaristatic int jumbo_disable = 0;
157170589SyongariTUNABLE_INT("hw.nfe.msi_disable", &msi_disable);
158170589SyongariTUNABLE_INT("hw.nfe.msix_disable", &msix_disable);
159171559SyongariTUNABLE_INT("hw.nfe.jumbo_disable", &jumbo_disable);
160159967Sobrien
161159967Sobrienstatic device_method_t nfe_methods[] = {
162159967Sobrien	/* Device interface */
163159967Sobrien	DEVMETHOD(device_probe,		nfe_probe),
164159967Sobrien	DEVMETHOD(device_attach,	nfe_attach),
165159967Sobrien	DEVMETHOD(device_detach,	nfe_detach),
166170589Syongari	DEVMETHOD(device_suspend,	nfe_suspend),
167170589Syongari	DEVMETHOD(device_resume,	nfe_resume),
168159967Sobrien	DEVMETHOD(device_shutdown,	nfe_shutdown),
169159967Sobrien
170159967Sobrien	/* MII interface */
171159967Sobrien	DEVMETHOD(miibus_readreg,	nfe_miibus_readreg),
172159967Sobrien	DEVMETHOD(miibus_writereg,	nfe_miibus_writereg),
173163503Sobrien	DEVMETHOD(miibus_statchg,	nfe_miibus_statchg),
174159967Sobrien
175227843Smarius	DEVMETHOD_END
176159952Sobrien};
177159952Sobrien
178159967Sobrienstatic driver_t nfe_driver = {
179159967Sobrien	"nfe",
180159967Sobrien	nfe_methods,
181159967Sobrien	sizeof(struct nfe_softc)
182159967Sobrien};
183159967Sobrien
184159967Sobrienstatic devclass_t nfe_devclass;
185159967Sobrien
186159967SobrienDRIVER_MODULE(nfe, pci, nfe_driver, nfe_devclass, 0, 0);
187159967SobrienDRIVER_MODULE(miibus, nfe, miibus_driver, miibus_devclass, 0, 0);
188159967Sobrien
189159967Sobrienstatic struct nfe_type nfe_devs[] = {
190159967Sobrien	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE_LAN,
191163503Sobrien	    "NVIDIA nForce MCP Networking Adapter"},
192159967Sobrien	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE2_LAN,
193163503Sobrien	    "NVIDIA nForce2 MCP2 Networking Adapter"},
194159967Sobrien	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE2_400_LAN1,
195163503Sobrien	    "NVIDIA nForce2 400 MCP4 Networking Adapter"},
196159967Sobrien	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE2_400_LAN2,
197163503Sobrien	    "NVIDIA nForce2 400 MCP5 Networking Adapter"},
198163437Sobrien	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE3_LAN1,
199163503Sobrien	    "NVIDIA nForce3 MCP3 Networking Adapter"},
200159967Sobrien	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE3_250_LAN,
201163503Sobrien	    "NVIDIA nForce3 250 MCP6 Networking Adapter"},
202159967Sobrien	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE3_LAN4,
203163503Sobrien	    "NVIDIA nForce3 MCP7 Networking Adapter"},
204159967Sobrien	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE4_LAN1,
205163503Sobrien	    "NVIDIA nForce4 CK804 MCP8 Networking Adapter"},
206159967Sobrien	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE4_LAN2,
207163503Sobrien	    "NVIDIA nForce4 CK804 MCP9 Networking Adapter"},
208159967Sobrien	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP04_LAN1,
209170589Syongari	    "NVIDIA nForce MCP04 Networking Adapter"},		/* MCP10 */
210159967Sobrien	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP04_LAN2,
211170589Syongari	    "NVIDIA nForce MCP04 Networking Adapter"},		/* MCP11 */
212159967Sobrien	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE430_LAN1,
213163503Sobrien	    "NVIDIA nForce 430 MCP12 Networking Adapter"},
214159967Sobrien	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE430_LAN2,
215163503Sobrien	    "NVIDIA nForce 430 MCP13 Networking Adapter"},
216159967Sobrien	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP55_LAN1,
217163503Sobrien	    "NVIDIA nForce MCP55 Networking Adapter"},
218159967Sobrien	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP55_LAN2,
219163503Sobrien	    "NVIDIA nForce MCP55 Networking Adapter"},
220162212Sobrien	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP61_LAN1,
221163503Sobrien	    "NVIDIA nForce MCP61 Networking Adapter"},
222162212Sobrien	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP61_LAN2,
223163503Sobrien	    "NVIDIA nForce MCP61 Networking Adapter"},
224162212Sobrien	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP61_LAN3,
225163503Sobrien	    "NVIDIA nForce MCP61 Networking Adapter"},
226170589Syongari	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP61_LAN4,
227163503Sobrien	    "NVIDIA nForce MCP61 Networking Adapter"},
228162212Sobrien	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP65_LAN1,
229163503Sobrien	    "NVIDIA nForce MCP65 Networking Adapter"},
230162212Sobrien	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP65_LAN2,
231163503Sobrien	    "NVIDIA nForce MCP65 Networking Adapter"},
232162212Sobrien	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP65_LAN3,
233163503Sobrien	    "NVIDIA nForce MCP65 Networking Adapter"},
234170589Syongari	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP65_LAN4,
235163503Sobrien	    "NVIDIA nForce MCP65 Networking Adapter"},
236170589Syongari	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP67_LAN1,
237170589Syongari	    "NVIDIA nForce MCP67 Networking Adapter"},
238170589Syongari	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP67_LAN2,
239170589Syongari	    "NVIDIA nForce MCP67 Networking Adapter"},
240170589Syongari	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP67_LAN3,
241170589Syongari	    "NVIDIA nForce MCP67 Networking Adapter"},
242170589Syongari	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP67_LAN4,
243170589Syongari	    "NVIDIA nForce MCP67 Networking Adapter"},
244178055Syongari	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP73_LAN1,
245178055Syongari	    "NVIDIA nForce MCP73 Networking Adapter"},
246178055Syongari	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP73_LAN2,
247178055Syongari	    "NVIDIA nForce MCP73 Networking Adapter"},
248178055Syongari	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP73_LAN3,
249178055Syongari	    "NVIDIA nForce MCP73 Networking Adapter"},
250178055Syongari	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP73_LAN4,
251178055Syongari	    "NVIDIA nForce MCP73 Networking Adapter"},
252183509Syongari	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP77_LAN1,
253183509Syongari	    "NVIDIA nForce MCP77 Networking Adapter"},
254183509Syongari	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP77_LAN2,
255183509Syongari	    "NVIDIA nForce MCP77 Networking Adapter"},
256183509Syongari	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP77_LAN3,
257183509Syongari	    "NVIDIA nForce MCP77 Networking Adapter"},
258183509Syongari	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP77_LAN4,
259183509Syongari	    "NVIDIA nForce MCP77 Networking Adapter"},
260183509Syongari	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP79_LAN1,
261183509Syongari	    "NVIDIA nForce MCP79 Networking Adapter"},
262183509Syongari	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP79_LAN2,
263183509Syongari	    "NVIDIA nForce MCP79 Networking Adapter"},
264183509Syongari	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP79_LAN3,
265183509Syongari	    "NVIDIA nForce MCP79 Networking Adapter"},
266183509Syongari	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP79_LAN4,
267183509Syongari	    "NVIDIA nForce MCP79 Networking Adapter"},
268159967Sobrien	{0, 0, NULL}
269159967Sobrien};
270159967Sobrien
271159967Sobrien
272159967Sobrien/* Probe for supported hardware ID's */
273159967Sobrienstatic int
274159967Sobriennfe_probe(device_t dev)
275159952Sobrien{
276159967Sobrien	struct nfe_type *t;
277159967Sobrien
278159967Sobrien	t = nfe_devs;
279159967Sobrien	/* Check for matching PCI DEVICE ID's */
280159967Sobrien	while (t->name != NULL) {
281159967Sobrien		if ((pci_get_vendor(dev) == t->vid_id) &&
282159967Sobrien		    (pci_get_device(dev) == t->dev_id)) {
283159967Sobrien			device_set_desc(dev, t->name);
284170589Syongari			return (BUS_PROBE_DEFAULT);
285159967Sobrien		}
286159967Sobrien		t++;
287159967Sobrien	}
288159967Sobrien
289159967Sobrien	return (ENXIO);
290159952Sobrien}
291159952Sobrien
292170589Syongaristatic void
293170589Syongarinfe_alloc_msix(struct nfe_softc *sc, int count)
294170589Syongari{
295170589Syongari	int rid;
296163503Sobrien
297170589Syongari	rid = PCIR_BAR(2);
298170589Syongari	sc->nfe_msix_res = bus_alloc_resource_any(sc->nfe_dev, SYS_RES_MEMORY,
299170589Syongari	    &rid, RF_ACTIVE);
300170589Syongari	if (sc->nfe_msix_res == NULL) {
301170589Syongari		device_printf(sc->nfe_dev,
302170589Syongari		    "couldn't allocate MSIX table resource\n");
303170589Syongari		return;
304170589Syongari	}
305170589Syongari	rid = PCIR_BAR(3);
306170589Syongari	sc->nfe_msix_pba_res = bus_alloc_resource_any(sc->nfe_dev,
307170589Syongari	    SYS_RES_MEMORY, &rid, RF_ACTIVE);
308170589Syongari	if (sc->nfe_msix_pba_res == NULL) {
309170589Syongari		device_printf(sc->nfe_dev,
310170589Syongari		    "couldn't allocate MSIX PBA resource\n");
311170589Syongari		bus_release_resource(sc->nfe_dev, SYS_RES_MEMORY, PCIR_BAR(2),
312170589Syongari		    sc->nfe_msix_res);
313170589Syongari		sc->nfe_msix_res = NULL;
314170589Syongari		return;
315170589Syongari	}
316170589Syongari
317170589Syongari	if (pci_alloc_msix(sc->nfe_dev, &count) == 0) {
318170589Syongari		if (count == NFE_MSI_MESSAGES) {
319170589Syongari			if (bootverbose)
320170589Syongari				device_printf(sc->nfe_dev,
321170589Syongari				    "Using %d MSIX messages\n", count);
322170589Syongari			sc->nfe_msix = 1;
323170589Syongari		} else {
324170589Syongari			if (bootverbose)
325170589Syongari				device_printf(sc->nfe_dev,
326170589Syongari				    "couldn't allocate MSIX\n");
327170589Syongari			pci_release_msi(sc->nfe_dev);
328170589Syongari			bus_release_resource(sc->nfe_dev, SYS_RES_MEMORY,
329170589Syongari			    PCIR_BAR(3), sc->nfe_msix_pba_res);
330170589Syongari			bus_release_resource(sc->nfe_dev, SYS_RES_MEMORY,
331170589Syongari			    PCIR_BAR(2), sc->nfe_msix_res);
332170589Syongari			sc->nfe_msix_pba_res = NULL;
333170589Syongari			sc->nfe_msix_res = NULL;
334170589Syongari		}
335170589Syongari	}
336170589Syongari}
337170589Syongari
338264293Syongari
339159967Sobrienstatic int
340264293Syongarinfe_detect_msik9(struct nfe_softc *sc)
341264293Syongari{
342264293Syongari	static const char *maker = "MSI";
343264293Syongari	static const char *product = "K9N6PGM2-V2 (MS-7309)";
344264293Syongari	char *m, *p;
345264293Syongari	int found;
346264293Syongari
347264293Syongari	found = 0;
348273174Sdavide	m = kern_getenv("smbios.planar.maker");
349273174Sdavide	p = kern_getenv("smbios.planar.product");
350264293Syongari	if (m != NULL && p != NULL) {
351264293Syongari		if (strcmp(m, maker) == 0 && strcmp(p, product) == 0)
352264293Syongari			found = 1;
353264293Syongari	}
354264293Syongari	if (m != NULL)
355264293Syongari		freeenv(m);
356264293Syongari	if (p != NULL)
357264293Syongari		freeenv(p);
358264293Syongari
359264293Syongari	return (found);
360264293Syongari}
361264293Syongari
362264293Syongari
363264293Syongaristatic int
364159967Sobriennfe_attach(device_t dev)
365159952Sobrien{
366159967Sobrien	struct nfe_softc *sc;
367268131Smarcel	if_t ifp;
368170589Syongari	bus_addr_t dma_addr_max;
369264293Syongari	int error = 0, i, msic, phyloc, reg, rid;
370159952Sobrien
371159967Sobrien	sc = device_get_softc(dev);
372159967Sobrien	sc->nfe_dev = dev;
373159952Sobrien
374159967Sobrien	mtx_init(&sc->nfe_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK,
375170589Syongari	    MTX_DEF);
376159967Sobrien	callout_init_mtx(&sc->nfe_stat_ch, &sc->nfe_mtx, 0);
377159967Sobrien
378163503Sobrien	pci_enable_busmaster(dev);
379159967Sobrien
380170589Syongari	rid = PCIR_BAR(0);
381170589Syongari	sc->nfe_res[0] = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
382170589Syongari	    RF_ACTIVE);
383170589Syongari	if (sc->nfe_res[0] == NULL) {
384170589Syongari		device_printf(dev, "couldn't map memory resources\n");
385170589Syongari		mtx_destroy(&sc->nfe_mtx);
386170589Syongari		return (ENXIO);
387170589Syongari	}
388159967Sobrien
389219902Sjhb	if (pci_find_cap(dev, PCIY_EXPRESS, &reg) == 0) {
390170589Syongari		uint16_t v, width;
391170589Syongari
392170589Syongari		v = pci_read_config(dev, reg + 0x08, 2);
393170589Syongari		/* Change max. read request size to 4096. */
394170589Syongari		v &= ~(7 << 12);
395170589Syongari		v |= (5 << 12);
396170589Syongari		pci_write_config(dev, reg + 0x08, v, 2);
397170589Syongari
398170589Syongari		v = pci_read_config(dev, reg + 0x0c, 2);
399170589Syongari		/* link capability */
400170589Syongari		v = (v >> 4) & 0x0f;
401170589Syongari		width = pci_read_config(dev, reg + 0x12, 2);
402170589Syongari		/* negotiated link width */
403170589Syongari		width = (width >> 4) & 0x3f;
404170589Syongari		if (v != width)
405170589Syongari			device_printf(sc->nfe_dev,
406170589Syongari			    "warning, negotiated width of link(x%d) != "
407170589Syongari			    "max. width of link(x%d)\n", width, v);
408159952Sobrien	}
409159952Sobrien
410215327Syongari	if (nfe_can_use_msix(sc) == 0) {
411215327Syongari		device_printf(sc->nfe_dev,
412215327Syongari		    "MSI/MSI-X capability black-listed, will use INTx\n");
413215327Syongari		msix_disable = 1;
414215327Syongari		msi_disable = 1;
415215327Syongari	}
416215327Syongari
417159967Sobrien	/* Allocate interrupt */
418170589Syongari	if (msix_disable == 0 || msi_disable == 0) {
419170589Syongari		if (msix_disable == 0 &&
420170589Syongari		    (msic = pci_msix_count(dev)) == NFE_MSI_MESSAGES)
421170589Syongari			nfe_alloc_msix(sc, msic);
422170589Syongari		if (msi_disable == 0 && sc->nfe_msix == 0 &&
423170589Syongari		    (msic = pci_msi_count(dev)) == NFE_MSI_MESSAGES &&
424170589Syongari		    pci_alloc_msi(dev, &msic) == 0) {
425170589Syongari			if (msic == NFE_MSI_MESSAGES) {
426170589Syongari				if (bootverbose)
427170589Syongari					device_printf(dev,
428170589Syongari					    "Using %d MSI messages\n", msic);
429170589Syongari				sc->nfe_msi = 1;
430170589Syongari			} else
431170589Syongari				pci_release_msi(dev);
432170589Syongari		}
433170589Syongari	}
434159967Sobrien
435170589Syongari	if (sc->nfe_msix == 0 && sc->nfe_msi == 0) {
436170589Syongari		rid = 0;
437170589Syongari		sc->nfe_irq[0] = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
438170589Syongari		    RF_SHAREABLE | RF_ACTIVE);
439170589Syongari		if (sc->nfe_irq[0] == NULL) {
440170589Syongari			device_printf(dev, "couldn't allocate IRQ resources\n");
441170589Syongari			error = ENXIO;
442170589Syongari			goto fail;
443170589Syongari		}
444170589Syongari	} else {
445170589Syongari		for (i = 0, rid = 1; i < NFE_MSI_MESSAGES; i++, rid++) {
446170589Syongari			sc->nfe_irq[i] = bus_alloc_resource_any(dev,
447170589Syongari			    SYS_RES_IRQ, &rid, RF_ACTIVE);
448170589Syongari			if (sc->nfe_irq[i] == NULL) {
449170589Syongari				device_printf(dev,
450170589Syongari				    "couldn't allocate IRQ resources for "
451170589Syongari				    "message %d\n", rid);
452170589Syongari				error = ENXIO;
453170589Syongari				goto fail;
454170589Syongari			}
455170589Syongari		}
456170589Syongari		/* Map interrupts to vector 0. */
457170589Syongari		if (sc->nfe_msix != 0) {
458170589Syongari			NFE_WRITE(sc, NFE_MSIX_MAP0, 0);
459170589Syongari			NFE_WRITE(sc, NFE_MSIX_MAP1, 0);
460170589Syongari		} else if (sc->nfe_msi != 0) {
461170589Syongari			NFE_WRITE(sc, NFE_MSI_MAP0, 0);
462170589Syongari			NFE_WRITE(sc, NFE_MSI_MAP1, 0);
463170589Syongari		}
464159952Sobrien	}
465159952Sobrien
466170589Syongari	/* Set IRQ status/mask register. */
467170589Syongari	sc->nfe_irq_status = NFE_IRQ_STATUS;
468170589Syongari	sc->nfe_irq_mask = NFE_IRQ_MASK;
469170589Syongari	sc->nfe_intrs = NFE_IRQ_WANTED;
470170589Syongari	sc->nfe_nointrs = 0;
471170589Syongari	if (sc->nfe_msix != 0) {
472170589Syongari		sc->nfe_irq_status = NFE_MSIX_IRQ_STATUS;
473170589Syongari		sc->nfe_nointrs = NFE_IRQ_WANTED;
474170589Syongari	} else if (sc->nfe_msi != 0) {
475170589Syongari		sc->nfe_irq_mask = NFE_MSI_IRQ_MASK;
476170589Syongari		sc->nfe_intrs = NFE_MSI_VECTOR_0_ENABLED;
477170589Syongari	}
478159952Sobrien
479170589Syongari	sc->nfe_devid = pci_get_device(dev);
480170589Syongari	sc->nfe_revid = pci_get_revid(dev);
481159967Sobrien	sc->nfe_flags = 0;
482159952Sobrien
483170589Syongari	switch (sc->nfe_devid) {
484159952Sobrien	case PCI_PRODUCT_NVIDIA_NFORCE3_LAN2:
485159952Sobrien	case PCI_PRODUCT_NVIDIA_NFORCE3_LAN3:
486159952Sobrien	case PCI_PRODUCT_NVIDIA_NFORCE3_LAN4:
487159952Sobrien	case PCI_PRODUCT_NVIDIA_NFORCE3_LAN5:
488159967Sobrien		sc->nfe_flags |= NFE_JUMBO_SUP | NFE_HW_CSUM;
489159952Sobrien		break;
490159952Sobrien	case PCI_PRODUCT_NVIDIA_MCP51_LAN1:
491159952Sobrien	case PCI_PRODUCT_NVIDIA_MCP51_LAN2:
492183561Syongari		sc->nfe_flags |= NFE_40BIT_ADDR | NFE_PWR_MGMT | NFE_MIB_V1;
493159952Sobrien		break;
494159952Sobrien	case PCI_PRODUCT_NVIDIA_CK804_LAN1:
495159952Sobrien	case PCI_PRODUCT_NVIDIA_CK804_LAN2:
496159952Sobrien	case PCI_PRODUCT_NVIDIA_MCP04_LAN1:
497159952Sobrien	case PCI_PRODUCT_NVIDIA_MCP04_LAN2:
498183561Syongari		sc->nfe_flags |= NFE_JUMBO_SUP | NFE_40BIT_ADDR | NFE_HW_CSUM |
499183561Syongari		    NFE_MIB_V1;
500159952Sobrien		break;
501159952Sobrien	case PCI_PRODUCT_NVIDIA_MCP55_LAN1:
502159952Sobrien	case PCI_PRODUCT_NVIDIA_MCP55_LAN2:
503163503Sobrien		sc->nfe_flags |= NFE_JUMBO_SUP | NFE_40BIT_ADDR | NFE_HW_CSUM |
504183561Syongari		    NFE_HW_VLAN | NFE_PWR_MGMT | NFE_TX_FLOW_CTRL | NFE_MIB_V2;
505159952Sobrien		break;
506170589Syongari
507162212Sobrien	case PCI_PRODUCT_NVIDIA_MCP61_LAN1:
508162212Sobrien	case PCI_PRODUCT_NVIDIA_MCP61_LAN2:
509162212Sobrien	case PCI_PRODUCT_NVIDIA_MCP61_LAN3:
510162212Sobrien	case PCI_PRODUCT_NVIDIA_MCP61_LAN4:
511170589Syongari	case PCI_PRODUCT_NVIDIA_MCP67_LAN1:
512170589Syongari	case PCI_PRODUCT_NVIDIA_MCP67_LAN2:
513170589Syongari	case PCI_PRODUCT_NVIDIA_MCP67_LAN3:
514170589Syongari	case PCI_PRODUCT_NVIDIA_MCP67_LAN4:
515178055Syongari	case PCI_PRODUCT_NVIDIA_MCP73_LAN1:
516178055Syongari	case PCI_PRODUCT_NVIDIA_MCP73_LAN2:
517178055Syongari	case PCI_PRODUCT_NVIDIA_MCP73_LAN3:
518178055Syongari	case PCI_PRODUCT_NVIDIA_MCP73_LAN4:
519170589Syongari		sc->nfe_flags |= NFE_40BIT_ADDR | NFE_PWR_MGMT |
520183561Syongari		    NFE_CORRECT_MACADDR | NFE_TX_FLOW_CTRL | NFE_MIB_V2;
521162212Sobrien		break;
522183509Syongari	case PCI_PRODUCT_NVIDIA_MCP77_LAN1:
523183509Syongari	case PCI_PRODUCT_NVIDIA_MCP77_LAN2:
524183509Syongari	case PCI_PRODUCT_NVIDIA_MCP77_LAN3:
525183509Syongari	case PCI_PRODUCT_NVIDIA_MCP77_LAN4:
526183509Syongari		/* XXX flow control */
527183509Syongari		sc->nfe_flags |= NFE_40BIT_ADDR | NFE_HW_CSUM | NFE_PWR_MGMT |
528183561Syongari		    NFE_CORRECT_MACADDR | NFE_MIB_V3;
529183509Syongari		break;
530183509Syongari	case PCI_PRODUCT_NVIDIA_MCP79_LAN1:
531183509Syongari	case PCI_PRODUCT_NVIDIA_MCP79_LAN2:
532183509Syongari	case PCI_PRODUCT_NVIDIA_MCP79_LAN3:
533183509Syongari	case PCI_PRODUCT_NVIDIA_MCP79_LAN4:
534183509Syongari		/* XXX flow control */
535183509Syongari		sc->nfe_flags |= NFE_JUMBO_SUP | NFE_40BIT_ADDR | NFE_HW_CSUM |
536183561Syongari		    NFE_PWR_MGMT | NFE_CORRECT_MACADDR | NFE_MIB_V3;
537183509Syongari		break;
538162212Sobrien	case PCI_PRODUCT_NVIDIA_MCP65_LAN1:
539162212Sobrien	case PCI_PRODUCT_NVIDIA_MCP65_LAN2:
540162212Sobrien	case PCI_PRODUCT_NVIDIA_MCP65_LAN3:
541162212Sobrien	case PCI_PRODUCT_NVIDIA_MCP65_LAN4:
542170589Syongari		sc->nfe_flags |= NFE_JUMBO_SUP | NFE_40BIT_ADDR |
543183561Syongari		    NFE_PWR_MGMT | NFE_CORRECT_MACADDR | NFE_TX_FLOW_CTRL |
544183561Syongari		    NFE_MIB_V2;
545163503Sobrien		break;
546159952Sobrien	}
547159952Sobrien
548170589Syongari	nfe_power(sc);
549170589Syongari	/* Check for reversed ethernet address */
550170589Syongari	if ((NFE_READ(sc, NFE_TX_UNK) & NFE_MAC_ADDR_INORDER) != 0)
551170589Syongari		sc->nfe_flags |= NFE_CORRECT_MACADDR;
552170589Syongari	nfe_get_macaddr(sc, sc->eaddr);
553159952Sobrien	/*
554159967Sobrien	 * Allocate the parent bus DMA tag appropriate for PCI.
555159967Sobrien	 */
556170589Syongari	dma_addr_max = BUS_SPACE_MAXADDR_32BIT;
557170589Syongari	if ((sc->nfe_flags & NFE_40BIT_ADDR) != 0)
558170589Syongari		dma_addr_max = NFE_DMA_MAXADDR;
559170589Syongari	error = bus_dma_tag_create(
560170589Syongari	    bus_get_dma_tag(sc->nfe_dev),	/* parent */
561163503Sobrien	    1, 0,				/* alignment, boundary */
562170589Syongari	    dma_addr_max,			/* lowaddr */
563163503Sobrien	    BUS_SPACE_MAXADDR,			/* highaddr */
564163503Sobrien	    NULL, NULL,				/* filter, filterarg */
565170589Syongari	    BUS_SPACE_MAXSIZE_32BIT, 0,		/* maxsize, nsegments */
566163503Sobrien	    BUS_SPACE_MAXSIZE_32BIT,		/* maxsegsize */
567170589Syongari	    0,					/* flags */
568163503Sobrien	    NULL, NULL,				/* lockfunc, lockarg */
569163503Sobrien	    &sc->nfe_parent_tag);
570159967Sobrien	if (error)
571159967Sobrien		goto fail;
572159967Sobrien
573268131Smarcel	ifp = sc->nfe_ifp = if_gethandle(IFT_ETHER);
574164650Sobrien	if (ifp == NULL) {
575268131Smarcel		device_printf(dev, "can not if_gethandle()\n");
576164650Sobrien		error = ENOSPC;
577164650Sobrien		goto fail;
578164650Sobrien	}
579164650Sobrien
580159967Sobrien	/*
581159952Sobrien	 * Allocate Tx and Rx rings.
582159952Sobrien	 */
583170589Syongari	if ((error = nfe_alloc_tx_ring(sc, &sc->txq)) != 0)
584159967Sobrien		goto fail;
585159952Sobrien
586170589Syongari	if ((error = nfe_alloc_rx_ring(sc, &sc->rxq)) != 0)
587159967Sobrien		goto fail;
588170589Syongari
589171559Syongari	nfe_alloc_jrx_ring(sc, &sc->jrxq);
590183561Syongari	/* Create sysctl node. */
591183561Syongari	nfe_sysctl_node(sc);
592170589Syongari
593268131Smarcel	if_setsoftc(ifp, sc);
594270876Sglebius	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
595268131Smarcel	if_setflags(ifp, IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST);
596268131Smarcel	if_setioctlfn(ifp, nfe_ioctl);
597268131Smarcel	if_setstartfn(ifp, nfe_start);
598268131Smarcel	if_sethwassist(ifp, 0);
599268131Smarcel	if_setcapabilities(ifp, 0);
600268131Smarcel	if_setinitfn(ifp, nfe_init);
601268131Smarcel	if_setsendqlen(ifp, NFE_TX_RING_COUNT - 1);
602268131Smarcel	if_setsendqready(ifp);
603159952Sobrien
604268131Smarcel
605170589Syongari	if (sc->nfe_flags & NFE_HW_CSUM) {
606268131Smarcel		if_setcapabilitiesbit(ifp, IFCAP_HWCSUM | IFCAP_TSO4, 0);
607268131Smarcel		if_sethwassistbits(ifp, NFE_CSUM_FEATURES | CSUM_TSO, 0);
608170589Syongari	}
609268131Smarcel	if_setcapenable(ifp, if_getcapabilities(ifp));
610164650Sobrien
611268131Smarcel	sc->nfe_framesize = if_getmtu(ifp) + NFE_RX_HEADERS;
612170589Syongari	/* VLAN capability setup. */
613268131Smarcel	if_setcapabilitiesbit(ifp, IFCAP_VLAN_MTU, 0);
614170589Syongari	if ((sc->nfe_flags & NFE_HW_VLAN) != 0) {
615268131Smarcel		if_setcapabilitiesbit(ifp, IFCAP_VLAN_HWTAGGING, 0);
616268131Smarcel		if ((if_getcapabilities(ifp) & IFCAP_HWCSUM) != 0)
617268131Smarcel			if_setcapabilitiesbit(ifp,
618268131Smarcel			    (IFCAP_VLAN_HWCSUM | IFCAP_VLAN_HWTSO), 0);
619159952Sobrien	}
620215132Syongari
621219902Sjhb	if (pci_find_cap(dev, PCIY_PMG, &reg) == 0)
622268131Smarcel		if_setcapabilitiesbit(ifp, IFCAP_WOL_MAGIC, 0);
623268131Smarcel	if_setcapenable(ifp, if_getcapabilities(ifp));
624159952Sobrien
625170589Syongari	/*
626170589Syongari	 * Tell the upper layer(s) we support long frames.
627270876Sglebius	 * Must appear after the call to ether_ifattach() because
628270876Sglebius	 * ether_ifattach() sets ifi_hdrlen to the default value.
629170589Syongari	 */
630268131Smarcel	if_setifheaderlen(ifp, sizeof(struct ether_vlan_header));
631170589Syongari
632159967Sobrien#ifdef DEVICE_POLLING
633268131Smarcel	if_setcapabilitiesbit(ifp, IFCAP_POLLING, 0);
634159967Sobrien#endif
635159952Sobrien
636159967Sobrien	/* Do MII setup */
637264293Syongari	phyloc = MII_PHY_ANY;
638264293Syongari	if (sc->nfe_devid == PCI_PRODUCT_NVIDIA_MCP61_LAN1 ||
639264293Syongari	    sc->nfe_devid == PCI_PRODUCT_NVIDIA_MCP61_LAN2 ||
640264293Syongari	    sc->nfe_devid == PCI_PRODUCT_NVIDIA_MCP61_LAN3 ||
641264293Syongari	    sc->nfe_devid == PCI_PRODUCT_NVIDIA_MCP61_LAN4) {
642264293Syongari		if (nfe_detect_msik9(sc) != 0)
643264293Syongari			phyloc = 0;
644264293Syongari	}
645268131Smarcel	error = mii_attach(dev, &sc->nfe_miibus, ifp,
646268131Smarcel	    (ifm_change_cb_t)nfe_ifmedia_upd, (ifm_stat_cb_t)nfe_ifmedia_sts,
647268131Smarcel	    BMSR_DEFCAPMASK, phyloc, MII_OFFSET_ANY, MIIF_DOPAUSE);
648213894Smarius	if (error != 0) {
649213894Smarius		device_printf(dev, "attaching PHYs failed\n");
650159967Sobrien		goto fail;
651159967Sobrien	}
652270876Sglebius	ether_ifattach(ifp, sc->eaddr);
653159952Sobrien
654170589Syongari	TASK_INIT(&sc->nfe_int_task, 0, nfe_int_task, sc);
655170589Syongari	sc->nfe_tq = taskqueue_create_fast("nfe_taskq", M_WAITOK,
656170589Syongari	    taskqueue_thread_enqueue, &sc->nfe_tq);
657170589Syongari	taskqueue_start_threads(&sc->nfe_tq, 1, PI_NET, "%s taskq",
658170589Syongari	    device_get_nameunit(sc->nfe_dev));
659170589Syongari	error = 0;
660170589Syongari	if (sc->nfe_msi == 0 && sc->nfe_msix == 0) {
661170589Syongari		error = bus_setup_intr(dev, sc->nfe_irq[0],
662170589Syongari		    INTR_TYPE_NET | INTR_MPSAFE, nfe_intr, NULL, sc,
663170589Syongari		    &sc->nfe_intrhand[0]);
664170589Syongari	} else {
665170589Syongari		for (i = 0; i < NFE_MSI_MESSAGES; i++) {
666170589Syongari			error = bus_setup_intr(dev, sc->nfe_irq[i],
667170589Syongari			    INTR_TYPE_NET | INTR_MPSAFE, nfe_intr, NULL, sc,
668170589Syongari			    &sc->nfe_intrhand[i]);
669170589Syongari			if (error != 0)
670170589Syongari				break;
671170589Syongari		}
672170589Syongari	}
673159967Sobrien	if (error) {
674170589Syongari		device_printf(dev, "couldn't set up irq\n");
675170589Syongari		taskqueue_free(sc->nfe_tq);
676170589Syongari		sc->nfe_tq = NULL;
677270876Sglebius		ether_ifdetach(ifp);
678159967Sobrien		goto fail;
679159967Sobrien	}
680159967Sobrien
681159967Sobrienfail:
682159967Sobrien	if (error)
683159967Sobrien		nfe_detach(dev);
684159967Sobrien
685159967Sobrien	return (error);
686159952Sobrien}
687159952Sobrien
688159967Sobrien
689159967Sobrienstatic int
690159967Sobriennfe_detach(device_t dev)
691159952Sobrien{
692163503Sobrien	struct nfe_softc *sc;
693268131Smarcel	if_t ifp;
694170589Syongari	uint8_t eaddr[ETHER_ADDR_LEN];
695170589Syongari	int i, rid;
696159952Sobrien
697159967Sobrien	sc = device_get_softc(dev);
698159967Sobrien	KASSERT(mtx_initialized(&sc->nfe_mtx), ("nfe mutex not initialized"));
699159967Sobrien	ifp = sc->nfe_ifp;
700159967Sobrien
701159967Sobrien#ifdef DEVICE_POLLING
702268131Smarcel	if (ifp != NULL && if_getcapenable(ifp) & IFCAP_POLLING)
703159967Sobrien		ether_poll_deregister(ifp);
704159967Sobrien#endif
705159967Sobrien	if (device_is_attached(dev)) {
706164649Sobrien		NFE_LOCK(sc);
707170589Syongari		nfe_stop(ifp);
708268131Smarcel		if_setflagbits(ifp, 0, IFF_UP);
709164649Sobrien		NFE_UNLOCK(sc);
710159967Sobrien		callout_drain(&sc->nfe_stat_ch);
711270876Sglebius		ether_ifdetach(ifp);
712159967Sobrien	}
713159967Sobrien
714170589Syongari	if (ifp) {
715170589Syongari		/* restore ethernet address */
716170589Syongari		if ((sc->nfe_flags & NFE_CORRECT_MACADDR) == 0) {
717170589Syongari			for (i = 0; i < ETHER_ADDR_LEN; i++) {
718170589Syongari				eaddr[i] = sc->eaddr[5 - i];
719170589Syongari			}
720170589Syongari		} else
721170589Syongari			bcopy(sc->eaddr, eaddr, ETHER_ADDR_LEN);
722170589Syongari		nfe_set_macaddr(sc, eaddr);
723270876Sglebius		if_free(ifp);
724170589Syongari	}
725159967Sobrien	if (sc->nfe_miibus)
726159967Sobrien		device_delete_child(dev, sc->nfe_miibus);
727159967Sobrien	bus_generic_detach(dev);
728170589Syongari	if (sc->nfe_tq != NULL) {
729170589Syongari		taskqueue_drain(sc->nfe_tq, &sc->nfe_int_task);
730170589Syongari		taskqueue_free(sc->nfe_tq);
731170589Syongari		sc->nfe_tq = NULL;
732170589Syongari	}
733159967Sobrien
734170589Syongari	for (i = 0; i < NFE_MSI_MESSAGES; i++) {
735170589Syongari		if (sc->nfe_intrhand[i] != NULL) {
736170589Syongari			bus_teardown_intr(dev, sc->nfe_irq[i],
737170589Syongari			    sc->nfe_intrhand[i]);
738170589Syongari			sc->nfe_intrhand[i] = NULL;
739170589Syongari		}
740170589Syongari	}
741159967Sobrien
742170589Syongari	if (sc->nfe_msi == 0 && sc->nfe_msix == 0) {
743170589Syongari		if (sc->nfe_irq[0] != NULL)
744170589Syongari			bus_release_resource(dev, SYS_RES_IRQ, 0,
745170589Syongari			    sc->nfe_irq[0]);
746170589Syongari	} else {
747170589Syongari		for (i = 0, rid = 1; i < NFE_MSI_MESSAGES; i++, rid++) {
748170589Syongari			if (sc->nfe_irq[i] != NULL) {
749170589Syongari				bus_release_resource(dev, SYS_RES_IRQ, rid,
750170589Syongari				    sc->nfe_irq[i]);
751170589Syongari				sc->nfe_irq[i] = NULL;
752170589Syongari			}
753170589Syongari		}
754170589Syongari		pci_release_msi(dev);
755170589Syongari	}
756170589Syongari	if (sc->nfe_msix_pba_res != NULL) {
757170589Syongari		bus_release_resource(dev, SYS_RES_MEMORY, PCIR_BAR(3),
758170589Syongari		    sc->nfe_msix_pba_res);
759170589Syongari		sc->nfe_msix_pba_res = NULL;
760170589Syongari	}
761170589Syongari	if (sc->nfe_msix_res != NULL) {
762170589Syongari		bus_release_resource(dev, SYS_RES_MEMORY, PCIR_BAR(2),
763170589Syongari		    sc->nfe_msix_res);
764170589Syongari		sc->nfe_msix_res = NULL;
765170589Syongari	}
766170589Syongari	if (sc->nfe_res[0] != NULL) {
767170589Syongari		bus_release_resource(dev, SYS_RES_MEMORY, PCIR_BAR(0),
768170589Syongari		    sc->nfe_res[0]);
769170589Syongari		sc->nfe_res[0] = NULL;
770170589Syongari	}
771170589Syongari
772159967Sobrien	nfe_free_tx_ring(sc, &sc->txq);
773159967Sobrien	nfe_free_rx_ring(sc, &sc->rxq);
774170589Syongari	nfe_free_jrx_ring(sc, &sc->jrxq);
775159967Sobrien
776170589Syongari	if (sc->nfe_parent_tag) {
777159967Sobrien		bus_dma_tag_destroy(sc->nfe_parent_tag);
778170589Syongari		sc->nfe_parent_tag = NULL;
779170589Syongari	}
780159967Sobrien
781159967Sobrien	mtx_destroy(&sc->nfe_mtx);
782159967Sobrien
783159967Sobrien	return (0);
784159952Sobrien}
785159952Sobrien
786159967Sobrien
787170589Syongaristatic int
788170589Syongarinfe_suspend(device_t dev)
789170589Syongari{
790170589Syongari	struct nfe_softc *sc;
791170589Syongari
792170589Syongari	sc = device_get_softc(dev);
793170589Syongari
794170589Syongari	NFE_LOCK(sc);
795170589Syongari	nfe_stop(sc->nfe_ifp);
796215132Syongari	nfe_set_wol(sc);
797170589Syongari	sc->nfe_suspended = 1;
798170589Syongari	NFE_UNLOCK(sc);
799170589Syongari
800170589Syongari	return (0);
801170589Syongari}
802170589Syongari
803170589Syongari
804170589Syongaristatic int
805170589Syongarinfe_resume(device_t dev)
806170589Syongari{
807170589Syongari	struct nfe_softc *sc;
808268131Smarcel	if_t ifp;
809170589Syongari
810170589Syongari	sc = device_get_softc(dev);
811170589Syongari
812170589Syongari	NFE_LOCK(sc);
813215132Syongari	nfe_power(sc);
814170589Syongari	ifp = sc->nfe_ifp;
815268131Smarcel	if (if_getflags(ifp) & IFF_UP)
816170589Syongari		nfe_init_locked(sc);
817170589Syongari	sc->nfe_suspended = 0;
818170589Syongari	NFE_UNLOCK(sc);
819170589Syongari
820170589Syongari	return (0);
821170589Syongari}
822170589Syongari
823170589Syongari
824215327Syongaristatic int
825215327Syongarinfe_can_use_msix(struct nfe_softc *sc)
826215327Syongari{
827215327Syongari	static struct msix_blacklist {
828215327Syongari		char	*maker;
829215327Syongari		char	*product;
830215327Syongari	} msix_blacklists[] = {
831215327Syongari		{ "ASUSTeK Computer INC.", "P5N32-SLI PREMIUM" }
832215327Syongari	};
833215327Syongari
834215327Syongari	struct msix_blacklist *mblp;
835215327Syongari	char *maker, *product;
836215350Syongari	int count, n, use_msix;
837215327Syongari
838215327Syongari	/*
839215327Syongari	 * Search base board manufacturer and product name table
840215327Syongari	 * to see this system has a known MSI/MSI-X issue.
841215327Syongari	 */
842273174Sdavide	maker = kern_getenv("smbios.planar.maker");
843273174Sdavide	product = kern_getenv("smbios.planar.product");
844215350Syongari	use_msix = 1;
845215327Syongari	if (maker != NULL && product != NULL) {
846215327Syongari		count = sizeof(msix_blacklists) / sizeof(msix_blacklists[0]);
847215327Syongari		mblp = msix_blacklists;
848215327Syongari		for (n = 0; n < count; n++) {
849215327Syongari			if (strcmp(maker, mblp->maker) == 0 &&
850215350Syongari			    strcmp(product, mblp->product) == 0) {
851215350Syongari				use_msix = 0;
852215350Syongari				break;
853215350Syongari			}
854215327Syongari			mblp++;
855215327Syongari		}
856215327Syongari	}
857215350Syongari	if (maker != NULL)
858215350Syongari		freeenv(maker);
859215350Syongari	if (product != NULL)
860215350Syongari		freeenv(product);
861215327Syongari
862215350Syongari	return (use_msix);
863215327Syongari}
864215327Syongari
865215327Syongari
866170589Syongari/* Take PHY/NIC out of powerdown, from Linux */
867159967Sobrienstatic void
868170589Syongarinfe_power(struct nfe_softc *sc)
869170589Syongari{
870170589Syongari	uint32_t pwr;
871170589Syongari
872170589Syongari	if ((sc->nfe_flags & NFE_PWR_MGMT) == 0)
873170589Syongari		return;
874170589Syongari	NFE_WRITE(sc, NFE_RXTX_CTL, NFE_RXTX_RESET | NFE_RXTX_BIT2);
875170589Syongari	NFE_WRITE(sc, NFE_MAC_RESET, NFE_MAC_RESET_MAGIC);
876170589Syongari	DELAY(100);
877170589Syongari	NFE_WRITE(sc, NFE_MAC_RESET, 0);
878170589Syongari	DELAY(100);
879170589Syongari	NFE_WRITE(sc, NFE_RXTX_CTL, NFE_RXTX_BIT2);
880170589Syongari	pwr = NFE_READ(sc, NFE_PWR2_CTL);
881170589Syongari	pwr &= ~NFE_PWR2_WAKEUP_MASK;
882170589Syongari	if (sc->nfe_revid >= 0xa3 &&
883170589Syongari	    (sc->nfe_devid == PCI_PRODUCT_NVIDIA_NFORCE430_LAN1 ||
884170589Syongari	    sc->nfe_devid == PCI_PRODUCT_NVIDIA_NFORCE430_LAN2))
885170589Syongari		pwr |= NFE_PWR2_REVA3;
886170589Syongari	NFE_WRITE(sc, NFE_PWR2_CTL, pwr);
887170589Syongari}
888170589Syongari
889170589Syongari
890170589Syongaristatic void
891159967Sobriennfe_miibus_statchg(device_t dev)
892159952Sobrien{
893159967Sobrien	struct nfe_softc *sc;
894159967Sobrien	struct mii_data *mii;
895268131Smarcel	if_t ifp;
896215132Syongari	uint32_t rxctl, txctl;
897159952Sobrien
898215132Syongari	sc = device_get_softc(dev);
899170589Syongari
900159967Sobrien	mii = device_get_softc(sc->nfe_miibus);
901170589Syongari	ifp = sc->nfe_ifp;
902159967Sobrien
903215132Syongari	sc->nfe_link = 0;
904215132Syongari	if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) ==
905215132Syongari	    (IFM_ACTIVE | IFM_AVALID)) {
906215132Syongari		switch (IFM_SUBTYPE(mii->mii_media_active)) {
907215132Syongari		case IFM_10_T:
908215132Syongari		case IFM_100_TX:
909215132Syongari		case IFM_1000_T:
910170589Syongari			sc->nfe_link = 1;
911215132Syongari			break;
912215132Syongari		default:
913215132Syongari			break;
914215132Syongari		}
915215132Syongari	}
916170589Syongari
917215132Syongari	nfe_mac_config(sc, mii);
918215132Syongari	txctl = NFE_READ(sc, NFE_TX_CTL);
919215132Syongari	rxctl = NFE_READ(sc, NFE_RX_CTL);
920268131Smarcel	if (sc->nfe_link != 0 && (if_getdrvflags(ifp) & IFF_DRV_RUNNING) != 0) {
921215132Syongari		txctl |= NFE_TX_START;
922215132Syongari		rxctl |= NFE_RX_START;
923215132Syongari	} else {
924215132Syongari		txctl &= ~NFE_TX_START;
925215132Syongari		rxctl &= ~NFE_RX_START;
926215132Syongari	}
927215132Syongari	NFE_WRITE(sc, NFE_TX_CTL, txctl);
928215132Syongari	NFE_WRITE(sc, NFE_RX_CTL, rxctl);
929215132Syongari}
930215132Syongari
931215132Syongari
932215132Syongaristatic void
933215132Syongarinfe_mac_config(struct nfe_softc *sc, struct mii_data *mii)
934215132Syongari{
935215132Syongari	uint32_t link, misc, phy, seed;
936215132Syongari	uint32_t val;
937215132Syongari
938215132Syongari	NFE_LOCK_ASSERT(sc);
939215132Syongari
940159952Sobrien	phy = NFE_READ(sc, NFE_PHY_IFACE);
941159952Sobrien	phy &= ~(NFE_PHY_HDX | NFE_PHY_100TX | NFE_PHY_1000T);
942159952Sobrien
943159952Sobrien	seed = NFE_READ(sc, NFE_RNDSEED);
944159952Sobrien	seed &= ~NFE_SEED_MASK;
945159952Sobrien
946215132Syongari	misc = NFE_MISC1_MAGIC;
947215132Syongari	link = NFE_MEDIA_SET;
948215132Syongari
949215132Syongari	if ((IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) == 0) {
950159952Sobrien		phy  |= NFE_PHY_HDX;	/* half-duplex */
951159952Sobrien		misc |= NFE_MISC1_HDX;
952159952Sobrien	}
953159952Sobrien
954159952Sobrien	switch (IFM_SUBTYPE(mii->mii_media_active)) {
955159952Sobrien	case IFM_1000_T:	/* full-duplex only */
956159952Sobrien		link |= NFE_MEDIA_1000T;
957159952Sobrien		seed |= NFE_SEED_1000T;
958159952Sobrien		phy  |= NFE_PHY_1000T;
959159952Sobrien		break;
960159952Sobrien	case IFM_100_TX:
961159952Sobrien		link |= NFE_MEDIA_100TX;
962159952Sobrien		seed |= NFE_SEED_100TX;
963159952Sobrien		phy  |= NFE_PHY_100TX;
964159952Sobrien		break;
965159952Sobrien	case IFM_10_T:
966159952Sobrien		link |= NFE_MEDIA_10T;
967159952Sobrien		seed |= NFE_SEED_10T;
968159952Sobrien		break;
969159952Sobrien	}
970159952Sobrien
971170589Syongari	if ((phy & 0x10000000) != 0) {
972170589Syongari		if (IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_T)
973170589Syongari			val = NFE_R1_MAGIC_1000;
974170589Syongari		else
975170589Syongari			val = NFE_R1_MAGIC_10_100;
976170589Syongari	} else
977170589Syongari		val = NFE_R1_MAGIC_DEFAULT;
978170589Syongari	NFE_WRITE(sc, NFE_SETUP_R1, val);
979170589Syongari
980159952Sobrien	NFE_WRITE(sc, NFE_RNDSEED, seed);	/* XXX: gigabit NICs only? */
981159952Sobrien
982159952Sobrien	NFE_WRITE(sc, NFE_PHY_IFACE, phy);
983159952Sobrien	NFE_WRITE(sc, NFE_MISC1, misc);
984159952Sobrien	NFE_WRITE(sc, NFE_LINKSPEED, link);
985170589Syongari
986215132Syongari	if ((IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) != 0) {
987170589Syongari		/* It seems all hardwares supports Rx pause frames. */
988170589Syongari		val = NFE_READ(sc, NFE_RXFILTER);
989215297Smarius		if ((IFM_OPTIONS(mii->mii_media_active) &
990215297Smarius		    IFM_ETH_RXPAUSE) != 0)
991170589Syongari			val |= NFE_PFF_RX_PAUSE;
992170589Syongari		else
993170589Syongari			val &= ~NFE_PFF_RX_PAUSE;
994170589Syongari		NFE_WRITE(sc, NFE_RXFILTER, val);
995170589Syongari		if ((sc->nfe_flags & NFE_TX_FLOW_CTRL) != 0) {
996170589Syongari			val = NFE_READ(sc, NFE_MISC1);
997215132Syongari			if ((IFM_OPTIONS(mii->mii_media_active) &
998215297Smarius			    IFM_ETH_TXPAUSE) != 0) {
999170589Syongari				NFE_WRITE(sc, NFE_TX_PAUSE_FRAME,
1000170589Syongari				    NFE_TX_PAUSE_FRAME_ENABLE);
1001170589Syongari				val |= NFE_MISC1_TX_PAUSE;
1002170589Syongari			} else {
1003170589Syongari				val &= ~NFE_MISC1_TX_PAUSE;
1004170589Syongari				NFE_WRITE(sc, NFE_TX_PAUSE_FRAME,
1005170589Syongari				    NFE_TX_PAUSE_FRAME_DISABLE);
1006170589Syongari			}
1007170589Syongari			NFE_WRITE(sc, NFE_MISC1, val);
1008170589Syongari		}
1009170589Syongari	} else {
1010170589Syongari		/* disable rx/tx pause frames */
1011170589Syongari		val = NFE_READ(sc, NFE_RXFILTER);
1012170589Syongari		val &= ~NFE_PFF_RX_PAUSE;
1013170589Syongari		NFE_WRITE(sc, NFE_RXFILTER, val);
1014170589Syongari		if ((sc->nfe_flags & NFE_TX_FLOW_CTRL) != 0) {
1015170589Syongari			NFE_WRITE(sc, NFE_TX_PAUSE_FRAME,
1016170589Syongari			    NFE_TX_PAUSE_FRAME_DISABLE);
1017170589Syongari			val = NFE_READ(sc, NFE_MISC1);
1018170589Syongari			val &= ~NFE_MISC1_TX_PAUSE;
1019170589Syongari			NFE_WRITE(sc, NFE_MISC1, val);
1020170589Syongari		}
1021170589Syongari	}
1022159952Sobrien}
1023159952Sobrien
1024163503Sobrien
1025159967Sobrienstatic int
1026159967Sobriennfe_miibus_readreg(device_t dev, int phy, int reg)
1027159952Sobrien{
1028159967Sobrien	struct nfe_softc *sc = device_get_softc(dev);
1029170589Syongari	uint32_t val;
1030159952Sobrien	int ntries;
1031159952Sobrien
1032159952Sobrien	NFE_WRITE(sc, NFE_PHY_STATUS, 0xf);
1033159952Sobrien
1034159952Sobrien	if (NFE_READ(sc, NFE_PHY_CTL) & NFE_PHY_BUSY) {
1035159952Sobrien		NFE_WRITE(sc, NFE_PHY_CTL, NFE_PHY_BUSY);
1036159952Sobrien		DELAY(100);
1037159952Sobrien	}
1038159952Sobrien
1039159952Sobrien	NFE_WRITE(sc, NFE_PHY_CTL, (phy << NFE_PHYADD_SHIFT) | reg);
1040159952Sobrien
1041170589Syongari	for (ntries = 0; ntries < NFE_TIMEOUT; ntries++) {
1042159952Sobrien		DELAY(100);
1043159952Sobrien		if (!(NFE_READ(sc, NFE_PHY_CTL) & NFE_PHY_BUSY))
1044159952Sobrien			break;
1045159952Sobrien	}
1046170589Syongari	if (ntries == NFE_TIMEOUT) {
1047170589Syongari		DPRINTFN(sc, 2, "timeout waiting for PHY\n");
1048159952Sobrien		return 0;
1049159952Sobrien	}
1050159952Sobrien
1051159952Sobrien	if (NFE_READ(sc, NFE_PHY_STATUS) & NFE_PHY_ERROR) {
1052170589Syongari		DPRINTFN(sc, 2, "could not read PHY\n");
1053159952Sobrien		return 0;
1054159952Sobrien	}
1055159952Sobrien
1056159952Sobrien	val = NFE_READ(sc, NFE_PHY_DATA);
1057159952Sobrien	if (val != 0xffffffff && val != 0)
1058159952Sobrien		sc->mii_phyaddr = phy;
1059159952Sobrien
1060170589Syongari	DPRINTFN(sc, 2, "mii read phy %d reg 0x%x ret 0x%x\n", phy, reg, val);
1061159952Sobrien
1062170589Syongari	return (val);
1063159952Sobrien}
1064159952Sobrien
1065163503Sobrien
1066159967Sobrienstatic int
1067159967Sobriennfe_miibus_writereg(device_t dev, int phy, int reg, int val)
1068159952Sobrien{
1069159967Sobrien	struct nfe_softc *sc = device_get_softc(dev);
1070170589Syongari	uint32_t ctl;
1071163503Sobrien	int ntries;
1072159952Sobrien
1073159952Sobrien	NFE_WRITE(sc, NFE_PHY_STATUS, 0xf);
1074159952Sobrien
1075159952Sobrien	if (NFE_READ(sc, NFE_PHY_CTL) & NFE_PHY_BUSY) {
1076159952Sobrien		NFE_WRITE(sc, NFE_PHY_CTL, NFE_PHY_BUSY);
1077159952Sobrien		DELAY(100);
1078159952Sobrien	}
1079159952Sobrien
1080159952Sobrien	NFE_WRITE(sc, NFE_PHY_DATA, val);
1081159952Sobrien	ctl = NFE_PHY_WRITE | (phy << NFE_PHYADD_SHIFT) | reg;
1082159952Sobrien	NFE_WRITE(sc, NFE_PHY_CTL, ctl);
1083159952Sobrien
1084170589Syongari	for (ntries = 0; ntries < NFE_TIMEOUT; ntries++) {
1085159952Sobrien		DELAY(100);
1086159952Sobrien		if (!(NFE_READ(sc, NFE_PHY_CTL) & NFE_PHY_BUSY))
1087159952Sobrien			break;
1088159952Sobrien	}
1089159952Sobrien#ifdef NFE_DEBUG
1090170589Syongari	if (nfedebug >= 2 && ntries == NFE_TIMEOUT)
1091170589Syongari		device_printf(sc->nfe_dev, "could not write to PHY\n");
1092159952Sobrien#endif
1093170589Syongari	return (0);
1094159952Sobrien}
1095159952Sobrien
1096170589Syongaristruct nfe_dmamap_arg {
1097170589Syongari	bus_addr_t nfe_busaddr;
1098170589Syongari};
1099170589Syongari
1100159967Sobrienstatic int
1101159967Sobriennfe_alloc_rx_ring(struct nfe_softc *sc, struct nfe_rx_ring *ring)
1102159952Sobrien{
1103170589Syongari	struct nfe_dmamap_arg ctx;
1104159967Sobrien	struct nfe_rx_data *data;
1105170589Syongari	void *desc;
1106159967Sobrien	int i, error, descsize;
1107159967Sobrien
1108159967Sobrien	if (sc->nfe_flags & NFE_40BIT_ADDR) {
1109170589Syongari		desc = ring->desc64;
1110159967Sobrien		descsize = sizeof (struct nfe_desc64);
1111159967Sobrien	} else {
1112170589Syongari		desc = ring->desc32;
1113159967Sobrien		descsize = sizeof (struct nfe_desc32);
1114159967Sobrien	}
1115159967Sobrien
1116159967Sobrien	ring->cur = ring->next = 0;
1117159967Sobrien
1118163503Sobrien	error = bus_dma_tag_create(sc->nfe_parent_tag,
1119170589Syongari	    NFE_RING_ALIGN, 0,			/* alignment, boundary */
1120170589Syongari	    BUS_SPACE_MAXADDR,			/* lowaddr */
1121170589Syongari	    BUS_SPACE_MAXADDR,			/* highaddr */
1122170589Syongari	    NULL, NULL,				/* filter, filterarg */
1123170589Syongari	    NFE_RX_RING_COUNT * descsize, 1,	/* maxsize, nsegments */
1124170589Syongari	    NFE_RX_RING_COUNT * descsize,	/* maxsegsize */
1125170589Syongari	    0,					/* flags */
1126170589Syongari	    NULL, NULL,				/* lockfunc, lockarg */
1127170589Syongari	    &ring->rx_desc_tag);
1128159967Sobrien	if (error != 0) {
1129170589Syongari		device_printf(sc->nfe_dev, "could not create desc DMA tag\n");
1130159967Sobrien		goto fail;
1131159967Sobrien	}
1132159967Sobrien
1133159967Sobrien	/* allocate memory to desc */
1134170589Syongari	error = bus_dmamem_alloc(ring->rx_desc_tag, &desc, BUS_DMA_WAITOK |
1135170589Syongari	    BUS_DMA_COHERENT | BUS_DMA_ZERO, &ring->rx_desc_map);
1136159967Sobrien	if (error != 0) {
1137170589Syongari		device_printf(sc->nfe_dev, "could not create desc DMA map\n");
1138159967Sobrien		goto fail;
1139159967Sobrien	}
1140170589Syongari	if (sc->nfe_flags & NFE_40BIT_ADDR)
1141170589Syongari		ring->desc64 = desc;
1142170589Syongari	else
1143170589Syongari		ring->desc32 = desc;
1144159967Sobrien
1145159967Sobrien	/* map desc to device visible address space */
1146170589Syongari	ctx.nfe_busaddr = 0;
1147170589Syongari	error = bus_dmamap_load(ring->rx_desc_tag, ring->rx_desc_map, desc,
1148170589Syongari	    NFE_RX_RING_COUNT * descsize, nfe_dma_map_segs, &ctx, 0);
1149159967Sobrien	if (error != 0) {
1150170589Syongari		device_printf(sc->nfe_dev, "could not load desc DMA map\n");
1151159967Sobrien		goto fail;
1152159967Sobrien	}
1153170589Syongari	ring->physaddr = ctx.nfe_busaddr;
1154159967Sobrien
1155170589Syongari	error = bus_dma_tag_create(sc->nfe_parent_tag,
1156170589Syongari	    1, 0,			/* alignment, boundary */
1157170589Syongari	    BUS_SPACE_MAXADDR,		/* lowaddr */
1158170589Syongari	    BUS_SPACE_MAXADDR,		/* highaddr */
1159170589Syongari	    NULL, NULL,			/* filter, filterarg */
1160170589Syongari	    MCLBYTES, 1,		/* maxsize, nsegments */
1161170589Syongari	    MCLBYTES,			/* maxsegsize */
1162170589Syongari	    0,				/* flags */
1163170589Syongari	    NULL, NULL,			/* lockfunc, lockarg */
1164170589Syongari	    &ring->rx_data_tag);
1165170589Syongari	if (error != 0) {
1166170589Syongari		device_printf(sc->nfe_dev, "could not create Rx DMA tag\n");
1167170589Syongari		goto fail;
1168170589Syongari	}
1169159967Sobrien
1170170589Syongari	error = bus_dmamap_create(ring->rx_data_tag, 0, &ring->rx_spare_map);
1171170589Syongari	if (error != 0) {
1172170589Syongari		device_printf(sc->nfe_dev,
1173170589Syongari		    "could not create Rx DMA spare map\n");
1174170589Syongari		goto fail;
1175170589Syongari	}
1176170589Syongari
1177159967Sobrien	/*
1178159967Sobrien	 * Pre-allocate Rx buffers and populate Rx ring.
1179159967Sobrien	 */
1180159967Sobrien	for (i = 0; i < NFE_RX_RING_COUNT; i++) {
1181159967Sobrien		data = &sc->rxq.data[i];
1182170589Syongari		data->rx_data_map = NULL;
1183170589Syongari		data->m = NULL;
1184170589Syongari		error = bus_dmamap_create(ring->rx_data_tag, 0,
1185170589Syongari		    &data->rx_data_map);
1186164651Sobrien		if (error != 0) {
1187170589Syongari			device_printf(sc->nfe_dev,
1188170589Syongari			    "could not create Rx DMA map\n");
1189164651Sobrien			goto fail;
1190164651Sobrien		}
1191170589Syongari	}
1192159967Sobrien
1193170589Syongarifail:
1194170589Syongari	return (error);
1195170589Syongari}
1196170589Syongari
1197170589Syongari
1198171559Syongaristatic void
1199170589Syongarinfe_alloc_jrx_ring(struct nfe_softc *sc, struct nfe_jrx_ring *ring)
1200170589Syongari{
1201170589Syongari	struct nfe_dmamap_arg ctx;
1202170589Syongari	struct nfe_rx_data *data;
1203170589Syongari	void *desc;
1204170589Syongari	int i, error, descsize;
1205170589Syongari
1206170589Syongari	if ((sc->nfe_flags & NFE_JUMBO_SUP) == 0)
1207171559Syongari		return;
1208171559Syongari	if (jumbo_disable != 0) {
1209171559Syongari		device_printf(sc->nfe_dev, "disabling jumbo frame support\n");
1210171559Syongari		sc->nfe_jumbo_disable = 1;
1211171559Syongari		return;
1212171559Syongari	}
1213170589Syongari
1214170589Syongari	if (sc->nfe_flags & NFE_40BIT_ADDR) {
1215170589Syongari		desc = ring->jdesc64;
1216170589Syongari		descsize = sizeof (struct nfe_desc64);
1217170589Syongari	} else {
1218170589Syongari		desc = ring->jdesc32;
1219170589Syongari		descsize = sizeof (struct nfe_desc32);
1220170589Syongari	}
1221170589Syongari
1222170589Syongari	ring->jcur = ring->jnext = 0;
1223170589Syongari
1224170589Syongari	/* Create DMA tag for jumbo Rx ring. */
1225170589Syongari	error = bus_dma_tag_create(sc->nfe_parent_tag,
1226170589Syongari	    NFE_RING_ALIGN, 0,			/* alignment, boundary */
1227170589Syongari	    BUS_SPACE_MAXADDR,			/* lowaddr */
1228170589Syongari	    BUS_SPACE_MAXADDR,			/* highaddr */
1229170589Syongari	    NULL, NULL,				/* filter, filterarg */
1230170589Syongari	    NFE_JUMBO_RX_RING_COUNT * descsize,	/* maxsize */
1231170589Syongari	    1, 					/* nsegments */
1232170589Syongari	    NFE_JUMBO_RX_RING_COUNT * descsize,	/* maxsegsize */
1233170589Syongari	    0,					/* flags */
1234170589Syongari	    NULL, NULL,				/* lockfunc, lockarg */
1235170589Syongari	    &ring->jrx_desc_tag);
1236170589Syongari	if (error != 0) {
1237170589Syongari		device_printf(sc->nfe_dev,
1238170589Syongari		    "could not create jumbo ring DMA tag\n");
1239170589Syongari		goto fail;
1240170589Syongari	}
1241170589Syongari
1242170589Syongari	/* Create DMA tag for jumbo Rx buffers. */
1243170589Syongari	error = bus_dma_tag_create(sc->nfe_parent_tag,
1244192706Syongari	    1, 0,				/* alignment, boundary */
1245170589Syongari	    BUS_SPACE_MAXADDR,			/* lowaddr */
1246170589Syongari	    BUS_SPACE_MAXADDR,			/* highaddr */
1247170589Syongari	    NULL, NULL,				/* filter, filterarg */
1248176859Syongari	    MJUM9BYTES,				/* maxsize */
1249170589Syongari	    1,					/* nsegments */
1250176859Syongari	    MJUM9BYTES,				/* maxsegsize */
1251170589Syongari	    0,					/* flags */
1252170589Syongari	    NULL, NULL,				/* lockfunc, lockarg */
1253170589Syongari	    &ring->jrx_data_tag);
1254170589Syongari	if (error != 0) {
1255170589Syongari		device_printf(sc->nfe_dev,
1256170589Syongari		    "could not create jumbo Rx buffer DMA tag\n");
1257170589Syongari		goto fail;
1258170589Syongari	}
1259170589Syongari
1260170589Syongari	/* Allocate DMA'able memory and load the DMA map for jumbo Rx ring. */
1261170589Syongari	error = bus_dmamem_alloc(ring->jrx_desc_tag, &desc, BUS_DMA_WAITOK |
1262170589Syongari	    BUS_DMA_COHERENT | BUS_DMA_ZERO, &ring->jrx_desc_map);
1263170589Syongari	if (error != 0) {
1264170589Syongari		device_printf(sc->nfe_dev,
1265170589Syongari		    "could not allocate DMA'able memory for jumbo Rx ring\n");
1266170589Syongari		goto fail;
1267170589Syongari	}
1268170589Syongari	if (sc->nfe_flags & NFE_40BIT_ADDR)
1269170589Syongari		ring->jdesc64 = desc;
1270170589Syongari	else
1271170589Syongari		ring->jdesc32 = desc;
1272170589Syongari
1273170589Syongari	ctx.nfe_busaddr = 0;
1274170589Syongari	error = bus_dmamap_load(ring->jrx_desc_tag, ring->jrx_desc_map, desc,
1275170589Syongari	    NFE_JUMBO_RX_RING_COUNT * descsize, nfe_dma_map_segs, &ctx, 0);
1276170589Syongari	if (error != 0) {
1277170589Syongari		device_printf(sc->nfe_dev,
1278170589Syongari		    "could not load DMA'able memory for jumbo Rx ring\n");
1279170589Syongari		goto fail;
1280170589Syongari	}
1281170589Syongari	ring->jphysaddr = ctx.nfe_busaddr;
1282170589Syongari
1283170589Syongari	/* Create DMA maps for jumbo Rx buffers. */
1284170589Syongari	error = bus_dmamap_create(ring->jrx_data_tag, 0, &ring->jrx_spare_map);
1285170589Syongari	if (error != 0) {
1286170589Syongari		device_printf(sc->nfe_dev,
1287170589Syongari		    "could not create jumbo Rx DMA spare map\n");
1288170589Syongari		goto fail;
1289170589Syongari	}
1290170589Syongari
1291170589Syongari	for (i = 0; i < NFE_JUMBO_RX_RING_COUNT; i++) {
1292170589Syongari		data = &sc->jrxq.jdata[i];
1293170589Syongari		data->rx_data_map = NULL;
1294170589Syongari		data->m = NULL;
1295170589Syongari		error = bus_dmamap_create(ring->jrx_data_tag, 0,
1296164651Sobrien		    &data->rx_data_map);
1297164651Sobrien		if (error != 0) {
1298170589Syongari			device_printf(sc->nfe_dev,
1299170589Syongari			    "could not create jumbo Rx DMA map\n");
1300164651Sobrien			goto fail;
1301164651Sobrien		}
1302170589Syongari	}
1303159967Sobrien
1304171559Syongari	return;
1305159967Sobrien
1306170589Syongarifail:
1307171559Syongari	/*
1308171559Syongari	 * Running without jumbo frame support is ok for most cases
1309171559Syongari	 * so don't fail on creating dma tag/map for jumbo frame.
1310171559Syongari	 */
1311170589Syongari	nfe_free_jrx_ring(sc, ring);
1312171559Syongari	device_printf(sc->nfe_dev, "disabling jumbo frame support due to "
1313171559Syongari	    "resource shortage\n");
1314171559Syongari	sc->nfe_jumbo_disable = 1;
1315170589Syongari}
1316159967Sobrien
1317159967Sobrien
1318170589Syongaristatic int
1319170589Syongarinfe_init_rx_ring(struct nfe_softc *sc, struct nfe_rx_ring *ring)
1320170589Syongari{
1321170589Syongari	void *desc;
1322170589Syongari	size_t descsize;
1323170589Syongari	int i;
1324159967Sobrien
1325170589Syongari	ring->cur = ring->next = 0;
1326170589Syongari	if (sc->nfe_flags & NFE_40BIT_ADDR) {
1327170589Syongari		desc = ring->desc64;
1328170589Syongari		descsize = sizeof (struct nfe_desc64);
1329170589Syongari	} else {
1330170589Syongari		desc = ring->desc32;
1331170589Syongari		descsize = sizeof (struct nfe_desc32);
1332159967Sobrien	}
1333170589Syongari	bzero(desc, descsize * NFE_RX_RING_COUNT);
1334170589Syongari	for (i = 0; i < NFE_RX_RING_COUNT; i++) {
1335170589Syongari		if (nfe_newbuf(sc, i) != 0)
1336170589Syongari			return (ENOBUFS);
1337170589Syongari	}
1338159967Sobrien
1339163503Sobrien	bus_dmamap_sync(ring->rx_desc_tag, ring->rx_desc_map,
1340170589Syongari	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1341159967Sobrien
1342170589Syongari	return (0);
1343159967Sobrien}
1344159967Sobrien
1345163503Sobrien
1346170589Syongaristatic int
1347170589Syongarinfe_init_jrx_ring(struct nfe_softc *sc, struct nfe_jrx_ring *ring)
1348159967Sobrien{
1349170589Syongari	void *desc;
1350170589Syongari	size_t descsize;
1351159967Sobrien	int i;
1352159967Sobrien
1353170589Syongari	ring->jcur = ring->jnext = 0;
1354170589Syongari	if (sc->nfe_flags & NFE_40BIT_ADDR) {
1355170589Syongari		desc = ring->jdesc64;
1356170589Syongari		descsize = sizeof (struct nfe_desc64);
1357170589Syongari	} else {
1358170589Syongari		desc = ring->jdesc32;
1359170589Syongari		descsize = sizeof (struct nfe_desc32);
1360159952Sobrien	}
1361176859Syongari	bzero(desc, descsize * NFE_JUMBO_RX_RING_COUNT);
1362170589Syongari	for (i = 0; i < NFE_JUMBO_RX_RING_COUNT; i++) {
1363170589Syongari		if (nfe_jnewbuf(sc, i) != 0)
1364170589Syongari			return (ENOBUFS);
1365170589Syongari	}
1366159952Sobrien
1367170589Syongari	bus_dmamap_sync(ring->jrx_desc_tag, ring->jrx_desc_map,
1368170589Syongari	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1369159952Sobrien
1370170589Syongari	return (0);
1371159967Sobrien}
1372159967Sobrien
1373159967Sobrien
1374159967Sobrienstatic void
1375159967Sobriennfe_free_rx_ring(struct nfe_softc *sc, struct nfe_rx_ring *ring)
1376159967Sobrien{
1377159967Sobrien	struct nfe_rx_data *data;
1378159967Sobrien	void *desc;
1379266270Sbrueffer	int i;
1380159967Sobrien
1381266270Sbrueffer	if (sc->nfe_flags & NFE_40BIT_ADDR)
1382159967Sobrien		desc = ring->desc64;
1383266270Sbrueffer	else
1384159967Sobrien		desc = ring->desc32;
1385159952Sobrien
1386170589Syongari	for (i = 0; i < NFE_RX_RING_COUNT; i++) {
1387170589Syongari		data = &ring->data[i];
1388170589Syongari		if (data->rx_data_map != NULL) {
1389170589Syongari			bus_dmamap_destroy(ring->rx_data_tag,
1390170589Syongari			    data->rx_data_map);
1391170589Syongari			data->rx_data_map = NULL;
1392170589Syongari		}
1393170589Syongari		if (data->m != NULL) {
1394170589Syongari			m_freem(data->m);
1395170589Syongari			data->m = NULL;
1396170589Syongari		}
1397170589Syongari	}
1398170589Syongari	if (ring->rx_data_tag != NULL) {
1399170589Syongari		if (ring->rx_spare_map != NULL) {
1400170589Syongari			bus_dmamap_destroy(ring->rx_data_tag,
1401170589Syongari			    ring->rx_spare_map);
1402170589Syongari			ring->rx_spare_map = NULL;
1403170589Syongari		}
1404170589Syongari		bus_dma_tag_destroy(ring->rx_data_tag);
1405170589Syongari		ring->rx_data_tag = NULL;
1406170589Syongari	}
1407170589Syongari
1408159967Sobrien	if (desc != NULL) {
1409159967Sobrien		bus_dmamap_unload(ring->rx_desc_tag, ring->rx_desc_map);
1410159967Sobrien		bus_dmamem_free(ring->rx_desc_tag, desc, ring->rx_desc_map);
1411170589Syongari		ring->desc64 = NULL;
1412170589Syongari		ring->desc32 = NULL;
1413170589Syongari	}
1414170589Syongari	if (ring->rx_desc_tag != NULL) {
1415159967Sobrien		bus_dma_tag_destroy(ring->rx_desc_tag);
1416170589Syongari		ring->rx_desc_tag = NULL;
1417159967Sobrien	}
1418170589Syongari}
1419159967Sobrien
1420164650Sobrien
1421170589Syongaristatic void
1422170589Syongarinfe_free_jrx_ring(struct nfe_softc *sc, struct nfe_jrx_ring *ring)
1423170589Syongari{
1424170589Syongari	struct nfe_rx_data *data;
1425170589Syongari	void *desc;
1426170589Syongari	int i, descsize;
1427170589Syongari
1428170589Syongari	if ((sc->nfe_flags & NFE_JUMBO_SUP) == 0)
1429170589Syongari		return;
1430170589Syongari
1431170589Syongari	if (sc->nfe_flags & NFE_40BIT_ADDR) {
1432170589Syongari		desc = ring->jdesc64;
1433170589Syongari		descsize = sizeof (struct nfe_desc64);
1434170589Syongari	} else {
1435170589Syongari		desc = ring->jdesc32;
1436170589Syongari		descsize = sizeof (struct nfe_desc32);
1437170589Syongari	}
1438170589Syongari
1439170589Syongari	for (i = 0; i < NFE_JUMBO_RX_RING_COUNT; i++) {
1440170589Syongari		data = &ring->jdata[i];
1441164651Sobrien		if (data->rx_data_map != NULL) {
1442170589Syongari			bus_dmamap_destroy(ring->jrx_data_tag,
1443164651Sobrien			    data->rx_data_map);
1444170589Syongari			data->rx_data_map = NULL;
1445164651Sobrien		}
1446170589Syongari		if (data->m != NULL) {
1447164651Sobrien			m_freem(data->m);
1448170589Syongari			data->m = NULL;
1449170589Syongari		}
1450164651Sobrien	}
1451170589Syongari	if (ring->jrx_data_tag != NULL) {
1452170589Syongari		if (ring->jrx_spare_map != NULL) {
1453170589Syongari			bus_dmamap_destroy(ring->jrx_data_tag,
1454170589Syongari			    ring->jrx_spare_map);
1455170589Syongari			ring->jrx_spare_map = NULL;
1456170589Syongari		}
1457170589Syongari		bus_dma_tag_destroy(ring->jrx_data_tag);
1458170589Syongari		ring->jrx_data_tag = NULL;
1459170589Syongari	}
1460170589Syongari
1461170589Syongari	if (desc != NULL) {
1462170589Syongari		bus_dmamap_unload(ring->jrx_desc_tag, ring->jrx_desc_map);
1463170589Syongari		bus_dmamem_free(ring->jrx_desc_tag, desc, ring->jrx_desc_map);
1464170589Syongari		ring->jdesc64 = NULL;
1465170589Syongari		ring->jdesc32 = NULL;
1466170589Syongari	}
1467176859Syongari
1468170589Syongari	if (ring->jrx_desc_tag != NULL) {
1469170589Syongari		bus_dma_tag_destroy(ring->jrx_desc_tag);
1470170589Syongari		ring->jrx_desc_tag = NULL;
1471170589Syongari	}
1472159952Sobrien}
1473159952Sobrien
1474163503Sobrien
1475159967Sobrienstatic int
1476159967Sobriennfe_alloc_tx_ring(struct nfe_softc *sc, struct nfe_tx_ring *ring)
1477159952Sobrien{
1478170589Syongari	struct nfe_dmamap_arg ctx;
1479159967Sobrien	int i, error;
1480170589Syongari	void *desc;
1481159967Sobrien	int descsize;
1482159952Sobrien
1483159967Sobrien	if (sc->nfe_flags & NFE_40BIT_ADDR) {
1484170589Syongari		desc = ring->desc64;
1485159967Sobrien		descsize = sizeof (struct nfe_desc64);
1486159967Sobrien	} else {
1487170589Syongari		desc = ring->desc32;
1488159967Sobrien		descsize = sizeof (struct nfe_desc32);
1489159967Sobrien	}
1490159952Sobrien
1491159967Sobrien	ring->queued = 0;
1492159967Sobrien	ring->cur = ring->next = 0;
1493159967Sobrien
1494163503Sobrien	error = bus_dma_tag_create(sc->nfe_parent_tag,
1495170589Syongari	    NFE_RING_ALIGN, 0,			/* alignment, boundary */
1496170589Syongari	    BUS_SPACE_MAXADDR,			/* lowaddr */
1497170589Syongari	    BUS_SPACE_MAXADDR,			/* highaddr */
1498170589Syongari	    NULL, NULL,				/* filter, filterarg */
1499170589Syongari	    NFE_TX_RING_COUNT * descsize, 1,	/* maxsize, nsegments */
1500170589Syongari	    NFE_TX_RING_COUNT * descsize,	/* maxsegsize */
1501170589Syongari	    0,					/* flags */
1502170589Syongari	    NULL, NULL,				/* lockfunc, lockarg */
1503170589Syongari	    &ring->tx_desc_tag);
1504159967Sobrien	if (error != 0) {
1505170589Syongari		device_printf(sc->nfe_dev, "could not create desc DMA tag\n");
1506159967Sobrien		goto fail;
1507159952Sobrien	}
1508159952Sobrien
1509170589Syongari	error = bus_dmamem_alloc(ring->tx_desc_tag, &desc, BUS_DMA_WAITOK |
1510170589Syongari	    BUS_DMA_COHERENT | BUS_DMA_ZERO, &ring->tx_desc_map);
1511159967Sobrien	if (error != 0) {
1512170589Syongari		device_printf(sc->nfe_dev, "could not create desc DMA map\n");
1513159967Sobrien		goto fail;
1514159967Sobrien	}
1515170589Syongari	if (sc->nfe_flags & NFE_40BIT_ADDR)
1516170589Syongari		ring->desc64 = desc;
1517170589Syongari	else
1518170589Syongari		ring->desc32 = desc;
1519159967Sobrien
1520170589Syongari	ctx.nfe_busaddr = 0;
1521170589Syongari	error = bus_dmamap_load(ring->tx_desc_tag, ring->tx_desc_map, desc,
1522170589Syongari	    NFE_TX_RING_COUNT * descsize, nfe_dma_map_segs, &ctx, 0);
1523159967Sobrien	if (error != 0) {
1524170589Syongari		device_printf(sc->nfe_dev, "could not load desc DMA map\n");
1525159967Sobrien		goto fail;
1526159967Sobrien	}
1527170589Syongari	ring->physaddr = ctx.nfe_busaddr;
1528159967Sobrien
1529163503Sobrien	error = bus_dma_tag_create(sc->nfe_parent_tag,
1530170589Syongari	    1, 0,
1531170589Syongari	    BUS_SPACE_MAXADDR,
1532170589Syongari	    BUS_SPACE_MAXADDR,
1533170589Syongari	    NULL, NULL,
1534170595Syongari	    NFE_TSO_MAXSIZE,
1535170589Syongari	    NFE_MAX_SCATTER,
1536170595Syongari	    NFE_TSO_MAXSGSIZE,
1537170589Syongari	    0,
1538170589Syongari	    NULL, NULL,
1539170589Syongari	    &ring->tx_data_tag);
1540159967Sobrien	if (error != 0) {
1541170589Syongari		device_printf(sc->nfe_dev, "could not create Tx DMA tag\n");
1542170589Syongari		goto fail;
1543159967Sobrien	}
1544159967Sobrien
1545159967Sobrien	for (i = 0; i < NFE_TX_RING_COUNT; i++) {
1546163503Sobrien		error = bus_dmamap_create(ring->tx_data_tag, 0,
1547163503Sobrien		    &ring->data[i].tx_data_map);
1548159967Sobrien		if (error != 0) {
1549170589Syongari			device_printf(sc->nfe_dev,
1550170589Syongari			    "could not create Tx DMA map\n");
1551159967Sobrien			goto fail;
1552159967Sobrien		}
1553159967Sobrien	}
1554159967Sobrien
1555170589Syongarifail:
1556170589Syongari	return (error);
1557159967Sobrien}
1558159967Sobrien
1559159967Sobrien
1560159967Sobrienstatic void
1561170589Syongarinfe_init_tx_ring(struct nfe_softc *sc, struct nfe_tx_ring *ring)
1562159967Sobrien{
1563170589Syongari	void *desc;
1564170589Syongari	size_t descsize;
1565159967Sobrien
1566170589Syongari	sc->nfe_force_tx = 0;
1567170589Syongari	ring->queued = 0;
1568170589Syongari	ring->cur = ring->next = 0;
1569170589Syongari	if (sc->nfe_flags & NFE_40BIT_ADDR) {
1570170589Syongari		desc = ring->desc64;
1571170589Syongari		descsize = sizeof (struct nfe_desc64);
1572170589Syongari	} else {
1573170589Syongari		desc = ring->desc32;
1574170589Syongari		descsize = sizeof (struct nfe_desc32);
1575159967Sobrien	}
1576170589Syongari	bzero(desc, descsize * NFE_TX_RING_COUNT);
1577159967Sobrien
1578163503Sobrien	bus_dmamap_sync(ring->tx_desc_tag, ring->tx_desc_map,
1579170589Syongari	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1580159967Sobrien}
1581159967Sobrien
1582163503Sobrien
1583159967Sobrienstatic void
1584159967Sobriennfe_free_tx_ring(struct nfe_softc *sc, struct nfe_tx_ring *ring)
1585159967Sobrien{
1586159967Sobrien	struct nfe_tx_data *data;
1587159967Sobrien	void *desc;
1588159967Sobrien	int i, descsize;
1589159967Sobrien
1590159967Sobrien	if (sc->nfe_flags & NFE_40BIT_ADDR) {
1591159967Sobrien		desc = ring->desc64;
1592159967Sobrien		descsize = sizeof (struct nfe_desc64);
1593159967Sobrien	} else {
1594159967Sobrien		desc = ring->desc32;
1595159967Sobrien		descsize = sizeof (struct nfe_desc32);
1596159967Sobrien	}
1597159967Sobrien
1598159967Sobrien	for (i = 0; i < NFE_TX_RING_COUNT; i++) {
1599159967Sobrien		data = &ring->data[i];
1600159967Sobrien
1601159967Sobrien		if (data->m != NULL) {
1602170589Syongari			bus_dmamap_sync(ring->tx_data_tag, data->tx_data_map,
1603163503Sobrien			    BUS_DMASYNC_POSTWRITE);
1604170589Syongari			bus_dmamap_unload(ring->tx_data_tag, data->tx_data_map);
1605159967Sobrien			m_freem(data->m);
1606170589Syongari			data->m = NULL;
1607159967Sobrien		}
1608170589Syongari		if (data->tx_data_map != NULL) {
1609170589Syongari			bus_dmamap_destroy(ring->tx_data_tag,
1610170589Syongari			    data->tx_data_map);
1611170589Syongari			data->tx_data_map = NULL;
1612170589Syongari		}
1613159967Sobrien	}
1614159967Sobrien
1615170589Syongari	if (ring->tx_data_tag != NULL) {
1616170589Syongari		bus_dma_tag_destroy(ring->tx_data_tag);
1617170589Syongari		ring->tx_data_tag = NULL;
1618159967Sobrien	}
1619159967Sobrien
1620170589Syongari	if (desc != NULL) {
1621170589Syongari		bus_dmamap_sync(ring->tx_desc_tag, ring->tx_desc_map,
1622170589Syongari		    BUS_DMASYNC_POSTWRITE);
1623170589Syongari		bus_dmamap_unload(ring->tx_desc_tag, ring->tx_desc_map);
1624170589Syongari		bus_dmamem_free(ring->tx_desc_tag, desc, ring->tx_desc_map);
1625170589Syongari		ring->desc64 = NULL;
1626170589Syongari		ring->desc32 = NULL;
1627170589Syongari		bus_dma_tag_destroy(ring->tx_desc_tag);
1628170589Syongari		ring->tx_desc_tag = NULL;
1629170589Syongari	}
1630159967Sobrien}
1631159967Sobrien
1632159967Sobrien#ifdef DEVICE_POLLING
1633272257Sglebiusstatic poll_handler_t nfe_poll;
1634159967Sobrien
1635163503Sobrien
1636193096Sattiliostatic int
1637268131Smarcelnfe_poll(if_t ifp, enum poll_cmd cmd, int count)
1638159967Sobrien{
1639268131Smarcel	struct nfe_softc *sc = if_getsoftc(ifp);
1640170589Syongari	uint32_t r;
1641193096Sattilio	int rx_npkts = 0;
1642159967Sobrien
1643159967Sobrien	NFE_LOCK(sc);
1644159967Sobrien
1645268131Smarcel	if (!(if_getdrvflags(ifp) & IFF_DRV_RUNNING)) {
1646170589Syongari		NFE_UNLOCK(sc);
1647193096Sattilio		return (rx_npkts);
1648159967Sobrien	}
1649159967Sobrien
1650171559Syongari	if (sc->nfe_framesize > MCLBYTES - ETHER_HDR_LEN)
1651193096Sattilio		rx_npkts = nfe_jrxeof(sc, count, &rx_npkts);
1652171559Syongari	else
1653193096Sattilio		rx_npkts = nfe_rxeof(sc, count, &rx_npkts);
1654159967Sobrien	nfe_txeof(sc);
1655268131Smarcel	if (!if_sendq_empty(ifp))
1656216925Sjhb		nfe_start_locked(ifp);
1657159967Sobrien
1658159967Sobrien	if (cmd == POLL_AND_CHECK_STATUS) {
1659170589Syongari		if ((r = NFE_READ(sc, sc->nfe_irq_status)) == 0) {
1660170589Syongari			NFE_UNLOCK(sc);
1661193096Sattilio			return (rx_npkts);
1662163503Sobrien		}
1663170589Syongari		NFE_WRITE(sc, sc->nfe_irq_status, r);
1664159967Sobrien
1665163503Sobrien		if (r & NFE_IRQ_LINK) {
1666163503Sobrien			NFE_READ(sc, NFE_PHY_STATUS);
1667163503Sobrien			NFE_WRITE(sc, NFE_PHY_STATUS, 0xf);
1668170589Syongari			DPRINTF(sc, "link state changed\n");
1669163503Sobrien		}
1670159967Sobrien	}
1671170589Syongari	NFE_UNLOCK(sc);
1672193096Sattilio	return (rx_npkts);
1673159967Sobrien}
1674159967Sobrien#endif /* DEVICE_POLLING */
1675159967Sobrien
1676170589Syongaristatic void
1677170589Syongarinfe_set_intr(struct nfe_softc *sc)
1678170589Syongari{
1679159967Sobrien
1680170589Syongari	if (sc->nfe_msi != 0)
1681170589Syongari		NFE_WRITE(sc, NFE_IRQ_MASK, NFE_IRQ_WANTED);
1682170589Syongari}
1683170589Syongari
1684170589Syongari
1685170589Syongari/* In MSIX, a write to mask reegisters behaves as XOR. */
1686170589Syongaristatic __inline void
1687170589Syongarinfe_enable_intr(struct nfe_softc *sc)
1688170589Syongari{
1689170589Syongari
1690170589Syongari	if (sc->nfe_msix != 0) {
1691170589Syongari		/* XXX Should have a better way to enable interrupts! */
1692170589Syongari		if (NFE_READ(sc, sc->nfe_irq_mask) == 0)
1693170589Syongari			NFE_WRITE(sc, sc->nfe_irq_mask, sc->nfe_intrs);
1694170589Syongari	} else
1695170589Syongari		NFE_WRITE(sc, sc->nfe_irq_mask, sc->nfe_intrs);
1696170589Syongari}
1697170589Syongari
1698170589Syongari
1699170589Syongaristatic __inline void
1700170589Syongarinfe_disable_intr(struct nfe_softc *sc)
1701170589Syongari{
1702170589Syongari
1703170589Syongari	if (sc->nfe_msix != 0) {
1704170589Syongari		/* XXX Should have a better way to disable interrupts! */
1705170589Syongari		if (NFE_READ(sc, sc->nfe_irq_mask) != 0)
1706170589Syongari			NFE_WRITE(sc, sc->nfe_irq_mask, sc->nfe_nointrs);
1707170589Syongari	} else
1708170589Syongari		NFE_WRITE(sc, sc->nfe_irq_mask, sc->nfe_nointrs);
1709170589Syongari}
1710170589Syongari
1711170589Syongari
1712159967Sobrienstatic int
1713268131Smarcelnfe_ioctl(if_t ifp, u_long cmd, caddr_t data)
1714159967Sobrien{
1715170589Syongari	struct nfe_softc *sc;
1716170589Syongari	struct ifreq *ifr;
1717163503Sobrien	struct mii_data *mii;
1718170589Syongari	int error, init, mask;
1719159967Sobrien
1720268131Smarcel	sc = if_getsoftc(ifp);
1721170589Syongari	ifr = (struct ifreq *) data;
1722170589Syongari	error = 0;
1723170589Syongari	init = 0;
1724159952Sobrien	switch (cmd) {
1725159952Sobrien	case SIOCSIFMTU:
1726170589Syongari		if (ifr->ifr_mtu < ETHERMIN || ifr->ifr_mtu > NFE_JUMBO_MTU)
1727159952Sobrien			error = EINVAL;
1728268131Smarcel		else if (if_getmtu(ifp) != ifr->ifr_mtu) {
1729171559Syongari			if ((((sc->nfe_flags & NFE_JUMBO_SUP) == 0) ||
1730171559Syongari			    (sc->nfe_jumbo_disable != 0)) &&
1731170589Syongari			    ifr->ifr_mtu > ETHERMTU)
1732170589Syongari				error = EINVAL;
1733170589Syongari			else {
1734170589Syongari				NFE_LOCK(sc);
1735268131Smarcel				if_setmtu(ifp, ifr->ifr_mtu);
1736268131Smarcel				if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) {
1737268131Smarcel					if_setdrvflagbits(ifp, 0, IFF_DRV_RUNNING);
1738170589Syongari					nfe_init_locked(sc);
1739217794Syongari				}
1740170589Syongari				NFE_UNLOCK(sc);
1741164650Sobrien			}
1742164650Sobrien		}
1743159952Sobrien		break;
1744159952Sobrien	case SIOCSIFFLAGS:
1745159967Sobrien		NFE_LOCK(sc);
1746268131Smarcel		if (if_getflags(ifp) & IFF_UP) {
1747159952Sobrien			/*
1748159952Sobrien			 * If only the PROMISC or ALLMULTI flag changes, then
1749159952Sobrien			 * don't do a full re-init of the chip, just update
1750159952Sobrien			 * the Rx filter.
1751159952Sobrien			 */
1752268131Smarcel			if ((if_getdrvflags(ifp) & IFF_DRV_RUNNING) &&
1753268131Smarcel			    ((if_getflags(ifp) ^ sc->nfe_if_flags) &
1754159967Sobrien			     (IFF_ALLMULTI | IFF_PROMISC)) != 0)
1755159952Sobrien				nfe_setmulti(sc);
1756159967Sobrien			else
1757159967Sobrien				nfe_init_locked(sc);
1758159952Sobrien		} else {
1759268131Smarcel			if (if_getdrvflags(ifp) & IFF_DRV_RUNNING)
1760170589Syongari				nfe_stop(ifp);
1761159952Sobrien		}
1762268131Smarcel		sc->nfe_if_flags = if_getflags(ifp);
1763159967Sobrien		NFE_UNLOCK(sc);
1764159967Sobrien		error = 0;
1765159952Sobrien		break;
1766159952Sobrien	case SIOCADDMULTI:
1767159952Sobrien	case SIOCDELMULTI:
1768268131Smarcel		if ((if_getdrvflags(ifp) & IFF_DRV_RUNNING) != 0) {
1769159967Sobrien			NFE_LOCK(sc);
1770159967Sobrien			nfe_setmulti(sc);
1771159967Sobrien			NFE_UNLOCK(sc);
1772159952Sobrien			error = 0;
1773159952Sobrien		}
1774159952Sobrien		break;
1775159952Sobrien	case SIOCSIFMEDIA:
1776159952Sobrien	case SIOCGIFMEDIA:
1777159967Sobrien		mii = device_get_softc(sc->nfe_miibus);
1778270876Sglebius		error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, cmd);
1779159952Sobrien		break;
1780159967Sobrien	case SIOCSIFCAP:
1781268131Smarcel		mask = ifr->ifr_reqcap ^ if_getcapenable(ifp);
1782159967Sobrien#ifdef DEVICE_POLLING
1783170589Syongari		if ((mask & IFCAP_POLLING) != 0) {
1784170589Syongari			if ((ifr->ifr_reqcap & IFCAP_POLLING) != 0) {
1785272257Sglebius				error = ether_poll_register(nfe_poll, ifp);
1786159967Sobrien				if (error)
1787170589Syongari					break;
1788159967Sobrien				NFE_LOCK(sc);
1789170589Syongari				nfe_disable_intr(sc);
1790268131Smarcel				if_setcapenablebit(ifp, IFCAP_POLLING, 0);
1791159967Sobrien				NFE_UNLOCK(sc);
1792159967Sobrien			} else {
1793159967Sobrien				error = ether_poll_deregister(ifp);
1794159967Sobrien				/* Enable interrupt even in error case */
1795159967Sobrien				NFE_LOCK(sc);
1796170589Syongari				nfe_enable_intr(sc);
1797268131Smarcel				if_setcapenablebit(ifp, 0, IFCAP_POLLING);
1798159967Sobrien				NFE_UNLOCK(sc);
1799159967Sobrien			}
1800159967Sobrien		}
1801163503Sobrien#endif /* DEVICE_POLLING */
1802215132Syongari		if ((mask & IFCAP_WOL_MAGIC) != 0 &&
1803268131Smarcel		    (if_getcapabilities(ifp) & IFCAP_WOL_MAGIC) != 0)
1804268131Smarcel			if_togglecapenable(ifp, IFCAP_WOL_MAGIC);
1805215432Syongari		if ((mask & IFCAP_TXCSUM) != 0 &&
1806268131Smarcel		    (if_getcapabilities(ifp) & IFCAP_TXCSUM) != 0) {
1807268131Smarcel			if_togglecapenable(ifp, IFCAP_TXCSUM);
1808268131Smarcel			if ((if_getcapenable(ifp) & IFCAP_TXCSUM) != 0)
1809268131Smarcel				if_sethwassistbits(ifp, NFE_CSUM_FEATURES, 0);
1810159967Sobrien			else
1811268131Smarcel				if_sethwassistbits(ifp, 0, NFE_CSUM_FEATURES);
1812215432Syongari		}
1813215432Syongari		if ((mask & IFCAP_RXCSUM) != 0 &&
1814268131Smarcel		    (if_getcapabilities(ifp) & IFCAP_RXCSUM) != 0) {
1815268131Smarcel			if_togglecapenable(ifp, IFCAP_RXCSUM);
1816170589Syongari			init++;
1817159967Sobrien		}
1818215432Syongari		if ((mask & IFCAP_TSO4) != 0 &&
1819268131Smarcel		    (if_getcapabilities(ifp) & IFCAP_TSO4) != 0) {
1820268131Smarcel			if_togglecapenable(ifp, IFCAP_TSO4);
1821268131Smarcel			if ((IFCAP_TSO4 & if_getcapenable(ifp)) != 0)
1822268131Smarcel				if_sethwassistbits(ifp, CSUM_TSO, 0);
1823215432Syongari			else
1824268131Smarcel				if_sethwassistbits(ifp, 0, CSUM_TSO);
1825215432Syongari		}
1826215432Syongari		if ((mask & IFCAP_VLAN_HWTSO) != 0 &&
1827268131Smarcel		    (if_getcapabilities(ifp) & IFCAP_VLAN_HWTSO) != 0)
1828268131Smarcel			if_togglecapenable(ifp, IFCAP_VLAN_HWTSO);
1829215432Syongari		if ((mask & IFCAP_VLAN_HWTAGGING) != 0 &&
1830268131Smarcel		    (if_getcapabilities(ifp) & IFCAP_VLAN_HWTAGGING) != 0) {
1831268131Smarcel			if_togglecapenable(ifp, IFCAP_VLAN_HWTAGGING);
1832268131Smarcel			if ((if_getcapenable(ifp) & IFCAP_VLAN_HWTAGGING) == 0)
1833268131Smarcel				if_setcapenablebit(ifp, 0, IFCAP_VLAN_HWTSO);
1834170589Syongari			init++;
1835170589Syongari		}
1836170589Syongari		/*
1837170589Syongari		 * XXX
1838170589Syongari		 * It seems that VLAN stripping requires Rx checksum offload.
1839170589Syongari		 * Unfortunately FreeBSD has no way to disable only Rx side
1840170589Syongari		 * VLAN stripping. So when we know Rx checksum offload is
1841170589Syongari		 * disabled turn entire hardware VLAN assist off.
1842170589Syongari		 */
1843268131Smarcel		if ((if_getcapenable(ifp) & IFCAP_RXCSUM) == 0) {
1844268131Smarcel			if ((if_getcapenable(ifp) & IFCAP_VLAN_HWTAGGING) != 0)
1845215432Syongari				init++;
1846268131Smarcel			if_setcapenablebit(ifp, 0,
1847268131Smarcel			    (IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_HWTSO));
1848170589Syongari		}
1849268131Smarcel		if (init > 0 && (if_getdrvflags(ifp) & IFF_DRV_RUNNING) != 0) {
1850268131Smarcel			if_setdrvflagbits(ifp, 0, IFF_DRV_RUNNING);
1851164656Sobrien			nfe_init(sc);
1852170589Syongari		}
1853268131Smarcel		if_vlancap(ifp);
1854159967Sobrien		break;
1855159952Sobrien	default:
1856270876Sglebius		error = ether_ioctl(ifp, cmd, data);
1857159967Sobrien		break;
1858159952Sobrien	}
1859159952Sobrien
1860170589Syongari	return (error);
1861159952Sobrien}
1862159952Sobrien
1863159967Sobrien
1864170589Syongaristatic int
1865163503Sobriennfe_intr(void *arg)
1866159967Sobrien{
1867170589Syongari	struct nfe_softc *sc;
1868170589Syongari	uint32_t status;
1869170589Syongari
1870170589Syongari	sc = (struct nfe_softc *)arg;
1871170589Syongari
1872170589Syongari	status = NFE_READ(sc, sc->nfe_irq_status);
1873170589Syongari	if (status == 0 || status == 0xffffffff)
1874170589Syongari		return (FILTER_STRAY);
1875170589Syongari	nfe_disable_intr(sc);
1876296272Sjhb	taskqueue_enqueue(sc->nfe_tq, &sc->nfe_int_task);
1877170589Syongari
1878170589Syongari	return (FILTER_HANDLED);
1879170589Syongari}
1880170589Syongari
1881170589Syongari
1882170589Syongaristatic void
1883170589Syongarinfe_int_task(void *arg, int pending)
1884170589Syongari{
1885159967Sobrien	struct nfe_softc *sc = arg;
1886268131Smarcel	if_t ifp = sc->nfe_ifp;
1887170589Syongari	uint32_t r;
1888170589Syongari	int domore;
1889159967Sobrien
1890163503Sobrien	NFE_LOCK(sc);
1891159967Sobrien
1892170589Syongari	if ((r = NFE_READ(sc, sc->nfe_irq_status)) == 0) {
1893170589Syongari		nfe_enable_intr(sc);
1894170589Syongari		NFE_UNLOCK(sc);
1895170589Syongari		return;	/* not for us */
1896170589Syongari	}
1897170589Syongari	NFE_WRITE(sc, sc->nfe_irq_status, r);
1898170589Syongari
1899170589Syongari	DPRINTFN(sc, 5, "nfe_intr: interrupt register %x\n", r);
1900170589Syongari
1901159967Sobrien#ifdef DEVICE_POLLING
1902268131Smarcel	if (if_getcapenable(ifp) & IFCAP_POLLING) {
1903159967Sobrien		NFE_UNLOCK(sc);
1904159967Sobrien		return;
1905159967Sobrien	}
1906159967Sobrien#endif
1907159967Sobrien
1908172169Syongari	if (r & NFE_IRQ_LINK) {
1909172169Syongari		NFE_READ(sc, NFE_PHY_STATUS);
1910172169Syongari		NFE_WRITE(sc, NFE_PHY_STATUS, 0xf);
1911172169Syongari		DPRINTF(sc, "link state changed\n");
1912172169Syongari	}
1913172169Syongari
1914268131Smarcel	if ((if_getdrvflags(ifp) & IFF_DRV_RUNNING) == 0) {
1915163503Sobrien		NFE_UNLOCK(sc);
1916222542Syongari		nfe_disable_intr(sc);
1917170589Syongari		return;
1918159967Sobrien	}
1919159967Sobrien
1920170589Syongari	domore = 0;
1921170589Syongari	/* check Rx ring */
1922170589Syongari	if (sc->nfe_framesize > MCLBYTES - ETHER_HDR_LEN)
1923193096Sattilio		domore = nfe_jrxeof(sc, sc->nfe_process_limit, NULL);
1924170589Syongari	else
1925193096Sattilio		domore = nfe_rxeof(sc, sc->nfe_process_limit, NULL);
1926170589Syongari	/* check Tx ring */
1927170589Syongari	nfe_txeof(sc);
1928159967Sobrien
1929268131Smarcel	if (!if_sendq_empty(ifp))
1930216925Sjhb		nfe_start_locked(ifp);
1931159967Sobrien
1932159967Sobrien	NFE_UNLOCK(sc);
1933159967Sobrien
1934170589Syongari	if (domore || (NFE_READ(sc, sc->nfe_irq_status) != 0)) {
1935296272Sjhb		taskqueue_enqueue(sc->nfe_tq, &sc->nfe_int_task);
1936170589Syongari		return;
1937170589Syongari	}
1938170589Syongari
1939170589Syongari	/* Reenable interrupts. */
1940170589Syongari	nfe_enable_intr(sc);
1941159967Sobrien}
1942159967Sobrien
1943163503Sobrien
1944170589Syongaristatic __inline void
1945170589Syongarinfe_discard_rxbuf(struct nfe_softc *sc, int idx)
1946159952Sobrien{
1947170589Syongari	struct nfe_desc32 *desc32;
1948170589Syongari	struct nfe_desc64 *desc64;
1949170589Syongari	struct nfe_rx_data *data;
1950170589Syongari	struct mbuf *m;
1951163503Sobrien
1952170589Syongari	data = &sc->rxq.data[idx];
1953170589Syongari	m = data->m;
1954170589Syongari
1955170589Syongari	if (sc->nfe_flags & NFE_40BIT_ADDR) {
1956170589Syongari		desc64 = &sc->rxq.desc64[idx];
1957170589Syongari		/* VLAN packet may have overwritten it. */
1958170589Syongari		desc64->physaddr[0] = htole32(NFE_ADDR_HI(data->paddr));
1959170589Syongari		desc64->physaddr[1] = htole32(NFE_ADDR_LO(data->paddr));
1960170589Syongari		desc64->length = htole16(m->m_len);
1961170589Syongari		desc64->flags = htole16(NFE_RX_READY);
1962170589Syongari	} else {
1963170589Syongari		desc32 = &sc->rxq.desc32[idx];
1964170589Syongari		desc32->length = htole16(m->m_len);
1965170589Syongari		desc32->flags = htole16(NFE_RX_READY);
1966170589Syongari	}
1967159952Sobrien}
1968159952Sobrien
1969163503Sobrien
1970170589Syongaristatic __inline void
1971170589Syongarinfe_discard_jrxbuf(struct nfe_softc *sc, int idx)
1972159952Sobrien{
1973170589Syongari	struct nfe_desc32 *desc32;
1974170589Syongari	struct nfe_desc64 *desc64;
1975170589Syongari	struct nfe_rx_data *data;
1976170589Syongari	struct mbuf *m;
1977163503Sobrien
1978170589Syongari	data = &sc->jrxq.jdata[idx];
1979170589Syongari	m = data->m;
1980170589Syongari
1981170589Syongari	if (sc->nfe_flags & NFE_40BIT_ADDR) {
1982170589Syongari		desc64 = &sc->jrxq.jdesc64[idx];
1983170589Syongari		/* VLAN packet may have overwritten it. */
1984170589Syongari		desc64->physaddr[0] = htole32(NFE_ADDR_HI(data->paddr));
1985170589Syongari		desc64->physaddr[1] = htole32(NFE_ADDR_LO(data->paddr));
1986170589Syongari		desc64->length = htole16(m->m_len);
1987170589Syongari		desc64->flags = htole16(NFE_RX_READY);
1988170589Syongari	} else {
1989170589Syongari		desc32 = &sc->jrxq.jdesc32[idx];
1990170589Syongari		desc32->length = htole16(m->m_len);
1991170589Syongari		desc32->flags = htole16(NFE_RX_READY);
1992170589Syongari	}
1993159952Sobrien}
1994159952Sobrien
1995163503Sobrien
1996170589Syongaristatic int
1997170589Syongarinfe_newbuf(struct nfe_softc *sc, int idx)
1998159952Sobrien{
1999170589Syongari	struct nfe_rx_data *data;
2000170589Syongari	struct nfe_desc32 *desc32;
2001170589Syongari	struct nfe_desc64 *desc64;
2002170589Syongari	struct mbuf *m;
2003170589Syongari	bus_dma_segment_t segs[1];
2004170589Syongari	bus_dmamap_t map;
2005170589Syongari	int nsegs;
2006163503Sobrien
2007243857Sglebius	m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
2008170589Syongari	if (m == NULL)
2009170589Syongari		return (ENOBUFS);
2010159952Sobrien
2011170589Syongari	m->m_len = m->m_pkthdr.len = MCLBYTES;
2012170589Syongari	m_adj(m, ETHER_ALIGN);
2013163503Sobrien
2014170589Syongari	if (bus_dmamap_load_mbuf_sg(sc->rxq.rx_data_tag, sc->rxq.rx_spare_map,
2015170589Syongari	    m, segs, &nsegs, BUS_DMA_NOWAIT) != 0) {
2016170589Syongari		m_freem(m);
2017170589Syongari		return (ENOBUFS);
2018170589Syongari	}
2019170589Syongari	KASSERT(nsegs == 1, ("%s: %d segments returned!", __func__, nsegs));
2020163503Sobrien
2021170589Syongari	data = &sc->rxq.data[idx];
2022170589Syongari	if (data->m != NULL) {
2023170589Syongari		bus_dmamap_sync(sc->rxq.rx_data_tag, data->rx_data_map,
2024170589Syongari		    BUS_DMASYNC_POSTREAD);
2025170589Syongari		bus_dmamap_unload(sc->rxq.rx_data_tag, data->rx_data_map);
2026170589Syongari	}
2027170589Syongari	map = data->rx_data_map;
2028170589Syongari	data->rx_data_map = sc->rxq.rx_spare_map;
2029170589Syongari	sc->rxq.rx_spare_map = map;
2030170589Syongari	bus_dmamap_sync(sc->rxq.rx_data_tag, data->rx_data_map,
2031170589Syongari	    BUS_DMASYNC_PREREAD);
2032170589Syongari	data->paddr = segs[0].ds_addr;
2033170589Syongari	data->m = m;
2034170589Syongari	/* update mapping address in h/w descriptor */
2035170589Syongari	if (sc->nfe_flags & NFE_40BIT_ADDR) {
2036170589Syongari		desc64 = &sc->rxq.desc64[idx];
2037170589Syongari		desc64->physaddr[0] = htole32(NFE_ADDR_HI(segs[0].ds_addr));
2038170589Syongari		desc64->physaddr[1] = htole32(NFE_ADDR_LO(segs[0].ds_addr));
2039170589Syongari		desc64->length = htole16(segs[0].ds_len);
2040170589Syongari		desc64->flags = htole16(NFE_RX_READY);
2041170589Syongari	} else {
2042170589Syongari		desc32 = &sc->rxq.desc32[idx];
2043170589Syongari		desc32->physaddr = htole32(NFE_ADDR_LO(segs[0].ds_addr));
2044170589Syongari		desc32->length = htole16(segs[0].ds_len);
2045170589Syongari		desc32->flags = htole16(NFE_RX_READY);
2046170589Syongari	}
2047170589Syongari
2048170589Syongari	return (0);
2049159952Sobrien}
2050159952Sobrien
2051163503Sobrien
2052170589Syongaristatic int
2053170589Syongarinfe_jnewbuf(struct nfe_softc *sc, int idx)
2054159952Sobrien{
2055170589Syongari	struct nfe_rx_data *data;
2056170589Syongari	struct nfe_desc32 *desc32;
2057170589Syongari	struct nfe_desc64 *desc64;
2058170589Syongari	struct mbuf *m;
2059170589Syongari	bus_dma_segment_t segs[1];
2060170589Syongari	bus_dmamap_t map;
2061170589Syongari	int nsegs;
2062163503Sobrien
2063243857Sglebius	m = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, MJUM9BYTES);
2064170589Syongari	if (m == NULL)
2065170589Syongari		return (ENOBUFS);
2066176859Syongari	m->m_pkthdr.len = m->m_len = MJUM9BYTES;
2067170589Syongari	m_adj(m, ETHER_ALIGN);
2068159952Sobrien
2069170589Syongari	if (bus_dmamap_load_mbuf_sg(sc->jrxq.jrx_data_tag,
2070170589Syongari	    sc->jrxq.jrx_spare_map, m, segs, &nsegs, BUS_DMA_NOWAIT) != 0) {
2071170589Syongari		m_freem(m);
2072170589Syongari		return (ENOBUFS);
2073170589Syongari	}
2074170589Syongari	KASSERT(nsegs == 1, ("%s: %d segments returned!", __func__, nsegs));
2075163503Sobrien
2076170589Syongari	data = &sc->jrxq.jdata[idx];
2077170589Syongari	if (data->m != NULL) {
2078170589Syongari		bus_dmamap_sync(sc->jrxq.jrx_data_tag, data->rx_data_map,
2079170589Syongari		    BUS_DMASYNC_POSTREAD);
2080170589Syongari		bus_dmamap_unload(sc->jrxq.jrx_data_tag, data->rx_data_map);
2081170589Syongari	}
2082170589Syongari	map = data->rx_data_map;
2083170589Syongari	data->rx_data_map = sc->jrxq.jrx_spare_map;
2084170589Syongari	sc->jrxq.jrx_spare_map = map;
2085170589Syongari	bus_dmamap_sync(sc->jrxq.jrx_data_tag, data->rx_data_map,
2086170589Syongari	    BUS_DMASYNC_PREREAD);
2087170589Syongari	data->paddr = segs[0].ds_addr;
2088170589Syongari	data->m = m;
2089170589Syongari	/* update mapping address in h/w descriptor */
2090170589Syongari	if (sc->nfe_flags & NFE_40BIT_ADDR) {
2091170589Syongari		desc64 = &sc->jrxq.jdesc64[idx];
2092170589Syongari		desc64->physaddr[0] = htole32(NFE_ADDR_HI(segs[0].ds_addr));
2093170589Syongari		desc64->physaddr[1] = htole32(NFE_ADDR_LO(segs[0].ds_addr));
2094170589Syongari		desc64->length = htole16(segs[0].ds_len);
2095170589Syongari		desc64->flags = htole16(NFE_RX_READY);
2096170589Syongari	} else {
2097170589Syongari		desc32 = &sc->jrxq.jdesc32[idx];
2098170589Syongari		desc32->physaddr = htole32(NFE_ADDR_LO(segs[0].ds_addr));
2099170589Syongari		desc32->length = htole16(segs[0].ds_len);
2100170589Syongari		desc32->flags = htole16(NFE_RX_READY);
2101170589Syongari	}
2102159967Sobrien
2103170589Syongari	return (0);
2104159952Sobrien}
2105159952Sobrien
2106163503Sobrien
2107170589Syongaristatic int
2108193096Sattilionfe_rxeof(struct nfe_softc *sc, int count, int *rx_npktsp)
2109159952Sobrien{
2110268131Smarcel	if_t ifp = sc->nfe_ifp;
2111170589Syongari	struct nfe_desc32 *desc32;
2112170589Syongari	struct nfe_desc64 *desc64;
2113159952Sobrien	struct nfe_rx_data *data;
2114170589Syongari	struct mbuf *m;
2115170589Syongari	uint16_t flags;
2116193096Sattilio	int len, prog, rx_npkts;
2117170589Syongari	uint32_t vtag = 0;
2118159952Sobrien
2119193096Sattilio	rx_npkts = 0;
2120159967Sobrien	NFE_LOCK_ASSERT(sc);
2121159967Sobrien
2122170589Syongari	bus_dmamap_sync(sc->rxq.rx_desc_tag, sc->rxq.rx_desc_map,
2123170589Syongari	    BUS_DMASYNC_POSTREAD);
2124159967Sobrien
2125170589Syongari	for (prog = 0;;NFE_INC(sc->rxq.cur, NFE_RX_RING_COUNT), vtag = 0) {
2126170589Syongari		if (count <= 0)
2127170589Syongari			break;
2128170589Syongari		count--;
2129159967Sobrien
2130159952Sobrien		data = &sc->rxq.data[sc->rxq.cur];
2131159952Sobrien
2132159967Sobrien		if (sc->nfe_flags & NFE_40BIT_ADDR) {
2133159952Sobrien			desc64 = &sc->rxq.desc64[sc->rxq.cur];
2134170589Syongari			vtag = le32toh(desc64->physaddr[1]);
2135170589Syongari			flags = le16toh(desc64->flags);
2136170589Syongari			len = le16toh(desc64->length) & NFE_RX_LEN_MASK;
2137159952Sobrien		} else {
2138159952Sobrien			desc32 = &sc->rxq.desc32[sc->rxq.cur];
2139170589Syongari			flags = le16toh(desc32->flags);
2140170589Syongari			len = le16toh(desc32->length) & NFE_RX_LEN_MASK;
2141159952Sobrien		}
2142159952Sobrien
2143159952Sobrien		if (flags & NFE_RX_READY)
2144159952Sobrien			break;
2145170589Syongari		prog++;
2146159967Sobrien		if ((sc->nfe_flags & (NFE_JUMBO_SUP | NFE_40BIT_ADDR)) == 0) {
2147170589Syongari			if (!(flags & NFE_RX_VALID_V1)) {
2148271782Sglebius				if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
2149170589Syongari				nfe_discard_rxbuf(sc, sc->rxq.cur);
2150170589Syongari				continue;
2151170589Syongari			}
2152159952Sobrien			if ((flags & NFE_RX_FIXME_V1) == NFE_RX_FIXME_V1) {
2153159952Sobrien				flags &= ~NFE_RX_ERROR;
2154159952Sobrien				len--;	/* fix buffer length */
2155159952Sobrien			}
2156159952Sobrien		} else {
2157170589Syongari			if (!(flags & NFE_RX_VALID_V2)) {
2158271782Sglebius				if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
2159170589Syongari				nfe_discard_rxbuf(sc, sc->rxq.cur);
2160170589Syongari				continue;
2161170589Syongari			}
2162159952Sobrien
2163159952Sobrien			if ((flags & NFE_RX_FIXME_V2) == NFE_RX_FIXME_V2) {
2164159952Sobrien				flags &= ~NFE_RX_ERROR;
2165159952Sobrien				len--;	/* fix buffer length */
2166159952Sobrien			}
2167159952Sobrien		}
2168159952Sobrien
2169159952Sobrien		if (flags & NFE_RX_ERROR) {
2170271782Sglebius			if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
2171170589Syongari			nfe_discard_rxbuf(sc, sc->rxq.cur);
2172170589Syongari			continue;
2173159952Sobrien		}
2174159952Sobrien
2175170589Syongari		m = data->m;
2176170589Syongari		if (nfe_newbuf(sc, sc->rxq.cur) != 0) {
2177271782Sglebius			if_inc_counter(ifp, IFCOUNTER_IQDROPS, 1);
2178170589Syongari			nfe_discard_rxbuf(sc, sc->rxq.cur);
2179170589Syongari			continue;
2180159952Sobrien		}
2181159952Sobrien
2182170589Syongari		if ((vtag & NFE_RX_VTAG) != 0 &&
2183268131Smarcel		    (if_getcapenable(ifp) & IFCAP_VLAN_HWTAGGING) != 0) {
2184170589Syongari			m->m_pkthdr.ether_vtag = vtag & 0xffff;
2185170589Syongari			m->m_flags |= M_VLANTAG;
2186164651Sobrien		}
2187159952Sobrien
2188170589Syongari		m->m_pkthdr.len = m->m_len = len;
2189170589Syongari		m->m_pkthdr.rcvif = ifp;
2190164651Sobrien
2191268131Smarcel		if ((if_getcapenable(ifp) & IFCAP_RXCSUM) != 0) {
2192170589Syongari			if ((flags & NFE_RX_IP_CSUMOK) != 0) {
2193170589Syongari				m->m_pkthdr.csum_flags |= CSUM_IP_CHECKED;
2194170589Syongari				m->m_pkthdr.csum_flags |= CSUM_IP_VALID;
2195170589Syongari				if ((flags & NFE_RX_TCP_CSUMOK) != 0 ||
2196170589Syongari				    (flags & NFE_RX_UDP_CSUMOK) != 0) {
2197170589Syongari					m->m_pkthdr.csum_flags |=
2198170589Syongari					    CSUM_DATA_VALID | CSUM_PSEUDO_HDR;
2199170589Syongari					m->m_pkthdr.csum_data = 0xffff;
2200170589Syongari				}
2201159952Sobrien			}
2202170589Syongari		}
2203170589Syongari
2204271782Sglebius		if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1);
2205170589Syongari
2206170589Syongari		NFE_UNLOCK(sc);
2207268131Smarcel		if_input(ifp, m);
2208170589Syongari		NFE_LOCK(sc);
2209193096Sattilio		rx_npkts++;
2210170589Syongari	}
2211170589Syongari
2212170589Syongari	if (prog > 0)
2213170589Syongari		bus_dmamap_sync(sc->rxq.rx_desc_tag, sc->rxq.rx_desc_map,
2214170589Syongari		    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
2215170589Syongari
2216193096Sattilio	if (rx_npktsp != NULL)
2217193096Sattilio		*rx_npktsp = rx_npkts;
2218170589Syongari	return (count > 0 ? 0 : EAGAIN);
2219170589Syongari}
2220170589Syongari
2221170589Syongari
2222170589Syongaristatic int
2223193096Sattilionfe_jrxeof(struct nfe_softc *sc, int count, int *rx_npktsp)
2224170589Syongari{
2225268131Smarcel	if_t ifp = sc->nfe_ifp;
2226170589Syongari	struct nfe_desc32 *desc32;
2227170589Syongari	struct nfe_desc64 *desc64;
2228170589Syongari	struct nfe_rx_data *data;
2229170589Syongari	struct mbuf *m;
2230170589Syongari	uint16_t flags;
2231193096Sattilio	int len, prog, rx_npkts;
2232170589Syongari	uint32_t vtag = 0;
2233170589Syongari
2234193096Sattilio	rx_npkts = 0;
2235170589Syongari	NFE_LOCK_ASSERT(sc);
2236170589Syongari
2237170589Syongari	bus_dmamap_sync(sc->jrxq.jrx_desc_tag, sc->jrxq.jrx_desc_map,
2238170589Syongari	    BUS_DMASYNC_POSTREAD);
2239170589Syongari
2240170589Syongari	for (prog = 0;;NFE_INC(sc->jrxq.jcur, NFE_JUMBO_RX_RING_COUNT),
2241170589Syongari	    vtag = 0) {
2242170589Syongari		if (count <= 0)
2243170589Syongari			break;
2244170589Syongari		count--;
2245170589Syongari
2246170589Syongari		data = &sc->jrxq.jdata[sc->jrxq.jcur];
2247170589Syongari
2248170589Syongari		if (sc->nfe_flags & NFE_40BIT_ADDR) {
2249170589Syongari			desc64 = &sc->jrxq.jdesc64[sc->jrxq.jcur];
2250170589Syongari			vtag = le32toh(desc64->physaddr[1]);
2251170589Syongari			flags = le16toh(desc64->flags);
2252170589Syongari			len = le16toh(desc64->length) & NFE_RX_LEN_MASK;
2253170589Syongari		} else {
2254170589Syongari			desc32 = &sc->jrxq.jdesc32[sc->jrxq.jcur];
2255170589Syongari			flags = le16toh(desc32->flags);
2256170589Syongari			len = le16toh(desc32->length) & NFE_RX_LEN_MASK;
2257170589Syongari		}
2258170589Syongari
2259170589Syongari		if (flags & NFE_RX_READY)
2260170589Syongari			break;
2261170589Syongari		prog++;
2262170589Syongari		if ((sc->nfe_flags & (NFE_JUMBO_SUP | NFE_40BIT_ADDR)) == 0) {
2263170589Syongari			if (!(flags & NFE_RX_VALID_V1)) {
2264271782Sglebius				if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
2265170589Syongari				nfe_discard_jrxbuf(sc, sc->jrxq.jcur);
2266170589Syongari				continue;
2267170589Syongari			}
2268170589Syongari			if ((flags & NFE_RX_FIXME_V1) == NFE_RX_FIXME_V1) {
2269170589Syongari				flags &= ~NFE_RX_ERROR;
2270170589Syongari				len--;	/* fix buffer length */
2271170589Syongari			}
2272170589Syongari		} else {
2273170589Syongari			if (!(flags & NFE_RX_VALID_V2)) {
2274271782Sglebius				if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
2275170589Syongari				nfe_discard_jrxbuf(sc, sc->jrxq.jcur);
2276170589Syongari				continue;
2277170589Syongari			}
2278170589Syongari
2279170589Syongari			if ((flags & NFE_RX_FIXME_V2) == NFE_RX_FIXME_V2) {
2280170589Syongari				flags &= ~NFE_RX_ERROR;
2281170589Syongari				len--;	/* fix buffer length */
2282170589Syongari			}
2283170589Syongari		}
2284170589Syongari
2285170589Syongari		if (flags & NFE_RX_ERROR) {
2286271782Sglebius			if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
2287170589Syongari			nfe_discard_jrxbuf(sc, sc->jrxq.jcur);
2288170589Syongari			continue;
2289164651Sobrien		}
2290159952Sobrien
2291159952Sobrien		m = data->m;
2292170589Syongari		if (nfe_jnewbuf(sc, sc->jrxq.jcur) != 0) {
2293271782Sglebius			if_inc_counter(ifp, IFCOUNTER_IQDROPS, 1);
2294170589Syongari			nfe_discard_jrxbuf(sc, sc->jrxq.jcur);
2295170589Syongari			continue;
2296170589Syongari		}
2297159952Sobrien
2298170589Syongari		if ((vtag & NFE_RX_VTAG) != 0 &&
2299268131Smarcel		    (if_getcapenable(ifp) & IFCAP_VLAN_HWTAGGING) != 0) {
2300170589Syongari			m->m_pkthdr.ether_vtag = vtag & 0xffff;
2301170589Syongari			m->m_flags |= M_VLANTAG;
2302170589Syongari		}
2303170589Syongari
2304159952Sobrien		m->m_pkthdr.len = m->m_len = len;
2305159952Sobrien		m->m_pkthdr.rcvif = ifp;
2306159952Sobrien
2307268131Smarcel		if ((if_getcapenable(ifp) & IFCAP_RXCSUM) != 0) {
2308170589Syongari			if ((flags & NFE_RX_IP_CSUMOK) != 0) {
2309170589Syongari				m->m_pkthdr.csum_flags |= CSUM_IP_CHECKED;
2310159967Sobrien				m->m_pkthdr.csum_flags |= CSUM_IP_VALID;
2311170589Syongari				if ((flags & NFE_RX_TCP_CSUMOK) != 0 ||
2312170589Syongari				    (flags & NFE_RX_UDP_CSUMOK) != 0) {
2313170589Syongari					m->m_pkthdr.csum_flags |=
2314170589Syongari					    CSUM_DATA_VALID | CSUM_PSEUDO_HDR;
2315170589Syongari					m->m_pkthdr.csum_data = 0xffff;
2316170589Syongari				}
2317159967Sobrien			}
2318159952Sobrien		}
2319159952Sobrien
2320271782Sglebius		if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1);
2321159952Sobrien
2322159967Sobrien		NFE_UNLOCK(sc);
2323268131Smarcel		if_input(ifp, m);
2324159967Sobrien		NFE_LOCK(sc);
2325193096Sattilio		rx_npkts++;
2326170589Syongari	}
2327159967Sobrien
2328170589Syongari	if (prog > 0)
2329170589Syongari		bus_dmamap_sync(sc->jrxq.jrx_desc_tag, sc->jrxq.jrx_desc_map,
2330170589Syongari		    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
2331159952Sobrien
2332193096Sattilio	if (rx_npktsp != NULL)
2333193096Sattilio		*rx_npktsp = rx_npkts;
2334170589Syongari	return (count > 0 ? 0 : EAGAIN);
2335159952Sobrien}
2336159952Sobrien
2337163503Sobrien
2338163503Sobrienstatic void
2339163503Sobriennfe_txeof(struct nfe_softc *sc)
2340159952Sobrien{
2341268131Smarcel	if_t ifp = sc->nfe_ifp;
2342159952Sobrien	struct nfe_desc32 *desc32;
2343159952Sobrien	struct nfe_desc64 *desc64;
2344159952Sobrien	struct nfe_tx_data *data = NULL;
2345170589Syongari	uint16_t flags;
2346170589Syongari	int cons, prog;
2347159952Sobrien
2348159967Sobrien	NFE_LOCK_ASSERT(sc);
2349159967Sobrien
2350170589Syongari	bus_dmamap_sync(sc->txq.tx_desc_tag, sc->txq.tx_desc_map,
2351170589Syongari	    BUS_DMASYNC_POSTREAD);
2352170589Syongari
2353170589Syongari	prog = 0;
2354170589Syongari	for (cons = sc->txq.next; cons != sc->txq.cur;
2355170589Syongari	    NFE_INC(cons, NFE_TX_RING_COUNT)) {
2356159967Sobrien		if (sc->nfe_flags & NFE_40BIT_ADDR) {
2357170589Syongari			desc64 = &sc->txq.desc64[cons];
2358170589Syongari			flags = le16toh(desc64->flags);
2359159952Sobrien		} else {
2360170589Syongari			desc32 = &sc->txq.desc32[cons];
2361170589Syongari			flags = le16toh(desc32->flags);
2362159952Sobrien		}
2363159952Sobrien
2364159952Sobrien		if (flags & NFE_TX_VALID)
2365159952Sobrien			break;
2366159952Sobrien
2367170589Syongari		prog++;
2368170589Syongari		sc->txq.queued--;
2369170589Syongari		data = &sc->txq.data[cons];
2370159952Sobrien
2371159967Sobrien		if ((sc->nfe_flags & (NFE_JUMBO_SUP | NFE_40BIT_ADDR)) == 0) {
2372170589Syongari			if ((flags & NFE_TX_LASTFRAG_V1) == 0)
2373170589Syongari				continue;
2374159952Sobrien			if ((flags & NFE_TX_ERROR_V1) != 0) {
2375170589Syongari				device_printf(sc->nfe_dev,
2376170589Syongari				    "tx v1 error 0x%4b\n", flags, NFE_V1_TXERR);
2377159967Sobrien
2378271782Sglebius				if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
2379159952Sobrien			} else
2380271782Sglebius				if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1);
2381159952Sobrien		} else {
2382170589Syongari			if ((flags & NFE_TX_LASTFRAG_V2) == 0)
2383170589Syongari				continue;
2384159952Sobrien			if ((flags & NFE_TX_ERROR_V2) != 0) {
2385170589Syongari				device_printf(sc->nfe_dev,
2386170589Syongari				    "tx v2 error 0x%4b\n", flags, NFE_V2_TXERR);
2387271782Sglebius				if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
2388159952Sobrien			} else
2389271782Sglebius				if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1);
2390159952Sobrien		}
2391159952Sobrien
2392159952Sobrien		/* last fragment of the mbuf chain transmitted */
2393170589Syongari		KASSERT(data->m != NULL, ("%s: freeing NULL mbuf!", __func__));
2394170589Syongari		bus_dmamap_sync(sc->txq.tx_data_tag, data->tx_data_map,
2395159967Sobrien		    BUS_DMASYNC_POSTWRITE);
2396170589Syongari		bus_dmamap_unload(sc->txq.tx_data_tag, data->tx_data_map);
2397159952Sobrien		m_freem(data->m);
2398159952Sobrien		data->m = NULL;
2399159952Sobrien	}
2400159952Sobrien
2401170589Syongari	if (prog > 0) {
2402170589Syongari		sc->nfe_force_tx = 0;
2403170589Syongari		sc->txq.next = cons;
2404268131Smarcel		if_setdrvflagbits(ifp, 0, IFF_DRV_OACTIVE);
2405170589Syongari		if (sc->txq.queued == 0)
2406170589Syongari			sc->nfe_watchdog_timer = 0;
2407159952Sobrien	}
2408159952Sobrien}
2409159952Sobrien
2410163503Sobrienstatic int
2411170589Syongarinfe_encap(struct nfe_softc *sc, struct mbuf **m_head)
2412159952Sobrien{
2413170589Syongari	struct nfe_desc32 *desc32 = NULL;
2414170589Syongari	struct nfe_desc64 *desc64 = NULL;
2415159952Sobrien	bus_dmamap_t map;
2416163503Sobrien	bus_dma_segment_t segs[NFE_MAX_SCATTER];
2417170589Syongari	int error, i, nsegs, prod, si;
2418254803Sandre	uint32_t tsosegsz;
2419170589Syongari	uint16_t cflags, flags;
2420170589Syongari	struct mbuf *m;
2421159952Sobrien
2422170589Syongari	prod = si = sc->txq.cur;
2423170589Syongari	map = sc->txq.data[prod].tx_data_map;
2424159952Sobrien
2425170589Syongari	error = bus_dmamap_load_mbuf_sg(sc->txq.tx_data_tag, map, *m_head, segs,
2426159967Sobrien	    &nsegs, BUS_DMA_NOWAIT);
2427170589Syongari	if (error == EFBIG) {
2428243857Sglebius		m = m_collapse(*m_head, M_NOWAIT, NFE_MAX_SCATTER);
2429170589Syongari		if (m == NULL) {
2430170589Syongari			m_freem(*m_head);
2431170589Syongari			*m_head = NULL;
2432170589Syongari			return (ENOBUFS);
2433170589Syongari		}
2434170589Syongari		*m_head = m;
2435170589Syongari		error = bus_dmamap_load_mbuf_sg(sc->txq.tx_data_tag, map,
2436170589Syongari		    *m_head, segs, &nsegs, BUS_DMA_NOWAIT);
2437170589Syongari		if (error != 0) {
2438170589Syongari			m_freem(*m_head);
2439170589Syongari			*m_head = NULL;
2440170589Syongari			return (ENOBUFS);
2441170589Syongari		}
2442170589Syongari	} else if (error != 0)
2443170589Syongari		return (error);
2444170589Syongari	if (nsegs == 0) {
2445170589Syongari		m_freem(*m_head);
2446170589Syongari		*m_head = NULL;
2447170589Syongari		return (EIO);
2448159952Sobrien	}
2449159952Sobrien
2450170589Syongari	if (sc->txq.queued + nsegs >= NFE_TX_RING_COUNT - 2) {
2451159967Sobrien		bus_dmamap_unload(sc->txq.tx_data_tag, map);
2452170589Syongari		return (ENOBUFS);
2453159952Sobrien	}
2454159952Sobrien
2455170589Syongari	m = *m_head;
2456170589Syongari	cflags = flags = 0;
2457254803Sandre	tsosegsz = 0;
2458206876Syongari	if ((m->m_pkthdr.csum_flags & CSUM_TSO) != 0) {
2459254803Sandre		tsosegsz = (uint32_t)m->m_pkthdr.tso_segsz <<
2460206876Syongari		    NFE_TX_TSO_SHIFT;
2461206876Syongari		cflags &= ~(NFE_TX_IP_CSUM | NFE_TX_TCP_UDP_CSUM);
2462206876Syongari		cflags |= NFE_TX_TSO;
2463206876Syongari	} else if ((m->m_pkthdr.csum_flags & NFE_CSUM_FEATURES) != 0) {
2464170589Syongari		if ((m->m_pkthdr.csum_flags & CSUM_IP) != 0)
2465170589Syongari			cflags |= NFE_TX_IP_CSUM;
2466170589Syongari		if ((m->m_pkthdr.csum_flags & CSUM_TCP) != 0)
2467170589Syongari			cflags |= NFE_TX_TCP_UDP_CSUM;
2468170589Syongari		if ((m->m_pkthdr.csum_flags & CSUM_UDP) != 0)
2469170589Syongari			cflags |= NFE_TX_TCP_UDP_CSUM;
2470164656Sobrien	}
2471159967Sobrien
2472159967Sobrien	for (i = 0; i < nsegs; i++) {
2473159967Sobrien		if (sc->nfe_flags & NFE_40BIT_ADDR) {
2474170589Syongari			desc64 = &sc->txq.desc64[prod];
2475170589Syongari			desc64->physaddr[0] =
2476170589Syongari			    htole32(NFE_ADDR_HI(segs[i].ds_addr));
2477170589Syongari			desc64->physaddr[1] =
2478170589Syongari			    htole32(NFE_ADDR_LO(segs[i].ds_addr));
2479170589Syongari			desc64->vtag = 0;
2480159967Sobrien			desc64->length = htole16(segs[i].ds_len - 1);
2481159952Sobrien			desc64->flags = htole16(flags);
2482159952Sobrien		} else {
2483170589Syongari			desc32 = &sc->txq.desc32[prod];
2484170589Syongari			desc32->physaddr =
2485170589Syongari			    htole32(NFE_ADDR_LO(segs[i].ds_addr));
2486159967Sobrien			desc32->length = htole16(segs[i].ds_len - 1);
2487159952Sobrien			desc32->flags = htole16(flags);
2488159952Sobrien		}
2489159952Sobrien
2490170589Syongari		/*
2491170589Syongari		 * Setting of the valid bit in the first descriptor is
2492170589Syongari		 * deferred until the whole chain is fully setup.
2493170589Syongari		 */
2494170589Syongari		flags |= NFE_TX_VALID;
2495163503Sobrien
2496159952Sobrien		sc->txq.queued++;
2497170589Syongari		NFE_INC(prod, NFE_TX_RING_COUNT);
2498159952Sobrien	}
2499159952Sobrien
2500170589Syongari	/*
2501170589Syongari	 * the whole mbuf chain has been DMA mapped, fix last/first descriptor.
2502170589Syongari	 * csum flags, vtag and TSO belong to the first fragment only.
2503170589Syongari	 */
2504159967Sobrien	if (sc->nfe_flags & NFE_40BIT_ADDR) {
2505170589Syongari		desc64->flags |= htole16(NFE_TX_LASTFRAG_V2);
2506170589Syongari		desc64 = &sc->txq.desc64[si];
2507170589Syongari		if ((m->m_flags & M_VLANTAG) != 0)
2508170589Syongari			desc64->vtag = htole32(NFE_TX_VTAG |
2509170589Syongari			    m->m_pkthdr.ether_vtag);
2510254803Sandre		if (tsosegsz != 0) {
2511170589Syongari			/*
2512170589Syongari			 * XXX
2513170589Syongari			 * The following indicates the descriptor element
2514170589Syongari			 * is a 32bit quantity.
2515170589Syongari			 */
2516254803Sandre			desc64->length |= htole16((uint16_t)tsosegsz);
2517254803Sandre			desc64->flags |= htole16(tsosegsz >> 16);
2518170589Syongari		}
2519170589Syongari		/*
2520170589Syongari		 * finally, set the valid/checksum/TSO bit in the first
2521170589Syongari		 * descriptor.
2522170589Syongari		 */
2523170589Syongari		desc64->flags |= htole16(NFE_TX_VALID | cflags);
2524159952Sobrien	} else {
2525159967Sobrien		if (sc->nfe_flags & NFE_JUMBO_SUP)
2526170589Syongari			desc32->flags |= htole16(NFE_TX_LASTFRAG_V2);
2527159952Sobrien		else
2528170589Syongari			desc32->flags |= htole16(NFE_TX_LASTFRAG_V1);
2529170589Syongari		desc32 = &sc->txq.desc32[si];
2530254803Sandre		if (tsosegsz != 0) {
2531170589Syongari			/*
2532170589Syongari			 * XXX
2533170589Syongari			 * The following indicates the descriptor element
2534170589Syongari			 * is a 32bit quantity.
2535170589Syongari			 */
2536254803Sandre			desc32->length |= htole16((uint16_t)tsosegsz);
2537254803Sandre			desc32->flags |= htole16(tsosegsz >> 16);
2538170589Syongari		}
2539170589Syongari		/*
2540170589Syongari		 * finally, set the valid/checksum/TSO bit in the first
2541170589Syongari		 * descriptor.
2542170589Syongari		 */
2543170589Syongari		desc32->flags |= htole16(NFE_TX_VALID | cflags);
2544159952Sobrien	}
2545159952Sobrien
2546170589Syongari	sc->txq.cur = prod;
2547170589Syongari	prod = (prod + NFE_TX_RING_COUNT - 1) % NFE_TX_RING_COUNT;
2548170589Syongari	sc->txq.data[si].tx_data_map = sc->txq.data[prod].tx_data_map;
2549170589Syongari	sc->txq.data[prod].tx_data_map = map;
2550170589Syongari	sc->txq.data[prod].m = m;
2551159952Sobrien
2552159967Sobrien	bus_dmamap_sync(sc->txq.tx_data_tag, map, BUS_DMASYNC_PREWRITE);
2553159952Sobrien
2554170589Syongari	return (0);
2555159952Sobrien}
2556159952Sobrien
2557159967Sobrien
2558163503Sobrienstatic void
2559163503Sobriennfe_setmulti(struct nfe_softc *sc)
2560159952Sobrien{
2561268131Smarcel	if_t ifp = sc->nfe_ifp;
2562268131Smarcel	int i, mc_count, mcnt;
2563170589Syongari	uint32_t filter;
2564170589Syongari	uint8_t addr[ETHER_ADDR_LEN], mask[ETHER_ADDR_LEN];
2565170589Syongari	uint8_t etherbroadcastaddr[ETHER_ADDR_LEN] = {
2566163503Sobrien		0xff, 0xff, 0xff, 0xff, 0xff, 0xff
2567163503Sobrien	};
2568268131Smarcel	uint8_t *mta;
2569159967Sobrien
2570159967Sobrien	NFE_LOCK_ASSERT(sc);
2571159967Sobrien
2572268131Smarcel	if ((if_getflags(ifp) & (IFF_ALLMULTI | IFF_PROMISC)) != 0) {
2573159967Sobrien		bzero(addr, ETHER_ADDR_LEN);
2574159967Sobrien		bzero(mask, ETHER_ADDR_LEN);
2575159967Sobrien		goto done;
2576159967Sobrien	}
2577159967Sobrien
2578159967Sobrien	bcopy(etherbroadcastaddr, addr, ETHER_ADDR_LEN);
2579159967Sobrien	bcopy(etherbroadcastaddr, mask, ETHER_ADDR_LEN);
2580159967Sobrien
2581268131Smarcel	mc_count = if_multiaddr_count(ifp, -1);
2582268131Smarcel	mta = malloc(sizeof(uint8_t) * ETHER_ADDR_LEN * mc_count, M_DEVBUF,
2583268131Smarcel	    M_NOWAIT);
2584159967Sobrien
2585268131Smarcel	/* Unable to get memory - process without filtering */
2586268131Smarcel	if (mta == NULL) {
2587268131Smarcel		device_printf(sc->nfe_dev, "nfe_setmulti: failed to allocate"
2588268131Smarcel		    "temp multicast buffer!\n");
2589159967Sobrien
2590268131Smarcel		bzero(addr, ETHER_ADDR_LEN);
2591268131Smarcel		bzero(mask, ETHER_ADDR_LEN);
2592268131Smarcel		goto done;
2593268131Smarcel	};
2594268131Smarcel
2595269479Smarcel	if_multiaddr_array(ifp, mta, &mcnt, mc_count);
2596268131Smarcel
2597268131Smarcel	for (i = 0; i < mcnt; i++) {
2598268131Smarcel		uint8_t *addrp;
2599269479Smarcel		int j;
2600268131Smarcel
2601268131Smarcel		addrp = mta + (i * ETHER_ADDR_LEN);
2602269479Smarcel		for (j = 0; j < ETHER_ADDR_LEN; j++) {
2603269479Smarcel			u_int8_t mcaddr = addrp[j];
2604269479Smarcel			addr[j] &= mcaddr;
2605269479Smarcel			mask[j] &= ~mcaddr;
2606159967Sobrien		}
2607159967Sobrien	}
2608159967Sobrien
2609269479Smarcel	free(mta, M_DEVBUF);
2610269479Smarcel
2611159967Sobrien	for (i = 0; i < ETHER_ADDR_LEN; i++) {
2612159967Sobrien		mask[i] |= addr[i];
2613159967Sobrien	}
2614159967Sobrien
2615159967Sobriendone:
2616159967Sobrien	addr[0] |= 0x01;	/* make sure multicast bit is set */
2617159967Sobrien
2618159967Sobrien	NFE_WRITE(sc, NFE_MULTIADDR_HI,
2619159967Sobrien	    addr[3] << 24 | addr[2] << 16 | addr[1] << 8 | addr[0]);
2620159967Sobrien	NFE_WRITE(sc, NFE_MULTIADDR_LO,
2621159967Sobrien	    addr[5] <<  8 | addr[4]);
2622159967Sobrien	NFE_WRITE(sc, NFE_MULTIMASK_HI,
2623159967Sobrien	    mask[3] << 24 | mask[2] << 16 | mask[1] << 8 | mask[0]);
2624159967Sobrien	NFE_WRITE(sc, NFE_MULTIMASK_LO,
2625159967Sobrien	    mask[5] <<  8 | mask[4]);
2626159967Sobrien
2627170589Syongari	filter = NFE_READ(sc, NFE_RXFILTER);
2628170589Syongari	filter &= NFE_PFF_RX_PAUSE;
2629170589Syongari	filter |= NFE_RXFILTER_MAGIC;
2630268131Smarcel	filter |= (if_getflags(ifp) & IFF_PROMISC) ? NFE_PFF_PROMISC : NFE_PFF_U2M;
2631159967Sobrien	NFE_WRITE(sc, NFE_RXFILTER, filter);
2632159967Sobrien}
2633159967Sobrien
2634163503Sobrien
2635163503Sobrienstatic void
2636268131Smarcelnfe_start(if_t ifp)
2637159967Sobrien{
2638268131Smarcel	struct nfe_softc *sc = if_getsoftc(ifp);
2639159967Sobrien
2640216925Sjhb	NFE_LOCK(sc);
2641216925Sjhb	nfe_start_locked(ifp);
2642216925Sjhb	NFE_UNLOCK(sc);
2643159967Sobrien}
2644159967Sobrien
2645163503Sobrienstatic void
2646268131Smarcelnfe_start_locked(if_t ifp)
2647159967Sobrien{
2648268131Smarcel	struct nfe_softc *sc = if_getsoftc(ifp);
2649163503Sobrien	struct mbuf *m0;
2650268131Smarcel	int enq = 0;
2651159952Sobrien
2652216925Sjhb	NFE_LOCK_ASSERT(sc);
2653170589Syongari
2654268131Smarcel	if ((if_getdrvflags(ifp) & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) !=
2655216925Sjhb	    IFF_DRV_RUNNING || sc->nfe_link == 0)
2656159967Sobrien		return;
2657159967Sobrien
2658268131Smarcel	while (!if_sendq_empty(ifp)) {
2659268131Smarcel		m0 = if_dequeue(ifp);
2660268131Smarcel
2661159952Sobrien		if (m0 == NULL)
2662159952Sobrien			break;
2663159952Sobrien
2664170589Syongari		if (nfe_encap(sc, &m0) != 0) {
2665170589Syongari			if (m0 == NULL)
2666170589Syongari				break;
2667268131Smarcel			if_sendq_prepend(ifp, m0);
2668268131Smarcel			if_setdrvflagbits(ifp, IFF_DRV_OACTIVE, 0);
2669159952Sobrien			break;
2670159952Sobrien		}
2671170589Syongari		enq++;
2672268131Smarcel		if_etherbpfmtap(ifp, m0);
2673159952Sobrien	}
2674159952Sobrien
2675170589Syongari	if (enq > 0) {
2676170589Syongari		bus_dmamap_sync(sc->txq.tx_desc_tag, sc->txq.tx_desc_map,
2677170589Syongari		    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
2678159952Sobrien
2679170589Syongari		/* kick Tx */
2680170589Syongari		NFE_WRITE(sc, NFE_RXTX_CTL, NFE_RXTX_KICKTX | sc->rxtxctl);
2681159952Sobrien
2682170589Syongari		/*
2683170589Syongari		 * Set a timeout in case the chip goes out to lunch.
2684170589Syongari		 */
2685170589Syongari		sc->nfe_watchdog_timer = 5;
2686170589Syongari	}
2687159952Sobrien}
2688159952Sobrien
2689163503Sobrien
2690163503Sobrienstatic void
2691268131Smarcelnfe_watchdog(if_t ifp)
2692159952Sobrien{
2693268131Smarcel	struct nfe_softc *sc = if_getsoftc(ifp);
2694159952Sobrien
2695170589Syongari	if (sc->nfe_watchdog_timer == 0 || --sc->nfe_watchdog_timer)
2696170589Syongari		return;
2697159952Sobrien
2698170589Syongari	/* Check if we've lost Tx completion interrupt. */
2699170589Syongari	nfe_txeof(sc);
2700170589Syongari	if (sc->txq.queued == 0) {
2701170589Syongari		if_printf(ifp, "watchdog timeout (missed Tx interrupts) "
2702170589Syongari		    "-- recovering\n");
2703268131Smarcel		if (!if_sendq_empty(ifp))
2704216925Sjhb			nfe_start_locked(ifp);
2705170589Syongari		return;
2706170589Syongari	}
2707170589Syongari	/* Check if we've lost start Tx command. */
2708170589Syongari	sc->nfe_force_tx++;
2709170589Syongari	if (sc->nfe_force_tx <= 3) {
2710170589Syongari		/*
2711170589Syongari		 * If this is the case for watchdog timeout, the following
2712170589Syongari		 * code should go to nfe_txeof().
2713170589Syongari		 */
2714170589Syongari		NFE_WRITE(sc, NFE_RXTX_CTL, NFE_RXTX_KICKTX | sc->rxtxctl);
2715170589Syongari		return;
2716170589Syongari	}
2717170589Syongari	sc->nfe_force_tx = 0;
2718170589Syongari
2719170589Syongari	if_printf(ifp, "watchdog timeout\n");
2720170589Syongari
2721268131Smarcel	if_setdrvflagbits(ifp, 0, IFF_DRV_RUNNING);
2722271782Sglebius	if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
2723170589Syongari	nfe_init_locked(sc);
2724159952Sobrien}
2725159952Sobrien
2726163503Sobrien
2727163503Sobrienstatic void
2728163503Sobriennfe_init(void *xsc)
2729159952Sobrien{
2730159967Sobrien	struct nfe_softc *sc = xsc;
2731159952Sobrien
2732159967Sobrien	NFE_LOCK(sc);
2733159967Sobrien	nfe_init_locked(sc);
2734159967Sobrien	NFE_UNLOCK(sc);
2735159967Sobrien}
2736159967Sobrien
2737163503Sobrien
2738163503Sobrienstatic void
2739163503Sobriennfe_init_locked(void *xsc)
2740159967Sobrien{
2741159967Sobrien	struct nfe_softc *sc = xsc;
2742268131Smarcel	if_t ifp = sc->nfe_ifp;
2743159967Sobrien	struct mii_data *mii;
2744170589Syongari	uint32_t val;
2745170589Syongari	int error;
2746159967Sobrien
2747159967Sobrien	NFE_LOCK_ASSERT(sc);
2748159967Sobrien
2749159967Sobrien	mii = device_get_softc(sc->nfe_miibus);
2750159967Sobrien
2751268131Smarcel	if (if_getdrvflags(ifp) & IFF_DRV_RUNNING)
2752159967Sobrien		return;
2753170589Syongari
2754170589Syongari	nfe_stop(ifp);
2755170589Syongari
2756268131Smarcel	sc->nfe_framesize = if_getmtu(ifp) + NFE_RX_HEADERS;
2757170589Syongari
2758170589Syongari	nfe_init_tx_ring(sc, &sc->txq);
2759170589Syongari	if (sc->nfe_framesize > (MCLBYTES - ETHER_HDR_LEN))
2760170589Syongari		error = nfe_init_jrx_ring(sc, &sc->jrxq);
2761170589Syongari	else
2762170589Syongari		error = nfe_init_rx_ring(sc, &sc->rxq);
2763170589Syongari	if (error != 0) {
2764170589Syongari		device_printf(sc->nfe_dev,
2765170589Syongari		    "initialization failed: no memory for rx buffers\n");
2766170589Syongari		nfe_stop(ifp);
2767170589Syongari		return;
2768159967Sobrien	}
2769159967Sobrien
2770170589Syongari	val = 0;
2771170589Syongari	if ((sc->nfe_flags & NFE_CORRECT_MACADDR) != 0)
2772170589Syongari		val |= NFE_MAC_ADDR_INORDER;
2773170589Syongari	NFE_WRITE(sc, NFE_TX_UNK, val);
2774159952Sobrien	NFE_WRITE(sc, NFE_STATUS, 0);
2775159952Sobrien
2776170589Syongari	if ((sc->nfe_flags & NFE_TX_FLOW_CTRL) != 0)
2777170589Syongari		NFE_WRITE(sc, NFE_TX_PAUSE_FRAME, NFE_TX_PAUSE_FRAME_DISABLE);
2778170589Syongari
2779159952Sobrien	sc->rxtxctl = NFE_RXTX_BIT2;
2780159967Sobrien	if (sc->nfe_flags & NFE_40BIT_ADDR)
2781159952Sobrien		sc->rxtxctl |= NFE_RXTX_V3MAGIC;
2782159967Sobrien	else if (sc->nfe_flags & NFE_JUMBO_SUP)
2783159952Sobrien		sc->rxtxctl |= NFE_RXTX_V2MAGIC;
2784164656Sobrien
2785268131Smarcel	if ((if_getcapenable(ifp) & IFCAP_RXCSUM) != 0)
2786159952Sobrien		sc->rxtxctl |= NFE_RXTX_RXCSUM;
2787268131Smarcel	if ((if_getcapenable(ifp) & IFCAP_VLAN_HWTAGGING) != 0)
2788170589Syongari		sc->rxtxctl |= NFE_RXTX_VTAG_INSERT | NFE_RXTX_VTAG_STRIP;
2789159967Sobrien
2790159952Sobrien	NFE_WRITE(sc, NFE_RXTX_CTL, NFE_RXTX_RESET | sc->rxtxctl);
2791159952Sobrien	DELAY(10);
2792159952Sobrien	NFE_WRITE(sc, NFE_RXTX_CTL, sc->rxtxctl);
2793159952Sobrien
2794268131Smarcel	if ((if_getcapenable(ifp) & IFCAP_VLAN_HWTAGGING) != 0)
2795159952Sobrien		NFE_WRITE(sc, NFE_VTAG_CTL, NFE_VTAG_ENABLE);
2796170589Syongari	else
2797170589Syongari		NFE_WRITE(sc, NFE_VTAG_CTL, 0);
2798159952Sobrien
2799159952Sobrien	NFE_WRITE(sc, NFE_SETUP_R6, 0);
2800159952Sobrien
2801159952Sobrien	/* set MAC address */
2802268131Smarcel	nfe_set_macaddr(sc, if_getlladdr(ifp));
2803159952Sobrien
2804159952Sobrien	/* tell MAC where rings are in memory */
2805170589Syongari	if (sc->nfe_framesize > MCLBYTES - ETHER_HDR_LEN) {
2806170589Syongari		NFE_WRITE(sc, NFE_RX_RING_ADDR_HI,
2807170589Syongari		    NFE_ADDR_HI(sc->jrxq.jphysaddr));
2808170589Syongari		NFE_WRITE(sc, NFE_RX_RING_ADDR_LO,
2809170589Syongari		    NFE_ADDR_LO(sc->jrxq.jphysaddr));
2810170589Syongari	} else {
2811170589Syongari		NFE_WRITE(sc, NFE_RX_RING_ADDR_HI,
2812170589Syongari		    NFE_ADDR_HI(sc->rxq.physaddr));
2813170589Syongari		NFE_WRITE(sc, NFE_RX_RING_ADDR_LO,
2814170589Syongari		    NFE_ADDR_LO(sc->rxq.physaddr));
2815170589Syongari	}
2816170589Syongari	NFE_WRITE(sc, NFE_TX_RING_ADDR_HI, NFE_ADDR_HI(sc->txq.physaddr));
2817170589Syongari	NFE_WRITE(sc, NFE_TX_RING_ADDR_LO, NFE_ADDR_LO(sc->txq.physaddr));
2818159952Sobrien
2819159952Sobrien	NFE_WRITE(sc, NFE_RING_SIZE,
2820159952Sobrien	    (NFE_RX_RING_COUNT - 1) << 16 |
2821159952Sobrien	    (NFE_TX_RING_COUNT - 1));
2822159952Sobrien
2823170589Syongari	NFE_WRITE(sc, NFE_RXBUFSZ, sc->nfe_framesize);
2824159952Sobrien
2825159952Sobrien	/* force MAC to wakeup */
2826170589Syongari	val = NFE_READ(sc, NFE_PWR_STATE);
2827170589Syongari	if ((val & NFE_PWR_WAKEUP) == 0)
2828170589Syongari		NFE_WRITE(sc, NFE_PWR_STATE, val | NFE_PWR_WAKEUP);
2829159952Sobrien	DELAY(10);
2830170589Syongari	val = NFE_READ(sc, NFE_PWR_STATE);
2831170589Syongari	NFE_WRITE(sc, NFE_PWR_STATE, val | NFE_PWR_VALID);
2832159952Sobrien
2833159952Sobrien#if 1
2834159952Sobrien	/* configure interrupts coalescing/mitigation */
2835159952Sobrien	NFE_WRITE(sc, NFE_IMTIMER, NFE_IM_DEFAULT);
2836159952Sobrien#else
2837159952Sobrien	/* no interrupt mitigation: one interrupt per packet */
2838159952Sobrien	NFE_WRITE(sc, NFE_IMTIMER, 970);
2839159952Sobrien#endif
2840159952Sobrien
2841170589Syongari	NFE_WRITE(sc, NFE_SETUP_R1, NFE_R1_MAGIC_10_100);
2842159952Sobrien	NFE_WRITE(sc, NFE_SETUP_R2, NFE_R2_MAGIC);
2843159952Sobrien	NFE_WRITE(sc, NFE_SETUP_R6, NFE_R6_MAGIC);
2844159952Sobrien
2845159952Sobrien	/* update MAC knowledge of PHY; generates a NFE_IRQ_LINK interrupt */
2846159952Sobrien	NFE_WRITE(sc, NFE_STATUS, sc->mii_phyaddr << 24 | NFE_STATUS_MAGIC);
2847159952Sobrien
2848159952Sobrien	NFE_WRITE(sc, NFE_SETUP_R4, NFE_R4_MAGIC);
2849215132Syongari	/* Disable WOL. */
2850215132Syongari	NFE_WRITE(sc, NFE_WOL_CTL, 0);
2851159952Sobrien
2852159952Sobrien	sc->rxtxctl &= ~NFE_RXTX_BIT2;
2853159952Sobrien	NFE_WRITE(sc, NFE_RXTX_CTL, sc->rxtxctl);
2854159952Sobrien	DELAY(10);
2855159952Sobrien	NFE_WRITE(sc, NFE_RXTX_CTL, NFE_RXTX_BIT1 | sc->rxtxctl);
2856159952Sobrien
2857159952Sobrien	/* set Rx filter */
2858159952Sobrien	nfe_setmulti(sc);
2859159952Sobrien
2860159952Sobrien	/* enable Rx */
2861159952Sobrien	NFE_WRITE(sc, NFE_RX_CTL, NFE_RX_START);
2862159952Sobrien
2863159952Sobrien	/* enable Tx */
2864159952Sobrien	NFE_WRITE(sc, NFE_TX_CTL, NFE_TX_START);
2865159952Sobrien
2866159952Sobrien	NFE_WRITE(sc, NFE_PHY_STATUS, 0xf);
2867159952Sobrien
2868183561Syongari	/* Clear hardware stats. */
2869183561Syongari	nfe_stats_clear(sc);
2870183561Syongari
2871159967Sobrien#ifdef DEVICE_POLLING
2872268131Smarcel	if (if_getcapenable(ifp) & IFCAP_POLLING)
2873170589Syongari		nfe_disable_intr(sc);
2874159967Sobrien	else
2875159967Sobrien#endif
2876170589Syongari	nfe_set_intr(sc);
2877170589Syongari	nfe_enable_intr(sc); /* enable interrupts */
2878159952Sobrien
2879268131Smarcel	if_setdrvflagbits(ifp, IFF_DRV_RUNNING, 0);
2880268131Smarcel	if_setdrvflagbits(ifp, 0, IFF_DRV_OACTIVE);
2881159952Sobrien
2882159967Sobrien	sc->nfe_link = 0;
2883170589Syongari	mii_mediachg(mii);
2884159952Sobrien
2885170589Syongari	callout_reset(&sc->nfe_stat_ch, hz, nfe_tick, sc);
2886159952Sobrien}
2887159952Sobrien
2888163503Sobrien
2889163503Sobrienstatic void
2890268131Smarcelnfe_stop(if_t ifp)
2891159952Sobrien{
2892268131Smarcel	struct nfe_softc *sc = if_getsoftc(ifp);
2893170589Syongari	struct nfe_rx_ring *rx_ring;
2894170589Syongari	struct nfe_jrx_ring *jrx_ring;
2895170589Syongari	struct nfe_tx_ring *tx_ring;
2896170589Syongari	struct nfe_rx_data *rdata;
2897170589Syongari	struct nfe_tx_data *tdata;
2898170589Syongari	int i;
2899159952Sobrien
2900159967Sobrien	NFE_LOCK_ASSERT(sc);
2901159952Sobrien
2902170589Syongari	sc->nfe_watchdog_timer = 0;
2903268131Smarcel	if_setdrvflagbits(ifp, 0, (IFF_DRV_RUNNING | IFF_DRV_OACTIVE));
2904159952Sobrien
2905159967Sobrien	callout_stop(&sc->nfe_stat_ch);
2906159967Sobrien
2907159952Sobrien	/* abort Tx */
2908159952Sobrien	NFE_WRITE(sc, NFE_TX_CTL, 0);
2909159952Sobrien
2910159952Sobrien	/* disable Rx */
2911159952Sobrien	NFE_WRITE(sc, NFE_RX_CTL, 0);
2912159952Sobrien
2913159952Sobrien	/* disable interrupts */
2914170589Syongari	nfe_disable_intr(sc);
2915159952Sobrien
2916159967Sobrien	sc->nfe_link = 0;
2917159967Sobrien
2918170589Syongari	/* free Rx and Tx mbufs still in the queues. */
2919170589Syongari	rx_ring = &sc->rxq;
2920170589Syongari	for (i = 0; i < NFE_RX_RING_COUNT; i++) {
2921170589Syongari		rdata = &rx_ring->data[i];
2922170589Syongari		if (rdata->m != NULL) {
2923170589Syongari			bus_dmamap_sync(rx_ring->rx_data_tag,
2924170589Syongari			    rdata->rx_data_map, BUS_DMASYNC_POSTREAD);
2925170589Syongari			bus_dmamap_unload(rx_ring->rx_data_tag,
2926170589Syongari			    rdata->rx_data_map);
2927170589Syongari			m_freem(rdata->m);
2928170589Syongari			rdata->m = NULL;
2929170589Syongari		}
2930170589Syongari	}
2931159952Sobrien
2932170589Syongari	if ((sc->nfe_flags & NFE_JUMBO_SUP) != 0) {
2933170589Syongari		jrx_ring = &sc->jrxq;
2934170589Syongari		for (i = 0; i < NFE_JUMBO_RX_RING_COUNT; i++) {
2935170589Syongari			rdata = &jrx_ring->jdata[i];
2936170589Syongari			if (rdata->m != NULL) {
2937170589Syongari				bus_dmamap_sync(jrx_ring->jrx_data_tag,
2938170589Syongari				    rdata->rx_data_map, BUS_DMASYNC_POSTREAD);
2939170589Syongari				bus_dmamap_unload(jrx_ring->jrx_data_tag,
2940170589Syongari				    rdata->rx_data_map);
2941170589Syongari				m_freem(rdata->m);
2942170589Syongari				rdata->m = NULL;
2943170589Syongari			}
2944170589Syongari		}
2945170589Syongari	}
2946170589Syongari
2947170589Syongari	tx_ring = &sc->txq;
2948170589Syongari	for (i = 0; i < NFE_RX_RING_COUNT; i++) {
2949170589Syongari		tdata = &tx_ring->data[i];
2950170589Syongari		if (tdata->m != NULL) {
2951170589Syongari			bus_dmamap_sync(tx_ring->tx_data_tag,
2952170589Syongari			    tdata->tx_data_map, BUS_DMASYNC_POSTWRITE);
2953170589Syongari			bus_dmamap_unload(tx_ring->tx_data_tag,
2954170589Syongari			    tdata->tx_data_map);
2955170589Syongari			m_freem(tdata->m);
2956170589Syongari			tdata->m = NULL;
2957170589Syongari		}
2958170589Syongari	}
2959183561Syongari	/* Update hardware stats. */
2960183561Syongari	nfe_stats_update(sc);
2961159952Sobrien}
2962159952Sobrien
2963163503Sobrien
2964163503Sobrienstatic int
2965268131Smarcelnfe_ifmedia_upd(if_t ifp)
2966159952Sobrien{
2967268131Smarcel	struct nfe_softc *sc = if_getsoftc(ifp);
2968170589Syongari	struct mii_data *mii;
2969159952Sobrien
2970159967Sobrien	NFE_LOCK(sc);
2971159967Sobrien	mii = device_get_softc(sc->nfe_miibus);
2972159967Sobrien	mii_mediachg(mii);
2973170589Syongari	NFE_UNLOCK(sc);
2974159967Sobrien
2975159967Sobrien	return (0);
2976159952Sobrien}
2977159952Sobrien
2978163503Sobrien
2979163503Sobrienstatic void
2980268131Smarcelnfe_ifmedia_sts(if_t ifp, struct ifmediareq *ifmr)
2981159952Sobrien{
2982163503Sobrien	struct nfe_softc *sc;
2983163503Sobrien	struct mii_data *mii;
2984159952Sobrien
2985268131Smarcel	sc = if_getsoftc(ifp);
2986159952Sobrien
2987159967Sobrien	NFE_LOCK(sc);
2988159967Sobrien	mii = device_get_softc(sc->nfe_miibus);
2989159967Sobrien	mii_pollstat(mii);
2990159952Sobrien
2991159967Sobrien	ifmr->ifm_active = mii->mii_media_active;
2992159967Sobrien	ifmr->ifm_status = mii->mii_media_status;
2993226478Syongari	NFE_UNLOCK(sc);
2994159952Sobrien}
2995159952Sobrien
2996163503Sobrien
2997170589Syongarivoid
2998159967Sobriennfe_tick(void *xsc)
2999159952Sobrien{
3000159967Sobrien	struct nfe_softc *sc;
3001163503Sobrien	struct mii_data *mii;
3002268131Smarcel	if_t ifp;
3003159952Sobrien
3004170589Syongari	sc = (struct nfe_softc *)xsc;
3005159952Sobrien
3006163503Sobrien	NFE_LOCK_ASSERT(sc);
3007159952Sobrien
3008159967Sobrien	ifp = sc->nfe_ifp;
3009159952Sobrien
3010159967Sobrien	mii = device_get_softc(sc->nfe_miibus);
3011159967Sobrien	mii_tick(mii);
3012183561Syongari	nfe_stats_update(sc);
3013170589Syongari	nfe_watchdog(ifp);
3014159967Sobrien	callout_reset(&sc->nfe_stat_ch, hz, nfe_tick, sc);
3015159952Sobrien}
3016159952Sobrien
3017159952Sobrien
3018173839Syongaristatic int
3019163503Sobriennfe_shutdown(device_t dev)
3020159952Sobrien{
3021159952Sobrien
3022215132Syongari	return (nfe_suspend(dev));
3023159952Sobrien}
3024159952Sobrien
3025159952Sobrien
3026163503Sobrienstatic void
3027170589Syongarinfe_get_macaddr(struct nfe_softc *sc, uint8_t *addr)
3028159952Sobrien{
3029170589Syongari	uint32_t val;
3030159952Sobrien
3031170589Syongari	if ((sc->nfe_flags & NFE_CORRECT_MACADDR) == 0) {
3032170589Syongari		val = NFE_READ(sc, NFE_MACADDR_LO);
3033170589Syongari		addr[0] = (val >> 8) & 0xff;
3034170589Syongari		addr[1] = (val & 0xff);
3035159952Sobrien
3036170589Syongari		val = NFE_READ(sc, NFE_MACADDR_HI);
3037170589Syongari		addr[2] = (val >> 24) & 0xff;
3038170589Syongari		addr[3] = (val >> 16) & 0xff;
3039170589Syongari		addr[4] = (val >>  8) & 0xff;
3040170589Syongari		addr[5] = (val & 0xff);
3041170589Syongari	} else {
3042170589Syongari		val = NFE_READ(sc, NFE_MACADDR_LO);
3043170589Syongari		addr[5] = (val >> 8) & 0xff;
3044170589Syongari		addr[4] = (val & 0xff);
3045170589Syongari
3046170589Syongari		val = NFE_READ(sc, NFE_MACADDR_HI);
3047170589Syongari		addr[3] = (val >> 24) & 0xff;
3048170589Syongari		addr[2] = (val >> 16) & 0xff;
3049170589Syongari		addr[1] = (val >>  8) & 0xff;
3050170589Syongari		addr[0] = (val & 0xff);
3051170589Syongari	}
3052159952Sobrien}
3053159952Sobrien
3054163503Sobrien
3055163503Sobrienstatic void
3056170589Syongarinfe_set_macaddr(struct nfe_softc *sc, uint8_t *addr)
3057159952Sobrien{
3058159967Sobrien
3059159967Sobrien	NFE_WRITE(sc, NFE_MACADDR_LO, addr[5] <<  8 | addr[4]);
3060159967Sobrien	NFE_WRITE(sc, NFE_MACADDR_HI, addr[3] << 24 | addr[2] << 16 |
3061159967Sobrien	    addr[1] << 8 | addr[0]);
3062159952Sobrien}
3063159952Sobrien
3064163503Sobrien
3065159967Sobrien/*
3066159967Sobrien * Map a single buffer address.
3067159967Sobrien */
3068159967Sobrien
3069159967Sobrienstatic void
3070170589Syongarinfe_dma_map_segs(void *arg, bus_dma_segment_t *segs, int nseg, int error)
3071159952Sobrien{
3072170589Syongari	struct nfe_dmamap_arg *ctx;
3073159952Sobrien
3074170589Syongari	if (error != 0)
3075159967Sobrien		return;
3076159952Sobrien
3077159967Sobrien	KASSERT(nseg == 1, ("too many DMA segments, %d should be 1", nseg));
3078159967Sobrien
3079170589Syongari	ctx = (struct nfe_dmamap_arg *)arg;
3080170589Syongari	ctx->nfe_busaddr = segs[0].ds_addr;
3081170589Syongari}
3082159967Sobrien
3083170589Syongari
3084170589Syongaristatic int
3085170589Syongarisysctl_int_range(SYSCTL_HANDLER_ARGS, int low, int high)
3086170589Syongari{
3087170589Syongari	int error, value;
3088170589Syongari
3089170589Syongari	if (!arg1)
3090170589Syongari		return (EINVAL);
3091170589Syongari	value = *(int *)arg1;
3092170589Syongari	error = sysctl_handle_int(oidp, &value, 0, req);
3093170589Syongari	if (error || !req->newptr)
3094170589Syongari		return (error);
3095170589Syongari	if (value < low || value > high)
3096170589Syongari		return (EINVAL);
3097170589Syongari	*(int *)arg1 = value;
3098170589Syongari
3099170589Syongari	return (0);
3100159952Sobrien}
3101170589Syongari
3102170589Syongari
3103170589Syongaristatic int
3104170589Syongarisysctl_hw_nfe_proc_limit(SYSCTL_HANDLER_ARGS)
3105170589Syongari{
3106170589Syongari
3107170589Syongari	return (sysctl_int_range(oidp, arg1, arg2, req, NFE_PROC_MIN,
3108170589Syongari	    NFE_PROC_MAX));
3109170589Syongari}
3110183561Syongari
3111183561Syongari
3112183561Syongari#define	NFE_SYSCTL_STAT_ADD32(c, h, n, p, d)	\
3113183561Syongari	    SYSCTL_ADD_UINT(c, h, OID_AUTO, n, CTLFLAG_RD, p, 0, d)
3114183561Syongari#define	NFE_SYSCTL_STAT_ADD64(c, h, n, p, d)	\
3115217323Smdf	    SYSCTL_ADD_UQUAD(c, h, OID_AUTO, n, CTLFLAG_RD, p, d)
3116183561Syongari
3117183561Syongaristatic void
3118183561Syongarinfe_sysctl_node(struct nfe_softc *sc)
3119183561Syongari{
3120183561Syongari	struct sysctl_ctx_list *ctx;
3121183561Syongari	struct sysctl_oid_list *child, *parent;
3122183561Syongari	struct sysctl_oid *tree;
3123183561Syongari	struct nfe_hw_stats *stats;
3124183561Syongari	int error;
3125183561Syongari
3126183561Syongari	stats = &sc->nfe_stats;
3127183561Syongari	ctx = device_get_sysctl_ctx(sc->nfe_dev);
3128183561Syongari	child = SYSCTL_CHILDREN(device_get_sysctl_tree(sc->nfe_dev));
3129183561Syongari	SYSCTL_ADD_PROC(ctx, child,
3130183561Syongari	    OID_AUTO, "process_limit", CTLTYPE_INT | CTLFLAG_RW,
3131183561Syongari	    &sc->nfe_process_limit, 0, sysctl_hw_nfe_proc_limit, "I",
3132183561Syongari	    "max number of Rx events to process");
3133183561Syongari
3134183561Syongari	sc->nfe_process_limit = NFE_PROC_DEFAULT;
3135183561Syongari	error = resource_int_value(device_get_name(sc->nfe_dev),
3136183561Syongari	    device_get_unit(sc->nfe_dev), "process_limit",
3137183561Syongari	    &sc->nfe_process_limit);
3138183561Syongari	if (error == 0) {
3139183561Syongari		if (sc->nfe_process_limit < NFE_PROC_MIN ||
3140183561Syongari		    sc->nfe_process_limit > NFE_PROC_MAX) {
3141183561Syongari			device_printf(sc->nfe_dev,
3142183561Syongari			    "process_limit value out of range; "
3143183561Syongari			    "using default: %d\n", NFE_PROC_DEFAULT);
3144183561Syongari			sc->nfe_process_limit = NFE_PROC_DEFAULT;
3145183561Syongari		}
3146183561Syongari	}
3147183561Syongari
3148183561Syongari	if ((sc->nfe_flags & (NFE_MIB_V1 | NFE_MIB_V2 | NFE_MIB_V3)) == 0)
3149183561Syongari		return;
3150183561Syongari
3151183561Syongari	tree = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "stats", CTLFLAG_RD,
3152183561Syongari	    NULL, "NFE statistics");
3153183561Syongari	parent = SYSCTL_CHILDREN(tree);
3154183561Syongari
3155183561Syongari	/* Rx statistics. */
3156183561Syongari	tree = SYSCTL_ADD_NODE(ctx, parent, OID_AUTO, "rx", CTLFLAG_RD,
3157183561Syongari	    NULL, "Rx MAC statistics");
3158183561Syongari	child = SYSCTL_CHILDREN(tree);
3159183561Syongari
3160183561Syongari	NFE_SYSCTL_STAT_ADD32(ctx, child, "frame_errors",
3161183561Syongari	    &stats->rx_frame_errors, "Framing Errors");
3162183561Syongari	NFE_SYSCTL_STAT_ADD32(ctx, child, "extra_bytes",
3163183561Syongari	    &stats->rx_extra_bytes, "Extra Bytes");
3164183561Syongari	NFE_SYSCTL_STAT_ADD32(ctx, child, "late_cols",
3165183561Syongari	    &stats->rx_late_cols, "Late Collisions");
3166183561Syongari	NFE_SYSCTL_STAT_ADD32(ctx, child, "runts",
3167183561Syongari	    &stats->rx_runts, "Runts");
3168183561Syongari	NFE_SYSCTL_STAT_ADD32(ctx, child, "jumbos",
3169183561Syongari	    &stats->rx_jumbos, "Jumbos");
3170183561Syongari	NFE_SYSCTL_STAT_ADD32(ctx, child, "fifo_overuns",
3171183561Syongari	    &stats->rx_fifo_overuns, "FIFO Overruns");
3172183561Syongari	NFE_SYSCTL_STAT_ADD32(ctx, child, "crc_errors",
3173183561Syongari	    &stats->rx_crc_errors, "CRC Errors");
3174183561Syongari	NFE_SYSCTL_STAT_ADD32(ctx, child, "fae",
3175183561Syongari	    &stats->rx_fae, "Frame Alignment Errors");
3176183561Syongari	NFE_SYSCTL_STAT_ADD32(ctx, child, "len_errors",
3177183561Syongari	    &stats->rx_len_errors, "Length Errors");
3178183561Syongari	NFE_SYSCTL_STAT_ADD32(ctx, child, "unicast",
3179183561Syongari	    &stats->rx_unicast, "Unicast Frames");
3180183561Syongari	NFE_SYSCTL_STAT_ADD32(ctx, child, "multicast",
3181183561Syongari	    &stats->rx_multicast, "Multicast Frames");
3182186346Syongari	NFE_SYSCTL_STAT_ADD32(ctx, child, "broadcast",
3183183561Syongari	    &stats->rx_broadcast, "Broadcast Frames");
3184183561Syongari	if ((sc->nfe_flags & NFE_MIB_V2) != 0) {
3185183561Syongari		NFE_SYSCTL_STAT_ADD64(ctx, child, "octets",
3186183561Syongari		    &stats->rx_octets, "Octets");
3187183561Syongari		NFE_SYSCTL_STAT_ADD32(ctx, child, "pause",
3188183561Syongari		    &stats->rx_pause, "Pause frames");
3189183561Syongari		NFE_SYSCTL_STAT_ADD32(ctx, child, "drops",
3190183561Syongari		    &stats->rx_drops, "Drop frames");
3191183561Syongari	}
3192183561Syongari
3193183561Syongari	/* Tx statistics. */
3194183561Syongari	tree = SYSCTL_ADD_NODE(ctx, parent, OID_AUTO, "tx", CTLFLAG_RD,
3195183561Syongari	    NULL, "Tx MAC statistics");
3196183561Syongari	child = SYSCTL_CHILDREN(tree);
3197183561Syongari	NFE_SYSCTL_STAT_ADD64(ctx, child, "octets",
3198183561Syongari	    &stats->tx_octets, "Octets");
3199183561Syongari	NFE_SYSCTL_STAT_ADD32(ctx, child, "zero_rexmits",
3200183561Syongari	    &stats->tx_zero_rexmits, "Zero Retransmits");
3201183561Syongari	NFE_SYSCTL_STAT_ADD32(ctx, child, "one_rexmits",
3202183561Syongari	    &stats->tx_one_rexmits, "One Retransmits");
3203183561Syongari	NFE_SYSCTL_STAT_ADD32(ctx, child, "multi_rexmits",
3204183561Syongari	    &stats->tx_multi_rexmits, "Multiple Retransmits");
3205183561Syongari	NFE_SYSCTL_STAT_ADD32(ctx, child, "late_cols",
3206183561Syongari	    &stats->tx_late_cols, "Late Collisions");
3207183561Syongari	NFE_SYSCTL_STAT_ADD32(ctx, child, "fifo_underuns",
3208183561Syongari	    &stats->tx_fifo_underuns, "FIFO Underruns");
3209183561Syongari	NFE_SYSCTL_STAT_ADD32(ctx, child, "carrier_losts",
3210183561Syongari	    &stats->tx_carrier_losts, "Carrier Losts");
3211183561Syongari	NFE_SYSCTL_STAT_ADD32(ctx, child, "excess_deferrals",
3212183561Syongari	    &stats->tx_excess_deferals, "Excess Deferrals");
3213183561Syongari	NFE_SYSCTL_STAT_ADD32(ctx, child, "retry_errors",
3214183561Syongari	    &stats->tx_retry_errors, "Retry Errors");
3215183561Syongari	if ((sc->nfe_flags & NFE_MIB_V2) != 0) {
3216183561Syongari		NFE_SYSCTL_STAT_ADD32(ctx, child, "deferrals",
3217183561Syongari		    &stats->tx_deferals, "Deferrals");
3218183561Syongari		NFE_SYSCTL_STAT_ADD32(ctx, child, "frames",
3219183561Syongari		    &stats->tx_frames, "Frames");
3220183561Syongari		NFE_SYSCTL_STAT_ADD32(ctx, child, "pause",
3221183561Syongari		    &stats->tx_pause, "Pause Frames");
3222183561Syongari	}
3223183561Syongari	if ((sc->nfe_flags & NFE_MIB_V3) != 0) {
3224183561Syongari		NFE_SYSCTL_STAT_ADD32(ctx, child, "unicast",
3225183561Syongari		    &stats->tx_deferals, "Unicast Frames");
3226183561Syongari		NFE_SYSCTL_STAT_ADD32(ctx, child, "multicast",
3227183561Syongari		    &stats->tx_frames, "Multicast Frames");
3228183561Syongari		NFE_SYSCTL_STAT_ADD32(ctx, child, "broadcast",
3229183561Syongari		    &stats->tx_pause, "Broadcast Frames");
3230183561Syongari	}
3231183561Syongari}
3232183561Syongari
3233183561Syongari#undef NFE_SYSCTL_STAT_ADD32
3234183561Syongari#undef NFE_SYSCTL_STAT_ADD64
3235183561Syongari
3236183561Syongaristatic void
3237183561Syongarinfe_stats_clear(struct nfe_softc *sc)
3238183561Syongari{
3239183561Syongari	int i, mib_cnt;
3240183561Syongari
3241183561Syongari	if ((sc->nfe_flags & NFE_MIB_V1) != 0)
3242183561Syongari		mib_cnt = NFE_NUM_MIB_STATV1;
3243183561Syongari	else if ((sc->nfe_flags & (NFE_MIB_V2 | NFE_MIB_V3)) != 0)
3244183561Syongari		mib_cnt = NFE_NUM_MIB_STATV2;
3245183561Syongari	else
3246183561Syongari		return;
3247183561Syongari
3248256038Syongari	for (i = 0; i < mib_cnt; i++)
3249256038Syongari		NFE_READ(sc, NFE_TX_OCTET + i * sizeof(uint32_t));
3250183561Syongari
3251183561Syongari	if ((sc->nfe_flags & NFE_MIB_V3) != 0) {
3252183561Syongari		NFE_READ(sc, NFE_TX_UNICAST);
3253183561Syongari		NFE_READ(sc, NFE_TX_MULTICAST);
3254183561Syongari		NFE_READ(sc, NFE_TX_BROADCAST);
3255183561Syongari	}
3256183561Syongari}
3257183561Syongari
3258183561Syongaristatic void
3259183561Syongarinfe_stats_update(struct nfe_softc *sc)
3260183561Syongari{
3261183561Syongari	struct nfe_hw_stats *stats;
3262183561Syongari
3263183561Syongari	NFE_LOCK_ASSERT(sc);
3264183561Syongari
3265183561Syongari	if ((sc->nfe_flags & (NFE_MIB_V1 | NFE_MIB_V2 | NFE_MIB_V3)) == 0)
3266183561Syongari		return;
3267183561Syongari
3268183561Syongari	stats = &sc->nfe_stats;
3269183561Syongari	stats->tx_octets += NFE_READ(sc, NFE_TX_OCTET);
3270183561Syongari	stats->tx_zero_rexmits += NFE_READ(sc, NFE_TX_ZERO_REXMIT);
3271183561Syongari	stats->tx_one_rexmits += NFE_READ(sc, NFE_TX_ONE_REXMIT);
3272183561Syongari	stats->tx_multi_rexmits += NFE_READ(sc, NFE_TX_MULTI_REXMIT);
3273183561Syongari	stats->tx_late_cols += NFE_READ(sc, NFE_TX_LATE_COL);
3274183561Syongari	stats->tx_fifo_underuns += NFE_READ(sc, NFE_TX_FIFO_UNDERUN);
3275183561Syongari	stats->tx_carrier_losts += NFE_READ(sc, NFE_TX_CARRIER_LOST);
3276183561Syongari	stats->tx_excess_deferals += NFE_READ(sc, NFE_TX_EXCESS_DEFERRAL);
3277183561Syongari	stats->tx_retry_errors += NFE_READ(sc, NFE_TX_RETRY_ERROR);
3278183561Syongari	stats->rx_frame_errors += NFE_READ(sc, NFE_RX_FRAME_ERROR);
3279183561Syongari	stats->rx_extra_bytes += NFE_READ(sc, NFE_RX_EXTRA_BYTES);
3280183561Syongari	stats->rx_late_cols += NFE_READ(sc, NFE_RX_LATE_COL);
3281183561Syongari	stats->rx_runts += NFE_READ(sc, NFE_RX_RUNT);
3282183561Syongari	stats->rx_jumbos += NFE_READ(sc, NFE_RX_JUMBO);
3283183561Syongari	stats->rx_fifo_overuns += NFE_READ(sc, NFE_RX_FIFO_OVERUN);
3284183561Syongari	stats->rx_crc_errors += NFE_READ(sc, NFE_RX_CRC_ERROR);
3285183561Syongari	stats->rx_fae += NFE_READ(sc, NFE_RX_FAE);
3286183561Syongari	stats->rx_len_errors += NFE_READ(sc, NFE_RX_LEN_ERROR);
3287183561Syongari	stats->rx_unicast += NFE_READ(sc, NFE_RX_UNICAST);
3288183561Syongari	stats->rx_multicast += NFE_READ(sc, NFE_RX_MULTICAST);
3289183561Syongari	stats->rx_broadcast += NFE_READ(sc, NFE_RX_BROADCAST);
3290183561Syongari
3291183561Syongari	if ((sc->nfe_flags & NFE_MIB_V2) != 0) {
3292183561Syongari		stats->tx_deferals += NFE_READ(sc, NFE_TX_DEFERAL);
3293183561Syongari		stats->tx_frames += NFE_READ(sc, NFE_TX_FRAME);
3294183561Syongari		stats->rx_octets += NFE_READ(sc, NFE_RX_OCTET);
3295183561Syongari		stats->tx_pause += NFE_READ(sc, NFE_TX_PAUSE);
3296183561Syongari		stats->rx_pause += NFE_READ(sc, NFE_RX_PAUSE);
3297183561Syongari		stats->rx_drops += NFE_READ(sc, NFE_RX_DROP);
3298183561Syongari	}
3299183561Syongari
3300183561Syongari	if ((sc->nfe_flags & NFE_MIB_V3) != 0) {
3301183561Syongari		stats->tx_unicast += NFE_READ(sc, NFE_TX_UNICAST);
3302183561Syongari		stats->tx_multicast += NFE_READ(sc, NFE_TX_MULTICAST);
3303255648Sdelphij		stats->tx_broadcast += NFE_READ(sc, NFE_TX_BROADCAST);
3304183561Syongari	}
3305183561Syongari}
3306215132Syongari
3307215132Syongari
3308215132Syongaristatic void
3309215132Syongarinfe_set_linkspeed(struct nfe_softc *sc)
3310215132Syongari{
3311215132Syongari	struct mii_softc *miisc;
3312215132Syongari	struct mii_data *mii;
3313215132Syongari	int aneg, i, phyno;
3314215132Syongari
3315215132Syongari	NFE_LOCK_ASSERT(sc);
3316215132Syongari
3317215132Syongari	mii = device_get_softc(sc->nfe_miibus);
3318215132Syongari	mii_pollstat(mii);
3319215132Syongari	aneg = 0;
3320215132Syongari	if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) ==
3321215132Syongari	    (IFM_ACTIVE | IFM_AVALID)) {
3322215132Syongari		switch IFM_SUBTYPE(mii->mii_media_active) {
3323215132Syongari		case IFM_10_T:
3324215132Syongari		case IFM_100_TX:
3325215132Syongari			return;
3326215132Syongari		case IFM_1000_T:
3327215132Syongari			aneg++;
3328215132Syongari			break;
3329215132Syongari		default:
3330215132Syongari			break;
3331215132Syongari		}
3332215132Syongari	}
3333221407Smarius	miisc = LIST_FIRST(&mii->mii_phys);
3334221407Smarius	phyno = miisc->mii_phy;
3335221407Smarius	LIST_FOREACH(miisc, &mii->mii_phys, mii_list)
3336221407Smarius		PHY_RESET(miisc);
3337215132Syongari	nfe_miibus_writereg(sc->nfe_dev, phyno, MII_100T2CR, 0);
3338215132Syongari	nfe_miibus_writereg(sc->nfe_dev, phyno,
3339215132Syongari	    MII_ANAR, ANAR_TX_FD | ANAR_TX | ANAR_10_FD | ANAR_10 | ANAR_CSMA);
3340215132Syongari	nfe_miibus_writereg(sc->nfe_dev, phyno,
3341215132Syongari	    MII_BMCR, BMCR_RESET | BMCR_AUTOEN | BMCR_STARTNEG);
3342215132Syongari	DELAY(1000);
3343215132Syongari	if (aneg != 0) {
3344215132Syongari		/*
3345215132Syongari		 * Poll link state until nfe(4) get a 10/100Mbps link.
3346215132Syongari		 */
3347215132Syongari		for (i = 0; i < MII_ANEGTICKS_GIGE; i++) {
3348215132Syongari			mii_pollstat(mii);
3349215132Syongari			if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID))
3350215132Syongari			    == (IFM_ACTIVE | IFM_AVALID)) {
3351215132Syongari				switch (IFM_SUBTYPE(mii->mii_media_active)) {
3352215132Syongari				case IFM_10_T:
3353215132Syongari				case IFM_100_TX:
3354215132Syongari					nfe_mac_config(sc, mii);
3355215132Syongari					return;
3356215132Syongari				default:
3357215132Syongari					break;
3358215132Syongari				}
3359215132Syongari			}
3360215132Syongari			NFE_UNLOCK(sc);
3361215132Syongari			pause("nfelnk", hz);
3362215132Syongari			NFE_LOCK(sc);
3363215132Syongari		}
3364215132Syongari		if (i == MII_ANEGTICKS_GIGE)
3365215132Syongari			device_printf(sc->nfe_dev,
3366215132Syongari			    "establishing a link failed, WOL may not work!");
3367215132Syongari	}
3368215132Syongari	/*
3369215132Syongari	 * No link, force MAC to have 100Mbps, full-duplex link.
3370215132Syongari	 * This is the last resort and may/may not work.
3371215132Syongari	 */
3372215132Syongari	mii->mii_media_status = IFM_AVALID | IFM_ACTIVE;
3373215132Syongari	mii->mii_media_active = IFM_ETHER | IFM_100_TX | IFM_FDX;
3374215132Syongari	nfe_mac_config(sc, mii);
3375215132Syongari}
3376215132Syongari
3377215132Syongari
3378215132Syongaristatic void
3379215132Syongarinfe_set_wol(struct nfe_softc *sc)
3380215132Syongari{
3381268131Smarcel	if_t ifp;
3382215132Syongari	uint32_t wolctl;
3383215132Syongari	int pmc;
3384215132Syongari	uint16_t pmstat;
3385215132Syongari
3386215132Syongari	NFE_LOCK_ASSERT(sc);
3387215132Syongari
3388219902Sjhb	if (pci_find_cap(sc->nfe_dev, PCIY_PMG, &pmc) != 0)
3389215132Syongari		return;
3390215132Syongari	ifp = sc->nfe_ifp;
3391268131Smarcel	if ((if_getcapenable(ifp) & IFCAP_WOL_MAGIC) != 0)
3392215132Syongari		wolctl = NFE_WOL_MAGIC;
3393215132Syongari	else
3394215132Syongari		wolctl = 0;
3395215132Syongari	NFE_WRITE(sc, NFE_WOL_CTL, wolctl);
3396268131Smarcel	if ((if_getcapenable(ifp) & IFCAP_WOL_MAGIC) != 0) {
3397215132Syongari		nfe_set_linkspeed(sc);
3398215132Syongari		if ((sc->nfe_flags & NFE_PWR_MGMT) != 0)
3399215132Syongari			NFE_WRITE(sc, NFE_PWR2_CTL,
3400215132Syongari			    NFE_READ(sc, NFE_PWR2_CTL) & ~NFE_PWR2_GATE_CLOCKS);
3401215132Syongari		/* Enable RX. */
3402215132Syongari		NFE_WRITE(sc, NFE_RX_RING_ADDR_HI, 0);
3403215132Syongari		NFE_WRITE(sc, NFE_RX_RING_ADDR_LO, 0);
3404215132Syongari		NFE_WRITE(sc, NFE_RX_CTL, NFE_READ(sc, NFE_RX_CTL) |
3405215132Syongari		    NFE_RX_START);
3406215132Syongari	}
3407215132Syongari	/* Request PME if WOL is requested. */
3408215132Syongari	pmstat = pci_read_config(sc->nfe_dev, pmc + PCIR_POWER_STATUS, 2);
3409215132Syongari	pmstat &= ~(PCIM_PSTAT_PME | PCIM_PSTAT_PMEENABLE);
3410268131Smarcel	if ((if_getcapenable(ifp) & IFCAP_WOL) != 0)
3411215132Syongari		pmstat |= PCIM_PSTAT_PME | PCIM_PSTAT_PMEENABLE;
3412215132Syongari	pci_write_config(sc->nfe_dev, pmc + PCIR_POWER_STATUS, pmstat, 2);
3413215132Syongari}
3414