if_nfe.c revision 164649
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 164649 2006-11-27 00:10:00Z obrien $");
25159952Sobrien
26159967Sobrien/* Uncomment the following line to enable polling. */
27163503Sobrien/* #define	DEVICE_POLLING */
28159967Sobrien
29163503Sobrien#define	NFE_NO_JUMBO
30163503Sobrien#define	NFE_CSUM
31163503Sobrien#define	NFE_CSUM_FEATURES	(CSUM_IP | CSUM_TCP | CSUM_UDP)
32163503Sobrien#define	NVLAN 0
33159967Sobrien
34159967Sobrien#ifdef HAVE_KERNEL_OPTION_HEADERS
35159967Sobrien#include "opt_device_polling.h"
36159967Sobrien#endif
37159967Sobrien
38159952Sobrien#include <sys/param.h>
39159952Sobrien#include <sys/endian.h>
40159952Sobrien#include <sys/systm.h>
41159952Sobrien#include <sys/sockio.h>
42159952Sobrien#include <sys/mbuf.h>
43159952Sobrien#include <sys/malloc.h>
44159967Sobrien#include <sys/module.h>
45159952Sobrien#include <sys/kernel.h>
46159952Sobrien#include <sys/socket.h>
47159967Sobrien#include <sys/taskqueue.h>
48159952Sobrien
49159952Sobrien#include <net/if.h>
50159967Sobrien#include <net/if_arp.h>
51159967Sobrien#include <net/ethernet.h>
52159952Sobrien#include <net/if_dl.h>
53159952Sobrien#include <net/if_media.h>
54159952Sobrien#include <net/if_types.h>
55159952Sobrien#include <net/if_vlan_var.h>
56159952Sobrien
57159952Sobrien#include <net/bpf.h>
58159952Sobrien
59159967Sobrien#include <machine/bus.h>
60159967Sobrien#include <machine/resource.h>
61159967Sobrien#include <sys/bus.h>
62159967Sobrien#include <sys/rman.h>
63159967Sobrien
64159952Sobrien#include <dev/mii/mii.h>
65159952Sobrien#include <dev/mii/miivar.h>
66159952Sobrien
67159952Sobrien#include <dev/pci/pcireg.h>
68159952Sobrien#include <dev/pci/pcivar.h>
69159952Sobrien
70159967Sobrien#include <dev/nfe/if_nfereg.h>
71159967Sobrien#include <dev/nfe/if_nfevar.h>
72159952Sobrien
73159967SobrienMODULE_DEPEND(nfe, pci, 1, 1, 1);
74159967SobrienMODULE_DEPEND(nfe, ether, 1, 1, 1);
75159967SobrienMODULE_DEPEND(nfe, miibus, 1, 1, 1);
76159967Sobrien#include "miibus_if.h"
77159952Sobrien
78163503Sobrienstatic int  nfe_probe(device_t);
79163503Sobrienstatic int  nfe_attach(device_t);
80163503Sobrienstatic int  nfe_detach(device_t);
81163503Sobrienstatic void nfe_shutdown(device_t);
82163503Sobrienstatic int  nfe_miibus_readreg(device_t, int, int);
83163503Sobrienstatic int  nfe_miibus_writereg(device_t, int, int, int);
84163503Sobrienstatic void nfe_miibus_statchg(device_t);
85163503Sobrienstatic int  nfe_ioctl(struct ifnet *, u_long, caddr_t);
86163503Sobrienstatic void nfe_intr(void *);
87159967Sobrienstatic void nfe_txdesc32_sync(struct nfe_softc *, struct nfe_desc32 *, int);
88159967Sobrienstatic void nfe_txdesc64_sync(struct nfe_softc *, struct nfe_desc64 *, int);
89159967Sobrienstatic void nfe_txdesc32_rsync(struct nfe_softc *, int, int, int);
90159967Sobrienstatic void nfe_txdesc64_rsync(struct nfe_softc *, int, int, int);
91159967Sobrienstatic void nfe_rxdesc32_sync(struct nfe_softc *, struct nfe_desc32 *, int);
92159967Sobrienstatic void nfe_rxdesc64_sync(struct nfe_softc *, struct nfe_desc64 *, int);
93159967Sobrienstatic void nfe_rxeof(struct nfe_softc *);
94159967Sobrienstatic void nfe_txeof(struct nfe_softc *);
95159967Sobrienstatic int  nfe_encap(struct nfe_softc *, struct mbuf *);
96159967Sobrienstatic struct nfe_jbuf *nfe_jalloc(struct nfe_softc *);
97159967Sobrienstatic void nfe_jfree(void *, void *);
98159967Sobrienstatic int  nfe_jpool_alloc(struct nfe_softc *);
99159967Sobrienstatic void nfe_jpool_free(struct nfe_softc *);
100159967Sobrienstatic void nfe_setmulti(struct nfe_softc *);
101159967Sobrienstatic void nfe_start(struct ifnet *);
102159967Sobrienstatic void nfe_start_locked(struct ifnet *);
103159967Sobrienstatic void nfe_watchdog(struct ifnet *);
104159967Sobrienstatic void nfe_init(void *);
105159967Sobrienstatic void nfe_init_locked(void *);
106159967Sobrienstatic void nfe_stop(struct ifnet *, int);
107159967Sobrienstatic int  nfe_alloc_rx_ring(struct nfe_softc *, struct nfe_rx_ring *);
108159967Sobrienstatic void nfe_reset_rx_ring(struct nfe_softc *, struct nfe_rx_ring *);
109159967Sobrienstatic void nfe_free_rx_ring(struct nfe_softc *, struct nfe_rx_ring *);
110159967Sobrienstatic int  nfe_alloc_tx_ring(struct nfe_softc *, struct nfe_tx_ring *);
111159967Sobrienstatic void nfe_reset_tx_ring(struct nfe_softc *, struct nfe_tx_ring *);
112159967Sobrienstatic void nfe_free_tx_ring(struct nfe_softc *, struct nfe_tx_ring *);
113159967Sobrienstatic int  nfe_ifmedia_upd(struct ifnet *);
114159967Sobrienstatic int  nfe_ifmedia_upd_locked(struct ifnet *);
115159967Sobrienstatic void nfe_ifmedia_sts(struct ifnet *, struct ifmediareq *);
116159967Sobrienstatic void nfe_tick(void *);
117159967Sobrienstatic void nfe_tick_locked(struct nfe_softc *);
118159967Sobrienstatic void nfe_get_macaddr(struct nfe_softc *, u_char *);
119159967Sobrienstatic void nfe_set_macaddr(struct nfe_softc *, u_char *);
120159967Sobrienstatic void nfe_dma_map_segs	(void *, bus_dma_segment_t *, int, int);
121159967Sobrien#ifdef DEVICE_POLLING
122159967Sobrienstatic void nfe_poll_locked(struct ifnet *, enum poll_cmd, int);
123159967Sobrien#endif
124159952Sobrien
125159952Sobrien#ifdef NFE_DEBUG
126159952Sobrienint nfedebug = 0;
127163503Sobrien#define	DPRINTF(x)	do { if (nfedebug) printf x; } while (0)
128163503Sobrien#define	DPRINTFN(n,x)	do { if (nfedebug >= (n)) printf x; } while (0)
129159952Sobrien#else
130163503Sobrien#define	DPRINTF(x)
131163503Sobrien#define	DPRINTFN(n,x)
132159952Sobrien#endif
133159952Sobrien
134159967Sobrien#define	NFE_LOCK(_sc)		mtx_lock(&(_sc)->nfe_mtx)
135159967Sobrien#define	NFE_UNLOCK(_sc)		mtx_unlock(&(_sc)->nfe_mtx)
136159967Sobrien#define	NFE_LOCK_ASSERT(_sc)	mtx_assert(&(_sc)->nfe_mtx, MA_OWNED)
137159967Sobrien
138163503Sobrien#define	letoh16(x) le16toh(x)
139159967Sobrien
140159967Sobrien#define	NV_RID		0x10
141159967Sobrien
142159967Sobrienstatic device_method_t nfe_methods[] = {
143159967Sobrien	/* Device interface */
144159967Sobrien	DEVMETHOD(device_probe,		nfe_probe),
145159967Sobrien	DEVMETHOD(device_attach,	nfe_attach),
146159967Sobrien	DEVMETHOD(device_detach,	nfe_detach),
147159967Sobrien	DEVMETHOD(device_shutdown,	nfe_shutdown),
148159967Sobrien
149159967Sobrien	/* bus interface */
150159967Sobrien	DEVMETHOD(bus_print_child,	bus_generic_print_child),
151159967Sobrien	DEVMETHOD(bus_driver_added,	bus_generic_driver_added),
152159967Sobrien
153159967Sobrien	/* MII interface */
154159967Sobrien	DEVMETHOD(miibus_readreg,	nfe_miibus_readreg),
155159967Sobrien	DEVMETHOD(miibus_writereg,	nfe_miibus_writereg),
156163503Sobrien	DEVMETHOD(miibus_statchg,	nfe_miibus_statchg),
157159967Sobrien
158159967Sobrien	{ 0, 0 }
159159952Sobrien};
160159952Sobrien
161159967Sobrienstatic driver_t nfe_driver = {
162159967Sobrien	"nfe",
163159967Sobrien	nfe_methods,
164159967Sobrien	sizeof(struct nfe_softc)
165159967Sobrien};
166159967Sobrien
167159967Sobrienstatic devclass_t nfe_devclass;
168159967Sobrien
169159967SobrienDRIVER_MODULE(nfe, pci, nfe_driver, nfe_devclass, 0, 0);
170159967SobrienDRIVER_MODULE(miibus, nfe, miibus_driver, miibus_devclass, 0, 0);
171159967Sobrien
172159967Sobrienstatic struct nfe_type nfe_devs[] = {
173159967Sobrien	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE_LAN,
174163503Sobrien	    "NVIDIA nForce MCP Networking Adapter"},
175159967Sobrien	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE2_LAN,
176163503Sobrien	    "NVIDIA nForce2 MCP2 Networking Adapter"},
177159967Sobrien	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE2_400_LAN1,
178163503Sobrien	    "NVIDIA nForce2 400 MCP4 Networking Adapter"},
179159967Sobrien	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE2_400_LAN2,
180163503Sobrien	    "NVIDIA nForce2 400 MCP5 Networking Adapter"},
181163437Sobrien	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE3_LAN1,
182163503Sobrien	    "NVIDIA nForce3 MCP3 Networking Adapter"},
183159967Sobrien	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE3_250_LAN,
184163503Sobrien	    "NVIDIA nForce3 250 MCP6 Networking Adapter"},
185159967Sobrien	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE3_LAN4,
186163503Sobrien	    "NVIDIA nForce3 MCP7 Networking Adapter"},
187159967Sobrien	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE4_LAN1,
188163503Sobrien	    "NVIDIA nForce4 CK804 MCP8 Networking Adapter"},
189159967Sobrien	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE4_LAN2,
190163503Sobrien	    "NVIDIA nForce4 CK804 MCP9 Networking Adapter"},
191159967Sobrien	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP04_LAN1,
192163503Sobrien	    "NVIDIA nForce MCP04 Networking Adapter"},		// MCP10
193159967Sobrien	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP04_LAN2,
194163503Sobrien	    "NVIDIA nForce MCP04 Networking Adapter"},		// MCP11
195159967Sobrien	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE430_LAN1,
196163503Sobrien	    "NVIDIA nForce 430 MCP12 Networking Adapter"},
197159967Sobrien	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE430_LAN2,
198163503Sobrien	    "NVIDIA nForce 430 MCP13 Networking Adapter"},
199159967Sobrien	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP55_LAN1,
200163503Sobrien	    "NVIDIA nForce MCP55 Networking Adapter"},
201159967Sobrien	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP55_LAN2,
202163503Sobrien	    "NVIDIA nForce MCP55 Networking Adapter"},
203162212Sobrien	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP61_LAN1,
204163503Sobrien	    "NVIDIA nForce MCP61 Networking Adapter"},
205162212Sobrien	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP61_LAN2,
206163503Sobrien	    "NVIDIA nForce MCP61 Networking Adapter"},
207162212Sobrien	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP61_LAN3,
208163503Sobrien	    "NVIDIA nForce MCP61 Networking Adapter"},
209162212Sobrien	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP61_LAN2,
210163503Sobrien	    "NVIDIA nForce MCP61 Networking Adapter"},
211162212Sobrien	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP65_LAN1,
212163503Sobrien	    "NVIDIA nForce MCP65 Networking Adapter"},
213162212Sobrien	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP65_LAN2,
214163503Sobrien	    "NVIDIA nForce MCP65 Networking Adapter"},
215162212Sobrien	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP65_LAN3,
216163503Sobrien	    "NVIDIA nForce MCP65 Networking Adapter"},
217162212Sobrien	{PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP65_LAN2,
218163503Sobrien	    "NVIDIA nForce MCP65 Networking Adapter"},
219159967Sobrien	{0, 0, NULL}
220159967Sobrien};
221159967Sobrien
222159967Sobrien
223159967Sobrien/* Probe for supported hardware ID's */
224159967Sobrienstatic int
225159967Sobriennfe_probe(device_t dev)
226159952Sobrien{
227159967Sobrien	struct nfe_type *t;
228159967Sobrien
229159967Sobrien	t = nfe_devs;
230159967Sobrien	/* Check for matching PCI DEVICE ID's */
231159967Sobrien	while (t->name != NULL) {
232159967Sobrien		if ((pci_get_vendor(dev) == t->vid_id) &&
233159967Sobrien		    (pci_get_device(dev) == t->dev_id)) {
234159967Sobrien			device_set_desc(dev, t->name);
235159967Sobrien			return (0);
236159967Sobrien		}
237159967Sobrien		t++;
238159967Sobrien	}
239159967Sobrien
240159967Sobrien	return (ENXIO);
241159952Sobrien}
242159952Sobrien
243163503Sobrien
244159967Sobrienstatic int
245159967Sobriennfe_attach(device_t dev)
246159952Sobrien{
247159967Sobrien	struct nfe_softc *sc;
248159952Sobrien	struct ifnet *ifp;
249159967Sobrien	int unit, error = 0, rid;
250159952Sobrien
251159967Sobrien	sc = device_get_softc(dev);
252159967Sobrien	unit = device_get_unit(dev);
253159967Sobrien	sc->nfe_dev = dev;
254159967Sobrien	sc->nfe_unit = unit;
255159952Sobrien
256159967Sobrien	mtx_init(&sc->nfe_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK,
257159967Sobrien	    MTX_DEF | MTX_RECURSE);
258159967Sobrien	callout_init_mtx(&sc->nfe_stat_ch, &sc->nfe_mtx, 0);
259159967Sobrien
260163503Sobrien	pci_enable_busmaster(dev);
261159967Sobrien
262159967Sobrien	rid = NV_RID;
263159967Sobrien	sc->nfe_res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid,
264159967Sobrien	    0, ~0, 1, RF_ACTIVE);
265159967Sobrien
266159967Sobrien	if (sc->nfe_res == NULL) {
267159967Sobrien		printf ("nfe%d: couldn't map ports/memory\n", unit);
268159967Sobrien		error = ENXIO;
269159967Sobrien		goto fail;
270159952Sobrien	}
271159952Sobrien
272159967Sobrien	sc->nfe_memt = rman_get_bustag(sc->nfe_res);
273159967Sobrien	sc->nfe_memh = rman_get_bushandle(sc->nfe_res);
274159967Sobrien
275159967Sobrien	/* Allocate interrupt */
276159967Sobrien	rid = 0;
277159967Sobrien	sc->nfe_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid,
278159967Sobrien	    0, ~0, 1, RF_SHAREABLE | RF_ACTIVE);
279159967Sobrien
280159967Sobrien	if (sc->nfe_irq == NULL) {
281159967Sobrien		printf("nfe%d: couldn't map interrupt\n", unit);
282159967Sobrien		error = ENXIO;
283159967Sobrien		goto fail;
284159952Sobrien	}
285159952Sobrien
286159967Sobrien	nfe_get_macaddr(sc, sc->eaddr);
287159952Sobrien
288159967Sobrien	sc->nfe_flags = 0;
289159952Sobrien
290159967Sobrien	switch (pci_get_device(dev)) {
291159952Sobrien	case PCI_PRODUCT_NVIDIA_NFORCE3_LAN2:
292159952Sobrien	case PCI_PRODUCT_NVIDIA_NFORCE3_LAN3:
293159952Sobrien	case PCI_PRODUCT_NVIDIA_NFORCE3_LAN4:
294159952Sobrien	case PCI_PRODUCT_NVIDIA_NFORCE3_LAN5:
295159967Sobrien		sc->nfe_flags |= NFE_JUMBO_SUP | NFE_HW_CSUM;
296159952Sobrien		break;
297159952Sobrien	case PCI_PRODUCT_NVIDIA_MCP51_LAN1:
298159952Sobrien	case PCI_PRODUCT_NVIDIA_MCP51_LAN2:
299159967Sobrien		sc->nfe_flags |= NFE_40BIT_ADDR;
300159952Sobrien		break;
301159952Sobrien	case PCI_PRODUCT_NVIDIA_CK804_LAN1:
302159952Sobrien	case PCI_PRODUCT_NVIDIA_CK804_LAN2:
303159952Sobrien	case PCI_PRODUCT_NVIDIA_MCP04_LAN1:
304159952Sobrien	case PCI_PRODUCT_NVIDIA_MCP04_LAN2:
305159967Sobrien		sc->nfe_flags |= NFE_JUMBO_SUP | NFE_40BIT_ADDR | NFE_HW_CSUM;
306159952Sobrien		break;
307159952Sobrien	case PCI_PRODUCT_NVIDIA_MCP55_LAN1:
308159952Sobrien	case PCI_PRODUCT_NVIDIA_MCP55_LAN2:
309163503Sobrien		sc->nfe_flags |= NFE_JUMBO_SUP | NFE_40BIT_ADDR | NFE_HW_CSUM |
310163503Sobrien		    NFE_HW_VLAN;
311159952Sobrien		break;
312162212Sobrien	case PCI_PRODUCT_NVIDIA_MCP61_LAN1:
313162212Sobrien	case PCI_PRODUCT_NVIDIA_MCP61_LAN2:
314162212Sobrien	case PCI_PRODUCT_NVIDIA_MCP61_LAN3:
315162212Sobrien	case PCI_PRODUCT_NVIDIA_MCP61_LAN4:
316162212Sobrien		sc->nfe_flags |= NFE_40BIT_ADDR;
317162212Sobrien		break;
318162212Sobrien	case PCI_PRODUCT_NVIDIA_MCP65_LAN1:
319162212Sobrien	case PCI_PRODUCT_NVIDIA_MCP65_LAN2:
320162212Sobrien	case PCI_PRODUCT_NVIDIA_MCP65_LAN3:
321162212Sobrien	case PCI_PRODUCT_NVIDIA_MCP65_LAN4:
322162212Sobrien		sc->nfe_flags |= NFE_JUMBO_SUP | NFE_40BIT_ADDR | NFE_HW_CSUM;
323163503Sobrien		break;
324159952Sobrien	}
325159952Sobrien
326159952Sobrien#ifndef NFE_NO_JUMBO
327159952Sobrien	/* enable jumbo frames for adapters that support it */
328159967Sobrien	if (sc->nfe_flags & NFE_JUMBO_SUP)
329159967Sobrien		sc->nfe_flags |= NFE_USE_JUMBO;
330159952Sobrien#endif
331159952Sobrien
332159952Sobrien	/*
333159967Sobrien	 * Allocate the parent bus DMA tag appropriate for PCI.
334159967Sobrien	 */
335163503Sobrien#define	NFE_NSEG_NEW 32
336159967Sobrien	error = bus_dma_tag_create(NULL,	/* parent */
337163503Sobrien	    1, 0,				/* alignment, boundary */
338163503Sobrien	    BUS_SPACE_MAXADDR_32BIT,		/* lowaddr */
339163503Sobrien	    BUS_SPACE_MAXADDR,			/* highaddr */
340163503Sobrien	    NULL, NULL,				/* filter, filterarg */
341163503Sobrien	    MAXBSIZE, NFE_NSEG_NEW,		/* maxsize, nsegments */
342163503Sobrien	    BUS_SPACE_MAXSIZE_32BIT,		/* maxsegsize */
343163503Sobrien	    BUS_DMA_ALLOCNOW,			/* flags */
344163503Sobrien	    NULL, NULL,				/* lockfunc, lockarg */
345163503Sobrien	    &sc->nfe_parent_tag);
346159967Sobrien	if (error)
347159967Sobrien		goto fail;
348159967Sobrien
349159967Sobrien	/*
350159952Sobrien	 * Allocate Tx and Rx rings.
351159952Sobrien	 */
352159952Sobrien	if (nfe_alloc_tx_ring(sc, &sc->txq) != 0) {
353159967Sobrien		printf("nfe%d: could not allocate Tx ring\n", unit);
354159967Sobrien		error = ENXIO;
355159967Sobrien		goto fail;
356159952Sobrien	}
357159952Sobrien
358159952Sobrien	if (nfe_alloc_rx_ring(sc, &sc->rxq) != 0) {
359159967Sobrien		printf("nfe%d: could not allocate Rx ring\n", unit);
360159952Sobrien		nfe_free_tx_ring(sc, &sc->txq);
361159967Sobrien		error = ENXIO;
362159967Sobrien		goto fail;
363159952Sobrien	}
364159952Sobrien
365159967Sobrien	ifp = sc->nfe_ifp = if_alloc(IFT_ETHER);
366159967Sobrien	if (ifp == NULL) {
367159967Sobrien		printf("nfe%d: can not if_alloc()\n", unit);
368159967Sobrien		error = ENOSPC;
369159967Sobrien		goto fail;
370159967Sobrien	}
371159967Sobrien
372159952Sobrien	ifp->if_softc = sc;
373159967Sobrien	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
374159967Sobrien	ifp->if_mtu = ETHERMTU;
375159952Sobrien	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
376159952Sobrien	ifp->if_ioctl = nfe_ioctl;
377159952Sobrien	ifp->if_start = nfe_start;
378159967Sobrien	/* ifp->if_hwassist = NFE_CSUM_FEATURES; */
379159952Sobrien	ifp->if_watchdog = nfe_watchdog;
380159952Sobrien	ifp->if_init = nfe_init;
381159952Sobrien	ifp->if_baudrate = IF_Gbps(1);
382159967Sobrien	ifp->if_snd.ifq_maxlen = NFE_IFQ_MAXLEN;
383159952Sobrien
384159952Sobrien	ifp->if_capabilities = IFCAP_VLAN_MTU;
385159952Sobrien#if NVLAN > 0
386159967Sobrien	if (sc->nfe_flags & NFE_HW_VLAN)
387159952Sobrien		ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING;
388159952Sobrien#endif
389159952Sobrien#ifdef NFE_CSUM
390159967Sobrien	if (sc->nfe_flags & NFE_HW_CSUM) {
391159967Sobrien		ifp->if_capabilities |= IFCAP_HWCSUM;
392159952Sobrien	}
393159952Sobrien#endif
394159967Sobrien	ifp->if_capenable = ifp->if_capabilities;
395159952Sobrien
396159967Sobrien#ifdef DEVICE_POLLING
397159967Sobrien	ifp->if_capabilities |= IFCAP_POLLING;
398159967Sobrien#endif
399159952Sobrien
400159967Sobrien	/* Do MII setup */
401163503Sobrien	if (mii_phy_probe(dev, &sc->nfe_miibus, nfe_ifmedia_upd,
402163503Sobrien	    nfe_ifmedia_sts)) {
403159967Sobrien		printf("nfe%d: MII without any phy!\n", unit);
404159967Sobrien		error = ENXIO;
405159967Sobrien		goto fail;
406159967Sobrien	}
407159952Sobrien
408159967Sobrien	ether_ifattach(ifp, sc->eaddr);
409159952Sobrien
410163503Sobrien	error = bus_setup_intr(dev, sc->nfe_irq, INTR_TYPE_NET | INTR_MPSAFE,
411159967Sobrien	    nfe_intr, sc, &sc->nfe_intrhand);
412159952Sobrien
413159967Sobrien	if (error) {
414159967Sobrien		printf("nfe%d: couldn't set up irq\n", unit);
415159967Sobrien		ether_ifdetach(ifp);
416159967Sobrien		goto fail;
417159967Sobrien	}
418159967Sobrien
419159967Sobrienfail:
420159967Sobrien	if (error)
421159967Sobrien		nfe_detach(dev);
422159967Sobrien
423159967Sobrien	return (error);
424159952Sobrien}
425159952Sobrien
426159967Sobrien
427159967Sobrienstatic int
428159967Sobriennfe_detach(device_t dev)
429159952Sobrien{
430163503Sobrien	struct nfe_softc *sc;
431163503Sobrien	struct ifnet *ifp;
432163503Sobrien	u_char eaddr[ETHER_ADDR_LEN];
433163503Sobrien	int i;
434159952Sobrien
435159967Sobrien	sc = device_get_softc(dev);
436159967Sobrien	KASSERT(mtx_initialized(&sc->nfe_mtx), ("nfe mutex not initialized"));
437159967Sobrien	ifp = sc->nfe_ifp;
438159967Sobrien
439159967Sobrien#ifdef DEVICE_POLLING
440159967Sobrien	if (ifp->if_capenable & IFCAP_POLLING)
441159967Sobrien		ether_poll_deregister(ifp);
442159967Sobrien#endif
443159967Sobrien
444159967Sobrien	for (i = 0; i < ETHER_ADDR_LEN; i++) {
445159967Sobrien		eaddr[i] = sc->eaddr[5 - i];
446159952Sobrien	}
447159967Sobrien	nfe_set_macaddr(sc, eaddr);
448159967Sobrien
449159967Sobrien	if (device_is_attached(dev)) {
450164649Sobrien		NFE_LOCK(sc);
451159967Sobrien		nfe_stop(ifp, 1);
452159967Sobrien		ifp->if_flags &= ~IFF_UP;
453164649Sobrien		NFE_UNLOCK(sc);
454159967Sobrien		callout_drain(&sc->nfe_stat_ch);
455159967Sobrien		ether_ifdetach(ifp);
456159967Sobrien	}
457159967Sobrien
458159967Sobrien	if (ifp)
459159967Sobrien		if_free(ifp);
460159967Sobrien	if (sc->nfe_miibus)
461159967Sobrien		device_delete_child(dev, sc->nfe_miibus);
462159967Sobrien	bus_generic_detach(dev);
463159967Sobrien
464159967Sobrien	if (sc->nfe_intrhand)
465159967Sobrien		bus_teardown_intr(dev, sc->nfe_irq, sc->nfe_intrhand);
466159967Sobrien	if (sc->nfe_irq)
467159967Sobrien		bus_release_resource(dev, SYS_RES_IRQ, 0, sc->nfe_irq);
468159967Sobrien	if (sc->nfe_res)
469159967Sobrien		bus_release_resource(dev, SYS_RES_MEMORY, NV_RID, sc->nfe_res);
470159967Sobrien
471159967Sobrien	nfe_free_tx_ring(sc, &sc->txq);
472159967Sobrien	nfe_free_rx_ring(sc, &sc->rxq);
473159967Sobrien
474159967Sobrien	if (sc->nfe_parent_tag)
475159967Sobrien		bus_dma_tag_destroy(sc->nfe_parent_tag);
476159967Sobrien
477159967Sobrien	mtx_destroy(&sc->nfe_mtx);
478159967Sobrien
479159967Sobrien	return (0);
480159952Sobrien}
481159952Sobrien
482159967Sobrien
483159967Sobrienstatic void
484159967Sobriennfe_miibus_statchg(device_t dev)
485159952Sobrien{
486159967Sobrien	struct nfe_softc *sc;
487159967Sobrien	struct mii_data *mii;
488159967Sobrien	u_int32_t phy, seed, misc = NFE_MISC1_MAGIC, link = NFE_MEDIA_SET;
489159952Sobrien
490159967Sobrien	sc = device_get_softc(dev);
491159967Sobrien	mii = device_get_softc(sc->nfe_miibus);
492159967Sobrien
493159952Sobrien	phy = NFE_READ(sc, NFE_PHY_IFACE);
494159952Sobrien	phy &= ~(NFE_PHY_HDX | NFE_PHY_100TX | NFE_PHY_1000T);
495159952Sobrien
496159952Sobrien	seed = NFE_READ(sc, NFE_RNDSEED);
497159952Sobrien	seed &= ~NFE_SEED_MASK;
498159952Sobrien
499159952Sobrien	if ((mii->mii_media_active & IFM_GMASK) == IFM_HDX) {
500159952Sobrien		phy  |= NFE_PHY_HDX;	/* half-duplex */
501159952Sobrien		misc |= NFE_MISC1_HDX;
502159952Sobrien	}
503159952Sobrien
504159952Sobrien	switch (IFM_SUBTYPE(mii->mii_media_active)) {
505159952Sobrien	case IFM_1000_T:	/* full-duplex only */
506159952Sobrien		link |= NFE_MEDIA_1000T;
507159952Sobrien		seed |= NFE_SEED_1000T;
508159952Sobrien		phy  |= NFE_PHY_1000T;
509159952Sobrien		break;
510159952Sobrien	case IFM_100_TX:
511159952Sobrien		link |= NFE_MEDIA_100TX;
512159952Sobrien		seed |= NFE_SEED_100TX;
513159952Sobrien		phy  |= NFE_PHY_100TX;
514159952Sobrien		break;
515159952Sobrien	case IFM_10_T:
516159952Sobrien		link |= NFE_MEDIA_10T;
517159952Sobrien		seed |= NFE_SEED_10T;
518159952Sobrien		break;
519159952Sobrien	}
520159952Sobrien
521159952Sobrien	NFE_WRITE(sc, NFE_RNDSEED, seed);	/* XXX: gigabit NICs only? */
522159952Sobrien
523159952Sobrien	NFE_WRITE(sc, NFE_PHY_IFACE, phy);
524159952Sobrien	NFE_WRITE(sc, NFE_MISC1, misc);
525159952Sobrien	NFE_WRITE(sc, NFE_LINKSPEED, link);
526159952Sobrien}
527159952Sobrien
528163503Sobrien
529159967Sobrienstatic int
530159967Sobriennfe_miibus_readreg(device_t dev, int phy, int reg)
531159952Sobrien{
532159967Sobrien	struct nfe_softc *sc = device_get_softc(dev);
533159967Sobrien	u_int32_t val;
534159952Sobrien	int ntries;
535159952Sobrien
536159952Sobrien	NFE_WRITE(sc, NFE_PHY_STATUS, 0xf);
537159952Sobrien
538159952Sobrien	if (NFE_READ(sc, NFE_PHY_CTL) & NFE_PHY_BUSY) {
539159952Sobrien		NFE_WRITE(sc, NFE_PHY_CTL, NFE_PHY_BUSY);
540159952Sobrien		DELAY(100);
541159952Sobrien	}
542159952Sobrien
543159952Sobrien	NFE_WRITE(sc, NFE_PHY_CTL, (phy << NFE_PHYADD_SHIFT) | reg);
544159952Sobrien
545159952Sobrien	for (ntries = 0; ntries < 1000; ntries++) {
546159952Sobrien		DELAY(100);
547159952Sobrien		if (!(NFE_READ(sc, NFE_PHY_CTL) & NFE_PHY_BUSY))
548159952Sobrien			break;
549159952Sobrien	}
550159952Sobrien	if (ntries == 1000) {
551159967Sobrien		DPRINTFN(2, ("nfe%d: timeout waiting for PHY\n", sc->nfe_unit));
552159952Sobrien		return 0;
553159952Sobrien	}
554159952Sobrien
555159952Sobrien	if (NFE_READ(sc, NFE_PHY_STATUS) & NFE_PHY_ERROR) {
556159967Sobrien		DPRINTFN(2, ("nfe%d: could not read PHY\n", sc->nfe_unit));
557159952Sobrien		return 0;
558159952Sobrien	}
559159952Sobrien
560159952Sobrien	val = NFE_READ(sc, NFE_PHY_DATA);
561159952Sobrien	if (val != 0xffffffff && val != 0)
562159952Sobrien		sc->mii_phyaddr = phy;
563159952Sobrien
564163503Sobrien	DPRINTFN(2, ("nfe%d: mii read phy %d reg 0x%x ret 0x%x\n",
565163503Sobrien	    sc->nfe_unit, phy, reg, val));
566159952Sobrien
567159952Sobrien	return val;
568159952Sobrien}
569159952Sobrien
570163503Sobrien
571159967Sobrienstatic int
572159967Sobriennfe_miibus_writereg(device_t dev, int phy, int reg, int val)
573159952Sobrien{
574159967Sobrien	struct nfe_softc *sc = device_get_softc(dev);
575159967Sobrien	u_int32_t ctl;
576163503Sobrien	int ntries;
577159952Sobrien
578159952Sobrien	NFE_WRITE(sc, NFE_PHY_STATUS, 0xf);
579159952Sobrien
580159952Sobrien	if (NFE_READ(sc, NFE_PHY_CTL) & NFE_PHY_BUSY) {
581159952Sobrien		NFE_WRITE(sc, NFE_PHY_CTL, NFE_PHY_BUSY);
582159952Sobrien		DELAY(100);
583159952Sobrien	}
584159952Sobrien
585159952Sobrien	NFE_WRITE(sc, NFE_PHY_DATA, val);
586159952Sobrien	ctl = NFE_PHY_WRITE | (phy << NFE_PHYADD_SHIFT) | reg;
587159952Sobrien	NFE_WRITE(sc, NFE_PHY_CTL, ctl);
588159952Sobrien
589159952Sobrien	for (ntries = 0; ntries < 1000; ntries++) {
590159952Sobrien		DELAY(100);
591159952Sobrien		if (!(NFE_READ(sc, NFE_PHY_CTL) & NFE_PHY_BUSY))
592159952Sobrien			break;
593159952Sobrien	}
594159952Sobrien#ifdef NFE_DEBUG
595159952Sobrien	if (nfedebug >= 2 && ntries == 1000)
596159952Sobrien		printf("could not write to PHY\n");
597159952Sobrien#endif
598159967Sobrien	return 0;
599159952Sobrien}
600159952Sobrien
601163503Sobrien
602159967Sobrienstatic int
603159967Sobriennfe_alloc_rx_ring(struct nfe_softc *sc, struct nfe_rx_ring *ring)
604159952Sobrien{
605159967Sobrien	struct nfe_desc32 *desc32;
606159967Sobrien	struct nfe_desc64 *desc64;
607159967Sobrien	struct nfe_rx_data *data;
608159967Sobrien	struct nfe_jbuf *jbuf;
609159967Sobrien	void **desc;
610159967Sobrien	bus_addr_t physaddr;
611159967Sobrien	int i, error, descsize;
612159967Sobrien
613159967Sobrien	if (sc->nfe_flags & NFE_40BIT_ADDR) {
614159967Sobrien		desc = (void **)&ring->desc64;
615159967Sobrien		descsize = sizeof (struct nfe_desc64);
616159967Sobrien	} else {
617159967Sobrien		desc = (void **)&ring->desc32;
618159967Sobrien		descsize = sizeof (struct nfe_desc32);
619159967Sobrien	}
620159967Sobrien
621159967Sobrien	ring->cur = ring->next = 0;
622159967Sobrien	ring->bufsz = MCLBYTES;
623159967Sobrien
624163503Sobrien	error = bus_dma_tag_create(sc->nfe_parent_tag,
625163503Sobrien	   PAGE_SIZE, 0,			/* alignment, boundary */
626163503Sobrien	   BUS_SPACE_MAXADDR_32BIT,		/* lowaddr */
627163503Sobrien	   BUS_SPACE_MAXADDR,			/* highaddr */
628163503Sobrien	   NULL, NULL,				/* filter, filterarg */
629163503Sobrien	   NFE_RX_RING_COUNT * descsize, 1,	/* maxsize, nsegments */
630163503Sobrien	   NFE_RX_RING_COUNT * descsize,	/* maxsegsize */
631163503Sobrien	   BUS_DMA_ALLOCNOW,			/* flags */
632163503Sobrien	   NULL, NULL,				/* lockfunc, lockarg */
633163503Sobrien	   &ring->rx_desc_tag);
634159967Sobrien	if (error != 0) {
635159967Sobrien		printf("nfe%d: could not create desc DMA tag\n", sc->nfe_unit);
636159967Sobrien		goto fail;
637159967Sobrien	}
638159967Sobrien
639159967Sobrien	/* allocate memory to desc */
640163503Sobrien	error = bus_dmamem_alloc(ring->rx_desc_tag, (void **)desc,
641163503Sobrien	    BUS_DMA_NOWAIT, &ring->rx_desc_map);
642159967Sobrien	if (error != 0) {
643159967Sobrien		printf("nfe%d: could not create desc DMA map\n", sc->nfe_unit);
644159967Sobrien		goto fail;
645159967Sobrien	}
646159967Sobrien
647159967Sobrien	/* map desc to device visible address space */
648159967Sobrien	error = bus_dmamap_load(ring->rx_desc_tag, ring->rx_desc_map, *desc,
649163503Sobrien	    NFE_RX_RING_COUNT * descsize, nfe_dma_map_segs,
650163503Sobrien	    &ring->rx_desc_segs, BUS_DMA_NOWAIT);
651159967Sobrien	if (error != 0) {
652159967Sobrien		printf("nfe%d: could not load desc DMA map\n", sc->nfe_unit);
653159967Sobrien		goto fail;
654159967Sobrien	}
655159967Sobrien
656159967Sobrien	bzero(*desc, NFE_RX_RING_COUNT * descsize);
657159967Sobrien	ring->rx_desc_addr = ring->rx_desc_segs.ds_addr;
658159967Sobrien	ring->physaddr = ring->rx_desc_addr;
659159967Sobrien
660159967Sobrien	if (sc->nfe_flags & NFE_USE_JUMBO) {
661159967Sobrien		ring->bufsz = NFE_JBYTES;
662159967Sobrien		if ((error = nfe_jpool_alloc(sc)) != 0) {
663163503Sobrien			printf("nfe%d: could not allocate jumbo frames\n",
664163503Sobrien			    sc->nfe_unit);
665159967Sobrien			goto fail;
666159967Sobrien		}
667159967Sobrien	}
668159967Sobrien
669159967Sobrien	/*
670159967Sobrien	 * Pre-allocate Rx buffers and populate Rx ring.
671159967Sobrien	 */
672159967Sobrien	for (i = 0; i < NFE_RX_RING_COUNT; i++) {
673159967Sobrien		data = &sc->rxq.data[i];
674159967Sobrien
675159967Sobrien		MGETHDR(data->m, M_DONTWAIT, MT_DATA);
676159967Sobrien		if (data->m == NULL) {
677163503Sobrien			printf("nfe%d: could not allocate rx mbuf\n",
678163503Sobrien			    sc->nfe_unit);
679159967Sobrien			error = ENOMEM;
680159967Sobrien			goto fail;
681159967Sobrien		}
682159967Sobrien
683159967Sobrien		if (sc->nfe_flags & NFE_USE_JUMBO) {
684159967Sobrien			if ((jbuf = nfe_jalloc(sc)) == NULL) {
685163503Sobrien				printf("nfe%d: could not allocate jumbo buffer\n",
686163503Sobrien				    sc->nfe_unit);
687159967Sobrien				goto fail;
688159967Sobrien			}
689159967Sobrien			data->m->m_data = (void *)jbuf->buf;
690159967Sobrien			data->m->m_len = data->m->m_pkthdr.len = NFE_JBYTES;
691163503Sobrien			MEXTADD(data->m, jbuf->buf, NFE_JBYTES, nfe_jfree,
692163503Sobrien			    (struct nfe_softc *)sc, 0, EXT_NET_DRV);
693159967Sobrien			/* m_adj(data->m, ETHER_ALIGN); */
694159967Sobrien			physaddr = jbuf->physaddr;
695159967Sobrien		} else {
696163503Sobrien			error = bus_dma_tag_create(sc->nfe_parent_tag,
697163503Sobrien			    ETHER_ALIGN, 0,	       /* alignment, boundary */
698163503Sobrien			    BUS_SPACE_MAXADDR_32BIT,	/* lowaddr */
699163503Sobrien			    BUS_SPACE_MAXADDR,		/* highaddr */
700163503Sobrien			    NULL, NULL,		/* filter, filterarg */
701163503Sobrien			    MCLBYTES, 1,		/* maxsize, nsegments */
702163503Sobrien			    MCLBYTES,			/* maxsegsize */
703163503Sobrien			    BUS_DMA_ALLOCNOW,		/* flags */
704163503Sobrien			    NULL, NULL,		/* lockfunc, lockarg */
705163503Sobrien			    &data->rx_data_tag);
706163503Sobrien			if (error != 0) {
707163503Sobrien				printf("nfe%d: could not create DMA map\n",
708163503Sobrien				    sc->nfe_unit);
709163503Sobrien				goto fail;
710163503Sobrien			}
711159967Sobrien
712163503Sobrien			error = bus_dmamap_create(data->rx_data_tag, 0,
713163503Sobrien			    &data->rx_data_map);
714163503Sobrien			if (error != 0) {
715163503Sobrien				printf("nfe%d: could not allocate mbuf cluster\n",
716163503Sobrien				    sc->nfe_unit);
717163503Sobrien				goto fail;
718163503Sobrien			}
719159967Sobrien
720163503Sobrien			MCLGET(data->m, M_DONTWAIT);
721163503Sobrien			if (!(data->m->m_flags & M_EXT)) {
722163503Sobrien				error = ENOMEM;
723163503Sobrien				goto fail;
724163503Sobrien			}
725159967Sobrien
726163503Sobrien			error = bus_dmamap_load(data->rx_data_tag,
727163503Sobrien			    data->rx_data_map, mtod(data->m, void *), MCLBYTES,
728163503Sobrien			    nfe_dma_map_segs, &data->rx_data_segs,
729163503Sobrien			    BUS_DMA_NOWAIT);
730163503Sobrien			if (error != 0) {
731163503Sobrien				printf("nfe%d: could not load rx buf DMA map\n",
732163503Sobrien				    sc->nfe_unit);
733163503Sobrien				goto fail;
734163503Sobrien			}
735159967Sobrien
736163503Sobrien			data->rx_data_addr = data->rx_data_segs.ds_addr;
737163503Sobrien			physaddr = data->rx_data_addr;
738159967Sobrien
739159967Sobrien		}
740159967Sobrien
741159967Sobrien		if (sc->nfe_flags & NFE_40BIT_ADDR) {
742159967Sobrien			desc64 = &sc->rxq.desc64[i];
743159967Sobrien#if defined(__LP64__)
744159967Sobrien			desc64->physaddr[0] = htole32(physaddr >> 32);
745159967Sobrien#endif
746159967Sobrien			desc64->physaddr[1] = htole32(physaddr & 0xffffffff);
747159967Sobrien			desc64->length = htole16(sc->rxq.bufsz);
748159967Sobrien			desc64->flags = htole16(NFE_RX_READY);
749159967Sobrien		} else {
750159967Sobrien			desc32 = &sc->rxq.desc32[i];
751159967Sobrien			desc32->physaddr = htole32(physaddr);
752159967Sobrien			desc32->length = htole16(sc->rxq.bufsz);
753159967Sobrien			desc32->flags = htole16(NFE_RX_READY);
754159967Sobrien		}
755159967Sobrien
756159967Sobrien	}
757159967Sobrien
758163503Sobrien	bus_dmamap_sync(ring->rx_desc_tag, ring->rx_desc_map,
759163503Sobrien	    BUS_DMASYNC_PREWRITE);
760159967Sobrien
761159967Sobrien	return 0;
762159967Sobrien
763159967Sobrienfail:	nfe_free_rx_ring(sc, ring);
764159967Sobrien
765159967Sobrien	return error;
766159967Sobrien}
767159967Sobrien
768163503Sobrien
769159967Sobrienstatic int
770159967Sobriennfe_jpool_alloc(struct nfe_softc *sc)
771159967Sobrien{
772159967Sobrien	struct nfe_rx_ring *ring = &sc->rxq;
773159967Sobrien	struct nfe_jbuf *jbuf;
774159967Sobrien	bus_addr_t physaddr;
775159967Sobrien	caddr_t buf;
776159967Sobrien	int i, error;
777159967Sobrien
778159967Sobrien	/*
779159967Sobrien	 * Allocate a big chunk of DMA'able memory.
780159967Sobrien	 */
781163503Sobrien	error = bus_dma_tag_create(sc->nfe_parent_tag,
782163503Sobrien	   PAGE_SIZE, 0,		/* alignment, boundary */
783163503Sobrien	   BUS_SPACE_MAXADDR_32BIT,	/* lowaddr */
784163503Sobrien	   BUS_SPACE_MAXADDR,		/* highaddr */
785163503Sobrien	   NULL, NULL,			/* filter, filterarg */
786163503Sobrien	   NFE_JPOOL_SIZE, 1,		/* maxsize, nsegments */
787163503Sobrien	   NFE_JPOOL_SIZE,		/* maxsegsize */
788163503Sobrien	   BUS_DMA_ALLOCNOW,		/* flags */
789163503Sobrien	   NULL, NULL,			/* lockfunc, lockarg */
790163503Sobrien	   &ring->rx_jumbo_tag);
791159967Sobrien	if (error != 0) {
792159967Sobrien		printf("nfe%d: could not create jumbo DMA tag\n", sc->nfe_unit);
793159967Sobrien		goto fail;
794159967Sobrien	}
795163503Sobrien
796163503Sobrien	error = bus_dmamem_alloc(ring->rx_jumbo_tag, (void **)&ring->jpool,
797163503Sobrien	    BUS_DMA_NOWAIT, &ring->rx_jumbo_map);
798159967Sobrien	if (error != 0) {
799163503Sobrien		printf("nfe%d: could not create jumbo DMA memory\n",
800163503Sobrien		    sc->nfe_unit);
801159967Sobrien		goto fail;
802159967Sobrien	}
803159967Sobrien
804163503Sobrien	error = bus_dmamap_load(ring->rx_jumbo_tag, ring->rx_jumbo_map,
805163503Sobrien	    ring->jpool, NFE_JPOOL_SIZE, nfe_dma_map_segs, &ring->rx_jumbo_segs,
806163503Sobrien	    BUS_DMA_NOWAIT);
807159967Sobrien	if (error != 0) {
808159967Sobrien		printf("nfe%d: could not load jumbo DMA map\n", sc->nfe_unit);
809159967Sobrien		goto fail;
810159967Sobrien	}
811159967Sobrien
812159967Sobrien	/* ..and split it into 9KB chunks */
813159967Sobrien	SLIST_INIT(&ring->jfreelist);
814159967Sobrien
815159967Sobrien	buf = ring->jpool;
816159967Sobrien	ring->rx_jumbo_addr = ring->rx_jumbo_segs.ds_addr;
817159967Sobrien	physaddr = ring->rx_jumbo_addr;
818159967Sobrien
819159967Sobrien	for (i = 0; i < NFE_JPOOL_COUNT; i++) {
820159967Sobrien		jbuf = &ring->jbuf[i];
821159967Sobrien
822159967Sobrien		jbuf->buf = buf;
823159967Sobrien		jbuf->physaddr = physaddr;
824159967Sobrien
825159967Sobrien		SLIST_INSERT_HEAD(&ring->jfreelist, jbuf, jnext);
826159967Sobrien
827159967Sobrien		buf += NFE_JBYTES;
828159967Sobrien		physaddr += NFE_JBYTES;
829159967Sobrien	}
830159967Sobrien
831159967Sobrien	return 0;
832159967Sobrien
833159967Sobrienfail:	nfe_jpool_free(sc);
834159967Sobrien	return error;
835159967Sobrien}
836159967Sobrien
837159967Sobrien
838159967Sobrienstatic void
839159967Sobriennfe_jpool_free(struct nfe_softc *sc)
840159967Sobrien{
841159967Sobrien	struct nfe_rx_ring *ring = &sc->rxq;
842159967Sobrien
843159967Sobrien	if (ring->jpool != NULL) {
844159967Sobrien#if 0
845163503Sobrien		bus_dmamem_unmap(ring->rx_jumbo_tag, ring->jpool,
846163503Sobrien		    NFE_JPOOL_SIZE);
847159967Sobrien#endif
848163503Sobrien		bus_dmamem_free(ring->rx_jumbo_tag, &ring->rx_jumbo_segs,
849163503Sobrien		    ring->rx_jumbo_map);
850159967Sobrien	}
851159967Sobrien	if (ring->rx_jumbo_map != NULL) {
852163503Sobrien		bus_dmamap_sync(ring->rx_jumbo_tag, ring->rx_jumbo_map,
853163503Sobrien		    BUS_DMASYNC_POSTWRITE);
854159967Sobrien		bus_dmamap_unload(ring->rx_jumbo_tag, ring->rx_jumbo_map);
855159967Sobrien		bus_dmamap_destroy(ring->rx_jumbo_tag, ring->rx_jumbo_map);
856159967Sobrien	}
857159967Sobrien}
858159967Sobrien
859163503Sobrien
860159967Sobrienstatic struct nfe_jbuf *
861159967Sobriennfe_jalloc(struct nfe_softc *sc)
862159967Sobrien{
863159967Sobrien	struct nfe_jbuf *jbuf;
864159967Sobrien
865159967Sobrien	jbuf = SLIST_FIRST(&sc->rxq.jfreelist);
866159967Sobrien	if (jbuf == NULL)
867159967Sobrien		return NULL;
868159967Sobrien	SLIST_REMOVE_HEAD(&sc->rxq.jfreelist, jnext);
869159967Sobrien	return jbuf;
870159967Sobrien}
871159967Sobrien
872163503Sobrien
873159967Sobrien/*
874159967Sobrien * This is called automatically by the network stack when the mbuf is freed.
875159967Sobrien * Caution must be taken that the NIC might be reset by the time the mbuf is
876159967Sobrien * freed.
877159967Sobrien */
878159967Sobrienstatic void
879159967Sobriennfe_jfree(void *buf, void *arg)
880159967Sobrien{
881159952Sobrien	struct nfe_softc *sc = arg;
882159967Sobrien	struct nfe_jbuf *jbuf;
883159967Sobrien	int i;
884159952Sobrien
885159967Sobrien	/* find the jbuf from the base pointer */
886159967Sobrien	i = ((vm_offset_t)buf - (vm_offset_t)sc->rxq.jpool) / NFE_JBYTES;
887159967Sobrien	if (i < 0 || i >= NFE_JPOOL_COUNT) {
888163503Sobrien		printf("nfe%d: request to free a buffer (%p) not managed by us\n",
889163503Sobrien		    sc->nfe_unit, buf);
890159967Sobrien		return;
891159967Sobrien	}
892159967Sobrien	jbuf = &sc->rxq.jbuf[i];
893159952Sobrien
894159967Sobrien	/* ..and put it back in the free list */
895159967Sobrien	SLIST_INSERT_HEAD(&sc->rxq.jfreelist, jbuf, jnext);
896159967Sobrien}
897159952Sobrien
898159967Sobrien
899159967Sobrienstatic void
900159967Sobriennfe_reset_rx_ring(struct nfe_softc *sc, struct nfe_rx_ring *ring)
901159967Sobrien{
902159967Sobrien	int i;
903159967Sobrien
904159967Sobrien	for (i = 0; i < NFE_RX_RING_COUNT; i++) {
905159967Sobrien		if (sc->nfe_flags & NFE_40BIT_ADDR) {
906159967Sobrien			ring->desc64[i].length = htole16(ring->bufsz);
907159967Sobrien			ring->desc64[i].flags = htole16(NFE_RX_READY);
908159967Sobrien		} else {
909159967Sobrien			ring->desc32[i].length = htole16(ring->bufsz);
910159967Sobrien			ring->desc32[i].flags = htole16(NFE_RX_READY);
911159967Sobrien		}
912159952Sobrien	}
913159952Sobrien
914163503Sobrien	bus_dmamap_sync(ring->rx_desc_tag, ring->rx_desc_map,
915163503Sobrien	    BUS_DMASYNC_PREWRITE);
916159952Sobrien
917159967Sobrien	ring->cur = ring->next = 0;
918159967Sobrien}
919159967Sobrien
920159967Sobrien
921159967Sobrienstatic void
922159967Sobriennfe_free_rx_ring(struct nfe_softc *sc, struct nfe_rx_ring *ring)
923159967Sobrien{
924159967Sobrien	struct nfe_rx_data *data;
925159967Sobrien	void *desc;
926159967Sobrien	int i, descsize;
927159967Sobrien
928159967Sobrien	if (sc->nfe_flags & NFE_40BIT_ADDR) {
929159967Sobrien		desc = ring->desc64;
930159967Sobrien		descsize = sizeof (struct nfe_desc64);
931159967Sobrien	} else {
932159967Sobrien		desc = ring->desc32;
933159967Sobrien		descsize = sizeof (struct nfe_desc32);
934159952Sobrien	}
935159952Sobrien
936159967Sobrien	if (desc != NULL) {
937163503Sobrien		bus_dmamap_sync(ring->rx_desc_tag, ring->rx_desc_map,
938163503Sobrien		    BUS_DMASYNC_POSTWRITE);
939159967Sobrien		bus_dmamap_unload(ring->rx_desc_tag, ring->rx_desc_map);
940159967Sobrien		bus_dmamem_free(ring->rx_desc_tag, desc, ring->rx_desc_map);
941159967Sobrien		bus_dma_tag_destroy(ring->rx_desc_tag);
942159967Sobrien	}
943159967Sobrien
944159967Sobrien	if (sc->nfe_flags & NFE_USE_JUMBO) {
945163503Sobrien		nfe_jpool_free(sc);
946159967Sobrien	} else {
947163503Sobrien		for (i = 0; i < NFE_RX_RING_COUNT; i++) {
948163503Sobrien			data = &ring->data[i];
949159967Sobrien
950163503Sobrien			if (data->rx_data_map != NULL) {
951163503Sobrien				bus_dmamap_sync(data->rx_data_tag,
952163503Sobrien				    data->rx_data_map, BUS_DMASYNC_POSTREAD);
953163503Sobrien				bus_dmamap_unload(data->rx_data_tag,
954163503Sobrien				    data->rx_data_map);
955163503Sobrien				bus_dmamap_destroy(data->rx_data_tag,
956163503Sobrien				    data->rx_data_map);
957163503Sobrien				bus_dma_tag_destroy(data->rx_data_tag);
958163503Sobrien			}
959163503Sobrien
960163503Sobrien			if (data->m != NULL)
961163503Sobrien				m_freem(data->m);
962163503Sobrien		}
963159967Sobrien	}
964159952Sobrien}
965159952Sobrien
966163503Sobrien
967159967Sobrienstatic int
968159967Sobriennfe_alloc_tx_ring(struct nfe_softc *sc, struct nfe_tx_ring *ring)
969159952Sobrien{
970159967Sobrien	int i, error;
971159967Sobrien	void **desc;
972159967Sobrien	int descsize;
973159952Sobrien
974159967Sobrien	if (sc->nfe_flags & NFE_40BIT_ADDR) {
975159967Sobrien		desc = (void **)&ring->desc64;
976159967Sobrien		descsize = sizeof (struct nfe_desc64);
977159967Sobrien	} else {
978159967Sobrien		desc = (void **)&ring->desc32;
979159967Sobrien		descsize = sizeof (struct nfe_desc32);
980159967Sobrien	}
981159952Sobrien
982159967Sobrien	ring->queued = 0;
983159967Sobrien	ring->cur = ring->next = 0;
984159967Sobrien
985163503Sobrien	error = bus_dma_tag_create(sc->nfe_parent_tag,
986163503Sobrien	   PAGE_SIZE, 0,			/* alignment, boundary */
987163503Sobrien	   BUS_SPACE_MAXADDR_32BIT,		/* lowaddr */
988163503Sobrien	   BUS_SPACE_MAXADDR,			/* highaddr */
989163503Sobrien	   NULL, NULL,				/* filter, filterarg */
990163503Sobrien	   NFE_TX_RING_COUNT * descsize, 1,	/* maxsize, nsegments */
991163503Sobrien	   NFE_TX_RING_COUNT * descsize,	/* maxsegsize */
992163503Sobrien	   BUS_DMA_ALLOCNOW,			/* flags */
993163503Sobrien	   NULL, NULL,				/* lockfunc, lockarg */
994163503Sobrien	   &ring->tx_desc_tag);
995159967Sobrien	if (error != 0) {
996159967Sobrien		printf("nfe%d: could not create desc DMA tag\n", sc->nfe_unit);
997159967Sobrien		goto fail;
998159952Sobrien	}
999159952Sobrien
1000163503Sobrien	error = bus_dmamem_alloc(ring->tx_desc_tag, (void **)desc,
1001163503Sobrien	    BUS_DMA_NOWAIT, &ring->tx_desc_map);
1002159967Sobrien	if (error != 0) {
1003159967Sobrien		printf("nfe%d: could not create desc DMA map\n", sc->nfe_unit);
1004159967Sobrien		goto fail;
1005159967Sobrien	}
1006159967Sobrien
1007159967Sobrien	error = bus_dmamap_load(ring->tx_desc_tag, ring->tx_desc_map, *desc,
1008163503Sobrien	    NFE_TX_RING_COUNT * descsize, nfe_dma_map_segs, &ring->tx_desc_segs,
1009163503Sobrien	    BUS_DMA_NOWAIT);
1010159967Sobrien	if (error != 0) {
1011159967Sobrien		printf("nfe%d: could not load desc DMA map\n", sc->nfe_unit);
1012159967Sobrien		goto fail;
1013159967Sobrien	}
1014159967Sobrien
1015159967Sobrien	bzero(*desc, NFE_TX_RING_COUNT * descsize);
1016159967Sobrien
1017159967Sobrien	ring->tx_desc_addr = ring->tx_desc_segs.ds_addr;
1018159967Sobrien	ring->physaddr = ring->tx_desc_addr;
1019159967Sobrien
1020163503Sobrien	error = bus_dma_tag_create(sc->nfe_parent_tag,
1021163503Sobrien	   ETHER_ALIGN, 0,
1022163503Sobrien	   BUS_SPACE_MAXADDR_32BIT,
1023163503Sobrien	   BUS_SPACE_MAXADDR,
1024163503Sobrien	   NULL, NULL,
1025163503Sobrien	   NFE_JBYTES, NFE_MAX_SCATTER,
1026163503Sobrien	   NFE_JBYTES,
1027163503Sobrien	   BUS_DMA_ALLOCNOW,
1028163503Sobrien	   NULL, NULL,
1029163503Sobrien	   &ring->tx_data_tag);
1030159967Sobrien	if (error != 0) {
1031159967Sobrien	  printf("nfe%d: could not create DMA tag\n", sc->nfe_unit);
1032159967Sobrien	  goto fail;
1033159967Sobrien	}
1034159967Sobrien
1035159967Sobrien	for (i = 0; i < NFE_TX_RING_COUNT; i++) {
1036163503Sobrien		error = bus_dmamap_create(ring->tx_data_tag, 0,
1037163503Sobrien		    &ring->data[i].tx_data_map);
1038159967Sobrien		if (error != 0) {
1039163503Sobrien			printf("nfe%d: could not create DMA map\n",
1040163503Sobrien			    sc->nfe_unit);
1041159967Sobrien			goto fail;
1042159967Sobrien		}
1043159967Sobrien	}
1044159967Sobrien
1045159967Sobrien	return 0;
1046159967Sobrien
1047159967Sobrienfail:	nfe_free_tx_ring(sc, ring);
1048159967Sobrien	return error;
1049159967Sobrien}
1050159967Sobrien
1051159967Sobrien
1052159967Sobrienstatic void
1053159967Sobriennfe_reset_tx_ring(struct nfe_softc *sc, struct nfe_tx_ring *ring)
1054159967Sobrien{
1055159967Sobrien	struct nfe_tx_data *data;
1056159967Sobrien	int i;
1057159967Sobrien
1058159967Sobrien	for (i = 0; i < NFE_TX_RING_COUNT; i++) {
1059159967Sobrien		if (sc->nfe_flags & NFE_40BIT_ADDR)
1060159967Sobrien			ring->desc64[i].flags = 0;
1061159967Sobrien		else
1062159967Sobrien			ring->desc32[i].flags = 0;
1063159967Sobrien
1064159967Sobrien		data = &ring->data[i];
1065159967Sobrien
1066159967Sobrien		if (data->m != NULL) {
1067163503Sobrien			bus_dmamap_sync(ring->tx_data_tag, data->active,
1068163503Sobrien			    BUS_DMASYNC_POSTWRITE);
1069159967Sobrien			bus_dmamap_unload(ring->tx_data_tag, data->active);
1070159967Sobrien			m_freem(data->m);
1071159967Sobrien			data->m = NULL;
1072159967Sobrien		}
1073159967Sobrien	}
1074159967Sobrien
1075163503Sobrien	bus_dmamap_sync(ring->tx_desc_tag, ring->tx_desc_map,
1076163503Sobrien	    BUS_DMASYNC_PREWRITE);
1077159967Sobrien
1078159967Sobrien	ring->queued = 0;
1079159967Sobrien	ring->cur = ring->next = 0;
1080159967Sobrien}
1081159967Sobrien
1082163503Sobrien
1083159967Sobrienstatic void
1084159967Sobriennfe_free_tx_ring(struct nfe_softc *sc, struct nfe_tx_ring *ring)
1085159967Sobrien{
1086159967Sobrien	struct nfe_tx_data *data;
1087159967Sobrien	void *desc;
1088159967Sobrien	int i, descsize;
1089159967Sobrien
1090159967Sobrien	if (sc->nfe_flags & NFE_40BIT_ADDR) {
1091159967Sobrien		desc = ring->desc64;
1092159967Sobrien		descsize = sizeof (struct nfe_desc64);
1093159967Sobrien	} else {
1094159967Sobrien		desc = ring->desc32;
1095159967Sobrien		descsize = sizeof (struct nfe_desc32);
1096159967Sobrien	}
1097159967Sobrien
1098159967Sobrien	if (desc != NULL) {
1099163503Sobrien		bus_dmamap_sync(ring->tx_desc_tag, ring->tx_desc_map,
1100163503Sobrien		    BUS_DMASYNC_POSTWRITE);
1101159967Sobrien		bus_dmamap_unload(ring->tx_desc_tag, ring->tx_desc_map);
1102159967Sobrien		bus_dmamem_free(ring->tx_desc_tag, desc, ring->tx_desc_map);
1103159967Sobrien		bus_dma_tag_destroy(ring->tx_desc_tag);
1104159967Sobrien	}
1105159967Sobrien
1106159967Sobrien	for (i = 0; i < NFE_TX_RING_COUNT; i++) {
1107159967Sobrien		data = &ring->data[i];
1108159967Sobrien
1109159967Sobrien		if (data->m != NULL) {
1110163503Sobrien			bus_dmamap_sync(ring->tx_data_tag, data->active,
1111163503Sobrien			    BUS_DMASYNC_POSTWRITE);
1112159967Sobrien			bus_dmamap_unload(ring->tx_data_tag, data->active);
1113159967Sobrien			m_freem(data->m);
1114159967Sobrien		}
1115159967Sobrien	}
1116159967Sobrien
1117159967Sobrien	/* ..and now actually destroy the DMA mappings */
1118159967Sobrien	for (i = 0; i < NFE_TX_RING_COUNT; i++) {
1119159967Sobrien		data = &ring->data[i];
1120159967Sobrien		if (data->tx_data_map == NULL)
1121159967Sobrien			continue;
1122159967Sobrien		bus_dmamap_destroy(ring->tx_data_tag, data->tx_data_map);
1123159967Sobrien	}
1124159967Sobrien
1125159967Sobrien	bus_dma_tag_destroy(ring->tx_data_tag);
1126159967Sobrien}
1127159967Sobrien
1128159967Sobrien#ifdef DEVICE_POLLING
1129159967Sobrienstatic poll_handler_t nfe_poll;
1130159967Sobrien
1131163503Sobrien
1132159967Sobrienstatic void
1133159967Sobriennfe_poll(struct ifnet *ifp, enum poll_cmd cmd, int count)
1134159967Sobrien{
1135164360Sobrien	struct nfe_softc *sc = ifp->if_softc;
1136159967Sobrien
1137159967Sobrien	NFE_LOCK(sc);
1138159967Sobrien	if (ifp->if_drv_flags & IFF_DRV_RUNNING)
1139159967Sobrien		nfe_poll_locked(ifp, cmd, count);
1140159967Sobrien	NFE_UNLOCK(sc);
1141159967Sobrien}
1142159967Sobrien
1143159967Sobrien
1144159967Sobrienstatic void
1145159967Sobriennfe_poll_locked(struct ifnet *ifp, enum poll_cmd cmd, int count)
1146159967Sobrien{
1147164360Sobrien	struct nfe_softc *sc = ifp->if_softc;
1148159967Sobrien	u_int32_t r;
1149159967Sobrien
1150159967Sobrien	NFE_LOCK_ASSERT(sc);
1151159967Sobrien
1152159967Sobrien	if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) {
1153159967Sobrien		return;
1154159967Sobrien	}
1155159967Sobrien
1156159967Sobrien	sc->rxcycles = count;
1157159967Sobrien	nfe_rxeof(sc);
1158159967Sobrien	nfe_txeof(sc);
1159159967Sobrien	if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
1160159967Sobrien		nfe_start_locked(ifp);
1161159967Sobrien
1162159967Sobrien	if (cmd == POLL_AND_CHECK_STATUS) {
1163163503Sobrien		if ((r = NFE_READ(sc, NFE_IRQ_STATUS)) == 0) {
1164163503Sobrien			return;
1165163503Sobrien		}
1166163503Sobrien		NFE_WRITE(sc, NFE_IRQ_STATUS, r);
1167159967Sobrien
1168163503Sobrien		if (r & NFE_IRQ_LINK) {
1169163503Sobrien			NFE_READ(sc, NFE_PHY_STATUS);
1170163503Sobrien			NFE_WRITE(sc, NFE_PHY_STATUS, 0xf);
1171163503Sobrien			DPRINTF(("nfe%d: link state changed\n", sc->nfe_unit));
1172163503Sobrien		}
1173159967Sobrien	}
1174159967Sobrien}
1175159967Sobrien#endif /* DEVICE_POLLING */
1176159967Sobrien
1177159967Sobrien
1178159967Sobrienstatic int
1179159967Sobriennfe_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
1180159967Sobrien{
1181163503Sobrien	struct nfe_softc *sc = ifp->if_softc;
1182163503Sobrien	struct ifreq *ifr = (struct ifreq *) data;
1183163503Sobrien	struct mii_data *mii;
1184163503Sobrien	int error = 0;
1185159967Sobrien
1186159952Sobrien	switch (cmd) {
1187159952Sobrien	case SIOCSIFMTU:
1188159952Sobrien		if (ifr->ifr_mtu < ETHERMIN ||
1189159967Sobrien		    ((sc->nfe_flags & NFE_USE_JUMBO) &&
1190159952Sobrien		    ifr->ifr_mtu > ETHERMTU_JUMBO) ||
1191159967Sobrien		    (!(sc->nfe_flags & NFE_USE_JUMBO) &&
1192163503Sobrien		    ifr->ifr_mtu > ETHERMTU)) {
1193159952Sobrien			error = EINVAL;
1194163503Sobrien		} else if (ifp->if_mtu != ifr->ifr_mtu) {
1195159952Sobrien			ifp->if_mtu = ifr->ifr_mtu;
1196159967Sobrien			ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
1197159967Sobrien			nfe_init(sc);
1198159967Sobrien		}
1199159952Sobrien		break;
1200159952Sobrien	case SIOCSIFFLAGS:
1201159967Sobrien		NFE_LOCK(sc);
1202159952Sobrien		if (ifp->if_flags & IFF_UP) {
1203159952Sobrien			/*
1204159952Sobrien			 * If only the PROMISC or ALLMULTI flag changes, then
1205159952Sobrien			 * don't do a full re-init of the chip, just update
1206159952Sobrien			 * the Rx filter.
1207159952Sobrien			 */
1208159967Sobrien			if ((ifp->if_drv_flags & IFF_DRV_RUNNING) &&
1209159967Sobrien			    ((ifp->if_flags ^ sc->nfe_if_flags) &
1210159967Sobrien			     (IFF_ALLMULTI | IFF_PROMISC)) != 0)
1211159952Sobrien				nfe_setmulti(sc);
1212159967Sobrien			else
1213159967Sobrien				nfe_init_locked(sc);
1214159952Sobrien		} else {
1215159967Sobrien			if (ifp->if_drv_flags & IFF_DRV_RUNNING)
1216159952Sobrien				nfe_stop(ifp, 1);
1217159952Sobrien		}
1218159967Sobrien		sc->nfe_if_flags = ifp->if_flags;
1219159967Sobrien		NFE_UNLOCK(sc);
1220159967Sobrien		error = 0;
1221159952Sobrien		break;
1222159952Sobrien	case SIOCADDMULTI:
1223159952Sobrien	case SIOCDELMULTI:
1224159967Sobrien		if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
1225159967Sobrien			NFE_LOCK(sc);
1226159967Sobrien			nfe_setmulti(sc);
1227159967Sobrien			NFE_UNLOCK(sc);
1228159952Sobrien			error = 0;
1229159952Sobrien		}
1230159952Sobrien		break;
1231159952Sobrien	case SIOCSIFMEDIA:
1232159952Sobrien	case SIOCGIFMEDIA:
1233159967Sobrien		mii = device_get_softc(sc->nfe_miibus);
1234159967Sobrien		error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, cmd);
1235159952Sobrien		break;
1236159967Sobrien	case SIOCSIFCAP:
1237163503Sobrien	{
1238159967Sobrien		int mask = ifr->ifr_reqcap ^ ifp->if_capenable;
1239159967Sobrien#ifdef DEVICE_POLLING
1240159967Sobrien		if (mask & IFCAP_POLLING) {
1241159967Sobrien			if (ifr->ifr_reqcap & IFCAP_POLLING) {
1242159967Sobrien				error = ether_poll_register(nfe_poll, ifp);
1243159967Sobrien				if (error)
1244159967Sobrien					return(error);
1245159967Sobrien				NFE_LOCK(sc);
1246159967Sobrien				NFE_WRITE(sc, NFE_IRQ_MASK, 0);
1247163503Sobrien				ifp->if_capenable |= IFCAP_POLLING;
1248159967Sobrien				NFE_UNLOCK(sc);
1249159967Sobrien			} else {
1250159967Sobrien				error = ether_poll_deregister(ifp);
1251159967Sobrien				/* Enable interrupt even in error case */
1252159967Sobrien				NFE_LOCK(sc);
1253159967Sobrien				NFE_WRITE(sc, NFE_IRQ_MASK, NFE_IRQ_WANTED);
1254159967Sobrien				ifp->if_capenable &= ~IFCAP_POLLING;
1255159967Sobrien				NFE_UNLOCK(sc);
1256159967Sobrien			}
1257159967Sobrien		}
1258163503Sobrien#endif /* DEVICE_POLLING */
1259159967Sobrien		if (mask & IFCAP_HWCSUM) {
1260159967Sobrien			ifp->if_capenable ^= IFCAP_HWCSUM;
1261159967Sobrien			if (IFCAP_HWCSUM & ifp->if_capenable &&
1262159967Sobrien			    IFCAP_HWCSUM & ifp->if_capabilities)
1263159967Sobrien				ifp->if_hwassist = NFE_CSUM_FEATURES;
1264159967Sobrien			else
1265159967Sobrien				ifp->if_hwassist = 0;
1266159967Sobrien		}
1267163503Sobrien	}
1268159967Sobrien		break;
1269159967Sobrien
1270159952Sobrien	default:
1271159967Sobrien		error = ether_ioctl(ifp, cmd, data);
1272159967Sobrien		break;
1273159952Sobrien	}
1274159952Sobrien
1275159952Sobrien	return error;
1276159952Sobrien}
1277159952Sobrien
1278159967Sobrien
1279163503Sobrienstatic void
1280163503Sobriennfe_intr(void *arg)
1281159967Sobrien{
1282159967Sobrien	struct nfe_softc *sc = arg;
1283159967Sobrien	struct ifnet *ifp = sc->nfe_ifp;
1284159967Sobrien	u_int32_t r;
1285159967Sobrien
1286163503Sobrien	NFE_LOCK(sc);
1287159967Sobrien
1288159967Sobrien#ifdef DEVICE_POLLING
1289159967Sobrien	if (ifp->if_capenable & IFCAP_POLLING) {
1290159967Sobrien		NFE_UNLOCK(sc);
1291159967Sobrien		return;
1292159967Sobrien	}
1293159967Sobrien#endif
1294159967Sobrien
1295159967Sobrien	if ((r = NFE_READ(sc, NFE_IRQ_STATUS)) == 0) {
1296163503Sobrien		NFE_UNLOCK(sc);
1297159967Sobrien		return;	/* not for us */
1298159967Sobrien	}
1299159967Sobrien	NFE_WRITE(sc, NFE_IRQ_STATUS, r);
1300159967Sobrien
1301159967Sobrien	DPRINTFN(5, ("nfe_intr: interrupt register %x\n", r));
1302159967Sobrien
1303159967Sobrien	NFE_WRITE(sc, NFE_IRQ_MASK, 0);
1304159967Sobrien
1305159967Sobrien	if (r & NFE_IRQ_LINK) {
1306159967Sobrien		NFE_READ(sc, NFE_PHY_STATUS);
1307159967Sobrien		NFE_WRITE(sc, NFE_PHY_STATUS, 0xf);
1308159967Sobrien		DPRINTF(("nfe%d: link state changed\n", sc->nfe_unit));
1309159967Sobrien	}
1310159967Sobrien
1311159967Sobrien	if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
1312159967Sobrien		/* check Rx ring */
1313159967Sobrien		nfe_rxeof(sc);
1314159967Sobrien		/* check Tx ring */
1315159967Sobrien		nfe_txeof(sc);
1316159967Sobrien	}
1317159967Sobrien
1318163503Sobrien	NFE_WRITE(sc, NFE_IRQ_MASK, NFE_IRQ_WANTED);
1319159967Sobrien
1320159967Sobrien	if (ifp->if_drv_flags & IFF_DRV_RUNNING &&
1321159967Sobrien	    !IFQ_DRV_IS_EMPTY(&ifp->if_snd))
1322159967Sobrien		nfe_start_locked(ifp);
1323159967Sobrien
1324159967Sobrien	NFE_UNLOCK(sc);
1325159967Sobrien
1326159967Sobrien	return;
1327159967Sobrien}
1328159967Sobrien
1329163503Sobrien
1330159967Sobrienstatic void
1331159952Sobriennfe_txdesc32_sync(struct nfe_softc *sc, struct nfe_desc32 *desc32, int ops)
1332159952Sobrien{
1333163503Sobrien
1334159967Sobrien	bus_dmamap_sync(sc->txq.tx_desc_tag, sc->txq.tx_desc_map, ops);
1335159952Sobrien}
1336159952Sobrien
1337163503Sobrien
1338159967Sobrienstatic void
1339159952Sobriennfe_txdesc64_sync(struct nfe_softc *sc, struct nfe_desc64 *desc64, int ops)
1340159952Sobrien{
1341163503Sobrien
1342159967Sobrien	bus_dmamap_sync(sc->txq.tx_desc_tag, sc->txq.tx_desc_map, ops);
1343159952Sobrien}
1344159952Sobrien
1345163503Sobrien
1346159967Sobrienstatic void
1347159952Sobriennfe_txdesc32_rsync(struct nfe_softc *sc, int start, int end, int ops)
1348159952Sobrien{
1349163503Sobrien
1350159967Sobrien	bus_dmamap_sync(sc->txq.tx_desc_tag, sc->txq.tx_desc_map, ops);
1351159952Sobrien}
1352159952Sobrien
1353163503Sobrien
1354159967Sobrienstatic void
1355159952Sobriennfe_txdesc64_rsync(struct nfe_softc *sc, int start, int end, int ops)
1356159952Sobrien{
1357163503Sobrien
1358159967Sobrien	bus_dmamap_sync(sc->txq.tx_desc_tag, sc->txq.tx_desc_map, ops);
1359159952Sobrien}
1360159952Sobrien
1361163503Sobrien
1362159967Sobrienstatic void
1363159952Sobriennfe_rxdesc32_sync(struct nfe_softc *sc, struct nfe_desc32 *desc32, int ops)
1364159952Sobrien{
1365163503Sobrien
1366159967Sobrien	bus_dmamap_sync(sc->rxq.rx_desc_tag, sc->rxq.rx_desc_map, ops);
1367159952Sobrien}
1368159952Sobrien
1369163503Sobrien
1370159967Sobrienstatic void
1371159952Sobriennfe_rxdesc64_sync(struct nfe_softc *sc, struct nfe_desc64 *desc64, int ops)
1372159952Sobrien{
1373159967Sobrien
1374159967Sobrien	bus_dmamap_sync(sc->rxq.rx_desc_tag, sc->rxq.rx_desc_map, ops);
1375159952Sobrien}
1376159952Sobrien
1377163503Sobrien
1378163503Sobrienstatic void
1379163503Sobriennfe_rxeof(struct nfe_softc *sc)
1380159952Sobrien{
1381159967Sobrien	struct ifnet *ifp = sc->nfe_ifp;
1382159967Sobrien	struct nfe_desc32 *desc32=NULL;
1383159967Sobrien	struct nfe_desc64 *desc64=NULL;
1384159952Sobrien	struct nfe_rx_data *data;
1385159952Sobrien	struct nfe_jbuf *jbuf;
1386159952Sobrien	struct mbuf *m, *mnew;
1387159952Sobrien	bus_addr_t physaddr;
1388159967Sobrien	u_int16_t flags;
1389159952Sobrien	int error, len;
1390159967Sobrien#if NVLAN > 1
1391159967Sobrien	u_int16_t vlan_tag = 0;
1392159967Sobrien	int have_tag = 0;
1393159967Sobrien#endif
1394159952Sobrien
1395159967Sobrien	NFE_LOCK_ASSERT(sc);
1396159967Sobrien
1397159952Sobrien	for (;;) {
1398159967Sobrien
1399159967Sobrien#ifdef DEVICE_POLLING
1400159967Sobrien		if (ifp->if_capenable & IFCAP_POLLING) {
1401159967Sobrien			if (sc->rxcycles <= 0)
1402159967Sobrien				break;
1403159967Sobrien			sc->rxcycles--;
1404159967Sobrien		}
1405159967Sobrien#endif
1406159967Sobrien
1407159952Sobrien		data = &sc->rxq.data[sc->rxq.cur];
1408159952Sobrien
1409159967Sobrien		if (sc->nfe_flags & NFE_40BIT_ADDR) {
1410159952Sobrien			desc64 = &sc->rxq.desc64[sc->rxq.cur];
1411159952Sobrien			nfe_rxdesc64_sync(sc, desc64, BUS_DMASYNC_POSTREAD);
1412159952Sobrien
1413159952Sobrien			flags = letoh16(desc64->flags);
1414159952Sobrien			len = letoh16(desc64->length) & 0x3fff;
1415159967Sobrien
1416159967Sobrien#if NVLAN > 1
1417159967Sobrien			if (flags & NFE_TX_VLAN_TAG) {
1418159967Sobrien				have_tag = 1;
1419159967Sobrien				vlan_tag = desc64->vtag;
1420159967Sobrien			}
1421159967Sobrien#endif
1422159967Sobrien
1423159952Sobrien		} else {
1424159952Sobrien			desc32 = &sc->rxq.desc32[sc->rxq.cur];
1425159952Sobrien			nfe_rxdesc32_sync(sc, desc32, BUS_DMASYNC_POSTREAD);
1426159952Sobrien
1427159952Sobrien			flags = letoh16(desc32->flags);
1428159952Sobrien			len = letoh16(desc32->length) & 0x3fff;
1429159952Sobrien		}
1430159952Sobrien
1431159952Sobrien		if (flags & NFE_RX_READY)
1432159952Sobrien			break;
1433159952Sobrien
1434159967Sobrien		if ((sc->nfe_flags & (NFE_JUMBO_SUP | NFE_40BIT_ADDR)) == 0) {
1435159952Sobrien			if (!(flags & NFE_RX_VALID_V1))
1436159952Sobrien				goto skip;
1437159952Sobrien			if ((flags & NFE_RX_FIXME_V1) == NFE_RX_FIXME_V1) {
1438159952Sobrien				flags &= ~NFE_RX_ERROR;
1439159952Sobrien				len--;	/* fix buffer length */
1440159952Sobrien			}
1441159952Sobrien		} else {
1442159952Sobrien			if (!(flags & NFE_RX_VALID_V2))
1443159952Sobrien				goto skip;
1444159952Sobrien
1445159952Sobrien			if ((flags & NFE_RX_FIXME_V2) == NFE_RX_FIXME_V2) {
1446159952Sobrien				flags &= ~NFE_RX_ERROR;
1447159952Sobrien				len--;	/* fix buffer length */
1448159952Sobrien			}
1449159952Sobrien		}
1450159952Sobrien
1451159952Sobrien		if (flags & NFE_RX_ERROR) {
1452159952Sobrien			ifp->if_ierrors++;
1453159952Sobrien			goto skip;
1454159952Sobrien		}
1455159952Sobrien
1456159952Sobrien		/*
1457159952Sobrien		 * Try to allocate a new mbuf for this ring element and load
1458159952Sobrien		 * it before processing the current mbuf. If the ring element
1459159952Sobrien		 * cannot be loaded, drop the received packet and reuse the
1460159952Sobrien		 * old mbuf. In the unlikely case that the old mbuf can't be
1461159952Sobrien		 * reloaded either, explicitly panic.
1462159952Sobrien		 */
1463159952Sobrien		MGETHDR(mnew, M_DONTWAIT, MT_DATA);
1464159952Sobrien		if (mnew == NULL) {
1465159952Sobrien			ifp->if_ierrors++;
1466159952Sobrien			goto skip;
1467159952Sobrien		}
1468159952Sobrien
1469159967Sobrien		if (sc->nfe_flags & NFE_USE_JUMBO) {
1470159952Sobrien			if ((jbuf = nfe_jalloc(sc)) == NULL) {
1471159952Sobrien				m_freem(mnew);
1472159952Sobrien				ifp->if_ierrors++;
1473159952Sobrien				goto skip;
1474159952Sobrien			}
1475159967Sobrien			mnew->m_data = (void *)jbuf->buf;
1476159967Sobrien			mnew->m_len = mnew->m_pkthdr.len = NFE_JBYTES;
1477159967Sobrien			MEXTADD(mnew, jbuf->buf, NFE_JBYTES, nfe_jfree,
1478159967Sobrien			    (struct nfe_softc *)sc, 0 , EXT_NET_DRV);
1479159952Sobrien
1480159967Sobrien			bus_dmamap_sync(sc->rxq.rx_jumbo_tag,
1481159967Sobrien			    sc->rxq.rx_jumbo_map, BUS_DMASYNC_POSTREAD);
1482159952Sobrien			physaddr = jbuf->physaddr;
1483159952Sobrien		} else {
1484159952Sobrien			MCLGET(mnew, M_DONTWAIT);
1485159952Sobrien			if (!(mnew->m_flags & M_EXT)) {
1486159952Sobrien				m_freem(mnew);
1487159952Sobrien				ifp->if_ierrors++;
1488159952Sobrien				goto skip;
1489159952Sobrien			}
1490159952Sobrien
1491159967Sobrien			bus_dmamap_sync(data->rx_data_tag, data->rx_data_map,
1492159967Sobrien			    BUS_DMASYNC_POSTREAD);
1493159967Sobrien			bus_dmamap_unload(data->rx_data_tag, data->rx_data_map);
1494159967Sobrien			error = bus_dmamap_load(data->rx_data_tag,
1495159967Sobrien			    data->rx_data_map, mtod(mnew, void *), MCLBYTES,
1496159967Sobrien			    nfe_dma_map_segs, &data->rx_data_segs,
1497159967Sobrien			    BUS_DMA_NOWAIT);
1498159952Sobrien			if (error != 0) {
1499159952Sobrien				m_freem(mnew);
1500159952Sobrien
1501159952Sobrien				/* try to reload the old mbuf */
1502159967Sobrien				error = bus_dmamap_load(data->rx_data_tag,
1503159967Sobrien				    data->rx_data_map, mtod(data->m, void *),
1504159967Sobrien				    MCLBYTES, nfe_dma_map_segs,
1505159967Sobrien				    &data->rx_data_segs, BUS_DMA_NOWAIT);
1506159952Sobrien				if (error != 0) {
1507159952Sobrien					/* very unlikely that it will fail.. */
1508159967Sobrien				      panic("nfe%d: could not load old rx mbuf",
1509159967Sobrien					    sc->nfe_unit);
1510159952Sobrien				}
1511159952Sobrien				ifp->if_ierrors++;
1512159952Sobrien				goto skip;
1513159952Sobrien			}
1514159967Sobrien			data->rx_data_addr = data->rx_data_segs.ds_addr;
1515159967Sobrien			physaddr = data->rx_data_addr;
1516159952Sobrien		}
1517159952Sobrien
1518159952Sobrien		/*
1519159952Sobrien		 * New mbuf successfully loaded, update Rx ring and continue
1520159952Sobrien		 * processing.
1521159952Sobrien		 */
1522159952Sobrien		m = data->m;
1523159952Sobrien		data->m = mnew;
1524159952Sobrien
1525159952Sobrien		/* finalize mbuf */
1526159952Sobrien		m->m_pkthdr.len = m->m_len = len;
1527159952Sobrien		m->m_pkthdr.rcvif = ifp;
1528159952Sobrien
1529159967Sobrien
1530159967Sobrien#if defined(NFE_CSUM)
1531159967Sobrien		if ((sc->nfe_flags & NFE_HW_CSUM) && (flags & NFE_RX_CSUMOK)) {
1532159967Sobrien			m->m_pkthdr.csum_flags |= CSUM_IP_CHECKED;
1533159967Sobrien			if (flags & NFE_RX_IP_CSUMOK_V2) {
1534159967Sobrien				m->m_pkthdr.csum_flags |= CSUM_IP_VALID;
1535159967Sobrien			}
1536159967Sobrien			if (flags & NFE_RX_UDP_CSUMOK_V2 ||
1537159967Sobrien			    flags & NFE_RX_TCP_CSUMOK_V2) {
1538159967Sobrien				m->m_pkthdr.csum_flags |=
1539163503Sobrien				    CSUM_DATA_VALID | CSUM_PSEUDO_HDR;
1540159967Sobrien				m->m_pkthdr.csum_data = 0xffff;
1541159967Sobrien			}
1542159952Sobrien		}
1543159952Sobrien#endif
1544159952Sobrien
1545159967Sobrien#if NVLAN > 1
1546159967Sobrien		if (have_tag) {
1547162375Sandre			m->m_pkthdr.ether_vtag = vlan_tag;
1548162375Sandre			m->m_flags |= M_VLANTAG;
1549159967Sobrien		}
1550159952Sobrien#endif
1551159967Sobrien
1552159952Sobrien		ifp->if_ipackets++;
1553159952Sobrien
1554159967Sobrien		NFE_UNLOCK(sc);
1555159967Sobrien		(*ifp->if_input)(ifp, m);
1556159967Sobrien		NFE_LOCK(sc);
1557159967Sobrien
1558159952Sobrien		/* update mapping address in h/w descriptor */
1559159967Sobrien		if (sc->nfe_flags & NFE_40BIT_ADDR) {
1560159952Sobrien#if defined(__LP64__)
1561159952Sobrien			desc64->physaddr[0] = htole32(physaddr >> 32);
1562159952Sobrien#endif
1563159952Sobrien			desc64->physaddr[1] = htole32(physaddr & 0xffffffff);
1564159952Sobrien		} else {
1565159952Sobrien			desc32->physaddr = htole32(physaddr);
1566159952Sobrien		}
1567159952Sobrien
1568159967Sobrienskip:		if (sc->nfe_flags & NFE_40BIT_ADDR) {
1569159952Sobrien			desc64->length = htole16(sc->rxq.bufsz);
1570159952Sobrien			desc64->flags = htole16(NFE_RX_READY);
1571159952Sobrien
1572159952Sobrien			nfe_rxdesc64_sync(sc, desc64, BUS_DMASYNC_PREWRITE);
1573159952Sobrien		} else {
1574159952Sobrien			desc32->length = htole16(sc->rxq.bufsz);
1575159952Sobrien			desc32->flags = htole16(NFE_RX_READY);
1576159952Sobrien
1577159952Sobrien			nfe_rxdesc32_sync(sc, desc32, BUS_DMASYNC_PREWRITE);
1578159952Sobrien		}
1579159952Sobrien
1580159952Sobrien		sc->rxq.cur = (sc->rxq.cur + 1) % NFE_RX_RING_COUNT;
1581159952Sobrien	}
1582159952Sobrien}
1583159952Sobrien
1584163503Sobrien
1585163503Sobrienstatic void
1586163503Sobriennfe_txeof(struct nfe_softc *sc)
1587159952Sobrien{
1588159967Sobrien	struct ifnet *ifp = sc->nfe_ifp;
1589159952Sobrien	struct nfe_desc32 *desc32;
1590159952Sobrien	struct nfe_desc64 *desc64;
1591159952Sobrien	struct nfe_tx_data *data = NULL;
1592159967Sobrien	u_int16_t flags;
1593159952Sobrien
1594159967Sobrien	NFE_LOCK_ASSERT(sc);
1595159967Sobrien
1596159952Sobrien	while (sc->txq.next != sc->txq.cur) {
1597159967Sobrien		if (sc->nfe_flags & NFE_40BIT_ADDR) {
1598159952Sobrien			desc64 = &sc->txq.desc64[sc->txq.next];
1599159952Sobrien			nfe_txdesc64_sync(sc, desc64, BUS_DMASYNC_POSTREAD);
1600159952Sobrien
1601159952Sobrien			flags = letoh16(desc64->flags);
1602159952Sobrien		} else {
1603159952Sobrien			desc32 = &sc->txq.desc32[sc->txq.next];
1604159952Sobrien			nfe_txdesc32_sync(sc, desc32, BUS_DMASYNC_POSTREAD);
1605159952Sobrien
1606159952Sobrien			flags = letoh16(desc32->flags);
1607159952Sobrien		}
1608159952Sobrien
1609159952Sobrien		if (flags & NFE_TX_VALID)
1610159952Sobrien			break;
1611159952Sobrien
1612159952Sobrien		data = &sc->txq.data[sc->txq.next];
1613159952Sobrien
1614159967Sobrien		if ((sc->nfe_flags & (NFE_JUMBO_SUP | NFE_40BIT_ADDR)) == 0) {
1615159952Sobrien			if (!(flags & NFE_TX_LASTFRAG_V1) && data->m == NULL)
1616159952Sobrien				goto skip;
1617159952Sobrien
1618159952Sobrien			if ((flags & NFE_TX_ERROR_V1) != 0) {
1619159967Sobrien				printf("nfe%d: tx v1 error 0x%4b\n",
1620163503Sobrien				    sc->nfe_unit, flags, NFE_V1_TXERR);
1621159967Sobrien
1622159952Sobrien				ifp->if_oerrors++;
1623159952Sobrien			} else
1624159952Sobrien				ifp->if_opackets++;
1625159952Sobrien		} else {
1626159952Sobrien			if (!(flags & NFE_TX_LASTFRAG_V2) && data->m == NULL)
1627159952Sobrien				goto skip;
1628159952Sobrien
1629159952Sobrien			if ((flags & NFE_TX_ERROR_V2) != 0) {
1630159967Sobrien				printf("nfe%d: tx v1 error 0x%4b\n",
1631163503Sobrien				    sc->nfe_unit, flags, NFE_V2_TXERR);
1632159967Sobrien
1633159952Sobrien				ifp->if_oerrors++;
1634159952Sobrien			} else
1635159952Sobrien				ifp->if_opackets++;
1636159952Sobrien		}
1637159952Sobrien
1638159952Sobrien		if (data->m == NULL) {	/* should not get there */
1639163503Sobrien			printf("nfe%d: last fragment bit w/o associated mbuf!\n",
1640159967Sobrien			    sc->nfe_unit);
1641159952Sobrien			goto skip;
1642159952Sobrien		}
1643159952Sobrien
1644159952Sobrien		/* last fragment of the mbuf chain transmitted */
1645159967Sobrien		bus_dmamap_sync(sc->txq.tx_data_tag, data->active,
1646159967Sobrien		    BUS_DMASYNC_POSTWRITE);
1647159967Sobrien		bus_dmamap_unload(sc->txq.tx_data_tag, data->active);
1648159952Sobrien		m_freem(data->m);
1649159952Sobrien		data->m = NULL;
1650159952Sobrien
1651159952Sobrien		ifp->if_timer = 0;
1652159952Sobrien
1653159952Sobrienskip:		sc->txq.queued--;
1654159952Sobrien		sc->txq.next = (sc->txq.next + 1) % NFE_TX_RING_COUNT;
1655159952Sobrien	}
1656159952Sobrien
1657159952Sobrien	if (data != NULL) {	/* at least one slot freed */
1658159967Sobrien		ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
1659159967Sobrien		nfe_start_locked(ifp);
1660159952Sobrien	}
1661159952Sobrien}
1662159952Sobrien
1663163503Sobrien
1664163503Sobrienstatic int
1665163503Sobriennfe_encap(struct nfe_softc *sc, struct mbuf *m0)
1666159952Sobrien{
1667159967Sobrien	struct nfe_desc32 *desc32=NULL;
1668159967Sobrien	struct nfe_desc64 *desc64=NULL;
1669159967Sobrien	struct nfe_tx_data *data=NULL;
1670159952Sobrien	bus_dmamap_t map;
1671163503Sobrien	bus_dma_segment_t segs[NFE_MAX_SCATTER];
1672163503Sobrien	int error, i, nsegs;
1673159967Sobrien	u_int16_t flags = NFE_TX_VALID;
1674159952Sobrien
1675159967Sobrien	map = sc->txq.data[sc->txq.cur].tx_data_map;
1676159952Sobrien
1677159967Sobrien	error = bus_dmamap_load_mbuf_sg(sc->txq.tx_data_tag, map, m0, segs,
1678159967Sobrien	    &nsegs, BUS_DMA_NOWAIT);
1679159967Sobrien
1680159952Sobrien	if (error != 0) {
1681159967Sobrien		printf("nfe%d: could not map mbuf (error %d)\n", sc->nfe_unit,
1682159967Sobrien		    error);
1683159952Sobrien		return error;
1684159952Sobrien	}
1685159952Sobrien
1686159967Sobrien	if (sc->txq.queued + nsegs >= NFE_TX_RING_COUNT - 1) {
1687159967Sobrien		bus_dmamap_unload(sc->txq.tx_data_tag, map);
1688159952Sobrien		return ENOBUFS;
1689159952Sobrien	}
1690159952Sobrien
1691159967Sobrien
1692159952Sobrien#ifdef NFE_CSUM
1693159967Sobrien	if (m0->m_pkthdr.csum_flags & CSUM_IP)
1694159952Sobrien		flags |= NFE_TX_IP_CSUM;
1695159967Sobrien	if (m0->m_pkthdr.csum_flags & CSUM_TCP)
1696159952Sobrien		flags |= NFE_TX_TCP_CSUM;
1697159967Sobrien	if (m0->m_pkthdr.csum_flags & CSUM_UDP)
1698159967Sobrien		flags |= NFE_TX_TCP_CSUM;
1699159952Sobrien#endif
1700159952Sobrien
1701159967Sobrien	for (i = 0; i < nsegs; i++) {
1702159952Sobrien		data = &sc->txq.data[sc->txq.cur];
1703159952Sobrien
1704159967Sobrien		if (sc->nfe_flags & NFE_40BIT_ADDR) {
1705159952Sobrien			desc64 = &sc->txq.desc64[sc->txq.cur];
1706159952Sobrien#if defined(__LP64__)
1707159967Sobrien			desc64->physaddr[0] = htole32(segs[i].ds_addr >> 32);
1708159952Sobrien#endif
1709159967Sobrien			desc64->physaddr[1] = htole32(segs[i].ds_addr &
1710159967Sobrien			    0xffffffff);
1711159967Sobrien			desc64->length = htole16(segs[i].ds_len - 1);
1712159952Sobrien			desc64->flags = htole16(flags);
1713159952Sobrien#if NVLAN > 0
1714162375Sandre			if (m0->m_flags & M_VLANTAG)
1715162375Sandre				desc64->vtag = htole32(NFE_TX_VTAG |
1716162375Sandre				    m0->m_pkthdr.ether_vtag);
1717159952Sobrien#endif
1718159952Sobrien		} else {
1719159952Sobrien			desc32 = &sc->txq.desc32[sc->txq.cur];
1720159952Sobrien
1721159967Sobrien			desc32->physaddr = htole32(segs[i].ds_addr);
1722159967Sobrien			desc32->length = htole16(segs[i].ds_len - 1);
1723159952Sobrien			desc32->flags = htole16(flags);
1724159952Sobrien		}
1725159952Sobrien
1726159952Sobrien		/* csum flags and vtag belong to the first fragment only */
1727159967Sobrien		if (nsegs > 1) {
1728159952Sobrien			flags &= ~(NFE_TX_IP_CSUM | NFE_TX_TCP_CSUM);
1729159952Sobrien		}
1730163503Sobrien
1731159952Sobrien		sc->txq.queued++;
1732159952Sobrien		sc->txq.cur = (sc->txq.cur + 1) % NFE_TX_RING_COUNT;
1733159952Sobrien	}
1734159952Sobrien
1735159952Sobrien	/* the whole mbuf chain has been DMA mapped, fix last descriptor */
1736159967Sobrien	if (sc->nfe_flags & NFE_40BIT_ADDR) {
1737159952Sobrien		flags |= NFE_TX_LASTFRAG_V2;
1738159952Sobrien		desc64->flags = htole16(flags);
1739159952Sobrien	} else {
1740159967Sobrien		if (sc->nfe_flags & NFE_JUMBO_SUP)
1741159952Sobrien			flags |= NFE_TX_LASTFRAG_V2;
1742159952Sobrien		else
1743159952Sobrien			flags |= NFE_TX_LASTFRAG_V1;
1744159952Sobrien		desc32->flags = htole16(flags);
1745159952Sobrien	}
1746159952Sobrien
1747159952Sobrien	data->m = m0;
1748159952Sobrien	data->active = map;
1749159967Sobrien	data->nsegs = nsegs;
1750159952Sobrien
1751159967Sobrien	bus_dmamap_sync(sc->txq.tx_data_tag, map, BUS_DMASYNC_PREWRITE);
1752159952Sobrien
1753159952Sobrien	return 0;
1754159952Sobrien}
1755159952Sobrien
1756159967Sobrien
1757163503Sobrienstatic void
1758163503Sobriennfe_setmulti(struct nfe_softc *sc)
1759159952Sobrien{
1760159967Sobrien	struct ifnet *ifp = sc->nfe_ifp;
1761163503Sobrien	struct ifmultiaddr *ifma;
1762163503Sobrien	int i;
1763163503Sobrien	u_int32_t filter = NFE_RXFILTER_MAGIC;
1764159967Sobrien	u_int8_t addr[ETHER_ADDR_LEN], mask[ETHER_ADDR_LEN];
1765163503Sobrien	u_int8_t etherbroadcastaddr[ETHER_ADDR_LEN] = {
1766163503Sobrien		0xff, 0xff, 0xff, 0xff, 0xff, 0xff
1767163503Sobrien	};
1768159967Sobrien
1769159967Sobrien	NFE_LOCK_ASSERT(sc);
1770159967Sobrien
1771159967Sobrien	if ((ifp->if_flags & (IFF_ALLMULTI | IFF_PROMISC)) != 0) {
1772159967Sobrien		bzero(addr, ETHER_ADDR_LEN);
1773159967Sobrien		bzero(mask, ETHER_ADDR_LEN);
1774159967Sobrien		goto done;
1775159967Sobrien	}
1776159967Sobrien
1777159967Sobrien	bcopy(etherbroadcastaddr, addr, ETHER_ADDR_LEN);
1778159967Sobrien	bcopy(etherbroadcastaddr, mask, ETHER_ADDR_LEN);
1779159967Sobrien
1780159967Sobrien	IF_ADDR_LOCK(ifp);
1781159967Sobrien	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
1782159967Sobrien		u_char *addrp;
1783159967Sobrien
1784159967Sobrien		if (ifma->ifma_addr->sa_family != AF_LINK)
1785159967Sobrien			continue;
1786159967Sobrien
1787159967Sobrien		addrp = LLADDR((struct sockaddr_dl *) ifma->ifma_addr);
1788159967Sobrien		for (i = 0; i < ETHER_ADDR_LEN; i++) {
1789159967Sobrien			u_int8_t mcaddr = addrp[i];
1790159967Sobrien			addr[i] &= mcaddr;
1791159967Sobrien			mask[i] &= ~mcaddr;
1792159967Sobrien		}
1793159967Sobrien	}
1794159967Sobrien	IF_ADDR_UNLOCK(ifp);
1795159967Sobrien
1796159967Sobrien	for (i = 0; i < ETHER_ADDR_LEN; i++) {
1797159967Sobrien		mask[i] |= addr[i];
1798159967Sobrien	}
1799159967Sobrien
1800159967Sobriendone:
1801159967Sobrien	addr[0] |= 0x01;	/* make sure multicast bit is set */
1802159967Sobrien
1803159967Sobrien	NFE_WRITE(sc, NFE_MULTIADDR_HI,
1804159967Sobrien	    addr[3] << 24 | addr[2] << 16 | addr[1] << 8 | addr[0]);
1805159967Sobrien	NFE_WRITE(sc, NFE_MULTIADDR_LO,
1806159967Sobrien	    addr[5] <<  8 | addr[4]);
1807159967Sobrien	NFE_WRITE(sc, NFE_MULTIMASK_HI,
1808159967Sobrien	    mask[3] << 24 | mask[2] << 16 | mask[1] << 8 | mask[0]);
1809159967Sobrien	NFE_WRITE(sc, NFE_MULTIMASK_LO,
1810159967Sobrien	    mask[5] <<  8 | mask[4]);
1811159967Sobrien
1812159967Sobrien	filter |= (ifp->if_flags & IFF_PROMISC) ? NFE_PROMISC : NFE_U2M;
1813159967Sobrien	NFE_WRITE(sc, NFE_RXFILTER, filter);
1814159967Sobrien}
1815159967Sobrien
1816163503Sobrien
1817163503Sobrienstatic void
1818163503Sobriennfe_start(struct ifnet *ifp)
1819159967Sobrien{
1820159967Sobrien	struct nfe_softc *sc;
1821159967Sobrien
1822159967Sobrien	sc = ifp->if_softc;
1823159967Sobrien	NFE_LOCK(sc);
1824159967Sobrien	nfe_start_locked(ifp);
1825159967Sobrien	NFE_UNLOCK(sc);
1826159967Sobrien}
1827159967Sobrien
1828163503Sobrien
1829163503Sobrienstatic void
1830163503Sobriennfe_start_locked(struct ifnet *ifp)
1831159967Sobrien{
1832159952Sobrien	struct nfe_softc *sc = ifp->if_softc;
1833163503Sobrien	struct mbuf *m0;
1834159952Sobrien	int old = sc->txq.cur;
1835159952Sobrien
1836159967Sobrien	if (!sc->nfe_link || ifp->if_drv_flags & IFF_DRV_OACTIVE) {
1837159967Sobrien		return;
1838159967Sobrien	}
1839159967Sobrien
1840159952Sobrien	for (;;) {
1841159952Sobrien		IFQ_POLL(&ifp->if_snd, m0);
1842159952Sobrien		if (m0 == NULL)
1843159952Sobrien			break;
1844159952Sobrien
1845159952Sobrien		if (nfe_encap(sc, m0) != 0) {
1846159967Sobrien			ifp->if_drv_flags |= IFF_DRV_OACTIVE;
1847159952Sobrien			break;
1848159952Sobrien		}
1849159952Sobrien
1850159952Sobrien		/* packet put in h/w queue, remove from s/w queue */
1851159952Sobrien		IFQ_DEQUEUE(&ifp->if_snd, m0);
1852159952Sobrien
1853159967Sobrien		BPF_MTAP(ifp, m0);
1854159952Sobrien	}
1855159967Sobrien	if (sc->txq.cur == old)	{ /* nothing sent */
1856159952Sobrien		return;
1857159967Sobrien	}
1858159952Sobrien
1859159967Sobrien	if (sc->nfe_flags & NFE_40BIT_ADDR)
1860159952Sobrien		nfe_txdesc64_rsync(sc, old, sc->txq.cur, BUS_DMASYNC_PREWRITE);
1861159952Sobrien	else
1862159952Sobrien		nfe_txdesc32_rsync(sc, old, sc->txq.cur, BUS_DMASYNC_PREWRITE);
1863159952Sobrien
1864159952Sobrien	/* kick Tx */
1865159952Sobrien	NFE_WRITE(sc, NFE_RXTX_CTL, NFE_RXTX_KICKTX | sc->rxtxctl);
1866159952Sobrien
1867159952Sobrien	/*
1868159952Sobrien	 * Set a timeout in case the chip goes out to lunch.
1869159952Sobrien	 */
1870159952Sobrien	ifp->if_timer = 5;
1871159967Sobrien
1872159967Sobrien	return;
1873159952Sobrien}
1874159952Sobrien
1875163503Sobrien
1876163503Sobrienstatic void
1877163503Sobriennfe_watchdog(struct ifnet *ifp)
1878159952Sobrien{
1879159952Sobrien	struct nfe_softc *sc = ifp->if_softc;
1880159952Sobrien
1881159967Sobrien	printf("nfe%d: watchdog timeout\n", sc->nfe_unit);
1882159952Sobrien
1883159967Sobrien	ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
1884159967Sobrien	nfe_init(sc);
1885159952Sobrien	ifp->if_oerrors++;
1886159967Sobrien
1887159967Sobrien	return;
1888159952Sobrien}
1889159952Sobrien
1890163503Sobrien
1891163503Sobrienstatic void
1892163503Sobriennfe_init(void *xsc)
1893159952Sobrien{
1894159967Sobrien	struct nfe_softc *sc = xsc;
1895159952Sobrien
1896159967Sobrien	NFE_LOCK(sc);
1897159967Sobrien	nfe_init_locked(sc);
1898159967Sobrien	NFE_UNLOCK(sc);
1899159967Sobrien
1900159967Sobrien	return;
1901159967Sobrien}
1902159967Sobrien
1903163503Sobrien
1904163503Sobrienstatic void
1905163503Sobriennfe_init_locked(void *xsc)
1906159967Sobrien{
1907159967Sobrien	struct nfe_softc *sc = xsc;
1908159967Sobrien	struct ifnet *ifp = sc->nfe_ifp;
1909159967Sobrien	struct mii_data *mii;
1910159967Sobrien	u_int32_t tmp;
1911159967Sobrien
1912159967Sobrien	NFE_LOCK_ASSERT(sc);
1913159967Sobrien
1914159967Sobrien	mii = device_get_softc(sc->nfe_miibus);
1915159967Sobrien
1916159967Sobrien	if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
1917159967Sobrien		return;
1918159967Sobrien	}
1919159967Sobrien
1920159952Sobrien	nfe_stop(ifp, 0);
1921159952Sobrien
1922159952Sobrien	NFE_WRITE(sc, NFE_TX_UNK, 0);
1923159952Sobrien	NFE_WRITE(sc, NFE_STATUS, 0);
1924159952Sobrien
1925159952Sobrien	sc->rxtxctl = NFE_RXTX_BIT2;
1926159967Sobrien	if (sc->nfe_flags & NFE_40BIT_ADDR)
1927159952Sobrien		sc->rxtxctl |= NFE_RXTX_V3MAGIC;
1928159967Sobrien	else if (sc->nfe_flags & NFE_JUMBO_SUP)
1929159952Sobrien		sc->rxtxctl |= NFE_RXTX_V2MAGIC;
1930159952Sobrien#ifdef NFE_CSUM
1931159967Sobrien	if (sc->nfe_flags & NFE_HW_CSUM)
1932159952Sobrien		sc->rxtxctl |= NFE_RXTX_RXCSUM;
1933159952Sobrien#endif
1934159967Sobrien
1935159952Sobrien#if NVLAN > 0
1936159952Sobrien	/*
1937159952Sobrien	 * Although the adapter is capable of stripping VLAN tags from received
1938159952Sobrien	 * frames (NFE_RXTX_VTAG_STRIP), we do not enable this functionality on
1939159952Sobrien	 * purpose.  This will be done in software by our network stack.
1940159952Sobrien	 */
1941159967Sobrien	if (sc->nfe_flags & NFE_HW_VLAN)
1942159952Sobrien		sc->rxtxctl |= NFE_RXTX_VTAG_INSERT;
1943159952Sobrien#endif
1944159967Sobrien
1945159952Sobrien	NFE_WRITE(sc, NFE_RXTX_CTL, NFE_RXTX_RESET | sc->rxtxctl);
1946159952Sobrien	DELAY(10);
1947159952Sobrien	NFE_WRITE(sc, NFE_RXTX_CTL, sc->rxtxctl);
1948159952Sobrien
1949159952Sobrien#if NVLAN
1950159967Sobrien	if (sc->nfe_flags & NFE_HW_VLAN)
1951159952Sobrien		NFE_WRITE(sc, NFE_VTAG_CTL, NFE_VTAG_ENABLE);
1952159952Sobrien#endif
1953159952Sobrien
1954159952Sobrien	NFE_WRITE(sc, NFE_SETUP_R6, 0);
1955159952Sobrien
1956159952Sobrien	/* set MAC address */
1957159967Sobrien	nfe_set_macaddr(sc, sc->eaddr);
1958159952Sobrien
1959159952Sobrien	/* tell MAC where rings are in memory */
1960159952Sobrien#ifdef __LP64__
1961159952Sobrien	NFE_WRITE(sc, NFE_RX_RING_ADDR_HI, sc->rxq.physaddr >> 32);
1962159952Sobrien#endif
1963159952Sobrien	NFE_WRITE(sc, NFE_RX_RING_ADDR_LO, sc->rxq.physaddr & 0xffffffff);
1964159952Sobrien#ifdef __LP64__
1965159952Sobrien	NFE_WRITE(sc, NFE_TX_RING_ADDR_HI, sc->txq.physaddr >> 32);
1966159952Sobrien#endif
1967159952Sobrien	NFE_WRITE(sc, NFE_TX_RING_ADDR_LO, sc->txq.physaddr & 0xffffffff);
1968159952Sobrien
1969159952Sobrien	NFE_WRITE(sc, NFE_RING_SIZE,
1970159952Sobrien	    (NFE_RX_RING_COUNT - 1) << 16 |
1971159952Sobrien	    (NFE_TX_RING_COUNT - 1));
1972159952Sobrien
1973159952Sobrien	NFE_WRITE(sc, NFE_RXBUFSZ, sc->rxq.bufsz);
1974159952Sobrien
1975159952Sobrien	/* force MAC to wakeup */
1976159952Sobrien	tmp = NFE_READ(sc, NFE_PWR_STATE);
1977159952Sobrien	NFE_WRITE(sc, NFE_PWR_STATE, tmp | NFE_PWR_WAKEUP);
1978159952Sobrien	DELAY(10);
1979159952Sobrien	tmp = NFE_READ(sc, NFE_PWR_STATE);
1980159952Sobrien	NFE_WRITE(sc, NFE_PWR_STATE, tmp | NFE_PWR_VALID);
1981159952Sobrien
1982159952Sobrien#if 1
1983159952Sobrien	/* configure interrupts coalescing/mitigation */
1984159952Sobrien	NFE_WRITE(sc, NFE_IMTIMER, NFE_IM_DEFAULT);
1985159952Sobrien#else
1986159952Sobrien	/* no interrupt mitigation: one interrupt per packet */
1987159952Sobrien	NFE_WRITE(sc, NFE_IMTIMER, 970);
1988159952Sobrien#endif
1989159952Sobrien
1990159952Sobrien	NFE_WRITE(sc, NFE_SETUP_R1, NFE_R1_MAGIC);
1991159952Sobrien	NFE_WRITE(sc, NFE_SETUP_R2, NFE_R2_MAGIC);
1992159952Sobrien	NFE_WRITE(sc, NFE_SETUP_R6, NFE_R6_MAGIC);
1993159952Sobrien
1994159952Sobrien	/* update MAC knowledge of PHY; generates a NFE_IRQ_LINK interrupt */
1995159952Sobrien	NFE_WRITE(sc, NFE_STATUS, sc->mii_phyaddr << 24 | NFE_STATUS_MAGIC);
1996159952Sobrien
1997159952Sobrien	NFE_WRITE(sc, NFE_SETUP_R4, NFE_R4_MAGIC);
1998159952Sobrien	NFE_WRITE(sc, NFE_WOL_CTL, NFE_WOL_MAGIC);
1999159952Sobrien
2000159952Sobrien	sc->rxtxctl &= ~NFE_RXTX_BIT2;
2001159952Sobrien	NFE_WRITE(sc, NFE_RXTX_CTL, sc->rxtxctl);
2002159952Sobrien	DELAY(10);
2003159952Sobrien	NFE_WRITE(sc, NFE_RXTX_CTL, NFE_RXTX_BIT1 | sc->rxtxctl);
2004159952Sobrien
2005159952Sobrien	/* set Rx filter */
2006159952Sobrien	nfe_setmulti(sc);
2007159952Sobrien
2008159952Sobrien	nfe_ifmedia_upd(ifp);
2009159952Sobrien
2010159967Sobrien	nfe_tick_locked(sc);
2011159967Sobrien
2012159952Sobrien	/* enable Rx */
2013159952Sobrien	NFE_WRITE(sc, NFE_RX_CTL, NFE_RX_START);
2014159952Sobrien
2015159952Sobrien	/* enable Tx */
2016159952Sobrien	NFE_WRITE(sc, NFE_TX_CTL, NFE_TX_START);
2017159952Sobrien
2018159952Sobrien	NFE_WRITE(sc, NFE_PHY_STATUS, 0xf);
2019159952Sobrien
2020159967Sobrien#ifdef DEVICE_POLLING
2021159967Sobrien	if (ifp->if_capenable & IFCAP_POLLING)
2022159967Sobrien		NFE_WRITE(sc, NFE_IRQ_MASK, 0);
2023159967Sobrien	else
2024159967Sobrien#endif
2025159967Sobrien	NFE_WRITE(sc, NFE_IRQ_MASK, NFE_IRQ_WANTED); /* enable interrupts */
2026159952Sobrien
2027159967Sobrien	ifp->if_drv_flags |= IFF_DRV_RUNNING;
2028159967Sobrien	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
2029159952Sobrien
2030159967Sobrien	sc->nfe_link = 0;
2031159952Sobrien
2032159967Sobrien	return;
2033159952Sobrien}
2034159952Sobrien
2035163503Sobrien
2036163503Sobrienstatic void
2037163503Sobriennfe_stop(struct ifnet *ifp, int disable)
2038159952Sobrien{
2039159952Sobrien	struct nfe_softc *sc = ifp->if_softc;
2040159967Sobrien	struct mii_data  *mii;
2041159952Sobrien
2042159967Sobrien	NFE_LOCK_ASSERT(sc);
2043159952Sobrien
2044159952Sobrien	ifp->if_timer = 0;
2045159967Sobrien	ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
2046159952Sobrien
2047159967Sobrien	mii = device_get_softc(sc->nfe_miibus);
2048159952Sobrien
2049159967Sobrien	callout_stop(&sc->nfe_stat_ch);
2050159967Sobrien
2051159952Sobrien	/* abort Tx */
2052159952Sobrien	NFE_WRITE(sc, NFE_TX_CTL, 0);
2053159952Sobrien
2054159952Sobrien	/* disable Rx */
2055159952Sobrien	NFE_WRITE(sc, NFE_RX_CTL, 0);
2056159952Sobrien
2057159952Sobrien	/* disable interrupts */
2058159952Sobrien	NFE_WRITE(sc, NFE_IRQ_MASK, 0);
2059159952Sobrien
2060159967Sobrien	sc->nfe_link = 0;
2061159967Sobrien
2062159952Sobrien	/* reset Tx and Rx rings */
2063159952Sobrien	nfe_reset_tx_ring(sc, &sc->txq);
2064159952Sobrien	nfe_reset_rx_ring(sc, &sc->rxq);
2065159952Sobrien
2066159967Sobrien	return;
2067159952Sobrien}
2068159952Sobrien
2069163503Sobrien
2070163503Sobrienstatic int
2071163503Sobriennfe_ifmedia_upd(struct ifnet *ifp)
2072159952Sobrien{
2073159967Sobrien	struct nfe_softc *sc = ifp->if_softc;
2074159952Sobrien
2075159967Sobrien	NFE_LOCK(sc);
2076159967Sobrien	nfe_ifmedia_upd_locked(ifp);
2077159967Sobrien	NFE_UNLOCK(sc);
2078159967Sobrien	return (0);
2079159952Sobrien}
2080159952Sobrien
2081163503Sobrien
2082163503Sobrienstatic int
2083163503Sobriennfe_ifmedia_upd_locked(struct ifnet *ifp)
2084159952Sobrien{
2085163503Sobrien	struct nfe_softc *sc = ifp->if_softc;
2086163503Sobrien	struct mii_data *mii;
2087159952Sobrien
2088159967Sobrien	NFE_LOCK_ASSERT(sc);
2089159952Sobrien
2090159967Sobrien	mii = device_get_softc(sc->nfe_miibus);
2091159952Sobrien
2092159967Sobrien	if (mii->mii_instance) {
2093159967Sobrien		struct mii_softc *miisc;
2094159967Sobrien		for (miisc = LIST_FIRST(&mii->mii_phys); miisc != NULL;
2095159967Sobrien		    miisc = LIST_NEXT(miisc, mii_list)) {
2096159967Sobrien			mii_phy_reset(miisc);
2097159952Sobrien		}
2098159952Sobrien	}
2099159967Sobrien	mii_mediachg(mii);
2100159967Sobrien
2101159967Sobrien	return (0);
2102159952Sobrien}
2103159952Sobrien
2104163503Sobrien
2105163503Sobrienstatic void
2106163503Sobriennfe_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
2107159952Sobrien{
2108163503Sobrien	struct nfe_softc *sc;
2109163503Sobrien	struct mii_data *mii;
2110159952Sobrien
2111159967Sobrien	sc = ifp->if_softc;
2112159952Sobrien
2113159967Sobrien	NFE_LOCK(sc);
2114159967Sobrien	mii = device_get_softc(sc->nfe_miibus);
2115159967Sobrien	mii_pollstat(mii);
2116159967Sobrien	NFE_UNLOCK(sc);
2117159952Sobrien
2118159967Sobrien	ifmr->ifm_active = mii->mii_media_active;
2119159967Sobrien	ifmr->ifm_status = mii->mii_media_status;
2120159952Sobrien
2121159967Sobrien	return;
2122159952Sobrien}
2123159952Sobrien
2124163503Sobrien
2125159967Sobrienstatic void
2126159967Sobriennfe_tick(void *xsc)
2127159952Sobrien{
2128159967Sobrien	struct nfe_softc *sc;
2129159952Sobrien
2130159967Sobrien	sc = xsc;
2131159952Sobrien
2132159967Sobrien	NFE_LOCK(sc);
2133159967Sobrien	nfe_tick_locked(sc);
2134159967Sobrien	NFE_UNLOCK(sc);
2135159952Sobrien}
2136159952Sobrien
2137159952Sobrien
2138163503Sobrienvoid
2139163503Sobriennfe_tick_locked(struct nfe_softc *arg)
2140159952Sobrien{
2141163503Sobrien	struct nfe_softc *sc;
2142163503Sobrien	struct mii_data *mii;
2143163503Sobrien	struct ifnet *ifp;
2144159952Sobrien
2145159967Sobrien	sc = arg;
2146159952Sobrien
2147163503Sobrien	NFE_LOCK_ASSERT(sc);
2148159952Sobrien
2149159967Sobrien	ifp = sc->nfe_ifp;
2150159952Sobrien
2151159967Sobrien	mii = device_get_softc(sc->nfe_miibus);
2152159967Sobrien	mii_tick(mii);
2153159952Sobrien
2154159967Sobrien	if (!sc->nfe_link) {
2155159967Sobrien		if (mii->mii_media_status & IFM_ACTIVE &&
2156159967Sobrien		    IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) {
2157159967Sobrien			sc->nfe_link++;
2158159967Sobrien			if (IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_T
2159159967Sobrien			    && bootverbose)
2160159967Sobrien				if_printf(sc->nfe_ifp, "gigabit link up\n");
2161159967Sobrien					if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
2162159967Sobrien						nfe_start_locked(ifp);
2163159952Sobrien		}
2164159952Sobrien	}
2165159967Sobrien	callout_reset(&sc->nfe_stat_ch, hz, nfe_tick, sc);
2166159952Sobrien
2167159967Sobrien	return;
2168159952Sobrien}
2169159952Sobrien
2170159952Sobrien
2171163503Sobrienstatic void
2172163503Sobriennfe_shutdown(device_t dev)
2173159952Sobrien{
2174159967Sobrien	struct nfe_softc *sc;
2175159967Sobrien	struct ifnet *ifp;
2176159952Sobrien
2177159967Sobrien	sc = device_get_softc(dev);
2178159952Sobrien
2179159967Sobrien	NFE_LOCK(sc);
2180159967Sobrien	ifp = sc->nfe_ifp;
2181159967Sobrien	nfe_stop(ifp,0);
2182159967Sobrien	/* nfe_reset(sc); */
2183159967Sobrien	NFE_UNLOCK(sc);
2184159952Sobrien
2185159967Sobrien	return;
2186159952Sobrien}
2187159952Sobrien
2188159952Sobrien
2189163503Sobrienstatic void
2190163503Sobriennfe_get_macaddr(struct nfe_softc *sc, u_char *addr)
2191159952Sobrien{
2192159952Sobrien	uint32_t tmp;
2193159952Sobrien
2194159952Sobrien	tmp = NFE_READ(sc, NFE_MACADDR_LO);
2195159952Sobrien	addr[0] = (tmp >> 8) & 0xff;
2196159952Sobrien	addr[1] = (tmp & 0xff);
2197159952Sobrien
2198159952Sobrien	tmp = NFE_READ(sc, NFE_MACADDR_HI);
2199159952Sobrien	addr[2] = (tmp >> 24) & 0xff;
2200159952Sobrien	addr[3] = (tmp >> 16) & 0xff;
2201159952Sobrien	addr[4] = (tmp >>  8) & 0xff;
2202159952Sobrien	addr[5] = (tmp & 0xff);
2203159952Sobrien}
2204159952Sobrien
2205163503Sobrien
2206163503Sobrienstatic void
2207163503Sobriennfe_set_macaddr(struct nfe_softc *sc, u_char *addr)
2208159952Sobrien{
2209159967Sobrien
2210159967Sobrien	NFE_WRITE(sc, NFE_MACADDR_LO, addr[5] <<  8 | addr[4]);
2211159967Sobrien	NFE_WRITE(sc, NFE_MACADDR_HI, addr[3] << 24 | addr[2] << 16 |
2212159967Sobrien	    addr[1] << 8 | addr[0]);
2213159952Sobrien}
2214159952Sobrien
2215163503Sobrien
2216159967Sobrien/*
2217159967Sobrien * Map a single buffer address.
2218159967Sobrien */
2219159967Sobrien
2220159967Sobrienstatic void
2221159967Sobriennfe_dma_map_segs(arg, segs, nseg, error)
2222159967Sobrien	void *arg;
2223159967Sobrien	bus_dma_segment_t *segs;
2224159967Sobrien	int error, nseg;
2225159952Sobrien{
2226159952Sobrien
2227159967Sobrien	if (error)
2228159967Sobrien		return;
2229159952Sobrien
2230159967Sobrien	KASSERT(nseg == 1, ("too many DMA segments, %d should be 1", nseg));
2231159967Sobrien
2232159967Sobrien	*(bus_dma_segment_t *)arg = *segs;
2233159967Sobrien
2234159967Sobrien	return;
2235159952Sobrien}
2236